gnunet-0.9.3/0000755000175000017500000000000011763406747010043 500000000000000gnunet-0.9.3/ABOUT-NLS0000644000175000017500000023334011260753602011202 000000000000001 Notes on the Free Translation Project *************************************** Free software is going international! The Free Translation Project is a way to get maintainers of free software, translators, and users all together, so that free software will gradually become able to speak many languages. A few packages already provide translations for their messages. If you found this `ABOUT-NLS' file inside a distribution, you may assume that the distributed package does use GNU `gettext' internally, itself available at your nearest GNU archive site. But you do _not_ need to install GNU `gettext' prior to configuring, installing or using this package with messages translated. Installers will find here some useful hints. These notes also explain how users should proceed for getting the programs to use the available translations. They tell how people wanting to contribute and work on translations can contact the appropriate team. When reporting bugs in the `intl/' directory or bugs which may be related to internationalization, you should tell about the version of `gettext' which is used. The information can be found in the `intl/VERSION' file, in internationalized packages. 1.1 Quick configuration advice ============================== If you want to exploit the full power of internationalization, you should configure it using ./configure --with-included-gettext to force usage of internationalizing routines provided within this package, despite the existence of internationalizing capabilities in the operating system where this package is being installed. So far, only the `gettext' implementation in the GNU C library version 2 provides as many features (such as locale alias, message inheritance, automatic charset conversion or plural form handling) as the implementation here. It is also not possible to offer this additional functionality on top of a `catgets' implementation. Future versions of GNU `gettext' will very likely convey even more functionality. So it might be a good idea to change to GNU `gettext' as soon as possible. So you need _not_ provide this option if you are using GNU libc 2 or you have installed a recent copy of the GNU gettext package with the included `libintl'. 1.2 INSTALL Matters =================== Some packages are "localizable" when properly installed; the programs they contain can be made to speak your own native language. Most such packages use GNU `gettext'. Other packages have their own ways to internationalization, predating GNU `gettext'. By default, this package will be installed to allow translation of messages. It will automatically detect whether the system already provides the GNU `gettext' functions. If not, the included GNU `gettext' library will be used. This library is wholly contained within this package, usually in the `intl/' subdirectory, so prior installation of the GNU `gettext' package is _not_ required. Installers may use special options at configuration time for changing the default behaviour. The commands: ./configure --with-included-gettext ./configure --disable-nls will, respectively, bypass any pre-existing `gettext' to use the internationalizing routines provided within this package, or else, _totally_ disable translation of messages. When you already have GNU `gettext' installed on your system and run configure without an option for your new package, `configure' will probably detect the previously built and installed `libintl.a' file and will decide to use this. This might not be desirable. You should use the more recent version of the GNU `gettext' library. I.e. if the file `intl/VERSION' shows that the library which comes with this package is more recent, you should use ./configure --with-included-gettext to prevent auto-detection. The configuration process will not test for the `catgets' function and therefore it will not be used. The reason is that even an emulation of `gettext' on top of `catgets' could not provide all the extensions of the GNU `gettext' library. Internationalized packages usually have many `po/LL.po' files, where LL gives an ISO 639 two-letter code identifying the language. Unless translations have been forbidden at `configure' time by using the `--disable-nls' switch, all available translations are installed together with the package. However, the environment variable `LINGUAS' may be set, prior to configuration, to limit the installed set. `LINGUAS' should then contain a space separated list of two-letter codes, stating which languages are allowed. 1.3 Using This Package ====================== As a user, if your language has been installed for this package, you only have to set the `LANG' environment variable to the appropriate `LL_CC' combination. Here `LL' is an ISO 639 two-letter language code, and `CC' is an ISO 3166 two-letter country code. For example, let's suppose that you speak German and live in Germany. At the shell prompt, merely execute `setenv LANG de_DE' (in `csh'), `export LANG; LANG=de_DE' (in `sh') or `export LANG=de_DE' (in `bash'). This can be done from your `.login' or `.profile' file, once and for all. You might think that the country code specification is redundant. But in fact, some languages have dialects in different countries. For example, `de_AT' is used for Austria, and `pt_BR' for Brazil. The country code serves to distinguish the dialects. The locale naming convention of `LL_CC', with `LL' denoting the language and `CC' denoting the country, is the one use on systems based on GNU libc. On other systems, some variations of this scheme are used, such as `LL' or `LL_CC.ENCODING'. You can get the list of locales supported by your system for your language by running the command `locale -a | grep '^LL''. Not all programs have translations for all languages. By default, an English message is shown in place of a nonexistent translation. If you understand other languages, you can set up a priority list of languages. This is done through a different environment variable, called `LANGUAGE'. GNU `gettext' gives preference to `LANGUAGE' over `LANG' for the purpose of message handling, but you still need to have `LANG' set to the primary language; this is required by other parts of the system libraries. For example, some Swedish users who would rather read translations in German than English for when Swedish is not available, set `LANGUAGE' to `sv:de' while leaving `LANG' to `sv_SE'. Special advice for Norwegian users: The language code for Norwegian bokma*l changed from `no' to `nb' recently (in 2003). During the transition period, while some message catalogs for this language are installed under `nb' and some older ones under `no', it's recommended for Norwegian users to set `LANGUAGE' to `nb:no' so that both newer and older translations are used. In the `LANGUAGE' environment variable, but not in the `LANG' environment variable, `LL_CC' combinations can be abbreviated as `LL' to denote the language's main dialect. For example, `de' is equivalent to `de_DE' (German as spoken in Germany), and `pt' to `pt_PT' (Portuguese as spoken in Portugal) in this context. 1.4 Translating Teams ===================== For the Free Translation Project to be a success, we need interested people who like their own language and write it well, and who are also able to synergize with other translators speaking the same language. Each translation team has its own mailing list. The up-to-date list of teams can be found at the Free Translation Project's homepage, `http://www.iro.umontreal.ca/contrib/po/HTML/', in the "National teams" area. If you'd like to volunteer to _work_ at translating messages, you should become a member of the translating team for your own language. The subscribing address is _not_ the same as the list itself, it has `-request' appended. For example, speakers of Swedish can send a message to `sv-request@li.org', having this message body: subscribe Keep in mind that team members are expected to participate _actively_ in translations, or at solving translational difficulties, rather than merely lurking around. If your team does not exist yet and you want to start one, or if you are unsure about what to do or how to get started, please write to `translation@iro.umontreal.ca' to reach the coordinator for all translator teams. The English team is special. It works at improving and uniformizing the terminology in use. Proven linguistic skills are praised more than programming skills, here. 1.5 Available Packages ====================== Languages are not equally supported in all packages. The following matrix shows the current state of internationalization, as of October 2006. The matrix shows, in regard of each package, for which languages PO files have been submitted to translation coordination, with a translation percentage of at least 50%. Ready PO files af am ar az be bg bs ca cs cy da de el en en_GB eo +----------------------------------------------------+ GNUnet | [] | a2ps | [] [] [] [] [] | aegis | () | ant-phone | () | anubis | [] | ap-utils | | aspell | [] [] [] [] [] | bash | [] [] [] | batchelor | [] | bfd | | bibshelf | [] | binutils | [] | bison | [] [] | bison-runtime | | bluez-pin | [] [] [] [] [] | cflow | [] | clisp | [] [] | console-tools | [] [] | coreutils | [] [] [] | cpio | | cpplib | [] [] [] | cryptonit | [] | darkstat | [] () [] | dialog | [] [] [] [] [] [] | diffutils | [] [] [] [] [] [] | doodle | [] | e2fsprogs | [] [] | enscript | [] [] [] [] | error | [] [] [] [] | fetchmail | [] [] () [] | fileutils | [] [] | findutils | [] [] [] | flex | [] [] [] | fslint | [] | gas | | gawk | [] [] [] | gbiff | [] | gcal | [] | gcc | [] | gettext-examples | [] [] [] [] [] | gettext-runtime | [] [] [] [] [] | gettext-tools | [] [] | gimp-print | [] [] [] [] | gip | [] | gliv | [] | glunarclock | [] | gmult | [] [] | gnubiff | () | gnucash | () () [] | gnucash-glossary | [] () | gnuedu | | gnulib | [] [] [] [] [] [] | gnunet-gtk | | gnutls | | gpe-aerial | [] [] | gpe-beam | [] [] | gpe-calendar | | gpe-clock | [] [] | gpe-conf | [] [] | gpe-contacts | | gpe-edit | [] | gpe-filemanager | | gpe-go | [] | gpe-login | [] [] | gpe-ownerinfo | [] [] | gpe-package | | gpe-sketchbook | [] [] | gpe-su | [] [] | gpe-taskmanager | [] [] | gpe-timesheet | [] | gpe-today | [] [] | gpe-todo | | gphoto2 | [] [] [] [] | gprof | [] [] | gpsdrive | () () | gramadoir | [] [] | grep | [] [] [] [] [] [] | gretl | | gsasl | | gss | | gst-plugins | [] [] [] [] | gst-plugins-base | [] [] [] | gst-plugins-good | [] [] [] [] [] [] [] | gstreamer | [] [] [] [] [] [] [] | gtick | () | gtkam | [] [] [] | gtkorphan | [] [] | gtkspell | [] [] [] [] | gutenprint | [] | hello | [] [] [] [] [] | id-utils | [] [] | impost | | indent | [] [] [] | iso_3166 | [] [] | iso_3166_2 | | iso_4217 | [] | iso_639 | [] [] | jpilot | [] | jtag | | jwhois | | kbd | [] [] [] [] | keytouch | | keytouch-editor | | keytouch-keyboa... | | latrine | () | ld | [] | leafpad | [] [] [] [] [] | libc | [] [] [] [] [] | libexif | [] | libextractor | [] | libgpewidget | [] [] [] | libgpg-error | [] | libgphoto2 | [] [] | libgphoto2_port | [] [] | libgsasl | | libiconv | [] [] | libidn | [] [] | lifelines | [] () | lilypond | [] | lingoteach | | lynx | [] [] [] [] | m4 | [] [] [] [] | mailutils | [] | make | [] [] | man-db | [] () [] [] | minicom | [] [] [] | mysecretdiary | [] [] | nano | [] [] [] | nano_1_0 | [] () [] [] | opcodes | [] | parted | | pilot-qof | [] | psmisc | [] | pwdutils | | python | | qof | | radius | [] | recode | [] [] [] [] [] [] | rpm | [] [] | screem | | scrollkeeper | [] [] [] [] [] [] [] [] | sed | [] [] [] | sh-utils | [] [] | shared-mime-info | [] [] [] [] | sharutils | [] [] [] [] [] [] | shishi | | silky | | skencil | [] () | sketch | [] () | solfege | | soundtracker | [] [] | sp | [] | stardict | [] | system-tools-ba... | [] [] [] [] [] [] [] [] [] | tar | [] | texinfo | [] [] [] | textutils | [] [] [] | tin | () () | tp-robot | [] | tuxpaint | [] [] [] [] [] | unicode-han-tra... | | unicode-transla... | | util-linux | [] [] [] [] | vorbis-tools | [] [] [] [] | wastesedge | () | wdiff | [] [] [] [] | wget | [] [] | xchat | [] [] [] [] [] [] | xkeyboard-config | | xpad | [] [] | +----------------------------------------------------+ af am ar az be bg bs ca cs cy da de el en en_GB eo 10 0 1 2 9 22 1 42 41 2 60 95 16 1 17 16 es et eu fa fi fr ga gl gu he hi hr hu id is it +--------------------------------------------------+ GNUnet | | a2ps | [] [] [] () | aegis | | ant-phone | [] | anubis | [] | ap-utils | [] [] | aspell | [] [] [] | bash | [] [] [] | batchelor | [] [] | bfd | [] | bibshelf | [] [] [] | binutils | [] [] [] | bison | [] [] [] [] [] [] | bison-runtime | [] [] [] [] [] | bluez-pin | [] [] [] [] [] | cflow | [] | clisp | [] [] | console-tools | | coreutils | [] [] [] [] [] [] | cpio | [] [] [] | cpplib | [] [] | cryptonit | [] | darkstat | [] () [] [] [] | dialog | [] [] [] [] [] [] [] [] | diffutils | [] [] [] [] [] [] [] [] [] | doodle | [] [] | e2fsprogs | [] [] [] | enscript | [] [] [] | error | [] [] [] [] [] | fetchmail | [] | fileutils | [] [] [] [] [] [] | findutils | [] [] [] [] | flex | [] [] [] | fslint | [] | gas | [] [] | gawk | [] [] [] [] | gbiff | [] | gcal | [] [] | gcc | [] | gettext-examples | [] [] [] [] [] [] | gettext-runtime | [] [] [] [] [] [] | gettext-tools | [] [] [] | gimp-print | [] [] | gip | [] [] [] | gliv | () | glunarclock | [] [] [] | gmult | [] [] [] | gnubiff | () () | gnucash | () () () | gnucash-glossary | [] [] | gnuedu | [] | gnulib | [] [] [] [] [] [] [] [] | gnunet-gtk | | gnutls | | gpe-aerial | [] [] | gpe-beam | [] [] | gpe-calendar | | gpe-clock | [] [] [] [] | gpe-conf | [] | gpe-contacts | [] [] | gpe-edit | [] [] [] [] | gpe-filemanager | [] | gpe-go | [] [] [] | gpe-login | [] [] [] | gpe-ownerinfo | [] [] [] [] [] | gpe-package | [] | gpe-sketchbook | [] [] | gpe-su | [] [] [] [] | gpe-taskmanager | [] [] [] | gpe-timesheet | [] [] [] [] | gpe-today | [] [] [] [] | gpe-todo | [] | gphoto2 | [] [] [] [] [] | gprof | [] [] [] [] | gpsdrive | () () [] () | gramadoir | [] [] | grep | [] [] [] [] [] [] [] [] [] [] [] [] | gretl | [] [] [] | gsasl | [] [] | gss | [] | gst-plugins | [] [] [] | gst-plugins-base | [] [] | gst-plugins-good | [] [] [] | gstreamer | [] [] [] | gtick | [] | gtkam | [] [] [] [] | gtkorphan | [] [] | gtkspell | [] [] [] [] [] [] | gutenprint | [] | hello | [] [] [] [] [] [] [] [] [] [] [] [] [] | id-utils | [] [] [] [] [] | impost | [] [] | indent | [] [] [] [] [] [] [] [] [] [] | iso_3166 | [] [] [] | iso_3166_2 | [] | iso_4217 | [] [] [] [] | iso_639 | [] [] [] [] [] | jpilot | [] [] | jtag | [] | jwhois | [] [] [] [] [] | kbd | [] [] | keytouch | [] | keytouch-editor | [] | keytouch-keyboa... | [] | latrine | [] [] [] | ld | [] [] | leafpad | [] [] [] [] [] [] | libc | [] [] [] [] [] | libexif | [] | libextractor | [] | libgpewidget | [] [] [] [] [] | libgpg-error | | libgphoto2 | [] [] [] | libgphoto2_port | [] [] | libgsasl | [] [] | libiconv | [] [] | libidn | [] [] | lifelines | () | lilypond | [] | lingoteach | [] [] [] | lynx | [] [] [] | m4 | [] [] [] [] | mailutils | [] [] | make | [] [] [] [] [] [] [] [] | man-db | () | minicom | [] [] [] [] | mysecretdiary | [] [] [] | nano | [] [] [] [] [] [] | nano_1_0 | [] [] [] [] [] | opcodes | [] [] [] [] | parted | [] [] [] [] | pilot-qof | | psmisc | [] [] [] | pwdutils | | python | | qof | [] | radius | [] [] | recode | [] [] [] [] [] [] [] [] | rpm | [] [] | screem | | scrollkeeper | [] [] [] | sed | [] [] [] [] [] | sh-utils | [] [] [] [] [] [] [] | shared-mime-info | [] [] [] [] [] [] | sharutils | [] [] [] [] [] [] [] [] | shishi | | silky | [] | skencil | [] [] | sketch | [] [] | solfege | [] | soundtracker | [] [] [] | sp | [] | stardict | [] | system-tools-ba... | [] [] [] [] [] [] [] [] | tar | [] [] [] [] [] [] [] | texinfo | [] [] | textutils | [] [] [] [] [] | tin | [] () | tp-robot | [] [] [] [] | tuxpaint | [] [] | unicode-han-tra... | | unicode-transla... | [] [] | util-linux | [] [] [] [] [] [] [] | vorbis-tools | [] [] | wastesedge | () | wdiff | [] [] [] [] [] [] [] [] | wget | [] [] [] [] [] [] [] [] | xchat | [] [] [] [] [] [] [] [] | xkeyboard-config | [] [] [] [] | xpad | [] [] [] | +--------------------------------------------------+ es et eu fa fi fr ga gl gu he hi hr hu id is it 88 22 14 2 40 115 61 14 1 8 1 6 59 31 0 52 ja ko ku ky lg lt lv mk mn ms mt nb ne nl nn no +-------------------------------------------------+ GNUnet | | a2ps | () [] [] () | aegis | () | ant-phone | [] | anubis | [] [] [] | ap-utils | [] | aspell | [] [] | bash | [] | batchelor | [] [] | bfd | | bibshelf | [] | binutils | | bison | [] [] [] | bison-runtime | [] [] [] | bluez-pin | [] [] [] | cflow | | clisp | [] | console-tools | | coreutils | [] | cpio | | cpplib | [] | cryptonit | [] | darkstat | [] [] | dialog | [] [] | diffutils | [] [] [] | doodle | | e2fsprogs | [] | enscript | [] | error | [] | fetchmail | [] [] | fileutils | [] [] | findutils | [] | flex | [] [] | fslint | [] [] | gas | | gawk | [] [] | gbiff | [] | gcal | | gcc | | gettext-examples | [] [] | gettext-runtime | [] [] [] | gettext-tools | [] [] | gimp-print | [] [] | gip | [] [] | gliv | [] | glunarclock | [] [] | gmult | [] [] | gnubiff | | gnucash | () () | gnucash-glossary | [] | gnuedu | | gnulib | [] [] [] [] | gnunet-gtk | | gnutls | | gpe-aerial | [] | gpe-beam | [] | gpe-calendar | [] | gpe-clock | [] [] [] | gpe-conf | [] [] | gpe-contacts | [] | gpe-edit | [] [] [] | gpe-filemanager | [] [] | gpe-go | [] [] [] | gpe-login | [] [] [] | gpe-ownerinfo | [] [] | gpe-package | [] [] | gpe-sketchbook | [] [] | gpe-su | [] [] [] | gpe-taskmanager | [] [] [] [] | gpe-timesheet | [] | gpe-today | [] [] | gpe-todo | [] | gphoto2 | [] [] | gprof | | gpsdrive | () () () | gramadoir | () | grep | [] [] [] [] | gretl | | gsasl | [] | gss | | gst-plugins | [] | gst-plugins-base | | gst-plugins-good | [] | gstreamer | [] | gtick | | gtkam | [] | gtkorphan | [] | gtkspell | [] [] | gutenprint | | hello | [] [] [] [] [] [] | id-utils | [] | impost | | indent | [] [] | iso_3166 | [] | iso_3166_2 | [] | iso_4217 | [] [] [] | iso_639 | [] [] | jpilot | () () () | jtag | | jwhois | [] | kbd | [] | keytouch | [] | keytouch-editor | | keytouch-keyboa... | | latrine | [] | ld | | leafpad | [] [] | libc | [] [] [] [] [] | libexif | | libextractor | | libgpewidget | [] | libgpg-error | | libgphoto2 | [] | libgphoto2_port | [] | libgsasl | [] | libiconv | | libidn | [] [] | lifelines | [] | lilypond | | lingoteach | [] | lynx | [] [] | m4 | [] [] | mailutils | | make | [] [] [] | man-db | () | minicom | [] | mysecretdiary | [] | nano | [] [] [] | nano_1_0 | [] [] [] | opcodes | [] | parted | [] [] | pilot-qof | | psmisc | [] [] [] | pwdutils | | python | | qof | | radius | | recode | [] | rpm | [] [] | screem | [] | scrollkeeper | [] [] [] [] | sed | [] [] | sh-utils | [] [] | shared-mime-info | [] [] [] [] [] | sharutils | [] [] | shishi | | silky | [] | skencil | | sketch | | solfege | | soundtracker | | sp | () | stardict | [] [] | system-tools-ba... | [] [] [] [] | tar | [] [] [] | texinfo | [] [] [] | textutils | [] [] [] | tin | | tp-robot | [] | tuxpaint | [] | unicode-han-tra... | | unicode-transla... | | util-linux | [] [] | vorbis-tools | [] | wastesedge | [] | wdiff | [] [] | wget | [] [] | xchat | [] [] [] [] | xkeyboard-config | [] | xpad | [] [] [] | +-------------------------------------------------+ ja ko ku ky lg lt lv mk mn ms mt nb ne nl nn no 52 24 2 2 1 3 0 2 3 21 0 15 1 97 5 1 nso or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv ta +------------------------------------------------------+ GNUnet | | a2ps | () [] [] [] [] [] [] | aegis | () () | ant-phone | [] [] | anubis | [] [] [] | ap-utils | () | aspell | [] [] | bash | [] [] [] | batchelor | [] [] | bfd | | bibshelf | [] | binutils | [] [] | bison | [] [] [] [] [] | bison-runtime | [] [] [] [] | bluez-pin | [] [] [] [] [] [] [] [] [] | cflow | [] | clisp | [] | console-tools | [] | coreutils | [] [] [] [] | cpio | [] [] [] | cpplib | [] | cryptonit | [] [] | darkstat | [] [] [] [] [] [] | dialog | [] [] [] [] [] [] [] [] [] | diffutils | [] [] [] [] [] [] | doodle | [] [] | e2fsprogs | [] [] | enscript | [] [] [] [] [] | error | [] [] [] [] | fetchmail | [] [] [] | fileutils | [] [] [] [] [] | findutils | [] [] [] [] [] [] | flex | [] [] [] [] [] | fslint | [] [] [] [] | gas | | gawk | [] [] [] [] | gbiff | [] | gcal | [] | gcc | [] | gettext-examples | [] [] [] [] [] [] [] [] | gettext-runtime | [] [] [] [] [] [] [] [] | gettext-tools | [] [] [] [] [] [] [] | gimp-print | [] [] | gip | [] [] [] [] | gliv | [] [] [] [] | glunarclock | [] [] [] [] [] [] | gmult | [] [] [] [] | gnubiff | () | gnucash | () [] | gnucash-glossary | [] [] [] | gnuedu | | gnulib | [] [] [] [] [] | gnunet-gtk | [] | gnutls | [] [] | gpe-aerial | [] [] [] [] [] [] [] | gpe-beam | [] [] [] [] [] [] [] | gpe-calendar | [] | gpe-clock | [] [] [] [] [] [] [] [] | gpe-conf | [] [] [] [] [] [] [] | gpe-contacts | [] [] [] [] [] | gpe-edit | [] [] [] [] [] [] [] [] | gpe-filemanager | [] [] | gpe-go | [] [] [] [] [] [] | gpe-login | [] [] [] [] [] [] [] [] | gpe-ownerinfo | [] [] [] [] [] [] [] [] | gpe-package | [] [] | gpe-sketchbook | [] [] [] [] [] [] [] [] | gpe-su | [] [] [] [] [] [] [] [] | gpe-taskmanager | [] [] [] [] [] [] [] [] | gpe-timesheet | [] [] [] [] [] [] [] [] | gpe-today | [] [] [] [] [] [] [] [] | gpe-todo | [] [] [] [] | gphoto2 | [] [] [] [] [] | gprof | [] [] [] | gpsdrive | [] [] [] | gramadoir | [] [] | grep | [] [] [] [] [] [] [] [] | gretl | [] | gsasl | [] [] [] | gss | [] [] [] | gst-plugins | [] [] [] [] | gst-plugins-base | [] | gst-plugins-good | [] [] [] [] | gstreamer | [] [] [] | gtick | [] | gtkam | [] [] [] [] | gtkorphan | [] | gtkspell | [] [] [] [] [] [] [] [] | gutenprint | [] | hello | [] [] [] [] [] [] [] [] | id-utils | [] [] [] [] | impost | [] | indent | [] [] [] [] [] [] | iso_3166 | [] [] [] [] [] [] | iso_3166_2 | | iso_4217 | [] [] [] [] | iso_639 | [] [] [] [] | jpilot | | jtag | [] | jwhois | [] [] [] [] | kbd | [] [] [] | keytouch | [] | keytouch-editor | [] | keytouch-keyboa... | [] | latrine | [] [] | ld | [] | leafpad | [] [] [] [] [] [] | libc | [] [] [] [] [] | libexif | [] | libextractor | [] [] | libgpewidget | [] [] [] [] [] [] [] | libgpg-error | [] [] | libgphoto2 | [] | libgphoto2_port | [] [] [] | libgsasl | [] [] [] [] | libiconv | [] [] | libidn | [] [] () | lifelines | [] [] | lilypond | | lingoteach | [] | lynx | [] [] [] | m4 | [] [] [] [] [] | mailutils | [] [] [] [] | make | [] [] [] [] | man-db | [] [] | minicom | [] [] [] [] [] | mysecretdiary | [] [] [] [] | nano | [] [] [] | nano_1_0 | [] [] [] [] | opcodes | [] [] | parted | [] | pilot-qof | [] | psmisc | [] [] | pwdutils | [] [] | python | | qof | [] [] | radius | [] [] | recode | [] [] [] [] [] [] [] | rpm | [] [] [] [] | screem | | scrollkeeper | [] [] [] [] [] [] [] | sed | [] [] [] [] [] [] [] [] [] | sh-utils | [] [] [] | shared-mime-info | [] [] [] [] [] | sharutils | [] [] [] [] | shishi | [] | silky | [] | skencil | [] [] [] | sketch | [] [] [] | solfege | [] | soundtracker | [] [] | sp | | stardict | [] [] [] | system-tools-ba... | [] [] [] [] [] [] [] [] [] | tar | [] [] [] [] [] | texinfo | [] [] [] [] | textutils | [] [] [] | tin | () | tp-robot | [] | tuxpaint | [] [] [] [] [] | unicode-han-tra... | | unicode-transla... | | util-linux | [] [] [] [] | vorbis-tools | [] [] | wastesedge | | wdiff | [] [] [] [] [] [] | wget | [] [] [] [] | xchat | [] [] [] [] [] [] [] | xkeyboard-config | [] [] | xpad | [] [] [] | +------------------------------------------------------+ nso or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv ta 0 2 3 58 30 54 5 73 72 4 40 46 11 50 128 2 tg th tk tr uk ven vi wa xh zh_CN zh_HK zh_TW zu +---------------------------------------------------+ GNUnet | [] | 2 a2ps | [] [] [] | 19 aegis | | 0 ant-phone | [] [] | 6 anubis | [] [] [] | 11 ap-utils | () [] | 4 aspell | [] [] [] | 15 bash | [] | 11 batchelor | [] [] | 9 bfd | | 1 bibshelf | [] | 7 binutils | [] [] [] | 9 bison | [] [] [] | 19 bison-runtime | [] [] [] | 15 bluez-pin | [] [] [] [] [] [] | 28 cflow | [] [] | 5 clisp | | 6 console-tools | [] [] | 5 coreutils | [] [] | 16 cpio | [] [] [] | 9 cpplib | [] [] [] [] | 11 cryptonit | | 5 darkstat | [] () () | 15 dialog | [] [] [] [] [] | 30 diffutils | [] [] [] [] | 28 doodle | [] | 6 e2fsprogs | [] [] | 10 enscript | [] [] [] | 16 error | [] [] [] [] | 18 fetchmail | [] [] | 12 fileutils | [] [] [] | 18 findutils | [] [] [] | 17 flex | [] [] | 15 fslint | [] | 9 gas | [] | 3 gawk | [] [] | 15 gbiff | [] | 5 gcal | [] | 5 gcc | [] [] [] | 6 gettext-examples | [] [] [] [] [] [] | 27 gettext-runtime | [] [] [] [] [] [] | 28 gettext-tools | [] [] [] [] [] | 19 gimp-print | [] [] | 12 gip | [] [] | 12 gliv | [] [] | 8 glunarclock | [] [] [] | 15 gmult | [] [] [] [] | 15 gnubiff | [] | 1 gnucash | () | 2 gnucash-glossary | [] [] | 9 gnuedu | [] | 2 gnulib | [] [] [] [] [] | 28 gnunet-gtk | | 1 gnutls | | 2 gpe-aerial | [] [] | 14 gpe-beam | [] [] | 14 gpe-calendar | [] | 3 gpe-clock | [] [] [] [] | 21 gpe-conf | [] [] | 14 gpe-contacts | [] [] | 10 gpe-edit | [] [] [] [] | 20 gpe-filemanager | [] | 6 gpe-go | [] [] | 15 gpe-login | [] [] [] [] [] | 21 gpe-ownerinfo | [] [] [] [] | 21 gpe-package | [] | 6 gpe-sketchbook | [] [] | 16 gpe-su | [] [] [] | 20 gpe-taskmanager | [] [] [] | 20 gpe-timesheet | [] [] [] [] | 18 gpe-today | [] [] [] [] [] | 21 gpe-todo | [] | 7 gphoto2 | [] [] [] [] | 20 gprof | [] [] | 11 gpsdrive | | 4 gramadoir | [] | 7 grep | [] [] [] [] | 34 gretl | | 4 gsasl | [] [] | 8 gss | [] | 5 gst-plugins | [] [] [] | 15 gst-plugins-base | [] [] [] | 9 gst-plugins-good | [] [] [] [] [] | 20 gstreamer | [] [] [] | 17 gtick | [] | 3 gtkam | [] | 13 gtkorphan | [] | 7 gtkspell | [] [] [] [] [] [] | 26 gutenprint | | 3 hello | [] [] [] [] [] | 37 id-utils | [] [] | 14 impost | [] | 4 indent | [] [] [] [] | 25 iso_3166 | [] [] [] [] | 16 iso_3166_2 | | 2 iso_4217 | [] [] | 14 iso_639 | [] | 14 jpilot | [] [] [] [] | 7 jtag | [] | 3 jwhois | [] [] [] | 13 kbd | [] [] | 12 keytouch | [] | 4 keytouch-editor | | 2 keytouch-keyboa... | [] | 3 latrine | [] [] | 8 ld | [] [] [] [] | 8 leafpad | [] [] [] [] | 23 libc | [] [] [] | 23 libexif | [] | 4 libextractor | [] | 5 libgpewidget | [] [] [] | 19 libgpg-error | [] | 4 libgphoto2 | [] | 8 libgphoto2_port | [] [] [] | 11 libgsasl | [] | 8 libiconv | [] | 7 libidn | [] [] | 10 lifelines | | 4 lilypond | | 2 lingoteach | [] | 6 lynx | [] [] [] | 15 m4 | [] [] [] | 18 mailutils | [] | 8 make | [] [] [] | 20 man-db | [] | 6 minicom | [] | 14 mysecretdiary | [] [] | 12 nano | [] [] | 17 nano_1_0 | [] [] [] | 18 opcodes | [] [] | 10 parted | [] [] [] | 10 pilot-qof | [] | 3 psmisc | [] | 10 pwdutils | [] | 3 python | | 0 qof | [] | 4 radius | [] | 6 recode | [] [] [] | 25 rpm | [] [] [] [] | 14 screem | [] | 2 scrollkeeper | [] [] [] [] | 26 sed | [] [] [] | 22 sh-utils | [] | 15 shared-mime-info | [] [] [] [] | 24 sharutils | [] [] [] | 23 shishi | | 1 silky | [] | 4 skencil | [] | 7 sketch | | 6 solfege | | 2 soundtracker | [] [] | 9 sp | [] | 3 stardict | [] [] [] [] | 11 system-tools-ba... | [] [] [] [] [] [] [] | 37 tar | [] [] [] [] | 20 texinfo | [] [] [] | 15 textutils | [] [] [] | 17 tin | | 1 tp-robot | [] [] [] | 10 tuxpaint | [] [] [] | 16 unicode-han-tra... | | 0 unicode-transla... | | 2 util-linux | [] [] [] | 20 vorbis-tools | [] [] | 11 wastesedge | | 1 wdiff | [] [] | 22 wget | [] [] [] | 19 xchat | [] [] [] [] | 29 xkeyboard-config | [] [] [] [] | 11 xpad | [] [] [] | 14 +---------------------------------------------------+ 77 teams tg th tk tr uk ven vi wa xh zh_CN zh_HK zh_TW zu 170 domains 0 1 1 77 39 0 136 10 1 48 5 54 0 2028 Some counters in the preceding matrix are higher than the number of visible blocks let us expect. This is because a few extra PO files are used for implementing regional variants of languages, or language dialects. For a PO file in the matrix above to be effective, the package to which it applies should also have been internationalized and distributed as such by its maintainer. There might be an observable lag between the mere existence a PO file and its wide availability in a distribution. If October 2006 seems to be old, you may fetch a more recent copy of this `ABOUT-NLS' file on most GNU archive sites. The most up-to-date matrix with full percentage details can be found at `http://www.iro.umontreal.ca/contrib/po/HTML/matrix.html'. 1.6 Using `gettext' in new packages =================================== If you are writing a freely available program and want to internationalize it you are welcome to use GNU `gettext' in your package. Of course you have to respect the GNU Library General Public License which covers the use of the GNU `gettext' library. This means in particular that even non-free programs can use `libintl' as a shared library, whereas only free software can use `libintl' as a static library or use modified versions of `libintl'. Once the sources are changed appropriately and the setup can handle the use of `gettext' the only thing missing are the translations. The Free Translation Project is also available for packages which are not developed inside the GNU project. Therefore the information given above applies also for every other Free Software Project. Contact `translation@iro.umontreal.ca' to make the `.pot' files available to the translation teams. gnunet-0.9.3/README0000644000175000017500000002430411761753146010642 00000000000000 Welcome to GNUnet What is GNUnet? =============== GNUnet is peer-to-peer framework focusing on security. The first and primary application for GNUnet is anonymous file-sharing. GNUnet is currently developed by a worldwide group of independent free software developers. GNUnet is a GNU package (http://www.gnu.org/). This is an ALPHA release. There are known and significant bugs as well as many missing features in this release. Additional documentation about GNUnet can be found at https://gnunet.org/. Dependencies: ============= Please note that for many of its dependencies GNUnet requires very recent versions of the libraries which are often NOT to be found in stable distributions in 2011. While using older packages may in some cases on some operating systems may seem to work in some limited fashion, we are in many cases aware of serious problems with older packages. Hence please make sure to use the versions listed below. These are the direct dependencies for running GNUnet: - libextractor >= 0.6.1 - libmicrohttpd >= 0.9.18 - libgcrypt >= 1.2 - libcurl >= 7.21.0 - libunistring >= 0.9.2 - libltdl >= 2.2 (part of GNU libtool) - sqlite >= 3.0 (default database) - mysql >= 5.1 (alternative to sqLite) - postgres >= 8.3 (alternative to sqLite) Recommended autotools for compiling the SVN version are: - autoconf >= 2.59 - automake >= 1.11.1 - libtool >= 2.2 How to install? =============== The fastest way is to use a binary package if it is available for your system. For a more detailed description, read the installation instructions on the webpage at https://gnunet.org/installation. Note that some functions of GNUnet require "root" access. GNUnet will install (tiny) SUID binaries for those functions is you run "make install" as root. If you do not, GNUnet will still work, but some functionality will not be available (including certain forms of NAT traversal). GNUnet requires the GNU MP library (http://www.gnu.org/software/gmp/) and libgcrypt (http://www.gnupg.org/). You can specify the path to libgcrypt by passing "--with-gcrypt=PATH" to configure. You will also need either sqlite (http://www.sqlite.org/), MySQL (http://www.mysql.org/) or PostGres (http://www.postgres.org/). If you install from source, you need to install GNU libextractor first (download from http://www.gnu.org/software/libextractor/). We also recommend installing GNU libmicrohttpd (download from http://www.gnu.org/software/libmicrohttpd/). Then you can start the actual GNUnet compilation and installation process with: $ export GNUNET_PREFIX=/usr/local # or other directory of your choice $ addgroup gnunetdns $ adduser gnunet gnunet $ ./configure --prefix=$GNUNET_PREFIX --with-extractor=$LE_PREFIX $ make # make install # sudo -u gnunet mkdir ~/.gnunet/ # sudo -u gnunet touch ~/.gnunet/gnunet.conf # sudo -u gnunet gnunet-arm -s This will create the users and groups needed for running GNUnet securely and then compile and install GNUnet to $GNUNET_PREFIX/bin/, $GNUNET_PREFIX/lib/ and $GNUNET_PREFIX/share/ and start the system with the default configuration. It is strongly recommended that you add a user "gnunet" to run "gnunet-arm". You can then still run the end-user applications as another user. If you create a system user "gnunet", it is recommended that you edit the configuration file slightly so that data can be stored in the system user home directory at "/var/lib/gnunet"; you may also want to use "/etc/gnunet.conf" for the location of the configuration file in this case. You can avoid running 'make install' as root if you run configure with the "--with-sudo=yes" option and have extensive sudo rights (can run "chmod +s" and "chown" via 'sudo'). If you run 'make install' as a normal user without sudo rights (or the configure option), certain binaries that require additional priviledges will not be installed properly (and autonomous NAT traversal, WLAN, DNS/GNS and the VPN will then not work). If you run 'configure' and 'make install' as root or use the SUDO option, GNUnet's build system will install "libnss_gns*" libraries to "/lib/" regardless (!) of the $GNUNET_PREFIX you might have specified, as those libraries must be in "/lib/". If you are packaging GNUnet for binary distribution, this may cause your packaging script to miss those plugins, so you might need to do some additional manual work to include those libraries in your binary package(s). Similarly, if you want to use the GNUnet naming system and did NOT run GNUnet's 'make install' process with SUDO rights, the libraries will be installed to "$GNUNET_PREFIX/lib" and you will have to move them to "/lib/" manually. Finally, if you are compiling the code from subversion, you have to run ". bootstrap" before ./configure. If you receive an error during the running of ". bootstrap" that looks like "macro `AM_PATH_GTK' not found in library", you may need to run aclocal by hand with the -I option, pointing to your aclocal m4 macros, i.e. $ aclocal -I /usr/local/share/aclocal Configuration ============= Note that additional, per-user configuration files (~/.gnunet/gnunet.conf) need to be created by each user (for example, by running gnunet-setup). Note that gnunet-setup is a separate download and requires recent versions of GTK+ and Glade; you can also edit the configuration file by hand, but this is not recommended. For more general information about the GNU build process read the INSTALL file. GNUnet uses two types of configuration files, one that specifies the system-wide defaults (typically located in $GNUNET_PREFIX/share/gnunet/config.d/) and a second one that overrides default values with user-specific preferences. The user-specific configuration file should be located in "~/.gnunet/gnunet.conf" or its location can be specified by giving the "-c" option to the respective GNUnet application. The defaults that are shipped with the installation are usually ok, you may want to adjust the limitations (space consumption, bandwidth, etc.) though. The configuration files are human-readable. Note that you MUST create "~/.gnunet/gnunet.conf" explicitly before starting GNUnet. You can either run gnunet-setup (available as part of the gnunet-gtk source package) or simply create an empty file. Usage ===== First, you must obtain an initial list of GNUnet hosts. Knowing a single peer is sufficient since after that GNUnet propagates information about other peers. Note that the default "gnunet.conf" contains URLs from where GNUnet downloads an initial hostlist whenever it is started. If you want to create an alternative URL for others to use, the file can be generated on any machine running GNUnet by periodically executing $ cat $SERVICEHOME/data/hosts/* > the_file and offering 'the_file' via your web server. Alternatively, you can run the build-in web server by adding '-p' to the OPTIONS value in the "hostlist" section of gnunet.conf and opening the respective HTTPPORT to the public. If the solution with the hostlist URL is not feasible for your situation, you can also add hosts manually. Simply copy the hostkeys to "$SERVICEHOME/data/hosts/" (where $SERVICEHOME is the directory specified in the gnunet.conf configuration file). Now start the local node using "gnunet-arm -s". GNUnet should run 24/7 if you want to maximize your anonymity. You should then be able to access GNUnet using the shell: $ gnunet-search KEYWORD This will display a list of results to the console. Then use $ gnunet-download -o FILENAME GNUNET_URI to retrieve a file. The GNUNET_URI is printed by gnunet-search together with a description. To publish files on GNUnet, use the "gnunet-publish" command. The GTK user interface is shipped separately. After downloading and installing gnunet-gtk, you can invoke the setup tool and the file-sharing GUI with: $ gnunet-setup $ gnunet-fs-gtk For further documentation, see our webpage. Hacking GNUnet ============== Contributions are welcome, please submit bugs to https://gnunet.org/bugs/. Please make sure to run contrib/report.sh and include the output with your bug reports. More about how to report bugs can be found in the GNUnet FAQ on the webpage. Submit patches via E-Mail to gnunet-developers@gnu.org. In order to run the unit tests with "make check", you need to set an environment variable ("GNUNET_PREFIX") to the directory where GNUnet is installed (usually, GNUnet will use OS specific tricks in order to try to figure out the PREFIX, but since the testcase binaries are not installed, that trick does not work for them). Also, before running any testcases, you must complete the installation first. Quick summary: $ ./configure --prefix=$SOMEWHERE $ make $ make install $ export GNUNET_PREFIX=$SOMEWHERE $ make check Some of the testcases require python >= 2.6 and pexpect to be installed. If any testcases fail to pass on your system, run "contrib/report.sh" and report the output together with information about the failing testcase to the Mantis bugtracking system at https://gnunet.org/bugs/. Running http on port 80 and https on port 443 ============================================= In order to hide GNUnet's HTTP/HTTPS traffic perfectly, you might consider running GNUnet's HTTP/HTTPS transport on port 80/443. However, we do not recommend running GNUnet as root. Instead, forward port 80 to say 1080 with this command (as root, in your startup scripts): # iptables -t nat -A PREROUTING -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 1080 or for HTTPS # iptables -t nat -A PREROUTING -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 4433 Then set in the HTTP section of gnunet.conf the "ADVERTISED_PORT" to "80" and "PORT" to 1080 and similarly in the HTTPS section the "ADVERTISED_PORT" to "443" and "PORT" to 4433. You can do the same trick for the TCP and UDP transports if you want to map them to a priviledged port (from the point of view of the network). However, we are not aware of this providing any advantages at this point. Stay tuned ========== * https://gnunet.org/ * https://gnunet.org/bugs/ * https://gnunet.org/svn/ * http://www.gnu.org/software/gnunet/ * http://mail.gnu.org/mailman/listinfo/gnunet-developers * http://mail.gnu.org/mailman/listinfo/help-gnunet * http://mail.gnu.org/mailman/listinfo/info-gnunet * http://mail.gnu.org/mailman/listinfo/gnunet-svn gnunet-0.9.3/compile0000755000175000017500000000727111762217210011330 00000000000000#! /bin/sh # Wrapper for compilers which do not understand `-c -o'. scriptversion=2009-10-06.20; # UTC # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2009 Free Software # Foundation, Inc. # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . case $1 in '') echo "$0: No command. Try \`$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand `-c -o'. Remove `-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file `INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; esac ofile= cfile= eat= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as `compile cc -o foo foo.c'. # So we strip `-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no `-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # `.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use `[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: gnunet-0.9.3/config.guess0000755000175000017500000012761511762217210012277 00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 # Free Software Foundation, Inc. timestamp='2009-11-20' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner. Please send patches (context # diff format) to and include a ChangeLog # entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[456]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) case ${UNAME_MACHINE} in pc98) echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-gnu else echo ${UNAME_MACHINE}-unknown-linux-gnueabi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; i*86:Linux:*:*) LIBC=gnu eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in i386) eval $set_cc_for_build if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then UNAME_PROCESSOR="x86_64" fi fi ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: gnunet-0.9.3/doc/0000755000175000017500000000000011763406747010610 500000000000000gnunet-0.9.3/doc/man/0000755000175000017500000000000011763406747011363 500000000000000gnunet-0.9.3/doc/man/gnunet-download.10000644000175000017500000001502611722230374014460 00000000000000.TH GNUNET-DOWNLOAD "1" "25 Feb 2012" "GNUnet" .SH NAME gnunet\-download \- a command line interface for downloading files from GNUnet .SH SYNOPSIS .B gnunet\-download [\fIOPTIONS\fR] \-\- GNUNET_URI .SH DESCRIPTION .PP Download files from GNUnet. .TP \fB\-a \fILEVEL\fR, \fB\-\-anonymity=LEVEL\fR set desired level of receiver anonymity. Default is 1. .TP \fB\-c \fIFILENAME\fR, \fB\-\-config=FILENAME\fR use config file (defaults: ~/.gnunet/gnunet.conf) .TP \fB\-D, \fB\-\-delete\-incomplete\fR causes gnunet\-download to delete incomplete downloads when aborted with CTRL\-C. Note that complete files that are part of an incomplete recursive download will not be deleted even with this option. Without this option, terminating gnunet\-download with a signal will cause incomplete downloads to stay on disk. If gnunet\-download runs to (normal) completion finishing the download, this option has no effect. .TP \fB\-h\fR, \fB\-\-help\fR print help page .TP \fB\-L \fILOGLEVEL\fR, \fB\-\-loglevel=LOGLEVEL\fR Change the loglevel. Possible values for LOGLEVEL are ERROR, WARNING, INFO and DEBUG. .TP \fB\-n\fR, \fB\-\-no-network\fR Only search locally, do not forward requests to other peers. .TP \fB\-o \fIFILENAME\fR, \fB\-\-output=FILENAME\fR write the file to FILENAME. Hint: when recursively downloading a directory, append a '/' to the end of the FILENAME to create a directory of that name. If no FILENAME is specified, gnunet\-download constructs a temporary ID from the URI of the file. The final filename is constructed based on meta\-data extracted using libextractor (if available). .TP \fB\-p \fIDOWNLOADS\fR, \fB\-\-parallelism=DOWNLOADS\fR set the maximum number of parallel downloads that is allowed. More parallel downloads can, to some extent, improve the overall time to download content. However, parallel downloads also take more memory (see also option \-r which can be used to limit memory utilization) and more sockets. This option is used to limit the number of files that are downloaded in parallel (\-r can be used to limit the number of blocks that are concurrently requested). As a result, the value only matters for recursive downloads. The default value is 32. .TP \fB\-r \fIREQUESTS\fR, \fB\-\-request-parallelism=REQUESTS\fR set the maximum number of parallel requests that is allowed. If multiple files are downloaded, gnunet\-download will not run them in parallel if this would cause the number of pending requests to possibly exceed the given value. This is useful since, for example, downloading dozens of multi\-gigabyte files in parallel could exhaust memory resources and would hardly improve performance. Note that the limit only applies to this specific process and that other download activities by other processes are not included in this limit. Consider raising this limit for large recursive downloads with many large files if memory and network bandwidth are not fully utilized and if the parallelism limit (\-p option) is not reached. This option also only matters for recursive downloads. The default value is 4092. .TP \fB\-R\fR, \fB\-\-recursive\fR download directories recursively (and in parallel); note that the URI must belong to a GNUnet directory and that the filename given must end with a '/' \-\- otherwise, only the file corresponding to the URI will be downloaded. Note that in addition to using '-R', you must also specify a filename ending in '.gnd' so that the code realizes that the top-level file is a directory (since we have no meta data). .TP \fB\-v\fR, \fB\-\-version\fR print the version number .TP \fB\-V\fR, \fB\-\-verbose\fR print progress information .SH NOTES The GNUNET_URI is typically obtained from gnunet\-search. gnunet\-fs\-gtk can also be used instead of gnunet\-download. If you ever have to abort a download, you can at any time continue it by re\-issuing gnunet\-download with the same filename. In that case GNUnet will not download blocks again that are already present. GNUnet's file\-encoding will ensure file integrity, even if the existing file was not downloaded from GNUnet in the first place. Temporary information will be appended to the target file until the download is completed. .SH SETTING ANONYMITY LEVEL The \fB\-a\fR option can be used to specify additional anonymity constraints. If set to 0, GNUnet will try to download the file as fast as possible, including using non-anonymous methods. If you set it to 1 (default), you use the standard anonymous routing algorithm (which does not explicitly leak your identity). However, a powerful adversary may still be able to perform traffic analysis (statistics) to over time infer data about your identity. You can gain better privacy by specifying a higher level of anonymity, which increases the amount of cover traffic your own traffic will get, at the expense of performance. Note that your download performance is not only determined by your own anonymity level, but also by the anonymity level of the peers publishing the file. So even if you download with anonymity level 0, the peers publishing the data might be sharing with a higher anonymity level, which in this case will determine performance. Also, peers that cache content in the network always use anonymity level 1. This option can be used to limit requests further than that. In particular, you can require GNUnet to receive certain amounts of traffic from other peers before sending your queries. This way, you can gain very high levels of anonymity \- at the expense of much more traffic and much higher latency. So set it only if you really believe you need it. The definition of ANONYMITY\-RECEIVE is the following. 0 means no anonymity is required. Otherwise a value of 'v' means that 1 out of v bytes of "anonymous" traffic can be from the local user, leaving 'v-1' bytes of cover traffic per byte on the wire. Thus, if GNUnet routes n bytes of messages from foreign peers (using anonymous routing), it may originate n/(v-1) bytes of queries in the same time\-period. The time\-period is twice the average delay that GNUnet defers forwarded queries. The default is 1 and this should be fine for most users. Also notice that if you choose very large values, you may end up having no throughput at all, especially if many of your fellow GNUnet\-peers all do the same. .SH FILES .TP ~/.gnunet/gnunet.conf GNUnet configuration file .SH "REPORTING BUGS" Report bugs to or by sending electronic mail to .SH "SEE ALSO" \fBgnunet\-fs\-gtk\fP(1), \fBgnunet\-publish\fP(1), \fBgnunet\-search\fP(1), \fBgnunet.conf\fP(5), \fBgnunet\-service\-fs\fP(1) gnunet-0.9.3/doc/man/gnunet-directory.10000644000175000017500000000576311722227223014663 00000000000000.TH gnunet-directory "1" "25 Feb 2012" "GNUnet" .SH NAME gnunet\-directory \- display directories .SH SYNOPSIS .B gnunet\-directory [\fIOPTIONS\fR] (FILENAME)* .SH DESCRIPTION .PP gnunet\-directory lists the contents of one or more GNUnet directories. A GNUnet directory is a binary file that contains a list of GNUnet file\-sharing URIs and meta data. The names of the directory files must be passed as command\-line arguments to gnunet\-directory. .TP \fB\-c \fIFILENAME\fR, \fB\-\-config=FILENAME\fR configuration file to use (useless option since gnunet\-directory does not really depend on any configuration options) .TP \fB\-h\fR, \fB\-\-help\fR print help page .TP \fB\-L \fILOGLEVEL\fR, \fB\-\-loglevel=LOGLEVEL\fR Change the loglevel. Possible values for LOGLEVEL are ERROR, WARNING, INFO and DEBUG. .TP \fB\-v\fR, \fB\-\-version\fR print the version number .SH NOTES A GNUnet directory is a file containing a list of GNUnet URIs and meta data. The keys can point to files, other directories or files in namespaces. In other words, a GNUnet directory is similar to UNIX directories. The difference to tar and zip is that GNUnet directory does not contain the actual files (except if they are really small, in which case they may be inlined), just symbolic (links), similar to directories with symbolic links in UNIX filesystems. The benefit is that the individual files can be retrieved separately (if desired) and if some of the files are inserted to another node in GNUnet, this just increases their availability but does not produce useless duplicates (for example, it is a better idea to publish a collection of pictures or compressed sound files using a GNUnet directory instead of processing them with archivers such as tar or zip first). Directories can contain arbitrary meta data for each file. If a directory has missing blocks (for example, some blocks failed to download), GNUnet is typically able to retrieve information about other files in the directory. Files in a GNUnet directory have no particular order; the GNUnet code that generates a directory can reorder the entries in order to better fit the information about files into blocks of 32k. Respecting 32k boundaries where possible makes it easier for gnunet\-directory (and other tools) to recover information from partially downloaded directory files. At the moment, directories can be created by \fBgnunet\-fs\-gtk\fP and \fBgnunet\-publish\fP. Just like ordinary files, a directory can be published in a namespace. GNUnet directories use the (unregistered) mimetype \fBapplication/gnunet\-directory\fP. They can show up among normal search results. The directory file can be downloaded to disk by \fBgnunet\-download\fP(1) for later processing or be handled more directly by \fBgnunet\-fs\-gtk\fP(1). .SH "REPORTING BUGS" Report bugs by using mantis or by sending electronic mail to .SH "SEE ALSO" \fBgnunet\-fs\-gtk\fP(1), \fBgnunet\-publish\fP(1), \fBgnunet\-search\fP(1), \fBgnunet\-download\fP(1) gnunet-0.9.3/doc/man/gnunet-namestore.10000644000175000017500000000337311725136552014656 00000000000000.TH GNUNET\-NAMESTORE 1 "Mar 5, 2012" "GNUnet" .SH NAME gnunet\-namestore \- manipulate GNUnet zones .SH SYNOPSIS .B gnunet\-namestore .RI [ options ] -z ZONEFILE .br .SH DESCRIPTION \fBgnunet\-namestore\fP can be used to create and manipulate a GNS zone. .SH OPTIONS .B .IP "\-a, \-\-add" Desired operation is adding a record .B .IP "\-c FILENAME, \-\-config=FILENAME" Use the configuration file FILENAME. .B .IP "\-d, \-\-delete" Desired operation is deleting a record .B .IP "\-D, \-\-display" Desired operation is listing of matching records .B .IP "\-e TIME, \-\-expiration=TIME" Specifies expiration time of record to add; format is relative time, i.e "1 h" or "7 d 30 m". Supported units are "ms", "s", "min" or "minutes", "h" (hours), "d" (days) and "a" (years). .B .IP "\-h, \-\-help" Print short help on options. .B .IP "\-L LOGLEVEL, \-\-loglevel=LOGLEVEL" Use LOGLEVEL for logging. Valid values are DEBUG, INFO, WARNING and ERROR. .B .IP "\-n NAME, \-\-name=NAME" Name of the record to add/delete/display .B .IP "\-t TYPE, \-\-type=TYPE" Type of the record to add/delete/display (i.e. "A", "AAAA", "NS", "PKEY", "MX" etc.) .B .IP "\-v, \-\-version" Print GNUnet version number. .B .IP "\-V VALUE, \-\-value=VALUE" Value to store or remove from the GNS zone. Specific format depends on the record type. A records expect a dotted decimal IPv4 address, AAAA records an IPv6 address, PKEY a public key in GNUnet's printable format, and CNAME and NS records should be a domain name. .B .IP "\-z FILENAME, \-\-zonekey=FILENAME" Specifies the filename with the private key for the zone (mandatory option) .SH BUGS Report bugs by using Mantis or by sending electronic mail to .SH "SEE ALSO" \fBgnunet\-gns\fP(1) gnunet-0.9.3/doc/man/Makefile.am0000644000175000017500000000063711736004647013336 00000000000000man_MANS = \ gnunet-arm.1 \ gnunet-core.1 \ gnunet-directory.1 \ gnunet-download.1 \ gnunet-download-manager.1 \ gnunet-fs.1 \ gnunet-gns.1 \ gnunet-namestore.1 \ gnunet-nat-server.1 \ gnunet-peerinfo.1 \ gnunet-pseudonym.1 \ gnunet-publish.1 \ gnunet-rsa.1 \ gnunet-search.1 \ gnunet-statistics.1 \ gnunet-transport.1 \ gnunet-unindex.1 \ gnunet-vpn.1 EXTRA_DIST = ${man_MANS} gnunet-0.9.3/doc/man/gnunet-gns.10000644000175000017500000000143511725136546013450 00000000000000.TH GNUNET\-GNS 1 "Mar 5, 2012" "GNUnet" .SH NAME gnunet\-gns \- manipulate GNUnet GNS zones .SH SYNOPSIS .B gnunet\-gns .RI [ options ] -z ZONEFILE .br .SH DESCRIPTION \fBgnunet\-gns\fP can be used to create and manipulate a GNS zone. .SH OPTIONS .B .IP "\-c FILENAME, \-\-config=FILENAME" Use the configuration file FILENAME. .B .IP "\-h, \-\-help" Print short help on options. .B .IP "\-L LOGLEVEL, \-\-loglevel=LOGLEVEL" Use LOGLEVEL for logging. Valid values are DEBUG, INFO, WARNING and ERROR. .B .IP "\-s NAME, \-\-shorten=NAME" GNS domain name to shorten .B .IP "\-v, \-\-version" Print GNUnet version number. .SH BUGS Report bugs by using Mantis or by sending electronic mail to .SH "SEE ALSO" \fBgnunet\-namestore\fP(1) gnunet-0.9.3/doc/man/gnunet-rsa.10000644000175000017500000000256611731702725013447 00000000000000.TH GNUNET\-RSA 1 "Mar 15, 2012" "GNUnet" .SH NAME gnunet\-rsa \- manipulate GNUnet RSA key files .SH SYNOPSIS .B gnunet\-rsa .RI [ options ] FILENAME .br .SH DESCRIPTION \fBgnunet\-rsa\fP can be used to create an RSA private key and to print the corresponding public key. You must specify a filename containing an RSA private key in GNUnet format as an argument. If the file does not exist, gnunet\-rsa will create a key. This may then take a while. If the option \-p is given, the corresponding public key will be printed to the console. .SH OPTIONS .B .IP "\-p, \-\-print-public-key" Print the corresponding public key to stdout. .B .IP "\-P, \-\-print-peer-identity" Print the corresponding peer identity (hash of the public key) to stdout. This hash is used for the name of peers. .B .IP "\-s, \-\-print-short-identity" Print the corresponding short hash (256-bit hash of the public key) to stdout. This hash is used for names in the zkey zone. .B .IP "\-c FILENAME, \-\-config=FILENAME" Use the configuration file FILENAME. .B .IP "\-h, \-\-help" Print short help on options. .B .IP "\-L LOGLEVEL, \-\-loglevel=LOGLEVEL" Use LOGLEVEL for logging. Valid values are DEBUG, INFO, WARNING and ERROR. .B .IP "\-v, \-\-version" Print GNUnet version number. .SH BUGS Report bugs by using Mantis or by sending electronic mail to gnunet-0.9.3/doc/man/gnunet-fs.10000644000175000017500000000214511655176023013264 00000000000000.TH gnunet\-fs "1" "2 Nov 2011" "GNUnet" .SH NAME gnunet\-fs \- measure and control the fs subsystem .SH SYNOPSIS .B gnunet\-fs [\fIOPTIONS\fR] .SH DESCRIPTION .PP gnunet\-fs is a tool to access various functions of GNUnet's fs subsystem from the command\-line. Most of these are not expected to be useful for end-users. gnunet\-fs can currently only be used to obtain a list of indexed files. Other functions should be added in the near future. .TP \fB\-c \fIFILENAME\fR, \fB\-\-config=FILENAME\fR configuration file to use .TP \fB\-h\fR, \fB\-\-help\fR print help page .TP \fB\-i\fR, \fB\-\-list-indexed\fR print information about files that are currently indexed by file-sharing .TP \fB\-L \fILOGLEVEL\fR, \fB\-\-loglevel=LOGLEVEL\fR Change the loglevel. Possible values for LOGLEVEL are ERROR, WARNING, INFO and DEBUG. .TP \fB\-v\fR, \fB\-\-version\fR print the version number .TP \fB\-V\fR, \fB\-\-verbose\fR be verbose .SH NOTES .SH "REPORTING BUGS" Report bugs by using mantis or by sending electronic mail to .SH "SEE ALSO" \fBgnunet\-publish\fP(1) gnunet-0.9.3/doc/man/gnunet-vpn.10000644000175000017500000000521011722227231013444 00000000000000.TH GNUNET\-VPN 1 "25 Feb 2012" "GNUnet" .SH NAME gnunet\-vpn \- manually setup a GNUnet VPN tunnel .SH SYNOPSIS .B gnunet\-vpn .RI [ options ] .br .SH DESCRIPTION \fBgnunet\-vpn\fP can be used to manually setup a VPN tunnel via the GNUnet network. There are two main types of tunnels. Tunnels to an exit node which routes the traffic to the global Internet, and tunnels to a node that runs a service only within GNUnet. Depending on the type of tunnel, gnunet\-vpn takes different options. The "\-i" option is required for tunnels to an exit node, whereas the "\-p" and "\-s" options in conjunction with either "\-u" or "\-t" are required for tunnels to services. For exit tunnels, both UDP and TCP traffic will be redirected. For service tunnels, either UDP ("\-u") or TCP ("\-t") traffic will be redirected. The tool will display the IP address for this end of the tunnel. The address can be displayed as soon as it has been allocated, or only after ("\-a") the tunnel has been created. .SH OPTIONS .B .IP "\-4, \-\-ipv4" Desired IP address on this end of the tunnel should be an IPv4 address. .B .IP "\-6, \-\-ipv6" Desired IP address on this end of the tunnel should be an IPv6 address. .B .IP "\-a, \-\-after\-connect" Display IP address only after the tunnel is fully connected. .B .IP "\-c FILENAME, \-\-config=FILENAME" Use the configuration file FILENAME. .B .IP "\-d SEC, \-\-duration SEC" The mapping should be established for SEC seconds. Default is 5 minutes. .B .IP "\-h, \-\-help" Print short help on options. .B .IP "\-i IP, \-\-ip IP" Tunnel should be to an exit node and connect to the given IPv4 or IPv6 IP address. Note that you can specify an IPv6 address as the target here, even in combination with "\-4" (4to6) and similarly you can specify an IPv4 address in combination with "\-6" (6to4). .B .IP "\-L LOGLEVEL, \-\-loglevel=LOGLEVEL" Use LOGLEVEL for logging. Valid values are DEBUG, INFO, WARNING and ERROR. .B .IP "\-p PEERID, \-\-peer=PEERID" Name of the peer offering the service to connect to. Cannot be used in conjunction with "\-i", requires "\-s". .B .IP "\-s NAME, \-\-service=NAME" Name of the service running on the target peer. Cannot be used in conjunction with "\-i", requires "\-p". .B .IP "\-t, \-\-tcp" Service runs TCP. Either "\-t" or "\-u" must be specified when using "\-s". .B .IP "\-u, \-\-udp" Service runs UDP. Either "\-t" or "\-u" must be specified when using "\-s". .B .IP "\-V, \-\-verbose" Be verbose. .B .IP "\-v, \-\-version" Print GNUnet version number. .SH BUGS Report bugs by using Mantis or by sending electronic mail to .SH SEE ALSO gnunet\-setup(1) gnunet-0.9.3/doc/man/gnunet-unindex.10000644000175000017500000000233111635157371014326 00000000000000.TH GNUNET-UNINDEX "1" "6 Sep 2009" "GNUnet" .SH NAME gnunet\-unindex \- a command line interface for deleting indexed files from GNUnet .SH SYNOPSIS .B gnunet\-unindex [\fIOPTIONS\fR] FILENAME .SH DESCRIPTION .PP gnunet\-unindex is used for deleting indexed files from GNUnet. .TP \fB\-c \fIFILENAME\fR, \fB\-\-config=FILENAME\fR use config file (defaults: ~/.gnunet/gnunet.conf) .TP \fB\-h\fR, \fB\-\-help\fR print help page .TP \fB\-L \fILOGLEVEL\fR, \fB\-\-loglevel=LOGLEVEL\fR Change the loglevel. Possible values for LOGLEVEL are NOTHING, ERROR, WARNING, INFO and DEBUG. .TP \fB\-v\fR, \fB\-\-version\fR print the version number .TP \fB\-V\fR, \fB\-\-verbose\fR be verbose .SH NOTES You can only unindex files that you indexed and that you still have available locally in full. You should use gnunet\-unindex on files that you indexed (not inserted) and that you are going to delete or move locally. .TP .SH FILES .TP ~/.gnunet/gnunet.conf GNUnet configuration file .SH "REPORTING BUGS" Report bugs to or by sending electronic mail to .SH "SEE ALSO" \fBgnunet\-fs\-gtk\fP(1), \fBgnunet\-publish\fP(1), \fBgnunet\-search\fP(1), \fBgnunet\-download\fP(1), \fBgnunet.conf\fP(5) gnunet-0.9.3/doc/man/gnunet-arm.10000644000175000017500000000370011724074662013434 00000000000000.TH GNUNET\-ARM 1 "Jan 4, 2012" "GNUnet" .SH NAME gnunet\-arm \- control GNUnet services .SH SYNOPSIS .B gnunet\-arm .RI [ options ] .br .SH DESCRIPTION \fBgnunet\-arm\fP can be used to start or stop GNUnet services, including the ARM service itself. The ARM service is a supervisor for GNUnet's service processes. ARM starts services on-demand or as configured and re-starts them if they crash. .SH OPTIONS .B .IP "\-c FILENAME, \-\-config=FILENAME" Use the configuration file FILENAME. .B .IP "\-e, \-\-end" Shutdown all GNUnet services (including ARM itself). Running "gnunet-arm -e" is the usual way to shutdown a GNUnet peer. .B .IP "\-h, \-\-help" Print short help on options. .B .IP "\-L LOGLEVEL, \-\-loglevel=LOGLEVEL" Use LOGLEVEL for logging. Valid values are DEBUG, INFO, WARNING and ERROR. .B .IP "\-i SERVICE, \-\-init=SERVICE" Starts the specified SERVICE if it is not already running. More specifically, this makes the service behave as if it were in the default services list. .B .IP "\-k SERVICE, \-\-kill=SERVICE" Stop the specified SERVICE if it is running. While this will kill the service right now, the service may be restarted immediately if other services depend on it (service is then started 'on-demand'). If the service used to be a 'default' service, its default-service status will be revoked. If the service was not a default service, it will just be (temporarily) stopped, but could be re-started on-demand at any time. .B .IP "\-s, \-\-start" Start all GNUnet default services on this system (and also ARM). Naturally, if a service is demanded by a default service, it will then also be started. Running "gnunet-arm -s" is the usual way to start a GNUnet peer. .B .IP "\-I, \-\-info" List all running services. .B .IP "\-v, \-\-version" Print GNUnet version number. .SH BUGS Report bugs by using Mantis or by sending electronic mail to .SH SEE ALSO gnunet\-service\-arm(1) gnunet-0.9.3/doc/man/gnunet-download-manager.10000644000175000017500000000171111704661565016076 00000000000000.TH GNUNET-DOWNLOAD-MANAGER 1 "15 Jan, 2011" "GNUnet" .SH NAME gnunet-download-manager \- manage downloads across sessions .SH SYNOPSIS .B gnunet\-download\-manager .RI [ options ] .br .SH DESCRIPTION \fBgnunet\-download\-manager\fP is a script that can be used to track download sessions. It makes the process of resuming downloads after a system reboot easier. A typical use is to define an alias (depending on your shell) of the form $ alias gnunet\-download='gnunet\-download\-manager.scm download' Other commands for the download manager include resume (resumes all downloads), status (show status of pending downloads), killall (abort all downloads), settings (for configuration) and help (print help text). gnunet\-download\-manager is a scheme script and will only work if guile is available. .SH BUGS Report bugs by using mantis or by sending electronic mail to .SH SEE ALSO gnunet\-download(1) gnunet-0.9.3/doc/man/gnunet-statistics.10000644000175000017500000000275711701422366015053 00000000000000.TH GNUNET\-STATISTICS 1 "Jan 4, 2012" "GNUnet" .SH NAME gnunet\-statistics \- Display statistics about your GNUnet system .SH SYNOPSIS .B gnunet\-statistics .RI [ options ] .RI [ VALUE ] .br .SH DESCRIPTION \fBgnunet\-statistics\fP is used to display detailed information about various aspect of GNUnet's operation. This tool only works if the "statistics" service is available. gnunet\-statistics can be used to set a value by giving the options \-n, \-s and also a VALUE. .SH OPTIONS .B .IP "\-c FILENAME, \-\-config=FILENAME" Use the configuration file FILENAME. .B .IP "\-h, \-\-help" Print short help on options. .B .IP "\-L LOGLEVEL, \-\-loglevel=LOGLEVEL" Use LOGLEVEL for logging. Valid values are DEBUG, INFO, WARNING and ERROR. .B .IP "\-n NAME, \-\-name=NAME" Each statistic has a name that is unique with in its subsystem. With this option, the output can be restricted to statistics that have a particular name. .B .IP "\-p, \-\-persistent" When setting a value, make the value persistent. If the value used to be persistent and this flag is not given, it will be marked as non\-persistent. .B .IP "\-s SUBSYSTEM, \-\-subsystem=SUBSYSTEM" Statistics are kept for various subsystems. With this option, the output can be restricted to a particular subsystem only. .B .IP "\-v, \-\-version" Print GNUnet version number. .SH BUGS Report bugs by using Mantis or by sending electronic mail to .SH SEE ALSO gnunet\-service\-statistics(1) gnunet-0.9.3/doc/man/gnunet-pseudonym.10000644000175000017500000001374311722227344014703 00000000000000.TH GNUNET-PSEUDONYM "1" "25 Feb 2012" "GNUnet" .SH NAME gnunet\-pseudonym \- create, delete or list pseudonyms .SH SYNOPSIS .B gnunet\-pseudonym [options] .SH DESCRIPTION .PP gnunet\-pseudonym is a tool for managing pseudonyms and namespaces. A pseudonym is the persona that controls a namespace. As such, it is identical to a public\-private RSA key pair. A namespace is a collection of files that have been signed by the corresponding private RSA key. A namespace is typically associated with a nickname and other metadata. Namespaces are an important tool for providing assurances about content integrity and authenticity in GNUnet. Since all of the content in the namespace must have been provided by the same entity, users can form an opinion about that entity and learn to search (or avoid) certain namespaces. gnunet\-pseudonym can be used to list all of the pseudonyms that were created locally, to create new pseudonyms, to delete existing pseudonyms (the namespace will continue to exist, but it will be impossible to add additional data to it) and to list all of the namespaces (with their meta-data) known to the local user. By default, gnunet\-pseudonym lists all pseudonyms that were discovered so far. Creating a new pseudonym requires using the \-C option together with a nickname that is to be used for the namespace. Nicknames must be unique for each user, global uniqueness is desirable but not necessary. If two namespaces in GNUnet use the same nickname all GNUnet tools will display the nickname together with a number which ensures that the name becomes locally unique to avoid ambiguity. Additional options can be passed together with the \-C option to provide additional meta\-data that describes the namespace. Possible meta\-data includes the 'realname' of the person controlling the namespace, a description, the mime\-type for content in the namespace (useful if the namespace is dedicated to some specific type of content) and contact information. One important piece of meta\-data that can be specified is the identifier of a document root, that is the name of a file in the namespace that is a portal to the rest of the content. This is useful to help users find this root in the absence of conventions. Note that all of this meta\-data is optional and should never be trusted blindly. As mentioned before, by default, gnunet\-pseudonym simply lists the meta\-data available for other namespaces. Namespaces can be discovered whenever the peer obtains the namespace advertisement. Namespace advertisements can be found using ordinary keyword\-based searches (by default gnunet\-pseudonym publishes the namespace advertisement under the keyword 'namespace', but the \-k option can be used to specify other keywords) and under the 'empty' identifier of the respective namespace (using a namespace\-search if the namespace ID is already known). For more details about GNUnet namespaces and content encoding please read the 'Encoding for Censorship\-resistant Sharing' (ECRS) paper which can be found on the GNUnet webpage. .TP \fB\-a \fILEVEL\fR, \fB\-\-anonymity=LEVEL\fR set desired level of sender anonymity. Default is 1. .TP \fB\-C NAME\fR, \fB\-\-create=NAME\fR Creates a new pseudonym with the given NAME or creates a new advertisement for the pseudonym with the given NAME (if the pseudonym already exists). .TP \fB\-D NAME\fR, \fB\-\-delete=NAME\fR Delete the pseudonym with the given NAME. .TP \fB\-h\fR, \fB\-\-help\fR Print help page. .TP \fB\-k KEYWORD\fR, \fB\-\-keyword=KEYWORD\fR Publish a namespace advertisement under the keyword 'KEYWORD'. Default is 'namespace' (use with \-C). You can specify \-k multiple times. In that case, the namespace will be published under each of those keywords. .TP \fB\-m \fITYPE:VALUE\fR, \fB\-\-meta=\fITYPE:VALUE\fR For the main file (or directory), set the metadata of the given TYPE to the given VALUE. Note that this will not add the respective VALUE to the set of keywords under which the file can be found. .TP \fB\-o\fR, \fB\-\-only\-local\fR display names of local namespaces (those that we can extend with content because we created them) .TP \fB\-p \fIPRIORITY\fR, \fB\-\-prio=\fIPRIORITY\fR Set the priority of the namespace advertisement (default: 365). If the local database is full, GNUnet will discard the content with the lowest ranking. Note that ranks change over time depending on popularity. The default should be high enough to preserve the locally inserted content in favor of content that migrates from other peers. .TP \fB\-q\fR, \fB\-\-quiet\fR Do not print the list of pseudonyms (only perform create or delete operation). .TP \fB\-r \fILEVEL\fR, \fB\-\-replication=\fILEVEL\fR Set the desired replication level. If CONTENT_PUSHING is set to YES, GNUnet will push each block (for the file) LEVEL times to other peers before doing nomral "random" replication of all content. This option can be used to push some content out into the network harder. Note that pushing content LEVEL times into the network does not guarantee that there will actually be LEVEL replicas. .TP \fB\-R IDENTIFIER\fR, \fB\-\-root=IDENTIFIER\fR Specify the identifier for the root of the namespace. Used in the namespace advertisement to tell users that find the namespace advertisement about an entry\-point into the namespace (use with \-C). Advertisements are only created if "\-C" and "\-r" are specified. .TP \fB\-s ID:VALUE\fR, \fB\-\-set-rating=ID:VALUE\fR Change the rating for the namespace identified by ID by VALUE. For example, "\-s test:-3" decrements the rating of the pseudonym "test" by 3. Note that ratings are purely local. Each user has his own independent rating of namespaces. The rating is merely a way for each user to keep track of his own experience with a given namespace. .SH FILES .TP ~/.gnunet/data/pseudonyms/ Directory where the pseudonyms are stored .SH "REPORTING BUGS" Report bugs by using Mantis or by sending electronic mail to .SH "SEE ALSO" \fBgnunet\-publish\fP(1), \fBgnunet\-search\fP(1) gnunet-0.9.3/doc/man/gnunet-publish.10000644000175000017500000003347611722230614014325 00000000000000.TH GNUNET-PUBLISH "1" "25 Feb 2012" "GNUnet" .SH NAME gnunet\-publish \- a command line interface for publishing new content into GNUnet .SH SYNOPSIS .B gnunet\-publish [\fIOPTIONS\fR] FILENAME .SH DESCRIPTION .PP In order to share files with other GNUnet users, the files must first be made available to GNUnet. GNUnet does not automatically share all files from a certain directory. In fact, even files that are downloaded are not automatically shared. .PP In order to start sharing files, the files must be added either using gnunet\-publish or a graphical interface such as gnunet\-fs\-gtk. The command line tool gnunet\-publish is more useful if many files are supposed to be added. gnunet\-publish can automatically publish batches of files, recursively publish directories, create directories that can be browsed within GNUnet and publish file lists in a namespace. When run on a directory, gnunet\-publish will always recursively publish all of the files in the directory. .PP gnunet\-publish can automatically extract keywords from the files that are shared. Users that want to download files from GNUnet use keywords to search for the appropriate content. You can disable keyword extraction with the \-D option. You can manually add keywords using the \-k option. The keywords are case\-sensitive. .PP You can use automatic meta\-data extraction (based on libextractor) or the command\-line option \-m to specify meta-data. For the \-m option you need to use the form keyword\-type:value. For example, use "\-m os:Linux" to specify that the operating system is Linux. Common meta\-data types are "author name", "title" , "mimetype", "filename", "language", "subject" and "keywords". A full list can be obtained from the extract tool using the option \-\-list. The meta\-data is used to help users in searching for files on the network. .PP In addition to searching for files by keyword, GNUnet allows organizing files into directories. With directories, the user only needs to find the directory in order to be able to download any of the files listed in the directory. Directories can contain pointers to other directories. .PP With gnunet\-publish, it is easy to create new directories simultaneously when adding the files. Simply pass the name of a directory instead of a file. .PP Since keywords can be spammed (any user can add any content under any keyword), GNUnet supports namespaces. A namespace is a subset of the searchspace into which only the holder of a certain pseudonym can add content. Any GNUnet user can create any number of pseudonyms using \fBgnunet\-pseudonym\fR. Pseudonyms are stored in the user's GNUnet directory. While pseudonyms are locally identified with an arbitrary string that the user selects when the pseudonym is created, the namespace is globally known only under the hash of the public key of the pseudonym. Since only the owner of the pseudonym can add content to the namespace, it is impossible for other users to pollute the namespace. gnunet\-publish automatically publishes the top\-directory (or the only file if only one file is specified) into the namespace if a pseudonym is specified. .PP It is possible to update content in GNUnet if that content was placed and obtained from a particular namespace. Updates are only possible for content in namespaces since this is the only way to assure that a malicious party can not supply counterfeited updates. Note that an update with GNUnet does not make the old content unavailable, GNUnet merely allows the publisher to point users to more recent versions. You can use the \-N option to specify the future identifier of an update. When using this option, a GNUnet client that finds the current (\-t) identifier will automatically begin a search for the update (\-N) identifier. If you later publish an update under the (\-N) identifier, both results will be given to the user. .PP You can use automatic meta\-data extraction (based on libextractor) or the command\-line option \-m to specify meta-data. For the \-m option you need to use the form keyword\-type:value. For example, use "\-m os:Linux" to specify that the operating system is Linux. Common meta\-data types are "author", "title" , "mimetype", "filename", "language", "subject" and "keywords". A full list can be obtained from the extract tool using the option \-\-list. The meta\-data is used to help users in searching for files on the network. The keywords are case\-sensitive. .PP GNUnet supports two styles of publishing files on the network. Publishing a file means that a copy of the file is made in the local (!) database of the node. Indexing a file means that an index is added to the local (!) database with symbolic links to the file itself. The links will use the SHA-512 hash of the entire file as the filename. Indexing is generally significantly more efficient and the default choice. However, indexing only works if the indexed file can be read (using the same absolute path) by gnunet-service-fs. If this is not the case, indexing will fail (and gnunet\-publish will automatically revert to publishing instead). Regardless of which method is used to publish the file, the file will be slowly (depending on how often it is requested and on how much bandwidth is available) dispersed into the network. If you publish or index a file and then leave the network, it will almost always NOT be available anymore. \fB\-c \fIFILENAME\fR, \fB\-\-config=FILENAME\fR Use alternate config file (if this option is not specified, the default is ~/.gnunet/gnunet.conf). .TP \fB\-D\fR, \fB\-\-disable\-extractor\fR Disable use of GNU libextractor for finding additional keywords and metadata. .TP \fB\-e\fR, \fB\-\-extract\fR Print the list of keywords that will be used for each file given the current options. Do not perform any indexing or publishing. .TP \fB\-h\fR, \fB\-\-help\fR Print a brief help page with all the options. .TP \fB\-k \fIKEYWORD\fR, \fB\-\-key=KEYWORD\fR additional key to index the content with (to add multiple keys, specify multiple times). Each additional key is case\-sensitive. Can be specified multiple times. The keyword is only applied to the top\-level file or directory. .TP \fB\-L \fILOGLEVEL\fR, \fB\-\-loglevel=\fILOGLEVEL\fR Change the loglevel. Possible values for LOGLEVEL are ERROR, WARNING, INFO and DEBUG. .TP \fB\-m \fITYPE:VALUE\fR, \fB\-\-meta=\fITYPE:VALUE\fR For the main file (or directory), set the metadata of the given TYPE to the given VALUE. Note that this will not add the respective VALUE to the set of keywords under which the file can be found. .TP \fB\-n\fR, \fB\-\-noindex\fR Executive summary: You probably don't need it. Do not index, full publishing. Note that directories, RBlocks, SBlocks and IBlocks are always published (even without this option). With this option, every block of the actual files is stored in encrypted form in the block database of the local peer. While this adds security if the local node is compromised (the adversary snags your machine), it is significantly less efficient compared to on\-demand encryption and is definitely not recommended for large files. .TP \fB\-N \fIID\fR, \fB\-\-next=\fIID\fR Specifies the next ID of a future version of the SBlock. This option is only valid together with the \-P option. This option can be used to specify what the identifier of an updated version will look like. Note that specifying \-i and \-N without \-t is not allowed. .TP \fB\-p \fIPRIORITY\fR, \fB\-\-prio=\fIPRIORITY\fR Executive summary: You probably don't need it. Set the priority of the published content (default: 365). If the local database is full, GNUnet will discard the content with the lowest ranking. Note that ranks change over time depending on popularity. The default should be high enough to preserve the locally published content in favor of content that migrates from other peers. .TP \fB\-P \fINAME\fR, \fB\-\-pseudonym=\fINAME\fR For the top\-level directory or file, create an SBlock that places the file into the namespace specified by the pseudonym NAME. .TP \fB\-r \fILEVEL\fR, \fB\-\-replication=\fILEVEL\fR Set the desired replication level. If CONTENT_PUSHING is set to YES, GNUnet will push each block (for the file) LEVEL times to other peers before doing normal "random" replication of all content. This option can be used to push some content out into the network harder. Note that pushing content LEVEL times into the network does not guarantee that there will actually be LEVEL replicas. .TP \fB\-s\fR, \fB\-\-simulate-only\fR When this option is used, gnunet\-publish will not actually publish the file but just simulate what would be done. This can be used to compute the GNUnet URI for a file without actually sharing it. .TP \fB\-t \fIID\fR, \fB\-\-this=\fIID\fR Specifies the ID of the SBlock. This option is only valid together with the\ \-s option. .TP \fB\-u \fIURI\fR, \fB\-\-uri=\fIURI\fR This option can be used to specify the URI of a file instead of a filename (this is the only case where the otherwise mandatory filename argument must be omitted). Instead of publishing a file or directory and using the corresponding URI, gnunet\-publish will use this URI and perform the selected namespace or keyword operations. This can be used to add additional keywords to a file that has already been shared or to add files to a namespace for which the URI is known but the content is not locally available. .TP \fB\-v\fR, \fB\-\-version\fR Print the version number. .TP \fB\-V\fR, \fB\-\-verbose\fR Be verbose. Using this option causes gnunet\-publish to print progress information and at the end the file identification that can be used to download the file from GNUnet. .SH SETTING ANONYMITY LEVEL The \fB\-a\fR option can be used to specify additional anonymity constraints. If set to 0, GNUnet will publish the file non-anonymously and in fact sign the advertisement for the file using your peer's private key. This will allow other users to download the file as fast as possible, including using non-anonymous methods (DHT, direct transfer). If you set it to 1 (default), you use the standard anonymous routing algorithm (which does not explicitly leak your identity). However, a powerful adversary may still be able to perform traffic analysis (statistics) to over time infer data about your identity. You can gain better privacy by specifying a higher level of anonymity, which increases the amount of cover traffic your own traffic will get, at the expense of performance. Note that regardless of the anonymity level you choose, peers that cache content in the network always use anonymity level 1. The definition of the ANONYMITY LEVEL is the following. 0 means no anonymity is required. Otherwise a value of 'v' means that 1 out of v bytes of "anonymous" traffic can be from the local user, leaving 'v-1' bytes of cover traffic per byte on the wire. Thus, if GNUnet routes n bytes of messages from foreign peers (using anonymous routing), it may originate n/(v-1) bytes of data in the same time\-period. The time\-period is twice the average delay that GNUnet defers forwarded queries. The default is 1 and this should be fine for most users. Also notice that if you choose very large values, you may end up having no throughput at all, especially if many of your fellow GNUnet\-peers all do the same. .SH EXAMPLES .PP \fBBasic examples\fR Index a file COPYING: # gnunet\-publish COPYING Publish a file COPYING: # gnunet\-publish \-n COPYING Index a file COPYING with the keywords \fBgpl\fR and \fBtest\fR: # gnunet\-publish \-k gpl \-k test COPYING Index a file COPYING with description "GNU License", mime-type "text/plain" and keywords \fBgpl\fR and \fBtest\fR: # gnunet\-publish \-m "description:GNU License" \-k gpl \-k test -m "mimetype:text/plain" COPYING \fBUsing directories\fR Index the files COPYING and AUTHORS with keyword \fBtest\fR and build a directory containing the two files. Make the directory itself available under keyword \fBgnu\fR and disable keyword extraction using libextractor: # mkdir gnu # mv COPYING AUTHORS gnu/ # gnunet\-publish \-K test \-k gnu \-D gnu/ Neatly publish an image gallery in \fBkittendir/\fR and its subdirs with keyword \fBkittens\fR for the directory but no keywords for the individual files or subdirs (\-n). Force description for all files: # gnunet\-publish \-n \-m "description:Kitten collection" \-k kittens kittendir/ \fBSecure publishing with namespaces\fR Publish file COPYING with pseudonym RIAA-2 (\-P) and with identifier \fBgpl\fR (\-t) and no updates: # gnunet\-publish \-P RIAA-2 \-t gpl COPYING Recursively index /home/ogg and build a matching directory structure. Publish the top\-level directory into the namespace under the pseudonym RIAA-2 (\-P) under identifier 'MUSIC' (\-t) and promise to provide an update with identifier 'VIDEOS' (\-N): # gnunet\-publish \-P RIAA-2 \-t MUSIC \-N VIDEOS /home/ogg Recursively publish (\-n) /var/lib/mysql and build a matching directory structure, but disable the use of libextractor to extract keywords (\-n). Print the file identifiers (\-V) that can be used to retrieve the files. This will store a copy of the MySQL database in GNUnet but without adding any keywords to search for it. Thus only people that have been told the secret file identifiers printed with the \-V option can retrieve the (secret?) files: # gnunet\-publish \-nV /var/lib/mysql Create a namespace entry 'root' in namespace MPAA-1 and announce that the next update will be called 'next': # gnunet\-publish \-P MPAA-1 -t root \-N next noise.mp3 Update the previous entry, do not allow any future updates: # gnunet\-publish \-P MPAA-1 \-t next noise_updated.mp3 .SH FILES .TP ~/.gnunet/gnunet.conf GNUnet configuration file .SH "REPORTING BUGS" Report bugs to or by sending electronic mail to .SH "SEE ALSO" \fBgnunet\-fs\-gtk\fP(1), \fBgnunet\-pseudonym\fP(1), \fBgnunet\-search\fP(1), \fBgnunet\-download\fP(1), \fBgnunet.conf\fP(5), \fBextract\fP(1) gnunet-0.9.3/doc/man/gnunet-nat-server.10000644000175000017500000000437511722227231014742 00000000000000.TH GNUNET\-NAT\-SERVER 1 "25 Feb 2012" "GNUnet" .SH NAME gnunet\-nat\-server \- help GNUnet setup test network setup with NAT .SH SYNOPSIS .B gnunet\-nat\-server .RI [ options ] .RI PORT .br .SH DESCRIPTION Normal GNUnet end-users should not concern themselves with gnunet\-nat\-server. In fact, distributions are encouraged to consider not shipping it at all. Running gnunet\-nat\-server's is similar to running hostlist servers: it is a special service to the community with special requirements and no benefit to those running the service. This program will listen on the specified PORT for incoming requests to test a peer's network connectivity. Incoming requests can ask it to connect to a given IPv4 address (and port) using TCP or UDP and to send a 2-byte test message using the specified address. The program can also be asked to send a "fake" ICMP response message to a given IPv4 address (for autonomous NAT traversal \-\-\- see the description in the respective research paper). The idea is that gnunet\-nat\-server will be run on some trusted hosts with unrestricted connectivity to allow GNUnet users to test their network configuration. As written, the code allows any user on the Internet to cause the gnunet\-nat\-server to send 2-bytes of arbitrary data to any TCP or UDP port at any address. We believe that this is generally harmless. When running gnunet\-nat\-server, make sure to use a configuration that disables most NAT options but enables 'enable_nat_client' and sets 'internal_address' to the global IP address of your local host. Also, the gnunet\-helper\-nat\-client should be installed locally and run with root privileges (SUID), otherwise the gnunet\-nat\-server will not work properly. Note that gnunet\-nat\-server could be run via gnunet\-arm but typically is not. Also, the name of the host and port that gnunet\-nat\-server is run on should be specified in the NATSERVER option in the [setup] section of the configuration file of hosts that are supposed to autoconfigure with this server. .SH OPTIONS .B .IP "\-c FILENAME, \-\-config=FILENAME" Use the configuration file FILENAME. .SH BUGS Report bugs by using Mantis or by sending electronic mail to .SH SEE ALSO gnunet\-transport(1) gnunet-0.9.3/doc/man/gnunet-peerinfo.10000644000175000017500000000202311421122363014443 00000000000000.TH GNUNET\-PEERINFO 1 "Mar 15, 2009" "GNUnet" .SH NAME gnunet\-peerinfo \- Display information about other peers. .SH SYNOPSIS .B gnunet\-peerinfo .RI [ options ] .br .SH DESCRIPTION .PP \fBgnunet\-peerinfo\fP display the known addresses and trust of known peers. .SH OPTIONS .B .IP "\-c FILENAME, \-\-config=FILENAME" Load config file (default: ~/.gnunet/gnunet.conf) .B .IP "\-h, \-\-help" Print help page .B .IP "\-n, \-\-numeric" Disable resolution of IPs to hostnames .B .IP "\-q, \-\-quiet" Do not print anything but the peer identities .B .IP "\-s, \-\-self" Print only our own identity (together with "\-q", this is the exact line that other peers would have to put in to their friends file in order to consider this peer one of their friends in F2F mode). .B .IP "\-v, \-\-version" Print the version number .B .IP "\-L LOGLEVEL, \-\-loglelvel=LOGLEVEL" Set the loglevel .SH BUGS Report bugs by using mantis or by sending electronic mail to .SH SEE ALSO gnunet.conf(5) gnunet-0.9.3/doc/man/Makefile.in0000644000175000017500000004054211762217210013335 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = doc/man DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ SOURCES = DIST_SOURCES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' man1dir = $(mandir)/man1 am__installdirs = "$(DESTDIR)$(man1dir)" NROFF = nroff MANS = $(man_MANS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ man_MANS = \ gnunet-arm.1 \ gnunet-core.1 \ gnunet-directory.1 \ gnunet-download.1 \ gnunet-download-manager.1 \ gnunet-fs.1 \ gnunet-gns.1 \ gnunet-namestore.1 \ gnunet-nat-server.1 \ gnunet-peerinfo.1 \ gnunet-pseudonym.1 \ gnunet-publish.1 \ gnunet-rsa.1 \ gnunet-search.1 \ gnunet-statistics.1 \ gnunet-transport.1 \ gnunet-unindex.1 \ gnunet-vpn.1 EXTRA_DIST = ${man_MANS} all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/man/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu doc/man/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-man1: $(man_MANS) @$(NORMAL_INSTALL) test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)" @list=''; test -n "$(man1dir)" || exit 0; \ { for i in $$list; do echo "$$i"; done; \ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.1[a-z]*$$/p'; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.1[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ test -z "$$files" || { \ echo " ( cd '$(DESTDIR)$(man1dir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(man1dir)" && rm -f $$files; } tags: TAGS TAGS: ctags: CTAGS CTAGS: distdir: $(DISTFILES) @list='$(MANS)'; if test -n "$$list"; then \ list=`for p in $$list; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ if test -n "$$list" && \ grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ echo " typically \`make maintainer-clean' will remove them" >&2; \ exit 1; \ else :; fi; \ else :; fi @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(MANS) installdirs: for dir in "$(DESTDIR)$(man1dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-man uninstall-man: uninstall-man1 .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ distclean distclean-generic distclean-libtool distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-man1 \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ uninstall uninstall-am uninstall-man uninstall-man1 # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/doc/man/gnunet-transport.10000644000175000017500000000443511714022017014701 00000000000000.TH gnunet\-transport "1" "26 Oct 2011" "GNUnet" .SH NAME gnunet\-transport \- measure and control the transport subsystem .SH SYNOPSIS .B gnunet\-transport [\fIOPTIONS\fR] .SH DESCRIPTION .PP gnunet\-transport is a tool to access various functions of GNUnet's transport subsystem from the command\-line. Most of these are not expected to be useful for end-users. gnunet\-transport can be used to evaluate the performance of the transports, force a peer to connect to another peer (if possible). Other functions should be added in the near future. .TP \fB\-b\fR, \fB\-\-benchmark\fR measure how fast we are receiving data (from all connections). On exit, the data rate will be reported. Runs until aborted with CTRL-C. .TP \fB\-c \fIFILENAME\fR, \fB\-\-config=FILENAME\fR configuration file to use .TP \fB\-C \fIPEER\fR, \fB\-\-connect=PEER\fR peer to connect to (and to use for sending if used in conjunction with \-s) .TP \fB\-h\fR, \fB\-\-help\fR print help page .TP \fB\-i\fR, \fB\-\-information\fR print information about our current connections (once) .TP \fB\-m\fR, \fB\-\-monitor\fR print information about our current connections (continuously) .TP \fB\-L \fILOGLEVEL\fR, \fB\-\-loglevel=LOGLEVEL\fR Change the loglevel. Possible values for LOGLEVEL are ERROR, WARNING, INFO and DEBUG. .TP \fB\-s\fR, \fB\-\-send\fR transmit (dummy) traffic as quickly as possible to the peer specified with the \-C option. The rate will still be limited by the quota(s) determined by the peers (ATS subsystem). Will run until CTRL\-C is pressed or until the connection to the other peer is disrupted. .TP \fB\-t\fR, \fB\-\-test\fR test transport configuration. With this flag, the tool will check if each of the configured transport plugins has a working address. Plugins that do not have a listen port configured will be ignored. The test is performed with the help of an external server (by default running on gnunet.org) which tries to contact the local machine. The test can only work if the local GNUnet peer is not yet running. .TP \fB\-v\fR, \fB\-\-version\fR print the version number .TP \fB\-V\fR, \fB\-\-verbose\fR be verbose .SH NOTES .SH "REPORTING BUGS" Report bugs by using mantis or by sending electronic mail to .SH "SEE ALSO" \fBgnunet\-arm\fP(1) gnunet-0.9.3/doc/man/gnunet-core.10000644000175000017500000000171511736005005013575 00000000000000.TH gnunet\-core "1" "1 Apr 2012" "GNUnet" .SH NAME gnunet\-core \- measure and control the core subsystem .SH SYNOPSIS .B gnunet\-core [\fIOPTIONS\fR] .SH DESCRIPTION .PP gnunet\-core is a tool to access various functions of GNUnet's core subsystem from the command\-line. The only function right now is to list the peers that are directly connected to this peer (with successful cryptographic handshake). .TP \fB\-c \fIFILENAME\fR, \fB\-\-config=FILENAME\fR configuration file to use .TP \fB\-h\fR, \fB\-\-help\fR print help page .TP \fB\-L \fILOGLEVEL\fR, \fB\-\-loglevel=LOGLEVEL\fR Change the loglevel. Possible values for LOGLEVEL are ERROR, WARNING, INFO and DEBUG. .TP \fB\-v\fR, \fB\-\-version\fR print the version number .TP \fB\-V\fR, \fB\-\-verbose\fR be verbose .SH NOTES .SH "REPORTING BUGS" Report bugs by using mantis or by sending electronic mail to .SH "SEE ALSO" \fBgnunet\-transport\fP(1) gnunet-0.9.3/doc/man/gnunet-search.10000644000175000017500000001237311722230317014115 00000000000000.TH GNUNET-SEARCH "1" "25 Feb 2012" "GNUnet" .SH NAME gnunet\-search \- a command line interface to search for content on GNUnet .SH SYNOPSIS .B gnunet\-search [\fIOPTIONS\fR] [+]\fIKEYWORD\fR [[+]\fIKEYWORD\fR]* .B gnunet\-search [\fIOPTIONS\fR] [+]\fIURI\fR .SH DESCRIPTION .PP Search for content on GNUnet. The keywords are case\-sensitive. gnunet\-search can be used both for a search in the global namespace as well as for searching a private subspace. .TP \fB\-a \fILEVEL\fR, \fB\-\-anonymity=\fILEVEL\fR The \fB\-a\fR option can be used to specify additional anonymity constraints. If set to 0, GNUnet will try to download the file as fast as possible, including using non-anonymous methods. If you set it to 1 (default), you use the standard anonymous routing algorithm (which does not explicitly leak your identity). However, a powerful adversary may still be able to perform traffic analysis (statistics) to over time infer data about your identity. You can gain better privacy by specifying a higher level of anonymity, which increases the amount of cover traffic your own traffic will get, at the expense of performance. Note that your download performance is not only determined by your own anonymity level, but also by the anonymity level of the peers publishing the file. So even if you download with anonymity level 0, the peers publishing the data might be sharing with a higher anonymity level, which in this case will determine performance. Also, peers that cache content in the network always use anonymity level 1. This option can be used to limit requests further than that. In particular, you can require GNUnet to receive certain amounts of traffic from other peers before sending your queries. This way, you can gain very high levels of anonymity \- at the expense of much more traffic and much higher latency. So set it only if you really believe you need it. The definition of ANONYMITY\-RECEIVE is the following. 0 means no anonymity is required. Otherwise a value of 'v' means that 1 out of v bytes of "anonymous" traffic can be from the local user, leaving 'v-1' bytes of cover traffic per byte on the wire. Thus, if GNUnet routes n bytes of messages from foreign peers (using anonymous routing), it may originate n/(v-1) bytes of queries in the same time\-period. The time\-period is twice the average delay that GNUnet defers forwarded queries. The default is 1 and this should be fine for most users. Also notice that if you choose very large values, you may end up having no throughput at all, especially if many of your fellow GNUnet\-peers all do the same. .TP \fB\-c \fIFILENAME\fR, \fB\-\-config=\fIFILENAME\fR use config file (defaults: ~/.gnunet/gnunet.conf) .TP \fB\-h\fR, \fB\-\-help\fR print help page .TP \fB\-L \fILOGLEVEL\fR, \fB\-\-loglevel=\fILOGLEVEL\fR Change the loglevel. Possible values for LOGLEVEL are ERROR, WARNING, INFO and DEBUG. .TP \fB\-o \fIFILENAME\fR, \fB\-\-output=\fIFILENAME\fR Writes a GNUnet directory containing all of the search results to FILENAME. .TP \fB\-n\fR, \fB\-\-no-network\fR Only search locally, do not forward requests to other peers. .TP \fB\-N \fIVALUE\fR, \fB\-\-results=\fIVALUE\fR automatically terminate the search after receiving VALUE results. .TP \fB\-t \fIVALUE\fR, \fB\-\-timeout=\fIVALUE\fR Automatically timeout search after VALUE ms. Otherwise the search runs until gnunet\-search is aborted with CTRL\-C. .TP \fB\-v\fR, \fB\-\-version\fR print the version number .TP \fB\-V\fR, \fB\-\-verbose\fR print meta data from search results as well .SH NOTES You can run gnunet\-search with an URI instead of a keyword. The URI can have the format for a namespace search or for a keyword search. For a namespace search, the format is gnunet://fs/sks/NAMESPACE/IDENTIFIER. For a keyword search, use gnunet://fs/ksk/KEYWORD[+KEYWORD]*. If the format does not correspond to a GNUnet URI, GNUnet will automatically assume that keywords are supplied directly. If multiple keywords are passed, gnunet-search will look for content matching any of the keywords. The prefix "+" makes a keyword mandatory. # gnunet\-search "Das Kapital" searches for content matching the keyword "Das Kapital". Whereas # gnunet\-search +Das +Kapital Searches for content matching both mandatory keywords "Das" and "Kapital". Search results are printed by gnunet\-search like this: .P .ad l gnunet\-download \-o "COPYING" gnunet://fs/chk/HASH1.HASH2.SIZE Description: The GNU Public License Mime-type: text/plain .ad b The first line contains the command to run to download the file. The suggested filename in the example is COPYING. The GNUnet URI consists of the key and query hash of the file and finally the size of the file. After the command to download the file GNUnet will print meta\-data about the file as advertised in the search result, here "The GNU Public License" and the mime\-type (see the options for gnunet\-publish on how to supply meta-data by hand). .SH FILES .TP ~/.gnunet/gnunet.conf GNUnet configuration file; specifies the default value for the timeout .SH "REPORTING BUGS" Report bugs to or by sending electronic mail to .SH "SEE ALSO" \fBgnunet\-fs\-gtk\fP(1), \fBgnunet\-publish\fP(1), \fBgnunet\-download\fP(1), \fBgnunet\-pseudonym\fP(1), \fBgnunet.conf\fP(5), gnunet-0.9.3/doc/Makefile.am0000644000175000017500000000007111574463021012546 00000000000000SUBDIRS = man EXTRA_DIST = README.mysql README.postgres gnunet-0.9.3/doc/README.mysql0000644000175000017500000000664611465257214012560 00000000000000How to setup the MySQL database for GNUnet. NOTE: This db module does NOT work with mysql before 4.1 since we need prepared statements. We are generally testing the code against MySQL 5.0 at this point. HIGHLIGHTS Pros + On up-to-date hardware where mysql can be used comfortably, this module will have better performance than the other db choices (according to our tests). + Its often possible to recover the mysql database from internal inconsistencies. The other db choices do not support repair (gnunet-check cannot fix problems internal to the dbmgr!). For example, we have seen several cases where power failure has ruined a gdbm database beyond repair. + much faster (for one of the key benchmarks -- content migration -- we have measure mysql taking 2s for an operation where sqlite takes 150s). Cons - Memory usage (Comment: "I have 1G and it never caused me trouble") - Manual setup MANUAL SETUP INSTRUCTIONS 1) in /etc/gnunet.conf, set DATABASE = mysql 2) Then access mysql as root, $ mysql -u root -p and do the following. [You should replace $USER with the username that will be running the gnunetd process]. CREATE DATABASE gnunet; GRANT select,insert,update,delete,create,alter,drop,create temporary tables ON gnunet.* TO $USER@localhost; SET PASSWORD FOR $USER@localhost=PASSWORD('$the_password_you_like'); FLUSH PRIVILEGES; 3) In the $HOME directory of $USER, create a ".my.cnf" file with the following lines [client] user=$USER password=$the_password_you_like Thats it. Note that .my.cnf file is a security risk unless its on a safe partition etc. The $HOME/.my.cnf can of course be a symbolic link. Even greater security risk can be achieved by setting no password for $USER. Luckily $USER has only priviledges to mess up GNUnet's tables, nothing else (unless you give him more, of course). 4) Still, perhaps you should briefly try if the DB connection works. First, login as $USER. Then use, $ mysql -u $USER mysql> use gnunet; If you get the message "Database changed" it probably works. [If you get "ERROR 2002: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)" it may be resolvable by "ln -s /var/run/mysqld/mysqld.sock /tmp/mysql.sock" so there may be some additional trouble depending on your mysql setup.] 5) If you want to run the testcases, you must create a second database "gnunetcheck" with the same username and password. This database will then be used for testing ("make check"). REPAIRING TABLES - Its probably healthy to check your tables for inconsistencies every now and then, especially after system crashes. - If you get odd SEGVs on gnunetd startup, it might be that the mysql databases have been corrupted. - The tables can be verified/fixed in two ways; 1) by shutting down mysqld (mandatory!) and running # myisamchk -r *.MYI in /var/lib/mysql/gnunet/ (or wherever the tables are stored). Another repair command is "mysqlcheck". The usable command may depend on your mysql build/version. Or, 2) by executing mysql> REPAIR TABLE gn090; PROBLEMS? If you have problems related to the mysql module, your best friend is probably the mysql manual. The first thing to check is that mysql is basically operational, that you can connect to it, create tables, issue queries etc. gnunet-0.9.3/doc/Makefile.in0000644000175000017500000004715411762217210012570 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = doc DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = man EXTRA_DIST = README.mysql README.postgres all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu doc/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. # To change the values of `make' variables: instead of editing Makefiles, # (1) if the variable is set in `config.status', edit `config.status' # (which will cause the Makefiles to be regenerated when you run `make'); # (2) otherwise, pass the desired values on the `make' command line. $(RECURSIVE_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ list='$(SUBDIRS)'; for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ rev="$$rev ."; \ target=`echo $@ | sed s/-recursive//`; \ for subdir in $$rev; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ install-am install-strip tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am check check-am clean clean-generic clean-libtool \ ctags ctags-recursive distclean distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/doc/README.postgres0000644000175000017500000000251111465257202013241 00000000000000How to setup the Postgres database for GNUnet. NOTE: This db module was developed for Postgres 8.3. I have no idea what the minimum version that we require is exactly. HIGHLIGHTS Pros + Easier to setup than MySQL + Real database Cons - Quite slow - Still some setup MANUAL SETUP INSTRUCTIONS 1) in /etc/gnunet.conf, set DATABASE = postgres 2) Then access postgres to create a user; I had to do this to get access and create a user: # su - postgres $ createuser At this point, use the name of the user running gnunet for the role, do not set it to superuser, allow the creation of databases. 3) As that user, create a database (or two): $ createdb gnunet $ createdb gnunetcheck # this way you can run "make check" Thats it. 4) Still, perhaps you should briefly try if the DB connection works. First, login as the user who will run gnunetd. Then use, $ psql gnunet # or gnunetcheck gnunet=> \dt If, after you have started gnunetd at least once, you get a gn090 table here, it probably works. PROBLEMS? If you have problems related to the postgres module, your best friend is probably the postgres manual. The first thing to check is that postgres is basically operational, that you can connect to it, create tables, issue queries etc. (see step 4 above for details). gnunet-0.9.3/pkgconfig/0000755000175000017500000000000011763406752012006 500000000000000gnunet-0.9.3/pkgconfig/gnunettransport.pc.in0000644000175000017500000000043511760502552016126 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: GNUnet transport Description: Library to access the low-level GNUnet P2P IO service URL: http://gnunet.org Version: @VERSION@ Requires: Libs: -L${libdir} -lgnunettransport Cflags: -I${includedir} gnunet-0.9.3/pkgconfig/gnunethello.pc.in0000644000175000017500000000042111760502552015170 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: GNUnet hello Description: Helper library for handling GNUnet HELLO messages URL: http://gnunet.org Version: @VERSION@ Requires: Libs: -L${libdir} -lgnunethello Cflags: -I${includedir} gnunet-0.9.3/pkgconfig/Makefile.am0000644000175000017500000000240311616304440013745 00000000000000pcfiles = \ gnunetarm.pc \ gnunetblock.pc \ gnunetcore.pc \ gnunetdatacache.pc \ gnunetdatastore.pc \ gnunetdht.pc \ gnunetdhtlog.pc \ gnunetdv.pc \ gnunetfragmentation.pc \ gnunetfs.pc \ gnunethello.pc \ gnunetnse.pc \ gnunetnat.pc \ gnunetpeerinfo.pc \ gnunetstatistics.pc \ gnunettesting.pc \ gnunettransport.pc \ gnunetutil.pc all-local: $(pcfiles) cp_verbose = $(cp_verbose_$(V)) cp_verbose_ = $(cp_verbose_$(AM_DEFAULT_VERBOSITY)) cp_verbose_0 = @echo " CP $@"; %.pc: %.pc $(cp_verbose_0)cp $< $@ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = $(pcfiles) EXTRA_DIST = \ gnunetarm.pc.in \ gnunetblock.pc.in \ gnunetcore.pc.in \ gnunetdatacache.pc.in \ gnunetdatastore.pc.in \ gnunetdht.pc.in \ gnunetdhtlog.pc.in \ gnunetdv.pc.in \ gnunetfragmentation.pc.in \ gnunetfs.pc.in \ gnunethello.pc.in \ gnunetnat.pc.in \ gnunetnse.pc.in \ gnunetpeerinfo.pc.in \ gnunetstatistics.pc.in \ gnunettesting.pc.in \ gnunettransport.pc.in \ gnunetutil.pc.in CLEANFILES = $(pcfiles) INCLUDES = -I$(top_srcdir)/src/include gnunet-0.9.3/pkgconfig/gnunetdatastore.pc.in0000644000175000017500000000045211760502552016057 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: GNUnet datastore Description: Management API for the datastore for files stored on a GNUnet node URL: http://gnunet.org Version: @VERSION@ Requires: Libs: -L${libdir} -lgnunetdatastore Cflags: -I${includedir} gnunet-0.9.3/pkgconfig/gnunetstatistics.pc.in0000644000175000017500000000042311760502552016261 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: GNUnet statistics Description: Provides API of GNUnet statistics service URL: http://gnunet.org Version: @VERSION@ Requires: Libs: -L${libdir} -lgnunetstatistics Cflags: -I${includedir} gnunet-0.9.3/pkgconfig/gnunetdht.pc.in0000644000175000017500000000040011760502552014641 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: GNUnet DHT Description: Library to access GNUnet DHT service URL: http://gnunet.org Version: @VERSION@ Requires: Libs: -L${libdir} -lgnunetdht Cflags: -I${includedir} gnunet-0.9.3/pkgconfig/gnunetdatacache.pc.in0000644000175000017500000000041511760502552015765 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: GNUnet datacache Description: Provides datacache API implementation URL: http://gnunet.org Version: @VERSION@ Requires: Libs: -L${libdir} -lgnunetdatacache Cflags: -I${includedir} gnunet-0.9.3/pkgconfig/gnunettesting.pc.in0000644000175000017500000000043511760502552015547 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: GNUnet testing Description: Provides convenience API for writing testcases for GNUnet URL: http://gnunet.org Version: @VERSION@ Requires: Libs: -L${libdir} -lgnunettesting Cflags: -I${includedir} gnunet-0.9.3/pkgconfig/gnunetdhtlog.pc.in0000644000175000017500000000042011760502552015345 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: GNUnet dhtlog Description: Library for logging DHT operations via plugins URL: http://gnunet.org Version: @VERSION@ Requires: Libs: -L${libdir} -lgnunetdhtlog Cflags: -I${includedir} gnunet-0.9.3/pkgconfig/gnunetutil.pc.in0000644000175000017500000000043111760502552015043 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: GNUnet util Description: Provides miscellaneous utility functions and API for GNUnet URL: http://gnunet.org Version: @VERSION@ Requires: Libs: -L${libdir} -lgnunetutil Cflags: -I${includedir} gnunet-0.9.3/pkgconfig/gnunetregex.pc.in0000644000175000017500000000044111760502552015201 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: GNUnet regex Description: Provides API for parsing regular expressions into finite automata URL: http://gnunet.org Version: @VERSION@ Requires: Libs: -L${libdir} -lgnunetregex Cflags: -I${includedir} gnunet-0.9.3/pkgconfig/gnunetnat.pc.in0000644000175000017500000000036611760502552014657 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: GNUnet NAT Description: library for NAT traversal URL: https://gnunet.org Version: @VERSION@ Requires: Libs: -L${libdir} -lgnunetnat Cflags: -I${includedir} gnunet-0.9.3/pkgconfig/gnunetnse.pc.in0000644000175000017500000000042711760502552014660 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: GNUnet NSE Description: library to access GNUnet network size estimate information URL: https://gnunet.org Version: @VERSION@ Requires: Libs: -L${libdir} -lgnunetnse Cflags: -I${includedir} gnunet-0.9.3/pkgconfig/gnunetpeerinfo.pc.in0000644000175000017500000000042411760502552015677 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: GNUnet peerinfo Description: Provides API to access GNUnet peerinfo service URL: http://gnunet.org Version: @VERSION@ Requires: Libs: -L${libdir} -lgnunetpeerinfo Cflags: -I${includedir} gnunet-0.9.3/pkgconfig/gnunetblock.pc.in0000644000175000017500000000040311760502552015157 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: GNUnet block Description: Library for data block manipulation URL: http://gnunet.org Version: @VERSION@ Requires: Libs: -L${libdir} -lgnunetblock Cflags: -I${includedir} gnunet-0.9.3/pkgconfig/gnunetcore.pc.in0000644000175000017500000000040111760502552015013 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: GNUnet core Description: Provides API to access core service URL: http://gnunet.org Version: @VERSION@ Requires: Libs: -L${libdir} -lgnunetcore Cflags: -I${includedir} gnunet-0.9.3/pkgconfig/Makefile.in0000644000175000017500000004633211762217210013767 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = pkgconfig DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/gnunetarm.pc.in $(srcdir)/gnunetblock.pc.in \ $(srcdir)/gnunetcore.pc.in $(srcdir)/gnunetdatacache.pc.in \ $(srcdir)/gnunetdatastore.pc.in $(srcdir)/gnunetdht.pc.in \ $(srcdir)/gnunetdhtlog.pc.in $(srcdir)/gnunetdv.pc.in \ $(srcdir)/gnunetfragmentation.pc.in $(srcdir)/gnunetfs.pc.in \ $(srcdir)/gnunethello.pc.in $(srcdir)/gnunetnat.pc.in \ $(srcdir)/gnunetnse.pc.in $(srcdir)/gnunetpeerinfo.pc.in \ $(srcdir)/gnunetregex.pc.in $(srcdir)/gnunetstatistics.pc.in \ $(srcdir)/gnunettesting.pc.in $(srcdir)/gnunettransport.pc.in \ $(srcdir)/gnunetutil.pc.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = gnunetarm.pc gnunetblock.pc gnunetcore.pc \ gnunetdatacache.pc gnunetdatastore.pc gnunetdht.pc \ gnunetdhtlog.pc gnunetdv.pc gnunetfragmentation.pc gnunetfs.pc \ gnunethello.pc gnunetnat.pc gnunetnse.pc gnunetpeerinfo.pc \ gnunetregex.pc gnunetstatistics.pc gnunettesting.pc \ gnunettransport.pc gnunetutil.pc CONFIG_CLEAN_VPATH_FILES = AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ SOURCES = DIST_SOURCES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(pkgconfigdir)" DATA = $(pkgconfig_DATA) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ pcfiles = \ gnunetarm.pc \ gnunetblock.pc \ gnunetcore.pc \ gnunetdatacache.pc \ gnunetdatastore.pc \ gnunetdht.pc \ gnunetdhtlog.pc \ gnunetdv.pc \ gnunetfragmentation.pc \ gnunetfs.pc \ gnunethello.pc \ gnunetnse.pc \ gnunetnat.pc \ gnunetpeerinfo.pc \ gnunetstatistics.pc \ gnunettesting.pc \ gnunettransport.pc \ gnunetutil.pc cp_verbose = $(cp_verbose_$(V)) cp_verbose_ = $(cp_verbose_$(AM_DEFAULT_VERBOSITY)) cp_verbose_0 = @echo " CP $@"; pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = $(pcfiles) EXTRA_DIST = \ gnunetarm.pc.in \ gnunetblock.pc.in \ gnunetcore.pc.in \ gnunetdatacache.pc.in \ gnunetdatastore.pc.in \ gnunetdht.pc.in \ gnunetdhtlog.pc.in \ gnunetdv.pc.in \ gnunetfragmentation.pc.in \ gnunetfs.pc.in \ gnunethello.pc.in \ gnunetnat.pc.in \ gnunetnse.pc.in \ gnunetpeerinfo.pc.in \ gnunetstatistics.pc.in \ gnunettesting.pc.in \ gnunettransport.pc.in \ gnunetutil.pc.in CLEANFILES = $(pcfiles) INCLUDES = -I$(top_srcdir)/src/include all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu pkgconfig/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu pkgconfig/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): gnunetarm.pc: $(top_builddir)/config.status $(srcdir)/gnunetarm.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ gnunetblock.pc: $(top_builddir)/config.status $(srcdir)/gnunetblock.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ gnunetcore.pc: $(top_builddir)/config.status $(srcdir)/gnunetcore.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ gnunetdatacache.pc: $(top_builddir)/config.status $(srcdir)/gnunetdatacache.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ gnunetdatastore.pc: $(top_builddir)/config.status $(srcdir)/gnunetdatastore.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ gnunetdht.pc: $(top_builddir)/config.status $(srcdir)/gnunetdht.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ gnunetdhtlog.pc: $(top_builddir)/config.status $(srcdir)/gnunetdhtlog.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ gnunetdv.pc: $(top_builddir)/config.status $(srcdir)/gnunetdv.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ gnunetfragmentation.pc: $(top_builddir)/config.status $(srcdir)/gnunetfragmentation.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ gnunetfs.pc: $(top_builddir)/config.status $(srcdir)/gnunetfs.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ gnunethello.pc: $(top_builddir)/config.status $(srcdir)/gnunethello.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ gnunetnat.pc: $(top_builddir)/config.status $(srcdir)/gnunetnat.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ gnunetnse.pc: $(top_builddir)/config.status $(srcdir)/gnunetnse.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ gnunetpeerinfo.pc: $(top_builddir)/config.status $(srcdir)/gnunetpeerinfo.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ gnunetregex.pc: $(top_builddir)/config.status $(srcdir)/gnunetregex.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ gnunetstatistics.pc: $(top_builddir)/config.status $(srcdir)/gnunetstatistics.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ gnunettesting.pc: $(top_builddir)/config.status $(srcdir)/gnunettesting.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ gnunettransport.pc: $(top_builddir)/config.status $(srcdir)/gnunettransport.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ gnunetutil.pc: $(top_builddir)/config.status $(srcdir)/gnunetutil.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgconfigDATA: $(pkgconfig_DATA) @$(NORMAL_INSTALL) test -z "$(pkgconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ done uninstall-pkgconfigDATA: @$(NORMAL_UNINSTALL) @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgconfigdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgconfigdir)" && rm -f $$files tags: TAGS TAGS: ctags: CTAGS CTAGS: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) all-local installdirs: for dir in "$(DESTDIR)$(pkgconfigdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgconfigDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-pkgconfigDATA .MAKE: install-am install-strip .PHONY: all all-am all-local check check-am clean clean-generic \ clean-libtool distclean distclean-generic distclean-libtool \ distdir dvi dvi-am html html-am info info-am install \ install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-pkgconfigDATA install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am uninstall uninstall-am uninstall-pkgconfigDATA all-local: $(pcfiles) %.pc: %.pc $(cp_verbose_0)cp $< $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/pkgconfig/gnunetfragmentation.pc.in0000644000175000017500000000051511760502552016727 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: GNUnet fragmentation Description: Provides API for sending and receiving messages that are larger than the MTU of the transport URL: http://gnunet.org Version: @VERSION@ Requires: Libs: -L${libdir} -lgnunetfragmentation Cflags: -I${includedir} gnunet-0.9.3/pkgconfig/gnunetdv.pc.in0000644000175000017500000000037511760502552014506 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: GNUnet dv Description: Library to access GNUnet DV service URL: http://gnunet.org Version: @VERSION@ Requires: Libs: -L${libdir} -lgnunetdv Cflags: -I${includedir} gnunet-0.9.3/pkgconfig/gnunetfs.pc.in0000644000175000017500000000040611760502552014500 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: GNUnet fs Description: Provides API for GNUnet File-Sharing service URL: http://gnunet.org Version: @VERSION@ Requires: Libs: -L${libdir} -lgnunetfs Cflags: -I${includedir} gnunet-0.9.3/pkgconfig/gnunetarm.pc.in0000644000175000017500000000043411760502552014650 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: GNUnet ARM Description: Provides API for accessing the Automated Restart Manager service URL: http://gnunet.org Version: @VERSION@ Requires: Libs: -L${libdir} -lgnunetarm Cflags: -I${includedir} gnunet-0.9.3/Makefile.am0000644000175000017500000000116511676151331012007 00000000000000INCLUDES = -I$(top_srcdir)/src/include SUBDIRS = contrib doc m4 src po pkgconfig EXTRA_DIST = \ ABOUT-NLS \ config.rpath \ install-sh \ acinclude.m4 gnunetincludedir = $(includedir)/gnunet gnunetinclude_HEADERS = gnunet_config.h docdir = $(datadir)/doc/gnunet/ doc_DATA = COPYING ACLOCAL_AMFLAGS = -I m4 ChangeLog: if test -f $(top_srcdir)/.svn/entries; then \ svn log -v --xml -r HEAD:18409 | \ xsltproc --stringparam ignore-message-starting "-" \ --stringparam strip-prefix "gnunet" \ --stringparam include-rev "yes" $(top_srcdir)/contrib/svn2cl.xsl - > $@; \ fi dist: ChangeLog .PHONY: ChangeLog gnunet-0.9.3/config.rpath0000755000175000017500000003744411260753602012272 00000000000000#! /bin/sh # Output a system dependent set of variables, describing how to set the # run time search path of shared libraries in an executable. # # Copyright 1996-2006 Free Software Foundation, Inc. # Taken from GNU libtool, 2001 # Originally by Gordon Matzigkeit , 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # # The first argument passed to this file is the canonical host specification, # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld # should be set by the caller. # # The set of defined variables is at the end of this script. # Known limitations: # - On IRIX 6.5 with CC="cc", the run time search patch must not be longer # than 256 bytes, otherwise the compiler driver will dump core. The only # known workaround is to choose shorter directory names for the build # directory and/or the installation directory. # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a shrext=.so host="$1" host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` # Code taken from libtool.m4's _LT_CC_BASENAME. for cc_temp in $CC""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'` # Code taken from libtool.m4's AC_LIBTOOL_PROG_COMPILER_PIC. wl= if test "$GCC" = yes; then wl='-Wl,' else case "$host_os" in aix*) wl='-Wl,' ;; darwin*) case $cc_basename in xlc*) wl='-Wl,' ;; esac ;; mingw* | pw32* | os2*) ;; hpux9* | hpux10* | hpux11*) wl='-Wl,' ;; irix5* | irix6* | nonstopux*) wl='-Wl,' ;; newsos6) ;; linux*) case $cc_basename in icc* | ecc*) wl='-Wl,' ;; pgcc | pgf77 | pgf90) wl='-Wl,' ;; ccc*) wl='-Wl,' ;; como) wl='-lopt=' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) wl='-Wl,' ;; esac ;; esac ;; osf3* | osf4* | osf5*) wl='-Wl,' ;; sco3.2v5*) ;; solaris*) wl='-Wl,' ;; sunos4*) wl='-Qoption ld ' ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) wl='-Wl,' ;; sysv4*MP*) ;; unicos*) wl='-Wl,' ;; uts4*) ;; esac fi # Code taken from libtool.m4's AC_LIBTOOL_PROG_LD_SHLIBS. hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_direct=no hardcode_minus_L=no case "$host_os" in cygwin* | mingw* | pw32*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; esac ld_shlibs=yes if test "$with_gnu_ld" = yes; then # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. # Unlike libtool, we use -rpath here, not --rpath, since the documented # option of GNU ld is called -rpath, not --rpath. hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' case "$host_os" in aix3* | aix4* | aix5*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no fi ;; amigaos*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # Samuel A. Falvo II reports # that the semantics of dynamic libraries on AmigaOS, at least up # to version 4, is to share data among multiple programs linked # with the same dynamic library. Since this doesn't match the # behavior of shared libraries on other platforms, we cannot use # them. ld_shlibs=no ;; beos*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; cygwin* | mingw* | pw32*) # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then : else ld_shlibs=no fi ;; interix3*) hardcode_direct=no hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; linux*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; netbsd*) ;; solaris*) if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then ld_shlibs=no elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' else ld_shlibs=no fi ;; esac ;; sunos4*) hardcode_direct=yes ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = no; then hardcode_libdir_flag_spec= fi else case "$host_os" in aix3*) # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix5*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac fi hardcode_direct=yes hardcode_libdir_separator=':' if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 hardcode_direct=yes else # We have old collect2 hardcode_direct=unsupported hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac fi # Begin _LT_AC_SYS_LIBPATH_AIX. echo 'int main () { return 0; }' > conftest.c ${CC} ${LDFLAGS} conftest.c -o conftest aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` fi if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib" fi rm -f conftest.c conftest # End _LT_AC_SYS_LIBPATH_AIX. if test "$aix_use_runtimelinking" = yes; then hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' else hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" fi fi ;; amigaos*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # see comment about different semantics on the GNU ld section ld_shlibs=no ;; bsdi[45]*) ;; cygwin* | mingw* | pw32*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec=' ' libext=lib ;; darwin* | rhapsody*) hardcode_direct=no if test "$GCC" = yes ; then : else case $cc_basename in xlc*) ;; *) ld_shlibs=no ;; esac fi ;; dgux*) hardcode_libdir_flag_spec='-L$libdir' ;; freebsd1*) ld_shlibs=no ;; freebsd2.2*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; freebsd2*) hardcode_direct=yes hardcode_minus_L=yes ;; freebsd* | kfreebsd*-gnu | dragonfly*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; hpux9*) hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; hpux10*) if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no ;; *) hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; netbsd*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; newsos6) hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; openbsd*) hardcode_direct=yes if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then hardcode_libdir_flag_spec='${wl}-rpath,$libdir' else case "$host_os" in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) hardcode_libdir_flag_spec='-R$libdir' ;; *) hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; osf3*) hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) if test "$GCC" = yes; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else # Both cc and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi hardcode_libdir_separator=: ;; solaris*) hardcode_libdir_flag_spec='-R$libdir' ;; sunos4*) hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes ;; sysv4) case $host_vendor in sni) hardcode_direct=yes # is this really true??? ;; siemens) hardcode_direct=no ;; motorola) hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac ;; sysv4.3*) ;; sysv4*MP*) if test -d /usr/nec; then ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7*) ;; sysv5* | sco3.2v5* | sco5v6*) hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' hardcode_libdir_separator=':' ;; uts4*) hardcode_libdir_flag_spec='-L$libdir' ;; *) ld_shlibs=no ;; esac fi # Check dynamic linker characteristics # Code taken from libtool.m4's AC_LIBTOOL_SYS_DYNAMIC_LINKER. libname_spec='lib$name' case "$host_os" in aix3*) ;; aix4* | aix5*) ;; amigaos*) ;; beos*) ;; bsdi[45]*) ;; cygwin* | mingw* | pw32*) shrext=.dll ;; darwin* | rhapsody*) shrext=.dylib ;; dgux*) ;; freebsd1*) ;; kfreebsd*-gnu) ;; freebsd* | dragonfly*) ;; gnu*) ;; hpux9* | hpux10* | hpux11*) case $host_cpu in ia64*) shrext=.so ;; hppa*64*) shrext=.sl ;; *) shrext=.sl ;; esac ;; interix3*) ;; irix5* | irix6* | nonstopux*) case "$host_os" in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;; *) libsuff= shlibsuff= ;; esac ;; esac ;; linux*oldld* | linux*aout* | linux*coff*) ;; linux*) ;; knetbsd*-gnu) ;; netbsd*) ;; newsos6) ;; nto-qnx*) ;; openbsd*) ;; os2*) libname_spec='$name' shrext=.dll ;; osf3* | osf4* | osf5*) ;; solaris*) ;; sunos4*) ;; sysv4 | sysv4.3*) ;; sysv4*MP*) ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) ;; uts4*) ;; esac sed_quote_subst='s/\(["`$\\]\)/\\\1/g' escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` shlibext=`echo "$shrext" | sed -e 's,^\.,,'` escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <, 2006. # msgid "" msgstr "" "Project-Id-Version: GNUnet 0.7.0b\n" "Report-Msgid-Bugs-To: gnunet-developers@mail.gnu.org\n" "POT-Creation-Date: 2012-06-05 15:47+0200\n" "PO-Revision-Date: 2006-01-21 17:16+0100\n" "Last-Translator: Daniel Nylander \n" "Language-Team: Swedish \n" "Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/arm/arm_api.c:165 msgid "Failed to transmit shutdown request to client.\n" msgstr "" #: src/arm/arm_api.c:349 #, fuzzy, c-format msgid "Configuration failes to specify option `%s' in section `%s'!\n" msgstr "Konfigurationsfil \"%s\" hittades inte. Kör \"gnunet-setup -d\"!\n" #: src/arm/arm_api.c:363 #, fuzzy, c-format msgid "Configuration fails to specify option `%s' in section `%s'!\n" msgstr "Konfigurationsfil \"%s\" skapad.\n" #: src/arm/arm_api.c:432 #, c-format msgid "Error receiving response to `%s' request from ARM for service `%s'\n" msgstr "" #: src/arm/arm_api.c:485 #, c-format msgid "Requesting start of service `%s'.\n" msgstr "" #: src/arm/arm_api.c:486 #, c-format msgid "Requesting termination of service `%s'.\n" msgstr "" #: src/arm/arm_api.c:507 #, c-format msgid "Error while trying to transmit request to start `%s' to ARM\n" msgstr "" #: src/arm/arm_api.c:508 #, c-format msgid "Error while trying to transmit request to stop `%s' to ARM\n" msgstr "" #: src/arm/arm_api.c:540 #, fuzzy, c-format msgid "Asked to start service `%s' within %llu ms\n" msgstr "\"%s\": Mottog inte meddelande inom %llu ms.\n" #: src/arm/arm_api.c:612 #, fuzzy, c-format msgid "Stopping service `%s' within %llu ms\n" msgstr "Inget svar mottaget inom %llums.\n" #: src/arm/gnunet-arm.c:159 #, fuzzy, c-format msgid "Service `%s' is unknown to ARM.\n" msgstr "\"%s\" är inte en fil.\n" #: src/arm/gnunet-arm.c:164 #, fuzzy, c-format msgid "Service `%s' has been stopped.\n" msgstr "Tjänst borttagen.\n" #: src/arm/gnunet-arm.c:167 #, fuzzy, c-format msgid "Service `%s' was already running.\n" msgstr "\"%s\" är inte en fil.\n" #: src/arm/gnunet-arm.c:172 #, fuzzy, c-format msgid "Service `%s' has been started.\n" msgstr "Tjänst borttagen.\n" #: src/arm/gnunet-arm.c:175 #, fuzzy, c-format msgid "Service `%s' was already being stopped.\n" msgstr "Tjänst borttagen.\n" #: src/arm/gnunet-arm.c:179 #, fuzzy, c-format msgid "Service `%s' was already not running.\n" msgstr "\"%s\" är inte en fil.\n" #: src/arm/gnunet-arm.c:183 msgid "Request ignored as ARM is shutting down.\n" msgstr "" #: src/arm/gnunet-arm.c:187 #, fuzzy msgid "Error communicating with ARM service.\n" msgstr "Skriv ut information om GNUnets motparter." #: src/arm/gnunet-arm.c:191 #, fuzzy msgid "Timeout communicating with ARM service.\n" msgstr "Skriv ut information om GNUnets motparter." #: src/arm/gnunet-arm.c:195 #, fuzzy msgid "Operation failed.\n" msgstr "\"%s\" misslyckades vid %s:%d med fel: \"%s\".\n" #: src/arm/gnunet-arm.c:199 msgid "Unknown response code from ARM.\n" msgstr "" #: src/arm/gnunet-arm.c:222 #, fuzzy msgid "Error communicating with ARM. ARM not running?\n" msgstr "Skriv ut information om GNUnets motparter." #: src/arm/gnunet-arm.c:225 #, fuzzy msgid "Running services:\n" msgstr "Startade samling \"%s\".\n" #: src/arm/gnunet-arm.c:249 #, c-format msgid "Fatal configuration error: `%s' option in section `%s' missing.\n" msgstr "" #: src/arm/gnunet-arm.c:257 src/arm/gnunet-arm.c:357 src/arm/gnunet-arm.c:373 msgid "Fatal error initializing ARM API.\n" msgstr "" #: src/arm/gnunet-arm.c:280 #, fuzzy, c-format msgid "Failed to remove configuration file %s\n" msgstr "Kunde inte spara konfigurationsfil \"%s\":" #: src/arm/gnunet-arm.c:286 #, fuzzy, c-format msgid "Failed to remove servicehome directory %s\n" msgstr "Filformatsfel (inte en GNUnet-katalog?)\n" #: src/arm/gnunet-arm.c:407 msgid "stop all GNUnet services" msgstr "" #: src/arm/gnunet-arm.c:409 msgid "start a particular service" msgstr "" #: src/arm/gnunet-arm.c:411 msgid "stop a particular service" msgstr "" #: src/arm/gnunet-arm.c:413 msgid "start all GNUnet default services" msgstr "" #: src/arm/gnunet-arm.c:416 msgid "stop and start all GNUnet default services" msgstr "" #: src/arm/gnunet-arm.c:419 msgid "delete config file and directory on exit" msgstr "" #: src/arm/gnunet-arm.c:421 msgid "don't print status messages" msgstr "" #: src/arm/gnunet-arm.c:424 msgid "timeout for completing current operation" msgstr "" #: src/arm/gnunet-arm.c:426 msgid "List currently running services" msgstr "" #: src/arm/gnunet-arm.c:437 msgid "Control services and the Automated Restart Manager (ARM)" msgstr "" #: src/arm/gnunet-service-arm.c:332 #, fuzzy, c-format msgid "Failed to start service `%s'\n" msgstr "Misslyckades att starta samling.\n" #: src/arm/gnunet-service-arm.c:335 #, fuzzy, c-format msgid "Starting service `%s'\n" msgstr "Startade samling \"%s\".\n" #: src/arm/gnunet-service-arm.c:361 #, fuzzy msgid "Could not send status result to client\n" msgstr "Kunde inte skicka begäran till gnunetd.\n" #: src/arm/gnunet-service-arm.c:393 #, fuzzy msgid "Could not send list result to client\n" msgstr "Kunde inte skicka begäran till gnunetd.\n" #: src/arm/gnunet-service-arm.c:523 #, fuzzy, c-format msgid "Unable to create socket for service `%s': %s\n" msgstr "Kunde inte skapa användarkonto:" #: src/arm/gnunet-service-arm.c:545 #, c-format msgid "Unable to bind listening socket for service `%s' to address `%s': %s\n" msgstr "" #: src/arm/gnunet-service-arm.c:559 #, c-format msgid "ARM now monitors connections to service `%s' at `%s'\n" msgstr "" #: src/arm/gnunet-service-arm.c:667 #, fuzzy, c-format msgid "Preparing to stop `%s'\n" msgstr "Startade samling \"%s\".\n" #: src/arm/gnunet-service-arm.c:878 #, fuzzy, c-format msgid "Restarting service `%s'.\n" msgstr "Startade samling \"%s\".\n" #: src/arm/gnunet-service-arm.c:970 msgid "exit" msgstr "" #: src/arm/gnunet-service-arm.c:975 msgid "signal" msgstr "" #: src/arm/gnunet-service-arm.c:980 #, fuzzy msgid "unknown" msgstr "Okänt fel" #: src/arm/gnunet-service-arm.c:986 #, fuzzy, c-format msgid "Service `%s' took %llu ms to terminate\n" msgstr "Tjänst borttagen.\n" #: src/arm/gnunet-service-arm.c:1021 #, c-format msgid "Service `%s' terminated with status %s/%d, will restart in %llu ms\n" msgstr "" #: src/arm/gnunet-service-arm.c:1127 #, fuzzy, c-format msgid "Configuration file `%s' for service `%s' not valid: %s\n" msgstr "Konfigurationsfil \"%s\" skapad.\n" #: src/arm/gnunet-service-arm.c:1129 msgid "option missing" msgstr "" #: src/arm/gnunet-service-arm.c:1213 #, fuzzy, c-format msgid "Starting default services `%s'\n" msgstr "Startade samling \"%s\".\n" #: src/arm/gnunet-service-arm.c:1224 #, c-format msgid "Default service `%s' not configured correctly!\n" msgstr "" #: src/arm/gnunet-service-arm.c:1238 msgid "" "No default services configured, GNUnet will not really start right now.\n" msgstr "" #: src/arm/mockup-service.c:44 msgid "Initiating shutdown as requested by client.\n" msgstr "" #: src/block/block.c:105 #, fuzzy, c-format msgid "Loading block plugin `%s'\n" msgstr "Testar transport(er) %s\n" #: src/chat/chat.c:175 #, fuzzy msgid "Could not transmit confirmation receipt\n" msgstr "Kunde inte komma Ã¥t namnrymdsinformation.\n" #: src/chat/chat.c:283 msgid "The current user must be the the first one joined\n" msgstr "" #: src/chat/chat.c:412 #, fuzzy, c-format msgid "Unknown message type: '%u'\n" msgstr "Okänd operation \"%s\"\n" #: src/chat/chat.c:472 #, fuzzy, c-format msgid "Configuration option `%s' in section `%s' missing\n" msgstr "Konfigurationsfil \"%s\" skapad.\n" #: src/chat/chat.c:480 #, fuzzy, c-format msgid "Failed to access chat home directory `%s'\n" msgstr "Filformatsfel (inte en GNUnet-katalog?)\n" #: src/chat/chat.c:498 #, fuzzy, c-format msgid "Failed to create/open key in file `%s'\n" msgstr "Misslyckades att leverera \"%s\" meddelande.\n" #: src/chat/chat.c:559 #, fuzzy msgid "Could not serialize metadata\n" msgstr "Kunde inte initiera libgnunetutil!\n" #: src/chat/chat.c:674 #, fuzzy msgid "Failed to connect to the chat service\n" msgstr "Misslyckades att ansluta till gnunetd.\n" #: src/chat/chat.c:680 msgid "Undefined mandatory parameter: joinCallback\n" msgstr "" #: src/chat/chat.c:686 msgid "Undefined mandatory parameter: messageCallback\n" msgstr "" #: src/chat/chat.c:692 msgid "Undefined mandatory parameter: memberCallback\n" msgstr "" #: src/chat/gnunet-chat.c:93 msgid "Joined\n" msgstr "" #: src/chat/gnunet-chat.c:125 src/chat/gnunet-chat.c:133 #: src/chat/gnunet-chat.c:213 src/chat/gnunet-chat.c:253 #: src/chat/gnunet-chat.c:329 src/chat/gnunet-chat.c:371 #: src/chat/gnunet-chat.c:400 src/chat/gnunet-chat.c:700 msgid "anonymous" msgstr "" #: src/chat/gnunet-chat.c:144 #, fuzzy, c-format msgid "(%s) `%s' said: %s\n" msgstr "\"%s\" %s misslyckades: %s\n" #: src/chat/gnunet-chat.c:147 src/chat/gnunet-chat.c:150 #, fuzzy, c-format msgid "(%s) `%s' said to you: %s\n" msgstr "\"%s\" %s misslyckades: %s\n" # drive = hard drive ? #: src/chat/gnunet-chat.c:153 #, fuzzy, c-format msgid "(%s) `%s' said for sure: %s\n" msgstr "\"%s\" misslyckades för enhet %s: %u\n" # drive = hard drive ? #: src/chat/gnunet-chat.c:156 #, fuzzy, c-format msgid "(%s) `%s' said to you for sure: %s\n" msgstr "\"%s\" misslyckades för enhet %s: %u\n" #: src/chat/gnunet-chat.c:159 #, c-format msgid "(%s) `%s' was confirmed that you received: %s\n" msgstr "" #: src/chat/gnunet-chat.c:162 #, c-format msgid "(%s) `%s' was confirmed that you and only you received: %s\n" msgstr "" #: src/chat/gnunet-chat.c:165 #, c-format msgid "(%s) `%s' was confirmed that you received from him or her: %s\n" msgstr "" #: src/chat/gnunet-chat.c:170 #, c-format msgid "" "(%s) `%s' was confirmed that you and only you received from him or her: %s\n" msgstr "" #: src/chat/gnunet-chat.c:173 #, fuzzy, c-format msgid "(%s) `%s' said off the record: %s\n" msgstr "\"%s\" misslyckades vid %s:%d med fel: %s\n" #: src/chat/gnunet-chat.c:176 #, c-format msgid "(%s) <%s> said using an unknown message type: %s\n" msgstr "" #: src/chat/gnunet-chat.c:217 #, c-format msgid "'%s' acknowledged message #%d\n" msgstr "" #: src/chat/gnunet-chat.c:260 #, c-format msgid "`%s' entered the room\n" msgstr "" #: src/chat/gnunet-chat.c:260 #, c-format msgid "`%s' left the room\n" msgstr "" #: src/chat/gnunet-chat.c:321 src/chat/gnunet-chat.c:363 #, fuzzy msgid "Could not change username\n" msgstr "Kunde inte skapa namnrymd \"%s\" (existerar?).\n" #: src/chat/gnunet-chat.c:334 src/chat/gnunet-chat.c:702 #, fuzzy, c-format msgid "Joining room `%s' as user `%s'...\n" msgstr "Ogiltigt svar till \"%s\" frÃ¥n motpart \"%s\".\n" #: src/chat/gnunet-chat.c:373 #, fuzzy, c-format msgid "Changed username to `%s'\n" msgstr "Kan inte ändra användare/grupp till \"%s\": %s\n" #: src/chat/gnunet-chat.c:388 #, c-format msgid "Users in room `%s': " msgstr "" #: src/chat/gnunet-chat.c:434 msgid "Syntax: /msg USERNAME MESSAGE" msgstr "" #: src/chat/gnunet-chat.c:443 #, c-format msgid "Unknown user `%s'. Make sure you specify its numeric suffix, if any.\n" msgstr "" #: src/chat/gnunet-chat.c:460 #, c-format msgid "User `%s' is currently not in the room!\n" msgstr "" #: src/chat/gnunet-chat.c:513 #, fuzzy, c-format msgid "Unknown command `%s'\n" msgstr "Okänd operation \"%s\"\n" #: src/chat/gnunet-chat.c:524 msgid "" "Use `/join #roomname' to join a chat room. Joining a room will cause you to " "leave the current room" msgstr "" #: src/chat/gnunet-chat.c:528 msgid "" "Use `/nick nickname' to change your nickname. This will cause you to leave " "the current room and immediately rejoin it with the new name." msgstr "" #: src/chat/gnunet-chat.c:532 msgid "" "Use `/msg nickname message' to send a private message to the specified user" msgstr "" #: src/chat/gnunet-chat.c:535 msgid "The `/notice' command is an alias for `/msg'" msgstr "" #: src/chat/gnunet-chat.c:537 msgid "The `/query' command is an alias for `/msg'" msgstr "" #: src/chat/gnunet-chat.c:539 msgid "Use `/sig message' to send a signed public message" msgstr "" #: src/chat/gnunet-chat.c:542 msgid "Use `/ack message' to require signed acknowledgment of the message" msgstr "" #: src/chat/gnunet-chat.c:545 msgid "Use `/anonymous message' to send a public anonymous message" msgstr "" #: src/chat/gnunet-chat.c:547 msgid "The `/anon' command is an alias for `/anonymous'" msgstr "" #: src/chat/gnunet-chat.c:549 msgid "Use `/quit' to terminate gnunet-chat" msgstr "" #: src/chat/gnunet-chat.c:551 msgid "The `/leave' command is an alias for `/quit'" msgstr "" #: src/chat/gnunet-chat.c:554 msgid "Use `/names' to list all of the current members in the chat room" msgstr "" #: src/chat/gnunet-chat.c:556 msgid "Use `/help command' to get help for a specific command" msgstr "" #: src/chat/gnunet-chat.c:672 #, fuzzy msgid "You must specify a nickname\n" msgstr "Du mÃ¥ste ange en mottagare!\n" #: src/chat/gnunet-chat.c:688 #, fuzzy, c-format msgid "Failed to join room `%s'\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/chat/gnunet-chat.c:727 msgid "set the nickname to use (required)" msgstr "" #: src/chat/gnunet-chat.c:730 msgid "set the chat room to join" msgstr "" #: src/chat/gnunet-chat.c:742 msgid "Join a chat on GNUnet." msgstr "" #: src/chat/gnunet-service-chat.c:267 #, fuzzy msgid "Failed to queue a message notification\n" msgstr "Kunde inte spara konfiguration!" #: src/chat/gnunet-service-chat.c:546 #, fuzzy msgid "Failed to queue a join notification\n" msgstr "Kunde inte spara konfiguration!" #: src/chat/gnunet-service-chat.c:729 #, fuzzy msgid "Failed to queue a confirmation receipt\n" msgstr "Kunde inte spara konfiguration!" #: src/chat/gnunet-service-chat.c:907 #, fuzzy msgid "Failed to queue a leave notification\n" msgstr "Kunde inte spara konfiguration!" #: src/core/core_api.c:786 msgid "Client was disconnected from core service, trying to reconnect.\n" msgstr "" #: src/core/gnunet-core.c:54 src/peerinfo-tool/gnunet-peerinfo.c:286 #, fuzzy, c-format msgid "Peer `%s'\n" msgstr "Jag är ändpunkt \"%s\".\n" #: src/core/gnunet-core.c:72 src/peerinfo-tool/gnunet-peerinfo.c:817 #, fuzzy, c-format msgid "Invalid command line argument `%s'\n" msgstr "Ogiltiga kommandoradsargument:\n" #: src/core/gnunet-core.c:95 #, fuzzy msgid "Print information about connected peers." msgstr "Skriv ut information om GNUnets motparter." #: src/core/gnunet-service-core.c:97 #, c-format msgid "Core service of `%4s' ready.\n" msgstr "" #: src/core/gnunet-service-core_clients.c:370 msgid "# send requests dropped (disconnected)" msgstr "" #: src/core/gnunet-service-core_clients.c:475 #, fuzzy msgid "# messages discarded (session disconnected)" msgstr "Nätverksannonsering avstängd i konfigurationen!\n" #: src/core/gnunet-service-core_clients.c:818 #, fuzzy, c-format msgid "# bytes of messages of type %u received" msgstr "# krypterade PONG-meddelanden mottagna" #: src/core/gnunet-service-core_kx.c:565 msgid "# bytes encrypted" msgstr "# byte krypterade" #: src/core/gnunet-service-core_kx.c:617 msgid "# bytes decrypted" msgstr "# byte dekrypterade" #: src/core/gnunet-service-core_kx.c:681 src/dv/gnunet-service-dv.c:3003 #, fuzzy msgid "Error in communication with PEERINFO service\n" msgstr "Skriv ut information om GNUnets motparter." #: src/core/gnunet-service-core_kx.c:700 msgid "# Delayed connecting due to lack of public key" msgstr "" #: src/core/gnunet-service-core_kx.c:753 msgid "# key exchanges initiated" msgstr "" #: src/core/gnunet-service-core_kx.c:775 msgid "# key exchanges stopped" msgstr "" #: src/core/gnunet-service-core_kx.c:828 #, fuzzy msgid "# session keys received" msgstr "# sessionnycklar vägrade" #: src/core/gnunet-service-core_kx.c:845 #, fuzzy, c-format msgid "`%s' is for `%s', not for me. Ignoring.\n" msgstr "storlek pÃ¥ \"%s\" meddelande är för litet. Ignorerar.\n" #: src/core/gnunet-service-core_kx.c:890 #, fuzzy msgid "# SET_KEY messages decrypted" msgstr "# PING-meddelanden skapade" #: src/core/gnunet-service-core_kx.c:977 #: src/transport/gnunet-service-transport_validation.c:810 #, fuzzy msgid "# PING messages received" msgstr "# PING-meddelanden skapade" #: src/core/gnunet-service-core_kx.c:1010 #, c-format msgid "" "Received PING from `%s' for different identity: I am `%s', PONG identity: `" "%s'\n" msgstr "" #: src/core/gnunet-service-core_kx.c:1029 #, fuzzy msgid "# PONG messages created" msgstr "# PING-meddelanden skapade" #: src/core/gnunet-service-core_kx.c:1125 #, fuzzy msgid "# sessions terminated by timeout" msgstr "# byte kastade via TCP (utgÃ¥ende)" #: src/core/gnunet-service-core_kx.c:1135 #, fuzzy msgid "# keepalive messages sent" msgstr "# PING-meddelanden i klartext skickade" #: src/core/gnunet-service-core_kx.c:1236 #: src/transport/gnunet-service-transport_validation.c:1031 #, fuzzy msgid "# PONG messages received" msgstr "# krypterade PONG-meddelanden mottagna" #: src/core/gnunet-service-core_kx.c:1275 #, fuzzy msgid "# PONG messages decrypted" msgstr "# PING-meddelanden skapade" #: src/core/gnunet-service-core_kx.c:1303 #, fuzzy msgid "# session keys confirmed via PONG" msgstr "# sessionnycklar vägrade" #: src/core/gnunet-service-core_kx.c:1329 #, fuzzy msgid "# rekey operations confirmed via PONG" msgstr "# sessionnycklar vägrade" #: src/core/gnunet-service-core_kx.c:1381 #: src/core/gnunet-service-core_kx.c:1398 #, fuzzy msgid "# SET_KEY and PING messages created" msgstr "# PING-meddelanden skapade" #: src/core/gnunet-service-core_kx.c:1402 msgid "# REKEY operations performed" msgstr "" #: src/core/gnunet-service-core_kx.c:1537 msgid "# failed to decrypt message (no session key)" msgstr "" #: src/core/gnunet-service-core_kx.c:1577 #: src/core/gnunet-service-core_kx.c:1602 #, fuzzy msgid "# bytes dropped (duplicates)" msgstr "# byte kastade via UDP (utgÃ¥ende)" #: src/core/gnunet-service-core_kx.c:1589 #, fuzzy msgid "# bytes dropped (out of sequence)" msgstr "# byte kastade via UDP (utgÃ¥ende)" #: src/core/gnunet-service-core_kx.c:1626 #, fuzzy, c-format msgid "Message received far too old (%llu ms). Content ignored.\n" msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" #: src/core/gnunet-service-core_kx.c:1630 #, fuzzy msgid "# bytes dropped (ancient message)" msgstr "# byte kastade via UDP (utgÃ¥ende)" #: src/core/gnunet-service-core_kx.c:1638 #, fuzzy msgid "# bytes of payload decrypted" msgstr "# byte dekrypterade" #: src/core/gnunet-service-core_kx.c:1700 #, fuzzy msgid "Core service is lacking HOSTKEY configuration setting. Exiting.\n" msgstr "GNUnet-konfiguration" #: src/core/gnunet-service-core_kx.c:1708 msgid "Core service could not access hostkey. Exiting.\n" msgstr "" #: src/core/gnunet-service-core_kx.c:1718 src/hostlist/hostlist-server.c:551 #: src/peerinfo-tool/gnunet-peerinfo.c:823 #: src/transport/gnunet-service-transport.c:611 #, fuzzy msgid "Could not access PEERINFO service. Exiting.\n" msgstr "Kunde inte komma Ã¥t namnrymdsinformation.\n" #: src/core/gnunet-service-core_neighbours.c:163 #, fuzzy msgid "# sessions terminated by transport disconnect" msgstr "Nätverksannonsering avstängd i konfigurationen!\n" #: src/core/gnunet-service-core_neighbours.c:180 #: src/core/gnunet-service-core_neighbours.c:334 msgid "# neighbour entries allocated" msgstr "" #: src/core/gnunet-service-core_neighbours.c:247 msgid "# encrypted bytes given to transport" msgstr "" #: src/core/gnunet-service-core_neighbours.c:418 #, c-format msgid "Unsupported message of type %u (%u bytes) received from peer `%s'\n" msgstr "" #: src/core/gnunet-service-core_sessions.c:206 #: src/core/gnunet-service-core_sessions.c:269 #: src/dht/gnunet-service-dht_neighbours.c:625 #: src/dht/gnunet-service-dht_neighbours.c:683 #: src/fs/gnunet-service-fs_cp.c:615 src/fs/gnunet-service-fs_cp.c:1532 #: src/topology/gnunet-daemon-topology.c:709 #: src/topology/gnunet-daemon-topology.c:810 #: src/transport/gnunet-service-transport_neighbours.c:874 #: src/transport/gnunet-service-transport_neighbours.c:1080 #: src/transport/gnunet-service-transport_neighbours.c:1089 #: src/transport/gnunet-service-transport_neighbours.c:2568 #: src/transport/gnunet-service-transport_neighbours.c:2814 #, fuzzy msgid "# peers connected" msgstr "# av anslutna parter" #: src/core/gnunet-service-core_sessions.c:236 msgid "# type map refreshes sent" msgstr "" #: src/core/gnunet-service-core_sessions.c:406 msgid "# messages discarded (expired prior to transmission)" msgstr "" #: src/core/gnunet-service-core_typemap.c:110 #: src/core/gnunet-service-core_typemap.c:121 #, fuzzy msgid "# type maps received" msgstr "# krypterade PONG-meddelanden mottagna" #: src/core/gnunet-service-core_typemap.c:151 msgid "# updates to my type map" msgstr "" #: src/datacache/datacache.c:115 src/datacache/datacache.c:250 #: src/datastore/gnunet-service-datastore.c:834 #, fuzzy msgid "# bytes stored" msgstr "# byte krypterade" #: src/datacache/datacache.c:141 src/datacache/datacache.c:148 #: src/datastore/gnunet-service-datastore.c:1483 #: src/datastore/gnunet-service-datastore.c:1494 #, fuzzy, c-format msgid "No `%s' specified for `%s' in configuration!\n" msgstr "Inga applikationer definierade i konfiguration!\n" #: src/datacache/datacache.c:180 #, c-format msgid "Loading `%s' datacache plugin\n" msgstr "" #: src/datacache/datacache.c:188 #, fuzzy, c-format msgid "Failed to load datacache plugin for `%s'\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/datacache/datacache.c:276 #, fuzzy msgid "# requests received" msgstr "# byte mottogs via TCP" #: src/datacache/datacache.c:284 msgid "# requests filtered by bloom filter" msgstr "" #: src/datacache/plugin_datacache_mysql.c:97 #: src/datacache/plugin_datacache_mysql.c:104 #: src/datacache/plugin_datacache_sqlite.c:69 #: src/datacache/plugin_datacache_sqlite.c:72 #: src/datastore/plugin_datastore_mysql.c:803 #: src/datastore/plugin_datastore_mysql.c:817 #: src/datastore/plugin_datastore_sqlite.c:57 src/mysql/mysql.c:41 #: src/mysql/mysql.c:48 src/mysql/mysql.c:522 src/mysql/mysql.c:531 #: src/mysql/mysql.c:591 src/mysql/mysql.c:607 #: src/namestore/plugin_namestore_sqlite.c:51 src/util/crypto_ksk.c:49 #: src/util/crypto_rsa.c:67 src/include/gnunet_common.h:525 #: src/include/gnunet_common.h:532 #, c-format msgid "`%s' failed at %s:%d with error: %s\n" msgstr "\"%s\" misslyckades vid %s:%d med fel: %s\n" #: src/datacache/plugin_datacache_mysql.c:450 msgid "MySQL datacache running\n" msgstr "" #: src/datacache/plugin_datacache_postgres.c:367 msgid "Postgres datacache running\n" msgstr "" #: src/datacache/plugin_datacache_sqlite.c:410 msgid "Sqlite datacache running\n" msgstr "" #: src/datacache/plugin_datacache_sqlite.c:443 #: src/datastore/plugin_datastore_sqlite.c:408 #: src/namestore/plugin_namestore_sqlite.c:370 msgid "Tried to close sqlite without finalizing all prepared statements.\n" msgstr "" #: src/datacache/plugin_datacache_sqlite.c:450 #, fuzzy, c-format msgid "Failed to close statement %p: %d\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/datacache/plugin_datacache_template.c:121 msgid "Template datacache running\n" msgstr "" #: src/datastore/datastore_api.c:305 #, fuzzy msgid "Failed to transmit request to drop database.\n" msgstr "Misslyckades att skicka HTTP-begäran till värd \"%s\": %s\n" #: src/datastore/datastore_api.c:388 msgid "# queue entry timeouts" msgstr "" #: src/datastore/datastore_api.c:432 msgid "# queue overflows" msgstr "" #: src/datastore/datastore_api.c:459 #, fuzzy msgid "# queue entries created" msgstr "# PING-meddelanden skapade" #: src/datastore/datastore_api.c:477 msgid "# Requests dropped from datastore queue" msgstr "" #: src/datastore/datastore_api.c:525 #, fuzzy msgid "# datastore connections (re)created" msgstr "Nätverksanslutning" #: src/datastore/datastore_api.c:548 msgid "# reconnected to DATASTORE" msgstr "" #: src/datastore/datastore_api.c:612 #, fuzzy msgid "# transmission request failures" msgstr "# klartext PONG-meddelanden mottagna" #: src/datastore/datastore_api.c:633 #, fuzzy msgid "# bytes sent to datastore" msgstr "# byte krypterade" #: src/datastore/datastore_api.c:764 #, fuzzy msgid "Failed to receive status response from database." msgstr "Misslyckades att ta emot svar till \"%s\" meddelande frÃ¥n gnunetd\n" #: src/datastore/datastore_api.c:778 msgid "Error reading response from datastore service" msgstr "" #: src/datastore/datastore_api.c:790 src/datastore/datastore_api.c:796 #, fuzzy msgid "Invalid error message received from datastore service" msgstr "Ogiltigt meddelande mottogs den %s:%d." #: src/datastore/datastore_api.c:800 #, fuzzy msgid "# status messages received" msgstr "# krypterade PONG-meddelanden mottagna" #: src/datastore/datastore_api.c:869 msgid "# PUT requests executed" msgstr "" #: src/datastore/datastore_api.c:936 msgid "# RESERVE requests executed" msgstr "" #: src/datastore/datastore_api.c:997 msgid "# RELEASE RESERVE requests executed" msgstr "" #: src/datastore/datastore_api.c:1054 msgid "# UPDATE requests executed" msgstr "" #: src/datastore/datastore_api.c:1118 msgid "# REMOVE requests executed" msgstr "" #: src/datastore/datastore_api.c:1163 #, fuzzy msgid "Failed to receive response from database.\n" msgstr "Misslyckades att ta emot svar till \"%s\" meddelande frÃ¥n gnunetd\n" #: src/datastore/datastore_api.c:1221 #, fuzzy msgid "# Results received" msgstr "# byte mottogs via TCP" #: src/datastore/datastore_api.c:1286 msgid "# GET REPLICATION requests executed" msgstr "" #: src/datastore/datastore_api.c:1349 msgid "# GET ZERO ANONYMITY requests executed" msgstr "" #: src/datastore/datastore_api.c:1409 msgid "# GET requests executed" msgstr "" #: src/datastore/gnunet-service-datastore.c:349 #, fuzzy msgid "# bytes expired" msgstr "# byte mottogs via TCP" #: src/datastore/gnunet-service-datastore.c:422 msgid "# bytes purged (low-priority)" msgstr "" #: src/datastore/gnunet-service-datastore.c:480 msgid "Transmission to client failed!\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:511 msgid "Shutdown in progress, aborting transmission.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:626 msgid "# results found" msgstr "" #: src/datastore/gnunet-service-datastore.c:669 #, c-format msgid "" "Insufficient space (%llu bytes are available) to satisfy `%s' request for " "%llu bytes\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:680 #, c-format msgid "" "The requested amount (%llu bytes) is larger than the cache size (%llu " "bytes)\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:684 msgid "" "Insufficient space to satisfy request and requested amount is larger than " "cache size" msgstr "" #: src/datastore/gnunet-service-datastore.c:690 msgid "Insufficient space to satisfy request" msgstr "" #: src/datastore/gnunet-service-datastore.c:695 #: src/datastore/gnunet-service-datastore.c:747 #: src/datastore/gnunet-service-datastore.c:960 #: src/datastore/gnunet-service-datastore.c:1417 msgid "# reserved" msgstr "" #: src/datastore/gnunet-service-datastore.c:760 msgid "Could not find matching reservation" msgstr "" #: src/datastore/gnunet-service-datastore.c:846 #, c-format msgid "Need %llu bytes more space (%llu allowed, using %llu)\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1006 #, fuzzy msgid "# GET requests received" msgstr "# byte mottogs via TCP" #: src/datastore/gnunet-service-datastore.c:1018 msgid "# requests filtered by bloomfilter" msgstr "" #: src/datastore/gnunet-service-datastore.c:1046 #, fuzzy msgid "# UPDATE requests received" msgstr "# byte mottogs via TCP" #: src/datastore/gnunet-service-datastore.c:1076 msgid "# GET REPLICATION requests received" msgstr "" #: src/datastore/gnunet-service-datastore.c:1109 msgid "# GET ZERO ANONYMITY requests received" msgstr "" #: src/datastore/gnunet-service-datastore.c:1134 #, fuzzy msgid "Content not found" msgstr "Kommando \"%s\" hittades inte!\n" #: src/datastore/gnunet-service-datastore.c:1142 msgid "# bytes removed (explicit request)" msgstr "" #: src/datastore/gnunet-service-datastore.c:1174 #, fuzzy msgid "# REMOVE requests received" msgstr "# byte mottogs via TCP" #: src/datastore/gnunet-service-datastore.c:1216 #, c-format msgid "Datastore payload inaccurate (%lld < %lld). Trying to fix.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1277 #, c-format msgid "Loading `%s' datastore plugin\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1286 #, fuzzy, c-format msgid "Failed to load datastore plugin for `%s'\n" msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" #: src/datastore/gnunet-service-datastore.c:1488 #, fuzzy, c-format msgid "# bytes used in file-sharing datastore `%s'" msgstr "# byte krypterade" #: src/datastore/gnunet-service-datastore.c:1499 msgid "# quota" msgstr "" #: src/datastore/gnunet-service-datastore.c:1501 msgid "# cache size" msgstr "" #: src/datastore/gnunet-service-datastore.c:1514 #, c-format msgid "Could not use specified filename `%s' for bloomfilter.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1532 #: src/datastore/gnunet-service-datastore.c:1548 #, fuzzy, c-format msgid "Failed to remove bogus bloomfilter file `%s'\n" msgstr "Kunde inte spara konfigurationsfil \"%s\":" #: src/datastore/gnunet-service-datastore.c:1578 #, fuzzy msgid "Failed to initialize bloomfilter.\n" msgstr "Misslyckades att initiera tjänsten \"%s\".\n" #: src/datastore/gnunet-service-datastore.c:1607 msgid "Rebuilding bloomfilter. Please be patient.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1612 msgid "Plugin does not support get_keys function. Please fix!\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1615 msgid "Bloomfilter construction complete.\n" msgstr "" #: src/datastore/plugin_datastore_mysql.c:780 #, fuzzy, c-format msgid "Failed to prepare statement `%s'\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/datastore/plugin_datastore_mysql.c:788 #, fuzzy, c-format msgid "`%s' for `%s' failed at %s:%d with error: %s\n" msgstr "\"%s\" till \"%s\" misslyckades vid %s:%d med fel: %s\n" #: src/datastore/plugin_datastore_mysql.c:1019 msgid "Mysql database running\n" msgstr "" #: src/datastore/plugin_datastore_postgres.c:824 #, fuzzy msgid "Failed to drop table from database.\n" msgstr "Misslyckades att ta emot svar till \"%s\" meddelande frÃ¥n gnunetd\n" #: src/datastore/plugin_datastore_postgres.c:860 msgid "Postgres database running\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:57 #, fuzzy, c-format msgid "`%s' failed at %s:%u with error: %s" msgstr "\"%s\" misslyckades vid %s:%d med fel: %s\n" #: src/datastore/plugin_datastore_sqlite.c:233 #: src/namestore/plugin_namestore_sqlite.c:204 #, fuzzy, c-format msgid "Option `%s' in section `%s' missing in configuration!\n" msgstr "Inga applikationer definierade i konfiguration!\n" #: src/datastore/plugin_datastore_sqlite.c:260 #: src/namestore/plugin_namestore_sqlite.c:229 #, fuzzy, c-format msgid "Unable to initialize SQLite: %s.\n" msgstr "Kunde inte initiera SQLite.\n" #: src/datastore/plugin_datastore_sqlite.c:655 msgid "Invalid data in database. Trying to fix (by deletion).\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:1139 msgid "sqlite version to old to determine size, assuming zero\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:1158 #, c-format msgid "" "Using sqlite page utilization to estimate payload (%llu pages of size %llu " "bytes)\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:1198 #: src/namestore/plugin_namestore_sqlite.c:829 msgid "Sqlite database running\n" msgstr "" #: src/datastore/plugin_datastore_template.c:241 msgid "Template database running\n" msgstr "" #: src/dht/dht_api.c:348 #, fuzzy msgid "Failed to connect to the DHT service!\n" msgstr "Misslyckades att ansluta till gnunetd.\n" #: src/dht/gnunet-dht-get.c:201 src/dht/gnunet-dht-monitor.c:293 #: src/dht/gnunet-dht-put.c:192 msgid "the query key" msgstr "" #: src/dht/gnunet-dht-get.c:204 msgid "how many parallel requests (replicas) to create" msgstr "" #: src/dht/gnunet-dht-get.c:207 src/dht/gnunet-dht-monitor.c:296 msgid "the type of data to look for" msgstr "" #: src/dht/gnunet-dht-get.c:210 src/dht/gnunet-dht-put.c:201 msgid "how long to execute this query before giving up?" msgstr "" #: src/dht/gnunet-dht-get.c:213 src/dht/gnunet-dht-monitor.c:302 #: src/dht/gnunet-dht-put.c:204 src/fs/gnunet-download.c:271 #: src/fs/gnunet-publish.c:731 src/fs/gnunet-search.c:297 #: src/fs/gnunet-unindex.c:169 src/nse/gnunet-nse-profiler.c:910 msgid "be verbose (print progress information)" msgstr "" #: src/dht/gnunet-dht-get.c:232 msgid "Issue a GET request to the GNUnet DHT, prints results." msgstr "" #: src/dht/gnunet-dht-monitor.c:299 msgid "how long to execute? 0 = forever" msgstr "" #: src/dht/gnunet-dht-monitor.c:321 msgid "Prints all packets that go through the DHT." msgstr "" #: src/dht/gnunet-dht-put.c:108 msgid "PUT request sent!\n" msgstr "" #: src/dht/gnunet-dht-put.c:111 msgid "Timeout sending PUT request!\n" msgstr "" #: src/dht/gnunet-dht-put.c:114 #, fuzzy msgid "PUT request not confirmed!\n" msgstr "# byte mottogs via TCP" #: src/dht/gnunet-dht-put.c:144 msgid "Must provide KEY and DATA for DHT put!\n" msgstr "" #: src/dht/gnunet-dht-put.c:152 #, fuzzy, c-format msgid "Could not connect to %s service!\n" msgstr "Kunde inte ansluta till gnunetd.\n" #: src/dht/gnunet-dht-put.c:157 #, fuzzy, c-format msgid "Connected to %s service!\n" msgstr "\"%s\" ansluten till \"%s\".\n" #: src/dht/gnunet-dht-put.c:172 #, c-format msgid "Issuing put request for `%s' with data `%s'!\n" msgstr "" #: src/dht/gnunet-dht-put.c:186 msgid "the data to insert under the key" msgstr "" #: src/dht/gnunet-dht-put.c:189 msgid "how long to store this entry in the dht (in seconds)" msgstr "" #: src/dht/gnunet-dht-put.c:195 msgid "how many replicas to create" msgstr "" #: src/dht/gnunet-dht-put.c:198 msgid "the type to insert data as" msgstr "" #: src/dht/gnunet-dht-put.c:223 msgid "Issue a PUT request to the GNUnet DHT insert DATA under KEY." msgstr "" #: src/dht/gnunet-service-dht.c:163 src/testing/testing.c:544 #: src/testing/testing.c:1968 src/testing/testing.c:1998 #, fuzzy msgid "Failed to connect to transport service!\n" msgstr "Misslyckades att ansluta till gnunetd.\n" #: src/dht/gnunet-service-dht_clients.c:407 #, fuzzy msgid "# GET requests from clients injected" msgstr "# byte mottogs via TCP" #: src/dht/gnunet-service-dht_clients.c:500 #, fuzzy msgid "# PUT requests received from clients" msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" #: src/dht/gnunet-service-dht_clients.c:584 #, fuzzy msgid "# GET requests received from clients" msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" #: src/dht/gnunet-service-dht_clients.c:682 #, fuzzy msgid "# GET STOP requests received from clients" msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" #: src/dht/gnunet-service-dht_clients.c:919 msgid "# Key match, type mismatches in REPLY to CLIENT" msgstr "" #: src/dht/gnunet-service-dht_clients.c:932 msgid "# Duplicate REPLIES to CLIENT request dropped" msgstr "" #: src/dht/gnunet-service-dht_clients.c:967 #, c-format msgid "Unsupported block type (%u) in request!\n" msgstr "" #: src/dht/gnunet-service-dht_clients.c:989 #, fuzzy msgid "# RESULTS queued for clients" msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" #: src/dht/gnunet-service-dht_clients.c:1038 #: src/dht/gnunet-service-dht_clients.c:1081 msgid "# REPLIES ignored for CLIENTS (no match)" msgstr "" #: src/dht/gnunet-service-dht_clients.c:1048 #, fuzzy msgid "Could not pass reply to client, message too big!\n" msgstr "Kunde inte skicka meddelande till gnunetd\n" #: src/dht/gnunet-service-dht_datacache.c:93 #, fuzzy, c-format msgid "%s request received, but have no datacache!\n" msgstr "# byte mottagna av typen %d" #: src/dht/gnunet-service-dht_datacache.c:103 msgid "# ITEMS stored in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:207 msgid "# Good RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:218 msgid "# Duplicate RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:224 msgid "# Invalid RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:236 msgid "# Unsupported RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:239 #, c-format msgid "Unsupported block type (%u) in local response!\n" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:269 #, fuzzy msgid "# GET requests given to datacache" msgstr "# byte mottogs via TCP" #: src/dht/gnunet-service-dht_hello.c:82 #, fuzzy msgid "# HELLOs obtained from peerinfo" msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" #: src/dht/gnunet-service-dht_neighbours.c:481 msgid "# Preference updates given to core" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:571 #, fuzzy msgid "# FIND PEER messages initiated" msgstr "# PING-meddelanden skapade" #: src/dht/gnunet-service-dht_neighbours.c:717 #, fuzzy msgid "# Queued messages discarded (peer disconnected)" msgstr "Nätverksannonsering avstängd i konfigurationen!\n" #: src/dht/gnunet-service-dht_neighbours.c:772 #, fuzzy msgid "# Bytes transmitted to other peers" msgstr "# byte skickade av typen %d" #: src/dht/gnunet-service-dht_neighbours.c:810 msgid "# Bytes of bandwdith requested from core" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1032 #: src/dht/gnunet-service-dht_neighbours.c:1060 msgid "# Peers excluded from routing due to Bloomfilter" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1041 #: src/dht/gnunet-service-dht_neighbours.c:1075 msgid "# Peer selection failed" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1207 #, fuzzy msgid "# PUT requests routed" msgstr "# byte mottogs via TCP" #: src/dht/gnunet-service-dht_neighbours.c:1236 #, fuzzy msgid "# PUT messages queued for transmission" msgstr "# PING-meddelanden skapade" #: src/dht/gnunet-service-dht_neighbours.c:1315 #, fuzzy msgid "# GET requests routed" msgstr "# byte mottogs via TCP" #: src/dht/gnunet-service-dht_neighbours.c:1342 #, fuzzy msgid "# GET messages queued for transmission" msgstr "# PING-meddelanden skapade" #: src/dht/gnunet-service-dht_neighbours.c:1443 #, fuzzy msgid "# RESULT messages queued for transmission" msgstr "# PING-meddelanden skapade" #: src/dht/gnunet-service-dht_neighbours.c:1531 #, fuzzy msgid "# P2P PUT requests received" msgstr "# byte mottogs via TCP" #: src/dht/gnunet-service-dht_neighbours.c:1647 msgid "# FIND PEER requests ignored due to Bloomfilter" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1655 msgid "# FIND PEER requests ignored due to lack of HELLO" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1746 #, fuzzy msgid "# P2P GET requests received" msgstr "# byte mottogs via TCP" #: src/dht/gnunet-service-dht_neighbours.c:1788 #, fuzzy msgid "# P2P FIND PEER requests processed" msgstr "# byte mottogs via TCP" #: src/dht/gnunet-service-dht_neighbours.c:1802 #, fuzzy msgid "# P2P GET requests ONLY routed" msgstr "# byte mottogs via TCP" #: src/dht/gnunet-service-dht_neighbours.c:1876 #, fuzzy msgid "# P2P RESULTS received" msgstr "# krypterade PONG-meddelanden mottagna" #: src/dht/gnunet-service-dht_nse.c:59 #, fuzzy msgid "# Network size estimates received" msgstr "# byte mottogs via TCP" #: src/dht/gnunet-service-dht_routing.c:211 msgid "# Good REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:220 msgid "# Duplicate REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:226 msgid "# Invalid REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:238 msgid "# Unsupported REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:311 msgid "# Entries removed from routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:352 msgid "# Entries added to routing table" msgstr "" #: src/dht/plugin_block_dht.c:136 #, fuzzy, c-format msgid "Block not of type %u\n" msgstr "Ingen transport av typ %d är känd.\n" #: src/dht/plugin_block_dht.c:143 msgid "Size mismatch for block\n" msgstr "" #: src/dht/plugin_block_dht.c:152 #, c-format msgid "Block of type %u is malformed\n" msgstr "" #: src/dns/gnunet-dns-monitor.c:337 msgid "only monitor DNS queries" msgstr "" #: src/dns/gnunet-dns-monitor.c:340 msgid "only monitor DNS replies" msgstr "" #: src/dns/gnunet-dns-monitor.c:348 msgid "Monitor DNS queries." msgstr "" #: src/dns/gnunet-dns-redirector.c:236 msgid "set A records" msgstr "" #: src/dns/gnunet-dns-redirector.c:239 msgid "set AAAA records" msgstr "" #: src/dns/gnunet-dns-redirector.c:247 msgid "Change DNS replies to point elsewhere." msgstr "" #: src/dns/gnunet-service-dns.c:485 #, fuzzy, c-format msgid "Could not bind to any port: %s\n" msgstr "Kunde inte köra \"%s\": %s\n" #: src/dns/gnunet-service-dns.c:639 msgid "# DNS requests answered via TUN interface" msgstr "" #: src/dns/gnunet-service-dns.c:822 msgid "# DNS exit failed (failed to open socket)" msgstr "" #: src/dns/gnunet-service-dns.c:1005 #, c-format msgid "Received DNS response that is too small (%u bytes)" msgstr "" #: src/dns/gnunet-service-dns.c:1050 msgid "# External DNS response discarded (no matching request)" msgstr "" #: src/dns/gnunet-service-dns.c:1168 msgid "# Client response discarded (no matching request)" msgstr "" #: src/dns/gnunet-service-dns.c:1281 msgid "Received malformed IPv4-UDP packet on TUN interface.\n" msgstr "" #: src/dns/gnunet-service-dns.c:1297 msgid "Received malformed IPv6-UDP packet on TUN interface.\n" msgstr "" #: src/dns/gnunet-service-dns.c:1306 #, c-format msgid "Got non-IP packet with %u bytes and protocol %u from TUN\n" msgstr "" #: src/dns/gnunet-service-dns.c:1315 msgid "# Non-DNS UDP packet received via TUN interface" msgstr "" #: src/dns/gnunet-service-dns.c:1380 #, fuzzy msgid "# DNS requests received via TUN interface" msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" #: src/dns/gnunet-service-dns.c:1465 #, c-format msgid "Configured DNS exit `%s' is not working / valid.\n" msgstr "" #: src/dns/gnunet-service-dns.c:1497 src/exit/gnunet-daemon-exit.c:2674 msgid "# Inbound MESH tunnels created" msgstr "" #: src/dns/gnunet-service-dns.c:1561 src/exit/gnunet-daemon-exit.c:3032 #, c-format msgid "`%s' must be installed SUID, refusing to run\n" msgstr "" #: src/dns/gnunet-service-dns.c:1581 msgid "Configured to provide DNS exit, but no valid DNS server configured!\n" msgstr "" #: src/dv/dv_api.c:179 #, fuzzy msgid "Failed to connect to the dv service!\n" msgstr "Misslyckades att ansluta till gnunetd.\n" #: src/dv/plugin_transport_dv.c:159 #, fuzzy, c-format msgid "%s Received message from %s of type %d, distance %u!\n" msgstr "Mottog skadat meddelande frÃ¥n motpart \"%s\"i %s:%d.\n" #: src/exit/gnunet-daemon-exit.c:508 #, c-format msgid "Got duplicate service records for `%s:%u'\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:563 #, fuzzy msgid "# Bytes transmitted via mesh tunnels" msgstr "# byte skickade av typen %d" #: src/exit/gnunet-daemon-exit.c:679 src/exit/gnunet-daemon-exit.c:2069 #: src/exit/gnunet-daemon-exit.c:2319 src/vpn/gnunet-service-vpn.c:1394 #: src/vpn/gnunet-service-vpn.c:1795 src/vpn/gnunet-service-vpn.c:1958 msgid "# ICMPv4 packets dropped (type not allowed)" msgstr "" #: src/exit/gnunet-daemon-exit.c:716 src/exit/gnunet-daemon-exit.c:2128 #: src/exit/gnunet-daemon-exit.c:2378 src/vpn/gnunet-service-vpn.c:1450 #: src/vpn/gnunet-service-vpn.c:1854 src/vpn/gnunet-service-vpn.c:1991 msgid "# ICMPv6 packets dropped (type not allowed)" msgstr "" #: src/exit/gnunet-daemon-exit.c:756 msgid "# ICMP packets dropped (not allowed)" msgstr "" #: src/exit/gnunet-daemon-exit.c:763 msgid "ICMP Packet dropped, have no matching connection information\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:840 msgid "UDP Packet dropped, have no matching connection information\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:915 msgid "TCP Packet dropped, have no matching connection information\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:968 #, fuzzy msgid "# Packets received from TUN" msgstr "# byte mottagna via HTTP" #: src/exit/gnunet-daemon-exit.c:982 #, fuzzy msgid "# Bytes received from TUN" msgstr "# byte mottagna via HTTP" #: src/exit/gnunet-daemon-exit.c:1008 msgid "IPv4 packet options received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1035 #, c-format msgid "IPv4 packet with unsupported next header %u received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1081 #, c-format msgid "IPv6 packet with unsupported next header %d received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1089 #, c-format msgid "Packet from unknown protocol %u received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1471 #, fuzzy msgid "# TCP packets sent via TUN" msgstr "# byte skickade via UDP" #: src/exit/gnunet-daemon-exit.c:1571 msgid "# TCP service creation requests received via mesh" msgstr "" #: src/exit/gnunet-daemon-exit.c:1574 src/exit/gnunet-daemon-exit.c:1653 #: src/exit/gnunet-daemon-exit.c:1763 src/exit/gnunet-daemon-exit.c:1993 #: src/exit/gnunet-daemon-exit.c:2235 src/exit/gnunet-daemon-exit.c:2516 #: src/exit/gnunet-daemon-exit.c:2616 #, fuzzy msgid "# Bytes received from MESH" msgstr "# byte mottagna via HTTP" #: src/exit/gnunet-daemon-exit.c:1607 src/exit/gnunet-daemon-exit.c:2638 #, c-format msgid "No service found for %s on port %d!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1611 #, fuzzy msgid "# TCP requests dropped (no such service)" msgstr "# byte mottogs via TCP" #: src/exit/gnunet-daemon-exit.c:1656 #, fuzzy msgid "# TCP IP-exit creation requests received via mesh" msgstr "# byte mottogs via TCP" #: src/exit/gnunet-daemon-exit.c:1766 #, fuzzy msgid "# TCP data requests received via mesh" msgstr "# byte mottogs via TCP" #: src/exit/gnunet-daemon-exit.c:1780 #, fuzzy msgid "# TCP DATA requests dropped (no session)" msgstr "# byte mottogs via TCP" #: src/exit/gnunet-daemon-exit.c:1830 #, fuzzy msgid "# ICMP packets sent via TUN" msgstr "# byte skickade via UDP" #: src/exit/gnunet-daemon-exit.c:1996 #, fuzzy msgid "# ICMP IP-exit requests received via mesh" msgstr "# byte mottogs via TCP" #: src/exit/gnunet-daemon-exit.c:2238 #, fuzzy msgid "# ICMP service requests received via mesh" msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" #: src/exit/gnunet-daemon-exit.c:2304 src/vpn/gnunet-service-vpn.c:1384 #: src/vpn/gnunet-service-vpn.c:1952 msgid "# ICMPv4 packets dropped (impossible PT to v6)" msgstr "" #: src/exit/gnunet-daemon-exit.c:2363 src/vpn/gnunet-service-vpn.c:1420 #: src/vpn/gnunet-service-vpn.c:1432 src/vpn/gnunet-service-vpn.c:1842 msgid "# ICMPv6 packets dropped (impossible PT to v4)" msgstr "" #: src/exit/gnunet-daemon-exit.c:2413 #, fuzzy msgid "# UDP packets sent via TUN" msgstr "# byte skickade via UDP" #: src/exit/gnunet-daemon-exit.c:2519 #, fuzzy msgid "# UDP IP-exit requests received via mesh" msgstr "# byte mottogs via TCP" #: src/exit/gnunet-daemon-exit.c:2619 #, fuzzy msgid "# UDP service requests received via mesh" msgstr "# byte mottogs via TCP" #: src/exit/gnunet-daemon-exit.c:2642 #, fuzzy msgid "# UDP requests dropped (no such service)" msgstr "# byte mottogs via TCP" #: src/exit/gnunet-daemon-exit.c:2882 #, c-format msgid "No addresses found for hostname `%s' of service `%s'!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:2896 src/exit/gnunet-daemon-exit.c:2908 #, c-format msgid "Service `%s' configured for IPv4, but IPv4 is disabled!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:2919 #, c-format msgid "No IP addresses found for hostname `%s' of service `%s'!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3048 msgid "" "This system does not support IPv4, will disable IPv4 functions despite them " "being enabled in the configuration\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3056 msgid "" "This system does not support IPv6, will disable IPv6 functions despite them " "being enabled in the configuration\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3063 msgid "" "Cannot enable IPv4 exit but disable IPv4 on TUN interface, will use " "ENABLE_IPv4=YES\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3069 msgid "" "Cannot enable IPv6 exit but disable IPv6 on TUN interface, will use " "ENABLE_IPv6=YES\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3075 src/pt/gnunet-daemon-pt.c:884 msgid "No useful service enabled. Exiting.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3236 msgid "Daemon to run to provide an IP exit node for the VPN" msgstr "" #: src/fragmentation/defragmentation.c:270 msgid "# acknowledgements sent for fragment" msgstr "" #: src/fragmentation/defragmentation.c:456 #, fuzzy msgid "# fragments received" msgstr "# byte mottogs via TCP" #: src/fragmentation/defragmentation.c:521 #, fuzzy msgid "# duplicate fragments received" msgstr "# byte mottogs via TCP" #: src/fragmentation/defragmentation.c:534 msgid "# messages defragmented" msgstr "" #: src/fragmentation/fragmentation.c:203 #, fuzzy msgid "# fragments transmitted" msgstr "# byte skickade av typen %d" #: src/fragmentation/fragmentation.c:206 #, fuzzy msgid "# fragments retransmitted" msgstr "# byte skickade av typen %d" #: src/fragmentation/fragmentation.c:232 #, fuzzy msgid "# fragments wrap arounds" msgstr "# byte skickade av typen %d" #: src/fragmentation/fragmentation.c:273 msgid "# messages fragmented" msgstr "" #: src/fragmentation/fragmentation.c:276 msgid "# total size of fragmented messages" msgstr "" #: src/fragmentation/fragmentation.c:363 msgid "# fragment acknowledgements received" msgstr "" #: src/fragmentation/fragmentation.c:369 msgid "# bits removed from fragmentation ACKs" msgstr "" #: src/fragmentation/fragmentation.c:393 #, fuzzy msgid "# fragmentation transmissions completed" msgstr "# klartext PONG-meddelanden mottagna" #: src/fs/fs_api.c:339 #, fuzzy, c-format msgid "Could not open file `%s': %s" msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" #: src/fs/fs_api.c:348 #, fuzzy, c-format msgid "Could not read file `%s': %s" msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" #: src/fs/fs_api.c:354 #, c-format msgid "Short read reading from file `%s'!" msgstr "" #: src/fs/fs_api.c:938 #, fuzzy, c-format msgid "Failed to resume publishing information `%s': %s\n" msgstr "Misslyckades att leverera \"%s\" meddelande.\n" #: src/fs/fs_api.c:1395 #, c-format msgid "Failed to recover namespace `%s', cannot resume publishing operation.\n" msgstr "" #: src/fs/fs_api.c:1437 #, c-format msgid "Failure while resuming publishing operation `%s': %s\n" msgstr "" #: src/fs/fs_api.c:1453 #, fuzzy, c-format msgid "Failed to resume publishing operation `%s': %s\n" msgstr "Misslyckades att leverera \"%s\" meddelande.\n" #: src/fs/fs_api.c:2106 #, c-format msgid "Failure while resuming unindexing operation `%s': %s\n" msgstr "" #: src/fs/fs_api.c:2116 #, fuzzy, c-format msgid "Failed to resume unindexing operation `%s': %s\n" msgstr "Misslyckades att leverera \"%s\" meddelande.\n" #: src/fs/fs_api.c:2241 src/fs/fs_api.c:2480 #, fuzzy, c-format msgid "Failed to resume sub-download `%s': %s\n" msgstr "Misslyckades att leverera \"%s\" meddelande.\n" #: src/fs/fs_api.c:2258 #, fuzzy, c-format msgid "Failed to resume sub-search `%s': %s\n" msgstr "Misslyckades att leverera \"%s\" meddelande.\n" #: src/fs/fs_api.c:2270 src/fs/fs_api.c:2289 src/fs/fs_api.c:2773 #, c-format msgid "Failure while resuming search operation `%s': %s\n" msgstr "" #: src/fs/fs_api.c:2471 #, c-format msgid "Failed to resume sub-download `%s': could not open file `%s'\n" msgstr "" #: src/fs/fs_api.c:2717 msgid "Could not resume running search, will resume as paused search\n" msgstr "" #: src/fs/fs_api.c:2811 #, c-format msgid "Failure while resuming download operation `%s': %s\n" msgstr "" #: src/fs/fs_directory.c:210 #, fuzzy msgid "MAGIC mismatch. This is not a GNUnet directory.\n" msgstr "Filformatsfel (inte en GNUnet-katalog?)\n" #: src/fs/fs_download.c:311 msgid "" "Recursive downloads of directories larger than 4 GB are not supported on 32-" "bit systems\n" msgstr "" #: src/fs/fs_download.c:331 msgid "Directory too large for system address space\n" msgstr "" #: src/fs/fs_download.c:497 src/fs/fs_download.c:509 #, fuzzy, c-format msgid "Failed to open file `%s' for writing" msgstr "Misslyckades att leverera \"%s\" meddelande.\n" #: src/fs/fs_download.c:878 #, fuzzy, c-format msgid "Failed to create directory for recursive download of `%s'\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/fs/fs_download.c:960 #, c-format msgid "" "Internal error or bogus download URI (expected %u bytes at depth %u and " "offset %llu/%llu, got %u bytes)" msgstr "" #: src/fs/fs_download.c:986 msgid "internal error decrypting content" msgstr "" #: src/fs/fs_download.c:1009 #, fuzzy, c-format msgid "Download failed: could not open file `%s': %s" msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" #: src/fs/fs_download.c:1019 #, fuzzy, c-format msgid "Failed to seek to offset %llu in file `%s': %s" msgstr "Misslyckades att leverera \"%s\" meddelande.\n" #: src/fs/fs_download.c:1028 #, fuzzy, c-format msgid "Failed to write block of %u bytes at offset %llu in file `%s': %s" msgstr "Misslyckades att leverera \"%s\" meddelande.\n" #: src/fs/fs_download.c:1125 #, fuzzy msgid "internal error decoding tree" msgstr "=\tFel vid läsning av katalog.\n" #: src/fs/fs_download.c:1888 #, fuzzy msgid "Invalid URI" msgstr "Ogiltiga argument: " #: src/fs/fs_getopt.c:191 #, c-format msgid "" "Unknown metadata type in metadata option `%s'. Using metadata type " "`unknown' instead.\n" msgstr "" #: src/fs/fs_list_indexed.c:90 #, fuzzy, c-format msgid "Failed to receive response for `%s' request from `%s' service.\n" msgstr "Misslyckades att ta emot svar till \"%s\" meddelande frÃ¥n gnunetd\n" #: src/fs/fs_list_indexed.c:113 #, fuzzy, c-format msgid "Failed to receive valid response for `%s' request from `%s' service.\n" msgstr "Misslyckades att ta emot svar till \"%s\" meddelande frÃ¥n gnunetd\n" #: src/fs/fs_list_indexed.c:151 #, fuzzy, c-format msgid "Failed to not connect to `%s' service.\n" msgstr "Misslyckades att initiera tjänsten \"%s\".\n" #: src/fs/fs_misc.c:126 #, fuzzy, c-format msgid "Did not find mime type `%s' in extension list.\n" msgstr "Kunde inte hitta motpart \"%s\" i routingtabell!\n" #: src/fs/fs_namespace_advertise.c:150 #, fuzzy msgid "Unknown error" msgstr "Okänt fel" #: src/fs/fs_namespace_advertise.c:238 src/fs/fs_namespace_advertise.c:259 #, fuzzy msgid "Failed to serialize meta data" msgstr "Misslyckades att leverera \"%s\" meddelande.\n" #: src/fs/fs_namespace_advertise.c:278 #, fuzzy msgid "Failed to connect to datastore service" msgstr "Misslyckades att ansluta till gnunetd.\n" #: src/fs/fs_namespace.c:57 src/fs/fs_namespace.c:83 #, fuzzy, c-format msgid "Configuration fails to specify `%s' in section `%s'\n" msgstr "Konfigurationsfil \"%s\" skapad.\n" #: src/fs/fs_namespace.c:112 #, fuzzy, c-format msgid "Failed to open `%s' for writing: %s\n" msgstr "Misslyckades att leverera \"%s\" meddelande.\n" #: src/fs/fs_namespace.c:134 src/fs/fs_namespace.c:222 #, fuzzy, c-format msgid "Failed to write `%s': %s\n" msgstr "Fel vid %s:%d.\n" #: src/fs/fs_namespace.c:256 #, fuzzy, c-format msgid "Failed to create or read private key for namespace `%s'\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/fs/fs_namespace.c:371 #, c-format msgid "Failed to read namespace private key file `%s', deleting it!\n" msgstr "" #: src/fs/fs_namespace.c:588 src/fs/fs_publish_ksk.c:295 #, fuzzy msgid "Internal error." msgstr "Okänt fel.\n" #: src/fs/fs_namespace.c:631 #, fuzzy msgid "Failed to connect to datastore." msgstr "Misslyckades att ansluta till gnunetd.\n" #: src/fs/fs_publish.c:129 src/fs/fs_publish.c:397 #, fuzzy, c-format msgid "Publishing failed: %s" msgstr "" "\n" "Fel vid uppladdning av fil: %s\n" #: src/fs/fs_publish.c:621 src/fs/fs_publish.c:638 src/fs/fs_publish.c:677 #: src/fs/fs_publish.c:697 src/fs/fs_publish.c:722 src/fs/fs_publish.c:862 #, fuzzy, c-format msgid "Can not index file `%s': %s. Will try to insert instead.\n" msgstr "Indexering av fil \"%s\" misslyckades. Försöker att infoga fil...\n" #: src/fs/fs_publish.c:623 msgid "timeout on index-start request to `fs' service" msgstr "" #: src/fs/fs_publish.c:635 #, fuzzy msgid "unknown error" msgstr "Okänt fel" #: src/fs/fs_publish.c:678 msgid "failed to compute hash" msgstr "" #: src/fs/fs_publish.c:698 msgid "filename too long" msgstr "" #: src/fs/fs_publish.c:723 #, fuzzy msgid "could not connect to `fs' service" msgstr "Kunde inte ansluta till gnunetd.\n" #: src/fs/fs_publish.c:746 #, fuzzy, c-format msgid "Failed to get file identifiers for `%s'\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/fs/fs_publish.c:811 #, fuzzy, c-format msgid "Recursive upload failed at `%s': %s" msgstr "\"%s\" misslyckades vid %s:%d med fel: \"%s\".\n" #: src/fs/fs_publish.c:817 #, fuzzy, c-format msgid "Recursive upload failed: %s" msgstr "" "\n" "Fel vid uppladdning av fil: %s\n" #: src/fs/fs_publish.c:863 msgid "needs to be an actual file" msgstr "" #: src/fs/fs_publish.c:1071 #, c-format msgid "Insufficient space for publishing: %s" msgstr "" #: src/fs/fs_publish.c:1142 #, c-format msgid "Reserving space for %u entries and %llu bytes for publication\n" msgstr "" #: src/fs/fs_publish_ksk.c:258 #, fuzzy msgid "Could not connect to datastore." msgstr "Kunde inte ansluta till gnunetd.\n" #: src/fs/fs_search.c:829 #, c-format msgid "Got result with unknown block type `%d', ignoring" msgstr "" #: src/fs/fs_test_lib.c:269 #, fuzzy, c-format msgid "Failed to start daemon: %s\n" msgstr "Misslyckades att starta samling.\n" #: src/fs/fs_unindex.c:58 msgid "Failed to find given position in file" msgstr "" #: src/fs/fs_unindex.c:63 #, fuzzy msgid "Failed to read file" msgstr "Misslyckades att leverera \"%s\" meddelande.\n" #: src/fs/fs_unindex.c:233 msgid "Unexpected time for a response from `fs' service." msgstr "" #: src/fs/fs_unindex.c:241 msgid "Timeout waiting for `fs' service." msgstr "" #: src/fs/fs_unindex.c:249 #, fuzzy msgid "Invalid response from `fs' service." msgstr "Ogiltigt svar till \"%s\" frÃ¥n \"%s\"\n" #: src/fs/fs_unindex.c:293 #, fuzzy msgid "Failed to connect to FS service for unindexing." msgstr "Misslyckades att ansluta till gnunetd.\n" #: src/fs/fs_unindex.c:344 #, fuzzy msgid "Failed to get KSKs from directory scan." msgstr "Filformatsfel (inte en GNUnet-katalog?)\n" #: src/fs/fs_unindex.c:356 #, fuzzy, c-format msgid "Internal error scanning `%s'.\n" msgstr "=\tFel vid läsning av katalog.\n" #: src/fs/fs_unindex.c:411 #, fuzzy, c-format msgid "Failed to remove KBlock: %s\n" msgstr "Misslyckades att leverera \"%s\" meddelande.\n" #: src/fs/fs_unindex.c:501 #, fuzzy, c-format msgid "Failed to parse URI `%s' from KBlock!\n" msgstr "Fil \"%s\" har URI: %s\n" #: src/fs/fs_unindex.c:553 src/fs/fs_unindex.c:618 #, fuzzy msgid "Failed to connect to `datastore' service." msgstr "Misslyckades att initiera tjänsten \"%s\".\n" #: src/fs/fs_unindex.c:631 #, fuzzy msgid "Failed to open file for unindexing." msgstr "Misslyckades att ansluta till gnunetd.\n" #: src/fs/fs_unindex.c:665 #, fuzzy msgid "Failed to compute hash of file." msgstr "Misslyckades att ansluta till gnunetd.\n" #: src/fs/fs_uri.c:220 #, c-format msgid "`%' must be followed by HEX number" msgstr "" #: src/fs/fs_uri.c:279 #, fuzzy msgid "Malformed KSK URI (must not begin or end with `+')" msgstr "Ogiltig URL \"%s\" (mÃ¥ste börja med \"%s\")\n" #: src/fs/fs_uri.c:297 msgid "`++' not allowed in KSK URI" msgstr "" #: src/fs/fs_uri.c:304 msgid "Quotes not balanced in KSK URI" msgstr "" #: src/fs/fs_uri.c:372 src/fs/fs_uri.c:379 msgid "Malformed SKS URI" msgstr "" #: src/fs/fs_uri.c:423 src/fs/fs_uri.c:438 msgid "Malformed CHK URI" msgstr "" #: src/fs/fs_uri.c:568 src/fs/fs_uri.c:583 src/fs/fs_uri.c:593 #: src/fs/fs_uri.c:621 msgid "SKS URI malformed" msgstr "" #: src/fs/fs_uri.c:603 msgid "SKS URI malformed (could not decode public key)" msgstr "" #: src/fs/fs_uri.c:609 msgid "SKS URI malformed (could not find signature)" msgstr "" #: src/fs/fs_uri.c:615 msgid "SKS URI malformed (could not decode signature)" msgstr "" #: src/fs/fs_uri.c:628 msgid "SKS URI malformed (could not parse expiration time)" msgstr "" #: src/fs/fs_uri.c:640 msgid "SKS URI malformed (signature failed validation)" msgstr "" #: src/fs/fs_uri.c:678 msgid "Unrecognized URI type" msgstr "" #: src/fs/fs_uri.c:903 #, fuzzy msgid "Lacking key configuration settings.\n" msgstr "GNUnet-konfiguration" #: src/fs/fs_uri.c:910 #, fuzzy, c-format msgid "Could not access hostkey file `%s'.\n" msgstr "Kunde inte tolka konfigurationsfil \"%s\".\n" #: src/fs/fs_uri.c:1115 src/fs/fs_uri.c:1142 msgid "No keywords specified!\n" msgstr "Inga nyckelord angivna!\n" #: src/fs/fs_uri.c:1148 msgid "Number of double-quotes not balanced!\n" msgstr "" #: src/fs/gnunet-directory.c:49 #, c-format msgid "\t\n" msgstr "" #: src/fs/gnunet-directory.c:94 #, fuzzy, c-format msgid "Directory `%s' meta data:\n" msgstr "==> Katalog \"%s\":\n" #: src/fs/gnunet-directory.c:97 #, fuzzy, c-format msgid "Directory `%s' contents:\n" msgstr "==> Katalog \"%s\":\n" #: src/fs/gnunet-directory.c:132 #, fuzzy msgid "You must specify a filename to inspect.\n" msgstr "Du mÃ¥ste ange en lista av filer att lägga in.\n" #: src/fs/gnunet-directory.c:145 #, fuzzy, c-format msgid "Failed to read directory `%s'\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/fs/gnunet-directory.c:154 #, fuzzy, c-format msgid "`%s' is not a GNUnet directory\n" msgstr "Filformatsfel (inte en GNUnet-katalog?)\n" #: src/fs/gnunet-directory.c:179 #, fuzzy msgid "Display contents of a GNUnet directory" msgstr "Filformatsfel (inte en GNUnet-katalog?)\n" #: src/fs/gnunet-download.c:101 #, fuzzy, c-format msgid "Starting download `%s'.\n" msgstr "Startade samling \"%s\".\n" #: src/fs/gnunet-download.c:110 #, fuzzy msgid "" msgstr "Okänt fel" #: src/fs/gnunet-download.c:119 #, c-format msgid "" "Downloading `%s' at %llu/%llu (%s remaining, %s/s). Block took %s to " "download\n" msgstr "" #: src/fs/gnunet-download.c:129 #, fuzzy, c-format msgid "Error downloading: %s.\n" msgstr "Fel vid nedladdning: %s\n" #: src/fs/gnunet-download.c:137 #, fuzzy, c-format msgid "Downloading `%s' done (%s/s).\n" msgstr "Uppladdning vägrades!" #: src/fs/gnunet-download.c:152 src/fs/gnunet-publish.c:190 #: src/fs/gnunet-search.c:190 src/fs/gnunet-unindex.c:109 #, c-format msgid "Unexpected status: %d\n" msgstr "" #: src/fs/gnunet-download.c:177 #, fuzzy msgid "You need to specify a URI argument.\n" msgstr "Du mÃ¥ste ange en och endast en fil att avindexera.\n" #: src/fs/gnunet-download.c:183 src/fs/gnunet-publish.c:624 #, fuzzy, c-format msgid "Failed to parse URI: %s\n" msgstr "Fil \"%s\" har URI: %s\n" #: src/fs/gnunet-download.c:190 msgid "Only CHK or LOC URIs supported.\n" msgstr "" #: src/fs/gnunet-download.c:197 msgid "Target filename must be specified.\n" msgstr "" #: src/fs/gnunet-download.c:211 src/fs/gnunet-publish.c:602 #: src/fs/gnunet-search.c:241 src/fs/gnunet-unindex.c:141 #, fuzzy, c-format msgid "Could not initialize `%s' subsystem.\n" msgstr "Misslyckades att initiera tjänsten \"%s\".\n" #: src/fs/gnunet-download.c:248 src/fs/gnunet-search.c:285 msgid "set the desired LEVEL of receiver-anonymity" msgstr "" #: src/fs/gnunet-download.c:251 msgid "delete incomplete downloads (when aborted with CTRL-C)" msgstr "" #: src/fs/gnunet-download.c:254 src/fs/gnunet-search.c:288 msgid "only search the local peer (no P2P network search)" msgstr "" #: src/fs/gnunet-download.c:257 msgid "write the file to FILENAME" msgstr "skriv filen till FILNAMN" #: src/fs/gnunet-download.c:261 msgid "set the maximum number of parallel downloads that is allowed" msgstr "" #: src/fs/gnunet-download.c:265 msgid "set the maximum number of parallel requests for blocks that is allowed" msgstr "" #: src/fs/gnunet-download.c:268 msgid "download a GNUnet directory recursively" msgstr "hämta en GNUnet-katalog rekursivt" #: src/fs/gnunet-download.c:278 msgid "" "Download files from GNUnet using a GNUnet CHK or LOC URI (gnunet://fs/" "chk/...)" msgstr "" #: src/fs/gnunet-fs.c:117 msgid "print a list of all indexed files" msgstr "" #: src/fs/gnunet-fs.c:124 #, fuzzy msgid "Special file-sharing operations" msgstr "Visa alla alternativ" #: src/fs/gnunet-pseudonym.c:160 src/statistics/gnunet-statistics.c:167 #, fuzzy, c-format msgid "Invalid argument `%s'\n" msgstr "Ogiltigt argument: \"%s\"\n" #: src/fs/gnunet-pseudonym.c:250 src/fs/gnunet-pseudonym.c:257 #: src/fs/gnunet-pseudonym.c:259 #, fuzzy, c-format msgid "Option `%s' ignored\n" msgstr "%s: flagga \"%s\" är tvetydig\n" #: src/fs/gnunet-pseudonym.c:279 src/fs/gnunet-publish.c:678 msgid "set the desired LEVEL of sender-anonymity" msgstr "" #: src/fs/gnunet-pseudonym.c:282 msgid "create or advertise namespace NAME" msgstr "" #: src/fs/gnunet-pseudonym.c:285 msgid "delete namespace NAME " msgstr "" #: src/fs/gnunet-pseudonym.c:288 msgid "" "add an additional keyword for the advertisment (this option can be specified " "multiple times)" msgstr "" #: src/fs/gnunet-pseudonym.c:292 src/fs/gnunet-publish.c:697 msgid "set the meta-data for the given TYPE to the given VALUE" msgstr "" #: src/fs/gnunet-pseudonym.c:295 msgid "print names of local namespaces" msgstr "" #: src/fs/gnunet-pseudonym.c:298 msgid "use the given PRIORITY for the advertisments" msgstr "" #: src/fs/gnunet-pseudonym.c:301 msgid "do not print names of remote namespaces" msgstr "" #: src/fs/gnunet-pseudonym.c:304 src/fs/gnunet-publish.c:716 msgid "set the desired replication LEVEL" msgstr "" #: src/fs/gnunet-pseudonym.c:307 #, fuzzy msgid "specify ID of the root of the namespace" msgstr "ange prioritet för innehÃ¥llet" #: src/fs/gnunet-pseudonym.c:310 msgid "change rating of namespace ID by VALUE" msgstr "" #: src/fs/gnunet-pseudonym.c:318 msgid "Manage GNUnet pseudonyms." msgstr "" #: src/fs/gnunet-publish.c:147 #, c-format msgid "Publishing `%s' at %llu/%llu (%s remaining)\n" msgstr "" #: src/fs/gnunet-publish.c:155 #, fuzzy, c-format msgid "Error publishing: %s.\n" msgstr "Fel vid nedladdning: %s\n" #: src/fs/gnunet-publish.c:165 #, c-format msgid "Publishing `%s' done.\n" msgstr "" #: src/fs/gnunet-publish.c:169 #, fuzzy, c-format msgid "URI is `%s'.\n" msgstr "Jag är ändpunkt \"%s\".\n" #: src/fs/gnunet-publish.c:187 #, fuzzy msgid "Cleanup after abort complete.\n" msgstr "\"%s\" uppstart klar.\n" #: src/fs/gnunet-publish.c:305 #, fuzzy, c-format msgid "Meta data for file `%s' (%s)\n" msgstr "Uppdaterar data för modul \"%s\"\n" #: src/fs/gnunet-publish.c:307 #, fuzzy, c-format msgid "Keywords for file `%s' (%s)\n" msgstr "Nyckelord för fil \"%s\":\n" #: src/fs/gnunet-publish.c:358 #, fuzzy, c-format msgid "Failed to create namespace `%s'\n" msgstr "Kunde inte skapa namnrymd \"%s\" (existerar?).\n" #: src/fs/gnunet-publish.c:433 #, fuzzy msgid "Could not publish\n" msgstr "Kunde inte köra \"%s\": %s\n" #: src/fs/gnunet-publish.c:460 #, fuzzy msgid "Could not start publishing.\n" msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" #: src/fs/gnunet-publish.c:491 #, fuzzy, c-format msgid "Scanning directory `%s'.\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/fs/gnunet-publish.c:493 #, fuzzy, c-format msgid "Scanning file `%s'.\n" msgstr "Startade samling \"%s\".\n" #: src/fs/gnunet-publish.c:498 #, c-format msgid "There was trouble processing file `%s', skipping it.\n" msgstr "" #: src/fs/gnunet-publish.c:503 #, fuzzy msgid "Preprocessing complete.\n" msgstr "Nedstängning klar.\n" #: src/fs/gnunet-publish.c:507 #, fuzzy, c-format msgid "Extracting meta data from file `%s' complete.\n" msgstr "Uppdaterar data för modul \"%s\"\n" #: src/fs/gnunet-publish.c:511 msgid "Meta data extraction has finished.\n" msgstr "" #: src/fs/gnunet-publish.c:518 #, fuzzy msgid "Internal error scanning directory.\n" msgstr "=\tFel vid läsning av katalog.\n" #: src/fs/gnunet-publish.c:552 #, c-format msgid "Cannot extract metadata from a URI!\n" msgstr "" #: src/fs/gnunet-publish.c:559 #, fuzzy, c-format msgid "You must specify one and only one filename for insertion.\n" msgstr "Du mÃ¥ste ange en och endast en fil att avindexera.\n" #: src/fs/gnunet-publish.c:565 #, fuzzy, c-format msgid "You must NOT specify an URI and a filename.\n" msgstr "Du mÃ¥ste ange en och endast en fil att avindexera.\n" #: src/fs/gnunet-publish.c:573 src/vpn/gnunet-vpn.c:214 #, fuzzy, c-format msgid "Option `%s' is required when using option `%s'.\n" msgstr "Kommando \"%s\" kräver ett argument (\"%s\").\n" #: src/fs/gnunet-publish.c:583 src/fs/gnunet-publish.c:590 #: src/transport/gnunet-transport.c:560 #, c-format msgid "Option `%s' makes no sense without option `%s'.\n" msgstr "" #: src/fs/gnunet-publish.c:612 #, fuzzy, c-format msgid "Could not create namespace `%s'\n" msgstr "Kunde inte skapa namnrymd \"%s\" (existerar?).\n" #: src/fs/gnunet-publish.c:645 #, fuzzy, c-format msgid "Failed to access `%s': %s\n" msgstr "Misslyckades att leverera \"%s\" meddelande.\n" #: src/fs/gnunet-publish.c:657 msgid "" "Failed to start meta directory scanner. Is gnunet-helper-publish-fs " "installed?\n" msgstr "" #: src/fs/gnunet-publish.c:682 msgid "disable adding the creation time to the metadata of the uploaded file" msgstr "" #: src/fs/gnunet-publish.c:685 msgid "do not use libextractor to add keywords or metadata" msgstr "" #: src/fs/gnunet-publish.c:689 msgid "" "print list of extracted keywords that would be used, but do not perform " "upload" msgstr "" #: src/fs/gnunet-publish.c:693 msgid "" "add an additional keyword for the top-level file or directory (this option " "can be specified multiple times)" msgstr "" #: src/fs/gnunet-publish.c:700 msgid "" "do not index, perform full insertion (stores entire file in encrypted form " "in GNUnet database)" msgstr "" #: src/fs/gnunet-publish.c:705 msgid "" "specify ID of an updated version to be published in the future (for " "namespace insertions only)" msgstr "" #: src/fs/gnunet-publish.c:709 msgid "specify the priority of the content" msgstr "ange prioritet för innehÃ¥llet" #: src/fs/gnunet-publish.c:713 msgid "publish the files under the pseudonym NAME (place file into namespace)" msgstr "" #: src/fs/gnunet-publish.c:719 msgid "" "only simulate the process but do not do any actual publishing (useful to " "compute URIs)" msgstr "" #: src/fs/gnunet-publish.c:723 msgid "" "set the ID of this version of the publication (for namespace insertions only)" msgstr "" #: src/fs/gnunet-publish.c:727 msgid "" "URI to be published (can be used instead of passing a file to add keywords " "to the file with the respective URI)" msgstr "" #: src/fs/gnunet-publish.c:742 msgid "Publish a file or directory on GNUnet" msgstr "" #: src/fs/gnunet-search.c:111 #, c-format msgid "Failed to write directory with search results to `%s'\n" msgstr "" #: src/fs/gnunet-search.c:181 #, fuzzy, c-format msgid "Error searching: %s.\n" msgstr "Fel vid lämning av DHT.\n" #: src/fs/gnunet-search.c:231 #, fuzzy msgid "Could not create keyword URI from arguments.\n" msgstr "Kunde inte skapa namnrymd \"%s\" (existerar?).\n" #: src/fs/gnunet-search.c:255 #, fuzzy msgid "Could not start searching.\n" msgstr "Kunde inte skapa namnrymd \"%s\" (existerar?).\n" #: src/fs/gnunet-search.c:291 msgid "write search results to file starting with PREFIX" msgstr "" #: src/fs/gnunet-search.c:294 msgid "automatically terminate search after VALUE ms" msgstr "" #: src/fs/gnunet-search.c:301 msgid "automatically terminate search after VALUE results are found" msgstr "" #: src/fs/gnunet-search.c:308 msgid "Search GNUnet for files that were published on GNUnet" msgstr "" #: src/fs/gnunet-service-fs.c:240 msgid "# running average P2P latency (ms)" msgstr "" #: src/fs/gnunet-service-fs.c:300 src/fs/gnunet-service-fs.c:489 msgid "# Loopback routes suppressed" msgstr "" #: src/fs/gnunet-service-fs.c:581 src/hostlist/gnunet-daemon-hostlist.c:297 #: src/topology/gnunet-daemon-topology.c:1330 #: src/topology/gnunet-daemon-topology.c:1337 #, fuzzy, c-format msgid "Failed to connect to `%s' service.\n" msgstr "Misslyckades att initiera tjänsten \"%s\".\n" #: src/fs/gnunet-service-fs_cp.c:696 #, fuzzy msgid "# migration stop messages received" msgstr "# krypterade PONG-meddelanden mottagna" #: src/fs/gnunet-service-fs_cp.c:700 #, c-format msgid "Migration of content to peer `%s' blocked for %llu ms\n" msgstr "" #: src/fs/gnunet-service-fs_cp.c:735 #, fuzzy msgid "# replies transmitted to other peers" msgstr "# byte skickade av typen %d" #: src/fs/gnunet-service-fs_cp.c:741 msgid "# replies dropped" msgstr "" #: src/fs/gnunet-service-fs_cp.c:766 src/fs/gnunet-service-fs_cp.c:1324 msgid "# P2P searches active" msgstr "" #: src/fs/gnunet-service-fs_cp.c:858 msgid "# artificial delays introduced (ms)" msgstr "" #: src/fs/gnunet-service-fs_cp.c:911 #, fuzzy msgid "# replies dropped due to type mismatch" msgstr "# byte mottagna av typen %d" #: src/fs/gnunet-service-fs_cp.c:919 #, fuzzy msgid "# replies received for other peers" msgstr "# byte mottagna av typen %d" #: src/fs/gnunet-service-fs_cp.c:933 msgid "# replies dropped due to insufficient cover traffic" msgstr "" #: src/fs/gnunet-service-fs_cp.c:971 msgid "# P2P searches destroyed due to ultimate reply" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1038 msgid "# requests done for free (low load)" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1062 msgid "# request dropped, priority insufficient" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1072 msgid "# requests done for a price (normal load)" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1151 msgid "# GET requests received (from other peers)" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1185 msgid "# requests dropped due to initiator not being connected" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1207 msgid "# requests dropped due to missing reverse route" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1267 msgid "# requests dropped due TTL underflow" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1293 msgid "# requests dropped due to higher-TTL request" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1322 #, fuzzy msgid "# P2P query messages received and processed" msgstr "# krypterade PONG-meddelanden mottagna" #: src/fs/gnunet-service-fs_cp.c:1687 #, fuzzy msgid "# migration stop messages sent" msgstr "# krypterade PONG-meddelanden mottagna" #: src/fs/gnunet-service-fs_indexing.c:113 #: src/fs/gnunet-service-fs_indexing.c:163 #, fuzzy, c-format msgid "Configuration option `%s' in section `%s' missing.\n" msgstr "Konfigurationsfil \"%s\" skapad.\n" #: src/fs/gnunet-service-fs_indexing.c:121 #: src/fs/gnunet-service-fs_indexing.c:177 #, fuzzy, c-format msgid "Could not open `%s'.\n" msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" #: src/fs/gnunet-service-fs_indexing.c:137 #, fuzzy, c-format msgid "Error writing `%s'.\n" msgstr "Fel vid skapandet av användare" #: src/fs/gnunet-service-fs_indexing.c:228 #, c-format msgid "" "Index request received for file `%s' is already indexed as `%s'. Permitting " "anyway.\n" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:266 #, c-format msgid "Hash mismatch trying to index file `%s' which has hash `%s'\n" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:481 #, fuzzy, c-format msgid "Failed to delete bogus block: %s\n" msgstr "Misslyckades att leverera \"%s\" meddelande.\n" #: src/fs/gnunet-service-fs_indexing.c:539 msgid "# index blocks removed: original file inaccessible" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:554 #, fuzzy, c-format msgid "Could not access indexed file `%s' (%s) at offset %llu: %s\n" msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" #: src/fs/gnunet-service-fs_indexing.c:556 #, fuzzy msgid "not indexed" msgstr "Avindexering misslyckades." #: src/fs/gnunet-service-fs_indexing.c:571 #, fuzzy, c-format msgid "Indexed file `%s' changed at offset %llu\n" msgstr "Indexering av data misslyckades vid position %i.\n" #: src/fs/gnunet-service-fs_lc.c:202 src/fs/gnunet-service-fs_lc.c:362 #: src/fs/gnunet-service-fs_lc.c:488 #, fuzzy msgid "# client searches active" msgstr "# klartext PONG-meddelanden mottagna" #: src/fs/gnunet-service-fs_lc.c:256 #, fuzzy msgid "# replies received for local clients" msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" #: src/fs/gnunet-service-fs_lc.c:321 #, fuzzy msgid "# client searches received" msgstr "# klartext PONG-meddelanden mottagna" #: src/fs/gnunet-service-fs_lc.c:356 msgid "# client searches updated (merged content seen list)" msgstr "" #: src/fs/gnunet-service-fs_pe.c:265 msgid "# average retransmission delay (ms)" msgstr "" #: src/fs/gnunet-service-fs_pe.c:391 #, fuzzy msgid "# transmission failed (core has no bandwidth)" msgstr "Ingen transport av typ %d är känd.\n" #: src/fs/gnunet-service-fs_pe.c:420 #, fuzzy msgid "# query messages sent to other peers" msgstr "# byte skickade av typen %d" #: src/fs/gnunet-service-fs_pe.c:469 msgid "# delay heap timeout" msgstr "" #: src/fs/gnunet-service-fs_pe.c:476 msgid "# query plans executed" msgstr "" #: src/fs/gnunet-service-fs_pe.c:538 #, fuzzy msgid "# requests merged" msgstr "# byte mottogs via TCP" #: src/fs/gnunet-service-fs_pe.c:544 #, fuzzy msgid "# requests refreshed" msgstr "# byte mottogs via TCP" #: src/fs/gnunet-service-fs_pe.c:597 src/fs/gnunet-service-fs_pe.c:681 #: src/fs/gnunet-service-fs_pe.c:748 msgid "# query plan entries" msgstr "" #: src/fs/gnunet-service-fs_pr.c:285 #, fuzzy msgid "# Pending requests created" msgstr "# byte mottogs via TCP" #: src/fs/gnunet-service-fs_pr.c:367 src/fs/gnunet-service-fs_pr.c:616 msgid "# Pending requests active" msgstr "" #: src/fs/gnunet-service-fs_pr.c:779 #, fuzzy msgid "# replies received and matched" msgstr "# byte mottagna av typen %d" #: src/fs/gnunet-service-fs_pr.c:808 msgid "# duplicate replies discarded (bloomfilter)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:822 #, c-format msgid "Unsupported block type %u\n" msgstr "" #: src/fs/gnunet-service-fs_pr.c:835 msgid "# results found locally" msgstr "" #: src/fs/gnunet-service-fs_pr.c:953 msgid "# Datastore `PUT' failures" msgstr "" #: src/fs/gnunet-service-fs_pr.c:980 #, fuzzy msgid "# storage requests dropped due to high load" msgstr "Nätverksannonsering avstängd i konfigurationen!\n" #: src/fs/gnunet-service-fs_pr.c:1015 #, fuzzy msgid "# Replies received from DHT" msgstr "# byte mottagna via HTTP" #: src/fs/gnunet-service-fs_pr.c:1106 #, c-format msgid "Datastore lookup already took %llu ms!\n" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1127 #, c-format msgid "On-demand lookup already took %llu ms!\n" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1174 msgid "# Datastore lookups concluded (no results)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1188 msgid "# Datastore lookups concluded (seen all)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1197 msgid "# Datastore lookups aborted (more than MAX_RESULTS)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1211 msgid "# requested DBLOCK or IBLOCK not found" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1224 msgid "# on-demand blocks matched requests" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1237 msgid "# on-demand lookups performed successfully" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1242 msgid "# on-demand lookups failed" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1269 src/fs/gnunet-service-fs_pr.c:1309 #: src/fs/gnunet-service-fs_pr.c:1447 msgid "# Datastore lookups concluded (error queueing)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1327 msgid "# Datastore lookups concluded (found last result)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1338 msgid "# Datastore lookups concluded (load too high)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1424 msgid "# Datastore lookups initiated" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1508 #, fuzzy msgid "# GAP PUT messages received" msgstr "# krypterade PONG-meddelanden mottagna" #: src/fs/gnunet-service-fs_pr.c:1601 src/fs/gnunet-service-fs_pr.c:1610 #, fuzzy, c-format msgid "Configuration fails to specify `%s', assuming default value." msgstr "Konfigurationsfil \"%s\" skapad.\n" #: src/fs/gnunet-service-fs_push.c:629 #, c-format msgid "" "Invalid value specified for option `%s' in section `%s', content pushing " "disabled\n" msgstr "" #: src/fs/gnunet-unindex.c:89 #, c-format msgid "Unindexing at %llu/%llu (%s remaining)\n" msgstr "" #: src/fs/gnunet-unindex.c:96 #, fuzzy, c-format msgid "Error unindexing: %s.\n" msgstr "" "\n" "Fel vid avindexering av fil: %s\n" #: src/fs/gnunet-unindex.c:101 #, fuzzy msgid "Unindexing done.\n" msgstr "Avindexera filer." #: src/fs/gnunet-unindex.c:131 #, fuzzy, c-format msgid "You must specify one and only one filename for unindexing.\n" msgstr "Du mÃ¥ste ange en och endast en fil att avindexera.\n" #: src/fs/gnunet-unindex.c:148 #, fuzzy msgid "Could not start unindex operation.\n" msgstr "Kunde inte komma Ã¥t namnrymdsinformation.\n" #: src/fs/gnunet-unindex.c:176 msgid "Unindex a file that was previously indexed with gnunet-publish." msgstr "" #: src/fs/plugin_block_fs.c:131 msgid "Reply mismatched in terms of namespace. Discarded.\n" msgstr "" #: src/gns/gnunet-gns.c:191 #, fuzzy msgid "Failed to connect to GNS\n" msgstr "Misslyckades att ansluta till gnunetd.\n" #: src/gns/gnunet-gns.c:232 msgid "try to shorten a given GNS name" msgstr "" #: src/gns/gnunet-gns.c:235 msgid "Lookup a record using GNS (NOT IMPLEMENTED)" msgstr "" #: src/gns/gnunet-gns.c:238 msgid "Get the authority of a particular name" msgstr "" #: src/gns/gnunet-gns.c:241 #, fuzzy msgid "Specify the type of the record lookup" msgstr "ange prioritet för innehÃ¥llet" #: src/gns/gnunet-gns.c:244 msgid "No unneeded output" msgstr "" #: src/gns/gnunet-gns.c:255 msgid "GNUnet GNS access tool" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:280 #, fuzzy, c-format msgid "Unsupported form value `%s'\n" msgstr "Kommando \"%s\" stöds ej. Avbryter.\n" #: src/gns/gnunet-gns-fcfsd.c:333 #, fuzzy, c-format msgid "Failed to create record for domain `%s': %s\n" msgstr "Kunde inte tolka konfigurationsfil \"%s\".\n" #: src/gns/gnunet-gns-fcfsd.c:377 #, c-format msgid "Found existing name `%s' for the given key\n" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:439 #, c-format msgid "Found %u existing records for domain `%s'\n" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:498 #, fuzzy, c-format msgid "Failed to create page for `%s'\n" msgstr "Kunde inte skapa namnrymd \"%s\" (existerar?).\n" #: src/gns/gnunet-gns-fcfsd.c:514 #, fuzzy, c-format msgid "Failed to setup post processor for `%s'\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/gns/gnunet-gns-fcfsd.c:725 src/gns/gnunet-gns-fcfsd.c:737 #, fuzzy, c-format msgid "Option `%s' not specified in configuration section `%s'\n" msgstr "Inga applikationer definierade i konfiguration!\n" #: src/gns/gnunet-gns-fcfsd.c:747 src/namestore/gnunet-namestore.c:299 #, fuzzy msgid "Failed to read or create private zone key\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/gns/gnunet-gns-fcfsd.c:757 src/namestore/gnunet-namestore.c:310 #, fuzzy msgid "Failed to connect to namestore\n" msgstr "Misslyckades att ansluta till gnunetd.\n" #: src/gns/gnunet-gns-fcfsd.c:773 src/gns/gnunet-gns-proxy.c:525 #, fuzzy msgid "Failed to start HTTP server\n" msgstr "Misslyckades att starta samling.\n" #: src/gns/gnunet-gns-fcfsd.c:804 msgid "GNUnet GNS first come first serve registration service" msgstr "" #: src/gns/gnunet-gns-proxy.c:800 msgid "listen on specified port" msgstr "" #: src/gns/gnunet-gns-proxy.c:811 msgid "GNUnet GNS proxy" msgstr "" #: src/hello/gnunet-hello.c:122 msgid "Call with name of HELLO file to modify.\n" msgstr "" #: src/hello/gnunet-hello.c:128 #, fuzzy, c-format msgid "Error accessing file `%s': %s\n" msgstr "Fel vid skapandet av användare" #: src/hello/gnunet-hello.c:136 #, c-format msgid "File `%s' is too big to be a HELLO\n" msgstr "" #: src/hello/gnunet-hello.c:143 #, c-format msgid "File `%s' is too small to be a HELLO\n" msgstr "" #: src/hello/gnunet-hello.c:153 src/hello/gnunet-hello.c:181 #, fuzzy, c-format msgid "Error opening file `%s': %s\n" msgstr "Fel vid skapandet av användare" #: src/hello/gnunet-hello.c:169 #, fuzzy, c-format msgid "Did not find well-formed HELLO in file `%s'\n" msgstr "%d filer hittades i katalog.\n" #: src/hello/gnunet-hello.c:193 #, fuzzy, c-format msgid "Error writing HELLO to file `%s': %s\n" msgstr "Fel vid skapandet av användare" #: src/hostlist/gnunet-daemon-hostlist.c:264 msgid "" "None of the functions for the hostlist daemon were enabled. I have no " "reason to run!\n" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:317 msgid "advertise our hostlist to other peers" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:322 msgid "" "bootstrap using hostlists (it is highly recommended that you always use this " "option)" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:325 msgid "enable learning about hostlist servers from other peers" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:329 msgid "provide a hostlist server" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:341 msgid "GNUnet hostlist server and client" msgstr "" #: src/hostlist/hostlist-client.c:289 msgid "# bytes downloaded from hostlist servers" msgstr "" #: src/hostlist/hostlist-client.c:310 src/hostlist/hostlist-client.c:340 msgid "# invalid HELLOs downloaded from hostlist servers" msgstr "" #: src/hostlist/hostlist-client.c:313 src/hostlist/hostlist-client.c:343 #, fuzzy, c-format msgid "Invalid `%s' message received from hostlist at `%s'\n" msgstr "Ogiltigt meddelande mottogs den %s:%d." #: src/hostlist/hostlist-client.c:331 msgid "# valid HELLOs downloaded from hostlist servers" msgstr "" #: src/hostlist/hostlist-client.c:375 src/hostlist/hostlist-client.c:396 #, c-format msgid "No `%s' specified in `%s' configuration, will not bootstrap.\n" msgstr "" #: src/hostlist/hostlist-client.c:473 src/hostlist/hostlist-client.c:683 #: src/hostlist/hostlist-client.c:689 src/hostlist/hostlist-client.c:741 #: src/hostlist/hostlist-client.c:750 src/hostlist/hostlist-client.c:871 #: src/hostlist/hostlist-client.c:961 src/hostlist/hostlist-client.c:966 #: src/transport/plugin_transport_http_client.c:110 #: src/transport/plugin_transport_http_client.c:125 #, fuzzy, c-format msgid "%s failed at %s:%d: `%s'\n" msgstr "\"%s\" misslyckades vid %s:%d med fel: \"%s\".\n" #: src/hostlist/hostlist-client.c:593 src/hostlist/hostlist-client.c:1331 msgid "# advertised hostlist URIs" msgstr "" #: src/hostlist/hostlist-client.c:623 #, c-format msgid "# advertised URI `%s' downloaded" msgstr "" #: src/hostlist/hostlist-client.c:664 #, c-format msgid "" "Advertised hostlist with URI `%s' could not be downloaded. Advertised URI " "gets dismissed.\n" msgstr "" #: src/hostlist/hostlist-client.c:802 #, fuzzy, c-format msgid "Timeout trying to download hostlist from `%s'\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/hostlist/hostlist-client.c:816 #, c-format msgid "Download limit of %u bytes exceeded, stopping download\n" msgstr "" #: src/hostlist/hostlist-client.c:836 #, fuzzy, c-format msgid "Download of hostlist from `%s' failed: `%s'\n" msgstr "" "Uppladdning av \"%s\" klar, aktuell genomsnittshastighet är %8.3f kbps.\n" #: src/hostlist/hostlist-client.c:842 #, fuzzy, c-format msgid "Download of hostlist `%s' completed.\n" msgstr "" "Uppladdning av \"%s\" klar, aktuell genomsnittshastighet är %8.3f kbps.\n" #: src/hostlist/hostlist-client.c:850 #, c-format msgid "Adding successfully tested hostlist `%s' datastore.\n" msgstr "" #: src/hostlist/hostlist-client.c:903 #, c-format msgid "Bootstrapping using hostlist at `%s'.\n" msgstr "" #: src/hostlist/hostlist-client.c:911 msgid "# hostlist downloads initiated" msgstr "" #: src/hostlist/hostlist-client.c:1037 src/hostlist/hostlist-client.c:1505 msgid "# milliseconds between hostlist downloads" msgstr "" #: src/hostlist/hostlist-client.c:1046 #, c-format msgid "Have %u/%u connections. Will consider downloading hostlist in %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1084 msgid "Scheduled saving of hostlists\n" msgstr "" #: src/hostlist/hostlist-client.c:1088 #, c-format msgid "Hostlists will be saved to file again in %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1111 src/hostlist/hostlist-client.c:1127 #, fuzzy msgid "# active connections" msgstr "Nätverksanslutning" #: src/hostlist/hostlist-client.c:1242 #, c-format msgid "Initial time between hostlist downloads is %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1273 #, c-format msgid "" "No `%s' specified in `%s' configuration, cannot load hostlists from file.\n" msgstr "" #: src/hostlist/hostlist-client.c:1279 #, fuzzy, c-format msgid "Loading saved hostlist entries from file `%s' \n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/hostlist/hostlist-client.c:1283 #, c-format msgid "Hostlist file `%s' is not existing\n" msgstr "" #: src/hostlist/hostlist-client.c:1294 #, fuzzy, c-format msgid "Could not open file `%s' for reading to load hostlists: %s\n" msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" #: src/hostlist/hostlist-client.c:1327 #, c-format msgid "%u hostlist URIs loaded from file\n" msgstr "" #: src/hostlist/hostlist-client.c:1329 msgid "# hostlist URIs read from file" msgstr "" #: src/hostlist/hostlist-client.c:1362 #, c-format msgid "" "No `%s' specified in `%s' configuration, cannot save hostlists to file.\n" msgstr "" #: src/hostlist/hostlist-client.c:1376 #, fuzzy, c-format msgid "Could not open file `%s' for writing to save hostlists: %s\n" msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" #: src/hostlist/hostlist-client.c:1381 #, fuzzy, c-format msgid "Writing %u hostlist URIs to `%s'\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/hostlist/hostlist-client.c:1405 src/hostlist/hostlist-client.c:1422 #, c-format msgid "Error writing hostlist URIs to file `%s'\n" msgstr "" #: src/hostlist/hostlist-client.c:1417 msgid "# hostlist URIs written to file" msgstr "" #: src/hostlist/hostlist-client.c:1470 msgid "Learning is enabled on this peer\n" msgstr "" #: src/hostlist/hostlist-client.c:1473 #, c-format msgid "Hostlists will be saved to file again in %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1482 msgid "Learning is not enabled on this peer\n" msgstr "" #: src/hostlist/hostlist-client.c:1494 #, c-format msgid "" "Since learning is not enabled on this peer, hostlist file `%s' was removed\n" msgstr "" #: src/hostlist/hostlist-client.c:1498 #, c-format msgid "Hostlist file `%s' could not be removed\n" msgstr "" #: src/hostlist/hostlist-server.c:134 #, fuzzy msgid "bytes in hostlist" msgstr "# byte krypterade" #: src/hostlist/hostlist-server.c:157 msgid "expired addresses encountered" msgstr "" #: src/hostlist/hostlist-server.c:184 src/hostlist/hostlist-server.c:425 #: src/peerinfo-tool/gnunet-peerinfo.c:403 #: src/peerinfo-tool/gnunet-peerinfo.c:519 #: src/topology/gnunet-daemon-topology.c:927 #, fuzzy, c-format msgid "Error in communication with PEERINFO service: %s\n" msgstr "Skriv ut information om GNUnets motparter." #: src/hostlist/hostlist-server.c:205 msgid "HELLOs without addresses encountered (ignored)" msgstr "" #: src/hostlist/hostlist-server.c:219 msgid "bytes not included in hostlist (size limit)" msgstr "" #: src/hostlist/hostlist-server.c:263 #, c-format msgid "Refusing `%s' request to hostlist server\n" msgstr "" #: src/hostlist/hostlist-server.c:266 msgid "hostlist requests refused (not HTTP GET)" msgstr "" #: src/hostlist/hostlist-server.c:273 msgid "Sending 100 CONTINUE reply\n" msgstr "" #: src/hostlist/hostlist-server.c:279 #, c-format msgid "Refusing `%s' request with %llu bytes of upload data\n" msgstr "" #: src/hostlist/hostlist-server.c:283 msgid "hostlist requests refused (upload data)" msgstr "" #: src/hostlist/hostlist-server.c:291 msgid "Could not handle hostlist request since I do not have a response yet\n" msgstr "" #: src/hostlist/hostlist-server.c:294 msgid "hostlist requests refused (not ready)" msgstr "" #: src/hostlist/hostlist-server.c:298 msgid "Received request for our hostlist\n" msgstr "" #: src/hostlist/hostlist-server.c:299 msgid "hostlist requests processed" msgstr "" #: src/hostlist/hostlist-server.c:341 msgid "# hostlist advertisements send" msgstr "" #: src/hostlist/hostlist-server.c:388 msgid "Advertisement message could not be queued by core\n" msgstr "" #: src/hostlist/hostlist-server.c:561 #, fuzzy, c-format msgid "Invalid port number %llu. Exiting.\n" msgstr "Ogiltiga argument. Avslutar.\n" #: src/hostlist/hostlist-server.c:570 #, c-format msgid "Hostlist service starts on %s:%llu\n" msgstr "" #: src/hostlist/hostlist-server.c:584 #, fuzzy, c-format msgid "Address to obtain hostlist: `%s'\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/hostlist/hostlist-server.c:624 #, fuzzy, c-format msgid "`%s' is not a valid IP address! Ignoring BINDTOIP.\n" msgstr "\"%s\" är inte tillgänglig." #: src/hostlist/hostlist-server.c:666 #, c-format msgid "Could not start hostlist HTTP server on port %u\n" msgstr "" #: src/integration-tests/connection_watchdog.c:997 #, fuzzy, c-format msgid "Transport plugin: `%s' port %llu\n" msgstr "Testar transport(er) %s\n" #: src/integration-tests/connection_watchdog.c:1030 #, fuzzy, c-format msgid "Found %u transport plugins: `%s'\n" msgstr "Testar transport(er) %s\n" #: src/integration-tests/connection_watchdog.c:1089 msgid "Send ping messages to test connectivity (default == NO)" msgstr "" #: src/integration-tests/connection_watchdog.c:1095 #: src/template/gnunet-template.c:68 #, fuzzy msgid "help text" msgstr "hjälptext för -t" #: src/mesh/gnunet-service-mesh.c:4590 msgid "Wrong CORE service\n" msgstr "" #: src/mesh/gnunet-service-mesh.c:4784 #, fuzzy msgid "Mesh service is lacking key configuration settings. Exiting.\n" msgstr "GNUnet-konfiguration" #: src/mesh/gnunet-service-mesh.c:4793 #, fuzzy msgid "Mesh service could not access hostkey. Exiting.\n" msgstr "Kunde inte komma Ã¥t namnrymdsinformation.\n" #: src/mysql/mysql.c:174 #, c-format msgid "Trying to use file `%s' for MySQL configuration.\n" msgstr "Försöker använda fil \"%s\" för MySQL-konfiguration.\n" #: src/mysql/mysql.c:181 #, fuzzy, c-format msgid "Could not access file `%s': %s\n" msgstr "Kunde inte köra \"%s\": %s\n" #: src/namestore/gnunet-namestore.c:157 #, fuzzy, c-format msgid "Adding record failed: %s\n" msgstr "" "\n" "Fel vid uppladdning av fil: %s\n" #: src/namestore/gnunet-namestore.c:183 #, fuzzy, c-format msgid "Deleting record failed: %s\n" msgstr "" "\n" "Fel vid uppladdning av fil: %s\n" #: src/namestore/gnunet-namestore.c:239 #, c-format msgid "\tCorrupt or unsupported record of type %u\n" msgstr "" #: src/namestore/gnunet-namestore.c:276 #, c-format msgid "Option `%s' not given, but I need a zone key file!\n" msgstr "" #: src/namestore/gnunet-namestore.c:281 #, fuzzy, c-format msgid "Using default zone file `%s'\n" msgstr "Startade samling \"%s\".\n" #: src/namestore/gnunet-namestore.c:291 #, c-format msgid "No options given\n" msgstr "" #: src/namestore/gnunet-namestore.c:321 #, fuzzy, c-format msgid "Unsupported type `%s'\n" msgstr "Kommando \"%s\" stöds ej. Avbryter.\n" #: src/namestore/gnunet-namestore.c:328 src/namestore/gnunet-namestore.c:350 #: src/namestore/gnunet-namestore.c:374 src/namestore/gnunet-namestore.c:384 #: src/namestore/gnunet-namestore.c:409 #, fuzzy, c-format msgid "Missing option `%s' for operation `%s'\n" msgstr "Konfigurationsfil \"%s\" skapad.\n" #: src/namestore/gnunet-namestore.c:329 src/namestore/gnunet-namestore.c:351 msgid "add/del" msgstr "" #: src/namestore/gnunet-namestore.c:341 #, fuzzy, c-format msgid "Value `%s' invalid for record type `%s'\n" msgstr "%s: symbolvärde \"%s\" ogiltigt för %s\n" #: src/namestore/gnunet-namestore.c:366 #, fuzzy, c-format msgid "Invalid time format `%s'\n" msgstr "Ogiltigt format för IP: \"%s\"\n" #: src/namestore/gnunet-namestore.c:375 src/namestore/gnunet-namestore.c:385 msgid "add" msgstr "" #: src/namestore/gnunet-namestore.c:410 msgid "del" msgstr "" #: src/namestore/gnunet-namestore.c:462 msgid "add record" msgstr "" #: src/namestore/gnunet-namestore.c:465 msgid "delete record" msgstr "" #: src/namestore/gnunet-namestore.c:468 msgid "display records" msgstr "" #: src/namestore/gnunet-namestore.c:471 msgid "" "expiration time for record to use (for adding only), \"never\" is possible" msgstr "" #: src/namestore/gnunet-namestore.c:474 msgid "name of the record to add/delete/display" msgstr "" #: src/namestore/gnunet-namestore.c:477 msgid "type of the record to add/delete/display" msgstr "" #: src/namestore/gnunet-namestore.c:480 msgid "value of the record to add/delete" msgstr "" #: src/namestore/gnunet-namestore.c:483 msgid "create or list public record" msgstr "" #: src/namestore/gnunet-namestore.c:486 msgid "create or list non-authority record" msgstr "" #: src/namestore/gnunet-namestore.c:489 msgid "filename with the zone key" msgstr "" #: src/namestore/gnunet-namestore.c:500 #, fuzzy msgid "GNUnet zone manipulation tool" msgstr "GNUnet-konfiguration" #: src/namestore/gnunet-service-namestore.c:143 #, c-format msgid "File zone `%s' but corrupt content already exists, failed to write! \n" msgstr "" #: src/namestore/gnunet-service-namestore.c:154 #, c-format msgid "File zone `%s' containing this key already exists\n" msgstr "" #: src/namestore/gnunet-service-namestore.c:160 #, c-format msgid "" "File zone `%s' but different zone key already exists, failed to write! \n" msgstr "" #: src/namestore/gnunet-service-namestore.c:198 #, fuzzy, c-format msgid "Stored zonekey for zone `%s' in file `%s'\n" msgstr "Misslyckades att leverera \"%s\" meddelande.\n" #: src/namestore/gnunet-service-namestore.c:1909 #, fuzzy msgid "No directory to load zonefiles specified in configuration\n" msgstr "Inga applikationer definierade i konfiguration!\n" #: src/namestore/gnunet-service-namestore.c:1918 #, c-format msgid "Creating directory `%s' for zone files failed!\n" msgstr "" #: src/namestore/namestore_api.c:315 src/namestore/namestore_api.c:353 msgid "Namestore added record successfully" msgstr "" #: src/namestore/namestore_api.c:323 msgid "Namestore failed to add record" msgstr "" #: src/namestore/namestore_api.c:361 msgid "Namestore record already existed" msgstr "" #: src/namestore/namestore_api.c:368 msgid "Namestore failed to add record\n" msgstr "" #: src/namestore/namestore_api.c:401 msgid "Namestore removed record successfully" msgstr "" #: src/namestore/namestore_api.c:408 msgid "No records for entry" msgstr "" #: src/namestore/namestore_api.c:415 #, fuzzy msgid "Could not find record to remove" msgstr "Kunde inte ansluta till gnunetd.\n" #: src/namestore/namestore_api.c:422 #, fuzzy msgid "Failed to create new signature" msgstr "Kunde inte skapa namnrymd \"%s\" (existerar?).\n" #: src/namestore/namestore_api.c:429 #, fuzzy msgid "Failed to put new set of records in database" msgstr "Misslyckades att skicka HTTP-begäran till värd \"%s\": %s\n" #: src/nat/gnunet-nat-server.c:279 #, c-format msgid "Please pass valid port number as the first argument! (got `%s')\n" msgstr "" #: src/nat/gnunet-nat-server.c:318 msgid "GNUnet NAT traversal test helper daemon" msgstr "" #: src/nat/nat.c:799 #, c-format msgid "gnunet-helper-nat-server generated malformed address `%s'\n" msgstr "" #: src/nat/nat.c:844 #, fuzzy, c-format msgid "Failed to start %s\n" msgstr "Misslyckades att starta samling.\n" #: src/nat/nat.c:1111 #, fuzzy, c-format msgid "Malformed %s `%s' given in configuration!\n" msgstr "Kunde inte spara konfiguration!" #: src/nat/nat.c:1177 src/nat/nat.c:1187 #, c-format msgid "" "Configuration requires `%s', but binary is not installed properly (SUID bit " "not set). Option disabled.\n" msgstr "" #: src/nat/nat.c:1321 msgid "Internal IP address not known, cannot use ICMP NAT traversal method\n" msgstr "" #: src/nat/nat.c:1332 #, c-format msgid "Running gnunet-helper-nat-client %s %s %u\n" msgstr "" #: src/nat/nat_test.c:341 #, fuzzy msgid "Failed to connect to `gnunet-nat-server'\n" msgstr "Misslyckades att ansluta till gnunetd.\n" #: src/nat/nat_test.c:411 #, c-format msgid "Failed to create listen socket bound to `%s' for NAT test: %s\n" msgstr "" #: src/nse/gnunet-nse-profiler.c:928 #, fuzzy msgid "Measure quality and performance of the NSE service." msgstr "Kan inte tillgÃ¥ tjänsten" #: src/nse/gnunet-service-nse.c:925 #, c-format msgid "Proof of work invalid: %llu!\n" msgstr "" #: src/nse/gnunet-service-nse.c:1381 src/nse/gnunet-service-nse.c:1400 #: src/nse/gnunet-service-nse.c:1421 msgid "NSE service is lacking key configuration settings. Exiting.\n" msgstr "" #: src/nse/gnunet-service-nse.c:1388 #, fuzzy msgid "Invalid work requirement for NSE service. Exiting.\n" msgstr "Ogiltiga argument. Avslutar.\n" #: src/nse/gnunet-service-nse.c:1409 #, fuzzy msgid "NSE service could not access hostkey. Exiting.\n" msgstr "Kunde inte komma Ã¥t namnrymdsinformation.\n" #: src/peerinfo/gnunet-service-peerinfo.c:134 #, fuzzy, c-format msgid "Removing expired address of transport `%s'\n" msgstr "Tillgängliga transport(er): %s\n" #: src/peerinfo/gnunet-service-peerinfo.c:203 #, fuzzy, c-format msgid "Failed to parse HELLO in file `%s'\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/peerinfo/gnunet-service-peerinfo.c:229 msgid "# peers known" msgstr "" #: src/peerinfo/gnunet-service-peerinfo.c:254 #, c-format msgid "" "File `%s' in directory `%s' does not match naming convention. Removed.\n" msgstr "" #: src/peerinfo/gnunet-service-peerinfo.c:353 #, c-format msgid "Still no peers found in `%s'!\n" msgstr "" #: src/peerinfo/gnunet-service-peerinfo.c:710 #, c-format msgid "Importing HELLOs from `%s'\n" msgstr "" #: src/peerinfo/peerinfo_api.c:238 msgid "aborted due to explicit disconnect request" msgstr "" #: src/peerinfo/peerinfo_api.c:358 #, fuzzy msgid "failed to transmit request (service down?)" msgstr "Misslyckades att skicka HTTP-begäran till värd \"%s\": %s\n" #: src/peerinfo/peerinfo_api.c:505 #, fuzzy msgid "Failed to receive response from `PEERINFO' service." msgstr "Misslyckades att ta emot svar till \"%s\" meddelande frÃ¥n gnunetd\n" #: src/peerinfo/peerinfo_api.c:531 src/peerinfo/peerinfo_api.c:550 #: src/peerinfo/peerinfo_api.c:565 src/peerinfo/peerinfo_api.c:576 #: src/peerinfo/peerinfo_api.c:587 #, fuzzy msgid "Received invalid message from `PEERINFO' service." msgstr "mottog ogiltigt \"%s\" meddelande: %s.\n" #: src/peerinfo/peerinfo_api.c:663 #, fuzzy msgid "Timeout transmitting iteration request to `PEERINFO' service." msgstr "Misslyckades att initiera tjänsten \"%s\".\n" #: src/peerinfo/peerinfo_api_notify.c:256 #, fuzzy, c-format msgid "Could not connect to `%s' service.\n" msgstr "Kunde inte ansluta till gnunetd.\n" #: src/peerinfo-tool/gnunet-peerinfo.c:581 #, fuzzy msgid "Failed to parse HELLO message: missing expiration time\n" msgstr "Kunde inte spara konfiguration!" #: src/peerinfo-tool/gnunet-peerinfo.c:589 #, fuzzy msgid "Failed to parse HELLO message: invalid expiration time\n" msgstr "Kunde inte spara konfiguration!" #: src/peerinfo-tool/gnunet-peerinfo.c:598 #, fuzzy msgid "Failed to parse HELLO message: malformed\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/peerinfo-tool/gnunet-peerinfo.c:608 #, fuzzy msgid "Failed to parse HELLO message: missing transport plugin\n" msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" #: src/peerinfo-tool/gnunet-peerinfo.c:625 #, c-format msgid "Plugin `%s' not found\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:634 #, c-format msgid "Plugin `%s' does not support URIs yet\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:653 #, fuzzy, c-format msgid "Failed to parse `%s' as an address for plugin `%s'\n" msgstr "Misslyckades att binda till UDP-port %d.\n" #: src/peerinfo-tool/gnunet-peerinfo.c:685 #, c-format msgid "Failure adding HELLO: %s\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:833 #, fuzzy, c-format msgid "Could not find option `%s:%s' in configuration.\n" msgstr "Kunde inte hitta motpart \"%s\" i routingtabell!\n" #: src/peerinfo-tool/gnunet-peerinfo.c:840 #, fuzzy, c-format msgid "Loading hostkey from `%s' failed.\n" msgstr "Tolkning av HTTP-svar för URL \"%s\" misslyckades.\n" #: src/peerinfo-tool/gnunet-peerinfo.c:875 #, fuzzy, c-format msgid "Invalid URI `%s'\n" msgstr "Ogiltiga argument: " #: src/peerinfo-tool/gnunet-peerinfo.c:899 #, c-format msgid "I am peer `%s'.\n" msgstr "Jag är ändpunkt \"%s\".\n" #: src/peerinfo-tool/gnunet-peerinfo.c:936 msgid "don't resolve host names" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:939 msgid "output only the identity strings" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:942 msgid "output our own identity only" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:945 msgid "list all known peers" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:948 msgid "also output HELLO uri(s)" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:951 msgid "add given HELLO uri to the database" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:957 #, fuzzy msgid "Print information about peers." msgstr "Skriv ut information om GNUnets motparter." #: src/peerinfo-tool/gnunet-peerinfo_plugins.c:105 #: src/transport/gnunet-service-transport_plugins.c:118 #, fuzzy, c-format msgid "Starting transport plugins `%s'\n" msgstr "Testar transport(er) %s\n" #: src/peerinfo-tool/gnunet-peerinfo_plugins.c:109 #: src/transport/gnunet-service-transport_plugins.c:122 #, fuzzy, c-format msgid "Loading `%s' transport plugin\n" msgstr "Testar transport(er) %s\n" #: src/peerinfo-tool/gnunet-peerinfo_plugins.c:129 #: src/transport/gnunet-service-transport_plugins.c:150 #, fuzzy, c-format msgid "Failed to load transport plugin for `%s'\n" msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" #: src/postgres/postgres.c:59 #, fuzzy, c-format msgid "`%s:%s' failed at %s:%d with error: %s" msgstr "\"%s\" misslyckades vid %s:%d med fel: %s\n" #: src/postgres/postgres.c:148 #, fuzzy, c-format msgid "Unable to initialize Postgres: %s" msgstr "Kunde inte initiera SQLite.\n" #: src/pt/gnunet-daemon-pt.c:264 #, fuzzy msgid "Failed to pack DNS request. Dropping.\n" msgstr "Misslyckades att skicka HTTP-begäran till värd \"%s\": %s\n" #: src/pt/gnunet-daemon-pt.c:270 #, fuzzy msgid "# DNS requests mapped to VPN" msgstr "# byte mottogs via TCP" #: src/pt/gnunet-daemon-pt.c:323 msgid "# DNS records modified" msgstr "" #: src/pt/gnunet-daemon-pt.c:500 msgid "# DNS replies intercepted" msgstr "" #: src/pt/gnunet-daemon-pt.c:506 #, fuzzy msgid "Failed to parse DNS request. Dropping.\n" msgstr "Misslyckades att skicka HTTP-begäran till värd \"%s\": %s\n" #: src/pt/gnunet-daemon-pt.c:602 #, fuzzy msgid "# DNS requests dropped (timeout)" msgstr "Nätverksannonsering avstängd i konfigurationen!\n" #: src/pt/gnunet-daemon-pt.c:632 #, fuzzy msgid "# DNS requests intercepted" msgstr "# byte mottogs via TCP" #: src/pt/gnunet-daemon-pt.c:637 msgid "# DNS requests dropped (DNS mesh tunnel down)" msgstr "" #: src/pt/gnunet-daemon-pt.c:645 #, fuzzy msgid "# DNS requests dropped (malformed)" msgstr "# byte mottogs via TCP" #: src/pt/gnunet-daemon-pt.c:716 #, fuzzy msgid "# DNS replies received" msgstr "# byte mottogs via TCP" #: src/pt/gnunet-daemon-pt.c:730 #, fuzzy msgid "# DNS replies dropped (too late?)" msgstr "# byte mottagna av typen %d" #: src/pt/gnunet-daemon-pt.c:748 src/pt/gnunet-daemon-pt.c:760 msgid "# DNS requests aborted (tunnel down)" msgstr "" #: src/pt/gnunet-daemon-pt.c:898 src/pt/gnunet-daemon-pt.c:907 #: src/pt/gnunet-daemon-pt.c:930 src/pt/gnunet-daemon-pt.c:940 #, fuzzy, c-format msgid "Failed to connect to %s service. Exiting.\n" msgstr "Misslyckades att initiera tjänsten \"%s\".\n" #: src/pt/gnunet-daemon-pt.c:973 msgid "Daemon to run to perform IP protocol translation to GNUnet" msgstr "" #: src/statistics/gnunet-service-statistics.c:271 #, fuzzy, c-format msgid "Loading %llu bytes of statistics from `%s'\n" msgstr "Ladda ner filer frÃ¥n GNUnet." #: src/statistics/gnunet-service-statistics.c:330 #, fuzzy, c-format msgid "Wrote %llu bytes of statistics to `%s'\n" msgstr "Ladda ner filer frÃ¥n GNUnet." #: src/statistics/gnunet-statistics.c:122 #, fuzzy msgid "Failed to obtain statistics.\n" msgstr "Misslyckades att binda till UDP-port %d.\n" #: src/statistics/gnunet-statistics.c:199 #, c-format msgid "No subsystem or name given\n" msgstr "" #: src/statistics/gnunet-statistics.c:207 #, fuzzy, c-format msgid "Failed to initialize watch routine\n" msgstr "Misslyckades att initiera tjänsten \"%s\".\n" #: src/statistics/gnunet-statistics.c:227 msgid "limit output to statistics for the given NAME" msgstr "" #: src/statistics/gnunet-statistics.c:230 msgid "make the value being set persistent" msgstr "" #: src/statistics/gnunet-statistics.c:233 msgid "limit output to the given SUBSYSTEM" msgstr "" #: src/statistics/gnunet-statistics.c:236 msgid "just print the statistics value" msgstr "" #: src/statistics/gnunet-statistics.c:239 msgid "watch value continously" msgstr "" #: src/statistics/gnunet-statistics.c:246 msgid "Print statistics about GNUnet operations." msgstr "Skriv ut statistik om GNUnet-operationer." #: src/statistics/statistics_api.c:456 #, fuzzy msgid "Could not save some persistent statistics\n" msgstr "Kunde inte skapa värdnyckel!\n" #: src/statistics/statistics_api.c:999 msgid "" "Failed to receive acknowledgement from statistics service, some statistics " "might have been lost!\n" msgstr "" #: src/testing/gnunet-testing.c:157 #, fuzzy msgid "Could not read hostkeys file, specify hostkey file with -H!\n" msgstr "Kunde inte skapa värdnyckel!\n" #: src/testing/gnunet-testing.c:159 #, c-format msgid "Specified hostkey file `%s' not found!\n" msgstr "" #: src/testing/gnunet-testing.c:273 #, fuzzy msgid "create unique configuration files" msgstr "skriv ut ett värde frÃ¥n konfigurationsfilen till standard ut" #: src/testing/gnunet-testing.c:275 msgid "create hostkey files from pre-computed hostkey list" msgstr "" #: src/testing/gnunet-testing.c:277 msgid "host key file" msgstr "" #: src/testing/gnunet-testing.c:279 #, fuzzy msgid "number of unique configuration files or hostkeys to create" msgstr "skriv ut ett värde frÃ¥n konfigurationsfilen till standard ut" #: src/testing/gnunet-testing.c:281 #, fuzzy msgid "configuration template" msgstr "Konfigurationsfil \"%s\" skapad.\n" #: src/testing/gnunet-testing.c:287 msgid "Command line tool to access the testing library" msgstr "" #: src/testing/helper.c:56 #, fuzzy msgid "Peer is lacking HOSTKEY configuration setting.\n" msgstr "GNUnet-konfiguration" #: src/testing/helper.c:64 #, fuzzy msgid "Could not access hostkey.\n" msgstr "Kunde inte tolka konfigurationsfil \"%s\".\n" #: src/testing/testing.c:200 msgid "`scp' does not seem to terminate (timeout copying config).\n" msgstr "" #: src/testing/testing.c:214 src/testing/testing.c:798 #, fuzzy msgid "`scp' did not complete cleanly.\n" msgstr "\"%s\" är inte ansluten till nÃ¥gon ändpunkt.\n" #: src/testing/testing.c:237 #, fuzzy msgid "Failed to create pipe for `gnunet-peerinfo' process.\n" msgstr "Misslyckades att starta samling.\n" #: src/testing/testing.c:238 #, fuzzy msgid "Failed to create pipe for `ssh' process.\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/testing/testing.c:286 #, fuzzy, c-format msgid "Could not start `%s' process to create hostkey.\n" msgstr "Kunde inte skapa värdnyckel!\n" #: src/testing/testing.c:293 #, fuzzy msgid "Failed to start `gnunet-peerinfo' process.\n" msgstr "Misslyckades att starta samling.\n" #: src/testing/testing.c:294 src/testing/testing.c:471 #, fuzzy msgid "Failed to start `ssh' process.\n" msgstr "Misslyckades att starta samling.\n" #: src/testing/testing.c:354 #, c-format msgid "Error reading from gnunet-peerinfo: %s\n" msgstr "" #: src/testing/testing.c:358 #, fuzzy msgid "Malformed output from gnunet-peerinfo!\n" msgstr "Misslyckades att starta samling.\n" #: src/testing/testing.c:368 #, fuzzy msgid "Failed to get hostkey!\n" msgstr "Kunde inte skapa värdnyckel!\n" #: src/testing/testing.c:400 msgid "`Failed while waiting for topology setup!\n" msgstr "" #: src/testing/testing.c:463 #, fuzzy, c-format msgid "Could not start `%s' process to start GNUnet.\n" msgstr "Kunde inte skapa värdnyckel!\n" #: src/testing/testing.c:470 #, fuzzy msgid "Failed to start `gnunet-arm' process.\n" msgstr "Misslyckades att ansluta till gnunetd.\n" #: src/testing/testing.c:493 src/testing/testing.c:600 msgid "`gnunet-arm' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:494 src/testing/testing.c:601 #: src/testing/testing.c:621 msgid "`ssh' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:570 msgid "Unable to get HELLO for peer!\n" msgstr "" #: src/testing/testing.c:620 msgid "`gnunet-arm' terminated with non-zero exit status (or timed out)!\n" msgstr "" #: src/testing/testing.c:643 src/testing/testing.c:675 msgid "either `gnunet-arm' or `ssh' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:658 src/testing/testing.c:713 #, fuzzy msgid "shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n" msgstr "\"%s\" är inte ansluten till nÃ¥gon ändpunkt.\n" #: src/testing/testing.c:786 msgid "`scp' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:948 #, fuzzy, c-format msgid "Starting service %s for peer `%4s'\n" msgstr "Startade samling \"%s\".\n" #: src/testing/testing.c:1207 src/testing/testing_group.c:6154 #, fuzzy, c-format msgid "Could not start `%s' process to copy configuration directory.\n" msgstr "Kunde inte skapa värdnyckel!\n" #: src/testing/testing.c:1292 src/testing/testing.c:1359 #, fuzzy, c-format msgid "Terminating peer `%4s'\n" msgstr "Ã…tkomst nekad för \"%s\" vid %s:%d.\n" #: src/testing/testing.c:1448 #, fuzzy, c-format msgid "Setting d->dead on peer `%4s'\n" msgstr "Startade samling \"%s\".\n" #: src/testing/testing.c:1601 msgid "Peer not yet running, can not change configuration at this point." msgstr "" #: src/testing/testing.c:1609 #, fuzzy msgid "Failed to write new configuration to disk." msgstr "Kunde inte spara konfiguration!" #: src/testing/testing.c:1636 #, fuzzy, c-format msgid "Could not start `%s' process to copy configuration file.\n" msgstr "Kunde inte skapa värdnyckel!\n" #: src/testing/testing.c:1639 #, fuzzy msgid "Failed to copy new configuration to remote machine." msgstr "Kunde inte spara konfiguration!" #: src/testing/testing.c:1794 #, fuzzy msgid "Peers failed to connect" msgstr "Misslyckades att ansluta till gnunetd.\n" #: src/testing/testing.c:1922 #, fuzzy msgid "Failed to connect to core service of first peer!\n" msgstr "Misslyckades att starta samling.\n" #: src/testing/testing.c:2145 msgid "Peers are not fully running yet, can not connect!\n" msgstr "" #: src/testing/testing_group.c:1895 src/testing/testing_group.c:1907 #: src/testing/testing_group.c:2008 src/testing/testing_group.c:2065 #: src/testing/testing_group.c:2152 src/testing/testing_group.c:2172 #: src/testing/testing_group.c:2302 src/testing/testing_peergroup.c:950 #, fuzzy, c-format msgid "Invalid value `%s' for option `%s' in section `%s': expected float\n" msgstr "Konfigurationsfil \"%s\" hittades inte. Kör \"gnunet-setup -d\"!\n" #: src/testing/testing_group.c:2160 #, c-format msgid "" "Invalid value `%s' for option `%s' in section `%s': got %f, needed value " "greater than 0\n" msgstr "" #: src/testing/testing_group.c:2877 src/testing/testing_group.c:3063 #, c-format msgid "" "No `%s' specified in peer configuration in section `%s', cannot copy friends " "file!\n" msgstr "" #: src/testing/testing_group.c:3957 msgid "Creating no allowed topology (all peers can connect at core level)\n" msgstr "" #: src/testing/testing_group.c:5226 msgid "Unknown topology specification, can't connect peers!\n" msgstr "" #: src/testing/testing_group.c:5944 src/transport/transport-testing.c:636 #, fuzzy msgid "Could not read hostkeys file!\n" msgstr "Kunde inte skapa värdnyckel!\n" #: src/testing/testing_group.c:6011 #, fuzzy, c-format msgid "Could not create configuration for peer number %u on `%s'!\n" msgstr "Kunde inte komma Ã¥t namnrymdsinformation.\n" #: src/testing/testing_new.c:169 msgid "tmppath cannot be NULL\n" msgstr "" #: src/testing/testing_new.c:356 #, c-format msgid "Hostkeys file not found: %s\n" msgstr "" #: src/testing/testing_new.c:365 #, fuzzy, c-format msgid "Could not open hostkeys file: %s\n" msgstr "Kunde inte skapa värdnyckel!\n" #: src/testing/testing_new.c:380 #, c-format msgid "Incorrect hostkey file format: %s\n" msgstr "" #: src/testing/testing_new.c:437 #, fuzzy, c-format msgid "Key number %u does not exist\n" msgstr "antal meddelanden att använda per iteration" #: src/testing/testing_new.c:446 #, fuzzy, c-format msgid "Error while decoding key %u\n" msgstr "Fel vid nedladdning: %s\n" #: src/testing/testing_new.c:680 #, fuzzy msgid "Failed to create configuration for peer (not enough free ports?)\n" msgstr "Kunde inte komma Ã¥t namnrymdsinformation.\n" #: src/testing/testing_new.c:691 #, c-format msgid "" "You attempted to create a testbed with more than %u hosts. Please " "precompute more hostkeys first.\n" msgstr "" #: src/testing/testing_new.c:704 #, fuzzy, c-format msgid "Failed to initialize hostkey for peer %u\n" msgstr "Misslyckades att initiera tjänsten \"%s\".\n" #: src/testing/testing_new.c:734 #, fuzzy, c-format msgid "Failed to write hostkey file for peer %u: %s\n" msgstr "Kunde inte skapa användarkonto:" #: src/testing/testing_new.c:751 #, fuzzy, c-format msgid "Failed to write configuration file `%s' for peer %u: %s\n" msgstr "Kunde inte spara konfigurationsfil \"%s\":" #: src/testing/testing_new.c:791 #, fuzzy, c-format msgid "Failed to start `%s': %s\n" msgstr "Fel vid %s:%d.\n" #: src/testing/testing_new.c:959 #, fuzzy, c-format msgid "Failed to load configuration from %s\n" msgstr "Kunde inte spara konfigurationsfil \"%s\":" #: src/topology/gnunet-daemon-topology.c:259 msgid "# peers blacklisted" msgstr "" #: src/topology/gnunet-daemon-topology.c:392 #, fuzzy msgid "# connect requests issued to transport" msgstr "# byte mottogs via TCP" #: src/topology/gnunet-daemon-topology.c:730 #: src/topology/gnunet-daemon-topology.c:815 #, fuzzy msgid "# friends connected" msgstr "# av anslutna parter" #: src/topology/gnunet-daemon-topology.c:996 msgid "Failed to connect to core service, can not manage topology!\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1026 #, c-format msgid "Option `%s' in section `%s' not specified!\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1039 #, fuzzy, c-format msgid "Could not read friends list `%s'\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/topology/gnunet-daemon-topology.c:1045 #, c-format msgid "Friends file `%s' is empty.\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1054 #, fuzzy, c-format msgid "Failed to read friends list from `%s': out of memory\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/topology/gnunet-daemon-topology.c:1062 #, c-format msgid "Failed to read friends list from `%s'\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/topology/gnunet-daemon-topology.c:1082 #, c-format msgid "" "Syntax error in topology specification at offset %llu, skipping bytes.\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1095 #, c-format msgid "" "Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1105 #, fuzzy, c-format msgid "Found friend `%s' in configuration\n" msgstr " gconfig\tGTK-konfiguration\n" #: src/topology/gnunet-daemon-topology.c:1111 #, c-format msgid "Found myself `%s' in friend list (useless, ignored)\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1121 #, fuzzy msgid "# friends in configuration" msgstr " gconfig\tGTK-konfiguration\n" #: src/topology/gnunet-daemon-topology.c:1127 msgid "" "Fewer friends specified than required by minimum friend count. Will only " "connect to friends.\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1134 msgid "" "More friendly connections required than target total number of connections.\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1169 #, fuzzy msgid "# HELLO messages received" msgstr "# krypterade PONG-meddelanden mottagna" #: src/topology/gnunet-daemon-topology.c:1224 msgid "# HELLO messages gossipped" msgstr "" #: src/topology/gnunet-daemon-topology.c:1363 msgid "GNUnet topology control (maintaining P2P mesh and F2F constraints)" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:246 #, fuzzy, c-format msgid "Could not read blacklist file `%s'\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/transport/gnunet-service-transport_blacklist.c:252 #, c-format msgid "Blacklist file `%s' is empty.\n" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:263 #, fuzzy, c-format msgid "Failed to read blacklist from `%s'\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/transport/gnunet-service-transport_blacklist.c:284 #: src/transport/gnunet-service-transport_blacklist.c:308 #, fuzzy, c-format msgid "Syntax error in blacklist file at offset %llu, giving up!\n" msgstr "Syntaxfel i konfigurationsfil \"%s\" pÃ¥ rad %d.\n" #: src/transport/gnunet-service-transport_blacklist.c:295 #: src/transport/gnunet-service-transport_blacklist.c:331 #, c-format msgid "Syntax error in blacklist file at offset %llu, skipping bytes.\n" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:345 #, fuzzy, c-format msgid "Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n" msgstr "Syntaxfel i konfigurationsfil \"%s\" pÃ¥ rad %d.\n" #: src/transport/gnunet-service-transport_blacklist.c:359 #, c-format msgid "Found myself `%s' in blacklist (useless, ignored)\n" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:514 #: src/transport/gnunet-service-transport_blacklist.c:747 msgid "# disconnects due to blacklist" msgstr "" #: src/transport/gnunet-service-transport.c:163 #, fuzzy msgid "# bytes payload discarded due to not connected peer " msgstr "Nätverksannonsering avstängd i konfigurationen!\n" #: src/transport/gnunet-service-transport.c:237 #, fuzzy msgid "# bytes total received" msgstr "# byte krypterade" #: src/transport/gnunet-service-transport.c:284 #, fuzzy msgid "# bytes payload received" msgstr "# byte dekrypterade" #: src/transport/gnunet-service-transport.c:582 msgid "Transport service is lacking key configuration settings. Exiting.\n" msgstr "" #: src/transport/gnunet-service-transport.c:591 msgid "Transport service could not access hostkey. Exiting.\n" msgstr "" #: src/transport/gnunet-service-transport_clients.c:352 #, c-format msgid "Dropping message of type %u and size %u, have %u/%u messages pending\n" msgstr "" #: src/transport/gnunet-service-transport_clients.c:357 msgid "# messages dropped due to slow client" msgstr "" #: src/transport/gnunet-service-transport_clients.c:503 #, c-format msgid "Rejecting control connection from peer `%s', which is not me!\n" msgstr "" #: src/transport/gnunet-service-transport_clients.c:631 msgid "# bytes payload dropped (other peer was not connected)" msgstr "" #: src/transport/gnunet-service-transport_clients.c:682 #, fuzzy msgid "# REQUEST CONNECT messages received" msgstr "# krypterade PONG-meddelanden mottagna" #: src/transport/gnunet-service-transport_hello.c:172 msgid "# refreshed my HELLO" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1032 #, fuzzy msgid "# DISCONNECT messages sent" msgstr "# krypterade PONG-meddelanden mottagna" #: src/transport/gnunet-service-transport_neighbours.c:1148 #: src/transport/gnunet-service-transport_neighbours.c:1482 msgid "# bytes in message queue for other peers" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1153 #, fuzzy msgid "# messages transmitted to other peers" msgstr "# byte skickade av typen %d" #: src/transport/gnunet-service-transport_neighbours.c:1158 #, fuzzy msgid "# transmission failures for messages to other peers" msgstr "# byte skickade av typen %d" #: src/transport/gnunet-service-transport_neighbours.c:1215 msgid "# messages timed out while in transport queue" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1254 #, fuzzy msgid "# keepalives sent" msgstr "# sessionsnycklar skickade" #: src/transport/gnunet-service-transport_neighbours.c:1278 #, fuzzy msgid "# KEEPALIVE messages discarded (peer unknown)" msgstr "Nätverksannonsering avstängd i konfigurationen!\n" #: src/transport/gnunet-service-transport_neighbours.c:1286 #, fuzzy msgid "# KEEPALIVE messages discarded (no session)" msgstr "Nätverksannonsering avstängd i konfigurationen!\n" #: src/transport/gnunet-service-transport_neighbours.c:1323 #, fuzzy msgid "# KEEPALIVE_RESPONSE messages discarded (not connected)" msgstr "Nätverksannonsering avstängd i konfigurationen!\n" #: src/transport/gnunet-service-transport_neighbours.c:1332 #, fuzzy msgid "# KEEPALIVE_RESPONSE messages discarded (not expected)" msgstr "Nätverksannonsering avstängd i konfigurationen!\n" #: src/transport/gnunet-service-transport_neighbours.c:1388 #, fuzzy msgid "# messages discarded due to lack of neighbour record" msgstr "Nätverksannonsering avstängd i konfigurationen!\n" #: src/transport/gnunet-service-transport_neighbours.c:1422 msgid "# bandwidth quota violations by other peers" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1438 msgid "# ms throttling suggested" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2544 #, fuzzy msgid "# unexpected CONNECT_ACK messages (no peer)" msgstr "skicka ANTAL meddelanden" #: src/transport/gnunet-service-transport_neighbours.c:2559 #: src/transport/gnunet-service-transport_neighbours.c:2585 #, fuzzy msgid "# unexpected CONNECT_ACK messages (not ready)" msgstr "skicka ANTAL meddelanden" #: src/transport/gnunet-service-transport_neighbours.c:2598 #, fuzzy msgid "# unexpected CONNECT_ACK messages (waiting on ATS)" msgstr "skicka ANTAL meddelanden" #: src/transport/gnunet-service-transport_neighbours.c:2627 #, fuzzy msgid "# unexpected CONNECT_ACK messages (disconnecting)" msgstr "skicka ANTAL meddelanden" #: src/transport/gnunet-service-transport_neighbours.c:2807 #, fuzzy msgid "# unexpected SESSION ACK messages" msgstr "# krypterade PONG-meddelanden skickade" #: src/transport/gnunet-service-transport_neighbours.c:2856 msgid "# SET QUOTA messages ignored (no such peer)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2870 msgid "# disconnects due to quota of 0" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2901 msgid "# disconnect messages ignored (old format)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2912 msgid "# disconnect messages ignored (timestamp)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2943 msgid "# other peer asked to disconnect from us" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:3020 #, fuzzy msgid "# disconnected from peer upon explicit request" msgstr "# av anslutna parter" #: src/transport/gnunet-service-transport_plugins.c:111 msgid "Transport service is lacking NEIGHBOUR_LIMIT option.\n" msgstr "" #: src/transport/gnunet-service-transport_validation.c:414 msgid "# address records discarded" msgstr "" #: src/transport/gnunet-service-transport_validation.c:463 #, c-format msgid "" "Not transmitting `%s' with `%s', message too big (%u bytes!). This should " "not happen.\n" msgstr "" #: src/transport/gnunet-service-transport_validation.c:512 #, fuzzy msgid "# PING without HELLO messages sent" msgstr "# PING-meddelanden i klartext skickade" #: src/transport/gnunet-service-transport_validation.c:570 msgid "# address revalidations started" msgstr "" #: src/transport/gnunet-service-transport_validation.c:805 #, fuzzy msgid "# PING message for different peer received" msgstr "# PING-meddelanden skapade" #: src/transport/gnunet-service-transport_validation.c:840 #, c-format msgid "" "Not confirming PING with address `%s' since I cannot confirm having this " "address.\n" msgstr "" #: src/transport/gnunet-service-transport_validation.c:924 msgid "# PONGs unicast via reliable transport" msgstr "" #: src/transport/gnunet-service-transport_validation.c:933 msgid "# PONGs multicast to all available addresses" msgstr "" #: src/transport/gnunet-service-transport_validation.c:1055 msgid "# PONGs dropped, no matching pending validation" msgstr "" #: src/transport/gnunet-service-transport_validation.c:1080 msgid "# PONGs dropped, signature expired" msgstr "" #: src/transport/gnunet-service-transport_validation.c:1136 #, fuzzy, c-format msgid "Adding `%s' without addresses for peer `%s'\n" msgstr "Motpart \"%s\" med pÃ¥litlighet %8u och adress \"%s\"\n" #: src/transport/gnunet-transport.c:260 msgid "No transport plugins configured, peer will never communicate\n" msgstr "" #: src/transport/gnunet-transport.c:273 #, c-format msgid "No port configured for plugin `%s', cannot test it\n" msgstr "" #: src/transport/gnunet-transport.c:323 #, c-format msgid "Received %llu bytes/s (%llu bytes in %llu ms)\n" msgstr "" #: src/transport/gnunet-transport.c:330 #, c-format msgid "Transmitted %llu bytes/s (%llu bytes in %llu ms)\n" msgstr "" #: src/transport/gnunet-transport.c:363 #, fuzzy, c-format msgid "Transmitting %u bytes to %s\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/transport/gnunet-transport.c:383 #, fuzzy, c-format msgid "Connected to %s\n" msgstr "\"%s\" ansluten till \"%s\".\n" #: src/transport/gnunet-transport.c:414 #, fuzzy, c-format msgid "Disconnected from %s\n" msgstr "\"%s\" ansluten till \"%s\".\n" #: src/transport/gnunet-transport.c:443 #, c-format msgid "Received %u bytes from %s\n" msgstr "" #: src/transport/gnunet-transport.c:466 #, fuzzy, c-format msgid "Peer `%s': %s %s\n" msgstr "Jag är ändpunkt \"%s\".\n" #: src/transport/gnunet-transport.c:473 #, c-format msgid "Peer `%s': %s \n" msgstr "" #: src/transport/gnunet-transport.c:501 #, fuzzy, c-format msgid "Peer `%s' disconnected\n" msgstr "# av anslutna parter" #: src/transport/gnunet-transport.c:569 #, fuzzy, c-format msgid "Failed to parse peer identity `%s'\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/transport/gnunet-transport.c:618 msgid "measure how fast we are receiving data (until CTRL-C)" msgstr "" #: src/transport/gnunet-transport.c:621 #, fuzzy msgid "try to connect to the given peer" msgstr "Misslyckades att ansluta till gnunetd.\n" #: src/transport/gnunet-transport.c:624 #, fuzzy msgid "provide information about all current connections (once)" msgstr "Skriv ut information om GNUnets motparter." #: src/transport/gnunet-transport.c:627 #, fuzzy msgid "provide information about all current connections (continuously)" msgstr "Skriv ut information om GNUnets motparter." #: src/transport/gnunet-transport.c:630 #, fuzzy msgid "do not resolve hostnames" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/transport/gnunet-transport.c:634 msgid "send data for benchmarking to the other peer (until CTRL-C)" msgstr "" #: src/transport/gnunet-transport.c:637 msgid "test transport configuration (involves external server)" msgstr "" #: src/transport/gnunet-transport.c:645 #, fuzzy msgid "Direct access to transport service." msgstr "Misslyckades att ansluta till gnunetd.\n" #: src/transport/plugin_transport_http.c:1100 msgid "Disabling IPv6 since it is not supported on this system!\n" msgstr "" #: src/transport/plugin_transport_http.c:1149 #, fuzzy msgid "Require valid port number for service in configuration!\n" msgstr "Inga applikationer definierade i konfiguration!\n" #: src/transport/plugin_transport_http.c:1174 src/util/service.c:1036 #, fuzzy, c-format msgid "Failed to resolve `%s': %s\n" msgstr "Misslyckades att leverera \"%s\" meddelande.\n" #: src/transport/plugin_transport_http.c:1191 src/util/service.c:1053 #, fuzzy, c-format msgid "Failed to find %saddress for `%s'.\n" msgstr "Misslyckades att binda till UDP-port %d.\n" #: src/transport/plugin_transport_http.c:1296 #, c-format msgid "Found %u addresses to report to NAT service\n" msgstr "" #: src/transport/plugin_transport_http.c:1309 #, c-format msgid "FREEING %s\n" msgstr "" #: src/transport/plugin_transport_http.c:1386 msgid "Neither IPv4 nor IPv6 are enabled! Fix in configuration\n" msgstr "" #: src/transport/plugin_transport_http.c:1399 #, fuzzy msgid "Port is required! Fix in configuration\n" msgstr " gconfig\tGTK-konfiguration\n" #: src/transport/plugin_transport_http.c:1410 msgid "Port 0, client only mode\n" msgstr "" #: src/transport/plugin_transport_http.c:1430 #, c-format msgid "" "Specific IPv4 address `%s' for plugin %s in configuration file is invalid! " "Binding to all addresses!\n" msgstr "" #: src/transport/plugin_transport_http.c:1460 #, c-format msgid "" "Specific IPv6 address `%s' for plugin %s in configuration file is invalid! " "Binding to all addresses!\n" msgstr "" #: src/transport/plugin_transport_http_client.c:624 #, c-format msgid "Could not initialize curl multi handle, failed to start %s plugin!\n" msgstr "" #: src/transport/plugin_transport_http_server.c:178 msgid "" "Could not create a new TLS certificate, program `gnunet-transport-" "certificate-creation' could not be started!\n" msgstr "" #: src/transport/plugin_transport_http_server.c:202 msgid "No usable TLS certificate found and creating one failed!\n" msgstr "" #: src/transport/plugin_transport_tcp.c:591 #, c-format msgid "Unexpected address length: %u bytes\n" msgstr "" #: src/transport/plugin_transport_tcp.c:767 #: src/transport/plugin_transport_tcp.c:856 #: src/transport/plugin_transport_tcp.c:906 #: src/transport/plugin_transport_tcp.c:992 #: src/transport/plugin_transport_tcp.c:1086 #: src/transport/plugin_transport_tcp.c:1103 #, fuzzy msgid "# bytes currently in TCP buffers" msgstr "# byte skickades via TCP" #: src/transport/plugin_transport_tcp.c:774 #: src/transport/plugin_transport_tcp.c:963 #: src/transport/plugin_transport_tcp.c:1761 #: src/transport/plugin_transport_tcp.c:2390 #, fuzzy msgid "# TCP sessions active" msgstr "# sessionsnycklar accepterade" #: src/transport/plugin_transport_tcp.c:860 #, fuzzy msgid "# bytes discarded by TCP (timeout)" msgstr "# byte kastade via TCP (utgÃ¥ende)" #: src/transport/plugin_transport_tcp.c:909 #, fuzzy msgid "# bytes transmitted via TCP" msgstr "# byte skickade av typen %d" #: src/transport/plugin_transport_tcp.c:996 #, fuzzy msgid "# bytes discarded by TCP (disconnect)" msgstr "# byte kastade via TCP (utgÃ¥ende)" #: src/transport/plugin_transport_tcp.c:1290 #, c-format msgid "Address of unexpected length: %u\n" msgstr "" #: src/transport/plugin_transport_tcp.c:1401 msgid "# transport-service disconnect requests for TCP" msgstr "" #: src/transport/plugin_transport_tcp.c:1802 #, fuzzy msgid "# TCP WELCOME messages received" msgstr "# krypterade PONG-meddelanden mottagna" #: src/transport/plugin_transport_tcp.c:1973 msgid "# bytes received via TCP" msgstr "# byte mottogs via TCP" #: src/transport/plugin_transport_tcp.c:2043 msgid "# network-level TCP disconnect events" msgstr "" #: src/transport/plugin_transport_tcp.c:2279 src/util/service.c:940 #, c-format msgid "Require valid port number for service `%s' in configuration!\n" msgstr "" #: src/transport/plugin_transport_tcp.c:2293 #, fuzzy msgid "Failed to start service.\n" msgstr "Misslyckades att starta samling.\n" #: src/transport/plugin_transport_tcp.c:2355 #, fuzzy, c-format msgid "Failed to find option %s in section %s!\n" msgstr "Misslyckades att binda till UDP-port %d.\n" #: src/transport/plugin_transport_tcp.c:2378 #, c-format msgid "TCP transport listening on port %llu\n" msgstr "" #: src/transport/plugin_transport_tcp.c:2382 msgid "TCP transport not listening on any port (client only)\n" msgstr "" #: src/transport/plugin_transport_tcp.c:2386 #, c-format msgid "TCP transport advertises itself as being on port %llu\n" msgstr "" #: src/transport/plugin_transport_udp_broadcasting.c:128 #, fuzzy msgid "# IPv6 multicast HELLO beacons received via udp" msgstr "# krypterade PONG-meddelanden mottagna" #: src/transport/plugin_transport_udp_broadcasting.c:169 #, fuzzy msgid "# IPv4 broadcast HELLO beacons received via udp" msgstr "# krypterade PONG-meddelanden mottagna" #: src/transport/plugin_transport_udp_broadcasting.c:367 #, c-format msgid "Failed to set IPv4 broadcast option for broadcast socket on port %d\n" msgstr "" #: src/transport/plugin_transport_udp.c:1894 #, c-format msgid "" "UDP could not message to `%s': `%s'. Please check your network configuration " "and disable IPv6 if your connection does not have a global IPv6 address\n" msgstr "" #: src/transport/plugin_transport_udp.c:2138 #, fuzzy msgid "Failed to open UDP sockets\n" msgstr "Misslyckades att binda till UDP6-port %d.\n" #: src/transport/plugin_transport_udp.c:2306 #, c-format msgid "Given `%s' option is out of range: %llu > %u\n" msgstr "" #: src/transport/plugin_transport_udp.c:2349 #, fuzzy, c-format msgid "Invalid IPv6 address: `%s'\n" msgstr "Ogiltigt svar pÃ¥ \"%s\".\n" #: src/transport/plugin_transport_unix.c:1356 #, fuzzy msgid "Failed to open UNIX sockets\n" msgstr "Misslyckades att leverera \"%s\" meddelande.\n" #: src/transport/plugin_transport_wlan.c:561 msgid "# WLAN ACKs sent" msgstr "" #: src/transport/plugin_transport_wlan.c:580 #, fuzzy msgid "# WLAN messages defragmented" msgstr "# PING-meddelanden skapade" #: src/transport/plugin_transport_wlan.c:626 #: src/transport/plugin_transport_wlan.c:676 #: src/transport/plugin_transport_wlan.c:1696 #, fuzzy msgid "# WLAN sessions allocated" msgstr "# sessionsnycklar accepterade" #: src/transport/plugin_transport_wlan.c:749 #, fuzzy msgid "# WLAN message fragments sent" msgstr "# byte mottogs via TCP" #: src/transport/plugin_transport_wlan.c:767 msgid "# WLAN messages pending (with fragmentation)" msgstr "" #: src/transport/plugin_transport_wlan.c:867 #: src/transport/plugin_transport_wlan.c:948 #: src/transport/plugin_transport_wlan.c:1698 #, fuzzy msgid "# WLAN MAC endpoints allocated" msgstr "# byte mottogs via TCP" #: src/transport/plugin_transport_wlan.c:1119 #, fuzzy msgid "# HELLO messages received via WLAN" msgstr "# krypterade PONG-meddelanden mottagna" #: src/transport/plugin_transport_wlan.c:1140 #, fuzzy msgid "# fragments received via WLAN" msgstr "# byte mottogs via TCP" #: src/transport/plugin_transport_wlan.c:1150 #, fuzzy msgid "# ACKs received via WLAN" msgstr "# byte mottogs via TCP" #: src/transport/plugin_transport_wlan.c:1207 #, fuzzy msgid "# WLAN DATA messages discarded due to CRC32 error" msgstr "Nätverksannonsering avstängd i konfigurationen!\n" #: src/transport/plugin_transport_wlan.c:1306 #, fuzzy msgid "# DATA messages received via WLAN" msgstr "# krypterade PONG-meddelanden mottagna" #: src/transport/plugin_transport_wlan.c:1341 #, fuzzy msgid "# WLAN DATA messages processed" msgstr "# krypterade PONG-meddelanden mottagna" #: src/transport/plugin_transport_wlan.c:1402 #, fuzzy msgid "# HELLO beacons sent via WLAN" msgstr "# byte skickade via UDP" #: src/transport/plugin_transport_wlan.c:1511 msgid "WLAN address with invalid size encountered\n" msgstr "" #: src/transport/plugin_transport_wlan.c:1668 #, fuzzy, c-format msgid "Invalid configuration option `%s' in section `%s'\n" msgstr "Konfigurationsfil \"%s\" skapad.\n" #: src/transport/plugin_transport_wlan.c:1677 #, c-format msgid "Helper binary `%s' not SUID, cannot run WLAN transport\n" msgstr "" #: src/transport/plugin_transport_wlan.c:1687 #, fuzzy, c-format msgid "Missing configuration option `%s' in section `%s'\n" msgstr "Konfigurationsfil \"%s\" skapad.\n" #: src/transport/transport_api.c:570 #, fuzzy, c-format msgid "Received unexpected message of type %u in %s:%u\n" msgstr "Mottog skadat meddelande frÃ¥n motpart \"%s\"i %s:%d.\n" #: src/util/bio.c:136 src/util/bio.c:142 #, fuzzy, c-format msgid "Error reading `%s': %s" msgstr "Fel vid skapandet av användare" #: src/util/bio.c:143 #, fuzzy msgid "End of file" msgstr "Läs in en konfigurationsfil" #: src/util/bio.c:195 #, c-format msgid "Error reading length of string `%s'" msgstr "" #: src/util/bio.c:205 #, c-format msgid "String `%s' longer than allowed (%u > %u)" msgstr "" #: src/util/bio.c:250 #, c-format msgid "Serialized metadata `%s' larger than allowed (%u>%u)" msgstr "" #: src/util/bio.c:264 #, c-format msgid "Metadata `%s' failed to deserialize" msgstr "" #: src/util/client.c:359 #, c-format msgid "" "Could not determine valid hostname and port for service `%s' from " "configuration.\n" msgstr "" #: src/util/client.c:367 #, c-format msgid "Need a non-empty hostname for service `%s'.\n" msgstr "" #: src/util/client.c:685 msgid "Failure to transmit TEST request.\n" msgstr "" #: src/util/client.c:740 src/util/service.c:970 #, c-format msgid "UNIXPATH `%s' too long, maximum length is %llu\n" msgstr "" #: src/util/client.c:882 #, fuzzy, c-format msgid "Could not connect to service `%s', must not be running.\n" msgstr "Kunde inte ansluta till gnunetd.\n" #: src/util/client.c:896 #, fuzzy, c-format msgid "Failure to transmit request to service `%s'\n" msgstr "Misslyckades att skicka HTTP-begäran till värd \"%s\": %s\n" #: src/util/client.c:1149 msgid "Could not submit request, not expecting to receive a response.\n" msgstr "" #: src/util/common_logging.c:239 src/util/common_logging.c:890 msgid "DEBUG" msgstr "FELSÖKNING" #: src/util/common_logging.c:241 src/util/common_logging.c:888 msgid "INFO" msgstr "INFO" #: src/util/common_logging.c:243 src/util/common_logging.c:886 msgid "WARNING" msgstr "VARNING" #: src/util/common_logging.c:245 src/util/common_logging.c:884 msgid "ERROR" msgstr "FEL" #: src/util/common_logging.c:247 src/util/common_logging.c:892 msgid "NONE" msgstr "" #: src/util/common_logging.c:610 #, fuzzy, c-format msgid "Failed to create or access directory for log file `%s'\n" msgstr "Kunde inte tolka konfigurationsfil \"%s\".\n" #: src/util/common_logging.c:725 #, c-format msgid "Message `%.*s' repeated %u times in the last %s\n" msgstr "" #: src/util/common_logging.c:893 msgid "INVALID" msgstr "" #: src/util/common_logging.c:992 msgid "unknown address" msgstr "" #: src/util/common_logging.c:1030 msgid "invalid address" msgstr "" #: src/util/configuration.c:244 #, fuzzy, c-format msgid "Syntax error in configuration file `%s' at line %u.\n" msgstr "Syntaxfel i konfigurationsfil \"%s\" pÃ¥ rad %d.\n" #: src/util/configuration.c:816 #, c-format msgid "" "Configuration value '%s' for '%s' in section '%s' is not in set of legal " "choices\n" msgstr "" #: src/util/connection.c:420 #, fuzzy, c-format msgid "Access denied to `%s'\n" msgstr "Ã…tkomst nekad för \"%s\" vid %s:%d.\n" #: src/util/connection.c:435 #, c-format msgid "Accepting connection from `%s': %p\n" msgstr "" #: src/util/connection.c:550 #, fuzzy, c-format msgid "" "Failed to establish TCP connection to `%s:%u', no further addresses to try.\n" msgstr "Misslyckades att starta samling.\n" #: src/util/connection.c:739 src/util/connection.c:909 #, fuzzy, c-format msgid "Trying to connect to `%s' (%p)\n" msgstr "Kan inte ansluta till %u.%u.%u.%u:%u: %s\n" #: src/util/connection.c:748 #, fuzzy, c-format msgid "Failed to connect to `%s' (%p)\n" msgstr "Kan inte ansluta till %u.%u.%u.%u:%u: %s\n" #: src/util/connection.c:900 #, fuzzy, c-format msgid "Attempt to connect to `%s' failed\n" msgstr " Anslutning misslyckades\n" #: src/util/container_bloomfilter.c:510 #, c-format msgid "" "Size of file on disk is incorrect for this Bloom filter (want %llu, have " "%llu)\n" msgstr "" #: src/util/crypto_random.c:280 #, c-format msgid "Starting `%s' process to generate entropy\n" msgstr "" #: src/util/crypto_random.c:309 #, c-format msgid "libgcrypt has not the expected version (version %s is required).\n" msgstr "libgcrypt har inte den förväntande versionen (version %s krävs).\n" #: src/util/crypto_rsa.c:661 src/util/crypto_rsa.c:708 #, fuzzy, c-format msgid "Could not aquire lock on file `%s': %s...\n" msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" #: src/util/crypto_rsa.c:666 #, fuzzy msgid "Creating a new private key. This may take a while.\n" msgstr "Skapar ny värdnyckel (det här kan ta en stund).\n" #: src/util/crypto_rsa.c:684 #, c-format msgid "I am host `%s'. Stored new private key in `%s'.\n" msgstr "" #: src/util/crypto_rsa.c:712 src/util/crypto_rsa.c:748 msgid "This may be ok if someone is currently generating a hostkey.\n" msgstr "" #: src/util/crypto_rsa.c:743 #, c-format msgid "" "When trying to read hostkey file `%s' I found %u bytes but I need at least " "%u.\n" msgstr "" #: src/util/crypto_rsa.c:763 #, fuzzy, c-format msgid "File `%s' does not contain a valid private key. Deleting it.\n" msgstr "Filen \"%s\" innehÃ¥ller ingen pseudonym.\n" #: src/util/crypto_rsa.c:781 #, fuzzy, c-format msgid "I am host `%s'. Read private key from `%s'.\n" msgstr "Anrop till \"%s\" med nyckel \"%s\".\n" #: src/util/crypto_rsa.c:1032 #, c-format msgid "RSA signature verification failed at %s:%d: %s\n" msgstr "" # drive = hard drive ? #: src/util/disk.c:498 #, fuzzy, c-format msgid "`%s' failed for drive `%S': %u\n" msgstr "\"%s\" misslyckades för enhet %s: %u\n" #: src/util/disk.c:1062 #, fuzzy, c-format msgid "Expected `%s' to be a directory!\n" msgstr "\"%s\" förväntade att \"%s\" skulle vara en katalog!\n" #: src/util/disk.c:1416 src/util/service.c:1650 #, fuzzy, c-format msgid "Cannot obtain information about user `%s': %s\n" msgstr "Kan inte öppna konfigurationsfil \"%s\".\n" #: src/util/disk.c:1734 #, fuzzy, c-format msgid "No `%s' specified for service `%s' in configuration.\n" msgstr "Inga applikationer definierade i konfiguration!\n" #: src/util/getopt.c:669 #, c-format msgid "%s: option `%s' is ambiguous\n" msgstr "%s: flagga \"%s\" är tvetydig\n" #: src/util/getopt.c:693 #, c-format msgid "%s: option `--%s' does not allow an argument\n" msgstr "%s: flagga \"--%s\" tillÃ¥ter inte ett argument\n" #: src/util/getopt.c:698 #, c-format msgid "%s: option `%c%s' does not allow an argument\n" msgstr "%s: flagga \"%c%s\" tillÃ¥ter inte ett argument\n" #: src/util/getopt.c:715 src/util/getopt.c:883 #, c-format msgid "%s: option `%s' requires an argument\n" msgstr "%s: flagga \"%s\" kräver ett argument\n" #: src/util/getopt.c:744 #, c-format msgid "%s: unrecognized option `--%s'\n" msgstr "%s: okänd flagga \"--%s\"\n" #: src/util/getopt.c:748 #, c-format msgid "%s: unrecognized option `%c%s'\n" msgstr "%s: okänd flagga \"%c%s\"\n" #: src/util/getopt.c:773 #, c-format msgid "%s: illegal option -- %c\n" msgstr "%s: otillÃ¥ten flagga -- %c\n" #: src/util/getopt.c:775 #, c-format msgid "%s: invalid option -- %c\n" msgstr "%s: ogiltig flagga -- %c\n" #: src/util/getopt.c:803 src/util/getopt.c:931 #, c-format msgid "%s: option requires an argument -- %c\n" msgstr "%s: flagga kräver ett argument -- %c\n" #: src/util/getopt.c:851 #, c-format msgid "%s: option `-W %s' is ambiguous\n" msgstr "%s: flagga \"-W %s\" är tvetydig\n" #: src/util/getopt.c:869 #, c-format msgid "%s: option `-W %s' does not allow an argument\n" msgstr "%s: flagga \"-W %s\" tillÃ¥ter inte ett argument\n" #: src/util/getopt.c:1035 #, fuzzy, c-format msgid "Use %s to get a list of options.\n" msgstr "Använd --help för att fÃ¥ en lista pÃ¥ flaggor.\n" #: src/util/getopt_helpers.c:86 #, c-format msgid "" "Arguments mandatory for long options are also mandatory for short options.\n" msgstr "" "Argument som är obligatoriska för lÃ¥nga flaggor är ocksÃ¥ obligatoriska för " "korta flaggor.\n" #: src/util/getopt_helpers.c:258 src/util/getopt_helpers.c:286 #, c-format msgid "You must pass a number to the `%s' option.\n" msgstr "Du mÃ¥ste skicka med ett nummer till flaggan \"%s\".\n" #: src/util/gnunet-resolver.c:148 msgid "perform a reverse lookup" msgstr "" #: src/util/gnunet-resolver.c:154 msgid "Use build-in GNUnet stub resolver" msgstr "" #: src/util/gnunet-rsa.c:64 #, c-format msgid "No hostkey file specified on command line\n" msgstr "" #: src/util/gnunet-rsa.c:112 msgid "print the public key in ASCII format" msgstr "" #: src/util/gnunet-rsa.c:115 msgid "print the hash of the public key in ASCII format" msgstr "" #: src/util/gnunet-rsa.c:118 msgid "print the short hash of the public key in ASCII format" msgstr "" #: src/util/gnunet-rsa.c:124 msgid "Manipulate GNUnet private RSA key files" msgstr "" #: src/util/gnunet-service-resolver.c:288 #, fuzzy, c-format msgid "Could not resolve `%s' (%s): %s\n" msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" #: src/util/gnunet-service-resolver.c:358 #: src/util/gnunet-service-resolver.c:399 #, c-format msgid "Could not find IP of host `%s': %s\n" msgstr "" #: src/util/helper.c:244 #, fuzzy, c-format msgid "Error reading from `%s': %s\n" msgstr "Fel vid skapandet av användare" #: src/util/helper.c:259 #, c-format msgid "Got 0 bytes from helper `%s' (EOF)\n" msgstr "" #: src/util/helper.c:269 #, c-format msgid "Got %u bytes from helper `%s'\n" msgstr "" #: src/util/helper.c:278 #, fuzzy, c-format msgid "Failed to parse inbound message from helper `%s'\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/util/helper.c:310 #, fuzzy, c-format msgid "Starting HELPER process `%s'\n" msgstr "Startade samling \"%s\".\n" #: src/util/helper.c:440 #, fuzzy, c-format msgid "Error writing to `%s': %s\n" msgstr "Fel vid skapandet av användare" #: src/util/network.c:1200 #, c-format msgid "" "Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n" msgstr "" #: src/util/os_installation.c:299 #, c-format msgid "" "Could not determine installation path for %s. Set `%s' environment " "variable.\n" msgstr "" #: src/util/os_installation.c:486 #, fuzzy, c-format msgid "Could not find binary `%s' in PATH!\n" msgstr "Kunde inte hitta motpart \"%s\" i routingtabell!\n" #: src/util/os_installation.c:492 #, fuzzy, c-format msgid "access (%s, X_OK) failed: %s\n" msgstr "\"%s\" %s misslyckades: %s\n" #: src/util/os_installation.c:507 #, fuzzy, c-format msgid "stat (%s) failed: %s\n" msgstr "\"%s\" %s misslyckades: %s\n" #: src/util/os_priority.c:305 #, fuzzy, c-format msgid "Failed to open named pipe `%s' for reading: %s\n" msgstr "Misslyckades att leverera \"%s\" meddelande.\n" #: src/util/os_priority.c:306 #, fuzzy, c-format msgid "Failed to open named pipe `%s' for writing: %s\n" msgstr "Misslyckades att leverera \"%s\" meddelande.\n" #: src/util/plugin.c:89 #, c-format msgid "Initialization of plugin mechanism failed: %s!\n" msgstr "Initiering av insticksmekanism misslyckades: %s!\n" #: src/util/plugin.c:146 #, fuzzy, c-format msgid "`%s' failed to resolve method '%s' with error: %s\n" msgstr "\"%s\" misslyckades för fil \"%s\" vid %s:%d med fel: %s\n" #: src/util/plugin.c:219 #, fuzzy, c-format msgid "`%s' failed for library `%s' with error: %s\n" msgstr "\"%s\" misslyckades vid %s:%d med fel: %s\n" #: src/util/plugin.c:349 #, fuzzy msgid "Could not determine plugin installation path.\n" msgstr "Kunde inte fastställa min publika IPv6-adress.\n" #: src/util/pseudonym.c:276 #, fuzzy, c-format msgid "Failed to parse metadata about pseudonym from file `%s': %s\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/util/pseudonym.c:407 src/util/pseudonym.c:433 #, fuzzy msgid "no-name" msgstr "Visa namn" #: src/util/resolver_api.c:202 #, fuzzy, c-format msgid "Must specify `%s' for `%s' in configuration!\n" msgstr "Försöker använda fil \"%s\" för MySQL-konfiguration.\n" #: src/util/resolver_api.c:221 #, fuzzy, c-format msgid "" "Must specify `%s' or numeric IP address for `%s' of `%s' in configuration!\n" msgstr "" "Du mÃ¥ste ange ett positivt nummer för \"%s\" i konfigurationen i sektion \"%s" "\".\n" #: src/util/resolver_api.c:347 #, c-format msgid "Timeout trying to resolve IP address `%s'.\n" msgstr "" #: src/util/resolver_api.c:351 #, fuzzy, c-format msgid "Timeout trying to resolve hostname `%s'.\n" msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #: src/util/resolver_api.c:890 #, fuzzy, c-format msgid "Could not resolve our FQDN : %s\n" msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" #: src/util/scheduler.c:786 msgid "Looks like we're busy waiting...\n" msgstr "" #: src/util/scheduler.c:916 #, c-format msgid "Attempt to cancel dead task %llu!\n" msgstr "" # drive = hard drive ? #: src/util/server.c:483 #, fuzzy, c-format msgid "`%s' failed for port %d (%s).\n" msgstr "\"%s\" misslyckades för enhet %s: %u\n" #: src/util/server.c:492 #, fuzzy, c-format msgid "`%s' failed for port %d (%s): address already in use\n" msgstr "\"%s\" misslyckades för port %d: %s. Körs verkligen gnunetd?\n" #: src/util/server.c:497 #, fuzzy, c-format msgid "`%s' failed for `%s': address already in use\n" msgstr "\"%s\" misslyckades för port %d: %s. Körs verkligen gnunetd?\n" #: src/util/server.c:827 #, c-format msgid "" "Processing code for message of type %u did not call " "GNUNET_SERVER_receive_done after %llums\n" msgstr "" #: src/util/service.c:135 src/util/service.c:161 src/util/service.c:204 #: src/util/service.c:225 src/util/service.c:232 #, c-format msgid "Invalid format for IP: `%s'\n" msgstr "Ogiltigt format för IP: \"%s\"\n" #: src/util/service.c:188 #, c-format msgid "Invalid network notation ('/%d' is not legal in IPv4 CIDR)." msgstr "Ogiltig nätverksnotation (\"/%d\" är inte giltig i IPv4 CIDR)." #: src/util/service.c:281 #, c-format msgid "Invalid network notation (does not end with ';': `%s')\n" msgstr "Ogiltig nätverksnotation (slutar inte med \";\": \"%s\")\n" #: src/util/service.c:313 #, fuzzy, c-format msgid "Wrong format `%s' for netmask\n" msgstr "Fel format \"%s\" för nätmask: %s\n" #: src/util/service.c:343 #, fuzzy, c-format msgid "Wrong format `%s' for network\n" msgstr "Fel format \"%s\" för nätverk: %s\n" #: src/util/service.c:698 #, c-format msgid "Access denied to UID %d / GID %d\n" msgstr "" #: src/util/service.c:703 #, fuzzy, c-format msgid "Unknown address family %d\n" msgstr "Okänd operation \"%s\"\n" #: src/util/service.c:710 #, c-format msgid "Access from `%s' denied to service `%s'\n" msgstr "" #: src/util/service.c:765 #, c-format msgid "Could not parse IPv4 network specification `%s' for `%s:%s'\n" msgstr "" #: src/util/service.c:802 #, c-format msgid "Could not parse IPv6 network specification `%s' for `%s:%s'\n" msgstr "" #: src/util/service.c:920 #, c-format msgid "" "Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n" msgstr "" #: src/util/service.c:990 #, c-format msgid "" "Disabling UNIX domain socket support for service `%s', failed to create UNIX " "domain socket: %s\n" msgstr "" #: src/util/service.c:1007 #, c-format msgid "Have neither PORT nor UNIXPATH for service `%s', but one is required\n" msgstr "" #: src/util/service.c:1241 msgid "Could not access a pre-bound socket, will try to bind myself\n" msgstr "" #: src/util/service.c:1292 src/util/service.c:1310 #, c-format msgid "Specified value for `%s' of service `%s' is invalid\n" msgstr "" #: src/util/service.c:1337 #, c-format msgid "Could not access pre-bound socket %u, will try to bind myself\n" msgstr "" #: src/util/service.c:1506 #, fuzzy, c-format msgid "Failed to start `%s' at `%s'\n" msgstr "Fel vid %s:%d.\n" #: src/util/service.c:1539 #, fuzzy, c-format msgid "Service `%s' runs at %s\n" msgstr "Motpart \"%s\" med pÃ¥litlighet %8u och adress \"%s\"\n" #: src/util/service.c:1588 msgid "Service process failed to initialize\n" msgstr "" #: src/util/service.c:1592 msgid "Service process could not initialize server function\n" msgstr "" #: src/util/service.c:1596 msgid "Service process failed to report status\n" msgstr "" #: src/util/service.c:1651 msgid "No such user" msgstr "" #: src/util/service.c:1664 #, c-format msgid "Cannot change user/group to `%s': %s\n" msgstr "Kan inte ändra användare/grupp till \"%s\": %s\n" #: src/util/service.c:1729 msgid "do daemonize (detach from terminal)" msgstr "" #: src/util/signal.c:80 #, fuzzy, c-format msgid "signal (%d, %p) returned %d.\n" msgstr "Anrop till \"%s\" returnerade %d.\n" #: src/util/strings.c:144 msgid "b" msgstr "b" #: src/util/strings.c:334 #, c-format msgid "Character sets requested were `%s'->`%s'\n" msgstr "" #: src/util/strings.c:481 msgid "Failed to expand `$HOME': environment variable `HOME' not set" msgstr "" #: src/util/strings.c:573 msgid "ms" msgstr "ms" #: src/util/strings.c:578 msgid "eternity" msgstr "" #: src/util/strings.c:582 msgid "s" msgstr "s" #: src/util/strings.c:586 msgid "m" msgstr "m" #: src/util/strings.c:590 msgid "h" msgstr "h" #: src/util/strings.c:594 msgid " days" msgstr " dagar" #: src/util/strings.c:618 msgid "end of time" msgstr "" #: src/util/strings.c:1012 msgid "IPv6 address did not start with `['\n" msgstr "" #: src/util/strings.c:1020 msgid "IPv6 address did contain ':' to separate port number\n" msgstr "" #: src/util/strings.c:1026 msgid "IPv6 address did contain ']' before ':' to separate port number\n" msgstr "" #: src/util/strings.c:1033 msgid "IPv6 address did contain a valid port number after the last ':'\n" msgstr "" #: src/util/strings.c:1042 #, fuzzy, c-format msgid "Invalid IPv6 address `%s': %s\n" msgstr "Ogiltigt svar pÃ¥ \"%s\".\n" #: src/vpn/gnunet-service-vpn.c:511 src/vpn/gnunet-service-vpn.c:1071 #, fuzzy msgid "# Active tunnels" msgstr "Nätverksanslutning" #: src/vpn/gnunet-service-vpn.c:608 src/vpn/gnunet-service-vpn.c:645 #, fuzzy msgid "# peers connected to mesh tunnels" msgstr "# av anslutna parter" #: src/vpn/gnunet-service-vpn.c:699 #, fuzzy msgid "# Bytes given to mesh for transmission" msgstr "# PING-meddelanden skapade" #: src/vpn/gnunet-service-vpn.c:737 #, fuzzy msgid "# Bytes dropped in mesh queue (overflow)" msgstr "# byte kastade via UDP (utgÃ¥ende)" #: src/vpn/gnunet-service-vpn.c:772 #, fuzzy msgid "# Mesh tunnels created" msgstr "# PING-meddelanden skapade" #: src/vpn/gnunet-service-vpn.c:795 #, fuzzy msgid "Failed to setup mesh tunnel!\n" msgstr "Kunde inte skapa värdnyckel!\n" #: src/vpn/gnunet-service-vpn.c:973 #, c-format msgid "Protocol %u not supported, dropping\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1291 msgid "# ICMPv4 packets dropped (not allowed)" msgstr "" #: src/vpn/gnunet-service-vpn.c:1312 msgid "# ICMPv6 packets dropped (not allowed)" msgstr "" #: src/vpn/gnunet-service-vpn.c:1517 #, fuzzy msgid "# Packets received from TUN interface" msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" #: src/vpn/gnunet-service-vpn.c:1555 src/vpn/gnunet-service-vpn.c:1596 #, c-format msgid "Packet received for unmapped destination `%s' (dropping it)\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1606 msgid "Received IPv4 packet with options (dropping it)\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1620 #, c-format msgid "Received packet of unknown protocol %d from TUN (dropping it)\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1704 #, fuzzy msgid "# ICMP packets received from mesh" msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" #: src/vpn/gnunet-service-vpn.c:2045 #, fuzzy msgid "# UDP packets received from mesh" msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" #: src/vpn/gnunet-service-vpn.c:2203 #, fuzzy msgid "# TCP packets received from mesh" msgstr "Meddelande mottaget frÃ¥n klient är ogiltig.\n" #: src/vpn/gnunet-service-vpn.c:2354 msgid "Failed to find unallocated IPv4 address in VPN's range\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:2409 msgid "Failed to find unallocated IPv6 address in VPN's range\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:2448 src/vpn/gnunet-service-vpn.c:2661 #, fuzzy msgid "# Active destinations" msgstr "Nätverksanslutning" #: src/vpn/gnunet-service-vpn.c:2734 msgid "Failed to allocate IP address for new destination\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:3141 msgid "IPv6 support disabled as this system does not support IPv6\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:3173 msgid "IPv4 support disabled as this system does not support IPv4\n" msgstr "" #: src/vpn/gnunet-vpn.c:151 #, fuzzy msgid "Error creating tunnel\n" msgstr "Klar med skapandet av värdnyckel.\n" #: src/vpn/gnunet-vpn.c:195 src/vpn/gnunet-vpn.c:226 #, fuzzy, c-format msgid "Option `%s' makes no sense with option `%s'.\n" msgstr "Kommando \"%s\" kräver ett argument (\"%s\").\n" #: src/vpn/gnunet-vpn.c:208 #, fuzzy, c-format msgid "Option `%s' or `%s' is required.\n" msgstr "%s: flagga \"%s\" är tvetydig\n" #: src/vpn/gnunet-vpn.c:220 #, fuzzy, c-format msgid "Option `%s' or `%s' is required when using option `%s'.\n" msgstr "Kommando \"%s\" kräver ett argument (\"%s\").\n" #: src/vpn/gnunet-vpn.c:238 #, fuzzy, c-format msgid "`%s' is not a valid peer identifier.\n" msgstr "\"%s\" är inte en vanlig fil.\n" #: src/vpn/gnunet-vpn.c:260 #, fuzzy, c-format msgid "`%s' is not a valid IP address.\n" msgstr "\"%s\" är inte tillgänglig." #: src/vpn/gnunet-vpn.c:296 msgid "request that result should be an IPv4 address" msgstr "" #: src/vpn/gnunet-vpn.c:299 msgid "request that result should be an IPv6 address" msgstr "" #: src/vpn/gnunet-vpn.c:302 msgid "print IP address only after mesh tunnel has been created" msgstr "" #: src/vpn/gnunet-vpn.c:305 msgid "how long should the mapping be valid for new tunnels?" msgstr "" #: src/vpn/gnunet-vpn.c:308 msgid "destination IP for the tunnel" msgstr "" #: src/vpn/gnunet-vpn.c:311 msgid "peer offering the service we would like to access" msgstr "" #: src/vpn/gnunet-vpn.c:314 msgid "name of the service we would like to access" msgstr "" #: src/vpn/gnunet-vpn.c:317 #, fuzzy msgid "service is offered via TCP" msgstr "# byte mottogs via TCP" #: src/vpn/gnunet-vpn.c:320 #, fuzzy msgid "service is offered via UDP" msgstr "# byte mottagna via UDP" #: src/vpn/gnunet-vpn.c:329 msgid "Setup tunnels via VPN." msgstr "" #: src/include/gnunet_common.h:497 src/include/gnunet_common.h:502 #: src/include/gnunet_common.h:508 #, fuzzy, c-format msgid "Assertion failed at %s:%d.\n" msgstr "\"%s\" misslyckades vid %s:%d med fel: \"%s\".\n" #: src/include/gnunet_common.h:518 #, c-format msgid "External protocol violation detected at %s:%d.\n" msgstr "" #: src/include/gnunet_common.h:539 src/include/gnunet_common.h:546 #, c-format msgid "`%s' failed on file `%s' at %s:%d with error: %s\n" msgstr "\"%s\" misslyckades för fil \"%s\" vid %s:%d med fel: %s\n" #, fuzzy #~ msgid "Received malformed message via %s. Ignored.\n" #~ msgstr "Mottog ogiltigt \"%s\" meddelande frÃ¥n \"%s\".\n" # capped är inte ett bra ord IMHO #, fuzzy #~ msgid "SMTP filter string to invalid, lacks ': '\n" #~ msgstr "SMTP-filtersträng för lÃ¥ng, kapad till \"%s\"\n" # capped är inte ett bra ord IMHO #~ msgid "SMTP filter string to long, capped to `%s'\n" #~ msgstr "SMTP-filtersträng för lÃ¥ng, kapad till \"%s\"\n" #, fuzzy #~ msgid "SMTP: `%s' failed: %s.\n" #~ msgstr "\"%s\" %s misslyckades: %s\n" #, fuzzy #~ msgid "# bytes received via SMTP" #~ msgstr "# byte mottogs via TCP" #, fuzzy #~ msgid "# bytes sent via SMTP" #~ msgstr "# byte skickades via TCP" #, fuzzy #~ msgid "# bytes dropped by SMTP (outgoing)" #~ msgstr "# byte kastade via TCP (utgÃ¥ende)" #, fuzzy #~ msgid "# Peers connected" #~ msgstr "# av anslutna parter" #, fuzzy #~ msgid "%s failed for `%s' at %s:%d: `%s'\n" #~ msgstr "\"%s\" misslyckades vid %s:%d med fel: \"%s\".\n" #, fuzzy #~ msgid "Failed to transmit shutdown ACK.\n" #~ msgstr "Misslyckades att starta samling.\n" #, fuzzy #~ msgid "Unable to initialize Postgres with configuration `%s': %s" #~ msgstr "Kunde inte spara konfigurationsfil \"%s\":" #, fuzzy #~ msgid "Failed to transmit message to `%s' service.\n" #~ msgstr "Misslyckades att initiera tjänsten \"%s\".\n" #, fuzzy #~ msgid "Target is %d connections per peer." #~ msgstr "Misslyckades att starta samling.\n" #, fuzzy #~ msgid "Copying file with RENAME (%s,%s)\n" #~ msgstr "\"%s\" misslyckades vid %s:%d med fel: %s\n" #, fuzzy #~ msgid "Copying file with command scp %s %s\n" #~ msgstr "\"%s\" misslyckades vid %s:%d med fel: %s\n" #, fuzzy #~ msgid "Finished copying all blacklist files!\n" #~ msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #, fuzzy #~ msgid "Failed during blacklist file copying!\n" #~ msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #, fuzzy #~ msgid "# bytes payload received for other peers" #~ msgstr "# byte mottagna av typen %d" #, fuzzy #~ msgid "# fast reconnects failed" #~ msgstr "# av anslutna parter" #, fuzzy #~ msgid "# peers disconnected due to timeout" #~ msgstr "# av anslutna parter" #, fuzzy #~ msgid "# peers disconnected due to global disconnect" #~ msgstr "Nätverksannonsering avstängd i konfigurationen!\n" #, fuzzy #~ msgid "# unexpected CONNECT_ACK messages" #~ msgstr "skicka ANTAL meddelanden" #, fuzzy #~ msgid "# wlan session timeouts" #~ msgstr "# sessionsnycklar accepterade" #, fuzzy #~ msgid "# wlan session created" #~ msgstr "# sessionsnycklar accepterade" #, fuzzy #~ msgid "# wlan pending fragments" #~ msgstr "# byte mottogs via TCP" #, fuzzy #~ msgid "# wlan whole messages received" #~ msgstr "# krypterade PONG-meddelanden mottagna" #, fuzzy #~ msgid "# wlan hello messages received" #~ msgstr "# krypterade PONG-meddelanden mottagna" #, fuzzy #~ msgid "# wlan fragments received" #~ msgstr "# byte mottogs via TCP" #, fuzzy #~ msgid "# wlan acks received" #~ msgstr "# klartext PONG-meddelanden mottagna" #, fuzzy #~ msgid "# wlan messages for this client received" #~ msgstr "# krypterade PONG-meddelanden mottagna" #, fuzzy #~ msgid "# wlan messages inside WLAN_HELPER_DATA received" #~ msgstr "# krypterade PONG-meddelanden mottagna" #, fuzzy #~ msgid "Unknown user `%s'\n" #~ msgstr "Okänd operation \"%s\"\n" #, fuzzy #~ msgid "Namespace `%s' unknown.\n" #~ msgstr "Namnrymd \"%s\" skapad(rot: %s).\n" #, fuzzy #~ msgid "Failed to connect to statistics service!\n" #~ msgstr "Misslyckades att ansluta till gnunetd.\n" #, fuzzy #~ msgid "Failed to send to `%s': %s\n" #~ msgstr "Misslyckades att leverera \"%s\" meddelande.\n" #, fuzzy #~ msgid "Could not access file: %s\n" #~ msgstr "Kunde inte köra \"%s\": %s\n" # drive = hard drive ? #, fuzzy #~ msgid "`%s' failed on file `%s': %s" #~ msgstr "\"%s\" misslyckades för enhet %s: %u\n" #, fuzzy #~ msgid "# bytes TCP was asked to transmit" #~ msgstr "# byte skickade av typen %d" #, fuzzy #~ msgid "# bytes discarded by TCP (failed to connect)" #~ msgstr "# byte kastade via TCP (utgÃ¥ende)" #, fuzzy #~ msgid "# wlan messages queued" #~ msgstr "# krypterade PONG-meddelanden mottagna" #~ msgid "print this help" #~ msgstr "skriv ut denna hjälp" #~ msgid "print the version number" #~ msgstr "skriv ut versionsnummer" #~ msgid "be verbose" #~ msgstr "var informativ" #~ msgid "use configuration file FILENAME" #~ msgstr "använd konfigurationsfil FILNAMN" #, fuzzy #~ msgid "Failed to stop service `%s'!\n" #~ msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #, fuzzy #~ msgid "Failed to start service `%s'!\n" #~ msgstr "Misslyckades att starta samling.\n" #, fuzzy #~ msgid "Service `%s' stopped\n" #~ msgstr "Tjänst borttagen.\n" #, fuzzy #~ msgid "Unable to start service `%s': %s\n" #~ msgstr "Kunde inte spara konfigurationsfil \"%s\":" #, fuzzy #~ msgid "Unable to accept connection for service `%s': %s\n" #~ msgstr "Kunde inte spara konfigurationsfil \"%s\":" #, fuzzy #~ msgid "Peer `%s' plugin: `%s' address `%s'\n" #~ msgstr "Motpart \"%s\" med pÃ¥litlighet %8u och adress \"%s\"\n" #, fuzzy #~ msgid "Failed to create IPv4 broadcast socket on port %d\n" #~ msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #, fuzzy #~ msgid "Failed to load block plugin `%s'\n" #~ msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" #, fuzzy #~ msgid "Could not resolve our FQDN : %s %u\n" #~ msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" #, fuzzy #~ msgid "Failed to load dhtlog plugin for `%s'\n" #~ msgstr "Misslyckades att läsa kompislista frÃ¥n \"%s\"\n" #, fuzzy #~ msgid "Found peer `%s'\n" #~ msgstr "Jag är ändpunkt \"%s\".\n" #, fuzzy #~ msgid "Loading udp transport plugin\n" #~ msgstr "Testar transport(er) %s\n" #, fuzzy #~ msgid "# SET QUOTA messages received" #~ msgstr "# krypterade PONG-meddelanden mottagna" #, fuzzy #~ msgid "curl failed for `%s' at %s:%d: `%s'\n" #~ msgstr "\"%s\" misslyckades vid %s:%d med fel: \"%s\".\n" #, fuzzy #~ msgid "Phase 3: sending messages\n" #~ msgstr "Misslyckades att leverera \"%s\" meddelande.\n" #, fuzzy #~ msgid "Loading HTTPS transport plugin `%s'\n" #~ msgstr "Testar transport(er) %s\n" #, fuzzy #~ msgid "Failed to load transport plugin for https\n" #~ msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" #, fuzzy #~ msgid "Fail! Could not connect peers\n" #~ msgstr "\"%s\": Kunde inte ansluta.\n" #, fuzzy #~ msgid "Loading tcp transport plugin\n" #~ msgstr "Testar transport(er) %s\n" #, fuzzy #~ msgid "Failed to load transport plugin for tcp\n" #~ msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" #, fuzzy #~ msgid "Connection: %X: %s failed at %s:%d: `%s'\n" #~ msgstr "\"%s\" misslyckades vid %s:%d med fel: \"%s\".\n" #, fuzzy #~ msgid "Misconfigured address to bind to in configuration!\n" #~ msgstr "Inga applikationer definierade i konfiguration!\n" #, fuzzy #~ msgid "Failed to load transport plugin for http\n" #~ msgstr "Kunde inte slÃ¥ upp \"%s\": %s\n" #, fuzzy #~ msgid "# PING messages decrypted" #~ msgstr "# PING-meddelanden skapade" #, fuzzy #~ msgid "Failed to connect to core service\n" #~ msgstr "Misslyckades att ansluta till gnunetd.\n" #, fuzzy #~ msgid "# bytes successfully transmitted by plugins" #~ msgstr "# byte skickade av typen %d" #, fuzzy #~ msgid "# connected addresses" #~ msgstr "# av anslutna parter" #, fuzzy #~ msgid "# transport failed to selected peer address" #~ msgstr "Annonserar min transport %d till valda ändpunkter.\n" #, fuzzy #~ msgid "# PING with HELLO messages sent" #~ msgstr "# PING-meddelanden skapade" #, fuzzy #~ msgid "Received `%s' message from `%s' destined for `%s' which is not me!\n" #~ msgstr "Mottog PING som ej var ämnat för oss!\n" #, fuzzy #~ msgid "Could not send PONG to `%s': no address available\n" #~ msgstr "Kunde inte hitta motpart \"%s\" i routingtabell!\n" #~ msgid "Error" #~ msgstr "Fel" #~ msgid "Help" #~ msgstr "Hjälp" #, fuzzy #~ msgid "Error!" #~ msgstr "Fel" #~ msgid "No" #~ msgstr "Nej" #~ msgid "Yes" #~ msgstr "Ja" #, fuzzy #~ msgid "Abort" #~ msgstr "_Om" #, fuzzy #~ msgid "Ok" #~ msgstr "k" #~ msgid "" #~ "Welcome to GNUnet!\n" #~ "\n" #~ "This assistant will ask you a few basic questions in order to configure " #~ "GNUnet.\n" #~ "\n" #~ "Please visit our homepage at\n" #~ "\thttp://gnunet.org/\n" #~ "and join our community at\n" #~ "\thttp://gnunet.org/drupal/\n" #~ "\n" #~ "Have a lot of fun,\n" #~ "\n" #~ "the GNUnet team" #~ msgstr "" #~ "Välkommen till GNUnet!\n" #~ "\n" #~ "Denna assistant kommer att frÃ¥ga dig nÃ¥gra enkla frÃ¥gor för att " #~ "konfigurera GNUnet.\n" #~ "\n" #~ "Vänligen besök pÃ¥ webbplats pÃ¥\n" #~ "\thttp://gnunet.org/\n" #~ "och gÃ¥ med i vÃ¥r gemenskap pÃ¥\n" #~ "\thttp://gnunet.org/drupal/\n" #~ "\n" #~ "Ha det sÃ¥ kul,\n" #~ "\n" #~ "the GNUnet team" #, fuzzy #~ msgid "Network configuration: interface" #~ msgstr "Nätverksgränssnitt:" #, fuzzy #~ msgid "Network configuration: IP" #~ msgstr "GNUnet-konfiguration" #, fuzzy #~ msgid "Bandwidth configuration: upload" #~ msgstr "GNUnet-konfiguration" #, fuzzy #~ msgid "How much upstream bandwidth (in bytes/s) may be used?" #~ msgstr "Hur mycket CPU (i %) fÃ¥r användas?" #, fuzzy #~ msgid "Bandwidth configuration: download" #~ msgstr "GNUnet-konfiguration" #, fuzzy #~ msgid "How much downstream bandwidth (in bytes/s) may be used?" #~ msgstr "Hur mycket CPU (i %) fÃ¥r användas?" #, fuzzy #~ msgid "Quota configuration" #~ msgstr "GNUnet-konfiguration" #, fuzzy #~ msgid "Daemon configuration: user account" #~ msgstr "Kunde inte skapa användarkonto:" #, fuzzy #~ msgid "Save configuration?" #~ msgstr "GNUnet-konfiguration" #, fuzzy #~ msgid "GNUnet Configuration" #~ msgstr "GNUnet-konfiguration" #~ msgid "Back" #~ msgstr "Tillbaka" #~ msgid "Up" #~ msgstr "Upp" #~ msgid "Cancel" #~ msgstr "Avbryt" #, fuzzy #~ msgid "Configuration unchanged, no need to save.\n" #~ msgstr "" #~ "Konfiguration eller version av GNUnet ändrad. Du behöver köra \"%s\"!\n" #, fuzzy #~ msgid "Do you wish to save your new configuration?" #~ msgstr "Vill du spara dina inställningar?" #~ msgid "This version of Windows doesn't support services.\n" #~ msgstr "Denna version av Windows har inte stöd för tjänster.\n" #~ msgid "Error: can't create service: %s\n" #~ msgstr "Fel: kan inte skapa tjänst: %s\n" #~ msgid "Error: can't delete service: %s\n" #~ msgstr "Fel: kan inte ta bort tjänst: %s\n" #, fuzzy #~ msgid "Configuration changed. Save?" #~ msgstr "Konfigurationsfil \"%s\" skapad.\n" #, fuzzy #~ msgid "Error saving configuration." #~ msgstr "Kunde inte spara konfiguration!" #, fuzzy #~ msgid "(unknown connection)" #~ msgstr "Nätverksanslutning" #, fuzzy #~ msgid "Do you want to save the new configuration?" #~ msgstr "Vill du spara dina inställningar?" #~ msgid "Tool to setup GNUnet." #~ msgstr "Verktyg för att ställa in GNUnet." #, fuzzy #~ msgid "Too many arguments.\n" #~ msgstr "Ogiltiga kommandoradsargument.\n" #, fuzzy #~ msgid "No interface specified, using default.\n" #~ msgstr "Inget tabellnamn angivet, använder \"%s\".\n" #, fuzzy #~ msgid "Configuration file `%s' must be a filename (but is a directory).\n" #~ msgstr "Konfigurationsfil \"%s\" skapad.\n" #, fuzzy #~ msgid "Unknown operation '%s'.\n" #~ msgstr "Okänd operation \"%s\"\n" #, fuzzy #~ msgid "yes" #~ msgstr "Ja" #, fuzzy #~ msgid "Yes\n" #~ msgstr "Ja" #, fuzzy #~ msgid "No\n" #~ msgstr "Nej" #, fuzzy #~ msgid "Help\n" #~ msgstr "Hjälp" #, fuzzy #~ msgid "Abort\n" #~ msgstr "_Om" #, fuzzy #~ msgid "Configuration was unchanged, no need to save.\n" #~ msgstr "" #~ "Konfiguration eller version av GNUnet ändrad. Du behöver köra \"%s\"!\n" #~ msgid "Can't create service" #~ msgstr "Kan inte skapa tjänst" #~ msgid "Error changing the permissions of the GNUnet directory" #~ msgstr "Fel vid ändring av rättigheterna pÃ¥ GNUnet-katalogen" #, fuzzy #~ msgid "Cannot write to the registry" #~ msgstr "Kan inte skriva till registret" #~ msgid "Can't delete the service" #~ msgstr "Kan inte ta bort tjänsten" #~ msgid "This version of Windows does not support multiple users." #~ msgstr "Denna version för Windows har inte stöd för flera användare." #~ msgid "Error accessing local security policy" #~ msgstr "Fel vid Ã¥tkomst av lokal säkerhetspolicy" #~ msgid "Unknown error while creating a new user" #~ msgstr "Okänt fel vid skapandet av ny användare" #~ msgid "FATAL" #~ msgstr "ÖDESDIGER" #~ msgid "NOTHING" #~ msgstr "INGET" #, fuzzy #~ msgid "Syntax error in configuration entry HOST in section NETWORK: `%s'\n" #~ msgstr "Syntaxfel i konfigurationsfil \"%s\" pÃ¥ rad %d.\n" #, fuzzy #~ msgid "Reading result from gnunetd failed, reply invalid!\n" #~ msgstr "\"%s\" misslyckades, svar ogiltigt!\n" #, fuzzy #~ msgid "No interface specified in section `%s' under `%s'!\n" #~ msgstr "" #~ "Inga nätverksgränssnitt angivna i konfigurationssektionen \"%s\" under " #~ "\"%s\"!\n" #, fuzzy #~ msgid "`%s' returned with error code %u" #~ msgstr "\"%s\" misslyckades vid %s:%d med fel: %s\n" #~ msgid "Can't create semaphore: %i" #~ msgstr "Kan inte skapa semafor: %i" #~ msgid "Cannot query the CPU usage (Windows NT).\n" #~ msgstr "Kan inte frÃ¥ga efter CPU-användning (Windows NT).\n" #~ msgid "Cannot query the CPU usage (Win 9x)\n" #~ msgstr "Kan inte frÃ¥ga efter CPU-användning (Win 9x).\n" #~ msgid "" #~ "No network interfaces defined in configuration section `%s' under `%s'!\n" #~ msgstr "" #~ "Inga nätverksgränssnitt angivna i konfigurationssektionen \"%s\" under " #~ "\"%s\"!\n" #, fuzzy #~ msgid "Command `%s' failed with error code %u\n" #~ msgstr "\"%s\" misslyckades vid %s:%d med fel: %s\n" #, fuzzy #~ msgid "Real-time delay violation (%llu ms) at %s:%u\n" #~ msgstr "Icke-förväntad mycket stor allokering (%u byte) vid %s:%d!\n" #, fuzzy #~ msgid "`%s' failed with error code %d: %s\n" #~ msgstr "\"%s\" misslyckades vid %s:%d med fel: %s\n" #, fuzzy #~ msgid "GNUnet error log" #~ msgstr "SpÃ¥ra GNUnets nätverkstopologi." #~ msgid "Availability test failed for `%s' at %s:%d.\n" #~ msgstr "Tillgänglighetstest misslyckades för \"%s\" vid %s:%d.\n" #, fuzzy #~ msgid "Starting datastore conversion (this may take a while).\n" #~ msgstr "Skapar ny värdnyckel (det här kan ta en stund).\n" #, fuzzy #~ msgid "" #~ "%s:%d - RPC %s:%p could not be registered: another callback is already " #~ "using this name (%p)\n" #~ msgstr "%s::%s - RPC %s:%p kunde inte avregistreras: hittades inte\n" #, fuzzy #~ msgid "%s:%d - async RPC %s:%p could not be unregistered: not found\n" #~ msgstr "%s::%s - RPC %s:%p kunde inte avregistreras: hittades inte\n" #~ msgid "`%s' registering handlers %d %d %d\n" #~ msgstr "\"%s\" registrerar handtag %d %d %d\n" #~ msgid "output in gnuplot format" #~ msgstr "utdata i gnuplot-format" #~ msgid "number of iterations" #~ msgstr "antal iterationer" #~ msgid "number of messages to use per iteration" #~ msgstr "antal meddelanden att använda per iteration" #~ msgid "message size" #~ msgstr "meddelandestorlek" #~ msgid "number of messages in a message block" #~ msgstr "antal meddelanden i ett meddelandeblock" #~ msgid "You must specify a receiver!\n" #~ msgstr "Du mÃ¥ste ange en mottagare!\n" #~ msgid "Time:\n" #~ msgstr "Tid:\n" #~ msgid "\tmax %llums\n" #~ msgstr "\tmax %llums\n" #~ msgid "\tmin %llums\n" #~ msgstr "\tmin %llums\n" #~ msgid "\tmax %u\n" #~ msgstr "\tmax %u\n" #~ msgid "\tmin %u\n" #~ msgstr "\tmin %u\n" #~ msgid "Output format not known, this should not happen.\n" #~ msgstr "Utdataformat är inte känt, detta bör inte hända.\n" #, fuzzy #~ msgid "# bytes received in plaintext of type %d" #~ msgstr "# byte mottagna av typen %d" #, fuzzy #~ msgid "use PRIORITY for the priority of the trace request" #~ msgstr "ange prioritet för innehÃ¥llet" #~ msgid "allows mapping of the network topology" #~ msgstr "tillÃ¥ter kartläggning av nätverkstopologin" #, fuzzy #~ msgid "HELLO message from `%s' has an invalid signature. Dropping.\n" #~ msgstr "Meddelande frÃ¥n \"%s\" kastades bort: ogiltigt format.\n" #~ msgid "`%s' registering handler %d (plaintext and ciphertext)\n" #~ msgstr "\"%s\" registrerar handtag %d (klartext och kryptotext)\n" #~ msgid "`%s' registering handler %d\n" #~ msgstr "\"%s\" registrerar handtag %d\n" #, fuzzy #~ msgid "`%s' registering CS handlers %d and %d\n" #~ msgstr "\"%s\" registrerar handtagen %d och %d\n" #~ msgid "enables P2P-chat (incomplete)" #~ msgstr "aktiverar P2P-chatt (ej komplett)" #, fuzzy #~ msgid "Existing key in file `%s' failed format check, creating new key.\n" #~ msgstr "" #~ "Existerande värdnyckel i filen \"%s\" felade vid formatkontroll, skapar " #~ "en ny värdnyckel.\n" #, fuzzy #~ msgid "Creating new key for this nickname (this may take a while).\n" #~ msgstr "Skapar ny värdnyckel (det här kan ta en stund).\n" #, fuzzy #~ msgid "allow TIME ms to process a GET command" #~ msgstr "tillÃ¥t TID ms för behandling av varje kommando" #, fuzzy #~ msgid "Issuing `%s(%s,%s)' command.\n" #~ msgstr "\"%s(%s,%s)\" misslyckades.\n" #~ msgid "Command `%s' requires an argument (`%s').\n" #~ msgstr "Kommando \"%s\" kräver ett argument (\"%s\").\n" #~ msgid "Command `%s' requires two arguments (`%s' and `%s').\n" #~ msgstr "Kommando \"%s\" kräver tvÃ¥ argument (\"%s\" och \"%s\").\n" #, fuzzy #~ msgid "# dht discovery messages sent" #~ msgstr "# krypterade PONG-meddelanden skickade" #, fuzzy #~ msgid "`%s' registering p2p handlers: %d %d %d\n" #~ msgstr "\"%s\" registrerar handtag %d %d %d\n" #~ msgid "`%s' failed. Terminating connection to client.\n" #~ msgstr "\"%s\" misslyckades. Terminerar anslutning till klient.\n" #, fuzzy #~ msgid "`%s' registering client handlers: %d %d\n" #~ msgstr "\"%s\" registrerar klienthandtag %d\n" #~ msgid "" #~ "Existing hostkey in file `%s' failed format check, creating new hostkey.\n" #~ msgstr "" #~ "Existerande värdnyckel i filen \"%s\" felade vid formatkontroll, skapar " #~ "en ny värdnyckel.\n" #~ msgid "Done creating hostkey.\n" #~ msgstr "Klar med skapandet av värdnyckel.\n" #~ msgid "Cannot create PING, table full. Try increasing MAX_PING_PONG.\n" #~ msgstr "" #~ "Kan inte skapa PING, tabell är full. Försök att öka MAX_PING_PONG.\n" #~ msgid "# plaintext PONG messages received" #~ msgstr "# klartext PONG-meddelanden mottagna" #~ msgid "# encrypted PING messages received" #~ msgstr "# krypterade PING-meddelanden mottagna" #~ msgid "# encrypted PING messages sent" #~ msgstr "# krypterade PING-meddelanden skickade" #~ msgid "`%s' registering handlers %d %d (plaintext and ciphertext)\n" #~ msgstr "\"%s\" registrerar handtag %d %d (klartext och kryptotext)\n" #, fuzzy #~ msgid "Cannot encrypt sessionkey, peer `%s' not known!\n" #~ msgstr "Kan inte kryptera sessionsnyckel, andra parten är inte känd!\n" #, fuzzy #~ msgid "" #~ "Session key received from peer `%s' has invalid format (discarded).\n" #~ msgstr "Meddelande mottaget frÃ¥n motpart är ogiltig.\n" #~ msgid "# sessions established" #~ msgstr "# sessioner etablerade" #~ msgid "create a new pseudonym under the given NICKNAME" #~ msgstr "skapa en ny pseudonym under angivet SMEKNAMN" #~ msgid "delete the pseudonym with the given NICKNAME" #~ msgstr "ta bort pseudonymen med angivet SMEKNAMN" #~ msgid "" #~ "Create new pseudonyms, delete pseudonyms or list existing pseudonyms." #~ msgstr "" #~ "Skapa nya pseudonymer, ta bort pseudonymer eller lista existerande " #~ "pseudonymer." #~ msgid "Collection stopped.\n" #~ msgstr "Samling stoppad.\n" #~ msgid "Failed to stop collection (not active?).\n" #~ msgstr "Misslyckades att stoppa samling (inte aktiv?).\n" #~ msgid "Pseudonym `%s' deleted.\n" #~ msgstr "Pseudonym \"%s\" togs bort.\n" #~ msgid "Error deleting pseudonym `%s' (does not exist?).\n" #~ msgstr "Fel vid borttagning av pseudonym \"%s\" (existerar den?).\n" #, fuzzy #~ msgid "Started collection.\n" #~ msgstr "Startade samling \"%s\".\n" #, fuzzy #~ msgid "You must specify a name for the collection (`%s' option).\n" #~ msgstr "" #~ "Du mÃ¥ste ange ett namn för PID-filen i sektion \"%s\" under \"%s\".\n" #~ msgid "%d files found in directory.\n" #~ msgstr "%d filer hittades i katalog.\n" #~ msgid "Perform directory related operations." #~ msgstr "Genomför katalogrelaterade operationer." #~ msgid "Listed %d matching entries.\n" #~ msgstr "Listade %d matchande poster.\n" #, fuzzy #~ msgid "Upload of `%s' at %llu out of %llu bytes.\n" #~ msgstr "Hämtning av fil \"%s\" vid %16llu av %16llu byte (%8.3f kbps)\n" #, fuzzy #~ msgid "Upload aborted.\n" #~ msgstr "Nedladdning avbruten." #, fuzzy #~ msgid "Uploading suspended.\n" #~ msgstr "Uppladdning misslyckades.\n" #, fuzzy #~ msgid "" #~ "do not use libextractor to add additional references to directory entries " #~ "and/or the published file" #~ msgstr "" #~ "använd libextractor för att lägga till ytterligare direktreferenser till " #~ "katalogposter" #~ msgid "Created entry `%s' in namespace `%s'\n" #~ msgstr "Skapade post \"%s\" i namnrymd \"%s\"\n" #, fuzzy #~ msgid "" #~ "%16llu of %16llu bytes inserted (estimating %6s to completion) - %s\n" #~ msgstr "%16llu av %16llu byte inlagda (uppskattar %s till färdigställd)\n" #, fuzzy #~ msgid "" #~ "Upload of `%s' complete, %llu bytes took %llu seconds (%8.3f KiB/s).\n" #~ msgstr "" #~ "Uppladdning av \"%s\" klar, %llu byte tog %llu sekunder (%8.3f kbps).\n" #, fuzzy #~ msgid "" #~ "\n" #~ "Upload aborted.\n" #~ msgstr "Nedladdning avbruten." #, fuzzy #~ msgid "" #~ "\n" #~ "Error uploading file: %s" #~ msgstr "" #~ "\n" #~ "Fel vid uppladdning av fil: %s\n" #~ msgid "" #~ "even if gnunetd is running on the local machine, force the creation of a " #~ "copy instead of making a link to the GNUnet share directory" #~ msgstr "" #~ "även om gnunetd körs pÃ¥ den lokala maskinen, tvinga fram skapandet av en " #~ "kopia istället för att göra en länk till GNUnets utdelade katalog" #~ msgid "Make files available to GNUnet for sharing." #~ msgstr "Gör filer tillgängliga via utdelning till GNUnet." #~ msgid "Search GNUnet for files." #~ msgstr "Sök GNUnet efter filer." #~ msgid "" #~ "%16llu of %16llu bytes unindexed (estimating %llu seconds to " #~ "completion) " #~ msgstr "" #~ "%16llu av %16llu byte avindexerat (uppskattar %llu sekunder till " #~ "färdigställd) " #, fuzzy #~ msgid "" #~ "\n" #~ "Unindexing of `%s' complete, %llu bytes took %llu seconds (%8.3f KiB/s).\n" #~ msgstr "" #~ "\n" #~ "Avindexering av \"%s\" klar, %llu byte tog %llu sekunder (%8.3f kbps).\n" #, fuzzy #~ msgid "Not enough arguments. You must specify a filename.\n" #~ msgstr "" #~ "Inte tillräckligt med argument. Du mÃ¥ste ange en URI till en GNUnet-fil\n" #~ msgid "`%s' failed. Is `%s' a file?\n" #~ msgstr "\"%s\" misslyckades. Är \"%s\" en fil?\n" #~ msgid "Download files from GNUnet." #~ msgstr "Ladda ner filer frÃ¥n GNUnet." #, fuzzy #~ msgid "Download of file `%s' at %16llu out of %16llu bytes (%8.3f KiB/s)\n" #~ msgstr "Hämtning av fil \"%s\" vid %16llu av %16llu byte (%8.3f kbps)\n" #, fuzzy #~ msgid "Download aborted.\n" #~ msgstr "Nedladdning avbruten." #, fuzzy #~ msgid "Download of file `%s' complete. Speed was %8.3f KiB per second.\n" #~ msgstr "" #~ "Hämtning av fil \"%s\" färdig. Hastigheten var %8.3f kilobyte per " #~ "sekund.\n" #~ msgid "Not enough arguments. You must specify a GNUnet file URI\n" #~ msgstr "" #~ "Inte tillräckligt med argument. Du mÃ¥ste ange en URI till en GNUnet-fil\n" #~ msgid "URI `%s' invalid for gnunet-download.\n" #~ msgstr "URI \"%s\" ogiltig för gnunet-download.\n" #, fuzzy #~ msgid "No filename specified, using `%s' instead (for now).\n" #~ msgstr "Inget tabellnamn angivet, använder \"%s\".\n" #, fuzzy #~ msgid "Downloading %d files from directory `%s'.\n" #~ msgstr "Ladda ner filer frÃ¥n GNUnet." #~ msgid "File stored as `%s'.\n" #~ msgstr "Fil lagrad som \"%s\".\n" #~ msgid "Cannot get size of file `%s'" #~ msgstr "Kan inte hämta storlek pÃ¥ fil \"%s\"" #~ msgid "Initialization for indexing file `%s' failed.\n" #~ msgstr "Initiering av indexering av fil \"%s\" misslyckades.\n" #, fuzzy #~ msgid "Cannot open file `%s': `%s'" #~ msgstr "Kan inte öppna konfigurationsfil \"%s\".\n" #~ msgid "Renaming of file `%s' to `%s' failed: %s\n" #~ msgstr "Namnbyte pÃ¥ fil \"%s\" till \"%s\" misslyckades: %s\n" #~ msgid "Could not rename file `%s' to `%s': file exists\n" #~ msgstr "Kunde inte byta namn pÃ¥ fil \"%s\" till \"%s\": filen existerar\n" #~ msgid "CHK URI not allowed for search.\n" #~ msgstr "CHK URI tillÃ¥ts inte för sökning.\n" #~ msgid "LOC URI not allowed for search.\n" #~ msgstr "LOC URI tillÃ¥ts inte för sökning.\n" #~ msgid "Format of pseudonym `%s' is invalid.\n" #~ msgstr "Formatet pÃ¥ pseudonym \"%s\" är ogiltig.\n" #, fuzzy #~ msgid "Format of file `%s' is invalid, trying to remove.\n" #~ msgstr "Formatet pÃ¥ filen \"%s\" är ogiltig.\n" #~ msgid "" #~ "Decrypted content does not match key. This is either a bug or a " #~ "maliciously inserted file. Download aborted.\n" #~ msgstr "" #~ "Dekrypterat innehÃ¥ll stämmer inte med nyckeln. Det är antingen ett fel " #~ "eller en fil inlagd med onda avsikter. Hämtning avbruten.\n" #, fuzzy #~ msgid "" #~ "`%s' registering client handlers %d %d %d %d %d %d %d %d and P2P handlers " #~ "%d %d\n" #~ msgstr "\"%s\" registrerar klienthandtagen %d och %d\n" #~ msgid "enables (anonymous) file-sharing" #~ msgstr "aktiverar (anonym) fildelning" #, fuzzy #~ msgid "Friend list of %s:%d\n" #~ msgstr "Fel vid %s:%d.\n" #, fuzzy #~ msgid "Waiting for peers to connect" #~ msgstr "Väntar pÃ¥ att motparter ska ansluta (%u iterationer kvar)...\n" #, fuzzy #~ msgid "Bootstrap data obtained from `%s' is invalid.\n" #~ msgstr "Formatet pÃ¥ pseudonym \"%s\" är ogiltig.\n" #~ msgid "`%s' registering client handler %d\n" #~ msgstr "\"%s\" registrerar klienthandtag %d\n" #~ msgid "allows clients to determine gnunetd's configuration" #~ msgstr "tillÃ¥ter klienter att fastställa gnunetds konfiguration" #~ msgid "`%s' registering client handler %d and %d\n" #~ msgstr "\"%s\" registrerar klienthandtagen %d och %d\n" #~ msgid "Uptime (seconds)" #~ msgstr "Upptid (sekunder)" #, fuzzy #~ msgid "`%s' registering client handlers %d %d %d and p2p handler %d\n" #~ msgstr "\"%s\" registrerar klienthandtagen %d och %d\n" #~ msgid "keeps statistics about gnunetd's operation" #~ msgstr "behÃ¥ller statistik om gnunetds operation" #~ msgid "prints supported protocol messages" #~ msgstr "skriver ut stödda protokollmeddelanden" #, fuzzy #~ msgid "Cannot open tunnel device: %s" #~ msgstr "Kan inte öppna konfigurationsfil \"%s\".\n" #, fuzzy #~ msgid "`%s' initialising RFC4913 module %d and %d\n" #~ msgstr "\"%s\" registrerar handtagen %d och %d\n" #, fuzzy #~ msgid "enables IPv6 over GNUnet (incomplete)" #~ msgstr "aktiverar P2P-chatt (ej komplett)" #, fuzzy #~ msgid "Core initialization failed.\n" #~ msgstr " Anslutning misslyckades\n" #~ msgid "Updates GNUnet datastructures after version change." #~ msgstr "Uppdaterar GNUnets datastruktur efter versionsändring." #~ msgid "run as user LOGIN" #~ msgstr "kör som användare LOGIN" #~ msgid "run in client mode (for getting client configuration values)" #~ msgstr "kör i klientläge (för att hämta värden frÃ¥n klientkonfiguration)" #~ msgid "Starts the gnunetd daemon." #~ msgstr "Startar gnunetd-demonen." #, fuzzy #~ msgid "specify username as which gnunetd should run" #~ msgstr "ange värd pÃ¥ vilken gnunetd körs" #~ msgid "Configuration or GNUnet version changed. You need to run `%s'!\n" #~ msgstr "" #~ "Konfiguration eller version av GNUnet ändrad. Du behöver köra \"%s\"!\n" #, fuzzy #~ msgid "Unable to obtain filesystem information for `%s': %u\n" #~ msgstr "Kunde inte spara konfigurationsfil \"%s\":" #, fuzzy #~ msgid "`%s' message invalid (signature invalid).\n" #~ msgstr "\"%s\" misslyckades, svar ogiltigt!\n" #~ msgid "`%s' selected %d out of %d messages (MTU: %d).\n" #~ msgstr "\"%s\" valda %d av %d meddelanden (MTU: %d).\n" #~ msgid "Message details: %u: length %d, priority: %d\n" #~ msgstr "Detaljer om meddelande: %u: längd %d, prioritet: %d\n" #~ msgid "Message from `%s' discarded: invalid format.\n" #~ msgstr "Meddelande frÃ¥n \"%s\" kastades bort: ogiltigt format.\n" #, fuzzy #~ msgid "# total number of messages in send buffers" #~ msgstr "antal meddelanden i ett meddelandeblock" #~ msgid "`%s': Could not send.\n" #~ msgstr "\"%s\": Kunde inte skicka.\n" #~ msgid "`%s': Could not disconnect.\n" #~ msgstr "\"%s\": Kunde inte koppla ned.\n" #, fuzzy #~ msgid "" #~ "`%s' transport OK. It took %ums to transmit %llu messages of %llu bytes " #~ "each.\n" #~ msgstr "" #~ "\"%s\" transport OK. Det tog %ums att överföra %d meddelanden pÃ¥ %d byte " #~ "styck.\n" #, fuzzy #~ msgid " Transport %d is not being tested\n" #~ msgstr " Transport %d ej tillgänglig\n" #~ msgid "" #~ "\n" #~ "Contacting `%s'." #~ msgstr "" #~ "\n" #~ "Kontaktar \"%s\"." #~ msgid " Connection failed (bug?)\n" #~ msgstr " Anslutning misslyckades (fel?)\n" #, fuzzy #~ msgid "OK!\n" #~ msgstr "OK" #~ msgid "send messages with SIZE bytes payload" #~ msgstr "skicka meddelanden med STORLEK bytes nyttolast" #~ msgid "specifies which TRANSPORT should be tested" #~ msgstr "anger vilken TRANSPORT som ska testas" #~ msgid "specifies after how many MS to time-out" #~ msgstr "anger timeout efter antal MS" #~ msgid "Testing transport(s) %s\n" #~ msgstr "Testar transport(er) %s\n" #~ msgid "Available transport(s): %s\n" #~ msgstr "Tillgängliga transport(er): %s\n" #, fuzzy #~ msgid "%s failed for url `%s' and post-data `%s' at %s:%d: `%s'\n" #~ msgstr "\"%s\" misslyckades för fil \"%s\" vid %s:%d med fel: %s\n" #~ msgid "# bytes sent via HTTP" #~ msgstr "# byte skickade via HTTP" #~ msgid "# bytes dropped by HTTP (outgoing)" #~ msgstr "# byte kastade via HTTP (utgÃ¥ende)" #, fuzzy #~ msgid "# HTTP connect calls" #~ msgstr "# av anslutna parter" #~ msgid "specify host on which gnunetd is running" #~ msgstr "ange värd pÃ¥ vilken gnunetd körs" #, fuzzy #~ msgid "No help available." #~ msgstr "\"%s\" är inte tillgänglig." #, fuzzy #~ msgid "Show rarely used options" #~ msgstr "Visa alla alternativ" #, fuzzy #~ msgid "Meta-configuration" #~ msgstr "GNUnet-konfiguration" #, fuzzy #~ msgid "Full pathname of GNUnet HOME directory" #~ msgstr "Filformatsfel (inte en GNUnet-katalog?)\n" #, fuzzy #~ msgid "Run gnunetd as this group." #~ msgstr "Kör gnunet-update" #, fuzzy #~ msgid "General settings" #~ msgstr "Andra inställningar" #, fuzzy #~ msgid "Settings for restricting connections to friends" #~ msgstr "\"%s\" misslyckades. Terminerar anslutning till klient.\n" #, fuzzy #~ msgid "Configuration of the MySQL database" #~ msgstr "Konfigurationsfil \"%s\" skapad.\n" #, fuzzy #~ msgid "Options for anonymous file sharing" #~ msgstr "aktiverar (anonym) fildelning" #, fuzzy #~ msgid "Applications" #~ msgstr "_Alternativ" #, fuzzy #~ msgid "Network interface" #~ msgstr "Nätverksgränssnitt:" #, fuzzy #~ msgid "Network interface to monitor" #~ msgstr "Nätverksgränssnitt:" #, fuzzy #~ msgid "What is the path to the configuration file for gnunetd?" #~ msgstr "skriv ut ett värde frÃ¥n konfigurationsfilen till standard ut" #, fuzzy #~ msgid "General options" #~ msgstr "Visa alla alternativ" #, fuzzy #~ msgid "Options related to gnunet-gtk" #~ msgstr "Ej ansluten till gnunetd." #~ msgid "`%s' failed (%d, %u). Will not send PING.\n" #~ msgstr "\"%s\" misslyckades (%d, %u). Kommer inte skicka PING.\n" #~ msgid "Could not resolve name of HTTP proxy `%s'. Trying without a proxy.\n" #~ msgstr "" #~ "Kunde inte slÃ¥ upp namn för HTTP-proxy \"%s\". Försöker utan proxy.\n" #~ msgid "Maximum number of chat clients reached.\n" #~ msgstr "Maximalt antal chattklienter uppnÃ¥tt.\n" #~ msgid "Now %d of %d chat clients at this node.\n" #~ msgstr "Nu är det %d av %d chattklienter pÃ¥ den här noden.\n" #~ msgid "specify nickname" #~ msgstr "ange smeknamn" #~ msgid "Start GNUnet chat client." #~ msgstr "Starta GNUnets chattklient." #~ msgid "You must specify a nickname (use option `%s').\n" #~ msgstr "Du mÃ¥ste ange ett smeknamn (använd flagga \"%s\").\n" #~ msgid "Database failed to delete `%s'.\n" #~ msgstr "Databas misslyckades att ta bort \"%s\".\n" #~ msgid "`%s' failed: table not found!\n" #~ msgstr "\"%s\" misslyckades: tabell hittades inte!\n" #~ msgid "`%s' failed. Terminating connection to client.\n" #~ msgstr "\"%s\" misslyckades. Terminerar anslutning till klient.\n" #~ msgid "sendAck failed. Terminating connection to client.\n" #~ msgstr "sendAck misslyckades. Terminerar anslutning till klient.\n" #~ msgid "`%s' called with timeout above 1 hour (bug?)\n" #~ msgstr "\"%s\" anropad med timeout över 1 timma (fel?)\n" #~ msgid "Received invalid RPC `%s'.\n" #~ msgstr "Mottog ogiltig RPC \"%s\".\n" #~ msgid "allow SIZE bytes of memory for the local table" #~ msgstr "tillÃ¥t STORLEK byte av minne för lokaltabellen" #~ msgid "Superflous arguments (ignored).\n" #~ msgstr "Onödiga argument (ignorerade).\n" #~ msgid "Call to `%s' with value '%.*s' (%d bytes).\n" #~ msgstr "Anrop till \"%s\" med värde \"%.*s\" (%d byte).\n" #~ msgid "query table called NAME" #~ msgstr "frÃ¥ga tabell kallad NAME" #~ msgid "No commands specified.\n" #~ msgstr "Inga kommandon angivna.\n" #~ msgid "'%s(%s,%s)' succeeded\n" #~ msgstr "\"%s(%s,%s)\" lyckades\n" #~ msgid "Failed to send `%s'. Closing connection.\n" #~ msgstr "Misslyckades att skicka \"%s\". Stänger anslutning.\n" #~ msgid "Received invalid `%s' request (size %d)\n" #~ msgstr "Mottog ogiltig \"%s\" begäran (storlek %d)\n" #~ msgid "Received invalid `%s' request (wrong table)\n" #~ msgstr "Mottog ogiltig \"%s\" begäran (fel tabell)\n" #~ msgid "Received unknown request type %d at %s:%d\n" #~ msgstr "Mottog okänd typ av begäran %d vid %s:%d\n" #~ msgid "gnunetd signaled error in response to `%s' message\n" #~ msgstr "gnunetd signalerade fel i svar till \"%s\" meddelande\n" #~ msgid "Failed to send `%s' message to gnunetd\n" #~ msgstr "Misslyckades att skicka \"%s\" meddelande till gnunetd\n" #~ msgid "Unexpected reply to `%s' operation.\n" #~ msgstr "Oväntat svar till \"%s\" operation.\n" #~ msgid "Waiting for gnunetd to start (%u iterations left)...\n" #~ msgstr "Väntar pÃ¥ att gnunetd ska starta (%u iterationer kvar)...\n" #~ msgid "Write(%d, %p, %d) failed: %s\n" #~ msgstr "Skrivning(%d, %p, %d) misslyckades: %s\n" #~ msgid "Cannot create pseudonym `%s', file `%s' exists.\n" #~ msgstr "Kan inte skapa pseudonym \"%s\", filen \"%s\" existerar.\n" #~ msgid "AND" #~ msgstr "OCH" #~ msgid "Publication interval for periodic publication changed." #~ msgstr "Publiseringsintervall för periodisk publisering har ändrats." #~ msgid "Indexed file disappeared, deleting block for query `%s'\n" #~ msgstr "Indexerad fil försvann, tar bort block för frÃ¥ga \"%s\"\n" #~ msgid "%8u of %8u bytes deleted." #~ msgstr "%8u av %8u byte togs bort." #~ msgid "specify the file to delete from GNUnet (obligatory, file must exist)" #~ msgstr "" #~ "ange filen att ta bort frÃ¥n GNUnet (obligatorisk, filen mÃ¥ste existera)" #~ msgid "" #~ "Remove file from GNUnet. The specified file is not removed\n" #~ "from the filesystem but just from the local GNUnet datastore." #~ msgstr "" #~ "Ta bort fil frÃ¥n GNUnet. Den angivna filen tas inte bort frÃ¥n\n" #~ "filsystemet utan bara frÃ¥n det lokala GNUnet-datalagret." #~ msgid "You must specify a filename (option -f)\n" #~ msgstr "Du mÃ¥ste ange ett filnamn (flagga -f)\n" #~ msgid "gnunet-directory [OPTIONS] [FILENAMES]" #~ msgstr "gnunet-directory [FLAGGOR] [FILNAMN]" #~ msgid "LEVEL" #~ msgstr "NIVÃ…" #~ msgid "FILENAME" #~ msgstr "FILNAMN" #~ msgid "process directories recursively" #~ msgstr "bearbeta kataloger rekursivt" #~ msgid "Only one file or directory can be specified at a time.\n" #~ msgstr "Endast en fil eller katalog kan anges samtidigt.\n" #~ msgid "You must specify a file or directory to upload.\n" #~ msgstr "Du mÃ¥ste ange en fil eller katalog att ladda upp.\n" #~ msgid "Not enough arguments. You must specify a keyword or identifier.\n" #~ msgstr "" #~ "Inte tillräckligt med argument. Du mÃ¥ste ange ett nyckelord eller " #~ "identifierare.\n" #~ msgid "`%s' registering handlers %d %d\n" #~ msgstr "\"%s\" registrerar handtag %d %d\n" #~ msgid "" #~ "Configuration file must specify a directory for GNUnet to store per-peer " #~ "data under %s%s\n" #~ msgstr "" #~ "Konfigurationsfil mÃ¥ste ange en katalog för GNUnet att lagra motpartsdata " #~ "under %s%s\n" #~ msgid "%s `%s' returned no known hosts!\n" #~ msgstr "%s \"%s\" returnerade inga kända värdar!\n" #~ msgid "Template for gnunet-clients." #~ msgstr "Mall för gnunet-clients." #~ msgid "Start GNUnet-testbed helper." #~ msgstr "Starta hjälpprogrammet GNUnet-testbed." #~ msgid "size of `%s' message is wrong. Ignoring.\n" #~ msgstr "storlek pÃ¥ \"%s\" meddelande är fel. Ignorerar.\n" #~ msgid "received invalid `%s' message\n" #~ msgstr "mottog ogiltigt \"%s\" meddelande\n" #~ msgid "'..' is not allowed in file name (%s).\n" #~ msgstr "\"..\" tillÃ¥ts inte i filnamn (%s).\n" #~ msgid "Could not resolve name of HTTP proxy `%s'.\n" #~ msgstr "Kunde inte slÃ¥ upp namn för HTTP-proxy \"%s\".\n" #~ msgid "Failed so send HTTP request `%s' to host `%s': %s\n" #~ msgstr "Misslyckades att skicka HTTP-begäran \"%s\" till värd \"%s\": %s\n" #~ msgid "Peer `%s' did not report back.\n" #~ msgstr "Motpart \"%s\" rapporterade inte tillbaka.\n" #~ msgid "Sorry, no help is available for this option.\n" #~ msgstr "Tyvärr, ingen hjälp är tillgänglig för den här flaggan.\n" #~ msgid "_File" #~ msgstr "_Fil" #~ msgid "_Load" #~ msgstr "_Läs in" #~ msgid "_Save" #~ msgstr "_Spara" #~ msgid "Save the config in .config" #~ msgstr "Spara konfigurationen i .config" #~ msgid "_Quit" #~ msgstr "_Avsluta" #~ msgid "Show _name" #~ msgstr "Visa _namn" #~ msgid "Show _range" #~ msgstr "Visa _omfÃ¥ng" #~ msgid "Show range (Y/M/N)" #~ msgstr "Visa omfÃ¥ng (Y/M/N)" #~ msgid "Show _data" #~ msgstr "Visa _data" #~ msgid "Show value of the option" #~ msgstr "Visa värde av alternativet" #~ msgid "Show all _options" #~ msgstr "Visa alla a_lternativ" #~ msgid "_Help" #~ msgstr "_Hjälp" #~ msgid "_Introduction" #~ msgstr "_Introduktion" #~ msgid "_License" #~ msgstr "_Licens" #~ msgid "Goes up of one level (single view)" #~ msgstr "GÃ¥r upp en nivÃ¥ (enkel vy)" #~ msgid "Load" #~ msgstr "Läs in" #~ msgid "Save a config file" #~ msgstr "Spara en konfigurationsfil" #~ msgid "Save" #~ msgstr "Spara" #~ msgid "Single view" #~ msgstr "Enkel vy" #~ msgid "Single" #~ msgstr "Enkel" #~ msgid "Split view" #~ msgstr "Dela vy" #~ msgid "Split" #~ msgstr "Dela" #~ msgid "Full view" #~ msgstr "Full vy" #~ msgid "Full" #~ msgstr "Full" #~ msgid "Collapse" #~ msgstr "Fäll in" #~ msgid "Expand" #~ msgstr "Expandera" #~ msgid "Sorry, no help available for this option yet." #~ msgstr "Tyvärr, ingen hjälp tillgänglig för den här flaggan ännu." #~ msgid "Couldn't find pixmap file: %s" #~ msgstr "Kunde inte htta bildfil: %s" #~ msgid "Available MODEs:\n" #~ msgstr "Tillgängliga lägen:\n" #~ msgid " config\t\ttext-based configuration\n" #~ msgstr " config\t\ttextbaserad konfiguration\n" #~ msgid " menuconfig\ttext-based menu\n" #~ msgstr " menuconfig\ttextbaserad meny\n" #~ msgid " wizard-curses\tBasic text-based graphical configuration\n" #~ msgstr " wizard-curses\tEnkel textbaserad grafisk konfiguration\n" #~ msgid "" #~ " wizard-gtk\tBasic GTK configuration\n" #~ "\n" #~ msgstr "" #~ " wizard-gtk\tEnkel GTK-konfiguration\n" #~ "\n" #~ msgid "gnunet-setup must have write-access to the configuration file `%s'\n" #~ msgstr "" #~ "gnunet-setup mÃ¥ste ha skrivrättighet till konfigurationsfilen \"%s\"\n" #~ msgid "" #~ "Can only run wizard to configure gnunetd.\n" #~ "Did you forget the `%s' option?\n" #~ msgstr "" #~ "Kan endast köra vägvisaren för att konfigurera gnunetd.\n" #~ "Glömde du flaggan \"%s\"?\n" #~ msgid "" #~ "You can limit GNUnet's resource usage here.\n" #~ "\n" #~ "This is the percentage of processor time GNUnet is allowed to use." #~ msgstr "" #~ "Du kan begränsa GNUnets resursanvändning här.\n" #~ "\n" #~ "Det här är det procenttal som GNUnet tillÃ¥ts använda av processortiden." #~ msgid "" #~ "Welcome to GNUnet!\n" #~ "\n" #~ "This assistant will ask you a few basic questions in order to configure " #~ "GNUnet.\n" #~ "\n" #~ "Please visit our homepage at\n" #~ "\thttp://www.gnunet.org\n" #~ "and join our community at\n" #~ "\thttp://www.gnunet.org/drupal/\n" #~ "\n" #~ "Have a lot of fun,\n" #~ "\n" #~ "the GNUnet team" #~ msgstr "" #~ "Välkommen till GNUnet!\n" #~ "\n" #~ "Denna assistant kommer att frÃ¥ga dig nÃ¥gra enkla frÃ¥gor för att " #~ "konfigurera GNUnet.\n" #~ "\n" #~ "Besök pÃ¥ webbplats pÃ¥\n" #~ "\thttp://gnunet.org/\n" #~ "och gÃ¥ med i vÃ¥r gemenskap pÃ¥\n" #~ "\thttp://www.gnunet.org/drupal/\n" #~ "\n" #~ "Ha det sÃ¥ kul,\n" #~ "\n" #~ "GNUnet-laget" #~ msgid "Next" #~ msgstr "Nästa" #~ msgid "IP-Address/Hostname:" #~ msgstr "IP-adress/Värdnamn:" #~ msgid "Bandwidth limitation" #~ msgstr "Bandbreddsbegränsning" #~ msgid "Bandwidth sharing" #~ msgstr "Bandbreddsdelning" #~ msgid "Max. CPU usage (%):" #~ msgstr "Max. CPU-användning (%):" #~ msgid "CPU usage" #~ msgstr "CPU-användning" #~ msgid "Finish" #~ msgstr "Slutför" #~ msgid "Question" #~ msgstr "FrÃ¥ga" #~ msgid "Group:" #~ msgstr "Grupp:" #~ msgid "User account:" #~ msgstr "Användarkonto:" #~ msgid "gnunet-update failed!" #~ msgstr "gnunet-update misslyckades!" #~ msgid "You must specify a non-empty set of transports to test!\n" #~ msgstr "Du mÃ¥ste ange en icke-tom uppsättning av transporter att testa!\n" #~ msgid "" #~ "\n" #~ "Exiting.\n" #~ msgstr "" #~ "\n" #~ "Avslutar.\n" #~ msgid "Updated data for %d applications.\n" #~ msgstr "Uppdaterade data för %d program.\n" #~ msgid "`%s' starting\n" #~ msgstr "\"%s\" startar\n" #~ msgid "Argument %d: `%s'\n" #~ msgstr "Argument %d: \"%s\"\n" #~ msgid "%s: Rejected connection from blacklisted address %u.%u.%u.%u.\n" #~ msgstr "%s: Vägrade anslutning frÃ¥n svartlistad adress %u.%u.%u.%u.\n" #~ msgid "HTTP: Could not determine my public IP address.\n" #~ msgstr "HTTP: Kunde inte fastställa min publika IP-adress.\n" #~ msgid "Could not resolve name of SMTP server `%s': %s" #~ msgstr "Kunde inte slÃ¥ upp namnet för SMTP-server \"%s\": %s" #~ msgid "" #~ "You must specify the name of a pipe for the SMTP transport in section `" #~ "%s' under `%s'.\n" #~ msgstr "" #~ "Du mÃ¥ste ange ett namn pÃ¥ röret för SMTP-transporten i sektion \"%s\" " #~ "under \"%s\".\n" #~ msgid "Sending E-mail to `%s' failed.\n" #~ msgstr "Sändning av e-post till \"%s\" misslyckades.\n" #~ msgid "%.*s filter %s (SMTP)" #~ msgstr "%.*s filter %s (SMTP)" #~ msgid "`%s': unknown service: %s\n" #~ msgstr "\"%s\": okänd tjänst: %s\n" #~ msgid "Configuration file `%s' not found. Run gnunet-setup!\n" #~ msgstr "Konfigurationsfil \"%s\" hittades inte. Kör gnunet-setup!\n" #~ msgid "" #~ "Configuration file not found. Please run GNUnet Setup (Client " #~ "Configuration) first." #~ msgstr "" #~ "Konfigurationsfil hittades inte. Vänligen kör konfigurationen för GNUnet " #~ "(klientkonfiguration) först." #~ msgid "Cron stopped\n" #~ msgstr "Cron stoppad\n" #~ msgid "Caught signal %d.\n" #~ msgstr "FÃ¥ngade signal %d.\n" #~ msgid "Invalid network notation (additional characters: `%s')." #~ msgstr "Ogiltig nätverksnotation (ytterligare tecken: \"%s\")." #~ msgid "FAILURE" #~ msgstr "MISSLYCKANDE" #~ msgid "MESSAGE" #~ msgstr "MEDDELANDE" #~ msgid "CRON" #~ msgstr "CRON" #~ msgid "EVERYTHING" #~ msgstr "ALLT" #~ msgid "Invalid LOGLEVEL `%s' specified.\n" #~ msgstr "Ogiltig LOGGNIVÃ… \"%s\" angiven.\n" #~ msgid "" #~ "Usage: %s\n" #~ "%s\n" #~ "\n" #~ msgstr "" #~ "Användning: %s\n" #~ "%s\n" #~ "\n" #~ msgid "" #~ "Configuration file must specify a directory for GNUnet to store per-peer " #~ "data under %s\\%s.\n" #~ msgstr "" #~ "Konfigurationsfil mÃ¥ste ange en katalog för GNUnet att lagra motpartsdata " #~ "under %s\\%s.\n" #~ msgid "g" #~ msgstr "g" #~ msgid "t" #~ msgstr "t" #~ msgid "`%s' failed, other side closed connection.\n" #~ msgstr "\"%s\" misslyckades, andra sidan har stängt anslutningen.\n" #~ msgid "Attempted path to `%s' was `%s'.\n" #~ msgstr "Försökt sökväg till \"%s\" var \"%s\".\n" #~ msgid "set verbosity to LEVEL" #~ msgstr "sätt informationsnivÃ¥ till NIVÃ…" gnunet-0.9.3/po/vi.po0000644000175000017500000120513111763406751011355 00000000000000# Vietnamese translation for GNUnet. # Copyright © 2008 Christian Grothoff (msgids). # This file is distributed under the same license as the gnunet package. # Phan Vinh Thinh , 2005. # Clytie Siddall , 2008. # msgid "" msgstr "" "Project-Id-Version: gnunet 0.8.0a\n" "Report-Msgid-Bugs-To: gnunet-developers@mail.gnu.org\n" "POT-Creation-Date: 2012-06-05 15:47+0200\n" "PO-Revision-Date: 2008-09-10 22:05+0930\n" "Last-Translator: Clytie Siddall \n" "Language-Team: Vietnamese \n" "Language: vi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: LocFactoryEditor 1.7b3\n" #: src/arm/arm_api.c:165 msgid "Failed to transmit shutdown request to client.\n" msgstr "" #: src/arm/arm_api.c:349 #, fuzzy, c-format msgid "Configuration failes to specify option `%s' in section `%s'!\n" msgstr "" "Cấu hình không thá»a mãn các ràng buá»™c cá»§a tập tin đặc tả cấu hình « %s ».\n" #: src/arm/arm_api.c:363 #, fuzzy, c-format msgid "Configuration fails to specify option `%s' in section `%s'!\n" msgstr "" "Cấu hình không thá»a mãn các ràng buá»™c cá»§a tập tin đặc tả cấu hình « %s ».\n" #: src/arm/arm_api.c:432 #, c-format msgid "Error receiving response to `%s' request from ARM for service `%s'\n" msgstr "" #: src/arm/arm_api.c:485 #, c-format msgid "Requesting start of service `%s'.\n" msgstr "" #: src/arm/arm_api.c:486 #, c-format msgid "Requesting termination of service `%s'.\n" msgstr "" #: src/arm/arm_api.c:507 #, c-format msgid "Error while trying to transmit request to start `%s' to ARM\n" msgstr "" #: src/arm/arm_api.c:508 #, c-format msgid "Error while trying to transmit request to stop `%s' to ARM\n" msgstr "" #: src/arm/arm_api.c:540 #, fuzzy, c-format msgid "Asked to start service `%s' within %llu ms\n" msgstr "« %s »: Chưa nhận thông báo sau %llu miligiây.\n" #: src/arm/arm_api.c:612 #, c-format msgid "Stopping service `%s' within %llu ms\n" msgstr "" #: src/arm/gnunet-arm.c:159 #, fuzzy, c-format msgid "Service `%s' is unknown to ARM.\n" msgstr "Không gian tên « %s » có đánh giá %d.\n" #: src/arm/gnunet-arm.c:164 #, fuzzy, c-format msgid "Service `%s' has been stopped.\n" msgstr "Dịch vụ đã bị xoá.\n" #: src/arm/gnunet-arm.c:167 #, fuzzy, c-format msgid "Service `%s' was already running.\n" msgstr "Không gian tên « %s » có đánh giá %d.\n" #: src/arm/gnunet-arm.c:172 #, fuzzy, c-format msgid "Service `%s' has been started.\n" msgstr "Dịch vụ đã bị xoá.\n" #: src/arm/gnunet-arm.c:175 #, fuzzy, c-format msgid "Service `%s' was already being stopped.\n" msgstr "Dịch vụ đã bị xoá.\n" #: src/arm/gnunet-arm.c:179 #, fuzzy, c-format msgid "Service `%s' was already not running.\n" msgstr "« %s » không phải là má»™t tập tin.\n" #: src/arm/gnunet-arm.c:183 #, fuzzy msgid "Request ignored as ARM is shutting down.\n" msgstr "« %s » Ä‘ang tắt.\n" #: src/arm/gnunet-arm.c:187 #, fuzzy msgid "Error communicating with ARM service.\n" msgstr "Cổng để liên lạc vá»›i giao diện ngưá»i dùng GNUnet" #: src/arm/gnunet-arm.c:191 #, fuzzy msgid "Timeout communicating with ARM service.\n" msgstr "Cổng để liên lạc vá»›i giao diện ngưá»i dùng GNUnet" #: src/arm/gnunet-arm.c:195 #, fuzzy msgid "Operation failed.\n" msgstr "Lá»—i ná»™i bá»™ : khẳng định không thành công tại %s:%d.\n" #: src/arm/gnunet-arm.c:199 msgid "Unknown response code from ARM.\n" msgstr "" #: src/arm/gnunet-arm.c:222 #, fuzzy msgid "Error communicating with ARM. ARM not running?\n" msgstr "Cổng để liên lạc vá»›i giao diện ngưá»i dùng GNUnet" #: src/arm/gnunet-arm.c:225 #, fuzzy msgid "Running services:\n" msgstr "Äang nạp và khởi động dùng « %s ».\n" #: src/arm/gnunet-arm.c:249 #, c-format msgid "Fatal configuration error: `%s' option in section `%s' missing.\n" msgstr "" #: src/arm/gnunet-arm.c:257 src/arm/gnunet-arm.c:357 src/arm/gnunet-arm.c:373 msgid "Fatal error initializing ARM API.\n" msgstr "" #: src/arm/gnunet-arm.c:280 #, fuzzy, c-format msgid "Failed to remove configuration file %s\n" msgstr "Không thể lưu tập tin cấu hình « %s »:" #: src/arm/gnunet-arm.c:286 #, fuzzy, c-format msgid "Failed to remove servicehome directory %s\n" msgstr "Lá»—i truy cập đến thư mục nhà GNUnet « %s »\n" #: src/arm/gnunet-arm.c:407 #, fuzzy msgid "stop all GNUnet services" msgstr "há»§y cài đặt dịch vụ GNUnet" #: src/arm/gnunet-arm.c:409 msgid "start a particular service" msgstr "" #: src/arm/gnunet-arm.c:411 msgid "stop a particular service" msgstr "" #: src/arm/gnunet-arm.c:413 #, fuzzy msgid "start all GNUnet default services" msgstr "há»§y cài đặt dịch vụ GNUnet" #: src/arm/gnunet-arm.c:416 #, fuzzy msgid "stop and start all GNUnet default services" msgstr "há»§y cài đặt dịch vụ GNUnet" #: src/arm/gnunet-arm.c:419 msgid "delete config file and directory on exit" msgstr "" #: src/arm/gnunet-arm.c:421 msgid "don't print status messages" msgstr "" #: src/arm/gnunet-arm.c:424 #, fuzzy msgid "timeout for completing current operation" msgstr "thá»i gian chá» sá»± hoàn thành cá»§a má»™t lần lặp (theo miligiây)" #: src/arm/gnunet-arm.c:426 msgid "List currently running services" msgstr "" #: src/arm/gnunet-arm.c:437 msgid "Control services and the Automated Restart Manager (ARM)" msgstr "" #: src/arm/gnunet-service-arm.c:332 #, fuzzy, c-format msgid "Failed to start service `%s'\n" msgstr "Lá»—i bắt đầu thu thập.\n" #: src/arm/gnunet-service-arm.c:335 #, fuzzy, c-format msgid "Starting service `%s'\n" msgstr "Äang bắt đầu tài vỠ« %s »\n" #: src/arm/gnunet-service-arm.c:361 msgid "Could not send status result to client\n" msgstr "" #: src/arm/gnunet-service-arm.c:393 #, fuzzy msgid "Could not send list result to client\n" msgstr "Không thể Ä‘á»c danh sách bạn bè « %s »\n" #: src/arm/gnunet-service-arm.c:523 #, fuzzy, c-format msgid "Unable to create socket for service `%s': %s\n" msgstr "Không thể tạo tài khoản ngưá»i dùng:" #: src/arm/gnunet-service-arm.c:545 #, c-format msgid "Unable to bind listening socket for service `%s' to address `%s': %s\n" msgstr "" #: src/arm/gnunet-service-arm.c:559 #, c-format msgid "ARM now monitors connections to service `%s' at `%s'\n" msgstr "" #: src/arm/gnunet-service-arm.c:667 #, fuzzy, c-format msgid "Preparing to stop `%s'\n" msgstr "Äang bắt đầu tài lên « %s ».\n" #: src/arm/gnunet-service-arm.c:878 #, fuzzy, c-format msgid "Restarting service `%s'.\n" msgstr "Äang nạp và khởi động dùng « %s ».\n" #: src/arm/gnunet-service-arm.c:970 msgid "exit" msgstr "" #: src/arm/gnunet-service-arm.c:975 msgid "signal" msgstr "" #: src/arm/gnunet-service-arm.c:980 #, fuzzy msgid "unknown" msgstr "Lá»—i không rõ" #: src/arm/gnunet-service-arm.c:986 #, fuzzy, c-format msgid "Service `%s' took %llu ms to terminate\n" msgstr "Dịch vụ đã bị xoá.\n" #: src/arm/gnunet-service-arm.c:1021 #, c-format msgid "Service `%s' terminated with status %s/%d, will restart in %llu ms\n" msgstr "" #: src/arm/gnunet-service-arm.c:1127 #, fuzzy, c-format msgid "Configuration file `%s' for service `%s' not valid: %s\n" msgstr "Tập tin cấu hình « %s » đã được ghi.\n" #: src/arm/gnunet-service-arm.c:1129 msgid "option missing" msgstr "" #: src/arm/gnunet-service-arm.c:1213 #, fuzzy, c-format msgid "Starting default services `%s'\n" msgstr "Äang bắt đầu tài vỠ« %s »\n" #: src/arm/gnunet-service-arm.c:1224 #, c-format msgid "Default service `%s' not configured correctly!\n" msgstr "" #: src/arm/gnunet-service-arm.c:1238 msgid "" "No default services configured, GNUnet will not really start right now.\n" msgstr "" #: src/arm/mockup-service.c:44 msgid "Initiating shutdown as requested by client.\n" msgstr "" #: src/block/block.c:105 #, fuzzy, c-format msgid "Loading block plugin `%s'\n" msgstr "Äang nạp các truyá»n tải « %s »\n" #: src/chat/chat.c:175 #, fuzzy msgid "Could not transmit confirmation receipt\n" msgstr "Không thể truy cập đến thông tin vá» không gian tên.\n" #: src/chat/chat.c:283 msgid "The current user must be the the first one joined\n" msgstr "" #: src/chat/chat.c:412 #, fuzzy, c-format msgid "Unknown message type: '%u'\n" msgstr "\tKhông rõ miá»n tên « %s »\n" #: src/chat/chat.c:472 #, fuzzy, c-format msgid "Configuration option `%s' in section `%s' missing\n" msgstr "Giá trị cấu hình « %s » cho « %s » trong phần « %s » nên là con số\n" #: src/chat/chat.c:480 #, fuzzy, c-format msgid "Failed to access chat home directory `%s'\n" msgstr "Lá»—i truy cập đến thư mục nhà GNUnet « %s »\n" #: src/chat/chat.c:498 #, fuzzy, c-format msgid "Failed to create/open key in file `%s'\n" msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" #: src/chat/chat.c:559 #, fuzzy msgid "Could not serialize metadata\n" msgstr "Không thể tạo miá»n tên.\n" #: src/chat/chat.c:674 #, fuzzy msgid "Failed to connect to the chat service\n" msgstr "Lá»—i kết nối đến gnunetd.\n" #: src/chat/chat.c:680 msgid "Undefined mandatory parameter: joinCallback\n" msgstr "" #: src/chat/chat.c:686 msgid "Undefined mandatory parameter: messageCallback\n" msgstr "" #: src/chat/chat.c:692 msgid "Undefined mandatory parameter: memberCallback\n" msgstr "" #: src/chat/gnunet-chat.c:93 msgid "Joined\n" msgstr "" #: src/chat/gnunet-chat.c:125 src/chat/gnunet-chat.c:133 #: src/chat/gnunet-chat.c:213 src/chat/gnunet-chat.c:253 #: src/chat/gnunet-chat.c:329 src/chat/gnunet-chat.c:371 #: src/chat/gnunet-chat.c:400 src/chat/gnunet-chat.c:700 msgid "anonymous" msgstr "nặc danh" #: src/chat/gnunet-chat.c:144 #, fuzzy, c-format msgid "(%s) `%s' said: %s\n" msgstr "« %s » nói: %s\n" #: src/chat/gnunet-chat.c:147 src/chat/gnunet-chat.c:150 #, fuzzy, c-format msgid "(%s) `%s' said to you: %s\n" msgstr "« %s » nói cho bạn: %s\n" #: src/chat/gnunet-chat.c:153 #, fuzzy, c-format msgid "(%s) `%s' said for sure: %s\n" msgstr "« %s » nói thật: %s\n" #: src/chat/gnunet-chat.c:156 #, fuzzy, c-format msgid "(%s) `%s' said to you for sure: %s\n" msgstr "« %s » nói thật cho bạn: %s\n" #: src/chat/gnunet-chat.c:159 #, fuzzy, c-format msgid "(%s) `%s' was confirmed that you received: %s\n" msgstr "« %s » xác nhận bạn đã nhận được: %s\n" #: src/chat/gnunet-chat.c:162 #, fuzzy, c-format msgid "(%s) `%s' was confirmed that you and only you received: %s\n" msgstr "« %s » xác nhận mà chỉ bạn đã nhận được: %s\n" #: src/chat/gnunet-chat.c:165 #, fuzzy, c-format msgid "(%s) `%s' was confirmed that you received from him or her: %s\n" msgstr "« %s » xác nhận mà bạn đã nhận được từ há» : %s\n" #: src/chat/gnunet-chat.c:170 #, fuzzy, c-format msgid "" "(%s) `%s' was confirmed that you and only you received from him or her: %s\n" msgstr "« %s » xác nhận mà chỉ bạn Ä‘a nhận được từ há» : %s\n" #: src/chat/gnunet-chat.c:173 #, fuzzy, c-format msgid "(%s) `%s' said off the record: %s\n" msgstr "« %s » nói không chính thức: %s\n" #: src/chat/gnunet-chat.c:176 #, fuzzy, c-format msgid "(%s) <%s> said using an unknown message type: %s\n" msgstr "<%s> đã nói bằng má»™t kiểu tin nhẳn không rõ : %s\n" #: src/chat/gnunet-chat.c:217 #, c-format msgid "'%s' acknowledged message #%d\n" msgstr "" #: src/chat/gnunet-chat.c:260 #, c-format msgid "`%s' entered the room\n" msgstr "« %s » vào phòng\n" #: src/chat/gnunet-chat.c:260 #, c-format msgid "`%s' left the room\n" msgstr "« %s » rá»i phòng\n" #: src/chat/gnunet-chat.c:321 src/chat/gnunet-chat.c:363 #, fuzzy msgid "Could not change username\n" msgstr "Không thể tạo miá»n tên.\n" #: src/chat/gnunet-chat.c:334 src/chat/gnunet-chat.c:702 #, fuzzy, c-format msgid "Joining room `%s' as user `%s'...\n" msgstr "Äã vào phòng « %s » là ngưá»i dùng « %s ».\n" #: src/chat/gnunet-chat.c:373 #, fuzzy, c-format msgid "Changed username to `%s'\n" msgstr "Äã thay đổi tên ngưá»i dùng thành « %s ».\n" #: src/chat/gnunet-chat.c:388 #, c-format msgid "Users in room `%s': " msgstr "Ngưá»i dùng trong phòng « %s »:" #: src/chat/gnunet-chat.c:434 msgid "Syntax: /msg USERNAME MESSAGE" msgstr "Cú pháp: /msg TÊN_NGƯỜI_DÙNG TIN_NHẲN" #: src/chat/gnunet-chat.c:443 #, c-format msgid "Unknown user `%s'. Make sure you specify its numeric suffix, if any.\n" msgstr "" #: src/chat/gnunet-chat.c:460 #, c-format msgid "User `%s' is currently not in the room!\n" msgstr "Ngưá»i dùng « %s » hiện thá»i không có trong phòng này.\n" #: src/chat/gnunet-chat.c:513 #, fuzzy, c-format msgid "Unknown command `%s'\n" msgstr "Không rõ câu lệnh « %s ».\n" #: src/chat/gnunet-chat.c:524 msgid "" "Use `/join #roomname' to join a chat room. Joining a room will cause you to " "leave the current room" msgstr "" "Gõ chuá»—i « /join #tên_phòng » để vào má»™t phòng trò chuyện nào đó (việc này " "cÅ©ng gây ra bạn ra khá»i phòng hiện tại)" #: src/chat/gnunet-chat.c:528 msgid "" "Use `/nick nickname' to change your nickname. This will cause you to leave " "the current room and immediately rejoin it with the new name." msgstr "" "Gõ chuá»—i « /nick tên_hiệu » để thay đổi tên hiệu cá»§a mình (việc này cÅ©ng gây " "ra bạn ra khá»i phòng hiện tại, sau đó vào lại ngay vá»›i tên má»›i)" #: src/chat/gnunet-chat.c:532 msgid "" "Use `/msg nickname message' to send a private message to the specified user" msgstr "" "Gõ chuá»—i « /msg tên_hiệu tin_nhẳn » để gá»­i má»™t tin nhẳn riêng cho ngưá»i dùng " "có tên đó" #: src/chat/gnunet-chat.c:535 msgid "The `/notice' command is an alias for `/msg'" msgstr "Lệnh « /notice » là má»™t biệt hiệu cho « /msg »" #: src/chat/gnunet-chat.c:537 msgid "The `/query' command is an alias for `/msg'" msgstr "Lệnh « /query » là má»™t biệt hiệu cho « /msg »" #: src/chat/gnunet-chat.c:539 #, fuzzy msgid "Use `/sig message' to send a signed public message" msgstr "" "Gõ chuá»—i « /msg tên_hiệu tin_nhẳn » để gá»­i má»™t tin nhẳn riêng cho ngưá»i dùng " "có tên đó" #: src/chat/gnunet-chat.c:542 msgid "Use `/ack message' to require signed acknowledgment of the message" msgstr "" #: src/chat/gnunet-chat.c:545 msgid "Use `/anonymous message' to send a public anonymous message" msgstr "" #: src/chat/gnunet-chat.c:547 #, fuzzy msgid "The `/anon' command is an alias for `/anonymous'" msgstr "Lệnh « /notice » là má»™t biệt hiệu cho « /msg »" #: src/chat/gnunet-chat.c:549 msgid "Use `/quit' to terminate gnunet-chat" msgstr "Gõ chuá»—i « /quit » để thoát khá»i trình gnunet-chat" #: src/chat/gnunet-chat.c:551 msgid "The `/leave' command is an alias for `/quit'" msgstr "Lệnh « /leave » là má»™t biệt hiệu cho « /quit »" #: src/chat/gnunet-chat.c:554 msgid "Use `/names' to list all of the current members in the chat room" msgstr "" "Gõ chuá»—i « /names » để liệt kê tất cả các thành viên hiện thá»i trong phòng " "trò chuyện đó" #: src/chat/gnunet-chat.c:556 msgid "Use `/help command' to get help for a specific command" msgstr "Gõ chuá»—i « /help LỆNH » để xem trợ giúp vá» lệnh đó" #: src/chat/gnunet-chat.c:672 msgid "You must specify a nickname\n" msgstr "Phải ghi rõ tên hiệu\n" #: src/chat/gnunet-chat.c:688 #, c-format msgid "Failed to join room `%s'\n" msgstr "Lá»—i vào phòng « %s »\n" #: src/chat/gnunet-chat.c:727 msgid "set the nickname to use (required)" msgstr "đặt tên hiệu cần dùng (cần thiết)" #: src/chat/gnunet-chat.c:730 msgid "set the chat room to join" msgstr "đặt phòng trò chuyện cần vào" #: src/chat/gnunet-chat.c:742 msgid "Join a chat on GNUnet." msgstr "Vào phòng trò chuyện trên GNUnet." #: src/chat/gnunet-service-chat.c:267 #, fuzzy msgid "Failed to queue a message notification\n" msgstr "Lá»—i lưu cấu hình." #: src/chat/gnunet-service-chat.c:546 #, fuzzy msgid "Failed to queue a join notification\n" msgstr "Lá»—i lưu cấu hình." #: src/chat/gnunet-service-chat.c:729 #, fuzzy msgid "Failed to queue a confirmation receipt\n" msgstr "Lá»—i lưu cấu hình." #: src/chat/gnunet-service-chat.c:907 #, fuzzy msgid "Failed to queue a leave notification\n" msgstr "Lá»—i lưu cấu hình." #: src/core/core_api.c:786 msgid "Client was disconnected from core service, trying to reconnect.\n" msgstr "" #: src/core/gnunet-core.c:54 src/peerinfo-tool/gnunet-peerinfo.c:286 #, fuzzy, c-format msgid "Peer `%s'\n" msgstr "Tôi là đồng đẳng « %s ».\n" #: src/core/gnunet-core.c:72 src/peerinfo-tool/gnunet-peerinfo.c:817 #, fuzzy, c-format msgid "Invalid command line argument `%s'\n" msgstr "Äối số không hợp lệ cho « %s ».\n" #: src/core/gnunet-core.c:95 #, fuzzy msgid "Print information about connected peers." msgstr "In ra thông tin vá» các đồng đẳng GNUnet." #: src/core/gnunet-service-core.c:97 #, c-format msgid "Core service of `%4s' ready.\n" msgstr "" #: src/core/gnunet-service-core_clients.c:370 #, fuzzy msgid "# send requests dropped (disconnected)" msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" #: src/core/gnunet-service-core_clients.c:475 #, fuzzy msgid "# messages discarded (session disconnected)" msgstr "# các thông báo được chắp liá»n" #: src/core/gnunet-service-core_clients.c:818 #, fuzzy, c-format msgid "# bytes of messages of type %u received" msgstr "# các byte nhiá»…u được nhận" #: src/core/gnunet-service-core_kx.c:565 msgid "# bytes encrypted" msgstr "# các byte đã mã hoá" #: src/core/gnunet-service-core_kx.c:617 msgid "# bytes decrypted" msgstr "# các byte đã giải mã" #: src/core/gnunet-service-core_kx.c:681 src/dv/gnunet-service-dv.c:3003 #, fuzzy msgid "Error in communication with PEERINFO service\n" msgstr "Cổng để liên lạc vá»›i giao diện ngưá»i dùng GNUnet" #: src/core/gnunet-service-core_kx.c:700 msgid "# Delayed connecting due to lack of public key" msgstr "" #: src/core/gnunet-service-core_kx.c:753 msgid "# key exchanges initiated" msgstr "" #: src/core/gnunet-service-core_kx.c:775 msgid "# key exchanges stopped" msgstr "" #: src/core/gnunet-service-core_kx.c:828 #, fuzzy msgid "# session keys received" msgstr "# các khoá phiên chạy bị từ chối" #: src/core/gnunet-service-core_kx.c:845 #, c-format msgid "`%s' is for `%s', not for me. Ignoring.\n" msgstr "" #: src/core/gnunet-service-core_kx.c:890 #, fuzzy msgid "# SET_KEY messages decrypted" msgstr "# các thông báo được chắp liá»n" #: src/core/gnunet-service-core_kx.c:977 #: src/transport/gnunet-service-transport_validation.c:810 #, fuzzy msgid "# PING messages received" msgstr "# các thông báo PING được tạo" #: src/core/gnunet-service-core_kx.c:1010 #, c-format msgid "" "Received PING from `%s' for different identity: I am `%s', PONG identity: `" "%s'\n" msgstr "" #: src/core/gnunet-service-core_kx.c:1029 #, fuzzy msgid "# PONG messages created" msgstr "# các thông báo PING được tạo" #: src/core/gnunet-service-core_kx.c:1125 #, fuzzy msgid "# sessions terminated by timeout" msgstr "# các byte loại Ä‘i bởi TCP (Ä‘i ra)" #: src/core/gnunet-service-core_kx.c:1135 #, fuzzy msgid "# keepalive messages sent" msgstr "# các thông báo PING nhập thô được gá»­i" #: src/core/gnunet-service-core_kx.c:1236 #: src/transport/gnunet-service-transport_validation.c:1031 #, fuzzy msgid "# PONG messages received" msgstr "# các thông báo PONG đã mật mã được nhận" #: src/core/gnunet-service-core_kx.c:1275 #, fuzzy msgid "# PONG messages decrypted" msgstr "# các thông báo PING được tạo" #: src/core/gnunet-service-core_kx.c:1303 #, fuzzy msgid "# session keys confirmed via PONG" msgstr "# Các quảng cáo đồng đẳng được xác nhận qua PONG" #: src/core/gnunet-service-core_kx.c:1329 #, fuzzy msgid "# rekey operations confirmed via PONG" msgstr "# Các quảng cáo đồng đẳng được xác nhận qua PONG" #: src/core/gnunet-service-core_kx.c:1381 #: src/core/gnunet-service-core_kx.c:1398 #, fuzzy msgid "# SET_KEY and PING messages created" msgstr "# các thông báo PING được tạo" #: src/core/gnunet-service-core_kx.c:1402 msgid "# REKEY operations performed" msgstr "" #: src/core/gnunet-service-core_kx.c:1537 msgid "# failed to decrypt message (no session key)" msgstr "" #: src/core/gnunet-service-core_kx.c:1577 #: src/core/gnunet-service-core_kx.c:1602 #, fuzzy msgid "# bytes dropped (duplicates)" msgstr "# các byte loại bá» bởi UDP (Ä‘i ra)" #: src/core/gnunet-service-core_kx.c:1589 #, fuzzy msgid "# bytes dropped (out of sequence)" msgstr "# các byte loại bá» bởi UDP (Ä‘i ra)" #: src/core/gnunet-service-core_kx.c:1626 #, fuzzy, c-format msgid "Message received far too old (%llu ms). Content ignored.\n" msgstr "Thông báo nhận được cÅ© hÆ¡n má»™t ngày. Äã loại bá».\n" #: src/core/gnunet-service-core_kx.c:1630 #, fuzzy msgid "# bytes dropped (ancient message)" msgstr "# các byte loại bá» bởi UDP (Ä‘i ra)" #: src/core/gnunet-service-core_kx.c:1638 #, fuzzy msgid "# bytes of payload decrypted" msgstr "# các byte đã giải mã" #: src/core/gnunet-service-core_kx.c:1700 #, fuzzy msgid "Core service is lacking HOSTKEY configuration setting. Exiting.\n" msgstr "Lưu cấu hình ngay bây giá» không?" #: src/core/gnunet-service-core_kx.c:1708 msgid "Core service could not access hostkey. Exiting.\n" msgstr "" #: src/core/gnunet-service-core_kx.c:1718 src/hostlist/hostlist-server.c:551 #: src/peerinfo-tool/gnunet-peerinfo.c:823 #: src/transport/gnunet-service-transport.c:611 #, fuzzy msgid "Could not access PEERINFO service. Exiting.\n" msgstr "Không thể truy cập đến thông tin vá» không gian tên.\n" #: src/core/gnunet-service-core_neighbours.c:163 #, fuzzy msgid "# sessions terminated by transport disconnect" msgstr "# Các quảng cáo đồng đẳng bị há»§y do trá»ng tải" #: src/core/gnunet-service-core_neighbours.c:180 #: src/core/gnunet-service-core_neighbours.c:334 msgid "# neighbour entries allocated" msgstr "" #: src/core/gnunet-service-core_neighbours.c:247 msgid "# encrypted bytes given to transport" msgstr "" #: src/core/gnunet-service-core_neighbours.c:418 #, c-format msgid "Unsupported message of type %u (%u bytes) received from peer `%s'\n" msgstr "" #: src/core/gnunet-service-core_sessions.c:206 #: src/core/gnunet-service-core_sessions.c:269 #: src/dht/gnunet-service-dht_neighbours.c:625 #: src/dht/gnunet-service-dht_neighbours.c:683 #: src/fs/gnunet-service-fs_cp.c:615 src/fs/gnunet-service-fs_cp.c:1532 #: src/topology/gnunet-daemon-topology.c:709 #: src/topology/gnunet-daemon-topology.c:810 #: src/transport/gnunet-service-transport_neighbours.c:874 #: src/transport/gnunet-service-transport_neighbours.c:1080 #: src/transport/gnunet-service-transport_neighbours.c:1089 #: src/transport/gnunet-service-transport_neighbours.c:2568 #: src/transport/gnunet-service-transport_neighbours.c:2814 #, fuzzy msgid "# peers connected" msgstr "# cá»§a các đồng đẳng đã kết nối" #: src/core/gnunet-service-core_sessions.c:236 #, fuzzy msgid "# type map refreshes sent" msgstr "# tổng số yêu cầu lá»— hổng được gá»­i" #: src/core/gnunet-service-core_sessions.c:406 msgid "# messages discarded (expired prior to transmission)" msgstr "" #: src/core/gnunet-service-core_typemap.c:110 #: src/core/gnunet-service-core_typemap.c:121 #, fuzzy msgid "# type maps received" msgstr "# các thông báo phát hiện dht được nhận" #: src/core/gnunet-service-core_typemap.c:151 msgid "# updates to my type map" msgstr "" #: src/datacache/datacache.c:115 src/datacache/datacache.c:250 #: src/datastore/gnunet-service-datastore.c:834 #, fuzzy msgid "# bytes stored" msgstr "# các byte trong kho dữ liệu" #: src/datacache/datacache.c:141 src/datacache/datacache.c:148 #: src/datastore/gnunet-service-datastore.c:1483 #: src/datastore/gnunet-service-datastore.c:1494 #, c-format msgid "No `%s' specified for `%s' in configuration!\n" msgstr "" #: src/datacache/datacache.c:180 #, c-format msgid "Loading `%s' datacache plugin\n" msgstr "" #: src/datacache/datacache.c:188 #, fuzzy, c-format msgid "Failed to load datacache plugin for `%s'\n" msgstr "Lá»—i cập nhật dữ liệu cho mô-Ä‘un « %s »\n" #: src/datacache/datacache.c:276 #, fuzzy msgid "# requests received" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/datacache/datacache.c:284 msgid "# requests filtered by bloom filter" msgstr "# các yêu cầu được lá»c theo bá»™ lá»c bloom" #: src/datacache/plugin_datacache_mysql.c:97 #: src/datacache/plugin_datacache_mysql.c:104 #: src/datacache/plugin_datacache_sqlite.c:69 #: src/datacache/plugin_datacache_sqlite.c:72 #: src/datastore/plugin_datastore_mysql.c:803 #: src/datastore/plugin_datastore_mysql.c:817 #: src/datastore/plugin_datastore_sqlite.c:57 src/mysql/mysql.c:41 #: src/mysql/mysql.c:48 src/mysql/mysql.c:522 src/mysql/mysql.c:531 #: src/mysql/mysql.c:591 src/mysql/mysql.c:607 #: src/namestore/plugin_namestore_sqlite.c:51 src/util/crypto_ksk.c:49 #: src/util/crypto_rsa.c:67 src/include/gnunet_common.h:525 #: src/include/gnunet_common.h:532 #, c-format msgid "`%s' failed at %s:%d with error: %s\n" msgstr "« %s » bị lá»—i tại %s:%d vá»›i lá»—i: %s\n" #: src/datacache/plugin_datacache_mysql.c:450 msgid "MySQL datacache running\n" msgstr "" #: src/datacache/plugin_datacache_postgres.c:367 msgid "Postgres datacache running\n" msgstr "" #: src/datacache/plugin_datacache_sqlite.c:410 msgid "Sqlite datacache running\n" msgstr "" #: src/datacache/plugin_datacache_sqlite.c:443 #: src/datastore/plugin_datastore_sqlite.c:408 #: src/namestore/plugin_namestore_sqlite.c:370 msgid "Tried to close sqlite without finalizing all prepared statements.\n" msgstr "" #: src/datacache/plugin_datacache_sqlite.c:450 #, fuzzy, c-format msgid "Failed to close statement %p: %d\n" msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" #: src/datacache/plugin_datacache_template.c:121 msgid "Template datacache running\n" msgstr "" #: src/datastore/datastore_api.c:305 msgid "Failed to transmit request to drop database.\n" msgstr "" #: src/datastore/datastore_api.c:388 msgid "# queue entry timeouts" msgstr "" #: src/datastore/datastore_api.c:432 msgid "# queue overflows" msgstr "" #: src/datastore/datastore_api.c:459 #, fuzzy msgid "# queue entries created" msgstr "# các truy vấn lá»— hổng được định tuyến" #: src/datastore/datastore_api.c:477 #, fuzzy msgid "# Requests dropped from datastore queue" msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" #: src/datastore/datastore_api.c:525 #, fuzzy msgid "# datastore connections (re)created" msgstr "# các kết nối dht" #: src/datastore/datastore_api.c:548 msgid "# reconnected to DATASTORE" msgstr "" #: src/datastore/datastore_api.c:612 #, fuzzy msgid "# transmission request failures" msgstr "# các sá»± truyá»n PONG bị lá»—i" #: src/datastore/datastore_api.c:633 #, fuzzy msgid "# bytes sent to datastore" msgstr "# các byte trong kho dữ liệu" #: src/datastore/datastore_api.c:764 #, fuzzy msgid "Failed to receive status response from database." msgstr "" "\n" "Không nhận được đáp ứng từ gnunetd.\n" #: src/datastore/datastore_api.c:778 msgid "Error reading response from datastore service" msgstr "" #: src/datastore/datastore_api.c:790 src/datastore/datastore_api.c:796 #, fuzzy msgid "Invalid error message received from datastore service" msgstr "Nhận được thông báo « %s » sai từ đồng đẳng « %s ».\n" #: src/datastore/datastore_api.c:800 #, fuzzy msgid "# status messages received" msgstr "# các thông báo phát hiện dht được nhận" #: src/datastore/datastore_api.c:869 #, fuzzy msgid "# PUT requests executed" msgstr "# các yêu cầu dht được định tuyến" #: src/datastore/datastore_api.c:936 #, fuzzy msgid "# RESERVE requests executed" msgstr "# các yêu cầu dht được định tuyến" #: src/datastore/datastore_api.c:997 msgid "# RELEASE RESERVE requests executed" msgstr "" #: src/datastore/datastore_api.c:1054 #, fuzzy msgid "# UPDATE requests executed" msgstr "# các yêu cầu dht được định tuyến" #: src/datastore/datastore_api.c:1118 #, fuzzy msgid "# REMOVE requests executed" msgstr "# các yêu cầu dht được định tuyến" #: src/datastore/datastore_api.c:1163 #, fuzzy msgid "Failed to receive response from database.\n" msgstr "" "\n" "Không nhận được đáp ứng từ gnunetd.\n" #: src/datastore/datastore_api.c:1221 #, fuzzy msgid "# Results received" msgstr "# các kết quả dht được nhận" #: src/datastore/datastore_api.c:1286 msgid "# GET REPLICATION requests executed" msgstr "" #: src/datastore/datastore_api.c:1349 msgid "# GET ZERO ANONYMITY requests executed" msgstr "" #: src/datastore/datastore_api.c:1409 #, fuzzy msgid "# GET requests executed" msgstr "# các yêu cầu dht được định tuyến" #: src/datastore/gnunet-service-datastore.c:349 #, fuzzy msgid "# bytes expired" msgstr "# các byte được nhận" #: src/datastore/gnunet-service-datastore.c:422 msgid "# bytes purged (low-priority)" msgstr "" #: src/datastore/gnunet-service-datastore.c:480 msgid "Transmission to client failed!\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:511 msgid "Shutdown in progress, aborting transmission.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:626 msgid "# results found" msgstr "" #: src/datastore/gnunet-service-datastore.c:669 #, c-format msgid "" "Insufficient space (%llu bytes are available) to satisfy `%s' request for " "%llu bytes\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:680 #, c-format msgid "" "The requested amount (%llu bytes) is larger than the cache size (%llu " "bytes)\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:684 msgid "" "Insufficient space to satisfy request and requested amount is larger than " "cache size" msgstr "" #: src/datastore/gnunet-service-datastore.c:690 msgid "Insufficient space to satisfy request" msgstr "" #: src/datastore/gnunet-service-datastore.c:695 #: src/datastore/gnunet-service-datastore.c:747 #: src/datastore/gnunet-service-datastore.c:960 #: src/datastore/gnunet-service-datastore.c:1417 msgid "# reserved" msgstr "" #: src/datastore/gnunet-service-datastore.c:760 msgid "Could not find matching reservation" msgstr "" #: src/datastore/gnunet-service-datastore.c:846 #, c-format msgid "Need %llu bytes more space (%llu allowed, using %llu)\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1006 #, fuzzy msgid "# GET requests received" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/datastore/gnunet-service-datastore.c:1018 #, fuzzy msgid "# requests filtered by bloomfilter" msgstr "# các yêu cầu được lá»c theo bá»™ lá»c bloom" #: src/datastore/gnunet-service-datastore.c:1046 #, fuzzy msgid "# UPDATE requests received" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/datastore/gnunet-service-datastore.c:1076 #, fuzzy msgid "# GET REPLICATION requests received" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/datastore/gnunet-service-datastore.c:1109 #, fuzzy msgid "# GET ZERO ANONYMITY requests received" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/datastore/gnunet-service-datastore.c:1134 msgid "Content not found" msgstr "" #: src/datastore/gnunet-service-datastore.c:1142 msgid "# bytes removed (explicit request)" msgstr "" #: src/datastore/gnunet-service-datastore.c:1174 #, fuzzy msgid "# REMOVE requests received" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/datastore/gnunet-service-datastore.c:1216 #, c-format msgid "Datastore payload inaccurate (%lld < %lld). Trying to fix.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1277 #, c-format msgid "Loading `%s' datastore plugin\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1286 #, fuzzy, c-format msgid "Failed to load datastore plugin for `%s'\n" msgstr "Không thể nạp phần bổ sung truyá»n tải « %s »\n" #: src/datastore/gnunet-service-datastore.c:1488 #, fuzzy, c-format msgid "# bytes used in file-sharing datastore `%s'" msgstr "# các byte được phép trong kho dữ liệu" #: src/datastore/gnunet-service-datastore.c:1499 msgid "# quota" msgstr "" #: src/datastore/gnunet-service-datastore.c:1501 msgid "# cache size" msgstr "" #: src/datastore/gnunet-service-datastore.c:1514 #, c-format msgid "Could not use specified filename `%s' for bloomfilter.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1532 #: src/datastore/gnunet-service-datastore.c:1548 #, fuzzy, c-format msgid "Failed to remove bogus bloomfilter file `%s'\n" msgstr "Không thể lưu tập tin cấu hình « %s »:" #: src/datastore/gnunet-service-datastore.c:1578 #, fuzzy msgid "Failed to initialize bloomfilter.\n" msgstr "Lá»—i sÆ¡ khởi dịch vụ « %s ».\n" #: src/datastore/gnunet-service-datastore.c:1607 msgid "Rebuilding bloomfilter. Please be patient.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1612 msgid "Plugin does not support get_keys function. Please fix!\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1615 msgid "Bloomfilter construction complete.\n" msgstr "" #: src/datastore/plugin_datastore_mysql.c:780 #, fuzzy, c-format msgid "Failed to prepare statement `%s'\n" msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" #: src/datastore/plugin_datastore_mysql.c:788 #, fuzzy, c-format msgid "`%s' for `%s' failed at %s:%d with error: %s\n" msgstr "« %s » bị lá»—i tại %s:%d vá»›i lá»—i: %s\n" #: src/datastore/plugin_datastore_mysql.c:1019 msgid "Mysql database running\n" msgstr "" #: src/datastore/plugin_datastore_postgres.c:824 #, fuzzy msgid "Failed to drop table from database.\n" msgstr "" "\n" "Không nhận được đáp ứng từ gnunetd.\n" #: src/datastore/plugin_datastore_postgres.c:860 msgid "Postgres database running\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:57 #, fuzzy, c-format msgid "`%s' failed at %s:%u with error: %s" msgstr "« %s » bị lá»—i tại %s:%d vá»›i lá»—i: %s" #: src/datastore/plugin_datastore_sqlite.c:233 #: src/namestore/plugin_namestore_sqlite.c:204 #, c-format msgid "Option `%s' in section `%s' missing in configuration!\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:260 #: src/namestore/plugin_namestore_sqlite.c:229 #, c-format msgid "Unable to initialize SQLite: %s.\n" msgstr "Không thể sÆ¡ khởi SQLite: %s.\n" #: src/datastore/plugin_datastore_sqlite.c:655 #, fuzzy msgid "Invalid data in database. Trying to fix (by deletion).\n" msgstr "Dữ liệu sai trong %s. Äang thá»­ sá»­a chữa (bằng cách xoá).\n" #: src/datastore/plugin_datastore_sqlite.c:1139 msgid "sqlite version to old to determine size, assuming zero\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:1158 #, c-format msgid "" "Using sqlite page utilization to estimate payload (%llu pages of size %llu " "bytes)\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:1198 #: src/namestore/plugin_namestore_sqlite.c:829 #, fuzzy msgid "Sqlite database running\n" msgstr "kho dữ liệu sqlite" #: src/datastore/plugin_datastore_template.c:241 msgid "Template database running\n" msgstr "" #: src/dht/dht_api.c:348 #, fuzzy msgid "Failed to connect to the DHT service!\n" msgstr "Lá»—i kết nối đến gnunetd.\n" #: src/dht/gnunet-dht-get.c:201 src/dht/gnunet-dht-monitor.c:293 #: src/dht/gnunet-dht-put.c:192 msgid "the query key" msgstr "" #: src/dht/gnunet-dht-get.c:204 msgid "how many parallel requests (replicas) to create" msgstr "" #: src/dht/gnunet-dht-get.c:207 src/dht/gnunet-dht-monitor.c:296 msgid "the type of data to look for" msgstr "" #: src/dht/gnunet-dht-get.c:210 src/dht/gnunet-dht-put.c:201 msgid "how long to execute this query before giving up?" msgstr "" #: src/dht/gnunet-dht-get.c:213 src/dht/gnunet-dht-monitor.c:302 #: src/dht/gnunet-dht-put.c:204 src/fs/gnunet-download.c:271 #: src/fs/gnunet-publish.c:731 src/fs/gnunet-search.c:297 #: src/fs/gnunet-unindex.c:169 src/nse/gnunet-nse-profiler.c:910 msgid "be verbose (print progress information)" msgstr "" #: src/dht/gnunet-dht-get.c:232 msgid "Issue a GET request to the GNUnet DHT, prints results." msgstr "" #: src/dht/gnunet-dht-monitor.c:299 msgid "how long to execute? 0 = forever" msgstr "" #: src/dht/gnunet-dht-monitor.c:321 msgid "Prints all packets that go through the DHT." msgstr "" #: src/dht/gnunet-dht-put.c:108 #, fuzzy msgid "PUT request sent!\n" msgstr "# độ tin cậy được tiêu phí" #: src/dht/gnunet-dht-put.c:111 msgid "Timeout sending PUT request!\n" msgstr "" #: src/dht/gnunet-dht-put.c:114 #, fuzzy msgid "PUT request not confirmed!\n" msgstr "# độ tin cậy được tiêu phí" #: src/dht/gnunet-dht-put.c:144 msgid "Must provide KEY and DATA for DHT put!\n" msgstr "" #: src/dht/gnunet-dht-put.c:152 #, fuzzy, c-format msgid "Could not connect to %s service!\n" msgstr "Không thể kết nối tá»›i %s:%u: %s\n" #: src/dht/gnunet-dht-put.c:157 #, fuzzy, c-format msgid "Connected to %s service!\n" msgstr "« %s » được kết nối tá»›i « %s ».\n" #: src/dht/gnunet-dht-put.c:172 #, c-format msgid "Issuing put request for `%s' with data `%s'!\n" msgstr "" #: src/dht/gnunet-dht-put.c:186 msgid "the data to insert under the key" msgstr "" #: src/dht/gnunet-dht-put.c:189 msgid "how long to store this entry in the dht (in seconds)" msgstr "" #: src/dht/gnunet-dht-put.c:195 msgid "how many replicas to create" msgstr "" #: src/dht/gnunet-dht-put.c:198 msgid "the type to insert data as" msgstr "" #: src/dht/gnunet-dht-put.c:223 msgid "Issue a PUT request to the GNUnet DHT insert DATA under KEY." msgstr "" #: src/dht/gnunet-service-dht.c:163 src/testing/testing.c:544 #: src/testing/testing.c:1968 src/testing/testing.c:1998 #, fuzzy msgid "Failed to connect to transport service!\n" msgstr "Lá»—i kết nối đến gnunetd.\n" #: src/dht/gnunet-service-dht_clients.c:407 #, fuzzy msgid "# GET requests from clients injected" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/dht/gnunet-service-dht_clients.c:500 #, fuzzy msgid "# PUT requests received from clients" msgstr "# các đáp ứng lá»— hổng được gá»­i cho trình/máy khách" #: src/dht/gnunet-service-dht_clients.c:584 #, fuzzy msgid "# GET requests received from clients" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/dht/gnunet-service-dht_clients.c:682 #, fuzzy msgid "# GET STOP requests received from clients" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/dht/gnunet-service-dht_clients.c:919 msgid "# Key match, type mismatches in REPLY to CLIENT" msgstr "" #: src/dht/gnunet-service-dht_clients.c:932 msgid "# Duplicate REPLIES to CLIENT request dropped" msgstr "" #: src/dht/gnunet-service-dht_clients.c:967 #, c-format msgid "Unsupported block type (%u) in request!\n" msgstr "" #: src/dht/gnunet-service-dht_clients.c:989 msgid "# RESULTS queued for clients" msgstr "" #: src/dht/gnunet-service-dht_clients.c:1038 #: src/dht/gnunet-service-dht_clients.c:1081 msgid "# REPLIES ignored for CLIENTS (no match)" msgstr "" #: src/dht/gnunet-service-dht_clients.c:1048 msgid "Could not pass reply to client, message too big!\n" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:93 #, fuzzy, c-format msgid "%s request received, but have no datacache!\n" msgstr "# các byte kiểu %d được nhận" #: src/dht/gnunet-service-dht_datacache.c:103 msgid "# ITEMS stored in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:207 msgid "# Good RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:218 msgid "# Duplicate RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:224 msgid "# Invalid RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:236 msgid "# Unsupported RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:239 #, c-format msgid "Unsupported block type (%u) in local response!\n" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:269 #, fuzzy msgid "# GET requests given to datacache" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/dht/gnunet-service-dht_hello.c:82 #, fuzzy msgid "# HELLOs obtained from peerinfo" msgstr "Nhận được thông báo « %s » sai từ đồng đẳng « %s ».\n" #: src/dht/gnunet-service-dht_neighbours.c:481 msgid "# Preference updates given to core" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:571 #, fuzzy msgid "# FIND PEER messages initiated" msgstr "# các thông báo PING được tạo" #: src/dht/gnunet-service-dht_neighbours.c:717 #, fuzzy msgid "# Queued messages discarded (peer disconnected)" msgstr "# các thông báo được chắp liá»n" #: src/dht/gnunet-service-dht_neighbours.c:772 #, fuzzy msgid "# Bytes transmitted to other peers" msgstr "# các byte kiểu %d được gá»­i " #: src/dht/gnunet-service-dht_neighbours.c:810 #, fuzzy msgid "# Bytes of bandwdith requested from core" msgstr "# các yêu cầu máy/trình khách lá»— hổng được phun vào" #: src/dht/gnunet-service-dht_neighbours.c:1032 #: src/dht/gnunet-service-dht_neighbours.c:1060 msgid "# Peers excluded from routing due to Bloomfilter" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1041 #: src/dht/gnunet-service-dht_neighbours.c:1075 #, fuzzy msgid "# Peer selection failed" msgstr "# các cuá»™c gá»i HTTP select (lá»±a chá»n)" #: src/dht/gnunet-service-dht_neighbours.c:1207 #, fuzzy msgid "# PUT requests routed" msgstr "# các yêu cầu dht được định tuyến" #: src/dht/gnunet-service-dht_neighbours.c:1236 #, fuzzy msgid "# PUT messages queued for transmission" msgstr "# các thông báo PING được tạo" #: src/dht/gnunet-service-dht_neighbours.c:1315 #, fuzzy msgid "# GET requests routed" msgstr "# các yêu cầu dht được định tuyến" #: src/dht/gnunet-service-dht_neighbours.c:1342 #, fuzzy msgid "# GET messages queued for transmission" msgstr "# các thông báo PING được tạo" #: src/dht/gnunet-service-dht_neighbours.c:1443 #, fuzzy msgid "# RESULT messages queued for transmission" msgstr "# các thông báo PING được tạo" #: src/dht/gnunet-service-dht_neighbours.c:1531 #, fuzzy msgid "# P2P PUT requests received" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/dht/gnunet-service-dht_neighbours.c:1647 #, fuzzy msgid "# FIND PEER requests ignored due to Bloomfilter" msgstr "# các yêu cầu được lá»c theo bá»™ lá»c bloom" #: src/dht/gnunet-service-dht_neighbours.c:1655 msgid "# FIND PEER requests ignored due to lack of HELLO" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1746 #, fuzzy msgid "# P2P GET requests received" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/dht/gnunet-service-dht_neighbours.c:1788 #, fuzzy msgid "# P2P FIND PEER requests processed" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/dht/gnunet-service-dht_neighbours.c:1802 #, fuzzy msgid "# P2P GET requests ONLY routed" msgstr "# các yêu cầu dht được định tuyến" #: src/dht/gnunet-service-dht_neighbours.c:1876 #, fuzzy msgid "# P2P RESULTS received" msgstr "# Tín hiệu HTTP PUT được nhận" #: src/dht/gnunet-service-dht_nse.c:59 #, fuzzy msgid "# Network size estimates received" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/dht/gnunet-service-dht_routing.c:211 msgid "# Good REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:220 msgid "# Duplicate REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:226 msgid "# Invalid REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:238 msgid "# Unsupported REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:311 msgid "# Entries removed from routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:352 msgid "# Entries added to routing table" msgstr "" #: src/dht/plugin_block_dht.c:136 #, fuzzy, c-format msgid "Block not of type %u\n" msgstr "Không biết truyá»n tải nào kiểu %d.\n" #: src/dht/plugin_block_dht.c:143 msgid "Size mismatch for block\n" msgstr "" #: src/dht/plugin_block_dht.c:152 #, c-format msgid "Block of type %u is malformed\n" msgstr "" #: src/dns/gnunet-dns-monitor.c:337 msgid "only monitor DNS queries" msgstr "" #: src/dns/gnunet-dns-monitor.c:340 msgid "only monitor DNS replies" msgstr "" #: src/dns/gnunet-dns-monitor.c:348 msgid "Monitor DNS queries." msgstr "" #: src/dns/gnunet-dns-redirector.c:236 msgid "set A records" msgstr "" #: src/dns/gnunet-dns-redirector.c:239 msgid "set AAAA records" msgstr "" #: src/dns/gnunet-dns-redirector.c:247 msgid "Change DNS replies to point elsewhere." msgstr "" #: src/dns/gnunet-service-dns.c:485 #, fuzzy, c-format msgid "Could not bind to any port: %s\n" msgstr "Không tìm thấy địa chỉ IP cá»§a máy « %s »: %s\n" #: src/dns/gnunet-service-dns.c:639 msgid "# DNS requests answered via TUN interface" msgstr "" #: src/dns/gnunet-service-dns.c:822 msgid "# DNS exit failed (failed to open socket)" msgstr "" #: src/dns/gnunet-service-dns.c:1005 #, c-format msgid "Received DNS response that is too small (%u bytes)" msgstr "" #: src/dns/gnunet-service-dns.c:1050 msgid "# External DNS response discarded (no matching request)" msgstr "" #: src/dns/gnunet-service-dns.c:1168 msgid "# Client response discarded (no matching request)" msgstr "" #: src/dns/gnunet-service-dns.c:1281 msgid "Received malformed IPv4-UDP packet on TUN interface.\n" msgstr "" #: src/dns/gnunet-service-dns.c:1297 msgid "Received malformed IPv6-UDP packet on TUN interface.\n" msgstr "" #: src/dns/gnunet-service-dns.c:1306 #, c-format msgid "Got non-IP packet with %u bytes and protocol %u from TUN\n" msgstr "" #: src/dns/gnunet-service-dns.c:1315 msgid "# Non-DNS UDP packet received via TUN interface" msgstr "" #: src/dns/gnunet-service-dns.c:1380 #, fuzzy msgid "# DNS requests received via TUN interface" msgstr "# các đáp ứng lá»— hổng được gá»­i cho trình/máy khách" #: src/dns/gnunet-service-dns.c:1465 #, c-format msgid "Configured DNS exit `%s' is not working / valid.\n" msgstr "" #: src/dns/gnunet-service-dns.c:1497 src/exit/gnunet-daemon-exit.c:2674 msgid "# Inbound MESH tunnels created" msgstr "" #: src/dns/gnunet-service-dns.c:1561 src/exit/gnunet-daemon-exit.c:3032 #, c-format msgid "`%s' must be installed SUID, refusing to run\n" msgstr "" #: src/dns/gnunet-service-dns.c:1581 msgid "Configured to provide DNS exit, but no valid DNS server configured!\n" msgstr "" #: src/dv/dv_api.c:179 #, fuzzy msgid "Failed to connect to the dv service!\n" msgstr "Lá»—i kết nối đến gnunetd.\n" #: src/dv/plugin_transport_dv.c:159 #, fuzzy, c-format msgid "%s Received message from %s of type %d, distance %u!\n" msgstr "Nhận được thông báo bị há»ng từ đồng đẳng « %s » trong %s:%d.\n" #: src/exit/gnunet-daemon-exit.c:508 #, c-format msgid "Got duplicate service records for `%s:%u'\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:563 #, fuzzy msgid "# Bytes transmitted via mesh tunnels" msgstr "# các byte được gá»­i" #: src/exit/gnunet-daemon-exit.c:679 src/exit/gnunet-daemon-exit.c:2069 #: src/exit/gnunet-daemon-exit.c:2319 src/vpn/gnunet-service-vpn.c:1394 #: src/vpn/gnunet-service-vpn.c:1795 src/vpn/gnunet-service-vpn.c:1958 msgid "# ICMPv4 packets dropped (type not allowed)" msgstr "" #: src/exit/gnunet-daemon-exit.c:716 src/exit/gnunet-daemon-exit.c:2128 #: src/exit/gnunet-daemon-exit.c:2378 src/vpn/gnunet-service-vpn.c:1450 #: src/vpn/gnunet-service-vpn.c:1854 src/vpn/gnunet-service-vpn.c:1991 msgid "# ICMPv6 packets dropped (type not allowed)" msgstr "" #: src/exit/gnunet-daemon-exit.c:756 msgid "# ICMP packets dropped (not allowed)" msgstr "" #: src/exit/gnunet-daemon-exit.c:763 msgid "ICMP Packet dropped, have no matching connection information\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:840 msgid "UDP Packet dropped, have no matching connection information\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:915 msgid "TCP Packet dropped, have no matching connection information\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:968 #, fuzzy msgid "# Packets received from TUN" msgstr "# các byte đã nhận qua HTTP" #: src/exit/gnunet-daemon-exit.c:982 #, fuzzy msgid "# Bytes received from TUN" msgstr "# các byte đã nhận qua HTTP" #: src/exit/gnunet-daemon-exit.c:1008 msgid "IPv4 packet options received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1035 #, c-format msgid "IPv4 packet with unsupported next header %u received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1081 #, c-format msgid "IPv6 packet with unsupported next header %d received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1089 #, c-format msgid "Packet from unknown protocol %u received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1471 #, fuzzy msgid "# TCP packets sent via TUN" msgstr "# các byte đã gá»­i qua UDP" #: src/exit/gnunet-daemon-exit.c:1571 #, fuzzy msgid "# TCP service creation requests received via mesh" msgstr "# các yêu cầu danh sách máy được nhận" #: src/exit/gnunet-daemon-exit.c:1574 src/exit/gnunet-daemon-exit.c:1653 #: src/exit/gnunet-daemon-exit.c:1763 src/exit/gnunet-daemon-exit.c:1993 #: src/exit/gnunet-daemon-exit.c:2235 src/exit/gnunet-daemon-exit.c:2516 #: src/exit/gnunet-daemon-exit.c:2616 #, fuzzy msgid "# Bytes received from MESH" msgstr "# các byte đã nhận qua HTTP" #: src/exit/gnunet-daemon-exit.c:1607 src/exit/gnunet-daemon-exit.c:2638 #, c-format msgid "No service found for %s on port %d!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1611 #, fuzzy msgid "# TCP requests dropped (no such service)" msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" #: src/exit/gnunet-daemon-exit.c:1656 #, fuzzy msgid "# TCP IP-exit creation requests received via mesh" msgstr "# các yêu cầu danh sách máy được nhận" #: src/exit/gnunet-daemon-exit.c:1766 #, fuzzy msgid "# TCP data requests received via mesh" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/exit/gnunet-daemon-exit.c:1780 #, fuzzy msgid "# TCP DATA requests dropped (no session)" msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" #: src/exit/gnunet-daemon-exit.c:1830 #, fuzzy msgid "# ICMP packets sent via TUN" msgstr "# các byte đã gá»­i qua UDP" #: src/exit/gnunet-daemon-exit.c:1996 #, fuzzy msgid "# ICMP IP-exit requests received via mesh" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/exit/gnunet-daemon-exit.c:2238 #, fuzzy msgid "# ICMP service requests received via mesh" msgstr "# các đáp ứng lá»— hổng được gá»­i cho trình/máy khách" #: src/exit/gnunet-daemon-exit.c:2304 src/vpn/gnunet-service-vpn.c:1384 #: src/vpn/gnunet-service-vpn.c:1952 msgid "# ICMPv4 packets dropped (impossible PT to v6)" msgstr "" #: src/exit/gnunet-daemon-exit.c:2363 src/vpn/gnunet-service-vpn.c:1420 #: src/vpn/gnunet-service-vpn.c:1432 src/vpn/gnunet-service-vpn.c:1842 msgid "# ICMPv6 packets dropped (impossible PT to v4)" msgstr "" #: src/exit/gnunet-daemon-exit.c:2413 #, fuzzy msgid "# UDP packets sent via TUN" msgstr "# các byte đã gá»­i qua UDP" #: src/exit/gnunet-daemon-exit.c:2519 #, fuzzy msgid "# UDP IP-exit requests received via mesh" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/exit/gnunet-daemon-exit.c:2619 #, fuzzy msgid "# UDP service requests received via mesh" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/exit/gnunet-daemon-exit.c:2642 #, fuzzy msgid "# UDP requests dropped (no such service)" msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" #: src/exit/gnunet-daemon-exit.c:2882 #, c-format msgid "No addresses found for hostname `%s' of service `%s'!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:2896 src/exit/gnunet-daemon-exit.c:2908 #, c-format msgid "Service `%s' configured for IPv4, but IPv4 is disabled!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:2919 #, c-format msgid "No IP addresses found for hostname `%s' of service `%s'!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3048 msgid "" "This system does not support IPv4, will disable IPv4 functions despite them " "being enabled in the configuration\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3056 msgid "" "This system does not support IPv6, will disable IPv6 functions despite them " "being enabled in the configuration\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3063 msgid "" "Cannot enable IPv4 exit but disable IPv4 on TUN interface, will use " "ENABLE_IPv4=YES\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3069 msgid "" "Cannot enable IPv6 exit but disable IPv6 on TUN interface, will use " "ENABLE_IPv6=YES\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3075 src/pt/gnunet-daemon-pt.c:884 msgid "No useful service enabled. Exiting.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3236 msgid "Daemon to run to provide an IP exit node for the VPN" msgstr "" #: src/fragmentation/defragmentation.c:270 msgid "# acknowledgements sent for fragment" msgstr "" #: src/fragmentation/defragmentation.c:456 #, fuzzy msgid "# fragments received" msgstr "# các mảnh bị loại bá»" #: src/fragmentation/defragmentation.c:521 #, fuzzy msgid "# duplicate fragments received" msgstr "# các kết quả dht được nhận" #: src/fragmentation/defragmentation.c:534 msgid "# messages defragmented" msgstr "# các thông báo được chắp liá»n" #: src/fragmentation/fragmentation.c:203 #, fuzzy msgid "# fragments transmitted" msgstr "# Các tá»± quảng cáo được truyá»n" #: src/fragmentation/fragmentation.c:206 #, fuzzy msgid "# fragments retransmitted" msgstr "# Các tá»± quảng cáo được truyá»n" #: src/fragmentation/fragmentation.c:232 #, fuzzy msgid "# fragments wrap arounds" msgstr "# Các tá»± quảng cáo được truyá»n" #: src/fragmentation/fragmentation.c:273 msgid "# messages fragmented" msgstr "# các thông báo bị tế phân" #: src/fragmentation/fragmentation.c:276 msgid "# total size of fragmented messages" msgstr "" #: src/fragmentation/fragmentation.c:363 #, fuzzy msgid "# fragment acknowledgements received" msgstr "# Các quảng cáo đồng đẳng được nhận" #: src/fragmentation/fragmentation.c:369 msgid "# bits removed from fragmentation ACKs" msgstr "" #: src/fragmentation/fragmentation.c:393 #, fuzzy msgid "# fragmentation transmissions completed" msgstr "# các sá»± truyá»n PONG bị lá»—i" #: src/fs/fs_api.c:339 #, fuzzy, c-format msgid "Could not open file `%s': %s" msgstr "Lá»—i mở tập tin theo dõi « %s »: %s\n" #: src/fs/fs_api.c:348 #, fuzzy, c-format msgid "Could not read file `%s': %s" msgstr "Lá»—i mở tập tin theo dõi « %s »: %s\n" #: src/fs/fs_api.c:354 #, c-format msgid "Short read reading from file `%s'!" msgstr "" #: src/fs/fs_api.c:938 #, fuzzy, c-format msgid "Failed to resume publishing information `%s': %s\n" msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" #: src/fs/fs_api.c:1395 #, c-format msgid "Failed to recover namespace `%s', cannot resume publishing operation.\n" msgstr "" #: src/fs/fs_api.c:1437 #, c-format msgid "Failure while resuming publishing operation `%s': %s\n" msgstr "" #: src/fs/fs_api.c:1453 #, fuzzy, c-format msgid "Failed to resume publishing operation `%s': %s\n" msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" #: src/fs/fs_api.c:2106 #, c-format msgid "Failure while resuming unindexing operation `%s': %s\n" msgstr "" #: src/fs/fs_api.c:2116 #, fuzzy, c-format msgid "Failed to resume unindexing operation `%s': %s\n" msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" #: src/fs/fs_api.c:2241 src/fs/fs_api.c:2480 #, fuzzy, c-format msgid "Failed to resume sub-download `%s': %s\n" msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" #: src/fs/fs_api.c:2258 #, fuzzy, c-format msgid "Failed to resume sub-search `%s': %s\n" msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" #: src/fs/fs_api.c:2270 src/fs/fs_api.c:2289 src/fs/fs_api.c:2773 #, c-format msgid "Failure while resuming search operation `%s': %s\n" msgstr "" #: src/fs/fs_api.c:2471 #, c-format msgid "Failed to resume sub-download `%s': could not open file `%s'\n" msgstr "" #: src/fs/fs_api.c:2717 msgid "Could not resume running search, will resume as paused search\n" msgstr "" #: src/fs/fs_api.c:2811 #, c-format msgid "Failure while resuming download operation `%s': %s\n" msgstr "" #: src/fs/fs_directory.c:210 #, fuzzy msgid "MAGIC mismatch. This is not a GNUnet directory.\n" msgstr "Lá»—i định dạng tập tin (không phải là thư mục GNUnet ?)\n" #: src/fs/fs_download.c:311 msgid "" "Recursive downloads of directories larger than 4 GB are not supported on 32-" "bit systems\n" msgstr "" #: src/fs/fs_download.c:331 msgid "Directory too large for system address space\n" msgstr "" #: src/fs/fs_download.c:497 src/fs/fs_download.c:509 #, fuzzy, c-format msgid "Failed to open file `%s' for writing" msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" #: src/fs/fs_download.c:878 #, fuzzy, c-format msgid "Failed to create directory for recursive download of `%s'\n" msgstr "Lá»—i cập nhật dữ liệu cho mô-Ä‘un « %s »\n" #: src/fs/fs_download.c:960 #, c-format msgid "" "Internal error or bogus download URI (expected %u bytes at depth %u and " "offset %llu/%llu, got %u bytes)" msgstr "" #: src/fs/fs_download.c:986 msgid "internal error decrypting content" msgstr "" #: src/fs/fs_download.c:1009 #, fuzzy, c-format msgid "Download failed: could not open file `%s': %s" msgstr "Lá»—i mở tập tin theo dõi « %s »: %s\n" #: src/fs/fs_download.c:1019 #, fuzzy, c-format msgid "Failed to seek to offset %llu in file `%s': %s" msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" #: src/fs/fs_download.c:1028 #, fuzzy, c-format msgid "Failed to write block of %u bytes at offset %llu in file `%s': %s" msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" #: src/fs/fs_download.c:1125 #, fuzzy msgid "internal error decoding tree" msgstr "=\tLá»—i Ä‘á»c thư mục.\n" #: src/fs/fs_download.c:1888 #, fuzzy msgid "Invalid URI" msgstr "Dữ liệu nhập không hợp lệ.\n" #: src/fs/fs_getopt.c:191 #, c-format msgid "" "Unknown metadata type in metadata option `%s'. Using metadata type " "`unknown' instead.\n" msgstr "" "Không rõ kiểu siêu dữ liệu trong tùy chá»n siêu dữ liệu « %s ». Äang ùng kiểu " "siêu dữ liệu « không rõ » (unknown) để thay thế.\n" #: src/fs/fs_list_indexed.c:90 #, fuzzy, c-format msgid "Failed to receive response for `%s' request from `%s' service.\n" msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" #: src/fs/fs_list_indexed.c:113 #, fuzzy, c-format msgid "Failed to receive valid response for `%s' request from `%s' service.\n" msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" #: src/fs/fs_list_indexed.c:151 #, fuzzy, c-format msgid "Failed to not connect to `%s' service.\n" msgstr "Lá»—i sÆ¡ khởi dịch vụ « %s ».\n" #: src/fs/fs_misc.c:126 #, c-format msgid "Did not find mime type `%s' in extension list.\n" msgstr "" #: src/fs/fs_namespace_advertise.c:150 #, fuzzy msgid "Unknown error" msgstr "Lá»—i không rõ.\n" #: src/fs/fs_namespace_advertise.c:238 src/fs/fs_namespace_advertise.c:259 #, fuzzy msgid "Failed to serialize meta data" msgstr "Lá»—i lấy thông kê vá» truyá»n tải.\n" #: src/fs/fs_namespace_advertise.c:278 #, fuzzy msgid "Failed to connect to datastore service" msgstr "Không kết nối được đến trình ná»n gnunetd." #: src/fs/fs_namespace.c:57 src/fs/fs_namespace.c:83 #, fuzzy, c-format msgid "Configuration fails to specify `%s' in section `%s'\n" msgstr "Tập tin cấu hình « %s » đã được ghi.\n" #: src/fs/fs_namespace.c:112 #, fuzzy, c-format msgid "Failed to open `%s' for writing: %s\n" msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" #: src/fs/fs_namespace.c:134 src/fs/fs_namespace.c:222 #, fuzzy, c-format msgid "Failed to write `%s': %s\n" msgstr "Lá»—i chạy %s: %s %d\n" #: src/fs/fs_namespace.c:256 #, fuzzy, c-format msgid "Failed to create or read private key for namespace `%s'\n" msgstr "Lá»—i cập nhật dữ liệu cho mô-Ä‘un « %s »\n" #: src/fs/fs_namespace.c:371 #, fuzzy, c-format msgid "Failed to read namespace private key file `%s', deleting it!\n" msgstr "Lá»—i thêm mục nhập vào không gian tên « %s » (có chưa ?)\n" #: src/fs/fs_namespace.c:588 src/fs/fs_publish_ksk.c:295 #, fuzzy msgid "Internal error." msgstr "Lá»—i VR." #: src/fs/fs_namespace.c:631 #, fuzzy msgid "Failed to connect to datastore." msgstr "Không kết nối được đến trình ná»n gnunetd." #: src/fs/fs_publish.c:129 src/fs/fs_publish.c:397 #, fuzzy, c-format msgid "Publishing failed: %s" msgstr "Gặp lá»—i khi tải lên tập tin: %s\n" #: src/fs/fs_publish.c:621 src/fs/fs_publish.c:638 src/fs/fs_publish.c:677 #: src/fs/fs_publish.c:697 src/fs/fs_publish.c:722 src/fs/fs_publish.c:862 #, fuzzy, c-format msgid "Can not index file `%s': %s. Will try to insert instead.\n" msgstr "Lá»—i đánh chỉ mục tập tin « %s ». Äá» nghị: thá»­ chèn tập tin.\n" #: src/fs/fs_publish.c:623 msgid "timeout on index-start request to `fs' service" msgstr "" #: src/fs/fs_publish.c:635 #, fuzzy msgid "unknown error" msgstr "Lá»—i không rõ" #: src/fs/fs_publish.c:678 msgid "failed to compute hash" msgstr "" #: src/fs/fs_publish.c:698 #, fuzzy msgid "filename too long" msgstr "tên tập tin" #: src/fs/fs_publish.c:723 msgid "could not connect to `fs' service" msgstr "" #: src/fs/fs_publish.c:746 #, fuzzy, c-format msgid "Failed to get file identifiers for `%s'\n" msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" #: src/fs/fs_publish.c:811 #, fuzzy, c-format msgid "Recursive upload failed at `%s': %s" msgstr "%s bị lá»—i tại %s:%d: « %s »\n" #: src/fs/fs_publish.c:817 #, fuzzy, c-format msgid "Recursive upload failed: %s" msgstr "Gặp lá»—i khi tải lên tập tin: %s\n" #: src/fs/fs_publish.c:863 msgid "needs to be an actual file" msgstr "" #: src/fs/fs_publish.c:1071 #, fuzzy, c-format msgid "Insufficient space for publishing: %s" msgstr "Không đủ quyá»n truy cập cho « %s »: %s\n" #: src/fs/fs_publish.c:1142 #, c-format msgid "Reserving space for %u entries and %llu bytes for publication\n" msgstr "" #: src/fs/fs_publish_ksk.c:258 #, fuzzy msgid "Could not connect to datastore." msgstr "« %s »: Không thể kết nối.\n" #: src/fs/fs_search.c:829 #, c-format msgid "Got result with unknown block type `%d', ignoring" msgstr "" #: src/fs/fs_test_lib.c:269 #, fuzzy, c-format msgid "Failed to start daemon: %s\n" msgstr "Lá»—i bắt đầu thu thập.\n" #: src/fs/fs_unindex.c:58 msgid "Failed to find given position in file" msgstr "" #: src/fs/fs_unindex.c:63 #, fuzzy msgid "Failed to read file" msgstr "Lá»—i gá»­i tin nhẳn.\n" #: src/fs/fs_unindex.c:233 msgid "Unexpected time for a response from `fs' service." msgstr "" #: src/fs/fs_unindex.c:241 msgid "Timeout waiting for `fs' service." msgstr "" #: src/fs/fs_unindex.c:249 #, fuzzy msgid "Invalid response from `fs' service." msgstr "Äối số không hợp lệ cho « %s ».\n" #: src/fs/fs_unindex.c:293 #, fuzzy msgid "Failed to connect to FS service for unindexing." msgstr "Không kết nối được đến trình ná»n gnunetd." #: src/fs/fs_unindex.c:344 #, fuzzy msgid "Failed to get KSKs from directory scan." msgstr "Lá»—i truy cập đến thư mục nhà GNUnet « %s »\n" #: src/fs/fs_unindex.c:356 #, fuzzy, c-format msgid "Internal error scanning `%s'.\n" msgstr "=\tLá»—i Ä‘á»c thư mục.\n" #: src/fs/fs_unindex.c:411 #, fuzzy, c-format msgid "Failed to remove KBlock: %s\n" msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" #: src/fs/fs_unindex.c:501 #, fuzzy, c-format msgid "Failed to parse URI `%s' from KBlock!\n" msgstr "Tập tin « %s » có URI: %s\n" #: src/fs/fs_unindex.c:553 src/fs/fs_unindex.c:618 #, fuzzy msgid "Failed to connect to `datastore' service." msgstr "Lá»—i sÆ¡ khởi dịch vụ « %s ».\n" #: src/fs/fs_unindex.c:631 #, fuzzy msgid "Failed to open file for unindexing." msgstr "Không kết nối được đến trình ná»n gnunetd." #: src/fs/fs_unindex.c:665 #, fuzzy msgid "Failed to compute hash of file." msgstr "Không kết nối được đến trình ná»n gnunetd." #: src/fs/fs_uri.c:220 #, c-format msgid "`%' must be followed by HEX number" msgstr "" #: src/fs/fs_uri.c:279 msgid "Malformed KSK URI (must not begin or end with `+')" msgstr "" #: src/fs/fs_uri.c:297 msgid "`++' not allowed in KSK URI" msgstr "" #: src/fs/fs_uri.c:304 msgid "Quotes not balanced in KSK URI" msgstr "" #: src/fs/fs_uri.c:372 src/fs/fs_uri.c:379 msgid "Malformed SKS URI" msgstr "" #: src/fs/fs_uri.c:423 src/fs/fs_uri.c:438 msgid "Malformed CHK URI" msgstr "" #: src/fs/fs_uri.c:568 src/fs/fs_uri.c:583 src/fs/fs_uri.c:593 #: src/fs/fs_uri.c:621 msgid "SKS URI malformed" msgstr "" #: src/fs/fs_uri.c:603 msgid "SKS URI malformed (could not decode public key)" msgstr "" #: src/fs/fs_uri.c:609 msgid "SKS URI malformed (could not find signature)" msgstr "" #: src/fs/fs_uri.c:615 msgid "SKS URI malformed (could not decode signature)" msgstr "" #: src/fs/fs_uri.c:628 msgid "SKS URI malformed (could not parse expiration time)" msgstr "" #: src/fs/fs_uri.c:640 msgid "SKS URI malformed (signature failed validation)" msgstr "" #: src/fs/fs_uri.c:678 msgid "Unrecognized URI type" msgstr "" #: src/fs/fs_uri.c:903 #, fuzzy msgid "Lacking key configuration settings.\n" msgstr "Lưu cấu hình ngay bây giá» không?" #: src/fs/fs_uri.c:910 #, fuzzy, c-format msgid "Could not access hostkey file `%s'.\n" msgstr "Không thể truy cập đến tập tin gnunet-directory « %s »\n" #: src/fs/fs_uri.c:1115 src/fs/fs_uri.c:1142 msgid "No keywords specified!\n" msgstr "Chưa ghi rõ từ khoá.\n" #: src/fs/fs_uri.c:1148 msgid "Number of double-quotes not balanced!\n" msgstr "Có dấu nháy kép thừa hay thiếu.\n" #: src/fs/gnunet-directory.c:49 #, c-format msgid "\t\n" msgstr "" #: src/fs/gnunet-directory.c:94 #, fuzzy, c-format msgid "Directory `%s' meta data:\n" msgstr "==> Thư mục « %s »:\n" #: src/fs/gnunet-directory.c:97 #, fuzzy, c-format msgid "Directory `%s' contents:\n" msgstr "==> Thư mục « %s »:\n" #: src/fs/gnunet-directory.c:132 #, fuzzy msgid "You must specify a filename to inspect.\n" msgstr "Phải ghi rõ chỉ má»™t tên tập tin để chèn.\n" #: src/fs/gnunet-directory.c:145 #, fuzzy, c-format msgid "Failed to read directory `%s'\n" msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" #: src/fs/gnunet-directory.c:154 #, fuzzy, c-format msgid "`%s' is not a GNUnet directory\n" msgstr "Lá»—i định dạng tập tin (không phải là thư mục GNUnet ?)\n" #: src/fs/gnunet-directory.c:179 #, fuzzy msgid "Display contents of a GNUnet directory" msgstr "Lá»—i định dạng tập tin (không phải là thư mục GNUnet ?)\n" #: src/fs/gnunet-download.c:101 #, fuzzy, c-format msgid "Starting download `%s'.\n" msgstr "Äang bắt đầu tài vỠ« %s »\n" #: src/fs/gnunet-download.c:110 #, fuzzy msgid "" msgstr "Lá»—i không rõ" #: src/fs/gnunet-download.c:119 #, c-format msgid "" "Downloading `%s' at %llu/%llu (%s remaining, %s/s). Block took %s to " "download\n" msgstr "" #: src/fs/gnunet-download.c:129 #, fuzzy, c-format msgid "Error downloading: %s.\n" msgstr "Gặp lá»—i khi tải xuống: %s\n" #: src/fs/gnunet-download.c:137 #, fuzzy, c-format msgid "Downloading `%s' done (%s/s).\n" msgstr "Tiến trình tải lên « %s » đã tiếp tục lại.\n" #: src/fs/gnunet-download.c:152 src/fs/gnunet-publish.c:190 #: src/fs/gnunet-search.c:190 src/fs/gnunet-unindex.c:109 #, fuzzy, c-format msgid "Unexpected status: %d\n" msgstr "Gặp sá»± kiện bất thưá»ng: %d\n" #: src/fs/gnunet-download.c:177 #, fuzzy msgid "You need to specify a URI argument.\n" msgstr "KHÔNG cho phép ghi rõ cả hai địa chỉ URI và tên tập tin.\n" #: src/fs/gnunet-download.c:183 src/fs/gnunet-publish.c:624 #, fuzzy, c-format msgid "Failed to parse URI: %s\n" msgstr "Tập tin « %s » có URI: %s\n" #: src/fs/gnunet-download.c:190 msgid "Only CHK or LOC URIs supported.\n" msgstr "" #: src/fs/gnunet-download.c:197 msgid "Target filename must be specified.\n" msgstr "" #: src/fs/gnunet-download.c:211 src/fs/gnunet-publish.c:602 #: src/fs/gnunet-search.c:241 src/fs/gnunet-unindex.c:141 #, fuzzy, c-format msgid "Could not initialize `%s' subsystem.\n" msgstr "Lá»—i sÆ¡ khởi dịch vụ « %s ».\n" #: src/fs/gnunet-download.c:248 src/fs/gnunet-search.c:285 #, fuzzy msgid "set the desired LEVEL of receiver-anonymity" msgstr "đặt CẤP mong muốn cá»§a tình trạng nặc danh cá»§a ngưá»i gá»­i" #: src/fs/gnunet-download.c:251 msgid "delete incomplete downloads (when aborted with CTRL-C)" msgstr "xoá việc tải vá» không hoàn thành (khi há»§y bở dùng CTRL-C)" #: src/fs/gnunet-download.c:254 src/fs/gnunet-search.c:288 msgid "only search the local peer (no P2P network search)" msgstr "" #: src/fs/gnunet-download.c:257 msgid "write the file to FILENAME" msgstr "ghi tập tin vào TÊN_TẬP_TIN" #: src/fs/gnunet-download.c:261 #, fuzzy msgid "set the maximum number of parallel downloads that is allowed" msgstr "đặt số tối Ä‘a các việc tải xuống đồng thá»i được phép" #: src/fs/gnunet-download.c:265 #, fuzzy msgid "set the maximum number of parallel requests for blocks that is allowed" msgstr "đặt số tối Ä‘a các việc tải xuống đồng thá»i được phép" #: src/fs/gnunet-download.c:268 msgid "download a GNUnet directory recursively" msgstr "tải xuống đệ quy má»™t thư mục GNUnet" #: src/fs/gnunet-download.c:278 msgid "" "Download files from GNUnet using a GNUnet CHK or LOC URI (gnunet://fs/" "chk/...)" msgstr "" #: src/fs/gnunet-fs.c:117 msgid "print a list of all indexed files" msgstr "" #: src/fs/gnunet-fs.c:124 #, fuzzy msgid "Special file-sharing operations" msgstr "Tùy chá»n chia sẻ tập tin" #: src/fs/gnunet-pseudonym.c:160 src/statistics/gnunet-statistics.c:167 #, fuzzy, c-format msgid "Invalid argument `%s'\n" msgstr "Äối số không hợp lệ cho « %s ».\n" #: src/fs/gnunet-pseudonym.c:250 src/fs/gnunet-pseudonym.c:257 #: src/fs/gnunet-pseudonym.c:259 #, fuzzy, c-format msgid "Option `%s' ignored\n" msgstr "%s: tùy chá»n « %s » là mÆ¡ hồ\n" #: src/fs/gnunet-pseudonym.c:279 src/fs/gnunet-publish.c:678 msgid "set the desired LEVEL of sender-anonymity" msgstr "đặt CẤP mong muốn cá»§a tình trạng nặc danh cá»§a ngưá»i gá»­i" #: src/fs/gnunet-pseudonym.c:282 msgid "create or advertise namespace NAME" msgstr "" #: src/fs/gnunet-pseudonym.c:285 msgid "delete namespace NAME " msgstr "" #: src/fs/gnunet-pseudonym.c:288 #, fuzzy msgid "" "add an additional keyword for the advertisment (this option can be specified " "multiple times)" msgstr "" "thêm má»™t từ khóa bổ sung cho tất cả tập tin và thư mục (có thể chỉ ra tùy " "chá»n này nhiá»u lần)" #: src/fs/gnunet-pseudonym.c:292 src/fs/gnunet-publish.c:697 msgid "set the meta-data for the given TYPE to the given VALUE" msgstr "đặt siêu dữ liệu cho KIỂU đưa ra thành GIÃ_TRỊ chỉ ra" #: src/fs/gnunet-pseudonym.c:295 #, fuzzy msgid "print names of local namespaces" msgstr "đặt đánh giá cá»§a má»™t không gian tên" #: src/fs/gnunet-pseudonym.c:298 msgid "use the given PRIORITY for the advertisments" msgstr "" #: src/fs/gnunet-pseudonym.c:301 msgid "do not print names of remote namespaces" msgstr "" #: src/fs/gnunet-pseudonym.c:304 src/fs/gnunet-publish.c:716 msgid "set the desired replication LEVEL" msgstr "" #: src/fs/gnunet-pseudonym.c:307 #, fuzzy msgid "specify ID of the root of the namespace" msgstr "đặt đánh giá cá»§a má»™t không gian tên" #: src/fs/gnunet-pseudonym.c:310 #, fuzzy msgid "change rating of namespace ID by VALUE" msgstr "đặt đánh giá cá»§a má»™t không gian tên" #: src/fs/gnunet-pseudonym.c:318 msgid "Manage GNUnet pseudonyms." msgstr "" #: src/fs/gnunet-publish.c:147 #, c-format msgid "Publishing `%s' at %llu/%llu (%s remaining)\n" msgstr "" #: src/fs/gnunet-publish.c:155 #, fuzzy, c-format msgid "Error publishing: %s.\n" msgstr "Gặp lá»—i khi tải xuống: %s\n" #: src/fs/gnunet-publish.c:165 #, c-format msgid "Publishing `%s' done.\n" msgstr "" #: src/fs/gnunet-publish.c:169 #, fuzzy, c-format msgid "URI is `%s'.\n" msgstr "Tôi là đồng đẳng « %s ».\n" #: src/fs/gnunet-publish.c:187 #, fuzzy msgid "Cleanup after abort complete.\n" msgstr "Hoàn thành khởi chạy « %s ».\n" #: src/fs/gnunet-publish.c:305 #, fuzzy, c-format msgid "Meta data for file `%s' (%s)\n" msgstr "Äang cập nhật dữ liệu cho mô-Ä‘un « %s »\n" #: src/fs/gnunet-publish.c:307 #, fuzzy, c-format msgid "Keywords for file `%s' (%s)\n" msgstr "Từ khoá cho tập tin « %s »:\n" #: src/fs/gnunet-publish.c:358 #, fuzzy, c-format msgid "Failed to create namespace `%s'\n" msgstr "Không thể tạo miá»n tên.\n" #: src/fs/gnunet-publish.c:433 #, fuzzy msgid "Could not publish\n" msgstr "Không thể truy cập đến « %s »: %s\n" #: src/fs/gnunet-publish.c:460 #, fuzzy msgid "Could not start publishing.\n" msgstr "Không thể nạp phần bổ sung truyá»n tải « %s »\n" #: src/fs/gnunet-publish.c:491 #, fuzzy, c-format msgid "Scanning directory `%s'.\n" msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" #: src/fs/gnunet-publish.c:493 #, fuzzy, c-format msgid "Scanning file `%s'.\n" msgstr "Äang bắt đầu tài vỠ« %s »\n" #: src/fs/gnunet-publish.c:498 #, c-format msgid "There was trouble processing file `%s', skipping it.\n" msgstr "" #: src/fs/gnunet-publish.c:503 msgid "Preprocessing complete.\n" msgstr "" #: src/fs/gnunet-publish.c:507 #, fuzzy, c-format msgid "Extracting meta data from file `%s' complete.\n" msgstr "Äang cập nhật dữ liệu cho mô-Ä‘un « %s »\n" #: src/fs/gnunet-publish.c:511 msgid "Meta data extraction has finished.\n" msgstr "" #: src/fs/gnunet-publish.c:518 #, fuzzy msgid "Internal error scanning directory.\n" msgstr "=\tLá»—i Ä‘á»c thư mục.\n" #: src/fs/gnunet-publish.c:552 #, c-format msgid "Cannot extract metadata from a URI!\n" msgstr "Không thể trích siêu dữ liệu ra má»™t địa chỉ URI.\n" #: src/fs/gnunet-publish.c:559 #, c-format msgid "You must specify one and only one filename for insertion.\n" msgstr "Phải ghi rõ chỉ má»™t tên tập tin để chèn.\n" #: src/fs/gnunet-publish.c:565 #, c-format msgid "You must NOT specify an URI and a filename.\n" msgstr "KHÔNG cho phép ghi rõ cả hai địa chỉ URI và tên tập tin.\n" #: src/fs/gnunet-publish.c:573 src/vpn/gnunet-vpn.c:214 #, c-format msgid "Option `%s' is required when using option `%s'.\n" msgstr "Tùy chá»n « %s » cần thiết khi dùng tùy chá»n « %s ».\n" #: src/fs/gnunet-publish.c:583 src/fs/gnunet-publish.c:590 #: src/transport/gnunet-transport.c:560 #, c-format msgid "Option `%s' makes no sense without option `%s'.\n" msgstr "Tùy chá»n « %s » không có nghÄ©a khi không có tùy chá»n « %s ».\n" #: src/fs/gnunet-publish.c:612 #, fuzzy, c-format msgid "Could not create namespace `%s'\n" msgstr "Không thể tạo miá»n tên.\n" #: src/fs/gnunet-publish.c:645 #, fuzzy, c-format msgid "Failed to access `%s': %s\n" msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" #: src/fs/gnunet-publish.c:657 msgid "" "Failed to start meta directory scanner. Is gnunet-helper-publish-fs " "installed?\n" msgstr "" #: src/fs/gnunet-publish.c:682 msgid "disable adding the creation time to the metadata of the uploaded file" msgstr "tắt thêm giá» tạo vào siêu dữ liệu cá»§a tập tin đã tải lên" #: src/fs/gnunet-publish.c:685 msgid "do not use libextractor to add keywords or metadata" msgstr "" #: src/fs/gnunet-publish.c:689 msgid "" "print list of extracted keywords that would be used, but do not perform " "upload" msgstr "" "in ra danh sách các từ khóa đã giải phóng cần sá»­ dụng, nhưng không thá»±c hiện " "tải lên" #: src/fs/gnunet-publish.c:693 msgid "" "add an additional keyword for the top-level file or directory (this option " "can be specified multiple times)" msgstr "" "thêm má»™t từ khoá bổ sung cho tập tin hoặc thư mục ở cấp đầu (có thể chỉ ra " "tùy chá»n này nhiá»u lần)" #: src/fs/gnunet-publish.c:700 msgid "" "do not index, perform full insertion (stores entire file in encrypted form " "in GNUnet database)" msgstr "" "không đánh chỉ mục, thá»±c hiện việc chèn đầy đủ (chứa toàn bá»™ tập tin ở dạng " "mã hóa trong cÆ¡ sở dữ liệu GNUnet)" #: src/fs/gnunet-publish.c:705 msgid "" "specify ID of an updated version to be published in the future (for " "namespace insertions only)" msgstr "" "chỉ ra mã số cá»§a má»™t phiên bản đã cập nhật để công bố trong tương lai (chỉ " "cho sá»± chèn không gian tên)" #: src/fs/gnunet-publish.c:709 msgid "specify the priority of the content" msgstr "xác định mức ưu tiên cá»§a ná»™i dung" #: src/fs/gnunet-publish.c:713 msgid "publish the files under the pseudonym NAME (place file into namespace)" msgstr "" "công bố các tập tin dưới biệt hiệu TÊN (đặt tập tin vào không gian tên)" #: src/fs/gnunet-publish.c:719 #, fuzzy msgid "" "only simulate the process but do not do any actual publishing (useful to " "compute URIs)" msgstr "" "chỉ mô phá»ng tiến trình, không thật công bố (có ích để tính địa chỉ URI)" #: src/fs/gnunet-publish.c:723 msgid "" "set the ID of this version of the publication (for namespace insertions only)" msgstr "" "đặt mã số cá»§a phiên bản này cá»§a sá»± công bố (chỉ cho chèn không gian tên)" #: src/fs/gnunet-publish.c:727 msgid "" "URI to be published (can be used instead of passing a file to add keywords " "to the file with the respective URI)" msgstr "" "Äịa chỉ URI cần công bố (có thể được dùng thay vào gá»­i má»™t tập tin để thêm " "từ khoá vào tập tin có địa chỉ URI tương ứng)" #: src/fs/gnunet-publish.c:742 msgid "Publish a file or directory on GNUnet" msgstr "" #: src/fs/gnunet-search.c:111 #, c-format msgid "Failed to write directory with search results to `%s'\n" msgstr "" #: src/fs/gnunet-search.c:181 #, fuzzy, c-format msgid "Error searching: %s.\n" msgstr "Gặp lá»—i khi tải xuống: %s\n" #: src/fs/gnunet-search.c:231 #, fuzzy msgid "Could not create keyword URI from arguments.\n" msgstr "Không thể tạo miá»n tên.\n" #: src/fs/gnunet-search.c:255 #, fuzzy msgid "Could not start searching.\n" msgstr "Không thể tạo miá»n tên.\n" #: src/fs/gnunet-search.c:291 msgid "write search results to file starting with PREFIX" msgstr "" #: src/fs/gnunet-search.c:294 msgid "automatically terminate search after VALUE ms" msgstr "" #: src/fs/gnunet-search.c:301 msgid "automatically terminate search after VALUE results are found" msgstr "" #: src/fs/gnunet-search.c:308 #, fuzzy msgid "Search GNUnet for files that were published on GNUnet" msgstr "Không hiển thị kết quả tìm kiếm cho tập tin được chúng ta tải lên" #: src/fs/gnunet-service-fs.c:240 msgid "# running average P2P latency (ms)" msgstr "" #: src/fs/gnunet-service-fs.c:300 src/fs/gnunet-service-fs.c:489 #, fuzzy msgid "# Loopback routes suppressed" msgstr "# tổng số định tuyến lá»— hổng thành công" #: src/fs/gnunet-service-fs.c:581 src/hostlist/gnunet-daemon-hostlist.c:297 #: src/topology/gnunet-daemon-topology.c:1330 #: src/topology/gnunet-daemon-topology.c:1337 #, fuzzy, c-format msgid "Failed to connect to `%s' service.\n" msgstr "Lá»—i sÆ¡ khởi dịch vụ « %s ».\n" #: src/fs/gnunet-service-fs_cp.c:696 #, fuzzy msgid "# migration stop messages received" msgstr "# các thông báo phát hiện dht được nhận" #: src/fs/gnunet-service-fs_cp.c:700 #, c-format msgid "Migration of content to peer `%s' blocked for %llu ms\n" msgstr "" #: src/fs/gnunet-service-fs_cp.c:735 #, fuzzy msgid "# replies transmitted to other peers" msgstr "# các byte kiểu %d được gá»­i " #: src/fs/gnunet-service-fs_cp.c:741 #, fuzzy msgid "# replies dropped" msgstr "# các đáp ứng dht được định tuyến" #: src/fs/gnunet-service-fs_cp.c:766 src/fs/gnunet-service-fs_cp.c:1324 msgid "# P2P searches active" msgstr "" #: src/fs/gnunet-service-fs_cp.c:858 msgid "# artificial delays introduced (ms)" msgstr "" #: src/fs/gnunet-service-fs_cp.c:911 #, fuzzy msgid "# replies dropped due to type mismatch" msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" #: src/fs/gnunet-service-fs_cp.c:919 #, fuzzy msgid "# replies received for other peers" msgstr "# các byte kiểu %d được nhận" #: src/fs/gnunet-service-fs_cp.c:933 msgid "# replies dropped due to insufficient cover traffic" msgstr "" #: src/fs/gnunet-service-fs_cp.c:971 msgid "# P2P searches destroyed due to ultimate reply" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1038 #, fuzzy msgid "# requests done for free (low load)" msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" #: src/fs/gnunet-service-fs_cp.c:1062 msgid "# request dropped, priority insufficient" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1072 #, fuzzy msgid "# requests done for a price (normal load)" msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" #: src/fs/gnunet-service-fs_cp.c:1151 msgid "# GET requests received (from other peers)" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1185 #, fuzzy msgid "# requests dropped due to initiator not being connected" msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" #: src/fs/gnunet-service-fs_cp.c:1207 #, fuzzy msgid "# requests dropped due to missing reverse route" msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" #: src/fs/gnunet-service-fs_cp.c:1267 #, fuzzy msgid "# requests dropped due TTL underflow" msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" #: src/fs/gnunet-service-fs_cp.c:1293 #, fuzzy msgid "# requests dropped due to higher-TTL request" msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" #: src/fs/gnunet-service-fs_cp.c:1322 #, fuzzy msgid "# P2P query messages received and processed" msgstr "# các thông báo phát hiện dht được nhận" #: src/fs/gnunet-service-fs_cp.c:1687 #, fuzzy msgid "# migration stop messages sent" msgstr "# các thông báo phát hiện dht được nhận" #: src/fs/gnunet-service-fs_indexing.c:113 #: src/fs/gnunet-service-fs_indexing.c:163 #, fuzzy, c-format msgid "Configuration option `%s' in section `%s' missing.\n" msgstr "Giá trị cấu hình « %s » cho « %s » trong phần « %s » nên là con số\n" #: src/fs/gnunet-service-fs_indexing.c:121 #: src/fs/gnunet-service-fs_indexing.c:177 #, fuzzy, c-format msgid "Could not open `%s'.\n" msgstr "Lá»—i mở tập tin theo dõi « %s »: %s\n" #: src/fs/gnunet-service-fs_indexing.c:137 #, fuzzy, c-format msgid "Error writing `%s'.\n" msgstr "Gặp lá»—i khi tạo ngưá»i dùng" #: src/fs/gnunet-service-fs_indexing.c:228 #, c-format msgid "" "Index request received for file `%s' is already indexed as `%s'. Permitting " "anyway.\n" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:266 #, c-format msgid "Hash mismatch trying to index file `%s' which has hash `%s'\n" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:481 #, fuzzy, c-format msgid "Failed to delete bogus block: %s\n" msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" #: src/fs/gnunet-service-fs_indexing.c:539 msgid "# index blocks removed: original file inaccessible" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:554 #, fuzzy, c-format msgid "Could not access indexed file `%s' (%s) at offset %llu: %s\n" msgstr "Không thể giải quyết « %s » (%s): %s\n" #: src/fs/gnunet-service-fs_indexing.c:556 msgid "not indexed" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:571 #, fuzzy, c-format msgid "Indexed file `%s' changed at offset %llu\n" msgstr "Äánh chỉ mục dữ liệu cá»§a tập tin « %s » bị lá»—i tại vị tri %llu.\n" #: src/fs/gnunet-service-fs_lc.c:202 src/fs/gnunet-service-fs_lc.c:362 #: src/fs/gnunet-service-fs_lc.c:488 #, fuzzy msgid "# client searches active" msgstr "# các yêu cầu khách lá»— hổng được nhận" #: src/fs/gnunet-service-fs_lc.c:256 #, fuzzy msgid "# replies received for local clients" msgstr "# các đáp ứng lá»— hổng được gá»­i cho trình/máy khách" #: src/fs/gnunet-service-fs_lc.c:321 #, fuzzy msgid "# client searches received" msgstr "# các yêu cầu khách lá»— hổng được nhận" #: src/fs/gnunet-service-fs_lc.c:356 msgid "# client searches updated (merged content seen list)" msgstr "" #: src/fs/gnunet-service-fs_pe.c:265 #, fuzzy msgid "# average retransmission delay (ms)" msgstr "# thá»i gian trung bình còn kết nối (theo miligiây)" #: src/fs/gnunet-service-fs_pe.c:391 #, fuzzy msgid "# transmission failed (core has no bandwidth)" msgstr "Lá»—i thá»­ gá»­i, kiểu truyá»n tải %d không được há»— trợ\n" #: src/fs/gnunet-service-fs_pe.c:420 #, fuzzy msgid "# query messages sent to other peers" msgstr "# các byte thông báo gá»­i Ä‘i bị loại bá»" #: src/fs/gnunet-service-fs_pe.c:469 msgid "# delay heap timeout" msgstr "" #: src/fs/gnunet-service-fs_pe.c:476 #, fuzzy msgid "# query plans executed" msgstr "# các yêu cầu dht được định tuyến" #: src/fs/gnunet-service-fs_pe.c:538 #, fuzzy msgid "# requests merged" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/fs/gnunet-service-fs_pe.c:544 #, fuzzy msgid "# requests refreshed" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/fs/gnunet-service-fs_pe.c:597 src/fs/gnunet-service-fs_pe.c:681 #: src/fs/gnunet-service-fs_pe.c:748 msgid "# query plan entries" msgstr "" #: src/fs/gnunet-service-fs_pr.c:285 #, fuzzy msgid "# Pending requests created" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/fs/gnunet-service-fs_pr.c:367 src/fs/gnunet-service-fs_pr.c:616 #, fuzzy msgid "# Pending requests active" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/fs/gnunet-service-fs_pr.c:779 #, fuzzy msgid "# replies received and matched" msgstr "# các byte kiểu %d được nhận" #: src/fs/gnunet-service-fs_pr.c:808 msgid "# duplicate replies discarded (bloomfilter)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:822 #, c-format msgid "Unsupported block type %u\n" msgstr "" #: src/fs/gnunet-service-fs_pr.c:835 #, fuzzy msgid "# results found locally" msgstr "# ná»™i dung lá»— hổng được tìm cục bá»™" #: src/fs/gnunet-service-fs_pr.c:953 msgid "# Datastore `PUT' failures" msgstr "" #: src/fs/gnunet-service-fs_pr.c:980 #, fuzzy msgid "# storage requests dropped due to high load" msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" #: src/fs/gnunet-service-fs_pr.c:1015 #, fuzzy msgid "# Replies received from DHT" msgstr "# các byte đã nhận qua HTTP" #: src/fs/gnunet-service-fs_pr.c:1106 #, c-format msgid "Datastore lookup already took %llu ms!\n" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1127 #, c-format msgid "On-demand lookup already took %llu ms!\n" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1174 msgid "# Datastore lookups concluded (no results)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1188 msgid "# Datastore lookups concluded (seen all)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1197 msgid "# Datastore lookups aborted (more than MAX_RESULTS)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1211 msgid "# requested DBLOCK or IBLOCK not found" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1224 msgid "# on-demand blocks matched requests" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1237 msgid "# on-demand lookups performed successfully" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1242 msgid "# on-demand lookups failed" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1269 src/fs/gnunet-service-fs_pr.c:1309 #: src/fs/gnunet-service-fs_pr.c:1447 msgid "# Datastore lookups concluded (error queueing)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1327 msgid "# Datastore lookups concluded (found last result)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1338 msgid "# Datastore lookups concluded (load too high)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1424 msgid "# Datastore lookups initiated" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1508 #, fuzzy msgid "# GAP PUT messages received" msgstr "# các thông báo PONG đã mật mã được nhận" #: src/fs/gnunet-service-fs_pr.c:1601 src/fs/gnunet-service-fs_pr.c:1610 #, fuzzy, c-format msgid "Configuration fails to specify `%s', assuming default value." msgstr "Tập tin cấu hình « %s » đã được ghi.\n" #: src/fs/gnunet-service-fs_push.c:629 #, c-format msgid "" "Invalid value specified for option `%s' in section `%s', content pushing " "disabled\n" msgstr "" #: src/fs/gnunet-unindex.c:89 #, fuzzy, c-format msgid "Unindexing at %llu/%llu (%s remaining)\n" msgstr "Lá»—i bá» chỉ mục (không đưa ra lý do)." #: src/fs/gnunet-unindex.c:96 #, fuzzy, c-format msgid "Error unindexing: %s.\n" msgstr "" "\n" "Gặp lá»—i khi bá» chỉ mục tập tin: %s\n" #: src/fs/gnunet-unindex.c:101 #, fuzzy msgid "Unindexing done.\n" msgstr "Bá» chỉ mục tập tin." #: src/fs/gnunet-unindex.c:131 #, fuzzy, c-format msgid "You must specify one and only one filename for unindexing.\n" msgstr "Phải ghi rõ chỉ má»™t tên tập tin để chèn.\n" #: src/fs/gnunet-unindex.c:148 #, fuzzy msgid "Could not start unindex operation.\n" msgstr "Không thể truy cập đến thông tin vá» không gian tên.\n" #: src/fs/gnunet-unindex.c:176 msgid "Unindex a file that was previously indexed with gnunet-publish." msgstr "" #: src/fs/plugin_block_fs.c:131 msgid "Reply mismatched in terms of namespace. Discarded.\n" msgstr "" #: src/gns/gnunet-gns.c:191 #, fuzzy msgid "Failed to connect to GNS\n" msgstr "Lá»—i kết nối đến gnunetd.\n" #: src/gns/gnunet-gns.c:232 msgid "try to shorten a given GNS name" msgstr "" #: src/gns/gnunet-gns.c:235 msgid "Lookup a record using GNS (NOT IMPLEMENTED)" msgstr "" #: src/gns/gnunet-gns.c:238 msgid "Get the authority of a particular name" msgstr "" #: src/gns/gnunet-gns.c:241 #, fuzzy msgid "Specify the type of the record lookup" msgstr "xác định mức ưu tiên cá»§a ná»™i dung" #: src/gns/gnunet-gns.c:244 msgid "No unneeded output" msgstr "" #: src/gns/gnunet-gns.c:255 msgid "GNUnet GNS access tool" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:280 #, fuzzy, c-format msgid "Unsupported form value `%s'\n" msgstr "Lệnh không được há»— trợ « %s ». Äang há»§y bá».\n" #: src/gns/gnunet-gns-fcfsd.c:333 #, fuzzy, c-format msgid "Failed to create record for domain `%s': %s\n" msgstr "Không thể truy cập đến tập tin gnunet-directory « %s »\n" #: src/gns/gnunet-gns-fcfsd.c:377 #, c-format msgid "Found existing name `%s' for the given key\n" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:439 #, c-format msgid "Found %u existing records for domain `%s'\n" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:498 #, fuzzy, c-format msgid "Failed to create page for `%s'\n" msgstr "Không thể tạo miá»n tên.\n" #: src/gns/gnunet-gns-fcfsd.c:514 #, fuzzy, c-format msgid "Failed to setup post processor for `%s'\n" msgstr "Lá»—i cập nhật dữ liệu cho mô-Ä‘un « %s »\n" #: src/gns/gnunet-gns-fcfsd.c:725 src/gns/gnunet-gns-fcfsd.c:737 #, fuzzy, c-format msgid "Option `%s' not specified in configuration section `%s'\n" msgstr "" "Äặc tả mạng dạng sai trong cấu hình phần « %s » cho mục nhập « %s »: %s\n" #: src/gns/gnunet-gns-fcfsd.c:747 src/namestore/gnunet-namestore.c:299 #, fuzzy msgid "Failed to read or create private zone key\n" msgstr "Lá»—i cập nhật dữ liệu cho mô-Ä‘un « %s »\n" #: src/gns/gnunet-gns-fcfsd.c:757 src/namestore/gnunet-namestore.c:310 #, fuzzy msgid "Failed to connect to namestore\n" msgstr "Không kết nối được đến trình ná»n gnunetd." #: src/gns/gnunet-gns-fcfsd.c:773 src/gns/gnunet-gns-proxy.c:525 #, fuzzy msgid "Failed to start HTTP server\n" msgstr "Lá»—i bắt đầu thu thập.\n" #: src/gns/gnunet-gns-fcfsd.c:804 msgid "GNUnet GNS first come first serve registration service" msgstr "" #: src/gns/gnunet-gns-proxy.c:800 msgid "listen on specified port" msgstr "" #: src/gns/gnunet-gns-proxy.c:811 msgid "GNUnet GNS proxy" msgstr "" #: src/hello/gnunet-hello.c:122 msgid "Call with name of HELLO file to modify.\n" msgstr "" #: src/hello/gnunet-hello.c:128 #, fuzzy, c-format msgid "Error accessing file `%s': %s\n" msgstr "Gặp lá»—i khi tạo ngưá»i dùng" #: src/hello/gnunet-hello.c:136 #, c-format msgid "File `%s' is too big to be a HELLO\n" msgstr "" #: src/hello/gnunet-hello.c:143 #, c-format msgid "File `%s' is too small to be a HELLO\n" msgstr "" #: src/hello/gnunet-hello.c:153 src/hello/gnunet-hello.c:181 #, fuzzy, c-format msgid "Error opening file `%s': %s\n" msgstr "Gặp lá»—i khi tạo ngưá»i dùng" #: src/hello/gnunet-hello.c:169 #, fuzzy, c-format msgid "Did not find well-formed HELLO in file `%s'\n" msgstr "Không tìm thấy tập tin nào trong thư mục « %s »\n" #: src/hello/gnunet-hello.c:193 #, fuzzy, c-format msgid "Error writing HELLO to file `%s': %s\n" msgstr "Gặp lá»—i khi tạo ngưá»i dùng" #: src/hostlist/gnunet-daemon-hostlist.c:264 msgid "" "None of the functions for the hostlist daemon were enabled. I have no " "reason to run!\n" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:317 #, fuzzy msgid "advertise our hostlist to other peers" msgstr "Tắt quảng cáo máy này cho đồng đẳng khác" #: src/hostlist/gnunet-daemon-hostlist.c:322 msgid "" "bootstrap using hostlists (it is highly recommended that you always use this " "option)" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:325 #, fuzzy msgid "enable learning about hostlist servers from other peers" msgstr "Tắt quảng cáo máy này cho đồng đẳng khác" #: src/hostlist/gnunet-daemon-hostlist.c:329 #, fuzzy msgid "provide a hostlist server" msgstr "trình phục vụ danh sách máy HTTP hợp nhất" #: src/hostlist/gnunet-daemon-hostlist.c:341 msgid "GNUnet hostlist server and client" msgstr "" #: src/hostlist/hostlist-client.c:289 #, fuzzy msgid "# bytes downloaded from hostlist servers" msgstr "trình phục vụ danh sách máy HTTP hợp nhất" #: src/hostlist/hostlist-client.c:310 src/hostlist/hostlist-client.c:340 #, fuzzy msgid "# invalid HELLOs downloaded from hostlist servers" msgstr "# các HELLO tải xuống qua HTTP" #: src/hostlist/hostlist-client.c:313 src/hostlist/hostlist-client.c:343 #, fuzzy, c-format msgid "Invalid `%s' message received from hostlist at `%s'\n" msgstr "Nhận được thông báo « %s » sai từ đồng đẳng « %s ».\n" #: src/hostlist/hostlist-client.c:331 #, fuzzy msgid "# valid HELLOs downloaded from hostlist servers" msgstr "# các HELLO tải xuống qua HTTP" #: src/hostlist/hostlist-client.c:375 src/hostlist/hostlist-client.c:396 #, fuzzy, c-format msgid "No `%s' specified in `%s' configuration, will not bootstrap.\n" msgstr "" "Chưa ghi rõ địa chỉ URL cá»§a danh sách các máy nên không nạp và khởi động.\n" #: src/hostlist/hostlist-client.c:473 src/hostlist/hostlist-client.c:683 #: src/hostlist/hostlist-client.c:689 src/hostlist/hostlist-client.c:741 #: src/hostlist/hostlist-client.c:750 src/hostlist/hostlist-client.c:871 #: src/hostlist/hostlist-client.c:961 src/hostlist/hostlist-client.c:966 #: src/transport/plugin_transport_http_client.c:110 #: src/transport/plugin_transport_http_client.c:125 #, c-format msgid "%s failed at %s:%d: `%s'\n" msgstr "%s bị lá»—i tại %s:%d: « %s »\n" #: src/hostlist/hostlist-client.c:593 src/hostlist/hostlist-client.c:1331 msgid "# advertised hostlist URIs" msgstr "" #: src/hostlist/hostlist-client.c:623 #, c-format msgid "# advertised URI `%s' downloaded" msgstr "" #: src/hostlist/hostlist-client.c:664 #, c-format msgid "" "Advertised hostlist with URI `%s' could not be downloaded. Advertised URI " "gets dismissed.\n" msgstr "" #: src/hostlist/hostlist-client.c:802 #, fuzzy, c-format msgid "Timeout trying to download hostlist from `%s'\n" msgstr "Äang thá»­ tải danh sách các máy xuống « %s »\n" #: src/hostlist/hostlist-client.c:816 #, c-format msgid "Download limit of %u bytes exceeded, stopping download\n" msgstr "" #: src/hostlist/hostlist-client.c:836 #, fuzzy, c-format msgid "Download of hostlist from `%s' failed: `%s'\n" msgstr "Tải lên « %s » hoàn thành, địa chỉ URI là « %s ».\n" #: src/hostlist/hostlist-client.c:842 #, fuzzy, c-format msgid "Download of hostlist `%s' completed.\n" msgstr "Tải lên « %s » hoàn thành, địa chỉ URI là « %s ».\n" #: src/hostlist/hostlist-client.c:850 #, c-format msgid "Adding successfully tested hostlist `%s' datastore.\n" msgstr "" #: src/hostlist/hostlist-client.c:903 #, fuzzy, c-format msgid "Bootstrapping using hostlist at `%s'.\n" msgstr "Äang nạp và khởi động dùng « %s ».\n" #: src/hostlist/hostlist-client.c:911 msgid "# hostlist downloads initiated" msgstr "" #: src/hostlist/hostlist-client.c:1037 src/hostlist/hostlist-client.c:1505 msgid "# milliseconds between hostlist downloads" msgstr "" #: src/hostlist/hostlist-client.c:1046 #, c-format msgid "Have %u/%u connections. Will consider downloading hostlist in %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1084 msgid "Scheduled saving of hostlists\n" msgstr "" #: src/hostlist/hostlist-client.c:1088 #, c-format msgid "Hostlists will be saved to file again in %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1111 src/hostlist/hostlist-client.c:1127 #, fuzzy msgid "# active connections" msgstr "# các kết nối dht" #: src/hostlist/hostlist-client.c:1242 #, c-format msgid "Initial time between hostlist downloads is %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1273 #, fuzzy, c-format msgid "" "No `%s' specified in `%s' configuration, cannot load hostlists from file.\n" msgstr "" "Chưa ghi rõ địa chỉ URL cá»§a danh sách các máy nên không nạp và khởi động.\n" #: src/hostlist/hostlist-client.c:1279 #, fuzzy, c-format msgid "Loading saved hostlist entries from file `%s' \n" msgstr "Äang thá»­ tải danh sách các máy xuống « %s »\n" #: src/hostlist/hostlist-client.c:1283 #, c-format msgid "Hostlist file `%s' is not existing\n" msgstr "" #: src/hostlist/hostlist-client.c:1294 #, fuzzy, c-format msgid "Could not open file `%s' for reading to load hostlists: %s\n" msgstr "Lá»—i mở tập tin theo dõi « %s »: %s\n" #: src/hostlist/hostlist-client.c:1327 #, c-format msgid "%u hostlist URIs loaded from file\n" msgstr "" #: src/hostlist/hostlist-client.c:1329 #, fuzzy msgid "# hostlist URIs read from file" msgstr "# các byte danh sách máy được trả vá»" #: src/hostlist/hostlist-client.c:1362 #, fuzzy, c-format msgid "" "No `%s' specified in `%s' configuration, cannot save hostlists to file.\n" msgstr "" "Chưa ghi rõ địa chỉ URL cá»§a danh sách các máy nên không nạp và khởi động.\n" #: src/hostlist/hostlist-client.c:1376 #, fuzzy, c-format msgid "Could not open file `%s' for writing to save hostlists: %s\n" msgstr "Lá»—i mở tập tin theo dõi « %s »: %s\n" #: src/hostlist/hostlist-client.c:1381 #, fuzzy, c-format msgid "Writing %u hostlist URIs to `%s'\n" msgstr "Äang thá»­ tải danh sách các máy xuống « %s »\n" #: src/hostlist/hostlist-client.c:1405 src/hostlist/hostlist-client.c:1422 #, c-format msgid "Error writing hostlist URIs to file `%s'\n" msgstr "" #: src/hostlist/hostlist-client.c:1417 #, fuzzy msgid "# hostlist URIs written to file" msgstr "# các byte danh sách máy được trả vá»" #: src/hostlist/hostlist-client.c:1470 msgid "Learning is enabled on this peer\n" msgstr "" #: src/hostlist/hostlist-client.c:1473 #, c-format msgid "Hostlists will be saved to file again in %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1482 msgid "Learning is not enabled on this peer\n" msgstr "" #: src/hostlist/hostlist-client.c:1494 #, c-format msgid "" "Since learning is not enabled on this peer, hostlist file `%s' was removed\n" msgstr "" #: src/hostlist/hostlist-client.c:1498 #, fuzzy, c-format msgid "Hostlist file `%s' could not be removed\n" msgstr "Khoá phiên chạy từ đồng đẳng « %s » không thể được thẩm tra.\n" #: src/hostlist/hostlist-server.c:134 #, fuzzy msgid "bytes in hostlist" msgstr "# các byte trong kho dữ liệu" #: src/hostlist/hostlist-server.c:157 msgid "expired addresses encountered" msgstr "" #: src/hostlist/hostlist-server.c:184 src/hostlist/hostlist-server.c:425 #: src/peerinfo-tool/gnunet-peerinfo.c:403 #: src/peerinfo-tool/gnunet-peerinfo.c:519 #: src/topology/gnunet-daemon-topology.c:927 #, fuzzy, c-format msgid "Error in communication with PEERINFO service: %s\n" msgstr "Cổng để liên lạc vá»›i giao diện ngưá»i dùng GNUnet" #: src/hostlist/hostlist-server.c:205 msgid "HELLOs without addresses encountered (ignored)" msgstr "" #: src/hostlist/hostlist-server.c:219 msgid "bytes not included in hostlist (size limit)" msgstr "" #: src/hostlist/hostlist-server.c:263 #, fuzzy, c-format msgid "Refusing `%s' request to hostlist server\n" msgstr "trình phục vụ danh sách máy HTTP hợp nhất" #: src/hostlist/hostlist-server.c:266 #, fuzzy msgid "hostlist requests refused (not HTTP GET)" msgstr "# các yêu cầu danh sách máy được nhận" #: src/hostlist/hostlist-server.c:273 msgid "Sending 100 CONTINUE reply\n" msgstr "" #: src/hostlist/hostlist-server.c:279 #, c-format msgid "Refusing `%s' request with %llu bytes of upload data\n" msgstr "" #: src/hostlist/hostlist-server.c:283 #, fuzzy msgid "hostlist requests refused (upload data)" msgstr "# các yêu cầu danh sách máy được nhận" #: src/hostlist/hostlist-server.c:291 msgid "Could not handle hostlist request since I do not have a response yet\n" msgstr "" #: src/hostlist/hostlist-server.c:294 #, fuzzy msgid "hostlist requests refused (not ready)" msgstr "# các yêu cầu danh sách máy được nhận" #: src/hostlist/hostlist-server.c:298 #, fuzzy msgid "Received request for our hostlist\n" msgstr "Nhận yêu cầu định tuyến\n" #: src/hostlist/hostlist-server.c:299 #, fuzzy msgid "hostlist requests processed" msgstr "# các yêu cầu danh sách máy được nhận" #: src/hostlist/hostlist-server.c:341 #, fuzzy msgid "# hostlist advertisements send" msgstr "# Các quảng cáo ngoại được chuyển tiếp" #: src/hostlist/hostlist-server.c:388 msgid "Advertisement message could not be queued by core\n" msgstr "" #: src/hostlist/hostlist-server.c:561 #, c-format msgid "Invalid port number %llu. Exiting.\n" msgstr "" #: src/hostlist/hostlist-server.c:570 #, c-format msgid "Hostlist service starts on %s:%llu\n" msgstr "" #: src/hostlist/hostlist-server.c:584 #, fuzzy, c-format msgid "Address to obtain hostlist: `%s'\n" msgstr "Äang thá»­ tải danh sách các máy xuống « %s »\n" #: src/hostlist/hostlist-server.c:624 #, fuzzy, c-format msgid "`%s' is not a valid IP address! Ignoring BINDTOIP.\n" msgstr "« %s » không sẵn sàng.\n" #: src/hostlist/hostlist-server.c:666 #, fuzzy, c-format msgid "Could not start hostlist HTTP server on port %u\n" msgstr "Cổng cho trình phục vụ HTTP danh sách máy chá»§ thống nhất" #: src/integration-tests/connection_watchdog.c:997 #, fuzzy, c-format msgid "Transport plugin: `%s' port %llu\n" msgstr "Äang nạp các truyá»n tải « %s »\n" #: src/integration-tests/connection_watchdog.c:1030 #, fuzzy, c-format msgid "Found %u transport plugins: `%s'\n" msgstr "Äang nạp các truyá»n tải « %s »\n" #: src/integration-tests/connection_watchdog.c:1089 msgid "Send ping messages to test connectivity (default == NO)" msgstr "" #: src/integration-tests/connection_watchdog.c:1095 #: src/template/gnunet-template.c:68 msgid "help text" msgstr "" #: src/mesh/gnunet-service-mesh.c:4590 msgid "Wrong CORE service\n" msgstr "" #: src/mesh/gnunet-service-mesh.c:4784 #, fuzzy msgid "Mesh service is lacking key configuration settings. Exiting.\n" msgstr "Lưu cấu hình ngay bây giá» không?" #: src/mesh/gnunet-service-mesh.c:4793 #, fuzzy msgid "Mesh service could not access hostkey. Exiting.\n" msgstr "Không thể truy cập đến thông tin vá» không gian tên.\n" #: src/mysql/mysql.c:174 #, c-format msgid "Trying to use file `%s' for MySQL configuration.\n" msgstr "Äang thá»­ dùng tập tin « %s » cho cấu hình MySQL.\n" #: src/mysql/mysql.c:181 #, fuzzy, c-format msgid "Could not access file `%s': %s\n" msgstr "Không thể truy cập đến « %s »: %s\n" #: src/namestore/gnunet-namestore.c:157 #, fuzzy, c-format msgid "Adding record failed: %s\n" msgstr "Gặp lá»—i khi tải lên tập tin: %s\n" #: src/namestore/gnunet-namestore.c:183 #, fuzzy, c-format msgid "Deleting record failed: %s\n" msgstr "Gặp lá»—i khi tải lên tập tin: %s\n" #: src/namestore/gnunet-namestore.c:239 #, c-format msgid "\tCorrupt or unsupported record of type %u\n" msgstr "" #: src/namestore/gnunet-namestore.c:276 #, c-format msgid "Option `%s' not given, but I need a zone key file!\n" msgstr "" #: src/namestore/gnunet-namestore.c:281 #, fuzzy, c-format msgid "Using default zone file `%s'\n" msgstr "Äang bắt đầu tài vỠ« %s »\n" #: src/namestore/gnunet-namestore.c:291 #, fuzzy, c-format msgid "No options given\n" msgstr "chưa đưa ra tên" #: src/namestore/gnunet-namestore.c:321 #, fuzzy, c-format msgid "Unsupported type `%s'\n" msgstr "Lệnh không được há»— trợ « %s ». Äang há»§y bá».\n" #: src/namestore/gnunet-namestore.c:328 src/namestore/gnunet-namestore.c:350 #: src/namestore/gnunet-namestore.c:374 src/namestore/gnunet-namestore.c:384 #: src/namestore/gnunet-namestore.c:409 #, fuzzy, c-format msgid "Missing option `%s' for operation `%s'\n" msgstr "Giá trị cấu hình « %s » cho « %s » trong phần « %s » nên là con số\n" #: src/namestore/gnunet-namestore.c:329 src/namestore/gnunet-namestore.c:351 msgid "add/del" msgstr "" #: src/namestore/gnunet-namestore.c:341 #, c-format msgid "Value `%s' invalid for record type `%s'\n" msgstr "" #: src/namestore/gnunet-namestore.c:366 #, fuzzy, c-format msgid "Invalid time format `%s'\n" msgstr "Äịa chỉ IP định dạng sai: %s\n" #: src/namestore/gnunet-namestore.c:375 src/namestore/gnunet-namestore.c:385 msgid "add" msgstr "" #: src/namestore/gnunet-namestore.c:410 msgid "del" msgstr "" #: src/namestore/gnunet-namestore.c:462 msgid "add record" msgstr "" #: src/namestore/gnunet-namestore.c:465 msgid "delete record" msgstr "" #: src/namestore/gnunet-namestore.c:468 msgid "display records" msgstr "" #: src/namestore/gnunet-namestore.c:471 msgid "" "expiration time for record to use (for adding only), \"never\" is possible" msgstr "" #: src/namestore/gnunet-namestore.c:474 msgid "name of the record to add/delete/display" msgstr "" #: src/namestore/gnunet-namestore.c:477 msgid "type of the record to add/delete/display" msgstr "" #: src/namestore/gnunet-namestore.c:480 msgid "value of the record to add/delete" msgstr "" #: src/namestore/gnunet-namestore.c:483 msgid "create or list public record" msgstr "" #: src/namestore/gnunet-namestore.c:486 msgid "create or list non-authority record" msgstr "" #: src/namestore/gnunet-namestore.c:489 #, fuzzy msgid "filename with the zone key" msgstr "tên tập tin" #: src/namestore/gnunet-namestore.c:500 #, fuzzy msgid "GNUnet zone manipulation tool" msgstr "Cấu hình GNUnet" #: src/namestore/gnunet-service-namestore.c:143 #, c-format msgid "File zone `%s' but corrupt content already exists, failed to write! \n" msgstr "" #: src/namestore/gnunet-service-namestore.c:154 #, c-format msgid "File zone `%s' containing this key already exists\n" msgstr "" #: src/namestore/gnunet-service-namestore.c:160 #, c-format msgid "" "File zone `%s' but different zone key already exists, failed to write! \n" msgstr "" #: src/namestore/gnunet-service-namestore.c:198 #, fuzzy, c-format msgid "Stored zonekey for zone `%s' in file `%s'\n" msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" #: src/namestore/gnunet-service-namestore.c:1909 msgid "No directory to load zonefiles specified in configuration\n" msgstr "" #: src/namestore/gnunet-service-namestore.c:1918 #, c-format msgid "Creating directory `%s' for zone files failed!\n" msgstr "" #: src/namestore/namestore_api.c:315 src/namestore/namestore_api.c:353 msgid "Namestore added record successfully" msgstr "" #: src/namestore/namestore_api.c:323 msgid "Namestore failed to add record" msgstr "" #: src/namestore/namestore_api.c:361 msgid "Namestore record already existed" msgstr "" #: src/namestore/namestore_api.c:368 msgid "Namestore failed to add record\n" msgstr "" #: src/namestore/namestore_api.c:401 #, fuzzy msgid "Namestore removed record successfully" msgstr "Dịch vụ GNUnet đã được cài đặt.\n" #: src/namestore/namestore_api.c:408 msgid "No records for entry" msgstr "" #: src/namestore/namestore_api.c:415 #, fuzzy msgid "Could not find record to remove" msgstr "Không thể kết nối tá»›i %s:%u: %s\n" #: src/namestore/namestore_api.c:422 #, fuzzy msgid "Failed to create new signature" msgstr "Không thể tạo miá»n tên.\n" #: src/namestore/namestore_api.c:429 #, fuzzy msgid "Failed to put new set of records in database" msgstr "" "\n" "Không nhận được đáp ứng từ gnunetd.\n" #: src/nat/gnunet-nat-server.c:279 #, c-format msgid "Please pass valid port number as the first argument! (got `%s')\n" msgstr "" #: src/nat/gnunet-nat-server.c:318 msgid "GNUnet NAT traversal test helper daemon" msgstr "" #: src/nat/nat.c:799 #, c-format msgid "gnunet-helper-nat-server generated malformed address `%s'\n" msgstr "" #: src/nat/nat.c:844 #, fuzzy, c-format msgid "Failed to start %s\n" msgstr "Lá»—i bắt đầu thu thập.\n" #: src/nat/nat.c:1111 #, fuzzy, c-format msgid "Malformed %s `%s' given in configuration!\n" msgstr "Lá»—i lưu cấu hình." #: src/nat/nat.c:1177 src/nat/nat.c:1187 #, c-format msgid "" "Configuration requires `%s', but binary is not installed properly (SUID bit " "not set). Option disabled.\n" msgstr "" #: src/nat/nat.c:1321 msgid "Internal IP address not known, cannot use ICMP NAT traversal method\n" msgstr "" #: src/nat/nat.c:1332 #, c-format msgid "Running gnunet-helper-nat-client %s %s %u\n" msgstr "" #: src/nat/nat_test.c:341 #, fuzzy msgid "Failed to connect to `gnunet-nat-server'\n" msgstr "Lá»—i kết nối đến gnunetd.\n" #: src/nat/nat_test.c:411 #, c-format msgid "Failed to create listen socket bound to `%s' for NAT test: %s\n" msgstr "" #: src/nse/gnunet-nse-profiler.c:928 #, fuzzy msgid "Measure quality and performance of the NSE service." msgstr "Không thể truy cập đến dịch vụ" #: src/nse/gnunet-service-nse.c:925 #, c-format msgid "Proof of work invalid: %llu!\n" msgstr "" #: src/nse/gnunet-service-nse.c:1381 src/nse/gnunet-service-nse.c:1400 #: src/nse/gnunet-service-nse.c:1421 msgid "NSE service is lacking key configuration settings. Exiting.\n" msgstr "" #: src/nse/gnunet-service-nse.c:1388 msgid "Invalid work requirement for NSE service. Exiting.\n" msgstr "" #: src/nse/gnunet-service-nse.c:1409 #, fuzzy msgid "NSE service could not access hostkey. Exiting.\n" msgstr "Không thể truy cập đến thông tin vá» không gian tên.\n" #: src/peerinfo/gnunet-service-peerinfo.c:134 #, fuzzy, c-format msgid "Removing expired address of transport `%s'\n" msgstr "Äã nạp truyá»n tải « %s »\n" #: src/peerinfo/gnunet-service-peerinfo.c:203 #, fuzzy, c-format msgid "Failed to parse HELLO in file `%s'\n" msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" #: src/peerinfo/gnunet-service-peerinfo.c:229 msgid "# peers known" msgstr "" #: src/peerinfo/gnunet-service-peerinfo.c:254 #, c-format msgid "" "File `%s' in directory `%s' does not match naming convention. Removed.\n" msgstr "" "Tập tin « %s » trong thư mục « %s » không tùy theo quy ước đặt tên. Bị gỡ " "bá».\n" #: src/peerinfo/gnunet-service-peerinfo.c:353 #, c-format msgid "Still no peers found in `%s'!\n" msgstr "Vẫn còn không tìm thấy đồng đẳng trong « %s ».\n" #: src/peerinfo/gnunet-service-peerinfo.c:710 #, c-format msgid "Importing HELLOs from `%s'\n" msgstr "" #: src/peerinfo/peerinfo_api.c:238 msgid "aborted due to explicit disconnect request" msgstr "" #: src/peerinfo/peerinfo_api.c:358 #, fuzzy msgid "failed to transmit request (service down?)" msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" #: src/peerinfo/peerinfo_api.c:505 #, fuzzy msgid "Failed to receive response from `PEERINFO' service." msgstr "" "\n" "Không nhận được đáp ứng từ gnunetd.\n" #: src/peerinfo/peerinfo_api.c:531 src/peerinfo/peerinfo_api.c:550 #: src/peerinfo/peerinfo_api.c:565 src/peerinfo/peerinfo_api.c:576 #: src/peerinfo/peerinfo_api.c:587 #, fuzzy msgid "Received invalid message from `PEERINFO' service." msgstr "" "\n" "Không nhận được đáp ứng từ gnunetd.\n" #: src/peerinfo/peerinfo_api.c:663 #, fuzzy msgid "Timeout transmitting iteration request to `PEERINFO' service." msgstr "Lá»—i sÆ¡ khởi dịch vụ « %s ».\n" #: src/peerinfo/peerinfo_api_notify.c:256 #, fuzzy, c-format msgid "Could not connect to `%s' service.\n" msgstr "Không thể kết nối tá»›i %s:%u: %s\n" #: src/peerinfo-tool/gnunet-peerinfo.c:581 #, fuzzy msgid "Failed to parse HELLO message: missing expiration time\n" msgstr "Lá»—i lưu cấu hình." #: src/peerinfo-tool/gnunet-peerinfo.c:589 #, fuzzy msgid "Failed to parse HELLO message: invalid expiration time\n" msgstr "Lá»—i lưu cấu hình." #: src/peerinfo-tool/gnunet-peerinfo.c:598 #, fuzzy msgid "Failed to parse HELLO message: malformed\n" msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" #: src/peerinfo-tool/gnunet-peerinfo.c:608 #, fuzzy msgid "Failed to parse HELLO message: missing transport plugin\n" msgstr "Không thể nạp phần bổ sung truyá»n tải « %s »\n" #: src/peerinfo-tool/gnunet-peerinfo.c:625 #, c-format msgid "Plugin `%s' not found\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:634 #, c-format msgid "Plugin `%s' does not support URIs yet\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:653 #, fuzzy, c-format msgid "Failed to parse `%s' as an address for plugin `%s'\n" msgstr "Lá»—i đóng kết đến cổng %s %d.\n" #: src/peerinfo-tool/gnunet-peerinfo.c:685 #, c-format msgid "Failure adding HELLO: %s\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:833 #, fuzzy, c-format msgid "Could not find option `%s:%s' in configuration.\n" msgstr "Không tìm thấy phương pháp « %s%s » trong thư viện « %s ».\n" #: src/peerinfo-tool/gnunet-peerinfo.c:840 #, c-format msgid "Loading hostkey from `%s' failed.\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:875 #, fuzzy, c-format msgid "Invalid URI `%s'\n" msgstr "Dữ liệu nhập không hợp lệ.\n" #: src/peerinfo-tool/gnunet-peerinfo.c:899 #, c-format msgid "I am peer `%s'.\n" msgstr "Tôi là đồng đẳng « %s ».\n" #: src/peerinfo-tool/gnunet-peerinfo.c:936 msgid "don't resolve host names" msgstr "không quyết định các tên máy" #: src/peerinfo-tool/gnunet-peerinfo.c:939 msgid "output only the identity strings" msgstr "chỉ xuất những chuá»—i nhận diện" #: src/peerinfo-tool/gnunet-peerinfo.c:942 msgid "output our own identity only" msgstr "chỉ xuất nhận diện mình" #: src/peerinfo-tool/gnunet-peerinfo.c:945 #, fuzzy msgid "list all known peers" msgstr "liệt kê má»i bá»™ tiếp hợp mạng" #: src/peerinfo-tool/gnunet-peerinfo.c:948 msgid "also output HELLO uri(s)" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:951 msgid "add given HELLO uri to the database" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:957 #, fuzzy msgid "Print information about peers." msgstr "In ra thông tin vá» các đồng đẳng GNUnet." #: src/peerinfo-tool/gnunet-peerinfo_plugins.c:105 #: src/transport/gnunet-service-transport_plugins.c:118 #, fuzzy, c-format msgid "Starting transport plugins `%s'\n" msgstr "Äang nạp các truyá»n tải « %s »\n" #: src/peerinfo-tool/gnunet-peerinfo_plugins.c:109 #: src/transport/gnunet-service-transport_plugins.c:122 #, fuzzy, c-format msgid "Loading `%s' transport plugin\n" msgstr "Äang nạp các truyá»n tải « %s »\n" #: src/peerinfo-tool/gnunet-peerinfo_plugins.c:129 #: src/transport/gnunet-service-transport_plugins.c:150 #, fuzzy, c-format msgid "Failed to load transport plugin for `%s'\n" msgstr "Không thể nạp phần bổ sung truyá»n tải « %s »\n" #: src/postgres/postgres.c:59 #, fuzzy, c-format msgid "`%s:%s' failed at %s:%d with error: %s" msgstr "« %s » bị lá»—i tại %s:%d vá»›i lá»—i: %s" #: src/postgres/postgres.c:148 #, fuzzy, c-format msgid "Unable to initialize Postgres: %s" msgstr "Không thể sÆ¡ khởi SQLite: %s.\n" #: src/pt/gnunet-daemon-pt.c:264 msgid "Failed to pack DNS request. Dropping.\n" msgstr "" #: src/pt/gnunet-daemon-pt.c:270 #, fuzzy msgid "# DNS requests mapped to VPN" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/pt/gnunet-daemon-pt.c:323 msgid "# DNS records modified" msgstr "" #: src/pt/gnunet-daemon-pt.c:500 #, fuzzy msgid "# DNS replies intercepted" msgstr "# các đáp ứng dht được định tuyến" #: src/pt/gnunet-daemon-pt.c:506 msgid "Failed to parse DNS request. Dropping.\n" msgstr "" #: src/pt/gnunet-daemon-pt.c:602 #, fuzzy msgid "# DNS requests dropped (timeout)" msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" #: src/pt/gnunet-daemon-pt.c:632 #, fuzzy msgid "# DNS requests intercepted" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/pt/gnunet-daemon-pt.c:637 #, fuzzy msgid "# DNS requests dropped (DNS mesh tunnel down)" msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" #: src/pt/gnunet-daemon-pt.c:645 #, fuzzy msgid "# DNS requests dropped (malformed)" msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" #: src/pt/gnunet-daemon-pt.c:716 #, fuzzy msgid "# DNS replies received" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/pt/gnunet-daemon-pt.c:730 #, fuzzy msgid "# DNS replies dropped (too late?)" msgstr "# các đáp ứng dht được định tuyến" #: src/pt/gnunet-daemon-pt.c:748 src/pt/gnunet-daemon-pt.c:760 msgid "# DNS requests aborted (tunnel down)" msgstr "" #: src/pt/gnunet-daemon-pt.c:898 src/pt/gnunet-daemon-pt.c:907 #: src/pt/gnunet-daemon-pt.c:930 src/pt/gnunet-daemon-pt.c:940 #, fuzzy, c-format msgid "Failed to connect to %s service. Exiting.\n" msgstr "Lá»—i sÆ¡ khởi dịch vụ « %s ».\n" #: src/pt/gnunet-daemon-pt.c:973 msgid "Daemon to run to perform IP protocol translation to GNUnet" msgstr "" #: src/statistics/gnunet-service-statistics.c:271 #, fuzzy, c-format msgid "Loading %llu bytes of statistics from `%s'\n" msgstr "Äã tải %llu byte xuống « %s ».\n" #: src/statistics/gnunet-service-statistics.c:330 #, fuzzy, c-format msgid "Wrote %llu bytes of statistics to `%s'\n" msgstr "Äã tải %llu byte xuống « %s ».\n" #: src/statistics/gnunet-statistics.c:122 #, fuzzy msgid "Failed to obtain statistics.\n" msgstr "Lá»—i lấy thông kê vá» truyá»n tải.\n" #: src/statistics/gnunet-statistics.c:199 #, fuzzy, c-format msgid "No subsystem or name given\n" msgstr "chưa đưa ra tên" #: src/statistics/gnunet-statistics.c:207 #, fuzzy, c-format msgid "Failed to initialize watch routine\n" msgstr "Lá»—i sÆ¡ khởi dịch vụ « %s ».\n" #: src/statistics/gnunet-statistics.c:227 msgid "limit output to statistics for the given NAME" msgstr "" #: src/statistics/gnunet-statistics.c:230 msgid "make the value being set persistent" msgstr "" #: src/statistics/gnunet-statistics.c:233 msgid "limit output to the given SUBSYSTEM" msgstr "" #: src/statistics/gnunet-statistics.c:236 msgid "just print the statistics value" msgstr "" #: src/statistics/gnunet-statistics.c:239 msgid "watch value continously" msgstr "" #: src/statistics/gnunet-statistics.c:246 msgid "Print statistics about GNUnet operations." msgstr "In ra thống kê vá» các thao tác GNUnet." #: src/statistics/statistics_api.c:456 #, fuzzy msgid "Could not save some persistent statistics\n" msgstr "Không thể tạo miá»n tên.\n" #: src/statistics/statistics_api.c:999 msgid "" "Failed to receive acknowledgement from statistics service, some statistics " "might have been lost!\n" msgstr "" #: src/testing/gnunet-testing.c:157 #, fuzzy msgid "Could not read hostkeys file, specify hostkey file with -H!\n" msgstr "Không thể Ä‘á»c danh sách bạn bè « %s »\n" #: src/testing/gnunet-testing.c:159 #, c-format msgid "Specified hostkey file `%s' not found!\n" msgstr "" #: src/testing/gnunet-testing.c:273 #, fuzzy msgid "create unique configuration files" msgstr "cập nhật má»™t giá trị trong tập tin cấu hình" #: src/testing/gnunet-testing.c:275 msgid "create hostkey files from pre-computed hostkey list" msgstr "" #: src/testing/gnunet-testing.c:277 msgid "host key file" msgstr "" #: src/testing/gnunet-testing.c:279 #, fuzzy msgid "number of unique configuration files or hostkeys to create" msgstr "in ra đầu ra tiêu chuẩn má»™t giá trị từ tập tin cấu hình" #: src/testing/gnunet-testing.c:281 #, fuzzy msgid "configuration template" msgstr "Cấu hình đã được lưu." #: src/testing/gnunet-testing.c:287 msgid "Command line tool to access the testing library" msgstr "" #: src/testing/helper.c:56 #, fuzzy msgid "Peer is lacking HOSTKEY configuration setting.\n" msgstr "Lưu cấu hình ngay bây giá» không?" #: src/testing/helper.c:64 #, fuzzy msgid "Could not access hostkey.\n" msgstr "Không thể truy cập đến tập tin gnunet-directory « %s »\n" #: src/testing/testing.c:200 msgid "`scp' does not seem to terminate (timeout copying config).\n" msgstr "" #: src/testing/testing.c:214 src/testing/testing.c:798 #, fuzzy msgid "`scp' did not complete cleanly.\n" msgstr "« %s » không phải được kết nối tá»›i đồng đẳng nào.\n" #: src/testing/testing.c:237 #, fuzzy msgid "Failed to create pipe for `gnunet-peerinfo' process.\n" msgstr "Lá»—i bắt đầu thu thập.\n" #: src/testing/testing.c:238 #, fuzzy msgid "Failed to create pipe for `ssh' process.\n" msgstr "Lá»—i tạo thư mục tạm thá»i." #: src/testing/testing.c:286 #, fuzzy, c-format msgid "Could not start `%s' process to create hostkey.\n" msgstr "Lá»—i bắt đầu thu thập.\n" #: src/testing/testing.c:293 #, fuzzy msgid "Failed to start `gnunet-peerinfo' process.\n" msgstr "Lá»—i bắt đầu thu thập.\n" #: src/testing/testing.c:294 src/testing/testing.c:471 #, fuzzy msgid "Failed to start `ssh' process.\n" msgstr "Lá»—i bắt đầu thu thập.\n" #: src/testing/testing.c:354 #, fuzzy, c-format msgid "Error reading from gnunet-peerinfo: %s\n" msgstr "Gặp lá»—i khi Ä‘á»c thông tin từ gnunetd.\n" #: src/testing/testing.c:358 #, fuzzy msgid "Malformed output from gnunet-peerinfo!\n" msgstr "Gặp lá»—i khi Ä‘á»c thông tin từ gnunetd.\n" #: src/testing/testing.c:368 #, fuzzy msgid "Failed to get hostkey!\n" msgstr "Lá»—i lấy thông kê vá» truyá»n tải.\n" #: src/testing/testing.c:400 msgid "`Failed while waiting for topology setup!\n" msgstr "" #: src/testing/testing.c:463 #, fuzzy, c-format msgid "Could not start `%s' process to start GNUnet.\n" msgstr "Không thể tạo miá»n tên.\n" #: src/testing/testing.c:470 #, fuzzy msgid "Failed to start `gnunet-arm' process.\n" msgstr "Lá»—i dừng chạy gnunet-auto-share.\n" #: src/testing/testing.c:493 src/testing/testing.c:600 msgid "`gnunet-arm' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:494 src/testing/testing.c:601 #: src/testing/testing.c:621 msgid "`ssh' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:570 msgid "Unable to get HELLO for peer!\n" msgstr "" #: src/testing/testing.c:620 msgid "`gnunet-arm' terminated with non-zero exit status (or timed out)!\n" msgstr "" #: src/testing/testing.c:643 src/testing/testing.c:675 msgid "either `gnunet-arm' or `ssh' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:658 src/testing/testing.c:713 #, fuzzy msgid "shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n" msgstr "« %s » không phải được kết nối tá»›i đồng đẳng nào.\n" #: src/testing/testing.c:786 msgid "`scp' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:948 #, fuzzy, c-format msgid "Starting service %s for peer `%4s'\n" msgstr "Äang bắt đầu tài vỠ« %s »\n" #: src/testing/testing.c:1207 src/testing/testing_group.c:6154 #, fuzzy, c-format msgid "Could not start `%s' process to copy configuration directory.\n" msgstr "Không thể truy cập đến thông tin vá» không gian tên.\n" #: src/testing/testing.c:1292 src/testing/testing.c:1359 #, fuzzy, c-format msgid "Terminating peer `%4s'\n" msgstr "Không đủ quyá»n cho « %s ».\n" #: src/testing/testing.c:1448 #, fuzzy, c-format msgid "Setting d->dead on peer `%4s'\n" msgstr "Äang bắt đầu tài lên « %s ».\n" #: src/testing/testing.c:1601 msgid "Peer not yet running, can not change configuration at this point." msgstr "" #: src/testing/testing.c:1609 #, fuzzy msgid "Failed to write new configuration to disk." msgstr "Lá»—i lưu cấu hình." #: src/testing/testing.c:1636 #, fuzzy, c-format msgid "Could not start `%s' process to copy configuration file.\n" msgstr "Không tìm thấy phương pháp « %s%s » trong thư viện « %s ».\n" #: src/testing/testing.c:1639 #, fuzzy msgid "Failed to copy new configuration to remote machine." msgstr "Lá»—i lưu cấu hình." #: src/testing/testing.c:1794 #, fuzzy msgid "Peers failed to connect" msgstr "Không kết nối được đến trình ná»n gnunetd." #: src/testing/testing.c:1922 #, fuzzy msgid "Failed to connect to core service of first peer!\n" msgstr "Lá»—i nạp dịch vụ sqstore. Hãy kiểm tra lại cấu hình.\n" #: src/testing/testing.c:2145 msgid "Peers are not fully running yet, can not connect!\n" msgstr "" #: src/testing/testing_group.c:1895 src/testing/testing_group.c:1907 #: src/testing/testing_group.c:2008 src/testing/testing_group.c:2065 #: src/testing/testing_group.c:2152 src/testing/testing_group.c:2172 #: src/testing/testing_group.c:2302 src/testing/testing_peergroup.c:950 #, fuzzy, c-format msgid "Invalid value `%s' for option `%s' in section `%s': expected float\n" msgstr "Giá trị cấu hình « %s » cho « %s » trong phần « %s » nên là con số\n" #: src/testing/testing_group.c:2160 #, fuzzy, c-format msgid "" "Invalid value `%s' for option `%s' in section `%s': got %f, needed value " "greater than 0\n" msgstr "Giá trị cấu hình « %s » cho « %s » trong phần « %s » nên là con số\n" #: src/testing/testing_group.c:2877 src/testing/testing_group.c:3063 #, fuzzy, c-format msgid "" "No `%s' specified in peer configuration in section `%s', cannot copy friends " "file!\n" msgstr "" "Äặc tả mạng dạng sai trong cấu hình phần « %s » cho mục nhập « %s »: %s\n" #: src/testing/testing_group.c:3957 msgid "Creating no allowed topology (all peers can connect at core level)\n" msgstr "" #: src/testing/testing_group.c:5226 #, fuzzy msgid "Unknown topology specification, can't connect peers!\n" msgstr "Lá»—i cú pháp trong sá»± xác định địa hình há»c, Ä‘ang bá» qua các byte.\n" #: src/testing/testing_group.c:5944 src/transport/transport-testing.c:636 #, fuzzy msgid "Could not read hostkeys file!\n" msgstr "Không thể Ä‘á»c danh sách bạn bè « %s »\n" #: src/testing/testing_group.c:6011 #, fuzzy, c-format msgid "Could not create configuration for peer number %u on `%s'!\n" msgstr "Không thể truy cập đến thông tin vá» không gian tên.\n" #: src/testing/testing_new.c:169 msgid "tmppath cannot be NULL\n" msgstr "" #: src/testing/testing_new.c:356 #, c-format msgid "Hostkeys file not found: %s\n" msgstr "" #: src/testing/testing_new.c:365 #, fuzzy, c-format msgid "Could not open hostkeys file: %s\n" msgstr "Không thể Ä‘á»c danh sách bạn bè « %s »\n" #: src/testing/testing_new.c:380 #, c-format msgid "Incorrect hostkey file format: %s\n" msgstr "" #: src/testing/testing_new.c:437 #, fuzzy, c-format msgid "Key number %u does not exist\n" msgstr "đặt số trình ná»n cần khởi chạy" #: src/testing/testing_new.c:446 #, fuzzy, c-format msgid "Error while decoding key %u\n" msgstr "Gặp lá»—i khi tải xuống: %s\n" #: src/testing/testing_new.c:680 #, fuzzy msgid "Failed to create configuration for peer (not enough free ports?)\n" msgstr "Không thể truy cập đến thông tin vá» không gian tên.\n" #: src/testing/testing_new.c:691 #, c-format msgid "" "You attempted to create a testbed with more than %u hosts. Please " "precompute more hostkeys first.\n" msgstr "" #: src/testing/testing_new.c:704 #, fuzzy, c-format msgid "Failed to initialize hostkey for peer %u\n" msgstr "Lá»—i sÆ¡ khởi dịch vụ « %s ».\n" #: src/testing/testing_new.c:734 #, fuzzy, c-format msgid "Failed to write hostkey file for peer %u: %s\n" msgstr "Lá»—i tạo thư mục tạm thá»i." #: src/testing/testing_new.c:751 #, fuzzy, c-format msgid "Failed to write configuration file `%s' for peer %u: %s\n" msgstr "Không thể lưu tập tin cấu hình « %s »:" #: src/testing/testing_new.c:791 #, fuzzy, c-format msgid "Failed to start `%s': %s\n" msgstr "Lá»—i chạy %s: %s %d\n" #: src/testing/testing_new.c:959 #, fuzzy, c-format msgid "Failed to load configuration from %s\n" msgstr "Không thể lưu tập tin cấu hình « %s »:" #: src/topology/gnunet-daemon-topology.c:259 msgid "# peers blacklisted" msgstr "" #: src/topology/gnunet-daemon-topology.c:392 #, fuzzy msgid "# connect requests issued to transport" msgstr "# các yêu cầu máy/trình khách lá»— hổng được phun vào" #: src/topology/gnunet-daemon-topology.c:730 #: src/topology/gnunet-daemon-topology.c:815 #, fuzzy msgid "# friends connected" msgstr "# cá»§a các đồng đẳng đã kết nối" #: src/topology/gnunet-daemon-topology.c:996 msgid "Failed to connect to core service, can not manage topology!\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1026 #, fuzzy, c-format msgid "Option `%s' in section `%s' not specified!\n" msgstr "Bị từ chối đặt tùy chá»n « %s » trong phần « %s » thành « %s ».\n" #: src/topology/gnunet-daemon-topology.c:1039 #, c-format msgid "Could not read friends list `%s'\n" msgstr "Không thể Ä‘á»c danh sách bạn bè « %s »\n" #: src/topology/gnunet-daemon-topology.c:1045 #, fuzzy, c-format msgid "Friends file `%s' is empty.\n" msgstr "Äịnh dạng cá»§a tập tin « %s » là không hợp lệ.\n" #: src/topology/gnunet-daemon-topology.c:1054 #, fuzzy, c-format msgid "Failed to read friends list from `%s': out of memory\n" msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" #: src/topology/gnunet-daemon-topology.c:1062 #, c-format msgid "Failed to read friends list from `%s'\n" msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" #: src/topology/gnunet-daemon-topology.c:1082 #, fuzzy, c-format msgid "" "Syntax error in topology specification at offset %llu, skipping bytes.\n" msgstr "Lá»—i cú pháp trong sá»± xác định địa hình há»c, Ä‘ang bá» qua các byte.\n" #: src/topology/gnunet-daemon-topology.c:1095 #, fuzzy, c-format msgid "" "Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n" msgstr "" "Lá»—i cú pháp trong sá»± xác định địa hình há»c, Ä‘ang bá» qua các byte « %s ».\n" #: src/topology/gnunet-daemon-topology.c:1105 #, fuzzy, c-format msgid "Found friend `%s' in configuration\n" msgstr "" "\n" "Kết thúc cấu hình.\n" #: src/topology/gnunet-daemon-topology.c:1111 #, c-format msgid "Found myself `%s' in friend list (useless, ignored)\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1121 #, fuzzy msgid "# friends in configuration" msgstr "" "\n" "Kết thúc cấu hình.\n" #: src/topology/gnunet-daemon-topology.c:1127 msgid "" "Fewer friends specified than required by minimum friend count. Will only " "connect to friends.\n" msgstr "" "Xác định quá ít bạn bè (dưới số tối thiểu). Sẽ chỉ kết nối tá»›i bạn bè.\n" #: src/topology/gnunet-daemon-topology.c:1134 msgid "" "More friendly connections required than target total number of connections.\n" msgstr "Cần thiết nhiá»u kết nối bạn bè hÆ¡n tổng số kết nối đích.\n" #: src/topology/gnunet-daemon-topology.c:1169 #, fuzzy msgid "# HELLO messages received" msgstr "# các thông báo PONG đã mật mã được nhận" #: src/topology/gnunet-daemon-topology.c:1224 #, fuzzy msgid "# HELLO messages gossipped" msgstr "# các thông báo gá»­i Ä‘i bị loại bá»" #: src/topology/gnunet-daemon-topology.c:1363 msgid "GNUnet topology control (maintaining P2P mesh and F2F constraints)" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:246 #, fuzzy, c-format msgid "Could not read blacklist file `%s'\n" msgstr "Không thể Ä‘á»c danh sách bạn bè « %s »\n" #: src/transport/gnunet-service-transport_blacklist.c:252 #, c-format msgid "Blacklist file `%s' is empty.\n" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:263 #, fuzzy, c-format msgid "Failed to read blacklist from `%s'\n" msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" #: src/transport/gnunet-service-transport_blacklist.c:284 #: src/transport/gnunet-service-transport_blacklist.c:308 #, fuzzy, c-format msgid "Syntax error in blacklist file at offset %llu, giving up!\n" msgstr "Gặp lá»—i cú pháp trong tập tin cấu hình « %s » tại dòng %d.\n" #: src/transport/gnunet-service-transport_blacklist.c:295 #: src/transport/gnunet-service-transport_blacklist.c:331 #, fuzzy, c-format msgid "Syntax error in blacklist file at offset %llu, skipping bytes.\n" msgstr "Lá»—i cú pháp trong sá»± xác định địa hình há»c, Ä‘ang bá» qua các byte.\n" #: src/transport/gnunet-service-transport_blacklist.c:345 #, fuzzy, c-format msgid "Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n" msgstr "" "Lá»—i cú pháp trong sá»± xác định địa hình há»c, Ä‘ang bá» qua các byte « %s ».\n" #: src/transport/gnunet-service-transport_blacklist.c:359 #, c-format msgid "Found myself `%s' in blacklist (useless, ignored)\n" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:514 #: src/transport/gnunet-service-transport_blacklist.c:747 msgid "# disconnects due to blacklist" msgstr "" #: src/transport/gnunet-service-transport.c:163 #, fuzzy msgid "# bytes payload discarded due to not connected peer " msgstr "# Các quảng cáo đồng đẳng bị há»§y do trá»ng tải" #: src/transport/gnunet-service-transport.c:237 #, fuzzy msgid "# bytes total received" msgstr "# tổng số ná»™i dung lá»— hổng được nhận" #: src/transport/gnunet-service-transport.c:284 #, fuzzy msgid "# bytes payload received" msgstr "# các byte đã giải mã" #: src/transport/gnunet-service-transport.c:582 msgid "Transport service is lacking key configuration settings. Exiting.\n" msgstr "" #: src/transport/gnunet-service-transport.c:591 msgid "Transport service could not access hostkey. Exiting.\n" msgstr "" #: src/transport/gnunet-service-transport_clients.c:352 #, c-format msgid "Dropping message of type %u and size %u, have %u/%u messages pending\n" msgstr "" #: src/transport/gnunet-service-transport_clients.c:357 #, fuzzy msgid "# messages dropped due to slow client" msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" #: src/transport/gnunet-service-transport_clients.c:503 #, c-format msgid "Rejecting control connection from peer `%s', which is not me!\n" msgstr "" #: src/transport/gnunet-service-transport_clients.c:631 msgid "# bytes payload dropped (other peer was not connected)" msgstr "" #: src/transport/gnunet-service-transport_clients.c:682 #, fuzzy msgid "# REQUEST CONNECT messages received" msgstr "# các thông báo PONG đã mật mã được nhận" #: src/transport/gnunet-service-transport_hello.c:172 msgid "# refreshed my HELLO" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1032 #, fuzzy msgid "# DISCONNECT messages sent" msgstr "# các thông báo PONG đã mật mã được nhận" #: src/transport/gnunet-service-transport_neighbours.c:1148 #: src/transport/gnunet-service-transport_neighbours.c:1482 #, fuzzy msgid "# bytes in message queue for other peers" msgstr "# các byte thông báo gá»­i Ä‘i bị loại bá»" #: src/transport/gnunet-service-transport_neighbours.c:1153 #, fuzzy msgid "# messages transmitted to other peers" msgstr "# các byte kiểu %d được gá»­i " #: src/transport/gnunet-service-transport_neighbours.c:1158 #, fuzzy msgid "# transmission failures for messages to other peers" msgstr "# các byte thông báo gá»­i Ä‘i bị loại bá»" #: src/transport/gnunet-service-transport_neighbours.c:1215 msgid "# messages timed out while in transport queue" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1254 #, fuzzy msgid "# keepalives sent" msgstr "# các khoá phiên chạy được gá»­i" #: src/transport/gnunet-service-transport_neighbours.c:1278 #, fuzzy msgid "# KEEPALIVE messages discarded (peer unknown)" msgstr "# các thông báo được chắp liá»n" #: src/transport/gnunet-service-transport_neighbours.c:1286 #, fuzzy msgid "# KEEPALIVE messages discarded (no session)" msgstr "# các thông báo được chắp liá»n" #: src/transport/gnunet-service-transport_neighbours.c:1323 #, fuzzy msgid "# KEEPALIVE_RESPONSE messages discarded (not connected)" msgstr "# các thông báo được chắp liá»n" #: src/transport/gnunet-service-transport_neighbours.c:1332 #, fuzzy msgid "# KEEPALIVE_RESPONSE messages discarded (not expected)" msgstr "# các thông báo được chắp liá»n" #: src/transport/gnunet-service-transport_neighbours.c:1388 #, fuzzy msgid "# messages discarded due to lack of neighbour record" msgstr "# các thông báo được chắp liá»n" #: src/transport/gnunet-service-transport_neighbours.c:1422 #, fuzzy msgid "# bandwidth quota violations by other peers" msgstr "theo dõi gnunetd sá»­ dụng dải thông" #: src/transport/gnunet-service-transport_neighbours.c:1438 msgid "# ms throttling suggested" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2544 #, fuzzy msgid "# unexpected CONNECT_ACK messages (no peer)" msgstr "gá»­i ÄẾM thông báo" #: src/transport/gnunet-service-transport_neighbours.c:2559 #: src/transport/gnunet-service-transport_neighbours.c:2585 #, fuzzy msgid "# unexpected CONNECT_ACK messages (not ready)" msgstr "gá»­i ÄẾM thông báo" #: src/transport/gnunet-service-transport_neighbours.c:2598 #, fuzzy msgid "# unexpected CONNECT_ACK messages (waiting on ATS)" msgstr "gá»­i ÄẾM thông báo" #: src/transport/gnunet-service-transport_neighbours.c:2627 #, fuzzy msgid "# unexpected CONNECT_ACK messages (disconnecting)" msgstr "gá»­i ÄẾM thông báo" #: src/transport/gnunet-service-transport_neighbours.c:2807 #, fuzzy msgid "# unexpected SESSION ACK messages" msgstr "# các thông báo PONG đã mật mã được gá»­i" #: src/transport/gnunet-service-transport_neighbours.c:2856 msgid "# SET QUOTA messages ignored (no such peer)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2870 msgid "# disconnects due to quota of 0" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2901 msgid "# disconnect messages ignored (old format)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2912 msgid "# disconnect messages ignored (timestamp)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2943 msgid "# other peer asked to disconnect from us" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:3020 #, fuzzy msgid "# disconnected from peer upon explicit request" msgstr "# các yêu cầu lá»— hổng bị bá» do trá»ng tải" #: src/transport/gnunet-service-transport_plugins.c:111 msgid "Transport service is lacking NEIGHBOUR_LIMIT option.\n" msgstr "" #: src/transport/gnunet-service-transport_validation.c:414 msgid "# address records discarded" msgstr "" #: src/transport/gnunet-service-transport_validation.c:463 #, c-format msgid "" "Not transmitting `%s' with `%s', message too big (%u bytes!). This should " "not happen.\n" msgstr "" #: src/transport/gnunet-service-transport_validation.c:512 #, fuzzy msgid "# PING without HELLO messages sent" msgstr "# các thông báo PONG nhập thô được gá»­i" #: src/transport/gnunet-service-transport_validation.c:570 msgid "# address revalidations started" msgstr "" #: src/transport/gnunet-service-transport_validation.c:805 #, fuzzy msgid "# PING message for different peer received" msgstr "# các thông báo PING được tạo" #: src/transport/gnunet-service-transport_validation.c:840 #, c-format msgid "" "Not confirming PING with address `%s' since I cannot confirm having this " "address.\n" msgstr "" #: src/transport/gnunet-service-transport_validation.c:924 msgid "# PONGs unicast via reliable transport" msgstr "" #: src/transport/gnunet-service-transport_validation.c:933 msgid "# PONGs multicast to all available addresses" msgstr "" #: src/transport/gnunet-service-transport_validation.c:1055 msgid "# PONGs dropped, no matching pending validation" msgstr "" #: src/transport/gnunet-service-transport_validation.c:1080 msgid "# PONGs dropped, signature expired" msgstr "" #: src/transport/gnunet-service-transport_validation.c:1136 #, fuzzy, c-format msgid "Adding `%s' without addresses for peer `%s'\n" msgstr "Không thể lấy địa chỉ cá»§a đồng đẳng « %s ».\n" #: src/transport/gnunet-transport.c:260 msgid "No transport plugins configured, peer will never communicate\n" msgstr "" #: src/transport/gnunet-transport.c:273 #, c-format msgid "No port configured for plugin `%s', cannot test it\n" msgstr "" #: src/transport/gnunet-transport.c:323 #, c-format msgid "Received %llu bytes/s (%llu bytes in %llu ms)\n" msgstr "" #: src/transport/gnunet-transport.c:330 #, c-format msgid "Transmitted %llu bytes/s (%llu bytes in %llu ms)\n" msgstr "" #: src/transport/gnunet-transport.c:363 #, fuzzy, c-format msgid "Transmitting %u bytes to %s\n" msgstr "Äang thá»­ tải danh sách các máy xuống « %s »\n" #: src/transport/gnunet-transport.c:383 #, fuzzy, c-format msgid "Connected to %s\n" msgstr "« %s » được kết nối tá»›i « %s ».\n" #: src/transport/gnunet-transport.c:414 #, fuzzy, c-format msgid "Disconnected from %s\n" msgstr "« %.*s » được kết nối tá»›i « %.*s ».\n" #: src/transport/gnunet-transport.c:443 #, fuzzy, c-format msgid "Received %u bytes from %s\n" msgstr "Nhận yêu cầu định tuyến\n" #: src/transport/gnunet-transport.c:466 #, fuzzy, c-format msgid "Peer `%s': %s %s\n" msgstr "Tôi là đồng đẳng « %s ».\n" #: src/transport/gnunet-transport.c:473 #, c-format msgid "Peer `%s': %s \n" msgstr "" #: src/transport/gnunet-transport.c:501 #, fuzzy, c-format msgid "Peer `%s' disconnected\n" msgstr "# cá»§a các đồng đẳng đã kết nối" #: src/transport/gnunet-transport.c:569 #, fuzzy, c-format msgid "Failed to parse peer identity `%s'\n" msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" #: src/transport/gnunet-transport.c:618 msgid "measure how fast we are receiving data (until CTRL-C)" msgstr "" #: src/transport/gnunet-transport.c:621 #, fuzzy msgid "try to connect to the given peer" msgstr "Lá»—i kết nối đến gnunetd.\n" #: src/transport/gnunet-transport.c:624 #, fuzzy msgid "provide information about all current connections (once)" msgstr "In ra thông tin vá» các đồng đẳng GNUnet." #: src/transport/gnunet-transport.c:627 #, fuzzy msgid "provide information about all current connections (continuously)" msgstr "In ra thông tin vá» các đồng đẳng GNUnet." #: src/transport/gnunet-transport.c:630 #, fuzzy msgid "do not resolve hostnames" msgstr "không quyết định các tên máy" #: src/transport/gnunet-transport.c:634 msgid "send data for benchmarking to the other peer (until CTRL-C)" msgstr "" #: src/transport/gnunet-transport.c:637 msgid "test transport configuration (involves external server)" msgstr "" #: src/transport/gnunet-transport.c:645 #, fuzzy msgid "Direct access to transport service." msgstr "Lá»—i kết nối đến gnunetd.\n" #: src/transport/plugin_transport_http.c:1100 msgid "Disabling IPv6 since it is not supported on this system!\n" msgstr "" #: src/transport/plugin_transport_http.c:1149 #, fuzzy msgid "Require valid port number for service in configuration!\n" msgstr "Lá»—i lưu cấu hình." #: src/transport/plugin_transport_http.c:1174 src/util/service.c:1036 #, fuzzy, c-format msgid "Failed to resolve `%s': %s\n" msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" #: src/transport/plugin_transport_http.c:1191 src/util/service.c:1053 #, fuzzy, c-format msgid "Failed to find %saddress for `%s'.\n" msgstr "Lá»—i đóng kết đến cổng %s %d.\n" #: src/transport/plugin_transport_http.c:1296 #, c-format msgid "Found %u addresses to report to NAT service\n" msgstr "" #: src/transport/plugin_transport_http.c:1309 #, c-format msgid "FREEING %s\n" msgstr "" #: src/transport/plugin_transport_http.c:1386 msgid "Neither IPv4 nor IPv6 are enabled! Fix in configuration\n" msgstr "" #: src/transport/plugin_transport_http.c:1399 #, fuzzy msgid "Port is required! Fix in configuration\n" msgstr "" "\n" "Kết thúc cấu hình.\n" #: src/transport/plugin_transport_http.c:1410 msgid "Port 0, client only mode\n" msgstr "" #: src/transport/plugin_transport_http.c:1430 #, c-format msgid "" "Specific IPv4 address `%s' for plugin %s in configuration file is invalid! " "Binding to all addresses!\n" msgstr "" #: src/transport/plugin_transport_http.c:1460 #, c-format msgid "" "Specific IPv6 address `%s' for plugin %s in configuration file is invalid! " "Binding to all addresses!\n" msgstr "" #: src/transport/plugin_transport_http_client.c:624 #, c-format msgid "Could not initialize curl multi handle, failed to start %s plugin!\n" msgstr "" #: src/transport/plugin_transport_http_server.c:178 msgid "" "Could not create a new TLS certificate, program `gnunet-transport-" "certificate-creation' could not be started!\n" msgstr "" #: src/transport/plugin_transport_http_server.c:202 msgid "No usable TLS certificate found and creating one failed!\n" msgstr "" #: src/transport/plugin_transport_tcp.c:591 #, fuzzy, c-format msgid "Unexpected address length: %u bytes\n" msgstr "Gặp sá»± kiện bất thưá»ng: %d\n" #: src/transport/plugin_transport_tcp.c:767 #: src/transport/plugin_transport_tcp.c:856 #: src/transport/plugin_transport_tcp.c:906 #: src/transport/plugin_transport_tcp.c:992 #: src/transport/plugin_transport_tcp.c:1086 #: src/transport/plugin_transport_tcp.c:1103 #, fuzzy msgid "# bytes currently in TCP buffers" msgstr "# các byte đã gừi qua TCP" #: src/transport/plugin_transport_tcp.c:774 #: src/transport/plugin_transport_tcp.c:963 #: src/transport/plugin_transport_tcp.c:1761 #: src/transport/plugin_transport_tcp.c:2390 #, fuzzy msgid "# TCP sessions active" msgstr "# các khoá phiên chạy được chấp nhận" #: src/transport/plugin_transport_tcp.c:860 #, fuzzy msgid "# bytes discarded by TCP (timeout)" msgstr "# các byte loại Ä‘i bởi TCP (Ä‘i ra)" #: src/transport/plugin_transport_tcp.c:909 #, fuzzy msgid "# bytes transmitted via TCP" msgstr "# các byte được gá»­i" #: src/transport/plugin_transport_tcp.c:996 #, fuzzy msgid "# bytes discarded by TCP (disconnect)" msgstr "# các byte loại Ä‘i bởi TCP (Ä‘i ra)" #: src/transport/plugin_transport_tcp.c:1290 #, fuzzy, c-format msgid "Address of unexpected length: %u\n" msgstr "Gặp sá»± kiện bất thưá»ng: %d\n" #: src/transport/plugin_transport_tcp.c:1401 msgid "# transport-service disconnect requests for TCP" msgstr "" #: src/transport/plugin_transport_tcp.c:1802 #, fuzzy msgid "# TCP WELCOME messages received" msgstr "# các thông báo PONG đã mật mã được nhận" #: src/transport/plugin_transport_tcp.c:1973 msgid "# bytes received via TCP" msgstr "# các byte đã nhận qua TCP" #: src/transport/plugin_transport_tcp.c:2043 msgid "# network-level TCP disconnect events" msgstr "" #: src/transport/plugin_transport_tcp.c:2279 src/util/service.c:940 #, c-format msgid "Require valid port number for service `%s' in configuration!\n" msgstr "" #: src/transport/plugin_transport_tcp.c:2293 #, fuzzy msgid "Failed to start service.\n" msgstr "Lá»—i bắt đầu thu thập.\n" #: src/transport/plugin_transport_tcp.c:2355 #, fuzzy, c-format msgid "Failed to find option %s in section %s!\n" msgstr "Lá»—i đóng kết đến cổng %s %d.\n" #: src/transport/plugin_transport_tcp.c:2378 #, c-format msgid "TCP transport listening on port %llu\n" msgstr "" #: src/transport/plugin_transport_tcp.c:2382 msgid "TCP transport not listening on any port (client only)\n" msgstr "" #: src/transport/plugin_transport_tcp.c:2386 #, c-format msgid "TCP transport advertises itself as being on port %llu\n" msgstr "" #: src/transport/plugin_transport_udp_broadcasting.c:128 #, fuzzy msgid "# IPv6 multicast HELLO beacons received via udp" msgstr "# các thông báo PONG đã mật mã được nhận" #: src/transport/plugin_transport_udp_broadcasting.c:169 #, fuzzy msgid "# IPv4 broadcast HELLO beacons received via udp" msgstr "# các thông báo PONG đã mật mã được nhận" #: src/transport/plugin_transport_udp_broadcasting.c:367 #, c-format msgid "Failed to set IPv4 broadcast option for broadcast socket on port %d\n" msgstr "" #: src/transport/plugin_transport_udp.c:1894 #, c-format msgid "" "UDP could not message to `%s': `%s'. Please check your network configuration " "and disable IPv6 if your connection does not have a global IPv6 address\n" msgstr "" #: src/transport/plugin_transport_udp.c:2138 #, fuzzy msgid "Failed to open UDP sockets\n" msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" #: src/transport/plugin_transport_udp.c:2306 #, c-format msgid "Given `%s' option is out of range: %llu > %u\n" msgstr "" #: src/transport/plugin_transport_udp.c:2349 #, fuzzy, c-format msgid "Invalid IPv6 address: `%s'\n" msgstr "Mức ưu tiên tiến trình không hợp lê « %s ».\n" #: src/transport/plugin_transport_unix.c:1356 #, fuzzy msgid "Failed to open UNIX sockets\n" msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" #: src/transport/plugin_transport_wlan.c:561 msgid "# WLAN ACKs sent" msgstr "" #: src/transport/plugin_transport_wlan.c:580 #, fuzzy msgid "# WLAN messages defragmented" msgstr "# các thông báo được chắp liá»n" #: src/transport/plugin_transport_wlan.c:626 #: src/transport/plugin_transport_wlan.c:676 #: src/transport/plugin_transport_wlan.c:1696 #, fuzzy msgid "# WLAN sessions allocated" msgstr "# các khoá phiên chạy được chấp nhận" #: src/transport/plugin_transport_wlan.c:749 #, fuzzy msgid "# WLAN message fragments sent" msgstr "# các thông báo bị tế phân" #: src/transport/plugin_transport_wlan.c:767 msgid "# WLAN messages pending (with fragmentation)" msgstr "" #: src/transport/plugin_transport_wlan.c:867 #: src/transport/plugin_transport_wlan.c:948 #: src/transport/plugin_transport_wlan.c:1698 #, fuzzy msgid "# WLAN MAC endpoints allocated" msgstr "# các yêu cầu get (lấy) dht được nhận" #: src/transport/plugin_transport_wlan.c:1119 #, fuzzy msgid "# HELLO messages received via WLAN" msgstr "# các thông báo PONG đã mật mã được nhận" #: src/transport/plugin_transport_wlan.c:1140 #, fuzzy msgid "# fragments received via WLAN" msgstr "# các mảnh bị loại bá»" #: src/transport/plugin_transport_wlan.c:1150 #, fuzzy msgid "# ACKs received via WLAN" msgstr "# các byte đã nhận qua TCP" #: src/transport/plugin_transport_wlan.c:1207 #, fuzzy msgid "# WLAN DATA messages discarded due to CRC32 error" msgstr "# các thông báo được chắp liá»n" #: src/transport/plugin_transport_wlan.c:1306 #, fuzzy msgid "# DATA messages received via WLAN" msgstr "# các thông báo PONG đã mật mã được nhận" #: src/transport/plugin_transport_wlan.c:1341 #, fuzzy msgid "# WLAN DATA messages processed" msgstr "# các thông báo PONG đã mật mã được nhận" #: src/transport/plugin_transport_wlan.c:1402 #, fuzzy msgid "# HELLO beacons sent via WLAN" msgstr "# các byte đã gá»­i qua UDP" #: src/transport/plugin_transport_wlan.c:1511 msgid "WLAN address with invalid size encountered\n" msgstr "" #: src/transport/plugin_transport_wlan.c:1668 #, fuzzy, c-format msgid "Invalid configuration option `%s' in section `%s'\n" msgstr "Giá trị cấu hình « %s » cho « %s » trong phần « %s » nên là con số\n" #: src/transport/plugin_transport_wlan.c:1677 #, c-format msgid "Helper binary `%s' not SUID, cannot run WLAN transport\n" msgstr "" #: src/transport/plugin_transport_wlan.c:1687 #, fuzzy, c-format msgid "Missing configuration option `%s' in section `%s'\n" msgstr "Giá trị cấu hình « %s » cho « %s » trong phần « %s » nên là con số\n" #: src/transport/transport_api.c:570 #, fuzzy, c-format msgid "Received unexpected message of type %u in %s:%u\n" msgstr "Nhận được thông báo bị há»ng từ đồng đẳng « %s » trong %s:%d.\n" #: src/util/bio.c:136 src/util/bio.c:142 #, fuzzy, c-format msgid "Error reading `%s': %s" msgstr "Gặp lá»—i khi tạo ngưá»i dùng" #: src/util/bio.c:143 msgid "End of file" msgstr "" #: src/util/bio.c:195 #, c-format msgid "Error reading length of string `%s'" msgstr "" #: src/util/bio.c:205 #, c-format msgid "String `%s' longer than allowed (%u > %u)" msgstr "" #: src/util/bio.c:250 #, c-format msgid "Serialized metadata `%s' larger than allowed (%u>%u)" msgstr "" #: src/util/bio.c:264 #, c-format msgid "Metadata `%s' failed to deserialize" msgstr "" #: src/util/client.c:359 #, c-format msgid "" "Could not determine valid hostname and port for service `%s' from " "configuration.\n" msgstr "" #: src/util/client.c:367 #, c-format msgid "Need a non-empty hostname for service `%s'.\n" msgstr "" #: src/util/client.c:685 msgid "Failure to transmit TEST request.\n" msgstr "" #: src/util/client.c:740 src/util/service.c:970 #, c-format msgid "UNIXPATH `%s' too long, maximum length is %llu\n" msgstr "" #: src/util/client.c:882 #, c-format msgid "Could not connect to service `%s', must not be running.\n" msgstr "" #: src/util/client.c:896 #, fuzzy, c-format msgid "Failure to transmit request to service `%s'\n" msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" #: src/util/client.c:1149 msgid "Could not submit request, not expecting to receive a response.\n" msgstr "" #: src/util/common_logging.c:239 src/util/common_logging.c:890 msgid "DEBUG" msgstr "Gá»  Lá»–I" #: src/util/common_logging.c:241 src/util/common_logging.c:888 msgid "INFO" msgstr "TIN" #: src/util/common_logging.c:243 src/util/common_logging.c:886 msgid "WARNING" msgstr "CẢNH BÃO" #: src/util/common_logging.c:245 src/util/common_logging.c:884 msgid "ERROR" msgstr "Lá»–I" #: src/util/common_logging.c:247 src/util/common_logging.c:892 msgid "NONE" msgstr "" #: src/util/common_logging.c:610 #, fuzzy, c-format msgid "Failed to create or access directory for log file `%s'\n" msgstr "Không thể truy cập đến tập tin gnunet-directory « %s »\n" #: src/util/common_logging.c:725 #, fuzzy, c-format msgid "Message `%.*s' repeated %u times in the last %s\n" msgstr "Thông Ä‘iệp « %.*s » đã lặp lại %u lần trong %llu giây trước\n" #: src/util/common_logging.c:893 msgid "INVALID" msgstr "" #: src/util/common_logging.c:992 msgid "unknown address" msgstr "" #: src/util/common_logging.c:1030 msgid "invalid address" msgstr "" #: src/util/configuration.c:244 #, fuzzy, c-format msgid "Syntax error in configuration file `%s' at line %u.\n" msgstr "Gặp lá»—i cú pháp trong tập tin cấu hình « %s » tại dòng %d.\n" #: src/util/configuration.c:816 #, c-format msgid "" "Configuration value '%s' for '%s' in section '%s' is not in set of legal " "choices\n" msgstr "" "Giá trị cấu hình « %s » cho « %s » trong phần « %s » không phải nằm trong " "tập hợp các sá»± chá»n được phép\n" #: src/util/connection.c:420 #, fuzzy, c-format msgid "Access denied to `%s'\n" msgstr "Không đủ quyá»n cho « %s ».\n" #: src/util/connection.c:435 #, c-format msgid "Accepting connection from `%s': %p\n" msgstr "" #: src/util/connection.c:550 #, fuzzy, c-format msgid "" "Failed to establish TCP connection to `%s:%u', no further addresses to try.\n" msgstr "Lá»—i thiết lập kết nối vá»›i đồng đẳng.\n" #: src/util/connection.c:739 src/util/connection.c:909 #, fuzzy, c-format msgid "Trying to connect to `%s' (%p)\n" msgstr "Không thể kết nối tá»›i %s:%u: %s\n" #: src/util/connection.c:748 #, fuzzy, c-format msgid "Failed to connect to `%s' (%p)\n" msgstr "Không thể kết nối tá»›i %s:%u: %s\n" #: src/util/connection.c:900 #, fuzzy, c-format msgid "Attempt to connect to `%s' failed\n" msgstr " Lá»—i kết nối\n" #: src/util/container_bloomfilter.c:510 #, c-format msgid "" "Size of file on disk is incorrect for this Bloom filter (want %llu, have " "%llu)\n" msgstr "" #: src/util/crypto_random.c:280 #, c-format msgid "Starting `%s' process to generate entropy\n" msgstr "" #: src/util/crypto_random.c:309 #, c-format msgid "libgcrypt has not the expected version (version %s is required).\n" msgstr "libgcrypt không có phiên bản mong đợi (yêu cầu phiên bản %s).\n" #: src/util/crypto_rsa.c:661 src/util/crypto_rsa.c:708 #, fuzzy, c-format msgid "Could not aquire lock on file `%s': %s...\n" msgstr "Lá»—i mở tập tin theo dõi « %s »: %s\n" #: src/util/crypto_rsa.c:666 #, fuzzy msgid "Creating a new private key. This may take a while.\n" msgstr "Äang tạo khoá máy má»›i (có thể hÆ¡i lâu).\n" #: src/util/crypto_rsa.c:684 #, c-format msgid "I am host `%s'. Stored new private key in `%s'.\n" msgstr "" #: src/util/crypto_rsa.c:712 src/util/crypto_rsa.c:748 msgid "This may be ok if someone is currently generating a hostkey.\n" msgstr "" #: src/util/crypto_rsa.c:743 #, c-format msgid "" "When trying to read hostkey file `%s' I found %u bytes but I need at least " "%u.\n" msgstr "" #: src/util/crypto_rsa.c:763 #, fuzzy, c-format msgid "File `%s' does not contain a valid private key. Deleting it.\n" msgstr "Tập tin « %s » không chứa biệt hiệu nên thá»­ gỡ bá».\n" #: src/util/crypto_rsa.c:781 #, c-format msgid "I am host `%s'. Read private key from `%s'.\n" msgstr "" #: src/util/crypto_rsa.c:1032 #, c-format msgid "RSA signature verification failed at %s:%d: %s\n" msgstr "Lá»—i thẩm tra chữ ký RSA tại %s:%d: %s\n" #: src/util/disk.c:498 #, fuzzy, c-format msgid "`%s' failed for drive `%S': %u\n" msgstr "« %s » thất bại cho ổ đĩa « %s »: %u\n" #: src/util/disk.c:1062 #, c-format msgid "Expected `%s' to be a directory!\n" msgstr "Mong đợi « %s » là má»™t thư mục.\n" #: src/util/disk.c:1416 src/util/service.c:1650 #, c-format msgid "Cannot obtain information about user `%s': %s\n" msgstr "Không thể lấy thông tin vá» ngưá»i dùng « %s »: %s\n" #: src/util/disk.c:1734 #, c-format msgid "No `%s' specified for service `%s' in configuration.\n" msgstr "" #: src/util/getopt.c:669 #, c-format msgid "%s: option `%s' is ambiguous\n" msgstr "%s: tùy chá»n « %s » là mÆ¡ hồ\n" #: src/util/getopt.c:693 #, c-format msgid "%s: option `--%s' does not allow an argument\n" msgstr "%s: tùy chá»n « --%s » không cho phép đối số\n" #: src/util/getopt.c:698 #, c-format msgid "%s: option `%c%s' does not allow an argument\n" msgstr "%s: tùy chá»n « %c%s » không cho phép đối số\n" #: src/util/getopt.c:715 src/util/getopt.c:883 #, c-format msgid "%s: option `%s' requires an argument\n" msgstr "%s: tùy chá»n « %s » cần thiết đối số\n" #: src/util/getopt.c:744 #, c-format msgid "%s: unrecognized option `--%s'\n" msgstr "%s: không nhận ra tùy chá»n « --%s »\n" #: src/util/getopt.c:748 #, c-format msgid "%s: unrecognized option `%c%s'\n" msgstr "%s: không nhận ra tùy chá»n « %c%s »\n" #: src/util/getopt.c:773 #, c-format msgid "%s: illegal option -- %c\n" msgstr "%s: tùy chá»n không được phép -- %c\n" #: src/util/getopt.c:775 #, c-format msgid "%s: invalid option -- %c\n" msgstr "%s: tùy chá»n không hợp lệ -- %c\n" #: src/util/getopt.c:803 src/util/getopt.c:931 #, c-format msgid "%s: option requires an argument -- %c\n" msgstr "%s: tùy chá»n cần thiết đối số -- %c\n" #: src/util/getopt.c:851 #, c-format msgid "%s: option `-W %s' is ambiguous\n" msgstr "%s: tùy chá»n « -W %s » là mÆ¡ hồ\n" #: src/util/getopt.c:869 #, c-format msgid "%s: option `-W %s' does not allow an argument\n" msgstr "%s: tùy chá»n « -W %s » không cho phép đối số\n" #: src/util/getopt.c:1035 #, fuzzy, c-format msgid "Use %s to get a list of options.\n" msgstr "" "Hãy sá»­ dụng câu lệnh trợ giúp « --help » để xem danh sách các tùy chá»n.\n" #: src/util/getopt_helpers.c:86 #, c-format msgid "" "Arguments mandatory for long options are also mandatory for short options.\n" msgstr "" "Má»i đối số bắt buá»™c phải sá»­ dụng vá»›i tùy chá»n dài cÅ©ng bắt buá»™c vá»›i tùy chá»n " "ngắn.\n" #: src/util/getopt_helpers.c:258 src/util/getopt_helpers.c:286 #, c-format msgid "You must pass a number to the `%s' option.\n" msgstr "Phải gá»­i má»™t con số cho tùy chá»n « %s ».\n" #: src/util/gnunet-resolver.c:148 msgid "perform a reverse lookup" msgstr "" #: src/util/gnunet-resolver.c:154 msgid "Use build-in GNUnet stub resolver" msgstr "" #: src/util/gnunet-rsa.c:64 #, c-format msgid "No hostkey file specified on command line\n" msgstr "" #: src/util/gnunet-rsa.c:112 msgid "print the public key in ASCII format" msgstr "" #: src/util/gnunet-rsa.c:115 msgid "print the hash of the public key in ASCII format" msgstr "" #: src/util/gnunet-rsa.c:118 msgid "print the short hash of the public key in ASCII format" msgstr "" #: src/util/gnunet-rsa.c:124 msgid "Manipulate GNUnet private RSA key files" msgstr "" #: src/util/gnunet-service-resolver.c:288 #, c-format msgid "Could not resolve `%s' (%s): %s\n" msgstr "Không thể giải quyết « %s » (%s): %s\n" #: src/util/gnunet-service-resolver.c:358 #: src/util/gnunet-service-resolver.c:399 #, c-format msgid "Could not find IP of host `%s': %s\n" msgstr "Không tìm thấy địa chỉ IP cá»§a máy « %s »: %s\n" #: src/util/helper.c:244 #, fuzzy, c-format msgid "Error reading from `%s': %s\n" msgstr "Gặp lá»—i khi tạo ngưá»i dùng" #: src/util/helper.c:259 #, c-format msgid "Got 0 bytes from helper `%s' (EOF)\n" msgstr "" #: src/util/helper.c:269 #, fuzzy, c-format msgid "Got %u bytes from helper `%s'\n" msgstr "Nhận yêu cầu định tuyến\n" #: src/util/helper.c:278 #, fuzzy, c-format msgid "Failed to parse inbound message from helper `%s'\n" msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" #: src/util/helper.c:310 #, fuzzy, c-format msgid "Starting HELPER process `%s'\n" msgstr "Äang bắt đầu tài vỠ« %s »\n" #: src/util/helper.c:440 #, fuzzy, c-format msgid "Error writing to `%s': %s\n" msgstr "Gặp lá»—i khi tạo ngưá»i dùng" #: src/util/network.c:1200 #, c-format msgid "" "Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n" msgstr "" #: src/util/os_installation.c:299 #, c-format msgid "" "Could not determine installation path for %s. Set `%s' environment " "variable.\n" msgstr "" #: src/util/os_installation.c:486 #, fuzzy, c-format msgid "Could not find binary `%s' in PATH!\n" msgstr "Không thể Ä‘á»c danh sách bạn bè « %s »\n" #: src/util/os_installation.c:492 #, fuzzy, c-format msgid "access (%s, X_OK) failed: %s\n" msgstr "SMTP: « %s » bị lá»—i: %s\n" #: src/util/os_installation.c:507 #, fuzzy, c-format msgid "stat (%s) failed: %s\n" msgstr "SMTP: « %s » bị lá»—i: %s\n" #: src/util/os_priority.c:305 #, fuzzy, c-format msgid "Failed to open named pipe `%s' for reading: %s\n" msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" #: src/util/os_priority.c:306 #, fuzzy, c-format msgid "Failed to open named pipe `%s' for writing: %s\n" msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" #: src/util/plugin.c:89 #, c-format msgid "Initialization of plugin mechanism failed: %s!\n" msgstr "Lá»—i sÆ¡ khởi cÆ¡ chế phần bổ sung: %s\n" #: src/util/plugin.c:146 #, c-format msgid "`%s' failed to resolve method '%s' with error: %s\n" msgstr "« %s » không giải quyết được phương pháp « %s », vá»›i lá»—i: %s\n" #: src/util/plugin.c:219 #, c-format msgid "`%s' failed for library `%s' with error: %s\n" msgstr "« %s » thất bại cho thư viện « %s » vá»›i lá»—i: %s\n" #: src/util/plugin.c:349 #, fuzzy msgid "Could not determine plugin installation path.\n" msgstr "Không thể truy cập đến thông tin vá» không gian tên.\n" #: src/util/pseudonym.c:276 #, fuzzy, c-format msgid "Failed to parse metadata about pseudonym from file `%s': %s\n" msgstr "Lá»—i phân tích dữ liệu giao diện từ « %s ».\n" #: src/util/pseudonym.c:407 src/util/pseudonym.c:433 msgid "no-name" msgstr "không-tên" #: src/util/resolver_api.c:202 #, fuzzy, c-format msgid "Must specify `%s' for `%s' in configuration!\n" msgstr "Äang thá»­ dùng tập tin « %s » cho cấu hình MySQL.\n" #: src/util/resolver_api.c:221 #, c-format msgid "" "Must specify `%s' or numeric IP address for `%s' of `%s' in configuration!\n" msgstr "" #: src/util/resolver_api.c:347 #, fuzzy, c-format msgid "Timeout trying to resolve IP address `%s'.\n" msgstr "GNUnet bây giá» sá»­ dụng địa chỉ IP %s.\n" #: src/util/resolver_api.c:351 #, fuzzy, c-format msgid "Timeout trying to resolve hostname `%s'.\n" msgstr "không quyết định các tên máy" #: src/util/resolver_api.c:890 #, fuzzy, c-format msgid "Could not resolve our FQDN : %s\n" msgstr "Không thể giải quyết « %s » (%s): %s\n" #: src/util/scheduler.c:786 msgid "Looks like we're busy waiting...\n" msgstr "" #: src/util/scheduler.c:916 #, c-format msgid "Attempt to cancel dead task %llu!\n" msgstr "" #: src/util/server.c:483 #, fuzzy, c-format msgid "`%s' failed for port %d (%s).\n" msgstr "« %s » thất bại cho ổ đĩa « %s »: %u\n" #: src/util/server.c:492 #, fuzzy, c-format msgid "`%s' failed for port %d (%s): address already in use\n" msgstr "« %s » bị lá»—i cho cổng %d. Trình gnunetd có chạy chưa?\n" #: src/util/server.c:497 #, fuzzy, c-format msgid "`%s' failed for `%s': address already in use\n" msgstr "« %s » bị lá»—i cho cổng %d. Trình gnunetd có chạy chưa?\n" #: src/util/server.c:827 #, c-format msgid "" "Processing code for message of type %u did not call " "GNUNET_SERVER_receive_done after %llums\n" msgstr "" #: src/util/service.c:135 src/util/service.c:161 src/util/service.c:204 #: src/util/service.c:225 src/util/service.c:232 #, c-format msgid "Invalid format for IP: `%s'\n" msgstr "Äịa chỉ IP định dạng sai: %s\n" #: src/util/service.c:188 #, c-format msgid "Invalid network notation ('/%d' is not legal in IPv4 CIDR)." msgstr "Ký hiệu mạng sai (« /%d » không hợp lệ trong CIDR IPv4)." #: src/util/service.c:281 #, c-format msgid "Invalid network notation (does not end with ';': `%s')\n" msgstr "Ký hiệu mạng sai (không kết thúc vá»›i « ; »: « %s »)\n" #: src/util/service.c:313 #, fuzzy, c-format msgid "Wrong format `%s' for netmask\n" msgstr "Mặt nạ mạng có định dạng sai « %s »: %s\n" #: src/util/service.c:343 #, fuzzy, c-format msgid "Wrong format `%s' for network\n" msgstr "Mạng có định dạng sai « %s »: %s\n" #: src/util/service.c:698 #, c-format msgid "Access denied to UID %d / GID %d\n" msgstr "" #: src/util/service.c:703 #, fuzzy, c-format msgid "Unknown address family %d\n" msgstr "\tKhông rõ miá»n tên « %s »\n" #: src/util/service.c:710 #, c-format msgid "Access from `%s' denied to service `%s'\n" msgstr "" #: src/util/service.c:765 #, c-format msgid "Could not parse IPv4 network specification `%s' for `%s:%s'\n" msgstr "" #: src/util/service.c:802 #, c-format msgid "Could not parse IPv6 network specification `%s' for `%s:%s'\n" msgstr "" #: src/util/service.c:920 #, c-format msgid "" "Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n" msgstr "" #: src/util/service.c:990 #, c-format msgid "" "Disabling UNIX domain socket support for service `%s', failed to create UNIX " "domain socket: %s\n" msgstr "" #: src/util/service.c:1007 #, c-format msgid "Have neither PORT nor UNIXPATH for service `%s', but one is required\n" msgstr "" #: src/util/service.c:1241 msgid "Could not access a pre-bound socket, will try to bind myself\n" msgstr "" #: src/util/service.c:1292 src/util/service.c:1310 #, c-format msgid "Specified value for `%s' of service `%s' is invalid\n" msgstr "" #: src/util/service.c:1337 #, c-format msgid "Could not access pre-bound socket %u, will try to bind myself\n" msgstr "" #: src/util/service.c:1506 #, fuzzy, c-format msgid "Failed to start `%s' at `%s'\n" msgstr "Lá»—i chạy %s: %s %d\n" #: src/util/service.c:1539 #, fuzzy, c-format msgid "Service `%s' runs at %s\n" msgstr "Äồng đẳng « %s » có mức tin cậy %8u\n" #: src/util/service.c:1588 msgid "Service process failed to initialize\n" msgstr "" #: src/util/service.c:1592 msgid "Service process could not initialize server function\n" msgstr "" #: src/util/service.c:1596 msgid "Service process failed to report status\n" msgstr "" #: src/util/service.c:1651 msgid "No such user" msgstr "Không có ngưá»i dùng như vậy" #: src/util/service.c:1664 #, c-format msgid "Cannot change user/group to `%s': %s\n" msgstr "Không thể thay đổi ngưá»i dùng/nhóm thành « %s »: %s\n" #: src/util/service.c:1729 msgid "do daemonize (detach from terminal)" msgstr "" #: src/util/signal.c:80 #, c-format msgid "signal (%d, %p) returned %d.\n" msgstr "" #: src/util/strings.c:144 msgid "b" msgstr "b" #: src/util/strings.c:334 #, c-format msgid "Character sets requested were `%s'->`%s'\n" msgstr "" #: src/util/strings.c:481 msgid "Failed to expand `$HOME': environment variable `HOME' not set" msgstr "" "Lá»—i mở rá»™ng biến môi trưá»ng « $HOME »: chưa đặt biến môi trưá»ng « HOME »" #: src/util/strings.c:573 msgid "ms" msgstr "mg" #: src/util/strings.c:578 msgid "eternity" msgstr "" #: src/util/strings.c:582 msgid "s" msgstr "g" #: src/util/strings.c:586 msgid "m" msgstr "p" #: src/util/strings.c:590 msgid "h" msgstr "g" #: src/util/strings.c:594 msgid " days" msgstr " ngày" #: src/util/strings.c:618 msgid "end of time" msgstr "" #: src/util/strings.c:1012 msgid "IPv6 address did not start with `['\n" msgstr "" #: src/util/strings.c:1020 msgid "IPv6 address did contain ':' to separate port number\n" msgstr "" #: src/util/strings.c:1026 msgid "IPv6 address did contain ']' before ':' to separate port number\n" msgstr "" #: src/util/strings.c:1033 msgid "IPv6 address did contain a valid port number after the last ':'\n" msgstr "" #: src/util/strings.c:1042 #, fuzzy, c-format msgid "Invalid IPv6 address `%s': %s\n" msgstr "Mức ưu tiên tiến trình không hợp lê « %s ».\n" #: src/vpn/gnunet-service-vpn.c:511 src/vpn/gnunet-service-vpn.c:1071 #, fuzzy msgid "# Active tunnels" msgstr "# các kết nối dht" #: src/vpn/gnunet-service-vpn.c:608 src/vpn/gnunet-service-vpn.c:645 #, fuzzy msgid "# peers connected to mesh tunnels" msgstr "# cá»§a các đồng đẳng đã kết nối" #: src/vpn/gnunet-service-vpn.c:699 #, fuzzy msgid "# Bytes given to mesh for transmission" msgstr "# các thông báo PING được tạo" #: src/vpn/gnunet-service-vpn.c:737 #, fuzzy msgid "# Bytes dropped in mesh queue (overflow)" msgstr "# các byte loại bá» bởi UDP (Ä‘i ra)" #: src/vpn/gnunet-service-vpn.c:772 #, fuzzy msgid "# Mesh tunnels created" msgstr "# các truy vấn lá»— hổng được định tuyến" #: src/vpn/gnunet-service-vpn.c:795 #, fuzzy msgid "Failed to setup mesh tunnel!\n" msgstr "Lá»—i lấy thông kê vá» truyá»n tải.\n" #: src/vpn/gnunet-service-vpn.c:973 #, c-format msgid "Protocol %u not supported, dropping\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1291 msgid "# ICMPv4 packets dropped (not allowed)" msgstr "" #: src/vpn/gnunet-service-vpn.c:1312 msgid "# ICMPv6 packets dropped (not allowed)" msgstr "" #: src/vpn/gnunet-service-vpn.c:1517 #, fuzzy msgid "# Packets received from TUN interface" msgstr "# các đáp ứng lá»— hổng được gá»­i cho trình/máy khách" #: src/vpn/gnunet-service-vpn.c:1555 src/vpn/gnunet-service-vpn.c:1596 #, c-format msgid "Packet received for unmapped destination `%s' (dropping it)\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1606 msgid "Received IPv4 packet with options (dropping it)\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1620 #, c-format msgid "Received packet of unknown protocol %d from TUN (dropping it)\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1704 #, fuzzy msgid "# ICMP packets received from mesh" msgstr "# các đáp ứng lá»— hổng được gá»­i cho trình/máy khách" #: src/vpn/gnunet-service-vpn.c:2045 #, fuzzy msgid "# UDP packets received from mesh" msgstr "# các đáp ứng lá»— hổng được gá»­i cho trình/máy khách" #: src/vpn/gnunet-service-vpn.c:2203 #, fuzzy msgid "# TCP packets received from mesh" msgstr "# các đáp ứng lá»— hổng được gá»­i cho trình/máy khách" #: src/vpn/gnunet-service-vpn.c:2354 msgid "Failed to find unallocated IPv4 address in VPN's range\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:2409 msgid "Failed to find unallocated IPv6 address in VPN's range\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:2448 src/vpn/gnunet-service-vpn.c:2661 #, fuzzy msgid "# Active destinations" msgstr "# các kết nối dht" #: src/vpn/gnunet-service-vpn.c:2734 msgid "Failed to allocate IP address for new destination\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:3141 msgid "IPv6 support disabled as this system does not support IPv6\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:3173 msgid "IPv4 support disabled as this system does not support IPv4\n" msgstr "" #: src/vpn/gnunet-vpn.c:151 #, fuzzy msgid "Error creating tunnel\n" msgstr "Hoàn thành tạo khoá.\n" #: src/vpn/gnunet-vpn.c:195 src/vpn/gnunet-vpn.c:226 #, fuzzy, c-format msgid "Option `%s' makes no sense with option `%s'.\n" msgstr "Tùy chá»n « %s » không có nghÄ©a khi không có tùy chá»n « %s ».\n" #: src/vpn/gnunet-vpn.c:208 #, fuzzy, c-format msgid "Option `%s' or `%s' is required.\n" msgstr "Bị từ chối đặt tùy chá»n « %s » trong phần « %s » thành « %s ».\n" #: src/vpn/gnunet-vpn.c:220 #, fuzzy, c-format msgid "Option `%s' or `%s' is required when using option `%s'.\n" msgstr "Tùy chá»n « %s » cần thiết khi dùng tùy chá»n « %s ».\n" #: src/vpn/gnunet-vpn.c:238 #, fuzzy, c-format msgid "`%s' is not a valid peer identifier.\n" msgstr "« %s » không sẵn sàng.\n" #: src/vpn/gnunet-vpn.c:260 #, fuzzy, c-format msgid "`%s' is not a valid IP address.\n" msgstr "« %s » không sẵn sàng.\n" #: src/vpn/gnunet-vpn.c:296 msgid "request that result should be an IPv4 address" msgstr "" #: src/vpn/gnunet-vpn.c:299 msgid "request that result should be an IPv6 address" msgstr "" #: src/vpn/gnunet-vpn.c:302 msgid "print IP address only after mesh tunnel has been created" msgstr "" #: src/vpn/gnunet-vpn.c:305 msgid "how long should the mapping be valid for new tunnels?" msgstr "" #: src/vpn/gnunet-vpn.c:308 msgid "destination IP for the tunnel" msgstr "" #: src/vpn/gnunet-vpn.c:311 msgid "peer offering the service we would like to access" msgstr "" #: src/vpn/gnunet-vpn.c:314 msgid "name of the service we would like to access" msgstr "" #: src/vpn/gnunet-vpn.c:317 #, fuzzy msgid "service is offered via TCP" msgstr "# các byte đã nhận qua TCP" #: src/vpn/gnunet-vpn.c:320 #, fuzzy msgid "service is offered via UDP" msgstr "# các byte đã nhận qua UDP" #: src/vpn/gnunet-vpn.c:329 msgid "Setup tunnels via VPN." msgstr "" #: src/include/gnunet_common.h:497 src/include/gnunet_common.h:502 #: src/include/gnunet_common.h:508 #, fuzzy, c-format msgid "Assertion failed at %s:%d.\n" msgstr "Lá»—i ná»™i bá»™ : khẳng định không thành công tại %s:%d.\n" #: src/include/gnunet_common.h:518 #, fuzzy, c-format msgid "External protocol violation detected at %s:%d.\n" msgstr "Lá»—i ná»™i bá»™ : khẳng định không thành công tại %s:%d.\n" #: src/include/gnunet_common.h:539 src/include/gnunet_common.h:546 #, c-format msgid "`%s' failed on file `%s' at %s:%d with error: %s\n" msgstr "« %s » thất bại ở tập tin « %s » tại %s:%d vá»›i lá»—i: %s\n" #~ msgid "Received malformed message via %s. Ignored.\n" #~ msgstr "Nhận được thông báo dạng sai qua %s. Bị bá» qua.\n" #~ msgid "SMTP filter string to invalid, lacks ': '\n" #~ msgstr "Chuá»—i lá»c vào SMTP không hợp lệ, còn thiếu « : »\n" #~ msgid "SMTP filter string to long, capped to `%s'\n" #~ msgstr "Chuá»—i lá»c vào SMTP quá dài, tối Ä‘a « %s »\n" #~ msgid "SMTP: `%s' failed: %s.\n" #~ msgstr "SMTP: « %s » bị lá»—i: %s\n" #~ msgid "No email-address specified, can not start SMTP transport.\n" #~ msgstr "" #~ "Chưa ghi rõ địa chỉ thư Ä‘iện tá»­ nên không tạo được truyá»n tải SMTP.\n" #~ msgid "# bytes received via SMTP" #~ msgstr "# các byte đã nhận qua SMTP" #~ msgid "# bytes sent via SMTP" #~ msgstr "# các byte đã gá»­i qua SMTP" #~ msgid "# bytes dropped by SMTP (outgoing)" #~ msgstr "# các byte loại Ä‘i bởi SMTP (Ä‘i ra)" #, fuzzy #~ msgid "# Peers connected" #~ msgstr "# cá»§a các đồng đẳng đã kết nối" #, fuzzy #~ msgid "%s failed for `%s' at %s:%d: `%s'\n" #~ msgstr "%s bị lá»—i tại %s:%d: « %s »\n" #, fuzzy #~ msgid "Failed to transmit shutdown ACK.\n" #~ msgstr "Lá»—i bắt đầu thu thập.\n" #, fuzzy #~ msgid "Unable to initialize Postgres with configuration `%s': %s" #~ msgstr "Không thể lưu tập tin cấu hình « %s »:" #, fuzzy #~ msgid "Failed to transmit message to `%s' service.\n" #~ msgstr "Lá»—i sÆ¡ khởi dịch vụ « %s ».\n" #, fuzzy #~ msgid "Target is %d connections per peer." #~ msgstr "Lá»—i thiết lập kết nối vá»›i đồng đẳng.\n" #~ msgid "Connecting nodes in 2d torus topology: %u rows %u columns\n" #~ msgstr "" #~ "Äang kết nối các Ä‘iểm nút theo địa hình há»c hình xuyến hai chiá»u: %u " #~ "hàng, %u cá»™t\n" #, fuzzy #~ msgid "Copying file with RENAME (%s,%s)\n" #~ msgstr "« %s » thất bại vá»›i mã lá»—i %s: %s\n" #, fuzzy #~ msgid "Copying file with command scp %s %s\n" #~ msgstr "« %s » thất bại vá»›i mã lá»—i %s: %s\n" #, fuzzy #~ msgid "Finished copying all blacklist files!\n" #~ msgstr "Không thể Ä‘á»c danh sách bạn bè « %s »\n" #, fuzzy #~ msgid "Offering HELLO of peer %s to peer %s\n" #~ msgstr "Ä‘ang kết nối đồng đẳng %s:%d tá»›i đồng đẳng %s:%d\n" #, fuzzy #~ msgid "Failed during blacklist file copying!\n" #~ msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" #, fuzzy #~ msgid "# bytes payload received for other peers" #~ msgstr "# các byte kiểu %d được nhận" #, fuzzy #~ msgid "# fast reconnects failed" #~ msgstr "# cá»§a các đồng đẳng đã kết nối" #, fuzzy #~ msgid "# peers disconnected due to timeout" #~ msgstr "# các kết nối bị đóng (vấn đỠtruyá»n tải)" #, fuzzy #~ msgid "# peers disconnected due to global disconnect" #~ msgstr "# Các quảng cáo đồng đẳng bị há»§y do trá»ng tải" #, fuzzy #~ msgid "# messages not sent (no such peer or not connected)" #~ msgstr "# các thông báo được chắp liá»n" #, fuzzy #~ msgid "# unexpected CONNECT_ACK messages" #~ msgstr "gá»­i ÄẾM thông báo" #, fuzzy #~ msgid "# wlan session timeouts" #~ msgstr "# các khoá phiên chạy được chấp nhận" #, fuzzy #~ msgid "# wlan session created" #~ msgstr "# các khoá phiên chạy được chấp nhận" #, fuzzy #~ msgid "# wlan pending fragments" #~ msgstr "# các mảnh bị loại bá»" #, fuzzy #~ msgid "# wlan fragments send" #~ msgstr "# các mảnh bị loại bá»" #, fuzzy #~ msgid "# wlan whole messages received" #~ msgstr "# các thông báo phát hiện dht được nhận" #, fuzzy #~ msgid "# wlan hello messages received" #~ msgstr "# các thông báo phát hiện dht được nhận" #, fuzzy #~ msgid "# wlan fragments received" #~ msgstr "# các mảnh bị loại bá»" #, fuzzy #~ msgid "# wlan acks received" #~ msgstr "# các yêu cầu khách lá»— hổng được nhận" #, fuzzy #~ msgid "# wlan messages for this client received" #~ msgstr "# các thông báo phát hiện dht được nhận" #, fuzzy #~ msgid "# wlan messages inside WLAN_HELPER_DATA received" #~ msgstr "# các thông báo phát hiện dht được nhận" #~ msgid "Unknown user `%s'\n" #~ msgstr "Không rõ ngưá»i dùng « %s »\n" #, fuzzy #~ msgid "Namespace `%s' unknown.\n" #~ msgstr "Không gian tên « %s » có đánh giá %d.\n" #, fuzzy #~ msgid "Failed to connect to statistics service!\n" #~ msgstr "Lá»—i kết nối đến gnunetd.\n" #, fuzzy #~ msgid "Failed to send to `%s': %s\n" #~ msgstr "Lá»—i mở tập tin ghi sá»± kiện « %s »: %s\n" #, fuzzy #~ msgid "Could not access file: %s\n" #~ msgstr "Không thể truy cập đến « %s »: %s\n" #, fuzzy #~ msgid "`%s' failed on file `%s': %s" #~ msgstr "« %s » thất bại cho ổ đĩa « %s »: %u\n" #, fuzzy #~ msgid "# bytes TCP was asked to transmit" #~ msgstr "# các byte được gá»­i" #, fuzzy #~ msgid "# bytes discarded by TCP (failed to connect)" #~ msgstr "# các byte loại Ä‘i bởi TCP (Ä‘i ra)" #, fuzzy #~ msgid "# wlan messages queued" #~ msgstr "# các thông báo phát hiện dht được nhận" #~ msgid "print this help" #~ msgstr "hiển thị trợ giúp này" #~ msgid "print the version number" #~ msgstr "hiển thị số thứ tá»± phiên bản" #, fuzzy #~ msgid "configure logging to write logs to LOGFILE" #~ msgstr "cấu hình chức năng ghi sá»± kiện để dùng CẤP_GHI_LƯU" #~ msgid "configure logging to use LOGLEVEL" #~ msgstr "cấu hình chức năng ghi sá»± kiện để dùng CẤP_GHI_LƯU" #~ msgid "be verbose" #~ msgstr "xuất chi tiết" #~ msgid "use configuration file FILENAME" #~ msgstr "dùng tập tin cấu hình TÊN_TẬP_TIN" #, fuzzy #~ msgid "Failed to stop service `%s'!\n" #~ msgstr "Lá»—i vào phòng « %s »\n" #, fuzzy #~ msgid "Failed to start service `%s'!\n" #~ msgstr "Lá»—i bắt đầu thu thập.\n" #, fuzzy #~ msgid "Binary implementing service `%s' not known!\n" #~ msgstr "Không thẩm tra được chữ ký: không rõ đồng đẳng « %s ».\n" #, fuzzy #~ msgid "Service `%s' stopped\n" #~ msgstr "Dịch vụ đã bị xoá.\n" #, fuzzy #~ msgid "Unable to start service `%s': %s\n" #~ msgstr "Không thể lưu tập tin cấu hình « %s »:" #, fuzzy #~ msgid "Unable to accept connection for service `%s': %s\n" #~ msgstr "Không thể lưu tập tin cấu hình « %s »:" #, fuzzy #~ msgid "Peer `%s' plugin: `%s' address `%s'\n" #~ msgstr "Äồng đẳng « %s » có mức tin cậy %8u và địa chỉ « %s »\n" #~ msgid "KiB" #~ msgstr "KiB" #~ msgid "MiB" #~ msgstr "MiB" #~ msgid "GiB" #~ msgstr "GiB" #~ msgid "TiB" #~ msgstr "TiB" #, fuzzy #~ msgid "Failed to create IPv4 broadcast socket on port %d\n" #~ msgstr "Lá»—i cập nhật dữ liệu cho mô-Ä‘un « %s »\n" #, fuzzy #~ msgid "Failed to load block plugin `%s'\n" #~ msgstr "Không thể nạp phần bổ sung truyá»n tải « %s »\n" #, fuzzy #~ msgid "Could not resolve our FQDN : %s %u\n" #~ msgstr "Không thể giải quyết « %s » (%s): %s\n" #, fuzzy #~ msgid "Failed to load dhtlog plugin for `%s'\n" #~ msgstr "Lá»—i Ä‘á»c danh sách bạn bè từ « %s »\n" #, fuzzy #~ msgid "Found peer `%s'\n" #~ msgstr "Tôi là đồng đẳng « %s ».\n" #, fuzzy #~ msgid "Failed to initialize MySQL database connection for dhtlog.\n" #~ msgstr "Lá»—i sÆ¡ khởi kết nối cÆ¡ sở dữ liệu MySQL cho kho dữ liệu.\n" #, fuzzy #~ msgid "Loading udp transport plugin\n" #~ msgstr "Äang nạp các truyá»n tải « %s »\n" #, fuzzy #~ msgid "# SET QUOTA messages received" #~ msgstr "# các thông báo PONG đã mật mã được nhận" #, fuzzy #~ msgid "curl failed for `%s' at %s:%d: `%s'\n" #~ msgstr "%s bị lá»—i tại %s:%d: « %s »\n" #, fuzzy #~ msgid "Phase 3: sending messages\n" #~ msgstr "Lá»—i gá»­i tin nhẳn.\n" #, fuzzy #~ msgid "Loading HTTPS transport plugin `%s'\n" #~ msgstr "Äang nạp các truyá»n tải « %s »\n" #, fuzzy #~ msgid "Failed to load transport plugin for https\n" #~ msgstr "Không thể nạp phần bổ sung truyá»n tải « %s »\n" #, fuzzy #~ msgid "Fail! Could not connect peers\n" #~ msgstr "Không thể kết nối tá»›i %s:%u: %s\n" #, fuzzy #~ msgid "Loading tcp transport plugin\n" #~ msgstr "Äang nạp các truyá»n tải « %s »\n" #, fuzzy #~ msgid "Failed to load transport plugin for tcp\n" #~ msgstr "Không thể nạp phần bổ sung truyá»n tải « %s »\n" #, fuzzy #~ msgid "# HTTP peers active" #~ msgstr "# Tín hiệu HTTP GET được nhận" #, fuzzy #~ msgid "Connection: %X: %s failed at %s:%d: `%s'\n" #~ msgstr "%s bị lá»—i tại %s:%d: « %s »\n" #, fuzzy #~ msgid "Failed to load transport plugin for http\n" #~ msgstr "Không thể nạp phần bổ sung truyá»n tải « %s »\n" #, fuzzy #~ msgid "# PING messages decrypted" #~ msgstr "# các thông báo PING được tạo" #, fuzzy #~ msgid "Failed to connect to core service\n" #~ msgstr "Lá»—i kết nối đến gnunetd.\n" #, fuzzy #~ msgid "# bytes successfully transmitted by plugins" #~ msgstr "# các byte được gá»­i" #, fuzzy #~ msgid "# connected addresses" #~ msgstr "# cá»§a các đồng đẳng đã kết nối" #, fuzzy #~ msgid "# transport failed to selected peer address" #~ msgstr "Äang quảng cáo truyá»n tải %d cá»§a mình tá»›i các đồng đẳng đã chá»n.\n" #, fuzzy #~ msgid "# peer addresses considered valid" #~ msgstr "# Các quảng cáo đồng đẳng được xác nhận qua PONG" #, fuzzy #~ msgid "# PING with HELLO messages sent" #~ msgstr "# các thông báo PING được tạo" #, fuzzy #~ msgid "# HELLOs received for validation" #~ msgstr "# các khối được lấy để nâng cấp" #, fuzzy #~ msgid "Received `%s' message from `%s' destined for `%s' which is not me!\n" #~ msgstr "Nhận được PING « %s » không dành cho chúng ta.\n" #~ msgid "Error" #~ msgstr "Lá»—i" #~ msgid "Help" #~ msgstr "Trợ giúp" #~ msgid "Error!" #~ msgstr "Lá»—i !" #~ msgid "No" #~ msgstr "Không" #~ msgid "Yes" #~ msgstr "Có" #~ msgid "Internal error! (Choice invalid?)" #~ msgstr "Lá»—i ná»™i bá»™ (sai chá»n ?)" #~ msgid "Abort" #~ msgstr "Há»§y" #~ msgid "Ok" #~ msgstr "OK" #~ msgid "" #~ "Welcome to GNUnet!\n" #~ "\n" #~ "This assistant will ask you a few basic questions in order to configure " #~ "GNUnet.\n" #~ "\n" #~ "Please visit our homepage at\n" #~ "\thttp://gnunet.org/\n" #~ "and join our community at\n" #~ "\thttp://gnunet.org/drupal/\n" #~ "\n" #~ "Have a lot of fun,\n" #~ "\n" #~ "the GNUnet team" #~ msgstr "" #~ "Xin chào mừng tá»›i GNUnet !\n" #~ "\n" #~ "Trình giúp đỡ này sẽ há»i bạn vài câu cÆ¡ bản để cấu hình GNUnet.\n" #~ "\n" #~ "Xin hãy thăm trang chá»§ cá»§a chúng tôi tại\n" #~ "\thttp://gnunet.org\n" #~ "và tham gia cá»™ng đồng tại\n" #~ "\thttp://www.gnunet.org/drupal/\n" #~ "\n" #~ "Chúc có nhiá»u niá»m vui,\n" #~ "\n" #~ "đội GNUnet" #~ msgid "" #~ "Choose the network interface that connects your computer to the internet " #~ "from the list below." #~ msgstr "" #~ "Chá»n giao diện mạng kết nối máy tính tá»›i Internet từ danh sách dưới đây." #~ msgid "" #~ "The \"Network interface\" is the device that connects your computer to " #~ "the internet. This is usually a modem, an ISDN card or a network card in " #~ "case you are using DSL." #~ msgstr "" #~ "« Giao diện mạng » là thiết bị kết nối máy tính vá»›i Internet. Äây thưá»ng " #~ "là má»™t bá»™ Ä‘iá»u giải, má»™t bo mạch ISDN hay má»™t bo mạch mạng nếu dùng DSL." #~ msgid "Network configuration: interface" #~ msgstr "Cấu hình mạng: giao diện" #~ msgid "" #~ "What is the name of the network interface that connects your computer to " #~ "the Internet?" #~ msgstr "Máy tính này kết nối tá»›i Internet qua giao diện mạng tên nào?" #~ msgid "Network configuration: IP" #~ msgstr "Cấu hình mạng: IP" #~ msgid "What is this computer's public IP address or hostname?" #~ msgstr "Äịa chỉ IP công cá»™ng hoặc tên cá»§a máy tính này là gì?" #~ msgid "" #~ "If your provider always assigns the same IP-Address to you (a \"static\" " #~ "IP-Address), enter it into the \"IP-Address\" field. If your IP-Address " #~ "changes every now and then (\"dynamic\" IP-Address) but there's a " #~ "hostname that always points to your actual IP-Address (\"Dynamic DNS\"), " #~ "you can also enter it here.\n" #~ "If left empty, GNUnet will try to automatically detect the IP.\n" #~ "You can specify a hostname, GNUnet will then use DNS to resolve it.\n" #~ "If in doubt, leave this empty." #~ msgstr "" #~ "Nếu nhà cung cấp luôn luôn gán cùng má»™t địa chỉ IP (má»™t địa chỉ IP « tÄ©nh " #~ "»), thì hãy nhập địa chỉ đó vào vùng « Äịa chỉ IP ». Nếu địa chỉ IP thay " #~ "đổi sau má»—i lần kết nối (địa chỉ IP « động ») nhưng có má»™t tên máy luôn " #~ "luôn chỉ tá»›i địa chỉ IP thá»±c cá»§a bạn (« DNS động »), thì cÅ©ng có thể nhập " #~ "nó ở đây.\n" #~ "Nếu không biết phải làm gì, thì hãy để trống. GNUnet sẽ thá»­ tá»± động phát " #~ "hiện địa chỉ IP.\n" #~ "Bạn cÅ©ng có thể ghi rõ tên máy. Vì thế GNUnet sẽ dùng dịch vụ DNS để giải " #~ "quyết nó." #~ msgid "Bandwidth configuration: upload" #~ msgstr "Cấu hình dải thông: tải lên" #~ msgid "How much upstream bandwidth (in bytes/s) may be used?" #~ msgstr "Dòng ra có thể dùng bao nhiêu byte?" #~ msgid "" #~ "You can limit GNUnet's resource usage here.\n" #~ "\n" #~ "The \"upstream\" is the data channel through which data is *sent* to the " #~ "internet. The limit is the maximum amount which GNUnet is allowed to use. " #~ "If you have a flatrate, you can set it to the maximum speed of your " #~ "internet connection. You should not use a value that is higher than what " #~ "your actual connection allows." #~ msgstr "" #~ "Có thể giá»›i hạn sá»­ dụng tài nguyên cá»§a GNUnet ở đây.\n" #~ "\n" #~ "« Dòng ra » (upstream) là kênh dữ liệu qua đó _gá»­i_ dữ liệu tá»›i Internet. " #~ "Giá»›i hạn là số tối Ä‘a được gán cho GNUnet. Nếu có tốc độ Ä‘á»u, thì có thể " #~ "đặt thành tốc độ kết nối Internet lá»›n nhất. Không nên đặt giá trị lá»›n hÆ¡n " #~ "số được gán cho kết nối Internet cá»§a bạn." #~ msgid "Bandwidth configuration: download" #~ msgstr "Cấu hình dải thông: tải xuống" #~ msgid "How much downstream bandwidth (in bytes/s) may be used?" #~ msgstr "Dòng vào có thể dùng bao nhiêu byte?" #~ msgid "" #~ "You can limit GNUnet's resource usage here.\n" #~ "\n" #~ "The \"downstream\" is the data channel through which data is *received* " #~ "from the internet. The limit is the maximum amount which GNUnet is " #~ "allowed to use. If you have a flatrate, you can set it to the maximum " #~ "speed of your internet connection. You should not use a value that is " #~ "higher than what your actual connection allows." #~ msgstr "" #~ "Có thể giá»›i hạn sá»­ dụng tài nguyên cá»§a GNUnet ở đây.\n" #~ "\n" #~ "« Dòng vào » (downstream) là kênh dữ liệu qua đó _nhận_ dữ liệu từ " #~ "Internet. Giá»›i hạn là số tối Ä‘a được gán cho GNUnet. Nếu có tốc độ Ä‘á»u, " #~ "thì có thể đặt thành tốc độ kết nối Internet lá»›n nhất. Không nên đặt giá " #~ "trị lá»›n hÆ¡n số được gán cho kết nối Internet cá»§a bạn." #~ msgid "Quota configuration" #~ msgstr "Cấu hình hạn ngạch" #~ msgid "What is the maximum size of the datastore in MB?" #~ msgstr "Kho dữ liệu có kích cỡ tối Ä‘a (theo MB)?" #~ msgid "" #~ "The GNUnet datastore contains all content that GNUnet needs to store " #~ "(indexed, inserted and migrated content)." #~ msgstr "" #~ "Kho dữ liệu GNUnet chứa tất cả các dữ liệu GNUnet cần cất giữ (dữ liệu " #~ "chỉ mục, ná»™i dung chèn và nhập vào)." #~ msgid "Daemon configuration: user account" #~ msgstr "Cấu hình trình ná»n: tài khoản ngưá»i dùng" #~ msgid "As which user should gnunetd be run?" #~ msgstr "Trình ná»n gnunetd nên chạy vá»›i tư cách ngưá»i dùng nào?" #~ msgid "" #~ "For security reasons, it is a good idea to let this setup create a new " #~ "user account under which the GNUnet service is started at system " #~ "startup.\n" #~ "\n" #~ "However, GNUnet may not be able to access files other than its own. This " #~ "includes files you want to publish in GNUnet. You'll have to grant read " #~ "permissions to the user specified below.\n" #~ "\n" #~ "Leave the field empty to run GNUnet with system privileges.\n" #~ msgstr "" #~ "Vì lý do bảo mật, nên cho phép thiết lập này tạo má»™t tài khoản ngưá»i dùng " #~ "má»›i sở hữu dịch vụ GNUnet chạy má»—i khi khởi động máy tính.\n" #~ "\n" #~ "Tuy nhiên, GNUnet có thể không truy cập được tá»›i các tập tin mà nó không " #~ "sở hữu, bao gồm các tập tin ngưá»i dùng muốn đưa ra chia sẻ trong GNUnet. " #~ "Sẽ cần cho phép ngưá»i dùng chỉ ra dưới đây quyá»n Ä‘á»c chúng.\n" #~ "\n" #~ "Äể trống để chạy GNUnet vá»›i quyá»n hệ thống.\n" #~ msgid "Daemon configuration: group account" #~ msgstr "Cấu hình trình ná»n: tài khoản nhóm" #~ msgid "As which group should gnunetd be run?" #~ msgstr "gnunetd nên chạy như nhóm nào?" #~ msgid "" #~ "For security reasons, it is a good idea to let this setup create a new " #~ "group for the chosen user account.\n" #~ "\n" #~ "You can also specify a already existent group here.\n" #~ "\n" #~ "Only members of this group will be allowed to start and stop the the " #~ "GNUnet server and have access to GNUnet server data.\n" #~ msgstr "" #~ "Vì lý do bảo mật, nên để thiết lập này tạo má»™t nhóm má»›i cho tài khoản " #~ "ngưá»i dùng đã chá»n\n" #~ "\n" #~ "CÅ©ng có thể chỉ ra má»™t nhóm đã có.\n" #~ "\n" #~ "Chỉ thành viên cá»§a nhóm này má»›i có quyá»n chạy và dừng trình phục vụ " #~ "GNUnet và có truy cập tá»›i dữ liệu cá»§a trình phục vụ GNUnet.\n" #~ msgid "Do you want to automatically launch GNUnet as a system service?" #~ msgstr "Bạn có muốn tá»± động khởi chạy GNUnet như là dịch vụ hệ thống không?" #~ msgid "" #~ "If you say \"yes\" here, the GNUnet background process will be " #~ "automatically started when you turn on your computer. If you say \"no\" " #~ "here, you have to launch GNUnet yourself each time you want to use it." #~ msgstr "" #~ "Bật tùy chá»n này thì tiến trình GNUnet ná»n được tá»± động khởi chạy má»—i lần " #~ "mở máy tính. Không thì bạn cần phải tá»± khởi chạy GNUnet má»—i lần để sá»­ " #~ "dụng nó." #~ msgid "Unable to create user account for daemon." #~ msgstr "Không thể tạo tài khoản ngưá»i dùng cho trình ná»n." #~ msgid "Unable to setup autostart for daemon." #~ msgstr "Không thể thiết lập chức năng tá»± động khởi chạy cho trình ná»n." #~ msgid "Save configuration?" #~ msgstr "Lưu cấu hình không?" #~ msgid "GNUnet Configuration" #~ msgstr "Cấu hình GNUnet" #~ msgid "Back" #~ msgstr "Lùi" #~ msgid "Exit" #~ msgstr "Thoát" #~ msgid "Up" #~ msgstr "Lên" #~ msgid "Cancel" #~ msgstr "Thôi" #~ msgid "Internal error! (Value invalid?)" #~ msgstr "Lá»—i ná»™i bá»™ (giá trị sai ?)" #~ msgid "Invalid input, expecting floating point value." #~ msgstr "Dữ liệu nhập sai, mong đợi giá trị chấm động." #~ msgid "Invalid input, expecting integer." #~ msgstr "Dữ liệu nhập sai, mong đợi số nguyên." #~ msgid "Value is not in legal range." #~ msgstr "Giá trị không nằm trong phạm vi được phép." #~ msgid "Configuration unchanged, no need to save.\n" #~ msgstr "Cấu hình chưa thay đổi thì không cần lưu lại.\n" #~ msgid "Do you wish to save your new configuration?" #~ msgstr "Bạn có muốn lưu cấu hình má»›i không?" #~ msgid "" #~ "\n" #~ "Your configuration changes were NOT saved.\n" #~ msgstr "" #~ "\n" #~ "CHƯA lưu các thay đổi trong cấu hình.\n" #~ msgid "install GNUnet as Windows service" #~ msgstr "cài đặt GNUnet như là má»™t dịch vụ Windows" #~ msgid "increase the maximum number of TCP/IP connections" #~ msgstr "tăng sổ tối Ä‘a các kết nối TCP/IP" #~ msgid "display a file's hash value" #~ msgstr "hiển thị giá trị tổng kiểm cá»§a tập tin" #~ msgid "This version of Windows doesn't support services.\n" #~ msgstr "Phiên bản Windows này không há»— trợ dịch vụ.\n" #~ msgid "Error: can't open Service Control Manager: %s\n" #~ msgstr "Lá»—i: không thể mở Bá»™ Quản lý Äiá»u khiển Dịch vụ : %s\n" #~ msgid "Error: can't create service: %s\n" #~ msgstr "Lá»—i: không thể tạo dịch vụ : %s\n" #~ msgid "Error: can't access service: %s\n" #~ msgstr "Lá»—i: không thể truy cập đến dịch vụ : %s\n" #~ msgid "Error: can't delete service: %s\n" #~ msgstr "Lá»—i: không thể xoá dịch vụ : %s\n" #~ msgid "Configuration changed. Save?" #~ msgstr "Cấu hình bị thay đổi. Lưu ?" #~ msgid "Error saving configuration." #~ msgstr "Gặp lá»—i khi lưu cấu hình." #~ msgid "(unknown connection)" #~ msgstr "(không rõ kết nối)" #~ msgid "Do you want to save the new configuration?" #~ msgstr "Bạn có muốn lưu cấu hình má»›i này không?" #~ msgid "Unable to change startup process:" #~ msgstr "Không thể thay đổi tiến trình khởi chạy:" #~ msgid "" #~ "Running gnunet-update failed.\n" #~ "This maybe due to insufficient permissions, please check your " #~ "configuration.\n" #~ "Finally, run gnunet-update manually." #~ msgstr "" #~ "Lá»—i chạy tiến trình cập nhật gnunet-update.\n" #~ "Äây có thể do không đủ quyá»n, hãy kiểm tra cấu hình.\n" #~ "Cuối cùng, chạy gnunet-update thá»§ công." #~ msgid "Can only set one option per invocation.\n" #~ msgstr "Chỉ có thể đặt má»™t tùy chá»n trong má»—i cuá»™c gá»i.\n" #~ msgid "" #~ "Invalid syntax, argument to 'set' must have the format SECTION:" #~ "OPTION=VALUE.\n" #~ msgstr "" #~ "Cú pháp sai, đối số tá»›i « set » phải theo định dạng:\n" #~ "PHẦN:TÙY_CHỌN­=GIÃ_TRỊ\n" #~ msgid "Can only display one option per invocation.\n" #~ msgstr "Chỉ có thể hiển thị má»™t tùy chá»n trong má»—i cuá»™c gá»i.\n" #~ msgid "" #~ "Invalid syntax, argument to 'get' must have the format SECTION:OPTION.\n" #~ msgstr "" #~ "Cú pháp sai, đối số tá»›i « get » phải theo định dạng:\n" #~ "PHẦN:TÙY_CHỌN\n" #~ msgid "generate configuration for gnunetd, the GNUnet daemon" #~ msgstr "tạo ra cấu hình cho gnunetd, trình ná»n GNUnet" #~ msgid "Tool to setup GNUnet." #~ msgstr "Công cụ để thiết lập GNUnet." #~ msgid "Too many arguments.\n" #~ msgstr "Quá nhiá»u đối số.\n" #~ msgid "No interface specified, using default.\n" #~ msgstr "Chưa xác định giao diện nên dùng mặc định.\n" #~ msgid "Undefined option.\n" #~ msgstr "Tùy chá»n không xác định.\n" #~ msgid "Unknown operation '%s'.\n" #~ msgstr "Không rõ thao tác « %s ».\n" #~ msgid "yes" #~ msgstr "có" #~ msgid "no" #~ msgstr "không" #~ msgid "\tEnter yes (%s), no (%s) or help (%s): " #~ msgstr "\tNhập có (%s), không (%s) hoặc trợ giúp (%s): " #~ msgid "\tPossible choices:\n" #~ msgstr "\tLá»±a chá»n có thể:\n" #~ msgid "\tUse single space prefix to avoid conflicts with hotkeys!\n" #~ msgstr "\tHãy dùng tiá»n tố má»™t dấu cách để tránh xung đột vá»›i phím nóng.\n" #~ msgid "\tEnter string (type '%s' for default value `%s'): " #~ msgstr "\tNhập chuá»—i (gõ « %s » cho giá trị mặc định « %s »): " #~ msgid "\t Enter choice (default is %c): " #~ msgstr "\t Nhập sá»± chá»n (mặc định là %c):" #~ msgid "\tEnter floating point (type '%s' for default value %f): " #~ msgstr "\tNhập chấm động (gõ « %s » cho giá trị mặc định %f): " #~ msgid "" #~ "\tEnter unsigned integer in interval [%llu,%llu] (type '%s' for default " #~ "value %llu): " #~ msgstr "" #~ "\tNhập số nguyên không có dấu trong khoảng [%llu,%llu] (gõ « %s » cho giá " #~ "trị mặc định %llu): " #~ msgid "Yes\n" #~ msgstr "Có\n" #~ msgid "No\n" #~ msgstr "Không\n" #~ msgid "Help\n" #~ msgstr "Trợ giúp\n" #~ msgid "Abort\n" #~ msgstr "Há»§y bá»\n" #~ msgid "" #~ "\n" #~ "Invalid entry, try again (use '?' for help): " #~ msgstr "" #~ "\n" #~ "Dữ liệu nhập sai. Hãy thá»­ lại (dùng « ? » để xem trợ giúp): " #~ msgid "Unknown kind %x (internal error). Skipping option.\n" #~ msgstr "Kiểu không rõ %x (lá»—i ná»™i bá»™). Äang bá» qua tùy chá»n.\n" #~ msgid "\tDescend? (y/n/?) " #~ msgstr "\tGiảm dần ? (c/k?)" #~ msgid "Aborted.\n" #~ msgstr "Bị há»§y bá».\n" #~ msgid "Unknown kind %x (internal error). Aborting.\n" #~ msgstr "Kiểu không rõ %x (lá»—i ná»™i bá»™). Äang há»§y bá».\n" #~ msgid "You can always press ENTER to keep the current value.\n" #~ msgstr "" #~ "Lúc nào bạn cÅ©ng có thể bấm phím Enter để giữ lại giá trị hiện có.\n" #~ msgid "Use the '%s' key to abort.\n" #~ msgstr "Dùng phím « %s » để há»§y bá».\n" #~ msgid "" #~ "Save configuration? Answer 'y' for yes, 'n' for no, 'r' to repeat " #~ "configuration. " #~ msgstr "" #~ "Lưu lại cấu hình không?\n" #~ " • y\t\tcó\n" #~ " • n\t\tkhông\n" #~ " • r\t\tlặp lại cấu hình." #~ msgid "Configuration was unchanged, no need to save.\n" #~ msgstr "Cấu hình chưa thay đổi thì không cần lưu lại.\n" #~ msgid "" #~ "Internal error: entry `%s' in section `%s' not found for visibility " #~ "change!\n" #~ msgstr "" #~ "Lá»—i ná»™i bá»™ : mục nhập « %s » trong phần « %s » không tìm thấy để thay đổi " #~ "tình trạng hiển rõ.\n" #~ msgid "Can't open Service Control Manager" #~ msgstr "Không thể mở Bá»™ Quản lý Äiá»u khiển Dịch vụ" #~ msgid "Can't create service" #~ msgstr "Không thể tạo dịch vụ" #~ msgid "Error changing the permissions of the GNUnet directory" #~ msgstr "Gặp lá»—i khi thay đổi quyá»n hạn cá»§a thư mục GNUnet" #~ msgid "Cannot write to the registry" #~ msgstr "Không thể ghi vào sổ đăng ký" #~ msgid "Can't delete the service" #~ msgstr "Không thể xoá dịch vụ" #~ msgid "This version of Windows does not support multiple users." #~ msgstr "Phiên bản Windows này không có há»— trợ Ä‘a ngưá»i dùng." #~ msgid "Error accessing local security policy" #~ msgstr "Gặp lá»—i khi truy cập đến chính sách bảo mật cục bá»™" #~ msgid "Error granting service right to user" #~ msgstr "Gặp lá»—i khi cấp quyá»n dịch vụ cho ngưá»i dùng" #~ msgid "Unknown error while creating a new user" #~ msgstr "Gặp lá»—i không rõ trong khi tạo má»™t ngưá»i dùng má»›i" #~ msgid "" #~ "\n" #~ "Press any key to continue\n" #~ msgstr "" #~ "\n" #~ "Hãy bấm bất cứ phím nào để tiếp tục.\n" #~ msgid "STATUS" #~ msgstr "TRẠNG THÃI" #~ msgid "FATAL" #~ msgstr "NGHIÊM TRỌNG" #~ msgid "USER" #~ msgstr "NGƯỜI DÙNG" #~ msgid "ADMIN" #~ msgstr "QUẢN TRỊ" #~ msgid "DEVELOPER" #~ msgstr "NHÀ PHÃT TRIỂN" #~ msgid "REQUEST" #~ msgstr "YÊU CẦU" #~ msgid "BULK" #~ msgstr "HÀNG LOẠT" #~ msgid "IMMEDIATE" #~ msgstr "NGAY" #~ msgid "ALL" #~ msgstr "TẤT CẢ" #~ msgid "NOTHING" #~ msgstr "KHÔNG GÃŒ" #, fuzzy #~ msgid "Could not find valid value for HOST in section NETWORK.\n" #~ msgstr "Không tìm thấy giá trị đúng cho MÃY trong phần MẠNG." #, fuzzy #~ msgid "Syntax error in configuration entry HOST in section NETWORK: `%s'\n" #~ msgstr "Gặp lá»—i cú pháp trong mục nhập cấu hình MÃY trong phần MẠNG: « %s »" #~ msgid "Error connecting to %s:%u. Is the daemon running?\n" #~ msgstr "Gặp lá»—i khi kết nối tá»›i %s:%u. Trình ná»n Ä‘ang chạy không?\n" #~ msgid "Reading result from gnunetd failed, reply invalid!\n" #~ msgstr "Lá»—i Ä‘á»c kết quả từ gnunetd, đáp ứng không hợp lệ.\n" #~ msgid "" #~ "Setting option `%s' in section `%s' to `%s' when processing command line " #~ "option `%s' was denied.\n" #~ msgstr "" #~ "Bị từ chối đặt tùy chá»n « %s » trong phần « %s » thành « %s » khi xá»­ lý " #~ "tùy chá»n dòng lệnh « %s ».\n" #~ msgid "No interface specified in section `%s' under `%s'!\n" #~ msgstr "" #~ "Không có giao diện mạng được xác định trong cấu hình phần « %s » dưới « " #~ "%s ».\n" #~ msgid "Could not obtain IP for interface `%s' using `%s'.\n" #~ msgstr "Không thể lấy địa chỉ IP cho giao diện « %s », dùng « %s ».\n" #~ msgid "" #~ "Could not find interface `%s' using `%s', trying to find another " #~ "interface.\n" #~ msgstr "" #~ "Không tìm thấy giao diện « %s » trong « %s », Ä‘ang thá»­ tìm giao diện " #~ "khác.\n" #~ msgid "Could not find an IP address for interface `%s'.\n" #~ msgstr "Không tìm thấy má»™t địa chỉ IP cho giao diện « %s ».\n" #~ msgid "" #~ "There is more than one IP address specified for interface `%s'.\n" #~ "GNUnet will use %s.\n" #~ msgstr "" #~ "Có vài địa chỉ IP chỉ ra cho giao diện « %s ».\n" #~ "GNUnet sẽ dùng %s.\n" #~ msgid "Could not resolve `%s' to determine our IP address: %s\n" #~ msgstr "" #~ "Không thể giải quyết « %s » để quyết định địa chỉ IP cá»§a chúng ta: %s\n" #~ msgid "Received malformed message (too small) from connection. Closing.\n" #~ msgstr "Nhận được thông báo bị há»ng (quá nhá») từ kết nối. Äang đóng.\n" #~ msgid "select listen socket for `%s' not valid!\n" #~ msgstr "sai chá»n ổ cắm lắng nghe cho « %s »\n" #~ msgid "" #~ "Configuration value '%llu' for '%s' in section '%s' is out of legal " #~ "bounds [%llu,%llu]\n" #~ msgstr "" #~ "Giá tri cấu hình « %llu » cho « %s » trong phần « %s » ở ngoại phạm vi " #~ "được phép [%llu,%llu]\n" #~ msgid "`%s' returned with error code %u" #~ msgstr "« %s » trả lại vá»›i mã lá»—i %u" #~ msgid "Can't create semaphore: %i" #~ msgstr "Không thể tạo cá» hiệu : %i" #~ msgid "Cannot query the CPU usage (Windows NT).\n" #~ msgstr "Không há»i được sá»± sá»­ dụng CPU (Windows NT).\n" #~ msgid "Cannot query the CPU usage (Win 9x)\n" #~ msgstr "Không há»i được sá»± sá»­ dụng CPU (Windows 9x).\n" #~ msgid "" #~ "No network interfaces defined in configuration section `%s' under `%s'!\n" #~ msgstr "" #~ "Không có giao diện mạng được xác định trong cấu hình phần « %s » dưới « " #~ "%s ».\n" #~ msgid "Setting open descriptor limit not supported.\n" #~ msgstr "Không há»— trợ chức năng đặt giá»›i hạn bá»™ mô tả còn mở.\n" #~ msgid "Command `%s' failed with error code %u\n" #~ msgstr "Câu lệnh « %s » đã thất bại vá»›i mã lá»—i %u\n" #~ msgid "Real-time delay violation (%llu ms) at %s:%u\n" #~ msgstr "Xâm phạm khoảng đợi thá»i gian thá»±c (%llu miligiây) tại %s:%u\n" #~ msgid "`%s' failed with error code %d: %s\n" #~ msgstr "« %s » thất bại vá»›i mã lá»—i %d: %s\n" #~ msgid "Deadlock due to `%s'.\n" #~ msgstr "Bế tắc do « %s ».\n" #~ msgid "Lock acquired for too long (%llu ms) at %s:%u\n" #~ msgstr "Khoá đặt được quá lâu (%llu miligiây) tại %s:%u\n" #~ msgid "GNUnet error log" #~ msgstr "Bản ghi lá»—i GNUnet" #~ msgid "Out of memory (for logging)\n" #~ msgstr "Tràn bá»™ nhá»› (để ghi sá»± kiện)\n" #~ msgid "Availability test failed for `%s' at %s:%d.\n" #~ msgstr "Lá»—i kiểm tra tình trạng sẵn sàng cho « %s » tại %s:%d.\n" #~ msgid "# bloom filter false positives" #~ msgstr "# các dương giả cá»§a bá»™ lá»c bloom" #~ msgid "Failed to load state service. Trying to do without.\n" #~ msgstr "Lá»—i nạp dịch vụ tình trạng. Không có nhưng vẫn Ä‘ang thá»­ tiếp tục.\n" #~ msgid "Datastore conversion at approximately %u%%\n" #~ msgstr "Chuyển đổi kho dữ liệu theo xấp xỉ %u%%\n" #~ msgid "Starting datastore conversion (this may take a while).\n" #~ msgstr "Äang bắt đầu chuyển đổi kho dữ liệu (có thể hÆ¡i lâu).\n" #~ msgid "Completed datastore conversion.\n" #~ msgstr "Hoàn tất chuyển đổi kho dữ liệu.\n" #~ msgid "" #~ "%s:%d - RPC %s:%p could not be registered: another callback is already " #~ "using this name (%p)\n" #~ msgstr "" #~ "%s:%d - RPC %s:%p không đăng ký được: má»™t cuá»™c gá»i ngược lại khác Ä‘ang " #~ "dùng tên này (%p)\n" #~ msgid "%s:%d - async RPC %s:%p could not be unregistered: not found\n" #~ msgstr "" #~ "%s:%d - RPC không đồng bá»™ %s:%p không há»§y đăng ký được: không tìm thấy\n" #~ msgid "`%s' registering handlers %d %d %d\n" #~ msgstr "« %s » Ä‘ang đăng ký các trình Ä‘iá»u khiển %d %d %d\n" #~ msgid "Using %u messages of size %u for %u times.\n" #~ msgstr "Sá»­ dụng %u thông báo vá»›i kích cỡ %u trong %u lần.\n" #~ msgid "Times: max %16llu min %16llu mean %12.3f variance %12.3f\n" #~ msgstr "Thá»i gian: đại %16llu tiểu %16llu t.bình %12.3f ph.sai %12.3f\n" #~ msgid "Loss: max %16u min %16u mean %12.3f variance %12.3f\n" #~ msgstr "Mất: đại %16u tiểu %16u t.bình %12.3f ph.sai %12.3f\n" #~ msgid "Running benchmark...\n" #~ msgstr "Äang chạy tiến trình kiểm chuẩn...\n" #~ msgid "allows profiling of direct peer-to-peer connections" #~ msgstr "cho phép Ä‘o hiệu năng sá»­ dụng cá»§a kết nối đồng đẳng trá»±c tiếp" #~ msgid "Start GNUnet transport benchmarking tool." #~ msgstr "Khởi chạy công cụ kiểm chuẩn truyá»n tải cá»§a GNUnet." #~ msgid "output in gnuplot format" #~ msgstr "kết xuất theo định dạng gnuplot" #~ msgid "number of iterations" #~ msgstr "số lần lặp lại" #~ msgid "number of messages to use per iteration" #~ msgstr "số tin nhắn cần dùng má»—i lần lặp" #~ msgid "receiver host identifier (ENC file name)" #~ msgstr "đồ nhận diện máy nhận (tên tập tin mã hoá)" #~ msgid "message size" #~ msgstr "kích cỡ tin nhắn" #~ msgid "sleep for SPACE ms after each a message block" #~ msgstr "ngá»§ KHOẢNG miligiây sau má»—i khối tin nhắn" #~ msgid "number of messages in a message block" #~ msgstr "số tin nhắn trong má»™t khối tin nhắn" #~ msgid "Error establishing connection with gnunetd.\n" #~ msgstr "Lá»—i thiết lập kết nối đến gnunetd.\n" #~ msgid "You must specify a receiver!\n" #~ msgstr "Phải ghi rõ má»™t máy nhận.\n" #~ msgid "Invalid receiver peer ID specified (`%s' is not valid name).\n" #~ msgstr "" #~ "Chỉ ra mã số đồng đẳng nhận sai (« %s » không phải là má»™t tên đúng).\n" #~ msgid "Time:\n" #~ msgstr "Thá»i gian:\n" #~ msgid "\tmax %llums\n" #~ msgstr "\tđại %llu mg\n" #~ msgid "\tmin %llums\n" #~ msgstr "\ttiểu %llu mg\n" #~ msgid "\tmean %8.4fms\n" #~ msgstr "\ttrung bình %8.4f mg\n" #~ msgid "\tvariance %8.4fms\n" #~ msgstr "\tphương sai %8.4f mg\n" #~ msgid "Loss:\n" #~ msgstr "Mất:\n" #~ msgid "\tmax %u\n" #~ msgstr "\tđại %u\n" #~ msgid "\tmin %u\n" #~ msgstr "\ttiểu %u\n" #~ msgid "\tmean %8.4f\n" #~ msgstr "\tt.bình %8.4f\n" #~ msgid "\tvariance %8.4f\n" #~ msgstr "\tph.sai %8.4f\n" #~ msgid "Output format not known, this should not happen.\n" #~ msgstr "Äịnh dạng kết xuất không rõ, Ä‘iá»u này không nên xảy ra.\n" #~ msgid "" #~ "\n" #~ "Did not receive the message from gnunetd. Is gnunetd running?\n" #~ msgstr "" #~ "\n" #~ "Không nhận được thông báo từ gnunetd. Trình ná»n gnunetd Ä‘ang chạy không?\n" #~ msgid "# bytes received in plaintext of type %d" #~ msgstr "# các byte nhập thô kiểu %d được nhận" #, fuzzy #~ msgid "# bytes allocated by SQLite" #~ msgstr "# các byte được phép trong kho dữ liệu" #~ msgid "" #~ "Failed to load MySQL database module. Check that MySQL is running and " #~ "configured properly!\n" #~ msgstr "" #~ "Lá»—i nạp mô-Ä‘un cÆ¡ sở dữ liệu MySQL. Hãy kiểm tra lại MySQL Ä‘ang chạy và " #~ "có cấu hình đúng.\n" #~ msgid "probe network to the given DEPTH" #~ msgstr "dò mạng tá»›i độ sâu SÂU đưa ra" #~ msgid "" #~ "specify output format; 0 for human readable output, 1 for dot, 2 for vcg" #~ msgstr "" #~ "chỉ ra định dạng kết quả;\n" #~ " • 0\t\tkết xuất cho ngưá»i Ä‘á»c được\n" #~ " • 1\t\tdấu chấm\n" #~ " • 2\t\tvcg" #~ msgid "use PRIORITY for the priority of the trace request" #~ msgstr "dùng ƯU_TIÊN làm ưu tiên cá»§a yêu cầu tìm đưá»ng" #~ msgid "wait DELAY seconds for replies" #~ msgstr "đợi đáp ứng TRỄ giây" #~ msgid "" #~ "Format specification invalid. Use 0 for user-readable, 1 for dot, 2 for " #~ "vcg.\n" #~ msgstr "" #~ "Äặt tả định dạng sai. Dùng:\n" #~ " • 0\t\tkết xuất cho ngưá»i Ä‘á»c được\n" #~ " • 1\t\tdấu chấm\n" #~ " • 2\t\tvcg\n" #~ msgid "allows mapping of the network topology" #~ msgstr "cho phép ánh xạ địa hình cá»§a mạng" #~ msgid "HELLO message from `%s' has an invalid signature. Dropping.\n" #~ msgstr "Thông báo HELLO từ « %s » có chữ ký sai. Äang bá» Ä‘i.\n" #~ msgid "HELLO message has expiration too far in the future. Dropping.\n" #~ msgstr "Thông báo HELLO hết hạn trong tương lai quá nhiá»u. Äang bá» Ä‘i.\n" #~ msgid "Could not send HELLO+PING, ping buffer full.\n" #~ msgstr "Không gá»­i được tín hiệu HELLO+PING, đầy bá»™ đệm ping.\n" #~ msgid "" #~ "Failed to create an advertisement for this peer. Will not send PING.\n" #~ msgstr "" #~ "Không tạo được quảng cáo cho đồng đẳng này. Sẽ không gá»­i tín hiệu PING.\n" #~ msgid "" #~ "Announcing ourselves pointless: no other peers are known to us so far.\n" #~ msgstr "Không có nghÄ©a khi tá»± thông báo : chưa biết đồng đẳng khác.\n" #~ msgid "# Peer advertisements of type NAT received" #~ msgstr "# Các quảng cáo đồng đẳng kiểu NAT được nhận" #~ msgid "# Peer advertisements updating earlier HELLOs" #~ msgstr "# Các quảng cáo đồng đẳng cập nhật tin hiệu HELLO trước" #~ msgid "# Peer advertisements for unsupported transport" #~ msgstr "# Các quảng cáo đồng đẳng cho truyá»n tải không được há»— trợ" #~ msgid "# Peer advertisements not confirmed due to ping busy" #~ msgstr "# Các quảng cáo đồng đẳng không được xác nhận do ping Ä‘ang bận" #~ msgid "# Peer advertisements not confirmed due to lack of self ad" #~ msgstr "# Các quảng cáo đồng đẳng không được xác nhận do không tá»± quảng cáo" #~ msgid "# Peer advertisements not confirmed due to send error" #~ msgstr "# Các quảng cáo đồng đẳng không được xác nhận do lá»—i gá»­i" #~ msgid "`%s' registering handler %d (plaintext and ciphertext)\n" #~ msgstr "" #~ "« %s » Ä‘ang đăng ký trình Ä‘iá»u khiển %d (nhập thô và văn bản mã hóa)\n" #~ msgid "" #~ "ensures that this peer is known by other peers and discovers other peers" #~ msgstr "" #~ "đảm bảo là đồng đẳng này được biết bởi và phát hiện các đồng đẳng khác" #~ msgid "`%s' registering handler %d\n" #~ msgstr "« %s » Ä‘ang đăng ký trình Ä‘iá»u khiển %d\n" #~ msgid "maintains GNUnet default mesh topology" #~ msgstr "bảo quản định hình mắc lưới mặc định cá»§a GNUnet" #~ msgid "`%s' registering CS handlers %d and %d\n" #~ msgstr "« %s » Ä‘ang đăng ký các trình Ä‘iá»u khiển CS %d và %d\n" #~ msgid "enables P2P-chat (incomplete)" #~ msgstr "hiệu lá»±c trò chuyện giữa các đồng đẳng (chưa hoàn tất)" #~ msgid "Existing key in file `%s' failed format check, creating new key.\n" #~ msgstr "" #~ "Kiểm tra định dạng cá»§a chìa khóa đã có trong tập tin « %s » không thành " #~ "công, Ä‘ang tạo chìa khóa máy má»›i.\n" #~ msgid "Creating new key for this nickname (this may take a while).\n" #~ msgstr "Äang tạo khoá má»›i cho tên hiệu này (có thể hÆ¡i lâu).\n" #~ msgid "# max bytes allowed in dstore" #~ msgstr "# các byte được phép trong kho dữ liệu dstore" #~ msgid "" #~ "Converting peer address to string failed, transport type %d not " #~ "supported\n" #~ msgstr "" #~ "Lá»—i chuyển đổi địa chỉ đồng đẳng sang chuá»—i, kiểu truyá»n tải %d không " #~ "được há»— trợ\n" #~ msgid "" #~ "Transport connection attempt failed, transport type %d not supported\n" #~ msgstr "" #~ "Lá»—i thá»­ kết nối truyá»n tải, kiểu cÆ¡ chế truyá»n %d không được há»— trợ\n" #~ msgid "" #~ "Transport failed to connect to peer `%s' (%u HELLOs known, none worked)\n" #~ msgstr "" #~ "Truyá»n tải không kết nối được tá»›i đồng đẳng « %s » (đã biết %u tín hiệu " #~ "HELLO, mà không có tín hiệu nào hoạt động được)\n" #~ msgid "No transport succeeded in creating a hello!\n" #~ msgstr "Không có truyá»n tải nào đã tạo được má»™t tín hiệu HELLO.\n" #~ msgid "Transport library `%s' did not provide required function '%s%s'.\n" #~ msgstr "" #~ "Thư viện truyá»n tải « %s » không cung cấp chức năng yêu cầu « %s%s ».\n" #~ msgid "Query (get KEY, put KEY VALUE) DHT table." #~ msgstr "Há»i (nhận KHOÃ, gá»­i GIÃ_TRỊ_KHOÃ) bảng DHT." #~ msgid "allow TIME ms to process a GET command" #~ msgstr "cho phép THỜI_GIAN mili giây để xá»­ lý má»—i câu lệnh GET (lấy)" #~ msgid "Issuing `%s(%s,%s)' command.\n" #~ msgstr "Äang cấp câu lệnh « %s(%s,%s) ».\n" #~ msgid "Command `%s' requires an argument (`%s').\n" #~ msgstr "Câu lệnh « %s » cần đến má»™t đối số (« %s »).\n" #~ msgid "Command `%s' requires two arguments (`%s' and `%s').\n" #~ msgstr "Câu lệnh « %s » cần đến hai đối số (« %s » và « %s »).\n" #~ msgid "# dht route host lookups performed" #~ msgstr "# các việc tra tìm đưá»ng tá»›i máy dht được làm" #~ msgid "# dht discovery messages sent" #~ msgstr "# các thông báo phát hiện dht được gá»­i" #~ msgid "# dht put requests received" #~ msgstr "# các yêu cầu put (gá»­i) dht được nhận" #~ msgid "`%s' registering p2p handlers: %d %d %d\n" #~ msgstr "« %s » Ä‘ang đăng ký các trình Ä‘iá»u khiển p2p: %d %d %d\n" #~ msgid "`%s' failed. Terminating connection to client.\n" #~ msgstr "« %s » bị lá»—i. Äang chấm dứt kết nối tá»›i máy khách.\n" #~ msgid "`%s' registering client handlers: %d %d\n" #~ msgstr "« %s » Ä‘ang đăng ký các trình Ä‘iá»u khiển máy khách: %d %d\n" #~ msgid "Enables efficient non-anonymous routing" #~ msgstr "Hiệu lá»±c định tuyến khác nặc danh hiệu dụng" #~ msgid "" #~ "Existing hostkey in file `%s' failed format check, creating new hostkey.\n" #~ msgstr "" #~ "Kiểm tra định dạng cá»§a chìa khóa máy trong tập tin « %s » không thành " #~ "công, Ä‘ang tạo chìa khóa máy má»›i.\n" #~ msgid "Done creating hostkey.\n" #~ msgstr "Hoàn thành tạo khoá máy.\n" #~ msgid "Removed file `%s' containing invalid HELLO data.\n" #~ msgstr "Äã gỡ bá» tập tin « %s » chứa dữ liệu HELLO sai.\n" #~ msgid "Signature failed verification: signature invalid.\n" #~ msgstr "Không thẩm tra được chữ ký: chữ ký sai.\n" #~ msgid "Peer `%s' is currently strictly blacklisted (for another %llums).\n" #~ msgstr "" #~ "Äồng đẳng « %s » hiện thá»i bị cấm hoàn toàn (trong %llu miligiây sau).\n" #~ msgid "Peer `%s' is currently blacklisted (for another %llums).\n" #~ msgstr "Äồng đẳng « %s » hiện thá»i bị cấm (trong %llu miligiây sau).\n" #~ msgid "Received malformed `%s' message. Dropping.\n" #~ msgstr "Nhận được thông báo « %s » bị há»ng. Äang bá» Ä‘i.\n" #~ msgid "Received ping for another peer. Dropping.\n" #~ msgstr "Nhận được tin hiệu ping cho đồng đẳng khác. Äang bá» Ä‘i.\n" #~ msgid "" #~ "Could not match PONG against any PING. Try increasing MAX_PING_PONG " #~ "constant.\n" #~ msgstr "" #~ "Không tương ứng được PONG đối vá»›i bất kỳ PING. Hãy thá»­ tăng hằng số " #~ "MAX_PING_PONG.\n" #~ msgid "Cannot create PING, table full. Try increasing MAX_PING_PONG.\n" #~ msgstr "Không tạo được PING, bảng đầy. Hãy thá»­ tăng MAX_PING_PONG.\n" #~ msgid "# plaintext PONG messages received" #~ msgstr "# các thông báo PONG nhập thô được nhận" #~ msgid "# encrypted PING messages received" #~ msgstr "# các thông báo PING đã mật mã được nhận" #~ msgid "# encrypted PING messages sent" #~ msgstr "# các thông báo PING đã mật mã được gá»­i" #~ msgid "`%s' registering handlers %d %d (plaintext and ciphertext)\n" #~ msgstr "" #~ "« %s » Ä‘ang đăng ký các trình Ä‘iá»u khiển %d %d (nhập thô và văn bản mã " #~ "hóa)\n" #~ msgid "# hostlist HELLOs returned" #~ msgstr "# các lá»i chào mừng HELLO danh sách máy được trả vá»" #~ msgid "Cannot encrypt sessionkey, peer `%s' not known!\n" #~ msgstr "Không thể mã hoá khoá phiên chạy, không rõ đồng đẳng « %s ».\n" #~ msgid "Could not create any HELLO for myself (have transports `%s')!\n" #~ msgstr "Không thể tạo tín hiệu HELLO nào cho mình (có truyá»n tải « %s »).\n" #~ msgid "" #~ "Session key received from peer `%s' has invalid format (discarded).\n" #~ msgstr "" #~ "Khoá phiên chạy được nhận từ đồng đẳng « %s » có định dạng sai (bị há»§y).\n" #~ msgid "Session key received from peer `%s' is for `%s' and not for me!\n" #~ msgstr "" #~ "Khoá phiên chạy được nhận từ đồng đẳng « %s » dành cho « %s », không phải " #~ "cho tôi.\n" #~ msgid "setkey `%s' from `%s' fails CRC check (have: %u, want %u).\n" #~ msgstr "" #~ "Kiểm tra CRC setkey « %s » từ « %s » không thành công (có %u, còn muốn " #~ "%u).\n" #~ msgid "" #~ "Error parsing encrypted session key from `%s', given message part size is " #~ "invalid.\n" #~ msgstr "" #~ "Lá»—i phân tích chìa khóa phiên chạy đã mã hóa từ « %s », kích cỡ cá»§a phần " #~ "thông báo đưa ra là sai.\n" #~ msgid "Unknown type in embedded message from `%s': %u (size: %u)\n" #~ msgstr "" #~ "Gặp kiểu không rõ trong thông báo nhúng từ « %s »: %u (kích cỡ : %u)\n" #~ msgid "# sessions established" #~ msgstr "# các phiên chạy được thiết lập" #~ msgid "automate creation of a namespace by starting a collection" #~ msgstr "tá»± động tạo má»™t không gian tên bằng cách bắt đầu má»™t thu thập" #~ msgid "create a new pseudonym under the given NICKNAME" #~ msgstr "tạo má»™t biệt hiệu má»›i dưới TÊN_HIỆU đưa ra" #~ msgid "delete the pseudonym with the given NICKNAME" #~ msgstr "xoá biệt hiệu có TÊN_HIỆU đã cho" #~ msgid "end automated building of a namespace (ends collection)" #~ msgstr "" #~ "kết thúc việc tá»± động xây dá»±ng má»™t không gian tên (kết thúc thu thập)" #~ msgid "" #~ "Create new pseudonyms, delete pseudonyms or list existing pseudonyms." #~ msgstr "Tạo biệt hiệu má»›i, xóa biệt hiệu hoặc liệt kê các biệt hiệu có." #~ msgid "" #~ "use the given keyword to advertise the namespace (use when creating a new " #~ "pseudonym)" #~ msgstr "" #~ "sá»­ dụng từ khóa đưa ra để quảng cáo không gian tên (dùng khi tạo má»™t biệt " #~ "hiệu má»›i)" #~ msgid "specify metadata describing the namespace or collection" #~ msgstr "ghi rõ siêu dữ liệu mô tả không gian tên (hoặc thu thập)" #~ msgid "" #~ "do not generate an advertisement for this namespace (use when creating a " #~ "new pseudonym)" #~ msgstr "" #~ "đừng tạo ra má»™t quảng cáo cho không gian tên này (dùng khi tạo má»™t biệt " #~ "hiệu má»›i)" #~ msgid "do not list the pseudonyms from the pseudonym database" #~ msgstr "không liệt kê các biệt hiệu từ cÆ¡ sở dữ liệu biệt hiệu" #~ msgid "" #~ "specify IDENTIFIER to be the address of the entrypoint to content in the " #~ "namespace (use when creating a new pseudonym)" #~ msgstr "" #~ "ghi rõ BỘ_NHẬN_DIỆN là địa chỉ cá»§a Ä‘iểm vào ná»™i dung trong không gian tên " #~ "(dùng khi tạo má»™t biệt hiệu má»›i)" #~ msgid "Namespace `%s' (%s) has rating %d.\n" #~ msgstr "Không gian tên « %s » (%s) có đánh giá %d.\n" #~ msgid "\tRating (after update): %d\n" #~ msgstr "\tÄánh giá (sau khi cập nhật): %d\n" #~ msgid "Collection stopped.\n" #~ msgstr "Thu thập bị dừng.\n" #~ msgid "Failed to stop collection (not active?).\n" #~ msgstr "Lá»—i dừng thu thập (không hoạt động ?).\n" #~ msgid "Pseudonym `%s' deleted.\n" #~ msgstr "Biệt hiệu « %s » bị xoá.\n" #~ msgid "Error deleting pseudonym `%s' (does not exist?).\n" #~ msgstr "Lá»— xoá biệt hiệu « %s » (không tồn tại ?).\n" #~ msgid "Started collection.\n" #~ msgstr "Äã bắt đầu thu thập.\n" #~ msgid "Namespace `%s' created (root: %s).\n" #~ msgstr "Äã tạo không gian tên « %s » (gốc: %s).\n" #~ msgid "You must specify a name for the collection (`%s' option).\n" #~ msgstr "Bạn phải ghi rõ má»™t tên cho thu thập (tùy chá»n « %s »).\n" #~ msgid "%d files found in directory.\n" #~ msgstr "Tìm thấy %d tập tin trong thư mục.\n" #~ msgid "Perform directory related operations." #~ msgstr "Thá»±c hiện các thao tác liên quan đến thư mục." #~ msgid "" #~ "remove all entries from the directory database and stop tracking URIs" #~ msgstr "" #~ "gỡ bá» má»i mục nhập khá»i cÆ¡ sở dữ liệu thư mục, và dừng theo dõi các địa " #~ "chỉ URI" #~ msgid "list entries from the directory database" #~ msgstr "liệt kê các mục nhập từ cÆ¡ sở dữ liệu thư mục" #~ msgid "start tracking entries for the directory database" #~ msgstr "bắt đầu theo dõi các mục nhập cho cÆ¡ sở dữ liệu thư mục" #~ msgid "Listed %d matching entries.\n" #~ msgstr "Äã liệt kê %d mục nhập tương ứng.\n" #~ msgid "Upload of `%s' at %llu out of %llu bytes.\n" #~ msgstr "Tải lên tập tin « %s » tại %llu trên %llu byte.\n" #~ msgid "Upload aborted.\n" #~ msgstr "Tải lên bị há»§y bá».\n" #~ msgid "Uploading suspended.\n" #~ msgstr "Tiến trình tải lên bị ngưng.\n" #~ msgid "" #~ "run in debug mode; gnunet-auto-share will not daemonize and error " #~ "messages will be written to stderr instead of a logfile" #~ msgstr "" #~ "chạy trong chế độ tìm sá»­a lá»—i; gnunet-auto-share sẽ không trở thành trình " #~ "ná»n và sẽ ghi thông báo lá»—i ra đầu lá»—i tiêu chuẩn thay vì vào má»™t tập tin " #~ "ghi sá»± kiện." #~ msgid "" #~ "do not use libextractor to add additional references to directory entries " #~ "and/or the published file" #~ msgstr "" #~ "đừng dùng libextractor để thêm các tham chiếu bổ sung vào mục nhập thư " #~ "mục và/hay tập tin công bố" #~ msgid "Automatically share a directory." #~ msgstr "Tá»± động chia sẻ má»™t thư mục." #~ msgid "Unknown keyword type `%s' in metadata configuration\n" #~ msgstr "Không rõ kiểu từ khoá « %s » trong cấu hình siêu dữ liệu\n" #~ msgid "Directory `%s' is already on the list of shared directories.\n" #~ msgstr "Thư mục « %s » đã có trong danh sách các thư mục dùng chung.\n" #~ msgid "" #~ "The specified directories were added to the list of shared directories.\n" #~ msgstr "" #~ "Những thư mục đưa ra đã được thêm vào danh sách các thư mục dùng chung.\n" #~ msgid "Created entry `%s' in namespace `%s'\n" #~ msgstr "Äã tạo mục nhập « %s » trong không gian tên « %s »\n" #~ msgid "mimetype" #~ msgstr "kiểu MIME" #~ msgid "" #~ "%16llu of %16llu bytes inserted (estimating %6s to completion) - %s\n" #~ msgstr "" #~ "đã chèn %16llu trên %16llu byte (sẽ hoàn thành trong khoảng %6s giây) - " #~ "%s\n" #~ msgid "" #~ "Upload of `%s' complete, %llu bytes took %llu seconds (%8.3f KiB/s).\n" #~ msgstr "" #~ "Hoàn thành tải lên « %s », %llu byte trong %llu giây (%8.3f KiB/giây).\n" #~ msgid "" #~ "\n" #~ "Upload aborted.\n" #~ msgstr "" #~ "\n" #~ "Tải lên bị há»§y bá».\n" #~ msgid "" #~ "\n" #~ "Error uploading file: %s" #~ msgstr "" #~ "\n" #~ "Gặp lá»—i khi tải lên tập tin: %s" #~ msgid "" #~ "\n" #~ "Unexpected event: %d\n" #~ msgstr "" #~ "\n" #~ "Gặp sá»± kiện bất thưá»ng: %d\n" #~ msgid "" #~ "even if gnunetd is running on the local machine, force the creation of a " #~ "copy instead of making a link to the GNUnet share directory" #~ msgstr "" #~ "thậm chí nếu gnunetd Ä‘ang chạy trên máy cục bá»™, bắt buá»™c tạo má»™t bản sao " #~ "thay vì tạo má»™t liên kết đến thư mục chia sẻ cá»§a GNUnet" #~ msgid "Make files available to GNUnet for sharing." #~ msgstr "Làm cho các tập tin sẵn sàng qua GNUnet để chia sẻ." #~ msgid "Could not access namespace `%s' (does not exist?).\n" #~ msgstr "Không thể truy cập đến không gian tên « %s » (không tồn tại ?).\n" #~ msgid "Search GNUnet for files." #~ msgstr "Tìm tập tin trong GNUnet." #~ msgid "write encountered (decrypted) search results to FILENAME" #~ msgstr "ghi kết quả tìm kiếm tìm thấy (đã giải mã) vào tập tin TÊN_TẬP_TIN" #~ msgid "Error converting arguments to URI!\n" #~ msgstr "Gặp lá»—i khi chuyển đổi các đối số sang URI.\n" #~ msgid "" #~ "%16llu of %16llu bytes unindexed (estimating %llu seconds to " #~ "completion) " #~ msgstr "" #~ "Äã bá» chỉ mục %16llu trên %16llu byte (sẽ hoàn thành sau khoảng %llu " #~ "giây) " #~ msgid "" #~ "\n" #~ "Unindexing of `%s' complete, %llu bytes took %llu seconds (%8.3f KiB/s).\n" #~ msgstr "" #~ "\n" #~ "Hoàn thành bá» chỉ mục cá»§a « %s », %llu byte sau %llu giây (%8.3f KiB/" #~ "giây).\n" #~ msgid "Not enough arguments. You must specify a filename.\n" #~ msgstr "Không đủ đối số. Phải xác định má»™t tên tập tin.\n" #~ msgid "`%s' failed. Is `%s' a file?\n" #~ msgstr "« %s » bị lá»—i. « %s » là má»™t tập tin phải không?\n" #~ msgid "" #~ "download a GNUnet directory that has already been downloaded. Requires " #~ "that a filename of an existing file is specified instead of the URI. The " #~ "download will only download the top-level files in the directory unless " #~ "the `-R' option is also specified." #~ msgstr "" #~ "tải xuống má»™t thư mục GNUnet đã được tải vá» trước. Cần thiết ghi rõ tên " #~ "tập tin cá»§a má»™t tập tin đã có, thay cho địa chỉ URI. Việc tải vá» sẽ chỉ " #~ "tải vá» các tập tin cấp đầu cá»§a thư mục, nếu không cÅ©ng đưa ra tùy chá»n « -" #~ "R »." #~ msgid "Download files from GNUnet." #~ msgstr "Tải tập tin xuống GNUnet." #~ msgid "Download of file `%s' at %16llu out of %16llu bytes (%8.3f KiB/s)\n" #~ msgstr "" #~ "Tải xuống tập tin « %s » tại %16llu trên %16llu byte (%8.3f KiB/giây)\n" #~ msgid "Download aborted.\n" #~ msgstr "Tiến trình tải xuống bị há»§y bá».\n" #~ msgid "Download of file `%s' complete. Speed was %8.3f KiB per second.\n" #~ msgstr "" #~ "Hoàn thành tải xuống tập tin « %s ». Tốc độ là %8.3f KiB má»™t giây.\n" #~ msgid "Not enough arguments. You must specify a GNUnet file URI\n" #~ msgstr "Không đủ đối số. Phải ghi rõ má»™t địa chỉ URI tập tin GNUnet\n" #~ msgid "URI `%s' invalid for gnunet-download.\n" #~ msgstr "Sai URI « %s » cho gnunet-download.\n" #~ msgid "No filename specified, using `%s' instead (for now).\n" #~ msgstr "Chưa ghi rõ tên tập tin, Ä‘ang dùng « %s » để thay thế (lúc này).\n" #~ msgid "Downloading %d files from directory `%s'.\n" #~ msgstr "Äang tải %d tập tin xuống thư mục « %s ».\n" #~ msgid "File stored as `%s'.\n" #~ msgstr "Tập tin được lưu dạng « %s ».\n" #~ msgid "Collecting file identifiers disabled.\n" #~ msgstr "Chức năng thu thập các đồ nhận diện tập tin đã bị tắt.\n" #~ msgid "Deleted corrupt URI database in `%s'." #~ msgstr "Äã xoá cÆ¡ sở dữ liệu địa chỉ URI bị há»ng trong « %s »." #~ msgid "Cannot get size of file `%s'" #~ msgstr "Không thể lấy kích cỡ cá»§a tập tin « %s »" #~ msgid "Cannot hash `%s'.\n" #~ msgstr "Không thể tạo mẫu duy nhất đại diện cho « %s ».\n" #~ msgid "Initialization for indexing file `%s' failed.\n" #~ msgstr "Lá»—i sÆ¡ khởi tập tin đánh chỉ mục « %s ».\n" #~ msgid "Cannot open file `%s': `%s'" #~ msgstr "Không thể mở tập tin « %s »: « %s »" #~ msgid "Renaming of file `%s' to `%s' failed: %s\n" #~ msgstr "Lá»—i thay đổi tên cá»§a tập tin « %s » thành « %s »: %s\n" #~ msgid "Could not rename file `%s' to `%s': file exists\n" #~ msgstr "Không thể thay đổi tên tập tin « %s » thành « %s »: tập tin đã có\n" #~ msgid "CHK URI not allowed for search.\n" #~ msgstr "Không cho phép địa chỉ URI CHK khi tìm kiếm.\n" #~ msgid "LOC URI not allowed for search.\n" #~ msgstr "Không cho phép địa chỉ URI LOC khi tìm kiếm.\n" #~ msgid "File `%s' does not contain a pseudonym.\n" #~ msgstr "Tập tin « %s » không chứa biệt hiệu.\n" #~ msgid "Format of pseudonym `%s' is invalid.\n" #~ msgstr "Äịnh dạng cá»§a biệt hiệu « %s » là không hợp lệ.\n" #~ msgid "Format of file `%s' is invalid, trying to remove.\n" #~ msgstr "Äịnh dạng cá»§a tập tin « %s » là không hợp lệ nên thá»­ gỡ bá».\n" #~ msgid "" #~ "Decrypted content does not match key. This is either a bug or a " #~ "maliciously inserted file. Download aborted.\n" #~ msgstr "" #~ "Ná»™i dung đã giải mã không tương ứng chìa khóa. Äây là má»™t lá»—i hoặc má»™t " #~ "tập tin chèn vào vá»›i ý xấu. Tiến trình tải xuống bị há»§y bá».\n" #~ msgid "Revision %u" #~ msgstr "Bản sá»­a đổi %u" #~ msgid "Application aborted." #~ msgstr "Ứng dụng bị há»§y bá»." #~ msgid "FSUI state file `%s' had syntax error at offset %u.\n" #~ msgstr "Tập tin tình trạng FSUI « %s » có lá»—i cú pháp tại khoảng bù %u.\n" #~ msgid "# gap content total planned" #~ msgstr "# tổng số ná»™i dung lá»— hổng dá»± định" #~ msgid "Datastore full.\n" #~ msgstr "Kho dữ liệu đầy.\n" #~ msgid "# gap requests total received" #~ msgstr "# tổng số yêu cầu lá»— hổng được nhận" #~ msgid "# gap total trust awarded" #~ msgstr "# tổng số tin cậy lá»— hổng được cấp" #~ msgid "" #~ "`%s' registering client handlers %d %d %d %d %d %d %d %d and P2P handlers " #~ "%d %d\n" #~ msgstr "" #~ "« %s » Ä‘ang đăng ký các trình Ä‘iá»u khiển kiểu ứng dụng khách %d %d %d %d " #~ "%d %d %d %d và kiểu P2P %d %d\n" #~ msgid "enables (anonymous) file-sharing" #~ msgstr "hiệu lá»±c chia sẻ tập tin (nặc danh)" #~ msgid "" #~ "Because the file `%s' has been unavailable for 3 days it got removed from " #~ "your share. Please unindex files before deleting them as the index now " #~ "contains invalid references!\n" #~ msgstr "" #~ "Vì không có tập tin « %s » trong 3 ngày nên đã xóa nó khá»i chia sẻ cá»§a " #~ "bạn. Xin hãy bá» chỉ mục các tập tin trước khi xoá chúng vì chỉ mục hiện " #~ "thá»i chứa các tham chiếu sai.\n" #~ msgid "Indexed content changed (does not match its hash).\n" #~ msgstr "" #~ "Ná»™i dung đánh chỉ mục bị thay đổi (không tương ứng vá»›i tổng kiểm).\n" #~ msgid "" #~ "Unindexed ODB block `%s' from offset %llu already missing from " #~ "datastore.\n" #~ msgstr "" #~ "Khối ODB đã bá» chỉ mục « %s » từ khoảng bù %llu đã không có trong kho dữ " #~ "liệu.\n" #~ msgid "# distinct interned peer IDs in pid table" #~ msgstr "# các mã số đồng đẳng bị giam giữ riêng biệt trong bảng PID" #~ msgid "# total RC of interned peer IDs in pid table" #~ msgstr "# tổng số RC cá»§a mã số đồng đẳng bị giam giữ trong bảng PID" #~ msgid "# gap client requests tracked" #~ msgstr "# các yêu cầu máy/trình khách lá»— hổng được theo dõi" #~ msgid "# gap query bloomfilter resizing updates" #~ msgstr "" #~ "# các bản cập nhật thay đổi kích cỡ bá»™ lá»c bloomfilter truy vấn lá»— hổng" #~ msgid "# blocks migrated" #~ msgstr "# các khối được nâng cấp" #~ msgid "# blocks injected for migration" #~ msgstr "# các khối được phun vào để nâng cấp" #~ msgid "# on-demand fetches for migration" #~ msgstr "# các lần lấy theo yêu cầu để nâng cấp" #~ msgid "# gap queries dropped (table full)" #~ msgstr "# các truy vấn lá»— hổng bị bá» (bảng đầy)" #~ msgid "# gap queries dropped (redundant)" #~ msgstr "# các truy vấn lá»— hổng bị bá» (thừa)" #~ msgid "# gap queries refreshed existing record" #~ msgstr "# các truy vấn lá»— hổng đã cập nhật mục ghi đã có" #~ msgid "# trust earned" #~ msgstr "# độ tin cậy giành được" #~ msgid "# blocks pushed into DHT" #~ msgstr "# các khối được đẩy vào DHT" #~ msgid "scp command is : %s \n" #~ msgstr "Câu lệnh scp là: %s\n" #~ msgid "Friend list of %s:%d\n" #~ msgstr "Danh sách bạn bè cá»§a %s:%d\n" #~ msgid "scp command for friend file copy is : %s \n" #~ msgstr "Câu lệnh scp cho bản sao tập tin bạn bè là: %s\n" #~ msgid "Set up multiple gnunetd daemons across multiple hosts." #~ msgstr "Thiết lập nhiá»u trình ná»n gnunetd qua nhiá»u máy khác nhau." #~ msgid "Waiting for peers to connect" #~ msgstr "Äang đợi các đồng đẳng kết nối" #~ msgid "Bootstrap data obtained from `%s' is invalid.\n" #~ msgstr "Sai dữ liệu nạp và khởi động được lấy từ « %s ».\n" #~ msgid "`%s' registering client handler %d\n" #~ msgstr "« %s » Ä‘ang đăng ký trình Ä‘iá»u khiển máy khách %d\n" #~ msgid "allows clients to determine gnunetd's configuration" #~ msgstr "cho phép máy khách quyết định cấu hình cá»§a trình ná»n gnunetd." #~ msgid "`%s' registering client handler %d and %d\n" #~ msgstr "« %s » Ä‘ang đăng ký trình Ä‘iá»u khiển máy khách %d và %d\n" #~ msgid "Template description." #~ msgstr "Mô tả mẫu." #~ msgid "Uptime (seconds)" #~ msgstr "Thá»i gian chạy (giây)" #~ msgid "# Any-Blocks" #~ msgstr "# Khối bất kỳ" #~ msgid "# DBlocks" #~ msgstr "# Khối D" #~ msgid "# SBlocks" #~ msgstr "# Khối S" #~ msgid "# KBlocks" #~ msgstr "# Khối K" #~ msgid "# NBlocks" #~ msgstr "# Khối N" #~ msgid "# KNBlocks" #~ msgstr "# Khối KN" #~ msgid "# OnDemand-Blocks" #~ msgstr "# Khối theo yêu cầu" #~ msgid "# Unknown-Blocks" #~ msgstr "# Khối không rõ" #~ msgid "# expired" #~ msgstr "# đã hết hạn" #~ msgid "# expire in 1h" #~ msgstr "# hết hạn trong 1 giá»" #~ msgid "# expire in 24h" #~ msgstr "# hết hạn trong 24 giá»" #~ msgid "# expire in 1 week" #~ msgstr "# hết hạn trong 1 tuần" #~ msgid "# expire in 1 month" #~ msgstr "# hết hạn trong 1 tháng" #~ msgid "# zero priority" #~ msgstr "# ưu tiên 0" #~ msgid "# priority one" #~ msgstr "# ưu tiên 1" #~ msgid "# priority larger than one" #~ msgstr "# ưu tiên >1" #~ msgid "# no anonymity" #~ msgstr "# nặc danh 0" #~ msgid "# anonymity one" #~ msgstr "# nặc danh 1" #~ msgid "# anonymity larger than one" #~ msgstr "# nặc danh >1" #~ msgid "% of allowed network load (up)" #~ msgstr "% trá»ng tải mạng được phép (chạy)" #~ msgid "% of allowed network load (down)" #~ msgstr "% trá»ng tải mạng được phép (không chạy)" #~ msgid "% of allowed cpu load" #~ msgstr "% trá»ng tải CPU được phép" #~ msgid "% of allowed io load" #~ msgstr "% trá»ng tải V/R được phép" #~ msgid "# plibc handles" #~ msgstr "# các bá»™ xá»­ lý plibc" #~ msgid "`%s' registering client handlers %d %d %d and p2p handler %d\n" #~ msgstr "" #~ "« %s » Ä‘ang đăng ký các trình Ä‘iá»u khiển máy khách %d %d %d và trình Ä‘iá»u " #~ "khiển đồng đẳng %d\n" #~ msgid "keeps statistics about gnunetd's operation" #~ msgstr "tính thống kê vá» thao tác gnunetd" #~ msgid "Supported peer-to-peer messages:\n" #~ msgstr "Thông báo đồng đẳng được há»— trợ :\n" #~ msgid "Supported client-server messages:\n" #~ msgstr "Thông báo máy khách-chá»§ được há»— trợ :\n" #~ msgid "prints supported protocol messages" #~ msgstr "in ra các thông báo giao thức được há»— trợ" #~ msgid "Suppress display of asynchronous log messages" #~ msgstr "Thu hồi hiển thị các thông Ä‘iệp ghi sá»± kiện không đồng bá»™" #~ msgid "VPN IP src not anonymous. drop..\n" #~ msgstr "VPN Nguồn địa chỉ IP không phải nặc danh, bá» Ä‘i.\n" #~ msgid "VPN IP not anonymous, drop.\n" #~ msgstr "VPN Äịa chỉ IP không phải nặc danh, bá» Ä‘i.\n" #~ msgid "VPN Received, not anonymous, drop.\n" #~ msgstr "VPN Nhận được, không phải nặc danh, bá» Ä‘i.\n" #~ msgid "VPN Received unknown IP version %d...\n" #~ msgstr "VPN Nhận được phiên bản IP không rõ %d...\n" #~ msgid "<- GNUnet(%d) : %s\n" #~ msgstr "<- GNUnet(%d) : %s\n" #~ msgid "" #~ "Could not write the tunnelled IP to the OS... Did to setup a tunnel?\n" #~ msgstr "" #~ "Không thể ghi vào HÄH địa chỉ IP theo đưá»ng hầm... Äã làm để thiết lập " #~ "má»™t đưá»ng hầm ?\n" #~ msgid "Prepare route announcement level %d\n" #~ msgstr "Chuẩn bị thông cáo định tuyến cấp %d\n" #~ msgid "Send route announcement %d with route announce\n" #~ msgstr "Gá»­i thông cáo định tuyến %d vá»›i đưá»ng đã báo\n" #~ msgid "Send outside table info %d\n" #~ msgstr "Gá»­i thông tin bảng bên ngoài %d\n" #~ msgid "Receive route announce.\n" #~ msgstr "Nhận thông cáo định tuyến.\n" #~ msgid "Going to try insert route into local table.\n" #~ msgstr "Sẽ thá»­ chèn đưá»ng vào bảng cục bá»™.\n" #~ msgid "Inserting with hops %d\n" #~ msgstr "Äang chèn vá»›i số bước nhảy %d\n" #~ msgid "Request level %d from peer %d\n" #~ msgstr "Yêu cầu cấp %d từ đồng đẳng %d\n" #~ msgid "Receive table limit on peer reached %d\n" #~ msgstr "Giá»›i hạn bảng nhận trên đồng đẳng đã tá»›i %d\n" #~ msgid "Not storing route to myself from peer %d\n" #~ msgstr "Không phải lưu lại đưá»ng đến máy này từ đồng đẳng %d\n" #~ msgid "Duplicate route to node from peer %d, choosing minimum hops" #~ msgstr "" #~ "ÄÆ°á»ng trùng đến nút từ đồng đẳng %d, Ä‘ang chá»n đưá»ng có ít bước nhảy hÆ¡n" #~ msgid "Inserting route from peer %d in route table at location %d\n" #~ msgstr "Äang chèn đưá»ng từ đồng đẳng %d vào bảng định tuyến tại vị trí %d\n" #~ msgid "RFC4193 Frame length %d is too big for GNUnet!\n" #~ msgstr "RFC4193 Chiá»u dài khung %d quá lá»›n cho GNUnet!\n" #~ msgid "RFC4193 Frame length %d too small\n" #~ msgstr "RFC4193 Chiá»u dài khung %d quá nhá»\n" #~ msgid "RFC4193 Ethertype %x and IP version %x do not match!\n" #~ msgstr "RFC4193 Ethertype %x và phiên bản IP %x không tương ứng.\n" #~ msgid "RFC4193 Going to try and make a tunnel in slot %d\n" #~ msgstr "RFC4193 Sẽ thá»­ tạo má»™t đưá»ng hầm trong khoảng %d\n" #, fuzzy #~ msgid "Cannot open tunnel device: %s" #~ msgstr "Không thể mở thiết bị đưá»ng hầm do %s" #~ msgid "RFC4193 Create skips gnu%d as we are already using it\n" #~ msgstr "RFC4193 Chức năng tạo sẽ ná» qua gnu%d vì chúng ta Ä‘ang dùng nó\n" #~ msgid "Cannot set tunnel name to %s because of %s\n" #~ msgstr "không thể đặt tên đưá»ng hầm thành %s do %s\n" #~ msgid "Configured tunnel name to %s\n" #~ msgstr "Tên đưá»ng hầm đã được cấu hình thành %s\n" #~ msgid "Cannot get socket flags for gnu%d because %s\n" #~ msgstr "Không thể lấy các cỠổ cắm cho gnu%d do %s\n" #~ msgid "Cannot set socket flags for gnu%d because %s\n" #~ msgstr "Không thể đặt các cỠổ cắm cho gnu%d do %s\n" #~ msgid "Cannot set MTU for gnu%d because %s\n" #~ msgstr "Không thể đặt MTU cho gnu%d do %s\n" #~ msgid "Cannot get interface index for gnu%d because %s\n" #~ msgstr "Không thể lấy chá»§ mục giao diện cho gnu%d do %s\n" #~ msgid "IPv6 ifaddr gnu%d - %x:%x:%x:%x:%x:%x:%x:%x/%d\n" #~ msgstr "IPv6 ifaddr gnu%d - %x:%x:%x:%x:%x:%x:%x:%x/%d\n" #~ msgid "Cannot set interface IPv6 address for gnu%d because %s\n" #~ msgstr "Không thể đặt địa chỉ IPv6 cá»§a giao diện cho gnu%d do %s\n" #~ msgid "IPv6 route gnu%d - destination %x:%x:%x:%x:%x:%x:%x:%x/%d\n" #~ msgstr "ÄÆ°á»ng IPv6 gnu%d - đích đến %x:%x:%x:%x:%x:%x:%x:%x/%d\n" #~ msgid "Cannot add route IPv6 address for gnu%s because %s\n" #~ msgstr "Không thể thêm địa chỉ IPv6 cá»§a đưá»ng cho gnu%s do %s\n" #~ msgid "" #~ "RFC4193 We have run out of memory and so I can't store a tunnel for this " #~ "peer.\n" #~ msgstr "" #~ "RFC4193 Tràn bá»™ nhá»› thì không thể cất giữ má»™t đưá»ng hầm cho đồng đẳng " #~ "này.\n" #~ msgid "RFC4193 Thread running (frame %d tunnel %d f2f %d) ...\n" #~ msgstr "RFC4193 Mạch Ä‘ang chạy (khung %d đưá»ng hầm %d f2f %d) ...\n" #~ msgid "VPN dropping connection %x\n" #~ msgstr "VPN Ä‘ang bá» Ä‘i kết nối %x\n" #~ msgid "VPN cannot drop connection %x\n" #~ msgstr "VPN không thể bá» Ä‘i kết nối %x\n" #~ msgid "RFC4193 Thread exiting\n" #~ msgstr "RFC4193 Mạch Ä‘ang thoát\n" #~ msgid "realise alloc ram\n" #~ msgstr "realise cấp phát bá»™ nhá»› RAM\n" #~ msgid "realise add routes\n" #~ msgstr "realise thêm đưá»ng\n" #~ msgid "realise copy table\n" #~ msgstr "realise chép bảng\n" #~ msgid "`%s' initialising RFC4913 module %d and %d\n" #~ msgstr "« %s » Ä‘ang sÆ¡ khởi mô-Ä‘un RFC4913 %d và %d\n" #~ msgid "RFC4193 my First 4 hex digits of host id are %x\n" #~ msgstr "RFC4193 my 4 chữ số thập lúc đầu tiên cá»§a mã số máy là %x\n" #~ msgid "enables IPv6 over GNUnet (incomplete)" #~ msgstr "hiệu lá»±c IPv6 qua GNUnet (chưa hoàn tất)" #~ msgid "RFC4193 Waiting for tun thread to end\n" #~ msgstr "RFC4193 Äang đợi kết thúc mạch tun\n" #~ msgid "RFC4193 The tun thread has ended\n" #~ msgstr "RFC4193 Mạch tun đã kết thúc\n" #~ msgid "RFC4193 Closing tunnel %d fd %d\n" #~ msgstr "RFC4193 Äang đóng đưá»ng hầm %d fd %d\n" #~ msgid "Configuration value `%s' under [MODULES] for `%s' is invalid!\n" #~ msgstr "Sai giá trị cấu hình « %s » dưới [MÔ-ÄUN] cho « %s ».\n" #~ msgid "Application module `%s' already initialized!\n" #~ msgstr "Mô-Ä‘un ứng dụng « %s » đã được sở khởi.\n" #~ msgid "Failed to load plugin `%s' at %s:%d. Unloading plugin.\n" #~ msgstr "Lá»—i nạp phần bổ sung « %s » tại %s:%d. Äang há»§y nạp phần bổ sung.\n" #~ msgid "Could not shutdown `%s': application not loaded\n" #~ msgstr "Không thể tắt « %s »: chưa nạp ứng dụng\n" #~ msgid "Could not shutdown application `%s': not initialized\n" #~ msgstr "Không thể tắt ứng dụng « %s »: chưa được sÆ¡ khởi\n" #~ msgid "Could not release %p: service not loaded\n" #~ msgstr "Không thể giải phóng %p: chưa nạp dịch vụ\n" #~ msgid "Could not properly shutdown application `%s'.\n" #~ msgstr "Không thể tắt đúng ứng dụng « %s ».\n" #~ msgid "Could not properly unload service `%s'!\n" #~ msgstr "Không thể há»§y nạp đúng dịch vụ « %s ».\n" #~ msgid "Core initialization failed.\n" #~ msgstr "Lá»—i sÆ¡ khởi lõi.\n" #~ msgid "Updates GNUnet datastructures after version change." #~ msgstr "Cập nhật cấu trúc dữ liệu GNUnet sau khi thay đổi phiên bản." #~ msgid "run as user LOGIN" #~ msgstr "chạy dưới ngưá»i dùng ÄÄ‚NG_NHẬP" #~ msgid "run in client mode (for getting client configuration values)" #~ msgstr "chạy trong chế độ khách (để lấy các giá trị cấu hình cá»§a máy khách)" #~ msgid "" #~ "Failed to determine filename used to store GNUnet version information!\n" #~ msgstr "" #~ "Lá»—i quyết định tên tập tin được dùng để chứa thông tin vá» phiên bản " #~ "GNUnet.\n" #~ msgid "" #~ "run in debug mode; gnunetd will not daemonize and error messages will be " #~ "written to stderr instead of a logfile" #~ msgstr "" #~ "chạy trong chế độ tìm sá»­a lá»—i; gnunetd sẽ không trở thành trình ná»n và sẽ " #~ "ghi thông báo lá»—i ra đầu lá»—i tiêu chuẩn thay vì vào má»™t tập tin ghi sá»± " #~ "kiện." #~ msgid "Starts the gnunetd daemon." #~ msgstr "Khởi chạy trình ná»n gnunetd." #~ msgid "disable padding with random data (experimental)" #~ msgstr "tắt đệm lót vá»›i dữ liệu ngẫu nhiên (vẫn thá»±c nghiệm !)" #~ msgid "print all log messages to the console (only works together with -d)" #~ msgstr "" #~ "in má»i thông Ä‘iệp ghi sá»± kiện ra bàn giao tiếp (chỉ hoạt động tổ hợp vá»›i " #~ "« -d »)" #~ msgid "specify username as which gnunetd should run" #~ msgstr "chỉ ra tên ngưá»i dùng dưới đó cần chạy gnunetd" #~ msgid "Configuration or GNUnet version changed. You need to run `%s'!\n" #~ msgstr "" #~ "Cấu hình hoặc phiên bản GNUnet bị thay đổi. Ngưá»i dùng cần chạy « %s ».\n" #~ msgid "The `%s' request received from client is malformed.\n" #~ msgstr "Nhận được yêu cầu « %s » dạng sai từ máy khách.\n" #~ msgid "Registering failed, message type %d already in use.\n" #~ msgstr "Lá»—i đăng ký, thông Ä‘iệp kiểu %d Ä‘ang được dùng.\n" #~ msgid "Unable to obtain filesystem information for `%s': %u\n" #~ msgstr "Không thể đại được thông tin vá» hệ thống tập tin cho « %s »: %u\n" #~ msgid "" #~ "Filesystem `%s' of partition `%s' is unknown. Please contact gnunet-" #~ "developers@gnu.org!" #~ msgstr "" #~ "Hệ thống tập tin « %s » cá»§a phân vùng « %s » không rõ. Hãy liên lạc vá»›i " #~ "các nhà phát triển gnunet ở địa chỉ « gnunet-developers@gnu.org »." #~ msgid "" #~ "Limiting datastore size to %llu GB, because the `%s' filesystem does not " #~ "support larger files. Please consider storing the database on a NTFS " #~ "partition!\n" #~ msgstr "" #~ "Äang hạn chế kích cỡ kho dữ liệu thành %llu GB, vì hệ thống tập tin « %s " #~ "» không há»— trợ tập tin lá»›n hÆ¡n đó. Khuyên bạn cất giữ cÆ¡ sở dữ liệu trong " #~ "má»™t phiên bản kiểu NTFS.\n" #~ msgid "`%s' message invalid (signature invalid).\n" #~ msgstr "Thông báo « %s » không hợp lệ (chữ ký sai).\n" #~ msgid "`%s' selected %d out of %d messages (MTU: %d).\n" #~ msgstr "« %s » đã chá»n %d trên %d thông báo (MTU: %d).\n" #~ msgid "Message details: %u: length %d, priority: %d\n" #~ msgstr "Chi tiết vá» thông báo: %u: dài %d, ưu tiên: %d\n" #~ msgid "Message from `%s' discarded: invalid format.\n" #~ msgstr "Thông báo từ « %s » bị há»§y: định dạng sai.\n" #~ msgid "Invalid sequence number %u <= %u, dropping message.\n" #~ msgstr "" #~ "Sai số thứ tá»± dãy trong thông báo %u ≤ %u, Ä‘ang loại bá» thông báo.\n" #~ msgid "# connections closed (HANGUP sent)" #~ msgstr "# các kết nối bị đóng (gá»­i tín hiệu ngừng nói HANGUP)" #~ msgid "# bytes noise sent" #~ msgstr "# các byte nhiá»…u được gá»­i" #~ msgid "# total bytes per second send limit" #~ msgstr "# giá»›i hạn tổng số byte má»—i giây" #~ msgid "# total bytes per second receive limit" #~ msgstr "# giá»›i hạn nhận tổng số byte má»—i giây" #~ msgid "# total number of messages in send buffers" #~ msgstr "# tổng số thông báo trong bá»™ đệm gá»­i" #~ msgid "# total number of bytes we were allowed to send but did not" #~ msgstr "# tổng số byte được phép gá»­i mà chưa" #~ msgid "# total number of bytes we were allowed to sent" #~ msgstr "# tổng số byte được phép gá»­i" #~ msgid "# total number of bytes we are currently allowed to send" #~ msgstr "# tổng số byte hiện thá»i được phép gá»­i" #~ msgid "# transports switched to stream transport" #~ msgstr "# các truyá»n tải được chuyển sang truyá»n tải luồng" #~ msgid "# conn. shutdown: other peer sent too much" #~ msgstr "# kết nối bị ngắt: đồng đẳng khác đã gá»­i quá nhiá»u" #~ msgid "# conn. shutdown: we lacked bandwidth" #~ msgstr "# kết nối bị ngắt: không đủ băng thông." #~ msgid "# conn. shutdown: other peer timed out" #~ msgstr "# kết nối bị ngắt: đồng đẳng khác quá hạn" #~ msgid "# conn. shutdown: timed out during connect" #~ msgstr "# kết nối bị ngắt: quá hạn trong khi thiết lập kết nối" #~ msgid "# conn. shutdown: other peer requested it" #~ msgstr "# kết nối bị ngắt: theo yêu cầu cá»§a đồng đẳng khác" #~ msgid "`%s': Could not create hello.\n" #~ msgstr "« %s »: Không tạo được tín hiệu xin chào (hello).\n" #~ msgid "`%s': Could not send.\n" #~ msgstr "« %s »: Không thể gá»­i.\n" #~ msgid "`%s': Could not disconnect.\n" #~ msgstr "« %s »: Không thể ngắt kết nối.\n" #~ msgid "" #~ "`%s' transport OK. It took %ums to transmit %llu messages of %llu bytes " #~ "each.\n" #~ msgstr "" #~ "« %s » truyá»n tải OK. Cần %u miligiây để truyá»n Ä‘i %llu thông báo vá»›i " #~ "%llu byte má»—i cái.\n" #~ msgid " Transport %d is not being tested\n" #~ msgstr " Truyá»n tải %d không Ä‘ang thá»­\n" #~ msgid "" #~ "\n" #~ "Contacting `%s'." #~ msgstr "" #~ "\n" #~ "Äang liên lạc vá»›i « %s »." #~ msgid " Connection failed (bug?)\n" #~ msgstr " Không kết nối được (lá»—i ?)\n" #~ msgid "Timeout after %llums.\n" #~ msgstr "Quá hạn sau %llu miligiây.\n" #~ msgid "OK!\n" #~ msgstr "OK!\n" #~ msgid "Tool to test if GNUnet transport services are operational." #~ msgstr "" #~ "Công cụ để thá»­ nghiệm xem dịch vụ truyá»n tải GNUnet có hoạt động không." #~ msgid "ping peers from HOSTLISTURL that match transports" #~ msgstr "" #~ "gá»­i tín hiệu ping cho các đồng đẳng từ HOSTLISTURL (danh sách máy theo " #~ "URL) tương ứng vá»›i truyá»n tải" #~ msgid "send messages with SIZE bytes payload" #~ msgstr "gá»­i thông báo có KÃCH_Cá»  byte tải trá»ng" #~ msgid "specifies which TRANSPORT should be tested" #~ msgstr "chỉ ra TRUYỀN_TẢI nào cần được thá»­ nghiệm" #~ msgid "specifies after how many MS to time-out" #~ msgstr "chỉ ra hết thá»i gian chá» sau bao nhiêu miligiay" #~ msgid "repeat each test X times" #~ msgstr "lặp lại má»—i hàm thá»­ X lần" #~ msgid "Testing transport(s) %s\n" #~ msgstr "Äang thá»­ nghiệm (các) truyá»n tải %s\n" #~ msgid "Available transport(s): %s\n" #~ msgstr "Các truyá»n tải sẵn sàng: %s\n" #~ msgid "" #~ "\n" #~ "%d out of %d peers contacted successfully (%d times transport " #~ "unavailable).\n" #~ msgstr "" #~ "\n" #~ "Äã liên lạc thành công vá»›i %d trên %d đồng đẳng (truyá»n tải không sẵn " #~ "sàng %d lần).\n" #~ msgid "Port is 0, will only send using %s.\n" #~ msgstr "Cổng là 0, chỉ sẽ gá»­i dùng %s.\n" #~ msgid "%s failed for url `%s' and post-data `%s' at %s:%d: `%s'\n" #~ msgstr "" #~ "%s bị lá»—i đối vá»›i địa chỉ URL « %s » và dữ liệu cuối « %s » tại %s:%d: « " #~ "%s »\n" #~ msgid "upnp: NAT Returned IP: %s\n" #~ msgstr "upnp: địa chỉ IP được NAT trả vá»: %s\n" #~ msgid "" #~ "The UPnP service could not be loaded. To disable UPnP, set the " #~ "configuration option \"UPNP\" in section \"%s\" to \"NO\"\n" #~ msgstr "" #~ "Dịch vụ UPnP không thể nạp được. Äể tắt UPnP, đặt tùy chá»n cấu hình « " #~ "UPNP » trong phần « %s » thành « NO » (không).\n" #~ msgid "# bytes sent via HTTP" #~ msgstr "# các byte đã gá»­i qua HTTP" #~ msgid "# bytes dropped by HTTP (outgoing)" #~ msgstr "# các byte loại bá» bởi HTTP (Ä‘i ra)" #~ msgid "# HTTP GET issued" #~ msgstr "# Tín hiệu HTTP GET được gá»­i" #~ msgid "# HTTP PUT issued" #~ msgstr "# Tín hiệu HTTP PUT được gá»­i" #~ msgid "# HTTP send calls" #~ msgstr "# các cuá»™c gá»i HTTP send (gá»­i)" #~ msgid "# HTTP curl send callbacks" #~ msgstr "# các cuá»™c gá»i ngược HTTP curl send (hàm curl gá»­i)" #~ msgid "# HTTP curl receive callbacks" #~ msgstr "# các cuá»™c gá»i ngược HTTP curl receive (hàm curl nhận)" #~ msgid "# HTTP mhd access callbacks" #~ msgstr "# các cuá»™c gá»i ngược HTTP mhd access (hàm mhd truy cập)" #~ msgid "# HTTP mhd read callbacks" #~ msgstr "# các cuá»™c gá»i ngược HTTP mhd read (hàm mhd Ä‘á»c)" #~ msgid "# HTTP mhd close callbacks" #~ msgstr "# các cuá»™c gá»i ngược HTTP mhd close (hàm mhd đóng)" #~ msgid "# HTTP connect calls" #~ msgstr "# các cuá»™c gá»i HTTP connect (kết nối)" #~ msgid "Failed to obtain my (external) %s address!\n" #~ msgstr "Lá»—i lấy địa chỉ %s (bên ngoài) cá»§a mình.\n" #~ msgid "MTU %llu for `%s' is probably too low!\n" #~ msgstr "MTU %llu cho « %s » rất có thể quá thấp.\n" #~ msgid "# UDP connections (right now)" #~ msgstr "# các kết nối UDP (lúc này)" #~ msgid "specify host on which gnunetd is running" #~ msgstr "ghi rõ máy trên đó chạy trình ná»n gnunetd" #~ msgid "" #~ "External protocol violation: assertion failed at %s:%d (no need to panic, " #~ "we can handle this).\n" #~ msgstr "" #~ "Xâm phạm giao thức bên ngoài: khẳng định không thành công tại %s:%d (đừng " #~ "lo, vẫn còn có thể sá»­a chữa).\n" #~ msgid "No help available." #~ msgstr "Không có trợ giúp sẵn sàng." #~ msgid "" #~ "You can use 'make check' in src/transports/upnp/ to find out if your NAT " #~ "supports UPnP. You should disable this option if you are sure that you " #~ "are not behind a NAT. If your NAT box does not support UPnP, having this " #~ "on will not do much harm (only cost a small amount of resources)." #~ msgstr "" #~ "Bạn có thể dùng câu lệnh « make check » trong « src/transports/upnp » để " #~ "tìm biết nếu NAT đó há»— trợ UPnP không. Chưa chắc nếu máy này nằm sau má»™t " #~ "NAT thì bạn nên tắt tùy chá»n này. Nếu máy NAT đó không há»— trợ UPnP, việc " #~ "bật tùy chá»n này sẽ không rất vấn đỠgì (chỉ chiếm má»™t ít tài nguyên)." #~ msgid "Prompt for development and/or incomplete code" #~ msgstr "Nhắc vá»›i mã vẫn phát triển và/hay mã chưa hoàn toàn" #~ msgid "" #~ "If EXPERIMENTAL is set to NO, options for experimental code are not " #~ "shown. If in doubt, use NO.\n" #~ "\n" #~ "Some options apply to experimental code that maybe in a state of " #~ "development where the functionality, stability, or the level of testing " #~ "is not yet high enough for general use. These features are said to be of " #~ "\"alpha\" quality. If a feature is currently in alpha, uninformed use is " #~ "discouraged (since the developers then do not fancy \"Why doesn't this " #~ "work?\" type messages).\n" #~ "\n" #~ "However, active testing and qualified feedback of these features is " #~ "always welcome. Users should just be aware that alpha features may not " #~ "meet the normal level of reliability or it may fail to work in some " #~ "special cases. Bug reports are usually welcomed by the developers, but " #~ "please read the documents and and use for how to report problems." #~ msgstr "" #~ "Nếu EXPERIMENTAL (thá»±c nghiệm) được đặt thành NO (không) thì không hiển " #~ "thị tùy chá»n vá» mã vẫn thá»±c nghiệm. Chưa chắc thì đặt NO.\n" #~ "\n" #~ "Má»™t số tùy chá»n nào đó có áp dụng cho mã thá»±c nghiệm, mà có thể vẫn còn " #~ "được phát triển thì chưa đầy đủ chức năng, ổn định hay đủ thá»­ để sá»­ dụng " #~ "má»™t cách chung. Các tính năng này được nhãn là « alpha » (a). Nếu má»™t " #~ "tính năng vẫn là alpha, khuyên ngưá»i dùng bình thưá»ng không dùng nó.\n" #~ "\n" #~ "Tùy nhiên, nếu bạn quen vá»›i tiến trình thá»­ và phản hồi, má»i bạn tham gia " #~ "(miá»…n là bạn hiểu được rằng phần má»m này có thể chưa sẵn sàng sá»­ dụng vá»›i " #~ "dữ liệu quan trá»ng). Nhà phát triển má»i bạn gá»­i báo cáo lá»—i: xin hãy Ä‘á»c " #~ "tài liệu và , sau đó dùng địa " #~ "chỉ để thông báo vấn Ä‘á»." #~ msgid "Show options for advanced users" #~ msgstr "Hiện tùy chá»n cấp cao" #~ msgid "" #~ "These are options that maybe difficult to understand for the beginner. " #~ "These options typically refer to features that allow tweaking of the " #~ "installation. If in a hurry, say NO." #~ msgstr "" #~ "Tùy chá»n cấp này có thể khó hiểu cho ngưá»i dùng bắt đầu sá»­ dụng máy tính. " #~ "Tùy chá»n kiểu này thưá»ng tham chiếu đến tính năng cho phép Ä‘iá»u chỉnh bản " #~ "cài đặt. Vá»™i thì đặt NO (không)." #~ msgid "Show rarely used options" #~ msgstr "Hiện tùy chá»n ít dùng" #~ msgid "" #~ "These are options that hardly anyone actually needs. If you plan on " #~ "doing development on GNUnet, you may want to look into these. If in " #~ "doubt or in a hurry, say NO." #~ msgstr "" #~ "Tùy chá»n này cần bởi rất ít ngưá»i. Nếu bạn định phát triển qua GNUnet, có " #~ "lẽ tùy chá»n này có ích. Nếu không hay vá»™i, hãy đặt NO (không)." #~ msgid "Meta-configuration" #~ msgstr "Siêu cấu hình" #~ msgid "Which level of configuration should be available" #~ msgstr "Cấp cấu hình nên sẵn sàng" #~ msgid "Full pathname of GNUnet HOME directory" #~ msgstr "Tên đưá»ng dẫn đầy đủ đến thư mục HOME GNUnet" #~ msgid "" #~ "This gives the root-directory of the GNUnet installation. Make sure there " #~ "is some space left in that directory. :-) Users inserting or indexing " #~ "files will be able to store data in this directory up to the (global) " #~ "quota specified below. Having a few gigabytes of free space is " #~ "recommended." #~ msgstr "" #~ "Äây đưa ra thư mục gốc cá»§a bản cài đặt GNUnet. Hãy kiểm tra xem vẫn còn " #~ "có sức chứa còn lại trong thư mục đó. :-)\n" #~ "Ngưá»i dùng cần chèn hay phụ lục tập tin thì có thể lưu dữ liệu vào thư " #~ "mục này đến hạn ngạch (toàn cục) được ghi rõ dưới đây. Khuyên có vài GB " #~ "sức chứa còn rảnh." #~ msgid "Full pathname of GNUnet directory for file-sharing data" #~ msgstr "" #~ "Tên đưá»ng dẫn đầy đủ đến thư mục GNUnet sẽ chứa dữ liệu chia sẻ tập tin" #~ msgid "Full pathname to the directory with the key-value database" #~ msgstr "Tên đưá»ng dẫn đầy đủ đến thư mục có cÆ¡ sở dữ liệu khoá-giá_trị " #~ msgid "Note that the kvstore is currently not used." #~ msgstr "Ghi chú rằng hiện thá»i không dùng kvstore. " #~ msgid "Full pathname of GNUnet directory for indexed files symbolic links" #~ msgstr "" #~ "Tên đưá»ng dẫn đầy đủ đến thư mục GNUnet sẽ chứa các liên kết tương trưng " #~ "đến tập tin phụ lục" #~ msgid "How many minutes should peer advertisements last?" #~ msgstr "Có nên quảng cáo đồng đẳnh trong mấy phút?" #~ msgid "" #~ "How many minutes is the current IP valid? (GNUnet will sign HELLO " #~ "messages with this expiration timeline. If you are on dialup, 60 (for 1 " #~ "hour) is suggested. If you have a static IP address, you may want to set " #~ "this to a large value (say 14400). The default is 1440 (1 day). If your " #~ "IP changes periodically, you will want to choose an expiry period smaller " #~ "than the frequency with which your IP changes." #~ msgstr "" #~ "Äịa chỉ IP hiện thá»i vẫn hợp lệ trong bao nhiêu phút? (GNUnet sẽ ký má»—i " #~ "thông Ä‘iệp HELLO dùng thá»i hạn này. Nếu bạn quay số để kết nối, khuyên " #~ "dùng 60 (1 giá»). Nếu máy này có má»™t địa chỉ IP tÄ©nh, má»™t giá trị lá»›n hÆ¡n " #~ "(v.d. 14400) có ích. Mặc định là 1440 (1 ngày). Nếu máy này có má»™t địa " #~ "chỉ IP thay đổi theo định kỳ, khuyên bạn chá»n má»™t thá»i hạn ngắn hÆ¡n " #~ "khoảng thá»i gian giữa hai lần thay đổi địa chỉ IP." #~ msgid "Where can GNUnet find an initial list of peers?" #~ msgstr "GNUnet có thể tìm má»™t danh sách các đồng đẳng đầu tiên ở đâu?" #~ msgid "" #~ "GNUnet can automatically update the hostlist from the web. While GNUnet " #~ "internally communicates which hosts are online, it is typically a good " #~ "idea to get a fresh hostlist whenever gnunetd starts from the WEB. By " #~ "setting this option, you can specify from which server gnunetd should try " #~ "to download the hostlist. The default should be fine for now.\n" #~ "\t\t\n" #~ "The general format is a list of space-separated URLs. Each URL must have " #~ "the format http://HOSTNAME/FILENAME\n" #~ "\t\t\n" #~ "If you want to setup an alternate hostlist server, you must run a " #~ "permanent node and \"cat data/hosts/* > hostlist\" every few minutes to " #~ "keep the list up-to-date.\n" #~ "\t\t\n" #~ "If you do not specify a HOSTLISTURL, you must copy valid hostkeys to data/" #~ "hosts manually." #~ msgstr "" #~ "GNUnet có khả năng tá»± động cập nhật danh sách các máy chá»§ từ Web. Dù " #~ "GNUnet liên lạc ná»™i bá»™ những máy này hiện thá»i trá»±c tuyến, thưá»ng có ích " #~ "để lấy má»™t danh sách máy má»›i từ Web khi nào trình ná»n gnunetd khởi chạy. " #~ "Bằng cách đặt tùy chá»n này, bạn có thể ghi rõ gnunetd nên thá»­ tải danh " #~ "sách máy xuống máy phục vụ nào. Bây giá» giá trị mặc định vẫn ổn.\n" #~ "\n" #~ "Äịnh dạng chung là má»™t danh sách các địa chỉ URL định giá»›i bằng dấu cách. " #~ "Má»—i địa chỉ URL nên có dạng « http://tên_máy/tên_tập_tin ».\n" #~ "\n" #~ "Muốn thiết lập má»™t máy phục vụ danh sách máy xen kẽ thì bạn cần phải chạy " #~ "má»™t nút thông tin (node) bá»n bỉ, và chạy câu lệnh « cat data/hosts/* > " #~ "hostlist » sau má»—i vài phút để cập nhật danh sách.\n" #~ "\n" #~ "Nếu bạn không ghi rõ má»™t HOSTLISTURL (địa chỉ URL cá»§a danh sách máy), bạn " #~ "cÅ©ng cần phải tá»± sao chép má»—i khoá máy hợp lệ vào « data/hosts »." #~ msgid "HTTP Proxy Server" #~ msgstr "Máy phục vụ á»§y nhiệm HTTP" #~ msgid "" #~ "If you have to use a proxy for outbound HTTP connections, specify the " #~ "proxy configuration here. Default is no proxy." #~ msgstr "" #~ "Nếu bạn cần dùng má»™t máy phục vụ á»§y nhiệm cho kết nối HTTP Ä‘i ra, hãy ghi " #~ "rõ cấu hình á»§y nhiệm ở đây. Mặc định là không dùng á»§y nhiệm." #~ msgid "" #~ "Name of the directory where gnunetd should store contact information " #~ "about peers" #~ msgstr "" #~ "Tên cá»§a thư mục vào đó gnunetd nên lưu thông tin liên lạc vỠđồng đẳng" #~ msgid "" #~ "Unless you want to share the directory directly using a webserver, the " #~ "default is most likely just fine." #~ msgstr "" #~ "Nếu bạn không muốn chia sẻ thư mục má»™t cách trá»±c tiếp dùng má»™t máy phục " #~ "vụ Web, giá trị mặc định rất có thể ổn." #~ msgid "How long should logs be kept?" #~ msgstr "Bao lâu nên giữ bản theo dõi?" #~ msgid "" #~ "How long should logs be kept? If you specify a value greater than zero, a " #~ "log is created each day with the date appended to its filename. These " #~ "logs are deleted after $KEEPLOG days.\tTo keep logs forever, set this " #~ "value to 0." #~ msgstr "" #~ "Bao lâu nên giữ sổ theo dõi (log)? Nếu bạn ghi rõ má»™t giá trị hÆ¡n số " #~ "không, má»™t sổ theo dõi được tạo hàng ngày vá»›i ngày tháng được phụ thêm " #~ "vào tên tập tin. Sổ theo dõi này bị xoá sau $KEEPLOG ngày.\tÄể không bao " #~ "giá» xoá sổ theo dõi, hãy đặt giá trị này thành 0." #~ msgid "" #~ "What maximum number of open file descriptors should be requested from the " #~ "OS?" #~ msgstr "" #~ "Có nên yêu cầu từ hệ Ä‘iá»u hành bao nhiêu bá»™ mô tả tập tin còn mở (tối Ä‘a)?" #~ msgid "" #~ "The default of 1024 should be fine for most systems. If your system can " #~ "support more, increasing the number might help support additional clients " #~ "on machines with plenty of bandwidth. For embedded systems, a smaller " #~ "number might be acceptable. A value of 0 will leave the descriptor limit " #~ "untouched. This option is mostly for OS X systems where the default is " #~ "too low. Note that if gnunetd cannot obtain the desired number of file " #~ "descriptors from the operating system, it will print a warning and try to " #~ "run with what it is given." #~ msgstr "" #~ "Giá trị mặc định 1024 nên ổn cho phần lá»›n hệ thống. Nếu hệ thống này có " #~ "khả năng há»— trợ nhiá»u bá»™ mô tả tập tin hÆ¡n, má»™t số lá»›n hÆ¡n có thể giúp há»— " #~ "trợ các ứng dụng khách bổ sung trên máy có rất nhiá»u bảng thông. Äối vá»›i " #~ "hệ thống nhúng, má»™t số nhá» hÆ¡n có thể ổn. Giá trị 0 sẽ không thay đổi " #~ "giá»›i hạn. Tùy chá»n này thưá»ng có ích trên hệ thống OSX (có giá trị mặc " #~ "định quá thấp). Ghi chú rằng nếu gnunetd không thể lấy số các bá»™ mô tả " #~ "tập tin yêu cầu từ hệ Ä‘iá»u hành, thì nó sẽ in ra má»™t cảnh báo và thá»­ chạy " #~ "vá»›i số đưa ra." #~ msgid "Where should gnunetd write the logs?" #~ msgstr "gnunetd nên ghi sổ theo dõi vào đâu?" #~ msgid "Enable for extra-verbose logging." #~ msgstr "Bật để theo dõi rất chi tiết hÆ¡n." #~ msgid "Logging" #~ msgstr "Theo dõi" #~ msgid "Specify which system messages should be logged how" #~ msgstr "Ghi rõ những thông Ä‘iệp hệ thống nào nên được theo dõi như thế nào" #~ msgid "Logging of events for users" #~ msgstr "Theo dõi sá»± kiện cho ngưá»i dùng" #~ msgid "Logging of events for the system administrator" #~ msgstr "Theo dõi sá»± kiện cho quản trị hệ thống" #~ msgid "Where should gnunetd write the PID?" #~ msgstr "gnunetd nên ghi PID vào đâu?" #~ msgid "" #~ "The default is no longer /var/run/gnunetd.pid since we could not delete " #~ "the file on shutdown at that location." #~ msgstr "" #~ "Giá trị mặc định không còn là « /var/run/gnunetd.pid » lại, vì không thể " #~ "xoá tập tin ở vị trí đó khi tắt máy." #~ msgid "As which user should gnunetd run?" #~ msgstr "gnunetd nên chạy dưới ngưá»i dùng nào?" #~ msgid "" #~ "Empty means \"current user\". On computer startup, it is root/SYSTEM. " #~ "Under Windows, this setting affects the creation of a new system service " #~ "only." #~ msgstr "" #~ "Trống có nghÄ©a là « ngưá»i dùng hiện thá»i ». Khi máy khởi động, nó là « " #~ "root/SYSTEM ». Dưới Windows, thiết lập này chỉ ảnh hưởng đến việc tạo má»™t " #~ "dịch vụ hệ thống." #~ msgid "Should gnunetd be automatically started when the system boots?" #~ msgstr "Khi hệ thống khởi động, có nên tá»± động khởi chạy gnunetd không?" #~ msgid "" #~ "Set to YES if gnunetd should be automatically started on boot. If this " #~ "option is set, gnunet-setup will install a script to start the daemon " #~ "upon completion. This option may not work on all systems." #~ msgstr "" #~ "Äặt thành YES (có) nếu trình ná»n gnunetd nên tá»± động được khởi chạy khi " #~ "hệ thống khởi động. Nếu đặt tùy chá»n này thì tiến trình thiết lập gnunet-" #~ "setup sẽ cài đặt má»™t văn lệnh để khởi chạy trình ná»n này má»™t khi hoàn " #~ "tất. Tùy chá»n này có thể không hoạt động đúng trên má»i hệ thống." #~ msgid "Which transport mechanisms should GNUnet use?" #~ msgstr "GNUnet nên dùng những cÆ¡ chế truyá»n nào?" #~ msgid "" #~ "Use a space-separated list of modules, e.g. \"udp smtp tcp\". The " #~ "available transports are udp, tcp, http, smtp and nat.\n" #~ "\t\t\n" #~ "Loading the 'nat' and 'tcp' modules is required for peers behind NAT " #~ "boxes that cannot directly be reached from the outside. Peers that are " #~ "NOT behind a NAT box and that want to *allow* peers that ARE behind a NAT " #~ "box to connect must ALSO load the 'nat' module. Note that the actual " #~ "transfer will always be via tcp initiated by the peer behind the NAT " #~ "box. The nat transport requires the use of tcp, http and/or smtp in " #~ "addition to nat itself." #~ msgstr "" #~ "Dùng má»™t danh sách các mô-Ä‘un định giá»›i bằng dấu cách, v.d. « udp smtp " #~ "tcp ». Những cÆ¡ chế truyá»n sẵn sàng: udp, tcp, http, smtp, nat.\n" #~ "\n" #~ "Nạp hai mô-Ä‘un « nat » và « tcp » cần thiết cho đồng đẳng nằm sau máy NAT " #~ "mà không tá»›i được từ bên ngoài. Äồng đẳng KHÔNG phải nằm sau máy NAT và " #~ "muốn _cho phép_ kết nối từ đồng đẳng mà CÓ phải nằm sau NAT thì CŨNG cần " #~ "phải nạp mô-Ä‘un « nat ». Ghi chú rằng việc truyá»n thật lúc nào cÅ©ng chạy " #~ "qua tcp, được sÆ¡ khởi bởi đồng đẳng nằm sau máy NAT. CÆ¡ chế truyá»n nat " #~ "cÅ©ng cần thiết tcp, http và/hay smtp thêm vào nat chính nó." #~ msgid "Which applications should gnunetd support?" #~ msgstr "gnunetd nên há»— trợ những ứng dụng nào?" #~ msgid "" #~ "Whenever this option is changed, you MUST run gnunet-update. Currently, " #~ "the available applications are:\n" #~ "\n" #~ "advertising: advertises your peer to other peers. Without it, your peer " #~ "will not participate in informing peers about other peers. You should " #~ "always load this module.\n" #~ "\n" #~ "getoption: allows clients to query gnunetd about the values of various " #~ "configuration options. Many tools need this. You should always load " #~ "this module.\n" #~ "\n" #~ "stats: allows tools like gnunet-stats and gnunet-gtk to query gnunetd " #~ "about various statistics. This information is usually quite useful to " #~ "diagnose errors, hence it is recommended that you load this module.\n" #~ "\n" #~ "traffic: keeps track of how many messages were recently received and " #~ "transmitted. This information can then be used to establish how much " #~ "cover traffic is currently available. The amount of cover traffic " #~ "becomes important if you want to make anonymous requests with an " #~ "anonymity level that is greater than one. It is recommended that you " #~ "load this module.\n" #~ "\n" #~ "fs: needed for anonymous file sharing. You should always load this " #~ "module.\n" #~ "\n" #~ "hostlist: integrated hostlist HTTP server. Useful if you want to offer a " #~ "hostlist and running Apache would be overkill.\n" #~ "\n" #~ "chat: broadcast chat (demo-application, ALPHA quality).\tRequired for " #~ "gnunet-chat. Note that the current implementation of chat is not " #~ "considered to be secure.\n" #~ "\n" #~ "tbench: benchmark transport performance. Required for gnunet-tbench. " #~ "Note that tbench allows other users to abuse your resources.\n" #~ "\n" #~ "tracekit: topology visualization toolkit. Required for gnunet-tracekit. " #~ "Note that loading tracekit will make it slightly easier for an adversary " #~ "to compromise your anonymity." #~ msgstr "" #~ "Khi nào tùy chá»n này bị thay đổi, bạn CẦN PHẢI chạy tiến trình cập nhật " #~ "gnunet-update. Hiện thá»i có những ứng dụng sẵn sàng này:\n" #~ "\n" #~ " • advertising\tquảng cáo đồng đẳng này cho các đồng đẳng khác. Không có " #~ "ứng dụng này thì đồng đẳng này sẽ không tham gia hoạt động cho đồng đẳng " #~ "biết vỠđồng đẳng khác. Lúc nào cÅ©ng nên nạp mô-Ä‘un này.\n" #~ "\n" #~ " • getoption\tcho phép ứng dụng khách há»i gnunetd vá» giá trị cá»§a má»™t số " #~ "tùy chá»n cấu hình nào đó. Rất nhiá»u công cụ cần chức năng này. Lúc nào " #~ "cÅ©ng nên nạp mô-Ä‘un này.\n" #~ "\n" #~ " • stats\tcho phép công cụ như gnunet-stats và gnunet-gtk há»i gnunetd vá» " #~ "má»™t số thống kê nào đó. Thông tin này thưá»ng hÆ¡i hữu ích để chẩn Ä‘oán " #~ "lá»—i, do đó khuyên bạn nạp mô-Ä‘un này.\n" #~ "\n" #~ " • traffic\ttheo dõi bao nhiêu tin nhẳn vừa nhận và gá»­i. Thông tin này " #~ "thì có thể được dùng để tính bao nhiêu giao thông trải ra hiện thá»i sẵn " #~ "sàng. Lượng giao thông trải ra trở thành quan trá»ng nếu bạn muốn gá»­i yêu " #~ "cầu nặc danh vá»›i má»™t cấp nặc danh hÆ¡n má»™t. Khuyên bạn nạp mô-Ä‘un này.\n" #~ "\n" #~ " • fs\tcần để chia sẻ tập tin má»™t cách nặc danh. Lúc nào cÅ©ng nên nạp mô-" #~ "Ä‘un này.\n" #~ "\n" #~ " • hostlist\ttrình phục vụ HTTP danh sách máy thống nhất. Có ích nếu bạn " #~ "muốn cung cấp má»™t danh sách máy, nhưng không muốn chạy Apache cho má»™t " #~ "công việc rất nhá» như vậy.\n" #~ "\n" #~ " • chat\ttrò chuyện quảng bá (ứng dụng minh hoạ, vẫn ALPHA). Cần thiết " #~ "cho ứng dụng trò chuyện gnunet-chat. Ghi chú rằng bản thá»±c hiện chat hiện " #~ "thá»i chưa được xem là bảo mật.\n" #~ "\n" #~ " • tbench\tkiểm chuẩn hiệu suất truyá»n. Cần thiết cho gnunet-tbench. Ghi " #~ "chú rằng tbench cho phép ngưá»i dùng khác lạm dụng các tài nguyên cá»§a " #~ "bạn.\n" #~ "\n" #~ " • tracekit\tbá»™ công cụ mưá»ng tượng địa hình. Cần thiết cho gnunet-" #~ "tracekit. Ghi chú rằng việc nạp tracekit sẽ làm cho má»™t ít dá»… hÆ¡n khi " #~ "ngưá»i dùng muốn xâm nhập tình trạng nặc danh cá»§a bạn." #~ msgid "Disable client-server connections" #~ msgstr "Tắt má»i kết nối kiểu khách-máy_phục_vụ" #~ msgid "" #~ "This option can be used to tell gnunetd not to open the client port. " #~ "When run like this, gnunetd will participate as a peer in the network but " #~ "not support any user interfaces. This may be useful for headless systems " #~ "that are never expected to have end-user interactions. Note that this " #~ "will also prevent you from running diagnostic tools like gnunet-stats!" #~ msgstr "" #~ "Tùy chá»n này có thể được dùng để báo trình ná»n gnunetd không mở cổng cho " #~ "ứng dụng khách. Khi chạy bằng cách này, gnunetd sẽ tham gia là má»™t đồng " #~ "đẳng trên mạng, còn không há»— trợ giao diện ngưá»i dùng nào. Có thể hữu ích " #~ "cho hệ thống không cần màn hình mà không bao giá» nên tương tác vá»›i ngưá»i " #~ "dùng cuối cùng. Ghi chú rằng tùy chá»n này cÅ©ng ngăn cản bạn chạy công cụ " #~ "chẩn Ä‘oán như tiến trình thống kê gnunet-stats !" #~ msgid "YES disables IPv6 support, NO enables IPv6 support" #~ msgstr "YES hay NO thì tắt hay bật há»— trợ IPv6" #~ msgid "" #~ "This option may be useful on peers where the kernel does not support " #~ "IPv6. You might also want to set this option if you do not have an IPv6 " #~ "network connection." #~ msgstr "" #~ "Tùy chá»n này có thể hữu ích trên đồng đẳng không có hạt nhân há»— trợ IPv6. " #~ "CÅ©ng có thể đặt tùy chá»n này nếu không có kết nối mạng kiểu IPv6." #~ msgid "Disable peer discovery" #~ msgstr "Tắt khám phá đồng đẳng" #~ msgid "" #~ "The option 'PRIVATE-NETWORK' can be used to limit the connections of this " #~ "peer to peers of which the hostkey has been copied by hand to data/" #~ "hosts; if this option is given, GNUnet will not accept advertisements of " #~ "peers that the local node does not already know about. Note that in " #~ "order for this option to work, HOSTLISTURL should either not be set at " #~ "all or be set to a trusted peer that only advertises the private network. " #~ "Also, the option does NOT work at the moment if the NAT transport is " #~ "loaded; for that, a couple of lines above would need some minor " #~ "editing :-)." #~ msgstr "" #~ "Tùy chá»n « PRIVATE-NETWORK » có thể được dùng để hạn chế kết nối cá»§a đồng " #~ "đẳng này thành những đồng đẳng có khoá máy đã được sao chép bằng tay vào " #~ "« data/hosts »; nếu bật tùy chá»n này thì GNUnet sẽ không chấp nhận quảng " #~ "cáo vỠđồng đẳng không được nút cục bá»™ nhận ra. Ghi chú rằng tùy chá»n này " #~ "cÅ©ng cần HOSTLISTURL không đặt bằng cách nào cả hay có đặt thành má»™t đồng " #~ "đẳng tin cậy mà chỉ quảng cáo mạng riêng. HÆ¡n nữa, tùy chá»n này KHÔNG " #~ "hoạt động khi nào cÆ¡ chế trung NAT được nạp: để tránh trưá»ng hợp đó, cÅ©ng " #~ "cần phải chỉnh sá»­a vài dòng bên trên. :-)" #~ msgid "Disable automatic establishment of connections" #~ msgstr "Tắt tá»± động thiết lập kết nối" #~ msgid "" #~ "If this option is enabled, GNUnet will not automatically establish " #~ "connections to other peers, but instead wait for applications to " #~ "specifically request connections to other peers (or for other peers to " #~ "connect to us)." #~ msgstr "" #~ "Bật tùy chá»n này thì GNUnet sẽ không tá»± động thiết lập kết nối tá»›i đồng " #~ "đẳng khác, thay vào đó nó đợi ứng đụng yêu cầu dứt khoát kết nối tá»›i đồng " #~ "đẳng khác (hoặc đợi đồng đẳng khác kết nối đến máy này)." #~ msgid "Enable advertising of other peers by this peer" #~ msgstr "Bật máy này quảng cáo đồng đẳng khác" #~ msgid "" #~ "This option may be useful during testing, but turning it off is " #~ "dangerous! If in any doubt, set it to YES (which is the default)." #~ msgstr "" #~ "Tùy chá»n này có thể hữu ích trong khi thá»­: trong má»i trưá»ng hợp Ä‘á»u không " #~ "nên tắt nó ! Chưa chắc thì đặt nó thành YES (có) mà mặc định." #~ msgid "" #~ "Which is the client-server port that is used between gnunetd and the " #~ "clients (TCP only). You may firewall this port for non-local machines " #~ "(but you do not have to since GNUnet will perform access control and only " #~ "allow connections from machines that are listed under TRUSTED)." #~ msgstr "" #~ "Trình ná»n gnunetd và các ứng dụng khách liên lạc (chỉ TCP) qua cổng khách-" #~ "phục_vụ nào? Bạn cÅ©ng có thể đặt bức tưá»ng lá»­a giữa cổng này và các máy " #~ "khác cục bá»™, nhưng không cần phải vì GNUnet sẽ Ä‘iá»u khiển truy cập và chỉ " #~ "cho phép kết nối từ máy được liệt kê dưới TRUSTED (tin cậy). " #~ msgid "IPv4 networks allowed to use gnunetd server" #~ msgstr "Các mạng IPV4 được phép dùng trình phục vụ gnunetd" #~ msgid "" #~ "This option specifies which hosts are trusted enough to connect as " #~ "clients (to the TCP port). This is useful if you run gnunetd on one host " #~ "of your network and want to allow all other hosts to use this node as " #~ "their server. By default, this is set to 'loopback only'. The format is " #~ "IP/NETMASK where the IP is specified in dotted-decimal and the netmask " #~ "either in CIDR notation (/16) or in dotted decimal (255.255.0.0). Several " #~ "entries must be separated by a semicolon, spaces are not allowed." #~ msgstr "" #~ "Tùy chá»n này ghi rõ những máy nào đủ tin cậy để kết nối là ứng dụng khách " #~ "(đến cổng TCP). Có ích nếu bạn chạy trình nên gnunetd trên má»™t máy cá»§a " #~ "mạng cục bá»™, cÅ©ng muốn các máy khác cùng mạng dùng nút này làm máy phục " #~ "vụ. Mặc định là tùy chá»n này được đặt thành « loopback only » (chỉ mạch " #~ "ná»™i bá»™). Äịnh dạng là IP/MẶT_NẠ_MẠNG mà địa chỉ IP được ghi rõ theo thập " #~ "phân đánh chấm (v.d. 255.255.0.0), và mặt nạ mạng (netmask) theo hoặc " #~ "cách ghi CIDR (v.d. 1/16) hoặc thập phân đánh chấm. Vài mục nhập nên định " #~ "giá»›i bằng dấu hai chấm, cÅ©ng không cho phép khoảng cách." #~ msgid "IPv6 networks allowed to use gnunetd server" #~ msgstr "Các mạng IPv6 được phép dùng trình phục vụ gnunetd" #~ msgid "Limit connections to the specfied set of peers." #~ msgstr "Hạn chế kết nối thành tập hợp đồng đẳng được ghi rõ." #~ msgid "" #~ "If this option is not set, any peer is allowed to connect. If it is set, " #~ "only the specified peers are allowed. Specify the list of peer IDs (not " #~ "IPs!)" #~ msgstr "" #~ "Không bật tùy chá»n này thì má»i đồng đẳng được phép kết nối. Nếu bật nó " #~ "thì chỉ cho phép những đồng đẳng đưa ra. Hãy ghi rõ danh sách các mã số " #~ "đồng đẳng, không phải địa chỉ IP !" #~ msgid "Run gnunetd as this group." #~ msgstr "Chạy gnunetd dưới nhóm này." #~ msgid "" #~ "When started as root, gnunetd will change permissions to the given group." #~ msgstr "" #~ "Khi khởi chạy bởi ngưá»i chá»§, trình ná»n gnunetd sẽ chuyển đổi quyá»n truy " #~ "cập sang nhóm đưa ra." #~ msgid "Prevent the specfied set of peers from connecting." #~ msgstr "Chặn kết nối từ tập hợp đồng đẳng được ghi rõ." #~ msgid "" #~ "If this option is not set, any peer is allowed to connect. If the ID of " #~ "a peer is listed here, connections from that peer will be refused. " #~ "Specify the list of peer IDs (not IPs!)" #~ msgstr "" #~ "Không bật tùy chá»n này thì má»i đồng đẳng Ä‘á»u được phép kết nối. Nếu mã số " #~ "cá»§a má»™t đồng đẳng nào đó được liệt kê ở đây, thì kết nối từ máy đó bị từ " #~ "chối. Hãy ghi rõ danh sách các mã số đồng đẳng, không phải địa chỉ IP !" #~ msgid "Topology Maintenance" #~ msgstr "Duy trì địa hình" #~ msgid "Rarely used settings for peer advertisements and connections" #~ msgstr "Thiết lập ít dùng vá» quảng cáo và kết nối cá»§a đồng đẳng" #~ msgid "General settings" #~ msgstr "Thiết lập chung" #~ msgid "Settings that change the behavior of GNUnet in general" #~ msgstr "Thiết lập mà sá»­a đổi ứng xá»­ chung cá»§a GNUnet" #~ msgid "Modules" #~ msgstr "Mô-Ä‘un" #~ msgid "Settings that select specific implementations for GNUnet modules" #~ msgstr "Thiết lập mà chá»n bản thá»±c hiện riêng cho mô-Ä‘un GNUnet" #~ msgid "Fundamentals" #~ msgstr "CÆ¡ bản" #~ msgid "Which database should be used?" #~ msgstr "Có nên dùng cÆ¡ sở dữ liệu nào?" #, fuzzy #~ msgid "" #~ "Which database should be used? The options are \"sqstore_sqlite\", " #~ "\"sqstore_postgres\" and \"sqstore_mysql\". You must run gnunet-update " #~ "after changing this value!\n" #~ "\t\t\t\n" #~ "In order to use MySQL or Postgres, you must configure the respective " #~ "database, which is relatively simple. Read the file doc/README.mysql or " #~ "doc/README.postgres for how to setup the respective database." #~ msgstr "" #~ "Có nên dùng cÆ¡ sở dữ liệu nào? Hai tùy chá»n là « sqstore_sqlite » và « " #~ "sqstore_mysql ». Sau khi thay đổi giá trị này thì cÅ©ng cần phải chạy tiến " #~ "trình cập nhật gnunet-update !\n" #~ "\n" #~ "Äể sá»­ dụng sqstore_mysql, bạn cÅ©ng cần phải cấu hình cÆ¡ sở dữ liệu MySQL: " #~ "má»™t công việc hÆ¡i đơn giản. Hãy Ä‘á»c tài liệu Äá»c Äi « doc/README.mysql » " #~ "để tìm biết thiết lập MySQL như thế nào." #~ msgid "Which topology should be used?" #~ msgstr "Có nên địa hình nào?" #~ msgid "" #~ "Which database should be used for the temporary datastore of the DHT?" #~ msgstr "Có nên dùng cÆ¡ sở dữ liệu nào làm kho dữ liệu tạm thá»i cá»§a DHT?" #~ msgid "" #~ "Which topology should be used? The only option at the moment is " #~ "\"topology_default\"" #~ msgstr "" #~ "Có nên địa hình nào? Tùy chá»n duy nhất hiện thá»i là « topology_default »." #~ msgid "" #~ "The minimum number of connected friends before this peer is allowed to " #~ "connect to peers that are not listed as friends" #~ msgstr "" #~ "Số tối thiểu các bạn bè có kết nối trước khi đồng đẳng nay được phép kết " #~ "nối tá»›i đồng đẳng lạ (không phải được liệt kê là bạn bè)" #~ msgid "" #~ "Note that this option does not guarantee that the peer will be able to " #~ "connect to the specified number of friends. Also, if the peer had " #~ "connected to a sufficient number of friends and then established non-" #~ "friend connections, some of the friends may drop out of the network, " #~ "temporarily resulting in having fewer than the specified number of " #~ "friends connected while being connected to non-friends. However, it is " #~ "guaranteed that the peer itself will never choose to drop a friend's " #~ "connection if this would result in dropping below the specified number of " #~ "friends (unless that number is higher than the overall connection target)." #~ msgstr "" #~ "Ghi chú rằng tùy chá»n này không đảm bảo rằng đồng đẳng sẽ kết nối được " #~ "tá»›i số các bạn bè đưa ra. HÆ¡n nữa, nếu đồng đẳng có kết nối tá»›i đủ bạn " #~ "bè, sau đó thiết lập kết nối khác bạn bè, thì má»™t số bạn bè có thể dứt " #~ "khá»i mạng, tạm thá»i có kết quả là quá ít bạn bè có kết nối trong khi kết " #~ "nối tá»›i khác bạn bè. Tuy nhiên đảm bảo rằng đồng đẳng chính nó không bao " #~ "giá» chá»n ngắt kết nối tá»›i bạn bè nếu việc đó có kết quả là quá ít bán bè " #~ "có kết nối (nếu số đã đặt không phải lá»›n hÆ¡n đích kết nối toàn bá»™)." #~ msgid "" #~ "If set to YES, the peer is only allowed to connect to other peers that " #~ "are explicitly specified as friends" #~ msgstr "" #~ "Bật tùy chá»n này (đặt YES) thì đồng đẳng chỉ được phép tá»›i đồng đẳng được " #~ "ghi rõ dứt khoát là bạn bè" #~ msgid "" #~ "Use YES only if you have (trustworthy) friends that use GNUnet and are " #~ "afraid of establishing (direct) connections to unknown peers" #~ msgstr "" #~ "Hãy đặt YES chỉ nếu bạn có bạn bè tin cậy có sá»­ dụng GNUnet và không muốn " #~ "thiết lập kết nối trá»±c tiếp tá»›i đồng đẳng lạ" #~ msgid "List of friends for friend-to-friend topology" #~ msgstr "Danh sách bạn bè cho địa hình bạn-đến-bạn" #~ msgid "" #~ "Specifies the name of a file which contains a list of GNUnet peer IDs " #~ "that are friends. If used with the friend-to-friend topology, this will " #~ "ensure that GNUnet only connects to these peers (via any available " #~ "transport)." #~ msgstr "" #~ "Ghi rõ tên cá»§a má»™t tập tin chứa danh sách các mã số đồng đẳng GNUnet cÅ©ng " #~ "là bạn bè. Nếu dùng vá»›i địa hình bạn-đến-bạn, thì tùy chá»n này sẽ đảm bảo " #~ "rằng GNUnet chỉ kết nối tá»›i những đồng đẳng đó (qua bất cứ cÆ¡ chế truyá»n " #~ "hoạt động nào)." #~ msgid "Friend-to-Friend Topology Specification" #~ msgstr "Äặc tả địa hình bạn-đến-bạn" #~ msgid "Settings for restricting connections to friends" #~ msgstr "Thiết lập để hạn chế kết nối thành bạn bè" #~ msgid "Name of the MySQL database GNUnet should use" #~ msgstr "Tên cá»§a cÆ¡ sở dữ liệu MySQL mà GNUnet nên dùng" #~ msgid "Configuration file that specifies the MySQL username and password" #~ msgstr "Tập tin cấu hình mà ghi rõ tên ngưá»i dùng và mật khẩu MySQL" #~ msgid "Configuration of the MySQL database" #~ msgstr "Cấu hình cá»§a cÆ¡ sở dữ liệu MySQL" #~ msgid "MB of diskspace GNUnet can use for anonymous file sharing" #~ msgstr "MB sức chứa trên đĩa cho GNUnet dùng để chia sẻ tập tin nặc danh" #~ msgid "" #~ "How much disk space (MB) is GNUnet allowed to use for anonymous file " #~ "sharing? This does not take indexed files into account, only the space " #~ "directly used by GNUnet is accounted for. GNUnet will gather content " #~ "from the network if the current space-consumption is below the number " #~ "given here (and if content migration is allowed below).\n" #~ "\n" #~ "Note that if you change the quota, you need to run gnunet-update " #~ "afterwards." #~ msgstr "" #~ "Bao nhiêu sức chứa trên đĩa (theo MB) cho phép GNUnet dùng để chia sẻ tập " #~ "tin má»™t cách nặc danh? Giá trị này không tính tập tin phụ lục, chỉ tính " #~ "sức chứa được GNUnet dùng trá»±c tiếp. GNUnet sẽ tập hợp ná»™i dung từ mạng " #~ "nếu tiêu thụ sức chứa hiện thá»i nhá» hÆ¡n số đưa ra ở đây (và nếu chức năng " #~ "nâng cấp ná»™i dung được phép bên dưới).\n" #~ "\n" #~ "Ghi chú rằng nếu bạn sá»­a đổi hạn ngạch này, sau đó cÅ©ng cần phải chạy " #~ "tiến trình cập nhật gnunet-update." #~ msgid "Number of entries in the migration buffer" #~ msgstr "Số các mục nhập trong vùng đệm nâng cấp" #~ msgid "" #~ "Each entry uses about 32k of memory. More entries can reduce disk IO and " #~ "CPU usage at the expense of having gnunetd use more memory. Very large " #~ "values may again increase CPU usage. A value of 0 will prevent your peer " #~ "from sending unsolicited responses." #~ msgstr "" #~ "Má»—i mục nhập chiếm khoảng 32k trong vùng nhá»›. Nhiá»u mục nhập hÆ¡n thì có " #~ "thể giảm VR cá»§a đĩa và sá»­ dụng CPU, còn gnunetd chiếm vùng nhá»› lá»›n hÆ¡n. " #~ "Giá trị rất lá»›n cÅ©ng có thể tăng sá»­ dụng CPU. Giá trị 0 sẽ ngăn cản máy " #~ "này đáp ứng mà không yêu cầu." #~ msgid "Size of the routing table for anonymous routing." #~ msgstr "Kích cỡ cá»§a bảng định tuyến đối vá»›i định tuyến nặc danh." #~ msgid "Size of the routing table for DHT routing." #~ msgstr "Kích cỡ cá»§a bảng định tuyến đối vá»›i định tuyến DHT." #~ msgid "Allow migrating content to this peer." #~ msgstr "Cho phép nâng cấp ná»™i dung lên máy này." #~ msgid "" #~ "If you say yes here, GNUnet will migrate content to your server, and you " #~ "will not be able to control what data is stored on your machine. \n" #~ "\t\t\t\n" #~ "If you activate it, you can claim for *all* the non-indexed (-n to gnunet-" #~ "insert) content that you did not know what it was even if an adversary " #~ "takes control of your machine. If you do not activate it, it is obvious " #~ "that you have knowledge of all the content that is hosted on your machine " #~ "and thus can be considered liable for it." #~ msgstr "" #~ "Bật tùy chá»n này thì GNUnet sẽ nâng cấp ná»™i dung đến máy phục vụ này, và " #~ "bạn không thể Ä‘iá»u khiển dữ liệu nào được giữ trên máy này.\n" #~ "\n" #~ "Tùy chá»n này cho phép ngưá»i dùng từ chối trách nhiệm vá» ná»™i dung không " #~ "phụ lục (-n tá»›i gnunet-insert) nằm trong máy cá»§a mình, thậm chí nếu ngưá»i " #~ "khác xâm nhập hệ thống. Không bật tùy chá»n này thì ngưá»i dùng chịu trách " #~ "nhiệm vá» tất cả các ná»™i dung trên máy cá»§a mình." #~ msgid "" #~ "MB of diskspace GNUnet can use for caching DHT index data (the data will " #~ "be stored in /tmp)" #~ msgstr "" #~ "MB sức chứa trên đĩa cho GNUnet dùng để lưu tạm dữ liệu phụ lục DHT (dữ " #~ "liệu được giữ trong /tmp)" #~ msgid "" #~ "DHT index data is inherently small and expires comparatively quickly. It " #~ "is deleted whenever gnunetd is shut down.\n" #~ "\n" #~ "The size of the DSTORE QUOTA is specified in MB." #~ msgstr "" #~ "Dữ liệu phụ lục DHT vốn đã nhá» và hết hạn hÆ¡i nhanh. Nó bị xoá khi nào " #~ "gnunetd bị thoát.\n" #~ "\n" #~ "Kích cỡ cá»§a hạn ngạch kho dữ liệu (DSTORE QUOTA) được ghi rõ theo MB." #~ msgid "Options for anonymous file sharing" #~ msgstr "Tùy chá»n vá» chia sẻ tập tin nặc danh" #~ msgid "Applications" #~ msgstr "Ứng dụng" #~ msgid "Is this machine unreachable behind a NAT?" #~ msgstr "Máy này không tá»›i được ở sau NAT không?" #~ msgid "" #~ "Set to YES if this machine is behind a NAT that limits connections from " #~ "the outside to the GNUnet port and that cannot be traversed using UPnP. " #~ "Note that if you have configured your NAT box to allow direct connections " #~ "from other machines to the GNUnet ports or if GNUnet can open ports using " #~ "UPnP, you should set the option to NO. Set this only to YES if other " #~ "peers cannot contact you directly. You can use 'make check' in src/" #~ "transports/upnp/ to find out if your NAT supports UPnP. You can also use " #~ "gnunet-transport-check with the '-p' option in order to determine which " #~ "setting results in more connections. Use YES only if you get no " #~ "connections otherwise. Set to AUTO to use YES if the local IP is belongs " #~ "to a private IP network and NO otherwise." #~ msgstr "" #~ "Äặt thành YES (có) nếu máy này nằm sau má»™t máy NAT mà hạn chế kết nối từ " #~ "bên ngoài đến cổng GNUnet và không thể Ä‘i qua được dùng UPnP. Ghi chú " #~ "rằng nếu bạn đã cấu hình máy NAT để cho phép kết nối trá»±c tiếp từ máy " #~ "khác đến cổng GNUnet, hoặc nếu GNUnet có quyá»n mở cổng dùng UPnP, thì bạn " #~ "nên đặt tùy chá»n này thành NO (không). Chỉ đặt thành YES nếu đồng đẳng " #~ "khác không thể liên lạc vá»›i máy này má»™t cách trá»±c tiếp. Bạn cÅ©ng có thể " #~ "sá»­ dụng câu lệnh « make check » (trong /src/transports/upnp) để tìm biết " #~ "nếu NAT đó há»— trợ UPnP không. Bạn cÅ©ng có thể sá»­ dụng công cụ gnunet-" #~ "transport-check vá»›i tùy chá»n « -p » để quyết định thiết lập nào gây ra " #~ "nhiá»u kết nối hÆ¡n. Äặt YES chỉ nếu bạn không nhận kết nối bằng cách khác. " #~ "Äặt thành AUTO (tá»± động) để sá»­ dụng YES nếu địa chỉ IP cục bá»™ thuá»™c vá» " #~ "má»™t mạng IP riêng, không thì NO." #~ msgid "Which port should be used by the TCP IPv4 transport?" #~ msgstr "CÆ¡ chế truyá»n IPv4 TCP nên dùng cổng nào?" #~ msgid "Should we try to determine our external IP using UPnP?" #~ msgstr "" #~ "Có nên thá»­ quyết định địa chỉ IP bên ngoài cá»§a mình dùng UPnP không?" #~ msgid "Which IP(v4)s are not allowed to connect?" #~ msgstr "Những địa chỉ IP(v4) nào không có quyá»n kết nối?" #~ msgid "" #~ "Which IP(v4)s are allowed to connect? Leave empty to use the IP of your " #~ "primary network interface." #~ msgstr "" #~ "Những địa chỉ IP(v4) nào có quyá»n kết nối? Bá» trống để sá»­ dụng địa chỉ IP " #~ "cá»§a giao diện mạng chính." #~ msgid "Which IPv6s are not allowed to connect?" #~ msgstr "Những địa chỉ IPv6 nào không có quyá»n kết nối?" #~ msgid "" #~ "Which IPv6s are allowed to connect? Leave empty to allow any IP to " #~ "connect." #~ msgstr "" #~ "Những địa chỉ IPv6 nào có quyá»n kết nối? Bá» trống để cho phép má»i địa chỉ " #~ "IP kết nối." #~ msgid "TCP transport" #~ msgstr "CÆ¡ chế truyá»n TCP" #~ msgid "Which port should be used by the HTTP transport?" #~ msgstr "CÆ¡ chế truyá»n HTTP nên dùng cổng nào?" #~ msgid "Which is the external port of the HTTP transport?" #~ msgstr "CÆ¡ chế truyá»n HTTP dùng cổng bên ngoài nào?" #~ msgid "" #~ "Use this option if your firewall maps, say, port 80 to your real HTTP " #~ "port. This can be useful in making the HTTP messages appear even more " #~ "legit (without needing to run gnunetd as root due to the use of a " #~ "privileged port)." #~ msgstr "" #~ "Hãy bật tùy chá»n này nếu bức tưá»ng lá»­a ánh xạ, v.d. cổng 80 vá»›i cổng HTTP " #~ "thật. Có thể hữu ích để làm cho các thông Ä‘iệp HTTP hình như ngay cả " #~ "chính đáng hÆ¡n (mà không cần chạy gnunetd dưới ngưá»i chá»§ do dùng má»™t cổng " #~ "có quyá»n đặc biệt)." #~ msgid "HTTP transport" #~ msgstr "CÆ¡ chế truyá»n HTTP" #~ msgid "What is the maximum transfer unit for SMTP?" #~ msgstr "Äối vá»›i SMTP, đơn vị truyá»n tối Ä‘a là gì?" #~ msgid "" #~ "What is the maximum number of e-mails that gnunetd would be allowed to " #~ "send per hour?" #~ msgstr "gnunetd có quyá»n gá»­i má»—i giá» bao nhiêu thư Ä‘iện tá»­ (tối Ä‘a)?" #~ msgid "Use 0 for unlimited" #~ msgstr "0 = vô hạn" #~ msgid "Which e-mail address should be used to send e-mail to this peer?" #~ msgstr "Äể gá»­i thư cho đồng đẳng này, có nên dùng địa chỉ thư Ä‘iện tá»­ nào?" #~ msgid "" #~ "You must make sure that e-mail received at this address is forwarded to " #~ "the PIPE which is read by gnunetd. Use the FILTER option to filter e-" #~ "mail with procmail and the PIPE option to set the name of the pipe." #~ msgstr "" #~ "Bạn cần phải đảm bảo rằng thư Ä‘iện tá»­ được nhận ở địa chỉ này thật được " #~ "chuyển tiếp tá»›i PIPE (ống dẫn) được gnunetd Ä‘á»c. Hãy dùng tùy chá»n FILTER " #~ "(lá»c) để lá»c thư bằng procmail, và tùy chá»n PIPE để đặt tên cá»§a ống dẫn." #~ msgid "" #~ "Which header line should other peers include in e-mails to enable " #~ "filtering?" #~ msgstr "Äể hiệu lá»±c lá»c thư, đồng đẳng khác nên ghi dòng đầu nào?" #~ msgid "" #~ "You can specify a header line here which can then be used by procmail to " #~ "filter GNUnet e-mail from your inbox and forward it to gnunetd." #~ msgstr "" #~ "Ở đây thì bạn có dịp ghi rõ má»™t dòng đầu cho procmail dùng để lá»c thư " #~ "GNUnet từ há»™p Thư Äến cá»§a bạn và chuyển tiếp nó tá»›i gnunetd." #~ msgid "What is the filename of the pipe where gnunetd can read its e-mail?" #~ msgstr "gnunetd có thể Ä‘á»c thư qua ống dẫn có tên tập tin nào?" #~ msgid "" #~ "Have a look at contrib/dot-procmailrc for an example .procmailrc file." #~ msgstr "" #~ "Xem « contrib/dot-procmailrc » để tìm má»™t tập tin .procmailrc ví dụ." #~ msgid "What is the name and port of the server for outgoing e-mail?" #~ msgstr "Máy phục vụ thư gá»­i ra có tên và cổng nào?" #~ msgid "The basic format is HOSTNAME:PORT." #~ msgstr "Äịnh dạng cÆ¡ bản là « TÊN_MÃY:Cá»”NG »." #~ msgid "SMTP transport" #~ msgstr "CÆ¡ chế SMTP" #~ msgid "Which port should be used by the UDP IPv4 transport?" #~ msgstr "CÆ¡ chế truyá»n IPv4 UDP nên dùng cổng nào?" #~ msgid "What is the maximum transfer unit for UDP?" #~ msgstr "Äối vá»›i UDP, đơn vị truyá»n tối Ä‘a là gì?" #~ msgid "Which IPs are not allowed to connect?" #~ msgstr "Những địa chỉ IP nào không có quyá»n kết nối?" #~ msgid "" #~ "Which IPs are allowed to connect? Leave empty to allow connections from " #~ "any IP." #~ msgstr "" #~ "Những địa chỉ IP nào có quyá»n kết nối? Bá» trống để cho phép kết nối từ " #~ "má»i địa chỉ IP." #~ msgid "UDP transport" #~ msgstr "CÆ¡ chế truyá»n UDP" #~ msgid "Network interface" #~ msgstr "Giao diện mạng" #~ msgid "External IP address (leave empty to try auto-detection)" #~ msgstr "Äịa chỉ IP bên ngoài (bá» trống để thá»­ tá»± động phát hiện)" #~ msgid "External IPv6 address (leave empty to try auto-detection)" #~ msgstr "Äịa chỉ IPv6 bên ngoài (bá» trống để thá»­ tá»± động phát hiện)" #~ msgid "Transports" #~ msgstr "CÆ¡ chế truyá»n" #~ msgid "What is the maximum number of bytes per second that we may receive?" #~ msgstr "Có thể nhận bao nhiêu byte má»—i giây (tối Ä‘a)?" #~ msgid "What is the maximum number of bytes per second that we may send?" #~ msgstr "Có thể gá»­i bao nhiêu byte má»—i giây (tối Ä‘a)?" #~ msgid "What is the maximum CPU load (percentage)?" #~ msgstr "Tải trá»ng CPU tối Ä‘a là gì (theo phần trăm)?" #~ msgid "" #~ "The highest tolerable CPU load. Load here always refers to the total " #~ "system load, that is it includes CPU utilization by other processes. A " #~ "value of 50 means that once your 1 minute-load average goes over 50% non-" #~ "idle, GNUnet will try to reduce CPU consumption until the load goes under " #~ "the threshold. Reasonable values are typically between 50 and 100. " #~ "Multiprocessors may use values above 100." #~ msgstr "" #~ "Tải trá»ng CPU cao nhất có thể. Ở đây thì tải trá»ng tham chiếu đến tổng số " #~ "tải trá»ng hệ thống, tức là nó cÅ©ng tính sá»­ dụng CPU cá»§a các tiến trình " #~ "khác. Giá trị 50 có nghÄ©a là má»™t khi tải trá»ng trung bình má»—i phút vượt " #~ "quá 50% không nghỉ, thì GNUnet thá»­ giảm sá»­ dụng CPU đến khi tải trá»ng nhá» " #~ "hÆ¡n ngưỡng. Giá trị hợp lý thưá»ng nằm giữa 50 và 100. Máy Ä‘a bá»™ xá»­ lý có " #~ "khả năng sá»­ dụng giá trị hÆ¡n 100." #~ msgid "What is the maximum IO load (permille)?" #~ msgstr "Tải trá»ng VR tối Ä‘a là gì (theo phần nghìn)?" #~ msgid "" #~ "The highest tolerable IO load. Load here refers to the percentage of CPU " #~ "cycles wasted waiting for IO for the entire system, that is it includes " #~ "disk utilization by other processes. A value of 10 means that once the " #~ "average number of cycles wasted waiting for IO is more than 10% non-idle, " #~ "GNUnet will try to reduce IO until the load goes under the threshold. " #~ "Reasonable values are typically between 10 and 75." #~ msgstr "" #~ "Tải trá»ng VR cao nhất có thể tha thứ được. Ở đây thì tải trá»ng tham chiếu " #~ "đến tá»· lệ phần trăm chu kỳ CPU bị phí khi đợi VR đối vá»›i toàn hệ thống, " #~ "tức là nó cÅ©ng tính sá»­ dụng đĩa cá»§a các tiến trình khác. Giá trị 10 có " #~ "nghÄ©a là má»™t khi số các chu kỳ trung bình bị phí khi đợi VR hÆ¡n 10% không " #~ "nghỉ, GNUnet sẽ thá»­ giảm VR đến khi tải trá»ng nhá» hÆ¡n ngưỡng. Giá trị hợp " #~ "lý thưá»ng nằm giữa 10 và 75." #~ msgid "What is the maximum CPU load (hard limit)?" #~ msgstr "Tải trá»ng CPU tối Ä‘a là gì (giá»›i hạn cứng)?" #~ msgid "" #~ "The highest tolerable CPU load. This is the hard limit, so once it is " #~ "reached, gnunetd will start to massively drop data to reduce the load. " #~ "Use with caution." #~ msgstr "" #~ "Tải trá»ng CPU cao nhất có thể tha thứ được. Äây là giá»›i hạn cứng, do đó " #~ "má»™t khi tá»›i được, gnunetd sẽ bắt đầu bá» rất nhiá»u dữ liệu để giảm tải " #~ "trá»ng. Hãy sá»­ dụng cẩn thận." #~ msgid "What is the maximum upstream bandwidth (hard limit)?" #~ msgstr "Băng thông dòng ra tối Ä‘a là gì (giá»›i hạn cứng)?" #~ msgid "" #~ "The limit is given as a percentage of the MAXNETUPBPS limit. Use 100 to " #~ "have MAXNETUPBPS be the hard limit. Use zero for no limit." #~ msgstr "" #~ "Giá»›i hạn được ghi rõ theo phần trăm cá»§a giá»›i hạn MAXNETUPBPS. Dùng 100 để " #~ "đặt MAXNETUPBPS là giá»›i hạn cứng. 0 = vô hạn." #, fuzzy #~ msgid "What priority should gnunetd use to run?" #~ msgstr "gnunetd nên chạy như nhóm nào?" #~ msgid "Should we disable random padding (experimental option)?" #~ msgstr "Có nên tắt đệm ngẫu nhiên (tùy chá»n vẫn thá»±c nghiệm) không?" #~ msgid "Use basic bandwidth limitation? (YES/NO). If in doubt, say YES." #~ msgstr "" #~ "Äặt giá»›i hạn băng thông cÆ¡ bản không? (YES/NO) Chưa chắc thì đặt YES (có)." #~ msgid "" #~ "Basic bandwidth limitation (YES) means simply that the bandwidth limits " #~ "specified apply to GNUnet and only to GNUnet. If set to YES, you simply " #~ "specify the maximum bandwidth (upstream and downstream) that GNUnet is " #~ "allowed to use and GNUnet will stick to those limitations. This is " #~ "useful if your overall bandwidth is so large that the limit is mostly " #~ "used to ensure that enough capacity is left for other applications. Even " #~ "if you want to dedicate your entire connection to GNUnet you should not " #~ "set the limits to values higher than what you have since GNUnet uses " #~ "those limits to determine for example the number of connections to " #~ "establish (and it would be inefficient if that computation yields a " #~ "number that is far too high). \n" #~ "\n" #~ "While basic bandwidth limitation is simple and always works, there are " #~ "some situations where it is not perfect. Suppose you are running another " #~ "application which performs a larger download. During that particular " #~ "time, it would be nice if GNUnet would throttle its bandwidth consumption " #~ "(automatically) and resume using more bandwidth after the download is " #~ "complete. This is obviously advanced magic since GNUnet will have to " #~ "monitor the behavior of other applications. Another scenario is a monthly " #~ "cap on bandwidth imposed by your ISP, which you would want to ensure is " #~ "obeyed. Here, you may want GNUnet to monitor the traffic from other " #~ "applications to ensure that the combined long-term traffic is within the " #~ "pre-set bounds. Note that you should probably not set the bounds tightly " #~ "since GNUnet may observe that the bounds are about to be broken but would " #~ "be unable to stop other applications from continuing to use bandwidth.\n" #~ "\n" #~ "If either of these two scenarios applies, set BASICLIMITING to NO. Then " #~ "set the bandwidth limits to the COMBINED amount of traffic that is " #~ "acceptable for both GNUnet and other applications. GNUnet will then " #~ "immediately throttle bandwidth consumption if the short-term average is " #~ "above the limit, and it will also try to ensure that the long-term " #~ "average is below the limit. Note however that using NO can have the " #~ "effect of GNUnet (almost) ceasing operations after other applications " #~ "perform high-volume downloads that are beyond the defined limits. GNUnet " #~ "would reduce consumption until the long-term limits are again within " #~ "bounds.\n" #~ "\n" #~ "NO only works on platforms where GNUnet can monitor the amount of traffic " #~ "that the local host puts out on the network. This is only implemented " #~ "for Linux and Win32. In order for the code to work, GNUnet needs to know " #~ "the specific network interface that is used for the external connection " #~ "(after all, the amount of traffic on loopback or on the LAN should never " #~ "be counted since it is irrelevant)." #~ msgstr "" #~ "Giá»›i hạn băng thông cÆ¡ bản (YES) có nghÄ©a đơn giản là má»—i giá»›i hạn băng " #~ "thông đưa ra chỉ áp dụng cho GNUnet. Nếu đặt thành YES (có) thì bạn đơn " #~ "giản chỉ ghi rõ băng thông tối Ä‘a (dòng ra và dòng vào) cho phép GNUnet " #~ "dùng, và GNUnet sẽ tuân theo những giá»›i hạn đó. Có ích nếu băng thông " #~ "toàn bá»™ lá»›n quá đến mức là giá»›i hạn thưá»ng dùng để đảm bảo đủ khả năng " #~ "còn lại cho các ứng dụng khác. Thậm chí nếu bạn muốn dành kết nối hoàn " #~ "toàn cho GNUnet, không nên đặt giá»›i hạn thành giá trị cao hÆ¡n khả năng, " #~ "vì GNUnet dùng giá»›i hạn đó để quyết định, ví dụ, số các kết nối nên thiết " #~ "lập (không có hiệu quả nếu phép tính có kết quả là quá lá»›n).\n" #~ "\n" #~ "Dù chức năng hạn chế băng thông cÆ¡ bản vẫn đơn giản và lúc nào cÅ©ng hoạt " #~ "động được, trong má»™t số trưá»ng hợp nào đó nó không phải hoàn toàn. Giả sá»­ " #~ "bạn Ä‘ang chạy má»™t ứng dụng khác mà thá»±c hiện má»™t công việc tải xuống lá»›n " #~ "hÆ¡n. Trong khi làm công việc đó, có ích nếu GNUnet giảm tiêu thụ băng " #~ "thông (má»™t cách tá»± động), cÅ©ng tăng lại má»™t khi công việc tải xuống đó đã " #~ "chạy xong. Chức năng này thá»±c sá»± phức tạp, vì GNUnet phải theo dõi ứng xá»­ " #~ "cá»§a các ứng dụng khác. Má»™t trưá»ng hợp khác là má»™t ngưỡng băng thông hàng " #~ "tháng được nhà cung cấp dịch vụ Internet (ISP) Ä‘iá»u khiển: bạn muốn đảm " #~ "bảo tuân theo nó. Trong trưá»ng hợp đó, bạn có thể muốn theo dõi tải cho " #~ "mạng từ các ứng dụng khác để đảm bảo rằng tổng số tải trá»ng lâu dài nằm " #~ "dưới ngưỡng định sẵn. Ghi chú rằng không nên đặt ngưỡng quá chặt chẽ vì " #~ "GNUnet có thể phát hiện ngưỡng sắp bị vượt quá nhưng không thể ngăn cản " #~ "ứng dụng khác tiếp tục chiếm băng thông.\n" #~ "\n" #~ "Nếu có má»™t cá»§a hai trưá»ng hợp này, hãy đặt BASICLIMITING thành NO " #~ "(không). Sau đó thì đặt giá»›i hạn băng thông thành Tá»”NG Sá» tải trá»ng thoả " #~ "đáng cho cả hai GNUnet và ứng dụng khác. GNUnet thì giảm ngay tiêu thụ " #~ "băng thông nếu trung bình ngắn kỳ hÆ¡n giá»›i hạn, nó cÅ©ng thá»­ đảm bảo rằng " #~ "trung bình lâu dài dưới giá»›i hạn. Tuy nhiên, ghi chú rằng việc đặt NO " #~ "(không) có kết quả có thể là GNUnet gần dừng hoạt động sau khi ứng dụng " #~ "khác chạy công việc lá»›n mà vượt quá giá»›i hạn đã xác định. Lúc đó, GNUnet " #~ "sẽ giảm tiêu thụ đến khi giá»›i hạn lâu dài lại nằm trong phạm vi đưa ra.\n" #~ "\n" #~ "Giá trị NO chỉ hoạt động được trên ná»n tảng thích hợp vá»›i GNUnet theo dõi " #~ "tải cho mạng được máy cục bá»™ gá»­i. Chức năng này chỉ được thá»±c hiện cho " #~ "Linux và Win32. Äể mà mã hoạt động được, GNUnet cần biết giao diện mạng " #~ "dứt khoát dùng cho kết nối bên ngoài (thôi, lượng tải trá»ng trên mạch ná»™i " #~ "bá»™ hay LAN không bao giá» nên được đếm vì nó không thích đáng). " #~ msgid "Network interface to monitor" #~ msgstr "Giao diện mạng cần theo dõi" #~ msgid "" #~ "For which interfaces should we do accounting? GNUnet will evaluate the " #~ "total traffic (not only the GNUnet related traffic) and adjust its " #~ "bandwidth usage accordingly. You can currently only specify a single " #~ "interface. GNUnet will also use this interface to determine the IP to " #~ "use. Typical values are eth0, ppp0, eth1, wlan0, etc. 'ifconfig' will " #~ "tell you what you have. Never use 'lo', that just won't work. Under " #~ "Windows, specify the index number reported by 'gnunet-win-tool -n'." #~ msgstr "" #~ "Có nên tính đến những giao diện nào? GNUnet sẽ định giá tổng số tải trá»ng " #~ "(không phải chỉ tải trá»ng liên quan đến GNUnet) và Ä‘iá»u chỉnh sá»­ dụng " #~ "băng thông má»™t cách thích hợp. Hiện thá»i ngưá»i dùng chỉ có thể ghi rõ má»™t " #~ "giao diện riêng lẻ. GNUnet sẽ cÅ©ng sá»­ dụng giao doện này để quyết định " #~ "địa chỉ IP cần dùng. Giá trị thưá»ng dùng: eth0, ppp0, eth1, wlan0, v.v. " #~ "Lệnh « ifconfig » sẽ hiển thị những giao diện sẵn sàng. Không bao giá» nên " #~ "dùng « lo » vì nó không hoạt động được. Dưới Windows, hãy ghi rõ số chỉ " #~ "mục trả lại bởi câu lệnh « gnunet-win-tool -n »." #~ msgid "Load management" #~ msgstr "Quản lý tải trá»ng" #~ msgid "Root node" #~ msgstr "Nút gốc" #~ msgid "Where should gnunet-clients write their logs?" #~ msgstr "Ứng dụng khách gnunet-clients nên ghi sổ theo dõi vào đâu?" #~ msgid "On which machine and port is gnunetd running (for clients)?" #~ msgstr "gnunetd Ä‘ang chạy trên máy và cổng nào (cho ứng dụng khách)?" #~ msgid "This is equivalent to the -H option. The format is IP:PORT." #~ msgstr "Äây tương đương vá»›i tùy chá»n « -H ». Äịnh dạng là « IP:Cá»”NG »." #~ msgid "What is the path to the configuration file for gnunetd?" #~ msgstr "Tập tin cấu hình gnunetd có đưá»ng dẫn nào?" #~ msgid "This option is used when clients need to start gnunetd." #~ msgstr "Tùy chá»n này dùng khi ứng dụng khách cần khởi chạy gnunetd." #~ msgid "General options" #~ msgstr "Tùy chá»n chung" #~ msgid "Do not add metadata listing the creation time for inserted content" #~ msgstr "" #~ "Không nên thêm siêu dữ liệu mà ghi nhá»› giá» tạo cá»§a ná»™i dung được chèn vào" #~ msgid "" #~ "Which non-default extractors should GNUnet use for keyword extractors" #~ msgstr "" #~ "Äối vá»›i bá»™ trích khác từ khoá, GNUnet nên dùng những bá»™ trích khác mặc " #~ "định nào?" #~ msgid "" #~ "Specify which additional extractor libraries should be used. gnunet-" #~ "insert uses libextractor to extract keywords from files. libextractor can " #~ "be dynamically extended to handle additional file formats. If you want to " #~ "use more than the default set of extractors, specify additional extractor " #~ "libraries here. The format is [[-]LIBRARYNAME[:[-]LIBRARYNAME]*].\n" #~ "\n" #~ "The default is to use filenames and to break larger words at spaces (and " #~ "underscores, etc.). This should be just fine for most people. The '-' " #~ "before a library name indicates that this should be executed last and " #~ "makes only sense for the split-library." #~ msgstr "" #~ "Ghi rõ những thư viện trích bổ sung nào nên dùng. Tiến trình chèn gnunet-" #~ "insert sá»­ dụng libextractor để trích các từ khoá khá»i tập tin. " #~ "libextractor cÅ©ng có thể mở rá»™ng động để quản lý định dạng tập tin bổ " #~ "sung. Muốn sá»­ dụng bá»™ trích bên ngoài tập hợp mặc định thì ghi rõ ở đây " #~ "những thư viện trích bổ sung. Äịnh dạng là « [[-]tên_thư_viện[:[-]" #~ "tên_thư_viện]*] ».\n" #~ "\n" #~ "Mặc định là dùng tên tập tin, và ngắt từ lá»›n ở dấu cách, dấu gạch dưới v." #~ "v. Äây nên ổn cho phần lá»›n ngưá»i dùng. Dấu gạch nối « - » đằng trước má»™t " #~ "tên thư viện có ngụ ý nó nên được thá»±c hiện cuối cùng, thích hợp chỉ cho " #~ "split-library." #~ msgid "How many entries should the URI DB table have?" #~ msgstr "Bảng DB URI nên chứa bao nhiêu mục nhập?" #~ msgid "" #~ "GNUnet uses two bytes per entry on the disk. This database is used to " #~ "keep track of how a particular URI has been used in the past. For " #~ "example, GNUnet may remember that a particular URI has been found in a " #~ "search previously or corresponds to a file uploaded by the user. This " #~ "information can then be used by user-interfaces to filter URI lists, such " #~ "as search results. If the database is full, older entries will be " #~ "discarded. The default value should be sufficient without causing undue " #~ "disk utilization." #~ msgstr "" #~ "GNUnet dùng hai byte cho má»—i mục nhập trên đĩa. CÆ¡ sở dữ liệu này dùng để " #~ "theo dõi má»™t URI nào đó đã được sá»­ dụng như thế nào. Ví dụ, GNUnet có thể " #~ "nhá»› rằng má»™t URI nào đó đã được phát hiện bằng má»™t công việc tìm kiếm " #~ "trước, hay tương ứng vá»›i má»™t tập tin được ngưá»i dùng tải lên. Thông tin " #~ "này thì có thể được dùng bởi giao diện ngưá»i dùng để lá»c danh sách các " #~ "URI, như kết quả tìm kiếm. Nếu cÆ¡ sở dữ liệu bị đầy thì há»§y các mục nhập " #~ "cÅ©. Giá trị mặc định nên ổn mà không gây ra sá»­ dụng đĩa má»™t cách quá " #~ "chừng." #~ msgid "" #~ "Location of the file specifying metadata for the auto-share directory" #~ msgstr "Vị trí cá»§a tập tin ghi rõ siêu dữ liệu cho thư mục tá»± động chia sẻ" #~ msgid "" #~ "Location of the file with the PID of any running gnunet-auto-share daemon " #~ "process" #~ msgstr "" #~ "Vị trí cá»§a tập tin chứa PID cá»§a bất kỳ tiến trình ná»n gnunet-auto-share" #~ msgid "Location of the log file for gnunet-auto-share" #~ msgstr "Vị trí cá»§a tập tin theo dõi cho gnunet-auto-share" #~ msgid "Which plugins should be loaded by gnunet-gtk?" #~ msgstr "gnunet-gtk nên nạp những phần bổ sung nào?" #~ msgid "" #~ "Load the about plugin for the about dialog. The daemon plugin allows " #~ "starting and stopping of gnunetd and displays information about gnunetd. " #~ "The fs plugin provides the file-sharing functionality. The stats plugin " #~ "displays various statistics about gnunetd." #~ msgstr "" #~ "Nạp phần bổ sung about cho há»™p thoại giá»›i thiệu. Phần bổ sung daemon cho " #~ "phép khởi chạy và dừng chạy trình ná»n gnunetd, và hiển thị thông tin vá» " #~ "gnunetd. Phần bổ sung fs cung cấp chức năng chia sẻ tập tin. Phần bổ sung " #~ "stats hiển thị thống kê khác nhau vá» gnunetd." #~ msgid "How frequently (in milli-seconds) should the statistics update?" #~ msgstr "Thống kê có nên cập nhật thưá»ng xuyên cỡ nào (theo mili-giây)?" #~ msgid "" #~ "Each pixel in the stats dialog corresponds to the time interval specified " #~ "here." #~ msgstr "" #~ "Má»—i Ä‘iểm ảnh trong há»™p thoại thống kê thì tương ứng vá»›i khoảng thá»i gian " #~ "đưa ra ở đây." #~ msgid "Do not show thumbnail previews from meta-data in search results" #~ msgstr "" #~ "Không hiển thị ô xem thá»­ ảnh mẫu từ siêu dữ liệu trong kết quả tìm kiếm" #~ msgid "" #~ "This option is useful for people who maybe offended by some previews or " #~ "use gnunet-gtk at work and would like to avoid bad surprises." #~ msgstr "" #~ "Tùy chá»n này có ích cho ngưá»i dùng không thích má»™t số ô xem thá»­, hoặc sá»­ " #~ "dụng gnunet-gtk ở chá»— làm và muốn tránh sá»± ngạc nhiên xấu." #~ msgid "" #~ "This option is useful to eliminate files that the user already has from " #~ "the search. Naturally, enabling this option maybe confusing because some " #~ "obviously expected search results would no longer show up. This option " #~ "only works if the URI_DB_SIZE option under FS is not zero (since the URI " #~ "DB is used to determine which files the user is sharing)" #~ msgstr "" #~ "Tùy chá»n này có ích để loại ra việc tìm kiếm những tập tin đã có trên máy " #~ "đó. Tất nhiên, bật tùy chá»n có thể gây ra bối rối vì má»™t số kết quả tìm " #~ "kiếm mong đợi sẽ không được hiển thị. Tùy chá»n này chỉ hoạt động được nếu " #~ "tùy chá»n URI_DB_SIZE (kích cỡ cÆ¡ sở dữ liệu URI) dưới FS khác số không " #~ "(vì cÆ¡ sở dữ liệu URI được dùng để quyết định những tập tin được ngưá»i " #~ "dùng chia sẻ)" #~ msgid "To which directory should gnunet-gtk save downloads to?" #~ msgstr "gnunet-gtk nên lưu tập tin tải vá» vào thư mục nào?" #~ msgid "Options related to gnunet-gtk" #~ msgstr "Tùy chá»n liên quan đến gnunet-gtk" #~ msgid "Full pathname of GNUnet client HOME directory" #~ msgstr "Tên đưá»ng dẫn đầy đủ đến thư mục HOME khách GNUnet" #~ msgid "The directory for GNUnet files that belong to the user." #~ msgstr "Thư mục chứa những tập tin GNUnet mà thuá»™c vá» ngưá»i dùng." #~ msgid "`%s' failed at %s:%d with error `%s' after %llums\n" #~ msgstr "« %s » bị lá»—i tại %s:%d vá»›i lá»—i:« %s » đẳng sau %llu miligiây\n" #~ msgid "" #~ "Directory `%s' in directory `%s' does not match naming convention. " #~ "Removed.\n" #~ msgstr "" #~ "Thư mục « %s » trong thư mục « %s » không tùy theo quy ước đặt tên. Bị gỡ " #~ "bá».\n" gnunet-0.9.3/po/en@quot.header0000644000175000017500000000226311260753602013154 00000000000000# All this catalog "translates" are quotation characters. # The msgids must be ASCII and therefore cannot contain real quotation # characters, only substitutes like grave accent (0x60), apostrophe (0x27) # and double quote (0x22). These substitutes look strange; see # http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html # # This catalog translates grave accent (0x60) and apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019). # It also translates pairs of apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019) # and pairs of quotation mark (0x22) to # left double quotation mark (U+201C) and right double quotation mark (U+201D). # # When output to an UTF-8 terminal, the quotation characters appear perfectly. # When output to an ISO-8859-1 terminal, the single quotation marks are # transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to # grave/acute accent (by libiconv), and the double quotation marks are # transliterated to 0x22. # When output to an ASCII terminal, the single quotation marks are # transliterated to apostrophes, and the double quotation marks are # transliterated to 0x22. # gnunet-0.9.3/po/sv.gmo0000644000175000017500000000755611763406752011546 00000000000000Þ•+t;̸¹¿Ñãü-0^%|-¢.Ð ÿ& GgK‡%Óùÿ&,=/Br;7Ë)1Ew+$«1Ð',A.pru#w›v¶- 4 H Z q Ž .¨ × %õ . /J z &›  Ü `ö /W ‡ “ .— Æ ß 1ä  >5 6t « )Ä 7î &3.(b6‹Â"ÄçDé.035U !&)($ '"+*# %   days# bytes decrypted# bytes encrypted# bytes received via TCP%s: illegal option -- %c %s: invalid option -- %c %s: option `%c%s' does not allow an argument %s: option `%s' is ambiguous %s: option `%s' requires an argument %s: option `--%s' does not allow an argument %s: option `-W %s' does not allow an argument %s: option `-W %s' is ambiguous %s: option requires an argument -- %c %s: unrecognized option `%c%s' %s: unrecognized option `--%s' Arguments mandatory for long options are also mandatory for short options. Cannot change user/group to `%s': %s DEBUGERRORFailed to read friends list from `%s' I am peer `%s'. INFOInitialization of plugin mechanism failed: %s! Invalid format for IP: `%s' Invalid network notation ('/%d' is not legal in IPv4 CIDR).Invalid network notation (does not end with ';': `%s') No keywords specified! Print statistics about GNUnet operations.Trying to use file `%s' for MySQL configuration. WARNINGYou must pass a number to the `%s' option. `%s' failed at %s:%d with error: %s `%s' failed on file `%s' at %s:%d with error: %s bdownload a GNUnet directory recursivelyhlibgcrypt has not the expected version (version %s is required). mmssspecify the priority of the contentwrite the file to FILENAMEProject-Id-Version: GNUnet 0.7.0b Report-Msgid-Bugs-To: gnunet-developers@mail.gnu.org POT-Creation-Date: 2012-06-05 15:47+0200 PO-Revision-Date: 2006-01-21 17:16+0100 Last-Translator: Daniel Nylander Language-Team: Swedish Language: sv MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit dagar# byte dekrypterade# byte krypterade# byte mottogs via TCP%s: otillÃ¥ten flagga -- %c %s: ogiltig flagga -- %c %s: flagga "%c%s" tillÃ¥ter inte ett argument %s: flagga "%s" är tvetydig %s: flagga "%s" kräver ett argument %s: flagga "--%s" tillÃ¥ter inte ett argument %s: flagga "-W %s" tillÃ¥ter inte ett argument %s: flagga "-W %s" är tvetydig %s: flagga kräver ett argument -- %c %s: okänd flagga "%c%s" %s: okänd flagga "--%s" Argument som är obligatoriska för lÃ¥nga flaggor är ocksÃ¥ obligatoriska för korta flaggor. Kan inte ändra användare/grupp till "%s": %s FELSÖKNINGFELMisslyckades att läsa kompislista frÃ¥n "%s" Jag är ändpunkt "%s". INFOInitiering av insticksmekanism misslyckades: %s! Ogiltigt format för IP: "%s" Ogiltig nätverksnotation ("/%d" är inte giltig i IPv4 CIDR).Ogiltig nätverksnotation (slutar inte med ";": "%s") Inga nyckelord angivna! Skriv ut statistik om GNUnet-operationer.Försöker använda fil "%s" för MySQL-konfiguration. VARNINGDu mÃ¥ste skicka med ett nummer till flaggan "%s". "%s" misslyckades vid %s:%d med fel: %s "%s" misslyckades för fil "%s" vid %s:%d med fel: %s bhämta en GNUnet-katalog rekursivthlibgcrypt har inte den förväntande versionen (version %s krävs). mmssange prioritet för innehÃ¥lletskriv filen till FILNAMNgnunet-0.9.3/po/quot.sed0000644000175000017500000000023111260753602012045 00000000000000s/"\([^"]*\)"/“\1â€/g s/`\([^`']*\)'/‘\1’/g s/ '\([^`']*\)' / ‘\1’ /g s/ '\([^`']*\)'$/ ‘\1’/g s/^'\([^`']*\)' /‘\1’ /g s/“â€/""/g gnunet-0.9.3/po/boldquot.sed0000644000175000017500000000033111260753602012707 00000000000000s/"\([^"]*\)"/“\1â€/g s/`\([^`']*\)'/‘\1’/g s/ '\([^`']*\)' / ‘\1’ /g s/ '\([^`']*\)'$/ ‘\1’/g s/^'\([^`']*\)' /‘\1’ /g s/“â€/""/g s/“/“/g s/â€/â€/g s/‘/‘/g s/’/’/g gnunet-0.9.3/po/POTFILES.in0000644000175000017500000001646611763406744012170 00000000000000src/arm/arm_api.c src/arm/do_start_process.c src/arm/gnunet-arm.c src/arm/gnunet-service-arm.c src/arm/mockup-service.c src/ats/ats_api_performance.c src/ats/ats_api_scheduling.c src/ats/gnunet-service-ats_addresses.c src/ats/gnunet-service-ats_addresses_mlp.c src/ats/gnunet-service-ats.c src/ats/gnunet-service-ats_performance.c src/ats/gnunet-service-ats_reservations.c src/ats/gnunet-service-ats_scheduling.c src/block/block.c src/block/plugin_block_template.c src/block/plugin_block_test.c src/chat/chat.c src/chat/gnunet-chat.c src/chat/gnunet-service-chat.c src/core/core_api.c src/core/core_api_is_connected.c src/core/core_api_iterate_peers.c src/core/gnunet-core.c src/core/gnunet-service-core.c src/core/gnunet-service-core_clients.c src/core/gnunet-service-core_kx.c src/core/gnunet-service-core_neighbours.c src/core/gnunet-service-core_sessions.c src/core/gnunet-service-core_typemap.c src/datacache/datacache.c src/datacache/plugin_datacache_mysql.c src/datacache/plugin_datacache_postgres.c src/datacache/plugin_datacache_sqlite.c src/datacache/plugin_datacache_template.c src/datastore/datastore_api.c src/datastore/gnunet-service-datastore.c src/datastore/plugin_datastore_mysql.c src/datastore/plugin_datastore_postgres.c src/datastore/plugin_datastore_sqlite.c src/datastore/plugin_datastore_template.c src/dht/dht_api.c src/dht/gnunet-dht-get.c src/dht/gnunet-dht-monitor.c src/dht/gnunet-dht-put.c src/dht/gnunet-service-dht.c src/dht/gnunet-service-dht_clients.c src/dht/gnunet-service-dht_datacache.c src/dht/gnunet-service-dht_hello.c src/dht/gnunet-service-dht_neighbours.c src/dht/gnunet-service-dht_nse.c src/dht/gnunet-service-dht_routing.c src/dht/plugin_block_dht.c src/dns/dns_api.c src/dns/dnsparser.c src/dns/gnunet-dns-monitor.c src/dns/gnunet-dns-redirector.c src/dns/gnunet-helper-dns.c src/dns/gnunet-service-dns.c src/dns/plugin_block_dns.c src/dv/dv_api.c src/dv/gnunet-service-dv.c src/dv/plugin_transport_dv.c src/exit/gnunet-daemon-exit.c src/exit/gnunet-helper-exit.c src/fragmentation/defragmentation.c src/fragmentation/fragmentation.c src/fs/fs_api.c src/fs/fs_directory.c src/fs/fs_dirmetascan.c src/fs/fs_download.c src/fs/fs_file_information.c src/fs/fs_getopt.c src/fs/fs_list_indexed.c src/fs/fs_misc.c src/fs/fs_namespace_advertise.c src/fs/fs_namespace.c src/fs/fs_publish.c src/fs/fs_publish_ksk.c src/fs/fs_search.c src/fs/fs_sharetree.c src/fs/fs_test_lib.c src/fs/fs_tree.c src/fs/fs_unindex.c src/fs/fs_uri.c src/fs/gnunet-directory.c src/fs/gnunet-download.c src/fs/gnunet-fs.c src/fs/gnunet-helper-fs-publish.c src/fs/gnunet-pseudonym.c src/fs/gnunet-publish.c src/fs/gnunet-search.c src/fs/gnunet-service-fs.c src/fs/gnunet-service-fs_cp.c src/fs/gnunet-service-fs_indexing.c src/fs/gnunet-service-fs_lc.c src/fs/gnunet-service-fs_pe.c src/fs/gnunet-service-fs_pr.c src/fs/gnunet-service-fs_push.c src/fs/gnunet-service-fs_put.c src/fs/gnunet-unindex.c src/fs/plugin_block_fs.c src/gns/gns_api.c src/gns/gnunet-gns.c src/gns/gnunet-gns-fcfsd.c src/gns/gnunet-gns-proxy.c src/gns/gnunet-service-gns.c src/gns/gnunet-service-gns_interceptor.c src/gns/gnunet-service-gns_resolver.c src/gns/nss/nss_gns.c src/gns/nss/nss_gns_query.c src/gns/plugin_block_gns.c src/hello/address.c src/hello/gnunet-hello.c src/hello/hello.c src/hostlist/gnunet-daemon-hostlist.c src/hostlist/hostlist-client.c src/hostlist/hostlist-server.c src/integration-tests/connection_watchdog.c src/lockmanager/gnunet-service-lockmanager.c src/lockmanager/lockmanager_api.c src/mesh/gnunet-service-mesh.c src/mesh/mesh_api.c src/mesh/mesh_tunnel_tree.c src/mysql/mysql.c src/namestore/gnunet-namestore.c src/namestore/gnunet-service-namestore.c src/namestore/namestore_api.c src/namestore/namestore_common.c src/namestore/plugin_namestore_sqlite.c src/nat/gnunet-helper-nat-client.c src/nat/gnunet-helper-nat-client-windows.c src/nat/gnunet-helper-nat-server.c src/nat/gnunet-helper-nat-server-windows.c src/nat/gnunet-nat-server.c src/nat/nat.c src/nat/nat_mini.c src/nat/nat_test.c src/nse/gnunet-nse-profiler.c src/nse/gnunet-service-nse.c src/nse/nse_api.c src/peerinfo/gnunet-service-peerinfo.c src/peerinfo/peerinfo_api.c src/peerinfo/peerinfo_api_notify.c src/peerinfo-tool/gnunet-peerinfo.c src/peerinfo-tool/gnunet-peerinfo_plugins.c src/postgres/postgres.c src/pt/gnunet-daemon-pt.c src/regex/regex.c src/statistics/gnunet-service-statistics.c src/statistics/gnunet-statistics.c src/statistics/statistics_api.c src/stream/stream_api.c src/template/gnunet-service-template.c src/template/gnunet-template.c src/testbed/testbed_api.c src/testbed/testbed_api_hosts.c src/testbed/testbed_api_operations.c src/testbed/testbed_api_peers.c src/testbed/testbed_api_services.c src/testbed/testbed_api_testbed.c src/testbed/testbed_api_test.c src/testbed/testbed_api_topology.c src/testing/gnunet-testing.c src/testing/helper.c src/testing/testing.c src/testing/testing_group.c src/testing/testing_new.c src/testing/testing_peergroup.c src/topology/gnunet-daemon-topology.c src/transport/gnunet-helper-transport-wlan.c src/transport/gnunet-helper-transport-wlan-dummy.c src/transport/gnunet-service-transport_blacklist.c src/transport/gnunet-service-transport.c src/transport/gnunet-service-transport_clients.c src/transport/gnunet-service-transport_hello.c src/transport/gnunet-service-transport_neighbours.c src/transport/gnunet-service-transport_plugins.c src/transport/gnunet-service-transport_validation.c src/transport/gnunet-transport.c src/transport/gnunet-transport-certificate-creation.c src/transport/gnunet-transport-wlan-sender.c src/transport/plugin_transport_http.c src/transport/plugin_transport_http_client.c src/transport/plugin_transport_http_server.c src/transport/plugin_transport_tcp.c src/transport/plugin_transport_template.c src/transport/plugin_transport_udp_broadcasting.c src/transport/plugin_transport_udp.c src/transport/plugin_transport_unix.c src/transport/plugin_transport_wlan.c src/transport/transport_api_address_lookup.c src/transport/transport_api_address_to_string.c src/transport/transport_api_blacklist.c src/transport/transport_api.c src/transport/transport-testing.c src/tun/tun.c src/util/bandwidth.c src/util/bio.c src/util/client.c src/util/common_allocation.c src/util/common_endian.c src/util/common_logging.c src/util/configuration.c src/util/connection.c src/util/container_bloomfilter.c src/util/container_heap.c src/util/container_meta_data.c src/util/container_multihashmap.c src/util/container_slist.c src/util/crypto_aes.c src/util/crypto_crc.c src/util/crypto_hash.c src/util/crypto_hkdf.c src/util/crypto_kdf.c src/util/crypto_ksk.c src/util/crypto_random.c src/util/crypto_rsa.c src/util/disk.c src/util/getopt.c src/util/getopt_helpers.c src/util/gnunet-config-diff.c src/util/gnunet-resolver.c src/util/gnunet-rsa.c src/util/gnunet-service-resolver.c src/util/helper.c src/util/load.c src/util/network.c src/util/os_installation.c src/util/os_network.c src/util/os_priority.c src/util/peer.c src/util/plugin.c src/util/program.c src/util/pseudonym.c src/util/resolver_api.c src/util/scheduler.c src/util/server.c src/util/server_mst.c src/util/server_nc.c src/util/server_tc.c src/util/service.c src/util/signal.c src/util/speedup.c src/util/strings.c src/util/time.c src/util/winproc.c src/vpn/gnunet-helper-vpn.c src/vpn/gnunet-service-vpn.c src/vpn/gnunet-vpn.c src/vpn/vpn_api.c src/dht/dht.h src/include/gnunet_common.h src/include/gnunet_postgres_lib.h src/include/gnunet_time_lib.h gnunet-0.9.3/po/vi.gmo0000644000175000017500000003170011763406752011520 00000000000000Þ•id•¬    + D \ #r – ° Ê -ä  %0 -V .„ ³ &Ô û  K; %‡ $­ .Ò Q #S !w ™ º À !Æ =è & &@ ]g GÅ  /#S;p7¬äLûH `&m0”0Å)ö/ Po,,º+ç1oE!µW×6/bfKÉ@‰V$à(.C,K+x¤:Áü$,81e2—ÊkÞ JT6VE^Ó2'KsAu·¹¼ ÄåNFQ˜Mšè)7,"d^‡#æ Ä%êñ ')G"q6”$Ë,ð(8F&3¦8Ú9)M0w,¨,ÕvByA¼?þ‰> ;È 2!.7! f!q!+w!b£!"0""fS"fº"#!#E#0I#'z#D¢#Cç#'+$QS$¥$$À$)å$C%LS%- %/Î%>þ%.=&;l&;¨&:ä&<'¥\'$(£'(EË(”)r¦)t*¸Ž*>G+D†+%Ë+ ñ+Gý+6E,|,7˜,Ð,0æ,?-IW-Q¡-ó-… . .›.H.Næ.–5/%Ì//ò/"0L$0q0s0 v0*‚0 ­0mÎ0]<1š1`œ1&ý1L$2Gq2.¹2‡è2-p3!ž3*=6J"_'(YI[.d0>hXF,K;\PL<aDH 1eB#7)C2!Tg+M ^ 5S A @NRE8V?9Z]O %G&U:i4bfcQ/`3-W$ days# bytes decrypted# bytes encrypted# bytes received via TCP# messages defragmented# messages fragmented# requests filtered by bloom filter%s failed at %s:%d: `%s' %s: illegal option -- %c %s: invalid option -- %c %s: option `%c%s' does not allow an argument %s: option `%s' is ambiguous %s: option `%s' requires an argument %s: option `--%s' does not allow an argument %s: option `-W %s' does not allow an argument %s: option `-W %s' is ambiguous %s: option requires an argument -- %c %s: unrecognized option `%c%s' %s: unrecognized option `--%s' Arguments mandatory for long options are also mandatory for short options. Cannot change user/group to `%s': %s Cannot extract metadata from a URI! Cannot obtain information about user `%s': %s Configuration value '%s' for '%s' in section '%s' is not in set of legal choices Could not find IP of host `%s': %s Could not read friends list `%s' Could not resolve `%s' (%s): %s DEBUGERRORExpected `%s' to be a directory! Failed to expand `$HOME': environment variable `HOME' not setFailed to join room `%s' Failed to read friends list from `%s' Fewer friends specified than required by minimum friend count. Will only connect to friends. File `%s' in directory `%s' does not match naming convention. Removed. I am peer `%s'. INFOInitialization of plugin mechanism failed: %s! Invalid format for IP: `%s' Invalid network notation ('/%d' is not legal in IPv4 CIDR).Invalid network notation (does not end with ';': `%s') Join a chat on GNUnet.More friendly connections required than target total number of connections. No keywords specified! No such userNumber of double-quotes not balanced! Option `%s' is required when using option `%s'. Option `%s' makes no sense without option `%s'. Print statistics about GNUnet operations.RSA signature verification failed at %s:%d: %s Still no peers found in `%s'! Syntax: /msg USERNAME MESSAGEThe `/leave' command is an alias for `/quit'The `/notice' command is an alias for `/msg'The `/query' command is an alias for `/msg'Trying to use file `%s' for MySQL configuration. URI to be published (can be used instead of passing a file to add keywords to the file with the respective URI)Unable to initialize SQLite: %s. Unknown metadata type in metadata option `%s'. Using metadata type `unknown' instead. Use `/help command' to get help for a specific commandUse `/join #roomname' to join a chat room. Joining a room will cause you to leave the current roomUse `/msg nickname message' to send a private message to the specified userUse `/names' to list all of the current members in the chat roomUse `/nick nickname' to change your nickname. This will cause you to leave the current room and immediately rejoin it with the new name.Use `/quit' to terminate gnunet-chatUser `%s' is currently not in the room! Users in room `%s': WARNINGYou must NOT specify an URI and a filename. You must pass a number to the `%s' option. You must specify a nickname You must specify one and only one filename for insertion. `%s' entered the room `%s' failed at %s:%d with error: %s `%s' failed for library `%s' with error: %s `%s' failed on file `%s' at %s:%d with error: %s `%s' failed to resolve method '%s' with error: %s `%s' left the room add an additional keyword for the top-level file or directory (this option can be specified multiple times)anonymousbdelete incomplete downloads (when aborted with CTRL-C)disable adding the creation time to the metadata of the uploaded filedo not index, perform full insertion (stores entire file in encrypted form in GNUnet database)don't resolve host namesdownload a GNUnet directory recursivelyhlibgcrypt has not the expected version (version %s is required). mmsno-nameoutput only the identity stringsoutput our own identity onlyprint list of extracted keywords that would be used, but do not perform uploadpublish the files under the pseudonym NAME (place file into namespace)sset the ID of this version of the publication (for namespace insertions only)set the chat room to joinset the desired LEVEL of sender-anonymityset the meta-data for the given TYPE to the given VALUEset the nickname to use (required)specify ID of an updated version to be published in the future (for namespace insertions only)specify the priority of the contentwrite the file to FILENAMEProject-Id-Version: gnunet 0.8.0a Report-Msgid-Bugs-To: gnunet-developers@mail.gnu.org POT-Creation-Date: 2012-06-05 15:47+0200 PO-Revision-Date: 2008-09-10 22:05+0930 Last-Translator: Clytie Siddall Language-Team: Vietnamese Language: vi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=1; plural=0; X-Generator: LocFactoryEditor 1.7b3 ngày# các byte đã giải mã# các byte đã mã hoá# các byte đã nhận qua TCP# các thông báo được chắp liá»n# các thông báo bị tế phân# các yêu cầu được lá»c theo bá»™ lá»c bloom%s bị lá»—i tại %s:%d: « %s » %s: tùy chá»n không được phép -- %c %s: tùy chá»n không hợp lệ -- %c %s: tùy chá»n « %c%s » không cho phép đối số %s: tùy chá»n « %s » là mÆ¡ hồ %s: tùy chá»n « %s » cần thiết đối số %s: tùy chá»n « --%s » không cho phép đối số %s: tùy chá»n « -W %s » không cho phép đối số %s: tùy chá»n « -W %s » là mÆ¡ hồ %s: tùy chá»n cần thiết đối số -- %c %s: không nhận ra tùy chá»n « %c%s » %s: không nhận ra tùy chá»n « --%s » Má»i đối số bắt buá»™c phải sá»­ dụng vá»›i tùy chá»n dài cÅ©ng bắt buá»™c vá»›i tùy chá»n ngắn. Không thể thay đổi ngưá»i dùng/nhóm thành « %s »: %s Không thể trích siêu dữ liệu ra má»™t địa chỉ URI. Không thể lấy thông tin vá» ngưá»i dùng « %s »: %s Giá trị cấu hình « %s » cho « %s » trong phần « %s » không phải nằm trong tập hợp các sá»± chá»n được phép Không tìm thấy địa chỉ IP cá»§a máy « %s »: %s Không thể Ä‘á»c danh sách bạn bè « %s » Không thể giải quyết « %s » (%s): %s Gá»  Lá»–ILá»–IMong đợi « %s » là má»™t thư mục. Lá»—i mở rá»™ng biến môi trưá»ng « $HOME »: chưa đặt biến môi trưá»ng « HOME »Lá»—i vào phòng « %s » Lá»—i Ä‘á»c danh sách bạn bè từ « %s » Xác định quá ít bạn bè (dưới số tối thiểu). Sẽ chỉ kết nối tá»›i bạn bè. Tập tin « %s » trong thư mục « %s » không tùy theo quy ước đặt tên. Bị gỡ bá». Tôi là đồng đẳng « %s ». TINLá»—i sÆ¡ khởi cÆ¡ chế phần bổ sung: %s Äịa chỉ IP định dạng sai: %s Ký hiệu mạng sai (« /%d » không hợp lệ trong CIDR IPv4).Ký hiệu mạng sai (không kết thúc vá»›i « ; »: « %s ») Vào phòng trò chuyện trên GNUnet.Cần thiết nhiá»u kết nối bạn bè hÆ¡n tổng số kết nối đích. Chưa ghi rõ từ khoá. Không có ngưá»i dùng như vậyCó dấu nháy kép thừa hay thiếu. Tùy chá»n « %s » cần thiết khi dùng tùy chá»n « %s ». Tùy chá»n « %s » không có nghÄ©a khi không có tùy chá»n « %s ». In ra thống kê vá» các thao tác GNUnet.Lá»—i thẩm tra chữ ký RSA tại %s:%d: %s Vẫn còn không tìm thấy đồng đẳng trong « %s ». Cú pháp: /msg TÊN_NGƯỜI_DÙNG TIN_NHẲNLệnh « /leave » là má»™t biệt hiệu cho « /quit »Lệnh « /notice » là má»™t biệt hiệu cho « /msg »Lệnh « /query » là má»™t biệt hiệu cho « /msg »Äang thá»­ dùng tập tin « %s » cho cấu hình MySQL. Äịa chỉ URI cần công bố (có thể được dùng thay vào gá»­i má»™t tập tin để thêm từ khoá vào tập tin có địa chỉ URI tương ứng)Không thể sÆ¡ khởi SQLite: %s. Không rõ kiểu siêu dữ liệu trong tùy chá»n siêu dữ liệu « %s ». Äang ùng kiểu siêu dữ liệu « không rõ » (unknown) để thay thế. Gõ chuá»—i « /help LỆNH » để xem trợ giúp vá» lệnh đóGõ chuá»—i « /join #tên_phòng » để vào má»™t phòng trò chuyện nào đó (việc này cÅ©ng gây ra bạn ra khá»i phòng hiện tại)Gõ chuá»—i « /msg tên_hiệu tin_nhẳn » để gá»­i má»™t tin nhẳn riêng cho ngưá»i dùng có tên đóGõ chuá»—i « /names » để liệt kê tất cả các thành viên hiện thá»i trong phòng trò chuyện đóGõ chuá»—i « /nick tên_hiệu » để thay đổi tên hiệu cá»§a mình (việc này cÅ©ng gây ra bạn ra khá»i phòng hiện tại, sau đó vào lại ngay vá»›i tên má»›i)Gõ chuá»—i « /quit » để thoát khá»i trình gnunet-chatNgưá»i dùng « %s » hiện thá»i không có trong phòng này. Ngưá»i dùng trong phòng « %s »:CẢNH BÃOKHÔNG cho phép ghi rõ cả hai địa chỉ URI và tên tập tin. Phải gá»­i má»™t con số cho tùy chá»n « %s ». Phải ghi rõ tên hiệu Phải ghi rõ chỉ má»™t tên tập tin để chèn. « %s » vào phòng « %s » bị lá»—i tại %s:%d vá»›i lá»—i: %s « %s » thất bại cho thư viện « %s » vá»›i lá»—i: %s « %s » thất bại ở tập tin « %s » tại %s:%d vá»›i lá»—i: %s « %s » không giải quyết được phương pháp « %s », vá»›i lá»—i: %s « %s » rá»i phòng thêm má»™t từ khoá bổ sung cho tập tin hoặc thư mục ở cấp đầu (có thể chỉ ra tùy chá»n này nhiá»u lần)nặc danhbxoá việc tải vá» không hoàn thành (khi há»§y bở dùng CTRL-C)tắt thêm giá» tạo vào siêu dữ liệu cá»§a tập tin đã tải lênkhông đánh chỉ mục, thá»±c hiện việc chèn đầy đủ (chứa toàn bá»™ tập tin ở dạng mã hóa trong cÆ¡ sở dữ liệu GNUnet)không quyết định các tên máytải xuống đệ quy má»™t thư mục GNUnetglibgcrypt không có phiên bản mong đợi (yêu cầu phiên bản %s). pmgkhông-tênchỉ xuất những chuá»—i nhận diệnchỉ xuất nhận diện mìnhin ra danh sách các từ khóa đã giải phóng cần sá»­ dụng, nhưng không thá»±c hiện tải lêncông bố các tập tin dưới biệt hiệu TÊN (đặt tập tin vào không gian tên)gđặt mã số cá»§a phiên bản này cá»§a sá»± công bố (chỉ cho chèn không gian tên)đặt phòng trò chuyện cần vàođặt CẤP mong muốn cá»§a tình trạng nặc danh cá»§a ngưá»i gá»­iđặt siêu dữ liệu cho KIỂU đưa ra thành GIÃ_TRỊ chỉ rađặt tên hiệu cần dùng (cần thiết)chỉ ra mã số cá»§a má»™t phiên bản đã cập nhật để công bố trong tương lai (chỉ cho sá»± chèn không gian tên)xác định mức ưu tiên cá»§a ná»™i dungghi tập tin vào TÊN_TẬP_TINgnunet-0.9.3/po/Rules-quot0000644000175000017500000000337611260753602012400 00000000000000# Special Makefile rules for English message catalogs with quotation marks. DISTFILES.common.extra1 = quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot .SUFFIXES: .insert-header .po-update-en en@quot.po-create: $(MAKE) en@quot.po-update en@boldquot.po-create: $(MAKE) en@boldquot.po-update en@quot.po-update: en@quot.po-update-en en@boldquot.po-update: en@boldquot.po-update-en .insert-header.po-update-en: @lang=`echo $@ | sed -e 's/\.po-update-en$$//'`; \ if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; GETTEXTLIBDIR=`cd $(top_srcdir)/src && pwd`; export GETTEXTLIBDIR; fi; \ tmpdir=`pwd`; \ echo "$$lang:"; \ ll=`echo $$lang | sed -e 's/@.*//'`; \ LC_ALL=C; export LC_ALL; \ cd $(srcdir); \ if $(MSGINIT) -i $(DOMAIN).pot --no-translator -l $$ll -o - 2>/dev/null | sed -f $$tmpdir/$$lang.insert-header | $(MSGCONV) -t UTF-8 | $(MSGFILTER) sed -f `echo $$lang | sed -e 's/.*@//'`.sed 2>/dev/null > $$tmpdir/$$lang.new.po; then \ if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ rm -f $$tmpdir/$$lang.new.po; \ else \ if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ :; \ else \ echo "creation of $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ exit 1; \ fi; \ fi; \ else \ echo "creation of $$lang.po failed!" 1>&2; \ rm -f $$tmpdir/$$lang.new.po; \ fi en@quot.insert-header: insert-header.sin sed -e '/^#/d' -e 's/HEADER/en@quot.header/g' $(srcdir)/insert-header.sin > en@quot.insert-header en@boldquot.insert-header: insert-header.sin sed -e '/^#/d' -e 's/HEADER/en@boldquot.header/g' $(srcdir)/insert-header.sin > en@boldquot.insert-header mostlyclean: mostlyclean-quot mostlyclean-quot: rm -f *.insert-header gnunet-0.9.3/po/zh_CN.gmo0000644000175000017500000001032011763406752012076 00000000000000Þ•1¤C,89?Y-s¡%¿-å. B&cŠªKÊ%.<#k °¶!¼=Þ/!Q;n7ª âï! (/Xmu”+³ßü ' 1 3 A5 w y | „ † "  …à I N g (€ © )Ç (ñ * E 'f %Ž %´ 7Ú ' /: #j Ž ­ ´ » <Ô $=AY<› Øå'$Lj$q–0µæ5<>7Bz~ …“ ¯ '(.#/! -$* ,1& +0"% ) days%s: illegal option -- %c %s: invalid option -- %c %s: option `%c%s' does not allow an argument %s: option `%s' is ambiguous %s: option `%s' requires an argument %s: option `--%s' does not allow an argument %s: option `-W %s' does not allow an argument %s: option `-W %s' is ambiguous %s: option requires an argument -- %c %s: unrecognized option `%c%s' %s: unrecognized option `--%s' Arguments mandatory for long options are also mandatory for short options. Cannot change user/group to `%s': %s Cannot obtain information about user `%s': %s Could not find IP of host `%s': %s Could not resolve `%s' (%s): %s DEBUGERRORExpected `%s' to be a directory! Failed to expand `$HOME': environment variable `HOME' not setINFOInitialization of plugin mechanism failed: %s! Invalid format for IP: `%s' Invalid network notation ('/%d' is not legal in IPv4 CIDR).Invalid network notation (does not end with ';': `%s') No such userSyntax: /msg USERNAME MESSAGEUnable to initialize SQLite: %s. User `%s' is currently not in the room! Users in room `%s': WARNINGWrong format `%s' for netmask Wrong format `%s' for network You must pass a number to the `%s' option. You must specify a nickname `%s' entered the room `%s' left the room anonymousbhlibgcrypt has not the expected version (version %s is required). mmsno-namesset the chat room to joinset the nickname to use (required)Project-Id-Version: gnunet-0.8.1 Report-Msgid-Bugs-To: gnunet-developers@mail.gnu.org POT-Creation-Date: 2012-06-05 15:47+0200 PO-Revision-Date: 2011-07-09 12:12+0800 Last-Translator: Wylmer Wang Language-Team: Chinese (simplified) Language: zh_CN MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit 天%sï¼šéžæ³•选项 -- %c %s:无效选项 -- %c %s:选项“%c%sâ€ä¸å…è®¸æœ‰å‚æ•° %s:选项“%sâ€æœ‰æ­§ä¹‰ %s:选项“%sâ€è¦æ±‚æœ‰ä¸€ä¸ªå‚æ•° %s:选项“--%sâ€ä¸å…è®¸æœ‰å‚æ•° %s:选项“-W %s†ä¸å…è®¸æœ‰å‚æ•° %s:选项“-W %sâ€æœ‰æ­§ä¹‰ %sï¼šé€‰é¡¹è¦æ±‚æœ‰ä¸€ä¸ªå‚æ•° -- %c %s:无法识别的选项“%c%s†%s:无法识别的选项“--%sâ€ é•¿é€‰é¡¹çš„å¿…é€‰å‚æ•°å¯¹çŸ­é€‰é¡¹ä¹Ÿæ˜¯å¿…选的。 无法更改用户/组为“%sâ€ï¼š%s æ— æ³•èŽ·å–æœ‰å…³ç”¨æˆ·â€œ%sâ€çš„ä¿¡æ¯ï¼š%s 找ä¸åˆ°ä¸»æœºâ€œ%sâ€çš„ IP:%s 无法解æžâ€œ%sâ€(%s):%s 调试错误“%sâ€åº”ä¸ºç›®å½•ï¼ æ‰©å±•â€œ$HOMEâ€å¤±è´¥ï¼šæ²¡æœ‰è®¾ç½®çŽ¯å¢ƒå˜é‡â€œHOMEâ€ä¿¡æ¯æ’件机构åˆå§‹åŒ–失败:%sï¼ IP æ ¼å¼æ— æ•ˆï¼šâ€œ%s†网络表示法无效(“/%d†在 IPv4 CIDR ä¸­æ˜¯éžæ³•çš„)。无效的网络表示法(没有以“;â€ç»“尾:“%sâ€) 无此用户语法:/msg ç”¨æˆ·å æ¶ˆæ¯æ— æ³•åˆå§‹åŒ– SQLite:%s。 用户“%sâ€å½“å‰ä¸åœ¨æˆ¿é—´é‡Œï¼ 房间“%sâ€ä¸­çš„用户:警告网络掩ç çš„æ ¼å¼â€œ%sâ€é”™è¯¯ 网络的格å¼â€œ%sâ€é”™è¯¯ 您必须å‘“%sâ€é€‰é¡¹ä¼ é€’一个数字。 您必须指定一个昵称 “%sâ€è¿›å…¥äº†æˆ¿é—´ “%sâ€ç¦»å¼€äº†æˆ¿é—´ 匿åbæ—¶libgcrypt 的版本ä¸ç¬¦åˆé¢„期(è¦æ±‚版本 %s)。 分毫秒无å称秒设置è¦åŠ å…¥çš„èŠå¤©å®¤è®¾ç½®è¦ä½¿ç”¨çš„æ˜µç§°(å¿…é¡»)gnunet-0.9.3/po/Makefile.in.in0000644000175000017500000003322111760502552013040 00000000000000# Makefile for PO directory in any package using GNU gettext. # Copyright (C) 1995-1997, 2000-2006 by Ulrich Drepper # # This file can be copied and used freely without restrictions. It can # be used in projects which are not available under the GNU General Public # License but which still want to provide support for the GNU gettext # functionality. # Please note that the actual code of GNU gettext is covered by the GNU # General Public License and is *not* in the public domain. # # Origin: gettext-0.16 PACKAGE = @PACKAGE@ VERSION = @VERSION@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ SHELL = /bin/sh @SET_MAKE@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ datarootdir = @datarootdir@ datadir = @datadir@ localedir = @localedir@ gettextsrcdir = $(datadir)/gettext/po INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ # We use $(mkdir_p). # In automake <= 1.9.x, $(mkdir_p) is defined either as "mkdir -p --" or as # "$(mkinstalldirs)" or as "$(install_sh) -d". For these automake versions, # @install_sh@ does not start with $(SHELL), so we add it. # In automake >= 1.10, @mkdir_p@ is derived from ${MKDIR_P}, which is defined # either as "/path/to/mkdir -p" or ".../install-sh -c -d". For these automake # versions, $(mkinstalldirs) and $(install_sh) are unused. mkinstalldirs = $(SHELL) @install_sh@ -d install_sh = $(SHELL) @install_sh@ MKDIR_P = @MKDIR_P@ mkdir_p = @mkdir_p@ GMSGFMT_ = @GMSGFMT@ GMSGFMT_no = @GMSGFMT@ GMSGFMT_yes = @GMSGFMT_015@ GMSGFMT = $(GMSGFMT_$(USE_MSGCTXT)) MSGFMT_ = @MSGFMT@ MSGFMT_no = @MSGFMT@ MSGFMT_yes = @MSGFMT_015@ MSGFMT = $(MSGFMT_$(USE_MSGCTXT)) XGETTEXT_ = @XGETTEXT@ XGETTEXT_no = @XGETTEXT@ XGETTEXT_yes = @XGETTEXT_015@ XGETTEXT = $(XGETTEXT_$(USE_MSGCTXT)) MSGMERGE = msgmerge MSGMERGE_UPDATE = @MSGMERGE@ --update MSGINIT = msginit MSGCONV = msgconv MSGFILTER = msgfilter POFILES = @POFILES@ GMOFILES = @GMOFILES@ UPDATEPOFILES = @UPDATEPOFILES@ DUMMYPOFILES = @DUMMYPOFILES@ DISTFILES.common = Makefile.in.in remove-potcdate.sin \ $(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3) DISTFILES = $(DISTFILES.common) Makevars POTFILES.in \ $(POFILES) $(GMOFILES) \ $(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3) POTFILES = \ CATALOGS = @CATALOGS@ # Makevars gets inserted here. (Don't remove this line!) .SUFFIXES: .SUFFIXES: .po .gmo .mo .sed .sin .nop .po-create .po-update .po.mo: @echo "$(MSGFMT) -c -o $@ $<"; \ $(MSGFMT) -c -o t-$@ $< && mv t-$@ $@ .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o $${lang}.gmo $${lang}.po"; \ cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo .sin.sed: sed -e '/^#/d' $< > t-$@ mv t-$@ $@ all: all-@USE_NLS@ all-yes: stamp-po all-no: # $(srcdir)/$(DOMAIN).pot is only created when needed. When xgettext finds no # internationalized messages, no $(srcdir)/$(DOMAIN).pot is created (because # we don't want to bother translators with empty POT files). We assume that # LINGUAS is empty in this case, i.e. $(POFILES) and $(GMOFILES) are empty. # In this case, stamp-po is a nop (i.e. a phony target). # stamp-po is a timestamp denoting the last time at which the CATALOGS have # been loosely updated. Its purpose is that when a developer or translator # checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS, # "make" will update the $(DOMAIN).pot and the $(CATALOGS), but subsequent # invocations of "make" will do nothing. This timestamp would not be necessary # if updating the $(CATALOGS) would always touch them; however, the rule for # $(POFILES) has been designed to not touch files that don't need to be # changed. stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) @test ! -f $(srcdir)/$(DOMAIN).pot || { \ echo "touch stamp-po" && \ echo timestamp > stamp-poT && \ mv stamp-poT stamp-po; \ } # Note: Target 'all' must not depend on target '$(DOMAIN).pot-update', # otherwise packages like GCC can not be built if only parts of the source # have been downloaded. # This target rebuilds $(DOMAIN).pot; it is an expensive operation. # Note that $(DOMAIN).pot is not touched if it doesn't need to be changed. $(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in remove-potcdate.sed if test -n '$(MSGID_BUGS_ADDRESS)' || test '$(PACKAGE_BUGREPORT)' = '@'PACKAGE_BUGREPORT'@'; then \ msgid_bugs_address='$(MSGID_BUGS_ADDRESS)'; \ else \ msgid_bugs_address='$(PACKAGE_BUGREPORT)'; \ fi; \ $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) \ --files-from=$(srcdir)/POTFILES.in \ --copyright-holder='$(COPYRIGHT_HOLDER)' \ --msgid-bugs-address="$$msgid_bugs_address" test ! -f $(DOMAIN).po || { \ if test -f $(srcdir)/$(DOMAIN).pot; then \ sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \ sed -f remove-potcdate.sed < $(DOMAIN).po > $(DOMAIN).2po && \ if cmp $(DOMAIN).1po $(DOMAIN).2po >/dev/null 2>&1; then \ rm -f $(DOMAIN).1po $(DOMAIN).2po $(DOMAIN).po; \ else \ rm -f $(DOMAIN).1po $(DOMAIN).2po $(srcdir)/$(DOMAIN).pot && \ mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ fi; \ else \ mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ fi; \ } # This rule has no dependencies: we don't need to update $(DOMAIN).pot at # every "make" invocation, only create it when it is missing. # Only "make $(DOMAIN).pot-update" or "make dist" will force an update. $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update # This target rebuilds a PO file if $(DOMAIN).pot has changed. # Note that a PO file is not touched if it doesn't need to be changed. $(POFILES): $(srcdir)/$(DOMAIN).pot @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ echo "$${cdcmd}$(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot"; \ cd $(srcdir) && $(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot; \ else \ $(MAKE) $${lang}.po-create; \ fi install: install-exec install-data install-exec: install-data: install-data-@USE_NLS@ if test "$(PACKAGE)" = "gettext-tools"; then \ $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ for file in $(DISTFILES.common) Makevars.template; do \ $(INSTALL_DATA) $(srcdir)/$$file \ $(DESTDIR)$(gettextsrcdir)/$$file; \ done; \ for file in Makevars; do \ rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ done; \ else \ : ; \ fi install-data-no: all install-data-yes: all $(mkdir_p) $(DESTDIR)$(datadir) @catalogs='$(CATALOGS)'; \ for cat in $$catalogs; do \ cat=`basename $$cat`; \ lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ dir=$(localedir)/$$lang/LC_MESSAGES; \ $(mkdir_p) $(DESTDIR)$$dir; \ if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \ $(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \ echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \ for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ if test -n "$$lc"; then \ if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ for file in *; do \ if test -f $$file; then \ ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ fi; \ done); \ rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ else \ if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ :; \ else \ rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ fi; \ fi; \ rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \ fi; \ done; \ done install-strip: install installdirs: installdirs-exec installdirs-data installdirs-exec: installdirs-data: installdirs-data-@USE_NLS@ if test "$(PACKAGE)" = "gettext-tools"; then \ $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ else \ : ; \ fi installdirs-data-no: installdirs-data-yes: $(mkdir_p) $(DESTDIR)$(datadir) @catalogs='$(CATALOGS)'; \ for cat in $$catalogs; do \ cat=`basename $$cat`; \ lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ dir=$(localedir)/$$lang/LC_MESSAGES; \ $(mkdir_p) $(DESTDIR)$$dir; \ for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ if test -n "$$lc"; then \ if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ for file in *; do \ if test -f $$file; then \ ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ fi; \ done); \ rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ else \ if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ :; \ else \ rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ fi; \ fi; \ fi; \ done; \ done # Define this as empty until I found a useful application. installcheck: uninstall: uninstall-exec uninstall-data uninstall-exec: uninstall-data: uninstall-data-@USE_NLS@ if test "$(PACKAGE)" = "gettext-tools"; then \ for file in $(DISTFILES.common) Makevars.template; do \ rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ done; \ else \ : ; \ fi uninstall-data-no: uninstall-data-yes: catalogs='$(CATALOGS)'; \ for cat in $$catalogs; do \ cat=`basename $$cat`; \ lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \ rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ done; \ done check: all info dvi ps pdf html tags TAGS ctags CTAGS ID: mostlyclean: rm -f remove-potcdate.sed rm -f stamp-poT rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po rm -fr *.o clean: mostlyclean distclean: clean rm -f Makefile Makefile.in POTFILES *.mo maintainer-clean: distclean @echo "This command is intended for maintainers to use;" @echo "it deletes files that may require special tools to rebuild." rm -f stamp-po $(GMOFILES) distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) dist distdir: $(MAKE) update-po @$(MAKE) dist2 # This is a separate target because 'update-po' must be executed before. dist2: stamp-po $(DISTFILES) dists="$(DISTFILES)"; \ if test "$(PACKAGE)" = "gettext-tools"; then \ dists="$$dists Makevars.template"; \ fi; \ if test -f $(srcdir)/$(DOMAIN).pot; then \ dists="$$dists $(DOMAIN).pot stamp-po"; \ fi; \ if test -f $(srcdir)/ChangeLog; then \ dists="$$dists ChangeLog"; \ fi; \ for i in 0 1 2 3 4 5 6 7 8 9; do \ if test -f $(srcdir)/ChangeLog.$$i; then \ dists="$$dists ChangeLog.$$i"; \ fi; \ done; \ if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \ for file in $$dists; do \ if test -f $$file; then \ cp -p $$file $(distdir) || exit 1; \ else \ cp -p $(srcdir)/$$file $(distdir) || exit 1; \ fi; \ done update-po: Makefile $(MAKE) $(DOMAIN).pot-update test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. .nop.po-create: @lang=`echo $@ | sed -e 's/\.po-create$$//'`; \ echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 # General rule for updating PO files. .nop.po-update: @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; fi; \ tmpdir=`pwd`; \ echo "$$lang:"; \ test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ echo "$${cdcmd}$(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ cd $(srcdir); \ if $(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$tmpdir/$$lang.new.po; then \ if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ rm -f $$tmpdir/$$lang.new.po; \ else \ if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ :; \ else \ echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ exit 1; \ fi; \ fi; \ else \ echo "msgmerge for $$lang.po failed!" 1>&2; \ rm -f $$tmpdir/$$lang.new.po; \ fi $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) @: Makefile: Makefile.in.in Makevars $(top_builddir)/config.status @POMAKEFILEDEPS@ cd $(top_builddir) \ && $(SHELL) ./config.status $(subdir)/$@.in po-directories force: # Tell versions [3.59,3.63) of GNU make not to export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/po/insert-header.sin0000644000175000017500000000124011260753602013626 00000000000000# Sed script that inserts the file called HEADER before the header entry. # # At each occurrence of a line starting with "msgid ", we execute the following # commands. At the first occurrence, insert the file. At the following # occurrences, do nothing. The distinction between the first and the following # occurrences is achieved by looking at the hold space. /^msgid /{ x # Test if the hold space is empty. s/m/m/ ta # Yes it was empty. First occurrence. Read the file. r HEADER # Output the file's contents by reading the next line. But don't lose the # current line while doing this. g N bb :a # The hold space was nonempty. Following occurrences. Do nothing. x :b } gnunet-0.9.3/po/gnunet.pot0000644000175000017500000041535311763406751012433 00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Christian Grothoff # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: gnunet-developers@mail.gnu.org\n" "POT-Creation-Date: 2012-06-05 15:47+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: src/arm/arm_api.c:165 msgid "Failed to transmit shutdown request to client.\n" msgstr "" #: src/arm/arm_api.c:349 #, c-format msgid "Configuration failes to specify option `%s' in section `%s'!\n" msgstr "" #: src/arm/arm_api.c:363 #, c-format msgid "Configuration fails to specify option `%s' in section `%s'!\n" msgstr "" #: src/arm/arm_api.c:432 #, c-format msgid "Error receiving response to `%s' request from ARM for service `%s'\n" msgstr "" #: src/arm/arm_api.c:485 #, c-format msgid "Requesting start of service `%s'.\n" msgstr "" #: src/arm/arm_api.c:486 #, c-format msgid "Requesting termination of service `%s'.\n" msgstr "" #: src/arm/arm_api.c:507 #, c-format msgid "Error while trying to transmit request to start `%s' to ARM\n" msgstr "" #: src/arm/arm_api.c:508 #, c-format msgid "Error while trying to transmit request to stop `%s' to ARM\n" msgstr "" #: src/arm/arm_api.c:540 #, c-format msgid "Asked to start service `%s' within %llu ms\n" msgstr "" #: src/arm/arm_api.c:612 #, c-format msgid "Stopping service `%s' within %llu ms\n" msgstr "" #: src/arm/gnunet-arm.c:159 #, c-format msgid "Service `%s' is unknown to ARM.\n" msgstr "" #: src/arm/gnunet-arm.c:164 #, c-format msgid "Service `%s' has been stopped.\n" msgstr "" #: src/arm/gnunet-arm.c:167 #, c-format msgid "Service `%s' was already running.\n" msgstr "" #: src/arm/gnunet-arm.c:172 #, c-format msgid "Service `%s' has been started.\n" msgstr "" #: src/arm/gnunet-arm.c:175 #, c-format msgid "Service `%s' was already being stopped.\n" msgstr "" #: src/arm/gnunet-arm.c:179 #, c-format msgid "Service `%s' was already not running.\n" msgstr "" #: src/arm/gnunet-arm.c:183 msgid "Request ignored as ARM is shutting down.\n" msgstr "" #: src/arm/gnunet-arm.c:187 msgid "Error communicating with ARM service.\n" msgstr "" #: src/arm/gnunet-arm.c:191 msgid "Timeout communicating with ARM service.\n" msgstr "" #: src/arm/gnunet-arm.c:195 msgid "Operation failed.\n" msgstr "" #: src/arm/gnunet-arm.c:199 msgid "Unknown response code from ARM.\n" msgstr "" #: src/arm/gnunet-arm.c:222 msgid "Error communicating with ARM. ARM not running?\n" msgstr "" #: src/arm/gnunet-arm.c:225 msgid "Running services:\n" msgstr "" #: src/arm/gnunet-arm.c:249 #, c-format msgid "Fatal configuration error: `%s' option in section `%s' missing.\n" msgstr "" #: src/arm/gnunet-arm.c:257 src/arm/gnunet-arm.c:357 src/arm/gnunet-arm.c:373 msgid "Fatal error initializing ARM API.\n" msgstr "" #: src/arm/gnunet-arm.c:280 #, c-format msgid "Failed to remove configuration file %s\n" msgstr "" #: src/arm/gnunet-arm.c:286 #, c-format msgid "Failed to remove servicehome directory %s\n" msgstr "" #: src/arm/gnunet-arm.c:407 msgid "stop all GNUnet services" msgstr "" #: src/arm/gnunet-arm.c:409 msgid "start a particular service" msgstr "" #: src/arm/gnunet-arm.c:411 msgid "stop a particular service" msgstr "" #: src/arm/gnunet-arm.c:413 msgid "start all GNUnet default services" msgstr "" #: src/arm/gnunet-arm.c:416 msgid "stop and start all GNUnet default services" msgstr "" #: src/arm/gnunet-arm.c:419 msgid "delete config file and directory on exit" msgstr "" #: src/arm/gnunet-arm.c:421 msgid "don't print status messages" msgstr "" #: src/arm/gnunet-arm.c:424 msgid "timeout for completing current operation" msgstr "" #: src/arm/gnunet-arm.c:426 msgid "List currently running services" msgstr "" #: src/arm/gnunet-arm.c:437 msgid "Control services and the Automated Restart Manager (ARM)" msgstr "" #: src/arm/gnunet-service-arm.c:332 #, c-format msgid "Failed to start service `%s'\n" msgstr "" #: src/arm/gnunet-service-arm.c:335 #, c-format msgid "Starting service `%s'\n" msgstr "" #: src/arm/gnunet-service-arm.c:361 msgid "Could not send status result to client\n" msgstr "" #: src/arm/gnunet-service-arm.c:393 msgid "Could not send list result to client\n" msgstr "" #: src/arm/gnunet-service-arm.c:523 #, c-format msgid "Unable to create socket for service `%s': %s\n" msgstr "" #: src/arm/gnunet-service-arm.c:545 #, c-format msgid "Unable to bind listening socket for service `%s' to address `%s': %s\n" msgstr "" #: src/arm/gnunet-service-arm.c:559 #, c-format msgid "ARM now monitors connections to service `%s' at `%s'\n" msgstr "" #: src/arm/gnunet-service-arm.c:667 #, c-format msgid "Preparing to stop `%s'\n" msgstr "" #: src/arm/gnunet-service-arm.c:878 #, c-format msgid "Restarting service `%s'.\n" msgstr "" #: src/arm/gnunet-service-arm.c:970 msgid "exit" msgstr "" #: src/arm/gnunet-service-arm.c:975 msgid "signal" msgstr "" #: src/arm/gnunet-service-arm.c:980 msgid "unknown" msgstr "" #: src/arm/gnunet-service-arm.c:986 #, c-format msgid "Service `%s' took %llu ms to terminate\n" msgstr "" #: src/arm/gnunet-service-arm.c:1021 #, c-format msgid "Service `%s' terminated with status %s/%d, will restart in %llu ms\n" msgstr "" #: src/arm/gnunet-service-arm.c:1127 #, c-format msgid "Configuration file `%s' for service `%s' not valid: %s\n" msgstr "" #: src/arm/gnunet-service-arm.c:1129 msgid "option missing" msgstr "" #: src/arm/gnunet-service-arm.c:1213 #, c-format msgid "Starting default services `%s'\n" msgstr "" #: src/arm/gnunet-service-arm.c:1224 #, c-format msgid "Default service `%s' not configured correctly!\n" msgstr "" #: src/arm/gnunet-service-arm.c:1238 msgid "" "No default services configured, GNUnet will not really start right now.\n" msgstr "" #: src/arm/mockup-service.c:44 msgid "Initiating shutdown as requested by client.\n" msgstr "" #: src/block/block.c:105 #, c-format msgid "Loading block plugin `%s'\n" msgstr "" #: src/chat/chat.c:175 msgid "Could not transmit confirmation receipt\n" msgstr "" #: src/chat/chat.c:283 msgid "The current user must be the the first one joined\n" msgstr "" #: src/chat/chat.c:412 #, c-format msgid "Unknown message type: '%u'\n" msgstr "" #: src/chat/chat.c:472 #, c-format msgid "Configuration option `%s' in section `%s' missing\n" msgstr "" #: src/chat/chat.c:480 #, c-format msgid "Failed to access chat home directory `%s'\n" msgstr "" #: src/chat/chat.c:498 #, c-format msgid "Failed to create/open key in file `%s'\n" msgstr "" #: src/chat/chat.c:559 msgid "Could not serialize metadata\n" msgstr "" #: src/chat/chat.c:674 msgid "Failed to connect to the chat service\n" msgstr "" #: src/chat/chat.c:680 msgid "Undefined mandatory parameter: joinCallback\n" msgstr "" #: src/chat/chat.c:686 msgid "Undefined mandatory parameter: messageCallback\n" msgstr "" #: src/chat/chat.c:692 msgid "Undefined mandatory parameter: memberCallback\n" msgstr "" #: src/chat/gnunet-chat.c:93 msgid "Joined\n" msgstr "" #: src/chat/gnunet-chat.c:125 src/chat/gnunet-chat.c:133 #: src/chat/gnunet-chat.c:213 src/chat/gnunet-chat.c:253 #: src/chat/gnunet-chat.c:329 src/chat/gnunet-chat.c:371 #: src/chat/gnunet-chat.c:400 src/chat/gnunet-chat.c:700 msgid "anonymous" msgstr "" #: src/chat/gnunet-chat.c:144 #, c-format msgid "(%s) `%s' said: %s\n" msgstr "" #: src/chat/gnunet-chat.c:147 src/chat/gnunet-chat.c:150 #, c-format msgid "(%s) `%s' said to you: %s\n" msgstr "" #: src/chat/gnunet-chat.c:153 #, c-format msgid "(%s) `%s' said for sure: %s\n" msgstr "" #: src/chat/gnunet-chat.c:156 #, c-format msgid "(%s) `%s' said to you for sure: %s\n" msgstr "" #: src/chat/gnunet-chat.c:159 #, c-format msgid "(%s) `%s' was confirmed that you received: %s\n" msgstr "" #: src/chat/gnunet-chat.c:162 #, c-format msgid "(%s) `%s' was confirmed that you and only you received: %s\n" msgstr "" #: src/chat/gnunet-chat.c:165 #, c-format msgid "(%s) `%s' was confirmed that you received from him or her: %s\n" msgstr "" #: src/chat/gnunet-chat.c:170 #, c-format msgid "" "(%s) `%s' was confirmed that you and only you received from him or her: %s\n" msgstr "" #: src/chat/gnunet-chat.c:173 #, c-format msgid "(%s) `%s' said off the record: %s\n" msgstr "" #: src/chat/gnunet-chat.c:176 #, c-format msgid "(%s) <%s> said using an unknown message type: %s\n" msgstr "" #: src/chat/gnunet-chat.c:217 #, c-format msgid "'%s' acknowledged message #%d\n" msgstr "" #: src/chat/gnunet-chat.c:260 #, c-format msgid "`%s' entered the room\n" msgstr "" #: src/chat/gnunet-chat.c:260 #, c-format msgid "`%s' left the room\n" msgstr "" #: src/chat/gnunet-chat.c:321 src/chat/gnunet-chat.c:363 msgid "Could not change username\n" msgstr "" #: src/chat/gnunet-chat.c:334 src/chat/gnunet-chat.c:702 #, c-format msgid "Joining room `%s' as user `%s'...\n" msgstr "" #: src/chat/gnunet-chat.c:373 #, c-format msgid "Changed username to `%s'\n" msgstr "" #: src/chat/gnunet-chat.c:388 #, c-format msgid "Users in room `%s': " msgstr "" #: src/chat/gnunet-chat.c:434 msgid "Syntax: /msg USERNAME MESSAGE" msgstr "" #: src/chat/gnunet-chat.c:443 #, c-format msgid "Unknown user `%s'. Make sure you specify its numeric suffix, if any.\n" msgstr "" #: src/chat/gnunet-chat.c:460 #, c-format msgid "User `%s' is currently not in the room!\n" msgstr "" #: src/chat/gnunet-chat.c:513 #, c-format msgid "Unknown command `%s'\n" msgstr "" #: src/chat/gnunet-chat.c:524 msgid "" "Use `/join #roomname' to join a chat room. Joining a room will cause you to " "leave the current room" msgstr "" #: src/chat/gnunet-chat.c:528 msgid "" "Use `/nick nickname' to change your nickname. This will cause you to leave " "the current room and immediately rejoin it with the new name." msgstr "" #: src/chat/gnunet-chat.c:532 msgid "" "Use `/msg nickname message' to send a private message to the specified user" msgstr "" #: src/chat/gnunet-chat.c:535 msgid "The `/notice' command is an alias for `/msg'" msgstr "" #: src/chat/gnunet-chat.c:537 msgid "The `/query' command is an alias for `/msg'" msgstr "" #: src/chat/gnunet-chat.c:539 msgid "Use `/sig message' to send a signed public message" msgstr "" #: src/chat/gnunet-chat.c:542 msgid "Use `/ack message' to require signed acknowledgment of the message" msgstr "" #: src/chat/gnunet-chat.c:545 msgid "Use `/anonymous message' to send a public anonymous message" msgstr "" #: src/chat/gnunet-chat.c:547 msgid "The `/anon' command is an alias for `/anonymous'" msgstr "" #: src/chat/gnunet-chat.c:549 msgid "Use `/quit' to terminate gnunet-chat" msgstr "" #: src/chat/gnunet-chat.c:551 msgid "The `/leave' command is an alias for `/quit'" msgstr "" #: src/chat/gnunet-chat.c:554 msgid "Use `/names' to list all of the current members in the chat room" msgstr "" #: src/chat/gnunet-chat.c:556 msgid "Use `/help command' to get help for a specific command" msgstr "" #: src/chat/gnunet-chat.c:672 msgid "You must specify a nickname\n" msgstr "" #: src/chat/gnunet-chat.c:688 #, c-format msgid "Failed to join room `%s'\n" msgstr "" #: src/chat/gnunet-chat.c:727 msgid "set the nickname to use (required)" msgstr "" #: src/chat/gnunet-chat.c:730 msgid "set the chat room to join" msgstr "" #: src/chat/gnunet-chat.c:742 msgid "Join a chat on GNUnet." msgstr "" #: src/chat/gnunet-service-chat.c:267 msgid "Failed to queue a message notification\n" msgstr "" #: src/chat/gnunet-service-chat.c:546 msgid "Failed to queue a join notification\n" msgstr "" #: src/chat/gnunet-service-chat.c:729 msgid "Failed to queue a confirmation receipt\n" msgstr "" #: src/chat/gnunet-service-chat.c:907 msgid "Failed to queue a leave notification\n" msgstr "" #: src/core/core_api.c:786 msgid "Client was disconnected from core service, trying to reconnect.\n" msgstr "" #: src/core/gnunet-core.c:54 src/peerinfo-tool/gnunet-peerinfo.c:286 #, c-format msgid "Peer `%s'\n" msgstr "" #: src/core/gnunet-core.c:72 src/peerinfo-tool/gnunet-peerinfo.c:817 #, c-format msgid "Invalid command line argument `%s'\n" msgstr "" #: src/core/gnunet-core.c:95 msgid "Print information about connected peers." msgstr "" #: src/core/gnunet-service-core.c:97 #, c-format msgid "Core service of `%4s' ready.\n" msgstr "" #: src/core/gnunet-service-core_clients.c:370 msgid "# send requests dropped (disconnected)" msgstr "" #: src/core/gnunet-service-core_clients.c:475 msgid "# messages discarded (session disconnected)" msgstr "" #: src/core/gnunet-service-core_clients.c:818 #, c-format msgid "# bytes of messages of type %u received" msgstr "" #: src/core/gnunet-service-core_kx.c:565 msgid "# bytes encrypted" msgstr "" #: src/core/gnunet-service-core_kx.c:617 msgid "# bytes decrypted" msgstr "" #: src/core/gnunet-service-core_kx.c:681 src/dv/gnunet-service-dv.c:3003 msgid "Error in communication with PEERINFO service\n" msgstr "" #: src/core/gnunet-service-core_kx.c:700 msgid "# Delayed connecting due to lack of public key" msgstr "" #: src/core/gnunet-service-core_kx.c:753 msgid "# key exchanges initiated" msgstr "" #: src/core/gnunet-service-core_kx.c:775 msgid "# key exchanges stopped" msgstr "" #: src/core/gnunet-service-core_kx.c:828 msgid "# session keys received" msgstr "" #: src/core/gnunet-service-core_kx.c:845 #, c-format msgid "`%s' is for `%s', not for me. Ignoring.\n" msgstr "" #: src/core/gnunet-service-core_kx.c:890 msgid "# SET_KEY messages decrypted" msgstr "" #: src/core/gnunet-service-core_kx.c:977 #: src/transport/gnunet-service-transport_validation.c:810 msgid "# PING messages received" msgstr "" #: src/core/gnunet-service-core_kx.c:1010 #, c-format msgid "" "Received PING from `%s' for different identity: I am `%s', PONG identity: `" "%s'\n" msgstr "" #: src/core/gnunet-service-core_kx.c:1029 msgid "# PONG messages created" msgstr "" #: src/core/gnunet-service-core_kx.c:1125 msgid "# sessions terminated by timeout" msgstr "" #: src/core/gnunet-service-core_kx.c:1135 msgid "# keepalive messages sent" msgstr "" #: src/core/gnunet-service-core_kx.c:1236 #: src/transport/gnunet-service-transport_validation.c:1031 msgid "# PONG messages received" msgstr "" #: src/core/gnunet-service-core_kx.c:1275 msgid "# PONG messages decrypted" msgstr "" #: src/core/gnunet-service-core_kx.c:1303 msgid "# session keys confirmed via PONG" msgstr "" #: src/core/gnunet-service-core_kx.c:1329 msgid "# rekey operations confirmed via PONG" msgstr "" #: src/core/gnunet-service-core_kx.c:1381 #: src/core/gnunet-service-core_kx.c:1398 msgid "# SET_KEY and PING messages created" msgstr "" #: src/core/gnunet-service-core_kx.c:1402 msgid "# REKEY operations performed" msgstr "" #: src/core/gnunet-service-core_kx.c:1537 msgid "# failed to decrypt message (no session key)" msgstr "" #: src/core/gnunet-service-core_kx.c:1577 #: src/core/gnunet-service-core_kx.c:1602 msgid "# bytes dropped (duplicates)" msgstr "" #: src/core/gnunet-service-core_kx.c:1589 msgid "# bytes dropped (out of sequence)" msgstr "" #: src/core/gnunet-service-core_kx.c:1626 #, c-format msgid "Message received far too old (%llu ms). Content ignored.\n" msgstr "" #: src/core/gnunet-service-core_kx.c:1630 msgid "# bytes dropped (ancient message)" msgstr "" #: src/core/gnunet-service-core_kx.c:1638 msgid "# bytes of payload decrypted" msgstr "" #: src/core/gnunet-service-core_kx.c:1700 msgid "Core service is lacking HOSTKEY configuration setting. Exiting.\n" msgstr "" #: src/core/gnunet-service-core_kx.c:1708 msgid "Core service could not access hostkey. Exiting.\n" msgstr "" #: src/core/gnunet-service-core_kx.c:1718 src/hostlist/hostlist-server.c:551 #: src/peerinfo-tool/gnunet-peerinfo.c:823 #: src/transport/gnunet-service-transport.c:611 msgid "Could not access PEERINFO service. Exiting.\n" msgstr "" #: src/core/gnunet-service-core_neighbours.c:163 msgid "# sessions terminated by transport disconnect" msgstr "" #: src/core/gnunet-service-core_neighbours.c:180 #: src/core/gnunet-service-core_neighbours.c:334 msgid "# neighbour entries allocated" msgstr "" #: src/core/gnunet-service-core_neighbours.c:247 msgid "# encrypted bytes given to transport" msgstr "" #: src/core/gnunet-service-core_neighbours.c:418 #, c-format msgid "Unsupported message of type %u (%u bytes) received from peer `%s'\n" msgstr "" #: src/core/gnunet-service-core_sessions.c:206 #: src/core/gnunet-service-core_sessions.c:269 #: src/dht/gnunet-service-dht_neighbours.c:625 #: src/dht/gnunet-service-dht_neighbours.c:683 #: src/fs/gnunet-service-fs_cp.c:615 src/fs/gnunet-service-fs_cp.c:1532 #: src/topology/gnunet-daemon-topology.c:709 #: src/topology/gnunet-daemon-topology.c:810 #: src/transport/gnunet-service-transport_neighbours.c:874 #: src/transport/gnunet-service-transport_neighbours.c:1080 #: src/transport/gnunet-service-transport_neighbours.c:1089 #: src/transport/gnunet-service-transport_neighbours.c:2568 #: src/transport/gnunet-service-transport_neighbours.c:2814 msgid "# peers connected" msgstr "" #: src/core/gnunet-service-core_sessions.c:236 msgid "# type map refreshes sent" msgstr "" #: src/core/gnunet-service-core_sessions.c:406 msgid "# messages discarded (expired prior to transmission)" msgstr "" #: src/core/gnunet-service-core_typemap.c:110 #: src/core/gnunet-service-core_typemap.c:121 msgid "# type maps received" msgstr "" #: src/core/gnunet-service-core_typemap.c:151 msgid "# updates to my type map" msgstr "" #: src/datacache/datacache.c:115 src/datacache/datacache.c:250 #: src/datastore/gnunet-service-datastore.c:834 msgid "# bytes stored" msgstr "" #: src/datacache/datacache.c:141 src/datacache/datacache.c:148 #: src/datastore/gnunet-service-datastore.c:1483 #: src/datastore/gnunet-service-datastore.c:1494 #, c-format msgid "No `%s' specified for `%s' in configuration!\n" msgstr "" #: src/datacache/datacache.c:180 #, c-format msgid "Loading `%s' datacache plugin\n" msgstr "" #: src/datacache/datacache.c:188 #, c-format msgid "Failed to load datacache plugin for `%s'\n" msgstr "" #: src/datacache/datacache.c:276 msgid "# requests received" msgstr "" #: src/datacache/datacache.c:284 msgid "# requests filtered by bloom filter" msgstr "" #: src/datacache/plugin_datacache_mysql.c:97 #: src/datacache/plugin_datacache_mysql.c:104 #: src/datacache/plugin_datacache_sqlite.c:69 #: src/datacache/plugin_datacache_sqlite.c:72 #: src/datastore/plugin_datastore_mysql.c:803 #: src/datastore/plugin_datastore_mysql.c:817 #: src/datastore/plugin_datastore_sqlite.c:57 src/mysql/mysql.c:41 #: src/mysql/mysql.c:48 src/mysql/mysql.c:522 src/mysql/mysql.c:531 #: src/mysql/mysql.c:591 src/mysql/mysql.c:607 #: src/namestore/plugin_namestore_sqlite.c:51 src/util/crypto_ksk.c:49 #: src/util/crypto_rsa.c:67 src/include/gnunet_common.h:525 #: src/include/gnunet_common.h:532 #, c-format msgid "`%s' failed at %s:%d with error: %s\n" msgstr "" #: src/datacache/plugin_datacache_mysql.c:450 msgid "MySQL datacache running\n" msgstr "" #: src/datacache/plugin_datacache_postgres.c:367 msgid "Postgres datacache running\n" msgstr "" #: src/datacache/plugin_datacache_sqlite.c:410 msgid "Sqlite datacache running\n" msgstr "" #: src/datacache/plugin_datacache_sqlite.c:443 #: src/datastore/plugin_datastore_sqlite.c:408 #: src/namestore/plugin_namestore_sqlite.c:370 msgid "Tried to close sqlite without finalizing all prepared statements.\n" msgstr "" #: src/datacache/plugin_datacache_sqlite.c:450 #, c-format msgid "Failed to close statement %p: %d\n" msgstr "" #: src/datacache/plugin_datacache_template.c:121 msgid "Template datacache running\n" msgstr "" #: src/datastore/datastore_api.c:305 msgid "Failed to transmit request to drop database.\n" msgstr "" #: src/datastore/datastore_api.c:388 msgid "# queue entry timeouts" msgstr "" #: src/datastore/datastore_api.c:432 msgid "# queue overflows" msgstr "" #: src/datastore/datastore_api.c:459 msgid "# queue entries created" msgstr "" #: src/datastore/datastore_api.c:477 msgid "# Requests dropped from datastore queue" msgstr "" #: src/datastore/datastore_api.c:525 msgid "# datastore connections (re)created" msgstr "" #: src/datastore/datastore_api.c:548 msgid "# reconnected to DATASTORE" msgstr "" #: src/datastore/datastore_api.c:612 msgid "# transmission request failures" msgstr "" #: src/datastore/datastore_api.c:633 msgid "# bytes sent to datastore" msgstr "" #: src/datastore/datastore_api.c:764 msgid "Failed to receive status response from database." msgstr "" #: src/datastore/datastore_api.c:778 msgid "Error reading response from datastore service" msgstr "" #: src/datastore/datastore_api.c:790 src/datastore/datastore_api.c:796 msgid "Invalid error message received from datastore service" msgstr "" #: src/datastore/datastore_api.c:800 msgid "# status messages received" msgstr "" #: src/datastore/datastore_api.c:869 msgid "# PUT requests executed" msgstr "" #: src/datastore/datastore_api.c:936 msgid "# RESERVE requests executed" msgstr "" #: src/datastore/datastore_api.c:997 msgid "# RELEASE RESERVE requests executed" msgstr "" #: src/datastore/datastore_api.c:1054 msgid "# UPDATE requests executed" msgstr "" #: src/datastore/datastore_api.c:1118 msgid "# REMOVE requests executed" msgstr "" #: src/datastore/datastore_api.c:1163 msgid "Failed to receive response from database.\n" msgstr "" #: src/datastore/datastore_api.c:1221 msgid "# Results received" msgstr "" #: src/datastore/datastore_api.c:1286 msgid "# GET REPLICATION requests executed" msgstr "" #: src/datastore/datastore_api.c:1349 msgid "# GET ZERO ANONYMITY requests executed" msgstr "" #: src/datastore/datastore_api.c:1409 msgid "# GET requests executed" msgstr "" #: src/datastore/gnunet-service-datastore.c:349 msgid "# bytes expired" msgstr "" #: src/datastore/gnunet-service-datastore.c:422 msgid "# bytes purged (low-priority)" msgstr "" #: src/datastore/gnunet-service-datastore.c:480 msgid "Transmission to client failed!\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:511 msgid "Shutdown in progress, aborting transmission.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:626 msgid "# results found" msgstr "" #: src/datastore/gnunet-service-datastore.c:669 #, c-format msgid "" "Insufficient space (%llu bytes are available) to satisfy `%s' request for " "%llu bytes\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:680 #, c-format msgid "" "The requested amount (%llu bytes) is larger than the cache size (%llu " "bytes)\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:684 msgid "" "Insufficient space to satisfy request and requested amount is larger than " "cache size" msgstr "" #: src/datastore/gnunet-service-datastore.c:690 msgid "Insufficient space to satisfy request" msgstr "" #: src/datastore/gnunet-service-datastore.c:695 #: src/datastore/gnunet-service-datastore.c:747 #: src/datastore/gnunet-service-datastore.c:960 #: src/datastore/gnunet-service-datastore.c:1417 msgid "# reserved" msgstr "" #: src/datastore/gnunet-service-datastore.c:760 msgid "Could not find matching reservation" msgstr "" #: src/datastore/gnunet-service-datastore.c:846 #, c-format msgid "Need %llu bytes more space (%llu allowed, using %llu)\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1006 msgid "# GET requests received" msgstr "" #: src/datastore/gnunet-service-datastore.c:1018 msgid "# requests filtered by bloomfilter" msgstr "" #: src/datastore/gnunet-service-datastore.c:1046 msgid "# UPDATE requests received" msgstr "" #: src/datastore/gnunet-service-datastore.c:1076 msgid "# GET REPLICATION requests received" msgstr "" #: src/datastore/gnunet-service-datastore.c:1109 msgid "# GET ZERO ANONYMITY requests received" msgstr "" #: src/datastore/gnunet-service-datastore.c:1134 msgid "Content not found" msgstr "" #: src/datastore/gnunet-service-datastore.c:1142 msgid "# bytes removed (explicit request)" msgstr "" #: src/datastore/gnunet-service-datastore.c:1174 msgid "# REMOVE requests received" msgstr "" #: src/datastore/gnunet-service-datastore.c:1216 #, c-format msgid "Datastore payload inaccurate (%lld < %lld). Trying to fix.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1277 #, c-format msgid "Loading `%s' datastore plugin\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1286 #, c-format msgid "Failed to load datastore plugin for `%s'\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1488 #, c-format msgid "# bytes used in file-sharing datastore `%s'" msgstr "" #: src/datastore/gnunet-service-datastore.c:1499 msgid "# quota" msgstr "" #: src/datastore/gnunet-service-datastore.c:1501 msgid "# cache size" msgstr "" #: src/datastore/gnunet-service-datastore.c:1514 #, c-format msgid "Could not use specified filename `%s' for bloomfilter.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1532 #: src/datastore/gnunet-service-datastore.c:1548 #, c-format msgid "Failed to remove bogus bloomfilter file `%s'\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1578 msgid "Failed to initialize bloomfilter.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1607 msgid "Rebuilding bloomfilter. Please be patient.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1612 msgid "Plugin does not support get_keys function. Please fix!\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1615 msgid "Bloomfilter construction complete.\n" msgstr "" #: src/datastore/plugin_datastore_mysql.c:780 #, c-format msgid "Failed to prepare statement `%s'\n" msgstr "" #: src/datastore/plugin_datastore_mysql.c:788 #, c-format msgid "`%s' for `%s' failed at %s:%d with error: %s\n" msgstr "" #: src/datastore/plugin_datastore_mysql.c:1019 msgid "Mysql database running\n" msgstr "" #: src/datastore/plugin_datastore_postgres.c:824 msgid "Failed to drop table from database.\n" msgstr "" #: src/datastore/plugin_datastore_postgres.c:860 msgid "Postgres database running\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:57 #, c-format msgid "`%s' failed at %s:%u with error: %s" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:233 #: src/namestore/plugin_namestore_sqlite.c:204 #, c-format msgid "Option `%s' in section `%s' missing in configuration!\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:260 #: src/namestore/plugin_namestore_sqlite.c:229 #, c-format msgid "Unable to initialize SQLite: %s.\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:655 msgid "Invalid data in database. Trying to fix (by deletion).\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:1139 msgid "sqlite version to old to determine size, assuming zero\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:1158 #, c-format msgid "" "Using sqlite page utilization to estimate payload (%llu pages of size %llu " "bytes)\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:1198 #: src/namestore/plugin_namestore_sqlite.c:829 msgid "Sqlite database running\n" msgstr "" #: src/datastore/plugin_datastore_template.c:241 msgid "Template database running\n" msgstr "" #: src/dht/dht_api.c:348 msgid "Failed to connect to the DHT service!\n" msgstr "" #: src/dht/gnunet-dht-get.c:201 src/dht/gnunet-dht-monitor.c:293 #: src/dht/gnunet-dht-put.c:192 msgid "the query key" msgstr "" #: src/dht/gnunet-dht-get.c:204 msgid "how many parallel requests (replicas) to create" msgstr "" #: src/dht/gnunet-dht-get.c:207 src/dht/gnunet-dht-monitor.c:296 msgid "the type of data to look for" msgstr "" #: src/dht/gnunet-dht-get.c:210 src/dht/gnunet-dht-put.c:201 msgid "how long to execute this query before giving up?" msgstr "" #: src/dht/gnunet-dht-get.c:213 src/dht/gnunet-dht-monitor.c:302 #: src/dht/gnunet-dht-put.c:204 src/fs/gnunet-download.c:271 #: src/fs/gnunet-publish.c:731 src/fs/gnunet-search.c:297 #: src/fs/gnunet-unindex.c:169 src/nse/gnunet-nse-profiler.c:910 msgid "be verbose (print progress information)" msgstr "" #: src/dht/gnunet-dht-get.c:232 msgid "Issue a GET request to the GNUnet DHT, prints results." msgstr "" #: src/dht/gnunet-dht-monitor.c:299 msgid "how long to execute? 0 = forever" msgstr "" #: src/dht/gnunet-dht-monitor.c:321 msgid "Prints all packets that go through the DHT." msgstr "" #: src/dht/gnunet-dht-put.c:108 msgid "PUT request sent!\n" msgstr "" #: src/dht/gnunet-dht-put.c:111 msgid "Timeout sending PUT request!\n" msgstr "" #: src/dht/gnunet-dht-put.c:114 msgid "PUT request not confirmed!\n" msgstr "" #: src/dht/gnunet-dht-put.c:144 msgid "Must provide KEY and DATA for DHT put!\n" msgstr "" #: src/dht/gnunet-dht-put.c:152 #, c-format msgid "Could not connect to %s service!\n" msgstr "" #: src/dht/gnunet-dht-put.c:157 #, c-format msgid "Connected to %s service!\n" msgstr "" #: src/dht/gnunet-dht-put.c:172 #, c-format msgid "Issuing put request for `%s' with data `%s'!\n" msgstr "" #: src/dht/gnunet-dht-put.c:186 msgid "the data to insert under the key" msgstr "" #: src/dht/gnunet-dht-put.c:189 msgid "how long to store this entry in the dht (in seconds)" msgstr "" #: src/dht/gnunet-dht-put.c:195 msgid "how many replicas to create" msgstr "" #: src/dht/gnunet-dht-put.c:198 msgid "the type to insert data as" msgstr "" #: src/dht/gnunet-dht-put.c:223 msgid "Issue a PUT request to the GNUnet DHT insert DATA under KEY." msgstr "" #: src/dht/gnunet-service-dht.c:163 src/testing/testing.c:544 #: src/testing/testing.c:1968 src/testing/testing.c:1998 msgid "Failed to connect to transport service!\n" msgstr "" #: src/dht/gnunet-service-dht_clients.c:407 msgid "# GET requests from clients injected" msgstr "" #: src/dht/gnunet-service-dht_clients.c:500 msgid "# PUT requests received from clients" msgstr "" #: src/dht/gnunet-service-dht_clients.c:584 msgid "# GET requests received from clients" msgstr "" #: src/dht/gnunet-service-dht_clients.c:682 msgid "# GET STOP requests received from clients" msgstr "" #: src/dht/gnunet-service-dht_clients.c:919 msgid "# Key match, type mismatches in REPLY to CLIENT" msgstr "" #: src/dht/gnunet-service-dht_clients.c:932 msgid "# Duplicate REPLIES to CLIENT request dropped" msgstr "" #: src/dht/gnunet-service-dht_clients.c:967 #, c-format msgid "Unsupported block type (%u) in request!\n" msgstr "" #: src/dht/gnunet-service-dht_clients.c:989 msgid "# RESULTS queued for clients" msgstr "" #: src/dht/gnunet-service-dht_clients.c:1038 #: src/dht/gnunet-service-dht_clients.c:1081 msgid "# REPLIES ignored for CLIENTS (no match)" msgstr "" #: src/dht/gnunet-service-dht_clients.c:1048 msgid "Could not pass reply to client, message too big!\n" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:93 #, c-format msgid "%s request received, but have no datacache!\n" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:103 msgid "# ITEMS stored in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:207 msgid "# Good RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:218 msgid "# Duplicate RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:224 msgid "# Invalid RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:236 msgid "# Unsupported RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:239 #, c-format msgid "Unsupported block type (%u) in local response!\n" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:269 msgid "# GET requests given to datacache" msgstr "" #: src/dht/gnunet-service-dht_hello.c:82 msgid "# HELLOs obtained from peerinfo" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:481 msgid "# Preference updates given to core" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:571 msgid "# FIND PEER messages initiated" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:717 msgid "# Queued messages discarded (peer disconnected)" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:772 msgid "# Bytes transmitted to other peers" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:810 msgid "# Bytes of bandwdith requested from core" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1032 #: src/dht/gnunet-service-dht_neighbours.c:1060 msgid "# Peers excluded from routing due to Bloomfilter" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1041 #: src/dht/gnunet-service-dht_neighbours.c:1075 msgid "# Peer selection failed" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1207 msgid "# PUT requests routed" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1236 msgid "# PUT messages queued for transmission" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1315 msgid "# GET requests routed" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1342 msgid "# GET messages queued for transmission" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1443 msgid "# RESULT messages queued for transmission" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1531 msgid "# P2P PUT requests received" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1647 msgid "# FIND PEER requests ignored due to Bloomfilter" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1655 msgid "# FIND PEER requests ignored due to lack of HELLO" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1746 msgid "# P2P GET requests received" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1788 msgid "# P2P FIND PEER requests processed" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1802 msgid "# P2P GET requests ONLY routed" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1876 msgid "# P2P RESULTS received" msgstr "" #: src/dht/gnunet-service-dht_nse.c:59 msgid "# Network size estimates received" msgstr "" #: src/dht/gnunet-service-dht_routing.c:211 msgid "# Good REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:220 msgid "# Duplicate REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:226 msgid "# Invalid REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:238 msgid "# Unsupported REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:311 msgid "# Entries removed from routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:352 msgid "# Entries added to routing table" msgstr "" #: src/dht/plugin_block_dht.c:136 #, c-format msgid "Block not of type %u\n" msgstr "" #: src/dht/plugin_block_dht.c:143 msgid "Size mismatch for block\n" msgstr "" #: src/dht/plugin_block_dht.c:152 #, c-format msgid "Block of type %u is malformed\n" msgstr "" #: src/dns/gnunet-dns-monitor.c:337 msgid "only monitor DNS queries" msgstr "" #: src/dns/gnunet-dns-monitor.c:340 msgid "only monitor DNS replies" msgstr "" #: src/dns/gnunet-dns-monitor.c:348 msgid "Monitor DNS queries." msgstr "" #: src/dns/gnunet-dns-redirector.c:236 msgid "set A records" msgstr "" #: src/dns/gnunet-dns-redirector.c:239 msgid "set AAAA records" msgstr "" #: src/dns/gnunet-dns-redirector.c:247 msgid "Change DNS replies to point elsewhere." msgstr "" #: src/dns/gnunet-service-dns.c:485 #, c-format msgid "Could not bind to any port: %s\n" msgstr "" #: src/dns/gnunet-service-dns.c:639 msgid "# DNS requests answered via TUN interface" msgstr "" #: src/dns/gnunet-service-dns.c:822 msgid "# DNS exit failed (failed to open socket)" msgstr "" #: src/dns/gnunet-service-dns.c:1005 #, c-format msgid "Received DNS response that is too small (%u bytes)" msgstr "" #: src/dns/gnunet-service-dns.c:1050 msgid "# External DNS response discarded (no matching request)" msgstr "" #: src/dns/gnunet-service-dns.c:1168 msgid "# Client response discarded (no matching request)" msgstr "" #: src/dns/gnunet-service-dns.c:1281 msgid "Received malformed IPv4-UDP packet on TUN interface.\n" msgstr "" #: src/dns/gnunet-service-dns.c:1297 msgid "Received malformed IPv6-UDP packet on TUN interface.\n" msgstr "" #: src/dns/gnunet-service-dns.c:1306 #, c-format msgid "Got non-IP packet with %u bytes and protocol %u from TUN\n" msgstr "" #: src/dns/gnunet-service-dns.c:1315 msgid "# Non-DNS UDP packet received via TUN interface" msgstr "" #: src/dns/gnunet-service-dns.c:1380 msgid "# DNS requests received via TUN interface" msgstr "" #: src/dns/gnunet-service-dns.c:1465 #, c-format msgid "Configured DNS exit `%s' is not working / valid.\n" msgstr "" #: src/dns/gnunet-service-dns.c:1497 src/exit/gnunet-daemon-exit.c:2674 msgid "# Inbound MESH tunnels created" msgstr "" #: src/dns/gnunet-service-dns.c:1561 src/exit/gnunet-daemon-exit.c:3032 #, c-format msgid "`%s' must be installed SUID, refusing to run\n" msgstr "" #: src/dns/gnunet-service-dns.c:1581 msgid "Configured to provide DNS exit, but no valid DNS server configured!\n" msgstr "" #: src/dv/dv_api.c:179 msgid "Failed to connect to the dv service!\n" msgstr "" #: src/dv/plugin_transport_dv.c:159 #, c-format msgid "%s Received message from %s of type %d, distance %u!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:508 #, c-format msgid "Got duplicate service records for `%s:%u'\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:563 msgid "# Bytes transmitted via mesh tunnels" msgstr "" #: src/exit/gnunet-daemon-exit.c:679 src/exit/gnunet-daemon-exit.c:2069 #: src/exit/gnunet-daemon-exit.c:2319 src/vpn/gnunet-service-vpn.c:1394 #: src/vpn/gnunet-service-vpn.c:1795 src/vpn/gnunet-service-vpn.c:1958 msgid "# ICMPv4 packets dropped (type not allowed)" msgstr "" #: src/exit/gnunet-daemon-exit.c:716 src/exit/gnunet-daemon-exit.c:2128 #: src/exit/gnunet-daemon-exit.c:2378 src/vpn/gnunet-service-vpn.c:1450 #: src/vpn/gnunet-service-vpn.c:1854 src/vpn/gnunet-service-vpn.c:1991 msgid "# ICMPv6 packets dropped (type not allowed)" msgstr "" #: src/exit/gnunet-daemon-exit.c:756 msgid "# ICMP packets dropped (not allowed)" msgstr "" #: src/exit/gnunet-daemon-exit.c:763 msgid "ICMP Packet dropped, have no matching connection information\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:840 msgid "UDP Packet dropped, have no matching connection information\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:915 msgid "TCP Packet dropped, have no matching connection information\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:968 msgid "# Packets received from TUN" msgstr "" #: src/exit/gnunet-daemon-exit.c:982 msgid "# Bytes received from TUN" msgstr "" #: src/exit/gnunet-daemon-exit.c:1008 msgid "IPv4 packet options received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1035 #, c-format msgid "IPv4 packet with unsupported next header %u received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1081 #, c-format msgid "IPv6 packet with unsupported next header %d received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1089 #, c-format msgid "Packet from unknown protocol %u received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1471 msgid "# TCP packets sent via TUN" msgstr "" #: src/exit/gnunet-daemon-exit.c:1571 msgid "# TCP service creation requests received via mesh" msgstr "" #: src/exit/gnunet-daemon-exit.c:1574 src/exit/gnunet-daemon-exit.c:1653 #: src/exit/gnunet-daemon-exit.c:1763 src/exit/gnunet-daemon-exit.c:1993 #: src/exit/gnunet-daemon-exit.c:2235 src/exit/gnunet-daemon-exit.c:2516 #: src/exit/gnunet-daemon-exit.c:2616 msgid "# Bytes received from MESH" msgstr "" #: src/exit/gnunet-daemon-exit.c:1607 src/exit/gnunet-daemon-exit.c:2638 #, c-format msgid "No service found for %s on port %d!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1611 msgid "# TCP requests dropped (no such service)" msgstr "" #: src/exit/gnunet-daemon-exit.c:1656 msgid "# TCP IP-exit creation requests received via mesh" msgstr "" #: src/exit/gnunet-daemon-exit.c:1766 msgid "# TCP data requests received via mesh" msgstr "" #: src/exit/gnunet-daemon-exit.c:1780 msgid "# TCP DATA requests dropped (no session)" msgstr "" #: src/exit/gnunet-daemon-exit.c:1830 msgid "# ICMP packets sent via TUN" msgstr "" #: src/exit/gnunet-daemon-exit.c:1996 msgid "# ICMP IP-exit requests received via mesh" msgstr "" #: src/exit/gnunet-daemon-exit.c:2238 msgid "# ICMP service requests received via mesh" msgstr "" #: src/exit/gnunet-daemon-exit.c:2304 src/vpn/gnunet-service-vpn.c:1384 #: src/vpn/gnunet-service-vpn.c:1952 msgid "# ICMPv4 packets dropped (impossible PT to v6)" msgstr "" #: src/exit/gnunet-daemon-exit.c:2363 src/vpn/gnunet-service-vpn.c:1420 #: src/vpn/gnunet-service-vpn.c:1432 src/vpn/gnunet-service-vpn.c:1842 msgid "# ICMPv6 packets dropped (impossible PT to v4)" msgstr "" #: src/exit/gnunet-daemon-exit.c:2413 msgid "# UDP packets sent via TUN" msgstr "" #: src/exit/gnunet-daemon-exit.c:2519 msgid "# UDP IP-exit requests received via mesh" msgstr "" #: src/exit/gnunet-daemon-exit.c:2619 msgid "# UDP service requests received via mesh" msgstr "" #: src/exit/gnunet-daemon-exit.c:2642 msgid "# UDP requests dropped (no such service)" msgstr "" #: src/exit/gnunet-daemon-exit.c:2882 #, c-format msgid "No addresses found for hostname `%s' of service `%s'!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:2896 src/exit/gnunet-daemon-exit.c:2908 #, c-format msgid "Service `%s' configured for IPv4, but IPv4 is disabled!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:2919 #, c-format msgid "No IP addresses found for hostname `%s' of service `%s'!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3048 msgid "" "This system does not support IPv4, will disable IPv4 functions despite them " "being enabled in the configuration\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3056 msgid "" "This system does not support IPv6, will disable IPv6 functions despite them " "being enabled in the configuration\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3063 msgid "" "Cannot enable IPv4 exit but disable IPv4 on TUN interface, will use " "ENABLE_IPv4=YES\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3069 msgid "" "Cannot enable IPv6 exit but disable IPv6 on TUN interface, will use " "ENABLE_IPv6=YES\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3075 src/pt/gnunet-daemon-pt.c:884 msgid "No useful service enabled. Exiting.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3236 msgid "Daemon to run to provide an IP exit node for the VPN" msgstr "" #: src/fragmentation/defragmentation.c:270 msgid "# acknowledgements sent for fragment" msgstr "" #: src/fragmentation/defragmentation.c:456 msgid "# fragments received" msgstr "" #: src/fragmentation/defragmentation.c:521 msgid "# duplicate fragments received" msgstr "" #: src/fragmentation/defragmentation.c:534 msgid "# messages defragmented" msgstr "" #: src/fragmentation/fragmentation.c:203 msgid "# fragments transmitted" msgstr "" #: src/fragmentation/fragmentation.c:206 msgid "# fragments retransmitted" msgstr "" #: src/fragmentation/fragmentation.c:232 msgid "# fragments wrap arounds" msgstr "" #: src/fragmentation/fragmentation.c:273 msgid "# messages fragmented" msgstr "" #: src/fragmentation/fragmentation.c:276 msgid "# total size of fragmented messages" msgstr "" #: src/fragmentation/fragmentation.c:363 msgid "# fragment acknowledgements received" msgstr "" #: src/fragmentation/fragmentation.c:369 msgid "# bits removed from fragmentation ACKs" msgstr "" #: src/fragmentation/fragmentation.c:393 msgid "# fragmentation transmissions completed" msgstr "" #: src/fs/fs_api.c:339 #, c-format msgid "Could not open file `%s': %s" msgstr "" #: src/fs/fs_api.c:348 #, c-format msgid "Could not read file `%s': %s" msgstr "" #: src/fs/fs_api.c:354 #, c-format msgid "Short read reading from file `%s'!" msgstr "" #: src/fs/fs_api.c:938 #, c-format msgid "Failed to resume publishing information `%s': %s\n" msgstr "" #: src/fs/fs_api.c:1395 #, c-format msgid "Failed to recover namespace `%s', cannot resume publishing operation.\n" msgstr "" #: src/fs/fs_api.c:1437 #, c-format msgid "Failure while resuming publishing operation `%s': %s\n" msgstr "" #: src/fs/fs_api.c:1453 #, c-format msgid "Failed to resume publishing operation `%s': %s\n" msgstr "" #: src/fs/fs_api.c:2106 #, c-format msgid "Failure while resuming unindexing operation `%s': %s\n" msgstr "" #: src/fs/fs_api.c:2116 #, c-format msgid "Failed to resume unindexing operation `%s': %s\n" msgstr "" #: src/fs/fs_api.c:2241 src/fs/fs_api.c:2480 #, c-format msgid "Failed to resume sub-download `%s': %s\n" msgstr "" #: src/fs/fs_api.c:2258 #, c-format msgid "Failed to resume sub-search `%s': %s\n" msgstr "" #: src/fs/fs_api.c:2270 src/fs/fs_api.c:2289 src/fs/fs_api.c:2773 #, c-format msgid "Failure while resuming search operation `%s': %s\n" msgstr "" #: src/fs/fs_api.c:2471 #, c-format msgid "Failed to resume sub-download `%s': could not open file `%s'\n" msgstr "" #: src/fs/fs_api.c:2717 msgid "Could not resume running search, will resume as paused search\n" msgstr "" #: src/fs/fs_api.c:2811 #, c-format msgid "Failure while resuming download operation `%s': %s\n" msgstr "" #: src/fs/fs_directory.c:210 msgid "MAGIC mismatch. This is not a GNUnet directory.\n" msgstr "" #: src/fs/fs_download.c:311 msgid "" "Recursive downloads of directories larger than 4 GB are not supported on 32-" "bit systems\n" msgstr "" #: src/fs/fs_download.c:331 msgid "Directory too large for system address space\n" msgstr "" #: src/fs/fs_download.c:497 src/fs/fs_download.c:509 #, c-format msgid "Failed to open file `%s' for writing" msgstr "" #: src/fs/fs_download.c:878 #, c-format msgid "Failed to create directory for recursive download of `%s'\n" msgstr "" #: src/fs/fs_download.c:960 #, c-format msgid "" "Internal error or bogus download URI (expected %u bytes at depth %u and " "offset %llu/%llu, got %u bytes)" msgstr "" #: src/fs/fs_download.c:986 msgid "internal error decrypting content" msgstr "" #: src/fs/fs_download.c:1009 #, c-format msgid "Download failed: could not open file `%s': %s" msgstr "" #: src/fs/fs_download.c:1019 #, c-format msgid "Failed to seek to offset %llu in file `%s': %s" msgstr "" #: src/fs/fs_download.c:1028 #, c-format msgid "Failed to write block of %u bytes at offset %llu in file `%s': %s" msgstr "" #: src/fs/fs_download.c:1125 msgid "internal error decoding tree" msgstr "" #: src/fs/fs_download.c:1888 msgid "Invalid URI" msgstr "" #: src/fs/fs_getopt.c:191 #, c-format msgid "" "Unknown metadata type in metadata option `%s'. Using metadata type " "`unknown' instead.\n" msgstr "" #: src/fs/fs_list_indexed.c:90 #, c-format msgid "Failed to receive response for `%s' request from `%s' service.\n" msgstr "" #: src/fs/fs_list_indexed.c:113 #, c-format msgid "Failed to receive valid response for `%s' request from `%s' service.\n" msgstr "" #: src/fs/fs_list_indexed.c:151 #, c-format msgid "Failed to not connect to `%s' service.\n" msgstr "" #: src/fs/fs_misc.c:126 #, c-format msgid "Did not find mime type `%s' in extension list.\n" msgstr "" #: src/fs/fs_namespace_advertise.c:150 msgid "Unknown error" msgstr "" #: src/fs/fs_namespace_advertise.c:238 src/fs/fs_namespace_advertise.c:259 msgid "Failed to serialize meta data" msgstr "" #: src/fs/fs_namespace_advertise.c:278 msgid "Failed to connect to datastore service" msgstr "" #: src/fs/fs_namespace.c:57 src/fs/fs_namespace.c:83 #, c-format msgid "Configuration fails to specify `%s' in section `%s'\n" msgstr "" #: src/fs/fs_namespace.c:112 #, c-format msgid "Failed to open `%s' for writing: %s\n" msgstr "" #: src/fs/fs_namespace.c:134 src/fs/fs_namespace.c:222 #, c-format msgid "Failed to write `%s': %s\n" msgstr "" #: src/fs/fs_namespace.c:256 #, c-format msgid "Failed to create or read private key for namespace `%s'\n" msgstr "" #: src/fs/fs_namespace.c:371 #, c-format msgid "Failed to read namespace private key file `%s', deleting it!\n" msgstr "" #: src/fs/fs_namespace.c:588 src/fs/fs_publish_ksk.c:295 msgid "Internal error." msgstr "" #: src/fs/fs_namespace.c:631 msgid "Failed to connect to datastore." msgstr "" #: src/fs/fs_publish.c:129 src/fs/fs_publish.c:397 #, c-format msgid "Publishing failed: %s" msgstr "" #: src/fs/fs_publish.c:621 src/fs/fs_publish.c:638 src/fs/fs_publish.c:677 #: src/fs/fs_publish.c:697 src/fs/fs_publish.c:722 src/fs/fs_publish.c:862 #, c-format msgid "Can not index file `%s': %s. Will try to insert instead.\n" msgstr "" #: src/fs/fs_publish.c:623 msgid "timeout on index-start request to `fs' service" msgstr "" #: src/fs/fs_publish.c:635 msgid "unknown error" msgstr "" #: src/fs/fs_publish.c:678 msgid "failed to compute hash" msgstr "" #: src/fs/fs_publish.c:698 msgid "filename too long" msgstr "" #: src/fs/fs_publish.c:723 msgid "could not connect to `fs' service" msgstr "" #: src/fs/fs_publish.c:746 #, c-format msgid "Failed to get file identifiers for `%s'\n" msgstr "" #: src/fs/fs_publish.c:811 #, c-format msgid "Recursive upload failed at `%s': %s" msgstr "" #: src/fs/fs_publish.c:817 #, c-format msgid "Recursive upload failed: %s" msgstr "" #: src/fs/fs_publish.c:863 msgid "needs to be an actual file" msgstr "" #: src/fs/fs_publish.c:1071 #, c-format msgid "Insufficient space for publishing: %s" msgstr "" #: src/fs/fs_publish.c:1142 #, c-format msgid "Reserving space for %u entries and %llu bytes for publication\n" msgstr "" #: src/fs/fs_publish_ksk.c:258 msgid "Could not connect to datastore." msgstr "" #: src/fs/fs_search.c:829 #, c-format msgid "Got result with unknown block type `%d', ignoring" msgstr "" #: src/fs/fs_test_lib.c:269 #, c-format msgid "Failed to start daemon: %s\n" msgstr "" #: src/fs/fs_unindex.c:58 msgid "Failed to find given position in file" msgstr "" #: src/fs/fs_unindex.c:63 msgid "Failed to read file" msgstr "" #: src/fs/fs_unindex.c:233 msgid "Unexpected time for a response from `fs' service." msgstr "" #: src/fs/fs_unindex.c:241 msgid "Timeout waiting for `fs' service." msgstr "" #: src/fs/fs_unindex.c:249 msgid "Invalid response from `fs' service." msgstr "" #: src/fs/fs_unindex.c:293 msgid "Failed to connect to FS service for unindexing." msgstr "" #: src/fs/fs_unindex.c:344 msgid "Failed to get KSKs from directory scan." msgstr "" #: src/fs/fs_unindex.c:356 #, c-format msgid "Internal error scanning `%s'.\n" msgstr "" #: src/fs/fs_unindex.c:411 #, c-format msgid "Failed to remove KBlock: %s\n" msgstr "" #: src/fs/fs_unindex.c:501 #, c-format msgid "Failed to parse URI `%s' from KBlock!\n" msgstr "" #: src/fs/fs_unindex.c:553 src/fs/fs_unindex.c:618 msgid "Failed to connect to `datastore' service." msgstr "" #: src/fs/fs_unindex.c:631 msgid "Failed to open file for unindexing." msgstr "" #: src/fs/fs_unindex.c:665 msgid "Failed to compute hash of file." msgstr "" #: src/fs/fs_uri.c:220 #, c-format msgid "`%' must be followed by HEX number" msgstr "" #: src/fs/fs_uri.c:279 msgid "Malformed KSK URI (must not begin or end with `+')" msgstr "" #: src/fs/fs_uri.c:297 msgid "`++' not allowed in KSK URI" msgstr "" #: src/fs/fs_uri.c:304 msgid "Quotes not balanced in KSK URI" msgstr "" #: src/fs/fs_uri.c:372 src/fs/fs_uri.c:379 msgid "Malformed SKS URI" msgstr "" #: src/fs/fs_uri.c:423 src/fs/fs_uri.c:438 msgid "Malformed CHK URI" msgstr "" #: src/fs/fs_uri.c:568 src/fs/fs_uri.c:583 src/fs/fs_uri.c:593 #: src/fs/fs_uri.c:621 msgid "SKS URI malformed" msgstr "" #: src/fs/fs_uri.c:603 msgid "SKS URI malformed (could not decode public key)" msgstr "" #: src/fs/fs_uri.c:609 msgid "SKS URI malformed (could not find signature)" msgstr "" #: src/fs/fs_uri.c:615 msgid "SKS URI malformed (could not decode signature)" msgstr "" #: src/fs/fs_uri.c:628 msgid "SKS URI malformed (could not parse expiration time)" msgstr "" #: src/fs/fs_uri.c:640 msgid "SKS URI malformed (signature failed validation)" msgstr "" #: src/fs/fs_uri.c:678 msgid "Unrecognized URI type" msgstr "" #: src/fs/fs_uri.c:903 msgid "Lacking key configuration settings.\n" msgstr "" #: src/fs/fs_uri.c:910 #, c-format msgid "Could not access hostkey file `%s'.\n" msgstr "" #: src/fs/fs_uri.c:1115 src/fs/fs_uri.c:1142 msgid "No keywords specified!\n" msgstr "" #: src/fs/fs_uri.c:1148 msgid "Number of double-quotes not balanced!\n" msgstr "" #: src/fs/gnunet-directory.c:49 #, c-format msgid "\t\n" msgstr "" #: src/fs/gnunet-directory.c:94 #, c-format msgid "Directory `%s' meta data:\n" msgstr "" #: src/fs/gnunet-directory.c:97 #, c-format msgid "Directory `%s' contents:\n" msgstr "" #: src/fs/gnunet-directory.c:132 msgid "You must specify a filename to inspect.\n" msgstr "" #: src/fs/gnunet-directory.c:145 #, c-format msgid "Failed to read directory `%s'\n" msgstr "" #: src/fs/gnunet-directory.c:154 #, c-format msgid "`%s' is not a GNUnet directory\n" msgstr "" #: src/fs/gnunet-directory.c:179 msgid "Display contents of a GNUnet directory" msgstr "" #: src/fs/gnunet-download.c:101 #, c-format msgid "Starting download `%s'.\n" msgstr "" #: src/fs/gnunet-download.c:110 msgid "" msgstr "" #: src/fs/gnunet-download.c:119 #, c-format msgid "" "Downloading `%s' at %llu/%llu (%s remaining, %s/s). Block took %s to " "download\n" msgstr "" #: src/fs/gnunet-download.c:129 #, c-format msgid "Error downloading: %s.\n" msgstr "" #: src/fs/gnunet-download.c:137 #, c-format msgid "Downloading `%s' done (%s/s).\n" msgstr "" #: src/fs/gnunet-download.c:152 src/fs/gnunet-publish.c:190 #: src/fs/gnunet-search.c:190 src/fs/gnunet-unindex.c:109 #, c-format msgid "Unexpected status: %d\n" msgstr "" #: src/fs/gnunet-download.c:177 msgid "You need to specify a URI argument.\n" msgstr "" #: src/fs/gnunet-download.c:183 src/fs/gnunet-publish.c:624 #, c-format msgid "Failed to parse URI: %s\n" msgstr "" #: src/fs/gnunet-download.c:190 msgid "Only CHK or LOC URIs supported.\n" msgstr "" #: src/fs/gnunet-download.c:197 msgid "Target filename must be specified.\n" msgstr "" #: src/fs/gnunet-download.c:211 src/fs/gnunet-publish.c:602 #: src/fs/gnunet-search.c:241 src/fs/gnunet-unindex.c:141 #, c-format msgid "Could not initialize `%s' subsystem.\n" msgstr "" #: src/fs/gnunet-download.c:248 src/fs/gnunet-search.c:285 msgid "set the desired LEVEL of receiver-anonymity" msgstr "" #: src/fs/gnunet-download.c:251 msgid "delete incomplete downloads (when aborted with CTRL-C)" msgstr "" #: src/fs/gnunet-download.c:254 src/fs/gnunet-search.c:288 msgid "only search the local peer (no P2P network search)" msgstr "" #: src/fs/gnunet-download.c:257 msgid "write the file to FILENAME" msgstr "" #: src/fs/gnunet-download.c:261 msgid "set the maximum number of parallel downloads that is allowed" msgstr "" #: src/fs/gnunet-download.c:265 msgid "set the maximum number of parallel requests for blocks that is allowed" msgstr "" #: src/fs/gnunet-download.c:268 msgid "download a GNUnet directory recursively" msgstr "" #: src/fs/gnunet-download.c:278 msgid "" "Download files from GNUnet using a GNUnet CHK or LOC URI (gnunet://fs/" "chk/...)" msgstr "" #: src/fs/gnunet-fs.c:117 msgid "print a list of all indexed files" msgstr "" #: src/fs/gnunet-fs.c:124 msgid "Special file-sharing operations" msgstr "" #: src/fs/gnunet-pseudonym.c:160 src/statistics/gnunet-statistics.c:167 #, c-format msgid "Invalid argument `%s'\n" msgstr "" #: src/fs/gnunet-pseudonym.c:250 src/fs/gnunet-pseudonym.c:257 #: src/fs/gnunet-pseudonym.c:259 #, c-format msgid "Option `%s' ignored\n" msgstr "" #: src/fs/gnunet-pseudonym.c:279 src/fs/gnunet-publish.c:678 msgid "set the desired LEVEL of sender-anonymity" msgstr "" #: src/fs/gnunet-pseudonym.c:282 msgid "create or advertise namespace NAME" msgstr "" #: src/fs/gnunet-pseudonym.c:285 msgid "delete namespace NAME " msgstr "" #: src/fs/gnunet-pseudonym.c:288 msgid "" "add an additional keyword for the advertisment (this option can be specified " "multiple times)" msgstr "" #: src/fs/gnunet-pseudonym.c:292 src/fs/gnunet-publish.c:697 msgid "set the meta-data for the given TYPE to the given VALUE" msgstr "" #: src/fs/gnunet-pseudonym.c:295 msgid "print names of local namespaces" msgstr "" #: src/fs/gnunet-pseudonym.c:298 msgid "use the given PRIORITY for the advertisments" msgstr "" #: src/fs/gnunet-pseudonym.c:301 msgid "do not print names of remote namespaces" msgstr "" #: src/fs/gnunet-pseudonym.c:304 src/fs/gnunet-publish.c:716 msgid "set the desired replication LEVEL" msgstr "" #: src/fs/gnunet-pseudonym.c:307 msgid "specify ID of the root of the namespace" msgstr "" #: src/fs/gnunet-pseudonym.c:310 msgid "change rating of namespace ID by VALUE" msgstr "" #: src/fs/gnunet-pseudonym.c:318 msgid "Manage GNUnet pseudonyms." msgstr "" #: src/fs/gnunet-publish.c:147 #, c-format msgid "Publishing `%s' at %llu/%llu (%s remaining)\n" msgstr "" #: src/fs/gnunet-publish.c:155 #, c-format msgid "Error publishing: %s.\n" msgstr "" #: src/fs/gnunet-publish.c:165 #, c-format msgid "Publishing `%s' done.\n" msgstr "" #: src/fs/gnunet-publish.c:169 #, c-format msgid "URI is `%s'.\n" msgstr "" #: src/fs/gnunet-publish.c:187 msgid "Cleanup after abort complete.\n" msgstr "" #: src/fs/gnunet-publish.c:305 #, c-format msgid "Meta data for file `%s' (%s)\n" msgstr "" #: src/fs/gnunet-publish.c:307 #, c-format msgid "Keywords for file `%s' (%s)\n" msgstr "" #: src/fs/gnunet-publish.c:358 #, c-format msgid "Failed to create namespace `%s'\n" msgstr "" #: src/fs/gnunet-publish.c:433 msgid "Could not publish\n" msgstr "" #: src/fs/gnunet-publish.c:460 msgid "Could not start publishing.\n" msgstr "" #: src/fs/gnunet-publish.c:491 #, c-format msgid "Scanning directory `%s'.\n" msgstr "" #: src/fs/gnunet-publish.c:493 #, c-format msgid "Scanning file `%s'.\n" msgstr "" #: src/fs/gnunet-publish.c:498 #, c-format msgid "There was trouble processing file `%s', skipping it.\n" msgstr "" #: src/fs/gnunet-publish.c:503 msgid "Preprocessing complete.\n" msgstr "" #: src/fs/gnunet-publish.c:507 #, c-format msgid "Extracting meta data from file `%s' complete.\n" msgstr "" #: src/fs/gnunet-publish.c:511 msgid "Meta data extraction has finished.\n" msgstr "" #: src/fs/gnunet-publish.c:518 msgid "Internal error scanning directory.\n" msgstr "" #: src/fs/gnunet-publish.c:552 #, c-format msgid "Cannot extract metadata from a URI!\n" msgstr "" #: src/fs/gnunet-publish.c:559 #, c-format msgid "You must specify one and only one filename for insertion.\n" msgstr "" #: src/fs/gnunet-publish.c:565 #, c-format msgid "You must NOT specify an URI and a filename.\n" msgstr "" #: src/fs/gnunet-publish.c:573 src/vpn/gnunet-vpn.c:214 #, c-format msgid "Option `%s' is required when using option `%s'.\n" msgstr "" #: src/fs/gnunet-publish.c:583 src/fs/gnunet-publish.c:590 #: src/transport/gnunet-transport.c:560 #, c-format msgid "Option `%s' makes no sense without option `%s'.\n" msgstr "" #: src/fs/gnunet-publish.c:612 #, c-format msgid "Could not create namespace `%s'\n" msgstr "" #: src/fs/gnunet-publish.c:645 #, c-format msgid "Failed to access `%s': %s\n" msgstr "" #: src/fs/gnunet-publish.c:657 msgid "" "Failed to start meta directory scanner. Is gnunet-helper-publish-fs " "installed?\n" msgstr "" #: src/fs/gnunet-publish.c:682 msgid "disable adding the creation time to the metadata of the uploaded file" msgstr "" #: src/fs/gnunet-publish.c:685 msgid "do not use libextractor to add keywords or metadata" msgstr "" #: src/fs/gnunet-publish.c:689 msgid "" "print list of extracted keywords that would be used, but do not perform " "upload" msgstr "" #: src/fs/gnunet-publish.c:693 msgid "" "add an additional keyword for the top-level file or directory (this option " "can be specified multiple times)" msgstr "" #: src/fs/gnunet-publish.c:700 msgid "" "do not index, perform full insertion (stores entire file in encrypted form " "in GNUnet database)" msgstr "" #: src/fs/gnunet-publish.c:705 msgid "" "specify ID of an updated version to be published in the future (for " "namespace insertions only)" msgstr "" #: src/fs/gnunet-publish.c:709 msgid "specify the priority of the content" msgstr "" #: src/fs/gnunet-publish.c:713 msgid "publish the files under the pseudonym NAME (place file into namespace)" msgstr "" #: src/fs/gnunet-publish.c:719 msgid "" "only simulate the process but do not do any actual publishing (useful to " "compute URIs)" msgstr "" #: src/fs/gnunet-publish.c:723 msgid "" "set the ID of this version of the publication (for namespace insertions only)" msgstr "" #: src/fs/gnunet-publish.c:727 msgid "" "URI to be published (can be used instead of passing a file to add keywords " "to the file with the respective URI)" msgstr "" #: src/fs/gnunet-publish.c:742 msgid "Publish a file or directory on GNUnet" msgstr "" #: src/fs/gnunet-search.c:111 #, c-format msgid "Failed to write directory with search results to `%s'\n" msgstr "" #: src/fs/gnunet-search.c:181 #, c-format msgid "Error searching: %s.\n" msgstr "" #: src/fs/gnunet-search.c:231 msgid "Could not create keyword URI from arguments.\n" msgstr "" #: src/fs/gnunet-search.c:255 msgid "Could not start searching.\n" msgstr "" #: src/fs/gnunet-search.c:291 msgid "write search results to file starting with PREFIX" msgstr "" #: src/fs/gnunet-search.c:294 msgid "automatically terminate search after VALUE ms" msgstr "" #: src/fs/gnunet-search.c:301 msgid "automatically terminate search after VALUE results are found" msgstr "" #: src/fs/gnunet-search.c:308 msgid "Search GNUnet for files that were published on GNUnet" msgstr "" #: src/fs/gnunet-service-fs.c:240 msgid "# running average P2P latency (ms)" msgstr "" #: src/fs/gnunet-service-fs.c:300 src/fs/gnunet-service-fs.c:489 msgid "# Loopback routes suppressed" msgstr "" #: src/fs/gnunet-service-fs.c:581 src/hostlist/gnunet-daemon-hostlist.c:297 #: src/topology/gnunet-daemon-topology.c:1330 #: src/topology/gnunet-daemon-topology.c:1337 #, c-format msgid "Failed to connect to `%s' service.\n" msgstr "" #: src/fs/gnunet-service-fs_cp.c:696 msgid "# migration stop messages received" msgstr "" #: src/fs/gnunet-service-fs_cp.c:700 #, c-format msgid "Migration of content to peer `%s' blocked for %llu ms\n" msgstr "" #: src/fs/gnunet-service-fs_cp.c:735 msgid "# replies transmitted to other peers" msgstr "" #: src/fs/gnunet-service-fs_cp.c:741 msgid "# replies dropped" msgstr "" #: src/fs/gnunet-service-fs_cp.c:766 src/fs/gnunet-service-fs_cp.c:1324 msgid "# P2P searches active" msgstr "" #: src/fs/gnunet-service-fs_cp.c:858 msgid "# artificial delays introduced (ms)" msgstr "" #: src/fs/gnunet-service-fs_cp.c:911 msgid "# replies dropped due to type mismatch" msgstr "" #: src/fs/gnunet-service-fs_cp.c:919 msgid "# replies received for other peers" msgstr "" #: src/fs/gnunet-service-fs_cp.c:933 msgid "# replies dropped due to insufficient cover traffic" msgstr "" #: src/fs/gnunet-service-fs_cp.c:971 msgid "# P2P searches destroyed due to ultimate reply" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1038 msgid "# requests done for free (low load)" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1062 msgid "# request dropped, priority insufficient" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1072 msgid "# requests done for a price (normal load)" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1151 msgid "# GET requests received (from other peers)" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1185 msgid "# requests dropped due to initiator not being connected" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1207 msgid "# requests dropped due to missing reverse route" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1267 msgid "# requests dropped due TTL underflow" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1293 msgid "# requests dropped due to higher-TTL request" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1322 msgid "# P2P query messages received and processed" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1687 msgid "# migration stop messages sent" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:113 #: src/fs/gnunet-service-fs_indexing.c:163 #, c-format msgid "Configuration option `%s' in section `%s' missing.\n" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:121 #: src/fs/gnunet-service-fs_indexing.c:177 #, c-format msgid "Could not open `%s'.\n" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:137 #, c-format msgid "Error writing `%s'.\n" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:228 #, c-format msgid "" "Index request received for file `%s' is already indexed as `%s'. Permitting " "anyway.\n" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:266 #, c-format msgid "Hash mismatch trying to index file `%s' which has hash `%s'\n" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:481 #, c-format msgid "Failed to delete bogus block: %s\n" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:539 msgid "# index blocks removed: original file inaccessible" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:554 #, c-format msgid "Could not access indexed file `%s' (%s) at offset %llu: %s\n" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:556 msgid "not indexed" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:571 #, c-format msgid "Indexed file `%s' changed at offset %llu\n" msgstr "" #: src/fs/gnunet-service-fs_lc.c:202 src/fs/gnunet-service-fs_lc.c:362 #: src/fs/gnunet-service-fs_lc.c:488 msgid "# client searches active" msgstr "" #: src/fs/gnunet-service-fs_lc.c:256 msgid "# replies received for local clients" msgstr "" #: src/fs/gnunet-service-fs_lc.c:321 msgid "# client searches received" msgstr "" #: src/fs/gnunet-service-fs_lc.c:356 msgid "# client searches updated (merged content seen list)" msgstr "" #: src/fs/gnunet-service-fs_pe.c:265 msgid "# average retransmission delay (ms)" msgstr "" #: src/fs/gnunet-service-fs_pe.c:391 msgid "# transmission failed (core has no bandwidth)" msgstr "" #: src/fs/gnunet-service-fs_pe.c:420 msgid "# query messages sent to other peers" msgstr "" #: src/fs/gnunet-service-fs_pe.c:469 msgid "# delay heap timeout" msgstr "" #: src/fs/gnunet-service-fs_pe.c:476 msgid "# query plans executed" msgstr "" #: src/fs/gnunet-service-fs_pe.c:538 msgid "# requests merged" msgstr "" #: src/fs/gnunet-service-fs_pe.c:544 msgid "# requests refreshed" msgstr "" #: src/fs/gnunet-service-fs_pe.c:597 src/fs/gnunet-service-fs_pe.c:681 #: src/fs/gnunet-service-fs_pe.c:748 msgid "# query plan entries" msgstr "" #: src/fs/gnunet-service-fs_pr.c:285 msgid "# Pending requests created" msgstr "" #: src/fs/gnunet-service-fs_pr.c:367 src/fs/gnunet-service-fs_pr.c:616 msgid "# Pending requests active" msgstr "" #: src/fs/gnunet-service-fs_pr.c:779 msgid "# replies received and matched" msgstr "" #: src/fs/gnunet-service-fs_pr.c:808 msgid "# duplicate replies discarded (bloomfilter)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:822 #, c-format msgid "Unsupported block type %u\n" msgstr "" #: src/fs/gnunet-service-fs_pr.c:835 msgid "# results found locally" msgstr "" #: src/fs/gnunet-service-fs_pr.c:953 msgid "# Datastore `PUT' failures" msgstr "" #: src/fs/gnunet-service-fs_pr.c:980 msgid "# storage requests dropped due to high load" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1015 msgid "# Replies received from DHT" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1106 #, c-format msgid "Datastore lookup already took %llu ms!\n" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1127 #, c-format msgid "On-demand lookup already took %llu ms!\n" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1174 msgid "# Datastore lookups concluded (no results)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1188 msgid "# Datastore lookups concluded (seen all)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1197 msgid "# Datastore lookups aborted (more than MAX_RESULTS)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1211 msgid "# requested DBLOCK or IBLOCK not found" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1224 msgid "# on-demand blocks matched requests" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1237 msgid "# on-demand lookups performed successfully" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1242 msgid "# on-demand lookups failed" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1269 src/fs/gnunet-service-fs_pr.c:1309 #: src/fs/gnunet-service-fs_pr.c:1447 msgid "# Datastore lookups concluded (error queueing)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1327 msgid "# Datastore lookups concluded (found last result)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1338 msgid "# Datastore lookups concluded (load too high)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1424 msgid "# Datastore lookups initiated" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1508 msgid "# GAP PUT messages received" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1601 src/fs/gnunet-service-fs_pr.c:1610 #, c-format msgid "Configuration fails to specify `%s', assuming default value." msgstr "" #: src/fs/gnunet-service-fs_push.c:629 #, c-format msgid "" "Invalid value specified for option `%s' in section `%s', content pushing " "disabled\n" msgstr "" #: src/fs/gnunet-unindex.c:89 #, c-format msgid "Unindexing at %llu/%llu (%s remaining)\n" msgstr "" #: src/fs/gnunet-unindex.c:96 #, c-format msgid "Error unindexing: %s.\n" msgstr "" #: src/fs/gnunet-unindex.c:101 msgid "Unindexing done.\n" msgstr "" #: src/fs/gnunet-unindex.c:131 #, c-format msgid "You must specify one and only one filename for unindexing.\n" msgstr "" #: src/fs/gnunet-unindex.c:148 msgid "Could not start unindex operation.\n" msgstr "" #: src/fs/gnunet-unindex.c:176 msgid "Unindex a file that was previously indexed with gnunet-publish." msgstr "" #: src/fs/plugin_block_fs.c:131 msgid "Reply mismatched in terms of namespace. Discarded.\n" msgstr "" #: src/gns/gnunet-gns.c:191 msgid "Failed to connect to GNS\n" msgstr "" #: src/gns/gnunet-gns.c:232 msgid "try to shorten a given GNS name" msgstr "" #: src/gns/gnunet-gns.c:235 msgid "Lookup a record using GNS (NOT IMPLEMENTED)" msgstr "" #: src/gns/gnunet-gns.c:238 msgid "Get the authority of a particular name" msgstr "" #: src/gns/gnunet-gns.c:241 msgid "Specify the type of the record lookup" msgstr "" #: src/gns/gnunet-gns.c:244 msgid "No unneeded output" msgstr "" #: src/gns/gnunet-gns.c:255 msgid "GNUnet GNS access tool" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:280 #, c-format msgid "Unsupported form value `%s'\n" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:333 #, c-format msgid "Failed to create record for domain `%s': %s\n" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:377 #, c-format msgid "Found existing name `%s' for the given key\n" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:439 #, c-format msgid "Found %u existing records for domain `%s'\n" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:498 #, c-format msgid "Failed to create page for `%s'\n" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:514 #, c-format msgid "Failed to setup post processor for `%s'\n" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:725 src/gns/gnunet-gns-fcfsd.c:737 #, c-format msgid "Option `%s' not specified in configuration section `%s'\n" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:747 src/namestore/gnunet-namestore.c:299 msgid "Failed to read or create private zone key\n" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:757 src/namestore/gnunet-namestore.c:310 msgid "Failed to connect to namestore\n" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:773 src/gns/gnunet-gns-proxy.c:525 msgid "Failed to start HTTP server\n" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:804 msgid "GNUnet GNS first come first serve registration service" msgstr "" #: src/gns/gnunet-gns-proxy.c:800 msgid "listen on specified port" msgstr "" #: src/gns/gnunet-gns-proxy.c:811 msgid "GNUnet GNS proxy" msgstr "" #: src/hello/gnunet-hello.c:122 msgid "Call with name of HELLO file to modify.\n" msgstr "" #: src/hello/gnunet-hello.c:128 #, c-format msgid "Error accessing file `%s': %s\n" msgstr "" #: src/hello/gnunet-hello.c:136 #, c-format msgid "File `%s' is too big to be a HELLO\n" msgstr "" #: src/hello/gnunet-hello.c:143 #, c-format msgid "File `%s' is too small to be a HELLO\n" msgstr "" #: src/hello/gnunet-hello.c:153 src/hello/gnunet-hello.c:181 #, c-format msgid "Error opening file `%s': %s\n" msgstr "" #: src/hello/gnunet-hello.c:169 #, c-format msgid "Did not find well-formed HELLO in file `%s'\n" msgstr "" #: src/hello/gnunet-hello.c:193 #, c-format msgid "Error writing HELLO to file `%s': %s\n" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:264 msgid "" "None of the functions for the hostlist daemon were enabled. I have no " "reason to run!\n" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:317 msgid "advertise our hostlist to other peers" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:322 msgid "" "bootstrap using hostlists (it is highly recommended that you always use this " "option)" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:325 msgid "enable learning about hostlist servers from other peers" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:329 msgid "provide a hostlist server" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:341 msgid "GNUnet hostlist server and client" msgstr "" #: src/hostlist/hostlist-client.c:289 msgid "# bytes downloaded from hostlist servers" msgstr "" #: src/hostlist/hostlist-client.c:310 src/hostlist/hostlist-client.c:340 msgid "# invalid HELLOs downloaded from hostlist servers" msgstr "" #: src/hostlist/hostlist-client.c:313 src/hostlist/hostlist-client.c:343 #, c-format msgid "Invalid `%s' message received from hostlist at `%s'\n" msgstr "" #: src/hostlist/hostlist-client.c:331 msgid "# valid HELLOs downloaded from hostlist servers" msgstr "" #: src/hostlist/hostlist-client.c:375 src/hostlist/hostlist-client.c:396 #, c-format msgid "No `%s' specified in `%s' configuration, will not bootstrap.\n" msgstr "" #: src/hostlist/hostlist-client.c:473 src/hostlist/hostlist-client.c:683 #: src/hostlist/hostlist-client.c:689 src/hostlist/hostlist-client.c:741 #: src/hostlist/hostlist-client.c:750 src/hostlist/hostlist-client.c:871 #: src/hostlist/hostlist-client.c:961 src/hostlist/hostlist-client.c:966 #: src/transport/plugin_transport_http_client.c:110 #: src/transport/plugin_transport_http_client.c:125 #, c-format msgid "%s failed at %s:%d: `%s'\n" msgstr "" #: src/hostlist/hostlist-client.c:593 src/hostlist/hostlist-client.c:1331 msgid "# advertised hostlist URIs" msgstr "" #: src/hostlist/hostlist-client.c:623 #, c-format msgid "# advertised URI `%s' downloaded" msgstr "" #: src/hostlist/hostlist-client.c:664 #, c-format msgid "" "Advertised hostlist with URI `%s' could not be downloaded. Advertised URI " "gets dismissed.\n" msgstr "" #: src/hostlist/hostlist-client.c:802 #, c-format msgid "Timeout trying to download hostlist from `%s'\n" msgstr "" #: src/hostlist/hostlist-client.c:816 #, c-format msgid "Download limit of %u bytes exceeded, stopping download\n" msgstr "" #: src/hostlist/hostlist-client.c:836 #, c-format msgid "Download of hostlist from `%s' failed: `%s'\n" msgstr "" #: src/hostlist/hostlist-client.c:842 #, c-format msgid "Download of hostlist `%s' completed.\n" msgstr "" #: src/hostlist/hostlist-client.c:850 #, c-format msgid "Adding successfully tested hostlist `%s' datastore.\n" msgstr "" #: src/hostlist/hostlist-client.c:903 #, c-format msgid "Bootstrapping using hostlist at `%s'.\n" msgstr "" #: src/hostlist/hostlist-client.c:911 msgid "# hostlist downloads initiated" msgstr "" #: src/hostlist/hostlist-client.c:1037 src/hostlist/hostlist-client.c:1505 msgid "# milliseconds between hostlist downloads" msgstr "" #: src/hostlist/hostlist-client.c:1046 #, c-format msgid "Have %u/%u connections. Will consider downloading hostlist in %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1084 msgid "Scheduled saving of hostlists\n" msgstr "" #: src/hostlist/hostlist-client.c:1088 #, c-format msgid "Hostlists will be saved to file again in %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1111 src/hostlist/hostlist-client.c:1127 msgid "# active connections" msgstr "" #: src/hostlist/hostlist-client.c:1242 #, c-format msgid "Initial time between hostlist downloads is %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1273 #, c-format msgid "" "No `%s' specified in `%s' configuration, cannot load hostlists from file.\n" msgstr "" #: src/hostlist/hostlist-client.c:1279 #, c-format msgid "Loading saved hostlist entries from file `%s' \n" msgstr "" #: src/hostlist/hostlist-client.c:1283 #, c-format msgid "Hostlist file `%s' is not existing\n" msgstr "" #: src/hostlist/hostlist-client.c:1294 #, c-format msgid "Could not open file `%s' for reading to load hostlists: %s\n" msgstr "" #: src/hostlist/hostlist-client.c:1327 #, c-format msgid "%u hostlist URIs loaded from file\n" msgstr "" #: src/hostlist/hostlist-client.c:1329 msgid "# hostlist URIs read from file" msgstr "" #: src/hostlist/hostlist-client.c:1362 #, c-format msgid "" "No `%s' specified in `%s' configuration, cannot save hostlists to file.\n" msgstr "" #: src/hostlist/hostlist-client.c:1376 #, c-format msgid "Could not open file `%s' for writing to save hostlists: %s\n" msgstr "" #: src/hostlist/hostlist-client.c:1381 #, c-format msgid "Writing %u hostlist URIs to `%s'\n" msgstr "" #: src/hostlist/hostlist-client.c:1405 src/hostlist/hostlist-client.c:1422 #, c-format msgid "Error writing hostlist URIs to file `%s'\n" msgstr "" #: src/hostlist/hostlist-client.c:1417 msgid "# hostlist URIs written to file" msgstr "" #: src/hostlist/hostlist-client.c:1470 msgid "Learning is enabled on this peer\n" msgstr "" #: src/hostlist/hostlist-client.c:1473 #, c-format msgid "Hostlists will be saved to file again in %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1482 msgid "Learning is not enabled on this peer\n" msgstr "" #: src/hostlist/hostlist-client.c:1494 #, c-format msgid "" "Since learning is not enabled on this peer, hostlist file `%s' was removed\n" msgstr "" #: src/hostlist/hostlist-client.c:1498 #, c-format msgid "Hostlist file `%s' could not be removed\n" msgstr "" #: src/hostlist/hostlist-server.c:134 msgid "bytes in hostlist" msgstr "" #: src/hostlist/hostlist-server.c:157 msgid "expired addresses encountered" msgstr "" #: src/hostlist/hostlist-server.c:184 src/hostlist/hostlist-server.c:425 #: src/peerinfo-tool/gnunet-peerinfo.c:403 #: src/peerinfo-tool/gnunet-peerinfo.c:519 #: src/topology/gnunet-daemon-topology.c:927 #, c-format msgid "Error in communication with PEERINFO service: %s\n" msgstr "" #: src/hostlist/hostlist-server.c:205 msgid "HELLOs without addresses encountered (ignored)" msgstr "" #: src/hostlist/hostlist-server.c:219 msgid "bytes not included in hostlist (size limit)" msgstr "" #: src/hostlist/hostlist-server.c:263 #, c-format msgid "Refusing `%s' request to hostlist server\n" msgstr "" #: src/hostlist/hostlist-server.c:266 msgid "hostlist requests refused (not HTTP GET)" msgstr "" #: src/hostlist/hostlist-server.c:273 msgid "Sending 100 CONTINUE reply\n" msgstr "" #: src/hostlist/hostlist-server.c:279 #, c-format msgid "Refusing `%s' request with %llu bytes of upload data\n" msgstr "" #: src/hostlist/hostlist-server.c:283 msgid "hostlist requests refused (upload data)" msgstr "" #: src/hostlist/hostlist-server.c:291 msgid "Could not handle hostlist request since I do not have a response yet\n" msgstr "" #: src/hostlist/hostlist-server.c:294 msgid "hostlist requests refused (not ready)" msgstr "" #: src/hostlist/hostlist-server.c:298 msgid "Received request for our hostlist\n" msgstr "" #: src/hostlist/hostlist-server.c:299 msgid "hostlist requests processed" msgstr "" #: src/hostlist/hostlist-server.c:341 msgid "# hostlist advertisements send" msgstr "" #: src/hostlist/hostlist-server.c:388 msgid "Advertisement message could not be queued by core\n" msgstr "" #: src/hostlist/hostlist-server.c:561 #, c-format msgid "Invalid port number %llu. Exiting.\n" msgstr "" #: src/hostlist/hostlist-server.c:570 #, c-format msgid "Hostlist service starts on %s:%llu\n" msgstr "" #: src/hostlist/hostlist-server.c:584 #, c-format msgid "Address to obtain hostlist: `%s'\n" msgstr "" #: src/hostlist/hostlist-server.c:624 #, c-format msgid "`%s' is not a valid IP address! Ignoring BINDTOIP.\n" msgstr "" #: src/hostlist/hostlist-server.c:666 #, c-format msgid "Could not start hostlist HTTP server on port %u\n" msgstr "" #: src/integration-tests/connection_watchdog.c:997 #, c-format msgid "Transport plugin: `%s' port %llu\n" msgstr "" #: src/integration-tests/connection_watchdog.c:1030 #, c-format msgid "Found %u transport plugins: `%s'\n" msgstr "" #: src/integration-tests/connection_watchdog.c:1089 msgid "Send ping messages to test connectivity (default == NO)" msgstr "" #: src/integration-tests/connection_watchdog.c:1095 #: src/template/gnunet-template.c:68 msgid "help text" msgstr "" #: src/mesh/gnunet-service-mesh.c:4590 msgid "Wrong CORE service\n" msgstr "" #: src/mesh/gnunet-service-mesh.c:4784 msgid "Mesh service is lacking key configuration settings. Exiting.\n" msgstr "" #: src/mesh/gnunet-service-mesh.c:4793 msgid "Mesh service could not access hostkey. Exiting.\n" msgstr "" #: src/mysql/mysql.c:174 #, c-format msgid "Trying to use file `%s' for MySQL configuration.\n" msgstr "" #: src/mysql/mysql.c:181 #, c-format msgid "Could not access file `%s': %s\n" msgstr "" #: src/namestore/gnunet-namestore.c:157 #, c-format msgid "Adding record failed: %s\n" msgstr "" #: src/namestore/gnunet-namestore.c:183 #, c-format msgid "Deleting record failed: %s\n" msgstr "" #: src/namestore/gnunet-namestore.c:239 #, c-format msgid "\tCorrupt or unsupported record of type %u\n" msgstr "" #: src/namestore/gnunet-namestore.c:276 #, c-format msgid "Option `%s' not given, but I need a zone key file!\n" msgstr "" #: src/namestore/gnunet-namestore.c:281 #, c-format msgid "Using default zone file `%s'\n" msgstr "" #: src/namestore/gnunet-namestore.c:291 #, c-format msgid "No options given\n" msgstr "" #: src/namestore/gnunet-namestore.c:321 #, c-format msgid "Unsupported type `%s'\n" msgstr "" #: src/namestore/gnunet-namestore.c:328 src/namestore/gnunet-namestore.c:350 #: src/namestore/gnunet-namestore.c:374 src/namestore/gnunet-namestore.c:384 #: src/namestore/gnunet-namestore.c:409 #, c-format msgid "Missing option `%s' for operation `%s'\n" msgstr "" #: src/namestore/gnunet-namestore.c:329 src/namestore/gnunet-namestore.c:351 msgid "add/del" msgstr "" #: src/namestore/gnunet-namestore.c:341 #, c-format msgid "Value `%s' invalid for record type `%s'\n" msgstr "" #: src/namestore/gnunet-namestore.c:366 #, c-format msgid "Invalid time format `%s'\n" msgstr "" #: src/namestore/gnunet-namestore.c:375 src/namestore/gnunet-namestore.c:385 msgid "add" msgstr "" #: src/namestore/gnunet-namestore.c:410 msgid "del" msgstr "" #: src/namestore/gnunet-namestore.c:462 msgid "add record" msgstr "" #: src/namestore/gnunet-namestore.c:465 msgid "delete record" msgstr "" #: src/namestore/gnunet-namestore.c:468 msgid "display records" msgstr "" #: src/namestore/gnunet-namestore.c:471 msgid "" "expiration time for record to use (for adding only), \"never\" is possible" msgstr "" #: src/namestore/gnunet-namestore.c:474 msgid "name of the record to add/delete/display" msgstr "" #: src/namestore/gnunet-namestore.c:477 msgid "type of the record to add/delete/display" msgstr "" #: src/namestore/gnunet-namestore.c:480 msgid "value of the record to add/delete" msgstr "" #: src/namestore/gnunet-namestore.c:483 msgid "create or list public record" msgstr "" #: src/namestore/gnunet-namestore.c:486 msgid "create or list non-authority record" msgstr "" #: src/namestore/gnunet-namestore.c:489 msgid "filename with the zone key" msgstr "" #: src/namestore/gnunet-namestore.c:500 msgid "GNUnet zone manipulation tool" msgstr "" #: src/namestore/gnunet-service-namestore.c:143 #, c-format msgid "File zone `%s' but corrupt content already exists, failed to write! \n" msgstr "" #: src/namestore/gnunet-service-namestore.c:154 #, c-format msgid "File zone `%s' containing this key already exists\n" msgstr "" #: src/namestore/gnunet-service-namestore.c:160 #, c-format msgid "" "File zone `%s' but different zone key already exists, failed to write! \n" msgstr "" #: src/namestore/gnunet-service-namestore.c:198 #, c-format msgid "Stored zonekey for zone `%s' in file `%s'\n" msgstr "" #: src/namestore/gnunet-service-namestore.c:1909 msgid "No directory to load zonefiles specified in configuration\n" msgstr "" #: src/namestore/gnunet-service-namestore.c:1918 #, c-format msgid "Creating directory `%s' for zone files failed!\n" msgstr "" #: src/namestore/namestore_api.c:315 src/namestore/namestore_api.c:353 msgid "Namestore added record successfully" msgstr "" #: src/namestore/namestore_api.c:323 msgid "Namestore failed to add record" msgstr "" #: src/namestore/namestore_api.c:361 msgid "Namestore record already existed" msgstr "" #: src/namestore/namestore_api.c:368 msgid "Namestore failed to add record\n" msgstr "" #: src/namestore/namestore_api.c:401 msgid "Namestore removed record successfully" msgstr "" #: src/namestore/namestore_api.c:408 msgid "No records for entry" msgstr "" #: src/namestore/namestore_api.c:415 msgid "Could not find record to remove" msgstr "" #: src/namestore/namestore_api.c:422 msgid "Failed to create new signature" msgstr "" #: src/namestore/namestore_api.c:429 msgid "Failed to put new set of records in database" msgstr "" #: src/nat/gnunet-nat-server.c:279 #, c-format msgid "Please pass valid port number as the first argument! (got `%s')\n" msgstr "" #: src/nat/gnunet-nat-server.c:318 msgid "GNUnet NAT traversal test helper daemon" msgstr "" #: src/nat/nat.c:799 #, c-format msgid "gnunet-helper-nat-server generated malformed address `%s'\n" msgstr "" #: src/nat/nat.c:844 #, c-format msgid "Failed to start %s\n" msgstr "" #: src/nat/nat.c:1111 #, c-format msgid "Malformed %s `%s' given in configuration!\n" msgstr "" #: src/nat/nat.c:1177 src/nat/nat.c:1187 #, c-format msgid "" "Configuration requires `%s', but binary is not installed properly (SUID bit " "not set). Option disabled.\n" msgstr "" #: src/nat/nat.c:1321 msgid "Internal IP address not known, cannot use ICMP NAT traversal method\n" msgstr "" #: src/nat/nat.c:1332 #, c-format msgid "Running gnunet-helper-nat-client %s %s %u\n" msgstr "" #: src/nat/nat_test.c:341 msgid "Failed to connect to `gnunet-nat-server'\n" msgstr "" #: src/nat/nat_test.c:411 #, c-format msgid "Failed to create listen socket bound to `%s' for NAT test: %s\n" msgstr "" #: src/nse/gnunet-nse-profiler.c:928 msgid "Measure quality and performance of the NSE service." msgstr "" #: src/nse/gnunet-service-nse.c:925 #, c-format msgid "Proof of work invalid: %llu!\n" msgstr "" #: src/nse/gnunet-service-nse.c:1381 src/nse/gnunet-service-nse.c:1400 #: src/nse/gnunet-service-nse.c:1421 msgid "NSE service is lacking key configuration settings. Exiting.\n" msgstr "" #: src/nse/gnunet-service-nse.c:1388 msgid "Invalid work requirement for NSE service. Exiting.\n" msgstr "" #: src/nse/gnunet-service-nse.c:1409 msgid "NSE service could not access hostkey. Exiting.\n" msgstr "" #: src/peerinfo/gnunet-service-peerinfo.c:134 #, c-format msgid "Removing expired address of transport `%s'\n" msgstr "" #: src/peerinfo/gnunet-service-peerinfo.c:203 #, c-format msgid "Failed to parse HELLO in file `%s'\n" msgstr "" #: src/peerinfo/gnunet-service-peerinfo.c:229 msgid "# peers known" msgstr "" #: src/peerinfo/gnunet-service-peerinfo.c:254 #, c-format msgid "" "File `%s' in directory `%s' does not match naming convention. Removed.\n" msgstr "" #: src/peerinfo/gnunet-service-peerinfo.c:353 #, c-format msgid "Still no peers found in `%s'!\n" msgstr "" #: src/peerinfo/gnunet-service-peerinfo.c:710 #, c-format msgid "Importing HELLOs from `%s'\n" msgstr "" #: src/peerinfo/peerinfo_api.c:238 msgid "aborted due to explicit disconnect request" msgstr "" #: src/peerinfo/peerinfo_api.c:358 msgid "failed to transmit request (service down?)" msgstr "" #: src/peerinfo/peerinfo_api.c:505 msgid "Failed to receive response from `PEERINFO' service." msgstr "" #: src/peerinfo/peerinfo_api.c:531 src/peerinfo/peerinfo_api.c:550 #: src/peerinfo/peerinfo_api.c:565 src/peerinfo/peerinfo_api.c:576 #: src/peerinfo/peerinfo_api.c:587 msgid "Received invalid message from `PEERINFO' service." msgstr "" #: src/peerinfo/peerinfo_api.c:663 msgid "Timeout transmitting iteration request to `PEERINFO' service." msgstr "" #: src/peerinfo/peerinfo_api_notify.c:256 #, c-format msgid "Could not connect to `%s' service.\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:581 msgid "Failed to parse HELLO message: missing expiration time\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:589 msgid "Failed to parse HELLO message: invalid expiration time\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:598 msgid "Failed to parse HELLO message: malformed\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:608 msgid "Failed to parse HELLO message: missing transport plugin\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:625 #, c-format msgid "Plugin `%s' not found\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:634 #, c-format msgid "Plugin `%s' does not support URIs yet\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:653 #, c-format msgid "Failed to parse `%s' as an address for plugin `%s'\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:685 #, c-format msgid "Failure adding HELLO: %s\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:833 #, c-format msgid "Could not find option `%s:%s' in configuration.\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:840 #, c-format msgid "Loading hostkey from `%s' failed.\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:875 #, c-format msgid "Invalid URI `%s'\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:899 #, c-format msgid "I am peer `%s'.\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:936 msgid "don't resolve host names" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:939 msgid "output only the identity strings" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:942 msgid "output our own identity only" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:945 msgid "list all known peers" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:948 msgid "also output HELLO uri(s)" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:951 msgid "add given HELLO uri to the database" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:957 msgid "Print information about peers." msgstr "" #: src/peerinfo-tool/gnunet-peerinfo_plugins.c:105 #: src/transport/gnunet-service-transport_plugins.c:118 #, c-format msgid "Starting transport plugins `%s'\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo_plugins.c:109 #: src/transport/gnunet-service-transport_plugins.c:122 #, c-format msgid "Loading `%s' transport plugin\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo_plugins.c:129 #: src/transport/gnunet-service-transport_plugins.c:150 #, c-format msgid "Failed to load transport plugin for `%s'\n" msgstr "" #: src/postgres/postgres.c:59 #, c-format msgid "`%s:%s' failed at %s:%d with error: %s" msgstr "" #: src/postgres/postgres.c:148 #, c-format msgid "Unable to initialize Postgres: %s" msgstr "" #: src/pt/gnunet-daemon-pt.c:264 msgid "Failed to pack DNS request. Dropping.\n" msgstr "" #: src/pt/gnunet-daemon-pt.c:270 msgid "# DNS requests mapped to VPN" msgstr "" #: src/pt/gnunet-daemon-pt.c:323 msgid "# DNS records modified" msgstr "" #: src/pt/gnunet-daemon-pt.c:500 msgid "# DNS replies intercepted" msgstr "" #: src/pt/gnunet-daemon-pt.c:506 msgid "Failed to parse DNS request. Dropping.\n" msgstr "" #: src/pt/gnunet-daemon-pt.c:602 msgid "# DNS requests dropped (timeout)" msgstr "" #: src/pt/gnunet-daemon-pt.c:632 msgid "# DNS requests intercepted" msgstr "" #: src/pt/gnunet-daemon-pt.c:637 msgid "# DNS requests dropped (DNS mesh tunnel down)" msgstr "" #: src/pt/gnunet-daemon-pt.c:645 msgid "# DNS requests dropped (malformed)" msgstr "" #: src/pt/gnunet-daemon-pt.c:716 msgid "# DNS replies received" msgstr "" #: src/pt/gnunet-daemon-pt.c:730 msgid "# DNS replies dropped (too late?)" msgstr "" #: src/pt/gnunet-daemon-pt.c:748 src/pt/gnunet-daemon-pt.c:760 msgid "# DNS requests aborted (tunnel down)" msgstr "" #: src/pt/gnunet-daemon-pt.c:898 src/pt/gnunet-daemon-pt.c:907 #: src/pt/gnunet-daemon-pt.c:930 src/pt/gnunet-daemon-pt.c:940 #, c-format msgid "Failed to connect to %s service. Exiting.\n" msgstr "" #: src/pt/gnunet-daemon-pt.c:973 msgid "Daemon to run to perform IP protocol translation to GNUnet" msgstr "" #: src/statistics/gnunet-service-statistics.c:271 #, c-format msgid "Loading %llu bytes of statistics from `%s'\n" msgstr "" #: src/statistics/gnunet-service-statistics.c:330 #, c-format msgid "Wrote %llu bytes of statistics to `%s'\n" msgstr "" #: src/statistics/gnunet-statistics.c:122 msgid "Failed to obtain statistics.\n" msgstr "" #: src/statistics/gnunet-statistics.c:199 #, c-format msgid "No subsystem or name given\n" msgstr "" #: src/statistics/gnunet-statistics.c:207 #, c-format msgid "Failed to initialize watch routine\n" msgstr "" #: src/statistics/gnunet-statistics.c:227 msgid "limit output to statistics for the given NAME" msgstr "" #: src/statistics/gnunet-statistics.c:230 msgid "make the value being set persistent" msgstr "" #: src/statistics/gnunet-statistics.c:233 msgid "limit output to the given SUBSYSTEM" msgstr "" #: src/statistics/gnunet-statistics.c:236 msgid "just print the statistics value" msgstr "" #: src/statistics/gnunet-statistics.c:239 msgid "watch value continously" msgstr "" #: src/statistics/gnunet-statistics.c:246 msgid "Print statistics about GNUnet operations." msgstr "" #: src/statistics/statistics_api.c:456 msgid "Could not save some persistent statistics\n" msgstr "" #: src/statistics/statistics_api.c:999 msgid "" "Failed to receive acknowledgement from statistics service, some statistics " "might have been lost!\n" msgstr "" #: src/testing/gnunet-testing.c:157 msgid "Could not read hostkeys file, specify hostkey file with -H!\n" msgstr "" #: src/testing/gnunet-testing.c:159 #, c-format msgid "Specified hostkey file `%s' not found!\n" msgstr "" #: src/testing/gnunet-testing.c:273 msgid "create unique configuration files" msgstr "" #: src/testing/gnunet-testing.c:275 msgid "create hostkey files from pre-computed hostkey list" msgstr "" #: src/testing/gnunet-testing.c:277 msgid "host key file" msgstr "" #: src/testing/gnunet-testing.c:279 msgid "number of unique configuration files or hostkeys to create" msgstr "" #: src/testing/gnunet-testing.c:281 msgid "configuration template" msgstr "" #: src/testing/gnunet-testing.c:287 msgid "Command line tool to access the testing library" msgstr "" #: src/testing/helper.c:56 msgid "Peer is lacking HOSTKEY configuration setting.\n" msgstr "" #: src/testing/helper.c:64 msgid "Could not access hostkey.\n" msgstr "" #: src/testing/testing.c:200 msgid "`scp' does not seem to terminate (timeout copying config).\n" msgstr "" #: src/testing/testing.c:214 src/testing/testing.c:798 msgid "`scp' did not complete cleanly.\n" msgstr "" #: src/testing/testing.c:237 msgid "Failed to create pipe for `gnunet-peerinfo' process.\n" msgstr "" #: src/testing/testing.c:238 msgid "Failed to create pipe for `ssh' process.\n" msgstr "" #: src/testing/testing.c:286 #, c-format msgid "Could not start `%s' process to create hostkey.\n" msgstr "" #: src/testing/testing.c:293 msgid "Failed to start `gnunet-peerinfo' process.\n" msgstr "" #: src/testing/testing.c:294 src/testing/testing.c:471 msgid "Failed to start `ssh' process.\n" msgstr "" #: src/testing/testing.c:354 #, c-format msgid "Error reading from gnunet-peerinfo: %s\n" msgstr "" #: src/testing/testing.c:358 msgid "Malformed output from gnunet-peerinfo!\n" msgstr "" #: src/testing/testing.c:368 msgid "Failed to get hostkey!\n" msgstr "" #: src/testing/testing.c:400 msgid "`Failed while waiting for topology setup!\n" msgstr "" #: src/testing/testing.c:463 #, c-format msgid "Could not start `%s' process to start GNUnet.\n" msgstr "" #: src/testing/testing.c:470 msgid "Failed to start `gnunet-arm' process.\n" msgstr "" #: src/testing/testing.c:493 src/testing/testing.c:600 msgid "`gnunet-arm' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:494 src/testing/testing.c:601 #: src/testing/testing.c:621 msgid "`ssh' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:570 msgid "Unable to get HELLO for peer!\n" msgstr "" #: src/testing/testing.c:620 msgid "`gnunet-arm' terminated with non-zero exit status (or timed out)!\n" msgstr "" #: src/testing/testing.c:643 src/testing/testing.c:675 msgid "either `gnunet-arm' or `ssh' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:658 src/testing/testing.c:713 msgid "shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n" msgstr "" #: src/testing/testing.c:786 msgid "`scp' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:948 #, c-format msgid "Starting service %s for peer `%4s'\n" msgstr "" #: src/testing/testing.c:1207 src/testing/testing_group.c:6154 #, c-format msgid "Could not start `%s' process to copy configuration directory.\n" msgstr "" #: src/testing/testing.c:1292 src/testing/testing.c:1359 #, c-format msgid "Terminating peer `%4s'\n" msgstr "" #: src/testing/testing.c:1448 #, c-format msgid "Setting d->dead on peer `%4s'\n" msgstr "" #: src/testing/testing.c:1601 msgid "Peer not yet running, can not change configuration at this point." msgstr "" #: src/testing/testing.c:1609 msgid "Failed to write new configuration to disk." msgstr "" #: src/testing/testing.c:1636 #, c-format msgid "Could not start `%s' process to copy configuration file.\n" msgstr "" #: src/testing/testing.c:1639 msgid "Failed to copy new configuration to remote machine." msgstr "" #: src/testing/testing.c:1794 msgid "Peers failed to connect" msgstr "" #: src/testing/testing.c:1922 msgid "Failed to connect to core service of first peer!\n" msgstr "" #: src/testing/testing.c:2145 msgid "Peers are not fully running yet, can not connect!\n" msgstr "" #: src/testing/testing_group.c:1895 src/testing/testing_group.c:1907 #: src/testing/testing_group.c:2008 src/testing/testing_group.c:2065 #: src/testing/testing_group.c:2152 src/testing/testing_group.c:2172 #: src/testing/testing_group.c:2302 src/testing/testing_peergroup.c:950 #, c-format msgid "Invalid value `%s' for option `%s' in section `%s': expected float\n" msgstr "" #: src/testing/testing_group.c:2160 #, c-format msgid "" "Invalid value `%s' for option `%s' in section `%s': got %f, needed value " "greater than 0\n" msgstr "" #: src/testing/testing_group.c:2877 src/testing/testing_group.c:3063 #, c-format msgid "" "No `%s' specified in peer configuration in section `%s', cannot copy friends " "file!\n" msgstr "" #: src/testing/testing_group.c:3957 msgid "Creating no allowed topology (all peers can connect at core level)\n" msgstr "" #: src/testing/testing_group.c:5226 msgid "Unknown topology specification, can't connect peers!\n" msgstr "" #: src/testing/testing_group.c:5944 src/transport/transport-testing.c:636 msgid "Could not read hostkeys file!\n" msgstr "" #: src/testing/testing_group.c:6011 #, c-format msgid "Could not create configuration for peer number %u on `%s'!\n" msgstr "" #: src/testing/testing_new.c:169 msgid "tmppath cannot be NULL\n" msgstr "" #: src/testing/testing_new.c:356 #, c-format msgid "Hostkeys file not found: %s\n" msgstr "" #: src/testing/testing_new.c:365 #, c-format msgid "Could not open hostkeys file: %s\n" msgstr "" #: src/testing/testing_new.c:380 #, c-format msgid "Incorrect hostkey file format: %s\n" msgstr "" #: src/testing/testing_new.c:437 #, c-format msgid "Key number %u does not exist\n" msgstr "" #: src/testing/testing_new.c:446 #, c-format msgid "Error while decoding key %u\n" msgstr "" #: src/testing/testing_new.c:680 msgid "Failed to create configuration for peer (not enough free ports?)\n" msgstr "" #: src/testing/testing_new.c:691 #, c-format msgid "" "You attempted to create a testbed with more than %u hosts. Please " "precompute more hostkeys first.\n" msgstr "" #: src/testing/testing_new.c:704 #, c-format msgid "Failed to initialize hostkey for peer %u\n" msgstr "" #: src/testing/testing_new.c:734 #, c-format msgid "Failed to write hostkey file for peer %u: %s\n" msgstr "" #: src/testing/testing_new.c:751 #, c-format msgid "Failed to write configuration file `%s' for peer %u: %s\n" msgstr "" #: src/testing/testing_new.c:791 #, c-format msgid "Failed to start `%s': %s\n" msgstr "" #: src/testing/testing_new.c:959 #, c-format msgid "Failed to load configuration from %s\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:259 msgid "# peers blacklisted" msgstr "" #: src/topology/gnunet-daemon-topology.c:392 msgid "# connect requests issued to transport" msgstr "" #: src/topology/gnunet-daemon-topology.c:730 #: src/topology/gnunet-daemon-topology.c:815 msgid "# friends connected" msgstr "" #: src/topology/gnunet-daemon-topology.c:996 msgid "Failed to connect to core service, can not manage topology!\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1026 #, c-format msgid "Option `%s' in section `%s' not specified!\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1039 #, c-format msgid "Could not read friends list `%s'\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1045 #, c-format msgid "Friends file `%s' is empty.\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1054 #, c-format msgid "Failed to read friends list from `%s': out of memory\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1062 #, c-format msgid "Failed to read friends list from `%s'\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1082 #, c-format msgid "" "Syntax error in topology specification at offset %llu, skipping bytes.\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1095 #, c-format msgid "" "Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1105 #, c-format msgid "Found friend `%s' in configuration\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1111 #, c-format msgid "Found myself `%s' in friend list (useless, ignored)\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1121 msgid "# friends in configuration" msgstr "" #: src/topology/gnunet-daemon-topology.c:1127 msgid "" "Fewer friends specified than required by minimum friend count. Will only " "connect to friends.\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1134 msgid "" "More friendly connections required than target total number of connections.\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1169 msgid "# HELLO messages received" msgstr "" #: src/topology/gnunet-daemon-topology.c:1224 msgid "# HELLO messages gossipped" msgstr "" #: src/topology/gnunet-daemon-topology.c:1363 msgid "GNUnet topology control (maintaining P2P mesh and F2F constraints)" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:246 #, c-format msgid "Could not read blacklist file `%s'\n" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:252 #, c-format msgid "Blacklist file `%s' is empty.\n" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:263 #, c-format msgid "Failed to read blacklist from `%s'\n" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:284 #: src/transport/gnunet-service-transport_blacklist.c:308 #, c-format msgid "Syntax error in blacklist file at offset %llu, giving up!\n" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:295 #: src/transport/gnunet-service-transport_blacklist.c:331 #, c-format msgid "Syntax error in blacklist file at offset %llu, skipping bytes.\n" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:345 #, c-format msgid "Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:359 #, c-format msgid "Found myself `%s' in blacklist (useless, ignored)\n" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:514 #: src/transport/gnunet-service-transport_blacklist.c:747 msgid "# disconnects due to blacklist" msgstr "" #: src/transport/gnunet-service-transport.c:163 msgid "# bytes payload discarded due to not connected peer " msgstr "" #: src/transport/gnunet-service-transport.c:237 msgid "# bytes total received" msgstr "" #: src/transport/gnunet-service-transport.c:284 msgid "# bytes payload received" msgstr "" #: src/transport/gnunet-service-transport.c:582 msgid "Transport service is lacking key configuration settings. Exiting.\n" msgstr "" #: src/transport/gnunet-service-transport.c:591 msgid "Transport service could not access hostkey. Exiting.\n" msgstr "" #: src/transport/gnunet-service-transport_clients.c:352 #, c-format msgid "Dropping message of type %u and size %u, have %u/%u messages pending\n" msgstr "" #: src/transport/gnunet-service-transport_clients.c:357 msgid "# messages dropped due to slow client" msgstr "" #: src/transport/gnunet-service-transport_clients.c:503 #, c-format msgid "Rejecting control connection from peer `%s', which is not me!\n" msgstr "" #: src/transport/gnunet-service-transport_clients.c:631 msgid "# bytes payload dropped (other peer was not connected)" msgstr "" #: src/transport/gnunet-service-transport_clients.c:682 msgid "# REQUEST CONNECT messages received" msgstr "" #: src/transport/gnunet-service-transport_hello.c:172 msgid "# refreshed my HELLO" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1032 msgid "# DISCONNECT messages sent" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1148 #: src/transport/gnunet-service-transport_neighbours.c:1482 msgid "# bytes in message queue for other peers" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1153 msgid "# messages transmitted to other peers" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1158 msgid "# transmission failures for messages to other peers" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1215 msgid "# messages timed out while in transport queue" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1254 msgid "# keepalives sent" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1278 msgid "# KEEPALIVE messages discarded (peer unknown)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1286 msgid "# KEEPALIVE messages discarded (no session)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1323 msgid "# KEEPALIVE_RESPONSE messages discarded (not connected)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1332 msgid "# KEEPALIVE_RESPONSE messages discarded (not expected)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1388 msgid "# messages discarded due to lack of neighbour record" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1422 msgid "# bandwidth quota violations by other peers" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1438 msgid "# ms throttling suggested" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2544 msgid "# unexpected CONNECT_ACK messages (no peer)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2559 #: src/transport/gnunet-service-transport_neighbours.c:2585 msgid "# unexpected CONNECT_ACK messages (not ready)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2598 msgid "# unexpected CONNECT_ACK messages (waiting on ATS)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2627 msgid "# unexpected CONNECT_ACK messages (disconnecting)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2807 msgid "# unexpected SESSION ACK messages" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2856 msgid "# SET QUOTA messages ignored (no such peer)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2870 msgid "# disconnects due to quota of 0" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2901 msgid "# disconnect messages ignored (old format)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2912 msgid "# disconnect messages ignored (timestamp)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2943 msgid "# other peer asked to disconnect from us" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:3020 msgid "# disconnected from peer upon explicit request" msgstr "" #: src/transport/gnunet-service-transport_plugins.c:111 msgid "Transport service is lacking NEIGHBOUR_LIMIT option.\n" msgstr "" #: src/transport/gnunet-service-transport_validation.c:414 msgid "# address records discarded" msgstr "" #: src/transport/gnunet-service-transport_validation.c:463 #, c-format msgid "" "Not transmitting `%s' with `%s', message too big (%u bytes!). This should " "not happen.\n" msgstr "" #: src/transport/gnunet-service-transport_validation.c:512 msgid "# PING without HELLO messages sent" msgstr "" #: src/transport/gnunet-service-transport_validation.c:570 msgid "# address revalidations started" msgstr "" #: src/transport/gnunet-service-transport_validation.c:805 msgid "# PING message for different peer received" msgstr "" #: src/transport/gnunet-service-transport_validation.c:840 #, c-format msgid "" "Not confirming PING with address `%s' since I cannot confirm having this " "address.\n" msgstr "" #: src/transport/gnunet-service-transport_validation.c:924 msgid "# PONGs unicast via reliable transport" msgstr "" #: src/transport/gnunet-service-transport_validation.c:933 msgid "# PONGs multicast to all available addresses" msgstr "" #: src/transport/gnunet-service-transport_validation.c:1055 msgid "# PONGs dropped, no matching pending validation" msgstr "" #: src/transport/gnunet-service-transport_validation.c:1080 msgid "# PONGs dropped, signature expired" msgstr "" #: src/transport/gnunet-service-transport_validation.c:1136 #, c-format msgid "Adding `%s' without addresses for peer `%s'\n" msgstr "" #: src/transport/gnunet-transport.c:260 msgid "No transport plugins configured, peer will never communicate\n" msgstr "" #: src/transport/gnunet-transport.c:273 #, c-format msgid "No port configured for plugin `%s', cannot test it\n" msgstr "" #: src/transport/gnunet-transport.c:323 #, c-format msgid "Received %llu bytes/s (%llu bytes in %llu ms)\n" msgstr "" #: src/transport/gnunet-transport.c:330 #, c-format msgid "Transmitted %llu bytes/s (%llu bytes in %llu ms)\n" msgstr "" #: src/transport/gnunet-transport.c:363 #, c-format msgid "Transmitting %u bytes to %s\n" msgstr "" #: src/transport/gnunet-transport.c:383 #, c-format msgid "Connected to %s\n" msgstr "" #: src/transport/gnunet-transport.c:414 #, c-format msgid "Disconnected from %s\n" msgstr "" #: src/transport/gnunet-transport.c:443 #, c-format msgid "Received %u bytes from %s\n" msgstr "" #: src/transport/gnunet-transport.c:466 #, c-format msgid "Peer `%s': %s %s\n" msgstr "" #: src/transport/gnunet-transport.c:473 #, c-format msgid "Peer `%s': %s \n" msgstr "" #: src/transport/gnunet-transport.c:501 #, c-format msgid "Peer `%s' disconnected\n" msgstr "" #: src/transport/gnunet-transport.c:569 #, c-format msgid "Failed to parse peer identity `%s'\n" msgstr "" #: src/transport/gnunet-transport.c:618 msgid "measure how fast we are receiving data (until CTRL-C)" msgstr "" #: src/transport/gnunet-transport.c:621 msgid "try to connect to the given peer" msgstr "" #: src/transport/gnunet-transport.c:624 msgid "provide information about all current connections (once)" msgstr "" #: src/transport/gnunet-transport.c:627 msgid "provide information about all current connections (continuously)" msgstr "" #: src/transport/gnunet-transport.c:630 msgid "do not resolve hostnames" msgstr "" #: src/transport/gnunet-transport.c:634 msgid "send data for benchmarking to the other peer (until CTRL-C)" msgstr "" #: src/transport/gnunet-transport.c:637 msgid "test transport configuration (involves external server)" msgstr "" #: src/transport/gnunet-transport.c:645 msgid "Direct access to transport service." msgstr "" #: src/transport/plugin_transport_http.c:1100 msgid "Disabling IPv6 since it is not supported on this system!\n" msgstr "" #: src/transport/plugin_transport_http.c:1149 msgid "Require valid port number for service in configuration!\n" msgstr "" #: src/transport/plugin_transport_http.c:1174 src/util/service.c:1036 #, c-format msgid "Failed to resolve `%s': %s\n" msgstr "" #: src/transport/plugin_transport_http.c:1191 src/util/service.c:1053 #, c-format msgid "Failed to find %saddress for `%s'.\n" msgstr "" #: src/transport/plugin_transport_http.c:1296 #, c-format msgid "Found %u addresses to report to NAT service\n" msgstr "" #: src/transport/plugin_transport_http.c:1309 #, c-format msgid "FREEING %s\n" msgstr "" #: src/transport/plugin_transport_http.c:1386 msgid "Neither IPv4 nor IPv6 are enabled! Fix in configuration\n" msgstr "" #: src/transport/plugin_transport_http.c:1399 msgid "Port is required! Fix in configuration\n" msgstr "" #: src/transport/plugin_transport_http.c:1410 msgid "Port 0, client only mode\n" msgstr "" #: src/transport/plugin_transport_http.c:1430 #, c-format msgid "" "Specific IPv4 address `%s' for plugin %s in configuration file is invalid! " "Binding to all addresses!\n" msgstr "" #: src/transport/plugin_transport_http.c:1460 #, c-format msgid "" "Specific IPv6 address `%s' for plugin %s in configuration file is invalid! " "Binding to all addresses!\n" msgstr "" #: src/transport/plugin_transport_http_client.c:624 #, c-format msgid "Could not initialize curl multi handle, failed to start %s plugin!\n" msgstr "" #: src/transport/plugin_transport_http_server.c:178 msgid "" "Could not create a new TLS certificate, program `gnunet-transport-" "certificate-creation' could not be started!\n" msgstr "" #: src/transport/plugin_transport_http_server.c:202 msgid "No usable TLS certificate found and creating one failed!\n" msgstr "" #: src/transport/plugin_transport_tcp.c:591 #, c-format msgid "Unexpected address length: %u bytes\n" msgstr "" #: src/transport/plugin_transport_tcp.c:767 #: src/transport/plugin_transport_tcp.c:856 #: src/transport/plugin_transport_tcp.c:906 #: src/transport/plugin_transport_tcp.c:992 #: src/transport/plugin_transport_tcp.c:1086 #: src/transport/plugin_transport_tcp.c:1103 msgid "# bytes currently in TCP buffers" msgstr "" #: src/transport/plugin_transport_tcp.c:774 #: src/transport/plugin_transport_tcp.c:963 #: src/transport/plugin_transport_tcp.c:1761 #: src/transport/plugin_transport_tcp.c:2390 msgid "# TCP sessions active" msgstr "" #: src/transport/plugin_transport_tcp.c:860 msgid "# bytes discarded by TCP (timeout)" msgstr "" #: src/transport/plugin_transport_tcp.c:909 msgid "# bytes transmitted via TCP" msgstr "" #: src/transport/plugin_transport_tcp.c:996 msgid "# bytes discarded by TCP (disconnect)" msgstr "" #: src/transport/plugin_transport_tcp.c:1290 #, c-format msgid "Address of unexpected length: %u\n" msgstr "" #: src/transport/plugin_transport_tcp.c:1401 msgid "# transport-service disconnect requests for TCP" msgstr "" #: src/transport/plugin_transport_tcp.c:1802 msgid "# TCP WELCOME messages received" msgstr "" #: src/transport/plugin_transport_tcp.c:1973 msgid "# bytes received via TCP" msgstr "" #: src/transport/plugin_transport_tcp.c:2043 msgid "# network-level TCP disconnect events" msgstr "" #: src/transport/plugin_transport_tcp.c:2279 src/util/service.c:940 #, c-format msgid "Require valid port number for service `%s' in configuration!\n" msgstr "" #: src/transport/plugin_transport_tcp.c:2293 msgid "Failed to start service.\n" msgstr "" #: src/transport/plugin_transport_tcp.c:2355 #, c-format msgid "Failed to find option %s in section %s!\n" msgstr "" #: src/transport/plugin_transport_tcp.c:2378 #, c-format msgid "TCP transport listening on port %llu\n" msgstr "" #: src/transport/plugin_transport_tcp.c:2382 msgid "TCP transport not listening on any port (client only)\n" msgstr "" #: src/transport/plugin_transport_tcp.c:2386 #, c-format msgid "TCP transport advertises itself as being on port %llu\n" msgstr "" #: src/transport/plugin_transport_udp_broadcasting.c:128 msgid "# IPv6 multicast HELLO beacons received via udp" msgstr "" #: src/transport/plugin_transport_udp_broadcasting.c:169 msgid "# IPv4 broadcast HELLO beacons received via udp" msgstr "" #: src/transport/plugin_transport_udp_broadcasting.c:367 #, c-format msgid "Failed to set IPv4 broadcast option for broadcast socket on port %d\n" msgstr "" #: src/transport/plugin_transport_udp.c:1894 #, c-format msgid "" "UDP could not message to `%s': `%s'. Please check your network configuration " "and disable IPv6 if your connection does not have a global IPv6 address\n" msgstr "" #: src/transport/plugin_transport_udp.c:2138 msgid "Failed to open UDP sockets\n" msgstr "" #: src/transport/plugin_transport_udp.c:2306 #, c-format msgid "Given `%s' option is out of range: %llu > %u\n" msgstr "" #: src/transport/plugin_transport_udp.c:2349 #, c-format msgid "Invalid IPv6 address: `%s'\n" msgstr "" #: src/transport/plugin_transport_unix.c:1356 msgid "Failed to open UNIX sockets\n" msgstr "" #: src/transport/plugin_transport_wlan.c:561 msgid "# WLAN ACKs sent" msgstr "" #: src/transport/plugin_transport_wlan.c:580 msgid "# WLAN messages defragmented" msgstr "" #: src/transport/plugin_transport_wlan.c:626 #: src/transport/plugin_transport_wlan.c:676 #: src/transport/plugin_transport_wlan.c:1696 msgid "# WLAN sessions allocated" msgstr "" #: src/transport/plugin_transport_wlan.c:749 msgid "# WLAN message fragments sent" msgstr "" #: src/transport/plugin_transport_wlan.c:767 msgid "# WLAN messages pending (with fragmentation)" msgstr "" #: src/transport/plugin_transport_wlan.c:867 #: src/transport/plugin_transport_wlan.c:948 #: src/transport/plugin_transport_wlan.c:1698 msgid "# WLAN MAC endpoints allocated" msgstr "" #: src/transport/plugin_transport_wlan.c:1119 msgid "# HELLO messages received via WLAN" msgstr "" #: src/transport/plugin_transport_wlan.c:1140 msgid "# fragments received via WLAN" msgstr "" #: src/transport/plugin_transport_wlan.c:1150 msgid "# ACKs received via WLAN" msgstr "" #: src/transport/plugin_transport_wlan.c:1207 msgid "# WLAN DATA messages discarded due to CRC32 error" msgstr "" #: src/transport/plugin_transport_wlan.c:1306 msgid "# DATA messages received via WLAN" msgstr "" #: src/transport/plugin_transport_wlan.c:1341 msgid "# WLAN DATA messages processed" msgstr "" #: src/transport/plugin_transport_wlan.c:1402 msgid "# HELLO beacons sent via WLAN" msgstr "" #: src/transport/plugin_transport_wlan.c:1511 msgid "WLAN address with invalid size encountered\n" msgstr "" #: src/transport/plugin_transport_wlan.c:1668 #, c-format msgid "Invalid configuration option `%s' in section `%s'\n" msgstr "" #: src/transport/plugin_transport_wlan.c:1677 #, c-format msgid "Helper binary `%s' not SUID, cannot run WLAN transport\n" msgstr "" #: src/transport/plugin_transport_wlan.c:1687 #, c-format msgid "Missing configuration option `%s' in section `%s'\n" msgstr "" #: src/transport/transport_api.c:570 #, c-format msgid "Received unexpected message of type %u in %s:%u\n" msgstr "" #: src/util/bio.c:136 src/util/bio.c:142 #, c-format msgid "Error reading `%s': %s" msgstr "" #: src/util/bio.c:143 msgid "End of file" msgstr "" #: src/util/bio.c:195 #, c-format msgid "Error reading length of string `%s'" msgstr "" #: src/util/bio.c:205 #, c-format msgid "String `%s' longer than allowed (%u > %u)" msgstr "" #: src/util/bio.c:250 #, c-format msgid "Serialized metadata `%s' larger than allowed (%u>%u)" msgstr "" #: src/util/bio.c:264 #, c-format msgid "Metadata `%s' failed to deserialize" msgstr "" #: src/util/client.c:359 #, c-format msgid "" "Could not determine valid hostname and port for service `%s' from " "configuration.\n" msgstr "" #: src/util/client.c:367 #, c-format msgid "Need a non-empty hostname for service `%s'.\n" msgstr "" #: src/util/client.c:685 msgid "Failure to transmit TEST request.\n" msgstr "" #: src/util/client.c:740 src/util/service.c:970 #, c-format msgid "UNIXPATH `%s' too long, maximum length is %llu\n" msgstr "" #: src/util/client.c:882 #, c-format msgid "Could not connect to service `%s', must not be running.\n" msgstr "" #: src/util/client.c:896 #, c-format msgid "Failure to transmit request to service `%s'\n" msgstr "" #: src/util/client.c:1149 msgid "Could not submit request, not expecting to receive a response.\n" msgstr "" #: src/util/common_logging.c:239 src/util/common_logging.c:890 msgid "DEBUG" msgstr "" #: src/util/common_logging.c:241 src/util/common_logging.c:888 msgid "INFO" msgstr "" #: src/util/common_logging.c:243 src/util/common_logging.c:886 msgid "WARNING" msgstr "" #: src/util/common_logging.c:245 src/util/common_logging.c:884 msgid "ERROR" msgstr "" #: src/util/common_logging.c:247 src/util/common_logging.c:892 msgid "NONE" msgstr "" #: src/util/common_logging.c:610 #, c-format msgid "Failed to create or access directory for log file `%s'\n" msgstr "" #: src/util/common_logging.c:725 #, c-format msgid "Message `%.*s' repeated %u times in the last %s\n" msgstr "" #: src/util/common_logging.c:893 msgid "INVALID" msgstr "" #: src/util/common_logging.c:992 msgid "unknown address" msgstr "" #: src/util/common_logging.c:1030 msgid "invalid address" msgstr "" #: src/util/configuration.c:244 #, c-format msgid "Syntax error in configuration file `%s' at line %u.\n" msgstr "" #: src/util/configuration.c:816 #, c-format msgid "" "Configuration value '%s' for '%s' in section '%s' is not in set of legal " "choices\n" msgstr "" #: src/util/connection.c:420 #, c-format msgid "Access denied to `%s'\n" msgstr "" #: src/util/connection.c:435 #, c-format msgid "Accepting connection from `%s': %p\n" msgstr "" #: src/util/connection.c:550 #, c-format msgid "" "Failed to establish TCP connection to `%s:%u', no further addresses to try.\n" msgstr "" #: src/util/connection.c:739 src/util/connection.c:909 #, c-format msgid "Trying to connect to `%s' (%p)\n" msgstr "" #: src/util/connection.c:748 #, c-format msgid "Failed to connect to `%s' (%p)\n" msgstr "" #: src/util/connection.c:900 #, c-format msgid "Attempt to connect to `%s' failed\n" msgstr "" #: src/util/container_bloomfilter.c:510 #, c-format msgid "" "Size of file on disk is incorrect for this Bloom filter (want %llu, have " "%llu)\n" msgstr "" #: src/util/crypto_random.c:280 #, c-format msgid "Starting `%s' process to generate entropy\n" msgstr "" #: src/util/crypto_random.c:309 #, c-format msgid "libgcrypt has not the expected version (version %s is required).\n" msgstr "" #: src/util/crypto_rsa.c:661 src/util/crypto_rsa.c:708 #, c-format msgid "Could not aquire lock on file `%s': %s...\n" msgstr "" #: src/util/crypto_rsa.c:666 msgid "Creating a new private key. This may take a while.\n" msgstr "" #: src/util/crypto_rsa.c:684 #, c-format msgid "I am host `%s'. Stored new private key in `%s'.\n" msgstr "" #: src/util/crypto_rsa.c:712 src/util/crypto_rsa.c:748 msgid "This may be ok if someone is currently generating a hostkey.\n" msgstr "" #: src/util/crypto_rsa.c:743 #, c-format msgid "" "When trying to read hostkey file `%s' I found %u bytes but I need at least " "%u.\n" msgstr "" #: src/util/crypto_rsa.c:763 #, c-format msgid "File `%s' does not contain a valid private key. Deleting it.\n" msgstr "" #: src/util/crypto_rsa.c:781 #, c-format msgid "I am host `%s'. Read private key from `%s'.\n" msgstr "" #: src/util/crypto_rsa.c:1032 #, c-format msgid "RSA signature verification failed at %s:%d: %s\n" msgstr "" #: src/util/disk.c:498 #, c-format msgid "`%s' failed for drive `%S': %u\n" msgstr "" #: src/util/disk.c:1062 #, c-format msgid "Expected `%s' to be a directory!\n" msgstr "" #: src/util/disk.c:1416 src/util/service.c:1650 #, c-format msgid "Cannot obtain information about user `%s': %s\n" msgstr "" #: src/util/disk.c:1734 #, c-format msgid "No `%s' specified for service `%s' in configuration.\n" msgstr "" #: src/util/getopt.c:669 #, c-format msgid "%s: option `%s' is ambiguous\n" msgstr "" #: src/util/getopt.c:693 #, c-format msgid "%s: option `--%s' does not allow an argument\n" msgstr "" #: src/util/getopt.c:698 #, c-format msgid "%s: option `%c%s' does not allow an argument\n" msgstr "" #: src/util/getopt.c:715 src/util/getopt.c:883 #, c-format msgid "%s: option `%s' requires an argument\n" msgstr "" #: src/util/getopt.c:744 #, c-format msgid "%s: unrecognized option `--%s'\n" msgstr "" #: src/util/getopt.c:748 #, c-format msgid "%s: unrecognized option `%c%s'\n" msgstr "" #: src/util/getopt.c:773 #, c-format msgid "%s: illegal option -- %c\n" msgstr "" #: src/util/getopt.c:775 #, c-format msgid "%s: invalid option -- %c\n" msgstr "" #: src/util/getopt.c:803 src/util/getopt.c:931 #, c-format msgid "%s: option requires an argument -- %c\n" msgstr "" #: src/util/getopt.c:851 #, c-format msgid "%s: option `-W %s' is ambiguous\n" msgstr "" #: src/util/getopt.c:869 #, c-format msgid "%s: option `-W %s' does not allow an argument\n" msgstr "" #: src/util/getopt.c:1035 #, c-format msgid "Use %s to get a list of options.\n" msgstr "" #: src/util/getopt_helpers.c:86 #, c-format msgid "" "Arguments mandatory for long options are also mandatory for short options.\n" msgstr "" #: src/util/getopt_helpers.c:258 src/util/getopt_helpers.c:286 #, c-format msgid "You must pass a number to the `%s' option.\n" msgstr "" #: src/util/gnunet-resolver.c:148 msgid "perform a reverse lookup" msgstr "" #: src/util/gnunet-resolver.c:154 msgid "Use build-in GNUnet stub resolver" msgstr "" #: src/util/gnunet-rsa.c:64 #, c-format msgid "No hostkey file specified on command line\n" msgstr "" #: src/util/gnunet-rsa.c:112 msgid "print the public key in ASCII format" msgstr "" #: src/util/gnunet-rsa.c:115 msgid "print the hash of the public key in ASCII format" msgstr "" #: src/util/gnunet-rsa.c:118 msgid "print the short hash of the public key in ASCII format" msgstr "" #: src/util/gnunet-rsa.c:124 msgid "Manipulate GNUnet private RSA key files" msgstr "" #: src/util/gnunet-service-resolver.c:288 #, c-format msgid "Could not resolve `%s' (%s): %s\n" msgstr "" #: src/util/gnunet-service-resolver.c:358 #: src/util/gnunet-service-resolver.c:399 #, c-format msgid "Could not find IP of host `%s': %s\n" msgstr "" #: src/util/helper.c:244 #, c-format msgid "Error reading from `%s': %s\n" msgstr "" #: src/util/helper.c:259 #, c-format msgid "Got 0 bytes from helper `%s' (EOF)\n" msgstr "" #: src/util/helper.c:269 #, c-format msgid "Got %u bytes from helper `%s'\n" msgstr "" #: src/util/helper.c:278 #, c-format msgid "Failed to parse inbound message from helper `%s'\n" msgstr "" #: src/util/helper.c:310 #, c-format msgid "Starting HELPER process `%s'\n" msgstr "" #: src/util/helper.c:440 #, c-format msgid "Error writing to `%s': %s\n" msgstr "" #: src/util/network.c:1200 #, c-format msgid "" "Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n" msgstr "" #: src/util/os_installation.c:299 #, c-format msgid "" "Could not determine installation path for %s. Set `%s' environment " "variable.\n" msgstr "" #: src/util/os_installation.c:486 #, c-format msgid "Could not find binary `%s' in PATH!\n" msgstr "" #: src/util/os_installation.c:492 #, c-format msgid "access (%s, X_OK) failed: %s\n" msgstr "" #: src/util/os_installation.c:507 #, c-format msgid "stat (%s) failed: %s\n" msgstr "" #: src/util/os_priority.c:305 #, c-format msgid "Failed to open named pipe `%s' for reading: %s\n" msgstr "" #: src/util/os_priority.c:306 #, c-format msgid "Failed to open named pipe `%s' for writing: %s\n" msgstr "" #: src/util/plugin.c:89 #, c-format msgid "Initialization of plugin mechanism failed: %s!\n" msgstr "" #: src/util/plugin.c:146 #, c-format msgid "`%s' failed to resolve method '%s' with error: %s\n" msgstr "" #: src/util/plugin.c:219 #, c-format msgid "`%s' failed for library `%s' with error: %s\n" msgstr "" #: src/util/plugin.c:349 msgid "Could not determine plugin installation path.\n" msgstr "" #: src/util/pseudonym.c:276 #, c-format msgid "Failed to parse metadata about pseudonym from file `%s': %s\n" msgstr "" #: src/util/pseudonym.c:407 src/util/pseudonym.c:433 msgid "no-name" msgstr "" #: src/util/resolver_api.c:202 #, c-format msgid "Must specify `%s' for `%s' in configuration!\n" msgstr "" #: src/util/resolver_api.c:221 #, c-format msgid "" "Must specify `%s' or numeric IP address for `%s' of `%s' in configuration!\n" msgstr "" #: src/util/resolver_api.c:347 #, c-format msgid "Timeout trying to resolve IP address `%s'.\n" msgstr "" #: src/util/resolver_api.c:351 #, c-format msgid "Timeout trying to resolve hostname `%s'.\n" msgstr "" #: src/util/resolver_api.c:890 #, c-format msgid "Could not resolve our FQDN : %s\n" msgstr "" #: src/util/scheduler.c:786 msgid "Looks like we're busy waiting...\n" msgstr "" #: src/util/scheduler.c:916 #, c-format msgid "Attempt to cancel dead task %llu!\n" msgstr "" #: src/util/server.c:483 #, c-format msgid "`%s' failed for port %d (%s).\n" msgstr "" #: src/util/server.c:492 #, c-format msgid "`%s' failed for port %d (%s): address already in use\n" msgstr "" #: src/util/server.c:497 #, c-format msgid "`%s' failed for `%s': address already in use\n" msgstr "" #: src/util/server.c:827 #, c-format msgid "" "Processing code for message of type %u did not call " "GNUNET_SERVER_receive_done after %llums\n" msgstr "" #: src/util/service.c:135 src/util/service.c:161 src/util/service.c:204 #: src/util/service.c:225 src/util/service.c:232 #, c-format msgid "Invalid format for IP: `%s'\n" msgstr "" #: src/util/service.c:188 #, c-format msgid "Invalid network notation ('/%d' is not legal in IPv4 CIDR)." msgstr "" #: src/util/service.c:281 #, c-format msgid "Invalid network notation (does not end with ';': `%s')\n" msgstr "" #: src/util/service.c:313 #, c-format msgid "Wrong format `%s' for netmask\n" msgstr "" #: src/util/service.c:343 #, c-format msgid "Wrong format `%s' for network\n" msgstr "" #: src/util/service.c:698 #, c-format msgid "Access denied to UID %d / GID %d\n" msgstr "" #: src/util/service.c:703 #, c-format msgid "Unknown address family %d\n" msgstr "" #: src/util/service.c:710 #, c-format msgid "Access from `%s' denied to service `%s'\n" msgstr "" #: src/util/service.c:765 #, c-format msgid "Could not parse IPv4 network specification `%s' for `%s:%s'\n" msgstr "" #: src/util/service.c:802 #, c-format msgid "Could not parse IPv6 network specification `%s' for `%s:%s'\n" msgstr "" #: src/util/service.c:920 #, c-format msgid "" "Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n" msgstr "" #: src/util/service.c:990 #, c-format msgid "" "Disabling UNIX domain socket support for service `%s', failed to create UNIX " "domain socket: %s\n" msgstr "" #: src/util/service.c:1007 #, c-format msgid "Have neither PORT nor UNIXPATH for service `%s', but one is required\n" msgstr "" #: src/util/service.c:1241 msgid "Could not access a pre-bound socket, will try to bind myself\n" msgstr "" #: src/util/service.c:1292 src/util/service.c:1310 #, c-format msgid "Specified value for `%s' of service `%s' is invalid\n" msgstr "" #: src/util/service.c:1337 #, c-format msgid "Could not access pre-bound socket %u, will try to bind myself\n" msgstr "" #: src/util/service.c:1506 #, c-format msgid "Failed to start `%s' at `%s'\n" msgstr "" #: src/util/service.c:1539 #, c-format msgid "Service `%s' runs at %s\n" msgstr "" #: src/util/service.c:1588 msgid "Service process failed to initialize\n" msgstr "" #: src/util/service.c:1592 msgid "Service process could not initialize server function\n" msgstr "" #: src/util/service.c:1596 msgid "Service process failed to report status\n" msgstr "" #: src/util/service.c:1651 msgid "No such user" msgstr "" #: src/util/service.c:1664 #, c-format msgid "Cannot change user/group to `%s': %s\n" msgstr "" #: src/util/service.c:1729 msgid "do daemonize (detach from terminal)" msgstr "" #: src/util/signal.c:80 #, c-format msgid "signal (%d, %p) returned %d.\n" msgstr "" #: src/util/strings.c:144 msgid "b" msgstr "" #: src/util/strings.c:334 #, c-format msgid "Character sets requested were `%s'->`%s'\n" msgstr "" #: src/util/strings.c:481 msgid "Failed to expand `$HOME': environment variable `HOME' not set" msgstr "" #: src/util/strings.c:573 msgid "ms" msgstr "" #: src/util/strings.c:578 msgid "eternity" msgstr "" #: src/util/strings.c:582 msgid "s" msgstr "" #: src/util/strings.c:586 msgid "m" msgstr "" #: src/util/strings.c:590 msgid "h" msgstr "" #: src/util/strings.c:594 msgid " days" msgstr "" #: src/util/strings.c:618 msgid "end of time" msgstr "" #: src/util/strings.c:1012 msgid "IPv6 address did not start with `['\n" msgstr "" #: src/util/strings.c:1020 msgid "IPv6 address did contain ':' to separate port number\n" msgstr "" #: src/util/strings.c:1026 msgid "IPv6 address did contain ']' before ':' to separate port number\n" msgstr "" #: src/util/strings.c:1033 msgid "IPv6 address did contain a valid port number after the last ':'\n" msgstr "" #: src/util/strings.c:1042 #, c-format msgid "Invalid IPv6 address `%s': %s\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:511 src/vpn/gnunet-service-vpn.c:1071 msgid "# Active tunnels" msgstr "" #: src/vpn/gnunet-service-vpn.c:608 src/vpn/gnunet-service-vpn.c:645 msgid "# peers connected to mesh tunnels" msgstr "" #: src/vpn/gnunet-service-vpn.c:699 msgid "# Bytes given to mesh for transmission" msgstr "" #: src/vpn/gnunet-service-vpn.c:737 msgid "# Bytes dropped in mesh queue (overflow)" msgstr "" #: src/vpn/gnunet-service-vpn.c:772 msgid "# Mesh tunnels created" msgstr "" #: src/vpn/gnunet-service-vpn.c:795 msgid "Failed to setup mesh tunnel!\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:973 #, c-format msgid "Protocol %u not supported, dropping\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1291 msgid "# ICMPv4 packets dropped (not allowed)" msgstr "" #: src/vpn/gnunet-service-vpn.c:1312 msgid "# ICMPv6 packets dropped (not allowed)" msgstr "" #: src/vpn/gnunet-service-vpn.c:1517 msgid "# Packets received from TUN interface" msgstr "" #: src/vpn/gnunet-service-vpn.c:1555 src/vpn/gnunet-service-vpn.c:1596 #, c-format msgid "Packet received for unmapped destination `%s' (dropping it)\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1606 msgid "Received IPv4 packet with options (dropping it)\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1620 #, c-format msgid "Received packet of unknown protocol %d from TUN (dropping it)\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1704 msgid "# ICMP packets received from mesh" msgstr "" #: src/vpn/gnunet-service-vpn.c:2045 msgid "# UDP packets received from mesh" msgstr "" #: src/vpn/gnunet-service-vpn.c:2203 msgid "# TCP packets received from mesh" msgstr "" #: src/vpn/gnunet-service-vpn.c:2354 msgid "Failed to find unallocated IPv4 address in VPN's range\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:2409 msgid "Failed to find unallocated IPv6 address in VPN's range\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:2448 src/vpn/gnunet-service-vpn.c:2661 msgid "# Active destinations" msgstr "" #: src/vpn/gnunet-service-vpn.c:2734 msgid "Failed to allocate IP address for new destination\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:3141 msgid "IPv6 support disabled as this system does not support IPv6\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:3173 msgid "IPv4 support disabled as this system does not support IPv4\n" msgstr "" #: src/vpn/gnunet-vpn.c:151 msgid "Error creating tunnel\n" msgstr "" #: src/vpn/gnunet-vpn.c:195 src/vpn/gnunet-vpn.c:226 #, c-format msgid "Option `%s' makes no sense with option `%s'.\n" msgstr "" #: src/vpn/gnunet-vpn.c:208 #, c-format msgid "Option `%s' or `%s' is required.\n" msgstr "" #: src/vpn/gnunet-vpn.c:220 #, c-format msgid "Option `%s' or `%s' is required when using option `%s'.\n" msgstr "" #: src/vpn/gnunet-vpn.c:238 #, c-format msgid "`%s' is not a valid peer identifier.\n" msgstr "" #: src/vpn/gnunet-vpn.c:260 #, c-format msgid "`%s' is not a valid IP address.\n" msgstr "" #: src/vpn/gnunet-vpn.c:296 msgid "request that result should be an IPv4 address" msgstr "" #: src/vpn/gnunet-vpn.c:299 msgid "request that result should be an IPv6 address" msgstr "" #: src/vpn/gnunet-vpn.c:302 msgid "print IP address only after mesh tunnel has been created" msgstr "" #: src/vpn/gnunet-vpn.c:305 msgid "how long should the mapping be valid for new tunnels?" msgstr "" #: src/vpn/gnunet-vpn.c:308 msgid "destination IP for the tunnel" msgstr "" #: src/vpn/gnunet-vpn.c:311 msgid "peer offering the service we would like to access" msgstr "" #: src/vpn/gnunet-vpn.c:314 msgid "name of the service we would like to access" msgstr "" #: src/vpn/gnunet-vpn.c:317 msgid "service is offered via TCP" msgstr "" #: src/vpn/gnunet-vpn.c:320 msgid "service is offered via UDP" msgstr "" #: src/vpn/gnunet-vpn.c:329 msgid "Setup tunnels via VPN." msgstr "" #: src/include/gnunet_common.h:497 src/include/gnunet_common.h:502 #: src/include/gnunet_common.h:508 #, c-format msgid "Assertion failed at %s:%d.\n" msgstr "" #: src/include/gnunet_common.h:518 #, c-format msgid "External protocol violation detected at %s:%d.\n" msgstr "" #: src/include/gnunet_common.h:539 src/include/gnunet_common.h:546 #, c-format msgid "`%s' failed on file `%s' at %s:%d with error: %s\n" msgstr "" gnunet-0.9.3/po/de.po0000644000175000017500000107214311763406751011334 00000000000000# German translations for GNUnet package # German messages for GNUnet. # Copyright (C) 2004, 2005 Christian Grothoff # This file is distributed under the same license as the GNUnet package. # Christian Grothoff , 2004, 2005. msgid "" msgstr "" "Project-Id-Version: GNUnet 0.7.0b\n" "Report-Msgid-Bugs-To: gnunet-developers@mail.gnu.org\n" "POT-Creation-Date: 2012-06-05 15:47+0200\n" "PO-Revision-Date: 2006-03-17 21:37+0100\n" "Last-Translator: Nils Durner \n" "Language-Team: German \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: src/arm/arm_api.c:165 #, fuzzy msgid "Failed to transmit shutdown request to client.\n" msgstr "Fehler beim Senden einer `%s' Anfrage an den SMTP Server.\n" #: src/arm/arm_api.c:349 #, fuzzy, c-format msgid "Configuration failes to specify option `%s' in section `%s'!\n" msgstr "" "Die Konfigurationsdatei muss in der Sektion `%s' unter `%s' ein Verzeichnis " "angeben, in dem FS Daten gespeichert werden.\n" #: src/arm/arm_api.c:363 #, fuzzy, c-format msgid "Configuration fails to specify option `%s' in section `%s'!\n" msgstr "" "Die Konfigurationsdatei muss in der Sektion `%s' unter `%s' ein Verzeichnis " "angeben, in dem FS Daten gespeichert werden.\n" #: src/arm/arm_api.c:432 #, fuzzy, c-format msgid "Error receiving response to `%s' request from ARM for service `%s'\n" msgstr "Beschädigte Antwort auf `%s' von Knoten `%s' empfangen.\n" #: src/arm/arm_api.c:485 #, c-format msgid "Requesting start of service `%s'.\n" msgstr "" #: src/arm/arm_api.c:486 #, c-format msgid "Requesting termination of service `%s'.\n" msgstr "" #: src/arm/arm_api.c:507 #, c-format msgid "Error while trying to transmit request to start `%s' to ARM\n" msgstr "" #: src/arm/arm_api.c:508 #, c-format msgid "Error while trying to transmit request to stop `%s' to ARM\n" msgstr "" #: src/arm/arm_api.c:540 #, fuzzy, c-format msgid "Asked to start service `%s' within %llu ms\n" msgstr "`%s': Nachricht wurde nicht innerhalb %llu ms empfangen.\n" #: src/arm/arm_api.c:612 #, fuzzy, c-format msgid "Stopping service `%s' within %llu ms\n" msgstr "Keine Antwort innerhalb %llums erhalten.\n" #: src/arm/gnunet-arm.c:159 #, fuzzy, c-format msgid "Service `%s' is unknown to ARM.\n" msgstr "Namespace `%s' hat das Rating %d.\n" #: src/arm/gnunet-arm.c:164 #, fuzzy, c-format msgid "Service `%s' has been stopped.\n" msgstr "Dienst gelöscht.\n" #: src/arm/gnunet-arm.c:167 #, fuzzy, c-format msgid "Service `%s' was already running.\n" msgstr "Diese Suche läuft bereits!\n" #: src/arm/gnunet-arm.c:172 #, fuzzy, c-format msgid "Service `%s' has been started.\n" msgstr "Dienst gelöscht.\n" #: src/arm/gnunet-arm.c:175 #, fuzzy, c-format msgid "Service `%s' was already being stopped.\n" msgstr "Dienst gelöscht.\n" #: src/arm/gnunet-arm.c:179 #, fuzzy, c-format msgid "Service `%s' was already not running.\n" msgstr "Diese Suche läuft bereits!\n" #: src/arm/gnunet-arm.c:183 #, fuzzy msgid "Request ignored as ARM is shutting down.\n" msgstr "`%s' fährt herunter.\n" #: src/arm/gnunet-arm.c:187 #, fuzzy msgid "Error communicating with ARM service.\n" msgstr "Informationen über andere GNUnet Knoten ausgeben." #: src/arm/gnunet-arm.c:191 #, fuzzy msgid "Timeout communicating with ARM service.\n" msgstr "Informationen über andere GNUnet Knoten ausgeben." #: src/arm/gnunet-arm.c:195 #, fuzzy msgid "Operation failed.\n" msgstr "Absicherung fehlgeschlagen bei %s:%d.\n" #: src/arm/gnunet-arm.c:199 msgid "Unknown response code from ARM.\n" msgstr "" #: src/arm/gnunet-arm.c:222 #, fuzzy msgid "Error communicating with ARM. ARM not running?\n" msgstr "Informationen über andere GNUnet Knoten ausgeben." #: src/arm/gnunet-arm.c:225 #, fuzzy msgid "Running services:\n" msgstr "Collection `%s' begonnen.\n" #: src/arm/gnunet-arm.c:249 #, fuzzy, c-format msgid "Fatal configuration error: `%s' option in section `%s' missing.\n" msgstr "" "Es muss eine Liste von Freunden in der Konfigurationsdatei unter `%s' in der " "Sektion `%s' angegeben werden.\n" #: src/arm/gnunet-arm.c:257 src/arm/gnunet-arm.c:357 src/arm/gnunet-arm.c:373 msgid "Fatal error initializing ARM API.\n" msgstr "" #: src/arm/gnunet-arm.c:280 #, fuzzy, c-format msgid "Failed to remove configuration file %s\n" msgstr "Fehler beim Speichern der Konfigurationsdatei `%s':" #: src/arm/gnunet-arm.c:286 #, fuzzy, c-format msgid "Failed to remove servicehome directory %s\n" msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" #: src/arm/gnunet-arm.c:407 msgid "stop all GNUnet services" msgstr "" #: src/arm/gnunet-arm.c:409 msgid "start a particular service" msgstr "" #: src/arm/gnunet-arm.c:411 msgid "stop a particular service" msgstr "" #: src/arm/gnunet-arm.c:413 msgid "start all GNUnet default services" msgstr "" #: src/arm/gnunet-arm.c:416 msgid "stop and start all GNUnet default services" msgstr "" #: src/arm/gnunet-arm.c:419 msgid "delete config file and directory on exit" msgstr "" #: src/arm/gnunet-arm.c:421 msgid "don't print status messages" msgstr "" #: src/arm/gnunet-arm.c:424 #, fuzzy msgid "timeout for completing current operation" msgstr "Zeit, die gewartet wird, bis der Durchlauf fertiggestellt wird (in ms)" #: src/arm/gnunet-arm.c:426 msgid "List currently running services" msgstr "" #: src/arm/gnunet-arm.c:437 msgid "Control services and the Automated Restart Manager (ARM)" msgstr "" #: src/arm/gnunet-service-arm.c:332 #, fuzzy, c-format msgid "Failed to start service `%s'\n" msgstr "Der Transportdienst auf Port %d konnte nicht gestartet werden.\n" #: src/arm/gnunet-service-arm.c:335 #, fuzzy, c-format msgid "Starting service `%s'\n" msgstr "Collection `%s' begonnen.\n" #: src/arm/gnunet-service-arm.c:361 #, fuzzy msgid "Could not send status result to client\n" msgstr "Anfrage konnte nicht an gnunetd gesendet werden.\n" #: src/arm/gnunet-service-arm.c:393 #, fuzzy msgid "Could not send list result to client\n" msgstr "Anfrage konnte nicht an gnunetd gesendet werden.\n" #: src/arm/gnunet-service-arm.c:523 #, fuzzy, c-format msgid "Unable to create socket for service `%s': %s\n" msgstr "Fehler beim Anlegen des Benutzerkontos:" #: src/arm/gnunet-service-arm.c:545 #, c-format msgid "Unable to bind listening socket for service `%s' to address `%s': %s\n" msgstr "" #: src/arm/gnunet-service-arm.c:559 #, c-format msgid "ARM now monitors connections to service `%s' at `%s'\n" msgstr "" #: src/arm/gnunet-service-arm.c:667 #, fuzzy, c-format msgid "Preparing to stop `%s'\n" msgstr "Collection `%s' begonnen.\n" #: src/arm/gnunet-service-arm.c:878 #, fuzzy, c-format msgid "Restarting service `%s'.\n" msgstr "Collection `%s' begonnen.\n" #: src/arm/gnunet-service-arm.c:970 msgid "exit" msgstr "" #: src/arm/gnunet-service-arm.c:975 msgid "signal" msgstr "" #: src/arm/gnunet-service-arm.c:980 #, fuzzy msgid "unknown" msgstr "Unbekannter Fehler" #: src/arm/gnunet-service-arm.c:986 #, fuzzy, c-format msgid "Service `%s' took %llu ms to terminate\n" msgstr "Dienst gelöscht.\n" #: src/arm/gnunet-service-arm.c:1021 #, c-format msgid "Service `%s' terminated with status %s/%d, will restart in %llu ms\n" msgstr "" #: src/arm/gnunet-service-arm.c:1127 #, fuzzy, c-format msgid "Configuration file `%s' for service `%s' not valid: %s\n" msgstr "Konfigurationsdatei `%s' wurde erzeugt.\n" #: src/arm/gnunet-service-arm.c:1129 msgid "option missing" msgstr "" #: src/arm/gnunet-service-arm.c:1213 #, fuzzy, c-format msgid "Starting default services `%s'\n" msgstr "Collection `%s' begonnen.\n" #: src/arm/gnunet-service-arm.c:1224 #, c-format msgid "Default service `%s' not configured correctly!\n" msgstr "" #: src/arm/gnunet-service-arm.c:1238 msgid "" "No default services configured, GNUnet will not really start right now.\n" msgstr "" #: src/arm/mockup-service.c:44 msgid "Initiating shutdown as requested by client.\n" msgstr "" #: src/block/block.c:105 #, fuzzy, c-format msgid "Loading block plugin `%s'\n" msgstr "Teste Transport(e) %s\n" #: src/chat/chat.c:175 #, fuzzy msgid "Could not transmit confirmation receipt\n" msgstr "Auf die Namespace Informationen konnte nicht zugegriffen werden.\n" #: src/chat/chat.c:283 msgid "The current user must be the the first one joined\n" msgstr "" #: src/chat/chat.c:412 #, fuzzy, c-format msgid "Unknown message type: '%u'\n" msgstr "Unbekannte Operation `%s'\n" #: src/chat/chat.c:472 #, fuzzy, c-format msgid "Configuration option `%s' in section `%s' missing\n" msgstr "Konfigurationsdatei `%s' wurde erzeugt.\n" #: src/chat/chat.c:480 #, fuzzy, c-format msgid "Failed to access chat home directory `%s'\n" msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" #: src/chat/chat.c:498 #, fuzzy, c-format msgid "Failed to create/open key in file `%s'\n" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/chat/chat.c:559 #, fuzzy msgid "Could not serialize metadata\n" msgstr "Konnte libgnunetutil nicht initialisieren!\n" #: src/chat/chat.c:674 #, fuzzy msgid "Failed to connect to the chat service\n" msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" #: src/chat/chat.c:680 msgid "Undefined mandatory parameter: joinCallback\n" msgstr "" #: src/chat/chat.c:686 msgid "Undefined mandatory parameter: messageCallback\n" msgstr "" #: src/chat/chat.c:692 msgid "Undefined mandatory parameter: memberCallback\n" msgstr "" #: src/chat/gnunet-chat.c:93 msgid "Joined\n" msgstr "" #: src/chat/gnunet-chat.c:125 src/chat/gnunet-chat.c:133 #: src/chat/gnunet-chat.c:213 src/chat/gnunet-chat.c:253 #: src/chat/gnunet-chat.c:329 src/chat/gnunet-chat.c:371 #: src/chat/gnunet-chat.c:400 src/chat/gnunet-chat.c:700 msgid "anonymous" msgstr "" #: src/chat/gnunet-chat.c:144 #, fuzzy, c-format msgid "(%s) `%s' said: %s\n" msgstr "`%s' %s schlug fehl: %s\n" #: src/chat/gnunet-chat.c:147 src/chat/gnunet-chat.c:150 #, fuzzy, c-format msgid "(%s) `%s' said to you: %s\n" msgstr "`%s' %s schlug fehl: %s\n" #: src/chat/gnunet-chat.c:153 #, fuzzy, c-format msgid "(%s) `%s' said for sure: %s\n" msgstr "`%s' fehlgeschlagen für Laufwerk %s: %u\n" #: src/chat/gnunet-chat.c:156 #, fuzzy, c-format msgid "(%s) `%s' said to you for sure: %s\n" msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" #: src/chat/gnunet-chat.c:159 #, fuzzy, c-format msgid "(%s) `%s' was confirmed that you received: %s\n" msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" #: src/chat/gnunet-chat.c:162 #, fuzzy, c-format msgid "(%s) `%s' was confirmed that you and only you received: %s\n" msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" #: src/chat/gnunet-chat.c:165 #, fuzzy, c-format msgid "(%s) `%s' was confirmed that you received from him or her: %s\n" msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" #: src/chat/gnunet-chat.c:170 #, fuzzy, c-format msgid "" "(%s) `%s' was confirmed that you and only you received from him or her: %s\n" msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" #: src/chat/gnunet-chat.c:173 #, fuzzy, c-format msgid "(%s) `%s' said off the record: %s\n" msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" #: src/chat/gnunet-chat.c:176 #, c-format msgid "(%s) <%s> said using an unknown message type: %s\n" msgstr "" #: src/chat/gnunet-chat.c:217 #, c-format msgid "'%s' acknowledged message #%d\n" msgstr "" #: src/chat/gnunet-chat.c:260 #, c-format msgid "`%s' entered the room\n" msgstr "" #: src/chat/gnunet-chat.c:260 #, fuzzy, c-format msgid "`%s' left the room\n" msgstr "Fehler beim Binden an UDP Port %d.\n" #: src/chat/gnunet-chat.c:321 src/chat/gnunet-chat.c:363 #, fuzzy msgid "Could not change username\n" msgstr "Namespace `%s' konnte nicht erstellt werden (existiert bereits?).\n" #: src/chat/gnunet-chat.c:334 src/chat/gnunet-chat.c:702 #, fuzzy, c-format msgid "Joining room `%s' as user `%s'...\n" msgstr "Ungültige Antwort auf `%s' von Knoten `%s' empfangen.\n" #: src/chat/gnunet-chat.c:373 #, fuzzy, c-format msgid "Changed username to `%s'\n" msgstr "Benutzer/Gruppe kann nicht zu `%s' gewechselt werden: %s\n" #: src/chat/gnunet-chat.c:388 #, c-format msgid "Users in room `%s': " msgstr "" #: src/chat/gnunet-chat.c:434 msgid "Syntax: /msg USERNAME MESSAGE" msgstr "" #: src/chat/gnunet-chat.c:443 #, c-format msgid "Unknown user `%s'. Make sure you specify its numeric suffix, if any.\n" msgstr "" #: src/chat/gnunet-chat.c:460 #, c-format msgid "User `%s' is currently not in the room!\n" msgstr "" #: src/chat/gnunet-chat.c:513 #, fuzzy, c-format msgid "Unknown command `%s'\n" msgstr "Unbekannte Operation `%s'\n" #: src/chat/gnunet-chat.c:524 msgid "" "Use `/join #roomname' to join a chat room. Joining a room will cause you to " "leave the current room" msgstr "" #: src/chat/gnunet-chat.c:528 msgid "" "Use `/nick nickname' to change your nickname. This will cause you to leave " "the current room and immediately rejoin it with the new name." msgstr "" #: src/chat/gnunet-chat.c:532 msgid "" "Use `/msg nickname message' to send a private message to the specified user" msgstr "" #: src/chat/gnunet-chat.c:535 msgid "The `/notice' command is an alias for `/msg'" msgstr "" #: src/chat/gnunet-chat.c:537 msgid "The `/query' command is an alias for `/msg'" msgstr "" #: src/chat/gnunet-chat.c:539 msgid "Use `/sig message' to send a signed public message" msgstr "" #: src/chat/gnunet-chat.c:542 msgid "Use `/ack message' to require signed acknowledgment of the message" msgstr "" #: src/chat/gnunet-chat.c:545 msgid "Use `/anonymous message' to send a public anonymous message" msgstr "" #: src/chat/gnunet-chat.c:547 msgid "The `/anon' command is an alias for `/anonymous'" msgstr "" #: src/chat/gnunet-chat.c:549 msgid "Use `/quit' to terminate gnunet-chat" msgstr "" #: src/chat/gnunet-chat.c:551 msgid "The `/leave' command is an alias for `/quit'" msgstr "" #: src/chat/gnunet-chat.c:554 msgid "Use `/names' to list all of the current members in the chat room" msgstr "" #: src/chat/gnunet-chat.c:556 msgid "Use `/help command' to get help for a specific command" msgstr "" #: src/chat/gnunet-chat.c:672 #, fuzzy msgid "You must specify a nickname\n" msgstr "Sie müssen einen Empfänger angeben!\n" #: src/chat/gnunet-chat.c:688 #, fuzzy, c-format msgid "Failed to join room `%s'\n" msgstr "Fehler beim Binden an UDP Port %d.\n" #: src/chat/gnunet-chat.c:727 msgid "set the nickname to use (required)" msgstr "" #: src/chat/gnunet-chat.c:730 msgid "set the chat room to join" msgstr "" #: src/chat/gnunet-chat.c:742 msgid "Join a chat on GNUnet." msgstr "" #: src/chat/gnunet-service-chat.c:267 #, fuzzy msgid "Failed to queue a message notification\n" msgstr "Fehler beim Speichern der Konfiguration!" #: src/chat/gnunet-service-chat.c:546 #, fuzzy msgid "Failed to queue a join notification\n" msgstr "Fehler beim Abfragen der Netzwerkverkehrsbedingungen von gnunetd.\n" #: src/chat/gnunet-service-chat.c:729 #, fuzzy msgid "Failed to queue a confirmation receipt\n" msgstr "Fehler beim Speichern der Konfiguration!" #: src/chat/gnunet-service-chat.c:907 #, fuzzy msgid "Failed to queue a leave notification\n" msgstr "Fehler beim Speichern der Konfiguration!" #: src/core/core_api.c:786 msgid "Client was disconnected from core service, trying to reconnect.\n" msgstr "" #: src/core/gnunet-core.c:54 src/peerinfo-tool/gnunet-peerinfo.c:286 #, fuzzy, c-format msgid "Peer `%s'\n" msgstr "Ich bin Peer `%s'.\n" #: src/core/gnunet-core.c:72 src/peerinfo-tool/gnunet-peerinfo.c:817 #, fuzzy, c-format msgid "Invalid command line argument `%s'\n" msgstr "Ungültige Kommandozeilen Parameter:\n" #: src/core/gnunet-core.c:95 #, fuzzy msgid "Print information about connected peers." msgstr "Informationen über andere GNUnet Knoten ausgeben." #: src/core/gnunet-service-core.c:97 #, c-format msgid "Core service of `%4s' ready.\n" msgstr "" #: src/core/gnunet-service-core_clients.c:370 #, fuzzy msgid "# send requests dropped (disconnected)" msgstr "# gap Anfragen verworfen: Kollision in RT" #: src/core/gnunet-service-core_clients.c:475 #, fuzzy msgid "# messages discarded (session disconnected)" msgstr "# defragmentierter Nachrichten" #: src/core/gnunet-service-core_clients.c:818 #, fuzzy, c-format msgid "# bytes of messages of type %u received" msgstr "# Bytes Rauschen empfangen" #: src/core/gnunet-service-core_kx.c:565 msgid "# bytes encrypted" msgstr "# Bytes verschlüsselt" #: src/core/gnunet-service-core_kx.c:617 msgid "# bytes decrypted" msgstr "# Bytes entschlüsselt" #: src/core/gnunet-service-core_kx.c:681 src/dv/gnunet-service-dv.c:3003 #, fuzzy msgid "Error in communication with PEERINFO service\n" msgstr "Informationen über andere GNUnet Knoten ausgeben." #: src/core/gnunet-service-core_kx.c:700 msgid "# Delayed connecting due to lack of public key" msgstr "" #: src/core/gnunet-service-core_kx.c:753 msgid "# key exchanges initiated" msgstr "" #: src/core/gnunet-service-core_kx.c:775 msgid "# key exchanges stopped" msgstr "" #: src/core/gnunet-service-core_kx.c:828 #, fuzzy msgid "# session keys received" msgstr "# Sitzungsschlüssel abgelehnt" #: src/core/gnunet-service-core_kx.c:845 #, fuzzy, c-format msgid "`%s' is for `%s', not for me. Ignoring.\n" msgstr "Größe der `%s' Nachricht ist zu kurz. Nachricht wird ignoriert.\n" #: src/core/gnunet-service-core_kx.c:890 #, fuzzy msgid "# SET_KEY messages decrypted" msgstr "# defragmentierter Nachrichten" #: src/core/gnunet-service-core_kx.c:977 #: src/transport/gnunet-service-transport_validation.c:810 #, fuzzy msgid "# PING messages received" msgstr "# PING Nachrichten erstellt" #: src/core/gnunet-service-core_kx.c:1010 #, c-format msgid "" "Received PING from `%s' for different identity: I am `%s', PONG identity: `" "%s'\n" msgstr "" #: src/core/gnunet-service-core_kx.c:1029 #, fuzzy msgid "# PONG messages created" msgstr "# PING Nachrichten erstellt" #: src/core/gnunet-service-core_kx.c:1125 #, fuzzy msgid "# sessions terminated by timeout" msgstr "# Bytes verworfen von TCP (ausgehend)" #: src/core/gnunet-service-core_kx.c:1135 #, fuzzy msgid "# keepalive messages sent" msgstr "# Klartext PING Nachrichten gesendet" #: src/core/gnunet-service-core_kx.c:1236 #: src/transport/gnunet-service-transport_validation.c:1031 #, fuzzy msgid "# PONG messages received" msgstr "# verschlüsselter PONG Nachrichten empfangen" #: src/core/gnunet-service-core_kx.c:1275 #, fuzzy msgid "# PONG messages decrypted" msgstr "# PING Nachrichten erstellt" #: src/core/gnunet-service-core_kx.c:1303 #, fuzzy msgid "# session keys confirmed via PONG" msgstr "# Knotenankündigungen empfangen" #: src/core/gnunet-service-core_kx.c:1329 #, fuzzy msgid "# rekey operations confirmed via PONG" msgstr "# Knotenankündigungen empfangen" #: src/core/gnunet-service-core_kx.c:1381 #: src/core/gnunet-service-core_kx.c:1398 #, fuzzy msgid "# SET_KEY and PING messages created" msgstr "# PING Nachrichten erstellt" #: src/core/gnunet-service-core_kx.c:1402 msgid "# REKEY operations performed" msgstr "" #: src/core/gnunet-service-core_kx.c:1537 msgid "# failed to decrypt message (no session key)" msgstr "" #: src/core/gnunet-service-core_kx.c:1577 #: src/core/gnunet-service-core_kx.c:1602 #, fuzzy msgid "# bytes dropped (duplicates)" msgstr "# Bytes verworfen von UDP (outgoing)" #: src/core/gnunet-service-core_kx.c:1589 #, fuzzy msgid "# bytes dropped (out of sequence)" msgstr "# Bytes verworfen von UDP (outgoing)" #: src/core/gnunet-service-core_kx.c:1626 #, fuzzy, c-format msgid "Message received far too old (%llu ms). Content ignored.\n" msgstr "Empfangene Client-Nachricht ist ungültig.\n" #: src/core/gnunet-service-core_kx.c:1630 #, fuzzy msgid "# bytes dropped (ancient message)" msgstr "# Bytes verworfen von UDP (outgoing)" #: src/core/gnunet-service-core_kx.c:1638 #, fuzzy msgid "# bytes of payload decrypted" msgstr "# Bytes entschlüsselt" #: src/core/gnunet-service-core_kx.c:1700 #, fuzzy msgid "Core service is lacking HOSTKEY configuration setting. Exiting.\n" msgstr "GNUnet Konfiguration" #: src/core/gnunet-service-core_kx.c:1708 msgid "Core service could not access hostkey. Exiting.\n" msgstr "" #: src/core/gnunet-service-core_kx.c:1718 src/hostlist/hostlist-server.c:551 #: src/peerinfo-tool/gnunet-peerinfo.c:823 #: src/transport/gnunet-service-transport.c:611 #, fuzzy msgid "Could not access PEERINFO service. Exiting.\n" msgstr "Auf die Namespace Informationen konnte nicht zugegriffen werden.\n" #: src/core/gnunet-service-core_neighbours.c:163 #, fuzzy msgid "# sessions terminated by transport disconnect" msgstr "# Knotenankündigungen empfangen" #: src/core/gnunet-service-core_neighbours.c:180 #: src/core/gnunet-service-core_neighbours.c:334 msgid "# neighbour entries allocated" msgstr "" #: src/core/gnunet-service-core_neighbours.c:247 msgid "# encrypted bytes given to transport" msgstr "" #: src/core/gnunet-service-core_neighbours.c:418 #, fuzzy, c-format msgid "Unsupported message of type %u (%u bytes) received from peer `%s'\n" msgstr "Ungültige Nachricht des Typs %u empfangen. Nachricht wird verworfen.\n" #: src/core/gnunet-service-core_sessions.c:206 #: src/core/gnunet-service-core_sessions.c:269 #: src/dht/gnunet-service-dht_neighbours.c:625 #: src/dht/gnunet-service-dht_neighbours.c:683 #: src/fs/gnunet-service-fs_cp.c:615 src/fs/gnunet-service-fs_cp.c:1532 #: src/topology/gnunet-daemon-topology.c:709 #: src/topology/gnunet-daemon-topology.c:810 #: src/transport/gnunet-service-transport_neighbours.c:874 #: src/transport/gnunet-service-transport_neighbours.c:1080 #: src/transport/gnunet-service-transport_neighbours.c:1089 #: src/transport/gnunet-service-transport_neighbours.c:2568 #: src/transport/gnunet-service-transport_neighbours.c:2814 #, fuzzy msgid "# peers connected" msgstr "# verbundener Knoten" #: src/core/gnunet-service-core_sessions.c:236 #, fuzzy msgid "# type map refreshes sent" msgstr "# p2p Trace-Antworten gesendet" #: src/core/gnunet-service-core_sessions.c:406 msgid "# messages discarded (expired prior to transmission)" msgstr "" #: src/core/gnunet-service-core_typemap.c:110 #: src/core/gnunet-service-core_typemap.c:121 #, fuzzy msgid "# type maps received" msgstr "# verschlüsselter PING Nachrichten empfangen" #: src/core/gnunet-service-core_typemap.c:151 msgid "# updates to my type map" msgstr "" #: src/datacache/datacache.c:115 src/datacache/datacache.c:250 #: src/datastore/gnunet-service-datastore.c:834 #, fuzzy msgid "# bytes stored" msgstr "# bytes in der Datenbank" #: src/datacache/datacache.c:141 src/datacache/datacache.c:148 #: src/datastore/gnunet-service-datastore.c:1483 #: src/datastore/gnunet-service-datastore.c:1494 #, fuzzy, c-format msgid "No `%s' specified for `%s' in configuration!\n" msgstr "In der Konfigurationsdatei wurden keine Anwendungen definiert!\n" #: src/datacache/datacache.c:180 #, c-format msgid "Loading `%s' datacache plugin\n" msgstr "" #: src/datacache/datacache.c:188 #, fuzzy, c-format msgid "Failed to load datacache plugin for `%s'\n" msgstr "Fehler beim Aktualisieren der Daten des Moduls `%s'\n" #: src/datacache/datacache.c:276 #, fuzzy msgid "# requests received" msgstr "# Client Trace-Anfragen empfangen" #: src/datacache/datacache.c:284 msgid "# requests filtered by bloom filter" msgstr "" #: src/datacache/plugin_datacache_mysql.c:97 #: src/datacache/plugin_datacache_mysql.c:104 #: src/datacache/plugin_datacache_sqlite.c:69 #: src/datacache/plugin_datacache_sqlite.c:72 #: src/datastore/plugin_datastore_mysql.c:803 #: src/datastore/plugin_datastore_mysql.c:817 #: src/datastore/plugin_datastore_sqlite.c:57 src/mysql/mysql.c:41 #: src/mysql/mysql.c:48 src/mysql/mysql.c:522 src/mysql/mysql.c:531 #: src/mysql/mysql.c:591 src/mysql/mysql.c:607 #: src/namestore/plugin_namestore_sqlite.c:51 src/util/crypto_ksk.c:49 #: src/util/crypto_rsa.c:67 src/include/gnunet_common.h:525 #: src/include/gnunet_common.h:532 #, c-format msgid "`%s' failed at %s:%d with error: %s\n" msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" #: src/datacache/plugin_datacache_mysql.c:450 msgid "MySQL datacache running\n" msgstr "" #: src/datacache/plugin_datacache_postgres.c:367 msgid "Postgres datacache running\n" msgstr "" #: src/datacache/plugin_datacache_sqlite.c:410 msgid "Sqlite datacache running\n" msgstr "" #: src/datacache/plugin_datacache_sqlite.c:443 #: src/datastore/plugin_datastore_sqlite.c:408 #: src/namestore/plugin_namestore_sqlite.c:370 msgid "Tried to close sqlite without finalizing all prepared statements.\n" msgstr "" #: src/datacache/plugin_datacache_sqlite.c:450 #, fuzzy, c-format msgid "Failed to close statement %p: %d\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/datacache/plugin_datacache_template.c:121 msgid "Template datacache running\n" msgstr "" #: src/datastore/datastore_api.c:305 #, fuzzy msgid "Failed to transmit request to drop database.\n" msgstr "Fehler beim Senden einer `%s' Anfrage an den SMTP Server.\n" #: src/datastore/datastore_api.c:388 msgid "# queue entry timeouts" msgstr "" #: src/datastore/datastore_api.c:432 msgid "# queue overflows" msgstr "" #: src/datastore/datastore_api.c:459 #, fuzzy msgid "# queue entries created" msgstr "# dht Anfragen weitergeleitet" #: src/datastore/datastore_api.c:477 #, fuzzy msgid "# Requests dropped from datastore queue" msgstr "# gap Anfragen verworfen: Kollision in RT" #: src/datastore/datastore_api.c:525 msgid "# datastore connections (re)created" msgstr "" #: src/datastore/datastore_api.c:548 msgid "# reconnected to DATASTORE" msgstr "" #: src/datastore/datastore_api.c:612 #, fuzzy msgid "# transmission request failures" msgstr "# Klartext PONG Nachrichten empfangen" #: src/datastore/datastore_api.c:633 #, fuzzy msgid "# bytes sent to datastore" msgstr "# bytes in der Datenbank" #: src/datastore/datastore_api.c:764 #, fuzzy msgid "Failed to receive status response from database." msgstr "" "\n" "Fehler beim Empfangen der Antwort von gnunetd.\n" #: src/datastore/datastore_api.c:778 msgid "Error reading response from datastore service" msgstr "" #: src/datastore/datastore_api.c:790 src/datastore/datastore_api.c:796 #, fuzzy msgid "Invalid error message received from datastore service" msgstr "Ungültige `%s' Nachricht von Knoten `%s' empfangen.\n" #: src/datastore/datastore_api.c:800 #, fuzzy msgid "# status messages received" msgstr "# verschlüsselter PING Nachrichten empfangen" #: src/datastore/datastore_api.c:869 #, fuzzy msgid "# PUT requests executed" msgstr "# dht Anfragen weitergeleitet" #: src/datastore/datastore_api.c:936 #, fuzzy msgid "# RESERVE requests executed" msgstr "# dht Anfragen weitergeleitet" #: src/datastore/datastore_api.c:997 msgid "# RELEASE RESERVE requests executed" msgstr "" #: src/datastore/datastore_api.c:1054 #, fuzzy msgid "# UPDATE requests executed" msgstr "# dht Anfragen weitergeleitet" #: src/datastore/datastore_api.c:1118 #, fuzzy msgid "# REMOVE requests executed" msgstr "# dht Anfragen weitergeleitet" #: src/datastore/datastore_api.c:1163 #, fuzzy msgid "Failed to receive response from database.\n" msgstr "" "\n" "Fehler beim Empfangen der Antwort von gnunetd.\n" #: src/datastore/datastore_api.c:1221 #, fuzzy msgid "# Results received" msgstr "# Bytes empfangen über TCP" #: src/datastore/datastore_api.c:1286 msgid "# GET REPLICATION requests executed" msgstr "" #: src/datastore/datastore_api.c:1349 msgid "# GET ZERO ANONYMITY requests executed" msgstr "" #: src/datastore/datastore_api.c:1409 #, fuzzy msgid "# GET requests executed" msgstr "# dht Anfragen weitergeleitet" #: src/datastore/gnunet-service-datastore.c:349 #, fuzzy msgid "# bytes expired" msgstr "# Bytes empfangen über TCP" #: src/datastore/gnunet-service-datastore.c:422 msgid "# bytes purged (low-priority)" msgstr "" #: src/datastore/gnunet-service-datastore.c:480 msgid "Transmission to client failed!\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:511 msgid "Shutdown in progress, aborting transmission.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:626 msgid "# results found" msgstr "" #: src/datastore/gnunet-service-datastore.c:669 #, c-format msgid "" "Insufficient space (%llu bytes are available) to satisfy `%s' request for " "%llu bytes\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:680 #, c-format msgid "" "The requested amount (%llu bytes) is larger than the cache size (%llu " "bytes)\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:684 msgid "" "Insufficient space to satisfy request and requested amount is larger than " "cache size" msgstr "" #: src/datastore/gnunet-service-datastore.c:690 msgid "Insufficient space to satisfy request" msgstr "" #: src/datastore/gnunet-service-datastore.c:695 #: src/datastore/gnunet-service-datastore.c:747 #: src/datastore/gnunet-service-datastore.c:960 #: src/datastore/gnunet-service-datastore.c:1417 msgid "# reserved" msgstr "" #: src/datastore/gnunet-service-datastore.c:760 msgid "Could not find matching reservation" msgstr "" #: src/datastore/gnunet-service-datastore.c:846 #, c-format msgid "Need %llu bytes more space (%llu allowed, using %llu)\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1006 #, fuzzy msgid "# GET requests received" msgstr "# Client Trace-Anfragen empfangen" #: src/datastore/gnunet-service-datastore.c:1018 msgid "# requests filtered by bloomfilter" msgstr "" #: src/datastore/gnunet-service-datastore.c:1046 #, fuzzy msgid "# UPDATE requests received" msgstr "# Client Trace-Anfragen empfangen" #: src/datastore/gnunet-service-datastore.c:1076 #, fuzzy msgid "# GET REPLICATION requests received" msgstr "# Client Trace-Anfragen empfangen" #: src/datastore/gnunet-service-datastore.c:1109 #, fuzzy msgid "# GET ZERO ANONYMITY requests received" msgstr "# Client Trace-Anfragen empfangen" #: src/datastore/gnunet-service-datastore.c:1134 #, fuzzy msgid "Content not found" msgstr "Kommando `%s' wurde nicht gefunden!\n" #: src/datastore/gnunet-service-datastore.c:1142 msgid "# bytes removed (explicit request)" msgstr "" #: src/datastore/gnunet-service-datastore.c:1174 #, fuzzy msgid "# REMOVE requests received" msgstr "# Client Trace-Anfragen empfangen" #: src/datastore/gnunet-service-datastore.c:1216 #, c-format msgid "Datastore payload inaccurate (%lld < %lld). Trying to fix.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1277 #, c-format msgid "Loading `%s' datastore plugin\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1286 #, fuzzy, c-format msgid "Failed to load datastore plugin for `%s'\n" msgstr "Anwendung `%s' konnte nicht initialisiert werden.\n" #: src/datastore/gnunet-service-datastore.c:1488 #, fuzzy, c-format msgid "# bytes used in file-sharing datastore `%s'" msgstr "# bytes erlaubt in der Datenbank" #: src/datastore/gnunet-service-datastore.c:1499 msgid "# quota" msgstr "" #: src/datastore/gnunet-service-datastore.c:1501 msgid "# cache size" msgstr "" #: src/datastore/gnunet-service-datastore.c:1514 #, c-format msgid "Could not use specified filename `%s' for bloomfilter.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1532 #: src/datastore/gnunet-service-datastore.c:1548 #, fuzzy, c-format msgid "Failed to remove bogus bloomfilter file `%s'\n" msgstr "Fehler beim Speichern der Konfigurationsdatei `%s':" #: src/datastore/gnunet-service-datastore.c:1578 #, fuzzy msgid "Failed to initialize bloomfilter.\n" msgstr "SQLite Datenbank konnte nicht initialisiert werden.\n" #: src/datastore/gnunet-service-datastore.c:1607 msgid "Rebuilding bloomfilter. Please be patient.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1612 msgid "Plugin does not support get_keys function. Please fix!\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1615 msgid "Bloomfilter construction complete.\n" msgstr "" #: src/datastore/plugin_datastore_mysql.c:780 #, fuzzy, c-format msgid "Failed to prepare statement `%s'\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/datastore/plugin_datastore_mysql.c:788 #, fuzzy, c-format msgid "`%s' for `%s' failed at %s:%d with error: %s\n" msgstr "`%s' an `%s' schlug fehl bei %s:%d mit dem Fehler: %s\n" #: src/datastore/plugin_datastore_mysql.c:1019 msgid "Mysql database running\n" msgstr "" #: src/datastore/plugin_datastore_postgres.c:824 #, fuzzy msgid "Failed to drop table from database.\n" msgstr "" "\n" "Fehler beim Empfangen der Antwort von gnunetd.\n" #: src/datastore/plugin_datastore_postgres.c:860 msgid "Postgres database running\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:57 #, fuzzy, c-format msgid "`%s' failed at %s:%u with error: %s" msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" #: src/datastore/plugin_datastore_sqlite.c:233 #: src/namestore/plugin_namestore_sqlite.c:204 #, fuzzy, c-format msgid "Option `%s' in section `%s' missing in configuration!\n" msgstr "In der Konfigurationsdatei wurden keine Anwendungen definiert!\n" #: src/datastore/plugin_datastore_sqlite.c:260 #: src/namestore/plugin_namestore_sqlite.c:229 #, c-format msgid "Unable to initialize SQLite: %s.\n" msgstr "SQLite Datenbank konnte nicht initialisiert werden: %s.\n" #: src/datastore/plugin_datastore_sqlite.c:655 #, fuzzy msgid "Invalid data in database. Trying to fix (by deletion).\n" msgstr "Ungültige Daten in %s. Korrektur wird versucht (durch Löschung).\n" #: src/datastore/plugin_datastore_sqlite.c:1139 msgid "sqlite version to old to determine size, assuming zero\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:1158 #, c-format msgid "" "Using sqlite page utilization to estimate payload (%llu pages of size %llu " "bytes)\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:1198 #: src/namestore/plugin_namestore_sqlite.c:829 #, fuzzy msgid "Sqlite database running\n" msgstr "sqlite Datenspeicher" #: src/datastore/plugin_datastore_template.c:241 msgid "Template database running\n" msgstr "" #: src/dht/dht_api.c:348 #, fuzzy msgid "Failed to connect to the DHT service!\n" msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" #: src/dht/gnunet-dht-get.c:201 src/dht/gnunet-dht-monitor.c:293 #: src/dht/gnunet-dht-put.c:192 msgid "the query key" msgstr "" #: src/dht/gnunet-dht-get.c:204 msgid "how many parallel requests (replicas) to create" msgstr "" #: src/dht/gnunet-dht-get.c:207 src/dht/gnunet-dht-monitor.c:296 msgid "the type of data to look for" msgstr "" #: src/dht/gnunet-dht-get.c:210 src/dht/gnunet-dht-put.c:201 msgid "how long to execute this query before giving up?" msgstr "" #: src/dht/gnunet-dht-get.c:213 src/dht/gnunet-dht-monitor.c:302 #: src/dht/gnunet-dht-put.c:204 src/fs/gnunet-download.c:271 #: src/fs/gnunet-publish.c:731 src/fs/gnunet-search.c:297 #: src/fs/gnunet-unindex.c:169 src/nse/gnunet-nse-profiler.c:910 msgid "be verbose (print progress information)" msgstr "" #: src/dht/gnunet-dht-get.c:232 msgid "Issue a GET request to the GNUnet DHT, prints results." msgstr "" #: src/dht/gnunet-dht-monitor.c:299 msgid "how long to execute? 0 = forever" msgstr "" #: src/dht/gnunet-dht-monitor.c:321 msgid "Prints all packets that go through the DHT." msgstr "" #: src/dht/gnunet-dht-put.c:108 #, fuzzy msgid "PUT request sent!\n" msgstr "# gap Anfragen insgesamt empfangen" #: src/dht/gnunet-dht-put.c:111 msgid "Timeout sending PUT request!\n" msgstr "" #: src/dht/gnunet-dht-put.c:114 #, fuzzy msgid "PUT request not confirmed!\n" msgstr "# gap Anfragen insgesamt empfangen" #: src/dht/gnunet-dht-put.c:144 msgid "Must provide KEY and DATA for DHT put!\n" msgstr "" #: src/dht/gnunet-dht-put.c:152 #, fuzzy, c-format msgid "Could not connect to %s service!\n" msgstr "Verbindung zu gnunetd konnte nicht hergestellt werden.\n" #: src/dht/gnunet-dht-put.c:157 #, fuzzy, c-format msgid "Connected to %s service!\n" msgstr "`%s' hat sich mit `%s' verbunden.\n" #: src/dht/gnunet-dht-put.c:172 #, c-format msgid "Issuing put request for `%s' with data `%s'!\n" msgstr "" #: src/dht/gnunet-dht-put.c:186 msgid "the data to insert under the key" msgstr "" #: src/dht/gnunet-dht-put.c:189 msgid "how long to store this entry in the dht (in seconds)" msgstr "" #: src/dht/gnunet-dht-put.c:195 msgid "how many replicas to create" msgstr "" #: src/dht/gnunet-dht-put.c:198 msgid "the type to insert data as" msgstr "" #: src/dht/gnunet-dht-put.c:223 msgid "Issue a PUT request to the GNUnet DHT insert DATA under KEY." msgstr "" #: src/dht/gnunet-service-dht.c:163 src/testing/testing.c:544 #: src/testing/testing.c:1968 src/testing/testing.c:1998 #, fuzzy msgid "Failed to connect to transport service!\n" msgstr "Der Transportdienst auf Port %d konnte nicht gestartet werden.\n" #: src/dht/gnunet-service-dht_clients.c:407 #, fuzzy msgid "# GET requests from clients injected" msgstr "# Client Trace-Anfragen empfangen" #: src/dht/gnunet-service-dht_clients.c:500 #, fuzzy msgid "# PUT requests received from clients" msgstr "Empfangene Client-Nachricht ist ungültig.\n" #: src/dht/gnunet-service-dht_clients.c:584 #, fuzzy msgid "# GET requests received from clients" msgstr "Empfangene Client-Nachricht ist ungültig.\n" #: src/dht/gnunet-service-dht_clients.c:682 #, fuzzy msgid "# GET STOP requests received from clients" msgstr "Empfangene Client-Nachricht ist ungültig.\n" #: src/dht/gnunet-service-dht_clients.c:919 msgid "# Key match, type mismatches in REPLY to CLIENT" msgstr "" #: src/dht/gnunet-service-dht_clients.c:932 msgid "# Duplicate REPLIES to CLIENT request dropped" msgstr "" #: src/dht/gnunet-service-dht_clients.c:967 #, fuzzy, c-format msgid "Unsupported block type (%u) in request!\n" msgstr "Ungültige Nachricht des Typs %u empfangen. Nachricht wird verworfen.\n" #: src/dht/gnunet-service-dht_clients.c:989 #, fuzzy msgid "# RESULTS queued for clients" msgstr "Empfangene Client-Nachricht ist ungültig.\n" #: src/dht/gnunet-service-dht_clients.c:1038 #: src/dht/gnunet-service-dht_clients.c:1081 msgid "# REPLIES ignored for CLIENTS (no match)" msgstr "" #: src/dht/gnunet-service-dht_clients.c:1048 #, fuzzy msgid "Could not pass reply to client, message too big!\n" msgstr "'join' Nachricht konnte nicht an gnunetd gesendet werden.\n" #: src/dht/gnunet-service-dht_datacache.c:93 #, fuzzy, c-format msgid "%s request received, but have no datacache!\n" msgstr "# Bytes empfangen über TCP" #: src/dht/gnunet-service-dht_datacache.c:103 msgid "# ITEMS stored in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:207 msgid "# Good RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:218 msgid "# Duplicate RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:224 msgid "# Invalid RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:236 msgid "# Unsupported RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:239 #, c-format msgid "Unsupported block type (%u) in local response!\n" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:269 #, fuzzy msgid "# GET requests given to datacache" msgstr "# Client Trace-Anfragen empfangen" #: src/dht/gnunet-service-dht_hello.c:82 #, fuzzy msgid "# HELLOs obtained from peerinfo" msgstr "Empfangene Client-Nachricht ist ungültig.\n" #: src/dht/gnunet-service-dht_neighbours.c:481 msgid "# Preference updates given to core" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:571 #, fuzzy msgid "# FIND PEER messages initiated" msgstr "# PING Nachrichten erstellt" #: src/dht/gnunet-service-dht_neighbours.c:717 #, fuzzy msgid "# Queued messages discarded (peer disconnected)" msgstr "# defragmentierter Nachrichten" #: src/dht/gnunet-service-dht_neighbours.c:772 #, fuzzy msgid "# Bytes transmitted to other peers" msgstr "# Bytes des Typs %d übertragen" #: src/dht/gnunet-service-dht_neighbours.c:810 #, fuzzy msgid "# Bytes of bandwdith requested from core" msgstr "# Client Trace-Anfragen empfangen" #: src/dht/gnunet-service-dht_neighbours.c:1032 #: src/dht/gnunet-service-dht_neighbours.c:1060 msgid "# Peers excluded from routing due to Bloomfilter" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1041 #: src/dht/gnunet-service-dht_neighbours.c:1075 #, fuzzy msgid "# Peer selection failed" msgstr " Verbindung fehlgeschlagen\n" #: src/dht/gnunet-service-dht_neighbours.c:1207 #, fuzzy msgid "# PUT requests routed" msgstr "# dht Anfragen weitergeleitet" #: src/dht/gnunet-service-dht_neighbours.c:1236 #, fuzzy msgid "# PUT messages queued for transmission" msgstr "# PING Nachrichten erstellt" #: src/dht/gnunet-service-dht_neighbours.c:1315 #, fuzzy msgid "# GET requests routed" msgstr "# dht Anfragen weitergeleitet" #: src/dht/gnunet-service-dht_neighbours.c:1342 #, fuzzy msgid "# GET messages queued for transmission" msgstr "# PING Nachrichten erstellt" #: src/dht/gnunet-service-dht_neighbours.c:1443 #, fuzzy msgid "# RESULT messages queued for transmission" msgstr "# PING Nachrichten erstellt" #: src/dht/gnunet-service-dht_neighbours.c:1531 #, fuzzy msgid "# P2P PUT requests received" msgstr "# Client Trace-Anfragen empfangen" #: src/dht/gnunet-service-dht_neighbours.c:1647 msgid "# FIND PEER requests ignored due to Bloomfilter" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1655 msgid "# FIND PEER requests ignored due to lack of HELLO" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1746 #, fuzzy msgid "# P2P GET requests received" msgstr "# Client Trace-Anfragen empfangen" #: src/dht/gnunet-service-dht_neighbours.c:1788 #, fuzzy msgid "# P2P FIND PEER requests processed" msgstr "# Client Trace-Anfragen empfangen" #: src/dht/gnunet-service-dht_neighbours.c:1802 #, fuzzy msgid "# P2P GET requests ONLY routed" msgstr "# dht Anfragen weitergeleitet" #: src/dht/gnunet-service-dht_neighbours.c:1876 #, fuzzy msgid "# P2P RESULTS received" msgstr "# Bytes empfangen über TCP" #: src/dht/gnunet-service-dht_nse.c:59 #, fuzzy msgid "# Network size estimates received" msgstr "# Client Trace-Anfragen empfangen" #: src/dht/gnunet-service-dht_routing.c:211 msgid "# Good REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:220 msgid "# Duplicate REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:226 msgid "# Invalid REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:238 msgid "# Unsupported REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:311 msgid "# Entries removed from routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:352 msgid "# Entries added to routing table" msgstr "" #: src/dht/plugin_block_dht.c:136 #, fuzzy, c-format msgid "Block not of type %u\n" msgstr "Kein Transport des Typs %d bekannt.\n" #: src/dht/plugin_block_dht.c:143 msgid "Size mismatch for block\n" msgstr "" #: src/dht/plugin_block_dht.c:152 #, c-format msgid "Block of type %u is malformed\n" msgstr "" #: src/dns/gnunet-dns-monitor.c:337 msgid "only monitor DNS queries" msgstr "" #: src/dns/gnunet-dns-monitor.c:340 msgid "only monitor DNS replies" msgstr "" #: src/dns/gnunet-dns-monitor.c:348 msgid "Monitor DNS queries." msgstr "" #: src/dns/gnunet-dns-redirector.c:236 msgid "set A records" msgstr "" #: src/dns/gnunet-dns-redirector.c:239 msgid "set AAAA records" msgstr "" #: src/dns/gnunet-dns-redirector.c:247 msgid "Change DNS replies to point elsewhere." msgstr "" #: src/dns/gnunet-service-dns.c:485 #, fuzzy, c-format msgid "Could not bind to any port: %s\n" msgstr "IP des Hosts `%s' konnte nicht ermittelt werden: %s\n" #: src/dns/gnunet-service-dns.c:639 msgid "# DNS requests answered via TUN interface" msgstr "" #: src/dns/gnunet-service-dns.c:822 msgid "# DNS exit failed (failed to open socket)" msgstr "" #: src/dns/gnunet-service-dns.c:1005 #, c-format msgid "Received DNS response that is too small (%u bytes)" msgstr "" #: src/dns/gnunet-service-dns.c:1050 msgid "# External DNS response discarded (no matching request)" msgstr "" #: src/dns/gnunet-service-dns.c:1168 msgid "# Client response discarded (no matching request)" msgstr "" #: src/dns/gnunet-service-dns.c:1281 msgid "Received malformed IPv4-UDP packet on TUN interface.\n" msgstr "" #: src/dns/gnunet-service-dns.c:1297 msgid "Received malformed IPv6-UDP packet on TUN interface.\n" msgstr "" #: src/dns/gnunet-service-dns.c:1306 #, c-format msgid "Got non-IP packet with %u bytes and protocol %u from TUN\n" msgstr "" #: src/dns/gnunet-service-dns.c:1315 msgid "# Non-DNS UDP packet received via TUN interface" msgstr "" #: src/dns/gnunet-service-dns.c:1380 #, fuzzy msgid "# DNS requests received via TUN interface" msgstr "Empfangene Client-Nachricht ist ungültig.\n" #: src/dns/gnunet-service-dns.c:1465 #, c-format msgid "Configured DNS exit `%s' is not working / valid.\n" msgstr "" #: src/dns/gnunet-service-dns.c:1497 src/exit/gnunet-daemon-exit.c:2674 msgid "# Inbound MESH tunnels created" msgstr "" #: src/dns/gnunet-service-dns.c:1561 src/exit/gnunet-daemon-exit.c:3032 #, c-format msgid "`%s' must be installed SUID, refusing to run\n" msgstr "" #: src/dns/gnunet-service-dns.c:1581 msgid "Configured to provide DNS exit, but no valid DNS server configured!\n" msgstr "" #: src/dv/dv_api.c:179 #, fuzzy msgid "Failed to connect to the dv service!\n" msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" #: src/dv/plugin_transport_dv.c:159 #, fuzzy, c-format msgid "%s Received message from %s of type %d, distance %u!\n" msgstr "Beschädigte Nachricht von Knoten `%s' in %s:%d empfangen.\n" #: src/exit/gnunet-daemon-exit.c:508 #, c-format msgid "Got duplicate service records for `%s:%u'\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:563 #, fuzzy msgid "# Bytes transmitted via mesh tunnels" msgstr "# Bytes des Typs %d übertragen" #: src/exit/gnunet-daemon-exit.c:679 src/exit/gnunet-daemon-exit.c:2069 #: src/exit/gnunet-daemon-exit.c:2319 src/vpn/gnunet-service-vpn.c:1394 #: src/vpn/gnunet-service-vpn.c:1795 src/vpn/gnunet-service-vpn.c:1958 msgid "# ICMPv4 packets dropped (type not allowed)" msgstr "" #: src/exit/gnunet-daemon-exit.c:716 src/exit/gnunet-daemon-exit.c:2128 #: src/exit/gnunet-daemon-exit.c:2378 src/vpn/gnunet-service-vpn.c:1450 #: src/vpn/gnunet-service-vpn.c:1854 src/vpn/gnunet-service-vpn.c:1991 msgid "# ICMPv6 packets dropped (type not allowed)" msgstr "" #: src/exit/gnunet-daemon-exit.c:756 msgid "# ICMP packets dropped (not allowed)" msgstr "" #: src/exit/gnunet-daemon-exit.c:763 msgid "ICMP Packet dropped, have no matching connection information\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:840 msgid "UDP Packet dropped, have no matching connection information\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:915 msgid "TCP Packet dropped, have no matching connection information\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:968 #, fuzzy msgid "# Packets received from TUN" msgstr "# Bytes empfangen über HTTP" #: src/exit/gnunet-daemon-exit.c:982 #, fuzzy msgid "# Bytes received from TUN" msgstr "# Bytes empfangen über HTTP" #: src/exit/gnunet-daemon-exit.c:1008 msgid "IPv4 packet options received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1035 #, c-format msgid "IPv4 packet with unsupported next header %u received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1081 #, c-format msgid "IPv6 packet with unsupported next header %d received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1089 #, c-format msgid "Packet from unknown protocol %u received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1471 #, fuzzy msgid "# TCP packets sent via TUN" msgstr "# Bytes gesendet über UDP" #: src/exit/gnunet-daemon-exit.c:1571 #, fuzzy msgid "# TCP service creation requests received via mesh" msgstr "# Client Trace-Anfragen empfangen" #: src/exit/gnunet-daemon-exit.c:1574 src/exit/gnunet-daemon-exit.c:1653 #: src/exit/gnunet-daemon-exit.c:1763 src/exit/gnunet-daemon-exit.c:1993 #: src/exit/gnunet-daemon-exit.c:2235 src/exit/gnunet-daemon-exit.c:2516 #: src/exit/gnunet-daemon-exit.c:2616 #, fuzzy msgid "# Bytes received from MESH" msgstr "# Bytes empfangen über HTTP" #: src/exit/gnunet-daemon-exit.c:1607 src/exit/gnunet-daemon-exit.c:2638 #, c-format msgid "No service found for %s on port %d!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1611 #, fuzzy msgid "# TCP requests dropped (no such service)" msgstr "# gap Anfragen verworfen: Kollision in RT" #: src/exit/gnunet-daemon-exit.c:1656 #, fuzzy msgid "# TCP IP-exit creation requests received via mesh" msgstr "# Client Trace-Anfragen empfangen" #: src/exit/gnunet-daemon-exit.c:1766 #, fuzzy msgid "# TCP data requests received via mesh" msgstr "# Client Trace-Anfragen empfangen" #: src/exit/gnunet-daemon-exit.c:1780 #, fuzzy msgid "# TCP DATA requests dropped (no session)" msgstr "# gap Anfragen verworfen: Kollision in RT" #: src/exit/gnunet-daemon-exit.c:1830 #, fuzzy msgid "# ICMP packets sent via TUN" msgstr "# Bytes gesendet über UDP" #: src/exit/gnunet-daemon-exit.c:1996 #, fuzzy msgid "# ICMP IP-exit requests received via mesh" msgstr "# Client Trace-Anfragen empfangen" #: src/exit/gnunet-daemon-exit.c:2238 #, fuzzy msgid "# ICMP service requests received via mesh" msgstr "Empfangene Client-Nachricht ist ungültig.\n" #: src/exit/gnunet-daemon-exit.c:2304 src/vpn/gnunet-service-vpn.c:1384 #: src/vpn/gnunet-service-vpn.c:1952 msgid "# ICMPv4 packets dropped (impossible PT to v6)" msgstr "" #: src/exit/gnunet-daemon-exit.c:2363 src/vpn/gnunet-service-vpn.c:1420 #: src/vpn/gnunet-service-vpn.c:1432 src/vpn/gnunet-service-vpn.c:1842 msgid "# ICMPv6 packets dropped (impossible PT to v4)" msgstr "" #: src/exit/gnunet-daemon-exit.c:2413 #, fuzzy msgid "# UDP packets sent via TUN" msgstr "# Bytes gesendet über UDP" #: src/exit/gnunet-daemon-exit.c:2519 #, fuzzy msgid "# UDP IP-exit requests received via mesh" msgstr "# Client Trace-Anfragen empfangen" #: src/exit/gnunet-daemon-exit.c:2619 #, fuzzy msgid "# UDP service requests received via mesh" msgstr "# Client Trace-Anfragen empfangen" #: src/exit/gnunet-daemon-exit.c:2642 #, fuzzy msgid "# UDP requests dropped (no such service)" msgstr "# gap Anfragen verworfen: Kollision in RT" #: src/exit/gnunet-daemon-exit.c:2882 #, c-format msgid "No addresses found for hostname `%s' of service `%s'!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:2896 src/exit/gnunet-daemon-exit.c:2908 #, c-format msgid "Service `%s' configured for IPv4, but IPv4 is disabled!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:2919 #, c-format msgid "No IP addresses found for hostname `%s' of service `%s'!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3048 msgid "" "This system does not support IPv4, will disable IPv4 functions despite them " "being enabled in the configuration\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3056 msgid "" "This system does not support IPv6, will disable IPv6 functions despite them " "being enabled in the configuration\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3063 msgid "" "Cannot enable IPv4 exit but disable IPv4 on TUN interface, will use " "ENABLE_IPv4=YES\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3069 msgid "" "Cannot enable IPv6 exit but disable IPv6 on TUN interface, will use " "ENABLE_IPv6=YES\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3075 src/pt/gnunet-daemon-pt.c:884 msgid "No useful service enabled. Exiting.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3236 msgid "Daemon to run to provide an IP exit node for the VPN" msgstr "" #: src/fragmentation/defragmentation.c:270 msgid "# acknowledgements sent for fragment" msgstr "" #: src/fragmentation/defragmentation.c:456 #, fuzzy msgid "# fragments received" msgstr "# verworfener Nachrichten" #: src/fragmentation/defragmentation.c:521 #, fuzzy msgid "# duplicate fragments received" msgstr "# Bytes empfangen über TCP" #: src/fragmentation/defragmentation.c:534 msgid "# messages defragmented" msgstr "# defragmentierter Nachrichten" #: src/fragmentation/fragmentation.c:203 #, fuzzy msgid "# fragments transmitted" msgstr "# Selbstbekanntmachungen übertragen" #: src/fragmentation/fragmentation.c:206 #, fuzzy msgid "# fragments retransmitted" msgstr "# Selbstbekanntmachungen übertragen" #: src/fragmentation/fragmentation.c:232 #, fuzzy msgid "# fragments wrap arounds" msgstr "# Selbstbekanntmachungen übertragen" #: src/fragmentation/fragmentation.c:273 msgid "# messages fragmented" msgstr "# fragmentierter Nachrichten" #: src/fragmentation/fragmentation.c:276 msgid "# total size of fragmented messages" msgstr "" #: src/fragmentation/fragmentation.c:363 #, fuzzy msgid "# fragment acknowledgements received" msgstr "# Knotenankündigungen empfangen" #: src/fragmentation/fragmentation.c:369 msgid "# bits removed from fragmentation ACKs" msgstr "" #: src/fragmentation/fragmentation.c:393 #, fuzzy msgid "# fragmentation transmissions completed" msgstr "# Klartext PONG Nachrichten empfangen" #: src/fs/fs_api.c:339 #, fuzzy, c-format msgid "Could not open file `%s': %s" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/fs/fs_api.c:348 #, fuzzy, c-format msgid "Could not read file `%s': %s" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/fs/fs_api.c:354 #, c-format msgid "Short read reading from file `%s'!" msgstr "" #: src/fs/fs_api.c:938 #, fuzzy, c-format msgid "Failed to resume publishing information `%s': %s\n" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/fs/fs_api.c:1395 #, c-format msgid "Failed to recover namespace `%s', cannot resume publishing operation.\n" msgstr "" #: src/fs/fs_api.c:1437 #, c-format msgid "Failure while resuming publishing operation `%s': %s\n" msgstr "" #: src/fs/fs_api.c:1453 #, fuzzy, c-format msgid "Failed to resume publishing operation `%s': %s\n" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/fs/fs_api.c:2106 #, c-format msgid "Failure while resuming unindexing operation `%s': %s\n" msgstr "" #: src/fs/fs_api.c:2116 #, fuzzy, c-format msgid "Failed to resume unindexing operation `%s': %s\n" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/fs/fs_api.c:2241 src/fs/fs_api.c:2480 #, fuzzy, c-format msgid "Failed to resume sub-download `%s': %s\n" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/fs/fs_api.c:2258 #, fuzzy, c-format msgid "Failed to resume sub-search `%s': %s\n" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/fs/fs_api.c:2270 src/fs/fs_api.c:2289 src/fs/fs_api.c:2773 #, c-format msgid "Failure while resuming search operation `%s': %s\n" msgstr "" #: src/fs/fs_api.c:2471 #, c-format msgid "Failed to resume sub-download `%s': could not open file `%s'\n" msgstr "" #: src/fs/fs_api.c:2717 msgid "Could not resume running search, will resume as paused search\n" msgstr "" #: src/fs/fs_api.c:2811 #, c-format msgid "Failure while resuming download operation `%s': %s\n" msgstr "" #: src/fs/fs_directory.c:210 #, fuzzy msgid "MAGIC mismatch. This is not a GNUnet directory.\n" msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" #: src/fs/fs_download.c:311 #, fuzzy msgid "" "Recursive downloads of directories larger than 4 GB are not supported on 32-" "bit systems\n" msgstr "Rekursiver Download des Verzeichnisses `%s' bei %llu von %llu Bytes.\n" #: src/fs/fs_download.c:331 msgid "Directory too large for system address space\n" msgstr "" #: src/fs/fs_download.c:497 src/fs/fs_download.c:509 #, fuzzy, c-format msgid "Failed to open file `%s' for writing" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/fs/fs_download.c:878 #, fuzzy, c-format msgid "Failed to create directory for recursive download of `%s'\n" msgstr "Fehler beim Aktualisieren der Daten des Moduls `%s'\n" #: src/fs/fs_download.c:960 #, c-format msgid "" "Internal error or bogus download URI (expected %u bytes at depth %u and " "offset %llu/%llu, got %u bytes)" msgstr "" #: src/fs/fs_download.c:986 msgid "internal error decrypting content" msgstr "" #: src/fs/fs_download.c:1009 #, fuzzy, c-format msgid "Download failed: could not open file `%s': %s" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/fs/fs_download.c:1019 #, fuzzy, c-format msgid "Failed to seek to offset %llu in file `%s': %s" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/fs/fs_download.c:1028 #, fuzzy, c-format msgid "Failed to write block of %u bytes at offset %llu in file `%s': %s" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/fs/fs_download.c:1125 #, fuzzy msgid "internal error decoding tree" msgstr "=\tFehler beim Lesen des Verzeichnisses.\n" #: src/fs/fs_download.c:1888 #, fuzzy msgid "Invalid URI" msgstr "Ungültiger Parameter: `%s'\n" #: src/fs/fs_getopt.c:191 #, c-format msgid "" "Unknown metadata type in metadata option `%s'. Using metadata type " "`unknown' instead.\n" msgstr "" #: src/fs/fs_list_indexed.c:90 #, fuzzy, c-format msgid "Failed to receive response for `%s' request from `%s' service.\n" msgstr "Fehler beim Empfangen der Antwort von gnunetd auf die `%s' Nachricht\n" #: src/fs/fs_list_indexed.c:113 #, fuzzy, c-format msgid "Failed to receive valid response for `%s' request from `%s' service.\n" msgstr "Fehler beim Empfangen der Antwort von gnunetd auf die `%s' Nachricht\n" #: src/fs/fs_list_indexed.c:151 #, fuzzy, c-format msgid "Failed to not connect to `%s' service.\n" msgstr "`%s' Dienst konnte nicht initialisiert werden.\n" #: src/fs/fs_misc.c:126 #, fuzzy, c-format msgid "Did not find mime type `%s' in extension list.\n" msgstr "Knoten `%s' konnte nicht in der Routing Tabelle gefunden werden!\n" #: src/fs/fs_namespace_advertise.c:150 #, fuzzy msgid "Unknown error" msgstr "Unbekannter Fehler" #: src/fs/fs_namespace_advertise.c:238 src/fs/fs_namespace_advertise.c:259 #, fuzzy msgid "Failed to serialize meta data" msgstr "SQLite Datenbank konnte nicht initialisiert werden.\n" #: src/fs/fs_namespace_advertise.c:278 #, fuzzy msgid "Failed to connect to datastore service" msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" #: src/fs/fs_namespace.c:57 src/fs/fs_namespace.c:83 #, fuzzy, c-format msgid "Configuration fails to specify `%s' in section `%s'\n" msgstr "" "Die Konfigurationsdatei muss in der Sektion `%s' unter `%s' ein Verzeichnis " "angeben, in dem FS Daten gespeichert werden.\n" #: src/fs/fs_namespace.c:112 #, fuzzy, c-format msgid "Failed to open `%s' for writing: %s\n" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/fs/fs_namespace.c:134 src/fs/fs_namespace.c:222 #, fuzzy, c-format msgid "Failed to write `%s': %s\n" msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" #: src/fs/fs_namespace.c:256 #, fuzzy, c-format msgid "Failed to create or read private key for namespace `%s'\n" msgstr "Fehler beim Aktualisieren der Daten des Moduls `%s'\n" #: src/fs/fs_namespace.c:371 #, fuzzy, c-format msgid "Failed to read namespace private key file `%s', deleting it!\n" msgstr "" "Der Eintrag konnte dem Namespace `%s' nicht hinzugefügt werden (existiert " "er?)\n" #: src/fs/fs_namespace.c:588 src/fs/fs_publish_ksk.c:295 #, fuzzy msgid "Internal error." msgstr "Unbekannter Fehler.\n" #: src/fs/fs_namespace.c:631 #, fuzzy msgid "Failed to connect to datastore." msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden." #: src/fs/fs_publish.c:129 src/fs/fs_publish.c:397 #, fuzzy, c-format msgid "Publishing failed: %s" msgstr "" "\n" "Fehler beim Uploaden der Datei: %s\n" #: src/fs/fs_publish.c:621 src/fs/fs_publish.c:638 src/fs/fs_publish.c:677 #: src/fs/fs_publish.c:697 src/fs/fs_publish.c:722 src/fs/fs_publish.c:862 #, fuzzy, c-format msgid "Can not index file `%s': %s. Will try to insert instead.\n" msgstr "Indizieren der Datei `%s' schlug fehl. Versuch Datei einzufügen...\n" #: src/fs/fs_publish.c:623 msgid "timeout on index-start request to `fs' service" msgstr "" #: src/fs/fs_publish.c:635 #, fuzzy msgid "unknown error" msgstr "Unbekannter Fehler" #: src/fs/fs_publish.c:678 msgid "failed to compute hash" msgstr "" #: src/fs/fs_publish.c:698 msgid "filename too long" msgstr "" #: src/fs/fs_publish.c:723 #, fuzzy msgid "could not connect to `fs' service" msgstr "Verbindung zu gnunetd konnte nicht hergestellt werden.\n" #: src/fs/fs_publish.c:746 #, fuzzy, c-format msgid "Failed to get file identifiers for `%s'\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/fs/fs_publish.c:811 #, fuzzy, c-format msgid "Recursive upload failed at `%s': %s" msgstr "`%s' schlug fehl bei %s:%d mit dem Fehler: `%s'.\n" #: src/fs/fs_publish.c:817 #, fuzzy, c-format msgid "Recursive upload failed: %s" msgstr "" "\n" "Fehler beim Uploaden der Datei: %s\n" #: src/fs/fs_publish.c:863 #, fuzzy msgid "needs to be an actual file" msgstr "`%s' ist keine normale Datei.\n" #: src/fs/fs_publish.c:1071 #, c-format msgid "Insufficient space for publishing: %s" msgstr "" #: src/fs/fs_publish.c:1142 #, c-format msgid "Reserving space for %u entries and %llu bytes for publication\n" msgstr "" #: src/fs/fs_publish_ksk.c:258 #, fuzzy msgid "Could not connect to datastore." msgstr "Verbindung zu gnunetd konnte nicht hergestellt werden.\n" #: src/fs/fs_search.c:829 #, c-format msgid "Got result with unknown block type `%d', ignoring" msgstr "" #: src/fs/fs_test_lib.c:269 #, fuzzy, c-format msgid "Failed to start daemon: %s\n" msgstr "Fehler beim Starten der Collection.\n" #: src/fs/fs_unindex.c:58 msgid "Failed to find given position in file" msgstr "" #: src/fs/fs_unindex.c:63 #, fuzzy msgid "Failed to read file" msgstr "Zustellung der Nachricht `%s' fehlgeschlagen.\n" #: src/fs/fs_unindex.c:233 msgid "Unexpected time for a response from `fs' service." msgstr "" #: src/fs/fs_unindex.c:241 msgid "Timeout waiting for `fs' service." msgstr "" #: src/fs/fs_unindex.c:249 #, fuzzy msgid "Invalid response from `fs' service." msgstr "Ungültige Antwort auf `%s'.\n" #: src/fs/fs_unindex.c:293 #, fuzzy msgid "Failed to connect to FS service for unindexing." msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden." #: src/fs/fs_unindex.c:344 #, fuzzy msgid "Failed to get KSKs from directory scan." msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" #: src/fs/fs_unindex.c:356 #, fuzzy, c-format msgid "Internal error scanning `%s'.\n" msgstr "=\tFehler beim Lesen des Verzeichnisses.\n" #: src/fs/fs_unindex.c:411 #, fuzzy, c-format msgid "Failed to remove KBlock: %s\n" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/fs/fs_unindex.c:501 #, fuzzy, c-format msgid "Failed to parse URI `%s' from KBlock!\n" msgstr "Datei `%s' hat URI: %s\n" #: src/fs/fs_unindex.c:553 src/fs/fs_unindex.c:618 #, fuzzy msgid "Failed to connect to `datastore' service." msgstr "`%s' Dienst konnte nicht initialisiert werden.\n" #: src/fs/fs_unindex.c:631 #, fuzzy msgid "Failed to open file for unindexing." msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden." #: src/fs/fs_unindex.c:665 #, fuzzy msgid "Failed to compute hash of file." msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden." #: src/fs/fs_uri.c:220 #, c-format msgid "`%' must be followed by HEX number" msgstr "" #: src/fs/fs_uri.c:279 #, fuzzy msgid "Malformed KSK URI (must not begin or end with `+')" msgstr "Ungültige URL `%s' (muss mit `%s' beginnen)\n" #: src/fs/fs_uri.c:297 msgid "`++' not allowed in KSK URI" msgstr "" #: src/fs/fs_uri.c:304 msgid "Quotes not balanced in KSK URI" msgstr "" #: src/fs/fs_uri.c:372 src/fs/fs_uri.c:379 msgid "Malformed SKS URI" msgstr "" #: src/fs/fs_uri.c:423 src/fs/fs_uri.c:438 msgid "Malformed CHK URI" msgstr "" #: src/fs/fs_uri.c:568 src/fs/fs_uri.c:583 src/fs/fs_uri.c:593 #: src/fs/fs_uri.c:621 msgid "SKS URI malformed" msgstr "" #: src/fs/fs_uri.c:603 msgid "SKS URI malformed (could not decode public key)" msgstr "" #: src/fs/fs_uri.c:609 msgid "SKS URI malformed (could not find signature)" msgstr "" #: src/fs/fs_uri.c:615 msgid "SKS URI malformed (could not decode signature)" msgstr "" #: src/fs/fs_uri.c:628 msgid "SKS URI malformed (could not parse expiration time)" msgstr "" #: src/fs/fs_uri.c:640 msgid "SKS URI malformed (signature failed validation)" msgstr "" #: src/fs/fs_uri.c:678 msgid "Unrecognized URI type" msgstr "" #: src/fs/fs_uri.c:903 #, fuzzy msgid "Lacking key configuration settings.\n" msgstr "GNUnet Konfiguration" #: src/fs/fs_uri.c:910 #, fuzzy, c-format msgid "Could not access hostkey file `%s'.\n" msgstr "Konfigurationsdatei `%s' konnte nicht geparst werden.\n" #: src/fs/fs_uri.c:1115 src/fs/fs_uri.c:1142 msgid "No keywords specified!\n" msgstr "Keine Schlüsselwörter angegeben!\n" #: src/fs/fs_uri.c:1148 msgid "Number of double-quotes not balanced!\n" msgstr "" #: src/fs/gnunet-directory.c:49 #, c-format msgid "\t\n" msgstr "" #: src/fs/gnunet-directory.c:94 #, fuzzy, c-format msgid "Directory `%s' meta data:\n" msgstr "==> Verzeichnis `%s':\n" #: src/fs/gnunet-directory.c:97 #, fuzzy, c-format msgid "Directory `%s' contents:\n" msgstr "==> Verzeichnis `%s':\n" #: src/fs/gnunet-directory.c:132 #, fuzzy msgid "You must specify a filename to inspect.\n" msgstr "Sie müssen eine Liste von Dateien zum Einfügen angeben.\n" #: src/fs/gnunet-directory.c:145 #, fuzzy, c-format msgid "Failed to read directory `%s'\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/fs/gnunet-directory.c:154 #, fuzzy, c-format msgid "`%s' is not a GNUnet directory\n" msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" #: src/fs/gnunet-directory.c:179 #, fuzzy msgid "Display contents of a GNUnet directory" msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" #: src/fs/gnunet-download.c:101 #, fuzzy, c-format msgid "Starting download `%s'.\n" msgstr "Collection `%s' begonnen.\n" #: src/fs/gnunet-download.c:110 #, fuzzy msgid "" msgstr "Unbekannter Fehler" #: src/fs/gnunet-download.c:119 #, c-format msgid "" "Downloading `%s' at %llu/%llu (%s remaining, %s/s). Block took %s to " "download\n" msgstr "" #: src/fs/gnunet-download.c:129 #, fuzzy, c-format msgid "Error downloading: %s.\n" msgstr "Fehler beim Download: %s\n" #: src/fs/gnunet-download.c:137 #, fuzzy, c-format msgid "Downloading `%s' done (%s/s).\n" msgstr "Upload abgewiesen!" #: src/fs/gnunet-download.c:152 src/fs/gnunet-publish.c:190 #: src/fs/gnunet-search.c:190 src/fs/gnunet-unindex.c:109 #, c-format msgid "Unexpected status: %d\n" msgstr "" #: src/fs/gnunet-download.c:177 #, fuzzy msgid "You need to specify a URI argument.\n" msgstr "Sie müssen einen Empfänger angeben!\n" #: src/fs/gnunet-download.c:183 src/fs/gnunet-publish.c:624 #, fuzzy, c-format msgid "Failed to parse URI: %s\n" msgstr "Datei `%s' hat URI: %s\n" #: src/fs/gnunet-download.c:190 msgid "Only CHK or LOC URIs supported.\n" msgstr "" #: src/fs/gnunet-download.c:197 msgid "Target filename must be specified.\n" msgstr "" #: src/fs/gnunet-download.c:211 src/fs/gnunet-publish.c:602 #: src/fs/gnunet-search.c:241 src/fs/gnunet-unindex.c:141 #, fuzzy, c-format msgid "Could not initialize `%s' subsystem.\n" msgstr "`%s' Dienst konnte nicht initialisiert werden.\n" #: src/fs/gnunet-download.c:248 src/fs/gnunet-search.c:285 msgid "set the desired LEVEL of receiver-anonymity" msgstr "Den Grad LEVEL der gewünschten Empfänger-Anonymität setzen" #: src/fs/gnunet-download.c:251 msgid "delete incomplete downloads (when aborted with CTRL-C)" msgstr "" #: src/fs/gnunet-download.c:254 src/fs/gnunet-search.c:288 msgid "only search the local peer (no P2P network search)" msgstr "" #: src/fs/gnunet-download.c:257 msgid "write the file to FILENAME" msgstr "Schreibe die Datei in DATEINAME" #: src/fs/gnunet-download.c:261 msgid "set the maximum number of parallel downloads that is allowed" msgstr "" #: src/fs/gnunet-download.c:265 msgid "set the maximum number of parallel requests for blocks that is allowed" msgstr "" #: src/fs/gnunet-download.c:268 msgid "download a GNUnet directory recursively" msgstr "Das GNUnet Verzeichnis rekursiv herunterladen" #: src/fs/gnunet-download.c:278 msgid "" "Download files from GNUnet using a GNUnet CHK or LOC URI (gnunet://fs/" "chk/...)" msgstr "" #: src/fs/gnunet-fs.c:117 msgid "print a list of all indexed files" msgstr "" #: src/fs/gnunet-fs.c:124 #, fuzzy msgid "Special file-sharing operations" msgstr "Alle Optionen anzeigen" #: src/fs/gnunet-pseudonym.c:160 src/statistics/gnunet-statistics.c:167 #, fuzzy, c-format msgid "Invalid argument `%s'\n" msgstr "Ungültiger Parameter: `%s'\n" #: src/fs/gnunet-pseudonym.c:250 src/fs/gnunet-pseudonym.c:257 #: src/fs/gnunet-pseudonym.c:259 #, fuzzy, c-format msgid "Option `%s' ignored\n" msgstr "%s: Option `%s' ist mehrdeutig\n" #: src/fs/gnunet-pseudonym.c:279 src/fs/gnunet-publish.c:678 msgid "set the desired LEVEL of sender-anonymity" msgstr "Gewünschten Grad an Sender-Anonymität festlegen" #: src/fs/gnunet-pseudonym.c:282 msgid "create or advertise namespace NAME" msgstr "" #: src/fs/gnunet-pseudonym.c:285 msgid "delete namespace NAME " msgstr "" #: src/fs/gnunet-pseudonym.c:288 #, fuzzy msgid "" "add an additional keyword for the advertisment (this option can be specified " "multiple times)" msgstr "" "Ein zusätzliches Schlüsselwort für alle Dateien und Verzeichnisse hinzufügen " "(diese Option kann mehrmals angegeben werden)" #: src/fs/gnunet-pseudonym.c:292 src/fs/gnunet-publish.c:697 msgid "set the meta-data for the given TYPE to the given VALUE" msgstr "" "Die Meta-Daten des angegebenen Typs TYPE auf den angegebenen Wert VALUE " "setzen" #: src/fs/gnunet-pseudonym.c:295 #, fuzzy msgid "print names of local namespaces" msgstr "das Rating eines Namespaces setzen" #: src/fs/gnunet-pseudonym.c:298 msgid "use the given PRIORITY for the advertisments" msgstr "" #: src/fs/gnunet-pseudonym.c:301 msgid "do not print names of remote namespaces" msgstr "" #: src/fs/gnunet-pseudonym.c:304 src/fs/gnunet-publish.c:716 msgid "set the desired replication LEVEL" msgstr "" #: src/fs/gnunet-pseudonym.c:307 #, fuzzy msgid "specify ID of the root of the namespace" msgstr "das Rating eines Namespaces setzen" #: src/fs/gnunet-pseudonym.c:310 #, fuzzy msgid "change rating of namespace ID by VALUE" msgstr "das Rating eines Namespaces setzen" #: src/fs/gnunet-pseudonym.c:318 msgid "Manage GNUnet pseudonyms." msgstr "" #: src/fs/gnunet-publish.c:147 #, c-format msgid "Publishing `%s' at %llu/%llu (%s remaining)\n" msgstr "" #: src/fs/gnunet-publish.c:155 #, fuzzy, c-format msgid "Error publishing: %s.\n" msgstr "Fehler beim Download: %s\n" #: src/fs/gnunet-publish.c:165 #, c-format msgid "Publishing `%s' done.\n" msgstr "" #: src/fs/gnunet-publish.c:169 #, fuzzy, c-format msgid "URI is `%s'.\n" msgstr "Ich bin Peer `%s'.\n" #: src/fs/gnunet-publish.c:187 #, fuzzy msgid "Cleanup after abort complete.\n" msgstr "`%s' Startvorgang abgeschlossen.\n" #: src/fs/gnunet-publish.c:305 #, fuzzy, c-format msgid "Meta data for file `%s' (%s)\n" msgstr "Daten des Moduls `%s' werden aktualisiert\n" #: src/fs/gnunet-publish.c:307 #, fuzzy, c-format msgid "Keywords for file `%s' (%s)\n" msgstr "Schlüsselwörter für Datei `%s':\n" #: src/fs/gnunet-publish.c:358 #, fuzzy, c-format msgid "Failed to create namespace `%s'\n" msgstr "Namespace `%s' konnte nicht erstellt werden (existiert bereits?).\n" #: src/fs/gnunet-publish.c:433 #, fuzzy msgid "Could not publish\n" msgstr "`%s' konnte nicht aufgelöst werden: %s\n" #: src/fs/gnunet-publish.c:460 #, fuzzy msgid "Could not start publishing.\n" msgstr "Anwendung `%s' konnte nicht initialisiert werden.\n" #: src/fs/gnunet-publish.c:491 #, fuzzy, c-format msgid "Scanning directory `%s'.\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/fs/gnunet-publish.c:493 #, fuzzy, c-format msgid "Scanning file `%s'.\n" msgstr "Collection `%s' begonnen.\n" #: src/fs/gnunet-publish.c:498 #, c-format msgid "There was trouble processing file `%s', skipping it.\n" msgstr "" #: src/fs/gnunet-publish.c:503 #, fuzzy msgid "Preprocessing complete.\n" msgstr "GNUnet wurde erfolgreich heruntergefahren.\n" #: src/fs/gnunet-publish.c:507 #, fuzzy, c-format msgid "Extracting meta data from file `%s' complete.\n" msgstr "Daten des Moduls `%s' werden aktualisiert\n" #: src/fs/gnunet-publish.c:511 msgid "Meta data extraction has finished.\n" msgstr "" #: src/fs/gnunet-publish.c:518 #, fuzzy msgid "Internal error scanning directory.\n" msgstr "=\tFehler beim Lesen des Verzeichnisses.\n" #: src/fs/gnunet-publish.c:552 #, c-format msgid "Cannot extract metadata from a URI!\n" msgstr "" #: src/fs/gnunet-publish.c:559 #, c-format msgid "You must specify one and only one filename for insertion.\n" msgstr "Sie dürfen nur eine Datei zum Deindizieren angeben.\n" #: src/fs/gnunet-publish.c:565 #, fuzzy, c-format msgid "You must NOT specify an URI and a filename.\n" msgstr "Sie müssen einen Empfänger angeben!\n" #: src/fs/gnunet-publish.c:573 src/vpn/gnunet-vpn.c:214 #, fuzzy, c-format msgid "Option `%s' is required when using option `%s'.\n" msgstr "Option `%s' macht keinen Sinn ohne die Option `%s'.\n" #: src/fs/gnunet-publish.c:583 src/fs/gnunet-publish.c:590 #: src/transport/gnunet-transport.c:560 #, c-format msgid "Option `%s' makes no sense without option `%s'.\n" msgstr "Option `%s' macht keinen Sinn ohne die Option `%s'.\n" #: src/fs/gnunet-publish.c:612 #, fuzzy, c-format msgid "Could not create namespace `%s'\n" msgstr "Namespace `%s' konnte nicht erstellt werden (existiert bereits?).\n" #: src/fs/gnunet-publish.c:645 #, fuzzy, c-format msgid "Failed to access `%s': %s\n" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/fs/gnunet-publish.c:657 msgid "" "Failed to start meta directory scanner. Is gnunet-helper-publish-fs " "installed?\n" msgstr "" #: src/fs/gnunet-publish.c:682 msgid "disable adding the creation time to the metadata of the uploaded file" msgstr "" #: src/fs/gnunet-publish.c:685 msgid "do not use libextractor to add keywords or metadata" msgstr "" #: src/fs/gnunet-publish.c:689 msgid "" "print list of extracted keywords that would be used, but do not perform " "upload" msgstr "" "Liste der extrahierten Schlüsselworte, die verwendet werden würden, " "ausgeben, aber keinen Upload durchführen" #: src/fs/gnunet-publish.c:693 msgid "" "add an additional keyword for the top-level file or directory (this option " "can be specified multiple times)" msgstr "" "Ein zusätzliches Schlüsselwort für die Datei oder das Verzeichnis auf der " "obersten Ebene hinzufügen (diese Option kann mehrmals angegeben werden)" #: src/fs/gnunet-publish.c:700 msgid "" "do not index, perform full insertion (stores entire file in encrypted form " "in GNUnet database)" msgstr "" "Nicht indizieren, sondern komplett einfügen (speichert die gesamte Datei in " "verschlüsselter Form in der GNUnet Datenbank)" #: src/fs/gnunet-publish.c:705 msgid "" "specify ID of an updated version to be published in the future (for " "namespace insertions only)" msgstr "" "ID einer aktualisierten Version angeben, die in der Zukunft veröffentlich " "werden soll. (nur für das Einfügen in Namespaces)" #: src/fs/gnunet-publish.c:709 msgid "specify the priority of the content" msgstr "Die Priorität des Inhalts angeben" #: src/fs/gnunet-publish.c:713 msgid "publish the files under the pseudonym NAME (place file into namespace)" msgstr "" "Die Datei unter dem Pseudonym NAME veröffentlichen (platziert die Datei in " "einem Namespace)" #: src/fs/gnunet-publish.c:719 msgid "" "only simulate the process but do not do any actual publishing (useful to " "compute URIs)" msgstr "" #: src/fs/gnunet-publish.c:723 msgid "" "set the ID of this version of the publication (for namespace insertions only)" msgstr "" "die ID dieser Version der Veröffentlichung setzen (nur für das Einfügen in " "Namespaces)" #: src/fs/gnunet-publish.c:727 msgid "" "URI to be published (can be used instead of passing a file to add keywords " "to the file with the respective URI)" msgstr "" #: src/fs/gnunet-publish.c:742 msgid "Publish a file or directory on GNUnet" msgstr "" #: src/fs/gnunet-search.c:111 #, c-format msgid "Failed to write directory with search results to `%s'\n" msgstr "" #: src/fs/gnunet-search.c:181 #, fuzzy, c-format msgid "Error searching: %s.\n" msgstr "Fehler beim Verlassen der DHT.\n" #: src/fs/gnunet-search.c:231 #, fuzzy msgid "Could not create keyword URI from arguments.\n" msgstr "Namespace `%s' konnte nicht erstellt werden (existiert bereits?).\n" #: src/fs/gnunet-search.c:255 #, fuzzy msgid "Could not start searching.\n" msgstr "Namespace `%s' konnte nicht erstellt werden (existiert bereits?).\n" #: src/fs/gnunet-search.c:291 msgid "write search results to file starting with PREFIX" msgstr "" #: src/fs/gnunet-search.c:294 msgid "automatically terminate search after VALUE ms" msgstr "" #: src/fs/gnunet-search.c:301 msgid "automatically terminate search after VALUE results are found" msgstr "" #: src/fs/gnunet-search.c:308 msgid "Search GNUnet for files that were published on GNUnet" msgstr "" #: src/fs/gnunet-service-fs.c:240 msgid "# running average P2P latency (ms)" msgstr "" #: src/fs/gnunet-service-fs.c:300 src/fs/gnunet-service-fs.c:489 #, fuzzy msgid "# Loopback routes suppressed" msgstr "# gap Routing erfolgreich (insgesamt)" #: src/fs/gnunet-service-fs.c:581 src/hostlist/gnunet-daemon-hostlist.c:297 #: src/topology/gnunet-daemon-topology.c:1330 #: src/topology/gnunet-daemon-topology.c:1337 #, fuzzy, c-format msgid "Failed to connect to `%s' service.\n" msgstr "`%s' Dienst konnte nicht initialisiert werden.\n" #: src/fs/gnunet-service-fs_cp.c:696 #, fuzzy msgid "# migration stop messages received" msgstr "# verschlüsselter PING Nachrichten empfangen" #: src/fs/gnunet-service-fs_cp.c:700 #, c-format msgid "Migration of content to peer `%s' blocked for %llu ms\n" msgstr "" #: src/fs/gnunet-service-fs_cp.c:735 #, fuzzy msgid "# replies transmitted to other peers" msgstr "# Bytes des Typs %d übertragen" #: src/fs/gnunet-service-fs_cp.c:741 msgid "# replies dropped" msgstr "" #: src/fs/gnunet-service-fs_cp.c:766 src/fs/gnunet-service-fs_cp.c:1324 msgid "# P2P searches active" msgstr "" #: src/fs/gnunet-service-fs_cp.c:858 msgid "# artificial delays introduced (ms)" msgstr "" #: src/fs/gnunet-service-fs_cp.c:911 #, fuzzy msgid "# replies dropped due to type mismatch" msgstr "# gap Anfragen verworfen: Kollision in RT" #: src/fs/gnunet-service-fs_cp.c:919 #, fuzzy msgid "# replies received for other peers" msgstr "# Bytes des Typs %d empfangen" #: src/fs/gnunet-service-fs_cp.c:933 msgid "# replies dropped due to insufficient cover traffic" msgstr "" #: src/fs/gnunet-service-fs_cp.c:971 msgid "# P2P searches destroyed due to ultimate reply" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1038 #, fuzzy msgid "# requests done for free (low load)" msgstr "# gap Anfragen verworfen: Kollision in RT" #: src/fs/gnunet-service-fs_cp.c:1062 msgid "# request dropped, priority insufficient" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1072 #, fuzzy msgid "# requests done for a price (normal load)" msgstr "# gap Anfragen verworfen: Kollision in RT" #: src/fs/gnunet-service-fs_cp.c:1151 msgid "# GET requests received (from other peers)" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1185 #, fuzzy msgid "# requests dropped due to initiator not being connected" msgstr "# gap Anfragen verworfen: Kollision in RT" #: src/fs/gnunet-service-fs_cp.c:1207 #, fuzzy msgid "# requests dropped due to missing reverse route" msgstr "# gap Anfragen verworfen: Kollision in RT" #: src/fs/gnunet-service-fs_cp.c:1267 #, fuzzy msgid "# requests dropped due TTL underflow" msgstr "# gap Anfragen verworfen: Kollision in RT" #: src/fs/gnunet-service-fs_cp.c:1293 #, fuzzy msgid "# requests dropped due to higher-TTL request" msgstr "# gap Anfragen verworfen: Kollision in RT" #: src/fs/gnunet-service-fs_cp.c:1322 #, fuzzy msgid "# P2P query messages received and processed" msgstr "# verschlüsselter PING Nachrichten empfangen" #: src/fs/gnunet-service-fs_cp.c:1687 #, fuzzy msgid "# migration stop messages sent" msgstr "# verschlüsselter PING Nachrichten empfangen" #: src/fs/gnunet-service-fs_indexing.c:113 #: src/fs/gnunet-service-fs_indexing.c:163 #, fuzzy, c-format msgid "Configuration option `%s' in section `%s' missing.\n" msgstr "Konfigurationsdatei `%s' wurde erzeugt.\n" #: src/fs/gnunet-service-fs_indexing.c:121 #: src/fs/gnunet-service-fs_indexing.c:177 #, fuzzy, c-format msgid "Could not open `%s'.\n" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/fs/gnunet-service-fs_indexing.c:137 #, fuzzy, c-format msgid "Error writing `%s'.\n" msgstr "Fehler beim Anlegen des Benutzers" #: src/fs/gnunet-service-fs_indexing.c:228 #, c-format msgid "" "Index request received for file `%s' is already indexed as `%s'. Permitting " "anyway.\n" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:266 #, c-format msgid "Hash mismatch trying to index file `%s' which has hash `%s'\n" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:481 #, fuzzy, c-format msgid "Failed to delete bogus block: %s\n" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/fs/gnunet-service-fs_indexing.c:539 msgid "# index blocks removed: original file inaccessible" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:554 #, fuzzy, c-format msgid "Could not access indexed file `%s' (%s) at offset %llu: %s\n" msgstr "`%s' konnte nicht aufgelöst werden: %s\n" #: src/fs/gnunet-service-fs_indexing.c:556 #, fuzzy msgid "not indexed" msgstr "Deindizierung schlug fehl." #: src/fs/gnunet-service-fs_indexing.c:571 #, fuzzy, c-format msgid "Indexed file `%s' changed at offset %llu\n" msgstr "Indizierung der Daten schlug an Position %i fehl.\n" #: src/fs/gnunet-service-fs_lc.c:202 src/fs/gnunet-service-fs_lc.c:362 #: src/fs/gnunet-service-fs_lc.c:488 #, fuzzy msgid "# client searches active" msgstr "# gap Anfragen insgesamt empfangen" #: src/fs/gnunet-service-fs_lc.c:256 #, fuzzy msgid "# replies received for local clients" msgstr "# gap Anfragen insgesamt empfangen" #: src/fs/gnunet-service-fs_lc.c:321 #, fuzzy msgid "# client searches received" msgstr "# gap Anfragen insgesamt empfangen" #: src/fs/gnunet-service-fs_lc.c:356 msgid "# client searches updated (merged content seen list)" msgstr "" #: src/fs/gnunet-service-fs_pe.c:265 msgid "# average retransmission delay (ms)" msgstr "" #: src/fs/gnunet-service-fs_pe.c:391 #, fuzzy msgid "# transmission failed (core has no bandwidth)" msgstr "Kein Transport des Typs %d bekannt.\n" #: src/fs/gnunet-service-fs_pe.c:420 #, fuzzy msgid "# query messages sent to other peers" msgstr "# Bytes ausgehender Nachrichten verworfen" #: src/fs/gnunet-service-fs_pe.c:469 msgid "# delay heap timeout" msgstr "" #: src/fs/gnunet-service-fs_pe.c:476 #, fuzzy msgid "# query plans executed" msgstr "# dht Anfragen weitergeleitet" #: src/fs/gnunet-service-fs_pe.c:538 #, fuzzy msgid "# requests merged" msgstr "# Client Trace-Anfragen empfangen" #: src/fs/gnunet-service-fs_pe.c:544 #, fuzzy msgid "# requests refreshed" msgstr "# Client Trace-Anfragen empfangen" #: src/fs/gnunet-service-fs_pe.c:597 src/fs/gnunet-service-fs_pe.c:681 #: src/fs/gnunet-service-fs_pe.c:748 msgid "# query plan entries" msgstr "" #: src/fs/gnunet-service-fs_pr.c:285 #, fuzzy msgid "# Pending requests created" msgstr "# Client Trace-Anfragen empfangen" #: src/fs/gnunet-service-fs_pr.c:367 src/fs/gnunet-service-fs_pr.c:616 #, fuzzy msgid "# Pending requests active" msgstr "# Client Trace-Anfragen empfangen" #: src/fs/gnunet-service-fs_pr.c:779 #, fuzzy msgid "# replies received and matched" msgstr "# Bytes empfangen über TCP" #: src/fs/gnunet-service-fs_pr.c:808 msgid "# duplicate replies discarded (bloomfilter)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:822 #, c-format msgid "Unsupported block type %u\n" msgstr "" #: src/fs/gnunet-service-fs_pr.c:835 msgid "# results found locally" msgstr "" #: src/fs/gnunet-service-fs_pr.c:953 msgid "# Datastore `PUT' failures" msgstr "" #: src/fs/gnunet-service-fs_pr.c:980 #, fuzzy msgid "# storage requests dropped due to high load" msgstr "# gap Anfragen verworfen: Kollision in RT" #: src/fs/gnunet-service-fs_pr.c:1015 #, fuzzy msgid "# Replies received from DHT" msgstr "# Bytes empfangen über HTTP" #: src/fs/gnunet-service-fs_pr.c:1106 #, c-format msgid "Datastore lookup already took %llu ms!\n" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1127 #, c-format msgid "On-demand lookup already took %llu ms!\n" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1174 msgid "# Datastore lookups concluded (no results)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1188 msgid "# Datastore lookups concluded (seen all)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1197 msgid "# Datastore lookups aborted (more than MAX_RESULTS)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1211 msgid "# requested DBLOCK or IBLOCK not found" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1224 msgid "# on-demand blocks matched requests" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1237 msgid "# on-demand lookups performed successfully" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1242 msgid "# on-demand lookups failed" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1269 src/fs/gnunet-service-fs_pr.c:1309 #: src/fs/gnunet-service-fs_pr.c:1447 msgid "# Datastore lookups concluded (error queueing)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1327 msgid "# Datastore lookups concluded (found last result)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1338 msgid "# Datastore lookups concluded (load too high)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1424 msgid "# Datastore lookups initiated" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1508 #, fuzzy msgid "# GAP PUT messages received" msgstr "# verschlüsselter PONG Nachrichten empfangen" #: src/fs/gnunet-service-fs_pr.c:1601 src/fs/gnunet-service-fs_pr.c:1610 #, fuzzy, c-format msgid "Configuration fails to specify `%s', assuming default value." msgstr "Konfigurationsdatei `%s' wurde erzeugt.\n" #: src/fs/gnunet-service-fs_push.c:629 #, c-format msgid "" "Invalid value specified for option `%s' in section `%s', content pushing " "disabled\n" msgstr "" #: src/fs/gnunet-unindex.c:89 #, c-format msgid "Unindexing at %llu/%llu (%s remaining)\n" msgstr "" #: src/fs/gnunet-unindex.c:96 #, fuzzy, c-format msgid "Error unindexing: %s.\n" msgstr "" "\n" "Fehler beim Deindizieren der Datei: %s\n" #: src/fs/gnunet-unindex.c:101 #, fuzzy msgid "Unindexing done.\n" msgstr "Dateien deindizieren." #: src/fs/gnunet-unindex.c:131 #, fuzzy, c-format msgid "You must specify one and only one filename for unindexing.\n" msgstr "Sie dürfen nur eine Datei zum Deindizieren angeben.\n" #: src/fs/gnunet-unindex.c:148 #, fuzzy msgid "Could not start unindex operation.\n" msgstr "Auf die Namespace Informationen konnte nicht zugegriffen werden.\n" #: src/fs/gnunet-unindex.c:176 msgid "Unindex a file that was previously indexed with gnunet-publish." msgstr "" #: src/fs/plugin_block_fs.c:131 msgid "Reply mismatched in terms of namespace. Discarded.\n" msgstr "" #: src/gns/gnunet-gns.c:191 #, fuzzy msgid "Failed to connect to GNS\n" msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" #: src/gns/gnunet-gns.c:232 msgid "try to shorten a given GNS name" msgstr "" #: src/gns/gnunet-gns.c:235 msgid "Lookup a record using GNS (NOT IMPLEMENTED)" msgstr "" #: src/gns/gnunet-gns.c:238 msgid "Get the authority of a particular name" msgstr "" #: src/gns/gnunet-gns.c:241 #, fuzzy msgid "Specify the type of the record lookup" msgstr "Die Priorität des Inhalts angeben" #: src/gns/gnunet-gns.c:244 msgid "No unneeded output" msgstr "" #: src/gns/gnunet-gns.c:255 msgid "GNUnet GNS access tool" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:280 #, fuzzy, c-format msgid "Unsupported form value `%s'\n" msgstr "Kommando `%s' wird nicht unterstützt. Vorgang wird abgebrochen.\n" #: src/gns/gnunet-gns-fcfsd.c:333 #, fuzzy, c-format msgid "Failed to create record for domain `%s': %s\n" msgstr "Konfigurationsdatei `%s' konnte nicht geparst werden.\n" #: src/gns/gnunet-gns-fcfsd.c:377 #, c-format msgid "Found existing name `%s' for the given key\n" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:439 #, c-format msgid "Found %u existing records for domain `%s'\n" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:498 #, fuzzy, c-format msgid "Failed to create page for `%s'\n" msgstr "Namespace `%s' konnte nicht erstellt werden (existiert bereits?).\n" #: src/gns/gnunet-gns-fcfsd.c:514 #, fuzzy, c-format msgid "Failed to setup post processor for `%s'\n" msgstr "Fehler beim Aktualisieren der Daten des Moduls `%s'\n" #: src/gns/gnunet-gns-fcfsd.c:725 src/gns/gnunet-gns-fcfsd.c:737 #, fuzzy, c-format msgid "Option `%s' not specified in configuration section `%s'\n" msgstr "" "Option `%s' ist in der Konfigurationsdatei in der Sektion `%s' nicht " "gesetzt, sie wird auf %dm gesetzt.\n" #: src/gns/gnunet-gns-fcfsd.c:747 src/namestore/gnunet-namestore.c:299 #, fuzzy msgid "Failed to read or create private zone key\n" msgstr "Fehler beim Aktualisieren der Daten des Moduls `%s'\n" #: src/gns/gnunet-gns-fcfsd.c:757 src/namestore/gnunet-namestore.c:310 #, fuzzy msgid "Failed to connect to namestore\n" msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden." #: src/gns/gnunet-gns-fcfsd.c:773 src/gns/gnunet-gns-proxy.c:525 #, fuzzy msgid "Failed to start HTTP server\n" msgstr "Fehler beim Starten der Collection.\n" #: src/gns/gnunet-gns-fcfsd.c:804 msgid "GNUnet GNS first come first serve registration service" msgstr "" #: src/gns/gnunet-gns-proxy.c:800 msgid "listen on specified port" msgstr "" #: src/gns/gnunet-gns-proxy.c:811 msgid "GNUnet GNS proxy" msgstr "" #: src/hello/gnunet-hello.c:122 msgid "Call with name of HELLO file to modify.\n" msgstr "" #: src/hello/gnunet-hello.c:128 #, fuzzy, c-format msgid "Error accessing file `%s': %s\n" msgstr "Fehler beim Anlegen des Benutzers" #: src/hello/gnunet-hello.c:136 #, c-format msgid "File `%s' is too big to be a HELLO\n" msgstr "" #: src/hello/gnunet-hello.c:143 #, c-format msgid "File `%s' is too small to be a HELLO\n" msgstr "" #: src/hello/gnunet-hello.c:153 src/hello/gnunet-hello.c:181 #, fuzzy, c-format msgid "Error opening file `%s': %s\n" msgstr "Fehler beim Anlegen des Benutzers" #: src/hello/gnunet-hello.c:169 #, fuzzy, c-format msgid "Did not find well-formed HELLO in file `%s'\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/hello/gnunet-hello.c:193 #, fuzzy, c-format msgid "Error writing HELLO to file `%s': %s\n" msgstr "Fehler beim Anlegen des Benutzers" #: src/hostlist/gnunet-daemon-hostlist.c:264 msgid "" "None of the functions for the hostlist daemon were enabled. I have no " "reason to run!\n" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:317 msgid "advertise our hostlist to other peers" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:322 msgid "" "bootstrap using hostlists (it is highly recommended that you always use this " "option)" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:325 msgid "enable learning about hostlist servers from other peers" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:329 msgid "provide a hostlist server" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:341 msgid "GNUnet hostlist server and client" msgstr "" #: src/hostlist/hostlist-client.c:289 msgid "# bytes downloaded from hostlist servers" msgstr "" #: src/hostlist/hostlist-client.c:310 src/hostlist/hostlist-client.c:340 #, fuzzy msgid "# invalid HELLOs downloaded from hostlist servers" msgstr "# Hellos per HTTP heruntergeladen" #: src/hostlist/hostlist-client.c:313 src/hostlist/hostlist-client.c:343 #, fuzzy, c-format msgid "Invalid `%s' message received from hostlist at `%s'\n" msgstr "Ungültige `%s' Nachricht von Knoten `%s' empfangen.\n" #: src/hostlist/hostlist-client.c:331 #, fuzzy msgid "# valid HELLOs downloaded from hostlist servers" msgstr "# Hellos per HTTP heruntergeladen" #: src/hostlist/hostlist-client.c:375 src/hostlist/hostlist-client.c:396 #, c-format msgid "No `%s' specified in `%s' configuration, will not bootstrap.\n" msgstr "" #: src/hostlist/hostlist-client.c:473 src/hostlist/hostlist-client.c:683 #: src/hostlist/hostlist-client.c:689 src/hostlist/hostlist-client.c:741 #: src/hostlist/hostlist-client.c:750 src/hostlist/hostlist-client.c:871 #: src/hostlist/hostlist-client.c:961 src/hostlist/hostlist-client.c:966 #: src/transport/plugin_transport_http_client.c:110 #: src/transport/plugin_transport_http_client.c:125 #, c-format msgid "%s failed at %s:%d: `%s'\n" msgstr "`%s' schlug fehl bei %s:%d mit dem Fehler: `%s'.\n" #: src/hostlist/hostlist-client.c:593 src/hostlist/hostlist-client.c:1331 msgid "# advertised hostlist URIs" msgstr "" #: src/hostlist/hostlist-client.c:623 #, c-format msgid "# advertised URI `%s' downloaded" msgstr "" #: src/hostlist/hostlist-client.c:664 #, c-format msgid "" "Advertised hostlist with URI `%s' could not be downloaded. Advertised URI " "gets dismissed.\n" msgstr "" #: src/hostlist/hostlist-client.c:802 #, fuzzy, c-format msgid "Timeout trying to download hostlist from `%s'\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/hostlist/hostlist-client.c:816 #, c-format msgid "Download limit of %u bytes exceeded, stopping download\n" msgstr "" #: src/hostlist/hostlist-client.c:836 #, fuzzy, c-format msgid "Download of hostlist from `%s' failed: `%s'\n" msgstr "" "Upload von `%s' komplett, derzeitige durchschnittliche Geschwindigkeit " "beträgt %8.3f KB/s.\n" #: src/hostlist/hostlist-client.c:842 #, fuzzy, c-format msgid "Download of hostlist `%s' completed.\n" msgstr "" "Upload von `%s' komplett, derzeitige durchschnittliche Geschwindigkeit " "beträgt %8.3f KB/s.\n" #: src/hostlist/hostlist-client.c:850 #, c-format msgid "Adding successfully tested hostlist `%s' datastore.\n" msgstr "" #: src/hostlist/hostlist-client.c:903 #, c-format msgid "Bootstrapping using hostlist at `%s'.\n" msgstr "" #: src/hostlist/hostlist-client.c:911 msgid "# hostlist downloads initiated" msgstr "" #: src/hostlist/hostlist-client.c:1037 src/hostlist/hostlist-client.c:1505 msgid "# milliseconds between hostlist downloads" msgstr "" #: src/hostlist/hostlist-client.c:1046 #, c-format msgid "Have %u/%u connections. Will consider downloading hostlist in %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1084 msgid "Scheduled saving of hostlists\n" msgstr "" #: src/hostlist/hostlist-client.c:1088 #, c-format msgid "Hostlists will be saved to file again in %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1111 src/hostlist/hostlist-client.c:1127 #, fuzzy msgid "# active connections" msgstr "GNUnet Konfiguration" #: src/hostlist/hostlist-client.c:1242 #, c-format msgid "Initial time between hostlist downloads is %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1273 #, c-format msgid "" "No `%s' specified in `%s' configuration, cannot load hostlists from file.\n" msgstr "" #: src/hostlist/hostlist-client.c:1279 #, fuzzy, c-format msgid "Loading saved hostlist entries from file `%s' \n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/hostlist/hostlist-client.c:1283 #, c-format msgid "Hostlist file `%s' is not existing\n" msgstr "" #: src/hostlist/hostlist-client.c:1294 #, fuzzy, c-format msgid "Could not open file `%s' for reading to load hostlists: %s\n" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/hostlist/hostlist-client.c:1327 #, c-format msgid "%u hostlist URIs loaded from file\n" msgstr "" #: src/hostlist/hostlist-client.c:1329 msgid "# hostlist URIs read from file" msgstr "" #: src/hostlist/hostlist-client.c:1362 #, c-format msgid "" "No `%s' specified in `%s' configuration, cannot save hostlists to file.\n" msgstr "" #: src/hostlist/hostlist-client.c:1376 #, fuzzy, c-format msgid "Could not open file `%s' for writing to save hostlists: %s\n" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/hostlist/hostlist-client.c:1381 #, fuzzy, c-format msgid "Writing %u hostlist URIs to `%s'\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/hostlist/hostlist-client.c:1405 src/hostlist/hostlist-client.c:1422 #, c-format msgid "Error writing hostlist URIs to file `%s'\n" msgstr "" #: src/hostlist/hostlist-client.c:1417 msgid "# hostlist URIs written to file" msgstr "" #: src/hostlist/hostlist-client.c:1470 msgid "Learning is enabled on this peer\n" msgstr "" #: src/hostlist/hostlist-client.c:1473 #, c-format msgid "Hostlists will be saved to file again in %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1482 msgid "Learning is not enabled on this peer\n" msgstr "" #: src/hostlist/hostlist-client.c:1494 #, c-format msgid "" "Since learning is not enabled on this peer, hostlist file `%s' was removed\n" msgstr "" #: src/hostlist/hostlist-client.c:1498 #, fuzzy, c-format msgid "Hostlist file `%s' could not be removed\n" msgstr "Sitzungsschlüssel von Knoten `%s' konnte nicht überprüft werden.\n" #: src/hostlist/hostlist-server.c:134 #, fuzzy msgid "bytes in hostlist" msgstr "# bytes in der Datenbank" #: src/hostlist/hostlist-server.c:157 msgid "expired addresses encountered" msgstr "" #: src/hostlist/hostlist-server.c:184 src/hostlist/hostlist-server.c:425 #: src/peerinfo-tool/gnunet-peerinfo.c:403 #: src/peerinfo-tool/gnunet-peerinfo.c:519 #: src/topology/gnunet-daemon-topology.c:927 #, fuzzy, c-format msgid "Error in communication with PEERINFO service: %s\n" msgstr "Informationen über andere GNUnet Knoten ausgeben." #: src/hostlist/hostlist-server.c:205 msgid "HELLOs without addresses encountered (ignored)" msgstr "" #: src/hostlist/hostlist-server.c:219 msgid "bytes not included in hostlist (size limit)" msgstr "" #: src/hostlist/hostlist-server.c:263 #, fuzzy, c-format msgid "Refusing `%s' request to hostlist server\n" msgstr "Fehler beim Senden einer `%s' Anfrage an den SMTP Server.\n" #: src/hostlist/hostlist-server.c:266 #, fuzzy msgid "hostlist requests refused (not HTTP GET)" msgstr "# Client Trace-Anfragen empfangen" #: src/hostlist/hostlist-server.c:273 msgid "Sending 100 CONTINUE reply\n" msgstr "" #: src/hostlist/hostlist-server.c:279 #, c-format msgid "Refusing `%s' request with %llu bytes of upload data\n" msgstr "" #: src/hostlist/hostlist-server.c:283 #, fuzzy msgid "hostlist requests refused (upload data)" msgstr "# Client Trace-Anfragen empfangen" #: src/hostlist/hostlist-server.c:291 msgid "Could not handle hostlist request since I do not have a response yet\n" msgstr "" #: src/hostlist/hostlist-server.c:294 #, fuzzy msgid "hostlist requests refused (not ready)" msgstr "# Client Trace-Anfragen empfangen" #: src/hostlist/hostlist-server.c:298 msgid "Received request for our hostlist\n" msgstr "" #: src/hostlist/hostlist-server.c:299 #, fuzzy msgid "hostlist requests processed" msgstr "# Client Trace-Anfragen empfangen" #: src/hostlist/hostlist-server.c:341 #, fuzzy msgid "# hostlist advertisements send" msgstr "# Bekanntmachungen von anderen übertragen" #: src/hostlist/hostlist-server.c:388 msgid "Advertisement message could not be queued by core\n" msgstr "" #: src/hostlist/hostlist-server.c:561 #, fuzzy, c-format msgid "Invalid port number %llu. Exiting.\n" msgstr "Ungültige Parameter. Abbruch.\n" #: src/hostlist/hostlist-server.c:570 #, c-format msgid "Hostlist service starts on %s:%llu\n" msgstr "" #: src/hostlist/hostlist-server.c:584 #, fuzzy, c-format msgid "Address to obtain hostlist: `%s'\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/hostlist/hostlist-server.c:624 #, fuzzy, c-format msgid "`%s' is not a valid IP address! Ignoring BINDTOIP.\n" msgstr "`%s' ist nicht verfügbar." #: src/hostlist/hostlist-server.c:666 #, fuzzy, c-format msgid "Could not start hostlist HTTP server on port %u\n" msgstr "Der Transportdienst auf Port %d konnte nicht gestartet werden.\n" #: src/integration-tests/connection_watchdog.c:997 #, fuzzy, c-format msgid "Transport plugin: `%s' port %llu\n" msgstr "Der Transportdienst auf Port %d konnte nicht gestartet werden.\n" #: src/integration-tests/connection_watchdog.c:1030 #, fuzzy, c-format msgid "Found %u transport plugins: `%s'\n" msgstr "Teste Transport(e) %s\n" #: src/integration-tests/connection_watchdog.c:1089 msgid "Send ping messages to test connectivity (default == NO)" msgstr "" #: src/integration-tests/connection_watchdog.c:1095 #: src/template/gnunet-template.c:68 #, fuzzy msgid "help text" msgstr "Hilfetext für -t" #: src/mesh/gnunet-service-mesh.c:4590 msgid "Wrong CORE service\n" msgstr "" #: src/mesh/gnunet-service-mesh.c:4784 #, fuzzy msgid "Mesh service is lacking key configuration settings. Exiting.\n" msgstr "GNUnet Konfiguration" #: src/mesh/gnunet-service-mesh.c:4793 #, fuzzy msgid "Mesh service could not access hostkey. Exiting.\n" msgstr "Auf die Namespace Informationen konnte nicht zugegriffen werden.\n" #: src/mysql/mysql.c:174 #, c-format msgid "Trying to use file `%s' for MySQL configuration.\n" msgstr "Versuche, Datei `%s' für MySQL Konfiguration zu verwenden.\n" #: src/mysql/mysql.c:181 #, fuzzy, c-format msgid "Could not access file `%s': %s\n" msgstr "`%s' konnte nicht aufgelöst werden: %s\n" #: src/namestore/gnunet-namestore.c:157 #, fuzzy, c-format msgid "Adding record failed: %s\n" msgstr "" "\n" "Fehler beim Uploaden der Datei: %s\n" #: src/namestore/gnunet-namestore.c:183 #, fuzzy, c-format msgid "Deleting record failed: %s\n" msgstr "" "\n" "Fehler beim Uploaden der Datei: %s\n" #: src/namestore/gnunet-namestore.c:239 #, c-format msgid "\tCorrupt or unsupported record of type %u\n" msgstr "" #: src/namestore/gnunet-namestore.c:276 #, c-format msgid "Option `%s' not given, but I need a zone key file!\n" msgstr "" #: src/namestore/gnunet-namestore.c:281 #, fuzzy, c-format msgid "Using default zone file `%s'\n" msgstr "Collection `%s' begonnen.\n" #: src/namestore/gnunet-namestore.c:291 #, c-format msgid "No options given\n" msgstr "" #: src/namestore/gnunet-namestore.c:321 #, fuzzy, c-format msgid "Unsupported type `%s'\n" msgstr "Ungültige Nachricht des Typs %u empfangen. Nachricht wird verworfen.\n" #: src/namestore/gnunet-namestore.c:328 src/namestore/gnunet-namestore.c:350 #: src/namestore/gnunet-namestore.c:374 src/namestore/gnunet-namestore.c:384 #: src/namestore/gnunet-namestore.c:409 #, fuzzy, c-format msgid "Missing option `%s' for operation `%s'\n" msgstr "Konfigurationsdatei `%s' wurde erzeugt.\n" #: src/namestore/gnunet-namestore.c:329 src/namestore/gnunet-namestore.c:351 msgid "add/del" msgstr "" #: src/namestore/gnunet-namestore.c:341 #, fuzzy, c-format msgid "Value `%s' invalid for record type `%s'\n" msgstr "%s: Symbolwert `%s' ist ungültig für %s\n" #: src/namestore/gnunet-namestore.c:366 #, fuzzy, c-format msgid "Invalid time format `%s'\n" msgstr "Ungültiger Parameter: `%s'\n" #: src/namestore/gnunet-namestore.c:375 src/namestore/gnunet-namestore.c:385 msgid "add" msgstr "" #: src/namestore/gnunet-namestore.c:410 msgid "del" msgstr "" #: src/namestore/gnunet-namestore.c:462 msgid "add record" msgstr "" #: src/namestore/gnunet-namestore.c:465 msgid "delete record" msgstr "" #: src/namestore/gnunet-namestore.c:468 msgid "display records" msgstr "" #: src/namestore/gnunet-namestore.c:471 msgid "" "expiration time for record to use (for adding only), \"never\" is possible" msgstr "" #: src/namestore/gnunet-namestore.c:474 msgid "name of the record to add/delete/display" msgstr "" #: src/namestore/gnunet-namestore.c:477 msgid "type of the record to add/delete/display" msgstr "" #: src/namestore/gnunet-namestore.c:480 msgid "value of the record to add/delete" msgstr "" #: src/namestore/gnunet-namestore.c:483 msgid "create or list public record" msgstr "" #: src/namestore/gnunet-namestore.c:486 msgid "create or list non-authority record" msgstr "" #: src/namestore/gnunet-namestore.c:489 msgid "filename with the zone key" msgstr "" #: src/namestore/gnunet-namestore.c:500 #, fuzzy msgid "GNUnet zone manipulation tool" msgstr "GNUnet Konfiguration" #: src/namestore/gnunet-service-namestore.c:143 #, c-format msgid "File zone `%s' but corrupt content already exists, failed to write! \n" msgstr "" #: src/namestore/gnunet-service-namestore.c:154 #, c-format msgid "File zone `%s' containing this key already exists\n" msgstr "" #: src/namestore/gnunet-service-namestore.c:160 #, c-format msgid "" "File zone `%s' but different zone key already exists, failed to write! \n" msgstr "" #: src/namestore/gnunet-service-namestore.c:198 #, fuzzy, c-format msgid "Stored zonekey for zone `%s' in file `%s'\n" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/namestore/gnunet-service-namestore.c:1909 #, fuzzy msgid "No directory to load zonefiles specified in configuration\n" msgstr "In der Konfigurationsdatei wurden keine Anwendungen definiert!\n" #: src/namestore/gnunet-service-namestore.c:1918 #, c-format msgid "Creating directory `%s' for zone files failed!\n" msgstr "" #: src/namestore/namestore_api.c:315 src/namestore/namestore_api.c:353 msgid "Namestore added record successfully" msgstr "" #: src/namestore/namestore_api.c:323 msgid "Namestore failed to add record" msgstr "" #: src/namestore/namestore_api.c:361 msgid "Namestore record already existed" msgstr "" #: src/namestore/namestore_api.c:368 msgid "Namestore failed to add record\n" msgstr "" #: src/namestore/namestore_api.c:401 #, fuzzy msgid "Namestore removed record successfully" msgstr "Der GNUnet Dienst wurde erfolgreich installiert.\n" #: src/namestore/namestore_api.c:408 msgid "No records for entry" msgstr "" #: src/namestore/namestore_api.c:415 #, fuzzy msgid "Could not find record to remove" msgstr "Verbindung zu gnunetd konnte nicht hergestellt werden.\n" #: src/namestore/namestore_api.c:422 #, fuzzy msgid "Failed to create new signature" msgstr "Namespace `%s' konnte nicht erstellt werden (existiert bereits?).\n" #: src/namestore/namestore_api.c:429 #, fuzzy msgid "Failed to put new set of records in database" msgstr "Fehler beim Senden einer `%s' Anfrage an den SMTP Server.\n" #: src/nat/gnunet-nat-server.c:279 #, c-format msgid "Please pass valid port number as the first argument! (got `%s')\n" msgstr "" #: src/nat/gnunet-nat-server.c:318 msgid "GNUnet NAT traversal test helper daemon" msgstr "" #: src/nat/nat.c:799 #, c-format msgid "gnunet-helper-nat-server generated malformed address `%s'\n" msgstr "" #: src/nat/nat.c:844 #, fuzzy, c-format msgid "Failed to start %s\n" msgstr "Fehler beim Starten der Collection.\n" #: src/nat/nat.c:1111 #, fuzzy, c-format msgid "Malformed %s `%s' given in configuration!\n" msgstr "Fehler beim Speichern der Konfiguration!" #: src/nat/nat.c:1177 src/nat/nat.c:1187 #, c-format msgid "" "Configuration requires `%s', but binary is not installed properly (SUID bit " "not set). Option disabled.\n" msgstr "" #: src/nat/nat.c:1321 msgid "Internal IP address not known, cannot use ICMP NAT traversal method\n" msgstr "" #: src/nat/nat.c:1332 #, c-format msgid "Running gnunet-helper-nat-client %s %s %u\n" msgstr "" #: src/nat/nat_test.c:341 #, fuzzy msgid "Failed to connect to `gnunet-nat-server'\n" msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" #: src/nat/nat_test.c:411 #, c-format msgid "Failed to create listen socket bound to `%s' for NAT test: %s\n" msgstr "" #: src/nse/gnunet-nse-profiler.c:928 #, fuzzy msgid "Measure quality and performance of the NSE service." msgstr "Auf den Dienst konnte nicht zugegriffen werden" #: src/nse/gnunet-service-nse.c:925 #, c-format msgid "Proof of work invalid: %llu!\n" msgstr "" #: src/nse/gnunet-service-nse.c:1381 src/nse/gnunet-service-nse.c:1400 #: src/nse/gnunet-service-nse.c:1421 msgid "NSE service is lacking key configuration settings. Exiting.\n" msgstr "" #: src/nse/gnunet-service-nse.c:1388 #, fuzzy msgid "Invalid work requirement for NSE service. Exiting.\n" msgstr "Ungültige Parameter. Abbruch.\n" #: src/nse/gnunet-service-nse.c:1409 #, fuzzy msgid "NSE service could not access hostkey. Exiting.\n" msgstr "Auf die Namespace Informationen konnte nicht zugegriffen werden.\n" #: src/peerinfo/gnunet-service-peerinfo.c:134 #, fuzzy, c-format msgid "Removing expired address of transport `%s'\n" msgstr "Verfügbare(r) Transport(e): %s\n" #: src/peerinfo/gnunet-service-peerinfo.c:203 #, fuzzy, c-format msgid "Failed to parse HELLO in file `%s'\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/peerinfo/gnunet-service-peerinfo.c:229 msgid "# peers known" msgstr "" #: src/peerinfo/gnunet-service-peerinfo.c:254 #, c-format msgid "" "File `%s' in directory `%s' does not match naming convention. Removed.\n" msgstr "" "Die Datei `%s' im Verzeichnis `%s' entspricht nicht der Namenskonvention. " "Datei wurde entfernt.\n" #: src/peerinfo/gnunet-service-peerinfo.c:353 #, fuzzy, c-format msgid "Still no peers found in `%s'!\n" msgstr "Dienst `%s' konnte nicht ordentlich entladen werden!\n" #: src/peerinfo/gnunet-service-peerinfo.c:710 #, c-format msgid "Importing HELLOs from `%s'\n" msgstr "" #: src/peerinfo/peerinfo_api.c:238 msgid "aborted due to explicit disconnect request" msgstr "" #: src/peerinfo/peerinfo_api.c:358 #, fuzzy msgid "failed to transmit request (service down?)" msgstr "Fehler beim Senden einer `%s' Anfrage an den SMTP Server.\n" #: src/peerinfo/peerinfo_api.c:505 #, fuzzy msgid "Failed to receive response from `PEERINFO' service." msgstr "Fehler beim Empfangen der Antwort von gnunetd auf die `%s' Nachricht\n" #: src/peerinfo/peerinfo_api.c:531 src/peerinfo/peerinfo_api.c:550 #: src/peerinfo/peerinfo_api.c:565 src/peerinfo/peerinfo_api.c:576 #: src/peerinfo/peerinfo_api.c:587 #, fuzzy msgid "Received invalid message from `PEERINFO' service." msgstr "Ungültige `%s' Anfrage von `%s' empfangen.\n" #: src/peerinfo/peerinfo_api.c:663 #, fuzzy msgid "Timeout transmitting iteration request to `PEERINFO' service." msgstr "Fehler beim Senden einer `%s' Anfrage an den SMTP Server.\n" #: src/peerinfo/peerinfo_api_notify.c:256 #, fuzzy, c-format msgid "Could not connect to `%s' service.\n" msgstr "Verbindung zu gnunetd konnte nicht hergestellt werden.\n" #: src/peerinfo-tool/gnunet-peerinfo.c:581 #, fuzzy msgid "Failed to parse HELLO message: missing expiration time\n" msgstr "Fehler beim Speichern der Konfiguration!" #: src/peerinfo-tool/gnunet-peerinfo.c:589 #, fuzzy msgid "Failed to parse HELLO message: invalid expiration time\n" msgstr "Fehler beim Speichern der Konfiguration!" #: src/peerinfo-tool/gnunet-peerinfo.c:598 #, fuzzy msgid "Failed to parse HELLO message: malformed\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/peerinfo-tool/gnunet-peerinfo.c:608 #, fuzzy msgid "Failed to parse HELLO message: missing transport plugin\n" msgstr "Anwendung `%s' konnte nicht initialisiert werden.\n" #: src/peerinfo-tool/gnunet-peerinfo.c:625 #, c-format msgid "Plugin `%s' not found\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:634 #, c-format msgid "Plugin `%s' does not support URIs yet\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:653 #, fuzzy, c-format msgid "Failed to parse `%s' as an address for plugin `%s'\n" msgstr "Fehler beim Binden an UDP Port %d.\n" #: src/peerinfo-tool/gnunet-peerinfo.c:685 #, fuzzy, c-format msgid "Failure adding HELLO: %s\n" msgstr "Fehler bei %s:%d.\n" #: src/peerinfo-tool/gnunet-peerinfo.c:833 #, fuzzy, c-format msgid "Could not find option `%s:%s' in configuration.\n" msgstr "Knoten `%s' konnte nicht in der Routing Tabelle gefunden werden!\n" #: src/peerinfo-tool/gnunet-peerinfo.c:840 #, fuzzy, c-format msgid "Loading hostkey from `%s' failed.\n" msgstr "Das Parsen des Hello von `%s' schlug fehl.\n" #: src/peerinfo-tool/gnunet-peerinfo.c:875 #, fuzzy, c-format msgid "Invalid URI `%s'\n" msgstr "Ungültiger Parameter: `%s'\n" #: src/peerinfo-tool/gnunet-peerinfo.c:899 #, c-format msgid "I am peer `%s'.\n" msgstr "Ich bin Peer `%s'.\n" #: src/peerinfo-tool/gnunet-peerinfo.c:936 msgid "don't resolve host names" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:939 msgid "output only the identity strings" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:942 msgid "output our own identity only" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:945 msgid "list all known peers" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:948 msgid "also output HELLO uri(s)" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:951 msgid "add given HELLO uri to the database" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:957 #, fuzzy msgid "Print information about peers." msgstr "Informationen über andere GNUnet Knoten ausgeben." #: src/peerinfo-tool/gnunet-peerinfo_plugins.c:105 #: src/transport/gnunet-service-transport_plugins.c:118 #, fuzzy, c-format msgid "Starting transport plugins `%s'\n" msgstr "Teste Transport(e) %s\n" #: src/peerinfo-tool/gnunet-peerinfo_plugins.c:109 #: src/transport/gnunet-service-transport_plugins.c:122 #, fuzzy, c-format msgid "Loading `%s' transport plugin\n" msgstr "Teste Transport(e) %s\n" #: src/peerinfo-tool/gnunet-peerinfo_plugins.c:129 #: src/transport/gnunet-service-transport_plugins.c:150 #, fuzzy, c-format msgid "Failed to load transport plugin for `%s'\n" msgstr "Anwendung `%s' konnte nicht initialisiert werden.\n" #: src/postgres/postgres.c:59 #, fuzzy, c-format msgid "`%s:%s' failed at %s:%d with error: %s" msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" #: src/postgres/postgres.c:148 #, fuzzy, c-format msgid "Unable to initialize Postgres: %s" msgstr "SQLite Datenbank konnte nicht initialisiert werden: %s.\n" #: src/pt/gnunet-daemon-pt.c:264 #, fuzzy msgid "Failed to pack DNS request. Dropping.\n" msgstr "Fehler beim Senden einer `%s' Anfrage an den SMTP Server.\n" #: src/pt/gnunet-daemon-pt.c:270 #, fuzzy msgid "# DNS requests mapped to VPN" msgstr "# Client Trace-Anfragen empfangen" #: src/pt/gnunet-daemon-pt.c:323 msgid "# DNS records modified" msgstr "" #: src/pt/gnunet-daemon-pt.c:500 msgid "# DNS replies intercepted" msgstr "" #: src/pt/gnunet-daemon-pt.c:506 #, fuzzy msgid "Failed to parse DNS request. Dropping.\n" msgstr "Fehler beim Senden einer `%s' Anfrage an den SMTP Server.\n" #: src/pt/gnunet-daemon-pt.c:602 #, fuzzy msgid "# DNS requests dropped (timeout)" msgstr "# gap Anfragen verworfen: Kollision in RT" #: src/pt/gnunet-daemon-pt.c:632 #, fuzzy msgid "# DNS requests intercepted" msgstr "# Client Trace-Anfragen empfangen" #: src/pt/gnunet-daemon-pt.c:637 #, fuzzy msgid "# DNS requests dropped (DNS mesh tunnel down)" msgstr "# gap Anfragen verworfen: Kollision in RT" #: src/pt/gnunet-daemon-pt.c:645 #, fuzzy msgid "# DNS requests dropped (malformed)" msgstr "# gap Anfragen verworfen: Kollision in RT" #: src/pt/gnunet-daemon-pt.c:716 #, fuzzy msgid "# DNS replies received" msgstr "# Client Trace-Anfragen empfangen" #: src/pt/gnunet-daemon-pt.c:730 #, fuzzy msgid "# DNS replies dropped (too late?)" msgstr "# gap Anfragen verworfen: Kollision in RT" #: src/pt/gnunet-daemon-pt.c:748 src/pt/gnunet-daemon-pt.c:760 msgid "# DNS requests aborted (tunnel down)" msgstr "" #: src/pt/gnunet-daemon-pt.c:898 src/pt/gnunet-daemon-pt.c:907 #: src/pt/gnunet-daemon-pt.c:930 src/pt/gnunet-daemon-pt.c:940 #, fuzzy, c-format msgid "Failed to connect to %s service. Exiting.\n" msgstr "`%s' Dienst konnte nicht initialisiert werden.\n" #: src/pt/gnunet-daemon-pt.c:973 msgid "Daemon to run to perform IP protocol translation to GNUnet" msgstr "" #: src/statistics/gnunet-service-statistics.c:271 #, fuzzy, c-format msgid "Loading %llu bytes of statistics from `%s'\n" msgstr "Dateien aus dem GNUnet herunterladen." #: src/statistics/gnunet-service-statistics.c:330 #, fuzzy, c-format msgid "Wrote %llu bytes of statistics to `%s'\n" msgstr "Dateien aus dem GNUnet herunterladen." #: src/statistics/gnunet-statistics.c:122 #, fuzzy msgid "Failed to obtain statistics.\n" msgstr "Statistiken über den Netzwerkverkehr konnten nicht ermittelt werden.\n" #: src/statistics/gnunet-statistics.c:199 #, c-format msgid "No subsystem or name given\n" msgstr "" #: src/statistics/gnunet-statistics.c:207 #, fuzzy, c-format msgid "Failed to initialize watch routine\n" msgstr "SQLite Datenbank konnte nicht initialisiert werden.\n" #: src/statistics/gnunet-statistics.c:227 msgid "limit output to statistics for the given NAME" msgstr "" #: src/statistics/gnunet-statistics.c:230 msgid "make the value being set persistent" msgstr "" #: src/statistics/gnunet-statistics.c:233 msgid "limit output to the given SUBSYSTEM" msgstr "" #: src/statistics/gnunet-statistics.c:236 msgid "just print the statistics value" msgstr "" #: src/statistics/gnunet-statistics.c:239 msgid "watch value continously" msgstr "" #: src/statistics/gnunet-statistics.c:246 msgid "Print statistics about GNUnet operations." msgstr "Statistiken der GNUnet Aktivitäten ausgeben." #: src/statistics/statistics_api.c:456 #, fuzzy msgid "Could not save some persistent statistics\n" msgstr "" "IP(v4) dieses Hosts konnte nicht ermittelt werden. Bitte geben Sie die IP in " "der Konfigurationsdatei an.\n" #: src/statistics/statistics_api.c:999 msgid "" "Failed to receive acknowledgement from statistics service, some statistics " "might have been lost!\n" msgstr "" #: src/testing/gnunet-testing.c:157 #, fuzzy msgid "Could not read hostkeys file, specify hostkey file with -H!\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/testing/gnunet-testing.c:159 #, c-format msgid "Specified hostkey file `%s' not found!\n" msgstr "" #: src/testing/gnunet-testing.c:273 #, fuzzy msgid "create unique configuration files" msgstr "" "Einen Wert aus der Konfigurationsdatei auf der Standardausgabe ausgeben" #: src/testing/gnunet-testing.c:275 msgid "create hostkey files from pre-computed hostkey list" msgstr "" #: src/testing/gnunet-testing.c:277 msgid "host key file" msgstr "" #: src/testing/gnunet-testing.c:279 #, fuzzy msgid "number of unique configuration files or hostkeys to create" msgstr "" "Einen Wert aus der Konfigurationsdatei auf der Standardausgabe ausgeben" #: src/testing/gnunet-testing.c:281 #, fuzzy msgid "configuration template" msgstr "GNUnet Konfiguration" #: src/testing/gnunet-testing.c:287 msgid "Command line tool to access the testing library" msgstr "" #: src/testing/helper.c:56 #, fuzzy msgid "Peer is lacking HOSTKEY configuration setting.\n" msgstr "GNUnet Konfiguration" #: src/testing/helper.c:64 #, fuzzy msgid "Could not access hostkey.\n" msgstr "Konfigurationsdatei `%s' konnte nicht geparst werden.\n" #: src/testing/testing.c:200 msgid "`scp' does not seem to terminate (timeout copying config).\n" msgstr "" #: src/testing/testing.c:214 src/testing/testing.c:798 #, fuzzy msgid "`scp' did not complete cleanly.\n" msgstr "`%s' ist zu keinem Knoten verbunden.\n" #: src/testing/testing.c:237 #, fuzzy msgid "Failed to create pipe for `gnunet-peerinfo' process.\n" msgstr "Fehler beim Starten der Collection.\n" #: src/testing/testing.c:238 #, fuzzy msgid "Failed to create pipe for `ssh' process.\n" msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" #: src/testing/testing.c:286 #, fuzzy, c-format msgid "Could not start `%s' process to create hostkey.\n" msgstr "" "IP(v4) dieses Hosts konnte nicht ermittelt werden. Bitte geben Sie die IP in " "der Konfigurationsdatei an.\n" #: src/testing/testing.c:293 #, fuzzy msgid "Failed to start `gnunet-peerinfo' process.\n" msgstr "Fehler beim Starten der Collection.\n" #: src/testing/testing.c:294 src/testing/testing.c:471 #, fuzzy msgid "Failed to start `ssh' process.\n" msgstr "Fehler beim Starten der Collection.\n" #: src/testing/testing.c:354 #, fuzzy, c-format msgid "Error reading from gnunet-peerinfo: %s\n" msgstr "Fehler beim Lesen von Informationen von gnunetd.\n" #: src/testing/testing.c:358 #, fuzzy msgid "Malformed output from gnunet-peerinfo!\n" msgstr "Fehler beim Lesen von Informationen von gnunetd.\n" #: src/testing/testing.c:368 #, fuzzy msgid "Failed to get hostkey!\n" msgstr "Statistiken über den Netzwerkverkehr konnten nicht ermittelt werden.\n" #: src/testing/testing.c:400 msgid "`Failed while waiting for topology setup!\n" msgstr "" #: src/testing/testing.c:463 #, fuzzy, c-format msgid "Could not start `%s' process to start GNUnet.\n" msgstr "" "IP(v4) dieses Hosts konnte nicht ermittelt werden. Bitte geben Sie die IP in " "der Konfigurationsdatei an.\n" #: src/testing/testing.c:470 #, fuzzy msgid "Failed to start `gnunet-arm' process.\n" msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" #: src/testing/testing.c:493 src/testing/testing.c:600 msgid "`gnunet-arm' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:494 src/testing/testing.c:601 #: src/testing/testing.c:621 msgid "`ssh' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:570 msgid "Unable to get HELLO for peer!\n" msgstr "" #: src/testing/testing.c:620 msgid "`gnunet-arm' terminated with non-zero exit status (or timed out)!\n" msgstr "" #: src/testing/testing.c:643 src/testing/testing.c:675 msgid "either `gnunet-arm' or `ssh' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:658 src/testing/testing.c:713 #, fuzzy msgid "shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n" msgstr "`%s' ist zu keinem Knoten verbunden.\n" #: src/testing/testing.c:786 msgid "`scp' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:948 #, fuzzy, c-format msgid "Starting service %s for peer `%4s'\n" msgstr "Collection `%s' begonnen.\n" #: src/testing/testing.c:1207 src/testing/testing_group.c:6154 #, fuzzy, c-format msgid "Could not start `%s' process to copy configuration directory.\n" msgstr "" "IP(v4) dieses Hosts konnte nicht ermittelt werden. Bitte geben Sie die IP in " "der Konfigurationsdatei an.\n" #: src/testing/testing.c:1292 src/testing/testing.c:1359 #, fuzzy, c-format msgid "Terminating peer `%4s'\n" msgstr "Zugriff verweigert für `%s' bei %s:%d.\n" #: src/testing/testing.c:1448 #, fuzzy, c-format msgid "Setting d->dead on peer `%4s'\n" msgstr "Collection `%s' begonnen.\n" #: src/testing/testing.c:1601 msgid "Peer not yet running, can not change configuration at this point." msgstr "" #: src/testing/testing.c:1609 #, fuzzy msgid "Failed to write new configuration to disk." msgstr "Fehler beim Speichern der Konfiguration!" #: src/testing/testing.c:1636 #, fuzzy, c-format msgid "Could not start `%s' process to copy configuration file.\n" msgstr "" "IP(v4) dieses Hosts konnte nicht ermittelt werden. Bitte geben Sie die IP in " "der Konfigurationsdatei an.\n" #: src/testing/testing.c:1639 #, fuzzy msgid "Failed to copy new configuration to remote machine." msgstr "Fehler beim Speichern der Konfiguration!" #: src/testing/testing.c:1794 #, fuzzy msgid "Peers failed to connect" msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden." #: src/testing/testing.c:1922 #, fuzzy msgid "Failed to connect to core service of first peer!\n" msgstr "Der Transportdienst auf Port %d konnte nicht gestartet werden.\n" #: src/testing/testing.c:2145 msgid "Peers are not fully running yet, can not connect!\n" msgstr "" #: src/testing/testing_group.c:1895 src/testing/testing_group.c:1907 #: src/testing/testing_group.c:2008 src/testing/testing_group.c:2065 #: src/testing/testing_group.c:2152 src/testing/testing_group.c:2172 #: src/testing/testing_group.c:2302 src/testing/testing_peergroup.c:950 #, fuzzy, c-format msgid "Invalid value `%s' for option `%s' in section `%s': expected float\n" msgstr "" "Die Konfigurationsdatei muss in der Sektion `%s' unter `%s' ein Verzeichnis " "angeben, in dem FS Daten gespeichert werden.\n" #: src/testing/testing_group.c:2160 #, c-format msgid "" "Invalid value `%s' for option `%s' in section `%s': got %f, needed value " "greater than 0\n" msgstr "" #: src/testing/testing_group.c:2877 src/testing/testing_group.c:3063 #, fuzzy, c-format msgid "" "No `%s' specified in peer configuration in section `%s', cannot copy friends " "file!\n" msgstr "" "Option `%s' ist in der Konfigurationsdatei in der Sektion `%s' nicht " "gesetzt, sie wird auf %dm gesetzt.\n" #: src/testing/testing_group.c:3957 msgid "Creating no allowed topology (all peers can connect at core level)\n" msgstr "" #: src/testing/testing_group.c:5226 #, fuzzy msgid "Unknown topology specification, can't connect peers!\n" msgstr "Syntaxfehler in Topolgieangabe, Bytes werden übersprungen.\n" #: src/testing/testing_group.c:5944 src/transport/transport-testing.c:636 #, fuzzy msgid "Could not read hostkeys file!\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/testing/testing_group.c:6011 #, fuzzy, c-format msgid "Could not create configuration for peer number %u on `%s'!\n" msgstr "Auf die Namespace Informationen konnte nicht zugegriffen werden.\n" #: src/testing/testing_new.c:169 msgid "tmppath cannot be NULL\n" msgstr "" #: src/testing/testing_new.c:356 #, c-format msgid "Hostkeys file not found: %s\n" msgstr "" #: src/testing/testing_new.c:365 #, fuzzy, c-format msgid "Could not open hostkeys file: %s\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/testing/testing_new.c:380 #, c-format msgid "Incorrect hostkey file format: %s\n" msgstr "" #: src/testing/testing_new.c:437 #, fuzzy, c-format msgid "Key number %u does not exist\n" msgstr "Anzahl an Nachrichten, die pro Durchlauf verwendet wird" #: src/testing/testing_new.c:446 #, fuzzy, c-format msgid "Error while decoding key %u\n" msgstr "Fehler beim Download: %s\n" #: src/testing/testing_new.c:680 #, fuzzy msgid "Failed to create configuration for peer (not enough free ports?)\n" msgstr "Auf die Namespace Informationen konnte nicht zugegriffen werden.\n" #: src/testing/testing_new.c:691 #, c-format msgid "" "You attempted to create a testbed with more than %u hosts. Please " "precompute more hostkeys first.\n" msgstr "" #: src/testing/testing_new.c:704 #, fuzzy, c-format msgid "Failed to initialize hostkey for peer %u\n" msgstr "SQLite Datenbank konnte nicht initialisiert werden.\n" #: src/testing/testing_new.c:734 #, fuzzy, c-format msgid "Failed to write hostkey file for peer %u: %s\n" msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" #: src/testing/testing_new.c:751 #, fuzzy, c-format msgid "Failed to write configuration file `%s' for peer %u: %s\n" msgstr "Fehler beim Speichern der Konfigurationsdatei `%s':" #: src/testing/testing_new.c:791 #, fuzzy, c-format msgid "Failed to start `%s': %s\n" msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" #: src/testing/testing_new.c:959 #, fuzzy, c-format msgid "Failed to load configuration from %s\n" msgstr "Fehler beim Speichern der Konfigurationsdatei `%s':" #: src/topology/gnunet-daemon-topology.c:259 msgid "# peers blacklisted" msgstr "" #: src/topology/gnunet-daemon-topology.c:392 #, fuzzy msgid "# connect requests issued to transport" msgstr "# Client Trace-Anfragen empfangen" #: src/topology/gnunet-daemon-topology.c:730 #: src/topology/gnunet-daemon-topology.c:815 #, fuzzy msgid "# friends connected" msgstr "# verbundener Knoten" #: src/topology/gnunet-daemon-topology.c:996 msgid "Failed to connect to core service, can not manage topology!\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1026 #, c-format msgid "Option `%s' in section `%s' not specified!\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1039 #, fuzzy, c-format msgid "Could not read friends list `%s'\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/topology/gnunet-daemon-topology.c:1045 #, c-format msgid "Friends file `%s' is empty.\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1054 #, fuzzy, c-format msgid "Failed to read friends list from `%s': out of memory\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/topology/gnunet-daemon-topology.c:1062 #, c-format msgid "Failed to read friends list from `%s'\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/topology/gnunet-daemon-topology.c:1082 #, fuzzy, c-format msgid "" "Syntax error in topology specification at offset %llu, skipping bytes.\n" msgstr "Syntaxfehler in Topolgieangabe, Bytes werden übersprungen.\n" #: src/topology/gnunet-daemon-topology.c:1095 #, fuzzy, c-format msgid "" "Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n" msgstr "Syntaxfehler in Topologieangabe, überspringe Bytes `%s'.\n" #: src/topology/gnunet-daemon-topology.c:1105 #, fuzzy, c-format msgid "Found friend `%s' in configuration\n" msgstr " gconfig\tGTK Konfiguration\n" #: src/topology/gnunet-daemon-topology.c:1111 #, c-format msgid "Found myself `%s' in friend list (useless, ignored)\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1121 #, fuzzy msgid "# friends in configuration" msgstr " gconfig\tGTK Konfiguration\n" #: src/topology/gnunet-daemon-topology.c:1127 msgid "" "Fewer friends specified than required by minimum friend count. Will only " "connect to friends.\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1134 msgid "" "More friendly connections required than target total number of connections.\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1169 #, fuzzy msgid "# HELLO messages received" msgstr "# verschlüsselter PONG Nachrichten empfangen" #: src/topology/gnunet-daemon-topology.c:1224 #, fuzzy msgid "# HELLO messages gossipped" msgstr "# ausgehender Nachrichten verworfen" #: src/topology/gnunet-daemon-topology.c:1363 msgid "GNUnet topology control (maintaining P2P mesh and F2F constraints)" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:246 #, fuzzy, c-format msgid "Could not read blacklist file `%s'\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/transport/gnunet-service-transport_blacklist.c:252 #, c-format msgid "Blacklist file `%s' is empty.\n" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:263 #, fuzzy, c-format msgid "Failed to read blacklist from `%s'\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/transport/gnunet-service-transport_blacklist.c:284 #: src/transport/gnunet-service-transport_blacklist.c:308 #, fuzzy, c-format msgid "Syntax error in blacklist file at offset %llu, giving up!\n" msgstr "Syntaxfehler in Konfigurationsdatei `%s' in Zeile %d.\n" #: src/transport/gnunet-service-transport_blacklist.c:295 #: src/transport/gnunet-service-transport_blacklist.c:331 #, fuzzy, c-format msgid "Syntax error in blacklist file at offset %llu, skipping bytes.\n" msgstr "Syntaxfehler in Topolgieangabe, Bytes werden übersprungen.\n" #: src/transport/gnunet-service-transport_blacklist.c:345 #, fuzzy, c-format msgid "Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n" msgstr "Syntaxfehler in Topologieangabe, überspringe Bytes `%s'.\n" #: src/transport/gnunet-service-transport_blacklist.c:359 #, c-format msgid "Found myself `%s' in blacklist (useless, ignored)\n" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:514 #: src/transport/gnunet-service-transport_blacklist.c:747 msgid "# disconnects due to blacklist" msgstr "" #: src/transport/gnunet-service-transport.c:163 #, fuzzy msgid "# bytes payload discarded due to not connected peer " msgstr "# Knotenankündigungen empfangen" #: src/transport/gnunet-service-transport.c:237 #, fuzzy msgid "# bytes total received" msgstr "# gap Anfragen insgesamt empfangen" #: src/transport/gnunet-service-transport.c:284 #, fuzzy msgid "# bytes payload received" msgstr "# Bytes entschlüsselt" #: src/transport/gnunet-service-transport.c:582 msgid "Transport service is lacking key configuration settings. Exiting.\n" msgstr "" #: src/transport/gnunet-service-transport.c:591 msgid "Transport service could not access hostkey. Exiting.\n" msgstr "" #: src/transport/gnunet-service-transport_clients.c:352 #, c-format msgid "Dropping message of type %u and size %u, have %u/%u messages pending\n" msgstr "" #: src/transport/gnunet-service-transport_clients.c:357 #, fuzzy msgid "# messages dropped due to slow client" msgstr "# gap Anfragen verworfen: Kollision in RT" #: src/transport/gnunet-service-transport_clients.c:503 #, c-format msgid "Rejecting control connection from peer `%s', which is not me!\n" msgstr "" #: src/transport/gnunet-service-transport_clients.c:631 msgid "# bytes payload dropped (other peer was not connected)" msgstr "" #: src/transport/gnunet-service-transport_clients.c:682 #, fuzzy msgid "# REQUEST CONNECT messages received" msgstr "# verschlüsselter PONG Nachrichten empfangen" #: src/transport/gnunet-service-transport_hello.c:172 msgid "# refreshed my HELLO" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1032 #, fuzzy msgid "# DISCONNECT messages sent" msgstr "# verschlüsselter PONG Nachrichten empfangen" #: src/transport/gnunet-service-transport_neighbours.c:1148 #: src/transport/gnunet-service-transport_neighbours.c:1482 #, fuzzy msgid "# bytes in message queue for other peers" msgstr "# Bytes ausgehender Nachrichten verworfen" #: src/transport/gnunet-service-transport_neighbours.c:1153 #, fuzzy msgid "# messages transmitted to other peers" msgstr "# Bytes des Typs %d übertragen" #: src/transport/gnunet-service-transport_neighbours.c:1158 #, fuzzy msgid "# transmission failures for messages to other peers" msgstr "# Bytes ausgehender Nachrichten verworfen" #: src/transport/gnunet-service-transport_neighbours.c:1215 msgid "# messages timed out while in transport queue" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1254 #, fuzzy msgid "# keepalives sent" msgstr "# p2p Trace-Antworten gesendet" #: src/transport/gnunet-service-transport_neighbours.c:1278 #, fuzzy msgid "# KEEPALIVE messages discarded (peer unknown)" msgstr "# defragmentierter Nachrichten" #: src/transport/gnunet-service-transport_neighbours.c:1286 #, fuzzy msgid "# KEEPALIVE messages discarded (no session)" msgstr "# defragmentierter Nachrichten" #: src/transport/gnunet-service-transport_neighbours.c:1323 #, fuzzy msgid "# KEEPALIVE_RESPONSE messages discarded (not connected)" msgstr "# defragmentierter Nachrichten" #: src/transport/gnunet-service-transport_neighbours.c:1332 #, fuzzy msgid "# KEEPALIVE_RESPONSE messages discarded (not expected)" msgstr "# defragmentierter Nachrichten" #: src/transport/gnunet-service-transport_neighbours.c:1388 #, fuzzy msgid "# messages discarded due to lack of neighbour record" msgstr "# defragmentierter Nachrichten" #: src/transport/gnunet-service-transport_neighbours.c:1422 #, fuzzy msgid "# bandwidth quota violations by other peers" msgstr "Verfolgt die Bandbreitennutzung von gnunetd" #: src/transport/gnunet-service-transport_neighbours.c:1438 msgid "# ms throttling suggested" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2544 #, fuzzy msgid "# unexpected CONNECT_ACK messages (no peer)" msgstr "COUNT Nachrichten versenden" #: src/transport/gnunet-service-transport_neighbours.c:2559 #: src/transport/gnunet-service-transport_neighbours.c:2585 #, fuzzy msgid "# unexpected CONNECT_ACK messages (not ready)" msgstr "COUNT Nachrichten versenden" #: src/transport/gnunet-service-transport_neighbours.c:2598 #, fuzzy msgid "# unexpected CONNECT_ACK messages (waiting on ATS)" msgstr "COUNT Nachrichten versenden" #: src/transport/gnunet-service-transport_neighbours.c:2627 #, fuzzy msgid "# unexpected CONNECT_ACK messages (disconnecting)" msgstr "COUNT Nachrichten versenden" #: src/transport/gnunet-service-transport_neighbours.c:2807 #, fuzzy msgid "# unexpected SESSION ACK messages" msgstr "# verschlüsselter PONG Nachrichten gesendet" #: src/transport/gnunet-service-transport_neighbours.c:2856 msgid "# SET QUOTA messages ignored (no such peer)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2870 msgid "# disconnects due to quota of 0" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2901 msgid "# disconnect messages ignored (old format)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2912 msgid "# disconnect messages ignored (timestamp)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2943 msgid "# other peer asked to disconnect from us" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:3020 #, fuzzy msgid "# disconnected from peer upon explicit request" msgstr "# gap Anfragen verworfen: Kollision in RT" #: src/transport/gnunet-service-transport_plugins.c:111 msgid "Transport service is lacking NEIGHBOUR_LIMIT option.\n" msgstr "" #: src/transport/gnunet-service-transport_validation.c:414 msgid "# address records discarded" msgstr "" #: src/transport/gnunet-service-transport_validation.c:463 #, c-format msgid "" "Not transmitting `%s' with `%s', message too big (%u bytes!). This should " "not happen.\n" msgstr "" #: src/transport/gnunet-service-transport_validation.c:512 #, fuzzy msgid "# PING without HELLO messages sent" msgstr "# Klartext PING Nachrichten gesendet" #: src/transport/gnunet-service-transport_validation.c:570 msgid "# address revalidations started" msgstr "" #: src/transport/gnunet-service-transport_validation.c:805 #, fuzzy msgid "# PING message for different peer received" msgstr "# PING Nachrichten erstellt" #: src/transport/gnunet-service-transport_validation.c:840 #, c-format msgid "" "Not confirming PING with address `%s' since I cannot confirm having this " "address.\n" msgstr "" #: src/transport/gnunet-service-transport_validation.c:924 msgid "# PONGs unicast via reliable transport" msgstr "" #: src/transport/gnunet-service-transport_validation.c:933 msgid "# PONGs multicast to all available addresses" msgstr "" #: src/transport/gnunet-service-transport_validation.c:1055 msgid "# PONGs dropped, no matching pending validation" msgstr "" #: src/transport/gnunet-service-transport_validation.c:1080 msgid "# PONGs dropped, signature expired" msgstr "" #: src/transport/gnunet-service-transport_validation.c:1136 #, fuzzy, c-format msgid "Adding `%s' without addresses for peer `%s'\n" msgstr "Adresse des Knotens `%s' konnte nicht ermittelt werden.\n" #: src/transport/gnunet-transport.c:260 msgid "No transport plugins configured, peer will never communicate\n" msgstr "" #: src/transport/gnunet-transport.c:273 #, c-format msgid "No port configured for plugin `%s', cannot test it\n" msgstr "" #: src/transport/gnunet-transport.c:323 #, c-format msgid "Received %llu bytes/s (%llu bytes in %llu ms)\n" msgstr "" #: src/transport/gnunet-transport.c:330 #, c-format msgid "Transmitted %llu bytes/s (%llu bytes in %llu ms)\n" msgstr "" #: src/transport/gnunet-transport.c:363 #, fuzzy, c-format msgid "Transmitting %u bytes to %s\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/transport/gnunet-transport.c:383 #, fuzzy, c-format msgid "Connected to %s\n" msgstr "`%s' hat sich mit `%s' verbunden.\n" #: src/transport/gnunet-transport.c:414 #, fuzzy, c-format msgid "Disconnected from %s\n" msgstr "`%s' hat sich mit `%s' verbunden.\n" #: src/transport/gnunet-transport.c:443 #, fuzzy, c-format msgid "Received %u bytes from %s\n" msgstr "GAP hat ungültige Inhalte von `%s' empfangen.\n" #: src/transport/gnunet-transport.c:466 #, fuzzy, c-format msgid "Peer `%s': %s %s\n" msgstr "Ich bin Peer `%s'.\n" #: src/transport/gnunet-transport.c:473 #, c-format msgid "Peer `%s': %s \n" msgstr "" #: src/transport/gnunet-transport.c:501 #, fuzzy, c-format msgid "Peer `%s' disconnected\n" msgstr "# verbundener Knoten" #: src/transport/gnunet-transport.c:569 #, fuzzy, c-format msgid "Failed to parse peer identity `%s'\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/transport/gnunet-transport.c:618 msgid "measure how fast we are receiving data (until CTRL-C)" msgstr "" #: src/transport/gnunet-transport.c:621 #, fuzzy msgid "try to connect to the given peer" msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" #: src/transport/gnunet-transport.c:624 #, fuzzy msgid "provide information about all current connections (once)" msgstr "Informationen über andere GNUnet Knoten ausgeben." #: src/transport/gnunet-transport.c:627 #, fuzzy msgid "provide information about all current connections (continuously)" msgstr "Informationen über andere GNUnet Knoten ausgeben." #: src/transport/gnunet-transport.c:630 #, fuzzy msgid "do not resolve hostnames" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/transport/gnunet-transport.c:634 msgid "send data for benchmarking to the other peer (until CTRL-C)" msgstr "" #: src/transport/gnunet-transport.c:637 msgid "test transport configuration (involves external server)" msgstr "" #: src/transport/gnunet-transport.c:645 #, fuzzy msgid "Direct access to transport service." msgstr "Der Transportdienst auf Port %d konnte nicht gestartet werden.\n" #: src/transport/plugin_transport_http.c:1100 msgid "Disabling IPv6 since it is not supported on this system!\n" msgstr "" #: src/transport/plugin_transport_http.c:1149 #, fuzzy msgid "Require valid port number for service in configuration!\n" msgstr "In der Konfigurationsdatei wurden keine Anwendungen definiert!\n" #: src/transport/plugin_transport_http.c:1174 src/util/service.c:1036 #, fuzzy, c-format msgid "Failed to resolve `%s': %s\n" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/transport/plugin_transport_http.c:1191 src/util/service.c:1053 #, fuzzy, c-format msgid "Failed to find %saddress for `%s'.\n" msgstr "Fehler beim Binden an UDP Port %d.\n" #: src/transport/plugin_transport_http.c:1296 #, c-format msgid "Found %u addresses to report to NAT service\n" msgstr "" #: src/transport/plugin_transport_http.c:1309 #, c-format msgid "FREEING %s\n" msgstr "" #: src/transport/plugin_transport_http.c:1386 #, fuzzy msgid "Neither IPv4 nor IPv6 are enabled! Fix in configuration\n" msgstr "Netzwerkbekanntmachungen wurden per Konfiguration deaktiviert!\n" #: src/transport/plugin_transport_http.c:1399 #, fuzzy msgid "Port is required! Fix in configuration\n" msgstr " gconfig\tGTK Konfiguration\n" #: src/transport/plugin_transport_http.c:1410 msgid "Port 0, client only mode\n" msgstr "" #: src/transport/plugin_transport_http.c:1430 #, c-format msgid "" "Specific IPv4 address `%s' for plugin %s in configuration file is invalid! " "Binding to all addresses!\n" msgstr "" #: src/transport/plugin_transport_http.c:1460 #, c-format msgid "" "Specific IPv6 address `%s' for plugin %s in configuration file is invalid! " "Binding to all addresses!\n" msgstr "" #: src/transport/plugin_transport_http_client.c:624 #, c-format msgid "Could not initialize curl multi handle, failed to start %s plugin!\n" msgstr "" #: src/transport/plugin_transport_http_server.c:178 msgid "" "Could not create a new TLS certificate, program `gnunet-transport-" "certificate-creation' could not be started!\n" msgstr "" #: src/transport/plugin_transport_http_server.c:202 msgid "No usable TLS certificate found and creating one failed!\n" msgstr "" #: src/transport/plugin_transport_tcp.c:591 #, c-format msgid "Unexpected address length: %u bytes\n" msgstr "" #: src/transport/plugin_transport_tcp.c:767 #: src/transport/plugin_transport_tcp.c:856 #: src/transport/plugin_transport_tcp.c:906 #: src/transport/plugin_transport_tcp.c:992 #: src/transport/plugin_transport_tcp.c:1086 #: src/transport/plugin_transport_tcp.c:1103 #, fuzzy msgid "# bytes currently in TCP buffers" msgstr "# Bytes gesendet über TCP" #: src/transport/plugin_transport_tcp.c:774 #: src/transport/plugin_transport_tcp.c:963 #: src/transport/plugin_transport_tcp.c:1761 #: src/transport/plugin_transport_tcp.c:2390 #, fuzzy msgid "# TCP sessions active" msgstr "# Sitzungsschlüssel akzeptiert" #: src/transport/plugin_transport_tcp.c:860 #, fuzzy msgid "# bytes discarded by TCP (timeout)" msgstr "# Bytes verworfen von TCP (ausgehend)" #: src/transport/plugin_transport_tcp.c:909 #, fuzzy msgid "# bytes transmitted via TCP" msgstr "# Bytes des Typs %d übertragen" #: src/transport/plugin_transport_tcp.c:996 #, fuzzy msgid "# bytes discarded by TCP (disconnect)" msgstr "# Bytes verworfen von TCP (ausgehend)" #: src/transport/plugin_transport_tcp.c:1290 #, c-format msgid "Address of unexpected length: %u\n" msgstr "" #: src/transport/plugin_transport_tcp.c:1401 msgid "# transport-service disconnect requests for TCP" msgstr "" #: src/transport/plugin_transport_tcp.c:1802 #, fuzzy msgid "# TCP WELCOME messages received" msgstr "# verschlüsselter PONG Nachrichten empfangen" #: src/transport/plugin_transport_tcp.c:1973 msgid "# bytes received via TCP" msgstr "# Bytes empfangen über TCP" #: src/transport/plugin_transport_tcp.c:2043 msgid "# network-level TCP disconnect events" msgstr "" #: src/transport/plugin_transport_tcp.c:2279 src/util/service.c:940 #, c-format msgid "Require valid port number for service `%s' in configuration!\n" msgstr "" #: src/transport/plugin_transport_tcp.c:2293 #, fuzzy msgid "Failed to start service.\n" msgstr "Fehler beim Starten der Collection.\n" #: src/transport/plugin_transport_tcp.c:2355 #, fuzzy, c-format msgid "Failed to find option %s in section %s!\n" msgstr "Fehler beim Binden an UDP Port %d.\n" #: src/transport/plugin_transport_tcp.c:2378 #, fuzzy, c-format msgid "TCP transport listening on port %llu\n" msgstr "Der Transportdienst auf Port %d konnte nicht gestartet werden.\n" #: src/transport/plugin_transport_tcp.c:2382 msgid "TCP transport not listening on any port (client only)\n" msgstr "" #: src/transport/plugin_transport_tcp.c:2386 #, c-format msgid "TCP transport advertises itself as being on port %llu\n" msgstr "" #: src/transport/plugin_transport_udp_broadcasting.c:128 #, fuzzy msgid "# IPv6 multicast HELLO beacons received via udp" msgstr "# verschlüsselter PONG Nachrichten empfangen" #: src/transport/plugin_transport_udp_broadcasting.c:169 #, fuzzy msgid "# IPv4 broadcast HELLO beacons received via udp" msgstr "# verschlüsselter PONG Nachrichten empfangen" #: src/transport/plugin_transport_udp_broadcasting.c:367 #, c-format msgid "Failed to set IPv4 broadcast option for broadcast socket on port %d\n" msgstr "" #: src/transport/plugin_transport_udp.c:1894 #, c-format msgid "" "UDP could not message to `%s': `%s'. Please check your network configuration " "and disable IPv6 if your connection does not have a global IPv6 address\n" msgstr "" #: src/transport/plugin_transport_udp.c:2138 #, fuzzy msgid "Failed to open UDP sockets\n" msgstr "Fehler beim Binden an UDP6 Port %d.\n" #: src/transport/plugin_transport_udp.c:2306 #, c-format msgid "Given `%s' option is out of range: %llu > %u\n" msgstr "" #: src/transport/plugin_transport_udp.c:2349 #, fuzzy, c-format msgid "Invalid IPv6 address: `%s'\n" msgstr "Ungültiger Parameter: `%s'\n" #: src/transport/plugin_transport_unix.c:1356 #, fuzzy msgid "Failed to open UNIX sockets\n" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/transport/plugin_transport_wlan.c:561 msgid "# WLAN ACKs sent" msgstr "" #: src/transport/plugin_transport_wlan.c:580 #, fuzzy msgid "# WLAN messages defragmented" msgstr "# defragmentierter Nachrichten" #: src/transport/plugin_transport_wlan.c:626 #: src/transport/plugin_transport_wlan.c:676 #: src/transport/plugin_transport_wlan.c:1696 #, fuzzy msgid "# WLAN sessions allocated" msgstr "# Sitzungsschlüssel akzeptiert" #: src/transport/plugin_transport_wlan.c:749 #, fuzzy msgid "# WLAN message fragments sent" msgstr "# fragmentierter Nachrichten" #: src/transport/plugin_transport_wlan.c:767 msgid "# WLAN messages pending (with fragmentation)" msgstr "" #: src/transport/plugin_transport_wlan.c:867 #: src/transport/plugin_transport_wlan.c:948 #: src/transport/plugin_transport_wlan.c:1698 #, fuzzy msgid "# WLAN MAC endpoints allocated" msgstr "# Client Trace-Anfragen empfangen" #: src/transport/plugin_transport_wlan.c:1119 #, fuzzy msgid "# HELLO messages received via WLAN" msgstr "# verschlüsselter PONG Nachrichten empfangen" #: src/transport/plugin_transport_wlan.c:1140 #, fuzzy msgid "# fragments received via WLAN" msgstr "# verworfener Nachrichten" #: src/transport/plugin_transport_wlan.c:1150 #, fuzzy msgid "# ACKs received via WLAN" msgstr "# Bytes empfangen über TCP" #: src/transport/plugin_transport_wlan.c:1207 #, fuzzy msgid "# WLAN DATA messages discarded due to CRC32 error" msgstr "# defragmentierter Nachrichten" #: src/transport/plugin_transport_wlan.c:1306 #, fuzzy msgid "# DATA messages received via WLAN" msgstr "# verschlüsselter PONG Nachrichten empfangen" #: src/transport/plugin_transport_wlan.c:1341 #, fuzzy msgid "# WLAN DATA messages processed" msgstr "# verschlüsselter PONG Nachrichten empfangen" #: src/transport/plugin_transport_wlan.c:1402 #, fuzzy msgid "# HELLO beacons sent via WLAN" msgstr "# Bytes gesendet über UDP" #: src/transport/plugin_transport_wlan.c:1511 msgid "WLAN address with invalid size encountered\n" msgstr "" #: src/transport/plugin_transport_wlan.c:1668 #, fuzzy, c-format msgid "Invalid configuration option `%s' in section `%s'\n" msgstr "Konfigurationsdatei `%s' wurde erzeugt.\n" #: src/transport/plugin_transport_wlan.c:1677 #, c-format msgid "Helper binary `%s' not SUID, cannot run WLAN transport\n" msgstr "" #: src/transport/plugin_transport_wlan.c:1687 #, fuzzy, c-format msgid "Missing configuration option `%s' in section `%s'\n" msgstr "Konfigurationsdatei `%s' wurde erzeugt.\n" #: src/transport/transport_api.c:570 #, fuzzy, c-format msgid "Received unexpected message of type %u in %s:%u\n" msgstr "Es wurde eine unbekannte Testbed Nachricht des Typs %u empfangen.\n" #: src/util/bio.c:136 src/util/bio.c:142 #, fuzzy, c-format msgid "Error reading `%s': %s" msgstr "Fehler beim Anlegen des Benutzers" #: src/util/bio.c:143 #, fuzzy msgid "End of file" msgstr "Eine Konfigurationsdatei laden" #: src/util/bio.c:195 #, c-format msgid "Error reading length of string `%s'" msgstr "" #: src/util/bio.c:205 #, c-format msgid "String `%s' longer than allowed (%u > %u)" msgstr "" #: src/util/bio.c:250 #, c-format msgid "Serialized metadata `%s' larger than allowed (%u>%u)" msgstr "" #: src/util/bio.c:264 #, c-format msgid "Metadata `%s' failed to deserialize" msgstr "" #: src/util/client.c:359 #, c-format msgid "" "Could not determine valid hostname and port for service `%s' from " "configuration.\n" msgstr "" #: src/util/client.c:367 #, c-format msgid "Need a non-empty hostname for service `%s'.\n" msgstr "" #: src/util/client.c:685 msgid "Failure to transmit TEST request.\n" msgstr "" #: src/util/client.c:740 src/util/service.c:970 #, c-format msgid "UNIXPATH `%s' too long, maximum length is %llu\n" msgstr "" #: src/util/client.c:882 #, fuzzy, c-format msgid "Could not connect to service `%s', must not be running.\n" msgstr "Verbindung zu gnunetd konnte nicht hergestellt werden.\n" #: src/util/client.c:896 #, fuzzy, c-format msgid "Failure to transmit request to service `%s'\n" msgstr "Fehler beim Senden einer `%s' Anfrage an den SMTP Server.\n" #: src/util/client.c:1149 msgid "Could not submit request, not expecting to receive a response.\n" msgstr "" #: src/util/common_logging.c:239 src/util/common_logging.c:890 msgid "DEBUG" msgstr "DEBUG" #: src/util/common_logging.c:241 src/util/common_logging.c:888 msgid "INFO" msgstr "INFO" #: src/util/common_logging.c:243 src/util/common_logging.c:886 msgid "WARNING" msgstr "WARNUNG" #: src/util/common_logging.c:245 src/util/common_logging.c:884 msgid "ERROR" msgstr "FEHLER" #: src/util/common_logging.c:247 src/util/common_logging.c:892 msgid "NONE" msgstr "" #: src/util/common_logging.c:610 #, fuzzy, c-format msgid "Failed to create or access directory for log file `%s'\n" msgstr "Konfigurationsdatei `%s' konnte nicht geparst werden.\n" #: src/util/common_logging.c:725 #, c-format msgid "Message `%.*s' repeated %u times in the last %s\n" msgstr "" #: src/util/common_logging.c:893 msgid "INVALID" msgstr "" #: src/util/common_logging.c:992 #, fuzzy msgid "unknown address" msgstr "Unbekannter Fehler" #: src/util/common_logging.c:1030 #, fuzzy msgid "invalid address" msgstr "Ungültige Parameter: " #: src/util/configuration.c:244 #, fuzzy, c-format msgid "Syntax error in configuration file `%s' at line %u.\n" msgstr "Syntaxfehler in Konfigurationsdatei `%s' in Zeile %d.\n" #: src/util/configuration.c:816 #, c-format msgid "" "Configuration value '%s' for '%s' in section '%s' is not in set of legal " "choices\n" msgstr "" #: src/util/connection.c:420 #, fuzzy, c-format msgid "Access denied to `%s'\n" msgstr "Zugriff verweigert für `%s' bei %s:%d.\n" #: src/util/connection.c:435 #, c-format msgid "Accepting connection from `%s': %p\n" msgstr "" #: src/util/connection.c:550 #, fuzzy, c-format msgid "" "Failed to establish TCP connection to `%s:%u', no further addresses to try.\n" msgstr "Fehler beim Aufbauen einer Verbindung mit gnunetd.\n" #: src/util/connection.c:739 src/util/connection.c:909 #, fuzzy, c-format msgid "Trying to connect to `%s' (%p)\n" msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" #: src/util/connection.c:748 #, fuzzy, c-format msgid "Failed to connect to `%s' (%p)\n" msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" #: src/util/connection.c:900 #, fuzzy, c-format msgid "Attempt to connect to `%s' failed\n" msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" #: src/util/container_bloomfilter.c:510 #, c-format msgid "" "Size of file on disk is incorrect for this Bloom filter (want %llu, have " "%llu)\n" msgstr "" #: src/util/crypto_random.c:280 #, c-format msgid "Starting `%s' process to generate entropy\n" msgstr "" #: src/util/crypto_random.c:309 #, c-format msgid "libgcrypt has not the expected version (version %s is required).\n" msgstr "" "libgcrypt hat nicht die erwartete Version (Version %s wird vorausgesetzt).\n" #: src/util/crypto_rsa.c:661 src/util/crypto_rsa.c:708 #, fuzzy, c-format msgid "Could not aquire lock on file `%s': %s...\n" msgstr "PID konnte nicht in Datei `%s' geschrieben werden: %s.\n" #: src/util/crypto_rsa.c:666 #, fuzzy msgid "Creating a new private key. This may take a while.\n" msgstr "Ein neuer Hostkey wird erzeugt (dies kann eine Weile dauern).\n" #: src/util/crypto_rsa.c:684 #, c-format msgid "I am host `%s'. Stored new private key in `%s'.\n" msgstr "" #: src/util/crypto_rsa.c:712 src/util/crypto_rsa.c:748 msgid "This may be ok if someone is currently generating a hostkey.\n" msgstr "" #: src/util/crypto_rsa.c:743 #, c-format msgid "" "When trying to read hostkey file `%s' I found %u bytes but I need at least " "%u.\n" msgstr "" #: src/util/crypto_rsa.c:763 #, fuzzy, c-format msgid "File `%s' does not contain a valid private key. Deleting it.\n" msgstr "Die Datei `%s' enthält kein Pseudonym.\n" #: src/util/crypto_rsa.c:781 #, fuzzy, c-format msgid "I am host `%s'. Read private key from `%s'.\n" msgstr "Aufruf von `%s' mit Schlüssel `%s'.\n" #: src/util/crypto_rsa.c:1032 #, c-format msgid "RSA signature verification failed at %s:%d: %s\n" msgstr "RSA Signaturüberprüfung fehlgeschlagen bei %s:%d: %s\n" #: src/util/disk.c:498 #, fuzzy, c-format msgid "`%s' failed for drive `%S': %u\n" msgstr "`%s' fehlgeschlagen für Laufwerk %s: %u\n" #: src/util/disk.c:1062 #, fuzzy, c-format msgid "Expected `%s' to be a directory!\n" msgstr "`%s' erwartet, dass `%s' ein Verzeichnis ist!\n" #: src/util/disk.c:1416 src/util/service.c:1650 #, fuzzy, c-format msgid "Cannot obtain information about user `%s': %s\n" msgstr "Fehler beim Speichern der Konfigurationsdatei: `%s': %s.\n" #: src/util/disk.c:1734 #, fuzzy, c-format msgid "No `%s' specified for service `%s' in configuration.\n" msgstr "In der Konfigurationsdatei wurden keine Anwendungen definiert!\n" #: src/util/getopt.c:669 #, c-format msgid "%s: option `%s' is ambiguous\n" msgstr "%s: Option `%s' ist mehrdeutig\n" #: src/util/getopt.c:693 #, c-format msgid "%s: option `--%s' does not allow an argument\n" msgstr "%s: Option '--%s' erlaubt keinen Parameter\n" #: src/util/getopt.c:698 #, c-format msgid "%s: option `%c%s' does not allow an argument\n" msgstr "%s: Option '%c%s' erlaubt keinen Parameter\n" #: src/util/getopt.c:715 src/util/getopt.c:883 #, c-format msgid "%s: option `%s' requires an argument\n" msgstr "%s: Option `%s' benötigt einen Parameter\n" #: src/util/getopt.c:744 #, c-format msgid "%s: unrecognized option `--%s'\n" msgstr "%s: unbekannte Option '--%s'\n" #: src/util/getopt.c:748 #, c-format msgid "%s: unrecognized option `%c%s'\n" msgstr "%s: unbekannte Option '%c%s'\n" #: src/util/getopt.c:773 #, c-format msgid "%s: illegal option -- %c\n" msgstr "%s: unerlaubte Option -- %c\n" #: src/util/getopt.c:775 #, c-format msgid "%s: invalid option -- %c\n" msgstr "%s: ungültige Option -- %c\n" #: src/util/getopt.c:803 src/util/getopt.c:931 #, c-format msgid "%s: option requires an argument -- %c\n" msgstr "%s: Option benötigt einen Parameter -- %c\n" #: src/util/getopt.c:851 #, c-format msgid "%s: option `-W %s' is ambiguous\n" msgstr "%s: Option '-W %s' ist mehrdeutig\n" #: src/util/getopt.c:869 #, c-format msgid "%s: option `-W %s' does not allow an argument\n" msgstr "%s: Option '-W %s' erlaubt keinen Parameter\n" #: src/util/getopt.c:1035 #, fuzzy, c-format msgid "Use %s to get a list of options.\n" msgstr "Verwenden Sie --help, um eine Liste der Optionen zu erhalten.\n" #: src/util/getopt_helpers.c:86 #, c-format msgid "" "Arguments mandatory for long options are also mandatory for short options.\n" msgstr "" "Parameter, die für lange Optionen zwingend sind, sind auch für kurze " "Optionen zwingend.\n" #: src/util/getopt_helpers.c:258 src/util/getopt_helpers.c:286 #, c-format msgid "You must pass a number to the `%s' option.\n" msgstr "Sie müssen für die Option `%s' zusätzlich eine Zahl angeben.\n" #: src/util/gnunet-resolver.c:148 msgid "perform a reverse lookup" msgstr "" #: src/util/gnunet-resolver.c:154 msgid "Use build-in GNUnet stub resolver" msgstr "" #: src/util/gnunet-rsa.c:64 #, c-format msgid "No hostkey file specified on command line\n" msgstr "" #: src/util/gnunet-rsa.c:112 msgid "print the public key in ASCII format" msgstr "" #: src/util/gnunet-rsa.c:115 msgid "print the hash of the public key in ASCII format" msgstr "" #: src/util/gnunet-rsa.c:118 msgid "print the short hash of the public key in ASCII format" msgstr "" #: src/util/gnunet-rsa.c:124 msgid "Manipulate GNUnet private RSA key files" msgstr "" #: src/util/gnunet-service-resolver.c:288 #, fuzzy, c-format msgid "Could not resolve `%s' (%s): %s\n" msgstr "`%s' konnte nicht aufgelöst werden: %s\n" #: src/util/gnunet-service-resolver.c:358 #: src/util/gnunet-service-resolver.c:399 #, c-format msgid "Could not find IP of host `%s': %s\n" msgstr "IP des Hosts `%s' konnte nicht ermittelt werden: %s\n" #: src/util/helper.c:244 #, fuzzy, c-format msgid "Error reading from `%s': %s\n" msgstr "Fehler beim Anlegen des Benutzers" #: src/util/helper.c:259 #, c-format msgid "Got 0 bytes from helper `%s' (EOF)\n" msgstr "" #: src/util/helper.c:269 #, fuzzy, c-format msgid "Got %u bytes from helper `%s'\n" msgstr "GAP hat ungültige Inhalte von `%s' empfangen.\n" #: src/util/helper.c:278 #, fuzzy, c-format msgid "Failed to parse inbound message from helper `%s'\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/util/helper.c:310 #, fuzzy, c-format msgid "Starting HELPER process `%s'\n" msgstr "Collection `%s' begonnen.\n" #: src/util/helper.c:440 #, fuzzy, c-format msgid "Error writing to `%s': %s\n" msgstr "Fehler beim Anlegen des Benutzers" #: src/util/network.c:1200 #, c-format msgid "" "Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n" msgstr "" #: src/util/os_installation.c:299 #, c-format msgid "" "Could not determine installation path for %s. Set `%s' environment " "variable.\n" msgstr "" #: src/util/os_installation.c:486 #, fuzzy, c-format msgid "Could not find binary `%s' in PATH!\n" msgstr "Knoten `%s' konnte nicht in der Routing Tabelle gefunden werden!\n" #: src/util/os_installation.c:492 #, fuzzy, c-format msgid "access (%s, X_OK) failed: %s\n" msgstr "`%s' schlug fehl: %s\n" #: src/util/os_installation.c:507 #, fuzzy, c-format msgid "stat (%s) failed: %s\n" msgstr "`%s' schlug fehl: %s\n" #: src/util/os_priority.c:305 #, fuzzy, c-format msgid "Failed to open named pipe `%s' for reading: %s\n" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/util/os_priority.c:306 #, fuzzy, c-format msgid "Failed to open named pipe `%s' for writing: %s\n" msgstr "Datei wurde als `%s' gespeichert.\n" #: src/util/plugin.c:89 #, c-format msgid "Initialization of plugin mechanism failed: %s!\n" msgstr "Initialisierung des Plugin Mechanismuses fehlgeschlagen: %s!\n" #: src/util/plugin.c:146 #, fuzzy, c-format msgid "`%s' failed to resolve method '%s' with error: %s\n" msgstr "" "`%s' konnte die Methode '%s%s' nicht auflösen. Ort: %s:%d. Fehler: %s\n" #: src/util/plugin.c:219 #, fuzzy, c-format msgid "`%s' failed for library `%s' with error: %s\n" msgstr "`%s' fehlgeschlagen für die Bibliothek `%s'. Ort: %s:%d. Fehler: %s\n" #: src/util/plugin.c:349 #, fuzzy msgid "Could not determine plugin installation path.\n" msgstr "Öffentliche IP-Adresse konnte nicht ermittelt werden.\n" #: src/util/pseudonym.c:276 #, fuzzy, c-format msgid "Failed to parse metadata about pseudonym from file `%s': %s\n" msgstr "Fehler beim Parsen der Gerätedaten von `%s' bei %s:%d.\n" #: src/util/pseudonym.c:407 src/util/pseudonym.c:433 #, fuzzy msgid "no-name" msgstr "Name anzeigen" #: src/util/resolver_api.c:202 #, fuzzy, c-format msgid "Must specify `%s' for `%s' in configuration!\n" msgstr "Versuche, Datei `%s' für MySQL Konfiguration zu verwenden.\n" #: src/util/resolver_api.c:221 #, fuzzy, c-format msgid "" "Must specify `%s' or numeric IP address for `%s' of `%s' in configuration!\n" msgstr "" "Sie müssen für `%s' in der Sektion `%s' der Konfigurationsdatei eine " "positive Zahl angeben.\n" #: src/util/resolver_api.c:347 #, fuzzy, c-format msgid "Timeout trying to resolve IP address `%s'.\n" msgstr "GNUnet verwendet nun die IP-Adresse %u.%u.%u.%u.\n" #: src/util/resolver_api.c:351 #, fuzzy, c-format msgid "Timeout trying to resolve hostname `%s'.\n" msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #: src/util/resolver_api.c:890 #, fuzzy, c-format msgid "Could not resolve our FQDN : %s\n" msgstr "`%s' konnte nicht aufgelöst werden: %s\n" #: src/util/scheduler.c:786 msgid "Looks like we're busy waiting...\n" msgstr "" #: src/util/scheduler.c:916 #, c-format msgid "Attempt to cancel dead task %llu!\n" msgstr "" #: src/util/server.c:483 #, fuzzy, c-format msgid "`%s' failed for port %d (%s).\n" msgstr "`%s' fehlgeschlagen für Laufwerk %s: %u\n" #: src/util/server.c:492 #, fuzzy, c-format msgid "`%s' failed for port %d (%s): address already in use\n" msgstr "`%s' schlug fehl für Port %d: %s. Läuft gnunetd bereits?\n" #: src/util/server.c:497 #, fuzzy, c-format msgid "`%s' failed for `%s': address already in use\n" msgstr "`%s' schlug fehl für Port %d: %s. Läuft gnunetd bereits?\n" #: src/util/server.c:827 #, c-format msgid "" "Processing code for message of type %u did not call " "GNUNET_SERVER_receive_done after %llums\n" msgstr "" #: src/util/service.c:135 src/util/service.c:161 src/util/service.c:204 #: src/util/service.c:225 src/util/service.c:232 #, c-format msgid "Invalid format for IP: `%s'\n" msgstr "Ungültiges Format für IP: `%s'\n" #: src/util/service.c:188 #, c-format msgid "Invalid network notation ('/%d' is not legal in IPv4 CIDR)." msgstr "Ungültige Netzwerk Notation ('/%d ist nicht gültig in IPv4 CIDR)." #: src/util/service.c:281 #, c-format msgid "Invalid network notation (does not end with ';': `%s')\n" msgstr "Ungültige Netzwerk Notation (endet nicht mit ';': `%s')\n" #: src/util/service.c:313 #, fuzzy, c-format msgid "Wrong format `%s' for netmask\n" msgstr "Falsches Format `%s' für Netzmaske: %s\n" #: src/util/service.c:343 #, fuzzy, c-format msgid "Wrong format `%s' for network\n" msgstr "Falsches Format `%s' für Netzwerk: %s\n" #: src/util/service.c:698 #, c-format msgid "Access denied to UID %d / GID %d\n" msgstr "" #: src/util/service.c:703 #, fuzzy, c-format msgid "Unknown address family %d\n" msgstr "Unbekannte Operation `%s'\n" #: src/util/service.c:710 #, c-format msgid "Access from `%s' denied to service `%s'\n" msgstr "" #: src/util/service.c:765 #, c-format msgid "Could not parse IPv4 network specification `%s' for `%s:%s'\n" msgstr "" #: src/util/service.c:802 #, c-format msgid "Could not parse IPv6 network specification `%s' for `%s:%s'\n" msgstr "" #: src/util/service.c:920 #, c-format msgid "" "Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n" msgstr "" #: src/util/service.c:990 #, c-format msgid "" "Disabling UNIX domain socket support for service `%s', failed to create UNIX " "domain socket: %s\n" msgstr "" #: src/util/service.c:1007 #, c-format msgid "Have neither PORT nor UNIXPATH for service `%s', but one is required\n" msgstr "" #: src/util/service.c:1241 msgid "Could not access a pre-bound socket, will try to bind myself\n" msgstr "" #: src/util/service.c:1292 src/util/service.c:1310 #, c-format msgid "Specified value for `%s' of service `%s' is invalid\n" msgstr "" #: src/util/service.c:1337 #, c-format msgid "Could not access pre-bound socket %u, will try to bind myself\n" msgstr "" #: src/util/service.c:1506 #, fuzzy, c-format msgid "Failed to start `%s' at `%s'\n" msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" #: src/util/service.c:1539 #, fuzzy, c-format msgid "Service `%s' runs at %s\n" msgstr "Knoten `%s' mit Vertrauen %8u und Adresse `%s'\n" #: src/util/service.c:1588 msgid "Service process failed to initialize\n" msgstr "" #: src/util/service.c:1592 msgid "Service process could not initialize server function\n" msgstr "" #: src/util/service.c:1596 msgid "Service process failed to report status\n" msgstr "" #: src/util/service.c:1651 msgid "No such user" msgstr "" #: src/util/service.c:1664 #, c-format msgid "Cannot change user/group to `%s': %s\n" msgstr "Benutzer/Gruppe kann nicht zu `%s' gewechselt werden: %s\n" #: src/util/service.c:1729 msgid "do daemonize (detach from terminal)" msgstr "" #: src/util/signal.c:80 #, fuzzy, c-format msgid "signal (%d, %p) returned %d.\n" msgstr "Aufruf von `%s' gibt %d zurück.\n" #: src/util/strings.c:144 msgid "b" msgstr "b" #: src/util/strings.c:334 #, c-format msgid "Character sets requested were `%s'->`%s'\n" msgstr "" #: src/util/strings.c:481 msgid "Failed to expand `$HOME': environment variable `HOME' not set" msgstr "" #: src/util/strings.c:573 msgid "ms" msgstr "ms" #: src/util/strings.c:578 msgid "eternity" msgstr "" #: src/util/strings.c:582 msgid "s" msgstr "s" #: src/util/strings.c:586 msgid "m" msgstr "m" #: src/util/strings.c:590 msgid "h" msgstr "h" #: src/util/strings.c:594 msgid " days" msgstr " Tage" #: src/util/strings.c:618 msgid "end of time" msgstr "" #: src/util/strings.c:1012 msgid "IPv6 address did not start with `['\n" msgstr "" #: src/util/strings.c:1020 msgid "IPv6 address did contain ':' to separate port number\n" msgstr "" #: src/util/strings.c:1026 msgid "IPv6 address did contain ']' before ':' to separate port number\n" msgstr "" #: src/util/strings.c:1033 msgid "IPv6 address did contain a valid port number after the last ':'\n" msgstr "" #: src/util/strings.c:1042 #, fuzzy, c-format msgid "Invalid IPv6 address `%s': %s\n" msgstr "Ungültiger Parameter: `%s'\n" #: src/vpn/gnunet-service-vpn.c:511 src/vpn/gnunet-service-vpn.c:1071 #, fuzzy msgid "# Active tunnels" msgstr "GNUnet Konfiguration" #: src/vpn/gnunet-service-vpn.c:608 src/vpn/gnunet-service-vpn.c:645 #, fuzzy msgid "# peers connected to mesh tunnels" msgstr "# verbundener Knoten" #: src/vpn/gnunet-service-vpn.c:699 #, fuzzy msgid "# Bytes given to mesh for transmission" msgstr "# PING Nachrichten erstellt" #: src/vpn/gnunet-service-vpn.c:737 #, fuzzy msgid "# Bytes dropped in mesh queue (overflow)" msgstr "# Bytes verworfen von UDP (outgoing)" #: src/vpn/gnunet-service-vpn.c:772 #, fuzzy msgid "# Mesh tunnels created" msgstr "# dht Anfragen weitergeleitet" #: src/vpn/gnunet-service-vpn.c:795 #, fuzzy msgid "Failed to setup mesh tunnel!\n" msgstr "Statistiken über den Netzwerkverkehr konnten nicht ermittelt werden.\n" #: src/vpn/gnunet-service-vpn.c:973 #, c-format msgid "Protocol %u not supported, dropping\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1291 msgid "# ICMPv4 packets dropped (not allowed)" msgstr "" #: src/vpn/gnunet-service-vpn.c:1312 msgid "# ICMPv6 packets dropped (not allowed)" msgstr "" #: src/vpn/gnunet-service-vpn.c:1517 #, fuzzy msgid "# Packets received from TUN interface" msgstr "Empfangene Client-Nachricht ist ungültig.\n" #: src/vpn/gnunet-service-vpn.c:1555 src/vpn/gnunet-service-vpn.c:1596 #, c-format msgid "Packet received for unmapped destination `%s' (dropping it)\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1606 msgid "Received IPv4 packet with options (dropping it)\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1620 #, c-format msgid "Received packet of unknown protocol %d from TUN (dropping it)\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1704 #, fuzzy msgid "# ICMP packets received from mesh" msgstr "Empfangene Client-Nachricht ist ungültig.\n" #: src/vpn/gnunet-service-vpn.c:2045 #, fuzzy msgid "# UDP packets received from mesh" msgstr "Empfangene Client-Nachricht ist ungültig.\n" #: src/vpn/gnunet-service-vpn.c:2203 #, fuzzy msgid "# TCP packets received from mesh" msgstr "Empfangene Client-Nachricht ist ungültig.\n" #: src/vpn/gnunet-service-vpn.c:2354 msgid "Failed to find unallocated IPv4 address in VPN's range\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:2409 #, fuzzy msgid "Failed to find unallocated IPv6 address in VPN's range\n" msgstr "Die öffentliche IPv6-Adresse konnte nicht ermittelt werden!\n" #: src/vpn/gnunet-service-vpn.c:2448 src/vpn/gnunet-service-vpn.c:2661 #, fuzzy msgid "# Active destinations" msgstr "GNUnet Konfiguration" #: src/vpn/gnunet-service-vpn.c:2734 msgid "Failed to allocate IP address for new destination\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:3141 msgid "IPv6 support disabled as this system does not support IPv6\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:3173 msgid "IPv4 support disabled as this system does not support IPv4\n" msgstr "" #: src/vpn/gnunet-vpn.c:151 #, fuzzy msgid "Error creating tunnel\n" msgstr "Hostkey wurde erfolgreich erzeugt.\n" #: src/vpn/gnunet-vpn.c:195 src/vpn/gnunet-vpn.c:226 #, fuzzy, c-format msgid "Option `%s' makes no sense with option `%s'.\n" msgstr "Option `%s' macht keinen Sinn ohne die Option `%s'.\n" #: src/vpn/gnunet-vpn.c:208 #, fuzzy, c-format msgid "Option `%s' or `%s' is required.\n" msgstr "%s: Option `%s' ist mehrdeutig\n" #: src/vpn/gnunet-vpn.c:220 #, fuzzy, c-format msgid "Option `%s' or `%s' is required when using option `%s'.\n" msgstr "Option `%s' macht keinen Sinn ohne die Option `%s'.\n" #: src/vpn/gnunet-vpn.c:238 #, fuzzy, c-format msgid "`%s' is not a valid peer identifier.\n" msgstr "`%s' ist nicht verfügbar." #: src/vpn/gnunet-vpn.c:260 #, fuzzy, c-format msgid "`%s' is not a valid IP address.\n" msgstr "`%s' ist nicht verfügbar." #: src/vpn/gnunet-vpn.c:296 msgid "request that result should be an IPv4 address" msgstr "" #: src/vpn/gnunet-vpn.c:299 msgid "request that result should be an IPv6 address" msgstr "" #: src/vpn/gnunet-vpn.c:302 msgid "print IP address only after mesh tunnel has been created" msgstr "" #: src/vpn/gnunet-vpn.c:305 msgid "how long should the mapping be valid for new tunnels?" msgstr "" #: src/vpn/gnunet-vpn.c:308 msgid "destination IP for the tunnel" msgstr "" #: src/vpn/gnunet-vpn.c:311 msgid "peer offering the service we would like to access" msgstr "" #: src/vpn/gnunet-vpn.c:314 msgid "name of the service we would like to access" msgstr "" #: src/vpn/gnunet-vpn.c:317 #, fuzzy msgid "service is offered via TCP" msgstr "# Bytes empfangen über TCP" #: src/vpn/gnunet-vpn.c:320 #, fuzzy msgid "service is offered via UDP" msgstr "# Bytes empfangen über UDP" #: src/vpn/gnunet-vpn.c:329 msgid "Setup tunnels via VPN." msgstr "" #: src/include/gnunet_common.h:497 src/include/gnunet_common.h:502 #: src/include/gnunet_common.h:508 #, fuzzy, c-format msgid "Assertion failed at %s:%d.\n" msgstr "Absicherung fehlgeschlagen bei %s:%d.\n" #: src/include/gnunet_common.h:518 #, fuzzy, c-format msgid "External protocol violation detected at %s:%d.\n" msgstr "Absicherung fehlgeschlagen bei %s:%d.\n" #: src/include/gnunet_common.h:539 src/include/gnunet_common.h:546 #, fuzzy, c-format msgid "`%s' failed on file `%s' at %s:%d with error: %s\n" msgstr "`%s' schlug bei Datei `%s' fehl. Ort: %s:%d. Fehler: %s\n" #, fuzzy #~ msgid "Received malformed message via %s. Ignored.\n" #~ msgstr "" #~ "Es wurde eine ungültige Nachricht per SMTP empfangen (ungültige Größe).\n" #, fuzzy #~ msgid "SMTP filter string to invalid, lacks ': '\n" #~ msgstr "SMTP Filterstring zu lang, wurde auf `%s' abgeschnitten\n" #~ msgid "SMTP filter string to long, capped to `%s'\n" #~ msgstr "SMTP Filterstring zu lang, wurde auf `%s' abgeschnitten\n" #, fuzzy #~ msgid "SMTP: `%s' failed: %s.\n" #~ msgstr "`%s' schlug fehl: %s\n" #, fuzzy #~ msgid "No email-address specified, can not start SMTP transport.\n" #~ msgstr "" #~ "Kein Filter für E-Mail angegeben, es kann keine Bekanntmachung erstellt " #~ "werden.\n" #, fuzzy #~ msgid "# bytes received via SMTP" #~ msgstr "# Bytes empfangen über TCP" #, fuzzy #~ msgid "# bytes sent via SMTP" #~ msgstr "# Bytes gesendet über TCP" #, fuzzy #~ msgid "# bytes dropped by SMTP (outgoing)" #~ msgstr "# Bytes verworfen von TCP (ausgehend)" #, fuzzy #~ msgid "# Peers connected" #~ msgstr "# verbundener Knoten" #, fuzzy #~ msgid "%s failed for `%s' at %s:%d: `%s'\n" #~ msgstr "`%s' schlug fehl bei %s:%d mit dem Fehler: `%s'.\n" #, fuzzy #~ msgid "Failed to transmit shutdown ACK.\n" #~ msgstr "Fehler beim Starten der Collection.\n" #, fuzzy #~ msgid "Unable to initialize Postgres with configuration `%s': %s" #~ msgstr "Fehler beim Speichern der Konfigurationsdatei `%s':" #, fuzzy #~ msgid "Failed to transmit message to `%s' service.\n" #~ msgstr "`%s' Dienst konnte nicht initialisiert werden.\n" #, fuzzy #~ msgid "Target is %d connections per peer." #~ msgstr "Fehler beim Aufbauen einer Verbindung mit gnunetd.\n" #, fuzzy #~ msgid "Copying file with RENAME (%s,%s)\n" #~ msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" #, fuzzy #~ msgid "Copying file with command scp %s %s\n" #~ msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" #, fuzzy #~ msgid "Finished copying all blacklist files!\n" #~ msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #, fuzzy #~ msgid "Offering HELLO of peer %s to peer %s\n" #~ msgstr "Verbindung zu %u.%u.%u.%u:%u fehlgeschlagen: %s\n" #, fuzzy #~ msgid "Failed during blacklist file copying!\n" #~ msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #, fuzzy #~ msgid "# bytes payload received for other peers" #~ msgstr "# Bytes des Typs %d empfangen" #, fuzzy #~ msgid "# fast reconnects failed" #~ msgstr "# verbundener Knoten" #, fuzzy #~ msgid "# peers disconnected due to timeout" #~ msgstr "# geschlossener Verbindungen (HANGUP gesendet)" #, fuzzy #~ msgid "# peers disconnected due to global disconnect" #~ msgstr "# Knotenankündigungen empfangen" #, fuzzy #~ msgid "# messages not sent (no such peer or not connected)" #~ msgstr "# defragmentierter Nachrichten" #, fuzzy #~ msgid "# unexpected CONNECT_ACK messages" #~ msgstr "COUNT Nachrichten versenden" #, fuzzy #~ msgid "# wlan session timeouts" #~ msgstr "# Sitzungsschlüssel akzeptiert" #, fuzzy #~ msgid "# wlan session created" #~ msgstr "# Sitzungsschlüssel akzeptiert" #, fuzzy #~ msgid "# wlan pending fragments" #~ msgstr "# verworfener Nachrichten" #, fuzzy #~ msgid "# wlan fragments send" #~ msgstr "# verworfener Nachrichten" #, fuzzy #~ msgid "# wlan whole messages received" #~ msgstr "# verschlüsselter PING Nachrichten empfangen" #, fuzzy #~ msgid "# wlan hello messages received" #~ msgstr "# verschlüsselter PING Nachrichten empfangen" #, fuzzy #~ msgid "# wlan fragments received" #~ msgstr "# verworfener Nachrichten" #, fuzzy #~ msgid "# wlan acks received" #~ msgstr "# gap Anfragen insgesamt empfangen" #, fuzzy #~ msgid "# wlan messages for this client received" #~ msgstr "# verschlüsselter PING Nachrichten empfangen" #, fuzzy #~ msgid "# wlan messages inside WLAN_HELPER_DATA received" #~ msgstr "# verschlüsselter PING Nachrichten empfangen" #, fuzzy #~ msgid "Unknown user `%s'\n" #~ msgstr "Unbekannte Operation `%s'\n" #, fuzzy #~ msgid "Namespace `%s' unknown.\n" #~ msgstr "Namespace `%s' hat das Rating %d.\n" #, fuzzy #~ msgid "Failed to connect to statistics service!\n" #~ msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" #, fuzzy #~ msgid "Failed to send to `%s': %s\n" #~ msgstr "Datei wurde als `%s' gespeichert.\n" #, fuzzy #~ msgid "Could not access file: %s\n" #~ msgstr "`%s' konnte nicht aufgelöst werden: %s\n" #, fuzzy #~ msgid "`%s' failed on file `%s': %s" #~ msgstr "`%s' fehlgeschlagen für Laufwerk %s: %u\n" #, fuzzy #~ msgid "# bytes TCP was asked to transmit" #~ msgstr "# Bytes des Typs %d übertragen" #, fuzzy #~ msgid "# bytes discarded by TCP (failed to connect)" #~ msgstr "# Bytes verworfen von TCP (ausgehend)" #, fuzzy #~ msgid "# wlan messages queued" #~ msgstr "# verschlüsselter PING Nachrichten empfangen" #~ msgid "print this help" #~ msgstr "Gibt diese Hilfe aus" #~ msgid "print the version number" #~ msgstr "Versionsnummer ausgeben" #~ msgid "be verbose" #~ msgstr "umfangreiche Meldungen ausgeben" #~ msgid "use configuration file FILENAME" #~ msgstr "Konfigurationsdatei FILENAME verwenden" #, fuzzy #~ msgid "Failed to stop service `%s'!\n" #~ msgstr "Fehler beim Binden an UDP Port %d.\n" #, fuzzy #~ msgid "Failed to start service `%s'!\n" #~ msgstr "Der Transportdienst auf Port %d konnte nicht gestartet werden.\n" #, fuzzy #~ msgid "Service `%s' is not running.\n" #~ msgstr "`%s' ist keine Datei.\n" #, fuzzy #~ msgid "Binary implementing service `%s' not known!\n" #~ msgstr "" #~ "Signatur kann nicht verifiziert werden, der Knoten `%s' ist uns nicht " #~ "bekannt!\n" #, fuzzy #~ msgid "Service `%s' stopped\n" #~ msgstr "Dienst gelöscht.\n" #, fuzzy #~ msgid "Unable to start service `%s': %s\n" #~ msgstr "Fehler beim Speichern der Konfigurationsdatei `%s':" #, fuzzy #~ msgid "Unable to accept connection for service `%s': %s\n" #~ msgstr "Fehler beim Speichern der Konfigurationsdatei `%s':" #, fuzzy #~ msgid "Peer `%s' plugin: `%s' address `%s'\n" #~ msgstr "Knoten `%s' mit Vertrauen %8u und Adresse `%s'\n" #, fuzzy #~ msgid "Failed to transmit request to DATASTORE.\n" #~ msgstr "Fehler beim Senden einer `%s' Anfrage an den SMTP Server.\n" #, fuzzy #~ msgid "Failed to create IPv4 broadcast socket on port %d\n" #~ msgstr "Fehler beim Aktualisieren der Daten des Moduls `%s'\n" #, fuzzy #~ msgid "Failed to load block plugin `%s'\n" #~ msgstr "Anwendung `%s' konnte nicht initialisiert werden.\n" #, fuzzy #~ msgid "Could not resolve our FQDN : %s %u\n" #~ msgstr "`%s' konnte nicht aufgelöst werden: %s\n" #, fuzzy #~ msgid "Failed to load dhtlog plugin for `%s'\n" #~ msgstr "Fehler beim Lesen der Freunde-Liste von `%s'\n" #, fuzzy #~ msgid "Found peer `%s'\n" #~ msgstr "Ich bin Peer `%s'.\n" #, fuzzy #~ msgid "Failed to initialize MySQL database connection for dhtlog.\n" #~ msgstr "SQLite Datenbank konnte nicht initialisiert werden.\n" #, fuzzy #~ msgid "Loading udp transport plugin\n" #~ msgstr "Teste Transport(e) %s\n" #, fuzzy #~ msgid "# SET QUOTA messages received" #~ msgstr "# verschlüsselter PONG Nachrichten empfangen" #, fuzzy #~ msgid "curl failed for `%s' at %s:%d: `%s'\n" #~ msgstr "`%s' schlug fehl bei %s:%d mit dem Fehler: `%s'.\n" #, fuzzy #~ msgid "Phase 3: sending messages\n" #~ msgstr "Zustellung der Nachricht `%s' fehlgeschlagen.\n" #, fuzzy #~ msgid "Loading HTTPS transport plugin `%s'\n" #~ msgstr "Teste Transport(e) %s\n" #, fuzzy #~ msgid "Failed to load transport plugin for https\n" #~ msgstr "Anwendung `%s' konnte nicht initialisiert werden.\n" #, fuzzy #~ msgid "Fail! Could not connect peers\n" #~ msgstr "`%s': Verbindung konnte nicht hergestellt werden.\n" #, fuzzy #~ msgid "Loading tcp transport plugin\n" #~ msgstr "Teste Transport(e) %s\n" #, fuzzy #~ msgid "Failed to load transport plugin for tcp\n" #~ msgstr "Anwendung `%s' konnte nicht initialisiert werden.\n" #, fuzzy #~ msgid "# HTTP peers active" #~ msgstr "# Bytes empfangen über TCP" #, fuzzy #~ msgid "Connection: %X: %s failed at %s:%d: `%s'\n" #~ msgstr "`%s' schlug fehl bei %s:%d mit dem Fehler: `%s'.\n" #, fuzzy #~ msgid "Misconfigured address to bind to in configuration!\n" #~ msgstr "In der Konfigurationsdatei wurden keine Anwendungen definiert!\n" #, fuzzy #~ msgid "Required configuration options missing in section `%s'\n" #~ msgstr "" #~ "Es muss eine Liste von Freunden in der Konfigurationsdatei unter `%s' in " #~ "der Sektion `%s' angegeben werden.\n" #, fuzzy #~ msgid "Loading HTTP transport plugin `%s'\n" #~ msgstr "Teste Transport(e) %s\n" #, fuzzy #~ msgid "Failed to load transport plugin for http\n" #~ msgstr "Anwendung `%s' konnte nicht initialisiert werden.\n" #, fuzzy #~ msgid "# PING messages decrypted" #~ msgstr "# PING Nachrichten erstellt" #, fuzzy #~ msgid "Failed to connect to core service\n" #~ msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" #, fuzzy #~ msgid "# bytes successfully transmitted by plugins" #~ msgstr "# Bytes des Typs %d übertragen" #, fuzzy #~ msgid "# connected addresses" #~ msgstr "# verbundener Knoten" #, fuzzy #~ msgid "# transport failed to selected peer address" #~ msgstr "Transport %d wird ausgewählten anderen Knoten bekannt gegeben.\n" #, fuzzy #~ msgid "# peer addresses considered valid" #~ msgstr "# Knotenankündigungen empfangen" #, fuzzy #~ msgid "# PING with HELLO messages sent" #~ msgstr "# PING Nachrichten erstellt" #, fuzzy #~ msgid "# HELLOs received for validation" #~ msgstr "# Blöcke migriert" #, fuzzy #~ msgid "Received `%s' message from `%s' destined for `%s' which is not me!\n" #~ msgstr "Empfangener PING ist nicht an uns gerichtet!\n" #, fuzzy #~ msgid "Could not send PONG to `%s': no address available\n" #~ msgstr "Knoten `%s' konnte nicht in der Routing Tabelle gefunden werden!\n" #, fuzzy #~ msgid "# HELLO messages received from other peers" #~ msgstr "Ungültige `%s' Nachricht von Knoten `%s' empfangen.\n" #~ msgid "Error" #~ msgstr "Fehler" #~ msgid "Help" #~ msgstr "Hilfe" #, fuzzy #~ msgid "Error!" #~ msgstr "Fehler" #~ msgid "No" #~ msgstr "Nein" #~ msgid "Yes" #~ msgstr "Ja" #, fuzzy #~ msgid "Abort" #~ msgstr "_über" #, fuzzy #~ msgid "Ok" #~ msgstr "k" #~ msgid "" #~ "Welcome to GNUnet!\n" #~ "\n" #~ "This assistant will ask you a few basic questions in order to configure " #~ "GNUnet.\n" #~ "\n" #~ "Please visit our homepage at\n" #~ "\thttp://gnunet.org/\n" #~ "and join our community at\n" #~ "\thttp://gnunet.org/drupal/\n" #~ "\n" #~ "Have a lot of fun,\n" #~ "\n" #~ "the GNUnet team" #~ msgstr "" #~ "Willkommen bei GNUnet!\n" #~ "\n" #~ "Dieser Assistent wird Ihnen einige grundlegende Fragen stellen, um GNUnet " #~ "zu konfigurieren.\n" #~ "\n" #~ "Bitte besuchen Sie unsere Homepage\n" #~ "\thttp://gnunet.org\n" #~ "und schließen Sie sich unserer Community an:\n" #~ "\thttps://gnunet.org/drupal/\n" #~ "\n" #~ "Viel Spaß,\n" #~ "\n" #~ "das GNUnet-Team" #~ msgid "" #~ "Choose the network interface that connects your computer to the internet " #~ "from the list below." #~ msgstr "" #~ "Wählen Sie das Netzwerkgerät, das Ihren Computer mit dem Internet " #~ "verbindet, aus unten stehender Liste." #~ msgid "" #~ "The \"Network interface\" is the device that connects your computer to " #~ "the internet. This is usually a modem, an ISDN card or a network card in " #~ "case you are using DSL." #~ msgstr "" #~ "Das \"Netzwerkgerät\" ist das Gerät, das Ihren Computer mit dem Internet " #~ "verbindet. Dies ist üblicherweise ein Modem, eine ISDN-Karte oder eine " #~ "Netzwerkkarte falls Sie DSL nutzen." #, fuzzy #~ msgid "Network configuration: interface" #~ msgstr "Netzwerkgerät:" #~ msgid "" #~ "What is the name of the network interface that connects your computer to " #~ "the Internet?" #~ msgstr "" #~ "Was ist der Name des Netzwerkgerätes, das Ihren Computer mit dem Internet " #~ "verbindet?" #, fuzzy #~ msgid "Network configuration: IP" #~ msgstr "GNUnet Konfiguration" #, fuzzy #~ msgid "What is this computer's public IP address or hostname?" #~ msgstr "" #~ "Wie heißt die öffentliche IP-Adresse oder der öffentliche Name dieses " #~ "Computers?\n" #~ "Wenn Sie nicht sicher sind, lassen Sie dieses Feld leer." #, fuzzy #~ msgid "" #~ "If your provider always assigns the same IP-Address to you (a \"static\" " #~ "IP-Address), enter it into the \"IP-Address\" field. If your IP-Address " #~ "changes every now and then (\"dynamic\" IP-Address) but there's a " #~ "hostname that always points to your actual IP-Address (\"Dynamic DNS\"), " #~ "you can also enter it here.\n" #~ "If left empty, GNUnet will try to automatically detect the IP.\n" #~ "You can specify a hostname, GNUnet will then use DNS to resolve it.\n" #~ "If in doubt, leave this empty." #~ msgstr "" #~ "Wenn Ihr Provider Ihnen immer die gleiche IP-Adresse zuweist (eine " #~ "\"statische\" IP-Adresse), so geben Sie diese in das \"IP-Adresse\"-Feld " #~ "ein. Wenn sich Ihre IP-Adresse immer wieder ändert (\"dynamische\" IP-" #~ "Adresse), es jedoch einen Rechnernamen gibt, der immer auf Ihre aktuelle " #~ "IP-Adresse verweist, so können Sie diesen ebenfalls eintragen.\n" #~ "Wenn Sie nicht sicher sind, so können Sie das Feld leer lassen. GNUnet " #~ "wird dann versuchen, Ihre IP-Adresse automatisch zu bestimmen." #, fuzzy #~ msgid "Bandwidth configuration: upload" #~ msgstr "GNUnet Konfiguration" #, fuzzy #~ msgid "How much upstream bandwidth (in bytes/s) may be used?" #~ msgstr "Wieviel Upstream (Bytes/s) darf verwendet werden?" #, fuzzy #~ msgid "" #~ "You can limit GNUnet's resource usage here.\n" #~ "\n" #~ "The \"upstream\" is the data channel through which data is *sent* to the " #~ "internet. The limit is the maximum amount which GNUnet is allowed to use. " #~ "If you have a flatrate, you can set it to the maximum speed of your " #~ "internet connection. You should not use a value that is higher than what " #~ "your actual connection allows." #~ msgstr "" #~ "Hier können Sie GNUnets Ressourcenverwendung einschränken.\n" #~ "\n" #~ "Der \"Upstream\" ist der Datenkanal, durch den Daten an das Internet " #~ "*gesendet* werden. Das Limit ist entweder das gesamte Maximum für diesem " #~ "Computer oder wieviel GNUnet selbst verwenden darf. Dies können Sie " #~ "später festlegen. Wenn Sie eine Flatrate haben, können Sie die maximale " #~ "Geschwindigkeit Ihrer Internetverbindung angeben." #, fuzzy #~ msgid "Bandwidth configuration: download" #~ msgstr "GNUnet Konfiguration" #, fuzzy #~ msgid "How much downstream bandwidth (in bytes/s) may be used?" #~ msgstr "Wieviel Downstream (Bytes/s) darf verwendet werden?" #, fuzzy #~ msgid "" #~ "You can limit GNUnet's resource usage here.\n" #~ "\n" #~ "The \"downstream\" is the data channel through which data is *received* " #~ "from the internet. The limit is the maximum amount which GNUnet is " #~ "allowed to use. If you have a flatrate, you can set it to the maximum " #~ "speed of your internet connection. You should not use a value that is " #~ "higher than what your actual connection allows." #~ msgstr "" #~ "Hier können Sie GNUnets Ressourcenverwendung einschränken.\n" #~ "\n" #~ "Der \"Downstream\" ist der Datenkanal, durch den Daten vom Internet " #~ "*empfangen* werden. Das Limit ist entweder das gesamte Maximum für diesem " #~ "Computer oder wieviel GNUnet selbst verwenden darf. Dies können Sie " #~ "später festlegen. Wenn Sie eine Flatrate haben, können Sie die maximale " #~ "Geschwindigkeit Ihrer Internetverbindung angeben." #, fuzzy #~ msgid "Quota configuration" #~ msgstr "GNUnet Konfiguration" #, fuzzy #~ msgid "" #~ "The GNUnet datastore contains all content that GNUnet needs to store " #~ "(indexed, inserted and migrated content)." #~ msgstr "" #~ "Was ist die maximale Größe des GNUnet Datenspeichers (in MB)?\n" #~ "Der GNUnet Datenspeicher enthält alle Daten, die GNUnet erzeugt " #~ "(Indexdaten, eingefügte und migrierte Inhalte)." #, fuzzy #~ msgid "Daemon configuration: user account" #~ msgstr "Fehler beim Anlegen des Benutzerkontos:" #, fuzzy #~ msgid "" #~ "For security reasons, it is a good idea to let this setup create a new " #~ "user account under which the GNUnet service is started at system " #~ "startup.\n" #~ "\n" #~ "However, GNUnet may not be able to access files other than its own. This " #~ "includes files you want to publish in GNUnet. You'll have to grant read " #~ "permissions to the user specified below.\n" #~ "\n" #~ "Leave the field empty to run GNUnet with system privileges.\n" #~ msgstr "" #~ "Geben Sie den Benutzer an, dem der GNUnet Dienst gehören soll.\n" #~ "\n" #~ "Aus Sicherheitsgründen ist es eine gute Idee, dieses Setup ein neues " #~ "Benutzerkonto anlegen zu lassen, unter dem der GNUnet Dienst beim " #~ "Systemstart läuft.\n" #~ "\n" #~ "Natürlich kann GNUnet dann nur auf seine eigenen Dateien zugreifen. Dies " #~ "betrifft auch Dateien, die Sie im GNUnet veröffentlichen möchten. Sie " #~ "müssen dann dem unten angegebenen Benutzerkonto zuerst Leseberechtigungen " #~ "geben.\n" #~ "\n" #~ "Lassen Sie dieses Feld leer, wenn Sie GNUnet mit Systemprivilegien laufen " #~ "lassen möchten.\n" #~ "\n" #~ "GNUnet Benutzer:" #, fuzzy #~ msgid "" #~ "For security reasons, it is a good idea to let this setup create a new " #~ "group for the chosen user account.\n" #~ "\n" #~ "You can also specify a already existent group here.\n" #~ "\n" #~ "Only members of this group will be allowed to start and stop the the " #~ "GNUnet server and have access to GNUnet server data.\n" #~ msgstr "" #~ "Definieren Sie eine Gruppe, der der GNUnet Dienst gehört.\n" #~ "\n" #~ "Aus Sicherheitsgründen ist es eine gute Idee, dieses Setup eine neue " #~ "Gruppe für das gewählte Benutzerkonto anlegen zu lassen.\n" #~ "\n" #~ "Sie können hier auch eine bestehende Gruppe angeben.\n" #~ "\n" #~ "Nur Mitglieder dieser Gruppe dürfen den GNUnet Server starten und " #~ "anhalten und haben Zugriff auf die Daten des GNUnet Servers.\n" #~ "\n" #~ "GNUnet Gruppe:" #, fuzzy #~ msgid "" #~ "If you say \"yes\" here, the GNUnet background process will be " #~ "automatically started when you turn on your computer. If you say \"no\" " #~ "here, you have to launch GNUnet yourself each time you want to use it." #~ msgstr "" #~ "Möchten Sie GNUnet als Systemdienst starten?\n" #~ "\n" #~ "Wenn Sie hier \"Ja\" sagen, so wird der GNUnet Hintergrundprozess " #~ "jedesmal automatisch gestartet, wenn Sie Ihren Computer einschalten. Wenn " #~ "Sie hier \"Nein\" sagen, so müssen Sie GNUnet jedesmal selbst starten, " #~ "wenn Sie es verwenden möchten." #, fuzzy #~ msgid "Unable to create user account for daemon." #~ msgstr "Fehler beim Anlegen des Benutzerkontos:" #, fuzzy #~ msgid "Save configuration?" #~ msgstr "GNUnet Konfiguration" #, fuzzy #~ msgid "GNUnet Configuration" #~ msgstr "GNUnet Konfiguration" #~ msgid "Back" #~ msgstr "Zurück" #~ msgid "Up" #~ msgstr "Oben" #~ msgid "Cancel" #~ msgstr "Abbrechen" #, fuzzy #~ msgid "Configuration unchanged, no need to save.\n" #~ msgstr "" #~ "Konfiguration oder die GNUnet Version hat sich geändert. Sie müssen `%s' " #~ "ausführen!\n" #, fuzzy #~ msgid "Do you wish to save your new configuration?" #~ msgstr "Möchten Sie Ihre Einstellungen speichern?" #, fuzzy #~ msgid "" #~ "\n" #~ "Your configuration changes were NOT saved.\n" #~ msgstr "Konfigurationsdatei `%s' wurde erzeugt.\n" #~ msgid "This version of Windows doesn't support services.\n" #~ msgstr "Diese Version von Windows unterstützt keine Dienste.\n" #~ msgid "Error: can't open Service Control Manager: %s\n" #~ msgstr "Fehler: der Dienstemanager konnte nicht geöffnet werden: %s\n" #~ msgid "Error: can't create service: %s\n" #~ msgstr "Fehler: Dienst konnte nicht angelegt werden: %s\n" #~ msgid "Error: can't access service: %s\n" #~ msgstr "Fehler: auf den Dienst konnte nicht zugegriffen werden: %s\n" #~ msgid "Error: can't delete service: %s\n" #~ msgstr "Fehler: Dienst konnte nicht gelöscht werden: %s\n" #, fuzzy #~ msgid "Configuration changed. Save?" #~ msgstr "" #~ "Konfiguration oder die GNUnet Version hat sich geändert. Sie müssen `%s' " #~ "ausführen!\n" #, fuzzy #~ msgid "Error saving configuration." #~ msgstr "Fehler beim Speichern der Konfiguration!" #, fuzzy #~ msgid "(unknown connection)" #~ msgstr "Netzwerkverbindung" #, fuzzy #~ msgid "Do you want to save the new configuration?" #~ msgstr "Möchten Sie Ihre Einstellungen speichern?" #~ msgid "Unable to change startup process:" #~ msgstr "Startprozeß konnte nicht geändert werden:" #~ msgid "generate configuration for gnunetd, the GNUnet daemon" #~ msgstr "Generiere Konfiguration für gnunetd, den GNUnet Daemon" #~ msgid "Tool to setup GNUnet." #~ msgstr "Werkzeug für die Einrichtung von GNUnet." #, fuzzy #~ msgid "Too many arguments.\n" #~ msgstr "Ungültige Kommandozeilen Parameter.\n" #, fuzzy #~ msgid "No interface specified, using default.\n" #~ msgstr "Keine Oberfläche angegeben, verwende Standard\n" #, fuzzy #~ msgid "Configuration file `%s' must be a filename (but is a directory).\n" #~ msgstr "" #~ "Konfigurationsdatei `%s' nicht gefunden. Bitte führen Sie gnunet-setup " #~ "aus!\n" #, fuzzy #~ msgid "Undefined option.\n" #~ msgstr "Weitere Einstellungen" #, fuzzy #~ msgid "Unknown operation '%s'.\n" #~ msgstr "Unbekannte Operation `%s'\n" #, fuzzy #~ msgid "yes" #~ msgstr "Ja" #, fuzzy #~ msgid "Yes\n" #~ msgstr "Ja" #, fuzzy #~ msgid "No\n" #~ msgstr "Nein" #, fuzzy #~ msgid "Help\n" #~ msgstr "Hilfe" #, fuzzy #~ msgid "Abort\n" #~ msgstr "_über" #, fuzzy #~ msgid "Configuration was unchanged, no need to save.\n" #~ msgstr "" #~ "Konfiguration oder die GNUnet Version hat sich geändert. Sie müssen `%s' " #~ "ausführen!\n" #~ msgid "Can't open Service Control Manager" #~ msgstr "Der Dienstemanager konnte nicht geöffnet werden" #~ msgid "Can't create service" #~ msgstr "Der Dienst konnte nicht angelegt werden" #~ msgid "Error changing the permissions of the GNUnet directory" #~ msgstr "Fehler beim Ändern der Berechtigungen des GNUnet Verzeichnisses" #, fuzzy #~ msgid "Cannot write to the registry" #~ msgstr "Konnte nicht in die Registry schreiben" #~ msgid "Can't delete the service" #~ msgstr "Dienst konnte nicht gelöscht werden" #~ msgid "This version of Windows does not support multiple users." #~ msgstr "Diese Version von Windows ist nicht Mehrbenutzerfähig." #~ msgid "Error accessing local security policy" #~ msgstr "Fehler beim Zugriff auf die lokale Sicherheitsrichtlinie" #~ msgid "Error granting service right to user" #~ msgstr "Fehler beim Zuweisen des Dienstrechtes dem Benutzer" #~ msgid "Unknown error while creating a new user" #~ msgstr "Unbekannter Fehler beim Anlegen des neuen Benutzers" #, fuzzy #~ msgid "" #~ "Configuration does not satisfy constraints of configuration specification " #~ "file `%s'!\n" #~ msgstr "" #~ "Die Konfigurationsdatei muss in der Sektion `%s' unter `%s' ein " #~ "Verzeichnis für FS Daten angeben.\n" #~ msgid "FATAL" #~ msgstr "SCHWERWIEGEND" #~ msgid "NOTHING" #~ msgstr "NICHTS" #, fuzzy #~ msgid "Syntax error in configuration entry HOST in section NETWORK: `%s'\n" #~ msgstr "Syntaxfehler in Konfigurationsdatei `%s' in Zeile %d.\n" #, fuzzy #~ msgid "Error connecting to %s:%u. Is the daemon running?\n" #~ msgstr "Verbindung zu %u.%u.%u.%u:%u fehlgeschlagen: %s\n" #, fuzzy #~ msgid "Cannot connect to %s:%u: %s\n" #~ msgstr "Verbindung zu %u.%u.%u.%u:%u fehlgeschlagen: %s\n" #, fuzzy #~ msgid "Reading result from gnunetd failed, reply invalid!\n" #~ msgstr "`%s' fehlgeschlagen, Antwort ist ungültig!\n" #, fuzzy #~ msgid "No interface specified in section `%s' under `%s'!\n" #~ msgstr "" #~ "Es sind keine Netzwerkgeräte in der Konfigurationsdatei in der Sektion `" #~ "%s' unter `%s' definiert!\n" #~ msgid "Could not obtain IP for interface `%s' using `%s'.\n" #~ msgstr "" #~ "Es konnte keine IP für das Gerät `%s' unter Verwendung von `%s' ermittelt " #~ "werden.\n" #, fuzzy #~ msgid "" #~ "Could not find interface `%s' using `%s', trying to find another " #~ "interface.\n" #~ msgstr "" #~ "Gerät `%s' konnte in `%s' nicht gefunden werden, es wird versucht, ein " #~ "anderes Gerät zu finden.\n" #~ msgid "Could not find an IP address for interface `%s'.\n" #~ msgstr "Es konnte keine IP-Adresse für das Gerät `%s' ermittelt werden.\n" #, fuzzy #~ msgid "" #~ "There is more than one IP address specified for interface `%s'.\n" #~ "GNUnet will use %s.\n" #~ msgstr "" #~ "Es ist mehr als eine IP-Adresse für das Gerät `%s' angegeben.\n" #~ "GNUnet wird %u.%u.%u.%u. verwenden.\n" #~ msgid "Could not resolve `%s' to determine our IP address: %s\n" #~ msgstr "" #~ "`%s' konnte nicht aufgelöst werden, um unsere IP-Adresse zu ermitteln: " #~ "%s\n" #, fuzzy #~ msgid "Received malformed message (too small) from connection. Closing.\n" #~ msgstr "" #~ "Es wurde per TCP von einem anderen Knoten eine ungültige Nachricht (Größe " #~ "%u) empfangen. Verbindung wird geschlossen.\n" #, fuzzy #~ msgid "`%s' returned with error code %u" #~ msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" #~ msgid "Can't create semaphore: %i" #~ msgstr "Semaphore konnte nicht angelegt werden: %i" #~ msgid "Cannot query the CPU usage (Windows NT).\n" #~ msgstr "CPU Nutzung kann nicht ermittelt werden (Windows NT).\n" #~ msgid "Cannot query the CPU usage (Win 9x)\n" #~ msgstr "CPU Nutzung kann nicht ermittelt werden (Win 9x).\n" #~ msgid "" #~ "No network interfaces defined in configuration section `%s' under `%s'!\n" #~ msgstr "" #~ "Es sind keine Netzwerkgeräte in der Konfigurationsdatei in der Sektion `" #~ "%s' unter `%s' definiert!\n" #, fuzzy #~ msgid "Command `%s' failed with error code %u\n" #~ msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" #, fuzzy #~ msgid "Invalid process priority `%s'\n" #~ msgstr "Ungültige Antwort auf `%s'.\n" #, fuzzy #~ msgid "Real-time delay violation (%llu ms) at %s:%u\n" #~ msgstr "Unerwartete sehr große Allokierung (%u Bytes) bei %s:%d!\n" #, fuzzy #~ msgid "`%s' failed with error code %d: %s\n" #~ msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" #, fuzzy #~ msgid "Deadlock due to `%s'.\n" #~ msgstr "Durch `%s' ist ein Deadlock bei %s:%d entstanden\n" #, fuzzy #~ msgid "Lock acquired for too long (%llu ms) at %s:%u\n" #~ msgstr "Unerwartete sehr große Allokierung (%u Bytes) bei %s:%d!\n" #, fuzzy #~ msgid "GNUnet error log" #~ msgstr "GNUnet Netzwerk Topologie tracen." #~ msgid "Availability test failed for `%s' at %s:%d.\n" #~ msgstr "Verfügbarkeitstest für `%s' fehlgeschlagen bei %s:%d.\n" #, fuzzy #~ msgid "Failed to load state service. Trying to do without.\n" #~ msgstr "Der Transportdienst auf Port %d konnte nicht gestartet werden.\n" #, fuzzy #~ msgid "Starting datastore conversion (this may take a while).\n" #~ msgstr "Ein neuer Hostkey wird erzeugt (dies kann eine Weile dauern).\n" #, fuzzy #~ msgid "Failed to load sqstore service. Check your configuration!\n" #~ msgstr "Der Transportdienst auf Port %d konnte nicht gestartet werden.\n" #, fuzzy #~ msgid "" #~ "%s:%d - RPC %s:%p could not be registered: another callback is already " #~ "using this name (%p)\n" #~ msgstr "" #~ "%s::%s - RPC %s:%p konnte nicht registriert werden: ein anderer Callback " #~ "verwendet bereits diesen Namen (%p)\n" #, fuzzy #~ msgid "%s:%d - async RPC %s:%p could not be unregistered: not found\n" #~ msgstr "" #~ "%s::%s - async RPC %s:%p konnte nicht unregistriert werden: nicht " #~ "gefunden\n" #~ msgid "`%s' registering handlers %d %d %d\n" #~ msgstr "`%s' registriert Handler %d %d %d\n" #~ msgid "Using %u messages of size %u for %u times.\n" #~ msgstr "Verwende %u Nachrichten der Größe %u %umal.\n" #~ msgid "Times: max %16llu min %16llu mean %12.3f variance %12.3f\n" #~ msgstr "Zeiten: Max %16llu Min %16llu Mittel %12.3f Varianz %12.3f\n" #~ msgid "Loss: max %16u min %16u mean %12.3f variance %12.3f\n" #~ msgstr "Verloren: Max %16u Min %16u Mittel %12.3f Varianz %12.3f\n" #~ msgid "Running benchmark...\n" #~ msgstr "Benchmark läuft...\n" #~ msgid "allows profiling of direct peer-to-peer connections" #~ msgstr "Ermöglicht das Untersuchen direkter Peer-to-Peer Verbindungen" #~ msgid "Start GNUnet transport benchmarking tool." #~ msgstr "GNUnet Transport Benchmarking Werkzeug starten." #~ msgid "output in gnuplot format" #~ msgstr "Ausgabe im gnuplot Format" #~ msgid "number of iterations" #~ msgstr "Anzahl an Durchläufen" #~ msgid "number of messages to use per iteration" #~ msgstr "Anzahl an Nachrichten, die pro Durchlauf verwendet wird" #~ msgid "receiver host identifier (ENC file name)" #~ msgstr "Bezeichner des Empfängerhosts (ENC Dateiname)" #~ msgid "message size" #~ msgstr "Nachrichtengröße" #~ msgid "sleep for SPACE ms after each a message block" #~ msgstr "Für SPACE ms nach jedem Nachrichtenblock pausieren" #~ msgid "number of messages in a message block" #~ msgstr "Anzahl an Nachrichten in einem Nachrichtenblock" #~ msgid "Error establishing connection with gnunetd.\n" #~ msgstr "Fehler beim Aufbauen einer Verbindung mit gnunetd.\n" #~ msgid "You must specify a receiver!\n" #~ msgstr "Sie müssen einen Empfänger angeben!\n" #~ msgid "Invalid receiver peer ID specified (`%s' is not valid name).\n" #~ msgstr "" #~ "Ungültige Empfängerknoten ID angegeben (`%s' ist kein gültiger Name).\n" #~ msgid "Time:\n" #~ msgstr "Zeit:\n" #~ msgid "\tmax %llums\n" #~ msgstr "\tMax %llums\n" #~ msgid "\tmin %llums\n" #~ msgstr "\tMin %llums\n" #~ msgid "\tmean %8.4fms\n" #~ msgstr "\tMittel %8.4fms\n" #~ msgid "\tvariance %8.4fms\n" #~ msgstr "\tVarianz %8.4fms\n" #~ msgid "Loss:\n" #~ msgstr "Verlust:\n" #~ msgid "\tmax %u\n" #~ msgstr "\tMax %u\n" #~ msgid "\tmin %u\n" #~ msgstr "\tMin %u\n" #~ msgid "\tmean %8.4f\n" #~ msgstr "\tMittel %8.4fms\n" #~ msgid "\tvariance %8.4f\n" #~ msgstr "\tVarianz %8.4f\n" #~ msgid "Output format not known, this should not happen.\n" #~ msgstr "Ausgabeformat ist unbekannt, dies sollte nicht passieren.\n" #~ msgid "" #~ "\n" #~ "Did not receive the message from gnunetd. Is gnunetd running?\n" #~ msgstr "" #~ "\n" #~ "Es wurde keine Nachricht von gnunetd empfangen. Läuft gnunetd?\n" #, fuzzy #~ msgid "# bytes received in plaintext of type %d" #~ msgstr "# Bytes des Typs %d empfangen" #, fuzzy #~ msgid "# bytes allocated by SQLite" #~ msgstr "# bytes erlaubt in der Datenbank" #~ msgid "" #~ "Failed to load MySQL database module. Check that MySQL is running and " #~ "configured properly!\n" #~ msgstr "" #~ "Fehler beim Laden des MySQL Datenbankmoduls. Prüfen Sie, ob MySQL läuft " #~ "und richtig eingerichtet ist!\n" #~ msgid "probe network to the given DEPTH" #~ msgstr "Netzwerk bis zur angegebenen Tiefe DEPTH sondieren" #~ msgid "" #~ "specify output format; 0 for human readable output, 1 for dot, 2 for vcg" #~ msgstr "" #~ "Gibt das Ausgabeformat an: 0 für menschen-lesbar, 1 für dot, 2 für vcg" #, fuzzy #~ msgid "use PRIORITY for the priority of the trace request" #~ msgstr "PRIO als Priorität für die Trace Anfragen verwenden" #~ msgid "wait DELAY seconds for replies" #~ msgstr "DELAY Sekunden auf Antworten warten" #~ msgid "" #~ "Format specification invalid. Use 0 for user-readable, 1 for dot, 2 for " #~ "vcg.\n" #~ msgstr "" #~ "Formatangabe ungültig. Verwenden Sie 0 für menschen-lesbar, 1 für dot und " #~ "2 für vcg.\n" #~ msgid "allows mapping of the network topology" #~ msgstr "Erlaubt die Kartographierung der Netzwerktopologie" #, fuzzy #~ msgid "HELLO message from `%s' has an invalid signature. Dropping.\n" #~ msgstr "" #~ "Hello Nachricht von `%s' ist ungültig (Signatur ist ungültig). Nachricht " #~ "wurde verworfen.\n" #, fuzzy #~ msgid "HELLO message has expiration too far in the future. Dropping.\n" #~ msgstr "" #~ "Empfangene Hello Nachricht ist ungültig (Ablaufzeit über Limit). " #~ "Nachricht wurde verworfen.\n" #, fuzzy #~ msgid "Could not send HELLO+PING, ping buffer full.\n" #~ msgstr "Hellos+PING konnten nicht gesendet werden, Ping Puffer ist voll.\n" #~ msgid "" #~ "Announcing ourselves pointless: no other peers are known to us so far.\n" #~ msgstr "" #~ "Bekanntmachung von uns zwecklos: bis jetzt sind uns keine anderen Knoten " #~ "bekannt.\n" #, fuzzy #~ msgid "# Peer advertisements of type NAT received" #~ msgstr "# Knotenankündigungen empfangen" #, fuzzy #~ msgid "# Peer advertisements updating earlier HELLOs" #~ msgstr "# Knotenankündigungen empfangen" #, fuzzy #~ msgid "# Peer advertisements for unsupported transport" #~ msgstr "# Knotenankündigungen empfangen" #, fuzzy #~ msgid "# Peer advertisements not confirmed due to ping busy" #~ msgstr "# Knotenankündigungen empfangen" #, fuzzy #~ msgid "# Peer advertisements not confirmed due to lack of self ad" #~ msgstr "# Knotenankündigungen empfangen" #, fuzzy #~ msgid "# Peer advertisements not confirmed due to send error" #~ msgstr "# Knotenankündigungen empfangen" #~ msgid "`%s' registering handler %d (plaintext and ciphertext)\n" #~ msgstr "`%s' registriert Handler %d (Plaintext und Ciphertext)\n" #~ msgid "" #~ "ensures that this peer is known by other peers and discovers other peers" #~ msgstr "" #~ "Stellt sicher, dass dieser Knoten anderen Knoten bekannt ist und entdeckt " #~ "andere Knoten" #~ msgid "`%s' registering handler %d\n" #~ msgstr "`%s' registriert Handler %d\n" #, fuzzy #~ msgid "`%s' registering CS handlers %d and %d\n" #~ msgstr "`%s' registriert Handler %d und %d\n" #~ msgid "enables P2P-chat (incomplete)" #~ msgstr "Ermöglicht P2P-Chat" #, fuzzy #~ msgid "Existing key in file `%s' failed format check, creating new key.\n" #~ msgstr "" #~ "Formatüberprüfung schlug für die existierende Hostkeydatei `%s' fehl, es " #~ "wird ein neuer Hostkey erzeugt.\n" #, fuzzy #~ msgid "Creating new key for this nickname (this may take a while).\n" #~ msgstr "Ein neuer Hostkey wird erzeugt (dies kann eine Weile dauern).\n" #, fuzzy #~ msgid "# max bytes allowed in dstore" #~ msgstr "# bytes erlaubt in der Datenbank" #~ msgid "Transport library `%s' did not provide required function '%s%s'.\n" #~ msgstr "" #~ "Transport Bibliothek `%s' stellt nicht die benötigte Funktion '%s%s' zur " #~ "Verfügung.\n" #, fuzzy #~ msgid "Query (get KEY, put KEY VALUE) DHT table." #~ msgstr "" #~ "Eine DHT Tabelle abfragen (get KEY, put KEY VALUE, remove KEY VALUE)." #, fuzzy #~ msgid "allow TIME ms to process a GET command" #~ msgstr "TIME ms erlauben, um jedes Kommando zu bearbeiten" #, fuzzy #~ msgid "Issuing `%s(%s,%s)' command.\n" #~ msgstr "'%s(%s,%s)' fehlgeschlagen.\n" #~ msgid "Command `%s' requires an argument (`%s').\n" #~ msgstr "Kommando `%s' benötigt eine zusätzliche Angabe (`%s').\n" #~ msgid "Command `%s' requires two arguments (`%s' and `%s').\n" #~ msgstr "Kommando `%s' benötigt zwei zusätzliche Angaben (`%s' und `%s').\n" #, fuzzy #~ msgid "# dht discovery messages sent" #~ msgstr "# verschlüsselter PING Nachrichten empfangen" #, fuzzy #~ msgid "# dht put requests received" #~ msgstr "# Client Trace-Anfragen empfangen" #, fuzzy #~ msgid "`%s' registering p2p handlers: %d %d %d\n" #~ msgstr "`%s' registriert Handler %d %d %d\n" #~ msgid "`%s' failed. Terminating connection to client.\n" #~ msgstr "`%s' fehlgeschlagen. Beende Verbindung zu Client.\n" #, fuzzy #~ msgid "`%s' registering client handlers: %d %d\n" #~ msgstr "`%s' registriert Client-Handler %d\n" #~ msgid "" #~ "Existing hostkey in file `%s' failed format check, creating new hostkey.\n" #~ msgstr "" #~ "Formatüberprüfung schlug für die existierende Hostkeydatei `%s' fehl, es " #~ "wird ein neuer Hostkey erzeugt.\n" #~ msgid "Done creating hostkey.\n" #~ msgstr "Hostkey wurde erfolgreich erzeugt.\n" #, fuzzy #~ msgid "Removed file `%s' containing invalid HELLO data.\n" #~ msgstr "Datei `%s' enthielt ungültige Hello Daten und wurde entfernt.\n" #~ msgid "Signature failed verification: signature invalid.\n" #~ msgstr "" #~ "Verifikation einer Signatur fehlgeschlagen: Signatur ist ungültig.\n" #~ msgid "Received malformed `%s' message. Dropping.\n" #~ msgstr "Beschädigte `%s' Nachricht empfangen. Nachricht wird verworfen.\n" #~ msgid "Received ping for another peer. Dropping.\n" #~ msgstr "Ping für einen anderen Knoten empfangen. Ping wird verworfen.\n" #~ msgid "" #~ "Could not match PONG against any PING. Try increasing MAX_PING_PONG " #~ "constant.\n" #~ msgstr "" #~ "PONG konnte keinem PING zugeordnet werden. Versuchen Sie die Konstante " #~ "MAX_PING_PONG hochzusetzen.\n" #~ msgid "Cannot create PING, table full. Try increasing MAX_PING_PONG.\n" #~ msgstr "" #~ "PING konnte nicht erstellt werden, da die Tabelle voll ist. Versuchen " #~ "Sie, die Konstante MAX_PING_PONG hochzusetzen.\n" #~ msgid "# plaintext PONG messages received" #~ msgstr "# Klartext PONG Nachrichten empfangen" #~ msgid "# encrypted PING messages received" #~ msgstr "# verschlüsselter PING Nachrichten empfangen" #~ msgid "# encrypted PING messages sent" #~ msgstr "# verschlüsselter PING Nachrichten gesendet" #~ msgid "`%s' registering handlers %d %d (plaintext and ciphertext)\n" #~ msgstr "`%s' registriert Handler %d %d (Plaintext und Ciphertext)\n" #~ msgid "Cannot encrypt sessionkey, peer `%s' not known!\n" #~ msgstr "" #~ "Sitzungsschlüssel kann nicht verschlüsselt werden, Knoten `%s' ist uns " #~ "nicht bekannt!\n" #, fuzzy #~ msgid "Could not create any HELLO for myself (have transports `%s')!\n" #~ msgstr "Hostkey konnte nicht erzeugt werden!\n" #, fuzzy #~ msgid "" #~ "Session key received from peer `%s' has invalid format (discarded).\n" #~ msgstr "Empfangene Nachricht ist ungültig.\n" #, fuzzy #~ msgid "Session key received from peer `%s' is for `%s' and not for me!\n" #~ msgstr "Empfangene Nachricht ist ungültig.\n" #~ msgid "setkey `%s' from `%s' fails CRC check (have: %u, want %u).\n" #~ msgstr "" #~ "setkey `%s' von `%s' hat eine ungültige CRC Prüfsumme (tatsächlich: %u, " #~ "erwartet: %u).\n" #, fuzzy #~ msgid "" #~ "Error parsing encrypted session key from `%s', given message part size is " #~ "invalid.\n" #~ msgstr "" #~ "Fehler beim Parsen des Verschlüsselten Sitzungsschlüssels, gegebene " #~ "Nachrichtenteilgröße ist ungültig.\n" #, fuzzy #~ msgid "Unknown type in embedded message from `%s': %u (size: %u)\n" #~ msgstr "Unbekannter Typ in engebetteter Nachricht: %u (%u bytes)\n" #~ msgid "# session keys sent" #~ msgstr "# Sitzungsschlüssel gesendet" #~ msgid "# sessions established" #~ msgstr "# Sitzungen aufgebaut" #~ msgid "automate creation of a namespace by starting a collection" #~ msgstr "" #~ "Erstellung eines Namespaces durch das Anfangen einer Collection " #~ "automatisieren" #~ msgid "create a new pseudonym under the given NICKNAME" #~ msgstr "Neues Pseudonym unter dem angegebenen NICKNAME erstellen" #~ msgid "delete the pseudonym with the given NICKNAME" #~ msgstr "Pseudonym mit dem angegeben NICKNAME löschen" #~ msgid "end automated building of a namespace (ends collection)" #~ msgstr "" #~ "Automatisierte Erstellung eines Namespaces beenden (beendet Collection)" #~ msgid "" #~ "Create new pseudonyms, delete pseudonyms or list existing pseudonyms." #~ msgstr "" #~ "Erstellen von neuen Pseudonymen, Löschen von Pseudonymen und Auflisten " #~ "von bestehenden Pseudonymen." #~ msgid "" #~ "use the given keyword to advertise the namespace (use when creating a new " #~ "pseudonym)" #~ msgstr "" #~ "Das angegebene schlüsselwort verwenden, um den Namespace bekanntzumachen " #~ "(zu verwenden, wenn ein neues Pseudonym erstellt wird)" #, fuzzy #~ msgid "specify metadata describing the namespace or collection" #~ msgstr "" #~ "Automatisierte Erstellung eines Namespaces beenden (beendet Collection)" #~ msgid "" #~ "do not generate an advertisement for this namespace (use when creating a " #~ "new pseudonym)" #~ msgstr "" #~ "Keine Bekanntmachung für diesen Namespace erstellen (zu verwenden, wenn " #~ "ein neues Pseudonym erstellt wird)" #~ msgid "do not list the pseudonyms from the pseudonym database" #~ msgstr "Keine Ausgabe der Pseudonyme in der Pseudonymdatenbank" #~ msgid "" #~ "specify IDENTIFIER to be the address of the entrypoint to content in the " #~ "namespace (use when creating a new pseudonym)" #~ msgstr "" #~ "IDENTIFIER als Adresse angeben, die der Einsprungspunkt zu den Inhalten " #~ "im Namespace ist (zu verwenden, wenn ein neues Pseudonym erstellt wird)" #~ msgid "Namespace `%s' (%s) has rating %d.\n" #~ msgstr "Namespace `%s' (%s) hat das Rating %d.\n" #~ msgid "\tRating (after update): %d\n" #~ msgstr "\tRating (nach Update): %d\n" #~ msgid "Collection stopped.\n" #~ msgstr "Collection beendet.\n" #~ msgid "Failed to stop collection (not active?).\n" #~ msgstr "Fehler beim Beenden der Collection (nicht aktiv?).\n" #~ msgid "Pseudonym `%s' deleted.\n" #~ msgstr "Pseudonym `%s' wurde gelöscht.\n" #~ msgid "Error deleting pseudonym `%s' (does not exist?).\n" #~ msgstr "Fehler beim Löschen des Pseudonyms `%s' (existiert nicht?).\n" #, fuzzy #~ msgid "Started collection.\n" #~ msgstr "Collection `%s' begonnen.\n" #~ msgid "Namespace `%s' created (root: %s).\n" #~ msgstr "Namespace `%s' wurde erstellt (Root: %s).\n" #, fuzzy #~ msgid "You must specify a name for the collection (`%s' option).\n" #~ msgstr "" #~ "Sie müssen einen Namen für die PID Datei in Sektion `%s' unter `%s' " #~ "angeben.\n" #~ msgid "%d files found in directory.\n" #~ msgstr "%d Dateien im Verzeichnis gefunden.\n" #~ msgid "Perform directory related operations." #~ msgstr "Verzeichnisbezogene Operationen durchführen." #~ msgid "" #~ "remove all entries from the directory database and stop tracking URIs" #~ msgstr "" #~ "Alle Einträge aus der Verzeichnis Datenbank löschen und das Verfolgen von " #~ "URIs abbrechen" #~ msgid "list entries from the directory database" #~ msgstr "Einträge aus der Verzeichnis Datenbank auflisten" #~ msgid "start tracking entries for the directory database" #~ msgstr "Anfangen, Einträge für die Verzeichnis Datenbank zu verfolgen" #~ msgid "Listed %d matching entries.\n" #~ msgstr "%d übereinstimmende Einträge aufgelistet.\n" #, fuzzy #~ msgid "Upload of `%s' at %llu out of %llu bytes.\n" #~ msgstr "Download der Datei `%s' bei %16llu von %16llu Bytes (%8.3f kbps)\n" #, fuzzy #~ msgid "Upload aborted.\n" #~ msgstr "" #~ "\n" #~ "Upload abgebrochen.\n" #, fuzzy #~ msgid "Uploading suspended.\n" #~ msgstr "Upload abgewiesen!" #, fuzzy #~ msgid "" #~ "run in debug mode; gnunet-auto-share will not daemonize and error " #~ "messages will be written to stderr instead of a logfile" #~ msgstr "" #~ "Im Debug-Modus ausführen. gnunetd wird nicht im Hintergrund laufen und " #~ "Fehlermeldungen werden nicht in die Protokolldatei, sondern auf die " #~ "Standardfehlerausgabe (stderr) geschrieben." #, fuzzy #~ msgid "" #~ "do not use libextractor to add additional references to directory entries " #~ "and/or the published file" #~ msgstr "" #~ "benutze libextractor um weitere direkte Referenzen zu Dateien in " #~ "Verzeichnissen zu erzeugen" #~ msgid "Created entry `%s' in namespace `%s'\n" #~ msgstr "Eintag `%s' in Namespace `%s' wurde erstellt\n" #~ msgid "" #~ "%16llu of %16llu bytes inserted (estimating %6s to completion) - %s\n" #~ msgstr "" #~ "%16llu von %16llu Bytes eingefügt (geschätzte %6s bis Fertigstellung) - " #~ "%s\n" #~ msgid "" #~ "Upload of `%s' complete, %llu bytes took %llu seconds (%8.3f KiB/s).\n" #~ msgstr "" #~ "Upload von `%s' komplett, %llu Bytes brauchten %llu Sekunden (%8.3f KB/" #~ "s).\n" #~ msgid "" #~ "\n" #~ "Upload aborted.\n" #~ msgstr "" #~ "\n" #~ "Upload abgebrochen.\n" #, fuzzy #~ msgid "" #~ "\n" #~ "Error uploading file: %s" #~ msgstr "" #~ "\n" #~ "Fehler beim Uploaden der Datei: %s\n" #~ msgid "" #~ "even if gnunetd is running on the local machine, force the creation of a " #~ "copy instead of making a link to the GNUnet share directory" #~ msgstr "" #~ "Obwohl gnunetd auf der lokalen Maschiene läuft die Erstellung einer Kopie " #~ "anstelle der Erzeugung eines Links auf das GNUnet Share-Verzeichnis " #~ "erzwingen." #~ msgid "Make files available to GNUnet for sharing." #~ msgstr "Dateien GNUnet zum Filesharing zur Verfügung stellen." #~ msgid "Could not access namespace `%s' (does not exist?).\n" #~ msgstr "Konnte nicht auf den Namespace `%s' zugreifen (existiert nicht?).\n" #~ msgid "Search GNUnet for files." #~ msgstr "Das GNUnet nach Dateien durchsuchen." #~ msgid "write encountered (decrypted) search results to FILENAME" #~ msgstr "Begegnete (entschlüsselte) Suchergebnisse in FILENAME schreiben" #~ msgid "Error converting arguments to URI!\n" #~ msgstr "Fehler beim Konvertieren von Parametern in URI!\n" #~ msgid "" #~ "%16llu of %16llu bytes unindexed (estimating %llu seconds to " #~ "completion) " #~ msgstr "" #~ "%16llu von %16llu Bytes deindiziert (schätze %llu Sekunden bis " #~ "Fertigstellung) " #~ msgid "" #~ "\n" #~ "Unindexing of `%s' complete, %llu bytes took %llu seconds (%8.3f KiB/s).\n" #~ msgstr "" #~ "\n" #~ "Deindizierung von `%s' abgeschlossen, %llu Bytes benötigten %llu Sekunden " #~ "(%8.3f kbps).\n" #, fuzzy #~ msgid "Not enough arguments. You must specify a filename.\n" #~ msgstr "" #~ "Nicht genügend Parameter. Sie müssen eine GNUnet Datei URI angeben\n" #~ msgid "`%s' failed. Is `%s' a file?\n" #~ msgstr "`%s' schlug fehl. Ist `%s' eine Datei?\n" #~ msgid "Download files from GNUnet." #~ msgstr "Dateien aus dem GNUnet herunterladen." #~ msgid "Download of file `%s' at %16llu out of %16llu bytes (%8.3f KiB/s)\n" #~ msgstr "Download der Datei `%s' bei %16llu von %16llu Bytes (%8.3f kbps)\n" #~ msgid "Download aborted.\n" #~ msgstr "Download abgebrochen.\n" #~ msgid "Download of file `%s' complete. Speed was %8.3f KiB per second.\n" #~ msgstr "" #~ "Download der Datei `%s' abgeschlossen. Geschwindigkeit war %8.3f KB/s.\n" #~ msgid "Not enough arguments. You must specify a GNUnet file URI\n" #~ msgstr "" #~ "Nicht genügend Parameter. Sie müssen eine GNUnet Datei URI angeben\n" #~ msgid "URI `%s' invalid for gnunet-download.\n" #~ msgstr "URI `%s' ist ungültig für gnunet-download.\n" #, fuzzy #~ msgid "No filename specified, using `%s' instead (for now).\n" #~ msgstr "Kein Tabellenname angegeben, verwende `%s'.\n" #, fuzzy #~ msgid "Downloading %d files from directory `%s'.\n" #~ msgstr "Dateien aus dem GNUnet herunterladen." #~ msgid "File stored as `%s'.\n" #~ msgstr "Datei wurde als `%s' gespeichert.\n" #~ msgid "Collecting file identifiers disabled.\n" #~ msgstr "Einsammeln von Dateibezeichnern deaktiviert.\n" #~ msgid "Cannot get size of file `%s'" #~ msgstr "Die Größe der Datei `%s' konnte nicht ermittelt werden" #~ msgid "Cannot hash `%s'.\n" #~ msgstr "`%s' konnte nicht gehashed werden.\n" #~ msgid "Initialization for indexing file `%s' failed.\n" #~ msgstr "Initialisierung der Indizierung der Datei `%s' fehlgeschlagen.\n" #, fuzzy #~ msgid "Cannot open file `%s': `%s'" #~ msgstr "Konfigurationsdatei `%s' konnte nicht geöffnet werden.\n" #~ msgid "Renaming of file `%s' to `%s' failed: %s\n" #~ msgstr "Umbenennen der Datei `%s' zu `%s' fehlgeschlagen: %s\n" #~ msgid "Could not rename file `%s' to `%s': file exists\n" #~ msgstr "" #~ "Datei `%s' konnte nicht zu `%s' umbenannt werden: Datei existiert " #~ "bereits\n" #~ msgid "CHK URI not allowed for search.\n" #~ msgstr "CHK URI ist nicht erlaubt für Suchen.\n" #~ msgid "LOC URI not allowed for search.\n" #~ msgstr "LOC URI ist nicht erlaubt für Suchen.\n" #~ msgid "Format of pseudonym `%s' is invalid.\n" #~ msgstr "Format des Pseudonyms `%s' ist ungültig.\n" #, fuzzy #~ msgid "Format of file `%s' is invalid, trying to remove.\n" #~ msgstr "Format der Datei `%s' ist ungültig.\n" #~ msgid "" #~ "Decrypted content does not match key. This is either a bug or a " #~ "maliciously inserted file. Download aborted.\n" #~ msgstr "" #~ "Entschlüsselter Inhalt entspricht nicht dem Schlüssel. Dies ist entweder " #~ "ein Bug oder eine mit bösen Absichten eingefügte Datei. Download wurde " #~ "abgebrochen.\n" #, fuzzy #~ msgid "Application aborted." #~ msgstr "_Optionen" #~ msgid "FSUI state file `%s' had syntax error at offset %u.\n" #~ msgstr "FSUI Statusdatei `%s' hatte einen Syntaxfehler bei Offset %u.\n" #, fuzzy #~ msgid "# gap content total planned" #~ msgstr "# gap Anfragen insgesamt empfangen" #~ msgid "# gap requests total received" #~ msgstr "# gap Anfragen insgesamt empfangen" #, fuzzy #~ msgid "" #~ "`%s' registering client handlers %d %d %d %d %d %d %d %d and P2P handlers " #~ "%d %d\n" #~ msgstr "`%s' registriert die Client Handler %d %d %d %d %d %d %d %d %d\n" #~ msgid "enables (anonymous) file-sharing" #~ msgstr "Ermöglicht (anonymes) Filesharing" #~ msgid "" #~ "Because the file `%s' has been unavailable for 3 days it got removed from " #~ "your share. Please unindex files before deleting them as the index now " #~ "contains invalid references!\n" #~ msgstr "" #~ "Weil die Datei `%s' nun seit 3 Tagen nicht zur Verfügung steht, wurde Sie " #~ "aus Ihrem Share entfernt. Bitte deindizieren Sie Dateien, bevor Sie sie " #~ "löschen, da Ihr Index nun ungültige Referenzen enthält!\n" #~ msgid "" #~ "Unindexed ODB block `%s' from offset %llu already missing from " #~ "datastore.\n" #~ msgstr "" #~ "Deindizierter ODB Block `%s' vom Offset %llu fehlt bereits im " #~ "Datenspeicher.\n" #, fuzzy #~ msgid "# gap client requests tracked" #~ msgstr "# gap Anfragen insgesamt empfangen" #~ msgid "# blocks migrated" #~ msgstr "# Blöcke migriert" #, fuzzy #~ msgid "# blocks injected for migration" #~ msgstr "# Blöcke migriert" #, fuzzy #~ msgid "# on-demand fetches for migration" #~ msgstr "# Blöcke migriert" #, fuzzy #~ msgid "# gap queries dropped (table full)" #~ msgstr "# gap falsche Antworten" #, fuzzy #~ msgid "# gap queries dropped (redundant)" #~ msgstr "# gap falsche Antworten" #, fuzzy #~ msgid "# trust earned" #~ msgstr "# dht Anfragen weitergeleitet" #, fuzzy #~ msgid "Friend list of %s:%d\n" #~ msgstr "Es konnte keine Verbindung mit gnunetd hergestellt werden.\n" #, fuzzy #~ msgid "Waiting for peers to connect" #~ msgstr "" #~ "Warte darauf, dass sich andere Knoten verbinden (%u Iterationen " #~ "verbleiben)...\n" #, fuzzy #~ msgid "Bootstrap data obtained from `%s' is invalid.\n" #~ msgstr "Format des Pseudonyms `%s' ist ungültig.\n" #~ msgid "`%s' registering client handler %d\n" #~ msgstr "`%s' registriert Client-Handler %d\n" #~ msgid "allows clients to determine gnunetd's configuration" #~ msgstr "Erlaubt es Clients die Konfiguration von gnunetd abzufragen" #~ msgid "`%s' registering client handler %d and %d\n" #~ msgstr "`%s' registriert Client-Handler %d and %d\n" #~ msgid "Uptime (seconds)" #~ msgstr "Laufzeit (Sekunden)" #~ msgid "% of allowed network load (up)" #~ msgstr "% of allowed network load (up)" #~ msgid "% of allowed network load (down)" #~ msgstr "% of allowed network load (down)" #~ msgid "% of allowed cpu load" #~ msgstr "% of allowed cpu load" #, fuzzy #~ msgid "% of allowed io load" #~ msgstr "% of allowed cpu load" #, fuzzy #~ msgid "`%s' registering client handlers %d %d %d and p2p handler %d\n" #~ msgstr "`%s' registriert die Client Handler %d %d %d %d %d %d %d %d %d\n" #~ msgid "keeps statistics about gnunetd's operation" #~ msgstr "Hält Statistiken über Betrieb von gnunetd" #~ msgid "Supported peer-to-peer messages:\n" #~ msgstr "unterstützte Peer-to-Peer Nachrichten:\n" #~ msgid "Supported client-server messages:\n" #~ msgstr "unterstützte Client-Server Nachrichten:\n" #~ msgid "prints supported protocol messages" #~ msgstr "gibt unterstützte Protokollnachrichten aus" #, fuzzy #~ msgid "VPN Received unknown IP version %d...\n" #~ msgstr "Es wurde eine unbekannte Testbed Nachricht des Typs %u empfangen.\n" #, fuzzy #~ msgid "Cannot open tunnel device: %s" #~ msgstr "Konfigurationsdatei `%s' konnte nicht geöffnet werden.\n" #, fuzzy #~ msgid "Cannot set interface IPv6 address for gnu%d because %s\n" #~ msgstr "Es konnte keine IP-Adresse für das Gerät `%s' ermittelt werden.\n" #, fuzzy #~ msgid "Cannot add route IPv6 address for gnu%s because %s\n" #~ msgstr "Es konnte keine IP-Adresse für das Gerät `%s' ermittelt werden.\n" #, fuzzy #~ msgid "`%s' initialising RFC4913 module %d and %d\n" #~ msgstr "`%s' registriert Handler %d und %d\n" #, fuzzy #~ msgid "enables IPv6 over GNUnet (incomplete)" #~ msgstr "Ermöglicht P2P-Chat" #~ msgid "Application module `%s' already initialized!\n" #~ msgstr "Anwendungsmodul `%s' ist bereits initialisiert!\n" #~ msgid "Failed to load plugin `%s' at %s:%d. Unloading plugin.\n" #~ msgstr "" #~ "Fehler beim Laden des Plugins `%s' bei %s:%d. Plugin wird entladen.\n" #~ msgid "Could not shutdown `%s': application not loaded\n" #~ msgstr "" #~ "`%s' kann nicht heruntergefahren werden: Anwendung ist nicht geladen\n" #~ msgid "Could not shutdown application `%s': not initialized\n" #~ msgstr "" #~ "Anwendung `%s' kann nicht heruntergefahren werden: sie ist nicht " #~ "initialisiert\n" #~ msgid "Could not find '%s%s' method in library `%s'.\n" #~ msgstr "Methode '%s%s' kann in Bibliothek `%s' nicht gefunden werden.\n" #~ msgid "Could not release %p: service not loaded\n" #~ msgstr "%p kann nicht freigegeben werden: Dienst ist nicht geladen\n" #~ msgid "Could not properly shutdown application `%s'.\n" #~ msgstr "Anwendung `%s' konnte nicht ordentlich heruntergefahren werden.\n" #~ msgid "Could not properly unload service `%s'!\n" #~ msgstr "Dienst `%s' konnte nicht ordentlich entladen werden!\n" #, fuzzy #~ msgid "Core initialization failed.\n" #~ msgstr " Verbindung fehlgeschlagen\n" #~ msgid "Updates GNUnet datastructures after version change." #~ msgstr "GNUnet Datenstrukturen nach einer Versionsänderung aktualisieren." #~ msgid "run as user LOGIN" #~ msgstr "als Benutzer LOGIN ausführen" #~ msgid "run in client mode (for getting client configuration values)" #~ msgstr "" #~ "Im Benuter-Modus laufen (um benutzerspezifische " #~ "Konfigurationseinstellungen zu holen" #~ msgid "" #~ "run in debug mode; gnunetd will not daemonize and error messages will be " #~ "written to stderr instead of a logfile" #~ msgstr "" #~ "Im Debug-Modus ausführen. gnunetd wird nicht im Hintergrund laufen und " #~ "Fehlermeldungen werden nicht in die Protokolldatei, sondern auf die " #~ "Standardfehlerausgabe (stderr) geschrieben." #~ msgid "Starts the gnunetd daemon." #~ msgstr "Startet den gnunetd Daemonen." #, fuzzy #~ msgid "specify username as which gnunetd should run" #~ msgstr "Gibt an, auf welchem Host gnunetd läuft" #~ msgid "Configuration or GNUnet version changed. You need to run `%s'!\n" #~ msgstr "" #~ "Konfiguration oder die GNUnet Version hat sich geändert. Sie müssen `%s' " #~ "ausführen!\n" #~ msgid "The `%s' request received from client is malformed.\n" #~ msgstr "Die `%s' Anfrage, die vom Client empfangen wurde, ist beschädigt.\n" #~ msgid "" #~ "Malformed network specification in the configuration in section `%s' for " #~ "entry `%s': %s\n" #~ msgstr "" #~ "Beschädigte Netzwerkangabe in der Konfigurationsdatei in Sektion `%s' für " #~ "Eintrag `%s': %s\n" #, fuzzy #~ msgid "Registering failed, message type %d already in use.\n" #~ msgstr "%s schlug fehl, Nachrichten Typ %d ist bereits in Verwendung.\n" #, fuzzy #~ msgid "Unable to obtain filesystem information for `%s': %u\n" #~ msgstr "Fehler beim Speichern der Konfigurationsdatei: `%s': %s.\n" #, fuzzy #~ msgid "`%s' message invalid (signature invalid).\n" #~ msgstr "Hello Nachricht ist ungültig (Signatur ist ungültig).\n" #~ msgid "`%s' selected %d out of %d messages (MTU: %d).\n" #~ msgstr "`%s' wählte %d von %d Nachrichten aus (MTU: %d).\n" #~ msgid "Message details: %u: length %d, priority: %d\n" #~ msgstr "Nachrichten Details: %u: Länge %d, Priorität: %d\n" #~ msgid "Message from `%s' discarded: invalid format.\n" #~ msgstr "Nachricht von `%s' verworfen: ungültiges Format.\n" #~ msgid "Invalid sequence number %u <= %u, dropping message.\n" #~ msgstr "Ungültige Sequenznummer %u <= %u, Nachricht wird verworfen.\n" #~ msgid "Message received more than one day old. Dropped.\n" #~ msgstr "" #~ "Empfangene Nachricht ist mehr als ein Tag alt. Nachricht wird verworfen.\n" #~ msgid "# connections closed (HANGUP sent)" #~ msgstr "# geschlossener Verbindungen (HANGUP gesendet)" #~ msgid "# bytes noise sent" #~ msgstr "# Bytes Rauschen gesendet" #, fuzzy #~ msgid "# total bytes per second receive limit" #~ msgstr "# Bytes Rauschen empfangen" #, fuzzy #~ msgid "# total number of messages in send buffers" #~ msgstr "Anzahl an Nachrichten in einem Nachrichtenblock" #, fuzzy #~ msgid "# total number of bytes we were allowed to send but did not" #~ msgstr "Anzahl an Nachrichten in einem Nachrichtenblock" #, fuzzy #~ msgid "# total number of bytes we were allowed to sent" #~ msgstr "Anzahl an Nachrichten in einem Nachrichtenblock" #~ msgid "`%s': Could not create hello.\n" #~ msgstr "`%s': Hello konnte nicht erzeugt werden.\n" #~ msgid "`%s': Could not send.\n" #~ msgstr "`%s': Kann nicht senden.\n" #~ msgid "`%s': Could not disconnect.\n" #~ msgstr "`%s': Verbindung konnte nicht getrennt werden.\n" #, fuzzy #~ msgid "" #~ "`%s' transport OK. It took %ums to transmit %llu messages of %llu bytes " #~ "each.\n" #~ msgstr "" #~ "`%s' Transport funktioniert. Es dauerte %ums, um %d Nachrichten zu je %d " #~ "Bytes zu übertragen.\n" #, fuzzy #~ msgid " Transport %d is not being tested\n" #~ msgstr " Transport %d ist nicht verfügbar\n" #~ msgid "" #~ "\n" #~ "Contacting `%s'." #~ msgstr "" #~ "\n" #~ "Kontaktiere `%s'." #~ msgid " Connection failed (bug?)\n" #~ msgstr " Verbindung fehlgeschlagen (Bug?)\n" #, fuzzy #~ msgid "OK!\n" #~ msgstr "OK" #~ msgid "Tool to test if GNUnet transport services are operational." #~ msgstr "" #~ "Werkzeug, mit dem getestet werden kann, ob die GNUnet Transport Dienste " #~ "funktionsfähig sind." #~ msgid "ping peers from HOSTLISTURL that match transports" #~ msgstr "Knoten aus HOSTLISTURL anpingen, deren Transports passen" #~ msgid "send messages with SIZE bytes payload" #~ msgstr "Nachrichten mit SIZE Bytes Nutzlast versenden" #~ msgid "specifies which TRANSPORT should be tested" #~ msgstr "Gibt an, welcher TRANSPORT getestet werden soll" #~ msgid "specifies after how many MS to time-out" #~ msgstr "Gibt an, nach wievielen MS die Zeit abgelaufen sein soll" #~ msgid "Testing transport(s) %s\n" #~ msgstr "Teste Transport(e) %s\n" #~ msgid "Available transport(s): %s\n" #~ msgstr "Verfügbare(r) Transport(e): %s\n" #, fuzzy #~ msgid "" #~ "\n" #~ "%d out of %d peers contacted successfully (%d times transport " #~ "unavailable).\n" #~ msgstr "" #~ "%d von %d Knoten erfolgreich kontaktiert (%d mal war der Transport nicht " #~ "verfügbar).\n" #, fuzzy #~ msgid "%s failed for url `%s' and post-data `%s' at %s:%d: `%s'\n" #~ msgstr "`%s' schlug fehl bei %s:%d mit dem Fehler: `%s'.\n" #~ msgid "# bytes sent via HTTP" #~ msgstr "# Bytes gesendet über HTTP" #~ msgid "# bytes dropped by HTTP (outgoing)" #~ msgstr "# Bytes verworfen von HTTP" #, fuzzy #~ msgid "# HTTP connect calls" #~ msgstr "# verbundener Knoten" #, fuzzy #~ msgid "Failed to obtain my (external) %s address!\n" #~ msgstr "Fehler beim Bestimmen der (externen) IP-Adresse!\n" #, fuzzy #~ msgid "MTU %llu for `%s' is probably too low!\n" #~ msgstr "" #~ "MTU für `%s' ist möglicherweise zu gering (Fragmentierung ist nicht " #~ "implementiert!)\n" #~ msgid "specify host on which gnunetd is running" #~ msgstr "Gibt an, auf welchem Host gnunetd läuft" #~ msgid "No help available." #~ msgstr "Keine Hilfe verfügbar." #, fuzzy #~ msgid "Show rarely used options" #~ msgstr "Maskierte Optionen anzeigen" #, fuzzy #~ msgid "Meta-configuration" #~ msgstr "GNUnet Konfiguration" #, fuzzy #~ msgid "Full pathname of GNUnet HOME directory" #~ msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" #, fuzzy #~ msgid "Full pathname of GNUnet directory for file-sharing data" #~ msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" #, fuzzy #~ msgid "Full pathname to the directory with the key-value database" #~ msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" #, fuzzy #~ msgid "Note that the kvstore is currently not used." #~ msgstr "# gap Routingschächte im Moment in Verwendung" #, fuzzy #~ msgid "Full pathname of GNUnet directory for indexed files symbolic links" #~ msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" #, fuzzy #~ msgid "Run gnunetd as this group." #~ msgstr "gnunet-update ausführen" #, fuzzy #~ msgid "General settings" #~ msgstr "Weitere Einstellungen" #, fuzzy #~ msgid "Settings for restricting connections to friends" #~ msgstr "`%s' fehlgeschlagen. Beende Verbindung zu Client.\n" #, fuzzy #~ msgid "Configuration file that specifies the MySQL username and password" #~ msgstr "" #~ "Konfiguration oder die GNUnet Version hat sich geändert. Sie müssen `%s' " #~ "ausführen!\n" #, fuzzy #~ msgid "Configuration of the MySQL database" #~ msgstr "" #~ "Konfiguration oder die GNUnet Version hat sich geändert. Sie müssen `%s' " #~ "ausführen!\n" #, fuzzy #~ msgid "MB of diskspace GNUnet can use for anonymous file sharing" #~ msgstr "Ermöglicht (anonymes) Filesharing" #, fuzzy #~ msgid "Number of entries in the migration buffer" #~ msgstr "Anzahl an Nachrichten in einem Nachrichtenblock" #, fuzzy #~ msgid "Options for anonymous file sharing" #~ msgstr "Ermöglicht (anonymes) Filesharing" #, fuzzy #~ msgid "Applications" #~ msgstr "_Optionen" #, fuzzy #~ msgid "Network interface" #~ msgstr "Netzwerkgerät:" #, fuzzy #~ msgid "Network interface to monitor" #~ msgstr "Netzwerkgerät:" #, fuzzy #~ msgid "Load management" #~ msgstr "Ungültige Kommandozeilen Parameter.\n" #, fuzzy #~ msgid "This is equivalent to the -H option. The format is IP:PORT." #~ msgstr "Wert der Option anzeigen" #, fuzzy #~ msgid "What is the path to the configuration file for gnunetd?" #~ msgstr "" #~ "Einen Wert aus der Konfigurationsdatei auf der Standardausgabe ausgeben" #, fuzzy #~ msgid "General options" #~ msgstr "Weitere Einstellungen" #, fuzzy #~ msgid "Options related to gnunet-gtk" #~ msgstr "Nicht verbunden zu gnunetd." #, fuzzy #~ msgid "Full pathname of GNUnet client HOME directory" #~ msgstr "Dateiformat fehlerhaft (kein GNUnet Verzeichnis?)\n" #~ msgid "Could not determine my public IPv6 address.\n" #~ msgstr "Die öffentliche IPv6-Adresse konnte nicht ermittelt werden.\n" #~ msgid "`%s': unknown service: %s\n" #~ msgstr "`%s': unbekannter Dienst: %s\n" #, fuzzy #~ msgid "# bytes received via TCP6" #~ msgstr "# Bytes empfangen über TCP" #, fuzzy #~ msgid "# bytes sent via TCP6" #~ msgstr "# Bytes gesendet über TCP" #, fuzzy #~ msgid "# bytes dropped by TCP6 (outgoing)" #~ msgstr "# Bytes verworfen von TCP (ausgehend)" #~ msgid "UDP6: Could not determine my public IPv6 address.\n" #~ msgstr "UDP6: Öffentliche IPv6-Adresse konnte nicht ermittelt werden.\n" #, fuzzy #~ msgid "# bytes received via UDP6" #~ msgstr "# Bytes empfangen über UDP" #, fuzzy #~ msgid "# bytes sent via UDP6" #~ msgstr "# Bytes gesendet über UDP" #, fuzzy #~ msgid "# bytes dropped by UDP6 (outgoing)" #~ msgstr "# Bytes verworfen von UDP (outgoing)" #~ msgid "HTTP: Could not determine my public IP address.\n" #~ msgstr "HTTP: öffentliche IP-Adresse konnte nicht ermittelt werden.\n" #, fuzzy #~ msgid "Received malformed message instead of welcome message. Closing.\n" #~ msgstr "" #~ "Es wurde per TCP von einem anderen Knoten eine ungültige Nachricht (Größe " #~ "%u) empfangen. Verbindung wird geschlossen.\n" #, fuzzy #~ msgid "Received malformed message from tcp-peer connection. Closing.\n" #~ msgstr "" #~ "Es wurde per TCP von einem anderen Knoten eine ungültige Nachricht (Größe " #~ "%u) empfangen. Verbindung wird geschlossen.\n" #, fuzzy #~ msgid "TCP: Could not determine my public IP address.\n" #~ msgstr "HTTP: öffentliche IP-Adresse konnte nicht ermittelt werden.\n" #~ msgid "Cannot connect to %u.%u.%u.%u:%u: %s\n" #~ msgstr "Verbindung zu %u.%u.%u.%u:%u fehlgeschlagen: %s\n" #~ msgid "UDP: Could not determine my public IP address.\n" #~ msgstr "UDP: öffentliche IP-Adresse konnte nicht ermittelt werden.\n" #~ msgid "Failed to send message of size %d via UDP to %u.%u.%u.%u:%u: %s\n" #~ msgstr "" #~ "Eine Nachricht der Größe %d konnte nicht per UDP an %u.%u.%u.%u:%u " #~ "versendet werden: %s\n" #, fuzzy #~ msgid "Received malformed message from udp-peer connection. Closing.\n" #~ msgstr "" #~ "Es wurde per TCP von einem anderen Knoten eine ungültige Nachricht (Größe " #~ "%u) empfangen. Verbindung wird geschlossen.\n" #~ msgid "'%s(%s,%s)' succeeded\n" #~ msgstr "'%s(%s,%s)' erfolgreich abgeschlossen\n" #~ msgid "'%s(%s,%s)' failed.\n" #~ msgstr "'%s(%s,%s)' fehlgeschlagen.\n" #~ msgid "" #~ "%s::%s - RPC %s:%p could not be unregistered: another callback registered " #~ "under that name: %p\n" #~ msgstr "" #~ "%s::%s - RPC %s:%p konnte nicht unregistriert werden: ein anderer " #~ "Callback ist unter diesem Namen registiert: %p\n" #~ msgid "%s::%s - RPC %s:%p could not be unregistered: not found\n" #~ msgstr "" #~ "%s::%s - RPC %s:%p konnte nicht unregistriert werden: nicht gefunden\n" #~ msgid "Dropping RPC request %u: message malformed.\n" #~ msgstr "RPC Anfrage %u wird verworfen: Nachricht ist beschädigt.\n" #~ msgid "`%s' called with timeout above 1 hour (bug?)\n" #~ msgstr "`%s' mit einem Timeout von über einer Stunde aufgerufen (Fehler?)\n" #~ msgid "RPC not unregistered: %s:%p\n" #~ msgstr "RPC nicht unregistriert: %s:%p\n" #~ msgid "RPC async reply invalid.\n" #~ msgstr "RPC async Antwort ungültig.\n" #~ msgid "async RPC reply not received.\n" #~ msgstr "async RPC Antwort nicht empfangen.\n" #~ msgid "" #~ "Cover traffic requested but traffic service not loaded. Rejecting " #~ "request.\n" #~ msgstr "" #~ "Verdeckender Netzwerkverkehr angefordert, aber der Verkehrsdienst wurde " #~ "nicht geladen. Anfrage wird abgelehnt.\n" #~ msgid "Cannot satisfy desired level of anonymity, ignoring request.\n" #~ msgstr "" #~ "Gewünschter Grad an Anonymität kann nicht erreicht werden, Anfrage wird " #~ "ignoriert.\n" #~ msgid "# gap requests policy: immediate drop" #~ msgstr "# gap Anfragen mit taktischer Entscheidung: sofortiges Verwerfen" #~ msgid "# gap requests policy: not routed" #~ msgstr "# gap Anfragen mit taktischer Entscheidung: kein Routing" #~ msgid "# gap requests policy: not answered" #~ msgstr "# gap Anfragen mit taktischer Entscheidung: nicht Antworten" #~ msgid "# gap requests processed: attempted add to RT" #~ msgstr "# gap Anfragen verarbeitet: versucht, der RT hinzuzufügen" #~ msgid "# gap requests processed: local result" #~ msgstr "# gap Anfragen verarbeitet: lokales Ergebnis" #~ msgid "# gap requests forwarded (counting each peer)" #~ msgstr "#gap Anfragen weitergeleitet (jeder Knoten gezählt)" #~ msgid "# gap duplicate requests (pending)" #~ msgstr "# gap doppelte Anfragen (unfertig)" #~ msgid "# gap duplicate requests that were re-tried" #~ msgstr "# gap doppelte Anfragen, die wiederholt wurden" #~ msgid "# gap re-try ttl difference (cummulative)" #~ msgstr "# gap Wiederholungs-TTL-Differenz (kummulativ)" #~ msgid "# gap reply duplicates" #~ msgstr "#gap doppelte Antworten" #~ msgid "# gap routing slots currently in use" #~ msgstr "# gap Routingschächte im Moment in Verwendung" #, fuzzy #~ msgid "# gap rewards pending" #~ msgstr "# gap doppelte Anfragen (unfertig)" #, fuzzy #~ msgid "# gap response weights" #~ msgstr "# gap falsche Antworten" #~ msgid "" #~ "Traffic service failed to load; gap cannot ensure cover-traffic " #~ "availability.\n" #~ msgstr "" #~ "Verkehrsdienst konnte nicht geladen werden, GAP kann keinen verdeckenden " #~ "Netzwerkverkehr sicherstellen.\n" #~ msgid "`%s' registering handlers %d %d\n" #~ msgstr "`%s' registriert Handler %d %d\n" #~ msgid "" #~ "set interval for availability of updates to SECONDS (for namespace " #~ "insertions only)" #~ msgstr "" #~ "Intervall der Verfügbarkeit von Updates auf SECONDS setzen (nur für das " #~ "Einfügen in Namespaces)" #~ msgid "" #~ "specifies this as an aperiodic but updated publication (for namespace " #~ "insertions only)" #~ msgstr "" #~ "Dies als unregelmäßige aber aktualisierbare Veröffentlichung kennzeichnen " #~ "(nur für das Einfügen in Namespaces)" #~ msgid "specify creation time for SBlock (see man-page for format)" #~ msgstr "Erstellungszeit für den SBLOCK angeben (s. Manpage zum Format)" #~ msgid "" #~ "ID of the previous version of the content (for namespace update only)" #~ msgstr "" #~ "ID der vorherigen Version des Inhalts (nur für das Einfügen in Namespaces)" #~ msgid "Parsing time failed. Use `%s' format.\n" #~ msgstr "Das Parsen der Zeit schlug fehl. Verwenden Sie das `%s' Format.\n" #~ msgid "exit after receiving LIMIT results" #~ msgstr "Abbrechen, nachdem LIMIT Ergebnisse empfangen wurden" #~ msgid "wait DELAY seconds for search results before aborting" #~ msgstr "TIMEOUT Sekunden auf Suchergebnisse warten, bevor abgebrochen wird" #, fuzzy #~ msgid "# FS currently tracked queries from clients" #~ msgstr "# Client Trace-Antworten gesendet" #~ msgid "Indexed file disappeared, deleting block for query `%s'\n" #~ msgstr "" #~ "Indizierte Datei ist verschwunden, Block für Anfrage `%s' wird gelöscht\n" #~ msgid "" #~ "Configuration file must specify directory for storage of FS data in " #~ "section `%s' under `%s'.\n" #~ msgstr "" #~ "Die Konfigurationsdatei muss ein Verzeichnis für die Speicherung von FS " #~ "Daten in der Sektion `%s' unter `%s' angeben.\n" #~ msgid "AND" #~ msgstr "UND" #~ msgid "Error running search (no reason given)." #~ msgstr "Das Starten der Suche schlug fehl (Ursache unbekannt)." #~ msgid "Download failed (no reason given)" #~ msgstr "ECRS Download schlug fehl (Ursache unbekannt)." #~ msgid "Could not unlink temporary file `%s': %s\n" #~ msgstr "Temporäre Datei `%s' konnte nicht gelöscht werden: %s\n" #~ msgid "Write(%d, %p, %d) failed: %s\n" #~ msgstr "Write(%d, %p, %d) schlug fehl: %s\n" #~ msgid "" #~ "Content `%s' seems to be not available on the network (tried %u times).\n" #~ msgstr "" #~ "Inhalt `%s' scheint im Netzwerk nicht verfügbar zu sein (%u mal " #~ "versucht).\n" #~ msgid "Cannot create pseudonym `%s', file `%s' exists.\n" #~ msgstr "" #~ "Pseudonym `%s' kann nicht erstellt werden, da die Datei `%s' bereits " #~ "existiert.\n" #~ msgid "Publication interval for periodic publication changed." #~ msgstr "" #~ "Veröffentlichungsintervall für periodische Veröffentlichung wurde " #~ "geändert." #~ msgid "" #~ "Publishing update for periodically updated content more than a week ahead " #~ "of schedule.\n" #~ msgstr "" #~ "Veröffentlichungsdatum für periodisch aktualisierten Inhalt ist mehr als " #~ "eine Woche früher als geplant.\n" #~ msgid "Message received from peer is invalid.\n" #~ msgstr "Empfangene Nachricht ist ungültig.\n" #~ msgid "Maximum number of chat clients reached.\n" #~ msgstr "Maximale Anzahl an Chat Clients erreicht.\n" #~ msgid "Now %d of %d chat clients at this node.\n" #~ msgstr "Jetzt sind %d von %d auf diesem Knoten.\n" #, fuzzy #~ msgid "Invalid data in %s (NCS). Trying to fix (by deletion).\n" #~ msgstr "Ungültige Daten in %s. Korrektur wird versucht (durch Löschung).\n" #, fuzzy #~ msgid "`%s' failed at %s:%d with error `%s' after %llums\n" #~ msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" #~ msgid "" #~ "Directory `%s' in directory `%s' does not match naming convention. " #~ "Removed.\n" #~ msgstr "" #~ "Die Datei `%s' im Verzeichnis `%s' entspricht nicht der Namenskonvention. " #~ "Datei wurde entfernt.\n" #~ msgid "Start GNUnet-testbed helper." #~ msgstr "GNUnet-testbed Helfer starten." #~ msgid "Cannot connect to LOOPBACK port %d: %s\n" #~ msgstr "Verbindung zum LOOPBACK port %d schlug fehl: %s\n" #~ msgid "Could not execute `%s': %s\n" #~ msgstr "`%s' konnte nicht ausgeführt werden: %s\n" #~ msgid "No client service started. Trying again in 30 seconds.\n" #~ msgstr "Kein Client Dienst gestartet. Erneuter Versuch in 30 Sekunden.\n" #~ msgid "" #~ "Error (%s) binding the TCP listener to port %d. No proxy service " #~ "started.\n" #~ "Trying again in %d seconds...\n" #~ msgstr "" #~ "Fehler (%s) beim Binden des TCP Listeners an den Port %d. Der Proxy " #~ "Dienst wurde nicht gestartet.\n" #~ "Erneuter Versuch in %d Sekunden...\n" #~ msgid "Rejected unauthorized connection from %u.%u.%u.%u.\n" #~ msgstr "Unauthorisierte Verbindung von %u.%u.%u.%u. wurde abgewiesen.\n" #~ msgid "Protocol violation on socket. Expected command.\n" #~ msgstr "Protokollverletzung auf Socket. Kommando erwartet.\n" #~ msgid "Start GNUnet testbed controller." #~ msgstr "GNUnet testbed Controller starten." #~ msgid "Malformed entry in the configuration in section %s under %s: %s\n" #~ msgstr "" #~ "Beschädigter Eintrag in der Konfigurationsdatei in Sektion %s unter %s: " #~ "%s\n" #~ msgid "Could not send acknowledgement back to client.\n" #~ msgstr "Bestätigung konnte nicht an Client zurück gesendet werden.\n" #~ msgid "size of `%s' message is wrong. Ignoring.\n" #~ msgstr "Größe der `%s' Nachricht ist falsch. Nachricht wird ignoriert.\n" #~ msgid "TESTBED could not generate hello message for protocol %u\n" #~ msgstr "" #~ "Das TESTBED konnte keine Hello Nachricht für das Protokoll %u erzeugen\n" #~ msgid "received invalid `%s' message\n" #~ msgstr "ungültige `%s' Nachricht empfangen\n" #~ msgid "received invalid `%s' message (empty module name)\n" #~ msgstr "ungültige `%s' Nachricht empfangen (leerer Modulname)\n" #~ msgid "loading module `%s' failed. Notifying client.\n" #~ msgstr "das Laden von Modul `%s' schlug fehl. Client wird benachrichtigt.\n" #~ msgid "unloading module failed. Notifying client.\n" #~ msgstr "das Entladen des Moduls schlug fehl. Client wird benachrichtigt.\n" #~ msgid "received invalid `%s' message: %s.\n" #~ msgstr "ungültige `%s' Nachricht empfangen: %s.\n" #~ msgid "'..' is not allowed in file name (%s).\n" #~ msgstr "'..' ist nicht erlaubt in einem Dateinamen (%s).\n" #~ msgid "Empty filename for UPLOAD_FILE message is invalid!\n" #~ msgstr "Leerer Dateiname für UPLOAD_FILE Nachricht ist ungültig!\n" #~ msgid "Filename for UPLOAD_FILE message is not null-terminated (invalid!)\n" #~ msgstr "" #~ "Dateiname für UPLOAD_FILE Nachricht ist nicht Null-terminiert " #~ "(ungültig!)\n" #~ msgid "Invalid message received at %s:%d." #~ msgstr "Ungültige Nachricht empfangen bei %s:%d." #~ msgid "received invalid testbed message of size %u\n" #~ msgstr "ungültige Testbed Nachricht der Größe %u empfangen\n" #~ msgid "" #~ "Received testbed message of type %u but unexpected size %u, expected %u\n" #~ msgstr "" #~ "Empfangene Testbed Nachricht des Typs %u hat die unerwartete Größe %u, es " #~ "wurde %u erwartet\n" #~ msgid "No testbed URL given, not registered.\n" #~ msgstr "" #~ "Keine Testbed URL angegeben, es wurde keine Registrierung vorgenommen.\n" #~ msgid "Could not resolve name of HTTP proxy `%s'.\n" #~ msgstr "Der Name des HTTP Proxies `%s' konnte nicht aufgelöst werden.\n" #~ msgid "Malformed http URL: `%s' at `%s'. Testbed-client not registered.\n" #~ msgstr "" #~ "Beschädigte HTTP URL: `%s' bei `%s'. Testbed-Client wurde nicht " #~ "registriert.\n" #~ msgid "Could not register testbed, host `%s' unknown\n" #~ msgstr "" #~ "Testbed konnte nicht registriert werden, Host `%s' ist nicht bekannt.\n" #~ msgid "Failed to send HTTP request to host `%s': %s\n" #~ msgstr "HTTP Anfrage konnte nicht an Host `%s' gesendet werden: %s\n" #~ msgid "Failed so send HTTP request `%s' to host `%s': %s\n" #~ msgstr "Fehler beim Senden der HTTP Anfrage `%s' an Host `%s': %s\n" #~ msgid "Exit register (error: no http response read).\n" #~ msgstr "Abbruch der Registrierung (Fehler: keine HTTP Antwort gelesen).\n" #~ msgid "allows construction of a P2P-testbed (incomplete)" #~ msgstr "Ermöglicht die Konstruktion einer P2P-Testumgebung (inkomplett)" #, fuzzy #~ msgid "`%s' failed at %s:%d in %s with error: %s\n" #~ msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" #~ msgid "GNUnet configuration assistant" #~ msgstr "GNUnet Konfigurationsassistent" #, fuzzy #~ msgid "" #~ "Welcome to GNUnet!\n" #~ "\n" #~ "This assistant will ask you a few basic questions in order to configure " #~ "GNUnet.\n" #~ "\n" #~ "Please visit our homepage at\n" #~ "\thttp://gnunet.org\n" #~ "and join our community at\n" #~ "\thttps://gnunet.org/drupal/\n" #~ "\n" #~ "Have a lot of fun,\n" #~ "\n" #~ "The GNUnet team" #~ msgstr "" #~ "Willkommen bei GNUnet!\n" #~ "\n" #~ "Dieser Assistent wird Ihnen einige grundlegende Fragen stellen, um GNUnet " #~ "zu konfigurieren.\n" #~ "\n" #~ "Bitte besuchen Sie unsere Homepage\n" #~ "\thttp://gnunet.org\n" #~ "und schließen Sie sich unserer Community an:\n" #~ "\thttps://gnunet.org/drupal/\n" #~ "\n" #~ "Viel Spaß,\n" #~ "\n" #~ "das GNUnet-Team" #~ msgid "Next" #~ msgstr "Weiter" #~ msgid "" #~ "Enter information about your network connection here.\n" #~ "\n" #~ "The \"Network interface\" is the device that connects your computer to " #~ "the internet. This is usually a modem, an ISDN card or a network card in " #~ "case you are using DSL.\n" #~ "\n" #~ "If your provider always assigns the same IP-Address to you (a \"static\" " #~ "IP-Address), enter it into the \"IP-Address\" field. If your IP-Address " #~ "changes every now and then (\"dynamic\" IP-Address) but there's a " #~ "hostname that always points to your actual IP-Address (\"Dynamic DNS\"), " #~ "you can also enter it here.\n" #~ "If in doubt, leave the field empty. GNUnet will then try to determine " #~ "your IP-Address.\n" #~ "\n" #~ "If you are connected to the internet through another computer doing SNAT, " #~ "a router or a \"hardware firewall\" and other computers on the internet " #~ "cannot connect to this computer, check the last option on this page. " #~ "Leave it unchecked on direct connections through modems, ISDN cards and " #~ "DNAT (also known as \"port forwarding\")." #~ msgstr "" #~ "Geben Sie hier Ihre Netzwerkinformationen ein.\n" #~ "\n" #~ "Das \"Netzwerkgerät\" ist das Gerät, das Ihren Computer mit dem Internet " #~ "verbindet. Dies ist normalerweise ein Modem, eine ISDN-Karte oder eine " #~ "Netzwerkkarte für den Fall, dass Sie DSL benutzen.\n" #~ "\n" #~ "Wenn Ihnen Ihr Provider immer die gleiche IP-Adresse zuweist (eine " #~ "\"statische\" IP-Adresse), geben Sie diese in das \"IP-Adresse\"-Feld " #~ "ein. Wenn Ihre IP-Adresse sich hin und wieder ändert (\"dynamische\" IP-" #~ "Adresse), es jedoch einen Hostnamen gibt, der immer auf Ihre aktuelle IP-" #~ "Adresse zeigt (\"Dynamisches DNS\"), so können Sie ihn auch eingeben.\n" #~ "Im Zweifel lassen Sie das Feld leer. GNUnet wird dann versuchen, die IP-" #~ "Adresse automatisch zu bestimmen.\n" #~ "\n" #~ "Wenn Sie nicht direkt mit dem Internet verbunden sind, sondern dies über " #~ "einen anderen Rechner mit SNAT, einem Router oder einer \"Hardware " #~ "Firewall\" geschieht und andere Computer im Internet keine Verbindung mit " #~ "diesem Computer herstellen können, so aktivieren Sie die letzte Option " #~ "auf dieser Seite. Lassen Sie sie jedoch deaktiviert, wenn Sie eine " #~ "direkte Verbindung über ein Modem, eine ISDN-Karte oder einen anderen " #~ "Rechner mit DNAT (auch bekannt als \"Port forwarding\") zum Internet " #~ "haben." #~ msgid "Computer cannot receive inbound connections (SNAT/Firewall)" #~ msgstr "" #~ "Computer kann keine ankommenden Verbindungen akzeptieren (SNAT/Firewall)" #~ msgid "IP-Address/Hostname:" #~ msgstr "IP-Adresse/Hostname:" #, fuzzy #~ msgid "Network interface:" #~ msgstr "Netzwerkgerät:" #~ msgid "" #~ "You can limit GNUnet's ressource usage here.\n" #~ "\n" #~ "\"Bandwidth limitation\" is how much data may be sent per second. If you " #~ "have a flatrate you can set it to the maximum speed of your internet " #~ "connection.\n" #~ "\n" #~ "The \"Max. CPU usage\" is the percentage of processor time GNUnet is " #~ "allowed to use." #~ msgstr "" #~ "Hier können Sie GNUnet's Ressourcennutzung einschränken.\n" #~ "\n" #~ "\"Bandbreitenbeschränkung\" gibt an, wieviele Daten maximal pro Sekunde " #~ "übetragen werden dürfen. Wenn Sie eine Flatrate haben, können Sie diese " #~ "Werte auf die maximal erreichbare Geschwindigkeit Ihrer " #~ "Internetverbindung setzen.\n" #~ "\n" #~ "Die \"Max. CPU Nutzung\" gibt den Prozentsatz an CPU-Zeit an, den GNUnet " #~ "für sich verwenden darf." #~ msgid "Downstream (Bytes/s):" #~ msgstr "Downstream (Bytes/s):" #~ msgid "Upstream (Bytes/s):" #~ msgstr "Upstream (Bytes/s):" #~ msgid "Bandwidth limitation" #~ msgstr "Bandbreitenbeschränkung" #~ msgid "Use denoted bandwidth for GNUnet" #~ msgstr "Angegebene Bandbreite für GNUnet verwenden" #~ msgid "Share denoted bandwidth with other applications" #~ msgstr "Angegebene Bandbreite mit anderen Anwendungen teilen" #~ msgid "Bandwidth sharing" #~ msgstr "Aufteilung der Bandbreite" #~ msgid "Max. CPU usage (%):" #~ msgstr "Max. CPU Nutzung (%):" #~ msgid "CPU usage" #~ msgstr "CPU Nutzung" #~ msgid "Load limitation" #~ msgstr "Lastbeschränkung" #~ msgid "" #~ "GNUnet is able to store data from other peers in your datastore. This is " #~ "useful if an adversary has access to your inserted content and you need " #~ "to deny that the content is yours. With \"content migration\" on, the " #~ "content could have \"migrated\" over the internet to your node without " #~ "your knowledge.\n" #~ "It also helps to spread popular content over different peers to enhance " #~ "availability.\n" #~ "\n" #~ "The GNUnet datastore contains all data that GNUnet generates (index data, " #~ "inserted and migrated content). Its maximum size can be specified below.\n" #~ "\n" #~ "If you are an experienced user, you may want to tweak your GNUnet " #~ "installation using the enhanced configurator.\n" #~ "\n" #~ "After changing the configuration and/or updating GNUnet, it is sometimes " #~ "required to run gnunet-update to update internal data structures. " #~ "Depending on the changes made, this may take some time." #~ msgstr "" #~ "GNUnet ist in der Lage, Daten von anderen Knoten in Ihrem Datenspeicher " #~ "zu speichern. Das ist nützlich, wenn ein Widersacher Zugriff auf Ihre " #~ "eingefügten Inhalte erlangt und Sie abstreiten müssen, dass diese Daten " #~ "Ihnen gehören. Mit \"Inhaltsmigration\" angeschaltet können die Inhalte " #~ "über das Internet von einem anderen Knoten zu Ihrem Rechner ohne Ihr " #~ "Wissen \"gewandert\" sein.\n" #~ "Außerdem hilft es, beliebte Inhalte über verschiedene Netzteilnehmer zu " #~ "verteilen, um so die Verfügbarkeit zu erhöhen.\n" #~ "\n" #~ "Der GNUnet Datenspeicher enthält alle Daten, die GNUnet erzeugt " #~ "(Indexdaten, eingefügte und migrierte Inhalte). Seine maximale Größe kann " #~ "unten angegeben werden.\n" #~ "\n" #~ "Wenn Sie ein fortgeschrittener Benutzer sind, möchten Sie vielleicht " #~ "weitere Feinjustierungen an GNUnet über den \"erweiterten Konfigurator\" " #~ "vornehmen.\n" #~ "Nachdem die Konfiguration verändert und/oder GNUnet upgedated wurde ist " #~ "es manchmal nötig, gnunet-update auszuführen, um interne Datenstrukturen " #~ "zu aktualisieren. Abhängig von den gemachten Änderungen kann dies etwas " #~ "Zeit in Anspruch nehmen." #~ msgid "Store migrated content" #~ msgstr "Migrierte Inhalte speichern" #~ msgid "Maximum datastore size (MB):" #~ msgstr "Maximale Größe des Datenspeichers (MB):" #~ msgid "Start the GNUnet background process on computer startup" #~ msgstr "" #~ "GNUnet Hintergrundprozeß beim Starten des Computers automatisch starten" #~ msgid "Open the enhanced configurator" #~ msgstr "Erweiterten Konfigurator starten" #, fuzzy #~ msgid "Run gnunet-update" #~ msgstr "gnunet-update schlug fehlt!" #, fuzzy #~ msgid "Other settings" #~ msgstr "Weitere Einstellungen" #~ msgid "Finish" #~ msgstr "Fertigstellen" #~ msgid "" #~ "Define the user and the group owning the GNUnet service here.\n" #~ "\n" #~ "For security reasons, it is a good idea to let this setup create a new " #~ "user account and a new group under which the GNUnet service is started at " #~ "system startup.\n" #~ "\n" #~ "However, GNUnet may not be able to access files other than its own. This " #~ "includes files you want to publish in GNUnet. You'll have to grant read " #~ "permissions to the user specified below.\n" #~ "\n" #~ "Leave the fields empty to run GNUnet with system privileges." #~ msgstr "" #~ "Geben Sie den Benutzer und die Gruppe an, der der GNUnet Dienst gehören " #~ "soll.\n" #~ "\n" #~ "Aus Sicherheitsgründen ist es eine gute Idee, dieses Setup ein neues " #~ "Benutzerkonto und eine neue Gruppe anlegen zu lassen, unter der der " #~ "GNUnet Dienst beim Systemstart läuft.\n" #~ "\n" #~ "Natürlich kann GNUnet dann nur auf seine eigenen Dateien zugreifen. Dies " #~ "betrifft auch Dateien, die Sie im GNUnet veröffentlichen möchten. Sie " #~ "müssen dann dem unten angegebenen Benutzerkonto zuerst Leseberechtigungen " #~ "geben.\n" #~ "\n" #~ "Lassen Sie dieses Feld leer, wenn Sie GNUnet mit Systemprivilegien laufen " #~ "lassen möchten." #~ msgid "User account:" #~ msgstr "Benutzerkonto:" #~ msgid "Group:" #~ msgstr "Gruppe:" #, fuzzy #~ msgid "gnunet-setup" #~ msgstr "gnunet-update ausführen" #, fuzzy #~ msgid "Save configuration" #~ msgstr "GNUnet Konfiguration" #, fuzzy #~ msgid "Show copyright information for gnunet-setup." #~ msgstr "Fehler beim Lesen von Informationen von gnunetd.\n" #, fuzzy #~ msgid "About gnunet-setup" #~ msgstr "gnunet-update ausführen" #, fuzzy #~ msgid "This is the configuration tool for GNUnet." #~ msgstr "" #~ "Einen Wert aus der Konfigurationsdatei auf der Standardausgabe ausgeben" #~ msgid "Not for English ;-)" #~ msgstr "Nils Durner and Christian Grothoff" #, fuzzy #~ msgid "Description" #~ msgstr "Frage" #, fuzzy #~ msgid "Section" #~ msgstr "Frage" #, fuzzy #~ msgid "Option" #~ msgstr "_Optionen" #~ msgid "TRACEKIT: routing table full, trace request dropped\n" #~ msgstr "TRACEKIT: Routing-Tabelle ist voll, Trace-Anfrage wird verworfen\n" #~ msgid "TRACEKIT: received invalid `%s' message\n" #~ msgstr "TRACEKIT: ungültige `%s' Nachricht empfangen\n" #~ msgid "Format specification invalid. Use 0 for user-readable, 1 for dot\n" #~ msgstr "" #~ "Formatangabe ungültig. Verwenden Sie 0 für menschen-lesbar und 1 für dot\n" #~ msgid "Peer `%s' did not report back.\n" #~ msgstr "Knoten `%s' hat sich nicht zurückgemeldet.\n" #~ msgid "" #~ "You must specify the name of a pipe for the SMTP transport in section `" #~ "%s' under `%s'.\n" #~ msgstr "" #~ "Für den SMTP Transport müssen Sie den Namen einer Pipe in Sektion `%s', " #~ "Eintrag `%s' eintragen.\n" #~ msgid "Sending E-mail to `%s' failed.\n" #~ msgstr "Das Senden einer E-Mail an `%s' schlug fehl.\n" #~ msgid "%.*s filter %s (SMTP)" #~ msgstr "%.*s filter %s (SMTP)" #~ msgid "MTU for `%s' is probably too low (fragmentation not implemented!)\n" #~ msgstr "" #~ "MTU für `%s' ist möglicherweise zu gering (Fragmentierung ist nicht " #~ "implementiert!)\n" #, fuzzy #~ msgid "Network configuration: NAT" #~ msgstr "GNUnet Konfiguration" #~ msgid "" #~ "Is this machine behind NAT?\n" #~ "\n" #~ "If you are connected to the internet through another computer doing SNAT, " #~ "a router or a \"hardware firewall\" and other computers on the internet " #~ "cannot connect to this computer, say \"yes\" here. Answer \"no\" on " #~ "direct connections through modems, ISDN cards and DNAT (also known as " #~ "\"port forwarding\")." #~ msgstr "" #~ "Ist diese Maschine hinter NAT?\n" #~ "\n" #~ "Wenn Sie mit dem Internet über einen anderen Computer per SNAT, einem " #~ "Router oder einer \"Hardware Firewall\" verbunden sind und andere " #~ "Computer im Internet keine Verbindung zu diesem Computer herstellen " #~ "können, so sagen Sie hier \"Ja\". Antworten Sie \"Nein\" bei direkten " #~ "Verbindungen über Modem, ISDN-Karten und DNAT (auch bekannt als \"Port " #~ "forwarding\")." #, fuzzy #~ msgid "Configuration of the logging system" #~ msgstr "" #~ "Konfiguration oder die GNUnet Version hat sich geändert. Sie müssen `%s' " #~ "ausführen!\n" #, fuzzy #~ msgid "Run gnunetd as this user." #~ msgstr "gnunet-update ausführen" #, fuzzy #~ msgid "Run gnunetd during system startup?" #~ msgstr "gnunet-update ausführen" #, fuzzy #~ msgid "Path settings" #~ msgstr "Weitere Einstellungen" #~ msgid "specify nickname" #~ msgstr "Spitznamen angeben" #~ msgid "Start GNUnet chat client." #~ msgstr "GNUnet chat client starten" #~ msgid "You must specify a nickname (use option `%s').\n" #~ msgstr "" #~ "Sie müssen einen Spitznamen angeben (verwenden Sie die Option `%s').\n" #~ msgid "Could not send message to gnunetd\n" #~ msgstr "Nachricht konnte nicht an gnunetd gesendet werden.\n" #~ msgid "mysql datastore" #~ msgstr "mysql Datenspeicher" #, fuzzy #~ msgid "" #~ "`%s' failed at %s:%d with error: I/%s S/%s SC/%s SS/%s SSC/%s U/%s D/%s " #~ "DG/%s\n" #~ msgstr "`%s' schlug bei %s:%d mit dem Fehler %s fehl\n" #~ msgid "Database failed to delete `%s'.\n" #~ msgstr "Die Datenbank konnte `%s' nicht löschen.\n" #, fuzzy #~ msgid "Error log:\n" #~ msgstr "Fehler" #, fuzzy #~ msgid "# bytes received via TCP-OLD" #~ msgstr "# Bytes empfangen über TCP" #, fuzzy #~ msgid "# bytes sent via TCP-OLD" #~ msgstr "# Bytes gesendet über TCP" #, fuzzy #~ msgid "# bytes dropped by TCP-OLD (outgoing)" #~ msgstr "# Bytes verworfen von TCP (ausgehend)" #~ msgid "hello advertisement for protocol %d received.\n" #~ msgstr "Hello Ankündigung für Protokoll %d empfangen.\n" #~ msgid "`%s' failed (%d, %u). Will not send PING.\n" #~ msgstr "`%s' fehlgeschlagen (%d, %u). PING wird nicht gesendet.\n" #~ msgid "Removing hello from peer `%s' (expired %ds ago).\n" #~ msgstr "Hello von Knoten `%s' wird entfernt (lief vor %ds ab).\n" #~ msgid "Waiting for gnunetd to start (%u iterations left)...\n" #~ msgstr "Warte auf den Start von gnunetd (%u Iterationen verbleiben)...\n" #, fuzzy #~ msgid "Deleting expired content. This may take a while.\n" #~ msgstr "Ein neuer Hostkey wird erzeugt (dies kann eine Weile dauern).\n" #~ msgid "User `%s' not known, cannot change UID to it.\n" #~ msgstr "" #~ "Benutzer `%s' ist nicht bekannt, UID kann nicht gewechselt werden.\n" #~ msgid "" #~ "Expected welcome on http connection, got garbage. Closing connection.\n" #~ msgstr "" #~ "Es wurde eine Willkommensnachricht erwartet, tatsächlich wurde jedoch " #~ "keine gesendet. HTTP-Verbindung wird geschlossen.\n" #~ msgid "%s: Rejected connection from blacklisted address %u.%u.%u.%u.\n" #~ msgstr "" #~ "%s: Abgewiesene Verbindung von schwarzgelisteter Adresse %u.%u.%u.%u.\n" #~ msgid "" #~ "Could not bind the HTTP listener to port %d. No transport service " #~ "started.\n" #~ msgstr "" #~ "HTTP-Listener konnte nicht an Port %d gebunden werden. Der Transport " #~ "Dienst wurde nicht gestartet.\n" #~ msgid "Unexpected reply to `%s' operation.\n" #~ msgstr "Unerwartete Antwort zu `%s' Operation.\n" #~ msgid "join table called NAME" #~ msgstr "Tabelle NAME anschließen" #~ msgid "Malformed optional field `%s' received from peer `%s'.\n" #~ msgstr "Ungültiges optionales Feld `%s' empfangen von Knoten `%s'.\n" #~ msgid "Malformed response to `%s' on master table.\n" #~ msgstr "Beschädigte Antwort auf `%s' in Master Tabelle.\n" #~ msgid "Invalid response to `%s' from `%s'\n" #~ msgstr "Ungültige Antwort auf `%s' von `%s'\n" #~ msgid "Received invalid RPC `%s'.\n" #~ msgstr "Ungültiger RPC `%s' empfangen.\n" #~ msgid "RPC for `%s' received for table that we do not participate in!\n" #~ msgstr "" #~ "RPC für `%s' empfangen für eine Tabelle, an der wir nicht beteiligt " #~ "sind!\n" #~ msgid "`%s' failed. Terminating connection to client.\n" #~ msgstr "`%s' fehlgeschlagen. Beende Verbindung zu Client.\n" #~ msgid "" #~ "`%s' called with cron job not in queue, adding. This may not be what you " #~ "want.\n" #~ msgstr "" #~ "`%s' aufgerufen wobei Cron Job nicht Warteschlange ist. Er wird " #~ "hinzugefügt. Das ist möglicherweise nicht, was Sie wollen.\n" #~ msgid "" #~ "Share denoted bandwidth with other applications?\n" #~ "\n" #~ "Say \"yes\" here, if you don't want other network traffic to interfere " #~ "with GNUnet's operation, but still wish to constrain GNUnet's bandwidth " #~ "usage to values entered in the previous steps, or if you can't reliably " #~ "measure the maximum capabilities of your connection. \"No\" can be very " #~ "useful if other applications are causing a lot of traffic on your LAN. " #~ "In this case, you do not want to limit the traffic that GNUnet can " #~ "inflict on your internet connection whenever your high-speed LAN gets " #~ "used (e.g. by NFS)." #~ msgstr "" #~ "Angegebene Bandbreite mit anderen Anwendungen teilen?\n" #~ "\n" #~ "Sagen Sie hier \"Ja\", wenn Sie nicht möchten, dass anderer " #~ "Netzwerkverkehr GNUnets Funktion stört aber dennoch GNUnets Bandbreite " #~ "gemäß den Angaben in den vorherigen Schritten einschränken möchten oder " #~ "Sie die maximalen Möglichkeiten Ihrer Internetverbindung nicht " #~ "zuverlässig messen können. \"Nein\" kann nützlich sein, wenn andere " #~ "Anwendungen viel Netzwerkverkehr in Ihrem LAN verursachen. In diesem Fall " #~ "möchten Sie nicht GNUnets Netzwerkverkehr über die Internetverbindung " #~ "einschränken, wann immer Ihre Hochgeschwindigkeits-LAN-Verbindung " #~ "verwendet wird (z.B. durch NFS)." #~ msgid "How much CPU (in %) may be used?" #~ msgstr "Wieviel CPU (in %) darf verwendet werden?" #~ msgid "" #~ "You can limit GNUnet's resource usage here.\n" #~ "\n" #~ "This is the percentage of processor time GNUnet is allowed to use." #~ msgstr "" #~ "Hier können Sie GNUnets Ressourcenverwendung einschränken.\n" #~ "\n" #~ "Dies ist der Prozentsatz an Prozessorzeit, den GNUnet verwenden darf." #~ msgid "" #~ "Store migrated content?\n" #~ "\n" #~ "GNUnet is able to store data from other peers in your datastore. This is " #~ "useful if an adversary has access to your inserted content and you need " #~ "to deny that the content is yours. With \"content migration\" on, the " #~ "content could have \"migrated\" over the internet to your node without " #~ "your knowledge.\n" #~ "It also helps to spread popular content over different peers to enhance " #~ "availability." #~ msgstr "" #~ "Sollen migrierte Inhalte gespeichert werden?\n" #~ "GNUnet ist in der Lage, Daten von anderen Knoten in Ihrem Datenspeicher " #~ "zu speichern. Das ist nützlich, wenn ein Widersacher Zugriff auf Ihre " #~ "eingefügten Inhalte erlangt und Sie abstreiten müssen, dass diese Daten " #~ "Ihnen gehören. Ist die \"Inhaltsmigration\" angeschaltet, so können die " #~ "Inhalte über das Internet von einem anderen Knoten zu Ihrem Rechner ohne " #~ "Ihr Wissen \"gewandert\" sein.\n" #~ "Außerdem hilft es, beliebte Inhalte über verschiedene Netzteilnehmer zu " #~ "verteilen, um so die Verfügbarkeit zu erhöhen." #~ msgid "" #~ "If you are an experienced user, you may want to tweak your GNUnet " #~ "installation using the enhanced configurator.\n" #~ "\n" #~ "Do you want to start it after saving your configuration?" #~ msgstr "" #~ "Wenn Sie ein erfahrener Benutzer sind, so möchten Sie vielleicht Ihre " #~ "GNUnet Installation über den erweiterten Konfigurator optimieren.\n" #~ "\n" #~ "Möchten Sie ihn starten, nachdem Ihre Konfiguration gespeichert wurde?" #~ msgid "" #~ "Unable to save configuration file %s: %s.\n" #~ "\n" #~ "Try again?" #~ msgstr "" #~ "Konfigurationsdatei %s kann nicht gespeichert werden: %s.\n" #~ "\n" #~ "Soll es nochmals versucht werden?" #~ msgid "Failed to send `%s'. Closing connection.\n" #~ msgstr "Fehler beim Senden von `%s'. Verbindung wird geschlossen.\n" #~ msgid "Received invalid `%s' request (size %d)\n" #~ msgstr "Ungültige Anfrage `%s' empfangen (Größe %d)\n" #~ msgid "Received invalid `%s' request (wrong table)\n" #~ msgstr "Ungültige Anfrage `%s' empfangen (falsche Tabelle)\n" #~ msgid "Received unknown request type %d at %s:%d\n" #~ msgstr "Unbekannte Anfrageart %d empfangen bei %s:%d\n" #~ msgid "This client already participates in the given DHT!\n" #~ msgstr "Dieser Client beteiligt sich bereits an der angegebenen DHT!\n" #~ msgid "Cannot leave DHT: table not known!\n" #~ msgstr "DHT kann nicht verlassen werden: Tabelle unbekannt!\n" #~ msgid "gnunetd signaled error in response to `%s' message\n" #~ msgstr "gnunetd gab in Bezug auf die `%s' Nachricht einen Fehler zurück.\n" #~ msgid "Failed to send `%s' message to gnunetd\n" #~ msgstr "Fehler beim Senden der `%s' Nachricht an gnunetd\n" #~ msgid "Join a DHT." #~ msgstr "Einer DHT anschließen." #~ msgid "allow SIZE bytes of memory for the local table" #~ msgstr "SIZE bytes an Speicher für die lokale Tabelle erlauben" #~ msgid "Call to `%s' with value '%.*s' (%d bytes).\n" #~ msgstr "Aufruf von `%s' mit Wert '%.*s' (%d Bytes).\n" #~ msgid "Error joining DHT.\n" #~ msgstr "Fehler beim Beitreten zu der DHT.\n" #~ msgid "Joined DHT. Press CTRL-C to leave.\n" #~ msgstr "Der DHT beigetreten. Drücken Sie STRG-C, um sie zu verlassen.\n" #~ msgid "`%s' failed: table not found!\n" #~ msgstr "`%s' fehlgeschlagen: Tabelle nicht gefunden!\n" #~ msgid "sendAck failed. Terminating connection to client.\n" #~ msgstr "sendAck fehlgeschlagen. Beende Verbindung zu Client.\n" #, fuzzy #~ msgid "Upload failed (consult logs)." #~ msgstr "ECRS Download schlug fehl (siehe Protokolldateien)." #~ msgid "Could not resolve name of SMTP server `%s': %s" #~ msgstr "Der Name des SMTP servers `%s' konnte nicht aufgelöst werden: %s" #~ msgid "SMTP server send unexpected response at %s:%d.\n" #~ msgstr "Der SMTP server sendete eine unerwartete Antwort bei %s:%d.\n" #~ msgid "" #~ "SMTP server failed to respond with 250 confirmation code to `%s' " #~ "request.\n" #~ msgstr "" #~ "SMTP Server antwortete nicht mit einem 250 Bestätigungscode auf eine `%s' " #~ "Anfrage.\n" #~ msgid "query table called NAME" #~ msgstr "Frage Tabelle mit dem Namen NAME ab" #~ msgid "No commands specified.\n" #~ msgstr "Keine Kommandos angegeben.\n" #~ msgid "Superflous arguments (ignored).\n" #~ msgstr "überflüssige Parameter (werden ignoriert).\n" #~ msgid "Query `%s' had no results.\n" #~ msgstr "Abfrage `%s' hatte keine Ergebnisse.\n" #~ msgid "FSUI persistence: error restoring download\n" #~ msgstr "FSUI Beständigkeit: Fehler beim Wiederherstellen des Downloads\n" #~ msgid "ECRS download suspending." #~ msgstr "ECRS download wird eingefroren." #~ msgid "Upload failed." #~ msgstr "Upload fehlgeschlagen." #~ msgid "Cannot upload directory without using recursion." #~ msgstr "" #~ "Verzeichnis kann nicht ohne die Verwendung von Rekursion hochgeladen " #~ "werden." #, fuzzy #~ msgid "expected `%s' to be a directory!\n" #~ msgstr "`%s' erwartet, dass `%s' ein Verzeichnis ist!\n" #~ msgid "Sorry, no help is available for this option.\n" #~ msgstr "Sorry, für diese Option steht keine Hilfe zur Verfügung.\n" #~ msgid "" #~ "Cannot determine port to bind to. Define in configuration file in " #~ "section `%s' under `%s' or in `%s' under %s/%s.\n" #~ msgstr "" #~ "Der Port, an dem Verbindungen entgegengenommen werden sollen, konnte " #~ "nicht ermittelt werden. Bitte definieren Sie ihn in der " #~ "Konfigurationsdatei in der Sektion `%s' unter `%s' oder in `%s' unter %s/" #~ "%s.\n" #, fuzzy #~ msgid "UDP6: select returned, but ioctl reports %d bytes available!\n" #~ msgstr "" #~ "UDP: select kam zurück aber ioctl berichtet, dass 0 Bytes verfügbar " #~ "sind!\n" #~ msgid "Received invalid UDP6 message from %s:%d, dropping.\n" #~ msgstr "" #~ "Ungültige UDP6 Nachricht von %s:%d empfangen, Nachricht wird ignoriert.\n" #~ msgid "Packet received from %s:%d (UDP6) failed format check." #~ msgstr "" #~ "Die Formatüberprüfung des Pakets, das von %s:%d (UDP6) empfangen wurde, " #~ "schlug fehl." #~ msgid "%s: Rejected connection from blacklisted address %s.\n" #~ msgstr "%s: Zurückgewiesene Verbindung von schwarzgelisteter Adresse %s.\n" #~ msgid "" #~ "Expected welcome message on tcp connection, got garbage (%u, %u). " #~ "Closing.\n" #~ msgstr "" #~ "Es wurde eine Willkommensnachricht erwartet, über die TCP Verbindung " #~ "wurde aber keine gesendet (%u, %u). Verbindung wird geschlossen.\n" #, fuzzy #~ msgid "UDP: select returned, but ioctl reports %d bytes available!\n" #~ msgstr "" #~ "UDP: select kam zurück aber ioctl berichtet, dass 0 Bytes verfügbar " #~ "sind!\n" #~ msgid "Received invalid UDP message from %u.%u.%u.%u:%u, dropping.\n" #~ msgstr "" #~ "Es wurde eine ungültige UDP Nachricht von %u.%u.%u.%u:%u empfangen, " #~ "Nachricht wird ignoriert.\n" #~ msgid "Packet received from %u.%u.%u.%u:%u (UDP) failed format check.\n" #~ msgstr "" #~ "Ein Paket empfangen von %u.%u.%u.%u:%u (UDP) hat ein ungültiges Format.\n" #~ msgid "Expected welcome message on tcp connection, got garbage. Closing.\n" #~ msgstr "" #~ "Es wurde eine Willkommensnachricht erwartet, über die TCP Verbindung " #~ "wurde jedoch keine gesendet. Verbindung wird geschlossen.\n" #~ msgid "" #~ "Received malformed message from tcp6-peer connection. Closing " #~ "connection.\n" #~ msgstr "" #~ "über die TCP6-Verbindung zu einem anderen Knoten wurde eine ungültige " #~ "Nachricht empfangen. Verbindung wird geschlossen.\n" #~ msgid "Version mismatch (`%s' vs. '%*.s'), run gnunet-update!\n" #~ msgstr "" #~ "Versionen stimmen nicht überein (`%s' vs. '%*.s'), lassen Sie gnunet-" #~ "update laufen!\n" #~ msgid "" #~ "Configuration file must specify directory for storing FS data in section `" #~ "%s' under `%s'.\n" #~ msgstr "" #~ "Die Konfigurationsdatei muss in der Sektion `%s' unter `%s' ein " #~ "Verzeichnis angeben, in dem FS Daten gespeichert werden.\n" #~ msgid "" #~ "Configuration file must specify a directory for GNUnet to store per-peer " #~ "data under %s%s\n" #~ msgstr "" #~ "Die Konfigurationsdatei muss unter %s%s ein Verzeichnis angeben, in dem " #~ "GNUnet knotenspezifische Daten speichern kann.\n" #~ msgid "%s `%s' returned no known hosts!\n" #~ msgstr "%s `%s' ergab keine bekannten Knoten!\n" #~ msgid "" #~ "You should specify at least one transport service under option `%s' in " #~ "section `%s'.\n" #~ msgstr "" #~ "Sie sollten mindestens einen Transport Dienst unter der Option `%s' in " #~ "der Sektion `%s' angegeben.\n" #~ msgid "" #~ "specify that the contents of the namespace are of the given MIMETYPE (use " #~ "when creating a new pseudonym)" #~ msgstr "" #~ "Angeben, dass die Inhalte des Namespaces vom angegebenen MIMETYOE sind " #~ "(zu verwenden, wenn ein neues Pseudonym erstellt wird)" #~ msgid "" #~ "specify NAME to be the realname of the user controlling the namespace " #~ "(use when creating a new pseudonym)" #~ msgstr "" #~ "NAME als den Realnamen des Benutzers angeben, der den Namespace verwaltet " #~ "(zu verwenden, wenn ein neues Pseudonym erstellt wird)" #~ msgid "" #~ "use DESCRIPTION to describe the content of the namespace (use when " #~ "creating a new pseudonym)" #~ msgstr "" #~ "DESCRIPTION als Beschreibung der Inhalte des Namespaces verwenden (zu " #~ "verwenden, wenn ein neues Pseudonym erstellt wird)" #~ msgid "" #~ "specify the given URI as an address that contains more information about " #~ "the namespace (use when creating a new pseudonym)" #~ msgstr "" #~ "die angegebene URI als die Adresse angeben, die weitere Informationen " #~ "über den Namespace enthält (zu verwenden, wenn ein neues Pseudonym " #~ "erstellt wird)" #~ msgid "%8u of %8u bytes deleted." #~ msgstr "%8u von %8u Bytes gelöscht." #~ msgid "specify the file to delete from GNUnet (obligatory, file must exist)" #~ msgstr "" #~ "vom GNUnet zu löschende Datei angeben (obgligatorisch, Datei muss " #~ "existieren)" #~ msgid "" #~ "Remove file from GNUnet. The specified file is not removed\n" #~ "from the filesystem but just from the local GNUnet datastore." #~ msgstr "" #~ "Datei auf GNUnet löschen. Die angegebene Datei wird nicht aus dem " #~ "Dateisystem gelöscht, sondern aus dem lokalen GNUnet Datenspeicher." #~ msgid "You must specify a filename (option -f)\n" #~ msgstr "Sie müssen eine Datei angeben (Option -f)\n" #~ msgid "" #~ "Error deleting file %s.\n" #~ "Probably a few blocks were already missing from the database.\n" #~ msgstr "" #~ "Fehler beim Löschen der Datei %s.\n" #~ "Möglicherweise fehlen bereits einige wenige Datenblöcke in der " #~ "Datenbank.\n" #~ msgid "gnunet-directory [OPTIONS] [FILENAMES]" #~ msgstr "gnunet-directory [OPTIONEN] [DATEINAMEN]" #~ msgid "process directories recursively" #~ msgstr "Verzeichnisse rekursiv bearbeiten" #~ msgid "You must pass a positive number to the `%s' option.\n" #~ msgstr "Sie müssen eine positive Zahl zu der Option `%s' übergeben.\n" #~ msgid "Only one file or directory can be specified at a time.\n" #~ msgstr "Nur eine Datei oder Verzeichnis kann auf einmal angegeben werden.\n" #~ msgid "You must specify a file or directory to upload.\n" #~ msgstr "Sie müssen eine Datei oder Verzeichnis für den Upload angeben.\n" #~ msgid "Not enough arguments. You must specify a keyword or identifier.\n" #~ msgstr "" #~ "Nicht genügend Parameter. Sie müssen ein Schlüsselwort oder einen " #~ "Bezeichner angeben.\n" #~ msgid "LEVEL" #~ msgstr "GRAD" #~ msgid "FILENAME" #~ msgstr "DATEINAME" #~ msgid "" #~ "Configuration file must specify a directory for GNUnet to store per-peer " #~ "data under %s%s.\n" #~ msgstr "" #~ "Die Konfigurationsdatei muss unter %s%s ein Verzeichnis für GNUnet " #~ "angeben, in dem Knotenbezogene Daten gespeichert werden.\n" #~ msgid "Template for gnunet-clients." #~ msgstr "Vorlage für gnunet-clients." #~ msgid "Invalid port \"%s\" in hostlist specification, trying port %d.\n" #~ msgstr "Ungültiger Port \"%s\" in Angabe der Hostlist, versuche Port %d.\n" #~ msgid "Could not download list of peer contacts, host `%s' unknown.\n" #~ msgstr "" #~ "Die Liste mit Knotenkontakten konnte nicht heruntergeladen werden, Host `" #~ "%s' ist unbekannt.\n" #~ msgid "Parsing HTTP response for URL `%s' failed.\n" #~ msgstr "Das Parsen der HTTP Antwort für die URL `%s' schlug fehl.\n" #~ msgid "Could not resolve name of HTTP proxy `%s'. Trying without a proxy.\n" #~ msgstr "" #~ "Der Name des HTTP Proxies `%s' konnte nicht aufgelöst werden. Es wird " #~ "ohne Proxy versucht.\n" #~ msgid "Did not receive reply from gnunetd about traffic conditions.\n" #~ msgstr "Keine Antwort von gnunetd über die Netzwerkverkehrsbedingungen.\n" #~ msgid "" #~ "Configuration file must specify a directory for GNUnet to store per-peer " #~ "data under %s\\%s.\n" #~ msgstr "" #~ "Die Konfigurationsdatei muss unter %s\\%s ein Verzeichnis für GNUnet " #~ "angeben, in dem knotenbezogene Daten gespeichert werden.\n" #~ msgid "Option `%s' makes no sense without option `%s'." #~ msgstr "Option `%s' macht keinen Sinn ohne die Option `%s'." #~ msgid "" #~ "\n" #~ "Exiting.\n" #~ msgstr "" #~ "\n" #~ "Abbruch.\n" #~ msgid "Updated data for %d applications.\n" #~ msgstr "Daten für %d Anwendungen wurden aktualisiert.\n" #~ msgid "Argument %d: `%s'\n" #~ msgstr "Parameter %d: `%s'\n" #~ msgid "`%s' starting\n" #~ msgstr "`%s' startet\n" #~ msgid "FATAL: Identity plugin not found!\n" #~ msgstr "SCHWERWIEGEND: Identity Plugin wurde nicht gefunden!\n" #~ msgid "You must specify a non-empty set of transports to test!\n" #~ msgstr "" #~ "Sie müssen eine Menge an Transporten angeben, die getestet werden " #~ "sollen!\n" #~ msgid "Available MODEs:\n" #~ msgstr "Verfügbare MODEs:\n" #~ msgid " config\t\ttext-based configuration\n" #~ msgstr " config\t\ttext-basierte Konfiguration\n" #~ msgid " menuconfig\ttext-based menu\n" #~ msgstr "menuconfig\ttext-basiertes Menü\n" #~ msgid " wizard-curses\tBasic text-based graphical configuration\n" #~ msgstr " wizard-curses\tEinfache text-basierte grafische Konfiguration\n" #~ msgid "" #~ " wizard-gtk\tBasic GTK configuration\n" #~ "\n" #~ msgstr "" #~ " wizard-gtk\tEinfache GTK Konfiguration\n" #~ "\n" #~ msgid "gnunet-setup must have write-access to the configuration file `%s'\n" #~ msgstr "" #~ "gnunet-setup benötigt Schreibberechtigungen für die Konfigurationsdatei `" #~ "%s'\n" #~ msgid "" #~ "Can only run wizard to configure gnunetd.\n" #~ "Did you forget the `%s' option?\n" #~ msgstr "" #~ "Der Assistent kann nur zur Einrichtung von gnunetd gestartet werden.\n" #~ "Haben Sie die `%s'-Option vergessen?\n" #~ msgid "Gtk GNUnet Configurator" #~ msgstr "Gtk GNUnet Konfigurator" #~ msgid "_File" #~ msgstr "_Datei" #~ msgid "_Load" #~ msgstr "_öffnen" #~ msgid "Save the config in .config" #~ msgstr "Die Konfiguration in .config speichern" #~ msgid "_Save" #~ msgstr "_Speichern" #~ msgid "_Quit" #~ msgstr "_Beenden" #~ msgid "Show _name" #~ msgstr "_Name anzeigen" #~ msgid "Show range (Y/M/N)" #~ msgstr "Bereich anzeigen (Y/M/N)" #~ msgid "Show _range" #~ msgstr "_Bereich anzeigen" #~ msgid "Show _data" #~ msgstr "_Daten anzeigen" #~ msgid "Show all _options" #~ msgstr "Alle _Optionen anzeigen" #~ msgid "_Help" #~ msgstr "_Hilfe" #~ msgid "_Introduction" #~ msgstr "_Einführung" #~ msgid "Goes up of one level (single view)" #~ msgstr "Bewegt sich eine Ebene nach oben (einfache Ansicht)" #~ msgid "Load" #~ msgstr "Laden" #~ msgid "Save a config file" #~ msgstr "Konfigurationsdatei speichern" #~ msgid "Save" #~ msgstr "Speichern" #~ msgid "Single view" #~ msgstr "Einfache Ansicht" #~ msgid "Single" #~ msgstr "Einfach" #~ msgid "Split view" #~ msgstr "Geteilte Ansicht" #~ msgid "Split" #~ msgstr "Geteilt" #~ msgid "Full view" #~ msgstr "Volle Ansicht" #~ msgid "Full" #~ msgstr "Voll" #~ msgid "Collapse the whole tree in the right frame" #~ msgstr "Den gesamten Baum im rechten Frame kollabieren" #~ msgid "Collapse" #~ msgstr "Kollabieren" #~ msgid "Expand the whole tree in the right frame" #~ msgstr "Den gesamten Baum im rechten Frame expandieren" #~ msgid "Expand" #~ msgstr "Expandieren" #, fuzzy #~ msgid "Introduction" #~ msgstr "_Einführung" #~ msgid "inlining configration file `%s'\n" #~ msgstr "Binde Konfigurationsdatei `%s' ein\n" #~ msgid "" #~ "Configuration file not found. Please run GNUnet Setup (Client " #~ "Configuration) first." #~ msgstr "" #~ "Die Konfigurationsdatei wurde nicht gefunden. Bitte führen Sie zuerst " #~ "GNUnet Setup (Client Konfiguration) aus." #~ msgid "Configuration file `%s' not found. Run `gnunet-setup -d'!\n" #~ msgstr "" #~ "Konfigurationsdatei `%s' nicht gefunden. Bitte führen Sie `gnunet-setup -" #~ "d' aus!\n" #~ msgid "Cron stopped\n" #~ msgstr "Cron angehalten\n" #~ msgid "Caught signal %d.\n" #~ msgstr "Signal %d empfangen.\n" #~ msgid "Invalid network notation (additional characters: `%s')." #~ msgstr "Ungültige Netzwerk Notation (zusätzliche Zeichen: `%s')." #~ msgid "FAILURE" #~ msgstr "FEHLSCHLAG" #~ msgid "MESSAGE" #~ msgstr "MELDUNG" #~ msgid "CRON" #~ msgstr "CRON" #~ msgid "EVERYTHING" #~ msgstr "ALLES" #~ msgid "Invalid LOGLEVEL `%s' specified.\n" #~ msgstr "Ungültiger LOGLEVEL `%s' angegeben.\n" #~ msgid "Failure at %s:%d.\n" #~ msgstr "Fehler bei %s:%d.\n" #~ msgid "" #~ "Cannot determine port of gnunetd server. Define in configuration file in " #~ "section `%s' under `%s'.\n" #~ msgstr "" #~ "Der Port des gnunetd Servers konnte nicht ermittelt werden. Definieren " #~ "Sie ihn in der Sektion `%s' unter `%s'.\n" #~ msgid "" #~ "Usage: %s\n" #~ "%s\n" #~ "\n" #~ msgstr "" #~ "Verwendung: %s\n" #~ "%s\n" #~ "\n" #~ msgid "Invalid argument for `%s' at %s:%d.\n" #~ msgstr "Ungültiger Parameter für `%s' bei %s:%d.\n" #~ msgid "g" #~ msgstr "g" #~ msgid "t" #~ msgstr "t" #~ msgid "`%s' failed, other side closed connection.\n" #~ msgstr "" #~ "`%s' fehlgeschlagen, die andere Seite hat die Verbindung geschlossen\n" #~ msgid "Attempted path to `%s' was `%s'.\n" #~ msgstr "Versuchter Pfad für `%s' war `%s'.\n" #~ msgid "set verbosity to LEVEL" #~ msgstr "Umfang der Meldungen auf LEVEL setzen" #~ msgid "_License" #~ msgstr "_Lizenz" #~ msgid "Sorry, no help available for this option yet." #~ msgstr "Sorry, für diese Option steht noch keine Hilfe zur Verfügung" #~ msgid "Couldn't find pixmap file: %s" #~ msgstr "Pixmapdatei %s konnte nicht gefunden werden" #~ msgid "" #~ "Welcome to GNUnet!\n" #~ "\n" #~ "This assistant will ask you a few basic questions in order to configure " #~ "GNUnet.\n" #~ "\n" #~ "Please visit our homepage at\n" #~ "\thttp://www.gnunet.org\n" #~ "and join our community at\n" #~ "\thttp://www.gnunet.org/drupal/\n" #~ "\n" #~ "Have a lot of fun,\n" #~ "\n" #~ "the GNUnet team" #~ msgstr "" #~ "Willkommen bei GNUnet!\n" #~ "\n" #~ "Dieser Assistent wird Ihnen einige grundlegende Fragen stellen, um GNUnet " #~ "zu konfigurieren.\n" #~ "\n" #~ "Bitte besuchen Sie unsere Homepage\n" #~ "\thttp://gnunet.org\n" #~ "und schließen Sie sich unserer Community an:\n" #~ "\thttps://gnunet.org/drupal/\n" #~ "\n" #~ "Viel Spaß,\n" #~ "\n" #~ "das GNUnet-Team" #~ msgid "" #~ "You must specify a directory for FS files in the configuration in section " #~ "`%s' under `%s'." #~ msgstr "" #~ "Sie müssen ein Verzeichnis für FS Dateien in der Konfigurationsdatei in " #~ "der Sektion `%s' unter `%s' angeben." #~ msgid "Invalid data in MySQL database. Please verify integrity!\n" #~ msgstr "" #~ "Ungültige Daten in der MySQL Datenbank. Bitte überprüfen Sie die " #~ "Integrität!\n" #~ msgid "SQL Database corrupt, ignoring result.\n" #~ msgstr "SQL Datenbank beschädigt, Ergebnis wird ignoriert.\n" #~ msgid "Invalid data in database. Please verify integrity!\n" #~ msgstr "" #~ "Es befinden sich ungültige Daten in Datenbank. Bitte überprüfen Sie die " #~ "Integrität!\n" #~ msgid "menuconfig is not available\n" #~ msgstr " menuconfig ist nicht verfügbar\n" #~ msgid "wizard-curses is not available\n" #~ msgstr "wizard-curses ist nicht verfügbar\n" #~ msgid "wizard-gtk is not available\n" #~ msgstr "wizard-gtk ist nicht verfügbar\n" #~ msgid "gconfig is not available\n" #~ msgstr "gconfig ist nicht verfügbar\n" #~ msgid "" #~ "Indexing file `%s' failed. Check file permissions and consult your GNUnet " #~ "server's logs.\n" #~ msgstr "" #~ "Indizierung der Datei `%s' schlug fehl. Bitte prüfen Sie die " #~ "Dateiberechtigungen und ziehen Sie die Protokolldateien des GNUnet-" #~ "Servers zu Rate.\n" #~ msgid "Show _debug info" #~ msgstr "_Debug Informationen anzeigen" #~ msgid "" #~ "USAGE: gnunet-setup MODULE\n" #~ "\n" #~ "MODULE\n" #~ " recreate\trecreate configuration files\n" #~ " config\t\ttext-based configuration\n" #~ " menuconfig\ttext-based menu\n" #~ " gconfig\tGTK configuration\n" #~ " wizard-curses\tBasic text-based graphical configuration\n" #~ " wizard-gtk\tBasic GTK configuration\n" #~ "\n" #~ msgstr "" #~ "Verwendung: gnunet-setup MODUL\n" #~ "\n" #~ "MODUL\n" #~ " recreate\tKonfigurationsdateien neu erzeugen\n" #~ " config\t\tText-basierte Konfiguration\n" #~ " menuconfig\tText-basiertes Menü\n" #~ " gconfig\tGTK Konfiguration\n" #~ " wizard-curses\tEinfache text-basierte grafische Konfiguration\n" #~ " wizard-gtk\tEinfache GTK Konfiguration\n" #~ "\n" #~ msgid "Please specify a path where the configuration files will be stored." #~ msgstr "" #~ "Bitte geben Sie den Pfad an, wohin die Konfigurationsdateien gespeichert " #~ "werden." #~ msgid "Session with peer `%s' confirmed, but I cannot connect! (bug?)\n" #~ msgstr "" #~ "Sitzung mit Knoten `%s' ist bestätigt es kann jedoch nicht verbunden " #~ "werden! (Bug?)\n" #~ msgid "LOGLEVEL not specified, that is not ok.\n" #~ msgstr "LOGLEVEL wurde nicht angegeben, das ist nicht in Ordnung.\n" #~ msgid "" #~ "Interfaces string (%s) in configuration section `%s' under `%s' is " #~ "malformed.\n" #~ msgstr "" #~ "Geräteangabe (%s) in der Konfigurationssektion `%s' unter `%s' ist " #~ "beschädigt.\n" #~ msgid "" #~ "No network interfaces specified in the configuration file in section `%s' " #~ "under `%s'.\n" #~ msgstr "" #~ "Es sind keine Netzwerkgeräte in der Konfigurationsdatei in der Sektion " #~ "'%s' unter `%s' definiert.\n" #~ msgid "Failed to parse interface data `%s' output at %s:%d.\n" #~ msgstr "Fehler beim Parsen der Gerätedaten `%s' Ausgabe bei %s:%d.\n" #~ msgid "Could not decoding file `%s' at %s:%d.\n" #~ msgstr "Datei `%s' konnte nicht dekodiert werden bei %s:%d.\n" #~ msgid "" #~ "Configuration file must specify directory for network identities in " #~ "section %s under %s.\n" #~ msgstr "" #~ "Die Konfigurationsdatei muss in Sektion %s unter %s ein Verzeichnis für " #~ "Identitäten angeben.\n" #~ msgid "Sender %u.%u.%u.%u is blacklisted, dropping message.\n" #~ msgstr "" #~ "Sender %u.%u.%u.%u steht auf schwarzer Liste, Nachricht wird ignoriert.\n" #~ msgid "Sender %s is blacklisted, dropping message.\n" #~ msgstr "Sender %s steht auf schwarzer Liste, Nachricht wird ignoriert.\n" #~ msgid "Removed file `%s' containing invalid peer advertisement.\n" #~ msgstr "" #~ "Datei `%s' enthielt eine ungültige Knotenbekanntmachung und wurde " #~ "entfernt.\n" #~ msgid "Removed invalid HELO file `%s'\n" #~ msgstr "Ungültige HELO Datei `%s' wurde entfernt.\n" #~ msgid "Could not determine IP address of the local machine!\n" #~ msgstr "IP-Adresse der lokalen Maschiene konnte nicht ermittelt werden!\n" #~ msgid "Could not determine IP(v6) address of the local machine!\n" #~ msgstr "" #~ "IP(v6)-Adresse der lokalen Maschiene konnte nicht ermittelt werden!\n" #~ msgid "" #~ "Could not find IP(v6) for this host. Please provide the IP in the " #~ "configuration file.\n" #~ msgstr "" #~ "IP(v6) dieses Hosts konnte nicht ermittelt werden. Bitte geben Sie die IP " #~ "in der Konfigurationsdatei an.\n" #~ msgid "Save _as" #~ msgstr "Speichern _unter" #~ msgid "Save the config in a file" #~ msgstr "Die Konfiguration in einer Datei speichern" #~ msgid "Error: can't open Service Control Manager: %s (%i)\n" #~ msgstr "Fehler: der Dienstemanager konnte nicht geöffnet werden: %s (%i)\n" #~ msgid "Error: can't create service: %s (#%i)\n" #~ msgstr "Fehler: Dienst konnte nicht erzeugt werden: %s (#%i)\n" gnunet-0.9.3/po/stamp-po0000644000175000017500000000001211763406752012051 00000000000000timestamp gnunet-0.9.3/po/remove-potcdate.sin0000644000175000017500000000066011260753602014177 00000000000000# Sed script that remove the POT-Creation-Date line in the header entry # from a POT file. # # The distinction between the first and the following occurrences of the # pattern is achieved by looking at the hold space. /^"POT-Creation-Date: .*"$/{ x # Test if the hold space is empty. s/P/P/ ta # Yes it was empty. First occurrence. Remove the line. g d bb :a # The hold space was nonempty. Following occurrences. Do nothing. x :b } gnunet-0.9.3/po/de.gmo0000644000175000017500000001514111763406752011473 00000000000000Þ•<üSÜ()/ASl„š´Î-è%4-Z.ˆ ·&ØÿK?%‹#±ÕÛ&áGPa/f–;³7ï' 0? )p /š 1Ê !ü  +& :R $ k²  ^ ' § A© ë í Nð F? † Mˆ +Ö ) 7, ^d #à ç –­Äàÿ1Nk+ˆ´*Ô+ÿ,+"X+{§ÅZã9>4x­³-º`èI]=b! CÂ9#@4d-™7Ç<ÿ8<u@}5¾-ô•"¸{º-6dKf²´o·\'„Y†=à1NP~Ÿ"A1-+/ *(.9284,!3$ ':7&0< 6"5# );% days# bytes decrypted# bytes encrypted# bytes received via TCP# messages defragmented# messages fragmented%s failed at %s:%d: `%s' %s: illegal option -- %c %s: invalid option -- %c %s: option `%c%s' does not allow an argument %s: option `%s' is ambiguous %s: option `%s' requires an argument %s: option `--%s' does not allow an argument %s: option `-W %s' does not allow an argument %s: option `-W %s' is ambiguous %s: option requires an argument -- %c %s: unrecognized option `%c%s' %s: unrecognized option `--%s' Arguments mandatory for long options are also mandatory for short options. Cannot change user/group to `%s': %s Could not find IP of host `%s': %s DEBUGERRORFailed to read friends list from `%s' File `%s' in directory `%s' does not match naming convention. Removed. I am peer `%s'. INFOInitialization of plugin mechanism failed: %s! Invalid format for IP: `%s' Invalid network notation ('/%d' is not legal in IPv4 CIDR).Invalid network notation (does not end with ';': `%s') No keywords specified! Option `%s' makes no sense without option `%s'. Print statistics about GNUnet operations.RSA signature verification failed at %s:%d: %s Trying to use file `%s' for MySQL configuration. Unable to initialize SQLite: %s. WARNINGYou must pass a number to the `%s' option. You must specify one and only one filename for insertion. `%s' failed at %s:%d with error: %s add an additional keyword for the top-level file or directory (this option can be specified multiple times)bdo not index, perform full insertion (stores entire file in encrypted form in GNUnet database)download a GNUnet directory recursivelyhlibgcrypt has not the expected version (version %s is required). mmsprint list of extracted keywords that would be used, but do not perform uploadpublish the files under the pseudonym NAME (place file into namespace)sset the ID of this version of the publication (for namespace insertions only)set the desired LEVEL of receiver-anonymityset the desired LEVEL of sender-anonymityset the meta-data for the given TYPE to the given VALUEspecify ID of an updated version to be published in the future (for namespace insertions only)specify the priority of the contentwrite the file to FILENAMEProject-Id-Version: GNUnet 0.7.0b Report-Msgid-Bugs-To: gnunet-developers@mail.gnu.org POT-Creation-Date: 2012-06-05 15:47+0200 PO-Revision-Date: 2006-03-17 21:37+0100 Last-Translator: Nils Durner Language-Team: German Language: de MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n != 1); Tage# Bytes entschlüsselt# Bytes verschlüsselt# Bytes empfangen über TCP# defragmentierter Nachrichten# fragmentierter Nachrichten`%s' schlug fehl bei %s:%d mit dem Fehler: `%s'. %s: unerlaubte Option -- %c %s: ungültige Option -- %c %s: Option '%c%s' erlaubt keinen Parameter %s: Option `%s' ist mehrdeutig %s: Option `%s' benötigt einen Parameter %s: Option '--%s' erlaubt keinen Parameter %s: Option '-W %s' erlaubt keinen Parameter %s: Option '-W %s' ist mehrdeutig %s: Option benötigt einen Parameter -- %c %s: unbekannte Option '%c%s' %s: unbekannte Option '--%s' Parameter, die für lange Optionen zwingend sind, sind auch für kurze Optionen zwingend. Benutzer/Gruppe kann nicht zu `%s' gewechselt werden: %s IP des Hosts `%s' konnte nicht ermittelt werden: %s DEBUGFEHLERFehler beim Lesen der Freunde-Liste von `%s' Die Datei `%s' im Verzeichnis `%s' entspricht nicht der Namenskonvention. Datei wurde entfernt. Ich bin Peer `%s'. INFOInitialisierung des Plugin Mechanismuses fehlgeschlagen: %s! Ungültiges Format für IP: `%s' Ungültige Netzwerk Notation ('/%d ist nicht gültig in IPv4 CIDR).Ungültige Netzwerk Notation (endet nicht mit ';': `%s') Keine Schlüsselwörter angegeben! Option `%s' macht keinen Sinn ohne die Option `%s'. Statistiken der GNUnet Aktivitäten ausgeben.RSA Signaturüberprüfung fehlgeschlagen bei %s:%d: %s Versuche, Datei `%s' für MySQL Konfiguration zu verwenden. SQLite Datenbank konnte nicht initialisiert werden: %s. WARNUNGSie müssen für die Option `%s' zusätzlich eine Zahl angeben. Sie dürfen nur eine Datei zum Deindizieren angeben. `%s' schlug bei %s:%d mit dem Fehler %s fehl Ein zusätzliches Schlüsselwort für die Datei oder das Verzeichnis auf der obersten Ebene hinzufügen (diese Option kann mehrmals angegeben werden)bNicht indizieren, sondern komplett einfügen (speichert die gesamte Datei in verschlüsselter Form in der GNUnet Datenbank)Das GNUnet Verzeichnis rekursiv herunterladenhlibgcrypt hat nicht die erwartete Version (Version %s wird vorausgesetzt). mmsListe der extrahierten Schlüsselworte, die verwendet werden würden, ausgeben, aber keinen Upload durchführenDie Datei unter dem Pseudonym NAME veröffentlichen (platziert die Datei in einem Namespace)sdie ID dieser Version der Veröffentlichung setzen (nur für das Einfügen in Namespaces)Den Grad LEVEL der gewünschten Empfänger-Anonymität setzenGewünschten Grad an Sender-Anonymität festlegenDie Meta-Daten des angegebenen Typs TYPE auf den angegebenen Wert VALUE setzenID einer aktualisierten Version angeben, die in der Zukunft veröffentlich werden soll. (nur für das Einfügen in Namespaces)Die Priorität des Inhalts angebenSchreibe die Datei in DATEINAMEgnunet-0.9.3/po/Makevars0000644000175000017500000000344111260753602012062 00000000000000# Makefile variables for PO directory in any package using GNU gettext. # Usually the message domain is the same as the package name. DOMAIN = $(PACKAGE) # These two variables depend on the location of this directory. subdir = po top_builddir = .. # These options get passed to xgettext. XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ # This is the copyright holder that gets inserted into the header of the # $(DOMAIN).pot file. Set this to the copyright holder of the surrounding # package. (Note that the msgstr strings, extracted from the package's # sources, belong to the copyright holder of the package.) Translators are # expected to transfer the copyright for their translations to this person # or entity, or to disclaim their copyright. The empty string stands for # the public domain; in this case the translators are expected to disclaim # their copyright. COPYRIGHT_HOLDER = Christian Grothoff # This is the email address or URL to which the translators shall report # bugs in the untranslated strings: # - Strings which are not entire sentences, see the maintainer guidelines # in the GNU gettext documentation, section 'Preparing Strings'. # - Strings which use unclear terms or require additional context to be # understood. # - Strings which make invalid assumptions about notation of date, time or # money. # - Pluralisation problems. # - Incorrect English spelling. # - Incorrect formatting. # It can be your email address, or a mailing list address where translators # can write to without being subscribed, or the URL of a web page through # which the translators can contact you. MSGID_BUGS_ADDRESS = gnunet-developers@mail.gnu.org # This is the list of locale categories, beyond LC_MESSAGES, for which the # message catalogs shall be used. It is usually empty. EXTRA_LOCALE_CATEGORIES = gnunet-0.9.3/po/ChangeLog0000644000175000017500000000110011260753602012126 000000000000002007-02-08 gettextize * Makefile.in.in: Upgrade to gettext-0.16.1. * Rules-quot: Upgrade to gettext-0.16.1. 2004-08-21 gettextize * Makefile.in.in: New file, from gettext-0.14. * boldquot.sed: New file, from gettext-0.14. * en@boldquot.header: New file, from gettext-0.14. * en@quot.header: New file, from gettext-0.14. * insert-header.sin: New file, from gettext-0.14. * quot.sed: New file, from gettext-0.14. * remove-potcdate.sin: New file, from gettext-0.14. * Rules-quot: New file, from gettext-0.14. gnunet-0.9.3/po/zh_CN.po0000644000175000017500000052246711763406752011756 00000000000000# Chinese simplified translation for GNUnet. # Copyright (C) 2011 Christian Grothoff # This file is distributed under the same license as the GNUnet package. # Wylmer Wang , 2011. # msgid "" msgstr "" "Project-Id-Version: gnunet-0.8.1\n" "Report-Msgid-Bugs-To: gnunet-developers@mail.gnu.org\n" "POT-Creation-Date: 2012-06-05 15:47+0200\n" "PO-Revision-Date: 2011-07-09 12:12+0800\n" "Last-Translator: Wylmer Wang \n" "Language-Team: Chinese (simplified) \n" "Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/arm/arm_api.c:165 msgid "Failed to transmit shutdown request to client.\n" msgstr "" #: src/arm/arm_api.c:349 #, fuzzy, c-format msgid "Configuration failes to specify option `%s' in section `%s'!\n" msgstr "é…ç½®ä¸æ»¡è¶³é…置规范文件“%sâ€çš„约æŸï¼\n" #: src/arm/arm_api.c:363 #, fuzzy, c-format msgid "Configuration fails to specify option `%s' in section `%s'!\n" msgstr "é…ç½®ä¸æ»¡è¶³é…置规范文件“%sâ€çš„约æŸï¼\n" #: src/arm/arm_api.c:432 #, c-format msgid "Error receiving response to `%s' request from ARM for service `%s'\n" msgstr "" #: src/arm/arm_api.c:485 #, c-format msgid "Requesting start of service `%s'.\n" msgstr "" #: src/arm/arm_api.c:486 #, c-format msgid "Requesting termination of service `%s'.\n" msgstr "" #: src/arm/arm_api.c:507 #, c-format msgid "Error while trying to transmit request to start `%s' to ARM\n" msgstr "" #: src/arm/arm_api.c:508 #, c-format msgid "Error while trying to transmit request to stop `%s' to ARM\n" msgstr "" #: src/arm/arm_api.c:540 #, c-format msgid "Asked to start service `%s' within %llu ms\n" msgstr "" #: src/arm/arm_api.c:612 #, c-format msgid "Stopping service `%s' within %llu ms\n" msgstr "" #: src/arm/gnunet-arm.c:159 #, fuzzy, c-format msgid "Service `%s' is unknown to ARM.\n" msgstr "æœåŠ¡å·²åˆ é™¤ã€‚\n" #: src/arm/gnunet-arm.c:164 #, fuzzy, c-format msgid "Service `%s' has been stopped.\n" msgstr "æœåŠ¡å·²åˆ é™¤ã€‚\n" #: src/arm/gnunet-arm.c:167 #, fuzzy, c-format msgid "Service `%s' was already running.\n" msgstr "æœåŠ¡å·²åˆ é™¤ã€‚\n" #: src/arm/gnunet-arm.c:172 #, fuzzy, c-format msgid "Service `%s' has been started.\n" msgstr "æœåŠ¡å·²åˆ é™¤ã€‚\n" #: src/arm/gnunet-arm.c:175 #, fuzzy, c-format msgid "Service `%s' was already being stopped.\n" msgstr "æœåŠ¡å·²åˆ é™¤ã€‚\n" #: src/arm/gnunet-arm.c:179 #, fuzzy, c-format msgid "Service `%s' was already not running.\n" msgstr "æœåŠ¡å·²åˆ é™¤ã€‚\n" #: src/arm/gnunet-arm.c:183 msgid "Request ignored as ARM is shutting down.\n" msgstr "" #: src/arm/gnunet-arm.c:187 msgid "Error communicating with ARM service.\n" msgstr "" #: src/arm/gnunet-arm.c:191 msgid "Timeout communicating with ARM service.\n" msgstr "" #: src/arm/gnunet-arm.c:195 msgid "Operation failed.\n" msgstr "" #: src/arm/gnunet-arm.c:199 msgid "Unknown response code from ARM.\n" msgstr "" #: src/arm/gnunet-arm.c:222 #, fuzzy msgid "Error communicating with ARM. ARM not running?\n" msgstr "连接 %s:%u 出错。守护程åºåœ¨è¿è¡Œå—?\n" #: src/arm/gnunet-arm.c:225 msgid "Running services:\n" msgstr "" #: src/arm/gnunet-arm.c:249 #, c-format msgid "Fatal configuration error: `%s' option in section `%s' missing.\n" msgstr "" #: src/arm/gnunet-arm.c:257 src/arm/gnunet-arm.c:357 src/arm/gnunet-arm.c:373 msgid "Fatal error initializing ARM API.\n" msgstr "" #: src/arm/gnunet-arm.c:280 #, fuzzy, c-format msgid "Failed to remove configuration file %s\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/arm/gnunet-arm.c:286 #, c-format msgid "Failed to remove servicehome directory %s\n" msgstr "" #: src/arm/gnunet-arm.c:407 #, fuzzy msgid "stop all GNUnet services" msgstr "å¸è½½ GNUnet æœåŠ¡" #: src/arm/gnunet-arm.c:409 msgid "start a particular service" msgstr "" #: src/arm/gnunet-arm.c:411 msgid "stop a particular service" msgstr "" #: src/arm/gnunet-arm.c:413 #, fuzzy msgid "start all GNUnet default services" msgstr "å¸è½½ GNUnet æœåŠ¡" #: src/arm/gnunet-arm.c:416 #, fuzzy msgid "stop and start all GNUnet default services" msgstr "å¸è½½ GNUnet æœåŠ¡" #: src/arm/gnunet-arm.c:419 msgid "delete config file and directory on exit" msgstr "" #: src/arm/gnunet-arm.c:421 msgid "don't print status messages" msgstr "" #: src/arm/gnunet-arm.c:424 #, fuzzy msgid "timeout for completing current operation" msgstr "等待一次迭代完æˆçš„æ—¶é—´(毫秒)" #: src/arm/gnunet-arm.c:426 msgid "List currently running services" msgstr "" #: src/arm/gnunet-arm.c:437 msgid "Control services and the Automated Restart Manager (ARM)" msgstr "" #: src/arm/gnunet-service-arm.c:332 #, fuzzy, c-format msgid "Failed to start service `%s'\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/arm/gnunet-service-arm.c:335 #, c-format msgid "Starting service `%s'\n" msgstr "" #: src/arm/gnunet-service-arm.c:361 msgid "Could not send status result to client\n" msgstr "" #: src/arm/gnunet-service-arm.c:393 #, fuzzy msgid "Could not send list result to client\n" msgstr "找ä¸åˆ°æŽ¥å£â€œ%sâ€çš„一个 IP 地å€ã€‚\n" #: src/arm/gnunet-service-arm.c:523 #, fuzzy, c-format msgid "Unable to create socket for service `%s': %s\n" msgstr "无法创建用户账户:" #: src/arm/gnunet-service-arm.c:545 #, c-format msgid "Unable to bind listening socket for service `%s' to address `%s': %s\n" msgstr "" #: src/arm/gnunet-service-arm.c:559 #, c-format msgid "ARM now monitors connections to service `%s' at `%s'\n" msgstr "" #: src/arm/gnunet-service-arm.c:667 #, c-format msgid "Preparing to stop `%s'\n" msgstr "" #: src/arm/gnunet-service-arm.c:878 #, c-format msgid "Restarting service `%s'.\n" msgstr "" #: src/arm/gnunet-service-arm.c:970 msgid "exit" msgstr "" #: src/arm/gnunet-service-arm.c:975 msgid "signal" msgstr "" #: src/arm/gnunet-service-arm.c:980 #, fuzzy msgid "unknown" msgstr "未知错误" #: src/arm/gnunet-service-arm.c:986 #, fuzzy, c-format msgid "Service `%s' took %llu ms to terminate\n" msgstr "æœåŠ¡å·²åˆ é™¤ã€‚\n" #: src/arm/gnunet-service-arm.c:1021 #, c-format msgid "Service `%s' terminated with status %s/%d, will restart in %llu ms\n" msgstr "" #: src/arm/gnunet-service-arm.c:1127 #, fuzzy, c-format msgid "Configuration file `%s' for service `%s' not valid: %s\n" msgstr "é…置文件“%sâ€å·²å†™å…¥ã€‚\n" #: src/arm/gnunet-service-arm.c:1129 msgid "option missing" msgstr "" #: src/arm/gnunet-service-arm.c:1213 #, fuzzy, c-format msgid "Starting default services `%s'\n" msgstr "å¸è½½ GNUnet æœåŠ¡" #: src/arm/gnunet-service-arm.c:1224 #, c-format msgid "Default service `%s' not configured correctly!\n" msgstr "" #: src/arm/gnunet-service-arm.c:1238 msgid "" "No default services configured, GNUnet will not really start right now.\n" msgstr "" #: src/arm/mockup-service.c:44 msgid "Initiating shutdown as requested by client.\n" msgstr "" #: src/block/block.c:105 #, fuzzy, c-format msgid "Loading block plugin `%s'\n" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/chat/chat.c:175 msgid "Could not transmit confirmation receipt\n" msgstr "" #: src/chat/chat.c:283 msgid "The current user must be the the first one joined\n" msgstr "" #: src/chat/chat.c:412 #, fuzzy, c-format msgid "Unknown message type: '%u'\n" msgstr "未知æ“作“%sâ€ã€‚\n" #: src/chat/chat.c:472 #, fuzzy, c-format msgid "Configuration option `%s' in section `%s' missing\n" msgstr "é…置文件“%sâ€å·²å†™å…¥ã€‚\n" #: src/chat/chat.c:480 #, fuzzy, c-format msgid "Failed to access chat home directory `%s'\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/chat/chat.c:498 #, fuzzy, c-format msgid "Failed to create/open key in file `%s'\n" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/chat/chat.c:559 msgid "Could not serialize metadata\n" msgstr "" #: src/chat/chat.c:674 #, fuzzy msgid "Failed to connect to the chat service\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/chat/chat.c:680 msgid "Undefined mandatory parameter: joinCallback\n" msgstr "" #: src/chat/chat.c:686 msgid "Undefined mandatory parameter: messageCallback\n" msgstr "" #: src/chat/chat.c:692 msgid "Undefined mandatory parameter: memberCallback\n" msgstr "" #: src/chat/gnunet-chat.c:93 msgid "Joined\n" msgstr "" #: src/chat/gnunet-chat.c:125 src/chat/gnunet-chat.c:133 #: src/chat/gnunet-chat.c:213 src/chat/gnunet-chat.c:253 #: src/chat/gnunet-chat.c:329 src/chat/gnunet-chat.c:371 #: src/chat/gnunet-chat.c:400 src/chat/gnunet-chat.c:700 msgid "anonymous" msgstr "匿å" #: src/chat/gnunet-chat.c:144 #, fuzzy, c-format msgid "(%s) `%s' said: %s\n" msgstr "“%sâ€è¯´ï¼š%s\n" #: src/chat/gnunet-chat.c:147 src/chat/gnunet-chat.c:150 #, fuzzy, c-format msgid "(%s) `%s' said to you: %s\n" msgstr "“%sâ€å¯¹æ‚¨è¯´ï¼š%s\n" #: src/chat/gnunet-chat.c:153 #, fuzzy, c-format msgid "(%s) `%s' said for sure: %s\n" msgstr "“%sâ€å¯¹æ‚¨è¯´ï¼š%s\n" #: src/chat/gnunet-chat.c:156 #, fuzzy, c-format msgid "(%s) `%s' said to you for sure: %s\n" msgstr "“%sâ€å¯¹æ‚¨è¯´ï¼š%s\n" #: src/chat/gnunet-chat.c:159 #, c-format msgid "(%s) `%s' was confirmed that you received: %s\n" msgstr "" #: src/chat/gnunet-chat.c:162 #, c-format msgid "(%s) `%s' was confirmed that you and only you received: %s\n" msgstr "" #: src/chat/gnunet-chat.c:165 #, c-format msgid "(%s) `%s' was confirmed that you received from him or her: %s\n" msgstr "" #: src/chat/gnunet-chat.c:170 #, c-format msgid "" "(%s) `%s' was confirmed that you and only you received from him or her: %s\n" msgstr "" #: src/chat/gnunet-chat.c:173 #, fuzzy, c-format msgid "(%s) `%s' said off the record: %s\n" msgstr "“%sâ€å¯¹æ‚¨è¯´ï¼š%s\n" #: src/chat/gnunet-chat.c:176 #, c-format msgid "(%s) <%s> said using an unknown message type: %s\n" msgstr "" #: src/chat/gnunet-chat.c:217 #, c-format msgid "'%s' acknowledged message #%d\n" msgstr "" #: src/chat/gnunet-chat.c:260 #, c-format msgid "`%s' entered the room\n" msgstr "“%sâ€è¿›å…¥äº†æˆ¿é—´\n" #: src/chat/gnunet-chat.c:260 #, c-format msgid "`%s' left the room\n" msgstr "“%sâ€ç¦»å¼€äº†æˆ¿é—´\n" #: src/chat/gnunet-chat.c:321 src/chat/gnunet-chat.c:363 #, fuzzy msgid "Could not change username\n" msgstr "å·²å°†ç”¨æˆ·åæ”¹ä¸ºâ€œ%sâ€ã€‚\n" #: src/chat/gnunet-chat.c:334 src/chat/gnunet-chat.c:702 #, c-format msgid "Joining room `%s' as user `%s'...\n" msgstr "" #: src/chat/gnunet-chat.c:373 #, fuzzy, c-format msgid "Changed username to `%s'\n" msgstr "å·²å°†ç”¨æˆ·åæ”¹ä¸ºâ€œ%sâ€ã€‚\n" #: src/chat/gnunet-chat.c:388 #, c-format msgid "Users in room `%s': " msgstr "房间“%sâ€ä¸­çš„用户:" #: src/chat/gnunet-chat.c:434 msgid "Syntax: /msg USERNAME MESSAGE" msgstr "语法:/msg ç”¨æˆ·å æ¶ˆæ¯" #: src/chat/gnunet-chat.c:443 #, c-format msgid "Unknown user `%s'. Make sure you specify its numeric suffix, if any.\n" msgstr "" #: src/chat/gnunet-chat.c:460 #, c-format msgid "User `%s' is currently not in the room!\n" msgstr "用户“%sâ€å½“å‰ä¸åœ¨æˆ¿é—´é‡Œï¼\n" #: src/chat/gnunet-chat.c:513 #, fuzzy, c-format msgid "Unknown command `%s'\n" msgstr "未知的命令“%sâ€ã€‚\n" #: src/chat/gnunet-chat.c:524 msgid "" "Use `/join #roomname' to join a chat room. Joining a room will cause you to " "leave the current room" msgstr "" #: src/chat/gnunet-chat.c:528 msgid "" "Use `/nick nickname' to change your nickname. This will cause you to leave " "the current room and immediately rejoin it with the new name." msgstr "" #: src/chat/gnunet-chat.c:532 msgid "" "Use `/msg nickname message' to send a private message to the specified user" msgstr "" #: src/chat/gnunet-chat.c:535 msgid "The `/notice' command is an alias for `/msg'" msgstr "" #: src/chat/gnunet-chat.c:537 msgid "The `/query' command is an alias for `/msg'" msgstr "" #: src/chat/gnunet-chat.c:539 msgid "Use `/sig message' to send a signed public message" msgstr "" #: src/chat/gnunet-chat.c:542 msgid "Use `/ack message' to require signed acknowledgment of the message" msgstr "" #: src/chat/gnunet-chat.c:545 msgid "Use `/anonymous message' to send a public anonymous message" msgstr "" #: src/chat/gnunet-chat.c:547 msgid "The `/anon' command is an alias for `/anonymous'" msgstr "" #: src/chat/gnunet-chat.c:549 msgid "Use `/quit' to terminate gnunet-chat" msgstr "" #: src/chat/gnunet-chat.c:551 msgid "The `/leave' command is an alias for `/quit'" msgstr "" #: src/chat/gnunet-chat.c:554 msgid "Use `/names' to list all of the current members in the chat room" msgstr "" #: src/chat/gnunet-chat.c:556 msgid "Use `/help command' to get help for a specific command" msgstr "" #: src/chat/gnunet-chat.c:672 msgid "You must specify a nickname\n" msgstr "您必须指定一个昵称\n" #: src/chat/gnunet-chat.c:688 #, c-format msgid "Failed to join room `%s'\n" msgstr "" #: src/chat/gnunet-chat.c:727 msgid "set the nickname to use (required)" msgstr "设置è¦ä½¿ç”¨çš„æ˜µç§°(å¿…é¡»)" #: src/chat/gnunet-chat.c:730 msgid "set the chat room to join" msgstr "设置è¦åŠ å…¥çš„èŠå¤©å®¤" #: src/chat/gnunet-chat.c:742 msgid "Join a chat on GNUnet." msgstr "" #: src/chat/gnunet-service-chat.c:267 #, fuzzy msgid "Failed to queue a message notification\n" msgstr "ä¿å­˜é…置失败。" #: src/chat/gnunet-service-chat.c:546 #, fuzzy msgid "Failed to queue a join notification\n" msgstr "ä¿å­˜é…置失败。" #: src/chat/gnunet-service-chat.c:729 #, fuzzy msgid "Failed to queue a confirmation receipt\n" msgstr "ä¿å­˜é…置失败。" #: src/chat/gnunet-service-chat.c:907 #, fuzzy msgid "Failed to queue a leave notification\n" msgstr "ä¿å­˜é…置失败。" #: src/core/core_api.c:786 msgid "Client was disconnected from core service, trying to reconnect.\n" msgstr "" #: src/core/gnunet-core.c:54 src/peerinfo-tool/gnunet-peerinfo.c:286 #, c-format msgid "Peer `%s'\n" msgstr "" #: src/core/gnunet-core.c:72 src/peerinfo-tool/gnunet-peerinfo.c:817 #, fuzzy, c-format msgid "Invalid command line argument `%s'\n" msgstr "“%sâ€çš„傿•°æ— æ•ˆã€‚\n" #: src/core/gnunet-core.c:95 msgid "Print information about connected peers." msgstr "" #: src/core/gnunet-service-core.c:97 #, c-format msgid "Core service of `%4s' ready.\n" msgstr "" #: src/core/gnunet-service-core_clients.c:370 msgid "# send requests dropped (disconnected)" msgstr "" #: src/core/gnunet-service-core_clients.c:475 msgid "# messages discarded (session disconnected)" msgstr "" #: src/core/gnunet-service-core_clients.c:818 #, c-format msgid "# bytes of messages of type %u received" msgstr "" #: src/core/gnunet-service-core_kx.c:565 msgid "# bytes encrypted" msgstr "" #: src/core/gnunet-service-core_kx.c:617 msgid "# bytes decrypted" msgstr "" #: src/core/gnunet-service-core_kx.c:681 src/dv/gnunet-service-dv.c:3003 msgid "Error in communication with PEERINFO service\n" msgstr "" #: src/core/gnunet-service-core_kx.c:700 msgid "# Delayed connecting due to lack of public key" msgstr "" #: src/core/gnunet-service-core_kx.c:753 msgid "# key exchanges initiated" msgstr "" #: src/core/gnunet-service-core_kx.c:775 msgid "# key exchanges stopped" msgstr "" #: src/core/gnunet-service-core_kx.c:828 msgid "# session keys received" msgstr "" #: src/core/gnunet-service-core_kx.c:845 #, c-format msgid "`%s' is for `%s', not for me. Ignoring.\n" msgstr "" #: src/core/gnunet-service-core_kx.c:890 msgid "# SET_KEY messages decrypted" msgstr "" #: src/core/gnunet-service-core_kx.c:977 #: src/transport/gnunet-service-transport_validation.c:810 msgid "# PING messages received" msgstr "" #: src/core/gnunet-service-core_kx.c:1010 #, c-format msgid "" "Received PING from `%s' for different identity: I am `%s', PONG identity: `" "%s'\n" msgstr "" #: src/core/gnunet-service-core_kx.c:1029 msgid "# PONG messages created" msgstr "" #: src/core/gnunet-service-core_kx.c:1125 msgid "# sessions terminated by timeout" msgstr "" #: src/core/gnunet-service-core_kx.c:1135 msgid "# keepalive messages sent" msgstr "" #: src/core/gnunet-service-core_kx.c:1236 #: src/transport/gnunet-service-transport_validation.c:1031 msgid "# PONG messages received" msgstr "" #: src/core/gnunet-service-core_kx.c:1275 msgid "# PONG messages decrypted" msgstr "" #: src/core/gnunet-service-core_kx.c:1303 msgid "# session keys confirmed via PONG" msgstr "" #: src/core/gnunet-service-core_kx.c:1329 msgid "# rekey operations confirmed via PONG" msgstr "" #: src/core/gnunet-service-core_kx.c:1381 #: src/core/gnunet-service-core_kx.c:1398 msgid "# SET_KEY and PING messages created" msgstr "" #: src/core/gnunet-service-core_kx.c:1402 msgid "# REKEY operations performed" msgstr "" #: src/core/gnunet-service-core_kx.c:1537 msgid "# failed to decrypt message (no session key)" msgstr "" #: src/core/gnunet-service-core_kx.c:1577 #: src/core/gnunet-service-core_kx.c:1602 msgid "# bytes dropped (duplicates)" msgstr "" #: src/core/gnunet-service-core_kx.c:1589 msgid "# bytes dropped (out of sequence)" msgstr "" #: src/core/gnunet-service-core_kx.c:1626 #, c-format msgid "Message received far too old (%llu ms). Content ignored.\n" msgstr "" #: src/core/gnunet-service-core_kx.c:1630 msgid "# bytes dropped (ancient message)" msgstr "" #: src/core/gnunet-service-core_kx.c:1638 msgid "# bytes of payload decrypted" msgstr "" #: src/core/gnunet-service-core_kx.c:1700 #, fuzzy msgid "Core service is lacking HOSTKEY configuration setting. Exiting.\n" msgstr "ç«‹å³ä¿å­˜é…置?" #: src/core/gnunet-service-core_kx.c:1708 msgid "Core service could not access hostkey. Exiting.\n" msgstr "" #: src/core/gnunet-service-core_kx.c:1718 src/hostlist/hostlist-server.c:551 #: src/peerinfo-tool/gnunet-peerinfo.c:823 #: src/transport/gnunet-service-transport.c:611 msgid "Could not access PEERINFO service. Exiting.\n" msgstr "" #: src/core/gnunet-service-core_neighbours.c:163 msgid "# sessions terminated by transport disconnect" msgstr "" #: src/core/gnunet-service-core_neighbours.c:180 #: src/core/gnunet-service-core_neighbours.c:334 msgid "# neighbour entries allocated" msgstr "" #: src/core/gnunet-service-core_neighbours.c:247 msgid "# encrypted bytes given to transport" msgstr "" #: src/core/gnunet-service-core_neighbours.c:418 #, c-format msgid "Unsupported message of type %u (%u bytes) received from peer `%s'\n" msgstr "" #: src/core/gnunet-service-core_sessions.c:206 #: src/core/gnunet-service-core_sessions.c:269 #: src/dht/gnunet-service-dht_neighbours.c:625 #: src/dht/gnunet-service-dht_neighbours.c:683 #: src/fs/gnunet-service-fs_cp.c:615 src/fs/gnunet-service-fs_cp.c:1532 #: src/topology/gnunet-daemon-topology.c:709 #: src/topology/gnunet-daemon-topology.c:810 #: src/transport/gnunet-service-transport_neighbours.c:874 #: src/transport/gnunet-service-transport_neighbours.c:1080 #: src/transport/gnunet-service-transport_neighbours.c:1089 #: src/transport/gnunet-service-transport_neighbours.c:2568 #: src/transport/gnunet-service-transport_neighbours.c:2814 msgid "# peers connected" msgstr "" #: src/core/gnunet-service-core_sessions.c:236 msgid "# type map refreshes sent" msgstr "" #: src/core/gnunet-service-core_sessions.c:406 msgid "# messages discarded (expired prior to transmission)" msgstr "" #: src/core/gnunet-service-core_typemap.c:110 #: src/core/gnunet-service-core_typemap.c:121 msgid "# type maps received" msgstr "" #: src/core/gnunet-service-core_typemap.c:151 msgid "# updates to my type map" msgstr "" #: src/datacache/datacache.c:115 src/datacache/datacache.c:250 #: src/datastore/gnunet-service-datastore.c:834 msgid "# bytes stored" msgstr "" #: src/datacache/datacache.c:141 src/datacache/datacache.c:148 #: src/datastore/gnunet-service-datastore.c:1483 #: src/datastore/gnunet-service-datastore.c:1494 #, c-format msgid "No `%s' specified for `%s' in configuration!\n" msgstr "" #: src/datacache/datacache.c:180 #, c-format msgid "Loading `%s' datacache plugin\n" msgstr "" #: src/datacache/datacache.c:188 #, c-format msgid "Failed to load datacache plugin for `%s'\n" msgstr "" #: src/datacache/datacache.c:276 msgid "# requests received" msgstr "" #: src/datacache/datacache.c:284 msgid "# requests filtered by bloom filter" msgstr "" #: src/datacache/plugin_datacache_mysql.c:97 #: src/datacache/plugin_datacache_mysql.c:104 #: src/datacache/plugin_datacache_sqlite.c:69 #: src/datacache/plugin_datacache_sqlite.c:72 #: src/datastore/plugin_datastore_mysql.c:803 #: src/datastore/plugin_datastore_mysql.c:817 #: src/datastore/plugin_datastore_sqlite.c:57 src/mysql/mysql.c:41 #: src/mysql/mysql.c:48 src/mysql/mysql.c:522 src/mysql/mysql.c:531 #: src/mysql/mysql.c:591 src/mysql/mysql.c:607 #: src/namestore/plugin_namestore_sqlite.c:51 src/util/crypto_ksk.c:49 #: src/util/crypto_rsa.c:67 src/include/gnunet_common.h:525 #: src/include/gnunet_common.h:532 #, fuzzy, c-format msgid "`%s' failed at %s:%d with error: %s\n" msgstr "“%sâ€äºŽ %s:%d 处失败,错误为:%s\n" #: src/datacache/plugin_datacache_mysql.c:450 msgid "MySQL datacache running\n" msgstr "" #: src/datacache/plugin_datacache_postgres.c:367 msgid "Postgres datacache running\n" msgstr "" #: src/datacache/plugin_datacache_sqlite.c:410 msgid "Sqlite datacache running\n" msgstr "" #: src/datacache/plugin_datacache_sqlite.c:443 #: src/datastore/plugin_datastore_sqlite.c:408 #: src/namestore/plugin_namestore_sqlite.c:370 msgid "Tried to close sqlite without finalizing all prepared statements.\n" msgstr "" #: src/datacache/plugin_datacache_sqlite.c:450 #, fuzzy, c-format msgid "Failed to close statement %p: %d\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/datacache/plugin_datacache_template.c:121 msgid "Template datacache running\n" msgstr "" #: src/datastore/datastore_api.c:305 msgid "Failed to transmit request to drop database.\n" msgstr "" #: src/datastore/datastore_api.c:388 msgid "# queue entry timeouts" msgstr "" #: src/datastore/datastore_api.c:432 msgid "# queue overflows" msgstr "" #: src/datastore/datastore_api.c:459 msgid "# queue entries created" msgstr "" #: src/datastore/datastore_api.c:477 msgid "# Requests dropped from datastore queue" msgstr "" #: src/datastore/datastore_api.c:525 msgid "# datastore connections (re)created" msgstr "" #: src/datastore/datastore_api.c:548 msgid "# reconnected to DATASTORE" msgstr "" #: src/datastore/datastore_api.c:612 msgid "# transmission request failures" msgstr "" #: src/datastore/datastore_api.c:633 msgid "# bytes sent to datastore" msgstr "" #: src/datastore/datastore_api.c:764 msgid "Failed to receive status response from database." msgstr "" #: src/datastore/datastore_api.c:778 msgid "Error reading response from datastore service" msgstr "" #: src/datastore/datastore_api.c:790 src/datastore/datastore_api.c:796 msgid "Invalid error message received from datastore service" msgstr "" #: src/datastore/datastore_api.c:800 msgid "# status messages received" msgstr "" #: src/datastore/datastore_api.c:869 msgid "# PUT requests executed" msgstr "" #: src/datastore/datastore_api.c:936 msgid "# RESERVE requests executed" msgstr "" #: src/datastore/datastore_api.c:997 msgid "# RELEASE RESERVE requests executed" msgstr "" #: src/datastore/datastore_api.c:1054 msgid "# UPDATE requests executed" msgstr "" #: src/datastore/datastore_api.c:1118 msgid "# REMOVE requests executed" msgstr "" #: src/datastore/datastore_api.c:1163 msgid "Failed to receive response from database.\n" msgstr "" #: src/datastore/datastore_api.c:1221 msgid "# Results received" msgstr "" #: src/datastore/datastore_api.c:1286 msgid "# GET REPLICATION requests executed" msgstr "" #: src/datastore/datastore_api.c:1349 msgid "# GET ZERO ANONYMITY requests executed" msgstr "" #: src/datastore/datastore_api.c:1409 msgid "# GET requests executed" msgstr "" #: src/datastore/gnunet-service-datastore.c:349 msgid "# bytes expired" msgstr "" #: src/datastore/gnunet-service-datastore.c:422 msgid "# bytes purged (low-priority)" msgstr "" #: src/datastore/gnunet-service-datastore.c:480 msgid "Transmission to client failed!\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:511 msgid "Shutdown in progress, aborting transmission.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:626 msgid "# results found" msgstr "" #: src/datastore/gnunet-service-datastore.c:669 #, c-format msgid "" "Insufficient space (%llu bytes are available) to satisfy `%s' request for " "%llu bytes\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:680 #, c-format msgid "" "The requested amount (%llu bytes) is larger than the cache size (%llu " "bytes)\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:684 msgid "" "Insufficient space to satisfy request and requested amount is larger than " "cache size" msgstr "" #: src/datastore/gnunet-service-datastore.c:690 msgid "Insufficient space to satisfy request" msgstr "" #: src/datastore/gnunet-service-datastore.c:695 #: src/datastore/gnunet-service-datastore.c:747 #: src/datastore/gnunet-service-datastore.c:960 #: src/datastore/gnunet-service-datastore.c:1417 msgid "# reserved" msgstr "" #: src/datastore/gnunet-service-datastore.c:760 msgid "Could not find matching reservation" msgstr "" #: src/datastore/gnunet-service-datastore.c:846 #, c-format msgid "Need %llu bytes more space (%llu allowed, using %llu)\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1006 msgid "# GET requests received" msgstr "" #: src/datastore/gnunet-service-datastore.c:1018 msgid "# requests filtered by bloomfilter" msgstr "" #: src/datastore/gnunet-service-datastore.c:1046 msgid "# UPDATE requests received" msgstr "" #: src/datastore/gnunet-service-datastore.c:1076 msgid "# GET REPLICATION requests received" msgstr "" #: src/datastore/gnunet-service-datastore.c:1109 msgid "# GET ZERO ANONYMITY requests received" msgstr "" #: src/datastore/gnunet-service-datastore.c:1134 msgid "Content not found" msgstr "" #: src/datastore/gnunet-service-datastore.c:1142 msgid "# bytes removed (explicit request)" msgstr "" #: src/datastore/gnunet-service-datastore.c:1174 msgid "# REMOVE requests received" msgstr "" #: src/datastore/gnunet-service-datastore.c:1216 #, c-format msgid "Datastore payload inaccurate (%lld < %lld). Trying to fix.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1277 #, c-format msgid "Loading `%s' datastore plugin\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1286 #, fuzzy, c-format msgid "Failed to load datastore plugin for `%s'\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/datastore/gnunet-service-datastore.c:1488 #, c-format msgid "# bytes used in file-sharing datastore `%s'" msgstr "" #: src/datastore/gnunet-service-datastore.c:1499 msgid "# quota" msgstr "" #: src/datastore/gnunet-service-datastore.c:1501 msgid "# cache size" msgstr "" #: src/datastore/gnunet-service-datastore.c:1514 #, c-format msgid "Could not use specified filename `%s' for bloomfilter.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1532 #: src/datastore/gnunet-service-datastore.c:1548 #, fuzzy, c-format msgid "Failed to remove bogus bloomfilter file `%s'\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/datastore/gnunet-service-datastore.c:1578 #, fuzzy msgid "Failed to initialize bloomfilter.\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/datastore/gnunet-service-datastore.c:1607 msgid "Rebuilding bloomfilter. Please be patient.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1612 msgid "Plugin does not support get_keys function. Please fix!\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1615 msgid "Bloomfilter construction complete.\n" msgstr "" #: src/datastore/plugin_datastore_mysql.c:780 #, fuzzy, c-format msgid "Failed to prepare statement `%s'\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/datastore/plugin_datastore_mysql.c:788 #, fuzzy, c-format msgid "`%s' for `%s' failed at %s:%d with error: %s\n" msgstr "“%sâ€äºŽ %s:%d 处失败,错误为:%s\n" #: src/datastore/plugin_datastore_mysql.c:1019 msgid "Mysql database running\n" msgstr "" #: src/datastore/plugin_datastore_postgres.c:824 #, fuzzy msgid "Failed to drop table from database.\n" msgstr "å‘逿¶ˆæ¯å¤±è´¥ã€‚\n" #: src/datastore/plugin_datastore_postgres.c:860 msgid "Postgres database running\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:57 #, fuzzy, c-format msgid "`%s' failed at %s:%u with error: %s" msgstr "“%sâ€äºŽ %s:%d 处失败,错误为:%s\n" #: src/datastore/plugin_datastore_sqlite.c:233 #: src/namestore/plugin_namestore_sqlite.c:204 #, c-format msgid "Option `%s' in section `%s' missing in configuration!\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:260 #: src/namestore/plugin_namestore_sqlite.c:229 #, c-format msgid "Unable to initialize SQLite: %s.\n" msgstr "无法åˆå§‹åŒ– SQLite:%s。\n" #: src/datastore/plugin_datastore_sqlite.c:655 #, fuzzy msgid "Invalid data in database. Trying to fix (by deletion).\n" msgstr "%s 中有无效数æ®ã€‚请å°è¯•ä¿®å¤(删除之)。\n" #: src/datastore/plugin_datastore_sqlite.c:1139 msgid "sqlite version to old to determine size, assuming zero\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:1158 #, c-format msgid "" "Using sqlite page utilization to estimate payload (%llu pages of size %llu " "bytes)\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:1198 #: src/namestore/plugin_namestore_sqlite.c:829 #, fuzzy msgid "Sqlite database running\n" msgstr "sqlite æ•°æ®ä»“库" #: src/datastore/plugin_datastore_template.c:241 msgid "Template database running\n" msgstr "" #: src/dht/dht_api.c:348 #, fuzzy msgid "Failed to connect to the DHT service!\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/dht/gnunet-dht-get.c:201 src/dht/gnunet-dht-monitor.c:293 #: src/dht/gnunet-dht-put.c:192 msgid "the query key" msgstr "" #: src/dht/gnunet-dht-get.c:204 msgid "how many parallel requests (replicas) to create" msgstr "" #: src/dht/gnunet-dht-get.c:207 src/dht/gnunet-dht-monitor.c:296 msgid "the type of data to look for" msgstr "" #: src/dht/gnunet-dht-get.c:210 src/dht/gnunet-dht-put.c:201 msgid "how long to execute this query before giving up?" msgstr "" #: src/dht/gnunet-dht-get.c:213 src/dht/gnunet-dht-monitor.c:302 #: src/dht/gnunet-dht-put.c:204 src/fs/gnunet-download.c:271 #: src/fs/gnunet-publish.c:731 src/fs/gnunet-search.c:297 #: src/fs/gnunet-unindex.c:169 src/nse/gnunet-nse-profiler.c:910 msgid "be verbose (print progress information)" msgstr "" #: src/dht/gnunet-dht-get.c:232 msgid "Issue a GET request to the GNUnet DHT, prints results." msgstr "" #: src/dht/gnunet-dht-monitor.c:299 msgid "how long to execute? 0 = forever" msgstr "" #: src/dht/gnunet-dht-monitor.c:321 msgid "Prints all packets that go through the DHT." msgstr "" #: src/dht/gnunet-dht-put.c:108 msgid "PUT request sent!\n" msgstr "" #: src/dht/gnunet-dht-put.c:111 msgid "Timeout sending PUT request!\n" msgstr "" #: src/dht/gnunet-dht-put.c:114 msgid "PUT request not confirmed!\n" msgstr "" #: src/dht/gnunet-dht-put.c:144 msgid "Must provide KEY and DATA for DHT put!\n" msgstr "" #: src/dht/gnunet-dht-put.c:152 #, fuzzy, c-format msgid "Could not connect to %s service!\n" msgstr "无法连接到 %s:%u:%s\n" #: src/dht/gnunet-dht-put.c:157 #, fuzzy, c-format msgid "Connected to %s service!\n" msgstr "“%sâ€å·²è¿žæŽ¥åˆ°â€œ%sâ€ã€‚\n" #: src/dht/gnunet-dht-put.c:172 #, c-format msgid "Issuing put request for `%s' with data `%s'!\n" msgstr "" #: src/dht/gnunet-dht-put.c:186 msgid "the data to insert under the key" msgstr "" #: src/dht/gnunet-dht-put.c:189 msgid "how long to store this entry in the dht (in seconds)" msgstr "" #: src/dht/gnunet-dht-put.c:195 msgid "how many replicas to create" msgstr "" #: src/dht/gnunet-dht-put.c:198 msgid "the type to insert data as" msgstr "" #: src/dht/gnunet-dht-put.c:223 msgid "Issue a PUT request to the GNUnet DHT insert DATA under KEY." msgstr "" #: src/dht/gnunet-service-dht.c:163 src/testing/testing.c:544 #: src/testing/testing.c:1968 src/testing/testing.c:1998 #, fuzzy msgid "Failed to connect to transport service!\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/dht/gnunet-service-dht_clients.c:407 msgid "# GET requests from clients injected" msgstr "" #: src/dht/gnunet-service-dht_clients.c:500 msgid "# PUT requests received from clients" msgstr "" #: src/dht/gnunet-service-dht_clients.c:584 msgid "# GET requests received from clients" msgstr "" #: src/dht/gnunet-service-dht_clients.c:682 msgid "# GET STOP requests received from clients" msgstr "" #: src/dht/gnunet-service-dht_clients.c:919 msgid "# Key match, type mismatches in REPLY to CLIENT" msgstr "" #: src/dht/gnunet-service-dht_clients.c:932 msgid "# Duplicate REPLIES to CLIENT request dropped" msgstr "" #: src/dht/gnunet-service-dht_clients.c:967 #, c-format msgid "Unsupported block type (%u) in request!\n" msgstr "" #: src/dht/gnunet-service-dht_clients.c:989 msgid "# RESULTS queued for clients" msgstr "" #: src/dht/gnunet-service-dht_clients.c:1038 #: src/dht/gnunet-service-dht_clients.c:1081 msgid "# REPLIES ignored for CLIENTS (no match)" msgstr "" #: src/dht/gnunet-service-dht_clients.c:1048 msgid "Could not pass reply to client, message too big!\n" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:93 #, c-format msgid "%s request received, but have no datacache!\n" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:103 msgid "# ITEMS stored in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:207 msgid "# Good RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:218 msgid "# Duplicate RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:224 msgid "# Invalid RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:236 msgid "# Unsupported RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:239 #, c-format msgid "Unsupported block type (%u) in local response!\n" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:269 msgid "# GET requests given to datacache" msgstr "" #: src/dht/gnunet-service-dht_hello.c:82 msgid "# HELLOs obtained from peerinfo" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:481 msgid "# Preference updates given to core" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:571 msgid "# FIND PEER messages initiated" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:717 msgid "# Queued messages discarded (peer disconnected)" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:772 msgid "# Bytes transmitted to other peers" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:810 msgid "# Bytes of bandwdith requested from core" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1032 #: src/dht/gnunet-service-dht_neighbours.c:1060 msgid "# Peers excluded from routing due to Bloomfilter" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1041 #: src/dht/gnunet-service-dht_neighbours.c:1075 msgid "# Peer selection failed" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1207 msgid "# PUT requests routed" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1236 msgid "# PUT messages queued for transmission" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1315 msgid "# GET requests routed" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1342 msgid "# GET messages queued for transmission" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1443 msgid "# RESULT messages queued for transmission" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1531 msgid "# P2P PUT requests received" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1647 msgid "# FIND PEER requests ignored due to Bloomfilter" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1655 msgid "# FIND PEER requests ignored due to lack of HELLO" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1746 msgid "# P2P GET requests received" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1788 msgid "# P2P FIND PEER requests processed" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1802 msgid "# P2P GET requests ONLY routed" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1876 msgid "# P2P RESULTS received" msgstr "" #: src/dht/gnunet-service-dht_nse.c:59 msgid "# Network size estimates received" msgstr "" #: src/dht/gnunet-service-dht_routing.c:211 msgid "# Good REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:220 msgid "# Duplicate REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:226 msgid "# Invalid REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:238 msgid "# Unsupported REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:311 msgid "# Entries removed from routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:352 msgid "# Entries added to routing table" msgstr "" #: src/dht/plugin_block_dht.c:136 #, c-format msgid "Block not of type %u\n" msgstr "" #: src/dht/plugin_block_dht.c:143 msgid "Size mismatch for block\n" msgstr "" #: src/dht/plugin_block_dht.c:152 #, c-format msgid "Block of type %u is malformed\n" msgstr "" #: src/dns/gnunet-dns-monitor.c:337 msgid "only monitor DNS queries" msgstr "" #: src/dns/gnunet-dns-monitor.c:340 msgid "only monitor DNS replies" msgstr "" #: src/dns/gnunet-dns-monitor.c:348 msgid "Monitor DNS queries." msgstr "" #: src/dns/gnunet-dns-redirector.c:236 msgid "set A records" msgstr "" #: src/dns/gnunet-dns-redirector.c:239 msgid "set AAAA records" msgstr "" #: src/dns/gnunet-dns-redirector.c:247 msgid "Change DNS replies to point elsewhere." msgstr "" #: src/dns/gnunet-service-dns.c:485 #, fuzzy, c-format msgid "Could not bind to any port: %s\n" msgstr "找ä¸åˆ°ä¸»æœºâ€œ%sâ€çš„ IP:%s\n" #: src/dns/gnunet-service-dns.c:639 msgid "# DNS requests answered via TUN interface" msgstr "" #: src/dns/gnunet-service-dns.c:822 msgid "# DNS exit failed (failed to open socket)" msgstr "" #: src/dns/gnunet-service-dns.c:1005 #, c-format msgid "Received DNS response that is too small (%u bytes)" msgstr "" #: src/dns/gnunet-service-dns.c:1050 msgid "# External DNS response discarded (no matching request)" msgstr "" #: src/dns/gnunet-service-dns.c:1168 msgid "# Client response discarded (no matching request)" msgstr "" #: src/dns/gnunet-service-dns.c:1281 msgid "Received malformed IPv4-UDP packet on TUN interface.\n" msgstr "" #: src/dns/gnunet-service-dns.c:1297 msgid "Received malformed IPv6-UDP packet on TUN interface.\n" msgstr "" #: src/dns/gnunet-service-dns.c:1306 #, c-format msgid "Got non-IP packet with %u bytes and protocol %u from TUN\n" msgstr "" #: src/dns/gnunet-service-dns.c:1315 msgid "# Non-DNS UDP packet received via TUN interface" msgstr "" #: src/dns/gnunet-service-dns.c:1380 msgid "# DNS requests received via TUN interface" msgstr "" #: src/dns/gnunet-service-dns.c:1465 #, c-format msgid "Configured DNS exit `%s' is not working / valid.\n" msgstr "" #: src/dns/gnunet-service-dns.c:1497 src/exit/gnunet-daemon-exit.c:2674 msgid "# Inbound MESH tunnels created" msgstr "" #: src/dns/gnunet-service-dns.c:1561 src/exit/gnunet-daemon-exit.c:3032 #, c-format msgid "`%s' must be installed SUID, refusing to run\n" msgstr "" #: src/dns/gnunet-service-dns.c:1581 msgid "Configured to provide DNS exit, but no valid DNS server configured!\n" msgstr "" #: src/dv/dv_api.c:179 #, fuzzy msgid "Failed to connect to the dv service!\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/dv/plugin_transport_dv.c:159 #, c-format msgid "%s Received message from %s of type %d, distance %u!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:508 #, c-format msgid "Got duplicate service records for `%s:%u'\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:563 msgid "# Bytes transmitted via mesh tunnels" msgstr "" #: src/exit/gnunet-daemon-exit.c:679 src/exit/gnunet-daemon-exit.c:2069 #: src/exit/gnunet-daemon-exit.c:2319 src/vpn/gnunet-service-vpn.c:1394 #: src/vpn/gnunet-service-vpn.c:1795 src/vpn/gnunet-service-vpn.c:1958 msgid "# ICMPv4 packets dropped (type not allowed)" msgstr "" #: src/exit/gnunet-daemon-exit.c:716 src/exit/gnunet-daemon-exit.c:2128 #: src/exit/gnunet-daemon-exit.c:2378 src/vpn/gnunet-service-vpn.c:1450 #: src/vpn/gnunet-service-vpn.c:1854 src/vpn/gnunet-service-vpn.c:1991 msgid "# ICMPv6 packets dropped (type not allowed)" msgstr "" #: src/exit/gnunet-daemon-exit.c:756 msgid "# ICMP packets dropped (not allowed)" msgstr "" #: src/exit/gnunet-daemon-exit.c:763 msgid "ICMP Packet dropped, have no matching connection information\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:840 msgid "UDP Packet dropped, have no matching connection information\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:915 msgid "TCP Packet dropped, have no matching connection information\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:968 msgid "# Packets received from TUN" msgstr "" #: src/exit/gnunet-daemon-exit.c:982 msgid "# Bytes received from TUN" msgstr "" #: src/exit/gnunet-daemon-exit.c:1008 msgid "IPv4 packet options received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1035 #, c-format msgid "IPv4 packet with unsupported next header %u received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1081 #, c-format msgid "IPv6 packet with unsupported next header %d received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1089 #, c-format msgid "Packet from unknown protocol %u received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1471 msgid "# TCP packets sent via TUN" msgstr "" #: src/exit/gnunet-daemon-exit.c:1571 msgid "# TCP service creation requests received via mesh" msgstr "" #: src/exit/gnunet-daemon-exit.c:1574 src/exit/gnunet-daemon-exit.c:1653 #: src/exit/gnunet-daemon-exit.c:1763 src/exit/gnunet-daemon-exit.c:1993 #: src/exit/gnunet-daemon-exit.c:2235 src/exit/gnunet-daemon-exit.c:2516 #: src/exit/gnunet-daemon-exit.c:2616 msgid "# Bytes received from MESH" msgstr "" #: src/exit/gnunet-daemon-exit.c:1607 src/exit/gnunet-daemon-exit.c:2638 #, c-format msgid "No service found for %s on port %d!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1611 msgid "# TCP requests dropped (no such service)" msgstr "" #: src/exit/gnunet-daemon-exit.c:1656 msgid "# TCP IP-exit creation requests received via mesh" msgstr "" #: src/exit/gnunet-daemon-exit.c:1766 msgid "# TCP data requests received via mesh" msgstr "" #: src/exit/gnunet-daemon-exit.c:1780 msgid "# TCP DATA requests dropped (no session)" msgstr "" #: src/exit/gnunet-daemon-exit.c:1830 msgid "# ICMP packets sent via TUN" msgstr "" #: src/exit/gnunet-daemon-exit.c:1996 msgid "# ICMP IP-exit requests received via mesh" msgstr "" #: src/exit/gnunet-daemon-exit.c:2238 msgid "# ICMP service requests received via mesh" msgstr "" #: src/exit/gnunet-daemon-exit.c:2304 src/vpn/gnunet-service-vpn.c:1384 #: src/vpn/gnunet-service-vpn.c:1952 msgid "# ICMPv4 packets dropped (impossible PT to v6)" msgstr "" #: src/exit/gnunet-daemon-exit.c:2363 src/vpn/gnunet-service-vpn.c:1420 #: src/vpn/gnunet-service-vpn.c:1432 src/vpn/gnunet-service-vpn.c:1842 msgid "# ICMPv6 packets dropped (impossible PT to v4)" msgstr "" #: src/exit/gnunet-daemon-exit.c:2413 msgid "# UDP packets sent via TUN" msgstr "" #: src/exit/gnunet-daemon-exit.c:2519 msgid "# UDP IP-exit requests received via mesh" msgstr "" #: src/exit/gnunet-daemon-exit.c:2619 msgid "# UDP service requests received via mesh" msgstr "" #: src/exit/gnunet-daemon-exit.c:2642 msgid "# UDP requests dropped (no such service)" msgstr "" #: src/exit/gnunet-daemon-exit.c:2882 #, c-format msgid "No addresses found for hostname `%s' of service `%s'!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:2896 src/exit/gnunet-daemon-exit.c:2908 #, c-format msgid "Service `%s' configured for IPv4, but IPv4 is disabled!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:2919 #, c-format msgid "No IP addresses found for hostname `%s' of service `%s'!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3048 msgid "" "This system does not support IPv4, will disable IPv4 functions despite them " "being enabled in the configuration\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3056 msgid "" "This system does not support IPv6, will disable IPv6 functions despite them " "being enabled in the configuration\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3063 msgid "" "Cannot enable IPv4 exit but disable IPv4 on TUN interface, will use " "ENABLE_IPv4=YES\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3069 msgid "" "Cannot enable IPv6 exit but disable IPv6 on TUN interface, will use " "ENABLE_IPv6=YES\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3075 src/pt/gnunet-daemon-pt.c:884 msgid "No useful service enabled. Exiting.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3236 msgid "Daemon to run to provide an IP exit node for the VPN" msgstr "" #: src/fragmentation/defragmentation.c:270 msgid "# acknowledgements sent for fragment" msgstr "" #: src/fragmentation/defragmentation.c:456 msgid "# fragments received" msgstr "" #: src/fragmentation/defragmentation.c:521 msgid "# duplicate fragments received" msgstr "" #: src/fragmentation/defragmentation.c:534 msgid "# messages defragmented" msgstr "" #: src/fragmentation/fragmentation.c:203 msgid "# fragments transmitted" msgstr "" #: src/fragmentation/fragmentation.c:206 msgid "# fragments retransmitted" msgstr "" #: src/fragmentation/fragmentation.c:232 msgid "# fragments wrap arounds" msgstr "" #: src/fragmentation/fragmentation.c:273 msgid "# messages fragmented" msgstr "" #: src/fragmentation/fragmentation.c:276 msgid "# total size of fragmented messages" msgstr "" #: src/fragmentation/fragmentation.c:363 msgid "# fragment acknowledgements received" msgstr "" #: src/fragmentation/fragmentation.c:369 msgid "# bits removed from fragmentation ACKs" msgstr "" #: src/fragmentation/fragmentation.c:393 msgid "# fragmentation transmissions completed" msgstr "" #: src/fs/fs_api.c:339 #, fuzzy, c-format msgid "Could not open file `%s': %s" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/fs/fs_api.c:348 #, fuzzy, c-format msgid "Could not read file `%s': %s" msgstr "无法解æžâ€œ%sâ€(%s):%s\n" #: src/fs/fs_api.c:354 #, c-format msgid "Short read reading from file `%s'!" msgstr "" #: src/fs/fs_api.c:938 #, fuzzy, c-format msgid "Failed to resume publishing information `%s': %s\n" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/fs/fs_api.c:1395 #, c-format msgid "Failed to recover namespace `%s', cannot resume publishing operation.\n" msgstr "" #: src/fs/fs_api.c:1437 #, c-format msgid "Failure while resuming publishing operation `%s': %s\n" msgstr "" #: src/fs/fs_api.c:1453 #, fuzzy, c-format msgid "Failed to resume publishing operation `%s': %s\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/fs/fs_api.c:2106 #, c-format msgid "Failure while resuming unindexing operation `%s': %s\n" msgstr "" #: src/fs/fs_api.c:2116 #, fuzzy, c-format msgid "Failed to resume unindexing operation `%s': %s\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/fs/fs_api.c:2241 src/fs/fs_api.c:2480 #, fuzzy, c-format msgid "Failed to resume sub-download `%s': %s\n" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/fs/fs_api.c:2258 #, fuzzy, c-format msgid "Failed to resume sub-search `%s': %s\n" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/fs/fs_api.c:2270 src/fs/fs_api.c:2289 src/fs/fs_api.c:2773 #, c-format msgid "Failure while resuming search operation `%s': %s\n" msgstr "" #: src/fs/fs_api.c:2471 #, fuzzy, c-format msgid "Failed to resume sub-download `%s': could not open file `%s'\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/fs/fs_api.c:2717 msgid "Could not resume running search, will resume as paused search\n" msgstr "" #: src/fs/fs_api.c:2811 #, c-format msgid "Failure while resuming download operation `%s': %s\n" msgstr "" #: src/fs/fs_directory.c:210 msgid "MAGIC mismatch. This is not a GNUnet directory.\n" msgstr "" #: src/fs/fs_download.c:311 msgid "" "Recursive downloads of directories larger than 4 GB are not supported on 32-" "bit systems\n" msgstr "" #: src/fs/fs_download.c:331 msgid "Directory too large for system address space\n" msgstr "" #: src/fs/fs_download.c:497 src/fs/fs_download.c:509 #, fuzzy, c-format msgid "Failed to open file `%s' for writing" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/fs/fs_download.c:878 #, c-format msgid "Failed to create directory for recursive download of `%s'\n" msgstr "" #: src/fs/fs_download.c:960 #, c-format msgid "" "Internal error or bogus download URI (expected %u bytes at depth %u and " "offset %llu/%llu, got %u bytes)" msgstr "" #: src/fs/fs_download.c:986 msgid "internal error decrypting content" msgstr "" #: src/fs/fs_download.c:1009 #, fuzzy, c-format msgid "Download failed: could not open file `%s': %s" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/fs/fs_download.c:1019 #, fuzzy, c-format msgid "Failed to seek to offset %llu in file `%s': %s" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/fs/fs_download.c:1028 #, fuzzy, c-format msgid "Failed to write block of %u bytes at offset %llu in file `%s': %s" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/fs/fs_download.c:1125 #, fuzzy msgid "internal error decoding tree" msgstr "未知错误。\n" #: src/fs/fs_download.c:1888 #, fuzzy msgid "Invalid URI" msgstr "无效æ¡ç›®ã€‚\n" #: src/fs/fs_getopt.c:191 #, c-format msgid "" "Unknown metadata type in metadata option `%s'. Using metadata type " "`unknown' instead.\n" msgstr "" #: src/fs/fs_list_indexed.c:90 #, c-format msgid "Failed to receive response for `%s' request from `%s' service.\n" msgstr "" #: src/fs/fs_list_indexed.c:113 #, c-format msgid "Failed to receive valid response for `%s' request from `%s' service.\n" msgstr "" #: src/fs/fs_list_indexed.c:151 #, fuzzy, c-format msgid "Failed to not connect to `%s' service.\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/fs/fs_misc.c:126 #, c-format msgid "Did not find mime type `%s' in extension list.\n" msgstr "" #: src/fs/fs_namespace_advertise.c:150 #, fuzzy msgid "Unknown error" msgstr "未知错误" #: src/fs/fs_namespace_advertise.c:238 src/fs/fs_namespace_advertise.c:259 #, fuzzy msgid "Failed to serialize meta data" msgstr "å‘逿¶ˆæ¯å¤±è´¥ã€‚\n" #: src/fs/fs_namespace_advertise.c:278 #, fuzzy msgid "Failed to connect to datastore service" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/fs/fs_namespace.c:57 src/fs/fs_namespace.c:83 #, fuzzy, c-format msgid "Configuration fails to specify `%s' in section `%s'\n" msgstr "é…置文件“%sâ€å·²å†™å…¥ã€‚\n" #: src/fs/fs_namespace.c:112 #, fuzzy, c-format msgid "Failed to open `%s' for writing: %s\n" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/fs/fs_namespace.c:134 src/fs/fs_namespace.c:222 #, fuzzy, c-format msgid "Failed to write `%s': %s\n" msgstr "è¿è¡Œ %s失败:%s %d\n" #: src/fs/fs_namespace.c:256 #, c-format msgid "Failed to create or read private key for namespace `%s'\n" msgstr "" #: src/fs/fs_namespace.c:371 #, c-format msgid "Failed to read namespace private key file `%s', deleting it!\n" msgstr "" #: src/fs/fs_namespace.c:588 src/fs/fs_publish_ksk.c:295 #, fuzzy msgid "Internal error." msgstr "未知错误。\n" #: src/fs/fs_namespace.c:631 msgid "Failed to connect to datastore." msgstr "" #: src/fs/fs_publish.c:129 src/fs/fs_publish.c:397 #, c-format msgid "Publishing failed: %s" msgstr "" #: src/fs/fs_publish.c:621 src/fs/fs_publish.c:638 src/fs/fs_publish.c:677 #: src/fs/fs_publish.c:697 src/fs/fs_publish.c:722 src/fs/fs_publish.c:862 #, c-format msgid "Can not index file `%s': %s. Will try to insert instead.\n" msgstr "" #: src/fs/fs_publish.c:623 msgid "timeout on index-start request to `fs' service" msgstr "" #: src/fs/fs_publish.c:635 #, fuzzy msgid "unknown error" msgstr "未知错误" #: src/fs/fs_publish.c:678 msgid "failed to compute hash" msgstr "" #: src/fs/fs_publish.c:698 msgid "filename too long" msgstr "" #: src/fs/fs_publish.c:723 msgid "could not connect to `fs' service" msgstr "" #: src/fs/fs_publish.c:746 #, fuzzy, c-format msgid "Failed to get file identifiers for `%s'\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/fs/fs_publish.c:811 #, c-format msgid "Recursive upload failed at `%s': %s" msgstr "" #: src/fs/fs_publish.c:817 #, c-format msgid "Recursive upload failed: %s" msgstr "" #: src/fs/fs_publish.c:863 msgid "needs to be an actual file" msgstr "" #: src/fs/fs_publish.c:1071 #, c-format msgid "Insufficient space for publishing: %s" msgstr "" #: src/fs/fs_publish.c:1142 #, c-format msgid "Reserving space for %u entries and %llu bytes for publication\n" msgstr "" #: src/fs/fs_publish_ksk.c:258 msgid "Could not connect to datastore." msgstr "" #: src/fs/fs_search.c:829 #, c-format msgid "Got result with unknown block type `%d', ignoring" msgstr "" #: src/fs/fs_test_lib.c:269 #, fuzzy, c-format msgid "Failed to start daemon: %s\n" msgstr "è¿è¡Œ %s失败:%s %d\n" #: src/fs/fs_unindex.c:58 msgid "Failed to find given position in file" msgstr "" #: src/fs/fs_unindex.c:63 #, fuzzy msgid "Failed to read file" msgstr "å‘逿¶ˆæ¯å¤±è´¥ã€‚\n" #: src/fs/fs_unindex.c:233 msgid "Unexpected time for a response from `fs' service." msgstr "" #: src/fs/fs_unindex.c:241 msgid "Timeout waiting for `fs' service." msgstr "" #: src/fs/fs_unindex.c:249 #, fuzzy msgid "Invalid response from `fs' service." msgstr "“%sâ€çš„傿•°æ— æ•ˆã€‚\n" #: src/fs/fs_unindex.c:293 msgid "Failed to connect to FS service for unindexing." msgstr "" #: src/fs/fs_unindex.c:344 #, fuzzy msgid "Failed to get KSKs from directory scan." msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/fs/fs_unindex.c:356 #, fuzzy, c-format msgid "Internal error scanning `%s'.\n" msgstr "未知错误。\n" #: src/fs/fs_unindex.c:411 #, fuzzy, c-format msgid "Failed to remove KBlock: %s\n" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/fs/fs_unindex.c:501 #, fuzzy, c-format msgid "Failed to parse URI `%s' from KBlock!\n" msgstr "è¿è¡Œ %s失败:%s %d\n" #: src/fs/fs_unindex.c:553 src/fs/fs_unindex.c:618 #, fuzzy msgid "Failed to connect to `datastore' service." msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/fs/fs_unindex.c:631 #, fuzzy msgid "Failed to open file for unindexing." msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/fs/fs_unindex.c:665 msgid "Failed to compute hash of file." msgstr "" #: src/fs/fs_uri.c:220 #, c-format msgid "`%' must be followed by HEX number" msgstr "" #: src/fs/fs_uri.c:279 msgid "Malformed KSK URI (must not begin or end with `+')" msgstr "" #: src/fs/fs_uri.c:297 msgid "`++' not allowed in KSK URI" msgstr "" #: src/fs/fs_uri.c:304 msgid "Quotes not balanced in KSK URI" msgstr "" #: src/fs/fs_uri.c:372 src/fs/fs_uri.c:379 msgid "Malformed SKS URI" msgstr "" #: src/fs/fs_uri.c:423 src/fs/fs_uri.c:438 msgid "Malformed CHK URI" msgstr "" #: src/fs/fs_uri.c:568 src/fs/fs_uri.c:583 src/fs/fs_uri.c:593 #: src/fs/fs_uri.c:621 msgid "SKS URI malformed" msgstr "" #: src/fs/fs_uri.c:603 msgid "SKS URI malformed (could not decode public key)" msgstr "" #: src/fs/fs_uri.c:609 msgid "SKS URI malformed (could not find signature)" msgstr "" #: src/fs/fs_uri.c:615 msgid "SKS URI malformed (could not decode signature)" msgstr "" #: src/fs/fs_uri.c:628 msgid "SKS URI malformed (could not parse expiration time)" msgstr "" #: src/fs/fs_uri.c:640 msgid "SKS URI malformed (signature failed validation)" msgstr "" #: src/fs/fs_uri.c:678 msgid "Unrecognized URI type" msgstr "" #: src/fs/fs_uri.c:903 #, fuzzy msgid "Lacking key configuration settings.\n" msgstr "ç«‹å³ä¿å­˜é…置?" #: src/fs/fs_uri.c:910 #, fuzzy, c-format msgid "Could not access hostkey file `%s'.\n" msgstr "找ä¸åˆ°æŽ¥å£â€œ%sâ€çš„一个 IP 地å€ã€‚\n" #: src/fs/fs_uri.c:1115 src/fs/fs_uri.c:1142 msgid "No keywords specified!\n" msgstr "" #: src/fs/fs_uri.c:1148 msgid "Number of double-quotes not balanced!\n" msgstr "" #: src/fs/gnunet-directory.c:49 #, c-format msgid "\t\n" msgstr "" #: src/fs/gnunet-directory.c:94 #, c-format msgid "Directory `%s' meta data:\n" msgstr "" #: src/fs/gnunet-directory.c:97 #, c-format msgid "Directory `%s' contents:\n" msgstr "" #: src/fs/gnunet-directory.c:132 #, fuzzy msgid "You must specify a filename to inspect.\n" msgstr "您必须指定一个昵称\n" #: src/fs/gnunet-directory.c:145 #, fuzzy, c-format msgid "Failed to read directory `%s'\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/fs/gnunet-directory.c:154 #, fuzzy, c-format msgid "`%s' is not a GNUnet directory\n" msgstr "更改 GNUnet 目录的æƒé™å‡ºé”™" #: src/fs/gnunet-directory.c:179 #, fuzzy msgid "Display contents of a GNUnet directory" msgstr "更改 GNUnet 目录的æƒé™å‡ºé”™" #: src/fs/gnunet-download.c:101 #, fuzzy, c-format msgid "Starting download `%s'.\n" msgstr "未知的命令“%sâ€ã€‚\n" #: src/fs/gnunet-download.c:110 #, fuzzy msgid "" msgstr "未知错误" #: src/fs/gnunet-download.c:119 #, c-format msgid "" "Downloading `%s' at %llu/%llu (%s remaining, %s/s). Block took %s to " "download\n" msgstr "" #: src/fs/gnunet-download.c:129 #, c-format msgid "Error downloading: %s.\n" msgstr "" #: src/fs/gnunet-download.c:137 #, c-format msgid "Downloading `%s' done (%s/s).\n" msgstr "" #: src/fs/gnunet-download.c:152 src/fs/gnunet-publish.c:190 #: src/fs/gnunet-search.c:190 src/fs/gnunet-unindex.c:109 #, c-format msgid "Unexpected status: %d\n" msgstr "" #: src/fs/gnunet-download.c:177 #, fuzzy msgid "You need to specify a URI argument.\n" msgstr "您必须指定一个昵称\n" #: src/fs/gnunet-download.c:183 src/fs/gnunet-publish.c:624 #, fuzzy, c-format msgid "Failed to parse URI: %s\n" msgstr "è¿è¡Œ %s失败:%s %d\n" #: src/fs/gnunet-download.c:190 msgid "Only CHK or LOC URIs supported.\n" msgstr "" #: src/fs/gnunet-download.c:197 msgid "Target filename must be specified.\n" msgstr "" #: src/fs/gnunet-download.c:211 src/fs/gnunet-publish.c:602 #: src/fs/gnunet-search.c:241 src/fs/gnunet-unindex.c:141 #, fuzzy, c-format msgid "Could not initialize `%s' subsystem.\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/fs/gnunet-download.c:248 src/fs/gnunet-search.c:285 msgid "set the desired LEVEL of receiver-anonymity" msgstr "" #: src/fs/gnunet-download.c:251 msgid "delete incomplete downloads (when aborted with CTRL-C)" msgstr "" #: src/fs/gnunet-download.c:254 src/fs/gnunet-search.c:288 msgid "only search the local peer (no P2P network search)" msgstr "" #: src/fs/gnunet-download.c:257 msgid "write the file to FILENAME" msgstr "" #: src/fs/gnunet-download.c:261 msgid "set the maximum number of parallel downloads that is allowed" msgstr "" #: src/fs/gnunet-download.c:265 msgid "set the maximum number of parallel requests for blocks that is allowed" msgstr "" #: src/fs/gnunet-download.c:268 msgid "download a GNUnet directory recursively" msgstr "" #: src/fs/gnunet-download.c:278 msgid "" "Download files from GNUnet using a GNUnet CHK or LOC URI (gnunet://fs/" "chk/...)" msgstr "" #: src/fs/gnunet-fs.c:117 msgid "print a list of all indexed files" msgstr "" #: src/fs/gnunet-fs.c:124 msgid "Special file-sharing operations" msgstr "" #: src/fs/gnunet-pseudonym.c:160 src/statistics/gnunet-statistics.c:167 #, fuzzy, c-format msgid "Invalid argument `%s'\n" msgstr "“%sâ€çš„傿•°æ— æ•ˆã€‚\n" #: src/fs/gnunet-pseudonym.c:250 src/fs/gnunet-pseudonym.c:257 #: src/fs/gnunet-pseudonym.c:259 #, fuzzy, c-format msgid "Option `%s' ignored\n" msgstr "%s:选项“%sâ€æœ‰æ­§ä¹‰\n" #: src/fs/gnunet-pseudonym.c:279 src/fs/gnunet-publish.c:678 msgid "set the desired LEVEL of sender-anonymity" msgstr "" #: src/fs/gnunet-pseudonym.c:282 msgid "create or advertise namespace NAME" msgstr "" #: src/fs/gnunet-pseudonym.c:285 msgid "delete namespace NAME " msgstr "" #: src/fs/gnunet-pseudonym.c:288 msgid "" "add an additional keyword for the advertisment (this option can be specified " "multiple times)" msgstr "" #: src/fs/gnunet-pseudonym.c:292 src/fs/gnunet-publish.c:697 msgid "set the meta-data for the given TYPE to the given VALUE" msgstr "" #: src/fs/gnunet-pseudonym.c:295 msgid "print names of local namespaces" msgstr "" #: src/fs/gnunet-pseudonym.c:298 msgid "use the given PRIORITY for the advertisments" msgstr "" #: src/fs/gnunet-pseudonym.c:301 msgid "do not print names of remote namespaces" msgstr "" #: src/fs/gnunet-pseudonym.c:304 src/fs/gnunet-publish.c:716 msgid "set the desired replication LEVEL" msgstr "" #: src/fs/gnunet-pseudonym.c:307 msgid "specify ID of the root of the namespace" msgstr "" #: src/fs/gnunet-pseudonym.c:310 msgid "change rating of namespace ID by VALUE" msgstr "" #: src/fs/gnunet-pseudonym.c:318 msgid "Manage GNUnet pseudonyms." msgstr "" #: src/fs/gnunet-publish.c:147 #, c-format msgid "Publishing `%s' at %llu/%llu (%s remaining)\n" msgstr "" #: src/fs/gnunet-publish.c:155 #, c-format msgid "Error publishing: %s.\n" msgstr "" #: src/fs/gnunet-publish.c:165 #, c-format msgid "Publishing `%s' done.\n" msgstr "" #: src/fs/gnunet-publish.c:169 #, c-format msgid "URI is `%s'.\n" msgstr "" #: src/fs/gnunet-publish.c:187 msgid "Cleanup after abort complete.\n" msgstr "" #: src/fs/gnunet-publish.c:305 #, fuzzy, c-format msgid "Meta data for file `%s' (%s)\n" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/fs/gnunet-publish.c:307 #, fuzzy, c-format msgid "Keywords for file `%s' (%s)\n" msgstr "无法解æžâ€œ%sâ€(%s):%s\n" #: src/fs/gnunet-publish.c:358 #, fuzzy, c-format msgid "Failed to create namespace `%s'\n" msgstr "å‘逿¶ˆæ¯å¤±è´¥ã€‚\n" #: src/fs/gnunet-publish.c:433 #, fuzzy msgid "Could not publish\n" msgstr "无法解æžâ€œ%sâ€(%s):%s\n" #: src/fs/gnunet-publish.c:460 msgid "Could not start publishing.\n" msgstr "" #: src/fs/gnunet-publish.c:491 #, fuzzy, c-format msgid "Scanning directory `%s'.\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/fs/gnunet-publish.c:493 #, fuzzy, c-format msgid "Scanning file `%s'.\n" msgstr "未知的命令“%sâ€ã€‚\n" #: src/fs/gnunet-publish.c:498 #, c-format msgid "There was trouble processing file `%s', skipping it.\n" msgstr "" #: src/fs/gnunet-publish.c:503 msgid "Preprocessing complete.\n" msgstr "" #: src/fs/gnunet-publish.c:507 #, fuzzy, c-format msgid "Extracting meta data from file `%s' complete.\n" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/fs/gnunet-publish.c:511 msgid "Meta data extraction has finished.\n" msgstr "" #: src/fs/gnunet-publish.c:518 #, fuzzy msgid "Internal error scanning directory.\n" msgstr "未知错误。\n" #: src/fs/gnunet-publish.c:552 #, c-format msgid "Cannot extract metadata from a URI!\n" msgstr "" #: src/fs/gnunet-publish.c:559 #, c-format msgid "You must specify one and only one filename for insertion.\n" msgstr "" #: src/fs/gnunet-publish.c:565 #, c-format msgid "You must NOT specify an URI and a filename.\n" msgstr "" #: src/fs/gnunet-publish.c:573 src/vpn/gnunet-vpn.c:214 #, c-format msgid "Option `%s' is required when using option `%s'.\n" msgstr "" #: src/fs/gnunet-publish.c:583 src/fs/gnunet-publish.c:590 #: src/transport/gnunet-transport.c:560 #, c-format msgid "Option `%s' makes no sense without option `%s'.\n" msgstr "" #: src/fs/gnunet-publish.c:612 #, fuzzy, c-format msgid "Could not create namespace `%s'\n" msgstr "无法解æžâ€œ%sâ€(%s):%s\n" #: src/fs/gnunet-publish.c:645 #, fuzzy, c-format msgid "Failed to access `%s': %s\n" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/fs/gnunet-publish.c:657 msgid "" "Failed to start meta directory scanner. Is gnunet-helper-publish-fs " "installed?\n" msgstr "" #: src/fs/gnunet-publish.c:682 msgid "disable adding the creation time to the metadata of the uploaded file" msgstr "" #: src/fs/gnunet-publish.c:685 msgid "do not use libextractor to add keywords or metadata" msgstr "" #: src/fs/gnunet-publish.c:689 msgid "" "print list of extracted keywords that would be used, but do not perform " "upload" msgstr "" #: src/fs/gnunet-publish.c:693 msgid "" "add an additional keyword for the top-level file or directory (this option " "can be specified multiple times)" msgstr "" #: src/fs/gnunet-publish.c:700 msgid "" "do not index, perform full insertion (stores entire file in encrypted form " "in GNUnet database)" msgstr "" #: src/fs/gnunet-publish.c:705 msgid "" "specify ID of an updated version to be published in the future (for " "namespace insertions only)" msgstr "" #: src/fs/gnunet-publish.c:709 msgid "specify the priority of the content" msgstr "" #: src/fs/gnunet-publish.c:713 msgid "publish the files under the pseudonym NAME (place file into namespace)" msgstr "" #: src/fs/gnunet-publish.c:719 msgid "" "only simulate the process but do not do any actual publishing (useful to " "compute URIs)" msgstr "" #: src/fs/gnunet-publish.c:723 msgid "" "set the ID of this version of the publication (for namespace insertions only)" msgstr "" #: src/fs/gnunet-publish.c:727 msgid "" "URI to be published (can be used instead of passing a file to add keywords " "to the file with the respective URI)" msgstr "" #: src/fs/gnunet-publish.c:742 msgid "Publish a file or directory on GNUnet" msgstr "" #: src/fs/gnunet-search.c:111 #, c-format msgid "Failed to write directory with search results to `%s'\n" msgstr "" #: src/fs/gnunet-search.c:181 #, fuzzy, c-format msgid "Error searching: %s.\n" msgstr "创建用户出错" #: src/fs/gnunet-search.c:231 msgid "Could not create keyword URI from arguments.\n" msgstr "" #: src/fs/gnunet-search.c:255 msgid "Could not start searching.\n" msgstr "" #: src/fs/gnunet-search.c:291 msgid "write search results to file starting with PREFIX" msgstr "" #: src/fs/gnunet-search.c:294 msgid "automatically terminate search after VALUE ms" msgstr "" #: src/fs/gnunet-search.c:301 msgid "automatically terminate search after VALUE results are found" msgstr "" #: src/fs/gnunet-search.c:308 msgid "Search GNUnet for files that were published on GNUnet" msgstr "" #: src/fs/gnunet-service-fs.c:240 msgid "# running average P2P latency (ms)" msgstr "" #: src/fs/gnunet-service-fs.c:300 src/fs/gnunet-service-fs.c:489 msgid "# Loopback routes suppressed" msgstr "" #: src/fs/gnunet-service-fs.c:581 src/hostlist/gnunet-daemon-hostlist.c:297 #: src/topology/gnunet-daemon-topology.c:1330 #: src/topology/gnunet-daemon-topology.c:1337 #, fuzzy, c-format msgid "Failed to connect to `%s' service.\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/fs/gnunet-service-fs_cp.c:696 msgid "# migration stop messages received" msgstr "" #: src/fs/gnunet-service-fs_cp.c:700 #, c-format msgid "Migration of content to peer `%s' blocked for %llu ms\n" msgstr "" #: src/fs/gnunet-service-fs_cp.c:735 msgid "# replies transmitted to other peers" msgstr "" #: src/fs/gnunet-service-fs_cp.c:741 msgid "# replies dropped" msgstr "" #: src/fs/gnunet-service-fs_cp.c:766 src/fs/gnunet-service-fs_cp.c:1324 msgid "# P2P searches active" msgstr "" #: src/fs/gnunet-service-fs_cp.c:858 msgid "# artificial delays introduced (ms)" msgstr "" #: src/fs/gnunet-service-fs_cp.c:911 msgid "# replies dropped due to type mismatch" msgstr "" #: src/fs/gnunet-service-fs_cp.c:919 msgid "# replies received for other peers" msgstr "" #: src/fs/gnunet-service-fs_cp.c:933 msgid "# replies dropped due to insufficient cover traffic" msgstr "" #: src/fs/gnunet-service-fs_cp.c:971 msgid "# P2P searches destroyed due to ultimate reply" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1038 msgid "# requests done for free (low load)" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1062 msgid "# request dropped, priority insufficient" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1072 msgid "# requests done for a price (normal load)" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1151 msgid "# GET requests received (from other peers)" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1185 msgid "# requests dropped due to initiator not being connected" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1207 msgid "# requests dropped due to missing reverse route" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1267 msgid "# requests dropped due TTL underflow" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1293 msgid "# requests dropped due to higher-TTL request" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1322 msgid "# P2P query messages received and processed" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1687 msgid "# migration stop messages sent" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:113 #: src/fs/gnunet-service-fs_indexing.c:163 #, fuzzy, c-format msgid "Configuration option `%s' in section `%s' missing.\n" msgstr "é…置文件“%sâ€å·²å†™å…¥ã€‚\n" #: src/fs/gnunet-service-fs_indexing.c:121 #: src/fs/gnunet-service-fs_indexing.c:177 #, fuzzy, c-format msgid "Could not open `%s'.\n" msgstr "无法解æžâ€œ%sâ€(%s):%s\n" #: src/fs/gnunet-service-fs_indexing.c:137 #, fuzzy, c-format msgid "Error writing `%s'.\n" msgstr "创建用户出错" #: src/fs/gnunet-service-fs_indexing.c:228 #, c-format msgid "" "Index request received for file `%s' is already indexed as `%s'. Permitting " "anyway.\n" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:266 #, c-format msgid "Hash mismatch trying to index file `%s' which has hash `%s'\n" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:481 #, fuzzy, c-format msgid "Failed to delete bogus block: %s\n" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/fs/gnunet-service-fs_indexing.c:539 msgid "# index blocks removed: original file inaccessible" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:554 #, fuzzy, c-format msgid "Could not access indexed file `%s' (%s) at offset %llu: %s\n" msgstr "无法解æžâ€œ%sâ€(%s):%s\n" #: src/fs/gnunet-service-fs_indexing.c:556 msgid "not indexed" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:571 #, c-format msgid "Indexed file `%s' changed at offset %llu\n" msgstr "" #: src/fs/gnunet-service-fs_lc.c:202 src/fs/gnunet-service-fs_lc.c:362 #: src/fs/gnunet-service-fs_lc.c:488 msgid "# client searches active" msgstr "" #: src/fs/gnunet-service-fs_lc.c:256 msgid "# replies received for local clients" msgstr "" #: src/fs/gnunet-service-fs_lc.c:321 msgid "# client searches received" msgstr "" #: src/fs/gnunet-service-fs_lc.c:356 msgid "# client searches updated (merged content seen list)" msgstr "" #: src/fs/gnunet-service-fs_pe.c:265 msgid "# average retransmission delay (ms)" msgstr "" #: src/fs/gnunet-service-fs_pe.c:391 msgid "# transmission failed (core has no bandwidth)" msgstr "" #: src/fs/gnunet-service-fs_pe.c:420 msgid "# query messages sent to other peers" msgstr "" #: src/fs/gnunet-service-fs_pe.c:469 msgid "# delay heap timeout" msgstr "" #: src/fs/gnunet-service-fs_pe.c:476 msgid "# query plans executed" msgstr "" #: src/fs/gnunet-service-fs_pe.c:538 msgid "# requests merged" msgstr "" #: src/fs/gnunet-service-fs_pe.c:544 msgid "# requests refreshed" msgstr "" #: src/fs/gnunet-service-fs_pe.c:597 src/fs/gnunet-service-fs_pe.c:681 #: src/fs/gnunet-service-fs_pe.c:748 msgid "# query plan entries" msgstr "" #: src/fs/gnunet-service-fs_pr.c:285 msgid "# Pending requests created" msgstr "" #: src/fs/gnunet-service-fs_pr.c:367 src/fs/gnunet-service-fs_pr.c:616 msgid "# Pending requests active" msgstr "" #: src/fs/gnunet-service-fs_pr.c:779 msgid "# replies received and matched" msgstr "" #: src/fs/gnunet-service-fs_pr.c:808 msgid "# duplicate replies discarded (bloomfilter)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:822 #, c-format msgid "Unsupported block type %u\n" msgstr "" #: src/fs/gnunet-service-fs_pr.c:835 msgid "# results found locally" msgstr "" #: src/fs/gnunet-service-fs_pr.c:953 msgid "# Datastore `PUT' failures" msgstr "" #: src/fs/gnunet-service-fs_pr.c:980 msgid "# storage requests dropped due to high load" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1015 msgid "# Replies received from DHT" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1106 #, c-format msgid "Datastore lookup already took %llu ms!\n" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1127 #, c-format msgid "On-demand lookup already took %llu ms!\n" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1174 msgid "# Datastore lookups concluded (no results)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1188 msgid "# Datastore lookups concluded (seen all)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1197 msgid "# Datastore lookups aborted (more than MAX_RESULTS)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1211 msgid "# requested DBLOCK or IBLOCK not found" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1224 msgid "# on-demand blocks matched requests" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1237 msgid "# on-demand lookups performed successfully" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1242 msgid "# on-demand lookups failed" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1269 src/fs/gnunet-service-fs_pr.c:1309 #: src/fs/gnunet-service-fs_pr.c:1447 msgid "# Datastore lookups concluded (error queueing)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1327 msgid "# Datastore lookups concluded (found last result)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1338 msgid "# Datastore lookups concluded (load too high)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1424 msgid "# Datastore lookups initiated" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1508 msgid "# GAP PUT messages received" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1601 src/fs/gnunet-service-fs_pr.c:1610 #, fuzzy, c-format msgid "Configuration fails to specify `%s', assuming default value." msgstr "é…置文件“%sâ€å·²å†™å…¥ã€‚\n" #: src/fs/gnunet-service-fs_push.c:629 #, c-format msgid "" "Invalid value specified for option `%s' in section `%s', content pushing " "disabled\n" msgstr "" #: src/fs/gnunet-unindex.c:89 #, c-format msgid "Unindexing at %llu/%llu (%s remaining)\n" msgstr "" #: src/fs/gnunet-unindex.c:96 #, c-format msgid "Error unindexing: %s.\n" msgstr "" #: src/fs/gnunet-unindex.c:101 msgid "Unindexing done.\n" msgstr "" #: src/fs/gnunet-unindex.c:131 #, c-format msgid "You must specify one and only one filename for unindexing.\n" msgstr "" #: src/fs/gnunet-unindex.c:148 msgid "Could not start unindex operation.\n" msgstr "" #: src/fs/gnunet-unindex.c:176 msgid "Unindex a file that was previously indexed with gnunet-publish." msgstr "" #: src/fs/plugin_block_fs.c:131 msgid "Reply mismatched in terms of namespace. Discarded.\n" msgstr "" #: src/gns/gnunet-gns.c:191 #, fuzzy msgid "Failed to connect to GNS\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/gns/gnunet-gns.c:232 msgid "try to shorten a given GNS name" msgstr "" #: src/gns/gnunet-gns.c:235 msgid "Lookup a record using GNS (NOT IMPLEMENTED)" msgstr "" #: src/gns/gnunet-gns.c:238 msgid "Get the authority of a particular name" msgstr "" #: src/gns/gnunet-gns.c:241 msgid "Specify the type of the record lookup" msgstr "" #: src/gns/gnunet-gns.c:244 msgid "No unneeded output" msgstr "" #: src/gns/gnunet-gns.c:255 msgid "GNUnet GNS access tool" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:280 #, fuzzy, c-format msgid "Unsupported form value `%s'\n" msgstr "未知的命令“%sâ€ã€‚\n" #: src/gns/gnunet-gns-fcfsd.c:333 #, fuzzy, c-format msgid "Failed to create record for domain `%s': %s\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/gns/gnunet-gns-fcfsd.c:377 #, c-format msgid "Found existing name `%s' for the given key\n" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:439 #, c-format msgid "Found %u existing records for domain `%s'\n" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:498 #, fuzzy, c-format msgid "Failed to create page for `%s'\n" msgstr "å‘逿¶ˆæ¯å¤±è´¥ã€‚\n" #: src/gns/gnunet-gns-fcfsd.c:514 #, fuzzy, c-format msgid "Failed to setup post processor for `%s'\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/gns/gnunet-gns-fcfsd.c:725 src/gns/gnunet-gns-fcfsd.c:737 #, fuzzy, c-format msgid "Option `%s' not specified in configuration section `%s'\n" msgstr "é…置文件“%sâ€å·²å†™å…¥ã€‚\n" #: src/gns/gnunet-gns-fcfsd.c:747 src/namestore/gnunet-namestore.c:299 #, fuzzy msgid "Failed to read or create private zone key\n" msgstr "无法为守护程åºåˆ›å»ºç”¨æˆ·è´¦æˆ·ã€‚" #: src/gns/gnunet-gns-fcfsd.c:757 src/namestore/gnunet-namestore.c:310 #, fuzzy msgid "Failed to connect to namestore\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/gns/gnunet-gns-fcfsd.c:773 src/gns/gnunet-gns-proxy.c:525 #, fuzzy msgid "Failed to start HTTP server\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/gns/gnunet-gns-fcfsd.c:804 msgid "GNUnet GNS first come first serve registration service" msgstr "" #: src/gns/gnunet-gns-proxy.c:800 msgid "listen on specified port" msgstr "" #: src/gns/gnunet-gns-proxy.c:811 msgid "GNUnet GNS proxy" msgstr "" #: src/hello/gnunet-hello.c:122 msgid "Call with name of HELLO file to modify.\n" msgstr "" #: src/hello/gnunet-hello.c:128 #, fuzzy, c-format msgid "Error accessing file `%s': %s\n" msgstr "创建用户出错" #: src/hello/gnunet-hello.c:136 #, c-format msgid "File `%s' is too big to be a HELLO\n" msgstr "" #: src/hello/gnunet-hello.c:143 #, c-format msgid "File `%s' is too small to be a HELLO\n" msgstr "" #: src/hello/gnunet-hello.c:153 src/hello/gnunet-hello.c:181 #, fuzzy, c-format msgid "Error opening file `%s': %s\n" msgstr "创建用户出错" #: src/hello/gnunet-hello.c:169 #, c-format msgid "Did not find well-formed HELLO in file `%s'\n" msgstr "" #: src/hello/gnunet-hello.c:193 #, fuzzy, c-format msgid "Error writing HELLO to file `%s': %s\n" msgstr "创建用户出错" #: src/hostlist/gnunet-daemon-hostlist.c:264 msgid "" "None of the functions for the hostlist daemon were enabled. I have no " "reason to run!\n" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:317 msgid "advertise our hostlist to other peers" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:322 msgid "" "bootstrap using hostlists (it is highly recommended that you always use this " "option)" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:325 msgid "enable learning about hostlist servers from other peers" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:329 msgid "provide a hostlist server" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:341 msgid "GNUnet hostlist server and client" msgstr "" #: src/hostlist/hostlist-client.c:289 msgid "# bytes downloaded from hostlist servers" msgstr "" #: src/hostlist/hostlist-client.c:310 src/hostlist/hostlist-client.c:340 msgid "# invalid HELLOs downloaded from hostlist servers" msgstr "" #: src/hostlist/hostlist-client.c:313 src/hostlist/hostlist-client.c:343 #, c-format msgid "Invalid `%s' message received from hostlist at `%s'\n" msgstr "" #: src/hostlist/hostlist-client.c:331 msgid "# valid HELLOs downloaded from hostlist servers" msgstr "" #: src/hostlist/hostlist-client.c:375 src/hostlist/hostlist-client.c:396 #, c-format msgid "No `%s' specified in `%s' configuration, will not bootstrap.\n" msgstr "" #: src/hostlist/hostlist-client.c:473 src/hostlist/hostlist-client.c:683 #: src/hostlist/hostlist-client.c:689 src/hostlist/hostlist-client.c:741 #: src/hostlist/hostlist-client.c:750 src/hostlist/hostlist-client.c:871 #: src/hostlist/hostlist-client.c:961 src/hostlist/hostlist-client.c:966 #: src/transport/plugin_transport_http_client.c:110 #: src/transport/plugin_transport_http_client.c:125 #, c-format msgid "%s failed at %s:%d: `%s'\n" msgstr "" #: src/hostlist/hostlist-client.c:593 src/hostlist/hostlist-client.c:1331 msgid "# advertised hostlist URIs" msgstr "" #: src/hostlist/hostlist-client.c:623 #, c-format msgid "# advertised URI `%s' downloaded" msgstr "" #: src/hostlist/hostlist-client.c:664 #, c-format msgid "" "Advertised hostlist with URI `%s' could not be downloaded. Advertised URI " "gets dismissed.\n" msgstr "" #: src/hostlist/hostlist-client.c:802 #, c-format msgid "Timeout trying to download hostlist from `%s'\n" msgstr "" #: src/hostlist/hostlist-client.c:816 #, c-format msgid "Download limit of %u bytes exceeded, stopping download\n" msgstr "" #: src/hostlist/hostlist-client.c:836 #, fuzzy, c-format msgid "Download of hostlist from `%s' failed: `%s'\n" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/hostlist/hostlist-client.c:842 #, c-format msgid "Download of hostlist `%s' completed.\n" msgstr "" #: src/hostlist/hostlist-client.c:850 #, c-format msgid "Adding successfully tested hostlist `%s' datastore.\n" msgstr "" #: src/hostlist/hostlist-client.c:903 #, c-format msgid "Bootstrapping using hostlist at `%s'.\n" msgstr "" #: src/hostlist/hostlist-client.c:911 msgid "# hostlist downloads initiated" msgstr "" #: src/hostlist/hostlist-client.c:1037 src/hostlist/hostlist-client.c:1505 msgid "# milliseconds between hostlist downloads" msgstr "" #: src/hostlist/hostlist-client.c:1046 #, c-format msgid "Have %u/%u connections. Will consider downloading hostlist in %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1084 msgid "Scheduled saving of hostlists\n" msgstr "" #: src/hostlist/hostlist-client.c:1088 #, c-format msgid "Hostlists will be saved to file again in %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1111 src/hostlist/hostlist-client.c:1127 msgid "# active connections" msgstr "" #: src/hostlist/hostlist-client.c:1242 #, c-format msgid "Initial time between hostlist downloads is %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1273 #, c-format msgid "" "No `%s' specified in `%s' configuration, cannot load hostlists from file.\n" msgstr "" #: src/hostlist/hostlist-client.c:1279 #, c-format msgid "Loading saved hostlist entries from file `%s' \n" msgstr "" #: src/hostlist/hostlist-client.c:1283 #, c-format msgid "Hostlist file `%s' is not existing\n" msgstr "" #: src/hostlist/hostlist-client.c:1294 #, fuzzy, c-format msgid "Could not open file `%s' for reading to load hostlists: %s\n" msgstr "无法解æžâ€œ%sâ€æ¥ç¡®å®šå·²æ–¹çš„ IP 地å€ï¼š%s\n" #: src/hostlist/hostlist-client.c:1327 #, c-format msgid "%u hostlist URIs loaded from file\n" msgstr "" #: src/hostlist/hostlist-client.c:1329 msgid "# hostlist URIs read from file" msgstr "" #: src/hostlist/hostlist-client.c:1362 #, c-format msgid "" "No `%s' specified in `%s' configuration, cannot save hostlists to file.\n" msgstr "" #: src/hostlist/hostlist-client.c:1376 #, fuzzy, c-format msgid "Could not open file `%s' for writing to save hostlists: %s\n" msgstr "无法解æžâ€œ%sâ€æ¥ç¡®å®šå·²æ–¹çš„ IP 地å€ï¼š%s\n" #: src/hostlist/hostlist-client.c:1381 #, c-format msgid "Writing %u hostlist URIs to `%s'\n" msgstr "" #: src/hostlist/hostlist-client.c:1405 src/hostlist/hostlist-client.c:1422 #, c-format msgid "Error writing hostlist URIs to file `%s'\n" msgstr "" #: src/hostlist/hostlist-client.c:1417 msgid "# hostlist URIs written to file" msgstr "" #: src/hostlist/hostlist-client.c:1470 msgid "Learning is enabled on this peer\n" msgstr "" #: src/hostlist/hostlist-client.c:1473 #, c-format msgid "Hostlists will be saved to file again in %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1482 msgid "Learning is not enabled on this peer\n" msgstr "" #: src/hostlist/hostlist-client.c:1494 #, c-format msgid "" "Since learning is not enabled on this peer, hostlist file `%s' was removed\n" msgstr "" #: src/hostlist/hostlist-client.c:1498 #, c-format msgid "Hostlist file `%s' could not be removed\n" msgstr "" #: src/hostlist/hostlist-server.c:134 msgid "bytes in hostlist" msgstr "" #: src/hostlist/hostlist-server.c:157 msgid "expired addresses encountered" msgstr "" #: src/hostlist/hostlist-server.c:184 src/hostlist/hostlist-server.c:425 #: src/peerinfo-tool/gnunet-peerinfo.c:403 #: src/peerinfo-tool/gnunet-peerinfo.c:519 #: src/topology/gnunet-daemon-topology.c:927 #, c-format msgid "Error in communication with PEERINFO service: %s\n" msgstr "" #: src/hostlist/hostlist-server.c:205 msgid "HELLOs without addresses encountered (ignored)" msgstr "" #: src/hostlist/hostlist-server.c:219 msgid "bytes not included in hostlist (size limit)" msgstr "" #: src/hostlist/hostlist-server.c:263 #, c-format msgid "Refusing `%s' request to hostlist server\n" msgstr "" #: src/hostlist/hostlist-server.c:266 msgid "hostlist requests refused (not HTTP GET)" msgstr "" #: src/hostlist/hostlist-server.c:273 msgid "Sending 100 CONTINUE reply\n" msgstr "" #: src/hostlist/hostlist-server.c:279 #, c-format msgid "Refusing `%s' request with %llu bytes of upload data\n" msgstr "" #: src/hostlist/hostlist-server.c:283 msgid "hostlist requests refused (upload data)" msgstr "" #: src/hostlist/hostlist-server.c:291 msgid "Could not handle hostlist request since I do not have a response yet\n" msgstr "" #: src/hostlist/hostlist-server.c:294 msgid "hostlist requests refused (not ready)" msgstr "" #: src/hostlist/hostlist-server.c:298 msgid "Received request for our hostlist\n" msgstr "" #: src/hostlist/hostlist-server.c:299 msgid "hostlist requests processed" msgstr "" #: src/hostlist/hostlist-server.c:341 msgid "# hostlist advertisements send" msgstr "" #: src/hostlist/hostlist-server.c:388 msgid "Advertisement message could not be queued by core\n" msgstr "" #: src/hostlist/hostlist-server.c:561 #, c-format msgid "Invalid port number %llu. Exiting.\n" msgstr "" #: src/hostlist/hostlist-server.c:570 #, c-format msgid "Hostlist service starts on %s:%llu\n" msgstr "" #: src/hostlist/hostlist-server.c:584 #, c-format msgid "Address to obtain hostlist: `%s'\n" msgstr "" #: src/hostlist/hostlist-server.c:624 #, fuzzy, c-format msgid "`%s' is not a valid IP address! Ignoring BINDTOIP.\n" msgstr "“%sâ€ä¸å¯ç”¨ã€‚\n" #: src/hostlist/hostlist-server.c:666 #, c-format msgid "Could not start hostlist HTTP server on port %u\n" msgstr "" #: src/integration-tests/connection_watchdog.c:997 #, c-format msgid "Transport plugin: `%s' port %llu\n" msgstr "" #: src/integration-tests/connection_watchdog.c:1030 #, fuzzy, c-format msgid "Found %u transport plugins: `%s'\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/integration-tests/connection_watchdog.c:1089 msgid "Send ping messages to test connectivity (default == NO)" msgstr "" #: src/integration-tests/connection_watchdog.c:1095 #: src/template/gnunet-template.c:68 msgid "help text" msgstr "" #: src/mesh/gnunet-service-mesh.c:4590 msgid "Wrong CORE service\n" msgstr "" #: src/mesh/gnunet-service-mesh.c:4784 #, fuzzy msgid "Mesh service is lacking key configuration settings. Exiting.\n" msgstr "ç«‹å³ä¿å­˜é…置?" #: src/mesh/gnunet-service-mesh.c:4793 #, fuzzy msgid "Mesh service could not access hostkey. Exiting.\n" msgstr "找ä¸åˆ°æŽ¥å£â€œ%sâ€çš„一个 IP 地å€ã€‚\n" #: src/mysql/mysql.c:174 #, c-format msgid "Trying to use file `%s' for MySQL configuration.\n" msgstr "" #: src/mysql/mysql.c:181 #, fuzzy, c-format msgid "Could not access file `%s': %s\n" msgstr "无法解æžâ€œ%sâ€(%s):%s\n" #: src/namestore/gnunet-namestore.c:157 #, c-format msgid "Adding record failed: %s\n" msgstr "" #: src/namestore/gnunet-namestore.c:183 #, c-format msgid "Deleting record failed: %s\n" msgstr "" #: src/namestore/gnunet-namestore.c:239 #, c-format msgid "\tCorrupt or unsupported record of type %u\n" msgstr "" #: src/namestore/gnunet-namestore.c:276 #, c-format msgid "Option `%s' not given, but I need a zone key file!\n" msgstr "" #: src/namestore/gnunet-namestore.c:281 #, fuzzy, c-format msgid "Using default zone file `%s'\n" msgstr "å¸è½½ GNUnet æœåŠ¡" #: src/namestore/gnunet-namestore.c:291 #, c-format msgid "No options given\n" msgstr "" #: src/namestore/gnunet-namestore.c:321 #, fuzzy, c-format msgid "Unsupported type `%s'\n" msgstr "未知的命令“%sâ€ã€‚\n" #: src/namestore/gnunet-namestore.c:328 src/namestore/gnunet-namestore.c:350 #: src/namestore/gnunet-namestore.c:374 src/namestore/gnunet-namestore.c:384 #: src/namestore/gnunet-namestore.c:409 #, fuzzy, c-format msgid "Missing option `%s' for operation `%s'\n" msgstr "é…置文件“%sâ€å·²å†™å…¥ã€‚\n" #: src/namestore/gnunet-namestore.c:329 src/namestore/gnunet-namestore.c:351 msgid "add/del" msgstr "" #: src/namestore/gnunet-namestore.c:341 #, c-format msgid "Value `%s' invalid for record type `%s'\n" msgstr "" #: src/namestore/gnunet-namestore.c:366 #, fuzzy, c-format msgid "Invalid time format `%s'\n" msgstr "IP æ ¼å¼æ— æ•ˆï¼šâ€œ%sâ€\n" #: src/namestore/gnunet-namestore.c:375 src/namestore/gnunet-namestore.c:385 msgid "add" msgstr "" #: src/namestore/gnunet-namestore.c:410 msgid "del" msgstr "" #: src/namestore/gnunet-namestore.c:462 msgid "add record" msgstr "" #: src/namestore/gnunet-namestore.c:465 msgid "delete record" msgstr "" #: src/namestore/gnunet-namestore.c:468 msgid "display records" msgstr "" #: src/namestore/gnunet-namestore.c:471 msgid "" "expiration time for record to use (for adding only), \"never\" is possible" msgstr "" #: src/namestore/gnunet-namestore.c:474 msgid "name of the record to add/delete/display" msgstr "" #: src/namestore/gnunet-namestore.c:477 msgid "type of the record to add/delete/display" msgstr "" #: src/namestore/gnunet-namestore.c:480 msgid "value of the record to add/delete" msgstr "" #: src/namestore/gnunet-namestore.c:483 msgid "create or list public record" msgstr "" #: src/namestore/gnunet-namestore.c:486 msgid "create or list non-authority record" msgstr "" #: src/namestore/gnunet-namestore.c:489 msgid "filename with the zone key" msgstr "" #: src/namestore/gnunet-namestore.c:500 #, fuzzy msgid "GNUnet zone manipulation tool" msgstr "GNUnet é…ç½®" #: src/namestore/gnunet-service-namestore.c:143 #, c-format msgid "File zone `%s' but corrupt content already exists, failed to write! \n" msgstr "" #: src/namestore/gnunet-service-namestore.c:154 #, c-format msgid "File zone `%s' containing this key already exists\n" msgstr "" #: src/namestore/gnunet-service-namestore.c:160 #, c-format msgid "" "File zone `%s' but different zone key already exists, failed to write! \n" msgstr "" #: src/namestore/gnunet-service-namestore.c:198 #, fuzzy, c-format msgid "Stored zonekey for zone `%s' in file `%s'\n" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/namestore/gnunet-service-namestore.c:1909 msgid "No directory to load zonefiles specified in configuration\n" msgstr "" #: src/namestore/gnunet-service-namestore.c:1918 #, c-format msgid "Creating directory `%s' for zone files failed!\n" msgstr "" #: src/namestore/namestore_api.c:315 src/namestore/namestore_api.c:353 msgid "Namestore added record successfully" msgstr "" #: src/namestore/namestore_api.c:323 msgid "Namestore failed to add record" msgstr "" #: src/namestore/namestore_api.c:361 msgid "Namestore record already existed" msgstr "" #: src/namestore/namestore_api.c:368 msgid "Namestore failed to add record\n" msgstr "" #: src/namestore/namestore_api.c:401 #, fuzzy msgid "Namestore removed record successfully" msgstr "GNUnet æœåŠ¡å®‰è£…æˆåŠŸã€‚\n" #: src/namestore/namestore_api.c:408 msgid "No records for entry" msgstr "" #: src/namestore/namestore_api.c:415 #, fuzzy msgid "Could not find record to remove" msgstr "无法连接到 %s:%u:%s\n" #: src/namestore/namestore_api.c:422 #, fuzzy msgid "Failed to create new signature" msgstr "å‘逿¶ˆæ¯å¤±è´¥ã€‚\n" #: src/namestore/namestore_api.c:429 msgid "Failed to put new set of records in database" msgstr "" #: src/nat/gnunet-nat-server.c:279 #, c-format msgid "Please pass valid port number as the first argument! (got `%s')\n" msgstr "" #: src/nat/gnunet-nat-server.c:318 msgid "GNUnet NAT traversal test helper daemon" msgstr "" #: src/nat/nat.c:799 #, c-format msgid "gnunet-helper-nat-server generated malformed address `%s'\n" msgstr "" #: src/nat/nat.c:844 #, fuzzy, c-format msgid "Failed to start %s\n" msgstr "è¿è¡Œ %s失败:%s %d\n" #: src/nat/nat.c:1111 #, fuzzy, c-format msgid "Malformed %s `%s' given in configuration!\n" msgstr "ä¿å­˜é…置失败。" #: src/nat/nat.c:1177 src/nat/nat.c:1187 #, c-format msgid "" "Configuration requires `%s', but binary is not installed properly (SUID bit " "not set). Option disabled.\n" msgstr "" #: src/nat/nat.c:1321 msgid "Internal IP address not known, cannot use ICMP NAT traversal method\n" msgstr "" #: src/nat/nat.c:1332 #, c-format msgid "Running gnunet-helper-nat-client %s %s %u\n" msgstr "" #: src/nat/nat_test.c:341 msgid "Failed to connect to `gnunet-nat-server'\n" msgstr "" #: src/nat/nat_test.c:411 #, c-format msgid "Failed to create listen socket bound to `%s' for NAT test: %s\n" msgstr "" #: src/nse/gnunet-nse-profiler.c:928 #, fuzzy msgid "Measure quality and performance of the NSE service." msgstr "无法访问该æœåŠ¡" #: src/nse/gnunet-service-nse.c:925 #, c-format msgid "Proof of work invalid: %llu!\n" msgstr "" #: src/nse/gnunet-service-nse.c:1381 src/nse/gnunet-service-nse.c:1400 #: src/nse/gnunet-service-nse.c:1421 msgid "NSE service is lacking key configuration settings. Exiting.\n" msgstr "" #: src/nse/gnunet-service-nse.c:1388 msgid "Invalid work requirement for NSE service. Exiting.\n" msgstr "" #: src/nse/gnunet-service-nse.c:1409 #, fuzzy msgid "NSE service could not access hostkey. Exiting.\n" msgstr "找ä¸åˆ°æŽ¥å£â€œ%sâ€çš„一个 IP 地å€ã€‚\n" #: src/peerinfo/gnunet-service-peerinfo.c:134 #, c-format msgid "Removing expired address of transport `%s'\n" msgstr "" #: src/peerinfo/gnunet-service-peerinfo.c:203 #, fuzzy, c-format msgid "Failed to parse HELLO in file `%s'\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/peerinfo/gnunet-service-peerinfo.c:229 msgid "# peers known" msgstr "" #: src/peerinfo/gnunet-service-peerinfo.c:254 #, c-format msgid "" "File `%s' in directory `%s' does not match naming convention. Removed.\n" msgstr "" #: src/peerinfo/gnunet-service-peerinfo.c:353 #, c-format msgid "Still no peers found in `%s'!\n" msgstr "" #: src/peerinfo/gnunet-service-peerinfo.c:710 #, c-format msgid "Importing HELLOs from `%s'\n" msgstr "" #: src/peerinfo/peerinfo_api.c:238 msgid "aborted due to explicit disconnect request" msgstr "" #: src/peerinfo/peerinfo_api.c:358 #, fuzzy msgid "failed to transmit request (service down?)" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/peerinfo/peerinfo_api.c:505 msgid "Failed to receive response from `PEERINFO' service." msgstr "" #: src/peerinfo/peerinfo_api.c:531 src/peerinfo/peerinfo_api.c:550 #: src/peerinfo/peerinfo_api.c:565 src/peerinfo/peerinfo_api.c:576 #: src/peerinfo/peerinfo_api.c:587 #, fuzzy msgid "Received invalid message from `PEERINFO' service." msgstr "“%sâ€çš„傿•°æ— æ•ˆã€‚\n" #: src/peerinfo/peerinfo_api.c:663 #, fuzzy msgid "Timeout transmitting iteration request to `PEERINFO' service." msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/peerinfo/peerinfo_api_notify.c:256 #, fuzzy, c-format msgid "Could not connect to `%s' service.\n" msgstr "无法连接到 %s:%u:%s\n" #: src/peerinfo-tool/gnunet-peerinfo.c:581 #, fuzzy msgid "Failed to parse HELLO message: missing expiration time\n" msgstr "ä¿å­˜é…置失败。" #: src/peerinfo-tool/gnunet-peerinfo.c:589 #, fuzzy msgid "Failed to parse HELLO message: invalid expiration time\n" msgstr "ä¿å­˜é…置失败。" #: src/peerinfo-tool/gnunet-peerinfo.c:598 #, fuzzy msgid "Failed to parse HELLO message: malformed\n" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/peerinfo-tool/gnunet-peerinfo.c:608 msgid "Failed to parse HELLO message: missing transport plugin\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:625 #, c-format msgid "Plugin `%s' not found\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:634 #, c-format msgid "Plugin `%s' does not support URIs yet\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:653 #, fuzzy, c-format msgid "Failed to parse `%s' as an address for plugin `%s'\n" msgstr "找ä¸åˆ°æŽ¥å£â€œ%sâ€çš„一个 IP 地å€ã€‚\n" #: src/peerinfo-tool/gnunet-peerinfo.c:685 #, c-format msgid "Failure adding HELLO: %s\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:833 #, fuzzy, c-format msgid "Could not find option `%s:%s' in configuration.\n" msgstr "找ä¸åˆ°ä¸»æœºâ€œ%sâ€çš„ IP:%s\n" #: src/peerinfo-tool/gnunet-peerinfo.c:840 #, c-format msgid "Loading hostkey from `%s' failed.\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:875 #, fuzzy, c-format msgid "Invalid URI `%s'\n" msgstr "无效æ¡ç›®ã€‚\n" #: src/peerinfo-tool/gnunet-peerinfo.c:899 #, c-format msgid "I am peer `%s'.\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:936 msgid "don't resolve host names" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:939 msgid "output only the identity strings" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:942 msgid "output our own identity only" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:945 #, fuzzy msgid "list all known peers" msgstr "列出所有网络适é…器" #: src/peerinfo-tool/gnunet-peerinfo.c:948 msgid "also output HELLO uri(s)" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:951 msgid "add given HELLO uri to the database" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:957 #, fuzzy msgid "Print information about peers." msgstr "æ— æ³•èŽ·å–æœ‰å…³ç”¨æˆ·â€œ%sâ€çš„ä¿¡æ¯ï¼š%s\n" #: src/peerinfo-tool/gnunet-peerinfo_plugins.c:105 #: src/transport/gnunet-service-transport_plugins.c:118 #, c-format msgid "Starting transport plugins `%s'\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo_plugins.c:109 #: src/transport/gnunet-service-transport_plugins.c:122 #, c-format msgid "Loading `%s' transport plugin\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo_plugins.c:129 #: src/transport/gnunet-service-transport_plugins.c:150 #, fuzzy, c-format msgid "Failed to load transport plugin for `%s'\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/postgres/postgres.c:59 #, fuzzy, c-format msgid "`%s:%s' failed at %s:%d with error: %s" msgstr "“%sâ€äºŽ %s:%d 处失败,错误为:%s\n" #: src/postgres/postgres.c:148 #, fuzzy, c-format msgid "Unable to initialize Postgres: %s" msgstr "无法åˆå§‹åŒ– SQLite:%s。\n" #: src/pt/gnunet-daemon-pt.c:264 msgid "Failed to pack DNS request. Dropping.\n" msgstr "" #: src/pt/gnunet-daemon-pt.c:270 msgid "# DNS requests mapped to VPN" msgstr "" #: src/pt/gnunet-daemon-pt.c:323 msgid "# DNS records modified" msgstr "" #: src/pt/gnunet-daemon-pt.c:500 msgid "# DNS replies intercepted" msgstr "" #: src/pt/gnunet-daemon-pt.c:506 msgid "Failed to parse DNS request. Dropping.\n" msgstr "" #: src/pt/gnunet-daemon-pt.c:602 msgid "# DNS requests dropped (timeout)" msgstr "" #: src/pt/gnunet-daemon-pt.c:632 msgid "# DNS requests intercepted" msgstr "" #: src/pt/gnunet-daemon-pt.c:637 msgid "# DNS requests dropped (DNS mesh tunnel down)" msgstr "" #: src/pt/gnunet-daemon-pt.c:645 msgid "# DNS requests dropped (malformed)" msgstr "" #: src/pt/gnunet-daemon-pt.c:716 msgid "# DNS replies received" msgstr "" #: src/pt/gnunet-daemon-pt.c:730 msgid "# DNS replies dropped (too late?)" msgstr "" #: src/pt/gnunet-daemon-pt.c:748 src/pt/gnunet-daemon-pt.c:760 msgid "# DNS requests aborted (tunnel down)" msgstr "" #: src/pt/gnunet-daemon-pt.c:898 src/pt/gnunet-daemon-pt.c:907 #: src/pt/gnunet-daemon-pt.c:930 src/pt/gnunet-daemon-pt.c:940 #, fuzzy, c-format msgid "Failed to connect to %s service. Exiting.\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/pt/gnunet-daemon-pt.c:973 msgid "Daemon to run to perform IP protocol translation to GNUnet" msgstr "" #: src/statistics/gnunet-service-statistics.c:271 #, c-format msgid "Loading %llu bytes of statistics from `%s'\n" msgstr "" #: src/statistics/gnunet-service-statistics.c:330 #, c-format msgid "Wrote %llu bytes of statistics to `%s'\n" msgstr "" #: src/statistics/gnunet-statistics.c:122 #, fuzzy msgid "Failed to obtain statistics.\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/statistics/gnunet-statistics.c:199 #, c-format msgid "No subsystem or name given\n" msgstr "" #: src/statistics/gnunet-statistics.c:207 #, fuzzy, c-format msgid "Failed to initialize watch routine\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/statistics/gnunet-statistics.c:227 msgid "limit output to statistics for the given NAME" msgstr "" #: src/statistics/gnunet-statistics.c:230 msgid "make the value being set persistent" msgstr "" #: src/statistics/gnunet-statistics.c:233 msgid "limit output to the given SUBSYSTEM" msgstr "" #: src/statistics/gnunet-statistics.c:236 msgid "just print the statistics value" msgstr "" #: src/statistics/gnunet-statistics.c:239 msgid "watch value continously" msgstr "" #: src/statistics/gnunet-statistics.c:246 msgid "Print statistics about GNUnet operations." msgstr "" #: src/statistics/statistics_api.c:456 #, fuzzy msgid "Could not save some persistent statistics\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/statistics/statistics_api.c:999 msgid "" "Failed to receive acknowledgement from statistics service, some statistics " "might have been lost!\n" msgstr "" #: src/testing/gnunet-testing.c:157 #, fuzzy msgid "Could not read hostkeys file, specify hostkey file with -H!\n" msgstr "找ä¸åˆ°æŽ¥å£â€œ%sâ€çš„一个 IP 地å€ã€‚\n" #: src/testing/gnunet-testing.c:159 #, c-format msgid "Specified hostkey file `%s' not found!\n" msgstr "" #: src/testing/gnunet-testing.c:273 #, fuzzy msgid "create unique configuration files" msgstr "更改é…置文件中的一个值" #: src/testing/gnunet-testing.c:275 msgid "create hostkey files from pre-computed hostkey list" msgstr "" #: src/testing/gnunet-testing.c:277 msgid "host key file" msgstr "" #: src/testing/gnunet-testing.c:279 #, fuzzy msgid "number of unique configuration files or hostkeys to create" msgstr "打å°é…置文件中的一个值到标准输出" #: src/testing/gnunet-testing.c:281 #, fuzzy msgid "configuration template" msgstr "é…置已ä¿å­˜" #: src/testing/gnunet-testing.c:287 msgid "Command line tool to access the testing library" msgstr "" #: src/testing/helper.c:56 #, fuzzy msgid "Peer is lacking HOSTKEY configuration setting.\n" msgstr "ç«‹å³ä¿å­˜é…置?" #: src/testing/helper.c:64 #, fuzzy msgid "Could not access hostkey.\n" msgstr "找ä¸åˆ°æŽ¥å£â€œ%sâ€çš„一个 IP 地å€ã€‚\n" #: src/testing/testing.c:200 msgid "`scp' does not seem to terminate (timeout copying config).\n" msgstr "" #: src/testing/testing.c:214 src/testing/testing.c:798 msgid "`scp' did not complete cleanly.\n" msgstr "" #: src/testing/testing.c:237 #, fuzzy msgid "Failed to create pipe for `gnunet-peerinfo' process.\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/testing/testing.c:238 #, fuzzy msgid "Failed to create pipe for `ssh' process.\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/testing/testing.c:286 #, fuzzy, c-format msgid "Could not start `%s' process to create hostkey.\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/testing/testing.c:293 #, fuzzy msgid "Failed to start `gnunet-peerinfo' process.\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/testing/testing.c:294 src/testing/testing.c:471 #, fuzzy msgid "Failed to start `ssh' process.\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/testing/testing.c:354 #, c-format msgid "Error reading from gnunet-peerinfo: %s\n" msgstr "" #: src/testing/testing.c:358 msgid "Malformed output from gnunet-peerinfo!\n" msgstr "" #: src/testing/testing.c:368 #, fuzzy msgid "Failed to get hostkey!\n" msgstr "å‘逿¶ˆæ¯å¤±è´¥ã€‚\n" #: src/testing/testing.c:400 msgid "`Failed while waiting for topology setup!\n" msgstr "" #: src/testing/testing.c:463 #, fuzzy, c-format msgid "Could not start `%s' process to start GNUnet.\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/testing/testing.c:470 #, fuzzy msgid "Failed to start `gnunet-arm' process.\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/testing/testing.c:493 src/testing/testing.c:600 msgid "`gnunet-arm' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:494 src/testing/testing.c:601 #: src/testing/testing.c:621 msgid "`ssh' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:570 msgid "Unable to get HELLO for peer!\n" msgstr "" #: src/testing/testing.c:620 msgid "`gnunet-arm' terminated with non-zero exit status (or timed out)!\n" msgstr "" #: src/testing/testing.c:643 src/testing/testing.c:675 msgid "either `gnunet-arm' or `ssh' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:658 src/testing/testing.c:713 msgid "shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n" msgstr "" #: src/testing/testing.c:786 msgid "`scp' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:948 #, fuzzy, c-format msgid "Starting service %s for peer `%4s'\n" msgstr "å¸è½½ GNUnet æœåŠ¡" #: src/testing/testing.c:1207 src/testing/testing_group.c:6154 #, fuzzy, c-format msgid "Could not start `%s' process to copy configuration directory.\n" msgstr "找ä¸åˆ°ä¸»æœºâ€œ%sâ€çš„ IP:%s\n" #: src/testing/testing.c:1292 src/testing/testing.c:1359 #, fuzzy, c-format msgid "Terminating peer `%4s'\n" msgstr "未知的用户“%sâ€\n" #: src/testing/testing.c:1448 #, fuzzy, c-format msgid "Setting d->dead on peer `%4s'\n" msgstr "å¸è½½ GNUnet æœåŠ¡" #: src/testing/testing.c:1601 msgid "Peer not yet running, can not change configuration at this point." msgstr "" #: src/testing/testing.c:1609 #, fuzzy msgid "Failed to write new configuration to disk." msgstr "ä¿å­˜é…置失败。" #: src/testing/testing.c:1636 #, fuzzy, c-format msgid "Could not start `%s' process to copy configuration file.\n" msgstr "找ä¸åˆ°ä¸»æœºâ€œ%sâ€çš„ IP:%s\n" #: src/testing/testing.c:1639 #, fuzzy msgid "Failed to copy new configuration to remote machine." msgstr "ä¿å­˜é…置失败。" #: src/testing/testing.c:1794 #, fuzzy msgid "Peers failed to connect" msgstr "" "\n" "按任æ„键继续\n" #: src/testing/testing.c:1922 #, fuzzy msgid "Failed to connect to core service of first peer!\n" msgstr "加载 sqstore æœåŠ¡å¤±è´¥ã€‚æ£€æŸ¥æ‚¨çš„é…ç½®ï¼\n" #: src/testing/testing.c:2145 msgid "Peers are not fully running yet, can not connect!\n" msgstr "" #: src/testing/testing_group.c:1895 src/testing/testing_group.c:1907 #: src/testing/testing_group.c:2008 src/testing/testing_group.c:2065 #: src/testing/testing_group.c:2152 src/testing/testing_group.c:2172 #: src/testing/testing_group.c:2302 src/testing/testing_peergroup.c:950 #, fuzzy, c-format msgid "Invalid value `%s' for option `%s' in section `%s': expected float\n" msgstr "é…ç½®ä¸æ»¡è¶³é…置规范文件“%sâ€çš„约æŸï¼\n" #: src/testing/testing_group.c:2160 #, c-format msgid "" "Invalid value `%s' for option `%s' in section `%s': got %f, needed value " "greater than 0\n" msgstr "" #: src/testing/testing_group.c:2877 src/testing/testing_group.c:3063 #, c-format msgid "" "No `%s' specified in peer configuration in section `%s', cannot copy friends " "file!\n" msgstr "" #: src/testing/testing_group.c:3957 msgid "Creating no allowed topology (all peers can connect at core level)\n" msgstr "" #: src/testing/testing_group.c:5226 msgid "Unknown topology specification, can't connect peers!\n" msgstr "" #: src/testing/testing_group.c:5944 src/transport/transport-testing.c:636 #, fuzzy msgid "Could not read hostkeys file!\n" msgstr "找ä¸åˆ°æŽ¥å£â€œ%sâ€çš„一个 IP 地å€ã€‚\n" #: src/testing/testing_group.c:6011 #, fuzzy, c-format msgid "Could not create configuration for peer number %u on `%s'!\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/testing/testing_new.c:169 msgid "tmppath cannot be NULL\n" msgstr "" #: src/testing/testing_new.c:356 #, c-format msgid "Hostkeys file not found: %s\n" msgstr "" #: src/testing/testing_new.c:365 #, fuzzy, c-format msgid "Could not open hostkeys file: %s\n" msgstr "找ä¸åˆ°æŽ¥å£â€œ%sâ€çš„一个 IP 地å€ã€‚\n" #: src/testing/testing_new.c:380 #, c-format msgid "Incorrect hostkey file format: %s\n" msgstr "" #: src/testing/testing_new.c:437 #, c-format msgid "Key number %u does not exist\n" msgstr "" #: src/testing/testing_new.c:446 #, fuzzy, c-format msgid "Error while decoding key %u\n" msgstr "è§£æž dscl 输出时出错。\n" #: src/testing/testing_new.c:680 #, fuzzy msgid "Failed to create configuration for peer (not enough free ports?)\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/testing/testing_new.c:691 #, c-format msgid "" "You attempted to create a testbed with more than %u hosts. Please " "precompute more hostkeys first.\n" msgstr "" #: src/testing/testing_new.c:704 #, fuzzy, c-format msgid "Failed to initialize hostkey for peer %u\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/testing/testing_new.c:734 #, fuzzy, c-format msgid "Failed to write hostkey file for peer %u: %s\n" msgstr "å‘逿¶ˆæ¯å¤±è´¥ã€‚\n" #: src/testing/testing_new.c:751 #, fuzzy, c-format msgid "Failed to write configuration file `%s' for peer %u: %s\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/testing/testing_new.c:791 #, fuzzy, c-format msgid "Failed to start `%s': %s\n" msgstr "è¿è¡Œ %s失败:%s %d\n" #: src/testing/testing_new.c:959 #, fuzzy, c-format msgid "Failed to load configuration from %s\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/topology/gnunet-daemon-topology.c:259 msgid "# peers blacklisted" msgstr "" #: src/topology/gnunet-daemon-topology.c:392 msgid "# connect requests issued to transport" msgstr "" #: src/topology/gnunet-daemon-topology.c:730 #: src/topology/gnunet-daemon-topology.c:815 msgid "# friends connected" msgstr "" #: src/topology/gnunet-daemon-topology.c:996 msgid "Failed to connect to core service, can not manage topology!\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1026 #, c-format msgid "Option `%s' in section `%s' not specified!\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1039 #, c-format msgid "Could not read friends list `%s'\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1045 #, c-format msgid "Friends file `%s' is empty.\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1054 #, c-format msgid "Failed to read friends list from `%s': out of memory\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1062 #, c-format msgid "Failed to read friends list from `%s'\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1082 #, c-format msgid "" "Syntax error in topology specification at offset %llu, skipping bytes.\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1095 #, c-format msgid "" "Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1105 #, fuzzy, c-format msgid "Found friend `%s' in configuration\n" msgstr "" "\n" "结æŸé…置。\n" #: src/topology/gnunet-daemon-topology.c:1111 #, c-format msgid "Found myself `%s' in friend list (useless, ignored)\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1121 #, fuzzy msgid "# friends in configuration" msgstr "" "\n" "结æŸé…置。\n" #: src/topology/gnunet-daemon-topology.c:1127 msgid "" "Fewer friends specified than required by minimum friend count. Will only " "connect to friends.\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1134 msgid "" "More friendly connections required than target total number of connections.\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1169 msgid "# HELLO messages received" msgstr "" #: src/topology/gnunet-daemon-topology.c:1224 msgid "# HELLO messages gossipped" msgstr "" #: src/topology/gnunet-daemon-topology.c:1363 msgid "GNUnet topology control (maintaining P2P mesh and F2F constraints)" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:246 #, fuzzy, c-format msgid "Could not read blacklist file `%s'\n" msgstr "无法解æžâ€œ%sâ€(%s):%s\n" #: src/transport/gnunet-service-transport_blacklist.c:252 #, c-format msgid "Blacklist file `%s' is empty.\n" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:263 #, fuzzy, c-format msgid "Failed to read blacklist from `%s'\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/transport/gnunet-service-transport_blacklist.c:284 #: src/transport/gnunet-service-transport_blacklist.c:308 #, fuzzy, c-format msgid "Syntax error in blacklist file at offset %llu, giving up!\n" msgstr "é…置文件“%sâ€ç¬¬ %d 行有语法错误。\n" #: src/transport/gnunet-service-transport_blacklist.c:295 #: src/transport/gnunet-service-transport_blacklist.c:331 #, c-format msgid "Syntax error in blacklist file at offset %llu, skipping bytes.\n" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:345 #, fuzzy, c-format msgid "Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n" msgstr "é…置文件“%sâ€ç¬¬ %d 行有语法错误。\n" #: src/transport/gnunet-service-transport_blacklist.c:359 #, c-format msgid "Found myself `%s' in blacklist (useless, ignored)\n" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:514 #: src/transport/gnunet-service-transport_blacklist.c:747 msgid "# disconnects due to blacklist" msgstr "" #: src/transport/gnunet-service-transport.c:163 msgid "# bytes payload discarded due to not connected peer " msgstr "" #: src/transport/gnunet-service-transport.c:237 msgid "# bytes total received" msgstr "" #: src/transport/gnunet-service-transport.c:284 msgid "# bytes payload received" msgstr "" #: src/transport/gnunet-service-transport.c:582 msgid "Transport service is lacking key configuration settings. Exiting.\n" msgstr "" #: src/transport/gnunet-service-transport.c:591 msgid "Transport service could not access hostkey. Exiting.\n" msgstr "" #: src/transport/gnunet-service-transport_clients.c:352 #, c-format msgid "Dropping message of type %u and size %u, have %u/%u messages pending\n" msgstr "" #: src/transport/gnunet-service-transport_clients.c:357 msgid "# messages dropped due to slow client" msgstr "" #: src/transport/gnunet-service-transport_clients.c:503 #, c-format msgid "Rejecting control connection from peer `%s', which is not me!\n" msgstr "" #: src/transport/gnunet-service-transport_clients.c:631 msgid "# bytes payload dropped (other peer was not connected)" msgstr "" #: src/transport/gnunet-service-transport_clients.c:682 msgid "# REQUEST CONNECT messages received" msgstr "" #: src/transport/gnunet-service-transport_hello.c:172 msgid "# refreshed my HELLO" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1032 msgid "# DISCONNECT messages sent" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1148 #: src/transport/gnunet-service-transport_neighbours.c:1482 msgid "# bytes in message queue for other peers" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1153 msgid "# messages transmitted to other peers" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1158 msgid "# transmission failures for messages to other peers" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1215 msgid "# messages timed out while in transport queue" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1254 msgid "# keepalives sent" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1278 msgid "# KEEPALIVE messages discarded (peer unknown)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1286 msgid "# KEEPALIVE messages discarded (no session)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1323 msgid "# KEEPALIVE_RESPONSE messages discarded (not connected)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1332 msgid "# KEEPALIVE_RESPONSE messages discarded (not expected)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1388 msgid "# messages discarded due to lack of neighbour record" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1422 msgid "# bandwidth quota violations by other peers" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1438 msgid "# ms throttling suggested" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2544 msgid "# unexpected CONNECT_ACK messages (no peer)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2559 #: src/transport/gnunet-service-transport_neighbours.c:2585 msgid "# unexpected CONNECT_ACK messages (not ready)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2598 msgid "# unexpected CONNECT_ACK messages (waiting on ATS)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2627 msgid "# unexpected CONNECT_ACK messages (disconnecting)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2807 msgid "# unexpected SESSION ACK messages" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2856 msgid "# SET QUOTA messages ignored (no such peer)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2870 msgid "# disconnects due to quota of 0" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2901 msgid "# disconnect messages ignored (old format)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2912 msgid "# disconnect messages ignored (timestamp)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2943 msgid "# other peer asked to disconnect from us" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:3020 msgid "# disconnected from peer upon explicit request" msgstr "" #: src/transport/gnunet-service-transport_plugins.c:111 msgid "Transport service is lacking NEIGHBOUR_LIMIT option.\n" msgstr "" #: src/transport/gnunet-service-transport_validation.c:414 msgid "# address records discarded" msgstr "" #: src/transport/gnunet-service-transport_validation.c:463 #, c-format msgid "" "Not transmitting `%s' with `%s', message too big (%u bytes!). This should " "not happen.\n" msgstr "" #: src/transport/gnunet-service-transport_validation.c:512 msgid "# PING without HELLO messages sent" msgstr "" #: src/transport/gnunet-service-transport_validation.c:570 msgid "# address revalidations started" msgstr "" #: src/transport/gnunet-service-transport_validation.c:805 msgid "# PING message for different peer received" msgstr "" #: src/transport/gnunet-service-transport_validation.c:840 #, c-format msgid "" "Not confirming PING with address `%s' since I cannot confirm having this " "address.\n" msgstr "" #: src/transport/gnunet-service-transport_validation.c:924 msgid "# PONGs unicast via reliable transport" msgstr "" #: src/transport/gnunet-service-transport_validation.c:933 msgid "# PONGs multicast to all available addresses" msgstr "" #: src/transport/gnunet-service-transport_validation.c:1055 msgid "# PONGs dropped, no matching pending validation" msgstr "" #: src/transport/gnunet-service-transport_validation.c:1080 msgid "# PONGs dropped, signature expired" msgstr "" #: src/transport/gnunet-service-transport_validation.c:1136 #, c-format msgid "Adding `%s' without addresses for peer `%s'\n" msgstr "" #: src/transport/gnunet-transport.c:260 msgid "No transport plugins configured, peer will never communicate\n" msgstr "" #: src/transport/gnunet-transport.c:273 #, c-format msgid "No port configured for plugin `%s', cannot test it\n" msgstr "" #: src/transport/gnunet-transport.c:323 #, c-format msgid "Received %llu bytes/s (%llu bytes in %llu ms)\n" msgstr "" #: src/transport/gnunet-transport.c:330 #, c-format msgid "Transmitted %llu bytes/s (%llu bytes in %llu ms)\n" msgstr "" #: src/transport/gnunet-transport.c:363 #, c-format msgid "Transmitting %u bytes to %s\n" msgstr "" #: src/transport/gnunet-transport.c:383 #, fuzzy, c-format msgid "Connected to %s\n" msgstr "“%sâ€å·²è¿žæŽ¥åˆ°â€œ%sâ€ã€‚\n" #: src/transport/gnunet-transport.c:414 #, fuzzy, c-format msgid "Disconnected from %s\n" msgstr "“%sâ€å·²è¿žæŽ¥åˆ°â€œ%sâ€ã€‚\n" #: src/transport/gnunet-transport.c:443 #, c-format msgid "Received %u bytes from %s\n" msgstr "" #: src/transport/gnunet-transport.c:466 #, fuzzy, c-format msgid "Peer `%s': %s %s\n" msgstr "è¿è¡Œ %s失败:%s %d\n" #: src/transport/gnunet-transport.c:473 #, c-format msgid "Peer `%s': %s \n" msgstr "" #: src/transport/gnunet-transport.c:501 #, fuzzy, c-format msgid "Peer `%s' disconnected\n" msgstr "" "\n" "按任æ„键继续\n" #: src/transport/gnunet-transport.c:569 #, fuzzy, c-format msgid "Failed to parse peer identity `%s'\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/transport/gnunet-transport.c:618 msgid "measure how fast we are receiving data (until CTRL-C)" msgstr "" #: src/transport/gnunet-transport.c:621 #, fuzzy msgid "try to connect to the given peer" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/transport/gnunet-transport.c:624 msgid "provide information about all current connections (once)" msgstr "" #: src/transport/gnunet-transport.c:627 msgid "provide information about all current connections (continuously)" msgstr "" #: src/transport/gnunet-transport.c:630 msgid "do not resolve hostnames" msgstr "" #: src/transport/gnunet-transport.c:634 msgid "send data for benchmarking to the other peer (until CTRL-C)" msgstr "" #: src/transport/gnunet-transport.c:637 msgid "test transport configuration (involves external server)" msgstr "" #: src/transport/gnunet-transport.c:645 #, fuzzy msgid "Direct access to transport service." msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/transport/plugin_transport_http.c:1100 msgid "Disabling IPv6 since it is not supported on this system!\n" msgstr "" #: src/transport/plugin_transport_http.c:1149 #, fuzzy msgid "Require valid port number for service in configuration!\n" msgstr "ä¿å­˜é…置失败。" #: src/transport/plugin_transport_http.c:1174 src/util/service.c:1036 #, fuzzy, c-format msgid "Failed to resolve `%s': %s\n" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/transport/plugin_transport_http.c:1191 src/util/service.c:1053 #, fuzzy, c-format msgid "Failed to find %saddress for `%s'.\n" msgstr "找ä¸åˆ°æŽ¥å£â€œ%sâ€çš„一个 IP 地å€ã€‚\n" #: src/transport/plugin_transport_http.c:1296 #, c-format msgid "Found %u addresses to report to NAT service\n" msgstr "" #: src/transport/plugin_transport_http.c:1309 #, c-format msgid "FREEING %s\n" msgstr "" #: src/transport/plugin_transport_http.c:1386 msgid "Neither IPv4 nor IPv6 are enabled! Fix in configuration\n" msgstr "" #: src/transport/plugin_transport_http.c:1399 #, fuzzy msgid "Port is required! Fix in configuration\n" msgstr "" "\n" "结æŸé…置。\n" #: src/transport/plugin_transport_http.c:1410 msgid "Port 0, client only mode\n" msgstr "" #: src/transport/plugin_transport_http.c:1430 #, c-format msgid "" "Specific IPv4 address `%s' for plugin %s in configuration file is invalid! " "Binding to all addresses!\n" msgstr "" #: src/transport/plugin_transport_http.c:1460 #, c-format msgid "" "Specific IPv6 address `%s' for plugin %s in configuration file is invalid! " "Binding to all addresses!\n" msgstr "" #: src/transport/plugin_transport_http_client.c:624 #, c-format msgid "Could not initialize curl multi handle, failed to start %s plugin!\n" msgstr "" #: src/transport/plugin_transport_http_server.c:178 msgid "" "Could not create a new TLS certificate, program `gnunet-transport-" "certificate-creation' could not be started!\n" msgstr "" #: src/transport/plugin_transport_http_server.c:202 msgid "No usable TLS certificate found and creating one failed!\n" msgstr "" #: src/transport/plugin_transport_tcp.c:591 #, c-format msgid "Unexpected address length: %u bytes\n" msgstr "" #: src/transport/plugin_transport_tcp.c:767 #: src/transport/plugin_transport_tcp.c:856 #: src/transport/plugin_transport_tcp.c:906 #: src/transport/plugin_transport_tcp.c:992 #: src/transport/plugin_transport_tcp.c:1086 #: src/transport/plugin_transport_tcp.c:1103 msgid "# bytes currently in TCP buffers" msgstr "" #: src/transport/plugin_transport_tcp.c:774 #: src/transport/plugin_transport_tcp.c:963 #: src/transport/plugin_transport_tcp.c:1761 #: src/transport/plugin_transport_tcp.c:2390 msgid "# TCP sessions active" msgstr "" #: src/transport/plugin_transport_tcp.c:860 msgid "# bytes discarded by TCP (timeout)" msgstr "" #: src/transport/plugin_transport_tcp.c:909 msgid "# bytes transmitted via TCP" msgstr "" #: src/transport/plugin_transport_tcp.c:996 msgid "# bytes discarded by TCP (disconnect)" msgstr "" #: src/transport/plugin_transport_tcp.c:1290 #, c-format msgid "Address of unexpected length: %u\n" msgstr "" #: src/transport/plugin_transport_tcp.c:1401 msgid "# transport-service disconnect requests for TCP" msgstr "" #: src/transport/plugin_transport_tcp.c:1802 msgid "# TCP WELCOME messages received" msgstr "" #: src/transport/plugin_transport_tcp.c:1973 msgid "# bytes received via TCP" msgstr "" #: src/transport/plugin_transport_tcp.c:2043 msgid "# network-level TCP disconnect events" msgstr "" #: src/transport/plugin_transport_tcp.c:2279 src/util/service.c:940 #, c-format msgid "Require valid port number for service `%s' in configuration!\n" msgstr "" #: src/transport/plugin_transport_tcp.c:2293 #, fuzzy msgid "Failed to start service.\n" msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #: src/transport/plugin_transport_tcp.c:2355 #, c-format msgid "Failed to find option %s in section %s!\n" msgstr "" #: src/transport/plugin_transport_tcp.c:2378 #, c-format msgid "TCP transport listening on port %llu\n" msgstr "" #: src/transport/plugin_transport_tcp.c:2382 msgid "TCP transport not listening on any port (client only)\n" msgstr "" #: src/transport/plugin_transport_tcp.c:2386 #, c-format msgid "TCP transport advertises itself as being on port %llu\n" msgstr "" #: src/transport/plugin_transport_udp_broadcasting.c:128 msgid "# IPv6 multicast HELLO beacons received via udp" msgstr "" #: src/transport/plugin_transport_udp_broadcasting.c:169 msgid "# IPv4 broadcast HELLO beacons received via udp" msgstr "" #: src/transport/plugin_transport_udp_broadcasting.c:367 #, c-format msgid "Failed to set IPv4 broadcast option for broadcast socket on port %d\n" msgstr "" #: src/transport/plugin_transport_udp.c:1894 #, c-format msgid "" "UDP could not message to `%s': `%s'. Please check your network configuration " "and disable IPv6 if your connection does not have a global IPv6 address\n" msgstr "" #: src/transport/plugin_transport_udp.c:2138 #, fuzzy msgid "Failed to open UDP sockets\n" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/transport/plugin_transport_udp.c:2306 #, c-format msgid "Given `%s' option is out of range: %llu > %u\n" msgstr "" #: src/transport/plugin_transport_udp.c:2349 #, fuzzy, c-format msgid "Invalid IPv6 address: `%s'\n" msgstr "无效的进程优先级“%sâ€\n" #: src/transport/plugin_transport_unix.c:1356 #, fuzzy msgid "Failed to open UNIX sockets\n" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/transport/plugin_transport_wlan.c:561 msgid "# WLAN ACKs sent" msgstr "" #: src/transport/plugin_transport_wlan.c:580 msgid "# WLAN messages defragmented" msgstr "" #: src/transport/plugin_transport_wlan.c:626 #: src/transport/plugin_transport_wlan.c:676 #: src/transport/plugin_transport_wlan.c:1696 msgid "# WLAN sessions allocated" msgstr "" #: src/transport/plugin_transport_wlan.c:749 msgid "# WLAN message fragments sent" msgstr "" #: src/transport/plugin_transport_wlan.c:767 msgid "# WLAN messages pending (with fragmentation)" msgstr "" #: src/transport/plugin_transport_wlan.c:867 #: src/transport/plugin_transport_wlan.c:948 #: src/transport/plugin_transport_wlan.c:1698 msgid "# WLAN MAC endpoints allocated" msgstr "" #: src/transport/plugin_transport_wlan.c:1119 msgid "# HELLO messages received via WLAN" msgstr "" #: src/transport/plugin_transport_wlan.c:1140 msgid "# fragments received via WLAN" msgstr "" #: src/transport/plugin_transport_wlan.c:1150 msgid "# ACKs received via WLAN" msgstr "" #: src/transport/plugin_transport_wlan.c:1207 msgid "# WLAN DATA messages discarded due to CRC32 error" msgstr "" #: src/transport/plugin_transport_wlan.c:1306 msgid "# DATA messages received via WLAN" msgstr "" #: src/transport/plugin_transport_wlan.c:1341 msgid "# WLAN DATA messages processed" msgstr "" #: src/transport/plugin_transport_wlan.c:1402 msgid "# HELLO beacons sent via WLAN" msgstr "" #: src/transport/plugin_transport_wlan.c:1511 msgid "WLAN address with invalid size encountered\n" msgstr "" #: src/transport/plugin_transport_wlan.c:1668 #, fuzzy, c-format msgid "Invalid configuration option `%s' in section `%s'\n" msgstr "é…置文件“%sâ€å·²å†™å…¥ã€‚\n" #: src/transport/plugin_transport_wlan.c:1677 #, c-format msgid "Helper binary `%s' not SUID, cannot run WLAN transport\n" msgstr "" #: src/transport/plugin_transport_wlan.c:1687 #, fuzzy, c-format msgid "Missing configuration option `%s' in section `%s'\n" msgstr "é…置文件“%sâ€å·²å†™å…¥ã€‚\n" #: src/transport/transport_api.c:570 #, c-format msgid "Received unexpected message of type %u in %s:%u\n" msgstr "" #: src/util/bio.c:136 src/util/bio.c:142 #, fuzzy, c-format msgid "Error reading `%s': %s" msgstr "创建用户出错" #: src/util/bio.c:143 msgid "End of file" msgstr "" #: src/util/bio.c:195 #, c-format msgid "Error reading length of string `%s'" msgstr "" #: src/util/bio.c:205 #, c-format msgid "String `%s' longer than allowed (%u > %u)" msgstr "" #: src/util/bio.c:250 #, c-format msgid "Serialized metadata `%s' larger than allowed (%u>%u)" msgstr "" #: src/util/bio.c:264 #, c-format msgid "Metadata `%s' failed to deserialize" msgstr "" #: src/util/client.c:359 #, c-format msgid "" "Could not determine valid hostname and port for service `%s' from " "configuration.\n" msgstr "" #: src/util/client.c:367 #, c-format msgid "Need a non-empty hostname for service `%s'.\n" msgstr "" #: src/util/client.c:685 msgid "Failure to transmit TEST request.\n" msgstr "" #: src/util/client.c:740 src/util/service.c:970 #, c-format msgid "UNIXPATH `%s' too long, maximum length is %llu\n" msgstr "" #: src/util/client.c:882 #, c-format msgid "Could not connect to service `%s', must not be running.\n" msgstr "" #: src/util/client.c:896 #, c-format msgid "Failure to transmit request to service `%s'\n" msgstr "" #: src/util/client.c:1149 msgid "Could not submit request, not expecting to receive a response.\n" msgstr "" #: src/util/common_logging.c:239 src/util/common_logging.c:890 msgid "DEBUG" msgstr "调试" #: src/util/common_logging.c:241 src/util/common_logging.c:888 msgid "INFO" msgstr "ä¿¡æ¯" #: src/util/common_logging.c:243 src/util/common_logging.c:886 msgid "WARNING" msgstr "警告" #: src/util/common_logging.c:245 src/util/common_logging.c:884 msgid "ERROR" msgstr "错误" #: src/util/common_logging.c:247 src/util/common_logging.c:892 msgid "NONE" msgstr "" #: src/util/common_logging.c:610 #, fuzzy, c-format msgid "Failed to create or access directory for log file `%s'\n" msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #: src/util/common_logging.c:725 #, fuzzy, c-format msgid "Message `%.*s' repeated %u times in the last %s\n" msgstr "消æ¯â€œ%.*sâ€é‡å¤äº† %u 次,在最近 %llu 秒内\n" #: src/util/common_logging.c:893 msgid "INVALID" msgstr "" #: src/util/common_logging.c:992 msgid "unknown address" msgstr "" #: src/util/common_logging.c:1030 msgid "invalid address" msgstr "" #: src/util/configuration.c:244 #, fuzzy, c-format msgid "Syntax error in configuration file `%s' at line %u.\n" msgstr "é…置文件“%sâ€ç¬¬ %d 行有语法错误。\n" #: src/util/configuration.c:816 #, c-format msgid "" "Configuration value '%s' for '%s' in section '%s' is not in set of legal " "choices\n" msgstr "" #: src/util/connection.c:420 #, fuzzy, c-format msgid "Access denied to `%s'\n" msgstr "“%sâ€å·²è¿žæŽ¥åˆ°â€œ%sâ€ã€‚\n" #: src/util/connection.c:435 #, c-format msgid "Accepting connection from `%s': %p\n" msgstr "" #: src/util/connection.c:550 #, c-format msgid "" "Failed to establish TCP connection to `%s:%u', no further addresses to try.\n" msgstr "" #: src/util/connection.c:739 src/util/connection.c:909 #, fuzzy, c-format msgid "Trying to connect to `%s' (%p)\n" msgstr "无法连接到 %s:%u:%s\n" #: src/util/connection.c:748 #, fuzzy, c-format msgid "Failed to connect to `%s' (%p)\n" msgstr "无法连接到 %s:%u:%s\n" #: src/util/connection.c:900 #, c-format msgid "Attempt to connect to `%s' failed\n" msgstr "" #: src/util/container_bloomfilter.c:510 #, c-format msgid "" "Size of file on disk is incorrect for this Bloom filter (want %llu, have " "%llu)\n" msgstr "" #: src/util/crypto_random.c:280 #, c-format msgid "Starting `%s' process to generate entropy\n" msgstr "" #: src/util/crypto_random.c:309 #, c-format msgid "libgcrypt has not the expected version (version %s is required).\n" msgstr "libgcrypt 的版本ä¸ç¬¦åˆé¢„期(è¦æ±‚版本 %s)。\n" #: src/util/crypto_rsa.c:661 src/util/crypto_rsa.c:708 #, fuzzy, c-format msgid "Could not aquire lock on file `%s': %s...\n" msgstr "无法解æžâ€œ%sâ€(%s):%s\n" #: src/util/crypto_rsa.c:666 #, fuzzy msgid "Creating a new private key. This may take a while.\n" msgstr "正在å¯åŠ¨æ•°æ®ä»“库转æ¢(å¯èƒ½éœ€è¦ä¸€æ®µæ—¶é—´)。\n" #: src/util/crypto_rsa.c:684 #, c-format msgid "I am host `%s'. Stored new private key in `%s'.\n" msgstr "" #: src/util/crypto_rsa.c:712 src/util/crypto_rsa.c:748 msgid "This may be ok if someone is currently generating a hostkey.\n" msgstr "" #: src/util/crypto_rsa.c:743 #, c-format msgid "" "When trying to read hostkey file `%s' I found %u bytes but I need at least " "%u.\n" msgstr "" #: src/util/crypto_rsa.c:763 #, c-format msgid "File `%s' does not contain a valid private key. Deleting it.\n" msgstr "" #: src/util/crypto_rsa.c:781 #, c-format msgid "I am host `%s'. Read private key from `%s'.\n" msgstr "" #: src/util/crypto_rsa.c:1032 #, c-format msgid "RSA signature verification failed at %s:%d: %s\n" msgstr "" #: src/util/disk.c:498 #, fuzzy, c-format msgid "`%s' failed for drive `%S': %u\n" msgstr "对驱动器“%2$sâ€çš„“%1$sâ€æ“作失败:%3$u\n" #: src/util/disk.c:1062 #, c-format msgid "Expected `%s' to be a directory!\n" msgstr "“%sâ€åº”为目录ï¼\n" #: src/util/disk.c:1416 src/util/service.c:1650 #, c-format msgid "Cannot obtain information about user `%s': %s\n" msgstr "æ— æ³•èŽ·å–æœ‰å…³ç”¨æˆ·â€œ%sâ€çš„ä¿¡æ¯ï¼š%s\n" #: src/util/disk.c:1734 #, c-format msgid "No `%s' specified for service `%s' in configuration.\n" msgstr "" #: src/util/getopt.c:669 #, c-format msgid "%s: option `%s' is ambiguous\n" msgstr "%s:选项“%sâ€æœ‰æ­§ä¹‰\n" #: src/util/getopt.c:693 #, c-format msgid "%s: option `--%s' does not allow an argument\n" msgstr "%s:选项“--%sâ€ä¸å…è®¸æœ‰å‚æ•°\n" #: src/util/getopt.c:698 #, c-format msgid "%s: option `%c%s' does not allow an argument\n" msgstr "%s:选项“%c%sâ€ä¸å…è®¸æœ‰å‚æ•°\n" #: src/util/getopt.c:715 src/util/getopt.c:883 #, c-format msgid "%s: option `%s' requires an argument\n" msgstr "%s:选项“%sâ€è¦æ±‚æœ‰ä¸€ä¸ªå‚æ•°\n" #: src/util/getopt.c:744 #, c-format msgid "%s: unrecognized option `--%s'\n" msgstr "%s:无法识别的选项“--%sâ€\n" #: src/util/getopt.c:748 #, c-format msgid "%s: unrecognized option `%c%s'\n" msgstr "%s:无法识别的选项“%c%sâ€\n" #: src/util/getopt.c:773 #, c-format msgid "%s: illegal option -- %c\n" msgstr "%sï¼šéžæ³•选项 -- %c\n" #: src/util/getopt.c:775 #, c-format msgid "%s: invalid option -- %c\n" msgstr "%s:无效选项 -- %c\n" #: src/util/getopt.c:803 src/util/getopt.c:931 #, c-format msgid "%s: option requires an argument -- %c\n" msgstr "%sï¼šé€‰é¡¹è¦æ±‚æœ‰ä¸€ä¸ªå‚æ•° -- %c\n" #: src/util/getopt.c:851 #, c-format msgid "%s: option `-W %s' is ambiguous\n" msgstr "%s:选项“-W %sâ€æœ‰æ­§ä¹‰\n" #: src/util/getopt.c:869 #, c-format msgid "%s: option `-W %s' does not allow an argument\n" msgstr "%s:选项“-W %s†ä¸å…è®¸æœ‰å‚æ•°\n" #: src/util/getopt.c:1035 #, fuzzy, c-format msgid "Use %s to get a list of options.\n" msgstr "请使用 --help 获å–选项列表。\n" #: src/util/getopt_helpers.c:86 #, c-format msgid "" "Arguments mandatory for long options are also mandatory for short options.\n" msgstr "é•¿é€‰é¡¹çš„å¿…é€‰å‚æ•°å¯¹çŸ­é€‰é¡¹ä¹Ÿæ˜¯å¿…选的。\n" #: src/util/getopt_helpers.c:258 src/util/getopt_helpers.c:286 #, c-format msgid "You must pass a number to the `%s' option.\n" msgstr "您必须å‘“%sâ€é€‰é¡¹ä¼ é€’一个数字。\n" #: src/util/gnunet-resolver.c:148 msgid "perform a reverse lookup" msgstr "" #: src/util/gnunet-resolver.c:154 msgid "Use build-in GNUnet stub resolver" msgstr "" #: src/util/gnunet-rsa.c:64 #, c-format msgid "No hostkey file specified on command line\n" msgstr "" #: src/util/gnunet-rsa.c:112 msgid "print the public key in ASCII format" msgstr "" #: src/util/gnunet-rsa.c:115 msgid "print the hash of the public key in ASCII format" msgstr "" #: src/util/gnunet-rsa.c:118 msgid "print the short hash of the public key in ASCII format" msgstr "" #: src/util/gnunet-rsa.c:124 msgid "Manipulate GNUnet private RSA key files" msgstr "" #: src/util/gnunet-service-resolver.c:288 #, c-format msgid "Could not resolve `%s' (%s): %s\n" msgstr "无法解æžâ€œ%sâ€(%s):%s\n" #: src/util/gnunet-service-resolver.c:358 #: src/util/gnunet-service-resolver.c:399 #, c-format msgid "Could not find IP of host `%s': %s\n" msgstr "找ä¸åˆ°ä¸»æœºâ€œ%sâ€çš„ IP:%s\n" #: src/util/helper.c:244 #, fuzzy, c-format msgid "Error reading from `%s': %s\n" msgstr "创建用户出错" #: src/util/helper.c:259 #, c-format msgid "Got 0 bytes from helper `%s' (EOF)\n" msgstr "" #: src/util/helper.c:269 #, c-format msgid "Got %u bytes from helper `%s'\n" msgstr "" #: src/util/helper.c:278 #, fuzzy, c-format msgid "Failed to parse inbound message from helper `%s'\n" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/util/helper.c:310 #, fuzzy, c-format msgid "Starting HELPER process `%s'\n" msgstr "å¸è½½ GNUnet æœåŠ¡" #: src/util/helper.c:440 #, fuzzy, c-format msgid "Error writing to `%s': %s\n" msgstr "创建用户出错" #: src/util/network.c:1200 #, c-format msgid "" "Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n" msgstr "" #: src/util/os_installation.c:299 #, fuzzy, c-format msgid "" "Could not determine installation path for %s. Set `%s' environment " "variable.\n" msgstr "无法确定安装路径。请å°è¯•设置“%sâ€\n" #: src/util/os_installation.c:486 #, fuzzy, c-format msgid "Could not find binary `%s' in PATH!\n" msgstr "找ä¸åˆ°ä¸»æœºâ€œ%sâ€çš„ IP:%s\n" #: src/util/os_installation.c:492 #, fuzzy, c-format msgid "access (%s, X_OK) failed: %s\n" msgstr "“%sâ€è¯´ï¼š%s\n" #: src/util/os_installation.c:507 #, fuzzy, c-format msgid "stat (%s) failed: %s\n" msgstr "“%sâ€è¯´ï¼š%s\n" #: src/util/os_priority.c:305 #, fuzzy, c-format msgid "Failed to open named pipe `%s' for reading: %s\n" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/util/os_priority.c:306 #, fuzzy, c-format msgid "Failed to open named pipe `%s' for writing: %s\n" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/util/plugin.c:89 #, c-format msgid "Initialization of plugin mechanism failed: %s!\n" msgstr "æ’件机构åˆå§‹åŒ–失败:%sï¼\n" #: src/util/plugin.c:146 #, c-format msgid "`%s' failed to resolve method '%s' with error: %s\n" msgstr "" #: src/util/plugin.c:219 #, c-format msgid "`%s' failed for library `%s' with error: %s\n" msgstr "" #: src/util/plugin.c:349 #, fuzzy msgid "Could not determine plugin installation path.\n" msgstr "无法确定用户界é¢å®šä¹‰æ–‡ä»¶ã€‚" #: src/util/pseudonym.c:276 #, fuzzy, c-format msgid "Failed to parse metadata about pseudonym from file `%s': %s\n" msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #: src/util/pseudonym.c:407 src/util/pseudonym.c:433 msgid "no-name" msgstr "æ— åç§°" #: src/util/resolver_api.c:202 #, c-format msgid "Must specify `%s' for `%s' in configuration!\n" msgstr "" #: src/util/resolver_api.c:221 #, c-format msgid "" "Must specify `%s' or numeric IP address for `%s' of `%s' in configuration!\n" msgstr "" #: src/util/resolver_api.c:347 #, fuzzy, c-format msgid "Timeout trying to resolve IP address `%s'.\n" msgstr "GNUnet 现在使用 IP åœ°å€ %s。\n" #: src/util/resolver_api.c:351 #, c-format msgid "Timeout trying to resolve hostname `%s'.\n" msgstr "" #: src/util/resolver_api.c:890 #, fuzzy, c-format msgid "Could not resolve our FQDN : %s\n" msgstr "无法解æžâ€œ%sâ€(%s):%s\n" #: src/util/scheduler.c:786 msgid "Looks like we're busy waiting...\n" msgstr "" #: src/util/scheduler.c:916 #, c-format msgid "Attempt to cancel dead task %llu!\n" msgstr "" #: src/util/server.c:483 #, fuzzy, c-format msgid "`%s' failed for port %d (%s).\n" msgstr "对驱动器“%2$sâ€çš„“%1$sâ€æ“作失败:%3$u\n" #: src/util/server.c:492 #, c-format msgid "`%s' failed for port %d (%s): address already in use\n" msgstr "" #: src/util/server.c:497 #, fuzzy, c-format msgid "`%s' failed for `%s': address already in use\n" msgstr "对驱动器“%2$sâ€çš„“%1$sâ€æ“作失败:%3$u\n" #: src/util/server.c:827 #, c-format msgid "" "Processing code for message of type %u did not call " "GNUNET_SERVER_receive_done after %llums\n" msgstr "" #: src/util/service.c:135 src/util/service.c:161 src/util/service.c:204 #: src/util/service.c:225 src/util/service.c:232 #, c-format msgid "Invalid format for IP: `%s'\n" msgstr "IP æ ¼å¼æ— æ•ˆï¼šâ€œ%sâ€\n" #: src/util/service.c:188 #, c-format msgid "Invalid network notation ('/%d' is not legal in IPv4 CIDR)." msgstr "网络表示法无效(“/%d†在 IPv4 CIDR ä¸­æ˜¯éžæ³•çš„)。" #: src/util/service.c:281 #, c-format msgid "Invalid network notation (does not end with ';': `%s')\n" msgstr "无效的网络表示法(没有以“;â€ç»“尾:“%sâ€)\n" #: src/util/service.c:313 #, c-format msgid "Wrong format `%s' for netmask\n" msgstr "网络掩ç çš„æ ¼å¼â€œ%sâ€é”™è¯¯\n" #: src/util/service.c:343 #, c-format msgid "Wrong format `%s' for network\n" msgstr "网络的格å¼â€œ%sâ€é”™è¯¯\n" #: src/util/service.c:698 #, c-format msgid "Access denied to UID %d / GID %d\n" msgstr "" #: src/util/service.c:703 #, c-format msgid "Unknown address family %d\n" msgstr "" #: src/util/service.c:710 #, c-format msgid "Access from `%s' denied to service `%s'\n" msgstr "" #: src/util/service.c:765 #, c-format msgid "Could not parse IPv4 network specification `%s' for `%s:%s'\n" msgstr "" #: src/util/service.c:802 #, c-format msgid "Could not parse IPv6 network specification `%s' for `%s:%s'\n" msgstr "" #: src/util/service.c:920 #, c-format msgid "" "Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n" msgstr "" #: src/util/service.c:990 #, c-format msgid "" "Disabling UNIX domain socket support for service `%s', failed to create UNIX " "domain socket: %s\n" msgstr "" #: src/util/service.c:1007 #, c-format msgid "Have neither PORT nor UNIXPATH for service `%s', but one is required\n" msgstr "" #: src/util/service.c:1241 msgid "Could not access a pre-bound socket, will try to bind myself\n" msgstr "" #: src/util/service.c:1292 src/util/service.c:1310 #, c-format msgid "Specified value for `%s' of service `%s' is invalid\n" msgstr "" #: src/util/service.c:1337 #, c-format msgid "Could not access pre-bound socket %u, will try to bind myself\n" msgstr "" #: src/util/service.c:1506 #, fuzzy, c-format msgid "Failed to start `%s' at `%s'\n" msgstr "è¿è¡Œ %s失败:%s %d\n" #: src/util/service.c:1539 #, c-format msgid "Service `%s' runs at %s\n" msgstr "" #: src/util/service.c:1588 msgid "Service process failed to initialize\n" msgstr "" #: src/util/service.c:1592 msgid "Service process could not initialize server function\n" msgstr "" #: src/util/service.c:1596 msgid "Service process failed to report status\n" msgstr "" #: src/util/service.c:1651 msgid "No such user" msgstr "无此用户" #: src/util/service.c:1664 #, c-format msgid "Cannot change user/group to `%s': %s\n" msgstr "无法更改用户/组为“%sâ€ï¼š%s\n" #: src/util/service.c:1729 msgid "do daemonize (detach from terminal)" msgstr "" #: src/util/signal.c:80 #, c-format msgid "signal (%d, %p) returned %d.\n" msgstr "" #: src/util/strings.c:144 msgid "b" msgstr "b" #: src/util/strings.c:334 #, c-format msgid "Character sets requested were `%s'->`%s'\n" msgstr "" #: src/util/strings.c:481 msgid "Failed to expand `$HOME': environment variable `HOME' not set" msgstr "扩展“$HOMEâ€å¤±è´¥ï¼šæ²¡æœ‰è®¾ç½®çŽ¯å¢ƒå˜é‡â€œHOMEâ€" #: src/util/strings.c:573 msgid "ms" msgstr "毫秒" #: src/util/strings.c:578 msgid "eternity" msgstr "" #: src/util/strings.c:582 msgid "s" msgstr "ç§’" #: src/util/strings.c:586 msgid "m" msgstr "分" #: src/util/strings.c:590 msgid "h" msgstr "æ—¶" #: src/util/strings.c:594 msgid " days" msgstr " 天" #: src/util/strings.c:618 msgid "end of time" msgstr "" #: src/util/strings.c:1012 msgid "IPv6 address did not start with `['\n" msgstr "" #: src/util/strings.c:1020 msgid "IPv6 address did contain ':' to separate port number\n" msgstr "" #: src/util/strings.c:1026 msgid "IPv6 address did contain ']' before ':' to separate port number\n" msgstr "" #: src/util/strings.c:1033 msgid "IPv6 address did contain a valid port number after the last ':'\n" msgstr "" #: src/util/strings.c:1042 #, fuzzy, c-format msgid "Invalid IPv6 address `%s': %s\n" msgstr "无效的进程优先级“%sâ€\n" #: src/vpn/gnunet-service-vpn.c:511 src/vpn/gnunet-service-vpn.c:1071 msgid "# Active tunnels" msgstr "" #: src/vpn/gnunet-service-vpn.c:608 src/vpn/gnunet-service-vpn.c:645 #, fuzzy msgid "# peers connected to mesh tunnels" msgstr "" "\n" "按任æ„键继续\n" #: src/vpn/gnunet-service-vpn.c:699 msgid "# Bytes given to mesh for transmission" msgstr "" #: src/vpn/gnunet-service-vpn.c:737 msgid "# Bytes dropped in mesh queue (overflow)" msgstr "" #: src/vpn/gnunet-service-vpn.c:772 msgid "# Mesh tunnels created" msgstr "" #: src/vpn/gnunet-service-vpn.c:795 #, fuzzy msgid "Failed to setup mesh tunnel!\n" msgstr "å‘逿¶ˆæ¯å¤±è´¥ã€‚\n" #: src/vpn/gnunet-service-vpn.c:973 #, c-format msgid "Protocol %u not supported, dropping\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1291 msgid "# ICMPv4 packets dropped (not allowed)" msgstr "" #: src/vpn/gnunet-service-vpn.c:1312 msgid "# ICMPv6 packets dropped (not allowed)" msgstr "" #: src/vpn/gnunet-service-vpn.c:1517 msgid "# Packets received from TUN interface" msgstr "" #: src/vpn/gnunet-service-vpn.c:1555 src/vpn/gnunet-service-vpn.c:1596 #, c-format msgid "Packet received for unmapped destination `%s' (dropping it)\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1606 msgid "Received IPv4 packet with options (dropping it)\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1620 #, c-format msgid "Received packet of unknown protocol %d from TUN (dropping it)\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1704 msgid "# ICMP packets received from mesh" msgstr "" #: src/vpn/gnunet-service-vpn.c:2045 msgid "# UDP packets received from mesh" msgstr "" #: src/vpn/gnunet-service-vpn.c:2203 msgid "# TCP packets received from mesh" msgstr "" #: src/vpn/gnunet-service-vpn.c:2354 msgid "Failed to find unallocated IPv4 address in VPN's range\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:2409 msgid "Failed to find unallocated IPv6 address in VPN's range\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:2448 src/vpn/gnunet-service-vpn.c:2661 msgid "# Active destinations" msgstr "" #: src/vpn/gnunet-service-vpn.c:2734 msgid "Failed to allocate IP address for new destination\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:3141 msgid "IPv6 support disabled as this system does not support IPv6\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:3173 msgid "IPv4 support disabled as this system does not support IPv4\n" msgstr "" #: src/vpn/gnunet-vpn.c:151 #, fuzzy msgid "Error creating tunnel\n" msgstr "创建用户出错" #: src/vpn/gnunet-vpn.c:195 src/vpn/gnunet-vpn.c:226 #, c-format msgid "Option `%s' makes no sense with option `%s'.\n" msgstr "" #: src/vpn/gnunet-vpn.c:208 #, fuzzy, c-format msgid "Option `%s' or `%s' is required.\n" msgstr "%s:选项“%sâ€æœ‰æ­§ä¹‰\n" #: src/vpn/gnunet-vpn.c:220 #, c-format msgid "Option `%s' or `%s' is required when using option `%s'.\n" msgstr "" #: src/vpn/gnunet-vpn.c:238 #, fuzzy, c-format msgid "`%s' is not a valid peer identifier.\n" msgstr "“%sâ€ä¸å¯ç”¨ã€‚\n" #: src/vpn/gnunet-vpn.c:260 #, fuzzy, c-format msgid "`%s' is not a valid IP address.\n" msgstr "“%sâ€ä¸å¯ç”¨ã€‚\n" #: src/vpn/gnunet-vpn.c:296 msgid "request that result should be an IPv4 address" msgstr "" #: src/vpn/gnunet-vpn.c:299 msgid "request that result should be an IPv6 address" msgstr "" #: src/vpn/gnunet-vpn.c:302 msgid "print IP address only after mesh tunnel has been created" msgstr "" #: src/vpn/gnunet-vpn.c:305 msgid "how long should the mapping be valid for new tunnels?" msgstr "" #: src/vpn/gnunet-vpn.c:308 msgid "destination IP for the tunnel" msgstr "" #: src/vpn/gnunet-vpn.c:311 msgid "peer offering the service we would like to access" msgstr "" #: src/vpn/gnunet-vpn.c:314 msgid "name of the service we would like to access" msgstr "" #: src/vpn/gnunet-vpn.c:317 msgid "service is offered via TCP" msgstr "" #: src/vpn/gnunet-vpn.c:320 msgid "service is offered via UDP" msgstr "" #: src/vpn/gnunet-vpn.c:329 msgid "Setup tunnels via VPN." msgstr "" #: src/include/gnunet_common.h:497 src/include/gnunet_common.h:502 #: src/include/gnunet_common.h:508 #, c-format msgid "Assertion failed at %s:%d.\n" msgstr "" #: src/include/gnunet_common.h:518 #, c-format msgid "External protocol violation detected at %s:%d.\n" msgstr "" #: src/include/gnunet_common.h:539 src/include/gnunet_common.h:546 #, c-format msgid "`%s' failed on file `%s' at %s:%d with error: %s\n" msgstr "" #, fuzzy #~ msgid "# Peers connected" #~ msgstr "" #~ "\n" #~ "按任æ„键继续\n" #, fuzzy #~ msgid "%s failed for `%s' at %s:%d: `%s'\n" #~ msgstr "对驱动器“%2$sâ€çš„“%1$sâ€æ“作失败:%3$u\n" #, fuzzy #~ msgid "Unable to initialize Postgres with configuration `%s': %s" #~ msgstr "无法ä¿å­˜é…置文件“%sâ€ï¼š" #, fuzzy #~ msgid "Copying file with RENAME (%s,%s)\n" #~ msgstr "“%sâ€ä»¥é”™è¯¯ç  %s 失败:%s\n" #, fuzzy #~ msgid "Copying file with command scp %s %s\n" #~ msgstr "“%sâ€ä»¥é”™è¯¯ç  %s 失败:%s\n" #, fuzzy #~ msgid "Finished copying all blacklist files!\n" #~ msgstr "无法解æžâ€œ%sâ€(%s):%s\n" #, fuzzy #~ msgid "Failed during blacklist file copying!\n" #~ msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #, fuzzy #~ msgid "# fast reconnects failed" #~ msgstr "" #~ "\n" #~ "按任æ„键继续\n" #~ msgid "Unknown user `%s'\n" #~ msgstr "未知的用户“%sâ€\n" #, fuzzy #~ msgid "Failed to connect to statistics service!\n" #~ msgstr "åˆå§‹åŒ–“%sâ€æœåŠ¡å¤±è´¥ã€‚\n" #, fuzzy #~ msgid "Failed to send to `%s': %s\n" #~ msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #, fuzzy #~ msgid "Could not access file: %s\n" #~ msgstr "错误:无法访问æœåŠ¡ï¼š%s\n" #, fuzzy #~ msgid "`%s' failed on file `%s': %s" #~ msgstr "对驱动器“%2$sâ€çš„“%1$sâ€æ“作失败:%3$u\n" #, fuzzy #~ msgid "Failed to stop service `%s'!\n" #~ msgstr "打开日志文件“%sâ€å¤±è´¥ï¼š%s\n" #, fuzzy #~ msgid "Failed to start service `%s'!\n" #~ msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #, fuzzy #~ msgid "Service `%s' stopped\n" #~ msgstr "æœåŠ¡å·²åˆ é™¤ã€‚\n" #, fuzzy #~ msgid "Unable to start service `%s': %s\n" #~ msgstr "无法ä¿å­˜é…置文件“%sâ€ï¼š" #, fuzzy #~ msgid "Unable to accept connection for service `%s': %s\n" #~ msgstr "无法ä¿å­˜é…置文件“%sâ€ï¼š" #~ msgid "KiB" #~ msgstr "KiB" #~ msgid "MiB" #~ msgstr "MiB" #~ msgid "GiB" #~ msgstr "GiB" #~ msgid "TiB" #~ msgstr "TiB" #, fuzzy #~ msgid "Could not resolve our FQDN : %s %u\n" #~ msgstr "无法解æžâ€œ%sâ€(%s):%s\n" #, fuzzy #~ msgid "Failed to load dhtlog plugin for `%s'\n" #~ msgstr "è§£æžé…置文件“%sâ€å¤±è´¥\n" #, fuzzy #~ msgid "Phase 3: sending messages\n" #~ msgstr "å‘逿¶ˆæ¯å¤±è´¥ã€‚\n" #, fuzzy #~ msgid "Fail! Could not connect peers\n" #~ msgstr "无法连接到 %s:%u:%s\n" #~ msgid "Error" #~ msgstr "错误" #~ msgid "Help" #~ msgstr "帮助" #~ msgid "Error!" #~ msgstr "错误ï¼" #~ msgid "No" #~ msgstr "å¦" #~ msgid "Yes" #~ msgstr "是" #~ msgid "Internal error! (Choice invalid?)" #~ msgstr "内部错误ï¼(选择无效?)" #~ msgid "Abort" #~ msgstr "中止" #~ msgid "Ok" #~ msgstr "确定" #~ msgid "" #~ "Welcome to GNUnet!\n" #~ "\n" #~ "This assistant will ask you a few basic questions in order to configure " #~ "GNUnet.\n" #~ "\n" #~ "Please visit our homepage at\n" #~ "\thttp://gnunet.org/\n" #~ "and join our community at\n" #~ "\thttp://gnunet.org/drupal/\n" #~ "\n" #~ "Have a lot of fun,\n" #~ "\n" #~ "the GNUnet team" #~ msgstr "" #~ "欢迎使用 GNUnetï¼\n" #~ "\n" #~ "此助手将询问您几个基本问题,以é…ç½® GNUnet。\n" #~ "\n" #~ "请访问我们的主页\n" #~ "\thttp://gnunet.org/\n" #~ "并欢迎加入我们的社区\n" #~ "\thttp://gnunet.org/drupal/\n" #~ "\n" #~ "ç¥æ‚¨ä½¿ç”¨æ„‰å¿«ï¼Œ\n" #~ "\n" #~ "GNUnet 团队" #~ msgid "" #~ "Choose the network interface that connects your computer to the internet " #~ "from the list below." #~ msgstr "请从下é¢çš„列表中选择计算机è”网的网络接å£ã€‚" #~ msgid "" #~ "The \"Network interface\" is the device that connects your computer to " #~ "the internet. This is usually a modem, an ISDN card or a network card in " #~ "case you are using DSL." #~ msgstr "" #~ "“网络接å£â€æ˜¯å°†æ‚¨çš„计算机连接到互è”网的设备。该设备通常为一å°è°ƒåˆ¶è§£è°ƒå™¨ã€ä¸€" #~ "å¼  ISDN 塿ˆ–一张网å¡(若您使用 DSL 网络)。" #~ msgid "Network configuration: interface" #~ msgstr "网络é…置:接å£" #~ msgid "" #~ "What is the name of the network interface that connects your computer to " #~ "the Internet?" #~ msgstr "您的计算机è”网所使用的网络接å£çš„å称是什么?" #~ msgid "Network configuration: IP" #~ msgstr "网络é…置:IP" #~ msgid "What is this computer's public IP address or hostname?" #~ msgstr "è¿™å°è®¡ç®—机的公网 IP åœ°å€æˆ–ä¸»æœºåæ˜¯ä»€ä¹ˆï¼Ÿ" #~ msgid "" #~ "If your provider always assigns the same IP-Address to you (a \"static\" " #~ "IP-Address), enter it into the \"IP-Address\" field. If your IP-Address " #~ "changes every now and then (\"dynamic\" IP-Address) but there's a " #~ "hostname that always points to your actual IP-Address (\"Dynamic DNS\"), " #~ "you can also enter it here.\n" #~ "If left empty, GNUnet will try to automatically detect the IP.\n" #~ "You can specify a hostname, GNUnet will then use DNS to resolve it.\n" #~ "If in doubt, leave this empty." #~ msgstr "" #~ "如果您的网络è¿è¥å•†æ€»æ˜¯åˆ†é…固定的 IP 地å€ç»™æ‚¨(â€œé™æ€â€ IP 地å€),请将它输" #~ "入“IP 地å€â€å­—段。如果您的 IP æ˜¯ä¸æ—¶å˜åŒ–çš„(“动æ€â€ IP 地å€)但有一个总是指å‘" #~ "您的实际 IP 地å€çš„主机å(â€œåŠ¨æ€ DNSâ€),也å¯ä»¥å°†è¿™ä¸ªä¸»æœºå填到这里。\n" #~ "如果ä¸å¡«ï¼ŒGNUnet å°†å°è¯•自动检测此 IP。\n" #~ "您å¯ä»¥æŒ‡å®šä¸€ä¸ªä¸»æœºå,GNUnet 将使用 DNS æ¥è§£æžå®ƒã€‚\n" #~ "å¦‚æžœä¸æ˜Žç™½ï¼Œè¯·ä¸å¡«ã€‚" #~ msgid "Bandwidth configuration: upload" #~ msgstr "带宽é…置:上传" #~ msgid "How much upstream bandwidth (in bytes/s) may be used?" #~ msgstr "å¯ä»¥ä½¿ç”¨å¤šå°‘上行带宽(å•ä½ä¸ºå­—节/ç§’)?" #~ msgid "" #~ "You can limit GNUnet's resource usage here.\n" #~ "\n" #~ "The \"upstream\" is the data channel through which data is *sent* to the " #~ "internet. The limit is the maximum amount which GNUnet is allowed to use. " #~ "If you have a flatrate, you can set it to the maximum speed of your " #~ "internet connection. You should not use a value that is higher than what " #~ "your actual connection allows." #~ msgstr "" #~ "您å¯ä»¥åœ¨æ­¤é™åˆ¶ GNUnet 的资æºå ç”¨ã€‚\n" #~ "\n" #~ "â€œä¸Šè¡Œâ€æ˜¯å‘互è”网“å‘é€â€æ•°æ®çš„æ•°æ®é€šé“。é™åˆ¶æ˜¯ GNUnet å¯ä½¿ç”¨çš„æœ€å¤§æ•°æ®æµé‡ã€‚" #~ "如果您的网速很平稳,您å¯ä»¥å°†è¯¥é™åˆ¶è®¾ç½®ä¸ºç½‘速的最大值。您ä¸åº”该使用超过实际" #~ "连接速度æžé™çš„值。" #~ msgid "Bandwidth configuration: download" #~ msgstr "带宽é…置:下载" #~ msgid "How much downstream bandwidth (in bytes/s) may be used?" #~ msgstr "å¯ä»¥ä½¿ç”¨å¤šå°‘下行带宽(å•ä½ä¸ºå­—节/ç§’)?" #~ msgid "" #~ "You can limit GNUnet's resource usage here.\n" #~ "\n" #~ "The \"downstream\" is the data channel through which data is *received* " #~ "from the internet. The limit is the maximum amount which GNUnet is " #~ "allowed to use. If you have a flatrate, you can set it to the maximum " #~ "speed of your internet connection. You should not use a value that is " #~ "higher than what your actual connection allows." #~ msgstr "" #~ "您å¯ä»¥åœ¨æ­¤é™åˆ¶ GNUnet 的资æºå ç”¨ã€‚\n" #~ "\n" #~ "â€œä¸‹è¡Œâ€æ˜¯æ•°æ®ä»Žäº’è”ç½‘â€œæŽ¥æ”¶â€æ•°æ®çš„æ•°æ®é€šé“。é™åˆ¶æ˜¯ GNUnet å¯ä½¿ç”¨çš„æœ€å¤§æ•°æ®æµ" #~ "é‡ã€‚如果您的网速很平稳,您å¯ä»¥å°†è¯¥é™åˆ¶è®¾ç½®ä¸ºç½‘速的最大值。您ä¸åº”该使用超过" #~ "实际连接速度æžé™çš„值。" #~ msgid "Quota configuration" #~ msgstr "é…é¢é…ç½®" #~ msgid "What is the maximum size of the datastore in MB?" #~ msgstr "æ•°æ®ä»“库的最大尺寸是多少(MB)?" #~ msgid "" #~ "The GNUnet datastore contains all content that GNUnet needs to store " #~ "(indexed, inserted and migrated content)." #~ msgstr "" #~ "GNUnet æ•°æ®ä»“库包å«äº† GNUnet 需è¦ä¿å­˜çš„æ‰€æœ‰å†…容(ç´¢å¼•çš„ã€æ’入的和åˆå¹¶çš„内" #~ "容)。" #~ msgid "Daemon configuration: user account" #~ msgstr "守护程åºé…置:用户账户" #~ msgid "As which user should gnunetd be run?" #~ msgstr "以什么用户身份è¿è¡Œ gnunetd?" #, fuzzy #~ msgid "" #~ "For security reasons, it is a good idea to let this setup create a new " #~ "user account under which the GNUnet service is started at system " #~ "startup.\n" #~ "\n" #~ "However, GNUnet may not be able to access files other than its own. This " #~ "includes files you want to publish in GNUnet. You'll have to grant read " #~ "permissions to the user specified below.\n" #~ "\n" #~ "Leave the field empty to run GNUnet with system privileges.\n" #~ msgstr "" #~ "出于安全考虑,让设置助手创建一个专门用于在系统å¯åŠ¨æ—¶å¯åЍ GNUnet æœåŠ¡çš„è´¦æˆ·" #~ "是个ä¸é”™çš„主æ„。\n" #~ "\n" #~ "但是,GNUnet å¯èƒ½æ— æ³•访问ä¸å±žäºŽè‡ªå·±è´¦æˆ·çš„æ–‡ä»¶ã€‚这包括您想通过 GNUnet å‘布" #~ "的文件。您必须对以下用户赋予读æƒé™ã€‚\n" #~ "\n" #~ "ä¸å¡«æ­¤å­—段则以系统æƒé™è¿è¡Œ GNUnet。\n" #~ msgid "Daemon configuration: group account" #~ msgstr "守护程åºé…置:组账户" #~ msgid "As which group should gnunetd be run?" #~ msgstr "以什么用户组身份è¿è¡Œ gnunetd?" #~ msgid "" #~ "For security reasons, it is a good idea to let this setup create a new " #~ "group for the chosen user account.\n" #~ "\n" #~ "You can also specify a already existent group here.\n" #~ "\n" #~ "Only members of this group will be allowed to start and stop the the " #~ "GNUnet server and have access to GNUnet server data.\n" #~ msgstr "" #~ "出于安全考虑,让设置助手为选择的用户创建一个新组是个ä¸é”™çš„主æ„。\n" #~ "\n" #~ "您也å¯ä»¥åœ¨æ­¤æŒ‡å®šä¸€ä¸ªçŽ°æœ‰çš„ç»„ã€‚\n" #~ "\n" #~ "åªæœ‰è¯¥ç»„çš„æˆå‘˜å¯ä»¥å¯åŠ¨å’Œåœæ­¢ GNUnet æœåŠ¡å™¨å’Œè®¿é—® GNUnet æœåŠ¡å™¨æ•°æ®ã€‚\n" #~ msgid "Do you want to automatically launch GNUnet as a system service?" #~ msgstr "您想将 GNUnet 作为系统æœåŠ¡è‡ªåŠ¨å¯åЍå—?" #~ msgid "" #~ "If you say \"yes\" here, the GNUnet background process will be " #~ "automatically started when you turn on your computer. If you say \"no\" " #~ "here, you have to launch GNUnet yourself each time you want to use it." #~ msgstr "" #~ "如果您回答“是â€ï¼ŒGNUnet åŽå°è¿›ç¨‹å°†åœ¨å¼€æœºæ—¶è‡ªåЍå¯åŠ¨ã€‚å¦‚æžœæ‚¨å›žç­”â€œå¦â€ï¼Œåˆ™éœ€è¦" #~ "åœ¨æ¯æ¬¡ä½¿ç”¨ GNUnet 时自己å¯åŠ¨å®ƒã€‚" #~ msgid "Unable to setup autostart for daemon." #~ msgstr "无法将守护进程设置为自动å¯åŠ¨ã€‚" #~ msgid "Save configuration?" #~ msgstr "ä¿å­˜é…置?" #~ msgid "GNUnet Configuration" #~ msgstr "GNUnet é…ç½®" #~ msgid "Back" #~ msgstr "åŽé€€" #~ msgid "Exit" #~ msgstr "退出" #~ msgid "Up" #~ msgstr "å‘上" #~ msgid "Cancel" #~ msgstr "å–æ¶ˆ" #~ msgid "Internal error! (Value invalid?)" #~ msgstr "内部错误ï¼(值无效?)" #~ msgid "Invalid input, expecting floating point value." #~ msgstr "无效输入,应为浮点值。" #~ msgid "Invalid input, expecting integer." #~ msgstr "无效输入,应为整数。" #~ msgid "Value is not in legal range." #~ msgstr "值ä¸åœ¨åˆæ³•范围内。" #~ msgid "Configuration unchanged, no need to save.\n" #~ msgstr "é…置未更改,无须ä¿å­˜ã€‚\n" #~ msgid "Do you wish to save your new configuration?" #~ msgstr "您想ä¿å­˜æ–°é…ç½®å—?" #~ msgid "" #~ "\n" #~ "Your configuration changes were NOT saved.\n" #~ msgstr "" #~ "\n" #~ "您的é…置更改没有ä¿å­˜ã€‚\n" #~ msgid "install GNUnet as Windows service" #~ msgstr "以 Windows æœåŠ¡æ–¹å¼å®‰è£… GNUnet" #~ msgid "increase the maximum number of TCP/IP connections" #~ msgstr "增加 TCP/IP 的最大连接数" #~ msgid "display a file's hash value" #~ msgstr "显示一个文件的散列值" #~ msgid "This version of Windows doesn't support services.\n" #~ msgstr "此版本的 Windows 䏿”¯æŒæœåŠ¡ã€‚\n" #~ msgid "Error: can't open Service Control Manager: %s\n" #~ msgstr "错误:无法打开æœåŠ¡æŽ§åˆ¶ç®¡ç†å™¨ï¼š%s\n" #~ msgid "Error: can't create service: %s\n" #~ msgstr "错误:无法创建æœåŠ¡ï¼š%s\n" #~ msgid "Error: can't delete service: %s\n" #~ msgstr "错误:无法删除æœåŠ¡ï¼š%s\n" #~ msgid "Configuration changed. Save?" #~ msgstr "é…置已更改。ä¿å­˜å—?" #~ msgid "Error saving configuration." #~ msgstr "ä¿å­˜é…置出错。" #~ msgid "(unknown connection)" #~ msgstr "(未知连接)" #~ msgid "Do you want to save the new configuration?" #~ msgstr "您想ä¿å­˜æ–°é…ç½®å—?" #~ msgid "Unable to change startup process:" #~ msgstr "无法更改å¯åŠ¨è¿›ç¨‹ï¼š" #~ msgid "" #~ "Running gnunet-update failed.\n" #~ "This maybe due to insufficient permissions, please check your " #~ "configuration.\n" #~ "Finally, run gnunet-update manually." #~ msgstr "" #~ "è¿è¡Œ gnunet-update 失败。\n" #~ "è¿™å¯èƒ½æ˜¯æƒé™ä¸è¶³é€ æˆçš„,请检查您的é…置。\n" #~ "最åŽï¼Œæ‰‹åЍè¿è¡Œ gnunet-update。" #~ msgid "Can only set one option per invocation.\n" #~ msgstr "æ¯æ¬¡è°ƒç”¨åªèƒ½è®¾ç½®ä¸€ä¸ªé€‰é¡¹ã€‚\n" #~ msgid "" #~ "Invalid syntax, argument to 'set' must have the format SECTION:" #~ "OPTION=VALUE.\n" #~ msgstr "语法无效,“setâ€çš„傿•°å¿…须为 SECTION:OPTION=VALUE 的格å¼ã€‚\n" #~ msgid "Can only display one option per invocation.\n" #~ msgstr "æ¯æ¬¡è°ƒç”¨åªèƒ½æ˜¾ç¤ºä¸€ä¸ªé€‰é¡¹ã€‚\n" #~ msgid "" #~ "Invalid syntax, argument to 'get' must have the format SECTION:OPTION.\n" #~ msgstr "语法无效,“getâ€çš„傿•°å¿…须为 SECTION:OPTION 的格å¼ã€‚\n" #~ msgid "generate configuration for gnunetd, the GNUnet daemon" #~ msgstr "为 GNUnet å®ˆæŠ¤ç¨‹åº gnunetd 生æˆé…ç½®" #~ msgid "Tool to setup GNUnet." #~ msgstr "设置 GNUnet 的工具。" #~ msgid "Too many arguments.\n" #~ msgstr "傿•°è¿‡å¤šã€‚\n" #~ msgid "No interface specified, using default.\n" #~ msgstr "没有指定接å£ï¼Œå°†ä½¿ç”¨é»˜è®¤ã€‚\n" #~ msgid "Configuration file `%s' must be a filename (but is a directory).\n" #~ msgstr "é…置文件“%sâ€å¿…须是一个文件å(但是一个目录)。\n" #~ msgid "Undefined option.\n" #~ msgstr "未定义的选项。\n" #~ msgid "yes" #~ msgstr "是" #~ msgid "no" #~ msgstr "å¦" #~ msgid "\tEnter yes (%s), no (%s) or help (%s): " #~ msgstr "\t输入 yes (%s)ã€no (%s) 或 help (%s):" #~ msgid "\tPossible choices:\n" #~ msgstr "\tå¯ç”¨é€‰é¡¹ï¼š\n" #~ msgid "\tUse single space prefix to avoid conflicts with hotkeys!\n" #~ msgstr "\t使用一个空格å‰ç¼€æ¥é¿å…与快æ·é”®å†²çªï¼\n" #~ msgid "\tEnter string (type '%s' for default value `%s'): " #~ msgstr "\t输入字符串(输入“%sâ€ä»¥ä½¿ç”¨é»˜è®¤å€¼â€œ%sâ€):" #~ msgid "\t Enter choice (default is %c): " #~ msgstr "\t 输入选择(默认为 %c):" #~ msgid "\tEnter floating point (type '%s' for default value %f): " #~ msgstr "\t输入浮点数(输入“%sâ€ä»¥ä½¿ç”¨é»˜è®¤å€¼ %f):" #~ msgid "" #~ "\tEnter unsigned integer in interval [%llu,%llu] (type '%s' for default " #~ "value %llu): " #~ msgstr "\t输入区间 [%llu,%llu] å†…çš„æ— ç¬¦å·æ•´æ•°(输入“%sâ€ä»¥ä½¿ç”¨é»˜è®¤å€¼ %llu):" #~ msgid "Yes\n" #~ msgstr "是\n" #~ msgid "No\n" #~ msgstr "å¦\n" #~ msgid "Help\n" #~ msgstr "帮助\n" #~ msgid "Abort\n" #~ msgstr "中止\n" #~ msgid "" #~ "\n" #~ "Invalid entry, try again (use '?' for help): " #~ msgstr "" #~ "\n" #~ "无效æ¡ç›®ï¼Œè¯·é‡è¯•(使用“?â€èŽ·å–帮助):" #~ msgid "Unknown kind %x (internal error). Skipping option.\n" #~ msgstr "未知的类型 %x (内部错误)。将跳过选项。\n" #, fuzzy #~ msgid "\tDescend? (y/n/?) " #~ msgstr "\t下é™(y/n/?) " #~ msgid "Aborted.\n" #~ msgstr "已中止。\n" #~ msgid "Unknown kind %x (internal error). Aborting.\n" #~ msgstr "未知的类型 %x (内部错误)。将中止。\n" #~ msgid "You can always press ENTER to keep the current value.\n" #~ msgstr "您å¯ä»¥éšä¾¿æŒ‰ ENTER é”®æ¥ä¿æŒå½“å‰å€¼ã€‚\n" #~ msgid "Use the '%s' key to abort.\n" #~ msgstr "使用“%sâ€é”®æ¥ä¸­æ­¢ã€‚\n" #~ msgid "" #~ "Save configuration? Answer 'y' for yes, 'n' for no, 'r' to repeat " #~ "configuration. " #~ msgstr "ä¿å­˜é…置?回答“yâ€è¡¨ç¤ºæ˜¯ï¼Œâ€œnâ€è¡¨ç¤ºå¦ï¼Œâ€œrâ€è¡¨ç¤ºé‡å¤é…置。" #~ msgid "Configuration was unchanged, no need to save.\n" #~ msgstr "é…置未更改,无须ä¿å­˜ã€‚\n" #~ msgid "" #~ "Internal error: entry `%s' in section `%s' not found for visibility " #~ "change!\n" #~ msgstr "内部错误:找ä¸åˆ°â€œ%2$sâ€èŠ‚çš„æ¡ç›®â€œ%1$sâ€ä»¥è¿›è¡Œå¯è§†åŒ–更改ï¼\n" #~ msgid "Can't open Service Control Manager" #~ msgstr "无法打开æœåŠ¡æŽ§åˆ¶ç®¡ç†å™¨" #~ msgid "Can't create service" #~ msgstr "无法创建æœåŠ¡" #~ msgid "Cannot write to the registry" #~ msgstr "无法写入该注册表" #~ msgid "Can't delete the service" #~ msgstr "无法删除该æœåŠ¡" #~ msgid "This version of Windows does not support multiple users." #~ msgstr "此版本的 Windows 䏿”¯æŒå¤šç”¨æˆ·ã€‚" #~ msgid "Error accessing local security policy" #~ msgstr "访问本地安全策略出错" #~ msgid "Error granting service right to user" #~ msgstr "å‘用户授予æœåŠ¡æƒé™å‡ºé”™" #~ msgid "Unknown error while creating a new user" #~ msgstr "在创建新用户时å‘生未知错误" #~ msgid "STATUS" #~ msgstr "状æ€" #~ msgid "FATAL" #~ msgstr "致命" #~ msgid "USER" #~ msgstr "用户" #~ msgid "ADMIN" #~ msgstr "管ç†å‘˜" #~ msgid "DEVELOPER" #~ msgstr "å¼€å‘者" #~ msgid "REQUEST" #~ msgstr "请求" #~ msgid "BULK" #~ msgstr "批é‡" #~ msgid "IMMEDIATE" #~ msgstr "ç«‹å³" #~ msgid "ALL" #~ msgstr "所有" #~ msgid "NOTHING" #~ msgstr "æ— " #~ msgid "Could not find valid value for HOST in section NETWORK.\n" #~ msgstr "在 NETWORK(网络) 节中找ä¸åˆ° HOST(主机) 的有效值。\n" #~ msgid "Syntax error in configuration entry HOST in section NETWORK: `%s'\n" #~ msgstr "在 NETWORK 节的é…ç½®æ¡ç›® HOST 中有语法错误:“%sâ€\n" #~ msgid "Reading result from gnunetd failed, reply invalid!\n" #~ msgstr "从 gnunetd 读å–结果失败,应答无效ï¼\n" #~ msgid "" #~ "Setting option `%s' in section `%s' to `%s' when processing command line " #~ "option `%s' was denied.\n" #~ msgstr "" #~ "在处ç†å‘½ä»¤è¡Œé€‰é¡¹â€œ%4$sâ€æ—¶ï¼Œå°†â€œ%2$sâ€èŠ‚çš„é€‰é¡¹â€œ%1$sâ€è®¾ç½®ä¸ºâ€œ%3$sâ€è¢«æ‹’ç»ã€‚\n" #~ msgid "No interface specified in section `%s' under `%s'!\n" #~ msgstr "“%2$sâ€ä¸‹çš„“%1$sâ€èŠ‚ä¸­æ²¡æœ‰æŒ‡å®šæŽ¥å£ï¼\n" #~ msgid "Could not obtain IP for interface `%s' using `%s'.\n" #~ msgstr "无法利用“%2$sâ€è޷喿ޥå£â€œ%1$sâ€çš„ IP。\n" #~ msgid "" #~ "Could not find interface `%s' using `%s', trying to find another " #~ "interface.\n" #~ msgstr "无法利用“%2$sâ€æ‰¾åˆ°æŽ¥å£â€œ%1$sâ€ï¼Œå°è¯•查找å¦ä¸€ä¸ªæŽ¥å£ã€‚\n" #~ msgid "" #~ "There is more than one IP address specified for interface `%s'.\n" #~ "GNUnet will use %s.\n" #~ msgstr "" #~ "为“%sâ€æŽ¥å£æŒ‡å®šäº†è¶…过一个 IP 地å€ã€‚\n" #~ "GNUnet 将使用 %s。\n" #~ msgid "Received malformed message (too small) from connection. Closing.\n" #~ msgstr "从连接收到æŸå的消æ¯(过å°)。关闭。\n" #, fuzzy #~ msgid "select listen socket for `%s' not valid!\n" #~ msgstr "选择“%sâ€çš„监å¬å¥—接字无效ï¼\n" #~ msgid "`%s' returned with error code %u" #~ msgstr "“%sâ€è¿”å›žäº†é”™è¯¯ç  %u" #~ msgid "Can't create semaphore: %i" #~ msgstr "无法创建信å·é‡ï¼š%i" #~ msgid "Cannot query the CPU usage (Windows NT).\n" #~ msgstr "无法查询 CPU 使用率(Windows NT)。\n" #~ msgid "Cannot query the CPU usage (Win 9x)\n" #~ msgstr "无法查询 CPU 使用率(Windows 9x)。\n" #~ msgid "Setting open descriptor limit not supported.\n" #~ msgstr "䏿”¯æŒè®¾ç½®æ‰“å¼€æè¿°ç¬¦é™åˆ¶ã€‚\n" #~ msgid "Command `%s' failed with error code %u\n" #~ msgstr "命令“%sâ€å¤±è´¥ï¼Œé”™è¯¯ç  %u\n" #~ msgid "Real-time delay violation (%llu ms) at %s:%u\n" #~ msgstr "实时延迟冲çª(%llu 毫秒),于 %s:%u\n" #~ msgid "`%s' failed with error code %d: %s\n" #~ msgstr "“%sâ€ä»¥é”™è¯¯ç  %d 失败:%s\n" #~ msgid "Deadlock due to `%s'.\n" #~ msgstr "“%sâ€é€ æˆäº†æ­»é”。\n" #~ msgid "GNUnet error log" #~ msgstr "GNUnet 错误日志" #, fuzzy #~ msgid "Out of memory (for logging)\n" #~ msgstr "(用于日志的)内存耗尽\n" #~ msgid "Completed datastore conversion.\n" #~ msgstr "å·²å®Œæˆæ•°æ®ä»“库轮æ¢ã€‚\n" #~ msgid "" #~ "%s:%d - RPC %s:%p could not be registered: another callback is already " #~ "using this name (%p)\n" #~ msgstr "%s:%d - 无法注册 RPC %s:%p:å¦ä¸€è°ƒç”¨æ­£åœ¨ä½¿ç”¨æ­¤åç§°(%p)\n" #~ msgid "%s:%d - async RPC %s:%p could not be unregistered: not found\n" #~ msgstr "%s:%d - 异步 RPC %s:%p 无法解除注册:找ä¸åˆ°\n" #~ msgid "output in gnuplot format" #~ msgstr "以 gnuplot æ ¼å¼è¾“出" #~ msgid "number of iterations" #~ msgstr "迭代次数" #~ msgid "number of messages to use per iteration" #~ msgstr "æ¯æ¬¡è¿­ä»£æ‰€ä½¿ç”¨çš„æ¶ˆæ¯æ•°é‡" #~ msgid "receiver host identifier (ENC file name)" #~ msgstr "接收方主机标识(ENC 文件å)" #~ msgid "message size" #~ msgstr "消æ¯å°ºå¯¸" #~ msgid "number of messages in a message block" #~ msgstr "一个消æ¯å—ä¸­çš„æ¶ˆæ¯æ•°é‡" #~ msgid "Error establishing connection with gnunetd.\n" #~ msgstr "通过 gnunetd 建立连接失败。\n" #~ msgid "You must specify a receiver!\n" #~ msgstr "您必须指定一个接收方ï¼\n" #~ msgid "Time:\n" #~ msgstr "时间:\n" #~ msgid "\tmax %llums\n" #~ msgstr "\t最长 %llu毫秒\n" #~ msgid "\tmin %llums\n" #~ msgstr "\t最短 %llu毫秒\n" #~ msgid "\tmean %8.4fms\n" #~ msgstr "\tå¹³å‡ %8.4f毫秒\n" #, fuzzy #~ msgid "\tvariance %8.4fms\n" #~ msgstr "\t波动 %8.4f毫秒\n" #~ msgid "Loss:\n" #~ msgstr "丢失:\n" #~ msgid "\tmax %u\n" #~ msgstr "\t最多 %u\n" #~ msgid "\tmin %u\n" #~ msgstr "\t最少 %u\n" #~ msgid "\tmean %8.4f\n" #~ msgstr "\tå¹³å‡ %8.4f\n" #, fuzzy #~ msgid "\tvariance %8.4f\n" #~ msgstr "\t波动 %8.4f\n" #~ msgid "Output format not known, this should not happen.\n" #~ msgstr "è¾“å‡ºæ ¼å¼æœªçŸ¥ï¼Œä¸åº”å‡ºçŽ°è¿™ç§æƒ…况。\n" #~ msgid "" #~ "\n" #~ "Did not receive the message from gnunetd. Is gnunetd running?\n" #~ msgstr "" #~ "\n" #~ "没有从 gnunetd 接收到消æ¯ã€‚gnunetd 在è¿è¡Œå—?\n" #~ msgid "" #~ "Failed to load MySQL database module. Check that MySQL is running and " #~ "configured properly!\n" #~ msgstr "加载 MySQL æ•°æ®åº“模å—失败。请检查 MySQL 是å¦è¿è¡Œå’Œæ˜¯å¦é…置正确ï¼\n" #, fuzzy #~ msgid "Command `%s' requires an argument (`%s').\n" #~ msgstr "%s:选项“%sâ€è¦æ±‚æœ‰ä¸€ä¸ªå‚æ•°\n" #, fuzzy #~ msgid "Command `%s' requires two arguments (`%s' and `%s').\n" #~ msgstr "%s:选项“%sâ€è¦æ±‚æœ‰ä¸€ä¸ªå‚æ•°\n" #~ msgid "" #~ "OS tells us about very large message (%u bytes) pending on UDP socket, " #~ "truncating at 64k\n" #~ msgstr "" #~ "æ“作系统通知,在 UPnP å¥—æŽ¥å­—ä¸Šæœ‰å¤§é‡æ¶ˆæ¯å¾…处ç†(%u 字节),将截短为64k\n" #~ msgid "" #~ "Couldn't find a group (`%s') for the new user and none was specified.\n" #~ msgstr "找ä¸åˆ°æ–°ç”¨æˆ·çš„组(“%sâ€)且没有指定用户组。\n" #~ msgid "Failed to find a free system id for the new group.\n" #~ msgstr "无法为新组找到一个空闲的系统标识。\n" #~ msgid "Failed to find a free system id for the new user.\n" #~ msgstr "无法为新用户找到一个个空闲的系统标识。\n" gnunet-0.9.3/po/es.gmo0000644000175000017500000001417611763406752011521 00000000000000Þ•9äO¬èéï,DZt-޼%Ú-.. ]&~¥Å%å# /5G;ƒ”/™É;æ7"Z0r)£/Í1ýW/ ‡ + $» kà L ^N '­ Õ A×   N Fm ´ M¶ + )0 7Z ^’ #ñ   8 ÈÏæú.F`.~­*Í.ø/'"W*z!¥!Ç.é, EQVW® Ã9Ð$ ?/7o§6Æ:ý58Anw°(50'fŽt/‡·I¹[Qd¶]¸62M3€y´%. T`93 ,2% !7'/5$+ -1()04&"86 #* . days# bytes decrypted# bytes encrypted# bytes received via TCP# messages defragmented# messages fragmented%s: illegal option -- %c %s: invalid option -- %c %s: option `%c%s' does not allow an argument %s: option `%s' is ambiguous %s: option `%s' requires an argument %s: option `--%s' does not allow an argument %s: option `-W %s' does not allow an argument %s: option `-W %s' is ambiguous %s: option requires an argument -- %c %s: unrecognized option `%c%s' %s: unrecognized option `--%s' Cannot change user/group to `%s': %s Could not find IP of host `%s': %s DEBUGERRORFile `%s' in directory `%s' does not match naming convention. Removed. I am peer `%s'. INFOInitialization of plugin mechanism failed: %s! Invalid format for IP: `%s' Invalid network notation ('/%d' is not legal in IPv4 CIDR).Invalid network notation (does not end with ';': `%s') No keywords specified! Option `%s' makes no sense without option `%s'. Print statistics about GNUnet operations.RSA signature verification failed at %s:%d: %s Trying to use file `%s' for MySQL configuration. Unknown metadata type in metadata option `%s'. Using metadata type `unknown' instead. WARNINGYou must pass a number to the `%s' option. `%s' failed at %s:%d with error: %s add an additional keyword for the top-level file or directory (this option can be specified multiple times)bdo not index, perform full insertion (stores entire file in encrypted form in GNUnet database)download a GNUnet directory recursivelyhlibgcrypt has not the expected version (version %s is required). mmsprint list of extracted keywords that would be used, but do not perform uploadpublish the files under the pseudonym NAME (place file into namespace)sset the ID of this version of the publication (for namespace insertions only)set the desired LEVEL of receiver-anonymityset the desired LEVEL of sender-anonymityset the meta-data for the given TYPE to the given VALUEspecify ID of an updated version to be published in the future (for namespace insertions only)specify the priority of the contentunknownwrite the file to FILENAMEProject-Id-Version: GNUnet 0.7.0e Report-Msgid-Bugs-To: gnunet-developers@mail.gnu.org POT-Creation-Date: 2012-06-05 15:47+0200 PO-Revision-Date: 2006-06-29 12:05+0200 Last-Translator: Miguel Angel Arruga Language-Team: Spanish Language: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n != 1); días# bytes desencriptados# bytes encriptados# bytes recibidos por TCP# mensajes defragmentados# mensajes fragmentados%s: opción ilegal -- %c %s: opción no válida -- %c %s: la opción '%c%s' no permite un argumento %s: la opción '%s' es ambigua %s: la opción '%s' requiere un argumento %s: la opción '--%s' no permite un argumento %s: la opción '-W %s' no permite un argumento %s: la opción '-W %s' es ambigua %s: la opción requiere un argumento --%c %s: opción no reconocida '%c%s' %s: opción no reconocida '--%s' Imposible cambiar el usuario/grupo a '%s': %s Imposible encontrar la IP del host '%s': %s DEPURACIÓNERROREl fichero '%s' en el directorio '%s' no sigue la convención de nombres. Eliminando. Yo soy el par '%s'. INFORMACIÓN¡El mecanismo de iniciación de los plugins falló: %s! Formato no válido para la IP: '%s' Notación de red no válida ('/%d' no es válido en IPv4 CIDR).Notación de red no válida (no termina con ';': '%s') ¡Ninguna clave especificada! La opción '%s' no tiene sentido sin la opción '%s'. Imprime estadísticas acerca de las operaciones de GNUnet.La verificación de la firma RSA fallo en %s: %d: %s Intentando usar el fichero '%s' para la configuración de MySQL. Tipo de metadatos desconocido en la opción de metadatos '%s'. Usando el tipo de metadatos 'desconocido' en su lugar. PELIGROTienes que introducir un número en la opción '%s'. '%s' falló en %s: %d con el error: %s añade una clave adicional para el fichero del nivel más alto o el directorio (esta opción puede ser especificada varias veces)bno indexar, hacer inserciones totales (almacena el fichero entero de forma encriptada en la base de datos de GNUnet)descarga un directorio de GNUnet recursivamentehlibgcrypt no está en la versión esperada (se necesita la versión %s). mmsimprime la lista de las claves extraidas que podrían ser usadas, pero no realiza la subidapublica los ficheros bajo el pseudónimo NOMBRE (coloca el fichero en el espacio)scambia la ID de esta versión de la publicación (para inserciones en el espacio únicamente)seleccione el NIVEL deseado de anonimidad-del-receptorseleccione el NIVEL deseado de anonimato al enviarcambia el meta-dato para el TIPO dado al VALOR dadoespecifica la ID de una versión actualizada para ser publicada en el futuro (para inserciones en el espacio únicamente)especifica la prioridad del contenidodesconocidoescribe el fichero al FICHEROgnunet-0.9.3/po/es.po0000644000175000017500000101000511763406751011340 00000000000000# Spanish translations for GNUnet package. # # This file is distributed under the same license as the GNUnet package. # Miguel Angel Arruga Vivas , 2006. # msgid "" msgstr "" "Project-Id-Version: GNUnet 0.7.0e\n" "Report-Msgid-Bugs-To: gnunet-developers@mail.gnu.org\n" "POT-Creation-Date: 2012-06-05 15:47+0200\n" "PO-Revision-Date: 2006-06-29 12:05+0200\n" "Last-Translator: Miguel Angel Arruga \n" "Language-Team: Spanish\n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: src/arm/arm_api.c:165 msgid "Failed to transmit shutdown request to client.\n" msgstr "" #: src/arm/arm_api.c:349 #, fuzzy, c-format msgid "Configuration failes to specify option `%s' in section `%s'!\n" msgstr "" "El fichero de configuración debe especificar el directorio para almacenar " "los datos FS en la sección '%s' bajo '%s'.\n" #: src/arm/arm_api.c:363 #, fuzzy, c-format msgid "Configuration fails to specify option `%s' in section `%s'!\n" msgstr "" "El fichero de configuración debe especificar el directorio para almacenar " "los datos FS en la sección '%s' bajo '%s'.\n" #: src/arm/arm_api.c:432 #, fuzzy, c-format msgid "Error receiving response to `%s' request from ARM for service `%s'\n" msgstr "Recibida respuesta anómala a'%s' del par '%s'.\n" #: src/arm/arm_api.c:485 #, c-format msgid "Requesting start of service `%s'.\n" msgstr "" #: src/arm/arm_api.c:486 #, c-format msgid "Requesting termination of service `%s'.\n" msgstr "" #: src/arm/arm_api.c:507 #, c-format msgid "Error while trying to transmit request to start `%s' to ARM\n" msgstr "" #: src/arm/arm_api.c:508 #, c-format msgid "Error while trying to transmit request to stop `%s' to ARM\n" msgstr "" #: src/arm/arm_api.c:540 #, fuzzy, c-format msgid "Asked to start service `%s' within %llu ms\n" msgstr "'%s': No se recibió el mensaje en %llu ms.\n" #: src/arm/arm_api.c:612 #, fuzzy, c-format msgid "Stopping service `%s' within %llu ms\n" msgstr "No se ha recibido una respuesta en %llums.\n" #: src/arm/gnunet-arm.c:159 #, fuzzy, c-format msgid "Service `%s' is unknown to ARM.\n" msgstr "El espacio '%s' ha sido valorado con un %d.\n" #: src/arm/gnunet-arm.c:164 #, fuzzy, c-format msgid "Service `%s' has been stopped.\n" msgstr "Servicio eliminado.\n" #: src/arm/gnunet-arm.c:167 #, fuzzy, c-format msgid "Service `%s' was already running.\n" msgstr "¡Esta búsqueda está aún pendiente!\n" #: src/arm/gnunet-arm.c:172 #, fuzzy, c-format msgid "Service `%s' has been started.\n" msgstr "Servicio eliminado.\n" #: src/arm/gnunet-arm.c:175 #, fuzzy, c-format msgid "Service `%s' was already being stopped.\n" msgstr "Servicio eliminado.\n" #: src/arm/gnunet-arm.c:179 #, fuzzy, c-format msgid "Service `%s' was already not running.\n" msgstr "¡Esta búsqueda está aún pendiente!\n" #: src/arm/gnunet-arm.c:183 #, fuzzy msgid "Request ignored as ARM is shutting down.\n" msgstr "'%s' se esta cerrando.\n" #: src/arm/gnunet-arm.c:187 #, fuzzy msgid "Error communicating with ARM service.\n" msgstr "Imprime información de los pares de GNUnet." #: src/arm/gnunet-arm.c:191 #, fuzzy msgid "Timeout communicating with ARM service.\n" msgstr "Imprime información de los pares de GNUnet." #: src/arm/gnunet-arm.c:195 #, fuzzy msgid "Operation failed.\n" msgstr "La verificación de la firma RSA fallo en %s: %d: %s\n" #: src/arm/gnunet-arm.c:199 msgid "Unknown response code from ARM.\n" msgstr "" #: src/arm/gnunet-arm.c:222 #, fuzzy msgid "Error communicating with ARM. ARM not running?\n" msgstr "Imprime información de los pares de GNUnet." #: src/arm/gnunet-arm.c:225 #, fuzzy msgid "Running services:\n" msgstr "Iniciada colección '%s'.\n" #: src/arm/gnunet-arm.c:249 #, c-format msgid "Fatal configuration error: `%s' option in section `%s' missing.\n" msgstr "" #: src/arm/gnunet-arm.c:257 src/arm/gnunet-arm.c:357 src/arm/gnunet-arm.c:373 msgid "Fatal error initializing ARM API.\n" msgstr "" #: src/arm/gnunet-arm.c:280 #, fuzzy, c-format msgid "Failed to remove configuration file %s\n" msgstr "Imposible guardar el fichero de configuración '%s':" #: src/arm/gnunet-arm.c:286 #, fuzzy, c-format msgid "Failed to remove servicehome directory %s\n" msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" #: src/arm/gnunet-arm.c:407 msgid "stop all GNUnet services" msgstr "" #: src/arm/gnunet-arm.c:409 msgid "start a particular service" msgstr "" #: src/arm/gnunet-arm.c:411 msgid "stop a particular service" msgstr "" #: src/arm/gnunet-arm.c:413 msgid "start all GNUnet default services" msgstr "" #: src/arm/gnunet-arm.c:416 msgid "stop and start all GNUnet default services" msgstr "" #: src/arm/gnunet-arm.c:419 msgid "delete config file and directory on exit" msgstr "" #: src/arm/gnunet-arm.c:421 msgid "don't print status messages" msgstr "" #: src/arm/gnunet-arm.c:424 #, fuzzy msgid "timeout for completing current operation" msgstr "tiempo para esperar hasta completar una iteración (en ms)" #: src/arm/gnunet-arm.c:426 msgid "List currently running services" msgstr "" #: src/arm/gnunet-arm.c:437 msgid "Control services and the Automated Restart Manager (ARM)" msgstr "" #: src/arm/gnunet-service-arm.c:332 #, fuzzy, c-format msgid "Failed to start service `%s'\n" msgstr "Falló al comenzar la recolección.\n" #: src/arm/gnunet-service-arm.c:335 #, fuzzy, c-format msgid "Starting service `%s'\n" msgstr "Iniciada colección '%s'.\n" #: src/arm/gnunet-service-arm.c:361 #, fuzzy msgid "Could not send status result to client\n" msgstr "Imposible mandar el mensaje a gnunetd\n" #: src/arm/gnunet-service-arm.c:393 #, fuzzy msgid "Could not send list result to client\n" msgstr "Imposible mandar el mensaje a gnunetd\n" #: src/arm/gnunet-service-arm.c:523 #, fuzzy, c-format msgid "Unable to create socket for service `%s': %s\n" msgstr "Imposible crear la cuenta de usuario:" #: src/arm/gnunet-service-arm.c:545 #, c-format msgid "Unable to bind listening socket for service `%s' to address `%s': %s\n" msgstr "" #: src/arm/gnunet-service-arm.c:559 #, c-format msgid "ARM now monitors connections to service `%s' at `%s'\n" msgstr "" #: src/arm/gnunet-service-arm.c:667 #, fuzzy, c-format msgid "Preparing to stop `%s'\n" msgstr "Iniciada colección '%s'.\n" #: src/arm/gnunet-service-arm.c:878 #, fuzzy, c-format msgid "Restarting service `%s'.\n" msgstr "Iniciada colección '%s'.\n" #: src/arm/gnunet-service-arm.c:970 msgid "exit" msgstr "" #: src/arm/gnunet-service-arm.c:975 msgid "signal" msgstr "" #: src/arm/gnunet-service-arm.c:980 msgid "unknown" msgstr "desconocido" #: src/arm/gnunet-service-arm.c:986 #, fuzzy, c-format msgid "Service `%s' took %llu ms to terminate\n" msgstr "Servicio eliminado.\n" #: src/arm/gnunet-service-arm.c:1021 #, c-format msgid "Service `%s' terminated with status %s/%d, will restart in %llu ms\n" msgstr "" #: src/arm/gnunet-service-arm.c:1127 #, fuzzy, c-format msgid "Configuration file `%s' for service `%s' not valid: %s\n" msgstr "Fichero de configuración '%s' creado.\n" #: src/arm/gnunet-service-arm.c:1129 msgid "option missing" msgstr "" #: src/arm/gnunet-service-arm.c:1213 #, fuzzy, c-format msgid "Starting default services `%s'\n" msgstr "Iniciada colección '%s'.\n" #: src/arm/gnunet-service-arm.c:1224 #, c-format msgid "Default service `%s' not configured correctly!\n" msgstr "" #: src/arm/gnunet-service-arm.c:1238 msgid "" "No default services configured, GNUnet will not really start right now.\n" msgstr "" #: src/arm/mockup-service.c:44 msgid "Initiating shutdown as requested by client.\n" msgstr "" #: src/block/block.c:105 #, fuzzy, c-format msgid "Loading block plugin `%s'\n" msgstr "Probando transporte(s) %s\n" #: src/chat/chat.c:175 #, fuzzy msgid "Could not transmit confirmation receipt\n" msgstr "Imposible acceder a la información del espacio.\n" #: src/chat/chat.c:283 msgid "The current user must be the the first one joined\n" msgstr "" #: src/chat/chat.c:412 #, fuzzy, c-format msgid "Unknown message type: '%u'\n" msgstr "Operación desconocida '%s'\n" #: src/chat/chat.c:472 #, fuzzy, c-format msgid "Configuration option `%s' in section `%s' missing\n" msgstr "Fichero de configuración '%s' creado.\n" #: src/chat/chat.c:480 #, fuzzy, c-format msgid "Failed to access chat home directory `%s'\n" msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" #: src/chat/chat.c:498 #, fuzzy, c-format msgid "Failed to create/open key in file `%s'\n" msgstr "Fichero almacenado en '%s'.\n" #: src/chat/chat.c:559 #, fuzzy msgid "Could not serialize metadata\n" msgstr "¡Imposible inicializar libgnunetutil!\n" #: src/chat/chat.c:674 #, fuzzy msgid "Failed to connect to the chat service\n" msgstr "Fallo al conectar a gnunetd.\n" #: src/chat/chat.c:680 msgid "Undefined mandatory parameter: joinCallback\n" msgstr "" #: src/chat/chat.c:686 msgid "Undefined mandatory parameter: messageCallback\n" msgstr "" #: src/chat/chat.c:692 msgid "Undefined mandatory parameter: memberCallback\n" msgstr "" #: src/chat/gnunet-chat.c:93 msgid "Joined\n" msgstr "" #: src/chat/gnunet-chat.c:125 src/chat/gnunet-chat.c:133 #: src/chat/gnunet-chat.c:213 src/chat/gnunet-chat.c:253 #: src/chat/gnunet-chat.c:329 src/chat/gnunet-chat.c:371 #: src/chat/gnunet-chat.c:400 src/chat/gnunet-chat.c:700 msgid "anonymous" msgstr "" #: src/chat/gnunet-chat.c:144 #, fuzzy, c-format msgid "(%s) `%s' said: %s\n" msgstr "'%s' %s falló: %s\n" #: src/chat/gnunet-chat.c:147 src/chat/gnunet-chat.c:150 #, fuzzy, c-format msgid "(%s) `%s' said to you: %s\n" msgstr "'%s' %s falló: %s\n" #: src/chat/gnunet-chat.c:153 #, fuzzy, c-format msgid "(%s) `%s' said for sure: %s\n" msgstr "'%s' %s falló: %s\n" #: src/chat/gnunet-chat.c:156 #, fuzzy, c-format msgid "(%s) `%s' said to you for sure: %s\n" msgstr "'%s' falló con el código de error %s: %s" #: src/chat/gnunet-chat.c:159 #, fuzzy, c-format msgid "(%s) `%s' was confirmed that you received: %s\n" msgstr "'%s' falló con el código de error %d: %s" #: src/chat/gnunet-chat.c:162 #, fuzzy, c-format msgid "(%s) `%s' was confirmed that you and only you received: %s\n" msgstr "'%s' falló con el código de error %d: %s" #: src/chat/gnunet-chat.c:165 #, fuzzy, c-format msgid "(%s) `%s' was confirmed that you received from him or her: %s\n" msgstr "'%s' falló con el código de error %d: %s" #: src/chat/gnunet-chat.c:170 #, fuzzy, c-format msgid "" "(%s) `%s' was confirmed that you and only you received from him or her: %s\n" msgstr "'%s' falló con el código de error %d: %s" #: src/chat/gnunet-chat.c:173 #, fuzzy, c-format msgid "(%s) `%s' said off the record: %s\n" msgstr "'%s' falló con el código de error %s: %s" #: src/chat/gnunet-chat.c:176 #, c-format msgid "(%s) <%s> said using an unknown message type: %s\n" msgstr "" #: src/chat/gnunet-chat.c:217 #, c-format msgid "'%s' acknowledged message #%d\n" msgstr "" #: src/chat/gnunet-chat.c:260 #, c-format msgid "`%s' entered the room\n" msgstr "" #: src/chat/gnunet-chat.c:260 #, c-format msgid "`%s' left the room\n" msgstr "" #: src/chat/gnunet-chat.c:321 src/chat/gnunet-chat.c:363 #, fuzzy msgid "Could not change username\n" msgstr "Imposible crear el espacio '%s' (¿existe?).\n" #: src/chat/gnunet-chat.c:334 src/chat/gnunet-chat.c:702 #, fuzzy, c-format msgid "Joining room `%s' as user `%s'...\n" msgstr "Respuesta inválida a '%s' del par '%s'.\n" #: src/chat/gnunet-chat.c:373 #, fuzzy, c-format msgid "Changed username to `%s'\n" msgstr "Imposible cambiar el usuario/grupo a '%s': %s\n" #: src/chat/gnunet-chat.c:388 #, fuzzy, c-format msgid "Users in room `%s': " msgstr "Fichero almacenado en '%s'.\n" #: src/chat/gnunet-chat.c:434 msgid "Syntax: /msg USERNAME MESSAGE" msgstr "" #: src/chat/gnunet-chat.c:443 #, c-format msgid "Unknown user `%s'. Make sure you specify its numeric suffix, if any.\n" msgstr "" #: src/chat/gnunet-chat.c:460 #, c-format msgid "User `%s' is currently not in the room!\n" msgstr "" #: src/chat/gnunet-chat.c:513 #, fuzzy, c-format msgid "Unknown command `%s'\n" msgstr "Operación desconocida '%s'\n" #: src/chat/gnunet-chat.c:524 msgid "" "Use `/join #roomname' to join a chat room. Joining a room will cause you to " "leave the current room" msgstr "" #: src/chat/gnunet-chat.c:528 msgid "" "Use `/nick nickname' to change your nickname. This will cause you to leave " "the current room and immediately rejoin it with the new name." msgstr "" #: src/chat/gnunet-chat.c:532 msgid "" "Use `/msg nickname message' to send a private message to the specified user" msgstr "" #: src/chat/gnunet-chat.c:535 msgid "The `/notice' command is an alias for `/msg'" msgstr "" #: src/chat/gnunet-chat.c:537 msgid "The `/query' command is an alias for `/msg'" msgstr "" #: src/chat/gnunet-chat.c:539 msgid "Use `/sig message' to send a signed public message" msgstr "" #: src/chat/gnunet-chat.c:542 msgid "Use `/ack message' to require signed acknowledgment of the message" msgstr "" #: src/chat/gnunet-chat.c:545 msgid "Use `/anonymous message' to send a public anonymous message" msgstr "" #: src/chat/gnunet-chat.c:547 msgid "The `/anon' command is an alias for `/anonymous'" msgstr "" #: src/chat/gnunet-chat.c:549 msgid "Use `/quit' to terminate gnunet-chat" msgstr "" #: src/chat/gnunet-chat.c:551 msgid "The `/leave' command is an alias for `/quit'" msgstr "" #: src/chat/gnunet-chat.c:554 msgid "Use `/names' to list all of the current members in the chat room" msgstr "" #: src/chat/gnunet-chat.c:556 msgid "Use `/help command' to get help for a specific command" msgstr "" #: src/chat/gnunet-chat.c:672 #, fuzzy msgid "You must specify a nickname\n" msgstr "¡Debes especificar un receptor!\n" #: src/chat/gnunet-chat.c:688 #, fuzzy, c-format msgid "Failed to join room `%s'\n" msgstr "Fichero almacenado en '%s'.\n" #: src/chat/gnunet-chat.c:727 msgid "set the nickname to use (required)" msgstr "" #: src/chat/gnunet-chat.c:730 msgid "set the chat room to join" msgstr "" #: src/chat/gnunet-chat.c:742 msgid "Join a chat on GNUnet." msgstr "" #: src/chat/gnunet-service-chat.c:267 #, fuzzy msgid "Failed to queue a message notification\n" msgstr "Imposible guardar la configuración" #: src/chat/gnunet-service-chat.c:546 #, fuzzy msgid "Failed to queue a join notification\n" msgstr "Imposible guardar la configuración" #: src/chat/gnunet-service-chat.c:729 #, fuzzy msgid "Failed to queue a confirmation receipt\n" msgstr "Imposible guardar la configuración" #: src/chat/gnunet-service-chat.c:907 #, fuzzy msgid "Failed to queue a leave notification\n" msgstr "Imposible guardar la configuración" #: src/core/core_api.c:786 msgid "Client was disconnected from core service, trying to reconnect.\n" msgstr "" #: src/core/gnunet-core.c:54 src/peerinfo-tool/gnunet-peerinfo.c:286 #, fuzzy, c-format msgid "Peer `%s'\n" msgstr "Yo soy el par '%s'.\n" #: src/core/gnunet-core.c:72 src/peerinfo-tool/gnunet-peerinfo.c:817 #, fuzzy, c-format msgid "Invalid command line argument `%s'\n" msgstr "Argumentos en la linea de comandos inválidos:\n" #: src/core/gnunet-core.c:95 #, fuzzy msgid "Print information about connected peers." msgstr "Imprime información de los pares de GNUnet." #: src/core/gnunet-service-core.c:97 #, c-format msgid "Core service of `%4s' ready.\n" msgstr "" #: src/core/gnunet-service-core_clients.c:370 #, fuzzy msgid "# send requests dropped (disconnected)" msgstr "# Anuncios de los pares recibidos" #: src/core/gnunet-service-core_clients.c:475 #, fuzzy msgid "# messages discarded (session disconnected)" msgstr "# mensajes defragmentados" #: src/core/gnunet-service-core_clients.c:818 #, fuzzy, c-format msgid "# bytes of messages of type %u received" msgstr "# bytes de ruido recibidos" #: src/core/gnunet-service-core_kx.c:565 msgid "# bytes encrypted" msgstr "# bytes encriptados" #: src/core/gnunet-service-core_kx.c:617 msgid "# bytes decrypted" msgstr "# bytes desencriptados" #: src/core/gnunet-service-core_kx.c:681 src/dv/gnunet-service-dv.c:3003 #, fuzzy msgid "Error in communication with PEERINFO service\n" msgstr "Imprime información de los pares de GNUnet." #: src/core/gnunet-service-core_kx.c:700 msgid "# Delayed connecting due to lack of public key" msgstr "" #: src/core/gnunet-service-core_kx.c:753 msgid "# key exchanges initiated" msgstr "" #: src/core/gnunet-service-core_kx.c:775 msgid "# key exchanges stopped" msgstr "" #: src/core/gnunet-service-core_kx.c:828 #, fuzzy msgid "# session keys received" msgstr "# claves de la sesión rechazadas" #: src/core/gnunet-service-core_kx.c:845 #, fuzzy, c-format msgid "`%s' is for `%s', not for me. Ignoring.\n" msgstr "el tamaño del '%s' mensaje es demasiado corto. Ignorandolo.\n" #: src/core/gnunet-service-core_kx.c:890 #, fuzzy msgid "# SET_KEY messages decrypted" msgstr "# mensajes defragmentados" #: src/core/gnunet-service-core_kx.c:977 #: src/transport/gnunet-service-transport_validation.c:810 #, fuzzy msgid "# PING messages received" msgstr "# mensajes PONG encriptados recibidos" #: src/core/gnunet-service-core_kx.c:1010 #, c-format msgid "" "Received PING from `%s' for different identity: I am `%s', PONG identity: `" "%s'\n" msgstr "" #: src/core/gnunet-service-core_kx.c:1029 #, fuzzy msgid "# PONG messages created" msgstr "# mensajes fragmentados" #: src/core/gnunet-service-core_kx.c:1125 #, fuzzy msgid "# sessions terminated by timeout" msgstr "# bytes omitidos por TCP (salientes)" #: src/core/gnunet-service-core_kx.c:1135 #, fuzzy msgid "# keepalive messages sent" msgstr "# mensajes PONG encriptados recibidos" #: src/core/gnunet-service-core_kx.c:1236 #: src/transport/gnunet-service-transport_validation.c:1031 #, fuzzy msgid "# PONG messages received" msgstr "# mensajes PONG encriptados recibidos" #: src/core/gnunet-service-core_kx.c:1275 #, fuzzy msgid "# PONG messages decrypted" msgstr "# mensajes defragmentados" #: src/core/gnunet-service-core_kx.c:1303 #, fuzzy msgid "# session keys confirmed via PONG" msgstr "# Anuncios de los pares recibidos" #: src/core/gnunet-service-core_kx.c:1329 #, fuzzy msgid "# rekey operations confirmed via PONG" msgstr "# Anuncios de los pares recibidos" #: src/core/gnunet-service-core_kx.c:1381 #: src/core/gnunet-service-core_kx.c:1398 #, fuzzy msgid "# SET_KEY and PING messages created" msgstr "# mensajes de texto mandados por PING" #: src/core/gnunet-service-core_kx.c:1402 msgid "# REKEY operations performed" msgstr "" #: src/core/gnunet-service-core_kx.c:1537 msgid "# failed to decrypt message (no session key)" msgstr "" #: src/core/gnunet-service-core_kx.c:1577 #: src/core/gnunet-service-core_kx.c:1602 #, fuzzy msgid "# bytes dropped (duplicates)" msgstr "# bytes omitidos por UDP (salientes)" #: src/core/gnunet-service-core_kx.c:1589 #, fuzzy msgid "# bytes dropped (out of sequence)" msgstr "# bytes omitidos por UDP (salientes)" #: src/core/gnunet-service-core_kx.c:1626 #, fuzzy, c-format msgid "Message received far too old (%llu ms). Content ignored.\n" msgstr "El mensaje recibido del cliente es inválido\n" #: src/core/gnunet-service-core_kx.c:1630 #, fuzzy msgid "# bytes dropped (ancient message)" msgstr "# bytes omitidos por UDP (salientes)" #: src/core/gnunet-service-core_kx.c:1638 #, fuzzy msgid "# bytes of payload decrypted" msgstr "# bytes desencriptados" #: src/core/gnunet-service-core_kx.c:1700 #, fuzzy msgid "Core service is lacking HOSTKEY configuration setting. Exiting.\n" msgstr "Configuración de GNUnet" #: src/core/gnunet-service-core_kx.c:1708 msgid "Core service could not access hostkey. Exiting.\n" msgstr "" #: src/core/gnunet-service-core_kx.c:1718 src/hostlist/hostlist-server.c:551 #: src/peerinfo-tool/gnunet-peerinfo.c:823 #: src/transport/gnunet-service-transport.c:611 #, fuzzy msgid "Could not access PEERINFO service. Exiting.\n" msgstr "Imposible acceder a la información del espacio.\n" #: src/core/gnunet-service-core_neighbours.c:163 #, fuzzy msgid "# sessions terminated by transport disconnect" msgstr "# Anuncios de los pares recibidos" #: src/core/gnunet-service-core_neighbours.c:180 #: src/core/gnunet-service-core_neighbours.c:334 msgid "# neighbour entries allocated" msgstr "" #: src/core/gnunet-service-core_neighbours.c:247 msgid "# encrypted bytes given to transport" msgstr "" #: src/core/gnunet-service-core_neighbours.c:418 #, fuzzy, c-format msgid "Unsupported message of type %u (%u bytes) received from peer `%s'\n" msgstr "Mensaje no válido del tipo %u recibido. Omitiendo.\n" #: src/core/gnunet-service-core_sessions.c:206 #: src/core/gnunet-service-core_sessions.c:269 #: src/dht/gnunet-service-dht_neighbours.c:625 #: src/dht/gnunet-service-dht_neighbours.c:683 #: src/fs/gnunet-service-fs_cp.c:615 src/fs/gnunet-service-fs_cp.c:1532 #: src/topology/gnunet-daemon-topology.c:709 #: src/topology/gnunet-daemon-topology.c:810 #: src/transport/gnunet-service-transport_neighbours.c:874 #: src/transport/gnunet-service-transport_neighbours.c:1080 #: src/transport/gnunet-service-transport_neighbours.c:1089 #: src/transport/gnunet-service-transport_neighbours.c:2568 #: src/transport/gnunet-service-transport_neighbours.c:2814 #, fuzzy msgid "# peers connected" msgstr "# de pares conectados" #: src/core/gnunet-service-core_sessions.c:236 msgid "# type map refreshes sent" msgstr "" #: src/core/gnunet-service-core_sessions.c:406 msgid "# messages discarded (expired prior to transmission)" msgstr "" #: src/core/gnunet-service-core_typemap.c:110 #: src/core/gnunet-service-core_typemap.c:121 #, fuzzy msgid "# type maps received" msgstr "# mensajes PONG encriptados recibidos" #: src/core/gnunet-service-core_typemap.c:151 msgid "# updates to my type map" msgstr "" #: src/datacache/datacache.c:115 src/datacache/datacache.c:250 #: src/datastore/gnunet-service-datastore.c:834 #, fuzzy msgid "# bytes stored" msgstr "# bytes en la base de datos" #: src/datacache/datacache.c:141 src/datacache/datacache.c:148 #: src/datastore/gnunet-service-datastore.c:1483 #: src/datastore/gnunet-service-datastore.c:1494 #, fuzzy, c-format msgid "No `%s' specified for `%s' in configuration!\n" msgstr "¡Ninguna aplicación definida en la configuración!\n" #: src/datacache/datacache.c:180 #, c-format msgid "Loading `%s' datacache plugin\n" msgstr "" #: src/datacache/datacache.c:188 #, fuzzy, c-format msgid "Failed to load datacache plugin for `%s'\n" msgstr "Falló al actualizar los datos del módulo '%s'\n" #: src/datacache/datacache.c:276 #, fuzzy msgid "# requests received" msgstr "# mensajes PONG encriptados recibidos" #: src/datacache/datacache.c:284 msgid "# requests filtered by bloom filter" msgstr "" #: src/datacache/plugin_datacache_mysql.c:97 #: src/datacache/plugin_datacache_mysql.c:104 #: src/datacache/plugin_datacache_sqlite.c:69 #: src/datacache/plugin_datacache_sqlite.c:72 #: src/datastore/plugin_datastore_mysql.c:803 #: src/datastore/plugin_datastore_mysql.c:817 #: src/datastore/plugin_datastore_sqlite.c:57 src/mysql/mysql.c:41 #: src/mysql/mysql.c:48 src/mysql/mysql.c:522 src/mysql/mysql.c:531 #: src/mysql/mysql.c:591 src/mysql/mysql.c:607 #: src/namestore/plugin_namestore_sqlite.c:51 src/util/crypto_ksk.c:49 #: src/util/crypto_rsa.c:67 src/include/gnunet_common.h:525 #: src/include/gnunet_common.h:532 #, c-format msgid "`%s' failed at %s:%d with error: %s\n" msgstr "'%s' falló en %s: %d con el error: %s\n" #: src/datacache/plugin_datacache_mysql.c:450 msgid "MySQL datacache running\n" msgstr "" #: src/datacache/plugin_datacache_postgres.c:367 msgid "Postgres datacache running\n" msgstr "" #: src/datacache/plugin_datacache_sqlite.c:410 msgid "Sqlite datacache running\n" msgstr "" #: src/datacache/plugin_datacache_sqlite.c:443 #: src/datastore/plugin_datastore_sqlite.c:408 #: src/namestore/plugin_namestore_sqlite.c:370 msgid "Tried to close sqlite without finalizing all prepared statements.\n" msgstr "" #: src/datacache/plugin_datacache_sqlite.c:450 #, fuzzy, c-format msgid "Failed to close statement %p: %d\n" msgstr "Falló al actualizar los datos del módulo '%s'\n" #: src/datacache/plugin_datacache_template.c:121 msgid "Template datacache running\n" msgstr "" #: src/datastore/datastore_api.c:305 #, fuzzy msgid "Failed to transmit request to drop database.\n" msgstr "Falló al mandar la petición HTTP al host '%s': %s\n" #: src/datastore/datastore_api.c:388 msgid "# queue entry timeouts" msgstr "" #: src/datastore/datastore_api.c:432 msgid "# queue overflows" msgstr "" #: src/datastore/datastore_api.c:459 msgid "# queue entries created" msgstr "" #: src/datastore/datastore_api.c:477 #, fuzzy msgid "# Requests dropped from datastore queue" msgstr "# Anuncios de los pares recibidos" #: src/datastore/datastore_api.c:525 msgid "# datastore connections (re)created" msgstr "" #: src/datastore/datastore_api.c:548 msgid "# reconnected to DATASTORE" msgstr "" #: src/datastore/datastore_api.c:612 #, fuzzy msgid "# transmission request failures" msgstr "# mensajes de texto mandados por PING" #: src/datastore/datastore_api.c:633 #, fuzzy msgid "# bytes sent to datastore" msgstr "# bytes en la base de datos" #: src/datastore/datastore_api.c:764 #, fuzzy msgid "Failed to receive status response from database." msgstr "" "\n" "Fallo al recibir la respuesta de gnunetd.\n" #: src/datastore/datastore_api.c:778 msgid "Error reading response from datastore service" msgstr "" #: src/datastore/datastore_api.c:790 src/datastore/datastore_api.c:796 #, fuzzy msgid "Invalid error message received from datastore service" msgstr "Mensaje '%s' inválido recibido del par '%s'.\n" #: src/datastore/datastore_api.c:800 #, fuzzy msgid "# status messages received" msgstr "# mensajes PONG encriptados recibidos" #: src/datastore/datastore_api.c:869 #, fuzzy msgid "# PUT requests executed" msgstr "# mensajes PONG encriptados recibidos" #: src/datastore/datastore_api.c:936 msgid "# RESERVE requests executed" msgstr "" #: src/datastore/datastore_api.c:997 msgid "# RELEASE RESERVE requests executed" msgstr "" #: src/datastore/datastore_api.c:1054 #, fuzzy msgid "# UPDATE requests executed" msgstr "# mensajes PONG encriptados recibidos" #: src/datastore/datastore_api.c:1118 #, fuzzy msgid "# REMOVE requests executed" msgstr "# mensajes PONG encriptados recibidos" #: src/datastore/datastore_api.c:1163 #, fuzzy msgid "Failed to receive response from database.\n" msgstr "" "\n" "Fallo al recibir la respuesta de gnunetd.\n" #: src/datastore/datastore_api.c:1221 #, fuzzy msgid "# Results received" msgstr "# bytes recibidos por TCP" #: src/datastore/datastore_api.c:1286 msgid "# GET REPLICATION requests executed" msgstr "" #: src/datastore/datastore_api.c:1349 msgid "# GET ZERO ANONYMITY requests executed" msgstr "" #: src/datastore/datastore_api.c:1409 #, fuzzy msgid "# GET requests executed" msgstr "# mensajes PONG encriptados recibidos" #: src/datastore/gnunet-service-datastore.c:349 #, fuzzy msgid "# bytes expired" msgstr "# bytes recibidos por TCP" #: src/datastore/gnunet-service-datastore.c:422 msgid "# bytes purged (low-priority)" msgstr "" #: src/datastore/gnunet-service-datastore.c:480 msgid "Transmission to client failed!\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:511 msgid "Shutdown in progress, aborting transmission.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:626 msgid "# results found" msgstr "" #: src/datastore/gnunet-service-datastore.c:669 #, c-format msgid "" "Insufficient space (%llu bytes are available) to satisfy `%s' request for " "%llu bytes\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:680 #, c-format msgid "" "The requested amount (%llu bytes) is larger than the cache size (%llu " "bytes)\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:684 msgid "" "Insufficient space to satisfy request and requested amount is larger than " "cache size" msgstr "" #: src/datastore/gnunet-service-datastore.c:690 msgid "Insufficient space to satisfy request" msgstr "" #: src/datastore/gnunet-service-datastore.c:695 #: src/datastore/gnunet-service-datastore.c:747 #: src/datastore/gnunet-service-datastore.c:960 #: src/datastore/gnunet-service-datastore.c:1417 msgid "# reserved" msgstr "" #: src/datastore/gnunet-service-datastore.c:760 msgid "Could not find matching reservation" msgstr "" #: src/datastore/gnunet-service-datastore.c:846 #, c-format msgid "Need %llu bytes more space (%llu allowed, using %llu)\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1006 #, fuzzy msgid "# GET requests received" msgstr "# mensajes PONG encriptados recibidos" #: src/datastore/gnunet-service-datastore.c:1018 msgid "# requests filtered by bloomfilter" msgstr "" #: src/datastore/gnunet-service-datastore.c:1046 #, fuzzy msgid "# UPDATE requests received" msgstr "# mensajes PONG encriptados recibidos" #: src/datastore/gnunet-service-datastore.c:1076 #, fuzzy msgid "# GET REPLICATION requests received" msgstr "# mensajes PONG encriptados recibidos" #: src/datastore/gnunet-service-datastore.c:1109 #, fuzzy msgid "# GET ZERO ANONYMITY requests received" msgstr "# mensajes PONG encriptados recibidos" #: src/datastore/gnunet-service-datastore.c:1134 #, fuzzy msgid "Content not found" msgstr "¡Comando '%s' no encontrado!\n" #: src/datastore/gnunet-service-datastore.c:1142 msgid "# bytes removed (explicit request)" msgstr "" #: src/datastore/gnunet-service-datastore.c:1174 #, fuzzy msgid "# REMOVE requests received" msgstr "# mensajes PONG encriptados recibidos" #: src/datastore/gnunet-service-datastore.c:1216 #, c-format msgid "Datastore payload inaccurate (%lld < %lld). Trying to fix.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1277 #, c-format msgid "Loading `%s' datastore plugin\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1286 #, fuzzy, c-format msgid "Failed to load datastore plugin for `%s'\n" msgstr "Imposible inicializar la aplicación '%s'\n" #: src/datastore/gnunet-service-datastore.c:1488 #, fuzzy, c-format msgid "# bytes used in file-sharing datastore `%s'" msgstr "# bytes en la base de datos" #: src/datastore/gnunet-service-datastore.c:1499 msgid "# quota" msgstr "" #: src/datastore/gnunet-service-datastore.c:1501 msgid "# cache size" msgstr "" #: src/datastore/gnunet-service-datastore.c:1514 #, c-format msgid "Could not use specified filename `%s' for bloomfilter.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1532 #: src/datastore/gnunet-service-datastore.c:1548 #, fuzzy, c-format msgid "Failed to remove bogus bloomfilter file `%s'\n" msgstr "Imposible guardar el fichero de configuración '%s':" #: src/datastore/gnunet-service-datastore.c:1578 #, fuzzy msgid "Failed to initialize bloomfilter.\n" msgstr "Imposible inicializar SQLite.\n" #: src/datastore/gnunet-service-datastore.c:1607 msgid "Rebuilding bloomfilter. Please be patient.\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1612 msgid "Plugin does not support get_keys function. Please fix!\n" msgstr "" #: src/datastore/gnunet-service-datastore.c:1615 msgid "Bloomfilter construction complete.\n" msgstr "" #: src/datastore/plugin_datastore_mysql.c:780 #, fuzzy, c-format msgid "Failed to prepare statement `%s'\n" msgstr "Falló al actualizar los datos del módulo '%s'\n" #: src/datastore/plugin_datastore_mysql.c:788 #, fuzzy, c-format msgid "`%s' for `%s' failed at %s:%d with error: %s\n" msgstr "'%s' a '%s' falló en %s: %d con error %s\n" #: src/datastore/plugin_datastore_mysql.c:1019 msgid "Mysql database running\n" msgstr "" #: src/datastore/plugin_datastore_postgres.c:824 #, fuzzy msgid "Failed to drop table from database.\n" msgstr "" "\n" "Fallo al recibir la respuesta de gnunetd.\n" #: src/datastore/plugin_datastore_postgres.c:860 msgid "Postgres database running\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:57 #, fuzzy, c-format msgid "`%s' failed at %s:%u with error: %s" msgstr "'%s' falló en %s: %d con el error: %s\n" #: src/datastore/plugin_datastore_sqlite.c:233 #: src/namestore/plugin_namestore_sqlite.c:204 #, fuzzy, c-format msgid "Option `%s' in section `%s' missing in configuration!\n" msgstr "¡Ninguna aplicación definida en la configuración!\n" #: src/datastore/plugin_datastore_sqlite.c:260 #: src/namestore/plugin_namestore_sqlite.c:229 #, fuzzy, c-format msgid "Unable to initialize SQLite: %s.\n" msgstr "Imposible inicializar SQLite.\n" #: src/datastore/plugin_datastore_sqlite.c:655 #, fuzzy msgid "Invalid data in database. Trying to fix (by deletion).\n" msgstr "Datos no válidos en %s. Intentando fijar (por borrado).\n" #: src/datastore/plugin_datastore_sqlite.c:1139 msgid "sqlite version to old to determine size, assuming zero\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:1158 #, c-format msgid "" "Using sqlite page utilization to estimate payload (%llu pages of size %llu " "bytes)\n" msgstr "" #: src/datastore/plugin_datastore_sqlite.c:1198 #: src/namestore/plugin_namestore_sqlite.c:829 #, fuzzy msgid "Sqlite database running\n" msgstr "base de datos sqlite" #: src/datastore/plugin_datastore_template.c:241 msgid "Template database running\n" msgstr "" #: src/dht/dht_api.c:348 #, fuzzy msgid "Failed to connect to the DHT service!\n" msgstr "Fallo al conectar a gnunetd.\n" #: src/dht/gnunet-dht-get.c:201 src/dht/gnunet-dht-monitor.c:293 #: src/dht/gnunet-dht-put.c:192 msgid "the query key" msgstr "" #: src/dht/gnunet-dht-get.c:204 msgid "how many parallel requests (replicas) to create" msgstr "" #: src/dht/gnunet-dht-get.c:207 src/dht/gnunet-dht-monitor.c:296 msgid "the type of data to look for" msgstr "" #: src/dht/gnunet-dht-get.c:210 src/dht/gnunet-dht-put.c:201 msgid "how long to execute this query before giving up?" msgstr "" #: src/dht/gnunet-dht-get.c:213 src/dht/gnunet-dht-monitor.c:302 #: src/dht/gnunet-dht-put.c:204 src/fs/gnunet-download.c:271 #: src/fs/gnunet-publish.c:731 src/fs/gnunet-search.c:297 #: src/fs/gnunet-unindex.c:169 src/nse/gnunet-nse-profiler.c:910 msgid "be verbose (print progress information)" msgstr "" #: src/dht/gnunet-dht-get.c:232 msgid "Issue a GET request to the GNUnet DHT, prints results." msgstr "" #: src/dht/gnunet-dht-monitor.c:299 msgid "how long to execute? 0 = forever" msgstr "" #: src/dht/gnunet-dht-monitor.c:321 msgid "Prints all packets that go through the DHT." msgstr "" #: src/dht/gnunet-dht-put.c:108 msgid "PUT request sent!\n" msgstr "" #: src/dht/gnunet-dht-put.c:111 msgid "Timeout sending PUT request!\n" msgstr "" #: src/dht/gnunet-dht-put.c:114 #, fuzzy msgid "PUT request not confirmed!\n" msgstr "# mensajes PONG encriptados recibidos" #: src/dht/gnunet-dht-put.c:144 msgid "Must provide KEY and DATA for DHT put!\n" msgstr "" #: src/dht/gnunet-dht-put.c:152 #, fuzzy, c-format msgid "Could not connect to %s service!\n" msgstr "Imposible conectar con gnunetd.\n" #: src/dht/gnunet-dht-put.c:157 #, fuzzy, c-format msgid "Connected to %s service!\n" msgstr "'%s' conectado a '%s'.\n" #: src/dht/gnunet-dht-put.c:172 #, c-format msgid "Issuing put request for `%s' with data `%s'!\n" msgstr "" #: src/dht/gnunet-dht-put.c:186 msgid "the data to insert under the key" msgstr "" #: src/dht/gnunet-dht-put.c:189 msgid "how long to store this entry in the dht (in seconds)" msgstr "" #: src/dht/gnunet-dht-put.c:195 msgid "how many replicas to create" msgstr "" #: src/dht/gnunet-dht-put.c:198 msgid "the type to insert data as" msgstr "" #: src/dht/gnunet-dht-put.c:223 msgid "Issue a PUT request to the GNUnet DHT insert DATA under KEY." msgstr "" #: src/dht/gnunet-service-dht.c:163 src/testing/testing.c:544 #: src/testing/testing.c:1968 src/testing/testing.c:1998 #, fuzzy msgid "Failed to connect to transport service!\n" msgstr "Fallo al conectar a gnunetd.\n" #: src/dht/gnunet-service-dht_clients.c:407 #, fuzzy msgid "# GET requests from clients injected" msgstr "# mensajes PONG encriptados recibidos" #: src/dht/gnunet-service-dht_clients.c:500 #, fuzzy msgid "# PUT requests received from clients" msgstr "El mensaje recibido del cliente es inválido\n" #: src/dht/gnunet-service-dht_clients.c:584 #, fuzzy msgid "# GET requests received from clients" msgstr "El mensaje recibido del cliente es inválido\n" #: src/dht/gnunet-service-dht_clients.c:682 #, fuzzy msgid "# GET STOP requests received from clients" msgstr "El mensaje recibido del cliente es inválido\n" #: src/dht/gnunet-service-dht_clients.c:919 msgid "# Key match, type mismatches in REPLY to CLIENT" msgstr "" #: src/dht/gnunet-service-dht_clients.c:932 msgid "# Duplicate REPLIES to CLIENT request dropped" msgstr "" #: src/dht/gnunet-service-dht_clients.c:967 #, fuzzy, c-format msgid "Unsupported block type (%u) in request!\n" msgstr "Mensaje no válido del tipo %u recibido. Omitiendo.\n" #: src/dht/gnunet-service-dht_clients.c:989 #, fuzzy msgid "# RESULTS queued for clients" msgstr "El mensaje recibido del cliente es inválido\n" #: src/dht/gnunet-service-dht_clients.c:1038 #: src/dht/gnunet-service-dht_clients.c:1081 msgid "# REPLIES ignored for CLIENTS (no match)" msgstr "" #: src/dht/gnunet-service-dht_clients.c:1048 #, fuzzy msgid "Could not pass reply to client, message too big!\n" msgstr "Imposible mandar el mensaje a gnunetd\n" #: src/dht/gnunet-service-dht_datacache.c:93 #, fuzzy, c-format msgid "%s request received, but have no datacache!\n" msgstr "# bytes recibidos por TCP" #: src/dht/gnunet-service-dht_datacache.c:103 msgid "# ITEMS stored in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:207 msgid "# Good RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:218 msgid "# Duplicate RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:224 msgid "# Invalid RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:236 msgid "# Unsupported RESULTS found in datacache" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:239 #, c-format msgid "Unsupported block type (%u) in local response!\n" msgstr "" #: src/dht/gnunet-service-dht_datacache.c:269 #, fuzzy msgid "# GET requests given to datacache" msgstr "# mensajes PONG encriptados recibidos" #: src/dht/gnunet-service-dht_hello.c:82 #, fuzzy msgid "# HELLOs obtained from peerinfo" msgstr "El mensaje recibido del cliente es inválido\n" #: src/dht/gnunet-service-dht_neighbours.c:481 msgid "# Preference updates given to core" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:571 #, fuzzy msgid "# FIND PEER messages initiated" msgstr "# mensajes fragmentados" #: src/dht/gnunet-service-dht_neighbours.c:717 #, fuzzy msgid "# Queued messages discarded (peer disconnected)" msgstr "# mensajes defragmentados" #: src/dht/gnunet-service-dht_neighbours.c:772 #, fuzzy msgid "# Bytes transmitted to other peers" msgstr "# bytes recibidos por TCP" #: src/dht/gnunet-service-dht_neighbours.c:810 #, fuzzy msgid "# Bytes of bandwdith requested from core" msgstr "# mensajes PONG encriptados recibidos" #: src/dht/gnunet-service-dht_neighbours.c:1032 #: src/dht/gnunet-service-dht_neighbours.c:1060 msgid "# Peers excluded from routing due to Bloomfilter" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1041 #: src/dht/gnunet-service-dht_neighbours.c:1075 #, fuzzy msgid "# Peer selection failed" msgstr "Conexión fallida\n" #: src/dht/gnunet-service-dht_neighbours.c:1207 #, fuzzy msgid "# PUT requests routed" msgstr "# mensajes PONG encriptados recibidos" #: src/dht/gnunet-service-dht_neighbours.c:1236 #, fuzzy msgid "# PUT messages queued for transmission" msgstr "# bytes de mensajes salientes omitidos" #: src/dht/gnunet-service-dht_neighbours.c:1315 #, fuzzy msgid "# GET requests routed" msgstr "# mensajes PONG encriptados recibidos" #: src/dht/gnunet-service-dht_neighbours.c:1342 #, fuzzy msgid "# GET messages queued for transmission" msgstr "# bytes de mensajes salientes omitidos" #: src/dht/gnunet-service-dht_neighbours.c:1443 msgid "# RESULT messages queued for transmission" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1531 #, fuzzy msgid "# P2P PUT requests received" msgstr "# mensajes PONG encriptados recibidos" #: src/dht/gnunet-service-dht_neighbours.c:1647 msgid "# FIND PEER requests ignored due to Bloomfilter" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1655 msgid "# FIND PEER requests ignored due to lack of HELLO" msgstr "" #: src/dht/gnunet-service-dht_neighbours.c:1746 #, fuzzy msgid "# P2P GET requests received" msgstr "# mensajes PONG encriptados recibidos" #: src/dht/gnunet-service-dht_neighbours.c:1788 #, fuzzy msgid "# P2P FIND PEER requests processed" msgstr "# mensajes PONG encriptados recibidos" #: src/dht/gnunet-service-dht_neighbours.c:1802 #, fuzzy msgid "# P2P GET requests ONLY routed" msgstr "# mensajes PONG encriptados recibidos" #: src/dht/gnunet-service-dht_neighbours.c:1876 #, fuzzy msgid "# P2P RESULTS received" msgstr "# bytes recibidos por TCP" #: src/dht/gnunet-service-dht_nse.c:59 #, fuzzy msgid "# Network size estimates received" msgstr "# mensajes PONG encriptados recibidos" #: src/dht/gnunet-service-dht_routing.c:211 msgid "# Good REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:220 msgid "# Duplicate REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:226 msgid "# Invalid REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:238 msgid "# Unsupported REPLIES matched against routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:311 msgid "# Entries removed from routing table" msgstr "" #: src/dht/gnunet-service-dht_routing.c:352 msgid "# Entries added to routing table" msgstr "" #: src/dht/plugin_block_dht.c:136 #, c-format msgid "Block not of type %u\n" msgstr "" #: src/dht/plugin_block_dht.c:143 msgid "Size mismatch for block\n" msgstr "" #: src/dht/plugin_block_dht.c:152 #, c-format msgid "Block of type %u is malformed\n" msgstr "" #: src/dns/gnunet-dns-monitor.c:337 msgid "only monitor DNS queries" msgstr "" #: src/dns/gnunet-dns-monitor.c:340 msgid "only monitor DNS replies" msgstr "" #: src/dns/gnunet-dns-monitor.c:348 msgid "Monitor DNS queries." msgstr "" #: src/dns/gnunet-dns-redirector.c:236 msgid "set A records" msgstr "" #: src/dns/gnunet-dns-redirector.c:239 msgid "set AAAA records" msgstr "" #: src/dns/gnunet-dns-redirector.c:247 msgid "Change DNS replies to point elsewhere." msgstr "" #: src/dns/gnunet-service-dns.c:485 #, fuzzy, c-format msgid "Could not bind to any port: %s\n" msgstr "Imposible encontrar la IP del host '%s': %s\n" #: src/dns/gnunet-service-dns.c:639 msgid "# DNS requests answered via TUN interface" msgstr "" #: src/dns/gnunet-service-dns.c:822 msgid "# DNS exit failed (failed to open socket)" msgstr "" #: src/dns/gnunet-service-dns.c:1005 #, c-format msgid "Received DNS response that is too small (%u bytes)" msgstr "" #: src/dns/gnunet-service-dns.c:1050 msgid "# External DNS response discarded (no matching request)" msgstr "" #: src/dns/gnunet-service-dns.c:1168 msgid "# Client response discarded (no matching request)" msgstr "" #: src/dns/gnunet-service-dns.c:1281 msgid "Received malformed IPv4-UDP packet on TUN interface.\n" msgstr "" #: src/dns/gnunet-service-dns.c:1297 msgid "Received malformed IPv6-UDP packet on TUN interface.\n" msgstr "" #: src/dns/gnunet-service-dns.c:1306 #, c-format msgid "Got non-IP packet with %u bytes and protocol %u from TUN\n" msgstr "" #: src/dns/gnunet-service-dns.c:1315 msgid "# Non-DNS UDP packet received via TUN interface" msgstr "" #: src/dns/gnunet-service-dns.c:1380 #, fuzzy msgid "# DNS requests received via TUN interface" msgstr "El mensaje recibido del cliente es inválido\n" #: src/dns/gnunet-service-dns.c:1465 #, c-format msgid "Configured DNS exit `%s' is not working / valid.\n" msgstr "" #: src/dns/gnunet-service-dns.c:1497 src/exit/gnunet-daemon-exit.c:2674 msgid "# Inbound MESH tunnels created" msgstr "" #: src/dns/gnunet-service-dns.c:1561 src/exit/gnunet-daemon-exit.c:3032 #, c-format msgid "`%s' must be installed SUID, refusing to run\n" msgstr "" #: src/dns/gnunet-service-dns.c:1581 msgid "Configured to provide DNS exit, but no valid DNS server configured!\n" msgstr "" #: src/dv/dv_api.c:179 #, fuzzy msgid "Failed to connect to the dv service!\n" msgstr "Fallo al conectar a gnunetd.\n" #: src/dv/plugin_transport_dv.c:159 #, fuzzy, c-format msgid "%s Received message from %s of type %d, distance %u!\n" msgstr "Recibido mensaje corrupto del par '%s' en %s:%d.\n" #: src/exit/gnunet-daemon-exit.c:508 #, c-format msgid "Got duplicate service records for `%s:%u'\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:563 #, fuzzy msgid "# Bytes transmitted via mesh tunnels" msgstr "# bytes desencriptados" #: src/exit/gnunet-daemon-exit.c:679 src/exit/gnunet-daemon-exit.c:2069 #: src/exit/gnunet-daemon-exit.c:2319 src/vpn/gnunet-service-vpn.c:1394 #: src/vpn/gnunet-service-vpn.c:1795 src/vpn/gnunet-service-vpn.c:1958 msgid "# ICMPv4 packets dropped (type not allowed)" msgstr "" #: src/exit/gnunet-daemon-exit.c:716 src/exit/gnunet-daemon-exit.c:2128 #: src/exit/gnunet-daemon-exit.c:2378 src/vpn/gnunet-service-vpn.c:1450 #: src/vpn/gnunet-service-vpn.c:1854 src/vpn/gnunet-service-vpn.c:1991 msgid "# ICMPv6 packets dropped (type not allowed)" msgstr "" #: src/exit/gnunet-daemon-exit.c:756 msgid "# ICMP packets dropped (not allowed)" msgstr "" #: src/exit/gnunet-daemon-exit.c:763 msgid "ICMP Packet dropped, have no matching connection information\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:840 msgid "UDP Packet dropped, have no matching connection information\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:915 msgid "TCP Packet dropped, have no matching connection information\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:968 #, fuzzy msgid "# Packets received from TUN" msgstr "# bytes recibidos vía HTTP" #: src/exit/gnunet-daemon-exit.c:982 #, fuzzy msgid "# Bytes received from TUN" msgstr "# bytes recibidos vía HTTP" #: src/exit/gnunet-daemon-exit.c:1008 msgid "IPv4 packet options received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1035 #, c-format msgid "IPv4 packet with unsupported next header %u received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1081 #, c-format msgid "IPv6 packet with unsupported next header %d received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1089 #, c-format msgid "Packet from unknown protocol %u received. Ignored.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1471 #, fuzzy msgid "# TCP packets sent via TUN" msgstr "# bytes enviados vía UDP" #: src/exit/gnunet-daemon-exit.c:1571 #, fuzzy msgid "# TCP service creation requests received via mesh" msgstr "# mensajes PONG encriptados recibidos" #: src/exit/gnunet-daemon-exit.c:1574 src/exit/gnunet-daemon-exit.c:1653 #: src/exit/gnunet-daemon-exit.c:1763 src/exit/gnunet-daemon-exit.c:1993 #: src/exit/gnunet-daemon-exit.c:2235 src/exit/gnunet-daemon-exit.c:2516 #: src/exit/gnunet-daemon-exit.c:2616 #, fuzzy msgid "# Bytes received from MESH" msgstr "# bytes recibidos vía HTTP" #: src/exit/gnunet-daemon-exit.c:1607 src/exit/gnunet-daemon-exit.c:2638 #, c-format msgid "No service found for %s on port %d!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:1611 #, fuzzy msgid "# TCP requests dropped (no such service)" msgstr "# Anuncios de los pares recibidos" #: src/exit/gnunet-daemon-exit.c:1656 #, fuzzy msgid "# TCP IP-exit creation requests received via mesh" msgstr "# mensajes PONG encriptados recibidos" #: src/exit/gnunet-daemon-exit.c:1766 #, fuzzy msgid "# TCP data requests received via mesh" msgstr "# mensajes PONG encriptados recibidos" #: src/exit/gnunet-daemon-exit.c:1780 #, fuzzy msgid "# TCP DATA requests dropped (no session)" msgstr "# Anuncios de los pares recibidos" #: src/exit/gnunet-daemon-exit.c:1830 #, fuzzy msgid "# ICMP packets sent via TUN" msgstr "# bytes enviados vía UDP" #: src/exit/gnunet-daemon-exit.c:1996 #, fuzzy msgid "# ICMP IP-exit requests received via mesh" msgstr "# mensajes PONG encriptados recibidos" #: src/exit/gnunet-daemon-exit.c:2238 #, fuzzy msgid "# ICMP service requests received via mesh" msgstr "El mensaje recibido del cliente es inválido\n" #: src/exit/gnunet-daemon-exit.c:2304 src/vpn/gnunet-service-vpn.c:1384 #: src/vpn/gnunet-service-vpn.c:1952 msgid "# ICMPv4 packets dropped (impossible PT to v6)" msgstr "" #: src/exit/gnunet-daemon-exit.c:2363 src/vpn/gnunet-service-vpn.c:1420 #: src/vpn/gnunet-service-vpn.c:1432 src/vpn/gnunet-service-vpn.c:1842 msgid "# ICMPv6 packets dropped (impossible PT to v4)" msgstr "" #: src/exit/gnunet-daemon-exit.c:2413 #, fuzzy msgid "# UDP packets sent via TUN" msgstr "# bytes enviados vía UDP" #: src/exit/gnunet-daemon-exit.c:2519 #, fuzzy msgid "# UDP IP-exit requests received via mesh" msgstr "# mensajes PONG encriptados recibidos" #: src/exit/gnunet-daemon-exit.c:2619 #, fuzzy msgid "# UDP service requests received via mesh" msgstr "# mensajes PONG encriptados recibidos" #: src/exit/gnunet-daemon-exit.c:2642 #, fuzzy msgid "# UDP requests dropped (no such service)" msgstr "# Anuncios de los pares recibidos" #: src/exit/gnunet-daemon-exit.c:2882 #, c-format msgid "No addresses found for hostname `%s' of service `%s'!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:2896 src/exit/gnunet-daemon-exit.c:2908 #, c-format msgid "Service `%s' configured for IPv4, but IPv4 is disabled!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:2919 #, c-format msgid "No IP addresses found for hostname `%s' of service `%s'!\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3048 msgid "" "This system does not support IPv4, will disable IPv4 functions despite them " "being enabled in the configuration\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3056 msgid "" "This system does not support IPv6, will disable IPv6 functions despite them " "being enabled in the configuration\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3063 msgid "" "Cannot enable IPv4 exit but disable IPv4 on TUN interface, will use " "ENABLE_IPv4=YES\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3069 msgid "" "Cannot enable IPv6 exit but disable IPv6 on TUN interface, will use " "ENABLE_IPv6=YES\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3075 src/pt/gnunet-daemon-pt.c:884 msgid "No useful service enabled. Exiting.\n" msgstr "" #: src/exit/gnunet-daemon-exit.c:3236 msgid "Daemon to run to provide an IP exit node for the VPN" msgstr "" #: src/fragmentation/defragmentation.c:270 msgid "# acknowledgements sent for fragment" msgstr "" #: src/fragmentation/defragmentation.c:456 #, fuzzy msgid "# fragments received" msgstr "# fragmentos descartados" #: src/fragmentation/defragmentation.c:521 #, fuzzy msgid "# duplicate fragments received" msgstr "# bytes recibidos por TCP" #: src/fragmentation/defragmentation.c:534 msgid "# messages defragmented" msgstr "# mensajes defragmentados" #: src/fragmentation/fragmentation.c:203 #, fuzzy msgid "# fragments transmitted" msgstr "# Auto-anuncios transmitidos" #: src/fragmentation/fragmentation.c:206 #, fuzzy msgid "# fragments retransmitted" msgstr "# Auto-anuncios transmitidos" #: src/fragmentation/fragmentation.c:232 #, fuzzy msgid "# fragments wrap arounds" msgstr "# Auto-anuncios transmitidos" #: src/fragmentation/fragmentation.c:273 msgid "# messages fragmented" msgstr "# mensajes fragmentados" #: src/fragmentation/fragmentation.c:276 msgid "# total size of fragmented messages" msgstr "" #: src/fragmentation/fragmentation.c:363 #, fuzzy msgid "# fragment acknowledgements received" msgstr "# Anuncios de los pares recibidos" #: src/fragmentation/fragmentation.c:369 msgid "# bits removed from fragmentation ACKs" msgstr "" #: src/fragmentation/fragmentation.c:393 #, fuzzy msgid "# fragmentation transmissions completed" msgstr "# mensajes de texto mandados por PING" #: src/fs/fs_api.c:339 #, fuzzy, c-format msgid "Could not open file `%s': %s" msgstr "Fichero almacenado en '%s'.\n" #: src/fs/fs_api.c:348 #, fuzzy, c-format msgid "Could not read file `%s': %s" msgstr "Fichero almacenado en '%s'.\n" #: src/fs/fs_api.c:354 #, c-format msgid "Short read reading from file `%s'!" msgstr "" #: src/fs/fs_api.c:938 #, fuzzy, c-format msgid "Failed to resume publishing information `%s': %s\n" msgstr "Fichero almacenado en '%s'.\n" #: src/fs/fs_api.c:1395 #, c-format msgid "Failed to recover namespace `%s', cannot resume publishing operation.\n" msgstr "" #: src/fs/fs_api.c:1437 #, c-format msgid "Failure while resuming publishing operation `%s': %s\n" msgstr "" #: src/fs/fs_api.c:1453 #, fuzzy, c-format msgid "Failed to resume publishing operation `%s': %s\n" msgstr "Fichero almacenado en '%s'.\n" #: src/fs/fs_api.c:2106 #, c-format msgid "Failure while resuming unindexing operation `%s': %s\n" msgstr "" #: src/fs/fs_api.c:2116 #, fuzzy, c-format msgid "Failed to resume unindexing operation `%s': %s\n" msgstr "Fichero almacenado en '%s'.\n" #: src/fs/fs_api.c:2241 src/fs/fs_api.c:2480 #, fuzzy, c-format msgid "Failed to resume sub-download `%s': %s\n" msgstr "Fichero almacenado en '%s'.\n" #: src/fs/fs_api.c:2258 #, fuzzy, c-format msgid "Failed to resume sub-search `%s': %s\n" msgstr "Fichero almacenado en '%s'.\n" #: src/fs/fs_api.c:2270 src/fs/fs_api.c:2289 src/fs/fs_api.c:2773 #, c-format msgid "Failure while resuming search operation `%s': %s\n" msgstr "" #: src/fs/fs_api.c:2471 #, c-format msgid "Failed to resume sub-download `%s': could not open file `%s'\n" msgstr "" #: src/fs/fs_api.c:2717 msgid "Could not resume running search, will resume as paused search\n" msgstr "" #: src/fs/fs_api.c:2811 #, c-format msgid "Failure while resuming download operation `%s': %s\n" msgstr "" #: src/fs/fs_directory.c:210 #, fuzzy msgid "MAGIC mismatch. This is not a GNUnet directory.\n" msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" #: src/fs/fs_download.c:311 msgid "" "Recursive downloads of directories larger than 4 GB are not supported on 32-" "bit systems\n" msgstr "" #: src/fs/fs_download.c:331 msgid "Directory too large for system address space\n" msgstr "" #: src/fs/fs_download.c:497 src/fs/fs_download.c:509 #, fuzzy, c-format msgid "Failed to open file `%s' for writing" msgstr "Fichero almacenado en '%s'.\n" #: src/fs/fs_download.c:878 #, fuzzy, c-format msgid "Failed to create directory for recursive download of `%s'\n" msgstr "Falló al actualizar los datos del módulo '%s'\n" #: src/fs/fs_download.c:960 #, c-format msgid "" "Internal error or bogus download URI (expected %u bytes at depth %u and " "offset %llu/%llu, got %u bytes)" msgstr "" #: src/fs/fs_download.c:986 msgid "internal error decrypting content" msgstr "" #: src/fs/fs_download.c:1009 #, fuzzy, c-format msgid "Download failed: could not open file `%s': %s" msgstr "Fichero almacenado en '%s'.\n" #: src/fs/fs_download.c:1019 #, fuzzy, c-format msgid "Failed to seek to offset %llu in file `%s': %s" msgstr "Fichero almacenado en '%s'.\n" #: src/fs/fs_download.c:1028 #, fuzzy, c-format msgid "Failed to write block of %u bytes at offset %llu in file `%s': %s" msgstr "Fichero almacenado en '%s'.\n" #: src/fs/fs_download.c:1125 #, fuzzy msgid "internal error decoding tree" msgstr "=\tError leyendo el directorio.\n" #: src/fs/fs_download.c:1888 #, fuzzy msgid "Invalid URI" msgstr "Argumento no válido: '%s'\n" #: src/fs/fs_getopt.c:191 #, c-format msgid "" "Unknown metadata type in metadata option `%s'. Using metadata type " "`unknown' instead.\n" msgstr "" "Tipo de metadatos desconocido en la opción de metadatos '%s'. Usando el " "tipo de metadatos 'desconocido' en su lugar.\n" #: src/fs/fs_list_indexed.c:90 #, fuzzy, c-format msgid "Failed to receive response for `%s' request from `%s' service.\n" msgstr "Falló al recibir la respuesta al mensaje '%s' de gnunetd\n" #: src/fs/fs_list_indexed.c:113 #, fuzzy, c-format msgid "Failed to receive valid response for `%s' request from `%s' service.\n" msgstr "Falló al recibir la respuesta al mensaje '%s' de gnunetd\n" #: src/fs/fs_list_indexed.c:151 #, fuzzy, c-format msgid "Failed to not connect to `%s' service.\n" msgstr "Falló al inicializar el servicio '%s'.\n" #: src/fs/fs_misc.c:126 #, fuzzy, c-format msgid "Did not find mime type `%s' in extension list.\n" msgstr "¡Imposible encontrar el par '%s' en la tabla de enrutado!\n" #: src/fs/fs_namespace_advertise.c:150 #, fuzzy msgid "Unknown error" msgstr "Error desconocido" #: src/fs/fs_namespace_advertise.c:238 src/fs/fs_namespace_advertise.c:259 #, fuzzy msgid "Failed to serialize meta data" msgstr "Imposible inicializar SQLite.\n" #: src/fs/fs_namespace_advertise.c:278 #, fuzzy msgid "Failed to connect to datastore service" msgstr "Fallo al conectar a gnunetd.\n" #: src/fs/fs_namespace.c:57 src/fs/fs_namespace.c:83 #, fuzzy, c-format msgid "Configuration fails to specify `%s' in section `%s'\n" msgstr "" "El fichero de configuración debe especificar el directorio para almacenar " "los datos FS en la sección '%s' bajo '%s'.\n" #: src/fs/fs_namespace.c:112 #, fuzzy, c-format msgid "Failed to open `%s' for writing: %s\n" msgstr "Fichero almacenado en '%s'.\n" #: src/fs/fs_namespace.c:134 src/fs/fs_namespace.c:222 #, fuzzy, c-format msgid "Failed to write `%s': %s\n" msgstr "Fallo al conectar a gnunetd.\n" #: src/fs/fs_namespace.c:256 #, fuzzy, c-format msgid "Failed to create or read private key for namespace `%s'\n" msgstr "Falló al actualizar los datos del módulo '%s'\n" #: src/fs/fs_namespace.c:371 #, fuzzy, c-format msgid "Failed to read namespace private key file `%s', deleting it!\n" msgstr "Fallo al añadir la entrada al espacio '%s' (¿existe?)\n" #: src/fs/fs_namespace.c:588 src/fs/fs_publish_ksk.c:295 #, fuzzy msgid "Internal error." msgstr "Error desconocido.\n" #: src/fs/fs_namespace.c:631 #, fuzzy msgid "Failed to connect to datastore." msgstr "Fallo al conectarse a gnunetd" #: src/fs/fs_publish.c:129 src/fs/fs_publish.c:397 #, fuzzy, c-format msgid "Publishing failed: %s" msgstr "" "\n" "Error subiendo el fichero %s\n" #: src/fs/fs_publish.c:621 src/fs/fs_publish.c:638 src/fs/fs_publish.c:677 #: src/fs/fs_publish.c:697 src/fs/fs_publish.c:722 src/fs/fs_publish.c:862 #, fuzzy, c-format msgid "Can not index file `%s': %s. Will try to insert instead.\n" msgstr "Indexación del fichero '%s' fallida. Intentando insertar fichero...\n" #: src/fs/fs_publish.c:623 msgid "timeout on index-start request to `fs' service" msgstr "" #: src/fs/fs_publish.c:635 #, fuzzy msgid "unknown error" msgstr "Error desconocido" #: src/fs/fs_publish.c:678 msgid "failed to compute hash" msgstr "" #: src/fs/fs_publish.c:698 msgid "filename too long" msgstr "" #: src/fs/fs_publish.c:723 #, fuzzy msgid "could not connect to `fs' service" msgstr "Imposible conectar con gnunetd.\n" #: src/fs/fs_publish.c:746 #, fuzzy, c-format msgid "Failed to get file identifiers for `%s'\n" msgstr "Falló al actualizar los datos del módulo '%s'\n" #: src/fs/fs_publish.c:811 #, fuzzy, c-format msgid "Recursive upload failed at `%s': %s" msgstr "'%s' falló en %s: %d con error: '%s'.\n" #: src/fs/fs_publish.c:817 #, fuzzy, c-format msgid "Recursive upload failed: %s" msgstr "" "\n" "Error subiendo el fichero %s\n" #: src/fs/fs_publish.c:863 #, fuzzy msgid "needs to be an actual file" msgstr "'%s' no es un fichero regular.\n" #: src/fs/fs_publish.c:1071 #, c-format msgid "Insufficient space for publishing: %s" msgstr "" #: src/fs/fs_publish.c:1142 #, c-format msgid "Reserving space for %u entries and %llu bytes for publication\n" msgstr "" #: src/fs/fs_publish_ksk.c:258 #, fuzzy msgid "Could not connect to datastore." msgstr "Imposible conectar con gnunetd.\n" #: src/fs/fs_search.c:829 #, c-format msgid "Got result with unknown block type `%d', ignoring" msgstr "" #: src/fs/fs_test_lib.c:269 #, fuzzy, c-format msgid "Failed to start daemon: %s\n" msgstr "Falló al comenzar la recolección.\n" #: src/fs/fs_unindex.c:58 msgid "Failed to find given position in file" msgstr "" #: src/fs/fs_unindex.c:63 #, fuzzy msgid "Failed to read file" msgstr "Falló al entregar el mensaje '%s'.\n" #: src/fs/fs_unindex.c:233 msgid "Unexpected time for a response from `fs' service." msgstr "" #: src/fs/fs_unindex.c:241 msgid "Timeout waiting for `fs' service." msgstr "" #: src/fs/fs_unindex.c:249 #, fuzzy msgid "Invalid response from `fs' service." msgstr "Respuesta inválida a '%s'.\n" #: src/fs/fs_unindex.c:293 #, fuzzy msgid "Failed to connect to FS service for unindexing." msgstr "Fallo al conectarse a gnunetd" #: src/fs/fs_unindex.c:344 #, fuzzy msgid "Failed to get KSKs from directory scan." msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" #: src/fs/fs_unindex.c:356 #, fuzzy, c-format msgid "Internal error scanning `%s'.\n" msgstr "=\tError leyendo el directorio.\n" #: src/fs/fs_unindex.c:411 #, fuzzy, c-format msgid "Failed to remove KBlock: %s\n" msgstr "Fichero almacenado en '%s'.\n" #: src/fs/fs_unindex.c:501 #, fuzzy, c-format msgid "Failed to parse URI `%s' from KBlock!\n" msgstr "El fichero '%s' tiene la URI: '%s'\n" #: src/fs/fs_unindex.c:553 src/fs/fs_unindex.c:618 #, fuzzy msgid "Failed to connect to `datastore' service." msgstr "Falló al inicializar el servicio '%s'.\n" #: src/fs/fs_unindex.c:631 #, fuzzy msgid "Failed to open file for unindexing." msgstr "Fallo al conectarse a gnunetd" #: src/fs/fs_unindex.c:665 #, fuzzy msgid "Failed to compute hash of file." msgstr "Fallo al conectarse a gnunetd" #: src/fs/fs_uri.c:220 #, c-format msgid "`%' must be followed by HEX number" msgstr "" #: src/fs/fs_uri.c:279 #, fuzzy msgid "Malformed KSK URI (must not begin or end with `+')" msgstr "URL invalida '%s' (debe comenzar por '%s')\n" #: src/fs/fs_uri.c:297 msgid "`++' not allowed in KSK URI" msgstr "" #: src/fs/fs_uri.c:304 msgid "Quotes not balanced in KSK URI" msgstr "" #: src/fs/fs_uri.c:372 src/fs/fs_uri.c:379 msgid "Malformed SKS URI" msgstr "" #: src/fs/fs_uri.c:423 src/fs/fs_uri.c:438 msgid "Malformed CHK URI" msgstr "" #: src/fs/fs_uri.c:568 src/fs/fs_uri.c:583 src/fs/fs_uri.c:593 #: src/fs/fs_uri.c:621 msgid "SKS URI malformed" msgstr "" #: src/fs/fs_uri.c:603 msgid "SKS URI malformed (could not decode public key)" msgstr "" #: src/fs/fs_uri.c:609 msgid "SKS URI malformed (could not find signature)" msgstr "" #: src/fs/fs_uri.c:615 msgid "SKS URI malformed (could not decode signature)" msgstr "" #: src/fs/fs_uri.c:628 msgid "SKS URI malformed (could not parse expiration time)" msgstr "" #: src/fs/fs_uri.c:640 msgid "SKS URI malformed (signature failed validation)" msgstr "" #: src/fs/fs_uri.c:678 msgid "Unrecognized URI type" msgstr "" #: src/fs/fs_uri.c:903 #, fuzzy msgid "Lacking key configuration settings.\n" msgstr "Configuración de GNUnet" #: src/fs/fs_uri.c:910 #, fuzzy, c-format msgid "Could not access hostkey file `%s'.\n" msgstr "Imposible pasar el fichero de configuración '%s'.\n" #: src/fs/fs_uri.c:1115 src/fs/fs_uri.c:1142 msgid "No keywords specified!\n" msgstr "¡Ninguna clave especificada!\n" #: src/fs/fs_uri.c:1148 msgid "Number of double-quotes not balanced!\n" msgstr "" #: src/fs/gnunet-directory.c:49 #, c-format msgid "\t\n" msgstr "" #: src/fs/gnunet-directory.c:94 #, fuzzy, c-format msgid "Directory `%s' meta data:\n" msgstr "==> Directorio '%s':\n" #: src/fs/gnunet-directory.c:97 #, fuzzy, c-format msgid "Directory `%s' contents:\n" msgstr "==> Directorio '%s':\n" #: src/fs/gnunet-directory.c:132 #, fuzzy msgid "You must specify a filename to inspect.\n" msgstr "Debes especificar una lista de ficheros a insertar.\n" #: src/fs/gnunet-directory.c:145 #, fuzzy, c-format msgid "Failed to read directory `%s'\n" msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" #: src/fs/gnunet-directory.c:154 #, fuzzy, c-format msgid "`%s' is not a GNUnet directory\n" msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" #: src/fs/gnunet-directory.c:179 #, fuzzy msgid "Display contents of a GNUnet directory" msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" #: src/fs/gnunet-download.c:101 #, fuzzy, c-format msgid "Starting download `%s'.\n" msgstr "Iniciada colección '%s'.\n" #: src/fs/gnunet-download.c:110 #, fuzzy msgid "" msgstr "Error desconocido" #: src/fs/gnunet-download.c:119 #, c-format msgid "" "Downloading `%s' at %llu/%llu (%s remaining, %s/s). Block took %s to " "download\n" msgstr "" #: src/fs/gnunet-download.c:129 #, fuzzy, c-format msgid "Error downloading: %s.\n" msgstr "Error descargando: %s\n" #: src/fs/gnunet-download.c:137 #, fuzzy, c-format msgid "Downloading `%s' done (%s/s).\n" msgstr "¡Subida rechazada!" #: src/fs/gnunet-download.c:152 src/fs/gnunet-publish.c:190 #: src/fs/gnunet-search.c:190 src/fs/gnunet-unindex.c:109 #, fuzzy, c-format msgid "Unexpected status: %d\n" msgstr "Estado de descarga inesperado." #: src/fs/gnunet-download.c:177 #, fuzzy msgid "You need to specify a URI argument.\n" msgstr "¡Debes especificar un receptor!\n" #: src/fs/gnunet-download.c:183 src/fs/gnunet-publish.c:624 #, fuzzy, c-format msgid "Failed to parse URI: %s\n" msgstr "El fichero '%s' tiene la URI: '%s'\n" #: src/fs/gnunet-download.c:190 msgid "Only CHK or LOC URIs supported.\n" msgstr "" #: src/fs/gnunet-download.c:197 msgid "Target filename must be specified.\n" msgstr "" #: src/fs/gnunet-download.c:211 src/fs/gnunet-publish.c:602 #: src/fs/gnunet-search.c:241 src/fs/gnunet-unindex.c:141 #, fuzzy, c-format msgid "Could not initialize `%s' subsystem.\n" msgstr "Falló al inicializar el servicio '%s'.\n" #: src/fs/gnunet-download.c:248 src/fs/gnunet-search.c:285 msgid "set the desired LEVEL of receiver-anonymity" msgstr "seleccione el NIVEL deseado de anonimidad-del-receptor" #: src/fs/gnunet-download.c:251 msgid "delete incomplete downloads (when aborted with CTRL-C)" msgstr "" #: src/fs/gnunet-download.c:254 src/fs/gnunet-search.c:288 msgid "only search the local peer (no P2P network search)" msgstr "" #: src/fs/gnunet-download.c:257 msgid "write the file to FILENAME" msgstr "escribe el fichero al FICHERO" #: src/fs/gnunet-download.c:261 msgid "set the maximum number of parallel downloads that is allowed" msgstr "" #: src/fs/gnunet-download.c:265 msgid "set the maximum number of parallel requests for blocks that is allowed" msgstr "" #: src/fs/gnunet-download.c:268 msgid "download a GNUnet directory recursively" msgstr "descarga un directorio de GNUnet recursivamente" #: src/fs/gnunet-download.c:278 msgid "" "Download files from GNUnet using a GNUnet CHK or LOC URI (gnunet://fs/" "chk/...)" msgstr "" #: src/fs/gnunet-fs.c:117 msgid "print a list of all indexed files" msgstr "" #: src/fs/gnunet-fs.c:124 msgid "Special file-sharing operations" msgstr "" #: src/fs/gnunet-pseudonym.c:160 src/statistics/gnunet-statistics.c:167 #, fuzzy, c-format msgid "Invalid argument `%s'\n" msgstr "Argumento no válido: '%s'\n" #: src/fs/gnunet-pseudonym.c:250 src/fs/gnunet-pseudonym.c:257 #: src/fs/gnunet-pseudonym.c:259 #, fuzzy, c-format msgid "Option `%s' ignored\n" msgstr "%s: la opción '%s' es ambigua\n" #: src/fs/gnunet-pseudonym.c:279 src/fs/gnunet-publish.c:678 msgid "set the desired LEVEL of sender-anonymity" msgstr "seleccione el NIVEL deseado de anonimato al enviar" #: src/fs/gnunet-pseudonym.c:282 msgid "create or advertise namespace NAME" msgstr "" #: src/fs/gnunet-pseudonym.c:285 msgid "delete namespace NAME " msgstr "" #: src/fs/gnunet-pseudonym.c:288 #, fuzzy msgid "" "add an additional keyword for the advertisment (this option can be specified " "multiple times)" msgstr "" "añade una clave adicional para todos los ficheros y directorios (esta opción " "puede ser especificada varias veces)" #: src/fs/gnunet-pseudonym.c:292 src/fs/gnunet-publish.c:697 msgid "set the meta-data for the given TYPE to the given VALUE" msgstr "cambia el meta-dato para el TIPO dado al VALOR dado" #: src/fs/gnunet-pseudonym.c:295 #, fuzzy msgid "print names of local namespaces" msgstr "cambia la valoración de un espacio" #: src/fs/gnunet-pseudonym.c:298 msgid "use the given PRIORITY for the advertisments" msgstr "" #: src/fs/gnunet-pseudonym.c:301 msgid "do not print names of remote namespaces" msgstr "" #: src/fs/gnunet-pseudonym.c:304 src/fs/gnunet-publish.c:716 msgid "set the desired replication LEVEL" msgstr "" #: src/fs/gnunet-pseudonym.c:307 #, fuzzy msgid "specify ID of the root of the namespace" msgstr "cambia la valoración de un espacio" #: src/fs/gnunet-pseudonym.c:310 #, fuzzy msgid "change rating of namespace ID by VALUE" msgstr "cambia la valoración de un espacio" #: src/fs/gnunet-pseudonym.c:318 msgid "Manage GNUnet pseudonyms." msgstr "" #: src/fs/gnunet-publish.c:147 #, c-format msgid "Publishing `%s' at %llu/%llu (%s remaining)\n" msgstr "" #: src/fs/gnunet-publish.c:155 #, fuzzy, c-format msgid "Error publishing: %s.\n" msgstr "Error descargando: %s\n" #: src/fs/gnunet-publish.c:165 #, c-format msgid "Publishing `%s' done.\n" msgstr "" #: src/fs/gnunet-publish.c:169 #, fuzzy, c-format msgid "URI is `%s'.\n" msgstr "Yo soy el par '%s'.\n" #: src/fs/gnunet-publish.c:187 #, fuzzy msgid "Cleanup after abort complete.\n" msgstr "'%s' comienzo completo.\n" #: src/fs/gnunet-publish.c:305 #, fuzzy, c-format msgid "Meta data for file `%s' (%s)\n" msgstr "Actualizando los datos del módulo '%s'\n" #: src/fs/gnunet-publish.c:307 #, fuzzy, c-format msgid "Keywords for file `%s' (%s)\n" msgstr "Claves para los ficheros '%s':\n" #: src/fs/gnunet-publish.c:358 #, fuzzy, c-format msgid "Failed to create namespace `%s'\n" msgstr "Imposible crear el espacio '%s' (¿existe?).\n" #: src/fs/gnunet-publish.c:433 #, fuzzy msgid "Could not publish\n" msgstr "Imposible ejecutar '%s': %s\n" #: src/fs/gnunet-publish.c:460 #, fuzzy msgid "Could not start publishing.\n" msgstr "Imposible inicializar la aplicación '%s'\n" #: src/fs/gnunet-publish.c:491 #, fuzzy, c-format msgid "Scanning directory `%s'.\n" msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" #: src/fs/gnunet-publish.c:493 #, fuzzy, c-format msgid "Scanning file `%s'.\n" msgstr "Iniciada colección '%s'.\n" #: src/fs/gnunet-publish.c:498 #, c-format msgid "There was trouble processing file `%s', skipping it.\n" msgstr "" #: src/fs/gnunet-publish.c:503 #, fuzzy msgid "Preprocessing complete.\n" msgstr "Cierre completado.\n" #: src/fs/gnunet-publish.c:507 #, fuzzy, c-format msgid "Extracting meta data from file `%s' complete.\n" msgstr "Actualizando los datos del módulo '%s'\n" #: src/fs/gnunet-publish.c:511 msgid "Meta data extraction has finished.\n" msgstr "" #: src/fs/gnunet-publish.c:518 #, fuzzy msgid "Internal error scanning directory.\n" msgstr "=\tError leyendo el directorio.\n" #: src/fs/gnunet-publish.c:552 #, c-format msgid "Cannot extract metadata from a URI!\n" msgstr "" #: src/fs/gnunet-publish.c:559 #, fuzzy, c-format msgid "You must specify one and only one filename for insertion.\n" msgstr "Debes especificar uno y solo un fichero para desindexar.\n" #: src/fs/gnunet-publish.c:565 #, fuzzy, c-format msgid "You must NOT specify an URI and a filename.\n" msgstr "¡Debes especificar un receptor!\n" #: src/fs/gnunet-publish.c:573 src/vpn/gnunet-vpn.c:214 #, fuzzy, c-format msgid "Option `%s' is required when using option `%s'.\n" msgstr "La opción '%s' no tiene sentido sin la opción '%s'.\n" #: src/fs/gnunet-publish.c:583 src/fs/gnunet-publish.c:590 #: src/transport/gnunet-transport.c:560 #, c-format msgid "Option `%s' makes no sense without option `%s'.\n" msgstr "La opción '%s' no tiene sentido sin la opción '%s'.\n" #: src/fs/gnunet-publish.c:612 #, fuzzy, c-format msgid "Could not create namespace `%s'\n" msgstr "Imposible crear el espacio '%s' (¿existe?).\n" #: src/fs/gnunet-publish.c:645 #, fuzzy, c-format msgid "Failed to access `%s': %s\n" msgstr "Fichero almacenado en '%s'.\n" #: src/fs/gnunet-publish.c:657 msgid "" "Failed to start meta directory scanner. Is gnunet-helper-publish-fs " "installed?\n" msgstr "" #: src/fs/gnunet-publish.c:682 msgid "disable adding the creation time to the metadata of the uploaded file" msgstr "" #: src/fs/gnunet-publish.c:685 msgid "do not use libextractor to add keywords or metadata" msgstr "" #: src/fs/gnunet-publish.c:689 msgid "" "print list of extracted keywords that would be used, but do not perform " "upload" msgstr "" "imprime la lista de las claves extraidas que podrían ser usadas, pero no " "realiza la subida" #: src/fs/gnunet-publish.c:693 msgid "" "add an additional keyword for the top-level file or directory (this option " "can be specified multiple times)" msgstr "" "añade una clave adicional para el fichero del nivel más alto o el directorio " "(esta opción puede ser especificada varias veces)" #: src/fs/gnunet-publish.c:700 msgid "" "do not index, perform full insertion (stores entire file in encrypted form " "in GNUnet database)" msgstr "" "no indexar, hacer inserciones totales (almacena el fichero entero de forma " "encriptada en la base de datos de GNUnet)" #: src/fs/gnunet-publish.c:705 msgid "" "specify ID of an updated version to be published in the future (for " "namespace insertions only)" msgstr "" "especifica la ID de una versión actualizada para ser publicada en el futuro " "(para inserciones en el espacio únicamente)" #: src/fs/gnunet-publish.c:709 msgid "specify the priority of the content" msgstr "especifica la prioridad del contenido" #: src/fs/gnunet-publish.c:713 msgid "publish the files under the pseudonym NAME (place file into namespace)" msgstr "" "publica los ficheros bajo el pseudónimo NOMBRE (coloca el fichero en el " "espacio)" #: src/fs/gnunet-publish.c:719 msgid "" "only simulate the process but do not do any actual publishing (useful to " "compute URIs)" msgstr "" #: src/fs/gnunet-publish.c:723 msgid "" "set the ID of this version of the publication (for namespace insertions only)" msgstr "" "cambia la ID de esta versión de la publicación (para inserciones en el " "espacio únicamente)" #: src/fs/gnunet-publish.c:727 msgid "" "URI to be published (can be used instead of passing a file to add keywords " "to the file with the respective URI)" msgstr "" #: src/fs/gnunet-publish.c:742 msgid "Publish a file or directory on GNUnet" msgstr "" #: src/fs/gnunet-search.c:111 #, c-format msgid "Failed to write directory with search results to `%s'\n" msgstr "" #: src/fs/gnunet-search.c:181 #, fuzzy, c-format msgid "Error searching: %s.\n" msgstr "Error abandonando DHT.\n" #: src/fs/gnunet-search.c:231 #, fuzzy msgid "Could not create keyword URI from arguments.\n" msgstr "Imposible crear el espacio '%s' (¿existe?).\n" #: src/fs/gnunet-search.c:255 #, fuzzy msgid "Could not start searching.\n" msgstr "Imposible crear el espacio '%s' (¿existe?).\n" #: src/fs/gnunet-search.c:291 msgid "write search results to file starting with PREFIX" msgstr "" #: src/fs/gnunet-search.c:294 msgid "automatically terminate search after VALUE ms" msgstr "" #: src/fs/gnunet-search.c:301 msgid "automatically terminate search after VALUE results are found" msgstr "" #: src/fs/gnunet-search.c:308 msgid "Search GNUnet for files that were published on GNUnet" msgstr "" #: src/fs/gnunet-service-fs.c:240 msgid "# running average P2P latency (ms)" msgstr "" #: src/fs/gnunet-service-fs.c:300 src/fs/gnunet-service-fs.c:489 msgid "# Loopback routes suppressed" msgstr "" #: src/fs/gnunet-service-fs.c:581 src/hostlist/gnunet-daemon-hostlist.c:297 #: src/topology/gnunet-daemon-topology.c:1330 #: src/topology/gnunet-daemon-topology.c:1337 #, fuzzy, c-format msgid "Failed to connect to `%s' service.\n" msgstr "Fallo al conectar a gnunetd.\n" #: src/fs/gnunet-service-fs_cp.c:696 #, fuzzy msgid "# migration stop messages received" msgstr "# mensajes PONG encriptados recibidos" #: src/fs/gnunet-service-fs_cp.c:700 #, c-format msgid "Migration of content to peer `%s' blocked for %llu ms\n" msgstr "" #: src/fs/gnunet-service-fs_cp.c:735 msgid "# replies transmitted to other peers" msgstr "" #: src/fs/gnunet-service-fs_cp.c:741 msgid "# replies dropped" msgstr "" #: src/fs/gnunet-service-fs_cp.c:766 src/fs/gnunet-service-fs_cp.c:1324 msgid "# P2P searches active" msgstr "" #: src/fs/gnunet-service-fs_cp.c:858 msgid "# artificial delays introduced (ms)" msgstr "" #: src/fs/gnunet-service-fs_cp.c:911 #, fuzzy msgid "# replies dropped due to type mismatch" msgstr "# Anuncios de los pares recibidos" #: src/fs/gnunet-service-fs_cp.c:919 msgid "# replies received for other peers" msgstr "" #: src/fs/gnunet-service-fs_cp.c:933 msgid "# replies dropped due to insufficient cover traffic" msgstr "" #: src/fs/gnunet-service-fs_cp.c:971 msgid "# P2P searches destroyed due to ultimate reply" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1038 #, fuzzy msgid "# requests done for free (low load)" msgstr "# Anuncios de los pares recibidos" #: src/fs/gnunet-service-fs_cp.c:1062 msgid "# request dropped, priority insufficient" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1072 #, fuzzy msgid "# requests done for a price (normal load)" msgstr "# Anuncios de los pares recibidos" #: src/fs/gnunet-service-fs_cp.c:1151 msgid "# GET requests received (from other peers)" msgstr "" #: src/fs/gnunet-service-fs_cp.c:1185 #, fuzzy msgid "# requests dropped due to initiator not being connected" msgstr "# Anuncios de los pares recibidos" #: src/fs/gnunet-service-fs_cp.c:1207 #, fuzzy msgid "# requests dropped due to missing reverse route" msgstr "# Anuncios de los pares recibidos" #: src/fs/gnunet-service-fs_cp.c:1267 #, fuzzy msgid "# requests dropped due TTL underflow" msgstr "# Anuncios de los pares recibidos" #: src/fs/gnunet-service-fs_cp.c:1293 #, fuzzy msgid "# requests dropped due to higher-TTL request" msgstr "# Anuncios de los pares recibidos" #: src/fs/gnunet-service-fs_cp.c:1322 #, fuzzy msgid "# P2P query messages received and processed" msgstr "# mensajes PONG encriptados recibidos" #: src/fs/gnunet-service-fs_cp.c:1687 #, fuzzy msgid "# migration stop messages sent" msgstr "# mensajes PONG encriptados recibidos" #: src/fs/gnunet-service-fs_indexing.c:113 #: src/fs/gnunet-service-fs_indexing.c:163 #, fuzzy, c-format msgid "Configuration option `%s' in section `%s' missing.\n" msgstr "Fichero de configuración '%s' creado.\n" #: src/fs/gnunet-service-fs_indexing.c:121 #: src/fs/gnunet-service-fs_indexing.c:177 #, fuzzy, c-format msgid "Could not open `%s'.\n" msgstr "Fichero almacenado en '%s'.\n" #: src/fs/gnunet-service-fs_indexing.c:137 #, fuzzy, c-format msgid "Error writing `%s'.\n" msgstr "Error creando usuario" #: src/fs/gnunet-service-fs_indexing.c:228 #, c-format msgid "" "Index request received for file `%s' is already indexed as `%s'. Permitting " "anyway.\n" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:266 #, c-format msgid "Hash mismatch trying to index file `%s' which has hash `%s'\n" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:481 #, fuzzy, c-format msgid "Failed to delete bogus block: %s\n" msgstr "Fichero almacenado en '%s'.\n" #: src/fs/gnunet-service-fs_indexing.c:539 msgid "# index blocks removed: original file inaccessible" msgstr "" #: src/fs/gnunet-service-fs_indexing.c:554 #, fuzzy, c-format msgid "Could not access indexed file `%s' (%s) at offset %llu: %s\n" msgstr "Imposible resolver '%s': %s\n" #: src/fs/gnunet-service-fs_indexing.c:556 #, fuzzy msgid "not indexed" msgstr "El desindexado falló" #: src/fs/gnunet-service-fs_indexing.c:571 #, fuzzy, c-format msgid "Indexed file `%s' changed at offset %llu\n" msgstr "La indexación de los datos falló en la posición %i.\n" #: src/fs/gnunet-service-fs_lc.c:202 src/fs/gnunet-service-fs_lc.c:362 #: src/fs/gnunet-service-fs_lc.c:488 #, fuzzy msgid "# client searches active" msgstr "# mensajes PONG encriptados recibidos" #: src/fs/gnunet-service-fs_lc.c:256 #, fuzzy msgid "# replies received for local clients" msgstr "El mensaje recibido del cliente es inválido\n" #: src/fs/gnunet-service-fs_lc.c:321 #, fuzzy msgid "# client searches received" msgstr "# mensajes PONG encriptados recibidos" #: src/fs/gnunet-service-fs_lc.c:356 msgid "# client searches updated (merged content seen list)" msgstr "" #: src/fs/gnunet-service-fs_pe.c:265 msgid "# average retransmission delay (ms)" msgstr "" #: src/fs/gnunet-service-fs_pe.c:391 msgid "# transmission failed (core has no bandwidth)" msgstr "" #: src/fs/gnunet-service-fs_pe.c:420 #, fuzzy msgid "# query messages sent to other peers" msgstr "# bytes de mensajes salientes omitidos" #: src/fs/gnunet-service-fs_pe.c:469 msgid "# delay heap timeout" msgstr "" #: src/fs/gnunet-service-fs_pe.c:476 #, fuzzy msgid "# query plans executed" msgstr "# mensajes PONG encriptados recibidos" #: src/fs/gnunet-service-fs_pe.c:538 #, fuzzy msgid "# requests merged" msgstr "# mensajes PONG encriptados recibidos" #: src/fs/gnunet-service-fs_pe.c:544 #, fuzzy msgid "# requests refreshed" msgstr "# mensajes PONG encriptados recibidos" #: src/fs/gnunet-service-fs_pe.c:597 src/fs/gnunet-service-fs_pe.c:681 #: src/fs/gnunet-service-fs_pe.c:748 msgid "# query plan entries" msgstr "" #: src/fs/gnunet-service-fs_pr.c:285 #, fuzzy msgid "# Pending requests created" msgstr "# mensajes PONG encriptados recibidos" #: src/fs/gnunet-service-fs_pr.c:367 src/fs/gnunet-service-fs_pr.c:616 #, fuzzy msgid "# Pending requests active" msgstr "# mensajes PONG encriptados recibidos" #: src/fs/gnunet-service-fs_pr.c:779 #, fuzzy msgid "# replies received and matched" msgstr "# bytes recibidos por TCP" #: src/fs/gnunet-service-fs_pr.c:808 msgid "# duplicate replies discarded (bloomfilter)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:822 #, c-format msgid "Unsupported block type %u\n" msgstr "" #: src/fs/gnunet-service-fs_pr.c:835 msgid "# results found locally" msgstr "" #: src/fs/gnunet-service-fs_pr.c:953 msgid "# Datastore `PUT' failures" msgstr "" #: src/fs/gnunet-service-fs_pr.c:980 #, fuzzy msgid "# storage requests dropped due to high load" msgstr "# Anuncios de los pares recibidos" #: src/fs/gnunet-service-fs_pr.c:1015 #, fuzzy msgid "# Replies received from DHT" msgstr "# bytes recibidos vía HTTP" #: src/fs/gnunet-service-fs_pr.c:1106 #, c-format msgid "Datastore lookup already took %llu ms!\n" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1127 #, c-format msgid "On-demand lookup already took %llu ms!\n" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1174 msgid "# Datastore lookups concluded (no results)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1188 msgid "# Datastore lookups concluded (seen all)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1197 msgid "# Datastore lookups aborted (more than MAX_RESULTS)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1211 msgid "# requested DBLOCK or IBLOCK not found" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1224 msgid "# on-demand blocks matched requests" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1237 msgid "# on-demand lookups performed successfully" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1242 msgid "# on-demand lookups failed" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1269 src/fs/gnunet-service-fs_pr.c:1309 #: src/fs/gnunet-service-fs_pr.c:1447 msgid "# Datastore lookups concluded (error queueing)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1327 msgid "# Datastore lookups concluded (found last result)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1338 msgid "# Datastore lookups concluded (load too high)" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1424 msgid "# Datastore lookups initiated" msgstr "" #: src/fs/gnunet-service-fs_pr.c:1508 #, fuzzy msgid "# GAP PUT messages received" msgstr "# mensajes PONG encriptados recibidos" #: src/fs/gnunet-service-fs_pr.c:1601 src/fs/gnunet-service-fs_pr.c:1610 #, fuzzy, c-format msgid "Configuration fails to specify `%s', assuming default value." msgstr "Fichero de configuración '%s' creado.\n" #: src/fs/gnunet-service-fs_push.c:629 #, c-format msgid "" "Invalid value specified for option `%s' in section `%s', content pushing " "disabled\n" msgstr "" #: src/fs/gnunet-unindex.c:89 #, c-format msgid "Unindexing at %llu/%llu (%s remaining)\n" msgstr "" #: src/fs/gnunet-unindex.c:96 #, fuzzy, c-format msgid "Error unindexing: %s.\n" msgstr "" "\n" "Error desindexando el fichero: %s\n" #: src/fs/gnunet-unindex.c:101 #, fuzzy msgid "Unindexing done.\n" msgstr "Desindexar los ficheros." #: src/fs/gnunet-unindex.c:131 #, fuzzy, c-format msgid "You must specify one and only one filename for unindexing.\n" msgstr "Debes especificar uno y solo un fichero para desindexar.\n" #: src/fs/gnunet-unindex.c:148 #, fuzzy msgid "Could not start unindex operation.\n" msgstr "Imposible acceder a la información del espacio.\n" #: src/fs/gnunet-unindex.c:176 msgid "Unindex a file that was previously indexed with gnunet-publish." msgstr "" #: src/fs/plugin_block_fs.c:131 msgid "Reply mismatched in terms of namespace. Discarded.\n" msgstr "" #: src/gns/gnunet-gns.c:191 #, fuzzy msgid "Failed to connect to GNS\n" msgstr "Fallo al conectar a gnunetd.\n" #: src/gns/gnunet-gns.c:232 msgid "try to shorten a given GNS name" msgstr "" #: src/gns/gnunet-gns.c:235 msgid "Lookup a record using GNS (NOT IMPLEMENTED)" msgstr "" #: src/gns/gnunet-gns.c:238 msgid "Get the authority of a particular name" msgstr "" #: src/gns/gnunet-gns.c:241 #, fuzzy msgid "Specify the type of the record lookup" msgstr "especifica la prioridad del contenido" #: src/gns/gnunet-gns.c:244 msgid "No unneeded output" msgstr "" #: src/gns/gnunet-gns.c:255 msgid "GNUnet GNS access tool" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:280 #, fuzzy, c-format msgid "Unsupported form value `%s'\n" msgstr "Comando inesperado '%s'. Abortando.\n" #: src/gns/gnunet-gns-fcfsd.c:333 #, fuzzy, c-format msgid "Failed to create record for domain `%s': %s\n" msgstr "Imposible pasar el fichero de configuración '%s'.\n" #: src/gns/gnunet-gns-fcfsd.c:377 #, c-format msgid "Found existing name `%s' for the given key\n" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:439 #, c-format msgid "Found %u existing records for domain `%s'\n" msgstr "" #: src/gns/gnunet-gns-fcfsd.c:498 #, fuzzy, c-format msgid "Failed to create page for `%s'\n" msgstr "Imposible crear el espacio '%s' (¿existe?).\n" #: src/gns/gnunet-gns-fcfsd.c:514 #, fuzzy, c-format msgid "Failed to setup post processor for `%s'\n" msgstr "Falló al actualizar los datos del módulo '%s'\n" #: src/gns/gnunet-gns-fcfsd.c:725 src/gns/gnunet-gns-fcfsd.c:737 #, fuzzy, c-format msgid "Option `%s' not specified in configuration section `%s'\n" msgstr "¡Ninguna aplicación definida en la configuración!\n" #: src/gns/gnunet-gns-fcfsd.c:747 src/namestore/gnunet-namestore.c:299 #, fuzzy msgid "Failed to read or create private zone key\n" msgstr "Falló al actualizar los datos del módulo '%s'\n" #: src/gns/gnunet-gns-fcfsd.c:757 src/namestore/gnunet-namestore.c:310 #, fuzzy msgid "Failed to connect to namestore\n" msgstr "Fallo al conectarse a gnunetd" #: src/gns/gnunet-gns-fcfsd.c:773 src/gns/gnunet-gns-proxy.c:525 #, fuzzy msgid "Failed to start HTTP server\n" msgstr "Falló al comenzar la recolección.\n" #: src/gns/gnunet-gns-fcfsd.c:804 msgid "GNUnet GNS first come first serve registration service" msgstr "" #: src/gns/gnunet-gns-proxy.c:800 msgid "listen on specified port" msgstr "" #: src/gns/gnunet-gns-proxy.c:811 msgid "GNUnet GNS proxy" msgstr "" #: src/hello/gnunet-hello.c:122 msgid "Call with name of HELLO file to modify.\n" msgstr "" #: src/hello/gnunet-hello.c:128 #, fuzzy, c-format msgid "Error accessing file `%s': %s\n" msgstr "Error creando usuario" #: src/hello/gnunet-hello.c:136 #, c-format msgid "File `%s' is too big to be a HELLO\n" msgstr "" #: src/hello/gnunet-hello.c:143 #, c-format msgid "File `%s' is too small to be a HELLO\n" msgstr "" #: src/hello/gnunet-hello.c:153 src/hello/gnunet-hello.c:181 #, fuzzy, c-format msgid "Error opening file `%s': %s\n" msgstr "Error creando usuario" #: src/hello/gnunet-hello.c:169 #, fuzzy, c-format msgid "Did not find well-formed HELLO in file `%s'\n" msgstr "Falló al actualizar los datos del módulo '%s'\n" #: src/hello/gnunet-hello.c:193 #, fuzzy, c-format msgid "Error writing HELLO to file `%s': %s\n" msgstr "Error creando usuario" #: src/hostlist/gnunet-daemon-hostlist.c:264 msgid "" "None of the functions for the hostlist daemon were enabled. I have no " "reason to run!\n" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:317 msgid "advertise our hostlist to other peers" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:322 msgid "" "bootstrap using hostlists (it is highly recommended that you always use this " "option)" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:325 msgid "enable learning about hostlist servers from other peers" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:329 msgid "provide a hostlist server" msgstr "" #: src/hostlist/gnunet-daemon-hostlist.c:341 msgid "GNUnet hostlist server and client" msgstr "" #: src/hostlist/hostlist-client.c:289 msgid "# bytes downloaded from hostlist servers" msgstr "" #: src/hostlist/hostlist-client.c:310 src/hostlist/hostlist-client.c:340 #, fuzzy msgid "# invalid HELLOs downloaded from hostlist servers" msgstr "# saludos descargados vía HTTP" #: src/hostlist/hostlist-client.c:313 src/hostlist/hostlist-client.c:343 #, fuzzy, c-format msgid "Invalid `%s' message received from hostlist at `%s'\n" msgstr "Mensaje '%s' inválido recibido del par '%s'.\n" #: src/hostlist/hostlist-client.c:331 #, fuzzy msgid "# valid HELLOs downloaded from hostlist servers" msgstr "# saludos descargados vía HTTP" #: src/hostlist/hostlist-client.c:375 src/hostlist/hostlist-client.c:396 #, c-format msgid "No `%s' specified in `%s' configuration, will not bootstrap.\n" msgstr "" #: src/hostlist/hostlist-client.c:473 src/hostlist/hostlist-client.c:683 #: src/hostlist/hostlist-client.c:689 src/hostlist/hostlist-client.c:741 #: src/hostlist/hostlist-client.c:750 src/hostlist/hostlist-client.c:871 #: src/hostlist/hostlist-client.c:961 src/hostlist/hostlist-client.c:966 #: src/transport/plugin_transport_http_client.c:110 #: src/transport/plugin_transport_http_client.c:125 #, fuzzy, c-format msgid "%s failed at %s:%d: `%s'\n" msgstr "'%s' falló en %s: %d con error: '%s'.\n" #: src/hostlist/hostlist-client.c:593 src/hostlist/hostlist-client.c:1331 msgid "# advertised hostlist URIs" msgstr "" #: src/hostlist/hostlist-client.c:623 #, c-format msgid "# advertised URI `%s' downloaded" msgstr "" #: src/hostlist/hostlist-client.c:664 #, c-format msgid "" "Advertised hostlist with URI `%s' could not be downloaded. Advertised URI " "gets dismissed.\n" msgstr "" #: src/hostlist/hostlist-client.c:802 #, c-format msgid "Timeout trying to download hostlist from `%s'\n" msgstr "" #: src/hostlist/hostlist-client.c:816 #, c-format msgid "Download limit of %u bytes exceeded, stopping download\n" msgstr "" #: src/hostlist/hostlist-client.c:836 #, fuzzy, c-format msgid "Download of hostlist from `%s' failed: `%s'\n" msgstr "" "Subida de '%s' completada, la velocidad media de subida actual es %8.3f " "kbps.\n" #: src/hostlist/hostlist-client.c:842 #, fuzzy, c-format msgid "Download of hostlist `%s' completed.\n" msgstr "" "Subida de '%s' completada, la velocidad media de subida actual es %8.3f " "kbps.\n" #: src/hostlist/hostlist-client.c:850 #, c-format msgid "Adding successfully tested hostlist `%s' datastore.\n" msgstr "" #: src/hostlist/hostlist-client.c:903 #, c-format msgid "Bootstrapping using hostlist at `%s'.\n" msgstr "" #: src/hostlist/hostlist-client.c:911 msgid "# hostlist downloads initiated" msgstr "" #: src/hostlist/hostlist-client.c:1037 src/hostlist/hostlist-client.c:1505 msgid "# milliseconds between hostlist downloads" msgstr "" #: src/hostlist/hostlist-client.c:1046 #, c-format msgid "Have %u/%u connections. Will consider downloading hostlist in %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1084 msgid "Scheduled saving of hostlists\n" msgstr "" #: src/hostlist/hostlist-client.c:1088 #, c-format msgid "Hostlists will be saved to file again in %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1111 src/hostlist/hostlist-client.c:1127 #, fuzzy msgid "# active connections" msgstr "Configuración de GNUnet" #: src/hostlist/hostlist-client.c:1242 #, c-format msgid "Initial time between hostlist downloads is %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1273 #, c-format msgid "" "No `%s' specified in `%s' configuration, cannot load hostlists from file.\n" msgstr "" #: src/hostlist/hostlist-client.c:1279 #, c-format msgid "Loading saved hostlist entries from file `%s' \n" msgstr "" #: src/hostlist/hostlist-client.c:1283 #, c-format msgid "Hostlist file `%s' is not existing\n" msgstr "" #: src/hostlist/hostlist-client.c:1294 #, fuzzy, c-format msgid "Could not open file `%s' for reading to load hostlists: %s\n" msgstr "Fichero almacenado en '%s'.\n" #: src/hostlist/hostlist-client.c:1327 #, c-format msgid "%u hostlist URIs loaded from file\n" msgstr "" #: src/hostlist/hostlist-client.c:1329 msgid "# hostlist URIs read from file" msgstr "" #: src/hostlist/hostlist-client.c:1362 #, c-format msgid "" "No `%s' specified in `%s' configuration, cannot save hostlists to file.\n" msgstr "" #: src/hostlist/hostlist-client.c:1376 #, fuzzy, c-format msgid "Could not open file `%s' for writing to save hostlists: %s\n" msgstr "Fichero almacenado en '%s'.\n" #: src/hostlist/hostlist-client.c:1381 #, c-format msgid "Writing %u hostlist URIs to `%s'\n" msgstr "" #: src/hostlist/hostlist-client.c:1405 src/hostlist/hostlist-client.c:1422 #, fuzzy, c-format msgid "Error writing hostlist URIs to file `%s'\n" msgstr "Error creando usuario" #: src/hostlist/hostlist-client.c:1417 msgid "# hostlist URIs written to file" msgstr "" #: src/hostlist/hostlist-client.c:1470 msgid "Learning is enabled on this peer\n" msgstr "" #: src/hostlist/hostlist-client.c:1473 #, c-format msgid "Hostlists will be saved to file again in %llums\n" msgstr "" #: src/hostlist/hostlist-client.c:1482 msgid "Learning is not enabled on this peer\n" msgstr "" #: src/hostlist/hostlist-client.c:1494 #, c-format msgid "" "Since learning is not enabled on this peer, hostlist file `%s' was removed\n" msgstr "" #: src/hostlist/hostlist-client.c:1498 #, fuzzy, c-format msgid "Hostlist file `%s' could not be removed\n" msgstr "La clave de sesión del par '%s' no pudo ser verificada.\n" #: src/hostlist/hostlist-server.c:134 #, fuzzy msgid "bytes in hostlist" msgstr "# bytes en la base de datos" #: src/hostlist/hostlist-server.c:157 msgid "expired addresses encountered" msgstr "" #: src/hostlist/hostlist-server.c:184 src/hostlist/hostlist-server.c:425 #: src/peerinfo-tool/gnunet-peerinfo.c:403 #: src/peerinfo-tool/gnunet-peerinfo.c:519 #: src/topology/gnunet-daemon-topology.c:927 #, fuzzy, c-format msgid "Error in communication with PEERINFO service: %s\n" msgstr "Imprime información de los pares de GNUnet." #: src/hostlist/hostlist-server.c:205 msgid "HELLOs without addresses encountered (ignored)" msgstr "" #: src/hostlist/hostlist-server.c:219 msgid "bytes not included in hostlist (size limit)" msgstr "" #: src/hostlist/hostlist-server.c:263 #, c-format msgid "Refusing `%s' request to hostlist server\n" msgstr "" #: src/hostlist/hostlist-server.c:266 #, fuzzy msgid "hostlist requests refused (not HTTP GET)" msgstr "# mensajes PONG encriptados recibidos" #: src/hostlist/hostlist-server.c:273 msgid "Sending 100 CONTINUE reply\n" msgstr "" #: src/hostlist/hostlist-server.c:279 #, c-format msgid "Refusing `%s' request with %llu bytes of upload data\n" msgstr "" #: src/hostlist/hostlist-server.c:283 #, fuzzy msgid "hostlist requests refused (upload data)" msgstr "# mensajes PONG encriptados recibidos" #: src/hostlist/hostlist-server.c:291 msgid "Could not handle hostlist request since I do not have a response yet\n" msgstr "" #: src/hostlist/hostlist-server.c:294 #, fuzzy msgid "hostlist requests refused (not ready)" msgstr "# mensajes PONG encriptados recibidos" #: src/hostlist/hostlist-server.c:298 msgid "Received request for our hostlist\n" msgstr "" #: src/hostlist/hostlist-server.c:299 #, fuzzy msgid "hostlist requests processed" msgstr "# mensajes PONG encriptados recibidos" #: src/hostlist/hostlist-server.c:341 #, fuzzy msgid "# hostlist advertisements send" msgstr "# Anuncios a extraños mandados" #: src/hostlist/hostlist-server.c:388 msgid "Advertisement message could not be queued by core\n" msgstr "" #: src/hostlist/hostlist-server.c:561 #, fuzzy, c-format msgid "Invalid port number %llu. Exiting.\n" msgstr "Argumentos no válidos. Saliendo.\n" #: src/hostlist/hostlist-server.c:570 #, c-format msgid "Hostlist service starts on %s:%llu\n" msgstr "" #: src/hostlist/hostlist-server.c:584 #, c-format msgid "Address to obtain hostlist: `%s'\n" msgstr "" #: src/hostlist/hostlist-server.c:624 #, fuzzy, c-format msgid "`%s' is not a valid IP address! Ignoring BINDTOIP.\n" msgstr "'%s' no esta disponible." #: src/hostlist/hostlist-server.c:666 #, c-format msgid "Could not start hostlist HTTP server on port %u\n" msgstr "" #: src/integration-tests/connection_watchdog.c:997 #, fuzzy, c-format msgid "Transport plugin: `%s' port %llu\n" msgstr "Probando transporte(s) %s\n" #: src/integration-tests/connection_watchdog.c:1030 #, fuzzy, c-format msgid "Found %u transport plugins: `%s'\n" msgstr "Probando transporte(s) %s\n" #: src/integration-tests/connection_watchdog.c:1089 msgid "Send ping messages to test connectivity (default == NO)" msgstr "" #: src/integration-tests/connection_watchdog.c:1095 #: src/template/gnunet-template.c:68 #, fuzzy msgid "help text" msgstr "texto de ayuda para -t" #: src/mesh/gnunet-service-mesh.c:4590 #, fuzzy msgid "Wrong CORE service\n" msgstr "Deteniendo cron\n" #: src/mesh/gnunet-service-mesh.c:4784 #, fuzzy msgid "Mesh service is lacking key configuration settings. Exiting.\n" msgstr "Configuración de GNUnet" #: src/mesh/gnunet-service-mesh.c:4793 #, fuzzy msgid "Mesh service could not access hostkey. Exiting.\n" msgstr "Imposible acceder a la información del espacio.\n" #: src/mysql/mysql.c:174 #, c-format msgid "Trying to use file `%s' for MySQL configuration.\n" msgstr "Intentando usar el fichero '%s' para la configuración de MySQL.\n" #: src/mysql/mysql.c:181 #, fuzzy, c-format msgid "Could not access file `%s': %s\n" msgstr "Imposible ejecutar '%s': %s\n" #: src/namestore/gnunet-namestore.c:157 #, fuzzy, c-format msgid "Adding record failed: %s\n" msgstr "" "\n" "Error subiendo el fichero %s\n" #: src/namestore/gnunet-namestore.c:183 #, fuzzy, c-format msgid "Deleting record failed: %s\n" msgstr "" "\n" "Error subiendo el fichero %s\n" #: src/namestore/gnunet-namestore.c:239 #, c-format msgid "\tCorrupt or unsupported record of type %u\n" msgstr "" #: src/namestore/gnunet-namestore.c:276 #, c-format msgid "Option `%s' not given, but I need a zone key file!\n" msgstr "" #: src/namestore/gnunet-namestore.c:281 #, fuzzy, c-format msgid "Using default zone file `%s'\n" msgstr "Iniciada colección '%s'.\n" #: src/namestore/gnunet-namestore.c:291 #, c-format msgid "No options given\n" msgstr "" #: src/namestore/gnunet-namestore.c:321 #, fuzzy, c-format msgid "Unsupported type `%s'\n" msgstr "Mensaje no válido del tipo %u recibido. Omitiendo.\n" #: src/namestore/gnunet-namestore.c:328 src/namestore/gnunet-namestore.c:350 #: src/namestore/gnunet-namestore.c:374 src/namestore/gnunet-namestore.c:384 #: src/namestore/gnunet-namestore.c:409 #, fuzzy, c-format msgid "Missing option `%s' for operation `%s'\n" msgstr "Fichero de configuración '%s' creado.\n" #: src/namestore/gnunet-namestore.c:329 src/namestore/gnunet-namestore.c:351 msgid "add/del" msgstr "" #: src/namestore/gnunet-namestore.c:341 #, fuzzy, c-format msgid "Value `%s' invalid for record type `%s'\n" msgstr "%s: valor del símbolo '%s' no válido para %s\n" #: src/namestore/gnunet-namestore.c:366 #, fuzzy, c-format msgid "Invalid time format `%s'\n" msgstr "Argumento no válido: '%s'\n" #: src/namestore/gnunet-namestore.c:375 src/namestore/gnunet-namestore.c:385 msgid "add" msgstr "" #: src/namestore/gnunet-namestore.c:410 msgid "del" msgstr "" #: src/namestore/gnunet-namestore.c:462 msgid "add record" msgstr "" #: src/namestore/gnunet-namestore.c:465 msgid "delete record" msgstr "" #: src/namestore/gnunet-namestore.c:468 msgid "display records" msgstr "" #: src/namestore/gnunet-namestore.c:471 msgid "" "expiration time for record to use (for adding only), \"never\" is possible" msgstr "" #: src/namestore/gnunet-namestore.c:474 msgid "name of the record to add/delete/display" msgstr "" #: src/namestore/gnunet-namestore.c:477 msgid "type of the record to add/delete/display" msgstr "" #: src/namestore/gnunet-namestore.c:480 msgid "value of the record to add/delete" msgstr "" #: src/namestore/gnunet-namestore.c:483 msgid "create or list public record" msgstr "" #: src/namestore/gnunet-namestore.c:486 msgid "create or list non-authority record" msgstr "" #: src/namestore/gnunet-namestore.c:489 msgid "filename with the zone key" msgstr "" #: src/namestore/gnunet-namestore.c:500 #, fuzzy msgid "GNUnet zone manipulation tool" msgstr "Configuración de GNUnet" #: src/namestore/gnunet-service-namestore.c:143 #, c-format msgid "File zone `%s' but corrupt content already exists, failed to write! \n" msgstr "" #: src/namestore/gnunet-service-namestore.c:154 #, c-format msgid "File zone `%s' containing this key already exists\n" msgstr "" #: src/namestore/gnunet-service-namestore.c:160 #, c-format msgid "" "File zone `%s' but different zone key already exists, failed to write! \n" msgstr "" #: src/namestore/gnunet-service-namestore.c:198 #, fuzzy, c-format msgid "Stored zonekey for zone `%s' in file `%s'\n" msgstr "Fichero almacenado en '%s'.\n" #: src/namestore/gnunet-service-namestore.c:1909 #, fuzzy msgid "No directory to load zonefiles specified in configuration\n" msgstr "¡Ninguna aplicación definida en la configuración!\n" #: src/namestore/gnunet-service-namestore.c:1918 #, c-format msgid "Creating directory `%s' for zone files failed!\n" msgstr "" #: src/namestore/namestore_api.c:315 src/namestore/namestore_api.c:353 msgid "Namestore added record successfully" msgstr "" #: src/namestore/namestore_api.c:323 msgid "Namestore failed to add record" msgstr "" #: src/namestore/namestore_api.c:361 msgid "Namestore record already existed" msgstr "" #: src/namestore/namestore_api.c:368 msgid "Namestore failed to add record\n" msgstr "" #: src/namestore/namestore_api.c:401 #, fuzzy msgid "Namestore removed record successfully" msgstr "Servicio de GNUnet instalado satisfactoriamente.\n" #: src/namestore/namestore_api.c:408 msgid "No records for entry" msgstr "" #: src/namestore/namestore_api.c:415 #, fuzzy msgid "Could not find record to remove" msgstr "Imposible conectar con gnunetd.\n" #: src/namestore/namestore_api.c:422 #, fuzzy msgid "Failed to create new signature" msgstr "Imposible crear el espacio '%s' (¿existe?).\n" #: src/namestore/namestore_api.c:429 #, fuzzy msgid "Failed to put new set of records in database" msgstr "Falló al mandar la petición HTTP al host '%s': %s\n" #: src/nat/gnunet-nat-server.c:279 #, c-format msgid "Please pass valid port number as the first argument! (got `%s')\n" msgstr "" #: src/nat/gnunet-nat-server.c:318 msgid "GNUnet NAT traversal test helper daemon" msgstr "" #: src/nat/nat.c:799 #, c-format msgid "gnunet-helper-nat-server generated malformed address `%s'\n" msgstr "" #: src/nat/nat.c:844 #, fuzzy, c-format msgid "Failed to start %s\n" msgstr "Falló al comenzar la recolección.\n" #: src/nat/nat.c:1111 #, fuzzy, c-format msgid "Malformed %s `%s' given in configuration!\n" msgstr "Imposible guardar la configuración" #: src/nat/nat.c:1177 src/nat/nat.c:1187 #, c-format msgid "" "Configuration requires `%s', but binary is not installed properly (SUID bit " "not set). Option disabled.\n" msgstr "" #: src/nat/nat.c:1321 msgid "Internal IP address not known, cannot use ICMP NAT traversal method\n" msgstr "" #: src/nat/nat.c:1332 #, c-format msgid "Running gnunet-helper-nat-client %s %s %u\n" msgstr "" #: src/nat/nat_test.c:341 #, fuzzy msgid "Failed to connect to `gnunet-nat-server'\n" msgstr "Fallo al conectar a gnunetd.\n" #: src/nat/nat_test.c:411 #, c-format msgid "Failed to create listen socket bound to `%s' for NAT test: %s\n" msgstr "" #: src/nse/gnunet-nse-profiler.c:928 #, fuzzy msgid "Measure quality and performance of the NSE service." msgstr "Imposible acceder al servicio" #: src/nse/gnunet-service-nse.c:925 #, c-format msgid "Proof of work invalid: %llu!\n" msgstr "" #: src/nse/gnunet-service-nse.c:1381 src/nse/gnunet-service-nse.c:1400 #: src/nse/gnunet-service-nse.c:1421 msgid "NSE service is lacking key configuration settings. Exiting.\n" msgstr "" #: src/nse/gnunet-service-nse.c:1388 #, fuzzy msgid "Invalid work requirement for NSE service. Exiting.\n" msgstr "Argumentos no válidos. Saliendo.\n" #: src/nse/gnunet-service-nse.c:1409 #, fuzzy msgid "NSE service could not access hostkey. Exiting.\n" msgstr "Imposible acceder a la información del espacio.\n" #: src/peerinfo/gnunet-service-peerinfo.c:134 #, fuzzy, c-format msgid "Removing expired address of transport `%s'\n" msgstr "Transporte(s) disponible(s): %s\n" #: src/peerinfo/gnunet-service-peerinfo.c:203 #, fuzzy, c-format msgid "Failed to parse HELLO in file `%s'\n" msgstr "Falló al actualizar los datos del módulo '%s'\n" #: src/peerinfo/gnunet-service-peerinfo.c:229 msgid "# peers known" msgstr "" #: src/peerinfo/gnunet-service-peerinfo.c:254 #, c-format msgid "" "File `%s' in directory `%s' does not match naming convention. Removed.\n" msgstr "" "El fichero '%s' en el directorio '%s' no sigue la convención de nombres. " "Eliminando.\n" #: src/peerinfo/gnunet-service-peerinfo.c:353 #, fuzzy, c-format msgid "Still no peers found in `%s'!\n" msgstr "¡Imposible descargar adecuadamente el servicio '%s'!\n" #: src/peerinfo/gnunet-service-peerinfo.c:710 #, c-format msgid "Importing HELLOs from `%s'\n" msgstr "" #: src/peerinfo/peerinfo_api.c:238 msgid "aborted due to explicit disconnect request" msgstr "" #: src/peerinfo/peerinfo_api.c:358 #, fuzzy msgid "failed to transmit request (service down?)" msgstr "Falló al mandar la petición HTTP al host '%s': %s\n" #: src/peerinfo/peerinfo_api.c:505 #, fuzzy msgid "Failed to receive response from `PEERINFO' service." msgstr "Falló al recibir la respuesta al mensaje '%s' de gnunetd\n" #: src/peerinfo/peerinfo_api.c:531 src/peerinfo/peerinfo_api.c:550 #: src/peerinfo/peerinfo_api.c:565 src/peerinfo/peerinfo_api.c:576 #: src/peerinfo/peerinfo_api.c:587 #, fuzzy msgid "Received invalid message from `PEERINFO' service." msgstr "Recibido mensaje UDP6 inválido de %s:%d, omitiendo.\n" #: src/peerinfo/peerinfo_api.c:663 #, fuzzy msgid "Timeout transmitting iteration request to `PEERINFO' service." msgstr "Falló al inicializar el servicio '%s'.\n" #: src/peerinfo/peerinfo_api_notify.c:256 #, fuzzy, c-format msgid "Could not connect to `%s' service.\n" msgstr "Imposible conectar con gnunetd.\n" #: src/peerinfo-tool/gnunet-peerinfo.c:581 #, fuzzy msgid "Failed to parse HELLO message: missing expiration time\n" msgstr "Imposible guardar la configuración" #: src/peerinfo-tool/gnunet-peerinfo.c:589 #, fuzzy msgid "Failed to parse HELLO message: invalid expiration time\n" msgstr "Imposible guardar la configuración" #: src/peerinfo-tool/gnunet-peerinfo.c:598 #, fuzzy msgid "Failed to parse HELLO message: malformed\n" msgstr "Falló al pasar los datos de la interfaz de '%s' de %s:%d.\n" #: src/peerinfo-tool/gnunet-peerinfo.c:608 #, fuzzy msgid "Failed to parse HELLO message: missing transport plugin\n" msgstr "Imposible inicializar la aplicación '%s'\n" #: src/peerinfo-tool/gnunet-peerinfo.c:625 #, c-format msgid "Plugin `%s' not found\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:634 #, c-format msgid "Plugin `%s' does not support URIs yet\n" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:653 #, fuzzy, c-format msgid "Failed to parse `%s' as an address for plugin `%s'\n" msgstr "Fallo al conectar a gnunetd.\n" #: src/peerinfo-tool/gnunet-peerinfo.c:685 #, fuzzy, c-format msgid "Failure adding HELLO: %s\n" msgstr "Fallo en %s:%d.\n" #: src/peerinfo-tool/gnunet-peerinfo.c:833 #, fuzzy, c-format msgid "Could not find option `%s:%s' in configuration.\n" msgstr "¡Imposible encontrar el par '%s' en la tabla de enrutado!\n" #: src/peerinfo-tool/gnunet-peerinfo.c:840 #, fuzzy, c-format msgid "Loading hostkey from `%s' failed.\n" msgstr "Analizando saludo de '%s' se produjo un fallo.\n" #: src/peerinfo-tool/gnunet-peerinfo.c:875 #, fuzzy, c-format msgid "Invalid URI `%s'\n" msgstr "Argumento no válido: '%s'\n" #: src/peerinfo-tool/gnunet-peerinfo.c:899 #, c-format msgid "I am peer `%s'.\n" msgstr "Yo soy el par '%s'.\n" #: src/peerinfo-tool/gnunet-peerinfo.c:936 msgid "don't resolve host names" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:939 msgid "output only the identity strings" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:942 msgid "output our own identity only" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:945 msgid "list all known peers" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:948 msgid "also output HELLO uri(s)" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:951 msgid "add given HELLO uri to the database" msgstr "" #: src/peerinfo-tool/gnunet-peerinfo.c:957 #, fuzzy msgid "Print information about peers." msgstr "Imprime información de los pares de GNUnet." #: src/peerinfo-tool/gnunet-peerinfo_plugins.c:105 #: src/transport/gnunet-service-transport_plugins.c:118 #, fuzzy, c-format msgid "Starting transport plugins `%s'\n" msgstr "Probando transporte(s) %s\n" #: src/peerinfo-tool/gnunet-peerinfo_plugins.c:109 #: src/transport/gnunet-service-transport_plugins.c:122 #, fuzzy, c-format msgid "Loading `%s' transport plugin\n" msgstr "Probando transporte(s) %s\n" #: src/peerinfo-tool/gnunet-peerinfo_plugins.c:129 #: src/transport/gnunet-service-transport_plugins.c:150 #, fuzzy, c-format msgid "Failed to load transport plugin for `%s'\n" msgstr "Imposible inicializar la aplicación '%s'\n" #: src/postgres/postgres.c:59 #, fuzzy, c-format msgid "`%s:%s' failed at %s:%d with error: %s" msgstr "'%s' falló en %s: %d con el error: %s\n" #: src/postgres/postgres.c:148 #, fuzzy, c-format msgid "Unable to initialize Postgres: %s" msgstr "Imposible inicializar SQLite.\n" #: src/pt/gnunet-daemon-pt.c:264 #, fuzzy msgid "Failed to pack DNS request. Dropping.\n" msgstr "Falló al mandar la petición HTTP al host '%s': %s\n" #: src/pt/gnunet-daemon-pt.c:270 #, fuzzy msgid "# DNS requests mapped to VPN" msgstr "# mensajes PONG encriptados recibidos" #: src/pt/gnunet-daemon-pt.c:323 msgid "# DNS records modified" msgstr "" #: src/pt/gnunet-daemon-pt.c:500 msgid "# DNS replies intercepted" msgstr "" #: src/pt/gnunet-daemon-pt.c:506 #, fuzzy msgid "Failed to parse DNS request. Dropping.\n" msgstr "Falló al mandar la petición HTTP al host '%s': %s\n" #: src/pt/gnunet-daemon-pt.c:602 #, fuzzy msgid "# DNS requests dropped (timeout)" msgstr "# Anuncios de los pares recibidos" #: src/pt/gnunet-daemon-pt.c:632 #, fuzzy msgid "# DNS requests intercepted" msgstr "# mensajes PONG encriptados recibidos" #: src/pt/gnunet-daemon-pt.c:637 #, fuzzy msgid "# DNS requests dropped (DNS mesh tunnel down)" msgstr "# Anuncios de los pares recibidos" #: src/pt/gnunet-daemon-pt.c:645 #, fuzzy msgid "# DNS requests dropped (malformed)" msgstr "# Anuncios de los pares recibidos" #: src/pt/gnunet-daemon-pt.c:716 #, fuzzy msgid "# DNS replies received" msgstr "# mensajes PONG encriptados recibidos" #: src/pt/gnunet-daemon-pt.c:730 #, fuzzy msgid "# DNS replies dropped (too late?)" msgstr "# Anuncios de los pares recibidos" #: src/pt/gnunet-daemon-pt.c:748 src/pt/gnunet-daemon-pt.c:760 msgid "# DNS requests aborted (tunnel down)" msgstr "" #: src/pt/gnunet-daemon-pt.c:898 src/pt/gnunet-daemon-pt.c:907 #: src/pt/gnunet-daemon-pt.c:930 src/pt/gnunet-daemon-pt.c:940 #, fuzzy, c-format msgid "Failed to connect to %s service. Exiting.\n" msgstr "Fallo al conectar a gnunetd.\n" #: src/pt/gnunet-daemon-pt.c:973 msgid "Daemon to run to perform IP protocol translation to GNUnet" msgstr "" #: src/statistics/gnunet-service-statistics.c:271 #, fuzzy, c-format msgid "Loading %llu bytes of statistics from `%s'\n" msgstr "Descarga los ficheros de GNUnet" #: src/statistics/gnunet-service-statistics.c:330 #, fuzzy, c-format msgid "Wrote %llu bytes of statistics to `%s'\n" msgstr "Descarga los ficheros de GNUnet" #: src/statistics/gnunet-statistics.c:122 #, fuzzy msgid "Failed to obtain statistics.\n" msgstr "Fallo en las estadísticas del tráfico.\n" #: src/statistics/gnunet-statistics.c:199 #, c-format msgid "No subsystem or name given\n" msgstr "" #: src/statistics/gnunet-statistics.c:207 #, fuzzy, c-format msgid "Failed to initialize watch routine\n" msgstr "Imposible inicializar SQLite.\n" #: src/statistics/gnunet-statistics.c:227 msgid "limit output to statistics for the given NAME" msgstr "" #: src/statistics/gnunet-statistics.c:230 msgid "make the value being set persistent" msgstr "" #: src/statistics/gnunet-statistics.c:233 msgid "limit output to the given SUBSYSTEM" msgstr "" #: src/statistics/gnunet-statistics.c:236 msgid "just print the statistics value" msgstr "" #: src/statistics/gnunet-statistics.c:239 msgid "watch value continously" msgstr "" #: src/statistics/gnunet-statistics.c:246 msgid "Print statistics about GNUnet operations." msgstr "Imprime estadísticas acerca de las operaciones de GNUnet." #: src/statistics/statistics_api.c:456 #, fuzzy msgid "Could not save some persistent statistics\n" msgstr "Imposible crear el espacio '%s' (¿existe?).\n" #: src/statistics/statistics_api.c:999 msgid "" "Failed to receive acknowledgement from statistics service, some statistics " "might have been lost!\n" msgstr "" #: src/testing/gnunet-testing.c:157 #, fuzzy msgid "Could not read hostkeys file, specify hostkey file with -H!\n" msgstr "Imposible inicializar la aplicación '%s'\n" #: src/testing/gnunet-testing.c:159 #, c-format msgid "Specified hostkey file `%s' not found!\n" msgstr "" #: src/testing/gnunet-testing.c:273 #, fuzzy msgid "create unique configuration files" msgstr "Imposible guardar el fichero de configuración '%s':" #: src/testing/gnunet-testing.c:275 msgid "create hostkey files from pre-computed hostkey list" msgstr "" #: src/testing/gnunet-testing.c:277 msgid "host key file" msgstr "" #: src/testing/gnunet-testing.c:279 #, fuzzy msgid "number of unique configuration files or hostkeys to create" msgstr "Imposible guardar el fichero de configuración '%s':" #: src/testing/gnunet-testing.c:281 #, fuzzy msgid "configuration template" msgstr "Configuración de GNUnet" #: src/testing/gnunet-testing.c:287 msgid "Command line tool to access the testing library" msgstr "" #: src/testing/helper.c:56 #, fuzzy msgid "Peer is lacking HOSTKEY configuration setting.\n" msgstr "Configuración de GNUnet" #: src/testing/helper.c:64 #, fuzzy msgid "Could not access hostkey.\n" msgstr "Imposible pasar el fichero de configuración '%s'.\n" #: src/testing/testing.c:200 msgid "`scp' does not seem to terminate (timeout copying config).\n" msgstr "" #: src/testing/testing.c:214 src/testing/testing.c:798 #, fuzzy msgid "`scp' did not complete cleanly.\n" msgstr "'%s' no esta conectado a ningún par.\n" #: src/testing/testing.c:237 #, fuzzy msgid "Failed to create pipe for `gnunet-peerinfo' process.\n" msgstr "Falló al comenzar la recolección.\n" #: src/testing/testing.c:238 #, fuzzy msgid "Failed to create pipe for `ssh' process.\n" msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" #: src/testing/testing.c:286 #, fuzzy, c-format msgid "Could not start `%s' process to create hostkey.\n" msgstr "Imposible mandar el mensaje a gnunetd\n" #: src/testing/testing.c:293 #, fuzzy msgid "Failed to start `gnunet-peerinfo' process.\n" msgstr "Falló al comenzar la recolección.\n" #: src/testing/testing.c:294 src/testing/testing.c:471 #, fuzzy msgid "Failed to start `ssh' process.\n" msgstr "Falló al comenzar la recolección.\n" #: src/testing/testing.c:354 #, fuzzy, c-format msgid "Error reading from gnunet-peerinfo: %s\n" msgstr "Se produjo un error leyendo información de gnunetd.\n" #: src/testing/testing.c:358 #, fuzzy msgid "Malformed output from gnunet-peerinfo!\n" msgstr "Se produjo un error leyendo información de gnunetd.\n" #: src/testing/testing.c:368 #, fuzzy msgid "Failed to get hostkey!\n" msgstr "Fallo en las estadísticas del tráfico.\n" #: src/testing/testing.c:400 msgid "`Failed while waiting for topology setup!\n" msgstr "" #: src/testing/testing.c:463 #, fuzzy, c-format msgid "Could not start `%s' process to start GNUnet.\n" msgstr "Imposible crear el espacio '%s' (¿existe?).\n" #: src/testing/testing.c:470 #, fuzzy msgid "Failed to start `gnunet-arm' process.\n" msgstr "Fallo al conectar a gnunetd.\n" #: src/testing/testing.c:493 src/testing/testing.c:600 msgid "`gnunet-arm' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:494 src/testing/testing.c:601 #: src/testing/testing.c:621 msgid "`ssh' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:570 msgid "Unable to get HELLO for peer!\n" msgstr "" #: src/testing/testing.c:620 msgid "`gnunet-arm' terminated with non-zero exit status (or timed out)!\n" msgstr "" #: src/testing/testing.c:643 src/testing/testing.c:675 msgid "either `gnunet-arm' or `ssh' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:658 src/testing/testing.c:713 #, fuzzy msgid "shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n" msgstr "'%s' no esta conectado a ningún par.\n" #: src/testing/testing.c:786 msgid "`scp' does not seem to terminate.\n" msgstr "" #: src/testing/testing.c:948 #, fuzzy, c-format msgid "Starting service %s for peer `%4s'\n" msgstr "Iniciada colección '%s'.\n" #: src/testing/testing.c:1207 src/testing/testing_group.c:6154 #, fuzzy, c-format msgid "Could not start `%s' process to copy configuration directory.\n" msgstr "Imposible acceder a la información del espacio.\n" #: src/testing/testing.c:1292 src/testing/testing.c:1359 #, fuzzy, c-format msgid "Terminating peer `%4s'\n" msgstr "Permiso denegado para '%s' en %s:%d.\n" #: src/testing/testing.c:1448 #, fuzzy, c-format msgid "Setting d->dead on peer `%4s'\n" msgstr "Iniciada colección '%s'.\n" #: src/testing/testing.c:1601 msgid "Peer not yet running, can not change configuration at this point." msgstr "" #: src/testing/testing.c:1609 #, fuzzy msgid "Failed to write new configuration to disk." msgstr "Imposible guardar la configuración" #: src/testing/testing.c:1636 #, fuzzy, c-format msgid "Could not start `%s' process to copy configuration file.\n" msgstr "¡Imposible encontrar el par '%s' en la tabla de enrutado!\n" #: src/testing/testing.c:1639 #, fuzzy msgid "Failed to copy new configuration to remote machine." msgstr "Imposible guardar la configuración" #: src/testing/testing.c:1794 #, fuzzy msgid "Peers failed to connect" msgstr "Fallo al conectar a gnunetd.\n" #: src/testing/testing.c:1922 #, fuzzy msgid "Failed to connect to core service of first peer!\n" msgstr "Fallo al conectar a gnunetd.\n" #: src/testing/testing.c:2145 msgid "Peers are not fully running yet, can not connect!\n" msgstr "" #: src/testing/testing_group.c:1895 src/testing/testing_group.c:1907 #: src/testing/testing_group.c:2008 src/testing/testing_group.c:2065 #: src/testing/testing_group.c:2152 src/testing/testing_group.c:2172 #: src/testing/testing_group.c:2302 src/testing/testing_peergroup.c:950 #, fuzzy, c-format msgid "Invalid value `%s' for option `%s' in section `%s': expected float\n" msgstr "" "El fichero de configuración debe especificar el directorio para almacenar " "los datos FS en la sección '%s' bajo '%s'.\n" #: src/testing/testing_group.c:2160 #, c-format msgid "" "Invalid value `%s' for option `%s' in section `%s': got %f, needed value " "greater than 0\n" msgstr "" #: src/testing/testing_group.c:2877 src/testing/testing_group.c:3063 #, c-format msgid "" "No `%s' specified in peer configuration in section `%s', cannot copy friends " "file!\n" msgstr "" #: src/testing/testing_group.c:3957 msgid "Creating no allowed topology (all peers can connect at core level)\n" msgstr "" #: src/testing/testing_group.c:5226 msgid "Unknown topology specification, can't connect peers!\n" msgstr "" #: src/testing/testing_group.c:5944 src/transport/transport-testing.c:636 #, fuzzy msgid "Could not read hostkeys file!\n" msgstr "Imposible inicializar la aplicación '%s'\n" #: src/testing/testing_group.c:6011 #, fuzzy, c-format msgid "Could not create configuration for peer number %u on `%s'!\n" msgstr "Imposible acceder a la información del espacio.\n" #: src/testing/testing_new.c:169 msgid "tmppath cannot be NULL\n" msgstr "" #: src/testing/testing_new.c:356 #, c-format msgid "Hostkeys file not found: %s\n" msgstr "" #: src/testing/testing_new.c:365 #, fuzzy, c-format msgid "Could not open hostkeys file: %s\n" msgstr "Imposible inicializar la aplicación '%s'\n" #: src/testing/testing_new.c:380 #, c-format msgid "Incorrect hostkey file format: %s\n" msgstr "" #: src/testing/testing_new.c:437 #, fuzzy, c-format msgid "Key number %u does not exist\n" msgstr "número de mensajes a usar por iteración" #: src/testing/testing_new.c:446 #, fuzzy, c-format msgid "Error while decoding key %u\n" msgstr "Error descargando: %s\n" #: src/testing/testing_new.c:680 #, fuzzy msgid "Failed to create configuration for peer (not enough free ports?)\n" msgstr "Imposible acceder a la información del espacio.\n" #: src/testing/testing_new.c:691 #, c-format msgid "" "You attempted to create a testbed with more than %u hosts. Please " "precompute more hostkeys first.\n" msgstr "" #: src/testing/testing_new.c:704 #, fuzzy, c-format msgid "Failed to initialize hostkey for peer %u\n" msgstr "Imposible inicializar SQLite.\n" #: src/testing/testing_new.c:734 #, fuzzy, c-format msgid "Failed to write hostkey file for peer %u: %s\n" msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" #: src/testing/testing_new.c:751 #, fuzzy, c-format msgid "Failed to write configuration file `%s' for peer %u: %s\n" msgstr "Imposible guardar el fichero de configuración '%s':" #: src/testing/testing_new.c:791 #, fuzzy, c-format msgid "Failed to start `%s': %s\n" msgstr "Fallo al conectar a gnunetd.\n" #: src/testing/testing_new.c:959 #, fuzzy, c-format msgid "Failed to load configuration from %s\n" msgstr "Imposible guardar el fichero de configuración '%s':" #: src/topology/gnunet-daemon-topology.c:259 msgid "# peers blacklisted" msgstr "" #: src/topology/gnunet-daemon-topology.c:392 #, fuzzy msgid "# connect requests issued to transport" msgstr "# mensajes PONG encriptados recibidos" #: src/topology/gnunet-daemon-topology.c:730 #: src/topology/gnunet-daemon-topology.c:815 #, fuzzy msgid "# friends connected" msgstr "# de pares conectados" #: src/topology/gnunet-daemon-topology.c:996 msgid "Failed to connect to core service, can not manage topology!\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1026 #, c-format msgid "Option `%s' in section `%s' not specified!\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1039 #, fuzzy, c-format msgid "Could not read friends list `%s'\n" msgstr "Imposible inicializar la aplicación '%s'\n" #: src/topology/gnunet-daemon-topology.c:1045 #, fuzzy, c-format msgid "Friends file `%s' is empty.\n" msgstr "El formato del fichero '%s' no es válido.\n" #: src/topology/gnunet-daemon-topology.c:1054 #, fuzzy, c-format msgid "Failed to read friends list from `%s': out of memory\n" msgstr "Imposible inicializar la aplicación '%s'\n" #: src/topology/gnunet-daemon-topology.c:1062 #, c-format msgid "Failed to read friends list from `%s'\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1082 #, c-format msgid "" "Syntax error in topology specification at offset %llu, skipping bytes.\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1095 #, c-format msgid "" "Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1105 #, fuzzy, c-format msgid "Found friend `%s' in configuration\n" msgstr " gconfig\tConfiguración GTK\n" #: src/topology/gnunet-daemon-topology.c:1111 #, c-format msgid "Found myself `%s' in friend list (useless, ignored)\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1121 #, fuzzy msgid "# friends in configuration" msgstr " gconfig\tConfiguración GTK\n" #: src/topology/gnunet-daemon-topology.c:1127 msgid "" "Fewer friends specified than required by minimum friend count. Will only " "connect to friends.\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1134 msgid "" "More friendly connections required than target total number of connections.\n" msgstr "" #: src/topology/gnunet-daemon-topology.c:1169 #, fuzzy msgid "# HELLO messages received" msgstr "# mensajes PONG encriptados recibidos" #: src/topology/gnunet-daemon-topology.c:1224 #, fuzzy msgid "# HELLO messages gossipped" msgstr "# mensajes salientes omitidos" #: src/topology/gnunet-daemon-topology.c:1363 msgid "GNUnet topology control (maintaining P2P mesh and F2F constraints)" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:246 #, fuzzy, c-format msgid "Could not read blacklist file `%s'\n" msgstr "Imposible inicializar la aplicación '%s'\n" #: src/transport/gnunet-service-transport_blacklist.c:252 #, c-format msgid "Blacklist file `%s' is empty.\n" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:263 #, fuzzy, c-format msgid "Failed to read blacklist from `%s'\n" msgstr "Falló al pasar los datos de la interfaz de '%s' de %s:%d.\n" #: src/transport/gnunet-service-transport_blacklist.c:284 #: src/transport/gnunet-service-transport_blacklist.c:308 #, fuzzy, c-format msgid "Syntax error in blacklist file at offset %llu, giving up!\n" msgstr "" "Error de sintaxis en el fichero de configuración '%s' en la linea %d.\n" #: src/transport/gnunet-service-transport_blacklist.c:295 #: src/transport/gnunet-service-transport_blacklist.c:331 #, c-format msgid "Syntax error in blacklist file at offset %llu, skipping bytes.\n" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:345 #, fuzzy, c-format msgid "Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n" msgstr "" "Error de sintaxis en el fichero de configuración '%s' en la linea %d.\n" #: src/transport/gnunet-service-transport_blacklist.c:359 #, c-format msgid "Found myself `%s' in blacklist (useless, ignored)\n" msgstr "" #: src/transport/gnunet-service-transport_blacklist.c:514 #: src/transport/gnunet-service-transport_blacklist.c:747 msgid "# disconnects due to blacklist" msgstr "" #: src/transport/gnunet-service-transport.c:163 #, fuzzy msgid "# bytes payload discarded due to not connected peer " msgstr "# Anuncios de los pares recibidos" #: src/transport/gnunet-service-transport.c:237 #, fuzzy msgid "# bytes total received" msgstr "# bytes en la base de datos" #: src/transport/gnunet-service-transport.c:284 #, fuzzy msgid "# bytes payload received" msgstr "# bytes desencriptados" #: src/transport/gnunet-service-transport.c:582 msgid "Transport service is lacking key configuration settings. Exiting.\n" msgstr "" #: src/transport/gnunet-service-transport.c:591 msgid "Transport service could not access hostkey. Exiting.\n" msgstr "" #: src/transport/gnunet-service-transport_clients.c:352 #, c-format msgid "Dropping message of type %u and size %u, have %u/%u messages pending\n" msgstr "" #: src/transport/gnunet-service-transport_clients.c:357 #, fuzzy msgid "# messages dropped due to slow client" msgstr "# Anuncios de los pares recibidos" #: src/transport/gnunet-service-transport_clients.c:503 #, c-format msgid "Rejecting control connection from peer `%s', which is not me!\n" msgstr "" #: src/transport/gnunet-service-transport_clients.c:631 msgid "# bytes payload dropped (other peer was not connected)" msgstr "" #: src/transport/gnunet-service-transport_clients.c:682 #, fuzzy msgid "# REQUEST CONNECT messages received" msgstr "# mensajes PONG encriptados recibidos" #: src/transport/gnunet-service-transport_hello.c:172 msgid "# refreshed my HELLO" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1032 #, fuzzy msgid "# DISCONNECT messages sent" msgstr "# mensajes PONG encriptados recibidos" #: src/transport/gnunet-service-transport_neighbours.c:1148 #: src/transport/gnunet-service-transport_neighbours.c:1482 #, fuzzy msgid "# bytes in message queue for other peers" msgstr "# bytes de mensajes salientes omitidos" #: src/transport/gnunet-service-transport_neighbours.c:1153 #, fuzzy msgid "# messages transmitted to other peers" msgstr "# bytes recibidos por TCP" #: src/transport/gnunet-service-transport_neighbours.c:1158 #, fuzzy msgid "# transmission failures for messages to other peers" msgstr "# bytes de mensajes salientes omitidos" #: src/transport/gnunet-service-transport_neighbours.c:1215 msgid "# messages timed out while in transport queue" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1254 #, fuzzy msgid "# keepalives sent" msgstr "# claves de la sesión mandadas" #: src/transport/gnunet-service-transport_neighbours.c:1278 #, fuzzy msgid "# KEEPALIVE messages discarded (peer unknown)" msgstr "# mensajes defragmentados" #: src/transport/gnunet-service-transport_neighbours.c:1286 #, fuzzy msgid "# KEEPALIVE messages discarded (no session)" msgstr "# mensajes defragmentados" #: src/transport/gnunet-service-transport_neighbours.c:1323 #, fuzzy msgid "# KEEPALIVE_RESPONSE messages discarded (not connected)" msgstr "# mensajes defragmentados" #: src/transport/gnunet-service-transport_neighbours.c:1332 #, fuzzy msgid "# KEEPALIVE_RESPONSE messages discarded (not expected)" msgstr "# mensajes defragmentados" #: src/transport/gnunet-service-transport_neighbours.c:1388 #, fuzzy msgid "# messages discarded due to lack of neighbour record" msgstr "# mensajes defragmentados" #: src/transport/gnunet-service-transport_neighbours.c:1422 msgid "# bandwidth quota violations by other peers" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:1438 msgid "# ms throttling suggested" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2544 #, fuzzy msgid "# unexpected CONNECT_ACK messages (no peer)" msgstr "envia COUNT mensajes" #: src/transport/gnunet-service-transport_neighbours.c:2559 #: src/transport/gnunet-service-transport_neighbours.c:2585 #, fuzzy msgid "# unexpected CONNECT_ACK messages (not ready)" msgstr "envia COUNT mensajes" #: src/transport/gnunet-service-transport_neighbours.c:2598 #, fuzzy msgid "# unexpected CONNECT_ACK messages (waiting on ATS)" msgstr "envia COUNT mensajes" #: src/transport/gnunet-service-transport_neighbours.c:2627 #, fuzzy msgid "# unexpected CONNECT_ACK messages (disconnecting)" msgstr "envia COUNT mensajes" #: src/transport/gnunet-service-transport_neighbours.c:2807 #, fuzzy msgid "# unexpected SESSION ACK messages" msgstr "# de pares conectados" #: src/transport/gnunet-service-transport_neighbours.c:2856 msgid "# SET QUOTA messages ignored (no such peer)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2870 msgid "# disconnects due to quota of 0" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2901 msgid "# disconnect messages ignored (old format)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2912 msgid "# disconnect messages ignored (timestamp)" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:2943 msgid "# other peer asked to disconnect from us" msgstr "" #: src/transport/gnunet-service-transport_neighbours.c:3020 #, fuzzy msgid "# disconnected from peer upon explicit request" msgstr "# Anuncios de los pares recibidos" #: src/transport/gnunet-service-transport_plugins.c:111 msgid "Transport service is lacking NEIGHBOUR_LIMIT option.\n" msgstr "" #: src/transport/gnunet-service-transport_validation.c:414 msgid "# address records discarded" msgstr "" #: src/transport/gnunet-service-transport_validation.c:463 #, c-format msgid "" "Not transmitting `%s' with `%s', message too big (%u bytes!). This should " "not happen.\n" msgstr "" #: src/transport/gnunet-service-transport_validation.c:512 #, fuzzy msgid "# PING without HELLO messages sent" msgstr "# mensajes de texto mandados por PING" #: src/transport/gnunet-service-transport_validation.c:570 msgid "# address revalidations started" msgstr "" #: src/transport/gnunet-service-transport_validation.c:805 #, fuzzy msgid "# PING message for different peer received" msgstr "# mensajes PONG encriptados recibidos" #: src/transport/gnunet-service-transport_validation.c:840 #, c-format msgid "" "Not confirming PING with address `%s' since I cannot confirm having this " "address.\n" msgstr "" #: src/transport/gnunet-service-transport_validation.c:924 msgid "# PONGs unicast via reliable transport" msgstr "" #: src/transport/gnunet-service-transport_validation.c:933 msgid "# PONGs multicast to all available addresses" msgstr "" #: src/transport/gnunet-service-transport_validation.c:1055 msgid "# PONGs dropped, no matching pending validation" msgstr "" #: src/transport/gnunet-service-transport_validation.c:1080 msgid "# PONGs dropped, signature expired" msgstr "" #: src/transport/gnunet-service-transport_validation.c:1136 #, fuzzy, c-format msgid "Adding `%s' without addresses for peer `%s'\n" msgstr "Imposible obtener la dirección del par '%s'.\n" #: src/transport/gnunet-transport.c:260 msgid "No transport plugins configured, peer will never communicate\n" msgstr "" #: src/transport/gnunet-transport.c:273 #, c-format msgid "No port configured for plugin `%s', cannot test it\n" msgstr "" #: src/transport/gnunet-transport.c:323 #, c-format msgid "Received %llu bytes/s (%llu bytes in %llu ms)\n" msgstr "" #: src/transport/gnunet-transport.c:330 #, c-format msgid "Transmitted %llu bytes/s (%llu bytes in %llu ms)\n" msgstr "" #: src/transport/gnunet-transport.c:363 #, c-format msgid "Transmitting %u bytes to %s\n" msgstr "" #: src/transport/gnunet-transport.c:383 #, fuzzy, c-format msgid "Connected to %s\n" msgstr "'%s' conectado a '%s'.\n" #: src/transport/gnunet-transport.c:414 #, fuzzy, c-format msgid "Disconnected from %s\n" msgstr "'%s' conectado a '%s'.\n" #: src/transport/gnunet-transport.c:443 #, fuzzy, c-format msgid "Received %u bytes from %s\n" msgstr "GAP recibido contenido no válido de '%s'\n" #: src/transport/gnunet-transport.c:466 #, fuzzy, c-format msgid "Peer `%s': %s %s\n" msgstr "Yo soy el par '%s'.\n" #: src/transport/gnunet-transport.c:473 #, c-format msgid "Peer `%s': %s \n" msgstr "" #: src/transport/gnunet-transport.c:501 #, fuzzy, c-format msgid "Peer `%s' disconnected\n" msgstr "# de pares conectados" #: src/transport/gnunet-transport.c:569 #, fuzzy, c-format msgid "Failed to parse peer identity `%s'\n" msgstr "Falló al actualizar los datos del módulo '%s'\n" #: src/transport/gnunet-transport.c:618 msgid "measure how fast we are receiving data (until CTRL-C)" msgstr "" #: src/transport/gnunet-transport.c:621 #, fuzzy msgid "try to connect to the given peer" msgstr "Fallo al conectar a gnunetd.\n" #: src/transport/gnunet-transport.c:624 #, fuzzy msgid "provide information about all current connections (once)" msgstr "Imprime información de los pares de GNUnet." #: src/transport/gnunet-transport.c:627 #, fuzzy msgid "provide information about all current connections (continuously)" msgstr "Imprime información de los pares de GNUnet." #: src/transport/gnunet-transport.c:630 msgid "do not resolve hostnames" msgstr "" #: src/transport/gnunet-transport.c:634 msgid "send data for benchmarking to the other peer (until CTRL-C)" msgstr "" #: src/transport/gnunet-transport.c:637 msgid "test transport configuration (involves external server)" msgstr "" #: src/transport/gnunet-transport.c:645 #, fuzzy msgid "Direct access to transport service." msgstr "Fallo al conectar a gnunetd.\n" #: src/transport/plugin_transport_http.c:1100 msgid "Disabling IPv6 since it is not supported on this system!\n" msgstr "" #: src/transport/plugin_transport_http.c:1149 #, fuzzy msgid "Require valid port number for service in configuration!\n" msgstr "¡Ninguna aplicación definida en la configuración!\n" #: src/transport/plugin_transport_http.c:1174 src/util/service.c:1036 #, fuzzy, c-format msgid "Failed to resolve `%s': %s\n" msgstr "Fichero almacenado en '%s'.\n" #: src/transport/plugin_transport_http.c:1191 src/util/service.c:1053 #, fuzzy, c-format msgid "Failed to find %saddress for `%s'.\n" msgstr "Fallo al conectar a gnunetd.\n" #: src/transport/plugin_transport_http.c:1296 #, c-format msgid "Found %u addresses to report to NAT service\n" msgstr "" #: src/transport/plugin_transport_http.c:1309 #, c-format msgid "FREEING %s\n" msgstr "" #: src/transport/plugin_transport_http.c:1386 #, fuzzy msgid "Neither IPv4 nor IPv6 are enabled! Fix in configuration\n" msgstr "¡Advertencias de la red desconectadas por configuración!\n" #: src/transport/plugin_transport_http.c:1399 #, fuzzy msgid "Port is required! Fix in configuration\n" msgstr " gconfig\tConfiguración GTK\n" #: src/transport/plugin_transport_http.c:1410 msgid "Port 0, client only mode\n" msgstr "" #: src/transport/plugin_transport_http.c:1430 #, c-format msgid "" "Specific IPv4 address `%s' for plugin %s in configuration file is invalid! " "Binding to all addresses!\n" msgstr "" #: src/transport/plugin_transport_http.c:1460 #, c-format msgid "" "Specific IPv6 address `%s' for plugin %s in configuration file is invalid! " "Binding to all addresses!\n" msgstr "" #: src/transport/plugin_transport_http_client.c:624 #, c-format msgid "Could not initialize curl multi handle, failed to start %s plugin!\n" msgstr "" #: src/transport/plugin_transport_http_server.c:178 msgid "" "Could not create a new TLS certificate, program `gnunet-transport-" "certificate-creation' could not be started!\n" msgstr "" #: src/transport/plugin_transport_http_server.c:202 msgid "No usable TLS certificate found and creating one failed!\n" msgstr "" #: src/transport/plugin_transport_tcp.c:591 #, c-format msgid "Unexpected address length: %u bytes\n" msgstr "" #: src/transport/plugin_transport_tcp.c:767 #: src/transport/plugin_transport_tcp.c:856 #: src/transport/plugin_transport_tcp.c:906 #: src/transport/plugin_transport_tcp.c:992 #: src/transport/plugin_transport_tcp.c:1086 #: src/transport/plugin_transport_tcp.c:1103 #, fuzzy msgid "# bytes currently in TCP buffers" msgstr "# bytes enviados por TCP" #: src/transport/plugin_transport_tcp.c:774 #: src/transport/plugin_transport_tcp.c:963 #: src/transport/plugin_transport_tcp.c:1761 #: src/transport/plugin_transport_tcp.c:2390 #, fuzzy msgid "# TCP sessions active" msgstr "# claves de la sesión aceptadas" #: src/transport/plugin_transport_tcp.c:860 #, fuzzy msgid "# bytes discarded by TCP (timeout)" msgstr "# bytes omitidos por TCP (salientes)" #: src/transport/plugin_transport_tcp.c:909 #, fuzzy msgid "# bytes transmitted via TCP" msgstr "# bytes desencriptados" #: src/transport/plugin_transport_tcp.c:996 #, fuzzy msgid "# bytes discarded by TCP (disconnect)" msgstr "# bytes omitidos por TCP (salientes)" #: src/transport/plugin_transport_tcp.c:1290 #, c-format msgid "Address of unexpected length: %u\n" msgstr "" #: src/transport/plugin_transport_tcp.c:1401 msgid "# transport-service disconnect requests for TCP" msgstr "" #: src/transport/plugin_transport_tcp.c:1802 #, fuzzy msgid "# TCP WELCOME messages received" msgstr "# mensajes PONG encriptados recibidos" #: src/transport/plugin_transport_tcp.c:1973 msgid "# bytes received via TCP" msgstr "# bytes recibidos por TCP" #: src/transport/plugin_transport_tcp.c:2043 msgid "# network-level TCP disconnect events" msgstr "" #: src/transport/plugin_transport_tcp.c:2279 src/util/service.c:940 #, c-format msgid "Require valid port number for service `%s' in configuration!\n" msgstr "" #: src/transport/plugin_transport_tcp.c:2293 #, fuzzy msgid "Failed to start service.\n" msgstr "Falló al comenzar la recolección.\n" #: src/transport/plugin_transport_tcp.c:2355 #, fuzzy, c-format msgid "Failed to find option %s in section %s!\n" msgstr "Fallo al conectar a gnunetd.\n" #: src/transport/plugin_transport_tcp.c:2378 #, c-format msgid "TCP transport listening on port %llu\n" msgstr "" #: src/transport/plugin_transport_tcp.c:2382 msgid "TCP transport not listening on any port (client only)\n" msgstr "" #: src/transport/plugin_transport_tcp.c:2386 #, c-format msgid "TCP transport advertises itself as being on port %llu\n" msgstr "" #: src/transport/plugin_transport_udp_broadcasting.c:128 #, fuzzy msgid "# IPv6 multicast HELLO beacons received via udp" msgstr "# mensajes PONG encriptados recibidos" #: src/transport/plugin_transport_udp_broadcasting.c:169 #, fuzzy msgid "# IPv4 broadcast HELLO beacons received via udp" msgstr "# mensajes PONG encriptados recibidos" #: src/transport/plugin_transport_udp_broadcasting.c:367 #, c-format msgid "Failed to set IPv4 broadcast option for broadcast socket on port %d\n" msgstr "" #: src/transport/plugin_transport_udp.c:1894 #, c-format msgid "" "UDP could not message to `%s': `%s'. Please check your network configuration " "and disable IPv6 if your connection does not have a global IPv6 address\n" msgstr "" #: src/transport/plugin_transport_udp.c:2138 #, fuzzy msgid "Failed to open UDP sockets\n" msgstr "Fichero almacenado en '%s'.\n" #: src/transport/plugin_transport_udp.c:2306 #, c-format msgid "Given `%s' option is out of range: %llu > %u\n" msgstr "" #: src/transport/plugin_transport_udp.c:2349 #, fuzzy, c-format msgid "Invalid IPv6 address: `%s'\n" msgstr "Argumento no válido: '%s'\n" #: src/transport/plugin_transport_unix.c:1356 #, fuzzy msgid "Failed to open UNIX sockets\n" msgstr "Fichero almacenado en '%s'.\n" #: src/transport/plugin_transport_wlan.c:561 msgid "# WLAN ACKs sent" msgstr "" #: src/transport/plugin_transport_wlan.c:580 #, fuzzy msgid "# WLAN messages defragmented" msgstr "# mensajes defragmentados" #: src/transport/plugin_transport_wlan.c:626 #: src/transport/plugin_transport_wlan.c:676 #: src/transport/plugin_transport_wlan.c:1696 #, fuzzy msgid "# WLAN sessions allocated" msgstr "# claves de la sesión aceptadas" #: src/transport/plugin_transport_wlan.c:749 #, fuzzy msgid "# WLAN message fragments sent" msgstr "# mensajes fragmentados" #: src/transport/plugin_transport_wlan.c:767 msgid "# WLAN messages pending (with fragmentation)" msgstr "" #: src/transport/plugin_transport_wlan.c:867 #: src/transport/plugin_transport_wlan.c:948 #: src/transport/plugin_transport_wlan.c:1698 #, fuzzy msgid "# WLAN MAC endpoints allocated" msgstr "# mensajes PONG encriptados recibidos" #: src/transport/plugin_transport_wlan.c:1119 #, fuzzy msgid "# HELLO messages received via WLAN" msgstr "# mensajes PONG encriptados recibidos" #: src/transport/plugin_transport_wlan.c:1140 #, fuzzy msgid "# fragments received via WLAN" msgstr "# fragmentos descartados" #: src/transport/plugin_transport_wlan.c:1150 #, fuzzy msgid "# ACKs received via WLAN" msgstr "# bytes recibidos por TCP" #: src/transport/plugin_transport_wlan.c:1207 #, fuzzy msgid "# WLAN DATA messages discarded due to CRC32 error" msgstr "# mensajes defragmentados" #: src/transport/plugin_transport_wlan.c:1306 #, fuzzy msgid "# DATA messages received via WLAN" msgstr "# mensajes PONG encriptados recibidos" #: src/transport/plugin_transport_wlan.c:1341 #, fuzzy msgid "# WLAN DATA messages processed" msgstr "# mensajes PONG encriptados recibidos" #: src/transport/plugin_transport_wlan.c:1402 #, fuzzy msgid "# HELLO beacons sent via WLAN" msgstr "# bytes enviados vía UDP" #: src/transport/plugin_transport_wlan.c:1511 msgid "WLAN address with invalid size encountered\n" msgstr "" #: src/transport/plugin_transport_wlan.c:1668 #, fuzzy, c-format msgid "Invalid configuration option `%s' in section `%s'\n" msgstr "Fichero de configuración '%s' creado.\n" #: src/transport/plugin_transport_wlan.c:1677 #, c-format msgid "Helper binary `%s' not SUID, cannot run WLAN transport\n" msgstr "" #: src/transport/plugin_transport_wlan.c:1687 #, fuzzy, c-format msgid "Missing configuration option `%s' in section `%s'\n" msgstr "Fichero de configuración '%s' creado.\n" #: src/transport/transport_api.c:570 #, fuzzy, c-format msgid "Received unexpected message of type %u in %s:%u\n" msgstr "Recibido mensaje corrupto del par '%s' en %s:%d.\n" #: src/util/bio.c:136 src/util/bio.c:142 #, fuzzy, c-format msgid "Error reading `%s': %s" msgstr "Error creando usuario" #: src/util/bio.c:143 #, fuzzy msgid "End of file" msgstr "Cargar un fichero de configuración" #: src/util/bio.c:195 #, c-format msgid "Error reading length of string `%s'" msgstr "" #: src/util/bio.c:205 #, c-format msgid "String `%s' longer than allowed (%u > %u)" msgstr "" #: src/util/bio.c:250 #, c-format msgid "Serialized metadata `%s' larger than allowed (%u>%u)" msgstr "" #: src/util/bio.c:264 #, c-format msgid "Metadata `%s' failed to deserialize" msgstr "" #: src/util/client.c:359 #, c-format msgid "" "Could not determine valid hostname and port for service `%s' from " "configuration.\n" msgstr "" #: src/util/client.c:367 #, c-format msgid "Need a non-empty hostname for service `%s'.\n" msgstr "" #: src/util/client.c:685 msgid "Failure to transmit TEST request.\n" msgstr "" #: src/util/client.c:740 src/util/service.c:970 #, c-format msgid "UNIXPATH `%s' too long, maximum length is %llu\n" msgstr "" #: src/util/client.c:882 #, fuzzy, c-format msgid "Could not connect to service `%s', must not be running.\n" msgstr "Imposible conectar con gnunetd.\n" #: src/util/client.c:896 #, fuzzy, c-format msgid "Failure to transmit request to service `%s'\n" msgstr "Falló al mandar la petición HTTP al host '%s': %s\n" #: src/util/client.c:1149 msgid "Could not submit request, not expecting to receive a response.\n" msgstr "" #: src/util/common_logging.c:239 src/util/common_logging.c:890 msgid "DEBUG" msgstr "DEPURACIÓN" #: src/util/common_logging.c:241 src/util/common_logging.c:888 msgid "INFO" msgstr "INFORMACIÓN" #: src/util/common_logging.c:243 src/util/common_logging.c:886 msgid "WARNING" msgstr "PELIGRO" #: src/util/common_logging.c:245 src/util/common_logging.c:884 msgid "ERROR" msgstr "ERROR" #: src/util/common_logging.c:247 src/util/common_logging.c:892 msgid "NONE" msgstr "" #: src/util/common_logging.c:610 #, fuzzy, c-format msgid "Failed to create or access directory for log file `%s'\n" msgstr "Imposible pasar el fichero de configuración '%s'.\n" #: src/util/common_logging.c:725 #, c-format msgid "Message `%.*s' repeated %u times in the last %s\n" msgstr "" #: src/util/common_logging.c:893 msgid "INVALID" msgstr "" #: src/util/common_logging.c:992 #, fuzzy msgid "unknown address" msgstr "desconocido" #: src/util/common_logging.c:1030 #, fuzzy msgid "invalid address" msgstr "Argumentos inválidos: " #: src/util/configuration.c:244 #, fuzzy, c-format msgid "Syntax error in configuration file `%s' at line %u.\n" msgstr "" "Error de sintaxis en el fichero de configuración '%s' en la linea %d.\n" #: src/util/configuration.c:816 #, c-format msgid "" "Configuration value '%s' for '%s' in section '%s' is not in set of legal " "choices\n" msgstr "" #: src/util/connection.c:420 #, fuzzy, c-format msgid "Access denied to `%s'\n" msgstr "Permiso denegado para '%s' en %s:%d.\n" #: src/util/connection.c:435 #, c-format msgid "Accepting connection from `%s': %p\n" msgstr "" #: src/util/connection.c:550 #, fuzzy, c-format msgid "" "Failed to establish TCP connection to `%s:%u', no further addresses to try.\n" msgstr "Se produjo un error estableciendo conexión con gnunetd.\n" #: src/util/connection.c:739 src/util/connection.c:909 #, fuzzy, c-format msgid "Trying to connect to `%s' (%p)\n" msgstr "Fallo al conectar a gnunetd.\n" #: src/util/connection.c:748 #, fuzzy, c-format msgid "Failed to connect to `%s' (%p)\n" msgstr "Fallo al conectar a gnunetd.\n" #: src/util/connection.c:900 #, fuzzy, c-format msgid "Attempt to connect to `%s' failed\n" msgstr "Fallo al conectar a gnunetd.\n" #: src/util/container_bloomfilter.c:510 #, c-format msgid "" "Size of file on disk is incorrect for this Bloom filter (want %llu, have " "%llu)\n" msgstr "" #: src/util/crypto_random.c:280 #, c-format msgid "Starting `%s' process to generate entropy\n" msgstr "" #: src/util/crypto_random.c:309 #, c-format msgid "libgcrypt has not the expected version (version %s is required).\n" msgstr "" "libgcrypt no está en la versión esperada (se necesita la versión %s).\n" #: src/util/crypto_rsa.c:661 src/util/crypto_rsa.c:708 #, fuzzy, c-format msgid "Could not aquire lock on file `%s': %s...\n" msgstr "Imposible escribir PID al fichero '%s': %s.\n" #: src/util/crypto_rsa.c:666 #, fuzzy msgid "Creating a new private key. This may take a while.\n" msgstr "Creando nueva clave local (esto puede llevar un tiempo).\n" #: src/util/crypto_rsa.c:684 #, c-format msgid "I am host `%s'. Stored new private key in `%s'.\n" msgstr "" #: src/util/crypto_rsa.c:712 src/util/crypto_rsa.c:748 msgid "This may be ok if someone is currently generating a hostkey.\n" msgstr "" #: src/util/crypto_rsa.c:743 #, c-format msgid "" "When trying to read hostkey file `%s' I found %u bytes but I need at least " "%u.\n" msgstr "" #: src/util/crypto_rsa.c:763 #, fuzzy, c-format msgid "File `%s' does not contain a valid private key. Deleting it.\n" msgstr "El fichero '%s' no contiene un pseudónimo.\n" #: src/util/crypto_rsa.c:781 #, fuzzy, c-format msgid "I am host `%s'. Read private key from `%s'.\n" msgstr "Llamada a '%s' con la clave '%s'.\n" #: src/util/crypto_rsa.c:1032 #, c-format msgid "RSA signature verification failed at %s:%d: %s\n" msgstr "La verificación de la firma RSA fallo en %s: %d: %s\n" #: src/util/disk.c:498 #, fuzzy, c-format msgid "`%s' failed for drive `%S': %u\n" msgstr "'%s' falló para la unidad %s: %u\n" #: src/util/disk.c:1062 #, fuzzy, c-format msgid "Expected `%s' to be a directory!\n" msgstr "¡'%s' se esperaba que '%s' fuera un directorio!\n" #: src/util/disk.c:1416 src/util/service.c:1650 #, fuzzy, c-format msgid "Cannot obtain information about user `%s': %s\n" msgstr "Imposible guardar el fichero de configuración '%s': %s.\n" #: src/util/disk.c:1734 #, fuzzy, c-format msgid "No `%s' specified for service `%s' in configuration.\n" msgstr "¡Ninguna aplicación definida en la configuración!\n" #: src/util/getopt.c:669 #, c-format msgid "%s: option `%s' is ambiguous\n" msgstr "%s: la opción '%s' es ambigua\n" #: src/util/getopt.c:693 #, c-format msgid "%s: option `--%s' does not allow an argument\n" msgstr "%s: la opción '--%s' no permite un argumento\n" #: src/util/getopt.c:698 #, c-format msgid "%s: option `%c%s' does not allow an argument\n" msgstr "%s: la opción '%c%s' no permite un argumento\n" #: src/util/getopt.c:715 src/util/getopt.c:883 #, c-format msgid "%s: option `%s' requires an argument\n" msgstr "%s: la opción '%s' requiere un argumento\n" #: src/util/getopt.c:744 #, c-format msgid "%s: unrecognized option `--%s'\n" msgstr "%s: opción no reconocida '--%s'\n" #: src/util/getopt.c:748 #, c-format msgid "%s: unrecognized option `%c%s'\n" msgstr "%s: opción no reconocida '%c%s'\n" #: src/util/getopt.c:773 #, c-format msgid "%s: illegal option -- %c\n" msgstr "%s: opción ilegal -- %c\n" #: src/util/getopt.c:775 #, c-format msgid "%s: invalid option -- %c\n" msgstr "%s: opción no válida -- %c\n" #: src/util/getopt.c:803 src/util/getopt.c:931 #, c-format msgid "%s: option requires an argument -- %c\n" msgstr "%s: la opción requiere un argumento --%c\n" #: src/util/getopt.c:851 #, c-format msgid "%s: option `-W %s' is ambiguous\n" msgstr "%s: la opción '-W %s' es ambigua\n" #: src/util/getopt.c:869 #, c-format msgid "%s: option `-W %s' does not allow an argument\n" msgstr "%s: la opción '-W %s' no permite un argumento\n" #: src/util/getopt.c:1035 #, fuzzy, c-format msgid "Use %s to get a list of options.\n" msgstr "Usar --help para obtener una lista de opciones.\n" #: src/util/getopt_helpers.c:86 #, c-format msgid "" "Arguments mandatory for long options are also mandatory for short options.\n" msgstr "" #: src/util/getopt_helpers.c:258 src/util/getopt_helpers.c:286 #, c-format msgid "You must pass a number to the `%s' option.\n" msgstr "Tienes que introducir un número en la opción '%s'.\n" #: src/util/gnunet-resolver.c:148 msgid "perform a reverse lookup" msgstr "" #: src/util/gnunet-resolver.c:154 msgid "Use build-in GNUnet stub resolver" msgstr "" #: src/util/gnunet-rsa.c:64 #, c-format msgid "No hostkey file specified on command line\n" msgstr "" #: src/util/gnunet-rsa.c:112 msgid "print the public key in ASCII format" msgstr "" #: src/util/gnunet-rsa.c:115 msgid "print the hash of the public key in ASCII format" msgstr "" #: src/util/gnunet-rsa.c:118 msgid "print the short hash of the public key in ASCII format" msgstr "" #: src/util/gnunet-rsa.c:124 msgid "Manipulate GNUnet private RSA key files" msgstr "" #: src/util/gnunet-service-resolver.c:288 #, fuzzy, c-format msgid "Could not resolve `%s' (%s): %s\n" msgstr "Imposible resolver '%s': %s\n" #: src/util/gnunet-service-resolver.c:358 #: src/util/gnunet-service-resolver.c:399 #, c-format msgid "Could not find IP of host `%s': %s\n" msgstr "Imposible encontrar la IP del host '%s': %s\n" #: src/util/helper.c:244 #, fuzzy, c-format msgid "Error reading from `%s': %s\n" msgstr "Error creando usuario" #: src/util/helper.c:259 #, c-format msgid "Got 0 bytes from helper `%s' (EOF)\n" msgstr "" #: src/util/helper.c:269 #, fuzzy, c-format msgid "Got %u bytes from helper `%s'\n" msgstr "GAP recibido contenido no válido de '%s'\n" #: src/util/helper.c:278 #, fuzzy, c-format msgid "Failed to parse inbound message from helper `%s'\n" msgstr "Falló al pasar los datos de la interfaz de '%s' de %s:%d.\n" #: src/util/helper.c:310 #, fuzzy, c-format msgid "Starting HELPER process `%s'\n" msgstr "Iniciada colección '%s'.\n" #: src/util/helper.c:440 #, fuzzy, c-format msgid "Error writing to `%s': %s\n" msgstr "Error creando usuario" #: src/util/network.c:1200 #, c-format msgid "" "Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n" msgstr "" #: src/util/os_installation.c:299 #, c-format msgid "" "Could not determine installation path for %s. Set `%s' environment " "variable.\n" msgstr "" #: src/util/os_installation.c:486 #, fuzzy, c-format msgid "Could not find binary `%s' in PATH!\n" msgstr "¡Imposible encontrar el par '%s' en la tabla de enrutado!\n" #: src/util/os_installation.c:492 #, fuzzy, c-format msgid "access (%s, X_OK) failed: %s\n" msgstr "'%s' %s falló: %s\n" #: src/util/os_installation.c:507 #, fuzzy, c-format msgid "stat (%s) failed: %s\n" msgstr "'%s' %s falló: %s\n" #: src/util/os_priority.c:305 #, fuzzy, c-format msgid "Failed to open named pipe `%s' for reading: %s\n" msgstr "Fichero almacenado en '%s'.\n" #: src/util/os_priority.c:306 #, fuzzy, c-format msgid "Failed to open named pipe `%s' for writing: %s\n" msgstr "Fichero almacenado en '%s'.\n" #: src/util/plugin.c:89 #, c-format msgid "Initialization of plugin mechanism failed: %s!\n" msgstr "¡El mecanismo de iniciación de los plugins falló: %s!\n" #: src/util/plugin.c:146 #, fuzzy, c-format msgid "`%s' failed to resolve method '%s' with error: %s\n" msgstr "'%s' falló al resolver el método '%s%s' en %s:%d con un error: %s\n" #: src/util/plugin.c:219 #, fuzzy, c-format msgid "`%s' failed for library `%s' with error: %s\n" msgstr "'%s' falló en la biblioteca '%s' en %s:%d con un error: %s\n" #: src/util/plugin.c:349 #, fuzzy msgid "Could not determine plugin installation path.\n" msgstr "Imposible determinar mi dirección IPv6 pública.\n" #: src/util/pseudonym.c:276 #, fuzzy, c-format msgid "Failed to parse metadata about pseudonym from file `%s': %s\n" msgstr "Falló al pasar los datos de la interfaz de '%s' de %s:%d.\n" #: src/util/pseudonym.c:407 src/util/pseudonym.c:433 #, fuzzy msgid "no-name" msgstr "Mostrar el nombre" #: src/util/resolver_api.c:202 #, fuzzy, c-format msgid "Must specify `%s' for `%s' in configuration!\n" msgstr "Intentando usar el fichero '%s' para la configuración de MySQL.\n" #: src/util/resolver_api.c:221 #, fuzzy, c-format msgid "" "Must specify `%s' or numeric IP address for `%s' of `%s' in configuration!\n" msgstr "" "Debes especificar un número positivo para '%s' en la configuración en la " "sección '%s'.\n" #: src/util/resolver_api.c:347 #, fuzzy, c-format msgid "Timeout trying to resolve IP address `%s'.\n" msgstr "GNUnet usa ahora la dirección IP %u.%u.%u.%u.\n" #: src/util/resolver_api.c:351 #, c-format msgid "Timeout trying to resolve hostname `%s'.\n" msgstr "" #: src/util/resolver_api.c:890 #, fuzzy, c-format msgid "Could not resolve our FQDN : %s\n" msgstr "Imposible resolver '%s': %s\n" #: src/util/scheduler.c:786 msgid "Looks like we're busy waiting...\n" msgstr "" #: src/util/scheduler.c:916 #, c-format msgid "Attempt to cancel dead task %llu!\n" msgstr "" #: src/util/server.c:483 #, fuzzy, c-format msgid "`%s' failed for port %d (%s).\n" msgstr "'%s' falló para la unidad %s: %u\n" #: src/util/server.c:492 #, fuzzy, c-format msgid "`%s' failed for port %d (%s): address already in use\n" msgstr "" "'%s' falló para el puerto %d: %s. ¿Está gnunet ejecutandose actualmente?\n" #: src/util/server.c:497 #, fuzzy, c-format msgid "`%s' failed for `%s': address already in use\n" msgstr "" "'%s' falló para el puerto %d: %s. ¿Está gnunet ejecutandose actualmente?\n" #: src/util/server.c:827 #, c-format msgid "" "Processing code for message of type %u did not call " "GNUNET_SERVER_receive_done after %llums\n" msgstr "" #: src/util/service.c:135 src/util/service.c:161 src/util/service.c:204 #: src/util/service.c:225 src/util/service.c:232 #, c-format msgid "Invalid format for IP: `%s'\n" msgstr "Formato no válido para la IP: '%s'\n" #: src/util/service.c:188 #, c-format msgid "Invalid network notation ('/%d' is not legal in IPv4 CIDR)." msgstr "Notación de red no válida ('/%d' no es válido en IPv4 CIDR)." #: src/util/service.c:281 #, c-format msgid "Invalid network notation (does not end with ';': `%s')\n" msgstr "Notación de red no válida (no termina con ';': '%s')\n" #: src/util/service.c:313 #, fuzzy, c-format msgid "Wrong format `%s' for netmask\n" msgstr "Formato '%s' erróneo para la máscara de red: %s\n" #: src/util/service.c:343 #, fuzzy, c-format msgid "Wrong format `%s' for network\n" msgstr "Formato '%s' erróneo para la red: %s\n" #: src/util/service.c:698 #, c-format msgid "Access denied to UID %d / GID %d\n" msgstr "" #: src/util/service.c:703 #, fuzzy, c-format msgid "Unknown address family %d\n" msgstr "Operación desconocida '%s'\n" #: src/util/service.c:710 #, c-format msgid "Access from `%s' denied to service `%s'\n" msgstr "" #: src/util/service.c:765 #, c-format msgid "Could not parse IPv4 network specification `%s' for `%s:%s'\n" msgstr "" #: src/util/service.c:802 #, c-format msgid "Could not parse IPv6 network specification `%s' for `%s:%s'\n" msgstr "" #: src/util/service.c:920 #, c-format msgid "" "Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n" msgstr "" #: src/util/service.c:990 #, c-format msgid "" "Disabling UNIX domain socket support for service `%s', failed to create UNIX " "domain socket: %s\n" msgstr "" #: src/util/service.c:1007 #, c-format msgid "Have neither PORT nor UNIXPATH for service `%s', but one is required\n" msgstr "" #: src/util/service.c:1241 msgid "Could not access a pre-bound socket, will try to bind myself\n" msgstr "" #: src/util/service.c:1292 src/util/service.c:1310 #, c-format msgid "Specified value for `%s' of service `%s' is invalid\n" msgstr "" #: src/util/service.c:1337 #, c-format msgid "Could not access pre-bound socket %u, will try to bind myself\n" msgstr "" #: src/util/service.c:1506 #, fuzzy, c-format msgid "Failed to start `%s' at `%s'\n" msgstr "Fallo al conectar a gnunetd.\n" #: src/util/service.c:1539 #, fuzzy, c-format msgid "Service `%s' runs at %s\n" msgstr "Par '%s' con credibilidad %8u y dirección '%s'\n" #: src/util/service.c:1588 msgid "Service process failed to initialize\n" msgstr "" #: src/util/service.c:1592 msgid "Service process could not initialize server function\n" msgstr "" #: src/util/service.c:1596 msgid "Service process failed to report status\n" msgstr "" #: src/util/service.c:1651 msgid "No such user" msgstr "" #: src/util/service.c:1664 #, c-format msgid "Cannot change user/group to `%s': %s\n" msgstr "Imposible cambiar el usuario/grupo a '%s': %s\n" #: src/util/service.c:1729 msgid "do daemonize (detach from terminal)" msgstr "" #: src/util/signal.c:80 #, fuzzy, c-format msgid "signal (%d, %p) returned %d.\n" msgstr "La llamada a '%s' devuelve %d.\n" #: src/util/strings.c:144 msgid "b" msgstr "b" #: src/util/strings.c:334 #, c-format msgid "Character sets requested were `%s'->`%s'\n" msgstr "" #: src/util/strings.c:481 msgid "Failed to expand `$HOME': environment variable `HOME' not set" msgstr "" #: src/util/strings.c:573 msgid "ms" msgstr "ms" #: src/util/strings.c:578 msgid "eternity" msgstr "" #: src/util/strings.c:582 msgid "s" msgstr "s" #: src/util/strings.c:586 msgid "m" msgstr "m" #: src/util/strings.c:590 msgid "h" msgstr "h" #: src/util/strings.c:594 msgid " days" msgstr " días" #: src/util/strings.c:618 msgid "end of time" msgstr "" #: src/util/strings.c:1012 msgid "IPv6 address did not start with `['\n" msgstr "" #: src/util/strings.c:1020 msgid "IPv6 address did contain ':' to separate port number\n" msgstr "" #: src/util/strings.c:1026 msgid "IPv6 address did contain ']' before ':' to separate port number\n" msgstr "" #: src/util/strings.c:1033 msgid "IPv6 address did contain a valid port number after the last ':'\n" msgstr "" #: src/util/strings.c:1042 #, fuzzy, c-format msgid "Invalid IPv6 address `%s': %s\n" msgstr "Argumento no válido: '%s'\n" #: src/vpn/gnunet-service-vpn.c:511 src/vpn/gnunet-service-vpn.c:1071 #, fuzzy msgid "# Active tunnels" msgstr "Configuración de GNUnet" #: src/vpn/gnunet-service-vpn.c:608 src/vpn/gnunet-service-vpn.c:645 #, fuzzy msgid "# peers connected to mesh tunnels" msgstr "# de pares conectados" #: src/vpn/gnunet-service-vpn.c:699 #, fuzzy msgid "# Bytes given to mesh for transmission" msgstr "# bytes de mensajes salientes omitidos" #: src/vpn/gnunet-service-vpn.c:737 #, fuzzy msgid "# Bytes dropped in mesh queue (overflow)" msgstr "# bytes omitidos por UDP (salientes)" #: src/vpn/gnunet-service-vpn.c:772 #, fuzzy msgid "# Mesh tunnels created" msgstr "# mensajes PONG encriptados recibidos" #: src/vpn/gnunet-service-vpn.c:795 #, fuzzy msgid "Failed to setup mesh tunnel!\n" msgstr "Fallo en las estadísticas del tráfico.\n" #: src/vpn/gnunet-service-vpn.c:973 #, c-format msgid "Protocol %u not supported, dropping\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1291 msgid "# ICMPv4 packets dropped (not allowed)" msgstr "" #: src/vpn/gnunet-service-vpn.c:1312 msgid "# ICMPv6 packets dropped (not allowed)" msgstr "" #: src/vpn/gnunet-service-vpn.c:1517 #, fuzzy msgid "# Packets received from TUN interface" msgstr "El mensaje recibido del cliente es inválido\n" #: src/vpn/gnunet-service-vpn.c:1555 src/vpn/gnunet-service-vpn.c:1596 #, c-format msgid "Packet received for unmapped destination `%s' (dropping it)\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1606 msgid "Received IPv4 packet with options (dropping it)\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1620 #, c-format msgid "Received packet of unknown protocol %d from TUN (dropping it)\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:1704 #, fuzzy msgid "# ICMP packets received from mesh" msgstr "El mensaje recibido del cliente es inválido\n" #: src/vpn/gnunet-service-vpn.c:2045 #, fuzzy msgid "# UDP packets received from mesh" msgstr "El mensaje recibido del cliente es inválido\n" #: src/vpn/gnunet-service-vpn.c:2203 #, fuzzy msgid "# TCP packets received from mesh" msgstr "El mensaje recibido del cliente es inválido\n" #: src/vpn/gnunet-service-vpn.c:2354 msgid "Failed to find unallocated IPv4 address in VPN's range\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:2409 #, fuzzy msgid "Failed to find unallocated IPv6 address in VPN's range\n" msgstr "¡Falló al obtener mi dirección IPv6 (externa)!\n" #: src/vpn/gnunet-service-vpn.c:2448 src/vpn/gnunet-service-vpn.c:2661 #, fuzzy msgid "# Active destinations" msgstr "Configuración de GNUnet" #: src/vpn/gnunet-service-vpn.c:2734 msgid "Failed to allocate IP address for new destination\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:3141 msgid "IPv6 support disabled as this system does not support IPv6\n" msgstr "" #: src/vpn/gnunet-service-vpn.c:3173 msgid "IPv4 support disabled as this system does not support IPv4\n" msgstr "" #: src/vpn/gnunet-vpn.c:151 #, fuzzy msgid "Error creating tunnel\n" msgstr "Correcto al crear la clave local.\n" #: src/vpn/gnunet-vpn.c:195 src/vpn/gnunet-vpn.c:226 #, fuzzy, c-format msgid "Option `%s' makes no sense with option `%s'.\n" msgstr "La opción '%s' no tiene sentido sin la opción '%s'.\n" #: src/vpn/gnunet-vpn.c:208 #, fuzzy, c-format msgid "Option `%s' or `%s' is required.\n" msgstr "%s: la opción '%s' es ambigua\n" #: src/vpn/gnunet-vpn.c:220 #, fuzzy, c-format msgid "Option `%s' or `%s' is required when using option `%s'.\n" msgstr "La opción '%s' no tiene sentido sin la opción '%s'.\n" #: src/vpn/gnunet-vpn.c:238 #, fuzzy, c-format msgid "`%s' is not a valid peer identifier.\n" msgstr "'%s' no esta disponible." #: src/vpn/gnunet-vpn.c:260 #, fuzzy, c-format msgid "`%s' is not a valid IP address.\n" msgstr "'%s' no esta disponible." #: src/vpn/gnunet-vpn.c:296 msgid "request that result should be an IPv4 address" msgstr "" #: src/vpn/gnunet-vpn.c:299 msgid "request that result should be an IPv6 address" msgstr "" #: src/vpn/gnunet-vpn.c:302 msgid "print IP address only after mesh tunnel has been created" msgstr "" #: src/vpn/gnunet-vpn.c:305 msgid "how long should the mapping be valid for new tunnels?" msgstr "" #: src/vpn/gnunet-vpn.c:308 msgid "destination IP for the tunnel" msgstr "" #: src/vpn/gnunet-vpn.c:311 msgid "peer offering the service we would like to access" msgstr "" #: src/vpn/gnunet-vpn.c:314 msgid "name of the service we would like to access" msgstr "" #: src/vpn/gnunet-vpn.c:317 #, fuzzy msgid "service is offered via TCP" msgstr "# bytes recibidos por TCP" #: src/vpn/gnunet-vpn.c:320 #, fuzzy msgid "service is offered via UDP" msgstr "# bytes recibidos vía UDP" #: src/vpn/gnunet-vpn.c:329 msgid "Setup tunnels via VPN." msgstr "" #: src/include/gnunet_common.h:497 src/include/gnunet_common.h:502 #: src/include/gnunet_common.h:508 #, fuzzy, c-format msgid "Assertion failed at %s:%d.\n" msgstr "La verificación de la firma RSA fallo en %s: %d: %s\n" #: src/include/gnunet_common.h:518 #, fuzzy, c-format msgid "External protocol violation detected at %s:%d.\n" msgstr "La verificación de la firma RSA fallo en %s: %d: %s\n" #: src/include/gnunet_common.h:539 src/include/gnunet_common.h:546 #, fuzzy, c-format msgid "`%s' failed on file `%s' at %s:%d with error: %s\n" msgstr "'%s' falló en el fichero '%s' en %s: %d con el error: %s\n" #, fuzzy #~ msgid "Received malformed message via %s. Ignored.\n" #~ msgstr "Recibido el mensaje '%s' con un mal formato. Omitiendo.\n" #, fuzzy #~ msgid "SMTP: `%s' failed: %s.\n" #~ msgstr "'%s' %s falló: %s\n" #, fuzzy #~ msgid "# bytes received via SMTP" #~ msgstr "# bytes recibidos por TCP" #, fuzzy #~ msgid "# bytes sent via SMTP" #~ msgstr "# bytes enviados por TCP" #, fuzzy #~ msgid "# bytes dropped by SMTP (outgoing)" #~ msgstr "# bytes omitidos por TCP (salientes)" #, fuzzy #~ msgid "# Peers connected" #~ msgstr "# de pares conectados" #, fuzzy #~ msgid "%s failed for `%s' at %s:%d: `%s'\n" #~ msgstr "'%s' falló en %s: %d con error: '%s'.\n" #, fuzzy #~ msgid "Failed to transmit shutdown ACK.\n" #~ msgstr "Falló al comenzar la recolección.\n" #, fuzzy #~ msgid "Unable to initialize Postgres with configuration `%s': %s" #~ msgstr "Imposible guardar el fichero de configuración '%s':" #, fuzzy #~ msgid "Failed to transmit message to `%s' service.\n" #~ msgstr "Falló al inicializar el servicio '%s'.\n" #, fuzzy #~ msgid "Target is %d connections per peer." #~ msgstr "Se produjo un error estableciendo conexión con gnunetd.\n" #, fuzzy #~ msgid "Copying file with RENAME (%s,%s)\n" #~ msgstr "'%s' falló con el código de error %s: %s" #, fuzzy #~ msgid "Copying file with command scp %s %s\n" #~ msgstr "'%s' falló con el código de error %s: %s" #, fuzzy #~ msgid "Finished copying all blacklist files!\n" #~ msgstr "Imposible inicializar la aplicación '%s'\n" #, fuzzy #~ msgid "Offering HELLO of peer %s to peer %s\n" #~ msgstr "Imposible conectar a %u.%u.%u.%u:%u: %s\n" #, fuzzy #~ msgid "Failed during blacklist file copying!\n" #~ msgstr "Falló al pasar los datos de la interfaz de '%s' de %s:%d.\n" #, fuzzy #~ msgid "# bytes payload received for other peers" #~ msgstr "# bytes recibidos por TCP" #, fuzzy #~ msgid "# fast reconnects failed" #~ msgstr "# de pares conectados" #, fuzzy #~ msgid "# peers disconnected due to timeout" #~ msgstr "# de pares conectados" #, fuzzy #~ msgid "# peers disconnected due to global disconnect" #~ msgstr "# Anuncios de los pares recibidos" #, fuzzy #~ msgid "# messages not sent (no such peer or not connected)" #~ msgstr "# mensajes defragmentados" #, fuzzy #~ msgid "# unexpected CONNECT_ACK messages" #~ msgstr "envia COUNT mensajes" #, fuzzy #~ msgid "# wlan session timeouts" #~ msgstr "# claves de la sesión aceptadas" #, fuzzy #~ msgid "# wlan session created" #~ msgstr "# claves de la sesión aceptadas" #, fuzzy #~ msgid "# wlan pending fragments" #~ msgstr "# fragmentos descartados" #, fuzzy #~ msgid "# wlan fragments send" #~ msgstr "# fragmentos descartados" #, fuzzy #~ msgid "# wlan whole messages received" #~ msgstr "# mensajes PONG encriptados recibidos" #, fuzzy #~ msgid "# wlan hello messages received" #~ msgstr "# mensajes PONG encriptados recibidos" #, fuzzy #~ msgid "# wlan fragments received" #~ msgstr "# fragmentos descartados" #, fuzzy #~ msgid "# wlan acks received" #~ msgstr "# mensajes PONG encriptados recibidos" #, fuzzy #~ msgid "# wlan messages for this client received" #~ msgstr "# mensajes PONG encriptados recibidos" #, fuzzy #~ msgid "# wlan messages inside WLAN_HELPER_DATA received" #~ msgstr "# mensajes PONG encriptados recibidos" #, fuzzy #~ msgid "Unknown user `%s'\n" #~ msgstr "Operación desconocida '%s'\n" #, fuzzy #~ msgid "Namespace `%s' unknown.\n" #~ msgstr "El espacio '%s' ha sido valorado con un %d.\n" #, fuzzy #~ msgid "Failed to connect to statistics service!\n" #~ msgstr "Fallo al conectar a gnunetd.\n" #, fuzzy #~ msgid "Failed to send to `%s': %s\n" #~ msgstr "Fichero almacenado en '%s'.\n" #, fuzzy #~ msgid "Could not access file: %s\n" #~ msgstr "Imposible ejecutar '%s': %s\n" #, fuzzy #~ msgid "`%s' failed on file `%s': %s" #~ msgstr "'%s' falló para la unidad %s: %u\n" #, fuzzy #~ msgid "# bytes TCP was asked to transmit" #~ msgstr "# bytes desencriptados" #, fuzzy #~ msgid "# bytes discarded by TCP (failed to connect)" #~ msgstr "# bytes omitidos por TCP (salientes)" #, fuzzy #~ msgid "# wlan messages queued" #~ msgstr "# mensajes PONG encriptados recibidos" #~ msgid "print this help" #~ msgstr "imprime esta ayuda" #~ msgid "print the version number" #~ msgstr "imprime el número de versión" #, fuzzy #~ msgid "use configuration file FILENAME" #~ msgstr "usa el fichero de configuración FILENAME" #, fuzzy #~ msgid "Failed to stop service `%s'!\n" #~ msgstr "Fichero almacenado en '%s'.\n" #, fuzzy #~ msgid "Failed to start service `%s'!\n" #~ msgstr "Falló al comenzar la recolección.\n" #, fuzzy #~ msgid "Service `%s' is not running.\n" #~ msgstr "'%s' no es un fichero.\n" #, fuzzy #~ msgid "Binary implementing service `%s' not known!\n" #~ msgstr "La verificación de la firma falló: el par '%s' no es conocido.\n" #, fuzzy #~ msgid "Service `%s' stopped\n" #~ msgstr "Servicio eliminado.\n" #, fuzzy #~ msgid "Unable to start service `%s': %s\n" #~ msgstr "Imposible guardar el fichero de configuración '%s':" #, fuzzy #~ msgid "Unable to accept connection for service `%s': %s\n" #~ msgstr "Imposible guardar el fichero de configuración '%s':" #, fuzzy #~ msgid "Peer `%s' plugin: `%s' address `%s'\n" #~ msgstr "Par '%s' con credibilidad %8u y dirección '%s'\n" #~ msgid "KiB" #~ msgstr "KiB" #~ msgid "MiB" #~ msgstr "MiB" #~ msgid "GiB" #~ msgstr "GiB" #~ msgid "TiB" #~ msgstr "TiB" #, fuzzy #~ msgid "Failed to create IPv4 broadcast socket on port %d\n" #~ msgstr "Falló al actualizar los datos del módulo '%s'\n" #, fuzzy #~ msgid "Failed to load block plugin `%s'\n" #~ msgstr "Imposible inicializar la aplicación '%s'\n" #, fuzzy #~ msgid "Could not resolve our FQDN : %s %u\n" #~ msgstr "Imposible resolver '%s': %s\n" #, fuzzy #~ msgid "Failed to load dhtlog plugin for `%s'\n" #~ msgstr "Imposible inicializar la aplicación '%s'\n" #, fuzzy #~ msgid "Found peer `%s'\n" #~ msgstr "Yo soy el par '%s'.\n" #, fuzzy #~ msgid "Failed to initialize MySQL database connection for dhtlog.\n" #~ msgstr "Imposible inicializar SQLite.\n" #, fuzzy #~ msgid "Loading udp transport plugin\n" #~ msgstr "Probando transporte(s) %s\n" #, fuzzy #~ msgid "# SET QUOTA messages received" #~ msgstr "# mensajes PONG encriptados recibidos" #, fuzzy #~ msgid "curl failed for `%s' at %s:%d: `%s'\n" #~ msgstr "'%s' falló en %s: %d con error: '%s'.\n" #, fuzzy #~ msgid "Phase 3: sending messages\n" #~ msgstr "Falló al entregar el mensaje '%s'.\n" #, fuzzy #~ msgid "Loading HTTPS transport plugin `%s'\n" #~ msgstr "Probando transporte(s) %s\n" #, fuzzy #~ msgid "Failed to load transport plugin for https\n" #~ msgstr "Imposible inicializar la aplicación '%s'\n" #, fuzzy #~ msgid "Fail! Could not connect peers\n" #~ msgstr "'%s': Imposible conectar.\n" #, fuzzy #~ msgid "Loading tcp transport plugin\n" #~ msgstr "Probando transporte(s) %s\n" #, fuzzy #~ msgid "Failed to load transport plugin for tcp\n" #~ msgstr "Imposible inicializar la aplicación '%s'\n" #, fuzzy #~ msgid "# HTTP peers active" #~ msgstr "# bytes recibidos por TCP" #, fuzzy #~ msgid "Connection: %X: %s failed at %s:%d: `%s'\n" #~ msgstr "'%s' falló en %s: %d con error: '%s'.\n" #, fuzzy #~ msgid "Misconfigured address to bind to in configuration!\n" #~ msgstr "¡Ninguna aplicación definida en la configuración!\n" #, fuzzy #~ msgid "Failed to load transport plugin for http\n" #~ msgstr "Imposible inicializar la aplicación '%s'\n" #, fuzzy #~ msgid "# PING messages decrypted" #~ msgstr "# mensajes defragmentados" #, fuzzy #~ msgid "Failed to connect to core service\n" #~ msgstr "Fallo al conectar a gnunetd.\n" #, fuzzy #~ msgid "# bytes successfully transmitted by plugins" #~ msgstr "# bytes desencriptados" #, fuzzy #~ msgid "# transport failed to selected peer address" #~ msgstr "Anunciando mi transporte %d a los pares seleccionados.\n" #, fuzzy #~ msgid "# peer addresses considered valid" #~ msgstr "# Anuncios de los pares recibidos" #, fuzzy #~ msgid "# PING with HELLO messages sent" #~ msgstr "# mensajes de texto mandados por PING" #, fuzzy #~ msgid "# HELLOs received for validation" #~ msgstr "# blocks migrados" #, fuzzy #~ msgid "Received `%s' message from `%s' destined for `%s' which is not me!\n" #~ msgstr "¡Recibido PING no destinado a nosotros!\n" #, fuzzy #~ msgid "Could not send PONG to `%s': no address available\n" #~ msgstr "¡Imposible encontrar el par '%s' en la tabla de enrutado!\n" #, fuzzy #~ msgid "# HELLO messages received from other peers" #~ msgstr "Mensaje '%s' inválido recibido del par '%s'.\n" #~ msgid "Error" #~ msgstr "Error" #~ msgid "Help" #~ msgstr "Ayuda" #~ msgid "Error!" #~ msgstr "¡Error!" #~ msgid "No" #~ msgstr "No" #~ msgid "Yes" #~ msgstr "Sí" #, fuzzy #~ msgid "Abort" #~ msgstr "_Acerca de" #, fuzzy #~ msgid "Ok" #~ msgstr "k" #~ msgid "" #~ "Welcome to GNUnet!\n" #~ "\n" #~ "This assistant will ask you a few basic questions in order to configure " #~ "GNUnet.\n" #~ "\n" #~ "Please visit our homepage at\n" #~ "\thttp://gnunet.org/\n" #~ "and join our community at\n" #~ "\thttp://gnunet.org/drupal/\n" #~ "\n" #~ "Have a lot of fun,\n" #~ "\n" #~ "the GNUnet team" #~ msgstr "" #~ "¡Bienvenido a GNUnet!\n" #~ "\n" #~ "Este asistente te preguntará unas cuestiones básicas para configurar " #~ "GNUnet.\n" #~ "\n" #~ "Por favor, visita nuestra página en\n" #~ "\thttp://gnunet.org/\n" #~ "y únete a nuestra comunidad en \n" #~ "\thttp://gnunet.org/drupal/\n" #~ "\n" #~ "Diviertete,\n" #~ "\n" #~ "el equipo de GNUnet" #~ msgid "" #~ "Choose the network interface that connects your computer to the internet " #~ "from the list below." #~ msgstr "" #~ "Escoge la interfaz de red que conecta tu ordenador a Internet de la lista " #~ "de abajo." #~ msgid "" #~ "The \"Network interface\" is the device that connects your computer to " #~ "the internet. This is usually a modem, an ISDN card or a network card in " #~ "case you are using DSL." #~ msgstr "" #~ "La \"Interfaz de red\" es el dispositivo que conecta tu ordenador a " #~ "Internet. Normalmente es un módem, una tarjeta de RDSI o una tarjeta de " #~ "red en el caso de los xDSL como el ADSL." #, fuzzy #~ msgid "Network configuration: interface" #~ msgstr "Interfaz de red:" #~ msgid "" #~ "What is the name of the network interface that connects your computer to " #~ "the Internet?" #~ msgstr "" #~ "¿Cuál es el nombre de la interfaz de red que conecta tu ordenador a " #~ "Internet?" #, fuzzy #~ msgid "Network configuration: IP" #~ msgstr "Configuración de GNUnet" #, fuzzy #~ msgid "What is this computer's public IP address or hostname?" #~ msgstr "" #~ "¿Cuál es es la dirección pública IP o el nombre del dominio de éste " #~ "ordenador?\n" #~ "\n" #~ "En caso de duda, dejar este campo en blanco." #, fuzzy #~ msgid "" #~ "If your provider always assigns the same IP-Address to you (a \"static\" " #~ "IP-Address), enter it into the \"IP-Address\" field. If your IP-Address " #~ "changes every now and then (\"dynamic\" IP-Address) but there's a " #~ "hostname that always points to your actual IP-Address (\"Dynamic DNS\"), " #~ "you can also enter it here.\n" #~ "If left empty, GNUnet will try to automatically detect the IP.\n" #~ "You can specify a hostname, GNUnet will then use DNS to resolve it.\n" #~ "If in doubt, leave this empty." #~ msgstr "" #~ "Si tu proveedor siempre te asigna la misma dirección IP (una IP \"estática" #~ "\") introducela en el campo \"Dirección IP\". Si tu dirección IP cambia " #~ "pero hay un nombre de dominio que siempre apunta a tu dirección IP actual " #~ "(\"DNS dinámica\"), puedes introducirlo allí también.\n" #~ "En caso de duda deja el campo en blanco. GNUnet intentará determinar tu " #~ "dirección IP" #, fuzzy #~ msgid "Bandwidth configuration: upload" #~ msgstr "Configuración de GNUnet" #, fuzzy #~ msgid "How much upstream bandwidth (in bytes/s) may be used?" #~ msgstr "¿Cuánta subida (Bytes/s) será usada por GNUnet?" #, fuzzy #~ msgid "" #~ "You can limit GNUnet's resource usage here.\n" #~ "\n" #~ "The \"upstream\" is the data channel through which data is *sent* to the " #~ "internet. The limit is the maximum amount which GNUnet is allowed to use. " #~ "If you have a flatrate, you can set it to the maximum speed of your " #~ "internet connection. You should not use a value that is higher than what " #~ "your actual connection allows." #~ msgstr "" #~ "Puedes limitar el uso de recursos de GNUnet aquí.\n" #~ "\n" #~ "La \"subida\" es el canal de datos a través del cual los datos son " #~ "*mandados* a Internet. El límite, o bien es el total máximo para este " #~ "ordenador, o bien el que se le permita usar a GNUnet. Puedes especificar " #~ "este valor más tarde. Si tienes una tarifa plana puedes configurarlo a la " #~ "máxima velocidad de tu conexión a Internet." #, fuzzy #~ msgid "Bandwidth configuration: download" #~ msgstr "Configuración de GNUnet" #, fuzzy #~ msgid "How much downstream bandwidth (in bytes/s) may be used?" #~ msgstr "¿Cuánta bajada (Bytes/s) será usada por GNUnet?" #, fuzzy #~ msgid "" #~ "You can limit GNUnet's resource usage here.\n" #~ "\n" #~ "The \"downstream\" is the data channel through which data is *received* " #~ "from the internet. The limit is the maximum amount which GNUnet is " #~ "allowed to use. If you have a flatrate, you can set it to the maximum " #~ "speed of your internet connection. You should not use a value that is " #~ "higher than what your actual connection allows." #~ msgstr "" #~ "Puedes limitar el uso de recursos de GNUnet aquí.\n" #~ "\n" #~ "La \"bajada\" es el canal de datos a través del cuál los datos son " #~ "*recibidos* de Internet. El límite, o bien es el total máximo de este " #~ "ordenador, o bien el que se le permita usar a GNUnet. Puedes especificar " #~ "este valor más tarde. Si tienes una tarifa plana puedes configurarlo a la " #~ "máxima velocidad de tu conexión a Internet." #, fuzzy #~ msgid "Quota configuration" #~ msgstr "Configuración de GNUnet" #, fuzzy #~ msgid "" #~ "The GNUnet datastore contains all content that GNUnet needs to store " #~ "(indexed, inserted and migrated content)." #~ msgstr "" #~ "¿Cuál es el tamaño máximo de almacenamiento en MB?\n" #~ "\n" #~ "El almacenamiento de GNUnet contiene todos los datos que GNUnet genera " #~ "(datos del índice, contenido insertado y migrado)." #, fuzzy #~ msgid "Daemon configuration: user account" #~ msgstr "Imposible crear la cuenta de usuario:" #, fuzzy #~ msgid "" #~ "For security reasons, it is a good idea to let this setup create a new " #~ "user account under which the GNUnet service is started at system " #~ "startup.\n" #~ "\n" #~ "However, GNUnet may not be able to access files other than its own. This " #~ "includes files you want to publish in GNUnet. You'll have to grant read " #~ "permissions to the user specified below.\n" #~ "\n" #~ "Leave the field empty to run GNUnet with system privileges.\n" #~ msgstr "" #~ "Define el usuario bajo el que correrán los servicios de GNUnet.\n" #~ "\n" #~ "Por razones de seguridad, es una buena idea dejar que la configuración " #~ "cree una nueva cuenta de usuario bajo el cual el servicio de GNUnet es " #~ "arrancado al iniciar el sistema.\n" #~ "\n" #~ "Por consiguiente, GNUnet no tiene la posibilidad de acceder a otros " #~ "ficheros que no sean los que posee. Ésto incluye los ficheros que quieras " #~ "publicar en GNUnet. Tendrás que garantizar que el usuario especificado " #~ "aquí posea permisos de lectura.\n" #~ "\n" #~ "Deja los campos vacíos para arrancar GNUnet con privilegios de sistema.\n" #~ "Usuario de GNUnet:" #, fuzzy #~ msgid "" #~ "For security reasons, it is a good idea to let this setup create a new " #~ "group for the chosen user account.\n" #~ "\n" #~ "You can also specify a already existent group here.\n" #~ "\n" #~ "Only members of this group will be allowed to start and stop the the " #~ "GNUnet server and have access to GNUnet server data.\n" #~ msgstr "" #~ "Define el grupo bajo el que correrán los servicios de GNUnet aquí.\n" #~ "\n" #~ "Por razones de seguridad, es una buena idea dejar que la configuración " #~ "cree un nuevo grupo para la cuenta de usuario creada.\n" #~ "\n" #~ "Puedes especificar un grupo ya existente aquí.\n" #~ "\n" #~ "Sólo los miembros de este grupo esta autorizados a arrancar y parar el " #~ "servidor de GNUnet y tener acceso a los datos del servidor de GNUnet.\n" #~ "\n" #~ "Grupo de GNUnet:" #, fuzzy #~ msgid "" #~ "If you say \"yes\" here, the GNUnet background process will be " #~ "automatically started when you turn on your computer. If you say \"no\" " #~ "here, you have to launch GNUnet yourself each time you want to use it." #~ msgstr "" #~ "¿Quieres arrancar GNUnet como un servicio de sistema?\n" #~ "n\n" #~ "Si dices \"sí\" aquí, el proceso en segundo plano de GNUnet sera " #~ "automáticamente arrancado cuando enciendas tu ordenador. Si dices \"no\" " #~ "aquí, tendrás que ejecutar GNUnet tu mismo cada vez que quieras usarlo." #, fuzzy #~ msgid "Unable to create user account for daemon." #~ msgstr "Imposible crear la cuenta de usuario:" #, fuzzy #~ msgid "Save configuration?" #~ msgstr "Configuración de GNUnet" #, fuzzy #~ msgid "GNUnet Configuration" #~ msgstr "Configuración de GNUnet" #~ msgid "Back" #~ msgstr "Atrás" #~ msgid "Up" #~ msgstr "Arriba" #~ msgid "Cancel" #~ msgstr "Cancelar" #, fuzzy #~ msgid "Configuration unchanged, no need to save.\n" #~ msgstr "" #~ "La configuración o la versión de GNUnet cambiaron. ¡Debes ejecutar " #~ "'%s'!\n" #, fuzzy #~ msgid "Do you wish to save your new configuration?" #~ msgstr "¿Quieres guardar tu configuración?" #, fuzzy #~ msgid "" #~ "\n" #~ "Your configuration changes were NOT saved.\n" #~ msgstr "Fichero de configuración '%s' creado.\n" #~ msgid "This version of Windows doesn't support services.\n" #~ msgstr "Esta versión de Windows no soporta servicios.\n" #, fuzzy #~ msgid "Error: can't open Service Control Manager: %s\n" #~ msgstr "Error: imposible abrir el Service Control Manager: &s\n" #~ msgid "Error: can't create service: %s\n" #~ msgstr "Error: imposible crear el servicio: %s\n" #~ msgid "Error: can't access service: %s\n" #~ msgstr "Error: imposible acceder al servicio: %s\n" #~ msgid "Error: can't delete service: %s\n" #~ msgstr "Error: imposible borrar el servicio: %s\n" #, fuzzy #~ msgid "Configuration changed. Save?" #~ msgstr "" #~ "La configuración o la versión de GNUnet cambiaron. ¡Debes ejecutar " #~ "'%s'!\n" #, fuzzy #~ msgid "Error saving configuration." #~ msgstr "Imposible guardar la configuración" #, fuzzy #~ msgid "(unknown connection)" #~ msgstr "Conexión de red" #, fuzzy #~ msgid "Do you want to save the new configuration?" #~ msgstr "¿Quieres guardar tu configuración?" #~ msgid "Unable to change startup process:" #~ msgstr "Imposible cambiar el proceso de arranque:" #~ msgid "generate configuration for gnunetd, the GNUnet daemon" #~ msgstr "genera configuración para gnunetd, el demonio de GNUnet" #~ msgid "Tool to setup GNUnet." #~ msgstr "Herramienta de configuración de GNUnet." #, fuzzy #~ msgid "Too many arguments.\n" #~ msgstr "Argumentos en la linea de comandos inválidos.\n" #, fuzzy #~ msgid "No interface specified, using default.\n" #~ msgstr "Ninguna interfaz especificada, usando la marcada por defecto\n" #, fuzzy #~ msgid "Configuration file `%s' must be a filename (but is a directory).\n" #~ msgstr "" #~ "El fichero de configuración '%s' no ha sido encontrado. ¡Ejecute gnunet-" #~ "setup!\n" #, fuzzy #~ msgid "Undefined option.\n" #~ msgstr "Otras configuraciones" #, fuzzy #~ msgid "Unknown operation '%s'.\n" #~ msgstr "Operación desconocida '%s'\n" #, fuzzy #~ msgid "yes" #~ msgstr "Bytes" #~ msgid "Yes\n" #~ msgstr "Sí\n" #~ msgid "No\n" #~ msgstr "No\n" #~ msgid "Help\n" #~ msgstr "Ayuda\n" #, fuzzy #~ msgid "Abort\n" #~ msgstr "_Acerca de" #, fuzzy #~ msgid "Configuration was unchanged, no need to save.\n" #~ msgstr "" #~ "La configuración o la versión de GNUnet cambiaron. ¡Debes ejecutar " #~ "'%s'!\n" #~ msgid "Can't open Service Control Manager" #~ msgstr "Imposible abrir el Service Control Manager" #~ msgid "Can't create service" #~ msgstr "Imposible crear el servicio" #~ msgid "Error changing the permissions of the GNUnet directory" #~ msgstr "Error cambiando los permisos del directorio de GNUnet" #, fuzzy #~ msgid "Cannot write to the registry" #~ msgstr "Imposible escribir en el registro" #~ msgid "Can't delete the service" #~ msgstr "Imposible borrar el servicio" #~ msgid "This version of Windows does not support multiple users." #~ msgstr "Esta versión de Windows no permite usuarios múltiples" #~ msgid "Error accessing local security policy" #~ msgstr "Error accediendo a la política de seguridad local" #~ msgid "Error granting service right to user" #~ msgstr "Error garantizando el servicio correcto al usuario" #~ msgid "Unknown error while creating a new user" #~ msgstr "Error desconocido mientras se creaba un nuevo usuario" #, fuzzy #~ msgid "" #~ "Configuration does not satisfy constraints of configuration specification " #~ "file `%s'!\n" #~ msgstr "" #~ "La configuración debe especificar un directorio para los datos FS en la " #~ "sección '%s' bajo'%s'.\n" #~ msgid "FATAL" #~ msgstr "FATAL" #~ msgid "NOTHING" #~ msgstr "NADA" #, fuzzy #~ msgid "Syntax error in configuration entry HOST in section NETWORK: `%s'\n" #~ msgstr "" #~ "Error de sintaxis en el fichero de configuración '%s' en la linea %d.\n" #, fuzzy #~ msgid "Error connecting to %s:%u. Is the daemon running?\n" #~ msgstr "Imposible conectar a %u.%u.%u.%u:%u: %s\n" #, fuzzy #~ msgid "Cannot connect to %s:%u: %s\n" #~ msgstr "Imposible conectar a %u.%u.%u.%u:%u: %s\n" #, fuzzy #~ msgid "Reading result from gnunetd failed, reply invalid!\n" #~ msgstr "¡'%s' falló, respuesta no válida!\n" #, fuzzy #~ msgid "No interface specified in section `%s' under `%s'!\n" #~ msgstr "Ninguna interfaz especificada, usando la marcada por defecto\n" #~ msgid "Could not obtain IP for interface `%s' using `%s'.\n" #~ msgstr "Imposible obtener IP para la interfaz '%s' usando '%s'.\n" #, fuzzy #~ msgid "" #~ "Could not find interface `%s' using `%s', trying to find another " #~ "interface.\n" #~ msgstr "Imposible obtener IP para la interfaz '%s' usando '%s'.\n" #~ msgid "Could not find an IP address for interface `%s'.\n" #~ msgstr "Imposible obtener la dirección IP para la interfaz '%s'.\n" #, fuzzy #~ msgid "" #~ "There is more than one IP address specified for interface `%s'.\n" #~ "GNUnet will use %s.\n" #~ msgstr "" #~ "Hay más de una dirección IP especificada para la interfaz '%s'.\n" #~ "GNUnet usará %u.%u.%u.%u.\n" #~ msgid "Could not resolve `%s' to determine our IP address: %s\n" #~ msgstr "Imposible resolver '%s' para determinar nuestra dirección IP: %s\n" #, fuzzy #~ msgid "Received malformed message (too small) from connection. Closing.\n" #~ msgstr "Recibida respuesta anómala a'%s' del par '%s'.\n" #, fuzzy #~ msgid "`%s' returned with error code %u" #~ msgstr "'%s' falló con el código de error %s: %s" #~ msgid "Can't create semaphore: %i" #~ msgstr "Imposible crear un semáforo: %i" #, fuzzy #~ msgid "Command `%s' failed with error code %u\n" #~ msgstr "'%s' falló con el código de error %s: %s" #, fuzzy #~ msgid "Invalid process priority `%s'\n" #~ msgstr "Respuesta inválida a '%s'.\n" #, fuzzy #~ msgid "`%s' failed with error code %d: %s\n" #~ msgstr "'%s' falló con el código de error %d: %s" #~ msgid "Availability test failed for `%s' at %s:%d.\n" #~ msgstr "Test de disponibilidad fallido para '%s' en %s:%d.\n" #, fuzzy #~ msgid "Starting datastore conversion (this may take a while).\n" #~ msgstr "Creando nueva clave local (esto puede llevar un tiempo).\n" #, fuzzy #~ msgid "Failed to load sqstore service. Check your configuration!\n" #~ msgstr "Imposible guardar la configuración" #, fuzzy #~ msgid "" #~ "%s:%d - RPC %s:%p could not be registered: another callback is already " #~ "using this name (%p)\n" #~ msgstr "" #~ "%s::%s - RPC %s:%p no pudo ser registrada: otro evento está actualmente " #~ "usando este nombre (%p)\n" #, fuzzy #~ msgid "%s:%d - async RPC %s:%p could not be unregistered: not found\n" #~ msgstr "" #~ "%s::%s RPC asíncrona %s:%p no pudo ser desregistrada: no encontrada\n" #~ msgid "`%s' registering handlers %d %d %d\n" #~ msgstr "'%s' registrando manejadores %d %d %d\n" #~ msgid "Using %u messages of size %u for %u times.\n" #~ msgstr "Usando %u mensajes de un tamaño de %u durante %u veces.\n" #~ msgid "output in gnuplot format" #~ msgstr "salida en formato de gnuplot" #~ msgid "number of iterations" #~ msgstr "número de repeticiones" #~ msgid "number of messages to use per iteration" #~ msgstr "número de mensajes a usar por iteración" #~ msgid "message size" #~ msgstr "tamaño del mensaje" #~ msgid "sleep for SPACE ms after each a message block" #~ msgstr "duerme durante SPACE ms después de cada bloque de mensajes" #~ msgid "number of messages in a message block" #~ msgstr "número de mensajes en un bloque de mensajes" #~ msgid "Error establishing connection with gnunetd.\n" #~ msgstr "Se produjo un error estableciendo conexión con gnunetd.\n" #~ msgid "You must specify a receiver!\n" #~ msgstr "¡Debes especificar un receptor!\n" #~ msgid "Invalid receiver peer ID specified (`%s' is not valid name).\n" #~ msgstr "" #~ "ID del par receptor especificada no válida ('%s' no es un nombre " #~ "válido).\n" #~ msgid "Time:\n" #~ msgstr "Tiempo:\n" #~ msgid "\tmax %llums\n" #~ msgstr "\tmax %llums\n" #~ msgid "\tmin %llums\n" #~ msgstr "\tmin %llums\n" #~ msgid "\tmean %8.4fms\n" #~ msgstr "\tmean %8.4fms\n" #~ msgid "\tvariance %8.4fms\n" #~ msgstr "\tvariance %8.4fms\n" #~ msgid "Loss:\n" #~ msgstr "Perdido:\n" #~ msgid "\tmax %u\n" #~ msgstr "\tmax %u\n" #~ msgid "\tmin %u\n" #~ msgstr "\tmin %u\n" #~ msgid "\tmean %8.4f\n" #~ msgstr "\tmean %8.4f\n" #~ msgid "\tvariance %8.4f\n" #~ msgstr "\tvariance %8.4f\n" #~ msgid "Output format not known, this should not happen.\n" #~ msgstr "El formato de salida es desconocido, ésto no debería pasar.\n" #~ msgid "" #~ "\n" #~ "Did not receive the message from gnunetd. Is gnunetd running?\n" #~ msgstr "" #~ "\n" #~ "No se recibió el mensaje de gnunetd. ¿Está gnunetd ejecutandose?\n" #, fuzzy #~ msgid "# bytes received in plaintext of type %d" #~ msgstr "# bytes recibidos por TCP" #, fuzzy #~ msgid "# bytes allocated by SQLite" #~ msgstr "# bytes en la base de datos" #~ msgid "" #~ "Failed to load MySQL database module. Check that MySQL is running and " #~ "configured properly!\n" #~ msgstr "" #~ "Falló al cargar el modulo de la base de datos MySQL. ¡Comprueba que " #~ "MySQL esta ejecutandose y esta configurada correctamente!\n" #, fuzzy #~ msgid "use PRIORITY for the priority of the trace request" #~ msgstr "especifica la prioridad del contenido" #, fuzzy #~ msgid "HELLO message from `%s' has an invalid signature. Dropping.\n" #~ msgstr "mensaje de saludo de '%s' inválido (firma inválida). Omitiendo.\n" #, fuzzy #~ msgid "HELLO message has expiration too far in the future. Dropping.\n" #~ msgstr "" #~ "mensaje de saludo recibido inválido (tiempo superior al límite). " #~ "Omitiendo.\n" #, fuzzy #~ msgid "Could not send HELLO+PING, ping buffer full.\n" #~ msgstr "Imposible mandar ahora saludos+PING, buffer del ping lleno.\n" #~ msgid "" #~ "Announcing ourselves pointless: no other peers are known to us so far.\n" #~ msgstr "" #~ "Es inútil anunciarnos: no hay más pares que nos conozcan más allá.\n" #, fuzzy #~ msgid "# Peer advertisements of type NAT received" #~ msgstr "# Anuncios de los pares recibidos" #, fuzzy #~ msgid "# Peer advertisements updating earlier HELLOs" #~ msgstr "# Anuncios de los pares recibidos" #, fuzzy #~ msgid "# Peer advertisements for unsupported transport" #~ msgstr "# Anuncios de los pares recibidos" #, fuzzy #~ msgid "# Peer advertisements not confirmed due to ping busy" #~ msgstr "# Anuncios de los pares recibidos" #, fuzzy #~ msgid "# Peer advertisements not confirmed due to lack of self ad" #~ msgstr "# Anuncios de los pares recibidos" #, fuzzy #~ msgid "# Peer advertisements not confirmed due to send error" #~ msgstr "# Anuncios de los pares recibidos" #~ msgid "`%s' registering handler %d (plaintext and ciphertext)\n" #~ msgstr "'%s' registrando manejador %d (texto plano e hipertexto)\n" #~ msgid "" #~ "ensures that this peer is known by other peers and discovers other peers" #~ msgstr "" #~ "Asegura que este par es conocido por otros pares y descubre otros pares" #~ msgid "`%s' registering handler %d\n" #~ msgstr "'%s' registrando manejador %d\n" #, fuzzy #~ msgid "`%s' registering CS handlers %d and %d\n" #~ msgstr "'%s' registrando manejadores %d y %d\n" #~ msgid "enables P2P-chat (incomplete)" #~ msgstr "Activa el chat P2P (incompleto)" #, fuzzy #~ msgid "Existing key in file `%s' failed format check, creating new key.\n" #~ msgstr "" #~ "Se produjo un fallo al comprobar la clave local existente en el fichero " #~ "'%s', creando nueva clave local.\n" #, fuzzy #~ msgid "Creating new key for this nickname (this may take a while).\n" #~ msgstr "Creando nueva clave local (esto puede llevar un tiempo).\n" #, fuzzy #~ msgid "# max bytes allowed in dstore" #~ msgstr "# bytes en la base de datos" #~ msgid "Transport library `%s' did not provide required function '%s%s'.\n" #~ msgstr "" #~ "La biblioteca de transporte '%s' no provee la función '%s%s' requerida.\n" #, fuzzy #~ msgid "Query (get KEY, put KEY VALUE) DHT table." #~ msgstr "" #~ "Pregunta (coje KEY, pone KEY VALUE, borra KEY VALUE) a una tabla DHT." #, fuzzy #~ msgid "allow TIME ms to process a GET command" #~ msgstr "Reserva TIME ms para procesar cada comando" #, fuzzy #~ msgid "Issuing `%s(%s,%s)' command.\n" #~ msgstr "'%s(%s, %s)' falló.\n" #~ msgid "Command `%s' requires an argument (`%s').\n" #~ msgstr "El comando '%s' requiere un argumento ('%s').\n" #~ msgid "Command `%s' requires two arguments (`%s' and `%s').\n" #~ msgstr "El comando '%s' requiere dos argumentos ('%s' y '%s').\n" #, fuzzy #~ msgid "# dht put requests received" #~ msgstr "# bytes recibidos por TCP" #, fuzzy #~ msgid "`%s' registering p2p handlers: %d %d %d\n" #~ msgstr "'%s' registrando manejadores %d %d %d\n" #~ msgid "`%s' failed. Terminating connection to client.\n" #~ msgstr "'%s' falló. Finalizando conexión con el cleinte.\n" #, fuzzy #~ msgid "`%s' registering client handlers: %d %d\n" #~ msgstr "'%s' registrando un manejador de clientes %d\n" #~ msgid "" #~ "Existing hostkey in file `%s' failed format check, creating new hostkey.\n" #~ msgstr "" #~ "Se produjo un fallo al comprobar la clave local existente en el fichero " #~ "'%s', creando nueva clave local.\n" #~ msgid "Done creating hostkey.\n" #~ msgstr "Correcto al crear la clave local.\n" #, fuzzy #~ msgid "Removed file `%s' containing invalid HELLO data.\n" #~ msgstr "Borrando el fichero '%s' que contiene datos de saludo no válidos.\n" #~ msgid "Signature failed verification: signature invalid.\n" #~ msgstr "Falló la verificación de la firma: firma no válida.\n" #~ msgid "Received malformed `%s' message. Dropping.\n" #~ msgstr "Recibido el mensaje '%s' con un mal formato. Omitiendo.\n" #~ msgid "Received ping for another peer. Dropping.\n" #~ msgstr "Recibido ping de otro par. Omitiendo.\n" #~ msgid "`%s' registering handlers %d %d (plaintext and ciphertext)\n" #~ msgstr "'%s' registrando manejadores %d %d (texto plano e hipertexto)\n" #, fuzzy #~ msgid "Cannot encrypt sessionkey, peer `%s' not known!\n" #~ msgstr "¡Imposible encriptar la clave de sesión, otro par desconocido!\n" #, fuzzy #~ msgid "Could not create any HELLO for myself (have transports `%s')!\n" #~ msgstr "¡Imposible crear la clave local!\n" #, fuzzy #~ msgid "" #~ "Session key received from peer `%s' has invalid format (discarded).\n" #~ msgstr "El mensaje recibido del par es inválido.\n" #, fuzzy #~ msgid "Session key received from peer `%s' is for `%s' and not for me!\n" #~ msgstr "El mensaje recibido del par es inválido.\n" #~ msgid "setkey `%s' from `%s' fails CRC check (have: %u, want %u).\n" #~ msgstr "" #~ "el cambio de clave '%s' de '%s' falló al comprobar el CRC (dio: %u, " #~ "esperado %u).\n" #, fuzzy #~ msgid "" #~ "Error parsing encrypted session key from `%s', given message part size is " #~ "invalid.\n" #~ msgstr "" #~ "Error pasando la clave de sesión encriptada, el mensaje dado del tamaño " #~ "de las partes es inválido.\n" #, fuzzy #~ msgid "Unknown type in embedded message from `%s': %u (size: %u)\n" #~ msgstr "Tipo desconocido en el mensaje embebido: %u (tamaño: %u)\n" #~ msgid "# sessions established" #~ msgstr "# sesiones establecidas" #~ msgid "automate creation of a namespace by starting a collection" #~ msgstr "creación automática de un espacio al empezar una colección" #~ msgid "create a new pseudonym under the given NICKNAME" #~ msgstr "crea un nuevo pseudónimo bajo el APODO dado" #~ msgid "delete the pseudonym with the given NICKNAME" #~ msgstr "borra el pseudónimo con el APODO dado" #~ msgid "end automated building of a namespace (ends collection)" #~ msgstr "" #~ "finaliza la construcción automática de un espacio (finaliza la " #~ "recolección)" #~ msgid "" #~ "Create new pseudonyms, delete pseudonyms or list existing pseudonyms." #~ msgstr "" #~ "Crea nuevos pseudónimos, borra pseudónimos o lista los pseudónimos " #~ "existentes." #~ msgid "" #~ "use the given keyword to advertise the namespace (use when creating a new " #~ "pseudonym)" #~ msgstr "" #~ "usa la clave dada para anunciar el espacio (úsalo cuando crees un nuevo " #~ "pseudónimo)" #, fuzzy #~ msgid "specify metadata describing the namespace or collection" #~ msgstr "" #~ "finaliza la construcción automática de un espacio (finaliza la " #~ "recolección)" #~ msgid "" #~ "do not generate an advertisement for this namespace (use when creating a " #~ "new pseudonym)" #~ msgstr "" #~ "no genera un anuncio para este espacio (úsalo cuando crees un nuevo " #~ "pseudónimo)" #~ msgid "do not list the pseudonyms from the pseudonym database" #~ msgstr "no listar los pseudónimos de la base de datos de pseudónimos" #~ msgid "" #~ "specify IDENTIFIER to be the address of the entrypoint to content in the " #~ "namespace (use when creating a new pseudonym)" #~ msgstr "" #~ "especifica el IDENTIFIER para ser la dirección del punto de entrada al " #~ "contenido en el espacio (úsalo cuando crees un nuevo pseudónimo)" #~ msgid "Namespace `%s' (%s) has rating %d.\n" #~ msgstr "El espacio '%s' (%s) ha sido valorado con un %d.\n" #~ msgid "\tRating (after update): %d\n" #~ msgstr "\tValoración (después de la actualización): %d\n" #~ msgid "Collection stopped.\n" #~ msgstr "Colección detenida.\n" #~ msgid "Failed to stop collection (not active?).\n" #~ msgstr "Falló al parar la recolección (¿no está activa?).\n" #~ msgid "Pseudonym `%s' deleted.\n" #~ msgstr "El pseudónimo '%s' fue borrado.\n" #~ msgid "Error deleting pseudonym `%s' (does not exist?).\n" #~ msgstr "Error borrando el pseudónimo '%s' (¿no existe?).\n" #, fuzzy #~ msgid "Started collection.\n" #~ msgstr "Iniciada colección '%s'.\n" #~ msgid "Namespace `%s' created (root: %s).\n" #~ msgstr "El espacio '%s' fue creado (root: %s).\n" #, fuzzy #~ msgid "You must specify a name for the collection (`%s' option).\n" #~ msgstr "Debes especificar un apodo (use la opción '%s').\n" #~ msgid "%d files found in directory.\n" #~ msgstr "%d ficheros encontrados en el directorio.\n" #~ msgid "Perform directory related operations." #~ msgstr "Realiza operaciones respecto al directorio." #~ msgid "" #~ "remove all entries from the directory database and stop tracking URIs" #~ msgstr "" #~ "borra todas las entradas de la base de datos del directorio y detiene el " #~ "seguimiento de URIs" #~ msgid "list entries from the directory database" #~ msgstr "lista las entradas de la base de datos del directorio" #~ msgid "start tracking entries for the directory database" #~ msgstr "comienza a seguir las entradas de la base de datos del directorio" #~ msgid "Listed %d matching entries.\n" #~ msgstr "%d entradas encontradas.\n" #, fuzzy #~ msgid "Upload of `%s' at %llu out of %llu bytes.\n" #~ msgstr "Descargado del fichero '%s' el %16llu de %16llu bytes(%8.3f kbps)\n" #, fuzzy #~ msgid "Upload aborted.\n" #~ msgstr "Descarga abortada" #, fuzzy #~ msgid "Uploading suspended.\n" #~ msgstr "¡Subida rechazada!" #, fuzzy #~ msgid "" #~ "run in debug mode; gnunet-auto-share will not daemonize and error " #~ "messages will be written to stderr instead of a logfile" #~ msgstr "" #~ "se ejecuta en modo de depuración; gnunetd no sera un demonio y los " #~ "mensajes de error serán escritos a través de stderr en vez de en un " #~ "fichero de log" #, fuzzy #~ msgid "" #~ "do not use libextractor to add additional references to directory entries " #~ "and/or the published file" #~ msgstr "" #~ "usa libextractor para añadir referencias directas adicionales a las " #~ "entradas del directorio" #~ msgid "Created entry `%s' in namespace `%s'\n" #~ msgstr "Creada la entrada '%s' en el espacio '%s'\n" #, fuzzy #~ msgid "" #~ "%16llu of %16llu bytes inserted (estimating %6s to completion) - %s\n" #~ msgstr "%16llu de %16llu bytes insertados (%s estimado para completar)\n" #, fuzzy #~ msgid "" #~ "Upload of `%s' complete, %llu bytes took %llu seconds (%8.3f KiB/s).\n" #~ msgstr "" #~ "Subida de '%s' completada, %llu bytes tomaron %llu segundos (%8.3f " #~ "kbps).\n" #, fuzzy #~ msgid "" #~ "\n" #~ "Upload aborted.\n" #~ msgstr "Descarga abortada" #, fuzzy #~ msgid "" #~ "\n" #~ "Error uploading file: %s" #~ msgstr "" #~ "\n" #~ "Error subiendo el fichero %s\n" #~ msgid "" #~ "even if gnunetd is running on the local machine, force the creation of a " #~ "copy instead of making a link to the GNUnet share directory" #~ msgstr "" #~ "aunque gnunetd este corriendo en el ordenador local, fuerza la creación " #~ "de una copia en vez de hacer un enlace al directorio para compartir de " #~ "GNUnet" #~ msgid "Make files available to GNUnet for sharing." #~ msgstr "Permite a GNUnet disponer de los ficheros para compartirlos." #~ msgid "Could not access namespace `%s' (does not exist?).\n" #~ msgstr "Imposible acceder al espacio '%s' (¿no existe?).\n" #~ msgid "Search GNUnet for files." #~ msgstr "Buscar GNUnet en busca de ficheros." #~ msgid "write encountered (decrypted) search results to FILENAME" #~ msgstr "escribe los resultados encontrados (desencriptados) a FILENAME" #~ msgid "Error converting arguments to URI!\n" #~ msgstr "¡Se produjo un error al convertir los argumentos a una URI!\n" #~ msgid "" #~ "%16llu of %16llu bytes unindexed (estimating %llu seconds to " #~ "completion) " #~ msgstr "" #~ "%16llu de %16llu bytes desindexados (estimados %llu segundos para " #~ "completar) " #, fuzzy #~ msgid "" #~ "\n" #~ "Unindexing of `%s' complete, %llu bytes took %llu seconds (%8.3f KiB/s).\n" #~ msgstr "" #~ "\n" #~ "El desindexado de '%s' se completó, %llu bytes tomaron %llu segundos " #~ "(%8.3f kbps).\n" #, fuzzy #~ msgid "Not enough arguments. You must specify a filename.\n" #~ msgstr "" #~ "Argumentos insuficientes. Debes especificar una URI de un fichero de " #~ "GNUnet\n" #~ msgid "`%s' failed. Is `%s' a file?\n" #~ msgstr "'%s' falló. ¿Es '%s' un fichero?\n" #~ msgid "Download files from GNUnet." #~ msgstr "Descarga los ficheros de GNUnet" #, fuzzy #~ msgid "Download of file `%s' at %16llu out of %16llu bytes (%8.3f KiB/s)\n" #~ msgstr "Descargado del fichero '%s' el %16llu de %16llu bytes(%8.3f kbps)\n" #, fuzzy #~ msgid "Download aborted.\n" #~ msgstr "Descarga abortada" #, fuzzy #~ msgid "Download of file `%s' complete. Speed was %8.3f KiB per second.\n" #~ msgstr "" #~ "Descarga del fichero '%s' completada. La velocidad media fue " #~ "%8.3fkilobytes por segundo.\n" #~ msgid "Not enough arguments. You must specify a GNUnet file URI\n" #~ msgstr "" #~ "Argumentos insuficientes. Debes especificar una URI de un fichero de " #~ "GNUnet\n" #~ msgid "URI `%s' invalid for gnunet-download.\n" #~ msgstr "La URI '%s' no es válida para una descarga-de-gnunet.\n" #, fuzzy #~ msgid "No filename specified, using `%s' instead (for now).\n" #~ msgstr "Ningún nombre especificado para la tabla, usando '%s'.\n" #, fuzzy #~ msgid "Downloading %d files from directory `%s'.\n" #~ msgstr "Descarga los ficheros de GNUnet" #~ msgid "File stored as `%s'.\n" #~ msgstr "Fichero almacenado en '%s'.\n" #~ msgid "Collecting file identifiers disabled.\n" #~ msgstr "Recolección de identificadores de fichero desactivada.\n" #~ msgid "Deleted corrupt URI database in `%s'." #~ msgstr "Borrada base de datos de URIs corrupta en '%s'." #~ msgid "Cannot get size of file `%s'" #~ msgstr "Imposible determinar el tamaño del fichero '%s'" #~ msgid "Cannot hash `%s'.\n" #~ msgstr "Imposible hallar el hash de '%s'.\n" #~ msgid "Initialization for indexing file `%s' failed.\n" #~ msgstr "" #~ "Durante la inicialización de la indexación del fichero '%s' se produjo un " #~ "fallo.\n" #, fuzzy #~ msgid "Cannot open file `%s': `%s'" #~ msgstr "Imposible abrir el fichero de configuración '%s'.\n" #~ msgid "Renaming of file `%s' to `%s' failed: %s\n" #~ msgstr "Al renombrar el fichero '%s' a '%s' se produjo un fallo: %s\n" #~ msgid "Could not rename file `%s' to `%s': file exists\n" #~ msgstr "Imposible renombrar el fichero '%s' a '%s': el fichero ya existe\n" #~ msgid "CHK URI not allowed for search.\n" #~ msgstr "CHK URI no autorizado para buscar.\n" #~ msgid "LOC URI not allowed for search.\n" #~ msgstr "LOC URI no autorizado para buscar.\n" #~ msgid "File `%s' does not contain a pseudonym.\n" #~ msgstr "El fichero '%s' no contiene un pseudónimo.\n" #~ msgid "Format of pseudonym `%s' is invalid.\n" #~ msgstr "Formato del pseudónimo '%s' no es válido.\n" #, fuzzy #~ msgid "Format of file `%s' is invalid, trying to remove.\n" #~ msgstr "El formato del fichero '%s' no es válido.\n" #~ msgid "" #~ "Decrypted content does not match key. This is either a bug or a " #~ "maliciously inserted file. Download aborted.\n" #~ msgstr "" #~ "El contenido desencriptado no encuentra una clave. Esto puede ser un bug " #~ "o un fichero introducido maliciosamente. Descarga abortada.\n" #, fuzzy #~ msgid "Application aborted." #~ msgstr "_Opciones" #~ msgid "FSUI state file `%s' had syntax error at offset %u.\n" #~ msgstr "" #~ "Fichero del estado de FSUI '%s' tiene un error de sintáxis en la " #~ "asignación %u.\n" #, fuzzy #~ msgid "" #~ "`%s' registering client handlers %d %d %d %d %d %d %d %d and P2P handlers " #~ "%d %d\n" #~ msgstr "" #~ "'%s' registrando manejadores de clientes %d %d %d %d %d %d %d %d %d\n" #~ msgid "enables (anonymous) file-sharing" #~ msgstr "activa la compartición de ficheros anónima" #~ msgid "" #~ "Because the file `%s' has been unavailable for 3 days it got removed from " #~ "your share. Please unindex files before deleting them as the index now " #~ "contains invalid references!\n" #~ msgstr "" #~ "El fichero '%s' se ha eliminado de tus compartidos porque no ha estado " #~ "disponible durante tres días. Por favor, desindexa los ficheros antes de " #~ "borrarlos porque eso causa que el índice tenga referencias no válidas.\n" #, fuzzy #~ msgid "" #~ "Unindexed ODB block `%s' from offset %llu already missing from " #~ "datastore.\n" #~ msgstr "" #~ "Bloque ODB '%s' desindexado del offset %llu perdido de la base de datos.\n" #, fuzzy #~ msgid "# gap client requests tracked" #~ msgstr "# mensajes PONG encriptados recibidos" #~ msgid "# blocks migrated" #~ msgstr "# blocks migrados" #, fuzzy #~ msgid "# blocks injected for migration" #~ msgstr "# blocks migrados" #, fuzzy #~ msgid "# on-demand fetches for migration" #~ msgstr "# blocks migrados" #, fuzzy #~ msgid "Friend list of %s:%d\n" #~ msgstr "Fallo al conectar a gnunetd.\n" #, fuzzy #~ msgid "Waiting for peers to connect" #~ msgstr "Esperando a los pares para conectar (%u ciclos restantes)...\n" #, fuzzy #~ msgid "Bootstrap data obtained from `%s' is invalid.\n" #~ msgstr "Formato del pseudónimo '%s' no es válido.\n" #~ msgid "`%s' registering client handler %d\n" #~ msgstr "'%s' registrando un manejador de clientes %d\n" #~ msgid "allows clients to determine gnunetd's configuration" #~ msgstr "permite a los clientes determinar la configuración de gnunetd" #~ msgid "`%s' registering client handler %d and %d\n" #~ msgstr "'%s' registrando manejador de clientes %d y %d\n" #, fuzzy #~ msgid "% of allowed network load (up)" #~ msgstr "% de red permitida para la subida" #, fuzzy #~ msgid "% of allowed network load (down)" #~ msgstr "% de red permitida para bajada" #, fuzzy #~ msgid "% of allowed cpu load" #~ msgstr "% de CPU permitida para el uso" #, fuzzy #~ msgid "% of allowed io load" #~ msgstr "% de CPU permitida para el uso" #, fuzzy #~ msgid "`%s' registering client handlers %d %d %d and p2p handler %d\n" #~ msgstr "" #~ "'%s' registrando manejadores de clientes %d %d %d %d %d %d %d %d %d\n" #~ msgid "Supported peer-to-peer messages:\n" #~ msgstr "Mensajes P2P soportados:\n" #~ msgid "Supported client-server messages:\n" #~ msgstr "Mensajes cliente-servidor soportados:\n" #~ msgid "prints supported protocol messages" #~ msgstr "imprime los mensajes del protocolo" #, fuzzy #~ msgid "VPN Received unknown IP version %d...\n" #~ msgstr "Recibida petición de tipo desconocido %d en %s: %d\n" #, fuzzy #~ msgid "Cannot open tunnel device: %s" #~ msgstr "Imposible abrir el fichero de configuración '%s'.\n" #, fuzzy #~ msgid "Cannot set interface IPv6 address for gnu%d because %s\n" #~ msgstr "Imposible obtener la dirección IP para la interfaz '%s'.\n" #, fuzzy #~ msgid "Cannot add route IPv6 address for gnu%s because %s\n" #~ msgstr "Imposible obtener la dirección IP para la interfaz '%s'.\n" #, fuzzy #~ msgid "`%s' initialising RFC4913 module %d and %d\n" #~ msgstr "'%s' registrando manejadores %d y %d\n" #, fuzzy #~ msgid "enables IPv6 over GNUnet (incomplete)" #~ msgstr "Activa el chat P2P (incompleto)" #~ msgid "Application module `%s' already initialized!\n" #~ msgstr "¡El módulo de la aplicación '%s' ya esta inicializado!\n" #~ msgid "Failed to load plugin `%s' at %s:%d. Unloading plugin.\n" #~ msgstr "Falló al cargar el plugin '%s' en %s:%d. Descargando plugin.\n" #~ msgid "Could not shutdown `%s': application not loaded\n" #~ msgstr "Imposible apagar '%s': aplicación no cargada\n" #~ msgid "Could not shutdown application `%s': not initialized\n" #~ msgstr "Imposible apagar la aplicación '%s': no inicializada\n" #~ msgid "Could not find '%s%s' method in library `%s'.\n" #~ msgstr "Imposible encontrar el método '%s%s' en la biblioteca '%s'.\n" #~ msgid "Could not properly shutdown application `%s'.\n" #~ msgstr "Imposible apagar la aplicación '%s' adecuadamente.\n" #~ msgid "Could not properly unload service `%s'!\n" #~ msgstr "¡Imposible descargar adecuadamente el servicio '%s'!\n" #, fuzzy #~ msgid "Core initialization failed.\n" #~ msgstr "Conexión fallida\n" #~ msgid "run as user LOGIN" #~ msgstr "ejecuta como el usuario LOGIN" #~ msgid "" #~ "run in debug mode; gnunetd will not daemonize and error messages will be " #~ "written to stderr instead of a logfile" #~ msgstr "" #~ "se ejecuta en modo de depuración; gnunetd no sera un demonio y los " #~ "mensajes de error serán escritos a través de stderr en vez de en un " #~ "fichero de log" #~ msgid "Starts the gnunetd daemon." #~ msgstr "Arranca el demonio de gnunetd." #, fuzzy #~ msgid "specify username as which gnunetd should run" #~ msgstr "especifica el host en el que gnunetd esta ejecutandose" #~ msgid "Configuration or GNUnet version changed. You need to run `%s'!\n" #~ msgstr "" #~ "La configuración o la versión de GNUnet cambiaron. ¡Debes ejecutar " #~ "'%s'!\n" #~ msgid "The `%s' request received from client is malformed.\n" #~ msgstr "La petición '%s' recibida del cliente esta mal formada.\n" #, fuzzy #~ msgid "Registering failed, message type %d already in use.\n" #~ msgstr "%s falló, el mensaje del tipo %d ya está en uso.\n" #, fuzzy #~ msgid "Unable to obtain filesystem information for `%s': %u\n" #~ msgstr "Imposible guardar el fichero de configuración '%s': %s.\n" #, fuzzy #~ msgid "`%s' message invalid (signature invalid).\n" #~ msgstr "mensaje de saludo inválido (firma no válida).\n" #~ msgid "Message details: %u: length %d, priority: %d\n" #~ msgstr "Detalles del mensaje: %u: longitud %d, prioridad: %d\n" #~ msgid "Message from `%s' discarded: invalid format.\n" #~ msgstr "Mensaje de '%s' descartado: formato inválido.\n" #~ msgid "Invalid sequence number %u <= %u, dropping message.\n" #~ msgstr "Secuencia de números no válida %u <= %u, omitiendo mensaje.\n" #~ msgid "Message received more than one day old. Dropped.\n" #~ msgstr "Mensajes recibidos de mas de un día de antigüedad. Omitidos.\n" #~ msgid "# bytes noise sent" #~ msgstr "# \"bytes-ruido\" mandados" #, fuzzy #~ msgid "# total bytes per second receive limit" #~ msgstr "# bytes de ruido recibidos" #, fuzzy #~ msgid "# total number of messages in send buffers" #~ msgstr "número de mensajes en un bloque de mensajes" #, fuzzy #~ msgid "# total number of bytes we were allowed to send but did not" #~ msgstr "número de mensajes en un bloque de mensajes" #, fuzzy #~ msgid "# total number of bytes we were allowed to sent" #~ msgstr "número de mensajes en un bloque de mensajes" #~ msgid "`%s': Could not create hello.\n" #~ msgstr "'%s': Imposible crear saludo.\n" #~ msgid "`%s': Could not send.\n" #~ msgstr "'%s': Imposible mandar.\n" #~ msgid "`%s': Could not disconnect.\n" #~ msgstr "'%s': Imposible desconectar.\n" #, fuzzy #~ msgid "" #~ "`%s' transport OK. It took %ums to transmit %llu messages of %llu bytes " #~ "each.\n" #~ msgstr "" #~ "Transporte '%s' OK. Tomó %ums transmitir %d mensajes de %d bytes cada " #~ "uno.\n" #~ msgid " Transport %d is not being tested\n" #~ msgstr " El transporte %d no esta siendo probado\n" #~ msgid "" #~ "\n" #~ "Contacting `%s'." #~ msgstr "" #~ "\n" #~ "Contactando '%s'." #~ msgid " Connection failed (bug?)\n" #~ msgstr "Conexión fallida (¿bug?)\n" #, fuzzy #~ msgid "OK!\n" #~ msgstr "OK" #~ msgid "send messages with SIZE bytes payload" #~ msgstr "manda mensajes con SIZE bytes payload" #~ msgid "Testing transport(s) %s\n" #~ msgstr "Probando transporte(s) %s\n" #~ msgid "Available transport(s): %s\n" #~ msgstr "Transporte(s) disponible(s): %s\n" #, fuzzy #~ msgid "%s failed for url `%s' and post-data `%s' at %s:%d: `%s'\n" #~ msgstr "'%s' falló en %s: %d con error: '%s'.\n" #~ msgid "# bytes sent via HTTP" #~ msgstr "# bytes mandados vía HTTP" #~ msgid "# bytes dropped by HTTP (outgoing)" #~ msgstr "#bytes omitidos vía HTTP (salientes)" #, fuzzy #~ msgid "# HTTP curl receive callbacks" #~ msgstr "# bytes recibidos por TCP" #, fuzzy #~ msgid "# HTTP connect calls" #~ msgstr "# de pares conectados" #, fuzzy #~ msgid "Failed to obtain my (external) %s address!\n" #~ msgstr "¡Falló al obtener mi dirección IP (externa)!\n" #, fuzzy #~ msgid "specify host on which gnunetd is running" #~ msgstr "especifica el host en el que gnunetd esta ejecutandose" #, fuzzy #~ msgid "No help available." #~ msgstr "'%s' no esta disponible." #, fuzzy #~ msgid "Show rarely used options" #~ msgstr "Mostrar todas las opciones" #, fuzzy #~ msgid "Meta-configuration" #~ msgstr "Configuración de GNUnet" #, fuzzy #~ msgid "Full pathname of GNUnet HOME directory" #~ msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" #, fuzzy #~ msgid "Full pathname of GNUnet directory for file-sharing data" #~ msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" #, fuzzy #~ msgid "Full pathname to the directory with the key-value database" #~ msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" #, fuzzy #~ msgid "Full pathname of GNUnet directory for indexed files symbolic links" #~ msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" #, fuzzy #~ msgid "Disable automatic establishment of connections" #~ msgstr "Se produjo un error estableciendo conexión con gnunetd.\n" #, fuzzy #~ msgid "Run gnunetd as this group." #~ msgstr "Ejecutar gnunet-update" #, fuzzy #~ msgid "General settings" #~ msgstr "Otras configuraciones" #, fuzzy #~ msgid "Settings for restricting connections to friends" #~ msgstr "'%s' falló. Finalizando conexión con el cleinte.\n" #, fuzzy #~ msgid "Name of the MySQL database GNUnet should use" #~ msgstr "Imposible inicializar SQLite.\n" #, fuzzy #~ msgid "Configuration file that specifies the MySQL username and password" #~ msgstr "" #~ "La configuración o la versión de GNUnet cambiaron. ¡Debes ejecutar " #~ "'%s'!\n" #, fuzzy #~ msgid "Configuration of the MySQL database" #~ msgstr "" #~ "La configuración o la versión de GNUnet cambiaron. ¡Debes ejecutar " #~ "'%s'!\n" #, fuzzy #~ msgid "MB of diskspace GNUnet can use for anonymous file sharing" #~ msgstr "activa la compartición de ficheros anónima" #, fuzzy #~ msgid "Number of entries in the migration buffer" #~ msgstr "número de mensajes en un bloque de mensajes" #, fuzzy #~ msgid "" #~ "MB of diskspace GNUnet can use for caching DHT index data (the data will " #~ "be stored in /tmp)" #~ msgstr "activa la compartición de ficheros anónima" #, fuzzy #~ msgid "Options for anonymous file sharing" #~ msgstr "activa la compartición de ficheros anónima" #, fuzzy #~ msgid "Applications" #~ msgstr "_Opciones" #, fuzzy #~ msgid "Network interface" #~ msgstr "Interfaz de red:" #, fuzzy #~ msgid "Network interface to monitor" #~ msgstr "Interfaz de red:" #, fuzzy #~ msgid "Load management" #~ msgstr "Argumentos en la linea de comandos inválidos.\n" #, fuzzy #~ msgid "This is equivalent to the -H option. The format is IP:PORT." #~ msgstr "Muestra el valor de la opción" #, fuzzy #~ msgid "What is the path to the configuration file for gnunetd?" #~ msgstr "Esta es la herramienta de configuración de GNUnet." #, fuzzy #~ msgid "General options" #~ msgstr "Otras configuraciones" #, fuzzy #~ msgid "Full pathname of GNUnet client HOME directory" #~ msgstr "Error en el formato del fichero (¿no es un directorio de GNUnet?)\n" #, fuzzy #~ msgid "`%s' failed at %s:%d in %s with error: %s\n" #~ msgstr "'%s' falló en %s: %d con el error: %s\n" #, fuzzy #~ msgid "`%s' failed at %s:%d with error `%s' after %llums\n" #~ msgstr "'%s' falló en %s: %d con el error: %s\n" #~ msgid "'%s(%s,%s)' succeeded\n" #~ msgstr "'%s (%s, %s)' logrado satisfactoriamente\n" #~ msgid "'%s(%s,%s)' failed.\n" #~ msgstr "'%s(%s, %s)' falló.\n" #, fuzzy #~ msgid "" #~ "Directory `%s' in directory `%s' does not match naming convention. " #~ "Removed.\n" #~ msgstr "" #~ "El fichero '%s' en el directorio '%s' no sigue la convención de nombres. " #~ "Eliminando.\n" #, fuzzy #~ msgid "You must specify one and only one directory for sharing.\n" #~ msgstr "Debes especificar uno y solo un fichero para desindexar.\n" #~ msgid "" #~ "set interval for availability of updates to SECONDS (for namespace " #~ "insertions only)" #~ msgstr "" #~ "cambia el intervalo de disponibilidad de las actualizaciones a SEGUNDOS " #~ "(para inserciones en el espacio solamente)" #~ msgid "" #~ "specifies this as an aperiodic but updated publication (for namespace " #~ "insertions only)" #~ msgstr "" #~ "especifica esto como una aperiódica pero actualizada publicación (para " #~ "inserciones en el espacio únicamente)" #~ msgid "specify creation time for SBlock (see man-page for format)" #~ msgstr "" #~ "especifica el tiempo para la creación de un Superbloque (vea la página " #~ "del manual para el formato)" #~ msgid "" #~ "ID of the previous version of the content (for namespace update only)" #~ msgstr "" #~ "ID de la versión previa del contenido (para actualizaciones del espacio " #~ "únicamente)" #~ msgid "Parsing time failed. Use `%s' format.\n" #~ msgstr "Se produjo un fallo al analizar el tiempo. Use el formato '%s'.\n" #~ msgid "Publication interval for periodic publication changed." #~ msgstr "Intervalo de publicación periódica cambiado." #~ msgid "" #~ "Publishing update for periodically updated content more than a week ahead " #~ "of schedule.\n" #~ msgstr "" #~ "publicaciones actualizadas para contenido actualizado periódicamente más " #~ "de una semana antes de la tarea planificada.\n" #, fuzzy #~ msgid "Received malformed message via TCP. Closing.\n" #~ msgstr "Recibido el mensaje '%s' con un mal formato. Omitiendo.\n" #~ msgid "Cannot create pseudonym `%s', file `%s' exists.\n" #~ msgstr "Imposible crear el pseudónimo '%s', el fichero '%s' ya existe.\n" #~ msgid "GNUnet configuration assistant" #~ msgstr "Asistente de configuración de GNUnet" #~ msgid "" #~ "Welcome to GNUnet!\n" #~ "\n" #~ "This assistant will ask you a few basic questions in order to configure " #~ "GNUnet.\n" #~ "\n" #~ "Please visit our homepage at\n" #~ "\thttp://gnunet.org\n" #~ "and join our community at\n" #~ "\thttps://gnunet.org/drupal/\n" #~ "\n" #~ "Have a lot of fun,\n" #~ "\n" #~ "The GNUnet team" #~ msgstr "" #~ "¡Bienvenido a GNUnet!\n" #~ "\n" #~ "Este asistente le preguntará unos datos básicos para configurar GNUnet.\n" #~ "\n" #~ "Por favor, visite nuestra página en\n" #~ "\thttps://gnunet.org/drupal/\n" #~ "\n" #~ "Diviertase,\n" #~ "\n" #~ "El equipo de GNUnet" #~ msgid "Next" #~ msgstr "Siguiente" #~ msgid "" #~ "Enter information about your network connection here.\n" #~ "\n" #~ "The \"Network interface\" is the device that connects your computer to " #~ "the internet. This is usually a modem, an ISDN card or a network card in " #~ "case you are using DSL.\n" #~ "\n" #~ "If your provider always assigns the same IP-Address to you (a \"static\" " #~ "IP-Address), enter it into the \"IP-Address\" field. If your IP-Address " #~ "changes every now and then (\"dynamic\" IP-Address) but there's a " #~ "hostname that always points to your actual IP-Address (\"Dynamic DNS\"), " #~ "you can also enter it here.\n" #~ "If in doubt, leave the field empty. GNUnet will then try to determine " #~ "your IP-Address.\n" #~ "\n" #~ "If you are connected to the internet through another computer doing SNAT, " #~ "a router or a \"hardware firewall\" and other computers on the internet " #~ "cannot connect to this computer, check the last option on this page. " #~ "Leave it unchecked on direct connections through modems, ISDN cards and " #~ "DNAT (also known as \"port forwarding\")." #~ msgstr "" #~ "Introduce información acerca de tu conexión aquí.\n" #~ "\n" #~ "La \"Interfaz de red\" es el dispositivo que conecta tu ordenador a " #~ "Internet. Normalmente es un módem, una tarjeta de RDSI, un módem ADSL o " #~ "una tarjeta de red en el caso de un router.\n" #~ "\n" #~ "Si tu proveedor siempre te da la misma dirección IP (una dirección IP " #~ "\"estática\") introducelo en el campo \"Dirección IP\". Si tu dirección " #~ "IP cambia (una dirección IP \"dinámica\") pero hay un nombre de dominio " #~ "que siempre apunta a tu dirección IP actual (\"DNS dinámica\") también " #~ "puedes introducirla aquí.\n" #~ "En caso de duda deja el campo vacío. GNUnet intentara determinar tu " #~ "dirección IP automaticamente.\n" #~ "\n" #~ "Si tu estas conectado a Internet a través de otro ordenador haciendo " #~ "SNAT, a un router o a un \"cortafuegos de hardware\" y otros ordenadores " #~ "no pueden conectar con tu ordenador marca la última opción en ésta " #~ "página. Déjala sin marcar en conexiones directas a través de modems, " #~ "tarjetas de RDSI y DNAT (también conocido como \"seguimiento de puertos" #~ "\")." #~ msgid "Computer cannot receive inbound connections (SNAT/Firewall)" #~ msgstr "" #~ "El ordenador no puede recibir conexiones entrantes (SNAT/Cortafuegos)" #~ msgid "IP-Address/Hostname:" #~ msgstr "Dirección IP/Nombre del dominio" #, fuzzy #~ msgid "Network interface:" #~ msgstr "Interfaz de red:" #~ msgid "" #~ "You can limit GNUnet's ressource usage here.\n" #~ "\n" #~ "\"Bandwidth limitation\" is how much data may be sent per second. If you " #~ "have a flatrate you can set it to the maximum speed of your internet " #~ "connection.\n" #~ "\n" #~ "The \"Max. CPU usage\" is the percentage of processor time GNUnet is " #~ "allowed to use." #~ msgstr "" #~ "Puedes limitar el uso de recursos de GNUnet aquí.\n" #~ "\n" #~ "\"Limitación de ancho de banda\" es cuantos datos pueden ser mandados por " #~ "segundo. Si tienes una tarifa plana puedes seleccionar la velocidad " #~ "máxima de tu conexión a Internet.\n" #~ "\n" #~ "El \"Uso máximo de CPU\" es el porcentaje del tiempo de procesado que " #~ "GNUnet puede usar." #~ msgid "Downstream (Bytes/s):" #~ msgstr "Bajada (Bytes/s):" #~ msgid "Upstream (Bytes/s):" #~ msgstr "Subida (Bytes/s):" #~ msgid "Bandwidth limitation" #~ msgstr "Limitación del ancho de banda" #~ msgid "Use denoted bandwidth for GNUnet" #~ msgstr "Usa el ancho de banda marcado para GNUnet" #~ msgid "Share denoted bandwidth with other applications" #~ msgstr "Comparte el ancho de banda marcado con otras aplicaciones" #~ msgid "Bandwidth sharing" #~ msgstr "Ancho de banda compartido" #~ msgid "Max. CPU usage (%):" #~ msgstr "Uso máximo de la CPU (%):" #~ msgid "CPU usage" #~ msgstr "Uso de CPU" #~ msgid "Load limitation" #~ msgstr "Limitación de carga" #~ msgid "" #~ "GNUnet is able to store data from other peers in your datastore. This is " #~ "useful if an adversary has access to your inserted content and you need " #~ "to deny that the content is yours. With \"content migration\" on, the " #~ "content could have \"migrated\" over the internet to your node without " #~ "your knowledge.\n" #~ "It also helps to spread popular content over different peers to enhance " #~ "availability.\n" #~ "\n" #~ "The GNUnet datastore contains all data that GNUnet generates (index data, " #~ "inserted and migrated content). Its maximum size can be specified below.\n" #~ "\n" #~ "If you are an experienced user, you may want to tweak your GNUnet " #~ "installation using the enhanced configurator.\n" #~ "\n" #~ "After changing the configuration and/or updating GNUnet, it is sometimes " #~ "required to run gnunet-update to update internal data structures. " #~ "Depending on the changes made, this may take some time." #~ msgstr "" #~ "GNUnet es capaz de almacenar datos de otros pares en tu base de datos. " #~ "Ésto es útil si un adversario tiene acceso a tu contenido y tu necesitas " #~ "negar que ese contenido sea tuyo. Con la \"migración de contenido\" " #~ "activada, tu contenido puede haber \"migrado\" por Internet hasta tu nodo " #~ "sin tu conocimiento.\n" #~ "Ésto también ayuda a difundir contenidos populares por diferentes pares " #~ "para facilitar su disponibilidad.\n" #~ "\n" #~ "La base de datos de GNUnet contiene todos los datos que GNUnet genera " #~ "(índices, contenido insertado y descargado). Su máximo tamaño puede ser " #~ "especificado debajo.\n" #~ "\n" #~ "Si eres un usuario experimentado, puedes desear exprimir tu instalación " #~ "de GNUnet usando la herramienta de configuración avanzada.\n" #~ "\n" #~ "Después de cambiar la configuración y/o actualizar GNUnet, a veces " #~ "esnecesario ejecutar gnunet-update para actualizar las estructuras de " #~ "datos internas. Dependiendo de los cambios que se hayan hecho, ésto podrá " #~ "tomar algún tiempo." #~ msgid "Store migrated content" #~ msgstr "Almacena contenido migrado" #~ msgid "Maximum datastore size (MB):" #~ msgstr "Máximo tamaño de almacenamiento (MB):" #~ msgid "Start the GNUnet background process on computer startup" #~ msgstr "Arranca el demonio de GNUnet al encender el ordenador" #~ msgid "Open the enhanced configurator" #~ msgstr "Abre el editor de configuración avanzado" #, fuzzy #~ msgid "Run gnunet-update" #~ msgstr "¡gnunet-update falló!" #, fuzzy #~ msgid "Other settings" #~ msgstr "Otras configuraciones" #~ msgid "Finish" #~ msgstr "Finalizar" #~ msgid "" #~ "Define the user and the group owning the GNUnet service here.\n" #~ "\n" #~ "For security reasons, it is a good idea to let this setup create a new " #~ "user account and a new group under which the GNUnet service is started at " #~ "system startup.\n" #~ "\n" #~ "However, GNUnet may not be able to access files other than its own. This " #~ "includes files you want to publish in GNUnet. You'll have to grant read " #~ "permissions to the user specified below.\n" #~ "\n" #~ "Leave the fields empty to run GNUnet with system privileges." #~ msgstr "" #~ "Define el usuario y el grupo bajo el que correrán los servicios de GNUnet " #~ "aquí.\n" #~ "\n" #~ "Por razones de seguridad, es una buena idea dejar que la configuración " #~ "cree una nueva cuenta de usuario y un nuevo grupo bajo el cual el " #~ "servicio de GNUnet es arrancado al iniciar el sistema.\n" #~ "\n" #~ "Por consiguiente, GNUnet no tiene la posibilidad de acceder a otros " #~ "ficheros que no sean los que posee. Ésto incluye los ficheros que quieras " #~ "publicar en GNUnet. Tendrás que garantizar que el usuario especificado " #~ "aquí posea permisos de lectura.\n" #~ "\n" #~ "Deja los campos vacíos para arrancar GNUnet con privilegios de sistema." #~ msgid "User account:" #~ msgstr "Cuenta de usuario:" #~ msgid "Group:" #~ msgstr "Grupo:" #~ msgid "gnunet-setup" #~ msgstr "gnunet-setup" #, fuzzy #~ msgid "Save configuration" #~ msgstr "Configuración de GNUnet" #, fuzzy #~ msgid "Show copyright information for gnunet-setup." #~ msgstr "Se produjo un error leyendo información de gnunetd.\n" #, fuzzy #~ msgid "About gnunet-setup" #~ msgstr "gnunet-setup" #, fuzzy #~ msgid "(C) 2001-2007 Christian Grothoff (and other contributing authors)" #~ msgstr "" #~ "C) 2001-2006 Christian Grothoff (y otros autores que han contribuido)" #~ msgid "This is the configuration tool for GNUnet." #~ msgstr "Esta es la herramienta de configuración de GNUnet." #~ msgid "Could not unlink temporary file `%s': %s\n" #~ msgstr "Imposible desenlazar temporalmente el fichero '%s': %s\n" #~ msgid "Write(%d, %p, %d) failed: %s\n" #~ msgstr "Escribiendo(%d, %p, %d) se produjo un fallo: %s\n" #~ msgid "AND" #~ msgstr "Y" #, fuzzy #~ msgid "Could not find IPv6 address of host `%s': %s\n" #~ msgstr "Imposible encontrar la IP del host '%s': %s\n" #, fuzzy #~ msgid "Error running search (no reason given)." #~ msgstr "Se produjo un fallo al comenzar la búsqueda. Consulte los logs.\n" #, fuzzy #~ msgid "Download failed (no reason given)" #~ msgstr "La descarga del ERCS falló (vea los logs)." #~ msgid "Maximum number of chat clients reached.\n" #~ msgstr "Número máximo de clientes en el chat alcanzado.\n" #~ msgid "Now %d of %d chat clients at this node.\n" #~ msgstr "Ahora hay %d de %d clientes de chat en este nodo.\n" #, fuzzy #~ msgid "Invalid data in %s (NCS). Trying to fix (by deletion).\n" #~ msgstr "Datos no válidos en %s. Intentando fijar (por borrado).\n" #~ msgid "HTTP: Could not determine my public IP address.\n" #~ msgstr "HTTP: Imposible determinar mi dirección IP pública.\n" #~ msgid "" #~ "%s::%s - RPC %s:%p could not be unregistered: another callback registered " #~ "under that name: %p\n" #~ msgstr "" #~ "%s::%s - RPC %s:%p no pudo ser desregistrada: otro evento está " #~ "actualmente registrado con este nombre (%p)\n" #~ msgid "%s::%s - RPC %s:%p could not be unregistered: not found\n" #~ msgstr "%s::%s - RPC %s:%p no pudo ser desregistrada: no encontrada\n" #~ msgid "Dropping RPC request %u: message malformed.\n" #~ msgstr "Omitiendo la petición RPC %u: mensaje mal formado.\n" #~ msgid "`%s' called with timeout above 1 hour (bug?)\n" #~ msgstr "'%s' fue llamada con un retraso de una hora(¿bug?)\n" #~ msgid "RPC not unregistered: %s:%p\n" #~ msgstr "No fue desregistrada RPC: %s:%p\n" #~ msgid "RPC async reply invalid.\n" #~ msgstr "RPC respuesta asíncrona no válida.\n" #~ msgid "async RPC reply not received.\n" #~ msgstr "respuesta RPC asíncrona no recibida.\n" #~ msgid "`%s': unknown service: %s\n" #~ msgstr "'%s': servicio desconocido: %s\n" #, fuzzy #~ msgid "# bytes received via TCP6" #~ msgstr "# bytes recibidos por TCP" #, fuzzy #~ msgid "# bytes sent via TCP6" #~ msgstr "# bytes enviados por TCP" #, fuzzy #~ msgid "# bytes dropped by TCP6 (outgoing)" #~ msgstr "# bytes omitidos por TCP (salientes)" #~ msgid "UDP6: Could not determine my public IPv6 address.\n" #~ msgstr "UDP6: Imposible determinar mi dirección IPv6 pública.\n" #, fuzzy #~ msgid "# bytes received via UDP6" #~ msgstr "# bytes recibidos vía UDP" #, fuzzy #~ msgid "# bytes sent via UDP6" #~ msgstr "# bytes enviados vía UDP" #, fuzzy #~ msgid "# bytes dropped by UDP6 (outgoing)" #~ msgstr "# bytes omitidos por UDP (salientes)" #, fuzzy #~ msgid "Received malformed message instead of welcome message. Closing.\n" #~ msgstr "Recibido el mensaje '%s' con un mal formato. Omitiendo.\n" #, fuzzy #~ msgid "Received malformed message from tcp-peer connection. Closing.\n" #~ msgstr "Recibido el mensaje '%s' con un mal formato. Omitiendo.\n" #, fuzzy #~ msgid "TCP: Could not determine my public IP address.\n" #~ msgstr "HTTP: Imposible determinar mi dirección IP pública.\n" #~ msgid "Cannot connect to %u.%u.%u.%u:%u: %s\n" #~ msgstr "Imposible conectar a %u.%u.%u.%u:%u: %s\n" #~ msgid "UDP: Could not determine my public IP address.\n" #~ msgstr "UDP: Imposible determinar mi dirección IP pública.\n" #~ msgid "Failed to send message of size %d via UDP to %u.%u.%u.%u:%u: %s\n" #~ msgstr "" #~ "Falló al mandar el mensaje de tamaño %d a través de UDP a %u.%u.%u.%u:%u: " #~ "%s\n" #, fuzzy #~ msgid "Received malformed message from udp-peer connection. Closing.\n" #~ msgstr "Recibido el mensaje '%s' con un mal formato. Omitiendo.\n" #~ msgid "exit after receiving LIMIT results" #~ msgstr "sale después de recibir LIMIT resultados" #, fuzzy #~ msgid "wait DELAY seconds for search results before aborting" #~ msgstr "espera TIMEOUT segundos para buscar resultados después de abortar" #~ msgid "Message received from peer is invalid.\n" #~ msgstr "El mensaje recibido del par es inválido.\n" #~ msgid "myself" #~ msgstr "yo" #~ msgid "" #~ "Cover traffic requested but traffic service not loaded. Rejecting " #~ "request.\n" #~ msgstr "" #~ "Solicitada la cobertura de tráfico pero el servicio de tráfico no ha sido " #~ "cargado. Rechazando la petición.\n" #~ msgid "Cannot satisfy desired level of anonymity, ignoring request.\n" #~ msgstr "" #~ "Imposible satisfacer el nivel deseado de anonimato, ignorando la " #~ "petición.\n" #~ msgid "`%s' registering handlers %d %d\n" #~ msgstr "'%s' registrando manejadores %d %d\n" #, fuzzy #~ msgid "Indexed file disappeared, deleting block for query `%s'\n" #~ msgstr "" #~ "Fichero indexado desaparecido, borrando el bloque para preguntas '%s'\n" #~ msgid "" #~ "Configuration file must specify directory for storage of FS data in " #~ "section `%s' under `%s'.\n" #~ msgstr "" #~ "El fichero de configuración debe especificar un directorio para el " #~ "almacenamiento de los datos de FS en la sección '%s' bajo '%s'.\n" #~ msgid "" #~ "Content `%s' seems to be not available on the network (tried %u times).\n" #~ msgstr "" #~ "El contenido '%s' parece no estar disponible en la red (intentado %u " #~ "veces).\n" #, fuzzy #~ msgid "Start GNUnet-testbed helper." #~ msgstr "Arranca el cliente de chat de GNUnet" #~ msgid "Cannot connect to LOOPBACK port %d: %s\n" #~ msgstr "Imposible conectar al puerto de LOOPBACK %d: %s\n" #~ msgid "No client service started. Trying again in 30 seconds.\n" #~ msgstr "" #~ "No hay ningún servicio de cliente ejecutandose. Se volverá a intentar en " #~ "30 segundos.\n" #, fuzzy #~ msgid "" #~ "Error (%s) binding the TCP listener to port %d. No proxy service " #~ "started.\n" #~ "Trying again in %d seconds...\n" #~ msgstr "" #~ "No hay ningún servicio de cliente ejecutandose. Se volverá a intentar en " #~ "30 segundos.\n" #~ msgid "Rejected unauthorized connection from %u.%u.%u.%u.\n" #~ msgstr "Rechazada conexión no autorizada de %u.%u.%u.%u.\n" #~ msgid "Protocol violation on socket. Expected command.\n" #~ msgstr "Violación del protocolo en el socket. Esperando comando.\n" #, fuzzy #~ msgid "Start GNUnet testbed controller." #~ msgstr "Arranca el cliente de chat de GNUnet" #~ msgid "Malformed entry in the configuration in section %s under %s: %s\n" #~ msgstr "" #~ "Entrada mal formada en la configuración en la sección %s bajo %s: %s\n" #~ msgid "size of `%s' message is wrong. Ignoring.\n" #~ msgstr "el tamaño del mensaje '%s' es erroneo. Se ignora.\n" #~ msgid "TESTBED could not generate hello message for protocol %u\n" #~ msgstr "" #~ "TESTBED no puede generar el mensaje de saludo para el protocolo %u\n" #~ msgid "received invalid `%s' message\n" #~ msgstr "recibido mensaje '%s' no válido\n" #~ msgid "received invalid `%s' message (empty module name)\n" #~ msgstr "recibido mensaje '%s' no válido (nombre del módulo vacío)\n" #~ msgid "loading module `%s' failed. Notifying client.\n" #~ msgstr "" #~ "se produjo un fallo al cargar el módulo '%s'. Notificando al cliente.\n" #~ msgid "unloading module failed. Notifying client.\n" #~ msgstr "" #~ "se produjo un fallo al descargar el módulo. Notificando al cliente.\n" #~ msgid "received invalid `%s' message: %s.\n" #~ msgstr "recibido mensaje '%s' no válido: %s.\n" #~ msgid "'..' is not allowed in file name (%s).\n" #~ msgstr "'..' no esta permitido en el nombre del fichero(%s).\n" #~ msgid "Empty filename for UPLOAD_FILE message is invalid!\n" #~ msgstr "" #~ "¡Nombre del fichero vacío para el mensaje UPLOAD_FILE es inválido!\n" #~ msgid "Filename for UPLOAD_FILE message is not null-terminated (invalid!)\n" #~ msgstr "" #~ "Nombre del fichero para el mensaje UPLOAD_FILE no esta terminado en null " #~ "(¡inválido!)\n" #~ msgid "Invalid message received at %s:%d." #~ msgstr "Mensaje inválido recibido en %s:%d." #, fuzzy #~ msgid "received invalid testbed message of size %u\n" #~ msgstr "recibido mensaje '%s' no válido: %s.\n" #~ msgid "Could not resolve name of HTTP proxy `%s'.\n" #~ msgstr "Imposible resolver el nombre del proxy HTTP '%s'.\n" #, fuzzy #~ msgid "Could not register testbed, host `%s' unknown\n" #~ msgstr "" #~ "Imposible descargar lista de contactos, servidor '%s' desconocido.\n" #~ msgid "Failed so send HTTP request `%s' to host `%s': %s\n" #~ msgstr "Falló al mandar la petición HTTP '%s' al host '%s': %s\n" #~ msgid "Exit register (error: no http response read).\n" #~ msgstr "Saliendo del registro (error: no se leyó una respuesta de http).\n" #, fuzzy #~ msgid "Description" #~ msgstr "Pregunta" #, fuzzy #~ msgid "Section" #~ msgstr "Pregunta" #, fuzzy #~ msgid "Option" #~ msgstr "_Opciones" #~ msgid "Sending E-mail to `%s' failed.\n" #~ msgstr "Enviando un correo electrónico a '%s' se produjo un fallo.\n" #, fuzzy #~ msgid "Network configuration: NAT" #~ msgstr "Configuración de GNUnet" #~ msgid "" #~ "Is this machine behind NAT?\n" #~ "\n" #~ "If you are connected to the internet through another computer doing SNAT, " #~ "a router or a \"hardware firewall\" and other computers on the internet " #~ "cannot connect to this computer, say \"yes\" here. Answer \"no\" on " #~ "direct connections through modems, ISDN cards and DNAT (also known as " #~ "\"port forwarding\")." #~ msgstr "" #~ "¿Tu máquina esta detrás de un NAT?\n" #~ "\n" #~ "Si tu estás conectado a Internet a través de otro ordenador haciendo " #~ "SNAT, un router o un \"cortafuegos de hardware\" y otros ordenadores no " #~ "pueden conectarse al tuyo a través de Internet directamente, responde \"si" #~ "\" aquí. Responde \"no\" en conexiones directas a través de módems, " #~ "tarjetas de RDSI y DNAT (también conocido como \"seguimiento de puertos" #~ "\")." #, fuzzy #~ msgid "Configuration of the logging system" #~ msgstr "" #~ "La configuración o la versión de GNUnet cambiaron. ¡Debes ejecutar " #~ "'%s'!\n" #, fuzzy #~ msgid "Run gnunetd as this user." #~ msgstr "Ejecutar gnunet-update" #, fuzzy #~ msgid "Run gnunetd during system startup?" #~ msgstr "Ejecutar gnunet-update" #, fuzzy #~ msgid "Path settings" #~ msgstr "Otras configuraciones" #~ msgid "specify nickname" #~ msgstr "especifica el apodo" #~ msgid "You must specify a nickname (use option `%s').\n" #~ msgstr "Debes especificar un apodo (use la opción '%s').\n" #~ msgid "mysql datastore" #~ msgstr "base de datos mysql" #, fuzzy #~ msgid "" #~ "`%s' failed at %s:%d with error: I/%s S/%s SC/%s SS/%s SSC/%s U/%s D/%s " #~ "DG/%s\n" #~ msgstr "'%s' falló en %s: %d con el error: %s\n" #~ msgid "Database failed to delete `%s'.\n" #~ msgstr "Falló al borrar de la base de datos %s.\n" #, fuzzy #~ msgid "Error log:\n" #~ msgstr "Error" #, fuzzy #~ msgid "# bytes received via TCP-OLD" #~ msgstr "# bytes recibidos por TCP" #, fuzzy #~ msgid "# bytes sent via TCP-OLD" #~ msgstr "# bytes enviados por TCP" #, fuzzy #~ msgid "# bytes dropped by TCP-OLD (outgoing)" #~ msgstr "# bytes omitidos por TCP (salientes)" #~ msgid "hello advertisement for protocol %d received.\n" #~ msgstr "Inicio de comunicación del protocolo %d recibido.\n" #~ msgid "`%s' failed (%d, %u). Will not send PING.\n" #~ msgstr "'%s' falló (%d, %u). No se mandará el PING.\n" #~ msgid "Removing hello from peer `%s' (expired %ds ago).\n" #~ msgstr "Eliminando saludo del par '%s' (expiró hace %ds).\n" #~ msgid "Waiting for gnunetd to start (%u iterations left)...\n" #~ msgstr "Esperando a gnunetd para empezar (%u ciclos restantes)...\n" #, fuzzy #~ msgid "Deleting expired content. This may take a while.\n" #~ msgstr "Creando nueva clave local (esto puede llevar un tiempo).\n" #~ msgid "User `%s' not known, cannot change UID to it.\n" #~ msgstr "Usuario '%s' desconocido, imposible cambiar la UID a él.\n" #~ msgid "" #~ "Expected welcome on http connection, got garbage. Closing connection.\n" #~ msgstr "" #~ "Esperada bienvenida en la conexión http, encontrada basura. Cerrando la " #~ "conexión.\n" #~ msgid "%s: Rejected connection from blacklisted address %u.%u.%u.%u.\n" #~ msgstr "" #~ "%s: Conexión rechazada de una dirección de la \"lista negra\" %u.%u.%u." #~ "%u.\n" #~ msgid "Unexpected reply to `%s' operation.\n" #~ msgstr "Respuesta inesperada a la operación '%s'.\n" #~ msgid "join table called NAME" #~ msgstr "únete a la tabla llamada NAME" #~ msgid "Malformed optional field `%s' received from peer `%s'.\n" #~ msgstr "Campo opcional anómalo '%s' recibido del par '%s'.\n" #~ msgid "Malformed response to `%s' on master table.\n" #~ msgstr "Respuesta anómala a '%s' en la tabla maestra.\n" #~ msgid "Invalid response to `%s' from `%s'\n" #~ msgstr "Respuesta inválida a '%s' de '%s'\n" #~ msgid "Received invalid RPC `%s'.\n" #~ msgstr "Recibido RPC '%s' inválida.\n" #~ msgid "RPC for `%s' received for table that we do not participate in!\n" #~ msgstr "¡RPC para '%s' recibida de la tabla en la cual no participamos!\n" #~ msgid "`%s' failed. Terminating connection to client.\n" #~ msgstr "'%s' falló. Finalizando conexión con el cliente.\n" #~ msgid "" #~ "Share denoted bandwidth with other applications?\n" #~ "\n" #~ "Say \"yes\" here, if you don't want other network traffic to interfere " #~ "with GNUnet's operation, but still wish to constrain GNUnet's bandwidth " #~ "usage to values entered in the previous steps, or if you can't reliably " #~ "measure the maximum capabilities of your connection. \"No\" can be very " #~ "useful if other applications are causing a lot of traffic on your LAN. " #~ "In this case, you do not want to limit the traffic that GNUnet can " #~ "inflict on your internet connection whenever your high-speed LAN gets " #~ "used (e.g. by NFS)." #~ msgstr "" #~ "¿Compartir el ancho de banda marcado con otras aplicaciones?\n" #~ "\n" #~ "Di \"sí\" aquí si no quieres que el resto del tráfico de la red no " #~ "interfiera con las operaciones de GNUnet, pero aun quieres mantener el " #~ "ancho de banda usado por GNUnet introducido en los pasos previos, o no " #~ "puedes asegurar las máximas capacidades de tu conexión. \"No\" puede ser " #~ "muy útil si otras aplicaciones crean mucho tráfico en tu LAN. En ese " #~ "caso no quieres limitar el tráfico que GNUnet puede crear en tu conexión " #~ "a Internet cuando una LAN de alta velocidad es usada (por ejemplo bajo " #~ "NFS)." #~ msgid "How much CPU (in %) may be used?" #~ msgstr "¿Cuánta CPU (en %) podrá ser usada?" #~ msgid "" #~ "You can limit GNUnet's resource usage here.\n" #~ "\n" #~ "This is the percentage of processor time GNUnet is allowed to use." #~ msgstr "" #~ "Tu puedes limitar el uso de recursos de GNUnet aquí.\n" #~ "\n" #~ "Este es el porcentaje del tiempo del procesador que GNUnet puede usar." #~ msgid "" #~ "Store migrated content?\n" #~ "\n" #~ "GNUnet is able to store data from other peers in your datastore. This is " #~ "useful if an adversary has access to your inserted content and you need " #~ "to deny that the content is yours. With \"content migration\" on, the " #~ "content could have \"migrated\" over the internet to your node without " #~ "your knowledge.\n" #~ "It also helps to spread popular content over different peers to enhance " #~ "availability." #~ msgstr "" #~ "¿Almacena el contenido migrado?\n" #~ "\n" #~ "GNUnet puede almacenar datos de otros pares en tu ordenador. Esto es muy " #~ "útil si un adversario accede a tu contenido insertado y necesitas negar " #~ "que dicho contenido sea tuyo. Con la \"migración de contenidos\" " #~ "activada, el contenido puede haber \"migrado\" a través de internet a tu " #~ "nodo sin tu conocimiento.\n" #~ "Ésto también ayuda a repartir contenido popular a través de diferentes " #~ "pares para aumentar la disponibilidad." #~ msgid "" #~ "If you are an experienced user, you may want to tweak your GNUnet " #~ "installation using the enhanced configurator.\n" #~ "\n" #~ "Do you want to start it after saving your configuration?" #~ msgstr "" #~ "Si eres un usuario experimentado, puedes desear exprimir tu instalación " #~ "de GNUnet usando la herramienta de configuración avanzada.\n" #~ "\n" #~ "¿Quieres arrancarla después de guardar tu configuración?" #~ msgid "" #~ "Unable to save configuration file %s: %s.\n" #~ "\n" #~ "Try again?" #~ msgstr "" #~ "Imposible guardar el fichero de configuración %s: %s.\n" #~ "\n" #~ "¿Intentar de nuevo?" #~ msgid "Failed to send `%s'. Closing connection.\n" #~ msgstr "Fallo al mandar '%s'. Cerrando la conexión.\n" #~ msgid "Received invalid `%s' request (size %d)\n" #~ msgstr "Recibida petición '%s' no válida (tamaño %d)\n" #~ msgid "Received invalid `%s' request (wrong table)\n" #~ msgstr "Recibida petición '%s' no válida (tabla errónea)\n" #~ msgid "This client already participates in the given DHT!\n" #~ msgstr "Este cliente ya participa en el DHT dado\n" #~ msgid "Cannot leave DHT: table not known!\n" #~ msgstr "Imposible dejar DHT: ¡tabla no conocida!\n" #~ msgid "gnunetd signaled error in response to `%s' message\n" #~ msgstr "gnunetd lanzó una señal de error en respuesta al mensaje '%s'\n" #~ msgid "Failed to send `%s' message to gnunetd\n" #~ msgstr "Falló al mandar el mensaje '%s' a gnunetd\n" #~ msgid "Join a DHT." #~ msgstr "Únete a DHT" #~ msgid "allow SIZE bytes of memory for the local table" #~ msgstr "Reserva SIZE bytes de memoria para la tabla local" #~ msgid "Call to `%s' with value '%.*s' (%d bytes).\n" #~ msgstr "Llama a '%s' con el valor '%.*s' (%d bytes).\n" #~ msgid "Error joining DHT.\n" #~ msgstr "Error uniéndose a DHT.\n" #~ msgid "Joined DHT. Press CTRL-C to leave.\n" #~ msgstr "Unido a DHT. Pulsa CTRL-C para abandonarlo.\n" #~ msgid "`%s' failed: table not found!\n" #~ msgstr "'%s' falló: ¡tabla no encontrada!\n" #~ msgid "sendAck failed. Terminating connection to client.\n" #~ msgstr "sendAck falló. Finalizando conexión con el cliente.\n" #, fuzzy #~ msgid "Upload failed (consult logs)." #~ msgstr "La descarga del ERCS falló (vea los logs)." #~ msgid "Could not resolve name of SMTP server `%s': %s" #~ msgstr "Imposible resolver el nombre del servidor de SMTP '%s': %s" #~ msgid "query table called NAME" #~ msgstr "pregunta a la tabla llamada NAME" #~ msgid "No commands specified.\n" #~ msgstr "Ningún comando fue especificado.\n" #~ msgid "Superflous arguments (ignored).\n" #~ msgstr "Argumentos superfluos (ignorados).\n" #~ msgid "Query `%s' had no results.\n" #~ msgstr "La pregunta '%s' no tuvo resultados.\n" #~ msgid "FSUI persistence: error restoring download\n" #~ msgstr "FSUI persistente: error restableciendo la descarga\n" #~ msgid "ECRS download suspending." #~ msgstr "La descarga del ERCS fue suspendida." #~ msgid "Upload failed." #~ msgstr "Subida fallida" #~ msgid "Cannot upload directory without using recursion." #~ msgstr "Imposible compartir un directorio sin hacerlo recursivamente." #, fuzzy #~ msgid "expected `%s' to be a directory!\n" #~ msgstr "¡'%s' se esperaba que '%s' fuera un directorio!\n" #~ msgid "Sorry, no help is available for this option.\n" #~ msgstr "Lo siento, no hay ayuda disponible para esta opción.\n" #~ msgid "%s: Rejected connection from blacklisted address %s.\n" #~ msgstr "%s: Conexión rechazada de una dirección de la \"lista negra\" %s.\n" #~ msgid "Received invalid UDP message from %u.%u.%u.%u:%u, dropping.\n" #~ msgstr "Recibido mensaje UDP no válido del %u.%u.%u.%u:%u, omitiendo.\n" #~ msgid "" #~ "Configuration file must specify directory for storing FS data in section `" #~ "%s' under `%s'.\n" #~ msgstr "" #~ "El fichero de configuración debe especificar el directorio para almacenar " #~ "los datos FS en la sección '%s' bajo '%s'.\n" #~ msgid "" #~ "Configuration file must specify a directory for GNUnet to store per-peer " #~ "data under %s%s\n" #~ msgstr "" #~ "El fichero de configuración debe especificar un directorio para que " #~ "GNUnet almacene la información por-par bajo%s%s\n" #~ msgid "%s `%s' returned no known hosts!\n" #~ msgstr "¡%s '%s' devolvió hosts desconocidos!\n" #~ msgid "" #~ "specify that the contents of the namespace are of the given MIMETYPE (use " #~ "when creating a new pseudonym)" #~ msgstr "" #~ "especifica que los contenidos del espacio son del MIMETYPE dado (úsalo " #~ "cuando crees un nuevo pseudónimo)" #~ msgid "" #~ "specify NAME to be the realname of the user controlling the namespace " #~ "(use when creating a new pseudonym)" #~ msgstr "" #~ "especifica el NAME para ser el nombre real del usuario que controla el " #~ "espacio (úsalo cuando crees un nuevo pseudónimo)" #~ msgid "" #~ "use DESCRIPTION to describe the content of the namespace (use when " #~ "creating a new pseudonym)" #~ msgstr "" #~ "usa la DESCRIPTION para describir el contenido del espacio (úsalo cuando " #~ "crees un nuevo pseudónimo)" #~ msgid "" #~ "specify the given URI as an address that contains more information about " #~ "the namespace (use when creating a new pseudonym)" #~ msgstr "" #~ "especifica la URI dada como dirección que contiene mas información del " #~ "espacio (úsalo cuando crees un nuevo pseudónimo)" #~ msgid "%8u of %8u bytes deleted." #~ msgstr "%8u de %8u bytes borrados." #~ msgid "specify the file to delete from GNUnet (obligatory, file must exist)" #~ msgstr "" #~ "especifica el fichero a borrar de GNUnet (el fichero debe existir " #~ "obligatoriamente)" #~ msgid "" #~ "Remove file from GNUnet. The specified file is not removed\n" #~ "from the filesystem but just from the local GNUnet datastore." #~ msgstr "" #~ "Borra el fichero de GNUnet. El fichero especificado no es borrado\n" #~ "del sistema de ficheros, solamente de la base de datos local de GNUnet." #~ msgid "You must specify a filename (option -f)\n" #~ msgstr "Debes especificar un fichero (opción -f)\n" #~ msgid "" #~ "Error deleting file %s.\n" #~ "Probably a few blocks were already missing from the database.\n" #~ msgstr "" #~ "Error borrando el fichero %s.\n" #~ "Probablemente algunos bloques se hayan perdido de la base de datos.\n" #~ msgid "gnunet-directory [OPTIONS] [FILENAMES]" #~ msgstr "directorio-de-gnunet [OPCIONES] [FICHEROS]" #~ msgid "process directories recursively" #~ msgstr "procesa los directorios recursivamente" #~ msgid "You must pass a positive number to the `%s' option.\n" #~ msgstr "Debes pasar un número positivo a la opción '%s'.\n" #~ msgid "Only one file or directory can be specified at a time.\n" #~ msgstr "Solo un fichero o un directorio puede ser especificado cada vez.\n" #~ msgid "You must specify a file or directory to upload.\n" #~ msgstr "Debes especificar un fichero o directorio para subir.\n" #~ msgid "Not enough arguments. You must specify a keyword or identifier.\n" #~ msgstr "" #~ "No hay suficientes argumentos. Debes especificar una clave o un " #~ "identificador.\n" #~ msgid "LEVEL" #~ msgstr "NIVEL" #~ msgid "FILENAME" #~ msgstr "FICHERO" #~ msgid "" #~ "Configuration file must specify a directory for GNUnet to store per-peer " #~ "data under %s%s.\n" #~ msgstr "" #~ "El fichero de configuración debe especificar un directorio para que " #~ "GNUnet almacene la información por-par bajo %s%s.\n" #~ msgid "Template for gnunet-clients." #~ msgstr "Plantilla para clientes-de-gnunet." #~ msgid "Invalid port \"%s\" in hostlist specification, trying port %d.\n" #~ msgstr "" #~ "Puerto inválido \"%s\" en la especificación de la lista local, probando " #~ "el puerto %d.\n" #~ msgid "Parsing HTTP response for URL `%s' failed.\n" #~ msgstr "Analizando HTTP de la URL '%s' se produjo un fallo.\n" #~ msgid "Could not resolve name of HTTP proxy `%s'. Trying without a proxy.\n" #~ msgstr "" #~ "Imposible resolver el nombre del proxy HTTP '%s'. Intentándolo sin un " #~ "proxy.\n" #~ msgid "Option `%s' makes no sense without option `%s'." #~ msgstr "La opción '%s' no tiene ningún sentido sin la opción '%s'." #~ msgid "" #~ "\n" #~ "Exiting.\n" #~ msgstr "" #~ "\n" #~ "Saliendo.\n" #~ msgid "Updated data for %d applications.\n" #~ msgstr "Actualizados los datos para %d aplicaciones.\n" #~ msgid "Argument %d: `%s'\n" #~ msgstr "Argumento %d: '%s'\n" #~ msgid "`%s' starting\n" #~ msgstr "'%s' comenzando\n" #~ msgid "FATAL: Identity plugin not found!\n" #~ msgstr "FATAL: ¡Plugin de identidad no encontrado!\n" #~ msgid "Available MODEs:\n" #~ msgstr "MODOs disponibles:\n" #~ msgid " config\t\ttext-based configuration\n" #~ msgstr " configuración\t\tconfiguración basada en texto\n" #~ msgid " menuconfig\ttext-based menu\n" #~ msgstr " menuconfig\tmenú basado en texto\n" #~ msgid " wizard-curses\tBasic text-based graphical configuration\n" #~ msgstr "" #~ " wizard-curses\t Configuración básica en modo gráfico pero basado en " #~ "texto\n" #~ msgid "" #~ " wizard-gtk\tBasic GTK configuration\n" #~ "\n" #~ msgstr "" #~ " wizard-gtk\tConfiguración GTK básica\n" #~ "\n" #~ msgid "gnunet-setup must have write-access to the configuration file `%s'\n" #~ msgstr "" #~ "gnunet-setup debe tener acceso de escritura al fichero de configuración " #~ "'%s'\n" #, fuzzy #~ msgid "" #~ "Can only run wizard to configure gnunetd.\n" #~ "Did you forget the `%s' option?\n" #~ msgstr "" #~ "Solo se puede arrancar wizard para configurar gnunetd.\n" #~ "¿Te olvidaste de la opción %s'?\n" #~ msgid "Gtk GNUnet Configurator" #~ msgstr "Configurador Gtk de GNUnet" #~ msgid "_File" #~ msgstr "_Fichero" #~ msgid "_Load" #~ msgstr "_Cargar" #~ msgid "Save the config in .config" #~ msgstr "Guardar la configuración en .config" #~ msgid "_Save" #~ msgstr "_Guardar" #~ msgid "_Quit" #~ msgstr "_Salir" #~ msgid "Show _name" #~ msgstr "Mostrar el _nombre" #~ msgid "Show range (Y/M/N)" #~ msgstr "Muestra el rango (Y/M/N)" #~ msgid "Show _range" #~ msgstr "Muestra el _rango" #~ msgid "Show _data" #~ msgstr "Mostrar los _datos" #~ msgid "Show all _options" #~ msgstr "Mostrar todas las _opciones" #~ msgid "_Help" #~ msgstr "_Ayuda" #~ msgid "_Introduction" #~ msgstr "_Introducción" #~ msgid "Goes up of one level (single view)" #~ msgstr "Sube un nivel (vista única)" #~ msgid "Load" #~ msgstr "Cargar" #~ msgid "Save a config file" #~ msgstr "Guardar un fichero de configuración" #~ msgid "Save" #~ msgstr "Guardar" #~ msgid "Single view" #~ msgstr "Vista única" #~ msgid "Single" #~ msgstr "Única" #~ msgid "Split view" #~ msgstr "Vista doble" #~ msgid "Split" #~ msgstr "Doble" #~ msgid "Full view" #~ msgstr "Vista completa" #~ msgid "Full" #~ msgstr "Completa" #~ msgid "Collapse the whole tree in the right frame" #~ msgstr "Contraer el árbol completo en el lateral izquierdo" #~ msgid "Collapse" #~ msgstr "Contraer" #~ msgid "Expand the whole tree in the right frame" #~ msgstr "Expandir el árbol entero en el lateral izquierdo" #~ msgid "Expand" #~ msgstr "Expandir" #~ msgid "" #~ "This is GNUnet's configuration interface.\n" #~ "\n" #~ "GNUnet's options are separated into categories. You can browse them in " #~ "the left tree. If you click on one of the categories, its options are " #~ "shown above. \n" #~ "\n" #~ "To change the value of an option, simply click on its value and enter a " #~ "new value. To get additional information about a specific option, click " #~ "on its description." #~ msgstr "" #~ "Ésta es la interfaz de configuración de GNUnet.\n" #~ "\n" #~ "Las opciones de GNUnet están separadas en categorías. Tu puedes " #~ "explorarlas en el árbol de la izquierda. Si pulsas en una de las " #~ "categorías las opciones son mostradas encima.\n" #~ "\n" #~ "Para cambiar el valor de una opción, simplemente pulsa en su valor e " #~ "introduce uno nuevo. Para obtener información adicional acerca de una " #~ "opción específica, pulsa en su descripción." #~ msgid "Introduction" #~ msgstr "Introducción" #, fuzzy #~ msgid "" #~ "Welcome to GNUnet Setup.\n" #~ "\n" #~ "For each option, a blank box indicates the feature is disabled, and " #~ "checked one indicates it is enabled.\n" #~ "If you do not see an option that you believe should be present, try " #~ "turning on Show All Options under the Options menu.\n" #~ "\n" #~ "Although there is no cross reference yet to help you figure out what " #~ "other options must be enabled to support the option you are interested " #~ "in, you can still view the help of a grayed-out option.\n" #~ "\n" #~ "Toggling Show Debug Info under the Options menu will show the " #~ "dependencies, which you can then match by examining other options." #~ msgstr "" #~ "Bienvenido a la configuración de GNUnet.\n" #~ "\n" #~ "Para cada opción una caja en blanco indica que la opción está desactivada " #~ "y una marcada indica que está activada.\n" #~ "Si no ves una opción que crees que debería estar presente, prueba " #~ "activando la opción \"Mostrar todas las opciones\" en el menú de " #~ "\"Opciones\".\n" #~ "\n" #~ "Although·there·is·no·cross·reference·yet·to·help·you·figure·out·what·other·options·must·be·enabled·to·support·the·option·you·are·interested·in," #~ "·you·can·still·view·the·help·of·a·grayed-out·option.\n" #~ "\n" #~ "Toggling·Show·Debug·Info·under·the·Options·menu·will·show·the·dependencies," #~ "·which·you·can·then·match·by·examining·other·options." #~ msgid "" #~ "Configuration file not found. Please run GNUnet Setup (Client " #~ "Configuration) first." #~ msgstr "" #~ "Fichero de configuración no encontrado. Por favor, ejecuta GNUnet Setup " #~ "(Configuración del cliente) primero." #~ msgid "Configuration file `%s' not found. Run `gnunet-setup -d'!\n" #~ msgstr "" #~ "El·fichero·de·configuración·'%s'·no·ha·sido·encontrado.··¡Ejecute·'gnunet-" #~ "setup -d'!\n" #~ msgid "Cron stopped\n" #~ msgstr "Cron detenido\n" #~ msgid "Caught signal %d.\n" #~ msgstr "Cogida señal %d.\n" #~ msgid "Invalid network notation (additional characters: `%s')." #~ msgstr "Notación de red no válida (caracteres adicionales: '%s')." #~ msgid "FAILURE" #~ msgstr "FALLO" #~ msgid "MESSAGE" #~ msgstr "MENSAJE" #~ msgid "CRON" #~ msgstr "CRON" #~ msgid "EVERYTHING" #~ msgstr "TODO" #~ msgid "Invalid LOGLEVEL `%s' specified.\n" #~ msgstr "LOGLEVEL inválido '%s' especificado.\n" #~ msgid "" #~ "Cannot determine port of gnunetd server. Define in configuration file in " #~ "section `%s' under `%s'.\n" #~ msgstr "" #~ "Imposible determinar el puerto del servidor de gnunetd. Defínelo en el " #~ "fichero de configuración en la sección '%s' bajo '%s'.\n" #~ msgid "" #~ "Usage: %s\n" #~ "%s\n" #~ "\n" #~ msgstr "" #~ "Uso: %s\n" #~ "%s\n" #~ "\n" #~ msgid "Invalid argument for `%s' at %s:%d.\n" #~ msgstr "Argumento no válido para '%s' en %s:%d.\n" #~ msgid "g" #~ msgstr "g" #~ msgid "t" #~ msgstr "t" #~ msgid "`%s' failed, other side closed connection.\n" #~ msgstr "'%s' falló, conexión cerrada en el otro lado.\n" #~ msgid "Attempted path to `%s' was `%s'.\n" #~ msgstr "La ruta esperada a '%s' fue '%s'.\n" gnunet-0.9.3/po/en@boldquot.header0000644000175000017500000000247111260753602014016 00000000000000# All this catalog "translates" are quotation characters. # The msgids must be ASCII and therefore cannot contain real quotation # characters, only substitutes like grave accent (0x60), apostrophe (0x27) # and double quote (0x22). These substitutes look strange; see # http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html # # This catalog translates grave accent (0x60) and apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019). # It also translates pairs of apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019) # and pairs of quotation mark (0x22) to # left double quotation mark (U+201C) and right double quotation mark (U+201D). # # When output to an UTF-8 terminal, the quotation characters appear perfectly. # When output to an ISO-8859-1 terminal, the single quotation marks are # transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to # grave/acute accent (by libiconv), and the double quotation marks are # transliterated to 0x22. # When output to an ASCII terminal, the single quotation marks are # transliterated to apostrophes, and the double quotation marks are # transliterated to 0x22. # # This catalog furthermore displays the text between the quotation marks in # bold face, assuming the VT100/XTerm escape sequences. # gnunet-0.9.3/po/LINGUAS0000644000175000017500000000005711610064747011417 00000000000000# set of available languages vi de sv es zh_CN gnunet-0.9.3/contrib/0000755000175000017500000000000011763406747011503 500000000000000gnunet-0.9.3/contrib/testing_hostkeys.dat0000644000175000017500001521752211523626760015533 00000000000000’€€ÀåñÜ÷¢6¯]’‹íléÞ‘¯Uøê‘—— ®9"&ú|¾Tô˜1Ü/âl‚J…ç¿—Àä4 ·fa«€*÷š«6lq¦°íšÞëºéUœ&tÇìJê ãF¶²€+qÀ´ÈÈ ›l|ÇFáq´2ziÜIÖdAñâir"¼P+Qr'' ŸpÔáM‚å.™{zU÷OEÕHx¢©[ò´*©ÎE<¼:}$ÊAv}_ä‡Í[¦À1Ãê´âÖü«ÏQ¡á"À©¹á@ÕØ-ÙYß3ë4d\°ë æ¶}µ Mñz± ª ñq8UÐ_ž8UŒïÜb)—{”ùÿº†š8Õú~øå>²âÄå×÷ÒkIOvžÌAM*¦yàrÅ- KÐN'UC>JþáÉä3u.‰š»¶pA»}Ì¡.7³ÉE”gç.s˜XzÚX[Ý>ÆT…¬Æ6H‚ÕrÍ“‡8Ð@3âxX-(u­¤÷³!³æäpQ3Ð9aq ¢§Ð:æ{r‚;L™ ~hŠ=^,2ØÛJ&&î ŽVz¾ç U)ž¯¥d&`øá.ƒe2„yx!Ê!a ¼˜ˆç+Mô” {sðé`¯Ù Y¥.NÌ]RNV?¥jK“¸•¢a¹zp©d{¶Ú͹Y62U©iÌÀY ×½sk ;Ë\ca•/Ô¦œþÊÞøó]1ýŽ»¯qtw#@FßбïÇðqÍç‘ö¬M„Œ÷P|Èy¦´–€*DMMÍ íz®p.F½?ý £’€€ÕÜ*H¾ BÞ;˜ò¾5¦H‘+¸E?wß²£…g'ˆ˜qÕûo†ŒP¢Ât¤ÈK¯äÛ7Ÿ—Ró LLOAH™§îŒËæÛ´åx¬m„OÈfènÅš)ÌœLpØfŒˆCÀžÁûj>^ÞP£Ÿ|lžðj\‡† M¶ÖÊ Þê²néù rÛcT]…hMÏJyë~ýÜUÊm¢êÐ]á°A<¦d åb#åÏ·[„U%_ÑúGØóStùþEµÓðYÓ‚q$( ô»ÇÝ·+Æ[5¥ùQ]çÙ:' n E5<U£¬üOاâ[^ t¨íûÇIȃ ;àZ{‰ý뜈ÄCˆå_t3š Î÷äçšîŒú¹JÖ&2–,.f24 ˆ¸nBM°{SÏ«4¤O¶OÞ@Ù’ÙæÅÐ9ßõ'TÃv¾S'¯»åNûBÅ$æçHJ^9ˆ‘¸HpÏÑ÷ŸS˵0bQÇ\ö± 7 :;b¨ëèÈ&:¼$È.=Ó7DºñœÇY5§Ñsåô9\iÜÉ.GÓo…´ÎQæ$©“qfÇÕÉM„ZõÖêÚö7ËÅÙo;|º±yÖ¨4*¥ëiâüß¹ .Ì9üÂgkn «¿ÐÞ„¤s'Ã4eŽMãoíΫQüÖé£Bü6Ù¥û‰‰Ø¹ç[Q`Ÿ§Yz¢ÝãH¹!¨1*M%…¸âó!0v¯ØŠEQ2üœìpz‰‘¡¡‡}âh/þÓsèºv©g,ñŠÏæ{‚ò”~x"òþÌiU¶dï/ ZI™ÉúŒÝÒ½>öLr¬m•ÕÌÛ­ßd½rÓ_GÙ§òîµ2Éùôå{·ÂÇ«JìûŸf“Û×<ÏOªA4Ô¾©PìÂxäBSDp2<*Ç} §± YÅQûš<(cBÅý†³U‡áúØ…¬ˆ Ba":øÊZJEW-e¿yøöšU:®F¾ß#¼FÚióüÛÒ™{™åÄî­qRŽ£<îŸR‘4Áà’Z'´'£O·’+ÛÒoXøKæp2J[‹Äl£]”…xÇQ÷qä`qB×wòJ+FDçuxy߯zïà?ÙX²`®ÌB\\ýãî n>êÔH?TM©}ªAä8“¢“–Ê»ÕS'M2J‘n ÚQ˜)’€€ÆCO{/0FC+¬ëœ% Ö »í—~‡ÐÛ²C¥²(ZÜü M É¿#¢zÒÑÙOøIe­q¨9qø|ñ¯áI"è}O6àh\4pè£Y»|úÄ2þƒ'˜È*]óR^RéM¾.<Ìø¢ÞEøå+eížEAî#° èôæ¤_úÄF÷ÄubH>|œŠ1yN¬¸W?uþ;i{mÔ¶9j½=3d6Vò¤€E€ü˜ÝŠçð#È«¸,ÎÉ,òŠoÃ'iìÏËëë¡>Ø¢­‹M‹ÉÅuúªmµ¾ÓÜkÍ”ñžw~~äùì¿'V\1ϱá(}µD<Ü¡yOÞ–#‡ë>s+Ùë.›çG€WÌ¥&Ø)eòÉŽ|1"ËÇí‡P3j_{\/rq0î6‰}˜~pp(ñf•ü±å,*‡lÔ¸ G©ì©[ÐëŒd5Rª8OCU¡ƒ …?ÌÐR]gÌ-šU[têïµ^ )I®õ¥…hWhÆN‡s€õ~ýÌ·Ÿ¦ú¨+ ÀÐÈ£ØyñŽVs°ôdlç!µÍ):V±‘OYåQüƒ?Ë, ’‰­½ÉTl5!ê†#&åuF±¯›VàoñÍ¥šÔ m»ø\\¢Ø?±MsƳµXäeÇ, ŽíwDg›ïÇ8} V³hÇB¡´ÎÙÚñŸSÑg“âKaÍ¿ö½lñRÞ0ºfæñ7èjeþ0HЄñÚº‘85Ø< S“`;0ü}™Ïv¶ÌAj5Î%ùŽöÝDÑ’K±}vd¤Ý0kàï‡!ÙÛ‘éa„Ò-‚Â$Ñqûˆˆ0ctÅlúÔ©\TTýÓ˜’ójÇš>2Óº¸ï”²5],®ŽXî_ÜWgÐ]9ùÍ- Ó5#ø¾<¨—¸P5Ä&Š¥v’€€ô ÆZ¸Õ¹ò1=ÂB¬×ØÌò[Нɻ´ð¾Tˆ„º$ìmFg{ ÄW Q-ŸÐ…“ÏIµRæO:Zµä6LCõY¾Òlùà,øW½1¨nß»5öøù7†ó4Éݯ'¤v^h…\Ëb0»Låù0–A…þêŒGÖWÞ(¥Ó8Êô:D¸ëXIÖkGD‹ÏÕ/†÷moI%UÿÝz}ÿýFæûô¦¿B>¦Å¿BDÊþò‡Ùª2€õU¦ÏxdÂγÿM>×õܶ& e%Mú::C+i½¯a^&(µä·)‰È{,Äb}äýËA=HKdÊâïÕÛŒã<ç9Ci—m]5œí?{FŠQ;{^FZ+þ¢\®\º©2Å–¬#~V£†Y¹½pb¿Õ„²¶¸d¡ˆËŠõ.réßoh›PÂJÁËë¼!ï¦Æ<>32¼íºÐ~èYOÊjÜ Ô{¨ZõKK\Wðt%_µ•ÿÉé–vÚ(â¬Î ™q€—!Ü©ÏÛ=·2bT§q¢„7Øû‡ö]'^ Ì€a½ß^â1ŽÜß+oê-*@¾¡W Ùß='!õ9ÿoÐŽ•†rð[üp\e­•[&²[½Kû°¦á´hýóÀŠ q Ùq!?áà¶‚ÛQ²‡!ÓµÔÕߪS/«êMû˜{'ùþN”Û÷²xÎ2ø |+Ôøç­:$ö2ʈhÚu£&þ§6FçHœ'3ÿ×\Ù1ñ5öÚ™Ekò;EÝ.?.ÅQ”Jß,?ê±Yºr‹78Ûðís¥Ù£1›g¿ØìŸj÷—1ÎRŸºÐc¾Åre)²ä´Ý;08wDóÁÛõ­··e¬™Sí]ÀˆŽ|õõÌÙÂüQr©z]‹¸SƒT®ZÝÓÞº¿v«üþ¢¨ôÖ€õgLmëÏ”Ükß½)£Åß„r›EhâνÛ^éÙÈÀ±€”›(2®Þ'œvtÎÂ?¿@}º^ Ž?,ŠiPò“ÛõÙ˜„ޏæîÿÝÇW8ÌG]Õt¾ò$G_¯—\{~wXsoعÕ§lÖIKœgªÝ¢Ñ“tñí1o¹ìh;:¦Ù#'9<6g"O†Í!„h;öp-i©¶LÙ›=×ü¡h ºâœÿ sGäúà§l`K—¶IêÌEË)ÝWŒ10¿…Â’€€È‹­5cF f+’Tñ(¾QêÃãWÛeÂÒN‚3ñíK^™ìñb®È'KÐ1õQ¿×X#Ý‹¯&ñÚšuHÿ ]¿æ‰?Ï E¡…‘˜~ê ‚B)žùƒ)±ÓMéÿZ0E¢G †Úš%s8ã×ôB3><®fk÷FæÝ:¶9Ýšì1xhMGKS5fo{s_L[‹Q“”›2¨äÛHmT´õ‡HEúN'IJ9Ãué:r·Ó²{l$\£ÏE"EØ ÙxrÙƒ¸ n0¯#Ä’<(Hl^`ˆ…¸Ú½V©»ˆ)ÖÒX”¬]ŒíX¹ÁXÒª"eÚGè!Ú=a¾0V~ߊöf\çgÇ\0a¿®‘k¯ IÕýž4x¯ðT^¤ 9Ô‹ñ>%ó$UÂbÙi´d@ýèfUTÆålêÄoå %Q?†µ“ŽÂñ âƒFOh£ŸDŽ¥/ãH~k¹wå.û¸M³Œ(êe=*.V5ßœúw]}oŸhÎòë5H.ÎøÔ›¢^ʺ#4q¥‘Ô/²®½Ù½ÈÑ}ÀeýƒÑô}oE¨À ¨º3óÒ‚¨ÊZÿqžˆ‰2G¦;w¶;ùʔՔÈB>Š)´ÀJ/ÌL‹Çv#B>M 8‰„hœÉ–Ö+cç?I‡7¼Ä!^#çºi·yg:¿†ÐÚcãÔ£Š?Vpd©Ýæž’|—©FKýŒŽ-c¾U÷„Ó½:gìãêÏäV’:œÆ? Ÿ"=üSµà¹<Œ‚ù%Ó÷Ž„iÆÉÞ¢ÜI/<ÌÎÂë‹8,×äÄpp.;Pô+ØD[¼fÙ>,&’é›÷G«Ëæ®ü óÅ ÊþV#á}Û+|VnüC0F–tl«µoûߤ¿BF¼uíªÝ6KóOfÛÅ—ŽMÊ:>J›…ߊ ÜÚ¦óQ× Ï†ñ) <Õu> º‹ÃÊ•‰ˆ80/häaùKˆ´Òt~²Y€z~¥¢¯«ÉÈÖùo8Uµ‰ðØNÆêLm‡¹þb–ÕsFuDý:F_@Ù*g×áw!„°HÅŠ~kí Hût°«…H€E&øtNX  $óô‡‰N¥y"ÉBs%ð9½•«ÅâG½I1h$gÖi@fÇd´PþŸ?‚½‚ÆÑôÎ- 7|Xʃ¢ùtÖ~~€1Üõ+A9ÝzÄ¿’€€â\"ÚƒÀüë <ëºgñÈôÂ@ª0µ] ŠjL1pœ“O&Ä4Ÿæw%œã9é2`ûú&Ê ®9÷EÁ&rè9–ºµ·Êåp˜Lj!çEâѦ;´ïK”ÛÁ€×åý¿Fz=É=ŠåIæwu†=ä›OŒÒž/E Þ`p[‡’Zr5}[Ç‹»ŒŠò›ßK‰ Ÿ~Æc‘m6Ól›eu&rç\õö3¥tvÅÅãoCv×9·ËïÚ€4×yý¤ Š·‚¶+m¾j}nî8rñÌPñ/)`é¬IµEü0ˤ·sôg¤r«Z±@nXجÏrBƒüf™1µÅ ™z4Ì`¥ýòéðÊ{«[±üy1ðõ “½,.`"Õ9ˆÁ‚yÑû%F°íz"’üšøúÐ9QÏ-/¤  *Ï¿{ç ¬].[Ÿk6ù4:•|V{¿ƒl:x>Ï+wr¢…¹Š9£Ìb©áeн֥D*”ÉEäÒ]ùä›XšUÆÈÅ–—,DøŒ¤‚ØZKpœøÿÄBµfê$Y z,RÔ„½|Tß4åÁþe${}'À“æYòˆæaKEòÙírÿ¥¹˜ÌÖì<lÛµ$|îè[†èmrAå ËÇ="\5mí1ÁáL=‡N{þ4þ-cÓ¢@ˆ7ë´M¸Z”ì‚G¸ |¹‚æ( ®„ø¿áèWYlÙ‘R5þ~ò‘±ùú”²¢Ë"e+¯e´růP€¦ÚÌï'R)z¶Ê_ Œ6ŠHUŒ7>·C£qý8eã÷ê<ºþêÚø¹S±ªãúKi•ã¶kvz~˜]L+ýp®á·¤­åŠ='›ÌÚE:¯Ü ò2qʼnÃT#˜´gõióVM•g¢¸‡¹“±>™ú±®µWºþ±¼å ãM˜ã¤kvðgf7Üé½U³‰2C_E†xmKFÄbVÄhØsˆ}8ȯ­*IX4>õAîv•G0 ´€ݵ¶ú¹¬éÞ‚:Ó=³ÌûQç±ZÁ1§8î¿P4^ßq±â“×Ó`_»ÛÕ»ˆÇ2W¿‡»Óѽ±0ð^>èð€=|1uÔuØSô úÞ˜å N?‰ñÚIU-áɱ*º`Q>ôV-nnÏ¥n÷r›äî¢g |‰’€€ŸGUÓÐ0í_ZêÚY5ãx²r+H`Y…ŽÔ—á9€ý¦ï8Î\¿G¯¹ëοõ x´ ;ëàq9·*!··H@¬‚óÌc,æ&!Wn-ärB}ã^•ˆå$Yð)í(€Úp¬È=³¹°{ψ8Ü ûù“ªï“äæ”¬àa#øûÄáý à ¥åu.<ÜH3amïä¹Oªýü $­$àX#ƒÐ~uÖ›h°v'ºq3­ÞËX B‹³Æ©V%!®îræ ;˜KôÇS:`mðjtÅršËbþÎ|¬ÁgÛ“ñès•á•„>‘¶D(¥ì¨±¬[i²»J¸ûÜØ{®%Œæ4sAî¬À$ÝòÁs9 üh:  ¦i’?àf¾&tNtjÒˆï7Áu×®¥&äÜFÁíeÄ båÙÙysæÞ#*u”®ÃRGq«?À+7Á>®òÃòa€y‡ÉZQùã‘t  ·ì¥‚½:)f:SŠQ¯(aÙ`@;©ËI6¹Ë“[“øŽN½Ã 2ŸÃ²=ŽfÑ‹2;_×Tw°‘u“øomo'Án”vû$«ïÚ¶Š_Sþ¥{­üa|ÙgªBAªòO}6ìÎV°Bigˆæ„(ýÝ<í §¦wSmxzز„¨®lZ~86Dø€ŽÒ4¥S ëKŽJkM*1+Å[µPõ奡ì¹dPF~²w| n.C;Åž2{Ú¨¤ÚÝqI´`Ó¬ ØÈA'"?‘w¡vf¶S)VIX«­7ÇoEϦ“°øç’4M®&lëù“tŽ@Ók,Púæ$iLÚUV<õá!lêTjG…?äÉ _¼b’âë­‘‹Áâöö›ÐûƒxãŸ?éw52±’H ܇Ôô×DÙ%ˆÙè©N@ÿgÆòÛ]UøÊ|%l;ú› f_õûã^F|Š 9±T/ˆº¦æwšØM1f¥ÝõÐ>³UƒIJÖc94ï˜[«Œ5)=jëÎÂcŠ2 t”ÈRdÿPñØ„aL&^Ë-Ê,^ƒJõºñH‚¡WMf¹(«-½mC]Œ®‘÷È4—d²‹C²º?q {i‡ ¼á:Ò¿¢ÝÊóŸ°ÿ GHŸ×$Lðê= ‚;!uá;͎ߘeÃÁ#ç@¨Bñ–ÂÝ6h«5>4%›W‹ª%*5–íÔ ß'§%;Gÿ–M/À,,Ìn€‚Ì C­µª—§KQð©ê߈ c‚·¸Ò-f¦üÓ*5SA +Ÿeí]1E4T‰Ü¬~Ànâlz­+@É ‡L,Á„yjuXœ3œý@G‘ÎmZ1CíàmôЮë³×“ â°j‘ëE§÷l®ë8ƒ]%·@OR–)<´Ó•ê"2–»»d£šµI™ã¶÷±žIäyΈ z '_I“ðàmzÇÞ(+É~´WҜꀭãbå’èîÐìûC¬k§àð —ìy޾²ç`[7§/¨Úç³91NJ?öWSr–9'ž~뺉Õ˜&k©í±Vf`GRý™e'‚ƒ^•úÂ|Bûh ÚL&~’€€ÙÚ1@["œïß8þ“—KEë¥Ý}E˜úŸ£ÞvÅ>©Š[ÛárXŸT¢oÐã@“ÊbµK¿ÎŸÁp0Áž¢FZµ`.$xaUˆ8mØpZ©3Êìï;(Ò÷ý@ÀmÄFÚ»Âp×özoùï}ÂVåÒ+[AଳPÅ1 €mÏÝ/FV=£™¹+-JüÐCE7„½úž>Ƨ2 Ý2ø²%ó)7öß"‡ Kq4i™#½fÒvÜxs•ån±“<ê©öuŒûc'A(Ïgâ“%u; z°’©Å_lÜð)Á¡?aÐòÓTáôÿCáÎ:oéš;wx½¯{Žw‡}/xæVeî›Íê½S‰ÛVM^O+¡ –ºŽ‚£¨‚b[(<;ÄçlˆV1UR×Èžšï?(?>6,Òˆi9÷hbwq.à)¯¥Ç^Ñ·ž $ë#ƒ=<%Ä–=OrÃ-D=åésÿÂy´e~«òa #ˆS´¢_¼”®ÄZ‰‚ލŽì£b,™® BŸ ‘<˜$ $×6Wèo*Mq()ñ¡Zïîs”ÀÙŒ'^Xä‡-ŽÛâU×?üÑ’k‚cüΑgóõ¾<ÂDn¸WöÖ27`Ÿ0Åw#]z÷àɯVçŠ$>û¨Uò¾UXˆÑíû;”0v7tm¢®˜aŒ«“}B'ØíÂv é¢44‚&Ø­m”Jq Û ¿¯„Ôçæún*‰1}¢ÁÐù®¤NT{ëäáù‚:nö89ë,àÃ5™>–ù%°ìæÞÕ1qKou=£K/fÁéT£OHÌ&eñ.F¿ë\9êXÌÙˆ ‚ ÿÕ]»ñLY È8ä äWdS¸–ÙbjvÕ#[·3¾ZM£•Ã}øž ç¶±±ÿ‚ƒz³y—D ç.>I§_Ê{ Q7}Ä’˜1NæK³›NuøTAît«IÐ^÷z¾œ©‹‰ièî ¬AØþŒÁ7\{%¼ËIsu~1¿ãҧȆè‡S;'ÜN”Ëð*ì‡b6– Ì¸GCÌË–ÂQî¯O+ÑP‹ $íÁ:Åþ?‡.É…ºA¬€ËlÔ‰ ÝŽI†­al˜‘å†;â}P¥`1øï„° ½Ì»5b¼P€e}È”6Mÿ[´j’€€£_jñÂôÂð)“¦pá ‘—{L/³—LJµÈ¿@ã¦:§tøTìËre~Ÿ/4ökHªóf…CI¿ì'- pRA+‰9Ÿp´eì´ŒGl½jݽ±Cbù’â÷vĘŒ1¢ Q4dr>Òx1>1÷;(û%AžÓ´t³B¯â û‚Ó½K'¼ômìCð‚<œ Þòä”­¶Q|‚Ƚ$ÍP¢ýWÁv´b¨qÅäÖb8£ñÈuzá4àG'ùfPqâ8½VÅ,K›û;ý˜\Ú¤’€€Ã?•§‡¦²*Pì† @ÓPkE[$È´ºNÚªýäHwîhÿ¢ƒb6ßy’豋\‚ãªw+†r½³²7ÌX<ŸÙ¢;ÒóÀjÁ?0<3cÖ48ß’ß.êáó²ùqh;üâÃ_úÊ:Žôœ˜Ö¸-&‡îš€)6 ­¬!. Û«[© ²´²ùj]þ˜®øbbѾ2Æã&ÞÌ!s‹í¹îÙçÅ-©ͧm›ÈS ¹˜ŽJð‹¤AdfÉI}±©gk²ÐrI GÞq·"ñà"Hñ%ÇÒžêH¢}ãøO]Ý‹wn"©¾}›¹\D¢ìõœÓíÍ ºe¶Õ,¾µ«¦…î%tòaÝÞp‡5þP}VjÞWpüfU“lèt?ÃðÒI$¦U…†2*tkl ‰W³g~¬FØOç[®´žèÇHÝ$YỬ®y1¿^Dœ·AJR¿7vRl__Q‚N>+&{™NVïÁ—\εt `Á…Î-R÷FZx8ÕÄŠW¸/í5@DÅ*‚dÉø9ð3FDkJd(¨À¥INÁ]pw˜2Üv ééxƒT€juè>K¾úïJÞ=»Iñ“£®Ôb´V~Z+ú¨âRS',ÂMEÇ—¾›k@iϽo´Â–Ÿ;5„Ï"ü1Þ0¢_ÏÆ FŽâv«šÓ3…ŸãÝìt%,yZ†<¢y€ê+ßB•ù©˜¥*-˜MÉQ¢ýóH ÊÊl‹§VKÈw)«Íø¦¬Õ#F”\¿ÊAG™2ˆA.Èއçç9Pwð¤{B)]Gî¬>w4!°Rmáqš’Û/ç§‹ôà>bTÉf-³/:³]›ã=š^Cá£2ça)öRĨ¹/a0~ãÉyh?Êj!?º‚kŠ{OZ}æŠj4òˆ†»ÜŠu]ð(…&3]¦Wbܙɻ«çäkÿ«">«Àÿ¶ Ø=_ÅG?—ÜL4RÐfá%B% 2v²š¹˜/¾VYޱcñ÷-èãÍYù¾a‘ËfhWÓ`üÓ™5_›Äø$‹¡ù"§gš>0EC‘Rð´ÓŸéÁ>.ñ6¸mõÔyÆŒ®§Hµ“–WØÑnêÃY€$Å}nI]H!{Ÿöª,>ø§1äK"½1ÿÌŠdò³35V['*gä(~%S3 ˜ –Øà¦îlP.gAÌë8É·ØyMŒ®Ï1ß›q¾a·7·o±Œ´¯:Öþµ-/÷['‡Ê$62±wöãÃh¢-tÃÙ”5vŒ> ‹uÅ1Â9’rµ ˆ…i1ê-ùOg6ÿ¼‚KþmsÉ‹8[÷ǰòàÚŠª".¦‡Í5ô“ýa— àœ2’€€Ò-ãÉv”Jù’Í È´E' Äu©‹²ÅŽ5çÄ©Q}&3h:´Wà…ÎzKKCç¹)NHö‰˜ZÚ|Êé~x„b\D¤{ €}»«•.ÏÚXÂ]éÏ·ùDCË,¦ÌþOA°XÀ|Í»ƒ½Š§.#MJú•mÃݪ_«“FÅM °ï2 òOÛ¯ÙÉŸ «&£†èF:Ä÷õèMH­"¾?þ—Y‚Åík çsœJ—D[³g¨r Fâ¤P·ºY,Ï›é[Ü(Câƒ{»b§íæTs°ø¼9ÒCß|H; A€JêF©}4>JÖŽ_q 4U\ö~+Uå€6¿ié\i×´9VÁhd_˜þ“òJX_Fc…®³™í Üa{5Ì}LÎAâ#ãeU娌FuÉðŠüt ð ²G¶¸²DV;œíáž8MüÒÎŽÝP®Åo@ôùÕØÜøˆs‹KáÎõß8q E«é4ã¸Ï£Ñ- u½D÷Rˆ…y2-0â–‘Ó¤ nœðò¤/’±óUƒÄ¢36¥6NTt$—óPÓ'‹)Q6‘?ÿì–^ås5*,nl„uÈ€eŠGPÓ5ìjfFu§„ÆŠì¼¶ó^ÉÓ¹½ÕÕÂwÚPæäP¯v«‡*ѦÚÜk…"Íû¹KD%g v—¥Ó¡>mð¤KÝéQó‘RåÓ¿Á<"î“úCËå76e>ä>ꀆÎJEF2…ñxÔcb„L úhµØî”ÐöW£ÄBKðÒ\ z“F9’RÉV~ß²U×ö̿ȗîŸÞ–µU|âaiͼ,ÖÚ©“·è!,›«©F¾2žÇ³{ó¦ö‰þ‡¹‘´iû]õáRM=(åòËÝø&b3ŒsÝx~¹e´…lï(¸ ÿ—R]šv[ÛsNþ2m1 ×,»dz:2ñ-Ê{É|H7ÞùF®ãPäcpùüèþa’€€ /P É1¢ôOàHíßÀÏÕý%-²<˜È¹‰aIbI¥A|=DTp)”æÙVàp¡©pË‚”1ZÉá¨LÄ4kçpª_kEžÒˆ&VJ »Æ·7eÕï\êóÝðµåtÆG_éñ©¨å‡rz SIOÑD]ŽLËA·Èž¥<¦ß‚ øÜÒ~ã -×ò¿Ô•Q­ôâà’Æeê>Ðñ v¿ÿ–k‡¨°g¼k«QP1úç¯vRòÁ¤¦óÃ{‹:.â y«éßE@‘”‰fGÆ·Ì"Ü·dgzõW¹z“Ûkù9oƒ±‡²pbÕÕhr5ù8JZ‹'/ÐçÑÐ*dFèY~-*ðÑ«HÃεåRz£c Ê5ú¿wæ;¼vãqÆñX>LTaÄ«¬xÌ%›ÊÑK^-ú¼»E”4K‡˜vòÇ‹°±‘ŒS‚x½¥x?ƒI p“FUsïrÀ¤§Âr,ôžÇû>KôÅ)˜ùÔ}(=sïqÆLX¬K‚ÂVŠrg¢w”½'Àl²ˆ'_ŽTtÙcÐé5ÝÔyi=bhŒ©¶0ã„=¶ãd(¢`ÇYfåÈæ»ó誧¶‰~ÉkÚ^ÄIvLä/ÞI%òÍM½ úædCËŽnhLnÃQ±’©òÀuKœ¿?ƒ«Ó;ŸLûþ=x&t­©…i˳^ø“=§*Ø (̉ÊãáKßß1ÑÚ¹J±6‚Ǽƨ"K4½Z/Q8ÊþÔ£Gª(íK³÷“5å²®] ìÅì.>!8Ám§˜j7ǽdCH"Ó«3l„n¯ËJžµ£±rÒñI–±ç6A‰±ØÚ~ué¼bÅü­ýà?ónãÿÔzL®&k_ÖPR”ö¬þ§%@Õ•exn®µÈ&öižÏ%Û|s”°¢;€&ê%aúD¾ßžNÞ7£¦|““2?œq‚ BÀ7;û3šyì¾1 ýÐr¿¿*ÄVƒ‹AtŽ>F±iO¥9 㵋{'U‰ŽK¢ê;Ý÷ p»ôO N»Î!@^Ì¡¾ð& ì“ â°Ú KWÃôvwwjGšcïr4&Ú1sä®6Ò„f+8»¬¬.túçLY0)=’€€éó¼¨èUf§rJË"Å ,+Ü4mЉñ–_CØ™r€ßEÊðP±BÊ ,ü‰b\œ‡qPsü UgÓÆi­• ö#´ˆ£uá¦g¥ÉªEä­ä+LH5JµhÛÎ#åç®`Ä•Ìuóò‰¡eWÇ«…ÛË´@˜åÍa*Î:t! Kž®bZ¤Mzú÷å꩹U™líÀ÷êŽMÂP~mƒéolHýLIÇûU©„2ðv1è^vÔZ÷…$æ¹ZòJ"@¦n³>üNhê`­e÷ÇFJ ¿ìwzw×a7Cçý*0­^³¡‡pJ%ýç7-Mµüj[¼8t÷E´STœ0—Ã4SØ”Y#Yò­½š¥ª/Þ®qñ°JFÔ® K«:·Õ¤Ìº9+ÿ£S nphÏ e“®5Ò³œWr[È÷v½<TQ#‹‡.øýfó)úyI!ÔjA% 8³kÂ<&³ºw«Ó6Áñå‚4ߘ C‘8\BNâ F|¹âÁ'ÈB³ßƒMmÅ)Àµ§>*­‡¤@Ê%-X¶ÿgI/$vÖ^¢Æó [ºV½=Z‹QæÄ™ÂJé9뉱ÿ§Ó°¥Ëyù÷dÝ‚«*Rsó©þÇP{JVœ"{…Ì_Þm|wÙËñwŠùš‰^†Ú,K*(¯Y®Ø>t#g°vKCŒÏå}.ǨµªêàúvAoƒBㆼVöé=7pŽ|LpØñ؃OyƒvÞ_G7iü=b”GœÐ1‚(ô.YPyúW¥òü®J¬·Ò‰~Xö/ÍvÁ:µÖ~}/ ·|xób‚ oÊsä|bàCîæÕäÛŒÆ~q(˜5”Ëx÷‚ž2Å›µ–TiDÒ™jÿsSi1Çè…’¸ŽãóÞ% ©3aøe`ÿãéaKaD5ãïæ¿?¿¡Td-é‹Û3r©6¼ äÅ+ð‹åkûÓmf2–VKè{ÖÿTîéÇ à¿ÎFμµL½ô2~Xý¾"²ôxܳ®H7}$ú OoGÅ4Ö_-Œ]\ó: ákᨻQI$òúd`Òq=êÒÙ>äU‡Ý/cÃo½ã²ÅÊC.zíÑ7˾‰’€€än•ÑÙZ ¨^°u7€—ä#…hÔ4ɶRë¢À¡Ü-ÙÃGz¥âèa’+I½a$ÀN7Y7ý:˜°6]jrñAއ”ût™ó` æcsßìû+É.dÎkØûiIŽ>%ÇI…à—˜Gg8í­÷)ßõÃ!Xr»o¨Öý0÷§•? «6sˆLªÿ=^p½=½b v¾'s¨"°@ÜËBãAÁáÄLÓä­Í'RX8Å&1,@¶q ][©¬‹´ˆYµøÊ¢ù&Î?Ä8¼˜b\,¦"9]qJà†ç!W‡p Xo‹ÙL¬žÈCèÂáÇØÁì”âެŠ·„gö 0 ­›f•‘1¨`’"}çÆÆs áæ¢)óœd™FTwÁƒÒ ^E0Ø*Á6w‡AŽå‘‰9Ú\ª[‡X~+륳¦·ÔÂ%èÑ ³Ï°´ÕÊ`dü4ݶèŸ&Ýyl×9Jº%t—‘õ%¡‹þ.+è>xD#úãó$1Ðû™õdo5œÎ{îï Èã£ÂUð “Nn%„òÏÖ±Mi2C2]QT †bú+¸Ë&…?TCµæeò€fxRóhó¿<µÑ6nó ÂL Ú}†…#²‡9~yUX`ü”bá_’äy8~kÂæ ˜SPCr$„{†þÉÓ!Ȱ5¼ÓQÓÀs~8´´Ø|Vgõ½îš×3"{ í§ýµÀ&pYˆ•ß{ÎiN\°í¾§Ù”xå‹°ÓYç0LN¼øÉT0 $cÀô÷Ùáö –? …mA¥ *¡°Fü^_Ù'$ªŸá€Š\œy·MqÊ2ÞJ÷ªeÚDRÉ=Ó·Ÿm‰›§|Ü@zHÕ_˜ëÍŸ;V’€€´Šf·¾O’:¾…ÍÂkþÎø?dN‘â²ôºý‡²§4'é$DÅý…³²½î¼ïp³@u ߬VW¬_9góéHó» ²¶«ZXj33`¢¾©»1âÔ¤û@K‚o¨ înlö¹Nøí:˺ë$i%ÄÀCÔ˜çnPþñ˜`¨ ÎÃiyYàå"!ƒ d‰5Ø>ÑRÚ2­Óî|«{s.íÚ™¤šªÅ\éŠI q°ãüy³Äx*”Â[F[jyŠ7!çë¿Ò<%Y”ޤSä/`h©¸i^»¦å4s‹/Xì2ÖR.ó´Fpe¡çÉÃiT¼OªÛQ·.‰›"«A2CvMº•ÝȰþ®!ß‹Õ%]ªØ@pð$Ðý_@ÑŽóqZ hQ yQ½ï¦XˆË™ riMcáPgI¯)‘΂<æå‚\¹¯GJà'RÐ+kØ%1rë]x˳¯“¨ìßcA;ƒ5]”ã"P³†ý…ã@z¶ñ“3¦;h:ˆ;÷ Eñ݈]ë]µ¾¨}­ó.ÈsêOx"´q‹sÊR ƒ;ýpB¼|àçÍñÚâSyv ¤²éâŸI„¬áËl£7ù¦«ŠŠ³ Ö˜bõM7lÆëB»;p¿¯búˆRWn^H³ÏÎÞû½·íhyxµ~d£o™¡Ý‘‘Üë-†€gë2‘c‡ÜQþI¢ØLO¯·ŸÙ wýmÌâ«¿Ó×.4¸°wR‰Gº±€­ü‘\v¶g¤ó&[ÿ(”<Ѐ¹ÍÅ\áš‘±cÕ‡T\~/DV‡eWYK!ž¦ã„ jÖRAœ;3žÒöÿ _•µ ‡wʵ¤‚áÙÑ5ÄÕ¾ŠÅÍòÚm´Ò™ø)òÿ\ÐùòbòŸ¯÷×}ä域¹P›zȨ‚ÞU_Œþ€øØ› ¡¾;¢»bÓÃWpjLP2݆NQÒâà>CÕC½Döi¹=ãÏʺµ·[º&I*”S­ä¬Àúcszå†r­‘yK©|÷l— zR_¬ÿöRþKØ'µQ¯ÉˆíeÇC4쌗ªóò*–s7Ýtëê‚8ÔŠÁËÌõð€²ÏÜ€F‰kÛƒ™YF‰Áÿ÷tx{òØüTj×Ù˜Q³:\“ºì‹ ²°ž*Eb'¢Æ5=æhs5qmÃkñ0ä‚î2¡pÛ©’€€ª½¸D4“‚§d¿…æEwŠÔg´rì–ÀIkåÍŒÛö§ÃiãÂÙ¶º‘üúÒp4‡D]§ÅÂqˆ´›Á5]êÈ‘îhA¹6›’¯ü~€ß%"ä‚å9Õùuöbcè.¿A·Ï/…|)­¢hcHj[±‚Ã&“CT›BÃzª6Œ—€C>¬¥JõÎUU_ש-cƒ^Ä.ÆjåzÄF)àV×M½ÖJûÒ5‚Íí6Ÿš(©TˆÚ*HÞõ)Os3Ð:ßÿÞIJwK§oÇ8çÎŒ eÃicÏ”NÆ!ÖMŠŸaã©Ã;«œ%&êˆ ­XCðèÀ:§4uy¼HR+;ã_j23EÞ'—/ÌHBEï•{ ôS‘9®p‚ý‡ qû8¸æ:¢æA~c(}]MqÈeÚðXΕˆKY8ö í)1Ñ|˜âBÖ±î}õn,ö¾^€KÑ`€hóÖ°EÎ}"^ö‡þb9+¹Û€³Ânç,^vÐ/;u°ŽTP‹ƒ0SÑGLSºÈbBEÜgƒÆ$)kÄLðVN@û·£±AxF®Éê–àya\Ømü<£>ˆšLnp¯üÑ$„YÖò×ûÈà‰óÿʯ¿" K;Å5tç3”CÙéFõ’í ÌÈ ÊL²Xr¾vï‰æôši”øddƒ³œ3z™¾ŒK't16oEWÑ>;¯ªšâÙññ¤žkûëme‡Ògq&#Z`!m³~'×@”Ìü_Þ&ÎZ×DC2µ}"¥¡pšné~ôÊ<¤âBbõ™$£[q¹ dß„!â.\düÂ+dY‘¡w æ=uáÿÁïV¶H?±ÄÏxÕ™:ŒËÛÏ;Z×éÀV°vr y£;âS©ÌPiúa»ò0ëŸÏþ%½>‰ÝM¶ÊáðÆxÿn¥ä÷œá5iuebøèmRe#H´ûû*§kl%ÅëÓ¾<Ö¶*=²‘ãf$LþËÞnÌ ‘2Â&tÝögr÷Æä랇Å'>¤F¡"Ç—àBÛë¾ä˜’€€°XÇWôüËT—¹B˜‘f+òk‹q!8—5šs&¦'–e&vÂD"§F©èÁ†×„˜ ½N¸¯æv8÷²;¦yE•«Aæ9´XÆì4ùôóŽp€OØ£†´÷D©`&^Å÷ŸúW. hØ'Ü௜Á¨„^¡ˆ²¯i°0o¾ÁCÈ{Ÿòzý=>Ík(ïÔåE‡þ~›’˜[FÉ:þþoÓã–¸²Ft”ƒæA`]¾Ô\sHÑ˪þ S:J¥ydâ±?ƒ›ÞBËóf;„³´©¼æ aÑþÁŸ|–Àj–ƒu-T ì§¥‹l=ù‘/§iÏÖ}·ói-Bþ`1i;=¹X' E¾˜ç¸gu篷êHÊQ8»d ¶Ð3¹ø;†é¿ª†€~tšÊ¨?!8õiâè2PF<4ªaWÕ¢*ʵô·/Y?ËKõÂ.:BÙǵ ;ì,´â#_•GéKª'ìN¢®ÐnvVÉ„`™)ÓN°JyÖ ó€-Öò„°í„s |à€¥Éª,Ôž#“@*Gº<úÐC}o:>(c dE/M Țܾƒ71Uy§xƒóüL²œ°C@UzaRk¡qàqê릅~™,†V$O¡~à7†|§ólÙàéó÷XPôMø:Ž,:1íV×]¨Õ€ ÃqßOê¶ql4o;‰>ûTÆoB²ö =ÚÔé ­€ÌsŸñôP#ËFƒþó‡ÛÀÖ=BQçàdüU}1<Žc‡ÝåÝ›UZ1õ9ÈöÜRÙŸ:;ïO±<›éÕ‘2ˈ`G…IÜÜ«AÙ;wV#öÑžw³c%óŽ|HoÜF—‡#Br­–&büw ¥©Šòm6CP¬Ì“õ\§Áˆ«éðŸÕ{d â×0½Fláºr>~:ç`VýÔÎsí•IsMS}„ ÑM] WÍ^Ýæu“úw¦+„Þp'-$<Ph2<&`-‹A54plǾÝO_Å$¬Aôçþeæhø•žÕoÀýy0V2ÙA'»Eq ü$.hfðEukÈÈã³9‹àšÆx÷«!#Öp@•ê×d8|Üòç8-Œý>çþ7‡ÇbmH;Ž˜¿Õ×LÉ€õ%Y..eõúfùïƒ, ½ pGw’€€¿¹MF:.ðP g-CEc1pz|*¦ÙsGy±™ƒøŒYؘªG„ãxnÅIÜxoÊdžÇ~|2U§Ï?|ôëçš™÷]eEÃ)•“úôz^XÚÉÙ#üxž×ÒÀ«ÆJS^¿©¥<­H­öÙî‹7ûæ ·]Nt°ëBÙ/á[çõ³÷?·‰b)[j:Ô·Ók›àÛ6u‚“®½LßkbÝŽfÑUús"(—Šà×hÛt‘çìü4@£ F¡%rû™Öç'\Ådµ)¤rŸD ~ÎRû6äX,õk¼ù±3Ù[G¯‰Šò›\žµèî7¾§¦§u‡)J]kn¼šõk³óñ+t:roT=m_aÒž›ëü!ï°fˆ_dÜàU5Ãõ-ùí×) q{³>0E ÚqÀ+•ózXÄ›i{ÏpÕoW|¦/4‚ö`L[®ÆÉ´å+h‡âgXÐhë"],U¯€Ø r‹üTA%+:KêÓ&¦C†´òí¾ì<Úˆl'Û(]DîКs!óô9Èrù™_o‘¾²bª³È®âu£­O…mËLJEÔ*‚Šl6²‡¶/¸…ÿŸzôQ•`éÍÐÁó°‹h#š˜ìm˜ñ€%N§kQîã‡wª†âèâQE,´pÄyåÞû‘ªrùŒE?uœ óíx–E‡\:Í708QóyŠüIêx ›´‰U’¥ï™ËʱP„.)4ëSe‡Ì¡Úuäzð쪿´ ˆšŠMÇ-+¤ ×!ÿ«Óu6)…j`Ÿ}T¡<+F3&zÙcã"¨v1‚‚hýV+Ñ êÈð1|zp}ÕS¾…'ʼnq¼4òSºÃ.Ô8ΪÈAG›:[«çÚÎÚ¼«vGè¦Qá~K—ñ!ÒÛõGýfw¡1ïvÃ_ì?muÍv¶»=¬ñPL‘ê:/Ú¦ñßápk-HßãÖï3?¦ÂÑÁ¬ÄÏ?ɺ7{s\Ô²f0nÑ)|YY ‚æœ&˜G‹ n] Hh²°ñÃÅ䡯æb§C?ùþDÃõÕ>þKõ ?—Ù£^¯5)ô/úë3MM®R•°ë«~ú3TÉë^ž¦jAVÄÚ­b{kÇØ‘q|8r-òô*øTçªQ$˜ùÈ­ºxÊ:°¨¼7uvò•ß ]…]p’€€¸¹ë°±`—€÷£«[j5ˆ¯4ûp<•c¶šQ:‡Þ»ÜÙ IÞª3ýã×ùÖ6Æy€Ô•©…Ël!T-Qhè€Móë1nHÄ -z®4¾ÈÕÉ8ÉF“qz·”GšÒ@R4ƒð°Ô³%~¶W~sbOkÿŒ`>h!LJ^¡ydk_ЫçH5ÀKJÉ«ÇP˜¤hž©+PÕj‚ü`×!Cqö£oõÞ9ýÐáÐËq9$ÚÎh\ͪA†þ!Áë5@®“ç`?äÔÔ!•þö™dd@lD¯<­&k»·=Ôy,·ð·ú×|ð/Wõ':I…¶ äTP°¡â¤¦_C¦rwMDÍ«t›¤Xá“Oɱ4^a4^:¶YÓù"ñê÷ô•ú~VÆfÊžÕ+,¨î+®D5œÙïéü¥;€lÖkd*(‰ô)&ö_f˜¿Å]Œšm©öŒ½E?Í™øI2 ¨èÔį@™6<.³{ÍŠ²]MÈó-œ)µ%·zSÍ7l( Ær¼EáAÌ4ièü?—9¾lñì*’Ÿ}™ù„mTdßÛS[–Mf8gpWµnX§æ‰×tC0…»ØÅú ÍД'sea5ã δ4oÜñà¦îñ>JŽÖâei=h=I] ¹§‘;ùwBJ$%ʵOƒÚjªØ½Íë‡áK™¤ë‘QGGÈï¯-FA †‘£plÉ…}©±I·_¦`‹éT‹4AcÀHh_æeFC=Xó‡ÛaŸ¶ $N7ç‚`E? Ô>zàïaÿÂbä© 8¬¾)qu¼w¿ ÇíÜ;ó[††j-Z/ å¼| ó…ÈÈc‡¸¦Sì:œ…¹(ìUÆj ¡­ð‹yt1î’½ôAdæ0zØ, ßá›"öÖS‘¯M¥ãݽîqÞŽNºŽÓ÷a§ë”ãdû†$pç“ê ›®¤Ù;¡â–ލCä¶OkkKÛit þ˜‹(3v;öU=¼ÀÝw:{=Ë+@í0!!6@mÒä'÷ÝFÚ´3½Þ”§–Y¯©Ç¦À]NÌôRzSo™Ÿ5Ï!rœUØe„f„¸Üu†ª T£k©¹ £ÂÃY\Àm;1Á2nŒæD™$ªYÿq}“º¡·sãÞ¾ê@o@’OAòP &ò6Ux¦¢Z/·H’€€Ö<ƒá©?½ Ý ­*xoÍ4´±Öié£ê€ò*©hij[>¼z/}ðqÿC1ÒKKpÊÞõh–)ã´]Põ V:¢u,¦làÌ>—(ȨX ¹P‰ œÑŸš‰‹ÄØVš/7Dá£üÈñ_HˆN¸ nÃShÜÁãÒr–eÆÐ@žGÐáþ K~s-3º„IÞJîom˜×À’¦äÈàdƒœýô) ôqç~½AyŸ…,Ý´Ãn”í¡@ëàoœ•l–1½åðÓ6S¸åh.Ùñzbç”YÀåéë9ã &Lõ{ñgÝ™–ŒÛ2ð›Å‚cŠû4-¬û ÕuI­Î?ùbøØbßan¦2Òáªùjäñg¨ó)²¶ /™6W‹;…y‚Í>ûg³æHßyþ5ö>øO¼j*y½55tžC]e¦”´¦M?·Gh­Ó\ËZ8ö9Ô˜ §\¢F®½Âp }þLwÿÕé3%Cvv¸{›µ0[6–}CT–éQ7sóÕŽøqû½"¡¾ sΪJùÖQ\#6ú•ÆžÜf*Ú°xÿÍüã…ï&,Ážóö!ìJé»ãñz…ûgcý_Ug¶ï,ƒY3Á^QKÚ y[UìË:®³Îâ§åRr}Fqå']QþYáZ]ÙÝiw}m9ÿ¹Ö1þª5¼}fPùæ„Þ ŽÈÀ–¾êd=bŸ8Ü™ r¤8‰-Á™XÈŽhGb“³åTõzJ%­kWÜÊ„|飓ŸGÆU{úkBÃ1¡ïap6‹~ï=©ÓeǧJ³mdv6ܪÍJ+KˆYæüd¾JáÛÂòa,ßñ/I ŽNGÈRŸ o  g/szÐÅ® 3†U€fFà1|Üý–¯ž1ŽÓœ£ÙÏ™…EŠ aüy-ÒEßjI²òñY¨<’qxCÞ,Ù~½Ö\#O™±pßiÍ9÷æþ¹´ÜSBÂRHªÄ¯ jüã b¾R~"žÝ”‚>”Œ¥Ð¸ê¢^Ø_&‰°¹ g]ŸêAâ'…¬<³ÄC(°ðÐ|xQÉY‚ƒQÞøM(’€€Ù4še{™EÐÒHi-BÿxB[¤åÎYOyu›?n”#Ú/ÑIRPVUŠr‰Ú\JØëW#¦Èû«?4ÐêSu[[…ãÁ¤aDZ¯y˜˜þÙˆ†£;]Ô@Qª{õék›•š|NVMÖK Üê:‡7ýÏýܸŸ \X³Ìº)¤OdÒÀçÃ|ZDƒNø™³w‡ŠøF¿%cÎú?|‹Í/¾þ~Ÿ€‹Ÿ‰ äí>§þy‡éˆp %æW;Õ^ï·sæ¼&_ÜÉÓñ®©ª þžõã‹\qâŽ?·ÚPÍ#V±$óÔµ¤¹0–Àõ>±;ï§ã=Çì®ÃVûuÇN™‚”IKÓzºÌŠÅSÊÏIyeve.C›„50ÚQ8sÏx*¼Zëaû3h«§ßQ|¥NHº²ƒr½'øYHçXKqæÐ…O¡øÔ á'¤ï¥a7±šöûbH¦4—¾ {ÝA掰‚ÄÐoNF­HÎtŸ‰Íg(ÂÈC}kþ$N {lÍho@‚7ôæáx”áŒÿ¯7É^¡G]‰Ð¼O§–2¤ÏÝ÷BŽOøÀpØ’~…ÍW ¾Gáó_¬Ã{yং%³ì6âz¦.‡j‹¹"q&·Ž)Þ´–ƒOÉÈÁðü1l *óÙÛ^. Ž’x«] ¹ìøÍu£ñ ptž‡õÖ Ab ê‡gùö”.gèIå\õƒ±=ìõ …~Ĉ9¥¸‰ 4ô3P q(Ò4<ÝL›Å–ãa™qeL}ã¯%jÃíãd‰õs0ÛixnãÆ²Œ¤>à¬e‚–È23]}•Y<™­_;Kê¥{g±GLvî]òÐBE–ŽÄ)yþŸß˜døm+òh„ƒá3èL¤‡ÄBÚë‚=âq¯\9بÊ`†Ô:EË£ïäVd²Ž¹;3)$u:óߣ²JÚ{ë_Xòu«ì+@f™¢4\-à{;.r(,(ÇŠk1»Pïæ¸ö{hE8ÕÐwçžC 7Ô(çcÃ÷8êê%Úrm'PßêúOe@[!^±7Q)ÈhŽœ ¡'Q7• Mr`äBðQÁ} _Ù¼A#¢û2û&{z0µDڨˮjÑ;dÝM%wuâMD™?Å)ïP: ü/æþ’€€¼dçùèÊŒVÄÃ0Ð/NiÍe<ý‡ JĶƒŽCWR~䙽éÀŸèh§ç ÞêèÏÜXÏœ‡Œä„+9kJlLØ,‹on²…ç¯-Pu²ØÚJDÍk?»öÅþ•F™aßU—³•q›Yc ýÝ9wš"𙽷m|GÀ@Vɰ+«Ôdãd·ÀG¥“£L¬0Ë÷ŒûÙ«>Ã\(zµfØ-‚¡}ãટ{b=á@–D íò+Mkª ®Ø¡ðN h[«ì“\i}ÊudTPó¯aÉ®àHºYõ«ˆV´Ì¬`¸>z«§˜£°/»(‚ƒ¹p™‚]»öÏ@$Xðú#ÓÔlJäCçeÃð*.y6S;`–t¢^&2ßCI E–Yk÷³ƒõ»Â×øb“oö^IÑ[jµvU~qÏth‰¯Øœù\¨“Ì0Ïk5è³®Õ`Ç=›r’ã48»¦³.eîªc$PH¸c¹jö8› aõÿ{0ohÅ'NTëx»šÌ??>Æ´'NÔ^ mÆ> ˆId¬f$ «Ú%Ã|áY¨EÖ‰ëå‘£»e7Ó¾| $ #C4Ðk^`念rTeÕApîÝõ)éêÐè'IŒBü°A¼ùó®ÔH¾Þù¦>©¾]ñgTÖöP¹k0KJàýóÑHX uÚÒqøOCbþ%úxMöñ÷ä— sˆ4K‡$Ïu_Ø7‰÷—Ê >—꩞Ïß ˆ¡µ†Ý“"[³«h£Ž]IL± ` H•÷?”6 ŠÿÙÒ˜Ìx5{…C’&ßÑÖo¹—#}tÐ ÿÏzL >ÚáÚˆ^MyÔyÓx—WgQ´4ÃË:©MêM¯Á+ðçgÍã’4ŽsŠ'R,ïqçÿªÓ$4|Ä•Bçn%{VàR‡uÉvÿ0¤R§ ¾ÒjUn:LsމÀÇ$˜Õ¾%6À&bqÜÙ\Aí×Z市$¹wZ Æî!ŒÕ!ס©Ï(ø˜²ú9"Ùˆ>ì=p-y”>—!@’€€½„ׄ“~"KÈ åFºP>_øœKŠj ÓB î«Ò2ïX°í+Ó»(”Bg+RþMš>ÍÆœ1ÈT5ON„ H.Ch¿2O·½jÁTKX sØ]ðp¤ã+€Â bLîPôœ!ÎTãˆÆ“ Zö¯)$‚ ¹å5”NóÉC(©˜^Gì-@žPÄ h|¬Eî*äEØÙí ö<ÍD£‰#ƒÁvoûVQïÌ´8Y;n…“ÎQdÕã9>fpáê…“C­ËÁ¨i.E5+ær·¤i3£7äS†g-QϳT†;’Ï1¥b#èlÑ]0=-Ü¥#¢ÄÉ~ÚQAþŠ] ¡”«þ€ S9Á8}d‘(õÒDt-§sЀÀr¢«3à‹£‰oDø:_d<>%ò‚gÙ8\#wrúÓc‘À’Œí×5= x®<•p‡*ûAê•«BB¾åSª"nÙ#´5ö^LžeÀø²”HGLû&·ËŽtg_ð¥Zhá¬ØÌôléM’¼4ùj-ÿ“9¨_FOârdšW®=7gžÑú‡jLþ» þm˜‚•ã½×28ª0¢Uzäh#@ðýþ²™Í-¸£Á¸¨%Ø(!‚aÌ}fûÒÅÓæýÐ2D;‰ÝúaP«:X€Å÷+Õç#À{iá±Í…Ôsú–á‘‚±)­hðÄF†ÍùæYðÿƒÔ®@ç|n>¶¨‘Xñ~k%zŸSE¡žËsh/ý :ͳíÀ´F—óMEà/çh²“ RÊWà‡jñ›¤Hó}ì±ØÉXóá,0Þ,CEѵ.ª7&¸Lh¢Àïc>þ{Çö‰Ö÷‚ 1‰}¼à^LAè¶¼‰þ©is ’Z¬ÜÚP!ŨIžF†}‚•ììŸò%¿½ú»3x«†yÓvÍ~LÁ©É«“ñïû²sØÙc3Ö’¸søUÊxÍ(ê’Äí¯ž[rénÈŸô ZÓXY>æÅHß)ibO-ðLxïñfDXP.^´€5Q4@Ki/6Kó­¶YƒˆB]äQ¼h?¸?E*Yh% -ÌùPýwwhi¨‡Ë)ÐÐ@]ƒ|6ùS¾j&è®°H„^ïÄê¡ehâ3!æßà„õØÈ5{ÊÒtU|$6ö²ƦK|©‚ÝÝj™ïË_wì"Œf7’€€Ç«+Àê`{ÂÛººN׋»¦¸¬õ »¦ÝÄ_ªY+Là˜¶¡åá+pýѶ›ÈØ_‚W,þ}–h€îësPï5}Ñ#ô†…¸w,bá‹ò¯`ƒbÐõLnÈ(zá^ BÝ…@KÄ?¹`þS6ÐæØ¸“Œ¡;še4… "iš !$9¤+­á Ýña~¹bàz;_+ 1Hq€Åm©WE-™ÓêNÂ{»Åg[ ݈ÐÐrݸñIضT`a{êx^>æB¬h§¢ÿº:ø»„@®Äy¾)"ý8¾÷ÀÜ;qÇÛìv"DºÚPq%øJÔ®µ&CjÀú¹Z±ƒ©¢ötƒ»ïVç+ÀY€©^ |+i!LÕ¦Ù`1jr¥»¼¦ìêáG4θMÚÎa9”bi‘ñ d¥Î­}M“¦Ös’QÚ•§©%£Pÿ³ WƒÓ¥·f|"q e¾ˆ!š>o8wñ@A]Åû»¥ãÔlݧŠ9Ñ#‹!Iâõ «Öã€9øãŠtPlà?4€2ítKó—!ßÜ>jQ05á\*ŽU´ºþba<‘>x‘«8ò\ª”‰”Ô9Â{«èÛT4¾Mïõº3òï{(Š7†zœ$EDÒjüKnHwWÞ‹Ðb›:Ûnœ.ý¸ ¹óÀVÆTS½—¨&LaŒ›çÉà>)ŒØH0À à5±åU¬Êx~U?áËÐêÊÑzáFälûlX¤6#=ÖA†ñ‰v9+T!nbjmJ%µ_Ádþ,´ÿSX[ÎÐò)jãËÉYh~”f™n5eñ“­AAÉ*¡Ë'µß‡ƒôd#öUêÔ¼>2&ÇÝ„µ £?G'rÞ±,X;G/-Á!sÚsÆË©ÐÓ³Ú#ñšÙúCX¢á™¨ˆKªaö®pP+ÐTv3²ÄꊾZ98«Ô&oÑu+å`«J°’€€´(Îü{ eKAv¨77ûü ¼~q* Màªùÿ7PV‰U¶`/¾ÓüÍñsF-º˜;é0b÷ÛaÑðÙ]Lö9ýzÙwCeˆ¨ó"]p‚; écºv5å;æHíHÇÐtÏÊÍÞ–![JŒEɹÉÌ ÆÙœÐ=5á?fŸÍ=½•šÝMßó¦00²_ÊVÔzpý2&úìCÕB øÌÈihr òµ’ޔ̨f,; œT³iÓÈÍhˆÖÄû‹ö¹‡sZóeÍðK@Ç{þOÒ_™»ÏÔ¢òÃqoIŸ)Ù±z÷^ZŠ8fq.”\–+{ €ÊFÙ&+Ô蔪ëxý`*®UswYøóJ˜ïÓ•¾”¢@Å#çÔ¯´²k¿K=7”…‘JÅŠŸ]u wÞrµÚׯçz¨ öyQZ¯¿¾x0yu%|8Ⱦš)”èFBÌü°uaì’4[«˜-‰'AÍó{hÑÂÄÜâJ}ºç5ÉCüc|Ýñè>i™Ž=gÿ½°JxðzI¢yœ%æÌ"°› 䛂U’Ÿß}1üúÏE¾s0ézÈÆ`Ñå]6ÀŠ# t»X8~æn ¨nöUÛ5_™\õE&¶€4"sk¿â‚Þœ­F.¢þí”’‚ÿã’9àR>–Ÿ.Qö>fIe< ïÍ(Ò·÷?¼ªI·Ñ8éñB€f%”Ci/òüAÿC#À0åPT:í, XÉÄŽy©(ôÂ/wvoѸföŠÕmÆNZUÙÊl(×1tÞÖ×lÌrÅÑé2õjP9aNÝhÑÔv"_ªšÅGo;'k`Q º¨jŒñ£Æ›£Ó‘ Ý%cý^Kñ}Ò1çcuÿ©"Œ…âf—´ÙX:«SØ#_gQ ÉŽQMüÇlpM¥]`ï[5¯3ì º4´Nóôd’€€¾‘«†ÂÝ’7‚¢ÃÌXjöXª*­l=?Aôk×Ù~Ð;Õ¢Ú2„ˆ¡.6rmD7ÿÂG*"ìT†s“áÔ†[ªœ€r@`8ûbÓˆ-_Ë/‘s±ƒ¶¾‘>”õ\,EµÍæû›;ÎGçÓy$Ró冬»—lôî¼^gTæô[K³KÉw\Ó¶ÉÄÉ‚ÑG[˜å.’Vn!G¬µBÐdB”Sn=NûAWkµß:àœ0­¼³?û•0+›¢¨.4þxAƒ°é“cøÐp*§LÊ2W:s‘÷XCOiÐL>Y*Wù.0‹EÇk™³HK3ä%®†[µ Aˆ reΕF³ Íü|ÙTd°–XK0¾ûÇ!ä Î ¯ »”IÌÀ„žN!^0èU­ýëKùxÞ^ÔÌÝ9£PHìØ‘›(\¬Û:Š5¦Ñú×ésµh55wjìÎÍ´Ðü–õžì'GÊÔ40’¬—µ‚ç9O‰›<.pz¯’ÕrSyȨ4¬Ì²(bƒeÜQIfíq2$çOlÑ`¹êæ­B¨Â0 ~&´êâÔÿäê]Ù3¢Ts¯¹ª:,Ý_ö6¬a Pèaå2L;i§.*5æ¥^%`“cs†±½¿Û ÛÝ58®öóñ°Ãñº™&ªÅ¢" ]ìϵi9„&µ _k“t†R>À¯©ÈËÔ–õÄÎY&Xò͇TóÖ'ûþ†S«èsP{ÿ°Cß¹£³Ý¶½=F“?õB8ù£@?²ì) Åb$ä„د3 v8ÆQà{WŠR\V-Tù™_Bÿ3/»AmõÕßs¿DÑWε–¬ZmI%½ŠKÙ¿d°ÀŽ:ÉbI 3í¤P¼¹«@Þ¥ïu̶6%­ºž­ë7tf ìN^`U^¸å Á)4óèt8*0ývŒ™¸àO£ª°j"ʵ_–nÌ`5EàZÖëX9ÿ1Q—€X;/v;?AfS ’d;ófÚ¿jýÀi›`Ôì3ñ¾žÂæ %s73²ßZ.U¨ÜrZ×cŽ'Š—e¨¢­ElsdµÜ ¢À ±Å»¡‚ƒK¥Z:47<4Ú°õ÷ó?÷RUÌäÈ-’NÖû¬F¤vð¼>94€ty‘m}ØÃ9ÈzÎÎ7ò›ç"bƒ‡S£’€€»Ê“½M£‚O?£-ݰ®*ó;eìS³Ù°â„òö¶EéLsèéÞ@LPŠßN¡ÃÀ­4Äq›á?vÃŒ+f#Õù¢¯§ Z&ºç€øÓ×¼#4L•h‡ØFQì2 ±øjK+÷MÔö¼÷sðÄ3˜QP ݉(F"?ä#˜@ñ™°ÍdW 'ÀJïƒð&x÷ê· z92,̨GW›åý ;sß0*²A‡èÀø6Ão›½È³õJò¦Ü¡=}/WTc‰@¾Ç……Yº'\¥Áÿ¾[9í=5’EîÀÿezc¢½0’î˜mÚªuÒp”Æ/Êáp¾!ñêñôÍ%ÿ&Û˜- nªBânœîôl98/àÓ-Òµ‚k—ið,ÙZ ~ B>æ)W0+Í´n¿÷ï$…;¨w)u[c½&eO»ñü1¬J§V¯Î¼K†°v)dôGP›ìÇÜ*y¬È¿ëY”§(]å§@zÿð“®Ät‹PÝa“:6×»1þ»`²«] íäåÝqxTk¡= vƒ¥ÂÃ,AÜ~MwÐV!ˆ¶|@›ñ¬‰ÉiñóOŒÌ…I– ˺÷¤ûìþP%ësSpsS€HŸC£V3¶&àΨwœxˆã(‘Ç)Ÿä¨-¶êÇ%+o-M?WÚF–Æíߌú£V1áw`¢+á-äÞeQ^|ì{½çSéAeÃ+RA8¿³ñ¬e;! ‹ âËb‹§o¬:Í&žk½Ú©»Q(Êù÷XZ(¿gXr¦k4žÒò©¯D Ñ0Â’âT¡Z-Ô‘*:ˆ–¦Ši« tÞsl’-ì‹ËV “`5ég;Õ8ï„àÿMÜM2›4Úñ}-þ˜¤˜õ*ìèâÒÝp#"!Áþe¦ÛóC w”B†»i’Z0ðKä "úpý-J¸†D^ ç d÷\ß¡ý©á9 ý¢\-„Ëg|!IDÙv)ÚÅ™šøÂo¿Öd¹¸^öZÚ~~ý®†6ë#—çv—Ñej4z/(oeÔmùRÍ¡Q#3î™U®5lc­?il’6%”Î>ïNsøÌœ¿, S }$ÙÇiÐÿ5®*w0•Ð mèKæû õ ¨”ý†qß⾜ñÜQ]Á-¯k†õh&ÇO«Z¶¤åªÌZ^¯u…˜š,k³®©’€€Êà­?ñu˜EíÁÖJÉ©EKñnY迟%êªY––âÊŠQÛ@ˆÑï–Ϭ)“ûû¨Œt—yP2Öq@QTÝìðw‚f˜Øç‘šLjqïÏo€Vg3·¥ßp·¸GmžµŒ>`Dú,Ò' nBÓRËÊ`v‘éiõîå«h‚r@5+šŒ<ÕUÆŒ¾q$þ—˜À ¥Gs:`ôà%Hr ,‘¤! ª- w9—wEä»cAn¤ÐÆúû;M•&H¬êJE€”ȲÇzyO~lqCÑòù­ÅXW^wÍgöÈ ¸?pïíO{ÿ(v)ú]¯G>š†œÝ·ªçRæ~§=’áç“ýÖŽ£79ÕuTu§|‹Ù'¼Ûá«Ô8©OðÅ_WÁ ä×oz8ÝèÄ–5PÖ O.(Y?ˆSJæ^ ¯’ÿvæ+Csgû¡WÎýV¦N;Øz«MÞ’½ðÖ+)ÚXi>Ɇլk>(­r¿×ë3Øñ 0¦Œô+¸tgþ:÷¤zÓmñNw)šl°'«üIìÊ}$КXÓçF@6n‘¹4«l>ÁŸ4¬Ïä­hL `É1 O|.ÏÉYíÕŒñv„¢º~j/`‚lȌތ+Áé“>A~ý& n›ÉdãÌÐ’ +\Öêå=có–qê¶AõœÓfAyºù€rÁ…XÓ ø…6‹ø)v¸ý¦DYpGòUEö;5Ï–èë§NÌ÷ç$Ǥ$=ó79†ySÑÝhû¥|ÖÚ$ zª)<ª)õSÈ#Œ[ ,»¸Á¤ŠAg2ضë=µ 0–¢Ð’øÆª*Ùû>. ’†cšï7Óu,sË=Mt¡!;Yã4ïSÙXWÍŒsȱåºN=ì"x¬õ·h _/6WQÐ_Ц»Cá=hN_BЉ¹‹çn4|¿[z"ü3ïŽ?Ç]¨ˆÅcö@½óÄ5Wíl88R0E@Îþ9“¦^¬ƒaî[Lr]eélqq–WÿGDŽÎ8ôª¯[„±‰}¦ MäY÷k1F°àBú¡Žoõ`,„­:…pq¦iHŠ™öàhÐâƒúÑ&é1î°F ¼ñ$ªí2'Ôj!“þÍÇK'2ŒÀºŽÊ”{æ0|f—çÓ1?uèpêŒîP/ÿ’Éœ{ÔÕøAê¯hfú’€€ÄsVF‰’£1«_йGÙé:Œ Ñ HSCÜßà·œÞÅsQO)ãØqG"ÀìïÊÏ, ¾“ãÓm‚j{›ý7®êß—®Ñ°ö÷à*ÉZ¾OšáÉÎj=Þ&½Ÿ6 ZùN“Y÷‡éGUƒž—É—ÀÙ^ªÍÔToØ —Mô ç æ÷÷°jW-î…šÝòlÊËõi§¶Dú¼€ë—?sxÖ)äAÈÕ²=p=“Ç’ñ0Ü.Y×wvY=ø&D„a&ð#³_cÛSn9I˜L,Gr2ŸÀQLt-Ð’€€´ÿÔP̯ŠL7Öc@« ¸Ì8åÛŸ³³3Ú¿j­ªví²`»hÙ+={r¼f¬êÅ÷ïö¡|d4£biíuw[㯠ÜáB~vâ9 ܽ%*+µªfèͽv›Ëµßî>ÝQŸŠ=÷fi)'sc?½ShÜ¥Ž37ˆ#ÊaO¦]¿Ò+»Û\2”ó|>4x92Î%xž±b¥#p’”VÏ BJÚ¥5 ùÐò+ÅËüÙP5ú/¤~æSÊ €ôŒ ²Ä$‘ƒﬠÄßÉ.àù© Vaã]çd ô¸•k HÏ¡Ëý¨ÂÍ׉w-ú:’4o“Í$µ®…±d­'æµ'Ëq=_`çkì€Ò‚â™<‰KÍüÉ:m®Œ³rà3XÒ!Ò÷òôåÔB3pºž7æÐi3MêP¸\uÙéÂaál.§47œkîÛ™²¡=¶©«÷þ»Ó<ºk[¨ýø­Ÿ­TmöO×1˜­?øU¸£Á³’)Ø’»äcÞ~Uú‡ü܌̂6cü°Ú[¯©è㹎ò¢r0Â0ÂKzÄfˆÁŒh"Lá:&¬¤<˜¿7Á€-b>ux8À…iI—¢(B@«ã ̤V¾x¢´ÕÈ'´Aôõ ¡6Æž³>yDÇm W±ÕŽÏ{˜;©†Î]ÿDŸ\ äØä{œ2ЗXŽ¢UoÛԹ⚊™Ï^>d³µ™‚_Ê82‰½â€¥´»]•=†Ç9¸ð$~TF`hzZkUЛ5ü Ê$ˆ±ûP{~0=TØ¿òx²W¶£æ¢_«û˜è}­ö\‡¼Žøâxi4SøÀnµX-?ûàÉÉü}fÞ µøé¹!†ãâLõ,FÜ™Áõ():cƒt:#}n¤"‰(BŽãKáÒŽµ(?Ññ‘è©iegà/ò8aJÔ«£ 2Óöù«‡ý ×ze!cd@ªJ¡„€sõNSV,yªA?°WÌ ø5/ ”#ßMßÌQ2ÍåB3 KùXË­³-¾5ù*¾ž{ž‰ذ°RâÞ­â÷‹ZNÓ¨ûDÒ L‰úžÄIæV"I…=)Ę/†½Ã:oükùñDö1å=åÑ^„÷h~äu2J¦nŸfïû0­¾tê:„‘¡ß Õ¯ðY1ßær©€üàHZ8înÚ$¡’€€æ€äo™Êb»¹~ÎZ¦3üD*fSVZ5Ýq—« VÊNç´ÊÞ0™”®,ª“6d‘¨[CÓñn 9,¹:'ú.ss·¶ùšªöX¬´M\2ÕÙ Ú2.$i8R"ª„púL°<pqJ/¨$°í¾ªÓ¡T Öce¡úý)“ÏÁ ã`ûÔ¨l©P3ƒÏ|7¹˜+uÆÇÒ—UVl«|.ɲ:hW: è*rNB6ˆû¦^¿Ïo©™Ë×¼DÖÀ샟´;nv² ¯g:¯@ñ ^ºGJØzm›/¬³TQ1³YUHD‹{\T}qHpÀÇ2`Ýr5~™Òç8i[ã(ÀZz6‚òw ’÷¬­Mü¬èGÞ±‰ýDÁnõNC`'Źru/Á <Ò2Ľ!P qƒçQaa3$ ´¥OL£ŸŸŠzh“¥&\ü*%¯~¬ƒ¼Q%{Ù»`X­ý>´ó¨ù“aÐ:ÑâÈêv`ãlŸ'¦ÿ m´Jé–u ýã¢[ûãíÞ‚ä/ñ¾ë)KGçqgo;¢"ÕºY#´ýU!m™21*Çuˆh£ ÓÅ &7ÊDòv›{ÝWD¤fº̽|0†ô’NÍMÂ"iŒÊÝ.»Œ1ÛCP@¨ì zð…ÏW˦ÿ ÒÁu^­ú[&‰ÕËÁMnmð¥ Ü„dìÇñOãrÖŽ ½–þ¢цÐöI³*QÞ¾OB2—Fþ×÷fíC^äŒÉ.â÷r^Ì£5{n–¥’‡~ÈTqŠ«vrÊÚUÈÎê­'|BÜ} zœº¹Ï6Ú­w%u5Tˤë ‚xk.3ë³+Gc™$X‰ánÉW¥×!B;õÔ¢ïbáD§=n¿¡‡D#½]jzrŸ•úZKuI',¼Ä]uWZ¼õÚJ©_gÙ¿>=„…;ˆXKr·'}9Ÿ>$e·>ªÖõáYRc·Õ¢e7¬wXu3 -Û £¢©M 9§gJ{jö"}`oea—f–<8]Ó|ÛÁèê;Íü;Àø2¹¯ÖÚ3Û|“QÁü*Ô‰‘Ò_Í>ȧ°€›4óP ,¯:¨ÎÎêóœ6hv¦ùXD“ Ík÷ÓË4ް•®ŠžGdUÙŽsÏ}í‘‘2Œ3Œ¯çàÜ&jîLÛÄÚ’Ê#ºŠ’€€¸ÊNÚè+CYû‹¤ÅZÁÆëJ@} ÀñÞ*cã$_#ß…q€Ùå’x$©Z÷8iv©0s ?€µ™¨AÛA(‘¸=dž`&¡À¢ VZXÏ¥#+'$3ß+V…Wx@ÐÎAo<#ް« š\¦x)Ú9Ç7šUsÙ`Ά‘zߟJšH¨m i“³†”Ãnxe”óú¢¿UHNfÜw‘¹X&»L„t\ë q¨ü-4@“hù)ÊKüÊ|üQ-ȺÝz 4+ë¡¥¿†8ò[˜Ñjžç-wýL -–tsd•:L¿‘1¥Tô]·8Бݛƒ¢…¹Wž¦Ðë‡N9«U6=àµ0fž— f´Rß~ƒ…°«œ'Á¬H]´ðõ:GòÖ}Žpi@˜}zD @‰z[z&`¿áêBw»’ðyþD/ܺ(¨ î6ÖÈœã9K*ê»ü M‰—åŠáì„üìÝÐúÍW÷2·¿£û¼—ÈiXì+‡)GÉA6ÿÖ´ã×D¹þ‘´ÓW*0/'âöÉ»Ñq”#DR¤Yžã¡þ;iü‘ô®Õ¤Ô”ýgÅL¦Žßgðd'riÕØ<¾É/J-bñ\Tߪ$Lçl=2ý1²Cæå[qóÔë[ûJ(iâ'r!ÙË+Žíðã%8µ8£K¯p¡Á¸ºJ§$l» wWf¾kg&=v€E{žE‡"½÷ŽgvŸ1”¨°C·ûÔ\õä˜q!ç«Îá=A‹Âp•¡šâ:´îN‰l(d n`2˜¡²…×@ùÓ¥l­CVž\Çð:•CSù…Òi”°—ÅóÅÞ˜EO,@ºnŠ ;ËÞu;þàÃW˜·Ê™d†™IZn[P+¥¨ÐxL|çpÜ^Cž¿³#\ЧFb$‚u1Ú¬qÅZïw½A qC $—:Q[“á£9N.9sN‹`Äéær¿§ÖÙÌì÷þ¦¯U?=é=”YŸ×›åIƒGJÃiB¢NÜÈÂ^o׎¥Ý«éJÕRl ³Š/5üv_øh‹^zµ³WºÞ(’ìÑÙ­šî÷aŒ´À¥ŸÙ³”6r„†üÍCþïùü}/¾›«J$gsvÚm€”Zð$¶6û¥j Pãðu­6#‘ÝÔ4$ á+’€€âPT ¢5ïÈ ù¶©©!êû!"š®8|' ‰2Aµ+! IaÆ_JY=?Ý@0E´¹ÌKKí-Ž'÷0¬ånú2e¶|qTßñŠG„L&À ´B€“?ŒìH|IU&!!º GÀmp$}fq;Í•ÿÝ…É€ÿ^™Ð[‘@ú®¥Ñ»©úÁ§¸òúÜ5‡]åø¿…"0Ö_ªÊ 6~~jXRÕ¾t÷*„Hªë…–S!*vÔo¨—‡ãGˆèI¡™ÏHûJüþS»Q…iV¦1 KÅv’`°]()23]kÑu¨þ·s"0m³È·M’Y 6Üfi»8mL3WÚ¡*DŸÏ©ä“¹ã¿à _~iˆ²yë&*•Êò;«œeG%u‘ P[+“yH @§IÊËF å–¨:ÜåjÑâÙlœ;%¢[ DÔç¯ÑõþŸxq¢¯>’ñ§3B¸«¸I ÿèJ«—güjbµì²g—w1Q5ÅÐdN2ÆÕDù˜­ÕÍIÞ½Å;«aŒ6à\/WosÎ\oox(¨ŠG·ÂŒeÝÀc ,Ò.ývÏ'Ò!ì–ØÉ­ºóåJ=zÝ”Död!1ÚËgtí~ eŸè}sš¿–;Óü•ܤnS%9*-rC|l 4MýWË“tÛaÖS 5O(rÈOQò&Q€6KŸp¿ÊÂM†ØLRˆæmLŽžVŒMD …00Ù»Ó¤!ÔÀöñÁÃNHr0ÏQå··áÄ à #÷噚'h±û¦%'?˜ì[£J!¡ù6&2(^Û[×z—Õµ ¢jþkÇ©<%ñ e'‘Ô iÃÄãïBlHÐk0Ð;°"›Špúkq3¯OµÕÆÊ´F}±^µNªœF È#Di¹†X¶óгکHÄŽ˜‚çZ;vV9u©çé¤?pÙ±X8|g*aàntˆ[ëp ÐÆg‚±rsJ1iIÛ¨`Ê­¶zÿ+öË¥ÅLfw«¢˜€êý•F„–ibÊŸ;+Xiß”vã%žcPß|°¨W´‹_Ž–$ǹñ@L²Œ¾*k_úyæÝaƒr³â?}VÒ¬Él(t×õÂÜ@¹zºéb«FUÁßcC*NÏðUÄÇwó0²‰é`¤¤{Ý‚†:õ=®X¤3 @“P•¤’€€Ó¤ˆÌoˆoÒY˜ýnôÂ,§ûŸ£+0Ú’-@¿}w¯+îàí˜P‡ŽC*…[§jDouópïϱŒR=ˆ†ÅðïɰôÄ,µ4í¨201ZÈZ!,V ߊ%6Q%ŽŽ‚c]š< *Æ¢˜Ç©d^zdm7 H£^iGölÝf’á3Xf~SjÔ>oF/ë²´üô/ʾtÿ÷¬^CõsÆ>3d°šÄæ¾|OˆÅUξyHOuâ¶4¿½OR…À¤rüÓ·âí,ö35Ö^Ë©õEl rˆ¬$[ùÛÒŸºÑ®÷âˆ^¡uk5Öæ²Ôp“Ìvl==§– „4癘íÈК¢N"´*ˆÛ•X‘îôpþ:ž çðùÌ5åXã ’Kh$,ê+[ÕÒâŤŸè¨™Ánr“©œ/‡çþPVœÊ$;í¢!;ÇDÛ;ÉI Ep¹ÿÙ÷³ØÚ'47”wÝòyÝi£ì“s͘¹è:}ú€eWw¾Ú{ZWÉ ¥H6΄ºËê[ÜjxkD´œ¡§3‹›õ„%Q6òt’ Mþ§™8ƒD8Ç۽`‚,ºŠa^NYÓˆîÅR—³mƒÝö…ÈúÙ‰%M2÷Ö¨ê£7·ò•ö0åöE¿|˜e>1®vì@õrú^Š®+ì^ÀLvÏd^p"Y ßÚ΢¡`ä›,6’®Ÿeüô˜õ7t&÷ŽÒêK+0ÔÎ/Ëeh÷%•ÌW¼¯4!tQš _‰N"¼ªáÂŽ<êM¹Ä‡¶ãg] `vß~6Ÿôéùö(ÞAJ‹Rµ–r`öÿ€ÔCÌÂÀ©ÉœR–:á“ΣO"îÃÙ”ôøïS½W]‡H¿“ê-aV;óËN?Ò´qïbÑU€l&j q2¹geG¡‚™Z;÷¤e©Í_vš¤’Ë@™äk}QTBwHäAã2º9d³|n[[b£yäê_Ëp^l%¹ò’Á¦†xsa*øZw°m— â™Íÿ™Âø*G£s'›cs’€€§kõ1(è¬^PøþÅ6OW°9q–pF`°Š#I§ЉÅBÓ_®214­:3>¶·šŒ`ìíh†âÐ ¬ŸÑF–‰È>÷ºJÏe’m!Ý-D¾iHó &I¼¾´éö¹÷cA³ò4sfv x2€fw˜œyúùP˜’¹êSC… ¹¿‘ÙoòÌD¿þtˆü2~öïÍüS/Øì—z@ݤ`âCTÍ·Zµòÿ|†)o©q¯"Èyw–Ö¹³ÔªÌúÒt$ÖTÆÑ(sjK^uú@PxSSð=Pkßʽð­›ûZSú8à’¡Al”ä½þ_ØyàÕ¶€ßr+¼¸)ÏÁE +æ¢óK—áïV¹ ö2T‡ÌÝ”Åo*Ä ˆl@ªµ~]7ƒŽ({ .ðP 6,þ?DÀé÷é¶ lëˆ1'ž DÿÉJqÁE) 8`0£p7wz‰Å¤ú £˜[m³‚°'W».¸îKÏi£Þ:^iêR=È Íξq¬ãÁ‚Ä­Â/ù¯æ [Îûî>§°êc*c‘ÐÚ4ß=­O¬#iñâk µNžq¢z&žvøÁÛ £ŸµXcöËÍFâ†8Ô«—°88ÌÒµ„´º Û&€©Q9XÙŽ:›wªäc3$ЬSß( X•NÜ%aòÁÑ{_Ê×; ôø"ØGÃ.(ëxi¥õK½H¡)ïØoôöu"òt¸ úóhÕ§ºž&üÌ™P/œVvçÒúú{{àÔnT= ȇÍÚ¬ ´2¨öèL ª`ð).í³íkø¯6ÚB:š€J3©Cµ’Ôó fä"`Ì™‹vânñ?)ê²¶¯c¶Àªâ²¾ðRª:¦sâ^ÔÖ‡ÿ`P˜hïÖ‰)²“leäoDÏ<#%¢Ûÿɉ#Ãã@xPÀ§Å(òº8Źi܆^´G‰{«o)cÀC†—–ÛøµõÙû2æ~ñHWWäî&æ¤:ra¢Ÿ³x²2>Úf ^HšÅÙžêâ<ƒ÷‚Ùñëk{íÂÝfdôÆ;ª‘#ô£ÍRÄÂËg»òù\bˆ&%=O›˜‚ÖCΧ„–øUk«‰û¢« §˜ÎsFIû·‘§ Ÿè¢O^yËN.æ3Ö@µ1vYlˆ¿»óÞ6dË®té-sÌ塺¥Úm{—§Š¿x2<Àzí#ª¹öºil‘I#ÐØÖ—]€‘GtÊ!Hæ³K“’úõ¸q€|»ÿ p(›Ó.8 ,}{Ðz]ºÇuÁZpcþ[ü9‹9]K‚Ô5_©L/é¯{3}¯• ”RÀ_‡#k)(ü9¨FØÒo}b¥ ¤èpÏ@$QŒ¢‡[Ãùℤjµ×‡°é{”ÆdžCÔÿD‚å$pÝ¿×íkÚ¿?#U_‘õ ²Ê¹½×Dm¨`!J 5#ô³Ýà5£™Bhò‘ñp û¡f·-I¿èµõƒUÊê¶ÅWÄÂÕ‘_IdñW‘}qÊ"[ÞxÀ›êþ ²8¿›^B­‹›bÍ‚ñŠ©§W¢N°ZåßJš°$=øŒ+æú}϶8׆¯Ã6˜)µ§§”˜©äf+.¹H˜)üª®GJÕx¾-Úk‰¢êunMýÞš÷È8œ/­C5g&Z.ߨær-|¿D8eòA ô¸`‰ž¨Ä¤bwÏæµÊ°N=îTÍE}»uà·þ÷9!YøycWO\›`†·"ÒÍá/ß Ô ò€9¾Rùœ8;àßx !kÑ×m”äºñA÷gÿ%õË%MPM=U~ÏÄ"Mç0=Î*HÒE³–'ØlQس(J«”¤2)¼›wïp7*Ìg¯¾X½¯ÿ:ûå‘÷µÍ“c£l³îÁ\¾F][M@{÷,¢)c2ìDÈáòôb7¬­@§Ë8`Ô^@ÿaP*R‡o;C\¦…&Ó©æ1úv(¶†’€€™6L=#L€UekÙ-Ç·”; ‚4€Ý÷êÃÃí­3räÞ ª¨âJRãöJ©–3Ò k0 nÛºÄÁž­\QfC@:(“ÍIJ56Œaƒ=d0ËÈxáÏfF¯Ýß25­xìYÈ\´’Ù®¬“ºÀCÊyÜ7§™ró ìrÆg´„ÀU7sëÿ#5(¦¡O«þÄ=5CVÌ0ŒavÉýìV²‘l¹ k­ ¾;ú©raÌvð³bnMÜ(4ÆÕö3“°FÚ’SŒjú[‚Ås°—sëKÒhгÎ?Äï›&ãk9¹¡´Ä. J±¼â {M@† L'`MÀ€¡àU+€Ià7ùp8 Ðs‡+{'Œ­ŒþiàÎèk磙 Kfį¤'Ž<”½nᬞ½~õÝM‘¢r¤#KÊ 6_Ñø[ŸÏÉéTìÆÖu%{¸¦„­½ÃA¨QE»¹/¿=lÒ3ž`[Æ‹Ý3<Þ^êGVÑð3 ^Š@ݵ'ØÑ°xQn®W–Å5ŠVÎ}¢˜e¸.`Å·¿«å#~1ÇÁÃÝüÏ qð¬rÌ4å,(¢@(\r8T«6²¨þdy¤4’£fýdò»+v%{”ß;\o}‰PbP²#Yûï™›ˆÆ–PǨKÊø€ØèjYWáÎp ×ÄI|Ñ`øè„ºH½Ž}ÄâiVúàF?cζ9…¬KíÎ…}Þ| “‹Mdúuý¡³ª°œ:;À|¥ñ?è±/aWIªëÅ©«Ò|"ï!/¤m¤ÈðgÏ `¥,æbp[¦×´; gÁ‚=y}“¦q×äÍgÈ—ÜÆz{×À`÷ÈzT ÓÙ´pu«}Õ~¦ÄÙ'-§ ÊíÙ»ö¼‚–’€€ÄaÅD(LèKœ¢r'ó-:üM~-3× àæ¢>­á}-‚:†¨Œ ¨)½~ÖÝÉà{r¦M@Œ¶}ƒ÷¨î°È$٬ˎRÙPQ>_Œ8Às)’4U%jo_Á_þþÈÝœÌ&[ev¥hpdtðЬ H­•-©j a¯jì±[piA›²3ù‡´Ëß¹@câb]*æël#7H ÊÍçøš£é7 ®ZÏŽ«Ï=ˆ¼*¸¸—v탴:ÖéÔ-h˜ÃÇÃ!¾ÎéçÍ5´O„{…è.XƒAq ¯ûî¤4‹Î¤ÚAI^<¶fóJÙ_ûIz#…!y\ól6}•´ê®C‰çÝÎû±>tšÇ"®FÈiÅD÷>L€÷,ÂN¾ ‡kßä éȨLBÁCîÌvnA¤+WôRžyT ÷-ƒYÀLxÝüÄÁ&Oí[øŠr@µË¡˜fzáœÿ;wJ½‚w3úf‘7®uêÝo3'–Ô…–qÝÕ4Ü¢oˆéG×mqÝä«èØ¥*Dí0{Ùe?¤9±ÓØ3–(Jµ{Õ¢Î$–q6lAÍ€ºÁ®Xbº’‡yL×â}yŠ©Þ¡{Xô¯± š_š ¸qhŸéÇ]tŸ0N^®Å˜À­2ß·k“gÛ2¤³å7¢QkTÿPŸÚÁøÇ©s,ƒÂy‡ÍEN~¾Þ†ëxŒê±‚Þjüt´{x0¦£€È ŠƒT>=~å7¤(²Ýýþ¹Ë&¿&ÅA ã{,(™Ùß" ?]òa˜Ó5ôž ÄnbâoÌb&Î,,¸~×-–Çáà{aŸm‚X½ŸíøA)b¤UÊÏÒˆ7Ö3kß^Zñ³‹ºds”–“‘\ÔnÛ#©Š´ª[÷^f|FFÅãUT¦-ñß÷ž ó˜b$µìsYòÂfm–*fK}ÓFÙ¬9¾lÚP¼BÇŒ¹e0ÕSpàQ2g»i$óªuXÝPýVj—ÞJÊ\rûÉŒÀИEi¦‰ƒ«04Kç(h~!S=5ÑÓq×ñÙÔã-ï“wç4J;¼3Ç”›5A!©¦”ßȬÚÒÚþ¶¯ì¨)âe®xŸä– Óˆû,¼¥ò)ûÔ±–T¯ç±3¬–sáà.·&• é¢/ïoõ9%ð‰'×{}–c%_E'p*ÙU,¢ KjýúèHYÑ}„xc27w C¦0¤ ÔJ†_—ˆ¨ÒRRmïˆ\ ‰³÷\AÁËõéMq»ÍŸŽACÌ]è†ðÕŒË9ÆMì¨ôóŸœ2†ÒKâÄ­ÉM-Nïgü{Û.?Þܵ€&KU0ÆP¤ohÅþšp}›¡²Ú›Û˜ó5¹âp¸êéØ5…¡`¥ëÕ[C#çÎSˆ¥w’.Ô“©µêøÂ&“!­òä¢%ˆñ€mÝŠ¯AtÁ\BÅD´½|ÐÇLE«ÍS’§òl†½¬® x‡0mºïrn|Y§¬?¡å`òfP±ÿ&tÝÇ5nÕ-ªnÇRc8J®²b·À¢!«P)a0/Ñ:L„û3Ç{³’hé$¸ÊŒèç`F5Z–ì¢Cn‰ u‘sƒ8^5‚HŸ]h%T%mø­  ØGEQ6ñ 6Ég2òüõÂrOLháP+Ã^½nÞ¡ß?WaÂÓ ‡’¾ÿÂpa—@²ÀI÷å˜ï:¡G@ʪ/ù›ä!Îcú¦¸uÔ®ÏXo€±«¦™L3·67hÓ¾½qgºþ([ÕÌ?×ê÷«œÚTi~€WCáÅôrUì‚5.OÔõn¡a±ÛðÚÒ™ü®gùzì»u¡ƒÿ 7šÂº|¹wLjì"’[ §gëöŽÖ7”™©×á®~¿ÄN°ß@׈9nÀˆ6i\6zoNbsØq]°s ZÎûo6¢­&eÛ3C*ª›Ü{J~¡„(å+&ó{\¡ÅäfäÁ!r¦½õ0ù”àÊÍrÚÇ Ã·ýn2øÿ¯2*’€€››O8·]..«3$'-fÑ”‹rp}‹³çî Õ Û=s'+¨§ËšÉ-ŒÚ ¶ÿ[Dtüc”tÊí˜\éPòš0Éì1bNÉ.*ÃCxž¤ëGœB]¡c«¸¬çÑ›h¯JséDZ—´ Â ¤6øosÖ±ñy(²2M+5̾uN iÀÏ:(.(>ôH1_ C7ѰoâãÒлôTÖÖ…v'âû®“X÷ãIêSmÒ{:ÞKÂ`‰¿øÀX#JØ~f†ŸNp#õv7*–ó*6Âs3½«x¬´äÂíS×Ï3q•§=Í£VJ8l (ÎQ3mõ„(ÓÁ Ÿ€oªaa¼=wóŽÁŽT´(‚` =+Çñ¯•QM£² EÔÙ§9ðDQ eS[e'¹(»o,ï.$hà˸ LטõÌ]è¿íÝ^vÃëW@z·¨CäΙq¾M¿\xç9ÔSTw7'|<çû ?ÕT°˜—æe®¶×Ðý¯y¬2ûòñZp*D¾mF:]Ô{á @¢9éµÅ"‚Ò»`èvlk0?ð™™ß¿¹O0w†fÇ’+[¾X¢RÕ“yéC×((½ž½ùmb~¯_I­7Œwñš ¶b²*½š‘%`Æ2¢gzâ4ßZ!™ÍnÌÕu=饖»D¯C‡¤ÊÉ3½•œx+@?¿Ây‡°šö‘XaQv#k:xâ¢Yݾˆ%ÆHÚwR¯òL¹ù{G®É­ ä_Žò ­ªvÔaÂÃQßT8Bép2=öÈhA¨òäsLý(zÃf œ!¿$Œ[h“œWÊí2ΖæïXUç¸Â×™£¿Ã.º;)ñÃÌ?¼åÉôé pèݪ<MêœÞÑA_‚lWWý^ÖõOsóÁÄXI†þŒ GÛ1?:Kåm¾Fó#6pÈ 5…åÂÄFÄ9W™Æ½NFD}ìD™œywÐ^è£:~ש¤ˆè ÏK&Äââ\¾p‚ºÀ¬=P+Ýní¾’€€Þê@3ÕIeædÍÌQ(YœœtŒxzÚ²³ÏêiõÌ…ø‡ìpÕ°¦è¤Üj zÃE~³Î!v<@¬èžv¼ƒ­Õùør2-Gnï¬:ƒ7ƒ¯ˆä‰XœØùKÉã¼¥ŒõôÇòäBÀ‡°E«Vç7«!{׃³¹=n7›®Ó‚Ö d4¹9lrÇlžÓ‰¨Á'2¸2²µ³]ÌþB$ÕK[jõM½Õ)™’>_eÄ[•+ïƒyYËÔìPAŽa^°Jx}Öèç¦2K\sPJsÈ™PO»ŠÐž.$bi¿Ày®OJú¿Û\wL=óm O’9X”¸ÊçÔœ‹¯OÙ+ÿi‹«Òíó‹?¥:̺g£»q¿•)—ïÚ.·ÇwW•¾ÿþ;eß¼jž‡Í`\e5r$}3y­~Øp¿ÑE«AÛ¡rþ3šú\ÑÀ‡ƒEðåV‚Ú­n˜Ög§¯ìË”Òáý=iv­¥“wá`ªQ0•4 A×»Ï1V†ûÀËõ!ÄÃvjÏpùªbžM–ˆóI à Ï\hÍRå^UC“ZM´¿k,Én>µb`žãýu82Óx¶yþs©h¸PÇ©kZ"–²[_-§ví„•+ûñ?A¾é ³ñÒ›J’Â2M.«a?Ï/É÷¢x{ôŽô¶b~‰ÿºK`âžjz€Áâ#à–ÎG¬‘B¨ƒÛŸ'AÈqf¹Än&yt«aâþb€€\ÑI+hŇ4ò–üf TÒ¼¡¢³ÎX[!˜¿~éÁ]QsAAl7ÌÍL9¶AšT£\t`(‰´]!Óu>Kn=r¥ÅhØ~0¦§c ß')¾æŠ*μT[5ï?Á1߹ֱ܌§óÁyhO“ç‘à“°gDÂÈG’Õ)@бS…p‹â#6è%Tß5X’ÏÌÕöÅÑ\høu~Ž7d£ÚCۿӀפôÌ ®IŒXŸ ’¹Q÷¾q|á.ÔWFćœÂ(Z§áý!Ž<Ò@w~ ÇJN»’‚õ,©Gln§ôI±Ê¥\nDDn*`¦\ÖÓ‡e AEÅ1¦ßf!EÛI‰Tƒ†Ôoùˆœõc=ê‡J1°´ÆàPòL Ö˜¥_Ù_ÇÚ÷Óá"§úÕü™‡îzZ‘ŠÝÆm$Wm1ï¹ $8ÂV’€€Ï9äò‹:‰ÕèÝ¢«gãž\˜ßÙFØ9¿‚£úThP‡¡å„w,_úßË÷lØ0ÉOÕíc»Û¦,Ù…e1lRì m4Þø3V~l¿Ìæÿ7ðYä÷½Ž§h}Gbjã-âVjÛ(^f´)mVS·h2㜽îXle„ûj{ªk‡PM8¥RýƒK \'vµªÿÕ¼ò.D$ºŒçÓÃ*Ì2´0ˆ‰*7®g¨‚òðÏþDJPÎg‡Ãïâ†ÜxĉÿÞ4sž¸–Ÿ²ûð’M°‘šd`[¯^!õĨÑRtÂK‘Å#ô§µ(Áž¨z`-–µ­ e;l¡öêVKÒ3°ß ˜ùY)WŸÈ¯;â34Ri§ŠkrCdŠ¦Ê„ï5o¬Íì¿ßAÌ(ËŸ8â×DÜ8ìóš}7Í38ˆŽÏÕ_Öñå&Tzúð½«u²ÎZå—i)³Œi6LÅã­-‘ÜoÅO#êðӬ󡉔F= 'Ó/ 2S‚œLëZäPÓ„Î#§y11dÂ3° Óžv)çˆ;Tö¢…r³ 3íâlجJdöd4Ô(ò×Y@Êi2Ïú1sÒ«ž ^+ÚÚ•]/mà[Ìh§4Æ,¹—d‰ž¼ðy{˜z½SÎG-+°E“kú»Û6XsуgËÕæ‚ˆdóÅÀiZïJ>‰#åJàé†PëM.ØUnq ‡‰sˆÕÁè;áíæ&û(f+Ð⢚²mJ¤wÂÈDÑRO12Ë÷ÂŽH&hÔ)z?­åkTþWm•´{a^îü2ãN|u´L 9…B;ø)Â×rDÏpjy§›OÙèë0Iæ$9Î…‰'£Ñ(šÏzÈÈÈ9¿¡ý¡´Me§=öÊæÛ5½ÿ«è¸’ÙT‹ÜÔa_ "?!ªõ%~hfê2õ±Õ6 ¢ùúW÷ÜRHÛe±ñ//ÊTZÀ ×ÀÒIžª¨ ·¯‹×€ytÇ·%ºÆÝ‘”„¥è­Õžø„Q V%z‰e öòµ3œuën‡vÉþïŒgºTas’áÙcÕyeÕùEœs¬ kÈrf‹Õ>1œj¤Ý5#©˜ÖKàè"ºªnðÜ ®³ #»ßÓÔšÛn÷uk8µèÔd‹u†eÆ8d‡@33ø¢þmûóÛn“O#(шA~T7×0QoC’€€­ }ûäJ=â»%CëÝTŸ÷MTdüK}j°|Ó›¹ÃÜV73k£szf£e†t±_7/£lÿˆ[F¡è¬ç*iC„ô#;3ÕÔ‘M¤Vœƒ{;×T…çu`Oß´ŽÖ|'ã׺õ×{Z¾ÑEâ7[”ЧĻMó^“²îÆ¿þ¬ÜƶÐ1Ãå&[#«‹R¶K'HsIŽå_vpE.~œaP;9gb¯]=h~G‚/ 8±ï]6ªÿ&Š$ŠÎl‚ †{°ê/b&D¹zo»‰dÙ}gTÅû+cÍWÉz‘°´–Èk<Á%‚½o ~gñð:Œ-'v×sO¼Áó{k˜ÿê×’¨× ÛŠˆ]ÿc«õ‹;~S'ú© ©€AЀ_[_ÕOî Ëh)çár£¾+¦ùOõêóp‚)c}ÔbŸRL¿3 k±¯¹áö]QáºÝ† ï,‘ë}³Wïヤ2ì/°‹G´ûþ;çÌš5iñO³,ÎÔý¾²L¯±¦†²ÎX$¥ÆëòÖ´-(ÖÄw„¨û„öQ¶šÉ‹~®LŒæÅµ$jýÕ­|cÈ F!òÿOIã‚™•Ö×K@îxùú4¡&·w„†^Z³’‚È·z©`˜ôÈH0·¶-;8¢ý¢zÔ|æÀeâxÍðÐú¤¯þ¤–r,m‡ºz-M#aÙJ¨åf˜0µK«ÈWÕ÷E^?¤=:ÁwÝ…ì¥BŸ $U;=g±Dþ§þTª`ºUE«·`‹K§Ô‘ã¤x7”aÍÁ&~“M׿=”(šë¶x1QÙ©1ÈÔŽ%|îkÆAïWÔ*uoë íº2)ž…·Èf¶•šÌ·A¹ö¹òh×ïRF ”#3yÒ6ݸ‚Ŕ݌8»^1‚e¥ÑCj„zh+)V Âˆ|Ÿ×)-MÙC®‡¡y(uOàÙîcûñå£-Q g?T#|ˆ½ ¥ˆ­Â¿FI±`«aH=SÚÌgÛáZàcïØçÖ†d\îšy?9óN¸câ${Ì…“ÚO©©Íü 4€Jœ—Áý?œ S«kYI:ëx{FMM ø¹üÏ“Øws’€€Â*9ôke[¾«!ûÚÈAÇȇöÔ]ЄiråÈóÖætBÓŽ eÉ~‘å‡Ôd‘ˆiT1R-P¾ïdA®¼\MÝúº# “*Qã`Ñ2õ܃ò/T{ŠL‘(ŠC ¨Šï-}øõ[w#2 °ƒ‡®Ô±z¤£ä–±ÊÛ8†]õ–ÞÞFd¶%!ä@éÔÉåá°®ÞPõPõQ'iy;½Å¢«¼¹—`ä\ <5 €™±~P´†±Æ‘Õ¦cf ž#ªãìò¼œËSÌØ0¡ñÜJ„ $ù4¨¡AÈá÷sà•í@¬Z AÏž*Q5ä¡ìÄ%¯ë^öNCgÇM›Te¬„ÔÔaàŸ=TO'Åþk~Ê6v|G…6ÆæâQ &­uz1%Ã…áÑÙa’YH€X»žiÃAßeÁŠS4óºÑÿ¾„ÕwHPJª¬ØõŪQO,I¡Åh®s‰½Në&ÅÄã‘/#?ó-Q¦ÛŸô}XN©]h ÚÑÄ¡9ô“ƒ¦j;FŽ‹Ôljî÷q³L_ÙïÔ³ÿn¡õEQÄò1ç˜`™½+žfk­þªN§wÀY®p Ôªü{*ÿR\>Ù˜t¡‹9r`‰]Wjï}  ò@§¨F¬23Ð}`ä´;ìKA !ûzñ‡ö o#BYeu¢YŽhQf¯v'µCr•o¤ÚU(Kvò3í`1ášÎÛˆÄØÕO2´bŽ£:䨮Yã\ÉSÞÌ—6ýÝf:O@Œðs&½L}ãÕ4ÑþÒªÖù“,^_ÐûÖô/‘æÍ ˜ý;·ÒÈåĦ¨æIf B¢§/Z(èÉD]Y »€Ènlh-öñþ7»5Øña¦3ë;ÑŸO<•Òå®pßVW!åÙkÀÙþÓ"/írjr8Øhë³g¸]ìQå•‘ˆ(¹£AcùÁ4"K-|”.OtÃæ$î÷ew:®ŸÔpFtŒã³HÈ“5o@vlί-öK0pP_ñ˜ô¢ s( òØ×ø 8p¸PLü™rSÀ[É‹DC`[ôSY¬Ùî&ÓÖ|Pð!ØoóU|–1£"ª.á2¾D;ÌÓ‘ììã >Ô‘Ÿ)„ Lçø€u4’€€Øê"U¼û<QÏÍ= e}þÐ+hˆêÄ’Ñáä¡Z’u Nb_°8gx,ÜÃ9纶]ámÿË*^)!¯9>Y‡Ž—!Ûù´Ë,Œx'h;éŸR”þ4‹¾V÷%AÚ)Þij/Sí‰nª€É^Rw‘i¹O*«:jJ:Õ9â°î“/ùBbÈ·y2‡ÞB@G”Ôl~óh b¡+‡ÉÆüdim²dÓÙ…ž*[˜¨|’º‘¤‡¡!ÕÆªóŸŒJk)ÙúhO 'gCkü£’g~…·ñMîœ@S¥ùü6L#uR& İý¯ =Û/eÔ$cL…ÎiQêž± iŸv=±û–ÍÖ[.:ãnv=¨»‘†# Í~ r°x üsŽ¿S½Ž=Ê ~µ©¸¶ŠW£1Dm™$üºß,ÍÆD~âlÑo‘ ½ÌŒº§Uúc׋KcDIÐ4$ÅÓï lr:Xÿñ`1å“Ôé'XMÏ[ã©@± ‡«²3ÅSå]ŠœÅßÔ[ÇÅÒÑ…NéÛ`W‘ çëÜ`' ~„R`Ëžt 5˜m…ë’©Ò=a¬8_¨½kŽMhe&`Äg*s„ÿÌe0é³.º°ÒmÒ©Ÿ1&HÙçáATÙ^XR:vi àÄ’vät)´[) Sâö1†EY "—ε÷d}!ÎÀ}[Vâô‚(CgdÊÏg>Ç·ÞL¢Ž¾$"îuÄ:½ñiUAêÓ1ßÌé’€€³ f‰ÿK 5 ‚¨¿ne~$ûÊ?‰k† ¶r¨ý lµÅ›×½¡…ìsµýú çq÷÷íDøÈ mÑâ³›l@© 7»Ëé¥ÿƒÃ0¨Mðüi ø²8ãjVžXµúäzP¯°¨èojÕBháÀ¦Ò5ÏC šq–œ”výÁyê%ÃVDƒtҙČD-{TOq¤VN–à è]@ñøõìûp€K…FoëÜPù&›õ6]er¿uµ{uÅ“ŽBÆŒÄðЛÐT49&e…/«ÔÏŸÏY­7írÒ ->w}ïx¾ø^ðµ†÷T—ã¸Ùܯ‡ø.!¸N•&!Ý„äí]†ÔZ ý‹ü¬JjoEˆ+ëC²f_QÁ`Zè]’ƒù’7ŠáH³'mBÒRã20ë9)´6»'Sc ˆ+ÎFô%T¡ë1»„}zŒ"Ïeòì“3ãX ˜{º†Y¦sœ@ð ÛãK‰° oZsÐyÚ¬ÁÜÿ(2ƒ6àà CÝô }iE£¿Îîe!±¶ˆ;/8˜`ûÏéÓWµk9/X…¦"¸Tù> ÷œg––_(Æ µ´k u? r>Ùl0Öªt¯i]{7:Ù¡x>Ò@¬p€ýfhuí^.%V<(UÁP]¢ð[0­eXÙ§—ìÌ8\N*¦Fœ£áD:dtVinr¤,bç ‘o%‹D°OhÍqu®¾à Õ¸É2R,™¶q4ÞêQ¾p g›?Ç_fIÞ@[šËæ{AN±‡ô¯±Ck&åq_¬Ÿ9CÆ©…SþÙ+.¹Î{s4+sCøŒý³œV ªtìEÊ[ûêBƒQæã²æžF“Ë Å{„ÕóÆð OÑÍj-74’©ºmœg¡WʲIáù;#yWo•¶QÔ¥’$ »eŽ%)®D­Ñnš¡p¾oai`ÓG*¢b)“üG(ྨcà“ëX¦St{?žÔî Ô›ôVBÆ>bÈúÇõˆ‘É`f‚d¨JKÏÊj-‚µð¢«>¥Á­_jÓfW3èô…ó÷Ƥõx¬rdy>é.ü©¬4AlÚQ¾ô£b`Ýê×2[Eºdùk€â–Á]ªY¿»ñjèý6¦ì`~ûfÐ)þ§À‡óëÉ&ꋊ+ÏSŒíòüÁÂþq­ Њ”´çq § ’€€Ð?®/ƒJP^Ô.Z«:0 œFé׺h.°sžÌuøìWü5R\;]šå‚au¤ð݆9‚7ëh2®SàP‡ß±û¹B‹,7ÊQËITŸÍN{ýgú`B¶ã'~«pgy›J”Œ¡McE€hXìgŒ é›a‡ö‘–" äÁeج5]:ìü€ç–‹5KÉÑé;G׎jŒÓó” Š[+^xº8 5§ÎC̸Ø7þÁµ?~Œˆöl#öRo+×"Uâ{|c8|…¯O-:jýøuð?Ä4f숉ʱ€¨Œ Á•‹2dLÔÇ$”•'Mä2­=[FŸubÂïâpÕ`£Iô1²—‡Œ°Öã²ôaö¦¬œn-áúö/Ú̈“And§YÌó}°¿S=Ãȧ<Ê_Y ,ûcÓ8ñßÓ°dۯ禑 Ù儯 `qÙMx˜;{E¤z„Ypöl/w´ðBÐ*Coá] ÝÄT®£)ZÚõoª[ê×Ú– ‚o<Ù=º¢oÅø>g±µ³±eI諾–q±zîq˜t¿ùë/¢'‹mní¸<çöÄŒl±†1]P* bdKäqÝY{/¶ܶÐJ.¼Õ€7¯vq.(å…ï,ùñ;Ì»”ßÕfßÖW:ªçT¿á,U$¡÷“)¸¼ ûqGX(«µâl‚0 ÿ$Ž ¢û…Õfnxx€ÊéÓ´›âFãa˜4‚£©š@ 2ïÊ=iÛÚôFÁ6xÏ{˜Te‹Óš÷”y§Óùû®Ù{WD’›¯ Tm³7U¾HÝ™ƒ_|ßá¦c¿ØçfC “ŠVDlÖÝÿ×3X: €u-rcO“á€\Eò9Ø2èÇnЯ høRáðÙƒ˜t URûŒ¦pûì"Bû'e"©bøÍ@¾ÂYÂ@#8"^æ+8æ¬N»ÊneÍ‘P¼ˆ‘¼³_ú¼ÍlTÜßÿçê£]Mk£å±ÌMº‡ ¾ÚÛ™'‰àØ)Ýû{fÀC5T£Ó®ü?£NA>£'hæ²%äŽo]ÍO}:4lw ö…ífç©7æ£Zàã©èð*¢y•0™ä®:c2¶÷‰ 9APÃrý7×^Øð¦,ã{î„Ô"ËÚ¨‘gc´˜Þ@|1es6–GÂuÔ<5|< ’€€Æ¥<ÿs–b‚=‹ûHo†)Í "qM\ÔšàÕÑiI´<ŒÊÂ#ý2ïrѹ c׋:Ì2’Ò¿„™–¦øéЇ‚ t ¦²êw¹ëß`ئ¿_+Qr©„OÓ(K4ó(þw].óÉLo¹rOÏ×1g¶‚µÑœx#ÇØ„ ­C® ¡Ú¹À¢ãcÛdKÐM•ùÁ¥FäWI˾Mí,ŠYŸýÌW–W…Ö+-%/˜êñ0Ýâq†ÐïäÑ¡)^S°º%,ò±+0§ËÈñc®­ì&†ømd´êv¹ë úµçZ¦÷gÐvaZ[ÉÜO¢‚§ë÷ü&*s$²¯ÃÀ1úï9»Gp¨‡™ÊQ¶ˆž,ùA*„PõŒb¨EØ — ­cãvÖXÿƒoËÈŒÙGµ‹´¾²=°ùOOÛ^åC1Oûá *6ßx“ž;h‡»¬8Ö§õ‰œ.—ŸB Ÿ-²o­f%*‹™óôx“#7 *ßoãw)ñÉ*!³…$ýúÜÁéuçãðó ]wúµäEbö°î#s‰ž©þ AlIâùú¿{‡)¸(°|±ë’'£úÚIqq·Ñ¯'Ã+oºTDæ€$AY¡‰ˆ‡Â ·GÙµCûD‹Oeß°ÕÆVªÜIùM2³z)ƒuÝR­*PÄAé¡f’¿JE\ ¬lC©ˆ) `Šq]Ë[îÔ+‡ÁS˜E„¾èÒ¸²eÂû™æ‚Ÿ…üòMÏgY1ž÷ѦÇ&¡úa«Ê±ï¢<@°ö÷^U{^Å!é_h0·VÝ&À§=# c—éAº¶ï'VÉåk>¹#ð—7d³nqôÙªNÀ™ª(»„ýA8ô?Å,’ÅgË'faUЉŠ()žœ|Ü¿¶2x¿UçÀÆLõ|Äëõ©± †:ɘåe¥p¥4ªKGçvÞÃ;F®‹e„Fïøm“Ä.íMªÐÓÔáõÀ±.Ë\} ÃVCóVØr½ô?&*ܡër)Ÿù¡šV±r*tôxγïF ‚äDE®vx²J‰&= ¥jŠcõkÕ_¢kJÁ¯~öH®†˜¦7€A°{Õ86-ØÓ81ûïß‘V^M62í+Nj˜þù©Ž›Ãm{!Â{ÔWÛ:‡¬÷ÊÆ:¾«ÕFâzMÂÔY×3ø’€€Ì€gÊš.†?~ç£úN\%q,Æi/­ÍFÕLþð$[D¡½/æ'N>^Ê¡]hY¦µXL‡»/mÖ,?ÈrØ2in$ë¢ òOVÉ_dãŒ%¦jWùñ×)|`Õê±™=iÿ’÷(‹_Ó=¿W… %ÔDn‹0¤%ýTyßZ]l- %íå ¯°cŠ×þ<ÇPn4 ½Eª5óšžÜ³º~Á2&u—V$ ÷0ôÍ’0 8KáQuçÓWžá®ÿX¤Êà*u”^¬§ Ý@±-ˆuù+W#¯¦ÇU*mƒëÔ‘xÁD©ÅüZÿ5«º¦™7 º.ß=Ìg¶ˆ' åTÙqˆjq4  E{ÒGèLÛJTýŽ1Á€4$pmÐøÞÌ7:EKÎek‡ÔñGÞ,§¿¿*èJöýPL¤…5Õ‘ó,/rǾZÍû˜ó#/vÎøQg6ŸükŸÙà’Ø‚èÁE£"ꔎ´=ÜÐ`|Ú¯4ê?ª¯°>ãu°ZZs·!¸Bw`5Q„‰¡P! —ÖØV|ç¥@°ƒN’D}Þ ô 3Öw€g\ëˆÅ@M9ñ‰As æÅc´=b óLö’£IÂßöª/’)wnSð@¯ôÕÍ×Ì}·½%í×*ÍÕá™™øt-­c¾…å6Þ‡pOÌ"öéì Ây k}@Ø9©æ%È%ìÿÇT˜%èw@[ééšö¿àÙ¯%þÚšõë«qQÛp'eåG0]œÂùRcÿ½×…ƒU!5±ÛV:Rüì…ø~‰Tµ"”xýé þ?å~¹î±¾># ;*õH¶·.S±=ï©“â9óW?4·©ý™®Î‰í¿k‹Û%Ðʼn]n´€9 $Cú0QÊIb,Í‚ýßfAüú* í¾ì–\å>0b˜ë`S­Áðª8%׿ï!‚'è}X‹Úäþ#B/Y(_¿drq(Ôö d_UNÓ\O®åÝ£ð¤0x/¡ж'Ü‚{‰+õ9Z2_à$B0ó#ƒŸtRÃ{}Prªdë’c~‹—+oÀ"EÎtk†& ˆ Îð›ŠÉöÿá)zÎß: Wñîö’€€ÉvÞ©XÿÇa¦KüÓ]‡l) !þ(ñôd÷û£ŠyŒP‡s¿0›-‘ǬóGCΗ4®äýR+±»¹=Dqó5€©'¶µG¢à3pºµ¢<‘ äØOpsr£`i|”à8X§ õ¥E¡ÌRþŒB¾óÃ7Òl'¦å‚åNzmK§ ƒ «ýWv£p u—:³K Ý€T‡„#ê"kÞ€¦”_Jk˜X?_ïTæ¶— 1³MnÒsuÁÜý¼-´&úd$¨‘ý=1"˜ß;kŸ=ÈÂx•ÛË©½ÎÝ´ÄpÃýe רDÎúæZØs¨_$’J6Œ!ƒ˜/mIBL8÷€ÊüÙÃŒNMŸ‘Ä¢ìË`ˆ¼Ò>TØ…_”†ŸòÌó¡«Æ›n¿YÕ&Ùºâ8rÉuëÖîÇ«EQÁlP KQÿw$âdÿÈ‘ [RwlÅß57Ð WmqUßb”ãµ$mõ”AÜát§#W};1>ÃxCb›)ö$SÍ(m‘ƒ¶1Ðï¼é½¤2^„®bé²ðK’‘áý.­»‹ä{êo´Ùûß[šåÁEN{?zÓ‰…i¾—C2‡ç"T •42“ r³ýr¦· q•s^×B]tå'Ù}3M8§¯¥Áîb•HLH·€øóŸ‚áÛ,ùV‰¯ò%×—ãîæ+D†—>¾ê[àmŽײpuÝ’4œÍ©€;G:­®.éÞ¹q7 <¹Sa²b-ïš«ð‚ò«d÷u÷b]Ú HªþØq¡VÅq™È"€õ’€€Ê¢-rûµ›äÙɇÈÖ`†'•ÇWô‘¢Ôý(qjÇý8¿¡:†_³¥Ó‡/—+õ’NÇË ³(ü%&š6–¿[×…i×z’ªÃKá”ÒLÄA± O|’« ™=DKsÂzzVç Bnr¬™³JíPdépKIÐú&c;QÑ'7ö¥ˆ<É}NXZê³1Ä~™àU«uqº]”ÔC 1ub@¥È†‹ÞJÈ5bˆ‰ºÞP_[¶sF¦Ñ#;³3ºÊ9œÖ®ÍGH=@eC‹Œ´2·Î>4Ì©DwÖ^^(‘æõè\obÿ§ÿA 6)à´µØ:8úäÔ¼ÊlSÕoˆÛ1A\5ñ4f¹œç,ŒnòÊ…x!J¿¨„á>}|JÚß]ëLËOIu­÷äWãzf¥;÷µ\qº¼øùLòOõѶÏcŽk+Ôù'|[·jäU²#eôª'•)ì’d¿Û¾ËÓæ?5©ú×ãObèXÒ²…¬ŠÇêž²]Ø §q2ó"Si.Š:˜*Ò_ê®r¿Ö-4A68§Û•Ûâ£è³p’”ß¶Aïfq__’pIL1D*¿1¬BûÄÓm_3)ô¹vw‡^qþÛŸŒ{þí–´:ªP”P¾©KxË„¯ÎÌ“x­Ç²æÇ-=m ÇŠ?Qf„°Ê=OÌÉÑΕ3Ýj«¡1â›Áÿµ¬ÆN §Â[G©Âm³%¶Á\TÜE’ïÇœm¬<]ÓDOuÀtNêh² 2GmxgùÚùÜNb’lY¡ß–€À|Ë·Ò¿-q7Ù%*2B)MfûT¡xÏS@>"õ%éA*xÔâ lƒÅ1œ@åGó—~ßóå8¹w±ôs¨ò÷zãÃ^qW7¸"(xôia!~`èT*°œ Òç'º@5¼«`¡ ×ÖÀPPÙÞªXP´7R]Ñ6Ld^J=¹=½ôÕ¥ÅzÝ’€€ÔhýŒYñ_6D;›BÍ> [auÖ…åݧ¢É ‡‘RÝÂ]q;Áí,W›Cá«–Lb€/Ðßš7˜²Ý®o «DI¼ÛE¿Ï²õÜ›ŒÕÐz¾ÔJ‘„ò9. Œ ¥A•=ÎþXñcWBk8üeò]Ñÿeg‚IU¤ó×sRò‘¨›Xÿy?‰ê‰&ò )Žy֎߉$avDTik¿4O,^x5àš1¥±÷¼<^~¾^ò V$à ê̶?ª7»)åýË.ÚŽç)‡Iúd]cÍ-(G=굊D~Jª©"A‘°GØ{ýÛjýÍEW7ñs….טîU²dµ–•nhÖº¥—'äüd‘;k’.E¯„Dÿ/Á¼o€%Ù>+Ÿ—®žïï¨ÒÁ`ê÷½îÞÞÑ©­¡Mµ«¼o©£­j¬ÔË»êq—M·¾±¥ˆg/¾$Rš_‹ v®cÐtà˜¢ Œ)´²MÕFŸ®Ð‘Y6’H]„ÀPöÄ|H?ÊçV}'\q¢Þ3àQLMðÍö¸BÓÒáŒkÆ/þ²æˆÉ9ÃwÜÆÄ,¸kâ?Ñ®¾QÛ Å]'êéZ2U@mkõ ìœÔ*÷¯£*‡COÚ$N?¾´i¾UÂGê'¨­Ns8Ç–I‘ä&&æani»íÇô’ò¬$‹RÓÏÖ$¹»3΂_c9@?·%Ç1Xæ™/\ŽYÝ $DöÅí¨ÑÃæNÄço¹ &ù<ô¼Ñ|Ì<‚µÁç¡%bì*ºZ‚údúsÊä¾Gkkíøæ°r“ŠáÀߤeZÌí¥Ì33Ë=nûr—éžCNëµGä¯cèc,^Œa†IÈË3JB¯è'«ž2-“›KŸ’¸ï~*þºÿM{JÒi`[‡$Üœ·qåæF96šhGëÔ³¯C¶O»dî¯Lùò•yžäÑzV’ïîVÉh*]»›録o÷.óÛ.ñsŽä n­sö_6øgQßÂú#ø•èz]ïŸöœÇ„E&޲Z„ŒwÚ˜ÇtüØðW®Q˜·¤÷m+ÎÔ÷€…å>-ÇøJª,'Í#ÜSÒ1Ò[ˆFB»@.!SHÖ$ m«Ú°ò4n1 IHkÍ#„ö“˜ØÁ/o3;›Ø‹Ç{c’€€º¿½íXÕˈ¡¶Ø[4Â;]CÝìd,TX0©Œ’"oÝu¨&]@ä&ß,šl9Cc€ËÝãõØ=è¬a D»Yœwšd~5¬‹5ÀîÞí™u#4Qɸ2%P?üe0ñÊZ¨ ²=ÝÚã·‰Záÿà‘}Wézo$<â`z@é¥gŒº‘É¢Æ]>ÖÝ*s_ï¿ Sg:<&­ßü©|’IÓâ áiˆ¡ ¸è~§žƒ ý¦¤}±Æq Â5„‚,ѸÚ+ÉŽž…e6$¬'æèó#.Ð8n@ê Œ?˜Þ;;¥þÞŒ#àšjž/o¹˜AºC¯-qPKxïèÔsZ3rë>Ó µ4Tè:-ã÷åc³•0R"¸ŽÅú­ ­èŠqÕIo~éM¬ýàM»®˜j@ YÐíNÇë{ÒïÆòeΫ¬cNƇ í¬h§s¯îƒ*uçïð@ˆÔ˜U+OúŠ0‰ Ù•7c8 Ðñt½Uü ×ÜÕéÿ¼­õT"÷ö[“O¶î 6‚möç —³sò-—µ>î¼’ï™T‚ÖiÄbá0¶ ³\¤wÜü.Çâj«Î:ž˜Ç »˜ ^Lú¶–³Ò¿-»oÁ“,.´è–Äûæà1MLõ 0{w›Ìø’‚Þcl4W"¡›=ö,AÁ5ÝóË ¶ó§¦µ­}‰¬X5至wÉ^¥Ht’›ããÞŽ‰/gVvþÉ’,5›Š(ÁГŔ5UõPIÞÑKÐ'à‚÷ÚHik VŸ1(ÛáõaNc^À¥ðË-Ž*³U¢„ÑöðMlõQ y‘ÑwéÆåÖ>U›Â45%Ý?¦ŸÜ½A'¹g4@À ÝYé³¥»D“ÜÕÞ1áƒpa#[SŒëáµ=Ñl*×>ñ÷„Ÿú›hŒ9w÷xñWïìß]EOO¶ÌðzMÂÔè3¾ñ˜ÎSA­ÆÄ#j)²k >ï5à:(§álÐ!\кQþ– ­èàÓÐ<Ðý>¦Ë”ËE¬$wY(—/]úÐèF臈ßù9ˆI·úV1‚”0õ† €ÐÕ4”¿Åxë*6#¨D¡~†ÃD:v¾Ü·;­à;C`WÈ–™Õ«¸IÊks©D¸sÃÞ¬gfšŸýŸR³×&d Ú¤„Û¾WLößi´’€€Á5”}›¨dž%@öħ}[@3'wû1X]h‹¸baÎ.|Þ8ÞJ+£ZÂÆÑ–-‡j׋2EAm(ζ%ÆEºmQ÷•BR)‘z2l3ìš $ îàÈÆèÔ–0oïuºryÄqggrIXfTéu •w û[T¡ DdîÀ?Øx/õc^vì˜_èñϵMN¤„#ÈæºW¦žº²ûµ“'°ÉË]þd¬ÀÝ ÆxXqÜ^†³Í¿;a»Žo/¼ª‰Åzó뻤-†,um?^¬.¹@1Ò|˜V.R&à¨5ôä’øš ÂŽ¡R8­+qðí4@³Jª°sÉAiɆmÕë:¢l¸ÞÌ!¾7Ö7¶'1­&ÚAÞÉr}Û–õäÊë22S>–ŒáŸ#¤‚¢é{M²ÛM/û¯/19ÐfLá+½¸@‘û}7J%}[U¼\R±`îÖpÁÃõ;r\‚Üvž={ã9o ¤ ̓ܪ)Óp;ÉõòþÃ0û7MÓ•¦ è+³í—Ê 3ƒ^P"z–ÔÒ±ëÌ|Ø£õ ÞuÐüZçIåõf—~ËL“@Ñt¸3@™%îùI *<ÏüE|ö7Ôgß'´,)”í-óTáã´»Íx…í9¡|†#g{ªKÔ‰•æýÌ×åÂ$eæ"Á &âÝá+”" ’¢ÆfO€õ†hržoaoA5'ñle8Ÿ¤M Áä¬ba•¬pĵ&åws2V«†¨+ÝJ„ùñÕ>QËÒ•Á0¢ÖLßm`´Ù•Aÿ«Îa'p„Ê2~ªÆ À\©îÙ3¢Z8-ªE»ãChOþ^9ê«×FÉ}‚…›¿"-- ¼/ìÊÄ r4EF7JŽSÂCTîBÓhù³Š»ÒBišÔ.u寠ùÙFE¤°À´ñùÖãÒÇ S¹uÕ€q²S¾woÌ«¸6ŒÛš ¼;N|é—÷‘dÁÙ/(‹—̃n§–‘[cEuRóƒTo8Ð3`V©£ò'ÕLûöí–Žšt¯ð9d=YÀÀFM¦úÖµô³£îy£yjŒNŽ÷÷´  vømlSÅ®@5Ç3µLœ4ø*’·ÚáGbÆ@y‘­ÿrê¢ê¡ÉÈŒ^_˳ÁÎç‹ÿÍ!×…æ¢4´™ %,ÈÓYwùKî,"0ê‚Q ?ÔFíö';÷©- —9MÍ›ƒ¡Ôª“½ñm#“kÅ !I™^Ì +ÉtÁLKä¦1¦Þ8R$žY¿”_žCûê†uÔ¨:è¿X& ÿ7ÅRGåÔ{SüF™ûAU>Â/oégP¤ò„U‘ƒô;‘)ÔŽ¬‹Öe’¦O*þÇ®wýƒ2 tÿh‘ Ìùß(£g|xÐ~èÃÈøË.\”ûx–á¨]§¼äÖ†šnFÖévšÑå 7Ø,äd@è›ë-ÔÒ3ÉoÙÇþ3ˆ;*Þ*×%½Ìú°jÇÄì–oðŽû9Êî&)(¯Pú ŽéÒU¡ú磉^ãÕ#S¸¶×ÙÃЇ‹&ž`ù¨í—.·'ó+OÛ!†¯—u<ùTe_ºÆnõk#ËsÅ계:"È ù9G‹Ïã¡z†R•ÏÄôC@È0^%`TDˆr‹¸m «Kv ªº‹‹,À¤  þ–呺x6Ûf¸µÔ>AÉ™ ÀPíWmšçoŽ)ùª¨e™n6¬ì5àÕȆ©íîÉ%4®Âå¯AˆOŒÝšÁ&ùs?³~é{Aü¸lfL_ $!AU^â¯YKÝUP®HŽ1‘]J­¹çZ€Ž)AŠ8â†No+6ÖáÚ %x9Šƒêóƒ‰ý¸çï)™™ãqMtyÊÆ+Ÿ¦ïY eT/ï ƒ`ñYƒÓÈ ²­*ZÕ2læ³n4YË#´e¯ƒ't¢s,TÊúPŒÕ);Ú¿oµn’€€Ò0þ›Â˜X2N?!Cà`ïCYs ÉYã_;†¤Ý6)Y±tËÄç:Ás¿±î°$Æq±’¸ q¡î–qã;!ax µÐ­ô¥á¹}”©Â>•‘œ«9 Ÿ!ÑΓ39ƒ‚½ÃY ¤ìOˆSçd:öt'´1Và³¶….…Šë~;Šò€Ù¸“w¶âµm!$ÉëJâŽÊÌöÅ¢¤±˜·áKdoȦ»ÁW hPLrD \cóA®±섳ӧ<švC¯ÍAÄÐÚ².Qà¦ðùC¾'2I×Ö,DèÑÕV!'ž½Ùn¯˜‘JߌTŠw›Í#}X^Žú*‰Íä†8çôÄî<ËðŠ _˜xä”FYÙô²hÞ²q§PŠoyp PM oÍh{ñÓî*`JŽ\:_e5­l`Zr-© þ3|Rè[+äµâÖ„Þ¶ª;›|{ÄWoÆÝ»ß¡fŒx©|k¦¢˜äœµ1S[“5(â7Ùî|'.8¹”ö,ŨšD`œ¡G\èåI9q`E[Åb½'·ûÀ„]U@'qR‹¤Êc»«–øáåhîõ¹u"Vµ@t‡ì~}(T-:3jý­õek¶6Xgœê¸Ãê§;0‘F½„&’€€¼2ŸEc–"A¤4/ øº+RÞ²«ót¼`²”à¯Ó¤ÛÅ;ÚzÔÍ®O©å§Kê;yu¤¤aEUÝ—¿‚Lp&ãDK3P)BA¼gþx£XfE€T2 u%þ"4Ï\È¡âú‹Pô®!Åñ}ó®0nÜd²i\ME…#Àì Öç} ËbWЖ°qÂeì½´Ó­é{ʳQLm*¶@êëÑ]ÜÆ80ñ#Ô‡†rÛ~>ÜR]qXÈó J[”=®¬~•¬k_uµøyó’qÀ‘»“IÌc¸—éþiŒÂ\,Zç}׃,Ù’6ZÃŒ ±¦ɰÝuE‘Ú@uAt­(Æ–Þš”¸]¶ ™´ž¨ápwjÚdüCF槉\aï$p‡Ëã¬OdÔ@ë¦r‹/­ÂO 2lény‘.!tïÕn)E¯D†)'jÕ£uØØÀ]ü>޲µóž3kWFvö­K×ñlÈPï½QLUR1ânðqFO¶ë„û¤bgÚæ–T”jÞp5 WAš›i™Vß_-;,ï1ÏÕ.±\72LKŒ½4„´Ê/|gIÄÕBU-ä“CtÕ¯RÓ Š—wä÷KäS¤ÑÑgÞ0+‹WÀÀj®IádP¡©' ”Ùò¤¾šƒÏè@r ¦À€ö…‰†Wh•çæZÆO‚<,ÈkÁǘ£ ¨]²`dñòŒ‹ÔëzãÎã]­ Övá¶ËCæ®ÄØEžÖEip†ŽÔöe‹uŽ0Ú*…ùäÄÐÐ õ‚›mÌtPy X¿ BzP'°ÐC›ªF¥èW#—Þ¨ú³?r­ÿ_µ®»µt Ç»s€¶‰yyX§^À]â­áKM/0Êl••¢‚¢en»‹hÄ«ñ_pNn\ênpX.ïƒI–^%Ù&\OæûÉHËú•›·R±8RÉðŒ+c(ËÔ–€Í¬ò‘`/’€€Ÿ(;Bš÷gní0ô=J‘ô-ò!h(é"/†mÀZÈ9'Ì2¢ÁÉ·b¸«é~·-prf¶5\›WPÒóf’ç@7ÇÛ¬#Ýò“ú—p ßHIÑê ¸@ezw)Þ"LiZ)þýú¿ £î@Ð)uA½E¬2C®9§^ºþ„ÙÇZŒ¦~ÊNGæ?œ"A¬"e)E´¥©ò\3³ùÓø÷€ §Wúù§˜Ú^0´º3‰"˜îý;ày7 tŽn,U’ÃÏvÎ_(ì'•á‘GÚ$}2£d¦Ž6¢¼þÊ'ïIáXYû½`fê ]É›„Ùj4²ó{.—(‹ –åԺǾºï|LÎÁÂ*Lßì*Ò¨J²¢_І+3nÓä&dÆ<ï}s:ž@1ÔµfÍ K¡“f€µ[ŽÑ‚É»RÿUÎý cñ@âûåàSXV{Øß~àÛÐLèe.78ËiO$ll@ðçë„K“P•]gñJ²›ü’8.%U°ŸÉžLö#á««V>¼)Ó¸|)ZG¹ŒO ‘¥~‡6ÃÔOŒ,)|R+$ëì˜Ò~§ñ4Ç‹ÔÞa¶Û˜‹Aâ~‰¹[/Š^(BX•œÛ8CNN¹A1ÿ­N·ZdóÎSR!¿#Ä›‡+T¨>¸"Y’ÐñÓ2a yøŸýXÜö7ø?MMÀ9ë\Ý&‘ó_côCÝßjÁ\ÍÙÙ’çF\F:–—a î>&ÿ²‡P‘¶K ºBÎ¥mH”Àh8ÕóÿãLöà˜7"?T• áqçÅQÂ1æ7p7“> ‰Á§v×qª‹?h@&0\ƒ¼GÀý: ÕÖ¢žf!/ ´³ÞäèöS"ª…›ª³/£)«Z€0Ãé ÞUà׫ÏÒ ÆD¡²¥·ìYÔPr›­æ«R}ÉËRb ¥ŒÍ^¢ÐbD°ã©½4(Ôju[,¾ šbû\SÌfc~¸bgõ":†B-Yý.31¦š9˜å¹ûF“YQV‡ß“r#ªh‹ò˜"°rpKÉO®§}Pd-ÌjîïW!ð†”ë6üh4›\jóÄ€îâÉnˆ¾æßñ­×ã b¤Á‘‘ Òò/lÓt/ÌÌ“™pûä‚3;A³ÞBÕY+ŽÒ/,öA¿>xú—Oä’€€§‹6€[W‘¸paió½.bÑ4¶o¤ä î²ÍnwáÊyåÜO GY¯Âåå721ØN©†´*¦—Ù°¤Ê(Pa€3¸VëXº¿áJf-Æç••­Æç[ÈPªaÚŸ™}…öª‰túk‹I¾éLJþZ«R‚;?—ZñÜÊ»A ›ÛÏVJ*R©ƒ,Û÷Õì ü}nw*Q~C‹•áÂmõ±ÏµÙÆjz\ã`v÷ì•Õ{ £RÞm~d{î±%;9ß`ªCή`—‹ éê»å)V¤:ÌB{brò]Å̇ &¥·~ dнŸI§´,6$Ç-s‰“¢@óÎlz5Ø´š Hoí/t‹~ù¨ô1 Ž9PÒû… ¼ªýé$EŸsƒù½#âàeðô|Ú Y7—ÁÄŒØé|›y¨áï’*¾F|MçÆ»6hÈR¯yS°ÏÞ$ñ`ùÈ ŠôadJR³H.Š&ìEИ~Qº\"n‘™T˜A¸¼§×&^. tŒ-Û%_¾äÅMá`/“ã&wí¦.ªžc—1¹7É´ ˜·bý<+%ÇÍ«+’wI©v{qü×ÓÒóp¯x>-4ôU¦—¼®þ’€€ÒÆCìa¦éz*3Ôwk,’îä›B·©8‚nQŽþS¢¢~J½d_ÿ$ ƒƒ©çúžµg#®ÓÚÜC_þ{y€ Žºlár“Ù»'vu¿j—?€ob‡G%ÊäBt§˜ôÞ’[0ô4((þòHt!tÍbUÉÖyæp¬ K¢Õ ­v\Å9A¬•S¦Œ›µ«/¡Ž¸& ‡ø¹Ïe½žïž|–kÂÉ$¬ã›' ÚTs…ŠfJ‚±Ìš”ÏÅj›|ì—ÒÉç!qвÞð*¾‡j÷ãÈÛÍ’=/ž-ŒøOàËM‘…öm*† õ 4xÀ÷l §9Sfþíi9ÑÇáw@A6Š»G›h;µAQ]ª55'òÍ“áÿ ýLsT@ç=2‘/¹Ñ³òô_F³ôª,²µ?Á4Ž€OþX£YÊQ»Á[ TÊ¢”F`œBj8 Ùowdè7ﯿ‹ÂZe“¬ÈÈÆƒ²í(‚ ‡üsÇÊ+×”u/¡&tãG„ÃÔ[í¤­¦ÚMû’<ŒþþeÕÇ>,÷Âp¿h³—þD“L«+<–H×f½R/«Í‹Een©*ñÕ“—G‹âˆ¢ƒ€ù½‘ϲÀà ¦Ã'+gÃ=ö/0D†œg;?|ÈÝgÀJ†ÍË |»«Ë†ÀÇÏ#ÎÌ:'>.»ð>ÿü2ÔÇÄBd83«:“/¤áõè—Žá@à§\߆{Qì?£#EÎÕq:n6`•î=H‡c¥Å©k[B¤–oÿ'öÏ<1Q:ÿ£Bþÿãê§/rú ]ÞpmªØ*Þ|^¦z¯‘RHƒÁؼŸ,°W3g¸^Hw©îÍ9U2BïwbdqT…CÉÀbÚS«Fà êY n(*ZüJÑ{Š“Bk׆£:z!0QŽD–~`*í¡õs4øèBkõ"V³OÉáöyÒu PCÍ5±*g’yªòޱ驊ã]$Ý pƒ{wÕuâò¯Í†Ý% Ül'µ¾†5ü“¼E’€€ÇL(_Üà'ÁÝÎ~bKÌH– 9Õš€ud~®Mpe+럮D)KCül+ÖÚé%BëãÚfÛùò…4yaSnøÍF½áD­Foj"îkO«èOÓ/¡×X›´G@YØóïqúðÀo¸½iºr3¬ ‰» åUvÚé™Y"7)¥öÍC]×ÇR²@qŒò1¯~¤°‚©¸Ö²ønÇ—âãSöT9.Ärt?ÞÅIh7Z¢ÎDZ*ä$‚·¨­Â¦íç Þ=/°Q”g€øäÓ®* N±ïù±šžêühæ)GÊŠîç;Å&Ô4¨Š…02ëò.J>aRƒG·Òªß]]i¼s´Ù‡ ¹Ä‡rNhÕ$h[¾´i¯éôôSšÏMÅ 4 üRþMvhyª‰dr•ÔGñ¦jLÌ,u¸]‘™X®ï˜‡,ä¶×îtPâ%´"ïS`‰p›@UŒÓ±UÃMÇÜx_Å¿ráê’Spठ)}FàœÅÜ£SÜ@¼ A~"ƒsÎG KޝÑÒç÷æ€ÿxÃY¬¼F\MÜjòÛBjÊ493¯~ )u‰¶·¦ôµoY”“ÌÀmm_Ç þ£©¢®Ù\=a™Ç#΄¿«[&•³i¸Øa ù¹ÕП Ê©jÕwÏp¹í“=gó¦CÊ d qZÜlß"„ÄIöÔ6¢nÉ»/IÛ°xGì̼<>lÂû³ÒVíuùBÆË. ³ÛI†s•1+ƒ}êÂëhA¯ˆ«Ðc‚ËnÙÝ-¿'Áÿz€(€‹/}õ¥™¨à5·œot¼ éÃØ×ŽAh$AºÏyœá¾bôÚÉÖÁ)!›ô`k8p'â¼é=©ÑwÈÓ¹92Æ€v+ºçÄ÷ÿð¯H d"ê?)< P©$NTQnY Ba{…TÿIp'tý ¼ãN£šrü‘×,*ÂD{îü‚é™ÉðнN\úRš504)6&|o¸YF5ýl¼cûb˜Y¦oÒX§Ë„xÃQg,éyÅeTØ™‹›9@Àª“¶ôÚÂFe=éÓ–èiC4¹÷ þ„ròš2ZLá`@JÜ‹Ð2êdo¾)†wJ¦W½…cm‰„έQ.¡Ìò&'½U„wrÿ½Ì.Œ½zš‘H[wNV î›’€€Ò¨Ù!èª9µ)ž²"2ù*}±Šª|ƒ‚­ã¯Ä Û]®}rÖwB‘µÝûPš8ÊûÑÒõðŒÛ –•_ØçÃ"Ûݹݸ0Qs'øù Ý­)}×3Zè-"Ô£1VèÈx™fA9Ó¢éMöå±ñˆÛ.¸Ù1©½ ÙDhZ~§c·90Ýcǃ|PÏ{®ü·ŒuC©{9‹záíQ”/Uq˜ø2t¶rËO®rz”;7`JLçLûg å=ÆúŽñÓ’w®Ae÷×fåí©ƒÍ•Iv¢<Û-ÓpÏ GMpêÔ3Ú0îŸÌÖQæ…HÚGUÎóp«8_Òï/jÙ;gÉäÑ¿S·¶>¡êœ3m ,>F%¥õp%¬ß’!oüŽvždÏ{béY—F¶W#Cš1†Þêþ¡þ·ÿ%\ØàúÕfµ†*È*IÍA'D÷AùU¨D>}å¼Û¾{hÄ4ø¸eìÔL¶cYv ž!>ËR„4ÌÛº'ð`"¶Q±rhikÈ%ÇæâJ“/#»-Ó4Óìþà8`‰£yW»VÛ8Tè <4'tçP€ƒ{Lï'ª}\Dã4©Kf|FÊ}¶t-b¬‹Û3ô"ìO×:$—o1 #o䥕‘Zx’ªbviTÄジ¿(æiã\ò~‚~âaóhÒ»dmÅ•!LÍ[ÓoŠ´Ê›#šŒ Ôï;9Uî|óX2 ýú¶â GʽDêùB1±”úÝ.‡ Ò/iÚ+¦]²1õ™îˈú’n¥G'?GCÝ åî{cüaÆØð3–0ći[r‘‹="Fˆ`ýä[ltXÞ)ÜùÜâöƒöEmÔ¹û\cÆÆ>§&'d&´™§†Ö<ñÎaˆD6†\zF««$ Swj[N*åö@Èw_æàH[óÿsqcTŠF„@žªUu9¤(<À=uqµ‰´$ÈÌqYÈH'£]!\ʈGàã¾2ÔnˆTU€ôŽW™îik=Û¯lóÑJs ¸³6P¶¸LbŽd”üŒÐØÖ Y·>“ý^f麪Ì…C%3½á8ÉÞOq¿çô} ²EÁ½­ànF×€/Ãjoh°].Áðî¸Eây4# Gw4Hq!Ê6§øõ-ËžVCXQ¤ÔU‡È}9ˆ’€€´®«ÑhiCG´H˜ Y!ä·€¼úÆMÇ}l…çKDRc0ä°&¹ÇÔv¬µ1†îÃfU:‹¡m¼:èH`±ªŸ58 9 9kɨENýòñFòæ’áÀûSòÛXFv»Í7(ôJ`#yáÞ4ä–bÀ@Ó`}=Þ3;Üþ+° vš#w¦Œ:\ƒ"“ÛýÙí [‹DãÐQÎÎUÇ5\áI¯~â;öTé@[Œsbêµ&yÎBNÚ<Гò|s*;L‰³/‰¡¾Í9}Éè+Aé Ð· ^ìç¢ô˜ý!ˆë¨¶æ‹_ÁÇÉ[Šû…°¿ü¹Äq”Ëž3qö¼R[—¦v:"{…ê…ž…$E8$¸^é…ù.|È7oªÄVØ‹9.¿²"ÆS²„ópÊŽ0yúPáUÊ$é€Pˆ¶·/\>™ÁGٚȻñJ†8$`J"‚ÿjpü™0ù¶³–.#ØÄ ÛÆœ<ü ÊF ¦Š<Ñht °\ÞMÝÛ<.±C ááŠÀTjsA÷)C%RZ&ÚO(vƒõMßÚ’#c­×S nË^X½V%åºá3ŠvÂ:¦Ž"ˆZ`Íè«]ñNraB:t¯%DÝa²‰5•ÛS‹ˆGPæ=sÄ⟔5F”v8 .a¿÷Àܵõè„\+wR•û'1`‡¢ÜßËtþ¸µB©Iµ V'LChOSòÑPlHOf߀'P„^—0”=•„»ší'•…6j BÛÅ-»_[ÛPd£“HXÔìÙC‹°ôï=-ɧfjÄÔ•¬âºÐ«ý7Æ—lnSð5 T%Æî$Û¢k›]JjžDÚa¸\©zMª¦_§Feèß`6-åæÔ Ö·À0 B á´Ô©XvþC%ãY”ÙäËB›ŒTºÕŒÅ2Yå2ˆˆá1c¥ôéoIïŽ6!üùÛ(ux‡=MɆ@Ð1¶›2Ê&]Kïv©†[ràÀ;ˆýû˜5”¨˜ÉV»NnqaÒìš7Ð(‰rå6ÃÓ9*ÿp½-Â(0ë„ĸ°¨ÂXƒ[~̾áIE¡\ÛÔT½W¬ÀYÇV½œ±xWIGµ±°¼—Ñ ›{êú’îñÙÑÛ)J®]H•„ú}¼ÜB“>äÜ>9HõË’€€™fXiƒ¡ÆL± ˆ|åâv>14Dk$F¢ïã¬BÓKz §8\…{~Åkà–ÖW/(ƒ/–Hm›“椨(©û©û ­1j)‡²õ ˆ|+;Mâ4£ô(xåÓÏ#@›qÿóV¦U8{›ÔÖÔóÊîNqnï˜öhíí6XK+.þuioCÈMÚóNc Vµß{«;‘„RùU¶weŒƒÒd”àj­|Üù>]cß7ˆ{d¸úöw Aêë+¿-m^|æüéèö¸K7ã­„ºS%×Ìk{¢®´0òº‰æ½£*Ä%…ÇeêÌåvp“Ñ…¡!¹]&#iÊi²1˜ü€  ®ÌLmnš&[;º7‡ü˜VË]G PZg~¥;dÙ P×Ú&„w¹F݉ÍO©Ú0 Nûì'‘ÖõÇ|õÔô:_NЖó£ _>ðr|2†¸~ÈÛxVRŸï­g8}Q¥¢B72˜Gc AÇ4OÜ I ‹våTKgè?¾¾ Á±Llý´;Å.1z(yO=Ôôn„®>¦*‹§j9^žÍ>o¢‡;}2wzÐ[(zc'1s‚Ÿ·ø‰»@}ú^x²ç&näI©õ<×Õì¥[…ó@ÆÒøˆªx&¦¯d:2œ³NЂUÇØã“ŠËÊyXE<ejuŽñ.PFýö üQš1,ˆM©ºóJæåî ´Eq·A]_Èž0kù3cG⃥à«áüàÁµºŽ£äˆ_ÕtñËÈéÜ´Z ‡ö¢9]ˈy˜heE-s„‘æ»Vø s¿¹$ˆAQu’w ÈOÂZn± ¦|LAØÃÞ¬Ó~Ö$‘ÒbHK‡‘æ¾Ë¾á1éG…ҟⓜs¯z¯@ƒÈëµ7ˆ§RÛ´“þ$p¸$®&EFÅØÊ+ì@×°Ivöqë0 íª¤¿U®Ûõ§o̺°ÛWP‹¨õÛ›€¸¬`œµØyzfg.óNBj[̦÷leµÃ#˜?€ ²¢åeÄ]ÍšÛ2@¸Õjicê© Ó$·H:„­9‚›q[cJ½šØêÁß}JØ­ÆÆ9³è¯Lz8á±e$qVäO4žE‡ô-7êŒnÕfðäò.Wª‚ÒÌ[ûË=»äÁÚ,Í’€€Ä¤‰™¿ o•wÕ4íÀè3ºÇ§)Z^ÉÕ¸s Í YÇêwP•ôj­ØÔTtpŒ<ÙÚ _!"{µ þѰƒ¢ÐÅÐÍ$×®pîú;8Ò°~9M,"@ñ™Õqž¹âÌz”k6/ÒñÈB‘nÆNc¯æ3יИ•ñ òÐ=ÁÝD: º†ê©¬sƒÚ€»¥÷ñˆÓoMämoy)ù°sÎ¥êe‹„¦%=m,üW÷z»É¢ŒAaI2ÄŸ*îÔ°Ê6ÙÚöŽ¡‰sT!_7c|¿î­¡ƒøcñöPƒÝ­Iu­Ë,n( !äŒLÖ# R„gXBOü§kÁÇT‚‹¸¹—Àt8Ì3 ú©È¥>ï³q®·Qn]‹9g+¸>#œP[yDĤˆøJk ?õ'Äáû.|ŒˆÛtj`íªí–ßÅÝ'Õl|—üyyéÉ.þ©õc·¼¯÷@€§…˜Tk“ÊöCÈŒÏyøæmŒ^ïG”['Ô L+Ÿ|©Ä·FBÐ|~ãª![¦ÿÇfsSð©÷Â(eÏ7‚A3 ‚¢6;YÍ)=¥Tè÷l“þ™d7]ñ[ ÿh†Þs^ÿß¹† ¢°Ô¡^?æž2“~ûr±ïRªê³-ÞyŸ³ ´» ÌŒ$ÂÀ¢YõOç„k‡¼^¹%Ã¥³Â6´@S†ÙÅX³l‘÷ÜÊÅ9ª5ßKŸD£õŒÊ*ï:’ïpãúˆ÷$E,lµØ4è%0’v0Â> p\wKþ€ ß4X *®Q»Ì~¡0fè$hTv‰?!2IúN ;FdÚÊH0™Àc‚¦‹V• ¬=ëœD¡NôÂoU&ªµ÷,¸Aùa'çGÈŽšŸlÁ(5ÏÁ‘5SãQºªê6„½óf¢~hŒŽÉÉÊkU(ÃV¹|C Ôò_£žõ^$‘^X¦›fIh¹Q¡°Úÿ'’'5B•-nxÃ8g¹Z|CB) À‘»Ù&…ù“ ~³„õdÖ ·Mõâi,ÓuFó*ïÔgÑÈ/¿ìdâÝ¡ð{†Ÿ•ø…#%ûׄÚ`‘Ú^KeCÝjÈ|zÔmª‚ÅH7êàUÞtòÛm]F™2r‰<ÕŠ(,nËâàÅ%‘äpðù £â2OU]¶ عŸû“Bä’€€¡†üH™¬÷¢^²Ê äH‡,B™â¸›É-L…mfvƒ{Óû¸´¡¤W{£…3bÝü©%iõw+¢Çn žF­ŠóËÞ}Ë‘«TÔ¾¿X$îFÒ’³o˃}‰Úx/ÖVñ,¸ò³d‡À ©õc ¾tÌEÔþZ>{΋åá5CZ4‰ë° ÀŠ|Æô( @rÀÌ=*gD{×à„)^çwÙR…ÕÑ9õ>SÈŸ|íÊ&øQ}KwZ$üä\IS)q™Òć+5躉?N ¬ ºÔ±ÐŒÂ¶ÜzÒÂð‹àš+jøêÓåäÊïG:BM]uyÉ 7j$%á ÎogDèøXÊ—„M>U‘n«jÅØ-Õ %”œuaCÄÎñ`'àœC…¨²ñ µñ÷áw¾aÌ‚¾NÅÊTÝ®gbÁk™£—„mmÏ2y•.Iûž¥sD~I›8êÌóP³Ò’Ài¹+žbJÝN¦\c‘Ëá‰{uĵÜöÞ 0QVÒÏ Ô d\Õi×S`C«žc¾¨£´@ÊqB„óúè¡«ø*[9Õy·#éuÉn=+@Ö©Ëa™À’OœC‹ rO€!ù^¦zf6l^OñÂmšà(Pr¼b¿Ô‡v¥cè2xï[  ÷:dÉDê¼ l[Òm)b¾iÌ~àÿ«_%Š6ÑàºcƒÁÚ(‘My®T11pC‘”ö¿ h ª¬ËݪX¾’ôWb# Ö=/˜˜äXÕ‡dFDWoßt È¿gõ¶¿ñÊ/£ã©¦a£ˆ?‘ýÆgªÚò.Þ±0˜î½¿tJ–CÝZèÇIñö4…ÊQ1UûùÊ6yq”Ýj‘‹qêÃ(íó—yß섹8XéLŒpm¼ËÂ9÷X•r¤yiwl,×PäØ="–EþX×ÕÁØ­Üp¨eºa ØÒN`8»—«.G—yhêŒaåz¼—ÐÌÆë ˆ_<³TIµ‰š¿ë6<ƒ¯ò>Ʀ½³RsþQ°Uˆ«Û¶[='w}Ëéà`ÍÒ¢£6~cÛ˜aÓÀÛW¨ì®\œ§‰BüZX ½ŒK¼‘*ÆÏ5‘YYà´Õw»##lŸ­ñÌ÷QÀµ,Û± Sš¸Ýù­lÜíë5ÀçÖ—ý·tvKP=Ç ¿àCºUâ-ÁÛ†µ46TÑÙ´ì¶ œ’€€¢ AµðòIa~rbòrÀ·Å;PàÜŠ-Æ ‘¼wý"Å»Aí0è|þ&7½Íƒ™ÁȾU¼US_´yÒMkÖéK !!ûü·J̺W ûâÄ××þk¡…€ 0É„4þ@©i Ìcþ1ÉKÀXå–QÔr97 ž7D8xXv¬³À‰ÍÁºœ«vå¥l?ÑÕWæùSÒã“i‰9kZ~aˆròt*²éúŠ isY”~û~IáûÿEò-½{¦ðÓôÞ9E#ÉåU¤ê¼“ÓG$™ Û9°1/ð¼OlLVl#…š7l1}dP®Þš;±ß}»æCJ¬€œ¦l)Ö~¸Æ½±æ0jø;Ö_ýI°‘ðôÆã}ÆÛÚ;íý’½Õh^ÛVFV´¥Êé™ ¤Hh/™¡œ¿?[Ç‹›¦oÿc´½êa”;§–¯æ±ùJÆÙÉÎ\#÷„½¢ÅÐ-‡·òqHÁ×´Š#ßn£JÕè0ü]Ã}Súay×É_¾ÀËÁòä&šÅï>Ïxæ3ÄšÚ“%ŽšÞè¦s²‚°0_ŽTH0eö¼o§Èáv.ÞRF¦•³C[ó´>‘|Ž?~0$ððAnoõ{B%áú,”á»”Iaï);P&0`í ÕK¼óÄ!G× , è2`<¾ähÑäûFq³º•ÄÏF<8}I" ¥å'Ê%5ˆÞŒL®%NºVÞò«Üì#èî8Ê{—“œýÇÛƒϯJà#ñ¬§n@I<†! ©‰Ÿf‚¨}2§hmé }..¨È›é:42Úxä)•9×Ý¢–mQ³Î%€¯ÝÁ©IÝËqúKáè’€€ÃK¼À¤¨"PéÔ_1Ê¿²Æon’¶‰4³k‘vÖ‹l½“Õ«² dRoZÃ{ˆßßžÏV<ØËyM*¢¯P¡—ü×1#:};Ùåô™üŽ ÒžžÀMJ<Õ¹ñŸÌâ¹*.bshã²¥‰Î>ŸÑ6¢o¾ÂˆSQ˜kTµ•âÍàN/fW€è•ÉèM^›“òëû¾9‚©ÕËóƹw‡”W1æƒõg¶ÍdRø†9Öo‘Bnþ‚X\ÜUýåËÔ$ý˜o¼ÿÙvPýÌ[Û:C”»ÜÒV xd“6~fŠ@©¬ì¿ærìD^ ,§áIáQ/’³ÅÌ®ƒ»"À—ë&`«ND¶tP¥zéÝu Æý'¨e÷Îè<÷yˆˆ]°oâžUFÜMY¶ìÝe‘Õº$[Í´¦­9I· Wa‡b}ýc!Q·üR)³ RÿN½ŒÄ+ï9ô5ОçêŠw‚Uqýõ¯oÐ| 4E9ÝeÌ9aÍìí(#À+ÖÄ,Ú©¿C:œ,¨…j}¨{UöõZº2Þt†MTÚÑÛèªËÍB”Þ?.R÷~¸p!*•VR Ñ8ÉÕ–ØD‹¿<4Ätd~!O<=^J‘F¿ „uèkù_BÐCbǘƒP#!+ahsJKŸ³AÖ)ôO’€€á4+˜²e©z ÔÝtµÿ:ÑÓ†ƒdUƒ´BΛHvvÏ~(Ï‚±Àð¡òº!Åa:Ù å[€m¬OÉ$VÎ 1bW&Ï– ж&B^¿2Q! «¼¡ßu_ýĶÏœ}`bu­ ˆ7ºÀ&ˆ†RxÈ.Md®âï+¤2x¼£J4¤ÇË,fûd[Ô2e]ÑÏïqé%… Î#rs3 Œel:p­‹ú•¤yËÄ&…l¸\˜Aà‘>ÜT”¿gì˾¦’:ûdÅÚg@ÙÊßåô=jì?7¡ç9X*ó #4Ð%ß«à)Šöêré <Ȩä9 E»T•4*&E>ïlH‘«'n¼ìêqm]ým€ùÞ M”š •r³ûÂŽ¼îP‚`a—§Bñ6AiN¡ÁV%(ëe¯ãcæ ;(§¡°"[}2Ñçµ+|¸Š^ßP»æa@žü—Šú;FÃ. ŽÜqìÆ ¹ ò©ÕeÊYAqL—s8¤:þ*}÷,v+/Y—vu§ÿjmV>U,YewÌt¯˜L¹@¶£ÀÈ壘ì¯oÿÜœ,Þ¬÷Ïæ/ý {ŒÇØ¥F²'0æ,Äã—×ö![`Ÿ9¿×ÈÎ6z|^WåøÞ{Lç ½"¾x‹øzæèÕ|ó](4€u•pÚ®ŠõMmçxÝyúŒË]É©h÷™#3R¾£ßPâjtwTŸÖˆ) “xy}§ýñŸ.Òà„:%‹Ä»¬¾޳j_‹#? ¯‰¿ÈÂØ¢Ú4­}SO¯æB7†\ ¬z¾±m xÿ0õ5¹ÆºÕèn™ïŽýª…_æ·g눷-¯îhYõ”úÿæ;ÜèæÓ0;ªÏž/–ÝL÷Ÿ—"ÃãŽh|e‹h.Ï-Ðøþ‡æ£ƒé |«kgƒÀH9¾÷ΓÇI j§i²¸UPIË)©K1SÒøÛüÎzq'àq¦ ‘\²›Rûð@qþJŸ&¶“‚¹Ç¾/Ï›ï[´` ÞzÉÉ>U– Aó™ZÏòÑŠ1¼àw&¶3Ÿ¥ NĹPçV&›èžDÆLõG×Ê~ê{4½é¨ev“…~ɱ?‹´Þ“‰À¹61œz^oÑE"]96®ê¢Ðs/&£9-Ÿ.#1f$GÙØ?‹Æ*ç¾B·€ÁÙ'*/£RçO’€€òY°‡ùçÑâr 4sþá‘î¥nàR?ÖÜnñ¢Lö¾—0‘AÒÉŠI¬a?Y(Œ”ÅXH<Þv‰4Nž˜ ¸€/yß|Ri€~ØV#ž]‡3€ ´Ë%)-‡)‚]_š!ÙñÒ;õ#¬¯„Þ Tb½½Ác-yý3MšÕÛà½õC>[gµÕt;.¡kI_OLâçªtEšF5®y}Óµ»=ìg±3 ˜[ÿ^ U…LžGw¦8矓¥oîùFn7Œm±Ÿ„”·ÞH m\dê»h6UW@럅ÆŽµÈ¿nE8÷–iÙ—œê ; r0kÃ;â_`/ŒÉ3ÉÈ”ºÉoÿ«:ü9R—FðÙF˜ûX¼²‘Æ& Š /À|Ýî&UÀÜ=‘.qÆa¡¤ü0—¨ú@jlæJJa!ðù•vÃE씽s¥ž@DÀO¹7–ÑRw˜ñ3ã…ößzIšqkbŒdo0'qÜpœç7,µ»0.ÍóúÆž8ÅUþ¿À{õ{ÒËÅd2¥ÏçöÇ™¥CâAó|}žWØ{LJDœßæå3,?ú™\EvOÌ‘ÈÖ–|*&>§ž udŸÖ5 HS¤ ¿½3yUû¨Üh|ŸÿBÏÞƽî5E“i¿> ÕÙ¿X1Åô£¶!ÿoõ¤s&Ì¥ï ëo5¼W¾b_ÿ+œ­Û” º3—ŵšM¢õ|‡O õ0ÿ͈ݼ2h4ƒ‡Ø%o d² 8ŒDÕ`¿kÃd4§H 8ûçQAg/=ÈÚÉSÕr+Û"¢É#˜ñ×D³qP# bv­æ3¸.§óKžsA¥ ºDmÔÁÂ^À¥ñíŠ3¤KQͺ¤½/‚ÅdÓcd?'Ķõ<а;cP22¿¹BÂ5l(>VÄßEåVÇtÃԃ؉y(Û:{kÞ:øÍ<“YÔ3õüz›ÍLÉz0È/þ#Öq^xi³˜âk’bqìΉ;¯áã祰J³X» Q¬Bl[c$Sñ hAs`ÜùËŸg ùP¢˜öï~,oر LCX•Zº9ô®“â¶áû‹Ô‹%˜À ý ˆÃ OºX÷êÃhÙzØ.YÛ¡‹Y Õ¨z¶ÀF¦ôˆ£|aaÞ¼Š®ø]nZM¸92õ÷9;×'ZL^$Ði;| Û¾V³¬×óyìäü•¶šç;ÝŠŽ$pøý’C *V·Jëé3H:V30zö˜e E"Bj¬^“IÔkIÏÈ7¬t-+E,BŸ6˜rˆîôÄé´sÒqjüB‘|oøíÔïQðrV§úJ_&Y<À™AΫD³*$´_߬ð€Åkùh!ü2D?d»&UnU3¸ƒü/§5ÉÝ `ãß/‚Œ*ótƒ™€oä*1¼Êîêw"á OöBÞaÞÛ±^My÷ïnuJCàìBÎL¥/€1MX§nÈ^äÝ•"µËîÝMÏó$%«™ëFÝlýGÈÄ8 ºh—‡Kô$ éšÓ ³ì1«([„ÁAgóì!<†Óu´ŸoÛ+.ùëׂãp‘gÈ+#ã¼J‚bt0ÒÉ QŸpËï׈%ëˆx$° .ÂPÅ\8t{(2ô•˜=SðÌHÍ.ÝŤõ­U1­Ì²ØfVXv8_õ‹ÕV–Ë1ÏÚò"I¼—„šÉ¨J{ÕûÛ:KËË6U’Z ±$ÐC¨[pè)Òl=}vÿàäR÷zÔÙ5î4"ITr îtŸA[XJ×È4Nswu²‚qüÌzÉX)s©Yº~»^x*¸×žZ:Õ é×éÔž¸ÃÔyµïkØ„9LQê¾Y¶m3­`9àç}¬§¥ôkÓZk-R÷‡¹E÷’ÈwüŠŠ¶¶ôƒýw‹‹GD Kü¯×vÙ;×õi?ï%ü6ŒD~ õI„_f/ŒŒ|÷ìhÚ ÉÈŽ¥0ž9)ŒW¥´n­ÈéàZ¢oÛðpUy*,3nDšÀ¼)*Ú¶¤»5˜ÄÕkÎA×X7ß¶b£%-ŽÄրǾÕd:º^+’LºSXúmJ›;~óŽî'Þ׬tЮ¤Âßqe®v¨ UbV©<²ëm|ôÈ×EÙÑꜵ†m6à*Ó¤±ú$TÈYó²LJ¸’€€Û¡÷‰‡WYkE^ÁQ»mòY ¤1@¦í¨-0 Ê€ö‡u]ÀîÊÿ¦2½Ÿ)nqÇ):HØ_µV™a+{Àš°•,'a3›w[û.”²×°£‹eÆè4Ò*¥Õ®ª<ϾåÖ?ÞæÌñ$¾Pˆò=ÊDk–‚i±h‰uÂQ«¯µåÌ'æ_.'¯y9ö¦„ðð3~XSúìÈòý¯øH“Æ0x)º£±å­^Ce2“– µÚ᫬Š!åïÕÜïQV;9–§à?ËaOlpàõ2i¦O;i¡Ö/ÊÓy‰¯‚vA^ êÁÐiI³B‘U,­|¸@tn¼ W/Xàë¤:À»ty’›šïîš™‹U.…|Ç ‚ÏŒPÁ݆ gF‡Þ‚÷ã ü œ8xíK™¯ýšL•7BgÞ`6‘+n}þ¹…¢Ú&_«A'€¢ÍÓ…I hø[Ë)þµ¯Ýˆj#Ÿ¢T˜·ÿ¢ÆS×óÁc—X¹¾x.Û]Ïpß#œ¹ËÓqœOdn1<0´?þ¤øV’²_+üR–¹ýï6fdÜ~õmBª p¿0ƒ‘lߘ5eóå¨âåZ'à«L*åœÒ²QöW˜6HPËú ½©Nµ†‘¼w7â/fá½¹.CR:.(›~ýRjÉ®)yzÍ#b°¶½MAîè"B?ûŠ—m#©S5?w†n𝢠œ2÷Ô é&*ªÑîΑɥ1^Á/ò!¤ykx åêì+ÀäµN'âãnæ8ŽCõ p@hÆFó 4ub…*RÕŽ©Ö5¨;$–•Aœ@ ¾û¸÷šLºÞĺ1…';Æ•ëXÎ (Ï™(¼µÖ†n@Fá.±n{ît>eŒ.ÎõÕÕ8F†Uc4"u¦DN·¨\î¦sÞ5Z½üÔî¯aÍZÏù\k/A ¹ñØk¥,íÀ%ÚÓx‰^‡ƒî ½¸®\š×=>¼.ÝÔ^•J‡3ËŽ@'ÆAœé~bwlLw³˜ç;Ê:Œ9Q¢^îN y+Šß®ª´šæ‚`ix7_BåíýU±uc@ðC±R‚ i‹Á„+NŠZ”À·¼ˆ§:‰µ,Û,K,GC§Éa–W^MW`:W»`ëÄýž°Ö\šsû§m­:&æ(p7‹×â¦'©LϪ ’€€¨T ÏŽ ö¿G}°—æüJÃŽ Ç+¶Æ2cüì¿’Ú¡Ú ÊjªÊã3kÿ§Ÿ)ãó^´k¢Œþ¬ŠW ³1èGçÔìªÞÅT+H«œšõhxª¾Èªg`@!—t㶇…œþái¥#YñA‚å£ '¢Õs§Rv¬n½Z0“hAlm FdÈå‘CúÝÔ—ÄNº(Cʱ2hÔÉĚʈyšƒ³2o­WæÓI¢Í]ZRùÆž¬Ö{Ž&+èn§'åî:ÐûZÃI¿lÆÍ,È4T½ÒÆý,Õ‚{ÞÉnÉáF‰–ÁÛbcÚ=ǹ“Ïw#÷O@x*¹Å]ÐÏ„ØñwÊîbø'Ã’ÛI9鿤 ¥Å}ÇÇĤ±ÎAxœZ_…Ýp›:ÿ;h¨ñ}Põéê¹¥ç{íW•È3ýKX„? 8·dGÕ/¤¼Bã¢K?qŸÞqo'ˆ+âDï‰í ”î݈†¾•&saü(ìIWgA^R=’—aà._ÕG m,3¦þŒZÆ-¢ }ãHÿl1«‰µÍš ›Æßºýw&EÉŒ´Y{Þ+ŽŠiâNsù…£.AzQªç{íEÑÚiy™¤-A­žËC t‰ÛΫ¤MŽÇñ¶ @ÿH$&†ójúžÉÕVÒKþŒŒe…Ib9ýt¿£N¥ç”%ÆébÜN8 Ê®F¿ËÚ$VE•Ó›e¯6ч†–‰ 9Ý?+y\°!_?­™P; Ì2³Ø£› Õøð¡"0zÿë^­‘ö°ÞDäNú?qqä³ôЖ wŠu?¼òîÔšÊHg0„.{„‹>'S)cœ{žÇÛ ¬âåHuõìGìNÕ‘u=$½]ЏžÆ©¥UU+Ÿ6Ó÷-䔨þ÷&0å"¡ÓT{pŒc:YÜíÔÙº÷Ï6‘qšgÑÞ/ºIYcö/øàá&:YÕÏ$tcO3ÛY…™ü-<úg "ÇØçû`µèó¡Cnî0ðhÒºÙm$už[< ”èaïø«€•›_„¾™tQV%…Ã5‘§¾/7ÿÌ"¡JMÏšûgOàn.QFKgLR,ÇC7`ó…„lõ„Û›â³Òܵ12øühsҼ،ÕüÏ•¥¤».žhÅÍšèûhYEô(*£Òß7Ä@ùZŽ93k.)¹he_Á¢™òÖuPª )™%ý„ýda¾eQ'/,0ži¦}z‹w-9ª‚ü3ìºçM!ÐÍÂj­á6“Ér6ÏŠj{Eç…gÝ5 #„R€Iôî§¡‰06NGþEÚ»8ìjPej_ÐFìÈf–Ò EùòG½ãÉ*¹ÂMYÄÇuù‹užIÖ Ï¶éöÕÊzý ¼Ô:$vœÎ/8Ý »¯c®E—=ÐU]ôU†ÔYæš#ÉRàÊû…¯"aþ¦ŠM2Mˆ²s¥@Üdj.xîfàÝÄ‘â6Ôò3ÜX(³½…?îÀz{t…ækfÐÌúÍOíU­Ôê¦ò˯¶Ù—ëÀŒ\÷õ­&×%W’¶«ššs%âé£ý%Y§!ð hО‡:à*~*lÛerçœo-³2aôÓý"JÚx0O÷cÿ›qÌð ëiqHÚF74‰x)6·DÐõù‰òiµ–˜-:¦á#]ÊϧªÅTM‡„º»Wk¶kñX–SÉ,¯¦ªxPƒºdJº4Ì4a§[ÝI¿òªwÝô·È¢¸Mg ë¸ÍÛÓé J¦È^Ù{Ë*W{Æ$Ÿò ^4ÐK y•:º_+o7ávÜÒzCê²òÍÆUIÌ ¸\"9?CB;TfJ¼jZI¥H!Mñµýxˆì±mÀ¾#¨«L:cÈš”+¯NØfž5,W£¤ÔH&á„ÞpŸ8Hì½^ŽO½fbc»¤àÏ‘^ï§$2 9¬Û ·¬Eçïþ]€^ÃHhvc×ühBâÓ»ênA"ˆ>à oðf(¢Uó¹qjŠÿNÔïµÍ÷kúGõ×FÝÄGÍ×X"ÙàûÁ™,¹öë¯*îšMá„o9ž€`½9+aÙ£eÚoqaõµ£’€€×Æù¯c~Ë`bÛ»Íîš(Î CtËÉ|y’@–™+éþÚº›þzÙÆŠ€µvM›ÖÏÑ´Šƒ\Š&0¯µ/Ø€P­Ü—_²åÉκ‹æî:Ž–1!©Äi&‘ÍSY"6’,.Ÿ~dó!Àâ•‘ 5dǽ ­^ùhéöÿÃ*a×UÚîÉlóWi’oA¥ªÞuãUó[kQ×¾%2ù÷Ê4”|‰Ç§Z¦f°7:·03(©i[ø¶2Ö"I (ﳵ݌›ñY\RhR>Í5™†g—ºT±T¢e11Œ–‚ñ2÷—MRcÈ UCaŸ0¥,±ÿP0(ñ…÷鸎ÏWO†™]Ð`VZë?ý_ÿ.‡áág;žÐEÒç-&kä;=È¡¾îCäµ2×÷á^U-ºx;ÂènYü …B‰ûÛ³ž€ëäÕÓñ $]ã‰ç'ÛpÒSS±yléÛ é"ˆ…X!I›”$KÖ»Qjyûÿ¾FW‰Å'Ù†“ÑO•Ó˜D¡©g)µ3òˆÆëíÍ£~•'M½åË?Ùªò»íÿV¾%œ#‘ÿÞËQÈE’?0;k¸^7º“Ûß ŽË®WǯÑ5%0ºD™NLajåCÂÀ§¹xÂÆ#úÿ³p!†VçW½_n¥’Ó‹ëP–a†¼zÛ`ÌÈ ˆ ð¬‚7<€K£C3MÉÕ Tž s¨…–Fc6³‘‹O4JM˜›d>&ÒD´^X/X¸å®Rö"±)+Mý¦°>eÌM©äóÍu'Ä|6Zï^•Á®¹†Þd+SPànè—ˆZ ©žÌuýÎ.N³àr\Ñ¿ÛÍ'Lk7i„r®Ë(—Ÿj‰ÿ˜lùÛ“ð^¹.²_’€€Ç}&ìyëu4§†)ÈjL4®ƒ¢G\ÏNÜýÂ$ñL¤4œŸ ŽUv–Å¥+êp)jy3F'XŽ2CN•i%møœÍ… Rª ºb›IòlŒß4³Q’ ’X´Ý{ã;G8¼ˆ0pªÀß…+=õ­ÎZLH¡Òh×Þß¾Lü‚ír¬³ ³‹¨xÂÝîÉ­®fw€ý¶Gãè=z¤mK,NÔ/¢#ÝPê,÷½`ðÃùW<ƒÅIçŠ"@%^žJËÏ7²iŽ3°ßÎ&ž¤”yl„8æMñ¢îôšÃ'Áƒeý|×§©¢vû{£+¼µµÎ\Ýtc6¼À‹Ñ³å‘åyPVÂ%UÅ…,¶§͹@޽Ðg´%ßðqæ±L¢ëÒrßmWEâŽþjù{lÚfáwUW4ËŒú{làœµ€Ä£_B³PHšQvÄ–G€äžD¯Ž@?V´‘™CÛ‰.3­°Æ„ëQñ£éÚƒÓ(d)œ¨E<šÂ©ç{ÊФËTÂ,&Œ¦³4Xé™f“8oÚžw¦ƒŠW°º2œF§bž+¹_@ ¤u¶¸ÜÿÑ e‡ÅýÀ—'£U2Ƀ6°4šdPvcUKG£MçWsìÈ"àcšÏ/%'Ÿë |'âoÇÆ²ŽágMòké²ýÖöÄ )>„$U5¸Þ“9æ§ù+!*Ú¨ÓqÉ·fáË9Îò,@ô[m¨CÀš ¨ênð¢WÈÚÚ-}sãRuùb”öu‰¦þ¹¸ƒþåáÅ·v ‘w;(¤/!ÐkYÃÒA~Þ«ð„\À@’8¦—3ä®d¤“ “âØF 4ÎklVŠÄ AÑg´‡ÌõS ù¾ÇË ˜‹Šà…³†óïøH±5‡ËÅ0,ßo]~$YÀ¸ÔyyBz˜Ïà?ð”G©ƒ¾£¬¸8)- aü-A„?æ¯)~kO†½¥áãÒVF°ÒLt÷ÙâÇcà#\Ô×?¼ÇÁIXÀÐ1°‡WØdžœ ÿÿ¢`Åî.³Ä¼V_«‚¥¸<þÃ3†=ÇÎê1žp:ì#}È‘KC]OÆX#¹ƒ+”Žðc agu €ñÔ¨ð,i>$wgQ€Wƒ³”?ë!û6þŒ µøSžeæ¬Â=¶0…Œ4Öp¦4m/ÿ÷§î?àwo:0šË­’€€Å 3«ûl‰ªt«UÍ1ÙlÆ U“ÈŽoê1I(~+µ :.÷yX1ãÀå b[KêM=óQ^–A•†zU#<ÏoØû'Pˆ´ê[;~”Ç83Ç>£ÍãpU‘‹ÕGím(ï’¶ŸŸvï¡ÙÉ!æn?4ö;*ê½ÜÙ`Å2£é=ôGŸ§{LÁ -ÓÓ„¸G´vÁIvTŠÀQ©Ã/·«´Yµ"ÉÕâ× ¦»¦UD$p/hsÛÃ'\”ïäàe[ *Þ{ܼšS™®TMmHíï [Ú:ÃÝ1 ×PªXîüü¯oÿ©º ±\™ £¶ƒä‡>$¦½“µž â%Uÿ ; Ê&”‚½«¨ÁߣD}o+£öǪÅЈrr0€ S7Ôÿצ ™Si:lþ—‰íÜ<*Vèõ,˜¡à’€€¼ÃÚE.—sô¸èc¸òz¥Œ!êÉýÄÇ=wMü˾šVÙe=U„,”OçìH“Q>1ôàÚwÕ¢ée#a•6“Ö„a˜r¾„Ýßk¦Ï7 ¯Ù˜ÈÛØ¸iÄõ É¡µ¶} ζü/åÚ1¦s bêYt‡VÕEO«JØÂ,ÿV%`¼Ê¼('‚á¦g¬¦°)(ôï³s—Îe ã!¬§´dý,A÷v÷Cïâõ5œJ/nËïJŸïNQ×ÖnDüy@¼£¼¶øF'³È šß%/oÛðã‹êØÿ”)Ÿ˜yb;Ž´§œ•°½Œ¿ÝÁr\Vû_›(e®6¦\-»×â aZ£vâ®lܔд’;ø©7ŽdÃäÏð="CP‚)ª~(L ”ó‘îúT›#Â=æÓÆ0ÝÛç/AµóÜÊ#BIaž_Öÿ…MÇ¿(g7ÎòÈ—Ì…8Ñcz|ìcÊO†ÛªÿÂôëU3Õ>ih{¢*½)hO[!ÚñHËß, 'JýºZ>|¼N¤±ñòÕ½Ò<0ñžråên¬Þ9oÞt÷K=O‘R>m2kˆ>†Ç¿¶†>*‰ðCàð\Oóê6˜ë:‘*šv^þàd®_“g†¾ úàÀÌ&ë³»’ T¼u|étÛÍü•eˆ¸™JÔA¨ÂÑ誉 ói^Ÿ²½Âˆ—\íó¸dÊ=Ë|ù—²¡r8ç×n›éJùÙz¨R7)ÞF?D”.BìÓ•fÖeÑWþý%,qYû£gîgdÓÜÿ½ß2l¥0¡ö=€¢ÐÑ-Ë·}í¦“>ªÂWhºÉ˜Á?×I Õ¢¡#·*ÕÐ98Ÿu¼àóQ‘dz²]ŒÌz¥SZê¡ÛœQ´7LçWoù´6_åz t‰Q\+šÆ.ûò Ö;4D<É fÑ+Ú/¦lÊüX‘óÂã‡Ð“ƒ!Oºs›„ÀµS[iIqxLŽ“é±i•oOÐA¬?#ô|ãx̾êGtf&bŒm}Ë£BXõ»ujô9ò±#yµ™þo£w-WÈ l3Т=Ÿ,¨#lùн©ÝÅC6kÀÃiM”ÑGŽzA—úÄʼÐjú­°~ºcëRk”Ää«,d £ÕоT^@ š³—ñ~<nµrY 鬓$“˜Î`Ô¨g^Ek¡’€€­»ckáw‡]¬ÑÇåéOí=éSJh>`àI¨ž¬› ½Y ¿ÛrHÞÒ_ŠÍpÏášfÝ¢‚û 3ßsg4¢¸í#«8ÃÒÅ‹Ûaˉv4’×CokÖGzn-1©­ «~Æ#)GªÇÌÏ [C[ØKuÁ€)ÉOfò?“’%‘Ñš¾±ðhœ7!=E`gʬú¬*êeØÖ.¹ÈOeORdeýåüIô'Y¥% P+Ÿߦà,;¼b”£Ü$dßÑ£ï·N¹PkIââÑ ]œ;S¸v™}ÖÔp¨ˆóÔÛ$œxâÀXºE¤[nM̘íñk²Æ¨®rÝȆB f|VŠÔ¬*/bØoUƒú8’6ø$çÂHOH¿9ÿí6Þƒ¿%q¶yˆÊáP*-AŒ¡c„2ÊÕù˜+Œ¨îÿ(á «¯ÓrøLåk¦Åá`V^ÉåSÓE0y;Êä~Ô4ÊpÃAi„ÐBÚ²ÁÍ€ëxz,- !RÿYžBZ¢¨ÏбaSÕŸ×i¼+4©Ûp2ÄЩp‰V^Ÿ6[î Ù¬°Îö‘L3–³P£R¾äš[Õ9Dè1ܲ‚µ}–ü©3K¸²³¸[ÍÉѶ@ê[u6g}ù1„*@\½y9"‘^…6+²è4¿Ï .nëÅm¸¬Â6µ¿öù~€åË’¦T•Õ¬‡‡Ùˆµ^ƒI›çÊý’ãÎG õV6þ3×¾„zÃò…|ÅJ¹ïßê©6ÐÏt°¥0©ö²Ka'L<ê¯ì±Õ±ÃQ\d×uôFÐ`Ñ ³…)Jå‡Çâ#ºy;_È´}ï+X uš¡@#Þ²Ògžu‰ gÂKr3‚¿Q¬£¹3(x¡:ÆÉwJmû×Àî^y ,‰V¤­‚ö3GF ¿an ƒ\{´éŒþ@9D¹©%¥¥K†•»¸dIÛkˆ ÀurYûÖ)°á½Ouò'áWJIJ®òî¼!F±‚—p,ÇMÇœ•w9ixôpÄÑh‹è«)>SÕ´æ+—ƒç©Á/2UÑ!Búgu°¨„/ õ|Â-ްO¸"¼nú þl®e!›ÒEä`¶PéÒi£Pröÿ3[¹M(<2Lí<¿pê˜æ½Dƒ¢¯Jäã@¬æð|Çd«§ThÑ¢X÷Ù¿5òâû -‡)åÆ^1o8ëYe öù\ˆ.®¿söý ÷šÈAÒSÓì™ÏÇëˆ0‹êk÷†riÛJ bÔ÷&ùVð Æ®F;™2!{ZPÆ™¨ëʺƒz4fѪ)4ŒƒVál±ns8@É)GÇ‹’ƒzg_ü16å|À5¤“D ð=&[gŠ…ßè`(°Pñ¨ a×}²(ì …€¨Ñ31Âöñ£² \ÞŸ’CaœŸÑMîtÆÓÕ¢ƒ´‰“þî€Ï·_Qâß@ÚÈ ˜n*ª4×Â/«_¼÷¼B:QYžyJ]ùŽ*¥×î!~6ÖKÅÄZŸO>Ózá©èÙº.´Tvf» ùl£§G;þð;mõBãàIÜR>‘òºKh÷¿Y›‰þ¾ó§n«h@á¦WöÂëµêϺ‘Q²·Ã—€<ÓX†Ë¯HÄÙ‚Ézï•r™ñÐòÇÜòÞD ± ”Òz­¥Ö°‹˜p‰ŠÂãâšÿ»A®ÿûÌ7‘0TBùÌÝß$!z +vêæ&ÄŸ…sñWìqX}Kñ²JéM’€€¿y÷ÂS¤ö…—'AÍ8‰§pYu™œ°Å4Ÿ ß9\)´è…nyòå´š-ødÝ%S}§óDy„1]Œ‡×óêÀùkí`´X :*¿¹­ÌeC)º˜îå­Ÿ _²U™‹þ‡ÆµF¬{ 6•Wq{ðSkëTÀà€ª3j_‰´™‡HG˜qŸ(ˆ (ò³5ÚæVoÇ[?tr§AÙ–ãÚ̓ªY4Ý¢2`xýТwîðK‹õˆá.ÜŠt—{(nÄ‹ÆWš‹ˆ€)shíæÞ62÷SÌ8En-¾TVÜ`¦!^øh¼<9Ú»1ǹÖ-æêò¦õjôšò®Î,TxmÉ!xÃc~Ó¯öhp¸°kܶƒ“Æö|û/s’2%‚Aiu…ä?%|õs@©÷™:›Ãe3ºîÇËž:p !)†nÄbßHŽàßÝo©çQ@8ºš_û²0ЕmÔÀÊØ¹W BSF1k›¹MáGšÅêæ%Ü6Ý öÀ4é£;_Pô¦è¦‚#¹Xð@½ímÍ$MûõÓ6QR~'^WTœsèÛ¾%¹~N'¡˜XûØïÍñˆiÀî÷½e¾ú¨ÍÛ%pR„¸èôá¬ÞﳦÏiü-·©'®¶ºD8¡™DNÇ¡.&¿ïÚxVÇíÙ‰SÈ|Ói‘亼Rí²"§e[8HÇ(T·êö£¢ä¾a„œÀbHÄ3ÓïmñsLTÄn‚LIPáÉg^Ï3-n 'í¬4ƒÿ”)˜sØd$èZUbŸœÐÛ0‘n;á‡p2é5£U…ïKØàÃ]Äâ‰(Ç®•6ç[ { sdÝÈ'FåU5]±0…cOo¥)ǧ-lŸi‡|K{fKêØK*Ÿo÷[LCˆwæC:’ç´wì99Ÿgm•ÛÌ¿/.³‚+„2M,¸éç?õ^¢áÄ*Ô£úzI!e„Ðýrßý ¨…á_̬¥SâϹRíK–îgœä¦‘Õ ½ €—µo0TDÝš¥¾]{z¹kj¼ ò<8±<Îe8=hKéJûpÍTìCTD[é–¨Ïz_]äýÔ¡˜t¶Þ)á9‚?ûúçËù†‰&óoCË€pò&—Ôb !ß;s!ð½öùiQÒ-c-ZÆ {yd"Êäú-âpÄÓϘcvÛ%`ÓÍÿÝÁ#*!=­€¢]¯œ¹ÝG]ù®-=8‘ø1‘G&uI¼C¯t¥ÉKA1¦/BB‰¯îc.fÚ6 S†ŠŽÄmWr­GC›#EN×O›ÛŽwa-$݃À1¹ÖãåÿLüáD;±HvKó]lv}<|q[öbÉ#ö,ÌøW?í):KÓ(AK5»dAxŸ¤3]¨=aëDò*bd£Óèª#®…T‚ýíãÚâÇ(&ÚêÃ?DL2ÞS~2½ûxµ€.)ky)}—ÙOéË MW–<—+h¿Ìk7N» †±öU2;mhÔ‘6Ð8>€û;Ù@M¿2¨"cÔ@Š9Ê kQ` @’ê¿Ó@4ËÅÒjÖ²QöN¹Œ€õçL©ùXÐéF“¶ž”`H~L—ís¨ §Æmg>ämªYš 1f¶¹ê÷œ›5ã+ ’€€×ûzPG`ºÏuF£Ëk%@ZŸu*~à2“ô ¿#[zßi*s9 ××D“`—¶Zog¸‰W¢ñ¶¢¼p[)bÏþ+¯œÖ¶Ú÷gc=ÿ‹W¶‚cÃåc ½—Ë*[aÁwLg½‡_Y•t«Šp€~å‹ßÑÏA?Ø^.ÂÒ r‹ÔŒòsÌliOÈ6Oéÿÿƒ…G(Óîë£Ôú0P{>ƒRÕ£››÷v?•yºV€jæÑxÊŒö¹A>HýÐ\þ=Lz¹I¨ÅÖ¬dПpßS“Ë•w3Œ=I~w/× '?¶<é1tû TÚÚ7ý%'¹…Ç4ÌÒžªÂ{¤w4ã"sA °›£ý™|ÍÎmºdãÐ8wŒ¹i2~åØQ•Q\ÁïSåùB'{ºY¬Bpý z~Ê=­f×1Ã{ŠØÒ*F÷Uí9êï`þ¦$ríÀ=‹à¸gOÿÝ,§Ý‡Ž‚á¾`×l·ëŸ<½ k\Ýê¯ô|¼n¶è3`ɘo“äÆE0*3F_3¡_'³}P}z¹Ë, Ã3EûÏ?—Ú¿€d©Û‡…*P§ý¶ËÍóqõ{æöóT®éK`éçòùœ~²[«ï˜¸7ãü2·ü÷rRž)‹R”¡-“-Z— PÛ= Ÿ¿ã£é‚Ù"W·)Ê“AºwYÐþ׊•¥&¢¤®?UScH2’("®7A):–Í#*hFn‡„b½hòúG˜‰¼e±%ž^6oö®o¼ >;$3Ôlfmš¹¢÷¶D"ÉXs&ü @ z“™{„6Zï Ñ“óß$ÐkªîeÏÝí%Gü~{I<­ïÇ'Ð$ò_»Ëß¾SqÂò»ZoK­ïŤ"¨~S¸RDÑ.ýT˜ iü ·l’²;æ©ÈÕð’€€›(>¶‹®L˜jbâ~{†xW.ó-ÛÈ’Ò8Ö‚ÞÁ…èˆ×hÄ»E^Ó_/w%Jç>‚·Ž@™ oÂ$n3L¤â‡‚+¹ÖIä]lV ‘ž£ü;­Êƒ|Ü%mkRÅB®S\{þ¦u· J›X<ꇆžC…î9á[Å‚„l3X5ô|qo ÔøÌÎorÁ'”d¢ˆÝU$ úŸ¸$` uø©ç(ÏÅà¯6ì–µâÄb2Û9f®IÏòQw.òbCá mEiy¡ð줄¿ü ú™5W ¿%× 8[d|‰°´XÙšÎdªI®1p9Z‚ãzDy\RtêßÒ:µ!Äãf bNµÙ”çûžñrQ~ßnÛìÝ$Zc†’Ýu(ÈÌ@²ÏN{}Mðˆƒã&JÆžA;ƒlÜqÈ.=¸³ Ÿ”Y3Å„j|;òØ}4»Ü¾¡’,„jæÈšä»­@®¤€‡Ã1‰….8®ƒpšÍüãg°ït,„´Ôë˜zêZ–0‚õâ禥æ““Ûñ<´ ûÝ2µøêÖ`ÕŽ”Ž>ž#,o+³f‹¸i¿“䮨”8wTÿK逤Hkçnvâ*9bLH̃í"«ÄE³¯Ã ‚ Ä”íö‰þ‰ÊÌ‘÷ÓR Z¹Üøÿyï[t ÿ¸7X”v—Ù¡û“Îä¦ÒÜü-Û¨•L–¢áþkæ+ç ÄHÈËØ«ÚqÔ̰dǶq!WUÂY|8Øtžu5¶Ö±4ƒÝÀDaêù¦~¦wšßxbmxļ*á\‡!í§{Ýö8¢^ÛÃÛðL™žpk”(Ã=»#Õ0:»WÎá;€8Ñ'LÁ;[õ¶J¨AÙ¯¾ÿ‹XÞö‹²¬Ã&O-íN-6ðPüã&9ÿþðF].h£;ôƒzäpÏÁ½ù%¶p¥, NÄþ7âÆ/–.cÿº.€“^«ïùuŽíúÒ…Œ- މªÙÉ+XÍ—âøÞåcÑAlœèpÇ)êqvè)Ñ:T‡nFFM-AAÒÀ÷¾þGñ!×öÙ^ Q£ñܽÝi§q‹€i^ØQ#ç×yºH8%óõÈ›"£eù2¬Šbž¸µƒ‘Ò¢äŒSÃ@G~€èÁÄ’€€³ÇŠ.Tø5t-Ö¾¨ãZM9Цê'ÀÄS |Ca€V}…Ù c(È ®˜çTŽçû+ì o†ôþ®ƒ]áù&gU~L“™ ¼¡¼O†×r[Ž&N7›Õ("ÎæqÄâú :¶u-@o®™ö /;%Š6Uô€!Á)R=`ûZÿ1%õêU|…X ÜëþaqÊ}÷ÃüA!B2–ïÕ»úXœ"$?o1_#Â2}óûô;Ý®ÿaÜî1£Nƒï,*ZÊ3¼w\Zvò¬æ,õ×ùbËœùCª×‚åË> ¯Ï˜á½ö›¯<1Ö‰‘ÿJǪz¶´æ¥—vÙÜ^ÜÞçðýÙþýA¢ìÐß]kÎÜ·*ö.Jñr_J«º»}Jay¢yå î ª½_ÏW?ïõ-æ÷VëâáX²£O\í^²yö?«Go©«ö0[Œ z‡hÞ8°3ôËø©úèϼ;š™rqíX¤Øqí¶”+þ¤þ8|…ˆàyóÿm¿|'¦ÌÓ€X6Mxš§Iÿû¥üµ…$Ç&{Ï?YZŽ…ÈðM¯CÙÑ/q>¢?òr©Ï‹#P«?äJä¯r¦q꟧ú’ÜCWó˜ûËV/3ï;RÅN@¯‘ôÜêeÌyá9|¼E3T=¼hò6ñ‹ŸÌ7î8ôLu­MwÄß¶pÎ7ŠÀN{Üì2ú¿OˆvšhPèœè<þ™ Ï!ß‹g/W“Þá…bÛQóê€ä”}ª»½ïÏÃÜ]ü»„.&+)ü—ë”QßÝ Œb¬ ìË$“$FP.Ú…,óƒ4"rHÀ¦^ô¨Úǧ–ùÚíë/ ç´-™iÙkTMB r…•æ×V"‚œlútRn~Ä2%F¹E ’€€õÛ­Qe<Í3A3¥—Í|~%Ïäí+@]d}Ô4ùcüvɧiÿ(%&;­‚ç>Ùþ]×ߨÚ}vñ€Úëj úgi§»®T’}³zF_²ÃÖ!ªÖ/Ç•ìç·1Úhµeð±ÊÇü›—¥ôÐÕãªGá¼MSMu4ÐOøS¨½Oç#PÛ1Kð› B(tNà‚Òaâ,ÞgT£]ra,7˜pdÏ!+)o÷¢œ “§yÿ ׬_Ú¹×Ìrk,Ýèüé‘ÕGX‘^žõŠôWË,æ jI 9ÂŽwœèîé•ÕÿcñÑ ñº´î˜ð’A¢éw³`J`:ýÓª$(0Ãé¸/Y–÷ïçR>[rÆzü•Oã l^Ñ'l®˜@ŨØ*´EPÿ\áv´©b7Ç™V_ŸD‹Ø:öÇÍ XsnaöáyfJ'l{éÓŒ+]½Þ€ìzg(ùQ"ÙÚ)OßÕׯt?J át¿J©©â!#] ¨×0±Én²¿“Û§Èl™¼’5‡tùã’˜±;ËA¨'À± S'î?AÌ‘£cËs™R2†íIëõCÖ`%P |ýK”‰AØíø¢ÈÍ/Wã¶f›ÃÆ«˜ÉxW5nr¯¾6í2†âŠšP‚‘{+YÏX?i‹0ôŠW8êÀiþ©/N-JËDk&†•"Î*: çäð>ºh3^–ý:SíÍbûj—W¾è{Ã5²‡_F®Ã ½<î ­ÅZT¬löürÚæþišžûYOÈqú½ÖZº•—ü´Ù¿ºyu f 2 GjŠÕ8Ì §sÄœ<Ë•eö˜±YuÙq£Ÿ:5¨«9J{*`3—éšÒÐ ‚’ÃkÇ Ía”àòÀ¦Œ³§.TNè¨K9Ï{vì1%2 Ü£—?™ƒ®¿ ¡Ñs6Û`úVD&‡ê¸Çã±ÖO”ÝÜÝ’ÅÄú'‡¶»©a¢²„[6àJ¥b舧®µôâ¹TÈà•¸³»ÑdÔKc£ø(BGþcÂwa³–“†ÂÛÐBi¦‘sƾxŸÈªxc(昈ç,høìMuÕ.3qøLÔsGÂ࡜œ¥9Úî߉y«m†°ãËþ_¢_Uº_G4j^wBçv!¸îŽð¥âÂW*¤[o˰¥6=’€€›`’1yFµA7Ó˜»Äud¶u¸¸)Ô¤êýÄ´aøš4)Zˆóß—TQ8;¹æ=@TL̨×ÀB=i AíÛ(ò^pT –ÍXºï;m¢…RH¡û¦â*Ï êt¥Úœ]á úÉÜþÿÑT'ªùb‘>DŸzµø½ªë‰|Þ5ÙœF%èvÿ/ž•úÒ/jnˆëm’4CŠÐWÊaõf&ñ974¢“åpª3Ápi¬#,ªVÕÀGªg ­XsÍÎTËÏ"“ ,ºl,=@"^‹+­`ÏÒ`ÂiÉþ ]ëá ©5ÊX®KW>|m·¢Íªrð}+µoi 1?™öl¥L¨ÆŸqx—÷zhSdrؼë—fCG²2¬%k_¿v¦p ±‘¿p‰À¯$သ®P©ãH^pkÐòÆûuñ ÆrlæVW„ õ6ž$ƒÌYWø0@ xC 14cã^3` Åâ>6Ž-‘_²³ñÉ Iyw`Nçy^ÆäŽ Ò^v®K˜­¢±dS4¡/£ðñ§¯¾Ê\eûÓÄR,Q0ÈßfIœ¹8†ŠÇXPŠé›Ëµz”×ãŒJe]TveC×]ý§]Ó´øùÍÞÇu]¼ó0žŠ@dXÖ4f.;iĽà¨GTÓ zA =›O%d‡Í¬W⻀h×}¥YcVóêm5Ùm©á:ü?Ò,Y¦ˆZ2=4ž´ƒÙ²wj8r´6©¤©¨,Ô‘$19Ñ # 0à=sÁež;+3û ÿûršLí sò¤Ë–èkM—"Œ!P¨D“ð×­ýÓ¤œZ@Ù0,S¤ãS`Ö>ÐF…‰Vª`Dêç+sû%ý«ÆÁ¥éÚÅ „¬.X¹‡ ó5-ù‚s g‘œmVâð&m ¥"΂yM¨³)Ä'h)êóŽ•ØnGN^RõiŸ¥Lˆêüt°þË׌,é <WWE}I”‚pÓžïUC4ן™° cH¨á~¨ÿžªôà ìr­›±òëƒÜ*Ã˃´õ C+×>ÛpƋԤ²iPUÕÌ=åc§.6ŸªA»ùÉȲ:Ó—Û’€€¸Ô.;šVóRí¬wÇ^%ðÒϱ¢âè¯TöJ†er½`eº¢ÀÅyðÜœ‹e}_õdÄ᳇½1›w>à—6O—±ýÛØ%¹šÀW£\•Ú™!oî|§óÏa8ˆ扫g¿?é_rrÅ™POÒ2 ²nΛ8yR{ ˆ gŒòÀº+FHGÎ?B7ññ*’D¬ùq9‡2)‚×[ªe<´õäqV}lߌçR$À>ƒç8ª63NÁ£DÌôL³Ÿ›MÝ"ͦ*ï4½¿'VÌ\ ªÂ2+Ýì7Yò ŒW?ƒ .©\O¹§ZY/+ÝÙ¨-†Tš„@ >Ð#Ž2$Q‰•,Å2€ÿ€[†þ¢1Ü Û&o‰ "ÃÒp%Ž v«¯Ô= …ËïˆT`¤=BBøuríèLùØpºK›²"žÍÎÅöú"ä <}FIUß9[4ý$sô¸íé3Fánˆ±j«(סYdòÌ*´5}^c;h†?ZûvöW‹#ªZ¿lFpõ ’ }›¹Ÿà+T†#WŸÍi¼³tú ‹~¦`#–žâp…üQ&”.ѻ̕{E§+ðñ!c&n{ (º·E¯90gxïBÑgé™B½ãŸp6§ÛHTÉ^!%ÃY¿øX½™5âöèEYQÆÉA±äMÛ1 ¸~eÚ[«Í±DÜaÁìiÀeœ+‘ïª Y?®]N‰ÿaëçʈޕ5à`ü™Ú»++ˆEɌĜ„ aZN$+¤Mío/ºyÒ9òVª6è$Ïê2ÎÜÔ©~'ƒ<˜@Ïpf÷å]það¹åiÄh“.:ÜÑÏ@+4¹àxÓAžeÅ’G!(½žŠïGÞ€)ÔPwSìëÊë® ÆÞ·ß×A§ÊÛÜa?BÇШ{¿VUmO僗‘ ~õJs[oaEÚËHM–"‘z1}ÈnPÛézm~ À%±àÆWoÒˆ°q´=ǶÚÔ+T*¯†WœhwW±‡`P$dÞR4Á óž,ÖÉ—rI¹þ¦\oùz0­m+’³0 EJ5 ýó„g|·Ø¹ÌÔÃOª ðŸY.Pò±VÚEMhby Ò â¶:»W9Âú¯âØköoïý‰5¥×8ìƒAâégšû}—Ü2»…ýÇéÄIš’€€Þ,èeà$ 1FÏJl° öÚðÖŸ {©¯Jò…«(IÜŽ]¢àÐÆËR ?vÎr˜Œšü E1·€Ðµ…™Ûø½µU“/Ó×@„(X.™ÛǶc^iN²ifû3[í_H°V¤;Áî˜H°äD¤èޱSÙ$Ùèð¬­Èöp¯AݬPÑIÁÂ`™ØÉû‡ƒ·œ*ó½/G€Pqw¾žaÉÚC›•¼³Šg‹8­Ž¢¨ù¹Rkù,„_Ti\بÝßU„ÿlõ:$ å¦ …ð‘FAHvã^\AäÊ¢äS¢íÒÆq$]»¨ÂûÜõóдV%å~ B!$O¥ ȹ\AÀu_šÍ²9Iì+¶“C~Ìüñ#x‚Çgói/á?]ýxå¯|ì‘M‡t¾‰e÷L1(ÿ7Zã3›„;ÎW@ 몎ÙËrœ'˺’ê\Œ¸’R㉋f;±/Ú\•8˜sùêWë#d³‘zEÎI3!a–Ü«gž¶¼ï^ÜÆo´çg±ïØ^öRun{W‘Áè0ÛBŽ¢ËŠbؤ±` œ‡$òè>QZµ¹<ÂM(®»˜®ù†ƒéH€‡w%dU¦€~®µj¥áæŸü'‡‚NŠf|° ]óTs¨×L1Vö²~›­MJ/)†‡áÿñqÌè­TB³p8l³4U”ëÇ¡n:S=HÊé×—øq24î¾*Wípu=ž…cÅmJ–u³ÿä›YÀ_ªP%•ö~„¯g•NÆ1_RËCíaìakq¶]3ÑÚ†€ [¼rÍ~®¨\4CÇŒ{1¨`Tâ´åg¥ýjÕß%Þ9Šû¾µº/ê0䦭Øô;ÚVœFûi­Ë<Ø vuŠÛY69% ¦%ÈZœ©'™cÊÞå\\lÃìêG8ùNâ#Y|¸(žŸÊ(¿ð%ëØ­åÀýgÂwú4ß©W¤Ãà c÷å:ÙPòTÊ ÞovãgÏü©Q¢#`TM•²“ß9 •‰~m¦mÅtÇÀƤƛtýü\0ªE€EîšFŸÀ#³ósBÿ÷‹߯ÚÃ1fB36…»¾‘-5),H–Ûö è˜ ƒÔ’rø½ó6qUsSAÃt5pÀŒ›M†©ÅªîêhU#ñŸJCÈTWùfÑ’€€Û$@æÝ/S#¸(Í$kUk"YÓg-ÁE¢–Ipþ0<¸9þ-<5eÍ'gîÆ3F†?6eõN…ýv^o 6ŒèÚïôüjÞkê{uÉ’ÉÎ žlÆ+C·Â! *Çp§ÃYÙ®°£×óÜ> Tdáq )¨£2AE/k>H~¶ŽH¡`4÷„ÿã(žœÏß7j5M²ûH‹úr3¬e‘)3Ùÿ}óšz, Áظk²Q6ÅÊÆ`®ÈåZwGÂöœ®ñž¢s¯Œ>ivxTÒiƒ™‡<û h•”‚’ŸV­P²ŒE±­”–öÏOÅ 6ÿöóêDX—G3 Aã ‘”ðjä[¦™<5~¸ï2+A3]Ø…1Ó!9Òh /žxqõËWûnŤµe]„!—èÌ²ÐLgÄWuà :`ÝBïÔ“£ÊÁq‰».F·ü'u-î§È ½à-¦‘=C'~žÚ¯´"—ox>Wû§= YYÈØUe±§|€Û *p(J)+§äxH=϶ fååZpCi\¹üª÷è¿ÍemôáQ`v)3dÛoÜûµ?ØŒ[B31[,ƒPµ§qO«`ˆåf@fVíjB?¯ådƒ“͹¶„Qìátƒ¼ëK!O›~:LKIûA#ËšlL×)î½Zƒ).h+:ă 9 ûMPö& s8B¼ÞüUåáI¢ÔnÓ¬¢ócsõÛiªþR¥s ¥ÇõvÁƶXÝ:@þl‰4“¢b;O– Ï óLÇÓ ¦uÒæu„ ŸG¸y°b©'<ô›5‡JcZÑà}P­?2ˆÕÙð©õ|=7Ôfõ@Îà/‘@ú°e›pcØY¤A8Út;geÕõg×iE ÙñVˆq’$ÿlkI8—7 ý#ÇÞjg:¿ó¥€ÃàúJjéÊÿÛûìPÙ·.ó¸[ÒzÕ×Z£À4ôÞ¥'¹ü Åà_¼9 ïÙk_ÍÜ šû ¬¤DAñg¢Ôœ§8Aû¹4ª§ aYî£<º°…%rTÇÕ×mr¤Ëâ«}FY4=HçfÏüÙ¢¨º<øä¢Ð¡)÷ÿ2 Òï kcx]¸y nûó¤Í©ð‡›‡ì‘ò`º47±·K±qøPˆh[p}HêCkŽ­­Ûû|¶H}bù[›{ÇO’¢}*ÎîEsôCÞbŠ$(^Š|ÈE{Ý»~Û ²Ù TAáÆª@åsFs‰ ~1“x)³ÀÙÐðŸ“Vh&zxzß‚¯ßç†:G[ŸsÓé&ïQb!ƒ¨”IJ•îÆ8§¶ª[–šÈ-”‹ðþ'¶ÿ0ýeû³_ÙÇ?ËèÆÀúOë®–Ÿ& n¥ö›»E­?8fà‘4 uø¹¾Üå¸u!l­ñùEãÙ·3 «´˜¸ÄHÃÙY˜YW!Ïeˆ›oA48}0¶Ië€Y°i§úá5Ûpa”ób—C’ĸ‡­ÐÏ[^ŽÚ&o]Ü*؈r^w—I¢­ÂÚ!Z0  …\IÍöòè¶_ÓÓ Ü ²¿:@RfY4‘lgÜMs˜Ò>e}˜¼]î”2úD¿7ól°ä“D’€€©Ntñ7eRyr­ž|MP]<õùñýn[Üwì$å<H kH™Ÿà7gjVÔN€˜j.…¡|¢Oؔˑšs_––ŽG®÷Ë;¸èûÿµ'ŒÀº@9)íá—‰—ÓÑ·È&1ݬ0G{–:Éë¦û€Ä¤à­1¹‡YfÕÚò«ÝCÆL½c2Ü·7J޵KVœ+R’=®Ò/“‰ë&Fe×j‰#F‹ÃÈitë-æ…ZzRZ–à\ ðzAc¸Ìçjr„«˜º;“¢²geTž .ô¾‘À ד2€±³FkÛÞ3cY·‰ŸÁ›ÐÝCF«ò·Çˆ@-*‹û“PD‡…ã—>“cÞS6“LãÓÖ„±™ðɲ›Y6h–…›Š³Ëq/)ªXÊ]H‘5j×Òñµi\LƧÁ…Ä-0©»x¶'ayKQd£[j¦tåÅzI¡ÎwwÜq¯ýWl6Š0±ÄyùeS(Dßx7´Ï+SHÛÔ6 ¸rs¥@+d€Þä­SNÄ™¦¢œ§Ìš\gQ7ÚM~üÓq¨Ý€™¶iJnĽh”ãÜ´Çæè»²I(0$Ä¡[éakÜgÕyQ—áAâEI5¾8ZßíV.£çAcKß:Œk&OëÁj§›z}Ó™sî‰Ds¼m>¸87Õ›0šJU¶ `éGÚƒt-‘úß…·‹wšN4˜‰F ½´µ û£Ã ü3·ùÕéà´rÿbHÊ‘ds;R5gm@ºì²±™éƒ’öÕ"=Æv*ǹޤì!ÍÁ Ȍè²/?ÑòÙ(Pg•’VÖ¬\ ç&²ùu]“¾>Ë­IíJ}Fñn©ŠÆpÎÒ©²_Ù?2µ†#Ñ’€€Ä[-ŒO&J~—ÇBÆ£.«•æÕql=““•*{ÆurZ´Á_ö4êK(„‘Sù^’ºkÁE*N³Ãƒžø4«×’´ ¯̹Ü>ЮTÜV>¥q—Ht¶8š¾)`&=©ÿ©¾Ë5'b¡™H{PЦ«S·Ú°¹jþåÔ¯{5ñf[Ëñ÷€Gû6[¸Ó±­ÑíQ÷A¶ø:‹OÕGåS.#û”ÜÏ hèì:âíîø«!XA&ø.j˜xÄ;ëM Œèt=àá9èßgA¸ÏG7÷Ø4ÍL\k/+ã¿•`3e•Ñ?}v¢U F~9FÃiD½ î(ä$¢³.¢ÒÏ©U?ŽIY*XûnßjÞ/>a¨¯²ZQUjyæ…l[tÊ]£÷Œ6½eU&&,Ï®†ßQL~vëÌ­o¿>͘Ê3Ýó±x×Áîâ/*U{'sZk·þáùËLòŸÂO€­Æ<–ñþ'wFÝ™¢ø¶]òÊ#o"×43D|\êμß}¢qü®hgþ‹¿Ë‰žÅoûÚ‡[DqNöh²ÞsréîW°±#—µtV¹ Òœ\¥k÷¥î“½‘šÉ³ëM%‰0hÅ? ¥-çñ5$m60¨œ¡;¯ 7²ìkÆÂ<ŒnƵÈyá),–ø|Ag/Ù’ÿYßÏv+$8-Ó24±ªƒÑ,»7¡ÕbOBí¹m qïKØY³/z~KÐA¹³§Í¥½ö³; egâ#¡¶jŽÀС¾Tz=ÙÞ»aEid1#¤lw§šÝÐ¥ãøê‚b°¨Îª.cò×J¡Ùôéé,ÛÍAŒ£š|&Œ´âˆ®½5²Ð9Â8ÕèN$‹§Y£nÐZŽ’€€¯‡¼¼‰q½ròšm„¬”3A“ðØ G~øÎxÕàQ{¿Y]PK–£gç†FV[—OoaEºmuƒqƣ̀ԥÎa$‚Í(Ú_6;ÇÂ9„Ø.JOŒr8xíeî*-¡¡Ž¥ð Õß ÙËe{ɨ*×àó !ŒÝŸÿï¿‹… AÌô„P\mà0B#7†01©ab„ªÏ.òUY€y…g˜ÏlŸS­æ&îXŒa¡XV¼ßÑd`ü.ŒàçŽÑñ®8?¤k×Ca?¥)ã ,a±w`Ÿ5 q™oÌQ÷. 2·± öNX$™ŠZ—}Æ6Ýt:éS%Á¹íì|Sã5ó íõ¡c:0j2îYäô£3™ÝTF3<ý|çt)úÍp]•1ȃ̵ï7×;—É‹ýs úFöÂJ^QRš?f<éVü&lηCíF*§ñ¦°Õn଑GÀ´O2Y/§·Óª··V)ÎWè*"øÎÃø\l)oà‘>&T½JÚ':‡4©¯(^'ÿ¡o¹ýæ\½Hoϸ<Þ :ÈAS7áî ]ž¨ïÂϸ!áãy!ûJïpTÕû'—íó¿Ú6“9OÕËQãßÔ õ ï•—³vˆ6§nIÓýé6~q„£•âBÑ-Ñ|¬`Ší'tÞc¢ÊÐËh(ièónƒ'UÐ2j!ŽcÇÓ?ï6ã"̓®ECí·üVC•ˆ¤‘tý(¡âʼ¤y>ÕÁ€øÁÏØ¸çÓÌj/Z÷‘[¢Ñ–o¿ßÚ=Yt§AX;Éè·Züo¡1µµÆøPÓPÈØCHÇzº:8Ÿ›Ý4’O):zÀåÛä!_~C/šaÌÿãMèªóa wö$pÂÑ!w[zœ\£"³3á’ìP÷=“QåÓîSžãZÖY*Òæ÷ƒªè?-ªtv^îÔ'Ùæ;—*ÉËÙÃ_£ c±°Å‚%*á„ã<«_nok†: °ì[ô–’¯áâ‹KŒ ýâò¡ÍÚ\ ŽÛŠ\M¨‡{á÷U®2y–º+Ëw«Úˆ ϧ†žqrÄqôJ+ë§±ÁŒxË<Ä““ZÙÄ©PrI´+¶¿(Šìë½FòØ´3q$X-ü(‡d>%Ï©¶’IÏž|#ªµâØm\2ªÖfTLkÛ/©â˜"’€€Ö>®^g±X´ ÂZ%Le¥„Éiô„!PMe¿Zàñ’F`þ°|*5y]5g$}Óh<ãÖÚ•éÔËäs—!¢8k2ì3íǪ;h~FGš|2z»]™ûƒÜ*Žf? %Éd~…ôß @´+€'sPþÏí·Žš†;‘Qx)ò3CŒÓpŽƒÊDʨwQ8{×;ø¹­¸;¼è3ö_Œ•ô£2¥¶-jLöpš (Ù²>©°:Wm€< ƨF÷‰½¶Þ_X,õ€Õ5 UYn55‰ed?Õd V ¹–~Ý&Û[ï~$ñÕj-ä@äØnMNPªë{øüš %¦z%ï¼úûÎ…Ž9dh£§¹<ËØkj7ù_Ü| kqŽ˜ÜîæRßÐTä Bkq ”6ŽS¤<&Ðë0ÔŠrÌa·›Æ)#ÕjÎnˆàŠMù^†ðt,G–.عÒ,\‚4…‰¸bôÖ¦Žìî© ]Žûoéõ¥òh“>Y4s"çl»éçá{’õS=Ö÷5w¹© ÒÓð+ÝêÅ(²ÃÚ™Ýν¸®wàyç}J®@ zÉøîi-ú“D!›‰ßkyf³)7Í>ÐÅÜœ}¨cÉØ4Yö©×¢RѨáéíFé-ZK²Vc¬UFn2ú«G‚¤þ²Ô¢KùüzhŠh_UɳÜn„µ(|ÓÄ÷/䌽ÐKpÚñ×T±^bŸ7tKt‘»ju®TÝÑJóL7‹=y*HÐîL£êþv>½n_¿)¹ŸâÛx6"¥}2Taµrÿ•®{D€š\û.(HDЇ­ÇU¤Ê R¾`MïqÙÙ;¾B>‰‹˜;îs]m; HY }º|¤¯tšŒ^)ö¬.ZçöO[«~¢ÎäP3ÐÂ08^ g›÷W`C5½²íµéÔb<û‹½6qOèÖ|`â^°^ßXì?ÚùF±ÜV¦£èµLB¸i·ç>­êOYÉ/w#r?Ÿ-ôØÔƒ-q‹ªKýrdñTdÿÔ†f¢ŒÄc3Ø#žUÞ•ì#HÿÔb *W+µµÇû+®Ì%%¶xH{eW"—QrSAÑÅú‚\ûzìqŒ<™{ M”†AŒ{éâ´”~”ïŸAÒ¢,ï7’°#dOÌ9}•}üI¼„h“kÍ%s’€€¹JF)ò«ýœlm•`—ŒDWO½‡®´¿–KB4dЈ%›1ŸGlV¿4°j¯“úѰÈwèô½Ìu!Ëû³M+˜(èö}-à mÎÜû_.³ùµØ\éöŠê7ÛXM_¾D~ɯŸä-ù¹©LÖVû  'êVȈÊg…ˆ¨ºÀÈ*ùõ1²™JÖÎz_ß"€æ²ëӦΗ&¯4îÌ/D5íwüñ«C€ô°Yñí ÔµK'©È -ŽâFÁÃ)muôw¡EÄ1L›AWÍI’„ÁùÌèÇ?8WùóúèÙÞ¤|Uä ´4W²ø4Z lt¥~Uw®WkYf“hè[—· £º Q:34¼]ì³T§÷•7”ß2.†*×ù-kõ§Ý–ô¸ÄÌÔEÏ„jž@]{å8{UŸÄÝM+eÊh¡ ùZ! è, `„¸òxТkÒòbW¸ŠÚR¼èÈI)\è –-BßO2ÖKö’þ<‹ˆ(èÃì%î§ÿ'ÇÀ9häÒCÞÙ1¬›¬æðò·„Åêøé¾Í ÀÌegû×-‚w8GÙ2Íro¶ÀQ¬3³Æ½îU…œ®Ïò :ë0Ó:Û&þÍ-AØl’5ì—ùtMzÏ*öP A¾÷mÔCP(\÷ã²g áÜ-ñ°'Á讇•eiº…í á!š]8'ÕÿÍ+]lhØ‰Û yìÛ›fªtA š‰bî!=Pr{QTd<Îç ERíš¿»øž?«D†Ç,D+;œ½ 4þƒÓu Ï‹º·Ø¿\Á<)c„’׸ûB™iÂx!±Ÿ ððe×oAjo»s$†Ç=ˆóëWé,5×Î<”ôÎp¾ÇÙÖX<Ó¾BÕ|,§¸‹•ç *­oEéZù’raÇáC…™HkZNCõì•DåŽçܩޥ»Ñ9Ý}íú ×g=ç 3Ócàð¨AêÖŽÒÆƒV—EÉ1V²qä<Íkkh’V©I"«q‰Ú·ö&BX,M¿w~pa3ÞÁ¥æ%«ù²i9ùæ•+n Èúõˆ^X÷ò&¶ýf6¡ÞØaScOÔ=„{ÂQDö ‹·½YÁzÒ«Š1«gƒØ§étâö,Ì«ú&»¬É¨¤÷“ µ§hƒ¢¸Lª< s‰k’€€ÖoþQðK-?MìëS¾ºù0Lw–l½+s²½* ïøo!LéJ{Úë½Êc”˜”0”b•?âìlùÃ͈YËæ,)8`-‡2à_ Ýz `°AÝ5ù8¡¢/ ΧX:@ÝCÍLrr¨ö°m¸¨É|Ò *£GFf_QšN3½š?;to7ÎGSI:Î^&`,ÑÒgºÕ^SZ!°:IvŸ”V=æ 4(12`ÂRšXÄÅLÇaÐMÿ‘nýâ˦ƈ>„Ò¶2Gã{ŠîâZô$P>¾(è“–kŒ ­•®Ü=)‚†êQ%µí“*i à û!?=ÖÒ7¿tqÑ UËîø%‘ÇÆs?Wq)a¹­_kuÎ\U½Ûkî£[’ß²ƒ™©– AYj€Åë(ê%pƒ¿N%~Õž94í ´<_Qð°ê•Jv)™y¾t[An ‰PáwIû·'¹géKöpU¿™Oô4T“îZD ‘ýÅ\Ž„ œÁ¦ºë?LÌ›T’^îVÚ£Wl¦ŠÒá×ýaRVïÆ –©­a….w2{öX·ÀÆ"Fbºr÷&>6³/@Ôšï!§ub 0}—äbÀÑW)¤L3}ë9Óh¬X›ìl7 ôØÛ}=¯"ôAz7§lqe»G¦øXʪïÖbï5Hö‹EœéPæWS*¾\#-À=1ÓVnúˆÞ"E´ÔûŠˆ5Ew}gYÞ›u2 ÷ Dh[Ëë˽¯~UwožIÈ)i|€Ã~à×Z¼H^]xð©.œæýZjHÂY“À­~¹™¼püjíë =å•8¯S^iãRQÜœÑÿ/=«"”øUQû|S‹sÁ¥¸û.Zxó$Î>v‘)‘Ó–øÑ¼<ˆ’© R'™dŽXl•-l7›ƒ4çtZ¶Ø…IíèuÛIu%µV­±^ܳ3À"âRáð¼a©& xÍ]‘ÜúOÈ•ê^|c»—zE‹Ÿ‚{ǵkjÂáGf±ÿùÏÞP#»Ž¡ªwÛE±álËC‘ã£z˜s‚ž\4‚cRq²«@‹.~8™ ˜|[;'gÀûð~/(⬄pí@ úÐv$–ÏËœøèÚ+U›â3=h–àX¾=ñäOüg"Ó°TVFS§Æ‡·cô5²…³×Œ'’€€ÉÑt¯•@Ú<›û1+Ñ]˜gÊ5¹ {ÝŠH¤´~°…ÀêS"ì¾Ý\,¥Zóíï5êç’¹‘¶Æ÷j¸&«®¤s¾´Â¹›xnþ…€+Érøoüv=¥œÛIë?P:TuÛGGr€»„„ô¸¾hG ¼­¨šr ñ+%h2*™Avp{ÖýâYÑ1Ò£tµˆ.¬ê¢„ò” VF1O5R$Ê–Pe†½Ä¾l•ÀÀ™üÍ¢útcÊŒïƒ.A™­" k-õrsryQøV,@£âä¸@k½†YÒ‘ðÁ=æm[–Õê{gÖpjµ:¶Ùgoâ# æÒDÐsïª ôU^ÀG¸¿ªo¼…/ O;¾œGx¥ÆTv¥wèÕsÜ1ñ« ý)ÔÃÿµŒ©0%ž ®“D‘s&8Ú¤2ݺIïtÌó9ºA!9§Ÿ€•K JÍYË” ú)Ð5@ùÉÞò h5\û6 TÝ„[ûUíMyÌš’/D·Á‘©¥¾ˆ`{Œ\>ôG$hc 0HðÛÅŠ[•UJ¿Ù)± m„»XY ý‚Ï4WK˜.P2ÜÕa3’Gó„%›…:t1ÖòóX)ÓeF7r_F“e‹ô<ž«­)ß1Ø8-½§s ~ªGº¬—ÔÚ@$¯‰Tk‹­E-û¤þ†UÒ.“ŸšëÙ&áx¦g"a3²VºÀB+ÏZuòJ‘È—2ƒïRûÖøÑ ªÃËð› ûse×ÕJ-K»º’œN×Ã8CÏøÖ5¹§¿oyÁ„š'òPV8Å×aÙì´Oä‰iÖóÀ²§Šd{Ö^‡Ø%Àܬ È‚ŸkQP ^¬ùj$ÿ)S_ËgRˆ+çß^U¡;˜ uX‚6ë-»`]òrn!’»Ô"èj™ÈÞwÆý¸pÇÉ5NÔOðݾ î!¹’€€ÄMéåâѯ\çVµ{Þ¦ÚÊX4ƒäøÒ;¯ï߯¾óðN •„tvoÅš—±  $»Nw¢_é. l˜ô€A´¹L— gMþÓ9à·¨Üål‡U •,{ç£öWp±½ô`èQòw1¤‰:CWöæ ÁÞ”æÿ ¤õÝ–¦>nÊHÓ}Çtñщ¢yÍÅ¿ìU¡BÆèC˜Û„Ç9Æe‚fJcþvp›q³7ÉFg¯¾Q×Uðubõ¬5¾kW›;=äµNxŽ—Í_™ÊÕÓÍi°º}KÉIAýFæ¡H1˜ >SaóÜÔÀ‡§)vRºŸ vÃ+Ù½;Dx]TŒt(² —&‰É Y"prò«KX;ÎÀ¨m`‚ n×LÄS©°·AXÜÎuÞ®ý©QIRo*‘2±˜Š×¿‘¼79OdƒYÒ„ ìiF÷éµl—ÅXËô¶r ×Fˆ¬7Ó…ÉšŽBr:C)›ö¡Ü¤» ·Aö ±æ[ï%G@êç ?{…¹ÿq.||s¾,|B±*Ю7°qBšš¸æÞ…õ¤OáläZnožGéS'´ºVøA[“g€û#Þi&É™Z›:EÏŸSU·ZCÅ©v¿å2Ù‡ÖebNFô8µ^!̼â¬Þì\Ckÿ/mRXkÐÈ™,2‡Qã1£m8—ЧÛ(K‚ß²·®­å„#õ_Ñn›TæÚëíâš{Ž—›î¡
    ÎLŒ@ðë&üE’€€ÐIËÂû#ã¹G¼J+&™—ÏxÚoØ]NÏZÚ  ÜÒ…F» ¥‡ßÝ©/^ºj ¦¼-Ä“„ Pnñn Í´õøÝôµKŽ€† # ša¡pPЃ݃t ^VEAšÛTýöN¢tIkW<M'?à WÖ™lòšœ¬1ĵÇ-Ï+ÍZqN/ªêv»™\ê'bâ–×{N0ô×¶•0&!¤÷; ÛøìÀºŸ\PÊ¿ÓGVÅð)ê;þ¼”÷1@ãŒ÷\aÆ>ÑÀÛ?†1Š{sS:o·?ÊòÀÀI­èüæ°÷õLM ͤãŒ1 x¢òõÊ.[#Ô2QŠüìâÇ+U?‡-Ê~ùŽÞ5/+â| úËas­~¶øHO•.^ÀÐ0‹êœ«f¡Û ^xmÆ"e®Ù@¡ì¸8sÔô¦¨Çëp’šYsÌå-Zg¹E¿[z¡oâ( Ù©D$îímm<÷9‡;èž‹„ ¨wäåo›ï0c^‹’⹫&èò|z$io܆Ye !d°"â0͇0¨ïf–bè1b'ËWôÚf×±±jýÉÍS‹*Ð;cpÁÛîgýs¬ G(˜DJMœ©‰© R¸ž¤æzÅÁu´¾4ŸÞKxš‰Ðnª½¹òR|Ô_5Î(f•qÜyèÔªg-õ€„÷7ò1C<õ¯W RUêcý®Á¤FD¨—åøiBª<3à(ÚÎQ¾é"Àk¨pŒ÷0žK!dPÅÒOŽ»áé$?êqhŠüc\TvÿØÅ°:c:ÁrÓ½‡ù|Ò°˜I€]C@Ðöcf¿äx®Vñ`¤Tž òCÙŽmÀ¼*ƒ#ê2Ã~¹…—×^¼M|¬ÅºŒæ{Dt´îÖÄĸ†¬|êý£]@N-#€¹:ÁÄ~»1œÇ*>;ºx âQè1]¼/tPñ•ã¹ëfʶ,¯bÐôÔÌüP¼ë|}'—OsmjR½3‚€£¢¥‘×smÌ8è9ù½ç–å¿Ã2ÊVcà áÝ`]ïQçTY­ A uBº]=ØâÝÁüp‰Øö1mºâÀT˜³!éËeZ©ùèŠõ¼ù3<ÛcÈG"Øtæá²œ2*{( û Ĺ›¹û®âj¸©Jn½¸ßÁË_VNO{(ˆD"ÁàëN,’€€ÏÍ& NfÒZ:GQ÷*ͧ;F¾6!ýëä1lbg. ¾[òáÞ-P¨6R&»”îsOa%hðÓO„{YÐÀ=¢§Àåó’Þä è„“ÎS NTQYQ”;ÕQuV8Òe7KvÀAÛjè.…NXãx;Á®? ­gZÞa¢ŒçÓ/mxʾZH-Ê9]ùgˆÄC[‰¨$‚ýG5äìµÝŽBšq›¦Œé„oùƒªŸìØ~Þpâ¨ë6_Ðëâ{qžyä ߊŸ‚ßL.nÿÃÙŽ«dÌâ~—„e‘§´wg°>&ëÌÉw;ËïÌ·}£É×mo®°Mˆ‹5ÌT¶‡&…ÕÌd³`ýð¶5ˆÍx$5?š×šgóòì|›I¤ÏÛ4þͰ8™¿wŸ‰@öl-Šf y€é—Þf0aa…N¬·û¿c<ú²Pl·b²³ÏîÃü´ÐØ,Ç8<ýX4!£VëóøÁTþ’®æêËä­Ž ^×k{ÈWš÷±Ãt€AѾ&X°Ä‚cŠMŒ^÷©¡÷[úZì¬Àa½N)Ö›CÙre]í ‡&ÞžOLýöw«QßDevٻɵ¤¯P] 騌$ܘ3cÛÛ'±Eµ+%É:иŸ„™Íi?¢\m_ìßOœuù+urÍ=»bÖ7k½¾ð×úIÜ0ÍP‰Tõ,?F¹ÕQNkÍ[øÕÆšU9ãÔä]À—%Ž”Ò—D¯™ã¢ó†;;ý¸©·i1fàÂ6r–Nä*ƒRl§>H6ËÚû#›  -è/TËoŠš î‘…à”à¯Ö"&Q4Xvýø[#ЯV9Šõ½ šrôûä³Ê"1 L#ÁÓW—Ybªk¥U#ø…Mÿ Á ¿é¶‡ÖÏ*UÚìm϶)@ff„ägªCã~•-^ÛÑ’¾Ev‘ÍP‰[ÙëÝ‚W.wÜ‚Æ%·’Uô2L˜¡g•œzQçè¬9žBˆ* óœêFêcìÁÇiÈÂyÄÕy$&×®YQe1His]d~ùCX(è   ½3ë*2µ"\]Ỿå8¨•ƒnAÞ ˆêÂílªÛ£á‹æÇwЬÐsú•p¢ãVÙÓ¡D×W¨¨¨]É’€€ÕQLSvÏ=â7^[KŸ ."Ãý8{n¾©‹HgzYŒ§5ÌNsÛ3–;\ód›ÀFÑÇô¬I<¨ÔJ‚_ZÉnä*çò™æÓ‚zŒcD¹øé&b y»wïjVcýCò»†Ï5E†ú]³†Ø B^Ó Xåð•ÕAõÓÓ~ji1/óê"p‹Œttœ\âךCò$ºãžhÀ-{&µQ¬¡I±¨øe[—‘0¹Jÿx—^  åžÎ˜=·ÑËæ«Éí›i Y¶ÏÙwMæWÝ‚~÷Mm7WWzGd!ÞMÅx=‡5õþ {Pص(ép}(à­ _ÿ’Ú—Û“ÌhÕõV…ŒAneÝíÈèQRR»½t«H^ÂåýùZCœ®Ùœ©•’‘øéΈÑ÷9M‡(¼‚Ó"O¼…³øèÅ;'÷€Óô}ÑîœòS&LÎxÂÒ‡sk%÷ŸÊ©zËüîmÌ~ó3`*Ü´%fÙÃì[<“¡83Þuá¢Óš ôZ]…FÇ̘£¦xhê•C&žã3ÅÙÊ ‚ÅJ®R`xEòÊ{,Rö¹±g¬‡}=.§ÁK5–¢ú»ï³ÆïšoßôôÚV—+v7Ÿ9DŠ,Š?{»-²é»153sÆë•¸­ñ4µÐAØDßå˜Áí÷”n<ÞŒ>€ó6©iÕ„zЈhRÞšpŸ¯ám–ÀmŠBòy}½P^I@wþ)C~1,/ +uè†z쇒€i¾ ш5ûö1…Ƴ¥¤Í5K ˜[3µº¼3±uSy“!*õðÑ,nrFR+BcpäqŽM™ñå{ˆ0lx;\¯äG´qϘüû‹Åk„h6Õ«=ð®p^™¡:×$¬Ü"sæQVÕîk"ª5Ž ¬§°+Éÿ~½] ÿh–tì¢*1g1vÌ=#º0µ’’€€¶óúV™ü Ѭ$D·–"J?r1/üxõ–M*È}¼µàc…Z Èjƒ§…e hͽáû¸ZÄ‘äÀµ Ži›’=¯åƒ ˜/QWC÷ÒL§tŠÄŠØ"¢1pÒw âzÒi9CfӅ䂸•F¹¸— Œeìƒô¿R½è›6>õâ…ö¦N‰H•Ã’¿öV\°D’(¤èªJγ²™Åÿ¡îc‚ç˜i§]Ó…ÐZƒ3Ôº »+’‘õÔõPÀQzí]W¹›ªÊ,ûZ2t¬]ù¤æMÆÚ£àq…¥Þ9»!C` O×>â;e“,ÅjD(Å ×µµ۔љL†¯ïmÞ¤2ÃÇõ °*ìžÇf>5r4Pz¥÷p)¢ÕWµ%¤ÚtTVÑæ¥#´Ï–k²í÷ YÚǸRðžMöôØ{Rg݃ÚQVÎ[âd­*^VGé*HzAóvê@y<çòׇ†ÅK{ºÃqF¬+Uã’yåõå4‰¹é<‘nÙwÌIPÞ•ùIï° Ý’ü,ψ•×öé¤MÕÝ—èP·”.Ñ»ù‰+³6_”‘Æn:à ©ŸÛŽÑsàHqyÀ­. kú9?Žo´xŸf&¡¸I$›qQeˆu.öìYÅy˸{m|)`ÏH¬{¨þß%LɈNÚê¹mŸ0Ë‚yCiO»¥^M ”*@·äòîË)ꥧZ­Õè<Úä½éÍÌÃuw f¾Á3Ó›J%%ˆÒÀÆ”wÍÈÑãmÓï§§gÓ5{ÿe<©h´-õ&ã4—“ïÚ¡cpª ¦ÐwªaœŽ­eC>Å-~kéøê_·zi¹3©;“œgR˜]qc®îS”³¿¸»þí{ž(WnÚy…¦ÝÛD3‰§–*˃iÓõR'Æ*:‰Iuei‹´û7ÕŠLý‡®Àèí0€®3lvT#w8cSÓRVg´È>Q¿ÛJ·—m^i²ÌQÒNCåÀ &u7L»a^–zç ÔP’€€Ÿ^ÙÕ‰tS‰‡×¥Ø%ú †ò(ØMŸ~£ïàô媴ñõéÊ—áþÂú›Þ[a? 0'a/ÚÐ@Ϲí 2¿e³ú­ðØ* €dæPIÊ¥e—©ëìVI•[Ôêo$¿ï]€%˪#”©×,:ë5/Gõ6rn¤ßGÿ;,i1ªn2¢«z¨©•ïfhÛw>¡šÇÍn™ŒxæÑdh÷M^¾v¦aç1djLñ¦¦&LìüºÖøÔþíД}=)þòÆrzGá²ò >)9û¬û›Õu®ôGèô×ê^’žÝÌÑ~Hay+aäÄ0 Míù§.]"Êõ˜±;<—7<=Ó>Òܺ¶±EÓ¡tÿZ\…J,W`œÎZ9Ê¢‹&”pÿÔ©LÇŸªÜ?¢ÂD2DÕŠ»±ö§5‡¿Òócܦ~åî@Gª¿]$¼ÍAß&?eŠ­$]ÑbКLüçLûáïÑz (S‡s>M˜™Z¥op—õ„h¿éHæ?Ú¹¿9´ T›„qC¨R„±Š[Cí÷tÂì7 .:ã±íèmVþr¹EžZ"õI$(®ûªÝt¸VW‚G2Í;â8#…p£9 Û?8:#qILß0®ß½ÌU&ún¶£Ý¬Å@`ξ6ÏÒ°qŠ|Q̽ Éi åÞX_zAì43:‰‚Zlóœ>))×½ ,²Š ˆl‡ÖåpÁÈÿ"sØÞD`0'ÉÑò«w§öBÌkeëŸ&[œ±E&ÍÈNŒno,ž©”ÇBâ¾?ÔÕkœµùûxüؽy"â…Òƒ#6ÓF<`åÇEäwQo±()àzº’»o¥Åǯ˲êBM|õ å³(³s~]R䀌›'r¡JŒæ>a~ÀÑùmcì"!%xÙ*7A½]ïjˆÀcßfÏèúe I°Ôx èÀ¦E ù È´â>º%Æ®Eóò*ˆÖäÝALÝ‘ˆ˜ðÑ6®ý|Jc<™ ¯FÆ>QBî}÷³%˜(ͺ|J™B(E@4!7¦”™“àRi–¼ûä.ÉRL˜ãÎßBñáÙaþÕ”Ärm¡7hØ,ÝËŒ£rkr¾xP°¼•µG\/«uŽl+ôÙ6rÙ7-ÃR…Êù•%ç4e·Qæ@ªMz®ªŸ—ï¿ÃypEËvÔ4ÜÄ6c¼›Á™­½7òà˜ëªòœÔHvBc¿c#m’Ët»³ U;]…l•3¬<ÓÙÓs†Vöá¡¶]¬^X0vŽ<43dˆb.D¾:ý¥Á÷µ ¥)ŠÖP ï8™YyŸ°¥ºa0è?`úv§Ã ¿cÔ]ÈÎG´nä)£Žñ úæ˜öSG5H£€’³—<Ò¬<ü`Üycê—úåÍv‰¸nH8Ĥٓѯ¬/ ‚ ½¦"õr5feq>0·gÝ=ϯëÌ\`WˆÀ ½}Êè†ÅÞäÊÑÛg…Î^4 Ss_„Ï“ŠÖV½½3û×ݸ ñ§ý»f!òšžÎ€ù€„$|C§ý<÷k¿u+;òEÍŽØGvuÅuÝ…±§IWû ¥&—ª´MZð¡D†ÍÉB9Ôt–â÷ðs T‘ÇÔÞªqDbÚ GR°Œ`ÿ³S žSíóù€o™Ó¯ˆG´a(ëŒ,g¸žl jËô„¾&ö©ðïxÌyµÅ]Ï]43dç˜-ÝÞƒ$™3lͯn¸a=g_‡{ÙàÊ”÷&«½µØÅÀݹԑ$(qF \Ð\ a|gÜBœK‘—²¼#ä€ÏÉRf¹dˆnåwdõSgó¨|Õ5L¶»µ>s–›+Ëy±Ã'7øtsmÍŸ6ÞÜ„¶}Qàþ0zýƒ]Ì$a #¬2(½MÕfà ¾’€€¨D×ÊqŸ[ >Ãö!ŽßÀZšœs„T“+M+‘µ$ä (wëŒ,xj6kßõßÀjÀ;¶g®!gj9Mt“Ø›ïoÒ´H/ë~ÜËs´>Æôjw_& …<ÇÛûôHOd¤)å²!Ü0ôø6@6Õíñr¹>ìÅÓáEZ$•^¤ì ‹,x Á,l7®O7¹fgÍ›"ËÉŒ,¹Vf@›lRf ×ZKÀ2W×U‚ý½Õ ZS.ꮟ9 ØÈÃ*6"‰ª5ê³±“9D oXõ¢ø·2¶ø‡qluÝq”âÁA Íj¡ÝFtoc[ih]åÂ?¢ÂpXð«3 xtÍ…ì 4 R ×øÕœÇVŠù¸v˜V M‹jÂÉüÀî¥3Í$ÖÕ W¨’¥&bN£¡–䯆• £8DtÂÕóäôHÝÐ!íï8è#!ÿ_ Å-S‡~b=ôw‰»Â†ýÃÜ9¦ÞW)´¼ Éò¬×º·P=Ž×, b{®ÊÌÆKlª|sCwœ†åÈ‚ýížD3‹:í š^«˜•kï4ß!¸pe×ÇWü+ŠƒÿVµgr¶LU½›~Þö5`Yb=˜«ãRWŒÛ  @˜È®{àl%0p¢øG‘,ÂÎEÄëÁÂv;À™Gk¸-ÍÅŒY<`¿ /QÂ.´æÈÜ?C*€“*vO »È->GÝÒjÎ9Ä€Šð›|¼ð‰=B ®xöå©Z¥ýùÿç€3Ç´E×i Na ´ö ¿Ÿ#ˆãíê±ö}Y>ˆæzx–„ ͵’€€àÚ@©,)_~hf©[ó`næ¿—,ò É$Ë¬ß ¯-'˸7ûÅšgVŽæ„[KA»—!%2~r 7i쯪d¥…ÁP"cq{ãE:­Ž~»eËåLë­¾º½h‘{³m[¯Ñ*ηN(9¹v÷SX<`œöäÓ¥¬Jå!4'× Æëk¿Æ£¶=@®éµŽ«)ßÝaÂä3 å :º+Ÿu!’NM.×”v뤨J®„ÎÕ±àjúÜ“âkíÜäV«D\MçVDSšëÀL+ОÁ IÌzÃJ¨v|ûÊœ`<äkö¬¿ÅAEVb5hMßÿùˆ<ê‘Vg$P¿©½b’.ˆ¾©ä!Æñòo%ÛP@¯ártÖWM¢×j¿cÛ¦H/ ‚ž¹)A_E‘Odåá¯D ê?·¤µ§M³H$,!*;ÙÐzTœ(ÙiX<¡Š!ñ7Õ¼~Œ±óµˆÈ"Ö›ÀÙT¡½jtÞ!ž]þqBwþ‰oL¼‹ôÑà,¦ðè úÈ"õpÐå%p·Ü­FT ;\Ž›UòˆV§n#û¤t®“h1Ütñ5|¶ª0vþLüàd–°˜iP:‰±£·/Ø×>’2ÖÔ_cºDÑ0«„ÝŸ^& QŽØãQIúW­Cx£nŠìšÜ>I‘ÓAª@#Câõüzù@/4ŽŠ„h ¶â4°¤ ì»kšíXvNÀðùP±G“ Š™yQALø(u@ÊÇTFq7ÎA8 ½mñTzâ£cRiŸ¯LEŸÖ³%39'”Á)=÷Ù ŠA<†á𻃖>?òZsåîô%|wˆZŒzqf¹‚Ìür÷ŸMÅïëHQÂmÎ!üK‚„8áëó¦|Jz±Úàž|ÔêY9¶µ2?‰CFoÁ¥‡Æ)A´*ÌX\ñ¡\L«µÑ³ÿýó­Ù§|á·ÂðOˆðÙ°—CÎ!ú,³rÂâ´G3¶ç(ZÚ¢TJp‹à%Ü;^¸‡3 KœG,ÚI1Ø`Àÿ2µˆ‰iHS¬ÿi˜vVmNé’iˆ³VÈ„Pä«‚ZçQ±b® ¹õ’³:‹iñSõ-\Æv³JØ%ãÕUX•Éôço$9 q>ök¾Ö²9;‚¾¹5 ABˆ—êo–+|Z™–’€€¯e‡×­%ƒ¿NtÁ‡8f 5yÍ{€óa~!Ibê$ÏH—'O‘Ø»=ˆÅ²7᫪|‹…ya+®Ÿª@·9 Ë4‚¤9íÌžà½ïÓê+ D‘0W=8[íÇìĪDóØNAÃ!vÀ·~Ž‚™«óXqI0UãÅ¡>žMŽ0N¬â?ËØ'÷WW~9«ÚŒ•Tlïc@м_=Œx,B{ËóµÈç¹7Dn2¡u-"àÕYmÇë$E ] hNÿ¶²TUžåNjÑMÒ…¢‡\¶˜ê`|…jpLBÉ-[ïäªWǯé/\!ý™¡QVDKQ©tÛ…ñÙy×ýý«q›W-ü*¬Èß „<#`dÝm·w=~:!Z¶‹A®tz'T¤‡™`­Nå¿ÆÄ“î¦L ’Êo¼RrdÆ°Þ V$Ó¨)ŽB kÀ`v@úDŸ¤5qTcõüæˆY¼½iæho8F::⯚Ÿ~ç²¼~xº»šÁ·Úƒß+µªƒ/Ó£ä³)ŽDW´Öƒ^™BïÔŠÎLéâz ›¬ÿ$øÊˆÏîüi’I]q •…ôbà÷b/Û0¡vËÞâ¾îoÖ°ô×bô6i…\îg•GñÁ‹^CTP¼€ïQ1Ý%Ïç@¢ÿåO½/gRsf~AÃ?c£‰ß©¹tGÄM¯ˆÍeLàþ³¸lƦÍ—_呞<¥aô¯W ¼™“]%;u™J B}*·jPžþ¿³×È‚ðžÛ„!*bˆÓ1áÒàr×nä9™­Ð=ª[Ÿ! Ûð"F.Ðæ„tæÞåßZ^ª§É=”¤Xv芾ŽÌ$Eù¢ q¼„ÒO@¹fP`Ñ2Ÿˆs‚tÆWH­dP ƒ}<WH:+-ŸÎèE"Y€ª”§~F`ÞLËÝQ§Šóþ|—Dàž{×W'ön‘‰Ì ªOìÈ»{º®ú}hPçíÔ×=„®¹mÓ¹Ú'°­™»š!¸§ï|ª)Ui£M¸mß{±Ý¡¯Q%}ڼȱÜ}²YÞn®=‰¸ D¡9¼r €N!•ÒØ „ŸŸórÜ€÷ìªs·Z‰Í;aÁp9×±©ŽK…¨°ÈðÄ3 ÊI.ˆÊ ÌB?=ÜNǧÓ·}’#Ó’€€«ëûŒŠH”1K6ß@@ ÐX]­¸`Nà¡è¿3×Ô”€É]Å}°äúʤ çFöº$TùßYa`ê Cÿô›Ù£CV2»½¶w튄tûõKýTàÍž=¦«²¾,Ðì¿Ü§®<<÷[°û}*°¶Û ŽèŽ×ºÀr¸ZÌŸP›ní]Ú¾ø›µˆÉ«¤ªÅllÂQÔ\Ð`¼ô`GË˪u°nĦìÂÌ®{»«qW“3¦Ö¶Ð*Òª“÷y —ƒx¦JùÉRǘ¦SÌÊ4qº$ÕQC#DÐ_›þó€$ûWÅóuîòºˆç©ïÌIIY•iÜÌù–ªá<^—Ó’ò¨„ ž'ñ°:Kxá™Èšµ¦ÝÈ–§ ’@HÂ"ý 2ã&ª@ìhÜçõm9²`ÜT£_ß›‚¤âŠ/ÐFv}£CôX°ÿ#-ªÃÖ²¸™;‡)@1£M ú5ú“)vçÕÔC0Q\âÄ©µ¶Ë¦ÚÜémþ=“¢îxhW$k“hNÃD; ¼wùi!nP|0‹/‹ dBƒGØØ!g¹êÝHµ¤7C7À’dEw_o¯“ƒ2w`z^2a›ô8Ëg È/èÜÕ¢')àŒ : cò½®‚÷í±ÉÊ ÎŒô=é:ïìÿpè#„М Ÿå| 3VƒT ©ÁáîjÑ ËÜÁæmiA8}=pš÷¨Mú¾H:{,¥Ó@TVùŽï„ÃJ‘œêËžà fb ²qô}Uѱ ­GÉ(z ÷"@|‚ƒë?s¾@–Ø6ĵº›ÛkÔågêÇ¿’³³ΧÈuªî‰:Z·ô ÚX‘ȵH¹W‰ÕÂÍoиi{«>St±ó·MÈþ‘¾ö‘\c<–Š â=¡bc_-«:ãŒ;¼È¯ËGÇtm®} ðü@fZJòºdq¥ÊÓ×QΪ\°_]Dɽð\ÅÅn',ä»&[Qv± óvÏ„LÕZ‰PÅßÜgV Çòù×áªb,ô/ªl°f¦Ã{Î;­EßÊkv ÒèE ÔEå1Uµ È ý±Ø-uÃqaÞdžyÈ ¬!Ô­–ÃT˘*üJú¥`Ä WkƼݬUlGÓ›Üë^rðΆÝX]>Tê“Aþ-¹˜{Ò2á]¶{‡ï Yrô’€€Ì˜¼â&Ý z¬!þ£„Y5ûQ~m‹Ä¸ÕÆ>&¨?&| b¬š0.qì4/Dº×>ì^Ž®ñ½Rm÷è!y(k3Â;gYŒ‚W«ÒÈÏ—ÿ‚üoÖƒµz䆒¨'ßT>CÕ»Gúƒ«Šh0Ó¶)]9õN··ÔêbÍV¼žÊ§‰^m– ÈNÏWº÷n)Ô|™Œ8•¢tŒCqCJ…ܘ‚®lšÆ{É낇u^ÚPÍûqæѲ"ñ¿n¤¢ò¡`µ÷&%iÙK€«Tp¦õ­’|æqAßů:µòbš¶Mpxf¤­Ø½—ÝZ&ÌóuBK¦1æ™eæwùiçVî· ;Hd6Æá§—Ÿ&» Ê FغƒŒ¤±›|šîœÀªô­™½»#…±J©d,VfY:úŸAÛ×ÔñOÛùïtòÙ&šãT–«/ä^êi©ã  J“ìU€DïP7à‰Q¶^P2ê–ÅÓ¡ÖԉĻ´€?“$1sü?CÔ¶žÉ Iljª%mšVLÌ…æ²Ô9ê@…Û¬1Úà cÝ<–ÌøVKÁe…™X$>_©…òyrrg¢Z¨OµÌÇ’>°¾«‚œpPt£55µÑŒøÿRŠŒ÷iÖœÑü-e"×è„:×'V ˜júG¨z‚1茗“…ðˆãÞ¬¾j4+9sœQu»¡æñ!€¯R­ß…šhYe•T–Æ5a×ÿ&õ}4]4mX!¤è'°4‡hM-¼Ç—…QKÿä#œbþR0bÑåR#³hå¡>‹ì¢JŠ%æÔj F³¬\­3á:ˆKC0¬Û™Žò ¼p!‹E¶EfhST„~¢$¦sHÞŸð†r!kÞçu‘RkëвÐùy>t+kÓ²D‚è–“o_¬f$bOÇO{½ P\×ö±}9Æõ«'¡mR v ×áŸ-!çl wÌ6|…þ2r“Þ¡<¾æ,‰‚ž¥ÞZþ¾ÀAî]ç–wû8ÃÑWŠô´•½€†ËOóüœ ^w.Ì}%˜†t5³—Ñ:C!Q‡)ÓAV” ˜sXÓ™È)|”$[Û+íF˜»Ÿ‰[©< Šfå°SA04Eâç÷œO]Œötýz…ì{D{¡³œ¿^l©’€€º ’‡/ õ™ çð§¾ Æ磌Ã3 çδ{bülXÿDú@…{m$.F´›ð¾ q%5h¸Æ¾£R6äO¨K3ƒ_˜ªÙÇ]“× 3ߟ>[Ójò#/ಖ¢®ÀÈx¸z‰eèr6¡m`ŸR_. ”ëç–Ô(ðþ­©öô#ýgölš¹Æk †¿ V÷¿*°ÃN\;Å•y¯ÎÚÂ;!y§Ò‡\•¿ÂöKã5̵褲èKŒOâà¥NÒ”~î­Nížø‘¡õèÈïÊ$8lY=RhäÔkû…ÄíÁ.ט#Ö .ÀVÊgÏžÐÈZ_Vg¦ýë8u™®Á®íE¤ù¢[%0ñ0‘hxnñ¡€7S7»,Ú«7‰^æWVŸÛ%ΩIÙÞ˜Vþ`H¸ ¬¨p @‰­u(c8è \(H­oá'ÿ‘|åS“êÏ¡mlMfIÚÀ' «„‘h\u'ŽrEŸùHpÉ{è_´†¼ |¬!}9…Â|g`3f¥@‡‡1,B¯Y&¡ŒJã©EÎ*ï«”=ÕÂë·¸GòZȤ‹§Í‚ôûÆJÖ÷D¦xúðY·2/!M'»Wkng}aVÀè›.9ª³ÙÒJ©µÀºß%‡ËQ.§8={NòuP¡[ÈKw¶€ªHý¶ûMR›:¨pkþÇž„PåòQ= —`Ä饢w}]&áIÄ»ýîõÖÙÙ† †ÎȘº„¥w)~n®:¤?V™cJ5Dö–(íSÂ|°u†"(èú€ùõÙ6bd!u ¡<3}¹_O³Ì÷b0{!vÃÎâÌ_Þäìºh‡+‰£mãpµ=¼m²N¼¹·ROoÑy•}üÚÓTè}oŒaS=‡ÃeõŽmð…SÀìô ë·æ${gŒZˆJÁÏG²uüÊÀS¼óe¸Ýš·£ü oIy ”VæFdå’€€ÂsñQ=£Ï¹ÔÈý¤É5ô"áõ!ŠkÓwØÄ]ÆY‚q‰ÄAˆL*ò7°áëœÜw•l ÍF÷I±”™ôÏ´ ÿÒô0Íû›ÔYÔ‹ý.‡SË#úÕíSØÄ¯ÈãǼî¾5‚HÂ"ñGÛ¹D’¯"Ã(Ñ8uuöØ„¨ŽóÛE¼X1Ñ%¶àýCSç~±ðÆ…,âcôv¿`öøwaÒü¡ÜõIMõ¹ìî•zcŠ›ÌȦupZ¿ÕÖx†6§§ 泑÷¾ßÉòS“ÖÙ~ WζR5^@,fýcY3UàBŒÃl2…Ì9ÁEóÖs 6%ŒúÄ(ì<1?Ž|±öC|¬M„nËF¾®)ñ8X‚ŽÜ„ÀC^f®°$Tÿ-‹r¤Õp™‡Ç°¦–q €G4ï?¼ÇK˜Ž¶˜1ê_‡“åØüH_H6»{¶XI•í3VW“*_ž·±Üâü¶Àjëˆ:EÛ¿8/Ù‹k•)Y±ÕymÂ2øD¬Ê߃‘²j„Ç[S³r™‚Uø›î¤Ó×™NÄÿZ|ÊÀêñ QÕ­í{µM\lh*4*„jþžºw õO‚Ú6<b“‰.5Ç«W{Ôcßƨ\é’À¯Ñ]<È·tÖ-æC-´¹Ð'./ô¬+ËiBÖçCêÆiŽÓçÑé LÍ‘O{ÿ‹ÛáNk¶Óô¸@~: W‰iôl¨ÈöSó«õñ„TÅÁ¤r°¡æ7®CÇ…È`eæ®2Ђñ` Q ý­ôÖ7x6­EôXRµô à&˜þ–Yf3‹lÛÿ|ñrÚwÈî;k>òþ‡räµJª_Õ™¦ahešÒe<-šÅËhB7 ÕÀQ¶½Y"i7oÖ®½q2W”uÑ ù$þ—å©•<á%;˰#µ÷€à‘Øóe}ê|rç‘Þ`½ôdTßhdàf´éŸäÖBÄïk\~óÖD;ÏvE¡,_”çš‘CIi8#:Y³ÓúÃoN•¾&úì(€¦{ôÕkë ˜„N…Q3D Å*=7¾àIh†Ð:gÓ=O„uebk°QV4‚ø}ÜÀ›2;_9 k;‰P¸AÁ ÅaCqi $"ßÓpIÊ w ãV¤Õ”ì÷æwJŸˆ¨w•_eHŠ’~Nu\¥Z†«‘–Í’€€³ëš£žætƒ]ìÑW4JÚN¾fŸ ‘w£.%X,K_&ݺeRzYõ^ƒá/Ó`GQ/OfÁtn—và«1¿õ¸[LGØÒ̧&vjmãÍГ·XXŒ3-»m[ã"¯|ÃTkñ¦W—þ(4ÀÊMs1 5LÏ7Ò[ú¥ÿ­{ì ©ôQŠ^!6p§ýÉ u¥ÀÙ¼÷¬§¦.PhÚbã;_‹Q3Ì;¡½q£§…Ô²"/°X¦×ˆ šWƒ‹œ‰ŽñȽÚÈÎö[ça)…º‹™¬ËPUSpšCCu<÷S)ò”ÿéοB‚ÛS . 0:›.{Æé« t]ÃCè,‡îG «êЉG¢3ðñQ„ GŒï71–ø¤_A#>×!®J yŒ6¶_½`†Ý-¹Yw«.MJœœ‹T7tié¹—†rs^õ`pŸ„ùL¶FŸð}Ï`¨Tv•ÂÑW Œt½]&ÿœŸE”d_\—×ÐÌyôóOÜÞëYŠ ƽÃ#¥¼XÑš„“ÊC¶`¯g Ùí Ñc‹ZÄcU~ì<©1ÄDš8žyªl,H˜49Á`}¾†þŒ( GÂô5iv¢Ÿ;Ñ/|ÔNj¸)}æ„ÿa´œó)rkNºË\éŘY"sÕáö¨b‚ó‚‘Ù:Õ´M÷ƶvöþ’ú)òñGÈW„ÒlWà¾afz>•熣¾a¦Co"&¿D¤¼äâ‘öÝ µË­ÀÈÐCÛšS$´ðsõù»¦Ín\]× ³¾ »ëëAe6s ä7Ú1Rd]áˆ9OÐbjïÐu¼”|„”?Þ)Ô„«2•ÐÁ@^Ë ×P¸ãà[B‰ê[FdvF˶±Q–ð›îXÇiZï)>[©ÈÓ{*¤îË}˜{p¸å˜ÔÂèVöÎ[ÿìMÓfq¾ë¡6“ú–ŠZ[šPf$ó#~‚°gëŸtãσ…ž{ùØIke€ÐÙ}{/]‚ ƒÜXìõ¿ßÅšø%¹Mã^ÿp{ÎÒ èÞBøçóbŽ-tîÝ(×€‰ûTÌA?-Ç ú"ö¥Vy“Þ¾æM¸ÚÔŠ';Ñx°Â×b"P¦êøÙt?™Yw$Wÿ@ZÂteé˜ú€@äצ˜û:«•&ê‡Ý éJô]’€€«RB ñâ­Üøõíûûú.ªrš’g…X‹ŸÙŸãbážù³Ìvqä[©|ÒÒÉŽðkŒˆ#ÞÞ[R­ãÓhj­+̸†JÑAË0÷^QŒ<¯sYüÖRbî”0™"½aMJ«»´ÿø{cߺ^¿†Ç]¤× ­É‘5ö½  øIw„8AùùzT°ßÝKì\þ'¯ï7ˆtԙͮÛÊ>Qk9ÙR¹µOÖv/·gyS}Ò#Fßñ&‹T¶ý\š¬¿ðå}sµt§² Å~QUøž>²à4°Öj˯´(&<‚Ë#øcôÙWv“]<$ÃS;a§Ý1x“=©N_OÒ×Í7¤Ø³Ø ÎÇ¡8­¹ÛE¸º‡šªþ›³+šwz× XùøVÌ¡B™ìIµ4p*\D¸à¥¦* ‰Ïy;¨ØôPòbµ ú¸[tàhøó‰çØ ŸõN»£”†W,îìÏà¶Ú²Í^[ºìËDE*{ªÌbYËÏz ä'Q„œË¿-1â-[ÒÓíÊ)±zrFm¢”nåˆ8ÖŸzd…ç¦|Ô¤˜§ª2õYyb]1wàÌDiÛíTféÀqôô19~š÷£;ÌGSU-gòØÃ:Ì”74EKä‹Ç=b.ËÓ©¶!‘~/ʤiµUAË~:Öjt»ˆcej*éïDÉ‘³±ÂGþ vº’ïnó+ÀWÜÒí_¯¬ïß¶>ìûèý¡¯>¸úmŸpW»äuƒ`-È ¨\éCwª9{:`~E‚‚cSœ¨d×e{B¡@pí:> f«,š×üg‰o>/šP«Ã¶» oK؎̳,g(›¼°Ü­qÅc àí~ÎìZͨÒà)3Èr.Ù©²Œ:©FRŒ2^ŠÝBbe˜˜„ [¤ÖMm nD’€€³xô¶Aß¡ÙþêÉÏúw‹s>ó¡ýhCܦ2õ¬E:´©Õ–“[Ç…)ŠéäˆH_ã³rßE¹‹ÿþÀ×R5ÿ'È|÷QÂÑïIÍ+…Ïèo¤ãåý­E"._="^OÝcÚã.KÒ%WTÿ¨ÄþÈø¾‰¬ ùÚˆ)élÛme°¯4Ø‘ìQRè/zõvC1 §€`Ø[*+A^l@†}^Ôçùb~É€ë«K2˜êöÞQ÷%‚=—CÔï0Ý£'?“›Ëùöžï–¿qu\…œ&þShm5 Õî+²mÊ)¶f@"€õˆk¶!“!‹d4eÓËû¶ÄôÒ°{eˆPÀÉ^8šþ‘©ª¾ûùw7OH }êÃù·‡Â³4%´Ñ ãD{óß󎛢s˜*«÷ÿž|¤xúðx¼#)^„ƒÚã¬_@Óë‘ löÍúë_êᤱ¾Îîª;N¤u(åì[¨§Ön#ØýÜ4<á£þà6 5Eb:N%â¬o@ñ3'¥¨×hñÑ k7ýS2}!}ÂvxöË÷1HÓrù[Ž“ :žØ—fq` ¹­#iþéB,Å¢Ÿ3‘q5ÜÓî/+¼ tKÚ@ú\”3Ç9è÷ÖÈÈ,I†©C!}¸ÿ2Ÿb½ köÎÃI³ÞjWà0y°?¶à휼KmVŠ[cÎ4Û «ò¯S0¤”ìTÄ5¹Q¡­úûóÝUK½ðL¿3¡Ú‡Ùá8Ô#Õ,y‘x.'n£~š$Ȧ0¬#éÍÎo¯Ã= ¾kK"}}Ù\–AäЈjµ>HœâríÜ›•Éq‘ÖzÐ&ž! ¦å¢UD{>”âÂ}Ò%-‚õÉ©ÉC ¼¤)3Ä2ÀÕ ƒ$GŠ¿£ª2‘šø…5&Ïc²j3ÛÕíÓ„é#RÏ\§Y¨8‰ Å,~4*Ú+¶Ê—ËR±Ð å±C™N|ì7î°µ¼Öˆ"5fçÅÿÿã3½;g toO*Ä ÜÈÖº7*07ɼ€ÔC…†ç%¢r«ÄR?Hsh¬h4N¯„yÈP,Ê&W<è»W0fFñH3î-fàr?œ@¦+oÑ'v&w×Z"v«Ü/‡åSÞ20{í¨ìOTc€‰ð™¨Î#;Be+¨¾:×™@ ;‰ ?–å{S¼²H¸Ã”¹Ñ!RŸŽÑeÒÃÖþN/Ó\‡hÙ3vp‡9»Ÿ!Î e±)hÎÇ[Ói :¡ +²Ñ€¯M¸Iv[ͳþè-à,5µžÏ´Ã¾ð¾8k6i•ô\SÈ«SÀÇÎ5$¾± ñJ£ñ†&ÍåF€ô¥âL•Æä‰HÅL‡j¹žQœÅc˜·Åwã øÊÞG(ËóÒxxã^~é5èRžr\ýЂ®H×ree!HÍt°ø¿°ôîOAóvGy¢»àf‰€GM‡¢GÄ~&Øš%ªœFI’Éõ7»JÏ«¼0Mß®¹uÿ’š¢´|‘/¬œQw¯EªÔ—\™¤¡øæÚí–Ij×;›$æ$HV…*ÇÝnÓýDtu¢Š”¤hÅ'­òW½ë½ñá<€‡.½°hqd[¾ìÊO´’` : Jd£aÍ-×ühÉ7‹Çt(^,—hŸëmÛNŽæFEÐ÷ÚŒSî|ìo5•Ž8c÷þÌu. g§sþ"Î|åæ]22¼¸Ræn2ÛÊ« p–>o¤RIÞ¬•š-§…xkì„SË#¦–,:Çù>ћԮ¿p[¹Ña}U÷M´J3fàýÑߤs¿•‡÷5ŸWÊÂùü`A£RÆV›”¥)—؉ —½ÈiŒ«$JcÆ•E§ñƒûT¾jÒ^ª¢7bÿÃó‡’ù¹½*¨ýÝߟ ä1Qý3•Y}öE»ï¯70kr]›—* ìÚ$Øo¬–ðÃpÎ÷€uÊNw¢¦Ü¦­6‰”Ø€QÿKæ‚“©|•5¢×ò6s:o†{>€î»jUß[É<΂û¬{üˆµÇOݳïyÉÙ,@w’€€½3‘³\ßLTÑr‹}ò;¥Õމ+08cΦ¥ãzë ¡P—RÇÏh™#ÐapœùÄŒíÜHFsÓн«!qXW_솠Túo]Ǻ-–WŸ2Újoíí$áJZ§Ž@$ê;IÂhå—  $:{™0êGš …•Ÿç}d m'ëyÊOòáÈä©êÔ€üù:…xø ^jHzܘOc2”qóú‘Þ¬D¼¨ .±cŽgæà®½“„ÓÓ5®ÓØiÐLn˼F*)úïÞb'ùLv1 U{™•2Uoe=Ã}ït2徫Œ:ôw^ÕáΫ;·s ­•=WéQP6Ø©=‡ÃÃ8~0Ã…¡\þÃâÒ?Ië·ÇE¢´Ý4$Í%ãè{v¶%ÊÆ%þ\¼PÝÑá"„ƒà~6· Ò_íN.fPÜËîòvTKbá_ ³˜Ý4&¸Ù㟛çòN¯6tIà`–} Æ®~7Ó1 ½Wd¹:·Ëùf¤d\C¹—ógèˆ|÷ž8ÓÔhÛ™-w#A Üƒ<Û9xiÚì÷'BzÎ u)è|îü20žc1©Ö슗Ó%È7zX!XhQ¦‘d *K7ýK×@ÖUW²’p=Lñ™+]ù4O|@¹11Ÿû(S¸-YÊ”‘½8ÇÁÄ;Œâ‹j Êg*L‚öŽ’Ö™Ð>(NØ\†E^°üDXŸÕÖ±NV…ŽRD®ö,Ä`!‰@ƒn¡/Úyë$nè‚gjª.L½Ü[•COUBþ}½I£ù.=pe!áZ!VƒV6èܯÿè¸ë=; ž Ð RQÅî, ìFºãu×y° iíÂDœ«ù~ÉŸ/’ÑUz ûœr=Ñ6——n#;j¥UhãŒË-¶æø3a+[£obGÒ¨…½ÄÃøž–äa þÁÆ,Õ@¦›6 –&ÎaïvÓø·bQ*ãüà5ÿ Ÿh„¢µš(Ÿ×ˆ3š5³’Ú ¨"o_»4lej#Ô²¿-ò¡ý¨äbcшOâšø™á 4_©˜óæö¦¤Ó`ùÞØ¬m¶³á7öf‡êt †Rt:À¶ˆ›C‰aá+äž=eoI ÅjqÞ¯b3ýÒzzÛªt:F?æ*žÌ#[Ž] Ñ:Åœ’€€¦†­/HÕY¬::˜êA. d!£f©9Îø¢î-Õ(L[—¢$“+Ôj8™Ï ££ãÊœŒ§l—÷WÐMš”/ €Rc¹ÎGõ}@ëa4uâÇÉlJ¬ï.FW½Gð“=h$Ý…-‰fA-2ÈôVÖPEŒ÷Îÿ épè3rl»Õ\:}ØÊ‰}~g€Ýr€¾¬Ñ#Ú„„lîÑîôã…I'ÅÈ냋ý¹£#‰ªUNS-’Éc$F¾N ‘„H¼+ïãbX_,ËÎ+j܆Êì@?*oJ¹î9‰y ¤Êt«‡h½²RÐPêüò 2Û=€ÙÙ¤lŒŸWá"ÚÃÖ=£´âvÁÍ,A’Î1Jsd"}ÓÓInŒ!¬®*Ò¢î£y`™{†‹*N„«Ëç ógO¢m]u.0 2Ÿ?Z Ø„ q6êp>µÇ*нïW‹¾ðí”WƒR9 ÚÂÇ¢5¾òEt VLƒŠªÁ[ÂÃæâZQ–ÿ­¹Å “8ãÇä²^aú“¸c‹,t@ÉŒØwš9%:F»Ο©è”ößë9þ8DG!>R»´œÕÑT /µÄ»¼¬íþ0¡½¸Z@Á—nƒÃ–ùRAÍ5מaÛù’VshãA¶¥.²ê3Eb¨ÿ AŠUÁ¯Ñ`2@ €·€ø3ó×èUýÁ]÷‹þkÄ wS,ÏuÙùÝ×pÜmuç0’ª,ûw~+vŒfГ'­D&#"!Z¶Å>/JXéBª¨eä ¶–*õÍ›sáìå¿ «Ð|n¹K!†âÁNÞÖž•?Ky®ÙÂË?žL—‰ÝÎ’€€Öo†­êÀíÃñŸ+tÏÚá?—¾x`GâL•m9DW~"KâçK Kž·!Dßt2Èl2„žÞîÝ}#Þ=TæÚ ,é•ö§7€]ß¼ÿîòŒX8»M¯ ®†W¨ 1¨ýö=å¥],cžŒÀ•7aôŒIÁ&u9ÝåÍ#•ÿÑeé%Ž%Û¾øü-`T0 ³Cˆ…iŒj÷΢ ~¤W+#ŽÐǬéÈ$;ðÏäPÏ;þ©°¬—Ä\×f?,ëŶZ5hÛBtÓÞ^sî’,M¾™_Ê G/u§àkqÝ¿r£ÿ;ÿ˜P–ÌՈωZ‡.åÐ.–/\‹j€;æ^4:9–£al·â’œ÷öd`ô”€gõ4vôRnVGRÏäÏ­|ɨY~jÊŠñK“õ¾ÞŸÛûŸ9f÷ñíÎúYA7/kàšÉBΞÀZÒTdÆEÙÉ'¬é;ü†“г$2Ö¦]˜´‘¥±bÛÕ'×Îkv±'ß^OßÓ¤_å GZÌ/yÍFÐJ¢Õ¿É…ÛÄu,¶^bóÑ}õS«úeШŠí'þÃì׿•Ö¼eOm)yȨº"ÅvÆ™1_®S‚eɬB|î `†ÉþP)lùŽÎ!ìÿ´¦NøAdu»³í&:†ÖMÀí“‘js[“Af“s$[tœKi†’W»£WŽ9yRñ#ѧ,ˆ?GØþ¬ ¬4ŒSrqN}!í ÙÚèLÔMDÇ„=6X”ÒÒÏ&ÃŒÿæïß@I4ƒ]íýÀI'Ö1¤…@ŸÞSJÚ¨ãK"/'jÒVTª%O¢œÀÊÈ$î ¢‡Cv;ѽÈ/"0åW:‹TÓý­;àeà…œ4P™žŒ¾„æÀ¤»àœbòF<“eܮnj™ì#ûÁ×ÛœT—¶=Ëþ”pbxš³ýÙè,²©Tþ€€ß8ÀæðQdæ)áB$“ð ª—i$(-Š>åßÈ é€fšŠÖ ¼ #Y—Ù{ò>Îòi~yˆ§Þš15Xp¶Y<ät´›´¢’L°(Oò0Cmã0ðè”õ,È-æÏ´uc•@Ç‚ÿj—Ò•@ŠgBuÆÌÀFb×X€ÀŒ@zé§XkŽ„ëýÉ÷ Br² ¥7'}ÌMë”ÀTWÙ·`eXVæ  ˜prdÔÍ´ÒÆ);sæQÉÈ}]šã:°®öú.š‹€—¤?¿5ü”`ÿ¢…›si«Uµ“;ÜÚk^î¡^w|N!µ:J˜—k}ŒÁ7H•.¬vѽ]ãbÏæ}'§_ØpÎWª¬)´qô¸¤öïÀ>K¤L4&q†Dõ-*xÑ@ù–{–†3 {•À EyÏ•$Æ(ATEµ!ȃ¢€:?Oˆ†ðT¯‡²±R]U,WƒÐn5ÆO5• ,·cÞg{ŽŸ>Uô»Cr„V£;ѧüÒ ð@Ÿ\ÙhrïÅ&XKÔORdû.Ht?0Í“ïš4ÜÚSö0 í$\;-ØN8F7sY;«ß.¦#ÒŠàþÊ< `7 /wJæ9»¥P#7åAìˆú¯ºªwùÄï-—õ&T‡«Îy½ë˜@©þ0â»~¹[ #û)jݺå´f¶ë˜žê3¸?jòßw%{9£g9ýð¼=Ý1Ò¼6<¡vi 7}–q‚ &qy¹‘ë4üœhnÍ`„=Ìm(Œ$+’€€¹á¢’JËŠ<ñíCô:¸-e\†ÍUZm³°t‡yfvŸè¾›•9úë¶³%Êh¾·h6¾ˆ‘óÉqDXÙ£üÄžL/l”ÂÅ—rUvH_ýˆ•´]ƒ…Ÿr&‰nI)fÛŸï‹ú±÷IÓæNÔÑ):‡ lu ɘ/'øÊ_{;rºÎ‡Ê‘3‰‡•µÃÎO÷¦‚ܽºIºa0££­˜p¼œÎÄž»J[Ù¦U¬Q¨¨Kpdžåü³õ0[L® "LUá:ÄŽuæi¢Z'ûÈTsŽçîÞRÊIóš.ñξjÊÈëm'VÅSÌÚÎÍž¦=£êø8[Ë7ì^§)ô†Â4f¦¹¡H'ܨïÉgOŽ`X®ÆyP¢ZLa圎^,pg ‹þêõR§^ö@ÖÝ ¿dìLvâüA¶tâÏÝÝ>ÓAÏDØÍt¢4´÷</’€€«aNH.".BJk‚ÄK¯ê¹{Dˆ:©tLâÊgh:Bú{¢x¶ ”‘ÜBáö²ûÙ`å4{ÔzÅÚ¹j‚„Âÿf º+`8è ‹ZE”BôßpÕ{ªÎI7Mv?Ä7î4™½QŽs˜›pëóàÄAUè³7ê&ô0?KZ˜EîÆkOOMèîJr}Ø]`º• §·—yV¦ªAB>Oy±~éøÍüºO:>ˆ01îÇÞÌÕ’Ø{"Ž$MÐJÿR¶5ÅÊAiß÷\‹ß‡ SSN'|h~ßónUàEĹÞëâ>ði´ó(ìšhQ% ~­0Ú YI”¯¼ }Ï«Â쳈š¤qe{âžf|q´W¯!¨ØŠ(åë¨Õ<õd§—‹Æw=.öw¦Í—rÞnY( ‡}É1ýè‰Tí¥Ð@ºšž¼ÉÿV7dÀ¹ÉÑG’•µ:~]?ò盆ÖýÁ;XD>ÖÒó V…í´JI!L~kQ¨Â¨güÝ{a ï]¤ç¦Îf qF‡Foça‹_Á$½ƒ/|ÇSUƒ8)gåÜÆd}0‰û¦ü«ôSÕ-ÉHD'’=ʳ)÷ÙÌúà@¾tâ#jiÐæ.äš -3ì‹á‡÷»`étÚ«žiÙýÔˆ–Yf=RáÕ‹ÛÖîs’ùÓ-RÙŠOuXuéb§:x ð·’†ÿl %jWæ‹ÅhjEL!;ƒûXõ°¼mƒÿ”‚p>ïþL¹¬Ý¹eîqz@8CÄ2åŽêÕ €WD¾T?¦¤èØ-n¤ªçØ$jI¤3ïÎ{<¬ÝmS“ŒO½wÓܬTð1üú±ã¹¾ÕÏÁ‹Ž‰-^Û*^Ä.wòÒ™. ÊÕ†0Å÷kR1(6˜ŽÅ†®UÔÔ"§±.*çÐ’I*¾öCãïùÆÆ†[ÜYciÎù'Xƒ¨×’ý/™×¢2ûq¼8Ú°(·ÄÈšÔ ÈÉ6 › ›Š"»e’Ÿ%|¹° æ>ÃV5Ì‘TzÚÎ3•˜ ‡“âw–XÎ|f ½ÖŸ—^»e@‰œœ„ ¬Ú£ºÐ"ÝSQu˜¤,;ÙÉT®;×Îw{…Ï'ǻěßZä»VΆYé¶] ƒ]§°)#åçuYoRßP³nÜvµÚGyï*~ÛÕáƒKüôî6ˆ1’€€ÍM{%¤V*Ê“H¤ké«u‡ýc®´ÞrS…‡ oâbÛL>Úc¨,i~mä’ø¾t×IÞ/5soÒ¡YB×raP8w¬4£µb=#R Þ2ì¤ÙÖ¤J¾÷ð×%²çZ:@HÈK¹‰ üj>ý¸á#×ós-sNªßª(ÒVS2Læ¾àõfz^¥¿ÌGÄTWq²è%K<(0;?S‘¶n;+N ªÌæÆÕxë7y;)iÿ 2¡n¡y½BâˆjȲX 3úê&8 PÌNƒÍ>:ú`:¢1Šb&¼ÇÕ2l½Ý‚é… N"ë1دVÈW~¸£w*Lg"·(ð§SÎ<549x*Qƒ1³$;Þ0Çtûì¹>4RC~t˜÷èŒÍО™6U»J`ã[ñŸ'ë‚aVŸÆûáÖOÉ…KÇÑ¡qš4¬<¡be©î;¾ZWìé­„Zj'rê&±sÒ ô"øµR üj¨½5EÏÊDº›@Gkb—ëQ¬É¦ÄÖ©6ôô¾RfP“ ê!ôf)³ "Íò…•ÞN0÷mRk)³ªØ‘ ™f²Šhœ†N7ä0'€9ål/{áý÷Þ”#aÆÏWFT2¶^qmtÔð÷ 5ÿB‹è­»¼º<è(›g€I÷ n’ñ¸—ÿìù"²Ð÷žeMôÞ—Ì'Tªis*3ÜZUõ2È  µúÞdrÝ1°~°2˜«ãÜ,6¦–+Kî7|÷ eFê›kúr½¨ý5{§ng!± #/tKç`Œ,NñáYqAÜß%Ñ_}“’€€Ð^¯ŽAØúî¬Í<#'©2R9}'lWQ=¡â¼*V^·¯ðÎæŠÎ9öÂ.U%]ƒ÷3Šú@ØgÚgoÉà÷zÈ^Ro%|LÍ©oŸ²î±@Ë*kNá’¥³š/É\ú1.ß÷¥5EÚ<Çé<÷>ùzˆ–‡œ‚áÀ[°ñÞòOlÊz`”òzEýõ¼í·Péó÷žš¢ƒOºÃ7î© û+ÛnUR½ä,±sæ8ú3à+<“;¡’¥8е4Hf‡’ò?[¹½V •…»­XÂ8™Ç[ö[‰6½i%WÀúwK Ðj§A«î&$Hë,r‚Ày6i2g×OuÉY6‹wõ ÛK/€,‡n]Z×êb äU­áä`ì, œÈ‘®mðÓÞ½mUCxô«€ ®¥Ò–´«ï·ÄÒoÌ¡kñ>1åA«ä&nïÀß´r6ñÑ×Ç{0óB·Cl/›Îo÷ãRB…e £þîžh5jû)ó‚ôí®!>wKiM à]>©CÖU… +3ru %1; y¦–`äg‡™†TiJk •š0²»æóœÿ䋃’X ›”§.G‹ß”’Stfİ&4[ðÝK®§†aœ¨¢øCžÎfb4€‡©Èã,aM¿Ï§Y,im<Éu ÿ]Ó‰ðÁ†\D+‘§Û´P© OïÃkK3˜ ÞÆ |ÚÆ{±jÈæ)é‰ö[ÖˆXîJƒ5аÊ÷J:¶¤ †2KÝÌr÷ÉîyœÍ‰4êfÊaðq“C½ˆsR@ózدK0›Cı¡ûëʼ«‡Ìé-™ ‹È—ra®`ÎZûŠd ¸Ëñ³Ç²‘¼ž°&ƒõ^kZÕ½²Œ‹¿ k¸ûžín<8ý¿³«$ûý–yøŠò〧üŒE¬ûãjîXµQDh|óäþl…¼ÄÈ•’€€Øw_/O__äsýËöCdéÜ‘Q>,ù†¹K‰Û¤®ïý=Ç·"åÌ–ëàõF`@ã±ÓáÈ^ªqÎan¥®àŸ»bíä=ò<@C!…"GÊJÔÅ"œ:‹Å¬Hǯu£§æ§ñ¡¿È|À¥c$†Õ;8z'fEdL["õ͢ꓙ¨Çw½DÒ^ƒOZ¦¸ŒWÑo­â˜pYt¡·É<\_0±H3¡ÿ½ÅOž«ƒptý16\ÒYP¬F±Aq’Œù@ŠHÒý)PT ¢þÝ×áëqȶNXI1§QNÿM„š1ùlzdßvêõØäó'X²ëÑ'–T% …üŽÜ6b&9M¡ÜÑPðÞÝ'¶˜ºœ^„Ø¥±ø¦ÁLk$½xs8±‰]²®œHŽ•ù̵\†É¡yÃ×RZ‡YïÜvœ…ç°š“O ëFš%ƒÆÚaû­‰û×T©ŒB¤¹£$HÝGTØÁ´ `MóˆM2Zÿ–nÖ¬m<Š˜èR÷Uâ:5ðÀ5b#ŒÙ±"´ŽßÙ‰»â«EÀQbp>N…Š!ÜVË«÷ÃËÌó—?óNÁiaÖ’Ùê`És•{¶i}²ƒ\Ó»šu0þ’©ž'õø< í Ž˜u¸n„6aW|QT¬ nÿ”-´Ùœxph³’¸Q–˜(kÒ/ESGåóâàÿ5aÎÃæ‘±ãH·DÆaò1„\9—À•ਈ6Éâ‘fM@>……’…÷ 2A­¾/ܳN—¥\ÎÁxµ`~£0½\;¨—ÅÊdKšbQÀ,Ư¹Ì'ÕÝ=R Ù¼o"Õå%%v›D.}9ó¬öagì§´š¾;õ…k(Á%ÚrÛ¾­(B<8 L…ñÃWJÖTQoD¼Y´ÀQáHögb¿LMM›§ÌÇØH½»Å‹!h<µ-·ahô²ãpø²[ ¨ûðž ÒfÍÅßYdââ2 &©^_-Vìk4F-|ë–2x¼CO [ãòE®$HÕ]ÿY{óºb:nóN’€€ºé×lTù»ü]Zíúúlû1ã¿®3&ÐþFø §×ó:‰vÖ®Ò[Pò…,ÿq¥ž“ø8%Rtò6†½ÞgtØB6Œ±jǼF®äe„˜5âzöûCéÞ®`"ó'8¢:îQyÍîíôŽ…Œ×CPæCñ‚~ĸ,;!e‡d5þÔšŠ 9 ÚmÌŸÁ‘nõ¹zP °´8rfñR^¦Íh›Âh~\sáì.Oõ̰¡}Íû/õÌäѬGTuW'X(¤,ýÝáu.ë£ÎìÉ«eök,vöäØìB N™”ìà 'õ¯©[èW9Úc0”ÓEû¼¡°ß@I.~Sf–-uVxd €¾¦²d ô.¹¸âírèäãB€:riϧì<>½þÑJÃ㞨 òŠr±}6£úzd‡Ä§¥ÝP}ôÍ89t×8p$ÖMPè‰(£ g‡ÏÚ¥6ÃÌU3)0Šiw&›" ¤š·ý^'þeæqté€Á´i°V …?À5ØjíÜ·hú\=h<Ì®ðÄûÜ|Š,·©º OŸôâ%° ¡u~.;p¸íË™¨&¨jªñ )?È©ñªîWiÆâɰ¦øãª¨ÃÛ‡fiSœÚI¹º×õfµ7ïµ:h ¦SwM‹#X0­:‚Š|øŠU‚Ä+Fd¥²b8ážéïæB&,3F †bÈT W»)ÐÚÀ•È¥‡_$°÷Ö¸]åEš¯=­ Ùn—¶5¯–E¨³ë 'à´Ã&vÝn‚]ðÑX˜ì00 ûM/¸®0y™‡„-Çž""›ë:±wX`ôvÜìwOï@^„*êg ¢ ž:5ˆµÀ€œ7¤nqŠ?OJTÕJtŒà <•á }ïéîíSŠö÷šµzÞ䌔/øí* .Ñ‹û¶ŽZ”‚˜ê~T©Â¯Á•Ž?ª2óýªôLZª”Ø0+´o(è&ÚAë`ÌП üÓY2/¼õƒH™,ß0’ÍýÄÅ×¾•úݶº¾«Eß”›¨û!ùjÄË*ëKºì¾ Ö[³þuäXFk…ƒÂgâÙJO$BT¦]–á?•@Æ„Àe— ‡sÎè-sîXo–ßW~m|rñf fÚLÿʦèÆß÷æ¡åÿ'êÀËàÚíw« }¯gؽÝ!‹.Ïš¸K~ ë$#–"eV½Ü™òå'§éëøOüú¶®'ävòŠyÑ<×S^\1:¤›Ñ÷ïjH@•Y°~Åó#CŒ’ß¹b^³ñz8^žðdsg­Mÿ~ïû;£Ã7Ñšþ°á/ÎúÈéô‡©êlßA1ø,jê\µª½ êÞ˜I)WA†òY æ`ú1þï U·Z"ÝWÇ xÚ)â!Ë©†’#»ä´õµÕÊ D^Ö#ჴɅÞNBŒÔç#Ã!òØÄUÂP;¬â{Têt4²ª'Ψò0úµýoß̼ʔìãFeA‘ónUDô S †žæÀ¨G©Î pšpŠÄÏ ’*‚¿è©ž×4И­y_â(£]~âO*©®[’ øÇm'~?­;:%îeÐOfÅ3š1#‚¸ö¬LË„¿þ Ý:û„/‹äUhNw“ûäºÿ° UÑähÑkóx?6ÏÔ:yë<:¡Ù\L½è«@£eï-)†&0JŽ˜Þ`÷V»s–ÚM•S%moÊv l’t‡|£ÓšÖUæ†,v[BsÆcv@jë@(1ÂÄù:#_g÷J ô´ v‘×5šèµDúB”O-ïaS-Ô^é᛿¢~ß¹ô›…A1WO ‰{Y²¼ß–¬&ϲc­úÿæ›Ҫʷ¶ÍÒ^”±¡X4ûͲ)H¹Ö°Õ˜%ŽÉÙ'³Œ¿ÊÏ·â”ц"o¶·eÆÆ_žoì.ÀÒ`~šóÐGýÈ °u.‘C€måç"ÀÛÉr¿’€€çjr€µB;U»´¶2^XrbŒgÅÑ>F25[åöâ;×dnô(_eÙx ½àËH}ˆå¶»q$yðYô ´[m±lªÙòYùG ¿÷ýøœÔO¾ðóúKô:²X;%Ù˜+|\gl‹/*{®†t­‘o+?'¯kMc„s<}0ª€åE“¥\^ʰˆ1^ìW¬°iéqœ’¨ìZ&ß­žö4¸”QŸ ‚Ñf'•[§WÞN½IDŽÌCIËA~ n1;ãM’´çQ-­ sId³Ew“!·I èf³9Ð_‚Ñ88ÈãbFƒHSÁ ý¶ñÊ/[N”Ï¥1‰Ù¦…Í¢:m¯ùà§®>•׆ßK†š)ì¥8e{ŒØm-ìo(ù±Å&žrUTXÆõÙáž-jÌ•I:¤Ø0sø†‰±ÔæW± W%ñôñ^Åùd¤äQ¼HÓ"‚ßlŸ×õ2ñÃÑcý…:ýÓ#Q› ݾ :[Rǵ¨$ŠiÔN\…ìªÛy´^ðè<Ù|®Rañ‡`ïØ,ªÔž"þí]ÚyìtŠÜ„œ÷sLV£RŒUƒÓ­ãEÖuAÔíæ¿™b;šKÚ›Ò\ÊWÔU'€ÜÅ·±v$ ¹ñê÷S,þÝ`9ð=±õÌ/:l˾óãô†÷!Í•t‰Øz/-ò¿ÖKoN‘åØÍä}¸§÷4cš×8/GÚXÖ¶™…®Ó—yc}ïl÷7Ëï’^½ =éàø+°©k‹·÷3k™»$N¸Ø¬y4RÑ[Oæã¬GñpþßÚ3™ó€°ª1ŸQð˜Åɉ4æ³µ¹.œ¤kAl?uï® Ñø÷;c%«`ïûA¼üuÈI9@~BÆÒr ‰»Nrä3¬€XNv€„¤‘,q7êþG5lùA\ ÑZ§a!ï‰/šÈupxÛVCëÓbÙð,ˆ6& #¡ùõèèJg ±q")®ÎLÔV"Öa¥ÇQJ€:Ùá*TB+«(™Y^©A U¦kàšÙçÕ°Ô ¾Ò³-£k$Fëtôªõa YDŒU…Úç?@7]Áǰá<èõ¦¸ñ«íÄ[ž`ìyuÝç2¨%SËDeù–Ãv‡~œ"ÅYØú}Ö¶J’€€Ö<š-Dq .±Åx(¦% `_“Ë‹3_H»£Ðš$ÔV Mé¯b'¿_ݬDpÄÓo¬Üx¹5•™‚·“ŸÎQŽú¡>H’¸¶Š]ºŒ°ð{u €i¨¡!LnÚ“}QŸ / rÌTòiƒË Áî6 ðñ™³5”Õá*uåb«Fbx–hÉJÞ¢ÅNlí#Ç$ Ø\ËóEþàÉáô–)‡V0÷ÿZzˆív=æÑ&À¶GÛ.Ø‚åšCO©˜˜¾[Ò8©xJ§çÕm\ìÛ³þæ?Y¬&1Ê”0–žo,f}…-FÖkGbêÌ&3ˆ60áñPûÄ,iî²™/fXâËaŪôpxZ¨Ë~ˆgÀʯ®&ß ô(…™|Y—GýqTÍ–HYq¹›ñó¥ |ëÝʧAŒØ›{¼Ø sm8‹=á°–gŽEº2ÕdbËœÏYã”ãNÏv£±Â q ïЩͷWAqãEËÊàÓV^|èÕ÷2A"Õú½YåÚŶpט +õm¡Ob>VXdJ^Zqo‡qÏ×L&4DL&i³o0EE©@NóüÔ,Tèñ=¤yUkÿº«jë‡ kn:Ÿ@{P•ž,q¿-â´iX)ËØŽ},ž2*Ú–l|Ϭ>Fã‚\ÆÊxÌí‘ ÞúÔ!H™>\fõà£b³mËóÃB<•žß7t‹'ÍGÏ͆ ˆ¡b©ìv˜ÓV2eú0±¸;º÷c–)úÇÒwí  þ«@R7ãõÓÝÅwµËø•»  ­’8ƒüaøë õlZg½»Hÿ"±ªÑ’€€¹²wæ½ØÓJâ°=C—8®Ë´3†“ó#ˆÔj KPb2“ØÅ(ò“8ãç#eÑ”S}äõÆR˜»f’›8õE*ÏvIËÖûŒU úF϶ $á>6ZbOǸÚ?l•olÙò|0}å£ñäy×Ïi ”Aο!ÆAi7¬–àìÑâØ§õkòÍ¿ ab9 ½Zý2Ì-ÄßN”†Ô:ØÖÂÑvbp;Ÿ½Þ`hZ"K9i<Ш¥w¦´GÒ¢ëØR’’6gB9÷jëÃD‹ÅÓîaéhÃô|oOJX쑱45; ùø³TÒSš4G)xïkÕ·x~¿,±dµÖœùÇê0Ù,®…$Ê+êíc`Ë:ØGwBÜÝ )©EâªGûe.»KAN]¥,ŠõÂnþT3C«ÛÙèK-V)™/ˆbcOP;åQoSÖ¬‹B¬JÊ·Ó 4Æ* ºõ*7¯ÐŸCbõ•Kg ûc‚¡ívÒº©»ˆ˜XUÕžG^ÑÈHØ=óv?åX¿ìèóP³ÜˆE4Ѥ~VÔ¦"ª¶ƒLrå¥?®ÉÊ‹úaCx+ƒ‡¶u»Þ‡¼!UœÅKoTÑÉ]¸Ôÿ`.ÙËyZ:AK¡üu"ƒ†Ç§ž\ææ¹ÕÈ"©‹ƒD´ Iáwâgtµ90n` ¥|¶Õº,í~wÅÅÖ,KÇ»Ô7Û¤ýÇ™b@•}MžÜÞ9ëi¬Áè@€äÖõèJª«›_ÄPÍ/¯š‡Þëé„r¶–Å|µénÔ³¼? iŒ*h% ÍèØê†£dÐÔBJj<–>õHË! êþÏÑáG?:ÎÔ›Q¶]–٘×OʼnÄ??jð|Ì×±LZþ`þ‘M$;¥ýú¤2¢K¨À; I¨Ø’U¼``-FìQýþ½ÓG¸OEeú™>>°-¢˜pwÛÏÑÿÐŒIzÙ9µ…ÓÔ¯FçͼŽìmrùüPÌ…¥ùüÎtÔÅ”-[)Ì2q.Œ¸É]–Ú?ï¼Qq†ûð’‰IrÔ¢TœöNœîÆn’ýݶ< Û£xŸ5ŠV.øç½Ïògâs„°švŠ†Û©s vÉ5”†UÐÎô£½¯?,­w`œ÷ÅxÎù܃æ÷zÞу‘¯~ î»é3’€€´V’Zê­å+5Ǥ2uOtzyöÔÞW¿¢ðøN!, ƒÊƒÎ3DÚ‰ð“Îhƒ¿¹B òÁ£[~ìÁ…‘FÈ\@ÙÜFèܲ|¿¯[ß7Ú--G{›É :­ ŸB˜©¡uûÞÒä"'‘ª5D°€«ºWà?ediÈ`Ô©¡×„²ñ“Ùô±éѲæª"[þF]Œ‹!»Hù‚µ­ R×ÿeï! …‹ÑyÆú|WÿÕåG}uZX9$jÀg½ –¼š#M ,öcþŽáœó€ÀíŸ÷®Z£âØhµCd¬³HêÑ ašòbÕÚQƒjY•"bµÈa»¸k¾§’¦NwÄxĬúÇÅo´º‘ì»þ\%{5µ-›ï>'Ì<ÝÙÓë vDŠMìw‘+g=±Æ•Žø¶~¶ÍËBüTǼ镠 ÌÇh¼Ôd‹¯y,Ï>šCÄŽNrCäy»º¶· c0¯Çb `ñ+”ÝSF;È¥Èk½Ï¯ðMKn~’LaL$ì³½R/ƒ£óèw7Õ\b¡ ìáí ÛS¸[ºbž©­N _SB©£²3º2É«|îDÇÄLlx!Ý+«%4"Ü,SÈ+Œ{'¢èx`ËLôjŽŠiÁ ³àFJÃ,´ááXL^³iÕYDÆRØQNL„¶ºÓ¸rëŽî_yJÕ¬¹Ê¦7:¿…â¥n(†o¨¢Ì«‰F1Ö³4nOïaE4G‡îµY20ˆ:š°·¬ÙŽNM{¡Ë8O3O³wë[î–ÐæÚ„0Ù¥U&ãé ÅeðÌ×zMƒ5BŸåž¯¬;v¬y#2»ï¬j*‰Õkš!­O{ö$OgÃ?Xcw_ˆ¸õ¼|¸àÛl³B7Ýc“zdô‰…e²B´:÷-`¨&ÛOãm™d? ïuõ+ûÖ¤óãóþiu^ÆõÜÎê¤Ôãí°¹4™Ú)²9«2S.)n‚öW>‚ĉ Ý€¼¬"r^Š*í^¦<þS`fpŽA‡÷y~ôþ ÏŠ`Ëz?+,&j¹ºøE¤¿°u‚ÀhVm-lX{—Ö¬–’€€á[©#üÏ1üS%Ù@l‚æyäú—‡Â¢ßùó6ôÁ·³ w SWRäbŒÍåL,O3vùo^„÷¶Åèô+ªg™ï0(.ü“NÖQ)¶]a œB¥2GÈÕ™”×ßµC>\G÷6ï¶ë+SI†SÈbƒàd𼋯â(-gLFÌÔ nH‹ç!ÿsV!l¯f¯ÉG½–ûŒc JRVzX3úùV÷È-f_m¬ø2¾¡@¥ ^ô{ÉZ<Éýn¤’‰ÿÔ÷¿š.k÷.^¿š˜éK§Pò1UIè³Y 3*ti¨ äåS‡ä…ÃÇø„eÎu¼>k®¥©*ËÚX\-XGgÂî­ÿ¿)éN¯«‘)áØhãWVyè5Xì‘™Ç8fÀµ|Ž8–ª ¡Dt2ŸÞŪ€MŒý„Ben(aûd¨¶h—9Ç ÍØv)opH¾F°µJÖsEßÕGø/í4¨ s9ŽzÙbËl¦±Á=˜$ÕAw{›È®?“vPQfÝÉQž¡ÀˆÕâEHæ¢ÍÂ`(-Öw¬m‚ƒJl‡èCæÌÐÕïã8ÿŒ@X2û’ü@PHˆØ‰áñå³'uq£ˆÕóg³“QÑ­›àœ|…ؾºv²ï¦²/øJÐ ,$ ‘ZSÃUõÀÆEÐLmþœßr&å–bà~úu´»Ú”í”|…¼3ê‡CQ )[ {Z@é“JÿXk>ÃÆ¹ ØÔ¤Ÿ%úºÇg ˆW¹ùS¶¹AŽŒòÖÌæVnýFkѯрfÎâßc?çÑ5ûI¯ñè‘î»ïÛ!0wN3 l çm“Xþå7â•ûï¾´§ä¨ âSÓlš'ݘÒeZòÔ}Ý,7Ô.*ö@é¦p0˜ñÊËV–¯Jn¾.Ý{CºÕvüùífJi~8 lƒ­­nQ‚l€k ùQŸí*Œ·ÓA<¼-ýµül¹øórò”¿ ªiŽ16×ÑLå®·ýØû$VØËè1 ̽ÆG“v°è¢¯e?^¨6Mh­%üõ1Ò;ˆÚùzUµœpVìÔ<î~䢀ø¨¶´x{S—‘k¿žÍÅ—;ú³€ÛßÑ3~øŠùˆlo4˜‚Àq  ²Äãåk¨Ü¤ä#‰4iO{Fé<’27à zÈ€’€€×…ÜCÆî6o¬#KºW‚o„ kk‘*n(‚ö¨Ü&ßn(/Œ Ðkq€©öõ ÙȆ[@ãN…Tà"MöÞX mÃ{ëªw®3gUÇ©& âò)7),áár7Þ:ú>q"µüW­ƒÚsSAª|;O5»#éé¼ÓüÊV‹Rq¾ºqä]CÃNÑ{Öãñ÷›’_!ŒPC_0ÈuS0Z´oìtdlm冡å°÷ »¨ƒÜ…|†Ÿm³‡1³Q™+ gߺœ¼mu `Oa('Ö¹ÃjrmÚ`bµQzêúéH-…ßÕuUĸžŽ-ð+ I; ªLìýÕZpò\†ÿ)ãÆþ]3ó¹›FJÌå31ù´Fw¢nœŠæd­{«âA›Ôë¼x7Ÿ# BÊ[ˆ¬pšþPP ¿©*;ç æËïK#_ïBÏgñy¹ •r?÷p=)Â…Þ%’˧nxŸ´¥¦óMÕÙW%_À ÊzøŒõR/‡Î¿”yt#„w¼˜A‚NÏâ AFÑÏžÍñ1õœ)%;DónØ[dŒF»¼È¤†–ñjâ9°tl&ªrdñÃÈݔûìÃ¥OøàüW[·D.N·L]ÃaØq BÀúOsA€j¶À2|Â¥IåØÎî«9Á8¼uô¯ƒ,¢ÄÇ¡y­0¸«1ò‰÷›±1-á&¿Ã#ÍþkDgµÄV¼¬oýóÁÖÙžpBTææÀ$ªým=–+9º5âÝ~V–(’ ㎟å¹dàÞ:RF)=}#¦çÎæÙšBH+m‹c‰ú£D°8U{O£çóâ¬äÍá|USííæ ˆý¨jÁd8'HpbG¯=xÝOÏy1§Éº´`¦Oã5ןDwÏ.ø`Ša“#'Ó’¨,…âg¦/?NWÈŸ¶§^Lí&@mûÞ¯Ò›€Àœ¸2+8(4mZ]…°ˆ–1·H,ŸÑ©´A*t5|ãÇE¥ÁÐ,¿~ è׿#oýj hMbë{ 2ŠwÆ„PYme' ‚˜¾w4!ÑdlF`Õ/»›\JãÇþQf&/Uíœ}šâÄ] á€uuöä€ÉNs+ Lƒ= ~Œ,º?µßõ‹7ªôŒ»é  )ûDðõ=«L¨Ë#¡½sšÄâ‘§!ÖÆD’€€æÍÅòpÀì9ôèIáSt쎻ÖÈ ¥C¯³S&,3\GÕçSçœãӾجæÇ+'¨˜§<™ï†ƒ¤«ˆ!DZŸÍ¥D¥„ï¸FR€æÆÌ}µÅÙå¬Uiøüèõê`Ó6]œO]¨íù•—3sOä£âã5X70´;Ī)-Q{zKÒkÃX’^¨ðnâös£eûûVÒ=ËÅ{tœÄݪ U¹úºkWÏßqÍMU©’½zzši– ê13Zú +šTç«èO汌d¿óIÝ÷yæ”7ê4gäÔã‘+…¨ê%æaz»ïq“—§05>ðÖ~ch-:þÜ;07 íT%óÝš‚¼Áâ|G¹M^?¦0Öoa+ÁóÂð'Ýœ‘ÆËšˆoõ6äÛ­F«J2 ]ÑöÙ“ si¾ïyæ?£S œò$u]¬Ú©Ò÷°‰TsúZj"„«öÕîyÁÙ5¿Ú¤s¤Œvï~Še4ÚÜåÃ-®óƒž©S õ¦Á÷:'#P*aõ¨73ªomÏ€óÂ5šû¡÷Ÿ¥Y|—QÞ‹×/B¿\WTïîwõ].úCÄ.s¿àÁìÀÁü¿Ùë™Ë*ÿ{„4žxïÍ/Ò×] Í¸ƒ¤±ºÝºð=}ÙæQ#­ýáÞ;)\Ô¾õ·bƒÅ€Pèî»Zƒÿ}H-O]$ÛL 3š«Ä‹9r%²Þ§êæ9¬þ½-MXQ# Ö;gKi×jî¦ÂL.ØaÚâK¡?EƒwØyéŪ?8Ÿ’C‰—i´3së “#…¡tJßpXr  {K'Áã¡B0Í[ÚŸ¿‘·ÃºW‹Z7`\ux¸¶!‚g~6U:SÖsÓ^ÿß1êe¶2c#GÛ\D¬®@œ_ÞñK7­J¼é*}ÈàþHøÑ˜‹>¶›­‘%Ž`λåS•Y;Ú!b‹ #ü1¿gQ¥“ ­w®’±¸›àm²He4}ùÛÚÄö±z^^O¯WŒ"ÂÅ/gß‚]œVƒ´*Äš¡‡†ñ9)®¶—rsF¹§ú¾þ¾‘n@ŽŒaˆÆ“óPuöZ.¶”\z %myŠW#™s9jÀ•’€€¯Ý?#T¯Úo©Ñ#¹Q…I¬é+¶LxíFÌEà>*n.üyó€„\ /à0~7:ýHK|Žpr#wIëtçÊ¡¤µc×ÁñHYPMNØ&BOnúlNd‹>]ÜLñè ¿®5RÃàáŠbˆÎ¨ÇºêF½„.|%“ C•;¼bxFefðx—_ }XVE^a:R¦Ëܢ܂GÛÚ¥Ü{2+}‰0¿`E%»’ÝQ5ÉØgUÖ¡á­{ý…<¹É êN£")ô48"t-VÆUû{ÜbÌ[1"¤4M uAAáŽsQRyJf6ž¿ÌÐ3Õ™@ïLêðÄyl´Å(ý«{"c—»Ûp<Gÿ@M“ÐQÒé›x}ƒ×mOÞrg hÿ½,Ù2BöØô]Ûÿ*“Eñ‡¡É¡h y ®A[W3`–M»K§òù5¤Öñäì!£þ^†æ( †Âèéi¬ê•R9AJ :|É â%P£°çÇ[îÑžYMïÌG̬S–‘¸ vSúEŒS\J2³˜¬#BfwOÚD…Ú$ŸUuÎnÆ",«1”ô¿}2¬ïIBÌะ>8Nâ ]L˜,æ3£·ä"o*o½õ¯Jçïé„kö9µ…˜(ÚP!ÌNò);aJ=w1<çÞ²Þ$3ÖòüŽs3_ž\5î’´M`g&em圄ÐA80ÍÕ ­çYŒ\¤-ƒfçožÚµYj3 ÖNoÜެôÂl?8¥bÁ7°ÛÈdЄ­’/ÕåpÿÍÀî) Œƒé®<.³È´U8$YŽxY‹ñ–+Œ/b ‡§·ol3.lÖ’€€¥ˆÛ»â,À27‰„ÂãçáÛ'H—öǺ ² oˆØ+ºrœóÖ›Ðv›Áíâ›oM““¦Mu§íyü9c%¦i]ÿî…c“c bTK‹Y®PÎ3r¬8%>%:a®°NBèÍÚ˜±t®Fò|!å¬(ªâSeØr¿&Iú5=Ú?ÂZ®‰Ø•cÎÑEk¼¨µIˆw0Ú§T‚<†Ø `ü†ƒä|V 0~L¦U¾¾e˜–Õálža—õÓ˜KhíYÍŠr¥ÎÃÆŒ¤|°3…7`ánxkjß)¡& ×fBµŸVÜæ4ôkø³†¿sêL8;&Ua0ÖÕØU^DzÒ]³©keËS•Y|³â«ô³ç¿Z¥„…ç8Ú/0ELD“¶ú¿z-.áS¬c‰¢4ƒìÅ_ؼ³pÐÐë‚cÅ¿à]Ìó¹QÅóñ‹¯Uèìn†:š‚pi‹©›Ì­»ìKký7\Y‚æËÍy1#?ÇŠÌšºw‚à‰ sB¯>*>€àl‡šrÝÙV1bò©h—EôåsŽ‚]˜¾­ïa°ú ƒÖ’m\»ï6g£u&$ÃÝž>| Ë=Å6T¬ÎþÉ)"zš‡ËèÚÏ Ï®¤å ]•2T8¾½ †Tn–µºû›sD’ß0ÒØ? QX|L3GŦŮÆdl­8¨–yÿ§XÚzž³ÝGêð .-"ã"¥Dþ¸¹».Lç_”É ›3‘ ™q_u¤»­Éf§â’€€àð.(ƒOè³ma ‰f=¼|7YA†Vª@å {Š¾Ç³‰Ônç¾ñˆ Ó…Ñ’j½ñ ÀªQvr+à‰·N©êš8ðEWt#hÍM™Cb~ø[[Í—£ B#‹­ôðq 0ZïšUdµ’ɘ.ŠªÉêÙÊl*v¿?uM.ˆ>­Ê·Ê Z6Í6;ó„ƒ+Cœb/oÀZu6ãZ=Ø“ÕÉ ÍŸp’XTÌnÓ£„aj2ø§)€ì£x:aÔq`ÚÈz´8â"Ñã§ÑŠÜTY[ÚÄ[¬ ¹GÚsŒq3{ò@vÔŸ‚Å'£¼ë‰Qc¨¹>– Ä:©Ã×÷Ç8hSLš`dL¢ nˆ£)ƒÁÜë)xÒTØ;·ÿU¤Ö p.C. ñ‰¼ž;ÉyŽ`4W³‡n¦‚0Ô•v'*ßV¥öqaÎ"l[pöSÑ_Éö$«]Eùº{ÙÕlÍ mh³¹íøGòˆ^¶:usÎU@ ž‘ß%¤øÞÏ#‹dRÖîyãÈÛŶo¯GÀè4$ð‘@-&'{‰ÕãìÐË¢¥(&a=š®ˆÐ…ËííÝÍ:š5?ßEoî6Œñ•ˆHù6†0D0vúhÒ¤ ÜÅ8€±á¶’îhþwçï>%4áø¥kÀ‚¥–e—ì=µ H(Ûj¤ÃgÒòmå˜à–ud• êHaÉiÒãÄ–‡ôþÑY}öü %¤™±~#[òê·øñC -fAʶ7øÆ“Dš½çì þ*n Ô]Ѭ¾ã÷õ?þSáÓ¸\—ì]˜V/¼ºWŠ;˜®n– ¶4•Ûh„™„D†ÐŸ´Œ‹­ú´ñŠ]ùhÔ“ñ³bÚK¶¶ßiG^¬öIÒì^1\Vj¯Øs4p|óFzs&tºÕëÏîMQªC Â`U‘b=‚øQh7Ô4&=,† ¹ÁWÝÄQ1RGvPôð‹žÒ’ï§Ð’€€·t§—»ÝÑ7¹Ó<rKû½xó~’=ÚÃ÷[]å—£â7£VtÊès:Ä@o¸äË(ð"pÜ~b®¢‡…rElh,ª Îmu¾WdȨØñ/Úá>C9Þh÷ftJö9ÚWb‚'i^פGþ5çîÙú1ÎÙhÝ•}t´ &º|[ñå=lãW ®6¤ô26xNà&y€’.°ƒàѧø›ÆWc?® CF}‰KxW õ6 ¢ïQZÝ„®$aôÙäHÞãG…v”X|×qsèAT+i˜B¢$¤²+Ômië!8/ ÚU­{æ ã>8S!ŒÝÏ'³Éïy£æ7x‘jˆ¯™£6,ë>»®%ÕAFð Òž¢ ­Zzé4OÚ UCtó3ê%™jwñÍ^Ý(½[B¢.ÍdºE޹;3ö©,R|ÜÝc;Ú õA£˜¿©í/™ž °ÇÍ ÷÷-ÌUêÃ_!‰œæáRìCžŽØ1YòkõЛOΞ»¨f>ñ‘Ñj²˜;¯¸+2ó˜óÆ,)–Ïý–j­‡¤,”«bD3$nÔiÔQ C˹']( GûÙØê35våRÛ¥€ 1H¿-ˆÿ›—± % ´r‰Þc›Êõ)†sg¶/y6­û^ž,¤’ÿ F¯ÂQÕÝw„ ɵéj—J5B|qR¯9‰£9ÿÜèþÒþÍ}^v·<¶Cª²ã!"θ—»Æp ¥NÐ>kö§,rÛ ‚!Š$c7¢õvÆ9=æ\”„N*ÃsS!ÍÓp~éÃo/hÑ£sdÛ(üú ÛgÒ‚/.„ÔÏ9 ÄÛ‰…ŒÃ}~K{z.“óÄÊzϵ`ŸI,H.Ù~+ÃÁåF]'ãebýÆ— ­m‚‹âSL:ƒ1OS€Ü…%¹ÍN÷ÅTg!²C¶–ÉGëØ ÷®ùlÊœ¦f¾0žË²iCÙÙ:JDF\HM‘Nž{G1|\⟕¡VF(ÏþI=V7]^r]Jë{;iy-®$è(WõÏúÉ6#aõèl²1n:ù®U’öig;w…Ÿ§B¿ijŠH¸Åí¢FüŠ wq¡¥©WM¯¾èð¬CÞ·ë+û÷íà’€€À ªd|êé”–K V«]\ʺ$þʈb>¸´cMІ5øáU<†¤ì‡Ø$‚µ¾hžzQ<«Ž>äjà+›&­tØ:Á+À¨w8;µA/Úgoð‡¨©R‘SšVkY6N”ºµÜ$ŠËà³xµP´ðpØ­ñ2[˜(¶ktô$UiÝâ#^m§}Íob‡p{Þ¬!;Ç=.ÂÂãñ1W†`,gݳ§ýæi•›”Àz½ÈŸb¸é8Ý f\S£.ÓÊLÐæCI ‡²ÀfüGõ:Æ¢°¸¹>šŽ·õʪv'À‘§3§Øo)˜¶ò}0ܬk] v-$Zz^g°£¿Š­müÀšò(ê,ïØ5ƒñnê–Іm/#…É“q}ïâç‚6t<5EH(UvÍsŠ×¤y`rÃÌ—ñ@x *ÏÀÝ“‹›ÏiØ«GK%”J–aê7ýôé­xÇdI€¡÷òwm¸sf”,Õ|³d•,ÖËø† 0a`¯"åQ¬Ê4FPBÖ[e•SnS‚€¸‚Üø¥„mnØÀMÌ.J~× ›øW¯Zâ_ž N„ˆèàV‹ Çøî´­ä··‰>×™—¢åêÏoïÚcùLrHщŠÿ|~•VÓl½öUÕggöJ [?€°7âèÁî®x6TîÌ­kµïdÿŠ ‰7¨h¾¡é[T…çi5«nÄ[Þmùç·³Ì<é$‘EæçÖôÀfgCØH2å»)sÛµ/4Àm²lÈòhûý éè|H6ÓZ“!÷SA;j˜¤{Ä>§iÍÈ#1–îýçCú½¬CæLÇ-á§”MH’UÍúí֔Ƅûã‰0[¾Z/íd4ø¼wü7r#![H23;Œ=o4¨än|Þ¥vSÞª¶ Zöd~¹ÑÇY·>@à¥1U~úYÙÞj(0Ú¦ AµÈecàÓò¢v‰%£ºS—{’ü_öÿÊ8þýÎ}ëÒ*hîøÅkvLé ý«õ/ÿÂ_<šÉ›Š¤ˆÅ ÌÕMs€jæ»î!„‚?ÂÍÊgw¯"Ç{U…¸Ñ#K—Ôí­"§Þ-§ŽÖÒ'þsíŽò¯3ÈØQnƒ-<\x`Ž–QAþ$Tå=äs3U»'| þ²š.fcLàêãL@Ù"–v­GÔÞ’€€Ã Ýjê#ALcÿ—–ô/¿R2m&ò†¿ÊFŠ®Ýv5PýÙöû8úù{½]+ë<`°ÛðÖ2ÕÖŒSøˆTÞÅì'€ F¨F •ÙÓÒËóùígo-ϵ$‰XÍ{é{àÏ1ëkЏA[E‚àXn¥’FéÁWºh„¬Qbw`íåÞÃøýËXQk94šøòVˆsû{ÜÝäegB÷¹¨ähÿÜaïíkM¤jõ2H —£²÷”¯<X ϸÀOR_ä5 óÉ, ÚÖ•6Z9þ!_þ®‘º4RèrÑ€·#k+¼è,^ÎXºâ§»ú8ôm(WõÎRù)OüˆHk~ã]0±óÒ2>Zµ€eO‘ ŽCBðèyKBÝD¾ ç¾ßTõ"ïx…Ø€?+Ñ¡oò·ÚD¡À$ ¨ÝЭua#›j®,wÁ’/Ž—¾>Ŷ?šå’a[ƒ$2s Q“—š# —ùëxŒ-%Mæ`çÆžh£‡®¡õkw¦³ÏÕm¦Üì'CµT-wò•Xý+A!28–ÒüÃ]-°¸Íµ»O»Þt$¹I´`ÿ`yž£Z^+J’Zc²”–_Ñ7BûßhöT·];#6EmP9rd–¶Š>Qö(™Ð‹®uЏU¹í™§{Õ‡ã dŽžª_7ʽ•s Füm« Và\³~ˆùNLG¾g÷1Êêˆûú)ç+“ÊÌc7ô|½V”¼÷ ñnJû›ìnqóóLTÆo$„Î6¢¡¥;$A7c`>$±88«ÄbýA?ß1áÉM¬²»¥Éçvç”’fSÜ— µÌŽ|:ä€J Ü%=þ F ÚMæ³±¿L€è` <´ÕÅÇTÏ0ÛÞjš)>Á.Þ¬ÛûÉöW-’ ÒÐ ƒ+—Þ…Õ–p"dd˜¿¼[ÂëÊ”ÀÏ©[2z'ž˜¼f°™qNVD ¡®P y "b?=¶ºi¦äÌ;Åè¼b)’få }«jǧÁëðÅÆ¥¬÷R‰%ÌÎíåº˸Ù´"ùWg¹[E° ûÐè>reu2ºŠ,[áq|Gƒ@q!*ÝHáÄîm£À‰âÖÜÕØfês­{NqaròΘl˜oû`uB' ºÀ³Àq’€€ÅSŠ+¼3è†côñÙ:¥Ïqº3Õ1bø{ÿš†îËø0̰Ż;3³=þ¶4®‹O´tÖ‚03ȼ—êï!|å´½%Ÿ9k®pcˆ©‚Ǧ„sÓë éå÷¦ ¡ÁùÁqnÞ´¦Ì²Ý‡þÚ\îÿÜåÈò[dž{–Á®_l>ØŠºKO9—b~#2f¿(ˆ_½p<Í)ëœä??†+Oø7Ö® z¯÷Ê—Õ·×äì@П³fÈ^ž<ö2§mãmXð°¤N¯Âxò`/Er<)önò·×É×?x«-“bÕª‰·ÏWì¹´(Ü„9ßuHŠš èlÛL°l5ÃR2¿¿LbÄ$ h·‡¿‹Ø×[Y¨ÎÞúú)ù' ù>@먅å)A¨ÔÎûÞõE$†Ðôt )Pn+¶û79ÖM™Hùµ‰>’H3§Ewe‰¥Äñ‡ Fõ›Œiu /,IJàiàž Ì$cã§u­9‘ýDe{0ÇWN`2]ßG9bv= óZÅ„ÍnÌD~d7‘¸!RöM‚Bgÿø5B£?4CB ß«ê\¤àW9Ñe÷Ïñí‚+Z?ë°^ãrd ¹eœå‹•ÊŽŽfs˜›€§bš%÷á«{˜OpZ*M£ƒÞÙH¡á¥*u£?áÚ/‚ÌÈ #Eº(´§ßŽ 5ý¡á4ÌõüœD篓™X@MõEáBë«§*¶¢Wq²y¶ÓO {+W‰¨qÏ¥ÜPðNÕ¨”,7¾Â0‘áÜái‚G0榩Ï5C3«Û3]¢6X¸9ºä½ßšÎ´«×ÌÅå.˜† PRh=uÝÁ¿Œ5üÉÿ“qP·@èËq¨OËø>ô¤j÷ Tü.'ì“ü¿ú¸u&§(t"®:¤Ë›d:>”Ó)­kP¬vˆbÞé1MCâÛŒœåG±½À”EãÇõ·Zmú‚¹Ÿ>° vüwZ;qg÷þx¬‚wçÞFþVs·Gp>rˆqZaþ6e._±#=@¿ýþ¸( UGw¿ëÞøYv ¦/4£ÍN³u«Œí%´]ÈrïÌâ4ef}îøn™ÅýlÕ>&Ýà†î¿A°À4¼D>Ðà1<Øî§Ï+¤km†’€€¿¶cÇìj¦kLúMf v;9v4;±æç N¡¦âóîd@¢ù©H²Ã®¿Ú–í9ê'‡MÄ×þU®²ï#'¬ž»·wÌ까Ç%x„ŒB$¡YýT.h½h.ç¦Æ-e}užðï­wuÇ3ð™`¼Ø|± 5x–r,ý÷©˜Õ ñúy¹ã0òH©Yi#GwÔ‰ÑÇ1R”’5YWÒÁBÁµGËKÕR.{| G±Rœ‰„BÇJþ/2¶_&å‡Tzòµå€; ½JÛß“ßxÃQ»±ô)3N3v·†$Ó3Aˆò7nØííˆâFÝR3<¢äC¼îÆÂ¨¸ì(¡°q#ÎdFO-&ÔJé59´ÎQ°Eå5™1ÿ[ïc¢¬ïÌåÝŽþÐì´ÏàãæfÇ Ihë4{•,7%°æ‰ÓïC#Séà„Ò4duÖMâ¾!^j6 •í—!©Å¨Ú-XµÛª»Yÿ½_b…â´¬¡hþ#ReÞA]¡› –/´°ºÊÖ&P‡Ý}åž³nÂâ•ÌU¾òAwÍ­½> !¨È+ø¼€L¶…Ù5¾§J(_8_ýYj°ÐΕ#MYšúŸŒ)‡LæÜü}ª`]ÔÑd¾ zÿX{oþ„-Ö0¸ 9ì½hò‰†‹_¸5pDˆp»¬‘¢2Lë̹QŽßS¾ØÚ2j¿cIC_½G<$ Ya`bÜb8Ó)¬Æý,Ù_QÙÚ»à`Ƈbæú‹µhÌ“$-°é¯Ž†c@È.nbL_ç5"¾Ï>ªx7«Ì–p0Ýwyö÷ˆâ9NNˆKsËÌD[ÁÍK £àjºW? è2ЖåÐ"ËáX†e+ôëÏ×OÎP¥•759»ãô÷X€ÿ£‡÷cT’¸?³:² J£x+?N Ú,{6ˆaŒ±-lRwFÛU ¹©vø¯Ò4[«>ö~1=·¢Ó à9øRluw:Û-¾âÚNE\"áN„ÃÏ Übô¯Ç‰Õ ¼2“mtb\C ЧUq-ÿe³{¢…Iïd‹Al[ûC@R¨-šõ#Îl3X}íŒ2ïŠ<7»WrÍÖ¬ÁKˆ…õ[ϛ˄AFH<±†Æ÷Ÿ×>‰¥0Ôm›°¶¤’£Ê-|/Æ rï+¦]Ö·h”•v‡Ðí$Á’€€ÏÜ£ ßœ¨'DƒÚÿ:8޶:ª]”ºè\ƒªœðê’<&Þ8hÀt$0®+'W1‡4árp_(еòÍÁåëcçEx‚ô€¼ïWú™”«[Ëv]î]_T‚2öʆˀçí—èð‚óbelœWJÐÆ¤“†„ˆ~ËìÒî*_ëäQÅýƈ;Êžïõ*­î‰¥‰R,‡käÿqOnlå§Ê9øblYT»r ªHïÓp‘8¤Ï‘ɳ»j2ic– ² q”s^€Üª‚.s Ù#ZÔ­AÀˆ'éÒÛd‰ÌîFH¿½’*Á\à h0G8eÕcʆ’ ·QšJªi–9ûÛ±ý}­WÝLÞsò˜qd¡íËн^³jÐ$жC ?.¹ˆËÑNíê’ _í-g?KüÕU\áäÍ¿±1œúT,’šªÛ#8zƒ.9b>_m+…z±Ù¿4²3þO¿à¯q‰{ŽHÞ‹Õ¾nòÌßOÂG’ ^êØ©%£ÏÅ#cÙ4·‡òr29s[77+ÁÁqÞ¾"ø¥Âa7°ú´$%$K’¬žŽW_¡BýÃÁ«ô·-‘²øÃÚ;™Ôœ?çÞ;¼ÆVÒ²­¬’eëϘ?«Ï5ÛpGãTu‚ƒä~Dò¾¤AßGñ©ôˆ]úÆYz5j®C¹ëY»YSð;q Ý\ÓŸ”³Q9Šõaï|ë9ÏÙs?™Œª¥,õÑŒˆLÅQqïÌ|!O:XšH‚#°é­ô‡ÎæP}£PyÆ}Q eXÌôëmLÙȈ²‚¬0×^ºZZí“BOÔ1cPÖEŽòY{ëÝkD }@àŽ„÷f‰çŶá b×n  hø{¥ù=5ÂXOÈËNRéf(²c5•Žˆáûcæ¹¾-×ázQ¢Ífê¶#º’1œ“ËÒ?†ú§£N t¨ 5ØÖd¦/î.ÀlæàèI÷pûØ$_]~Ž¢—W%´ƒá“CFZVJPÓÝ¿|_sd'À71‰Ñ‚Í'zã_(gÿUjœ ‘7¢Õ±L™E-f'IãÞm9ÚÜÒéú‚í®œDé?’a ·£ì$D'âo¬„>b*n±ý€ ƒ¢!ÚlÓ„ß…àÄö€.*sá*àé’€€ÖAm©à;WH3È_5Û3Î’>Å{h:ÞÕÕmYW.jVvÎraóyÚ禄èö}¡-òcÿŒn¼4ïÃFœAJ^ÓÒ~ÔWÊ)WŒr¦ 6….¿)«å¦ 4a†îÕk™ÈÑ«áhQJ6Ff¶r´v‘W¯£]·[§¶óL±L^àŒôæÿѨ  ¯úA ö Ê"¨–ÑôA‹±¡;(c¶÷¶¬¡@G]ôÏh!ZQ"v¶Ã@º‚s„"K©Ñá:·þ@ôéö3‹H®áÇàõã&‡½Ùñ”ØÿÆ8ê7­ô˜Xæ‘èòÇœ±eïÊ) uøž^e ï·—õÕÕø ¼ôJ3!ÆŸW*,ÜßfÔKÃæ¾)Ïñ`6Ñ3M­£ß†Þž›O‚;ÖcägXJú0Ö—PÓ¹”é#Glón‰íÝB;2è;}^ àº0Aþðç’‡öà5àýÒÙrù¦¡Î«‘5Ú CâÊLÑLó o À<¼&§f,.ãó,²R,Ànñ‘miÞ`’þä’Pdh¦wÓ²¬nû 'ø& ÌÃ$)vÿ(,Æ’¶4lößi)¤èô$ì\åûW…ß%GŽuq„J©brö×ß´Çaþ뤻kFW¥ã"½äN­!aH?ùУïŸÓµëöE¡>?Ï™úê×ïýüL¸sß0ì6ÿîèP¨*.}\\}— º•ÀÓ< •€ªòÂ=¶ì…Ûѯ¹¨pÒ‰¸-û=ü„q‚ ~²=\enÝ뼚졵{Ô¢¸ÚªÏ”æ@rЫëíÂÃiSЏi?EûJΞ£[ŒÜ çéT ‡ÐB.r¤QOÃŽ½ «®rV+m»´ñ1"Ì|kΘvÆ©©°™Þ¼æ2Ò 6BÂËÏ·OëH«æ4Û1ÄpDûôm|7|1ûSf|»0êJø2¥F‰ÂÇNâ ”¶i£Ã҃λü²e³»¤$*Æ}=¿L…ö>ý’ÖSºGN⃼Žá——ÀöMÇîŽŽÑæ#Úï^*>ôÓˆVû°ƒËVSÎÚË;x[œ—%Hv†Ëžƒ=!;½¥I)‡°W2×Àãju«}`bgõYB ­E*Õöfޱwk̬@G€£P3ˆÖÑÁ-ÒK’€€Ë¬áVƒÑQ?ï)ŠZ^QªÄ÷ÂQŽk†´,æÎëî±(MÌê.¹u¬ºyžF'!œ6› ;“÷sl£‡QQÛ7yð _ù5Ì}ÞóLɪˇ¯·6ýªmß´Ž 6¹ ‚æ<cÊÈ£U2ö½Fk¦ˆI–¼îÉ´…×5·Â% ßèc  ˆÛcܳ%iª›ëÜ!ûoåusŸ ŠFºnDÁ³½‡d_ªÅè´lonN.<Ú[ ‰¿åáÑ›¦«‡žßb-Ê?½ÔÚ²Ìܽiw“œ‹zËr‚ßYÒ³%þ}µ¸ÚËÊ4Zô$ÔízÌ—£“Z= µ¾0qò 1#º©‘½´³',)˜Æïp`)ò™¤2qëð`Ÿ\¶txMã1(&˜…s-kQ4+÷@Kå|K}RÐc3šàþÚ®ÖÄ–ÀÊ=ú³`˜ù° 6Ãt¢|`pvýÅuŒÑËt×·šÇ2>Ì=üpˆrqÔBÌѹ×Ïm7ã–‚«k³IuÇi¢/Gy2¼´W¢]I`j…?W䎶K +$ëEQ~RòIóJdPÏã§­¦Ùí”sP¯í‘$„]œ„FNø É,±®i2?Ì ZºrZsË¢ˆ95îVA°”ˆ¶ ½®Ÿ3n¹ß1]CI“ÆÑ(#—_Þ/.â§=>Ýó. ®›Ãö–›—*’hÓµÀrI黺,¨7nkè*ÃtÁ2áÕi*²Ùî{å鵜_°/w{‰U»óW°¶5ÞŸ–jÛÂ&¥ToÙœûNb 6‘˜3Dúȳ­ui4éã–hbEÌ ´`ŸÍÆ,S-{Åê^’€€Þé…0ùÉ,³f”à×ñ…ϘÆ]Sbi¿$hn毴ê-r¨“Js5xLâÈÖ>KV!hœ@Ø*Û j>Èxn ±–\ÀU€…·ì±×”ÀðoF N.Êk*0ÙÙ§Ïܳ{ü@BoµJu:=Ḛ́AA­~i„m{ýõþ2ÄðÉì® UúJ¼©ÐÙÁ=t3mŽBJ™4Wzy“¾”|ýgˆO?›œŠvñbhÛ|µÊ‚48îÞT‘;²{%Qêµ?‘‹”•Àu;áTÁ6[³Š?j Ï«>¬2Å+’a ƃʯÞëæº¥ŽŽ#i¤ÖÐ*ÇÅ&!œ<¬}QᢅAÇA_о#âJð¯¯v £¯PÇÚ—¸?ÅOtΪZ•Â3oÊUÕ7W>hhP,{~ÖZë'BezÛF»÷“'4še¥©ÑÅb¬ÏsÖ‡7ŒÈ(bú?}…ÁÿƒBóß_\Œ”Z¢˜¸‚{LfY»IÈ.ÀcJ¦ÃŽ•kð¨ž.¹ž ZDÉÂþI~²ámC05¤±¿ƒ „˜5<îì‹ôD‘ß}šNYqDÝy=˜FC®vHp±`8Ñ8k0ñèuÊ•Iá|ºéª”xlCƒ½ȇ-[ÿp§HƒÞ 1~»„ŠXf'žÚP.³ƒ²|¢¦ƒVÉÌŸ·Eñ¦E´“sóSâ2[H˜6cƒ Ô sC”Ö bÌN¾ öU”Ó4^‘ ÅŠé¿SÈ@ ±}ä’€€Õô?å_Ý«Šp ®Ë=[˜ÆqWo»n²(Ÿ$_=ö)´fxŒ'JAhÈ(!6<É0 ^F—ܧE¤„ÝDWœþ„L¶ùÑM¸N}D6ä÷˪‡¶Ø7½˜eÙnSÿþw–5ÿ§ج¤Èñ¨ÈüÜ8¾E>GM©ÍŸÿ¨”•J[må(…¹Q(*‘g’Æg±ýźn&¤$$„+áY“@°Å‚À¶¶XM÷yrƒòÃg†³§±&uÐ-KèL‚¯™Áâ 3Û>é²Ôæ‹eÚyE£%ÐáÄÿ¨à”øVÜ«’û5K#ß‘IsñÅžliœ¯*^ ]ŒÏ…µº¼Û5 1ªKM¿ŽÜXÒ!zÃsj£X¾úÈ?~ëõ mŽ"w<Ó »OûŒ‡¸/»£`im1âx¬îKÔ™,`’/U©Ä¼¶ s\<58½¶B.Ö;â_‡ÒÖ³|ƒrU“Ô%b÷áîä*qºª‘Y·Â‡FXרŽ|ØJù^è¥Æ<7Œþ¸:i®¯Á¯A"ª¦) Ýà5ÖàÜXTÚ‡ÂÖÖDbúº¢2¦>¹,HýW*¥¥ v‹%¯¬ÏÏFœtkí^_ÕS”®Õ­ÃÀÓ¢"8·Ðz›v¥ý›šØ$µÕNX€ ¨8&~ Ò¸Àƒ·Î ‘õWbTÞÜÙ^?Ó‚˜Þ‡µêø~IÕ4(¦°jÚŒ7ôŸ”i-~NoþÀ+í· àW•Id¾ð/À²½Mè?£­b`téGT`Ö‹¶¸?ÓRn×nÏqNªnÃóI-ºYî”h A{L’ï½4¿jY3D¹<“ÜÉ8JÖ-¶PI­·%ºá²*ÊÌTo߈²²¯}í™5h%¤Gþ£= aÑÑüE6ºðä þNAÐ)N¥ŸÂ ñÿBVŠÍìËö»cÂ’€€À¤vvUGrElæ}B–ãr7Þ "%¥3jf{yJÌÓŸzБeΖ —þÄ’n¸bU sœck¡.za2¾qç§cÁç´ì2Yµ6O È T“ݮβd*wŠˆ+™Ðµ½ôé˜ó¶¿.7Ðy䣿íïV ŒKŸ¸=uúfÅæ¾xËÁÈmÿ@o€Ù2ñ*FÁ=Æ]âNçf®¹5cð]>R*1˜sPÏþù1z©ÅèÆdØf<#Èómáê¸uþ ŸÃÉd¸ñÇÍÎÌIÎÇEÁÏ ³?…„€ØÅòë…­Qí "é±?Uè‚ÜB2V­Ìé¶D½ÿ­Å:÷°[ô#§ <„sµœŸç^1Lý‘øínú¶Ú"k[¹¥“@“—ô÷¼w’šI¤ÖŸÍfr½GXONK>9„·Mê$Ðí‚k³¨Zh§ŠkÀ "™î®wpÁür€ÒgN=ƒÉ?­€ÜŸ2Ê2S×ãú,Ò½n<­™Y¼pRû+ÿsÛÉTÁ0zÖOl¥Œ\$'(Ó¯Ù°õ¦£è4#GÒÊÔäÅSµ×óêiçÀ ^–iª–•\*öc1%:a¼;Ç'¬c¢º67 DWh‰®&ù•všœÒès[TJ¥a! ôjÊ™Í Ã1sÜÙÎVò kooBy¸‡¤â{ú°&RcкÐôê½×!a› ­3̃™v‹Õ‹¨}O‚ p»®P¡µ¤lÊÍÎ"δ1‚,œn†Ñ'j ø¯ˆ##e# ÃÜÈì;&B^Ž]%î^À4›CMØ«‘çKC§Ÿçáå€$"Âzº$d’†šd]ƒh`În¿ÚóĹqÌ,­K_jãŸç.¢ù£žjuû•ȧcÖ°øÓLºÁÛ47 [ç4þ5úÞ%Ō԰ hTëÄ& ª=ƒ¯°eE=‹Îö’ë}Š)a½õz"Ðîa½‰>¦`u$A?C(UŠÁ©D4œg%×õ>ÿŸ6P·‡E3 nò2¼”Î.”§THiãÏÑîÁ%)3C—QáÛ„•c`ä*:ƒP§˜UÙ÷á»xÃ^»[ {ÊÝŽ:Ñ—‰+À{¡P÷:9ÊþMFª#-\ò2mªCÞ”ßU*ò¢õEÙ×~^›g>cg3бší½ˆO‹Až;³’€€Á™§zº“] “aFKµÎ”]ì E²¶NUúº-;ìw0(æ:Kð ÿ¤³8JüL (¨TzgùõÙ쇉è%ÅÜÀb7ë–EÍ)L“E ŸtÀh³ƒ®•X{gþ!æH Vø8Ý2Vî8P ºúªþ’xû¬Q9|ûãé€MbÍÖ-³£RÚñ‹‚Ø]ÛH¥¡õnð ä6ýqS¤s“N #üTqox¸fšÛÁ*Z¹ˆùÊà2ɘ.›M¤‚Óœc!‹›æ>}9Hº6 ãÛe°IåÇ*r6·€NrÇ/W9ÁÑ÷®}ß>·?^²ô¢Œ²&‚ïopÆ3ê8­‹ jÉ°ÙƒÈÆ…~0ãm*6UV±¨¹ei«êW‰Å³ˆ@K°^E>•h{zBQ5F0±2&ßá—›o›©óøk+»€ò†òÓôu¶x‡ž-3¬=NÈXg«ö³ª±aÈÚå›(—l‚[P{˜6{–E‰%Ì7i8XÖ6‚Šö¤ÁסM\uƒq‘E¤ªà ¬£Q¼Ç!ÓááÇ"Û'++¢©†æ´µ°ÌCžÈ" u̪åœsð±Í–ȹ&;æ]*pº^PKíKÊzî´,Á7ÓÂùß”®?bdV†Ogž(;Loþ›V‹ˆÕ[1`rÜaå‡å™WKX_ÕˆÐ;4³dY'¹ôüƒ? q~$ ©L¦øXÇÅh‘÷Åx‹=UÜʺ´A),PóÀWq¤—×^€†ð› yêów3ã·[¡£7—Ž ø Ä â©‹–€î_;}{Tæ;‰ÿf>ö¥uµ­‚«#Øìh’•»µÂÍW¾Èˆ']q$¾y ®U‘6À…ˆ¤c„罤·SYLR¦—rþÜ ©B!Ñ̃ñO|b´-«¢#Ìæ«£p{Ä]øœ!®)vŠ·Ž­‘Ëah½ÛŽ-b«Æ€‘Gàñø ƒüQmë¿IÌÖ2ß®Q\ÀEümj[Ô‰Ù]futLCÆidašÁüOw«‚ä•_Â=²Oôð¢{¾3AF%µð5®íר8ÒóæTî}&èØ<.§Ñ¢3’€€ë‘p°ß(2?–X9)êØsøñºº’¡1Á½ èÀ’’  cIB‡šŒ³ûÅ™d\eFµ§ƒsàü9:Ç#‘¦ÝnF¤@‚£2gm¶Û ;iÈÈ©Ü6/‚J=X©2¸ÁïHÇŒ¤|Ð.s,™Ïé¸ìò>ÙÅ#øwš@üÀóïk÷Ô&ô³@äg05¹~ÁS O*Ü65YªéáÆüÅB¡pîëÑ\ ³‘I‘ܧ© –6Hìw»xm¢W„ ~èndý. LÒ¨˜ þB»ìuÔ»¤èàìíC>A¢‘!㿊ºœ~ðªð™¬™çâílakXåž/Ie¬À5½µÖ3 ü:Öòº9Urg¿w²´›%!”A 5µØîrßç5ûÏÚ·" ¦Ò¡Teù Ü1–ºS©•]ì“‚‚˜Rç*غ±‹ò×7Zî0î0Ôr¨œ=xNû¶ŽÁ¢nOŒÓtúµÏmG°(.•СniÑ—5 оJøY©+é:ûì Œ©K¹.Š  Doß ¼D”>ñ<`Ï~"pba›K+5ÿÂÅ »I§z2Ñ•o1u »Ò!í~#xÀá\ñ6WÑFÖ›ÝcK›Ã¤¸C7Ÿl4¿nå FûV:¾÷šù;–W«ä†—‡#rÆrjË*ç÷LÚú¤ÄòAGUþè¥>F¡¹3˜›¤…©Q“_úcŒT iOÒ½ P&Ò?ô¯9äH[ ?£Á`DÔÇaã¹f“wïI&!åXMkÔøÝÆ{¬kÊÄjN|a%ÜA°û²ì•1F‘wi,ªŠ$â~ßòtRú‹ç`è4I(Ìþ‡Ìõ_T}þ’<¤7ì“™‹” K¯Z” DMxm=zñªÔݬN2×+÷7%ÄÈðƬ]b’ŸØNE5X¼—’ر‘V¸7œÞ¡©òüŸ£¥§è«}\|qkJç¶'ãFOVœ€#Lsa‹õÀû­Xs}3?(޼õåX—é•KúåI çHýÓÁ6£V\«~'GˆoôD”á[A¿RÞÀܬÏBã­?°]^`Õ fâÌD¯J|‰ÉIev±¨ž·])e’ùM¸?&š¾é"’Àô”*°È,)Eµ…z‘§ú–À§žº" ³ÿÏ'ÙÉš;yoìá™ `ô­šxÁK>u’€€œ– =W{_Z½­´äUƒå³éÏdã8j¬^æ“ém(â4#dÖA2 •™näeõƒp× g«‹6`C|3ÁK~<©¹¥ €£9AEχÿÂÆ–Aõ©ŒÔ€ˆêZ’SÁÁB‡ã%)Ê¿,|˜¢1±D1ù#+!ÈfZÔß­ŒÔ½ ûãD™,{äUöŒ¿¥+ȉ1wBŸÔ<¯Ì2³üiI€Øx>"JR/ï%_—ìå6\±p]—„‚F '<8ѵ™#¡ªìhªbˆ× LïÐʽæ<ï»4¹´gDGéGöþO–jᢸ“)Ÿ!vê&"k‚ZhÚr¡MM?«”jŸ–F&vöqåO˜¾…k…£ ´Ò¸¤Zn ?ŠË|õ³ÁÛ×¹h[ß¾ù.adû,¤ár@ €žGØŽÂE}Ê}žf­Æ¯u‰­Vqž·5’#Øå’QX áƱ‡$jØ1wd®„1Ä‘ÔQvd¶IxÔó ÄCëlFäÑÐ6¢ FBm°Í­Êä))–Ϥii³ëðªàä"`(WÿDI½©……ZùÑf+c¥aòö´¨|áÞ®J櫯ŠåæX*ÒeZ&j$¹°µÁXÐ(¸¾ÏÞ ª®|–ÿk¤«½?·j<¡ÎíÔAƒó9.hÓ.°æ'íí¿µïZ/ËmîmÈ\£F.SO²ÍʇڡuVêîü³I‰`®°g^% @îµ…[{¸ŒC/,Æ/†ÿ.Ïä”S[wp§±Ã1øAr<ôØ»JFq›â ž\¯ÿW€ýêäÆŠ—Å ;Ê;Iʲ?qåIÎÈ¢èĨQdN4‰]õ0¿Å 'žÎ••Mc; Ÿd%Ké¡­Gwͳ£øšZŒ<È a%•¯®,ðƒêˆê,‚g‹/’ˆç.bìâö71hvcáSDÇ€øú†­é ÍeûÉdè×–@E%B8nœYêO’»˜…½ù›ßi    ÌŽ¸æ×Y(Ê=e¸=–c¸R`­®¥Ñp‹;‘‚äø®Ñ€lÍJpvíQð]ë+ôüÑ~*H°¯U§n k‹ÿøí‡L^âêR¤gê2ð)Rðc`—’;•à À^Éæ ÌRÛõº1Iö. 8ØPå葉U/^êKPx › áo!éq'yýÌe´jJúž¨ÕvÒ£Á[ÝHZMšx×±y5¿¸%Ñ+§{»2:q¥]h2üOãªå§¼Í#ÎÏ÷G._ùé:6í§]úg|9y»vp’Q7>æ–“„^æ{ürs•2Á²O*Ÿõƒbò7¼F5÷³ÇáÔRsÀÛM¤ã÷f +~"l·¸ © , võƒÐþÈ–[ޝ¾4j~9Þe…Wî>¡+qÊÈ×uËÝ´})æ{ÿÐ×dÀ3#Ošß²Í–DóT!ÑIrNSdJ¸6ȳ»ÛoàDµÚVo!z K'¡²æª‡ËîìGq îz®b ¿ޏPƒRÄa*tµýÍñõ3%f‚CLÀÂr%`²Âج놦å#¬D9 uñR´`ÿ©B¤ÓOå"'<>¢81Yíõ¹¶f˜]* (Ò¡ôõSádÅü=Ë?·¡+•Wt[·Ñ)m‡+äì“ ­¬iÖdz®Œ,‹ž¯o?ÌWáz½¾zþÀ»<9ý»ÐܤgN†D„VE\âë§yH¶äÒ ÂÕ‡åÜ®»ß;øpFpYKѼÃd³B('Œ­”ýq9WªÝûÆ”~ÞHÜò*8'=*^_Ìr§qælêŠÇÍý-ÖØßìIxÒÚNæ½rEíÓßiÉbŸcùšEK(Ã’x”^ H¸}>èËò¶ûN­"ñðh“ì‹J3ֈ͗€ ¡ ]ŒÏ®QN3‘ɦַí6øøZ½ü¤’Ón±û Çø!ô}n—3fŒ,Ã0²•ËÌ3‰_jj“•ìšüîóy)ÎÒWÕÔcüaC0É7FS­£å„u_‚•Ñ:ä Ð>¾:ËŽe6Þ¹xnÑÌÓŒË)!}{Dª;nN^XNK¿e¼§4­©!ú±+ °i6–âÅéLÆ ·ŠC¿½wip˱)5¿¨Wö¯æ3 Cg{àùt[/‹7é¸û©šÓ!B Ç´¶Nñ&»ðéÀ/ ” Â¶ÖÚ1f)„º­±+~ b½»¯ØÁošøÞŠî”á(i—ÝšxQt ¶A+~wËlÞ‰Éí&Œ*ÝËÁòÅJ Äéo1 1ùó´;[­ÓÞ¨cúÔÐ ¸¾>XHí÷ötŽñ߬=WN ñ™}Š"ß'¥µXR1æõ‘ãÀ®¡¹y9sû¾÷ÙóÃì¯áùa7Âb;ýy¬ãÝ—vàdèh¤Iþ÷d*,e9Ÿ7©,2è©G(@P‰Ãñ¿Vjô¡òM£À‘F)©K…€i»BHéw–½`ï ý-FŒÄØêÅø×C»bÕayÜŸamK׆KåöËÄ1tNvý×öÏé.¢QCæí£üÎ×v­Ô¡O¯K4gã)¬×Ó'~”Ð4)‘ú^/v‹+±èw¶çjƒûº»í(eÓÌ=~öŽÇ;ÏÞ¬ÁÚÿL3è£Ýaàð³«ƒŠ˜ˆŽT(ó{€7Ò(y €.Þ+DHb™u°õSE~Ès*q4¯&™Ãéôôa¤ÒF£7ÃÃ]þ«æ#ÖŠ¥Î¶E ¶ ]-Ö@)Ë‚S'Ïùw» Â{à[pxOè‰ÄJGR—<@Õ¶pŒ¾kg+”H³QEõV`µÐœÿ¤;¨4ç¶®´bàC:Z­±Ê¥¼¾ àÑ('Nü×#òPÿ¸½ N¸œÉ‹2.gëâ°‰*Eûè67“°ã@— ä/s±çÀJ¢Ý±—óE9p zŸc½ëbÙÇ‚.0§²VT6l_@w¼€9\I–°¹âÅA…¿EÀrª?{€¿~ï” 4m- ‹¥!ù\×®Pm$¯zÙ‡¸Ñí»Ã(m±†Rû¤¤$Š­ƒÁ©MóÇ0ÎÕ:G‘öÎO×ȨE±@ oÃå«3Â|èî¼²!Ú7®¡ƒŒ —\Íaõ¦käÌ¥*²RD/@¤ƒ`“G“ÆkåÙ TmB7}¸¯Ï˜ì× ‹ ɰœéE:/eÞ¥êfæÀkL½˜å1Oúî°«‹X ¤Q% ’1ò.@ó .Š®xÝφéGžóGà2suM1Š™–4b±ï¼èIïÐR5p/á‰ù[‰ÇsFÐ/u¯FP}³ÞY'ñ²Â;zäY°T«Ùƒ«¥&—v­GOr<6‰îØ¡_\^ò"Qò Ñaí‚J´­A?ð&â´5Í½Þ é×@£E½>§kÊž0ålÐ’€€¿A˱¸#%fêØÓ3lŒ ®úôkVxæ4ô„ Êœz;¼j;Œ®VÃ?"˜eAy‘a8«mhÀŒwò'ª³ì&Ü&/zLZµñÔ™…” ñbæñ«Ü{^lò7 L¼…~ÓÍw¶´š¥Dƒƒ ‡ùu.fKp?¸l|ÚÇZ¶wL\<Ô±ï`[Ÿ@›üy‰QK³TÔÕq€‘µö’:\™—䈰¤cûýšá9-‰s›®×}N Ì=ûšOºƒÍÛ¡›”^gYì.>L5DI6gÕß7áÀïwø f9Ý· §»æ¤ oyB½‡ÊšÅnB)`gkša~pƒc‡•ëndAH®Ö )RQð—ÐèlÒ4X˵"*–XŸªÎNQFŸ.ÓöC@³ñé÷uaÕ1\ð,åK©u5/nKÅk2¹È “=*s\v`eÄÍšOŽt½PˆHØ·€™÷JýÒN®¾tf2;‚Ɇ¡bÅÔBü“{ll”¤„Íà:]¢1ª®>ô''Z%n\€r mAnk“ø3¸D¨àÃ" ä{–‰*1&brxdW<Ùvxó( xÅ´h"c´W ‡¹Ç¢Hnfx€O"—Í*®}õ´IMh‘*•€.(ª¢K‘§uä%£¨åТ[»`ß©1œͦ-.?臙àªïú~êó€Ûãà;ü1¦‹»Í$FY$ ±=å‘aµˆ]]º %¥Ç{p×÷kÞîÿ×ÜS}1q/EÜ_§:VƒÀþ3ò .€KHº”ÅSàa¼+ñÐã 9‹dÜÙë1B† ~&Nß%Y(†»–°\U4^b¢ÅvÌmºÖ¥–eæÏxiÑ7¾ÁØ7ôûܪD+–èyM *éK½ÔàØï‡¶ÃÎÀ÷xî ñ5Ñ”# »–ØZ@R&QÃÕ´Ív’±@"&”<•Xÿ‘Y­±ƒ9N ä&˜XË©õ/oør[‰_–¢kÕ­}?2·u¯c˜Ù©ŸÃh­ÝÓ«ÄfòǺšzwÁ"suè95,¯Cþ;Áª’€€æ "´Ûñr£õ.Kø°'t>.ntP¨!aëËŸy±uHÑ—Ô1QdÚ d¾éHE’+¿­)E½ŸA^Íz…ŒUì~µVqnnVÝëÍJLÖÎþ¹ªÜ•ú‹8šhâøÙvO;^k&i  ¦ŒÄ/ýŸ3Ëߌ€œ‹ÂüRåãA&! Ä ›E?³X³MÊ«3K#Ÿó¤ Ï*’êë<9{„2ó”R"w»àÆu`æš"¼e_ªc.õf2ÉQ¬~mžª7b’þßHûCäŠØssÃZRfI w êšK¬ŒgC9fÐöÐÙ‚áIŸ×Äô7|}_;C'©»5ø¦µšõ½S~,õ?m`šn\}CÙ´á½l)¯Æ7o—NRƒ$ÿƒ!ÑZÒ",Á¦()°)3D’uIœ°mf:„׃ü–Ùæ†ö컼³k½—§wN oêaaƒNk¤ X)Ý¥Êþœ¯\´£ðièð—6›üͧ-„ä†7ÅâüïÉÇ_E™ß„Y3G ͕̣w¯®¿÷ÇHOǾ¬£%± LW®²z&¹ÅËô·>Y£!ÑòÅ–âM¼m¼­€ôóÈÿ³êx«-ùûµòséDFs/Í\ƒHáÉ£©È4ŸÃ—¨eÖjùø"£/ÂÃØ‘ç5˜2¤NŽO®Ï¦ç£l_ÌêöÉ¥dFùAÉI¹^N/ø¢,ï>=”±…¯?qH¢1¾³Ý&†°ÏV%^µsOÿ¡—R° žd¹«½’µòë!“É­FŠdÖ«~y§cÇmÇCo­8•5‘9/#†3{ÄwíaÐUÛÎk¤›?q$ˆ/¥Æ7N@/3äŸ"IêâˆÎ©oàøo+Ú×Ûx¸1 ËTp1Vù%Ñ1ËÀLÛ«êö€[KéÕ€bè]¸õe”³)Ì=}ó *ófl†©môþýýSl Ž'Üž)—ȧ†TÙÝaT¥ð“Û®•`”è}}ýjŸos—Å[TT”+õ˜Ñ*TçͶ*Ü;g÷zrŽ)¬AÏœ)CºyÞD–ï£ÄÖ(·Ç1hfY‘Ý4ÚÇËAå`ƒÃUõ!¬,#wq.jôM“f] ?BâÏÿ㪪"u¼wÏ6 nRy!ª‹ãs”oºIœ4sÌX„lÖ’€€¿ËÄæ-8’ƒz6‚Ö@2ä×W»˜|âæ«¦ú’Ùþ¼JG™ÅóåºÙ—–Ãù¬;8¥jÀì¹hñHÅ#רV’÷vqR>TæGä}7†ëdÍOî´ a)§ ¾–§:“›”yS×ßÜn?;b"-ö¨ÏƒóZV©X‰ø$ÂÖ~Nm$úï·"z—(ºtÆSLæŒQïKFã¥nS:BÙt˜új\^sÛÏé1¤ù—/˜Ù(ˆÆœO`þ¯a V[„ß­!Ìš>If¿o°As¥¼Ãí‘­Zõþå‘a« üþ}3&î¹pÏiÕ,¸–ëæQ†P!ÙúA¢r0q*Ò_ô˜¢'ö°-û¾ÏR¸J¡v¦%Ùɸ£>ø÷ÛŸ»yÍœzJw»_¨i“œù)›ªüÄ<ÎJf„ÊžŸ ×7«íŸ°*Á9‘Ìèõ¤®Z_@~±¿ÄÉ*©ïÆ÷óWžÜ8ñƒjê@¶‡àGH¡Qê%Ê\+vBß.¼ð-Ž IWÏ×~§]RYMW¤Y¤NùÐ0¡Ü£_p\å” ÈW¢2ÿàF¥/âÅm½Þ¢P2‹Ó>@+†&ûÞÅó´sF‚­/ã€Aeê ‰µœ¶ñ'I jÁ¤üÓ ´+,^¿_ß¡*´$î{÷ýœ Â’ÞVÄüéÏG„ Ò ¸Aí”q‡ys+x&¿¶µVÇ#{›± ¿¿¸Ô¿vÀI+Mì› vT}x}}û+"ôÛ°þ^ó,ж’ÜA±îrpýoþ{]¿¶¶É¶…ëƒEžÆØYSp£7p!R`ýwP%çΪ—å¾{¢²bJg•»Ò±.­¤³¶Ü=íEI«¸«Ö›è@m DÂa;Z޶u¯â{L‘úLå¯]!ï„^„ =Û?°!éÚ7… 6Ž–hŠ‚6ÂÀ ß.¡â^xºîÑ¿Ë ap>ÙûþôQOj÷Ÿ{4ÍÉÑ„Ôuœ>›„ §„Éÿà'´®cžýÚ9Wý•÷…¼]u[ÞéFZ\z•2NÒ¯¢’íú²±âHv1WVέB·&ÑÞ ˆíÞ' :RºEuÛ¯%!±qÈtJÔŽ])Ëw>¨³½Î¯[ÊÑ®ñ‡úèt€Gpx¸• WÖêY’€€Ë @wlõv!û}è—º9º¨¶å'ëw‹øNIÑQlhœg·ô'mi šOÝÍäqmŸŸliP ŸÛ0Q|ƒ†"»K^kWjWE)èV  ß !&C—Qo/½šý~ÅÄ#'bȨ»RMš,ó’ÀØÔx–¡¥¼¥u,·/REoø´!ý]Sù˜‘^¢ÜûC8Jª ðã&Û¤+§±`ç3MÊ߬ÃKž•uÍ!Ȧ0.Rµ¥"èçbõrU"ULŽñÊ×dšOµ?­Ãè¶õÛå}tö½Tmpz†óûA 6C,÷·vÇ@%ч§#áõ3=Ãï§ÔæÆ ”:­@FŠsP©ãÖlþ0Γ}ˆ³n!ìhµFõ ê¡-… —¢µ¨hÛÚ$æKŒÁÂeÆ’®$õ=fy;ÙCï}Xò„¾›C)7ðU¢ RU‘2%.[ƒ¨}iL5¶Ü$ªÃ¹´x}§lL{•9¹EžÑçY¼ü=ŒØFŠnçKfŽú£Àfg#BÙà/Ü.yÂö!EÛàâÃ`N¨¶ôd¬ô"ÀU÷t„Ï?”ßòdè´É3¶ñ{£LêÊN>Ê`7“Ô$²ÝÁBMú’Èv'™„<2¦Å@êmeuÌ«ÖIr—•ƒwtØÊ™j”n=5:ÛyòÑ­‡ä[þ¯áØì“_+a ­{¾y,«$6µÏÕY‘óÄ&‡×ÿ}š¤Bö/ägcà4GÖQ0’Ð/ ôø/©ì‡BRêýÂŽdæV A:º\ÛÆ8,Ùš)]†¡f^Œ1kH\<}×±#ÁoIœ™!ÙÅ«4¥ùË'v°Ä„)ÍsFîMƒî­ªFùvôÆŸÂk x €áý16³h,d!þŠ@¡¢“š¶œùúá¥7—-}ÚZó`]´¨ÕE†cðÕ`|•›â& ß0Ò(ædµdï†úƒÿ)þɃï.ŸjjåJ½ðñ÷Ÿy©¼(~gL‡‡4UAÊïQpµÕTüÙ[Ëi:í Ÿ3ׯ fnixÉô\îÀáð.êh!ÆÂƒ IP¥ÔxLìú¾¿ž—‰¾õmxOQ3†qQ›þzªÄã vd·¿báRÀ½]mâЙ‹]Û×yĻԉë€RÍCÕŒé4'(ŒýŒºÔEÅêZAÙ«eò|ÁÄþEü”-‘Chñ8ØÁI·Ïã(ÆF"'˜ß›ws'(3šî.Ï—²,uµ&áqìÔGò®›ñó“ÎF¤Ç.ü6GœDb§WÒ‘#)ÂÅ î_>#¯;UžÀxÈUD1?Ñã-z!‘ý*ïY󺂩3´/›…ã UE6š¹Ù-Ï·ôaí‹AåµËmHÿŸ «eÒwz9Üï€ßt9½%4õÅ¿Ï7®ƒ ȵßì!ÏÚLÙŠØçÏVñÛL…‹tYDÏ™¿â€”6úhf7ÁØ1õ‡ýÚöN KVzP6ývhîµ”A´’“Y‚”‰|î3?k†¾b4Ä¿Ýz€û¯Nh~üíMX[X wÿºBûªr]Q:;×’_þ3c=Ö»49¥ëPÙ²ñnl+ì&M‹eh”Ìž¾ˆ1=MK8ÁëÎ¥hÙÏÿßíÏ›Rlùo×PM!Í|yóƒîC#Wnxœäc¹TÃα^ÐÀ¿Ù)TjiðIIC¨YJ6LA;kiÃŽƒÑ®@Ü ©ŸÁÏ\Î(ã10Ÿè/ê è.ñr+ͯ’€€äöŸWø7îJ¦r€úÚÓçj M;ûÌ×]qEcöõÞìKØAB,öe‘ñ#KiŠ*.å” zí×Õ¢TPsnªËÂÚ m¤ù› mœ[Bü6;D™”Y}®$‡ì$L4\uGS‘Ôf¤„BØ9¥*‹¼7Õ=’y'¿ÆV6®ØÄé²û‡‰ëÄV“žè‹nýDz»BÕ]Kã@ݧ08|ýÊåBÜÀ JÚÄÖT8S6ã‘l¦k¯.ÑÔzMugþØÖ\µ•çå¾xhï æÁÛS¸w˜â ËP„bN;C^“ó´êpp+ß³{^×E±…'¢,¿sb9Iìs8¬?Ó(뼫05J½†åOcw6]Ý +ÄÆ„Y–l œ£À‰Æí‘ރ˨1n¹·ÊÃ]]‹Jܰ”… ‹öØmB#y”¥_È&úÎúÎ$â¸?öTYøÈ¸ygm7ç2%¸ŸËpÔi@íˆ_)s„Ÿ,ç4ÞÒÀ¬4þþ/MeļbϪþãðz`'`Aƒh,+à ¼u3g¼ 92-_àP6Φo²,=•ÆKžC1®*é*b¥´Ö¸ˆNSîÿȱ´+/Óˆ‡«eޤxÕCé´ªHAÈ>~G)x0x%‚Ã8|N-È6[b›¼õ #½°f…|Úù¬.àþlÅõd3¥žÆÿë#-9¨X Xb@•øì7¦™kE”Û2àvO£#ùg |yºš†Üî‰ôû%IòuŸ@f'øìiÙÐxµjŠ‹g»uÙD}&(Øm6^Ìzu0Mý@ÇÓ°îÐN "Úiðh—_ìOB$ªgL—¨ŸåQh¼üŸ5úX·¿>HS‰›lǦ$ܶunÉ…ž¯pW†Kœ†Mˆ·úøÉš• ṏ(õÊz]fÖ„ί|µïõ:A¹c'Áé1'Ý ®Möî ÐøÎ’€€ó|tò\ c©Oó²l-pà$JL?ļüûaÜa,(úÖ˜B…¹á^P”ôýÈa¸RäQÓÍD N4ØX3Ê¥ÄøÌžåÞËígS÷q—„ør!– !1Ìí#óª\´U¯äÛ.·en+µ9Ä¢èj tí|óדG~Xâ¡·ÃÜòØåŸ¶QøPW‘Ç8™2E66°ŒJA¸ÎÀ>¸$u)gÿ(Jo]ž =öNMæU:Ù¿¼õj‹°RäÖŦº÷èy£2_ó2sÕc;É,A¦¶jIÿ¼‚#dKRl•þp)ê[#Šÿjˆ$¨<–gEاÆ6-Ž ×»ùÛª*³VûnGÿ;|†kZFrªpɵ‘± šYñ~¶…ôw¤šên¬=6¿¤¤»DÇ^ 7N„ÍÆÉ…bµh½@·©K˿ٻP•h¸ÙÊÀÞq#G‰üÑV­»ÐiÂðÏL§Ì Làx´Íç°èÿ©TWÚr¤ â?¼ ¸ PkË«=@‹g.Á,äÓ)%«C<ÇÍEµZ Á%VÎzòsûsÕîëH&…ÂÙŠ.}øÑøÝ»Û…öN¦òo´¡ûM\z%&˜È15§Ê*ôòwø,xtkN¸ª$kAD ¬|J§®pBg*Ǯ̿öRPcP}ûŠe ½2:ÊHñokk5žú’XpBÕ\¾šo6ªx[#†.fŒJvS‰Ep–×!H Z" @›¼+Ï?#Aà pI¿"ž×)Šo›ñ¢/V ž•TC^„'üÜÖÍNöÅ~¡”ÄÞ¤öê»ß•ÿ5AÎlx@ºuÃz^zñk÷Íâc·ø‘Ú Š¼ÒRïˆ$‰9‚£­q=¸aé£8†2ù÷pävvÚD_áùÙ×-©Ê6Ç»?§»²êÙpõ D¯ ßž5—%î¶pZ¶Ú²Ò;õ#4ÙWÅÚØôýµN»·8ÊäkÞüñ/NŽ¢yâáªíùfMælú4õ¬`E]#D"ß ýÛ‰ƒÕ½Ãb¤; xš)óòH+-v–— ^ ±ñ06Å?»‰Â÷HjÔX Z]UAÙ‡§óº×Ë~O>¾Ïî+G ðè‚$VÌÍÈØïnÕ«LI!›G4XÇÌí§}oKGg ØB:„òéÊŒD’€€Ï@ØÀ<¨ÃD>mŒöÊ¢WÑ ü‡ö(oƒ6êYÙÁH£XGÍ•º¥ïMÂôr[úɸRˆ/ q¦–íNžŠæ ³©°£í¯Îš¤ÕüÍ0Åòº:tõhÑé=‚èðnAœÊN·»§£vz/Š2)E·"Ո˪Ïî‘õ5ŤU8ÇŠ3’·>Š]©Im(`[iaî§wHö3Ƚú™ð¯Ðü[ãËM’ædtõ¨—¼Eí¼¤þZ|6SÐCœm)¢O#`À,SþG*ÿŽK]Ñ;ªÑ;Â"R•¾~òC¬‰Mû{y| ëXwå”:41Ÿç¦³'©Ìn¢#ZÅÞêeܾz«¸6x<ÑÈì ¯WpŠøÜ<šøÄœ¿R‰Ê[ò,×ó"²¼HØoçyâ¾¢IB—nÒV& Tu±F›ú½ 5XˆðWÚÎJ7/û‡ ÿÿ¤ûMobZW Ó<Ó`¥qÍ;ì#¢UÓJ“ëAŸ!5¹†¾Ê„ùÙ*wt‹Õ}ì¨ÝӹߢÔ>Æ×ç'%Š¡[º@cì”C—þŸ Œ«aµ¾ß¯ }h5úfcÎV›MÖ¾IÝúü+D½.ç]Ù@R‡ùœbK–&nJíªb̪[®¸“ùáMÚ&¸†I ²N(0…nRDt.³Ôí,¥qèØ<åìâüŽÅÑ{W+dÅ—_B£´vˆÅ’G–·¹:å,1Cø-+½qEFàuc†š„C–xò_£ oàd‘6‰-{ÐaÉœ|Rà{ÓEœD‘]ÈNCɵJ7'Öìœ-‡×ßùĦãð%¡¸öPÝ>P;tÆH Y0ºJ¸½%¥bqÎQä^hÔâ§ã»ø‘S´mÌDŒøÕt(œA3ÿs7p¤sÊ(ƒYç“çBöÊ+DR½BEäÍ·SÉûÒ6ex›,„ÄZµ²*+K 1,»«žWg©(µ‡–3¡çÌ´çÃReTœï«SeÙ¸eGû™Øð F2)÷cøCÚÄ ]›?Q•rZ;XÏt`]Éóö&y ÿsv<>ÂNÑù÷J›.M†ÿ|ö¾b<ȉØÖ|ôÀµ‡Süç4ØwxT¬‚vìÆÄx™Ì¿,4æ_2W ºÁò|&7Ø’€€Ñn~›ß ß·»ü'„Šßà.ôoM¸i©s ÚóKêi³&ýÃd@EÄOöë><-Mcné EwŽEÀED¶ôÑPžZ-^xÁ)M¥ª¨ÉK—iõ>¢¶ T‡jYd[ÌÐËÄBÜæÿW\ ¥êB›?²)÷L¨Ó;œ™¤vëgöcË’ÝËhª $ÆÂnæà±5®çcw»7Ž{ßF^b;äÎ]%XŒg¹^¹sé{]-" m¥²ÎnZå&q_úPšk2¹w ¬Ú]‡íªJúM:ó5R @P‹¯ÔXUÙ\ŒºÐú\5ª‰ºo†6J:LXè¼ [é´Q%ÿf·NÕ›0î3™q®\‡RT§ÿR5®7Ù@}D£ºuK#'õÂFyÇ%¾*Ï"¾BoIêj 0aËÅ«u©ÙN\A?ÑR“ ™Qeûþ^í+ˆ`¬ÕÃñ ½ó]Å¡áO¹…8¦CÔÃlZG2aÞŽ˜Ž!~Aõ·^0Ú‡tÖåuœëð–¸#U ¢ùÜ•+ðøSAäXñø i©ÙÙ¢ù õb¿ŒäÌ™XC³T§C„ovi‰_žùà‚=»5¶+ÿtFºÊØ’{&ÿMÆsorß9¨’ ÿ]ä™™³>úÕòÿt\KœM× Rxôékcñî½³Wéh%Ðâ4lÄæ4 ÅPÓXk$ßC2?×øtßÉ´Ùà0%Á¸væŠ'EÒ %Ÿõ/e-îÄ­åÝ^¿C34º>ßÿĉqð™QÍ•RY<KÕŒ;"r¨9j¥;… ‚ö.þkÎ[Âê´O1ñCZ—Éωíà’_öëG`Ç¡¢ž3\Í2³òs”Áæ‰'4Üý§ìõT:Ñï_”ݺøs‰³ÁŸU2é3×àöU.è¢ê½7Gìf¹’ƒótôªe)Ø üAzBBgjKb¯J€®Ñv&ÎbÉÕOI†‘'AþH<œ³ÑJAf$yŒêm8¹œ.DIsíÝ<×èÉýBÉÝ{3ogлz`°ºª Ë^CîO±¿a]aŠ*x¼6š¢Ÿ--)º˜`ï^M?‰Œe¨OÐjòþ*‹8„à>î¥qA`ãžÄçÝ õÜJÈxr7FÖ€åôãt¤“©uÖ‚°%LÒÄ^y2’€€¼9qÖ5…ïÏgø‡"ÛWè^^B6Ų´úgßI÷F½ Ø™(‚´œ_¡¼9”äbÆ«)íK5oÖMª¥3¼ªì¥“»N–PqÆ´:þÌ5™‹®2˜DóY?Z2+/‰*ŒÍÝäÖËÔªi¸¸)6œa:›ÛLøךj‚ùÌ3K‘ºÔŒÇ‰›aùð~סªNÁ÷p ×ÚÌ}Hnªì*®=¨:imo]wÿ+ï:TŒXêÙ>«æÃÐ~|§áþlý/’ï…å׿íû%ÈÆp4®§äÚ¯~ê¤g9Æïÿ.a¶7åŸ,Ša(­±Ûi¥â—mƒÄC¤Œ'4³ç™ ÿ‰OQ((Û/ÚÄìÜöÅðM¤†Ù3åj5Þ¹÷¼„<ž’â‹áÓéŽ=âvy~âa Çë*³drÀïŽkT¨ÞUŽL_Wð”/o`“Pö8³!¶ëˆóà¨C‚Q(A9ý-žOqs}¬I¤bYfÎÄD/´,^&ÕÐÈnòàlI÷L“ý׃°£¯ª¤* ¤¿è¸=ÒV,‡ÇŽíÌð‹§¡¯^õ¶rœ¯†²Õ)ý¤‡ã†ûÞ "ïäJACm¢~/7 ¢&C¼yÏÆ;³]ýÑ”p ¸hý2Y+;fRúq©>Y ÃRè­,Í]Å–1æŠ3ì¡Þ-xaR(w`€Oƒ[ PKIp Â<ý1Þ1ž»,þoÊ gZÆó}åfË‹Ø^Í—§À m§$G 7ÀðH‘åFZޝeècRÅí8_sGÝÑ”* c?4„À+òå3zðó”õhqýâœRø £­aÅ ÂR1?îðq¶ÙØð¯SeÜæ ¼$:ª®ùô' UTtÙAkËÄrYŒÕcŒÉ&q€ÍP›—#*8ÚÆ6ZrÙÁ/óËXÈ@“×δÊÐ!ïç¾ÒÑ­ÓDŒÖ-ÕV<ŸÆ¸t5€ÜÀš7êOãËo(dØÑ‘ÈÜæž2šÐdØ!T)úÃZ1¬á7vüÔgN¬óó ÁïOü&4tqùƒ,0‘Γ|²9Õ-Ï·ÂV]c¾†¹ Žnë G1qà F3ÃzÈ›hŸ•ÎLÊKAÁ½›+¦oÍ•HT¶¢éè)žÉ´ã×àüãYªT¦pò „ ãõí×î}z°‘SÄQŸ,¾nfF‡š[’€€¡þÖ¿9z¬}ï@°Ù%Na¹$ ”SssÏHÇ&˜6LÙ¥ÙAíÌ6‹P~S—ußâv}Åg5=ÐEäç¸ÅƒîЀýs\ƒr9‘„H‚»†\"VØÐØì²~±H¡»?GkŒßî Œ®|iï<Üܔӈ¸¥®þ°Cµ®%Ý{¤dÿr%“° ¦;šÌïÊîÖbåÛ÷éSñ¨Àx¦^©É%¡Ôœ¤K‹1×Âqrüuë9¾\ ú|û®¤/kÙ™¶çœø®V5,  …Ï6iàKü£÷õƒüB"~š…6d‘Æ/­ºN9²&q,^PÊbÉ)EËA,¹hqd¸0IÄxní”ñM„6Àex…12àþ‰óº|?×ísYbäêsYÒ ãV‡RUÄ9ÓY'Ãz/vqU‘ldHÛ=8àá8ûĢ逤ÝÌ»I´FLŠ+jĽk<ä cHÀ ;—B oðC0*r˜ ”ä0;å"ì­J¹nz€©Ÿ e„¡ g§_r”Óe X§tŸþ%;1÷jÖö˜ážCÇIÏyÄ„ºÌ(@¸ EÛUˆ”¹å€¬.™çñžüyê¼þÎÔê&¥š”e:vÿÉ ŒÇtZ* #0òy½I‡D?ˆM„`[&þ³Åzî'{온¡ÜÝ~Býæ c]·Êñé ¨‡Ž”`ñ^lCM–åé¡* ÎÞˆ£ÈPkûàMÑü hÄãÆ}§õ<À³T2)ú豪ÛÅ–½KÄ;þ‹$#×K„J Óº2¯ÜRQ¬8{;GÃgöÒ%'yèò"Ä §ÅöÜêà#=ÕÜÿpüÆX i¤ ° ™\BÁšU*wÙ¿<Žæ=%9µJXØ’€€»˜+u¯ÊM?Í[6>š¸±Wæ r 鸳áQlx"§‡¼BWùÍ€½•%ÙØä `äÝ)¢®V($bhHA-Eä¨ñœ»ôÌ2ê ‹5ë ˆ_J“_îRe¸ß'Û!ËŸøl7ÄEg'3¼Xóiikh,gXHtÜ8Ä¿CMo{2F¸`’Ü @õ*á•Cyg*p¬qðSwÓÀ`ã¬Q2"öuw27_G‡™Â‡UnˆcÞ3ѧ3‹&ªÒ oèàAùø•°”&=iÍ­_{%¤4™oræÁJíÓ¶àRX&ŠøB3B,ö-p½ûúUHãß±å)1¶è3æ‰òEù#Û¯Û@ õ¾>BózpNÚ›S‘‰‹d9)¥…Ý?ƒÑMÜ +Ü¥ëÈ=¥•ÆJ9{(’C#(‘ð$ÓkÒ“ºƒa»o‚a‘£BiŒÂÒ®ü•WrMëÃßzvÙâÚ]ò>*¤ë[þ\MzV¶‡ÌÌ0™ƒ¿xGë %ÊÁRË{/t°<{·‹¦°0zì×7Q‹XŒÖkŸžÛˆj5ª ¾íô_mDò©8Ž¥x·$7¬Š>Á‹3‰¸èP«Ö2×8\­± æ¾Ò˜ÕÛ‹ËB„v˜:¢ÚOV|`ý g1>ÚKüèHÕk² •ëù^eÿÎH«¥®Sá»NÌ1¾ÆÚ¨.Gûcinì*#‡L*`l+çëùè]çU"È›°‡ÃO¡lÑwÊ‹9vÊá~´÷’€€¢h¶'TÖŽŸ;5<0 ,•˜¸¢b‘£"¼šÇùiÂÒQ&A¨IïmÎ'½Õê¾ß  ÐÆ}Y#jv®;©¾9i ñÀ²µª«JV‘¡æ«z-sð§¢/uDÒÇÂ:D˜ÿ9ÚG â²€®à;Ju 6æ ï’áp0 µošè*ek4'&øæ™Ü<HÜÚ¦!ד$¦¸ÜsáhåËõ Ž#”W A%QcÓ<Óä7ŒÌí!¨!cZ¡#×S‚4Fõ-£zN%Ì÷h².І½Ø{>¨4¡Ù–pFàpœå‚ÁƱ¾¯ÕÙ% ŠûëççâájX Œ6eÕu´ƒaÀ“&ÛÁ:нó¿5q†Œ#Tê"q“®°6Õs´± }ÿS\Ask`^ɳ:[ö+‰Š`YVºÁ òPZÌb=K+ßlÁ®B—&kÕ¼Êö»šè$B³ô¡?aëÜ^É)È®0Ùçz´5æü`,Ÿ$§ñU~D¨þðO ºÚ\•ɦ·Ã‚”C S¶îi£û„Ø×µ]P%&¡/ù›@fPOüÀQ<©Î;Üxý´ˆÐ’Ë~}ØÚ>€çå Ôl½&ØQ~Ün”¬#¼ rçµH 3VlfÐ@ßri·à߽؜ó‚ŒïÅ+Òk}·¿-0E€/ì"[Å×Èž£ x Ý¹7“®@UÕ®®•’‡Ycà×‚á ¯ëlÚVKÞ£­Ö*€’€€»Ÿ›-ë^M×p±,·¶]1²ˆÍ&kV›x¼|ƒ§¡µSûõÖº¸u ¡:wbc«>.y| úT§eo—,Ÿþ¼jÓä$òFG²7€bÇðZ™ãaM+Ë®A5¶ £äOJ úWË“Þ3ê¯Z¯ hî;ïy|xc”`Æ©?áÆ:­*2¥W›uUÞNYªð;Ú"<6É€Üô­$¡ƒÀî–-1F±Žl¤ îäxW*ÇÍíàÃà)ÜÆ„ì'¹çTíÀTYŽŸ¸íñùI²ìS0aÃ#ÃðëZ^gñÈXM“CõÔ;H’^m¬à9¡۞䘌z浆,w'cV”{\·vxŠ=†AôîñõîòNÔ£—þÉȰ^ýYÆÉ§±Ïõ >êN¦úúŒl¥Þ#¸¹:žoÔ°œÑß,&5¼Æ\Ì"=;ÃZÓ€°-dƒ-Ó\àE‡½‹.Ü•Ãán†È…½˜$KåM„yº¤—*B»A”•x·È|Cuð«W6¿ð6\”EÆ@¿yN7Äül$ã6̢dz ·²s|d„ùºÄÞSÌ€Îwþ”ã HJVÿR4cDÏèéJç[|ÀSqˆåA«Ihö \Dç„ÄŽû~!§&Gó;Áʸ} 97„RQBÞ *Ò…DB´'uVn­ˆx)‡íÍÏáìÌQÑô¦9.«qñòžìW¼ƒLÌfìiÛÀ¬‘Ç´ѮéŠqÌùyØó·Å(—"ñßOÁ9õ‘2/»“7:_h±1/e»šbYO7R,«âŸ­š¼þòD•Å"ïóƒg%Å%l‚Ÿ"ÒÇèìº÷$:!³øfyˬa‘óÄT¡úr°X§s¢ çñ f§Ñ—uæÌÃ[ŒrðTí¨ ê¤f·b~ÌÊÃ,òÛR-ÍûÞ6c4õ’vFÁ•áhE6#N‘¤V úœ¦ž!ס€ä$gJOŠf—%õøÿ„°ô½-·Bœ6 ,15¡?áØYH?Ô¼·“Òlþzxvo®{mgh² Tú\Ñ©ÐÞåú r‚·ÅÈ™4ƒ,4å0ø±­è•Þp£ÝÉõú(;bßú¾ó /+Ã/ ÛPï¤oˆÿMÙ±nv µÏµ_ ª—L ²á,>)Cå¯É*ȸj‡?`Ì’€€½Ÿñ˜ 1R)ë¬ Ù“2aÎÁÝõ†”~$Øh$â‰¯Þøz°‹CŸÍP€¸ÄGÓ‹wß•ƒMžwßÒcJŒáÌ5x+ÂÓ*ûmî~åt» pÃ0¤âû†}¬ Ó ‰‹Vèº Íæ,ž?Žhòð#’ ÎÜOaCÒׯ ñUìµP»ÊPvªsÂÆj…%ç\•røâ„ª`ý6ø%(ßÚþ4íÑPHm“ꔪ½á4*'B~å'%sl€£œz§¦¿Ò}ÍNu&à×¶ê.é‰íüOD@r—ïì®Â€Æ|#õâRñþã~&‚±ŠS8þ8¹ðÐØ¢§Áº…¯ Tt¯Â¤Œäû"[ÞÔü8îC‚ùì\¢»$'«èÛiº=àH¹c`™ÔŸCèøô+Ð Hqã³èÚaì^Ñ´Úø…@J8;ïÜðWfEÐE-{™Y÷‘Œ±€–zõs Ó6`O×QÅ‚çàŽQþe°ðÿ±`\Ķ( S‰§@2¸€5Ï„ÁÚñÃSÁ÷øV»`<’ãñ1”®ÛL•n) EÞ“–—ºÈ4ÿ¡`¤Û˜â§M~ÜëÐ3E@N;ÊÙS®ä2Þ„å®—†‰ÎjÍž§y6ÊÁQõ×xÚ¤ÐJ¼b ·aYês"‰«ËðûÁíuá)òuÙWIßl«]”%-¡}ÀIwsÂKg‡Ž«ÍÿxnãJ.ζӺñþñ`³ Ù=§‘5Ð?ñ0Žƒ hJ`Úølš‹øwX¾1Ð7§ÙKm¡cGÔÐ~Ê~KÊuâ%œó;¶AÐ"w"#‚9ëMÕPÌÈgA1©ñ|L¦Ám¡g›Ï²ÝQMl3z§¶(ÏSK`èˆùŽì "“•çxV8?Àˆ1’Úˆú."2&F<7è>3Ý‚67u2LjÓ*l>Ϊ’q-Rj R_ ¦n½^νkž¬É?OÂobø¯²õfxÆçx Ó(‚(+‡KÓ>µz ÂꎡG2¹ùè¡a9ÐV°kÆ•Sr›×¡P¶¬»}k¬¶9»W›¡pÞÞ ª<ßæPPŒŽ1¼¦FêEM\-~¢äÊ:G.›YŠz-ã$È3t" w»¢dÕ}{µO’ Zg¶’/äíýÐD*”gçlpi^ѱ—•F!¢üvÄ®9wØëôD¿×»Òý©Ùayãb+âÆœ¦"kK7‹w,~Æ…â-™MJnª—m˜{^\¿[|¼ÃîÎŽ¬ø¦r_UˆôûmAm¨•2Þ´Wæ ÓwÚÎaõ*•$~¥]—N)?«ÇÙIA. -” \çåWN;ÂHåÂüŸ’€€½¨¤ ¼shІ4f-o¦b<Â(xÝl ãr—´Z$¶ÈÃî‰ë6ÑWȧ T¾New¹•(øy[EmG®¿·¸ã¶<2ÅPiÝþNêF¥ ¤©êÚê6’*ý1Àú¬ÐØ^8\/ì2õ«Õ€®uÖr¾;ÚÎÎ]äëõK…—û¢ÓÁÛ6äa …!Ø/-Aa',R%¸Ÿ¡ˆ“¨(r^PwÓ®ä]Ží yÛa×drfºuØsEý Óìæ@nžÁeóaî„6ÁJÞ?{iJYÆL¾b<˜ìÂÇ1õ’ò Rº$Û]÷ë£[MÓ°•uœ­zN¯¿W²¼Á†ÜàÖòQCìNVVNòB>=ùʯÀÿ¡È”4?SÂâ×±®>)IÛ4´á|l˜Ÿá|¦cñ ?UíNŒ—;@­à £õ»d“ˆÅjž¯W‚âv3HD{‹ó$GÄý≼¼¢Îe\Úõ™žÿ¬û€~CU°ŽH4\Êuu]‘o@Ne%õë.a›áàœŽ8&ši˜;ÒÔ•¨}ˆùAÔ ™…éq}Eã§&&xÞP™‡Û²ô5ã=Ççˆ =¦ç—ç¨e+®ž½hÿý¢”ÔtžÜ°H’)«õÏ2×Ñ")Ø8µðï}s@,¹÷4´|ókóvƒ%û¸«ˆa_ž)+-Ç\#ÑÖ|ô殉%JeÃ[ˆh9gçsÊ 4 rãâÁ§C¤¦ºŽG·Ä“uÔ z.e\*]zÇ×]­Ð)ËÝ:˜DóYsŠ>Yù˜ß}éÍšQbã0­ Îdžû_ócý§´Î$Â91ü˜YìaÏYÀáêyŠ+«IOÔ“=¼3Õ_)Sa_¡Š†s[]cD ôZÍÁðDø9§4^ˆµ/íb*‡B ƒ¨VŽ. ²dþÅGæÂ¡«Ö îL";H-žâC—Ñ8ó) m?õd©o¾šºu)hT•†oPœ_gÍN¯î?"ʸ2è§cáã­ýe¾q}p;ƒrŒ®€ºðG†¬žiC›žÑÝ‹’vç¿ä$Lq5säAH`„“‹„ ^ñ„x¼­¿IW7Ân-²#¹NÁñî 'ƒ´t0Ï4)‡Â’Ét®c&?yè4Kª>ÔJæ™XT£RÞ:é\×h†>ÐÉõ޲RV`d18Ç’€€¸OhÙOp 烈 ²}[/û¾“ˆ ³=ö»tûoŸ“I±Ëf–ï2õ¹pýmlU‡JAÛzwÕóŸ#Çö˜wW ]ß©ëËžâôÇ1}â!ƒ)!=XŠ d›róä.N#ñi‹Äy¹®Ks¼ÐÚ ž2a‰)°K—ÐaÊ“(‹(Ùc‘~ö¥Acz;H¥Œ1JØja¬ššQÎÂõ§,Í5uìã$ƒ3}×öº|Lü8s¯c]Íô¾;?ÀK6•þ\è‚}è8õ…ÇNXfô#Ÿ´Ýw ÒgÈ¥ØGWYN‹¨KÂ÷+)Þ=µxpk„aÑÅæ{­‘…)•±çq%xbh€*õ`·÷™¿ðÖ,®_`C¯`%¦ìÝdúwfÕ†4w¶ô¾¶°N7b©°$º™¾JÈ-u$ž8][‡»Ô2þXm\z°d–àéYòÍÉ,åŠï/ëÃä&Dý‘”úË šMÚý©ÿTTÿ¤P‘é.×p²/Ϥš[{Ú³ÍÙKâÆÅ)èm‰‚?1›€é«*Ðd ½Â|ð~™egkè‚’Žg§â3û‹-¯ÆŠµ5»Þºf"C§Tôü߸§þžz ‘â§p=1\‹…°_Tú9T"Utæ<˜¡C ¿Vœ%¡ ¼‹xãLFÝ=—¤Æµ2.ðc»Õº9€z…ÏÀ›”Þ&hM“FæEßܧ¸Î°k¶0‰,íÁÍÜ5´X£h¾æDÒk‰×Öf—!/ÿQ5®#¼¥€¬ªz²_[×7nE¶›°n·sÔà›ÆGŒBÑs­£/pf#Þn6 “.Œ¤ÞúžYËãžÊ?“S pQøT×­¦ú/}¬‚%^´ GtIGé~ë.-8z„ß„ŠâPŽï;ôŽù2ÿ4C-Q XÄâ>$G÷I1mƒ~¶$á©`/¶Žd«‘!êÍÅa­áš¦Q—OŽq_±Dk%üM‰©Å©^”‰éÚ àÀ’áʹ F7~Å ÛÞym0<<œI²(ìW’ü’’„é"”W‰F¬ë÷?ðG“`\2«Ò-B¹€’±£$šñ¨2󕎵$Òwáî”B“ÓNS2å{ÌrIªØÁ!ÂÆl™td’Nþ¬S{¶dð]ðÏŒ×þ" ¥<{TÒòîëþÈë6>ŒRy}l Å<ERõUìw1±B¼„û;ú%%ISsôÿiKÄØ0@äÖ$jˆ7Ò^ÙkI¾r6n`ÉRmý-u¬aP#1Ø©a-³0¼aÙè£À%Ûhó’£bb¥ìø>-XOÙ<ä’ÀὤòeÅ­zšƒ|éÁ0EëKK ¦j³—øÊUÃ]W›J¿¶UIuNøÛfL¡Áí6≻þ˜%z;[yº“ѧ Ö†ÏøÚí6¡“­-ÂŒñ€ÎYV!Hl R¡×5© 5ñ-ɲª¦:u­jzñnµhŸ+)í[‚¹·µhô€æŒÔ¡ Dn³ïß×Ên¢3ýv#^M›¦GOÿÄc8)„’Z&B­‰ô@ 0¿íÓM/ ‹[Îų†Ù-ThpÉ…çÛfKæî½­¢êYÖ¨»h’€€¬…M2U¬­›Ì—‹ûPăñ-ÖaüD’ öE\žjíb>· 7Pq_ÿÊß-:² t rƒìÔYJ@°ð HC›1¤nóÓŸöX؃¸Óñí$ÞöýŸ!qJh¸iC>¾IjBtF€JIË3\Ã’ÐÀ+@ß!Ï'›dÌþtÚŠ—cRÀi{QÔZ7‚| ê‘÷l-¶ ÿS4»a^ ›<8 >ÐGD«&dpZ[\É %úa6Ƴ»;/”q‘ÊÁ³¨ÍÜd«õGuÆfuÇÛÑíÉw†íù«lôhîçóÞ“±Ø@tx\^\’/´ë2å’æóH‹Åƃ öß·Ó£¶=ÏÛhF†K“‚6SÆ‘žÆ£(áÎh£ÉvùØ¡øOñ<½dó^’ÿÛ€oMxò#N>ó-qèQ ‹ô45Yù|ƒ÷+D2}~Syk©iMüNó…Óó ëÔªÙæÿ"’¹]ÇAe‡å>Ráðöñ@TcIuV†Mµ²üñ‚!ý²×œ¸µB¯3h«F$"å2…ÖÛî˜Ñh‘D-€ùÂw¢Zmƒ¦„§²u,&Z+9Yày¤¦}g`ltó”•Y‡Ð¢ðîÄ7áýæû²x˜¸„å+|%– 9*…2”3ø(j>íº<n£ˆ`{Wã­RGviæÖ'i>^Ø7”ü"eMšR[½öq0ìmç]¢ÑFmðµîG…2îë€Ë(Û+énìDtÇ9©l®8ˆžOÓ~N.ôÚcx—Ú°|]àÐAãv qiêßóÎp+©H“Ó-¬ïu[ÒÍÀÛ8rsw÷£ß}å-:·Ì‰jAIç÷À1q®#·7ü+y¢kDÁ¿ÉVS_ÜèÈ‹V»Ò$1ƳW …CõùaÁ5K{.b®×ý‰fCžèç-JtE'¶2ÅY‰À1ü8Qa¸WpÎ[õ_JÕl¶Â:缋xE^|€Wö0î6w½Ð(Ì¢«%óâI*C2‘Õ ©˜Õ‹bTJiMêÝF­+¯uÏ~ÍÏ/Q«õëDÆ«¨\éí£<ÉÒœ‹›jB¼¤;Q·ÿBwi†Ä`Äxtμ‹,ÞóÓçJR±uÞ,vÔs¼æÖâØXh¢R΄(Wëv⋳|=M¸°¦”S…tÛÀ®êOäs@’€€¹L°¿¸çe§ð~šUì×½º`z‡3ü[JÕ]ËR ÒÐŒšGܨfÖÍiFÎâ$ V.žRL7cxÅ¡ß-Í—‰uçÙ õOf·tJüÕ£ÃÊS"Û›0ÇO%°dË_~!MýdRUãì&ž¼Ç&8“ï+äñµÙâï¨×#ÄÑbÅdV}D¥¬í‰ë&tGx¶„жœþ0^N_³*œi÷ÂbIGÜ]k?¬`74Λ1‰_?%¦ (ý;f]ŒY€/›éÇM÷ö¼nì!Ú’1ñ¾uÙ¨²Òˆ~ùˆ«-è}Ê£3þ¯Ž5‚“‡œ~Ôåù…ËÁ@‡‹¾Œgr²3Ö`4æ#çÔ»ìÎ

    —SÅ)¬¦.â?ä8ÊÁœŒÅ`3·¢@(ÔÈG"ýÕCÑhÂ'òl U Ôê—vã  ñò_ ‡,„è[¥Ï ‰Ä# <8q_¿Çw‹d¥?ƒî³f‹±À`ˆi iAi4õƒK—^­ôÏì_¡~+ÜI¿È¦ÉCœê$cŶi®YrUs8ÿ.F ÷/¼BÒ‰hUy­±jgcÁ¯ŽGK6§R2›"Ò—R"Jðv²ìÆ:$&,ÜZºl$óÆ7YF-A¬HÉÇù©•ê§_¯»Æ¶Ñäñši¦3—2ˆÇ©Š>*Ô4öT+¤ñîëû›\8Hò#¾RÔ™À)nd~253§Z…üYÀ€ zÖ'Éœá{¿ªù<Ò3íLmY×C¼´ŒzÛõ+¥P`-¹ – }OCŸ¯Dð=ôØ«³gøø¶:(€E’Út‰Cd2< 8ò5l¾çQ¬Î…¡I©¿ÙÐ…’€€Æ¡–®vÓç ì@&EBMÉ ì˜PÏ:½ZÖžHãîF·[’Í-21=9×Âýöʈ éçi¿ð÷ì4Õt<¦àæ¯ÿ üß<ܹ߮r%8Å›Æ fD€¿%á'¿¸'²õ½Àycú„‚¢‹ ·“|Íᘮ²•Þj¤ô]Bä8ì˜W ,²ÔJcþéW,Ü÷ø{êä¬£Ø âÈ…2¢^´oƒ‚óÃs•Üé0Í…ÌŸÒ£Èð‘P]þk4ÄÁ›qÔ’%3¬y··þ“¤âé¡’û6ñ€=jvÃRN»ø•rLœnã\µ‰›®-‹X˜kô°ê½?<õÍ8Ÿ÷*žôMa«FÅ“ P—›_C{,Œ‘]|¾àϰÛMCˆ2v° 8ÙÓâcac~«áõ,KÏ¡a鵑—'m*Ï_íi¾c5«¨ÄÒTb8;ð¨’k.ÑzPרüZ½“Œ%mŽßCv†%ã?´é7ŒP†‡ýÅ‚cÏ¿¶ ”¨þ骄I}«ýÆ¢ñ+-ƒ=°?ЇháO“%³»% 飕>e4Oocƶ%©÷É’€€±‡J#æð]™Yõ¶Û”!¯ØíòÇeþáQm¬Öfxbta£ü㔌6d´ôJt^ûu‚Dˆ*›ùß­Q‚’§°L†ÉOÊZ[>ºy}Ã×Öé( Äöq¤˜îÑÖ¦/üÙVç‚ßï…xvÿ1Âfã0<‚ú8VëKS &îõ Üx^‰#NvÆAúf ŽÃÅîš·E–ýIÛ(QK@Vø‡ã#l92û€ÒòEâÿ”˜<¢N¸á<ˆ›öRŽÆJ†=P¤eÝ-Ì¥VÈ·?Ði"7Â¥|{êw×æã¹±É6hyIæc¼ÚÝ4Éò›e°ó6· p¨q'ény³1“ˆ.²©Äûåîàhí5¨Å£Ðéܺ¢ÕÕçëRÉõ¬wC4n6ìQ/¸:G«°2}ndŠ¥AóÆ“í;t0®ð¨BOaþQ&Õ¾é,ú|qÒ„8ÔH¥ï6lðvƒx"¸ˆûš*Ðp~¡U!c7ky™Ú¥ µ“ç/ §ñ¥Ïä×»°h’ƒNþt-b†óÊÀ?XÇ€QrMkµ«žÈZµ+¹*o^nvZF¹ƒZ½Î«4x•'ïü'bhœ6jK²„ jÎuÂ}"íBsG”ˆèúý=Œ‹ì:Ä(mŒµ+èUí=®}wÎs7»§á‰Ø4ŽÆ`¸q¿? –S]ò° ¡±dÉÉT¹QîÒ^rñcwu¯ùÏtºXü’/Çú¶0äÈÈr¥-( [Mð;IÚš 2C~4*ç‘jX*ê]lªÍµÈ}<Ÿ#JIͺ€T8(À³kßÒ-9ÐC`Mû`+G…ÁíÙÿÒ4NŽM†3Â#ð©°)ÃÈU²ã«zÌËv¥ñÒÒ&et×Ï [#«¶¨;ÐïɰµÕND#⮜ešlœ:+Ú"ï°•ká…÷_{,ø³²a¤Ï>ßÜÃåk>P/Ó¹>Æ,çé¼|m•<®EbOÍ–ƒóÍóIH²ÒX-g1Ù× 4´[ºdê·’´Ü=<†gÿîé%é¤cˆÏiu^y„Üó¬ã_’¼õ}c d”(ü4ãÖ{po¢æ×J*kÃC‚hw°ºFŠÀ¡d|Ôl1ãÛ‹™Ö‰¥mÐjÀ‡ Ñý ¬ž>F—‰Æ2ù´ZUk â’€€ÏᘚVÜÔ6jG û¹‚H‹úËAx·çÍzûU?RÆ.=a1º*4+4l>9Ià:~Q‰Y¼§Ì¬J²¥Y}—ù^ãss£Á˜˜ ¢¶Ý>ö§òÌ-hÿˆóƒÏckV.™èç".F»ØOø! §§ÈÚïC¦‹mNßV@Û=Y¬Õ“Þ²Ø0Ç›!ÕèÓø¸zŃx‘~GµW±°É¨tÛœ“Ã9N̨¾OA"ò”‘¿šQöì“Ò½Ÿ2ÔíÒ[P÷xº¿q¯˜¸í^â¨ü›'ýYuGk…­ãÃ,ÿ[Ù)ΉšäñRÈ#…Øš ùÔ¥ 1_íò…Žyl¸i‘€/† (à-zøÿeë'Ìz$ÖùË‘N:ïý0ï¹ä¾ü;[7?¶úàþ¯d3†9”fàǺ#‡åÔ®ý;“lª9h”âtEÆÛµªßƒ,ÕŸ8Fö6Þ5©Ï¢i†¼Áën–vËGÅ͹ÞýÉÎpÔ:™}]ù Ù^ðt¸Ûo4«–¾*!f™nýª\À>\Ì·7¨ŒÆ>¨7qP&+쟿uÌÚ¶0 ½ª­§Žs¨Ân¡=•Ѓ[«ýÚl§kÏgÄbû­Þ|ùœŠØæÛ+-˜É%õ¼PgÀV–¿44§J动Ü9—YÃ¥¹ìÙex…é®óx¨K®Õ›Có[ˆ<­Ñ>J=¨£bGàÉ,$7E:e.ufS.×'|æSµ•âY‡Ö÷æk«Haö‰YÇåN„©Tƒõ÷ÿ¯©Ï”´0.‡½EQ=¸ðÍÖà™ß„ÚKcF{φJîÊF'™5pZé|µ¦„2ç‚gsÞ‹Ÿ9Æïý!DZÊÈúßKÕŒ%#ça{󪩢»/®oÜ ¥œ§zâž×ä¢ÑÓ±á$ºkŠw¼’ó¶óòD/jv.~¦gÉ üñìï4Kt' ~Ýð<“B24‰$PsˆU¾i-M Ñy± àÒï g¢`žûÚ¨_áÁíY¶$ðöQVÔÎí}wß*¬Idrí^B܈·€Ð9œ¡ˆßó⎜ð‡(,îZÄnmÍ4vw¯˜ÈÌ­³†i×fÎËt)¤Üå1a‹sXó¶ ‹•íÂè:ÔÕ§G›Ž¿Å€56Ñ;[ÅÂË0D»'K¿dL M¯”®Í½ü¬Eœ‘†ä£O‘Ð[P£Ƴ!¥xr…øÇ³Ìr•È.”þ1¯„ÇÃÌÕ}T8+ûôGBqÅî&Ö,½°žÅ{o›xÃzœ(ê"QQöÓù±jä+FªüäÀm Ô&Q”¢£éì&ÕÏl)Oø¾/ë=f^F]‚4¥³…ò‘b\ª]´­¥ú•òN­m] äú-3CNÏs¯‡}ötGwº8À{ñ’O¸Šw‹|.0v8ãÛjÑÞOÝbs'ª¼×ĶæþñÜ<˜5>«»jo›ÐÛ××x ¼~©RvÎÞ Ñ¾,¸zVò$ëºýùÐ\†ÝC:Ú hœ¿Y‰*‰^eªUñÌöISÝTTÜS{*ÜÏÖÿq'xåYîMÛ4ð¨$b—œO¹k'p +ˆ‡]Ò(Å gZÌDQ\Ú‡c*EÖPô?¬ÚkðAhAæÙW‡B:Š{"JÕT@q<¦ü`‰Æ“dS¦¥}µõì“|í3æD‰&ÿ/¾òîª(ŽËGýز¬â+™‹nW'ÓlÀEÄ·Ë´ì‰sjâê~ 9S5*+fƶ¹rŸ£‰Ÿw›ö`jeì2`ñJüŽ‚^ÌY¶ï÷Ðçÿ¯€×lÒôÛ`l&‚Ü ‰#ãNCYÿâ)+øR½–a®¹~įDb+ŽˆÛ@|Ÿ§‰«#þ<Ü@xˆÎ9R·Ý´#}íý?5àûÜãkÆ=bdÁ’ÔßÙÍLZØ‘‰Œrgø“òBá\Ç.â ºò§Twîú‘­ÜuL5DR•¾ù^çT¹Þ±|ù#‹˜#ŸkÄ4Òá´’€€Íäí¾¹Ûn–&Uøa•µýyZ1ãXÓ¯ ‹ÔwÖn~‘ª¼p5X¼Ö ô™BŠŠÐrÛæºÑ³—^øÉ1²tûÈ]D´P>3 Nês‚d Ô×Ûª)ó9w`ƒÒYllÈül»¹†b›¤{Ã~€@x@ÁœNœÐ"‡< ¶<€–ßßµRH¡)ÜýÖ¼ƒ«·2¿ëß1=¬ÐªJî> zУERò­åaÃ…C–ÌëÀìO³füì‹v™ÊóDJ6Ûâ~’,À‘PÂáFºÕÙ6M%Ê™ÀƒüäÅoŸÆ 1­NÍ)mct…z*5Pf?c¾‡c^XUáfŸÉó[¥ïú‰Óo¡à¿e¸9ƒ Ì»è©H_v¢ªJ*ž>"_Ö÷ä ¨2É ä8w†RXðóqéÿ±@¤vþþó É ‡µn7åsàaîß^ûx1šâX/“Mâ´ÕOTé[Oa1ӋάÑWLeU”|»0ÇéPý¾æDÁLÊ.ÅKñÜ‘È)¿=Á”© ø£äÚ‰Ø=0òP6} RNçš);:äü¼>Áù¿=ŽúK¾ïn6Œ“@ç<‘Ñ÷ RžK¢à7_•8ó¥Ð¦lN·¥rȬm§Ëw2€kÌ}’ðnU‚°œu\›ç\ÉÞÒAJeŠbœÀÿsÔŠ«C“¤|ɪ  òúÓ³ éœ&ûij¢²‚üǾ¢(Å«}Á´'ÎIeþràâhŸE^ÿ˜ž…GQs ¸ÏÃ}‚Æ3¸›L¡…1SÌúU/M']Y’øHQã».´°^nÔ`ªÓ7z»Ü$zµÄWgó?󥜄KѶxÞ3‡²Ê “¿8Èê6ýEÜ&ØÅgÅÔ§YM ÊSðÊOg¿’÷N™|â«€Ûë9"h)÷•²}ÍüT{ö«~Hž¡À&A è9T˜ÆÑ/¤„І—$Uìœ åmï@»«ï¢l-Ùb Œ¤î¨”C›2 d6Ÿ µDhJ·ûÞ† 3ÙÖ°ùúi¼¬øñÊ­Tãâ‹6NAßLÉ?\ç†E€LŒ0Ê(ðhMlÐJÕD}¼èf@ÊÛEˆ½m©%gçvâH?ªÇo)YŠ=&@‰=Ѽ0¯EœïÍ’€€ßˆza55ûnÚ;]r9W0Â¥><ïA÷Ûû.MZþ#ø}o¸z¾¼…¿å@Wªj:]n}ÀÄCõÅE Œr7®[ù$wìÔdY¿˜ÒMŸ¶‹ª«9×ÍòÁ¹r=G#qY<›fAXÊÔJó¡ÀÙ*"ïCXÓ€-¹.\AŽ8šGcUà°Å°l'‡Ð2¹húøì]¬"бµôZ#œ÷¶!ÐŽÈVÕµ!rdn©­k§Ë°´½ï‡Õ¼¸pÎŽK5Ã>—ª:]%Nñ^V烘>4Q4%Αkä?:~ÔIdžl0!ñÇŸJtn|V Dó—}FŸß‡•”ɲ&ñ,†œ6 ŽÀ6OÅ":k4}&²·e¼¶rñ½÷€ÍýÐ:TÔ¨ª.º œbim+Z¥;H—,O¤YOÉù/‰ -lbæiÇZ”ñÿ(Í㘵òQ@w¥Rkˆ9ø¸Gäm3ÈéÁ±ePó%·ëA_ûÑ“,¯’M€GZ™CJ~%ýÀÚZmUçÎ3’[+G†[>¼k¸ 'mh6í$èÈ[§eì°;¦YäS6ØJ8÷`ovpâ1î&õÌŸéIçÇÇÙ³â",bÿ¦5…´AÿØ7"«Øaã1ÊÏþç5!D[W‰“Óêo*æŸXžâ¦ŠQŠh-äá+ìÊà‚niƒ)ʦ;ÜPutË‚n`å®R<ælиq+FFÁKG‹‰ä2š…áD¸&EßÏME* “Дã‘pE9Ž9Ýhú',\º [ëûI)`xò†ÒŒßÍM•×–å ÕåªÔ…’üú¾ëÄkB(ÕÔBý Ô4?åe#ö7ž•ÛÜ‹0sm}¦M õpÆÃÏ—o~Ù”]õeéTBr?]Äõàq‚àe@š‚’„Øûü¦ #ºŽ!?HJ™Û1Ö‰ÉåÀ¥Ó7í˜Þ>¾(­ìíbà´º‘Žü©íw§ôDõ ç| ½K%AÌ™e.çåy„£ £è[s/ûSšUmhûåE [P³TYˆŽ-ÕüÖ‹h ï=pàq™®I@FXruåEjq>uj.óUÃQï.8âO°Ã _ºtnäÜnØz±a¨Ön„r„,V)˸Téñ‚cáÌux•F—K-³_Kq=TT!-`±³;õE8kf ÍQ6÷ ؾè6P :ozC=tHrÏK ø}câÍn.ûÆ_üË*`ÉŸ—toåÇõXÎù“c,O†m"äPBt¬ÔëF)Ylâ§×ŸEÔŽ!_Ñ-TeÄ.üpª·ˆû~ÛU[" ýpçxªðÍäÒCEg­­¹t9²7Kš(1#]¢9UQ³ð éY¸úýè2ô׳JËÅ÷L}ç܆ó&OŠÁç™F ›¢ ¬”+o¦VÃéãØ!×½¯|úX 7ðfž«GJsgˆäƒ$TO¾$b>^IÖÐÚŒ tC²^Éäú2îc´rfJ«XÂf°Ôð×£a\œ’²–ö&_éRB³“ª{ûáö³‹,û‹„š×k°C›JÀuŠüæ6PN©Óc¨°ZÒŠ6εՄ=y©¦QÒí+©ÿJAÜ$ÅQÐ ‘ÒVƒ\±wpv:oc’€€ùI VÈ ”o0ÿm³ì–×®æk„œÍÁçýÐDÒÄsÍÿÞ'¼;ÓFeäM²uÅÙÑÙ~Ú?pÿ¯»üB58`Bü™¯¿ÀÀIœæT56.KŽí‹¥ls×ÍaV,2 É!Ž«ØàT57Ùí"|)û"À+;}Þy†dc(t8I•*ɉrÁÁí˜&†±ÕÁ:¾úYЗXX—Ao ZOÇÆ°ÖÛÒ„Wˆ)‰k3°ªRh%{Íú8tÉà'yöC”„Ù uê2Ca‡×ôFü|fÀÆij¼·°Õ17ê&Ò˜ûÞO7½ÏàÜÍ3Œ@ =yÃßµœLé­PßtÔÝk'r'þX)ÕH£4SÄ&ÜLiéÒ½'èÿ¯Èg"¥Å)¦ã⇠‚W-ÁAGÐÉ7U{Ú9“¤µ>ÚâLÒ"}{ùÅzúøèÍÈìÜi›ºOlÂ/µ\A Áì4 Ë(>ý ^õ¬Û/îðX¨'‘Ä ¹Ç„®Är†(t¡!T¡ujä>‚—1t_@méÙz pt¥‚pZºÍ|¤L¥me©hŸ‹V=˜Â¥E ßíxáCùQú‡Qã£4aK``Zä (Ýê¬v‰›°­HÏ`§>qz"¦†@µ‘f‚$½IåÙ1(&ÖèCèMýjؚ²ғqäÆm“1ÿã½#ƒø“óŽ:´=IÏ+ÜŽË£ý’' äÌÍæG“î ×ç/«-óøO ƹIg¡ó0‚ÿÈ*OEüt-ŸÁž$“va7ÂÌã¥þ ¯ßay(ËȾ·)0Y™'S Þn“ÔAýùd‘x°½qƒŽ6lôoð^øý?1 #pm˜>4iã¾^D 2OApão‰àØ9ïSñÖžšŽRt\‰c¾s¡%gn’ ØÒ/i½Ó ô BѯÜÈ€©öKo<8îÝ72) ·81ðê0²²ŸÙ5¢]Rã¼}ù‡$‡Ÿ9{¶+ìú<Âmhºø×M'G8Ú¬múý"b›@güÅTdúÍ óp£*è6 /e°”š“¶´Ü ‹—…qP¨x+OGU 1¢È!ÚìRÆŸêfi3š[2<„Mè·îá1§üг[×¥³§QÈoÜvä™÷p0³€Ü’€€§h ILx jÄkõã Û+¥ø¾p-þöäêqhõUfptJw:Û%£ædªŠûk [½œhü4^;¬!‰âH­eaPîUr¨U.ˆÉbn JF¾ûX´6÷ª»ÕœLÒëŒ?ó/)ÆŠu;kÐ2¼}=ôM&À‹{lA¥J&ëë5>IznÜ ou ªûô¤9¨¥K!½š™Ü‰çQ‡ï¹:˜ºº[¤=ð²Šmî+,£ÊäuºAÚ‹^‘ýË~:‡nÜÉýW’jÑŸ3Ç~yXDÁ5ü‚+gÝ–™7;6 6÷Ù×ñðkoÅã_\÷B•ñí%6â²D[ÑÓškôu Æûþ”ËìÄùz~µ]”2ÕÜù]*¼vH¯ìø•›~"¹£Bmú7÷"ì…[2ÒE!]ê¤ÁÜ—*%•Û•ñ¡ÎÌì %l°8Ïp¤ìþ`áÓ2ïßöÿ#0_èç“ÅßV‘É›¡|ÎÇÃÚG\ã–v`cÀ£M­p”“ÜCó4\ïq b¥Äƒåv¾=í« !IEä†nÖ)ú\hYÑÞÇËŸêÉ?ôñPïÑד¯À´Ù.”µw]Ò[£¹ƒÁã <É|–hÖ 4« «-óàxcŒ ‡ú’€€á“{Þ’3ŒAIt~ÒÚYÝœJgC†O´‰æ¹?fÅnå4䣡06‹T#í%m€ñ]uƒrcÈo UœÚÿ<ÿ¿Zr-âJ­x'ñ®œ?ïW¤²zM‹a7a.‡€ÇÔß+®WSðذl‡Ñ Vó)ê†}ä5œ¹ìÆùÃsRÁ˜ãÔ»,;D·h¸LŽŸ"o‚†Q:Ð5¥3rˆ,Ä· ñ0ýaÈ•¡¨BܳnÃ÷ÂZßCa ˆxØCb¬„Ÿ+ºsÀ¦\½o®ãŸæ+zýµw Äî[/±í&Ò+%,L_ˆ üá/þ+ÿ6£l˜÷¡&žº±ol®Šï¹RGõ˜¢ÏG•4‹üàÒ5~)­8q}‘ÓDœ¬›¨J;œµwK#®{#eÕÓSù•!Ó¨£;@´/INQo[‰L„"ºÏ3§UÃùzÓÙ,*Éë™äe¼›úa Ì–lcÚx/(Þ°A‰ª¤y*n^z7¨©Ø2Öñ,°›Ô…ßï: ̶Ò›JžE¯¿Òwº—–Ñ”² ؘ¸¬" ÌÉ0Ï.~f‡ èWcío½F§ËèTE$ì"°4|ùw?•~ÕÆL\b®ÈÎé‡b›¡jzGØÁ·‡Ó7×'’$¹ pv4óKqGRéAðx¥¯Éžõ÷väŽó©?f"ÔÀkAmT¶˜úĽâ5 Z¥+Qc³Tþj¬Gxz[M<ên¹ J ¸ßïÚrZQ!*Ë 4ñOß°ÌÃ_SÀߪžíÕlbÞ]”—çvAJ8ÎÖù6:ٜۡbWìž[÷̶æék ­ðÈv¾Ã5å9Í-0‘ù·Ô|Faü^] l6;¯½´ëe «L-—)“I¦>äR ¢815Ã:nƒ½Û9]©­žã_¨â–Æi¼§p%À™Sô›|{‰Ó‚ßâŒ}Ñi7Ê,Ð×öŽ2û'~=§å†:Û3¨¢jm5}íE>…—¶D.xˆDVöî»útxŸ¶‰ê8´NæÑÍ\ú7°ÇH´M°ÅæÕ +<­±dK¤l*Ù;<àF•›¹ßÀ |/»Þž¿[#À=‰=OSg¦ëäì?¸ Cê[yÍ|ˆQódP0™È^ºn“ãC˜@ûºw[ëò†’€€ö•Ès*²ò< G[U¹ÍäcÕÙ0dfª³8«÷]¶ RžÔi?}`¶Ä66:jÁ–Ía•*qN;Mîç\öìFÃü1%*ñAXM5 õÝ•Ê>ø8TØû“’aÔpäõ¯,Øàl[W|Û4áj a^³À½v”Ñæ‡Ðç a9ÝŽ¿ØûÅüwKXñXEøÒˆµÄáD¶|Yêš6¯c§Þê2¦ ro¼Ö×¼NRü‰p{])ʹúç´ª0ëq8?Ä ² ¬suí;ÛÖ;ÙC^;ßYÓãÚÀÙFXIö«™Ø¢—âBË™C5û&øŽ›ÖG§ õRÉ„Ô" Î/ú j$–?}[ð»~ŽêøÈo‘DþRH2%;;ãBŒœ?öªB5QJI#Ó`¡ J¡ˆÖ]1Ÿiœœ˜Û{™jJg5#±Á* ÙÝa^×¢ÒíM¿XÖ'.é½Èœw$6¢¹J°aø³w˜¿çÈ­X´2ºnÒÄýÉùóOí÷ªÇ…ôTwVÜëM®ÌQàHË㺻]VÍ-_«ï55fƒ²÷-Xúð§s'2à?·ÛJ ´)ÅÁ9YÕ!pIF-~8ÁÓ¦ô²· ;}˜Ÿ"PøÐƒÆ;†¢äÊ€¥uøÐÖ÷g奺„{Ȇ‘A6¨j¹Œ¸îqæYKáZ’€€ÅS`¤¡_ô[Â¥|B+v›Ø³s ‡oW@R |°™Ú¦ÓêŒ!; íw _Ÿ 8S³ï[ÅÄù“ôøŒLï.Gç„ÅÔtÌ7åú–CÖ¥T|ûÛ ¹ÃT‘Í`îV§Ìø&ÀÀý(2 ññ?ÞßMİu¼‡Â¯²Ü²¾Ù[6å)ˆxŒ¯ä¢6.BF ÇÆõ±[®•¨Üô I”Î{.££W«xÚ‘:…õ2ª.äÊaY¡Æ\’îf©«¸µ8EfÝl<w#<…¦¢<ÀÔ<ýïþ™9ÔÜC!Óš s#ZÁ‹@ç²rMànóêEÞ¡lœ9®3a3A¯Â¨Ä5 o•Òô<A: U)„Õ+þ7 ÃÚqä(E!€VÇh%ývßñ   I–À.óœÔê]ÃÁë¸E˜ >ë_&€~>³¾¸³²ØèU"½‘X*lR#í$¼Ù)™W×Ì ùk‰Pâµ!t>ÓÐ&.@S"“òÓw¬ŠÍvëK°^™5ïP5È/Ÿ¿î.ÑûoÓ5-á|~×£Ÿ¯¸™Ñ_|Â.H=ÒmÓhe•Ò¼…޵žUÄ䤤ÂI£¶Qb…–Þg.D<6É8࿨ê %¥‹Õ^mÄLvg©»¢Ë±‰a¨ÜI’|­K(I’£¨Âl âW"‹ iù×;[¶ Õ÷ãÔtú9Zv× ðan~·£ %È…b:£©˜oãØ¶\aàðòy›âBÛÏD 9õ“&ìe§¼<ïwšWMô¬xR#‹^ô‰o›'üæéŒj¢‘/ÎM­BI™bxÙ=”bô‚¥ðò¦*FK—Èß.èàOTü·ÓòØ,¤»õ±üÊÎÆG…‘ÓÐZ ôhK‰Áõ°ò‚7R×=°rfY7 ÜÚýká qd¦Ðª?À¬‚¹”N»Öõ‰fâÍñ¿6ìå†Å©ÍþœÐró’®‚3•‰$£ÌkPšµÝ»Z©Tšw†#™UU]Ó8¿R¸WN?ͧw+:Æ?—©Ž‚ÑdÒ;Gój©ë=‰bµPÌb£²ÎòÀDöãd´Pä2hÍ9WQÑ´'uxîeÂò‘£p°[º(u Yv!iÅ îÈYxÈeA…lõ’-7ýuŒêá¯&æw…7¢vèp+l‹Mt¤Sz ð¹¨j*Èï’€€éÂW’Îû‹šY:jmeÜ{/¿QÅÔ·Ž"¼Õz÷έïG#0½•$|[ÓÅj(›då¿ß>À²·"ÿÊÒXóT·ã®"†ÞŸ5åaòr´A"µ ö % ·Gã¦v¹M^ÂÌN>p6¹ÄÅh}"è›/Tȉ>I\ˆù‹51kcH@Ècz†æ’£êçÛ!â·²<ï$yVÁÅ[Ò ˆ9UÚ*…Œ7jž4¦Ž§lÎåîÔZ-’¿‰µ±Œt_ {‰wF¹NrA—Ò¼]œNLŽÝ,¾`]FnÞV*%Ì•: â¹ÝÙqå~üÔFò®ÌKÁH³;ºCÀìÞR/$aû´ê*%(§|i‡™Ú˜¦Ï±8“ú;2.âfLéÎ|°²k?C¸KhRÄÖqRzS§:“q‚j3 O¨ÕôHR)iË™yOÚü+ùçé#&FÚ—vSÐÒi(Ù´¸;ÚØÝ’Yßá¦æ ž:tWç}¥"3>|ù{Æ«c2Ô¾Ã!̺jÔ£ÝèEKè"G0Vøàrˆ£I|€EªŽ4jšqLtÙ×eâ{ÀšLŽñZ“ƒÉ£ü A´%÷'UÌ}é8k­"€³4Ûït¿ÎÕgÜÝQ?oGë—¸UîòM±®Œû(5¦Ö. Nle·ÑÎjØzÖAõ&+æƒì–`µ¡½ÝΠ¶3ïPB®;0mRž…mj‡8”Šg­ ‰-ggxa®Þq˜³ã€Ã‚>ÜÛ®>§„Õqûš­›Eók¹T]”Ï„ ÖÇN–{]gêÙ²œÐ¬_Þe…¥seœ1jtct ñr0€T1 r„ùrù±\yƒô).ÑÔ’oñ_މx^#k¡û'/V¶–»o¤ †ùìp}$ÕçsffŸøs³À9L8¹j0’âM|?UG]%èZº$†å2Wg¬ä:ÊY²9KÀä£U]í[)›7†pwÙˆÌ>²G2 ¬¢ÜÀë!.Pm´¦L„±FÎås6Pit–ìãq—êXþCt/ý¬§÷†–®ËA+`Í~ºO7öïÅŵ§¤ŽgÞ†–(¤3âÖh A7ŒbÌP=¿ÖxÌvØV–’qˆ¸r/ØÓø]L"fÿV°¶ý¦+1‰9ò´\<É7·„ GŸGßN¿Öt œOÉ5’€€úÚÕ)sÇ4žº•ý=î­ŸÍÀ¾iY„ËB ê·7-zõÔLJœâÕÌD‹MÜþ˜mÒÀCkUÉm7ECÁt¾Dùž®'(ÓxÐS€³Âz§Aûä_€Á|:Ë™N]Ø«M¼}æìƒ½FÛßÀ š…M$Ü(iJ‘“Úu;_X¬nÞêMŸñ@%N Ý @îL>µ“¿TqËe! æˆ/ÌçoñÂÒòÀ$+Š|LyÇå2µ6–r‘XéõÖÿm_ ˜9ºÆ{ý¹™»Ôé‰M—:›™BN|ñƒg_Ö€]ÍT>…zÈ‘•]CϧwHL{ýD›Œ Î\×&daíWÒwŠòë¾ÛTž×É“‘µ¶5µ!Öƒùü]–ö ÛåŒ*û¦´M謽´ÙÅŒ÷ÐU`®”‡èƒf÷jKžÞ»7üd(ÆŠ)Ì"°èá«êÀÌaªŠYë°Ø6Ar”ã“—"]+Éy±dvÌúYÁ8?ÚO?2k…ž[´£p¬þÁéO”‡ ŠºÄ~}š›O¦*´·DàšX{5j|ßâfìS±ázœmÅUø»ÂyÐ.ég.™"éä÷>v™ñ„ß\ë¶Û5¤¯ÔdÛf:FSOâgZ ~2MFÿ"l˿ج;ºˆ2õ‘eWó™¦ÊV¯q¦¼ù¿‘È`z7‡ûÓ,gâ®,ÓU¹Ý>ü Óâ}ï(z!Š}à× ‰ýþwm£¢š¯rR„uçn*®’€€¿ÅPYIsÎUš#Ò<7ššÚ ŠÁøß¡_a gIú‹8FçÑGÌç½:Oê4¯Y; xe©q,uÍiÉ6¬~îCÞ_jDöt˨CÝØÇš"ˆ š27ª›(~t3‡—”?dïlÖŒëmsS<¿I™ÄBdãOÓUït„B^Çç!n‘Qü¥öç d~@` Ìó¹–è«p؈àà cPœñv‰·<–Æ"9|V4ÃЃ9Üþ˜ùLóù£_êÞé;h÷r.ÁR‘)}vg&¾TÍu·¡"QÄ#ò˜X¶¯­p((›Zݯ¬gL¡3c€Ñ„:ÂðOu\ A:Ší¬´CNLø;±cD“(÷½Û¤’ˆmýN­ga;o´ü2³_1Ó%þçE˜Éæ…bºTÔ£ºú7ì„Hø®_D쮦Õ>M'ÆK)ó¬ÐÔZ+×íØ¢¢ûM·û6V5ÐQz¤ét÷dãÐ~vc7EÓ'#©™ð¹[ó]"–(¡Í’qr4z¬qËx¾ÇTø˜iûFàìüáOîŠ_²K©ÙŸòÕº¼ ÿ“üÑ•sÌÔ¾S×G¥ýk¬°²aÈ>)2¢+ :c7ÜIˆ|-W1 NM+<”ËTáeß¿8† ¶¶”­=8Í 1T³Ö²Y*{ÍV&Ÿ½ä°Ó8@‘î}æw:x‘¶œ˜¡C’ùt¶âïü|yŽ›N%™LªÔ ï p¥m¨òþ„(#¸,®S7d³Ém¬üBc!éðß?-ËIÙá9ºgšKÍÖúpzM•?d»Ó"(FÛ WW,-/0ØÓ7Ÿ{ð³\6v”/ÖÜžÓ§19Ï·PQÍÙ#wy°x=¸ô¡{ábz{ª­5ü¿ÚÓ™7ë¹%ƒUB³7r\Dü,QcP:%Ü×°Ù'DH)-®o’÷ÑÞåeÅàFº4·íåª`€e/¬_áŒl7´9·5(@Ë8RØ-„q§aŠ4ØÃÙ—¿­’H¨ÜŸ†|¨R:¨ñàÝ50&|4† „y9%k7|Ëõ/…†ÄÈPé,—o5ÁZªòVäL l‘˜Ý<ŸŸ2c&8 F¯‡W¥t ­¸›ÙäAŽ%Ð{²DùË’ ¶$íã wõu¹9¾;™Ê• 8’[sÀ2rŽ‘ãYÒ^´¨*½]w£q’€€™ns[MhÜ[ÍÀ„côC˜£\ F´FÜÍžG_B  N䉫{ÌŒ±ryà1ˆ/2qœÉÚX3àD‰ÖõfŸm9%nÖsNúKq±ël³¾^>–h|ÈI©˜+ÀÆÅjq2‘rK™¹‹¶é5LJs³f7So( n¢þ¬¯•?;á:A6øšsu7ÊÍ™oÔrgi`'W[sbø“"jÐZà=Ñ>#w¿2š±ú,ç 6° ‰qm_`aH%¡ÿ#•\§9%)ÛŠŠF5NÛÄÊU&îÖŒ­gÒI¾ÅAlFoUtÇ}`)©…tFXF­¿Þ†?9 ¨ÃJ£ü å4êœqä²’‚•ç¹µz)ŠüPP¾^)à­œÁ,õ83 Ñ9*6¢l‚ÔUÄñå®–»¹çU¢)Q0ÕÑV Ç— äP­w 4!åSòŽ—|y´ÖR’fÎr¸ÓÄJ Ü9-¯¦FT Y{¸ÐCáã‹*ã›Çs.²A;ÂJöª‰†¾Eå•Þ,îsÕ˜8/`an„q¹UKgèö:F È 5µªËÍÖ]­Ü ÀùùNºù^‡øSx¾Ä˲"Ÿ¦…¹ tx$ΟphoÏä ¦{­Ðþ=– ä;d¾u?ïtù¿Ò÷µ'ã"*“9}f0cÀØ(ÙÈÛ?å¢;gç¹%eiÚB‰àßõ¨®'‹»â3;ÎBà+$ö݆Tï=•&‡÷õ¹Â÷pLþrcÇp@;:¸P,•Ÿãô@ØÂò «¯`Þ£¦³EÄýó7!>T¼²7€Ã†¬ê„×2uöYz'/{ÌGb?âCí§8[¾ÇÑV¬¿V±PPno›”h¿A1`½‹Žë‰F}¾°ò\ÀèÌz°Lo…*^ï$·u~Õ;úžÂJ…‹ž¡ôêZ‡ÿ3ðÂa’€€°•¡Í¥äøh¸I[æ^h{Áã@Ä …Þǃ×Ù ¢›˜{—OÆPxù÷É"mF¶ÚuÀr?&™–Ë»=üâ)¨\ç qi¢—¼y_…(êbWDs|Rf}±¨ÅmPIo¤ÂŒAØ6”xiü¬¯Ö‘ì‘Vм׫ù•ëËfÓèG7îžÅNDÄ’‹Òý¢ wìKqUKgЮ࣌±­›öë?:ä±}x“ë·[À ûNMMËž£ÆÔ<»¯‚Û¿\“ ÊF,Ë…ñïZ5åD$ÏtM¥gâ):úžŒ˜”“‡WÍA%VjÚYžØHòYŸ—¼~¥BÃCäæúÉLmÙATÛT:{ èí—PÁ઼÷®ä/e“¬n3ŸÒ=ÑͱJàñjÁÀÈ¿\ZíOæRã5!û{£-’-¸®fp*íË·/†ï2 GÅÎîNílžb¨ÈÚZ­Ž¬À›`zÉùÔ€÷*;À Çž$«ó¦eÕýC\¾|HÌÚw˜†0[úè©K†„sOƒ†K4J¥âiVꦢ—ür¬ƒdÐ~|Šzöp¯ŠSÚ-9¡&§&¶VËx3Õ¾"ÑÔ#4I§£ó VÒ=ÊG­€!§! Ûi‘—:êï«6#\)k ëµ)´þÒ1/â)±gM’³l4Ç»qK¼<È]ծϋ2ÜÀ6–‹MñÐôÎ8Ó{UŽ`Š\”³Üø7‰TîvŽWz nü^€“ŽuøáØy’—œ$™aÓÉ@0jÙÔÉ>3eyA­ÔN³Ó0<܈ÅîÀí‘×v¤^=¢<&zÇáT;®.+Á%U¯PϤº+íVQexGï 2Ç ˆÈl»6µj“ð×ýß”>¹H-Fo˜;C $‚:ª—ßµwCj¸î' bœ1÷ÇõÓÍ»ZNŒž‡‚[L_1qƒû%2Œ÷ãjqëéWA†JWrÑø-oDË5/,ì$-šÁ~Ïlãû¯”ÚÊ~}›éÜO,/SxŸ{,e¹½˜Õ»o\S¥5ÎK`(cÛ ®Ww[NXvˆ0LA†¶á ?€®í™þì䮽À½†Šòï'1ƒ“ègÅuH±ƒ)zÒ¯IÐrfC£vá‹Û/½Î¥UNÊÿ’€€Ü(Nóáçx«˜sÛ½BkËG•.^Û¥ÀG1·Oú}Ĥ” 1íT?|ê™Å“d8bêªý£8Wc/ñÑ?Àú¾£á;6°Ä¶Ôkàjl+„­m›8ÅŠÚ+áåRè붇zí 5à èöãê{BÕ›C`R3Bwgµ:q"_gµº#:¢¬Î§,ø±yL¹–`'G,Âí.ä¬ö?rõüà×)‰¥†|bîµâÙ­(r.LwÎ Ô~´pÎ5iå cÞ¡Ä^À}ðßÃ=çÛ—÷ðâó¢Ië·ÓàöûD€Q4}VÖéõ3y)€ÊèªÍk"“†R~™ˆ+.ÔÅ¿8ã†æÚ¨qþ‡zW*háíì1Tú@Ôìéá,ùî·½ŸÔD8›æ>ìÜUçp]žî«¨FMø'PÒ®U†k¥ƒ XßlgC žñðRm!xûœ“qÝè*Þq áJFuf…XD{c¥Y­- Õïí°õ"Tu'n•ïUô>GýWneÛ^.Ÿ¯ÎOb÷€\vNõ஀ËOm¯&BxïU îÅ×90 ñ;=QB„/&£¤Ažð?ì³Àdø¸GÌêºËciVQ“:VmK’bJ€|@Dz¢À§­<žEÒT!ƒCïµZÊ•½¸”kZÖ.3Ç3Ä¿“}ˆZ¥—û»”vALÿ±q=ûòOñRÃ;Y¯ƒåf0õÝ´)óüš}¬9ŠÐ…dcbIÏ#·ÿ|üt(Šë=}m¾;*Å!XN‡†jƒé~"«X”•õÙéH$’½ðÚdicûî’ t¯d¨+crâòFÈÈ9’¹^^XAg}h£rwlM#“ ’²úò߈&*Œ²5ÓãÓÆjR±–³12| ×F«–ÏÅÎÒ8ð¸2…Š=YÜh”3k ²¢Ì(ø ”¯U0åC×ýƒšÍàîÁkÇzôN3ãb}—©K›/9¶S Ù1ß‘w}´bá+áæêÐ"îSÃtó†[lA4æïͪöHÊ€:íÚÞÅ~†!báæóŽpè¼+ ÃR%ù0gyÜèóv°5ì«B›Úm„”w ·ž/ DO‘ÕU°1ÞãŠs’€€®<ۿЛª·ŠÌäû¯v˜`W£?{ˆ7Ĥø…4ŸÍªþº2–¤JV …:tƒÌþ#¿'.Ž~òŸ±¥ýzS˜Ö^"F*d‡W~;615ˉ³-Û~lIVZTá±g#@ƒ|aMšá\m'£°ÒÆÙª“Ö­kåw¹-µÅÇ–×Á˜ž.²p…ÁFþEVšúÊqøÑ—ŽÙaÜcMï…/`tˆpݨ.'ÆLÁ˜˜ë&z[~öîÎìB¶ví©Ÿ]ÕõyÏ£…¶<{L•‹åP$”±sUѬED„JHû#5³Æ†B:â ÞÀò½ž÷‡,HjOÚ©ü !šˆ˜‰VÓ(x™Òd“-©Mlö-Åg!MkAœðÕùöP4Pjð¦ÄA[º~rã8ëåˆó·t\Q<нÐyUÙËã\¡æ&¾*öÔÁ_}³å…Ž&)½8sn,ÌòÛŸÑFG`é©€_©I6àOÐ!ß\çã0x‘„3+Þ³U/¶÷sV;YŽŠ.ûž;Ø]&{‹34+›f=}4PàZjyþWÍ2)tßà@0Ö¹®CÂ|ì&ŒÓå_ûiˆý3s,+—úî|Õx¾–æFzJÇêú×ß?›‹³¿†WG 4ÍWpîÖÉÚkægs#¦÷ÐØ£4)ýêoåfüØQ7Ät«^QoMXÃб†=}¿øRƒ@És/xäÕ5'pfU°¿h$=³…ôß}ÝœÓëñ‹R–Šfpš: öh†êÄnR÷ô´†4 ¨¼(‚ba·Æzu›Gªå¢ç›~ÜR½yíð¸âá¸bcúL¸ªZ¦î’PT·!ߎ[ 8õ/Ç˸óÚ(Ö§¤º’üâKãYÛ‚‚€#Á+óSݶO0Âgp ‡ð¶}(bmX~€p&žsQ™pBDualuYŒÓ5UGï5d4ïhá3š¯ˆú¨åYê¾zèd@“¦”ÕÑíEÙ;Äqbá׸s6«oœ—µP¼ƒ»Y‡¨×B39xˆórmTS"Üikͨi­A&àñ27ˆ0“•aÌ;ï¢<ਛRÒ»ŠŽÃÝI{z=°Þ¶`©oÛ!—ôm!0Èf-íwi𼺻¨à)z¸9ª(U PõlLGÇåþ¢3e£CP/»EÔ#ýO×O½r›hËÓ}å # £e­JÌ5=ä@oNY@˜Í…#äá=ˆÉ8 -Ý#·Å’ ùcÉ:BñŽ÷çÒWÍPtd°RÚäPÂÖnnþh¹ ž{´æ1¢k%ZðHcx²(»n–Ìöó…‹UF&oðjùC®IA:ZŸg„Á¼ýHYY¾ÁTÃÌx諆<³ }ø¥8(Ѩ+_¯KÀMÝ&-ghEÚ’Ø|ÃÌb³òe2é–jÖþÝÕÝ ¼ª<ØežJ)‡%¶Qw>¢±}²!'"i¦™ùr‚îl¯䆱rvÛ€âÑôÞÃWéMÇ Í¾HŽóÛ'+³uÖk~G×ÿ€9lö=B› ò‰ ż\:.§|ÁbG)u<±¶?Š"Òã<°ËÕ ×³í¢“R%PS¼Šhb‰ å©ÈŒÉØ/bh…ZHk]3qîn¬•b'U™ˆX€CSy:›œ½_à^üI5–óg]| >*²ø#ÌsßSµCÍ‹ÊûYÚ¢JF Ú²wYÉÆ¤mCöžîÑËò$™«eð½BDE×ÈVy±žF¦š¬MØfBÉa[fîêõK' £Tæ=‡– YÇc\1ƒnÂ|œÇ?¡ƒ–;Уý÷µÈT²¸ï Ϊrj-pyK'‡¿öþ”œcµ ÒiKÃÚË7 3»Pˆ0mù…ÄŠf¥![ýÕr …­R~ùãFĉ5¡Jh#ëc5áš•Ãï«’ä ½&KôÉqV¬¶õѺŸå”¿S¼Ð ‚žôn§E-Z U>Áþ’ØSVÁ¿£¢HIž§fè û’î"†‘; *I}ü;=K.f¶kj¿Ç;‚ÎkTçìçÏ!l*ÄVÑ„×ÒæÉq J Eû’lzˆ´ùàŸÊpU.×÷È&¾ñ8e÷dÇËAš±w œb¾ÇɸlŽÈ*_Vù´Ü"fWÉ¥w:±_ºMvûûV‰o¢hXÑÉfûJOóýߢwÛ[øõ7fI÷#«g¸Dþ°]ÕÉ„CøÔ’%sMpâãÐïcˆ=„.tì±ðD5¿—’¶\è\Vÿø´›3à ﵌‚¢úžìd; øÆˆŠ[>™Â´'­Ð’ ,"*oâXµ*~(ôÚ]ü¤¶Úþ†‹j 3J&õüÁm@ÂREÿpúQvB•Y‰ÿŸSª±Ç¯ MI& ‘Î)÷ “‚.ÔÖÛa¹ #É…Î:@èÍ*!颸¨nó !I…Ѐ’€€ v´°Ô¯Ö‡µ#%ª~Ž¿f{鞣“%¦oH/{N>¥ìjçdͱv¤¸ H«½{šÂŒØ>£Om‚ä>r8ˆ,2Ö¦ø¯üÝ:+þb»‚XÛ!Ù ªN»Q®1sŽÈi<—‡¡ŽYÇ T™Hú·>¶k2’fçÃüe€Ýd9cßw<;v¤G«—6{èo­û5f»ZT`™á5F¢ÖªPÑz–,´ ¾ ]c“zí×)K6 ºÑ§ûS9F{ÅÕÔ†s‰rª«v§e«Á†¨jž¥`|îcqñÉXˆPªrJ¸{Qô±`)ožûÆyýÔÌ®!Ä;¿ /LØ#û ŸŸ3®P¦±ÊœK.‰L&»+p@Üͪ9OU,@µsT‡Ëõ¾H(¼ã«¡p›8£í$3å‘6ú!æÐOÊ‘{Œiæ~…-èi”BÇšðù ¨¯®È¢êC…ÐEÖÓÔc—ÿ¶*!VëlgZþ2&IŒÂÑë|ß‘  Œ ™{U, ²ä"·¬œÎçä£úÍ ©¾Y¹”"N>$*“=}QRqSî°–±/ÍRµ(ûónƒ–ð–y`úCPYí$…5ž†€+T¼GL톬´†Ÿú±W påa ÊÁ}îÂN¿`®áðqËéýÀ·pm‹›Â¤ý8²Òk$êržÞFëôœ’.ý¶¨Û‹,âä@ŽlžD ¿Ø$\¿²RN@k{Qçˆ+¯Š‘Ø[/EÍd¶ÞàÅ&4"uÀ,ùÈ÷,è(ñ$Ö~Zm‰¡gO¼P \3§„줔dŽÌü3­]H™Î{Ô7MëŽÉtWÂ%D¤öTTMjÇù+ï BjÒ ŒPA¸‹t{š‹·ÿãU£õè"ü`n7׺T}Êöµòé…ïˆé)ü÷"5›Ò¿æ' µ4.ÜÌÿ~ÎÕø‡h[Itd3O¿«$Ér¼äûÓ$bÒn„€%¾Ü­Ãß7O|æ¥èhz·¯†dþML Š˜¿oFVê¹¥¼Þ$+Ç–ÁIÐþ¶E­i6iAc к(W5®µã•»ý½37eŸ,ä+Ù¬˜›’>¢ås€N=²R2ù¢ u})†,¢ñŠüziÒIÌ×zžóc ÕY =y G£Nù‚å4ºõ r½’€€ªZ³#'Nâ›—D©)U4Wx” Ì Ã9€¼«vB«ˆÿéoÆ$½´;*í>9¡G„Q´ô/Çfê ^çÝÝçþ«Û?Ðj¡‰úìµx0 -3¡\R¦ò”\=éEC8v®ý2!ù†ñÕŽKKu Î=€ÂLd¼^Ú×ò|`òþ޳±aÉ*[´šZÏ0Ò"C ±¸}bxy±—‰Ð¦6îĸD6ÎŽñžáÕñeÁ#ÎEHºB˜¬-xب—§YXëÇF'šÞñ Ûô¬¹‰t^:]ŸÁëjZ£¨É¿3¤íV·D"é,rϹ |2ÜõfÌëe;¨:¿œ5…õ£,ö s€åÚ‰ƒlRdD@aÕlç7¥í‚Ë»<Ôw1¸ødh®¹'—c¶Íë²&¤g¢‹¸¤¦¶²;Ä?P82á·Å|ºFà 7¬A¥_¯Eâ‹8¼B}÷á¢}>F³t+Åó}‡ŒyþaãvοÁÝfçóv0P:bž%òEh ûaïÛpàî@}Jp‰ø+ùâþËc+ñŒRò¸Ãâë&ÒÐ_§ŠjçU&ôL“lÏÁS1·y¾z’Ì«Òj â«å.|V׎nE9Üð‰6þȬ7®†DR„N9ÁC¸eÕ¿! Ø/‚ˆbFÌñŠHßyÓ7}ü­Yd ™ÙýŶ=|[ §Ê‚Ó²ƒ=WŒœ–Ùú„ãf‡Ýq–ÕœÒw("ÔÐËw „{ZS#ǯˆq¹<èuãj.hÑk‹R--»àûýzF\º• ÒרŸÙ{ÉÓkƒvð ¤oÛaP7Ê®8^Š?™®5SÎyBþ°ðð_’Óèžq¶ÞIx0™‘@ùg›1dŸ"'ôG†]€ÀÁ¹¤5‰ý~#Þ«†¢7±&+Çî ‘yǬ%!°€|½áà’â§¢%‘oHØ€IÂT»9¸1¨š¼óT³M>N…O¨øGœ«?,È7uÅO“✠ægìQ{åç³w Mó?¬Gßn´£ýí(®ìÖ2Ñeu@4½´+:’2¼à®ñêp†@¡’É¢³ÿqà€Ž”%3…Á»àü,Ðl ó³ÍTäæ8Àô;xP”>äèLæÍ´;‰âãZÂÊé‘:íæÜ„hª˜Ø`çê1o5’€€¥ôŒý‡+ \øÌð¤ñǤÇèZ3ývïèåHóäÛtJþÛà½LEØ À]]Q©{ÁÉ}>¡×Çl´õ+¯¯ia§ÇN{^l÷ˆ8¥o«—‚¹øºQL¿Ê¼z…%±/tn%Ö …ºé9«\ÌÏrÿlH,\ÊùŒ!½‹§(5º±±ZšTäýðIR^Oãïz1R~|+rbùjGDò%7šä‹áó}Üa  W¨d/F³9óMaHœ4ø¯mñGeMà½]'û)”<!­B'{Çæ—x¦›ðTÚÈó²m‚Ü”í#k4åìÞ·E*šÔ·ÉËQSà“€ŸÙ‰!ÀQâ £¹<à4óÅÎÓ #Ïå”;Ñ|$ñêÓ›Þãô_±ª©¡ä h|{‰̘m ”!tµÓäÌnzY±È~ÅF¢õ½} ™qPs=J”óÐ0dÔU2qr¦ˆu6‚?ôýö¹ãXr¨Ç™üY[,§ßwUÔ³)ºQOe ex b!ÅYBªÂ¿Òc?Þ|ašMäyÛ Ír-ùϲÎ?òíéÑ1Ÿ’µC\Ð9Xøp※Žjª±eˆž;[šƒÁŠU;“½å¸ 3Ln³£+Ÿíµ55C8šwþ>¢æž›ç8Q\’ˆ±ÌŸó-}R'`%ÿBïš­{ˆ ¥Òrm½ãüàªý™Leh¶¥È¹ ¨`¬K?b|9…›ØXK"ཷa°é‰ÙBö ‡¼ð’Æ MÊc¸&ºy`Û-b,,†Ô´Æê_lýäûòúŸÓÑ4‹(²ãEfê¼×LEbéy+'?nzsàj[Á<‹blñ5ÊML5.U ·ˆ±ú½fÍ‘µø… ‹qWhG{GéâÕa˜Ö5¡›Så­©×ÊZµµŽ«>ãÏ»ÚúŠÉI[Ù>0;§P箉žÈŒì€ü;<2ßþë‹ñu‰À·/qFN&÷¹³é.tAéÞíå.g¸æz—ÏòÛUž……$õ‘Òv!YgÃOë$“ï+F'-Žjµ;K<¼×ˆ0j;¼5YP–é°C‹µÒP}!ŽBè'®<òi¹O-Œ×—ÿ­ÂUyn¾†*Þ#:éª3Â.eÆÕøYSöl›²²K Ah2÷¦ŒY8·ÒÍÀ5LME™mSl®ž[’€€ÓüX6Üâú$Ç!œyJY-š‹L“Æ3Ìå銢¸ÞC}¹ùzm䎩SÕOæÜÄ{–܆™98ÛAz‘TÛ1[-#"‚Ä}e ú¶^T¶«ò¿0~†Ô¸[®ÜÈ®®º}δ ë d©'Ÿ_²èJŸhÆU¢BFñõ“tE%‘ZÝñI>o?…À\÷GÏßAPFjÛ.¾ Ú]nZpT«e…Îå YÄÑè cßêám-DŽÏî¿B­Biž£é_äD’Ë {ch\ËcØÁOŠ?ë!0[ ápoO¿Ó¹®î¦´¦ìõã¤6­+_…Ûƒ¼™ß<Þ¡dókç5Ξ(¦C 0µõ½•©HtÚyIå•Âhî% Hg¶ ³|ÃMGOÂ6f$ˆÙ Þw¸ÊÞ^WI_5§˜åML­NÃ×Üg¤—ŠÏÒ?:ê©g-÷kù%^ˆ…uoÏ:EŒÐ•Y:ùl‚¢Ã5!„BÁ}š:%m±e–LÒ=å(Œk‹fÚÎâ\¡€™ø/þPV#º"‘ oŸýéÅÏ b­v÷#vŒ‘}²ï×¹MGг<-ëÀÝáøÜçü´ªÑ™åºHÖi©(æcâQ¢¼yGé¥!_IÈæô Ïu鯉ÖÅ$ÖOÅ)ݘû¼Ô;¶ô Ž¡-Dy”Škœ»dórÔÜ7aÑf–²Õ„šñcK« ‰•Çñ“\“ò5H¶1—v« ‚É9ß-*‡9D©‡è ´Jd/¢b¸”F­•à¶'¹Èᬎ¥á´qÍkT‡W=Ê÷“7F’/t^U;FŒÜ18MÜr-2$g&gÊÉ‚nC€TGpN§wTæÜg4éûÚÕöÓN@ǫޅ%Tæ»ìsh6yëÓ'¬‘#7eWá‚™¼`â<âKõ¿sFùgNó# œQW‚COPl…Ä<(»œ ®¥ö Á ‰ñ!€ohÅ>¶_)çÑÔMÿ¬pFy惦£ÊÂVóVGÙÄç[|ˆwͲeD5Ý·m—ßDFâ±à¨Ù"ô'§•(—“eÑõÍ—sÿÍ`=%’€€×¡.þªæ`ÖC¯w,{uŒEM².¤¥ßK’ž{”3 ëH„"¹(Ä›«—Aol±:ü±ZB ôcerjö`VíñDw6ó^³Ff`Â|Š1ûvzÈ^öX@=U&•ƒ3+²s`æÂ)9Dh‹…å¶p7'ºQ`'é~Y W€œ–õ‹?xÎÑKlÔYu“Þ‹ØínZÏ@‰kmH§ýƒï´]Ã¥öž Ùä¥üaa¼B›Ñ#ƒ„‚týê47\—0Ûˆ|0pÑæšÄ¬×ðÜ:H†l’â¾íýbÝâ´U¨A ÀµÄït ~œ|YßXÖ-éˆ3&ßÅê‚×±Wm¬¨m°6úZZhj:‡xF·r¹^4W¨t•N“Âû‘Í2gS½dZ2'óÁDËqvöÂê’ÃÄÐ>‡ ëjðýÇÞòÃ̲x‡$*hÎTÊçlŽ=g°Hiójm×à6ÙÃÓ¹d1Þ©¾T{„g¢”Ðcí™$Mñméyïy8³9®ô àûE*§Ðã´!Ešlé '9Ÿ¡÷ËU-úH˜ST'¸d³ ,Z•®Æ&¿wx6hÂÕs^þmu! ªQ)Z$³#«“Šñó‡Í”ÛOÛm½ÎA«}uár*7IHÞ¾§Z䉳ùÿ`¿z ø–›bpž•¼³úh¤cß¿*–'μQPüL Q»z…R®o`UÈ×#ÿYÏÌćmOíêDœÞ}]HÔIÈæˆ½9ÈnŸ0òž°ÖOnõÃå p‹b»u¸kjíÕM™!ݱSÉ5ª”ì˜Îq/¦pZ–™…Ÿ]°‘f#ãˆM@XYRÜð'·ö2€¾’V:0Þ­0ú,MíY4HîÖBÎjÑÉYPGž”4½¼qf‚¶ÅSÉg«}#`ñ/ù®N1§ž[!§§å»6íšÒ—A‚çÕØ.©C¿@,Ô>ªÿ©A\k ómmví»®Ø>Ü#}XŠÝà§[±†©ÈnºI^X_X‹ÝŽñTk·Õ­,.-üq6ÑÔ6°‡L¯ÞĪ{c:2¸MÞÊ«ÂÀzíT¨?Z|B€?ðL†ÄNALÊ–8R2ß6¨ð"‰ç®ñ£‚n7ez².®³¥ÓÇbÿ¨•·Ìù[ÎÑÓ# 2Á±Wÿ¡eÖÁ¶_(“É”3’7*x:}?Q¹«¤òõ pEôz $>JQÚ”®¡bÿçèòŽÂ² 8Ô uÑG¬rÃÀ°fU¢¤ùMŽŠÎÌ£íU\€ YÆïÀ|@¼âbåÀy<ž] mˆy@)ˆ~Ếúi§ûÀËçÔÕqü ýX—uœS§ÝðCÚä`6fŠ(¦( D‚>1eÚÅŽV‘†fÏjpé³áЦÀ Umî?ÏRE"Ù5ƒ žƒx%­åéÜF·ÄãÆÕƒdàÿ¦;ˆƒ³3gs2õZþ›P¥Ï‘,·(W/zŒ‚^ÃÃHbt¹WxÇÀS!1µe>â?Ùƒ_x1pY>Ì ö­™ï¥© 4åY_áZÃcƒðJPØúÆW¼#3ë¶Ò&!ØÒO1EFA1_N¼ÿ³yÂh'¿TØ¢4¥þ(‚÷t¤éÇŽ|Á‘¥Í>³0}{9x9žn‹ñI,#Zö‰ ¦HÞΚgÄªŠ„8X¦L£‚eGùWÐyõ"Bˆ—Ï Â6?;íÞ¥·¡#°Ã³Q¼gÍ·ê/-Êâ•Ö€rÌ;‹ÞÛ§*VIlVþÙí ¾GÀàƒpìKÔ Ùûk¹åMˆþîøq¨þŒ•TniTþ(úÅïÈIÀœ\Œ1ªÇ™ú˜ÆhOC…<‰qüèŸ]¤yÖD“at|ÈÉŒ’mš®ÿw†i{ÛýµÚñ®„ë0áh@€NíT$ö@^5X4¦Dj\R/ìàÊ}ð—ŒèW­ÑZÄó¦HcNËgR€×AW$€@ ùz­¾Hÿ4ÍGp{„›^¶ Ír”ß‚š Œ"žÝ‚®¦ ¢-LŒD`Z²ü¥Îwú)è“lÿÇZ܇F÷%‘*†gþ~mäÍÌM\ûóÒ -,n¡¡œ3mÖœo+½ð|§õÐëáœÝþÿò6Á0Ô$ oºŒ+%~îjÔ‰îë†2)‡/ôWÛ:ѪR¯Ï†ÂþH_ª1Œ¼RËŸå[ÙVÙjàå/£¥EYøl;¢rvÚ¼u¾¸ˆU­fvøTHøéV;$ú‚Óú"* Àj1y»ƒ4'lWO{ØA‡ø™€šé(CLp„¿thn‡p_£®õÀœ©â€¾Xr‹(6gÔr›Lpô. “Ô’€€Úц• >Ey¾ÏÁû-'úN »ÜÌâ…:8Org(ëÕãŽÁæÍ[P¢žO1>•3€ï§ç £©䃜0z ›LŸ‚:º23c€Ž­ ‹Äåx äÀ 'ö555Fæíò[ýŸ¿æÝ£Ø4,·k8XY˜l©)7Ã01QÒó]òEa»8vNí£æC~ûkÝö6»šÈ£«¡œÿq0êÉ«A,Y@ˆË\!“i†.£ºØÕ£ ¶õìM¸W)XMS\iuw#·ÔøAdbæg­çË^Ä_‰¨ÎÜÇtÒzG8¡ƒ<¶'"Q¹,Ú‘Ægä™áöÜéå òQSpx™M¯ ;«Z’•t&ÄxòÌKa2Ïì\äosË& ¿`Åy‹X‰;Û¡íAí¹xVÇÜøW¢Ùް)¡MŠ­x¸¹ˆbÚkذ1÷¦¹w,ÞžhßQh{:Dîºnº×3Q«ÐÞC€‹AÛ?™Da÷ì›òu¶„Šésl¢Ä)]×Ck%8çTP¹>(6ºÓÜhP‚¬ê®sÅ^F±*hóºíI²,2ñc_ ÙÚ´¤*_1]d»!TêAíR ”œüRB§9e²‹M)£gøºLθø,!6 /Òûëntïwþ9´öþÕìc¦’lq:”I1#@1ÆG 4-&7Õc«U½óÆúÆc¸Dà¢Nâv]æ ‡# ;jú–?"-f~ö)º°^oÞì†ßN@µ }èoÚmÐK§êpXìhA¨•Y-1I¨DHà`©cÉ }ì+ª Ä£™0J‹³ˆà0 bàÑgrÕÝ"TÆ­)…ÚñÚï®,î‡~3ÝôIr^åÊ/„øaÂõ[9Õþ6Œ*SNà7„&»Tf[Ùiæ '°åÐý޵-R-/Ò½/-äH a0cÄ”ô•Ú6‡‹äžcòaèÅ q& 7æœÏ›.Ú"o}ËéF!Ë@Þ#’ìRáìMûÄ¢9áKŠÜ=Å ä‚̳T··ýòtÜ»°fêèùM¼c_ŠS±'À‹¬E°Ð‡ ŸÒ¹ì´+ NaÙE£+—kÚníCª¢¹¶º#ªhêµ7ö†J²táÂg÷Fs€ÍݱUÂÖoó?ÀKÅûÖã Z©••µ§5G_Ò"m±fq^y DÕþǦVn ßÌÃ¥+ «'ŒJ$¬þn›%IÛÎ[^–#ÁõÜtxAÈå 4 ÃÄ€œ;³2ùã¨|®B}o™Á~?±8S¾÷Xå#Ž´}™y-µTl¦Ã!§ï¼WD†ïÁ÷äNæh~]ì`è¶·™n)¨ whª4Ÿ¯ZįòRJzáàY¶¤ZÎ&o$Q‘I}ŠE;Á¿òUÔæ‹€Hž‹‰ÁOxP}>Ä‘ÄõŽèÔP–ßTsl<ŒŒÙç JIß¼Ú A¸ eŽÀlö½Ò;sB!‰µX\eØ`åáPbë\–˶âú…Ç+;ï³M¡ü—!enöhýåµ4¦†Xå ²/¡ïEW Èöõ±Ÿˆü7›h¢jóh)_N\¼sjØ™0€ì4LV¬×%¯¦éa‡ä|!²ƒÈ:@ªñ6r‰ |1÷eT“ÍÿÝBhÕô=L¼á«ö+!û§-Aþ¡ñ堼℄•ñ9W-/X¯[n]ñ¿ ÖbÏæ·¹¼nä!6¡žºë3¸â,¤-–Ò ©#>DѮڗ¡¾vʸŒ9óEˆ#ÒjJ:>À”œz¨sýb‡ô¸8Áàrà4©„=®‹›Îï1êv«ÒN²Ê¡bÆ3¤UAäºÈŽ×6¯NË—g>€¢}®Þ•çÌàyooWÔÓ¼-:?EÚk)ãC’)÷{ö?×ðO!¦ÄœMzÃȦ‰h ÎMÎ’€€ÒÍ#6}nÞ ݯ;î¬xªÍ–Vžå't x¯pà§ÙÒ¨8‚ÑŒ†]±Ìÿ]“p ~%_×rãõ-IGðäür愆’ß;}Ém¯=Näãl&‚wy…$ËQÊ>ñ˜×¬(Í¿^—ö¨þ„eÿ† ¿ÆÆ!¡føŒúÎváS–ÓGQ¯T}·ã.2*Fu I¸ilÆJâè¦ÑÓS˜¥8Ú´ã̤ݠ¡Û®öy?¥ñèreiöJ˜9V8~¸¶[ñpÜe¨¤´ÜJr×P·vqãuìEdv=vÞ ˜>¼s€&D9ŽòO¼uÚ2vSÇæß´µjn³ÁqÖØðˆc©ÌØzq?ÐpÒ×E]ºÈà LŠñšQ¾yizµnfjÑÙw²§Fï Sš{Äj::wK½í.-0øµzîîs ¶Û*¿]h¡œ–ãh^YJ5yhTC^R3™X€ñ&í̪"¹ðv.FíqBeYbs·Þ±3À(èì’€€ß›G-F¢^ýLÃP%­f•Ó4üFJv}Ÿ­µQÄÐ<¤Ö©`´ù#A í1_[Ã8õ „š`}ç£täZ< ‘ó]-³D-Ÿ` t2-L"Q˜qJAáàËIäãàø>…r¾+xöèS¦ÍµP÷d¨S÷V¯whö­Œø( ø›AÀ:ë€QÇt'bðÐL>sßw£ôÂzœØ91ET`ï•€z¡C3QK_{äKYÝMX ˜ çp¶ÐÒþE‡·Dñ8™Ž°3¿ÖöVZ²+è(Y÷äR!Ÿ¹–‘òPÆEPN’»Æ•’\~»›@T:ýM#ãáV´ç)¿üßð“8€)ÌU¯‘ÍwUrÖσÿL ²Hu º2»²©Åð¦$°x¬Aü‘ èŒGAòú™ƒÚCOÆ¿.ÑLý/GrR$žþð‹¸/ ¤”K9NWxÈn®ö‚?h¸ÿÿìÐT,é§ þú„êLþÞ‚žÙêJLóßvšÏEÀŠj‰¨"È•³­ÙižHªÇæ”ÑÌ#^âtÞÞ,ž•À¼ ½!P¿¬ øBb¡C+tuÐíjñ½iªÅ-MQÁZ•¨óÌB¦¶Ö_ò ë›È€ahƒA‡¯5oíÛäöüÞNŒ4*‘O~wºŒþ‘ùƒâû!mŒ_m÷ŸÒ 5 ²AÎ âaA/“Á½›Œó Ž’ Ìé+îûèFé²[²4W*SS*¹Î{ЄL$»`ixA1f—yöˆLøV¯æ¾ó×—c¹JIð>ó¶žöX’£õÜ^V᥉QªÐ-!†øú>ÐæÓdªZ1åkÍÎM‹YþËÓ |ü_ßòDš=²L³|“;¡ è¶¼ÅH©¼¬[Ülƒ&(˜-ßú0ŸN–¡Œ`º*?»íìûÑli¿ø *—tGS >\°Ežd1IóQÜEë5 ÷h+ãsB /'æUæ„ FVôëõ;²oý3^³ñÝ.´ÚúOö™'\ÃŒgÎÕseŒƒ}Å“95QG§‚sZà—OÆÁÒŸ€òÏÊ6Géu°MÛM¡‚OWÂ,Iq„nˆ´èfá Ï«;eÂÓHdíÆGíî’^¤#²$=¬$3µË†¼­t‹:ÎÃ3&úPk÷Vðyy0À5’€€àÅø=L´818ôªj~#uS†A·-Ôß f$[Ëôù7ôÖOŒdGä[K3ëůݧ¿F_t{j|kxRQÓü\¨Ktî8–1h+‹GȃwP’Å )DJy5 “•ˆÛ…àlUÞ7Í5\q~JMº$tN¹£Ä8Bxª e÷ôÁ@©BÁ¦/a”rJ«° xi‘ã\»ÎU†Mè­C«âôþ"Rì÷?ãt}Y*^Á ZÀ}ˆ Dý&«ÉúFêL·ú~¢ÛöÕ„g”;7˜£A°ÆB”…_u!)ó›h9¡I<=ðëã§ÜS›‹“æ£òã•:ÍR=)’ÙAVγÐB>ÓÉØ×5>Å^åVîˆu:Ô­d\]y§íó?CéoË;ÄfWÜ-|Â!3£B]f¼Sk®•\ú,Û “ §Åó-ÚMÆ»¯œRnl³„”|ëÞxÒBMuhΕg!*¬Ã_î©8­†eëqݸ1ñ¶££‚”±âËè}J3:_̯wçiÏ`Wg+R¿Ý©§Èü§LŒÜ¾RG¤=t=I´Ž BÞA]”¸v™ 2q©˜˜³VÛèãòIç8ø1³¶-ôVrôÇ~áZ&Ùм–~;;³)(Œ÷Õ@›Ü°)aù_åZÿùŠ¿B„1ÁJÀ~8éý$ªˆÀ.£òH ݶY )$Ø  çî{œ^Ôô†Ÿ.8m´xx)gj:Z_è d@…ÚF!M›ã¶ã`§ÂpR„z?Ö•îÝ®àìwe¾9=X¥B>騬¨Ÿ kYX¼¹­æѶ¥²û±êÏ5LºócÐÐ °™à8ZnñeÞøúèiªp°ÜÄÿ´zUÏ ¸ÏŠ&ÅæÂî½ÙÁzN$]qX¸ËÖ¶Æ1†´ÆxÞXTbFm²'2¹ñ®”zwÐ^í_Áo‡}çÜk6TáuÞ ç +ÖPÙuù$ÁÏɸ>é¡›˜ ±¥»ð×ÔÅÛë”Æ­ÚZµ!W¬Êßu{Ìzk~¨×NiM6U$»«›tsô²w”gëxZ«‹Â¾Óà@ñiLäºùˆÓŽûöÉÜÑoBue͵¸7(¡øJ"?QááÄ^ñ/Ø_ÆŸÏ›¤ÙÒ3°Ëéç¡”’€€ hØûãÕß²pÿq‡ƒ[X8?"gÄ,fÁöJ$yÁðÍ0¨»úHMРp‡Ð!³WÔ!%ÑŒšƒÂ7[¥Rd€¥”ÈÜj~+®N$\oÇŒ3nèJ¢YIä4_MsèyfnûK§w•JB}U_H÷†!©¶ï.$°Ñ®ahÞÎΈ|Ïfëfð°vC»ŽOfl çQsûT`TSØ1ÍüŸ˜ü#X SMûèö)(•N;—e–%0sØ!øüapZÕó«Vì~_åhàÐ ­*xU§¯Ü$»¸<¾Hîdz‡í"Gy«X+÷T ƒ‹‡vþDÉ÷j›GÕ« ÁÙ »G^GM%0…nJ?Z°”ËÝ·N¦D—9‹úõ5)ø~,…n¸ÉmB«.}.´18SæòM´`æ^FjWˆ§±c?ÂßP€p­ðæÌä r(ý\'ΛXT–éG`•e ÃÅÒ­¶D™'sâM÷DìšJKm ÖPá#؆YõÁB’Š4itÉŠŽÙ!$¬ki>Ëï—3½™1ñ'x†£hÏšâY=Í ÇehÊÅÇ=o½g}%ŠŽE æ!£ÄÖqæë:ßC Mz0YQ­kžì/$nHâRy¡‹~‚8ì#óâ=!PêÿÅ  @~¯†·¦Ü‹ Aam íušlÖMyWXñÀ[p¨ +§À3é‹£ “3ç®Ql¾A`£¦)’€€æ·mX0›mi 7H¡å L“ÞeÐU¬tVåPYùNÎôª¥nÙ.:®¡ˆrÑFÎ#]. ¢lÔϤòt•©ÐÔ*k=÷#ggœ,”²G­@앇Lât×õ© Ï,Ÿk¿ž{ ªið ÄÄ Fl(Ëd³¿¬sà×Ú«1ÇŽj𝩳`²Ïôçbû¬õ?ú”«Ù<a3Ìþ4‘•¦äÉÑôïuŒ—i#hx‡FíCIN%¶Þü‘¸åÖ÷L kÕªz[ïIËN…èªD§<„™-9ÖdE^'¬ÌÕ«[ŽÄ,sÇh¡,X‡BoœÉüºs‹(¼ó@!cŠ'<½†XMÌßFCµí;j|£Š‘Ž+ ƒ°EÏÑó.(÷N¦´ã/‡s q")BW‹k#õ£hÉa$ËãÞlîr :ì6>J¿oYI1Ó¯¸,6. Þp ø)3` œ€-Í¥;¼¯-ÅÔü ,绾?´\sÓ²+UØñ8ú>þ²ôsº>:úD137t9p FÒ€+?‰=ö˜6îŠOÂÂX’ÆU\ð g&5z©®c),ÜtƒZà&~÷ÄQº ‰Š·ÉQJ4†ˆ92´f¼Çƒ@÷´¹§¡ë€²—W9«ûBÅžïýjp)áQûý9~µ0v“Tž0Á¹ä$DÏ9Ñ\85ÆK´D…sÅ~·T è&¾W™R”Üyá‹x75¤Pgضÿ£}1à §¬S Ü ß'™ZSÖŒóg½¦dе‡³Óx#Óû´Yª …ôè)¿ipGaüC¶ˆ żBŒ²Êgë6²<+ÊXìò,lJòב¼Rå³ð.¤rccA&2q»E~‹·#_¸~_;XODX+–SMb÷6ü·Á1¬Z{v¨EEº˜·n<úw™o%è“–ˆ>.4MùXÍ>§Ü†ü$f^ô¹"~Ûï2æÀã ã=Ýñ \_=܈NÂäŒM4ÁÉGÿ¾·øçhbQ;u䎒ˆ˜‹ûlÓ™`à ›‚Ol9Û>/Ë˼ð›…ÿA­¾„â(Ôúþ-ï‘9@ªºÂÕPy˜¥ÆOVïÇÃãŠG4¹÷ÂÍx:ÿr1¼¼XÉ@½´1€}Pu +ËLdz¥»¼Ôñü’€€­uvÂn¾/I¹8Hqñ—¼Â»Õ¹#,W1þ‘CŨuë1ýAD/9!úŒªÙÐÍ×ÜÀŽë´î(ù©§ßݘ@W‡*7#mHeV’óèÒË2ãI¿VôÑÅ€y«EvQx|ÆìÌåÌ0}P4Ï!àŸïçŸòm\Î-Œ 3€§€®×-¬Óã‡QãÎh kIœ~Ô”Ý5¿•ÙõŠY4'ÿVЦC;ªE_ž~uI›‰ ‚_Üßö¶:þ ¢›¾ø¦¤zd_•gÿ¿ES4´5p¯bˆ]·Mù¿%:3€˜É¸½”2¨¨&§ËcÎ&b¬×Íļs²ž¥“21‹zSç÷CÔÈVý|-c…ês:¤3Ý£M¥NßoxÂ^ôÙX¿âhl³8æLóÖÿÜ\µÌ¬#‰‘ºAtK³b yíu RÛüÅ–ù‹ÜŠagD¾ãÜ葨ÊÒw”»CÅ*™#¡Q²Wu†‘e +}‹¦Vdëàš> ¢Ë,Â,Ä]lÊ‘‹ZŒêO˜kjup+2;0H ÏÓùbç‡)'P]϶Ûõ{ªJ[$F¼j´=5y;-;ÉÒ8Ç„ç×½¹$?ŠÞ‚Ššî ßá [lšfêç­–Ï!?AdŸZäB%=ÔߎUô´÷óc-௙p¼&ö¤ôH@>w¬»ö• ÕÉ8ÅÓÆ Éèû(Qç¦Ü™@%>_€ÆÄµmO‰Óa'ç³ÖÝP»ÄL4añÛów&!ö¦ô)\»ß?èºÞ;„ÒphŒ%¼á–ÇÐŒeqJËڱܭ‘'6~³ßüµz/7V¤_‰’2á»V¼©:mÄý,†«ÆÑï‚Æ¡kõÒm6?ÿÓ­^@d O¯*;štÚ»­ás1nÑSg¼Þê)üÉ/Í1¦ÜãZ7*â’Ó§·¥í‘¯ÿa¯_æ‡ žˆèû£GŠ‚i×ü¡Iï#ªƒ—ÅùvUõSŽ0Õ b¼b"åÿ=ÂEi¾Ìô|ûåÚ¦»ÝÚÛÀ6_€îG-¢·ÃÚ%t·L5×Wf÷…ØÀß™RY¢raA=ÑdÕÊéÕ¤$$Š‹/b"×&-×z¯É]›àæ^ð4~·Ý$riýY)ãÔõ;ˆ%#C“Ȱ›‚‘šry/Á>ç$~½:NKÏU3Ä[› ]£U(K×’€€É êSÉ%¢ÙûõÁ^ý Ǥ"0wüq»¾ñšr6:ÇX¤@7Së4]ÆT:CÅ“/RÙT_5žÀ/.°ðwå}v ê·Ç^hU(Wg›­Ùú“Ö°Ðjcè1=QÕ7¨:„¼£\ãbK=*•ÓµGŠ´*A@\ 2s8]‹—NI³Ã…÷wÀ~€ëÁ8´yc¶­¯.cÐ?,&2œ¸¯ >\UZã÷ˆ˜Kƒ‘ïÞa#Ê…ËÐ~D“§Ø•¬"4õüTƒ,Dx¨óklëÈrZ†ZUs¡aÁh«ì÷~ï…´³ch™·©D(K_yÝ RÂRÉœÐslpàþ?lÓÍ%JâW€àsŽ l{Y®‡Û dC.Í,Qz=r½W~…å„3t"H¤Ú¶›Á#;Šû‰Æ~¡”61j¦Jü3n™ щÙùÑ»›ÞFÁÓ…­Ô|{%4³»Ù1ÓáË—f:›Í!òh<òÏà*­oÈ@}y#/¬o+VX.qº}¬»=8#ÒéÎÀñhù¿M‰üvëÈ,˜„€%Ö¢0:à“ âßšÒ2’÷,oå‘¿[»ú÷¢È÷Ò.tœ¸%½Ë9”{U$²9í&7ZÔ.ç8¹‹ò^Ac·ƒÃ¦ùª~¯]Îx¢B‚Þ:¹(3»´Å ¸Åx ›44-#5s©@CZø-‰ÏÜ)Pj />¸Ð™Ç¹´Kÿû€\©¦Ø2ÀCÉÃØ+(48[L®ÂeŸgDJ©ò>‘˼‹÷™Ý\z’P‚9ES[$ëâÓâsâ‹ëb4’€€Êþ"Ô3¨VÎÆÃ:.ææp׿bºÛ"y\IèÖŠÚPǵqÿäcè¥2¢”‚%¡6d4ÅçyÿÅ^ŸûñýµÁpoîæ!Ä,Äê}ˆº÷ê¯"…[ki覘H|^ñ@ÉpË™áü5Â'€Ðm[—Kvñ‰çÃü€åô*2øÈÜì€øÐZ‰ptò9qíÔò²ƒ!C¶Ìå~dÆN½®”}¤,%K”¬xÈ!c{gN‡??&†Çþ ždEŠ;lÜ…‘׿äçDJñ6cªZ#¦ZdóÈ+ôÝå|“«)$XêOÎ…ÓÁPà!Œ§CxÂh=á.Ä› ß4’º,¹µ1ÚrôB~Õ¢@ BÿÀ‡¡úm¹wàK*@Œ<8O¦ÉüQP>èŽ{áÑH7#n´¶aæëz•±‡¦O€a57€Örn×AÍ5¶Èu)&†Ô„õ“ÙÉAjʺ$/×û“°K^MåFÕ¸*ÚH–ÔþúkšZPýGÐ4•í8ÿå\râ,4Õ}ô +U.(ÿ* ½4+åªÄ Ì€ mÖ§ÍR©ìÚ —€æÂF¹àƒúj£ÝXïrtÙïÀ8tWJ€‘föáçÃWfÍJû‰ø+"žÜEÇ¡SMÔ‹8Éòø¹ÜWDx»ùìï –yuå¥`î47äë˜mö süÀ«}ÜÿþšýËÊßYGîKl(£a#³Îqz/ðQ3‚š›~ZûX^¸Œ«Á¤1 ÄÃ]qu< éå9.Ì?uB’r²Ç<×—æ[ñLÞ ÍÄ$Ǻ­lîw[<ƒ%Ã(q¹cõ iJn– ×ð©×ሥǩg?cÊ%Èlõ0šsCç^ƒ_oiwvÖ^ /KQ¨‘0ù —åë ûæ¥oþ÷;¯jȰ@Ø‹¨³N’€€®¤*bʲ`¸Å!·Z†Î.BC÷¦8¼[4fúÉÐ*X‹´Ãý3f´êOÄÏ’f/—,8 ˜¥¬™ìb,7¦,$OÅR`1ˆÒq˜µF—»ˆ(EZm!aëùEòë”aÏöóæRÿqZ½+JÏöð;¥Œ µ‰^qk*ÆCe%i;*g¥k@rÙ»…\v²&,ƒwˆ+&X'>©G¡ãxb¾lµ¤'iØù 0“rF³©¼qÞÅ¡ìÉM✪Êa` À³^›- C6á‚lºPËO„Y6DÈÖ0â2Ör!! SëçE'g\VÁ7ŸÃÆ̶¾)ÿý¢㙚.Âï:¯Vß±äÍ?¢}Sõ“ÑOI‹wœ+Ñmœ,Üã¶Ðz£‚‰O+Ìp·K£íPŒèȪWd¡Gx«†™W’Œw(£ñí³Þ [òž3Úà=lŸˆ¾ÔÝÚ/%Âò1š&…GÑwén„‰úbÜÔ@LçËÓ»±9ï|Θ8-¸ ð#©bâsÃ|øëÌõÅ —ÜTÈ42(Åic4¢EB6FÓUÅÇôò™f)k„–7¬Êd0­tδ}_bDÑ´£H'{øB…]é)6nfYë…?%ÇZ{œÊ¤~jÓ·ò]øyœCRŸX1p~O:Ó$´–tPÑÓØØ”ŒÙÍîIÝœŽ:Ø]4O ˆ‘>0™onùÓ¢ío¤ž$ä§­e#!OÃÄ@þ¯*Ífhl¤Ÿ†µ€õ ”TXùßvhó‘”Y ¢¿uÌx¤EóÀoýÁk|U3„ŽS¾dó£yoÚ)9ä “$$eÄž©0¸Tò"ßñÓ 2”Œžì"KÉiÙ|ÊùKEGæAáÐILþÐS¾Á*$+ê_að0°½y¹ŒâÖL9ÈEèš´½ñËé4Åɬsùº ä}AÓH˜U­ *Ÿªgï2a™ÉOò«¸/zrÔn^¿€Åµé¹ÕÝ MŸßXh£ø„Êl͘¤œUëB½ßh¤M«/ …×zuÈ-MçK q-'%Ò;“ê«®v@™£>J_®¥â‡¥Øö’o×"U¥ð¬ûR0±.åeµ'ª8IJIMˆuK´¹§þˆÀBhgΕü ³kÏuác›QÁÏ®IUùŒeº9¦’€€«ó YGU{Bèõ,?¿´h+pœrÃp½çg¶ ­áQœW²:ÁWÀ˜4¡t‘©ã=E{«©ÛTígñ3Ò)pðÍ3žœ'ì‰î÷¶YP„ÒÍXàZƒ9k(C±‰V–á…G×u%«±J01&Ér?r.Šsäl¦âV`6yÒwì¤ÑŒÛëŠ×ö¬ˆ°Xª;+¡ƒ‚_pêŠ.„‚ƒLª¢ü;˜·£×_/kÑœ<¥ &Âûsž ®>Ý›Üè)ÚÜn $)F4Q–c—bCF·ÏV{°o7‰›€¾†Ôüï²²••k¤„oOAú‡0rí|:2áÍ¡¿<½©Ù¤N¡g´dïÞR JÓuŸüjÍPÝÌgð÷ÅÕz¼lÍ¿]ê±òQ×6…ô‘j RQI¬ªœ£Kl©à䫱V¨8½Ah¾È6¾Š"@Ã*>y¯Ž¨¤ÎÓ©>×%–°˜ðûzýÔCxÃh Ü]ª§kÁÒqõ0x‘,Å ùiÃÕ¨ÌxðéìEu¬§±kBC3èÝÊÊd·ÎXJ¢ƒãð¤IuÎ3ð á 3ìºØô†(GRÃ…ônø•›|˜ßKÌh•'pRÕø¹ÞÒ¼×ùïBaFÊÍÃ=™R—òíѸìæ 6†ª ô‘ -¦iÑ+Ìh­ñòâÙÜW"H²½‡Ü§cÀ~~žá¡´­§N‘ÓV6¯YÛu%RƒJš¸zUmµwöžxþÚŠ ãÁÎ+¹7ý\iëçׄ]·âuÆÐá—ÁöXÄÕìYÐ øåùdÑ÷qÎbž-Òf©—Çï[@— uì¡•Kõ߆eûÒáx3ãØ•¿ÛHs«[ƒÎÛ¶ùZ°N6 øëÊ‚‰‰¨~â•r.̦íp´ÊáÃ¥£[ö‰\ŠÂN”¬ý’ÞŸ·áJL̆×pRiÉô]ôò@å3ù´¶©Þä;Ùqÿ¢ì0¼nO'A¼rçñܬ zUÃ’€€¿•DlŒèŠ=—FþÙ‹Æ x׊B¤ïO>±ñÑî·ÜÀ>â$ÛoÔÿ_Ó‡ ­ÿomPbk¯®>ZoåòȆ²G ø1R‰ÿž±ÉS°9£ÖPóƒç®E)©cÞm8,ª%i1??W¸«^^T×B;(•oLÁF2ÛÅŸ» }Õ½ŒBzÀÙ)þ#IA¿zŽ}xí2ìm§oÜL„øý.¯DakÁWÜX<"4ø  2¸ º\ìE´yéà¿®£Nv@¥ôŽ=hÖøl÷hq"W÷v6và4}ŒÙöZæ^äc#.Ûʶ©qºõ–·õ–êšÂbL:Wó@Û2QŠžˆÇ«‘Àª¤·£<Èëð„nªºM¥5<>v:ZFqj’>…À[¿d,-³Ÿ8;){2¾²&ž€_$ÜßO¡_ãfðï¥ë &ŒuâRô¡ÑkµŸ†F ½½~ý0pðÀnòìrOžLLæ€D“)Ì62¿ÛÂ4øâ—ã.>X„SNy,‹}±T¨^¿$žv©Â®[¤ÖZô7‰ ¤âUÔU‰øVØÝ'︧G}̶†ÿQaÙàÒ€¬ÛR4ÍÕÔ(um¿FYæüÒJæ%ûÆès e¡7³ÐßLndà–Ÿ2Gû· ûÿ‡&uc™4‘ÿ¹þc•{…U ŒO{N4×úGÒä•ݵû”Õ>[´±ñŠaÒšÃÇ¿ŸG[ pWŠ’F Y™w­FAo9›ã8—13 Y_ð±3`<ÏàLìgwO '#‹ŽK›&ºf8êóÜYY@{RW>ñoqê4<½‹EV×CÀÌ?ðÃîÈôp©/{Ew5±¼©>À¯ŠUlêÁg:”&zU`¸>/IÁð›ûú¬/³Ý¿85IVÃIrž©mìÖå˜q³†l¡)&¹q>Õ§âçp›Š^óÍ)½²;•ö]lSr­Î©„w.´x\øG]#“ø7èÚ‰Þu&Tg¤]*Û¨Y/t„.Ÿ³Œ`WSÃE §ÝäÊ©x)…:Э⽒?õÕc±îCø E:Ag°€Þ¶¬nš«•"N?ö™Ü×®ö=ÔŠÕ¸¬ 1€¹탊$½l£!=n1̘X]gÞÅ!:ëÃ@㌫’€€™š˜RíI]• -Ê€ ò‘½!ýÞyo"¼ÔÉw—‚÷–]˜Ô‘(„„ÌÚŠ'ݾ¥Â•ì¼ H¡*O»|ꯜɹ"&ì`žßÛš=è»êCÒߎõ:'D™äãÊ ÒšzÁX¨Bkë9ÚU­VÜE Å÷VdpNœ Žy$Ë%b*¾^h!<7l˜]Øj"‰Þ¿‰g¦#Bvþb`\‚È•þнÏ$Ï‘ìmz½líõˆùç¶/ÃÞ.økÝõ9_NF³R"Τö6'›½¾"ÌKÆr¤x32†IõáwpF͉¹à$îÖ·ÕžX£ûƒ4•fUÜOÉ]Èß< ”üdÖû£i»”‘1'C³'šK=bMÉÆ¸WÑZ(ÛÕÙkšHÚibóÀAÁ{[†Ýœ´€u·Ô–‘efù¿·Ôɶü£ƒÂ¨G4c­é3»¨Y’rN>Lº£u,"¶êA;jP~v‚ø{EóPÏ}‚8îǫح± Õì Óos'[)d8í‚‘ø[îAZäÉýæëš¦'Ð&i‰\ pß|²Ähã—-·ÎçîÍþТڡ{|ô»iôÎs{«„àŠKh ­páV‘•èÖ­$þv¤&¼úrŒ¸;Öƒ[ß]6Ixˆ‚Ïß´õ‰b<ËMµO’ …½‡}ÆàaÓÀõ®Sr ¶«?–6’kÑ@ñT×úá™Â‘Rnßæ¢ˆCá C/m£)ÐZ!YXäʈƒ÷„ƒì`• S'þ¥ý5À†C6Ù™±“çS-|ùßv»èôª·"‘Ÿ¸#?æHXîóoÄʘ¢ÈV©³˜r·„§/*²ÒííŹDÏP>T›'Ü;ëˆÝz:­åç Vr[: ËjçŒ\§€¿m…ÆMg~×Z ™PvQu£+ù­`Q-CnÛ³”ìŒéíb¶ÓŠÀô¨ÂëLQb‚²B@ºü*çúñIjqtxØC†j­×æÖ½Ã/Ltºÿ¢HTÝÏŸ0Ðy´uO«0wñ$KŸŒ _¢'Yz¢½£¿)û_<£&â8;Gëp¸È§ý×8› WBÍ›`3‰ÃF¬tMôºGTØ :>´Ë2ݨB«Ý‰/ÿÿ”§Z™Ú'â’solÕ‚]º†dÀöñ…>~¬ƒ«’ülN¨‹C’€€ËòiT_€L!“¸<Ï5¯f^Þܶï|£@97*Nl<]nû\Ç%½†¤È–ÐKõ;ŸÞ4óýC}úá:½[šï°l-è“à©6‡bùòpéÿ‘(õn÷v š˜¤í6übHažcÅ,Så çíeaÔ{²dî{Ei‘©ÙÅM7âzqj U{Æ«F¶mE—ôÖÑmw׆Ë~g/KçÏ3YèkÉ7¨Óš{* ‘ÄbÖ†l¤nëz*¼½Z‚¯xïs„n›ÓÝê®lûÕŒº0Ù"9ØŽ´’n¥7~‰*Í@BwHÓtßOç,>bfBáz9²ÀeØtž€Ûxº¶ö'#uVøb•9dxÄx–§÷À„ÕD©‡¬§K(Á†5 wÀ¥g*1f˜ËJ‚Ï´´õzϯââÉ.e“ÊŽš¤Y dÑÐwÇ·'–” `³À)ʶA?b«[ãȸ ú(_ð}Þt¡Ü"P̯¯ô>Õ “äí(’‰zÔžÜF+²æÁ \Ùá—Ç@ô¹Äª¶{gL™eg?ëzéT©téÆJ×·Àò7ß=9ÍA»ê+ðÚ¿š;}†„¦ :dÈæeŸ¹A·¯ y•²¸ÊÐÊiü?£H2LP0k˜Lâw•&'ëxÙH”\0ó*æ;ômJ¨áè-çvê·ï$ ³jõaŒQé¨gÌ€&ìŒNõLÆ¥7ÄþÀ9áú íxi±Ëp&ºµ •Ë»"i+ùá ˜PP`P24qµÁü6õš#5ã×'Êi×ï³pØîÝ:SZ©%ä¨W‚žÜ@‡3²FXÚóÛík÷Ô±v^„Ô}™¯Lb<»ÑÎx»âÒÛtAæp§Æ™ÌҾˤíáú¶PÉ`x¯ÃŒF L¾æs¯lËï_/er½>1R7ý>#yÚ±FK£(îxòS?ºýlˆžj¯§Έ²OdöÖ7‰]³"·Û5ÜgMBq ?€Oôâ_¿eq¹>ì‹o„¡tø¨JÿI¨m!ÆÞçÛ´k‘û}Fu§Vq|QDžˆ Í4Ñ‹JM¼/œM¾iXªKÝÛŸèúÒEšExÞ÷'.ºÀøM´…°I¾£1‡ëÃ/¸5nYÙe_b%ÝèF ò:RÉ©A?”¢É•P¹5£áV%b”R’€€³fH_,î²xت<ä¨ÌŠâ7sÓ ƒ ÎO…r’")§‘~×´Å‘®Ïæ ¬Îr­OI)8+ºŽ"˜l¯"5Bv™¦…QxÎôõqw x^ ïj½®tšT­šuýM,pï⳦;ŸºŒ3 õ\x/‡:ÖSGÝIVì ¥³ø¦§²×.¹ÈïaᬂéNinêÌ¡è|s8Û4f€ö_«ÃÝ3!xv=NŠs:×о¹ðÿT£çhå) ”~²g…¶ØQ3·63A]ÌQÝC@T„¼©j:A²HÄ\pw+Ä|¦#ØË·@6¢MÀâ¡U;¢òìðBàJÖ*g7E¡=m»%‘à-,^h†ò]`b­#›‘yåS7žÞ!0iš%ýì'ï‡&@¶´ÞS½hÂŒ{¥6­·¤&:ž&ªl¡2θkÈ–jǘº¯Ø<ÐKY3ò.:?ò”² U˜(è‹òõ+Œü[mât1{%Ž‚³-ö]˜E3‚s$¬§’ùÖÙÙn˜’ôó'q˜Ã'ØÔÌÊÇ:+â­ ‹ ñ ],z‡>Pñ9(°ä ®fŒ)õÀÖ‹b¨ .>ל›Q}¢#/im±t±nÝÑøÌT§GˆeÖÈp9ÿŸ)†O 4ÊV?²ôL'C1…>ÈXœÅôa_KµáߢÔÊpWÞ]™²’gàÙ‘Ýäy—¸¥Šu÷ÞJægت]¹-e÷˜»‹ Ât‰ÚËíøŽ$…~Ý!—V]7i°¥$X0$9l4×ìºí¼ùµæ•á> ìBXŠ1ÿ“)·'b|ŠLD©jÂ;ê(a²ÏË€QêñcÍ\˜ÄÊÙè›Ñré…ÙÔXîc[áâ#»fü.*3Ý[! ý¹„¢X-‘WMqcaÇ^oáwîR”Ž”s)ÝBwDI¿hl—͛ۜ*DeÆX¸iOÙ«¢’ÝOê±B:®¾^Uò>Ra+íÕOªÅBÆÖê]ëíAæ~+L7æØ½þWuA™Aݸpõ]aŒa$Ÿµ” öØžøÛÂ{#æ§´ÿcÛ_N$Á‚f)˜‡Cì¤,»ötF¿ìóëíUF‹€‡š%Ô¶›¾\ƒ¿vV-fà35øóÞE&Ï—‚ÀòåÖ¸~lµ…ƒP·¢ƒ––pS²8ˆ+¡NÛí󜵒€€©j©Uòâ\[…ëÞ–H“¾¦DÔމÙuèÄ©¦è TëTÏ[¯m®ý£CQkýbŠã¹Û¢CÚ°hóï·jÚ¯kJz¤wÈ7ïБ#þ‰§p2éDi擹ê>ZµÞeH*ÑÕö¤Üƒõm‰„„He°{úÈ—ZéãŽL|9ñKÕ]Ô|´×¥„•<àÓÁHBJôwæ.ÖÛfTˆLƒµßïi IÔê¿ÛIëvû¹1ÓÊ—‹YÝÆN)À…‘„JéC°RÎëô¯ŒUjñÛgØdÎñryYšû»TSþ‹ñSeKÉ<©5/óŠË“¤]þÎ@ý‡ëÌ_¨ÖâIÊ+/èä%ê<{ß(­m t–?;°=ÎŒà$UÈ“øéÚ,Ät‹pc¹g]O¿Í© †!Ê;&^¶:Ïã1î³צ7/ T>B×1=ü¬týpà#ü \¶”? "½i'F…^9º˜‹UíC´Þ´]—µz]מI²ÝßËT‹ñ«Õ×È… µ4 ñÐK.UÁpа‡b,["K77tB3ÔÅÜ¢‚ÁÃÙñþªq,+ãþæŒîuýve_Éä A‹×¬%&$óxߥhð"õÒ-ï³²RvÇì_B±LÎÅßçjÌ…†ê¡8‡#Ï!Ã’€€¿»æ«ÿn;ðe4 Ê^‘€œ¹8€ÓqÈ{p¾¾Ó-¨«óóŠÁÙ§yºú?W¥ÔFð þç1 d@ü„Âþ׿W¢JÖ:Tc°Ä¸4æÌì ¯4Z&¢¦²üp¬4@¬K߆g°ãw³EÜûïÃIÀjʽKÆ«¦Ì(þ‰ئKL’ L'qa­zrÈXªœª@OÌ5­ý¢»›§äé•ÕîŸØ´$°îò̳ù4)fç­¹ÌáÌ‘R^|°I—â¬Õ¿9 5O‘¶ÈªÞGŸèÁ Ô´ªp‘SŒ‹šõDQ¼TW¨ÆS…²Š9‹ñ‹²„^ Ñ¿;¯ k´TfÊe;¦–ö¯J—0â«ú˜¢ø©KrÑãØc·¤ï@ɤ<'ª˜)ÙFaݤ^A;­™ƒl7@º¨Sž›ÃcÙŸð—ˆ8±ÃÂý^ÍEމ‚`Ôì?õáÔúlÚB’Õ0¤j ïý @ÄcJÊÙF†IA¨4øw§`òÓev¹’iQ)·Oú¬üÅ2z—®l$ÞµK ŸýZþ?ƒÍDz‘8˜ç|оþ,éaU†c"æÿ»Û˜!sÞÿÊ‘‰#œÚÒ÷¾MýÚs K–Èà< ÞvãÙ&©C²¬þ3à€T‹Œ$\´ðEÆ 1}<çá˦y5Y½pe›…q2úé½1|m#B4¯Ì~Ån­*Ï-®q¬\‰b'W¥bL‘¶bA¶â!È”¼ãÓLÎóþ÷eW¬ëÎ..ªî+‹+÷qWëUß´HŒûÇ×FÐG\+mÝ6ç,?tÔ¢ÁêÅ•+‰6„@¿#$O»³°m±ÙaÑÂÈgiG^·ÔÕ–¹÷=„©çK°?&7ôƒ)ñz-í:…‚ؤ®xþãµ;)º…ð—c6=0ú±a¨¹²~L¿«aûM®åF½XâY¿FW×òO»™+f5È Ö«æ^E<ðGÂKÁõÐͱ´gg“]ži‰çâoQáñåÆoÛ»NÃËïY-Âù†Æ/ÈŠ>ƒ´vnƒ•ö‚9|n ”¤ªê‘x؈$$0™AÏð57iy±³'Ö_õÒüi»T¯Üo<ȼwOÑõªŒ#Q fž¨Wx0’©þcz/e_áûûkkÆ£.ogÿgÌT’€€°÷ÈoŒ _]E1f’ñû"OèÏ4,%’ƒAZȨãwLÐ Ÿ†^qO_¬Ïæ£J˜u%Ï«­® ’sú(¤!{ùœÙU4\#Ãú¢>ëÝLeüA8‹Õ¤t’ÅØƒ"ñoU èþ\CÁIä¹§N˜’ÎZE>ðN§¶ò=Ô׿c$0š›C¥!/ð»¾Dg©óƒ ‡e{É3ù-∃רú"qœuã@-RdŽÎ8 ?s`Ž ¢ÊŸâ¯ù—ÂlVmÕ,pópæé“–-—Çš¬É‘ð!{ªRÌ€ö"@zر?B£-^lŽwE#J‰,[æë…)y¶øK @|1Ó“ÕÙ"!¿Ï*=h5öçœh—OÒ´â¥Ze—MEù&>”Q‡ù±ß< þr/WüÖV­•§}Á¾x•NUºK½txVš{-EµH•îPß ÖK/P/Ãà ]*g~!Ò cû0_B 8K<Úøõ„`^ê•^U±§—YQï=M©ú¡ö÷¾—@¹~:øoª&̧ܪqf­¡Ò€.‡u§µ³ˆ©:…“ŽW}¯Y|ë?5уaø pŠK_âThcS½âºo^ZA,{-àÒ ËöÈçXn†2n8ú¤Ë‚ô,*ŸýáÉkÙ³ž·”&Ë»w:u–5 cçù³ìÈKt‘KTžä:z;¸hEc¦¸„ý›“£Ë"“ü:ä˜Ú©ˆ3WƒN5ËZð†íú ÄêVöŸ=Žê—ë&ñBBªËw&eyã3mLÞüB`õ(YmVøÚ7ß1‰á箳[Ï_(Ö7¥‘r±ßYJG>ºÁ¨¾¯­@ M³±±Q5»È,xÉéÃÿ ß¿þs¯HͲ£Öq´›0_Æ¿ƒø;Ššn‚笽±`ÒtùJÕæ¬q•ÕÖmgÌ1‡“‡3TááÛ}噲POâzm;À_ð4Wàbß{){UFÀÆK‹*ñ=õÐ}-E¼¤{÷ÝFY›|RAL9Ä„ò¾wÀ’aóIEôÉjOO‚Þg‡‚‰ù²Y«h;3Ÿb`¸Q¬ƪÎt«0!òßÐtGª¹c kóSi>ãÔü™È£ÞÞ ®³LÔn?™ææ6á?k«)¢Ö×’€€ñœ®+jyôÓE,¾4é!élî‘Æ]žo'7ª·4D ˜qït­ª½bZÀéëï+­€³‚9xÓat–ŸÚ8¤Ì)ÊŽ—¶:ï­•L@s¸}Æq‹Ó‘z'ÉžJõ7îqšá Ò¸"ï¼GBPmZ v4œÄ¼&Þ€Z½ÁZZª,"‡…”{s“½§amD‘ŒÔ§²Ð¬øòéÔÑXkèœy>T@›,2Ó`µJº³‹e»k_|_ô§Ü ÙgÌjËÐçÓýxêUïrÊèç÷ º¨Š.ú1²L¢ì»´ìSš·£Éê­Fâ†ËÕmÿ‚¹˜&ÁG·j9©RJã‹"LøÔ .’›ªòÜŒCKÙ¬zâ'8z$$xÈA,Ò)´•,8î§¹ÅÙ|Ý“•úymÄ€é¿×ë±ÐÁ\sPí»!:=ˆ&iêfwèµXŠqkb;“ÓZ±oYÑØÕonÿ¼Á³Äwä–2 ùWË] *¤eå`P±cêÕ‚=(ûøîgPB§oÏLuî\Q‰»©/=î%¿á8„Òo‘µq\Õ× (•³&XUapVõYðZÄ›À7¿„óíJ×RX@KG À« Á5!ć_6œn4´d ³¦¨2ÛÍcg„D»´<4éšüÉEú>g§zsØÉ£r¡ù]¢<á8/G}³Wn«Ù%{ºq?¹õ”§ô1˜¸oŸ0}/¶¬¸Ø«–äÝ^ýzC*¬Ó:›«švRö»ŠÝÞž: ¶/“e‰¢2 ¥Äb¹ž­˜_¶x-‘À vqCù&]øbc;YÖYŸ÷+r? ÄTÝ÷‰Ôîér±‚Ö£e¶®P,Qž‡ÚÞ•>Ù²¤º3_Äð¿D0ì»\˜ÑÓ]¬Gwû¬+¾íRçâú‰ƒ &Ãô½ÿ]#—¢ h¡ˆ Øf¼zf ,ZzŽX¤Hj,x¨XÈ ïÎì°‹õ01Ý~•w¿Ç…2ÊX¤Çĉ³žàDT•=jU>aZ¶¿ïµZOh0 Rv~ÈzŒ÷K%@T'<Îü†%ñó¨w‡Ý’²:>Ê5šÕï‚èKèôFvàHÆ»\\‘²ôÔl}´+j’O|5¤ÅFtÍ–s«'8¾‹%9-öd;º.Ùvþûà’€€ŸÁF'uÿ­Z‹|ý$2;Ìq\gÚûX R2C­m žµÌjamRÂ~Ò0m{©wnv¦´²‹Î‡NÓ!BËcÍ£érîOM©RŒôø®¨[ŠmtÜQœJBÍØëÙÀãÀA?Òtú$òÚXÿŠ¿?†üðÙ!ýýÞ›îê:Õ&‡§MÐýž6Ôõ×Öõ$ëöY|ëÁ4áÒ9§Ry’Ôãgi·ê`ÞC—¦LIÜya¾‹-› O_^SbYD.—÷À×÷ˆ¾¸ý¡¸QºÚŸÐ6}[¥@Ÿº?s‘\üê%|¦&@;Áf³ûFÕП{ oônpì9 °mŸ_# wã¶õ\œdï€ü—å° CTÒ¢;´À¡\î[åŸc¤G¯û˜¨ÇžÕî¿타ŠOlºÛÇû´õŽw]&ïƒ<“ëjLeFrrŸzåÛr-¾-YH¯zîíi{áWÎ}ÃL,üËBê9ÃuEÄ“ m¯ßGÂWžq+º³°DÓÆ¯cƒ5ü '¬ªÁü¤v;^W ö’˜´íÓ\ót~9§½å]fÆ Œ¾¸ïZ<ïÿkã¹l.«,t1] Š?xDlcímP':åOp,ag¯N˜vT¦^UçòS –:Æky¤5ŠkN…·ÇE>P¾–ŒOeqý(Å©pÑ‘(ïðK;Ÿ‰B>;Mw”‚·y7z •ãâ\Øêkã4ðuÈÏ$ð±´|XSzµÞ ‰“ÆG2ƒ.4£¸ñ‚uÔ£jìùPòÀû÷/8Æ&ÃPÁ+ØŽ(J¶âŠÔ:4ïi¶®XÈÆçhü@’™["’€€§Æ=ßñ N5 #¦¸àõ)`NA«!pk:Û·˜v¨ºW“••>£Vˆ>WÙ!Aq¢A <ïßüÄ­zÆÁÖu´éAÀšÐ^åœØ¹ë7ÄLª3™?±#ûÆ?ÃáRçͽ°±e¯´#¬KÄÎ?›¹|ÿ|ÖýRˆAª*ŠŒƘI¬}5,(GH]}.²Jx@½Âi×|bg¯M密Û;ËM‡Ê‰[µÂ¼¯>惢q .U¥îMÞðÄ%«©?þ‹nÐHÍ™ä#i[ê*}r™_šYò ΞI ÷àft®‘œ…+Øà Ĭ¶a±5eNB‰‹éD¼A>{|¯¨½sõ'e¾"]âS`/¹ ÛfÂJÔ-cÓ;" 4ÙÒ±ãÇ|p‹ªMú·¬I¾ì–`DHäÒ7˜@ÉËwH*é4}ÐQï3Ô_½ÆäSdUvÉ뾟¤”³$ºÂ:P%©}ÉŒ³Ë+5g5`òßU¸~|«ÅÙ‚ÑJ]œêX¦¾’ŒžÐ;FÖÄÞO2Bz¢úÎz13±¥j9³3ÿåúæÌ)²b2Gç¿EðÖ&›^¢Ò½$r}£ù< ô¤I^sý~ð¼ áßpCDé%qíáNgqcœh0ôn&úˆDÀˆÕµÓ’艦  Ì/÷oR’¯FDoÄRI<룦:ÍÌåÆÍυͺʆªtKòyúÁ} mÜñþSÍÉÅ̽Êë®}ë¶µÈ*’-‰õåpBD2Kßý‰?² §ó–ŠêÔv%?Ðȸ¥ÂZ¢üf0ª˜tžKz@mµËç°Ce‰e´J>ÕצÏÅÿŸÆyhÝúUÂMîeHuÖS™!"x,î5ðD›~öW'·þ!³† Ïú-·äÉUÄØa3.ϲC=4²ú˜–¼ŽÁœqÄ¡ÎêHºY‚æI#Æ“ÿÔØæ-ÚªlKz ¾…Ù~È¥oPIÌwB²,.=¤•»3zø1Œ†ˆ|ÚõÓ±}'YðoQœPÿl³a<¹„ápa÷™6ZëÇåªñ©¦x8¨ªÂ‚OÊ(eƒ‹‘èÇ|±ùíN|.ywÏ*åÛÒ¸Õ+éXÊTøÛ˜­›ñÛ^¿ ¨©H±Iž“&]¬I·!ë®§¡’€€¡ ÕØCZ†„¾³,ÝàÊx^³¶^”éfÏà­¤nú†Q½[…n»ThÄV®ÿ©ºûÝWÚée°á–­ÕaN¼Os“F¸å—¬÷­ÛŽòÒâÁh0³í‹‡-{Déæ‚dæïK‡àPø±„{›zºúÏ‹HFx@ÔLáyëu¸¾Z—¢°X÷³°Â=O ý®[|Çÿ*³sLª™üœD¸o9Éć…ÕB[i3‚9KÜ„ñ½Ç”Π—’´ð‚íЊ![ìú³÷¿=ºÖ/éë= z\Gâ‚}yâà9вHR Û/Šå Õ[;:ðÎêJVÐóÏÀíâéFÃê45#/ïÍr¿ëraIÀNï¼Ä4›cß Ÿ~ÜÆcy©ÃR†Ø¾<|ÑÚ >(Oó±Úãÿ\ yxʸ¾HüÁH:gØÂÞìC¿´gy‹7”E6úê-(îöGC³sL*Wº`ü6ñ%Ê,ßñ-ëšÔŠæM¡ìÇåΚ´-ƒî4¤ou(™mCà|”µºÒïY œ@?¾Äcý1äQ'P¤9Š·úo³qõýá§ZLÎ:k•+*–ùܧ.U,¼×÷õ* ° â¬ `Ç ™%qþØîÕ“¹Úßð‹€™=Ø´ö  NŠKÞ©L8ðÁZ@áÊÇG½ëµÍ:o3¾Ì.’=ó/Û’|,t"H .õ[ÁSÄ–[m—ÙøÚs·{?9íi˜õÜi3õuMÇ`ÍåõxÁªÚŠò·">¥H>g*æUMןU *$tàËF˜†›0ì éøºn ®£qH¨Z¤õÞðp@àeØãÒMÈâPÈI.J¶6/—eAØØ¹pbæ±çÑØjÄgûXZO¼¶´wîŒý”šÏgT“Ç µ?)ñÞ›¶¸Õ!ÿµ ]ÈÅ’Ú/}Ò-×DÜÈ”§çŽ_ÉgQ%'âbßhD|°°{³C<«[P¦Ž³{e¹] +§?åsõ}/Zpn r‡*}þŽÚ2<Ù࡬ B(þ¼ÚÅ·«=ùéì…Ò¨­‘:b®ÊÙz(êi±ë€8$èÊÏ"ë¬Æý% ËX ·9Ü×0ÅïÒèÉGËùôÿº¹JËÐm›ÖÝmJ­ˆÐFKtÈhÍÉ'8Dû Zg?-_’€€ÊÝsôÏ`¦~õe r£15•âeÇ.ì›/Ý­‰¢¨¡Ë2YÜ{JÊC±99DW—8N´Ï*GÔZze43Êaîªÿ³pH²A1 ò=‰ÐJ¿æo=};qr ’1Ø"©á1ìämd¬ŽÆç?\Çv‘G4˜ÓD¦7`îÆH”3®JÌÜ\î.„H)!äOHœí”ŽàxydËÕ¬K­b{ZPÏôî[—в'Tçs;\¦n]H»3kjfë~*ÞÒò´–ÈØ¯ŠuÓ°§à€˜­bí=ì#>ÊÚ|=wtÕÚÇËBêí±ÐSÙ!p]'¾É…>ð&ßv´R¤@ciE¼˜•Òòü!§«êҪпå}ÌÚdÕƒì8ÄÚ05!8eúêºØÉåªá"á?.Ðê[µ\üèáå„UZ‚Z$8úvŒ6,8QÖ.u}øTêÓ֪ɑªç&s¬x\ …øÿÂr¿Åµu›\Ôcö$iÓ˜ã'.XšîCWZ=¨Gx›ŸB™¦þ€úÁ¼ã«qDÀ‚aCï„+áÛ,]ø pq%ÿÄ¥^é«D—þNË©´å¥Bã~ëº~½lj­×5iwÆIŒÑAÎL ]ý ŽðÈüdU^|9o§ód$–Cï,_›)whDãýè#¬_iæ°<§"ñćSê‡Øv†‘Õ?Aõ~*maªÁ)÷¦)5F”|Hlþ§ýya! ŽLÁ±ÓŒ®©˜CâÏ5æ¬ÿ3ê@Z„Ip+ªº®9ܯ]mjw€1(Hæ ·Š&ù5Ѓ¥üç±³þœ  ä®RÍV¯}éYú¬:=Åá2D'±#üsÔékí5¹Ó½7èrT ‡Ø%“ƒÇ–Nˆƒe‹áO½%ñ}¾Z^Qd–î¥0|ñ>!Þzö¬ézE%çˆ9L…=7}ÉÍL\Þiê+œ I“”<ü]#ô^`ЉNÉ/·ÒSë‡P{˜xO~?rƒìÁ©å³Pµi u}u2)ú¨ýKª¸,͉E ò®¤ ³ª^©6Š~Ky®;Ú3W®}jí©%>Ê¢ÞRÁP2ĽDýµÅc)Ð0;òÇùg\°<„w†à».¼vVS‘A—9}å>ü‚’¿Í^|s£<3ëþä1¾~‡Ú_§­³þÅfäï@/2’€€ñõTŠá–´¯Rœ¶@ç¼ÝÿÌEKkØ#25dݵâ;â„Ë0:c ™Ö›G|}´èow/p‰CS €…'sà¤2´R zÝqöw»‚6ú,“ïžé8Q…2J»üüâ„£#?¤óA/F€ïuóŠ0886–²á鹑ùNG‘aƒýØÕ)g±’I—sà§„cÄP_àÖà*_oM3a´F6 …Zán²Ù‡Uäšn1ö”¦Ÿu¤ªY莟ŬÜ99zO'@ÝävûßÇš‰;¦ûýtcõ9`‹–¹ãË©¥Š€h‘FÑ*ÙÓ8\IÞoy "ê)Ç Ö§+ldÑ֌Љ²^Bž¥°Ü æK©X†òx,â¾¾èÏܶe»Ê“I}@MWÝíØ$Ÿ~Ž D•ˆ'ˆVÔx4{€Ñl ¤¨èbÍZYf¾N\×ýôMÁ©söú*7hšÿ‹Ö5ºš™ÑyX=—…Ë·vQ;a}/ì{mŠ"~S~|·fˆ#Ý i>·].ïÔÀ=ÚW¡ãŒPB•=`­|ü\Ó‰d«°Á¼’ôìÊB¤b·à  TòÉÄɤº¡f¢wó5üí =²ÔíÍ«v†ûµ‚Èþñ>e7f/rÇ Ÿ›V*p×ÁÌ…“YÃP$<®‘{æŠÿŸ— 3Àö6‰D˜3Ã,ŠañŸ2ÆiÐóxÍÜùƵճ•°¢Ãõr1¿5JÄ)L\z5ž‰ý„–½ ‚d£k^)ist£ãÅJ͉N”É ±D¾U• ÎåÏþq]Ù”Ïx™ædâoµvßþÕ‘jÇ-Ö½a‚ý”ëoFJRØ}Ô騆pÉ-{ú™"Cð”¬K„[{1’ŽÊøC‚R‚AÁÁåJºɨ+y^½ÛÐTC ÎTDTò—29Í´€ó6»$+ÏrtƒlÉFBaÒ1Ë obðl¯˜Œ¹Û8‡+ýâ&®nscŽí¼5^sM—Â\( rOâõ 5A1>Xõy 'ʉ9Ý`n ”Àû ½6‰©­¡›ÁxÍ’€€îéwêpî;†û24½ô'¥Ö§å$jYÕ€O˜¬b-¾ê× p9?×µÓ}wRÞÈ缸gçFuì_F!p‘ÓÎLˆñk¡ !?qæšr©ç@–›ýÑH‰Äu t6cèåv1…QžÅé)G´ÒB Ó3T¨§æ§Ú æz°‹–蘡†,²•¯>U¾)—Û¿•¿î#ý\†'ã¿>dÜ}8ÒIn¢JÔÎÅYfèh};V•®„¡B`Ç{0vR €z>GŽN¤M}‘¼ú³ŠŠ÷غç‡ÿøüh³bß­‹¹/Yq—s.oª+ËÍ÷ IÞ²f£3ï)ó<ãØV%¿%éQ·Ê³æÛi÷¡ÓMƒ²IÖ}ß…:à>uã2ÒÛÚË ¦_=\«÷oÚÇVX=oæy÷–¶h¬Ô¼Œ ÄEn꤀Qð§â©_‰ç$êUnƒ¯º0_¶þ¾ì¯²m5ìýõâàêú¼¤ä½k»:I¨ÃvaKÜ·w`ñ•=üdb7ÉÑu¿<%šÿcð»êäçì+ú²K"ƲÉÑ!€%7|Ax IYävzbZp‚‚S\éG©Ì|=â6ã.0`3ÿ»ÅîÃ] :­ ™/éÔ-›f#òH'G‘Æ1ä«Ó­ŒîËõlMA' z—' úÓ£6¹ù/ʵ ¿¥œ6e43ŠÃ¬8ò ññXOY] Ï Áe ~RM2C"石ó ¥A ¡ÿ ØÔ„›Ä9!—:<#¼“ îçõÆïf¹½*~u]ÿB+0^Î/0qm]ʆ{`í®YËÑ Œ«¥Ç+FRRĸ\&µ}¢`zviõrmJŒ>|)ø+¨ÑEïO5×+„Ì–q“˜öÜ}ìä:Ñ<ö'pZ \€¾ý÷(M6·»E|ñ»ñIþÂÄWt£N`žÛ·3™bÏ@Ëòª‘sõ:OØ c{æøSuM¨xãåƒ}’•5öC~·ùï‘Iñs äÔãÆ~Cp“Ãg‚ì>Õ( aLòs·.j£e”ÐFÍ gËæWÊ»@él¶@ ô#ˆ#^¹Òz®-1xÄNÌ Y3ò|î—7X|¿Ep9´rgü`V𥷦þ=-¢Kħ?¸}›»5,~‹ý)º(òg¯v¥%øú ÌqSä\bu‘’€€Ù{;ç\ÑáÉÔ @ ©³×Ü/k…ÕŒ\­ˆ×➣’ÖüG©bj¤øñ0lò ¹[ÝJ'ò#vÁ|ûiÔ_ÑÊ8-,ÛÕB±:}â pèé (s¶¬+O,z˜Ì©/˜ ÛRYꌫ6D×3ÈjÁ:8¿¢»º_é;·ô×ks 0'-¹Èm .ðì©-8% ClÛéF¢µí(ºñý#²²¨Þ)àjÐ LEXb®ög­æQ`eì¸Á))›ú•4ß`Å%€zK²–BŽ•T4Y¬ÿ͘åü{*âº>¹1þî›1íá.ç´÷Õþöý0½"1¯ø:ËÈ!À¿i[Žv-äj=ªDáÃD±ÈÌC‡KwšÊBºû+a.мóåúbzÀPûéÍbÂj³ÜÙèVê/+Ëüœéîc¼œ´5íC®‰åoµ³‘Ä^M¨ ›ô¶Y§z%*ªœ†u…$gì5\ 6­ÌÛÒýÛèç±#(úBoýi)š'Tìöºò§Eô Žˆ®\pyµ`ØqÞÏIwÚ^œ`ue*å]üNðå6P°½iŸMÛ-™5âÄCN• :ö°EÒc'–9'yýú£¼BÊ<׿s³—3‡PˆÝŠÆ˜&n!‘/ÐdÁâ\¦Ü¤+›A5ø\ö_}¿ŠÉ]êŠý©ïpï‡~ílèu\ÆM¨ÒÞ«˜™¬¶^1‰7ª@¼`•Ò‚gœ÷Tóf˜A¼#jhµ*¤.ÚjÖ ¯K´¶Ž"ðØðg+¦`º|O¶=VøwÃe È|æo(©%aœDB(½Wª]ÎÞî£ÒŠ ù'tZÙà±Á V9è…†9·ÓFèÒoboÅKPækw˜›ås)E@ÐCæï³ÉnêRÀµ ðcZ¡åGÙIxì\Êóqë‹ÀôŽo›´CÏÖðöûjG å×—†4t$[ï?yíBP"F뾿Cÿ§Õ!M3L­ôO†jêêÑÖp˜YFBâîº>N·•«ãÈØP÷€­†Ûbs™9IÓ{?fPÉ”9ÛO«¿nŠ#°Zc;U‹‘bœ %Sž×øÅv¢‚ÿ÷I}¨X˜öi‚çUÍuñUÅÒ¥¨C:«e¬Àb‡ŒoѧãöKíh«wœÞÿa Œ¸Ü–:ÈŽ¯Ãy³iø*ê“…t’€€ÙMî½Ümr¯ 'pb>²±G¼ZÚI<û³× ãjÀS²”,‘aÛp_ â¼!5"·*ý4æz  Z¼µþy Ö~÷E`z“†oŽÛ3ÓÍD÷tLiùdg6šïÒ8W °)è mïöÍňԕcI æ¿OŸâìÑ.Ìúã¡[OHÖ¯q‚¤†Œýìø×&€¢KEÁa­¹o}iÅKj’Äîz¿Î±:_X`¾g˜ŸôÆ¡TÚLo|›¡ÉAÔ+’ï«#'§qÿԞł“Oç¨D_¹ÊÉb×,aú^9’€Vq­1âP–tdbÇÔ6¸}˜È®ƒà1Ë,&Yä8öŽÏû;ŠÞÁ¥ô×òO o(kœÄâ%aN Q[­èDÆ¿¸ÒÝä+±Þ­VEt]¤‡](;† §)Ûdâ]í­§¹Øÿz™W5b_q‰ ·)]°íOÈlug7Ða‰5u“WŽH/ŒÚEù躦šÄà¬ã¹-‡"ÛÅm£“¯àæ8—Û,Ä`¥ÁèÝéüÔíɤ²‚.'…HãB)·ˆ¼ã€UÉÕVÜÛpŠ˜Yu’CVUÅN¿kµ;1þÖqž?CZÈŽx­%Zã›o‘ÁpÍ¥3Žܲ‚?Þê4'`QN%kn'Ð'äÉN”¬R½G}MÊÁñ:<›áÇús5“ТvQ ¨Ö>V%dLèsO’P–!vJ¿åó²$e× a~ñ²T‰k_©Xô4> ‹©„C}3^H:̶”•ìC¡eP$â-{íöÐ SÅp(X¶»ÚEUOŸ½t´ßÒ¢³£,ãÕëè|Z*‹æ½HÅÖÜ­ÆpÉ·s_ª?è;’Ç]:+«ŒZ®Ì£¿åŒQ˜mk0h@¸ 4.Ù¤ÙÏëð?åÛšÙ¢6Õlë³ÅL£¶‘·&î5‰ž-daÑö*î¦ÌÏü×g‘DìÑV‚З˭%{·òZ%ýì”T™pŸBó}SçÎaÕ3Ö©=ÁyÉŒŽTiߎlf•ð¿Òlõ¸@$)»ß\/êøÛÝ"€Ûrweüšâ=“¹ ã—פaÄLd¿²z1vrÏúT³X9°<–Vƒr€#±b\ü›D?›cÿˆé2™ àì]vA}… ®ïwK?œ+â^ª¨©«4JCÝ’€€¼²Vd)˜¼‹x‰£Ñ)«p±«çD쇊ça}*Ò+{¯šGóõtÑ?럸kþyã‹.¾Šy5¾‘à 1vU0$sÔ³y'XAÞQÉ›Ä^i~ã}ÿ w]ú¸© P9zTOî;XZI¦ŠÔ<'8އÉtšÜfg‹iê÷ûz dUëòÖ U²²…¦Ã“îÂh–›b\g;ºT2Œ7RññÛ–ÑEÇ"‘ðÃx,j΃!iš#A5Ä«àä²ê/~pâÍ“!v5õoQÐk¶Tp$¡Ò¶3m™Ø.&Ólä&_ËqM`µ ó3Kr|hÉ—^o>]j¾üÚ±}- a0CKbõ1Ëye©P¼-‚ ¸ºÙŽbÛà“VrbpѺel›¶Q+s3;'ÎÂhrÕ¸>‰Û6àÏQ,më~v‚3]ñB|Wíù.æåÇá­ê…§ „fä5v>$JÛþÔ]tJñ¬4RÒ]cë==ö£ ràÄ7}ßÛþð'\ï‰;_€¨µQ?ÉÒ$ïBÀcÈÜ/>¤•¿×W¦€–;;þSu݆î flPÕþ™?sÃĪõ’¼x‡a¦¯®ogçKÒµØÑ»¡Ö ›Ø[2J‘`‰ƒž—„Üò”á@úùšxÍÝTacëþý\Îøï wÂB‰Lˆ[®×Ú­‹öºRÉíQ›TegfWunè€ÿZK1€ÛŠ4}šg’{»mY¢8ž˜G <è˜Þ:ØA+·æü}—õúì#¾ú³S¹ššˆyïv’ÆÓ¬— YI$(ækUM]zäo0v6 Õ_¡¿Ž/¬Â1‹à©ÀÊ®šÇF™¿RAîÂåE)Å'všš‹észg4í–Ÿm/_þXøPæ|É.öˆ(z(ôü¶Ì®ék‰©в½r~¯ø 0nåv™pïÖ– ¤£U\€ïó@±ÿÉöµ\NÚ÷!E䎹$‰—Ã`‡ËÇ9_J—‡cÜÙé?°¥ú›Gg ý5ÄgXκ=g(Þ¦„Ý}*{B„—éOéRTCÀ«¨Íغ@yƒxYå7~†¬Wæ…³a–ª’ê‰m¤¤k¡_âÆ?Îè_'H(žÏü[ÊÎTÏ’€€®§’Y ©qÔˆŠ/[ƒÌâûAt£·!énfîg»_ýiòõSæÂÀü›T‰?Y:AÖ×f¾´É›]çôÆ®§;±'ö2ôáîCC÷†J­ ´'àbÇ…•ßb•R·dVgV §YÔ• 1_ý‹=õÊXü³^ú,µZKÕý9Å&ç}òîh•‰FBÔ–½Ã‰[|©-s+"›å*W·<×#^ÙVé\å4ˆÄîô¾&¤™åìpñÖNY éWɘŸ¸¢ñÕ׃çÇ$Ë`ìd˜P êP˜‚Äâ_¡B7bÏ2¹ò*¾ŸR"Åõº‡ýz~ºlžÝZSÑŠâªRqStƒø%¯Š!yc-xùÞÙÖžü»ÿã߬âD1ZiH¿ŠVXˆ %Œ6Ç#Ý»Ã~j%€y+}•·NÌ bñÈö–Cï4èÚ÷—§< &wR¢äÖKVhÏ™‚c>ÐFŸöÑn'ñîÁþÍJŠ„š—ABs·\/åHŒÿ‚(Pà–Æ“ÛKˆ.ú¼lfIp`ö2øË“Ô›°n‹i¡z3~€Õ½Ü%±Êý¶'ÉŸ¥bQ’,Á¼j)n‘œ‡v1¯þÉwèmlû”ç?Ë”ÑÜÖq;·u;OÏ{â1ù鲄ÈTþÿA{ÇAÓ£2 Y>34éÚÞÛ’_Mßï«›ñˆš´5J(J~€nûp0·LçÙwp„¥U%IËC¡Q¸Ø_ï.é?FCŽXTG—63ƒ>5ʨaØã 4QáÔÂn_jdôJ¢ðm,íÇíÆ1ÿÏüÿá?ªº,ôGaÛïn§ev ·'DÆo`ȶ‰Ì¡M¹©q=¦äHëaR¡žj-„Æ÷®t1¨%ø+õ¸Ç.ú]Ÿ˜y4«º‡|Rà¶Ô^Q½æ@Ì"IMúWü3~B‹ÆŸyÛh}ñ ô”–ý«ÌRt`Q<}©ªðô6%a;£ü`šïÛ-'¯ì$Ó(]IÚh»»½äµìÐY¹§UXÜ%y{°1‰¿]x¢Xº‘¿©¡Fÿ”©ã%K¿XjSêéÅpñ„o©a ¬éjÌK¸¤ ëmžW/»(›:>4x¬!t%æ‘€ÝÔ{¯d-g¨§¼¼ãwÎ#Ð-‰æ“›CL “%ERfç#‹à£ èç£ìÐd°]’€€Ï‹«ø–Âgìudb¢Ø¢n†ùlÑ š>b zކ¡¹¡ "ÛË9vá\VÁ?u/t´ !ºÄ£´¥ÙÃ(½UÅËðC(ÜT¤ˆ è ‚*w/oÇ[†‹ ýÔÈ–çÝDU8\ãww.) 3}o§1J$79F#p¹zí$F[íi§ÍR\#zÍ0µÐ+½yœ„›¿>âQ䥩¯Èš˜kÄâ ÿêÍ+ÅÚüºÏmP޹_Ñx2ÆÊ!WCÁÏDqt’6¸B)ûiYpq·ÀÇ‚‘—h“UÝBå?O«Ø™„àÍü»ÃD£òÔ ’åý¿[=(Þ/ ¶þ±ø¼Á‚ïøÔðÇÍãn'Þ›D¯Þ¬;Ïfµâ¬ñùA^÷>hj¥J[æuií-ߟœŸÅa“&w+R‰×x¢²NŽ“Ñ?B„\k2i#Å]衃p/FLNcwðërP‡ž#^Ù»Ñè2r›ˆš`/#±A-¤‘GÑßÇ€mD²¸H‘Œƒ}¨Ñ´^ 3o5Osen¥¸…+QûÕé0oçEÕÔW!é«! ûm°˜Úš—ƒ$}µ9H‘@óVw®0ùÞ`Ž|× }C÷‡Wkü5ºÐg“¡uâå‘Òü\‡"íI×Ü“¼l›:ƒïìòæ ñÈ“"gœùŠlÄ@D•BV‡©o²­çœ|yÚŒ»!?BÆ”=]íÁI+ j²ÔYR­‹_„±} ¾Ã L”@Ô6:˜ ós‰ [çCz’šÑ?ìüÄЯ%AÁDÓÛÏúÙ²õÛòL6ꊱ(Í—Ôȯ’€€¼äù@ ¿ëØ)ô®ì¤š“j5š†€9.ýß#¦eeF…¸™%1ßöñ6[Vº'jÆvC¬îgʶŽâ:³Ñôe?(4 u„’=* ¶+@7ZB”kX$°¬F¹’ „ Óúßc I¾Ô> žimU¿Ï¥`û€Ž9øÉ+kÑ–bØc×Âá–Ã<­Æl£¼8Ü>ˆ,T£jGÇQa¸]z†çÞÉZîKe yèlL¼ES%Ê„€’/aé¿8¥-e¾ÕébHu"ÇŽ¤,µç&¡-‰1Ò¤lJõºPåñV8)lÜ7áïŠðˆ> ~•.DÂA?eĤÁRž— 7mž¢3ÜT¤îõ=·±dVvMB^çD «tÞ®„²„ƒìåÿè2z5×2¨6Óæ²Ç}ÞìÑï¯p§Ûå|MbøÉŒ–Ìk”Ìy^†s†ìÕªJüµ¨nò‰Jò·ïß;Ëuú¢ƒ5õ]aïTpÛÄàJ˜3o‡“Akæ^TÜÉì‘…Ýë*K[™Îû›ÛX£N‘“¾JnÈ”Ë5 ç}Ò»œ·™öúãgÓKqaà'¡ˆ¡ÜQµ#ÿÜ"QBü*¦VAÃîªãÐDܳnOÀùLµ¥°ôÒõ·«¿3éCã¦C£¯ù,3QíUÒ +ùÌÉÄmO´ì eÝP™åGàýß‹‘úßÚ½¾–û9…´•¨Lõ}@ÆŒ3äYþ”Tt0jñª)çØ#9Zˆ]S©Èð¨¤Ì±+ß×s!J(FX¼S‚ж¾Ù\d}ªÕ£xb>{:{ªùÙ|S혦fJr]a*µ£?'ó‘¡]ÎH 3É­ªò¸­Ð8§ @cÕôMÍr"ÊUHl‚…ÄRÆñ¯‹èªs´ÖvÌå¥YëxI ý|o•óUkĦ°Ž-ÜáŤqÐlŠö×’€€ÈIu;Ìiôix”®zèx9_$ÏM ðNi§ò¥é,LõüZÆ3d0R;è…4i+2M {éòÆs8ø!Û7ÚãÕ0|h5ÂBR\b¦oÈx§æy»D´ÓÞq>]Âfªxô# ÄìKš÷g#©Ðh΂E1_QðHZüyvÓ7ã“È+¬Éf+ „ø»ÎÆáyÏ~(_ “¸/†6§¢& ;üâAðogÿ¬%ŠF«íùi ¥[;Í 6Ý)€ãŽªÄš7ö€Ê}eI¼ %Ì”„ˆ¡^ÿä‹úKÿ`œçË$E¥8õÎ /<èí‹+§Œ y­ç Øqí Zgf.ȬEa–—'fŠ¥Orb º{ãp ŽÍÌ­OûØ%˜f²†ðüd­gKÆ 'zrÏz&C€[EšV3|iÕg¶_•ïß§pPmr ¸„^·×̬4ÁXè0X©–›ŽsHZ!TžWé—Â(ÀÒÇJ5„zèµ€2T£·ÚƒTV!0Ú¡§ïœ†‡†oòEE?Ržhp¶ü½ÜE¤8äå2Ñú?jC[ܾ«÷¸+$0&2@.“œÁ€?‰©Arz±8gã” ¾3)å£ yÆE½>Ðûnçg°`¬ŠtŽJGö¾¨DbÐÕ »y7/–•KË×0¶Kñ¾ y˜Ñ ÍTqvëwÖOP8{u9Q$ÇŸ<¥=EʹäLB$(w~Aºÿ¤Å:”þ14$'$¢èaÁºÃnžº Qšø¤Þ$·ÕÀô"ý¯ñá­xo)ÓmežYÐÒ©r6Âηr’:i¸·=7Ä,îÙMnZ w}šÏ ù%»×6yd1x^úµ´¼ÇTà"Š>$5¬ö‘(wAÃÔ¸nž\î° ²: eXc1°:zêÕ7!"QH)†Æ¨$ó<Çþ•uÇ;]ÀXÄëÀýÈvž ä æC4wã _þÏLÒ¨SY¿qI5´èÆ Œi{ Õ¸pê=ô-taKX[V†ßL:ÐˆÎæ÷ð0$¡O/Ëj¤¼&®EÔöJ¦ã^Hp­Eþr’¬Ê¶×3jMÊc™Ç»³á7×§¤ æ±ÇM]Ölýª4¤F¦’€€ÇKƒ|.ù,:qU'YÛÒ“Às Û²ª|ì/¤ÛÒÿý>¬õ¡3P¡+÷ªÑEé2=A~¨øºÈa$íóÞœ˜A¥Vq¢ çT2–OÖ0麌Êä$Ûù§¯Ø “H"§Ÿ“ÁLJbT›,vW8x0Ðãy 3ˆÐ…õÒËÞPN!e+fDzfJÇwTT†â €š€U2$Û+Ë.!Åûç^´‰œgo¥`jÿ­ ½u­×®æïÿò m¸¼ ¹q¢/z½‰%KПÒú‚{”^¯} .èë¿E^@ c•Þ?pÙ‘ =ãÞhÕo°±o«0„ Aà°ºÄK/¯ãyBˆ¡TŸC—¶ ZU³UB·8= ÆØaz°ë¤nÚ²þ0ǹhãPÛ~@r(uQ=ñh5QQ‹¥3,HÃ@© „ V} 2㢾´™*ç§s"ñd‡r5!®ƒ]ä£ÁޏSJy˜ªkì“d VZË ¦pÍa«þ9Êÿxã’€€· ã¬] ‘C v³.ËÉduæ²6‚"T2Ì‹Ç64zx¤4º …“-ƒ÷Œ[æýžÆÇi6N›vÒM"øQÁ’k Nͺð+xÙVc‡+Pu=¡ô7 ¼ ³Ñ?möx4ë^Lã`É!ÃÛî@¿lÈQŒèh䣢 ”TÓEÍúÓéì/Ð+22bqyíy,*ô|‚¹(&Rôíkæ VWùt!à'2“yª‡’_Zô®` ­8Šá4’ƒ½÷2IMÒ½–…½cì zè¤ëu•™üÏ"y"{Ó]\2èt,ÍŽûnõ!ñ…ªIÝæè¯Ú.¬ŦþWHºÐ/3qÎ:-<îRˆRžÃ¡Uëe?&»cѪî¸õT3êLÉøytº]݆G)·­ý¡Øö^Ižw %õç~-Ì ¾8Å«‚–Ú;íî¤çRªuÖ'ÜRN¡ßv˜â²0ŠÑçjd}´ÐÏ$}Ç:úÄñ¦°9gõP×v…2™É¡†ëæäÂ_fOŸŠ&CóéÙ•Ž¥Fbw°!A—Ž„ïW!’íÙ K(Ó~‡z?7BpC› iN ½FG:ÁÉR)8Á â2=äí9kh‡—¬Œm8;ësþ½Yó§h8.hû›Øû~ØïÞâ°ëF¡~]TvŽ]õ¤š÷øwv|Aê”RN =è2‚wUÇ÷á« õ Qz>Šë“ˆ›o؟󞛟ƒ Â¤`ä;[G~¸Õ·òV¥(Ξoa~¥œ=¾ Ö꾇*J¿r¤gÊüI)|o[VÅâòDŒ~ÄŠ´³~îg\³£ÌOn´3¾ ‰½”=ªîÃÍClóÈÉnpa²·8똚ëR࢚t˜Ò>Ø‚^ù{ñIå-)5Dƒ³QÅOÅóÈ“]¨gùow€¦ªW`ÚÉ­îr˜\”KB!™3<ÌšžñgEó„Ë›Tix§¡6Öã=$B¿Ñg?ýæŽuy!¤úmh›q/7FŠM+¹+1®ÕÞÁ:Ök'жhdyŽõ‚Zßµºa¿òÎÊq­&eD«½Ùí Œ&>õk¢þÝYòs¥tào“A|ŒìWX Ö¨( OxІHQyS›¶U¹ŽUÔ[³XÉô#iŒxÁ†á‡ÍõÐ 8÷H€¢4lsG¥±®”@ ’€€¹³`g%G—u·›õ‚¶FrÏC$v´vkc4qïØR`ÇC‰gËó“vvt;°Mq¢BFÝH×êwžW] ø=÷ê+ÉËê@ªšŽÂ4ÒùÄILÜxÜ)ɇ/³‘]ÜÑÉ–š«§"ˆ/c³öELLý ·zËÌÒ”ò#iT’…—Èñ׈ߴ1\1¥›Iòƒ6F¤.–åq·3Ä;‰·,òÆCYU]ú°^"»x˓ͣKþšåæ1iÔöwÜ=¤žZH=߯ús† 0U‡Žôv:´®õ\#¨»"ŸV(‡ƒ[­=ºmÍš€Èlܰ¹±”2‡ÄN&íuÜw%’ÉJJ¨Üˆ;­‚œBJ»}iè1qö&Œ4$¤€7¹~‹´ÄòöNØ7×Ä[tFÎ'OÜî윳˜‘-¸Nwã­7Å|c1ð¶®Q!™Azd•ö–"Z”àÏ©Ý3¦õüšÏìU­û¤|¾ÍÀEͱÂQSñe5°~²²zïmÏiãuÃ@-#ÜðqêÔM]§&­CÜè2@Gu¼¤™+0’E“g+o)‚ê/Ô¬°N¬‰õð\'ßͦ+ ¢O›ôÂ5Ýùõ?Ô¦µg$3_Ê˦¤–lÃyc9æ ün-µ€õŠúCíÕUŽ;ÜažßÅLtWUÎ<½—–¡é+ÿõþô’»ØHnÈýµ©OØŠ¨–ÉxPƧÉ" ø&„FG•èGý²"ávM´2™eetc<.S <ÿ€hÇÞÂI_·ÁÚ𒉲9ŒlºTÇXû'ÝÅŽú”fü;õ.û@Y«ŸèU¥ðÔ¨¸D­—NûûšÜP›Ìªœ³J}&“LÓS8YaâõTŸ%ªëˆ3IØ*´yrL+[;;^»oIüa߉@Šš1§¯¿®/1ÒMñKúøÅäâ…Èà–PmQïÛU æ)Ã(f¯é¸©ÏõW'è:bJÖ¹ûfÅ“~›ÎÙÁ»ñÒû J [KFd¶ä]Õ½áëöbJÿ£ÆªÅ¹Ž7f F{™ú<ðkŠŠ~4º–5¾åŒ*JÿƒØž`«¢%¶ ­„FÞyÚK¯+Ñ@ýÂêzìfªÖ-¬ñmF@Þñ®{€ U·% •ƒ‹*®ÙðüÈt¦CB/$¬@òjêêkü‡å×Ï’€€ó'™âÊ"ž±š¥ßɵ W¶S Ì‘?,××-ar„r«©Áp+Cô'JèøG?Ô¼+!1<çÎ’„@6õ–úÅsȱS‘½R6\WVîÄ/ã ±’¨X·©Ž'_¨ ~Þ#¸7ßϱçÌËSYPlÚ+â Ÿ¿¢ªuœ~H5,©é»M }m¡ØáÕA{À¼›Þ}ØàHÜ'á¥\L*ÕQp誡ñÏ–±ÄI˜¡ƒ1²òs»~ V^)Õ3ÎI|[—%&gÁ7AñϤöÕvWtÔCáh––ye}Ó£}²Ö'¡«ð´Ñé›ÑØ™²RD÷OòŸ«°8“NQ:Emð$È«eªÛ6ËsgBä8ZO9 eâ íL™Z*gPËqÓUE>kYX|+óbcÈîϸ6c7ÅÝfmv-"Ÿ$îaN»¸i.:Vñ­É¢\¶AݹOŽÄH)6×a¡w¥]nƒø$ 1¡}øYÒà©sHt¾ëskîFŽ …WææS¾c­Ö–Tn9V"Œ€Ä’äØZ@L×µ~kcŸÈÌÛGòJ_UQa—’åDWNo’°(>`j¬Ðýÿ¸þ¦~³Î2+NSð ƒ…Á›ÙzÂé£o¦C¸]/w1ÜšçdͼòmqýmèŽ+p¡Ð(I—<ä³Òº]ñû¿³¶ž„­U9©ü5²Õæót”¾ä G”°ÄA. ô^&Îß™¶²4fUé~E顯ÅâuüÔúóLCWUÖO€Öð"¼¢2h~àáÊÁá:ñ¼K¦ì*Ž'],v†þÞÖº¦i ^“Çõì# Ýø8£Ž¨"Ðë7ÈÞRâUë56û¦"¿tSÐrO[Z怌rkýÛÓnÖ2Ç3/x.Òžy³e[r.?øîÝ#÷Úƒˆ_u¬Rt:;'Î ÷õ>H+·Bû¡£7¢lp›¼9d8¶?ÙÚj íÝ/7Ãk^p(eQ·'–%SI*¬sCK'ò9€dÒ1Åa Mº´.ÈíÄMš°hÐuªÆw_èÔXòtÇBxì¸ÖêyÙýÆÒr͉õ 53¿í*ͼ¸Ñ—5^ð„À“$>Š{¢  ¥úÃzÙ³r›ø0ªÄæÊævªøü—‘ÈMüt+t’€€¶àwÆ7lâA E¾D1ÒtÍõµ´[ƒc‹¸ÀÑ=ðx©èÎow «õxàzy*E»¨A/ì§|Û¢÷uŸ¿•E«oT¯E`HSB-Í^6уUó"†€ÁzºfLÖ§z†>nC­~2h!²;ïåS´ú¡"v§âh¬ÉÑeé‹F vÇrc¯;EòÚá†83ÜEz\¼[h>i©âuÌÈ:¿Gg¾T÷ÎcNð•k—üªp¸Šµ’Æ€Ãe!dV§fÖ8 ùÌVù'\­:ô=!–ŠÕìݹÅ`Š‹š ÓÌQÍ9¢&¬öOÛdì-ol«ˆ‹ºšw7ÓpÒñ´a 7ü-”ظ›b˜VàÞ¥“ÓÞ‰Šk<ç[<_J¿a½ý>1 )/A}ÛsÃÏYÃŒŽ®­ €îÇÎÆÍ€“6Õ.áí-5‡OÏ÷¯\;™šÿ T|b•fåZ-&šdè˜>›ŸYoV³ÝÝ}áÉå“ì`Aj¢3ð Ûëé!œRF±ã±°DI\˜h[S½°(NÄä#ø¬‹¤äàGL·×…?ûØôm+õ³Ê9Sž7µœµý¬·•;اU°L<"‹g™Ü¡IîX²g›³Ì.±…Ÿ0D³zÁlŠDo¸¿ƒ‚s«¾÷ˆ³ÚÔ/.ଶÑkDç+£âESpíšc“àyXôy7,6š9Á³Ä@ïVí¹8¨s„ñµ¾»j>·,8Ò", ÀG*ºÙbP4%„ýÑoèÿx­ìiùv6ï¡z¤¹KÃažO(¤d`CãêØvµ¡†þ/égó#Øžçü.… å;|%Õ04¸-À¯Ñ”÷‰,Çw69Hó²n=$~ÐÞØ`‚¹ÎKÁ4öËoä@#•‹¸áAZBê9UöŸøÀå¾%.GÛØÅÐh¬†4NÕXbV8 ¹2)|ây7ÊŠ ¢;oÉ[ß“<‰Ös2ά—›×y’€€¿ô;!T#Ö™µ'ï­•a—PŒŸB;· a„§l rÃc#eFýÕÙöWýO¬åTtÓ“VvážÔÙb©šm’ƒ+y15J¿èŽèDŒì‹šÿiŒ‚°ßª£Þ¾“ɤb™kÁ)úIö®ʱa‰£\º±m©ÚÂ_¬P¸­Q®v*gEþœÎiÉ(x‘+%GU¼ÉTã ¥€–tVh˜›ï ˬág=•‰=èóâ2åÞ4Øu¡ÏýüØE^€²JãÍâÛq_ûˆû&‘(JŸ:ÿDC œjœ-W¼¯gû‚[bsG„åQ–Wø¤!TÉ0“.™}DRøÿ<$P dà ²…gÎÇ™¦Œì‹_'÷URA$ÒUl4šƒ¨÷£èƒÕãÓ+N ÊB9š'äãÚ ð›†è¤•¦š¬§;Ï2½Ì*“ݟѱۀ5:»G  »™H‚%ª¹1ZÕGÓýëZŽzA]“V ÑAh®ìø °†ÅF—ªáîëjJµˆûoÒç.^¼cøgYNɸ¨Þú+ÕŽòLûÔNbäWP¶'a{uþõ ÷’ í²5èZ˜.¼ÙæÕaÜN䫚ΈÁ«M`/„^¡Ò]/ˆI‰#âÞXUÁ(9¬3 á5À±°³"Z ò­ðI).\UÚ€‹Ò´ -ñé?§‰Å})ÌáÁ†Éw¢JŸö¸/Ì«‡í9ñ,röC‚Rõí„Zþ¨a ÄKšË—R)v›Â§Ž1 eÔá·7w~–’P ÞÄL¡ô.ð”Õ]¨úUø¦ĺNˆ¬fKíÈ-Tmf¯µRR²mÔWtÒ[ª×+òÐj‰I€ZõD´yËQ„ï› ' IÜêðB5¯1}Qu錘Q±GMj,ûÄub\0·0¼\3U0n Y‹‡àÀrÝàů€±X ºÜXÕÀ¼ ’ÝOUAG$»z„ùdl7©Ìž8ËùÔf‡®áÞˆÞ­Èè„Á xz°¦BoZ÷ÈL D‹”+ óë•É…ßAº•’¾Dú6ɼ‚ªŠg¯ØüéܘD}Š×+Ïì_*cŠ5h…éI :2q¦¹’€€Å=w5ö{ˆÇÆÈ½H§oaó&@]¨CÕ½K¸8ñs¦e…\ú6µU¬nÌ«H¤‚Ý×pÀå“wFðo,hC·Éf#rbõ=æz/ÉÕRî¨ÕÿXè_(TÕ¹uÊÅ2naõ@KX`·«gQÞ&÷sÌD/§vúâkf\ÏŒèHÞ>õ_³8f9”/Wˆ†2*‘Ô^ÆÈtü—m§;Þ!_÷éÞ (uô'j°¹òkçq¾ F2æRþ¯*}2ÓÁ}pC ŸwÁÏó"‹ÃÀnp® ÿÊ~(^·_u±40#}àüˆE :g.ÕÀh°0•«'Ëă™UÊX_Ó$4¬oëü.“:4)Uõ½çR œ^Ìáº\+ êµ9EÛŽÓu®Âuþ²éÀG»¶æÒo¶ñkYé`{åÒ2ò!á€1J$ZO&ðGsNó)~üžhÇß"ë}9ƒ „p·›<2½ùôLS} –NÇU1ª4L/í”ØEõfa°]q¬ª M$¦šr+šf ~žsKg^(y€t’}ó­B@ƒ—ÓÛÑúß6›V2í°ñ†¤”dÝ`õÀ RŸ¦3·5Ïѯ÷½íƒQÞl‘è‰sy 7`¼Â­ËÑDsŽÉó:D*3ÿ ÷zúDBæ‹ÛÜV“¸Ì ýô/騎êr²¸?eK¥µ{ÏæFün—É#¾€N¶Ì ð‡]ö¹.û¿+9Y’ÖÌeB“«p®ÜXúŸfƶc }¤vÌÁžÍH‘Wë†!LgÙ$Gi÷g&X R² xÈôWnçÁæe¤$‚ð$Q€ÆDŠãdþa;A}{1ü‹‹óJ^þ¢BòlyMé|9u p.N›3Ï@³¢v›-%¡“þ”ò)bSÍá>ýS$\÷Ô„wW¼ë—`’”+’Yåb"õäIÝ¥]ÔXÛmÝ€‰'ºû—\jZ ¥È?Ï#¦rÄ€(GIüFÄJêâ—/ÄðK¹+­6²'~…iʰ™·oŠh ÿj™àzבû¤¹Î0rúCDC.½E4ÀLâ.¹¬@ïÈ9Ê(”O$¾*,È%_i´ñôjå‹´ã‹ÅC$Œ÷Y’€€»Ù`I‹þ8;wníR9¼FUZ¹¾‰ÜÔs9‰hð/L¼–<ôr®Î„šêæôjiÐHYáj˜¤A_TpµèÆ¡€î ŠvLœ5pÔæ¦£‘Czv¯$кgUäEßÀ¯‡¨±4G$”nå$øYr€Y«ÙÉ+ÃzÒÌ~Ý—áýülö ðfa´ØF*€Ñ¯.VÞªŠñs+Çwj¾ð¼EKp¿3ù¹ÈáÖK P©}‚༸_åy µ³­ÓÒŒ&ÀAÞñÇïO¥Ø“`¾õl#5˜Ý2ÝŒÈÖ¶Ù¹yz¤S2+»s¡'>æÐfÙ@:ÝŠÁQ ¯†[ÅÇMä7Ž-Ô SöIÅ¿'j¹ã=ZâËØ/íiy¯?ªD-È÷@D:à ˜6Í“§LŒ"οcƓЉû…;QI®Ä²þÁ‘.š. l²2ïT,Æ©0ì̦â=âùRÚ '-F®@›KÕœ× Uå⤀h°e\#-•Œ„ ì6:ÂDÒêi ØÅPøÖÛV"Ðñ“{^¥Œ•®Ë€‘9Mï?¼Q×Ï .9Ð 4÷tF9LQÉ 1n°¾ÑÐÁÀoù|—Øö(}ä5â(V÷Ö½ˆÉy(UÙ¹Ír´VªÛ°0OÅ`5†è²\±–kCÔ­Á½‡äÑÔppŸ+Õ’€€·ë¥ë´$¢†˜½­ßräa™óhF œd/æø8f®7.í¶I€/¼.(Êô–)÷÷Âñl¥ ˜Jn!¡r3B”Ûzšô|èøõ´NR5Q6' 4-ôt€ë½*`N¼TŠÚëüàĦÓü7ç¢è—Åûòï6v'”¿½˜VQØd1§Fó’ Œ{øñ¬µ%Õÿ·ð>}ÇwÜQSÜþ °À³_BQÇéì‹0×–Â>ÚŒNoëjGyª3¶¸”B-8‚¸F1ÒOØé¬Òå%F;¦Ä‡™P›yL©VÜHZ4&ökˆWôW eÄÈȦ=3zñ3:k8Qƒ‰ œQò9 «;³x€Ùãˆp L™9Üä ¶Ga¯E¤!ÿŒ o\0w•YI>wœ Êʪ{CÞ狚‘PÇÁ‚QýOî¼sW„?u5*çˆxl#³àX 7­ä¢ÛÝ~Y[Û‡›åõ}Ss¶ÏÝž•§uTzž‚<¯Þ­°€§øB-œã\}PÑär‹m±ôÏüªÆ&$Ìyô.–ž’i‚ <\°®ý%ìä©5¼R I³lµÀê2.þýy]j@¨©’Hb¹ìDZãö Ö¢ØÕ)‰ƒ ßã(fA,®¶PgáABíÓVÿE9"ä‘J2}À8icÚ¤';‡p3ŠÚ“Ú…·ç1ULüÍ™ÁGlòq"`ùc˜Ç‡ÆgŒ‹M–ýÞôù XÒf¦¢!·Ý{á¹²ëíÚe! €Ù¤½©.dXPëH2b—Jø!fO,Í„I7G4‹Ö…·YcÔ/ŽÝnÄ*‰ˆQÈh2D|Xb2gS‘‡ W5Îéž¼ ~áPÏAH(ÖÏ40†:o/ï0肼OÞ¯Ë÷xƒ½Ú0 sŒdGóŒßPL7”Ô‰,¥•ø‚$>Ïb0âÌ÷‡H÷[Ãmf¼\$0Ó9óç˹™ôˆGàÝEð“„ìSáʺ ˜B¶WÚ-éÙn®ù-¤è6DºTô[sê{`8¾43.3KÈ`Ñ|Æ7m”ôúñyùø#(Ñ~,nˆ‚/Pû×ôÑÒ˜=É"ô4,{ÈDÊX@Ì’ÁŽ7 Š—©öö>S2I¿~ÆßŸ}ã`dâé?¡ ¦ˆÅ®¸®&e™ÞïŠV2ØsN ‚lLø¶¢õvúÙöПî«Û¥ÜàÆp[,Þ£tXê†kN²Ö~ÀC‰ãï’Û¡ôÖ0cy©ò<¯‹±ezѳ%ûkÉA×™TŠJpÌc™Úw'ô°w2³Ó¨XúfNÊI=}™„Xÿx’ã‡î{Ó¯}ÊU, i³É¾ͽKar1}J¼+$@D+ëd@^àÐù¼K3ÔTå5ͳŬÉrèBY˜¬Ð±-wˆÌh~í¼Õ*¬o0ÞÅXŸz–»¬ÖÍ MêÊt×ð‚ ûNOz{¦rTûâ@xwúætþ ¾F@a,¥UÔ’€€·ù™¬h¿ß+€™mCçÎR5®3÷ dŸ‡Ün$ õªqÒ‹ÌÅ#@9Âg÷û#âÀ¤c åk€ªX±[”³é%-鈆¬A8Ÿò•FÑV-ŠM²MùEC³M˜ØOf¿gá™sQæ÷{V°žíÑÚˆ}˜²¶iåÜÑ“ŽG2k¦2Ö@)g*w'.$Îú…CÐ7¥?¨Ì¹ëžŽå¿Ö•²±¢±ÛqÛÙ¨Æ9m1µì' J]¬ ¡Bg›¢åÓ¨¢'#c—c:sP>B Ê/EÁǬ¯£¨‹OtèFuÔL!û<¡c¤(²§‰Æ¶&9 †¨K\€+% Æ—z¡•ídIÍ…°•Ý)ŒVYY?#áÏZqÊ\ÇVl¯iNA¡™YN˜b°¿â¾t|þ cÂ÷*a«öÄ™/šÎmÁÂD*Ié¿` S,’Ýõ2Acé@0ì%²ÛœÐÍ’œ-Â[)Œðiæ#S[_þ™kÈ4½iÍfè=¦Df3çË È`ø1€&⊵dÇSûÕû0LSéÊÀáþo/{Ÿ™…7g¬¥Tì6!ëñcGR‚ö±È7êß’Týó©,q)Õ<>GDè`êOsž ¢G{~ãMž©"G8e£_‰sÿº)M(-XáÒlA Ñ)Í€ôvy‡Aï^÷a¼³òp•E‚+>f1ZüèZ‘Ö]I¾Yî‡éÌhÇôAªT51$ñ&Zã­ý—¨4ëS_úlEëÈ´þÀÿî3¨¸p4ÑBÙAâ@zà‰‘¹uÄRPT)²à4§K¸‡H–ÝÙu)÷Åmù Öë&\Éáîñ[•.I@©ÁÄÁu*¶u”²b†Šû^ïÊ[+QWUxY9â8›Â?m“ÞÒýEßRîé~d”_šá'£³@j# X1`‚¥éžÛ¡°2 ¸‡‘zK?àMÜΔËtÚÔŸä nX-_MÚnÙœð£†Yðqh^Z…­…&ICáÇjÒª&©‚+úò-~] ¦®M,e’€€¿j…ÔrOs1k»àt3í ñåv&VºýðÁ\“މéò8í×èà ð™Ò\ÜížØ¸na„‚=kVð±I†ãÉêûÓ(å-‡¡àÍaL’c’o*rû5Hïöc)ߪ8‡ÀIt¶@öÌl© å²z£bŽ1ò]pëž­Äp~~#ŰºQÉáIå„èà×—r£‰.„CM7òð˜Ð®ÎÌBþ•‚á±=œS]C)xxn†¾ •.’üPPLQ?¢Æ}ä[kŒ¸…%x3‡äÝÑ @vf Y¯¡–d­é >U¦e{|'C~Î3;tù{ær«÷O7œÛ>c†4*'Z·"7.KZÆC„føRr"RäZøjõuOðÒ§Áõâ>ýE¬Ì:>?¸fµÎir˜áÈc4òEó«NÝBÿ¾‚˜ @ íEªÖG{èû|(ƒˆðük鸴¸ã ±'V¯U…F¸j­l¬¿ úÞö°Æx媓 M[~*Q71ucaJ‡ÈÕª-·wª {ïØÆˆÏn>”?k{ÓºVLŽ’¥—Ø 3Îêª Ö"¹KÍHŽr; ‰fó»—h ÙãF½ÝrgJ°HÈ+Õ.Å«Æú²\/~t™£”€ú_åWËqû·qåH6M5‘%° _ Œtõxª€|Ó²„Z«G*áÍ^Ö qï_'ñõE­êtæœáyb7ãäârà UãÝ—M±Cn²S“^ñ‘¯ÏJv¼ûž…>ÝÊaç é~R3kÎ3”Kã²Êkc›K‹ƒCj’€€ä˜:_.jüí´ËÍ­œ9²Ìç—a>V_ß 8-¸ºOãuÅ0u”1U8,ž?TÅž¬^‚U¸>ö,ݰ¸6´’Hh¶¥oFjšêlþœ‡È¤8©HUÀrŸk*åž%qmbjc<|ƒÅ½ˆ]$'¬¢€þvªh§”¦Ý «§ñ‹ÜùíœEBZyX‘s(7Tó';ïf˜a\ÚÒX‘Ò%‹u Ÿ ò´¤b\)ÀXY~öÐ ¡ªP»p$VتëUÓˆ|ð^Ç`úyˆ¯r¤K[$¥ýßÒiä£ Åéûcyðñ%[æš²Î#äj-„ë‹–c¢/bo¡u qRÒ6éáú¿4T¿²Äã±ÕÇ,ƒ@WäocG +½»ÓÛêüvýKÌG§K1B+Ñ©S8Õ ÿ…9{¨†Å;ÜèAÁ[ÌR¦IdóNîHàªÐàn€£Võ£³Æ×PIE«éG‡ÍŸTÓåªR7Lêå07ùð¦”Pˆ $IíÔ1öPv*‘¸ÕÿšýÅZ ù~³@j[¨±¬r­'(\UoÄši#`£·š ¬Èæê£}‰Hçñw=h}¶¦ØócUPŠ*çnc–çb~‚Ÿ98†Ø5­˜nz s§­VQ®ªÆFÊÆJÀ¯æ§ï Bý¢1BþŠ“ü4{ÇB_3<<Àå|°P„fö¢aͳq”PWÜ  =lU%¯7?·äj„ßÚú˜jÔâ81G8,2SA”~–SBe­¯Ã,f:·ÌKDIRÞË'û^ ¨P  ÒØë5ÜŸýuD4ûf¼-=| ªÉgF“OÌûèË“Lä\YýkܺÞëH—)¡Œ›âlW‚û‡¥æ†ŒÐ½›:hÌʪû$¢¤ÿøFâµEï@Ÿ'i}ù=„€ìèOq×Kðpž‚ÂVš+YðÞ_øð, ë‚íÃsªTsœ“§×Ûãþª ýþÈ>òd¯ïõ¾ :PÛ·Þ® ;¶ÔQ‹õ„ð\‰ u¥q‰”Ç(Q IsÁ¬7 ô©î†i¥<γbOѹÁù½ÏS•»ñ߈¦ÉNóòÚ›.‰)‰µaPQ¦7„\1üwYd²(³S’š¶yÉx ê@þÅ<æ^ªrúgÎ’€€Õ1F À¯¸ /lØà9vþ±ÛoEù‰(Ñ¥0ö·”H¼UšÈm~‡¤UL¼¿æ÷GýmNáÀxgªú©â$¿¦ƒbÚÆµ¶Q䬵w@_ñÜÖÃoýè 6ýÐ<èŸví:;]»-ñ—E¥FaCéq"D¨/G}ŽÔ«Çü•¿HÙmÐÌIɔڰßéм]Ós®µèuØçEÒ³ .IÄÄxºöǧég-mËÉImaÜ Mžp²¢ð´k¨„¿½2ëô–ƒ!iŒ“ÓTö€{'6S‚9ö(ÏE­´sxâ<¼âïq=ÍzÞØº$ß ‡˜Ùͪb:_,MHáB½ºB’^Y£ÀC¹q©³Ãu÷ð¶^»ÁšÙärI ©¼¨GGP1m1(M®Ù@õ†ö^øža–—I$¦è’ú¸"ÿ=ëQåüœ0[_Ö+Œ4.X_û;š#ÊÇ ¨ø…;YÙ.aÕx÷HÎn@šb#„X ¶‰ÚÆëQ}ióÅsC'-½û§v›e'P{›¦Ô‡=6¹cñFÏÈ¡^Ä/±´ºÉã(NÓXR¨‰æø¹˜êD¦ûc¶F4f\2‚ˆÚÒ$‹Z74I߆!ƒÉõìÁÝ¡ri—i¢§¸È·K%ñ—4p¹²²VUÿ¡0 ã°û™b1Ë aN4ì8ƒ­!¥ØßÆâÙÃú½\Bán-oß\*°z{ưш’ ÞFÜ ãž %¢ñÂÎUíþÁmN= $¼ßFe˜Ž©Qo,Yº8=–)VçÑÈ4z×Ap_?t£TC|³ä‡€K¸È Ü™aî6ô“oO“Vú~ ÃÖÅ=¾È5„¿&…¹·ü%À½ŒUmì>¤ÀÕ":TRGözøÜëó’J•‘ê"Ù­µÜ«…ÔÌ)ú `¸ E):Ηf …{#A>ã½åø§›ºL$"»#Gtàóì.½)Ê4· ^¥ ‡S´W÷µåä”­m_ûs‹zÞ"®ŸÏˆl›¶JQ¤×a‰x0SF’€€²¿)õÞ¹A£²R}0gV'!*¼&W4r0yäŵ’R´^;£:dØD•oÙ©à'}Iý¤«€ìk©ª!• ‰s_ØœG÷.¶+u/Ï.`N¹‰VÄmÕ$v;ô*V_Kôá ª_xQ·z W×PÙasÀd›Q€c ïÁÚbÒ'»ÙI‡ƒMâÔá3€á‡•(—ƒ ”³iÆåfëîJÛI'q’óz×S²ÌZv]!3Èí¤¹Ì"AÃàϼ`Z6BaSxÍ1[’ïƒdÄDœO€jþúEöcô¯ÝÅÖm n}¹’&²tÀ÷uQµžwEû «EˆU köÅ—iÐÈè×BöŒBhß×(góˆ†ýÛ™>Xë{dÃ{TæU™cì²SN0Nã|4™“|H¡Ê(sÍbdïÆþÀP%ð]¤‚" #õä 5LB¯@ÿ¤Õ½y—lVE2è/uð" •ç-}é¹Lk ŸÃû1 ¦~-ÑBƒž¨ÙxºqÛ,‘8µ «Ðž 6^.8$ -Œ¦Ф~ 1qFe_BB:û,Y/Ìîüot^ú<Ó› q_ÇÓWÀ×xϯÀ«:úÛÉ`“Üa[µ\l³¹t$˜ÂVV±ÌLä¼B£ÄBá"–Þ  ët9Ü×X½ˆÔL©g*€~ŸtÜHPê‚u(=/¶å,ˆ*퇃xgŽç>LâM Ø{^a+JâK±MÍ¢½`õTH¨Ðy b®sÜt}CþšòÄî öֽɥsˆ "þ›Žö–o£5’úƒSÂÚ¸÷Àõ"Ê«?ÿÁÓÜñfã[EÇÂX)} †!öò4ͬ›Ùæ7[ì¢}ܼM½(?sgÒˆræYºRëǵûìoL¥”´ûp”Öî᳑Z\òRÔ*1lëF­J¿ÊIAU`¥Ó®ÏDýø Óp=ƒÒfЧ3 eQ7¶õðÙ<"u±3ˆƒ„ú`ë:Ë î-ïlf©•Á}ƒñΔu÷Õˆ!.éâ¨àCÁM6ÑÓØe©÷ŒKzZ½ëœjçwî[§HßD¯Ù.D‚þáÞrÂO¬ÀÝèâhÁ ²ŸÄ/éòQ¨4J*ÿî/ïDò\ƒ!ÝW ÚY·¹ø$ÄÞí…ˆÜvÛ@”AÞŽ)bŽÿ=œ’€€ãWƒÏZí0avòÝgv’Kq›ý3<dj"„ÀÓdÝž(MR‚€=p.”Ï ¾t‡¦©ùUFiÞhõÖDìÃ$Cü’‚ä9‘%[ÙH®¬#ˆŒw÷¤=Æî'}kªcüYpÀ'Z/ƒ ŒÍN¤ž¹$62¶y]Òl¸Ãâ(zóÒ†/‡à0{ýöƒÀ´ùj~n~ §]emâÃTÒ†H³ùiö˜¢ô4.r2êËe½à‰9=ÿº¶žúLCSÍ÷¬>ÎÖhEÃ/GûH¸ì8á·Hm*d嵘6&0š]ÖûM ]?ÙÁ·ògV‰o»%àøDw Õ§Ô?é)uàÖž—§*¬!;#€0ñ ÃþhÅ$ºäÃv¥ý‰¹^ü£<ÆÅºè-ÿº¶ä¯Œ“Ýb@6±i•ÿàžè6xX:ªcÂPuV¿m†6-)ÅÌ×jŽ¢eÿ…Î lv±–n0%…µ •-Âåd£Þ5dçÌ í-¶O'‰ì.Õ–”æÏÎy†Öç4¬²Ž–¸a„Ôø€S½"È™ïsxPôµç>%røÂcqŸHwžôÿµ°X Æ´¿ÊNÙ;\#Ä”e‘ r­Ý°£eØòè$¼áA§Ä†_ò˜j利–9‹7[RŒ#µ0Ô ÚBž'¼›"ƒàÛŸ¿ùP–~S˜ù܆`œÕ”±H‰o6”cÂO"11tñ‰sh¨ÿ›=t‡=“ò†'ˆû¦Æ ÆddÖãœ!Äi0 ¥* ð¶_¥$rÁe#óXümÌ£¦ÃÀyäyX¬.¸™9õ\n@ôÕå nñsRo×£§X¯,Ú(—É©¡“R'G6ÃòF7~8 é&àÜ<ŠŽ§êù°,m5Ž Z"4?ÒJwCÁ"R©‚häañÀZ5LµMúfú¢9¤¶†Æ='÷NVð_À€ c°UÔ+H‘ dl_EEZÎxAÂlÄk|–Å^ì¶·Å@„%j@¾ýj‚õbÌUó6eýS›B/ÝlzLUo½è’LQRÉ%8-ý‘hÿûºƒá@PJHê¢ù‡ip׈Íþ"ó+st®+1(~:‹ª¡ýTyœáW¸šÇÚu´µú`€&—§‰g8L€×!ûÓ­O®´‘ÆÐçSy¾l‡ 樀hj~rnxujêjüí˜ Î|ä1’€€À¢#cjVÊ)œyÓÈÍÔL±•ÚˆÂýÃ#ãf6gÿÍr[œJ 2¼‚Û ^m‡Æy«Î“$ž‰%ä_¦îR4¢»Ù)€ðwî¤h:XçnL³0Ää¼idAwªÄåè3¤Y+Äk>¬ò¼¼¾ñѱˆÃa/gº‰øtÕKÊ9âm)ÉÆîÎqÁ± ´ÙbÖ]Ãèî ú­L}÷õÿYþ”ã´lʪ'u´Ó’‚>Û|&åz<°Z§}éiùý…có¾ª;¥*¿Õ`ŒÅ¾1æÔÛ2褼/½4 Þ¾ÄïïdÿŠåŸåT‘,W½´ µ·,¥éE°[§‚tmîç!ºÄ„§¯ÉçZ/!` 0?;û\ üJPüR¦Q?î.àHѧ\(ê8Ǹ쬔I™Éiå÷aÒõ†’’>ʨ˜;î]Lø¾Ñ=œQ*U=^ÖH>a èéç,¶õ»Ëõq9óâ­Ô,Ýzš©^_·$Éqs±¶‚Drõ+É¢˜Óœ!nš˜VÇbúo¡ÃÁèõžæíFïøÜ@áe[é~éY¦„Çë ³ÕYÙØ·7dýÞ—ª ¶Q#íj@Ũ¶‡Ô ûžÙS®=$Ð?ÕÃÖÕŽQµ€s ¼¦Æ4‘Œ9UwouÌPG7Y¼Òš÷º:^™;~âw¯ :DHjØE'¹ f£€âày]tyÁÓ¯õbOè›Ðì:A¹™VÆ3{*î£>%XM¸É½û-ßC Y庫‘Tů²°:g6 ¯Eä&L÷>îÞ4¬„‚î3B5›';r©?ŽX‰íT;Ä7$ö/•öÍOQh=)aèëùäó÷™î—†²œn™ü/wDÄB ­ÛÿßÑ[Ý)…»XÕÛ¹RÞª`H¥tšäm3ð-U<@ì± ÐHF˜LÚÚæ{+lŽ2]An,ºõºszàéà`äofÕâˆt/1sF’AYM›<€6$‹2U‚5ûõÁ<ÍZÂ\®ÝŸ“3ƒÍYÇ0<Û¿{ —™é7øéWU‡0”´¹wŒ†S±Ž¬1-¿®L5ñ TXŒ¡ò뀿ѻ+mš$ØQy€>„#õ3ßú¤íªÊÈÒiõ| ‚À0Ç{¯ö£·-ÌeÃ…*&WÞJÄ^ݰ±‡ˆ ˜–)2³CVZ]ªKT!¬à%áÔ ¯PQk?}9q¡1OÓ)>ÚÇ+(J_ž[íNÊ"îU¡Ú×î/¯¡'8þqUnÖƒwwuÛ„¾@:íŸPÍ“æ¥>j¼k.ìÚQÉĽá鮎—$ãPŸ1m(ôÅHÝè´dLmãH ´/u‰ÁøFÑÇ Úlï#<áþ>ôã݈„l‚怽þ%^Æ¿ Ùªx[wÏ. ÅnŠ»Gf£Àà–íê 1èbýX³þÒkBë³â“&Uª[âˆPüW¥Ëˆh-4ùÑ’U7l¿UA˜ß„©“Y•~s©œ“m¥fK‡WQq9é§?”– êt«u›îXwïðƒ¿ûwŠÉl$ ê™åÃÖßúdÒëz7ùòÒqhÐJµüdQiU‰ò>\N§»Übc¦ä4ý wí•ýKâ 4&âb,>df[/ºª°<8Ñà¸B9§»àþÒŸ—?­N[ðŸgMÎ'ßßBïx´×ØZ91=¾iq¡]:>*ⵯQŸÐQŠ$Wð¶õ-TáºÆ§)©Iyíß´åÎCpW|"¨`Q‰Uò“[4ïØÊT­¤r–·¿Ü'l½¦¢E,™¨´EäVÆ`…)iSc×]ßa—••7²¯ÅÇöÏ¥[δokÿR¦ÌuCËœ’€€Ï@ÆîÊŒ…÷l”‰[r¼/˜ÈĵHó‘æÿk§Oõ µ¾4æÿÍ©3zx4¢——(†£\Ì·7p%ž…=f®ù)B*ª†¦¿.U5¥îk nY¼ÏÑ—î|„a9‚6ýn¿Å,,†çµÐàŽ˜C” Ë(âáÂo?*²èqðÃÙÈ=~’/6>ÎŽ•­×òýƒF‚6™‡j÷4´`t, &ZmÊ×wpÞ3J)ü+Ûæ€¥¼ø9ª¸ ÝØFýÃe+†æyÔ*€Ý÷ã¸j¥±uìňɌ³¾Ø©û ¥•$³Ý´»g™|9Å<ƒúF ‘ØlLaƒWñbŠ3 Æ‚_o:·ÜŠÙ1ùSÛ_œÝèØ´¾áNGsì˜*&â¥EDJ=VTaÒÅ.–‚J …×sï`~aºË5›æûôÙ(cí)xcDh‡ÿÙ+×[)½q1—&ÎñÂ\_ÈteÞ³=yÄB«ú pr!eqš_ÜÙµfq¼Žeò X=Ž×Z.Œ°vå!Šw£sÙ%œ@o!o@õAãÞ)Ãg;ƒ£Q†ÿ»/×e"}‘þ\6ž·C”¢S=ýäÆˆÑÄuÛJèN&jªÿ8¶¥þßÂ…X"søc”ïc¦äv;k¬÷Ð9U›‹˜ð/é?Ýoáç3ÑfÙX;• ×ZÏ’×ºŽ—¨ºÛÌt(`o'´mन:üi™»óñ·s*:¶Q.€¨ð“ðÃmJò›!èc?šÛØl—Üßü¾jz…y…š´€ù·Ì' ÉCÈ÷´«ç¤åÕÔÕ&]&¶ôrcb0Žò6’ÒnÇumðMåK.Ðw ´¯üª•C¯o|7‘±4ÁZÿȹ¾³›mÍßyÿX=2HËyÎ/ if¿¾^Ä&*'V#B{öåº4JÎa'ÎÔk#~j|3ï¢ÅžÑjÝžŒ´Hq`|fZ–î L»I»H/FØÿë[*ç\¨—fÉõÄ^WÍ~A~¤û.L‡#Ó‘HwæñZTÀ¼$`YyWÄ·¹R|,]¸G¯Cö)€ ä“« ]ÿõûöÝqõA(hžƒ¿ûË22ö«“2‹Û‡-ÿ~/ÒäzÓäs’“Ô~š´¢cŸ—7m[sîBUÎw)#ÛáÌÛ!wÊõÜÂc«<“’€€£ºˆ·˜¿þê—¨½w ª%q[]tw¡Uì°žCú‰În­0çE£Š{Ý; åxXëOŒ Xêì«EÕË}­Ï†?óÏQ#—Æ!¼!Ø…ñNBµb*ï(K‘Qûš]–•%xÓÅÓÚÚ.¦aÈO©¤Ohl-^ƒ‡ÃcÍÈKJ‰Fæø«qÇ- 0¦te6Päˆ=aî…áx·ùÉ3Uç t%…–±GC«b>H6iq<¯°$‡~yï{мt×ò*Õ~^¢DÔæ«Éä|¦* ñÍa~ýpk¾UXÇû«0Åýp%¼bÑ^òBçÎŒ€²«ý]ƒçÒ_œÿúK2ü8#Õæ£³œ“/ÛöÏBH— ®yÙogáQÏr\jÇ›6W§)ãKᨓÈq$GiñP$p¾ïªµ¨×ÊMì S»„ I‚–®Íyåõ^5<ëobŒ€ ”ø<ágC°†5F†5—?1Ž€{ǹM e8ca–møœ›[׊€  pƒ ¥»³¢o*f¸/’«*ã_ÓN‚ ‰á÷¥»sgÎêyóZá%ÊNØP‡C})äy¶yÝÔï þ˜§ßµéÒÙÛ}]ÐòV }é>my'DMÐå²>>aÐ|$ ]ƒeÉcVqp! Q^‡9¤É*óæÍ2²¸**wqØ<|TaiÒtë­ô”¥:;(Bò^°³Ç'ô¢Ê¸o½’ì?Ηam²U?òŒm´¯a<Ø”‹ü»1X®¨AjâfPøÔ|Pv«¶íÎñ^˜Æ`qy³}ê?ó“icêΟKF6ü¶3– Ý ãïÄ &;>ØOàøhÑÁõÒÓy‚œ:ÑjWnE(¢BÑí øìÖÐ4=…Ë[^:Ÿ,r?©2êaSé°̬Èg¼Ä;{•Òk§`“¤UìÒ3£=ÂÚÉÕ>±K,á2X–ò<§ÌÙ1[3g úÓÌ m6« é,“Õk­S †·" †pÝŠÅ® Q”~³»…™¬OÞ©iŒƒËÒŸK®«ùਓdz&ó.ošýQŒî¬”ùÞlô‹ Ù4Ïeæ»ùdD}Bc‹ë½‰ÆU…´Ka§Þ3ää¹8r˜ü"qš¥Ó—¹%KB‡Å? È`€ ãÈ tÿòö¥ óƒ:îî^’€€Ùåš…:ÙLh®7ˆÜ/ï’ä­MŠ^5õx ¥íÀ‚!E˜Åå 6ÖkÊðW³>gˆÕ]W³¯zõ‘‡"´û]UÞâ"ʾ³õšI®oZg!è&–îtÿk–+ Vä}ÂÀeÐ:øe”)‘O†ž²4Ák Xm”vc¨x¥ü:0­Ã;ò9v;‹— ~í`SÒ×Ý2[ Zº¬Þ)1î·Á-ŽLÞì7fÿ‡'—$©†Úka¢bޱqœÒMćɢhÓË%ÿx.’Ç»“ˆh˜×ÒÿdBtûcÈ ùQ¦ùt¥h¡m°?ôt.¢?£¥‹„y2ð¢+¶ZKòëñi†«/çEUjŠÒH%¾°ç¬³8?ÿl^Š"üx&Ò*Ê%‡…–¼;Ï‹zµIi­ln¹!óÃZø0À¹`Kb\¹ý¶ÖF˜g,G{€<,yVJ‡×g=G[Ñœ%V XæØ]ÕW:Òc~¿• ‚¬—‰u9g:ïçÖƒ§N`/Á"©|N…»±Y2Xg¼R&c²êÍQK’ ’ã‰'§î#ðJXöµJ1̦gy™Þz÷y™W<” ÇßÄ? kv'y€—aV˜aƵl+$ÅwaŒ YHŽ=f›0ô ä Mz@}aÐR]t ²¶ÂÝzñ{)r7ÞTM삼ù’LDØ\¯Âm¶Ç(ü °0áü‘%çgï?Û‰±ˆæ 1®fAg´,²«’—Ñý÷nÉæL³q*F¹°:ˆ ·ØMYê°À ”¸«Åæ¡g/Ç Ì Xk®ƒ¶9~ƒ¥IÛäk±º¹nSÇ{­†„ÀŽÇy/ʱ>?MÁßëÚ3¥È‹g8Á¾>ƒW—I¡ÇÓ×{0%óP/$¬$âO·`!lÎ ÔÅÉí'C—ßß•ÁTÃy=ÁFÖM®JÃϽ¶KPÞ”òn?ýñ!²mu¥Ôb$÷öMŸ]lné’a.¡±ä_‡šÆ çæ ÅÜ_ ™—ܧ£öêÇ µQéÿf£f'H`E2{µɦè.´õôÀdò§ÐØ®_Ḻ¤ È&A2¢¼®s¹…´¥Oå¨Úbhì'„Û½(0JõOîQkŽnŒ©ó7®\A‘!:1½zÿí™EÜ!Âí%±så!÷_Ô‚cí9UÝ]ÞÖÁ’€€ØÂN÷H]¯À è¤ÌžÊªÕq–9Ðö¢ÕHQµnq|<P|•h­¬Q(±}±eZádF2%ÿÔÎÕùS#½¤ÐB Oádèným–l'(¡ýž H¤•Š‘Üèø/ ¥¦Ù†Þf\œ÷”I¥€ïÍH¿N:kHýSùÜù›6"$íKªßˆDpmø*Š%æusþ}Iy+ˆîµZA ú9œ©ïáÚ¨™ éI¢ÆÃâ‚Æ.±©Oú€²*ûÁÈ{Ï:{®P:»Æ^ Ô„M¶Œ;´}®Rt ¸E¾X•x¬VÕï¾§°ouÇ€½ŽS•.à ã[«…¢sc)V`Ÿ{l8Èþ¥Eœh "UM&c-U\$¡Yc¡èÙU>Mi.[ÕîH+ZÝ'I¢ŠdÑŠ]-÷ž°•”Múµ(|“Q´^Õ¤à>’Gˆ|qlLÊûX ¦á5PPfCP+c‘ÐL18ã­Œ^ÀÄ%âŒa³!i]U K‘v[+±±øšÜ³ÐváÊÅ“§Œäf.Å»gߘÚ²ÓÒYþèÖr£K«Ü hÚãø²_tàÇÓþáÍMBô<€.ÖîŽ1MáèPÄyK9Ííƒ Xü-¦ˆX$[¥*gXÂÕãeþ7© 6GlÂ+3ÑÄæó¹®%+k4Q„ÐwYÈO~ˆð$ùŸö‰¤ÂÇÄWPÌA÷¥××µŸôìÝoS‚5é7PÕ$q$"[Bq!:SéúºC+­¬‘²”ëF›åõ¾E’1G§Ÿ×#¿•÷])]E,´–6X„‚“eÑÞ§á|Qhk)Ám˜i&.ÍöÞ!¡Š06ÌÜP^0¾ããá]á=l‡~ä(§žâ“Y`-P¤Ò!RÖVë~CÒXmR€˜O1Y‡ÒŒG "L£¾Í 3Eí« à92p€–¥àô$aÀäš«û¢Jõ·4,S“w/ˆ²·…62ú(¿[ Âùj•AÖ·”64/&NòËçð§øƒŸR5÷%êÿ¶f»æV8Ln›«¿É,Rõ˜¨‰¥£ÇÂxØœÖ}¬üÆü¢gÊÂ1g²B‰qs,½&èfÈÇ« fMÏHà^ {÷î!öŒÅ¢„‰ó:mÏÐgÍúœ8¹ÔÕ˜”– ²3å¯Ï™òû¥º;df…ë,X[5aª'?®8þg>ŒÔæ 24ƒ¶¶ìmO´/$–mËò.†’€€¿jô‡‡oÝ8íK¡A[Þf ÎÔä,/Q:í¥;aS½ô–UÓëg+–1žm¥Ü5G¯û­ þЈÒ¦ÉQKù»öŵɟê4w•`-5þäþqLÍ`I· ì­‡Ki)mÑ8Aï÷;7x¬¿ÙåÜf¢ =¢xFuéM ¬úFËØÆf\©®ÙÈÄ|=f¥£ó¶õv®+3{ÔAÚªd‘cŠÆÞ¾†§ZžãÔÁ]AΞS•³:#Y…\¸U83ëšl~syªgyŸ-î|F|Ï)ÔúÂW¯ ÷è QHl´†Å-Leê»6CMEJñE†ª;*(8ç|4=+ßÊRúbÕ׈¯{©˜‰=ľ@ãÌv.—ä_ &Ò¦Ò”’.3+~––¹LYG€ÅÆ,êgÝâýÒíëÇ™@F‡^:€&Çr¹%=Û¶o‰U QkÍyG¬œJh€Ü›’ö ´“±+ãxêð„X_‡Ž%E‚ù$»ïé”4~•ù£X4ÍÁÌC®­ãÑf!!4”wÞŠ/»è»òBØ›+;ú!•/WÀ“Ðÿ<|Ý-ç–ÐÏ‘¦„µ>owb )€+„¼L«4ØTÞš8·Ý­¶ÄÖsMˆç©t!®&†å}f~—ß8„8# -Ø—©vÍéØðÆmJ³T"xœïnYê¨Ð3«ýÂFíÑžvE,ú'ÙáÑ€FA_ÈkÖÐ9l3#©æŒÇËž:CìøZ-ÕD[alñaMÒl4‰7o¼ïð\Pæ¾AÎ×oó 4ªN’€€ EëŲ{ûLO‡báÿ,¨ˆÑ{Ê~k©QUZ=2:µÁ…Iß·ÃN™CèdŸ.Ž—CìÙ/ZÀs?JÄŠ"¶–-w7Ï—XGعéAµ´ ›©òM2ß…¯„§¸ÊžqçeJ"¶þœÁΡ—ÿ¾ëM)ž®ã\×.BÂ'r·¶XžéÒ:¢ÁƒzÇÀ˜Œ`'§Q•x2FŒÁ¯/¶JˆÓTámA’„m`Ésûõ ³²i–TT/ÝLÏdOIøBÙJ±NL3+ Tüá× ƒ…îh/¹o˜r­?¢‘Énrþÿë;k!>äZˆeEÖ2âíìN%¥Æ«L…i O‘Ömݨýÿ²ä_‚ÓP?ОâÞ½1®4úœÃ•·'&T/H>bví$LÐ!:W½îdFºžYÁb h§—’É(ø/Èh‚Ÿ6¿l ³¶•Mƒ¦Ù×¢èK]_@Ò“yž|G¬éÍG íÃ)½Ò×À?~ÓPŠŽT«,N ¡ÕFVp×œÜø0ãüsבÿØú*£l¡gÒr$š5?–» LÀ§œgØ—Ún"Ì)ïBç”]ɨŸ7ÆÿãAÊÙó§Ó|f+R&ôã áËwΊ=~—á KÚ­¯ë´(b·pæog,l¿TÜu¥ôC5œ³ÉµÊè¦ý0cÝ;Ø$`iœH×]læ)ÓÏ1ÐØ–L,ᢱM›'e]vÛŒÜQtæJSâ-5Ú1HƳþçy¶µ w‚µX(¾ä´´¢Ø%7/ùà~_"Êæ³4w™_ÅF'Ùà®øûÏd§øq;R€ÂG|Á};®£[ºÙ5=ZUae-Ê5lM4NÙÕôbfMɃ»±Çc=Цæé»‚cMÄX”ø#{z¨ðÍ×Ó6dðˆ¨Ùœèš…u>÷:t/þðcœV vŤ'ÐÖ%ˆ(Ƀ¬F£3s8œÍpnýÒ,n°x7<%xËÂÖ¿2¶³œéÖÔÖõ|©Ô»³øc%î—üÕ\%ǵëúÌgŒ,æ´}-’t™L¿/Å’ý™•â®\tÀ»ñëžmÕsPúh×RÃL¿5…8œÖÔK›ƒA—Ift4²I~Ž iÈëÞNøÕ²U|d𞲿Ϩþú;gˆÁúç¼ „Cž‘nÎ'Ûë’€€ßãƒ|-7QØ]x±ù`X¾)©í5UÞøõ¬Éãx¢O…h‡…ÿi¨’5‰sÇzi½¢Ø á7ÿ¾×‘w¥&(ìÂ:ñ.ˆ.Ûæ+~ˆŸµ{éyAš‡IxÝ‹-8óZØÉVcV»êï•!‰¢÷ø/zÔ‚&™ðÃÈO„@®_[Œ[©å•åi瞊¨î€&²ÝÞ¹:æ¶è-oÒÓ4)%–Ž®X#³½\ý˜„¯c¬ÕÒOV(•yÇ)D17ÿ&sYPã£y°ú«XÖSíŽ0å}Þ~˜8´;7FúûKÎ ñ&)(¥Ê/‰¥Gš?Ö«!SÙVqŽd -퇞˜Ý `÷æÕ”^…™2–ªÈ^3Y«iã˜x(Ê/Õ¸Öá1šQ¶¬¾]ã}2ý!5(¹³¼;ƒÎèôÈI&K€S´yœ’ªŠ¿%ô€™ )\›&æ…ö „ÍC‡6Bî€È-ËpÖÎ Õx¾óFFÇ&a˜h(Ï¿‰mq;ôÀ8“à=Z-|)H°B_dÚ×Ý›¯Þc9ÑÉ÷£‘ÁƧ¼s XK»Å;›û%íqË¡kׄV˜ï †‘­˜%¶½Íƒg^Oqøºý¦Ý^F¥ª]u¿Ý-%ï>©Øs‡ÙÄ–y*ŠTÚaÍk¤n`ÝxŒÍq1ÿâ!µ3=¦e;† é†_Ql^`h€dØß‰TÙ·¢ØêQ[Ÿã'þ2Î ÉtÝãë˧WõGPÝ5оqiéÞÂ¥3]ê?>¶S`’ÚÄ ”~><Š‚§H®”¬Ù›qNß¼ÞÖ?)õäú þââCœcßý¥·ÍùcKa]qù”ÇÛ Û†²Kû?ü˜\C´°«AS!õ^¹]G,å¡,ߢHÄü2Ebbbí.;Ÿ?ì Ò\¶?–u”.¼³†’òIk”É Ò率¢ud‚x*!@wå)ø0« h¾c\f”"›0M«HåY3Pk±y‡Ñ'éþÐ j@ù‡£-oýqâõ…©xu '†š'>ã&7à-·§ÂþZªd‘ &~ç3%í¸™†x-û=âSWÛqÔL&_vöÚv4ô=ƒƒQÃb¹`Ö½Ö¾3|§2íàb"RÆ». ̉¸OÛQIEdHŽò–"þêv?`£|î9€³à¹KTœÿ8ßÖ–õþø×ÍÉçÔìÀ©ëm|zK.¯4ý<>á÷‡)ò©}ȯÖ×t9É äpOáS;JAÓÉ-E†¢®Ýµ··Ñ—_½\5DôÍX9üðúŠd à시 èVdíeɵ"è)7…ôÔÁÅ¥÷MÇb‰+™Kë²#6ü’éÍ?8|Ã}P¹N‰JE~CϘ£säJq"=è ÂD9]-Ý*_ü¹îMŸLÄaògø6}xÍÖïrbØY»îp€r¼ïuÿŸŠî"/VÊœRXi0ióÄ¢O;i(« ê÷j ´©3e|DñúÐCø£Æ#$¡¡Oêèùem£JD)}Ço3cÀz·†Iv„# Vû3;?Ã"tf—AÇãë脆“™ƒ#Á%4õ÷EßmÍ q3yßN]žž)f¨Q)G…•eûR¿ü²FxäÈ2Åvb›ç¢2äLŸâè¼FtàŠwæŠ d£1#EfOÉUÝ£†e¯‡'´çy ½U^‡uÚ BW8tÄ c_8äZ<ÔÒÿ¾¾,’ÓÙÌ™Ëâ‚»¬PÕª”‹ ‹^\µË°CI€–ìïÌ5¤ûi‹$*¥"#59ß áehŽ<‚öÞ^Íæ 1ÕÈüîë³-tžh’€€Ú&ï¹qš»Ëõy;„$ñ:†¶gRü©_ô²—„F°¾Õm¡Å=Y*^„—Š ø(òH•W‰L†¬ŸáeÿƒUÔÔÿU× ŒKÇjw'kZ¹ u¾GyTŒÓ/]ÌDz’P¿€zK[à±É „ ÅH¸ï•Ñ–"±ˆ‘ÇTÿ'H¾9¦®hÔQC#»¦7dS¾Ý… ˜z@ÇLe&M„PMeL‘ÉËp¨îõ}¬­ Ÿþ;N­5ÑÐ   hìˆ >pðš¨áM[-C¾õÌ/Þ]ÊXàHA.«z¤äí0{˜©íÒÔ¿ ÷™ô—5NGÐJ™„x™œÏå|›Ñò»“ok„š\ KVIR4ºûK7;ÁS𪠑ï4Ù驼¡7ÉWic¦€WsE¶º°±]Û;Á™NaL©úñž•q*£­Ï…KI\2ht?¢ ¯mH(du|FÔ¿uŒ–>R?€QÌå0´›F;»÷˜^ ‡{Ÿõ§£ÉÉNüÔl· c%¸3³3MÉ“Mñ7š÷§H¹ÔlbËå0z˜2Å®Wâ³VÞRßÔ¯ÌyZ1¤^=á–Én X©=·Veñ+¨ÃK“ÂsíåÈ:•;ˇžb}󢨯[¡è1¢Ô j;ââ6 j,Sµ9ðÆ÷#£¾öñoœIÔK¡ÿü-N–€ø‡ÌnŽ.¼Y]ܤ„Ò‹Lÿ€Õó€fv·ª3º;ºí9nÅ[¬ Ê*ÒˆÈ%ó½L`ÜBçPAX‚[ÁÈ–ÇÈe'H8ºRÇN‰ØÑu1åÒò  ൭éýÌÙþf&¶ÀÆ eçñÆ›&º„Eñ’ÊB“`vÒt˜ 隢3:­ŒíÙ%Jø¾þÅ*Ùß©EPAkKÄœý³ðw1üï¶_kLôV=ùýð}¬ýˤ¬~ù·+_Íj°yòæÙN‘%B)®Å…òhËWðqõ”BÆ«÷¥] øÀs˜ê2Æ™[¶m cmymíN sÜÔ°«d^›ôiRß›Ü<Å \uKÒˆF<à–QdG9 ÿŠdÎúì—Ø´ ßAø4Ý4ƒýE[6Óp¢”ŽRCˆ¢*)]d³NlKéìD&,ö¢’¥’€€É©ÔÌÛ5ˆ"Ü{p†¼D ŠÐ›ŽNÅ«…D´ü%•v)~œ™™ Œb7_Ù½„{Óú̆˜;y eeÇTÿò/ûâ*¼¯m³õçÚX†\C©Ê4gìsx«ýÜ“žr‹ÕœÜæôsÐý‘’$›&ÓF!ÆF-«ŸÀ4¡ËrÇîz‰CxsœC@À£wnú­´`iæÕ¯ÛÅáäÅlê.ú¥³^ã±Õפ8¢×è{mˆý%¦¨™¥Ú(~©žñ–í\Ž”K¦‘sá­ÍIø€ÝÆGÛ¤«˜|ðÊ険$Å¡[šFóm£± «:d4"ÙÏÚ´°Å>Ú„ÅÕ ’ç)Š=µñÖðT<<1Õ¯ "&J! ¯™îâu³qM3¸¶Ú}ñÛ¬2º )­ k’ìFĸ¯UCþƒ‡È”S;B(<Úš±»ò¢¬³¨";à 7ºêG‡á‹nelÝW®ïzÏvÛîؼýâÂF ‚µßx}½'6B¾ J.e÷sù‘ä#SéŽäÕJhÜÏ/n±äl”¤¾¯Dð3dX4B©%r¥\'ô ²/ñÄü;æuqò°·é·!ÆÍ Œéä(Èí™sKC‚NÅi L3ø6õÒ©ˆ«­5]f(b«¬ôÖŒ¸-0˸öÄòY~ùfø>¥ÍUµhÁãG·âìµeWA$]®ÝK}É™\U Mù_dêÊC¬“Ú^æõß¡*¸ë,åžâä=„–Ö܉’”õfgiÁzÚQ­úxIÏ]fe°®Õ׆'¹É_KeÔ]Oç=°ö¦,*—ýÌÛP¼$ ÃÉŽm±'ꎹõß<sôiùã%oïßôWãfÇ®M `ijütÄ¿ílIYª¿BƒÔgéÝüuBž/*þL˜êr8éPj픾8Wü"4•šÔt;y[ºó–e÷)ùbËÕá"„Í×s;Vš¸œ ¯¹‚|a¨ð“ŸÅst#Á=à¯._¶@Ú\Œ`Se÷ÁН'e‹·UNÚr:6¼/@@6üª±q]!ÉrÌ\äW§–£¥Kä­g i»Ò0ÿ¿QHx4e;“È_ÿEáÛeóL<œ±ª¤ºV™5YÆÉÅFjœ-Ò”Ž’9¿¡¸¬)ŠþÔß=ŽØVùãâc3›È²? Šö ˆêýg£ù[Ú¨à·Y -mšƒBåpÏdR­B„é çÀ:ñŽ¿6顊ÓPÌR=„$ÿìsdfB¨ Ò9‰ù"Úp ›d|¶TQÃëÖNw0¥;Æ4;üÏO.V¿‘‡wÁo áØËÒhñk@ xËcž¡½Ûlªi±yÌÖˆÿÅeäÞ’ÈÈ"h)ªTÎÍ<Ûò½K¼[‚@A³ÃÆìdl¹O¯¦Êv]èË;M…bäGúJÙ×·qužf:/ºÎY ™ ÒƒÊ»TSPlßÜç ÑšòóO¿‚Hß°Ÿ2ÐÍ„?lÈÎ=^~zÝn؃VƒrD-Ÿ ¬ Œa=¸¡ˆÚBc†8à?äÖœÊâ tïÔ•–Ÿi¼ÆödžZ¢Þ_Q¨Ov„ µsQËçÎ_ç`²â4½ú›ïƒu6ËèK;Þ)¨Rô©\ÖNähÔ%”çó©:ûE{ÂÙ7×”K¶Â§¤w®¿-k 5¢+Ä1FÌháÐb ö$ÇÍ­`åÝ=½µH>ó¯­J½ºÁ×t ~Ha ”g»VëЯêC)B% ‚ûØv¼ÿðßoŽbHxwúy(ëEXttÈ_$Yâü–5 ÇpÄÃÒ¨sG¡ÄÐe~`Çœ/r)èóèd30JÕßRÏ“ç«|XȦDÙù~Œff4‡· P‚:˜søA‚ö—½_HÞô±_QÙžiêL­ÌÕ …ÎÃÖՃ˜·3 #m0Ó =ùµ{ä‘X’oIÅ2Bx4y& ?”~v±­-Àþš<ÍÐ…ÕheºXenBÿp’Úâ$æp9 9WSTŸåO¨ëäY¯bLc’Ò€9LŠ¢HkÁÞ\q:nLØÊ50’EH#‘B†·™T GfŒ„,S”ôSÕ™o:^ÈFqë<5×2ÐnôTni*ϯÉ8øg+@Û.?[TèÁ;o/h$úóùš.L…V*—øµ7³Ç»¸7þC“¢xP„›öù±Í Ë$®ÂôO[ž—~-âø¸Srw ŽWÙÇn þ Š‡È¥C³Þ®d ‰È;Fÿ­½d•?`»Y|‘‚IËðïªÃ„Ž¿1Ê)'ü"Ày!ÐôCyô$€ÙZÄe- §áâ@F=\[Y°·Ä9þ_üaa‡+Ï‘¦¨QôŽ’Ô½köÝѼár æl 9Ü8ß}(KFh´ÿ—ö•,ÅÆlC江¼N•7‹§,Ÿ–»g9O 8 W\ïÄýп©|÷òÇ´TçQÉØ· ‰§}ú<µû.D¹ŒÀQgŒ"·§É»µVç"×'ÊX#ã‡dÁ{ºÐܤ·VH”0Ù?n sWƒ×õ™èlJš¡ÔþO°ÈÆ2 ñ®¿¨] нa×®.(‚Ùùž™Œ!-ãbá–Ì™BP.æb*6NÉoÜS+q«=Ó–í ÛdÒM*¶GXáéEžCötØÛæîÞ½k&±øzœRSZ‚ŠŽhjEåç ùE¬ÿøF×C§“ö‹©žÄü`¥k~·;Wú9˜o3%ÁØ_m#Ç«XæõÅOÔùç?wûŠd­¹ ¨s¢ö??Hɺ9Ùy‹¨Kï‘8çlI~re81põêíìp±f¿k1ªèSœN~Ú,¡œh-u+³Ÿ\nÅá@ m H»ÚIºÄ;+*c’3ê’}ÔÄÚp PyrîÎb¦=?#û–Mÿ.Ù½±¤ˆêA;€¢¶éqAN2!ãRüŽÙ9ðË7É ŸÂÈAp¤µ8Xÿ×:Òi …l'I0Ãav™£ç'ÏlU}XÁ4Guöz h•F°YZàÓyÆ«© qÀ0ëÆÓ@?B¯åZÂB nç Í¤­šCP"*Ë]¡à‡9¤|ºå§nà:±j&ןƒÊÖH%H1«Qc¹©W]fÏÀFTHžÐ_䑆SK^ߔ˻äÒEHkËa˜€t|ŸÅn´Ë¥F¿ªCô)¶™Ÿ):x¦UËÍ}ÞŠ¥r–V"ƒ sxŸtF/u ;ºEµmÏqôz”p}Ðås[mSDBåQŽ-žVüc&p¹M§¿,J’€€»« Dwø´ŠXW®±d›Ò 3×'`:áDVÌæ0cjÅ`A¼ªz1|î>Fƒwöz5rÐgg•b¯]2¤ §b…©œºÍ¼ ›p vÌ_` GùßÖ­Çgi?:ºôîëe;J v‘XD˜$úO±BdÂxê éÞ3­!s—®ê’_æMlÔBiQè^³Õt«“š0FRnÇ–-Ò ó6:µ|ª<_Š˜Ò¡°Ò·}./›lÃßuÐþ³erµPw~»¯¤îA4f²Öâ(p|n0›q',­ðD˜h^½”‘3cDFªNÒà ­Q£Hº™Yù*õðZá+ÕÍ´0DfÝrzýÎÈÔkA¨tñu¾NÂ2—ïlĬ;½d|E°1A2FMäݶ»Á8)‰hHÛ 7ͶjiâNìK•‚Û¯ R]Á¨ÞªŠäÃ.†n|Tñ®¢jñÄv1Q~mÇ;®¤~ËìiÞ1.eì´±» -»’{<Ì4° ²Gkò4!€éƒðŒ!“A'Ø#ݹ^ð”¶¼¸!ŸIÏqq1Î!,Âiþ[U=3­íµ9Û©_C=e¢Éí}W5ò+‡Øæ«úµÏô¢²¬ PWÒ•$uÌþ)m¹‹[ ;à*mÕ°"…æòž3 ­==†ïU®EF-Þ¨ñEŠÂjÔ ¼í,{Ô?”åè‡Yª€?á/‡—„2ý$É+»%|ã%ƒ]NÝ!umw¤ÝöåÐïÓX\fâÆ§©Âˆr3 \ ²3f¤:Œb?óaJ‡b N+c¢Ü¯9 cÒì{W= nÓîù1NÓÃA˜‹Ù×Å—¨ÚÒAb Ë8"sH•‹ˆLEà ö²»psHFìðɤÔÛOÃqÄÍ뉮©Õt#NN»ð]»˜Õ†f²7(¼[på^ıq@¨Šç·$q®!¥c›—:Úír3‘&? ª'v:.ƒB¤´-CãZšáÑ…^I×áèµ{ä_¡ÎrˆËcϫڋ霂‹;"@!¦; 騉õ-G]ƒØUE-ÑBü ¥Ó°ëb‚» >ü(_–l]yF3õÅ*‘ê9¿ÉÿŠáH“[ÞÃð0¤ä!¹>µ‰BU<î·ó»p!ðõ¾ÆþÆ ÷‡B,¨ôTŒ[}ð ˆnAÚÕ]´nC’€€Ò'§2B.Y¹“ë¶,åÒ)÷oã5«”HqÂßëÝ3ÆYõS=Æé9šýOõ|:~½š|ŠFƒêõŽÔÕ2Œ‰ ÿm·kÑUh“˜¨:€¥@IÆÛÝãÎ1Ò´›æ„§¢v•bØ€Fð(ÛOmóe=Tõ _Î|f^iD£óḟ©ò…g[…0SoV\Gm¬Æ§æöu¡l ãüD¼Q™÷ùÂùk%Ê|g5Àö3»TÛå¨ñ¼Lzõ[mœ®íªNÀúõ ÉeØóÒÜ“> úÅ£TßóØÿj/ ® µ††›X5Æ$› 5.Žþ`ìÐFºá8QnK5&ê‰9”0hÆX6¢žÇ’ÉÝõs=c-xÐÒ¨2°y«±&#õ#-ÿ8gò^îf$µx«nñ­ny¢¶Wîœ<ÌU€.œíÕÕ¼£s8wc_Wƒ·>™)T~×ÿ[K4¦î™zÅV—wèMaÉ!—šxG a4É/Šâ¾ ã‰Æ¡z§ÇY·v-US‚Å%=8Ýé³^þfv2ÊØ ¬vdžð©3×=T:þ¶n¼È¸ÓêzRE)„õöGu*î0l„'·Ç¤ð`»1ã^']ù« Z]àh„”åèv,ÔžT-[+n1bþyŽp/¾ßÄyí£~×0Al¶¥…›cµÕ{÷ƒ’Áòß®_Xb,t4Y¦F dãÍñFV÷¾¶ÓZÝ4rÿ%Èo-1Z²ñ™ã¤y‘ˆŠÒà /ü‚åÄýY¿/Î rq)†®Ø$á® æ)럔.S÷d)%°ÆNTÛNÁóªÎiïÞocá¥âdèŠÞaå1I¶4ˆ„>¼Aöxz=L€=™ Š;îŸ^nŽÜ?9®XGkµ­ó÷|×1é$hÜTÐZ‘üe®ÅµMÅuYª'× M:1³>‚ Ru©ˆô «õ¦j ¸ÏYégÁv<ÿ÷÷*—¤{á®A³÷vr³-/™âhåÂVòÎgFÃÁ2înËØ_«ÀªêÍun”•‹.¹d W¥5hö )h0ä,Ø2lpRìÀ·)ë) ³ÖøWM}÷¿óY qr_À?fÛ9È) »Îè R3mËdÌÀÂÇŒ’My’e+Í.îò̤=¬8 ¡¿[]¯ÍãZ’€€µéqÀŠÞæÍܶE1=gßÄþÖÝ›+ßX’xs¶þÄsØ·iæ2Þ¦«X™Yli–#Ll81ÞŠàQËŽRyiçÇèô‚ Õ¸Î>À²ØÎ)4~N˜mg7[óÝSøò7†ïÏ^//«|T½-&”c¢.”Nrhg1̮ܵ¨ñ/Y0ÓI zS¦^©¨5µ– 9/ް<@³œÃï3Õ2uÀÈh%i]ŠÜK<€ÝÒA¤öü’Y¤±° 6uÉ!¿{_kË%¶ƒG¯wÛógö ˆŽ6ÁÙcØr­×µXª ]ãÕš7-ðü„µmöÜ?ðLW|‚*q@M_Wj³¬¶H@7Â,5 ˆê1Ë%¯¸£8¦u]j}Hšr \Í¿nuót5ñ²Õ õKé2Ûÿÿ8=2‰©è®¢N“aZÞðj¼ÂƒrÔ².¤JŸèÞlÈ4Í˺ÝÒ·"oÓ«ŽëõMú"s X3¤ŒÐ÷–cPíU+/ +Û1ë—|MbEµùÓRêñÛ.è‘ò·¨}9jN·{®–“žKÈ5!3(£ íƒCÔÞ˜_„”ï–´Ÿ›fÀ¹]ñôà''9ñÿêãS=éÇmœ”ƒ"¡² ícÞÍÖI»Þ;)ÌZŒyº/IúD±pgGÁLO›SµK1@,œØ•×iÚFÔ¨P`ÖŠè{6‡~$\'©ÂA<Ü>¦ÁmZϾTÈÉJÜH~.ß‚$OÛ¼>䯼¡¹ÛwÖcöf“ztÐn²”þìuû9"´¢ÉÛ£%“ºt@¡>'1¢:Ù+‰ç+ÊÒo⯗ìö§Æ²mö9!ÿi¹›ÕY»ßÎîP"ÊÆnÂÙró.nû0Jg$½¨Îºn²¿´e¿·€F=S )ƒ\ž²ê«ÚúñÝÕK¥Ç# rtb#SÍ`?—üLS\ð—`QoíÈÑîô¸Óp9GKM{˜uV†Ñv _”£l~ê +î ‘É&§5éHêl2ÿÒ›„í±k:Å(˜ü`£ýo{±;e+Q« LN ­Ë õÐC; ýÚmÙeÿðsÃG3»lŽŽÄÑÜy¢ õ5;týG2sû¨Q8Ã×)æÌºu«| Éo¡6¸Z°²uhÛÍûq°5&øø³ò•};qϿ€µQi} 8.ŒßÈ™uð+6ÆP!M¦:>R½´ ƒî”J~‘¡ñ­¶ฤv4Àý¨6¥g/ƒjßøqÍ|(å.qi„>QØ3½—[œ¤&4ŠŽEëü?æ§ò"-?”¥¬ü$"øt ›]üw£,§´ÂLΜÍ뀓&n¬ Ÿ· ˜¨î ˜xæ%;vcÕ~`V?-ü±…n3—ßNkXnÔݧ Dá×/Ù´ý9,Ùë“!‚¦°7/‚â Ø‡˜ þ€Ønf[§.E•ýl†`†°N„y±b-ñ!êbV0û©é– î6ÿu̹òX,\bŠ»¨÷DoiŽÑ¢Ähàž,ÕP_ ¿":dô3iïñG×&?ðI«‚Ù¹Þ™ŒiæâÙÅZÁú€ÓÛÐH¸kq±mEs•vÍË-ÍNN´7ŒJ¦³~úê+'dƒúp#Æ-8jM å?×{KµÎínBý&ÔbAœÿ©«(ÂÈ´ê0Pµ†1\­ÂZm]¿õÂÈš/ñ1÷ —z=ƒÉ^)»+УŽS”a€ÂÛËûgj^Á.ù4Õ<Õà>¶`šÁϘkRë§\BíÖÎYð¼Ð_DÔ‘\^•Z‚=l2LÛÒ|µç£®„àðõ¹,綈áÛY¤WÁU^‰gmrU?¤OÙçòI4Õy$½ÿç c¡1ª”¶ác#Z"<@æ²BôW'á.9ÞÜ0“?jZ»AÜò0«ȱjOØî௣üµN ëtšˆw¥ƒÉ{…º¤Ýo•72Óv ÇV¶jãK’tnWÈÐ<-9Y!ruêrh‹*í1jLO×ÂôÔ“ÈêæR&ÎÉ¥îÙü"ïú‘Ï`ãa£`0Jÿó,Ã7œ7pˆ ÂÊÌIZ¹ŠðÁì@Ía±QÓ («ÈW@?üoS–4ßû9@•NoPÕ,blÞdž“`¯ÅœÉöZA¾³"|ˆ‡ãT}ïèÿõBwÈ"õZð&Dà‰ûrò´¬œtàË…‚µ1 éË€Û 5”;k‚ã„dý¥ü•cHaYÿÝØŸ“”µ&§#½ã¶”ñ=[+Òâc„D÷ô¶~„¸9:•$7jÌŹùƒ=Ê·:„Ù¢x¸/ÉMýˆÙ® E ÷€G/<ã>°zѶZÀuÏ$8€¿ú·6’€€Ôö§Ïr°P§"ñä A3|Å*À"`G.^ì€j¥^—À`ޤ‚TîëNã 0Î|î™¶§ÕwÔʽÁÊAa€£‘Ó´º”ÊÅ40³S!3•ƒüÿž¯P=ÜÏ€tIW¾}»Ù‰6<³ãÓ+dkQ9N…"½e#Š*›ÅþI×=‡´2E­³­+LDÕpÝD¤(ï…MQ?7èSCÄ0ÒÒF?Rwé0E•Î4hºÃâWC 7f×L@;%‰}ˆ°•ˆA®ŒàËVóÐØŠà¤A4{Ç}éÕê¿ßoŠ[Ô6Ílä¿4z¢Î΂yû¢Bw» &üÒe©aS5Ïå[,§i¬ÁŸÄ%…A%:áÐós9Èm ]ŠBiexˆ4bmfâ´$DÕ)$̘ýÎòo‚D¹ß‚Š3³Ú!¥¡ Mî«#H=ûwVñEË´^ [Õl8\2¾  ÆqÇ£•¦O:ª6ç°e;+P`ÌÕá80_M7È>OëÀkŽ3ݼ­ŠYk¬üö6s(׺h1älˆ‰¸ai'pðQ˜ÝsWäV夌ѿ[ξ;~–«ûÁ{ÚζI¯*Ûôà ^ÈÓøXƒ/Óé,öî‹ BÆj8JÙ}øw %›— CigÿïæjË ü‡™Ý'Jõ ò¿vöµÏ±¶ÏaàƒaVI Ü߇è»Èn“ØE¯;W²S!0ȉ°UJö•Q¨Z¬‰wÆvKÆðçš»<xVV¶|êŸÌÀúŒŽð„ê+ ?e1£Î‰o:» ú{ÑÀ9 B?„¿óq¼«ÀL‘NqûVóÞµ5#Âià–Åšs‹HȧS<¯Ææ¶’³t5ƒy"+ÿg¨"sÇ& ÐÜöÜXR²|nß bว8¯8Íæ„î«ó”ünÝ~šÇU•:é7®ÏÊþfŒ*RÓ¡ÜÎô''îí||eápŽô{á÷9°_¸_Kx–¸Xô~²ÎL¡Ú·ú¯ò°fœäqô_‡»yíïú×"±(ä}­E&`Fÿ“­‘õ0¶¡AÖ-ö‰8î/“M¾|ˆÖ ÇxŠI¢a"‰½–™’€€§¹ì–Ñ·Ëøêda ?8º);© Ì ò†ÀضNV@øð´Ü–Os«çv¼¸Ùer²€>€².Ñ[X[2 éIÝ…Äæ[iQ¬ô•d2!´Þà ‹r†üÎî (h<• ¾â›£Ê×¥ö¬ÃgÀr©^6>A\ñjPéÆ MHÉum;ˆßS{#T.#OËá«©B·-víWÆóv.ì]e°þV¡ýWòÆ ·…ŠtjÍp€³'V>XBizIÔúŸH€¿ÿ“žaÃq5ˆÃ*¢Ü_RËhPê#Er~ãôcCsŠÓPç¡Ò$çéÓÅK¡ ¸’k3 ÆÙ^\ƒ;‰5= ÿ÷t˜{à{¯/É;}ùñú­¾ÆÈÐß²}€Ê{\CÜò¨¹ ­g™ŸKWî\k]÷,8(³' 7#iÌpPi¡BŒ&jÞ ª1“¥B˜%C3¾:@–o®Ù §†Ý0Çú׉~xï¼·79¡Þói_â卿åп˜W˜Äu-¼Þ¬äûF«Ì §]–y„E¯ 'ŶñÚ¼0o¡-—~®”G4ĶŒ=‚¯mšUµ ¨ ¹j'pT#!_F =C”wþße]tBaÍ¿·U®¢Œb\ï÷ƒ—%@3úpx2¹Ð_øÓº¹õíàHœ¾1-ÖŠ#80a’¼ÈRîVßV &X­À¡aÒ¡NåàAÂl} ‹Å¤|ì¤3[þY쳩/€ØF]wìt`8!†¤t£JHëLXò`nÚTâý&ç]˜õmÓ ‘°üGð×…Êp-¼×2Lžíé?.µD‹§|‘fzS±¿–åÈ#Ív¶ÿø|C°ÖTÜÚíL“ñ£ ‘ËÀ;%ñ4¡æß¢óm¡`sOˆ ýÓçWø£a¤$[ôD%â.»½¨•áòuM"—‡ÍâMvƒ¥ýÿZ{"8©´×¢Aþ ¦?Ax!ä úе´'–Swƒ”Ó9ÒaïäÁ~²Bo57¹Dsh:¼ªÊŸ“œn?—UØÐ[D\ ¶/3™¤.ëäŽ6Á26U'º\a»׬,ó—$ã‰Ó̸îóºÉNÞr¼›Ë¹ Ós JbA+\bÀÞj4ÞDޏf‡>‰s ,] 3™ÑTðÙs*I”­Òç4]’€€ÀõoΦý®/^ü¾Ñ™ÎŸ;²ñUjÒÕδš¯¾‚ }pEë¬Ó¤y̵ÝÀŽ¿Ç VN¿a¢Š; ÿ·fëXwWbázÔë³Åî§\Y}=]gOýÇ,éhx"íÓ±¸Òâ×z{ªÚ,A ú§~ÚòHÿâvQ”ßÿŠè‹.Ïr|`t¹ ÿV7jĶÏöˆö RbŹÎÈ8²C¦/ÃZÿÞÁTÈ!ìÜûLSÞyÖß%ð¥¦0Sˆ†·Á,°à © M*ßH8Ó ½«3Ì]ÂÞùªˆî˜z'ì'±óÉù„^¹ÅºÛ”ìýrÛì“L¥²îlÖ[ïB ÛØêFë{nâK`*áÒ”DÏÎiuh1‹;[Ç—qoµœ j}a*~눬“¨¤¨ˆpÃè€ô𼺘¿ŽLâ=ײƒÕ!*¶å3Á2Ë•›À^ÄNL u)"Ò¯EƒE9;O pSVà„;hî†wI²Gû1%òGÑÅØâjiÈ“«6)N Ê4È:oáúð`am»ň [%9~K¶õƒ ‡5œ{Uú´|ߘw޵-ÂòdAb—èûŸâ<1…%QÎÞŠÓ° »ÕC*÷máOz«ÕûBy¿¥°™Dâé2˜!ðƒg'UóÃ'_¬úšç&0ÙÓÙ†Sç³@¶úêÆëÑ…Â:jsú>¨éìT!cåJeÃdº«ÖCH'i~)=O+»T­ùwDõð”,OM†æOe–‘lõ&7Wðƒ¹%ód÷9vijðmÁ¥¾æö=˜Ñ¶ABY-!ž(O"J†B‚¶¸vûï´èiÐ ï·Ñi5E¯–cyçé­ K™0pärŒà÷uöþ@/~Éñ<lÿëŒÕõ¦O5¶KCæÓ=ê™’€€â¼Î³É7Í”k©ù£eëôàÄ|¤Ñ8mß'^5ÄîVPÙ)Ey´Ncõ4JlôgB…[K¿øÆûäFûô¡}ä¿6qsÉ@yï°mMSäFùD¬UI~ÜÌ£xéú¹,.jˆ3ñw“å& þø4ý Á¼˜.N…TÔV·ï `îÆj×z6€é‹ÈnFœšN`X|˜p¾-TG Á›)Yþ‹ÍôôØ#m Iþ>åÚ'åˆÚfÕU„(¸øéaÚÚ ’²@ͼ¼,Û§ôg’$.€Z>sµ«ò‰èœ-›&AäÀåa%O˜jÁâ^œ=ӯȼ¶›D2%àïSAA_»,Z¿Aû&0¾ƒöÄñ}ʘ´Q10°©CRz“VN1r4ƒ'^Çeê3äNú€ÚdƒÄØ9úVëTeOï‚‘¤¡‚á;GŒöÙÑó+ÅÔô2á‚ ›pçH±§à*&ãuƒ–lìL+U†hÕÂØ¤$©«)oŽ\^|g\¤âê&O l‹XP7¡Z?èÙÄe¥ŒJ;ÒŽÎAsºÄ-_²¢KC`}ªdH¹5P Ú‚¦j-Z5¤ˆº sÇï.yȰQ’·FÌa±lA@8oœñcRjÉÅ‘E•)IO«’÷ "ü1ðžzq?›–—g¯)Ùß{EÿÆx>ÇÈË/ßx(sw¥ä';‡~Iìè)0àD;(€˜‘a […˜á†?škF­–C~uÕËbC·7Dè8c@[¼SêEX¬B F EYËÉójÞN¼̹%<®¸£Kȶ€DQ”æñÍêñ-Ñ€Ä)b ÿÍ[’ÍL—âïÎp~ÁaîÓ›ðeàëo‚äòèÇû;7l僬 ‘Ðõ‹›f­¿G (PM³;¦³|ë§îÖ¦ê]yý<ÈU AWò‚ž;HÍî*T7ˆSAÆù4¼_õÿkë¤Nf×ÝäLç¤Ù#«µ,#Mdl í'Ñ„µOøy-GÎÂ£Žƒl% ‚\|˜ù.³ú˜¹Óe'IºÎ‹rV™éJSÁô¹oA‘ìl‹áÖ‚ý|~džÀ1|Ó7µ×fŒ½]-§„A´™¥kè—š/kü€EF«³jhx)Ëuü"íå:õËdE¨Ñâ7}·´ÿq¸ÿédж^ø‘<¹}]’€€æÖ‡ƒ%-çr‰¢ƒ+ò#m®ÒÄub±}malŸ×Ç2¹`¼¯ýÉàë‰KàG¿sÞmÌ—ÑúâÀ‚_ÚªsÔ{“¹t×&¾Ÿ¢«¢M0çßÓ¤ ÝÆŽèv+C) ñ¯_:Þ/Ÿ!=zL7QPT<iÍ¿ëÄߊÐéRJs«ˆü×Î5q~5»UµÄ˜Ý^Œ6CÂ(Gˆ8M·É{µfA~!X¹×Z>žD{ ä¶hº¨ƒëÜÒÙØD[ý;|$p¨ëBQW0ꕜ™Øâ²üS·A;¿Ø/åxü 2ñçSïE>Ûk]7u|“ ª²/\bòY gx)…“¿øõÄ€™xæ‰-Q3…tìðQá¸.šþ$SÜì´‡0’5yj|&)D¤úˆÜçi.å bÓ“’™ Õ5ƒ'ïû~ [zŸGäMÞK™dduÄ7ŠKR?ì¼W–úwÉØ-×,›Z~OȲú«i,¨ šö„¤_† «\h“ä–©IµAlaÙ'¤BVéBž ñ~œ-±¡´©dV"~_®p­^õ’z![íõü3çª-wë# ¹õ„ÇÃápªsÜêqssó›w¨#l–ü^¬>P ê(7Šœ¬H¡ü½ŽÍ ggô¯g`;ƆEv/ñŸõÙ¨Õ>fÕ  d>ßc= *ˆ_i N½6yK_^}âÏJ³^^†a¥"A€¶C~ ¹©»‡™È­Hᄲ& ý€»¿¸ÓßÑ]NŠñ.©hŠäÙF5î‰v1Ð áñìQ3uìÍP6cl> $…¼xÏŲ·5›N`jV¸Å5‘r5à)¿TåɘOgfƒ”]gÒ ‚´‡äå÷Þ ´’€€Ú!N[BôóúÃ2€c`#ÃÉ/ä-”u`)à„É ï½Pïi•ã " G‹òχc€QIúEîg-<Ó#S»gVnxß”,õˆ+,õA¾áÄ\êº<Áò|UÛ×Ý_/HZ‚ ˜7Ó^8Þ¼–¨ˆßi ªÑ"iGlàùr6“gþ~‰›ßBShÚ"¾ÆøÚg!\ðk7­1 íÆ¢˜?ßOE“Š.jqø]0žÄ*¹çu˜çeÊ}g€s÷¬$yQ3Ç/ÓS%£þŠŽKìÍâÝiÇÍ7 å,T=`õ‚PæWí-OÒ„Üçn§tö£ >ä°¤ü`û;üü‚È÷NÎM‘2Ö•°†Ìι€ûZ³X‹¿Éâ]Vt<Ñ'wN¼ø<ˆƒ—­)¹lônáÕ2"Bûr^÷Ð ›Ê&óàäR©dV³^%Ê —m\¡Òë¶T‡™`Æ"‚;4žùPæ.&J«ªTûUÓ~+KbùjÄÖ‡–¸…g¨…MŠ©ÑÜp#B/SØ>¡¹daŸêLE<¢äMÏPì0TÿØ„[Qí‰‹í³¶É醜@`³;ÎáÉÒ‹ u© !­ØàÌ/ö€E"¤&jB4_­õ½><ªr5'w€qƒJ-O&¡÷>oë-ÈHÇÓ8SŽ!ø‘™Úhƒ{üXež•pGäõìÆUr`ÅY(n¼ ¹¼Ë_[:÷å=‘g*M6ï–S߯›ŸÞÔ|’9ºTýçÌ£eq¿ R“3É^ ©Lª®Ý8œš‰8¡;–eSÓ«2 ÂqŒ€; ”_[áÎO'V;S’•3*ØbLŸãžwJÔb¨ð>ãß}Üq²ÈŸWðs B ¸w”Škö´0 ^e@¿dÖRš½J5 ü›Ñ"dô+e௳Ϫ–|Ó&H*ÿÖvL^U#©–¨Å÷¹¢°ˆŸç;”ÈÝS I.®{ZøpYÏVÖÁäÊK¶ÁòÎ’:qR¸6Ot Ÿb½Ýòt¹HDZŒ›1Ù….sBV¤' ™é6°û¤[¨˜CÇ7 .å ¶ #'þãÓc?nËëëÀQH.Ã-cö7+ì ›GŠùÌ›¼8!ïôÀ³-ûP %„'\&—Î*_%fžƒA’€€²úý+È‹ºm}ö&cVo¥ëë­ÕA°Û¤ò—ëuL(öKì0—ÅLÖíßU•®QœV¡Á”¨©ÃPâòg ¬tâËu`,é€\°%›¼ÉÇMÙÕãÊùm]œUzé•xˆ'íU›ö{.ç$eÌ ó½>œ“f‡«ŠÍ EÞ¿áõÃ] 5ЪôHµï×ÏÌ“…Þ¯ÏGÚʨ)º«íˆÁé‚ÎÍW|Û1ó¥]žÅÄ^}§å+ÞOQk9­ »%u6¨² ¿*8Æø®ÌûJ@ƒ¤âõM^R_W#j¤yLbþíWÜæû2e©aâð¬NþWÕ¤qMî÷Yø—ØZ)âslû½—U¡ÈÁ‡¯Ú.‹>¬å^»ê›Æ}F™»yO|S#}ý °d1=z¸$H¸c:yþµ[Øsäãúฮâm%Í‹là Ò%P&?9 v“Ä(28·Ý 6þG€ù}‘—Hbz/I™§¤†Œ{’IpgVã­‘ ù,„©<%¥½‚ò£3žQp€„šÀÎîd=r$L…Ž ÂYDÒ Ãÿȳ #N¾òÎfz·è}à¨È3BéÏ¡…ÿšæñÛ§âzÉÆ7¿ËaPˆ·…¸cÈžqp¿éÓÖÏŠÌ~(UU 0qøìì°GS™k‡t1-J:êÒâÑÀE³;(<)^’²Ú®úøóÊ/h_ÛT­¶!Yší¨*@ÏÏkžìY£1&43*^€‡žÁ;°þ±sÕZŽ“zçj}ú¥ª•ÇÊO={z²ñæ¢]Uù×xTª!FƲrÚk:ôD 1Ã@5G…¸ÆÂ$ß¡ä̪®ÜJ-Ýr)­- XØ€ Ö´×qZ™@<‘ôJuÒÓë†Ã2Ï(¶¢išÏñ㲨k”„ÒP:TJ‘€öÜæ_EÏ”åÛ+%à 4dXÑÙC!Y0 Ç ¹:;+Ç8VÈbÕ‡-?urxüòü̆úB4óyæw”MeöÀï”Kã!5|­=¾<ξpÖ¡‰Âë•wƒÏ0r,f¹Ã½“÷Ù9éxƒXºd3â%°“›£†TÒò΂$ÿ.ܘ™Xs>tög}rYOÁmUnÐÛ­¬’€€ÕD’§êåÎbÔÚ]«N.H™rNĦ410E]”ÄÔÿÒ¶åQÉŽs½×«I騏ôØ1©}1|!|\—=óªáE¼ÍÊ6YÏÛRÔ=×Dè¤@ò)~ åãFí£EÔ×ÅQ>—¾£”ÍJ‘µ¸¼·€1RC8Ä–VÛ+È}kG:/M÷lM·m¬@Õ Žb©~+™—ܪaÔôÆÏÜÔýì¥×Q®í‡à2ž"¸ €”¯·°–Oœw¶~~û(b.g—ÏÔh–™Šúi€4üÐyñè¿?/à%~¨(s #¾^“¯°Ï±f2‹`=ÝÖ cOk·@púcu\ ýÜ°É á©Ö[Uæ W™Ë2ßwLƒZêRì_8¼x€m÷",Ѐh‡ÌÇœ¨Çº.Ð:aÀâ€Õ¸Ë^®!è=ü¾^Õÿž–öôÝØ~4^æà2âÈ …VÔ§w²döc§©‘áùæhMV3ðü2»Ïn ÆôÕyZ 8tÔuÓpxÝSxô×8£—íª7‘©^1Û¶áPÅ'³:U#¸væ »‰¿ß=xª%|¯dÈz+ª†7JM:Õûœñ»´ÊÐãPÜD¹á¦Qs¸-‘Ÿ:‚´­Ë½š"'Ô`q†¿Ý½£G´lú)å33ØéRî:[p™¤óè¸ÕŽ"i†TlßT£g‚¯ÿ6—4¦‡ƒÙœò lVk aW^°„FÌpä|«®&Ã,±âŽS‡P%v¿‡Ðø”‰&V¬ÂŠgÕ ‡^sÓÛ”X÷Âm·…Ù¬tÏFíI¶§v= ÎB¨„㬠ÃeX‘åc“þ"„ùÉ/%ÌEFr‚@[…¥SD6@û>ïçê+À‹q{¿ pu®D‘jÎ¥ª^\ëÈVÊÙäM ‹DFÈ1š øóý™i´}üéh’7K/?\$E,ËÀc÷»ÚòÎ ýæZæAPhn=úgÂ:Ž‚”§š·]N;M·^<ì×͸~yÑ{öûbçÞ¼£È’K·Z+8õnqj)ÓFX4v*×£,¨(¹Ð i€âZE޶ÆùKÇpÁ‹8©$J4J²¢ölþ¸ˆÓ ‡bŠ87¿Ôµ ð6úSã1Ôìô œ5Y¾TXá•PSD4ÕG­\n#+®_P½ß’€€Û)‹s o?Xæ†bàò]žã¬AZ… òFÎ W ¦‡Ò=ªUîД»ñ–w䄘é\Ë­“/ï†ÃŸ£cÓ¯Ž˜ƒ“û[—Ï)ÍTJFÛƒÉzÕ¨…ˆøÌŒ3¶®OlΧnl›·ÿ‰n0þîx_lZnƒFRä¿) ¨›ç­ªe‰‘[ÜHs+ú¯ÙmDEJçUÖþ úá ç-%gA|¸- 0¹w¹|ãbõÓb a˜r¸ÆôC=„HÓªø(S¦s0¾Õ.&¤ŒÌ­,CàÒi–Îv-/VeÿZ<öÒ·ÌibüƒMÒ4¢A!kù°E¼6k/)ƒÂÐþ‚Q§:µ¾ZV‘ëë³/ôf4ÁÏFñO4‹ÃÝ•çŒ6Ï+¨ñ0¢>HœããRö*†³]­²H]›ßÅ"ÃÌ[ácð;²zNóÚ¦LòÀ!o,•/«¼mr‹¿‹‹Ê1´£ 4ä}N AžÄ8òz^@mfÊ7L¿^ÿ$-…º™b£"(¼­òÙf;K‹1ÐÁ÷€_逡̅æìA.ž—ޔƪèTö¨!ìG\Ñ㊩˰ºvrð÷ I >þ3Œ‚ìRNCÁ£ßN­ÿŸû9”Ã%$¾¾EF”´«m¿Ý™ •>÷2ß›±®< \ëñ ¯'¥ò&üjz˜m²´µç´‡Ë±Mcœ£žrP‹0÷gðK¥ÃØÇMj™íþÊõ>e||€úr‚Š ¬Ëô$Aaß‹¹ ³ƒkˆ?"Š¢³ëAã’ËÀvÁ-Σ°¥07²'aTé†jSâ÷!'·€É<Ì8K|HPh~3Úá9$1B0E-¡K©ÕçþÊ!¢û²c:™ÐF- Õc™w¦ßæÕðÕv*ÊÒtøŠI@In~íK" ËgµfàÛ7+9p@è\ãŠÑhª«¢»‘½ëƘùÊ“¶j ˜m>M lgzuK¨ÿ™Ѫ;õ~bBø ÁuÖÃ[<¯Õ'Éi­ƒ²¹õhpD! ÉouÿPFsèÿ¾·ÚòÊ=Và†ƒ(êh×!Hã†÷cg˜à)ƒÓ×DZúÔKŸÝÓAÅÚ†u?åÆKnÝ©ö@ÚBÏŸâL+›–’€€³µzP›I#$ g‰üVìÕf—žÛàVŽ0KØÛîIãDðo’âÇé…êÅy¸ñ5a:|U›XÝðœ2©E¢J£i@T)‡úá·^qÒDÜV„àX™õº´]ý.Hü›áð9t‹µiœú ñó?QÄqÚ¶œ “¯Ð¾0÷@fŸ*:;A£‰x»¤nøÛWü¦4; ®×î_ªíµ|>‰ÜéR¨ò 4íÈy°¤Î"a€þºâ¹ÂBŠ§ÎªÚïEÆ¥.Íʯ¾Ù쵃à9#èÍdm·ªËP¹ ¢Ÿè ÓE¸“ ¡1_³‘ë^QÇÂ@¾®Þ¹Í\„Èý€æX[Ùª¥j°_ŠiòcA^ª.Ýç ÚÆ!Ý“Î}×[ÍÀùøñP²w¾É ]”ky|]ðœL› Tºn¢2%!S ÜTê%ê…†¾w3m̰QžKÓOÆ•½½XlTKæ²;°‰Õ#lˆQ×Ý%?¤ÿÅÓÜñó.´^çU.wK¬{¢ëÿ€•ß8.&T—×BsÓ(æ¥n¶mlüC|¸gûR§x„ÆÍ¯¢²í86Ú©†a±?…ÞŒoÆ4X‰™]>Pµé—|aä{ý¸¿~ ^§Ð$)~N|ˆµ™’Œ?Â8,l Ã¥ôiIn }¬|^œ: ,màQê 1‹U”Ö÷s:«Z1 Ú®”§ –ƒ/|q™ñ~YÁ÷øùb¼ „Åøãª¢MŽæî¡”Ðé p‰5,Z^©•îijÐc гTØÁhìã°†³¹É¨É3Ù‡íþ<õŒŽ²øÉt£œvißA-Ì—::º ľ´ê?W\ÖZ߬ ÛVø˜U)¯Çd‰4ïWkRêEŒV“Õ1Š,JæL.²ÿ  ›ÔN³7î§utÃ/nÐÖ&'wÃ/í”âwR}Ú˜àxŒçGMfùÊC¡±ànI{ËE/j6”$žÿ‚NCœ%U¹ §×BçnÛ¥†œÒ@µ“GQØWóÀ*¾,,ÛwÅiäMÝcB[äç5]¦èž’ݶ× › ]Æt4«kc³·üï.¾â÷6õÞ¦Âï°áý8œŽN#ÒñÙtWNsµKÇœ Ã[ÖDÅ·~wî,%‚‡5­óT’ ëC=²ïuùò~®K8ïK}>Vv;&•Á’€€´ºG ŤÀ\踋ˆÜŽhÙv 'dówÎßH*HÓ¯ßö·(˜h•ÂÓ!³~8k›U¢p'4Ä€’…(’c J‡e°_û쨙]!»¤¤»#à3 ý=¢teâ7°Q £¯½˜(Cœ+£Ïã:+'g©£v080ÖæöŠd#Sž`o—ÙJ)wµÜꥧA-IŒSqD/®×I%ÔŽšJ¬Š1;iØG’Þ€a7q’Éê!PasÚ*ÔßKRgä´4¡ÒiXr(ƒ²[+N‹†ŸJ•’÷\·Ëö4íø¤B¦ÆOJó, еVx÷0 °åu£« O•ã Ï.^ú'âtzÈÆÓ€Ý‡š+ç‰ã7ÆÏBœ@Ìò¯Á/¿!Þô=¡t=£Fß½“öÜŒPe˜?Ì35—å±ìç`¬¿Û*ÇaxPÕV¶¹\|;øgŸ“ýBz{ØÈSR——AŒ'tq;ëÌp§ˆRÖRõ½á­29µDONeâbñK¨ð}ÎI=ZøÿJó‘´øhWÒÂä]iÝ¢,ø˜zS—J¾zm'˜LùgþùÚÛ¬Œ¸9‹HmÁöéû‡š‰§˜Ç#5y]j‰g· (CÝjìR(k¢“f,.åö†80þµB8)©d)¡È™ptšnA÷{O ;/Rxºñ÷ÝâDªMSÏBÀâZ¯?Åø5ª™çôrž…Ù“bÏ"ÝRHt;T«Œœ‰›jG*çìDJÖ¥];Rq{ñ"XUsh¸zõ<Øðñ;>µ–Ëñ¨ÇÍibrdÌgaîwDsþ¿¡å¸XxÊ’(^ žŽæcЄ°*ù·Ìÿµ˜¥:Ã_Üe[éŽ#ùݲA· ELeçŠÔ}é“j«1!Q»ï…=â+t¤2ê~øòI:¬Z9p—½ŽÁΧUÕ²Œ¹ ë zy´/Ì@.Ð3np:Ï®Ñåö™ê­ûRY–0&€œZè»”ÚÔd¶¬²¥›Oµ…¢ZÆdC#ÄaÁà­Ùtß–ªH²änv¬ pD¯ÁÞmW¦;°Ï¸pº:ÌÉ?b âA^£Z×)´fj']ŽÎg‰ßé‘5¢’€€¶ÄÁº¢±Kàð×bbLBmf§»UÞ¥ÔFíì‹Þ*ÏÏ ^R<6gÂyÇݬ²"ã³™Q ¨nÜXL–x>¿afì-e_àƒ©®ù.™î÷EËm8JET!Zd¾ê¨ü RIR5~®£õü`_ r;vç:c*@ŽQ‡fʪ®u: ;ì³Mzãdz‹Ê¤dR!J å9¿!!´V$…l&QQŒ(Yf#÷É9°@€ «'ß§…¢0Ôýžát@k¾\YwG?R¼yžÑË/¬^á>Û´Rä9!HÑ*ܰ£é@Ë OÁðØì€ç ˆÕÎÜ™ªÔm€A)YBN—⟣jœ\F#5ß?vøì5Æê¥‡sÍ-tðè#Uûǿž:·ëExc1û¢¢Õ¡‚´³‡ŠÒꚘvx×Ï[Ìí¸!D Ê…s‰ñîÏnåæ~ÙÌDÅ^¾dí]žŠ=yÆZ“GG9y{vE‡#A¹åæ”èd*5Éaôºï¿JŽ *öóļjtõþ ”«èBŽ0ÕNGùQó]Åi3V¬™Váu‡Òï»CðdâÜ_ò«a¿EQG±að_¨ÂL¶-ýÿëÆÃ8d#t„R°˃ ~ª¬î‡°cs¥L«üǧ:‘¾°> ©tÍD¯R#n•èHxø0Êx æÉ´‹ ýEÎú¤ã—‹á‹˜‘÷öõ|™Ì´ÖL\h¦Lý9Ôgý—·‡ÀÖAö›fëéàÍBÌe¢Èt“¶œAùɨmõ2E!ÆØ·±e€P >ØÞÕ¼''ÓœQä ¹K%,¢qêF˜»Å‡úÔ«£¼Én Ë7Äi—¸ ¶™)«#A³¥T¥0ëEb0Œâ®Í]—Š®½r¸÷}AâjºPQŒhu±»W’WßçbiÁ2Ho™ú7¦ ô(Ê]pYôÔœoæ=7}SSV<¡±™Y`ø&ྲྀÅsüldbYÜs‚æ¶46q·}SÂì Mêoཱ æp¨ï¡¥/—/TX4kG‚CEj“ÿÍ÷{ Ñ÷ÞÎYâev[àbeUžZ¿òTEvÛ‹J•f‚®ÖrW5 å£Ê­ ÍW·ó‡4zµE®šÑå€þAm{«óokz^üô[tE¡«›IÀTóµ’€€Ì$ç“T‚êuZÄ/ SU«ÄØç@y`·Æ@6u°¿„aï(Êg]–{Ï9€Q™IÊÎ+òhN¥dZÒ~#‰* MÙ˜™Êœôqãp¨úa*ú‚qá^íŠ?whE5‰ÌÅ-|šÔùY¶¢Ú䦊¶’FàøPÛÑ¥ÛÕÑž!p61ÚÌë1<Ùƒ†©åúOn­Þ±?¦í÷çàpœl~w!¢`Ä'Mu#Žæ~·Æ*]“àj.ðxèØ;³£ß—üÚ¬Õ²íqãxaŒào©DæÔ¯œ¢Aã5¼¿ëxZ£ïM¬ÆJ褵’€€©TÖ6–{; òñT>醴-–€ð9¦·d‚ß²Àûð%(ûÃPR²m\û2òy#fñ¤C‹7Š¢4ù« ªn®%ÀWuÓ3eÂEQñЏå2ƈå"䳌ÄcŽÈ²l¿T²$òÈ| ì Õ ‰¦ d.‹Âj×ñ$œ7Þ¦ì†|²)cë0žŒ›ƒ"ùЖ žŒ†ÿÈŠ—,XÏ=àÎ:žWYv£iÎÕo[p¿ó ÌpÜS!‘ân'K;ÉB‰76OøóJXÏh`ÑMøÕWÓÙ‡b½ºE߃¼½×ñ‡C…o2I[Þ†èŒ3D‡&ZI¸R¶q^âJõµwëùºE?ÇÖØÍ¬G£»s‚d³ZöÑF´„À:=yf±d.†MDé WÊ[ëè,ÂôÙ2 ½R·äÕG 1~öe‡\¢¦L”Ä•2,ª’àf¦Î:9”ÀŸ†æ 3tavµÐLvö6äô{d–¯±6|Ùï&Ì9 ã©ðrûTþ‚Åì_Ñ(û$ˆ€£LçÕ †x©b¡ 3‘E6¢ ÁI²/ÂjªpÈœvZëKsB>íyt)¼0×I]6Œ`𬺿@ dňË#–Vy¨bbAa<Ù¥8RjÈ¢ C8àù‹*\”œ%±K‡xäžÿ—Þå·§éþ8¯Éb„ËKÙ¦jþÓÌÖwxo‚¯dœ|zN[‚Ê%$äg#%á ª7àæ©ù…Æ®7Ð2¨FäÂK£Ñ›àvºjA@LÙ0ë/°Uï’k83)Öã"WGìÛ|°'znà óþnÔ’ÃPcF B ‹Ki?Âzœ<©­6#ÅOh[ÏR¥̵,¥54–.Bu{„ãX˜·5$þll‡aÃ(홆tÄyýôp~¡ ÎÏú<¶¤fZcM¤L¨Íá îåZ C/ž{µ78?…­„”£9ý2PÞä$/ø¶QVœNX¹ÏçohJP½ÖË2tìϨi~CÔ3Y60Æt€ü»#5ÀHæ*èg„Rm|ˆ7”(zÞÜ9”ªLd Ï\C¥øc®¾›ØóSÛKBÇOì®ëŽòaD…NÈ_𘙵2p®ú¶èîÉÒ@ìm•2û™Ù¯ Ÿ‡–­Y×¾Žê9U›³h&’€€£ úáÙÑê!gbîÀ­*„w–PÙÜÉBÀýÞý5ü'¼f8ÂNûiEát½0CL·¬géüùv¤S6ÂÃåû(Ç áú 3qøgR¦=àÜϧY}ýÓ·dLÑYÈ]™|]ÀØìú^!ÂÃcÃ<;UnŸ]š×/?¤C–áB!Ö¡ãmH¨27ßî¨'¿ ©×=ÞáÜ΋ûXlâݤB¿1§XÍÀÌÞbV2}>&Î4X•³yvRå¤VšŒ¶Fövë ñÂd'ã|ø¯oî}ô¬i"jWRü„˜U¹ötµ‘ƒoÙðÓ,ÊRF``쯊¹Ûc®Å3.ÿýÙ¹·[_îûåˆ5'|?š1–‚È:xl -1XˆAܳv®Ý0ÿs*‹ðNØóÐyóÿ"´å$Íå/6ÒŸBW‹QO\¹sçÒbkœ¶ Ÿ;‰E· ó›™ÈÒ`°MùFʧÐâMEGÚq²ÚÊEBv¶š6ÌÑxVÑûjëLº˜ë'H/TãZ’´ö!ž¼ì`ä—"G½Ù©¯01E îK†÷Öä÷Fv‰Èª”wVwúܪc-Póy¬Vxíyày‹ˆF»jŒL€£bê×zÓÖˆò©êèg”Ú&>²Ö:î%KM>xáfmÂ/3Cæ°p:lŽH•yÎ1Óâ9á\òªÚÔæôaA~\Ñô¶'7k0¯æÏµ¤!k(è{§£ûv“ÖžjÙRÒÚâ« à0±Mroè«[±i¿(;öh+d4\ôh-M¼~Ð5ù˜eS˜“~ÀqýzðšïìI Ôa½ùúLÂa9¿åݹao»­Åâo=øQœ_¦ôm}ëBö™»ßDAð9'w#r"n8ç×iõÂ;…Ó T×Òr>ÆsÀ¯™šüoá±rçÁ©VV•Í£k»¶³3&h~~³GèVçô4y× õÒ„†%pÛ)ÊÎ2‡µ—5-UÌâ‡vG1÷ Êe<ë‘–±µ\ëoK+"%:o/“Lzâ¶DÖgLŸŽÈŸ]޹#µøÌ2Ÿ<ϵ®é< Ú«>¶š÷^pqõºáé¤7V{­ž(FÎAOª 6äŸ*B¢Éò¾cëXñNötèÛ^U& ”$‚SL¶'ËÆxò3§Yz¿rÉÏ<ò‰ç .a¯[èIË0 #Ë>Ͷk»!ö« Rs?b`‹݃ºù?”ÞÐιéVOS^bü$7xˆäÁñ-í-xôŒd±åÕv/jv“ö4Ì X|Ô[PËè¼3n!ŒáŸµæÿ`Jd`¿ ™R£h’€€–QBu•¹/¿Ÿ«_"7™ ¿1ôårÒtS«H²,„Iöj)^¹÷]‘Ž4é`åã||¬"S:û|Å B»V;¯ §ÿ[üŒeR‡=×x¼Y‡EýÄÉ•“º’Ÿy œÕDY¸cÿÐc—_nôP„ú9êÖúNïæ• ÅÔâ<Â7 ÁC)ꩉ«Ë<>„É— >E 2ÿ ȼíEëµ4”^ú× Œ’Sõ… ‰<ñ„B)¾AÕ¢\¥¶¹½MÛæ.û AðÎHì›—C*uâIt1!·É‘]v¿ö @·üçneгÐçôƒxBîiÚ^é&ç <‰På)à(6V0ÈEƒrâ™ÃxÓÞ¤ÌI¾ª9Ï0K›„gRy‘Ë’ôO„Ô*: ŒCµHO‘ÁlžSV8œÏío±”púÂí¬ôâ”Id€ÏVÛU|’í -ÀMõ©4e5ìYe‡9 ¨I¯¬sO÷G¢ÏÒ+³ˆÌãfêHˆ^=z c«;“"ÍæHÜ%‡µF·“ØÛ·e8 £Å#xƒƒ|a¡‹òæðt=Ô8è'BËq›!ö—¤qôèQVdãü-jýû±„EÐÐØ1YtýÈÔÔ±¬º;âÌvØëå‘£]v~F[+EoÅ}„ œíõÇôÙ=žÊš¡fèsy?šöÇ.àû”ºH´Ïj÷º]?o}‹M»X;ÿÝ&ÂP/7‚\›äÿó1ìå Kß´G"ëƒZñå‚’µÄɱø¨Ðmˆ”ž¤±ýY’? Ë_tŸì7Mð9~dÒ¾ØeJƒµÿè%²¶K•”’å À¿Àr½#æÒFLÏ"œqz÷ʼ¥†™Œæ€=ãÃÊfJe{Ø.NçaV Ô›¶q#Õz2€áY®QMY†µaòÙøqyþmÝßœ¸fó[ß9hØÙìë Á).{eÿNéGuu“¶V'¯¢u4ý‚ ‹ÌžÞ®µÄp`µp TÕ!&ÆŸYo‚† ûv¢gLJ2uÓå]GTð¦ÈIn<ÐgáL:na“lîÅ0+B`CP‚¡k|°Ò‰IDìðåkv®ÌDŽÏÄÑd.¤-Àj y˜öý#Ó^’L¦cÜc(ã¸è¢î½s,c{VbhvX éÅè0,’€€¸ókZ ¶î¡²òð¨WBÆ£úBã–ÀAÊØÃùDj õmü]‡y€>ïÞÖú`}ŒZšmh¼±!TjÆüç†=»„=iÒ Ù,»ÕT qI¢%ž_Ì˳ó|bƒ¡R›­8Ktë Üž ¤ö 7‘ÿ"_Œ¦+­%jÇN—U«™l;4_ùã;÷ãµØñò©w~øÊ>LåÜž]´Ù&Ìá*Á]c#š)\6zЕ¾ÑÍçî0Ú· CÑ%cø;|øfÁ+bîj…üU/±M®ÎåCýg)”ã¡$®'"2©OuøàÔm]i§;õmjmÌˤœ¼•;ÙúÕÖFZ+ýovÒÂP¨ÅÿÃCŒE²t)Îüøl~•“B›‚°7þög£¬¥èˆ4x‘¢çA¾SXŒº¾Ñ‚§­;¹Õ\ÙõÄꮑê졈$QV)RµuýL€*qã~Y%±¶ «W¹¸Wewô)K:Pþ­ Ó¨¢SÔyD¨[ð‰›3µQcáØ’7 gkœ•Eçom¯Öó)“.)õ¿E¼…[ž_h´® *ÛÂ.[nsÉ| ypŠÐ–êlO¶¯ƒ÷Èd@¤•~—m‚±H ŸÅ^¸²¶Ô¤„u1Ñ2‘Úà•jn’v‰ƒ:ôb؆´0¶ˆm•[ˆ8‡*ó“ŠöQoD%Á¢ÙÛöEo·¢Ÿ\ àÿ1N µ4/–rfÅä#qTòMŸ-eªœ=)<Ýý &9f[\îß[ëJ‹OQM25š=që#c¢ ýšm2û¿Uôo{µØR=ãpa>æÑæ)BÊxÄ™‹ÉZˆ«¦“DËÒîŒoçäñ™"ߺvq.õn8•£uÆþ°+ÌyŒÔzÙ¸‚ñÞÉ’2tqÛ®{£>ø›A/ž qñ›¬âóù~ÏžU)Wð¹vïu¸ó#KP»Ã<‡Þ*@~Ô•]\£ã¶®k´ë+(Þ™ì7@5âü%]íì°Æ@yau÷¶aþ5SO'Ðë›ß´jöHñé©e­>êñÎhøèÐZj8Èê\Ž@‚]×Î/û\bD›¿ÒgK7eó’ìò°¶÷pOŒä<ü—Ð:­lÇ>šL(Õ¡7G»à,‹ÇØ*…û”×€žp’€€§³3©XÎl`(VC¹<¡ñcu. ß8ð+¿£UzÞhFvŠÕdçTÈX͵v,É;Ð ¡Ö0TI¿j!Õ.*P$y×Þ ºÛùìHã>\—(ËäïÙ,â û²©$tßϳ'±‰¬4;I½^:¤–Ù¾´•Ãë.ÿ4ÏÇŒj‡Ù#ömúÒ F¶ˆíñ…*ë–.üX=ÀŰ›u…Ô6 ÜB®‰´ NOÆ‘M’Vq8j¸´NžøtžSO”'É¡‰Jq„~‡jµr¯XøŸ¯KŒœ–S/U·.b =W’/¸zŠZˆöí:-ºÅňͨ ¯£µïné¦%n–½6Sͽ¡³ø)~0†Å¦æu!£VÃE÷02Ñü×j"è êíB3×›ZD‘?&2^³«'ñEµì"?A\›gý 6lIï^Èo_×¾¥||ö›°(í¶í]Ò…î@äÅáR•CÏÜzê“ëÈ/T˜•ÕìÅšá‘‘Kà–R `†P®kÃJ¬f×Î(<jÊ×ÞîweJEÕÍó¸‹<«‘¡Ï­Ljfx ´(ý:*©H›s×Ãß;&?Û“¢›HƒOªÚp³gÁ,J’XûÙ›2˜Î®XÆ~XŠ'Èçþ ‰½§´¿%‰‰¡$·ÌÀn_ý0T©ßsqêwi¤Ú5Os$y‚MvDæ˜e_X‡Øè…N€¨ž˜rÞ¹%¿°Y&ÈNï?-­°ìâ{1ZÉY¤ßâZ‰Ž¿’€€Ìù*‘šö<†M@ !gÝ€ R­un¶dLòŸSæ-qÄÞÖ“fοóߟ c‡|—¬‚¸Ö,0î†…Õæj¼ÃÒl™XUpÉkAGÎi`äg^N£N4Öºˆ›Ž&µ…çTsZ™ð‘-ö›†mn>x;Ô¥-¢þ ÜÆ1žTj}劧y¾—†GlOàò1áS˜D$~IˆpŽ×~­R´qSRñö•UªŽÒvpÅHmݹ*ƒ—Y—><….h… C÷¸î{~Ëø£—KƒžrÄÏJÏ‹GÈÿ®QWëE°ŠæhL>A⤘ãd>«‹ÞÏŸ\Òò€Í×Âû¡!¿½‡/8ŽÌøe|ðàxÿ:)_§U¨âß%it€à†¤aÚÁn?zÖü"wÍ 2E×uëKb¯s¯Ì³¸mŸ­}7t7vbÃ:àåcÀéh€Ý!ŽC?Öç—&Æò+Y”“§£Mo»qÉèù¢‘¡9«Cc%œ«šˆhnIu\t¹`Ðÿ§ÐÑ ¿ !râöÈ Ø'G1f/sàñ(Åoñ›·JÊµŽ®¯oÝÐÞ÷ë?ŠdŠ(‰ÂW+^±1tˆ•´=1Ó‘[¯œFE©N×`ÔHä­5ä²þN´é%1 ŸÔÐu>Òº‡¾lLØF]þÇ9†ÔÛïWˆ©/Í;þº€,P8¶•¿tGëè-ëÿ#Õ*ß¹3{ßr7èì@ BRXùù2hÔåÏ„÷]N½‹'Ú׳Í<èG~ét…P~ã…ù¶úڙх(Æ ß·Y<À D_ƒÖ úßãŽ!Ä2.¤ë1U$û³™þþž²?+Û 2QƒèËé`¿×š¯ÔÍ‚ýäŸßš÷Jƒ½'.ìñ¯B¿}×!¥‰ïvX£žÈã1ã"_vKÇà]:G¸5h&X!#LH•TneªÔ¡“6¸”'0Κ3ž£sm±Þí³&RÁ¶³úÍNÞwº§Ï’78LÁPØHí½—È·jÎ5©…X Äà›6fkA,Z4ç:<ÞîáÊ oQ‘¸ AÙy-«1ÕjŽè-k^z¸4‡¶@Å—¬{sVÊ´022´ÆhµgÖu(ÙMï„9”ÏÓ-mxî€1˜\1frÁä™û¶è:Ù«øÛw½e9)—„芒€€ëaUæàrí>>5éBœvÞuÕ€‡h*X‹ù?Ôo#_Ú)º œžÞñŒÐŽ·<¬¾¸ë±ÉE¯aïvP1ÎÚ"þÐP›¿ìé¼ßù†eêÈ!MDasŽÕb¦uš‰®3Ì7³Ýi‚‘Ò×ô£ïwÞn~§¬2] ÁêS ×|AJåúƒn8º¡ìÛ» ù'cç'"¬Ä;ÀH™ã«@&hJ¼‘tK{¸jZ¢®Ò«5ú:ÈRëüØprc\ž™G(En€UÞÂÁø“á32Ÿ}"ÙÕ÷¥or€fku$9 ä“Ä…AP9d8ĬœnhÙP`S Ë1ãMœj“%eõèjþlÚùÝçÌý¡à5Þw!ûpYùfB…_o¯œµÌc>û6¿/zËÿ#òkØQœ~ZBrCå;Y +«…RSõ©ž¬b•‘aŠp ¯ÛhŠt „ mÆ-¿ýsR3aœ¥Ðæ>G4(ÆìØrüúcwBV‰µXÛ }m’KP[L8Úár!ਠàÀ“‘µ„bä÷в1—ž\@(~(|¿Å¨>¸‘ß¿6‚Ïq[,óö…î©Ñ Â[–•äàÑà•膕²'ôlïa„™†oìõÏk›(ùì›N€xUf8–ÛkEß&ÈÑ,µ*óŽaU÷T0Ñ ¤?FtY·gòÔñ‡%€DŸ‹{+IMÂ~dÌi³—ÝÛ‚Ú–«uðÖG>ë&éM¯ä6OÅœÄZ\þ7WÜ®UU¥å¼:¤Â“þÄP03E\M©Ù¸±&dù3ÁŠK͡`.óIgì‚êV,®×ó¡çtµM-¿÷±ø[…Õ™Ïý$j;¿º¥s;yºÆÀvÕœŽïù¸þ²mW«í7“¾¼ˆú¾1 ÜbŒÒÈ|ËÀ>9`¨wÍc~¼àƒÖpuÐS©+Ú¡ýú«[OšìÅOñ×…û'‡grÊ«8ÐRéB$£ãÆa[¥š„ÝH¬Á’Z/.®`twnëŠ_˜Ñ»X+î/_"óó¨:8® *”Hy~ágãÿD¬€ìSvý/1ôªì10»¿ì©êðѽ4± õž§ Ö­ØosL¼~G¹VÙ´í†pÆ»3šÜc~Ç¢g¢XxÅçæø¾d|[m¤:’€€›â~PÍ@=3Ô’Õ­y˜-˜Ý“_'Yœõ8ô©Ú£2*å)'nCqãéC#:Jò!cØ¡Gÿ’÷Œ° »|à³áŒå³f(rÿš±ºѹæê KUg2 ]GéßlfÓ vwàðX®}€ÀORÌ·s|Šê€‚#´ŽøYž€^€’¦¿±º) á Ü76𠛬 eÁ=ÙbÊ•×åóњɂ§Z7xkw™Æ!Zíˆ7["e{ä4òg ´×iâ*ëzVÚàL¯ôÖ‚Üæø<8ý¯±Àø&˜Žk˜­˜È#—² Š¥çH%E:ñ‰kª¤oK*q§MÊ:+\eezc‹÷à>j¾H¼¡ºÀžH!¦ÖNØ®ƒ4qv<·§_ºagr$FÅJòJîï@šåÍ!A%Êw·Ý“ù‡¯XáBØ1ãÏyòÃ+ë½á|œéØ­¬Ìc…ø)1Ÿ§;JgóÀ<Š ã•lC—âéÅÄ?=ÕbGí²¾Ydž¶æ9…â'º·u~çÓÂ&|gý²ºh8ÞÊÝ> %òÓ•çN\‡È¹qôcûÝŽPÇá ³žD²"°%àa -šÛ†|À¼6-eÄAž8ÖLSš0>ÙcpƤ¨Í˜ûß&:¸p"”6JL춃΀óÀ†}åŠùô¤Á½~*eòwµSäxuFŸ{ë‘WØ›>'ZžG?£7½™AíÆñ¬–ý’0oÛéú¡î‘Õ:æ æ-ãÕ¸_ž¬¬îÝ’€€½>Çÿ¡T…·AØGló¿Ióg!Úr¾×zz€µ¸9µ5˜"tÑçÇ*·¼:> ó€º ÙÝùP©“ Úp˜C@9tëÒ¾q!nj僡„€ªY º+õêù0Zs‰K7±ùG®²¼àNT‰hʢҵ܇/Û4&A:ÖþáüãÇ3K%q²( 5˜xª—üë&dÞ.ÎÕ¾÷ÆŒ½øaæIYá)nôÙIsö,E…'ŽØS%æWj_¤Ä;H¿W8Ï«ƒN Úè»/%­ÅˆmÆpŽ9ô³í7ò€Vó¥Kë:WÔWæ Ç 0\ ýU|ÎòHùe?Æc{(Ó?²P²\ѳ‡8[ƉÒAЬF©¦\roôˆÝážMTP(Ä ¿/å4y}5ê¬gÅ¥å˜È¸»Ë Ê„†ëÀGë`$ˆ¦IïÛòã%g’€Ä´Ú<:$þÛ¼) ÌÃFMž›ëyXrŠãr‘ Ò1|/a½! kÜŸ<ך¼w}¯¶‹¢àƒÀ…ÿÒéÔ±!ÉYLËFŠI(k¨B¿gNH¬ò'ãÁåEmD àçÛ•Ã)/h(Õ1é¨×xãƒÛ¸üá8à&q:«r¯Ø‰Á:ÍLVý"?ókÿòt9+ÓÒ-#`žÔè;äév{?Wƒ…ˆÏoâÒÛåù!¦+ýˆ¢ÙCÑì[ªFhâ&Çö8 ãž˜Ð^ŽEƒÃ®Ðõ4Ù û(`}«ÛDÕ|…!J2e ±Þæa£›o {ϼÚ"Ê”-¸´ ñ–Ǥ /‹}Aê¯áýþ_-ý!édìÐ\4úû¨Î“Zè‘&J®]Ȇ‚ö¸çUD™Ä<žk»éIžú’€€ÅÐ$oZ¾ñ9»3ðÒIq]³Y½88fM8„|ô¶Õ‡Gè:Íg‡g ™)ïò:Ý罂÷ß;Oß.‡¥P³#2E¼ïÝ6¿–ì1ÝB < yï]ÜD‚´ç˜s/¸ O€øE-Ž­b[ÊÊñ}BÛH+ «wœ”¯kò¸Ñfe|[1rÐ «]½¶,×7ÅÛ$ Çáü`L°û¾²Ð6°ƒ¦x~ß„æ‡F3—]D°Êæõ-=,»YîÜSïmÑWkçÜ]Ëcg柣NËÌÏš sAÜË{bÚÑæýðÒ}Ú7­ÒM¥fEðöË#ÐZã`ÌÒ«+´¦7‘p­½ 9Ü™¿õ©ÿmIÕò«´ÑÇ:9%õe3ü¼ÈCzšFtá™X½’}eÖ2f˜ÆÒL£å*2ò55oQ°S#(Ï^Ñü-r•õ3‘%×U™Lú›@ߟîñR'Òÿ_vŽ<'@Q€Õ Õ=;»âZ Ž¦yÏÝINÉb\àT×t¥è4YŸ•0·bf˜liYÁžÃÏ"dÙËcñ?Û“qþÕ¸ æ!¼gmý¸åÅø‰q´poPÂAÐP«ìKÑ ÀÄ÷`e•?åI“1U¶#î€äœoVè…™¯‘¤¸C£²Ëh™NP¶l‡cXbCp]âW/uâ +ë.Þ‡ž•á¬)sn¡Èq¿IöyPéf5ÈÀSe‘ª\¶ ;Ïáò¤ç¤ŸUd Ây"é0žÞA½£×sWŽ%û“ˆ—ûúf.[¥2ÆŒÿ…B‰dð2´)ºoU7j?úÉËÂòn ΄y«L='ò*jñ!¡½t)2àçà3¾uâ!˜ñoLOmìò“Eƒ%@ðųgì½ Þß ï>rÄ´*ÄWî]ð›w kÈôøµ—ž/q—¼—ùØmrüª¼ôº¸Y°±æ§µqãŸ+#6|pQ CþlÛ:³«œm™ð©Œþ»¯fëüo$mnAY˜¸ÈÐû!ØÓ» !ÍÊ ÒY45/Ùé&ì‰õÏDYÔ†ÿÂ+äÅ ·ž±yašìb´^uOzTÅÖh’Z#dÌ«/fü ,_k~F6‚ÓÎ/¯V€IƒúŒÂ„>«Ç…ÄeD5þ‰ƒ°ex"®±Õ3*´ËRe'i!ÑúªOéÞ—(À$/ù Ò¦!e›¯m±Ãcáœ{1š|ƒdÓ9¿Ø¬õõÃ.©y“a6cfó“)?6»úÃ,J‰5þp>>/LPÖU.a4êoÃIlô¸«›còtd×é››[ _ÙãúqÐþCzƒø3‹ ÖÆPj¿Èv»EÇùF_’˜ Ìbª…sR=‘/q.†–;ç¥"ñ(ã<;7Paän&eÞW+PÎ#VrV$TEعúc&} Øq.©Ü\¼ª%ëê½ «AÚȾD¬§-4«Þ`ÕrÑñž1ILI/Ž'ØOݽ”Ÿ ýÄÐÓ¹ñÔC¡6–¾b’fJ«ùú:¨Æï¹íœ±ÌA^—þ˜îÆò¿ ¨©+C³ë\ª¾rГæ Nú_$ôe’6ÀmÍ6 ˜~ÄMù¯Ë•ìÙg\þÍ È´ËGpÏœêTÀÖ»ê<äµô@¥G¼ÿÇ骨ÌzÄT0^ôv´ß­{*þ ö ¼ .aMî5МÅ1ÿaUTQâì¹»ÝÕîm†5&% Ëâ²ò–ÅHMÏ]òa€ÑÚE€±çxðN´—y/f¯Á®¨ª~Êçmä{Ñõ.™lq$žÛk[ƒ÷ò×þê<457xo…×Ü>‘Ä #¦šM‘ xD~®%­­_.i®ÇÖsfb˜1{õö­A&*Ú× ÂêÏCmÇ$8BgõÕ×suŸëO„,÷%¯°áŸ-ðˆóésh6bàá1¥¾›] ø=‘‰‘ Ï”ÖÇr¨b¤&!†X|´‰'`vã÷yu‹ƒcîÙPϯy£ãì(I¶ÿY‡z†—’€€¸U#Ï_ëÍM‡%º™tžh¿oCü8gV=¸-«9î"ÓøH:Ì]Ã{X´T°L@»åÆ=’ôz˜©à‘eõ¨³g0xò0øv”Å(j.û¼ÞO¸ôᨗå„–bŒöÇ+K¡¤Ž°„D¡¡$‡ˆ`ÌTe}=éÐÚꬆ`:Š—WNÙé†dF—‚_É56êy0í¹i]DeÙ3ŒÛ0tÖÍmP/ïc ½¿Ü;ŽÂÏ÷¸…E¡u&ö¨+¹)|c…ÝÎh@µ^?¿hÊ娷+ÞÀ¾Û¹aPí° sgYÉö”W¥—4Öë'ØRDØo°Ùá¬`˜O[F¸ÑëeÞm…}KbÔ5­‹Õ%¡fdU¸yù^² ¥ö– Ü´¯tçåpƒrîÙ%DÛ½7M&^.w[ó— ^u?0ßG#]¢¤ŠÓFöxœé˜z ìw–©ÑÊ.çÐõ~A·Ñ¦4§Õ›õ(OÂ=Þõÿ$i8áŒöÔXcóçv²uÃaø8{« •l¤ðÀ+„à¬Uܦí4l.hóf±,ž3P¡dbkõ’TkG·5f&2`N‡0ÿ± j¶Ò?Ûz)…ĪÄ[ øÔÃõ}4 ,Ž>uîú±¾4"ú]ÁÉð²ü&æ®Ë(ÁW¶oÑæ¡ä<@B-ü@B;ùà[ç,(z•;¨`á{›WÒx\ËËl:¿G¨¢£ @å]£Š^Ñ3qÀ©g €=Âç6­£Iñ›êêj]È9u´__ÞM¼w„Í'ååÛË[v†O7-º.åÂaž”9;¤NH—ê¼"Ù Ž_΀ÒgMùÊï-õÃxJ'½”ÆÇgr úJë,nîå4!UVÔ¶GûFÁùXä´ ç‡j@¾»l…t¼,ÂÌv.)_º„VQÖp¼1Ž2øù4O€ºEyA¹z!Ä)ò¬ckëÍöTOxô ªŽbyó.Ɔðׂ¸ˆølÍ€¢•S—Ü\c¿ö6Œ7Þ‘ÔRŸ3=¡°ÙØG”Süù"Â1zÅ®#x6/LŸúõ·j,r\拎<ËBãÁ‚ÚaíòU’bdÍœ¯ñ´ (5ê‹&ÛßÀ÷ýÔ³÷׫=þÇãIK‰‡Ò’€€Å¢Ôæ_+&hƒÓ"tøW¿~óÙ#‚ˆ–F²8 ¼ ŽT=oyB®¾eì¦ÏæË C½^‡:™Ýt~€3Î÷<™råT²º_U…ˆRý˜­óý²<­z§¬ÊR1þ ^5"Û ˜Ý½?_FZW+ä¢ÜÛ¸qâól| b+,?± ;7ްö M•rÿ' Vù2ݘ‘Ú ¼ðÆ ¬ÖôÏÞu3óB…`08¼T® ­Ÿaçpü‰ˆnV·‚È@£©} rД/ÈGL©ÜšÛ"ç9Á+®ñå„$?NúQ3.½c”ê@Uó?óàm9+ÌŒ·ÛÓ'+O–ðè½ö´`ã [7f££7}x)’e·âƒQÑÏsªü”k ›XèI«nlžÃ„¯7Ä/kDázî—óü¿§H(úËp7ü®¬v0Öªþ{»ºå.:, ¶¬ ¯26j ådÅ6†6ÁWå7Ó)Sâ"¸ò¿† À|¯•Zo ë`NñigŠœ*¬A˜Ÿ¯yBcú›²_έÜlx_ ?&KÃ̘ք²àÈ0VÖá3ä~€ëÔŸº¯Ô,‘Ú© ÑÆDH¸ÅÄbw¼UÛ–êéó9Fž`za oD zViGá –_^®Š» Ÿ!æçM¸ìýåµøb¿Ü*àcB-¨žiX<½6Š«ñâå>‹Ô ÓÑ”{â'Mõ@ `®^“%Ó ÷σmöý½ä…ÿ]‰A©]àzÉßøD2û¤oLÓe}P,ŽÔwޱ›;O{ ÜêÎÙ¹* ]*Ÿ ¬¶áï%ƒì±åk¨“‡–TË·N3Î5piyï’6Ý•šlc^¨Côõ!œq$SýÂ¥xaxµ¡ÏBcÒ½çl°§nZЉ%åÞ "“wfõëöäz„“{n†¬îVDü¾òAÀJŒMù󂲸2æíÙä¹)Jð×_¸+þ;==ë½ÒWf”VÝCq ~¯`Ÿò>Æ)ïmw\§ÊKZYUå¹àŸ!5QˆùÒ3…0ÈEj»­{Š_*seþ&…ªÆ?¨¿–Ð’ N¦åŸ†à²2Λ÷¢ÞÛNCì‰¹óºž  Ù`Rq…Òg)±GQzî*sÙ‘6§ˆß÷î6ÌÚü´1œ{€5ÝK2ð ¡äûýÅ ´™¬mTšbr51ä«—»,#×m±M2ŽEÕ„(iÉ» ‹ÄO‹!ÿr8\“&zCŒìCîÃYš¨ÖôÿWIt]Öõ‡ý‡ubê#k?¬mÛMVe²ãá!ÓéCá+1:%Úbšî-éçf§ïóWì C¬¾‘É+=bÿ¯~Û;ý°ü'0/YDXmA ó'÷“v7'¥U<5;èL/~}yÖP]ûæÔð-l.6æ;ŽÃ¹oÑx0;ñ ›Œµ3}Hmi±:ׂ ½gbP{°«jæ¯6¯œ9ì¾^¤XR(Øšk¹?nò… ÎÈF¥~¶Á•~V‰)e< #êæ’³[öÄŒÌüÂZg÷P€$èzºÚ‰‚¤C7E#‚­k/—îdFÇË2£ ÏŒ:`ÛºïÞÎo“©Û>2vÄ2˜ÁšVË`fœ8o¸¶Z^lH~r…)ï ™Ø©Þ­q®ÏóA$¼ó‚7`ÓѵjßÓ|ï,0Õ».i_lÉÉ¡² ÁÍèmZÍÎhÛ&¶ˆº<¶‹O’’e Ïž€åPî¯Î%¡®ÈT0/‚Å\y¨/ýÛ%âÚædÍS¼¼éø[ÅÞ°Ÿt—³~C“?ãÀÕà­ð™ìkpróÊaýƒUûW¯_¿õ€¼l Úó@-'ß(:¯÷prm<“õz ¼—"T.TªŸ2ÍöðB¥Ç{vê÷]C+WùqïÙÍJ¤ðçFwÜÓ<˜Ü ø‰{Õ$í¾± ÆΙª¾¹£ ­T‡½zäÙ0ůNîV×+»3>à®cg[^*3)6v¾Ceå¼vã\³Â}” WËLñyØ'Ö‘>…sˆVÃÌ™mBŸ ï^\¨?ó"‹1 ü:Ü|±”»ãw–gI´™¸#œT—¥R%Ü ¤ ÃÔ—`/pcúm{óžGÇ£‰":¯õBšúĈS½ÃòÓ†¶ç[¿Ðy¦vYø‚¹¤ Dæ2¬¥Ÿ1e¤KŒF ¶ŒÞçÄÄÁp2£ÀDúBÿ–ͶçU1U þÞ L­2F™+œ>æ7°üy$PÔÇÁHçŸÜU· .°>^b9¹á9"þ@öB0@¦MÎWк-ÇÛ«§Å;TØҨɟˆW5³ø¹Ó2ÎŽ"oœiTŽïí:gC€² T ò},“2óŠr9¡ø”dÃq!tgÓ—q(®W´¢—g€£ ºª åûM ëô0Û‹fد:œè½–ªÏý bëêN"´  Õm;_T*¼É/‡¨MYJ¾ýÒ»I•®GçYà ‚‘G=Ç WUþz uŒ×Mx žº>¿ž $ànrš)"³å·ýã] W €iñ¡ˆå'ŸTþìðìt[í©hûcÍí }©%DmÅ-¡~O—Kô“Ì’ýA„[WD4àÅó™ö6sÁ„a ˜ˆ4×[蔺.žcY‚Æ&tÛí†ÖK$y4q{d¸äôUúdy0ÀÂ=:ñšœl~uá3‡­.³0 é FP¸4ÿÈR$ØÊf*¥÷½> á\@þÙÕ±Ô,¶ Ù¨,7 Ûö:ù&ÄÜ ¤üð&™¯›™ÂE_Æ8Kצ*»jŽ\ÅG S/¶~ä¼’€€ÚÎ "Xɤ n?­5ZïÅÜ­âÛÇ ZªÒS܈%€](üŒ%èzÁ}8º!&<³ph ‹¯L0¿ùSgVJóòQýZpÒÒŸß|û +;¿¤ÏìizdUòá‘snG;àÜž_“txqÕö±h»/•onf¼)Þ›ñ¥¹Š`4l»ó™ßó?Šë)ù«£üÖð`TÜ]@WÀHŒ-ûgy:×E WÓ‰qFf¨Ù«M«ž”2`RäÛï†hàTñ‰»n}R%&s:ö²ó+HñÖÏÇTÚÞ8zƒ¬ ÌÀźgs±P^JcÍù—K ›Þhdã} ÅTl­¡æ"WUÜ»AÔÑ«ÖäûB댅Õû•sI¡}úëó˜„NB4š½u£l6ñ—ÍnøËİ_ D K«—=.|wNÛ»ý˜æØ÷¬VÑdeÙÚx®Ãç‚Qœï ÍøÍg&s%Ãü´ÕÛs‡}ýv!µØ?à|ž;g9n²£”]’Ó>¯AA¾’@@×꯴£^GÜ—™©î‘v}Ät=Î„É ÃzŠREÀnuÙ ÕòÁsº›‚Wî¾¶fÐ6B—9bW`Z© {'ãçDÌô¦”l\]É+ó/©Ig¾Vyç8ükûv'¡üPáÄIÁî\è¨ý(_›z¥mKã¹"ü¦RØeä}×£&Yî4þõì’äT†dËm„H‚]/B’ˆ ”v¯"öžËþ僷&e7Zû˜ OÏÂFÄÙਖ਼ض#:éÀSèV“Ó³jóqLû¤Ùpg;›° |b;º´ºß½cÿ ³ÔEô’wÁêþ«;æÎÂøO^½¶ÙŠæÔŸÙ¢/üÀ.0‹•})ãm˜)¾#¼Ñt)nòÂ÷ó©_Áôfôö¹ 1¬2÷'HÅÝ~µö <ˆVç¢ÍpA_µ }Oæ¤Äb¤¾=biù×v5ذ/wÝ–íœ^&:Š‹ýH¾Q?Ýwr´Ó­èñÚO– v>SÓG í°¢d<]xÆ´rÑÍ'¹VÜŠ;àÆöìs>» /ýµTšø‰Aéh©råXL ˆ/eøB¿v´½&rÿBXÞ{ ªN¿ÒÏYá§KnÅõ-ļ_·08ZP¸K-¦I68Í‹z ;d„2‚$Nb’€€ÜO>ª½Û4¸ ’Lú ì½ñâH^i…ÿ²øxMÇ¿d¦Á,ŽÝom›‚aNì1ö1XøvŸvXÔ”g®ˆ£ôÄéš9õÛåŽñäå=¶•¡Õ¯ý8æÙpe-NGÊÜU}Œ[ ÂÜ’ÒaµÓx˜§LÖólÞ§v‘wò†lϺ[U*Z›'ØGuܹþ$?…ƒ3ÂAxqkdMi ÏØ87?ÖV»ÆÐH$3R1`&¯¦¿ðI1.( éÏ (ŒG‹®…x<0çß7»ô¢Ø OüÎõ¹L|‰žCÍç`|¦å$ÿY#ëªÜYÆ´»ÐÂUͧ×l_\¢íÚI×7;&5®VÕ?õÍyôÊ{ã¹Ò_Ò+VTÉ"Ýgo&ùøé˜ñ™PÓfÞʬ®G³D´FŸQúìÁo\òÞß±íVÚ´+[ÖÚÑÌË£œ¹/ù`Môáò—“ñ‚£²O‘r´;`÷ Þ;yÚeñJ óGVÕýio`{‡O[Èj|p.Ÿ¦ ’]/&£'‘ðÌ!2†ú»Ü  ¨1¿Ú'cJØC2ú™ž X6šà Š*—äzzÝ ”?()J¹e—²}É7´>Žn'y8]´ §a–£­{j‰Ø‹B΢KwÑÚ¥FŒ ä~;¦ˆ’¡í¥»•è Yë-ü‡–çaóµøwT¿iÅçÛ€¥“>}}ö$—qPP§+Ô{J†ÏIMÂP”¿R¥e´–#qD,LÕHº¾Ôù´/Ò)2­(C2ª½¹dZ.÷ØòUãÖ2#MŽar¯p¶—qJ>”cÃ`×,iÌ ¤|ȿئ]?dÌÛ ¬€+Qù­¥5*iªbµÁÜ9³øx« `ÙÞÕqÚï‹Â‹”RP³>• D‘¨[K3^ZÉ\H¨k p< ŠA·î[ׇícbà O&ö,‡gƒ*æÄœyèÖewæ_H®=K—gÛÍÊ,pÒ xˆ¦ùù#2&Ûô NìκCã †Vâ³%X© †aMq§ŽÚ´­8Ä`ÃÛìI†)¼>œsf1Ì;Ͻ=3 ¤SÖ n[ÎÎ)³\‹l½i㨢2)Wž2ÄÜa×!¥îQj³l0zÄ´&QoTM8®éænÔa2õ¾®‰ñ„:É ¼àoŽâ(é3ùP^ö­;$äoRåþÂÖ *B%ª rÙAí“$8'ywêöÍÚOÞ\­ªÏ¢¡ÄÈY cùDT; fÄš¤1ÌA4~KW¤xGúV¸Œ>š»éÍ­¦°›¨Œ¼½_¦—±65â{ øÌ6mëwÀèDG,/tt]ƒV·qä“Z‡ÝEqü‘Žý¢8Ó>E’UxúpLÙKZHȂ풬¯Áó:Ëè2‡×3W ê·˜ÌcîbÂùw_ð»†Þ‹=­‹ÁžžL$žÏ @”-ÅdJ)ªãL'Oy€ENÂ% ¿`Õx |¾hÝj’€€àãqÚ.;ÊÊd]qôCÎ>I^“+Sôˆ\ùžG)PiÑPnF•^ÙI§äu_,24^­'¢bÀ¢&dÖ|oå‡Õ£ò ».yj¡¤Éô#ô'‡r …ë…øûgÏmĘ·¨¼w(¹J{˜ô?õ^ ÔÞ\ê ÜzùÞþrL±scõÞw£ïV 5Ä¢Ö[e¾¢ó[ÜahŽ ã?#=ºz#âjíñt—¼£Æ•ÀmÑäLù;nÀbÉ¥×S×fpÁç {C¼ŸÛ/" o£ä¼lPj,p:3K–<ÓòØ­O)t²ü»[ 5I¡û%Š `~Ør˜zÔll A‹C¼Ýºªš¨yÝÎKMÆ.ÉÕuÊÉœM~´×šÌØKiŽD²Sí¤ û¾¹ŒK$h*Õ'']ëà¯û¿Ni#FAîZ×rDO-’Í|ÐýþW©Q‹Þ4W 1Úæ0“IÑ{ …ð¼‚AáŒJuh]¿ZÇ…iÈÁ"=‚1Ô)„M%IÂT_Gó{@zà³ 7N% M:áñ«e…¡&JJ(V4Å¥Ã(Jˆîæu‘߮ʆžêÂ? ó!Gœ©L=•×äü)O¬ä“aZmžÝ§ƒÎöRcžlµ²UÉ]ƒÙ>ÏàÖŒˆá¹$H#ê“ íû,§Že4Qµ8,;ÄÊ̳>{߀ÆB >1GöVV±„MSͰey]ܯ ¥­Ì«[5œÍ—” Y£‹"!ÍF˜‡4’(&„ XÄÑ‹r²îF,é´]¼ƒº Ù$?"Ïìr2„¤CóBÖÿøæ|Çy7ŠÞ°ZónßöHq8óåM³å5_‰D6vÕ; \ {‰ì­”+”ÜZ9¹„ÇÉ3F¥¯ÎñRµø©ÑöTο*Y`—ÚÚ¤¡sû”Àê_7nXR‰Ó—~>ÉO¬ŽìÕéà]PSÛ¯©3£ÏÚ½µƒ…ÃÁ' ¢m©Y@V1ø˜¾XŽ’÷}oêf·“šuÎ*vír›¶æ¼jü"d8jeõÄ­´Ú‡¶tϰ<§ +e(ZF œg?•6Ñ¡ÑIÅp.¼™ðCù„»±+ðéðÒ(]i&xìΟÆw±‘¡Y§G#t—˜OØë­§ù”Úe¸Ó#¿âÝØå˜r¿–õ}"ÉÚó4ž’€€¿Âÿ¸ŠËE1GžCÛOÿæ“÷õ"€¢=êÓÙrÿ ÉæížKî°!:·yÇgðó²"^€ûOQ›Š`Ò'ÌÓÌÂoö~<ÅNý§š)V„Xe«Iìã:ð B`DÑ®†P;‚t>ôç˜r[o/¸H o•^Ëϧ)z¬hë[äûoñ7ÝæräÈÙíkëôůcøXÖKYžO5绺‹Í>œ"×¥N„”RcèÀ?UŠSרœã:IÜTŸº’+ˆÑ›×ohµÁ)G¸xŽ ›?¥OwêO½_Ãî±M¢Èê·UÒõð¡v6¢sM¾üW¿_ÃŒ©;µ3GmׂwÿWXkXåY½É† ‚‰žÊ:M¦”é]šÝ­l<ö ­kB2Ä©TqOjG…Nñ¼1­ |ŒA³5‰+)8 ‡Iýná yN²!wöÓ;ûšLöå=Nó÷± ¹bæS<žpØSϼ&¨{áR¾1!Ë]9“Å— T›EmÚóT´É˜éßSòCW£ÿùø4ïølaÉûËQla¼ïÕ$ýƆsYÁéûÛO­F· è/yø~>~ÇœÜâL·ƒ:tH=#ßþæu2èmÒV˜]AWxS0Pè5€zÅðÒܬ`a_Œ¨fn³ˆ*ßrÜ4í¤ò3ç ÂAq÷lÅû2ÁFQÓܪ»^àË™­Ê‹(éKs!—§Ö`bèH]·Ýú\¥VñWe·žëßWÛ—rnº5—å‘RŒtò@´ ˆ9C½¸ï~•ÌP˜%Š:Þo6ÃRû*q,Zq°{#_ †:jÜ|oP¦ùts¾½²ùåäoå“•Æh]‰îV½'Dj‚ƒ$ä.JÝXêϱ/Ø«“á3ˆjrg25t8Cµu4ÞÒ‰Àôau7 ¯ëàÒ,â¡cº-\cÁð”[9r§ÿ‰±býÞ`žT‹âè×ElŸÃŒn™;¸˜ÂH¶×ä…©ïÆ´ Uú 6PO¥Íç  žÜ"¾‚2¼uq háèJÃfU¸gqþF9 Л±Ž¼ÉrŸ¦ Ò]~{Ž'–ÐmùZ‡tPp †17ØU´™ö² ?˜´È7 î¢“¤wá ¦§O'øwjkO†ËÖÞYxIç!\Lâ«Ã6àßÍj¡¶®•íË5’€€‘~3Ï5åžâafäö‡ZÞ7Ú¦žÊH¸äFþw×ù¹J·È—u ê7ãjSiÿ‰oþ“46GÁ)+ü½$…s8Ù@ë=¦NAyÔ±ÞbÂö< Îc¨¤¨¾òÆšGø0.׎˜‚·'2ÍÇh*¿øë›M’OUÙYù‰ûƒÊG ¸¯o¯ñ16{€ÇY³6 H1?735½•ñTñŒþ¤´[_ M»—SßðÕR:5u»¼×’¶iž/Ÿ½3öhc4Ìs— ã˜#!µÈÞ7Jº~¹}Ùè"dF²3P€¶téæÈaJ»@ëIgÞ^þ¥€ÞÒîJ"Lr[v\e¾–Hb«àKŠz³ˆ¼ÅÉ4§¼Úƒ -í;‡ÜG½iìÐo†ŽQ|O¡h5•('4ëˆÙbc¦âR "gMÂy3~6ðyAJœJÚjÈíÖë Á²70âr Œžlh¥ÜŒê\?’1Œï1CÌ›zË4¬óßÚ⬻”¥ˆærÊ?þOA¢9ÈeŒgÞBFK”dÉ0„7´›?GåŒÝK‚ÒƒzdÆcY\e¹hçéPøÇ¦…Y^Õ-7öz¡þM9­‹kªÜ(K“bÒ3Ã.âå ⛎:•9áÏy!æ2<½½YÁUÝ½Ú ðU(Øžp#‹Zt.onSN$’Bm¹\ç„6V¸a9\Vž†°fðäG4TbùY$eFOñ jPYÄ¿ãï™qÓñÞF|.Q]Š]#LŠøöÜL°,H?ÁëËSrE³$³}éìø!*¸SÑJó­-$ŒpÁ€‰ÛC§À›'›pgrxµ?Õ^ KÔUæ’@r7°™Baþ)NXt΀¹Âmâƒs™¦×Ùè+;c4^l'ÞBtÞèÔ^èŒ2Ôw¸3µë£…J§øw2ä‘üJÊÐeCdö=¿'×q^ `®×Ññö Ž3 !Ú~CÎí8LH¿Òö’ÍÀýû› Õ³EiÈ™¦íê°Ò…dû|”SËÃÚåäb”°Õ¢ô}&^ÄE} ´¡o?Â_˜øà¬\Îâ~î¼ÉÃûiÕĨIST3o–úFÕ¶sÖ†¼Jy^ðÉkÖMfâãÓîeóà‡È5ǤUâEÒn-{<}©%ä)’€€Çy%¶²Ëo“Üy¾ºMmØ\ÃŽš³¹"î ƒçÁýUM5Xÿú§£!È4- ÔÓþn«CP¨ÚF S6³n+áoL!–ÙDrgÒvÂåA®²Ç·”öE3Ìq(üDøœEc=íSÑŸš_-útó¶I\8¦(e*ê…8-#AG ‘y”ç–౜4‰ØYr„}ª¤èÙYýÿ_eÿô*>7èT¬+‹û4NõeǺ 0}Â¥{Ò2Ô.™¯Ã'$ MU"Ép0ÞµjV!#óq ˜Bâ´âa—¢½¹J «?¯Ô7I”Lý¿˜ºÂ'û .´kÔýRñö2é@Ï4˜~Òˆ\^ ª ¸ˆË.ÎsU­Ç×13qÏrÂ^ó»+\"Ž'JÞÇþ²Vl¬0DŠˆ•ºPTh dám¹û—½7|aqÞÁƒ¢[“³9BJˈ ZÔÉj Þ8¿áü¶2¤;S†„úAæ= èŒa3FëA½Á¼·œÏn>d›Vö„pÏr-Êö¦·9ÈPÒ¦ê½ÉÙUÿÕ‚Mè4銾i‰Ï+%!‡´ðZת¨$Ÿ¥v%Á$+Ö V/EGð•nçСåÛT=V÷$'D~Ç/?¤®þSÿ,Ó¯éÆh#cW›69 8Ø«¬ÞtÌÆºµ…® ogëâ2” «6Vû|Žše2-Çex)½J ¼AŸåδÃû§ßB1¶&Üv¨ù°+›¼ŠÕLëµ·nÖ˜ QF³_ó£ÜÐqN=?ؾ瀵в䟪TdD–ìCä~¤ì :`ý ªê OÏìèV{Â|Š"#rM7gØ| H ºÿŸÿ0Ë>!ô6Ð $J´ÿ.oõ' À¶hš±ÊWUÕ¨— &·K)l_;LAïÍîÖ_ƒÁ¹þ:3HKÞ8,6°5š(f‰z)«›?5Š´Ž‚w§ÕƒD±„„ŽE•maäŠz"9ýH¤Ïèû)‘qÆÇk<••ýa/r;;ƒÅzØûÆþ¥£j:^§(þÐÅÄÖóò55gð)¨?ašöi=ëI¦¼(ÿÛ#õD#ú îv¥â7'\v ò»±T•:ÒÃöí-9·_ˆy¥­Í¡„sì'¤º<úÚÊ:¾}žÅ7÷~5û5§Ñ`úí´âvëüú–Mño<¡þ7‹È1ýfzç²RÉ9Ž?c²’jHÈ5ùhÆtIŽ z:¿ƒÌß›TÑSƒ&ºf’lÐ!ñÞž]==«Êm_Æ„Ÿtñÿ+‡*™oû(ëvZx.sEF‚‡:_}’M¦Ð"xG9ŠùÎîAH Ú^exeÜ7X†Rt ¥Ûˆg™¿M™ÆÞFh”gY—s÷ÌK#kái±Söˆß¨.¾ùóß¡¥˜ÄVnï¨ -»H‘~"ëý¦; Ž´{¯0DV-U²óeÙ<—ÀµŒY©€*ªOVÐI€Aºe‡ˆPl…,|‹ÚÁ?,TO±D¸¤x%ôR¾QØVî@=ÚÄà €dµzcSf …{ùÈVÊÑI!xð£=‘̯üm0z€Ã8°p´<kT~’ÞldÁ§þw@rÝËI£²v½…ü°Ï›NÆï*ê¯ÅL™À溟ÃÔŠ™%ÎYó(ý?ÓÎ÷‚°^ŒsÖ’€€¿êoÏtŠGKøÇñ¹G ¦?.ž0GǶu°¡ªux…r÷׆ǵ6!Ëÿfý9º÷&¥ô<öð{Ê^º£{}Dp± š`Ô;3“!‘O´Ñ/ìá­xgÖŽ%˽!ì–šÓØïïfÍ7Ò$ϲ$w¨„pžMÞrŒB*o,S-³„¦¦n늪çEWaCuòЗ²ÒÅe’¶’2Ãûå‹ûV®Átõx'„LÔxXù”û¹¹¤Õ^ÛáPF;WWÁ¾HÉm]Žz¨Èˆ\Ôh?)Š:º†ÒL~@„_Áœ/Ä a7F÷4eödêÎ¥çõtpjj¸?Ì|sÜÕ$g}+Áñc¦ —h¬´ž©^è^ɾb=t7íûI6ò°Å®9yï´ýXò8Or™ìCUOiU‹ 98[)… »Î kL Õ”±`ãÀ«Blivå³ùÌOBp( Á)uøÓ»ôáÏ‹Õoy²¿ L놞µféLMGxÖJ°¿B#˜J0°XbhÈ4“„ã8Æ lñß8.`AÊÎÊ΋ꅻìùm’„æ‰ûÓjÑG‘J§Ž­˜«ù쪟ÚÍ–²l{S=ZƒJlÄàš7z>5·ýÚ“7aµêÐC¿ÀõðÊG#n:=Þǵ°Yûì_„ý t˃-ò}õ¬\FÇäÝô` ïñªé0æ‹óà« #‘#ŽžoeÓ­‰hT‚\/ª-_;}F»~kœX¹u¥½ÿ½è’ui¢È «y¬‹¦-9Vûóü9ŽÎDxýóíÜh"¢à’à&h*`©/÷2½ËeçÑÿO9Ãxª7i©”$n¸“HSðÙt ƒ¹U%%4Kö"w|ÁFk•»Á öJÁ‘!„%,QÉÖà /94zKÇI@§>Ì1I"Ü;¼ÊìÇÓN‚î§þÓ„çKU•·rXå–+Ï]á$IxuÜ ‹q2ƒès¶´èêgA{áþhžW›ž}áó“ÜqS™³ËÛZ°ynš|ŸçcY¶°M™¾1úÀ P­ˆðÔQ‡æIÓmSðáÔÖm'ÛÓI¯I‹ÇW 0šƒBÖ§MúÌFq€ ¹±PFy’Ò]KØ—†Vþ£`ã›âÛßÖb'µKI„ä h™P±CdUqòÜ—_Q›ô¾’€€¨ÿV=¶Í|krðÆÕ}TnCk:nAæP,›½ü×_îœÚaÅ­—îqõ,¬ N•ÄxH:§€UªÕs%º*dÉý[uxäù%g•ÌÎßxÜ,£t_€ÙÐ’‰ý6ÒæÜx-a7ô—\@mÖªFÂ~Í7 aw`/S¤ÛÄRFéö»uì„c}„õ–©a™¸LoÞXí*îë`•£rvyÁ4ÒŒl>¥@éùmš³éeS…<¿üšS™«¹UƒÒLÍ*nÁÞ6šôÃ&j|å„TׄÞh¥ÌÏxj£[¸*´º8Z@Â]!‹ \–@×nüõ1ª‘ûŒÍn}Ã`®Ó‰‰p… :Wf dò9·8Ì!õU§W,™;ž¶L²3ª‰6ðò\&X¼’øø¿Ï„rñ+YOÛwºy ÖÈâ¦éXÔ"GÙC€¾ 2.mõ'0Îx$Ë´uñÛn>‹uÓHÊ Dy‰Uä<‹³ä-¸<'&¹¶Ñ—õ~Æ}§©v>]`ûðžGVøŸ\¿wÙhÚO;œÃ»ŠbŽåš;÷»s!w@å$öI¢ “Âzf¤>éßó…AÏ”·ïûYâ´æÑ§.ž^8³~³)yΜžƒ)Ÿ b'{’€€Õ€”#91÷Ç¥¦ˆ†>¥ƒx¢Åˑӯ_ƒ£ü­ÃÀ¼VtHâ=†Þ±<“°¶xø™øäDîM¶ô(°dÿž†%[} ó‰ö û«,ö|#ªœ÷Ñì`ÊG æ.“ÀÒ“<ïýu«‰ƒí0¼¥±G‹ƒ¬|ŽPFÔb~lŒàÄîÈÆŠ0¡û±ÇœçU¢sÈÓp…A’ëb[Å\§y³ž3‡©¼̗ߺo³°0_ÊM J¼@3^[efsncDªýPªv!hNñ`Ø•ˆŠf™`YDXÎ¥¯æƒ8ÛæQú—¶˜×?ÆcÑÆ-}ú~…GÜ) è@péÓ³[éŒn–‘ˆø¶"KSöW²(´ÓY8|÷ïPN&l:Íɵ¸&âZUøø^"Ÿ‚îËjÕžÅË –˜Ò…IûàÍSçôæzµË‚à §a9¾Ë 1nKÞö¢h¼ÖXä¾8±H5&°ñP‹éÆ>AZ¸qìU¥„$¼¶ì‚¬ž6=P5±àí©GêYٓܘYŒoãX{×öéšÐæb¶3hd?ÂL(çŸA²¨p­¨ˆÍΪqh ýÿè.‚8âZ!rÔ)‹­÷/˜eIÇcB¹kîÎÖ¯¸س­ëÉë´A>eäTc#œ<ô·có¯õ:ÿ§aFzVÉ>TÀQOÍD—‚ꫣ›¿:Kj°ìY+´¼…ÖÍã1°D¡åÇÙk¨R¯àiÌÓn¸‚¨Ô GH9™XÄÑ•6RìZ:䜊>ñÎ Šf¸+ál«7ðÑE‡2$7ˆ?莔3õ$%pïÇPu‹‡—Ÿl'p±e” €Ów¯Cª¤²ÛÅÿí´?¹¬;Ãî¢íÍI¹ªQ•…ÕN¶£¦_ù€.Æ–Ýè?ž ¸©Ù!ŠWŽKž1·–=u»5ÖMÈH{‡¤ÏSPãlß%R=šus‡™èslê¥P‰iÇ®ÖO7xD€>ZUÐ wæo~½3ɺׯOâgªÇâPJS!VG…0o!iNgïW‰~W@Ä‘¦’‹-æì¯ý w=µL[V2ʇ¥³üO0ñIÕ>•Täm'/‹}NÔO]+ƒZUÜߣtÑX3xpÅwù¸×yŠyÃGÒ}ò6’€€¸&á Mhnìòo=Ë?LW ]«ÞÁÛ€›F¿ž*ŽÛ]stiUñùKñsJ‘ª ПiüA ­¶Ù ñ¨Åè›ß¢®œÕÑ!äçè*Yê*—ýn<2ÀGr)8NënBÑvQ½…%©`F âñv“6¡&¨1š`ÿPê}!ª¢ÿC] à|Ù$cBC$~Ë-P׬«t„$1z±-øÔèŸTwï:>{ã˜L¾Gä™SV`ý鈣@ÚnT%q¹2¦±Å"r»-lú ½„d‚÷¶UjïSb§¼Jëèl o•±•DÉ—æH¸.áȤ„3Î KA('c!x¨–o^û¨þ…ÎÀïͽ½ûܳýS/ŠÃ÷¢6]LËûô#™²Y €6ûúmÜT'F'ÎRÁqÝo9§• Ň2§Êë UeMÇ.Úš"è¯AD¨§Sÿ2²½‘ r”È_T#áO½WÐz•Éžý)mæW-âSÏ­ƒq?½*þloØÆ:‡"ÇuÑ‹I!â—르ƒÜaÏ嬯ßçQñÓú"xfïÉZ N­VºYD߯ũNÕ¸VXa/á´iMŹîP?Èê+_™à\ëIt9‘ºHuÖ“Ú'a^òç,v—'Fæy˜& Ä{š‚¶5" ¨¦Ùl{$ÓYŽ_i<¨0I¢”_âã‡¥ÆˆØ `Ý4I¼PX¡a.¿wÎò ”¾-(ôû3|t7ïö[D”ÈéÜ Žw,%#HÖ¡Tø×âÔÿ·&5UÚúî¸f ócµ4ÕM»: ÍîÕŒ÷ì9ë+¾, ùhRð1ßžÛ“È(¶†ûH¼ÁèÇe ÔÛ'ª\¶CºÔ:R{#â%ôœXSK¶Ž,Ü7D•ÁŽž ©íÅ0ü<Ív-{Íî²^ʌֽ¹Ýñ]|,&œÐ“ù؆K;ýÞ Æ¾uÁä¹!ù:ÃeÚ’€€Á$Á_‚ª2}‰L›ƒM›ž0¤ó«G­5ñsFhaUïŠ< pÿE±ŸZ®5Ók'Ç„K5‰´Ã&_¤ÆÅÕm¹^&B¸Ct/ÊÀH˜”̹­<¤ˆBŒÛ“šå<¸UJ¼Ãh/»eü/X&ýü׎úR’h*e‚  #²Úß £çu*ÅÄ…ãü$Fª : ­b*Óêò -å&!Ì=Á`"NaÊhã± 45d@‘d–cÅ «$ä_Ê€ñe²M4›§[æ™ 6†J'×;s¨Ï„œ+iIJX”ßðB˜T"Á‡Fbòh\´ Í P…üu½=YÎÁjY‚~ÿgÒÇ3å±HÿcŒ2‡œºú¸H¬® ÞðmL#y×/áC{­XÑNr=sÿ¢Äˆ_1h•2aúKwsVšOÔž=ç`N/ ½&b.}ßîÞ¼TÊ51œer™7+ž5 'ÒHï*{·×®µERêää­>¡·§©öŸMìý´vµÓ$oïá âð{ÿ-a‹m“SbßÖË¢2ùD!ºþ<“9ŒÑ þoÙúõL9žØ!Ó”UOG.œ\#Œ.%é­OÆxs#3õo—'jl›Ø?‹!ï@ÉN_iXS R'*©žÂp¬†‹[S‚3ôɇÄ@ëTQ, ±s"0\Š>rŸÖÔ§;¶E×"J £â¹B÷'•ÊÔ„»Åòò=ØšºyòX!g×2«gÖÛxa \yÌœÐHvgÚ p¯[–~¥Ë¦þP (7Ƭ pfv&vfh:|Cõ–œPúçAÏ1¾wÉýk´Ê†ü1ê»ÄųÚêŒ=`oÏ{°£}Yº£¹±Äiü1£y¢_j+œ‚ñ†gm i>0sú7›öëù{·_§"?$ û'9’o]³µ4£XmÀ³¢{–ïgj}~O'M7[iúüÿ`y’:½1ñæËŸ¤ûô™Êëü;”fÊ̦E(¼¹þ+¤–¥ˆ~ú{‘¬mÏ C#îŠÚÑa_¨Páxúøÿ }¨–Äÿ (¤ÐG{BËtz¹¿]KLÚòß»¢…• …ɦdhiøˆòn¦82-ðªÅ>žfôl8sÂS›z™J-?Í¢c“0¹ëläì5Åã§]c@ÚPpÝò¾7gоõ™~rcØUg¥ÎКq¤Òz#Âá`_^%!ó|¶ë˜g]WùÀ#´ät)°>ûÀÏÑž.N‹Ï_æß<Ö•–é©t~,Iö ?EÜ ¶ÍôWŒïA±¦í?Ž‹8–‹Ué,A@³'|Èõ½U%¹ó|r@]Ó 9³–¡¤\|äIeÞ7tZ²œk'‘™0¬O.»Òª¡9ª º) úwe±;ÙÛ¼Û×9Ê<›ž1UFÐ"Zjཅw2:-ŸÏ(}íoÀ —Âdã ÍíT ñ³±oqªA¶ &SË2q+fáÕ3æÔ>Fë)Xæà-óz"´Ùrº53°;Ä /B.§µ–:rÀVö Àw™~H}¦mK8g‚g­æqÚÙ… *†éó¿ E %ÂÓƒ\°Žû/ZqDBl$ßÛ!~ð"`”M‚ýÙ¯îÜóKÇD%ZÔ©ÍÛéÈΟëgÿb“µâÖ´‘ï“£à¨n€´÷ÄKóóˆL%þÅ{ŽÝ«àô_.Cý‹úÜBDƒ¨ ¤è+µ§e¢Ãí{°ïü‹Ðßnn£Æ¦Fr‘9gõž3ÏÒ ¾³z2·Â'©Ü}xSR“nüo4HíÏF:ššLa¥êZù˜ˆXædºâßdz‰‡W>[íúÞ¨&\5d_ÑEkµÞýÐb–*ùÜ}agI»bºæRFgÊ_ó J® ^†s÷ùŒô}ª+Ï)“r´ØÜ¸ávYY`ì‹„ÙL–©könX÷6/Y¦™QÁ¸DªÃ2ûÃ^ýÆ¥+ÅoµÎúºù©¦‘ÀŒ,{Fâ&ÉuÊ ÷Kàãz!¢µ©jò?}ÁYZƽ/ þ|ÛNÈ‘*#ŽJmµ®·–³¯=šåh\Ÿî'iÛÊã°‹^Ɇ®Cªå*ÏIð“ÐÙ3Jtõý(LOžW¸û¯Ð©@8É’O)*:Ž<Î3¶Iq‚éq¾¿¦Jž^VËèc_®’€€ÄO5‹½ú)VPkÈÖO °&Ô|‚+ ä­ÒF–Âbí«‘¦ª‹´­4|ôÔ´û@Ãj/ĽÙÎg•vºœÍëÄH×L…*Ãé5dZ·"vN„€î²]Õ¸†·Å\ÔíGuY?ÁyeÇç$ßÈ4úîAÐïW=Ÿ[ -x¾1BŒ(Ù,­»1˜ÊöHI”Nóì·œ½ë˜ú„rl.~ÖÚ=°nÍ1 6õxôÈàYï¤Å¸‡€„Ó`´×‡¨ë«·2Á!…™ˆ¹†×Ü ˜gG–~Ýf?ùWÂåç}µ>¶È‚`ž18»Žq%U+.™~?ëæÅ‰y¿*dÇTw8ƒrÐÒ@¡gŽ´¡ŽÜ4×8œ»¡áíAÔy5d±Çz-~ÒDÏMîŠ](2ô4ƒ¥qãZãÀÜ1n§Í÷píÎs7||)ÛÞªDat '¯š#M°@˜¹¸8X~#/ž9É33sÐúè>­^ÞLþ‚ôß[žÊ%Ä*‘dR úëÙݽ¥RùdZ%ïá‹Ñ\ÊKžZñÕÆÔº²iv§I6n @øÊó¤ñ{žžÿu#uJW¶Ä|A äëNäsáÚ@Ò½,%ß¡³r³»ð—:ƒý”÷½p÷p™êü¬÷ ¿¼ò2;è· ¯'…øÓ³‰no« 3^tH²aûqj“õÿdæÝ ¨êj|baM^§ØAMkHÞ˜H2 =óò žw¬8wj9íÈ¡5Z¢.²\Ó?+ðû4tYpÏÁâÇÍÛÈzSd–”VR~¡4'†½Ëc¤Ò®KÚTxï¶É¦i~_Hq›É÷ðdá=½3"f¦YÏÀ‘Z€–äEðôÓ-h=ž**«C¨8M¾a…¡ì_Ÿá¡yÎO¢Èïõª»œ¨©ÉoÝíK–Ä[¿¯[¹½qþÔ´¥ ­/íæ(Þ£¶#{i\ ¯›¬F{v Mçìñ]1œÔÿJ{L6p§•<zäëP$OÑ3ê…{”;YèB~GBò‡¥è+Ü$$K f936 ‘”§ŽvæÃoo”r¹â*£AÅÍœìO½ÉÒ·ÌJ‰¼3jQ@ˆ¼¨´¢æ™o‚N>  &çe™H&§éHW ŒJ)¶é¯Ö ÿƒc—%l£¶Bõ,'icÍáËy…´¹~þ(SÒ7IÿiñͧášX_ÔÅÓèš¿(ÞìýÒöA»ñôTEŒ¬ý9kôz¡ßí£ï}rÚ=Õ>9:¢qJ°›ç¥ü^‚³ï’(RHæ<35õ|¿TÏGÇ øÚ—ÊZ(ž5á³#[¢<"NÞ1²ða•*‰‹;Ðc6À¾#x+¶[Õlê ;Ï¡Šl…;.v"ìðŠa8Oó+tD™Ðj§<‡·E%ekǼz ã̧ qxµ5K—dÁýL;üY—+ß"û÷³căRô@´Æn¸×ŠØX60­Ww佦])\µž'ÃqØý×( é¼1ÉìÀlBf߉¦;·v#$‡U im ƒ¶íÐ×x)×Rý)†Üf=JðDïKêm¸ +0c—w&ãíë+ÁÊœ˜Ëø)*Lœ™ueÔáÖ…d­×‡Z'û𭣂jÖî|ÒHµd´åŒ?iÝ(W~4Cºæï/Žƒ|äiÃôÂ\Ðb¬ ,0rô_eÀBsS‡ YÛ,zMò çýø<P(Í2Z5_¾ÖªÑlå¨FI²à¥ÿ5_J‹9n$¶ްw¯×è+þÔz½d´dF©Ø›¾;8™%tî^6ý¡4Ý`Ê)AÆïvÌ4àûê&Êzà‚nK*Ž,s5ëQí=L§šQT!wL[aŒÚxç®]{ûtH""²I!p˜æ.c S¶é=Ï•U;¢¼<Ý_·7®†j´|Å]¿Cq ³‹? «áø® Üæ€ï¨r$Â:Ö«¿Ã ¤P°€Û]mð‡HK›x1]k?W:ðMc^\7ªò,’€€È®j¸»²©Cê·&’Þ“ýò½>ûÉ ÐúÆ °M¯&ú$ÄÆuNbY üdó5~;’¼¸ ©ögܧàé–Ó‡ä¨êéØ§È£Ä3.Z¦ï9ÆD`S » ©^u¶lÈŽÚ®6ØL¢…¢Ç‘|/Í BÚsQFs”Hœ£ïß$`Ž»e"“©œ|~Õ}‡V¸„ã©‘wx²XÅÑíkbð¾?z?27ʳYš´»*ß»î[34’ Á²æ®&çìÁÉ6UâS,9áQZ¨©§!f +\·ÇØk™¤X3©‚ûlùWÎ’€€»*µº»ßàC7Úè†Ñ{.Æ’C%òÇ bå‘®D8CÍI—Un˜ëˆ‡×ÎÏÐ)¬°>JþH'cån‘÷¨h¼÷³0ŒøD8i¾tWïç2‚¸¿Ö%þNäÝLÊa¹м¼ãªøìs@â—EK=/ÈP0œOŸ1ç«Ï!Bï”ß)€8¸i²4eêÏßÍ(áÄD®£ò@1?’ûíýa@ÒéÊk†-Aüd=ÄÕ꧇˜,´ §;`EŒôÌ,­›¯8ÞDeÝófC«$+ŠG^\ÅnCAª9J°ê9‘Œv—ÈËDª'|ÈÖñ¤4ör¼Òp›¼èim¡‹Ãá‡>‚þÁÞ͆ٳÚäp+_×tm6îúB¶ÿæ÷YÜÉÍ “gž¡úŸ«ãI©pRÐ"ÝÄm¶\cZ㘵>x‡Š¬ÁóïàÓÎÊ‚ƒ‹Ù»§Zº8]þkßj‹õ†Úܧ|îú‡Æé\àĆo6ÑVÖazâÚ0)6Þ~Ô2ç„óÿëœçt9——Zšúá—^¼4k|Zß qQBâõÒ?”bÐE_Ÿ×^£¢˜¥ÔuÀFù¡¸IzÊÖ7êjŸ–\¶ÐrëÑùã¬'œQª#Üšáï Xߥ†‰„Ó/Cc¯ ¢Q^W¸þ½=,ÿ•^gp¦[P»‡N.zhgaèš>ÉŸŸÁ™A¶»r‘žV¿ÚNA¾û¼Ö%l6l3`Þ ç“‹?CµbŠðým0>+ ‹U s%Õÿ×½|êò{Nb Þ&°ñìÂø€õ%ôû¦z»Èrrư<Ò¸ÅøþÛ®‹Ý™uü´:yq‚a缸³2é.§ ;°â­ì1V¬¨¾¤*j3•ò‘Å™Ôî²((Ó¼Zn®{ Žä8Ueh×l˜Òêàg0Üy€q3EKÅ „¼l‡,üÖôͦ2œb‹*POD3¡­ýÉñVÐ(Ü b¤ßÛŸ$›ØTpª9 cžëb9ÈÉ>ªR]øs#6‹loRV Ÿ]òPï5E¨ò U'ÈÇô^Ûð¹¦×=¼RΆ`¥ÀïýN÷Oº»ÜWÁ%oˆC‰½Xn ÉAkáõñÍÔ†h…RÝèÑ¢^™vaÁcÐN’€€È–$ /1%¿Ó!Éé†þ;KÂÚÚã•TXgqb»&+ÄJ¹*+‰¡àýSÏú(¤À[Te·¼õj345*ëÅüp>\EþjãÉšø9ìúO?†gŸµ,°™!×ú‹ ªpgÊÅ?ú•¨Bp¨çö&V=ŽÐ # Y¼8'«‚ħ[/\jÖ¼íÀFd³Z ¢cVÂÿÒeQQ›-|¹Úx'„»o²MýT¼¡y°²¨˜/Þ‡±1Z]BW@Еګpox‘6- Q¾íþQ¬‚ËR S€ed¾ÜRÍZÉ[_ýà7ômßåŸBÆ%v°Œ,¬Š‰n( Ã×ñIåÅPƒþÓð˜pšíì“ÿPÄ}㘞‰«"ߨ—ék——çÏ/·æý ÇK(E­6²æã÷=ábBÈèd¦‰é!”6>Ž€ ÑQŠ^Å_’eû!”û(QÀ³\˜zû ò ï l ”é=ò9Qu7[šiÂ|4!‚wÝ-R¯ûùãëYt¯¿#RгBtP*`¢8I1› y)\ £ú UÇEc—J–€N¥PɈK¬Û\ L·Ã®:óQ,¹´õÅ8ï4H¹¾¤¬@¡×ÈèÎFqj¼nÙÚ´KÕÜ+uäí¬ßÁïæ[HÈi;eju RâÕ/÷kG»ïNöèªH ´Ô«F®-Ö@ºð˜ƒaKeÙÛB\.¡ŒÛ×@‚Dn‡(¨NL³¿ˆ¯‘}”|— 5ÆOn£9›ZĵâqÀ¥4jôÎËB“7˜Lo´DŒtž¸°ÒLÚ¿+18šd]}g“ºa¢¯Ö Z·x{ _R©oâáÛGSþÌy0Å¿³RÉ‚K49"áÅ£|¿,¨—9#ìˆv¦j,9«Âže°Šó¾äªŠ³<ú%"8ÙôÆšüà-"ÏŸðò~žuɶÉZƒkoò0By[•Y‡ÎqZãM"Z´bbÖþ5Ïí™Y’lÄÊf*L똲Pð¦aûßÜø â“…*oü#Ví;تí2x‡¥V &Ú(õÚº÷Ô™“¾w(ÎŽn‰Ñ»â8"yÈÒôè>>QÅè$Ý­ošÊ3köÕ÷ž¸NwÏ«8íK÷V”jšdŸù }´QMÙ˜U&‘Vó’€€¦Ál´_cºCAˆq¿:,iÁož>ËÁ×%º=‡Åó -nøèx.¯…-úmÐAß<¬´ÚðÌP‚pàw™øÃ72 Ò°ã. ‘øTΦÌò÷µD`’eÛ˜¾Ž§_%3wAºiBò[x¶ãÑ)Wx5Îÿ¾²‚DíÁÉ<#æ+™ÆûÏ6Û5)ª×§Ø¶74ÂPY€¾Áΰ]±ôy—²zŸ¹v—¾R“=½ò$ [“G_¯ù«”ÝÚ[ËV;ÃÓ[óxÍšWsŠ91ÞœƒÍmô/ö•wÑIµ‘»ÀnFïkñ^NëÀ?Ø çB|ÊAsgoÉÉ ’QHÝÓ!êNˆ&h ýa¢0i—â)~ûülcÕ]&•CLùzêž1ûö¬OõBOà1Ç®èöT¨YŸ‡¬38î$t]>áJàŠOzÄýÓ9¥²ZtŸÕ©e¦DŽáãCV%‘ß8sÏu~ý`ý»W"‰qèãšï«AÖnnZvµÝÐøde -šüõ`Òƒˆ÷CP”ù´gШµ2þˆëɼ·ÓÚ Ò€¾tGPÕ´¼‡áX}ÿa ¬¼ŽÆ/Ó²äø6A [qí®ÇÂòõ²cM†¾PˆSv²±’{üÿ5BÐ{dŠƒºûŸ_ÈpúÐyKV¶æˆEn!Ш)§ Ç]²;ÜöÓO»î³˜*Âz z €Ö1¬‘þÉþÄQ­è¢Zeo¡†S¦õ-ôcÍ¡t›èD÷Gõ½µqÐ@?/£æ_O;µÅdü¿”^äáó„Cœ÷wÙ9ñïpGu ø9Ù˜½(§„QÆ:Aøõ#Ée“Q‹r¶~ÃéÌ—l\ì,Ë‘t¬;H»€v<ÛVÏ!@ù¾—„Cä>ÖíÀ›[¯ëT°õÖVi¥Úno1£¥Œ…"-ÊÉHñ|ïé%Ígß©×fÔ´ïøÚbk‘ªkÎGiÁå± Ã÷M/…ÊLø/D¦›‚vg¡CËrW¨/=ÚŠá—T]Q€ê )ä=j–uÆÌükóm€_cª+]‹{Ž7Ê׈f¥ÊyáÄïo±4zamô–éfJ0¾®nU¦qº¬¨z²k#t£PvhÞ&T;©̶´†å±²9ìø•“¼ czôXŽDTÑ!>Ë;3‚ÊeÍ{qZÛÂÁ’€€ãL&D0.› :Gƒ‚¹`6êT±ƒ§q®¨Ý¨MægÀW7]Ÿ ¼ì’o0u™» x&x}êD˜ööžŸÀ3ò‹)tû¬H˜hÆä(û#ý­7'gêпM_[ਫ਼²ç&puŠÒâP¦±?R›eñNàrSW€tÊÝÈýhÐö\AYƒ/VÓ~ã(s¢¤mÁ³n"W‘Ãbzid¨òíðÆ OÚ ½ ›bæÛBY»].ýð9g8õâ4iŸÂdh®Í>¥Í%)Y†µˆºÈ’!-±‘„!r # NyNňy<\8æÇbV#Ik~´ˆ®Ü¿Íʮѥ-=Ðl#¦¥6<æ×’‚¦-ªÑPKAÐC@}ßùüÊ wtljbaá.ƒë~S n¢Ú`0Hx Ã="_Ì»cêƒüB¼ëRI2©bNdúµ(v‹¾U£ëîÄþ(v#*2Ùýº3’~Å\­”éÕe0o ¡õs7 ˆ†<LMÚ‚#wc°ýúá‹£–óR ëÇ嬤 ªê>.!ð;„ë!(ªã«ÿT²X9üØÊÉøoİ›ì)—•ç/ýÚtº”‚b"ûÚÑ÷™Åq;=¡ÕøÔþJòl‡gžbÙARƒÕ朸5ր͉“£Êa,‘z[‘µ» ñKçø?‡<Ï¡þ8ø±X‰8rÌmèWå‹ö>GÛãz²W…ˆ>¹9o&r×7Vð—îd ´€#}€ö“hÑÈç6îÆOìçbGú™™ ‰Œ¸V„›/òe*"Ä%E_ØlÓLÌÏZ8¼¦'K¢ˆ%¤3I˜Ur*³ÞÖÔ¦°Ù €¢ùoñ%Ý¥öyR @¾>N>ëcÛ¶!b†»²`ª>jPÎARò=ASUÈ!é"8+{‹¢Kr¬í/à-* uç+ú¤ú ’|s™(û`*å'~Ù1b%Ò›cöÿK”É€ÄÜãw1ØsJíTR}«ñˆ^Ûý ¥#Q£”úª½#ç¡ ½£‡JnUÇnõt ‘ÉÂ{I™*¯}m-™¢˜ÀL¡ìÅ-²ú–`,$wáEw+`œ®©ÛùT¥Bˆ0´¢2šÁÂ'ÇQ:LÔÍS𺘠žÒvpœZÁv×®’ê&Ðð¥ß<“©èö²ÃLG§Ö£ ’€€´û€uú*×,µ> A/: H†t§àq*ð.×c”yJ®Ó^ê°“­)Ÿì¶®Žr€±8uÖÚ…ÕT$„°õcÇåµ>]€‡0•û tÛcìš~š6$8Ä yqz¾ˆc‚œ*4¿wŸž¯so}÷þºqÏádú^æ>+Í.|[00.ͼd$×7Tmõœ¡‘Ùí½‘?iÔÛAì?åzÐ(MœJ6@6*¬IÉgë š*u™Cðo õÆèôAdsÏÜ­ê˜ñîw£—Š–×GÙ±ÖÃU³Óf!jAÜ' µ'ëÅLk”ôO¦Tõ® ¦ù[r@Jutò§å­§ øC)2kº7ÿ¸ó—ãÈH#"D`@ÞÎKS± @)05kàä ²=ñÁ™V÷E“GL¬"~cJYá^Þû †ÝÝÒùÃ…gmœ²{ѹ G­z.Bò€þÂeüÇ$”ø–øgž^H“ ô½’{u TTÄ ÐÕ(#ð‰‘9lôõ”è2‰m“%À¦ÙZi0&©ø,‚ìô±¦F…,ôøÞFº à þ^R^€dVëy }Ç6îñÍÀgo¦-+Ö,MißÅ?nLèl @ÔcíÿzeÊÁƒÆ=îx/|â+«ÿê×úR§u;²aë´¹¤úIêÍArèTç”]+€ZËG<¨*Ñ(¹>Ÿ‡À»CKä”·Sš_y„~ùݵ(ªQ­4_Í WŒ—m*ØéRtSyzùrä0´G-ò9eö£_Ü©Òm‰÷â8Ýè°~Œ>oÛ'ÌŠPÕaœuïfÙÍk À\€eÚítÀ?ÅRˆì&tÿMç"ìY¨áÖAYXàï¾ÛšÞ˜ïÒÛì@pô¶Ô¼VH'ôˆ7¯âiS­-ÐìÛÚ‚]PäJ„%…±Ò»XÏÞ»&W}¶L!ŸôݪdünO%é›åc¸!gðÇ©ÒË!P&î(Oÿ `?æÖX´8¯8™#9ÕE¶YùY<¶Ró«è#_®q†””á™Ý¿äJe¸ŸŠ–õ~™¬Þœ¡û’‹†ûÃÊthx£dxÆ6Qº!³vF¸ÁàÕƒ(±bºÙ†È?©YÙA`Ølß ÔÈ5ªq‡¯³·çÒ$Ö¥º}‡÷3þê3¸`hcç:úc€]酇撀€ËçÔöQ©$á±# òRm.g~»PSiÛC’’6‹µ>ÅŠ>°ê5àZ’HrqÔÉ5B˜¿fyBRâ¶Jù~±£ˆ=ÊóCV‹»’>h ÔÖÊ—0‚ÿX7–àÂW~Pô ôI.'Ƶ§É aÁ;Ô€˜QÕ𪛫˜ÓÍ`;î--%W"šÎ& ’x=²ýd¿/ÄJç|ìC~¨¢oS&ivoO„ sý½[·Ì›D噫bßæ¤Ä£RèµO5#Uq!yÎ|BËÂü`ÁÁìÎ7×¶8iXœ]¦¶3ˆ–Ò &ÅÜ7Q·<ña=fRüº×}+)úvWü@ù]õUhm´–C ± )›¼ÂvÂCô·“.¨f?〫UÉuvçðÜ+üUœˆoCaŒ»aRH¤#»/lïòFŠvífuÄ.-Ò´ïgÔg+qèW3œß…¬Âjv¿ø(˜Üc/NŒ8®leSÅàã ïÓrOÈâÇŸ)c† >_˜ßd!ólºrù$`8K¸°C[Òœ ì܆³­·nü6}ÑÜ y9³vòA·óµI1 7|.&™c[ú.ïz»HA°PDÐ93(‘Å@¹˜2X)r Ûs k«÷‚a0Eºq)ÌMë-5±Fz©1D%™“HZÄS$À šÝ$ëÿ÷aÃßC<±½Z‘%‘f¿¸¥¾#¶JùM §—t)bs>ÕrCX‰L{í°¹¥h:Q‘qHºñˆó-âžÍ„VõåÚÆWñª¢"ÞŒ}Ùª¢åÁ›_déò¢wÚa©ÍÅö΢ŀíT$Žr#)Æk ÃjsÔ°p»1{ÞÙÓTšç®Í€ÇzYž dD?º?áª92²˜€R<«@©>“›J7‹XySUãC9Í­_.½p\‹iº™Ë ĨÒuô÷ˆó„ßñ*^o êÞæoÇuBŠ  .î!<ãAðÂú)#ñ„ cgTš%váSS›!¥Öª0Èøð˜í¦;zSe%N¦|¿“XÆ6aº£j—°ð©£.Š*ä0ÖƬ©ù¬&W¢oîrIÒ.‚qÚóÏ:aòkk”{ºÔ¹ÏZuœ]›íñéˆU» Ìi0ú™¸ŽÝÌ’Ý Þ‹å4­U¼“Hv¶¢ßWvÊé±ÁC38&Õ]’€€»¼çŠO×½¼Þ\Õ…V”»]¿Î•±Y©–€¤ÿÊqp]³ÞÂG)ÆŒj:¥Y4Vv®´éËà„žî%à®õR~*fþš®î¬Dó€27’F]ö[LS¡ƒ%K¢ÚÎqÕ@µ–é„Ù—ìK2Ìp†žüœ[k³t ˆ°Þ§Ûj…ÿ%lµ3ÒŽºîÌ Í¨º±Ý_‹ Œ`y ˜I—ѵ%åq‰Ya¼ªP>¥Û‹Ì€ÃÈNÙÞz ŸG(ËNÉL„¼™h¹ýÐF Ë™,évSþVXEä}ô ŒœúCM;,‡Yó×®ˆ\p袰‰»–a(èj!Düz¶Ê† ÕÒée7µu{ î“aÎïÛÁ;}nµb‘·{Tfw«ªPfÕþ-VÍ)„ŸÈØD¾6ïVS·áe"Fý5H]ÑD ñ6È›×ô¡BµüO i>É_+PO›KZÌìþgÑjU;7äÓÉ©$ÞÈÆzçÕð. 6¿´ìæë~˜•xy¼M!“æÒò\ªeûa‚à‘îæ¦-÷I%•š{r8Ð$/ÿ𙨖¡¼D§ët–úp^q‰û3ò€€rÏãËgâžr°_·HuÄÐÞÌÂIÞ­y0»úÒ-S(j];ýjæVeq~Œc` nOÆWXú©„G¤ª·øB ­ˆ/:œ&X<¤$[BßÀjýõF’qoI• ¬ù£ ߨt4RhTKåf9û©ú(Š]ˆ –ð„(óîzs~{£¸½ªŽ •¤²CÒùu}&:¿½ÐZuKG¯Ôtƒ=IcNKÀ¨$¶°`9Ÿ|0Fž´ø,3Ý1OJ³Ã°¹To‹ŽÍò|ð½ÀÉ>ɃêE¿™™õË6ìJ7S;n¶µTðòÞÛuèæN9¡¥Ûo!ƒf¹Í  ’€€ÎOG[«å¢`2–©…½&U¤dÇër’ê?&¾t*ññËGZûªôò9q ¿ùO¹{áOª±Ü|ï;üÏÐÐåìb„¢.e:ôÈ¡<Œh É©ÑÏë$}’€ï˜†’†ë$•êÍ b½Hñ70†Ú54sC>?°Ö¬±-nà(MO Ÿ©OëÃËçE¡çEZ² §¶#6ÖÎ'm ƒ¡h%pÁÁÅ·˜­D"áÄ‘‰G’é—ŽQξñcÇ´QäË fZ·ÓeÄšICâ-~ÕŠLNœ$(R,´Ê3?dÃ}ÈìKNILk}¿Ô¦Ý ÷)2®„ÏD†?A왊ÿÏi–œ¢‡°h縜e9kÍT4Ô”@‡Aá"C^ð*À4$½Þ &õ7—óR¢ê"n¹?ïiœoYSóÒMØŽSÔ9s¦ë½ãZÖíu.­ÀÅôÍd[·l·%ù#zK­Õ¦òøkÑb’î³Ò1­«ŽÖ–¸Ûy#)íU“òjÕΑì(ÙŸj¦ŠÀú²½ÓÜive"^¼.,råö(ˆ¶E÷ÇÄQ:Ãsª3…3bC}Rà•+7}Ig>œáñØn-íÅ塚À´C•;!>$nAÓΟÇs·s²‘ö@ÂÕ»»˜êKk­tŸ“Ö»Ó‰˜ù¹EmΣ4k¨¬ÿË´ŸŸAWåBÊ-4‡J³´y#ˆ‡KLA¹ùLÁñeÃ8Ç^.SáÀS@Lg*®ºp9Óœ~ä$¡“nÄ«¶°ä‘g`¢€qâ–(0Ä>¡Ô;-f›ÏZmòc|CF…êË $O ã–AÃtg­-x ZÀ*æv(Ft²ãß}þ2bÑ; »äMÙŸ}ØŠyÂ;K«eg¢Ýi‰<’< Ï&®(·NÜ»O²ÛýÄD»™Éœo¶%…ÜŽÖ,ü}ÂbÌqí8Ct ,ºÛH»BtÞDjàœ?ÌPš‘m«Û†‰cr;±äú":;Ãn Šÿ–ÕYÙua–(ÅYäûŠ:’ÚÅÛÔá2#ú¼áÒÿËÚh½É ‹ÿ䳉mh¤—œxÈ·BHàÓ—­* x,Ÿ(ºÞ„6 —T÷hDC—炇œÑûdšƒ“”WUXp*—!2Ë?Îßæ;F_I‡³Hÿu³cÇŽŠ=[0?äµ#!îÙõëÆ~$>=¨™@L«iŒ]²õ·lU²ƒHSµÀŠK!Ðô×éç "èëw¯R[º‡ŸçT¶m(1"dåfC=¨è‹Ì?QÕOæÈ«æjC$Yÿ$‡àçì¶ k¨tŸ]#‡´h¾¯b‡VD˜ÚTrÑ41x: íŸÎÃ:œËª;…ẅEx‰²Ý"— ž “Çê£g½W§i ó&Ÿ—Ž)‹lx Ÿúö!Úö‰žB,–»ÿnýÑ`Å¿ F©ÊsÊAMPÜ—¥À’¶ÊAƒ E;[O\ª•óS…©´õQ8-†Þ»ü“¥da½¨¡\:ˆÛÄýf W• ¹6†† –Nª¸1é|ø>áFÎ*´:"áÛh§0 +‹ŒaŠˆÎNÉÛOHzËÙ5[e3R­«_¼|ªSèâHqvZùÊK5èÄçÇ© ¿wÚDâ¶R cÒ8 wýpY´e\P‡'ä~:K>=c9½U_!š± Çì)_F©m›èš1ß-Ýßæœ4° óõ ’xƒÀÎÍkµíRHnDHu}Nz»( ë\0 ôê'xNyË~¢°;ÿv9ÿÚGbïnòšÀdQöj÷x%o±Íýѧ\‹_¨îuãâÑa¨Ÿ7MoÐ"Ïkéµ²Áª„b$‡uwà%/4]9FK?µ»Þ×pOoB”Œé´lÎZÕØOýlàþ§Ï %š_Z4l1ï©•JIáñŒðt! pÍ s°ÁÁ iökPîöùiD ƒHP(Ö7¸†CR"ä}Ô€ +à¡[úŸÆ^ž)Oˆn”Ž»D­ãïb4X%„·ô]® +xJQò™ô ¹–LêAõˆþ)IBmŽ¢‹Òœ"À4 CiÙ#> ý5îe[îüP|×MIÞÒsý›™â¸Þë¸J+ |™gb âºNòìñL€óZÞÄΦ_©ÐO0è’vʵÎsQÛå¨g¤’ú²‘•¤î‰‹žêGƒµ6Q’¹Míñßë²4jÈ¢ÆþÚ¯Uެ‡šV4Þß VtÒ'Á!ºâ2“Ú\šçÿ¬Öãl 1ù·1Œ¼Uö•Ï}Ãlt™ºÓ•šz¶¯šgÁ~!øO¯ ‡' •ÌéÒ Y)=лN{KúÛD/ªH°§\öz2ŒY›@‘]³ú€¡#lBÜ '}8•n_!ƒžfëB €ï–A²8ŸøØ bkgT}|þ<éi‘Ý…ÿ÷ž-…ì€Ë‡¿1x^ ‚S)J¾*L*È9YC<ô7·>b(è¼óêK@Æ|ê§MòI”ãÝ\d0SHPúY?:é€KLñi2u¡…“ñšlæÐœ‰/–‚ìk™’€€—~.!'Ç4\gÌ…S$îå^g‡?›?¸WÕ÷ )K»ƒï[=ïwÓˆšÎóì¬íÊ/è`7AÊ„3SU𑽠æHíi ôtŒUÎcW½WÖæ¸(~ìæ (€I^œÇ8YE‡ ª*âÿäÒb-v¾îf )P”}nº (†°í¦«¶óÐ(øgWÙ—5r‰ lø- ^—®à” ÈSÚý7{éÍsaÌs aäxòphœ³F‘íJñ2@•võÜõB7ãÎÒu?BÜÈd0¥²0-ª1øg}îãÀâEà€ðÁÙê¦EÕÍ#®Ã¬§´D²[š¿,û+]^¥?ŃÚȾæéoIµ·@¹ï¢šx<¥j ߊ@ä×N‘A9]WnéjÑÑ‘^ŽÓmšE&œ¯3šÛn=;–ÿì0Aáª[’übÍ4ÖRÕbŸï+P‚¯*P©ºßO†ÚZ¸‰õŠ<,NgEµå^Κ°–ÿX7yÑð–MoBý(ȤŠ$–w‹û MAüP¡(j5Çàª[Иöäs.¾Õ<<Ç »#€ƒA·©Ð•”?¥‹´FŽCa·±Ï‰ öéÊM4Qß“Î>÷£= N?¶ûqò£Â1 Æ—(­§î[óœŸádó[WKr»4³*IñÅvb!mD}ÀÓ£éK£‚ÅÒî8&69H-C-0 u8òó+ŠÇHkÑ% ðç˺¸ÌþÞ1˜Qôê••üPæäê7‡u“K°ÕÀcm7Ç¿ÇçuŸ,óUâs°þ‡WþÆ ç‚Çö|g LÈ¡*±9ð!ž´oW•ÿ›ÌYÄ·³¿Ó|}úS«5Ãû8_ :åc)Cýr‰3¡!ôËf*  ;jûŒ&_~÷$¨…’ÀTB`z*œ\÷ÅwŽ<]Æ*˜|%øw?͙֮׭ÉìöÞ{¥a²¹øÌ¦3ºÙ =ksh¢ÜÔÌöÙt¬=•Wr'ÎÒÏœ|Uôe‰÷þ^{‰Ç ~/ íî$üÆcH2ôb·Ðý³1ö×Dâ j}üÚŸ0L Šeõ^hµÚoaÊüĦªð嘬GùÎAÁv%¯,Ú½å‡êÃkCûoùÜU×:L@º$– íÑÕÔ2/OuAˆ¢YWúÉt¿=N‰|jâh)¿Ôª?4’€€¾ZÍE§áëÄ»¬œÃ-ödÞìÏ^}&9+¼ôÎ ôÚ»íÚÞµX—ü» þKrº:jMé>>HŠ“05þ’¥¯ôç°[õe#ºóu„ g#ðÛ¬Wí ¢ ù/ÎÍß~ñ½w'þ±½ì áW¢OgV&ö߈ÈÊî…áÐ ¾^×=ß½ç~tâŽ%zîË?k8a†£®¤I«|eA%(§Å<Žäx<îO‚ÑN)ëXÙ»–U+v™e c²]IC£cÂh=†“ÌãXQÛí£Ñev¦oƺ¦C‚8ª\Ý¿z;c”«kºi)ãÖì}%‘' YŒ‚£"z½ÔíÜ>°Þµàœ¹…­Jë¸Dä+{°?õHB£`1p`¶µîÕ¤FîHÿ?BÁgŽ4^éÉÛÄ->¦"€wÆHÓàc*Æ©×ýä×-2ÛvkxšâÕëÉ>FÑ‘úaQKYÖýHÏj-ê–Ž òLÉ1·!ØØ"*ƃ¬6'xý²(óù½v\—â“jFóý³Àp•ªµå(‰MI詎½DŒ@%Ùo”ÒÁœ›ÇŠ.fÎÿ´Ò+7Ÿ˜W:/Çɰœzk‰^…'Xm…F—¾r]aä(石>¡çÜ2ˆmlåõ‹Ž8½uKÒˆC«ªŸöÌ^1Qãš<±iCècxUæ6¾å̧s $ ñÛ ÎKµÔ© Ž¡¤=ôk¯‘€„Ó‡z·áµ Gæ´(ÞX*çÜ‚Á‰æþëºEf´~Sª„ÍŒHvK˜.0úkI—Þ‘ëîÜ þ g„~ðY7ýÐÿKv~àn-žµ»ÅsêP]DcÙÀÞ–F½ªhÁàTµ­»Ÿ¤>È 6‚éÚéÕŠììåœ>xå@•¹ËÍë ™)[ÌKÕ0>ÓWÇ#Ó/÷×m=¹ƒ-¬ÕSx˜eµ÷)AÉÄ@÷;µ;ÝÃ˰¾> áLñQ^™´ñÎJ>!ñÑí—#«# ª–çôç޻ɕ(BLò +œ8Â\Ï ÚªÌŸmPI0@õ‡Bt¡ÆÆŒúÙ’ml:ÿ…êñÓìQt\ðG¿d/Õ¼³3¿b,ø±šH’ž1ÏXÖ`Âý %/Í6à Öi|ò¢5Ÿ‘¢ÐðŽ;œv'_¼’€€ð\Äü³øöàsãØÈxtÌz:„®¥F´ƒeYª¥rš×ç_ž3p¬Ñr™Aæ°V@àQï§óÞÃÓ¬?t¿yQç¼òuù“ê{q¿]Kg¨©} *"4’Ô*«%^o|\¡Þì*$ö8®È\Õ bã>×MÈ¿i^|™|DÈ-ÐÕh£¿¹_”V° »ÛÞ'üz‘øbG鶇ªþL4Ò7 üw`wõ|3üH–»ô5AJ÷"Î-¸N kÝðp¬ˆa3»VÏ'©¿QȲæ3¦@L¶º<%URq‚yTÔ[@ù‡^¥WœR+ ‚.Èš„O…|¬íKLÀð§T~ÛF\4K"Ù{ÄÁò«õ¤ãoˈ³N˜•qŠ‘Âq¦vSu mfl਻¹¶Û ·?彤Á-(†óÇ$ ãç.òè._L™øhª¸ðÇ{Q1«·bððAÿ¢ëAõ :7èq“±Aý”ŽeýjiËbêuäÂÊ<¯ßß5_º…híÄJsÀîŠR‚‹Ëëiy„Åþ|^ØeV2KÆwç*|@û[”j´³(n˜Ä¨‚Èbî·©â ×q'ñ!ˆ#ÍêÁZrH‡ÇÈðÃ0¿²(•ÊÑUt©ËÕæœ]±jŒÂÌq;‘€-çxõ‡*)¢ šŒ ìntm[›ù6‡ßŸ^Êi,Þk5©l¼pH[÷ð}]aA¶áµ`3 °´Hhå'ÍTÜå°E ¬Ežüå‹#(á=¬Û>ti{fK‰÷X ~ý ¯Üçl¤Ìü€õžî™–1#"èØ} ðU ÿR-z…®·IÇÚ ÅøXr¯Â8lÆÉ+@Q+ÊB&y®¤ÆPû‰ Ê«©kO*;ý VŸÉ‡£cžõ¿¿zsž*èÔ/?‹å…›ºªÙËq–¾o:FÔK™D®¸´×ËÒ¥\{üÍäÃø3‹j½9|lçPQ-³Û`$Ø«Ž'³¯Nmµe ƒ¢Ñî;§Êù JýBš°ˆ|6”¸´Ú}æå³Yç%‘E5´ûîbkVIkiw*t*jeK‹´¤ÒzêWùþßjeg¿_±–öš"︜Þx±Ýkf€‘¦ÊĪB´-Kiì ¥š<9+Ηš»ÑÍÎX²j¶k:`¸E@7ªÅŒJ%ÇDïxÓƒP%29¬BëP=í D«aH¸Ó„Έ: ¥p¹Âæ…ö7‘Ë€ÀJø“"ïéñø3ØÙ\EhŸÏ8èªÐ4ÅCòù¶Ûßáwr]<þòù€æ°6ïl5Ô›Ó¯EyŒº…âœU6b"eúÖñý°ßÄ âþ™2Ô²=5,‹ã{´$$$¬&`<µ·q´*û¼(BÁ7‘®‚p»¦Û˜¤~¨õ:/ëÊôÀN¸«eIw=šþrÞiÃŒœIKc7íƒêÊ9ñsoHÿ5tJÌÝLüÒÏ&ö¿áZ½=’s÷vÂÈ®Iß~˜<¦'$nôƒRžpûÃ8#4a…})@½-ß=AŸ½P Øˆ?Iºõ3èàS/-ny¢dQ8ö¢âçfø5÷`š™’€€ÇXª\0àd7ýå[KF þ»ÃƒvôWD‹áñoÃÜ|‘Ý—@MÝy®¢b!+€opaÕýޏÕ“Û§Âò‹b (ê)àø~|`ÜQÂåè <0²ÜÛíÐsÃlÍÉ”æßêëõ–ñÙ~b:¬W0ͺZC‘Ät›ÀwN‹9€)‡Y[6£½ÈPé¡ìÖ‘0*,ûì73Ù2Gkè ‰ŸqO_±/Y꽄ÿªÝý~çÀL;jHË:‡¿Ÿwåà#£báÄéµòý!¨@æMA¼úÐ{>À‰c D<ûéGƒ_ÞhÙƒ™¾f„=­¼à6XY)§ÜFÁKø8‡zñVbZ m~™¶ ˆÙθ뀜êWN±ü ‡8»5S:K¯ÚýClE›º Vª0WÄú¿4ºQ¹Ÿ„Ã|ZåÎ g`7š‚i¯•ÐRаäÚLïáñE@}0ÃùV¢ìWç9þ9ô¥èfÜ\ãLÞ2KQ<1Y\FT@Z×_¢8æÓ/*¤ë„¬ôÅ8l[hÎø†ÀeÁauÚ¡èΑе}ÛNZ¶¢ ‰rŠ&T‰Kë÷æîkå‰j1çŠY1?cbM›eB}´gD]ãјL81³l‰¾?Šº&iÝ© >õ5¹c¾²VÇîMÝÊ b©®ºŽAþ‡íä#ÚS·©ìR錠ȲÁ6u6•‚ö¶Ýpâ¤/™g~þ°ž¯e~˜C7L19üA»˜7þd7ñO«’P0S(«h9(ú.ÔT#š»÷)r:ëýy=<åïÉfÓÂÜÆ¤n|!²à特y ¹døÀ ˺iÐAÈ3^fù8¦Sݨÿ¼Q’(/i6xð[ƒÙ¡M¸íbK™ãxŽÎbýzþbj#©wÿ§:î¤3æˆÊ;— DÝ€—`ú=Ùóâ©»Þºñ=hÑðžIº hX,ý%åð;gFu?Ç­ÙãpÊ4sÀ“[Ü%óD«mç êW,„ûýÄ6“º/j’4úÚIµ/sRºUκ‹ê7eánAˆ¿%ç(þi%”à-ó„I¾ ú¹õâä^.¼é^l•Mlϸ-Ó K8T¶o’+'¨´¼6ÅCþ$3µÔTsȰE"‘>éôX|;XœÖU5ÜyÕmO/ùT²P: ¼êâ :øpoËÚãKúrIg|øÉ„yÃ|<&lˆöNE›è¡áŒ;t¹¶HÏÀ)ï!’D=€a ®K)Oß±J¦ðhE÷PÎŒ[aåWGã$»®rÝf»_1Õ6u‰sK)J˜4*½-ßxMç$~ðÜñæÂ'W†®Ìü?=§xtº@G†£îìaŸA|7šï¶á9ª ]ذþ‘±=ROý§RHâµÜ0&¨b%X–‘¾.ƒ?࣠~ËA룄ø\;^ïìnú&D馨ºôÏs±þ%¾Ljƒ6µ Á¿OÖYÑ@™XígÉz^M'iw*ë¾rñ±«“–=>˼íeöžÜÀÿ×"4iÊ©ƒ+ªZÁ1›ìåkÙ'r9Àç®Aëð©ÌWF˜Œ9MFD›=úRWeÐKò¸2 Ååu¨.†M"ÿÇMò£˜ÄQ4ÿhÐ=ú’€€´j6¼‡Y¨ Š$ÓŠµ–ºJdýªw½U…‹?êë<¤†¼¥º‘ØC™kÁ8¯èž{4¾Nm¶SS¯ÁícWýŒ³þîÅÍ";í&îØÅ*ËR9P:ìMXC˜ý…yâÙ‚°ÙÈñ²ÙD¿X Ø‚Ð2Ô&vuS^Wž süRR:QcY¿‡ +(KŠ%½†sèp˧ Ìf‡itÿLŒ ia*ᄈ[ŠVÙƒ¥íiæ „;y’{.›ù¯‡axÐDÃ!æ*ƒ%*ŒdŠ,o7„z©5Ÿ/²º2¯•š ŒîÜ0žÞ¡VþÓ¨°mÿÇYž|F—ܬ2‹H¶®W¡—Ÿ£ ËÖ„ú [ ℤcŽ 좇rŸ‰„Á#ê±Ç=„Î4ñ\úö‚é¨÷ÏpõÁ…ضқîÜ÷ Gw׺äÎYHi7£ãI­ÆBì3ÛŠõ û–Þáðëw½Ì{QÚæÖj®Ë™¼®^†DJÂЀmp‹çPÕ* ®\„$n˜ƒõàû²‡—9ЭŒùºËì@ýÊ8žc²8ëÐ×+Ì1Åiáû‡5ÑK5éFø€V^fQpJƒ"Õ;¢uvõÝ*Œ«=¨•¹Ê÷ ÏïhšB§¨Í>²a ×½¾OŽ“±ñ|œ…£å¢HíFNƒ ”AÞù’mêDC©ïF¿¸l!>:Рp’8òöÈ‘3(Ø$°µ×™qo䇯=~S€³Ôƒáîåd9{WŒˆîú0¼‡ ÅÄqŸÑí,@ý?À`Å"O-ó†”{Vå¹uã¸*t‹ 5ƒhã`ÀJ·¡Ðâ*ÿMÜõÏ#5ñ´º®ñÚÈ­ë2í®½ª>M X©ô¬Š£ jÃÚ^²œ¸4|ÄðÛ`é“È£=5Ò”?›iòLå|F€2dæD6\<Œ/IÄoh׈Ä$ë a•&€[Òˆ®4`×TkB|ðÏcý¡Ì¸¨3ô€ÜPï6_“´Ðs§½ä}\$ „~6‡ÛÑ4ufƒ~¥Œ"úˆvíÕ|;µÃ³Sã]´~C„=¤øí[ê×[C8!Çô¨‡  `ê‚Ó ^kD傇‘¹¯'O!–s·ƒ†ÓUE±ëÙX=rÇò#é¡:¸Ö~Bòä%KU&@޲¸Àº9O’€€©êd¥¬¦ñÁfÍÈfÕiNôý€È–› 7f­Êm­ Œâ@L]ÜO(9ü… âªIø6´3Ð&w›‚»ü}\ñÁ*Hy¹`›]?\ëÞö™tÏ”2[ä2,î ¤óif“àš–x(rJê ­ófñ‘QhwW÷bÁ°_‘Évqãò`®@+»‚Vh[™»=ÙOög±âØ@¥HWѳ–6txÐbÏaÒý‡äãë™’Tbd8Óü~U;M¯eÌ>µe³ûx/Ä<3Ígò©g¸zΟÂvm‰ÍèO­ïió!|Ø~è(˽IØQ“%!Ý"<—nWPg鯡çâÖmœÑ“¹Yãy²Ó/Ç´û¸b+n2Áà ƒ1ÄŒ~ñ9ÏîÈ뎩t‹˜ÝéËü šK”ì[ÏUV/·sò£És#ÍïÂ->øý’!Í4 €T¼‘$±4šn¸@í Äg¸É«¼°>>ãWÂ6Ÿuq¼—6ÓØMÙ#ù„*ĸS—ô#Yž—\²…O f„¾ûÅ©ÀÓµ^ì‰ï™D“kôI-éÔÕ¥L=‘­w ×!s!˜ž„âïô#Ò!€@*ŸæÊÉ=✜A-Å‹!÷¬ŠÎÇíI ÍÍá6RØë˜’ˆîå:U^DÑ4zmÿÃý£§®ÜfP¨ôÿªñÀÁï5èïBšhýCˆU M+ˆ›~ v›ÑЕþj0r1Ní"K«xé-v•‹3Ê1ú^ŽãhˆõëM}ýÚNm¾-·.ÂÒàÓ;Y,Ìlêðj³D™ά…ø£DÉ•?p wÞÌ7ã ‹ÉL±Ù[-Æ}$­ªÜ< ¢{ßP'€Á“įÍ-—C©>¤ý(íYGŒšßª/)æ÷hjÒ9uAöEKMÙ—xB©1R†,À\;z+u‡‡±JcO BÐÌiùVè@AYvU°`Š”¥MVrŠÑjÒй|»Ýu72ËadòN^JuGoNÂ^p~Óêô]¤aWƒ©ÐòN9Jnù¨§éàR®yŠjY©¦Ae“„¸¡E4¨P>‹ÛÊ¡ƒ‚‡¤’€€©†î"<-r¯G ×y*ü­ R›u¼©œeÑÖteÖ=EŸë9p!á@ÿùÿØÒÁŒWcÌô=í¿Œ¿Ko&f܈‹ë”Ö:½¡2vwì8Žn9ÌJdEÕ*¸+©4À°'¼z£(Lªd4hÉºÉØœÏHµØ›åôˆ.´K«¶À® s Ϻ‰ç:苎ÈÀžn¢‚p`³£3–v’Ã.¶“ÅixÃ(zøÈÇ'NV%nÔ …˜êÏLµEg"(„G£qçêp:xØÿ&e¢Hˆ*Lƒ¼8)@a4Ü–ã›Êµ‚xÛ@ö,ÌŽÒC"ðh÷¹Éc”ä9 ažà à¡E¥êÔn61O÷édsEnÙëEï6§^?¯{t5µÞ9èÀÂh(>ÞËÞvÑÈqV'U2™Z1ç´v¾SaécåY5,ie|îä$H>ìÎâ]/ï¦|Ú"ý–4ÈÕû\eä&æ É–7´éÅ'ݳnÕCV}q ¢D_½diH€b&s•³©¬–a¿~æ˜5Iµ„4ÚB=5,“ú0Á*ÍXÂQŠ /\œ±,mS—Éjü†ôb!pEúŸ6ÈT®‚‹_t‘κ“¾Ð¾©ñà.üqøÇ.—D+ É1©—òët™¥<‡]^uuÛJe·hW)Ùô°Ÿ²,à$Ô„Æ$*"ózÅâVkHÙÙM ˆf6ç­Í; Ý€I ÛT2³¿ÔÄj5òÝ?=-CHƒínð1üºp„#p•lW×;X=†ŒB}púb}³]zÚ‹—Kwñˆ†IÄ ‰“Eæ#%N5‰³¥S’c\Ø5(‡È2Ç)’qüg}ì —7ŽÞËŠQµOlÊ|… ×8ÁèH‚Žf"lJ´PÊîcÂ>ƒ»­.dUQ‚P tN(Aÿ›í$ø ¡ ¡ੱäcª›VYnÙF3­2ß«u»ÏH•¦iñ¾qØgÖQµýºh[Ì ™a& ù:c³`…&9­7¿†Yý¹¥È¡ìttëxðOkBÌ*CÈ$ÿ…AÆg™«¿¾$uÖˆžï¯B@Ð9Ýü·ö3š!kû:ab¿Znœ †M;‰žõXíÓ»Múj ÿ¢K>°êK÷‰ò”Ÿ±ó,@ÿðò>|6bÖĈÑ'\Ú×? zôñ3ÿã’€€Ý˜¤DÄï°ÄÆXV "*ÈÊ¡3 Sc“Å®‚AÌ& NyDgÍ5<¾[ e{f J{}<8Þ¬ß:¥ÐVH¶¸ ·@'¢F2ùú ¥çÛ­gãUOGJ&üg=õ;½X©19ñ f×t+}µŽˆÑø=–ë[uYT>¬Ó)=Øuã—R둦O•MÒkvé~þÇKå ‹žY=6e Žj¥÷'â}þô!§¸¼bñhTÉ5TKÂÎݾµv(rBoa.;µPÚ/R¶®XhH\Åóíã—÷¬œløÔƒOµŸ”¥"’I,‚„À„ñL VmC¤h¶íg30¹@í¶þ—$ô“l'¸¸ ^ÌL+1´¬÷à‘d›+Ó`ÜFŠ[Ämr,¡»ZÓdvØÚÀ¾yGåõ‡é$Á¶`ÕaçGÿY¿â³ÛˆÆÞwÜ»TU©=Aû2ÏLê x­¹Z%ÞRäͶågeÌ„¤¨škϾÒX»YëFÞÛ«…7R<ࣜ,ˆbÉ0q•füu[·(yó!Y"áyÙþô«Ñ ¶›º¼81…–«œ£s.ûÃL¿//‰Ñ¶¡~A>d=zÕòÒ _Û•i|°và$h‚„sþðm“t;ßóN†ä;¬+‹¥PºWªâô1.ôûùºÆv|$ uó˜ÊûNâRbó ‰€7`î²%>nå,…&­4†û øaË^¯âŒ þ&`î¦+ïä^$(Y¦ÖIò0ÆeŒ%Àâ4ü0 P}3õR宥„~çW³Û"š7¶Ã$ã |¾ÑÎÝíë›p#ð'U³y@Wb“£}ࣧØ-æ‰Ò OF™qPq&ªvi›y>¯Ò˜¿‚çMJmOkOù§Ñ5ZæEÌìXx £è ³/^¢`•s6€ÞΘêØogŠ8Bi”çƒ *Îoº(Úi>(¥>¾zúI¯P ö|¡VžÙå1©@zDTã³ÑUñ„ôÞáêyélÔ·$ÂLœg^+¼Wsxã^wdHeë6®B;mß@q†Rï¾I)`¾À‡3!Nc8²Ô4‚ÉŒÖÆ±{SÁ8íIRÍúEØ„„U¶F¼‡n½–6Æ|mó4I'Ô­µIÍeT'«¡â`‰hôK!ƒÌ…’€€¯Ù08Xr¦è'"®ŒDSág‡Ú Ïw8³?Ôæ½ñ7!'‚[yç×ç¹ €Îd~¥‹cu:Â¥â\6ÿºtM/¯!µXЇà‰ç9õA³Î%(&÷ãÜGg_tôñ—úȈyLBã®òEkó‡1?›“vÁ=Ê¿ž$ ìcß ‰9Åà©Tz¥f«Ì‡Òñ]v,™ûá+¡YúW7Üà V¢ÉRMü $vDR \‘ n¦fPÊšõó\i€ç_oÌcù=ø´Ž½`g³˜Âö 8«|DàÁ…Ã:Ñyu/Ÿ#PÎY‡Fj…lX·_æöóµá(Áã ]F÷A"`±F6¦™{o<–Ä$T»åWðhÕ¶Ï‚/`/;e^ójœ þÔ©A_bJ‘íž2ܨˈ1ø2÷•ì*>8éiãÛé—åZ=IYÅ4º9ˆä!ÿ·aŠÃCi 6W}(›k¡|¯£ÂL ü>Æ™ãЃ6†ønŸôiËbÁÖË“/E=VËiÈ ©¬Ü²#!Ñð$ù¥àðá'Yïq;º€kp¥È¦§ŒåW4+1º”ðª¸'Š=›kAåâ¨Eñþï5pŠZàu<,Œ=ܸç¬BUÉUJsbKž‡3‚ÅÛ¢'œ2ë˜Z—’]=Ð6Tšgîjé(02)ÎtéÐjÇÓ4Ècì1´!æq8Ú7ŽÀZ̲ŽÃÃI¡bWЉpGT¿¦ê¼Í,?|Ø~w~ƒe&"sß& ÒÏ´Ôš·eöªÏçÔ*dm;D]Ì'wÔR XZ1OI€¥Qζ>cØj×çê|àŽÇ 1 ÏŽä“ø¯'£»6µÜ‚dÑÒpÔuNÀ(Òç§G‚¼Û¤^Ø DR2QãMÚX«"}~€àçís‰½ãî0†ãbø¡°²èS«}§ÅjëÃcÛ$’Zz7PªûÏÙ*Ÿö)Ë%Cr…°È °'õÎXsƒ„öù¦ Öo[J´ÎȶcÇP„¤œ¯Ó¥\”+¢í "AñH?9Az½§«Rôß9ÎiMà‹ØˆÓ¢êíL^‡$Ö$=Â[\emX#ÉT»åýšƒ7ò!a’€€ÚÃ&O1}Ñ–Š%ç´n'ô„ZcÕ›UÙšaó#icÔ3½¦Âi )‡ð Úè9Š×#ª;!”;¡fG¿™ìmZ~õV‘[ˆ&JéÁÀÞú‹ƒ÷Æ{ ¹"pÊ‘÷îûÊL‰[ ¡í°j.±›³¨–#]ÓYÅò‹#ã^ÝX³ðÔ zû¹³!ç—¥’`cÞZkü Å΄*Éc”Z íÀ»aFZ„'Ûz?Š_Üø=Éø‚q›™¸{JmØ sþU=0mXÍ­(Ñɘ|Ž˜Â„üï„è IÕSprG3¯B#ÍÙügEÜ—Á†/ÈYÆ Ú§RØÑ¢«´¯;@xže‚ßn§¿'{bî~'ÝLl±»¸œ”*~Ù?ø  Hô>:8MÞß¼4Rë÷f¥çnžðO¸Z¬žZHçT­¹%¹ƒ*†y•3³Ú'CÒü79ó_fHgõäRX„KÂÄà ­ ©CŽF”ÆÎØÑ\±¸ûA©ûØ.ì9ÖXf‹îšü÷æô®dÑï×~&®ÈùÅ}ÁÆW‰ã¿'bü_h=xŠÊèO;%KÃo—zkgpÊ£MTú–ì¶ÿ¯êE-’#ðá+¦Õ¡†Z©jjFO[ ¿$ë<Þn¼ ÙpQ’¶Ç“B£†¥¼×³]­L˜Íü Dz´¼Éó]™ ¸)ã4“šŒ˜ñ„îÏšçØÄAÓ*r: ±v”þC † QEæ;ÿo–UbãÆ€I‘1™ç_²ˆ,|õ#ŠÝDnÅ„YFU^H%ßWÕ©S|Þ`Më’K*@û»‰Ô逫­A¾’ò±b‹­§Ù4¯©I=ÅÝwέ§ºôô|ò«Tó‡äci™ £eÏi°øŽÎŒ=ßþò)}±Óÿd™í'^1h ]×C(3þ" F¯§jIe¹œgó‰å¤uz€*Vú-¯îÎìDZ1¹û|ŽŒDŒæÒþ‹ÕO‰…¯y¸îôß– '‡ž™ªÿ¤;–⢠}I5>﹫Zpæ9¹•!6Tßï­‘ž™/ó9&¾ ×:m`Å“Éí&üM`к¾Ë+»O?lÀ®ôŒÿ6Šgáq¸Ú“WšÒÅÒU;Xÿu;°®˜~s70¢=Ý8ϧ9; {9jP[aŒ(¹nÉ8•²‘«ÒúŠ’€€Êàî MÓºCw[ÞD¦)WM`[ºuª.yâÂ\ç²›/G†ˆÀ²Äc‡[DÚžlrÎÄcyÐã·[ ^~·½‘æ€ê-ÔcÌÅC„f§,·~\Ç*ã÷«_O`…Zs> æß§-YAc˜›_„Y1€X„ö4®þÎñ Ú4‰ÍCž=!µh9áyÝoâ„ ä¥ahÕµ†³À?8”¾ËÒ•<”gt÷mvD²&x0‰bUgS†Àaó~㸚Kô§sÄJ“öѳÐMÓ_ µÀ9)š u̳ÿQ¨=©e—’xmMÒã)‰K:ë—Ó#Á© ’3@¦pêAذˆÖ±F´NýEÈÑm®h™æË0>üST á°» 'ñÅ÷„S’<8Oümþ¶^;H@HN%¥vKÑíâÇr£íœX.ÁV™£2áê$]É`~–ù³ÆR°¼²_°ƒsãëe‘ŠÁWüUã-=ÎØf»ŸÕÈ`EÕ^¼I­@>Käر!«$*ÏB€«õˆ•kCF¡,@£V ZB‘I‹n°ÍzD,Ç€ z"³œ×n’’€€¼Ah ªÎ›cRüÁ™AØÇ€V}Yés¾Û¨ëõÌžR¹ø>A(äm¿€Ñ7<ô ÂJäë÷˜iD{Ì̦~p€òeÆ)ÓQœàî‘Î&+ÿ͈^ué9,öu¾ÍŽÂŽþ°¾/3n¡ÚË,_}—ÚƒzBcˆ‹Jyo’àÍ|©}$ÚœÀ¼çð›´kBóð„ËåɆÖ+®öÚ)ìK"bNš!E«W”ùÖê/«-í°ñ´ÏüÀhŸäŒÞ½±Å~óÔ5ŠRÙHSÎbNáCS¦ÒÅ »ëñ?¨kPÍ©æ²i¨e?†_L3¯ I¼l¢ã„𱕑 \àÂÉzßú3ú²ÛªU¾@è>ϯì%‰ƒ°å€ÔØeYú.yO+BËáf«!ú Àí–σ7só›Ðß™~‰#¯‚ð•Ìñö¾òÛQ®G]¹séÌÒRëRnĪŽ5ƒ'õ&¬èí(Sÿ˜—€Xï][6Q"E×@˜+üÒbx¡ B&oã3(L›g™%ú¢û}AÆ´t”~Žº=ÃBô8Å(6»yÐäš ºOy8ÂJ¼`-"ÏÏÈñö`ÿ Gþk9{5†Sjžt,è)ùT‘éf=Â`Ï1H­P¨%v2TŒ1·È)å>8‡£ç´•­ø—­wlZá—Å¢\^T)äaâ9±ŽØ:œf®-¾;!9È­1™”Ä8\ù{oS…Z\PüìjRöÏÙw<ü­› >ÂÜó@à6âx@ý}YqÌÛEÌSUœB¯:}RƒjHï3>ãÆ¤ ]Þ+»×±GÒ:z^Ú±”*¯ÞÄs|üø™ðwŽû˜ X-6@¥ GS‹‚JÜ6MåÚK\ˆôûå„xWÐú0¥Õ—) æÓ=åÃÉä¦WÈ~O³[o }* »wüÆýZ Àƒ¶ÙVDQöz² ÷\Nn¹Œ¢š^?ð W¸IE¸³AéC­Ó¯éF˜êqÅ鶘ҘHÜ-^½t »qf1ÖéOúò|!n¡ßöÜL5Ȥ9»?-c€nËnŠ}Œw7TŽò¹ëÚ8÷Tn˱րB'‹öÒÀˆôxÇž«ç¶ï¹æÙ{ÆE+Ü@7©Å »wæ—ÄMðÉG\c¦¨>_g½¬’€€¿ÃP+MØ*ká\ñ‹Î>Ö…P8AÚ£óˆùJÔ·ê9”b'×Éàq¿@FµàºÏxP#gO¥œÿjGÂJoã„1aªö‚ý*2?)R¸;-^àqÕØ†FJA¼›üÌTŽžØK÷ G ,ÂΜD_—­‡X_ê:tŠ×Pó­GP–®åâð®4bΗþÈ?tAÁÕ.²”Ä øvr N€s´Ð2é£î,²üøºC‹/:ÓÙs C̈òšâÈù¨,ÉuŒÑ¯Û³Z kQ&UM+qú/"‹(™Ô”äXh’'÷Ä2•6~-lÀAF ÂóÕ ¶Ûë,e¢n)½óí,Ý ô{¼?å. 0ê0%ËWgˆÙ#¬–ZPÓœÒsGøž×È]¶Ì6Ç–Æm@gå(R[¯ÊbŸ• fpÝÏÞ<}Tlžî<8úØ\ùHþWéX%¤Fþ©BS¯iVötR²ŸDòÍèi‹i$&Àò£rÒ9cÊșܜäÓ\ q±ÇÛY쌜H(H»Á S›C/¡N œÛ̃z‡VÈ…žìKa!ÀßU[f«kOIKÕ>H!ñЃ•< l A`5roôË ¢¾8áö®ºSèMÇAðwM,Ë8¡L3>×T õí½n&ÃÌX´MЋýù º¦Fþ®ÈÐÜ[ëÛ‰ÚëmÐö˲ú­Ü\ñyG©øòêYŽHï;-Ô\$ülDã#V˜bóEÌÞ¨e`&{wÅÆG˜«6 eÿÀ³xÒIý±–]›,‡F—R/£ÌÎ…Î°ï¹ Vû9dA{ñ_k~U%ì7Å¥Wýü–Ö¡t¶8©™X!ª'hTý9gPèÅå«Ç%O†•gÄ"™ÎAFœíœXÜ# EÇö¥2¼o¨z:o?t™€…ÏØ¨ ¡ë~n¢Ø¬¸éÝ®Ú5Œ-ê™._z^ïø\FL½ýÝf0âp‹bŠr’Öuþ°—¥é»í±pká¸-óòì²À=A¤8œ7_]b^áj]^'¹œ¾¼Løº»oQ•:5iF ï,r'aýú•“oYÏúoš~å V½3Põ ᇬ£Õ˜ÖtwÌëI¼¶®jÚ¡°Ì¾RPØ‚AD,²7¾V`¬âN¶á~Ú9 ’€€·á&õ‘U,ª”­ˆì˜QÛ5˜Ê4v®@éµ®-ú68_—›v­?NÍ>?¿ºñ½P%Ü?Ózdml€÷¼ëÙ £ET|«´½’ÂFÖú;ÄÁ¹Èž’ü‹ãÔä×¢Øb}U©¶ëÊ`SÀß°®läéIf%@zAfÅWU[–3‘7ˆÄFN÷R¶ƒ%M/9'Íñå­ÝF`P¿Wû*ÃÿLOc€xp5xÏmõ) ›éP0JJߌâ{ÕòóXÎ0=VŒ&YöÒýVI«Bm„ù“ÐáàÐwQT:™FOšrŸWÿOL»ÈµÓpUà”÷¡Ê5÷+Il {]CÊ…evtɵ¢«¾Q”w¶ šÔÕ™7{Øe&Ê«t m£,gï±yVŹÓB84‡TϪáDxv•M*LGîÞP˜õŒAá>Á`ˆðËâ÷ب®òZº;“K×o/ ­àÅŽ5•]ãU1}hZG‘»â’7k·óÊ}ÍÐ/m>2†;ÞÙ–È,ˆÉ£ ]¸%q`¢M€—B‚̬‚H¹0Á¸îx  Ñ8 ²”2 úcÀQ­A)ÝßËoïK+Kë0Ib''h^a*L7£&œ¶™Ùñ_ jÝðŒd•Áq¥XjmSå`äEùíà'…å¢Û÷Ža ߣ“#ÂQàºÑõŸ´é ΛqZ;ñuCÚä@ Ö5Žb :ªmñºÙ²äÛs’šÝѦÔj¾ßœw©ûñ‰Ê€^V~Åªá¶‹Æ €EF&nLBR'º N>Ê‚]–’‚#«y¯½½âO\DŠ#¨]É–4_2¹N~?õÌýy\ã_¢§Ø‚¤ñúô *ì_h£»VC4ú;–FM<%·ªÃt¢]2e"n<Ũ,&‘Õ@lÑAeôRþiжëvª²N3¡)<ç öÁ™ÙB¤Ú&¯ù83WÈ/~<„ð¨AØÖeè¦zo£ðó¿þŠÖÚ‹C‘=UÆ»âù—ùºgrâL¿å± ó|ñ©„ýœ óTà×P_µnÊè Ávúz©M¯yŸ£²+ÀGÜÒ1„³â¥öpØà þ²[TJ594¡I¯ µ¬)- ñW~Ót2ªwh¶öΉV /šhņzŒSB¼ÊôS„Sü=³Wj’€€Ö8ÈcÀÕs[.»C±Oî8 0¿¢M ¬%LŒÕ«ƒ*BѾi«#ÛoJYŸÎl‹»%D±7SÔ?Mâ;i$¯H1`b7›£;üÔ¬¸#7‹¨^á:1s¬ÜÈèínf§÷'ï畹©>(ÕFfJE߈«EÐý–Á>öbŸ¹ö–užñ?rZîÌ÷5²ÊRìÈÎÍ­8ÆVYŒv½¥%ÖS+ÿ½tÈUÑp^ÏÈ}n6PPˆ¶ йebÒ ^F"±óA¡Õ#Õrü³)#,0CÆÎô2"éRÈuBÁ'rÛ•ëOléóĬù'¥M€ÎM*À$úÌ)†µE V6Oì!0v¾ó÷¼~–h{½N«u¿ïÒ‚F†ÓäNU×D¡ø¹„2Áã¶F (“1²Žl¦ÎnÕ(µnHJó†£ÕäOp\íݤ‹×¡l’*£)e)­91N$Z£Õ†c*&>(8 —Æ)Þ¬T»Aê&-Á¤…v)@'“¡gy_†uÙÒ¶Û¥ûGýy&.&è$³nìÚ»Ÿí[Y{àWé¢õ…E¸y֮Ƣ"ÿu%¿Ê‘xQ„î*ÀˆšÖ6eÖ¿%¨P‚YFŸo"I꼬c€»EÅX¢ö€“̘Ñ„Ùð`tX~µT»=œ÷zK)Ú¯•†¡7+ìÁë<ô¤EƒÓ0bpxeuÍ ÕÜ9¬¾» èºYYžü `Y@¢·8@»*”°²,ž—úöÓü¾Ê+ç@Š˜,$ÁõT#¯u.¾­Övês³åŠI¹Ý0Ãb€È^±ãy¤U­…(lN¬!‡Nn+˜a#Á ¢tÃÎé újË`-µe¶7¨òi¦iˆÕ0‰vª!¯`ê pák‹¸X–nôheüÈèrÒ¦6£L.Ò2V 4LÛs™3 ½Ò ÈÎYÂ|é D$/I„G+U‹¥Þ cà® ‚ЋrЗAjÌ2cªý1>J’‚ˆí§Ãqp£ƒBhë`¥ót…—~ál…„\ž˜úÄw€(R×D‚öÿ‡åØi-À„wuÈ\_1ÎúÛÅfv±3šlóYã»c÷ŒQ€G‘¿0C.6GGBž7„¾õ5ÆqZ’ÐÌœ{­gP®ãÂ’pЩJUÀößÕëûCVîJáµYÑo㬑„\R’€€øµV0f"Æ:¯lÉü—¤˜ÍJ= êøÆ´êé“&À«_”_*¥ÌÛ Éo išb%vç¹^دO[\y ,b„¯…Æ™DŒî6's~Vê7MÊP"I.úLø¼ÀNË^%È›0É×-«{Åø½òÎwõqº3¾°©Ya“.¯ Gm”+j×^ á«A_˜;‡(ñÓÔ1—q¢b¥ ¬Wó¤ÔPHÅ/ “ŸäÙÍ —íªƒ‡GÁ“´6tY õMEþšòÖjìj=X6à°DèÒ0^‘mp§Õ!IÌQšµw¾)óÊŒÃ/«:~'ÿýVÑAoŒdR õ.mEåÈ…,æã•ÓºŸÑ²ÈÀ§Ó¯Ë[Fzkô¼¨ ͈®nå°õ¯»œ{pÐ ‚<—;Ú§iÚn–Rj8näw“χlù.|\”΃‡¿Ñå"…AßBî`ÐPDO@>T-éC úkµqÖflµñ&5´·dêÑ £ßÀç}2Výe“„Fù[˜:é\å “tžˆó¼ÄÎ!¤¡Ì¶l7åZ+AP‰œ wðC$¡”¹’®Ä¤ö·]Òܱ)×cª÷ò{kù¶qmý¡Ð}"’ÃMA,ÞcÙ—\WH)b“`‹àJFd›íutE½ò>[M€ÏËöYü»ÒS­ð—¸zDÆÝ?'‚(*ålÌ2Š+q˜)¹Mtœg˜†4ØãÖ‰iÑäØAóãB^â·œÞ7Î7±ÈHC3¾¡”9§çnO§³»©µQ‘k­[¤`G“{¯XI}{àž®ÉjFÕHøÀ2%?ô4‰˜! ÷¹%ÿWÇ=ûíNØ$³»wh®pql©-üÙ,FŸ’4º)Œ¹lxf˜`âìý*+y1i$ÐΦ¦$[ˆ^…ÃPniœ(Æ”} ›êWè)0’Ëh+œ* léŒG¥çežGpVLæó=¿"OÕøâ™Þ© 3xçOÈ=½›[›°—±éà=¾aŠä7bw‚0ÙÃÏÓÏõh²;ËnŸnZ!JÃ+RÀè¡©ŸÖ¾y V&È :ß”¡ÊPDƒÏ3bC¿äsÃIɲþu‹uÔÏÐöpÎ[1WxÔ@¸;åèˆÝ’¬7ìöqÉäÅëx’€€çõŠˆ†a¤ÙgÒPéË$ñ篳+ÿ^ÄSÙñTÒéÉ2NâMnJ°ƒ—ô“ñC%GM„åƒÒ+•¿y)än…0ºÚ UN˜Òþ@m"Ϋ”¤f"40ÊGGLZœŽ´S æ¤©ói¤À PYøÐJ a„GùTY3Åj0ì#\ƒ<8\Žß^óãX¥+3#@ÒGä¯ +UjŸ–+½ÿ™Z§ZõÕÿ$?¶Fäkyíõ×±dÙs)R´o£/WâÆx¯ 0t–‹ï¬#ê#JN­ÛõT>§ý÷²çKƒ?èÉu2n¨tj·í„ÅÒLP]þÁDðÈFàÍú²Nx5Xú—ßìc6C@qâ oV¶d9 }ш'èʤ»Ÿkóûk2·{MÓ¯òp>Øåë gßBì¿SV ÑΘˆË¸ÈÄÇoÇ?‡xoî?eëü‚‚¼<¸FÙ¢K¤ïŠ@² Èñó&+®K .ÕáVÆp\çÿÛõ† >º1EçÑŽxîQç”Ä›ëøH+xdexÇŽ º)·÷by‡¬¼ÜiDíÃAu–¢2‰ÅП2‚Óéz%Ô E=çáksÊÃ+š´¬ÝAÛ¯ŒW0Å3ésªgÿ™LzÐ|{±®u@*í½£qÇ@"+(j¶¢b¦òïöN‘ÅÉýáW<ø˜§¦Àb‚HþØ@ñ"‚ê—Øuk2xü9Œ5*Lp1| …Î÷%Û[ãè|dÁWåóÌ™ÁJ1’ÕQðí(¢ÖURí3Êû,‹Å pÙ8UÕÌYþjÑ‘[Ø}µèã9;Ø…G¼ŽI?~ØæÀÝ¡s\s»0.Žàw·éäÝGgůËþ½³We2¸ÀªÁ)B¾†M÷ÒYÊ ¸µáEò(p|bÿ¯™Ñ›”0) F XøC=î-PÎ.—N3°  l ªí.PÁ[ÊQÅj@,ÉÝc[Í_èv¼p¬*E±ÿM‹ôÏ{%GªS÷ý‘Ì6£´üЄÄ=ÝÄñg'ûSj¦ZíRçÓâL†T‚Š:Ðp†¹#§µ;ƒä(?ójH/ß0ëÍK±týRÉa @¯dA¼QâtèK›¹}|~©Y×ß*|«‹:¡úùDçÊäz„'ý¶÷·RPÂ)ö#…ÉÙ6í1¢îH-"¥zûr†FÏ›6Äq’€€Ää…:§®Ðá ˆN·1 âú¶1APf««oío§TþVïþ¿ßYu"ƒ®ÀÀ±HP)5—ñ$þgqˆjpLÒÓ"ï`RDg’·Î1‹ V’0çŒ?ò>Slc7n0 2 óË%häó2i+›X§ V"9Ø#⼄í:%îñçBÎ÷ÄçóíXv Òm¸“•{˜¢g‰ÿ¨eÖZ¿N&z]ÆÞw¿Có£à˜~-öúxWÃÄbÜPó7 Ï×*sêÏÜ{k*ů’ +çMÊuÊ!‹VVçQÄçÀ„…o_Ð\ …•RàƒZÑ7×®¾‚†&´N(T`ô&0—?ÝèQ¾¶a1˜¿OÉŠí$%»ä…|"Áfê’ïx…š4Ñ^Up óø¾Q˜^<í_@h 1 ¨½ÎÁ¹¬îm¦;Y»Æ4'+3qùd $p7 >Ñù3ߎ"„³iíLQoø¶N¬§ w»›) ÇS˜®µ"Ϙ (ïñ„,– ™e%ÛË'(:Z›2;ŽáFZ3A¤.¹É¯›™›Rö7tÒTÖ7£–x„E~«]×øÇ âдr!œêÇt~¶Úbž¹ÙôØ^Õ¼¸:ôUn©`$/Æ„‹«5 "Ë95 äßþ»œÄç¦sE͘xÒføý…S§ü…"Ÿg†R&úÓÔ4#ne/:6/7bÕ íÙ³‰%™gh¨±oå:hÅüAu‹p}ò ¦Ûe®W‹·âxÅ ÕÁ×)¸õFÁîûØÃº‘‰“ŸËÞ ¯Gdö®Š>!oÆÜЧ‹þ*qm.}8hš#EL’€€Õks&Öí¡ÿ“›T¥˜–Uó"Œ<êkV;a`Yg­u3¢tÈ5¨È¸ ²Ê›‘#ÈZÄóÊã×/KøþrÔ8Yó&1 ¥¶' ߌ¶”Qä¶«ÂÈCXdßtÒs1ͺ¬Äž½]6bHMÝ~–¢ÕK¥S<1¨è·ZÆöìé<ØE„Âô…ÿónëü'4ûïâà‰JÌÛ<Ÿ,áô7ŽZͤP¿³,1¿tí[NA*‡\”…bmJ×yÔS¥Âî§/W?©& O’\ 6T”j«N¦3ÃHѰ™¦m‹aãä¢2_’éìM—~"ÊèlÓËW]ñRkeK'TàZ acvW‘Ú¯ÁcþuAQì‡ãV¥X“ÝQÉ&>ïb ´Ì|J­}8Ì÷×]B”ºkè.q½|ž×`­Å@²å ËsŒþLHœ0̺„g‹ÎÄóhckTTª"CjŸWÃ:zƒò+Å¥âÖç§™VvÉp°ß‡¶;±óCÏÆéò+$Òî•„²êI1^ø¾aXÙ÷XÙ¼Ùsbo±µ4ïßÜoTdˆš-‚‰âãláÅV“gUFô†Œ03¦íú†ÖÓØÕVpÞÌÞè<•U,f ŒmM·'ý¥×Žbƒs&ešUã ™JG€Œt«çÂuzTcäE>'í |Bïô‹“Ôz¸›ÊР! …9‘‘¯[A“ïd@ŠÄ5–wæ¡§õ|°ToT‘L¶8)ˆ©Ô|uÈD\á,–ÖÄ•ðyÍ®fêë^bÖLøc¬÷÷B¬Kˆº9¶Ç7ÌrùÅdznŽ*[ÍÓùDnŽ2'åÿ x8mé«× ¨xÃßj¢ß34NÓ=‹u¤ú·þ§á EksnéßÊŸÆ‹ Ó$F4i€ àȆÚk°ºuÍDM‹ë püí9³ríávÌUÿüþZॅąBCŽÙGšqJS¡–­Hïa×/Þ¡S<_ÿòu‚¸0¹–”ÞT©u é‡õ–ÛràFÆ)ßjtz'çæïGV?´ 9qHOiŽŽ¢ÇmŒ,Ñ’Ùr›D­'«¤ …J9,„©õ;s»9\?«N¦àà%Ll/ýnKic²³,D,lš? ïÂ?/âí¿ôµC­ZÖV ² tñÀIz²ÄêÛeý‘â±zRx•Öí’ÒíMìêS7ϵ–E>.Cn£¢¹«h¼j§%ø_1Ú;ªí\ Щ}[¡É~²k«åŒ#mqïoä»…†¯hÌ·BÉsR¾ý´n¸¬ÎÏjqI=už3D/,ÑÕºÔO9ñ<>l!2½ÑBùÌvLj½ƒéÖšë8X» •ƒÔ/cÕ‘ò¹¶ú oÄëÛue ó‘§Qâü¹L!9'óuaÁ9Úñ¾ß®l´ÌåIš›ý–¦ Çomƒ³±­œÊýôðA$.Xаž6ÛÍÙÑÞ´ý‘]Ö ‰fPW¡èò¸BjÒÕdô Õ`F@6rŒ%××f§+“ï;«^6ŠpW‰™þ,î âɉª|¥ýçl@VĦ*Š\þmˆHÔÏÅy{éÞA{LÒaÂóÃz¨#ªÿ€¨4²Ï˜ªU6ÕIo©… …ÂîQ…97f¹ß2üÃ¥üùÐ<Îbµ0Xì´Ö¸C]ñæÃì¬Ó ½ö<©n JÌs[äjgäç]<¼ ýÇ èÅÄf&ßð›î(ž5þ*¦zÆrÄÒ·{¤âiÌ=³ÜŸ MË HX„†¶ä4ÿ±÷É⨾sôåµßR[çY¡ñ!K†N “‹s×l_Q®¬¤Æ‹&Éós¨-ñSLJ•X¥˜×óû»½l|ëçÕÇÝ,‹ÓM8S@3…kÿöRûµ9;>-–"­ )é@]Ð<ß¼vˆ¡ @œê¶Ï×hNIõÏb, FÐôý¦ ›è;{]^èteðC™í´ð[wE$'ŠoÀt±éâÜ^ñáò»»Íàö¢Ä<mÒ(ñ S  NY|5ûV`ïÅwØ¡ñÿ¹£úí-WùéŒF¨j¼‘°ø’€€â‘þ<‘ùPÁÙƒ'ª P·wn¢q§ :uÍžwcÀûйÎPÑòšU ›Ÿ öÞìâÏNM¿ÖfªÍ¶PP#d×OÛ2¡óc20 Åü æ²ë ¿q×CL þ2Qw²¬ŠÊŽÆiiÅgÒi =¯•– m4ÇÍüyäé‘'ŽùG‹iª¨ó°¬®º âú¬9ð­â÷îT"'ÖE¤É7‘@Q¬ªãÓ³ àÞ¬‡gc+©³}¦\€`ÔS! @â{MPœZªüQã“ûR«»~+$öâæ‹¿‹­‚GAª&ÚYŠºQêâ…£jR <¬›Ì:ÖdΘh®ÝÁ7ÂÏA5¡QÇlF¤™~D|/%ø©êšmDV¶°Nè‹Ò44rlÃÝ¥·»N2‚ÂÐ3 ƒo‹Å3ðZ½‹*ÛUt2Ñ×˵Žuùµ ¯ E5ðm•s£ÅW_X»åÇçîó¼ÂÂG8%Wÿä=WJÆ,z[…0>ʤ6C¦´htùµaò`°EÉzšÚíUðhõ<Ç%xÍq¥ØFˆVKBÔ²˜y¦‘¹ZÌ©…vö½TËõpk 8Äs¤“sëø~«Aà]ßɳüʘ‡"ž«Íñ·ÇF -ea†²èJ üM¯õ˜U¯’¡\;MW¾eÅq@·W­Ò…/äË<žµ¹WíNÅECX× ÎNæƒv_GÛ·žËÄ,“×Buol‘q—ŠàÖqΗuåA¾¡Ëaݤj;ÿÌ}Z˂İ+yMÏ"U1|è8>b:¹íQ®%£aÿÒéÞ›Ñ= 'PVãUÀÒêÑ”øèB–jÌnuç Ž4®î•å.I€4Üœ|¹CŠÛ ,®<øS<üIçgËøl_oÈ:^r¯¶"ûSØpJ»–˳EZØ “ÈZ¢(gng#P‰‰j‘,¼Òø>Õ -ÃXb÷L .Ÿéÿ„Wä¢$B8—¿9ì”° PãKB6ÏÕÇO>Ÿ`+üÊ·%oûtû‹M…’¹ÊÎß á¡Èƒr¼ ý¤ÅŠ5À‚QË÷†cš>±Â9O6RvhŸO·¦<šæŸµÆ»Š†”É_¢ G åP#^áñ©ob÷ë)BÃ]çNá§1=ì¨e«ÖŒ˜ÇãÆ$ÈV‡3¤ uÕÏ£§Òqx_Óuh‡üÐäm“0Û'óð—: .×ôn@K—Âþo?´Îb,Òp;âë=R±Âíŵ´çþ(ñýí~ŒŸL‡×Ë—&ÐÄðËéÏ!Ó4ÀÔC’NÅm„Ѩs„̨Ä«5ÅìB´;÷÷˜¿3ÚaGÈ G¿€È± F>žº\r®s |àL o hâ6¯5‘%l¹–Ïõ>Öc›5+·ǩìîÀ=·±¬­줦ëIä³;‘® t»íp̃˜åL1y—[¹ÜpÊdhô FŒ pšÄ+˜r-w!g)Þ ¢Ï-æbáï b=Mýh c‰db ¨Ï×ó{殤f,ðÙJgHGld¯Hù’Í¡@ÌÛØG<Ð4õ|²$^…iî^%ô´vß)~êæ±N[YráO{Ûä9Çgîhûp͘ISäyKÛÄ‚ºÝƒ<@ôüaŠ¡§"™RµcØî0ôcküœ)²¾oÆä½!ÒnÑ¿²ù‘Iç[C¨‰ä6¾¡ôJ2—?–²u)^ôúŠçä Õ¼·V¸W_ è-­h8\°‡4·™Y<Æ2c)?¼7ìøç çìï®ÄÔmNV×%ÌjÿvÏ8WûÒìâ“›~HÁo”¤?òV»´\@Eä¶¥ðíÑïÖ|Áˆ<± A1ô0ÓY‹A*e~thßZ2 B j«È<Ôɹ¯gµýáÜD%=Dy÷ÿšBYz?âf̨¡2X·+.П=6ð"#JC«ŸlÄ-§d‡ü™çĺŒ³ªž“Cí´î=£SÐ7iL¿éŸb©DæÀm°,Ôhîmg‘„§Fò»Qâ5æF²,–ân`MLCÑV ƒï”2¯’€€¿”½†hóÕÊÔéÓ²*£B ÷€ñxåW¿BSÔÃA˜ïàJ)VÖ2o® ´“ ‘wÙ3ðûÕÑHÃκgìˆ÷Q«Ñ°Þé¨üèÿ«ul©º1Ð;èÏ[ÒRý?Øä–€JöCþRÛ¡àïK©X'‹s†kG[z.%¦­y[°ÆIJ±!±Â‰Î”¬íŽáÜÎðùú &áüJîáhÔtqÎô­/‰`ÚÍÐØé¼W\ŒÃÉ+bY4ÁS_FˆKñ}§ð*ïTܧKE”›Ñe·V¬ý¶³úÎ- „£²yA^×mÕÊP>‚Z©M¬—9àLYE¨k¥·øuþ´iôi¹–ý—~’qAö3™WºG‚dØuslbtž/pçÙ¸ùuAƒé‹~ p5È2åõõrDŽlªŒ.D²k;t œtX“„rx>6Ñ5» …¬]˜ ÞÕFù(1Òñ4ŽPh¡®©Ž¼åÙ~œéI”o½EG.‡ìײz¾ÍëÄïaxíWhjœ jsØ`¤­W &UË•¡àLôùî/Ћ‹ë3Ô½3Õa£á†V˜¿trbìî»L†ž+vÏXê?‰À,%^몀,K†Ið ލ²»¬ô“Ð`üu 7r‡ÀŽè˜{ßÅÈbŸ^Îó‡¼f@)ÃÐ"ñvÓ~¡¨ê¨z¶ü£!6c K©Gü µîi¾6Ü·µöcÓ$ñÔ쪌Ê((q««ê¦îb]]΂d]‹á©ÝÑ)sí ‹r6YúÇz$¯QÑaý›‘0ô_1CnN $µ® ˆú_ìÀôÕð|^ÙHyLm9Ü„аâz¥ÍÐGÍGˆ'W 3Dm".LûÇ2ÏÅ–/*>FÝÍܳçFNÉúÎýDa:<ê4l Ô•—~PÒ¦LýwHçúƒ1T‘÷[š83àj`u榒©Ôæ£4"|Õ/¸yÿå1ä¤ï=..fÄ –\’€€ÔO@4Á‡Ø‹Ùzw·[³YÊ1_5¬ GÔ ÁC: ®ƒ´rAºÔhÂäL  ƒ¡T½ÛoEQzuóMj\Å1¸´OkDnÔ–8mÄnàû¨:ˆ­6ÂÔ8.9 °BgÀßåpÝ·0¡pž!»V?¯¥ ÂWC—[¼•'O·„rhûÃè‡üê~Žæ ÇɘΖ]„UdcÔk/¼’q3U9ýV ò ŽõƒESŸuHš¨ù^þn“ÄO™Œ$ÏW,àÉ[rJïŸ!¨ù°¢JÇ0ݵOJ–7æ£Ò—»+‘Ö%Œ4åo–êàÜ„è¦DÅ^0(Á@NófÏŽb,àÇ$YEÃMõc½ºOú˜ê¾´—Öé’Êo#%3?t… Št.ÔÎ}žÕ¦‹v 3Þi}"—ø©ØÅFþÒ{Ì%¾Ìò šÔîRϰ-•y2Û Ug^ qŸIóÚS÷rb÷·®mLrèE†¬&Ëdø´²MP³XJw<:Çû^zÞÌŽÿ+¦è{€SŒ¯V¹:'ÌSCÞõû¢O¹ƒþ¥¥à²ð\†–u26»Ñâ üýËŸeï4ˆ ÞÚu›Ûåˆv»i¤“l81º™rôB«Àì'ù™—}ƒRïh*ýF è ¿:ñåOÇ „r á|qÎD¹÷Ò­0V!ñõøõðŒ)5+ƒ‹³À3’ V‚y?:PJÐfE™iäŠ)ñ…½ Óõͽü×ÿ"<<øDÈù÷Bo²Ç”dkùçÁ/¾Eûô®ušd68Ù::óÒW£1MàT© Øå’2>·Ád –2zÏ›3Š¡Ãà Ø…©eeuU…¡,ì Kû»Ü&í†àGßpëÑÈh±c/˜ôÃR<4Y®ŽÄYÉñ°m¸N!Êd`œüVL´©ªŠ±^ÛË•œ ø¥ hÓ‹‚M›b q—Õ.NU‹ÜŸÈà²ëýŸšbÇ)³¥á!áúN“J,ÊÅ0­cÖ$Øðšuq(è¥Vßž›>.7?—~$ârmÍŠeˆ¤qSžâê UäsuW{ÔZíìÄÆ x´C=ï“á;Ñ¯ß ä]¸‡`;yÙA»T±Kö£uù1nQø1Pº‰ùá²Æs€`ákºTép—D´³cçz•„'’€€ÚÅã¼~@¢JGÝÉP}+bMh¾zè^Ðâs5N'‚ˆ±æÝ™ÊJÞ)x“–gs÷YÇòG§„ç´dr¤‚Ý+][’ý·ØývdQ( =¤W~Ž@{ã:#^׋«_8¿&zwox‘ªßæÙ< ÌNÏ#*ÕGmÅ@#>ì«U¯x {¼Êžƒ¸ü7‰·4JÄ |)ÿÏqç §Úµoô¾¥•Žϵk¬# Á†Á;Y(Àó7è{È“ø"ßÄk«»w¸éY! X…ÄÇ>$Jæs=¡‡‡y5W•ýR;¯¦¦Ð1«Änê1Q&¦J,@¢õÚ(éEÒ#7ÁßäÕnIå à‚¼EÒ4PãCŠ™D}8¹¦‰¸¹7Bàž}hóžÄ}v]z"7‹p#¥ÒÕ§­®Òv1ÓD7XÍ4ª¸5æR|ÍÅ¥Æ+®–áA!¿½~1qî õ½hÓ…Wƒ•Ò…Ï¿F2CMG”ìÙP®Ð¤ìÁ°åÓó\liŸ-]ã ZÛŠî>á;³´â™wGÖ5<–^q5Æ Á°¡4Ú‹ eɧԹ¬¯óÈÉM臚wÜ‚-³3œ ?9<Û)’¤qRPæ_¹ï>ù±>dÿP%5%ª¸ÊËÏÊ6@NwÊ´^¶w¶`wŸ‡zý(œrYÉú-Ù¡«Ç×ÏT¹­UT^Qè¶x¿“fÚÇéÒ|—Ñö¬ù:jÌtÖß}zŸIqs€¬{N´èWРî;Ò`.ØMÚ­!ëÇ Ù;Gêë*i/í‚ËÚh_?^é‡ÞàÁ(Ǥæ‹4+4´÷åøAÖÅd´ËþVpk{ßÜùm‡h}}“á ƒt¢w2n‡ÞàÆ•ˆë}W›"ç”P}('Û\³3&xZxÓ9¹°Ö–‰ÍÎu¨|n¶>ÞÅn>A¦È‰:¡úè`4·X¬ýüã. íÉùÏs±F>Ì»¼Hàì©«´ +$•n ÖgR¸·‘yz”³y=î<®ò{çK;»üý$±ÔíÞËó\U<á`Sõ¦ŸÁ¥.~VGGY¯^ l·7nñOîuÏòáj,Åáþb FGÈ\d“ή}B™ò÷mJ¹Ò0ŽY#á ”“š¾\“»#0òF&/‰°à®tz‚xг0ÙPÌñÖaß…Ž ºö@)ÖìÇ6‹P3ƒ!ªçÍ¥Ãùqf<š×‰n™.>ÇC½ŠƒHÓì¢û[ÔkõþMøo¬Ðþù/°<øˆæÉã3Ùœ$À¾<^Ù{|òŒño´µ <á"¯ÜkèI±ºž3YDþ«éYŒ2 ÉaZ‚¶^Ö|ü”rk– óEz_¿©ªcý t™LÖa®%°ô¶²ÊG·Ç¥¡ÜÖ‡ídlÃk1B¨$·7ˆþ°KºïIéèÿûj!A˜$úè£é’(~Zâë7ºÕÝuª4¨ü8Cç®O)ZQÒá©=^ åúƒàúÞ:F/)üÕ‰õe±—-‹Z9t\};^Ã僡›ß}ÿ‹Ú P˜S‡³;â¡ØÖU#~/9ýÿõ•¬H5Nhæ&ÊŠGä‚Üä]£ @š3¡5† ¶¶Èr7å4Ɉӈ$~G^øÐuŸRkÑö8ÑÄ€ ©yoË$+a"ö­’„¡Ö¬p-~l Gßwš¼‡ÔC© Í NócË{ sNãF ¹GsèLÇϸÈH¾=´–þ_¢à‚Å”hyØõWÎ¨îØ¿òUØlCÇÒéÞyÖiÆë©PpÎïY–б ÿË÷‡$_Ü|²‘ÕLÅú™Keè¨À# gõRr´vÚGÁO-U±-¼è4’”‰4EMRhªX¸—WéJxå¬d²ñø=>P+=¨¦0YÜ µË[ι*+J֚˖²•åÆ?Ò£ñ­`&oÅéµDÑh ?—ªðQ ¶M£Rï˜ñéåºC›F¢¥¯KÊf ":þ‹´cÝ~kcñxŒPÆ£F ŒÚ33ê3S…V3ÐúE8¿mò2e¤?‘[×Ü€>ÁƒMKã•û£¶ÂBF~øÓ;‘¤ˆ&3ƒ_Lôõ‘ÝËFQeHè#x.QÌÂ,¶Be·Çëñ’€€ÑݘeòœúV¶>€ÐûÞý/Ñ”WãØ}¤›Qf²`ºóë³L ‘˜ÒÖï(Jšap._í#±í„×sÿhÊËÖžüb@ía¡O_¤nnÁz…ÀýWþÂêÓÑÀÙaOü“Ú•m0d3GF韅îvKy+6%ñÔK@IÙ$à¥l% ·ŽB!Wi¼|Rƒþ:³2•¨âëhÖpÑ&_D‘QÌbPÉá·ª4–†ÕbÏRÕ-+m föÆ‘øF zTRIê™í)gø{Ƹ۫ð¥ñŽÒnå‹fݘ۷Gå¯Ò žy•æÂ=ÅUe£Ž?nyñ¡Sa,Õae’˃3Ùªn¶^Nb×”`zo34OâóÉ!ÕP@APTµLœ+‚A s$€53ŒšQhMöɸîø+Ü8sºÄ7­Ç§­Î2ò:H¦ÉPðJ8€$çTÙŽÆžüyH6]f#ýø †»ß6ç*÷>H!’j·*Q»rkwèÎ<ßè| ~¹¹2È×y9ŒèòR^8ÞEÀ%8QÃ`õ®u-†ãé$XC8æ?w2F-4–d˦°vÔ<Æè 3ø¾e ¤Ùahˆ £ö÷¤„»‚ß4Fi_õ~6wæ¢ÀÐ]gX¶:énAöNb¡ôÈ"ߊíÄpõ÷LE‡Fo϶ŠÇ•hh4`BDrÌý®ù’±Qê¼U ë0FÑŽÃ%iÊ ·No\‡…õù¢fÐV¡@"‹¨)Óª$j•³»èúHÌÚdƒö¬†#ÏÚ1.ïÂCÁ`§s­pMeÚ¡Ú /·•Ê^à‹mÎ 0ܾªvk8ù>ºýõÄP 36O¯ }j6’ 9ë´{dÊm`jÒʇðü¿Jlº‹uvº[n`y çáäe0®¡Ž.>â}Ë,K¥Óhýö©ô×ð4_rØfTo~ͧŽÉºH,ð0/•‡3M0¼/¼º¿kÜ.£",²˜\ú/À°¡µ»}¸‹WäÏ“çÜqk\hÈ]?´É{’Œ~÷Á­aÊÁF‡¥TV\7¤>Ò$:ÕÞ>Çͼ’@[«bïëP§v°ÏZý IùÐrP¼Éo¿ÚõômF­®®?ŽÓFópþ¾O ’€€ÜæÇ]²j’y'aÙBÝB„®xmð#ô¨câî0•I³Œ‰P©aÖG¨èj© fIÇN Î-Æùž;ñ¦<$}zH³1 ÷ÅŠ"x®¬®¨¸VK—‘Y #»«³€¸*«¦ÓWǽ½«â•ˆÏ"šû¿©‰Ò¼’id4zàüýÏßR˜ aº“d¿ÎrÄ.K–‘Ī÷£ÆºÇ¤êà Nju²bmX³îÅ +˜À7RIÉt³ï ˜xÂ;MãÊ|dv_ë¹úÙˈ¢í¡‚ð—ëÙÕátÔ§€›Ø§ K_K•|; } ^Ÿ.÷ìÚX­Ö^7ú3â­:a ˆIà«<,GT±„ŽÃÊL‚[#¬saÔðÞËÒúÇÒèÄØ õñ×$¶Gôõµfüv\yÿK[–¶ðøàªëZN³¯Ûí[üiŽÌ%’NO*(‹êx8\ŸÕüýüä—Ѳˆ³ÛÑD7‹Š+Ù‡;jšî6„ßG2ØÁmkˆö¿ÌgÅ_ëUGg†“¨Z˜^ñ€Q–®^K.q%ë’‹ôhù\1 CÃMFÒ‰xE–l¾a|ºµÎöÞ1†H7W° “ú7 ¶dƒ°t“ûR¾Í娰ZOÁût9q™¤¡î-Ávà[;2çß¿[qi›Ö„(¬ñ˺'íÛä,‰ã £wNÛh<Ÿ6TXWžB`û(ÆÒ6tŸL_ƒ¼Ált@¿ö§[Ñ&'0‘Êÿ¦ðŒY”åÍ ¬× ޲uÑöy°`÷Nôn4 Ôºiâ‘Ù Ö+ž¬Èô MwwùïõQím`ð†Gdª*QŽè–yHsá’,†ÊkGï£Îï?LD’ªÆ2ÌLã€í”Öµ¦§Ž}:ð™öäÐâbϪKe»¼»[ àïöš„ÝË÷koOþáÉ΃mÊú Ó¢ÏÍ2'<èK¾YI)k’}[í¦þd˜@üÍ"ð`ˆªUaŽ¢zly Öp™´¹K ©V?$^q›jÛòà«&ÿ!„ö§Îô @ß;â×ê.o]ܸ® ¯Ê©Ö(ÅlÌ詸š]ßXääΧÝû I*ëVœXöi^ƒ ÓhZÖóëïdOÁ^X¼ÖÞc¢§F‹pØj¿;ŸV’€€ÕÍÆ€öciÇõkfIŠ2˜±l›g,¢Ë‰SÛÅžvcSí‰×{'ºì2ú–ï³ÿe‰® Câï¶g€™ê/)P¸Œ„h~ ° IÜmçWC û<ß‹Š–å¼ æÜRŸuÛ M®N²¼\Ã9_\†c– Ëk#,äÚ¡!Jü‡hKä‰ÜˆrÂhλÙNõB”lÔü¾Ó =bCTe¨‰@B!}I„± bº¸ô9WÝD58²Û…¢kìçï9ÔÌ ïwURº­³¢vazt–=/Éú–éöK®Õç-¡ 4‡°éýQÓéç4Íñ•oÙžf»VÙÁZáêH˜uc£ñÜ p(‘ÚVm6ë&”ºâ§)$g(m÷A9¥WpÂàvIß$¨*ƒ\/vºóŒõ÷ubš°CgzݺNFôúX¨ÑMH¼»12 T<˜³šÉ#uïß¼ †¼­ú´1°Š‹…eé…²óôPÖ1ɦ+ädVì/óì9Ï>¦F•›eéP­z“jˆâãr;“ªdhšDSÁ€0‡í §kÏ4÷FO÷‚oŸÛ[îû`ï]b¥^B(&}i\¢y •MÓ!~ׯø«@~u=Ô,ýŸ4^ݽÁÖùˆú¶â2U#bÄv¯[YÿŸ²—$KHcL¦Ò׺†ãSñVT.› ±\ÜÍ3qµÁý>ÑÖ™°¾©fKmO»ç\‹%º4£]íè•¿-ìŽ%Âbl”Ûï3ø¤ŸÂù¸ZWhÍqc¤„LwŠbí ³9vÆÛÄE¦Æ!ÌÂUÛ"é1?Eßå껫Ö'ŠléÖRžÄۤÂx’òTMÚÉ´‘–‰)ãNinCy;ã~ÕœÈ{Óíâ…ÙúY™—o14ùå®”ô[R=åͤ5¢l£¡¸÷:Ó„†õ¸xa¸Éu ÌCþMJ™S˜Ø:¢…‚(íÞ½MW®t3L~"9½Ê¶ÒÉ—$<´µEÍ%!*†®]îj®NÉüô#?ý™fÄîæ‚–”ÃK«®ªÚ.ÙÈ–qf¥ZÓÏF7Š=ÖºMRώʶqKÀ=evõ¸t‡ò ‘Ž®éJžPœŠfùºub:[³'øÿ‚áFuìò¯3w¿¡‚Ê0°ñq^Ø@”ùïÒÂ’€€²ª›á’ík<ÍëCcâ[‡Ü‡”²Ã,ŽQ/( ²ˆs!b>L—Ì yj¶¡,Dÿ` ]Tw©á„‹¸‚új¯»©ÿ ÷*·†±c)å0Ø$ô.Ïô` Ëußß”E"Y­0gÛQŒ¬} .˜ 3¤ÀÏçèi0æ^HWS‹ð9†¶ÛD? ð˜åxGŠ7 \=`<ž s âR8Áÿÿ ò˜¸ˆ–éÝ'ä™Âÿ@–ü‚Å1!ØóDáù¼ý9¡|Å4€1RGÝ(žegâT [û7Ž`âUor…N1)]ð§odÓëöXÅ7Æùcfõ'"¤ÞuÔöj1[lshÈu½Ç/‚M@ÚyC­™—ˆFCÀ¼>\ËÙ¦Á|ÝÒ…‘lXóv·¹d@ ä0µˆ\ÁWÒÉfL@Ú³<‹ZDm|Ø@˜ÇW‚pà0j+cÄ^n¾öăÑÄaZ]µ—yšu%|X„¯Aë‰Ã¬;ǰ°ÙYe¹S!æ.‡EWÞ̦˜,§´ÛH†ŽM()Õ6ĉfjÏq=ü7‰+¥ÅoÿŒäÅ+À%•´ zëq2>ãØ»‡rÓ÷dZÿÚ½ÝÜ­ÆaÝ™“f#]§‹œea6‹èxjFÛm{ª^™W²uC Z°`ú82g c ´58±%Í\úZµy«{‡qüEß9¯±|Äâ;g¬ä倶mà{^ otz½ˆõ9 àú95ÍT„mP>1%íÔx‰8}wýÌBç*æj–÷EòRµÎfÙŸB¾µ2™í”ŽP<ʶ‘K2Ñ…w¸Õy2á–%‹“˜å‹9Šå±X4%GrUwîI#²ñ–Æ`¡þ67ms×9•Ä”õ¤ã½þíÿSžbÃ"¨eÍEúÇ>ÃÊ-š]ÛàëKg«öÊàÒu5<Øä–ØÜõÉ MåN„+T¨‘)ÿŠò§}AKzV :Ÿãy^]-¡‘Gvââþ}”3›Üϻؔ–GûtÚm”2+8íPf¶lÖéÚøeÀ1V¬5h¿Ð˸A Wz–Ló/7ÑCÎ-óÖÔŽ÷ð%S¤‡pDJŒTû‚V÷ÍŒ“[AßúUfòD’>?)É)åßg¿x?Aäašµy)㌼èMWh‹Ìávs%ìbYÛÀ `PiÔ‰cÃ|²n¾¦¿9ˆ-ïÞѽ·¶¡„  W›.|Ío:=IÕÍèÁ¿iî”ÞBˆAÃÕähYJŽ ±ñúFáAû—[‘/ÞŽ•f çáMm/ˆ5ãp´•| ŠU ™« @þ!»˜p( bÈý¨oð T.k?›kJ„ÓF [‰í·‹´êKóG‹¨ U÷Ý5j(r}f«KêñvéÄœ“œóÀÔç+Ç<ûÏäË%ÕÙÖ^#ÔïOÁrrì5t]døÆIt¢)sßÏ]V¡´e(¢¶ð„Øu®Ï£+º?'…9"+ðk>3Ñ÷Ôð¬ en¤ÝH06ÑÓ—XK“–Zݨ{›2 =} NÄâ‰\jöycŠc¿ ôD2›n25ÃHð×*M©öÐÐ#žð@ûå嵋W h2|˜¢ùAr¨H•„¶Cï½T½±â摜èEž©1NâØÛ_•PwÊé CvC¿:Bƒ†·ø¼Ì§¢:ææR=²¥$±Ò±r~íz‡í&²£=Zê  ìßc›ôìè–UæiÉÔ©ž¥!’€€ÎÒû—<0ƒœHôÓÚS¢k¡9Ä\j0šLŠIŽ&DMÂÞæŠ>²£ ìÏ*±ØA ò# š *ÌÛŠ4вÙšò¥ó„ÏÜ@&t:Ù³A›e8Èsdqa7Ý»®¯øë_Æyø$êµtüù«$6K¹c¸»“ÀäÝó–üøu”ÒóÞ6ÞÆÐnRnËoøY#¡3~õæ7#û÷/âSõu_¹ìômB…V1iÎK°éŒ¡µ÷J…Ôù»-‡¾“ÐÇEúQ³…~¹jðtG¯ bi¶¶¶þõMËRPNŒYà!ü7°+¢ù]¤hæÓ‚¥‹—b"‰>o¯)nˆQ4-½h>‹ÖH,*³‚ f(úIn W!B6gÀõ¸Ý:SpOÏ×U·sik­ºm‰Á2¨ì÷zÊ©Bª%`ñÌÑž==úÇ:ÔJÆH¢:áFÄ%‡ˆÝ„ë8†]rþævÕ´N ø¼‡ã·Ò<Ð I¾²ìhøªâàF«³fÓ[lKÉ44ÚÆÊ Œ‰àÙýˆé´ì¢T¾Œ•âÍ-}uéŽjNÕç xÞGˆ¼³†$ ¾j¯Òî¼óëëÉëE ‘\jÚ¶%y3EÙÓóö5|Š–•šìÔ®¿¥ ¯ÀÊ“B83Í®½lÌ¿É ³t[ý4Im-ïÍ?²Är€cÚn tÖ•3´ÇÚa^x¦ÏŽÁ‰ñ EÔ¯g÷Îr*¼®‚–¥ÓMÔ5ŽnK1wäÉ% ¼ðPœôh*#ÝP7x ÉÆRXŠ& “àaPŒG9àH“ÏÉ©@ p±Ì§];¶¤ {ïg×´bú"Ê ÇÏ3—´â=Ç‚sd2™ apµÂ}'!·R˜z°Ê íU#È»¡þHâµ=_6Y—ÅÝoÅ-Ìi ­2kîÊ3 ªr.Ò¹qƒÕ8ZZgé;³M(JÍÊÒ•ÖrD›îŽsÏ"ðK8£q±6,âöèÇÔ:E;€Û’`߆t@äwKu8á_ãÖFH,eâúúz^âUçvul`°Æè€ryô—âÓx‹_µ($XŽ$jR‚~$†u.âÂ’ò@qÖcHÐ×+öQ¡ÖÿàýšƒY`݃"’€€ÉŒ´É˜×º¸}F) —¦Ãÿýý±Ø€­HB‚øw5ÒL,œq´\ìþ#%+*+¯¬Ž´]ÃÅrà« Á-ƒÇÎËÝl¾T…ü}‚ÍFŽm<Îj@żԢå'An¬„8ù+T¡h98w§Õfžó0aäúÔxâÞªVd ]ɺܰ´¡°Ë©iÃL‚OÒ¸‡LG;J×ܵ¼ç aðCšR3õø¦ŒøUÄ[»¨;ó)béÛÏ­Å-uWšWÏXÄõópMá=`ð&I*ÞjžI[n‚¤ ¬ dEAýl\õ“f!_uÊ)#mRåk¨{ÍA\¼*µg&7T‹k^Øåš r°3 í)Ý!ìþ_4ÙTgybHKiÕwÊLÓ¥ÆuO+-µ/\–ÕG&²Y7<næÞkÕuU£“ÍØõeA Cõ¥ŽñÏþ^R1rZhç§Í›B·üÏ€+}]u˜IFÓ®=™ÎUŸó¥S ˳2!Ôº" aÉ1&DÊ7³1MʰpVƼ—àµÊcQÏeŸ‘h £Ø/ÉÞéƒjl\š­–qÞ´2<%«bc'Ã’yâyçëµk©üèRlŒÍÌ.e45%eÂÊF·-òyJË_ˆ V"¯Éà§@pଥ`ÝT?ùwÂ{lÀR>Ó?ÊAæa¡ˆøõZ>¨2ûhäq° JM†_苼œ‰ô|™¢1îbýý9n~åNI{ä“lwÆŠx3ýe&Ñ9cg`+G¢” ½ÈUJªŽ7#•Âû‡ëѸdR!Í9¼¦Õ´Í±;6h¸µÊ‘ØÒ»%¤É# ƒW±“±„ssd:–hàU_‰Ôù°„Fá1÷…ºˆÙv>niÁ_%A‘Hö³wî†'¬¶©ÍJ«{Zjî˜ÅôâñKÍÃÖ/pŸµµº—ë úWšË+g/ý/¸«¼˜6óH½l15/¹€Ü0Ç¡n&òj·“BE<  ‹Û¸v<Ì&sc5½0üÞíìº ¦ÚçmšeÊe!ºjIÿº8ÞÆSéú¥ämmà÷󿈫ՙÿ´h†ÇXýâ¿Ð±cIÒþOª„Û‚é Ãÿ‡i)ÜJ8ž²6µ äMè¤fi9,¨#€HàÜ“‘#§·(·¿N¼ k¼À¾àÞкg’€€ç9Ja“„Ã^›…·”ã·˜Å$¶,ç²c€Ú/Dü/Mèø¦Éºžgïj|ÈçUä‰ým„¨*sM’L+T ½Þ÷1 CÖX~…)­q:a3€²`Hu.2Ã’˜@õ›ÕŒÒE¾(üNw»Õ'3™MB´œƒc2ñ›fŸ[C=ÂçÕ|Þ째RªK öûîŠöQ²o4µ×ZËŽ³àþÖc"@™šïlòx^G}?ø‚·Üß«pn×Þ^Û6u— mÚÍúÖœ„¼<¿µú )NiY«eóü•¶·¶¶x¤Š6½v40X<öñmF\ä"–“éç~é¸1$Šxôû\«E ßb÷sñsYƒd:£Ó~G ,|!æðË·Msú'àxCÇSÖ?|TþÙ[y™ôþ†}i¦€9o¤¿vf?F–:~åÏ¥? 1iL!rÕò›á/&’5r\`Æ_75z€ÁÐâ žûn‡‘Ž(jXmUX½‘gus°R⣦ZìUÈõi5l™Xì#-•ލعeÃp¸›|Þv\#¸öånóŒHGÑ„ €®oÑUšLë§ŸÏëF®1ÁÇ’8º>4È€ßp06¿.ÁsÏ7бúšÍÆ+|TÀÞW¶™@dÓšCá_Æ67ÜXðU’AªpE±®¦v6ì€ö!‹ùŸ¢Q©PÝ%¹^(¤kÙs‹tÚÔñŽ+wÆâB¬PM”‘j¨¿ïý1ߦfäÄÓ³of&åÿt c2Œ Ú·d˜vªzryRXaAxüÑäÏ lLH{·iÏú9ýòð˜ý ¬ÏdŽÁÔ'§qNmiÅ>t׺S…Qð~òç³ ·¦ ¼a+ºÖÌ…1pù‚¬jtÌŠcM퀱Œû™ÒerX”ÑÓôôPmŸƒµïËt–IÞ3&ÀC‘¾^ÎíÔ¼ùŽý)g§v˜ÚB+Ÿ;¯ñõúÖuevÕy¾Pê*´»ì–Xc,ëjÝ‘nš\êߥ}—øxÌ{ƒM°}ãä5k¨Ä?Cj•½Ô¦XE8¤8Åfôàí Ètð M=ØX¸ÈùI_¦’ÙÙ*þ¡…RV( ¾Â“åêY_ÍobOûMR@úY9î‡þÄÑ2xhÍá@h•Ø"ïƒwþõÄ~dªö÷=´9>²5àîóÐA7-IXêÓ@’€€È»©ŒZ»ž«/î#fÕõU"Òs…ߥ ~înYhÁ3~ƒø Y}ØÕk'ý^åÝß“8”Æ`ì($ q½<ézf+A ŒpÆ –•PÖ!JÍ ðbZ†œ!‹hª… SLÍùÅsKekÏŸƒ?8¼SÒžö2{»¥·:Ý T)X‡Qæ_«‰üvq#ª6Âùy稻ŸLk?ôußÇ›Gc;(ä†Ê?ßY®Ë,[=©l°¾Ø8¸&j¤™G‹ûìzí/í» B»[¹ ïçRÕz©«8ÁçÎÛ¹]îÅéÍôðçëVˆæJz"VC)”ÛMio ‹ZÏøëòòÁ+Rª«i?X3Ÿ«‰­ŽCs’™’c1uBà1ò·ãøˆ–œ­•ßll ²AÜ niMñqÖèþó~R6¬Å #‰¦ùB‚W­Pº_U}_Lœ÷‚VØšO¼yéx9Ý˺ª‰Êbí¨Íp·y„Óo†ú"eëP‚É£õŸtþút \ñIiS#ò\Q<³3^—º=Ÿæž”ÁT÷Sʦ7T‰]PÒ–›‡Íþ”ˆAÝîmós~´Èd c ;^ÐÎ>JœŸy.Ú¶ÜhÝ1„ëZi«Xsˆ­ðÛiÉ ÀmÀJ®. ªÀ¾Ìúèë¶eðY²°Dª#F”±'ÜyäÕTw²&A£PCÕðÓ[ºbrUBÊ9„œ)#šæç'ö.Æu¦n o¬€IG‰í**8cuZÝŠ:Ù¦k7£Vvz>DXßÇØwКëÓ¡éÒöeiý÷uV*kµ‘Ùz$OqÏ™âèoÚ‹3`EöÒ{_\z”‡RÖ•DáI¹$^vA¦d}€ø=)'¬ŸîÕe»×·¡[§^¦§€( bzI(/¦ÅZó ¤OvÏ U‘…b>ü_„»WþY˜Â6?WŽsIB’ §^v#KZ% i™çwÿ„^5Mu\¸Ô+õPï`ÄߪÝK¿oõ權ybü— ü£`•Neç+ë+=¬Ãï*…€DÃy¹ù5ךµÜôâ(}´Ètœv|D›ïy¢îó4ž†¨]×ïAÈ\й÷E2À[H~ähJ\9ƒGÿšiC-ñ;è+Â1¾ôµEeÕj’€€Ó¨È ÓV5¥éXíT€¤¿&8x-‰¶^|´z>çû‡0F"µF~.ZÒ¦P›™ñU×qÜ-Ç:ד°jõ{ÁcjQ`B½Šö‹ù-îÃàÔžØXsTlÂ.ž]­ù·¯€aÇ" |¼È9ܻٛCW¾fÀ¨K)¸ëõJɹCþý>Uáˊͬ_À3²[¸£¹Æo]œA}µÌ‹Dõ§ðð¹W:qŸêÚÿX}¦…•“ý¿qÀÀŒåâ¢þŽì”íþj5'qæÉR³ W´!tTÄÉ«8ùâ<òXŒ3tbë’„ å¬OûH›]ãEÐWžÙÞ÷lwj• ÿkñ-×N+´’ÀuêsüF¾G뇳Àø4,wù“žq/5»¨ä“J¥Kh£¾ù:Äÿ?ÜBTçõÂ¥<Ç(¹¤_!üu+Æœ¾Ù”ãÞ§ .JèãCç£ Œÿ¬žàØK±ahYqîúmWe¬ìçõgÆyH•—‘v^Ü9ÄoŸ®ÇµœÿÎB /â‘Î&­ieýÂ3¸b›Þ¼¹‹- ¼ÞÃòÏóšSQÞ™‘@A2T/Àù¬¥fWð”½ûÏ{ÃÅÛU#Y½F“N­œ^¾Ô b ”‹ÚR ²×™=Üû¨h^ü¿qõ|w äÅ Z)Ñ?cˆåΤ‚¸dÝÝ$Ò»?V•±ÞLã â$ž^¦gÖAìëîWΟ q->>ˆs ~B\±ÚDîp’}î°ŽÝ휰ž°¥Þ—C¦/%³:Ø0¾,*„¿[Ò?4øk°óùï—«\´ÜøñFö}SOYÆܹnù>ãÉ5áTQA¨ß0s2:Æ^ |V¿˜êÕuѯŠ•k´&åp-`ëûæÁUIhv;˜õ½ÅEcpi‘®- —&àM0ò°³¡xt'Ä(E0—‹ã¿¿8|Óæ9äEY¼„„rÜ5Îh•n"Aʹ^v7'ôV™¯ZWœÊ>²—¾e®~öÔ:‹n(I·H9=a}ÊPiœ•õ¬ÞVDEâÜ|Š8Ð EHÇ!×À)¡{ÂQ¡C§‰¸Œ¡-DTω0)ðhúé­51NíiOIDž}‚—*U´Ë¹ÜêÚáo ° ÑÂùÄ’Bs°ËÁe1’€€è±RW[×7+èrÅb]jð<86ôLй'z>¸øüeoš3ZœêaFð—Äfþ`,w-s1ÃtS¹¦(K4gÏPù4¨þß7hÅ-h m\=iA9 „z{Ö(ßgý 3FîÞô€aã# êÙÃÃõçÌØþéô.E©÷ß`6S3=ýÙ0œ§s²Ì”zr¶á#XáÛ±k‰d,Ui3bî!¢©Wô3ñ$© »¢a-Ñ5÷Ð^î†xïs XnÀOÈÚšmÐ4ÈЇ>™X ýO…ZèÓ"ªB‘w!a“,ý~ÖQ€®,ôt­„'¬C…g„Sðxó[F%9ÔûjNˆ|ä¸ I þŒ2³¼·7Ó}n¦âÅÜ“·J  9Ø© Š}gË›ËÔœ|‚×Ý}[…È£lxl^ˆÜdQ£è‰kÜ×U׫Têc?&ýÌ5˜yësN÷JàBXiÊT O!’j,ή¦T± ? ô”Dö)¾mqTcYœÕö(ŠxVýIG¸¡sø¤{DSPéÀ=÷–No›Ê+j£Õè˜ {¦ï`ÁàÁ˜yÀ&Âïo˜BÃL‚ôôòÔ8œŠPY~GÌ JÙø=D°ý'Qÿ£-zy×ÔÃzÒåñždP9¯£d‡¶‹xe‹çnU–áCÌó:;íᆱõkª²é¹†ñ\‰ôÎæhÅ­0†ýؽéùìó¡j´fhÿ È)Ä^¼˜èƒ¼:^ß[®¿–ËïÅmÕS+Y4­èþË^ßm4–lwäQé‹ñ$޼4ÿ³J]^ð›\âèqJäüáuÂáøç¼ëµÜŽU¼pàØ}c|š étªX„¸ÃVWi+¿ŽÁXíi!ey‚’ÿ?fü齫P`Œ¶PÜÆ&Ÿç1íkn‰×Æ«:\½Så„XámËÛª4ÄæcKÔÖh]KlR¥TAä¼ pâS¤rü1Ræ"?‡òÔö\?Š^é$l®å{ï»dËñª ¾lƒŒ0ÑËg×Íq«‰– ŽI×7«GŽ!x>B )ÙcyfGÓá¤òædEð}8yd¹G,…‘ifEH0hÖ\<9¸/’’€€Ü@·v(æ ¼ðL˜èqæ‹ÐˆëÐ;ͧÂå0 ‚©Zñ‰Osƒ¦.WSTBÑ—Ù¼ * [Í­Y6R¸BÌAÚ:Ì­¢Ñβi \ ƒà)¥@Íøµ¶C“üÈcvVQV .ˆxýÞÐ=w³tþ¢øÒÕ_lë(<*ʾө™r#˜S¿Ê8Ÿ¢gÎ×Ebw&šŒlì®™®7ñ^³Ë*t-ë˜p¤ç ‰–Ͼ´àzUJŽ×m ^µú5ÁýP¨!â¨ã ár‰ÿ¾ößô‹uüÑJu™¯Z9°ro´ÅÜ;LËÑWá¹}䃻,1µØ_º"¥!F+-…{ùrcì0ÖAÜ©[ Ð ²ñ¨ÃàkýÎiJÙ×ÊŠÑM~QëxˆÁ}ç A8{•b¼Lžž«?WôAîW ˆE©‰gÍpéˆßã+åÙÅ\d…yw@—Ú?˜“ªòó ¨Ç[!Ö½® 4l±8=蜨´JÒ÷+l6Ház”KÞÈCìY§·*€2Ç2¾;©•ÑF zB`¿øº»”©Õ=“Ñö‹á Q̺€•롈PPN=vÞ¦Áùž1w(ö ÊΧP‘‚•َ̈́*–E›)cÂGøÜÓÏâö¢$‹«ú¨9—÷7î*˶ÐŒGˆ@³/ú  ¦7쟂&Õ¡nºlÜÿ¯ò,¤˜F؆½e¦#‘ü˜ìv`sè<ý¯‰|rgälhnñ8Úq!ÿ¾g)Ý-Ä͡¯p¡hcí.‘ kIga,œk⌠)>Ç8/3X¹Èä9(®LVYfË£üY|]Fï!Α š#3E•à†ä\íA2¤Î˓ᘧ^ƒ³•þeÕ}2¯%®¹Ë%ê9ºg!Ü듃DQ9×MÇë´Ãe }•¨Bô÷\k1gpnÓtÖäEš¤®H‡?k™ˆÒöô@Š_OâÝ:¥)ÇX›V2y4 ˜€¿e^÷èü¸hьͼâl©lFr”;dÈ5‹›A‘¯ÑI†xôr8Þ‰„ôYÛ¨¶mÿ²îT¹“SǶW_ܰhËÆŠ…iÕý¥7R'`ÔNmXfqð0vrõ:#&ih#xEî4&Ð!âb] =Šéš/Ø’€€ÀL úÁ8~dԵ̹ŠiÕ[J ÌÔPõ0ÉV´0ȯ¦˜Û{hë’#%êziÞ=ˆjüºó¦I¬ ‰ÖÈñä«¢ŠUpZ@›Â Á^´,JŸ,ì‘ÌT(bÄbÒÓ”Eùƒµ´ð`ÑÍå ¥ø! Õ3½“ ×*ïÂâP>Öž»í¾Ü­—€sH-'P Ù”»p`V52@¥UöpÒCp—=•2GCg\LÕ}Ú“xq°lob“5·DF"“îEÝÂ_·¢È;öì8RÞ~eÿ4øVÓ䋟‹gº¦àj£wŠA¼:`rxÕŠlæïGòHR8UGu‰¿!“Z8íf!úANè1ÉN?ß(@ó@7{ 82™˃"âýŒÉ:áÃ5u }Q¢ÀÐ&¡ÇÀºôÒÍ)ºLÕÅO[¾\†|¦.‘Ã1%;¶Öiù¿¥RbõM×ø"r0æÅXëcêÿÃg¡, »ïÔ`«ÅmþKˆ=ÒÇ€ôª,`à§·óºÃ캎ÅoSrmÈ=ØYRãð¡–ϰ(¸Â°gR‹'ëm’ú'CaªŸ‹ú*r(&H„ó„C÷Ëù8d p |¢7ᵺ”pŸŸâòFày6öÎÅ‚Ìr³j8GlK`º«ä¦Qjÿ¥ºŽ'¸8°ï8exD‘‹‰/écO{Ìû Ÿ 9Pw€x^» ápÀ”šÁ.ß»ð¨Ãã_á/§Ü÷÷¤‡ÕíAò'·ɾþš >‡w—ëÄÀÄëŒñ°#ŒŠoR9µ=´M’Ù>Š[‚t-L98¶,‚ÐÀe¿È?×M&©¯ûcÙ0?tXéÞúýèù‚ òÔ"=}q1vÿÀF"èëC!,eãÆ}ÆpÍl ³Õ¡Ù¢á;;)HôA·R;X\è’TUdµþÅ<…0'~Ö˜#ÒÐŒ˜<½ŽªžèRÚLî?ŸþÑ”tðž”ØWúkÒ½>ouö€‚jY?Uðvê(1ï”ô ´bAºÂ h!·C7–¤LÍéVŠ8˺1j‰wiÝ“àçèfp¯7ÌiØù\Êw|8Q«1€¥Áz8rýöD¢]ìpÀHR>=|˜·Å<¾ö®(Pÿ¦>9ß­õð{í¶3Ud’€€ÐÅ;ŸŠ¨!×®`¬,T»¯:°‰âŒhC°¸HËÓÃv?ôµÛÈí±g£¥øœé/£N©ÃþIÓ4Â<¿0Êó†é^o$LxIQ?ßbÑT öU%@zþ?)+Ì¨ó½±æÁUJö,còŠ«[ɉ¡_ärF1qÅÍŠ,U}8ÚNH›CÏŽÿ¢l |(C—ååÆoÔ mÀÌÄÔ¬—®:¹Î•ÑãÀï£'-†Ý/}$é¥@ ÔÄ!)G+ÍàCüNí’0ØHb†e«˜8ͯŸM® Ù1¡&ü͘^WôkRí—°Áè¿éÍ{4g™aŽY§uîÞkh'¤Evb]+,€o\4j Ä ô/söNŽðe<_¥**újBB«–êN>Y¬Œ¿(ƒNzËÄ·Ÿ¹p´²ü>^—!²^Qj'žÐÓó›ÐC™©Q¨…hdŽù¯£ÌÑÄ §ZhÜbüë ¢Ñ4{]€÷œ}L 3´í²ö )Y´@¼LŠ:Tˆypº+pöñgÙ¹¢ŠYWÉTdçÝv-Œÿmİîai®³®8›#°îAä³Ö¹åq£ÁÛmœÅ¦ ŒœÜ‹›©…ŸÀ9læ°Z¸yÝlÛZîQ‚Ô>~ ¨hmì:áÜ@çYF-€5õÂKð%;â lþoYÝ8ZÊkË[Qnt&ût$¨ •c©vûVj^¿qí^){˜­îÜÝL3÷ûæm;½0eÞ…F–cdàe ô„sõ’žžÿóR¹àÒ·ªWðA¬Ý-ï™WñM0¬±[VŽnºJn]DNG~>PëM^ ÜrKkÂÍ¿•¿þ€5M®$.ŠB«‘LJsÚpÀAwæÝšæii›¸ÀÞU‘XÞüC£Y—È»8g\ ;~¿}BÞïT§ÏŠ;ý’f„¹È oTí|d¥+‹~Q’€€å¬TäÞµ·#?1¾ºVŸEÙLÇb­9…DR)SÌ×3o’àÙ§$è÷ù‹Dˆ³G­ö÷Á‚Àýbó¯/e@ãm" @ø:l |Hù¥ko…·È§KÔÖuæ5íª«¬F‡æå]ýÜo} BI¸'±?—üb’€€®æ ô³ÛlpöwÎsŒ÷øEžË¯žOÐÕù¬ÔnÊED0À³ ^¯è0s<€¹lXÌÆÚ°hù"ãRþ*¬[¢À3*Ãr.Kij Ìè Êa¢û¸º¢„˜È»Å­7ùZºí8g®Q¶ßÒ^¨|ÿh-1‹½Ú{ý9‚iŒ|t<²œlyçù¢Ô!ƒÏmÓ©$ç¹l뀲–*BÛÞ^2jð§~¼ŽAä†àÇ`oÆd—Ù³yIzLl  .Ä3x¼'+OôIŒ=°jšJ!“þÐ*Áß3Á>Ø`ð“8cŸ^}0ŒíUÌèQùMñl›¤N)°ü»Óè}Á… :ßMw¼è…Å]övÈ/@4°yØ€ û³X5ðþËmqVМﱕ<Ýuò(ôˆµ°=¥º¬´Ï¤Z½Æ9äŒäžú¶O™§¬(nfXõE—ÝÉu‡—Õ}@ÜWŽŸP8(íQ\š¯’,¯ ¼êíÜ9óˆKNibc§ƒÞO‘(³x®$†ßmx[4îÿ!…¨Ò0w¥\j[Œm:2O|äD…"=Ú, j°@{è>c«ñª=p=,ó+K­-ÛÓ{N}¯çwqÝìÊ#â3åÇrzæñIÈîɃñà{2(ó2I·aõcM‚žÔHÃs …™5uì××òÁ×ଯÀÕå¬KVžUÈa'çù‚ÖkÐjJ¾Ü(ÆCEʨüÿ@d¯!“§ œCøö/àG@ˆö',CV$v.‹¼vÐN6½QwI÷°%IÖ¢|8o\ þ9‚eE‡Ž…c¥³æ÷|Cy„ª‡,Í z·'k%^Ü•ì}‰ÏoæS W¶³’czDƒlXÃA2ßÎhF{µ ²+˜}³í>*y¢÷ÿüPŸÓÅ,ÓéJ ÆáÈ8L`>Èé_M‚Gç§Ø›Ÿ}^óÅEp%ä ѯîŽh`q6¦H¸^@ÞâÃ|Íàš¿4ÈÉUå»×ÆÊȮϰ,ýiñ¤9'kRá60©œ¯#” ñŒbsd†kßÕRo·9oe”PXrô;!逃ì»ÒÖû‹–ñ«ñúU[†….@¢þ7Ë1äêI=\£‹;²¿— Žéèf8QÇ·îì‰Êv(v\JÖ:k~¾™šý’€€Ïkâõ»‘)éI¯ôtãûbdÙä†j@üQ!›óD¾¦•§jÌ@(.À¨RŠÈ´Mëð:0åY«“œú3ŵ[]±ÛÝT„èIÃä ÷ÛDMŸ>à ‡g»:iv“ž-à‹KØÃ؈¬~7¿¶l¶SÌ1hÎô J•pce»lÔ̵*¬Žˆ¡¦Qþñƒ!<à\4ã Óð}Oþãf·½]­Æ}ý„›¯)û]9¦ 3ÒüºùºßŒŠ€~€™#•ÁH!^‰U[l‹ÿQ—°¥—hÀùa¥sـƀþôGc%SFGx¦â/iÈÕ7¢Á€®)õqù´|Å+‹ß*ÓDýäh¡ëÏÁ«ÓüÛ#¢&>™fmWà¬äuÉjx 2È"ĩާ›ž7ì ‡0zÛ©®iyãe0Ó.wtež­ù¯ëNÅ;öヱbÇüˆŽ¸¡DmÈüŽac2ìBó¹zi_ƒp$õSªÅ<Ý‹ëBXÆÖ²š}ÃWèy‡Òš5a öt^0ŸxÕ|ÐlŽ.nY`ã0ï9¹cCùþ^†ž=º‚Ñ*WukjAújøv¨°^6oô}¬;tZQ~}ÈQ%Íš |4®Äó~n)uçÆÉV 5)í3"}_`Óp[Фþ¿Bî¢61™óHàç±rî_ÇÓþߜۈ& ë/ÀEÿ[êlþ«.m:y'\Ì ½äýbɶ¸YØDGÈv ‹‹Ç6}Ù _QVÿSZ•ùvâ(©´RÓð]ÂWm‹¹&¸~]x!Í+ © ÇÞI楣´êå.¨Ï,§8lr½suß _g•EÕ˜½sa "ÛF.¹®$ ]¸óVwq3[ îG<Ùð‰ê_%Óê#ÌCuíž\KÒšÉÞ&Ek6Ò£.¡E‘ŒÎôN÷¶~ŽmBH¥»½qöÏl!ù([¯S L5€àÓSpÉÞW™†Üw—Ä8pöªÓnÑœæÔº6&)míì›Ùžx (‘ÕQN¥̇£.G„ÄànòN2NJ^QîC¤ìà8™Ï‡vÌ“ã”N[ÒߤÍ«z%­›Åu.ÿ´ÓOñët\µt"2uM¹J¯£P0’ŠpÚïZ€Ñ.µÁçö¶×Uì3©bË_ë3§rGVdGßà’€€×}ö¼½_Aÿºõ…c½.D„ÏYÐÇW|“x‹À¿\,¨Ö‚¹õ?ôÖu)A ›•¹ågëż¿ýhƆGªtä4gIÛéJ´wgŽ_Šÿ|aLgó¹œa%ü ²íø$Ë[½±Ç<»°EjÅUÈS«z¨´ËíN/•IæÉV3­—ÌzèÙ^–7ÿ:sûÊüEÿ¯Ämã\»’µ›ææ=·Íò<!3ïäËö¿³}FÀßþÛš™‰ÙÐiµõÆV0‹ñ×2ÂŽÙStø!ò¯‰s¶ „ Úl Édb6´W€ÀÑå‹XÃoeE%EÄÕ&5]n+…<ÖÑï~©ÙO¨yµ£Ú TǸJéB*×Ä.&S¥ÑiPkqíGK\>D½Eve0Iø Æ<©æëŠwèâ+Þ¨,kÕ‹$W­¦Á³‚¨Oß76žÕ¿W<5«\°h £«fMZîv‚]ÅÃâ‡;cÖ¿¬ªb@DC ö¶Bk˜VŽ(ÓªÞ™±,?l;®(ºhKãÛ[ŠgÁ÷³U;å’|_×2+Ê{ÒôàHÐø–ç„ÙפÚcÄQÔÿµÅì&zg®o ˜ "ÁÒW. >h-ý䢑åŽg£«aÅ‹W k(§F]Œ¸¢­@goû]MÖìu,/—‚¾Íþ?¿o>莊`¡¿WrÈèf®²¤WTµ¬týÙ¤!áÕ°€)¬W{h¸Ÿn¨ÀNm.pPÒ­j"š·i;4A¨¡3% B/ÏmP½ÿ~ÄŠ E[ !…΀¯K‘LÍ$³—Pª‚T1:ÓŠ¦aí…I޳q°2hÃ¥xšÄ!ØÃ¿$ï£ÏŸx¦éûýåA:—`ÁÔ¨nu`4ïÌÞŠ>‚·Ð…•ËA— zÍûŽ18ëá-I¸‚°„©Î|Ū¡æN½:¥hÄÅ·½º7@à<Áèä§#jió©÷¥% c«Îû_•]ÙoÆë±‰;-HeùD{«Hå–ar;0§L…“—ê¬ ¦CHe•ëh&JÙÑf¢g `úßu L•ªŠáG(L§V® ¿)\òhòèçq0”Ðï•.ïï{©%cÀIec†©j}ÖWD«íÜßä©%_n3ã£ôu¢ N|‡QÈÒ½]ѱ½¦P2Gb"0ŽWÛv9V’€€å/îT¿èÛÑvȱ>À7B}øû_fŽ“Ù-Ø¿·¦5Ò@,·oÌ\J”òßéó¡ƒñG¦¤XsÓ!±Û?€ŽGÑf`:y—7ÚãÏÜ^Œ’[3¾ÿú"‚[3lÕ8øõ¤šÎùvòª*¿zì,Ô1›°YWàhºõõBuðAÚ?õëoÈ+¬,šÍ8š¢X:æêÀ`’1®ÌP1Á~è2_½jÖ¹BBådI”h …F/ˆ"(¯9@è î-]=§‡ù!MÞåwê¼êÔ·“ƒÎXàáà2ÒHqk}_¡'»‚bØå°Ž~œ¤;YÕ(¤Ð¥¹×ê=V`8Bñ~<é^Þ¤#?ç/ÐJá6b¬¡7‡TrÔ.Œn–L`+œd»n Ë5Ð:¤®BÖŽFˆ51kt°G¯§ºQUtÆ„4sZÕÞäôlÝxM6¿Zƾ‚N)D³Á7YgËì–¾þ;T å0¹2×aÞÙž½úÃЬ£]JFˆÞòàG΢ˆ ÀÛïik**LáÿÁü:ì.ͨĵ17[[ UI.Ö³vüÚ­”dô¢ä­…z„ŽRÊ.Bªêɱ®.ñÿ.•€Ú|–REëÆ÷¹»¢h°{é™§Yj'ù< ‰côï>jl^¢st[ðà”;ú¿±3Ü^p cDÍðLÏÞÃeè' qw±›ï1K_x"=ðèõï Ÿ˜ !ǪÙ0;ÖC9,.éÝ-Äʂр¯D0ø·o5<éPAI æ;†N°oê˜ÌJš êÎöòŠùë€o†».óØEnù,^8P\®9¬vbD%'H:§~åo1#ÖõÎܜꚟ#iÔî1s³ó니³J}6¨Û1>–Íhú³´_jlcP´‚Ã’ öªyÕ9)3/Éf <˜P×ÉE§cïï—:×9Úý£DñôÜȺ ÆXáÓVä{¶ÿ`úAü_´Â¶bœÙJ;­B‚|pj<î+\ODÁAYü•áÊà|æ[F b/fÝý]//)!ÆÕc¶37WÌÑ+ªX;fV¥zÎ`ýç÷Žýã¬<–’€€«EáA.¹Rü•Ȇ˜ÎÈp=gAêj‚ :êyp³í7[%ˆœ½Ñ%hèl—Y.N·«æàïçúÜȾ öÏáòääm Y9PVæh—Mæì§Uë]Âvmƒ^‘î\´£òµy5dкO‚Ÿ¥Sç¬ðß`ÐwÛ7Sñí™ëNã~¶DäÊÞàQ%•Ðìxµæ8kPqŒ²¬R·3Ü Z-FY e‰9Îgi «/ Ë §Û…!¡¢ãì‡îƒ>c'±z€dÙM¤ôÚ2~û¼ÆŽv™Wu‡iý‘¡§ée•¤OÌ£ŒÛˆÿ,õ“^ÝS:ãïàEò‰§¿— Ä´ ŒŒp®Ý ßv«-¦Œ*n’¯æ-ú Δ¿â&GÍë8\ @|GvŸ…sÜ'e%èÁ´ÍÄl¡Ýd«z¾q¶$NQ“—»Vm²C;îqdš¦û€×rßæ_T¥ð˜5q\¯˜6¾Š$j„E4¥5bS[a‘ëÚ™B¥"ï9áZ¸ö€Së[ÛŽôÀUî%«¦'×ìLS&”~æ-¨…w¯×b>¥„~Å{ŸI!ú0*v¹êï‚b&u¾Û‡óbÎÌ;™e'†*i v¨À&ù|.¿³ñRNyôn_@¤7 q¹±ŽÎÛ×óºWúà‰I`N¾ûÿ ·.>±ß‘ßF¼,©ÚisVU2ÒhÏjã Òxn=™Áö(PäˆÄ¥%µÄŧ·3B§Ý4kŒÀ6’.BÛ±m’6v€Á¡¼¨à ÆÖ0†ôò%cDR x[ ¤á%Μ>õ¨.`ák üGÿù¹û´ãÊí2[È¡0¯NÖFšfãéPuâ©È¿¢;°âšºÈ’ŸÜW´Q–Âä_£;ÿ½þ¹)d~…]_ÑÖíúž)• Ž¥sø~“Ö¿Vñg¾)¬%–¾¾BÞà :(çâî×~Ê5)é5Ø8ÛÄ0Ø(Kå> "_Ÿ)R·}Èjðêßó´Ç:u5€…gÚ!ÿ¡¼…V\É73+ìŸn€™X=¨z/áÚ’€‡¸'/`œEDLüÙ¾·wͱó2ðªý:*òb»Ž¡åÖ„­DÈÁÌRo±C¢ñ–U£¤¤‘ô‹¥ýƒ£³ ¨_TóÔ!q+hbYÓ»ÕEõV5 Ò#ÅgøÙý‡qÞ¥¡P>M/C’€€Ä¥ŠÁªñ?0iØ$,Щɼ" g8YÃ’t•õ£Hßl?›á.×cüFêÙ{ëT¿YûÈw¾Aš’<ÿùÇ#s[䘊úðAž ºYinyÉ#–ýÉJ/}_‰„Xå-’çñÿÄËÞ§"Ý-­Ô»ü²ìÿ}­ìo¯÷ð—Yþ”>× åF Kæ[ß*üÍ™=ŒA}~ÍMêçñŸÑå3Ùg€Š…ÐOÚGg‚2ÒØëú§#úO)¼Â2Å¡éT'ð?tû…Þ®áAýñü±:ÒÀÚ©úþÂ~k˜ùé 2@d,*4¿µÎÔ¡Ùo Ûƒj+º$B©Ú®:ˆß5-Ãh+¼Áå¾ý0¡v.é0§kÒÇbÝ;Ÿ»È|ULêçY.Ü®uí”^K áE‰ìÆÈµiÿB0_ °oÊaˆ6è•z ˆôñ4ou[yô. Ønó-Â+-Ä›[°6zÆB×»›À¶MjF 9–:ÜŠ´[.ÿ?D†š}·Ù™ïwW¦VnVŠ"rÞ§xœÓ Û’:%`gW$Ú û€ ìGöTsÕOHiEAþ¶gfŸe•öªãðl^\²¬Œá'¶—#ÍßÚS|»±ãå&þÊ,ÏxÙ—ºfJ'5—[V2“H•É¥€u¿ÁrØ7öpÂ=L­r𝠽õ[^öa€TWK`Õd’²,Dÿ.Эº¬yÝI¬LåT‹P›î´©‹••Š@¤ju‚P˳ÂOÀtzçoÉáŽq¥ÝâY%IUæCÌïjˆ…®— ÷º”*G[ýðÈJ á°r*È û‡EB_{ãM¼CsnÑÛ…¼„4Ò©ãD5Í-A^g/f7M„í4[O()}²ñ1Åm,U»‚ÄÉñïß‹´¦Másã9ˆ^wd­M8PËV`jɸ]cpÌG+Lì)†?æÄÆSç‹À L$#Froà}È”žVõB/D:&³Œ²’šˆÑô’€€Ì·á5 âBÒÞ³·þDM±"88ùËÓþí1ôïÞÉ}Ìà2ðÖóUJ)Þ¤€ ‚ø²Ï÷×Vx£XÙçÿïëÖ–MŽb|ÙÛŠ‘ã 1Se÷‰Xö”hº N+€gýxǧ7Ëy íÐ1J5‹÷ü £±ñî§úó®"N`«þñÈ»4ÊÀ®«¡­âs> çòÄqÚ¥…¯Ãé›—Q•>ý7B™Ý>O¥#%sþ9¬E?rPc†æ{Õ6‘`$Æ )ÓnS†_Ø¡¤Çm$oƒK3fØpVw‹bf-­`mìd¯p&ô’À¥ò„[¼.™*æ[¥³E&Õ.óå¼ü 0Û «ž tW$ ÄÌÃÚðºuä¿íûËž–§É¿½Ïvi½¤½3¨dµ¼…2FÔW'Æ6˜„šª38D2ì&’ Ò.31p:¨¾òLJ©ÃDâ@ˆ+¡âÝ-$3¬RúuGuÓ‰s¯2瑱……ϨQÀr §ÐÒvÀÛs›ðwqÁ:ãÁ3Oûǃ™æf-‚G"Mà‚æ*'N…Qng ¯šÎÞ¿¤Ô†+ý ÛÛÇ.0ÑNfÛcnC”vïS¼#›JDZwÑ•zPK}š~纘š i÷"¨A â/T ~ùEŒn<%}ÈΉå‘òŠDM}-žkâ=\ Ë@` ¤ÌÕÔaô^)HZ|²i,Ïûƒ‘Þ÷ŸMÖô'ñÇ\éå°æin¼ÅƒEq ÜMƒ¸ê=¦ìx.LþòÈAMHH˜á4OçããóáV›|º7ù#º`&þj¤Ë•‹¼wH¥]ìöpQÚçòqØA–¸?¡ö^\‹«ÿ[(òùNL¥-?­ŠA§‡ƒWøbÄ@éB¦ú#t;°4ý"ë)ÐO6[õMO8HÙ' (“þ\ûiÉN1‚o aádd|›ç„mT_Ò+ËDZEÎóèG$B h¦¸7á¾ ÃÝ#@GSÐ 1Üs~…é; ௠B%ŸÇ&]/²*ýÂùj†öRCOdQU™FÙºŠÜŠòÊá¦HÈ¼©™|è¬ûSGQ¯·Ð§”2spQ» S¾ÃήüGÅ”@¬1:îÐÏŠWš´'¨›]Mo¼®ã»ù‡gçóŸ2ÞN'‚’€€Û:alä•B˜ Ä%Á,‡Ïîp¸ÁÀ#õ¶Ú|¨:Ø[76ç?!D‡BáxƒÍ(%{Ž4×ñYÂ>]#†Ü߸¨árw°ÅÖî—}è$9Q @EbqñÐðí +lE±'WÆ+ ƒÁß'çWî¶;‡?„àpRJ^¸ÄÒŒÏÀ®Mçz`JÍþ¸ˆø=]hp3@=ããf€ö£!b1•.N‡E¢· Ô G0‚žØßrè ¢yÇéi È«Fl³¨gj Š© ñ ‘^ ¦.JÓÌ”20Àð¨éG³qú¥}uD¡^0è%¬?hùôà2òÄ•ú®XCV|cˆ£ô B:m&Ð@š€Ü¹LoìÂÇHABòïJíç@¥Ï¤‘¾ƒ–"Gf£¿S—Õ!“ÝL)œÇ™Ë¨]·Õú}ÃÿRŽî#´‘YÏã„hxJ& Ýüïe™¦ÓÏ]Ùäc]·ê¬j²ójÿõ4c/ÑOÑËI@‰”O¦ù>—?›V•qzï²ö^µEµˆfÏ<%ŠRxgŠ@ܶQ Tr1$âó÷PÍ2GÇu.C9’ÙNb~WqqŠÇæï¥“£\¹gWþ˜V͆® YÏÇ÷|_*œ©T†K/™Šˆ"Ï—>QEÛ4ÁÔ† 2Ý%ËNUÄ 3äx@Æ ·Ô˺+ú&ò$¶mõߦq8Ú.K;á¼zØÛCh1¡Qð-«¦K7È3Ÿ*òc([€:sÅhç\2ÍnÒ"'¥"oåBš¥&“én×þAÁHaçMb-ýAusØr2Ò½ÒXªxÅLë†Æ¾ƒ­#ž6š!i߬+3taÌøâ×ßðŒå•¥eù@»ËºL»] gÒHc…RuZ-Q9Õèú¥?=åŸb¥«|c‰­NDRxÀË…Ú\0óÆß7ز´B™HÂøÁ¬ Kª¢¨°cÕýAÙrªJµ¯÷KV}:ô R’âìhú_@œ-Ã3GpPh([rÞQÊ”“M…©´ÛA˜|ŠçûøÈ¸ë¬ç[qèÇÓgV‡ oò¥$M@Q/f¸ªÖf¿»G¹ .ç)ç˜òfnSZÿŒ© ]=e |ç´7 xø~eù2õFš°ÓL}˜óTô!7ÜõÆ­ Øaôðº¯É&{cYñdïUªt0sn¥˜(¹²x³$°]*â𵨲ÐzÓ`´Í~>*m7Å6®³u Sæ>ñÄFAÌõ¼?HÕ4—Ÿóä½óœ›?:l¶r©sÃ-Xñ³¸91ÐA¬³ß„}ÓÐÉ¿®%{Fu$oy…Ü»Bdç±ÂTŽóq¯çé!O‰_¨[ ÀÙ®4Á8\–|ˆ”g Ù.×߯l,ÀÞßÙ—˜^¬‚Ž«è)~7—ƱëÝå%­èt”8dPã#¾¹â>‹½D™ßwÕëvú0áÀ©œ÷tFdTú%;Gº]hWš¼ÒÐæ˜´Üåš" l+ŸûcO#’]åÑòæœ9¤9$^3T •>Ã¥åͬE ‚ÐÖƒGEFÖÚC$WúDXéþÆ÷2ºè¿œˆ2Њõ cE§¯q½ƒÁ ÕÄÃw© Vø%ÜÁ3#‘Ä’îlÖ\äPµXæÈ= éœù{†$t*¤¨ô:’’»I¿ak‘epw~ /²¶ÊvŽCœ€‘Ã2 Ñ^Àv»Ï³4h¿ûPá Åz~ë>*·j`â»Â)…ä)¹Ã«n™]‡ôª˜0ÞíÝ%n½ák, ·yª»P™ØŒ×ÛÑ~•â__/üj/½ÝGWú»’%²þ¤g¹6¹ ´ûÇ.=%Ö+È´l˜ˆ¦‹ m¹å¥›ØRÉõ/ðÛJ`Ñ mÊþþÊy`±™ŠÆÝÒHçTÄÕìÃGŠYrÐßg;St$¾Åôä  >3%«>ñpJ|A¯’€€²Ì—¨¼"½(§tá&Ýn);ÊIva•?,ü<¦0Jƒ f!Xc;+òæ8Ÿª*F†çG²pv Ñûüu*[*«ÊŸxŒ÷Zþ ‘ß§rª[b(• ø]’I˜E|O>K‰3h}õ3·‹¡˜kò7ˆ&’pØq¬¦aæßÓkŒZ@‡ ¥ÊKL_»š,äaòG9fûFF„%QK5b¿ð ?h\Wsy§ÓUe±ÉßÀ*dó%È?` V:?Cª;°û…¶– 0:w‰†I«ú]}O{2Xѧ #Ï&…¼Ý·=ó é–IL+Í·öÈiòPRí›гäo§Íêº4ô1§Þv‡u>²@XhÁJâµÏ‘úñºI‚˲õ³f´è6‘êWjmÉzáâñ·´õM^¤…÷êI“Øú‡¿¾Þ뽯ØÉŠøè»jöШ”dÉ[pø©N†H•˜ëSîÁÖJOøYfèyKªî™rù¾I9|*OsÈ0£È˜ïAàˆoyôÜÜÀ ¤[‘u<€°^[Èçõö»!Ê&ítY³7ÐôÝ2E?:ÅG‚ÙÛùŒËFaŽz4C t~ù@ë¼Ù8±ÇÍí³gòxbˆiüAê9Ä¡úEز,µÜätT ·2»Ë`$̦“½¨Ç);/ça•v`îÄÃôËÝ!Àгº–í„æ\ ÙlRÉ)Ðó ½wp‹ºÃânytà;wñ,á“¢ü ìížòöKEó%ôÜ+¼Ô쟞V¾Æý¯«R߇öC¹÷4ÆÈýILùÃlJç ã³ÚEp2ÐOMÿ`åÉèÍ}À8€ZüŽàMÕhTçûhÂîi/l¥U"cEwÓ’. ¶ú¦mÚøÜ~§+É[í}нWw"•`Žæc‘ki‰ á{s—Á(…ï4ÃýkZ=[תçêÊ»ÈÄ1G‘ÓÄ;™á;Ý×.í+ixkÎ=ÛÚ .B0#âö8;ðèN–Ó´ßõI¹Áe¨;ëÄàƒ¹ö-_Ô稼oœè²G/¾².‘ÑÍ"€øMá¬9þ.°S¿é( P%N¬ƒ¾Õôš–5PœÙV/Ê?Ë ™R~ÜcÜdP³˜$ÒY>’€€Þ¦Út‹c«Ps —Ðmgs9õâO‘¬„-ï÷Ùµ…i éèCIß Ü:<¦ËÐU9a3>A?ñ×ùÓÊ:H"DÛ·Ó þ8/ÆÈ"F|Sµ«W“Ȧx†X@iŽ7DñT¡Î 1UGÜ2o >+síU¤]%S8dËjxv[m0*èU4½|úèÚöHôí3œ&  u©6!i4Õ6÷¥•Œ¨Gb:…oeùv› üT(­îå!ô áŠc½pãÁ^e‚š6\–æö¹øH£JØò+TóéûD¢d%”)À#¦’ÝqQ'ú²‚¼ã^ *"¢ìé&Žý ê7:™-ô#¯©$ªÃfFÂãÔ5ÝCÎ?Ìg„ ƒjëvc”uö´S{*±úéäÃs¼Æ7YÅ+)úÇ=(»¨ïW¯–Bç~e·¦¼|öO-oGÏ[¶n|6[lcxÛiªý\|/Š%@3¹$æƒxš€m3–ÑáŠ%åd#W•¦sù÷»1‘60v!lˆ^.ÞP°‰1ìj²ѵhE8ÀÏŒ¾ ®J';í ÐÑH•Hi¥ ØgýÛG8[;¢£’´º|’Ÿj‚mâúCØ}AÂXo›àç½ïHz¼û_q¯’Ìг ük¥75g«ÁõbèòL+lGOí¦á>ÇGs¹WÊIû¤óõPþbR¶/¶nKüúÖÌekßiEÞâ€`+ÉÐL DÆëÚ*™dy 6ùÖ§ƒ!"rÚxßò¿ ɆOCrä£-ŠL|ê@æF¹A së(¥¡]F¡l[è¿m¡Mèˆ2GÏÝ„ ÔP}¡¼³œ:'8s§WZwø‡þn¯D,÷~[­;M¸ÿA @‹rŠËûS¹&¸!¶>j’®»[G-[£º Ë=ÎjDóàÎð³wÃÄöÚHG奕´·ðÆ(Þ¸¸R õ½)ª‚‘kب’OP‚'ÿbÓÉ® ¬ M ‹ê¤»€.Æ 9½ºè=Û+dÙ&xRÙĤ{Æ,]’è¼p ‘®ˆ«RÉb)üé)  !ªØ[N ûÝ}¾…ŸìuÕn ØÏbÞh1û¨™¯XË‘ b¢’yĉ?eiBìÄÀ÷Liú3 °´©’ÁÊ}"‰“iç‰p-’€€³HÞzÃÇz«Ú¿ˆ€#‘ Ñ+}ºký·×ÚËçÏÃÓÜYŸºŽ.þºX° ÀÎgL'nðÿu­€®ßv£¸Š<`,ÄÏq–7·ÝÙÿLä7…2Õ-8¹ßšTÇeêeÂî ­Rsû”™OƒÞò¹TCqë=¨K9uSðñ 4Æ}<!çÆ,‡Ÿ¡7¡d§2•®7(K˜ÖÁ>§¦aÆ6ï$iü ÀX†­ ¦XF™ ‹­¥£Ž)WÅŠ’\3èö¶Þ7 ü<‰µo:_Åšù6ÛïKºŒÊ]r ô¡"‘_ÐTöÑÁ,%™@Î÷É~ïc–L`íϪ%ÒTœÊ@`Õe €|‹ à%KJÝWë¢{¶Q¾ Ûl}D0B\¨©ÚŠ3Ÿú‡÷Ô9 ¢$ÍðÉE }Ê }z"ŸT>X7~•¡òxó®Oµøª‰õ xvÐh”c-ù±ex%½s°ãk´zçö›Ìžû^g½ëâÃÎ@û'b¼#g#‚%ÄøÜ=ž¸¹„Ä#qQ†Ž»6”ª¢!L#rÔ+uýMŠX¿‡ä$íЋˆïŸ_ܲB$þÕ‰(È ÝøàTÛæl¤ûO’ípÙ™V ‡ùrþE~ã^ < ÙæÉ/Ù²Ñ â>÷n¨¾}ô#D˜ŒÙ2£1ÑPJ• ¦XíqSÕà­t%f-È–ÂE†_ý!]Ǭ+3h$ŠÈ…dwõA²ºÑoP…þÀn¿¢ÆYå8SÀ<…ñiÂú@ö)±ñ…£N„ØøhÅ’ \!úÅB.nÏ¿Š÷˜ò¶#ìâùRêbîO¡…ø¸Hµ~Î{Ÿ5[V\QAA¡nõOG5w`}iòæ‡Ü 8%À» T éü†f¸Ó˜Þ³_X_±`J«Ç3a-X5j Ó<Ãyq+P¤,úk©“ÛuÉe® ¼àͯ|ŽSݘ–[p+ÿ'ƒ•–q\lÁ;v¹§¼SˆKzo4¨_¡ñ›%J4ø£qÐÛî~ ±`]ül{£i®Sиxþ‚;€?ý $&²ÛSˆ¤\š©Ä åú*@Ž+›ãeS~uT#p˃qgÒð0ª¤eï•Áò¦ê°êG·Š¯m‰ÒNäw­ö¹fœVìSÕB{¥ì'À‘¤ÎÂ>M‹õ‰@¬/;½ u |1s+«˜o*k¸ëò3 Ó÷—HÓCcˆv)´k¤žºö?ºv»YGÉàôp¬X³Ô¢Í]:«$0….Fô Úf—xÿ J] i¥ôÊ©d_téRo„¾Ã%½ÀÀ['¾¯ñ~ÖíLØãV!n©cÑkØ;YÐ3+vý’€€·¥¥“ïÍ3m÷#IJGÀJ[°iàúO׉'ø£n,v;éD猾R©Õ4Óßn’µš½–`ŠÞUYâ2Cšp>ÉËžìNîáò5\¶#Ü͈ArÔ_ωÌ(£ é,÷¢‚=¢Ž<}ª© æ¬&fX£R’1#a6¿s©¡‹í„l?|&6ï©æø xå5@0[Üï†7NL¼vÕYxcé‘’ÉÔmè¶¾,/øª¿á®m§¨¼ï?æW‘‘Š;Ò² /ýs;¬l¯æ¢’DPÍóÇ+ÁÅ{ãÛø˜Z§cáèÚ•x à’·üj”‘‰‡€`ÑOYKm°~î „)}k/­"ó%aEeh^GÌÕ·•H9iÆ ²`ZµÆ5‘D*1â‘@)0%º/ãÎS‡,ùšã¾ê‚å}‘dÑrT¬ä’¿>Å8Õw;î³ëƇKçÄ_®”©m/ÌXC2w8–Ôfa‹©`Ø$oÎ6j" @…mÍ1/wcp£P&»éêá •¹µ!º3n^>~¶¥qâ/ÒiÉø;#Èl¨†¹ª'Ïå€[Ísó ö~Ä’*y2ÞW 9-Ê)fÉf¶IÁŽÛà é(£^2„€Bü‚¹ð°ŒJšŽO×—Y¤ö$ž€çªa8¤)ûè„q=Àñi6 7£Ñò2Ð'쎢 ÃáU¼–9ÀxœR÷–º‰‹º>äH9ôs*÷na'}`H¨™çÔÎ7¶åÑ [âD,c“#l¦YøÄÂå{s@nìÔÐmOqœ:;_ÃT“b½4Ѭ œ=ñ¶P‡NUòó¬˜êb¼°z4ÍN©ºSi“úrÛì_31ƨ¨ÿõ ÖÊRë C“X-£ížGÑw©“Ïñµ³³{Ö3È<ûS<ßqþü+Ô,Ã+‡×wtµ ˜ Ã9ÿ„ëÆgÖô†xÕ  AôvfYSe`Ô(ñi|Í Qý,ÿOíÌT+aA™¼èüÖÆÑöHÀnU@Ý“ì™ÚÚäApÒOf7Ù7ó´qÈŠ¾ð«s_RÈèó3}üÏ Y‡âúlÞìß¶Š3®Ì¦èz¿?¸"Œ¡> ÃÓ6=ÚK–ÁŸ³aP”ˆðí”ǨØQ’€€ÑÒ-.ÞiVC™‹XDŒaè(WK.pã‡ìP¦fG±)™½Øõä1: ²«©ÄPci½~€É²º'Ø yµ˜#úgh°Öá> gàälí….I^ÍɘgK­‚iRýÄw»ì‰ù‡„uQËN°–W×CúÑçÞ]ŸÊzWâ„›¹ˆõÎzx‘þ%Q{ƒÃ …(P¿×6Å´2öû¥ ¿˜C«Ò÷3ætá†ÊjàWJ¥‹ <À¥0Àà!v:OM`¾Tê;Š> ùZQ”x.À%÷îÁºK¥ËÈ |šA9k2­Z>ÐV &9@¸Ðzqç»;fa76Ÿ³a·D¡fQqHÑ´áÑ2{&zkì‘&´í½Ó ®L1it›jÎBÀ]Eaýé‘dÌaøú.j++IœÒº¨ãÓ™ùX!2u:±b>ѯä Zø¦ÓW¶2¾¸Ç% öÂ஑Ítvôà{¿{ššú(Ž.˜Þ39%+Uôˆ@Càûü«-t!{Š;‚ ý½Œ’:hÜñãF°ˆÍö€f‡Î‹¾¿‚ ¬}„WÉàïö™‘±~È D»óêíàC’F¨jBb/û‡½¯ÙD#ÀÛÀ½`ùxãĈ”Çdè[EWd .?UFuFT,Sì®m³b;caëÞ‹×í„+í¿/t¶GEj©bsð`•Ø…ÏÚfí*¶åßkõƒB)?ˆè–Ç»sè¹dc¡–JQÀ½•Å=PÛ›àHÀüÕA§ò›‘jÔž¬p¿T2МLGÄ¢Kž|6V÷$+å-ÿq81å ˆiA = ßí-ëR¯ý‰iŽÝË7â&Aƒÿ^õHÓÅÑæBhk5ï ¨Ç^:a_Šø­<¬,1—›«V/MÝΣ՛)}~edÒGÄ›·PRóSéæŒeåeäF•K…Áî䯚êòè ձ޿t¨ÞÄû¸Þþš‡°ÜdÕÜFcŸù“e‰»^ªK]0+ðø»¸.tÙžÄ?qŒs%ÀG¬Æ<ƒŒSür©¢9^±]ÞKÿÈ =†©L=Òc/\±±¡ÍWmi= íÊÅÃÔÏSîysµKž@Fì´´°¦)èBÿ6g3Ü׈ÖÝŽF!eABÚµÑä}b&®äÇ·eªû’€€Äë‚wl*„Ý}P0H¢Ùbq´ãÄ·ú{Ž™ƒ) žH^‡Wš¦i<(|KÒ/’>Ž9ôýÔp{tú ‘4î"Ó¢ê5í®f!ð„Ê_ÝPθßÏ…céRq¡JÐ`‹¤À !€šÏ–6 ·$|e kM_ÅÖ*0…y:>‚íöã2¦em}äÛÆ|u$ÀBºæ’Ã`tœÐ¯gµ_·*¾¢A@æœ4Ä73xÕäqzÜM¦÷A —ñÂh¸éI÷|e/§Ö<@&Ni$TönÙåâRÖŠ­å\JÑÀÀ&ÊNîŠ<>'ÿ+&¹z¦¸O-ìë9vüŠË4Þ›Ž§:ì‰1•¨ô^»)nŠúàƒ‚nÞφ}˜2w p ow7¢º|m\J‡âù\@Ç¢Ÿ±ŸÐ¶Ò)äKòÝì4j¥\*ú¼ia*«úÌßS€Ò×Ìl4DåDÀâ…=ÂEdUÞµÅbùÛ«‘E¦4›·\·BjHCfº9Ïd†O~¯Ö8ž¶óŸâ~V‹Ò|õÚ¶Æq’ÕÌY‡+;LM(áÑÐÙ-þ4Y‚ùÊRб5c¥üY¡t ¼¤@±7­ÄóüUÆ`p}¹(€¡g-¹~ÆÙ5ŽåwÕpžqˆî³¹bm¬ŠA¬ZW•ÂiëÔ¶Šºeq* ¬ðו eèÅ–ÚŠ—täoÎRã¡…À¨R¨èÍCÿ„‹ØÙØŽ·¨8>œ ÕH€9[“6ÞYW¯$7dÔ‡âg@‹•ND‹Œkê îKy0ÎO债‚·Y î³òd£Ù®r‘ÎX2šðÔ—ÕÂá W |â©Îä÷{¤ ªö-Ò£€hIŠ÷dضøÖ=…[Á.kVÃ|Þ%ŠirÖ¸c$ÇõIé/OÆÌ@À£€ÚENI Ý9 èéÐ3•Ânò¾êbB(¡?anQ©LÝõ#Þe*—‹âãNìJc{q*¡’صê¦UŽEÖ}íù,J…tˆNçGaá>eI󺋲ÿÓ 3´E‹Ä*y¼Ë7ž7Xw¹ chÁO‰‚Af &ÀžÜÓ O\¾¨#aó±5Ð×FÐÊ\å!ƒÐžw ÆIúT2=tÛ_ÂNr¡à‘‹“xüýnd;c„¦V8_{äm|²k'#Šª’€€«3É4|áðî£ÌÞÿ‘êË“_Ä7ï_>>]× (5ÙÔ»!EjÿíË-×Û~%4ÁóüÖ ¼«ÆSÊL ¶öÁM‹W›$b-FˆçZ­#?bÊQeGà[Äk¼a)»4ˆ ø…)´Oš¦p²kŸçr»ºüØ% Â(vx1MyœüálÊ>6Ž‚* T4ð*LJ!^½w‡Ø5õ­8c5öãú뚇e’Ûz©_ê¤ïžr=Œ9œÔE4˜Æâ¹N|QÎ7/Â÷á„ Á^q7›£ë6ž—ÞÁÕ¦÷™.w„ö­¹Þ8 ±R,çË ,ùxò¹Æ–ÿÅ–”Êæ +ÏšääÎx”}d„,¨‚ÿG…ik³: p¯×W} ñ1[æ…¦d÷Ų‡ýÊ3ºÃð‹¬u&Έ o¶wŒÆ L‡vXb ¤<:þG›ä© ‘ ÙUHõK"oö’âæÁù .³‘Öà ´‚z´¬Gê#v´n¹Y+6_d«²¥î†5J'B4SêãpÿA0‚Þ#_.¼ú̉&÷-áÊ#­6[KØÒÝÿÞQª­Ü¹(H)R‡ÉUo{ã.ýQ\ÈFÞ¤<õ59m@#Tèöu´Ö§3:×=PE-EýÎGº-Ò’ ¬ÐÜ1 7ÂJõNÁ§Éȇèëd‘Ò«fÁUÉýÝŒqî’*ýæðÌÃÊàwyB¦¬N íoYúóƒè2‰Í}ö»$¯³ªáÛ [ªº{F'E/ÆØšYÊ@Õ66“Ö€5?×»òŠ2Ø×l>zÅ—4rˆ3÷ |·œ žÔ95÷›RÜADÀ…×ÿðüŠ2¦~ÆEùÖ*è=šê™*‡>dq•/» pͺ¡s¹€U dü„‡…ÌwJœ<©v'Æ#°rZ¹a7Yˆ¯»-å´û~I’€€öQ†çøö35~Iãó©Žø¼J\{*ãº6â¨à'MHf7oÜb]¼ØËäoý6}(¬cU»LÇʃ¼ê-e´ªIöÀÿKCÃ¥(K—›øõ<Ñ`áø8•ÝêÍãø¿Ë²¿ûºÖ#%‰ÿ¯}C'2´QÚ>¯°ßЭ|%÷¦rš€_´0¿Ê™›–QV3p‰ $ i±œK¸$¡cxfS ú‚÷âÙïh4mã/ê^Æ‚ÿ2Âx(<]0Á¹*¼—K·á±ã/FÅM®÷6‰ iïD'›rÙt“)íco‰½3ŠyHwú¯;^ÈM»ôS Pضª2þN˜“µ"š×F›UÖœX~¨ß­0Fç¥?Rq‡9^ е°º{€4˜²UŠh7¡Ô…dŽk-½5ôR·ZCamÍ…šÝ~DåiûT-wW-Y€¦Š1F½kTiCZL;ZÌ_íÜÁÒ]U¦»e#£v7³¡Â˜áÇ“eå‚EbÞ=·°ÑkpCC0^pÌu­ËVÛ•Üp‡A`0žªÎ8ãÒá±Ò‰ŸHZ°tÁ\yQÖ\,¬ïÝy‘“ZÆ5 ½R©úTd‚™Ò¬Øð6°©<ǞƠ”·3Šw S*4 ¶Hx'Ü“]tfsÍÿ«SC±È­lO(á‡w¿ñè¼ðFžø](úíèxP¥¦òB½™=öT]1¸7u€¢ v)ÊÀ/^mçëë ä4ã~ÙuÈ×[=³ÿò¡×ØUaHæC¹°Q9é–Ðâ3?4GbÒç"@œ•$ NpmƒŽ55uT¼o>N%ëmöÞùD’ø”ž{Ö%þÅv .V+«z†XÂ!ÃE·<ÖJb¹’¿¹CC6»updV=lj~ƒÌP~_c¹ ;Vˆ(•Ë˦5°ñûº¹¨…Î!)÷Fd…Þ¦žŠ³Z"P'4œõle…©FiEûÏ-ʤŸ"#ú¿EiðµJs×yUO|×mH­£ôÖdÀãlÝQØ_âMå¤:8ËýölÊÁ#‘FwðÊ I÷%h¡J†¸î?Ì#P\ä·Ë;œ™;ÑÛH”VBTcÁk$8l¾Ï“¥"²†kv÷‡=ˆTNü"½P([×ð¸zÖÒ¤øW•÷ëÿ@,’€€Õò0/ÀßàF&2ï7-2ò¸ûÝ›Š ì`¥ŸTó?¿…JñgÀ±¨Wßì©5Žä©^’Úñ ÞN‘zQ†nûE$ÖÆ]‹E|Qé &@¤«ËCðÊp^P`ƒqR¬'è~”¶ )75 +¤R÷X­Þ¼'ÛDjývÜÉ“LÎQ0Z–d$ø‚ºåɱ8©I”R‡)½0é*ßY£+íÎà¢ýà–²§Q8NÆôoðôY1ûèøøÐhKPôŽ/ÂCC LL)Cý=|Z‡N¦¿WÜD¢r»@]ËèO‰{ÔD ÀhOGà(˜Åƒï”¾=œ«³Á|íµ‰ìi õþÐùLùPƒžü,GÕ+eÔ+RPÞ~ "O®•ÄúÛ8ŽÊeI·¦ï”ƒ‡ÕbßÛAUc—ÝT*¨+Á¸W_)ûÖ 鸚ˆM¦­549òææ±÷s¼Q$ ?zÇjÒËÞÒ¼ó SCÍ î­Geü 5ÝÍ‘åã%€Gª$s¦NµÊd±¥tÏíÃňtÃ…Àª5´:ÛÈ”bÏ[n-c ^ÕZ€˜Gke}¾*/‘ÀŒRлf@º4/¢3‰e敬ô}¤”•fs†»WðÈ JŒº'v@£]´—=£xIµ€þEÕ/Ïî)}Ó1ø¬å2P]¥°x¥ºllwø–‹3ãÍIÁáó¹Ëú)j×`-3N‚šö7bíGÌåQFsb\ ¿¹ü¼™*~`¢ºâ&Ä»ûOOÔ¯ñôO? `œÖ€±eh÷$ݳŒ½ýÞ‘}$%g PÚÂìHž3e-ŠUwB¦Ü?kÁa½X{ŽêÑ Y™<5ýÊs½H$ªÂóŠâWRd´p,M6»`î¢ ‹ŸÚÙ,NÉÕ¾u|Q3áZ¾rÆÙ[ëÕjqŒ *¹Áî]õMèé#èê­!A²z0ÖÀ _l/FìLü/ªó¡ëDÉüþ³FåLèÌwZ›ÃîÈû´Ò šÿ0`Ís$£—‰d$!ÉÎú?©3Œßj¹½³·‘¿ƒùV0îî%ÿNÛ§n·HGò°\¯Ï5[Í D]ÇY#–ð¼\‹ØbÏ*¤ŠÌö4ºÔTˆ‚Jê ÎUV„ÝTFéèbã8Ôú ø¬ìB.Œ’€€¿Ã?7¡Ž'†$juúïÆïñÖþÔøŽ€§øÛ Ó¢‘ôã3ù,À‚MçgõÍWתÒë—\Tîwywèu5öhGÂCü°Áe«à§i3€­nÄÞv´®¶øñAS{˜Y a·JÑ[îp§vOö ³";À÷‚“Ûí*"7î+¯©%áJ·•dñÅìà^˜ÒûW›Ãò¥1Õs¬ºœRPÃb@w(~ïÿB Î @E¦ŒÞÑü«R =Àûeµ&¤BùŒEÇè\øc<˜Üë¶ñsÔ•"»ôp‡‹1*>^rÕó¸¨Òw%7Ňt'Ž¢N¾iUΜƒ¶ƒÝŠ“wœG“»Ÿj¼7 QÕù[Pé×Ì"›o!ôxjÿ8ÆÏŸPµ ´Ï¨Y˜–øT¥Á@éÅåßEÁ'b"ÔÕ"—L1ûµëà&ز"ry²vMgb ,®tÚ«‰sk.Å„¶Tmx[½äÃâ?„»zçƒC.wZc…ϼQˆm׃Y1àβ~¹·ÌÖþS¯Ö¢}9ӢН±êçpÎB•yb@· vÖî_-5Vkoe+P’n6ôºŠ®{(F eMÎp•}æi:8)þêL÷Bmñut0I;:Q}BlP:æ$³Ð»QÐ!© lUþç¥òœ˜‡!þ¨ÅaüMõâQ¹5y[wÛZ·fà¬ôª!Ì%$z=/µàzÏ­EF˜‚nØ÷Ó÷¯ú!k“NÀ^Þ? tÕ×;ª‘8ç,ZðT¼ZYûÈÇ]nä¤n àdX‚Kn†Äò3f⩆6ò«ëÔYÝ<ÃMSYÚέ2—íúÈÔºrµùÂ’GsñÓ¡(¦hnž÷á›ØL7#é;,{õúw'œž b ¤|GTP¡*¢,Él†wÊè»Ê®a F•¸éÂ"x`²õN¼±ä,±J¼öjª§ëýíCƧtÀpy…xÊÁ–«,Zú0øG q2ì~áÌŽíì±WI¦÷«¥¿UfYãùZs`G⋬dËN#2öÊNo‹V@ûz9™·ŠmŒ ¼p¬t“Xöfæ8“¾bÓFUhIÓh–˜Æf_ÊÞq¤n11¬›žòò:Ð*(d™ŸÓßåøV„bw8[²?÷u~üÃðtn °Í«ÒäAlâÙ’€€åˆ¯ÿ S¸Ÿ‚¢Þ”˜œz Êù¢ÇÞ·ïÔ‘ŸM `²]•¥&”ºD¹jGâ£þYNÑ?îCÝv`:<Üà¶ÈiÜž¦ ËÕ*ÄÉKmƒ)=ÁÈüä®›Þ·9ç;ãPÓþ9o¶áâ-fI>".ö5 3×Ð5Kæ£%úÕåêÄIË›FÜ·")b¯¹åL êe~÷°PƒSWt˜#QMQ´#&*B}/x+Yx…Ã\Âû :L׿0%+]ÑuF°^™;âôà`Å„&O1îÝ`<üÓ×,;¸F"‘¤ÓǨ„ JdŸˆÐä}b¸[ ßøP*åIZb¾5Òð‡æn‰ÈE­l4Ãmäpe‘[eô®eê·óø;ÐO†±Ü•ýà8Ô^Sa[¾Þò:X—ZÒÞ’#Á¡À¾<¡‚mšy6pQòR5ö 1Uõ¸pÞk#žÍ5³ø„4L%®U (PÁ&(ç]»RëÆŒÂ*jÏFgÖ ºë¬ÞÂPHå×¹Á§ãIó-F…6DŠŽÔƒèºŽê[ç [1¾èûÒœt;ö:3ÚçDùöfãâ1  ’vl¿™œ“ÊùÃ?¼Mmq( 0·ù¾»ÍKäõ,þýìU]GøY‹RÏ9Hú‹åBLAP4RdwÒœÞX°S“ª &Áã ‹3Ñ¿œo…É;ÆíJ¯6JK$ûô°oSŒúØò©5õZ£=N­ÃÖk`òõ€ñø|{r¡¢c‡б·ðLÀP¹Úc¹æYÓYM‰ÿÌ_ÂzŠí_GÕÁÑÀ*ÜxÌò∊—÷vz^u¤ëM%¸vãíë\.M±jâä{ …Õ>¤Á?4>²@›ª—Fä颰²LJÈ¥é8)Ò;GÕˆß"²…W4©² aˆfCôµK®doƒ°ü/÷£Æ˜t课j!ÖãAO¡7’€€×õSξÙ=ÊÄáÒ9XŒ½–ÙìóÊû¿q›1À“`«öà"£‹O“½ñÿyˆ.EÌÉ{ŒŒêsкR) åí¤9DëÅü+ï”v2¢T5àÑq8d”ø•Í oF“)s9(—þûýLC©½†È&/[mýýw- ˆr’Ü-³Í³i²/c ÄÐÎã\̰ï¶óá¨zø‚RQú›é°çáÆVöç´èª©êU™nŒ07Á-’‹…¯e2A=ÈÇîù­—Å ç/Ì?‚jmö)°V¸ï 'eè¨í•&Ž$÷ò‘²B¿† ÕàשÍ])àGmž¼½#Н@,tÜOTV½C_ûðJ†çfþ°ÂÛ €K›`Já0i§@Ødš'jŸ5Öa Ú*/A&îQMLèjL²ƒ8®0Zùsà WÄÏËJÎÞ;ß³Öé"0¥Ñ¶(&q½: ð´2:Ũ‡ÁŒvœ(ÖE‹ùæF¹ñÄÃmé7øÒà€…až£º:Tdá;ï^FNü à:ÔüPÝL¡2-²|ª‹þ¦& Äp0~…Óá}6” V˜Éœ)KUêÞÉÝ:ô;êf’EÃMà1ò»+cþ%¸˜c;”é2VEpN$ÝKm`û¹0Μ¢ÏáùXþ$ šRÕõCæ¨îÅ!!ì§½„áhóžÓÉ}J·‡Ë’úⵃ!¾- _*Æô5ø0ùU¡ŸD\±Ó?“)´Âb¤*@¹Ê™êï?39o„t†ùÏ?³ëà@¼0VI œà–Ë_O /C,NÞWÄöý Ýîó-9ø!ÕY@l×~yp5àbîè|«ûx;ðž¡è‡éœ<)y”J…±ÔP¬Ï¦LñB}p¹jÀÎ/»< á(|x-ðEGSÄÀð†6ß Ê…/‰I¦ô ¬½ÈÑÆ¢8°wˆ×œªQ¬Ds»(ÒFqü̬Ø|[èì ›½pe?àÆ'8Nð/T=ó–+êÜAEž<òùaá`•Ùw‡1¼ -”XÌ' ÐcHÛwG»õÆQáN8€ ' –iBj¦.†F¶Ôg ‹2µÕb¶Á÷/þ ÊžVu™­v)€„ž¿(¾ª¿Ø|ï·²ÀWï¸÷¬æxx¸»/8Ž~E(¢ñ÷í]Š×”¹ÌÀ]0­ºÖWغ’€€À €pÈõs>ò¤·ÜÍn"î¼ÅmȳÏw3âe5¼?Tår{ØD!‹ë¬râ4âöGëóÏq`4 ± ÆD-š†y¶Š¶ÅûC÷íD»æz/û¯I^=ª]‚ŒõiH!€oð·ÆG+ÇO‘ßHëà3j]d%òQîGEZ@Òxß{}1nÎ#¶Ó| =µÁ(âàÖ¢j:]Óφv~åÙ¤,c> tHðÞêÌ0þ»7Snß3i×’]ÒëMþD—¯Œ«w:ÏS™qßsÕ# ˆ¥<"»´)$ã@ç»H ‰ »ó¹­Â¾®ÈQ³D¦…˾‰là¨)DÃb«¡“´ëœK¹ŽDpWÂì/*½ÿ2â”Eu³7P¸!Yê¼)JßCažÂã Äl>Ðôãø–5A& ²]Á:(RºÔ'=E{ʼ·æ!F—H?žp`d*äPdS9¸n©ë_FÄÔ¯‡ïÚ‹`ªQLç¥ÿ“™eÙÃô1‡¥É¯»@¶'²úR€!¼j¬]-¥£ª&´Ñ`AÉaþ[®YÕT[˜²ƒåiA‹‘îhÊpU¡ö…o-âºY2ëJ ¨—îGï¼ÙÐסUÇA3<·‰-ðjºiËÅdLhêzá¶›;T  üÚ–ÊšÑèS¶mtK5qÔãsÙF_êaƧšbj/☭±…1aŽjĶM$ÖÞ’ÖO³äÙâNÕð·”å½™®p‚”æÝhö&poÚf²´r—6‡{8JA\4Un,ÏïëZì ?FÆŠïæódâ­¬‚Ê®;@”žd¨\ù/upqÝ_›/uÑñ¼NBÚ•Íè˜GÉ$qèÅÙ‡†¬Ôfˆ¤Ü3·v·ó³¼Â2²Ê‡ôW’øâ¼öFZ7…í‰R?–»ãóø ÍÛ}Ýàc”ÒÔo‚˜îu›Ü()˜°‘xÎõÍ‘`Š¥Qiî˜[ž_43˜a,¨6öáõvX„x?vâËïÔŒ‹­ºòB#L¥÷dù_§¯R@\Z¸˜go Ïa¶ºG'“Šgݤa~o‘µ1Fj¿”QRo³ÚUÍÒŒk³´*ç]øåSNÉS«L(ÉŸ)°y—vŒåÕí À&Õ™ÿ…>¹îµŒ¼eê¶ ½hŸÐFÍÿí0Š"ì—LvØå}t”.TVVa8€j¨ê9LʸiJõÜlŽÔBweѰwxv@<ƒz\šæa2¹'*»¯; šþ 2r¦ì]°þwßMïåµ[DÏÐár_»õÝ«]è¶ÌñDÇ[-{;bÈopƒ„z°w×>¤ö@%O¾7m,0:;†,‡<ÿ&gÇ\WàžŠÞ& bÓ„’2’_ •i‡eéQýÉJž€ŸïdÁ¿Á4ý|¢†ÛN÷(ರx:f9›ŠÖŽâ™,ȹâÍ]j×ßäí#Å\>®GôØé$ù{ m:¤•P¢¨àz}²±:€µ¼E;¢€£xf‰á3l{º8þ¾9Üa5ž0r'Dåœ?+!¼ô).WÌþ ¼Ôëô_#Ú•LJ_K>ö³[¿ý #ȶ‡[ŠW2€¯«8×Â"f[0G‘MØèŒÊþ$"^wô#R&LæªÓ]ìÁø×hT„”4;À×ͶÑB§%JT Äÿ>góAšLfb@¤J%¶ÑÓ²-§ðÕ2 ø /§¤Ð—Ò¸œ„±Î ¶ëÓªRbTñ#Ãýð^ž“vh‡ºÕ‚Øš.v[öõ=]mPg|1E:UÄ-6`ûô·ù1ªÙ8-Ã_éóš#™p8/ª7L_”Ó´iC±Ç‹¥mJ3*™àXæ¹Ô kˆq4xê˜7Ï ÀtJ÷«¤°áŒÃ×Q׎nŒØîˆ«L:È;l÷p¸~S‰ÝgbWÒE¾ =¨c=‡¶òÈñ…ÇàCZ²=)`i]!(%eVE+y¬ŽØy6Õ…®x³¨¥°fDËÙ 2PjµÚ=ëä®@vl‡ïÒSÕ+ã&s"ˆÝm‡ Y‚¯î6‘å ¯ß¾Ë®Ö¿éÆ¹ôóP„Ý{bV<þ¦a¨[=ЀtuŸ÷¤ž ¥îáÖžYÐÏɧëæh4±LÞ7ˆ ¡ªa¨~v·Á° –sç’æµèJ,xÍ”¦'ÏñQétYÆ,´ó슩MDàä3{‘ª¤7Møþç>Ìר#…¥*?g¦ânHÙ±eRÍRrÕó¦{Pá¡Óª¡2ø^M¸e²bá9ßöÌà†–U‘ûÿÜÿËõZÔª8@+Œ?›té¯9 ÒtŒ¯U’maxëîÕ7ÙqKÎ.Î(¤ ¾žaéú)Ž‹Áò»EÙ-ÕÇÿڹхneßÝ·7RüzvÂdt䨅dÅÒzP‘"0‚g9FÞ‡í%µ¢]2H¶ |Ÿ'ôE0ü¿­¹LQÒ©¨@³)8ï­Â³Kéva©«Ñ[-îõìv2†»Ïý›ÌÁj~»Þ˜ÂE壆¢¦×è(ê.¶ŠœÚ.=’€€¬ñ*ÆŒ7>bW]þ[¬A3÷ø#â Œ[×ñxpú«­3·¿ãL[ ][çCñýGÂjhÛ,•È+CúÒ@ô£N–TðPÈÎÃlHw]—^hq‰aÍûÔzõ"¹ñ>´ _°ÈYO±ÄJOAù¢Õñœ[û2×Yõ@ucõ4Å1?‘¢ôÄ„îÅzSa ™Ùz :×FS‡³:¼_×9™ ò ­²µªU)wQ_1 b\w e+f¾pÓ„m…Á’ÓOpd¸le™S] N‚ –oÂâ"9g¸:ãþÓ‡eÚʦ› Ç&@aùû¡µòÝC:Ïp=þÂ4dbdèž+Õ-õûóv&EkHU=#ËÝ™jஇ٠³ T-ø›Fj”ë„üíoðݨµsNƒëe‘®IÀd`U­Ö^ xü¾>ÎYÙ–º…â·N}.Áø{;aœž-‘µbÓž8lOÛ˜ùæ©EÑanY‘Ne&ª ¦Ä#çÍ0¤ÊG»×¯$^ål¤ËêÎúopFcÈËŒ’1µ©³GY¶ÃÂ}çý ¡Ï†æEÃæ.CzÀâï*rÓH1Y$m”Î /ëÍ=¦°ág/VÉžjèE+”Ó¹!‰†Q|®Íý¿è;s\ö¾öVF†ð:…ƒïñJy‡ä‰ã7nQžÈQ>ùÑ‘.É„³ÍúJÇŠ_c³KjJØ¥gÍí’dͬí˜A½(£f›ñ÷3 ¤0Œ0xJ£nqàd­ûær¸ýÎT2‘Ï÷—Bƒˆˆg0FÂú¹ñlÇÏo‚~&}ã– „¿nVô_¢aÍ÷Àø*ó6ùê~§‡ÂÄØSI“âþmLõR9[Ž.çÝ8ßñÚ ¶çGÆœ©ù¸@Fk‡Y½uu8{¡3yõØíHó^ÿ~ûSÕîœöóyPªêb òÀ¡€H¾b1Ø€Šß] „†=Í4¡œª½ÒäÁ zòXÅï9P¡«/G[2‡`žA«¸˜fºàœ3¸Ó¸¦ÔióÓ.½‡G¾–GËXšžR1‘ÆÛâÁ:TÀóýÀ¢-¢° Çíx&e  ô ¸é†gwZ‚“•Jº*ƒ‚E4 ¡ájú2ƒgw85÷gÿA³¾ÎKzw "ë £È]žTYÙ¦êŒOU’€€«;·k„#ÈJ°`è* äç1AxøÕØR¸§h;ÀâbPŸ*{8œƒÎXªÄrТ¸!íÌ6ó.Pu‚­P¶û8¶¾¶;d²¯…dÂo7oG)q¹M‰mkl6Fz´^ô`øðÊ(¥:ÊÅ•>À½6VC²Ý»‹áí84ÚΫ²[ÀkØ´:Ä!ü§©–ba>uò¸ ƒy w‘9ö±õOùÞÛæmÃ%xŠ`Ꮃ¿6’8^ãCa\íÎ_ø·¡•ÄAFi¡`«‰¥©[œ:1ñˆ^yQ΋NöÁ½£±)ïÈúG4ª¯{¼L}ZÎ&Ÿ¬#× ·‘3NIŸÈ^_—¹;?Oýæ~šu§—¨ä"·@€VkœKÓäÙ´KC2}™¼Âs?"ª–ì¥ÿ;ü¡«D6V$G´™íò–4ƒ€ª(ㄤàÑ»[/‰DæUûÍÇc#ah?–äÛ­á1ô®Þyö ,”g ëû¸yçd-0‰Dß'øÓlYyšOÅ•wFÁPè[0r³Mô¤6A½óDu¶Ö‘rVCrî½€å_ã*çxºŸC–á¦*”u<Þ‘ØF‹’5[çÐÚŽK*¼MîÃGâ±²;Ð;b31áò¿kúÚ/÷Û1O¹™½A)ÛÏÇ©– 4Q-Ò6*nüŸl#á³Ð’rßÎblYMj%ÄÔˆ¶Æ848}Yk,$ÐÀ"°Á+¾JÔ}· _V‰Š:‘Ô´óšÆ2Š^RÖQ0,·[•']UH`Ü]¶ù›3 #xýžõ|Ž[«+º‘‰ÍrÉ F¤Ëø¢:?íYU SáûÕ ÝЈ ò7öø]¿Pq½tª*K›8OÖ(Ü×t£ÛÔ›]zéÚºÜÀt|ÐÂXE7õïK[…d9×8ýPÉsªsá(ç°êQáÁÜdl>ñ Å“ÖTW ÐÚ×àJãh9´CwxPqɦ²q¢-c°ä8æçDv–±'WH,'ͶÑO­ÝÎø}rœ\ï« ‚J8üsžÒ¤1¹aÄb>ìóþè‘.lnO$NÇN¾¢—òi¿õú¦D1M«ð&m(TíŽØŠ{n3Æ&=Ó‡þÓ‘`n5)w"è_ žûÃè0œðÙèµ{½›Ñ °ðìïÙ: ýºÚSƒ’€€Íãk®Ž‘e]d½ÅvVpÝhQ .#XUh-ܧ©ôì|+$«T¶ýD ˆõù3cv·¸ŸS–q€©é?¤³U¹Êð×HàØº(VÇÒ­Þ;N[•3:³0Õ( ðt‚…t‘x ð›Çò*ˆÚ%E£H[ÑÁs8z\BƘ…KZ •Ò•xÁYæ†9‡æ–Ê_”%s6f¨ç£–aö§d·43ÇWöÇW\V)°ˆ/¯TSˆ vo¼=š´„®aÊm,UÊãÒå//(ñS!iEvÁ¶IáŠ÷ìef¼Â<?Q î²¥”šªo*ÜŒjÄxÒ娮 -ëû*"ÍÖ”ÓØg/å·R±ÐŽÝî;’¡mǪ»|ÉÊrÖxì)"՜ƥÕêTxsbðø\¡ãgî4ù1iÿÛ ÖM`Óð‚2Y‰Xçq½W Ïâ娠vÑÁ¡÷Ÿ*â±5Ù' L ““Î,³]bá¹òVåA’@¯746?€o±£ ØÍùKe·<°èO„‚®ä+½,Táù‰°”«fÔ|rÁ VanÿÅîÓZXÒ,Ê[œA”M‘( ¢ßIZ€˜Îˆ=ßö„ˆ³…à®nn®—*c›ëØ9€x^Ól3x*»ãÄl0ô‰¿ü­ N”PIš $€Ê 'n Ýé•DÇG7( ñ;fh‰Î ӰߢyÍ´=á.Ï¿‘tn3Ž·ÊÅÎÿf‰(o³î‰û»mÁÊiÈ úËéê5¥Pé×M±ƒ‰ fôž4âßó(²?4ä.:Ⱦ?ŒÇó<µ×†&\EÉP¦xgõ¬þÀÌŽ 2¡¡&'b6⦺í¨çˆß Mc@î $4*°æX v…w±hÐFNwmñC<á‘_ Ó¤BYÚÊ0¾»^V»®%¼?À©™€„Áµ#Ïà›¸À©ÀÐ@r*‡Ä|ˆTŸŸI•!ÜåÂ6mæ+T¿£8±¯ïK£í/4¢‹f˜.[ÖDFRÑ'¾†Ú䑇 W-gߌš^]ZUã¢Ö‚ÿ+¢ìD¶Ë%Žàx 4:´£M~H ÿ·qá}¹B„GÄ·¼¢±$¾n !X©êá?k.(àz˸•ÝJ„º Lz ËøäúF’€€œuȰj±cÒð˜ãÁF‚ÄÛHôÖ«G*y‹â#¶{¯¡¼/ö¥…×£‰ÀX>á!*¤X„©¸Óƒx¦6²âWÙ¨—c¨Fîÿü¿‹7™Ú»”µeò…]Ú¶½ƒôÐ2}i£—ì¬öJE¯8ÈÔÈä}É»‰³·ØBš‘…ð6qÔ-UâNoé8‘‰ß:ôZV\™%“*üð & ñnªÁ)V;ÏNLàÌÇ0@ÊÁ"®ßˆÇºÜMqö6¥^›ñ'­(#R ‹e€òeûLS(£ïÉ'~ÿ¹¤ªÚˆó'ëÓhƒ©®ò}ÌöQÐ ƒ(ôã|r«ü‰«Å¨Ò.(¿ÊJ¡èÇÇù© YòöœÀ¶J?ïĽ­£˜Äth˜+Wݧñî ú?$•ÅÙ1»+› Ôõ~n×’U¿f÷•, ÓúÉÁ³¿[¯‘¨6u]ÂÑs;áM…öÆ¢ "«‘›ë0utÀS/’€€µÉÛ4f‚aÔ/pi$ |? ¤8†:Lsà:µp¯"½C¸ßkêDÔ`{@Ó#ÁY4æPòm,µïß.‹ëЦÌoÅJà9^º¨2áZÇ–gò ì« ÂÝ)ëTž¯ãÚ :­¤3Hu¼é6ù¹jAüI6¢Y»6ÏÕ;UÙ˜Öël¸,U;õÊWØ2^”©¾E3j^3¯ì2 ôîi^ðà1µ/;A:j" ÇQ»f6'”žjõ:` Mo‹6Æ€©]y<‡ðôŸbcj¸‡ ~}õÃø‰‚:™óÀÚI•R”¶jϤØJáò¤ˆ¥FÈiïÕûÿ)è$ÿ¿´oÊ™õãhÿ²TÐh7½ ']P(q媚æ~R®¯*\1ø[~¸ìxµ4çiæÀ.­ ž¸,wk‰!Êâle="}7šH33¿o´°ÀŽ`kÀ»§Í‘Ä ^µz¢ÊBË%Þ!ÁÏo4ð·ÇZ(SáÕÉèaïlî|Ü yøKú:ò=;•cgV•µgY(Å[×èCE+GDü‘óŸêävËú*r™ômÈ™^¿â#‚(bŽßv§Ÿ"2ü•±?C(ALªÔÇÏÅ5Ê&ˆ‘9¸^°÷gGÁÔdœý^sÅŽ+ÜB §ÀIŸ2Ų·Aé3¹}t|MGaÜ®Á{w_Qó6jªPZ&ô_Õ÷~-úíºò“³>8(ߤ8Ÿ§*¶¨ #ˆ5Ú}‰iÏ2¥ß!ôÁzâªÙ_fo½­«ñ…Ì|¼¥ÇÖNÔ¶Ž‰‹ÿCYtèÉ=c~ ¾J‹²\hp†| U-3xö§Ösþ–,ÿÑýtâ‡ÊÀ”!™äÌŒ;iQ]­<Ôn?¬[LK,(=ÝjJ*q—6Íë¾f؈-¼ â²¼dÖâà>Put.µ0ÅgÞBª;6m¡? D°þÊv( ì¯JËRØí½w"Î~D×Éçyº®39ªCqwÈ‘¯ß#küõ÷m W›ûá×ë /íc3áïØùÿ˜gÚ’SèG÷î’1:ÏoX ‘ÉÃέ0¥ç% ²BÙÿ5{r~U“d>ÜY&G¨e òiû¼êZÿ¾Bò²\qßd&40e=8ØCäÇ•w(z›Ük%pÕ@¯!Ýê1 Ž¥–’€€¶(©q‡ÙM«ë0_Mî"ŒuŽQU)zÅ“ÿ­«¸wfñÖ¡FñÆÉŽYº÷OèŠîì÷•# ú£Ï kÂ$›ÜÚݪ ¢m—póEù†å¨~%ÿqb;b•IûO#3e¥¾.@¼l —yŽ–pk”ìlËÕ6ˆÃ»P@L_rQV¯ß‰(7KkVÙät£È?ˆ ËY·òÂS·†Oªâ~3¤X.a*)‰a`êswï“âN§‚lÞõàqôU£Þ^CV‡Q ØüšÌ±ƒG,É!Õ*èÆ×Xü×”&o©jÜqÆê/?Ce•ùeЬ*¿‰‚½Wü±gX1-­à(.Ʈ榈w+ëIÄ`Ó# Bo>ñÞ©SÅQvG „]€v°0má‡Î2ô^Ti˶cc¾ÁÀÀQ¾À~}ÉCºÖ%»;¶ÉÏô¯þ«ýÆV rZ³O‘öÙ|Ö¡Jš»«Žï ±„‚:ÈÆ >KL6ùwÕ÷ê³7UxgÖl5ixª*äØ?˜8*–P»ù¤ œ[òôËÛ›À=ª§‹­ó6½OtnˆÛ ¤­uÔ!$šœá‚àšõÈVƒ°ÿoa‹! mlVFöô±’³Í¸ÌÂöu±õ’jºRJ ö°A};Òó*AÌqãDËpfìl zbK#â>ÖûsŠã)Ò¬PÃ)›(CM÷õgªkêW÷j’–ÀìíÚÞBDZÙ89ÒPúM³[G_¾–¼ G/ÒÒévƒ‹çÞŠÚ6UôGgÌ%ÝÝFQ#ÑÎÁ‘.x½fˆ÷Á‡³±:×î/ͧY-½·.bßÍ/ôRçàõk[í¯dà 0Tñ ü‹ÕIŸ²¨¿ÂJgÆœÌ%äbÚ=žÐÿ)ÿS‘-Z˜µY÷VAé¹ëØ@'mô6»V1ÄXÿuçt€7PŽ©®-¼çϘ‹Å#àó²‘*®+k؇îˆTZy:„¬ FÄÔtI–tƒ‰ÛšJÌ…”%mE”zÔßJü>AlŸ*ý,vö«zb¡a³ß”®ýäóáùË‘¤oÃ%&±0´3wc9®""KºM¶ ©˜T°¢UJ ½SñdG®õ·éÃ7Éìš íªæ&„Ì»ràv,þ¤Ë^BXºÉíWS]’€€ógåºj7­’°æÂ<‘Pˆˆ‹Æ6–ÿ‡ëV~ ‰_WWøÎ¡ n ùÚzȉÉ"Ñy#2¨FŽö2é7,î°FûNë肘-ÜN-f𡆗áé©XœÍ¥/Âx4‘A¢íÚŒýD6"hY®y$šaJùŠÅ32«­«ñ§L»Ò4 U‘ÈäsÛ‰%u›‘RYáW>œÎµ.¢¾éš‰Z;KíHu3sºh–[ûpÄO&eb@´lÇ©75™{Ù)¬j‹ÆG3¨"`}Y­F®|y%nšú—ydYVÍÉ~Ú3^ràÍ­õÔV¹*ßs‰?«Èn{Ñ‹% œ¬ŸJÛXÄëo¨ÌG+;T‰ïéÞ…aJP…}˜µý{w^)~4‰ƒ,7á^ÆÌþHÔ—n$á­_ :Èu[Òutˆ1F ë~ûɤ ²]¬¹áüTâ%¾>7ÜË’Ðÿ.|Ü= Kxù`;…šXJ)ßg‰{cHò¶½°¡6Ê¿—*§…”¡öŸ½íÊ $&i+=ï—´6ãiÌW¨tÀJÿ ¸HnptµE4 5-ʳŽòœ;í^xŠ_öã=y%Ô)]|î²)l=0~bM=Ì©:ž9³Ú )A]àj#—jé@‘›õþi©÷RÏïù²üq žŽ#!2?Iä '^;‹Û¦²~ø„^ywkqEëîÅLy:¼y\*¶“Y£{4Ú,óÂmhÓÛË8@cþÕ—è\̎/öW··œ1‘)¢FËM›yètRÌåök¯7¾W!‰ÔôNö3’¡()Eáö~ˆ‡„~Ú×ÁY¤2¸´¶©C¬Ç ´^‘‘Ê=¬ßÊ—áêŒZsÃ#Jd¬Wúï…è~Õ={öd§ a®p×Åî#í¤UoæmLƒ¹áX—ÙIðã`¸Ö•-õKkÒbmvrï[ÆøÛç ÚòÏ„ ùsxÁ%ߟòÆü*`3ÛR ƒ#’2"=Dúò÷c/½„œçF/èÀ²uP×·ÕÂ•Ê ^‘R tÐ-¸T`¸¦ã0ûfrk¿CãÜ1­¥?,d­ãy tãÆpÉ)ª}±SóŽg¾*ÏŠ ƒáôâ|h¨‡m³E3s}4˜æ½*²¶¹Ha‡Fþ’€€ÌD®Á-Öm¦+ýdÒ¾þý}“6¿kÏ ±¢Æ~¾m–›Léñ\Cx±nê,¥eOÀS‰Ê@3îôSMvx¼÷iÆ®²$Ž Éä-ˆ>-¡xµ0qª»ÅÕô „sý/ºy…²Û7ÿÓüeôë¦À[ù±Î " ýÉûM"îgñ’3c&çŸÜÌI9‚Ó™9B¸Lnß—u#m¸·á;¦ƒÇ†*—ý<—ÏHÜ­tƒ{³ýÿn%ŽûˆIüu¶l½G{òOŒ!/‡]^ÞŒÅH‚±&gÙ0Qt>–0ã¥Ú°)-ÿl’Xb¬–×-’,¯WÝHb|´¸ËÁ[Í/¨®èHŠr¢‰ÜKŸ“Ó×bÂ._ÏVô?M2ƒðm9¢v) nÖÙÐ/ÖœÜe:þ%«³ÊK’ƒîœ[±äu€?,[\E¾ÈÓEûð2ÕœÒÐ8ΩãâÁq0O°¡®ÐWa`úú†Ɔ»Ôk<, õ'=Û_ŠŠXTW%®JµTâªTÖ{ì+äûGñíìÉtº‹ëyu©±\b0 šÝ6£€¨Mm³TËli€ÎŸ¶FÕy!kð…Ö|a>DêQ¿©Laéðnc_â<‚"„,o»Â¼ÌM¥åÒQ€]+ÔÛ éH$vÇ``ÙÏéJ Îûãê#PKu0¸Ý{Í'šâ—’ ºA¨žnWS‡–4¥lÛ‘ÿ«¦ÍUne§*nÀ}z"Qó?¨ì!‡¸„K*D¥D8,w0â2EÌögšG¨ wóþIZŒð¡4 _<öxÞ™ºÇ"ÐÃÇ"W÷Œ“{aÀûŒëýö£ ]³bìö†hèÀB'u?0Kåb˜rî"fÜê;/*·Ž CÍ;T)ÙCo‡K‡xD¾Ì›¢ßM¨›}ñý2¥6ì T¯.ŽÛ^Q‡]‘+õ›¹õ£2æÒ«Sø¡Q”Þ|Bò,¤ÿ¼²À6Ä6« B8æ.R—8’€€Ý G2!ÏuÜ3Õ3´JïI6BN‹³áƒ¿ ›}L‹©6€PöØé,»Ts¹»¬í†ûñÊåÈ8¸¶L€ˆðªÅèÕîóä­ö¢ŒRÈÇCnš×Ž…Ç$Q6œ ¢…OYŽD­‚ªµëçùцtŠoSî­v!q Šg{RwSâ~¨ÚRš9¨·š0E&‹Ï *xRPdýÀªI—¶”1Úþ}LŽRüÑEº´=ƒ*Å+Ò; ì¤ö¤G0A²æ©¤ƒ.à&ÓÎ÷éz}62ó–¤9BÂþéñÛå­Më’´¤ù“ ú@é[9ñ_ SŠUè׋´³CW$Âç ÆºúÃñ}îu­´šòNI ÎOdŸËÀZ }aÔôen™¡'¬²RÖ”ÚüZáX˜અžû¹”K°×µY1¯¥NŒk`r•'¶†’PõdÖÒkSX ÷á‘m`Oqâµ6ÐÒ‘Í?5bÕÌ)Rœ®7^‚óL¿S3o—™nÂx­£Õ&µ^‰Ÿ+c޶ɧþŸç‘ôˆc2†+âºP±¯#ÉDZ[ýœy•—¶áY«¨áÎN÷ÁyÁ›BÄFcÿÊTy{½3¾TþÍó$wTªµ©çö «Ð@„€Õ²S,ÞœÇÆÙ0#ç6:Þ[Y6õ0˜Ùraõë.Ô¤Éz+Ry“(¸¸Òð>"¥$CâƒC1‹Ã2ÿYk•€%T]&DG ƨ™¶¢ÓÁe'±­%ç ƒÐ DÿFÍŒ¹ó“>Þª2?üÊûn´ƒ9k™–[U&êp×ätµ8˜µ–‹4)ŒS‹rÿö”¤w(ôæ¶'zNÉZìïÄV%KÊüýSp\?Dvͤ)šMføü£ï/™vPéUkÍí@…$|”ªWÇSº "\ ïáyxUbyeœ! Ûa cbÔâHˆÊS6&P)Ö¥a”4®-Ê<øŸåÕôS6Ý‚䯫J-…ÊÆ}›Ó|ÊÒ2’„xtó´7„ÍÌ|]ÊNV5‡ìç1ñ6Ù´ÇPlØ÷GÓ~` ›xKT½®Å@n¨j¤ðSe7f·¢]Ð>p„Q‹*GÙsù}’€€¹;¹0ˆQZ—="øÍ,`‹’yëWîßX‘pXv†Žý4¬–¡ñ„AŠÒ7u ‘ .m¤ü…HÏ•Aÿëÿ¨ 4'¶¥šç–…†ZÚxÃâ8Jî‚ûÕzµ½ÎÚðú¶’s) $,;~¼ ïË_ðÀ¦Kiv—û½î*q“d)•Ÿ,ß»1Zêc"A\IÑ+dnëNpk­ªï” ذOÁdöûÑTkÚt©0ì4bÛg6ÞMu[v8ŽËìÄ.¢~®–úÙ!©¼¡c¬šôWÍæA†Î0!,Xhò‰2º7­vé.CI–2lxp¡S€‹ÏÛÐû-wŠE.Y`v¶;£˜4'èú ›¡jž´ý-sA=y086س¬EÄ"ñðüDŒ b=Æ ¶ÁÆÆåy—Jò{DÅȱ‚úÛ¦¿òÃ2¹*3’‰|én™$½x;% 1ªÄ)©®{W„£V¨5Ìç/T‰ŽTÝ'ƒ3)]àÑ”— )•Ò8kálNnT…<&wo½mÞøöñpc¾hˆàgdu€A‹HÐøL˜É'^)Ó S¹Óöä-æ\w¥ŒyCÐ((5Õ z"»œœ:«¦ ßÚOÌ¥Iè]ÖxRˇ ¯_į 1]üw}XwÊ*$¹G¨›JQ¦uu·œ„eè)WçtKdáRÉ{NO¯goþ.%¥í3ÃÎ' ö Òƒ=m)½)X|­éeˆ+ïMP".iö×±ò³+ã :ÿPÑ$ÀÌ”ÆÞÄ;jbhUMî[ƒÑõ—ëi“`d’¸@Áî­£@£ ðwµBrœàŵ¸Uæà~SöætÍÈñ›¡Ñ#ð%­Pú;ʬ­Ðcƒj nþX¤Âè?ÀÕÖzу…»‹ùÙf|[±iPšS ­0~¤¾í!%=±D» |õ¡hL:kÞÞ]¬¯(•Ê,Q¸T*×ÝFþC™båýï‹8û<£ÍC5D2©Úo@×âÜc½×3Æ_¶~Új‚ ‹^á§Û•àNPû£œ{·e>÷¤½ƒ}˜ù5¥äÌ÷3³ÛU'¯z~¡ôJ±«É "¢•/Út®•_Cgš1âÛ=£ôNI(Æg¸`Þúqb’€€¶Ÿl§pšKRRœrcOUÓÒ Áº¢_¥Õ zª$0ùlE­’ñjåß»»2*)`Ìy@ìH„½ý¸‘TÝ'ˆk¡(t´ÿ¢ñXÃMX¡üåà7'†N\‡Ø1u‘(Ú­›A½mVDCå–7ô9Ñ&ªûµˆBnƒ)‹<qU&T )£tÒ­±'•ÓÿÔ9ËV9r¢ívú³—äÊn*ÍcÅø5œeó[Ör žï&×Rèbb<Wˆ=´T;°ýB•…ÖUú‰ï» Í#¨ôíÒShô˜rŨfQå¥/øi©{…¦.ËXÞþ½#I8 ôoLí²‡ÎçËÒòÞ¿’„…%6\G°XÍN3åÉö8t¯H]nÕa‚ÂÂ¥‡†©‹»ŒûÞójþ&Keõ£Ì°èt¦sÈ}.|JŸÎGü-{ÄRVFµ²`Q/LžËÚ½]PIج¬4°t¦–¾ˆÝl®µwÏ0Ý:üÂud¡YÁ±8”ûk¸»a§ÉŽÚ\’ïÜ6г8õçt̴͉kuOu'UsO2y/»”¿â„ÔÂÈòÈêG4úhyPó[®ß«›½¢õYOÐÉ6Ý`eèV €w­,ªRÜÝc*|.;KbMÀDªÞã8ÒÓæÌºñÞha{#þœéè7$ÛG宯¬?åáäµ5ºO­g‹ã`ò-‚¾_%J\q¸¿b¶I-¼—znûcªû¬_18{Zx~¶øƒ­Ç0«ÉùF°¥òg¡}C9J·0’™o62”XÇ$ÿsa¼Î¥ &³~RTñ•KììƒF‹¢Ñê½.Áa—F¹êEmœ!Ñ_& ëF~ÜË•=×ÊKWTzö7EÔŒo!Byõh m\ÖGŽ|Út .tÏ?û9A !Åv -i³™ëÏÞ¹2†)ÂeÈOnµD†S§7€È &0µ"ï19ìP…þ,½8ÕZU9ÑÙëèIãUãä[ÜB$b8ñ4—o'É±åøž°fóÚñØ™¨ÐB¸.Iv’Œ,Ù.À}¦klW\í†2×¶‚ï 볫kÉg7Cm°gE)$?)|ÿÖ¬1¶Åõïµ÷žµN:ºEuqЕå*NþuFÀÈ‘×ÜF¹[xÝvšÞ"W'éÙºÝl@¢nÑ$¨¼Ø@Ÿ¹Y ÒkbÝ<âÿ²[tË#•JXQ†;Ù€+=x…³â^®• ?t$Û8EÑ| ´LXdiâ,ðTÚÑë—IxÆžzš Í^r©Û\$ q*½y®yQŠsÔHÀ²6»~vµ%§„ŠÄÝGô1 L>w°óÈÔZÕ³L)¾ÃöŠÚ†½…3íYÐbI:ý +„<îöM3ó„hi5ÖÆUYE 5²WP†o6Ð?Pð|¸Ô¾iXŠå€ÇBûxQw¦nKY5¡&ØN7DìÛHN†$fþ$tŒ*oã«þu#]£/~ô²fw÷\'lÎCà²àËi¾Œœ†»I¨_k‡¾™Q.I§} ë,QK@Z”ÇÁcYï[9{i§ÌI±ø¨!K‘%PµðùùeËÚŸpî¿Ér9aÂ;BlEé^(†©|¤îÊÞóŸÎÜ 'EZ޲%Û¸Žþ¯Y›Ê¢2Oýš7[oVCKã´&Žù.Ü5ß$¢{1¢`Z“©úŸA Üò£¶IW¦))x)R´ŽÃøÀ£—Gç_ž º$DøFÇó®þGü KWáK[ù@è@b~ 7,<.Âá! àxRŘq À£Â¹²#{¡¥+—è /HÔ‘—½úkͦ:qbðV‰xa>´”3c\Rf{§H”n]WùõR޾ÌcÛ‚ØP.•‰ü‡„ä\Ë,·û¢×xS,â6ó¸ub¾MŽr¥0,6™Ý†ÓÌ#¨6U<{GÍ~ý"ö|=Ôm|u¤( óV¯è%¶›];°J’€€èÁÛzìîÀ£ xHíÎ\Ä¡'àù%HÂÀà@™ªAÌ€ÞsºŠs6Õö_{GAý3Él)«¢ÏëÀllÓF§ý>2±•Ë“µ-ÝA¤”?÷ ”8þW’ '‚®áLÀ6%ZšPûƉ€üãá•¢a %1¹@hD#ÄI^2ô -<¬”÷Rr'$Oc—™¼“/T8ÉàcƒW”µˆ”Ü”ˆÏuæt@ºÅQÇ \¥kœ9”Ø»ÙÏÖKÊÔ>réãò&?¢ ëv¿=C¯’Äuy/Í'9´}&ZžœÁ sIê.A6å,Ã@š^@à" x5ˆÊ迳ˆ¤Ñ…Ì ÄøHCZ$5€ÎIZIÕMäN`®e~®â–}Œv ü‹ªàG[Ón$Ù±¥¾……*LOÕ¬`Å<»+~e—º2êïåÚ>9å½'ÃâÔ>ËÄ~õl°}X (¼»$@K¶œÏ sgèw qÿR[ìDiíÝæãx€Žvÿ%BIËÒ·zæEÿΛFåÔCœÁ´õÜä dÆXuÐבÒ#Š,ž†'nŸOô“ö›ZÅé’eK›>pNšì7ÜæeAÀdOÝœ×ì9ØŒûœçÝLI;“•X×,QF „7À£9²š'É«ójª0opI7í%ýÕ! m ò•&ö ² »yŒÕ%Ëûå¶è¥ÓLöj舨ì$ÑèÚ´¬ÿ+¶0ã/2a LZÕY–¯ö÷Iìu¡õpà‹GÙ FHcF8=ôˆ(+¼KX‘§“º|<ù¨×Ô§*©6ñ˜[qÜí;¨dûÖ¬cGî½nÔ+k꾨„KMŒD˜ u[**+Òw©=ŒzzøR©jZQ(ƒ<[´›Ý˜¸w…bdP…8ý­Uo[EŒã Ìå´œ>= „šýøP`Þq¨¼l~iò<¹2¯/  ^ JÄ£ô5:Ð(Y҇餵!÷–kƒ‘Úa„&l«£UIüŒuéžÅT‚š b‡~O— ½Û}òyÆ\¢”Ït¯Èo´ô\ü€Ë)HökÑ_5¯Ì~ηÓs€âïmµæ½§“Â:4CÕ8^ð–/™rgËÉñÚ'»õ4 ãY¥‰:3Tp®{‡Ô¼Ä·½ÂûK/¥8$6¥¦mÈϪ·2Iþž’€€éÇèðu–'™¾žæ¡SƒÞA_ÌDt«ÔÜË!ÐØ_2v Ð[ðÎ'¬MVdòNŽ]6q óÞÂAïí˜yÀ‡P&AÅM½w3'Ð"팠ߤ›KøÁ× ÒÎëJDß²‹Ö™A#ð¨Ë`%¯`…„ÿÏöß (œViÖz+à}Tä!8Z7’Éói£Æ)¼§ö‹M+¿H@ø§ûƒèÕʺÛá{Ï+ýí’¸$­¶K1-1ƒ}½u 9«Už'œ@XôËÌ~…RVÖåË ÕZYÔ«9ÕŒéÔúÆ8¹­Ÿ#e‡Ú›¡ö°«›%,ˆ²Ç”DÐa£fJ²k$þçõc!Ó(Sóô®?e4hå} } •-l:yú´ ~šªë)Î;c>&j3F •(?͸À±·,D¦-âÛ—î*İ÷nH¢õC˜sHǨwÉdz;µd—ÅPPº+O©œ`&„‰·¶â;ï ;DÍE²¡GjÒ¿Ü!¬ýLhe”÷ÓV¬*|¶àçGÁñHv+ze%´ñòþÛñ?|Åõ¬ÁBÞ²<Ë+Ô— ¬ø£Önï[\%ô¨$_0Ô¸˜Ùjô^¬ÄŸYÎýîwyÖGn–hF4…ihC‰Nwƒkz<ÍÝhv'kbáXŸyM÷Å@`Aú¹{¬þÄK`F’_öA‡•æ2ÿغ«ÐË=À>—½ÇPo¢N-åî‡í€`§ï$úü7pš¶eÄçž&Ö[Œz%aôŽÁg V; ˜G¼ÕãYÓ¥i±pÿYý4ñs¦ªÌS"@Ë|r¸ydykÂ;Âèó‡üÇ8›î³Ž6»>Si€’óðöëGáþ Üa\‡¯3ðÍŽ­¨åÿ;sË1d4c‘»§DWCz^ ÁgXàÃìwnòAO§¶–qÊ]XGëæóŒÎ²ô(n&®á̬Ö÷™è×Iw}AoT¬^×åš+á` eÉÛïú’Í·ª”‚qÊqÇ&(÷ë@CX)pcxtApOF]Jõ‡ æ#Ž~ÐzS» yqàëÙÊS°ã©:ñíÜÒex†˜ˆ: ÙÀá=0ïs/‰ f"ÀÔŠ-ª:>²&E SôDìxH÷W+ÓE½´²Ø–lQ=™Ë”m5”¢¹ÓÙÈ’€€ÌGEäy¼Å€ý­üóÚ/­ºÐ~îË´"z6ŽÚâeokDR«‘ A77« ÜÝÝGCo)À@DÜW#Â=î%ÛÇ¿7~ÜÓgïæ ü=¬Ü”Å dûQ¿5óƒe—žj½ JjÀÉ‹±@‹o¸‹6ðØ!RKb9{¼–d(áºh$ÆDîGÛ«öë§\==ÐæóÙÖtZ«eü¹+GœæEÀ·ñiøþèÅ»:KÿqRçA¿o¢ iLÏÊP¸²Ù̧¸|¼BéYÚi÷‹ÆïJPù²PP冩SôÎÁÈ âÞ1q|šq6'Rlüåí¿AesoèmåL‡DÁSÉé9¬iMû´jz¾]Õ„oßodø­Ñs?,Òs²&üò{Ñ·d6:KFHæ:¼q€“–$k0EqÒ ÐÄ]hb`~ÁœláœrÇîLŠ^*€ñ-½*µfTsraY­**çÁc®u¤TúYft•zÍ̺påèÙuÂs¿«;Š™ˆðhÀc˜ýL»5°«Vu1<ºeΚ×}ˆ’ )¨ì̥ˡjܤYêT8=f”þÖa¥€Ò÷­3«D5@Ê™ÍÍ$M˜ÿHZÒßæ\ì mšJ®ÔWÚUH¾Ù°ÀÕ¨gQ–ZvßE÷T_òfî3P©í3ó›s¢Ï—‘yúª‡P‘Ö|lˆ 3hò¯ü¯ Ò¤¿)Ҿϴ·32û2·…›`~ëZƒ´¾ä Â<¯Ëj#VHCôæ-1_®‚º~j,UA˜ ÜCõ›Y)ØÀWn\¿rÀ†€HµŠW.Êô8¾F•]®ñÊ–cÛ(Ú¼£´hœå€XÝ9½›< L²Š€’Ç©’€€ÁÚ*âÇûì³1‚ÈÖçÂ,”âG܃ ž”\sÆ‘À-«£dËö O,!ItÖ‘ÓF ‡ëÓbÆ¿„¤tÆN £ d„Õ" €ÅWg.²¤ŽIÇk¯DâC™™r—q÷µ ™ç­‹ 9üXc+«¥Úšl”a×øˆ[°U«ÍŒ×fŸmý>gÖƒ· „Ðnå–ÇœMšºs#xh ¨7(p;7–8d,}õsñë‹£âUÉmGÓû¼ ¢ËÉ­1ã $Sù 's¿9+Ç ±bNq€Ðé#¡ÿ.å'λm¬WØOˆYZ©MÄ1‚e¶o8åíü…Ç¿Y×¶ßÖÄæ%Ç÷äê]‚P6Á4èÖ›žÿÑ­šÌðŽNùò³Ä]q±i~ß¹wUqPº’›Ø.»Tþ"ß‹¨Ù9)v98CJ9@Â/u¯´çý˜> nw½§›ÒHË´ ±l¿>‡Ëpkp?«B90ØYTÁöSçî%&—w¡*5¶ЈÃz »àŒlóèвkl‡³dä>¹™p%ûþè€ãøÂË Ñi€yR™£Á³IBºÿhžSÿôkhÇ'$]6xŸÁ#cÈ6ý áÆx,.Ù‰œHr'g®W%¨ìÿñܹÜ÷-¶ê¥¢kœgÏþ'^þi°Ýò*8»”(ûðº>k:éBP¯Wÿž“óÔ¹l§©ZþŠVº¶ÌݺàÖ²ZæÚ›tdXñx–yoó§\Ä&£v óyX \þцõgú‹ñœð!_šR\PKݘÈ4ˆ£Sl ת„=@üâ ýšÄ6÷Òe;D0(—5òP~xaþ«Ç5ÌíYkïÚ‘iÒ×P-4Ù;=y/E‡ažæ°¼ í7GýaïÔ_j®ý¹{ ¾ÀÒä~ïžÎ½†Dß1-x mxV)a²Xóíb[’ßW¡„7>LDå³®µ.Áxç»áø¡s–.ùE;™¢€ L¬ H_ö´@ÕKº‹áúÎ ¢[‚ç˜§ó ¬œeº®ïhl3Äc ᄈ …mH‡ËB˜È pˆ¾‘š©Å–Bñe’€…´wS.€Ðs’.й Ùh†j‹’mì.ôÛÒ öÈaFÃ!è(Û^r)“ÔžX.É”AwÅ`„›ãók0|‚ÚèzYÚk4oN’€€£Ë€2y\†"ˆÓz¥"}¯>ö³þÎMmsùŠí®•d& ¾¹cÌìÎ-΂ÄRߎ2oœ¶H± ŒPŽHëÛ1ê½(›Hb CÍÍîQNüËÊ{Z ZŸ`pS€éùãÂgøê(°8O¸á1|ˆ',E׉I ˆ¬¤”wø“ˆ‰ÝwK¬QÇÂ{+½|ˆd¬6g¼Ó‰ÎˆØUòû-!ò?Õ þ t|?iœ^3ÄV_ÑîȱŠ_xÐj8¹zÔ=gÍÎúÓk€h‹èZqfWÓôr)ûÎìµÞ‡XÔÄ\ëÏ%ÿì‰'‡2¹þŽáÏ<ÝŒÅìÐõ †Þ,‘ñOK¯|¶©S´qÙ K$¬jè?àÙõ諵ð:ÿÐ@ÓCF»/6U{"1Ä;â1Cjíô?š—­qŸðµ8H{ƒ»ŠÇŸµB úõ"yUZŒ™ýKlÍ,YC¸¢­ù´.xbÚd‘cg5Íù*¼ùÅη_u9Ô‰@æ ×5m÷¨œ„ÙMT:hôm}ªØ®ÚºAä€*rXÎxš áÁ|7Q¿ŠT*4ø¿ò¡g¡ <* +l–hžÑÐá6Kýw[ßí}rþI õVoàñŠªQ«u—¾ÌZ>Þi~Jyv£E®µ}B–ŠSp{¡iåÙ\^ß¶Ç"ý JyÔÏ+]¢Ýî}ÊLöš`]ÜHj4@‹å:šqÇ8{)¡ó/xuÐŒ˜½•I&‰§ó›"ŽÝçÚM?ÕàëE$˜ÕüÌÿD€’¥Õ›í±gÇ…¿@𗃽ð ÁI„B˜ÌªTÂb+ü­®X~1-Àéu½í'†î‡ZtñÉaIXHGçº'® ‹2ÿò×#qŒÓCð‡É+L«nîL§±fl¢ù”ã—ø ð±à»âÙš!HîRc7 Å©¬lóóJ±’Ÿ¿»ð}‘Ê®±þ'Ä âÞ bì@ï–È=iê¥b{Šfù8 ³>$k‰¤öß‘bθ1Ã]COƳõæ‘ÀÓ¹ø[¸ÆZyÄß]UKŸKP|¶A#rµÄQÞˆ© éçy/ñ·´¯>Ž Ôm-ؘ[~Ol=hž}ï´‡·’ÍÑã“Íogí´]‰Xb¹XëÖÈ„ »`…ÈÏÉsr 5‹(6Zò Cí?’€€˜»\Ûêfã*4§#øÂ9Ç`Ã&`•€î{ÁKí¿ 8>•«  ÀøÂ^DÓ[<ÏkñP“Òx$F‡ÖÖH7sçËî9U%Ù±Œw@„¶¿Ú@øThpƒÉ:Ìrð@+=x" ±Ë#dX‘ÏÜDaSø-.U˜²<Àט~y·p~ôØÙù?ÕñÏÉô­#…çÛŽx–B¶øÓ^ B? +Qî.â‰ÿˆòl&‡ð yM´nþ«M3þÜ÷(¤Å|ìÛ|aR+ËO«s]<îdü/ãç5uÕ•T¢Øæè™bÎÔŒ_Ö&CVôvKœ·¦éjFl`(U šˆßS{£bŸ,ŸÑSï“Aù Nrº¾¼éˆ¹Ô¨n þûšv‹O&ˆPJƒ­ñóØÒ!EÖ>¦‡Þˆí`û¤ãÞ‹4I%NÖboáU7¾9@L‚ŠY®'‰šB=ìü¿ð*ªÄ Ê,áë£ÀvTÜ—éA…-áÈdLÜbÓyÆ<Ÿ(í…ˆÒZ¶ØƒÉ4­T¥¾ñ öé§1òÜú¿[ðyÐA¹G'„\ÎÄ©Q¿M Ek­Àá|W»!.Iš›“99 nñÀ4@7òž³¬[Lò„ûmcµ7þUµÌÞSômÇ*^…«ýôØzÛ¢o¶´F™FÆÂ‡[[ ºšÁè[ £tæs§/ } Qžlì£fz¢b†˜…²@yËîêh >Iﲋ³èß²»}ͽº$½ßŸïÁ{Ò /u¯cqz¬&2­‰ýöÜ¢ÔìŽgQþ|æ/é9>‘e¼e½¹P –Rˆ=5Äm7B„ÿ ÍÇ=„n)zã(‰$­‰À¹å]°²¼{2¼qSÖ2Î-8B¾«Ù;@©lý€b¿»5»L»•W/´fåŠ]ãö—$ÞÔ&ýmƒ‘J9Ù3R¬P½ãÏZ4õ´~¦ƒS¾CÄtŠKAŒ¶C‡½bÀÄ%-DEvet©9;, µÉv7ý¤h%i²ûVn£Q#ˆ ·`Þš:»ïôÿÐ_ÒyaIùÎe…lܰ°QoAqë×-qgݳo¼dhós8»hÅÊÆ§žÂ6öï}·b†å”ÏU š½ˆ6ýÚ ZHuH634ÕâÆGî6åì%’€€Á|+srëå£.Úï  9µÃÀâMy´ó«z«È7†L²Ç;ǃa‰4ÛWÜØ/V„xŒ~*hññQ€l]J® Õ]Û‡åàsî¢UUµ8~ÉÀ›“”´KE¸kŽ‹†åNo•0ÕžHõhóÙ±Vå íFyAUæÄHgÉÕô“ù#`’zxS£(\÷ is½¢l-ö•¹òùTN¼ªùN~;h8Ì*«Ïá —ºÆ*TxO‹ö£D-óó}ÀsíÃH)€sŒ½2Lðýœ+W¤ Aðë$ûO¡Ù7¿íh}²mº„•çæöñ¯w÷uò ·›Jæä°Æ N>úÁ©Ì  ÀQIÄ FV S÷뎆Š]õFI¢—Û¾A‚öÖA¼ äò§LÕËö¤.\ÈÏ@þàõ+OùKGâ]oHr83P‚|bOˆ‹òØ>מ½Ûð)á/t`ÿ]Bä¿ÖÉÅèÎcý(é» >À.‘Æ=÷ê=ÚLÁJTð>ß§Ô6¥øYõáF^/ª‰~‚NŸ¾Å9³‚[j L´f®òÐŽ®ánðÎzï[Ôyöò‰pÔþ±\S|gbtI‡1Þ”–k™™4!ΊEt|è\H'ù›9ÙRkSã­÷§µ‚ª`‘C¤P·ã¾t u.Fa'¹rìk1gg¶ ÔcñÇq¢vhÚ·¢-\"€§¶TÐíës6n$ …ð^ ú³¨4êt ÑÒvt!_õn#¶dwO¡ÑôÇ"]ŸÌŽCÛ½{Yß ïuFmz@s†ùX\eáƒý¡ÔFÏìCÁt ͧ;™wÕZ ŠˆðªwÖ’kʼø¦ÐH‚Òu∠B«S HÁvÏòì( ÀÞ(|1  VŒô ¬ý±ªA“16Ü—°b÷|"´ñv†q¤Ö÷fKiƒá N&Ûó„NÖ2}è“Pò´âi6«Xë×)͉º«‰'•ü²Ç¬VhŠœ^…:ž~Âï‘„T|§œVy†,‘ N½Î|’€€´VÓÁx[B@ ÷¸u«e¸;nbzì%ð<\ô£$#žN_qy”$[m]§[’uЇ,2Wðy¤í‰š9çÓO^÷š3]£lK»KP?mZ£j°¯>ßÉø o1\>.x9K\„O)~‡4Ä"ñA¬!Ž…fÏ…ìBªõoŒYñrQ…Yï¿_ÆŽ¨XÕ(l¡½jën?“ øòuœ–¾ƒ?Ÿ;&[{à0"sLáÅã>·¬ßeÐÌÃ:b*º‹Ök¨¨i ÎRp­ÇÂ:‰Ö<·[Íî¯Ü寖„ÈïsGMe§§xz·00¨NÂfX“ Á!wÁóÅæü• Á©£‚©Ôxw~´™Åt¢Fz_ù±=^Q ž<Œ¡CN^–D à>š•†Ë Û] u§w4[ñŽÛ=QjLÜö·C[6,l›-K wÜŠbÉÅvN1”ShéÏ‡ÒØKâqrÚãicN€"Sòƒ³ÜM\‡ WªÀ©’ü ‑¼4Qå´¼vOŒwñ,ö&¢‘lutº¥'~L“Ò%]Ím›JÛŠ§{À‹<ŽnBÍ÷Ëî–IÔ'$1"5ó®.f˜¶èø…Â?áˆÜ?-3CÛp ôòØcVü´æ dTý9àP>ìxH D/ò¼×ad”_v£@cËÔËW‹SßÒz0ÏLÞÈ¡¡'¿‘õ‹m””â$3ú"‡s¨2Ü)²%œ˜c9òû€JzKµ‰¡¸{²H0Œ—8AqèñÝ,Œ¨i?hPý:Ξó2×^üø[kwÚ€ d8_©ÍÏ#” 2æ‰NinÄ5ù¶ÍßxQ Ï‚G4;3R¾É62¦Ý‘#E!#„CU>ú'OrUç²:A&áõb´d´'oîª.¶#Jzqõ6Ë&Þv‘ð™UÉ™,>wŠŒFkMYPé;.ßòÆkšðXV¬ ÔR4ç&@{ÆíÃ=£™·ÿyaTeéñ•ê–8«ð¹7<Ú§rQ«ݱÛLx¡ä:Ï0½„¬Ìˆ>Né%à.†lóÚ†ž²‘S2ï½Â €?†‘zJá ½Ab¤Ù‘Sᛯ©#oã<¨ÀÈ}t¾â$Øò(Ûoc—’€€ ¯ÙIó¬–E¶‰U~jÆÏÉÊ0+„yQÀZ`í{:Îçs=ç9ßK6krj+£åÅ’vÖQFÜòµÛ©ÒúäW|¶‘XI*‘`ÏDÊt²¤æW‘ÁDfw\¡\ ~{ñîÖúŒ¡ é¤ïŠ*»!¬ÐHL6=M vžz ú»+@0÷Ž ÑßÙæ¬ÉH±ÍÈ€0Ìjüü¾’¨°H£à°s*Âm?Rs%Tè—U%ÁB’[^‘t9EVucX#sp]†î}ÇàÖ"e#ì}^‘0öÁ`oùŠZHïÝg‚¹Ôšÿôn¹Ù1;žb| èˆhk—HË\n½ÖmðÝE1Çæ"X Ž˜ÑAý™2(6@‹WµoZp°Áy™>®Hd eÙØppj»ƒ~Ù_.¶åi¾§ÎLzX,¨Cœ•€SþÄšþ: )ä8ý¥‡oñÑeþñÊïãN+]„êctBTÑø#¼Œ‰€1*½‘HZl÷qP9­ÊÙyÏǾ.©Çf?= f(,máŠVÑP?:h Xø6#)‘•ºø¤YO®}žÐÜß8ëµñú*ŠQ'ü?vk´ ¶RÓ YØu¾îÎoñÈ µ‚-×—˜bös*û9Sì‹qG@.O6i)([ “|^iå@¶éUáT’€€ÈYàS9b—âä¶¼^Q0TšýT›òIzqðÿŽ7ÐŽü“3¼°¶¹ÞrVšãœlÌùÚ.X—²î5ùž±?N‡|œ>5Ë«‰ƒ Ë\ H…SØŠX ã Ç•’šP¿%¾,…5e°ƒ[)ÔÕ®fÖÕfÿÃpúG/ZzÎ/Pwgݨ·¤ü]j"lŽÐyÜ‘'Í•â±ýÀ”#àÒ%™Ñüñ+×D ©1’…4ò¡3ã«ËÀ¹kM·ß¦Æ4[Lò½¤äÒ«X±Ù'»ÍˆÏwÌTp9 QÊ ¹X ï>]õ=Eǰ»p„ÅÀ:õ¦¸Ýiæóh6SA$v]¿±ÕŒË×ì,  „û]ááÁ’£¯ˆõóa„Z iøAyYÝžúHžN­ç…t²¥yu<^kC©¬Yb`Èêæs䢕eDë~„Ï´€•#°PV c‹Ý òz âK~(¶>6?ÜüÄæ». ãqXÙ¦; /âåÒ±J&—†òRR]F÷»ÑŒoEßb‘žyÚQS[5ÚcÆãVÊ1# ófEë.÷Ei:¤’øvžÛ• ?irR·º0ì×XsfŽ®‰ªÑÁmãË3‘|਒r|ÍA;uÃf„ë¸Hšûnš}ÄÝ%(–¡ìÈ1“1'޵ApØfD‰×›´€%H&vY8OgÏ¡Aór®Ñ Àq檄ݬËzì5ä¤X›š‡È­ìùL,™`“`#iÖ? ’Úä{²‰Q›0¯·KËÓqIéýxáÓõ>CÌ &_¯ÆÿÊ’v¯³ù†d›×ÞÀ¥¬Ô`Íáýâ€P·¢‘Ó‘‡8ò™>ÃZÎxQI¥uÁa¾f±ùNÖ<Oý!ò<»'O๳+Ñ,×YÀJ'uZJ.:_ò6Ñ ¦He|›Bߥ&çì%ÏǤŽÐ!³Yç:øË~r6úlŸC?4D†óÂL>ŽTÒzàvöB©§qÂc{¦3v†ÌLJÛžü¸.Š,BüŸþ´lt<ۆǿêëMRcDè» »þ÷‹ßW»ªû3{vé eg˜•–FMµd¬´²‡?ROËþ>³Y«~ž"*GМç{'ÒÐÁî65úK6×=ñ‚LA3Ý=%ŸÄLÉ(_¡ë?†ŒÒ‘\ù­ðV¡ŸÃ.p‡ô]Åñd¨Ù1ÅúJßå€éßYôdåïÊïkWÜ.ÿïm¶Òrt!‡Q1-áR"^wªõ@;è¿ÓRbN˜"PÕêËËÞg=+rÎÒ/sr‘"¯äÔLý¡b L>á€ëC§;íxÖ`6·zº+Ô>Z¿áRD¶yûâ2Ue/î µG€Tå‘m• ( U6­®l­ù‡ågY<±IËC4줞rEpr2:kßF0|b«&Kq 8…'ã¾íãRf¸­õŽ-A´ §–Ù´ âUSܸTH8_"€TËvP40õ÷´J$‚s6ë}…!ׇ×Oa«ãíÚÑ’€€ÌÎ#Žœ¤tÁ-þ 6×KJ*}íóRqyŒ*KÚ?|o<ó¿½±r/„äÂ1~ éH‘[míljâøÈ,Ý§ËÆKk…—Þ*lìPeV¼ƒN°ËøÙ¢V»í^¿€£!ÜÖG‘Ïu¥ç24„)–æ2FuVšêIB<®\+_ððY“V(@jKTK²û.€*êDmGÅh¡wðêÚ¥h¨|dTÊ{ Ñ# ¥‘ÝÒ¢EI; ° æÒÕë²÷Ë4lld°ó¥@Ÿ´sžÓpî][µ’¯]ât³ñHiã'ï(Ôù»«R@2n6V‰9PÃÌ»Û"UDy$r"È2úê=Ê6ãsÚõÑÖ](÷ ·…¦æWç–ô\±74tèýŠÆ; –4 D«Ï*»ø2¸‡hvó#ºÌ¥ û9—¿˜‰¹ñ¬ÃôÉm×̽FqQ_áªic¿(V|½;OŽ…™ý„Ì3E**üµn‡E`n>{_EÌþSjZ4+|µî¨7w=DϧJ­±Z%l¹h‡.Öj.-_æGA‹ ÷¦a£b\D–žyC ¡ÏoÝþºq&° ¤ô'FŠp!Ó=\LT|'qþ™„·D¬†åÊñYÒúïKÆåýÄ;ÎÏA¥ë…°ÓFýgÉo:@žÜq÷|/|C7õ‹ò´cÓ¸\–{§A=v+È%T×L3®¨~þªâtˆ‰«FSéeDÿæµX.ƒV£eуlÁ¦‰­›®êàc ƒšÃâ:ž¬q׎#?­ŸîA’õÉœ¢5ƒpëpÝ&E–¦þši7Ë>Én~¦sJØ×4-öGä:1°ŒØ§)Ï󸃘Æ×ÌÓ×&ÚB÷:'M´ˆý&ŽCÌ~míF[eCéh„p%ì=hñi¯ $\G&³R¨Å3£çXqÂ/,鯭ÿù˜˜|]?Fk!‰)òV*ËåÏr"|õ¾’€€¦•z#ÉWÐ$m›m†¶Þ úY…(ˆD>íPÍ>FA? §øa6DÔ¨ûʾžÏ%-=f¡!ßhx­óU5~Ìú8‡,…IÍRzés4aÃTji1xóÃ+‰b­‰‹KL‰»º:.|–°ûE,m’a´|Ý Ð¶@¦2Pú‹÷<À–`3'û°Iiÿ„ã ÎÒÃøFªdíÂ…5.i·ãgÅF>|Ÿš9£¤-AIFK-Œn¾q)Ì8[ ˆyo¨BfP¼FbˆPµ„yrŽy¢lýR¢!´Ž"ã‚¶Få^=Ñ€Ò¾LÚ€¶·SÏ6¤ % ‡w«F3€Ù$Ò†¸ÄÇ—¾)æ¨|â^3‚êËO‹ì;­¸\EÚ:Ö%³w¡cì– ×­+ä;ŒbÈ2Hõ'ÍÌ·Ï­óîˆ/·ÜW‘PËæ.ø= ÞÇÊ;KÁ‹:©%æÇ^,‰œ›¡ãz¬B§]‹.×,ÀT]Xð–;·¼rÐùŸ*Ð_}r¬Uý ß³É:äu ²K?µ²çYý½¤ÞÜXì•çšÅsŒ“ظ-R¾ïág#ž>õî‹e*ГB§šÿâ?¯^0/ü«€j´ â)A(´–Y^á&þ¾½'t-x,RéÝÿhI&öE\àÿ7/ö/8#?ö9+Œó|òaÚê4vÓ’¥Ùt딄˜o]ÿ­”pd‘ftsyK–­&4ºŠD‡gòÍÕþoþê°5á·E-ø’üÿvÐ&§`I7Ë#ÝHA(f‚­™µhHMí,Ža  +æ\/ÁŽa¥Ëòúƒa}ïiAÎ/ÓAÌHä݃¯Ü ƒÂÍÎ¥›®âÁåLx¶•Ø ‚9'z vq»Èß%±–VÐCø‹´o“¡Ó¿1MÖ9Žw ®–o†Ë‡¬ö˜™’²ÍA2!É11‘HÆô²ë¶Î +ŠÂš-ô— ã¬ßÚfpî1“gÉäV1gN¯s•ºÀOmSo¦-ê$áÈù¹f­ÚTøÿ°0 bƧlKå7‰Õû¦²£Nå?•íW+û¶ÏHoÇ…ù].»5<Øe©×l‘×£›™²‡At·ºöð¬w¹ÍŠg|ÔÈì~ÊW~©kTäá³ë”!QV`Š“%{˜}G4Øý¹~Gÿ’€€Î{h!oäÅÇIØÿ§O,éÅBø@ölE–) %Û ˜SÚàÅž¤Ë1KDNÔ þg œ<±Œ¦•µÚ„Ë›"žØë2`MÏw2>F—@1HàÕ9p^Q—O4ðgI7—uÈ5¼£ôŸîéððˆ·ÑV}¦`K £ÝÑ/owmD Œ) +Ó®™ z+ß”QNޱƒ­6s-Ü•[5Œ*‘B Íʪ”&¯8ŸnúLÚë”Zi"7Yµ¢Ï!‚ýk#‰nn¾]lî1) âb`˜V¿»"álÛúÝ™_.« Wºõ37(Õ¢7<‹¦ ­PBl“&1þóu‹Tõxíp‡1/E§ŠQÕ43[®M™;ì-ÖgX ¯ƒA猷Þ°)1ÚM8 s|ò·ßXwu„àteñœåÂk£HDwâY–#BîÜôÄA†{e&{•[·ýéCrNZÉÚí?ã*k>­#gÆÐNß)§xAOÚ4ºöœÉ³W“Ýa°èBA£ªæžìÎ/Çû|µòË¡<üž²W“«¬˜6ë1Ý‘0P—¼þÖÂõ,bã´T¸°Âs±‚!‘‘ Rr× –êhZ %ÿ„êû\a"[o͇öZ¨SßVfZ­ù£+ ÅD¬á$ùÇØï^ˆY“L·íBGÍ­aø‹uå}ÿfú)Ë„V3ˆ1CB˜yRMGe»3:˜µþYäUtqã*Ólize@Î#lä€Àvü[¼Hà.ìèšùó–Ä$™Ð¢qq\þ£-Wp­#Ztb*ávé¤]ð>~Ûát”jÒBæ<ßBî("1ïä±D,±HÔFu¼‘!ÝT,©×v—æ:y! TW ‰ºù}ðIy‘é%Ë;æ+oú°m @ ,(Æ‚3AM{"êæ½#âQà¼YV–Ú«%¢ÃÑÓÍ]§;“! ë–h³¼·~¬1aøQÊL(-!KCýSòû½Ý,U;Xyš‡Uø•áüðN$…À»ƒÂóÔ¢­L\›…ç„æº~˜–Eä*3Ö²¹ÛUˆÑ¢q· XD´•¤ñ7F”‘†2.òcù°\ê%7m€[ö˜{D#$/Vo¡-ó¶·õ 5?ø_ñÅÂónßlE§¹ç“ª€÷¦þèˆ[¾-¸»&‚]’€€»o…‰¦@B'…hsî¢È\ºÇÊÎ”Êøþúw–ãÊÕçŒTxe&”b=Ø0£åS¬ê–›J&=“}æçú k+ÐA”Ï~Q‰{µ!ÕéŠÃ¹€ û«+ºø“ðÝà7cYcÓÛp(÷GK0Hy9 /å›hT~H¦ðFª“Ð…Tsʹ$Ê TðT3hžW cêÈ‚nNc²‹“S8kË-§hÂ`œ‹ˆÞ¹Ù;R}|xÖt83…T%|`Ñ©u ÜPCÀ_ã=+{»œ8‰hŸMÙh„vO€3¢X5hnÓI¸lßR—†Î!ä?0·?`Ѽ¦Gpålm÷ö£}#![)Áp%wñòüÜÝPò‡¬{}ØÇCýpžó=1¾Ô^#ì˜Í6šdÆÛ*Ëê÷ÂÐ)‹kD6Žª9çbñLÿrk½ÓC$?vë&­ºl‘kíô1Ÿâë­cJÑ¥õ:±(€XíY¬ÝŒLÀLä’7‹Ð<äF:(%±DnV ¥SÈ"ȇFs·¯Ó~ÑàçUJ Ú=Y‡ló½7q)ª£…á”yC>)N‡´˜øêõ+5ƒ²» S/y®óÉYLbÍ ‰cdñ+‚–M€nûÿ…YSûs¨¾àP£ÎŠ3–ŒËk“0$ *™i}ÙÿMÙä8Y2,—…ç:ih¶v•i{yrrÞy™-å’é í°×î`÷ô£z¡€<²¦A0/ëRmÍW _È«abú5#45Ç}Âlz"=éÏ÷KqÄn&t¤5µZ§yy¨J¢.U9Ë z·}¼~³ý’¤%×”„†8ñÅÑåQ54*¶… h›Ê —[ÝØêä=ÊLag†Œl8…#xæepÐþ¨‹®—Í雈 ¶è/ýLì½FÉ>«·‘opªö.Ÿ^tÏZáÔ‡´Î”µó³É%Ò|®Ò‚å3{¡» ÈO~È kªˆ¸ ÌvèžÐÀÕMžY§‚ÓÓé{ãÄXJa–Piœù'}g² ¹.@2ÖHÉkJê3FÄ’N@´ }l„V£Á88™9µ±¡žYј,‹oDèñë÷¼øgKº’gõUÌ4»íW §Vzˆš­ ØQöj¼Ó#nÉm¤ø…!„™#㥠7€îë’€€¸K¹ó‰xÞ»eP²Î.Ä‹y‚Q™ý†pöîâæÅ¿Rº÷1Àæ¶Íb=eˆJžˆòŸÏ;&¹þFtëBÉS…í/ÝÐñ¤zý¸¢GåÖ}Žã_­*öhÄë}€t­…ogº§iÛ͹ŽbaÎÒ÷¸aÝÖ™cIÑÅT´ÏÅÿ´B°% šQÎl–ŸM-ËźÜ_]\_hÂK!ŒSQ7’G¬Ð?Æ/?¦¬íÊe±ˆL%—†¡•W<÷е ÝGqP×K8PyƒÁ±óêáqò£Ûä°Ð¡k[-cKØÈEÕf¨ÁXõú‘ì].“!-aš7·'÷hPà§Î9pÝê¼? ‰.*›A$Õï™T)&­»ƒÅwÕ [«½r½»äÑÝtí÷³æ°IKaÚ©$õNÝrÞ1êXTK•Aš(:ÀÌ ×¡‚N`êklÒý·¯(«öuÚ¬ \Õ©¼•4ˆöYUÙ¨:2¦·º&ÈV]ß\³öÈÆh­9Xž>ƒíC)…¹R:âRÉš@ž¥zg P¸ùh êÜéƒlEMþ¢ÔÏ~9¹þºû”Aå/)®¢u.Žx*›åŒ£–?üõI2ã.K=.¦´ÿ!åJÚ fòNäçIx—v‘‰]€ír/¤í•}ÈhÆžø³‰׿ç~o|…y»Õæñö?¥#v¯„¤*•æóÍRQRœÀ¶m5øÆDV î¯|0òe<îáÍʰº°¯aQaôv_èQ>:δž °z'[é:8ž`üx.ü=÷*§ö2œÉtr~ X©b¶^W”lZoh,î­l¤ÇÍb¤žjÖêk¤Ñ,øÄÁ39ØËBVã *ì¿@…5×KgFY:žÐ³±"(}W=~*‘ÍÐ:H§8,ÕÓ"v­µƒ3³˜ô„ø5Èæ>y˜Ù”kí7O—‹à‰ìÛ tój å Mi¢_#×¢’z ÝÂÝ%Ûâ½  ýO—žWþØ?€“ñÖ•x?>hq¬G^ÜY¥ÞÏ’€€µ;Óuä~ü“W˜åQïÑ©äÀMówYâS§%ªð ÷¾ÊÆ×ö×&ƒã»b¬þË GGÄ mX˜×ŽprŽè¾§‚cUpÌä¶Ò% ©ÒSã¦L\³I"à ¯é]ôÇÁ"ËJgÉ6sÖe@qËȯ7Å믭Œ û6ÒZI*—a…ÜM£¦ÐzJáҲʣ“ˆ‚³úÊÌ[Pwèøï¸‚.8ûvï°]epþNMùùñ&æ%~[œvŒÜÅùÝûÓì3þ—(6®E¹žÔ‰üÖ ò¡n³|¢Ð4ôˆÔGé?ë2¡0áèÕy [‰üòP;G’—g¼0›ÊW_Ò™ŒbÁ> >.ñâæG×|’ÔGм‘¹1ëßšk¼øYÛ=ÃÄAKù¸S˜7÷uâ|c}™KNt ‹Æúó"*ÇÿÅZY-'{ÒŸŽ>á­;zLÇg¸(„2Ú2><­³ ã¾:#c#7àvç¼a½xÝ;ÉÉŸšô»G Ó:½O-wyi-éÄy8–x"ùo½É Ð¦jXd%ƒ—SnŸ‚Fh>¶,ŒiÛo~ HúqiíÏŸCAÛÐpÌ |ñãð“£Nÿ¾ÚÆujÛ°5O¡]Åd?+C£•8«ëÐAOº•úû&QZ¯”ìðñã½­üúߟ’€€ÐÑofÌÝ›Wœ[›?[®z rÄ@¿ŸÉ-q A{ï¬É;;üxDd:ÌqìgR’<Õ#˜Ö~ò˜öR¥qÈÂ%Éa§²ܵ}šºçÜ(Ó®—“kQä«¿.aÙˆ¶úÐ¥Bd.¨gN39_Cl\}ÿ } ÝÎ\UçOã °u’er0ìéç£Ü»îø.¹Ì‹×ëi}Ñmó=šã\C¡€’_ÜÓÿEàzñ—;6øuò×î&Hÿœ–hÃʹcû±ã`™„{'\®êúÝ-¢Ä5vJcá‰,ßÞgð†øjUn&]ÚÖÏþWˆ¸jXf‚MUSùckM£‰¬¾A3ã»m¢}q† Ð˼@ZVá8Ün¦n#«ÛI÷R4 &Æ×4AšPÓìOx ²“î’&Is\É õ|¸%:xBïvU|<-û4‘ZGån:Ûrê9´4ƒ‰Í#§s\C­bÊ$¦‚zú‘Õ…ðß}™är’Ûõ ×â |&Ž ìcØgÅ1ïm¶‰n¹Ç«%Ü=‹{=¹ôûøbÊ×ëþVóxð³rvbwëÇÏ?üøDc¬ï'”S¤éµ°éçÙôç_o|ˆ·ÀEß:{vQÌ2*]H˜A%ŒfÜ~`!é[ı¹ï ¾dg e·/„W+«í2áùÝ®¤ow8›ãƒ‰¸+#ÖR½X¹ê)ûì1”°"ƒ­Š™ÑàšGÎ:îzµ]Þt^¤àP~êÿ[¶èî!gíàoþµ4Ì2Ã6'¯­{>l`†î3Ö&Oü‹ÿ#©Š×˜W4•–'¨Ò£ƒ¸ë“`<¯£Xaêî)éðõô-Bàq?Fà&´Ì>$Û IYœOë ÁðJ´0¨Væil?ÊËJ2 ­ö¦¾’ ¸ôÍörš’FÐÜûÉCiˆL9¢P AŒÞ•cÿïT³Jû‹Þthp,“W+M=­¬I¬Vâ—ü2üÌÓLëRº´Á<­õzÌœ­¨6ûå êhùk®=uP=h#%OE)ôÀþx¡sxý+¾Ï7$½N³ y¦'H’€€Àÿ3ca‹€|¼Õê<}|F‡{ú*Í+ï=ÎÔÃ…rBVÕ5&<ê=“ý>ĉÿëñ\áÉ"&ðj»ÓßÑÚ=²ñã(' Jw£ÏÈÌ Ç&Æ8'°ØKEV¦:’Øs0…¬z‘9ˆ¾wúÖòÔþ ¶éÖÐUL ø{:»¬´×*g²'ŠÊÒ?Â> ÎÕ ƒJO;I¦uvøˆE‚ïc9ë Púžô3ò¹vw3ïnW§&,y´Wz‰p°ü«L8 ¡Ý°¸b†º^wqƒXI¿W0{ ®0¬rîvzã†hÙ‹°¡~öXºê¥ÐÙ¼¾È-Hpáë™(xŸ91—cfd¢epib~rŸÙ¸JÚåK%ò­ÀsñxÒŠ,VL;ÏÆ^`söí¼Mçý›ÇÓëØá!ããŒÖŽ—¥² Geº¸tíɽc, îq[¡’:­í –oµëÏÞM꫎싆¶«²®ËQp¹°ò9^0‘ct…ú!*²+JY¨}[ËzZQ·Þáj:˜Eqz išEkî‡Z):Ö¥/Eå-Pš#{ÞBEÞv7‰¦^ã;Ò¼¸¼‡§pê”oùÃï¯`Q•QÄ?ðsy˜¸KÞe±ûPAn Ïòoè²k}«©Œ0´Žè’Â.ÊYX•,F1óSØv!£ÒQÍm|§x¹¹äF~P=’×eUc[$FŠ,Á´¬¤]ò:P$8´RB´QáÍM )Ë%„2š"º4Þ¯£¨¤i!ƒýlh–q51¯ÄWà¹#q7N?ùì>b­àîå-#|"+©”\®»ýÔoè23š`ÆI·ÿ† ÌH5>‡’h-›'c,®Ïihwɼ4µ"úÜŠ’„Ã1ÆlPcmû>úÌRRèa†êí쪳TFœO^§Æ¤¿<íIŒ¤S"8_Ý·>ƒÑHŒMt 7ò»…М˛œ ³™E%ÓÁÈR3¢L#UÄßzh¯Å.>O¹«Ò:êže˜iyhˆÛ ä“\óÊù— Ïöû·Ê@Ú’$¶(²Í¦)ïÜêÓ°o€"[IîÍè·ö˜Tw;{1v-1Â%@Cò‹Ë´û¦Néb ¹bôÂþ™á5”=ƒ`F¤dgÚoAÜ_`ÔÊ…Îív&’€€¼½"‹áåja7õ•ÊE©.|‡²MÖ·ö'‘1ÎG\Öò/;Œ‡Uñ¨÷»|±Û¤Žyãª;ˆXžP¯£Øed‘æªÂ­Vª ó;JÜ5»¶WÄ&õ+)C3ò ¸OS‘Xÿåˆ`(ß'é±ß±Z:.ÈBnŽm8ðaÖ¼¼³Â\`6áÉA5XÕ)eÂà6œÚJPØ®|¶ŸçÍÊ¿D›ÿy±_@ØLG÷ Pµ„ÊF#¥Õ™x °JÍa¼™ÏW¨¦ç· 0ê­k›ˆE‰­ûÍQBÈ¡J¼Úoä±;E5WDìZ-­>¬0‡ y2Šéô”Bç:BGÐP¨zÕ2_©—!Í üe{8KPÙ¡ÝÙâÁð„‡Ìƒh PrÏŸ¬´ô¹¡ 8Òã6vzAúR uÕ›+ÌʳgwÎ_No×=Xè6~§š-zèpw¸€ÒqS#Òá8`‡ 2Pîu‡§¡WU£ ê¼ÌÏ®kÍ¥lF „&“ÀO –ª"vëe•Ñ“Cm'¢]N¯básAÈ"E§MÝ{½ù‘ÊÌĪÈf [E•dµöOx´Æfs:äNáÃ` \± Ú]ïÀv§a”!2ž–åÃM÷‹•N @kÃLŽYƒþY Q_T‡®q@ª.m^3®Šµ²0öÙSB©ú0þ$ãÂ@‡±XïS÷—6[¬Lôɯ¨¾…êêNnÃ0'Øk`8%¯·‚cSz‚NjÂx‘ëJ‚Á `s°>ÕÔÀýpô±FM^l¥QÞ›˜ ]o–ïó¸#Ïõ[á4C·¬¿…;RX»Ì¹—AÕãù^ç ²}t>ÄÔjÕ=«¶ãxúÐÑìl[õï%Ìy’€€ÍØ—$"¬ö~àé±sãyäžrùµ¬ ×±©¨XÝ^±  ØjƧI¨]}1¾¶ e¨DDbøJSnØæ3œð¹ž¯ZÌ!šQáσ!>”?²Ú;&ðrö4N<äŸ=757PoxP%úD3Âke‘'Mû'<ÉžŒ”¨$ùfâièàŒç/'`óŽò'Bw»Ü :.áö¼š§)¹l&mŠCÌèúGÿ ×ÛÖž¤­Svkm;´ñ¥±œc3Ó ©³õ ª‘ZZV¨ãmÄ‰Ê ï2*ˆŸÀßÇHM’è{Uú(û²Ü™œn?e8íé2%®%=J_œ£ŸM ¾éÑ•.‹ºûŠþÆy ÑÈ(Ý»?vl¶žVj/l^]ï›—8þ«vé¶ìAb£³.(]î[B?CË~öe¸ ¸F[ Á÷±Ø›%ÛCD Ÿa‘eÓVˆ”Ÿ‰é~?[Ýq@hÒ±¥ˆçš˜í*áuêŠyú'Û髱ÐÛWùaÔß>h_h}ǹ Ž´ÍálvtDú€ø·ÑóiìŸÐMlü‘œYì¡ ~Uä=ÒsY&!0&\ ø òçå&¤™|­n|T7EæÙGF¤!-ù+ß\Û‘…E¨ ¿Ôz‡Ù§é>ÐòeÏ;Œ‰»yø›J޼¥€—¸~1ñ–#pÝX¹àoxálSŠÒæq€hnü|’Ç÷DŒ1ôŠÿgEd„hìš­ ËP× šìÈzŒ‰¶c#útˆ¬ÈV>Ž!’ªyjë0wü8ŒØhIàJãa§ ñØÀßœo!¹üî¿Þ܈LUøΡ Ó2üZ©vаͮµ$i OÎë‡ þ¥Wšêy)3qížMਪT T‡:«YÕ Ñ­rÁ(õoʺ œë9DßÔìgAÅ@,ÌÖ—LCØnÎ-Ø¿´·é¼¾=‹Úè)i©H—I¿ëiÉ2ÞKé0ÞqeƒÒ‰*áJ.}­Å%%8Û•HKµuSÌeòÏŠ,Œ¦ÝÍÄH÷ð¿*‘±ô )rrøxp¶ß&ñ0™*H?¿ìZ³Ø-uÁ|úÈÙ¼Ütâ`Mº¦ yͲ œÈxÔR’&˜þ@ÊìàJuÈ/(ý!1>h‡ž¨s1.©(³óžöj»Á’€€Ë-Å‚FÛE´{‡ßœÃ~.Ò‚·«ÿ ~ˆNã äÏñ”ÇIÙÕð^üðpHÅhmù%ã9è>>ábÉ/3Ÿ3þ.²$j½äÒIw- B8…†¢¯¦1cÉpŠ<Ü(a‹¢Í‰Ã"Cz™‘0n: Â!ve®wlÊcÍ1p=ØÏ$. ¹VÄJãûd:š{$]ѧՋÛë‘*E¬~UzÚÛ“šÚìD/ùªöœRçÔ©]+º@u÷ 8Y´–T®[,µŠ³[ŠïXý‹êÙ]7éáùlÈ”Æe¾ðÔSJ 5ÌbÏ¥oTþ9{\‰ÜÎõf‰¾éòIfwl^v•»*ÇÇ® UÈÀëU–êuE»W櫮П°º<ö\„AvÒ4Æ`t#¼µØÙwÝÆ"zóœh“^¥Àøâ":‡8: R^û:ÞTÌ£2“Ö2+—©Ô”_ÏýêÑ®¶M8`ˆ9*)Õ–W}\Üúóc7ÌüþxöE HUwY¨­"z~J‡ï*§v4ÔÎWÎê‹ 5?ã"ñzv3j6o-\œ?o 3´E?Nîâßýç)­D¨Œßªv{rŒÖù” gœÚ9ÿ ×P14­‰{Ëk¹=5§`ùw?$± Ìj£gLY~Í@<¿ºkêbðâʼn2#ðRd'‰ÇòffÂ3R)âRx9Açÿ¿’€€Æzþš(/}dÔqí£ÓâpÑ©“±ÚQÍÇzEü{ë~m°2öþ;`¨Í¡2F\ý 9.aSçÓn°}ôµB>#n`‰ŒŒ‘B\ß&8—Ö7ÑL p4·ˆ!gJ¤í:ƒfq$|}ÞÏê>èÁÃÎ ^î~þ`H%àaƒ4 Ö&Í`-ý»[6¯Le½‰Ýr¼'šê Šjj'QEÚI2V8ZÂ^š°Wå”i®¡õ8L€º@Š(ýHM¾x8ú{ oþt‘Å^#y½ÆN•¶g[tÈBˆ¾t€@íÝö» Ú{õäÀ}‹í†u43?%ÍEùÐÈ¥€ô§Q6.®þÜÜ8½â681?v8¥¿ùTœ›nQkÝÅûi…ŽgÂd9>ÈÐÖç¥ü+Žä¤ö“ÍÊ÷’³.:qèžJ.Ü ´Ì1'Ž•¹#{ ôCî§g"Hšz—/Ø€2ûOY ÊN"Ø\«¬©y]üÒ®±‚¾Û)jp~‹B½NB M"g¬;î§ÝÞažÒÖÔ*wo$ÄQål){D•ËOmkØ ä’ÖÎ\?ò\]–¤“]Á‘Y¬*µžiÔXHµé ð·­.^a)Ö¿Ì6½=_”´‘uqèÁ‘ÊÐÅ È„ì /h4 ^ý숭êZ•ËüiÐDŒŠßߤ›-p,™½¶“]ÆÜЯ$ñÿxéû°3V­P¨ntx¡¦u 9gaê„ÿoµW¼Ó̽=®˜VhÄæÁŽâ’ñ:äu[—™8ä-|ç.Ö1AsL¬¶•´`›¸{Ò³%ZâÕ ~U =]sØÐ*-M‡‰÷¹š–9¬Å¼“»:9ÁèdáKb”7ý [Ûî!Y’qG®ÍâzQë"›*ñk,sîܤ¢º>æ>BŒ¼u›‰ÎÊ7ÆÂ‰ORDÐôª‹Ðƒ»CŽ)ϪbF]þDÂõEP 8þ·®]L·1"'ÑÖ}ê®0o~ý5¥©B°›oH˜Ö8*íÕ¤“¸Ä=bökõ+’ºöƒ½«ËB€c:׸xQ0Ej¢›¬Ù°1Wx •w–d¸¾?k£BRO¥0UîÙ#¹¸8üèÍ»ú¬Û‰š«ßËŸcßh×"íiµÁLß7Óæa+nŸ‘oÕ´?°¼÷2q”–´`p’€€Ìƒm¡N$nPöëð2H¾¥Vÿx*àTR¼šç×fBiaú–1þeV]Òp®ªº<õ›Éqžç¨¥X»¯ºˆW1Yó ŠÞ¤WÖ…*SíßaÇø‰Ò½ç¿ye DIWÜÑX3ùs2Ôêíäe¨Ova{u4srÆÜãx†ñqõʾ…¾–B!“ý[n.R÷õ.vŒ{a ºù‡gdúmS\$G…rN !“ƒü»;|¶Œº¿ü¿@ì»´ú=¯+[üË3Üy{ñ t9« 0”Ô#YO‡>û÷L/íÓö3Aռ㔇–Ÿsö/0æÄ ×”˜¢XXœô¢°©“ƒ„~[n¹šGö4š^mg#b5ê‹'î}ÁÕ²ÓÕ3¥iY=3›Er›ÝÇ¿Õxˆ¦ý·¦1õ¤õ1'pÏ4—Kiø«–Ã@Q|ݧ ÍWb›è Zn|«ӹ½i¬ø9Ùf’⨱VáÊó^®Õ—PòŒ>ÿ&¬¦þˆ°H ­rt ”õ¥|ô„ô"…ãäuo:´„> ±‘íß2—{Xo’¼† 4™…žq‹&ù`½·nNk‰ç¿n™¯ïŸËçTÓ˜ÒRs™…Hiñao"®ÄŠ%¨ÿxc%Í wOF×d÷kùëÁëùánײ,îx/âM«#Ïa¿žÀÏ;uàýkr$@ù—yjEµqª²Ïn&ðý'>¿Vš$‹5Síš‹)5y¤â¼Œá»Uq-ó VöÖÆ»^ò˜Ý‹Rã’×!8ÖsáÄm¸syãäîÎú|WÞø jédÔs À‚ý˜·^ôôåzh«ìÔö¡,q‰WaÆ~d{AÔàÙúù÷RÆ0ïs ™äî~8Þ¥/ä·ó7m‘ªä5t÷j6­VÅ»&N^U£-ἕˆËtÒg‘ZDç ¼‚=ÂN]å´ãxŠ£ Þ®²ƒdã e%·-Ù†Ã|tÆhɳ¥,7ìÄø#&Þ¨O^€‚&ë”.Í#$ Å@’ø2äfy»¯QüÕÛô÷â à»/þI‚#ÜÿÙâ+–ç¹{7@>‘_r›ÓàºLL†ŠG ¸5µópüUÜ5úûa6˜°º©Ï3Dð²áä.{&¤!üzù…ñc]÷Š)?>ï}–ësì!^*ÞKWÁpVIëyT˜Ii >/ŠÓ£æ¢ÁÆ8) ãýìzÑ¤Ž _䀸,¤•JªæbŒ nÜL E•6Öàpƒ4N|b’(h E]?¥vêWŽgñ¯²½Õš´L9—}ÐMo!äÖQ¦´ÎV÷Üq ’,Õ©‡ÊkêÄBc¼Î ªIzQ£·мÎ$ÏÁ­¿ˆFRM1u&Ì¥µ¨Ag5Væbx=øcCûÍÈëVç]÷DCWñ Ú°ââij™˜Éô(³¹p êÕïŠFËߨ*¾/m´f¸)Æâ”§ÇLDF0u{€Š³#‚/3B=ù>Y}fHÄ€TP®ì=½:œ‹îã#E‹Ûzê|l(WÌ_0¹—|ô§ÙѸÎ2“ƒáwA÷ÛCQçžXüU} ²=GÀʶÉ߿뺻fäc¼§PÞn›à-µ1 œ60Úp¶Lo*îÕ—»=mõr’€€ª­É`Üöâx¢&u”zHA_þ¸j3¯ÕèMyÜn>”9­Ø.»Œ“Nê¿ M .ÀyŽÆ–Û·FbLûb{3jë¢<ßí^Ÿ9õ@ôø[¶•ä´ŸQ<òÿïp'õ»EïfPÀõdln]œöµ‰roÙ©ÄFþþOÓÿšøÿ·<'(EÄ ž:×1ËNT·ta‚t5¶@Ó ŒVÛ²Ú%à”qHÖ(hõcTÎfazãÇ·¡òÆuæÿsCÐ…ée$È ÍR; ç‘|bÕØ˜3àBzäÐ áÅl ý“þMe…ðGã“ÉÈ͈k¡Z-¥£^£)¢;Éè2g.”ÿ‡©d„‚xÁ²EN=ª¨Eˆ¹¿Ýê°»«ýsd7äJÃ5o_­8ý(„N-Fv±‡ÜÎÒnd žÕc=û×á8!¿Ú¯¦"@ãOºžJµý{ PUñ‘[¬Kj¶–šåéDNÊ“¢ep&ëã,5L‘s°x qž£Fº—ºøAXDÙK³,½²îú¯éNßÜ+D%û(˜éüpY‰±ø5|Qy¥¨yš£å*·|éÏ.šEÈ.³±»!ú¯*ù¨`oçµñÿS’EðªÿËëaç¦óm̼>¡]7"óK4NdV•b‰>6HeÝUsZ$|¿ÒDZC0àô C~Èø €úª·;³òüe œ! øŠÈ Õ›¯ËYG1t€Ñ¯ÙY‚Ä$é?®§Ö']ŽºßëE=»yêr¶Èï\ˆÞ OýP»Ôdv«îå£püÑÆ›¦Ê}Sb+Dƒÿá£hέv7â³Åi/½CYÆr#Nßù„:S Í;âŠ\ûIdø…IOº‹ šèƘtî)ŠŽ´~—k›HÝ`Ðc é/ª÷>ÉÁëø­¶a~:"ˆúæ¥Í0å<')92Í;ðžì¾“¦rC'^ÃÍ¥\`àˆï‹çVÍ¡n¥ èÞÚrͳ‚kzG3>n`»à'æÂÖ³Èu0NA`¶7~DeŸÒ6½ÛePNˆª°³`;ù™FïÄñÍr²ý•^•\eþz‚­/öot„+vùŒ¹šÏêÒãlƘèw ŽàéN ±ð^-ȸmùíH6j¦ä«J°& ¬þgÜ=Þ`íCJtÛ’€€¥»ñÿ—áÿ$R?#PýŒ´$ L[¢ Â8 uBQœ„HQøææÿr³¬¸Dú„wîuã‹é4H±]ª/àŠ­w+=îßÇ ‡‚‰#l—.ÛjÌjíj¬Î\Þö–ã¯+ÉŸ_Ì“ †Øš­^.E±°ø¸Á‚öµ@ÓŸß‹ª»Ñ{ö°#¾sµLJŽî}5S/3TóÓX—ûÛ©­.fñ_œ\Fåò,Tº’ÆŸzIªÚH¢qrãÌ›³À¶§0<ÕHQö-^ þká^Ê_  qÚL'ã_n“mÕsŸ_fÖcÔrC$N²˜0‹ ÕRÊtŽÁ\ªQ‹Q–dIŒ¢sB Ú¥¬ˆù(©z™YÆRŸ•~)mY¬v#ð™tò0I³8"¨5j¤× Á%¿PL­^ ¢[3HÕœÛãØaø SÍ?øÛ“³jAµáJin¾R{9¿A,|G«HY0Ù‹éQy%«h`/#;ÅØÜ.þ)©A†eÏK'òú EÀP/-m;H³¶²½c |v¡QOytKííAèO¡þa><–’½ ”ÃÔê qãé÷\h‡ÓÂ#3úѾèÄ­TUYÅT¸ë `{š^ÍÙBìbÔ&ÖA‰™=•dSbw€.ËM `lïÍäˆ_x#†®.’e àÿ§ ZÆQ3ánûtpG;[rѵ­X‘ØÌ]ýJÌãå¯?d€¹Žµ›w8³ÕÞÞœ¡DóŠýjPæØh·æ_Ç#(æ,7 œšŸðZ4H_ š#öÓäoCA7:…ÍeSŒÄhô÷™q"ÉìÚŠ7Ë6N··-OG RBû5 u‚Kdžfª¨zµ™\ |\Pó]aO:[³c`ÿìØ88J;ÄÆf±û¡Ñ‰­èHÏûÅ7c{ª½8Aè…ß1xæ9›kЬUûÇYY]]°än§23Õ½Í|œ.—·0&ûñÚ’€€Æ¿ ™9îA~…%n™ªñuñènÉÎÞ»o$Ðy“rŸ“û…²š¥ À=_[4ÅÑF±\ƒn† sßã#ÝÅÙ,e_?m`òëkög$j•L啨w«š~‚ΰ´Jöô_Ì1žŒ"3 Uƒ‹VÌ’T²ØÊvªöw›Å`°7bËAâ^r˜ø)ábRfñ±å^ùá'ÏvN Ì¶«½©Gkð½œUnФö;V«Y/¡°5¬h!ì\ðÁC 9£D']nT»Ž$É"’~óUþ äk$‹ä'BÏ”¼H•×x¢L%žB¯íýãzÐ ) ¥éúÍ#õ^´2kbKñ<ò =‹ÿ •yG=g-§MC…¦ÑÀZ)•~KÆMKw¦1p5g¤SAT¬ÿo=_v¯3 v[åî'9œ›ñú[˜×,VåóoÏÅ"†è+‹Göv.IìaÊ2›îvx[dù‹z™„8_'0}•ÒÝXÓ kY­¿¡[cË¢½Õ™ «5`­# ¯W…´N¼êO„CÒk§lM‡ð·[ $=¯ z ̩ᵻ੧r}hÜoWz>Dš+·ÈØDÇLœ àÂtZ|J}×j Ëâõ8Q ¨ß=˜ÛÃT]ÖðMHmÍl¹9¿”¿÷ÑÞc¹;Åä{uEtÄ= Þ/“wñÔpÝ0ç!?ïÎf3ÀËFtø DˆVÞòÈÜh» —Lü·ÊÂäý‘º”(¶ ¸•~le\±¡FõÍØž†êíhY‰ÕÓöø#¸h,Wøž×pÀ]O 6ÚÂo+_Y Ã5h ‡~Wðl#šçÞ¯ «ëö µ ³j`‘pÅ{d¿eqeiÎ4XmòSè»)µÐá¹²cïȦ¼x›ïTW“î,ÃïŽJ5N7B>ñü)ú¦Dª€d÷c1è‰Ë¡ƒE- ­?¶å xa£~eCnyÖ}Õ¤îÙý„Óùް‚ oŠÊdò:ù§’jkƒ¶0ýHŒìîôç½Aï Ë8LthôÚÀ´lnXa¢ößÐa`8KhÈrì9¬× –ißk° Æ ”Ë!S)´È=(ÍMskk–œ8ê \¦ˆ×AÊŽéÙœäNÌÿîsÚ]ÊÉÔv‹Næþpµ’€€ÄyTÙ@|ùéç錻b(õ÷Ž v½H™T­,ËL7)ìDSPõ“vƒy‹ƒÒLô®H6››¼ËK¼®bÏ|–½^,«Å’¸Fû[/»ó `œ€‰ªOßI=ãUVyd¥`s À8/$­_ÔIO’ËŸ+•••‚þýþî$W(I ¨cÒÊNf[ÿ¶HÍwܾýŽÆ&±8hé8>Z¥Èäm|P)ÈTŠ£4ßòÊú‘3‡éOã8ò²ÕÚëç™K2ÇtJ%8r'¥ c X±õäªw±nqÝH:øªs褈ÉóŸI<êzUY-=§Íäƒ{g=[ P’“÷ô)­sÜ!óÕÞÑÍ"ç?rêÇm·Ø,gx9¦BÙü¦u)5­un{ê¢ån¬>L_s¦ÏèøŽºæšY#Yrz!ÁïñŸÎ¸Ê%þ6XÅÞÍ2蹺Sá\¸¿gÞ¢É5Ä9ÖÝ‹V­l:Á!×Éýž°‰ÏY$­ Þɰ'¿ÕÚ±ô°wé“WReòƒö4óZ‰v²'çÐû»ák jÇQ=ïÿI³/£§á$frÓŽà·í†îª³Z@—iY ÒD%èƒ 6úËÁÅÞR=T¥yÞÿ–¸Ø\×/ ñ¹™yò\îÝúiæ%s8‹Þ§tØ\*¬ç4úà®OiòGJ1§·Ÿ½P2ú¬¾Ü ’€€Ÿ¦Éè?Ï/2BrôF‡9³Ý‹¤$È©èr³r}CÌÑ‹ÄN?ö¯âå°ÁD*èÅÇö7”‡ctÔº¬EUòk¾[ ‡™Ÿ¯Õ‹Ë÷÷@Љ…³„=ý¡}­xNtÞZ‡Ÿ¶ªâcèë¥ j»¤tú>ŒÙçW~ =suâ#i—eBç‡)©Ç!)›,õÈ“uÚr°j3‘~ê>;‘y3̹»Â ÿ$ ©/-è=kñ:>Ô öÍ•Ñ]rš:„Õv¹ó #®¹Þ§2z’e6ín586‰‚Æ{øÈÂü4Á3kÒ_%±7v´Ñí¤}°¡Ä 72Qtn"k{ÎíqØxPðø!k„U}EGÃTeû’Æ­!, ²Šƒ#§ç?Qþ „(h>Uîø_£4¡·p†ÈH9¶{8Þ\qã–ï²Þ],Hç—ÀÁ…ýP|[Aþ©9Öûþ\H çä-t(Š2ÇÌ> èbgæD­…)·…ë*«œüdò¶&b'Ñ ȉ¦ØÎ*w;lÎý+ýÄút8Œœn !6ˆs™ûAÕ¢xX]¼ªM.ü7M(F¿f$Ù¸= Ò‚J²bÕcà{Íj/ÝÜå¸iZ†8¦rs{ƒ¼2M¤sä[Ðü}>¥è‘+tÙ² ?°%óÑù©1õqѳڨŠ_K¥ï¦¬»‹¹/hçG™ž"Q\g?|TBVíw}9úckóf¾í¨ã\²ƒæ#w¨Œç8ÌÂc2 ~}°…ë¢ø2ú/r[”Éx™ÅUªf&Ìf3Âó¨ô/pëlæÒÿÍð*6= "óPÁÍÂ’b;?8¾\IÂæœcð•Æ„®F­ŸÙþ Ú…tÎCƒgóQf/üF„™SúniœŒÍÍïíF¢1—Æ2漤±ãf—¾A£]Ð>ô°¤ö›õåVõµHK½V {šXlêøZ 'øŒ,2þ>CúþÍž6¨¬.G–í™7åž%-3˜èoMUÈí¶ò0„±ƒ»ç¬=f˜8ÄSdËáŠc oÁ¥›Én3Ñj"÷Ä_çí9.0#sK&])‘Ug¼0#‹:^AÇß•åw·ç·‹΃ô´âtº™ÙBŒ‡CëqC1CG¾…‚{Ûõ±Ä4HÇ·8ôÖºtÁ0’€€²XZüS¼‹Ö¢¼L²š<Ü ÑŽÊF]{A]T±ú­qÞdÓ•íøû†Tt)#Ññ¾ìèo.ÊZö#Ž©wØÀþÛõþšOŽ}m±´—ºÕ§Ý‘?Þ­ÃÐÜB@U–ÒŒƒÛ1wÅ£‚[ƒÒ°v‰ô¦Ì–“¦º@éI»Òì?ÍØ-Sð‘ SÝ+‚úø·Ý©É9¤æzùP øß%b›ëÍ,Ä¢dv’TpÓ£óù3ŠH Ð †¯-êÈß¡ «ûÿHÙ@Ÿ¸œþ³URn ´õD–:¶í9}Ö4;+å-—<Šº‹5¾âAs)íÈú ܶ;nó˵nóI&ØU ?!8TiIEB°ºRtº|ØfM¤‡¶Ë@›ü°¹”C×võ?g6o„; ŨI¡ÓNÑ7—@¤d(͘¼b~ìãZIÔŠË ¦šT‹¸d­˜½ž4s^c;[hp–H–^¬išçƒ“fœç'ÒU ªÖ$Ý,—’LJolqÆ+­öÖ¬‚¥#n`µƒ|]< myðxÖAC”ßdËqeºËž%J´ÜÊ(gÓ+yÂÿs­Ý 7Н‚¬Ï$‰õ0Œ%bç]ON¦é· •Ã2vÚFºäû&Db[©dª‰$š*ãqá¦ø—Dø‘»s.ÕŸuL"¿Áçºc.nø"À…TÔH2<&xùJ¿ù„uÌ.Ï¥áªÙ0Ò;xÏÈSl"K´•Ȭ¿ëß"Ìw¼ôÑ͆Áó#GpŠU¤61¹Ç Ô”ñsXTe…Õá¢'÷£ËÏgo ‹Ã~¦`  ˜;ð¹ôÃüð\ ž©¶]K¥‘Ō󄴕á'_-5³A¡a\P‘Cå0¸´†O“}„rH£>½¤Ä>´Š4‰ÐŒæ«ø•T¦¡[Ýy†ŒeÀ=‡1EŒ` ¬5ˆkþlü<Ç+²¿Ì«ë÷ûGɉƒø¼² þð Êš¯×àpJM‹cµk‚¦mï%l³µñ|ä9ÉÍì-•Ç~—‹Ð^ÆŒø²‚„àüžúUS«ƒ3Öf1öÁqŸªŠòZCÖÀ’$|—µX$æ´M¹ 2JaEÚH‘Hv[AS­SųYS Ý 6å9ItÏš]h„Ÿl+óš–á¢ûøwþ‰¢÷r·ÔqÄHäÄ’€€Ú(d‡¢Z j]rh¾ŸŠg÷ù6J&8¬ÂÔ±ÐVuf»|á_l“!6dÅ›/õ1 í©ŸŠ†R-_÷=˜”’aXøt£d®Â}änò¶Gd+ÞH„ÜoˆN$Ü 0ÚD[©­UöM§òÐåÏw•tË…Y1Ÿx±%R¹fÖú¸ÂÓ`¦F-Ö²?e’;:ÀÁ±kN‘É„e~¤bjsDE¨€[(BÄG¢©6o@zç"ÿâµL3±ÃæË(~ŸÄÀ%ÏjǦ¾!>¬Óˆy;«Ú6æFÈD[åS²ª PX¨4Å>÷–þg‰T¦Ð=©˵HJ-ª›1L»¡×9¹²Tˤœ6-¤ýc`= ‘ÙØN¿$›ãWþø6çª#Ô„R¹ÖûwM0´l™°EŽÑù´í@G/²);F¸C#šÐؘcU ú“c§|æO抢ý7Š ^"×"ïI’O¬ó¨Ÿ—å%õÍå î}3úa€Î?ªNð`g¡4~¤»r·y1(Îd,w£"]s Xû0yòDEmø:ªª=“òüL`ÈØ[4+“¡HøS¶{Æ©/ß4(á¥åŠ"Í@¢áÔ¿>å¨S˜Ñ»©³k7ë—Ž­Jlô9!g1`éÀJöôí+ §É =@‘Ž>Þ$ƒªuÓð?¦àÏ s‡™a=Ý© Nö´ìc”þ[.µúTÕ©>$´ë~ ž’»FÉv)Î^d¿¨G”š<ج[ŠR8tT4ª)h>J; ¡¯N »—Z¾ÉRxL€àã17áND ÐUCiõ P{ˆA}dá¡‹Œiçøi×èu÷müb”¡0¿UJÇ+ã<åXªž§†c+Í’’å[Gðk¿`ÞÚäÉ/7ÌÏ]ô§^ˆoxU‘ÂØ:ûY6€¡“|´,ÛšÈpaNÚ÷Ì”ípB¬9ox!û<…Œ¦òÿjù]HÛîîsSMgkàÁh8Gîÿ}y}åW¥ÔMÓÌhzór…'RÖ8_íu]·N–YÉ(•ë/˜6æ›ç48·Ä!-ðZ9Í—¼ó>&GÒµéKZ-·ñCŒãCüîåïNJé‡Ê‡4|m¥Ü3£E5ªhλóWM;ßRµ%Žr;Hãš®} »µª¨ÐÙö†²Kyñp’€€Þë¤h=Å7¹r‡›|^ÿe÷»‰ùódµF¼Ì¶Üèk\™°¡†J£5Œ¦ç¹B“íÔh$òÄ*ú³Ét–R‰:nkC7h…91kjÈ÷„adZ@YN·“x³¿kR¤"J® ó±‹îßYxCà‰ ¼²•å”<#wV˜ˆÔDh‚3ïý©ÜºBq'û<÷Y! ½8²Øƒa ÜOn.x<1(ÎÒ&B­1Α—ƒK„obƒ›’…?±´Í’•bùÇh²uQ“^óv™—•ÎDü8™¿ÙYÑtf¾>ˆÝEz%ŸÓûHÏöNÊÚ|éÅ¢líB5ðÂÑtÅé‹—ÄýïIoßÇdñkÈÎp¬Qà*lmÀ^òáUƒ6 ÃN•üã6j;¶Ž(\ÎøÃvÁ­+!_ŠÑŒ6ÀÚÔw1¸ìp™ÀZŒõË@«{>[¿}Ñp‡dãƒ\­ya²ðÛÁ{×zQPKøÈçÔߊÛ(›e® »»@hë¡ ¯¼´/ŸßF–%9†yøiõ— aK‡úu-:«¬Je±öI4b ú·eÂ̽XtfàÉÍå åÔä,²”f¯yÆœ^!'ÀQø,ýBýluâÌ€È@½“J×21éÿUµ¡˜Šž™XÖ%§Ó÷îMO ؤàÉë<õtH"pü.=iùӶ։⡠£ŒÒíw -HÈ=ÀÇ@…·h7|X#â*†!Ìß>°ë+h†- xIì;TVÈwê+‘+{üÖÁA[‹Áh®v4¤vOï³N¹´w·/?íÚ¦á0D'FœBÏÁĘü?U”ÈÁÈm«'‘¨’€€¿qã¯M©\œÆh6Á0`ÁQÓ€ kGÅrð)J5¶ Yhøv¬›ç¼È1êî`ú<¯AÝ  ‘HÀ3½ï…–8‡)’=WaÀ- þç9ÌZ¿Ú9têùP”¦úU^%ØOú˾®øøPÛ‡²D%¶ÉÈÅÕwRÌPÌ™|¡†ø;_$“¹ÇfkQc?o×9fD¢é3H¾Ïm¨¬êX%\Óözôst/%â žF:Ç)èúi¾Æl•<Ë8Œ¥…P1=ÿX|¦Ê¢Ýî*s •Ÿ*l"?y}PP¬—h2&Ràê: jÁ‘²–:g0¯‹õ|zÍÙm](±ÿ'¿rk¾î8wçSK ¶îYo)]âÐ… 3DsDÚ{‹hív1Ç&êLÁ{2°Ii‡z[õúØs'$G#xú¤A Š-ؤï|ÙgÜjYŒËo޹Ào±U'?4Ø7—+°¶8 Ä íþoG>ù»A Œ@·Ãä­G×FùT»k[ãÞ#†³ Føkk|E³|z?i󘦫ô1ÞΊñˆTa5jdVãŽH Ã>{¨¹k ›lVÌåGŽUÏlj”Í¡cá,˜÷L/`véüpU»€Vltèéû™X²ÎÅ[Ê\§*L_½ÕîŶâ:MdP_q¬iÈ­ƒEÕâ¬/†»I£\-¥â™+í¿# ˜¬ÁÐÌúê”n/QìnÒ õèÔI´íˆÔW‰v›Ì4~¤½åê–Ó Ëàæ8½€+è¯1´¼„''ê;>x¶[Ý2Ó²ð,àªXÆdzÀ!–Ò¬íÙô§nü„5±ŠÜýrb´fGµD#Ø6åûmªZ,‰©>tOÇ0`5ghÇ9Úé-+œŸ@Û–\ŒèÎ=>³Y"ß›“º³øF:Šç‚®Þ/Ø' Ó&”FžàêpR夙y,œ|ÏÛøHçê5š{f"‹hÞP$‘æ»ø6)¿_è1è& z¸auÕŸ8Ž1B\pSâH|HÅ€ÔÎf  ‡~“Yè`GÂ6I¾cm15Oá¸EÃÕ[5ÂPê&Ô…ëê…ãzÑ…þ‹É¤$¯ßÆÍ7;M35*þ‰£ ñCµ`C=0`Ÿ¤}3þCºûí ÕpJ=§çƒù"gƒñ(tXíå†1’€€µÓŒp¤p9«åÜJ’õÌ©rÖ4¹fîî%ÿFšÁ'í~™•òX².´ÛMU'dŒ,˜èï²éN÷R~JsÌ<Á A¼4¿ñm«øF-¿8Ïùb4e:ZU,{Tà?Ï ä%¡©p$„5AB™Á~Ø¢·ø¦Ki&š)¥’ä‡QŠ^õˆô =ëðv#«ÎÃ`ëÏ@íÍ“Jƒ³ãLSCV¥å#ËH6_d­@j¨ñ1r‘ 1ZQUr¦'ŒQ-ð†Ü Œ8×®+šnɨêÏ’6"o÷'R@Ç­ûQVÒEŸžÐsHj„ËäÊ€ŸÙéË Í#ˆb§è« Ùæ:´ÙrUq|pŸa”¤„ªð¿Ùޏônÿw~ç¬!C.aÚB)zp!ö7r˜Ag†G‚,Kb´¸a½}ʺªmFÜ9;.I]Pt^x£{ÿ‚Õ«N„Ï8°ºs”gžÐ™S¥)Ç;ßÔ\„/mW¢R]ï#9©a˜ñ½eˆ"¾Ñ½ZUÔjv2jf%°» ¤Áy&•ßÇ}›ŒõdÇÿ|¾.Â4¼‚™Ø¢¶ÏÕ¦EIh=ï߯¸›J¡à"‹ÃögJÉÿÖ dÆd ƒï±ç7<ìt#M¥—¼=^J{lòêð‡pû ËÙë×ÑÚÓ1¼ ¹8¯²Èr•n³Úž,@Œ oþ»˜G…³øÅ5ç@Eœ¿Bƶ’,. D>QÛ ;SªÄum_Õ=ðæk§S†°(u=^~zZ¿5V§úGBÀ…æ« i”Ñ$üUö‡Úh$úéòN,CétËÅm¦àVŸIÅ]ÛÛ¯­¶hBý?*(ŠÈÏ´]³1óNA¥±• L±×jÕ}ýè§_Œ¯ÓЉU:pc¢åÄ8Š(²')‰V–.?¬.`áÕNC` ûb0ç¾úŽÌÍDrà3®d×·åbîJÿÞøøxGT:côÆœkû͸%6ý”%/ûüs/eÆ2¢8Ü\¬-=X/ÝT*rB6¿¶Rü‹õ -")]°úZÞ ÆŸôÀ½è_˜!gåÕ”CãýÈ•M‘í±m·µ‰­ÞFÅœ];æ5ói]CNüŠßI´ñ?†Ï“òž·Rq0®ý±†L¨EÒ´ qËãÜÂ)zø;’€€Ê'µŽOzlt6j€ñî*¤}èì;õ€›'Á°1ý^8h×û'~!»züžÖŠÞú‰Õ Lx4bÙ¨-¢ß¾>ü¹Sˆn‡;°\UÐìÅ~”e, 6 ë›Ïj¢rÉóÍ$jÑ#üåÚ¤d©•”šô©u)jöy=dÒVMÄæ—Ì9ÑWv,æÓ_dhÇ·p'æþ<…RCQŒdç3‹ «†,5-áç­ÜZTµÍ,z¿’)Ô^gydþv/nàeÚ"N­ ã±æcŽJ&X³Ïm¨Ob£Ã…ÂXnàÍ_ŠÕÞøfší¡#[h—„"™NNeœŠÂÁ¬Œ[ d¯+›Œ0ØÝ\±éKô„r¢¯e6笠òí“DÉO¯@[Ø’ù„pÎB›"[óTð~þFE%`Eö#çæÊ¢1äìƒ[ú¢¼zÈÕ*ÿè#Ò/~‘p+%P}jK2Õéü•ŸÈÉ5=¯¢t`j_íŒÇò¢gÔÉè#ÅeÀ>3ê%l¯ T Òóíq—K; å^_@¯ ’I"ˆÙ0ˆ ëG} rû_;ÛÒàâ~<+]YÚ`)§ 2o8¹ bw 4(R-9ÈËÝÖ½F1 ðtþö½ì©V§”zÝÇŠù°äUA6ÍŽHP6 WìrrW •ÞCÕp¨·ß‚3™ÿ]…VY`eÔ±ÜaEgm–y¬@bÚmNÿ¡±—tiz»kÜpéT`°ÊLäÌÐ*pìú2ÿø ù#¥BXQs»“®>ïMnÑ}lPªå0Bi9\·&ç,ßö{ ùùûg>Ã7ð=Vh¶ã[K²‹¥Ü8*›`½‡r!Ì]K>¯ßíjÌ.V3IÞ}2§g¬e<!îîr8…˜ òØ"K”” @Q‡ >¼àà G3ñëtµÂÙC«®ï3°ÒÀFNª.E‰‰7ŸcÜ#nP5¼8½î||IþÛe‰î·î0AD&gò–î‚"£i¥•3Űçƒ9^m¢càá’€€àS×»m;M+ÝdCl‰_ú¿f=;ÃÞZ»ÁKúb­lfª¼0Ò,tø ý^*«æm ¬£.‡â!зÖó»kˆ½‹Kʤ±ÜËY[ 1¥(ùOüñ2¡†ÿÔ+/î§E‰G3¢š‚‚úŒ°¸gNzÌ|îWù¿oÞΞ”…©¡·LÙ/G|Î@HQ(#¸sôåÁÒ. §¨)~-± gŒ¬fQ ¢ÀGeÉõËîÁ}8ßèšÿMýi^=†o²è›9€'AºÎúÜRð‹8õåšÆD xÍ„Â5\T~ÏaÏk6Ëý¯êÈ߉|þÃO·^\"¼Tà£{UÝyà"÷Eq‘—ìèÖws^ oQ7qQ¡û¤½ópþnƒ$/|ðø+Ìß»wÖ¥“7’Úœr¶'B«i&M1µ tj™€p "¨Å\´/Å¥ðL›‘-/™7¯@—(+úÛ<öK6XàºPP\JÅ¡%fýñ(è¨QV®ùsÿp¿Þý½Ü±ïî5øì‰öTÞñÇå+* {$¸¹V*ö¥y.)´ P |`Óˆ5àÂØ©+¡ÝK%[]„…hDõo«íô³›OYÄðBµJHør±wÒgSñfØl?ØõÉ$nÇ`i)}v|QÞ¡t'Öû¸=#®¬X½¬èÿ¯Ô™øUá‰5×€;З4™Ðʱâ Íãò»hc¶¸myô¯»ç‰?ÝÔOÞ4ÞɨYßWÛºgh ÷D¯Ë`e-ŒÓ,èõ9<{§,€ô«&žÃàÒwŸNøÈ6\¤26`~›'ãØyþHκ¡ÖÐï]æß–ÉÆònäXŒVd’•”Éæü÷õÚ!ص í/䎯†u¥l·XnÃÒÇâþ\G›×+ž%ᨛ8¯‰^–ó»9áG>ýf¾~Õš¤@Ürы۱`ê³^1ì¿ÇO§®ù™ R†ÐMÄ‹;ïÛÚÐÁŠEõ`¦2\Ùðm ÇjXÿNe@¦Á{uf÷„¦u Œnr6¯I`ð|ÿÄ›3pZïXq]{?•|Nê@’GäóÛkÙÀ‚_ƒ#ýÀò@ד NT™U˜;­vR/ýÒthEÖ¿Èc¾ rsn|SÑÎö{Ç…+S€%¢+›SB„ÿhÓõ#Û@TMÕ×m¬X„X8)ÀþÆöå’€€¥ŒOŠªð˜™Ñ¬%í,<…R'±'Xê:ÙKh·êösSà:Õºô¥NqT¯Tûöjñ8Fk‹ò¼ÛŒÝ’m=àˆÉ\D¾Üc¸òƒñ‘¼Æ«[Õª‚Þö• ¥zÛØ/ÄÓô­Iv™o²[$ ×VÚFa#âú$aÓtoÖ… ^…ä7tÝÌXô·v·Ÿ°Tµô¹šô²nó§LÊâñÈÏNOLšnT:òŸ$) ´þh‚fv—Ò‹)¨‰ûÛB ÷ÿ| èóöä°^æÏPÐ#‰ÇÖ‹XÈ+Ô5M# ½|}xqrˆ"‚ÇÍ.,•UÁa^aüÔ`9ó•î}ÍÎú”ž³¢lDlYÚ¬C³¯Ä"CätÈ@t7¸sš•Yà}­Æ‰âFƲþŸ¹HƒIGÄ9„¾ >n!Øž®@€¦têŠï ýÅ#î;©% M„P¼æmPÞ£Þ|å—V&VãS=H‚Sì9ñI`4åÍJÄŒ›„Wù’»/KÌ n~›:¯ –Vö§¥õ- M N šN”z%×ùJ‡bºÜk'<'Ä(Ý€Øc)‰U — )D]ÖPZE2Lûp™Ò˜Ð Q_Á7p—𣡚ô:Æëû`ÙR9u:bŸçîXüb˜ó›>b œ¸Ç»÷¥©aÙÎZ ÇñI¿ÅùmÈ—H†ðžÝç’€€Ê@÷ ]ÏÑ/…‚ –ÂÈê^²KGõÄËëÏD…n2ó£¢oâŸàš"à˜U4Ä£Þd ?í©.ˆNFò$ˆûÚ¨»XCпq$ãý†/®Ã”f.¸ÌJÓ@е¼“ãgÉguIuÏâ !ªjóhÎG_¶¹h°ŸRŠÀÛ;,ÑÛ;îžåçGdÝœ/1A±õ±Ï0l׫¬ù4ÜÝ^·a§‹vCF|F-äS‘Ou€#ÑwêVfö–@€ü’{â~îÇ¿ðO%À¨oØ;òå’¥"•é¬Á9e=u¹Íú{pè®p÷W÷ßèâ{±.mäPNùŒLu2 á¥8©›ßâòâ{15’îû¦~­€^ú_òXìšcð•kBm ²DãYáxVÔòägî(cÄön³GD¿4åa%¯Ï¥ ÇKjm\^0ŒÜJ¶ïìÐ" ï……äV\ÀIN¦Š 'iƒ¡F1awÿî&O*Ù9±²rþ®!ðM[IQ3µl¯¶ð*¸:s{|Cª‚c³ø"4æ~ßaàIoBLjóö#P1©žj‚I]  k`'åGO"T;ÈŽf—RMB^ -½]*vÓE'R/RÁÔL Г(zÝŽ·à¹>áÚŽÉ¿/ú.Jà×J–‘´<ÝÔ©½|b‘æÍøpaý¡•¢O8ãºÃš E²1¶}’2u˜)™)\Xz–d’—ǧj²\1{ˆ‹°¶<¿+;ï®/þ^ðïj)bU=̰¤¢#|‹\Ì»¬eè½¹Ô°¤ Iâ<Õ¦õšÌ™—ô ºH`ÝpÎô¼ ¿Ú‘8V¤0ö¦Æ™íš9»Ì$Š^éÔ ¯‹Ñ·°ës‘ .‹Š6¸áÌ]MÎpY®Ä¤îÛlÑ}ð£xs;‡z­^{ýÀT®Qmdni bÂÂrêIW×›|/ÑÇy Å ™è…¥*L°8LæJíåÅq¿ÃªäLqmÒ±·\Q‡ ¹0Æ…?lœèR6È•ƒ!&‚•ßþ÷&‚]<ó:·lf 0uÆ50Mˆ¶2ÉÃÏN2 ÀgHÖn”Ç­½—»Pi<3Éab¼wLDõHn úÕ é—±µ"‡î7ŽôÉÞó,Td{V¶tS§šoQw|øb‘Üncª|á7ï L½¦­’€€ÉìšçWÙ^úfÚ6€ˆý·>|¸Kß5D°h[Ïòâd}YöLÇ@ ”^8Y‰c1¥Ê,ùQ­I ãé?òbtAô1€;Înƒp§Ù-{ü^°rçÞŸ¦3²‡Fþúß÷¢,$`ŠUGبο…¬–G3 ¿E´BÈÑÀå[idc;x«Fº®Q.Üðµ-og¨ÃÔfI’5¢‹Í±pÉcÂŒ• œnÞèûh{º†Kp¡üúB—ߨîß©*êîAB[dŸØ®ÿuN™Ð,$™u­z66pè¸ö§5{C*…G÷D·7ÎÚ hô$“J*Ë$;½”Npê¯Q+°r:N¡@W ™ò¯|;—#ÅGÜ\/`ž“V¨¤Ü¸šÚÆ-Ã镈­ON)†OQÍ80Gô|‚¦;Ôlwõ׉äBh“0·wUê)íÃ÷–~û> @ŽC-öh‰F¯Âl·‡ÐîÙÁãõPˆb;Í`߯ø -€UÿçüWuäÁ{þÚ]7Šøcl±ä@¾˜½[ŸóÅäÌëçc¯%üKÔßÊhz—‰¾EF퇿æ×jB@ˆçýdCn„ö§>ý‹ qLDó­PÿzéabÙ-ïÖA_3n9½auk-þKï~×µ´…¸í$YûfOuÉ…–Ô»GÇ (n'ëFþ³øí^¸‘ïë£=+ù¹¢(‘C!©ÐŸ iœíc]j&“ÿ’€€¼N®'–õø~{³†¯|’¤à¤I{ dʼ©Û˹G]¯u×Ç‘ ì0ò`'z×_ó1±£˜@êÉKNä6cÞÖgɲøŽt#×c)®®»á@Ïqý\B­çÚüÚ^2 7ªc¨½„yNŸÃ›UlD¡AߥtƒœgK™YEù«Á_“|ÒÌå7¥}¼PÑïÕy‰Kɧ'Õ5ò£ÈèdŸrKßÙ}šËçå´O5 Þsæ`í=ý[šB E 3 ¬™f‹5æÞZ|‘æÙ’cÕ;G_Õàà“‘}¿éne›€Ž?ËÖ²éqÍ4R­ü;ÈØí9a/¡€‚[ÝdS‰º¹æ7RËîð‰°þÕ€f×›Ú"—ÍwsmW÷žÞž¨Q³9ŽËVçW¿FüEU€2?. Tê~ÿ5r0©”>}„ËéÓü óÃ%¬f_ áŒÏ¢¸¶ J_=&m¨Ëä­ˆu Ø³ƒÓ¼÷Òxµ^Y|(EÒ7`ý²µ.É‘¹Å½Ëj¬ÐÊ  åØßœ‚à­¥(¢ÓÛz“ê䛟ÞÃK ˆ™Ã›j(ÒqU ¿[Wj=6ÍÁK$–Ý€5g£Ü×añ+gØmiÈKÔ¨cÛ2º8µ—{`äo©Ó¿CÀn!R^)\€ÛaÚ’Ö§–Õ’î·ÈÚq1êóüöé’ú,Ÿ‡1Õ‡DŽà¾G0”†´(Åæ.)ÔIÈrk¯Ôêá0]¨NHÊ`Ó¾E¡q ¥½´šÒ‰£„fr¿&À>.ÿØŠÜxå"4mŸ±¸e—Z¢ôÝe.´,Ó¥>9µ•%$i¾öZŸÄ`Ç'4½ÒÜFÓéÍ,ÿ¬0.%Ê®Ež³Ø¯mÖðÂ¥ÕU„ª-1×ðÇõݹ¡™Ýè–üVG7 +í`,@Fˆ¡ÃÙÝT ¹#4§3°²’ êœÐh^õå:l©†Ã€t¢}qUi(WâîvÜÆßœD'vñmÍìw+Û!8"êêÙÊÿÝ[ÄH¯5³™ÿåíù5[±©’bq÷Gug—×–{÷@”C²ºM1ev³ÑÒ*Àڙʼ ÇïÕçp€‘¶·Í"„F`Ýr•a{&ìBG¤’·Å…áû3¨ŨJY{ãë$ßÍÊ碗Š+6K¥+wDox)%NmêËØ4–·f‹J&mÍ1 ’€€È†Õ+ñ+p~p(¶½ì—¡¿$™A ¬¯µ¼å¤:cË®¶úÌêK0»¸ÖëRu¥mí ÃëÖØCo¦ÿ_u$Ô¦|(þ²ä´—`¾ŸIõ.v‚ÓÈo¡8DãS§ßÊ«¼FiV—ÚgKjšh–”H]Õ…0²þ!Jƒ]ßær_°ú£§éLÊc(ã–¡Œ¡ÊhÇP·½a'Ø,›rîô#!T!ÕzøæÜjã\ Þ(ëÙäbIþÚ>Þâ‹Â™+xE7| ÿÑ/¶U9»“Ó0{Cˆ‹ 䳄"R0·m×)Z’†g–³y¾¯&+Ï”ç¨ÀÒçÚå{$ö”kªþ,þâàè~‰SðŽ)èrÌõ¹Ķ‰l°áüÆwO—o«Ðê: aõd•º |™??Ü„" ïb6%/ÅÈ2Q[s\iQJ@KæÀlF´¸|þŒeÚ’ŸÏ-w>pMd2û°ö2ú¹Ý_‡MŸG@ÊÔuf¸8QÉ£cK°§ÁsòeÛƒÚ£FHRIß çœ÷GAþ–‹~O$úÒÑöA¼m(O_ŸW±¾ƒ‰‡9 é &®YJ¼üP7-^úÇÓ;º«æè˜TøK@Ra )þÒŸ§g®bƒvŒaóÎ ¼1ˆÜŒ< 1ÛÅíøû_î+"WxO4DÍm |­hÃà3›E¶¹È¥o¼nôqQ+Xæ^Å—¾÷ìxrèŠtmQ€àÔW1¨B&þjJ6‡«˜!È›?«Š™¬†A}>„P6xǬàÿ»ÌÉ7 NM\·JØ'§ÒŽšžº¸¾ôËzTnÂA3˜¼?x²ˆ¤;É>S%¦ü+T/[ H&-P êvlÐ!\OC1Üxjeëì`ÖZÂ2ט²–«<œ–MÂãÊé5Z=ÀlE×OôTZóysd­*v’×ÁYÚ´7ó‹“¢°¤~^MÉ<ÇèQ‰¯™ÏˆþÇí p—pºƒ8Xôéã´^ñGŸKÓX:«%Ây)ò[ ÃpMþ0÷œ'“„b”\¤ðu'ÝDƒQT¤¤š1¦ë„v766*ŠÔºãU·Á²Ú¹øþèFˆn1ƒ`" 즦î%œ¤ÌˆyÍ'¶H7 R›ôF|Ö ’€€Çf¯?}\lÓ›|°ŒÑªB§¥1ºïý2=©Î͹Û¿g@ˆµï,€W A9œD :ò˜‡F­¼=‹ÜÅ/¶Ý舖Uy;¡´xª-€ØÃË\B‹òcINý íœu¿’¨ÀÉ"Í“¸q<>€ïqI bÚ¼© I%Ì´èFT ¡B„wÄ#ãÈ¢¶×‹¢8/mÅú<ÊÄÓè5þQÙ /'å¿`š ,ð>+Ê k ØÁ^‚¿òå“M§r°Ü5§+cÕ¡³äœ [M ú©ÃŠ£í5+/0t’ï+ÅBŠ)Í=}eÊú\Á'3¨–\ޝ}©æqŠ2.–'~Þ£“LDªU@2£³ÇWÏpï¸ÏÞœ¿K¨çâNÑ%â¼ß?€¼hßËfhÚ #¾Ÿx/¡jÿ†31/® ·7×»‹Nƒ™bœ›8¿ÌœQZ Öà¸W^¬Claýcçklb7m)‹Qáu0X/ᯓ‘ÁÙ¹ œ#ó9dÓ"'iÚ¯œ³[ ÿÜÓiÌDnEç|.\'Ê.–é¨ÿ%d«—Á™}hE§Ì ·>‘­Z$blp´Ýpì?·ŽÚ·ñ58öÝÒ¹HZîUZsSè;ØÇvP]~ü†‰Å3¢:æ4O´U0³fKüÎ#¦Dâg@ç ×µƒ/5¯ªš9ƒ¥@÷‘âçÐÛÏ4ïv¢bªÈ‚|BñkÝ:q–=pDV2èû‘?§bÐ^Õ*‘ÈÙ!ùýÒ1‹˜-hµJp )>…Ì]Ûd¬-JXŒÇuR.KkÝ£á¨Ï9½·ºÇ~ƒ'GÄöÒÑܦl ]"&‚­ÜOQˆdÝ&J(䘓àøHpG0«‚Ç 0—Øx©ŒC*ßµX?Q vµAÚ¼U«¡ÐE‘oº^^¢8‹`*Ýà´C>Äý¿p$ê/:üB&äïêédFKÌ̶·'({²,]tºù£â½‚›N߀SÌâ߯ÜfDŠ[ ½B“øÕ=hgQé% Z¡7Õ¶Gà‹-@®ê°àÿ_ýÕ¯íUµ“Rn…ýÞN߈éhîC†§Çzô£ï” µÔy&2q –IXõëy`Pñ^ÓšÔçQ@HËX€9B⤊Áá ÐA|½2«+`c‰S •TÓø‰»YËú!LÖx)(¯TÔW&[´JU’€€êQ…iÕežÆoŒ#ÙŠ‡ZU6<3Ïj‰´‹¸‰OçÅèi¦z°‹yÒéùKEëàž¨˜«žé#WæbÔ×Ñ~y둼•q=›¿o~U÷èö@+}P„ë0;ýfm«ät†-ÅÛ;¿_üP쎜MY»e³»¯zÆJ‰Cä-òo‘'Œ2ý™µ?Øæ÷î$ ¤Œ;Ã}È¢bM}„DT×lDÍw©¢K¹˜#î=‘8EM€Ì,®W_<0D«¾½Ù]e‹Lv …RÊ÷ÂÇ®“5>¸¦Õ*H¥-Ø~$â,ß™<´ €^é'N¼³tly"“WÈœ2Ôjà@~·±üì<É4¦¨A‡¬Én±S ëÔ®¡¹âàKt{Ê)?"˜UÆ·ŽÄ$U2ˆ.7l€.¦Mš…µ¿?iÂ&-ÁƒÕ$,WcæñÒô§ÛÍPbŠ›ÿ/ø·#R kyÐâ'Åk_/qå+Œ­p,6õ3:uêýzëeHB4â›’¸à2]]”+ý¼/™*çáM.òMÜć°óc´„ð(ô¾BÛ¨ujZê¶ÇÚÐZýSù,ù%Š` J,è i~±¹Ú*8nþLW–ú¬û¯*6r¬ìBëwkâè5K2õ¨µt{Ôê’9ö¸z» «@Ý×[ÑŒïP9L ?O8¹´ Q`ò^}O/€I1%ðúIo¡ÈJSË^P¾b'¯‘CÉMª§D±ÿ‹OéUQB~5àñE¾?K¦ü\i<ð ²±Ý SÞòèµãD+‡}›Mv°‹‰¹‚ ~¯¡cÄÂC§€F'.ó! ø3ÂØÅfJt!9¨ü©Ëªá¯‡lôÿ­#*" $8ìnŒ|NU oÿɽQúEõù1°ìÆò燕f öÏ3eù!¸0æF}±‹E3š ·tÖâñ8­:æA‡Ù‹ý¢#ø÷—z NE~+¢L¿¾£âöåÞ’#‰×üA1Ìm?½*Êé”ÓW‘ÈO¿€À¡û]ŽðŒ…ß’t¡j‚3ÍÛÎJøë6F­7[Å·sNcVÎfðË•¾Æk?(òÚÊ+×ÞI-$EÊ%wÕÖÿqo A÷BJ‡©Påpj©¥mÆË{! Šå¹°0ä“Rcö\‡cÅ ;là7Œ­®@±3Ò/¥K¶âº¹¢%."¶e5Iœï *m@¬C€Vˆä†î‰ @_’˜Þë)`¤­úJÈ©Á­ÔØbw«2 Èä{g^F}™ËC¨Œ^µÓÂ’ÍÆù lp â{Ißñ·¯¯%ÉH÷ów¨Ë µáÇFàŠ’ƒÝ®Õ2DI‚}jÀõÈœözVÝê•oî:)½˜ÊÉY`ɨùIÅ=mäøæÇº¸I@èŽG0²(é™ Fž³ÖÒèÍFÅöÑý _Þµ fΓqG:%Üĸ`d·Ê1¯³ÿbHF:cK&×¢òË4~üÏ]5@›37‹€†9Q!ùÜÞºtõ[ÉŠéú‹ËžÅpY¼^BzÓÉÕ½aý'mÏvÈßL3cëAkïÄM°ñ˜™JÑ«XVâ(RNæh†^hÎåH/Ÿ`Jw‘nqºa¶Si1x[ëÖ¯‡â|åzk‹].i)¶PO|ò€6·€á¤$¯"zxœÜî~ŸmX1âPèTæSG½þ˜êeQå -ƇðUçË/¸:Óé´BV£ñ®QÇ4!ÂÛØ^•q"•Ì 7j]”Œ¢PQ†f÷’€€àì-xìAàX´ªúHœÌª ®¼ˆ±kVãOaÁŠ~|Þ ŽÕê£Ðþ‰R#rFi>Œ’‚ò“ïÜÆ—!ŒR³Ù÷òÉ*V¿â8Æu½ÒÅèweÛxÕ—BºÓxϤX›òªß‘Õ’S6ɘ_åG»>‘9q4uo–‚â“»vØ»¸q´"«rni¦9¹¹™çm/V ¤ ÍLe‹ë¤N –d•A³Úñí ç¼¦?û4:'lÅ ]Á˜îûÀ^S|ßQÕ×hThwkŽlŒÅíä6$>ºÑ†Ôgø—愉U9¸‚k{F£ßöú"’ÛIB-ç%äA™²gN”üèÝ»L¢XÉ߯t‹Öú“ýëÞ(ÞuÊâG£•‘pòüÌ»H×¹C¾xÆT8+Öeeø- m%þLkï¿®(›òÃR¥‰”}É+¡²c3¥¼mo~’ž'–…µ ¢¿;qKL¨R3#™ì>Q°g@:Šû¬çPuóæ¨å@NÖ"[X,nu*ðR‹«,8>Žú’ˆìéT<£–>‡æÃ<Œ,2õê Rä=!+£æ¢:¡®<Ì ƒûE Žc«XMœIö]êMx§Š çѨ¶<ÁŒW±)¯®û.C/å¤ý#»˜Žï_p ¦kAÿ…­T:¼Ú^æxñ{™ôž±kD;>‰ŒíŒˆL§`ƒ¶ J¡_oiýça¤óIÕó!?òæá¢î=ŒbWM8<»Ñ~ªpÒ“5¶Þ?€"í5W¼õu¢¸| bÞT‡Ïw¯~L„ÇÔeãÏ> ‰lYGøEô.Jé+¼‘›6„F¤€ïž÷Û|£¹Ãr/yê‰bà¡>zUtNU2¢ñ|ÊÞŠ€.ÏÔY|Ø`|®öÆJ3*â»_|XªIǶ薳 4# s¿­‚†°2€Ojº÷kÓ[z3k‰¿M×(¡c¬Ì©2íèÆ©¬Ø¸f»Â ‘Qߟ;“–Þ\ñ-_Ÿ ŠaM4Qq=ÔyßC0Þ>PÈËv„•x·¦k¤ØÅöx‘ð¨uTDh=VD…Êz±€æ£FšÜ€Ï¬Ù!)æ2)fS1>ÛÙ[µáDfÓÎD=ê­þù cr¥ü¢OžŒ¯> ½0çaȱÊ*.p!á}LZí’=Ì=¹¿L²OžÓȈ°{·Ð’€€Öém’LyYÆoÒ ½5zܵ5 =pGغês¾3'8À´}ã4ðçx=2'nx¢ îÝ‚?dS` D@’”Õ¬ÌæÎS“kX†‘ Ö“ô_‘f”¿å­¸÷/ÜeŠ0ÂÛëeN›ˆ¶¯[„*ãfï¢0Ür‰ìR ïó›¡DZcWäÓ¾xI,äí#TÕÊ«ÊGOÆ¥qüªµ#9SðhŒFmr ž,³†—ùô·f'§ŒBƒ*ÕEoñâGÑ•d»œR ƒ];»«V1ñV.3(S Ðh[–ȳcîÕÖ‰-q ­.aÔ@›qèÊð*Þé>\"à B8±ÄS;½ Õ Î=¡l“1ê´“1(Ù«k oHÝ5æ0h쨧¿ª>ŽðW3¹sM(M™-Õ§ù ëáJhÿ¼Ìµ‰Ø>É]éa“ *3 ˜šš²eû†;ê(×¹V¢¥Ãý2Gopj;LF°™Êpð‰Y¡×mŒP(¾îÂûRá·)¸9cèÿ¬š˜å¼ÜFäz;‰Þªµ7¶ÏÇ4‰Æ6AW˜ë,<~ èzv¢Z7‘|¥›4®ÒPzj-zB¿ à–Lášx`î„ÄØq{ò—×¼«/í„ýï.ðW)&wfÊì€Ï¡spaf¢c, :‹ –r“à©ü8²VŸ0Änä6÷„zV¤i2–‚¦v|¢us†Õï éj¿<ÌT5A߯Íe-s–ÚÜd"ˆoseOF÷ÁÏ´ÐZ]†É¦`nÇ=>Ÿõ¼'M©…O‘ä³õ¡\øµ9Ü©’a•-ÍW?4èŸÜvF0á{Iâ¯×Ú!Î墶˜î¾È&Ô—¹ÇllP+ÔÚ¬ '2)/P#%¹[”8à%a´ÝÆð”Ó1WôÆ’ÊÇè &†ª»FR­›TËÁ 4õ ˜¨WÀ}ì—§l7ãòâ`85fr3¬H;ú'”/ÚœÇæ¥#KaÒ³B7$Þ¥&./å¤~æg¦ˆ¶Ê£¾ØÙ× ;xCRá©Y³ FØWøÜ® £}›DÌÀ*Ì‘a÷)#ºéªÊ+Üù¯v›² /DSÎRÑ'Q•íâ d­;ÿÎW-¾ÈkKò‹£"&ç¨ÊO±êíPióôI§NFê„;ùÙܲ„¦„\ïr—D’€€·^û¤•fSb÷skØüK3çkXÖå@ç´qv xTÛÊô+»¸èóH§x]B¿©0 LóðOŸ?0OžÆ%¢o߀ÓpïÛ‘½y4=ìb±5ܪߊúšg³¼m—%ÍósÍk®æüÜ=¢+„(£oaA޹FŸrEÛ&dõ0K9˜ôò°²?ä­‚¤k ©›ßL¿ÙmÕôw•WžU–¸ÁâÂjé£ÔI€% \¨é3zzzAa?êEK¡©:œ¼Âx«¼þ4ØÜÂ[Å|-YVŒžZ厾ù&ˋȞ£N‰ ^g°tø<ÿ(PÌQ• Ò>øš>$Öñ…8(Ô,Ö¾‹k1ÿ©øsïG$zĹ¾!º8£úƒ>¿°µïH¿Àm༞>IN~Dë.ú+Òx ¹Ž¡UxO mN‰$cºù1±M¹÷#~Ìþ1öÔ-‘=™»Ï±½Õ=àԩň7G»¾ ›¯¤ã©·¤æÁd+ù¿ü$õhófj ‘/Ùí¶jPÖ§… \Ö3§Nž/= ö»³ç„2‹Óû±æ? ”€§A5ÙÞ„Ú‰R7jeÏ¿g$ wlQFü¼¡q,"mE>ZÏ-–+´²hB‰ ÓüºbAü³©ŸÎ\LjSåâmɯé˜1$1n¥ÖfB'Aœ2bÊ‹ÑÝæ|‚˜[Xú@yza ‡ Nz<΀C™]`HfKU›º…ëv»DLVKÄ¯ÛÆ:ç6šåª¸UÜ-ÚÈXóKPèäCÕ$@{“‚—i”;´k·!=ñ¹xüÖaßÃGõ’ÞvRÈõ“‚J ´Â‡Mº&âA½ )éàÒÅ9„@¤ì«)ŧÍwÚotâ¶à7ìÛóךé£&g†-ÞÏQQ3dNÓFÎýÕ¾ÆÊX¨Ûs@ø½2ûû>Ác•iÿÝ;Éo[óƒ ÿÈÇü$Ìë—•Þ2´´²œmYßÇÙÚ:‰Hí¾Fˆ æ&s7‰1îÈ) rË„Nø-În°³‘dŠ´0<¼bQ“¯à˜kÓ :ôòŒzñ)J÷þÒfÏêI–uŸd§ŽÉš ýïcU±e„æñWqEœ¥i*Äý¾I2Ÿ ç¡Tó?^ñã¤Ó{Ÿ‘o’€€›‘Œ{/ýCdÐ͈&çH×Û3”KOñ¾ˆ¸³vas.³ýµíÁÓ~s"—É’ôþØÉ‚—Ížù¢‘ýWªµPòÂ1Ÿ?˜Ã¶¤³®>^‡ýÒôÄ;4¨É¶®rçÞ6eè¬~˜É5*ý„/4: :/—–Ü3™6&ÂŒLÑ/»\e털„Y÷Qy[ŽÈK3Y·4[ ?2=ñh4•ÏîJï¢dBÐT™$cë(8S•Ëˆß ”ÙÁ$÷>óV_ï&üö‘ùr # h=%$§²"ûƒoóö9³9tm{2mmVð X¦¥Òø =¾Ðáò£ø7Û¹œÙÎtÀ8Þ+TDäAÂzNF–g‡Z½ø>h‘4›EÙ-¬šöwæ ÀR1â# *B¸Ì.øwÃ&Ž•a„ÃXÒ-k±»¯ÿ0&Ã`¼çÜÆ’€€¥í̾¿µÖQκõ¦XœÅÐõB®_},ȰW;sX=ÁÆâáŸ'ÅÒŠBEÒ5Öˆ/“›’¤9ßüŒþ1Šf-éÁ­ÆÓ'æVº;H–gº"p¸ —|al‘µ{¾f>Ÿy Š$¹¢Z÷Ÿƒƒ w ƒhŠ je(µÚä¬á9_N#zé³·ÏðÏwß§ÚÃfÈ@{qÝ›BH4sB9ò ÜÀÊŸs@#à’š¸— º±Fñ?.Â3ÿ•øÁ¹–m‡óú δI;s€{Ò"š¤“ÃÜ-~mi'¦Žúc¼#;˜•@HÌ­¼›»ô-”ÈÕƒÝk¥øÕ2®¼‹ñ¦#¢Ÿ˜}fíf¥íGªÍzgÓ¶\cWmñ"ìç”ý4}«d6=¾¢s1ã¢ó‡Ž˜qô‚EZ3‚a¦4•n©µÆ0Be¢…XYàzállØ›¦™÷Aù©Ò£›Õ¶ÛàXà›$è_¶¿U¼§qˆðGøÎƒšªÔkÎDùƒÃ4“-í’ûS÷-¶h¯ñç.i*ÕŸF~]† õ¾¶¤d¦¸e䢢¢¾m Qèv‚'r ­Z ¨Ü›[¥»÷*>[G 0}‡ä¶¡tE_qX#§=÷\ Å@”©%&œ Ùz˜XBh¼åjæß«¼d¨LÇó ̬Ç|ŒJ 8›.ÎÁ¸îÒ¤'Gq©×§n}ÜÁgËEÇ.v'ŽA?Í9ìï®@÷MG4/¨‡&!B¤ªË*+uÁý4˜~ùQve®’[¶©™¶‚ Û»ñŽL&¼ÙSj– §‹ò¬åæU~ïžÏwš6v|gÕÕÕªpdæE’€€ÉÃÔ²CYýãxUîáUfe‚6²,y?4ùVÃüÍøäÕxÚÔ±î‹]€ÑÄàM´L!´çADèHïÁêÒÏÝc¡1"¢§b&ù9º[v2Û×ÏP¬e­YͼQÌ¿¹€"…®KÀ»­ãù—«Xz»ÃñÆêýÓÂ\«*%Ës­\Ä%üQ7>Ûý‹Ý§ÀYjjJ¸¶L”ÄKË“Á[{úZºïÌ:þ½»JÜj9¸Au5ÎÆ¨ÛÌ}ß}²iÁ0ßžb¶ë ³·e0È$3V ßE&Ç0–ý©"a™C¼¾s(6üœÿ‚’ UâsRxÒ®VÒãQÏvMMÇ_Ó> KØR¾58… ùWHÛ›—ؓٺ¾Ú*¹‚Óèâ2à”§¹+ª3¨H D/Ø—*Te€º¨ƒ{gÓyz©—¡(—¥P ãžêêã<²²YÆBr“‚Ícm+Ÿð mXÐD¬M0¿%¹‘ %·vC­Ùïý:ð4*Œh ø`ÊˆŠ…sÉ×Wùu_ÌUÕÈ;Ý6cNÜ€´æèæõ+ó…{KÀå6Jwqˤǭï(²0`I78'† L]îP õæ‚^üFö ±w$Ž`!D—Ÿ¤¶ÄLÐmfb,=°mÁ0”«K-|:ÃØyPMßwp iôX\O^”ÎmÈŽÕœèž~mí°a Pñ–™¾ë.ÄÜœ‡ÏÐ[Q„1Y3ïÐêœA.‡Ÿ)²§krjê^KíOñÏ+`ýÙÙgh)”C¾OÊ]ñù=çŠßP­øÝh2O¬èÑ")ðù‹ƒÍ«ú†=) ºyÓ­.ÌoúËïšI'›ôq2IM)…æëP½™Õg| Jós†Œÿ¢³•©•9?AðPóµí4¦®ê\ù"̺iU·„"•Ë¿*ô†¨ÓÄœKÕຣ»ÜÕ›wE{kX]Df¢‚T¿Ëúb°ˆ„þ¤XZ·WÝÿã .£7¹™¡?u À\ cŸÿ[ö—wÊ|K½G@å×Ü£)àÇ"MRH-é&4en3oc'<Ö$ÌÐÒÖ¶ÕÈc%Î*VN?i·€ggØáœZN]Ø,ØÀJ”î?jo»b¢mŒ„vŠEåJõ1êÏy€“R‘¼}Sk¬V¬’€€¥Oè@ÃLbd®)€‘ꯂ ƒ­2©×#°Œ¿ïn½\§½ã†ºÐsßIŽn{üÝç)ª ;ä°•=Å×] ø“dåu8­Hþä݉a¬dÉ¿&ýÆ©òÔBüTq&×d ¤Ö(è‘Zƒ¹ é`v7ÅÍ«YHwM0ÿq½5å‡ÅY5šq²þôež°ãc1­güöKQjlJTŸDÿ)8‡|–›î3Fwæ_Ï[«ƒKDq?÷–ï}àº!cÔ –˜&KÄ<‡ ê§*A†ß=áÛ—ÅÚîQF´ ªÈŽƒ‹MÈøÐ£·GÙ‰û…G<Æ.᤹ª§mÁ¢|4¬Ì¾'¦ñw[.ƒï÷A[2«ø ûÔ¡Ù }-áæ%nSÝw©Í$’¸kVyÊ·ÖѰ@•3€:ËðØ2Fa„È-ÔÂW¿dþ% oQ¼ü¡l(Z$yMgb§®÷5ÒÓÝŽx,àz¾É&³ãרé¾xÈéçû[¥XDàxoR«£#ì#¹¬ô /´¶qÝ á¡GÝpwšO¤ÆEÇ•Ò_v],!Fô’g…@Û|-eçÌ©18:½:Åÿ^çur• ¸Œ{vŽñ«T}WaSÅÌÜBÿÍñJa䆶ؓ¨hâq™(Á4詃DzÍÓÂë4m‰=O¤äq>”HU…µûPê#ðáŽø Lj‰t C¤6µs  w{jÔnÎþAâïZNrŠ7}ÍA¼ pû£±š¦l=Þ”W›Ö®IxFöQ–T¶?”ù“_>˜Ê¤Y׆Êž¯‚[x¼‡°¹ÜFËÅâs4Æ ÂõÈ‚€ˆ'G´H·VïÒ2€.f (ˆN"N 9®ŽºJ}0U¸ñX·ŽÓP”ðw€Sû„+~Rè§LÀ”äwÅ7 Ùá ³ä¸t‚=UøxpƒgÊsHÒ p~>)½!V´-é¥Ömï ¢ qjݳÐÈf€(·J[Û^ŸÙ¦+ŒM…}ã„,–Ýû©…vÍE@¦ÅxULÜwÌï[U‡ÑÖ%#øoô9D5}+HþQ óñ´D1Û;!þQ¾ „@0CçN¥mO‚ÃH¯é<å#ÎUOj^úî•y“Ö¿À¤Ä4²ˆ)H^6¿$!Á9XBœDeYK¾ygá’€€³coB"ƒºv„l„ej^úëW” Æ_!Ýž]4úõÒ.Y1è„,ų­¨ñ¾Ãôœ| §Ûyä£ÑBLÏ]ÿ°Ò†Uw.õ̃ >»˜m@A”ò·‹ –ë–¸´LÄDiû†½"àj!–3ÕS2R_Ô:jªÊZæÈq÷Ûœ¼ÆíÿÛÿC‡£ñ}ÌŽ«zéW“(çÜ À ›eзQ`8þÀ¶ ôN<Ð !ÃõãË­^[º™$½/KrGçÿ…º¥È½.è7ßïuNž±ß‚Œâ¶eù ›tÞ(µ0,UƒÇ©‡ÎÀEw(±¸½Æì {4õàœè‚¼^ü3ú˜Âÿ”ßþª<§–wS¯û¾Â8-”åêö|æx1—¿ÎYk6õ¨Ì3~VÑ^ä!ý£[re‚fgyå|t„2´¡ý³ŒâA7 oÝÎþñÍ~;Úiå‘å@Ý •ì ‚N¬D0B¾™¢p“ï’BÓ%­ õRj„-pѳ8ElN<2D•rÏKšjÃ.Šr½ƒæd¯nÕ3TԎ׸ëxŠÕ ëOK¸ 7l?Ú=FõŽ›kÄõ’2È›iHË_íf¶·óÍk£&q2”]§Â0´±ªù¿{ï4q?Rt’[ ‚õo¢‹›èÚ•!Þm®7‚w”Ÿ÷,¢¬ì³&Sû¨ °ɶí.⩦éùq)½n£èkÐ3!Û™á)à/p¿ ë:\âéÀ)Õ†Úu ç¼\F\Tó©uK$½Í/£ØƒrJÙcuß)”¶`b:ÑvB"a¯¹L•š¬Æh‚yË»| ƶÖKÐPrµÎà3u¤´+a®û˜êË*ào|ñ6è—ø>.Þ„~ î^ ŽìF`)dHA'nTmpÊ´ØñÊoHúü5Õh«¥ö¦•L‘&Ì¥˜ -2^RÒ³ÆRø€“ÿN wÑvcé¶ÇÜÊš7'U:"ýU+ºIúéãS9oÀÙTý_;‹>ÚçŽ>Å7è2†-Õ W‡T<‡ p*c×vdCï‚©èMÿæ 7·CûQ4óœâþ• È–=0%œ}ɾ‹Õ·{y¢t´”Ï¡ä°é)³¥ÄŸ òŒÞÓÝ¿^™6äÏIWqÁ¸YVEôõŽø°d’€€Öë¤ü+žT„dž˜ }%S‘ &“f,š§·ët«º Pæ7ÿRaB¶tSb€pÞ§b=ÄçÉÅ:Î ßtV©7L~g%¦¬¶4 ¡rµE0ÍÊ݃ø/™zVú+}#…CxŒíÐÉó:Î=¡É™oú-7s ×UÍxÁ«@AëãiÊçë‡ÙJrªpß}ùÇìfÓ)ŠOA¯Lf:yíS¬Á—ð52)ÖŽ²pÞyÀ€ÜÄ-;ÂôB6¹àYʘ„—nX`—Û|¢Ý•0Ï_˜‚Φw€§&òpHIÇy`ÁóGôy¡`‰»º‡RÊ $5\’F'ï !Û;M+r1äòùoþßc¨li/óª'lÁ½êžŸsm\ªêª•ZVr«•…bnÍ=Wˆ) ½¸áI4Oå%Â]¯|]N9Y>ò"ÌBÖœ$Ù¢ðZªDÿvì„Cãƒ8aè3åPú˜Vw I}­9)V¶Bߌ£gÛv±VÇ>Û2¾Ž7ÄO7÷ZöV›;‚,’ÏIüaD#(‘tŽ«jaHr¼Ýbvi‘K¶Ø6¾GÅB‡S,¸˜Õë\8ûÜqTÀéDÎ?_dÜÄnkÇ pB(‘Ò䪊ɭ ý=C:Ò–ºñûÎ,Õ¬]9T øXžà©Ï0§q‹Ë@ûnñ)ö€ñç•û:‘×›ÎÏ­€Hªmn/ýL’V€@ú¸ùìöIþ÷ª_´f5 ¯…ÖÊðh±ª÷ ¦ê¦åN lRHØÑ°Óq‡AúAï·¾²Û|S— wy }úþUÝ»ëÎ%BhûLšûÅ~½ˆØ<•¨§‹cdi;¹_MÞ¶ä—Á]§À=÷h—ýsüĺ8/Ìå¼ÁB[.#tró¹ë<½mh Q!E/a{Û°ïo3È­^Ã;írPakmx„uW€x]•9o‚õÀþ¬ŒX"ÿ_ÏÛ(T^dçâ&°? =ræQ#<ƒYiÐuæ3håÏ\ÅT ÌyÇO ÛÑйáæpq`4­ÆÖ©6¶%õž÷~³MpÊ1 4ÒMbqÊÊ ‰Û¥âPËC³NW¦a)½\é™ê*,htg.Ø´…’€€¿X"â/Üê„Æ}Pé0ÞÍ¡¸Ö(#¸†ô ~ÐSþWn£î@iš©ÁiO½ïiˆÂ—~æÏ/kü¦§†EMŸi.Ú58›nbb#³Õò¬ºþ>èV'®œG ÞH·ŸþƒãgØ×åŠÕ@Õ5~ò¹8`Ã\ƒBÓõJI’ä2ás\rråÛÃ4[Øu€†ƒÃr(½²˜íØ#ÈÝÑD:ŽæÇ?Ù"U)¤¨àಙMú¦ š°Â6/鞃.‘ѹ¶ïT•Í:À‘UWX`%ÚN5gúÌqÉ w(EV<÷»Ñ/˜ºöèvm•—â+j=ûìûT $íˤ0;V‰qÓWÈÖ´ßÀÃÅÁûá@N…\Õÿ™$‡±fƒj¨ì{Uߨ—o ƒhê“í,¤1QŽ-ܦñj“.…}]x³UÆIÖÛ³3FN×÷3‚]d³ŸÏuMèÛÅïfÔíœ÷_Î#7ßÌOó›ü"ƒ~[‰¸[ðæ ±&/1–š“¢)0‹iåïWwÛ ̉¹ÝƒóÏéªòB7±mvN4è™`*.ÙŠžM!VbÌÚzáÖNïcòuÓJ¥:òzÈpG>âQÚYÀKg9šIÔ»mŒzÖï逞)tï¢âÜ—+©´¨þÑçüð¶Í‹´l½ÿ¸Ê}»lŸ¸+cî¤Nç!6EïÝLÓjO9!^Üö£#Å!Ãý; ÃŽþÆ®R‰—žfÿ)›Ä 0--4{N(Â7eAdÖfa³BãÍÔ5Í䌄»|cmÁÓL¢³Á|ÜH|ëÜH˜œsø ø”Ÿ¯Ó&?^qÖn´Ñpv5›K-pqÔð.™íƒl¡¥Ñ&ƒÃé{œ³»ÕÚd#1Wñ಴ù˜÷~Ð…˜ú‡ DÙ°„±R¼¯)öÙõÚR«cùÐÿS°ŒÒƒõ&Ó!b¥m·!ýëT8Y|mSª"öÇQÌQg…ýúÊp§Px.¸Ð¡ZKUÒ8žŸµVÆcZ†‘jÑM Ícd€˜ò Âbã‚Êõà¡Æ;ƒ>‚kõ§cô °Žàiªº2­g–…ª ×ôãê)~§o=cv8L–%ó h§»Âð`Í qÐ|lWà‰9~ÝDë†ÁT"öîÂSÝ~dl ¸ýq´å’€€¸o^{ùé˜ ™Yæ¬ÉslÁ’Oú<Øú…‰?u×( F¤XŒŠ_ëÄï(­WÞòÛY²ýX¡lrø[%•Rü$S{© kUàû3ç|¯VYÕ³DpñÓ¤ j¯Ápˈ–—”¹1™Ðø%z¡›Ê+XrM~´ñ)¶Nõ^ ¾ðõ³Ï^“nº±/sì>š›SàRp`tPãÂç  ÝiHª}òDw»yÒq­hS?8î“Ö¼ADäà÷Šûq0×1™5e^†E-ë€Â5ú^‘÷ ,àÉÉŽMÏ(§ê“ŸùM8ÜÀN,üU£*ëÌçå5 ¬VÐpã·8×C7ž†¡•÷Àç…2+£YTE…°ÚÕj¢ŠÒÔ/lw’MЖ ¸AØ&_Ÿ‹LˆUþÏJÞ¹'B¼‰fGHµÉÒ9ü—§m6û6Ž©D*‹"Ry»TQL µ¾ÇI:Õí/ðh7´ô¿_æ³ÂÀû%‹[×Úϯ:“^¦kRZÔ[êϼJ\µcuYFv‚¶$ìýÆ0eO 5ÀÜaú%¬MNua ©³ÝÒV#Ú•€@€(ÂTòénÆ—°L\.~º)|ù/;—ûdª¸ÐR±€®§ì KÖ·HI l`Ñ…ü#&L‰Ÿ>hûc£çÏ+”S^ïáà[Án¿qÜ„7ÜŸ¾e(|{48¾dbÄr…u Ìv(|kåéyœûé1ldÒN&Xžåàwf+uÄ|;5@ÔMrKƒŽ,‡2i{µL\–JÑ-­,ø÷¬–ÞÍK0íØH]+R£ãÀt ¡X–u‹Nj¨CT !ÃáŠÎ;½½9H#ÑÖ×㯗Üòý‰þ΋O¡ÚÈ•xÊz„9–e§!çhë‚Û¨ª.°ŸT¹÷VB7ëi³ê“Uxˆ…Zp÷ÄËÍØ…ùV$x[’r‡šÜøÓsÊ>Àák±ÌŒþ`âSU‚š,9›ÔUæ-_öC× '{wC5Ü6¼Ý²ÓµÛ²šñ¶@|®S[w¤³5fhO¥ ˆs1`ü8¨¤²Ä׋$”IÊýu§ukm8(qÇÊéÁ£Ó~$ö;[ËʶM©B~Î\AY4/´Ê>ŠBþ-¯mi¡Là!½Ì;…k#^s2¤tîÂÑ… ïš–€¸3’€€êŠÎõÒ ðcÎgƒŸ›Û¿y/XD±3[Ñ|)fÀñ-„®Å’áe&Vp›V»šy|ÅsH(%.kK¹Ž‰«Ñ·.Hlä\´Œ«[¥Š«ééà>äâ»EÉ€(¦ˆÇàé³#tî‘WÂ~)6­cÆŠ^ì^!F¼ MlÿØL‘ýHvù¸‘ù¶ˆ÷ò*mçëIHþaAAÞám)$×–¡«|iѽ sb[¥ç_ŒÏ”Pùœ¶ ’º6•½3²ØØÕ”VÄ,ÏÿlX0¸ _=Öß9(ÎȬ—?>V„ÀØ"øõ¢@&°®vá]YlÓAz‹Î» "Ô\3Ò¥®’»?žÓÔªÆn¡’K½ å·}t‹ÉýjÍ|àžã™µù_FpfFsœ+䕯µ>Úã,šþ˜uË-ñøi™Eµiã9t[ !és| Uõ‹(­ýz…¡ßßH—ö1x’ {€ËtÉû` ¹™¬ÆƒíøuxA·al}µ¿Yã§¶ºÆà£Ž•Š÷!q¢/‚&']WZbîfRq_þÎm±‰#9Ù˜„ôÙ!Ö žyñgN¾Ô?n¤Ö“a¤µ †ý(ã‘î­ÊR¹vQQ·ÆvI>ÝL êêOÈ>–ä’çkÀI§Ÿ÷‘¸µ|xá`Ž|±™BI÷³`W²’f|G5 1è*¤ôír /H¹mr3ØHG&³Z·4èÝY^#÷ÝïháÁž)¹oË:¿#m=¡dX õ±é­ãÄ5žÍ¯Ÿ¾BL:W•ËÂ[46žÜÚ"kŽW·¿Ž/ ß ®ã3©q'Olz Oy¢é%Óï-á¤uñÚļ3Xyg«—~¿ã¼P&Ñ®ˆVLH²­E̪såQ÷ÕHÕ‘]ÅT¹ ¿n†0¤èô‘¬SÍ&òP'ÑÉ UÌÜ'U€IApm&;o•>M]]¿Í!2”,Ï¥á†zq¶KÕCaZ™E ÷r+މoz /€olÜýuÞÅ’ÈNªzÿ^VO¼ÓtjeŽzÌ?ÅM±xf‡eõáƒa“ÄëBp¿¥5z:òË óœï³”u®ÂL£Ï¸¿ùpï$·j¬6.šö;Ùqr³v1ëòŒ lŒô„P§Óf·MÎÆÿz®‚U•Šçº®ô] "út’:†’€€¹{À'eÕ›ìÿœ«ÿmnP&xFì8¸¨‡õÅ&Ä¥¶=ú­Û·±}ˆD§æV QZBÆ"˧¤¦0÷W™îsŠ`ç¡û¶Î.¥q¤a® f*ì2sÜÖnæŒ.uÍ   ‘ƒ"å_¤ü…ªI)©qN8Ùœå]#ÅKXå†Î?pÿ¥4Œê¯S‹&ü}0z¤ÜoI‹æÉ9)Ô´­Ìò5Cß*ö‰næX"Ñ‘¹¦núB)HD£Šóc«×?²j˃[œ*¸j??ûôû®.p  }S)(NLdvf!Z˜ÏaüŽ&‰ ,¥y_Xº/+Bfû ˜8`1ÆBèóZuUý§&¬¡`ƒ¤)ö¡îíetz#»˜53öOÆ´AÂâÉI1ÁÛaëI"Š¥™’$tP†ô]T1‰IôB3~š)K‹‡’øÃóyh¸êr=œÃîgI›è÷S̽°®œ#åLýúéÎN NYh‚dÇÄ.M‡l–!ÎÍ”ˆ\¼<Ç wV8© ¬£ÂJÛ JIšñ±¯ÒŠÓ±`âü¬‚> ‘÷=/ÆÎŸo{qC¸>G¯JIuEFQ­ ÅCiˆ’A+Š…ÇââþÖÿ³äB3šÂ†èIú TØæRTi c*·ªf˜Ùl8Ó9L舶™Œw¡ðøÞ)•åÉpCñý"•š7¯ìíXºj¨š{„º…IþZ«ZÝ¢´šÙôW°û¹8 îäô«•q¼yµW’°’vÖ$–Oÿ!*O–m3Eºo¹eí®(ivßÀ8¿Æÿ‹{€ä‡œZ¾,;¸ìÞ°œß1]•+¦ÙmUÅ –ü¢aäh0º…‡àaÂ-çŒæÆˆ ~0N†?›~NîpñÇPWï`8F¿S]÷0gÿlOÙ¸¸Ú—½UÇ„>AqîHN¯4ßa ÖJ›ž÷Á‚„d í¼“WáyT~,îá$|q‡Î|k4uÜ×gâAë`ŒS9*á,Øü.# ÒZäZœÞY¡LæÇ…pB×L(ƒÍÙÅÐ]M1ðfG|gè­`Ÿ~÷7&¯+ž>ªD=”Ì›"8yúűašPfd—’ÏÕE lE_sn<ËM¾[%w©%W½Z¾·è³aÜ‘G”Šï à ïJŽô?·ÑþS H‹DUsn¢„àGEd…\Ò@`E »êÌNúqx/?ìdâJ-f~Ø4òåoÄL5áðOÃ!åFƒÛ»|M G ³¥§³èT c@n UTR€ŒIÞ?³4ÌmÌói´Ö ›n—?<.í¸– ”ÿSÌ™šÖBÈš÷ÕNÔ¹£Ør b«»dÕ9À«Iëé<(Jw„ÝHä<+îr…öZËï6s˜ÐÂEÖ@À7')W2½ÿ¯ü}•<ª@½_]•½H!Í(I½Ÿû'—°y“SÚúÎü´±D«¾»å47=4Þ„}”^Uð•AùU7&•Gòðü°:£Wq¿‚n£Ü|+®#«½dLN5;|øf{ôeG“!8–Ã$ÀíÓ+A‹š&1ð㬹sPÄ"¶ã„•#@­ÄxI âÀ3™5âpnI6+ï%£½Z$žd­µ]ÒF8Fq§W¯ëò;eÎܲ¬ºÐ£‘á1±¹K䊣Wª/r÷˜b»;;¬n4ªÉóùKÜ“ø¹© Aï)Â'¨›s+)îçø³ÝòOõ4#­f<’ÏaiaëÙ2‰  YO²Vq*ù²ßwúÐc\z¤ëˆöGwxìøþ¬ì$¬¡¬ÀÆ…"j•“C)äCö6©-e®˜f$Íir°‹˜[·•â$DÉĘ¥á“ß²ëñ&z¡L_’&%Wò „44U±:¥N¼(CÔs» ¿†· ‰  iÊ6=öréq Y%þÏ5Ü'¼ÌX·— ÛXOû}K=C‰2"ÅU;0dY‹×w(È6÷¸»`JY~§Ü–1•Ù¾Á¢ÁÒæÓ¨vx™n >k9XkhM¡3423·³ÞŽìLðl³díKC æÌ:îÑÀÄŠ©hgFi——r´¶mVÃþaÈ‹öàÁ…w¨7†²—·s"±Hìqjs»6¶0š.s˜#×3Ñ’·ÎÒ(aßÔË;D°óñ–™\ßž~Ï÷<>y¾žF½4ÌñýSc¸^hÅfyçÜÝ(x®ÿb‰·¶mâý7óD]Êeœ&ŽXvûE›ð¾Å†¥ßû𳋙#õ—¤LËJ{2[‹H²£ór2kÙ¦à˜tÉ_Yèé$äÉzeÖSŸ$Átz˜Ç,§±õˆ‚³ë”OE‹YU`ŽêâOŽìN€7OóõêŒz`­â—%+Âx%Y,±jÀÀ8jCà¡[ÉN$…“0¦?Ê:$ ì 4S<åÌïøñÊ[l/'!>ÖʲDQ6 £Ñ˜Ç'¦5ø_ùÌÊ=ÓIìdð(ÄGÕÒzfâÝ—PÑÂ}6žY$äù#Uh—<üK™,\ýäv¼˜3D˜ó›£Qü© ©&LÔnçšÕ¾ú Üû #’wqèhOÃò=$1à$U»áyÙ̽‰pgfUc™;ZÖ²îà”¦Ñ.^Y•*Ü +}c™ºI ˜ ƒ9)ùIxå(IÌ= Ú,ã¥V¼±´VaHGê—eñØ2²-U¨², cµ&`*à}‡x:JÇÚ-d ¿Žs`$ʈ$õ»AÊ»âz«;«¹œ”êJ“uŠ Ef.à»§˜ é¦CÌ'zýÕ÷Ü»Ã- mõc»ïžx«y)RÒ—¯dc5…ì¹»t|C0OEÇœYÝWí ¯p[FÈ0·GøiU–šxùзÏjr›¼Ñþ …lq½—ŒÁÃÏoŸPÓ=¸*üÄP-aSÌ4¤4 ÝÍÜ"“TãmÚ1ñ ONÜŠÆC‰//sÇÇøðÿ¿W2&Ì$ºj¶r%OP tv44:-¥g1âu6,Çq3#¹éj]„ã'¢GÞ!ë†Æê‚<JÄÿYî´ÈÕwÝÖ¿à×§«eô܇ÿËËyJqè3qšÓ‘Ïê#…θÕÖú+’€€¹˜ç(,iΓ3µ*­;¹ß´l¸5º'ö¼Ãº¬žÛ*·Ø^Y½jA²#ʼn¶Ósî!.M‹^UÙ„{¨€`"Ÿ³Lmgù[¨)zΟ=ô@?³ÒK- d·qv… É}å>“^¬ð޲92N²P]^Õ|¡Û½ö‘”R\+‹þܽ¨ïü?hÒ6‹À ó$‡vqêo®41Ì@2ô™hn²kÌvQÆþdÌÎõuú"n 45@´Gý5|¥C€GùÂû› ×(«x,’¯€i¹Ø…ÊŒ¶±ˈַx¹ …֯ݕœ½{[Vuѱ٣ݣ£VàÃR°d¶Ñhg"¿a/ú*ì%qQöT+ ”dë9Z>_yÏ]^>ÛçaÉ‹+ùøî}/rŸ]áWE‚ˆ†:餂lÅ<Å;»°žû&,—<åúú ï¡Ïµhð%[ ívjöº/ÇÞ„¼ñCŽôEê÷M¤Um0)¥á«ï3¾²ãI剋u8›}á¡Ñó=÷™ì¸q-V·¶ÝŸô $Ÿ$ê­9ó² $Fßc'üj– Pòºéc¬uÅõ™#ÝÁ‚~Ÿàˆ¸-¡8ÒQ027mÔÇÛm3hþûð¥Èâ!íNèˆ#(J÷ÅÃèhèÈÂS ÄÈ“}ÇÝ(…çÝSç<1Ú"ÝÃàw×VG¯ÿe{®Þ†$”Ö¹Þ_ š&¥&¶dŸ¥N¿««{t¹=!XÞCTËüÇk(±QZùISDÝ1w°}ú4‡Œ. ·1ùH¶ßù ú‡EÐé5åÙÕŽoõr€ùBìîàØê{å| c­À ÖÖ.h®¾¢Ç}!Z7ï™™ ÌÚZï"3b7{¡–û ËÚÓâ¼Üð›NÔ¡‰ò¨¹Xl{üf‹—ñ—à›š{ž±Î¼8˜M/7XsFš»wTÉÙ¬6_ ’.>´%Î6ºGA· «“ÙðTvcê?¡NÙæJÄ×'o÷ˆŒ.ðfae×ÜuìIL*­]"ÝèÁÒHâT¨‚úÔ¬Kü±6£˜5W‘Êz-3ÿ+1apß¡œö_§áQ‚*¿Çššb弯{:~g,®eÁ·.iz Å2™$¡È#l¼RKX C_;¿#íñ3 ,¹’€€«ÜB<%q|¾¦™RÔ:ÉÅ\Êõ`gpËIªÖ°¯yÚ_°r/Ìh)×ëz<ø·)Dùn#ý¦(Sp×)ÿéK:("«ŽÊŸ{þ•#J9E&CfðØ0ˆÊ­sKƒ=sè9`¨ÇOOjÏ‹’Lå×L8Þͧ¥tÒ•xŒÑ/ ‹2 H”âÛÕ‰µ¿þTur† `ÏF»#E[Tuæ‚æ€¾`{I”ºáÅ_Û7qOi£—àÒÇÓHYG(7àuĈƒÊ=T %™2éYž"¥Y/Ë<Ú­/ÆâÓxØã¥@•/ö{Q1‹‹«ºV¿z¼ŸÊð'+ÆÁ+·C>Ôâ¾ø(Mn o ŸCˆg#ì˜ÖŠåª"\H&ü6*æäŽ׃vïɽlJ^èKµg^4jKî­i/õÕ8,¢(‘í<õFrs—š|&놠ŠA|»XBRbMá/¸d;«L&úÊÚs«#Ú“žŠˆ½ÒŽ»äÓÿn³Y»žf/G告® ¾¬‚o÷†G›ÀÛfMõŸ¡â±}‡ë¥îÔÞ„â@ˆœ£C÷ã‹Z“ìÌ¢tk÷&«"C’醒m.§¥US§1šŒî€Wo ïXë.]’XB ùþFRëÈl?a&²Ü)€ tjÜ×Éb¯J§¡çûÖ›A)îÈT£A?]…1oKD¢IñìµR‘Çæ:Ãç ±/Ò¦ûá ?㎞þÝ÷s# ÷ß"AòiD¤ú=M t‹w w©p9ªÒtùy,äp‘ª8A‰Ý •FµÝÉk£ˆMdktÚ²"6µ•-?>¸,Ñ™t]QÚ{ÝXâxÓÇ?&ˆz-îØilX[÷(gIb{íÕ>9|qàB£kˆAîÙš_A0åP}ß« ñp¢àúÈyÑý{!æW{å °ÀëѧyÂÄ@398åjûjOX3”)@Ó)û4l\"‚/Ä÷E¤ÍÁÕ#_1Øò¥ß³&[ÿŸÓå’Ë*CLíƒ I•N$¥e´So’« /1’€€à=-ðöD–Pù\'Öpò<È]–wHç`xz’°ôü‹ zWWHÒ&×ûåée(òǭ5 ÇÅ/©åûu)¤ç`ˆËg!ÃrŠ¿?¼ü‚Íþˆ÷¶¯.uëó¯ W.“d¥S»eš¿3.¾ÜpÇNãÉìþ¼°ÞUT’$*<’j+[’ É’Š3ï”÷;Ö”ÞÓ Aôƒ9ÁiâM²ÒCÑ!ž%:(k»07F¥:àøÕb¨p=êî®Ûùßï ÐÈçŒ{]ۘô¡y¿gqØCÄ:ò@ÉÊ5=øY K0ž*ɺåô˜BI)¤f_kQ‰$³“îݵ]ÊÂ0HêCê‰ï9æ±IrŽ6 ŒdØ&õ¹-3äÜSŽñ‡7:áã@¹Úç÷;tÔ"b†wßkJp°F&–yèm5¤#Uû¶…ñc˜“\L<ʈ÷w{\&®“ÎFªñÁp"’ð@ŠÅQÚeWÆKUÿ»Œ‘:‘ÛħŠó•›_¼Ð·Ä‰µ˜ ü!ù/gÇK@†Þ{7ÊÇ)ð ‡H¯:G hÞû€‹G}cG¤Ë`õÔ¾ŒªëN§CÊ[‘.2Yî€Jôµ&uô²•¬ß±U«€ØBò»µ‹­YmìxþÚ+qQ±Î»;„-õXü%ÉŸåkkø@V3Ûÿ­¶·Wá3p&FkHíƒ=à) ïH÷E_?dœ^‹+xë™ôeþEŒÕ˜±?Ã$½ºCŸ¦ˆªy­ô7ì‰ (ºALÃìÜg˜Œ¹Òg–ü.é&} D5U.uHŒAr¨4Û÷9¬ê»°Œ~Òifü»û-¥­’z°Ñ˃ü½î¹l(-Š¿¢0æÄÌ<P¾2À$ý±u•­¼àÒIG’a ; Eš €€2W­U‡¨|ebŽ«aÖw)²2çè¬fœëé#ù༂!Îe&0QL¹¯‰]0@làhþhÁ[\âÍÞæÑjy7zs/¹r†(²“ ÄˆFáþFÜ+v&ÖÇœ¡»(»N.ò_Èwb§r2)¶ë, Ü|Çõß÷-µà9»ö)ÉT·{8±ÄüVÕ&ÿçJÄH%ù­M`ÆÔ6Eø@ƒSzE(ðz™”€ þà h®=LˆD˜[na’€€· s¾Ýï–=ÔúÁ­!"×pXBfìhEj‰*2 2nÓé7Eo¼À£™BeGÅ Öy89ëJ #óBÄz5$lûc¬€±ìk^È鼄.´÷_àÝù:}Ac«Þ¦c°ÿ5HÁ˜»Ïº!Ãíd•’ωëÛsXcñ¿7O¶²ã`$WÈ¥!êîémLU^„…›„£7É ¥/æmt„ì9ÈoˆPHÉ_+K¬£&NêºZŸ˜Hàé&¶ÞA#æ®×š@þAƒë‡ÞŽØ«R½Ü-¬>W!¼õ:!âÀÝä55NŠôÀ,žxô§DÅŒ,ªÒ/š;ŠÇܹ½$)…l©ª¡@çà·˜ •OÂiÓŠ!¡=s©ÁöI/*ÐkIºZÐ`“V=¼“R±Ökøøæ:?µý6âåý¯úgî^% }Ë?7b¼wÊ•c…|H=$4e5.Mõa6™’Î9kºSñ¥ª :j-Tl±g¨„$ú'ç¿æ×ÞJeÄé&þmçúº!P_Ffõ2«.Ü̉Cô9Íî ¾GŒP$¹$]µ}]ð5n9Æò🪥€ûk :7ÄýÒ^ 4=çI½b°ïSǾ}Û²E$°’€€ÈîpJðŸõÁ¸_‹šòmX8 ôz¾ZÁz’ù^v¬„âAs’3ÞDsfª+ 'S¶-´ nÈÖ Ì´ ;Ô‘3%®„"¼ÑEU'¶—¨î—åekße¡pV •ßÎeˆáÑéí=ÌñmMÆ3ظ&êHG“±"Nc¡§@ ‡r‡óÙ_£gJk1¨T©ËpÈA "”œ¥Væè»ÄV9ï]ã”é6£Y/äEdÌ*d8~¶Ñeü†–«dá¤éq꨽ÎJ,x©d3¨â—"qí+¡Òimõ¿C\s-—t›˜´2—ˆüg`0ÒZ/Ä„"ߘbà+¨JXçîÞ9'«àÖ¯@€VÙ Œ&Ç#¦¬ê(ÆYÍ+ÂO Ñ÷–Á}Ü$9#Íq'«1MJsQLj¶X×¾ ”KŒíHrIjN²ßì ºF„w-,¬ÄÝnèöùê c²Húƒ¼ÉéÑ=b¡…@äýäžL?Ž+dúºœ»Î±™w ô™©r&?ê‘0‡û3í¥Ÿ§±$èqâ¹µ9¿¢ß1'´QˆJÊ5ÜaüqPXbÐó­Ie¬¬çT¢rŠ6^ {ZQN£Ðþ({*Ìš(ü àð7©´¦$@¦¡ €Z¢ƒI⪋RùŠ9Ö@?á³”‡ÐáE¤«¨k'$Ë~⇸ÒVI½ãåò´ aYÀs¦¾œ‚[¶)©š­S“Mv~YU³Xk :¼½籨ýV â6ü¾ÂY¢£ìœŸæU@DL¡T…ܘò‡žF/µ´ù);6g<@uô36hXÊÁÈól~ÁÑüC€ØqŒCÿƒ(±ÜA>„ñÐ.,æ;ðƒ¸„ƈrþ†á3§äGD˜®öèð…„êR ‹Ö’€€œ!|x¢£6!_°Ë•…è0eu&VPõ,îS׊*ÔyTo®%¹½³äÍ.§Š8ìr*aª¯”LŒkYsPѯ³k<×e6û¼H§6Üuÿ2$Ù¨oá1;é~á7æ½>Vì•¿²´\”,+¿ãæ^aW·ÆÙ §ß+J’dÀ÷ÀHwÑ Ph˜ÍÆõ>Ýgê [(©/ZÜ¥ÉèSÒnlR)3“ËÏ-xâ‹ø‘âÅ7rÊÀ`ˆ‹ICîç{JXp½¯Ã èzŒË€ÝµGrLQÊg[1Â[Rä¿ë3çó…ŠOjžuPëÌçíœ}RÚ‘e' Ý:cÀ«á¦¹ S^ *{½}¿xûÓ°Úz2wFœ}ˆ¥uä9 V ˆ_Ió³Óu”ƒr.ŸƒÅ%¾ 2]7¶¯Ö5V”âÖ=]~lùùýWšGøxšcåZ¨ôžâµÎ´_Ì…,?h.,6 Ó£ f4dºâÆÍåÝ ÁËL8Ç™ XÈ/ûÛU¥Z Y?fv…†=ÕLS®|ÿëÈzF¸©X áõpü©Šd"Ø.|,Ђ—Õ‹sB¯‚Ж>pødq廿ºb%,¬æÒÄÿ}¼Ý¼Íâ¹?I0G—èJhœ¤¢>ûÐÔS64Qöõöá¨ï5` YûÉçVƒÌäœÄ q×ÉÄùå`9sÏè>J]ŽŸçÆÙëGÂõ;ŽÅ_m¶……Rê©ï$xÜïî—>¥àÔäyú/c dõ{YÅpüÜôÅm½,ü8e˲õGb2ä›3ËEkæ³vœ G£àãägYgá$|ëÊØsŒkÜ‘Ac!dÿ_s묓œó$âÆ41Ìà›ïoœg?&°ºw1‡”ôo£,–x˜"DîÚ¬'T$ ò’ÜÕ—,‘ó«ò*ÆÀo5Òëp÷þ|ÔˆìÉÔU1úÝw…~et+ó æÕ·§L M`vF"pO”EÔ°èÀd\¸Ä7/‰H ÌåPf7Zù zBð]aŸÁ ¶I÷ܰáJMiîÅó4¡Lì)œÆûie’ç³T:¼°ú‘–ÜbvekzDDn†ûÌœ‰Û<Ònù´Xסë¯ÚΰB}Œ\ha\Iof5‰úPzÍþqí[,»¨Ó7âÞ_oëÚ|´ès’€€¾ŽçhëÄ^d'8‚f–׸¦Þ¼ENÁx¤9HNY*£þwÄžJJúVbÏ)º”^³éË;ôäÞ^ ħ?¬‰g¡Æ_³Å¢a¿Å Ãßq£ÇÕoDVþ—sh£¸À†û/H☙DKåF ÅU¬ÐöàwŠNñ¾¥ó1×é×áÆ¡Á5fW[ÓLjïÍé]Æw´êðÛ—eÌ&]ËéÁ3¸;iå³¢*MÂ"ûæ×Ëáy \²3B9‡<½PDMÔÈ‹ž9q _Q—+†û”dS5~c1æ„õaR[žmKèZ%NW-'á>­è­e… YmêÅ L¦orÌò4) ãˆB­Y%˜úÑ$’±Ø›-+•wA«“®&/$ÑM÷a} ß0ôQ3W¯×Hãß›&R"X ™…0핦ܣïñ燤ãjõ1Š5 ÕFhîíkº‘Ý)ÌöŽ Mà¯dO£béžÙ0Œ¶Å-ýQ;”µ4„ôžn;å7œCÑêŒôßÑ~™CÝ,Yœï™å®«ù>˜†™íkÕïÐò_y·Úd‡`:ÞÓvì&¾%¨[ù¡Îýý¢Vî @§GQ×-ÅÈ'…A‘êÐÇGñã?“Q´L4¬‰z   ¾¬‘›HSVMAçP™BiÖˆ0Vʤú‘ó[ÖêÛcíBà1þ‰m9Tæd~uOäõ£¢º¦Ç[C"˜IÈ¢û¬€?/òˆ¥Wèì—ØïLJjÕ8¬MªåÑ12/¢j7 9Ò}9/ñŠÏég+{%2>ÛrHY|™Z[ôÄ TD®q®ÚÖjì(ís㑇œ“>SŠ/ÙÈf㦱’‚LÏü2Ù!Ɇêk'ZAÛo1þS 9SÏ^®Zka9ª·jÎè™em×Y?»3øåžwx>­¨¡y¯x§)ŸÖ¨÷|UÇòâܺÃKXÚ±µ¤áæ~(zçPnUˆõìoèŸHf Û7ߌX¾¦Ì*Í>Öè™p Ù­²ØíD®Ì,°æÜ¿®°lZ»jÒ¼jèCÖL8<ßýuøïy1þþõà,Rb^ÀZKUÄ/áÛâWoQPóÌ•¸ô¤H]JAÑE ½ÿãGp…šTm³Ý%§‘996}ž³ú45%l¬rõüÜ‘šÅ$€’€€Äœ;Ó3Õãš|iz¿iëãZ?8qx±z7¸°´†,Â>@}¡!ò[Ûb€Ç, гÒV»Öø©W†`ÛÞöÊ~–ÊÎx¹ˆg&òÇé+)[rî°i\›ù¦#Ôaœ"ŽPºM7œ…–°‹ínÞîRÀ`Ô^Ø^w#‹­¥á9 ee¤¬Á äÝXŸÉ³y@â['Ô3ät}Ëücµ¢©%/Hu“¸¼:’…“,efÍx 6ôFT=öŒü±ÿCK“ ¸‹>øM@{³UÖÚOJ‰­$÷- ÞD+ ¾l¯$V0±5;Kjô£ùok2¦J4ÂÌ3²Ïäaø<çþl¶è*éú)vFlÊF{÷c®Ò†¼¢6Ò o¶›þM¼KýKS\^÷ØÎñe`°ø‰šèï~n:™LPÿ ø)‹âqÄ:7’Jdv +°£$®­Ão™Ó¤j-.k˜¹Ý6ÄØÇ|¥ÙãZqQ™=S0J9º„†ÎÂQ GÒÒ±y}‰ 7çê¿D¸€QÀ2~]eïca.X4ˆ£ï^;Z8vÁƒ?¹hIÇ €8*Á>²íà’?†æC`ùH’€€šÛ"¾í UØÙØHóóp)¶ïÝdÎ^ã;ÅyhîSM¿äVß-6ÚÖ@—ò›]wºÉ—{tIQ¥w¡aFq2Œ…÷¥A®(7ÀÃÖږɳ=ܘ¹* …ê ¥ã ¨ÏaÒE»]w¼!éîuÍÅÓ£¬¶ïBô°·š! ƒDZj7¹z-Ž¿ý“-†kÁ ÄDƒ<˜ÜKñ!ž„÷59á¶”Ô vonÜá†!åG¢õz8¨Üή ]ÜÝæžŒ¥:+Ð3$~ýVM::ZŒŽVYI[¢úkÁNíÅÚÂÍm ÷}b„ie£WÙE»»½%5#5Å:— m?þ6×´7avÌCœŠfiàï×‹Ãæû{ä%ü·ŠpÓÙ¤oÿÛ)Ïû¥¨TI€†Åéa}l.þ8…H¨£¹d·ßâQ!ŸsÅèÇßÇ0¦ eÒz»šQ4`¿ tÖ¡°/ù‘èO¸qðY/KÔa¤ËÁì8k{Alf ˆ5Ž„]Ñx&:õ09l8Ô{,.ÂàÉ„V;×»™Dœž¤H­õF"xÄvƒÀÚx7<ž¸iJ2Ó¹­…±\©‹€S޲Ú}\;ÙTþuáK|o‡jbP)` ƒò¡#›¹wÆzêQ÷¬ 85q*„…dáÌ%Ò&¸°€Î ¾Í ‚0Én{ú$º3\8])i$hÖ’)¥7h¾Ò¸E`“ÂK6Üa¾R2où ‡TëÉkP¿½fy‰+·GÊý)¶Ïwч<X‹„Á&Zþb[z†coˆ0SÈÿètw^1åÁ^ì=“ ˆ4ÁÉ «áÂ>$5HÀìÕpŸ,HqþwWýö9Ä»DéœÑ %¤T«Tßöd¨;ƒY?]Êì›S4†´Úí䆤öŠ€ÐÍÞdÖʺ–´¥‚R¶Êg-öÛ"ÈOÍ-t›+XzD¬¸,`wÑŒ¡rîfò®|"ŠƒFL¥dG(çÜV¼9›XŒ$]— ™üP|¾ ½‚Su9ðDÂ+m¿0|*åÅËŠD,C(×¶ÿV¬ÊöšÂ¤ú%H™ÿdGbòŒ™`D¯EôÝÚʼwªÃÂоØÑÕ¿¶-ƒ„óy‘¾aP–½Òiyk“(رOùýöè•Ûqî[уÿÅʽ„P¡¸&b’€€¾Ê9O'µ…Ÿi[îe[ÑB˜'+og7pãd¿?=•Ô‡¶ø¸ð:ih(„1B1u”åŽ!+ë±%Ì`¶'M>ò‘Ëì­ìy§Õ+Ý QTÕÁ a ßJt\xÌtƒñ‡k£a Íä{‰ü&Ôo½¶’“†Ûköз×i‘‡Oôm¼Yqîb-=ª™#¿ …ÕHjìûóBêÒml‹µ@"_XØ_ãîðV,ïG\cûš¤1<ûv(—½Öån¢Qkp$/k¤÷Šej!j]£¿Ghgë]½ECžoÙØs“ý\!‚Ã7‡Ú#¸,ŸxkßÓ$T½FY ™{¢œ×ôÈ·6…ç2uî”è¦øku ^„ÀXe%7þ¹ï¡ í‹…ùNj_äèN4˜.*XW—d¹i ô#j»Vû"l€^È•, ÂÉ yrÙ•V ¾»à¬ðòö¼8˜y»H–!0¹ŠÙÐþšm`í0>¥q"ùÅEyQâæð-ƒ m3F×ô÷“ònE Ò™Ék/Äú­ÅÞ³Á †õ“ t€­Ág:€ezHyYßP”\2û¾¹Iñ`ççl°?Áão·êþBtÚÅœ°„èÕŠèƒ}u ñŒ¯¡Y<<ƒÄ‘Nò<ž»h{Чqò [sù-ù7áKoÇmi¬öÉ&ýÙÞ^^~IR;S#qA¢\ƒo…ëÍlrAéc—6·üƒ‡ÆšJÝÌ“±º÷e”ýlû„àY¯KrgaΡtm›ŒdzMe¨‡=öâ ó5º€$B”%§9¼êK2ŠšH-­pñÉÈ}Öþú>öº®·zxB:ù×ï céõbÏMþhº>Vàu¸ÇŒƒ}Ú™‡Œƒ7š(N”‘C5Í„ù7)×HUü&†AûQx–ÂGð;#Í£{[‹¸‹çX[?:‰=Šyé~ù•½Ó’¸ xaïHï÷ªE6y+é'vùsÿPJ˜ø ¿B¸Š—½Cåªú'€vãweܽºI\ÎÕÄB5Z^$ˆCŸYTxhêliºt+ ÂpŒÇŒ íŽÔ;ŒØ[DH>[<¼çßUǤ¯£è©–f“2QÐqìæÓI‘õ²ÙPr¬QÕÓG²ÙàET0ï’€€žÇJçI}Áø›î|‘Ô~Ò J;³ïÓÀÓN}ì¸þª¿©¸ìn³›e±d}ËP œ‚·Ù£dÁœ‰ÕûA¾"F•땟}]ÐTþJÆ´XI»÷ |Ã[•¼JKYÚcZ–×þý¬4¹+Œ09ç„”ìb;Aà¬I@…¿¤ȡк“޽û(âý©—œ€0D˃ÄŠ ;‘û½â ‰)FÓí+¯ôØ s©b÷½®‹Z0‹#náQ… +ˆ²32|ÍXÌLò]Íj« ë †ê,Ÿ¶»Çù|‹S~!1ŠïÃ$M!³wB_·Îükn¶! •ƒ97j‹i‹ß×Ç×{KâæûXU9«%œ³xˆT¤rá à©F œKV\aºoYÊS¹ú ·üwãePe­œ¿"¹r2ךÿŠ ÄèÂÛ‘í@êÿV:›ú•ÂQN¡]žhuüý=úÑ…Á­IÁR§%õ¶7Xê@Û»Æé ×ñÕaÞ~†NÇ®|1¾5± ‹ã{T’úͺ«!u m†èǤð³ÕrzÒKERã¹Zž½Ø²&9à4¸xðÖ@›ÆìÌœ½ò´%€SÒúcòíºåKÜÁ4v]@tQ¢“ÑÙ°`³Ü¬ï­žÇ4žžÇ{—13 ÿ¤ƒ-îÅf’žª¡’€€µ-c~6È”=OøzŸª¦rçüWm-cNSl–ÿþ¨ NÕm{m laôFšLCV3ÛP‘Î5Vh‡i‹PUETv ìûþðj`Gyf–mÀdGEy‹!<ô»¤A'«”ÿˆõÑÄ1h¯LŸ Ÿ_jªUL|™{0Ÿ·\œÔ¹¶Âé'®£ÑëºJðªÑ•#¸—Îך(sÄ€Ë#”Ä@nÓ–l–£”×KM|huÊñÙ\¨“)±þ3kã‹ÝÎÈžŠcáü{BŠqÒä7½?z9'á¡ÔœÊ+FT³ÔGÄÊØP“Î;áN²|‘›eŸ_l“‘Âïë+°GV`I;ÓòÒtFõÚz4Èž%÷ÚG+eo˜M4Áaa^x!¿I'àGÒxaý.†‡s…tQGèϽ5Æ`|]ë6vÈ¡§™|ýz#VÚ­k›4±Rî(üëCT‰ú£WIľ0úûå8íì?ÑlBZÒ_ìÿäÅ¿šSÏç;ÁÇ’È#ø“ï݇W¯eü&L÷Ò-â‡Až÷ìvi™3¼y¤ü³ÅNÌCj+P­Ÿ y¼,C=NPÓõ%)h¤aÖñ­[ÏØQPÖV^8híÄ—zn‹=ó­?Ïë¯-£‡l\9€G] çœr ýÂY†NL– \(©”!–Œì™Ú?³ããtøñZÍû–68ÓkhƒæÛ€ÔÔVÄvߘ!Ûo!LÈö˜v¿ö^„y³MߺÄkÞyèü½b;÷«Ú ­ƒ §èBòqŠœñw¨ûM³ø:ºs²Wì;ÇDl•ß`ƒ6w®5V%äpÏR v‚6 µÜJìtFär'ðªÇ|Ó¨²‹œ›Ã_ü”ž†È7{Éß]xˆÖ)wä]4-A½U yóÄFz˜„òýÌ…Q¶†į­ÏâÊa-L;„û0ü¹–¶ c =RmÈkŒaÚèõ‡l! ÔIšUz¾T¿_çûUfß-ØàëŠF“Ó¿B£ t¿^©YÓ»\g¬”„足„eÝ\ºÇ&kšÆŽFÑK×[ò%Ú±ú ,ðp¢ÑA!T Š“Š˜´\î èf¡œD«:Ñ¢H§ ³<Ñiú³|úlhŠÜáøÂŒ‘ëÝ®¤¢hHžå`ú~:ÿ½À¼x&×ixÅ̲\¢AA$“ ºA`e»1ñb’løéE5Æ+ £¬Ìh–±`ß@RÂ;åünAw,&Pæ$ÔÙ:ž–%G•‚ðŸT_ƒÓ_·W¯¥ö )gÃâ)õ@ØEžPe˜’Ø€ÍÕlÞ° ‚öO£ysc¡…£˜në‡Ó0‹v=âøÕq½]$ ¥ &–_&M×MtúVySTµ‚DzÏ*O*Õ í5á‰ð¡+[–W7y²"â«ÜÜYþ¹äŸ.ÿ¤`= ¹~á²ü#°ã–|lJšäi«€·–Ò[~¯ž®~Z¦e8p¤ZÙu.æasŠÅÅÑȲkúòNt¶GÛ«lr_âĵäÿ¤ÛF!ÝʉÎkÁýBÆZ^œˆbê ¯¯¶Cc ÙºäÒunìÎý1ð5+-m‰ zTí±]í¢¤¦ë]³8»½DÔô4jú““ÝíNe‹-Ì´èÌ“:¹aü—޲-é=XDÚ¥ ëSÿû5&0`©ÁT—Z½FJ7IëkP$j€œÉ܆…SÉ`3óÿ8u+=M#*8fE…á_eñ ‘l¤»j‚Œ óÀLCYgøô'Õ™‰›î(‰•MSFÅ0£÷ØÙºÂšê½¦mu[#ŠA$ÁSÚûF’€€Ëfø¿\ãu /Öqݪ^i;k#Hà™|Q7ü‹wc0ð„9—oØG„“J6MäÃb=7U|qnþLrk™Uë¶„Á€ ÛS-Æ]Ï,‚ øü”ºñöìvÚ@tu¼£†rîU\’Ä‘höF|„"“å7  WJud$,GxŒ`¼£¶¼‡TÇ£õKÂÊ>r¸r|öûe€ÇÌËvëKœ½´`0ŠËqê¦%;m€ Kk®:ÖT&À4œV· ´\ýcÝ=#"æï%$²€‰Âïm“ÖŸ!7¹ ?sÒq)?¿M©¨£ÜL(-pÊ€k‹é ”‘5WÖÿ–Ç©T¤¸AÛ/ÖO•¤)ªÍ†„ùpÒDy.91«ƒÍšc#›\y—¹Ð‚ùÀt/ç#,¼ò/ø˜Æ'ÿ ì*9šÓ½ø.’©Ç©üœš°~Ú|îÆDø%¶C ̵3U*ÄÑÓJ´;Ç\q wªIëHý,K‰é ÊœÇ1t8¤"€‰Ò¨Nùdœ=Û9!@Ü`˜$'^°Ú¢¹Èø9ªœÐÛ›/jÓ€móóe°_ƒó—=§†ÞIØúª9Cn›8ƒŽFb-ðèÈ—¥—ËE¨A(\ÉóŸ½zuy60bUzƒñfu™˜¨2áeܺ7õ„oâ,hãi-_FôQ÷ZØ™©-ÞÈeä6Á p†<,Ü ñŒñX«°Ç@ƒ7zQö ­f–y±ðÂÁFWÕ×2 ,Ó­ÀÌU²Ò%02‰YVÊúfÊ@·Æ%œ“bÉlyOµ9J#­å(‚…6é@/õ{ÞîŽÓ™ ÓÂ1y@^jt}>LÎÖªã=Íð‹âS—áÓøö#FE\(¥# ¾°A;®°vׯ§]ÈØ T¯Hk£r-cêl¹ÓÌLyëêmä¥âÐND¥#7NCF±§£¦7ßùÙ^>„Ï/—³uï£OÞÈ 8ˆXèhÀÖÜ9 ñè$ ÍdúûÐ/¡ùÖ¯7]£/•‰v‚%!…9ŽÈ€ #™X<ô²f TŠ¿áuÊ„%8)¡©~8Év`¶{5Úb~•{gQ·Q­‘œjÁT&sLvI ©Šlª»oÊäÕó…Û†³‹³£ )çíå ïiÜ!…Å7¿ë“…6lÉ~°ðԞêøcyÖª¨ÌªG6u#µŽáë‰rý‘\ÈÈ5Ýéè BÞâêíëAÄ´õ´ÿ½“å%/ ¬–ÒÍ.Ág*ò¢IXÚ³ð¡mjºpž3ßÃŒÀÅp~¶¡õºö(ÌbãÊÕ6s'_ý.X#ž,×Uà&÷ºšåoLß§³/Ü‚µ` :+\»þ~wƒÆz‡WGÈ×^ìT÷òìÚ˜œ툨ьúy¶Ä¦õÆryTšÅ¶ÀZ×âQÞér0z4gRìÌØðßf/¹Æ¥üœ¶|Š”F±k5aœ£µ/c·ëý‰U*‡•¿wšuJoˆ Ħ°™»\Ë~©ãó¼vOí Wç%/`ä6壘ÐB†«úÛJ-Df¤™¢š…±FîI ïÊòBüW#BhD¸«åW{&?ß®‘jޏH:¶Š¢.h‰ÝœGZ¦“àæÆgêÒbõÝç‹ÑLŒg3œ 9îÀþ›F{£¯írìê t Töä!»¹‰A¯·ÁtôV>’€€¹ ß%tž†Ø¨©X8’0mÌÈð6NìÏg­ß£Š©RÍ$2‚öv¢ãbäašóùýšŽjšÛé«‘Qs^z*„oOCÙôvÅÒ”jÓÀécà"cŸ«ÀÙÏv_=¡\ã]áBmà†÷ÀÙH=c[¼°cTíI™öpïº_½…nטÌboys‚`‚ß!$}hà=$Ðøèz,„æbí$a‘a–gœ”ÖÑV@іڞƠÁDLOÅî1“ÝñI>Ši]Óöý\æP]ç »ºLS¼Ät«Z7¾å3¼¤ÄèD¼^xë·‘?ºÌI'CZ'XÕKô-lmAÇáƒ3óî,Dw^u·¦ZÓg½£IoÑS|[/Æ”¹|®q‚m"/¨1ÚÈ9‰ÀGãdµí·êó¨Pä 6rIt…Ö¸ª'Û±”'¡a^Š1”!ÿ‰þ̰79B”vôÔìôõvгöj°Û©¸E±¤0È/A•œÚoHr H`Ÿ¾á´ÉO Æ{;8ú8²ï 3·(b@TÃJ¯ð˜²Z[$‘í'µ%ö •ëY1]˜]4A¶å*öñ×ù^îvŸk©Õ×¥®Œ˜Ò4³W·ËÌg7qܘ©%´YÏß2˯&ˉßÝÞ« KYò¨âÂcnú¸ºZçÍ VdQœã¾t‘ÛraíCu¥}Ÿçý­¤?bÞ&ÕM+ÝM6+–aM-¤ yפý¬b…Œ+ê¯JOû(êO#ŸؾøæÙ^UX½†‘Y&hœ›Ê=O|›`Tq·E!V)~Ñ(’€€ã²oôø9êÇýb[o·Hí\´!žKHuí²ÿchbQ ìÕLãÙ ¹û9î® \oa½‘ŒÏ{!øØ‡9Ýj±Iî°@Šú5Y3¡—Ž!ñ›j+PÞ¯X¡UÌJ`9±$âCE%†–§F¿Id‘4þ¿Ëèq²¬åU_’7/­rœ&36åP(†5`/øRÛó<ÑÖä‰ç»Î÷ñÐWÉtÏg”F‹vàù« Üë×h)*¯‘K­/ê2¨CsÐ`´ãùO,òê½¶œkM…Eì@îªKÇÇ÷»/¸;0`Œ<€œEfÜå Ca€Üª™XŠW­ ØÂ”Æ,bäç_áx™Ž@“JVʧnÅ"Tî¬ô®ÈY~9]ÝŒˆR•5声T‡©–˃|²‚85õÏðˆ€ë¬—µU5ÔÛ)ÑÏÎ6uýo7Õì Ëcé™Ú:`¥È¼fõ`ã¤ñÞî ÐÏP8A@•fÕ7rý¡Ž¡Çµ¡ ‹ªlWày•Ûq^G°iaÁÊr^œ Ÿ&GL 6Ÿ¡x{d¸t„2[uÙèÆhBùc´ ÞZüêˆä á›á»…‰ÌšICYTòÕà!ÝË1”Ê||H¦¿¾tíb1ªÆTAüCZú]bäG»seùɱ¦Bü°cÃWø>rzéÕzF爈Z_} ×_oMMÊZG,ìÌP\ãÆ£üëS„"-æQµâî‰H|ø”_W}n•»Z®ÍŒ"vÌÆJÖW:ÜÒ“âñ&Ñ8ôÞ=¨8äž¾t„Úqc<'Ý,¤bóxàºÒGõ¯‰u$þwïêˆ)fX¡Ûw^ô@}òr1!ûê0ì8l]FÁÝmÈoüijæi2S0¹Jm6ž³ÐEC×úhjH|ýJ‡C¯I"˜¬o¦}m1þ¬Ÿ¤¦Á:«æhD&›ÝÓ,×7ôð¶á6–J6ë‰J©µ˜Œ|ÏZÏbÂÅqB‡@¥_#7NÇ/¤R åW ±[<àÐÌ ÈgŸ­µæ†8¹$±þj•H7ñºAbñÄK!Ó…ÓÑšb±À#c­ÊIŸQšBVt³ZÅáHÓËží®16}y5IÞìû¯±5ÌX'fïŸ-ÞÓÂ*Ü ŠÒ%„‰–7íb9è¡ç’€€àùvqz‹×OI‘‰•šÃau8ä¹mÜÔÄøÒâ¨{“"/©•¿ÐÅÒOZ»GÕ[8$$e¦ÖþvûÓUÌ[2JI§Òê°A ¨ Dy²lœÚ”Jö–2€Šºô®VW_âv•J­M-×Ù]|þ…“löð c®:ÿlñpiZýÚ$ƒ3–ΪCHîž>È7˜ð¶ahâíp†Ù×ó” §-Á3¥Øs³xtCKÂÒŠÏÎíy í+˜¿°ÿ ›®Å¦Ù˜ïþýß›‡‚®Ó#rv †˜l)”\X"ùnl1¿ìI‚­{Aÿ’©e,¯ºP sÓ÷©ÞºŸQ«ÅPh eîUá ? uÄÚk‰³Æä#R±k! ²ŸEá¶ãYzÿè÷•ɘ &U߉ÍÈÌÆçêºõ)^VƒË»õ'W…pÛ#±\†F720m ÂQG\hˆcy?zQÒé%zý‚ŠUÛþŒQ\s¬Á¤@ÂÀwH—îø§zðí­ ‰¨ÏrÒBé.†#Ìc"'Ô±Gœ¾]~=t5¸±<ꈵÏ^חî7]úâ¹·­¾„§m6O9U¦"¾ÿPŠÐè…vô^vŒªýT0W¬Z˜¡*¿±0[,7e^ËJ>ìœ+!ÜÄ,ð— õ©Qßl~U<»klé#zÉa£¡,$z*Ôf(^pš–+Þ:£.è§â}C±ÏdÄ»æ[ðõêþ †JÊ ­Ï=£º]ê8êÃÁ ¯ÂüzPLzËñ¤ÂÔÕJ¶!²Á:Ñ=“ˆecæü/Q‰SÆ"õ–$át(„‹N‚q”Ï Ñ‡œ§­«„üë Î* [Yþt–Í«BÐô‡™~¨îñèIHÅ$0'Ž#cÍA„^jm³³¬Òºh3SÆ>ÃeÞþš:ž¥mã†B<‘–3|ìËË/xrÀ[rá}þ•>È<,»i«ÈŠ`$ê¹Û¦íݤÙ ^æXQ9Ú>Îl·e'|’£¦¼Û|(bLvR E©©ìH9reYµ¶…„I«Èâà 'iÒ³m>Zé4’€€á+VÆ®ä0œR½~b ÃnÜ>¶ÜˆFGÆm¹Ó®« {lm„YäÑuªŠM9{o˜žUoZ¨@žz, YéEBrå(ÌšNø¡Ì¥§å쟶]ò(Ñ+; %œ§™ïœ »@T¼\ì!_•8~ë¥ò9•ƒ¨$kVEßá)Љê¯á\ý,aÐÚ€Kqwíü¸ÎLUbNdJÏÙx˜*+m«YñÈòБ9ô½ÞDkÎW½Wóia|~É@YMÒ``Ãâæõ%8+Ø;ÁXT¤:ךÅúÕ-%ظ H±ºŒàêýr!k^è4Ý‚WVn=¹>ñÚ‰yÏþ™Åßx¹§ aªiUÒ7« 7ò¾MPs3#ÈÃÉjø²bi^Õw#%{o©•Sw›€¼ë8BKGž»¬¡LvYGh=‚‡ #ƒCÇ‘³O)Íí ÅJíP‰!ù×Ô¶5X}½Ÿ ^ý‡MÿuF)a9†­Ú2Sߣv Ûô~:«øUXÝ} Ì5 dVx6QëlÀ%M¨s«µ9²¿ÁkqI1ÛõiFÃòyhú1îÈ>ÒHúF¿$©iÌïEŸÖi†÷¬JÞÊÒ¥|mþîü¶.ÅcXð]¶¨Š“¥©¼9 e•fÞ„Â÷0R“s ®K‘ùjngw¯÷W(Û$,n¤ÐǶÍZ¢Ec·¨C±ÀôŒ‰Ðó®ç`pÈeµÕCBh:ô“i!Óû½ê'Mg .™ßu‘À|ɬ.ëEÀ°F\‹‘D‹ÞZÚ1‰}~f‰³ÿeCúž¼wÝ™4–9½FAò†œ5¿aLê1çz̽-“2.³„Ð§ŠæEØk¥’ÞKˆAÒ^ü6Ž…6Uµ€ªU,‹+åxÊñ½H% Ü ³‹(§õU˜•5:‘ã§`2Ïæ8óÑ{¨f=BÞ&WfPQÖуà†±èƒ—GeV$ÈûÑÁŽW­ï¾­£å¿;·S?õÍ»»øëGJœshÄV¬ð[öXGµ²>3ÿ|³ùÎ8¸TU™BµÔ9Ô[·ÄÓ`©` A°Àf4¬Àte{^²ŽÓ° c¯Šë£´¥SÓã<ÊçZb’€€Éˆ±Îìy§µŸðRÎZ»²§d´QÃl’Ó†¯"B±°Ë¥µ9H-9[•¾°SÖÊz$Æcñú3¹!äʫԀkïZOÎ+ôg•[ÛKaµ²;C„À6êɶP”á.­DÐÃAm÷š)•ò2fògòÚ9ºÖ‘»éA E(Î?x$˜»|Ìxéõínšö%‘ˆ~fÇ7ÀЬü–n<ûx{ò%ˆÿÊ»|µø'’D\ª{䔿s³’§åè©NA‹¹ U_¿6ó×¶q4ô{J+o8§Ïh4Ìâu#ÖD•×ü,‰p°S²—ïjèÕZ]øí;¢šÄçŸ)²4‡SÍêEXœ¹Â“Íå!ɪî&f¯]|_ƒå¶á6 Ÿ¡.0C \öí7´tÔîc  Â?Ð!ƒÇVx÷ÜÛâ’éV?LcAe”æ€4jØvUð1©NJ¯óB†Ö©WC%ã|©†[.ßRÜø4ê`ŸBïK?<—l๋Ìb8~šj Æ0$'{I­·}Ýñ…çOq1ºR’/Æpê:àmøº&íûIø—Ò£H˜“ct×)‘ á²üŸ6ôæû =3V»§tX;Ǵ̨âRhiv@¥A·æÎ%hÒÁ¿èùâÿ7( j× À>­c%Fœõ³‹i± €=eS$E©þšßÌzMZMž?ñÓ£ø¯R àE¦pD?cÆ·ÍOîLD è¿Æ‡éªü4¦wLwþØ&['"Ѻú6Ï:ê½ìÙ.<-µ«èY٪ˬÝÛ¿"‹è5UEuAQꈒo…ÐZ;UÔ]Ø­=j‡†EÏBRzJßPõ IÒòz*µöåÓ÷}ÊâC9‰L ãÿLGîè*@êúã^±éí~O³ï\…ÒXÍìä2 àܳ·ÔBëó‰ÄÿS Ça'#‹Î#—wÞòÿóÌkêµÚ™ íWBáüDª( y¾J-äâo<3<¬x:?‡ýJ.g.×Ü|˜EÏܤ„º“³æ*Ž`Æé£³õß ‘è7çC¤bÛóNS’€€Ì7‚F=Ê·³.Ú"œ“amø—a 4í%unBq÷¯Puô¸DÝD3!£Åÿ¿ŒîH-ÞšÁö¾6‚`óв_ÅSÛ›‚CÑ–t»ÎeN‚Õ ªCÇrG¶\`š²@5}øPŒ!†ƒaÁøk8/ïŸê.C“¢«¸ËO"¼vÀf`eÞËA:îºy ÎÑÛ wP©Æ©Và*×FåÄI,ú0!qØØBa-[ëP˜ßÇœY±+íDM@d"[útU}~²tæ©j±Z&âPl{‡ÎËʨûÜ}4än÷‡Ñ²’È÷¡Wö/íQ9œ-¦Ô˜‘Ê“Ó5Ràm§i-°ÆûËòPn—ggNÜ>$F¹’ä~Å$»ˆd4ìþxþe 1JÃ…s~eÐ}¿ÑžŸ—Oö¢¡3]%¬©*C~¼ÖtÃkpPÑ‘HcZÞV›õÉèÖ3II:§u¡ð5ÑäŽýw™²b¼J økÁÇçç"o’-ú!3Pÿ7`,µ¸3ý¯ÁSÖ|ÓÔ°.püùW=,:oMx)¯š§l½>Ð[ô@‰s¿€*‡íökÖ.N·‰¦ ‘EÙö:°Ô<ÅãXþ€¨Üæ\ÖD†(³” ½¸x­àC¤;•U¦Ïš@ó“ˆêª tRæ¥ýÉëšjdìä>ëjÊ;ùæZ¯Þø›K,ê½D2s°Ž«Û«Q 0»–³û³ê¥"•ª]]ád½uÃî’‡÷Ò°Çä`w@ØÊëü„ˆ¨/Ç äi$ÛÏ5¡ ý¢(¡ìPcüYísμÍâßÙQ,__G'„ÎäÔO¢ïDnî/˜Œƒ F±>õWrkØë$Î…Èõâóá†2µ )¤)V¡˜&ßpëj°1BËsFNùÿÕ{9éc0i5í÷;Ä( ÈCŠtÆ,z_¿[œ{8SÔ£Û*3m”`í,NU!öFíÞq1òt!è´_‚`ÛÀŠŒ»ù´D5IÛvEÓ?#)`îxUž¨DíjY ºR%¤%yçÜqŠ(£F/qfœ‡ ƾJ~ù-A&5ËB `HÆô6r01ò(®GŒâƒµ¨ž8”d˜Æq‹®¨¿fÛ¾•¡v³4²À ÕPô'¡Pc*¸Zã”v‹‚zIñp™U{—©ÍŠ!ÖÇæˆÑx|mt1"+Ž>™ëF’€€±5x‹zse¥3G¨,¿- ¢¹ºKžó›¡ ZsäfD*I Ø…ÞGö1¯2¾Êõ8—[D¥Ï”e¶)¤A{YkÄ º"ëeaT#oÛг•{C¼à› «´QcÅ+Ènä“äâ•ýÙ¢f‘úHܤh¢8|ÑÂOŸ>phÛŸpÏKC”m‚f!ª *ÓŒ´#FÏ<4– ÅöQeâ-0ú=dÊPÅ¡D_ù$Äùÿù]Œ—ä} Ë,îvXè¢?w=#ê—ÿµô5¤»ÓØð6¬.OTã¨=Œºi.“êÏdåp“O`ug¡Žn¡ôËnÿ—3oLh&j=g%ïÑš²WLáè©\JcÞæHmQâuBI[ë6©;h‡3æbAÀ¤Õ%eKñœ±œ³¤AXÀ¥(üïQ"Æ[ðæ<Í·‚ e}.ãR4sp´º}¿¦‘ %Úè꜉?É©K|Oü‘ØXWüø„%‡ uFÒÈNYA?áÌ¢SX$MTôSšÐa´ðÝtßp¹$Bzi"Æt дûo ñè<8ŒÆc.Z+uûŽR´èÝVp$µù:€Ù1}Ç#ñ³J‘KÝ<Ÿ±ñàB1ðÃ÷ªˆ’« d4åìðX†R£ý礿neÎXÊPˆ8/;äv:úÙgXÕé‰>8åò^ÿ³ø¡T¥ \[ô«~ÿ@ r„?#F+>HÇoŸ3ŠG^NÃN?U‡ûÛâøêH†_UËÀF@¼½%÷B3=íæS¸¯ðމ¦ `fé'¶a¢ƒ¾òàT?É41$‰ý;c!h†$lÒ‹ ÍUºUÝQZŒÏ ÂA/»Þ¢ˆjJÜÃø-±„‡ÜZ6Ç ¿Ùÿ¬<ódç.Ცuuµ)ÿ nS´Œ"°ýÍ’¬š‹F¬g£ðŒ¸’qîMi/f,VäË ü»\ô]Ž6䊡åòi6’„%Ÿ‘ȹÆRˆµ_Ô\Ïœ@C/*TÏóFC¥¶+§»:€èŸý–€Û…EkÔ–ó[JÕ A\éRcR:}YÙ÷ï³³aÊáq—lå#=3Ÿ´ßžÆNau†úPÄæOßçßzv¨óûÑVÈlszþ¤Ó„†Aæ2xË‹&ŸàÉ·s˜äµF=õc†tFo¿yjë„*ì‘}Î(h”,¸-ˆFÓ.Þ# å=ý H<ˆˆ Uá¡„Œè;/~줲n‘»ÜlÔôB„á:AmñÐ÷|&Hã_È€¤å¦Üª™î•z’Š,R¬ÙÔ TôJà 3°(q{ ÌøiÁrÿÕ]ñÈ:Ë—%Û0zïH9x;ÂÎ !ÆùÞM#u_)ÓFsÞ9C½k7w—ˆÂ_½ë¬Z•­Ðþ“`*³kCAu„ÒJ8§þïÔÁúü•iWö·á`ä`AѲo©Ï\øJþ“ñÇ-ý\‰j·bìZJ´…¬0±»ð"?}ßÐuCáö{a,Å'ߣŒ|Ì|d5ip+–Y › ¢ò@+M!«Å`4_€,þþÉæœnqÓuµËÜ ÄÜÅûpÝ_ù¥âŸ±Q]" ÌëHŠ£³¶Õ-/‰1éÅ{*³FPvŒ. VžN š8ñJz ±~™sù0§=Ûcr]ïJ8wî‘þÅ`z‚îÎs-pfõ-K¸#[þ(<ÑÆnSïûezÂF‰åkÔÞG ÛP¼[ÕCߤùcK©{Cm´Æù£§±JòÒ5IÓ’€€Í¶ïŠÑz67é·Í@+Ÿ—‚îbøÂWßôqTf˜;ᄊxÇ5ªMË ¤9;ç‡OÔrÙB] ¦Ò37eà•£¿f×ÄÓmKÖdIÜê@\¾ÃdPƒê·&þ $êí¬Ì­‚¬¼ -"a‚møBª²µÿwU»¿õh/‘:GUÂ{)šÆãrvf{ÃYÙŽG—|ß’Šô=¹ê~"-:©jt¯¹ÑÌŽKw Þ”Á—]ä‰„à Æ÷;(G$ëæÏ¤ï0òÎzñþ÷?sœý+™ ¸ìc]]*pA÷g§‚Ô¼‰½*×®Ð-yÜÒƒOš]ù¿t^é‚ÂEŽp )•ö§Bkÿý6'_°é"Òo®…Z§Ñ´nôI𣄕«JÀÜfÙxIü6Ëé%ɼ°J1ÕÜrç0®Æ*„ì'æ[ÅïÃñÎ€Š•[½ÛŸ¬Ul+‘4:Â@œ>“¸/Ààá ¡ÄxqÈŸ3Åå»JeA`5¡|4‹ ºç|ZÄFÏúú–Ó/^߿澂ìÒ}²b|úçv7¶ò2R +Z+2å &÷®ÜËï«Êõû?oºc8èA3Q؃ 1Íélzì=ïÍmÇÁ&r¶ZÀÙôÕHš\ØÅÕsHÏ@|[:^ãyªKÂ2O¶ö»KõÎÑ»¦dN„Èkwü)3ø?Žè¿”.‡Û¹w¡;EÈlsñÄÇohŸ‰á®\Én´€ÍØÐñß0×Úï ¦‡uïÓd´Ÿ›}1H-YФ}7ÅÆÚÜlûãBpwõclWeoÜ-à^ 2WùþV¶½ßHdÖæ’H3×'sÃpÜ«üírÌÃv‹49PCYþ@™ž÷ñhÉQûîþhäóS°º(G§5'9TSBÑÇšzzÚ$ÔÓ)îMuÔ—Oƒn!±5¯É9C¢ŽªdHPì*ü‹–<Ì‹ÆÜ)áZÚÔƒåwýö pÜš²Gi‚ÌLb¯Ñ›Ás HâiýžUÚm_õs¨²Ý xšç׸·?¦ŸÖyuž7¦föÕ\–"å¿B·[‘J–»lIÔ­&z EÁyœäô ˶;+/(Ù?¥² ¾8íâ†Ñi†o¢°3¬Ë: ¿Á9˜äjãÎ(Ã/F‹î«…q½ü°ÓÓ’ áîBCJ3l…ã-_²3Þ…DPÌýkå5àM]ì€jŸÔ/#Ù?æQ:`¿ƒ@VV⊡§I)ÔÄló>DfKi'Õnp’€€» ¾º“ˆ" x)tf®wgŠ[&švš ~gÄ« ¼§<8eåohMq*LF{™i”,0e›ðTÈü6…¹Ið`ÉÂZ¤ÌrfÜx‹M*rS,¾™àbúfꥇ3h)Áµ”tK#R,úêÂÍ òaˆÝersd—U4öÉ”ÁdµH\.Íç%c-ϵAÇ,וÏá5àØ„~+ž`(⸀$âu'¯U%‚îƒ-¾Œ¡Àûã¬Ïã¤õú±5¼­l}ÍêšÀRŽ#»ÏøDDX D+ÅG‘ÄÝL´(]=ú…ï©Ý?fÜÌ9ïµ€LP‡%ØVg~w×Ï%Æ¡Éǽ²Žy âôk«ž†7užTÒÓ],Ëoó-…‹¤å±Ì„–’ß9»br1{UâðJ°v²äÑ×$Vf IòñÖ¤±’ÿˆŽª:Û¼bÞµewp§ÜÚ”µ»mJ—3îÁ+÷®âÄ*¥'ÐÊtûrñQ䊯hÀMŠeÍjÅ3K¸™VYPßÉ÷q^Xµ„Hp™›O/^(&wwZƒ’àtîÊ)Þ!Ç÷êÀÓq8©ªé1èuÖ¼óßôN…÷tu‹·®MžÛâ¼K¼\qÿ tÛ7Œ\7ó‘'-;2Ï|dÏ©ñ»Ü…ÁçÜm›5e­¿›¨Aü°óh ®äJƒWЩ†EYB€ ”%pó¸ÔژɯßñÏI@Í:Òýϰ_›ŸbO”f'­Ï>ÍÞÇbt ­Ú^Y‰®,MlÝâTÍ ûQaWò¬»0´C‰ë`Ä·Ó9Iv{ @[óî¡çú‹—M…Ú ÎƒË÷øvò‹lκ¢‡J:¬3ýâ̸ժ˜Ç‚ä&!ŠÙ¹Ö ­¦ÙÌ©%˜Ðó9¶´¸uÊe`5Çcîi÷hÉK}âåYðÚ0GîVPÁº‘8ŸšU¥KºÀºkùå †TSĉÆgªI0p•õÓõ™ðf—:º&‡‘ƒˆœw¥=W¨­ÒþÓf8¶{°[Êf×ñcð£JNÌù×à¬×3vÊË“üé¢RD¡ÁÅÆBMÿ8A›ˆuÆv¸ͯêZÌ^æ.|ÂöOš¿QšÁ£¿}l·°:ó Àl|¢ïÚ4©ï;8•‡Ð”€›'žÌ±öùF‘TovË£Ÿ¯ýƒZ}§Wl¡¡ÁûmìµVüBÄÜGÄû ŸÑ7*ë£~û^+3sV=‚êN$Pó—wé­U^â«ÿg(›cÞ…ýÐL“Ϧ„!çQé¹Õ.£*21ÜJ^V„ì²ÉÚàË7n\Ù¦ÚõfbôIÍÀÖÝüXït倢`ÇݶSˆ×`C¯Ò¯¥$÷âjÅ©äУ‘’çaЈñ‘HÍ6U¢J6ç¼6suöcZ¾PËΓñ,ÀÔìʰ(XÛæôÕW)?ìÅÔÂ?–+ ¯‘s›LªÊòÄÔêĈ-Ø +µ/Õv+¯;»pžG¤_¢º=Åi.‹ÑÄzë¾mšÓ> P²(¹OþZd`LþP;lwÞˆøsu~V•ú¼Z²‹2Ù®Ò¢Q¶ùAš0/j9®;†æË8q¶clýLG ˜¼ž`çè§±‹u£1œjøWëèiaa¨Âõ»¤k·g¿V¶î8ÛAÂ^| Ë®Oër­'dÙþžß¤õ½Ê©véCæÃ§‡0üñ²par Óœº—ä*)²Ç,R¡.'ÿËÄÆ´aÁðå©É àL²ÁµY’€€ÕtŪRT7ã¸ÂÆÄ’ <8b†fP|ö ?¢‡Î:†ÁX™d›§AºÜó +y4bP,u,«ì§N3hvâ84c®OŸ;ß]mâû¢¢ñ—žÉç¢ójôÌr¬¶Ð·ËÍõïrPhqÐpWž€M™¤þxVt 5i0áSh0P—Ñë ¸½ä²±-PÛ~šcK¸•;&ám+Eê ZP\Æa³ëiŒƒõœÍZ(Ê sþ´ŸôŒÄöW Ò^ô‹|A6/7¡Nú7©ŽÚgj¥¶'{h?ge–ÿ¦ˆý;h3Œ= ¢DИÓb‹Jë ÇÂ= >Jêýè6uéÁpç’ŽI²‰ ¾qÿ¤ßýb†‘ ÙÊÒöc­x¢'1¾³ET«–(’§Ä÷ŠÍÿ}ˆËKA­+½RH‹º´bö=ÓR' Qýaϯޖà0Œ Ûõ1«K ­8`9UЬªbù½i0'éªÄÑê=OÜ¡²L( #¢Rm¯£«ãÎížúº’oæÜëÔD·:Â`¬cžÓ8Ö >Õ‡Õà\õëP“÷¶ŠÇ[æî¤!&†xºÏ“TV5ÆEs°èM‘<‚œ•rÕw4›Î©sü‡šhnå9YñöÑ”ËöŽåµF‘uQûÞ;h/íHŠZϯ;w3ÁØùìà UŽ.8ÒÇ—¶r´)!æÂßùº˜á1\þ£T”ko_þ‘x‰ÛÛáYMÅæ¿GÜÜ™ºüï4G^9±98ç?Z†KöW ®åš %ÒÈIX{ÇÏUUa¶iÞ¦: _^ç#Ãá˜#啸PL,€RæKÇ-} ¼~žÔ‰^¿™Å€hßíGCÅF+x’Ò¯y­¼ª3ks¤YÅ^f† »1ï™_º–JD‰|œ…g‘z⩉ùÚ­òxʆÅ^”9dÛØ¯(Ú 7ðX3 L|Áö!‰–”4•CzcB®sÔŽÂ>fÏ+w¢ãKLðïOJ«4Â4‚Œ«ðµMš³’X\´P€‡¨©Ô66ûú¹ËKýc¨þÓt‚RE¶œŽ¡¯ô)—Q¥<äåbXÒ¡› ú¥—²å­c <;Ú/¿¼öÁÈ9ìÿôÕ–Žà[|óÙqËðFB†=šw/ÖœÙw›Ed ’€€×W¨íy“ÙLûm5OÝ©¢À¦¶Ø”“kÇUÆJñ7× ß"£ôúÑꥫÌË9&¦ÄŸ,0[6ƒ f4Ú~A´Ä^íÍ…’·Ž adðÓxú×€ U„›1rwƒN˜Á¨ïòfÒXýDŸ* #K¡˜µ­¡iêPWš;_ña}&oÕ˘É/P Az͹g ÎbfD­­<¼ÁÔ”Šoq©¿ŸðDHèB|¾zµŠ.J3£ñ|ÇÉdÏp¥'M E¹ý8"„t0kTըʀÜÌ\ ·r´ô°U&µ´]–¥PT û—ãý‘lÆ ¶Ö&復çò®½X³ @ AÅ.K_ÕkMõ\eUä{w±É-ÿ»ÕmWë ŒIÝÁ—(¹å<‘RîeHÅÏǶ9!$_dcšóô3Œ!ý¦;AóMœ€ë‘cüÌ›ˆ# Ù)YA3ªÓ˜[ï'ŽèâÒö–OeCËŽD.d¹YFîGU†ÏL…Q–rÝ—A 8ô] =Œ€ZÊÜv%·ˆÞÎm¨?°’sFp͑١¤ôâ‘ú[Ñ’KãÜUõÏñ¦to€QŠ¡NÐÛU8›f ·Û³Ì&}Ïýëo€L?<0ÿ®²žs'¼Ò÷¼d©Tlµè¹á>Ra'àJ]GrÜTÚÊLyØØ±míÑæµÎÂs·%ÔqJÞä¥ù‡ýäY”=þ/¾GõݼыŠã¿=—óÆ@ªbí²Ê# F8ÝÅ'®Gy{Äö¶«/&Û”vÄ¢â4z¦à,ˆWõÉéÄbG%8’-{"†¬Hy OOB§ÔMðªW•&—3SZž|Æ'ù&/SÏN¦çΰ îTIm§RÀ f³‘‰¡2 =hàVßêØÄ# GYu!×Vš™1÷lš¹«œÃÄó¼b\Ô‘^hšˆ÷76ЙÐÅš  -…çr,m¯ä¤µ9õg;‡á `ßß4æË“!õ"ÆXñœ¶ˆ0°'V ?6'“ƒÅfÚe¢v÷B `Ÿ€[Í8 ö$Ðß%?¢#Z9[aôÑ òCø×FÛ€/Wö¯=ñÀ¦¬Äm[©‘³Ï‚@x9ƒyýE.Êþ nS†aÍ2Üä²´ó8¯„ÉJË{T–ÖöïÈ~=A©\ƒþ‹òkZó¡€xœ •ÁDsiýÑ{ƒš;…*ªó¬ÉWð"ÜœR\–• "›Ñ<úÁß<Ë«ûo„X²]ïfú¤g+´¨NßJÝïxÏ—±!›Üž‹Äâ0àiú2Д¶4óÙ¬ª*']ÁHëÝ·6ïú;‡8ÄŸ×ÆÖ%”'É2mfÂþ4[–zºú| Á±¶Í­íMZùŸ#BÏéñ…КºÓÆÑiU]?0«ôR{lÑn`2·ÿ ]0\x‚ƒfy°Qpš¶Ÿ¹“ŠXÊÿÓÔ4Ñù9óDÒh-•$5+UÖìàûÐÔ@ev #¹W0”Óko‹KÛ€fÅ3̺ó”š$Õͽ꭪Býc¦’Œš¼wÀÌÁ!/çT¦»Ï» £Ä{S½ï£˜þ•®%ÿadØ;6¶®WÃ+Ʋ¨‹o@-tA‡l¤§7&W´»r®>ámö·Ç{ú+  §i0²sé`Z„Á×Çù˜UQÇ63÷dƒWZ3Í€Ñ2²wkpî4…ݹå>\Yü æ©n+ÎÛ(ŠLJq†É${,Œé.ÒK¨ ½¹Å58‡ÈUÆúâ2Úòj¦w¦öƒ¤Nþ3Ç\°ÆâŠOÛ¥šs¾œÅcñÀëý úë°®!ü1¶RšÀ„7þZà±²ð%‘†ŠYÃÞ´Êq¯4_×ú+ìU¶$íËeþÆù+EûƒáJkÍ;7/èªrZš×íô€]~ÆRÊ)·Üxêÿ^Šieš@d•.Št!¬~án ­5#I_£òj’€€Ýf¥¯­+ §Oº|¯ôÀ¡áDÌ›Mô$2 ô&.M´4ÇFùÞUhäK‡Ü¥ª‚ñ¡¶È'ãÉ‚B¢“ÔÜf{KVC¬Šj—ªêƒGìÆ¯G9 QKæ-Lå?D–Q¼a˸àܪÎß»ãдŸLÌú‹urÉÉì;¾ S{‘Èönñ΄ƒ1Åi23("X _ø¢˜ûð†cR¢$yÆ”‰c^¬³OL ꬨ‘оaùØ2@»iÙÁ¿ýn˜Æ[L½Rî;¿Áö––XÕ¯ƒIë^µçmXYþü¬ã°äDé²cSÃü ˜Ë³Ò%D.ì߈Z³TrÇ“FäïmŒÉT£¨ZK#Zw~<‹ßÓ¥ËðþêuCѨx¥þˆèŠÖ¤°SæRx ùâÛ Þ×|W}4òb ’G=鬔ʇÞÿÛ ó®Ý=²·Zϙσàå—ï„å7Ή‘S"kôpq^gåi\ò­¼/kK¾yÄžÃZ†^\ýwàà{ø÷ã~c«Ê,—Йõœ4Jæh3ü8þ:öÙàÞÏSuM­ìÓY9Âǯ=îë#ÁkùžoÛé-ÆžP£èn-°bã3ŠÃ½Fx8ßM,Uvu½¯2ùàBå°UÞ-q·Mß,¡¹Ió!´‡J³‘ê.mÈÔà2‘ã2ÒŒ½£g6ù+„Îc£:’n‘Ìù?mþ74ê*t‚º*t'ÅL”6ÙH‰mã29~ÕPj’€€µc\ó[ß?JfyNúLÑ–’TC$ÈbÖ¯"´–ö<ú ÔåVÑZ$8Á0¹{Nâîp•dÑÈ’¤Ž/ ÜçÝ‘O¾Å¬¼4ž÷âuSûœÍ}Lyã«è¤æÍ§ÚÖwl§¦Ô—qðM…Écÿ–+ÈM€éƶÃh ôíBD¡güÂdÖ 'åÉ¿OÔA9ºÛÇËy\2Vìu9MÈThRµ ÈWzÓl§ßð3RÄMR€U•‡kмß|<÷wïýç?ÕeÜJ“œÞàxöªvéòM„‚™²&ë+{¦…Iáæ%¼Œ÷" ›R ÿ[=ƒ!Ä@8+Ø*C3G2ÎÜB©å” þûù>!åIáGe9…éYq»ÍrìÎ?ÐõÓr?NɼÂ:‹Œz4iØªÑ 7K[‹¿ÏJg6Ø\›@#jq<ñ™¤mTf+B‚rè»Â¬™•iiïðÚÑ7G@š Ù””²ï‹ew:%žñåCûA|Ùn^'bgÿ=0Ê„ð'¾ÆöË 9ÄÇާÚ3’qh°¦løLøgÚ¶LYxHü_æëbQV"]ól-^fÀ…rKÖ¿5 ºzï’Ÿ¶·€^rä3Áuq]ÒdZ,v»¶FïÿEÛs7¯K¼ô!MŠFPœ˜*p︾ì(×Js7è˜x‡ÑáyÁËÝC%GÔÊof-<‡Ã—nk_!+QX+Ö(áÛ“)SøsO{râ’D;PM”q@—Iθ½³Z–*_hk¢d/ÓÐ%JÕR¾3)ŒóÚÍ8²~¬9Ì“ Ž$)FÍ=Ù%ÌÉ›ŸîB¤cQwô‚õb¦áµFYv¯ž AŒÄ’€€Øz¯£›‡Ò÷Ÿ*%ùFÄép#÷L憮4w¼þæq“D`¦2 %lÛøŒ@¦åêØ!FzhUô?™ùÊPÍncYf3X°âXßÝd¬‘-×HÂÖÒ-·(/÷Tãà¨R Ñg2HB"c„fz&´ˆ=]SF½¸·í%Lý mè$°ŽºÐ&½¹^öÍÛl1<ŠËœ/Æ)Ÿl+Ýû€ª™ÉsíSf†Œ!á8¡´¿SC–á~2ÂÀîÒ’*ÊlPWÌËiý¬§z¹‹‚±û¢^*8”-IÕÁÚjß§Åðµd“!3ÎþN9Ú#|ëë„¶òº¬Ë–Ëá2R•ß#¢,\wk ýÆî8žÂô­ú`ÅÇ»³ž§ &[^ãi`ç=x{ø~.>íèõ¥Dÿ²,„Š÷dT‘"“×@ömré dê¿0®î¬V"j:‡ØÃŠž9åDÐ_I¶Áš´±ùéòãâÀ¶Þß'Uøó¬{æ…ÓÇoòÁ ŸÆÚç¶½â™yd!Îcžõ~ZQ€GÆMc“á»!É·G¸-! @LÄJ™YkZµëbͯZ4n3[ñô~™„g2ŒXC^¤rÀD˸³µLóÏæÓ½·ÒèXvT$†»•AÌÜP(ë•Zq lÉÿŸ-Œ7í£=òsKÙ;ýŒmêÐg’tÆB3<…Â9ÀéóÐ0ÕÖµa1,û«÷)é Ë|ÅÊ* Òm йÓOy)j8YÛ²7'•ÏtlÑô, Ê®Ú~(™ò e]2ŸñBî[té×s7a¶oè?†òìZ^ã*kJ(À,é4ç¸F&,’Œ}oö¬?5êç’“²Nÿ”ƒ6.Y—>š ¦oãëO,-ZQ¢Ð\øºÎP*Éߨ»t& Ã'æçCjñåÕuü—Ë®wµôŸ ÇV¸£‹ëEAÛ>ùè¯ã˜Ð¦qSáG7úñµ–ÕÙþ²JI·z2ÞÑl1#¢Çk4õ¤æBäòdÛ:’çÌçÍÑëm Jb|6/júv}…b°Fxp&‡×(9UYŽØ³ö”¢ô½l¯ˆ<„IýK¹‚zºdƒàŽ˜’y õñ”tDˆ™¾©åʉZ3LÞôd½º™;ò?äì~Yv¥>ß%Ö™®R3}4’€€·€ØZù(„95‚åÄ{µªÆ¢yø£„E‹qc㥜M3A«š›‚`k2Ûê¾ì`—¨£‡.¿þ7s &Ís?—jê ê(Á0E9g°yR´¾\ 6˜àÎÈ=l_oÂS;_Ñ] ªÇ·Á#&>' zKÙnGÞ¹Tʼnò/l“ºÕ¯ËDXäãòjR¶j^Åq¥Ž€’aŲ³šù×–ãá÷«q+CŽ\˜¿ú8sp¡=õUÜF³R<0¿oÜV1 …4 uv«a‚‰ tRŸÈ×H¬'ª Õã/1m•pæ0tÜ’b4‹N›F÷´BsYŒ‘°Ö»·?Ž'ªú ާè Rʯ…x4+•È¿™a½WÇ©8´°«ïßÛèõ° \›Hï´¿_y&•W=›×—ž´ê‹R:X ¿ŽF©|î#7}´íÓ—xeRá£×pý‹ÈG^È\à ¿Kˆ7̉ü¨u ,(F ðÐCíç¯çqL¦H—¥‡A&ñ«œC¹I,/´oo—ûVÈø5ÉOØujµ¥¹!Vù?Þµôu8K`b—xófª³FaoIÇêûÏsY4ðkòä#Ø ˆ5ûkú=àaÔ9}s …Ø!ùƒ3¿÷kvp§9G¦ªCãû:¤=³ð™Ì¯·WL(§RâQlË;8·ûéùLØIPVˆs¹Câé¶TÂ_üx´ .Ñ1 R À*ÜÜhí…1PÌ2ý–¶u¹wË>ç}¯qL-.®ÏãÞà3p¸D¿Zƒ*€iÕ(Ç®e@Rû럲4F§g ÁŸÚaGý°„þ–<4¿è‚‘€!ë¼Åš÷•pB;?5·C¯PŒÖ>ý-I\B yÊèvô1xkdQýǘFÅ’ûÎ{­–ú„Äõ¶¶O¶£ÿÎñÒ$´N-w›½Î4Ü«ŸúÔ 'A8‘f”½îåÇêMŸ·óæ\£„š‘¥1Vr4¡fêôæ kð,¹CS†ášB¤ÿ¡ÅšyšÐß ùË0ÚÑ'¦J¦þZÞt ?¬TWÖiÅWØ¡¹$O¯’€€³å¹c.ŸWRjt±C§ñ™ÅËèïØ×ƒYLþËWY¬²N¼÷}z?¿+d*þbMÐ~Å47)/’æ¨To‘B7³j{ó]¶›q‹ÂFÉ¥<>.n­ó¶.mö-[þTƒQÝ»«éIõå!+ÄÊ Ny—¡aJ +Ãa‚ƒåÙY½-(>ï_`ÿ2HO¨1CÑÂðq\rž³j’¡¶±Dv¹)nÊ«p–óV„>T×R…Ú–Ö/€ (wïT®×½WÞ’lŠˆcÈC++%jT´Dû-j€Iè: ˜érg ‡'¥»/?ÍߌÎ]üè[/6šKKåôfe ¸¤š"‚R–Ë»”Nä¦ðàþ²û'óžû”˜À£ù~«C·=AÁ¼š.&øËÏÑ*÷(bgê>!Ȉ ¾cÚ©c Zz} \]¿­‰Y½ÆÆÌ}úÛYÞ~]ŽËì˜n4¹¼räí¤\m’¯§á³ãKöËÈOÎ<k±¶–´6bèî§TÓNphÄßÙHlú>_ åÉ:ÓÿÆn¹˜(e¾¼ÑSÆË—Wns{#~!. "TÚ°âZ¤µäš+MFÛì­–kdîëw'rW'è»ý®þ<×9¥áŠÍý Ý«1°+~MGKFåUõ)Ù›{$3%«qÜxe]|£505I Pn Òºà ÷'ñÒét? <w™·Á4£®¢°=¤ñl–ÝyèLåC‘ÃF2- +^KïL03J"\ˆ >L)ȺýL¼Mšº~¼ëb†P¶9gÔsBbkð9Dìl~߀cÆNIb,Åœ¿yÐãyy¢U!ÞýÚ©¿ÜŒHœº¬­äÈ;õWØ=Ko•ôÌE.O íà¬=þ0=ràôØüË¥²ø7‰Óð»»Û1††¶ûª]½=KTVÞ‘„]jûœïç¤}ñ‰nJÏÎÉ%ù<[6HŒÜö¥ÔËÜ‘ fHœ)ÞG»YÎñ\§0Q‘ …·™.d 7óÍž¯oq:øRg—ŒÝÆ–Óƒža»'öiƒ¿œ®Õ¾Àˆé¾½ü>k4c±X‘²í7àé]þΠÌú»¤WRfãKœ<ödÓ._ÍÜT0—@š>'f%únZ^>?äôHìWD_šÊ?-’€€×!ƒ•MÂQTöBåQÕgçß5”Â…¹«9ëcÜ‘´RF¶à¼ à㉧8ÁßòSMLID+Šló)J'v y‡;Áâ]È8|=({~dÙÎÎ óSþ‘¶.=ܱ`¼kX.H´âÛtޤ°aÔœ]¿mZ{D"žµ_Ùј;od¢õ©Î/Í‰Ò þzŠ"_´¥v”‘¼aO0œ^Nº–rÄO(5±)ëÐQ¢†šju*ÅXÐG´Û¥™û’ßüi/ {éïš^:,"p­ý÷ŒˆÝ®F'ø\~±óø› ªÒRMý©™xI@ÔxcÕ?$™õŦM &îÿ£¸jÁœ)¡½äx±[ƒ=ʡ֡°! eb»º#&æKñì¯5¾(©¯IŒÙõ|GÑ;±™.˜X öÀŽâ’èu?ïL=–q!Ø’R(ˆ gðìEÿ¦|]°ôQ4`þ— =Tñ6„IQ3TvÖßp'»)[qÜx¯éÍR£¸k†D;‹ØV¸4˽g`¥ü~·‡óðÞ˜ÌÑDT4[–(Æ5aàût¬‚p& ¤ÙÐ…‡ÝŒ¢ªóD99«ê¼F±¼RÈÙ[†W¾ 6·6Ó;ƒþe5)ÿ:­=—:)3ÇÒó;ø§_.Wó_:µMÿÐØ×¹GAìpÊØ8äýØ ÇlŒ€t!ÎÏ;v©tf©GÔ–ŸØQ±ž^'K¯pçI.C•øuÞó)Qºš F¨NtCÝ<»<2ïéÿw2yŸ ÷ânÐiM)aÀgÔïHþÞÂ/ýQ'>sÕ÷<Áù-ö|AÍèíoá²Ùr \¨ú3³¬˜A›2}ÈfÐv,žéªÏ·éŸ×ð ^Á€×QÆ' “–ÜM÷Œ…S‡OX«FbЂæ%T{¤^»ë%~.7NŸö‚ÔìßS*Ö¾E2Îý9¨™4-MWì |vTšN!;ôgæ«x‘0|£/6sÌ» YΙ÷±ª·ÿ6ó(|!»Æ£Ô _o¥H1?£¼sç"bfÁá–A'%‰¸z½v\rƒ²½Î@8ÍâTÜŠ*}“tmN×çH]çHë—ÅM6Á¢µÕ­BM¿“Œð–àÑÀNÑÿ¼H1É-….òÍ$¨ÌÕ{ôCOH|’€€Î†²¥ü`¯;´Û1*P+RHçŸ`ß‚ÝÌ‚ÏÕóp…³¦]Òyì©ógçÜÏy ³ÜN¹–ƽí/ç³Úyí ƒ|!.2ifù—ü´øÙŒf$ËÈsmÆI¶Íꆣ`ŸÓ  Aj+ѧü¿šà¢}™èc~ï¥áG0å"ʲà:vÈèÿ“%i…Ú¶‡Î’d¨NÜBˆ¦xÎRùï}ˆÝ Ì/¬Å“AöÕ°BÙ*Ù´ê—ƒƒîÌ%.eD¦7§Œlñ78"Í·qÜ·hÜk·1ñX±Qü¾Ž|ŠÑøÛ2%@öƒéç0QûˆC2½ç …<%ñH00zuÜþuÆÉ1WÒÇZV†ZÛŽWV¥$5mÏïñÅC’ÙE=uR³»fÅU¹N­&Ø&)7šùÝ^L Æõè_b6YfÉã 6~–†Îk¨ÿ0ÐŽ~€LK+Øý6ס‹ûf¤ Yˆ%vŒé‡"K»· À=^Ò£1ö·Oæ¯v:¡â£BHvérÊœ`„в¤ÿI§´%øsº{Õ‰SŒ¢øR>|.Ø4€Hn ŒdäXÈßBÙ)ÀYïV¬ÖÇÝõb jPÐõÕ¾®.KB wÄAbí;­žÜÜ1Q'¼J>9d’#×’fn]Þ¿±°©×XîqìixÂl€rp^-',]¼ªÿäJ¨ªÕKkz°|n‘[óYl «Ë|kO,` Ä-h?®‘i¤2ÇÔÓÉïÿ?óæ´ýcFTºæW’%¢t}Ëù³4Ù¼ÞiŸ h@°EøêÍ6¬*–@»çéø¡•D-‚0T€Åu#6–S ߣ©ÉQ·çÔö1G¸ÕTC"g¬©)ó;q®YDà— L®ŒOZ%îuá¼öÓzìÁsNôXòïûz3dè¸[RJ’Ýl.]2ê®.±Ry1HnIùËvma¼#QÚ!ÆI½Ó·Æ2ëdš©ðø¹ÙPFFØ)Á³™ëuÈb ^»sáà»XaŒüÏfYYÿûÙ ‚5Rƒ–-»\‘ÎsbŽ"Ÿöçg)îbe0M¼ÀÛóæôúT@$ŠÍö³«Wè„åúô+eT–«åÒ9Ç0Y’YÚ å?½B¦À;½Rl“Ø[Ö¨E³á–®¸¿ÍÕ'uP‚Øù…NoË ;â]ôºÂ‘Ù¢é—Õ|Š@ŒâÜ«—örª‹Z£†ì:ûG$Ö¿ðȼ[)# ö¨ùD£•T:ªÏ!24½q‰qÓÏèmàÂEJW9ŒL{M`£1ÎÝ+¾‰Ézh•ôä_ot#/œ.Úo»'ÉpúG‡WÌ?\g0ïÉèæ‘ÒÈ`ì(µ NñÞ˜¶g° ˆùmªcÐzE]@:gªÍBMwò—Õ3•ƒ ú/÷"1•Lž7íg uD9µÌõæ*ÌLH»1•wwr“a1•)ñ+ô+‹÷_k#%p ¹f.Ì­ ±Ó’€€ÇáýÜ÷àêÙ‹xÊÈ\ž˜p`\qÖ‰²Ö,¨f¨ï«ÎddÕ#ÛÇ,P¦ zÃg>z·Ô›æÙŸt„Љ:[B_H=9Л7§á§.,>mNˆAaá%(r#Rüø¿z¥v %p/Žß¹+gNâÖ™÷hÄñðãˆÚ–#yËV‡BF,±U>Ãh; g¡&ÃÙÌÿ™—3ÒæÝÞ?¦¼q½ioPøypGuù•‘ò—0:í€×:K§Ó$å>õ¡øÂåŸüWR̆ b¡T¸•išAÛ Ry8BùÇÐüÎkÓÁ¼¢Äœ?¢ð›ä«dèWr®KÇÁÜqÕI¦Rð&º¤íѸ8¦”âhjK ¾I¹Œ½¿/Ò ä£èëS9¶žL\€Òƒ£âr&Íp ^k©®ó©HEyb߈ð9§HKµË)öðóš/a…²ZÿIáI¹aóé:7Ñ…êîû¼|ñƒMÔÖ©«Á1nžÇ>)ç¬ »:•¹î×A ïF¢ “#ùÒ`¸Ñb½_0ÑáÝЦŸCS·æ×UâZB¸!Zzã'ò£n“çñ%É0áŨ¢Dsý~y•?B#oð"ÒM¯=R'©iZp¦Èœ'F1ð¶:- &É[Cé¹øÛ‹+O nïÍÑ|­\…W,¡,µèWEÞï1\¾¦ Ðt–ÈÈb™ÿÊÇ6wÌ3Uyï¯ÎÕG,QŽpZB)y°ëR ywäàH—U£j¤ýWëHbéK4¡‡w“Êp]­ÄO1Càìe»|EÊ%X®ˆ ‡Û &.ЬÚëÆÕ*ãßI]¹v"Nvû G–ÉRº¯&ø×=µ˜>rÅÁÍ^ØÀk+¦ÕÐïú±gÚL0’€€åž O"Ôí¬¨Šðo.ŸÏßV‘ˆœ3mí)½0–E¼õE"#rÀP°ýÎç9m´iÒx®W4qM*óñ Ïé  2"q—p]W“ƒ¥ò oh8­Äô—+uamkÊ)"˜ïÞþñK#ù‹²~4²B¶(¯¨GA¢>\®Ë\Õ@ ¤ƒ3³nwõÀö7ÝÅŠÇ:*(Cí™P-úÇlN mUÀ®¯hI©ÔXÜv«)³öä;çÆòzÆ`CÒaÒó5ošú¸r·„¦"23öbÌ·ÙÆüÑîÝe˜TJc"=LœÜ&¨…kKF´Ög?kŤT&;æ¡4fçüß)¥‘ú¨oʨÆýþ]E¡úVËÌ…Ìñ!ç@kC W GQúW†:B>òd ®Z ‘טSŠñší%‘ ÕÂêsô°È9Í g c<áíþ]tÍèt;ñµÔ0Ëè—¦—qP‘“ [ê5™*“rn¬±‚mè8Šy;[^•Lw‚d­]bc$®Ò³ìóÈ’Á5[I¾ =X¹’o¹ëÛêÞûÙ1Ýÿ;Ì´æeCJktýPž2ĘT¯¾%‚Þ*¦VÎ{;8ë¬øÒÙ[±ˆƒ":f¤Ðq²Hïß½ü¯Ñ3î×A¾òÌREfzÁ¨EA6µZ•ú{Ü»Xì îÏŸ“v”K‡ìsÞ„›ä,ëøŸ2wæbs–ar¾ñK"í*a¹t2ü]Y;Ž’"ª«ÿe¬nÿÿaåà}x!ó¸9\Ë_þø¼R vü_³¹AùzË’€€­~«XÄþ:øvQ°À ÀôÀT ÑÌô8»îÁ`*N¢¾ÆË4ÿœh/qu‘(ú-Q®RX€Oyk|ʹö|ZÒ/½ ‹}¸êuëi!N9;Š:šŸ«º{ñîy(àÙ(@^!³V$&ÅúHòÝQrq+×Lj tŠŒ§¬–¾w¢pñ?Ç…hv”OE^×™YKÆÙß~„¢Ý/]ç¬Ð{‚¿H2Mu¼ëQ}ï…€HÝZ ßÁEŠØÝÌèÐÔš$Ô+]²žŠívÔßûUúkÐwÚ‘4ÕkTò.„ºQ¶ËŒ3éí+pÊìÓ¿ ÐX^3Dß(ÓCRBÝÞRh½Þxû %Ù‡Q€·[ˆ×EŸk+¸g>…æf³e¯¶ÏÌËÁc¥§1Ö°¢QŽñ6@h¾JÍV°_;êEW‘ÿóƒfÖiùÓtÖˆOðuùTmõƒ#e6·TÅ[µS½^½Ê-KR"2¾«p0þzá _Ž È®¼=Ç‘'Œ°Ù[Žf ÓC’ǃ#ç°‰go{jòLlK h=ÅÁDÇ©n9v¼$ä{ Óý´“g>{-ì5wb&¶ BÔk\¡/³é_§90õ÷žÛVc9ï„ÜI¿¥uÞcºId§k+BH³¬î8âp¼Œ I>©à©‹½8÷âÃ{³…Ú£Ø ¥ µ÷Nn®[·â±ÅÊ9>…îçº åLÖr’ñHÙñœ0 6ÄxŒÞ·VÀ – ×OéZtÕýœàÖl\ÿr϶*õ¯uG›éø:XÏ€`×>J?ª *ŸÑÇ·2ï…KÛñÊL«¾Ñw¹¨S9@ó¥¾ÀÀ12­•f!KÜ èäÞ»òìëwM>DÆ,>·Œ9LŒs #‚`Ln^–yý躉½U7ðU™D7>ÏϾ€µUcÐY1‘÷YI!8BU7(5 šŸñ„[ˆÏ‰S8?ñV«æzÆ[ñ%‚~±1e©áÀº‰5%vô\ÀËY,¶ÿsÀ,²ša>ôïçAXþg½ß9?Ò.Ö˜–¦=`ÃàÃÈŸ@åj~;5¥}¶oIK·Wó æl`“Ò:ÃÌö¯Q`¥hDÈç{IoLi{÷Fž§6–¤ 1•p»¡|ÐkÁ ¦9»š"éÉ éüÍå’€€Ìì¤?6ióÃÅÓšÁ q^ÐÑxE®=«Üö¸‘ÚŒ„Æ+İæÝ;ÕF{¥ ú¨êr&üÌh5]F+á.7rdWñ"i2áqâËÃýÅÜ-m>-+Y#hUYZðË^—8Ìò"lü°ôÆå·ááA2mjFòBœv7ðeï[š+ÔÚk¬¯5xPW#%ªÅÒH XÙШ˜h (ã\›ö²2æÑw 9fO¬UwjÄV÷Ò±»ÿºÃòbp&5JW É}%ÛJÌ›êµá2€RôÓ¬ø= ?5ÈÝe,‘|…9ök<ê¢GfÚ?ã–¦hûm.¥n,…ÕÒcÐlH’JÒ…b™ ¬1Ê""JÆŽ7Æš’Á¯lê^¡Ðœ%hÃy"`“4e-çÍÑòà $«Ý)ËDg<±5ˆ‘¶‚sqÕHX‚Æ^“Ø KLy ’¯R;ÜÉTúÂr‡ùMâ~—lNõbéÓÔJyFAÕÀg€y½ÎDð:z¥­˜²õÕ‡€Hµ*®ºàŸ¬jdûs³ë™=G,ÒGPs\ƒŽ¼ÿãP®ËD“¢ FŒg{ûšU'¼òP\÷¿^? ÖÓíÀtä×pýðÍÂoá*Á;P–ñp–\"( :¢¥Ò“j;ZALË~F'uv¢·0…\A[¾÷¨ôp„XK…eÕ¦†*ê›aš™¿ì­å,ûço’€€¤/ÔµmõÙh_YdcNG³=ŽÀ…‰›Uò}€GŽ†èæš~Eä`@Htà¥ÌA³V`Œ²U—²Õžþw ïÁyQˆ‡X?Ò›‰‡Î³ñŒÂNÛøèË‹Øl»•ŒŸvá;¼Sê¿« €´à¶y+¢Î‹AAéÃQ·÷,é5Ågr*Æ m|WÚÜ"®aSÒ·ò{–-Ñq®:ÜN‡ä|Sç‚Ïλ4›ÎÆ’Xˉ@{¶7yÛQT³Q~¼àT4de?9(þH¨…Ã.§N¶êÀ~¢®”C; t³Ä?‡ ÇÅʼnbˆi‡Â+ùžMrI6øö…K%?ÍâM÷Ù¼ø^*²zо¡ƒé-Þ圽Ÿ mU¦wNqãUGB·òмŽ\jÄ(l‚tºÛ,•ˆ•Wf•ä½îX6[’|fëùAdótâd½†GÇŸCõà¡úÈèXŸxOåȪøXùbfëjG ÇñBá\oÃõ¯i0ÀK£èÍëÁ¿qgµ˜Í½èÉòçY7£¦‰ÆìýØâmcA´œÓé(@!S¸­—>¿,%åkFØÃF:x¦YPNˆ8Þ„oaÒ¬œ¾_‹²ôxðÓPæÞCô ð„®=\•щÆö"™W€^žÚªã{2ÊhÉQÊÞU·Ç“)öÑ,EÏNý·síæ*cdÆÀÒz¬â¬>dþˆ3ÍôÁ‹×²¢oê0Õ½yǂРŒFu!m‰ £ÚZá·å]¥²],cþ™äŠ-Ú }õÅ¡($CÔa§ŽXÅå3€ÿÇa@°tF.ʈUš?Õ2kÔnÔ1m<Çk8œa~|«‰;´Î¤Æ«£ñÀ°›ÈÀÕZŠCGóxvrËEû´mé¬AðÒ ¦™-ŽàcËøÝ×~¯WX´s“Àe¡È×-ä/Ûb œJ˜¹¹»9 K|Gyj!¨JäóÉg‡å냌ü¤¾Gpµl.Ë‹¥øšówNC²½0ÖXù¶ \X0aÊEÑëiâ¶ùá:9,ù²_2ýÀ9×kí²æ¼õ‰”¹’€€ãÅ`)J”uò;™Mò«¦…˜cÜŽ”è“5ûjLæÆ—ŸÔqæ° “´^I¾å|è¸ ŒÿgÊÐpÝ*»G2K:U”ëÁީǰ¡GέŒ Ÿ$ct¹É×é¼A—(,M_•a½ ‹“ …ƽ£¸0IáïÏ¢ÐjŠ_ÛîŽÖö#›ƒûÄ7&53ÃÆôu…Ö®NGT¤jÌœ}({žÙ4–°DbHîód‚¶åW¤NÐD“Ï_ÔîcE7„9Xv¸>‹/äºþ>‡9?¹ëA- TŽˆzAa— ž|Ç)á–Çßݨh ˆ{¡â ¡6KsuFftL‰j$í<œÁeèßúNóê‹+h?±>q8Ö]Á˜«;b̰µM*½*ŸÕ_RúˆË¢Ó¬–f˼¸k70›&Ÿ·;¬ëjؘ©ŠtÅÚÈìä(ÖS1ͤ„JÒÖ³ÓTy^È”™ Çš¬†Râöº–ÌígiÞ½<àâô6#~ÌtHñ³‘Ñß0”{UtŒ±Æ]ª·&ÒïGò•ÔN:…>÷mÏ1??…Yj‹c}jX¨oÛ+êk/XAÔ æ/=z”µ`Sƒyâoç>lᬠp«âµÝÄÊt@õ©éOÒu¹_:š/mñ5𧥄æ6xŽ7 œÚ"ÑÿÁ¢-K·öã|2®¢g^ú2¼:°6ß«i\žª:ZBLxÔ„-ºŸiF_Koüo ¿/Zõa‹ ¿ï™-“wkíÛ,cý‚ÛØù¦æ~sAõ·ÓKURÆdÅ ò ¬¸6oˆÐHäe<ïe!£SQMUîöQ ¸–iElù}ä–‰s^Ý¡ÚÊI;)véW`@¼I±è :cž/Ï A¥³ÒRd_Â`äMééÂ"&C’ÈÐÚŠØb±ÊÊ¿»&©8¸¯¸ðÕ©Iç5W* –=¢ë7@s­5 «6’CÑ¿`yø }®—}™þZÏ ŸU§!‹“}œC(41]¹áþ%RÐv)z“f?°7Ud¾‰Æ—ÄúSÞ U€uz¬5 å•q~6Í,É¡Gì¤'£‘Æ’ùŸÒQÒêàçøcí\ž<ê-›nÿ^t\‹…òE Þ\K}KC’Â/µ9§*b,SÒ_”ŠT6ˆàaúwú,ŠÑ⬒€€Ù”;íãµ8ÜCÔŸ0c9©Ü?äô®^Í9‚$Ï}ËèO[Ÿ‡oIÚÞl/IîÄšGLU{!böD6€²Äsûaž:©x›fîÅò? ƒV0¾ ðA‘ ;û?üÿÄWÏ'6Úe¿Î2)ZÏä¸XÕv°L¬bJÆ/Õý?ùõè(yÐò½ ÆÆë‹¾Ü›–³DõRÞ'n®âgÐ?— #làT;r“;o…¤¼»›Ãå3?ż„L¼Z^.le“é–wigU®q€Dšåqª³èû|å"AÃCo±Åѯp»Mn«¢Ûsiœ™¤î„R°ƒ‘æ¥h^ØKÉ-¸o\‰NRù=³À’?ŒH³XaðQõã`¤-: f!¯w~°6,Q)æCÅö¤ƒ¬€>{´ŸÝRJ“œPÑ^V·¾'—•²£Téý6 :uRÒ|ó Ú`øcI„Ú$ f‚ ³`ï©Ñ¾ª·|ñ5IÖï"圑ÊýñQ/tj®78Þ_Höáßžä²½¯)ÍØ«ûÌVÜL½ŒÃï<,å2dÓüÍ+ÝûQÀa¼Øå c‡ßY(¾y¨M"]úÎ!ÂÜ£,pšOÍʦfB3AÔJ¹‹0SSA«·¯ÿý:B@N ¨šùɤ÷Û{½Ð*ÖiÐõÅoyññO!W¤%òJ2Õ ÌäN á ,%¨ \פÞyéGk6;f¤€ŽAìF"˜vh’IˆÇçØ“R¥È˜¨ÑÔ·Ö'`1Iû’÷BKOø.²dÚ'®t"<ÆÑ)p‹¦Är d5­¿Š‰ÉßÈ–6aö©3PQ&„(’÷ÿµ/b^=e×ègKëåäi«–…MŸ"‡Þ¡MróVÍ}Ðjš ÕLÉkÚ+5ÅÍÊç"Ãl}+õˆqã7@¢ŸA(§F²×?iÃ_[\†Y’þpâß‘FzÂÂGÞ\ Ì”þìÿFÐãº=á…`ËŇޱÇ3;®…ÄëÕ= ®œu½I=Ö¤ âÂÁ‘/è9Z(1üµAê~<à–? úbXŒ²ØžÊÐØe@¢Ÿ0zS%`=hyÜŸ9«Z_úió%æ :ùk¬‰+ú®’Õ7§¾Ë·ÿÜ0à|¦NÆÎ03ľÙ|JùÎçQé,Vª Pq­"Þk’€€ÐèûÙ’ç5)ЇgÔïK@À~5íE`ay‰2Š¥U‘¡ÆYø!Ÿ¨²á¶þ/ÖJ YúRœN³~(ÖNúrç>-2'Þaj ì$n¤©ÚÒ1m÷öñ )³MÓ;Ž ,c¦A…„@ <Yç9<øA-#mÙùåùtI®ƒvØ÷¨,~]•L‰ì„‹ÅÜ ÍÊgÆG-Óu‘à…¢åÇ–­¦çž!JüQýÖ#ÕÂ'vòÊÃÎüQƒAõ~ÕÈâ4ÃåÅa3‹fêÐlÙ0ÜFs)Ì3lòeÞ¸³C=Q׋Ÿ)G¹¢41û…¥¤ïºÞØ­&KD2We4`³C­Ã—Âæ´<£_ £GµçyÀ$Eó5é2 `=îâí³ž»j Ý“)ÔÉz=?ÈùC¥êu¢£q?œœÌà•'ÓR0.±aæðÇÆ8bˆ°Y¡v"Qõ½›ž×»º\@œÑÿ#ÖÖ•Yß6),ùÁðƒ7´Í;´XTÄ`ñ³ò¶:S }•Ö­‹Ñbe ßÔn9æF:•?ÁA`^¿³Ö¾ÊÖíÉ­14ÐX$âÀê`¥ UîÙ[ëñý•fGÄÓŒ7soϹÎf4*Ìì}`æ²Ö("3HL`sUUU½_1rüް¦\2X&]°B©ïF±) Ú˜õñqQ>àê©ÝŸâãXµ–ƒøÊ*áz‹W=8>ƒn ®›=á¼}2ÆDÖ§Y€2¢mó±S9ƯDq”HÈÉäÎkn¾ºü¢H?¼Dø¼yƒÌB í¨NÈ‘B‡”2¼mÒa²H€ÏÀ;öã¶bÿøªk݆_²cì‚”:Ù¹‰.–.”)8¢÷Å€åä4Rˆ%Kæ÷+S· ¾à Ë‘]ýðn“Ø>ƒ•;¢$ONÒ1Òü®¹Â¿ì+Œv)d&9Ù¡f÷D=Eel«¢éÇbü89û@èFÑZ-œó‘œBÒZÞ£x¹'ibdšºªÅ¡'{¬ÈXu I€F©¸-­ÂÁpžc †Ú-r/ØÑz)ïÉÀبJ,z–•Þ1Œ)|†ö-Ê%p«ÑN gùñ‘ÛÁþ ¬µR y81‹’[…Hæñsð:1Ù¯’Þ=eÔc]+D%yËRyª¹å:/. ôÐÿtíq'’-³”’€€ÁÎRcž  Ø±¢’Ê4\Ü ¨*(e[{t=@AЊ¾±òµ ¶ÊYœ ý7•õ¯´‹Fì4!O»ÙvÔåætjÃ\q³Ž:€šûqîŽ2ÆQ^öwÜæÎebdŠ>â%ˆäÆ>{,Ŧ<é¨„Ž ò¯ ‰j£øÚIŠJÏ‚ˆÏâÇ9x޲ ³EdÕlS5 pnzl->y;#Iú½§>è”\”àA¢"qÆëÈÏh2x-Tèý.W%.DƒçÆQsEæÐá’ñ  ³ ÿ'Ê3{ ¹ ð3°g"Õ<+Æ!ž“yã¡ß{§c0‚QúP¶iýÿhŠ#z§ä¶OnzØÁ?À°šÕz4¬J¥‰ªYޱoŒ½V„zü»åwŠ Þ–¾U×ñ¨ ÛXÄJŠ|~CYEXºÛ¶ +ˆR£çöÍUvLVŒj¸À´ Ì,ÿÞ/`– ‹æ¹‘kÓø(S$z…EžzO•Ò¡yúdŠgÉ~QÇ]7¾¡û^(0-àÕ$ÿ æT$9ÎX á fµ5BJÐëK÷k§Êµ§fð ¢£ûP©½qÚxщ×Ôzëêíœgs9ðg˜û? fÇý?»Á¦þÎVöï•?ORFió’"™ò¸s–™å(¢fïבµ;^ê_‘ù 4íÌLR’N21³¼’ õ<«%O,sTº0¼LŸaÀ€N®^´’?ÚSì~K±%¥ÒbL>¹•+üɬéŸ$…zêø§ù“‘ ßIѳ(ªâã2°‚¯,š ð¹÷¬½l_fêδ<ñQg”èÁsnŠàj§õÅD@1Ç7ÑvÎŤœˆ¬nÙ0 ¤ù­ ÕMsÞ%YQˆyÊŒ6Z™¼Î°ëÑYH‘p¶fà(á!ˆZãÉˉx7»šßÙßWŸ£êÏBc ‡÷›:{­å×/¿£œ64Om³x3iûH¢o¾mñáu±E„³ácm°Ø|y4Õ3¿ A0”º¯€Ð HQt[¾¸`xÍ–«4ŒŒWrpl&v6òß]‹ ÂAu‘ôþCm9Qt¼Â2)ÿìDHË0]^Eçvf;~€xœLÈ®¯ÉÀ)¤X ýÈ%îpmÏ _ùœ &Š%Ì:\û'w‡ÀÝ çÓ;ºaÏÖߨNi’€€£2Æ'»«B½䮕É5Ôù¾ÕÍ~ˆÔ\®×óÝï3`÷hîIú°d¨§¬~æBÖ¾ rÐ$¯)ÿ/&ÀB› ¼6\Ÿ\ƒ1G˜Žþsõñùfÿ=YˆÄP1º½‡ú%S’H?:øGš¢ô5?Ý­Hþ!~ ¹crǦM/“ËÀØ×^ [~/SʦŸÊÁÙ¥Œ7Õ8MÛ¼® ߈"Šö¡ë¢Ò[~ÞøR­Ò;÷ z/P d†W(ZÒ«ŽqXŸPâ‡ë)%à ªj܇15'X'+R>ÇÏ’sWó¤ò©Í/k0àO„û¥%ïÀ¥¾S»€Œp§1‡ºçx¢‹¢²êø´}&(>aˆ• €0ƒ†‚à DZ‡ !ýd“õêŸÁü®±W¾ÏÚeAQ•*0Ê ƒ‘ÌþÁ›þ臘[ò„ &ÿŽ¡W¬$W:MçÒ+6Ž#$‡8ûs³2ŒáV m$Þe’½`F"^,’§•Öm¨O 펾:™•`´K¦9–h)šÂ›(¾?ÏHñÁ[iô¨^ÛælHHß TàS‘.’PTá­·•–ßEê‡%ŽŽLBÃ]–NÏ. ¬[!ÛI´›ŸßÞ *o¦=¨«?à~k·O7Êû;Yç[˜åv–M+\‚ÂY™sÀ!€¯‘QÍ‹«"¯Øl`T!\°ÿ̇¶ˆÊŒ3yjÙý ”¶Sű3Vñp×›}Þz³cPï[]¹éTY;Ñö#?ÿ,+DÓ¡@ª‡AÿdEÈõV7òìHêÆ;ò  ¼´*0(ñ:{’lXb@ºûC Ææê³¤ýsTAÍËA-—ŽJgÕÑÇ–p(® Ça¡wÛ֑݈¦Ž(«³CìyT«? #ó8GÎ:§|€¤ç^â½}É“8Y.% ®Õþ¹ä„›¦Úÿø·½ãr6Çu!²åáL³øðBÕ˜Ãh~·¾îÚ]c[—»Ö-ÉÄ F&T¤C\Þy°¹ªÌãq¹g@Tm[hHþÆd \3×Ë}½»K£‹;+}Ñ]N°Å TÃ»Ž¹Sn;8.Ÿƒ ¶ÙAÇQ*û hñH³ß@üþ²tϵ.’òÇyÿ­H]#¨ýð뀢&ßÔhA/–ß•¢ÓB¯ó»ÔQ¹È-œsä|6,µq‹Ïk-¹ÁÑ¿·AÏ|{*ZÃâòØF]£ÂBÞÑ)› ˆ¤ðqUŠvŠцË?Ûä2™´÷ï½Ñ ½”òQôÁ>œy‰ íßdî¸]Û{å8äÈEà–…»uÏ@«^?XÜHPýëv ‰ÃËeàthèožbáïôÌSÒL:ºV=’f¼¼›Ç®ÀôEÌ5Ÿ8kj2tÒØ^;ƒuaXΤl}[,д&þOò¤¥gÍ©õ†'¥ãûýpx~Ÿº«‘æ’#ôüY0ÆjÝ(¢INR’ÓZèÊhúenZÄkz?˜ENÍûŠôtøÁÍAòC¨“©Ôÿöç>È€÷ÿÓrœ9 2dïYQÁ5‘¦e°7®LÿÍÿ<«Éú…kÿŒ€h§~àŠÜ,°¯»c‡ƒw4Ë׿½ ©ý/SŠJÖM>– ^€X‹ÅÝéβLÞü/E§/gšùÂmÆ?}Øoâ€à. ³-С=§»t!/g"uÞ MùÅÕýÖ‹ÏÝÃѨ‡¨LÚ6IJ²àeçŒU:5ïh”)o²»BšzŒ]Ó4“éç I›ÆLª-:¼4ÊÐWSvEÌ4œÝÍ5P ’¦Y”ò"Ä Ý8ù·—5ɽ àó€tm}‘ÛÈt‡"_i*íz¡g¾’€€Ó2ç©KSË1ïx+Jð¢)a eJaE{p¡kO/Ó…Jy¸qb¤Òr¥O~år‡Þ`¼±–ý¬Øl”lÆ­'o!Üg~MnóÁþêw›¡ F Y'Ç8ë§öI‰·Ý8ƒ¡½Ýl/Ó‹²ò»&È `ý³žÇ+Xôå=´!sÖc‘" ødvÓ6!“÷žØŸ*Hràà"Ú»X§Q-–ñmµ 5tnM†¸Ü>Õq5Tâ‚oÓ ÐžÜ4­‘! ýZéÂ/ØÞu¹œ‹G±‡í.:£¢G²}2Oós¥ï(è‹öR(%¬P`. 6˜kaÄZÝZé1÷ã0”¦Nµ¦©$½Äl?ïýtФ±Í»¢sä@*Øš= &”«ZeR×6KÀBy‚ýO…“¾€aKôW%ÇÑèìô"îÛ “:‘HÓŒ¡w–sÀ];èï´Iá :{=½5‡Ø#âs­· üò­„¹7êE32e|l_Àx мcÈë7ú} àL_ÛüXÛ³Ôp]ÉFÙçÍ#µƒ¿h ÇeW´3l“aC}÷Y—Ÿâg¾¬vÄæÛ¯K6›MF6pçŒCÑABÒ“©²EÖ,©á ïu„¯roצú›k{ ¬ÝÞLÁ<-³RÅ-ÁWá·VôE¯õ™éj¡$œümmE9ª'>&I†è/±BYaeOCe™´!š`Ê 1q¨giƒô•^©:¡Äy ×ä&.ùƒ£˜eu(ÜJ´hbÓ2ì 0àç;|c¥NìÊŸËð%o=Šì™0]:øX×tC¯àîðC–§ßœÚàBŒU¸]èþ'Í0~áì¬â«½W—»SnkÔRå‘ íêÌⵦ]¿x¯'X‚ÍšäóëTL4˵AV0š?Îãc³AÔ-ðôé¸f—UQ˜²“È:,ð^Ç_ëbu¬tŽL²ƒ‰ \ûÌÍ„™du53þKÑI7>BŸkCõ%:*^K?ÓLÀÁõòGÏP*ïÕ—a_·ÚVom6²³rÃ>¹²kÇO‹°UUã”ãüž§ŠvVæÈ :uø–‰ÌÍ®è(f B ‰·ŠwÚY°ÇÃ9‘ú¡¨À˜[;,蜞TûjñÃØ)}«ˆÂÍ5¬EEƒ73ãÐobÄ,ÿâ˨ö•8°’€€µ|öÌ·¸Þ¸Q”~&~õzoWS~ÞŒ J{u´ʘ hS¿Î9kPšÂGÁÖÞRɪ'Þdq)ŠåñmJ0÷é>#Cb§_‚5U¤øä4}Ä.04úµl@]á½ÝX¨\_ H l1G)]Ê—«C¤Å%Ìv"Ú°±Z>ÎúÇ üs@h_¹÷­8îaã…e™àÆ}-Úd!‹í—éL!ì¸YøkwîuÄ₪‰V-$Ë"gÆ‹ÛýÕM¾[x`ÂêLIVšp¯Ä÷ЫbPÛÆ!•Ù‰Þ9 [yÊ‘÷W²Ðüî\uÕöH•ÈWâXFÓ˜÷T½†<˜Q©m¶.̯³ Î7u ÄÊå›x¤Á-åK…Ž÷ö|‡°LF¿Ùz‹Ê¼)¿ïØ é9÷;i[›”È ÓÐL ÁÎŒŒšé~> ÷uk¦Ût›5î;Ï„Z2CÐ÷]x¨qbâ¤ç;È\µüŰDÔ)«Ò¼p’¿q<¼`ÑE7Ú(!èø¾Î*¢òr/µ$½®[±;¸Ñ³MÖ¸hQóŒ¥W=®Ž­KEo`¡Ýð&PÎ'çIU£KÕdúj—” ÚDjHy‚Ûrûh7›êÅÔÊ¢ô‡Ýœ½¡;ù—Ï9$ñ82à$Úˆ­ÖW1Q$ ‰ {c¡JÛØ¼C=ñE,)Èk½"1‘ûw®'SÝ®j1Ý uÅiã`*M†F¾|seÆîõ…âéZ,§â ýÃЭŒ¥Âè›SÕ-~7˜ìšŸÌÈ¥°jž»$¤«H[{õ`‘œÜè§MD@pl‘Vº\êšëó7:¯#ƒ$ƒe‘ÖÃöWsúÁ]Œ@ÿ3_¶‚âŸ?иNJðæ Ò/›{±ä ~éEØ|±n·E#+91>‡Xä Qà‹ôxP•†¦ð>K§ŒZñzq ÏÈõØ¢aKhh¹·=*™Š-ŒbSŒ‰6)º‘µ@Ó³ÒD¶f¢þšÒÛü –ña‡ zë˜p»Xh0‰ŒëgYe /9ÓÁ÷Šëú[üæ  vfÔ!a&C×K$¯&暸50×Mžà³òxÍ0Žt™¾i~ÏiÍÄ´Aô‹‚ï!äYò©LÇš¢­F´ñ/'î’iÅ §ÓQ2™†ûd”!]ôéÊ|+è¸Ýï‘ >W¦ÎE[éP'Ø•h¹’€€µÙp¥Ý®S?†&m©\M€‡ª)‡(›d,d^$åh7i„^[ÂU—)ŠÈidŽ ]Ô°ÝÛ+EÛÈ¡kÆç±’†øÍ zËvÙÌŠ^Ÿëå\NÉÀã‡9нf$ß‹V;~ª-ïLûèâWê XQHóøÞ}q :# š+1îõ›%t ïã1‘²51 ñM‘bÔ‡Ó>Þw¿‹ŽözAB1Òô@˜Á¤8ÿT|RPĸúÀîg“: çnKíʉ›«ºæ/âpª.•ÉéÓª\ø2¿±6ǹH‹Šµ¯Ï8q|îújö?Qº•¸ÝPl†pÄuá‘ aõŸBY›Oav5kû†IF!­& ~Ú.­ÁÃ굡ꈽ Í”À•Å7{³DðoF£FÃSÖ¢sÒ³ƒ…M;Üù©Ú_¢b Û ’Q*K#h†»§#ŒºçŒ8¹ÁÃ|ŸfþŒ—D~¹¢~túw`¨âÞ¿nÆÌmÅ4my‹µÔÁDÕ­éÂÀ}3F2…Çî µéîú d@@zð–ûCz3Æ‹±Œ‰Ÿq – åÛkà n§ø]E^¦é© Ëø–°ìų‘ˆÓÎjGzþ<ŠÁÀ„xt@ÝND·iù-õÍópµÜ´ëX'õ§é :À±{æ4(¹\ž‘¼&14°‹ºçK±ž«ªñ½ÁÙHs@-ÂÌÎï­‡Nœlw él˜¾VkÏÇI$E¶¦R¤+¦(YUóÔ‚Ý$&vOB<÷òþçv±Ð›¹Å2&õ†:ß5 hRÒð –\¯6¥G™V`ä+ ¿™£ØC5óAy>„êÙj¯†„.R*:BnÉD§ÎÑÈ*áuJe˜FA~TV|éâmS?%H|~Ü9¦õ?Σ›BŽæ6^T R´†ßfp[8_ìûÝÛbwÓ¿Uqeu{\=êWŸJ_½)Äõ÷˜\Ë øð,§ ï.K³Ó½ ÊŸïí· °_`ÖNH–[Îež^ Fe+ݧ<ܸ\’€€Ìî¤õQÇö‚åN1íkçlC}$ðH,cöü= Î|^QÞû‘ÒüW,m²û@Â:žh9U»Qbkˆ™xk­ÛiªÔ~§ál>ÇŠPws í”[‡í’Zö¨†[#0a;™ö)w-µ‘äù„úAM›’Ûi Œc»³ ¶d§£¢b€Ö#e„a¨rºU ÃrxLÄ~ vÏ¢tÕà—Ž”NŸªk9nV[õ‘]­švÉ #ê:›¨ûwÝà¯Ëa¸­ø~ Lµgš-†â^Žýe ÛVàµhô¯qKã(¯®(1—à ‹lå;dWÔÿå–›Kë¼vJÊá„ YÓ²ÿþ}†›§‘³­*DÍâ¾oó_I'D'åR6ÛÉ¡fæ¡'­T­Ðjyk.„Ê¿ÍJ¿Az¿4B$õŒbtJb¸ã¬f3"Ó‡ÏJ¸eóÁÈ$¯ ŒÀð a´®(=çõFÎ Kd<ÇÝÊ\»u+uˆÞ¶cIg÷duöªÒ£8Fʨ/NÅ“þoL¥KöTû«ѤÙñBòb.L”Ü»¾ÎüK…*´æoBAƒ,IÊÑÈ´¹«Ó&Îû½œ¥^Û ã¿EΊ,ƒIÈýYž·vPÖ Rÿ@ëK…c5eTù4Ü™ d›7ý—裙”é—΄=÷ Qî4KÃÖ p—nz_»€QWâÈÃ°Š¨DÍd6JúÝTøÐDŒ×kEÑûq%Jûï¡{c1f˜}&ëÅê)œy(bX4IPB„Î*'¯j£ßP10ýfˆ7ò¶Ü^Õ~–"ëg§›¼²ŒNГ†[á‚Ê]™®þFKŠdŒˆÁâ³Ø[U'à!½_ñøäžoÓ2}…Î^å.m/0l©(­ýn iGK>Aˆ®wM ɳ(GRÛ?ÞUÞ6‰á(r/i mTÅæ£C¿²øæ Äo€¸¦%«Eû3ŒÚ—ÚΖ߀ÇLjÏésæŠæ¿w4[*Z)cŸ læ­(†ã÷BQå†6çœ9x¯( 1P—•’&¼àjeê.åW~3¯àû/‡ãL¦ùùt™µ‚Õôë1Ö²4åXžz¿ß]7îPIØÇ™H /üõø@5ŽgFYzXŒñÜq¨ÊËÅÚ@wMkÁ§ÅNqã„l’€€ÔÈŽWKUÕžI8¤bÚc“¥xÀ\¨Ò²¯R¾ÇG[Κ¤Ã7m À@ŠƒYbSçó5‘ 5ÛžÓ#ØßOà30rRýlźg*áOêºÞÔXÌ´ÆÜué”Âñ‘«‡7,U •­)|„ÓÃy™ÊEá×¾±­vÇ…¹#²Ÿa·FXÛ>tˆ~º<  ZŸæq2§ð>@Nt½}EŠ_/CÓ*tµŠ¨¶Ù;3ಉÍ̱RKÞ¾IâáX©`r¢~—Ž5)}V1LCx¸zQj0¸]š“b^„ð @x¼ÆY*;xò¦n½±O{Cª*=gÙVŠ×s÷éÁM’‹ÌJ›öÀÅ<âÎUV·`Á‹þ3}Zq00t¯J‡ã¹gRQ<àÜËl} 8ïÜZö#g º· `Ö•@Ž)aÏzÒ“NöÅÂÁì#{5kÁ[Œ#P†lÊmö6  ˆªr[{è—½â<µcmÌAßÿzÈkâO™,´ƒòå1F¾ö¢ŽÆNáݹínæ‘á] á=:ßHÃk…Q]½)5Èó–Þâ:é»ZX…à¹f6½ãðv¥²lsÀ'e7äwuY8˜ž‘—°6h½[ÎDfLZbúÃmFß§.ÝÒg/$q4ŠB9p™ðJã A·iñêéBUÖ.ÆéqÖq v J¡çý¨1Íëz ÁÒ0Ù™µJ¸5o+ë0Q¹¾2uMó¾V?G÷·oG݉¡ì¶WÝèSÉËN±I[­À”—È Íu £D–A±ž×5Þè{`]¨hGQÁK Ámâ±S9à¦M‹”qѶ¬«ÃsqNÝÿ¤™w?/[Ûù7v»{õ3Êu³e“óO êÙp¬É^(˜l‡ƒ<Ø ûd›`"å†ÃQ2Ò¼KŽÖk·{ëÅiP9ØzL•¸cè%öã7k3À“á¤i&~VœÏâì<â©|:æìd¢»íÉ!Ñõ–ËÖìŸÞ6Y3tôhbk6®ýW„ª7¹óF*Ž‹DóªêÑãÓˆñºf¼Î7|Ò6Óòæ|›ÔÏ/Dz7þ:¿63ŽU¸Æn ¯¬‘ïž¶: gß ïœ:´H6‡t€¶m }pqi0ýWöä=””ˆ9ëGA#Íœ€’€€òRÆíèDUU4þ³¦q£»&Óå.Ûìùá1ò¶…±ü]vm=ø®va)hHmvXJøLP¼ÑŽ=ØVA=d|÷fjw´ÓóK Tõ_^ô^Ðb5/1îÀMιön±•[Ì½Ä xibå õ” °´aê7µ|_S¡+†ýÌf[äc¥èöêŠC×¹(al|¥Òu7˜¨Û³ùHu UVH¼F :qjÇ/Ì{inµ%Q„(­ªñö=éžÑõëåuâÓd”lðþl p*'ö@fÀuàa:±ßDé`u8CE¥}7RiP¼ ¯È†„NB:ÉÌ¿£'S8Qš>ªÞÌ¢*¤v·[‘¤ØüåŽÏ¥„}WXJtȶÉ¥^HJÂòWÕ+¬«ª?)ẏðÚ²9œ“ªætä •´Ï¯˜Íeˆ"}ÏÓæ½“.dÐ7t|( Úx*‡E:Žû¥ùë\©œúþ™úÛgÀ1¯gj§×.Þ`•PÐú bôU=û¼Š<ÃÃÿ‚`>ÒãæKáQÂM€deüë*nH¶ª2ä³—&-Ò}h”}9·A•mHf"Üɉ UÙ¯5—¬~<Ë`¼#|,Fx¾\þ•«¿Òù\,ÙŠr”Û•&Â×Ú‘.üE)Uÿ ¡ŒÐÊ!àcÝØ*zƒ;ëÁýÜâƒh&¹ŽP²DR{™®3Š}T±jpWØ¢I+ Ì ™L7øA]3¾ÇÇ¥–(AÆi*ûÙ‡2en„„Œ¿ÖV‰¼jVv'»·ˆãt2¬ùÞ<Ô×&·ç?(ÌVZŠNˆ7‚㦾bÑéã&V~,×W43ÜÊ8G‹ZÍÔR›ô]ÖÚ˜-È:>Õ±icžÊ©Ű"ØÝTUC®ª¶k‘̸rúœ:‰u~ý)ÓTü¼¬’d†‚ö;˜þw²Œ a¬Ë„®¢J\„2ƒï(€;zjYtŒ9}¡ûä¢qLXÐyºÙ /€ç[8]ð†H04ÀH»P^Ô³™)~@¬Íè?%˜–•0ü­¹ÚqÛNìXµe]n kòûÿ›"˜éL"¤R¦Žn¦Hòž ¦g´ž±¼©Sã€mu£ˆÛo€O0iù5:`u»žC+Xýg~¡`QçèTzsÏŒu òù]_DÕ¨èÜA·í¡aXMg™6’€€ØMF£{õÚFqç¾g¢¾Ý–8é£oÕËî_„S7œF} ”•ƒºû ¤Í€Èƒ¶×ó€ÓüŠà_ŠðºEöU1ØÂbÂÏn‚ß›l~íf^ÇÂOàbæŸ)ÍÙPNWxÍcXÙþqs D¥xÒé=82I ;+\ŠŸò‘x{CΊ~ÝÇDÜèF?È;*\ 4™‡«|ö¼ÚÓ4¹†ªKÅ]߉ÁÎ;ïÔr¥>ØwjK)¬Æ‹åù8Ì–Ü¡';-•fHjÛßN @u°›„–»QÿèàÄtÏüKë½ ·<^ ÙÀ˜¯[ÃÆÇ;‹ßÉ#;S^C‹\*~t]wëaõ>B¯ ÜÉ·6Råde~éj׿ïÅ»F#~OƘP±îiæÁš¶("*—’:ŽÂ«˜-¶ëþò²ˆ7õÓne™Ýª2qç}…l¾`”QPùý%!#¶%QkÃŽ@­J×@Éþ—h‹ØVShÚ£Uû½ ^_xe‘‚vCÉ7†"¹ÅX—%Œî“÷ßÎ9a0Ûɸßÿ&ø¥ñØ;*¼ÿÛÇîh«Âòž+#M¦‚â\`3¥ð±` >¿õm3CZÊgñŸÊU‘æˆ £”¿…Ëš!aÝfQ ¦žÕíô@}š'·ËNN¸yî­üŸªX“Êa uGíU}b”wwûšìÛæH´˜äñäÙ™¡ÇË—¸~r\ùÇèöÔ¬<ù¦©9,Y°¶ 0¤¶À1è€;¡qtÛBUC’€€Ü?çzÅÛQÈ勲çðXE¶+o¯ ˜¡Ä¾ ùÃ:†éµ*vÒ÷Ĥփ_u¤Jqéëh¨"_üš@jß#¸ÂÞ?ÛÕcúdæÆ‘ú[‰õ|&x/_€±/?&Èî(”c+òí&A¿®V”ÚýÎUÇò®…&š6R˾ÜdFÀÆPYÅábÅpûØ]ܹ cV[‘r‰TYÊÚÖr˰òz-üãÎ[ÐÇ’Ö5íÞ`ðöÍsÈÛ©ðè–·Sf`#„Å­4Xðƒ"óµ°«R¡ûeÿ ëŠèP–(ÍxŠt&ÕWÑÍužG¤Ò¿¥IÆp´ãùU<ñ¶8­C²Ó>!»¯Þf¡ú®¶KÄfIG¸ <¸6™ž7à7’_—¼ÉÜÊ`ÏÞáS5•ÿ,Q¨{"™•t;@ð­& ç.“[tôž¼×]4ÐØ ünÔY‡Ú¡F,Qß«K¦¥ƒÑÌûÒ¢âE¿!Í}¢—ÔàŽD.…b’…ñÈîŠèÌ¥ÕòOÆZËo,² øUÓr “̉‹Þú¸hùV呇ãÂ9P¦¿WAΕ¶?Ê+‚šðÔ^~‰©çи~ÑR2¯aØó%›"®¶åÂOK.DP›Spð®ßHâ ÓFÕÚèâç÷¸r§ µÁ^ÌhƒO^‚´€û5ïú‘‹PÌôaØã}éýË–¹º 6¦Ë, ^çlÈP¾pqÒŒOwuL0ï1q]«uñ˜€óë;¯ŽTI•V5½\Nl·{h¬©dôoøÌD¹•SnøÉD v¾Í\‚5Æ*Fáô‡,pÉ=}‡¡…°Ä0ëì%«ÐµàrÿLÍRâþÕ ñ=ØžÎkiéæÇÊÜ Mb^‰E»ï'‚¨φ ‘Ê»@H´ /úSL·'ç4_×xyêb¡ºÝ*$ÏЛ8/¼Éo ¶6 îg*Séú}Ãú¢Ô‡5áêK؇ҽ¬Ô;%²ò§#ßÏcë4gïørw³a dCaÄÜ ærá”V$;HŽíW¢-UI`W{Mq~Zô¹nÀc:—Oþ15.—m lµ³s[yÝNAº1ÿÑ“9 wø»+ßÃërŽÆ‚ŦþˆIw9³Bí¬I×!ô¡˜Yä籡å™m@ǘ ­9•¬’€€¼ÍµÂ[gŠyï϶ûñùJkH6œT°Ñ<°Gºr4ÎÑÑ<¯ƒÞ‚f– À4¨õ²|›šd²GÜþ¬ªB‘D8‹°Ð_§ÊÈÆ^šñ“•CU`ùkËè6Ñ—ªz>˜ªØ¡È˜Xñ'Ho²à;ÇïÛÊŠÐáëþ´kÿ‡Fög7_çç(%ÌEÇÙŒt ð×[‡MêÐkÒ™±‹SoÙãÄ€Œà3¬Tý꺒kCMP¢³†Å£ÙÄáVæLÀf!Ýñ˜Y®£•Evéû•=h®ŽÑúÉ¡Øi)F’a¨¬°ÛïΤ”¿}|SW.1"úx+ТWæùÆ"ß©]ûŽ6|ª~HçáÜÀ.VXÿœ¾Ôÿe¥Â“Å{|uUàeú{EHÆP‡+—£·1e‡»Ì…ÇpÊʇH¼¸ 5©i½™ €³ZKØ”ŠH>V&‰±åe š‚±´Ñ×O׬‰‚\à ?w`x¦<Ãù§~X3BdCá\uÃßEž•ùñ¹* 1ë2ˆ1n­á´…êfžôƒô돂µ°R ¦Ã•>ƒ<à[s[jBçnEùs€=]G¨"Z+0p1¡fvlãªp±ž‹¼¢“Ë•[œq¸ÜªÂÞA‚È IŸ?€É? ^Õ9 ê/ØÙgó²þA /fêf­(ŽÒ]‰TÛŽä[`Â2ÖÖâµ óLe›[*ƒê$l)ÉZÆÌþBZêBåÛ*U0< ïGaa[V\1°ÅÐûËÛ­Ÿüé>¶Ã<Ù^¿aG¿Qm•Ü꫆檕ךü‹\?ÌŸ®H¨ÏJé³Oö Ñ·Îc´:ÙŠQ·¿J!°‹¡GâdŸqHº¾eBCú-a÷à¢ê¿!ñÜáBÓSÕ9…É@xp‹IRÞɼѨ!’·4@Ã;?g!o[Œ5" 2Ïì> ³lÃúòñg_"v$×·á}Þn¢•ÝÇËNuÊb캞7LÏš"½Œq‰×õ-ã9&áµæ+áì„ ¤¦Î9ÚE‚z$+” ç¸æ…:'®›l£ó»XÚ:œŠzJ^š¤ÅÚ`ÇÕz²í_ÅÖ ‚£¾³äbÊý¹ñ™ _qä wïéÎÌ¢ á=~(‹Ò¡àç¤Ó®:ëï‘R|D3’€€  Ú$Õ2CÚ› -ëw»ÎþgŠR°Ob•àÞÜEâPŽPá ´þ+MÉ x ÁÙ™ äIÌØspS2FUz}j?2ZnCpï`Ë¢|ªP¯ÝøÌ§  ðß[9' o· ~¡vS2‡r%ùƒåÌCwzg….øS\M7Ý=ñõ¬®Ì­¥{ÿ»?ºTÔ¨DT+¦Mœ÷Ó{ò‹àw‚ƒ©cPٟĬD0I7M[pï(o; 0p_ŒT …¼ŠLSÁØꚃ²¦£˜Ñw=´fVyJhE©¨ØÌþ^Æ–ußOlyܵ(ÉéZa-xým‰ŸÚAï=§³;6¶#ô ]e—=AGĉ‰ çÚw$C–Øçš×Ï¡œp¤@fªŒôàw ïä+¹‰¸ !Eÿgƒ°š8S̵æ ù‚?¶6ûGCSõ3|{ggëDrŽ¿Õqé¿;=ë@ž|ËðÁñÆ–ô2!gM/8ÀæVå×ö¸* _NL ÊØE–lfCð4÷~ lÚ)M²“Ræ8Û4Õ[,#v;ͳNFçPò©(Z/Ë}Ò†õ£ô!¥ýì2Œ|`°ôƒX_P÷g–o]§}×¹2%t^D¿¶7pk ”À¤ü7G]kq4Cv=V5|@“Ç„ ëK@©”@ÁÐÈXs¢ÉÔ?‹½ÄËÓ™Fœ=¥ÓöÿUטÝý5þ¬A™©ÍRGxßÂ<ÌñfrÏ¡Ø"³ôòj•£’øÞ»kS) Øzþý0„4lM¬ÑÕ!µYê™Vš+«òÃÁV–^oXa8åçÐ1bU•.y¸j䀛ӷP´#Ûû Žª5ŠÄ\'5¾(Z\a›Ó~Ö_×ДY¬.â©4xiT~£™øäaqëMŸ—ò“¼Ye%«“¼ðؘšÎ'uÛÇfÑi½I«L!Îo„–ñ1£ÑóNLœ(ÄhA¦À£`_MŒWnÚ¦qÆdD˜;5è´Âö­©¤ó&™œE¯ŠÁTzyi8yNÁòaÛÝ0^-Âròú š‘Û"-užf)‘ö­¤÷;üº£Ó ^Úd±ÍñôäÄTÜWxNÜýŸÁ-^›Á`£×‰|ÝUÛÍoât¡¨¸+²ÞÜÛ½å±M§ÊƒÜf€VTwZŽ1Â$’€€áO°ù„¯¿ëUÅy+`ìþüí‚€*Ÿn‰üxhÖ‚Wýjh 6æ†z5ÁTƒOVø§£j3 6=ðõ†´(»-ºÛßxö‰1pªÉMã‘®;X¬»2#­)÷:¦L ÉÖ0Áú= .w¥¹Î(õÚG½¨7vÕØ özHí@§~+ÍͯPž œ˜·I\„ eHFs´ù×’4–ê{Ù¥'™ÅzÚE|±9ǹåõ¡ ÎW2€ÃÏûAÆÔÒßìÈVÐÿÐË>Ëù] ØËÞÚ…dÒ‹]ÿ7ÉÓÅD_µåÕÈBœ½×"z•ö |ü&ýBÑòEÇØ¹ë–°µ½f"¡h$½=˜ÿ9/.uǰ-º‹~›zhê{»TP„°í{±<ÞDŽ]ütEžþxòÎÌGàiQ7G!¢…6–f"ùV1a§gÊZFêpàŸ&‘íýt`©¢N³'s¼”§™XÀAî¾Üôå*6‘í·»/Þs0±$M¿~:—N®ÿL;® OŽ;€fŸÿñÃZW<_•/2QÒÓþÊÆÜHJÞˆ\Ä@v–Ô28tïR«Û¶€#bô!ëÇ:u»\èD arZU(¶:"´¢õ·+Äž|ÓSú?óvd󼔂<|ò,™Ë+žw9ò¨5Ú×ù«bâòlsÏŸö:J¤5ntõ;š]Žð˜Øû×Â[uy€Þ”Ó5SR©>îöÒ¤84J¨+qÌô8TÌ4Q<òjà·«¯Ezõ8hÅ èò¾,•í GmÐú†åƒÔ‹î-³Ìª$µËPP|ä!Þ¹b†Rm—(·Q+ Ná^¯ä¦ÞŸµhL7ê@âÕrÈrLÂ;n‚·VDä&ùÙU'{d¥×¿–Œ6ÖPœ¥†j°©w¡QRé,~¡\{-ž\ù­‰#`èlÚõeŠJY‹ªöåŠ,» -¦·é§úá—ó ”ÿ Ödz‚pz=¤×q韮'ñ)¶‘¸ ¾3E-s±¾«ÎM–Ì_ÑÊgþõ9}¨¤q!>‡Ö;wi mV©!ø³¯§N-eðÓ3µŸéág‹û)¾è8NïVÇœsU‡eåXek>âm8ÜÕ×$&Xç>­ëŽû ƒXM,Êĵù»ÇÜN ¿ªKËÿôÑ!´X[6²Ag×2`‘ƒ5„ýÌR¦úx’€€õ]è±ר]ÖW8—~”„yƒÌu A Šw¯T,†·f¥P-oÇ@ëW;–ÒrT}O›‘Å)Ë'¬ÎJŸà•ãåÄ™ï\1ìÒøÝ'2fä²’1²`È~BZ¨9 ˆzc% 6à{ÿñ´IË•0îîß0b_‰y³_ž 0K5jè=–ÀÉZõ"\ß³7!K)^­pj~å]š¶à¸©Ì7uûñ3Ö&àԚ🯠ÙÀÃë ¾:RÖßÏ^=-ž+FoŠ/‹ùÓ¶[™>S%˜¾P¡xª÷gÝÀMš6#ÖŽÃÉŒ‹JmHð<•€ G*h 2u&ްìÚí¬Œ˜]¡¨HàÈr¨œÇ•íèÇŠ¹%ôx ñ¼aD418œûï§DíôÞh¾GΟŸ{vLÙ'ô @—¶Æ›tÚ†¢ÅŽhS­–ûòŒ™õ}ÑÍKÏŒ» fÈJx8-è×ûª “ É{øÑ·öç>¶j%…6ϰMì1?‘ÿ³rGµq%FA€ér‰¢óB^0¦À>µ Ù+8”ÿ•LG/s(ëÚÕuÿ<ÔÓ\EÓºâ*œEYÈYõ¯ÇæJç`®©Ëï¤ 8.ʉ‘rRÀ†¨ ‹˜QÄD˜TŒs|ÉmdrÙlj¤ÞŠš8`<[üŸ—C8èÜn¡ïõ§^_ ÂŒt´Åí—àÔrŸBR™ËÖ¦¨™!«ÞÝ~\⟲癖dÏià'†eÏ*uŒÚâ›Ì+yRð•w¬¤}7²Á)^!ÊNFB®ähpt yUÿœ)¤!,Ê=qeãà¿áݨPWrËDN;P,fÎýúÏ^|^cËMzÍÊFc{ÛL˜í™µógL€ülÜÌïŸÅ#íç b–dŒã’€€ÇæKƒÌÇB6I¸#{2‡„½4Ú·4¦QŠˆ†6r$Bšf¸Ÿ…JÅJ•Þ@Œ7ý Í5†œÐOTˆ³}ö2üÔ)ù[Çá cYW›GÛ§=õC_»ØcÛ×HîýöÒP+Ù4‘Ê *Õ|×I‘ŠŒ Ùø)œM­‡Øiº¹B º*÷FÈÇÃÔáø3_ÔæF>/—ãôµ¼j+G>»—ncÑV# wHò/[HJ'È;+Ç ‚•%¦ãþº0‰êAØÞ<×;yºàß‘óû¤Ê{ˆ¹/vÙ#'ði4&»³³˜Ö¾uÊ¥ó]ƒ0J5<¨ß1'Þt*¥iëĺmŠÚÍ¡ ø í6?ïØÝ&þ‚î]ïÿ0¶ç+£¶™Pœ*<.±z6G$:4wÐ~ÂE«Íżd@ü6 íþK´”Ý]}`3µ®Ê¡š}|É8ØHj]Þ¼¥ë²6zŸ·pPñ?‘à}cåÔjå& 1ªÓ¢©`¨ó¦Ô²±ô–°4/ÿóÖ޳Ì40ÂQŒæŠð©¢?uWœr¹c«µ‰Š¹VŠæIJ^òj J ¹¯y€RàÊÔñ°sÄà”*Z…ø.Ÿ_I˜iï4t[{ŽVÿ†€c‹ÇœTæ§¢ë^7?Ö&úø9A–OŒUÍ Üâyµáþ‘¢Ù[èÝŸy%™žcÊn,Â8㣭6tÛ/üµÏÌ’Í\Äx£Ý¯ÁŠˆÇ€xc|¤«œS¥/ú£„•0HÛðÔAÓ¸çh@w‘Iø<‡‰ §ºæcD.­„ÅM àÖ¬Œ’ã]"~aå )Ùxà »×Ü¡%Ü:LáÉh— (2YþÌ“Ò0ýÎg^!Ù¥S0*˜ôX¾»£™vq7ë`/l‡_™1¬ê“ gÆ}Æé¤‡Hî¿é4QUN,ÁukúcH•ÍÇ¢©„ ] £Y¹‹³Ï.ú€å¢q=G?ˆ­„`žä]àG~—Ù?@ÇrÎDÕöz×óGXz$¥ÈARÿ…2+M€,¹½›(;MNnñ kVjQ¼TJÅV˜ùÇŸÇÎO¾MÑ®ª¹Oò¸•òFÁ'(‘³`F²œÉNeL½‰W`> Ë”mºyŒ+TÆ_ýj^Hgš“åq‘’‘¶¤I<̼}ëZÛÆÏ¯)R¡Â“ñuq’€€Ð¯d6å¶9M&zT%gdËp¿0…GÖ8°ÆþÙÿ¿­Åt?&·]¨¡j5]"Ôé%¤ ŽJbáåÅŸîihYp!vj&fǶXž‹^Á‘Y&÷+òù ÎT‡ZÉÒg¡ßaÃyep‚äL­‘ãK/"ôÈ„\ÔE‚©Î×—ÇÖi\I¨jé´“]rbÏE£1ÖÎCÄœç;ßvõº>~D+ó§âm”P®™ WðÒêûC"×ôFžšÐ²€v+MŒ,dß{Ë?#©}4Å¢–Ô9ψå,¡ÄwŠL Ê·ªdáíšLn4ÆÏ.iÌ¿ìI¬øZ}:ð…œ*޳œn)O{årF#}ø|«X7o@Äu–Ã& 0äÐü‘ÎÕ/O£( ­Xã#ähÈæ¤%@çxëU¤ô¼wTV`õskã—iºW–š#`ãâkW¨Šw(©Ç¶²c”Zt Pþü¸÷éøôÕMéõ{ÀUøiîØ¦r=  Ö;:ýÝ r¬‚˜Ghþ´f¨jïä“L×.nõÍ”BÔHFê±ës‚Çã¼tÖ¦›ã]:ðé‡åFQjqšSÀ*£G®£ºÜ$ëžËY‚µS[Uþ=uÏÌü" *™¦O‰NHµ5¶† mã^Ôö} År°AÿÙÕ9CvO,¿­`é±›lçR ¹ìÃIËïÀ4LÚ^ ξP z3ÇDçÃë¡IUƒ¯£r+M8ï/ÔêGŽys”HÊÃrDÔÖM)íÔC²ªèB•û+ïLcˆŠ¤Ó@ù¾ï/ -6`íê&3^&H néÞ4ê°jëÐÎ…Áê#´åaÛ§?›Ò߸ ú±Œ”¯Ð E¦pu›ê"èYbÅ%wwçñ‰ílå]ê^NÊ΀í¿SñéÂE Ê2µî_ƒë‚Å”AÏÌTÓn@F?¼ÆíLòiìá0\ã‘z÷µòý«9=¿~®ã¢ÁúCöjŒÖLŽ«ã˜{1iYé%fûA­÷qå‹U9#H_ )œÕ4—ž…ñcµ„Ò".RøT批ñ*OziÕþ0u”¢|¢i—/åÕ™ê$©ïðù[ihF]לBã¥3J6çæ.ÿ_t¡•¶•‹>[_|Ô«b|²—³©üÇîèOzYÄ;^’€€¹Ðñk@.ó•ú_`¡uƒp‹Te›#°È—Fp/ãúK„c)7ŒÜyxt%>RâIx¢»Wvš§;-<¿w-Šw9˜\þÊ-Y}šÛwz¢op©@·MuÈûú‘xõûâÊœÕq!‚ÓÇ …¾„ÒH–‚òU…gôcѰú€gë-kƒfÎ.îq2µÊòB ½‹Jíô -"«íø“ RÓ ‹›ÐXmmЃÏ"°ì þ:k~6¹«-dË9I§Lt´eR¶àS–V!°ö a*‰B?³³ß×೬æ ýþ©Óã H}˜oI ͯJ¯~ªÆl`' ®öÈgÈܰp©¡ 9öÎyðÃ(Âô3åëÒ2pJ6²Án,>Ž™iÜ¢É,åm;ó¡ _ÇvgvН é?´ËåÊŒ û¢øËÆš~*ν·F9åå;¯2˜˜ôX´½²\ŽEP¼ò¦;y[®ÉW†Auß…~ƶz9 Hþ*B̳6.¨È˜½ NTÿ»BáÎ*+¬ ©xqÝÓ–Šlè´˜"@/ü”]5ÖÛñ£Æëo[OàéöÝ&«1oÂ[Ú•Œ5šå„OÖaÆâó½]~á+ãµÒv°ôçιeÝ–œz@ãk¢ ðbW¢to¯œçîõs%s+bmÀéL:?»¥k’Yù8^1Êrÿ4Þ6ŸÙƒË?÷ñ˜ŸD£Yü+xÏØTv&~¾cšnVQ'á™:U€ñÖ«œ¨JÊ"sÂŽÏ›+4e›Žƒ¨ýpÅ}!Z[àÄ<5Ò:lÓ— ¸Síîk#|+Å&•´”¡¤…(;ÕÎ(Úí Q‹%׫N]o £ÈEͱîzXÂÞTþÀ¹»ä¢Ž&  ²N“ˆöÑ©ð¥_ž®«‡—Á5~L³‰ó‚Pä õ ajŸ§n)þ­‚§‘HÓkÝ´þð´Ö·žY“o>û•÷=ÂÞ—âùþÉ–ŽKH¨kZNÀÞÈSˆ?áÅù)ä•âF½ò¶mTà(rØ¡cÏÆ8oú$ü/ï~áaN¬œêÁKä› Qd=JýÚå’€€åœ±þÝèhnÛ¤ƒ‡J*-ï*MɯX>†áXŒøký#MæYÞáÕNèù^²0NÆ©|w˜.§¸”Àzê¿z®YŽa¨^VM&F½ÎU [±¶$u h¦ì)-=†‡JUO üAý"Íéú)Y?‹#{UíD)OÄH{g\JU÷…E>Í!º3!Gqê)ÇQªºÆh¼D¯p³§“é~…éóÙÂmŒ8EøiNºNÉÝÅ£ŠÊyëly^þWô¡Nó98nÊ,Ô‡Ò7yÊÙS>†zϧ†ˆš#c |¦Ó»]ÀF’•’¿ÅN 6©ˆoáˆ@CËmÑÄN“äëÓÑakë/=I–M¿½…ŸŒÆ¾ZœEhN^Äkë˜w¦# zÇ•¦yH“û;ƒüW7Fw›Æßà+–h"Jo ׯ"MI;]ɸ8éÙ“ó¶½ ˆÐÁƒjäæñ´óô†#ÑzãtÒó!‹áÒþísHq⿎¥Áô÷VIÿb$pµRýÈ÷yBÊÙ3Ù²^®#÷ZÅ.Gžv¥´ô1%í© d;Áƒæy÷=Ÿ=“ö¶Þ}½˜¦¬kÍÎ;_á§m·1¢!ƒO îV_”ísɶ&g=û`¹ÚäA9Ç–~w6Âò%IÍê[€5ÄÍ?Ž÷PÇÎsE_rÆKª^FMD†³Ã§ü“¶ ú«²zWªkí£+"§¶DÛ”[«¦’¶Îû¼Û™XÀKqxÂô•«p‘èø4ÕX$!eAÜÌ ûôÚÞ-¼R-V ƒŒæÆ3wøÜ˜ž‰ qÿ±ö$ ŸÒèK’³dr­å5 ˆ }£Bê×ÄŸ/²¨¥õæâßÑtɆ¿Ä`h–Ïš/€!Ö8SDï΃;‹„A&\`a9ø:¨Ë—z»óö˜óZÁÇ2!J–'÷)u ¹®%¹ÆÃC7â7Þaø*V™‚rHeê¥Æ¿¹˜t#j¨”ol~ÏäÅm¤äõ8}¨‚@ö#¼¥9Fw–]|uðÜEG³\Oô±¢îH—@’€€í¹Ç߀‚2Å+÷îXËÂzm…‰ÍKJ`t $å¾nÝeR̾ÈBµ”ƒv\8œø:o¨¸†”'Ó'ì|£ö”„Q#Ü_·ÿrpÁÎ`§kî¨nœsÌÝÙ(9𨔂VhÀ¯›ž†Æÿáf0T+JÏaIŠ‹:KÙ˜?óÁ†D§ƒ•E[]¶jì+÷Í~ÏÑ/Z”8)•Q/3¯-O m²ô'YX¥"ë/Ãp|øzŒÏ—íÔ°+T€þ6ƒÔÿ5/]£O¦3?ù&ôbôlYWçääm¾¡ƒ¾Â¢¼ÝôK0ZX&)“{$óÅ­ á½:¤üû„¦dÒ.S?Ū­ŸÔ¹„Ç1¨d'¬ÿ@¥§<öRb³oŠðl„ö@¼ H'î€ùû˜'ò䕘¾Gµ6ú¨˜²[ÖÈîÇðkvÆù$FLNO 9¢»Ò]ÝŽ‡—É( Í”[Öôg¥²¨‘uɧ$­ýGB)Q”’ª^“"&_0ËäzüQÌ"K€s £ä=i3lÇÚàœ#3vÌm¥+6ý°{ÇOÚÞð‰´n$hN[‘üLóD “¬dîÿ:©±Úx="Zææ¯0 ÉVþ´Ü‹ph"Ž,í9JC_0Æóª-[´‚"¤™¯[œ)ÉgoLÜ9+E/µ÷¯v1…ã‘p•¡9Ç:£j˹RvÚÅQïüAtGãïÆÕö©HR‰ÔÝ.-æ1¸Ïx€°‹~gMhæ4LÊ¿KÿGeC1 ¾ ¶ziÕx÷¢BŒŽklE€!†Ðµæz%ÀaÍùŸiRW¸’€€ÏÐ º­âø‹87ÑÍ£ÎÅøïK¡á઄2ƒýïøc^Ãû¢¡ð­¬šñäy/Ú÷ÀÙVYVQÃ!ú¡.³ÿ§u¤\ïë’ ù‘ÃÄ…ÒKñª4¾Ú-Dò‡¬ìösb–´»,›aÛµ]“*ê¨Ë\Çæ8áÀü،Ư‡%@]Äe¥ÛÃyiŽj³­ÿ:ƒT³„ZÑ©Š»˜úé.3$¸ oðH5w’4ÄZô‡8_›$óÁä\Z– X•W³Aÿ%w™D¯ØväʯåIƒÂ™¶¸¯\Ä¥ËâýÇ/[`it.ù³UžCeŒ*õÙYZrýû‹NÌ]·P˜õT»·ÇB[¶ò±nkå­±­¨o¨môË)ÖeäôvF”´9©V^d"2X\Èûu™˜4RÎå+‰¯÷5GÖAH Ûw–nÄE$I+6^ª6âlÉ}GŸŒci¨ehEµ1*ŠY™wmv.g‘íˆû¸L÷‹cjçèÔ2øäÎùïÔ)ðËF‘¿¿aU!¹Þ³Úwx0ö>sA(ñ·rÁ…ô§1T^ù†×KïÌÂç9¸°ÊEñ=Æ]þßE§³‰ÒÂ'DéëY²Š7¬ÑT8se<$…“C&êß |¬èDúÌ3ƒl"ÿAŠèÓ\™ùÚ’ãÎ˦þŠ–Ù–^½šœ^·gß@){òv·(7õ÷d-¬õÐÕxÿ„ÑU~…Y–Ãs!²p[ê¬_Æ%éŒúS ˜à>²™…zŠ]FKz@£ˆÓ +öâgNãE׫gEÇYqÚ(ðàxÛŠ]¤¯xvQƒÔì»q¢q‹TÆ%ÄD>Á€߉q³ t ±»çLÓ˜&kÑ’!×öLâvö3ÿûž„“+¦ËÊÁ‡.0Ú¼èÃÎ’B(­C/òª¦v^[ñ“®d+µ¯~rÄÚë·hú@F÷mÌ C`ßoã_øì§d5.ûVXˆ½æo#P+$€— %d›—mÝ þ. ¬—AìMÑÐsz@­I*ë}Êñ6Ãÿú±|#P<œ±©BËŽ½ سن4~ÙÿÄ/^•Ê-yÛ·÷A2¹Ñ†4GÜ~{h»¶£,|E·çi‡XšÂïùÒŒ,Ð1°Ì©Yä04cà±’€€Ò4ñøŽ²l™)µì²wn ¾—áÈÞ½ï &2ô_:ažPºÝ·H[¢ãÛuÙM>'ÉUÚ~§™öxç­Q_v­SÉi:×㨭ýd1©|ðJ‘&ÙˆÍÉMçÏ;1oyébg‡Ý9$߃ÑÌÉc޾§‡Õj$à T$Ú8®»ñGgßÇè…1CÝ·™ý{Wìtz€ ¾ÉÓ^;Ùrÿ1ëY¼M¾ˆ­ä6™¡kÙżb~cà[6Âb½©3¹°Ÿ¯ÿùÑ7ÏÇ!$_p¦ Ôƒ)fÇ3tøÉ]¼^UÀÇøCÄËŠ¡ÚÉàÿ¤”áæ˜“YqðÈ×3@Ęû?ËÜ]FØ,$ê"õs6xäí¤`8SÒ âòk¼¯}±ë½îRlHÊ—1·)3n£NÂÓlK8¢ÔˆõfI–Ž MÊc׊5f…{0ƒÓ‚ßÞ.~½“\_A½ÿn^“ñû÷Ë’= ;ç§ïTY9WÃà ±ÿ”:Å.ÞxÁš‚ÒT5ö™Ñ’8ûo/ò¾`³È]¶§û-ßê>] ©Áø¨/é›}‚j$ª•ë&¾5ËÆ ÂŒx²B\æXF½ËꗥàælÈÔˆª [rªûìÔw­Ã£oäV;¨°×-…"ŽG´Jn1éË3@V®¯å©q¾K‘ì_‹²÷@eúPK¥jÅ(˜r@Iª›‹˜[# tB|wí“OÀ2QÂï¹_Á[Q&XæÐdXøô!öúÌÉd…>'ªø³ ˜}ï[w1¬srSTìf„œKëÇÿDî ^Zü±±X¶Ë´4†, Ì‚@ÚöÑÌyˆžän_.‚=òéâÇパ|+ ªu š Õ ÆÓ|k¸G¬ìü@-i˜—RÍå&z@9Œ2ýë_ü·zW°ˆâ|(e Û~Ã["dž† Úéߢ¿øìšÊÐ_‘é[c=¢ggÕyNŠmv›ÍX®™êª®t}•$0ÜSûÈÊw˜ÝŽ‘NEÁqÖCØ›M&Põ·¼Ééê&?âŽÇп(·1K‰®ê Ÿ9;·O 0_Y|Ç'¡ÊÉÀXô²?÷AYìùp4S-ª¢Êuÿi0•ÉŸ ²ï6‹õ+æ;ƒÐr¼¦4³øH\N”¬ñ'ʰ)­æQ¢§Ãúvc–Ûj\MÅ Ð<ŽÝº2¸/]3™YÛ_ÎóAj'¨ºÆ4¼–ahÚ• jŠ[].—„ó¯w3KÖ#Ñ’†M7çBá² í¹ÂfÚÚw‚­=AÞ¡!’ãê\äW~m|qÚ&²ªdÔtµ ôäÃáypˆ(‹½CeFí§£¾ËZÎû#Nñ‡H¢BC*½p(¢Ú—u¹ThÔ'[}q«ëäEÿ3;ˆ4'LÕB”º–§ªp®†²6—÷÷Ž í?×è¼¢/íu1çÍ~o¼@–a3ƒ¹&—e©Ø ~Üþ›øæ/[n˜N)ÄÏî³4”âm(©ÿ$8tø«"æÆtXÎ –Z†l0G¨ͻ … eeŒš«í1€FôÈÌÁ}ó: \;žDÌ€O#ò(/þd„G‘²m¿¢½Ô3 ûïóVu¬õt£ƒºsHæAJP:•"“·ã¿81§§3+ô9Ô‹™Z'HÏïcä$DüZªóC©#úµ©½£ö-)øñixQ ‰úºKj1-§Ó¶Ã)êæÇMÑźÛúc Ù‘Ý¿}À‹ÃÄh¸^óÍÀ†Â²ù­»ëŽŽ‚b¨Nlá“(RÌ’üã©ö‘–Ž8·~œµ&Db`@îË+"W •×®°Í®ºhSõÞ–†\Y‘éø4}ç¬fì Ínv¯öv‡U¾RÍÍSí :¸®H¸ÃþÁ|—Hó ŸÀ–µ¦ô[À ýû<ÇaÖÉc™7»Æ L¾=l¢¥Ä#žqJ@¬Ö>`ó]xmÜ`—ôõÐÛœ£‡¯´Ûg:Øû÷e¿IpËÕüœpŠSCþeÚwRƒ ¦'_4Žs)Õ}zß}DE¸>sïT—=…¤aÈïç‡ÒI€›$áhe4TñB˜cÖ‘ZgJx[#²£Üs—(h¼­l’€€ÄYÆmÇ\yWÞ.hþ¦Qjuâ Þàe«žcq—(,ßÈj~Ì®ÛSé݇Ë}Š«5÷š¥õØ#D‰™PuA7‘ÚUÎcÃÉ^>|¬ N ùzÎwؾ±N–¯)ƒ¨w»âá ˆ2¿UËt)Ÿ™Ñ>««bÖêÖØàÅÈ"µUܙҧ] n9ïžÉÛDÉJoÁjp1òd%pÑ*¦Y}hÞ~÷¸zŽ(é–Lq“×™ÀâRë)ÀreïÁXaíu£M•¦óð»&Ôïõ¿¥Z5PÙÙ[©¨¥ `wÛ|µo‡K[Gäïç'qNÙ*yùêÈ iëËõ×ÇAÊá‡ru8} ë”"cdqÇ;„m›³üW ;ŠÆrãÉZð3–½·dÄD¢Ž$ŠQ?¿/VÚp ²wìCIoþ«®_³ëT0ü\>& äx\­ÏçØH‚E@›¤6j¥(U¤—ÁØ«6ê5Söâ½…ÒwœÏ–Sä`æçhcOúm·ý+%‰®¶ÕT>ú²xyð;Æh³QáÎhä CrvƬhŠcIíAìƒ-z8M¤ÍaP£šyæ$b1—Œ˜KªdsF%Æ ¦À¿ŽUÈrRn[·’í’¥AáÔ4úôGÑnןë-°ŠÅµv›mÿÀMä}ãàý¸(õÿ…g!òÒ_apâ°†=/ÛÊuv HäÔ}3DŠÃ³ OiܬRVw%ûJ°»fÃQ¾‘ÇèÓGúmáp„x3¼¼|Ó!†Â;ÜÙª´»á)NiÓ¥©1‚î’28ƒÉI9aoÏÚ¾Ñ …aÉè¼· kÍÄŠ­KMR W“JsA數FÜ$ÑÇI>4Á#]qRò9°§‚¯n¥†3æh7éòÝ©"JꚇÀ“C‡.Ðë·‰Frºì Ûä:¯Þ6û¡Rȃ¤ñ3]¬B¯;þ(»¯NÔCêïB¡.‘ŽÃ’š³Ch$6YoÁó}%%”Ïÿ1·oIùêx@qÝÄŸWIçEûûñ0Ö|®ð.˜|xùÒï÷›¦.†ßdžJ4B0ŸÏG(×d4k ÙN!Ké5~?c¿,–4¨g}Pƒ×n*X»Gµ‘8ö’;ƒ¼0|™:ÄõLÛÙ8òºP¿»å+Dx팈ÚËo+zE÷8ƒ¥’€€ÁÄ »u;íSg?_U%/òݱMõ‰b¤"ÁþÌ)}¦*YØ|êÛÙ”uZ‘™Ÿ)•ów»áç’#!Œc%,?ÇÔ" @*ü7ÎapªÝl)«Å1¿rûÜf`ªCí¨ÒZ4oRI²!òçÒÔ#¡&¡¦SjªçÐr tµé[*>K"ag$²aécˆ¸$¼] º§À˃3FÊE~á•’áò;ä |štyqS™Òœÿ~óòƒƒ¯ù¢*¥ªa‡ŠÉhƒéÄœ¸³-c‡j½Ÿ í©“`ÃüÕHÄõ…2ç‚„;c:táè|–pÿòÌÍNÞ/&}žkôÎâ?Cíé·–}X»*Û{®Šâ:eS«(Rá\ sê˜vRátÄ–ˆ]=2Ž~žâÞš¸Ñh`+qwŸˆ}é3Î œÚP9n®ž&6ðí¼ÓÖt0ô빫Çí­‰´/sW‹2¤ÎGÎiÈ” G§§§Û¯ÚÙÕPKw}Z˜¥TuL¯†“É5Ĺì.کد­çüÙdjè­P—D[,2wuÆÿ³=# ßõž]­Ê/jèh&6TÑðXÍÛ/˜á(hmöS@8¬ßjæ¹S8±e0°öõ+K™ÊYvš?ëòiÿd5<²œÇλn$R¾5wÑO¨!&IÞ½•IÐ@ þG?؇!’XÑЃvzK7ÒÆì–Àa¶©åãŽr¯<ÌÙá©yñÝ„ÓÓåPRSk'™|&þŠ–}g? Ã@q3ÃëüáéQeo›gÌå[Ÿ/&‰x7O€ :>4bð¹¥”Še#ʉPIª¬8ÊÇÅ¥G3‰Þ²áÉáÅÊ«¤°§…X8W`ü1rY 5 "% cç3«ðIw.7½ïHbv¼£EÃŒ¡6™ì^ã/º¸8eï2bELüJàÄL¬òôd0P` zö"°ÛZ¨ÄÁõIϯ{å`®aÔZ/‰m‹©\cøUÞZRôàÕÓ¡>»‰ª¼#Òpèù`ÓOz3ÈSãû>-òµ/#Xn#r¥øÜ òݼ>ë#wæ¾-à­‡Û&¿çz˜’3Õ+^ŒÙÙ–%û£cÞX;@DªÄçÇ¢C/±’D™­ëž3¤”ÃGqwƒúBc³ê`à˜°’™£´ wO%åÜÏsÔ°’€€Ç-]¸°Ô½[ Û3.OÀñ¥TöwQ¬§=ŠCÆ\*?²G”z!¾ýå–΄dŒ8 èßÒöº#4yNæi¢CÊT§’²}ú|NþpÈ*²MÖCÊ›K\O»§TZ ¡/btäypÙ(õÖŽ©ùìÐ1˜*Éü ­¸éØÈá{s»õc²“˜ÍCðþÇlÊšéSCî@7Ýë÷G950M¾Z¥å±ÔúÃò]EiEÕµ„­“¶^ó5¢®‰çdIg) ´#¬hÀ¼HÉò\/rm·€t¾/Þ&÷Cƒ*ÀÔaØ{D»pSiOé×A8ÃYŒì#¦€V¼°‰|ÞÁéy¸™è© 83=U£bªLßï´Y† †T´–Trµ޲fµü5öòåR•¿² Ìÿ.8Â^€ÁlîGÔ‡‹Ù>òµÜgå0Ë´yíïZ0eíÊFáL÷þ…+Õ8™­X(e nËÁ§B¡i|–ñ¨|ê-™Øó]“;amþ' „¼“j$<»ƒ.¢ˆæ¡#*¤V¬wÿÇQog‰ó}/ú‡{6g’œÛÞ ?ïÕÚÅtÎ2¼XýPT^—mÛú²6·•d7~™[;!/¦÷ (1ɵþ˜Ù·„šV¼´2kí|ØëÓú<ÆùúÈ’l2HÚøaè𻡚 î*¿Þ¨\/h-•oCô˜ú#ÃNăG¹ŠÚ[˜ ŒÖçfrš™šyð‚Ë—_%l YlWâ44f± aµù’9æÇžŽF¬òÞ@QÂP²Ì½©ž7¶š{;ø=¼$¼«ùµ¥mÔüqÀã€+žCsËQý¤FtSÕãÝSܵ†¶ºÍ å µ8¦/‹Êø£Ê@SU’¡CÒ/MMWË ÜÔ«[ïú¼Úfì@µ±ûüM~U„ƒŸStæF²R”-¡.VZ²¸z„I¦­–‘ÐÖln2ÙÕ'Ôo?F›€HjVù†eÄáí|:D‚ÜŠgCHë–ÔK0¡¾fÉZ*Fs.›ðl‘4V Šʬ¢`:•Ê:¤:Èî%¾o€°gútË®!×Q`Cˆ~0§ 2–6o^|­ÎÎïvSÅçkÞõAȨG„ÃP½ðè ±¦›j>KÙÃGõi½Oûåí`¸6õп$ö’€€ÉwßÏßA¸²âõ[âKô8ðU§‰ðä²:f kFQ·®±¥0…Šðr.P·Õ·Љ¦=cfM!NvvÜ‚4à¿?ôdÝÐ ¿½þh—•V²\C«6hް°^>m%§ïìŽèEî"“µjW_m&zø:Zèd 'ÚŽ÷Q“¬Õʹֽi§Ê.Ûê39UjâD´AÑ(éXíÄj¯b™Á?TúÜ@à§(öÓJþèϬwûUL#ÀÂrn®Ð™ê÷« "®´Ú¿êâ?ÁT.ÞT=&‡?ô³b ›öá!Na]þ+gù9¶A 7r‚öšõóØ.­ój}.ÌÈ#%æó*­Á«’€€õ^„!*'@Uòœ{b*o‚•'ùó ãÝó(ñ©Ï´3öÐ:ÞÚ\w6"•Û™N?êIòq–³góÿÕº’nµ»tQŸ¤ÌÄJ˜é†0ä­ ­ijvD~û$¥z£FóûŽ ^¨è÷O'Nvᩃˆº‘Ë&ºOñzmÇ$³+PӓˤL+°‡ç1û¥3Ñ[›h}ð#€LIÝ×­Å4ûF@½înçÑ‹ñÃ' 8GŦpž¡Ç¥ÃE]XÔ+ÃmçÉ»A^SÛkÓËå[ Ç®¢4-Ý‚D0ɧ9ÉAÙ’§] ÷ñµºÒX?yÓÎ" ï.Dkç7W–ô0VM´ÖsÆË¦: ñ·ÁœŸh·“Z ,žFCIߦ¹%™éè:ÆégÑ+&÷ø£²Ù¼3` óû …áý©„pë`(.QD`O½¥„î ì¸ù̆Nv=ò×=?¹=¬SSËsàæ¨Ø%·³¡,×îö©üØ8f!“3ò›%zÎѸæÓƒ+BÍã¦(§)C|)¦®tgû §/>>‘@j›õPB&c†s Ö±&_zFDkÓMv¬xµ¯õuÙ7Qu”=ßé=ÁëÞêDdÆdñ‡ÆÑ¦ÒÓ³Ìhº·’wV.œ)|¹£ ŠJÈ!“¡mþVæFsìÜô.ÑU€€LåÊÕãÁ(Êvç6æ*{äB_Ž ® ,2Ü «ø·(Ìĸ-BQxÙ¾X¤d² ôÃ-úºKT5ê’BŒ©^ø€ë|ø4Ÿhõ^(ê˜N’´óð{Ɖí× ©}šÏgÖqæÅüXW®Õc>ëöøŸ dÌô¹¨Ó󬢳٢‹æú 7"!Õ^fÄÝêq]o…@¦BY›ËõábÆã†‹-Jm9,¼ûC˜ôªÁÝo€ÛÇ[Çû»9S‹£NÚ(}±!Öߺ±÷ßû 1ºe hÑç) .Ó×$¹9JBžL–,pc}F’ðf¤Œš1Ÿ‰¢n Û7ó4]¼Áþ?h‡ú 2tr €TŸvŠŸÿlݬ©Ò^Ã̇®QṳõÀ™~šÚ:¨¾Ž ý1ÆØùFnyûÞå§AæVàR]YøÍ%öf–^e³à/§ªÒ*'î¸\ÞYg'ÊâÚùÁÆŸ­~.Ä’€€ìrŸ[Ußù„ô - \ë();]›.PÙµÓ&ƒB±¶È%cïʽ>¿R‘‰T £3A¬…ëªZIzz¸Í°ßÅaGÓî5~ÀZU÷î U°‘²BuûƃæÝ¢(]¢èÓ©§,ÂF4]4p^• dõóž9E5f}$¬Ìé¶n^›BªïÇPÊE—Õ<¿tFüVxX¨¨Ï@†É§Â6(#±nÜhqûÛ®š¨6sŽêCÅi£kDÎrª«Æ %Á½UÅ+W7Ú ŒqgøÆñ)ñtÛÙ÷²ëO##+@ß$Îï¬G%‡–_“+”b# 1®|&f[û|@¸x»+[ä¦~k§ç‰‰D¾m+êßzÂm¼%N®ñ¨#ÅQ ¨ú®+»ª-!òÛ¹xô‘YÂHIÏíaá‘Úî‰Âx³á7s©êÀã–ôE“ùõ8L.¾|Rõ¾lŠúüÖ5*çÄ¢€ð‡n~ÔΈu†å^Ü/Ï‹½ííµ °újƒMõê,ÉšmžÇ춺¸™(%½(Å™tœà ¨ü2º ¤o·ôÞÜ7¼î;kų^ Z¥‰{ŽÀÊü¹¸‚‘s§Í]Î#Í=ÃuºÌEÔI4œ5]/4/Ó 5iñ§\À IJ¸Ñ=iK/RÉÞ[0Ipê¸ûe¤!IßÝ(÷–·}`"$§Órwωnû¹Vü–›³ø}¢„6íñ:O³ÖªC´pU«H߸âÂlÍ84vÌß%¡yýz;îR(šC:Î'Ùí:3\ŒÌ;†FÉ®©\¬¥W”fGŒtƒ±^Ipé`û­£aVûõ{€ñ([•K~QÜJ M³Y[à(Æ‹¬ï†Mîõ¼Çõ¿ Ücd „®n·ƒšn!¾PZ?¶ÚO—¾v’f¯; ‰…†H‚êÊAó__ŒìÄŠ¨Ã˜"¡~WgwZÙVy ¥ÝBͳ`Zïn¯›â/¼ ·•xeÉ«û:`Ã×݉Ã[WbEheyoMYèÔ¼¦T#$¥=°„h³ìs+³'ž!öYòÊ“‘äËC@R¡¯]u$ÏÂ}ÈY«exOŒ±ú^ttÇ`•ÐÞÆÙ6å±áëì \ûÎÔÒ^Ð,ž$°Zvµ$ÿ×'SªùEªÓÞ‰u#ë]̶“IÄø¡’€€ÇíyJtWýã+ß»_¡ã1ÈAλÚf®`ÐSÁÞ¢H¯©Ý;Èþq¦à|^p­y4€ 27˜&t/ÀÖ ü惼øûH«àň¢NÝ«  Їiê&²ëlã';h÷ÕÀhqˆ´Á¨5ý(žL5=ò7tÀÍÓèàÊ •D¹€÷9AsL´0·ìïÍi!IbÓù`î[—7´åÍHÆæ¾8A_sásåwNoÝèúràÙto?)üp2Z¨Ši(T\?ðuNÙ¨8ÿâëUµ•M:óÖ“‹1{þ‘uAÇ Y‡(åPUíe$ -ÃP¸oq%ÃC®1ûO:¬›˜P·õŠy¼.ß}ÃÐF ×k{Q%xŸ —žÀBœÛÃòWì,Õ[| Ѫf~6¼A:ÿ‰\…du|ÙêùgÇÕ"GiÔ1YÇ•¾¤™zŠtÆ;ÅlèHcÕΔÄg.G&©€„„„òÙ &‡…Êí¦ßð4/åÕ¡B% Š#Üѵÿ-^š0Ò€jšgDð¹¼…_ô]§Ðõ彇Ëi¶[´[bE¨7v¨Ç4}Ašp]¢@ÂAá¨ñÆ aÃhÊÌsÚìT%ŒðÃnÊÛ·n-w¹¡š™3ôMã”zϼýÍþR}~3b„ß™Ú_ÂGë~ÞYç#o‚tŒ¹?8ØÜůHÔu‘ç×GŽÎ–]ÌØ#›Õ?qäC/»§4¬8]ÑÇXÿª™jTCRš¡ì­^' ~•g êr3׎8hQTð•Œg§ª)M® IzØÃ—~v”×9¹†ðXØ÷ UõÙ0Ó]ÜJúÒ›n½Ý>²uU:½DmÝnƒ´^¿ºöÌéß]­TÕiI½çQÄ õ@RN±jö î¤hèœùKHm8(âs &” i±³D¦°™O"Zn_î/ ü±á *Ò6šçà ÑÆk0-åÜŠ2ø€âEýù3VY/2·Æ,ÉvÈ7Ã8¥=؎÷äÔïY1]DîdíŠ[HšÌñöjQÙ" vY{ºÑY\Ôºz¦ÎMM\É9‚­°;çUUÐÚY4Ó‘}åÒèh?0¶XÀ7g¶Ò‰Å•Y[§H7´c÷Þvï6lüŠ¢¦@ú€2á9íwg MÄ•ºÑ«î ¢ Áqc°¤ L«ªd`\4’€€ŸÉx£Eúe+íGqè ºÛ«ôÁïè>®ÔŸ¿ß½£ÖçvSO-9K'²80Êú_Ϭ›¨'QºÕT E*Èu£?À¿‚UtâZ)»}WÚnYÖ0™Ê„û²^ -gb«»Î)|Ñ Í-Ñm\„þ ­ƒšÕíy+ö:¦_l¨Æžx?â_~ƒ·3¶N’.Ø€Ëä÷å{DœÝæ‹%·®ÐO)ÿؼ|c}Tˆée ›WC%ÿœ?užkùõZ\÷<à-غ¡µ½½Ž/°ËÓogšó>äçÂÔxJèÿ:–wÑ0ÓCÇib]›fvžjÈDö¥Xñâc>SÏ"$g<çpj$½~QÇ® Nš„þàïÏÙf¥Õr;Lé¼á$û_‚Ì—”Û†äÚÄW53p¤Šö“ÁÏ*U,R±øðÓàsö¸û#¸ú±¯„ø)Í—$ógg]ù~4ÄÝ6ÿ.kï³'‘xƒ“Ç?õ¶$ÍŠb9…SýŒ†gBPXöŠ))a­O°‡;\´̪ÙB¬gƒÆÿàÇô& ‡®øÙ’¨„L¦ãúÉjà‹øtÔÌÛñÿ^Î Ah?˜µ}X×™Xlÿ©±kêz»/‘ˆe:í³õDùœ%ë°€YÛašÀ/ V0x¶^­Y/^MÊ‹ ‘ÔžSÐ_ ƒflØ5†žõeLXKÜòv”wÞG5ÀO–Îå¦q"1ÀÅv®„0âúWr«³J(?úxu,ºŸÿž‚Å})ïŠ%KZ]tz‚&ºÔS×Aæ‘לӜÂÚ¿k&úžŸUÞÀèN»ìkzßÀccʼnyš"î2Ät$z›d¶×Ϲî6±Ý\‰7EZÛðÍPÀ¼ÓÖÀó¤•"j]UµD¢)WÀZMŒúy,J óˆ¬"ÀF2F¯»qN2N ‡^yÔ©û‰¬›–¦ÞÄG¸fN+É¿øðrŠ2Ò"‘¡¡)ÿKÄÀ*h§_GO…Í ÍT‹à\ÜÈ‚ò`€MÔxÌ7Ø"ã’“¶×¡ûšñÒ†¶4qé`O vͯ¢ Ýú§=@8N-Üé1k·¬·$4j_V$Qá¸Ý_Ù¸XC"yùjlÝ\ªZJ[MÁ¯\ï’€€¥y.¥µ!1ä^8-Þóüd MVÞ¬ÂÁ£í_`Ây Á™ÇÇnÅP33ôˆ‰ù[i‚§Ë^gÎ÷¾ˆS>9ÒÆ‰ËŒXãGÙ[nÕ5º÷Ó§ÄQƒ>î½æ˜‹3rÈO-f±;ã!’A|ÍOλ…õ÷Ã…ç:?aÙ.i@´bÑ‘áK’4w°„-êibHéBšSZ[úbëüd´È5¥(,׃<$„-{¼* ô(*qبPÈúJ93`¼hÃJ\ÔÙ§—Å¢‹,±[æ"Ðï/îV/BÞ ÈK­8â¡ &#-»½`Lk©žµ¬³€HTÍ‘¸'YHr÷dËåC«%xN¾.MwïÛžŒ³Èˆ€pKï__:Ù¡ï„:üSÈv¹—ÇËK§»Ó«Â½ÿVÒ•ÉA8©ÊÍ.$&ÄúÃ{ÇĬ±ÖüØYȥ˿“•H (šuÐn]î(‚ÓËÂù©c¨ëøíÁ8<‹{+'|uâÓøÿ!²/Ù©}5&dü³œEÔ(y,Wh±Ó] +ŠñAå¹ÏH àè ¾L‹Ì‰ûDI©”ø6,4s’€€ÉЦ#_ÄÀQÿ†SÁÏ  û¤•»ÝS,zæ‘R­´áZ…Ÿ(Z‚é öûWpG PMWaL¿²Eú̼Ì~~‹'Q.¿l'‹çSˆ@Àü$óÒÁW¼ä{g^87‰"2¸MÏt­Ö µ"Fz#ë…Žü¿k>È/s\c¸†Jë¡¶1ë³=Z‰µI¸~EYèP*8öC¾¶9ÎeWÙ…‘”{œúáô©"µYìy´ † #°ar˜auz€»­ÏðAYªåO¡´³@B!¿‹n!Â%r¸4¡p=EÐfNhÐeÉ8ý(‚¯'eñ„F“'ÚΚÑc/û‹ô›äŒÓ«ÍP“¬ÏÖhŽ-4AokûÓˆM•µ©æ&åfÔr·­€sq‡9Vù+ýY*stÏXÇÒByùh+w,mr"šh¿_}`Q±Ò0]\ÒVO]êP¡yc¦G\ÑöW³–ˆÕxD,~¯üçY;oØg6v"kÎæ ĘÌ^kFøž^´ù|Îly-›©â¶9OÒõàõ«2¶e¯Úä¬ñhÆAÑBNbSOæ^u_Þ|·øØ…á0ñ!•Ó¬ükÜǬ¥Çu †§0Ý €~[!m­÷Ã9bú1Ø’€€æK+“ +! ñÌoyç…BÚ´¨ì¯.+ùÒF‘œ¢€}âbZĆ­õG3Ÿ xŸÍ]üÀš[\ˆj¦&Ž‚ƒš=ÈÍ}${)ÚxtuŽ:4ÊåÛ7@ÿg]¸®ƒÛk@ÂQO¥}âLdÿúÆîÙÝÆ–øT±»pºP&ô(£¶¾rƒD»„Hú  Ù­Ý”?â1Gè˜8,L-™—œ/þk!ÿ•gÛè¼ÈiÔXûÌ4ƒ–YƒoL›ÃÛvDtR÷²SÎ&|/n8ˆ”EpvLªãµBÍøÐb8¯ŽÞßúxdNf?n¯‰¯øí¿@Á¤7…á ËoÒc’&ÙN+õí–ú`iA(&Q‰Ö]*µM¦£O ê+¥Ø!¡ždDvÚD‹ºòFòšÐG‡înÜô”³¬¦½HÀAØ($ÄX6=¾){ê´‹Üߨ6>ä‘0Txg[_\toWáþ™’ƒMo¹ óÜ ßR=Õ×D‡:ÂÏ–êLÜ­ÿ˜˜wÛçIÚz|;GœÆök'Õ›G7_¥ 2‡Ï¿ë)Íâyðgï0½·¯îZ&ŒÝÇu9çÚZ¢’ðøºmÄÀÅ—ýÙEéÐÈ–>Á5Âs3mè ËUÇZ>çÊh¹UÛ>{K}—ÙJiŽÍ©c·‚!~È+yb„Â麬¿‹š~Ö’Á3ÈÑû©šäõGÈÚXp/¯"¢êÿ¸þ¨åppà2ª\åŽmܘœ¸'({«_üGÁŠzz3ÂAiO(œ-‚wÚ­ã"•D¯ÏËÑ_¦q±Û+†©tsêQnYL*8LØ}8@Ÿ•C°_ ¹hT¬zèrÂ_D?X¾ÿnÄüôë‹U\Uð/,ÆG_ÅìP@Ååݬ.6¿•ÛƒuU±Zª¨ï…v´Xž™ ó¬!nKç0,AÓ´LÉÏ ö Cù)ÑEKÜyK$ô©°àÏ’€€«°û#_Ié ( -ð͸(Í‘oÎz;±“*:âI´ëÑ·èÕÄÕ’Øtæz¦0˜«“µtèžÜÐ Qçrélþßl¦TD-Àl`_×=ñŽÖxbuk8¢´Õ(KµÒûÿ€ö ªèým\Ñr¢w±¿£_cÝ®&ÓS¡Eì‚|3÷íÝakû™SöïÍG…*D.ÃÐ%RzÀFwª*¤Ð¶JˆÆä}Rn†fgª´¬1$1[¢Þ±Ò+×—ÒgÚ—ÚÚXÕ^äÆ=Ü©º'¯^ÀóZLqÝ!u;hóÈBë„25áDŒwKÓ$3úÄRÆ ôÈ—E?$!Ù8¥nÂqãÖèPʉ$‘û-z¿¼°ÿ›\|3- ¥lb6b9s#És‘>Þ“é[ÏEõ9r-ž=üLƒa! ã®âµÌß7(~iió‹.˜­ô!(.-ÎØN¹W¤hßê"q¥òh‚­ÓþW—àÖño®ùïÞ¤ ÉkF£4ζ»û ÀÏ¿ÂiŒŒ$ÄW…WÉ3VcžÆÞA‚®]2–)mœÜÚCGYl¦(Úg“ï% Š‘ühç“›óŸ«rúCÃaž@öµÈÐ|æ@ˆÍå;дå—)àúâ:vÝÞf/X–é9‚;#Ò¥Ë"˜EÚTûƒ¡|ÚL{Íæí’é7`*XòÝÆÉê™ì¨PÕ›Ÿe“Ü•QZIC¦Üw}m`§i-N4òžÔÓIƒ«B¯¹a½ëÖŽÈ Íæ=V9ìõ¢ß×ÃqL|·^½3öÇ­Q_vkNÏä×Åù|ÂÁµZm “ â…_ûqyF»ZZã-†¢"zÒ¨‹kú%òon Í™Šâ i_…yâߟþ‡¹e*&a˜•ðÄÔ¾Èm ZjnóÑ-éÔ”—-ÍK2+ÌÅWMq²ш«ä±äë ;¶ßâÔı¬æÛÔ}‚(=¢“ÛÀ»Ô]$ú³]ÆCZª &ˆcìéã¢=`99êÆuJ±})iïØ4ÀÜz=ͰÒd¸Hؘ|a´ ¨J'“V™c²Ã"S„ba¤žKKc)+'cyªfĸœË‹ú¬Ö®Áñ ´7ó†²ò¢CŠQ@}lK‘ÍýÁiímÄ ‡Òâ—FP¤D’€€àO\s‡À[©hXïµðªÏ­ÁŸ]Âq ¾/;Qi£¹õPð&¨Ël"W!Ú¼•>6¬ÊPYÅ\0»ëAØ>5¸º¦Ø-“ÉÏÔˆ €n:t\’f¤š6j‚åfô£zˆ¾’š¿<•ø‹/fFXÕB'‘Uë·òáèðÌ.2‘Ê´Ö\XØL+R^{B‚›ùïC 3$Û%̘nlÍ¡™°òî‘‹ú¦o*ãu#ÓmkžÎw]#è€i+xã4 °% _ØÍD×\l«ȇ´Ëlî»·ÿý»ØB¨ºHüÝ©²ÌöNSƒãÓ\|åýmTRÇHk:êݘ²…¥…}õ>üà)˜·Õ¯‰;˜‰›Ø=üú`K<ñålÄšh“É0<ïÉçj%2ü®Úóå¦àûˆÞKéM°O´ÂóY0­Ó‰}å„*>Hþ‘²Éßy›ç•pª$éV*Oô£I0Z®àAµÖ•¥L"¯x.ѸØjkÂ’¯)Ïdj­ýð(÷–B&öŠKUµð40.ˆ¼of”šmQãÇ‘Zã2¸èÓëã¶QÚ z)°{„ë8W ý›GÔšÚëgåOJ½n5R²CsWâý'.Ð\´SO‚`t$%–çJ¼/[5öÌs âöå-¸ZœP€•â½?4. ÂC9ñ§mM>pÞtqHk œê±yòo¯¬„ZöÁ2ØŸ‹Éiw³Í–Å&4TJsÍØ}–³dr0£¨’àƒý~Žu>ZjŒ«`àx!,*Ý)†²7uæï<ñ•MQ$WÞ‡À?NÌ)à”ã&#wÛ)›`²vúhK^‰h “í X•ˆHÎ&¶¡Ž@œ¹|s;Š)³¿*ÖïÅãørâþSý?3þá3⟭¹jÌVÏï%‹ÅAŠ‘òñ|~z5™S@>â.HÁàfO÷ÑµÏøõ„âcAµ:4Q¹áêF¿@M¥~À¹ÑÉÂ6XG6,5^ü|U—ÉdtÏÁ_H¹xFÊì,ò{ 4ZÄœ(Y^Ô°ÝÂþ¾ˆ¯#eûÄíy<Ï `«&ÁnÇþJ8§'#õ“SL]•¶D&‹ôôü_Ô:Âq‰eûœ“wÖ…óüì|ãTƒ#/ªO2©7:a5Ä›2ÍïÌÊÔU ˆ¬€"­ïõ’€€Ë&À¹k Ly²eQÎn]$GMq Ø“Ý@­‹·gJ1#íÊ*£qKõí6é ²A™ÆåÑA,;$iœWX€Õ7w_b„9ÜU¬$ò+¦º(úN”ÑkƒÄŽÆfe7Þïñ2eޝcá’ÑXôÖ…®–›ÝûÝ7ÓV-M¯1–úME~ÞFݯŹÄÏ?ß`çÙþ)q½²ßɵk8÷«¹;\¬~W¶º:žnõEP;GªH\ã—Î*¸Ñ/ʧU½ø¦2mðœÈÇò—^páÌ)8$„)í‚Êdˆ…ÛiNÃfz£‡‘.4ŠÜ”ÌD߃ "eúzƒ­v±Ðž>Ò¼/Ç ¥ÆEQhœ+o¶šš‚dPóU»vÇ ýÓeV TNÃ{a@r7ÿ©¨&¬ÁØ2ñé²»¡r #Ž·Úµ¿ÈE ¶Àµ@ç\AƒÖêFÛÞz*¾Žˆ0 <¥GG q}‘”Ä&Ïnª‚’üQC¥Ãùå×û³¯%µ=Û”ÀDÙíîIº®Zònn4ïE'yü*ʈ±ŸZá…±p?øBý& +72ÈHøhöjuÅ<´É~ôÛžêìt‡u ×½¿5_g_Ö½îâ2û·   ‘ ¹Fäà'¿×{ùï¾Ãl©jhÒ(ë{pª3Ï´,i–~ýqFÓQPóŠ,¶ŽÝøä›DÎðº‹ÇÑ•‚Q¦üPÁÃ7/÷ë`©‚¡˜?ñ¹Eƒ7á$µÐ‡E¹–ÏfâªcAx¸ò^8ÔÚø¡þºˆÄ1VŠ ?CÞ½„šãjBFIGQûï~ÏÀ?J ´LÙçެ黙Z>ÛºÐûìyÕ‹”¼‹j7.zûäáúóÓ¾Jü¶±äΗ÷úO5{ášx±£K&ˆï$M¨þ8o&7ÄÁ?_Í“¼·ïšˆ¤‚ä%;"µ µXÞßÕ¬Ý0ß$€D¶NÀS N(Hl¤@¦œiGÜ@jÕ2¯sáuœn?•eÈÝ&Wæ/‡ ›Q[Ôì‘ÞrŽY£-ò-30i";ËP`ÈGõ½Ýo êp­ÅJyFx3‹ªS^g-zY~JÀ>Ük"`Ÿ ¬·QŒý ~ÏœZM,u:‚tÐ…$×<ŸƒµÏ½Í'¬tðLÞûѕ؄•Ðéµ¾$ñ’€€î1’Šp;÷0î¸sóóßî$Ó2„¾˜ZR a–íJ6ƒk/ý¥µ”Ï*¹§oë–É507!òîk*´„s=Tƒj¼³7{{ó¡ ÏåµÛßWôÈÆg„@^/ÀñŸ/ïÔZap0uÀÕhã!Öš;T8LòHe²CpþèÕKn¿ ¼ ³ìv´ó,å°máıꤽȊf¶rŽTãºj‚%z슯öˆËtCRjSb@N©ý„S™|¡£.@¯X ª#zø¼E؇ž¥!bƒÛí@§Û½&K„;Uík]yFÑ)8ÿãžþ—ŸV`;y3v-jã·s fƒöYÚXXõ?>ÉÑk^óð+ZÅ([i$2 œÐóIÐ+óù™ûCöñÖ-è«Í÷´Ì[›V$?y=ÛsZ{[!r쟰š à”$¨úOÒ«×ÄޏÀùÚ'ØË¿º)^唞ÈvéÍ£ùÿ•’•µb™Ú ,<; EDÒ¦“Ñ7ã2Ü¿‘nCmŒñ6•…Zñp¸÷3¦Q«Ã}„£‰(Jor;uò®ˆ­zWꆙ+·î:(ær\ýœæa!`€Rpvð9ÆšúM\%“bøäÜfdA?Â2àS”1¡'x·4·zâ°¿1“,EÞ4¬.ûc— ÍÛ› $3˜OäîÙ³õÎÍo‚sfð‰dA¹;¢O±Ø†~È{-~“Ä#KˆÐ« ó Õz)<á ¦Ø¥_Ú¤ y²L _º~ Mw³ÎùE|³òÜ8® #Þƒ[M³I'yÖÖú¸µdy*€‹Cœö±j{Xk¬QìEôš@褶sמçÒ<îäa¨ÍBfzêõùž¿Üøµ»OÃ6&j˜ýâ)’€€Ãæuó†’9Á}ÊЇ0§Isù˜DgÃ[àß]Å'->x½«/27Sà{È€9néÛ´7›Ž”38Á˽:ÒŠm¤×NÌa@±X*kŸŒ Éñ01zÄe—û·¥´‚¥Ž‚{'JO±³Dcí“.‰¦jçþNˆ´ÇÚ$.Š;ÜÇæzì8Á?þžærAt†#V8„@œÕ2ü#ËÍ8¶žÀ(FoÜoݯh^î'°°ÞM âÙ:…JSËsÔ´ôŒÕÃZ^±(΃ÐÈ’}}*®¶”D8¢W¦5oX©gª]›u†¶¦H!“LL¼VÕJûg%ZY!øÛúˆmXƒpZ(U°-iðJÞÌ>4®²Bšì`¹ ÿ=_[z4zî÷ͧ³Bê*€:ØzoLO@ðThkrƒÅ3 Èsñò\ð‹XÁwxR±’–€e’f2$smMØçEŽ} \ hÖ1Vrµ@œ­Q(n‡P]Kžbs™SÉ…wHëv«&,&¹Â[ÈÖ‰ûrÏ!M΄ºå;„é脗↠x¦Å^ÖÊ•Yír 6w΋ ~Á6û…Iß ¾ù`ò«žC‘&m%¹‘’ŒRç%¹8!¼®Ìù÷v°‚ã·„~ ¦¸bmt=ƒ_à®Ë’†(sË1IQ‹ùy÷ç 0›)*–î jVïOŒzÑÉ EeÓÃO›l;,^¯»ƒfv~Õ$8ºìèÉ~ÅDNç57""î'Fvà~/\×R¿æ6½Uò¾øW&ÇŸLlÿ·üâKÇŸDƒJ l’€€–í¾ Hû¶R–~ZLÜ™S¥™ÛDMÃЕô" ¿7ɉxqI¹l›ÍSmj¾­Ï§ÖƒKéGµ¶êç´“3]&1SÌÚåz|×I÷îJ´þ ÖÉm±Æ£æiÍ`íÑYX“šdÉï$šcE³êÏ K+j™z ŠÉýˆ'º‘bÝ4ÖŸ³æù¡§ú“Žs©TE›óÙÜU¹ÿ ÿ$óOKiù5‡M°Ÿ•+e®u>qüç2kÈÐÚ>ˆÉ}Ƶb@Wi¨ÝCÐ{%ûÛ™r$D¬%„Ùö”t [­‰"³ÅçTûunñe§åûšÅääC±””'pQkC÷Çy!xÉ`×8á)ÑJ\ë›A*ìjÈTê ¸òº-þºu"ì|rêãõ]ˆ I'6 q䮋‹à\fÕ"XåL¶™%ÏIÍ0Ä‹ÀÑ%!1æ’?¹©ný©=¾‚$÷tMeÚQ±'œg¥kºuuI§¢w.£îØ:Æ¢ÞX#Ð|®†š¡yAe€z¥ML>ôО±y9¸¸ w^¡  JH/sÊ[+ #AÔzw.’’ ÙÔÖ+:Sô<ae •sqLLmÊ—ÁXV÷8øΪF²2,•Œ L SŒõ`‹…ãÎþ.`gåÞ§çÝ"­¡ÝÀ[È·[׿9t²«ƒýwÅÊ€6gUEj5Ž/ÃXáÑl~Øá+R "~–æƒÏÀMàåÛëÀ‘CO É«P!‡÷Jµ7ÖÍíˆÌlh‰Ø ªØjß9'æ$ìàt`Kp~Õç9NÔ‡„ÀC"R 0Н}@Ê€~GÄ©žÀ€QíÞ¡ÌRÊ£€ÎnêsEK‹ÒÏŽ?1†ÃÍè¼ãt7v=‚6tèŒEþÈÊSE‰ãˬH,àˆup¤[Q÷Ļڹ¾CÜÁæü¼¹QÐil˜Ê'F"£ EFÿޝŒŠ(ÖôÏ›ƒŽsÆ€&êë;ÅX«¸W¡/#rkt¬[aœžô÷öµzžœUD]³µÖ0`iåJn¹Äžp ˜Ã•€Öó@"ñg~B¦`‚Úø‚ÆJXkÅ íý±¿õ*aÆî,Z9€žÀ:®>"çQ1ñbeÚAý½ﻚ×"Äó/åÊ…Å_ëŽp³ÿNpœe:C®¥åqÂÊ’€€Àô±°ò[GŒ Lí`Öbá9²„ŽñÕ0ƒÃ±:vV‰š«Y\43{tÕ nÐ|9µÑÏl£)¬ИOn¹Àrÿ}<Ç`G’—Ï/¿¢ÉoîM”ZÉí»OŠý•6·Â%7VÝÞ×cA’™â“¤À(‘)^nÆÍyñW9åð!axíl*X ÿUý'D'%›å^Ô@?çíá=bHòâëÈÙ?¾ß…|Ÿ}ðê-Ur™q®rsTo§¥¥‰ë6HÀuéÌ2ÙÌÐ!}Çô¿€ÕÅV¡É‘p ‘Ûs¢y[·m›/Ë rר;)sróì58†z'YK>÷âx$±ýPð'gˆÁ%ÍQKä¥+¥ŒÃv:ø>0M™}¡i NECžŸo· dn†à‚jæîƒÕ»%4÷/+Uoö)5©Lg-¹nkGµŠª’”×g‚ú¨²Þ” cš²°û5æ$xWÄÔB„¾Û[a¼}sC´&õåŒb±+}e\J…Û“CéîïÎ$Qš=¶ÀBÞc˶óÁ§éPÊ!2kLóSõ⬄†õζñ–Ç{k=ätªY‘å·ü'" zwð‰ åW5ÎÎŽÕ´,.hTÍ쇽Ɖd…û“+ryF5qôyMôùgLý€U ªx¹ÞXÝ„¨Rtؿյâl?>œp£À¶Iîw=sÃ'ûŽÕ–NÞ‚ïK‘ãeù&¼. |6'Þ=0×{Îâ~´Cï É„$¸VMHä„êxÓAºu’¤Õ‡qÀ TÎPÓSÚ5l#Ýþ³ ü›‡ë f67Ke¾"%´›ÁÍ&¨Ç35¬„-#Kžyrf4 ‹¼Ây¨\’+ ¸èu’€€ *Ÿæj<ÖÛÉ’5Q"HE»pç ­ÔâCû_™à†& ÷&ÄЗӓ4õ¿P}ŸY Àýáèç­I¿M "çáQDµñB~õë/‹ø˜¶ë˜eà=ô‰IØq¡g‘›ndÝùbe+sí<±õ„–Í.¼ ÚRyâð’œ×!ÒKä〳‹ÁXÍKÉ”¯ÿc—Šý9v‚õßû”î²¥Ìd<»€=¼Ñ´9ù¶òŒùˆD!d2ý×͂ڂ›øön¢Q"³µåÁæd·’ë®'íW©•aéÖ/Jº¡ŽCSu>2)¨yµ[ïðÀ¯ŠRÐD¡'æFƒá+=iæeŽ@>­­Åÿd=2#ȦaÅ–öŠõ®$ÚÅòF¾w"£\¨PygyJðîÆÏ´ÓVær036óÏà³R\½Ç—î¶»IËùÕ_”Î@Œãb9Ä gDˆ§þ|Á8Ðv Vž] j¦[Ò5äCeWÿvnQ=Ì?çD¢lJ'•TÏzæ„K2{ß _Ç7&:º`æ¬þ毭œÅ  æñ…ƒt>/=°ÍŽœµ¢ ¹¼ÊÎ VÕ¸žÛŠ´ä£$æ²÷!û_˜Á_Œ³P9ÒüÌ´@Ôe} BÁJoæ[’þ¯òIFSPçdyÔOtTÇÿ•Ö Í5I½!ûð—Y¡­ÇkÐ:Óá½4ˆÒfÚÊеצ“:jpQNÓñØ‹ êˆ2BÏŒ¾ÐüÙ IlÛ»¬{PåS¬ôœN mÞãX¿N“€x•Ðüë‰+ÝÕöd±z WžÄ³SÚÃ¥¹r=ƒNNÉx†Äí4<µ]¾»ÇΡuMp¼SüÞµâ\ÌÔ8JEq(rˆ6Í@*“¯òl“û¹£Ìkظ]ÞÞXBpd'9Š+®›§l“–hs½Œ>l•%L£òñ?J»(6(IÃWoçŠ*e £é—)æ9„¦¤(r袽¨n‰M×ÞÕÜ4­öëd}î0El]NÐÛQ.ÏÙ1?B’@ßìø¿+d­•ñ„½æÕôÖËÂðjÇú:šf©§žSþ4joÖ[Åÿ¦qÅZ´l܉^1ýƒSãVBɳhºÎ]°É•æï[ºÜ7k] úêšëÌ6m“×â?‹ñQÁ»òö5ßö^!…Æ.'Ác2h‹’€€¨!Dþ,˜Á¶ =gQ‡ÚÅjÑâÙ'̸f-ɸºxHáÔC>4\µ_Œ"ÎADÞ;}}ÖÙ1Êx"Ϻ•Ƒ†Ê:tLÌéI»´¸;2ø¯©ê“?l~§åâ1çÃx…¸ÿTp¢IˆªX§VO¹d-\Y±ñáôK†vJ6•^{¬p;J3JÉÃõ•æ HÿX‡:¦]Æ[‹æŸãµ·-åâž›ÞT6@ç;šÏv¡`½9¹›ú£1xJ8âù-é…­7Ù‚•Ò¢N!öÃMÝ-öŽZçò-éùðH„.hX6Ìaó3ƒè˦¨UB|çœæwÒ•äˆ5ÉbH±câÏÌ)Uo,v_b~n½ßðòm”xû—ph¸”wÇJPS»)>¨afãR÷º Éá…BêŸ/Ï*Bšãb’«Áú<æM"šËà‹ÿ#&…žäÏ£ù puXa-@…Ò˜È_xé*èAÃÀÔ J$ñ—1u7·Ê´r_ ϨÒ³kJ¨ÜHÒ‰@¾ÇõT»¿£ø7iØ'®\±jÀ‹õÄ7½ú³c¤Ä0ÅŸµc^  ý„€~»k*úX…#fÆö?Û|JP·Rc©ðút{M6©·üèS¹'‚ì®RÄ¡%”(—Õ]<Ž˜z{¾±Ñ%F6N¨íFÍ?áÖûÔZâŽË\È'ëgíº‘®1:6þÁ¨Yäë»Òôz··®®ø„qQGY7üBØ9MÜ«eò/¯_|®Ã»ÈºÿœuÁ$ñˆÌ[¸a—ï±8îÅK©¤'¦¤ËKFÍÝœB†Î¼©$Ès²ƒßÌHË"Ð!Ù–²§!¦yP‡¤¨J(QÐZªºÛÿ°K4èe`?Zz®ê/*v-ëÇx)æä7#‘à~Ç€*·˜b|ò÷“Áºæ;]F@{Ñbÿ<„ú“DzÆçðaçGaÍ[_o/ZSDO’Æ~™ã 7°5½Ú§ïˆ‰ÌßÌ KbôI¾±Ðì¥èä¿Qö–CÙL+µ—Ú•7[NÕ ³bHŸŽÂ–‰<ˆ<mÈ ´É=·ÛOÛyöý¤êÙÇãç«ô¨}R•žêÕu_sÄÇÕNr­P]JåN­›rÂ¥ÉísîSÈUå“lwÀT Þp'6k#ÓÔ]DðÁ‹Äð3ëf„Ä¡0¯µ¼Ë0=kYüA]³¨}‰—r”˜o çï0Ú„TÉçbüÿº%ÉÑ_ .³Þa±a›=ñk·‹8 .{ÐÞ9õ`×OX"(:í ñ[ø*·Vœ/·Pä=waý¿FøtÆÒFŠ2‘U6ôÁ޲5’Œùo7G–í¼â‘+ÚÇ9–ÈÕõÜ{0{;Œ¬bˆê ùäÉYN)S»Ý™³Ôç‹çÌŸþdáÆ'U‹ú‰Ó™q0Ú¨8’i|’#“;gvøœÚÀµbô›\ô6óÑÏaîÉËÄË4ÌÔ)3`äY¤ŒUA.=Öøìoá㽊IÒìzc¬ÈˆÃÀF5`\]Úïo¡'ˆXÖÇ—Ô†ï/ž@°7ꃓÓÔ¿„÷ã¯û]î™­÷T‘ À Ç%ÉR k%îS E‘Íõ™Fî»Úܪá2ˆw ðxq0‰D.%wà‰ ÎÉ [Õ ¨›ƒÉ|Ü5ª ƒEx>Ö®ˆ*JÀ{St¢6s¸sû6Ûûú/ ß7RSõÝw#¨Œ~œÎ_1ì¤CPרtDÎd×âD­ûÈGá݉}ùBüþ¶—ì×ùç>#œ•¹Ç3³Ôäp3z õ"2€›ÒÿD³âX³“Õ{Ÿ ׇ5å»y5ʆiu¶öÍ`‚&;¶kÌD>®W;ˆˆ‚Ö’€€®RÖÝj˜?Ëð6f @µ©‰M¬™Ùõ{´‚ÜšÁ¾Ÿ¸ö±¼¨#“9÷ñߪ_Ptôš²‚JÂr³û;WxqÔÀŠ Œuúµ¤»>{‡/csr©‰z !îMº'‘Û; %= Jµä…ÚëÉwó¶,ÿ©n,<Š tÁÖü›Ï ú*¡b gÛ:í»XH‚¹¹þÎÙ&ˆ$îÑ¡w‹oaY”‡ø–{ÑÉù¬O´ÂjïŒD»0§7ÉØåŽõg|‰-XŒp%RGÖÌîï{–°„_µ9ðnfÑÖîí' % 1™U‡ºGZXG“v« ú•;Ñc…¸± 3( ¸v§ê^Ò6e“^ej›ë2E'}¶%¨r;à„øÕ¤MIþ]Iˆh×9dgxZ½”xI¹·falU 2Ϭuˆ3W+D˜Ï=Ÿ3i–dÔƒžþó€æ;ËVŒ­ À]’Éq¥º…Ã8b6 ø¶7 J‰`´!3Ò²èÓI«E§|ð_À™©¤7±à±ß•"Ôddt¿¶b”á®S[‹î„b‘SBÀ¾¢Ð6 €iزt¡@oî,Øœœ'¨ñý¯Z~À`Î Ý+º»q#'/dy\Yá…í'Œ|AA+y¿DÌÛñ*uÙ¢¥n˜!ÛHiÞrî½Ç­ïžè?µBã Ú­=X.ÝvúCNä×Å,©è1а0'h쥲J5üMQU¡¡6Ýô&þQúŽ Köà3zZ² P#oWßÄ-¯Ó àè‹Y^F”âY’±–‘Iê°hÙP¯<·ÚÂì9@4q%NÊ(BYÕ³SOv y½'—RÁ&ùU _/roM¤±+Œ$  !ð0ô3¤¼Z[Ë}¶øÁ¸æ¸äŽËÑ„µUá‰Ã—$XÔ}Ÿ9©iÑ|BŠvp®¸ºÓwÆ%^˜0Îòm'áÔ [Z³CP³á¥ä<ËcqŽÂÞíC‚V04&ú€çÖò.À¨`†rŸ!:sBÏOÌ›Ÿ¹áîdIüÿ;Dl$@îb"+šAûC|/tu¾‚ ZíjâpXQ_Ë`Œy&UÝ\ÊØ H†vÿÕÎdž‘F—H4ì,¿žöï´]Aü®^Ĭõ ÉTƒ^Ú‹°Ž¶)Á•u>Œ·QÿVŒqiœ·J¯&RÑg òà(NF;€ É8¼4”\q΂ ZÅ@ü,~Ð}!Ò–¬¯ëEIÚì¿™MÃêþ” (ÌFËð yD—Fi[ĹšŒ1ŒœàwµG §mý7ðay‘–Ïù¾>¤¨µ”*¸ëoTÖ!y¤ÌÍAð~`¶ê´ŸpÖ#ù´ÆÀ±Z S—±ëYë#¹<«¤mއìÔ¢J¤ÑÚÕÝùvf*¨S:]dI}BõÛ彯EçäpU¿c•óÉ:«^¡'Qû{…­c­íúóçØ'¤òÉ}Öz ð±D‘T\Óª±§ŠmZWÚê|óPîø§É6¢d\ˆ©o”Jµ~`¦6µÂ+ÒH!=E';´;]ñg¥žß@ 6…ôÎdÔó_›ÆL;ÊÓä+ÞR4>°0ìzĸVwéâ®y{IƆµÇËÔ±>Ü‹š‰£«žGËn§•ÍÊ¢Iˆù®í®¬¶=W(ù˜ØÍ8‘ÂPª>´çB³Æ=¼šIžìœÞdøCYŒ˜¿•xPÙB9•ZUÆ:yDΓ4§UîÉðŒ•€ÆÇfXñî™Dÿ…ˆÜí:dn?á*Pÿ'¥Åa  š¿;_îFáËôIþõ’€€Ò’}ûJÒàfm³>²Aµ¯ªn žŒX „Ü‹YÉ(XKO DŒþ­a… ÓÏàïpúÚ\uÏA" F{—z–€já*ÙÆÿ7¹«¹¾Yü2ú^—ÓLµ×íäA â6‹á´;BA—ÆÍ^¥HË“Ë\W ¢]ð-¤ƒòsM—Wò1‚>ïøíÑ ÍS:!U´[.O'Ha:îü¦‚úuâ/àeEQM@h­UÄøº;éæåꦸ8˜n8"¼€TRDNÄQ° àùÑç½àჩ,“£¾0Æ ¨m]ie‚Ó»èÕï~ þ[Ùš}¼v 4ã!ºÓÃϸ…å>—§øa„Ý7°WƒÐk¼Èb]Šó6ÌÚ­nÆáO\ìŸ}#ok£ô>Ì´L ½!&I[Ay±.­3ÿ¦ÞW ø2}9e;uR¶e½Pá¶•:›MA*´oZ[jaºù8î‰@qšˆ(ä¯e`<êµN°®C-GdäýVŸcÏQ|õr©OÒ‹ _¤ß'§“KÑ£$C¹t­¢mT#Â:~Ž«Ð¹*—€~Z(÷¡š¦Øîê-€4ì@¹º8ánÃÔà D¹(ŒÛɬ]Ä9• 5·VÞf퇠v=w4Ñu¯DyHkRÌá-’Þþ,ÐÿqŠqöyð]-Ž?Q€UD½7K=ˆ‹î/Yîå{·¾"2/ùk‡\8}¶|ccz¶§­O ±·1Zå"B®IXñ¦h:í]Šä$M•m©û Ä7¦B%ÓÓº=ï;÷îy¸[}¬J9 ú€'x}Œ'xFácV¹;ÑŽS»oêÄO¨/{àE/ï [ÑúÞ†ó7o}QÂóêQ¦¿`ŸzÊkD,'%‚8ùnRý3º¥øóo›….aƒµó<ˆáJF«È[Kðkè‰Ì m.H8ÀÑ q‹Ïn€sÔ3:P>6—I\•˜Î ÔdE÷äÉ jý•Jl0KùДÞ(ŒrÏÓ¹¬]( œ´ÌùW^Ìð¿\W â»2¬'LÙ§O€¾¶smßÁ³©™¬¹lYßš(|ÉOØhž@úñón;ESMóLàcDHÛÞÒ6ìôöS¶·Ì]òÑ#å“)Ú§×nóÓûž˜uhÐ’a µo£–GQsu"_¨’€€¢Ÿ ÇxË«Ò ‡1so&c~%¾É.ª¿+wø…L4ƒÆ¼Ü8¥1Ö‡boüò0šDñ{§g«~ç2ië Ë‹}œpQ:rx&÷Ǥ½Gâ:ãLÂ@l†«“T¯¥bùq˜ÞMjžN¬D,¯ ûw¹¡Kø˳ñKXò+ä¥Ì®ƒûx) ;;«,IJ>á/,›´ 1CP`AštÉS"òtÕ(Ú²Á»,ùØHõÀÄ:$?͇À†…‡I%8]ÆwÓ×’ŠTX .†kDžQῸljhn€)¢ºDP>ºø‹4Ê¥¤‘ƒém\¨Oc"xø².MnæúR„¸›·èíô5ƉI–ÆÅ!„W…XÒ¶v!5ΊxY×4»sdÃô4\‚-Õê¹ìR—Xô9Vi)ö’‹šdâÖÃw®v(ÑàáüÒÑû1ÀWýèå:Д sPŸö§ßäs«Œ’ÛߺaÀŽâÞYìè ¯É¶ˆ½À’u´7rÍ÷8¦MŠONæ¹|ŸÕ)xTÍ ü—ñFú«‚fçÏH™`°5Cµ×·AyMUµp w ðißÇ›2Öœ_ð ú@6©®ÛÅký:ÐÅJ©æQª¥Èî~kZ©2RT˸ÛW#ê'­Ê­Óú…WO±‚»ÝOë‘tÝ€¿³Ç‘ÍoË$ª¨f߯IY”R ¬8ión_5 Ó÷Q;Jóh)Rì¥ý4ûM#¯˜eÝë Û¿"ÊÂ2PO!Ãð]Øöyœp’ê[äÓ»«q+ÇãÜ,Û÷i¢k¸/"þ|^lºƒÞmy¬–²ì\Æ6]¹JëÉÝÀß·Ë ­p{å3†¢¬/ôÏ]°§øg½c…+EæÔª1Ú[à·!×ûYÔ‰¬ØZ?Hn÷OØ€&hb¶¯øÒ³Í³‚µ™žF|$ \ïž**d¿>~ò…*EžÊIÐÜÓÓ–^¡ÂÌÈH*8ãCéÆ%E1c]1°÷}»p…Cš‡&¢#kwÙйsæWAˆ³þÞ«Í&I†uŸ| aŸ[C†VñÌë÷± Ý»ªLÒdñJBÚÁ‰JÃ~ ‹i¥À¿î¶_Ï`48ˆQÓ\zÒ‡€y- ÝE]42ç¼ÝvÿCU­F“6h”>àCNµ¾†"kaxk–8ê’€€¾úHˆûDó •L³Ìp ãZD,°,I‰ö¶-£Lºèg›«íC—9ÀŸåJÑŒ R^hÌ(†¿z+|G—ùØð¨Ã|;éhÌ×ΜÀmãÊ)+‡×Ü~Dýà«.²“*¨åˆõ¼4tû3/ P­¶‚™‚ëÕ¡Î)„6uœl­´1ñÆš£…‘G~ô^jÎf¥MVôµþý"~áŸïPtP†€IU›çõ…½SœëðžÓë(jVü¼’ÔrrmÈäC‡ʼn>—ûZ¢i4ÙŸÅã™ à§iÆ9~¹f —ÚñD™²47§Ð¿Èo­È¥e­y÷UÔ¢+=}K§´f¸ˆÔ>ßÚÝ$vdPHäÙõ}}®óºÔGñ“¤s˜nÑ/XE’ öõLïžÁ4ãå¬{¾`»¯Ç£â³Ý[í—ø—‡rÔØ[Z9 G’€€ÇuÞå/Tâ¶èeö¤(Äþé:`~ûõýLWß'Š|{æ³´}>xMøîÜ84“Ì ň KÜ/û”X'š5«Ô¾jþÂ3šáI¥‡È£Aw .^ *0¥`Õæ~ìTü2›œï=ˤÛK½–5Â’«òBS]åM Ïˆü±×ÿ…È;làUÈå),©ŸÊ?â”äp Ž„|´oÕ;àìÈúŽ×⿤»TÑ6Èh’ aÇ6°#KA 'ϵÚxÁ-˜àÐ%­Þ2Oæ9º­¿Ç.pÚÌ'Þ ÷ :Iþ<ÉΣŽì‹®nêÒ•u‘"pDùlÆÃ´:Ó¢¹N¯ˆÛ‡œîþ÷À¦r&^9þ6¬':_ÄZœ[ùKn]sýOP :8l+®œ[/«t¤Ñ¼Œø½V FBÿe²hÿ·%AÌó Cx“";ÍQ4ïl¶À -íÐòà0ã­PÏ=SPÛ­å÷©Ž­ÛJ%• ‚ñPeE'Ø8 †>)à!ÞÐhЀ Ò$‰È$Ïß<'ÊŸ:mãh¹+Z¼œì ñkÑT³sòQ;«`ÉIÓˆK0ßÙ“ýå>ײº;*&H}R <²N”¤¢)Ç}L1¿u\©U)3(‹ò:ÑÙðB8 é]°÷ÿ-üKÃ"±ÿVÛÑ7Ÿ6£¬g†}»Ú8~—Æg­ êùÌÍÙ1„ƒse@0·|2ï õí…àƒ>Ä@M”Ïÿ!ÂõÚŠM7˜rб‘«^×>o€÷ÄTì€ò/9efÄWi?åƒ|£Æp@@ºÌþb5/±8µóµ_È$¼¹6KÒ¸æ£X7/Ú?ðGõÏBéîQ,,Àåü)¶)ÛÒ‰‰žÖÉOX®~›ãŽ(„<ßrøfÿOjúŒh ÇÈ!1Œ¿tY ®a¹TÛ‚!UüüÇ[jað–âÌBOËj#eÈL¡Lµ 5 ª*c¯ƒ@ ¢5ÍK3Å„·êȶÖ×`‰GUÛŒ"•S_¦?Ó©ü*;é¯ †1-–¯¿R÷ìKѪír-ô½Ð&‹Š”›ÑbР• Í”#r’™Ã‡·¬ŠƒÎ ƒ©^mÚª•AX?€«@€R¦«­–Ÿðkmõan®kVTŇ?eÕ’€€²þ•‹òö7ÙñŒóßñÙá5¥VZE¶y~ª#ýð©VEðøZw=Â*»0¡”JQŒ»3²@¶ÔÜùruï}q%'kÏ`k\ºàé…yöÈe¸«hî7¯ò?ìÁ…C¦ŽC í6sùlK,£ "Ç`›¬i—êVÑ‚ãÐe½Þ= ÷º…æå ù$&+=™Þó²LxEc¹Gâi”<1ÀL‚[¨‚ ŽüÓËkTó²ƒ3Y¾=mäÈ‹·í¹³lmûMBÂÁƒ¦¯Ñï¿áÇÝwRâåå>YŽÞˆxVm>-J®e‘6Ï"[óðg35…;ÆáËâc>g¦&¬°ÆêÓB$Ö.B'v¹{X¤0Ù;ló“£j¤{ˆT#‡šD !ÒeÅ žØw` >Àjvnkï…¢±UžÀ«)*Í쳺;“(%™YúÃ}o2¯«¦"Šëýã®§É–Nô”À,hv+¼ /´bnxOÓà3Ë?˺Ý\d;~ƒÙÓ‹Tmâ´Y•*Ò›N.¶_ 6ˆä§мÜTÊPáø7¸Š¦ÀõÌ«4JP| F¹Šƒã=z€úhÿÆÇìÓ?$­‘Ud-`DLæP°p“Oµµ[ÇÒ!»u'­ý‡9èhžù¡¶ä×”?³B—ùzú¤N‰]|"áÆwMz'˜¯l×ÊîJXÌôalcaаV!ÏìÿÈ*EbÎ À-БµV®RÕWòäÃÖ7“ÄqBx†xá¥B-‰é{0Z”ÄSÏ9ÅI&pƒµÀ“†SþC‘ïŠù5zjïêp}äÁ¤ö "«èØšÉÃ(Ÿ‰9á|b¬¶|p 'ÿ5bÀÊë`’€€ÁxËCm‘5a‹%³æ¿)«Ü#Ú.›1³¼RÓ9ôˆd‡òÅGùÇË[_Ì3ã6>E~ë{´ir讇}ižB1wÙßYWÇ^»ð{þ¹(¡vgÓæcl‘’¨t*þ\õKýh˜u$®Œá‰Ä L:ý4ŽjÐ삃<ª«/AlÓ?-W=> ³Fº!€Q;z5'õf zÓM$ x¦Ú˜V×î[Z ȱ­`íR• Pœ„&&Œ«^˜·ÄF%Æü(Eæ½hIžq3…·>¶ñ^Ö‘I3ðvô û+^l7¹ðív~«K.Í›Á,V:í—1`zc[·e¤f<}Sœ™Õ&d›Æ§i’Iƒnc8Ôeú-üÂx“?æÊçý,2.¶u·Ð$¼cA7k¯‹y2HÈw̦øð‹‚¨ iw­¨@løbng××ÒìÑ1µ?lMY®yˆ9Ï”· 8¾‹õabþÞÞB„fï£ò`¼ õºy3¶«Ìžmù‚ÝCò8/Ë7joƒrb¼pô­7©¶ Nð v“&«äoòºlÎÎÈ#>]IDZÙUjj×TÝÁîꮢÖëž%Ø·qé0ðêNŽfSUor+i.pMË“há ,âWÊ ªi„b·w¹ç£ [¬ƒ|ÙïîygŠé>à6%ã PìŽè0ë¿CÊž6øhxÆ=ö6CÞh Ïv«d˜gX’MG¨c¤wÂõÌRÝØ< Ö­H#‡ŸHç5¨ãBíG7Ñz(³¯Ý°q•’zçD_,¡Íoup®-¥ki¯Õä¡BúÜ*#ïÓc`J>‹˜A°zq ~]Ÿp­±’™QÈl]ã2znÑb7†Lt5¼Ž·Â0]GBÇŒ¥ ïY<ö9Ê·0ÂEPÒ@>W½ÜMb·\¡%êŸ>r“ƒrÏìÒ Ç@$„7ÖÂúKoØl†ÀMã‰6çV¨|™ Í“/·Èm¹:>á„Oõñ/Š×9¡|Ê Vª eÎ;Y­öõñ§* ìÕ”oŸÊ‘)¯ÚL¨t°±ðùéíÚøë®OMÁ溊eûP¯G+í7[öOÄ7—þÜ÷ÄM°ŸÞ»Þ¢/&ä-? íˆëÔQvYO#æîÅÓÏ&m½?*’€€¡’/^=ô€Çîb\3L…DÒ·Ù‚¤î^E>$zì6$"¸-æ+ìqñeÿ^¶|Ç(X«ð¦5>½.„®NhHê}”f²,DR®–ãÓDÓ?Â{Z@ãÇZLû饼OBœº_\e†Nð^;èìW7qÄ6Ð­Š¨ALÛ)‰N`¤Ž©!ÃJ÷›vú›¯Â’%|Nƒ™$#»uWž*Â'|wŽN»™ŒŒPŠÚ³Ç}/$N5“ÝÞ‘îÙ,4¯J±ïc$n±ϬðIužùqýwQæ‡}‰ùVÃDžç!ûñ×)`N‚w6§Ÿ-î®ãºð¢ê´ ‰@:·8kš¤Ëg«6d)ü™%¦n¸º7ôcÀæ{9?äÄP5‹ãN W{ ª`Ï(Ú˜MëWmêŒø9p…gb"o> JžNTà¯á€Ÿò¢Ñå9`ÅÔ)éðá%øBØEçú”h}U¥=ê‘ Ö¬D}aåz)‘ü%ôk2ÐW´´DŠÜl›ß¤Š…Ýg™Ç¥¢OØú¥ÌGÄÊFx›gàbåQ™¸„=úE^àR«5Œ‘‘…è5ýôv‡“ž1¾g aG7¤{Œ ¨¾)ÍÍôVÇÅ£®‡ëƒ~Á' çdñFIh¨~éRcæO²0‚ÜéŠÑG·ÈÿMéXÚRUme]ó÷w¿¤Œº†uë#ðñÖñ÷¦èƒÓéb•æò½Mx3ª4GÝðãÆÈ({)ÛZÓáPg4Â:~r/”tÕ y4êRv¥ÈµÐP«+8Ÿ(CRÁ‘öÒuž5>dÎþ9¯ƒ*^6;ÅâÈÁ9@SçqÑîMf¸rÍYÅ4óqgª# .Ÿé•(j¨¾ è*ëQ^|¯ÓCr/¹^©ñŠ _l_†ÒÊðZ‘>oÜ)ȶ™ '*ÝFrPC›ž½­z†ä¹+N`S:, à”VW Q!à R°mµ¾ q˜È¿ÕWå2uïAÁœã+å›ôí5 „Ó÷$=ñÇÃ>°<:iêV$…ç…î~erªL–™‹x·27M·èÐ¥ÁœšX` ”³ÍfŠÁÞDgÕ<ƶ·}ck¯¨`§ºe`¶¾ïš+Wõør˶…l±\ù–sýÇi½‡4’€€ºÄvÆ´þÞª²ÌžîP'(m °@|þ¬z'“ãÛx°}ù( ªò¾^hŠˆ À7‹IîÜV/§¢÷èV’K_îÇ;yïü¨šQ«;‰Fë.…è¼ÉÐ_ÊHN¶»xïÊúy˜§ÿ¡$ÇX¦'uˆI"VòE»àK9¥¾…¾V©"*V€’,Yý.ƒ3iøü/G!÷X¾z ~ê9÷Qô•È|@2Ùmù™ŠC¤Þ‡ ìÌ1&»8a3gDÀrVß©°6Qç¸s^”… X­Œâ1Ô&3 &×>°@b´8Ìh–²9·¼s6=}3'³GÂ+NÚ\HUhôƒþ¿Õ¢,Ž©„´¡Lÿ +Ôô ÒYÑÒUbNÉ?á¨wgù<véÏc—¸O%V_š÷"Còg2e?8&îkbwÚ~¦hˆ¾€¢G88 ‘ÎA¡ä<–Æl¬@-qûø¦5@»±}#½åŠŒH%Ô%ãô ‰ÛÈI¦Rå½¡ÎØßtŠØªÊ×ãµÍÒÃ`,çÔm+*C}úàâýâ|$fç÷Þ{­v¤ÌW d‚â³kÄ^düÎXÒÖ“Ì©ù0úkÀwé¼¹ È­TïRj£(ËŠ¡jP½ÄüŠÀo™TL5&¼í“aÚvsñua7Œ("Ð0fmòÅŠux˜€È ?ÏóÃ… ½ñzÚ—™ä¥†uÁ¯Ïrh×?ñ&-BÔµÒY7p·ÅY4`EÁLß‘Õ&~"hÁÿÅ‚odt¶ ^è÷†úôørÈ>±ˆ“¯[¥^ÔÛ$…HXhöS‚p²ª0o·g¿xßñ1%΋W‘O0ݬ ùXâÍš˜‚ â?ÖÑÑ¥ÄêNÒPî„é¡yáÁ£ÕaaÓž•¿ûW×§bOk€ÝÈ2—?(çŸûêüQјæšÜþ`ÕÙÖ› <±þRDèTc»åÏÀ:nÔÔûLt¶æ$|óJû.4¬?1¾døì± ÛýühUú.BòP拺 o-ÆL6ÂHŽ©¼ücÜ> ^ò4#ª÷îoÁ¢mD’€€¶€_¨ Oi¾½b9IÂ>gDh+PLkWðKÇNb>‹d×kéXÑÝj?^•±iis¾%i‘4aXM +Á§‹¬\’ Þäd85b8@°F+ÃÍÛ‡Mžªô© °m{ZO¹ˆê 2+æfíz¶h«>9éfàöE:³fË“êêzZÿöœYøfTˆø‚Ûò Ô•Âç,˜ã0íçzPÿhG*MA§Ú ȥʔÎôÁ¨uDµ‡IöÇ1d&̬:5«—Nܨ}ËÏÉ<‚tU>Nä{7<Ý‘m\f;ÉY¸UHzÒ8 t’Ã÷äÏLË›Çݺî  ͇NáB}ØàõMOË['*V“]˹—Ñ—£Œ"|å¸BÓ ˆ¨Lçˆ+n.m‡¦V•¨«e2´ÉÍBà Ñèc§2!÷îMdƒÕl³‚6À’OÎøvãáyeXÌ@ƒ'2;¡ï½û D.g"+{G=‰ã”’CÑݸðwN_t¬f„ôÛÆ¶äbÏ·]×¢cQÊvI"«C{ŽEW £DÑMÆ}ÚÉõ§5€Ï±^è7@')tè7¥RÀX0ãÇä„ã»sY§+ê]…!ÆŽSpâ×Z=n3¨áHçPŸI­5[±#Ü ½U•} @ò™±¯²å I(M˜v¶)»\½ ñ8l-ŽqŸ;ººâû?Ïú$鈪ҶÃ%,¡¡YáþJÚ©$‹q¹QuEesÔá r°‚|ª±Hø3 ’€€ËoWÄ£H¹!'_Ô“õe*¾lªäBJ×í6 Cÿ—ýFb$Je”öŠÚ£]sõšÕ¦;¬y7«µ{}ñ›ÖT䔇u~mæ!zx‚ë<Ž*|qH àÑë Šð[üUœˆUòýÅ/Vð/ÁTä_Ó5¨@´¨¦3ì&ÞLw:×(0üÌÝ,5€nBMH× ÌIFR+ªwÉç«JÒ¼T5dçN\&·û5|×9DáÊšq[Ήótkæ.î³+[F§†{Hµ¿-ÑF©›ÚÕ ªºž#ÁwG†p¦G’Qºv¿½5ˆKÀ¤t;"À@Çk,¤)µy/Ö[á`GK×ááG)Iº¥ ³ÏÉPvY똩lq«ÅøÝ•Ëð°Î:¾È`µ{6 ½ËûHµ<ÏêiÁ ¬òñFˆ|ÎO‚šo.‰wJlŸ¥]2P¡3Ó;t]GŸí,ñ"áqOúÙ­¦®r¨ ìø.C(œÆÎОú²R9ZÀLñ©‚8‡ì¹PtÕšÜDË=âÉù)–[ãËN„Ò²e·²ÉF=c‹¿Ž_©H…Q—Ô &@ßšienKÍ…5<_oáî˜ýd²pDÅFu÷bD•R2 wlÙHšw¼—#ƒüÔ&Ueô,Ü6Ö0'íKÈ`4îxµÓ êéÌ %+\ÉõÙiÉcùr.ZÝìhõÊöþÜ‚ÿNsÚžhrK|Þ—”«*£8–/M‘<ð‰¶ôÌ@°ÑM€vóiÌykã¼kPLL¢R0Iɧª:àºIÃï-ù)ÌÿBîmh[¡oûü'…Ð8¨ž>ßÕýÕt¹xÔ>üQIvÓ퀙ÓÕñâÂð³«>ÿºv.R¿:MÂà[¿[ÜØó§Î¼<Ö0íÂ2Ââ¡Mj½TåÇLç7m|5•ª›sCçœå­ %óö˜Žæƒ]o£-ÿ¶v¡ÔbíÁ5Û}ëF®`%Ùešs®V·ë-9§mÃ&š6  Á„ö‰wÍ:;ºà,cÓ %;Ð)CB¥:™üï` ÀÚ·bºßUktgæöK[O{Ö¶o ›Ÿr/•^°Q Ñ“Iì϶pÞµ•YÄ/w?1þa¤7]OÙ)÷t‡‹Øútì r&â"…]£÷ èç­ø1(Èq ç²D¶" Îw’€€È†Ã+S[°aBL0õF•C¯8g£ÝyÅOë<Ìï 3ã¹ÆjÔžqªwSeºõa2MnÕ$fš’·‘XŸ,½ ²Å[23ý©_Ò}2ÌhZj_¡EõÒt6‚ŸŠ·V{‘Ykü«ÊLÝ´|ãöp°¼Doc±XØÝ\åÈ#Ü—AŸÌylПÙã0RÔÉ€¤k€ÅÝøÌ°¬C°“êmPSß$f:5‰—ÏG²œ,ÂÜê›ÄvÛTâ¿Øbíú:ûWCÎx)ÛíX;¼U;¬æ¨Áxæ ÿ¢_'[ʳËkQÌœ°õ…¬¬ñ ûU#1:h¥E[R†^YA&ÍÚÆé~‰Dd»Ù'^QB€§>!…·€Kù@ÑqfÁþíÙ>øßz3±ÎË “æ#Øi=H` ÐØT‹¸)çÁ<Kòí4‰÷^IŒ…&â›ê[?›‰^i1׿åÏ~j@+CX¹™b¯ ½þ\…£kt`;B¯L¢áÚyœNÊXð+Bº¢¦ÎXÌZ>™kPne&æSŒº…DÙ£YL0å¸ö7‹jF´›1NJÐ>φöüâ·“”„bLÍÔ¦Nb ¢Wb̘lÈñ’€€¯þÕùÝdÐùŸÆÿãDñG«ùYouKOà|oPŽK¢)‹‘fZo‹Ûk‰²?É^°éÞm›Rf ª‰P¨Gg¿Ÿj·%&wð<:ŒI¾;!à,ÊG—´'ßUwìhf`ÿ¬šJ]þ-qñÑÙ…·Iù¡ «y³x\{ÓST ˆ®ܨþʹ€>6­xÓè(VrÚÑ»~wº=dzV£SÝÒ¼.ì壳ýí'—+3$a©¢QL8§¡‚^5D‡<óöþP•~Óqé)ù7ˆƒ‡‰´—RM¼íÈbÓMo†óä´Ñážm˜«D ‘ÿþùä=µ‚±i !^†©²½ÕS§Á6'Áûòü©Åg;÷}’€€äE•$ɦ"y9Yºª’Ÿ^`Íëo5%Xùó,ìÇTSä‚ÞUÊLûÝP“«é‹=^“TO¢“nZùF™ýxîͦ¹Ÿî3œ2F¯Þq¤Ïî|Aë2 €r£L§Ô׎Úu5 ´Ïèõä´&ÍQ Œ?õ î¯ý·á[&wJâµP–0³u”l¨š-8$Œ’­Ö!‚Ð %I>ƒàγïYª¹4¡jý7Lÿé)c(—ÅÇ1Á†Ú)Û`-o8T“½$í+FBHäiïP\³±@½˜RÔÑOÍá %f‰ÕöJè¤0ð–e¬qû èkæŸúÆÛ%1›ýx°¬ëxK4ÙR׋RÅú #°ªõZ%€6×~/¶„ð;Ý¡úp<³ÑvyÀ‘âäêÌö„¹_#&æ”[=,o˜´ “=Î07Ò¥Ä I¤=|^F­£^™€—®E.×{)ü«3Ðçnû@4çÿxÄ’ÝÜ ¥~»¼*PY¤"‚k'plQê+ØË0H±c6* .xwyB°o&{vþÑy¨€çmêÛœÃè—· )ï,C>ÞÅF³¥g„,ÅÂíŽ*Þôýcé J¹vab'æü^ Qži|?‘ÇHH‡ì$öñ@Üé½N:⼘k¨åÃÊOw]øë·/‚(˜j4šv±ÜWóWò!Jï 8\eÿZÐ]GD OöƒqQ6E?zä¸þõy°‰0¥?T|„Oö¦©_ñn±N3s5«8ñyâ óÂ÷B\QŠÞÓÇ€%Á˜m§«Û²Í ³9úaœlvnƒq›ý¦Âª÷…ç»×MêÇè.²ìÞ«ÖŠïò0ÞaÞç› Xä’€£0åŽ'Ä ‘‚ç~;ƒ†UFD`¢ÁZFj¡ãœ îÁéT}…Þ8™g÷ÊŸ%¼°Ë––™È¾;ŽÙb¡eÃøg­_&²T&ºzgè0XÁü„+´m³ÿšæ›4³&æ 'Ù÷ã=ŒÁÁ¼SìÌÛ}É.¯}›s?C}&àšðäÞ ã³ÓŒà=«H ¼Ê†Š–ùËúɘ tÑ^…sp6{pÐY¿â„¬">´a½¸‰áЈ¹ëÜóþ»“ÃJæé’ü…“PWb)+–±¥Ù)UW† 1,•€?úMg¬Žè˜-’€€²±Œp§°û¡TîWл9ËŽSïT 讳îé„ш‘ öóÙ 펢6¶ÕLÖÏ-A« .©tß™÷wHfn.4=°fö5o2³=¹®‰Ý•e±ü ¤Œ¡ÜÉÙ#uQŸÁmæúÚX²“Ü€•ª>Êô…< ¤~?ñ±AµÅ@+ŽüV¬|éQˆnj€@B¿/´wÝB-§J[ÚWcìåLÂñõ䀨T\ÚEc°Ðüqw` ÐåüÌ?oÉ3²†H^@1¨Èœ ‹ÊSTèotš­ÌKB@S Ÿ ý4Õà>Ë©"O§ÿ‡öj€üÛÿFT‚L<†IN"çb÷¤ï°*ÝX×ìÑØ¼âS­ÅºjŸQR<Å8‚`ÑFmfSQ5×_CË ŠSAXìÃAzO¯°Wº^XI‚Z˜­ÑD4[jãX×QlË¥Þ„ÓìrdBÒÒŽCÝ]šWµðNí…™'"wYÓ¾a3Iz¤É©WÊ„m'úDüýZ£Ãó$cãȱ±¼¥dp¡7+±P°V“ÿê9C#¨y¨Z\‡ã¯Š0ÑÍݰҫ0í$[ž|s¸djÿ!»ö:¨êä\éTÌR¬žŽˆ11îÑw†,W‹5ÿ_QF3fâ–œÝcTIÛ[ea=—Q÷ÇF_YõÕî9x(6.,Õǽ1|zÿ RÕìd« ’'Óõó³x/©º.-“±ÇÛ9ƒÛ˜7¡Û=Œ0 Áa€ëí’óp% Q3†GïŒbÅôñ‘ÄsQ×ÍÜÁ“ 1™Øè1MÄðš’Ó¤*ü9'{°½·>G™Ð‹7^}vùX1ðo¦Y?cë{·™Nƒ­2ç­PþF…/øÖ…¢hk\Õú$x' >¡=#Y„åÇêĦ:Z*¨Ô©ýê+»ßs™ ê^™º'äÄÛÁðÅO1¹ø8¬§• ñÊÞ‰qX˃.#À¶¼S Ž¾ ¥Æh!dWD—øb{+” ×nûf ¯Eji>s¹·"d XW!ä¤hA)<*>€Ë¡t=ÓŠŸo‡l§÷­/óý¡4€Ex+ñ˜¢“r{Ã]PeÖQô$ãZÏNÎ\¾Ø3¶gàc•_ñe?á6B.ŒÙ¸ ³Ä±ï¯SL£MâB5T “’€€³#3.OûúþΈ•:fâóp^¢7¹mš›ðyaEyâ2óoA /Ã`gŸÓ](½,Àã92•ÿZº mS2žòJ3”ÿx9ô¥*¥x(k¬ Ùî²<—éQ~•Gå4Cƒ^Z3RAcÒ°# 7¹•.FuþîbZü2÷ Ë W9,:lŽUnExº¾|gòÑ,yu‹€C,j¸»þÙÊö¢]Οå»côËV}ø?Zµ{ùQµÍ[L¦ëÍÎÐ%‡9 ejüó_§àÁÃN"x@oÔJ¶’ÒHHPl cËX·é¢Ò›½ÃÇ4\f‚Îâ3ßS¥«Þc + 'Ä%•畳Q~ÈÕîQ&Z  vFLMC€{/ÇfAáü '%ˆ¿²Zn+”¬1àðç£~¨0ËÀa|È“ì‹`»xè’W@:’u'%ž¾IvHÖ—T×5¹­âü¹š_‡î‹%î¨\³í’¯Å³-ûŒ`ëèÎA®Úvóå/‚†Ôê&F¯ü6àïnJÄ~Ksyj ÁëtÒqA < ïFظÀ{eJÈ쌶‡t~Vg)õ™­.Û"þ°7¡“Å7šJÒmU£KÉÌŸÓŠ…>Ÿ;Wùº*³–©|wïÇyèç ®^÷Ðd÷.²7°ÖabˆðjÌ•R¾.ùŸa#K“GŽø„¦|êîx«ÙC‡îò²µÂÄo/4Ú/ù'ãäC³²fKU8;B)ã^Ý;ä*C7Ç*|àmÊÑ¢ÓµÈ(7ÚçO;¿j“FÎäª l”’€€Æ¼a€«Bûtj© ¤¶xåÍ€˦û^ÏAýÕ« µsÙõoj¦FE¤#Û>Žc5øì Ù¬ fæç•¡cë›TÐaf±£Ü[뎻'ö*ºµº½ËRÊââòdŸÓQäqMÈŒ1cõ ÇSÐÂäÊS­G‚c3°9vˆžL,à94ß_ø†¿B5­Ùjü3Ü+“µäÑoî‘þ϶ ²¥s‰‰4ØŒ6[›ÿÖ+P–·Á 1D±e@Æ)²a ~GX›Ã7ÿ†÷"€^÷ñâc:\/)ç¿Tõƒ²: ´]¿Šà:Jò) 8»þdÌiÔ_î÷BѼò¢9@`˸úp(aeâ£ÚVR:ª¯öÚUÖ³rã?n†»Ñ^zs"r¡\CÁóUj­ñyjÚNi¼·ˆSkdGÂ?‘‘½.ADXC±³æ,–‚ä c/ì6"‰¾WUÍ®di{kΪHåç¾_¦ .š­ˆTjDl¦¯Û™®MÓÔ‡Q­ž³^ïÜ)ƒW£¢ÇwxLïø[ö¦w™`Ë:“÷Š!#»×l÷–)…ðÐd¢µ[=ÊbãŸÍu$kz²*è§–ï>t˜B$êTi„PQC…½¥v›xa…"R½ ‡vžóô!à^•ä†èfã” ¤ûüp?*ë4Ëà.æÒ}Eyævó¤j³}u½\˜ql‘ðE×Ëv,LéOèà ?ÀË}LÍ"ìó6ÐØ3â=+Ïœ#´+¬ÑÔµ·ËTôQ¿ôóþ_dy¶ìXú+ý&y– ³¥ª=°spÉ„\»Ydj>È3æœaÚê^Z¨¹øk ¡Ð˜iVÒ^Më \sàï D/S(°r»a˜ÆE²þê#.Ͼ¢åQÚc¼ Û„·„4üEh¾gCx …ʦ°4Ñ.³×©]³ ùÍTØmbÛïœíÀ€å½]ä!è“é?ĸ‰Ú,öP»¹¼ß4?dP ¸¢ÂÛ×4oÿ¥ÀÊþ %Œ”)S‹n•uÞ„fã±Â˜ï½xdå¦(êÔ=`1@)Ÿ=¤Ÿ|"ðòsºÕ·ä ¢Ç DÒOíÐùZáHl¨A^n€fü™¨aï’ia_€±ü{d&=u|7X¯õ M‹’€€»p^ Óï7´zÁ@oÏkF!é]¥:ÈŸ ˜ þ”±x‡!”Áç;E› ^l¿GH-üÀÿPUêƒë%”T3áìb W˜TÚ¸Ô"eP \ (æZÅfKwн ŸÊÂÞ //žæ…;jÞ­bǎщC•‘1ù6«I b.¹ŒÈuEí訞%¸ñ»ÎÙ˜Y—è߯’Ïô„LŒ¢k³J Óf£WRìÕƒœ „}pÔ®žÝ­¡Q°!þ‘ô«ZÍb+2 ³½}eø§0Œ3ôîˆútSÀܲÒÍ«]ªW[?æŠ|šDŒŽ£ÌÇ»”« ßÔ¾þ·Hž™èk7ðs³è­²ü:„ñR+ó¡þð^ÅÛb©DýQÏn:‰&P ð~”“I¼šsÉ™“zGm5@É™=h~ ±nŒðÍyöÅHÍ‚  •õí¾ ~×ñ8 °¬Æq‡È™viÏÂG±Û—‘gSªÿoû› v,Ã^1f‰»w*!Õ3º8Yæ:gZÞ40v{±ÜpöÔÑpÊ]f5M€Ñ >­áªµ“g¿Œ »B´SÏ/‰wÅdÔ¶K´x$FÿÜÔßÄ §Ýë7•BÃâÓÅã„zpy͹&­ÄÜîñ`e;RNCQªª¼ äˆÒ¹0­ò¦Å/]¼â:öÊ<”T¯¶¥:›í/ƒ†LÿL£Ñ‡"Xíâ;Á•Í…[oZÔ%@ú–× ÑÚ2Q , ß2ÝVלɎL_Ëñtô¾œÙ¼:™U÷øY’p àÙN‹]x¯]•ñ8©Üxj—¦n´á ­Ë <‡›_¦Q¼(×¾ÀÜ—bvå´fy¥œ%ë#« ^k–1¹n,3Š”u’­‘"©«qY‘±aŠwÇÝ% r1’€€¼¹«TŒ€Fd6O÷xôRs€JmÆ\="Ä6™D³°^ÀûÇÃoÕïçŒ-²åjgX™zû?˜0"Ž#4GˆʇjRZÇOBŒË³^›úÓ¿*kÆF¸^èý=­$5Ò¯'ÔÏá9¾ÉŒÅ)„Â+ÚJ)$Ie"$(ƒ+¦Ô:qа›^Ú´4 ë‘m£Úì|¦Uz‘§¼Î_ÂЖ•·’¥G«Šp¬e€:ñ3µ5+:iÊoÌ} Eá¡û`ÏPžkÃú_¦AR‰XXòΚëƒjÔ·èÐõÎ2)…x„¤ù¾ùG £bøkH-Lœá ܸif á;üÌP8Úï_‡n4{h!v¯âß›«s–+¯zAôë‰6úp#Éâ-eQö[üYb ¹©‰Fíx8˽ÿ9Pú!Sa¾Â”›LiLj5ˆaÈêAo¸“ˮĭ!‰žzî²¢ž¦¸p‚¦˜ºb ò$‚Ë$5îuïq$Ør•|C |”źHРfÕè^I⟤ý k}pW°7WßeìÀ‘ûÖ‹7£ï¬¡ºÅt@„£IÞnÊ"M´¤ØùSDÖ£ã9»óTwF(‹^Rª½w M“ÛAL3nõn‡0éÈí*ý¨÷„ìzÞ3§ÿ‹æðPÜØpvïõØW|’/¹5W3ö«:,Ø7ö— ”ˆÌ°ú⥷"’€€Â®Ûí×HÇ…f३Œ¢ÁõŸyAé†| AŒ¸Kl}3>CŸÏàƒ”ïàEP,ùþôeÀd±C¨-Ľ u VÞ8cHâdÊ·6Ã]ߪêx§5×’ÙîÏsÊ—Â@Ù~®Ö{`\¦ØÅöJk˜µ¼ô¯ú×sÐÍꯈFîûÇ1´ÒŽÒn=3›|=šSh]Y&j£`ÆŽéWÎfŽaíßž¢­ôÞÀTˆKùˆ‘a·ªky¶ 6p7x´*«ŸîŸ®˜h9¼R°#}x¡g#Úôm½`¿ÙXÿ#Â~6hnºS††"3®‹QèDmrÃÌ@|•XðõRŠÜ3Õ9Ž˜_¹±[!ОʻL0Ød_"À𔸧ãyͰÀ+L|u~ï€pQª¡S+wˆ¶ÌQ˜WÍ­¢Ã+&4¸oC¬ïè(²tnµ5<óñp®ÆÌÆ»6û”ñI¬ªÏd HÔ J]·S6Ýz:ôŒ¿. V[‹Ñ« *7â(“ÒÞ®%†©$KR§å»"‹^ûо™Lˆ©ãÒÁ >Á7d±´ò[{VBzÐúïÙfÍÏר¿K7$o¾Ú¶ëܱӼ¾Ê<’È!:‹¯4:}þÜsJ” ;µª·GXÆ™¢_‘:BZol°Üô‚­8ÆÏ¯¾ù™‰ÿ °µ'Û8µošÎÓlèKs*Q1ã5)4A#å| ¢»ºSÈï² o¡ë³,f&çî'¹ù"[{HãÛ¿©íeYËÂÜ„Övi“2¡w`¤+¤ÌÜÃ7øà ëlÍÎA~¶Q¨ÙÉI9 ‡Æåmgn‰¸>“Æ‹Ãg¸Ö„x>x! m¬7¬çñÇ™”|uÓó‡Ì•*ÇÀ:÷–m¾ôÉDÄöýv΋c»½—Ë¿[aM4î¸ÎDì·%1æ¯ ùžÙêFàö´õ[—´À3è¸ÿ–rD>1î;0A±œd Ÿ)˜jtDVKöÔ˜aòCøÑÏËɎ牢˜”JyÎ:§A©øœD1`‘à $pp»v†//åšr‰ã_K­:tÏу‘Qz•2™IÉ"É}œ»ƒœÁ½œCèŸÆˆáIU8‘ÎP1ÓØ¬äŽ,LI:òü÷®Å…lÒzV.ã ÊLíËŸtº+hÏs ý²’€€°¼éŽ’jB ½rÌés¡ã±Ê±ßƒ®ªV§>Çíì4 AïI™ó ·ñGßÍú@ šEØeÐ^ªIñ] 2c¯mÝû,ÿã’'Ϊù†ß*·5mèÀ{²›cI*Ô,[f[b>Çåž@ÜÖ+Ù Íìù&ÞM“ìéì…£Ì&¼|VîµrÖ›ƒ ˆ†Q´e¿íšÀç:wÀ]€xh̦xü;“Ýçд¿¢€F©i<%΀¼ÓùëþVTË‹ÝÔÝÒýœq¤3Ðû–ä…fëY÷ÿð28ƒuÇm˜Üzd9’R4°ûè¡ú©YØö©i0c û¶ánGHåSa¦øîlræÉ§à÷¼Õ üKR› M¦ÛM²L|ÅÂBfæ.܉ìÑÐ5óóδ9÷@ KNÙmĽàv–F¿gÓ— ç^¯Lr_¢Ÿo;ñ1PwøÇmèÁ¾©ÕÁ_,Kpg¢!4*Mj}Y}†=éfÑ¥´p¡æÄ[°F™Û« õ.š×BÄ”ªÆ—æPÂÄ…xL²’þÀ¶š&´Òa ÚnX°"ÿóTç„Xõ’õK€˜…/˜wç2 A]€ÏÖÄg3@'hë³¼3¤3‡I)9a tÓâLóEÝÀâ…æT’‰™e”c#MWTU\õì>8ç>9Ä+[önÛüÈW±DJe›vM}híxÒ‚8êë[šEy±û>dU¬/™’ñ¶ÑWÖ°§_VºÜš`i»îqQÑÌÂwDçf«#>“tÎ>²Ìü­"ýš$cêž­›‡ðáàRÁÇ¢¶”PÍ¡Ý8]Ì^âã±ËWd5Ã^ËóгÂ[VX_ì]s\&„ 7y5(D™œUæ·è¤ÆïëØy_çŠðúÙ@ø"Ô°;ò/ާ‹@àºH,³Ñ§ÅÝSa„nïå¿®Ùx3ÿ`™³9ÝÍ­kJv•Å}t;—{ý!-ƒçŠrOr3 ¢ªx#&‚±’€€©å¬…cp–¤ö«:Õ¸nÍÙâ’?¦Eísû'’vÆîS–= ˆŸ¸–•KZœ$ü!ã¢äþ¼’ÊÁ$ˆ½ÖµÏIFIù˜·>ðÂ( óx5¹ 7¬áž.!ª!®iÐû÷ðÉ59u¿‚ !`è§[£ZlGáÍÎó¬ìSȹ?ïßÃ;ˆ3>éðõecd1íîRcˆÇöÍ<„˵âäñEÇ>ƒ6m!ZAÏFnÅ Aöå6 $¾e}‚ôm®ùF4ö’à"Mñ|\õyZPëpfÙÞåa<7gSÖXQ‘>¯«8Rq0Ö¼!M‹­ãIÿAK ô$\îˆgsܕ̽ýÿ0H„CøDåß½Òt… Fí,úoI›§_ܲI!3R9…ˆ§Êác;ü´uÓ?ìr& ¢ªJ%'ýüñE¿e Ú±dUÂØèÇñ)âU ÌvÀ?(GûÕÊ6Ú=(fSC  ;Lö,€ƒGÈfÿô­z5†—Z\«—î¦ë¼Ÿ6©3SÝð<¸ƒÎÌ´¸G†r~œ²l|¢µgt}Ý‹ÃË÷ï‚áù‹+ènVNCdÊÕy¤ö¡¦pÂYû 0C.Ä”nC¨†Y1Ť4²¼{ˆ¨'±Œ6ßÑæQ·í A]7•{—J6¿ÙÛhâ¥?§v1 ]¿Ûˆ-hÚ…e×”1ï å˜T‚]–Ü d~h¬ck§†nù!ÿgþctGÄQ¨£š¾äíƒìÔå·hKK¦­g ¤Ýúëkÿi(?{·ólÿÖ5^ìÖ,»k¥MªFÎâ¤jwWåX°à…½a;-j©B,ïÖ¾Öxž>Îm«š žâõø2M¾)^¸«å@rå“7`dLǸ¡UË<g=k.—VŽ÷¬… vfhpç9j&– 'þ"%%x¨H Ü 6C‘£_‰ÙtLSÍû%Id2(Éy0“gŸËîQ·wI?í¬¢Z£w&‘¥ê˜àñ–´œ t´ŠùlR{¯V%[Ï![£ø1´h* ÆíJæ5ѨR¦c TGùb5Ãm’€€ÌQ/u™({ÌV­Âû{ö]Þè×R¬×ûÙTÔãàµ80#<šøïÆ-ž{ÐÓÆ#0¢%Îk¬³%½HÎË«+i*¥×$Ü£á·$4#—àâÞÞWøâÆ¥Ô5À¥*¦º8ËH§/œLB}©þ0Ñ_4­Ïºô:ÄΚS$pÕ÷”uо95â;ç ý·l8¯¸18TAR;6ˆDÙ‰3ó|ÂêÄyªSãÅmTlfe™„‚‡¿ ~—-ׇ¦ÝFÅU^×2B«6™»µG^˜Ç¥ÆG¬¾\j6^SíºOO¿q¿ü-‰B{‡‹£¬´s™dÌ!‹èÞ×Và%C¸Z| O. œË×ÿú¬$ïí=H×T=LÌS: üð4 m0å ÍÀ¿å✠CÐüHì¾1˵í³ú9ÄÑ©@Ñ!Ũý¥ÂäÔcäFÒ—ôö5‚”x_N“û›˜1À´»M~¶]pv>ôçê»UõëJS:wßí­Žï³{’Š£‚- ƒF"‰µ§!â_1Ùg8sÉé^—Ñç 1mnP.%€ð·4î5ˆ0á*‡v'P7ê­Q:¬ðþ-û;¢l°=ÂÎ5ßWÊdJ£¦›\äfï¥9å eò~x¹xm1T<ùLO\ƒøWV¯¢ÅºùyB|Âpóç…N N¶à’£ÊÒ Üo/ïèM_ZŠ@ŸíÓ–Yc–í0H7:¥VÊ~Øìy÷`à2†? ì{jéÖ[Qìø"ó lÁðã—¯Öº™½Ì@ž¤‡'·Æ¨SÙB§ˆëï8´áã‡}»5x‚™¡Eè³P®q…{AðÁo|¤›®BÕŠa¥LcJâÅå|”÷KÐìÀ½‚é~òpvÛüâ{p9lô¼„ Ìqaƒ…9¸ß*rd¨küj~¶*wmR’€€ÅÈu†Þ“ÿ_{ð„) ÚA¸ÑÄ>x¥háŽošOÈ«w~i­>ŽÙòxмÁºU†¿÷‰ãE$žÖ‹[w’ª· )Œ¾Ó84ÝWÅýË»ž1Èï‰T¹Pj™àÑ^/T õ¼ Ø(n«¼#2ñ§< Ö¦èÊCÙB¯³I°r¢ÜR†• L—œã9ÒÜEÕV½ÓEqÀ(_×Ë[ô¿ø ÏÍÜ_zÙz~êœÓ~®åéh«¼^X;HEFëè§PÄcð/Oq…À¯Ð‹HЈh 7 ¿Eå_ôÙ±§õÕÍ͈_;)Æ…=¼NZm¤GL*²ò¦ÎkúÁÒxSVá –“Ê ä´®Æ€9\'TÖÒÉÿ#ÿê~öOÃ1E¯×û’ÇíÍ‹ÛRuæʪíª;Ò ó†?›[VÛÞ Ú[pt7ãÕëHw¶ =àk#F8—VSz=|ÙZ}™~"㱟½òîËÍi®%èâÑ)8ŠAûËÕÆ|Ã`çÍŸn8ÑÓÞáÆÒ'[oבּîÿˆÐ^ÜðÀÞ©/_´ ¾ÿ/xvzþ»P~À§¯z 89³p½Ð áÏ}Wç]Ú8ukŒú©Îm‚Úµ¥ûÚÛãWQo͇Ýi•¾ÄrØuFʰŠtôº?”ðb<})ƒ°Ôçóøý[~‘Ç z|ØpOpèãzÝ?ê ©îñVŒ˜Ë}áÆ0þôe€:µÇØ3ŽÛÿb©}¥hµÂ2±åê|_pÈTežË©:¡¾ÊÇÜ€Å(?`ìL€@)>™C…DÚ€‘¦¶éµNÂWôÀ¦ÃkÄ ¾|äÅÌψŠêE·×\—ñÀ&\’}výo¼5ÝËCÖ…·dfD&°rÎVY€áiû‰B DºnT!õ+M?ÕÀö« <'¹²TíƒÔl¤°j=Yûth»ï†ôÑ;Yf±Ð±heP‘ýÏ4vêõú€jUͰå›Çj´­FÎ{ÿ'â-ïÄüØÒjÇRjž7ò™½ÈJø»ºñŸ!{q4Ï©ä=Ô"[Ç1¶§Z¯<%&v¡tÞ Íˆ9λ+s"y$7õ¡"qó©\èªü,ëð(’"Ȧ¿ ©È|x†~H¼)  Êô]@Až)Õ'êPQ’É0/ðéê:^ôÎlµ5Ü@¤ÖAQôì«îñ ø`<ûb”E…û™ ¹Akéʰ®†Y¤z‘#KÏÖ:ôV­×'5¬ÂLHžÀ|”Bèê¢;Ѳ_íac\FÆ•Õ *§¦fmuнö3†`Î(ä¢ýSØ~†G/ªo÷áôD©ÒxÙ=0  ”âZßKnèÔÅyè$œsç2´.}äŠÄ;”ENê¾7>&Á_nõÅ‹Øc3é˜ú#…ü2Òb«9W Ú¿5;–²Ïó+×DŠé™j]2ÁÌÝæŒG`,~Vf<Ü_«?¾ú³J„äÌõ‹•Âaξ3Q»o÷¢©mòs¾ó¬X –2JáŒØ \ ÞÚÕ»ÊR§` EÉჼàcV;ÍÕÈJBšƒë"1!p·vˆºlxTINA{ câß¶´`ç¯ì£ëü„vN‘#à ¶ªEòðr PEå=ö¬“t½š"Ÿ:€mAuµ5 í¾îön'À}‘7ïLC½Ýø%›QMeÒ¯/·Oa>Í }6ÿ-78ìáß,i0áÅXãûõËGLôyiG‹m)Åñ“d´#•ñxš¢£}‚)+d¨ÔÿçïGf6 Î2æ³)w÷ÆL{#ž÷f‘^ C–ûé5ï">&µÎð½œÎË‹ûÿ×>7Ãø¶^û½]m›ŒÄ­ÄÍù{¬N« yWû|_QãSý@s„ü.¬×«ôçŠ;T+ù Igv³¹·%¸&V rBÙ„6ù¶ˆÇ}!‘Z„õo(úñNºL! ݶÖßÞÂâãûNÈÞã÷³õAÎØï"~Ñk¤PMG´Æ’€€á9Ó&%öòéYz ”ÇN™«Åv8&<åË­#çué9\\éÉfR_‘¾né% ?ù—u‰­wî쮃Teùt_Tœ`l)ó\éhÏF•k,Cr”)ß7 ˆ<Ä©¾×M¿½ö»µK§#þºƒâ…ëLÃZNÙ­$žüÆ¥E"¸?ÿ{§ÆVv“n=ÔZć©û ކ¶9N)py ' ½%gZüÍþ{ÙÜbˆïÀéßòˆXåª7vÈãÊ$¼oò_Üz,güÎíÓ”¥¨þ¶WòzÿÞâJ­zZ\úÈL&LôïïÂ×™Ð(¾$éÅR€ìH‘ LUª“x8­ˆS Ñ w㣄Ýn«’/o©ˆÜþZõNj“g±À‡[”讄îSe ª –[q`UáÕaû $òj+ö75¿”˜S0† zXRõK¶–U©ž"§_hðO‚¥’xb{!ÊÔ;RSR:‹kù%PÕPûé!½x®;^—Éå’¼sµr14BYx 1]-b½« ¢µ¹«3–A¯*”­“LÐÀÙL*Ül®Gqí 'yåcbª™æA¥¯5ùuêàÛ é®-~DHvÝ‚n-ë¾Õú'7—ÆÆ,dØOss»­dX¥Óqò>²$`qóäqHQTûÄ(Â?úÎû¬x̯¿éQAWúãÏ>ß5k‚u%t|Æ5XWkïÉA5f“XëT•îx—1“MV4,ª‘«­ÅG˜MjêàÐÄqœ<$PQßðÖN—o%„0m¢'?7 ñš­£léî½4G/ºHl@Ñ•Y`S_)«È³ÍÃè±ûZ+j é)©÷Þ ÏöÈü;¤Ñ{«J´ÊÎ졈گ´¦êäÒdí¿· ŸHÂ÷,”Œá¾ò:ØäÆ §FÕ_æ®h·ëÕI÷xºöôt©¤L)bÅ&Ö)¼Ap+qÙ•iÔwêÕ凾&‡õz¢Iã©Æƒ<ë¢õ+Ðý³m‰H±­q±(×Afù ü©O*é7óÁû5ÕÈ‘µ¾>ÊY2r,ŒÍ½•”aµ× ëR\‡$æ€8?÷oÙALÁiM‘òóçÈÅ=e;êôé3NôQÖ+€M¦‰œw3¡'¥’€€ç´òÙðÒ·pM]¯õ=eH ÜXÅ-…¿ž¹(÷C¡½.K4yå;ÛÊDÔ³Ö¤1^§o[¨Áð„/3*ÅÌxÈåµÏŸÈä”ɵ^Å( gVÏz©‹Y²ƒêƸD@j¸ŒóÓ‰>ÌÂØÅÀ=¢òdB41ùîô)¸NgG[3á–îw§JŒÅ;NëÜ`f÷ñkÅÓ_Ž="•I­V=ºÖÜ|ØÈ—ßú¨´>©ÚÞ`2„¶I)¡=Lí(o¡d_ÂÛ´]¬p`O*.›ÄvÁwÄ$mÞl:/’a‡Ögº=ÊNïw[쨒%±‘ N¡Œóÿ•Q–zà4ݵ|ɰ6—‚\H$ Õû·eÑóÞ9Á]¯¨Y<´NztIÉ¥E-˰Ÿ)ªÏAo7>ìÝös\·¬É=¥°4!Ûÿzæ400‚OÁg÷.˜|)õ~µéœõ`ôý«.6¸ÒËÄÄ*m¦6ÇèŒ:²@Æjóª;ðm.rtÓ¸µGº8”ø‘pˆXXz‚ÁœG8Œ¸£MPÓæº·Î£}uMKÅ:àãÏärŽÄÖ*3†{P.ƒ=šª°JžÚ¡<}„Z=õåEŒI"ˆ¨þ>«õÑöᢘàD]R‹Ç¡·Ä­¼s}Ýžz®|Y=w±)ûÄJ´ë.’‘êíýCµÍ‡×³ÓTº®ë☋<#×~¸ãŽ)Gºßƹ¾é¯”Nµ_Š}D+aYˆßîbR¬°DõóÝ*¢ìwž0†A’€€¥ÖænŠt³=þ҃߹ï·hsd˜ÍÙ¯{üt²GÛº?Z¶¯Xö¯.÷ÇC°$v…x‹-M1qê.›}“Œ¯YÎÔ{$n³€š¬EÏúí}D3Ê‘oŸÒÔ3÷¡Ù‰ø+C¿œFµä#>¬îHXÞz¯Þá·yÉØ4‹ÀûÒå?œ[‰Óë OfT—ŽJ²#‡å×àˆŠÐ>w Å™*ªô ¹YZ‡ÍÇkL±A˜¹[¢ÓQÕq£=õ:ì—8ù1­¶íU—.DTÍ4“‡¥ÎùŸRýs!Æ%5 K[‘™¡%D®‹8'îâ@ëa‡Ÿ¤Ê6r"ÌÅ# O HúêVCæ‰2ç¦ÒbàšhB6°'ÇÔ€p/!ƤCÎ<—b.«8áÕê…“™ÖR¯ßa£DRÇû@ÈvªB¬L˜q‘ÝŠ{Œä>‰ä³6hÈÂãˆüD“ôvqøSྷ‡Nºïí/ÕȽ·ý*‘f|I9´a“‘MÅÈh1SëÙÉ%寘c/# é©ËÛ¯±§ÞC”Ì i8ȳ!!b}Ἤ4éVýgOa`kµ«ªŠw ¾àm¿_ée·lêúdò‘tƒíZhè=0n¯-•å3ªf ;¸¯6Ô^¤ñâéõzzZ®WÕp#ÿ×/CÂðXRÏy¼˜÷›®{S“’ÉY!6.Ò’"„§õ2 Ã(÷bÛªäªm9ýØU³Õ²s+¼N·°ÚËz£“†q.5>ÀA ½òSIYÁMÚ=#Ü 8µ(¬ÂÉtªÂXÂ[“sñ¡Kø•ô×-MìT hÕðÚ´‹ÍqT{Ê¡¡Ã2µ&ÌÀe2å!(ðlIR±¤òÔ µé¹¦m݆0Ô1.Nr[éí­~ÙN²RÙ¤…î7ÀZ•5+ŒcIâÖk`æÏïÖÈTVfÞän¿ß}­¡3sÅîÅ:Â0 ÂèrwCOtùàO»¸7„wæŠKÚÔ!±Mo~FÀs›Œ’€€ì‹JÝË‘õyEy›T¼põbê`ZÇ£BïDÍj>C¨š \“ÔA’½¸ä‚=R«$0ÆÉç 4@œ;3¹¿ÇŠ›¸°¯$øéÃÝ +×ý(¥[ £ðw¶'”Qü€g t+ÊbP²¨QæÕü㢪¾éP¤Ó. ³‡cbô¤^l,Ç>àBê&z] „„ýÒß¼èQ„"¼£QÝÓ³hIEà(þ0޾?lÿ¥ð'ZÛrxkÂ#¼" (&Ô%æüþÚC_M$‘Ö×3ä×}TÞÁÝâ{™²å–g4FC4ìü$)‹9Åqà D§ K*Qô¨‡f…Ëé¾9†j“3ò@§‹b¸¥W9 aÎ3`ˆk‘ÅwÚH")üs¿¡ã&^=JOÇŠwÛu÷õTwr2Iäãˆïy;ÐËõÐTõ«.$CÀÖLv´]óƒ¶}½Ûƒ[\©r’§QX]¦~ÚM[)iíÁ¾Ðì°çÃzÂÐ@m$‹åJòœ Æz}”_ÄçPáâ5=þ3ë é/}u…e‚ÃÄä”ÐÞo¼ÚyŒ.é›ü<Í ¯Œu#Ÿ¾¯TöH=…ģÞ™‰m›|MºÜ5è:A1kœô÷’UîZ›B%éÉîÕ¬vZ~/¾¼øŸÐÙ8 ‚_ð~=5jJËU‡$ éû¢zøðXØiD ìÉ##Ié]ð²}ú£v&I\EX±Ã(Ý~ /^Àg ssL:Ì»`úú=dž°ñð´ðJ°/aôÜhn“ø„æí0a\À®þœSÜ€.¿&Ú¸W%év/Š1ãd!hAæÚ&çˆÅ¢Êž"J;‹Põ*?ÿð¥ƒUùxc³™ÎŠT´üï¦XR›LKt…·jæ­Èü”_lN §j™–\±’2“©.6¶DOƧ-g“zW€RªÖòtÒmZÇÝ®$»\;)?éÜA70ƒüUÖ(§ ô÷+½¨:÷ìk6aÄ7²ÉTçŸõl6¿dÌå-nùÔÅxvS®  |ÅÝj·ù'Ù_r¨" Ìa{ïü9wõ*c Vy—³íÛ3"Ò®lŒF_˜ÉµÝÇTùË0š¤¹ƒ¾+[ #×G–¿¢±¦ÈÁrþÇÞÛ“é‰ ðe7«/SãÖÞ¾õÇ üL5§&‘„^…ázȦ¤˜¬@2Z›’€€‘mE4Ëkp r"“ '«²½`“;¼,Ôáo>OëµX,%ÆrnÓ6Iàc±SÉQåXããÕ…[b®„ÆåiT—(¾Ùu0Ãk^4dlB¾/qµÆü³Q’”×ÍÓK‰å;–ñ8!Œ‚X9¸!í³lEûìªb¦—äÄP ›‚ñ³– CÉfÜž"” bNJÇÔÇž¢^‰õJ}<áèóÅëx¦„¬)7¹>Í1 eÊ"ýù(w©×Aý¨I²=Ä´Ží`•Ðù‰¨‹äUÆŠOÕliÎ~³ @_¬ŠÃûZÌ|ׄgfI»ª²¿Qìÿ>HfþCÉ ¾Õ»?=dùÕ6½(‘Ò(.â°yO;º×ÿãòÄÇ̘ËF,ŸGûyç¢Ä_ï]u̠黩lð†óL¸5Ã{ä5vþ4™ì3ô_þòuQ½ƒ#“X±kÁ´¸ éÔZZ^&¦>þvDWϱ8Z-{¢ñR˜˜úÙÇ£¬|”´‚žyþgšó¾ø'‡YÛ3@8—yà´'A^ÁµÉÖ×r`'ÝTùF×ö…FZ>N[`§9hÎs*› m:íæx"­ïÂEªeØ€0…ÎÅñÅE)V#Ý·yk|6Ý7\g‡ µë:;UåÒn¡F¯óÐ_Ëö0çv€íqÁ^ì¡’g7>bi¼ -+ɰ[žä}P\p3hM£BÿHßY8L„UrxÆržî­Å7UÊÔÈýî¶aƒq:FƒŸå+Ùó¨ãýŽXºT >¶ÖKÜÊ}€IìÍU—4ÊËŸ·’÷5pÒÖåÐí¨[jQEò†\Mï}RPPQÒû5s/Ô-èÈA%5~gUá tÕ-þàó3çüžæœ›à‚+59ª˜t-ÛŠhž^²£õÀ&!o…QD|h’%Ú³&…md꩚Gí®"äŸA]ZʾÞ\kûk[JòBÑàëŒ b®ží?ôÚHzkíߊÅ©óq¦ P’€€ÜÀs ôÝè>Ðd×öç ¦ŒÝÎ/Ï!ñÂNVí"õHÐm_Ä«—ШÛ;;ux~çÐ<Ôó†ù²2¹Ä•1iåüå@áˆoþ¼<Ò&ä€'u ØXK¹yPZA¡"Q( Ÿtôhe[`/ÁóµçÃd<½‹Žì1_"ÒôøÐʪâ÷ãTMå­Hën=:Ddz䱨ïòñ‘0~†ã2¦½<ÄÚùÏì- ü @äÒüéqC$r=cþ~ftÎe3—[ÆEº'*쨾¦+’¦ óz¸8k“eÔXã:&DÒ*ªÔU`kOIš2CbÙÔïdACCé×w²îX(OÓi ó ÊÕûÜ}P9°«ë­ï‘íQîS&X™h”‡[½;<“o†E°ú±ã ç€dj°õNááezcòçÚQBÐß`4N¸¸©'µ/5i[(‚@[§"ÈS“³C¥EÔ!_v®ÎžylèqvbqˆR›v}zá{› –Fû=Ž;|óŠ“ú0d¿ý‚oŸ9†í»—r¼%šSlŒl‡¦y½Ý%äù”/û¡9H'h™üθ Ò†LFŽVC_6F™Ñltj$õãVC´í(‚¥GÓm‘0{Q ùa^;é9ÇùâÖŠã¶©±= B0ZHÄ«-ZײYèóÆ?îÅT…¾: Ä} mJ½h`eÓÙœõ»£yNÄöˆØ¥‡Lªš§(EôD‘œÐÞ˸P¡}vôýBõ/êžN†w3Æïƒe”¨WÇÓ4.D²*ýÃ)EÿÒšìÎ~Áèy,àåõø§¡*?¯x­í ]—¸úÐ¸Ëø pd²Òþ÷¤÷G&˜„‰½yCC{WnšÍ$eÒ/¬LÅGIà~¢ƒaîë\}T§¨ŽN>0v Wܵ<€‡Ð”L)\¯– £JÐ+÷'©Á½FRm·êq%ýZÿåfšÉ;鉮ÇÊ; s™éòè«DþÃX½Cû“çMš1¯ª§PAÎÇ ´lRäü …å»í5ŠòL6øY@;ø‘Ú9c~NAWÂz×y‡ûäŸ0p!EK´ûE¼m ¢âK™E¤xì›]^"›Ï‚ýy¹hÂP.Ì.£X‚t ÿ*+˜Fl¯C[ÌFïªo´·¯ò:+ºÙøTï¨éNYà0nÅÈ àþuõºýR)îöÿë¥ÊB[GýØq¥líÍÀû ´ªoå3ÉW pW aÌÕ$w–ÉK¢Xÿ;r;'Ë[¾B)gžµªpgÓ{-5r‘¹‹q¶£lÝ¿':‡t¤Î;£Q8ßúclVÌs²œc~‚®hu€4Š6¥Ð#ì×áÙÆ¤Ž÷ mj¼ÌúI ž}ɪW%ë[M³%®mÒaqËôì$N$øáí8±Í¨ÕŸi>_¾lRXa#)Õ¤Á·yü[=²Ý¸¥hq\ÛȪ#w÷ð>«¢öôè%Íå9ê·–Èêö*à‡Ûeöšq© ¤9ŸQ ˆMEÄeÇ^g?G–žàÍq[MwëõF=ÑzHU›+_›Üªb­¾z2æ'c%;àBï$Öa*´¤y"%«ÚŒUœUŽ2•Æ/oØ ~[ÝRwT äV²/«fâŒGîÊjÏ ZÛ Ò4gEv¿ ÀkPÄíQ¸pˆÍªÑP!¹A ´£ *" 1ÓÿÖLj!®xåè`[”óÜuä¹¶áB¶„^Zsâ7ùnr~çIáÕl?ƒ\‘?-Ž`ŒæyŠ˜¸HÂåµz"[<a ’íÈuˆ×È¿fÓ {²Þ*H,a²íô7ÉÖôs—˜ø$”TÆÖá’€€¯qË!T Í¶*áõëŒ/@¸oGoâåÊ6ÌAŒÊ¦Â1Y-kŠ®C/„—µ!мù®aî2—û8”Ù‡Ãt:¦OKuЄ3ª˜e6Qj|‡ƒ%Úá4ÉÞDêªðK=Žï91øÂEÆó-lýÁ·»É¥æYÞ¶›Ïê6T ŠýHH é¯Lv>Òø•!½ç<{è[„D’||œ7F$†ÉËAo✊°ÐužËO&¾l­•úøæ:›:óÅÙ}—áëöÏ8H̬•`U×ÿÊ” ´WKqXf=Ej²~eU)] ð¢3øl”fŠ;TÐŒ°Ø©Žd/ånY{ÕÃsg Ä]#WâHb|²Yk¢š¬Þ a&D!„0é/võ‰¸>{`^<¿X èªñ¬m¼5XEÀû»3……%>j†‰Åǧ—„íªQó¸@ÛãUyÝ¡Ù.z•‚ù}Å}1ò`bêé—åƒçkWL©Ø…§lóÄ,´?@ß°ÊýKÄ„1°ØôÎû˜“8}œÛUÁ˜Ñ™+øe˜ñ!./‰‘¥ƒÙ—×´`ÚÎTý[õÔÅKå¬t]bî ¿QŸâNaËcb¦™“·"ºä®7„bÐ~×{ñЇÿë¡.ÈUá!8òÖèš$dxSL<ª»É\ÒâVQ'ÂUÖm 9 Zž’6?ÿw¬‚]5düØì§õå?P»÷ë´¢:²Vñà^E—²w¦Ü#+U壿UÒàº*4þ¤ ‚ë ]v1æTG)‚$1ææŸ¨@RÒP|ÿýýAÁ²K[bÁ`ዱó^6 XŸ&—ø9vmšóÑuê`sHm¢kEê-To&_', P#œ.îI´¡gmïÜ› x` H/bª!4¤÷Á¶ÉÉ?äÛ0’‡hù–# ³é‡ÁK„©ÝÛሺâ’€€æÓ-ŸÐ¼ËIí>—GÁ•lÿ$½»Z¼2ìÇ]—'èúÏò |äJo¼cûì- ø@Ƴ>ðßÖ?$|íË#O Ë‹ûî »ëC/!-2ÐíùŒÔ´sœä¨›}œ‚2{­Ú@¾–|AÈ%±ò—É0=É"ÂÕÚ[ah#A¼‹Á¾`3B±´(Jù[„qÇÝ=xµ»ÏÍ­ÌÈeP‘~Ll:ÏîYNGÙµ0¼Åü±l N^ýgûÙÆ‰»±ijÉâû÷šå*–ƒ¤æš‚`€¤PßÐÒ®Žµ’¡Ÿæ§žX¶}Írп2,òê‹â^# ¨Lðˆè8ƒîjáHì]ªföBÌ\Ü¢¸D1y ó>ØU&…‹!_ã©¢óµÎ‰g+NËý8šËPÆÁ€w•WžtX¬óÛû¢o«øÕd--/ Üs+ò¬T"½$™Tõj܇9L+R}ö"u~DO¹ËëØµÏcÄÌ›äi±•Ò»^0t‚ŒñÅ÷äšÐ,~‹ÚOÒðNÉ+?"OWkÌN‘.ämÁÄùQœR$¥¹©Pky-¹fĬΰ¾í–pˆ‚ÄT4$šã/uïð—I”­‘Ë”Ì@PÛqÜ”»ÕG‘Ug@ì¡kº¯äPVY¤’)è¦Ì€ä}™8V]9‡@ñ ‹¤õV-¨‘c¹FÆoJaQnÌ‰Ãæœœ6ªvy×ã€UIˆA5¥•Ü TìfðÛUMa³žÌó÷FÞ^DfD?qµ±â‘.¦ô„dD#æLhñq †Bû(Ø8M¤¡b ~†XSÚí÷hRªƒ/¡/´®”cKæìXXk°_ðÛ‡ÀI•p³”kÏMíÆ“8b5RÆLÎ}’þ³7ÏÏòåØ#3ÉxjÝ ð}éˆ"š\r©£ÄXREQþ‚›¼7>®Ü²8©¼P‚È÷èüàB)Çœ#½úÖµ®ÎCÛ-øá|&¬Œî¹ oý`¶ÿíy¨!@ÕO…Ú”ÅcgÁ’г1®YÖ¯*l¤gúäj\õDvoÐ;#|¬àѨ|.ÿ*!97.ˆýEV?¹Ù—7Ÿwíéèõ\ÌÆÓ¢0K ! \ê`[ÐðžSÌLD‹¬T—v9XCƒç>Ý3ÎâÞc,óÚI4)°Â2ÙæQ”çÖdbÄ’€€æânh­TÁÙRKÕhßKž¥3 X†x°Ž%9ï1$ïÚCÿ–B–FaÍß)Pеøm …ýÌŒc.ú—x7ÝXÿö'e¤ž²€7¶Ì˜ ߬gg@9•ØÎhÖ^Yà¾3„ú^²•HbÃÈfÏ5-h]gn¼ ½Ÿ§TÕí'ðÖª*Óödø³®Äôp*{¯Ê]€OÔrç­Aõµq÷‡–i0¥¬ƒ=áEZj'd)‚+óB;8²÷oŒ°O¶Eì2hy>> Rx¼ymާ0 ©çöüòÌPýp™·…¢+…ÖÆÃI†ƒŒN„U܃«aýÁÕ!vû•&‚²$ànZsnRƒ¼Xy÷õºóö·VÖ«¹7\RŒTö>¡\^Õâà"<6„ËÖèE½¯¾× ±ŠéÔL¨Š³Ý^, ®×ÐK$”Ê¥&¯\i§ŠÖ7”tLäV=µ÷\ê‘§!=¿)ËÚ²i¼ Ñ’a?¤2ᦆiM÷ÌÏö‚ΫéÅ‘p†TQ.rMuIÇi mi8‚K¶cÅt¥¯ógqú¶’šÒc¢î¶£3,6oj.®}±Nô:k0í ×ñäS|Í,X‘P3B™ëq{/\µ<(ûÙ|çàÞ‚kH&/|I³ç¿Xþyoç€ÉjìŒaø pB‡\¡q—¡uéFz8T…­E¯~(y~Ð!5,’ï%ø"žé$éñ}¨#ÜVÙ‹¦k8rUéX¾Þ.¤p=ŒDUaRœ@’Ytœ=»;ó§»êsý¯!OwÝ)B†d‘ Š>¹o²;2úø§6»c¼¬»¦=È„õí»¡X8Ÿ)Ü@sa/8°A§«{ ºýiŸ‘©ƒ³}Ò!âñvÖ¡e“Y ~+u¬&ˆ[+ƒ¹‚¢½ø‹Ý[%.ƒaËR@&ÊëXÈÅsÉ å°«)%¸oÖÓZð€”¼~­ åÿ ›\/Ž»UŸ0‹Þã–FûºQÿ~á=aâ0±µ5}¤2õ•Ëê e•,Ëо/„}èAõê¨P8%RÿvÏw¬ÛjZÄ­FZʈŸ‹È˜aü¥Èôï³ñïæ|¡Q;t²hQÛƒ,ýçZg ï!2§ÐüBù{)î° áˆH¨¬I —SÜp\kŸæã‘ ›VU"‡xe@^’€€Í¤³râ1GÚ.Oܱ©iH$Pîl•ƒ²­@u±R$Ý–Zäƒ@íÉï8È ‡`zí}¦$ºÞ×\î–ò ýOšÁSØGÇ…u ¿rÅ¥:¦9©§¨‘ œ£ž‘OP£E²žŸ(Û™!Y*Æ&.,nî'ñ|Ù¥HBJ!q:Ëc!ng‹­â¨±oØ^¹P ¬R3î¡/ôÂÄ I£ýFò[s^Û-º&Hü™‡+´âYéºÂ¾»Òš®TgSªßŠÆ' H¯£ŸÉˆ]½eˆyëf†Iu2ïFsÞZaÀDA ·úH´u×ÝÞäq‰2ˆ2ÈIÅÓÖe óÌNîžÛÌöKFYÎ[L/1CppZÂÆkRÌB!%» €Ý–‹Ž°ì`çQ~¹é-™Q •}»o7–‹jm“–‘ rf©ŽbŸQË` ”’ÿ~+„ùâÆk×#¬Íâ•™o‰‰ÌíVæ”î›eŒøü¨'} Á¤v’dIÐöFÒBuùбC"£¸°–ÝÊ¥ù+m+)dTM|R]K”\Ö'æZ¤šÎV ¸5=¶µLŸŒÊüÝFh[†-–)޽9 5Φ®Þ¼€–ÐD\Tê*q Áû<ú!àî#úÓ³eN9I¶ÞxÖ‘¡¢ñã8t,º2h -ÎÿbúaË@JÙ­C™5eâþàó{a2ÞÅáë&|I 6좌ø Öòä§wvu>¨„ÓC‡2õŽ“Àk•‰©¾Ö4ï‹Q¨x?ŒÈO©wwÅ÷5æ/&¬k#qoôØ*Ñ ÜǃskhížþÁ¶¡¾Ñ‰Ç“ä.F{ˆö} ¨€I·!Ã’€€° ÈFûs8î:]Ê-l YB:îaÕ¨£ïŠ™/½ë·p¦“ç1/¨…VßZ@Ü•Ï4…6gÒ¦ Éʬ¨·)¢‘Ц„ž¤?J‹›²Zÿ 4ˆÉi›”Víib^eÚU°ðeÊL¼2èn,ç]6lê;Ìi1„&/tÅT—†îÁź…ÙîÆx¢¤åÁIg^NÉ:<™rα¯PÍ>”Ôn,yQ+ڿצ%¤º2YIx¦[¦xbfl›$a‘ÁÜì†àÂãÚr5_±ßAàÚ¦¹óÈÀs·IëxEU¦â7–4qB0•f+¬ù¬kÊ&yB£Aî-çîÔ^O_‡–à³+ü¶IW‚ùïÆ‘xE-°\æ2½Cce§½âéñm«°ä˜±À“8C¶!ù*D'|A}ƠʯÒ åL+¶3éä”6dè†VW λöz, Ó+¼ãEW™iÏYÞϘÑŸÏ: ÷ªW"ÇçÚ¸¸Ѓ‚ÊÙðjô_tÌ„iý~«ÕdÙ÷&Ó#¨•͈u¿@‹Vp[Ѩ¥(Ͷ7QÛ,÷|I^½a²%!nßsyáy_AS®lÿ‡°üÚû[÷DZj±ù –vÑX,ÜrGPUaÓQÒÿrzÞ²XÞÎ?ììºÉJYvHO6µaÁã®Ð˜´É hö5ß’Ù Xñ˜hþ,éÂÆ ,‘ç/åàÀ= Ï•ä5eÿ©ÄÕü4{i’€€´?P, Ê¾h ²íúúÎ.(àºk.¶Mæ¦1õõ‘=€ÑTakø;˜uû*]º¨I²‚AÅùÑfΩzŸãÛ4Æe»ZvX«4öš=k¬dLËWUYã;ÌÉaV`.·?ûÈj‘qкçmܨùåÛëTö`tö: 0ë–º}n•¹ÝàlõÒ‰^[ímÕæ‚‚ÍhSWÈdž$!Á×=„º¼í«%ù¥F^â2IBRQ_<Æ$ˆ¦n-ýŽ2ñâþ[k’$Û ábàØfh8çœyïônLôÄc="š>Ù nsjœPJÂQðû[»Ü{||H}|ÐÊ ytǾQÊàC£I{f/üÖŠ… úxâDHô߄4ç {¾oÞüåÔB¢˜§×O5m¯8@XuÊŸÈG?1uÝ 4f#F6²²G~4ë’RŸ¦$Ô ­Á7/„ð\Ó‚ã#𔇃cÈÞ«@g€ñÐVÒ}†›ßu®EôüÀŠh$¦H Mw`MO˜ q¦¨—l’V¢.G I“žH﬌ÜN Çn@CÈ^nú±Cdzs§Nʃ±Ž_bŽl4÷I|úl]ÐL¿•€Û½¦FÜ’uÌ4çrË‹sH³V˜ßœ¿(,K<º>üØ”Í(˜NÍ6ÏɶòRÓ¼MpŒÒôscuÊ­ð‡ÿŸÍ)~Ì)fdÂ5%1ðmÛÇ/Ù…H ý“©L†‹9Û;³²¬ç2çD&ªjMo.pèZòÊNoÊè¡’JGQqÞ¾{Êw»3w2¬#μH<Ђ]EzºY8"Ý!@wlGÃDÈM†S…ä® ,ö”‰Šr@ óþ‹Ê?§æ95ðŒ²4Iâz¢ŠIgç¾óP/Sóg¨XG þE&%é iNBNnÒ~CCÌ:¦Ï¹NÝÁò ´Y¡_K,”–gÜ8Æ‹vD’y±¶)E7™º~¼1@ÒC°­I‹-6{,¦öˆr}2²üïÕg"ï|sJœ~Üç—ß™³‹Ú£•ñÏ×—¸¥Ä±Hž5¾ÈLC€enÌ"x¯´±¤C|)ÇT`-$…KíöIaxmL?á…»DTcöOÉ¥C #ÿøÛ¼¢³qNoÀ0ùv¼ÀpK÷v9ÈöjÂq7±hE¤½üøh¸çeþ;c]edsDô¼5ÎÁµ{ع×e'0PÇvgÙ’Á‰#E'UÛkºÏ@§²Ã-(÷ÏàÙë`Ad­4|ój›ô–ÄÃúÿ¨‘€/7C±§‚Ÿ”„!~ÎŽ”@¾Ä°ÇÇuo©H²ƒ.<Í L(BÔ€ÚAó¦7ú>¼mÆ;¡ÛÌÁãy‡.¯â’Wµ¼§F‹‹G ÌYǦ‹ó2¹ŒÁtÞl¿ÜÝÆbf`°“ -erøßfÆ£†ou9çaQ¯ÿ䤲ÜU¡É+%€üâ|?•/’WþÜßÒŸèroß¶s;åƒ0ã0P:ÒEZx|5Ò§òÔÌܶDHäQÒÆTL¿Eµ+xâMÊ¿²åÎ iðèÏÖPá,vÁ½ð‰¯¥ÞLËϬì)qV§ÏdÃÕ¾I(¾÷/L¶+õ obaÙrB„UuýÜôûç M"Z‡mŒy`„ø¨Ç ’€€ÉòéŠû/4ÉäWk9ë}Ô¼(šë&6¨ïW¦…C ¨õ²TÙ×K(/®Vbö¬ÈðØX®õ¯Ë$Eþͺ9aÀ\˜öß&Š ÎJÔZy«Ãg Qä›áŽëM°ˆ#7㙆÷Lvæt¸ ?²«Â@h[Ïž[íUûv@üá €»9—µX ÜÊ¿ˆÞâ­œ‚—à€Å13Ȳ˜è9OL—´€ãchƒ´™çÝ šã°¼ö ϸýœ×.vO( òÙ]1Š…œ0tŒØÐ6ýù!h—áÚÌ£Þ²uk› ú¶Ìz„ïXöÓšŠ>–Šï½þf=ÏXtolòWõxžAjP¿æ*]q«2ÍAúËŽ}Å¥zd/ªÉýZ­zá—ØY ©#…7ʈ&oîÁ~1ÿšu²wä®…©3°è4ÔÅW¿È#h˜´È} ½]/P¨Ñ)Y„ºÜ~((p@Ý'Ñ¢ÏFtÐI‘wÝ4©(:#ºkÇðÓ`²>Æt…m%ó†€o‡ñ©ƒå¯GvUXKÕwbµ#Gè\lf•üOE”e¯q¬Ÿ”hö;Ò¥üèk|ÿõ]Ø(8TbsR 9Ž î/m]~Wã»j–îavyÿHæoÐ×⪌wókV-T.?wMýö¬lâõRpk½µ¨¯Ö¸ÏÉmŒ(ä]B!ð¿ÖÅ~6\‡bü9«¬6u$Û'èŒPÈW>ÓSf?ciXPau}AŠÒézCžŒÔ ’\cï” 8¿oÐ=sÃ!K_˜nªÐ†´RœƒØáÍsy½ÑˆÆ·=…q=D»wЮ36J©,k¥´e'#-¸Õº ºNz·#øíkæj0crˆ z¡Míºy[š žU!‡ìªJ©2£ãŒÚ\\G]žÑ—½Và(ÞétDr{k˜½0ÐÏögæÖýû#ûAèÒ9>ŸîƒBY‰oÃ(¸&‡ÿÆÒÌ2Îp…®eûqçwì Eó¢uä¿·tåJ†!É$¾óÕP*ƒ¬Lk¤dØ ºQ?Ú[SK¢9Ö[U+ªh˜ëPR©z“RCaMî”®%©”s á’ü±xè2Í…Ó1{4ühl•Ÿh‡ÓÚ=ÒZ…T{î­büµWMxÇWß#éöÈÐ]刵ê#ް†Éñ‘–´ üb&Í+íZÏ@úÍñèQÒ‘–FÚyïªLAEÆ"®Yw'›hSüM‡êXXûCü¼ÞkȘf¢·Qâ x»¨Ï!óe¹…ËbG² .ìæá1”Ë$‰lnîsõGV¢ ÀÍC†î×ßZÔǘДÝ˼Dt2ÛR$Î^ß[c ù…PÔU KûáÏNU”‹8 ¯í£®ñYlñøs^š²EHúþæ4i´ïŒðÚÿk²T¥‰D½Ý<7we–×r%;©ÿì›×aXÙâ§8¡ÖŽü¸UfZã„UP¤÷U`©Ò¦SAtÛ6Ÿü‡Õ*ü÷le¥÷{ᔫ”-0˜³lH öËO¥oTþ>Ù>ä!ŒûÏQ+ñ‘ûÓ#%¾`δÖiážIZ…IyÎlöá|Hd3·ìÅÚÆ—ïTG„BOÒú–ÿÿ5–ìLÁÙjGƒ‹Ö6;³bJ»"õ§µ4S$&Á¯Ž€¨ur -Q™º ½»iwØ}R”%ðt †Óɬ잶쮌ø¾»w/ÆüMážzâ?Ë`ÃÒñe3;Ý»Œ^¹ï¸/Ïšm¼éŽuÏiì#Á± =AÂHh35ûfv;wÓœ¦›ÞÜõ˜“á|x*ý1úšõ œi²MlºÓˆˆ‚ì#®Pî&L×s*¬§-¾Q±oãöß92²ŒÚqªJâ$EêÓ&„iû’€€ÒjO†»r[t'cvÚ_ýÐÆØÚ ñò}äg~"ÈsI§”÷0îCk×dbj×”¿.*.fœéMJDZ q&¦kàbxºi¦²ÁŒÆƒƒŸ˜x6Ó= ‹\S¢$…i=Å·².›<“ãë²û7%+Qàç^K°ùÖy=ajŒÎGF¬b¶wK<ŽB'¹Y®!UýE7µ%g‚û]`ýR0 ×Ý> nº„­ºhû÷é#v[euI’¬(‚™g·vÖ Æk‚’Gêjÿù|ÿìrpœØ¿dw•BÁ—B?gß„»U¦EÜwtQ[öCi©à+•!âY2±VÎ*|Í@cö»Ç²È¶µ›êíš]r‹—=‹ÍLæ™DqõGÂÊ 4³{½ªån Ë ÿ¿4ÊÏ`!rzQê –>`6r6Öì_,Œ?‚è«—Š_J¬7ƒA¦4 2³J™Õ ]‚6ó ÈÍäãHéí¸.ÈXѪ˜·o?ÍþÌÛïõ)à¬ÔiÚj\qX 7Å_àšõ;´6 ¨ŽQÌjËÓª5~Ks6!‡ÍF%ä²E?ÉañÖèe[òN´ÍÜ$Ô‚w’}ŒÊO }æÞ§ø 2¾û†òCã+: vøŒ̸ð4š—½”3ˆ?õZ´¼Ôž8j³¨«_ÖBÓéêò¡ìºÔÃÅÉè¿l®D¥Í.?,Ì.Þóq’Î>7k™“êÙžô»±ù·`eÕÔQr`@t e/‚ð(áÝÍ“ˆ Úf[wØ’€€ÁLY08µ-I£CæJ/ˆÙ”Z(~‘IRf†X|aÖÿ«?(´óž¶õ«Àä‘QÔ &è²±5@dÎd\ÕdM–ÜØœü.–`åý7k€—Ý7ˆÞ}RY£hÑåBës¦Z•¸@¾ P±Œkå G}<á¨sàk?²DåýÏËþjö÷ÞLaW% ‘tFQ 'qîÿЕÙé.98"Q¤¼HÛ&©¯È÷U·6êÂWû›ÿ.µB‡Ÿå ZÆ_„yWákœëZ%/Ø~Íôï TiÏÍ6i]P0öZÉ] ÈÓ{ÿÏ 6ÔN?0›âiÀW'yðòºÕ®tuË×Dlp^ w&ZŽ«"¾ñÿÙ° 'F¤üBO]jsv aËß@[R†°ÿÍ‘™­P ³œ Iù©M-£Ì)¿üašdÁ¶r΄’î¨ ÌÚs)†½Ðc(ÿ=%)Ü­Q‘b£øæ ÛȯrÒó³Y8±S2)%༳~ÕÄæèÏyåAmÌÇ+»·3ßÝ™Ö;ˆÐ2‘d¿Cf…®:ýþ[ݾX¤öwàhLôñ$Cc§T¨†!îñû¾{ÌHìæK0®ßt‰ß<7iÌc°©€iƒ_Ð.…mB0yrÞÝD®L=³¬%¶sy¤Ÿ@ªJçí®ÞUôföÇ©ZK4’ÛAáû^fwਇµ‘…Ëýª@l˜j0k1*cKÉ68ÓZÎmDÖ0öÊÀ¡dø¶½X»»Â ’èéÍ@ˆd®a)æd(!7q™º)cÙ:{ʽl gŒ5Wíh)‹ÈWù¾9ï2©<¨5P×ÕÊxÂO>ÂGä?öÂÛ(tä¤ ¢Ë\\ëç«?Ž¿‰`íMñwewpe3hè&î^º6zOSw{&=穠اÆòq3}ªâX‘=­ 5ùžÓ eø£’Zš6¿mbÂv{lLW[CGœ–CE%]Ö‘&p¡Â·vû©òMØ1æÈx{ÒX¥›fhmÚHôÃB–ó²µêàpÂ4ü(k)™Þ*Ïvƒæ0º´ÿ5}3¶ÉéÁyàúW¹ ¶Ú°tFų±Œ„á›}?ƒ@ gopàÑömˆ¦h]·x0’¿ã#˜ÖS8 ·Ö0OüSP¾e’€€×#çJŠMZ‘T²†_@Á–â$rZ¨´p‹1×îPÆÅ ÏËy@X/삞mŒ§­~—É¬èØ¿ú±ùÀ.ã]@(Q¤õÊLº› &=û&_ÈÓ3“îre””šJˆ'yCÇ-*¢æ{·¯ëó¬=#ˆ%©³–Ë>!3K5¶ðD±øÕöÑ5–sª2ûú¬q;[ßò@÷Š]ÏøqŒƒñú€×ûpq& ìB91‡}tˆÇN¨í¿•â8-À±öRÀ€iøçwð&PqµÜm&·lø=äÒžhŒ=§é.;@|f±ã7•œåZm2ø¼»¤“Al'Áo[ésØ× £4J1nÏÿøeæxšx!“ÈwqBD ª¦–CFwœgº„‘ßCT‡šN¨t÷FÔS¬Chè8ù®°Q’:.W$tJú2_k|I‚úovóû2*˜XÎ"Sç–Ïåó»qét¨U©øÔ÷¤št÷ÁèyJ©»ƒøðÉ»|Ï´OCGÓYVÛ2Ö¼®xžâ×Þvhp™ÙÉ@`C>"Ô PS¸ò'·x­ö‹ðe££ç$Ð ?nF™}ÌA\ËVÉ+O7èÙZ§IDîK4%¤»Àp¼[È„F+´âˆ{ßžçÙ6È$üeò÷™2釞ÛZ/&׌N!ìή+Iæüév7Á*ÿ$YŠÀo¦ö½kc^}ChVbªáŽÈ˜d`\uTDÕöÏKôÒ1èö;Ôž(+Ȥ`± ö¡©"íÎL©T¸ù'ìF—*H«éúŠ}¼®Ûý`<#ï xy >t°®ÇÃùà<œ:ußs°ÜŽÏmèЀ¡|òt6Ú@ªgÛó¢›çVe&imWÙ¨NÂã\üÈyë:4W>Ç‘ ‚·ó ­3GÔD”UXú) *Uâñ¨n!´"Žá•_oÔ[.”FòÐÛÌÑ’£¸»‚o…É’ÄY0P6hæ¨TpWæp&„)×3*Ӈיí>M·»Ëþ x(Ég23À È…+N‡P.¨çÕ•b¨ò"eF€v‡¨‚îU{š"'“O(‚›uB–tñzk×—WldòúôÄItŒ#àÙôðG¸Š õu퉀Á ºÞ ä­öB´¾ãÄkT‘I{àļ+ßæ÷Xã’€€¡jD˯0)è“l·¬ÂuÑc²É໽^W<Ì'Ù²›*p&Jß@QÓ½0D¶Õ‡˜÷à~_d fídNæE/>6^AD/÷(S²Eâ{OÂp’è¹DàÓ쇋8òÖý$~©¾sâ·††=Çò&Í£‰ü¸‡ÝRý¼²Âs˜•ݧV†“=Ì fT#—ñ?Ût ·À;.öª_ÓŶžk9µ­iß;!Y6&_%Dò[ù¨¿Ðƒ˜e¿¬T®ºôZ¸½1Cs&Jùóܯà é1vbùô~¹R XOtÍàiÈô"øà)NÕâèCƒ˜žæœüê›’çß…#Hµ¢"½ƒE2îÀku\Ð…Žöì„ô!~ê8„V²9é"?¸àØ{Òš¢-A˜`2ØsÊ6 GMíóaì‘ бÇMZo ¥&3káßO»Î"T)ë-zâayȺ^­À«k A*’þ%”À„«'ÀGÿÇ~V~šT ì['ôÅÞZŠa©X‘Ýs+1 ܃£%-XÑiùãqà ¾×0ŠPíFⓦ¾‘HY°l #LÆñMm„½ùÖwë¹@Ø+M­|UK!ßTн:pÚlu7#Œó¿"Æk— f.“m*¢wE¡«øûGß­%Õ™¢°¼“›­Ñ0¢â*þVd¹ÔÆsA)°`. vûÇpüÁ͸n—.”T¶óž0¥uÜZÅšˆ¨x‰Úzf{b‚Ò–±¡—XÍÒ¬ß#7:Dàì𔣽xßjo*UQp~e¡H~2x#À£UÖ´Lxs5“ rF§5SøS+ÿ—Û”öw}ňÞ@Æéç• =A ÈðqRlµPdQ"V(ßøkO°=w÷|EÞvðìM„¢ìéYBÖccÛÃAÉêµCTÑÝv··”gzh{<ÏØê¯í°^àÖÔ`rêì€ÖÙÎýΕ¸O-¬³9 ´}ÕÑÝÓ>K%»Kœ¤ •é3ÇûRͶ ß›pÔã©téþƒšìa6(aе×ѱ‰’Jiwµ¶-ÊBNbI+}Y IlÓzÆœé)¡n9$3¢»ð-–«²ƒ½¿ƒëiaýä W62úÖÉÃi’E§±cL‡é>|$m79æò¾×墡IR,&…Š´œ…}|ñ’€€¿(ã €x±ÿ?`þ*K’mFU üå$Ç^»$Ñïksä«;[Îb‹ÞªÊåJT"âOÏ9‘êÄF¾}Þ›¤‚tcSÃõ VÆùŸc Y†{;!Å3Ùñ³CÒL•(»Èz” èÐ<ŽÝŠö*†h 6ö5³ûØíŸéHæ-o*ÝpÿUkĨóßkV(îˆn±æ,EᆽŽËoÈ„m¹ò*žvåó”€'§lö Q—.É8Yk›]ýne0ð´ßÜ\j~²ŠßÐÙ¾C'ÉyXŽù¶I¢¬™óé·éóŠ+Íæ ÉAÜ4Uû³@OXY×Jßrá4'ÞŠ´(@ü8ˆ-ì7ô÷l‚Uí%/A«ãÊ{DÒ¯XS•E@?tQ hFÚ÷â@äÀãAñ臆wŒ“j‰0,½îºæ}<ßÏÎø4Ž~ä”öæ%B?ÆN6b™NIÈ¢q·°WXH̃/ì¾±ó??™έ×k:%\>¾ò™PÈ++Ù°é«,×iñà«QàØI]Áµsq†ÐHºhc¯‡ ã ú=ÞC¬(Ư3ïœD÷|Ù‹;íš”MSóGä¢EØ€È?ì‚ÅXìo韶]<ÿú…(úÌ'v¥ºY»Z] š×Ü>Y‡"6/$ pþ‰ß…½½V`¯Yf¡|«!4.uôÍ ¬½&1¸ +q€žäëZÓWÄëiÛúɜ¥Ž¬@w¦y§(]Ý @TrÉX¨z)©ãÅŸÌÂÓ 2S}EE=7e°ÍÛ-÷T’€€Ý–=%Xtn ZF¸íNF…b‰ãTß’,éŽW„ü x𜌠ËÓ.¥Á|5Ïô‡ÀxKø§Øz ,îöH —Ô›8lÿ ±µ‘¹žŠ™M‚îÞÀÉ’æâ +=,k×¹Ø^A,vƒ^#z²Q6b#[L<}g' ^M‡|Òµs͹Õ 0¯†<ÇÙ©‘&â« åZ-ÖM…žHÕŒ\¤Äû ŽVR±MÔeå[F9çÜjv*€JféóÆf¦ä¯ªMà7K—)ÐfÃ:Ô*”J»;Ѭ¾ÅÓFîÑ™s€¹³2ÃÚ( rW‰„—ƒ-/¢ŒÐCScŽÚÊØ†8±øï ‘Ù ü¢Ô^êêecþÅO–õ•‰F9œ¼+tÏQï_v3˜'D_Ä&×uiì èRozHߣçüY±©(÷„ö›.%›']R…”žË,?HÈ]Ãpìk'¬„ò `ÁÓšHÐSB¦#îï¹| ÙÉú‚ùJÍ^ÉÖû<»ƒ?&¡=ÑíWè,¯Vo ßÃé¶D éjý¸íTÃ1 f OÎËw—F‡ o VÍfËÀL´Â¬dêøe§ÿø³4Ø¿ì'2ÃëŽh>ê=+¼N¿ð§4Vè¤>~Z= ¾j’«ÉYЛ©› ðsèù¹öCVÃ_g×Ý•ÓãÆ  @¨ÐÊN!áâ³vÊ”Æ|Ï‹”BdýH¶S0…oN¿lÃ8›ìeçÁ?„6ÔÞTKF]· ôÉbÛ×%4‹hó¯üåŒRùÌv¤¼º¢®Ž‰tv6…òæ€\ ÕŽ=aBž”Üà¼Ñ× R0ÉÌ÷uæY! ]a¤húœ «ØÞ‰/Ïjã%¤Ì¿‹ç¶µg²¸ø*ØÓåí°VÞÈ´M]ØáCÍ¿Ó^¶¤¤G m€ƒ 'I<ª{8T/i5‡Cµ¥>¤pi_Ü7}hu@ øA¶V÷uÝ2r¥`qTÊÉ(Ÿ# Œ|Í\'²6XYMœwpkŽôGgGóß_Däß…Y¢ëQÁÏ”¯ñBYHd}B'~Å.Y@•4¥{ìt÷X•«ÀõŽÍ¡ Ë’tÉEò6VM3—“6{KëSƒ¯OûcB8K-ýIñRŠvW͵Ñ„÷ Åéj6èèÞêö¹>ØÄs2ÓeéÜAÇ_êžCîdðY^îqS}’½ø4Ñù¥ön±Sééó 6 ±.¾{oq³ÅÐê¬@{Ë,~ÕÛÔM½"#¦ˆš~bÇýÕ€–“²”SÓ•ëí/ÊÅ⻆Å߇|?žè Ò+ÀŸÕ·$bþÊ•§ùî±õ‚Å_ïjFÑÄ>rä]óßË5P ›ë”ĉʮ¸Þ¼¢ 7ÍÜ7Ú†‘¤ÂæÕ ‡sÝ?Å/¾b’G4¿®$ŠÿŒ•‘_Øi3 ñ‡ô8µxy7âýE’ */uÍ{|WUû•|³±Ž%ÃÑw¬âˆÚñS×F…à Fó…l4sm•»æ´ÃQ!åjTêF¦ub ˜«U3Z­9ð*+±¶KYÇoê0kTÙþÚ_ܰÈ`tñúxþFm6=™"Ð;œõpÜGæG¥Áâ´Æ-E°óTKÿáÄ(hå  9´dóÐÁˆ“§L˜PálOeIý»V̰b¢å~“•’¦í&bßQ’€€Ð9õ{`G˜š°—0+•õ„R L³ð=Ãxi€ õ•¥ð6às‰!äÍŽï¬NCÌ—ÓL­û»*ܽ/ (;Ô%¡Ø4˜ë•ã€ø„øjKËÇB°ì£‰¥qLR*•°¥‘¦Ò]Ú» ~ÛduEpµôÚE™Í¯â‘®$‡z@¨3Ë£‘ÛÆoBl„ë‡[q_X À’lxõM BR¿,ißÝØ–B¦¡ÀXôg×”ŠT¡9Õ›Å{±PqF ìö¨ÕNÏ ï:{{ŒK…%KO¼š×’û¨Ý3-ïÈ:èTªP åm}¬œ$e“ˆï«Ø¼F=BûoúP‰ L´[Ù!àÎí²ñÛ7ЉlËë]öºløµ6™†á`穘ÈSÄÂÔÿ×ÅË+ê£uÿÙç:¡ðD7!’´Ùªz«“Q0Ræ—µÔ"Gã¼V?½(‰zP?2¡ÃmH©3ø£†¹¸Ãðö-*Ï'`RÔÒî‡,Ç8¢v— Ï¹IÛìïž§=Z ( àM¿.ø³7j§ZÏváG5ó1?%¤+¸|’DȤÌ*C‘ïÀúŽX4aÿrÞPÿ´–±Tfc™EPe8.}4ÖÎqBªÁjÜ@0=fâýž@¢Ô” šý¡ ï½õ ªÒ7Æ2Äk P²(”üеO¦cùøT„,8¬RJ'‡W"¸â³éB•kf@ûNó©=œä¤1RýBš®]í¥–û{ Tí˜Eö#kçdýQ·…»¥ù–}EXo8É·Z§ßq9$‘¬žqWžbÙw'Ùhj6P^ÞWÜðàŽ €Pù`q\”œuHí¶=³ìÕ¯£*ßÉ>-‘äNúì+iLà˜8Ö78OšŽÆ•{( 9Ü쪒װÜUîQiñêUò=WNXWIi»ºjüÁâÉ‹_„ •n‰Ö½§L°^¾Ñ dþ\*QJ©âÎçƒp·ç¬çZ$éîzK¿Û %¡ßCHâÑW1Æd±ì­—ªäFì­›My !ÑçL}N»›öBëIVØMt­;¥µNh~¬‡+  ªÕ&Iùbn-ãÝõA9BÌÒa5MèAï„ê©×T8z™ä[’ST@ˆm²ÁgDXS’€€¿påYŒÀ}–¢Ê@¨š&gåDdô@¼Z:.#Htö]m†áäÌèà7Ø£¾ôvbšóIE&GÐÝæ¿ü”Ú JÁFViðá…úÛÅpµdy˃„Éê#âOQ ÏÿýS«w]þ* f­ZqˆuãØ”&Xœ¬¹ƒõþ—ªØcSõäðKöcQyÞÓ¹B¬ßc‹ŒŒøåZµ3úÚp¡u׿YüDÝÃ|z¾Í¡iö/V9° FáõžÍÈWîq¦PåØ#:šËñ{/}R3C`Ø"á2%ÂJ¸=-æÅVœ‡ÖS9þG÷ŸKø,+þ¶ôÇ!¨ü‡¶ˆ#û„«5ñ Þ¹%·E°Ï<°G‘!ŸÙ·)qÍyöÂáxGdÄŽñ d±:/ç³Z@£S&{«qŠúmfÔc,ED¬Ã™Á¼"^…t£˜Œ¢™F±aUN%(Ÿî°Â›¿¶ä ÛèÄÏÐt>©ô ų;%*ïÙÑ*ë0¿Ú:A,%žø£|5=É¢§›`í×_ŒÝ‘ÊKG÷"ƒÏÜ$Ëa·Ñ}?ë8@óL3'f$K*bs˜½0_­hИܣ·Ôƒæ_ ÎÏÇ£«° µùÈÈáø°çPIáÙÚk½©R.gý2s¹ÄÒà‚ß®T¹KL}‹Í(—ÿOŽk§ Ý/E7ó(g(Nºª4ޱ½ ½ ÷ ৘¦­í²Ýø±ÕЉ¡ÓE#”öÔ‹÷àœ ü¡-'8O§˜šj1'ŽNlr?ˆ³{}`/œø¾Úm¦è.ãÕúÿð¥«ÂuHÔGhÙ±›µfεv1Î6æ¹¶rjZVÒÎyÊV+¨‰¹w5ÉBnɲU´|h^S`>/$”àzîæõE—1'`ò]nÝ­¾²iƒãDÝ@¢'× óo(å…x!.ýÛœvCdȤ‹kj¦?@~“ÜÎqÚeüvúør9÷D‘]:5ªÜÒfÊÙèž¡ÂÏÚy$Âwç ÷×Ì×a'¯™ÕOMÖ2–Å’˜œÒòÑj:wÇJ¢Èe ‡ŒŸ%ÈK®ß ÐÔÝÚ€à3¿Në+1 ›¹ôæÙ€wG„^UàZ¼‡,§Mj¹òŦݫŠFyÔRõÒ‹ùL¦fnºÔß ‹²Á4a$¦jÍQm—ŒèyνNî 6œ’€€¶Nó´(v÷ÿ€æpÍ·µ©½àªÅù–ͪuÕt ni9H\b×Ð8X+t[§&—ûu_‘d¯%F|‰¸ß§™aN2ûó>W‰F×»ºÆ$ÂY>§p‚°A?\4 ˆNÛ ÷Œ0Ë`±¦pü¹Oú{-àÛ5ºæ$_)»¬/ÿå3æöÐ"Ø½Ì $kêG¿d› ,F²OiÇ „°õê=¥ù†Ó¾\Ô¼€Jõ® ØE޹~úâ[ؤ–cØPm®†N¼Íä\PïçZÁgÔL›‰‡Æ+Gñ¦hH_f†çm"àË¢uM ªÇºBܾµ›]nH´oÊ4÷,–@«ómeÏ:êQwS¿§hvOØ+¢e6ïgW¬¨g¼BßoŸ®ÀZ õéËzøuãôu‰#U*š~“$½¢o• H³?×F}Ø^âvw‚SP›ˆ èzi^é4CíØhs¨ k’—Ywd#lZØ "ÍGÏúüí@¿Mb{µ®ïU™<ЦTÍ$ åsÐÓz Lò}ÅýÉ÷¶ Š!¾a Ÿ4‡¬U•aê#ð*Ù_…2¥=V>5A|sÓÍ‹Mo¾ñÎ ©Ê®W›FŸFó]üV}¶­+Î5&¾ìàì ¨¹#æpé´P„5äàŠôjídzŠ^Y½v ÕÒÖ+Á¸»ªÓcc 8Û¸û¿ZŸï'^±æNÃïÝNÎñ L0üæäGî ø‡« 3TØôòçÕZY—=ø€¤Žódä>½ñhA$§‚Âãr€^CÙVG8ŸÅ A;v9‡ÌžÖ­x—ìÖÅ&Á ¨ía´B'‚£UCiÔÕ}¹“]—Á‡¾Ä'"õAÜÙ†)õmWa‘;ÀÂããŸjx¤9ö©2YO0¼ò?¯Žß}2Ž›Éó)|Òá‹Zípë)ž!·0ZÓNj٘Üó㻕Î]™ê–3—LR[vfMX;´WÍ%”Ž0–R9ßXD¯L"ÎðöµÏër¥íz}œ‘J„„b0sч÷wåü~<Ÿš^hJþd¹caôëõIØÀq/!·©q&liÀ^FZ¡Ú•ò,Z °Ê·‰í.±Vð;A–hrmp=†ýè Ö’€€œ°ó€7c¬®œ9«çáÛ Ï',3Ér¶¤‹›q5Ïûu2ÀÝ?©´ÀV ©ÿ<%0 ¹óÁ1¶¨\¢rWÂ/„paª Ë9‰“µ¶Ê®nâiÜø<®Ú¾q¨AÀf¿y‹¬ä»cl “C˜å0öG@nïÛâ5úBЇ^¡Ñe—cß[“Õ¨4Y ³.y0,”u÷Iôðþ½8Áý—†Ò@Ø×+ ö.ÝU®’‹ÙCa2m7ž'Ð{x¾ÚtãoØåÈu»nü©ádæ‘5²ÿ*§ÒïÁÓt‹Sâu=¬Ýbß«éFßCÒeAx,cPvsÓTÁ{\QØÌ $βkÅ çf ,8`¥pi`$Ú¤Éñÿkà˜-{¬ßUÊ'»2E>aN•lð˜=õC3ð\ÿpMÈvA.M{ä„ô»¸ùÄWfí./KS3x Ê¡±Ijài.lœæÁaÕŸ˜îlñäó&ÆO”¹Gp[#Tn—¸¸±gÍ›e!Ù,ÞðLN ­#ÅPý™“މMA_+sŒ}ý§IN~H…• SboŽèc2²Wó.®•Ú¿ìÖg•:rTβf u£ËÝ)©eumÕ!|bóíEwòCÚ=å )à²OÜG1½€Ð›•aÒ{õû\æÏÍvfmTC°ó‰èV^êéÁ½eu²)ÎûOµÅV©©á:¨”G¿²,s ž:»èÜx»mø„…Êcp©ÍwBebT_o9ÝX}|õ XÊ™ž“qP½B ºÀb8Qh¸n¤fÑ ¡D²Íúz|þSVöÉxUõ ®ï1%fãéç">M‚xX.:®±(n皯YÁ:·SŽù-÷{Çœ‹‰·66&GG ÿ°Ó ^Ía,M~´ ÷ ½’ÿ+SE‚BcDÐ cž‚YnÒìœÞ Ôºï*Fýž»+À)ϹH/fSnD–‹+,H¢ä+ôÀêÚªÏtùgxs=ÂÓ†üÁIòmý‚!þ £MNƒ¥@ý¡Rò >5×ÅEC:q–‡­N3ëǵ‘dcù¹uÍä´qf1ú¨ñä;Œ¼RƒÌãyRèÞ•'ʤ®‹ ôÅ @ýôš+ÓM+FæsÁ’«ÙûS¶Ð_Ã*®ÜØ%‰&t'¹$• æ£·Ë‡ŒÎáƒõÃÅï9ì9’€€¸œfÍ*ÿ3ÀYµÅxñdZE\ý „s #[Ìæw®I#Þ;“ƒãPuå÷‡ÖtÆ¥ìäÅ.Ì|ÅÙñí¤E^Ãê*À—«›™b3­G¦tÐiâ½UÆxÏÿD»jÑ…—7-ªå®-5¨-]'øâ5˜L{<ÕÁùrYS³ò4ýÞÐäfÙ¶¶ÍyO"KívÓ¹ÎØKKîZ1Ñ/yÊuÊLnôÍa|¡Öï‰ ¬Ö¡ 'SVEVÖž@\‘·°+Á™é¤L”êL3e|â}dEBþ²{ÓzÐY—E§^CçÁÔ£/*–zõš3\Rc阮Eó)}¼ë VkKL¬(UËÉÒxQÑèu÷67„ –8Ä4¸½OP®Ó’ oçÂ"æO’á»_§3«fxèwûHðpr¯AˆÓšZûëƒêúˆu,‰ Ê]‘,êàÑ‘DóÛà 8úëLYG5Chu¸?É’Ø+ÍîÚªì2²ƒ‹Ý»ú²öÙÓ—îYüK‚ Iy*4ëäJË ^PYŽjíÓ /à ÷©ê÷{ûÝTábVûë–©døÞjtˆ[EÁTˆ”âÖðINÑìãË\c·—U?túZ¦(IîSkbùMµ:ߤNÓä• ¢ï?vLÆ ÑÛ¦±J‚5u«ª)yI ©A¹’—'•féÀZêI ÇZƸï±*kÖùóEàüK¤%ŒÏØú™AƒUñ!ÎK‡1¬Ã¯¬¹‘‘ýK”i2êËËå ‰’€€¬²[ïdKUmÄ”ó2Á‰ÂøLÖÈÂ^"Ê*Ÿš ¿4³¯þå‰]åÀ4nIß|PÙÀ¨ÌˆMòÍ~vi1¶|xoà)9I;?p‘¼žÒ~¦þ]º®]í³õîƒÂ5`¶”LŠž¶«²x³˜sÂp§‹›0.O7ñ§A8#Š"º×#±TÓ• ÿ— =ý¬¾mÜ«öÄm€ŸRÑ›--´íЩ›YЍ\^eØX.·âi0ñN¼Éµ)‚ Û§¡F ®x†¡‹S¼câ'È]ö`4Þ¡bÇ—¢5›g6¥ù/éÆîâYÉùÇ(4U¾¼‹Æþá“3bó}i×W·byã©CÐ[˜²I2f·{È5:1“ß?¿,X$¥O«4sCd„Å¿thÝìöÏfÿÁOU‹ž.ú[6E¡xàpì5YFë®Ïþü"ßÐ ¢M oÖ€ž0@3ʵÝ›§J¸E…r FШR]ÇÚÂNö ÌhúeÁ¡9DÈœ_Ö.øò€é'ÎS¿fÇÄí•MþîAIÀ·—Nü!ŸN’…NÓ#'<z3ÁIkŸf½(ÎE ïNQBÄŸE>T·Ð9@1àJ³{}¢òÃ%f ³ Ž£~€q`e#¹ÓrV÷c I‹»e9G?%{.bØï#ˆý F’4îAå­kþùa1&auKLì0 žÃxâÅá›o”3¥ÚÍ1=Õè&zaÐq Š/"ïéiž0ðV+hA§Lá¥ïöüjöqç7è©ÃŸ/•àí>ÑIsF®¡¢{/Ÿ^-¸Æ¡ë¾®»‰¬f§àüÑ (ÈTn‡vÒÛáÀŠ\dỈÜò«H² ^wÅ݃£suòDÖ:¦Ýi»t ÊLF^—Ÿ$™õgTÀØP@„!/Šèwç_Ÿ7¶@b16Ö"Lè_ûFR~mëÿœiYN¹>2 Óg0ÔRaì3(9ÔàIÇ.ª.ý Ž»ŸVÙí9f—#Ik1šFC傞ü¯[࣯ׅ¦q,®h{NYâAŸØ/ÁÎ4öÁ›OÞ¥Ýb7½ñþì¡/¦"õ fW´Ä ˆjª/c¼Ñ $½Fù›ÔmÏ2"œÂî>“:._JŒeL¿?íïLó ü ¦‡c[ž‹HØ?ÎZ‘’€€ÞK¶šÙÏ ¦×MN]•éå˜Qijb Ý…ò>\ÓËŽ©5*NR°As¤¬rpA(j·s²Í³0›0lûÞ¹$HØ—÷®[ºÅiG)m€ÉVÙÜÞ½ N Û܄ۇUšwde(¿¹ÆW¾º³{ÚG8{7—EdÚ{‡9 j×i݈Âv¤ž¤ÒG§§vÄæ¥Ž…Ǿ|øÖ=ÞÈhÿÕÝ'Qi»…`ŠR¡()óÿÒ4±m—b tfÑZq?è–Z}ÔÆ-ÝÐåPyU®­ á!„ZŽå£Î¥í{Ô$G¯/ëIkñxÍ)°rI§ò(©1‹…*&1jS9ÏC5¨ E¯][†#€Q'µïº%º,(¢…b3?_”¸ATEB?顟M‡Ti†\j4=~”©!Êæ¡»PûIB†Ù«DrÑ4¶eÈN^ð´²SYl‹¿“ð ÃÕe&v Ú>âò÷ý®÷Ô¢òTÖÑ^…þp~¹…òôÎE”KꎩŒ~hæ[üJºø±Æj†Ä§‡'VÙ«ørS‚6ØŸÉN<«N–f¸u lbœ“/ù‚{@n8d¾Mó¥È¡E¸)U’@ MÞuÚ+Çt2»=BaGù®¼3²ªZ¯M )ç_û—|]‚•púEh‰­…1 ï‚~ͦxÖ¿¶½]®s‹…µñ•Ë©yGãU³ù%…½* –i$—È÷ÇÒý²r“çè÷CÒ¾ïâoÉk¹Û:¦Ïoñéd²®^®Ï'jR÷hOrÁ>´”Ÿ-9b|ÜG5þ·xÔãHÁ9¸AqAßWÄäÎ(¢¶l»W\m(ذ,P%ùtYÏ6ï-°i˜K ¿‹¢Ç¸ïœ0ƒäiÙa÷£{ iýÍu¼Û-/KO8Ò B"ÞOUQ•™G:5̵!ÕJ”Ñ¢Ùþ{|3€‚wùCy/N _¤oÑÖRå3Ïw¨‚Íð\öÚh`t&œ]åŒI!£‹°àðå7Ù»ú[ z”î¡ä‚¡¿‘ü¿ÚÔºšÿé‹›±Q‰Ñ—)† ”.ÿb ƒo3ÛƒHãÊbøkÉ[íSýœÒä{;©Ÿ!À¬`bíŒþ4È$äÔ”s5އk#ìô^*×ÖWgÑOóýoPº¶ò¥`7fd ÆÇ»MÍ,Ç&°P·þ§r÷´vxY €þ $`(Ú.åœîŒ¢¡AÚ’€€¬=\©Žð/á¼»\Æ…áÉÓ÷Ïh‰T05ó×°à§ðÑuÔ wù·ë®ýDšlŸo7ß%?¢óùÍ‘®‰Šã®è ÄjÞô±Zåç!ÊÝ›‚\<œ!€•žÂ¨Geo×!™’æò~¿Ï.b;$m»=É·˜NyIÕFzC?žÑ%?åoÛÂÉõ·èaøØŒ„<´HÎÒ"<;2Ép/bȨ`ŠÚY÷•/© „Ù¹i6Zl—áÈbVæÍ1ÍD4Õœ¸“rv™°±’€€¼ÔÄ@«Å<‡ ćþèw4Ämô‚S.òÝ×ÍKt÷á†1ŽåÙ°æ_r-D+7° ¨º4ZõY@\nÓÒ: Õ¿ú†Ó2zdòît€=¶‡„1¹¿aÍî=‰clÏ…qÐ-Ûøc<Oµ&e슈¤ägýiI ±ÕÛ@÷¥ré(ÙŸ_ôw–)à•1ÖߘµÌN@F]#+§FN;Okôè, ¨Ñ/JúåY^4Ýn[=ÇW¯2¿Õ±½îYßÄ3©Ê¨.« {ˆ •s7Jߣ€Ø¶Ú¤˜íG°Ð½«D„ß+N&¼ÐíJñ;aiøÝùŒ³H~ƒ`Vae¸€\âÆc6-ΠÖ,Œ¢*Çœ…Š`U:Àhoðí®ÂÀavd˶ùŠì¿÷Nd.÷=÷ø#0¡¶f^Øø…Òä×Œ)Œjm_4°^ƒrã?‰|Òvç_¦2ͤ ‹I°£²;Žù.Hãæòɸ…v‚FüÜQ‡Wº‚(ƬϷ®O~ügõ-4äðQþ!gFáì5lÌÃ]£Dòïcð"ÖôCLñÊ*+¯ï‚!!®ç#3¨¯éÉ>@|€ÒyS®‹yú[6/ŸoÛáÉû1"‘ÍW±hܬ¶Ó–Å¿˜’îºOM¿«ƒ]1ƒ™š”B‡Á؉œ²ÏÊfðµ+®ECSÁЧ#çYɲ"«~´P£ÃUçôÿV.‡N„~Õ  Þuëýv¦¥(3þ8.âI^Û’€€Ò€çìqûíwÍ4(uz›¦€ÅÖÌÖÌú²¦î‘}5–Èì9šö¥ œŒârž6Ém„†zdï1ú²ÆíPl‰µÎý>ÁšqRU›^Ø|]c 0…‰ÃjcQdòaÓÇG~ºy_OY‡ÐìÛœ˜¬Š@^ŽóÛ¹–ä. -Ð)°ì¿þŸ¶ù˜Gô-² þ.‹(F7 [©ˆ]¹”î13ô?-Àh õËJ“1î8„=•ÆIÊÒ‰±0|rͯ *=b̈qK‹§¤K#Ùaû@ aê¬ ؘº¬¤)tD‰Q¯ª~ÀýæãŽ l qz‚$þîj±ÈÙ+ IDRˆ%L­Æ?Αäý1ìÔ¶àµ@CR¯÷]­M9 ÇýÙ†åÅèCýGoÓµ€M¦:ðù ã̬úìÉ’'øÛ,+àà ºIнñX ¬ÜúØ:9ÎõîbÐê~+!•›ÆÕ—UÆÎ×g°0­r©pU5+Áðæx:܆(ëÿg£ªK§6‘/¬„{s^ø´2À0 ƒ]ýXææÇ dï{½Pó0€*ƒ:2爼e·2ƒ_/_åßÚ;äé{e9²Ã@,ç¤$èëÿ—Û»f³ô—›d.Ø›ÞΛ² Ì‚Á5Šª¹‹›À–>¸¾gþ•=Æ#Ý¢lòþßnw?ºø}× E_'\bø §w|CvHŸ"Ù4¤[Øó¯‚I¿voFµ®S9Òlü…Ê×rr&óIÔ" õÑü¢’üÌc’×ÕcL&< ºóÿ~b–Ù•õ6ÀÓFN‡o%ô&YXú.i²íP§óyšk¶åXgaŒöü=ØÝ7räe²ÉøKŸõ‚uC‡Îij©!z»RÔ®ÁÝvžì'S¥äQ¿×–GÏumev©ÕÊ[k T«Ñ¨¸^ý”¥sL=¨‰;»W‘+á€=]Ñò„ÐÍÖ·!egA¼[Ø‘ TW2κG”é æaMÇ<òán\®¨&ßYyJZ@y‡ud,úöÖ{|*ô¥³¼’ªBûu…üáì'I{nØ‚ɲ"G*ôï9àÑ#HG˜w£=EöæÇ‘4⦇°j˜„,pdãgCËÑ9 ]ƽ“Ë'sehðÀKKGPZOk›Æ]j3Ò0Øõ1&°Ê?š¨¿_-B&Ä—’€€¸]ýꟂÁwxEl¢C;ª/ú‡ü¢04O Þ¸’ S"{.É>´ir¥n¨eWÜÜ|ÌšØ%1…—¯æn»˜5t#sí•墛þy¯Õ.ÏÛÇŽº[FdÔpC ÷I¿0WN®³ïK pÑÑ."ly­Ù;#Î9“L©´·Iâ}d-žn/á\Õ[šü2È è yôÂ鎊[|d&ÎŽÄ  2©çu¦ï›³>ÒþÅ!ÞKBLįŸ6§@LÐ\ß²`éÚnݪW0Q¾g[‚ëlŠ™ãeö|ʵ}ò¶SFWôlh•ZÑ£ëôÜå‰<¦¦…zâ[ÚR½²b|›![¶è5Ã|”ºxß¼~ú<OgšJ+•êŒ,H>L’‡<#Û²1““¢d(q›M ¡m:eÜäš)ãËQÁdQG)eBe²ƒ…Ïé1>úº±=FMìõÚ»¨„øñóFò4§#˜àAR«q Ð"‘ˆ‹iÔ,Ȭ”×ûWòÐÀâã­ª!¤­íSA%9Å â,}Þ}ü²“W@&è)F ¬<Ö~¼9É ›I‘/œ®ó( Ò’íÛµ,´[ï3•, âî.õDi±!ƒ¿Ä+xHîX*-”ºµpÉ`ì(òD¯7Kê(³ó³Ñ\-@hŒ±ˆO†!×…è®ßÇCÞm‚ßpÏïÝ>‰„ûë‘—[;ìsRå'òÀÖ_yø<ÊcLZýw#Gt/·)ªÛá:§ž»-€(”ö[c˜À:15LŠõ_ª_IfûÞ <@뉓Ÿ|< ³Ý-©ÃÈ“ø‹a„üÑJ]ù6¡«múΦ hÒÃηÊ×¥£þbOéè¨×—³‹¤¸q \Ú"öÐÖ¾Þ”Ù‚BÍ5Mu–!蛸÷ÖsÓËíŒÜnˆÛ\6Mþ!Ôf‘r5{¥KSßIyÚ2ºÕWâsôpënõÐABp%b6È–se8a*Öú ÷×]-ZûmÜÆL6;HLÂæ×®Œ»=!Œ.7Èd"–¾õÞ6÷¬æóêÙø,}çéa—M,@Hd—TØÌùÜJ±UvÄÜ¢`‚tûƒ/sN k£„dÄвì”= /±t,|0Xzå,ï ®‡KÍÜ3ÀV‚õæ—V†­–…¸öùì§‘Q±[ÖÑM. ¢S¦’€€Ç!üØÜÖð%—aš= Ë.Zv¶“F‘»Úkîœ×‚E11âé35÷Ôñý»Ò0uŸr¶ú~gVRPH‰:zñm¨BŽi£õ&WÐòFM2,«†åê#¿™xŸ)“¶'ÅèDõóaHß ß'ž÷É< þZ„=бë~dà<¥?zrÛjšm{kÇÌ`(fãCZ xêYäV„á‰8˜²ö#êS_¨›6“M¾Òo2å|ûâÓÛ¼§_ÑÕùÍæÈº , ²6fe¾’« aýtètR9Fg8l•Ó%¡îÆQ¾Bo~âŸPF¹ØÓôeá»Twç$Å«>M à0€U‹»‡åx:Ë›ŒÖrÀOÖºÞž`ÄR‚Q®mȪ`Æ »>m·©W¨c1@å#ÛžGIøVnvbî¯å_SfCSû7Ì\Ëo™Úï«+þ ohÅ©Wª®¥€妆ˆÿ=ž¢áî'†CÑK£†0Øl$"gš Û»þ@»âD[BH¸ù1óYëA‰¨k‹$ „ÜŠMAO °&>ØùÌXËàÇò¥¨–ój?Œ~’Ï~«Eé ïuFÕ`Ìþj.Š/v¹}†I2CÙN–‹„˜v„ î ÖЩ帯t¨Š®ìdò¾"ׯ ›<=ã"EŸ¬;J>ÃŒp¢T•£àŒ¯Ìí3!YˆSÕ”:C‹iïßGöj©‰kúÂÖ-gϯº8­ÊSóßGãmÀTôiÒ2§—…ÉÑÝËáâb^¦ÈdFj·?½Ë3{ªã=8ÇÒvã|ŸÇ»®d£~S3ÔÿàpµáBAÙTÀ#¹¼Ÿær¬ßF¸[¦ µU£Ç\ÀŒ²öê4­üæ™«Þ z¡Çä~åüò|»—rG§ ND Ëv½ûSw)^êP|ÞRTzÛ5q®ÈuÏ"KŽöšmÏbH^Có0Ç1^Z˜Ñ¤¶x÷”éª ’òËÆ!Þ/¯E;qo×”® ¯³9ºJEtõ‚pØsð¹‹Êó–þCÄ!Å[]2ö9\¼>Vî€' ½¸säo+ͦ Ñ­ˆTn•Ú%¨`³öÃ1ù7œV‹»CÔ“ž5¼ýç«ULù£Ø\Ì~†DK+°Rú5½'E³=º\$bêÙ½§Í‰1üÌ^Û’€€—…Z‘¯‡¸« ~|RRp|2ç/ãIƒN·ßwø#D,ž‚ä2*š;OðfþĈ)Ѧ>p`‹ìßÛ^Ò¼¨8.6\bà Že"~û|j5Ýì`ç#asŸc™–Þ‘xÂ/„‘Döß…R,&ç}’wêž‹¸~À«½ÇF‡â7î箟¡Ýt(‹Õ2muð‚Ý#›v©=ò¨èKf]ŸR"%Ú»çÕní²ë'1S¥-İŸ:3í/I#7Ü;iEQßX(mùËæOn#è<"Ìáp rrÝ,üÞ- ”±BiJ´øÿ^%ƒ:¸¥Âã\M€XºŒÃKSŒèƒÁ®6o¾…†Ê®×y17·•GGÍ"DÙ%_Ž-îI{K±3ÿ'¡û¥ùx£ú_Sý×Ïd^f™±W†ÿ> (ÌÌp°Mè+3Hë6%ïíaŒmK»øØnæ|(ŠõÈ­OrÉY 6Óú³¬é(`y¿ÖÍøcÌÉÐ'…µ¥S‘WÙÑ5ŒºÙê ð¨å¿m1Ñ«ˆ”Ë&óPƒáL“gªWf¯©Ö²úùÜŒªº'¹`;VìùãÐù$’Ë#3u¡ÑÆüê¸òû–¥Ì˜ƒ†Mj—ÙŒk’s Ï?iž f:R-D!˜¶|>“¬á¬•€žHŒêŽå2q2¶tt’€€Ã%Ëkƒäâ˘èkª7è"9áç`±›ÕsH9ùÚíS¤[ñ ˆ&Ýÿôc|gvf”C ºµ|æìò ;lK˃ º{Ђ ­O ÛiŸq†aë<ÚÆ?;¨Í`Äm9ŠªåMˆîßÓ·Þ$ùï֨˷©Ò›f®ßwGtÁŒ¤†mG•!‚›z==ð¾ëpãKoÏøæŒA7W¢ÞÆ—1GœáÿZ¾Ë³¥Qv ³Mãh‚>‡Y*7ƒÉÔÊ:Êçõî<ÐiILl¶Èª8 ŸwaègøZhÎ/®šlm}ŽáB¤Šæ¶Î¿uqçÿ1ï˜ÌGíáëÏë4‰t±o8óypÍ칆Xù çGÒ6pöÁ#ØZȾ’uׯÀêøjŸ];ékI©@ˆæ½²*m:0¸G!˜œŒŠ-è7[jäÏxy=ZUŠÙúöꉡ·Ô+¯ð! ª3ø“h*ÜÂvÍ]Q}Cpþ=:·7ÅéÊiÉf’܉›+ðé6ê„¶÷”j(£]’‰…ÊÔ¬ííbbÛݾ۔§=÷ÄjûÝ~í¨Ëœ}Ë}Ÿè÷Å}ÿÌ~Ê{ÒÍf6°ÝŒîy[) º¨X×)R'rgâ‘É„£·Ÿ®4êŸô‚)8@ ÒèkŒTfÍè” k/&I‚ñõLÓÛ¹M~Sô¹ Z(>¸­¥ÎJöFGÑË_ÿ¸ÍÝXÑœæ$ C‰Í–fV3ûÝ>°ì/ø'ä®õ²0¯.·øoúI©jTé±Sa[#O†Hø¾t¡°±‚:¨M¨óM ë~©Ð§'ËRº-e½(a{;¼ îË!ÒÑjy˨îþu9"^ƒdtú-<…cÞ"ÀÂ;G‰« âæo…ëP±Ò‹›Œ®E{GZÛU}:}¬b<+n"2þHW{¼©µâ¹uÈáIý,ù„”ó¯*8Hر]"¹£°ÌP«nÏÉg¬áÒ¹ò¥*7ÀYƃ£Î¯Ïü| R݃{'Ϥð»ÏBP† ç¼G@#Û8 ±SùÉ„ÔÚþ½‡VTnµ¼xòe»˜"ùkȬµl…#×õ@êÑÁ1ktþŸÇ„y«ÛÏPeõ¦øy"<ýÄ53·ávÁ~ï+gËH°Ròx[à&áfžY¿ nãL³¨˜ö²Ö(XV5’€€¹…<])Nú8KáR?~Ú} ýÑ êæMþźiž¡Äµ©uM»*_[ŠAPJˆ×aqÕa œJØüKÎ>X2I;d‚Fï¸4ÛE€àï!ô¥þ³è3ž@Úã²$ÚäÇ+¼)§1MyÇln±Û]®ñòɶÔåJçç~WKCW¿•G8©°KŸã›P–ƒ ¢ 3ÎlR×ý:ϯCÖ–ö¼wöeljp¢ªO£w"ËʼƒUmÔv0¤GŠfd¾»7q~g·ôÙ±7sJÚúþwáü]'k|`9aÝ0” ?®©:³Ñ°j܇íùœ×q˜tT­h [x5ËKËÚ$!Ö®‡KxëÙMÉV§c£Èà¦a¹ rå ÷‡‘ãn¡·ö‹õ'º VÅÅîÛOà`ö®Ö4«oC»¿X?;ŸöeÓ›|Õ·õù£#¸‰‹aò¶_±‚´ETrñE«—†A”ÓY»×GþÈ,žÚŒf’ÙçU?|€Ñ:~LöIreWtǡ֘ʨ Û„ê4^Âì«5hÉóƒrÄoÉÒüÚä×yžq¸ ì#CÆ$zÚÖöµ•€+¤¸š?"dË1]@w4¥Ÿ_@_½ª\Ï7×PÌIJúÔ"ÅBÛWFv熰§ þPÖ^LCõâšÖW8l7féçD¯Ìw<‚ æù×,KYŽªÊ;MÙNˆhr *‘mM½Û‰Ä„âZ^ç³(uŽ„ø‘kKyx3+jÛ¥Üá¥ò¿ Ôåž$fÍÿ}{dI^@QQ=í×åÖuÔ]ybÊ/•` %8À×e±`¿²e”“²Ægß&êÙºÔqôÇÍ\"×_É5%¼ÈoXFK î?\A ø33\šŠá¼Zd0?ÌÇÌ!ƒ†Ág¿?b&ÃÁTx#Õ˜ðÎXÏY7™æ+Úêb”E)/ÒÉZ]wPÔO“ìÑ`å^™+´ükÙqk!ܵÔ9é)L¨ÿ¯4ßÛ7ÝP*Xü}½ÊÊaҰFÚ”Á ˜KËÐã’ÜjˆãWæÜ×}—ü1˜©âV[éHƒð"² ñ±5m}Í.ÂI — çÍ<?äÑnÔ˜Õ‘n-ç·±Rª†Ù¼ ¬áå÷Ûà²üßãü„‹ÏÝè¯ÒW#o ¢ÈÚßJDÐônŠìBlâ5A”’€€ÍøÆÄ[%±Å hd¾ÔˆtÒSy%]Ã2÷X ®¡ù“…¤Pp¸ó6rÑZ#eû ^b_æœ]`7rÈW²–Öûݹߤ+𵚲 Ÿ¬Â,ñ»2ÙtkÛÝ£›46Ètê,ø® ͦ²Ð5¤ÓÖWidQèºÊ‰އ¥ 1{XµÙ°´A•ˆ#UOtÙëqÄCÕ“”`)KWÖZ¢€BŠÖÄ6Tì?â&Àš *aPßžàÆ„,µÑüû=}fµMé=§ Kt kþ­ßU6 âÜ ³PwO\~yZǵ7…9 /¶™ÿ:à}^w°+dôa *Ü-òe‚×¼YnÝ(EtyÅ—_u/å/ÒqÙ0¢ÂÆêãý6.gUìaKs,w%>6õ9{Û¬l>Eú„Ðîš Ô;¼‰y&nq¯-ÀÞÕ[¤ûxŽR· ™kìDûtÅÅ€7à¸fxâì—jˆ%DÂ-b±agä®ñ0 „ûV«Ðf©Üýãû´ß½nK +›/ÄBöñ Ö© –Þe»Z. äÉ»WÀî6¼ÁXò`ýçõ?ßö¶Ù³}ãI«*; zÕÉv³mê`ÍýºO¨‘nÙ¨4¾Óªeë¼ù¬¿v6ºö“ÿëôãµA×+êÕ™”Áò± ²,"»X(çˉᙲx9Б··¥bC8;¤3“!›ØMænnyß¾r8Îê=Å£ÙÛ qfeÆ‚¨Ö]¢«®)û=)m!®A ®Õ’ÜUæºcr3GÓÏÅðá85½—ÉÔ¹"Óp¥æ<×Èh¼^Ðr¾£[Õ½.+"µ¬ø‡†4’€€±Ú ñþ1ÖYXj“©9û¦œbºâ–ß”>iœ)ƒP•˜ìP`Áöô.ÊœÊüño žÇì•&v–o€|g(Â2¡*€øA€Q{ÉzÈò¡²ª°S (¯hÀÛÜY™‘Þ£Ššx*è(—ß¶U¤½Ý€;%5N¯º¢NÐJDŒúåH×Û/‹Eƒê/ÈŸâÄcÙô=;¢ ïO ôûî9Âc݇¤Ïþ§¦a£ݲ­{Œ(øEùÿý½’úðR)•ç°‰‹ŒºÌ¿>j¨d™*’"E^={ú»¶yñIO…~bñÐd13ƒÎ³Í‰˜S4¢‰Ýñ,#¸Œó›‡Üž*M6×¶hðSÂXõåò¼W°c¯0»JS™î§<°"ˆM¸ÊM iê#áÈeð í¹Tõ>Þ›>‘í‰Î—h ‰§ÄŠ‹¼Lˈää8{úà%1‹Mr›²?ÃÉ*É1ä9-¶ÞšYï9 ­’+¯uÙ¾X^;4î/Ó”ïAed ‰Ž'ïÌí Fr3Ö)ËÁV¹ßFæ9·¾¡x•'”3À¼¿ñ9ýíºÖYµõŒ€Û8…ø+ÖÃMþc–ûÌPD¤S½@\ó?H¯hŠ^6ÝräxßßRÝ«n N ÄãÎÈ{ó»rÐ\¶:q¹T™þèY+̆»ÎÒ.ÜâíhžZáÄóæ–ç ´„E½§ìÕp(q.•ó­]ùÉ¡‰‡Ueîý)=aJ Šz¢˜±2¤ŽýB¡xÒ»´̽«?–†,š€²ëoK=Èù’€€½­D©Õ§;>#Ž ’W[§a¸w·©õ YKaýî$JýJBdͬ–Θëk¡Lï¤~4ÎÏXxø_­¢ 瘳Bk’­!Ífwcµ¥Ê½Þ— Nº¯·þ¼zML‘W2£wèÈ<Ìhx'Á rþo"u„‚)ãô]E¹»ò÷ê<M”qF·j曫‘¥¡cݽ]¡U ó]U1)’öÀ(u¢f²Ât£JaÚó¤éB3t­êŽÝ¦“¹X1Ô<`=Oùz½Ûz?6?tôú¢:Tdºö~/e¬Vá!<Ò­6¾¬€Â˜8`ÙTÞsáGíq à>„–X4ŠP˜C½;ˆhÅVØ5èaÛ0ÅUQàúËÚúüT?JŒÍ·¾@Þ•‚Y-”Ìñ®í5ö¯䥯ü°¤KõEA“Lýb(XË_qy[ÿõ=yÙI˜*Ø;®4( ›T!ÔQëÆ£ r±„š ŸùÈé{õæ~ÀHFŸ=¹Ic¯nXB­×Ò€  _†Úã$_u£ƒ<ÏÙSŒ'0­¦uùzêA|Žtö/-L,Å@2tŒÛ3 8ºPW8m?%õ '«•ö¼3\¥w|h9ü±6~« ¿xáŸÿk!™|åÓŒ†¨ï}Me“¹ƒª‘O¹ñ—ïûøj#†ejQ§¥ç€OG1rMIØÖ[$Ë„ °w[¼ér›¨pRÐ×ÞÀdÿ.-V«ï±MÎ[‡zõ]&¢ßøj§Pűɿ«?«cÅì͵4>‹íï^3Ÿ…¨·?Èoõ Ævñ$Æ#,!€Üçí·å ìÄ1@¾øwþ\†o®?ɶ=÷$u×”–)T‘UO%®ÕHxâ¦D;Á÷bM'ÿy>kŠõ!ÛçhÙ\rõó7<¡dpÉ6 á»6ïsbcDQ0ÐF&Ê œšý~°!& À#ún-yBÂ+…Š?4ÅIñ.[¿tÄMBJ$wþњݡµô,éåÏû4ØO©y¬¸\ðÁÒ¼ÒÐ…|{õLÕµíë´CGÆâºÊ¹ÓQy<}†gÇk·ùh¡´×uÆZJ‹ß}êâBúŸ‘ámš:I;”ŒgFïÕöMiÛô¯{ÒñqøÑ!)²núÆ©±­ð+'ªÃ­@!ð³$EQóÖv2X¸ FÅòyvÀ’«’€€¾JcYHÄò5¿Û)B itp·O^IðžV¥`OÇ.‘SH[68ÎÍç%a^šmÒ Ìö—™ÃÏmÊ£Ê)ñ0ÙDåkÒ,Îêþ¹DÆ´ ¹ø— ʘ‘ñlžú#|÷ÖhîcÊ´Æ é’åÄŠ]šÐGåLi-¨#C@ý|··¶µ€%`Ÿ$:°Qê-C{˜ÐêUðú~öƒ~ûØ3ò £‡Ì¿e­ìáHw' 0ÄJ€µn—¸¡¾Ã]dc…¾z˲½m“¼×µòéWö¼ã©b¯ÛÚ,$ý_Ç„[A{(–ÆÞûô–x3Æ`Jû +í€×«ìîz)ËEÇxé"ý 1>×ãï¼Ï\•›)šcKç·+XœJFuù9gLâY® tç?‹çPžÝQ.A²Û ´ê²v†°ô| "¸D…üið‘—‡/Ã…K†É„}Ø"4×ò!(ºGïŠä®ÆÝ*“‚ ú*Èg@©‚‰u)3ƒ¦/I ÷€^縞!ÿzÐÞ»}f˜læ€üßµm…JyÐ?³öþtE?r‚¨ÐfîWaò É|Ú±½Ý'~ˆê­3’ïüD4r-«ùæÚ·–©Þÿñ£sfœz(à ò]Î -#³ÅVŒ)2öõ÷_™k`´°Áº\{ÆT¡î¼Èí¥ŒäÒ'^“—fèÊ[¸H£dä Æ½^»×¢| °ÝÎ˧G¢ÞÏSÙa ͽ$Õ¯„HÉŒgð[Lk)á‹×b°üÏŽbPð‹"×8gî\7¸ÎW³b|¯a¨Âa‚p×fóv§²1—Šä(w¯Kõq)d¾1Ì fS+/ µ¤é¬A™Üû:難ü´!Y`K“èað9jNV?%•¾8ë2†SELyIx; /4úþ˜\Gœú[<èO› ôN¼ÉåÈ[V8‡xi‘ËVtä))7×~~¤jðÄ›SCÖ‡*k!;ưû þÂü ÄæQmw1_ì™>m½l1ËÀHâ8N¼{ßÁ3.ë›j+‡jšæ<>£¹½E} êHñ´5iï‚¢)/.m/ß}Õ¶Àåfm”¡£”¡)Þ¹GÍ÷2‹×^·M/þ6M•b«†¶R»õÝU…æbŠæv7óÐ}[Ì@ »GH’€€ë&!@f…›š×jM|j™ ªÔ¢ùPO6ݳ¯iÀoª½=C´ ç,ó»àßVVH¶ŽwiË-ˆþÅcò ^~ÿhºÀÓš5²3;7h tr“|‘=àL¬ÚŸ£¹ŒÑQN¾Ï_P$î†-†JèÕm@΀ù{" gÅà. âÑÿß]PàÂ+ŒVÍ‚6ºzt>¸·µò—£”»«'|;g‡Ç‘8¥zâ°>§8 ¿;Dg†–Ò‚l{<%Å 2ò+åZ%åE‹ŒŽ z5ØïW€šmá¹!}ÞwÌ””ÁDf²Ñ×(a–<5õMõW2¼¼üÚ$(Dò\RKî]ˆç njñ­÷ {r‰§!q¶tbþö65§R[wÎBg}õà] ­ýLe+O˜@vÓ!3vóJnÁ®ôlä©s¿´ü ýlè³ÊàT@gÇÐc1å–_©Æåå˜öiΦ¥3!núÒÒº~F%¯ú0ý…¤›Öi€À>)̱¹ø…ãšWÓ±^Û×ZLD _'q%ŽP?{p¢÷º( "g¸;{j"óõcÄ™{¥Sðæ<ŠEsÁø²²ªBiç@Qæû p"¹ÈfÌzÍ·¡Õž™¡Y2PGÊÎ5¡ãLé½/õùjXÙZë@w×sBÑÿ¡<ªJçDi]…¡ÿ÷ÀLkÐ?c×!ã4ç‘®ê Zü¯jGa¢ìDJð—VìçA:_wÓEõðYéÿÈ+ Ü6‘ú”רäz ˜º72?#ÝøB›b_H…=X_û®ö—`^}fú 両 SÕLê®Dõóqç…<›ÇÛ…búVèð±¶®œãòÚgw¾½ÀÞj)CpÊ)…‡Ø\á->õ¶ýXÜЮ$ Wœ%OG¹¯ç#ìGX˜‘±úIQÿ†å'£ægÌÜM½åɯíôüÒ "ëòð½«ØË4)hÁ‘¨¡Wî)ÀÚ*®âéú°“aÓߥMu²Ú[n–¶rG ‹Â¤y<„ä4ƒG->‡Y@"wǤó ™e᪓@ló¿ØÜžÊ+šÒú51tbˆvI–áϤ8äE&„KXʸ+pãúÞÏ…¦èQ''?g5ðÍO¾²''2‚\S¤ýê •åW}*Â.C>﬩¥¼åžãH耠#¬³éŒã2Ú‡•F’€€Ð?ì5ôê‹}å‘ÿÒƒ§Û&sƒS à ”4á®o›6ß—ÖÒÀ¡jíÇ}¶ÇÙÎ ñÚ½ŸâB¥¨•|ÿ6¶kBx‹žp*•&Õ û2!ûf탸_š=˜AF‡{éÿ6(dj&Ñ ŽIožÕÚ…®èN±–nSäi(÷|àDñW$e‘Žëc÷BÇÓEòÒnó/ò˜h,XEÏ$ß ÊSÜû";¹ÏŒEë_¸’ÙºªÃàgb\ì:§aÍ£Q¾C#apa®"RÀrðúŽš7]z91Ø^^iv,ƈJ P <œ‰¢•´Ú¨_Y.ÙóT©u+½ÞÒ˜ÊÆ÷ ¹E̺À>K›'°M›CÊŸˆ\ ‹g€¬Ž¶ S?4Þ?Òø”Hºjîõ›Âs5N8ªÓÇXktÚ'´BN>ÈUQ:3ë¿=FÙ¾ ÈYÒÍ–äVŒ–xØF»<¹Ð Yx[+ñJ3ÒkÑs¿$„ëg¥†c›Ô úŸ;GÝÊCXί…Yêƒðjý÷áI‚E=\ÆÔqñù>\’£½-î8·ê×Ú ñ4t™0áig?9`HÛSÊU…!þû`¥æ@ðI¥¤O¨Ü“ÕRgõö¿UõÙXØÛC*ÉÞÀYK¯›À‰QÞÿ¦^`µÖ»~oƒ}ü!*D¾ÇVè¡î Öå”Õ§³À;°¹[x ]©bûBÐXÁÿbö¬FÊ/¥Ö”¦ÈsëýÀ^‰Daœ—“X”òl³Ý—ˆúZ¿*€‰#»<–¸nP‚9l+ÖŠWà…°ØÆúB@bŸÖÞÈ«x1m= \ÜÄ'K&¶^ü )°¥k3¹]ßóÕÒŠ1-æ®.ªÕþÝsKDº÷¹}ÊSmé‘ §ÁcN7ŠY€£ed¬E\1í<¬Tö„˜³e×ÜÀ&Ââ"*]á&•¼^BþÔ|wa÷í7‚[þì6m¤)4¤Iâ€Ø[ט J¬-ÐOZ·'ýS’gµ{ Àcû¼ Xkóþ é6jrŽ (€<¼q~ˆÇ$š“ Ös¤¡õ RR«2«½Bc¶üâ-ê´,xÙ¯Û‡6Öná›ëq\'oì0µÏsZµD]'Æä-åcÂRµ*ªöIgï}KÜò­Å°»º`¸» .2ƒ5•ZÀ‘÷Ù2¾’€€Ø“Ã|{×gŠYO©èÏé2êméñ†s¶< )y!¸«VÚV ÌCMˆìèü¡DyüàÈŽ¨µ¬‚V€Ÿ„¡ljBßäñÌúEôÿß*™ú«oÎ%i ÝÂF0Ò&Œ9ö)ì‹óul(y½Ázöm‚ Eέ¹ª½˜x[˜+¿–l²é 0Y®©ˆeê}Låµ¼äJ‹±'Úxá©EG%cåïÞb–ùv®"£5ןl6€´iW‘¶‡§â w,Ù@¥¯xòr]hu`rMØäK3'I©Â^¢CDÖÐXNßÓOÅ™ëê¿o uÏn0¾ËX!]«ßÒâ'-5‹ƒ.€‹EC'¯Zc¹{mQÆé|2 iÒ øyc|‰á'wöíSööPßý 3ÓdF¨ÀO HÁõ”ú).ÑÅÎ G  /|o•úÏ5GlVŒ¥™³³w±$gWÍ j¨ˆfW„»¼È'^¨(ðL¤´_È#54ô`éEr‡ Íúò¬Ôª}Ñ&vªK©ìgæúñ;6%ß;‹Ù·*¹ú-¸&8qr œ¦˜*› ù‚Š/êjȥ׳´_™Ò){ƒ‚ìÙI_i,üf=è¡P;2.ãJ3ˆšžÉ©ðóO¼’Nkk¿úÊÚüéøù_g ®cÒùMËp_‚I,æYà''Õ•›­QY'­šw|›9S\Ïþ—šŸ'¨Ú‰€L–Ñöë삵;®#=ðàg(]]ti}‘]Kîfš¾Âp’ýÐ½ŠŸ^³2˜øëÉë+wðš¸Ú#ºqÃeÐßpô´–ç»5ÏéŽûÞ°YÆFÍ|"Áe˜Æ;sŒë¸òbaï ·ò︓yŽó%Zà-B¼û#Ô/ß1l¹Ï‹ÉµZÁô”Â0w.¨ÞXøI:88ZEô lÖâÔ“™Úª$&ë™Á0BZ¼ ^x‡Þ?rVks®`ùþÅB›eðDz׫`O/É ë,ß¹ j²ÃWmgѬlÉßáÀaŠÐYËOh|U.;êO3X½¿šR›u} )˜©’Pï™Uñá@Ìä÷ŠŠ*ä›ÇbÿÞÞáÿ…ÊB¶+ŠÙR®“ùÕ¤Ú„œ‰Ä¦À˜,ª`w•. Ø{é2bU@·*SüâE,x“H’€€¹‘û½Úe>²tk££ñ‡ŽÔà‚윣YMÂØ1M(áeµ³LÆô¿HFîÖù'lœ”=‰{¾PG•›ä}»ªs&e[ý"Eü~·x ¿µŽ܃èD#°HoÌa6Õ˜m¡T,yª¡%èÓË7ª×¸CÒ×}òè4Áh[B41Föq ~è¸uǹÉEˆƒÊ2õÿ'¤Ã[•¨»&û,Ì™Üíˆ7]@ºPé>äKüBå¹±›MR¡ØÉDÈ4rÈS]%ÔR. }[€uYuìM ë½m20›,Kt­-õŸBöÑÆ0Ϫè'´~·ÊugÔnSn¯PÈoìKe9"zJÜ?;Á·UΡ֩Þjžžî™(·<ŠXˆ‘êЄ‚ÌC/R(­Û|=ÆÍðEKoßSô±·E]É:²rxø÷†4×g;âÑ€WóBÔ(b«¸»PB[ÈÇe¶‡•ÃoÆÓÄeEÝŠb$–¬‚Áh*ÚxÕBâ'N¶–Û~è]ˆú@[Õ>…Uìnêš™L•¼%ÊkKâû»/J1–Ã]Uÿ·ž2F¬ú™è¬‰ºç¤?º5*ZššwLʼnÓik–yöÛ'%\óÔñêÀNå/cÂC”-üsa36÷ÓèÜçÙ¡¦û¹ÐcÙ¸mÝ]æ˜O®1¢¥ð×´ûîMð+íHÇ7fŠ,¹šO^^¾9zìÚé±8­} ‹Ïp˜=CÛÀÓ±&–¿Ò”`6é6§, Ûå)7ãóKQjAHÄ'"{¬Ø=GR¥ €‰®‘L~Û¸Ê_€4.ÿwiã 9œý¨£Jû‹amñý%ŠÐs‘/ß :ðlØ‚.ê25RŠéð´_¼I¸›ýXeè¬õâŒñ»{)Õ=¦çþmg2y„%_®ú@Yªd7¤öŽO”{–sÒAß7œÿOÕ÷“tÈUæƒL\k ƒŽ×„¦:h‡×Dk³ólîØ–wb·?OåÑ…ëÝœ(%jÛê‚Q?Ò,µ#Ó2®‡…Þ‹ƒÐ4§#ydŠF%Iè©ñù¹,î’€€·P[Ï/µoìû¹·ww 4宨Ÿž+3iÀ¿|r¦D@œŠé/­ÞäŒå+À¼‘!üScFP÷óÐWyMƒ?\¦zåehºÜ£wýÔàõœœ¡ã™žJ¿¡/¥Äœi—¬O{ãïs(Qn‡{tÃ(ÛqP­>‹ýb‘•ªz`ÜÁüP è8½Í(G:'Z<®»]p«Ì‹æ³Î`ömŠÌIÌ?´„”Žk¥Þ®RxÏm£>{pñRÜW«gV9åÊŸù²—3¤.Oå%‹ ÒÍÇ×ÒJŒŒO9€šMâ¹øÏ1GNˆúµk s5þí“G¨5.íÆ!F]‚…¡9ä\CJ›ºÁ‹Aˆ®ŽÏ¾Y— ëI1S)Àîö¢àÊwú?1-þyê™Ñ•1p¹0ÃÏÿ·*áõÛ8Cçþâ{ìq¨Ë•–cúvm}n^ëÙ }ÆôŠJ_[åo2lnAvrˆ…ÀαbþWãæ‹FÄGäPÛ†U”@iÙdß²wÄ豤‰ÁÊ—Úfò}3Ç"±Ã‚÷G)À˜crm­&få/y«&¡x -;Gì•yõý‰ùâœ.ŠÕI¨–ɺ§´wEœ)úŠß–PV´¶èÎ^2’®9%9ôÜ`ty/¬i/¬œïØ¿´œØkȾLÐÛ"ÈšƒYô¡Ú2‡Î× {èãÂB•Gà(>Ð⎼ÙIF Hÿ48]5R°ßÓ ^qÒR‹ÖZ`BHAû9pyW–LI£ Q¬yLñ#ÔªgF0³ ~OJSÐkÏœ ’hæú&³W^´RûüÃÌøÛK"ß®ö¾ (ó̹«ŸÝ†ƒMDdT‘’€€«×å÷ 16äø®ãtb#c‘v;ñ7m®Ž¢ý0+úâ„ιۓ‰)k¨'É<ŽZÁ©a⺸N¹%˜å±™¾–(¸+¾ª´—ò¶?÷¡ÌV–Mç‹3ã ÷Ô¬´%kÞïbµâ]Ûg@6²¿¤ÍJòöØÔH~é™~Ïf$(°Ó¬g¸N·~®MÆ—(¨–‰í $°„“E¢mRÍqÙ‹HQ)?R!¾”Û¯ª^EKK£ü#7:.àár›~u²Úd°RK߯e9= S¨Y‚ BéÞr^͘×úÖŒ[Ѿø¤å &ø2 Oœ oËè†OEßÁ»‘…c(‡\|…‰è‚¶l7ш öS•áTÌ ÐQ<ºC%L×f>ùóÅÞ–j÷À{¦ìëýÅ:D—½âxÛÒ¯€C¡ä®¶f/\ŒË=ÆŒ;ò".ÕíY/QfdÚ BÌØÝv€º ÁVÖì–†Hjð¡‚ÝŠs-mÀo- :øN³µ1Y~ñ“\rà¤u÷›7Mߺ >¸xDLŸ2HI£7ˆ[ñ°’Ë5>]>7~N Û¢¼`¸[#%%¼ü¹üÂg×_IsÊ>™‡@tlMüí•{šk¬ý ¬8dÙ³ÊW­ÉÌþÏu9S²ä å ïpÒ0Æaj¨ük|X=BŠk»ºEʉ(Ä“² »»._ÕNŸ=æMx0&bnPµãlÙÖâ;˜ë«¼'”Ì_€Òp3;BÚ?ÒáÚ²“±Á·0óµ»”r {È™ôC²Œk…øâõ_]ê?µâÆKýïžUU‚‡1p´mÀê @¨¢a'ǧ§­.%¾à#«Xò§\®A¼È‰37¸‹ÖäcV ÿ]Vômlð«æ¨ìÈÊl‹i_V™èÅ\Ù­V2~fÌgª2±'G Ê"PX@5 Š¿Ðèk&÷LeßÉYžo§Õa`äãŠ3Ù;KØþŒ{™;àdj¯[· ©È•E21wQ¥ÿÞÉ4ªüÓ©Àu)V_²ÝR­#Ýj¹è"¸þ0lÀªí•±üíÕ—Í5Ì5÷tìKˆèWK?á_ÚµE~oß7ËŒ¯1ì{"ÂtŸ˜_IxÂËÈ¢F;çˆ;5KÌíÇ›…‘Úd“ÇñY¬–¸SìÝN¦…†m‚vyJë?¤7En{¯ãËêjÈ{ è+¦ \€Õx¿u&¹%O¸P9Þ~ 9gßGÖÖ’aÛ|ÿ/§ ¦òëoL9f3Šb … 6‘‡k5XÄ—Hõ›†ÞI­šDò*:&°<³k·¦A ör¼l‚„uaÑbC.KQýÉxÌž©\’€€Ïh¡È ‹½:™ _8x04ðÄÈIêˤüóY…ï7¼Ú¦ku)ö¶P9-˜Aro ó˜¼öÓn…ºmžQZu¢€'¶¥…¦Ñ¬?¡iÍ6ʉYS]†Šî„ÛŠ³½&a_6ÇOÞÁkk<ü:¼Ûå­ jÇmtGt=Ñ|eÁ"öížÛ\°pcŦ¸…8Z:mN¡ ´À$ÕFodMÓdÆHõIžÇµ7¯÷¥lk°t›Yå _SH’.SÀ6ýËLö̇ÔÁ›< ™ÆžಋXã÷{T_àÙgÅGï¹ÂÜdõ‰¶›.ùúŠò«vqœ†ò±M‚õj VÝl޵1ƒÿâ/8w[‡¤P!¿Á½}ÚS }/d?c»fÔòÿŽémƒsí¶‹ÅsÔs»rÒæq°Ær›àm´OÔH5 ,zÂN-fc®1†+òº3Z×YÑyã¦ð" £ˆB·Žûλ­ðHÙ jà¯$±^. sŠSØ““ ˱äU¦c~Z„ 6q7¢2$¶öèÿ7À›ÑºÓ>iP³a„õÁoŠä?ñI`ºö*-‰*µßɈíÊ…G‰8…k†dTÓÕ€ÃÚ°qÔÜt®!4À¬s6Ò›”ÆÊ$¼€¿T°ÜÞ‘”¾´ŒiÀJôgŸ‰ýs&—ˆÀLÀ;泦ƒi™€÷-ÚœþˆžxˆÙÅØŸË3'8¥l`™ Z‰•`*ƒ°ÚŠÏdlm°î…“JÛݾ߆…M\ ôn¦ N¸A€Ø5Îè1ó‰(ÒÀÙ+hX{zZ‹¼®î‚¼â¶<œ*±v $®@E" æì‚ûÑ~âÛßuP¡‰öš!«`/æTŠ è‹À|0²ŸˆïG*ø÷iߤM ¿K ©ÏÆlsV€”ˆ¶È×(TÜfrEâÆïÀ ¼Ë%_:'RfWr ¾«#²Î§Þ…®XgöÐ7­[P¬?Ëæ«1~„_ OêÅ€éµü;øC»ã§+ê$è Ú.Å7u¡ØBÞ#d~¹¢¿Ûw: âo’ü†/©ªšìΉ,ïÀÑQ˜éìh Œýh}L»¶'­èèÓ6n‹X££™à[«Î§> Ö^3÷{F=Ù×/¿·m®-d*ueCâ9v›ÿõú y™yï)¬a8Ÿ×Xçºo’€€íÃé“ð6N$È8x˜¢öXÖm4#ŒM4õi&Œð‘8ËneóJ’—IöEµ%—wåOªé³¹‡±¶8ÎÏM®›ÎV ÷Oå/W›ôöæ7¹¡í¿—x«dÄá£ë:ÃÎjÎÝÝû 3C1–â¢FÞ¡†‰¾J€®T{Œ|MR_#’2­Êê5n˜–q¥ [+†[SÉç1¼»¿ß‰1iqbñÁÿPÙ°ßFÉZßšÿ`X;Ú¡ÿ0 å2X»F´Ù;éZ‡Å[dèÜôÛ;ž‰XF¦¿öV܆ÚjýÃiïÝ®ÎI*¯Úru$ßúrVÒ‹Mëc»cJ¯>oîêçLAøkG#jT¡É…£.~qa&ê oÌCOò#wñïc-÷Qk[—¶T+6™.ÉæÐX„Ÿtýr瞆îÜ+¦†@Ù?»~™½!>?˜ý¡˜;¢»›ÎŸ±iã ±Ea„›Ç’Ê\-è-±«b–Pš !ý‰.™º5éZt7U’üÃñ´ç›Þsm]]"tÜê‚Ì;5‘M7Ó®ØHg¬B¦½Ûµö¥¤1¬\¿Îží1=”ëÓ%b^±ƒ6Ú.AZs•U]Sü ‚•œÈ …™¯œs&švLÃ{ïØù\b§ù5Þ¿Kš/ Ùš~Ť G#¢eô¾D~)ÁÇ´Ê*p±vÝ×¥¤¹¨‰Ùµî=ž¼À&íø¤›Ã`‰Ö9¾íËGoøkОîÆçÕƒ3àVÅŸ “VîÔPìš5ƒyÅ7 eÏD¹lðbÍ<¤J’îg\™úPÖMËÙA®pŸCHÁ;LÄ&llvpŸŒlp¨Èl@JY¬Q”Š„]±ó7Ãr¾§À¥`<è¿EBä*;$%ö‡‡…êøe?‰Ã+ëæ’€€©Zåargï6ÚÛ¹Çâ*ßùvYl©À»Ì&£ÝòLYS>¾Ép‡ëã½CϨg¬ÜM¥Ⱦsé*,ªÐ6Løu<Ý<¼`:7Ù¢¹ÀßàÞ.€_¼`Hï“î×­Ø£³G zº~N/dÏÄ@=Mt€ƒiÈL»¡ xzHÉVjlÄaü"¯¿‘ú#mCêÄ€Ÿ(‡·„bÄÓ‹ðLšü„\š©H(wÖøãšÓpÏ€»·2n5NFßÉËè¤á!ßD»œ ­PŒ‘_“ݼf˜(ExRr+i‚a§}¾9õcpyµ„Ñõ†¸ßÿÞ$Y;³iÔÑ0îÒŠó~båšÜÏctL™ßØ]š¾}Ä3§ðËYöœLâÑ)Z4 &ùz;¤VKR9H÷Mˆ´Züb ÍÀØJÒÍä£@ÅÓ÷dAÒ´+Žþ.y¾HgŸªVÁÏ¥ú8#•YSþä¿ñ´‰õÜ «†EÁXQB?pUSVÉËG½ô{,1}ø&ºÐ-‹-‡ëÄE±¯ùý‚‰¨ÁÇ?¹Â  å°&›Dd;$X/0Ú\iGË*/ïd\Ò6Ô!ƒnhº¿Àù2CÕÆ.ðnAݬŸG<5fGXóò~VËàÞúÀm{ÿXãR[žõ×§É…h†[Ûª²Í$ÌÊ“5\ÆÁ\èÙ,ýà ”¼æ‚Ç1],\ž™,JÛ¹›ö$õ&ý7íj#+¨Ù)ËÑ'-ºÁs³6¡Ž½~7S>ý$ó€Ö½@G–è1Wïµ”6v„F§û/S;l3–’,@ƒ£h*Ê•ªK-¢ºÓe²é`ïbÄî#¾Ì „ØК_FÁ×2ÿ2—©ÈÎá/Å v}AÜuùÃ-úËiÝÓµïúÜA‡õ€E²°¡?‚ÁÊÏN†ß9­Ãã9™.z‹ÍÄ߆œã”­yNlcgÔ›w æ˜>dú³¾LžXߦÆYïøE_ÏÏ/«S9¹z…âËÔ§ýu%L²{ÉÕÃZvg„»‹#t ŽR?WDäì’€€¯¬óQ'·´ð•ˆ5m‰HF‡ Ò½¦ª–¸UŽ3mû¼D½&4[:Å {,|åa2å^‚kCûŸ¥øþ¾¼LÃÙ¦aøÝ fÔ-@¡kÏŠDÏ™jGÈÍjxkõ¥DýõÈ‚$g´"$zSYMˆn:غæ€R¨Pµwå*-ß|#@ÉGŽÑпDžj| å´œt}›N»BÂUHjøô‹¡õóâU*‡·»à2÷t­$/VˆPáøãÆAt á9²ÐZ`X»2·tž¢Één ôòFP†§ÂŽ·Áî÷²ÞÍÈ¿ö©B­¹ÀÜCúéf$=6h9'êãËñ„ùT(«éC¦e øh±L©ù ÕÄÁ{ù?Pk§ï@öMMÚ,pF¨iLÓß@fð²ŸȇC§DMÝ$=_{õIÝÉ”KI´€¸ü _Ý%œ›Ž èý<ŸR"–öÈç‡ÐÓ5Ö~JÏ¥1]w»Üçú<(áÖóü›ûÌŒ¼e ¼o¶!z¿H£‡ÄBäÕ›Ô=À‰ZíPKùžÓÙ°TPÃø˜!!àç÷"ŽX‰ïz¥z1Ê;?ƒ®¡|“Ð1e~ D  ,[ß½aÛm‹„¸Ý]¡(J™¡@õº*õ¶2AËóë,àUm«š!ùËç]¹|ò¼žø"nDm¦G3¹•ß4`/?¤<2  6©¯ˆ=å 4 2Ž×†rH•~3.x¶R­W öC?† RÝí%Þ+Ã÷Örƒ-•ÙÄ­’`£µÅõ¬½D–ô:˜}i´@Ž¡Þè¡âÈ:„‡8RÒ1Å^ß‹¸’,Àéÿ=º’@ˆ‹QèšÉÎF eÜ;µÿÉ|Ñ;9ø°}è¼È$Ô™lÏT4Î6S§wòÄŠ ÕZØEóÏE Ø—ºl´Á$Vô»¬QßQ—É?¨‡q—QÞ«ÓÕëh>š·þ=¿xy¶Lü"9äí6 ÃÒJ7á: YÅÌõÜ!%>ÈÉ Î›ÄQâß'4v{É_oÞNÝ¢†!{Ö`ÿýä2ÃEÈA¶’¼›ŒäžÁ%©ìž/ÆrJ}Õ$Šü¬buØÀ±ƒ$•bdRk¿Í*©<ÓŠ^@u–Gª?߀|Âi6Ö•ú~o ~•“\ñzõû$Eš0í+NÙ…þ« ®¶g% bPXÇAöUôÔ’€€¾ïj¾ié&w§zW%äh}×ÍæïuðJãðm\gJNÝH•TQÈ·ã˜ÒS«ŠìP“ƒù—.8¨-$0§vS¯‹i.A,÷ã†iwÀ´•®ŽÌ÷[Z3¨[wÍŠâN  ²¬2ÝÇV(XÚOŸû9ହ?½aûí)·kDŽÔÇöÓ8ð²DÒØh<4èÌL" ǼЃdÎkE£ †±Çð¥1cS‰y[jD^\¾ÔWÕ;GðÊ1V ù©6³%«zâj8³Ç82…8ÅEÿ|?Š’âUØ¿ÍÈôôÁ7”ªxÀ Özxw7ŽQ­7<šåÛ_œÂr‚*©¯ãû¸†er´ØŸ…ì *ƒ¯õ2¶ØfþÈÞ)Ô+©e#­*$‹ÀTëd7*=@˜ghùЈbš5<\þÚžpå#‰ùnŒ°è³=-êkƒã`êù #w*.äjªöM÷ëZê'Spù³?_R;³neü‚‹N/ ؇Îx›Až‘Þ\ª™rYNqm(²ª3¨™EÆ<ιáU+¦‰ŠOãߎKÅ[¢`ª¤Evc\ÑÇÈ^©hœ­—‘‹¦·ûô–ÊS­Uàˆå¬†n&‹Xì;Qyv ‹uàªüp3ϯ¢5²ŒE¥²†íWË0`SŒ,&f‹6s!0¿×Ù¼…ÀhÙr +7D‡ºÙV\JÂm²_É>Éiyç »ÁÅ?¨)¥pÃÌ…”3CÏ;ø4àÝ=ż'Ûšy ‘m9.‚LÉX‹ÓDÇÞõ›ïc{…Q%îëÃŽêœ$d|íÙ’#0›C,b’¬À×ýö§—’Æu¨R¦oÛsR$BQ¬å`Ð PôªQ¿e‰ ‹¦Ò¸•1ßÒ4ˆÍ9™¦Æ=\kSRƒæ¸H:¹s7xââÿÜÃGÓ®üLnÖeT 3~=”;§­Ÿcü -Ãê½å~6c)‰çk«h3Ê48¤ ™o8¬aªk^³ »(4†»ß¡¢pÑ7——*Ò½ÝÏWŸœ<!ßÅ š»p̈Œ$©øÚ—“"P3Á­CO3Xæ™ä2o‚’´5C†6Pˆìð ªÆ ûû£å9‘UìçÉä)\¹ÏÉh=y»¾Ù‚ZÛ5s¨Á‹B éÔ@×R0^Fîb°žŸ2ç`Bƒu1¬à‡4ë`¡0ÿ!÷è£h+7XnÜüù†ÂŠ7{"ëiq5O~3J}ƒIž|?tSt°Ø&ËÕ%¤hì¥9IQޝü§ïS™ re¤ºg©ý7mªG–GÛ‚ïäúè~[GJWŽùÅ'›}@±ÕÉ\ž…fKy1Ø;—Œ¤xIY s`Ô´ëÂîö––5jù,ÄŠhA™§«p¸éÏnÝX²›ì‡‹ºÏôU¸6¦ú„ô£ÂÓè `û–N½™Ç¿Iœù’•ý€‹è,q“Œ»‰JîCC™Í­ú×òXIß[åöž,³–¤ì 8/#üØhkõÃ\ƒÇú™öÈÇ™ÃÕ_ÔªŽ3"]ÿ¿^^­Ä,g1ƒÏ^]èþiÜu®þyÈm(ªt_øÑ+öèä·z*a™¦ëÈ(eüÀI•]E˜wo‹g‹¬˜T'ÿEcëÈc0ISè$ÑÊS8é2¨á :k £–ÚñÓ;$°§y%¿­©»’€€µ1„¦7ïËÁ!`^µþ'Ãi®#uÒ¾EWÏB%êÇsþ8Á +nkŽ)Ò7NóäŒ÷#=³^BëØñ ]$±ìôðþ4¢N~ké*ôƘ3¶ ÒÀÖSnxÙš×ã?¦‡â.É^%ý[B¡%@]Êì@½ r3Ä{¦ûyÕÚ³N:vº<ã‡ù³š”RÀ„»‡ZS}f³°!©­Ï„ÙŒDòÉ2$_r´±¬}©®1bCVéðÅ¢f£9L ‹Âù•`6”‰–žK†”\V¨Ðeö죭èâ½F)Àÿ?fuðEˆ]–öõV!Ìé5nyÞ7'3«^ÄArëh~í¸'ÇCRé‚lO=y’]]Ñ6Š«Góiþ’€€ÉOm‹[Ö‘\¨Ø¹^Ö¤©ñFfaÚL¸âM“œ´Ñaâ ãó‘ÁØã¡Ü·VÃaE 3t¼‹Øw¸D˜-»ƒŽžs«©F›Ø³t&$lÍ ¾þÉŽuËn \îs±áæñÌÖÝzkúd‹Ë,ïø}ê±ïW_Y.Fqòg™âÎ Hƒj•âºvÿ\袕¼˜ˆñ¤>Šs§€…Ò®˜Ò¶ÆýµäµQJ¿¶aÏ‘1׺Fv\Äïmå„aÃvÇ£Ýlˆ\îþ±Ç“ÉÔÎÇÄ’€€Á¾±Ø$/ÊR™0ŸE¦¾‘7r:Áöˆß÷Ã_—ÔlT>q{Í.-\ô¢€£‰a.3>fX°©™}5úciaqéJµ/DÀ+ ÎNaÉÕ]Šýþ­æÆL—õÖ JdI;±rއ¨DœúÅeŸ€¹ÛX)*¾„¢i",o?MïÈ›±ò¤H= ®dpÙ´ëïPhXZµ/U·9ír0¬òTÈòÀ³XQ¬ã'_ìžìÍ“"ªþÈ7Ü™Ý $¢i2¦>'—5+Ñþ É@4{N¤aÚНšØ ï—Õu¨¼…ÿanüÅ’õÀØ`á ­Ø'6Ï´°^']þ·HJ¿œâ.EzEP¢çßòÆIïë|3KQhÒÌ ×†]œî>ûwŠ=²kNG^ŽbÏ&·oξÇ]7uuÉ '0d¹›‘€ï|v@‡ëJ`”êvé´“•Öš²¥å‰ÊÐfzi°íÂ6ýÌa^3)Óµýê\êˆK¾zhp-­E´ó“Ð0êf¿ºÞÚeTÕšYíf€µ ¬zûJ{b] ž¿+ÙÖ`ßšØÙy„眷QN£ÊøæÔñ<²ú÷Æjjg0i¥Ne‹SN‡X#ºô½ÄïÂÞáxÆó“Z[AÛ'>¤ZÈÁ÷ô±&Ÿ×/V{}¬e,Žü`ÿX÷—Ìzàï8$04Îrа0ñQñðr¬¢Ot}ÉBϳ“}|lÓ1JY`º%„´ÿ¯¬WxE¡‹p«4é¿x9—Ŧ)vŬtAM ®mNiQÐ ?ú;y²u¾]@’Éîš’€€Ìõ°Œu!@Éè$5è¨?é ôN¸`”\T¸Âí,:ò5™¸åqì"-GUŠÆ4±0õVP04$RòOØÔgPHÅ_ˆßvO~3Ÿ>O&q3&…å7“jupû d2Ä4«"«S’½õ2²#–fGP*Züÿ`Ä̾z<š±úrA\ÿ‘ÐÂú&º6‹öD¶G(‘$|šÙÙ=z=tøuÏœÜGíxûw?Äb[NEHŒ'Ÿz›>“%-›îYYï<¬~~ œ¯ØÛªZëÈ hîΙ¦6\R4‘¨t¼Šä~šs—;ŽôôI3MC@–ß«¨E³«Gk~e¢Ì”š'⡌-£;Ök°N¼ž©j Ð@ß“°Õ@9ó‰î„fh©o“ëO`²iB¶C1ÔBAëòªà(žN¯ñÿzõë4/Ù ç­ Žc·h •Íá!ç<Ð ŸØUŠ"žVsú ™Tð}|U´IOYàõ¡ŽgH/ù¢ ´Ì7£Ä8œ’“³%hí¢/TŸ”QíÀàêÐÃÓˆV¥…øè1ÒeoÈWÿòƒ•Û ÂÁÈS1YÀ³£ž×L¯ã²ºÃi†€ÿWu+Vvr7uú …ÛÿªDѶüAÚ¿(¿±L].rÕEå/·';— òDŠu¿RÀGv”†x&á8Ÿ=(ˆé÷"éŽÿ=’%ÜͳGHWç…i?²þòó 8 Ü‚”SbÍ…žó |®ÍÝnZœ #|¬À#€éÖ¥ ÓæÏ¬™E`kÊCžÀÕ°ÃÄF`£ÊL~`”â iŒhKGäïÔåñ“—í§ùÅ¿'>ËâUþgãÈ=”PëÛ­É¥þ¿mÇü…R¸é¶Lyèp£±ôK=dµâh¶êr¥z@>óhBÞîĦ6»A)}×Àƺ@FåŠ\XO§«ÜeñϨaÔ0_%KñÀù§®kv,ÏóbDÙ@޵Ï*5;kkˆ+“è pÒä‹!·©+!1ìæR×ÈDÓžåF•ù}ð¿„ÿšEæ:5¬[ý³Ç÷¸±`h‘¢dº‚ÜkDàšljvpÅŽ1ÿs˜âÜŠÒ Ú»É™zc½}Âý.^'³/H¨¿XçÅGJNÏÞl‹üϵ~2 ’€€Àþ9½øM­Ðužœ»ýëó ‘ "[él:ðC¡#×T^t¶¦2æN‘ß5S>ì[‹"ûÇÄ6.\ ¸%Ø6’_ЬG›îÏuHfÓ™F°i¨2u;¸8WúRî¼l)Ѹõ-o=‡+¸1p£G¨Œé˜´8ÙÌþëФ*3uÉXŸ“D)Ã…å—+ÔÜ¢‘D€ƒÌƒ€§$=Z羊mþ^pö+ »e|È…û•§`‡‹‡©½ïÏ›"AKévÊ©½ÈÀÇ;|¦?R€ÅÀ†ºwÞììÆa¦9¦[tä‡iŸƒ±}ã<±YHC³}”¡ômbÖ•5Š4_åƒÞåIUèOCQbg<Ðlë+b–QmlDaë7¨bæ¡(ˆð+¬<< :\|‘CÞ%¦ã+ ÓÉx5šAì|wAàa…äŽJñ$ˆ\~`‹D|pÐÆœÙÊY¨‰úø¤ÿ8Óä—TŒŒ!Ÿò ÙaìŠJ#AY„=4#ÿSµ9àsMÀZ{wÔRý»/fk"†iÀ>¹ÂS!½—¤.Ü1Ð~òã\¡…Óƒ@Òzó–Å$ô)‘oªÓã$m¸qü•&DpƒÎ=›ôÄ$ÇÂZi^¤"+w…ù廙å‹A‰>÷gŸ°Cê6…‰¾…aù,‰qS-Üýü´"†ÛîI¿¢#Æ{´‡:~3ÝÊàDòUW|I;”-äÇUëÕ$àçÜ!!_æɉÃÌ‹*ë­TÎVN£òæðîSÏòÊ=ÀÙÖ1Ó?اžÍ/6ý%üêY¤-"À»¾NàÊy#Âgøßünª@…ˆfÍ%÷{ þèVЬ«”Œ%,ø$ü}#Ô–j®ùà¦Pï·ÌU\ˆ¹ÜØ4­-3,ëSòùTÄ› M½Þ{YaƒüÎKë$yÓ?ä5— dÕ÷|rL¼=Ò h+oàÀp–¬ éïòrrâ$4pæ4K/lB†×[2gvk‹ˆÕcS!¬—O¡ ¿ô¯¶_«Áð.¾žÇØgàf>êµÓîÖ·ü® РøLï-UQ-Æ5X…a!ö€cbÞè³\:“®£~oz¿ïî#ú ¶H’FZ,l»JîÆõ1Q6Á|÷¿·%eSYžh· å%Û{¨Ñ*—6ÝÔ ŽºKæ ô(Æ@³½“Rkb2s¼¬ØØ3dxWQ÷[@Ôû{»!ǵI´U*¸±2‘„G/ÄEYv¸‘_b”4•7K@søvMK••±š – Ì#Ì}Zo¤‘_WmC dMβÜõÒs‡ÈçúÖvól¤)Kô¸f'dA’«Ã;GÈWÜþÈÃÄë§1爓§åUjËYoe)„ž°/åV²Ù± 2cs”#ˆ)¯ÚÜØ¯¶W¡ßÇœÇA L¢ÇÓßx€'ú>ÏMWâíÈç=kY™T…•?÷§–å'‰²nzbeb’=­ tR”1CÀÏο×÷‘’Xo”G™»æN©EÎÈMUÀˆ<ÛKR) Ãù’€Pߌ÷éøú8XWÆ ô8óÀLQfó½k—Œç?–†Ý+œ+½»YIÇôHð{¥‹,îO¥Þñì8«kðÞž¦DÇì·¥÷oè$‡ü¥Ï­pi¨dÞ ~à–/¿zÚucu]¬ž 1Óp¨‡?宦iˬrŠ&`qÔá"Y`œa Eb]"0,EooÓ¹zÁÖw®üÌáÞ˜Ä×ÅMÏá#,ü3姈bz^<»ècÈ^ʧà‡s#-åÕ#ÒÕc¥ÜÊkÁs·LÐ&(…IÙOHd^(«‡JŠ<é~_ºi‚ ™c/,+Æ£ÈF÷@$5ì0ËpëŒàÝBo†\ÖÚµèxúòp;PgŽâ®Ùu—‡Å#œ…dŒ‘†Î]%-9=!î9û¬ø(“FŒ¤5àwzÕQoèeÑ×àw@ è¡A¤ÁîK¹A+m`ð^gEY«~Œi4ãÅô ZØ¯Ž $C7K0…¶«¨Ý¶QØUâ¼¹-±?ùgÑŠ--È«Ä'–Eù+S”Ž$g'Ç{¯ÓÌãq–Û¾‰cöÊܚܾC <ŠSz'p.®Öƒüi~™#@ Ù@+t#û‘÷­4Xcm8ÒÈ5$ÊÃÜÒèÓNàQ§ïH¾å "Û%¼Áp Ž%¹mƒª“5Æp<™²'ŒH䔲xÿçúJž7]lª ÔEâvÙõGàp2èrè Á;’H^«ÿ-?­xwí!ÚØ¸u[Ÿ[-+ÞO‘Ÿð .íœed¢hßPžÒ*x -+:rÕ?zÞ¯_ÊòŸá”Ybûʽ7 ò{Èo©€9%~¤æf½™|&üÜæSo˜öÏЧQ‹óq)U”ó&¥t¹Ü¤™°:^þMíaó;Œ‚ r5+ì©d´6?E=Û+èJ´#sà“ Iôÿßk}Y ƒ¥'/ævMiZ¢qå1@Al!4,Ë×>ê? 8Cf=žáçÞš-[­s×pW Œa}J"ÔÔZÙß(€Â€e’€€º÷¨[𻵠2Š­{½)XMú±Ùˆ$R@öR_² öö\f‡Ù‚›'‰ý8T,ktŠ»sDnŸ-å#˜È¹c£ ÆÀÉM¦$–ôWuÿ²üÚ|¬¦ çÑ|“ϵœh‚}ó%dFÜhìžHãPio¼«ˆ‰ÐÃ*Å•?ŠÕ¹Àôš^4†)­¡0`°5Ôðwq©ã`x>ú$>tr^‘öVéúééJd6u€Š$ œddi:”sf'»5¯Â7».ˆàRÀ/Ltêoûd‹ßS‘ 1N'.,X-CHéºw% æT»º€þÛMT T¦g›Y!63þ[Ú>úé kÓÌz¶ÔÚ£šó?Rñ°RO¸]QZœÈÉäá±6\ƒ¸)mÖÀz‹u.’FIWù?‡1&*ÒïýH’€€Íl^Ådi:½¦à‡.Žúû]L¼9LÏl n0¢÷ÒG QhýQ•Ÿ7 ký‹ê5š“tl¥Âtr©®f+BÍš‹DÓ`!E»€JcCéF-Þrˆß‹]îÑ b‚æ^Cæ«rÝ’Ž+ëÜX¶àó5sÀ©R£–Åü”óãFé»õ§ç%ïPÔY¿/$†¥NU•NÔàð WYzdϯ²WÂgš»_€5Ùaå*?3¥°Ä¶¨êÄ¥¦\«•ZGzcßá8wgb߈0kZq2 ÿlÕß2å’³ü;@H¯Á¢¥ Þ—³uGf”ŸöT¯ÏYá–AºïU tø&§Hœô瀼"Yΰ&Mü´ Ín]»#úŸ-ÙSòì„:ìÎäâŸOþ»œRà""ΧŠdf"¨GÚhnÑ¢^€qÙæ¥ ÛÒ›r(r lÇÒ‡p²6rˆëêLòƒÏ=¨ö4³a3ùÂäÁ¯1F°°F/0˜ ú£ôe.®Æ'­4Ù÷êq9@Oms‡,Û—™¤{bGqYÛ÷,&]8×–øQ¢âðrØ®‘4>“æ'hOær“'ƒËŠ)L,ݤrE`yfÚBçóGNmë£w™p†oçB’‰?ÍÌS3ø9"›9%hÊåñRAÉX@uÒYÉwQõ¡[G‹(i·ÙÆN==˜Îcã;Žß¨^zõ¦k{gLÅò‡fui»ñUô°»÷üÌö~Yë­ðˆÖ@yÜošy‘Ãã^šô°ùËQ­1ä®ÒäTôÁ~D7©Ú:ÊhÍïvh¬&°R“Ùë!°>2@[Ê”Vð§~bh_ ·jÍšd晉×S^UJfi¦yóöµ6vþJr$à–ñ"ë1Ê2žÒÙÿLìþñè .’úØwu²2ˆ¹Ï:Þ¾B’‰“¿*5 ˜ œx8Ö »‡ñgˆÁÞö†C»²ŒÅ:,ô`ly(£L…ãµ?èÖ`üìpn›/ÐGÁ1unVj ÔCøDTž·2IµA:›ØÞ« H˜Oõ3E1ið¯ÿ«1.Y0m‚‰7cc<ª¥ÃZ«ãÍ ÔGÁ•È$ ®]{¿a‡‡M=vÚYÇ+_X‚ ‘¦2™J1D {ºì%뺃þg««¾ú7dioׇÐÝGùO݈‘2/BͪLÖ®æRÝ]’XVÅÈ=­ižk’Â([UêZu›¦×92p"@5Uy¡(u-$C~ï`gÉóÛ`VѪv¿˜ír[Ê\lV¿‘ Fgµ]XÚ—÷o)û‚š!ÎÛÔû|qè‘¡|œ˜…3,óôbã»Fu@¦9#…uä™ÊÿЬ4¹Z5O}V+òÉÑdæ«ù e:nd ý‡-VÍQÆÔç…ÏdÊœÅ~r®"Wx ¬\y[@^–퀼Õp_¼K:LˆÞw‚!Û-)Í/$íS‘ÿ±¢ºÂ uÒž?²Áž+@ñÚì2öD÷©¿ª|ûÏ †SU¶[)ô/m¢Í{ž¦N æ„•Tqéoî÷_¯~µàºA7<-5H „P†¡LÞÆƒµ›sCáZtÿΔêH¼GWîOå×þÅÆdŸä†möy51åa•”üþw5p­3*~žr7Õ0­ú¯bíM~ˆ#û¹}ÎÝ%ÇDÊÉ£Å|„y\ý%@`é®(eßi<ºAõÃ2°º7õÊ]çëoÝéå ¯""ÔLåÕrTÒ›N4cúïLÓRÛˆjRI+"ap!KPñq5Üí9Ì2ÀjsZ©—t8ì†0%ÓwÌv.¦&Öâ°€ñ¯6‚º@X¶³ç‘´àOfMñ=ú,D@ˆfýÞÔ¼KUzF?ª›¬.Æ¡ÙWä’[ìEÖ{N|x ¿sÖëŸÍeˆÌÑw«~2M“c×]„eÉñx¢yËeÞ•‰õ `L‹;×½ I1êÌÉ€…(Lj;@G?Û7ÛØ9g–`9lšQÉ1^%KÍˆÃØÑ3«Ï䜦6í/u2þ?ɶ8Ã_ž\¹)Ðx…. '|µ?0Ö¦2ÍzÅ*Û}ôwüÌ·Š€õ~d†!(·wFܳ÷-X2b$éI.€«XýÆ»))s½/ÛýÔ@&evæÔ¢‡ªDk*â ÁSôYrÅÆ­Z4)(~Äánpe¡Ç€8Ù©X'3kU¯…3<”²'4Eòã-Ϫí(ÁQµ›?$ ²½­ßzk°ç«Õ¤©E'®"Õå.¢ƒCËÊá¥å¡Ì9w<˜(S>ð.|«¢J›´” ·b%9&ºÈÆ™O`'ÐÙŠ»‘h÷dBû&ÔÈÖ§gÑŸEpKÙ̼TÜÂoÕêMse‘†‹òíWOXü8—Ê¢­2# º4d&ÆGް´~»R«'4•h1°å1胬ÉÝ Tcjªà‹8¸Ç]ÞbÅßœ4ýsS+ñnrTÆä æÕò o¶èÁà»Ò§D"ÖˆÕ7±uÖ8VýôHú/|óÜÍ<n=×(UÅŒ+L-S:=é¼jT{Ø(RHä¶Êîft.‘”í1rÞ¶•®ƒÃ¤Š•¡|)&EÇð’€€é ò+h’ô{/™byRg`›y4X¨óŒv­mfì¨ÌÆ:ðÀ¼}ÒÏÅJøµÇŒ+‰µfo áç’¬íN]'¢ ,ÚŽþˆ—‹þ›ÎA@9]íKQÄjlèú…ˆ‰ÙEðñõ DÆÙ{Aå ,§ÐÙJª€#ˆíyxKŽœ˜ØMdÎ!ý€;ÍZ]ôådrK»ÿÿÉIØÂmíÔI=:fi2ºJpLÚͺä|€Ê'Lþ5ÙòÉVÕ×å…^¿^&á^£‰hvR_Té \ ÜámÇ„øYëRûT&`±pS}±ÄeöÓÆ MÔ ÑÙƒ—ÖGýV- ÑJ„´õN[Ó‹zB—ßYXÙŒ“vä´}UN®àþY,ÅëOÊle©H,à$Ô‹Å=ÿ4 O»Œƒ‘´lúªpŸÔÛa‘é碔5äJD–x] 7««;/EƒGFdÂÅÐ$E„jdáËþ¶"7ǼÕq“"#^‰¥Üß@ÕM[H Š×‘޳1 i/§i.KësrFnwL‹3w]¥, ŸÃÁ*Жbf7dI}DpÓr´¦WmæÒâz}OXO{)/”8¡Fve3•uWg§ÔŠ~{¿7A5Šù–ÄðmoJÈ/ÐÈèß0;c,S íÞ–v˜š’*Ôå÷¦F7¾ËXy-·) F/Ûx§ÇrÔ`ÝQ¼WöÄíb«š¤W¹¼Ç6|onð‚tOñF2t 6¦‰X¾¼vµ$בßlƒûaW¸¦‰2¥À™½4Ý*YW•b Švild¥¹^¼¡kg‹ýõÏ@N)hú’‰Õ§ðýS¿l~ç²bŽ÷¤[ÿ¾Í69FœÈ‚¿¶ wŽ ×v¼5!`I–SL36àæc’—ÿ³«·ÔºXM*TΆùE6ö¶‘¬˜wÅS¥ãç¸ä?@?d-‹©3ÎËnûtéÉìÛ2Æü¨‰v¤«ºCêSG–oca`ª‰ñ»*ƒ¢×ϱ¯>ºO¢¢„‡ã³·1âIÖ•–»]gô6eõª–ÇѸÜ ”ŽGüë÷ŒnÂÐ}ðÔû+}mZ‡S˜y2ÂAq? 0ÖHÒ‚@…«é-ŸËc‰=¦ñHÚ?–‡ÈEÿëe§óVê?GÛG1T’€€Ñóo+G° ß¡ùÿ|ÆÍç“™Ä\ƒ¶qz–»äXõÎyÀS_/.‹2¨úkÒÒ@(S•åi¡Q¹ÖÏçs±È ¤ÂÏîô¸•§¹É‚+­ÞŽ ÁóÓ4W2–¢7[P¡qC]s´HêêkÉÖvÅ¥%¶ñpy”¾äÃ\*ÒÊšs¸€8y:й=ÁBjâ r\'µð%«Z#E g~Èð@Aq[;{?,²\Žbrn´†Çf¸puíW‹U]ÑîÅU{ø‡ŒRt%¯tN4 Ç'1l›*á\¨1•þâàÈqïçÜDYxžÈ®C…Åÿó­&©ÔÑ’'øìŒMªrˆÉæCD|pG/p` 8éIõг<ÍV¢3kЃè®Èú4 ›ûÁ‘KS.‹@è.9øˆTö™³‰Þp­Çx•wŽc¼³RÄuQEy®þëPiÑVnf!Æ&Ü”¡-Y–wØôЦtˆì¸¾v}ÚðÚEGX°u½V)Y÷åâÿðÀCHÚŽ€Íšw7½/akÀøâ¿o«)J3ûU"]8M®dÏ’¹±Ãa¢ƒ>ùgøÚeÇS«î±Y—$ÿ R’N Jà„îÝdÕ1|®6Íèb¶…‡2VÍây·ú2 4[ÆÕ*ØÝuVOi½ž'Oëõ.ÙG€´Q¸ jª9Mø"½"Ž% &ƒ4á ešÆxò«”|¨°Ñ’íö[=î9XGo3±öÈ…%zøÚ0ÉÝf³J½u™0ú·N<ðƒâ)ZqöíçIÌàcSÄR$t³FJ´8ÎD:¡»õÿ²^Ìà½ê]íFʱ°<"=£ˆžªß;šÙ$2þµÏÎöªþ ;"_6w¹ÀÐ<ÆÄÇÒs6ÃÝY÷†ú¼· 4Ñ# þ+x儤B6¢€|*íïÖ£=“ßk¨ÕÚÿp ý¼àJ#lYëE '§>s›ÌJWšƒ ¢}½•ßñ¢sCa œSW×ßûª5ÒÍmøFÿßyúȈ?Ö~fï_­=vÚ4xH%ã²þ,lYðQ1g’€€ÔÊ,LN>¹Ùr©ƒ…Yôüfø|WWlZa“Áƒò'¤’ôÆÁíM[%D(‡ ˦9“Äu›îTÓ³¶Ž§™GIÓiưGPãí“cWéiâefû0â™ø_ÿ›-4}ª¿QX©ñÏTö¼• ¤€r[êiÒÊ›eëg…_‘¢ÝµU’øbÚ O"ç?ÚãÃ’ÅkØqØÊÿ&¹ß£wµA„´Ý(m õüÅ8Õµ,ºÿwuÃP`e= šºiV€n‡‰·>$èZoÚ•TWÍÛûÖõŠÍü*ÝÉ0#%$œ¬oyIŽØS‚¥œ &!€[`M<ô4B1aÀ^P«ëÌ90¹qð×àˆ9îInÑz@)¯õm•ÏkË@«Úœ4=ý—ÕéÁö|(d—Øj!HÞŽ” 6.!>ŸŽ—ó†ID…:Êð|®9ŒÏíÓ¸·F*{Yï½E:›@N:…ÊØê½†C…?íU‘ïÿÕ±pé-LÔÞH}Ém»ý;y½ÅÈAÇ{ ^ $Æ›ë#xÖäèÃ: f6€ìþ¶˜^’0½q¢3­+3¶U‡Gß´±Ÿ~O:¨| º_T(•h :¿¶(Ïvˆß mer:p~^\ã[íßú·»îa;zþ5‡?mLüãE§@ê!òo2p?ŠP”ÂEûgÕ‚¢=J™îk#?Ð(Th÷éŸÔ­5TÁi©[SÌOò>2çÆ'd5`lä %]Óñ[þM`^àšg9~ó,ȤõØníDPÑ`j¡kBn#åHœý¡ =O±» ¨>Ö.ÿˆLŸB ìUIà²SK 2ϳŒ›¶îÿ4Y@;¾\ 1|o09'÷Hg¥T½` Ë'‘f÷¢|áG>'r…NçÌYãÔUȶogEä_£al7;Rœá£cšù{‘íÙ¸ ¦…6"DŒa‘¨&_YNR¯îØÍHõã¾c°gê´]Ñ“ýÖAM©ŽÓšÄò“L…×>ª2¸OîÃ£ÔØ¡³-#“÷ÎÀþAR*|JþÃ`“¡p /–SùFÿ8#Úxañ.a,8!kÝö ˜ø69ȃçn¨¡S38ÛÜh‘#ǯБhT.‘ÏÆï ¥F@d&Qçz)ù=¦»LUp EþÕE¼ %+@’€€º¨á‰‰ö¥Pe§¡J/1€4ÜÞÿü5Ä,-Œšl±ÿ6ÎùÌ|Ç—Ö{Ø!:tÀPz\ž‰ðŸYîáòÜ~€oÓ©óÆ%֠Ѓ:ø›5¼}xNÿx`„WCII%ÈFhg©šØ?Ö5ŠÐÙy¹ÙLL"Ý|ro9>=Þ«°@™aý´=,kãQ™¤}ò;¹Ù=• yƒËÎU3 |)´„²<ªÖ3fÚiZ§\6ö E3_©º»P²âs2}i¯*4¥%ŒY‚FÙḖŽþ “uÛ˜&/õ“-gáaLbu~jB·ˆŸrbÅEaW9`’µÿ“‰zU ±ÏÀ† EŸ¢ß~R¬(3õ”cDF§Ï|deéñ>ø¹‡‚„ÔÀÔxÈd\[^“V^¿F[çÑòGÝÏl3þ¡Ë•ÊÊ`WȘEßèíÿ­·ÿŠ -˜¨mèßÛùœèØêˆ“ü]°Ú¤;zMõg,>ŸÎl Ò¾ é.\wbÕ:û¿Q¿Ž.lç"8Ûþ,Â6õ¹ý2¦µýi÷…`”;¸«c%_VËošÕìHnù‹3ð6Öã§ÂìVþ†• »ßý²ÑD|‰|@{r•¸£Â¿ »¡õÝY~Œ4D;i$ÖU¡øu#o¿õ<Á@ïÈ9ÓÔ7@7MºœÓ¹q®;hA oy‘„Ï9ço‰~ˆ’ì¼_=•‘cä³xÙÜ©"ü'•Ó¸žÈ§n¨±C¿ÜÔsÉb5ºSÕYu0…Ü\m¨PlÙR.ª˜à æ)ÂC¼çü¤³ö ¬"øµ;´gÀR´­b=I|:´FU—ÞéÍ &.ÒAJaê¤cÛ!Ø”Üû®£ ×®¢Æè(äÃa\“ûr•Ýn[FlGÑœâljíǧg\Ti×”Îâm_† ©J£mŸs!è H8×ë^Šo¤l¦-@Ýù±Ÿ(Tž±Ñ‘³ö¸\&U‘ UE§9Ùœ§SýL&¶þrôIãñœ‚ŒAži‚eHjD|ZÖ¨Æï#µTtˆeΨa_Ò'–eÝáïò—nû·ÇVá³×ŠR®Š³; ö”…¶|òoäMû°wˆ›™¢SGÅóo™k·Ûðpá$zÌóâuïÕBb[âÛ*¾é2’€€“ŒÖ|ºüƒ’'Qß±yéÁÊŸÛ‘j(ð˜­[éb6œd;œ,Ÿt +ë96ÂÍúâÂ3L5Ÿòôà¦\Ì pŠ©ÂðýáÙæo<9Ù¬Ú“Ê‚>ÕŒ‰Òó÷ü÷Që¹0YBJG£áªäZ±!¨Õ.^ÿz¹Â¡ÞŽª33¢´¿Ÿ¦rzqÆÉ™’óN<‰fS5<„5¤Á³"R^ñÏHó㔥£'aëÔ2E†YT’˜„/Ì ÚÏéÁüLªKïXA¿B]v…Åâ„;M3·J¼ G™•A«;_'6õÛÿfÂT¨ï *J*Ú>t»ÕC{òÎ2©œJ2Ï`¤4éºë|QƒWN}43sÂp¶vQœ©„îò¨ýhô©c©T”'÷7™­„¨¯…µ®tGøÒªü¬Ö>RäëÄ Ma2¡‡ìeš&ri·^G&1 é–;ÁÃsh«uÒ‡´noCD’¿. ¾ð|<4¸ú__–FŠóaT\%ZMèXž;lPSoá²Øö¬ûK¦€‘ ‚ºᓨ'D•lºáúRÔßðÌ\'x—ÃŽƒeõ·V'×9·ñOC+zçAÀ"¦ÖQªž¾[Qr’ü ¶x`¤Ï E©>Aä¤ Y‚Ý €:ŸÄ.á–ueL•äp g{–¶{¼o²™ù8r,7½Qx•­dsÕ“ÝbÕ¢ÍÚ)x~Ò–×§ÆË•ì[â ¢1í;DÚ„ U—Áü1©4Ëßrá¥UÕíÅH+'ÚÜþ<[–H‚_Cé=r¬8¥Z[k‚ã‰T©ËŠ;–aM]ÀŠ'äôƒ6£ÁåØ×u@Ç_=)\ž2×@ R³Rh˜cN”ï¸P×]Ûä3ù—¦ð7ŠÑ’ĉö틃¡ÔbÍ¡hºó¬ÿêÅpê_„fÞ ÌÒsjvª}Y½:9ìσPkœ{Ñ55RÕcVs=ŠË Sј8¬¸3²Ûò»j¦KŽî×gð^Ef‹¾“nrKf²q~•A†,ÆŸÉÀ.*[ö=צèÓÈû3º`´—ÊÝ ï¤ØÔ?¯Õî€öÛª}h©*?4„Œ¼žC ƽ K«ÀM£Þ|XÌœò²l’€€¨>Êë2{ýK…ÂÐ+ËxJÎdÞp„6G“ªrY÷ ȵoÛš¼œ•ÃDI:ïü% ñeÓI£7i\˜°9vs_ßÚ.7@`¢ØÐ>ˆˆdFŠÇ®÷»à»tÇ¥­–ØÞKæÀm@Ë=”{œCj.¢ÍkÙ†pºHvŠ7 ’×™¬mPM0/L·&î ÝÍ•A»,4#EèB‚UØÄ+®º †ªÀD\uc9!Žÿò?½é‹¸s T†ÎÁ7ðY¼Tš†°AÝ^Ÿ*¤¡Î%C/  úíø1ü¢gÄ{2À€D°ÀŸd]½šš~ÐMgÖlT·-Í[vm#ÀûSc°•z¨ûÄâ:ã|+Í _áéSu”2`bØ30à ݘÄÌ’ýò Œ44e“G>ÕçM&ê %©AÿÊNªó«ò‹êU§‚‚“‡tBáåSšVËS ƒÞ49#…èÈŠj6ËζßíW²†¤ÎÁ’`Ù<#²Âbd²W~õÂü—&†4¢ªfR²¾“¶‡<çƒ_ß¶sàå[~øé2û‡™Ç ˆSç»p©[ÕF=Û$âã_˜,4Ô˳¿´½…tŠžvšži’7ס™5 ©vÁpŒ,Û¦¦ïSGìam`û±Ñ2." ¥ëSå&ýJQÍÛ`öÜU"”PAÑ™gÄp a³€…w´¯Šá€èí9ðˆö šÂƒ?¥®Ö“T›>„=‘30Ã|â-ÚÔ$:cc¼¶AÝ>à”UM7—÷Eû Š'³©ë ¶Y\}8ƨ>ÃòTÑp%É>n£œ0ƒ”ˆvt$¿Áç/Ûhò}GMRþØ6héðƒôMXj¥qåÄå!I 8e€¸R¡˜Tê0‚O(µJDh˜ß„dBÜÖ¹EÃ’Õ¾AÂ6_"³ Ècªeö]Êòídjö‚ ¯?¾A˜\ŽqW~þqT¿,¥™I‘“dPζ2fjìþý÷4œ+\=›˜Ão6üSÖ…ÛßsïH©:Ùo"&6yGþ¥h_€J‹‰,lqÂß7Ê­¾û#F‡m_ÖÉ«ÐÉ©O `w9â™Â€µcçT”E âjH4sæÄÝ–½wMV·KNXNvPé»ÏËø {2!pA#íu­ý¯6]åT({‹FÃL;«°˜T{˜øÎ6R‡P?U#£V¡lžÛ1ÕjLëCÌT€ ðÀKÑXa9Y[ÑŽÌÈÉÜ©S¯8JôŒo[ÄÉï€*`Á‹“”‘S¡Ÿòp… º„ÐÃÚ¥V¹—©ÙEkJ²zÚÑÎOZÓä­£Q1âËÚr=­w£ð ©}Í6T }îø°»3›šÔH¢?k äs äò>ø Æœ’}ãæIÀÎà¸"¨ž6FÁ¹þr&÷V›ôõ¯m‰Éc0©Y¤9Ù·tçÆ?ÖãpŒ S›d¥¯eÌ,âðãÉcYzr'·èk›Ÿ†M (§˜a¥K¦:Š.rÒŸ¨¢³Dk¾BÚ/Ä=Ä–ƒÕº!>ËËÍÍå½’;|§¤œ+PHO>PZuggï4Љ³Ù >áQ’Èp¶„ZèBsÞÌ8Fj›ü}!JSƒý‚ÉbK(ìoë`Ö,Ü}ȰÚÂŽ¶†¥ÑM“õeb`8˜|kU«ÀÅ­¬fÎ û/²09ÿ ÅP-ͬ— ÔÇ€ ‘ñ=˜ß%”s?=W—.¬*ù›×ÉÅÒËn¼ì",ÚÉì•CÔ Å÷¨P–» ç·ñ^b»$Éžd3+ÔÁ[„ù€G“ß'wÓ^æÁÇ÷¸³wÊ^Ø4|²¨:Ç—ã‘»Ðìà9¼±sŠþÍ¿±ì_µH|]$aM1³§™+E_x$Ȥ¨©NïeÂÖ½yTeè\ëPJwÎO:鸛¥Oê-–ÕÙñƒÀ¸›Vn( ®cþ^-dJœú „@Wu{uJAØgGéF‰èb’€€Ï°ôè^–}?…Û>§âÄ­ÊÎãQãïæ@o¶,…}·^,ôbë|½Êe“?´ƒd˜l}îŸ*ç–ÿªÈµ» ]¯'ÆXTëZËR!ø¾¹^ï×'C ˜%˜¼Àåüÿm{'5<Á/~Õ`ß»ãdæ&ƒ® ~(å[Üí¬GòP¤gX 0Fù 9?Ý×cŠ]uPkO¾QK\úŠwâ f”¼fx÷äñ\œ%MÂKGvŒ/¥fúÄLï⎠l@^^ÐFÞkÆõÍ1 ·xŠÊ™¤Ó»Ûä°L Þ«¶NÞÒÆjM¡ÌYÆwçSɹ÷HÈ<,þj¹IñÍ›p0+žÈël`ÿ³/R; °›VèÜ"©8¸´è´ºOØëÆ”–‹•¯U Ó§âæüØíŠÖ´ëo §6.cö(Êàú*=íTžÇÀµ“Ís m„¯> “ð’ô™ò‡MÔ…ÜÊû”­ìžñ¡õ¨Rs”"ÞuÝð.JZâF‘qQ¸ ܤ¦«í˜ô®1 æÞŽ8´›¼Ì nñÔÙtNÄ”ùàu–;ë•…Î6ãG¦aÖÃi¥@Z¶¸ ¥43?[%,º5ëÔKÑ Ô©ëROàyÛ­¤’ »Ÿö ÄâÛ|¤•ås¼Ôsñ‰”ò¢Ó·ù²3Ã"dN£D<’°†‚ÿzhÍzü’#x©|ŠüÓql¡gP¥VyseÁ©h—ë÷CloŸÆÆ«w—qó>-3âfFsŨ¯<Ö,-ð½´wÚÍ„a»çc­]^í/Ûê‡`å(åe †Ìd‡dZsÍ"`'ýrÅ·ÔïF ‹T¦ø Â-FÖÍâ.õzEÈ#'–ÊS°¡ù¹ãâQ0Ö8ueÜ.ï¤9üMcíœÒ¥QäeÃ@àÆQž°Ä¥W"RÁêrQs°Ñm2mˆT¦»–„0\W1Êï˜ÂÎ°ÕæâZo-÷;;Ûš%RZWÂ1»¤|<î[bõ)¨¦=š&:¦—’l^])¶ÚÃÙe¡‰«—Ûãþ­op±›hÌ>—Ú”Çf-(`,lׄbÛĦ&‡&D &a ¯CÉÿ…©ˆ˜\ßý]·âäËfßWø8Œ¸Îï­dü…t[Ⱥ¨íÀ¥¤:ø†4@ÁpÓÍ Áô@ÜI‚Ø ÂRO)c³áu‚Û¥}ø­ÐE>8gZ5;ÞèÔ! æ³ág“­«Á@Ü-0(í5‚¨ŽlZÒþ9èUºŒ$Y¾üåpTpX/€’›9X¸Í•ÔÙ*ÑfÔƒ/±2f4r<(Ê”²R•h„ŸE§ÑïemÀ„|¸ªàlžÒÐèœSŒIVôñEþ¥5;ºÂ=È>µœÒ©eè’€€ØÜø–ÍGÜÀ{0¬.d^€Ï­nöé“Ã`jʆîyÀ'åP<{ÓðÀK;.pnÚ˪˜â(·hÚc&ìA r$0õ ¥RÇpAë|—ÍŸ. ²ôŠ÷\ƒØmrµ›òàÜšÑJùf8{€%óã¶Æ!Cð” D/DÄ’ dª*(DYLn!…Ë'=”jc%2oe,îì:ˆ\.åZCk83 ¤Pyã‹”*H3ýþv1Ý•`Üo;Üð…=йxšwÏË NKã†IdïjXmö,¾kÓš)oC¬5Æ:NœÞ¨ú²|ûôN0Ìq±v4b +á}$Ž ÌL¹)ÏœÆk¾pÉÀg îy6_QÑ–Ùá&󠫉ƒA)ÚEljW„(Ö7¸Œ¥ ,/ñÆ!ÛyH©X( ‹E=œ=&® 5ŽÆ”4%†³‹?ˆmÍzŽUWý¯ R1 Ÿ$TÁFnóD ]ã=À ÑA<œüúò¸UÆ«…aM™ôFBÿô]Z‰2£f}qˆ¶eÁ˜§˜¼k §ûŸ7¥é7iäŽùh°ò^ €RtÃ[øà üA±ü ø#)ë—–21>>góaýιYߢúÕÊzl‚€KÅïV(õaÍÛUsîæ%D±ƒ]wlzZʦô]BðÖ!:¯³§Hi>;Â÷ünEˆwÓ–*¯†›¡.-Ù+4ñh^ îÕHr¡¼˜ä¿#eáýD°`¶Íˆ¥ÚÎ#MBÉœRëîžü°«ÕQÿ|B"tªÝ©ÿB†øý̘ééˆ\J_dÄB Cå+7!sêÖ=GÁÒáo×å°æ„näw=ª"*³qôIU¥ô)ƶ9»¬—6"1cjÍWp­0ò³â)Ç\¨è 㤌d@ ÌñÑ‚)`žôVÒ¬LJŒ˜ˆ¿[QHbô³6i»³£ëef2&‹” •¥o‹Èt{>r?²1[^ä)ÛÙÒØÄÑÐŽ=Þ¹¿Fœ‚5ö Ÿni˜Œpœ 1/n··ï1QÆ~ƒ^-1ØT Ïó®xwÒnæÔ^e\BÏ<t†¢Ñø¤j}j˜ |èy¼Ðš!ñiÂé3gú¤QR WA=ô+Í3LO©Ç!kzÞL“”c׈¨L2 ñWo’€€£}Pci©ƒp‡Ý9 Be§Bì´zŠªÁðý}x}”³“û²îPʘÙ#ÏáûàôD­^p±ŸPQyòàfÔj¬NMûý1¶ƒ”4[ M¨nqÑÆÞRç«Æ²n½ÌSRç÷ÑŸ7ËšØÝüÆÂd6µ³ zé$§”WB;A‹Â×Þ€T®($4iìåBæ‡;ç㓼ä„pÆ“'/4¸3ꊿ'õºY‰ -Êî5@„H]ñ?Ž_Ö¬©IPhã˜iK…ó¿–{VœÞm‚óÄ¿üYöú‘Û$Î ?>G²Ù'5ÑÑ7½j öÞ]1~†¤ñýâC°oÃrÐç¶Di/M¹’?(zƒ"—ˆ'À啉KBäÿ¼1¬éæ}³í¨;$'©Ã>Ér´ÈãÚェ2¨±L5šS4"ÆY—ªÂçi7w¢„pk H\çì r'2H¯§t­˜ô $lǼ^þé1¶.^[¹‹u¿A[¯Ë¤Ð{‡Ùð7[Ô©" æ¶¹tRòõéHª§]4Uƒ«fÊŸ^¢h‚µ™öðzÊ¿@fÛ &šüG5´ï°F%é­D&x:8‡Ù¿”Ìí¿|1¸ª¤£a,38 !¸¤R}ŽcD'HÙÛÛI¤~…çÎáè‚›‡î}é`Ý„°=ðÅ Ó|Ô ·‡Ì|Ô…Õ¿E€ÊÚÍ;‘£ØÝÛ¸î—VŽ8 /ž|äU#e0æÝÊa@†MpømÄWqz¶viW±”¨yìúKtH·å4þ¦·üã:":ìG`ö*“m.[Š—÷ËE·×4OÉ(Ãym,u ¾Dè÷sÞgÏcÅæLBTH„^‰ïêêÞÝfç¡éw'¡Æ'›É¥€pŸ¨\¢×>†@tFÓõw#³ÃÌy:qVË0«Üî—À+´v㘖ÓD¦ª@—êÎÅ{çw|‰Þ²±qv‡>¯ïñ u!!y8;#àš¿“nÏãe2rÖȬS6Ómßž†,9°¡qv4üÀÚ™7þ}W€¤2F¯¡&GbQ…¨ò¤{nïÎaê?Ì|p ®ß–ºøBÅ.³ÞJlFžïƶѨSv…•±†úËq¦wÂ:R4— Ö®­¿¥¸lÙ<Ë…ùž]އm­‰#PÁ"¼Â„pÅ{8]ñ*’€€½g¦Ñ®l^Ï@Dû’úø4Œ¨—™×ÈIPBw2hkf–Ÿíì°Èl¸¬ñ4Ö‘ƒìûþsND<I9 âÇÇv½^z—€Gz]Ù*yú'+WÆ'ëcµSéÜNzÚô·Çã†áS6î4sxÛ²X뎖(8Û%¥ô?)#Ûݪ¡ú’N=ÈÀz…êW¯~–ü¯•7Êíá¦Æ"o‘uñ{:GvÒ ádÿˆ³½36†kŠ›HŸØmjcéã- ð¡9E+øFñÑ7DZε؜yá(< `ÙGzA~ˆ\1þ™MZ²N3çA1OÖΚ¸™‚Y #8zi]÷:$íç¾Û8X¬òsœ…ü<ØBèíAMøOgæ^È# \P&k*d$½õÇØUÈ÷<ûî´zP‰[¼#æÔ«»z€ÇÈã2ssM¹Qˆþâ²ÏñøÐ¶5a@b.HyR²Z¶PAAIΖÈ_–OKÉA fˆ‰è× µc5ÉÍÂî¬6]îæ`•ʾ,Ùï OS+#ãÀþ}l~3O¨cÁt˜U &ëiÂ4ÿ9¦ ç䥕)ãØC†ruUø‰Ô·ùQ²0û›@YVQßÊwÃÍù£È˜xÆ×F:–S 2ÚˆSr2A×pÞV³©]‹ô­L—âÈŽ¼d5LYRLÏ%O£œ´Ç€Wg@û넺¿Fõà´ RÅ~‰=?Ô$ÖÜOß £à˜Öõ+Ͷl9&êš<˜gÖÊзòò3œYºNm‘ßø m·ªMü9En½ˆA<³³¾Ú ll4³AS¦ÑÈâÇÈ_õòGçÆ+Š™¸Ò?I…Y—a|u6žcI?nrCß¿QÈÆü¬XÒ6l°g÷á¡çðˆájѳ>9œþVî¸RjÖô¿w±2>Ìñ—8GâÖ3ïêXиo@êžÃµ1¥- ª•o(~N¸>Ô;<¤¡]štsf`‰þü{¬e×èpž³¡/3"/„iPö!ô-#úrÀüø Ì™ffqˆQûHN†"Sq6åGï³9銀QÛÜÞKMG¼*óU N8µ>[‰Ç …+GRA|5oÑî²È)6^üäÖü/ ¥5=¨œ;gªn™¯ã´Ìn6ÂÝí& šÉ¥’€€Û\§ÝUòÃMËn\¿éÒ¾íœFÒ‰êtì¤ÙNæNFp™^Ñ|*F{Š‹îíâ©FëÈbÄSNvÒêå$­êé á\&ÐYrœºžË“\îMZwÏ4µÅLçö=rû·>ô<+Q¿Yfclu<¥‘X9X®â¼×Wb¢½ (0¤?\žTHûóOÝ`áh¯½YÊdƧõáÐA,Ôî[¥RAîÄ€ž1úÙáa™²°é;¡Wq±=jÈѧ™*ÅŠÔ$©Wø:°‡±ÿûQ>í£÷9‚ûyn×ÃÖs„üYxº3bH¬}úΊÁ³ G 'Yò!,ϰ¼'øP¼“Óä=Ç“ßØOk!dÈýw[žèåÑ\Þ!Šg¯Ä-È.|÷^‹X*Ôô¯[þ™§›zA+Ò3w5”ñÅ Udó/a^Z6//­`1Ì‚Ä2~u4å/o¤ÄRÝfW~b[¯@³šõ™)†W(‘—Óɦ9…:ƒX[Í`ü s æî_¸ÇL´z®þìÇ¬Ùæº–ã3c¨›Æã?¼}È$§ Ûv<Åp˜A g*É¥›s`âQqo䥠úWŠ-I'” x:!6€â ¢=LŠÓ,×Ãd*‹^iô­WŽ&8†•@M í bÚb–Ú5þ›õZƒ]•†Ð£Xæ Ê ~µê.l¿’¬üáÖ }ÑF.#$C·™ºËñBÅcY÷ÈëYæHP*vȬÇzäøåÇzkePR|nxJ3ïši%2CÁGü’Û«Ö±Ú’RYúIT7øˆnƒ†~\ôÓ/÷éÞÄFx‹ƒRRX²i3ëäájÁ¹U|€{‹Ð£ã-Kõ;ÅL뀫Ûe€¾;Ø\!­‘ŸWI½f¯Eû„i˜)ƒ ®æ½º=»UDm%IøgÊçX*‹ÇuE4͹ùŠeP wÉ4ŽÈQáÂÛh”·•!å4;¢VCü©Þ½;1ÀtÌûnëÕÃÉþ6¬œ1ήÆK#E`Þ0k¼®¤”©ÞYÊÀ ¯›/3èòÄœ¨ŽŸ ˆœcuZ%œÿzÜ&Õ­0˜ðÿ\µv½â¼§ái(¾©î0Ti5ÖbŸ*±ÏÍÚ£ˆØûQ¢‰#Áè,/%…C¨¢Ãp4™©ó73{]¯-*دgeà,mÁ:’€€á½oòæÚ!àp`›$½ì¬nh«<¸]ä+k©òÅ &ROð”¬ÉùF}zaèÊi¡ítZ¶ÿ¤Qaš«3ˆ„±mµ¾û„pÇIÁDø8Ÿx‡€‡P$)Þ LªFŸ¼*±Ï¤¨T[€”nàì+Ϙ±èý†ŒéO?cìR[å?!vé™+³Ä¨-z3 ¨Oûý˜— ̪¼à]bà[ÀÒ”XÜrx è,ÿ¥KKµ¸ÁÞŠÿ ¬~’Ì÷Ùìc¨ãö8ÅæôuQ]â÷—ÄûXÉßÝš£‰uV4­ÿT›òuÂÛ§£Ïú?[:E¯xvGÒq…}›(½ÅN¡¿@´½YuŽÓŽ¨È…$ÈÐqhÕœFµBýŽ™”¡ÈàL„UíoØ–üy(EF.ø”{ù-ëÔ^ï(äeö&•E#*j8ËB轸?¨ÏPM÷YD6ADñ›ü O¢÷·¯ÛKƒÚÛ à Îqá-”)?¢fLµ~þ¯.-°ýƒÕ®žG>lSÏÏäÎe<Ú²5ìÎ¥Ù&¬èžidêÝÞrXæ¦r„u¿u‹’~/8jjàE˜†-ŸãUù½Éü®þÎýO¹7ØeË1¥Äç?õ»O÷v¸4m>hèâFãš\ÄBSçr‰n (®!¼ÝáóR¢4Ú£M÷·ÆˆÉ#õ& ;ù£rkQ»J.Læ÷þÍœàÁ“(=a:@;A?3ó:оÃ>Úy‡Âêœ÷ét‹…yõdy)šÇÂoÄ´¯L¬•Âoøƒê;må~gBÚ' éíR»–HûîQ÷ÈW£ËÄb<´ÉŽ™p“y–„‘…šdedˆ9ÎÑ]ô5ùÍwðdoW‚pPoÌ:€9—¦*J¨„¨«>º"a[t-*Æb¼˜½`kírÖ¬eûÒbê]xd\3õ#yÜzŒ%6»n¾ k­ùÂ{ñL}§ÛÓYÚÆÜ5,IÓ9Øòm«­hsv<)ú•—¯P¡%&éú’€€Îµ Œ žhS_Z¬ü[B*Ø/mûçáHú×N? *–Ôï`º4ƒž%E·èÇ¿•Ii†àxësÍJw~œÚ4 Âm?îq.5HœÕšáë—›ùh†õŒþvØXy¶ÓrG¤!õƈú¾OYSÛSEêŠ^FÂ×ø!®.-&©";9ÐÐE‘qñB7ߌ;“}çð¾/‰ÛSýlõ)¼7JE ³kÓí©iýòú9¬k Üjå9Ä|b0ýN«³‹ÎCÂe ¯yʦ¢%ÚçJgx2 @©FÛ¢h[–v)?PÔ¨hg¹Xe°Ÿ†toþñM=óMÇ™oÌ™Q&4bâ™/´¦Ñ_ó%­A…m§­Ÿ7mÇP])#æ¤Nµüôr‰ørŒ29žL#|4Û1÷1nAºÜt·FÓ¨ÿŽ@ XåîÙå4mφéÝŒò&æ>,HÔgLýöVÃ’×®¡úïØ'Šiô·ÆZÌFCûÕ¶qÔŒ A=ã™9³ä*«6—ï¶û‚’SpË»ÁbÒ FšÎ®{/VPyý»ÈŒàq'Ù!j`ɘ¿Å´€,Ú ä¶‘ÏâŸf-‚#4é|ÝøÒ|»ˆéej 颟¦®ù¸1BÈOŸ^H‰žSV«þܘ‰, 2ÿS†}€>&l¯©=aÛïâJSêô\òá ó%š¿ûº-Ú¼Ãk)%¶ÄGdH*n(ôQ—íº!&Æ«¦?/å¸Q5N|œ!x‘N¡¤ :AÔÀƶ‘øE÷A>ÿ ƒÏ]"Ú±44Õ£ì×é.dá[öøúÃÃMï Ccª·k¡ €"i~;{ø÷ܘ%¯'—=Ä8”DBÐ{ÊOžUè1¬Ûû£àEÂoªÓ"«"Ô"6"=³euO¤X®_eGžewcæŠ[ÇfëËÇËè\Á ;—‹Dn`2ÏlÆY÷Í ‚^’¦}³ïtÞ!Áâ-ô;”jí‡9 rÅj÷76éé€jgMµ°Ôçê÷Sxg€·ª™=u‚€Óö¿Z0ÖÉm½`#’BV®o“RŠÙbÀ¹RcãJ»Ž~Ø»\4`p¦ß6ð3OwŸ²ð®ÕÕ~2V ýÚ!¼ŽóêÄ2­.à «×²®E9 ƒˆëêr†w@Þµx†ºI~À‹MÎ_ÿÑyÓµ ®°—Û­_’€€Ì Û7öŸÆD¿ú¶?X6iYSœ›-£•I9™ÅQäÒà÷XVMF×þtŠÐTšçs¸¨"ú?©˜¬¾iªùb¢È­Õ’WP¾ŒÞ>%.iã›Vh^æovØ}e+úÁ1(Ô|•Ýì·Ê0oOTòÙMêó áz°NQÛÄo)(I#Éâ™R£Â"¶¨ÖDª;l¬¹²á mh8Ø) Gñ—ª†ÑÅâß›ëï*ÙIã5óÈÖA²ŽÜbö¬µ¯j©ïÄøu‹ù'“WÃt•÷š›“U×Õ¾‰•U¾¿Ø=q®ïl4¢n½y,§ýÐþ{QòîaÖØ(jU\@½˜à·A¾MVãÞf3„;*S±•+<º³‡‹ÔýæÿH –.ž¤—›ÑyHT‚Ñ*ÀDƒ©ºì&š{g\½ã¯0Wãô@Ï=øìÄGëŸ.€‘§^× Q=zŒO¨‡JñZ&—°lt„šê©#£ oüÔáË(†^$p¼Tº à“{G÷p¤r°Í‡žÀb5k„À­ºb álþyðá1"¬¾‰ÆõØSÜ6w&–ôW5Ô°ùcÝJC™V i+\óB ecü‰ûìÁ ”,‰-àì0kïàf|8øÆqý°×«u ô˜ŠÁë`¸Fð °Ö;«‘Jr^oé! åqfµ#Þý{DŒ¶z%`î n¶a8Û½ê(ìY¢{Égƒ{1{RØàÞce9gÊŸ¬å!HÉUÁ\ÊŒQ; 6k‰¤}WJ~ šH›¡ÁÔi¥öÙ^ÍËùÖ:ˆÀ'ÐnÉ­Y›QãˆÉAÝí³ $î² p7ß/^*¬¬W.P¤â$l2¶ð ¶ñ&á\Ç ß^“~¦tÏÜÖ‘ûÉ5ÐÏ FØ“šGÕm#ç½ÂoÓõrŠVµu’—¯c]ÃPŠnôFÔ½š€µ©† TùG)+'ÃF|2çüoý.„E1]~ ÙvKæ'ŒWC~;%dxÁyn^Í5o±wrI+/ÕÈÍ€‚yìIœ ¬@8Mæ[aéS„Ûi‰t©Fø09fUlZ #÷âAwT|Z%rËÐ@$Ô/0Ç“‡ÆÈ”±K®¹,ƒ‰§-âÛe¼¡°î¦øõcû‚Óh`®IáÆÔ’€€åv|?¬G&Äâ˜":Æøçw·M/Á°@&厖 ¹íIè“tgQ‡uo¦JJl{S/©Ñ5ˆa’”NÚ³¶¦-úÝI…‰ËU´3oÙkÔ‘ñíô„j£Á—ÆWÍÔ0ahôëæ°Ž‹æòùŸ“¾ËNy.Í0¯çÛ~‡Z½Ô¦îÐÇ:Zܬ”¸öSZ'}Ê=‚5ƒ¿ÎY+ˆñ©ñEêsvOF±¢Ý4M‹Ü}ÎZ¾M˜©$ƽæ–ú̹î¹3ÆvŠUWEmrùWü&³¼T¬J”·7d’Óܵéžä ë¼4Ư2çß1žFNZëJUûKr)Ù+2JúÐfå+±˜Nµ9N«—ÖÈ;qe`0]oîäCD±"’`ÕQ?š¹¦_1{›€Y}wÃɽhÌÍŠ_<ÎQ~SDåt¸•uOD¶Ó²ãS×ÑàIâx’€” ’C¼©ïò~ Ö…"ÕgÆ !™™Ë`ã–„â<Ü3õrË ¯Oõ©EV~ýpC<Ýq½ÅgE(L›Özz;8O>AáYð]^gO‘ëd’%ÁËKŒ4 ¢8æ²Hç¤Ñ1ͲµLÀˆo&01¥Ê燶ܚ8De»,D‰HÚu{mÈ7%¡Êì•bºyEõðBÅÇá“% ±‘[°Uúº&¬EµÚnð ÜçœB½ßK‹!@ Äá?CÎxl[ålwbi;R”ÁPðq=c¿ÀµFR¼Æ5žÖ¶B‚Ît,]l`gùfXŽ 4‰'0ÖÝÄ•úƒÁ‘åÖOÒ4”»äkå ­¸ï“mo5DXÏìÑĤvY¬Œ^·f}ÝêIÚPOù÷%òfœ\Âì˜Tb}]ç{ËXêw‰eYÆ¤Ž l$ôùă@N—wyÁog]3œ£ ÿ©“^Ü* ŒâËϸÒánõ.LAþŸóÚŸ”™hòù¹327'‚p–!2¥Nÿ($ÎXF¡bzž1•C¡b·…‹Ö(¥e…Jy]X:©‘x´ÎQÓ£r²<ª5A–Íè’>9ßÌ‹ J3!ÖDguë³1æÌùâàŽæÚÐÙ‰«Éƺ—S+pÑ.¯JIÛ¡÷ßüDMº&ûä01± \àÙ;;Jv‘Ј@QØ@Õ©›>CèÅýð chõš2Ž’€€ÌÑ9Œ…C½cTZ+©ªgˆ ñÍ83èXùç|ß!q_ö‘PW¯„£ÍªôtËÿ„ )O ó»ÄãP>˜¸âÆíBiêg>jÚúÇXñN­Ÿ·§É Žg>M UL¹U÷9ï†gŒ–+Æì›)2·n'¦is×.|®£öR#Íœâ¸ëú(•D=õœP»r6>_‰Ùæ-1ÙE´îïe¢­<0£´nÆp¤Îkê§Oj’š‰àã/]ì>”òÊþÝÜRwÜÛ^Ûd¿œŒÅË‘¯5ÊêàxC—BWùÊØܼy C‡Ä¥ï„ÒU‡±{l®sèÅfÅûk(aøõ#•^|fÚål…÷Î}`¬|££¬¹«t¬U#w”$gLON>§î¹k/HYðâã‡kÇ÷„Ç¥‘ûß¶¤ÅOXðíèü±D¹JaìW zUÕ¼øF嘉{õÿÐê»î8½.¿—î8ép]û=¾aĆÒq«¯Uƒt#x|±…ú3œj5«dTmOÒ”ÊÂR2Êf¤P–4PHdßÉ…­ë„/6 âÁÌCü×C±8ÍÊø|Í!Ûpaž˜ß¸U[Q“¹}U-ú„+Nï@‘ý–å÷—}7k¼SÅÊš4 5põìò¬µÌøë²À×(QâþÛ¹Ì>ߪUÕÿqdðÕÝ„w£•ê@y‚lñ¼4 ç…h&#Ý>òº”~N‰,É+ ŠÁp€ÒRœ¤1o] …vÑ%r²ëȾ$¬æÌ×ð:‰´¯6ö7ûÚ Ö½Æo~ØšƒC@+/‹ÀÂΟ~LBG\=Dqg!Ðsö—¬u‹ÓË `Õ[--ÛË2­˜Irw¹£þÊß¶ë‰Úžk Bc‚·d2 ”‰Ïd#Ä»ÂÙè|üê§Xlg°åÍ zîH?t¨þ·¨®Ñú j•â¾ó£óÒì@Õ¹é’\-#Ø‘\€xÿù-uÎ4Q/” q@Ìë§E{æ-6¼€1˜5 ÚZ.ôô04‡·Æ²À”µ½6jÛ„"2h^½ õÈ?K `x3´þ¦÷bŽ9î”us{x$Ù“ê5ÿ6êc£Û@Ò’ŒÜ&cÜlu(Ìö‰isB"Ô‹êê{ÖÒ P‚)isÊ?Á<“Ò¯³lO|æmÀ¼óVD71ùU¤ÐËTl³^~$E×py„]'ZR†Ù/ûnò>Dpu÷ Æ_âEUhQ<øåîpÁ¥Â¸=IvG+À}T†.jº'1­/˸g”¸¸ºkÃ~j¬,m¤Qe}\øy?¸­öÕ  *ÌäK©é$³âUÑü$)r/ìÿ*, nuVCHÅK—ÜqW 2P쀌ÍJÁpÃÆä£Ïß›XÛCoX=JlŽyJŸ#(É£‰²â›x‡m9§°Mjê4¬¥X+zwwcëa°½÷Ô#`¿gµjzmÏu0š?²Y$_Ø5!ï:òƒ8ä5½`?wa-\|ŒêoÐü Bµ4§»Sۃ͟†‹t/2šê挄¤e®¾ô›Hka‰Ä]Çzù:ŠCäw!ìšæàETE™F èP—;èAR[sXn&•Y>ÿaHX 2ySU:ãu: ¿{œÜòÜ%w'¯ü®½$€9NUj´™531[kâàµX$»Iù}#3ÿŸ[Pê×Ðc¾¼í)qÃ]1XðE=•"JHB‡Þχ]~ð³ŒÔ}ßæ 6Ú3Y!¡8Üö»Œ7ƒÉÚüÑÑûÉ•ŠaÊÕžŽ"ËL¡„™Ëã¹ü(ÿ¤€î¬¹îÙ.û“v•…lèm·C¹¡c\èJO“yÒ¼êcë-’€€°‘t®Šê_3"U å}À+虂JÙ[ ¯ fs?frʶP÷mŠ>0r,ö],ÁfBCnÁû&!…<ÃÔtùx0;5ÌŒùƒr¬›w$ô •áÉè5uE× ÎðNïÃx{‰Ú5nÊê\…áqØŒið‡&(ÿ1\·ë}^É’jçFØvÒƒù7fë‹Z…:»×µúzÞ­»þd_¬Y>AÕéÚ‡0¯ïŸ¨pÏØÕWz+Ö„EBehÇ‘ØÝV“6™¶.©ø‰ã‚íû}>7Œ¿Î­<6Ô³é3S²­1—=ä_'YÑ×½÷}Ï Ÿ­-ú;öñâˆì±½.mÀ€ðþΊK¸žgIˆJä0ÕæÌjæëøíå°mÍÆZ£Ç¸»žÌä\âMÎZM¹ªµœ×…Ýæ Üðn=×==°¯k£h±Àѯd[ãTâ¡`|Î̪¨QUX/dÑL¬FŽv«5C¿”‹¢4C[2¤càìÅpKS3dÜ5 R­S…ã(Øn #ñ.Dx*ov0=q°h)  ²îKE×î–¹Oj’€€Ó†yNVð'ÉiÎu§òéühÝFɈª1 ­Ò½E¨¡A½qÁÓ|o'ó¦owrýÊ’·‚££8¶ÍGƒ*ÒJ µR Å*ËJ nV•ý HÁG¹o¿@½\è·>ŸW±õ èÍîQÄäìøï½‡k{vÔCsàßT2®!´¡xCh¹4Ì­.¹«¡­š‡íg‹ÿÎ3»e-±]•RƒÊ…|¡÷öÏe£vpg&§ÆŽu†~ 'y=¿}$¶¦’“íc‚·zûH—ö²‰FG\£L×”Šh‚2‹ŸÒY/wâG[Fk8‚cr¨€ø,¹;*k:ãÚèÍb_J}l%›Rú}ŠØk³ˆá (‹ÒMâÑÆZ8-¥b܆.ÊæirÛ9é§§$žõ¸‰lh㑚õ*xÕ¬9?ˆ‘¿*:ccâ=©‡¡ÐÂþFÃGì8NX`þ¹=!ÐãÌ;JMxŸhà·IbGžÜ¡ ô¨v#;/ZbÒ"*‡ !4îl[qØèµ”èÍ–Cp#¿×".Yf˜ê(»&¸hÅâÑ+1‘‡oÐü½ÔˆÓéáˆÅŠ*çûSìËÍ•^9ŸãÊFàž.~_ˆ‰vàÑ g! ñáØvá¦ÄHÈÉœ^샌Y¾—l›A4çáɨk†Rò1Ün±û–G´ÖV»Ùœvy9¼zºXÈHþÙ,‹4ß¹À‘FAZ¸j#<àk©1„›]Û¤Ð>ñ€øe¤Å[Ðü{]äËÂÉÿ"|]§À´ØvÜ;.äU•rÓß“ìI?ãáÞoö ÐŠåº?¼! ^Í—0ÙÊ‹Î'Üq×A=ñFü+¼ãWá­ Ù’i^YöN@y)åšü¥¼©SÉ?»pâÁä\s>»Ÿ1"xð®#΂ܤ$y±ÜLÔÚMU?ÆðG øl|¦qÁDꎄ‚J'o{ *øŸŽy¾37æÆ1ßÏê7›»s«ü&ÎRsôKz¹Û”KQ´÷®£O½Ä‰— ´ä\Å™áôQˆ²6i÷€’€€ºVîßËós{tÑTžƒ„¢ÔɳT@WoÿS¿â%Vg“+Y&fȳ‰Ô<’¶¡3“"ƒØ¹Ъlu† jQfa»%LI¶×„žÑ¸Z›³«í“ÿy¼Q85F~‘'zj jG·f6öòql4Þâ¾ühÍ#Å’óÉærD÷%3Hc¦,‰®j\Ú™•¼:KëÎS"_µé¼±ªy…wáûð¡ìcÞ¬ûЫ#·Ã`Š!fz\€? R9Mm€ìJõåuHÃg#Pv´ä>RFÑ]n÷³b¬&´ÀûÎf±ˆd¼dks‡Ãk{è­>­’<âÂøÜ[/z”X‘Fm Wë<.qì„‚]€îv-Òø_ÄŒP F¥Á>0ÒÁõΤ®cÑÝñ±ßVìËèHvÍ6ÍÙgÂX víDkAÕÖ\‰¾!Ý ,#‹FnÀk0y‚R%èlÌya§hdLð„»º]ŠG}i1”€eœ¦ÝÇ3OIÄà*Kk »e©èè1ví_Î¹Æ çÍ_é’ù”N–hºÜÛ ´lc¶ï:*õ=4[‘3žñ±4ØûÖðчõ¤ñŸŒë‹‚{ñ&™Qÿ&$äo0ŒêQ£ÝŒÝdŒ{7å2Ò{]Ñéü´á?ÛjøíÕM$´?\¶÷]ÒóDùïXZ}÷´ò€ip“v„ãû"ý'à~-ìÒñFåµIžk'F.ÿMtó©ÉC ‰ è‘°²·§ùR§Ì†¬¥'ª9ѱãƒâ‹ÓPÏË754ÌBUÚä”×½+‹`qÇå›#’'™¼žÀ,¹·#i.g‹Ë„£fÐÌï[x®hòÇNY_"DÈjq·¡ ›cÁn™G”Mé±k¿+æ§-z&‡Ã ãgÙv?A#¿3=q¾E³,D ¬‹ñ>Œ»LÓ1öåáÈ'é²KqÞÉ7ã^4SWù-ªÊ„YVÛpÞQ8K,G$½ kJO‚s‘YÂ¥¤ü s&”O6'7ýì¡xdß¾D €Þ›þMšar19ö´‘g”ž÷sû¤ªôE~Ã¥›*ò«Ít¾×ËÛ¦Šƒ©ˆ7Õ›-b¡lzæup@÷VlJ]âÿÓ/¦NWFT>YHOw×’ÿ«Þ¶}2€dÀ@bBéP@>¼ßð¾“é]Ÿ™q’€€è\“ÿ¯å%CfsfÄJ ëþ^[Ù%©O B‚;Ñå‹;çp¨> À–ú/EVY^0 _íÁp’ŠqþM/5ùF$­ ‘L„fô:Þ˜Wœ”$ÔO"@¸þÇ®š†e6Z—Ñ-7TóCù•Õ[€ wÁº®¼‹a¢t¦Ñ⽕daءʆ‚˜´/Õöbz€ðæ{Å2ö?w[«¦›?½–†g;Þ§ãÊù‡ˆõx´ää÷ˆÖ×{mŠA´Æu’g±PŒw5n¥ò˜-'ÔP¶.µ<º¾³Ý|˜Rƒ¯âÈ^y©tY¨ÿëYuH 0µ¥.ÁZ€|ê@\ùÉk›i‰Ž@Éy(+¤Æc7N&Ð]ÑT»ýŒ*,|}«X$¥aÕgcµvV^–Û£ç§j82|’Ë»ªpâÊù߸æªXë/Ø @GŒÔ¹–$0î9ŸžþV—•yàs5imeTu}ë4[æ+RÁ< ËÎÞ ¹ Ãßf®M_½œã3®x£U“Ë$d5µ£ço<4™…-t‚T$v¿õ~æ%çpT.¯{³“•ß}UÀFuÒˆN¾ œóÑÕÚ R |yÀô‰C0 »B/`·sØ>|Ä@ nS=hî—6²t»3…$b‰üMzø7†Ùy5ÿm®ê$j)·ÀAé\-ÁÌ $gC‹¯.)ŒŽ è–—³gž½ü?cò”p±šz]VH–kž.þ“#¥@»¡ûPî‹«E„uèõ‰ƒšœ;è!V‚olÕ…ô¨qS6yÚ#º´F…,„Å…_²º»…ÉëÄIÜÇAš,’ÁÜ¥UЮ¢ )\çø˜Š,¯B¿Ï;ÉìÈ ’Ž_Sÿe'ì~pßœa´’QÔ3 ­$ß´E×óÜ«$ÚkäÔÜfCÿ_*|¨@ÔÄPtûutWE9“‰ú0£É\^¹M†Àžö.â±m³IÜŠ ºé @y½ß “ý½1¼Â47ÎP£h¶í;ZP¦/ó0åö”·*ùOõXµZ Ëôã7È8ˆ%ލ1¿GÚ¶œäLød™õ®d=ÂE’o6A”ã-ŒTžAØ Ó£ïÍ¡u,¢9ñ‡ “º Ú1‘g&Ä*Œ,dzåõÔK–[)Õ’€€Ùñ"bÓ*­´,þ”Ù šÛ9¡ã}GY³¶Lg(XWØì5h¥obíV¬n¦`y5»è%í¶#(f=øD¢É޶†¼DÕ!Ïð‰ˆ¢ß0²b «o§:#ΰ'ø·½¹}aIQ©Tõ ;>¯x¬âH)Í Ÿòu¢b L+Zoþ\«í`ÕÉ~5²HãyI!kæ±âOÊçˆ2ÀBY$ó!$~ûUŒSäÓ»ûG;…K ¼à!+/»g¬êOÀšÄSŒ!~ýô¹øý?ZGt9ÆxEý Xbu_‹^ a‰GE~î{¨5V}¥Nß“%9D*›?0Ënõ½)™ëb‡ß›£ØÃö‡e/ÐË*ÝkS‘°ß𔡗R$‰=Ú†¿»p½H¢¸?0moKp!ºÊTÇXÚ¹—Xqwµbj `¾”’š3ð×iUÄšg¹!nB¹ì®|±ù‡x&á£Q*ºyG·Þ:Üs\£™in´³v1Öh7n}$C’…ÀîMŒÒ7’µPw„i%1t—«ÔNÙö¾Î³¬Dq™³¾“¦S÷•°¤F¼µtÑgî0<#mƒøë‰bê4´`é÷tnÜå¢9í7Ä.‚Y»rúË~SÉû!µÎ÷é£M’ƧNõ†MmG£³ÝíàË,Ù])¿éN2,ÄÑÅ¢\JO5ëPßeÆÅŒYÑ_"GËc{ïžv,²Œ ”SnMCŠ9DÊÈß’íZíA¶¥Â¬Q·ý`•j¦8wè ™ûW®Hv†Â:ÈÕí DÇ~Ä‹Þ2Ȇ w*s«ž‰ôŠÖeby°ùKìô´FuÍb›ê‹ˆü·Ðܶ ZI9 ]&Æ4À¢‘vÔ3 „¾Îjbé:PìΊ’Š™{¹- Ï£Š!˜ƒçBÔWþæA@úP1(†¸„iC¥•XN\¡þî+j¯Ã 5JÀþµ„÷˜§¾ ïµöfáßU®­i²]Àÿbë\B‡ˆ©šó%‡ê$'yÛÉ]„¦@EeyÃÍÁíJÌ~ ‘ÅKP¯UWÒ ôtº÷ê¦ÚwB^4åE–»èxu>)Î1ÙrÍ G?†¹^Aƒ¥’Ђü­ò-¾ëãWÀ‚²Ëi‰á!šÙœéHš]˜ØS#­ÉPÌxµ<’-’€€Ä¦7èaîÁµk tú»Ä‚¢¸b¥¾|_{Û> Qøcù–Þe„FÓŒÜĺ*èâ>™›¼ÆŽÄ1KìnÈx¿ôâ‚n–(” >¬ô[ \¡P€/ k¼ Þ!™­D@2H´ñ€= gì—Çi÷wa-)à #Guº¹ ŒÉdCwA –’Ùmpä+·öµ'#–oGÛÌYÎÐÙ–iõQô—Þº•ÃÞ£}¯½:Dù*$|÷^¾~}jFâ3Ƈ)ók~SÙRž^[ÐßXÀ5y\æ®ß÷zøÈ}âŽ{æ2Ð¥jäá û3,~TQ‡îrý·–øÓ?h<lÁ\§uº—Åf#ZÝÀ \m³"wî‡õÒäÀ|aéA­žáq¨Îð34ð“Èè.ª"å­x?^šÉ„WÆ' ðÂ5+š©nýrÀÆÕäõ,xU¯uåâ®lgãÉí‰|ïÁ90Õ×¢MÏʑ޵ÊS8K@ŸÌpîdÜøçª ÜšT­©v)ðȤÙÎ:µ “¯(|9wj3—Ê¢*{Òi×P4BвêB£[+~ ´` Iq´¡” €Q™dU…Ün÷äÊ&;D®ùþÑÊPÔTaõ7ŸÙT md&>ü_Žº$2×â—U¡X@ÆÓEBĹ÷ffd¯ñäuÂߥçŠ:ò¹¥`ªúwf¨‰µ ^aÙBŽôŒ%'Œ"Y)ùaiUË‘Ù>cžÐÑxÌ?Úà§Ö,•m#Óð/®jÚhÞf:#Ç·Q©xá͸ ß-Ä_ÏŒLH?8/L+B¬©÷!Ð1eËXò?LèqÙ¡4EMUDRþˆzYß'ÜZÈžÀ„_^^(bhL§SЩš}H±ƒÒßV¦<¦kù߆%‘|dä)žÎArY2GÕPÎTø’O½Å}¶8Ä$ÕïoE —çÐ77é–JGØ0ÖÛ'®Ï¤ BjB‡fu¤ÈºÍa=Ó“‰NÇDz¯P^ô¬Ð/Ú+[ƒt©Y7›W§€å øýïNÞ¹Éy—RbðSÄü/jß2в½vjº1Ë0N.MZ©&hÊ]ÈÓ¾b ¶×ž)DGýž…ª1½ÞÛ}™r1A0ÿT°-¤ZON•»Üª¨afÒð‰mÓ9/avgü£¤D.Õµ7N¹Ôıy¿Ó‘’€€ÁÌu`ÜdöÁ ±}×€¯LÐ`þz˜WíqØåneP'¥Òn้ˆ€±¡P]G?®`kþ½fÅýDÕèÛE…öwÇAâf9€þßÙç `1‹¾ïý7#•u¿â£y” I­áƒ,~óœ.}ÓhÙV ¼uëìÃNƒˆ"q>ª ÎáûL1f¹ Ÿ\†m°/)£×âãT_’¢‹aU÷¯[CðÛ/“¾Þ9Ó¶¸yÔü:dHŠ ­{Úœp÷ó©ýøša½˜xh½TðÏØÛ7€òÌÄZ+/'‚&})¿’*§ú»¶þÀèJ…ǘ ,hÙGµ`”Ÿ=9 ñ7W¦Nä‹RSZ2”&h®V;HzUÃ}¢³x(´¦ÜrC[zèhýfO=Ø7ì[f®öDç™ N%¸›)eq|ax YyÕd@Þ6µÇÖfi]½¨±ÚÊ|Bo~ÍJǹ}D5Uè 3{.º<½Ùžñw‰È÷<´€kì/}Œ‹9½óC¤—î7ü܃ô&pƒÈÊT)+D»€¢ë㊸©^®S@NO « ìkÿOöÙ«˜LâB¤MHéC!¨ G´×Ü¡ßTVFû*‘o‰ƒÈdÊ…­¢«”™›u~_·ŒÄî†\7úœq9.,8T´V2®™[úît6Y¸ ú4|;T¬RÝnö°¯ºËÅXjêÝÜzVýY_*ÏBõ>•ÝO­ÿŸg™3CA ÌŸ§,š.“–àõ çB<—’>Bt§“m§vÅï =ˆûr ¨;Á%¿b£"(ÇR_§ËX˜l§Î~Õƒ¦Šý…ÛWË·ë(]IQ$ç<櫟ì2J.MOжÊ÷„o^À¾î¦k¶3CƒäÛ£á^UN.šñMM"]l¼kH´ªgšÁ* GA½NÙ¿ ëyI¨'yØ‹¢Ö…Ñe»’€€¾ÎžÌ‘F3žáïLþY³b— ÿ&¨f“$GSÜ|ÊiÐúᣕ',øÏ3©í±´š'· Üý%åc˜Òé xš,§r±1|8ïæ/÷7×Z£ãxM LÝ! fÔ—Óæ‚ÅõÆgÚÖïtŠ÷˜WÚb;ñh=— ¶­ˆçU2´±×ÊY¥aMÄ|ã#w(þ¸ßTZWm«ˆçÚVL\3¬=ó@©²½ý<Ÿo ™Y&ã€é+·“w‡ð¾ ç7’ÿ¤Nºð»–s;4»°ƒsd’¦ §ýý´`Wœ§òÉ[·ˆì‘#SH®”f¼„cÑä¿ÿPÏvËYÞiýOAW9ŠÞ£üœÉ(¦YÎXh) ðn ŠX™.ïÔ/ÕÑŠ’¿ú)Ç­žŽéPR¦\ÈÝåóŸ´ÍÞ¦ -w%6Äêš¼«év¤‚Ú$¢1E„>²ú÷“Î(}Ê‘E¨?Q q »Vž˜¸m f(|½f þ²kœ®+冟xEÁâYÛîªÇÿY1 m}ç—{££˜ãË,s’UÒ“j {Ê%Þ׊¢R^æù ­åçq·¯ûnº—jmº• [ÊH}ºtŸ{’fí镨dzÅ«ãüDÞA|ÍèûbVIdW‰ Õ4²ñ ‘ò—ݸ¶Ú)æp¡XÿôéB¶¸E¿É' ½øèw0œnïÒ/Å zßY®’ºyä‚b+­øÉÈ|Þ£‹Eˆ¢ O5†ø‘3Ÿcf¯¨ðµ•àÒÇ©Î5šó¡ÍFnî˜Æ€‹›øžC‰Šî§—Fô%y Ã,•S{廉ÛûW‰Óøœ…!"…;ÀUyòD†'¢˜”®o¯x¥3òº5»Ðž½^EýоÈ27÷f0Ï’>^ÖŸ@Ÿáxœ‡< œïXPÕá\?ŸÜøLò¦›‚V1»‚W¦'û!©9]d7 mó¬-öRÕ̦ÙGªb 鹋 .&Vp±?(%¹ßŠI¯O¦;Ðùñ¢ýl &r3nÁÊ‹2u¶s}>áÀî¬ÓYêè/GÓøÙ^B³Tî€ÏŽ)×l±›ÌTR 8Ú+“79iì3xçv[Eç2,yA{.ÎÅÖ°Ä×´z äÊœè¬4]‡z­6ØJÂô”ÿöƒb»Â× ’€€Ç$ˆ‡.‚rëf•Póu9û®Œ—öϹÕs=ô.@ÏáºÞ¾î0jfíbúìPÕZRDÔô-¶±Túð ƒhG׵ȹ2á1\ ©]ÔC˜~ô“؈µT+)åýÂÄØ»§ xe…fÓ2ô¬f±¸|~™{¢¯6gQ¶}{<`Z1NS†ÄGÕË@–: 8d\ÿ!QóïèôßJ]j~Þ6ªö¯;K2pÍñ»ÍYœŸ´QŒ%ñþû9 ËZÙ`f(+z~ñÀÀ!È©a'Lj»”²''.;¢ÃVªÓÙyDØ ÂÖäaæp¬kOwÑyÌÆ#“µŽ E½䡸$B‰צ€ƒjË–äxÇÝ5у†üË 5“¡¡­rJº¼'M~¸[Íûº"¿sjmfõ wßÿæ02üøœ 4¡GIÒ@ýo0“ ˜c|a•{×ÿ¢y³ÓcäÕŒÆéûàiÖð«3Ú ;ˆøüz«×Á^Tx⊫T?µŸŠÝðÿ¤r,®*~\ˆG·FÁÂrÌt ¦¤§~ˆÚÄ_ËGë;ugbâPÝIz}õÓ÷öE”Sb|wÀòÝÓ“­è›¼×Ÿ·‘–2°CH7Vä=ÁAˆ ûãêúÁø‹ƒmQ©F[ü­A÷¨2aþF þáIÌ ñðÉ”šy{Ù¼¶ª6µRÀ!™B¨ ,m3B½ô›‚ܘà¾~ó® ÇœvÌN¦ò¸Žv§Å²PK^îë“aoN“H}îSk( K9Q¯â2 îÂèÛ4Æ·'Ø‚;¸n¸8UîVó2~ÏÆ¦ËÆœ¸ÑAV€,?È‹÷_/×P+ž€Ê’é(¯lþ¨Éc¾ÞøÔ -®;«À*”˜ÂPˆÍ~¨ÆgðsØŠO´izÚÊ©à ¦wB¯!Y.ìGò–‰Õ7Ž@íÊœ®©hr38h†B`{ųÛ áµð³UˆÜà”`HûAMú*}ä ·ÃILÅÃmºÌ€¾ÚÏX·.¬œB7l«€Û\ ?Ñ[–mGže*,°+ ¢…ˆã!º†4b´YT"㟢´ì9^äëjMçaÀJ¨¥À˜þX¯ó‹W7Ä{©R3—ú=W+‘µÃ'~û¥á@D€sÿ'Çæp6ã7©z»@b’€€±9•)ƒèë6œ›C÷z­‘3òa÷.-þ‰Ã¯þŒ{û;ìzÜr„‘¸ŒØ6*^–Þyb£®_ñ¥0A½„Àõröò¢Që"rž¦?Ýe;r$á]×r ´“ø6Ùl9!à¦!m²vhâáÍy+ÿ§O?ï-D’øÁÃë¡Ï9'AI þŠöÖèú£{bã[A²¿BžzÚaü Kl:åäóP eZ"‘^ÒžðÚ¢zl…œÁ‘?g].¿èwu!:ŽSÕY Ã¯öˆI°¯Q›šz¯( ?ln L"¡^jn!Ø ¢µ¤w†ªqƒ³g¶h$É*w‹ö¬\­®ö.‹õ#¬îÀM#¿­Íó¦—!“^½ÿ­Z—žú×áe*;¯¸ ‘œi˜öð’:Fâ+"×ÿg:`(Dä7ŒcŸc¦“4 ÖS4*Œ¸) °­¯L2ˆï¾ý¸PÀÃ_ôÉu`Étc€êv©UÌ0„ëól¿Ö5>ü4žoPÏÌ÷{<ú§˜‡žy(áuŠø>iGñæt+ ¸z6x¾0·6^Rm”!MÂÇÖj–¾0Õès‹t¿,Ýs2 1ë Sê…+$²2§~ÞËßvÿIû].ƒÿN`A[U½ô2æ"5HWQ$iìðt+~¸wtæ»Ë…öGú"1ÃøÂ_ ÈÇÂ-fpÇ=÷›Þ¦OeüiÙSÛÀ ¾‚}¸‚{û‰ìÖZ ê€å¾[ü¬½î7fÄ˽ø9*ÃRO‚Ö€ø4†ÇÑÁ[ß‘âýùÜíׯ‹*y㩦‹ó3$úžŠ@M@4ÝÖG‚/ÿ!@‡Ä€ ¦J²ñ`ÐòYQ×qžÂW)½ ¯Ö¨vÀÏ#émÃk8"®’Œ^îǤ¿¹ÇýÆ€œ±lêTÕ]…R:ç,vÿ6¾ö¾ƒÅÖ˜± lÒæ4±9dµ+,›:ö½/‹íÐÇ+äĶð{Ëú8yŠSp¦Ä‚e±zå*s@jð}Y‘nwÃ`+¯%™Ãt!ˆ†{c¤îÊ1€¥oå`óì2O.i€Þ_K «Ç’ü.kޱd‘¶©Z¸Ž<-Šuôûñ X¦r.ʪºRD‰@F•Ì'%¾@E$‹äBÏQiOíÝÞz˜ÓÖÈZ×ao DÖ飑…¶ ©¬ö¾©¥ðYç3–;’€€É-|`ñâ)ñª»ØÃß÷ì–¡¬P@ðÿ 7k+_^^Ò€æŽ=”/Ê@f‹hÉøêPƒ3:*Ê)HÔ Ý­iÅgžÆSÊC\+VtžA>ͳ|]{¶ÿÊ›ÿ.ßf„%j›©MtPOLš‰íðL-Z¯^=ÿê'$µî)}e„îÊã«vR†§>¶µ¸ s´Ã6Ã`éh‹Í'?úWÙ½É~JnŽþ òÓ—ûM÷Ëj"Lò;§ngóTÑöÍ\}ÿÛd!°›>´V?‹c£=ÉÏä­ãK–ÿ–ð™hŸÖmÇ$þWΩ}µ-„ûP‹ÍýùæxbˆyºÕHί –ݨe_€Åð’AúeCK:ÿvµ°³Ž:Æ» T푎@ASö2ŠœÛMÒ"Ì¥Ùs΄ ˜2xÒeV£(ðÔDž½ ¿7hA6ȢĔf?d†ä ÜŽw/”d›P•lU÷áýoz÷ÓùÕkmJ¦ÆŽdé7["ž“ÄÞ Ì?¿»úù—÷ئ21þʲlSøZY3íu q¢ãv΄\~¶‘hð$è§ÿêÑ+ǡ²<ûþävˆ4k¥ª!N³ûoŠÝ2DQ£3Á¶¢£xê1D+ÐPTyF žKî(ä iôp ÙïÍõ_O1L6 ¾ óöu~7rnÆÚ˜‘½*‹™ÕÞŽÀÜn‚MÄ–zÄ¡ä,†Ò0gÒ0Byе͖Â÷\¤",¾þ/¬ 0š2Þ²Y> [£;d¿w·Î¬zŠ|>œ×'ÿ ¯ÜS¥‚üXkÈþÅñ²5*hH”ƒmS±ÃE¢)' -9çq–gZ7ú+|Ô“{Õ—€0|0\#ƶB·¸¥ùPô^ðãËÚP¥QTr]Y/?p”H+™mè*aJ2.íº[þê{C ¿ÿOÎÐß‚yî ËkÃ볚®ê|ñü>%™ ¹@-øÛ¦†½—·í¶Ezvܘ†½»º”lQU Ò§rA†…jQÅ߃@¦l³ôäúvŸ'ÂÑÝÈ%ï*^Z±Äª–Gºrº†\ÓíDÒHQkH6ѽ)h=fNŽòI0É…2,ÆŒàÃõ¬ªÉ+åD–„,©˜8[¦Þ³‘‚ÔÉL5-f´M(‘g½¶|·­. ÆG¶xª›áMÉ-´ÈÒÊ5a3r˜ØšNëHŒßãÉíy¡ˆ*È9:CŸ*¾ßý­Z˪Mƒ8ðø9¶JÕUÎÐŒîƒwâÅ»ØòÞ t4 Äʹå(û~<¬vUZ']vÆ* Ð%˜¸v„€FÞ¡1ÊóȈÌëÚÂöM7çÛoH es蔄jÒÛB±fS”žÊm.%”냡eãd€#óq"·äûBZ0¼ÑªËÓYªJ¨g]ß©½3˜yšï‘¯P&ì…²ÂU‡!rUwzÉÂÙt Ú„˜QǬä!1\Ú¤__ú‘Îtº[ ñ²í:ðºä/BÚbQ=ʼa;'D¹9Àž MÜû©JwÀ³êçÏÖ·S3Tµ”gæZö qÿËÓz äŽ$%õ ¶71Ê6¦»æ›»ËjmÜö±Û]lc ØoäGYýT½)ßzz¦fçG<þh!gìvŠÀyg.üÄ®OÈ®ûocÁ<€…º?4b¿……mO0Ô0é¥&W'„u¾<ëÔ·B} Ë#Ç\á+<;M’€€Æ£¶~+¦!jµm¶vbŒ/óžËvçþB…‹Ë¥nuò³ÅvÈš\í,þ®²•mÖŸ`éÔýÝL¸ÎEñúi)^&®á@y…”}‰ÖÚå#¹œ²f¢YFzaê@NK B5B§o±jH®—?gG“6·¹¢³ÓÇççWH‡nê6Ñ‚ö§@ÇP˜Í­¢/<¯!"¾$ˆ ’•gÓVv Õ“º,ûx¬¦ i܆æ"[gÑ7ÓMJ”W|†µÌ¢µÐåd¼ÍÚ(ؼ›‹.PJb"·¾ÕYL6D¦Ý5·ÜôÛ*¡ÖoÛ{¦Z¬§a„HjÁÔ!‰Ÿ5-d9P¦S 4LºT¥­ØWÀd¨¡ú~§»Ê¢¯*DÖ:ªË.aHr`ô³H;?=›uGX<è£ÀûÚÄIyãØÊl¬ñÈ·³CÝ® æ$¤O0Açüßó»Ã ۑ妀È’€€å»á…‰…!(Faɼxç¤uËž !·,†.D™²äÍêâÓÃj…š1) éñ?ƾ52±j2úim°}ÖÑXÊu´Ë_ÇÈû9¤?­ôxM š–,l˜Ä'”õ$æWh8Õâ-YÇâzÁžEPÐ4”Â=—ä-O!åJ1?P:(›ëo%ôJ­ÒNHÚO/CÓöw ‚ÂÇ_Së‚/´ßñJ(ënïs׉Ò¦¼ókqÕ¼rãTÜ&‘:W R’Ç} 3o¨ÓjÓ©x]D`›–AY]kÉØÒR”³’[ËfŸíócT´qLÿ/ŸN%‘©~HÚÿø†ÍÅêž¹¤ÏŒ©³Í²æîúÿ W°/µÆª`Í1HR—Ô·$z )µónX®Ýç.õq^i®²‘Iþ© @ܢœónïŸ+¥¿ý SèÕ-h?‹FóSôB”rÀƒ†Ä-,´[ØRÅ–c À"ù‚ö+%-•Ñ( /=Ù'æõCñ—ª@Û&Å\þ¶Ô$üXw[÷P_RBl tQ³æ´GDã?Ž¢äè‚|cš¦eQ»~cÑ‘ùè·‘ÔѾ’IHýhŸ1'¸|€Ú£»¹ü¸s›™‘íŽ2ö“Œþ9Ì=Èú£ÂÍ+Ú—K¥#“™ÖU+¬BôÀK×9ÅÓý†®ÏESȹã# ö“©¨•oÙ“ÈR† 3`ÏAP<ÑìùË´Û”ËÌžŽF=Zú aU¯¢í´²8':Ÿ¶€£·w]§Þ a!–ÉÄÉ ±_J€M´ª¸¸'¿ótšËúêÖϪy>Jxß8±G}mD‡´þ)<Ü@Õ'çùìŽE›z7÷MB\¿Û%¨ƒÿè ÔbyÛ3Þ 3 -‘ï}bÏáèRmkœn;Ìyc›”xG¤n+Òƒ|ýŨ¦§…ƒŒ·ì¾ºfóP\5 ë –C­ÁÀ„O¤…aœ,ï|Ck¸%ÞŒ&Ô/UÓ]Q3àâË…€&×JÒ§$é%}¬ª†§_CÔˆ§€%³¶«g­6G<ø’ZÞxãd­óTÅŸ·–xâµx§WSž€²²[uXDS8bÏäð?ôJ2L'^ÆÀ{¨¿¢à¥¼Òva–«µÈ ®¹ÀÚŽXÞo^„Iôû#†™»Ÿ&H_’€€ò`êR7¬àA7B=µgiÆ»p·sÑô?W½üz ЀÏ5» ò1æEƒÄ>Æêa¼æÑ#{*ð7•úÂמÏR‚uX¼2åè„K aÖþ2$lÇ*”(‡þ+”þÄmõ ›Æ®¯²¹qf~“W†D²ŒµÒ¥oÒr¼W²1&•ÑG+j[NÄc¯ùG‚HÚd½piø£70ñ:c©…NZ¢‚Hç£Õ>zèÒ©Œ®âoâºî½™\ñŸ(]ÒUoQ*Ÿ0Ñ“LFE ”‹ˆïXSÑ2ª†&?€ÒçÍ·ó=<Å.nÐÆÛwÀ‘%œ0u}´‚)$»Úí¤ œ³î1È4yÚLÄòáAA-ìÍðÚ ¹à3*î$¥J“ÝáhbŽÏøËΈ´ŸH5÷û.匰X‘X½l/˜ê þ¬ÿh¦!Þ6‘z%§†Wе8ÆÇ~Ãc˜2ï:˜žÍƒ P›(¦JT™`¨ÑTN@ŽW·ßèA!‘z¢Ëd±&ÚwæÄpÆŽó)6YòÊPá:9œ qóÓ³7OÛ&?Ròͳ:ü§ù ÕâëÝâE’Òo@ƒ³1–¼™Îd¿–-uͶ :¿£zu&n%Bé r`ÜëÐ,ᮘmÌìx ~É:ùþOÁ¼"ÈÈæÁS–nƒ RÔ„|íRSZ/lõL×~ØÉ_6Z^)èô.Ä>S‹æe0£¦ëEëI øµ·ï*dÛ­JM´dô°ÄßüÓ\úrw©R¦Š‚&¼õЧÙT€–Öã” ¾ŸwúÏ´Hóæ<÷ïk±Jè&ÖhÀå»ì¡aÚ"ÜáUÜíõÜUï2Ù¶*%‹¨Úk>°Ü¿søJÙ8;uÔ[Œ_9WàW3Ë~Î:ù@³Nýð É4¬/§bÔc ëWÐé.ÿín£›2Ç›¤ G¾`;õöt¥J’çcL*û·ˆ×à³ „Â@øÿ¾1ýɸ’€€äràÍ»U´øÖ»iâ¡ÉÍL.ºÐ<Œ íÁo{ŦՅ4Ø­õEPK–èÏ鯷ßVêí½H/ܤrp z$Ç[1è—nônwh:Š íî±X&LÞ{ÆVe×ÌCÌ0°t•ô]páÜñ%ã¡U¨é_#Àk¯œ\ðNQåN´>yé×ßK¦¯KtÁbT­:+f=73–*YTºÂ8jåòñ³#ƒY|™©½cþáúszLœ4ôd2þÒÇùº†—ðNì’·¡ 6Ÿ^ ÛýfaÈLÉí'FØ57iAEåZÚŸy$/0Œ71Xh46àúwã Ÿ…b8'­h¨Œ±|àŠR»5ŠÜJò Mk&0~fÓvs6ÜÉLt$©<È.Ë¿òmoº4ð’ãœ%Ô¥Šò åÊ~¦Eôiî¹o èÚb;Ç ò*2CáW"‡Â EÀ“ p6}sf$ý†Z‚u‰òé1¤ƒ¿²uü#¸× Éùö§ zôõjÉ9ܱ0,(XÌ y¥q(Üu¢±GÍÊ‚TïÝqw—’Ÿû\.°Œ)%ôÛ\ﵘҎª£ØÚ-]5pc)8'MËË)ý\ÍÕ÷_ÔCx¬3ó@úlI" Ýê”ÔXWˆø‹ýtËÜ 'Æç]Ïî"–®ÈWB1ôjZ_ ±Ä«vU4Nê^î\í¨bbT†.+×Ùz2|ϧKí‰pM‘ø«j|E\`~ò =æ? ÙÚþÔ¾<°¿pþ…Xÿ1EjM­M[ò<¾/ôrV(*UžUǃ+.¢wHä~;ÀÔüîb¬ëø÷ý‚'ÔÝï"‡…“’–Ø9Í#B 5Ú“–S°£°,-8 Ø™.–‚²ù¡Öî‚åïšÓe ]îߨw´æ® Eì Ñ•,Šèðýÿµ_ Tô™úzrjh󤘌s)Dηi¤†F ªeã‹õ”ÚzÚ–uäŠ{®’€€È Žñ°€÷ôÄ­¡£S}{'¿"±å?ço˜§äî\iµ2;(wÐ:wÍìׯ¾¡l+ÐOõKzÑ+zÖë(ÔCuÝø̗ÏÝNÙôo0j–B‰Y}J.×=«Ý§Ê_ΫW~#ïE–Dèê6kºß…ŒÈŸÄÏȇ,S®•~<ª9D~–l äÕ«¹<»V8xtµ7´7L^CäbU{Pq’®÷¦-jè–Æ««0GÍÏ94V£J•T¾²ŸÛS$;<¸r‹uÓdCØÒJ œî»-fe'²h›ÉîèFPâ™t-Ñ·3Þ#Å«ŒÔFôtýÞŠ„”m[´*QT‰|²E½<ë¡\­@l   oarøÃ…ê`pQì|šPjò4pË$²ªÏ& ´-!eë+49çAis|>(€Wl.ݹ{èôíD¬ ²’~}–ø×k\³j(>‰j‰4—váÓêçÕØnÌBe8Ëä∉Ġ(n¹gjàPbÚÔÈÏŠ¬u£óSuØŒ‹UÖpÕ:b‡m)ªd#÷l©#+™¢Œ)‘5S›ï ¢gNPŸÄûµ¿ecÌZçË$¹¬ˆ·”è ܵÁXqÕ9úî1eWSæ»xYÄýmrØÑˆ_½”;êê‚bKÏ`bÐ01CmÛ!3ßW!æ‘ ö/Yk'F_"\5“'©™;7ŸëDÚJïc1zù˜^ró•‡,ðÎ:¬ù4öŒ^Šød¬#äT,·)0¹8;m¥Üœóÿ¤ùa‡Þœü­Ù|…DPÑêã«r0Þ@­ß|ª!Hþá;‡úÊ{#ë'Ê#BÝ ¨HiѰ>Id­«om’‹éý²ÚJ1C¼*×RþöÇ™µEÉn üæ Ìmuçel½Ï©©gÀB'å÷;ç ß…]’¯‡¡täˆã1–?Á²Ý•J.k«ù XroÚÜ<Ï››¶F3ó„¼nUSe/q~:Xñâyô¾M+KàD¤²`Ó%È“ïi=ñ¦¢Z©ßÆÖ½‘•ÍEÌe䌺ƒF“)3\îØ˜Åÿú‘†XD;Š»'tƒ˜\¤Ü(ü9jS§â5$3Q’€€°vL%þå¼|›ëç(² †1"Gk:h&,~TéMüDÌIýq›Žé§£ÂËßbËèÞ&9J,$ÓÙÒ²™|]Wñâ¤4Ý`S$M”¸Ú¿0°¶ùQ™ÄJ¾Ú¾R  •S°@%£8ܼèþŒ@–w¬ÛÚ‡†!Îj-:æ¸éCò+æ>†->©˜ºâ1»o¢—D‚<ë¿»íMQ_Q/Ý1\“{`ý£ ·r„u:!Òû ¾ù£OÂùze§Cò¯ý*h¨Þm}+T¦Êì}ŠT&bEŒÐÎ0õÂKÓ¦ZÄ´wwPYˆÙ ¯©rœÊÞFéJË´ÏýSVÛ™¾µÏÓ¾åi¨ŠpA„fàºÁk»»Î.$W*ÞIµ=RiïV®£Ñ„æÚƒØøéhZ7ŽTú&A#‹—:3[D°V'ü#@Ø=3"Ú}™ß\pb*§Ó«D ÿÔ@{Î ‹',{õcD0—¶4%üíµÆ1–a3BØ*4=\Òd¬r|Qa2EnÉ—®™9–¦R’!´C€kÞµ«<åZÍáº(ƒZJÕHô¸H¬ØÍ.+ªÈq¾L6¾iÜÑnŸOÚ˜aQv&…T÷›[³‚aè¼PŠ-w©`é¸ÃóçÖBÛÈ ¥ª°õK[¢MöÃU—Hò¹èA炾oJ¾ï?ø ¿g‡8œÞ@!/ ¦KÕÙ¶V~ÿÏ7A9zá<ŽíÎýþcõ¤våwñç!žÊðDgŽŸñįvûAÊhØï—±‰1Ëy 9³XN•û™F ˜¦´ÊªNx’£éYMÍ5{_ÏÂt7êqs±=^n&Ù¦Ö“Ã!g½ø‘³wFÞG=ODkÕà€æ@ÁejKÕæ'l„,ÉFì…> ++/jÙ4`ôMéf*烳õÇ e!sU?º£åHJll!Ϋsâ.sj¾£7hC‚ûåÑ<ßD¡Š@Ù 0¨÷gœ?Ͱ ¶F5˜œ£¸YS¬Í× àAÁDÍ<ßösû]ü-Å·Òžc¥–?>:[ò°®3ÐÑ¡j±©3,ùêlff§˜$'ä œGhm åÐk'$1ðQ:äßúkUtÛ&ß“œ‡}ƒÀ¥0HÝ:½kò™*g¬,X·û ÃÙf¸bïœûý ¬¤ž4÷GÝ8›Y‹V’€€¯ð©µ|æ\¤(CÊÀ1ýùu4b†®Bœd4¶‹ßí A8?F¨qD2¶ó7 ¿J6ƒ‹“P q܈^Ôýúc-àIƒâBIíD/W¥ð¢Òy‘aZ´âò}*q¬šàzp«n14q+>óä~×,3¹MèÂp‘?í°·1áž_½ö(ŒÍ•úÑ,¦z1ØðÂô´F¹‡«á/Ðe˜ò±X¥0‘·½(‹QÖ×ÇZæŠÍåF®7¨ÞòÒ»ýµ›@ gJ%4Ãå…ð*æjŠAŒ2 J´nÓA”%§VU6‘äÑjì¢ÇÚØYéåöM}ÎÝN¥Ÿ7¬5›F¯Ú2§Ð’G…ÓšS3pJÖº:Û¼ E¦6]`AhW S·WdÉÜpÞlúà]nT`î1”•hRî8w )™ê"«&\¾gáÂG­ò ¾dêþ&‘ôÍÄ 6Àë ûÂ|[ð>™ùäù¢¶3ŸSökqV;=ˆ6.ÖWŠ@çÅu°mWNFä otÉt -ˆpDo ì}2ÄX7H‡Ž8;1gìÈr–ìˆd'„úüÑ™ß0lÀ„låa"Ù?N^¡PõÞ÷¦H‰ùjnBuwpiÛ]îòs¯{YÌÅ’× ç½x~'×C¦Ù7p.ÊÒ6štt!¥ºÔ{QéãR'þ=Dn+¡b‰ÙR3êÆË¹ßΛ€½…¥VœsšŸ7YË,äí–cx+ò›Z¦sé¨÷zNa_{@Uš{ë»ß …L'át?b@‘ú·3 Óƒ“V]MȘ5ñÃÐý­™Úµ$ź‰ºÛ>z8DuνÅ»‡D½À’Ûe‰ñáeÑöÝøHóœe,ßnÈîÄüT¸ÈïìðÀÆÅ@·>1<¸:#?J“dÏ—ûã9[Ä«äõB›þÝs![ÖãÖ‚àFˆÞqŽl9¤ìIòE`¸½˜$ß{w#®Eθw¥w}í;eW9+°{ÔW<ÔcVÎ&Å7wß*z˜pãoê£"îLsú%ŠŸõ¼¿br¿µ”x{ê]qcNP݇‹/i&xŠÏ¿yb¨2»!xJ¦u«Fóöþ:.«V©$sŒ!q³OàÁîßáϰll¾ëcTËë²-ÈJÅìq2µÙÃK8  (¼Yßà’€€×!ÏÏÔ (ÒUð·Wö˜èž¶4–¯§øšF«ÙÂW5I‚«ëµ4ŒÑä¨ésý§>¶Ï}m¾ØzôÓ·ì‡Ï8ä®ç§r ó[ä°Ã9UÈjb­l‡÷#Í!A¶`’o[&»qÉ-©·—ÏÈï/æi-}Ž©‡RÜRõ³:VŸtÎÀè¬G¨hào‚„¬¶ÖOcÌö—GoKf¶§M0¯³éµÌíš§På㙉˜‰¦Á‘§[ Ð꟞}|B‹ªŽšôÔûþ[šP9YÑT$V•E¦ï”ÏÞ¸ÿ”pa¬ì`̯lcý&ƒ¼`âÎ0Ÿ½¾®¡tOhaÃ/y•y­r¶¨ ‰.¢Z0è¦^Ï^L˜ Q&ok—É‘¯—rüÊϺLs¥Ñ{/ĹØ5=åèÑhýÆÎPËËÒÔ7ä’×®–£˜(¢ÔŸ/ô*~Õþît©ýÕÝ$ÆÇSˆ¤%ëÕÓeˆ[ô¡U¹3xw Þ•0õZJSúÉ›(&6Æ›n (âfܤ>2e}€?žˆT’ .ô¡0B¦O^–U}C:íÒ3ºËÓIMX‚×u!Ùéæxš:†‹^…­ä5Žxòãß ºéZ ;??pÀayu™êkòÓ„f•™ž|B ÞŽ÷’Ž@›ÄÎê•,DýMP·q¦2ÿYý‚Áû]+yïë<oóH–±Pð/:Ú¡–{è8hÆÿ!©ºŸ¤Kæm¾Ä úÓ<Í*Q´4Jm ÇP±C2 äˆïÚ¢Óß Þ¨üßEèøždËÇ•Gíˆ+a 0%¤ú•* Qö1@¤_I_ìF•¾áL¸[£Ï‹®L"Uº¹.aE=MÚ7³Þ'ygóvR/èP<#ãˆé×OÑ ÞêZꄤ· $×x ?7sišH lÃ;á ,_#VÊ;æåü1”ÜDLF/ŽËïGÏ…Å6 ÒÄþx_q;4!*F–Ð…|oŽ‚^è<+U껆ccU•Yó3Rht÷‚-Üö]5ýš<”ɧ^:muß%/4^&s ÈÀÄëíSÙÌæ“"¨@šHÍí¤cÙxÅît,ËTB܉Úû›®G5QÈçpÔ#és ”Øî{u%ie ^š1ܬ’€€Å/ë ßñþ|ÛÍÆàÖ†ᆽ#¨bã£àžF±á´ ÍD[ފ饫Ǫ¹²¤ «YV¶y°ë77Fq®«µ‰ÕÒ~x£½Á™}h¹Uâš9ÑGr[4tZ,£W«=Ã!ødqóZ~òÙ —†ÇϨ.fKM¶J^‹ã­BÀV‹©ª1«‘mWãó¯žt•É \ÕÊâÀ“¥¬ßOfEC„‚»”5Í šþË0F ÎæÇL ‰Uê²ëzÿ-í=;Ÿ½Ô{ÕE£—¨]+avÛ’€€·Qü/Ó˜äª&Ž#Ùÿº‘^ ¿TÉÂÅÆAÉÂ’˜Ü4&¤Cà•ò‘€¤l¡•ì^Þ‘é^Is<ŠœB ¡üñ¤€ü¬EúÆU^¦9í‹#>±”/ñQÆÒ•ˆ Ön²Op'é0"‘÷óañ»eêT}Ú*6û\.- ŠzQã¼CR(ÅEѪ›jÖr1qž§~¾=X‡I©ECÖÄÅD¶Ë¶„:ÁT39îËIýº¦åw˜U ]fú±BJÚæÖ¾ât©?Á36å%¼Åõ¨Ð8+’Ù7½\»M#Ÿ«áÏã#hY Å"†ÂÓÀ8ˆÉM\É9Še£Cj€–ëJGì©[ Ã1  AXçe™ªr"ÓFsu7½‡«GüA¥&?0R“ño¦¾²Ê? ’óÈÀ1G¦gÐrÔ«;ܳÀ4/À{”eÛkÀ>m')EtûVJ‹\ËñP6Ê.ãä‡Ë±þÀœQ~[ןWà'ÁJ¦ñ€~õau/fúìÿø_9ùö4 sCm~¬DºDœMó‡íãø¥«ê,¬}tÚÙçxÕdO'hÞ¨ÍOÁ¶"hk ±»kìéE/º`ÞM\F¬a_±#Ö#~3·çQÕÈŸÿ.™>çW!ªXð…pØ­G yú<âPIßõñ}D!û-ÿ1Òœö±%ë1ÑÏùüÿj¨%œí'ŽÿìTERà gòÚÓp0.føWZ§ÓSm~hÈpÚže“çÈc"*ѳÄߪG!cQý]1­Ø¬˜ôãš‹HgJAÄD|›­ÎØFâ ¥‘‹Hh®có ÛmM[EHö%NæLž£Î•Î7|gLjeGï_W¬$7B]Áó§gXâAF‡îH'ç{2¦m(ëÏ?ØøÞ¡:?‡ÿóÖ–ËXt)_@µ5²àк×,ëþ«Ð*” yçIûÚ1ÈTw½_1åÚêaB‚Ø#òY¦k„ÀHU+c-=ùWeÆÑp+›€.Òíñ´ãgòý úϾ86ÜØ´œ¿6ƈAÁgeÏxÝåì)½×]ÅûTö §ÑŒ_ P$–zèo˜|¼e}iÜN»ˆárt?wƒuJ¦4òÒ0¥É 6ª¡p"«ñó2š¥òaÝûîhñÔÈIŸZÓÎ!–Oö3oŠ?Ed’€€¶¡$¨^&Éu³eR>TÀFv•÷4ùDÅ]DðsŒõÎ Å7N¹^ºã_×Ö•÷¢ÁX/X¨“ U›n-:G w*ü®gë›ç†kž³{ùjÈ Î÷Ì­]ÃýÓ1`$ìP2üV™[i¸.Ô=éЛŽ×Ö­nóxlë§iÚ¼~.Cmx+Ž›M〷"e/ ô|Ü4WË6ftߊ· ™®3Áœá1^RÐמ®À[ËèkÓù”Ý÷$œL0±þo¾>èQÉyx5X[@…ŽN½¶æyb{J뱺 ‘—ÚJÃßÊNªJò‹}Áü±ò³ÊÑv9FÉ ¬P3WyÝÒ.÷§èp¿ëq$Áš©7ÑÄÄ»­ýÚÏPÐ~è)>Ïèkb{Çs?JŒ -úoJ`Ö££Á/û}4ó&ñK¥ˆ›€6„4G¢äÛˆîô#P-mK Çã‰c ˜ÞÊ>{¿O†ÏÕ+’Þ<&é–ï-ûï'DÖÁPºBr0{ã–yèFbÇ£î-áÊ'7 J\U\É\ÞP<£( í=1ÔLJn›:ØLêuçÚÞIÞÏ‹%ÖxÊ.ØÚ¤/ˆë–F%F¢–üðÛÎ|ÃßÊÚžpðmæÙOÇ·S8:~—{D¡Õ7¤籕¸~×ôCÒ7 Ÿó)à_Ñ6¾ÎÅ]ê.¹•šñðbý7U$^¾ÀêTÌAíѺŒem{Ø`+Êð™JD2ˆ÷E¹.ûgCŒêwT M?‘ýèkK† „på´”< Çÿ0ä2ž7Ê-ÛÖ˜ QŠÎçW×ä©g‚¿¨Ï„äˆ %(Êø.F—åÏ«Pù³ø,ŠdM0 J=Øy™½Elâ?ÜÐ=%ªrr2”YŠÙ¦FªžF~ à‚uø!KûÔ¾qzÞ^)`i^‚×É¿ƒ•¯¾•šÐ—þ½™*ü礫‹|ÚZêƒn ù¤ÁƒTðtB„mþÇN<Äaçœ>pB×}\Ê™¾0¹@Ì÷'•CQt TÔÌ (²Du Râé ™–oOœÁ´QÜmÍtÚ>«GC{ ŽÜðUåiÄÎLè &s|M5ï&džÆíž4ÌÛТ ÁÞ„§«š]cS×f…P3èØ¸¥¦øóZäˆ\sh[YÀ¶]_˜|N;u’€€Á,°Kµ c·"_z´î¡Oþ¼i+Ë´Œy¥’&hÕ€Iég†T{lÊ–‹9ÃlÉ«óF[bׯŸã_Ò¼Ù¢¹´ÄÏ;u& ܨlð³SFÛÂp\z¼ßM‚‰˜-„¹Å…HóìQF^™Îëw¿{Ï Ö•›K)×*ç… ZмÊxá²ÙܱV[ÕÐSý ²¡˜ä `¶È‘©ºáùkS‘#$ê£2™ ]tÁ³Ÿ¼9lÝ„¬­.O༜·ÂÖHŒÆªvÇWSïö*BZ_Û{R™'^b„Çfò^dsÖäÃ!›Z Gt‹ŽitƒmÈ4çMr’ØVå…Lriqî½ µ›V’£>`–ë¶ùr§Ø¨µ€­ÍàÒ¿ÑÖ?I­ü·e/}I N–<,à`Š›Œ e¯d=g®›©/õ(êÒ­ZÖ ÝñÝ×óòöQËØéßKøu¬ÎxBèoi¸)rºFZíÌa$ën…ôN2Ü<â˜ïCA1|ý0:rúÞ_y'øß!Ú‘=Œ ñõmÝ!Ðäÿ {‡$Õ3ç|3­ù—,áRÈø3s;’eýA›RE¹èÆ5Œª^šë@_Ê|»Ý­¡0 }ÎÕGê~œ ôÆ2M°ž±|–¤V^µÉ9ÉHBHÈÙ¿ëEÏ.¤Q“íŒM…cÀ%Nˆÿ=©•FBŠÒ/8…ýPâ}ÝP¨¯Ððt\^a nÿðBsóݹLûfbÝûd–¹¼ >[^q]——É•GNŠžÛjƒ!RñÐ7ƒó™8Hãác‘Ì{úÒ[n‘ {:­ûùîÕi£Ð^5æuYÆ ûb*@3P°`v¥›f£ò–E *osÅY=}¸¥‹ß‹î;ÂqÄêÈn¬¢ßr'°ß¡_»M;`WX²õ3m¨V‡0f.L’€€Ø²ŽíÕg¤3ã$N0}yë'8Ú\v–¥¿Äá 6©¨°‰èöŸfP¾`þ“ÏÀr VgÄ'ƨkD·É³³›ñ âíÄèøª+å(ºï™UþÞHœ¡ç,!@ •TåúF`¢“aà›:0Fæs!;¼f½œi&ÛÌfT%Êq_Áˆø;¾¸¶ß63©ï‚á‚a-e“Òž.ŒžÇèì&“gåÞï3HØ -lÄ=rï¢sL;ýQ|¾h»ÑJe­4eU‚Jv\õ•+…èTýîƒìÀÀ ¡*íâÀËMú)l2 ¯Í±ƒëpZ xýÕ!ÆËšðfÁÈQ¹$‚ °a?…‰zý½w*Øð €p²Fð‚Y(Ø%[laÜGÆšæzM‘r ßöXúá|9(ÓŠõ'ô@ÐÀ¯bkÅËr !>Ùj…cJÆÚÜÜ»n±,ì£(p°Bõñ]`óÎè€>EáêQÐR2¯ÌèÀŽôœ&Ñ 1e_’””¡Ø<é ‘÷ŽB÷4?Sñ` DÛ…5Y?Y¹¯ºŸ`¬i×>ø<{“‚y¼.I©ªgMŽï†U–Êq,Ó’­lóƒCöàãQ c íÖí€uPC¿ (q¿/ Ývsìs¬Nì§fI€b”¨}•!›øeÝ ÔÅû¶ßÅ{4¡ÜªfÓ ’{ÇÛµ…Xß·îDèvC˜w(EÊÕ j×¾£qoC¸lÄX­7E”ûЍKNÜâÆ¢ïë–ÂË/]¥ú¡ÄbÔÎ#7Ç ÛDŸîkÙ#ùbqÎ'{8aÿÈYôØJóoY-y¿ßTTc2Øœü,½dŒí„à5°X Î0^ˆÈ6âݳá7PÇÏ4"gϘ_ß`ÓiÇ¢¾W$]rÅg>hðåì,"oʪXÄ1%ã›ßZðãá]B ܦѪVa©40Ì"À‰¿üøo‘îÿ•T¤D’Ó•Â,pÍ¥;U? "{(47¡@ˆ0ŽcßZ¡`¤ØVOJÞtÏ-ü»ÇÎÊÅ 5ˆq2ÞgC+Õ±›¢Õ#yrÆ¢ BZ쩿Ǧý¦IrŠ3Á° hÎù¬ëП<:þô¡™d·'º4‹’üôÂ\îÓë&uõe‰Ôo‰”l¢ºÁ @ø Ð‡‡s’€€¦±vç\d]‡~Õzqœ6B˜M8•E$ÀéãR$7vìÆØgQÓí‘ÚÖB²‘ñÒýH^} w²Nõãa ¹8Ωè•ë›ú ±°$DžÕ³0ú—–EzØìA-7:Ýà¿##)€P¹=/¨!ö+ˆ°ér·­ôŒBiQ טØó¡©w`üAOd¦¼øª:µ4µûþDöç·•uĹYàÀèIˆ™P.¡Å Á‘œô-À¦–dˆ+'UnKwx\¯—Úô®­Ð)ÞgkeÿÖ;Â&B–ù÷úåÔú˜ºû Ï}U›$ˆJ(^ÞËÁìì”(ñ¹0z»_É^Èì©”öðp ݳ–AÛP¤!ü¤â5H¯ì½Bku3àm‰µÌÂp’í¡]¢¼Žß™Ñ:^f`;嬮X¢ÎŽønÌ´kÌÂÕ0×{ÒYÝ-dcöyS†‡nk9Ú^ÐmeùÆÛÅxvîøÞòí.ñ´e3KJKÒÖò èµâM˜æÈîà-Vˆ!æHOÂ|hÃ^%Ú¼J /s§¦,4Üš‡µy¾ Ò­¤É;Va’‡{Š0@>B@Iˆ`ÜC/ÕÖ¡ìJÄ4î_ÈôD3ô*Ði¶–ù³÷WäÊûh>!» h߃¾à.¶¤íî{عt®ß Ô@.eÚÛrŒ*š‡Ñ ?D33Ø¢m$‚ ²QB™ìa°Ú f1NóðåVJ*®Ï¦˜Ç·ÁZ _㪒sKK>ê,ŘéÁ IR»‹†’í~âOd «=QÉ)¬nRc#±ÅdR[õ-7É‹@¡TðCSÍ;²çó«Þà0l~IL!Îâê8³ê›SÀùN’€€ÎÀFøDï™ÿa•º4i‹•Sª•‘`Œj¡z¤?§¢‘AÈñÈáéæ¶¡Y?åf•ƒxÇ¢XûÎr †mÂdÝ’¿8† Iì””4…u°ºá‘M3gAŸF[¯ƒ.ùû Ò¥GûLíhL$[+tü¬zº-Òì7ÌŸ>} ëÈîó ïÌ–éÿZ1›ó£|A^ ,¹újzQ ý]DA‘ûN4d^œÎ&î7Ä‹-úí£Ç€Öƒ«ÝˆÃ¾DUî7ríèÞs.4pK—”}D†Æƒgž4Cryš‰Ü–©ZbçpqHÞîs;aú¿òH Qû°ë[çËôì»uK<Ð̲gnY _·>ù]Œ_ãy[§Át›ºO³~n"7X!Ó …ÜCGh Gùw† ±¤y¶‘æJ;htÿCïÇe~ë;ßÈÕ²È[Š{½¸P7¶Ž)pšiªC— œú“¹™¶åÆñô:°;âY-Ðã§gµê¢S[ÍjïËMSè"§‚DöÔ'Þ@fè//u¯‡6Õx.º”3b«r€L¯m8YÔ™7™ì#_>ÆÕÒ5g åÆÿZ3qó1R–ÎN×)ÙiÐ7o¼ŠšHï¬ {ò}ª&nS²±,Áæ?û²À(Íæé)¨§û•Sœ/‹âŒ×x .ÐøÁ¡Äœÿˆ³pôü òåZ–òPAV>h£Ý¨^9 ±TÒh~—Z|6hSÖÝpeulhVt«¯©Y”më¦[Ù˜7œD€—f5Lh#ûÞ&>Ôæïí—2ÓHeÛÔÊ“ms‡NãÁÁ."³ƒd3Û±óŸs…buE§%í5H IhºasÈ눉j™q‡Ÿa9ÖZYtqnØôEaƒÈ,þ—Ý‹„eˆ1nnÃæO6S­©ë?Éyq˜Åp½9º”—Âã{™|ÄR2ùh8(øï×8wkúKèô¬9&¿–;òóbQ5ÝQs{›ÿ:‚å×ÕjìùgØ ©Õ‰ü™Ï¿>÷ˆƒlÛgÇ6€\î'îZgTW*÷nw4éß ‘ú=·tNÕ¯Rc6^YÌ–ç°Iš½)W +…’€€°É£\Ķ¿÷Ÿ±Œþfã I€ÁÝ—­Š ÁÝ¥*îVŽÑÑŸ÷’º›©`sL L´§6ÅYÉ ¹ŽcSL§•öí°Jé’×LôGDûC:ÎmB,¯ƒÊ}!1´¿.vƒ6íÈù×:i|-“Ò¤|ur^þ¾!3 †º˜T†WX(»Ì)¦ñC¡œ{ŽÝƒ’(¹3|¤ˆ²Þ§NÛz.1]ß!›@ ›Y#ÃBö…†V V¿ñ‰ƒúyìãÌ/øÊÒÊ3ß÷T씬%”Ãm¤Qy$k|4Ü5ÚîäîTˆùNnœiNFa‡1—ÅW‰û©¥ÄZ¬Ù )ÍKÀ*ïïœ!ß. x&]»{¥Œ@»%4°–›5&µêá ñúîy¾=;ãGÿ ËAÄ GÀvw3¥žPkk7ʘdèmÇ4;£Yl–„|\-—ãœ4³ÿ ðtÈ{i>jy9±q Þý;õÞhWI`y€íPZVµ=@ô(e«\Õ᪱•!cÃÙı(ù´ZØ„•ž»§pî”ÿ6XÛz__ÚeJ¤wÞPªii¥È}µ –[˜Ä†eMó taìA“$žyqØü}Ëðžó/6•'¸ËìH¶è ìöùùH­;L«ýGnbÄy’€€ß¾¤v‰T[® éÇYÅ)R œË˃y­Ñ´.þ‹¶ÎÓ»‰o×ÛVpß©s¿”#Uø§ó®4ì^ÁºtMåD"lÕB¹Õ÷ûÇâ,)žÁ HÑ’íD-õ`ú!@éüÀTw{3¢ÊmDQ¹Iµ€â½ߓʭ©¯4ÂÝëµo¡pXä,ã…^ë¯ü4=eo‡kt¼³=Ö%-—W·êGúLb·H˜ºšÇ÷ï®÷æéH!ûac÷¾œ¿¹ÊHƒ}/0Ư¡„|À››ÓúKú´­Ÿ€Õo& Ÿ‘=¯¯ my–¤åŸïÔH N[x@ûÍ/ûƒÖ &= (&…âÊ8×®@þÁýê‹,;iWs¦¯žóž„“eGö>ÍmîϹšá9d¿xØŽ—XþŒ•ÐO=ÆÑÌR½`“ŸHãxXèd· ¾C¹t¿2R"=šb–ÄŒšgß©u_SÞ­­dZ¦¼l y’ii‘0*s”¯ŠáEsE´µz>G_:–¼EíïɶtÖHµ)ü´Áºêäö6òÄ1si,‹E_è\…ÔXɹ´œøLÔ®³¼¾@FWˆƒUïÃRÎd"ê’œHÀGw¿Ó|˜©?¡©ñn¦©ä–¸²UFƃ« ·åíô¬ß:ˆZË¿}nj¾ØáÍ1óƒÒÄü™p¶ú@° ªñ™à` <ß)U¥:>Púœá‡œi>$&Ö:Ro,Áp@}¨‰EpMIõcbÎÜÁ-ü›,¢¯÷bÖ>nèáòÅXp[ŸÚ{öI{çSQQ ¬o‘ò%ûƒ‚™¬ø‘¡5ˆíYuâ:ø+$[„&SOsßÊ× ÿè "²©Ñ˜-E6 ¡ÖdÆÒ4Îk=¿tMj2RÄc¦¶ªhØí/BRµ&;"£Ø×s°ß:·Ùn_Ü—¸-Q#·Okš“]Ú.¥r9¾‘‰3ih÷³{´«á4|¡ˆ§µãÔBvÜeˆMèàÈ/ þ¼·´E{Ö—+`†ÌÌ×#§ƒDP”9œŒ—7ì¼JsûJˆ¶`³-UÎ…†= ˆøª’¹%–?|n-컋ԋŸBòv-…R{T Í,oO –—ܘ>nX:‡§• 6ÂVÅ ®L“zE²Ïaùó¬D8–6ÖFKݤh'çr蹸@@¼Â2-ýAeAyóU“—þ‰=9ÊÆíÅûk«-”‘sõµÑ'掬)úC)NfŽ{Ñz{-%0Qº Έ¶ö*QJàÜ äÍË}¨PÞÞuµ»˜m;ÝFÔdDgMª¼žÄ°œ\й þÙÍS0@ œ¸”Žã%8Õ4Ù×êË‹¡“mþs+÷ú¦·^˜¾Z&.?¢¯ i¢ø —,EhZä€kÙmg—?bYí±GŸʬ»ùµ†Ï4ò_ûÿžÛj,ªëm0@!«¯»T˜œÖôpæ ÷2Ú­ÚXû„ÉŠÙö¸/1iqh?¨„ò7ý,ƄȄ…òjyvÅ+”ëÈÉ\–saW†#€ÝŒnÑ>yh>¥w×˳§Ù ß×f˃ÍöámTéÈœ3ÔÝ[¤ .¨yøáÈ4ëqÂB +}ð¬Ù<áîÄûJpïûÝAísŠQÂü¦Ò?}Óß~º¦CÚ$¿í¢+éòc~¨±ç X癌„õçŠÐ|¨WÀÓÁƒ“ÐM\¸NË0=°ôD(Ϥ&÷_Œ‚Ù¦4öœ´Î#v+¡é%YMbù¾[Á뻇 Ì,À„v÷?òÕ\pú+„ó‡¤Ôí”´²i©W†u”'¹Ñäøéw–L÷ÚªBÑo©¾ËÍ„Ì^GÕ?çEH9‹Rƪä:H=U¥‰ÁŒlû0=@CÕ:2Ÿ°åñ8Q,è0QU}yù^(H°×ŸrlXƒÂƒuo½}FJ Sè*“ðO¹2âA}ï#ˆ×器>J=³á”âvCGÙ7ÔØ¡‡û(õ]&ŸùºZÕ*H²p¨;­~73™”$CÊØ%‡’Œxå’k¨C †Éz­661%¬„’FmAZÔ²œŽ:þ½ …•@ŒŒ«XÍy¡^ûÍöìÈ Kûüæ ã¹Ñ{)ºèp˜@;®ÿÐxZs÷¤‹Î°<„ç?TGl:ûójB·;‹Ø×f^H ³ÚE¬{Á„J0ÑxTCVúÙ³™Ÿ¸Ó±e»Ë¼“1yq8ïêÐn3€Žc½Ÿ?«±0N4Ü¥YíÊ]–Í%îih¦ð])g±ÀQÇ#®g)¹Œ˜¤¶A2R/dðß?žr¢Ü[`ÉŸ{:µKÈO[Uì€Eé8Væ”'Œ|·üîÜŒ‰?>Á g¦& îöøÞ³'¹¶Ãç†ö¢5ÔjpEÙbÍÖº?rÇ{φI<€üUûð’%ðo›’¨ °]/$¸F(ˆ{$;½|¼”‰³UßKÚ]Ôœ™ÿíÑ£²g—9Ê×:NFÿ¯8ÃïCÂvµ@ ™']óÿKfüýšÖc©ñ·] ±¨ä€v€|‡©|Ÿ…Ñ”'bƒËH~¹ P Š@Ä6² PöM—‹›ÜˆæïZ"ÒIÇ)T¹rñÌ„!¦°}BWÀÃå×wî’}òݬ|í¸Y`.¶ÀUÝY6EGÁÖ]ˆëúg…j¾phæé2mI®ü­[Û(–ð +HB@f´«}€Ñ°÷; ÐÖ °­‘èîv7À±W‘zš œïs@«k ×y¸ÿl»»Lže=K•×i(È ”Öÿ0xQ:äšé¥7‚€:LŒ…ƒßŽ´C¯– 1>”p c§Ô1OMt<¤´áÒË1ã˜/Cø’Œ’b½*¨<û<ŒØ]&:@ k…ÝÓb5ÞùÁ$ã ðˆÊà9¹À¤©ŸóÆ"É…)à'’#üÛ^ò«‡¿SÛ)Lw\ƒóI²*¨2é#ë§6Þ_ŽÚ‹NAøˆëc<™rèr8¤¹Î¦þÑðåQš×2Tôiäª]»¡.ò ¥ÿȧó³)±:¿Î¤Pd0ô {’€€¬µ®'§SÊŠ,Õb‰[¡)»6ÔÌ„äù6‡knžbK¼ÿI¾9®¤[ªy“–i9'œµÀ€ZxV5têWÌ)‰vÜ(êwlŒþ‡I¡—°«0Ç;Jã±*±¤X=u-žÇ«œÅ¬]¯a1-Ç‘ÙÀ~ y„X¤+õ±Œ·­™ˆ`ÖDAÛ9Ÿû#ÿb`ýÀÖ'ƒkIfî%@€ZÀŸúSIû¸ÑEÜØ¢moûaâL‘(yÞC“gïÒ?š¬W½½fK»Í¤šJm[ª!ʳKÜŒSëößòÀE½F† ½¯)¼‡›4Wÿˆÿ4jÚúÐTFbYßWHAΤblæÚ(íJöÎ  Ä·5»¯ˆÁ’D %§NÊöÔYƒ{ôAËÓ3¾ºcä ¬ú èA°@a-Y]Õ"ŠÙª|˜›7é}_¦?7£ƒ†ð3èËÒöpÇ\% (d+†ÛìäÍßÂèâòDbÌ" Ju]6øJñ<5luï/ÿç)¹‹»$~üšðì«® Þ––Ú׿!\‹éJe5æÇ¤@’´Û’aªÎœÞõèNª DÏêÀjÍ£FGŽ$$NGàɦ¨ØÐx„]TVrÌçE9«D…¥óÆ=-˜MÜnéÊÑ °F_HühöpÁ„íòì®Ð¶¯¬$áËNBÏ„¯1gßû-¾Áb𒀀ݛð86,ó"([…´#Í0ê:µÆ»V«¿Bò:pÈÜŽÙz®Ê4]CóëJëÛ’dPiîÓ>"É·g%–Å´9Þ-wodåP[À¥Ó"_£Œ½Æñ¥q“±˜x\©#tçYÿÑëÚ!fÄ¢¼…£>ƒõ W[øÌ¹h˜ÛFO{꿳ûñkÖ³—îÄ!ÞU ‘ßÇ-‡d?ìh:f_’,N/‹ÂßÌÞû|DW3™ßî%vbžhÕÑ>–PG“¹Ç{W>(¨Œg8«ud0YuØ¥:âÊOöç~~öâ&õ£Ê¸ÕVù·±>BXWvãÂæ£òô¬ågD*ÊK!Õêc v?‚‰Nn õñõ†\‡ºcM@BÕòpÐL°rÚ”×›‰ê¬$‰Î;F*r)¨Ò„èk—2ï¬8¿ IÄÃû°;Ôˆ\)P(ËFFGÆ€ÿQOI\-#gåÑ*fÿ U< ri‚¤™¡Ý9ùèòàU2»éDjœ8},jÛ}+.fq¸É;Ô×l½ªLd/b™Þƒµ²üåª?ò?‚h;ŒJùùŒ#á& —÷I“Ç«ñ÷nSLjýn£¢†OÝ2JlT²'KÚ²XIxȃmãüz2µœùÌSº…`¾I’|1ƒ ò\ø¢,±Ú¯Tó½Í‹'à÷WâÀ¶Œºg›šY0üN wÖ§ N ië‹¢ì´#P\ˆ6Újeò,†Lìî2iŽü™Ì6ÝÒ@Ir+?üÑDä‰Wþq²¦ež¬È]óÚ‚+’\Û^5Ê&µ›Vð/°”]¾Ôn$~¤‚fNTÃê€÷ÜÅöcÏkÁ2Ë,è>f'øØ‹¦ Wäñߨ²üê<[Ð#—@­R¦šóAce!Án‡í=µ±BÚ6N5žÔ)ʼn¼û?zÞ°'¸a HàñlÎ"¡Z_”îR‡N–|N¥ N®É,cØ:Ø ÜÉs·Ù÷ 4{“›NYÛ•¯we¿½*øû 2h¾%“1°-ÜÜËò;Sßpj½ begqHù¯Ùží‚éíýWèvTÁ_$¤ zÚ~ʤÝéX†KC & 'öb3dÕâ( t;Ùö?ò€×*ËÉ=OTÆçˆ-9ñb!ƒ~$Å^‰ZTêËÈ~E’€€Ø&!”òV[€ê¼õ-•“ž˜x=#iß¶Ê2ÎÌàöˆº£$OïéiðiZ™Ð\cÙÆ=ýÕèF¾Ìi|<€šÎBõfš±ttSV)à" ù…×ÜêÔF-z'+¨x5{qзÐPû í׿¿ŽïehI*q/+zóÁ»æ£Ü¥r¢Â‰ÊË%Ǫ *ZSê Ò8\i¦©Þ¤RñdÜ{©b׬—D6€·n"KUu”ñ_¥£ý9‘£¹‹!Sn·Ùà—ZÐÀ(ßÈMi›Ô6‚]/m ƒ"yé󀈖¼üº´cùEÊÜÕ4;Ä4þ; ‚rγóTØ>ÿø'ó,°¨ÿ·¶¥‹¡úä^®ÑÊJE]ÙJ§©+ý‘%Mè)5;TR³Wü·Uâoæõ}œ§b/Йv×ç~pÖŸ@0"ªÇÔŠÙ}ÑÔIéÁí¤.É¢Ý ‡0wð ªèZ§4H¿âL²µ8…ô÷ùCŸQ.—ÜõðYð=žYÞÑ ɸeÉL(ׇ±Ð˜H]ê úŸ®*€†–/rë¯i-yË%ðvŽcH‡`hSxËÈFÈ–5ÔM„ê¯ë_+Òξ8ø½šqMß;9¾./b¡£ì„ ÓûÔ¼FçÉü9ßÐÔp~c· sxD,xW¥1“EÙA±‹ó"Ñ=Õg£€znô½­ƒ&¦]1á˜ø ’€€´Ì—-͸¦#Ú„ šÐ½YGcêvrsdQôäsw%"“3hž¨ÆÙ6MMˆ™]‚½•\?]G¦Ÿû+öÉS ‘Üö雟(0be¥xâ2Å‚SçÔCâ×Ìp`ËÞ*Îaº›Î‘=†YÈE>—s7psÒü^•{Aü1ËÈ^‚P8¾Çöl§Aî[¶”1 *ã’ Q:ᄲ-V>,ßQÉ? xÌ©ÔJe×¥ oÉ»\´ãÅü8P.I¿Ãëäx1v—hö缋7¢maµþFz]±¬‚íä$¡]ê)#¿¦TþËgã]MNPbºðvàÿžPüq2oztmn€9¥dèëŸ*ñ"öúUÚ™opϙ脳²Â©õ‚j¬™$©Á`ëÙx‰hiÒTˆv./9f5S²rÂGl-AòÆdè²ùœí‹»ÐÖÂqAÕöºÄÖbóˆ‰ÂñŠGÑEƒ¼–â·à‡S¦ó’»vAåø&B™m:EŠaíª3hªq½þÔÑÍdjÖ þù|PN2ªo™?~6UH¥8X„ l›´e'YJ3Ò´–Ç"Â˃1AÀ»ñ1Ëñ(õ$úŠL¾ ºu!-r˜ÓÀ'DŠh¯ò–ëëý—Üí- ¨Ÿp_Éû ÏÕ4^U7¡åÒœS•<Ñ Ûº¼0‹›q$¡'&üõc9'’_ƱI›PcHÂghä ¿í<ÓoÉ>Kk.ß ö¤€j‚;¸ýK•d`h—ö9B›O½„þà¾ÑdIm|¤À\D·¨Ýwr0 ì‹?z¥ OFf`žEp3Ȉ/l;R‡?åãó¤Ä–l`R·/ŒÕŽ?áèÀkao¨5>aÆ1½F¢%Î︨Fáìi¯áË^ L2¬EhøjŒ^(‚‹´»ˆ©ž6²®‘ní¯ý× ýÍ —+Œ¤“ð únç,à,ª ® Hƒ,ðD© ˆQ~òýx3AìËD”l 0SV|Qm!´CÛ¤¬}b´ÆTG 5Sý¾±u¡òõSô|ÒÈÉÁ‘Z\s‘©n«æ– ® àƒô¹MþÉ¥ÞFä„ ýƒ‡Q[=©!9úšCIÇGø˜REtS¹Q4bog‚óºI~D'“u1SůÉE E…S’€€Èó4›+¶ˆ±Ý?ÉÂýu¬_ÕÒ¿‘;毷Ú*÷Õ8ç Z÷–¤*€,]¶§ÄØ/U3Ë)ñ -gñ…LdPÅÒÆHYS¿ìÁ'·ó𪹉jÁE[Ív”&•?H ©øEâè νìúÂPüZÀàngNç•Ëpó0 ê—Þh³Æ³ZwQ6cØeTÅQŒleí,jû¶•Œ¡ÊVIœPù¼Ãc(c§ÊˆêàºÕ~†4tKÝ·˜L!1‡P»KÏÀ)b0n ÷è#`(èR$'Î?kÓ‚®‡—Zø‹MˆÄ ›&꾪_0´SËDUóL¸bÇY¬óDñ¨bTßP0+óýw‡–Å´rÙÑ82©Ù[˜ ¿¬¬-+ hÄJüÂC’ÄWÞ­ÏÞ+5)DJRNk²$ pÞV-IJ0-5H»Äÿw%ýu Ÿ)õ^ŒZ{EØëâ}Lý| ¶[„¦æ!Ï)èõ´9£sß]‰ffAåt¡6ALâ/Þ*Të"ÍÌB×€öØœÏõ«3ÚØšä& 3hó}Cû‚툎ãîÝ» h½¯DÏMõâ~×ck‰ùòrŠ>ÜЀ§Ž[³SŸâ£~a¼üîË®Œ˜ðº%LQ—-W€\vðŒwªZQ<ß/’€€¯)Æ#Qék!”µBF„TJÙIävñ#ð giŒ:Y¥À¥×QÃŒ±ùã1´¼v¼‹c|©šœÓEB&U©}ŠÖ1Æ ä ,ìsÛì%‹¶Å,aÏ\›ðp²§9£d(ÒPfCàs¸jöƒÃ>…ƒ±ì ö‘¢ñ*Yþ‘Öä©íPìÇÉEëÔ©›”ŠR'†­B%'‡îZq±3ës“®*2Ó“·F¯¼ó¶¸ß ¡ìŸÊ»<ä¡ÛÌ·D$å³­íf_Ö€@4¯Á’½Ï(D3CƲ/•0J½ªÞ\NìCgû2‡Â>‹þê“ùS¼è¶É(m¹Ò›•@BZÚNÇÀNe- Òt”éÝñ.ßy¿ƒQ2pƒ9u¦†t$¼êý¦ßêЦê@‚;²7û‹õÞIà#f"­‹³ö=ôbß=Ù×7:…èÁÿ )îà³QzfR¹ô§ø¨¼±žÛ´ºS9Pmuv6¦ó}JÁÕTè9dÚEÁQnÓzrIüÒ•Õp—Lû\–$ê?¬Tϧø­UÀ£ngý_Lr®9W /à´ºìç‡kã%zn¢2¾âŠ ¸Oé5C iÆÌ!m7ûú7RÎã³™_ÆÏÚÃæ]Î@Eé:ðÎeŽQ9ò²þ æCS&yßxGZó9[O|B—Ò_ß©½:vÔ }÷l`/|Àü¬–þØæÙ? €4•Á8Ïû¬ÖîËsw‘ða佤hã[ og ŠÏïK_¸B½aÄßÚ2’ŒõÑ>‡ pÍàT'@t ™' ¯UÌÊÇ¢RpÝß©…¡ïÈúþ—ÀÒ%¯0•$(ËdŒ+m½YyžÁa…±Š¢ BðZ‰æÃ3t¡v R/Óî¼XȤgìãÏÿ[çÕº]µÍrΗ ¤Ì &ÅŸë9 4ºBí O"$ @_¼c ‘b€¸ÒjF‹£_äW¨fU$äæ2v8·“9ÖP¯½­+`oL«.½š-Bg€‹á‚f}ì’-Øð¸Û*#¿…Â=îöšréntí:¡£¼a󥛫‹Çµv×O¸Fñîº_{”Ó ò·æv|Tîö`Iè¯BN’wP‚Ãx2AçÔ,õžûõ,ÔŸÉÇâÿ’€€½³•Æ-Ǧ“ŸPÔœàTÔ/õœžƒÉ•H˜ýžr©1É_÷7h™Àž½î“ˆ/&\^M˜<6#ùöÞ®åÁºûkžõ£¨‹-ÚõVµ½Oß=èC–Kq7{H['ó8lн×!ûÒ¥Ç+­TϵÙC§’w"Éäg Ôýw˜Òu†¥Ð®Zªx‡˜&N°×¢?èó»;Á¡þ"‹¹Ñ7“á÷:‹ocÜ„º¹h_SB¼4‰†–YEB}¿2:FˆaÚ[ö™Åœ^˜èÃtJÎ0oM åÎÓgNÓ ‡J Lyœmírèü«Z7'PѲUû§Màã‘a/=§ oU”Öý7ïHÌh£Z MSž£ÐUé~š àlQ¬4¥€ï8w AÉÿ‡ÏHKôoŽîÈâ¡—Ø–(²ÕçhºeWý¯¿…N©&9ÀP”ï‘ï#¸‰„ZwŸ'"Ùô&û³Âx|-D†dðC©Ì„eÁªÎKw}SÍx±DŒž5þ˜?‚XœgYkvÉ5 ¦<5Á%7*Œ¦dçH}>]X_.˜3nLGǽ¬K°U¯ºÀÏcr3¤&^ç+Û×îŸL®ä'"Å ²%ïà®Y ”—dÚÔ•:¬zâ]Èiç¬#ÜçTM÷q¯ÖzPi¿ãvãFõzÔ³&Ù´m¼drBy b°;Km·tdXÊ$f¦ÐꆆԞÚ´˜ó Wgn×EïÈ*û‘û °.Ï¿no£Û47¶)Oµ¢ >q"8åéð4¿tcDe«Q¤ð }¬ñåùŽ’á(gO„MôñyÁWa †&ãÕ¬òd⊭ەMŧµ éÈwþHÊ4`’¯O~À_Œ¿8¸LNkQA8Ž­›ðƒ2FŒ¾Qß—‚Cø÷SÕI ôQ¦Ìü "–¶ÿê €!%kãKn](¹7ß O›)ÛÉâ™]ÁË´ ™9%I»"ï:XœyêmÏ·¶ÎÊÜ1Dí.{ç,[6œÆç. ²_o±à÷T›»;…EÒdTa ‡qÑ©WšeSåÐ5AŸMK®tŽ}âAš¾•œ/b—"u@ˆÆx¯{ùÏpýs1é.lõ „ò&>Âí‹BrùMå¸$mêKÖ·çxËjæ(p„k5þ’€€²þèÔà5pâ|”P1„y›( ч¾ãóâû[ý#Æä®JȾ ?ë鸾=¡ ¤±ª^×¾kPa~ÈwˆÝ¿ s c‹zÎ?m=²´P›‚èX-nAbÌ»öËF øTgÈþ=ûZ‚÷Úâeƒ/ _…ÚtašàÇ@­Õ¬ûJ."\j£°&Œ²™ì@¨RtÒƒRÛÄ?7¿bÅ’Ú¯v£MüÊGuDµ^ïb˜ù¡))ùf^5N™û¹Í˜vÈJ½ôaÚäª +Õ[½é}ZIßž%öo90J¨]ÄŒ H;_ת.¡‡P­p¾²]‡POVÂ9>“¨è¨&|*.+D]„ ÿ¬ºè½ZSQÔˆ©AKªpÀñ ,²°™?©èåRPdnÁsi¾ƒVÛõ$†—C—š=¡Þ£Û>5)³7^ºP‹("©Ašóbl)+‘ŸŽÛ‰v>Cw}Põƒ†Ü–: x.§›NS¢`öéúRÌœ?ÉËýÙýn JM«_Ý…¹é8IÏi„ie™ëì-[ ý v¸A–{Ã-B5¢?ñëâß»C³ÕQQaÉŸ“çuæÒG ˜UnÏÓ­6 öÛ9ÜyA_¢3¡>Ü7hm= 8ais#“»¶ü"ï(JËÛ‹]<ÛD÷µ-·u€•ÿ¡ÞUÎ…ƒ´$LÆPõ—‘§Šó_™ˆŸpIÕ¿{A`ôhëìpS$¢ Dìn »._W“Ã[H#s!35R›“³ªäìokr˜Ã m-Á¶Û¦ƒM“h¨Ö^ª=b€@[ÓÆ…¢ãpg˜Igº àJ€‚lÝá­w!Î,†7)®² €_°• ì>ñÐKZ-,;„ÃG)i;LÇtŠû|¹¬ BŸ»=¶ÝíkH˜ƒ¨~/ Ž qšœÒü9ö î%¼ÂŠÊ-޹ ß‡FPv%,ïJÜ1 <.¬k³:óøä=E%Í/ ÉåÉØ—åQ7Xñ+äšä%†©‚yÂÀæ>S/¾ `ÃSØ@³)—-Tvº‡ß[ש .¬þþž[©„«T”|+õW²o0{ñPå„·j¸ìW÷®¥ñ[évâÍÒ•ª1³sË nC­XßüÐËLêK¶8N7™£çz­ïÙŠ¬P'×À;˜’€€ÖRdÛ Œ#Ä3›½ ÕhƯËSÁÖa]UTõª3û=û ¥ï˜âžÊ=¶¤ì6:Ÿ¹²¤¨.Qá% ‚PP‘‚Gï·Kñ#{ô–e›¯´”ñJKGRЖcDþ†P%dƒüé/À_½$={†L›¶½T—îRW×Ô¶ï›¶žt¥2íÚ~ðÔàÒÁg2¤C‹4± V´fÛá'`.¢ÀÞÞ¡Úžù§RºâvÞaÞëºIIøYCg.³Bùø ÿ=÷f&b˜õ`¿ÅåáÌúà Ê%ºÞéÞymiÜ-{A'»C¯ãàe[F_³gJè`HZwV?]¹²ˆp£*$ú®o !Œ|›’Ûéè‹OR$wÿDrÐhÊIX8y&zŠž}ýù¹û”ïujœ´¶ÌP’½8`õ·ÝWíÝfÿOü.í'•!ÀJ³éCR÷þTgÕñýç¥FQ1k%hÍFóEÖxæ6é1]00 é‚öÃù—@G=ÀÈÄ!ÔG°^vèö)ød¬›ª°*’$5÷_°²È¨â±ª0b³\çÁì»ñí7£ªÕôƒ@ÍïE…¥b¨Åçj2{˜ÍØí«rp"08ܪémÞÓ"í¾i§Œ~eü€°Ê=`‰=BÉöC†þU8B;ìc³l›i± iêàøj2ƒžW-ú÷s‚¨~VñÈrUªlÃdõ#@Òýf/r`¤ãOùÒ²9ç·W3ñµ÷Ó…펧B¨ûFe¶\ æP·Ø ó8 Œ¥´­-Ön½Õ¥p¡CÒ÷Aä†,µ“t(¦ßlcµÍo¹8Ù}?£ŽË¦! ªß3é۰ƾ`Y0,P©XÅï"‚/ÔªôÛR,Cøù‘£UZ6ѦöD«³ê]ß‘3Ú¡m©ºÓkw*à‹%ÞOØö¡Pt côq 5©œ Ôã½[ñ©”¸z¬Ç Q£à>–Ç•«Ð ñƒaTÌ.zŒÑ,'B fû«§/ãN‚·²¹XãE*!룇o|Ý*uØÇTp¶Ä5º>õµ"ÂQg[‹=eN¥Bô馣6Í ‚¬ÓíŽÃ›02¯ 粊2ÅÊ+$÷æ«1d!Ïá?Àí}nß3ÆÇx](º–¤é¼ñ†Ûà» Íô´ºfkÄ‹ÐgnÉ’€€¾¿6¶^=q¡BëCß JY+ÉBg^Ö—7 U#*`vp+«£J€„-UeÏ<öñ„Ü úBf–*,¬Q†s킉ÖA¨ãû/µ&é’œƒ}ƒäõ>á"¾|¨*w›OÑÉI… w·N‘»Ý¥[)¥$-#¯9zÃHŸ\äKýƒùÜ }µb$ ¯Yu‘ÓâZ`^_P öÕ%‘±åi¬ ¤UM\ ¨ÏmVÖ®–0fOKî}øõÿ£'oIÚQ¿t0Áz8S#E“9UÇe ðsHc IE»pwZ$²„Dõ=Xlý å²ÿ«r£?¾íP#> ÇtÏAPjdL e›-ß·*dBÊdwT4e^œO>€…#’üʵTÔÇf ‹Îî)—]…€+y¶ä‰}Uí°ÎŒ¯Vàø¬3.xôiîwÍ’·®ò(üsA Ó\}QGÕâ:öOm3¾ â¿ p[Õv»K¾°Ó<8¾t¬J]Ù_58;šF…ZªÀ´ÜM#šöª€¢Czûü­ôNm6·ÔܬȻsKT¹Àž/Lìý4/îÀrÐ-: A‘´tŽ^©|"RHèד°0Õ7-&û7$/ôŸÑæí¾«ÎI\ \š ôs’WÊ1X’¥'€”êâ+Ò ¤‚ÓíEöþ;øÜQvÇUÃì†'Ûÿ¶’ÔòlŽñK½‚ô%Áú×ϸ"{â<<óï°<'Ho`W†üë’Æ¹¼?o¼€¥þ’]À’_·þÉÞ”Zäïç—ù†YØ44:!>žË>—V¿“´“ìpøR2¿1‘ ¬Wn×üßXlp.xÜÄ8Öò˜ï¿ùH´ò”Û Ý3\µ#í20©¯ Z®8{ø…žÚcZhÜ6œ ŵøøá1QYÌtnK99á£DN¯ •5 Kgÿ×xÞTÆßÁØO%Õïã,·98p†A«1dîí¿yÎ.SP%|7[Ü¡(. ΋)æ8ish®#Ûèá…ÔOªlÝHµ+ˆ“›†<¾L%âEÆ Áë;"Ä6U7™*²k „Ì…ôÒO¿~ΕÀ¢ .jðíÛòú0¾4B»Æ\þÂüóœ–sX™­3¿`ð -IžyQ’ä&Î`ûèEÜï¥#:“°©¿u &’€€¤Ä­šjUdDÔÝñ1½0Š_zôÝ¡l•Ÿw1ª¾ pN!x­_ÈâØ²ä¤V7ʜƟ#%Å•Û2¨¶S<#e÷«ËÚ²×uOô¸w_iºÓ5'›">VÂkÏÖ ~2|ÔŽ:c•½:àÄÓ¨“§`ŽêÓöRÑ¢’Bï²IóùâÜ‹«ü…ÐÚ㈼£À41ë¯D¾¦%tUEFÒ«ÎÑ zSmÐݸfïNY‡3&¾^•cÇ/‘ü¦§I@ ¼cÝ|‰ôºl“tzvq7¯õiE ócß $M+¦Šà„ãêÆn!Ò+ ‰C/@3 ÂÖq*8I½¡+æD´Ñë"ç;Úe î‹rºãg ;¬ÛâFä[½çÀ÷¿bõÎç@ä)¿û¡'#·ÒÒJ?ÞE1\E²ÎoB…ɯ{ÞVÞåT_æ÷ ©“ØI”é ¨ûJ ]’5ÉaÊ#§É¤juBĤ)U9dŸ: ÑÂÏ¢þ£¹ÚEÆòV^ב8gú5©}„ø,”˜>[µýÅwÆz LϬGÞo]"k5àyé°Üøtìðï&ÍuÚ¦+>[xX³·Z7ROsˆµY^€ôz,¿YSK`¬‚¾ÍÛ25{$O°a?£`sSð§EoœH Ü\ÁÎ3ŽJZ„,}ê¹UÀî¾,T5Je‡mR?m‰–Cg8þ»d¬nì”ò´“ú:ÏPucœ=´Ó oô®@ÅZ¢r¿XyÇ€¿dö¬#¯jýæ­ïL¢ìúËŠøVaàeÃÉŒÕcAù¨‘«j[SJHÏT•~\°’G«xAYÁ˵H÷Gž²(Ñðô‡Æ ŽLmh¢ð½˜. §@áWz×_Ê{_VõIƒ PSüdש%Üs©³Ê2L‹p"<¥´ùŽá0 bÅ¢ Íné ©¯šÔqQ[N+¬¯ñêJï]•ÕˤürHîµá£Šl‡¨éØáK´=~çIåωÒ\¢ZEíuŒÞþ1ò¾:û`šU¤·G¬j6äo[]‹ã‰B3—q+LK¹(ßã<Þk(쫬X©9‹N´Ç…jƒì~I[ }gÜ-…{E$¹g0äqב¿¹²ÆG0¨…«”˳¢BuF,²KNìIè؃8 Û„ ÈNSáP ’€€± s­CLy:ÇÀjˆ}ÊSzj®Ü;ùR+§’Së,¾ÁLæÈaÎÂÀÁâJ?G¤Y“S%½º•æç°œ®V«šÇ›Ù³ÁOÓ‘†.ÖT*NÍp ÖTËtŽ Ø;ˆ*¹ïÍÂu,> šÂ9†šT“¸ÓÎü ¥ýÈøuŸ_©T@Ƴ¢oø`ÏJpWT¦^¸»º‚NéK-XÇ$ÍW9Ѐ5H#tç2²æ” v0áqÎÀà~%R”ý³øäB‚ª|KGÅ=åþ›z}ðT[üŠ­ï#ÜZ© }U <O}6 òû«å=kø[°¢Vu’×/@m‰ð© \ªÏ8Ÿ 9H®\Ï#à†ô™VuqÎØŽd’}EqÍmä×u¿!É'u3ýuØÜf Üä´_¦”Uàã*…ÞçÀºŽëSãÔtÍìKHáƒöó…GMb l=pCawxi3UHSME]ëÏÁ3Ìý'ÐÉÎÜMža}¸J~x¤¿¹twÐhI˜¿-É ž <)¼—êz rcêÍ'‘u÷ÔÎÔµ!} ¿åka2•}åí 踌$B}š7×ìÍûγWN@é£>ÝúóÕ\ŒðO‹ù€é.’H‘ò¹Ác2÷ 25‡]Q%ÍOÑ\xroÅŒ#û1²§lÆ­.JqÅnÒ‡6ö«ya»Ù†TK—Īl7·îƒ-ưK{o!¹â&Æ  ¼AäåE}ÉÑmöx{%ïÕ´]}qTŠ{tqË›^ôkByß¿±¶¼wnµw+»Êi'¨€-‘g ­vÆŽü÷’0Èá5gxwb8Œ™-Ñã©»¸ã.;þLrY3 È*Ð^ƒ¦–}#ª YwTk„}¤ &$¿_Á~ëËw Í9ÃÈË \ Fj0ß»ö‘óQéw;þê30{MÈpâ°Ö=`õ''Bèp¯ ôš}·”ÁÉaøóRþNmðö"Û2‰Ñç¨Âú‘?z´é¸°\÷ï×>O"Áú+qXä~) ]*:m)As¥NµÌ»nŠÑÀoftOPxãáø©…p4­ps;®éZœ©bòÿú¿s„~¢A ÿ¸ëíÝóœ—eÖQ©]²’Ö¡l“AÆœ1ÄøÐsðv‚/ÒaÅHŠÐ+¿ŠEÄ—.*ÔÕ Fó•ľy"ΛG‹s£ŒYéÛOèî-d’α  7~Øc¥ìr¡ùƧÔ5ìž¶AÐt™öˆÛ…å¤ÞÏù•·¸¸œt“ ô#¿ ßpwÓã­?‹j ùie`ÄŸJ†]£j;¡¸í ͦ1gÕÑz¤þõ ã’]©gL&3‚_ ÈžHU2±0[­ÍÁ­Â]1g)›´4v¨èÿ2膮VTÀÀÊ=ogæÖ½½Ã´’¤2ÌTO‘`v]5Ô„æy˲zCpG ¸¸ÄHwðWxAÌkZ­JlÄŽX~úÆDþ(ohÀ ¥b ™’€€§¼ûáQ;ŠS÷HT2õŠœƒ¯bN‰ýÒ`Ÿä¹{’H~JuÐ&{ÇrKV“Ÿ¤­ <¥õë``Ë1ŠvBËı¨ØÜÏ"Z¾™”•ÛÆ»^æÞ–Cg¡ÕSW1Ë¢{bŽÔÆ Üöþ2£xnˆ\ÕìŸH#,‰Äwê{åZÚ‡ž}J¤p¹ID› $#r@vFYrû‚ÁéS[ÃÄ>\^dÅ®^5UM:,(Í]¢â›•(|»Ñi¨å¶#Jü\TS£f@ܤd¼lgg7¡Ý±ôGõ£@!LÛ)l4·îËàµB#bˆYéãh“®AKßÅ®ñùßÄS‰jGC²‰V%ð°yúÈÚŠÚÄ@‹ùÖN>2k¸˜Á˜jš ÿ1k^¶¥|YK÷õmù+’KÞ¬¬}lÒ‚A-üó¿¢y6¤âü•À]qkÜ‚ £Ý®?Ðï9|Ùhã4ztwPk$¾ 6O–òJBš=ªŒ£´µ†\Í¥SümPŒÅ ¢0ßdK[w¦XMì7—`ÁÚ ×&̾à{QC‚Áp_SDŸ£ýÙ›$d.T-9iéoš&cÒ }+ÙŠ¸ÛãÀ±’ã %È‘uœ‰gƧNUÕ,FgõS<¨Nózq·æê…µÀE›eùÜ‹Y¦ŽË/¶Puþ^q~}lE%Fw],MÀ'ãù=§ÿ®Û7¶™ƒD+Ù„ðδOO1gɾ‚$ ù4·ü™Öú‰ýq^˜ˆ2x¡ªÁ¹íï† Åz‹®¤ªHݧcK¹Ú.'9[;ým”-i·½«ð~ jš´[ãÕºùTNŸ~ºÏ YÒrY="5O¿Å§X£j5jJd »'¨‡ž¶òš\êÄ$[Y`9ØuÂ/þ;w…s·ryîkq¤ïIÖQïÓc%é7„q"W­P‘ »…ãr³óÃz}lMGë_³á¬)Îp4JK˜L,Xô8ÒNå)Âæþ&žÚÂé1ìñ:שÀÉ¿!Ò^{Šd¡{Iš¥“å{| ‹ãga1ªËjg!ƒD9ª¢Êc{Ôwʤc0ò‹ ‚Э¤‹1jŽ…œ„á#ÿéÓZ5±V õ+¾³Å ´+±‰@½$AaDƒ|7æjŸŒÏ>G»û.o×’€€ªq¶Þ!Ä%ƒ?"–€10ŽUºëq¬­ ^BrK£>/¼G[,¿Ä¡Ô$_@Rå~À‹K£alöU…çÕ+‚ÔÐFk/ ÿƒcŽXãmœÕÕ¯§Xòþva›Û0)Ú§²é…[n2_s ÑFÑPW¦߸Íj¼¡5[Ïð½V(íµný­„ÿ=²D.ëÓâ’6ž bm9;KÀ„†EÑØÿÅêhñ‡¢<C0H%)„ÃÑ,Ù&~oG\Ýa/Lè§³Àÿƒè_Cë¯n–vFCWºkÇsGûr/šômø©Î/A è Þ±ÓtFÙn*”v2ïÍc;‚(”œGÙÇ+Úxà›2ÉsŠÁgŒ8àÛpPNJ*¤ tËwGŒX*%w´\“ÁÇ„)gwj9‚ uä7è“hÿ{¹F3¡ ìúÕtœ‘[WÐñ3ÿ¾Î6ý $#ÃI9ÏËõ©Ò¦ ¦QõZÀÓ8T–³¼DË =êj릎£ÖïÌ>À@9­Ù*g¡Ë±b s´¡³Ê˜x¯$ZÄშ"¹q „îñy™`«Rnnšuy·}¼¹”ì’AÉwÞD^ÐȾ$î…ç–d[[ï„­ÓQ†oÓä§6ÒŸ?Ôª'ÚOû£J)rÊP‡aìØy±ØU´sr‘˜éž…eáxÄò ;šðJ†éåÝC·ÁÛÁËür‚Ùx ýÛû½îDƒ·ŽÀ}ìrÔt'Aî)X•ÓG“ºd>Ñ)§3i4–ø¡úv ¹’%Žù/Õ¨ ÿ%%ÍÝGCšß€)Ъ:U ê0•ÿ<ð÷q#×”;ɲ³ãíÙd FB_¡®0!:Ô›ž.Ä"!¯ž^hÃÏ~6Oeç+/ Ç/“<¥EÙ”*°Zqfek±õ=31&@ÃTi!ð°Ë1˜-ŒÆ7M|Äíxz)^aÖþZÑè(Ô¤œÆl]©ØO%ÊNnkA­…ÉV¾ ÝùÌ|·÷PCEÒAT…?aqñíx“>ûèm:9ö(I!S)^èÜUÝ:Ï•VKM%fZU âÄŒ2æVÜU±Ìº»2ªÐf”OÓã#ݺ¶‡¥ÌÓ;Â&íF=ðúì_£È^ùe^W‡H-›Ñ´|£ì}ˆ€áŒüÜ8øôý:0u5òmdòy[ì©Êj+Wêk?lXS¡lEeV#ô /¦Wuþ<ôÍ$~8¼"–3sçnêÃÐÌz0ÏÞ}8ËÉL¼Ýö“\Zîse§Ñ …‘;³h l*¡¸9¼O0˜Z~3°h=•Æ/ÉŽ_¤¢ &4çÍ#m…Ǥ]¦|h!uˆ Å3xîû—8ãá…A3³c;# ¶ÐûTŽ`ìƒaM.Q»ôRÀš2/jÿÖZoÌ{7¾îÑܶ¡ö¯Š{x¡ß¾±š›å‰$°¢o‰t§j L>öÒEBŒão¼oг 1Lz`éz2æÄ8…Q&ÙÿÛâ8¸h$ú¯Ð³D‘”@.T˃fÓY£¯ÂäÑî·u¤$³Õ=î©Ä:¾ÛÞͼkIòN ¾‘ÐШ¡·äéH™Õ§SPFk;ÎsòÜl§½O–æF¼Vô•¯ |6´3¦u’+äZÓ÷3_æl¾Rk "vÕyÌõ÷D‚YF´¸üØlÒ(x§4‚c"ÇU½¼2…xyô1Ad< àS+îú}ÊGÇt‹ÅaéŠö-q¦ ÇG(¡ù¼³‘ßÕv]î–"ÿ4ö½ùŒŲ"ÙîÜKãe ~õÄ¡`PKðÁ•ʺ€ý$…Ðù´'¾2À¹YS'íäÐs$ Ë­ÿ~R[ôÌo ïjÇPñ’€€áÞ,²jtèÛ]ð¯æ¼ï?â[XLPKûOÎ.:½f÷ÝXIÀX—¬Ô¾._™¿Ñê!Oùä4 å*é‘5•QbÙHãkl{à/¯× 4çÿŸæèžóÑ¡(»j¹"š™)æv‚©j»5ŽŽÉáõ(þ[çTqYh 'Àáä–‚œÄ¶ ì˜'‰³¦Lºšx>Æc 4 ¯ÿ}ò \ ^Á¿õð›/iÑòoÄ‹j°FÓE©Y×%8Ôß´ì=Ö†kHôÐ= ú¬©z†W/'ySºøà|@\·ú!Ý?éf‡pœ³®ý2à¹_žß ¯òú1¾!O˜Ç Ït¸)V†ÿ$i™¼¢Šà½Y‰§Cèíüµîç{Ñ©  ëØUž"ÂòÓÏæ[¡‡àü ‰ë¹í Šª°53ÚêLSks¥c óê(¬®ò¥C°I„Ý!™iy¦mòû¿.6Â!³ÚÈ£H÷û´ƒ…Zò22¹²î_ãQf©E+áë\_”èÁ0hÙBB gªŠ£OÖÓ4ßõ Ø% 'ÕŠU¶ªQA×0ÙxZAZd?_ Ó4ûÒrpj„³ Í­ÃþHZ„›ÁvâY.YY·ºYçËÆA¶>ý•ì'É£É&Û(Ÿº³Fba4S¹¶×ÒÉÁGIa§ ªÿ†èù!õ-ü$ô2‰]¹í:¦rå–ÜlZPiÛ¨ªñy@¯G‚§¦$ç\ø`9ÒeIn;ćŠy$ß~e©UàÖÓëÉS;hT9Ö mÌºêæ§ùFúŒúÉWu£ý1•X]$x¶¬9üá“KegׄîùùùåZv/Å6ÛMz]ä‘$MWOB ò¿&àÐ_àÝÄra,RüÍÇ ŸCÆï?­aˆÐ¤íz.Ô˃<‰,)Zök¹ƒÿ ±ÕÁbœ¤¤¿Ã¦ïD Â:]Kø‰‡üZj¸þ9ñq‚‚{Äþ@Á`_ôÀæjž xÄsÎ.‰†FS²h ®Wµ`mK'g»L7fX¶½ôdŠ Oêü^<€ÏŸ3 »ÜÆß«ÅhÓ Sp¾ UD7• * ]€ó¯b#³³6ö·§¦tTú ¶Ê1z•Ý[+xCáŒÀ‘¤çíå[¢ éúNˆ6›tGð¶þß@=*3âÜ\£aÄ#!éª1’€€Êp%\.|j<¹\1p’ÁdÈú=&~­kµÊ õLiŠRGòé–qØ­)Ô¸¼cõ tÏþ¬ÆÜVÛ£æ-§'Vﻼ†…ÚâP#v媬úpŸ¬ÒMžmĶóë‚Id§]To*øÜ¸&Öë*ÛW¤ü‘БáòÔþªÙ¸F%åñ~7Y"¶Ìàfp`º{hV~ ‘B3¦â 0ûõ[÷‡ùÎ+i’Ùi)“¸azKì§üÇmíTäP;MöC{Wo•@¼ÖcâÄt Rù}t¥Øõòü¹¥+Ù¾Ðú~kIeÒ¨NéšN˜p»"(;9¸²b)àÓ›ø»3˜e\9«*„õz‰ÃȲ–Õ1såƒÛ3Ïc/ùÜ17oT©wxÕ^޵~"«7ÿ©‹#3- &I‰#!oOÚeˬß3¸ !ñÖЉüQ}^ªki)MtaeÚ÷i°À½îŠ“\ Š¸ âÓ˃YùVK3ôÁò³?râI :òk[Z àÝev ¨ úaÉÿ˜ÎP,䣋ݦ Qd aSèh#­¯ÌVƒšì P@(Än>AÆh´±Ý¼90!&ìë­ ÷p²ÛÄay?¨P‡ù^ÿP³Ÿ«¡Ì³ì8ŒdnÉL?O¨oR#7…ÉÄf/ÇIdR£üXåwn…R›‚q}ñì2f¾÷©‹êþ~\êH3=. 5´ºkdC‡E/†ÁŠèaþïÌ3%ß9 ¢¨8ß:ƒ{"ñïJqÕáÀGUj¤™ˆ»€oæ:«HJ:C²á&ÖÚD#íŽÒ·ÁÇ´Ça  |јÚ!®NݳåáØ à^Ã¥4•ÅþéJ#í õ»V2Ežú,ÛøÚëçFkê<€&¬ =:th4I϶²1¬jû¹«TPW ›2ÈWlÉ ¬…¤}jWS­Ô²ÂG¬@[Tû!€€ao H%Ønxœ»è0è¬FUôGÄÐ~*Œ4)íÃÜŸø&ò`Êæë)©m6š×™_P3YEùØâRûÌ[œ*-¿‰¢YW” ,î)BÓ> FZ'ÕYB¨Ê3!íºÖƬŠ}¥æï´pvï*)¤D(ú&ó4%Âcb?“nÂ]!°N¼ÈÙu þ˜ÔÙk;Q—ªwÔéª1|Ö÷©•á´P×ËôpâÍ [ÖƒÐ+ÛÀpþÑ Ý.§Œ-lõ"UO©w|èÜCÎFð™úŠZÇWRˆHÉue.Üi¼„­’ ºðäÏíxùçú¨n¡½oü¶èpbÔãVüûÖ)”磨Šð%þáŠG±‘]åÀœ’è³6Èæ;ïF1CZlb•Ul™¾þhé<]‡ð¢G++EJ¨÷%³ õtžè›{Œº±ž×/0R<üF—z¿M*dUKB÷A…¥Aò¨Ô®DÅÊ‚L‰ÃšJœ£æœ¼¤MêZ:tÃ?\ËÒšKÞXÜ\6½Áüâ„u{{ðlðÖ3L΃ø†a‹ŸÇ1é† !#O'}Ù×|tôO‹«Y"wé`Á6Qa*ØJg]led–´÷³™#™BäÏgd^"rÅPÒ®ˆ·µáÁ8 o|2nüÁk'Ÿy&¤UðÏäíø´0>Í t¬8ܪ!õXjh?’>zóZúÿüDíƒ{ ø9K•™ÇŒ à6<àªþ‡Ë Û‚{p⻆¥Ó’hÿ±k¼Šéµ: Ú×ÖN¥…޵â-é…ᓜävÁà>,µƒ8ßv¶—Ÿ R;Ú÷_Ìì(_$õãøþíGÀy +3óV¥£Ð‰>óS #3a~cÃ2U"å_A?I3ª)o•…8ôš¥ñ#ù żÊ®J pzˆj]u~ÿþ=ÖçßG$ö㌉+YÏ+,å9¯EÆ8Yˆ}’€€Ý.Ë‘´yÂ].Ý®iý'ÄüÊ>p K‚ÝIo~q¦%–‡‰}Œ)•+Ï–é!~o1ÑP¥÷©ÉbrshžïâÑu”ÅzJ Î 6SKÝÉ‹¤ÌcS'[ã/Ê( aoš"®ÑòPå³y‚*ª2I¤šZ×N}]½„)6-×þ?m)QÆ EzÌÌ©fxl1´gµ>†~‡,Îý°³èøµ„ÌOUÕïìl&«=þˆDª¼ùŸB—%HëË„kvPŽëüR[Ah{óNEßÓÖ¼ k¼h£g"!„åó¾ >*ý²ŠFþºŽs-Ÿ–[á!¨{u϶±!Øj¤Š¬©…bÇØu…¯{È“-XUöŠbKR]Q²Uñ€¯Tiƒž$'¾•Z©‡ÀRLHb$ÉÊîüPæíVWä14×H2¡ÅðÙÆ…â!þõ ,¦Î¤ä»<ªZ£'í£üîÜ“´êF6 ×Âd<ØßxìM‡—׳v¶°ºùZk›ÎÀÉP”Ù»Œ²:†DA9§98¼œÀÐ-ˆat…ü XÁÚôH•Kµ//¶B’ŒF»Äñ.$2raÅghí·Ñû >’Á¢ ¡úí^ïùüGzðæ0óÖÀ1žÊ6€w½¥¬ ò-Í‘`HRr\ðjáÌø¹ú\Š¢Ö¬_(ÛR,˜Âó ˆËïZ@hÝ øqX^î‹ÝeÇl›º ;û£ª\µüYAõ¤Ñä™–ø&ë·‡›£ÿèqøâ#¡ü!…Îÿá§|Á{J|wmHrêú¥¹¡ªCò _£çÆW­ yöç<¬ùÖ¥Šn™¦zÿ¹2€ž?0§"ÀèœÚMÀö`äÁ‘¯U|ý"l`ÊÓ¶ßÈÃØ_3ÂîÑ–¢fÃýÿª_Ÿ,JÛ…x Ôým˜¬ël÷ü`iÊÂ]Œ<¡YB°ª¥T(ú\:¢&¼·ðp”\gµH¶6F£€cHV[ì瀨fñ¥cšçu‘­|{8ªJAÐÇàì€}«yÞ”>ò³“‚>Ï£™£>ÐÒH™Ãvr¬ñâ—|,àæÖ@’Æë*§é&ñ¡7åÐàþ^'oLÛ‘n –!°’’€€Ï=#çª.ë>|Ê—Rˆ~ÊòWîi3ÖºP{ufì÷Ïôœ³2øu%ŒhåîѾ¾Voðδ~Ý…oçJÖ¿ÍIhŸÊöK÷ž3гéñ€3ÆÁ_<’õSeöÈõFqðó×ÂdŸ•¥ ,ùm|áHü¯¶‚HI´YÇ“vé³BéÖ=”vŒP ©v9XgK)ßml%ZÆ–Å$Aò Ä¼¾»–aí€ìÄλÊÜTu}èÌy½—YVÀE±2eDF醉J3æÚUÖ•ÌÌyóulþtUP=÷q[®Ùt‘”4Ž(èƒÅLúÑãÒÞ¹£ÔêèÉLfŸ¤‡ö`*vâ€1b3mcOm˜·ëýw¾Ì7»}ÃÁ0¤–ãŽä³MAAB[`&6B!’QêWfìºÍzÝòIŽ}ÍÒùƒ;z(”š½ZiÐõikrƼ¯$Ç24ïÞ¬·ºžVûd;͉¬&]íÉv…ýìa— ƒ+iÏËí3œ¿%eäXèuÉ/¾AŠèØap¬ É `þ4PèÛbýÍ Öˆ¾3 ½Ôý¤`ïd¨xïøÌZôì >*ɰ¨+‘£<¡:$×ôù¾[H´m2úÀÃg‚—èY¸‰v4qx£1ŽqËÎkŸR0Ø“ªBê“n+wVWwÛVeÜ %À[íi6G™eù­Eìc±gA—Së§k¡8 ÙœÎòbkê=™È²»éËŠ)8:”ýx 9ÊÈO+¬ËÛÓdú-¿]÷sÆé®)F‡‡*K-²æ;×_„Y"EevÀpóQŠ$v£7-±Ÿ3.…ü_]—]5©C¥mq§`¬ Ô|º®sf®±÷,ñºJŠ­ QÊ!ÉJ©µÂA?< ÊìÜ'¸-¶â#ýò'Ü=<¹€†Ò–ñr­ó#”Dñ@rP†õÎoô,¿ÿb¸…ƒQs0G‹”Õý^ó+ƒêÛ¹$J—ã EuÊ韴„ƒ<ÞTÁC¯¬áìøÝð/3ùNÍÂcRô*ÔüÁÌLúO›9­ÕÓ7&L ïZBÝOMÄOF‰A^Ë—@ßÔüðê Çj~þJK¾nË:ÌF4iúù—NŸuvöé/zÙ`öÀ›4yÕÍš?¹âYj€°î¾”«[ëÿuÞzŠý·6Ï´¹âëìbǺ7äÞ’€€ßõÀ…½—¡®Ô±ßo¨·zaÖÍX½ŒN+6Ÿ¨~/|‹m‰PñY¸<§?„¿"Õ÷Ý‹ÌQfÕ-bqTo÷ÖÜĨùj‰.ië•¥îlLŠcž_/"|‹Îìƒ{¹Öi»ÐWUDµäÝýÂÛ½û*¬µ’Mö'ƒýù+=$÷tJkõ×)E=Ü !U/®U7m •´ˆ£¸yûKKsÜ1ô¬»´gœÓöŒ€P~<ȯlñß—P|Ø6Ð d÷•ĉN>? ]E—&‹Ü¢†Å¶.‘•f3toªådǦžm ë|o}Zݶ €™bœ{ •Éûš-*ŸO.Ÿµ•I¦ó±ÆÊ4dà ºž ³–ìË×:@S³ÇMOB`m%å ÿœE=%ëÅ™pøÉLôõÒ)(Ow š†f¹J« ÐO}L£Ë¥îÕkÚoZåPê»®[#Rh„?ñá®aôÁ¹ón”Zc ˜ú)kÎb¬'Y©Â«ÏÝ'æóæÿKÊëÐbá‚nwpf[»Ø¬Vq4¯ÑZ !Ä3>‰­tuwðE\ðOE)-K¨¦¹qíGŸ›àÝ} ã 4‰œƒ:ã7a{º“/@Á[4Ô–BZb"p ÊDÃh±Bs›’M2˜’¦ggÖY&«æŸû¼corhpû©nX¯¯oÎòŒ÷GÜ+¾=ȃ­®KÞ˜e ¢ùÝ@^CXÇémWØûnÊ’ûј|pÚG$RÎÇ–óí\©AᦀU3ö ó:Csë>¼ÛðOßþìl‹´·r§j.CíÑÿN«×ë½uÂVÑBú3¦ŽÐ®´3_ÕãÒkhT|2=±Uß$uõK2«;·ó~÷Êóò{Z>\‡,‰@%¦‘EaH·ŒÇ‚ÖÎéˆZR9nÑò Úº%AÖP2Ì@›®àÖU8ˆØýj`\7.ñRá˜WxßÞû9ãî¤ZÒã(é Uª°¬-Î]?üä¾~/R,¯ q9VŸ<ho³’ÓI¬,"åŠ2[Næz_ä‘‘Ñ^,ÄG½Z~UV äc WNÎYBùåŽÊ¢='_˜?¥}j&¢ïV0u5bZ2' ¸F‡ÆÐà%„7Äå »?ã«îq-ªôrªˆóYME–CBI±1Ó/8jÕ-"PÆoF’¦„;ßñš£\ Õ¯6Ò5ÍÀ¸ÙZ Oãè ojÐ…žD¤·¿ßù\öûAŠõ™3D²×ÿ\¬ùãCÃÊ6¨°êPËðá° Cï3\k(HL»¤§½/ 3šA¸†é¢±à‡º‹ÎªÀÍz/™&Íd¢pCŽN°è’z›[U­Þü«œÄ^†;9:.?5Æc6õ$–¡'¾)ª*ÉÏJÏ\ñWôtÄú¯Œ@:—e ñüqõag¬grõJqÃcWžìò,X¤^ƒ¯Š×¥Ä ³y"ŸÅ ‡7Ø0rÙxYme€Øƒ¡Ë­]è9?Ax`)I÷:Ö.‘ïÖ?uZ«oáéuɇªÖ-b?5þcT‰%δzÈ$Ý'üÎ˪é8sˉћê úøÕÿ²R$æFª‚údßJöPÛ3ÊÚ,®520D…YrÙœHüê)’b/“"@õišÙ‹g5A7M7¬hÉtØ ÷DÞ§u¢÷kõƒ˜,Ã3:Vß°«ÉÞ6Λ“êù‡]ûúÃJϲÖflú’§«Ea¹à‰b£ þ¥ù¦9éø(ÄDÜ2ïÒõ•÷8Gw»¼o“-cÝ5¼r9™a €Wƒ/¢‡JØc@9¤®ßÀç5C)@߀­A$Û µK{ÇX‰÷¢‡ë*§CR-Û‰Žl¾IaUóJ35–Üò=ÙÓoÍÖää›î>®]lJÆÔ–¦d½˜™IÉ®{@½ŠIùò_½ãw+#¡FÆ+ö»*#S:NìN€Áüd”pkíÜÅ-èÙH7E!猀|Š'åãðJJƒ%ÐQ6ûí–¼š¦gÉàÉ"•µêõæ-µF%Ìä$?fý-¦ÊAæ’€€³­??kÂÒúFg÷§ª8FåÇe¦ñÍý“„¤uûÐÝÃ›ÊØÉ« ä÷î ”Ä_:` )Ī–¶\´7U D†ŸœØãg»ˆªW7 — e›ÿ‹Màî>®,¨ØÄŠß>E‚Wƒ‚S˜½ÑlCz +Ș4ßB5뇜ú›ëÓO>C5+ ø ¯ß£ªèþÉM+U•`mF(©¿§¥üÄÑ80 ¤î+}ºK6ú›ªª±>±™)ÆnÉ÷Tƒ_»AL\ÈÏ¡»ð—ñIˆMl¼ô¢J£¼­oBbú"¨Îì¢É'‘¸ö_? ½W5Øó:ïÃþΞ¯‰.H%Ù (ÚžÓ% ÐGÙußÎõPe×ÎÞ³”vëj¥ j¡ËVç|Ä:¦úQ%B6dh?wžD@eQÿ4{ &)Kgèš“œBȰ6Ýœ7/Þ‡*ýH}‹À'¯p!1ÈF÷üãÌó>ÔUí1ò\C R ï ;û‹öû=w²}dâïϘK–®Ã²òëxvžëz%{üÓã|Ë|Û‚-C0ÊB“ë–~/ËV¹Žåä§cµÎ%´0f¸EÚÆÜ•r˜]XÁHÓ@jÏ©ªóïJ1_Ñà6´_ò—¬7T€÷šÈ‹AO–Š­h²>é/ÍæÆ”A”u¢ î܂̙‹¦¡é FÞ±_ÖÛÑ3¡¹O@¡[ÿ>æÉY×dÿÀ†uI¡=¤u~34ƒ\Æ›êPêÃt7py­Ù&(ZH”X ˜ÊfÎk[TxÖ_„ù`a^¤oÛ#ý~þƒ@Úó™€ém'Ëɑ֮| “seÖ'{µZ§ñmúnÉ1õ‘Äâr½µær>¡ˆ .ct> ª|?}Ê`üœü´Õ‚2éš[ÑöÐrï–Êdæ)½ñjDdóSpwóøs ä4ðCé„P‚×qóû@ò™o5Ñ޼U–~Èò’Ø|UiLîÅAçÖÈ“£Áâþ˜»B›Ežì9’#10’ÄRåúJÚ[ôååïê˜ñÊ ¾~Ó±P™¦þÛ£…ÜìIJÁÚ þo0Uï ]ÕÅ „ÆZÝ ñrÖJ–áâXr(êMñES÷cP'c—»ÉtØîb|gIåîï´Í² aÕbÿb\lµüƒµa¼8OvDqàËn¿&¯ÁFc&¹ÏóÄÈúÍG£¨’*qUFXùVŸ CÍîê?QÙ¥Iè¹5Þ¸Âx‘’¹Ø Ìfõ@nUœýó߯µÈ9” òI¦RŸ°*²_Ëøb]± N·Œ>/LŸZ¯cÐuCà]K) N.LJègáçZ'ýFî*å¼¥eÕÐù|•¬-÷;çðëàÉAó´(ˆœÜ€´fK_¾ïRKvÔ‹gêM$-ø3Aþã?.K#B¥6u h௉ø™ŽÎ T† AF~õñô]‘WG&uAûÚ˜ b3…œÐ!CÄ­ÚügñÁäL¯@O*ã,©Q£Þ{³(Ï¿ßt§2Æê>I¥„cKÕÇɬ9Œzêe ¤ÇD­'ÄAíÅlÎ>Ö©¿U`|zýf^{‰DZY"ö¾P¯r ž¼Ýí¬m&5ÑÃìVNö»{ZØûêfÊ!ÛWð!@5>†Éo¶º)òŠìR¨ïuåêjÔ¯Ô…d"'+öˆÿŽ6£™Í?B³µ[ái $Qv9ÍO•7õÿ:o?:‰uù²S•O@»ûª”i3V¾éº>AT¿?4øÞ¹¹Ðø¿~HË"pHç‚7Y}•AÚK(^ôþË9e{ÎA–ëð@É6wÌ„–çŸc‡ŽÏùæ´?`Škõõã®}¼3½fHƒï·@dŽI zJJ'ÀA ÁuK+,Ú|ÅÛZö‡’€€—TT믚dÁÀ‘íÑ îKŸ‘Xf›EOúeÛUÃõ§Ä³?­l~ †v¯¤\Ç@¡ylBդȔ€q×WðEÌ%ýΔ[–b–o}]MÂù,]ÇËÁÝJæÞ†œm3;0ÌW)ðQí¡”*¡M ˆ÷7ÊÖ=,.„`‚v;R XQÕvL«p@"†·{XýÁçC3&vÎ8R¤w*¾ÞÍN^6uW&JÇòÕÎr?IP¾+ÍÀÑ|öÌ#ÝÀøKÏbøç6 ±aÌ âS2}ÊÀqúf`e “[g„Û`»Ql°°´F„÷ìd!t"¿Ÿg®õz%>­dC”2ï÷Þ§yКÙÖoóõz!;åcs½ºi|šÄ@°.Ø¡š¤85ÞŸëƒz”{3¾õ6Ïv°xXÂGšŸS¢ìYÛ‚Û›Jq„ý›¿µM¸ýÊ%6ˆÎ¥½m Ž|Gš3<· ›ÐØ ÒßÕt_~Qº(¡ã =Ô¬ìžõL2Æ}ý`Ðôó¿U˜¦¹É@¬§Á¡hp¯†¹éW²JêÆ€˜Ïc9ÕqÎípÌ;¢?<ç‚ljÉ9÷-úÓöHtŸ-Ž4pý y0°º|ºª£6¡Ó…$ÑzŽrT#šJ@nG¼Ëpän÷GT ´¢šZ—ËÅI€6(Ï/q±} q®à&‹’Ÿµ÷Ev£Ùb4Jrßÿ5}}¦„0ÓÑÄ­#Äp„ÿxíUEô¸†e„âçô—žú"¥J@+I}ç׋õm©ü#Þ¢âîPbrV¸UÌM µx¸öß·5÷ L-÷¾#ËU˜éuU¼®ôžÃÈ l¬}pàPÛ Dó/„’€€¤üXcÂñz¯iZÌ»ûJ£Jcwª÷´pïU ó:”Í1Ä.>ÒÕZuxûÙGE¬G¥^D¤š"'‚ðF)òY¡Ï4Ê¡oÓû4¿‡á>¦†ÝÀ‹*qcß0À»Àʦ}„ >ßÍÒXkŸbötQ¥ýšTh<iò ÿ§/ï–<Ȫ„VW)ÏñPé¸Ïÿ÷ÃtL”ký瞌ÈËó[NGŠƒ®õ,©Vœ0,j´øQæ>X/QêTXèߢžX†Ò†›ìÍ#süv0†°íå¬ÖoÍ=âžä£\üU.DÖß÷ÒªRG⯺82­î}òI4ƒ°¬S¡Ð])tTüJ´ŒܪÀã-¢ —ƒ½Lk俥×¥Úôž›ðÖFHÜ[~íîl#RÚŸ‘[«ÕL9<þ»ÔœS ‹Úð~ûvp úRWÅŒ¿œÝvã°á¦_/3òå+<‚ßé¹fÎ^ß\+žEá&ž„9tnãȤ†íæw¼düëÜwøI£ 5º.ñí‡? 4Ó ÿ?v-6(OÉLEb¥ÓÎMŽÙiˆðOu«…$‘d¬ìNã",;Ƨäý¥ürXcø3Äq\—îÒ`‚ú.øFÏrUê†'IÚl"£‰ûŒa‡ZuÏ®¸ê™SÑ{ØÞGI\h¥é²ÕZ’€){Ýt¯"ÃoñRD 5I!'‚1GÝʆ4Èu8€¿s ÓÛÿ B­ .RÈJÕ'¶ø*ÛG."Þö{[BH?tФöL-RJK•F2á^5¡/¶3’çÛ(^i¦¬é­Éó#gœ[á®#•ŠòØíèh•êµßþKš’“™\ns~;Fcw îÚÓ{r¶R*Ñœ_Ø·a2Ùz­æ@刘ÚÓ†À•MVÛµÂp‰u_pN'C²¾w’€€ÚBeô[”«A®²~žŽå¼Þßÿi>/¡vnq>+åð¬Y*͘è}n®i‚R“/ƒèÅÒ’Ž@;@—9{ÕÜŸE£~ÐD!;­)³%¨UþúƒßG:•Oà9΋™u²\5Ø‚=qÝËûŸÄäVfSÀ"d§¦;Žì$YááÜ!ȩ́ÖÎÖJ—êY¾gÎãêúPê“;É^êÌçOoÄPªË†-…¼X©¬„Dª"¸t[{”œ1D@S¸9{ëЋ}\,sL¹µ*3Šûk@ÞVø“c3 ç»;|ôÕóáBVÞŒ(hbÑÛº.ãsÿèJ‚FÖŽ!„(ÛgÙJ(´;Owã xM–ÇU¯xåÚz h?v+éÎ [÷”O‚å=c,+«æ•Xh3¬VP¯W`ª0¥i'¯ï†zT"àr›(ê` Õ58ÀðC-Q‹.fçXÛiuc]ÀgLëg€ß†ÌP’ ê_®›'Î9 ³ÏB$oç.uü­>žrSOG bç?åœÿù‘À؀JHå¯9ñ)0H‘¦.c–+qÒ ù5~r+h‰F9ô¿:ký8óéEy+°§=±»ìyý½¸Û€&:º8d‹Ün_Ž\ OÜɶ3œÍšÀ…y†Ø¢y¤Í``Na’—Ìh˜&±êÅôPÝ;ȪLð'åRð,(̳—¸@ç c<Ö€«ØpÙck°¼¤ÌB…¾aœ„hŒ‚²oo²ØS›5KùÕûl<ÿ´.—¦îW‡F^]–9å°þ_—ë¦ÏvÓMÖÄÀ,4Åhã×–Ùƒ³`m¡)#ß®æÒÕ'tžå"M³·Añ%ÇX§æ”—wƒyU@ëÊòöÄêÄöîF„É·ÑåŒBõòü|#Hƒ®ìú% z4ië£Ü<œx€’€€¾9;Y:n­À)Úz§bï3—`»ôÎs•DlM‡RÚæýÅÕìÇsŠ&œœµ½¿ÙxV'ö6÷$ÚSŽZ2JpþŒ!`9_(ü,]Ç¥†cpQ#˜ ÒÉâ0o@%Z¹×wáH º¢§x™º¼m¢ÚÇ4lsÈzÖ§ý0Ø÷¥ÑˆÉpÎÔt:šl_úl?Oëtž"ØšÖ“ê`í>:ˆv7<V9¾µÎáÙ·ž. zfŽ­@e«!ë€íÝìW²Ü6f\˜þ™ó?‡!9â<„EnRþJþ}È@Õ/t¡¤5š7¿¬QV6§µêÏïÃÓˆpµ7xc[§S)‘±÷©uJ#®_kWõA['J¼²ØQ€}i Ÿ'|R’Ý_¹pBäëÌ,èãJ°(›ÒI@·mpËþï%Dpd®C¬økä‘¿°£¯ûµ¯û‡Á« gä–+]ÐGÒ´,¹…ŽŒ;Ö£Lkœ…<Ó¾Ïi®Í銻µ›­]Î7ÛÁ>‡Ár„“êå˜ÉésOjÀòŠU³ç΂ìæÊxú“Eª]»Uþãô$þn•b‡Äy2 !oÓÕ2œñµ·+!ÙÒQ£îÀ>áÕt›{"`ù‚6+õ½„‘Âü—+;æõí¼Ææ0  ýÃ0Î&‡µ”ÜUœLŸÁøzá™EÓR¼Ðhc2Œb3®Ô§ T1°ÕQzl¡H®ò;AåÞ”pôE9Y…vØÉ·QÆêŸ¹uªgƒá…Êâ3ÒOg c÷$Kƒ’>×Y®_Ê<ç¹™ÃÊXQXÕÞ땉¨8a»zÊMg®Zç¯qûÎtµé¶nš—ÃûµÃó*|´òò­·ÂŒûF½t?}Ÿ4DÄÿ[J‰o1Z¤þÆ `Z…íZ±c)õÇj(lUMu¾CŠn Çà>;3dÒ ža‰ËÿpS›¹5±?. Ì.M­âƒ~l"rD‚OqÞ” y¼؇Ò¬Ø6¹q¤v\œPùmÄ­‚1€lç#ÚØ°â(@X úFgC‰=Ì#œd‚jWäTñ^pÿgƒ' ­;Æh¦2÷×Hר^gü½tcŽ{?¶ \ìpA0fUh>P=÷•R¿jÇ´·Ð—XĘñjˆÐ‡Ô5îç¾§à–<Œœ¨m£’€€½\˜‹×6Ob3çŸ~@˘]kW^0©ÖöK>áce²žæeÁŽ)Ĭ&^ÎË¡ƒœÞ6µ™9…Z£¥½$8n¼Ó)#ŠTÓ—éýŸ(¶™¨E¡‹eO}çÍ|šôÇÞ}¦tÊ}îÝwõçáÊ@.£"-¾’ã©ÄíD)€M„“¹)Õq~N˜Ç3HË<ÞDóJ›^ÕIªá|­ÄÂói|Y½Ç~” ;`Ý<¨nd–l6ûÎØñ»j~Ä®\¦Ø ˆ:i’óÇ~ô+N§~6a·8`Ù¾É2¥çWï]71®ˆMjHð³>´ÛZ´ï‡ÑKuS2EŒ1­=’7tKµ#.Ö„ãqòe'#ªæH+Óø\O§ãíŠ Í e#Ö³–„Öz¨Ðª068ãDȇ©Fôkà¡Ðã{Ø¡ýª[Î9@– ÍZ^çy“¾¸Ý /¨fÂYL0›Y&þ•&Õ¾?§€ÆøöÕsQ«¢,ó*Õ‡ñ‡+¼IñVô±E¤Ö_\£ i¾§ú±â;4SSKÔŸxI)êç±Çê˾G^ù›M…vûU>œ5œ«5Rß¾0¨Û†1–¸ÍvÏØï%Â|ë+1𛎞Ó7)ݸ7(‡À­Öú‰vnb‹ã´f2q_1ú)ž1èÜSEGÃÏBpð4•°/Ùhð0yx0ýÿ&íÿçXd õ§åÆgw£á8MkhDךª+…ŸŽTgë´ Ÿ'Ýj,+vš±0‰zéÕ+/(¶5@­=€ÿo§à5¼Óý•¹Ú’€€Ñ|üÖ1GY×ó|n'ʼµÀqêÚ±½6|b©ÖQ)G¢mU­ÁŒ’,QKproD‹AGg¶Ä¡6¼ ÂbqUºr\ÈÙùÆuô®(Õ¼Ëö-Ukì8ÍŸ+úq¨¿…ÀbSf ýÇjg½ëGŠ/•};¾S#ÍÇÝË;˜º±ÕoHÐÅ´ úh4¢Î µ¦†N`ÄI³œ‹Ì?ÿxUØ1Óª3%Eï ÌqyVÈA…4œ¯QMPúidË}¦ÍQÔЭE´b§ÑñMˆ*¦]éĪ_~Âj '¾àVbÛ¹ »PbTµ6´°õDkÒ¯#êì†ÁX‹üéVÅlqG¢9Ó¡@˜V¬j!ðRĪÁ9¢‰ós?evÁ_•Û"1tKfãô +úäéßÁ>"F8ëtÛÕDnåé§Åt<†‘ ÑX;½˜[s,.ÓHTçÀ—êÅ‚Gýògn¬Hr0 @…çI&Ÿ|»$AËŽÐqZÈS"‹ææA¦—Fß.؃¶d·\SŒhÚéV--ý÷3 S—¢q<©êhL‘?P[7l^b‰60À!Ø‘ím‘K‰U5Ï –\¿ZåÀO£³iš£Œ"–MÜZÔ&Þž}?Ä(,ŒQwHoèfÇõ“ˆÍ|“Hã—ß&}¡æ?—ø1œ“Ô¯ã¨Æ3RÓ‘û(ëúçV¼× [7JÇ„f­å ez>’S„³0R{ÀÝ{ˆ ¢%"èJE¨ vùQ‡1 ‚‡Î2…Ü>ñºÚ˜ÊÚ¿xºöv„÷Û¡wyÊM]º_œ¡Ôágãïâ\ÁödªÎÿ®5én¦¿7|²™Rë·Åq–u0æÊˆI;ÜŸü̺ái¡ŠaSÌ¢TÒÿƒê-'¥æŸ:8à sÙ‚ê¾%Ûù¶XzêI²!AN9n¶5‘!@+9I /½~z|5“;û'?º$ì_‰l4’€€¦‹V%\4XÁe»åYá9 8š(ý‹œËÒˆ£'Õ+ˆ†6Lqî¢5! ö íŒô¦üWÃD: ðeÀí{˜r/ Ëogn;õÜ`c«ÎÇÄØpÈñ=Åüû_úÕ´Áý°ß^©îˆa2ûQ»€ÕÔšžÓ=‘ ¿U}"õ€aÜN§²#wÙ[=óÕ»–©·»í:£ÿiL§ª‹„’Uðák’ö%êNg´~ÈåŽꯘ];•ÅÿýI}MOÒ' ÿ²¼R’¤ÃÖ‹+ÿ—E'’$¥GšµƒøhRPÞDä31w’K?Ñê܈NJ ÐTÔ”¤tpæš;Ë31ÍÇ¿´aJä¾ïu†@|–/HF¸¥ÔCdAÓV¡ˆÐzN!jW?è»SÓ™T CmØ}¢Ò¶}†êüÔí¤bˆÿ¥•¿Ë§øj™Ú5FÑ4^ޤAí &r E|jêñÿ«ÚåÚÇØé 16’q oBìÆñ’€€¢Ìì‚ûì>ÈøÌÆl¼: ¸²µ‰ß…4Ô¥¥Õ6 wm›v(x'Z$ EåžÆ†lmªÍÕ:3Ó³=bÝ4ƒáº öK ¥ašîÞϯ´è4Qà¶PAQ÷ ì|ÛG¶®"ÿÝzõœ1 +÷ÁÙBgÑ àΰڈc#4Ðuq³=¨ÜË0ÂY4úZ·6¦*ºjÚ®· ]M«(³/ÏAÅðê¿T„†L£ü úøJ Dº€tB“ŸS·‡3´]ÿûDÚ êj §©ŸÀr,çÿøîÚ^\ (=šG‹vòbhÙ ©}×,XNÇž¡.â59„ª:Á?‹8¼cÕÅÛqÐÓkÆ&í\mW²H3I½ŒÌ ¦£Zou6·Ê¹„†-T^ÓúVÉbIµÛ™Š…˜”+& 6¿£V­é¹Û%­þXy#¦¦™°|ö€½ÉÃF¼·#úðµNS¾z_³L†l·+s›êäŽÓi ‚c;³ïº:ò&×—ÖYs¿_m#Îcøü0]<}çç¬ýûsŒÁ¹·rÂþ?¤¼Ùa ZYR}%󹃙UÛ;2æjµÙãM^Q¢"cO…¯:×8e¬R‹Ô¤US'|˜š PR^¶åuÈNzn†´Ÿ˜£¾TÁ Ÿu–‘©¾ì(! üœn"¼-ªÒ©ÐV÷ùô»ŒÔ'r—óqèÕ[&i6þm.í£Ïh1œÊP ©Vß/KêÛFêüÉÜfÈF­º;ËÈŒÇi'!Ýñ;÷xÉ×Eלǒ¾8ôñ3ûeDµkÓ"¼X™wYpý<ú“Pˆu¹1†,¨è{©}%ÕÈ §…þ’Sw=>ZE‘]nWïæñx®üCüKˆÒ'| ’Á:‡_‡Yá;%ÅüZãÙ651LÎZibÿ¯™£5'ôÒ-Ù‡Ûx³/æ[¢o×-¨eÀ곬EoKúüj\œÀÍ„´˜…UëÄÓF‘u”¼1,“µÚ)G!Þw z(n_hM‰,`ìÉ0šp LCA“FÞ¥íûíÄn›!ø­°·SL_ž¦ð;Œ¿^¤7ßB%ˆERÕ¬Éðßž0¥fØ¢øÄg¨Ã7$ ~hEe”ãEˆPÄ:ç÷É„­šÑ~UµèQôLy@5SãR”îØSR0T•ìM|’€€²=ß3ž†‡™ åtbD joVmåBåvˆtUàP ©Nv©’2ŠLí&(ð£­.Å~1ÂHdÐ¥e†žóZ$àSÄ|’ñÙØJ4ù5ùp°Pë. M‚Z¨ÏÑ š#ŽI)1Ò=~Œòâ+¡Ø7ípµ>bð`#--¥¯Y]+[I»É¼5ŠUœ·Žÿ”ð;F…4¯2ž¢á¸ãOë ¹žÙMïhÄŸ®öº¹À¬œS{X½bü…¹ÄŠ'!¡ÛÁÇ8‚ªÀì^‹Rrë„âÌð\Z‡f¦&*Ç¡Çâ: §X÷ýïëö{ ÇL¢x½¡Ä0pœ9'ÄBØ“eJí]R/t\¿öjÚéo -2JyÇ} ui5Ø~¸¥„UjÑÒ¹¿²; ^Í—m.—‘ÿìÄŸ$… Êè†OÚ¹Õ©'ÀäU¼«Çâ"ІADd’…îíìØýù+¤¸:;!»Õ¡ëå‘‚»±ÿ37^„ãv·. ë`㜟À¨ø9ql3˜ ψdf˜UÕ¹3¥ ÌH(|TžT†HX‚$4‰.pM7Ô§”ª»¦üãv&ç®>S¤çÈZù{SÍÇ3!@Ƀ‰‹bÆYfpø#g¥5á r ¸Ìì·øô[§[®{šôØ›Xü¿É 6²¦@¶þºDsû¸ìXÜ7nekÄ–•x_l‘’yæ)*]Ž¢zŽfšï÷Á î{êɳS¢ºYÜäçl<áÉÓY¿xVFà‚LYzNhÑq kâÕ¹O§#Ã,N4u–Ü©&RlT—!-¤Q/ÓáËúgÒU*B_ãâ- v–h¬ýÍ–JšÖZ‡Œ*ògÿ„”Á$üŨŽ1š|ÕïÍ{ò7#ÛùîåÞ [!Alf’)ò°üP^*ÎöÁ'MÓ輘öJ>Ìã;4W-¬»­pbÔVÂæœlÙžÈ+W¿ù_—HÌÅ´C”ÆKF>2Ðq}³?‚³æe’€€²ÿï^€þ´VÍzt…òéòdÄ\Ž­ß¼‚ÚWµ‘û'ÙHïØ³F;ÞkÃìò¿¼²…z÷Ãâf¡ÿ‹Ù¸=×¾ø”øzA¨óQThHêÿØ­\®‘i{?ÁXsGì]·?¶ÁxÕáKeÅ,¥óë•„mRRÁPÆì®ñÑ)'wZF 3JÉ´¨X¿ï4bþ£ù,øÙ¬ÌXý åÆiaƒ¼ëãút¤gQþ'Š&;Ix\9åvEj';Yì·÷0ÁvþŸ˜Œ’n|ã1%áÖ’º¬Ï`cäè“ôþ¥ÈÉT¦xÏåoþ``w»—ÔqMÔèiRgMd¿îÑ-q.ÁOÕtÌûÍrt1©Ì±æ³–¾,åjI .”ÔêµoCÇ.7Ï^ŸVNÃÖ‚{±‘ø[s€šÿöH€x¸å¤EDôý€'¹/ˆýø¥g4éks†¸…ºchÜí•ÙêžÅwL×Þ:üåÓ1ïe|g7ÐØ?j&Úí¹SÌÕ-ÖLÞ •¹»ºpéhX`?*>Ùn¾Im¨N³‡}2‚ßf.'9ZEqí‹&Ñ@›¢äÙñø'‡ÜHúÍuNgwÿ %²xO÷à^¸îŸV“§T”ÿzqFÆVªÈ÷Ø1üQ5wM1ø€al:bvË3‰|µá°åþZ!š®¶èŒ8p(ëûñSË* 6 P¼~p¤ì›70u¤ÿê»úÝTY„ ^BÕQY:ŽúK¦¼ô%UCëQv»Æï4о(ßdë R8íÒ‡I ;/¹•ÆïRw² €VE,íßEoc êªÿië@ù¼‘Êa5‚:ðöæmà3ûP„r· ýv’üeÏ]¿GENjג4<æ€úMÉ6%â®™j“¢87Ïfšü^?½ïÝØƒURÊ2Ù¸ga©˜þ=FëçÝÙ×S ¬he=þè/;NmU3ö~!dç ׊V»Që 5 2š>TÅÏÌvLÒÌ2–U8¤A#w{˜Ð­ƒOÈ $"íý¬ßA”œ²‘×:¾XµÕ©¯±ûÆ5o*œi>öEËYÆhòþ½Îm­‡gÏÝܬYɺL-~H—‘”Jx¸îR+ âG:7®ÚÒ5=!jž}l’€€³ÌÊ‚ðã¸jÀI“·½[&×Ó\uËÀ×}Ë÷uœaèF,"¬s ,[l÷ûCoÆŠìæ’5Ÿ;÷nîºáï09uóœó·È~SðÌoÝ–†+ÕÓ|ÓGÁ¡i©—`M¾”0©)Þ6 R±Nö(¤b/8óÖÈcW_«þö͘¦»Çë8Ãßkmžuÿ”Ž|ì|ª-ÕÛ×&Z“{†Ú“A޼l©Y,êÑüØþúvàþÞDz?aÀYÒÞ$Þ×ËŸ°7œa~ /'^"”Ä.ë5M9‚l<‰ì4–Ǹr.ï+ìðÚd‚cúí à eB²§o†!çXÕ2˜%€Ï'NÕ¹\÷p%VUÈâ§ÎÌËKèò¯À2k’ßIt€r£»=H«ˆÁ˲"ï¬U„wý08 µ/ýB:O%ÈÁ›ÓÚP—H²$2[[)ïöÜ(ùy(kæã½¬¿ô¢mñ,˜øì£¦ÈÖ÷ïaas&v<)‚Ý¿!c^í‘ÊÌat}.zIýD÷·Õ`Îosée+‚î¼öbî]ð±ÔÎÍœØYyanÞýå•‹>ÅÓ Ý“­Â1jó†KM6éѡܦΫèÊF؃(¼ºÔÉÿñu1ËcwsÉ)ï_|åae÷¤ÿ­‹´Ë†ƹ¬–Ç»ì5Çæxõ€~î9ò;ÅÑö ÐÖÙ½0?Ç–uÀ¹Põ†¨Úïnõ¸¹°âAGfÒN<ëqö›N™îb¢´°÷Ò¾~á6,f§¸=¦{ë´öT~—wݧ•F$(YK_'y0S}²£ªcÙÀIúèÝz2jåÀ‰ [Z¥\õƒ²‚Ï6í Žžèô¡Fx}®±Žñ²<¨§½=¼3Ë » ¾…tg¦Á"vœk1Ëz²®¦‚»;çˆeYMññ³}§Bƒã¢yuòáøÇéì0ex.ªÉ"𷀋T½ˆ,#Ñmf/zçËþ9•v½î¤þΑ¤X·c`ÆÊmª}ðÛ¾¼ª\[9Ò‚€Bt_ÀŒï(ŒwÙe€y e± j±ŠZô)—n¡fù%ïp½W{!¾>T^;š}¿&Ï`Ã,9Z0ttÒÒïV]4-¹EÞ í¨¿™ñ4® ¿Æ¡*-Þĉ’€€ËÁ`pÒT:þµ5nL¹ÊN8+`béî¥+~W:þ/s°ÈUo¯«¨8ÌÓ:/Ø–Ty1ˆ'çœ`ʇ7¢–]³#žŠ.ÿj2e¶qÆ@ÿ¼Õ1|k¥aΫ›4ïkÜ”wȘ‹GeìP}_Bwü#ZÉgîþS–Û‹HœÏþ±ùèuíX_ðCh©OôW¬ÈÚÌؽ­CÓ='—ÉYå¼4¿Ks_‰HåÁ&Ûg3†¡X³Èž_%hKwWÔƒùœ<âoº1I.uÎòçId<£ìàºwˆ±öã‰UÌÕU7&Rz|Ýc?Yh¸£¾y¯Qš—¹ÃT ËL`×;úkœØúFÿ•ÈßGH¡Cd}/¢ºÚÉÇGim†Úï}1mÈ ‘ÅànêS´Ê”Í6¿ÏâeïbÍM¥Llÿï°8Stž™IV¾®Î‰ˆcû`&Ô§s­ ”´ê?p½|¾bí¨¼i‹”gb®[8Öõõ#ƒmi6É:© "¬•"¥¥8ñ®Ü³ýI‹E¯‡a roéò¨8;-‚Ë!ûYà‹3lÏJÌ^qfôÅîL½H¤žþ]Õ-OG…>‚ªvBýàŸ„ÃÈJ¼u O} ÷…<Þ/e%«ÿ$îŸùÖMjrW¢µÄRRÀ¾:ÍBrM©øÁó˜ò@ _Ä«cpʼn!¢ÿÖ±T’Ö–r7…SyµgÿuÆ-üINIÈšN…Ø8ÊR6øÆO÷õ]Ôg`Tm\tù·åt’©7x¹(î<¾4n5Y÷® ÛAÌ¡ rÏ ¥Ã±óÈ´£d?¶¨5Š üsœ…éì•äK ‘V—ç0„!Џ¯½AìRl”$êNˆK”·[Ä´­ržÏ°$p«sĬ]dé{vÍúY6ŒpP]I²N“ÒÊfånƒá‚Þ·Tät÷ ..· h„9ý rÉöólV Z’ÎÎEòýé,R¨Q$Íuè6Í'·ä+VÛ¼C^ŠLrv:|í'™ÈÕ*³¨Ò¢6z"Г·ÆÊ¤¼è?Ÿß¡uñá†úÜpz,¸h*GÕ×[â!»³Ã8§ˆ’€€Ë¹˜;  Ú“Üöâ2TŠ«2n„ýË™¦epyu·ð1ãr.É¿šý6§¶6Â|Þøt^¢„,ž G¡m~o3e'õwt&®ç5 3iú¿O¬ô’Îè¦ùç—û”è¬=¾å¹Ñ ŽÛ¥ß»îØ,å“`®_ƒ£î^Îó³A'I”¡íKiTG;C¹®ø4ürR.ªH–T—˜°(-ˆtûl×èóÍ£4£ùÜù`Æ ð½3é¸C8õÕèN„VB›æÿ%“nó,åxm¨Ú`!F¯ul›SÂå\ýײñßù°oêèb‘:-—/œY51Ø>Ñγ ³ÔNŠ´›•ƲnÀ]ÅZ©ü%fêë\69ÄA¨·Ø8˶¦“6ò?gnNîácuB^rçGu fÿ}y}»O`›@ô|šv¸;ª‹yö1¼œV-fé|Ë ‰(ø^ÄÜsp[³ͽËRò7Œèà¥! —™±8M±~Ó3ÄéÖ·“¢áÎ=éó=òŠÙ“»ÜÐ'î§RkÂë%\|íšÖ—.LA-H ÁÓSÐW«ÚX'$æóââgµd”ÌO[ ŽjDviÄ„žPܶëÉŒðùðhNF®þ…onÉ·VÍ‹]ºÜ]w:¾roßu'€¼ü*ã³·AYöóS'äî˜ (1£ŒÕò¥?bOòݱC˜N¨0…?µáØ´?ynÙ¸. ,|Þ<øÃ5ÂE7‹êçènØXÚ¦¿bÈøåÍШÄë-L7× œ3¢Ézg)Üç—†ht5‹£ìGm~3•.æýWRöE²‹TgaÓ0ÃÿRö×Úê¡À7øPöª(øØ½ð—ÅWÚU+wm³P¢gš‹ ß¾ÊÛí›0‰Št—6£2›Žv( Â%5w`Ãv͈L‚¦1øu—úÛEµ‡³+N“5-TùO9-q¦ÅÈÊOŠÓ¥-½àd:6ŽÖ\ÔíL{í&2Sïs_ ¿ß^=OÝ$‡ÝõwdTfLkŠDêýƒ|s°¢ÉyÆ’µMJ½úvtè+Èè-)ÆQµ I/›5r5òí³”Ú=}ì’ï;n-Ú®àRÂ; ᆡá4tÙ©[,úË4%æˆmò¸®9瘟deUÑD}IóñIÂÎI.ÍË_ÿª8&›(Zˆ|¤ é[õ©3Eú-±Ý(¬v'2QÎík~1Pý‡<ÈNh_3JÅ•Zç- ,>Á`‰¶‘“ò?x3ö¸“ØM]r¸¤’·'lÙ]í†Qû{_Å~…N¾F3ª7\áBN†Öu¤¶n/E{®RÀú|“ßYa<x’"_(ůæ¬êë†Wé¯Á¨ù­hP:ÄËŠÎHUz#pü±¶%xú9g4ž¢•2H™\;«Ûù‡Ð%Ï)Ì+†Ä÷õÂôvE;/×1ºy RǿŠƠgH×4¶vZ=\ÄòØ ®9dý€ƒÓq T&© 8ëÌ– Œó CW‹ÞAÈ*h‰âG+ySÄ$’5?€ÅÈÉ9Ã.î‡É;lú0¯C›¶y¥¡t“M= á]±úœðV»‘¾{všŸìÇK“<…Ÿï&ç1Ç|µ"-–ÿpG¨Û þ$H²eR&’lBé¨}þdzk\$ÞnÀJæL.Ép5ë`Z9»É¬Rèˆç-iJqÊ{“KnŸ-å¼ iÚbš› ¾qŽÓþÑlUû¥¼Ók…wíA°K<| áÂ6eÅÅ€`¸$דÑúåˆáGÊÆ7˜3¬3¬¥§¡ä\D4“ÃJ±˜ÙT»õ`:*ÓðõûÕ–ôêPGzí‹—¦ÓnåßU}ÉU€Ïû5ŸÃðÿbr,pþ£-ϼ!Ö ú _MƒÌœPšþø°† sÕ“~S6A³VFÓ‘†»ZÎhùGîàÉš¶V’*qs¢†·ñ›ÐcòÃÏ™ªßëº&ú)ΓõÁÑâ-¦»JÉ¿Fö²ÕjÉl$‰ áUô}T”eQÕ3•œHš åXŠo´¥Ý6„[ÁìFlóÆyb^'ÖØmF“,ŸaáÊ,ZŒ¼ÛË#;ñ:€š×€k¹Ä\вË<T¶›…¶ÛÒXR1Ô’uµ¡ñ Dñ¯ÐK5RìÆV›Ú«Œ2Ù$¨ÆLèÓ:t Øs±X\¡‰Ðj<™KM’€€Ûì#NŽßÜs ªrï6œƒql -wø³´¤Äøò¥ÜvG„@Ô¡-â<†ýE¼LšER.ö¬Åjx(þŽ!.°„ >5ÆÌö…¡{ñw_<#܈ ê|¬”•/Á­IÞÐâÿú,‡òô MûZ~IZgs„ ä ¬-ì=Ѭ NãávãM2¨ RÏi¶I]ÁŠâ7£798·y¯kì*Lô§ËÞuš¨;<º„N°`=Ï5Ñ<|øýkNP8 ð4¡þý:¯]®p÷šàžÝLå.½ä…u%? ±UJJ4à–sŠ=êiïß½O³Š6é-æ†$sÜHGÖ¶±ÈÓ̺æÎhÊ>}gñZ±<ÎC2N_ þFHLâ¼oŒðü<«:²ú9x‘Çl©a¼:aÛÙj&u6þ€ÂðHŒÞ~=Zï…Šì™9ï+n¼ÐÞ~ë‰ög‘õl¤¿‹&ËsûÒRUö¡vS¹<&OH5KæGÄu.uØÌV¹34JuØ¢éC¯A‰†@¶XÒÒ»0 «­Ç¶ÍZdÈŠ‘mà”ÇÓ%xìÒÙödòó 8Í¥!;;@áňD<ªÎ˜e)ŽFßÿ]ö¯z"ä⓾²Púç:.%âþ¼UAϱ}ásÍ ²ïý‹­ŽßLA*¨9ÊÑ¥í™Íƒ¸Jà!¬4œ‘𢾃eÍòh×f3‰Ç™ ޾ؼOC-ÔE¾¸`}íÐ?©c=º{yѳ<õDnD¤ºy™q5¾ÈÄ æ £•øw¸ÇþAOÑ õ@VÙxG¥ivÃÇ4k:ÉeÒ°¨Zê—ܶ‚1 kÍõþxWI¯Þˆpe #Ç\S¢C ç¬{ž ŒœaØ|n'‡Òpi«$ ïtÙX”6ÉtÄœMgIÝ±ÞÆ(íƒv ÃÍX•^¢¿ˆ-žé´mÄŠdd•rØ´±š”Æ û­VبCæ×£_W‘Ý4¡x¥*ËY{Ë"šU ^l“9Ÿª 0QøŒÑLsCTZû,I-3à¬7Œ¼Š¥šJvµKDÍgÍçýhÙ7sM‘’€€°á+tëhô*T×=„Ëf¾OàLH°}½Ná{!,©£~¹Ø¾'+{WŸ˜0éSïìùmÛ%:î šÉ[ãƒr æ!ùû¼VƼSìÁö¶è‰Ã6»Íj[§ó¥ÌüåÌ*LÑlǬ¹ó:áNïm(HånþSààB.³LË-|8¥"°Š*g§%µìa}jƒãµXl0L%À^ÖNV1Ïî!p C sÚ(žc ’ˆCý˜©¹DžV¥s§<ÂÞ…R3fÛí–t-Û¿z½p l2ëàÍòv‰âEì`¢r.Ô.ãʃS¯š©Ðò9—ÐáN¡ÕÐj²¹;¤9·†” ¥©7Õf¯l6ÅL3¸,;ÞÍ-‘þ׆`i«†Ú)®äص¿>7©Ü( Âd˜B¹‰ôW3Ö‘Î>6d›ƒìÒ.ÂCëœ1YôÔök¼ùC²MÄ1‚_ÛïkaO×Jk+§Ã7™ ðïÕ }Î@ûIɰ}Î.וŽ9WUƾûÿK½Üý“ˆ#s(ÃïW»Åñ],û˜(ÙR ELd¦ ÙYpµøçAHß:PsÓr»FDŸØ$F<Òj’W¤2tâIįÁƒ©›ÌÓ)£ß˜ sÜò{AK¼‘Û Ä.¦¥²v¼GàôN53qœ }.·@o+÷\æä’WL¤lÃETsÜGt8 2…³JíÏj^uƒŽe§§Ø0Ã)öÕJb-Kä Y9.´Þ%×[C¥Q–V’xûµïñ½§Ms‘#tòwRÇæî1»´Mºæ´Ás]à­o”/ýŸB“—ÃsÈÛ§Q{p¯[ËýŠHa…Ôƒ“Ô}ÎymBr=É£CÔf3NÅa­G‡s“©IS„•ü>Ms1ûÓ\‡WƒqF…kf¼Žò!ö Cð–‡áÊ÷¬º;¿!Êf3¶-Q­þãðºÔ _@½y´åB ìH£p—m00¦—¼û 5reÈü‚ßËÞ%ITóã¤7.ñö4 ¿afð¥¹åKêÔ¾ÌD)Ž‹M ͽºéͧfúN Ý¿yѦ¦3T”C2š÷m§Ëæz*“¯ÏÓð‰<[žüÖ_?ŽH3­Y#iÖ·'Ìz4ð‰œ}MÈ – ¡ólº!å’€€ÞØ÷ìK£Ù…÷b(dlb¬Á}RÕ]·=-~y\ˆ\þÍd Cr¬x~`¹ôˆµeˆ/üFI7‹} ‰Õ¸êˆ#,œS´â!À¯Äi߀FŽ?“—R†f!ã1¾}ºPsnoƒX*c­sCNJÜà>H1|ÂöÎðžàÉTðècûù$ÜëzLX_zeMpjãnÂé_Ðâi1Q«NÕpM ®_´ðŽØG¿¬H_U+ø¦}lëK±Uóô/ÍÚ¬HgÕUãàS:µ¯Ð9N/Éü¥°H“ô.‰SKa˜ƒªÛêÈ@=‹ì$?9Û¹aˆtw_ >nJ(KHVN€‰ˆp9›¿X2˜¼Bg¨7€jƒù­Š‚¡=s =8ž^¦õÄ‹ŒTsý/r¢”ˆ‘J£jüÂè5R Àð‰’9…>e¤¦.kþ$×¹§ŒV%¹€­|n¹‹ë‚ÞÕ œ‡yyb#r› ÚÜ‘«õPžÈ{Õ 0ð¯ÐîxdäUŒr„UþÀ@u þý{ŠNºÆü01Ñßœ1›èà’€€è¿y1hsÕ §¤û–sI”nžù`HÌŸ=¿—;â þeÉâ€9™Xžç²C9ß¾ "Båx¿#hc•dœþ“’ ½üNÊæ˜ýqUrø¬ÑývÏÆ…‡Xj±ôˆ7aà0§©o!|zŠbr|RöÖ9ÐÛ9  nIš³âJ™‘/¤ìµúêмÄIý“«éÀù° ƒC ŽÌ\e42ÊçÙ“4y!ú˜ZëÒå‚)YÐk_ÞÐVäNçQK´OXä¡=kÿ´‡#n`ÚY}ÿZšÙßú]>ãø{ž)I’“•=l.ɉN­©ùœý°¹ý\—&LŽ)׎»=«ÆÚ_XZbü-ô\ð8ÇIp&½l¿U‰h+8„Ù„ÉuGì_¹Þí›Õ!«'Â'²tö$w%ØK|à#…,ë4fÎØž²Èu·aC›Ânvfèå\Áñá}úŠS"†oCðÉ–è7!´ÖžXÄ€Lõ*S¨K"’ÓºgÀ^MÈVO· nc”s]2›^¼o©y:€—e] I,TîXÌšY _¤ôÓlÚ:ŸxD¢ö6ÿÑÐòH7}fùÝÛ/” F¾\ò5WÔùœÀü7½(ìL­#ÈÈ‹!Ý>ÀÎ׊<Æè°{ÕR [2*¯sàYÇû±´¹6¼>ÐV—ôÝ:0裿ÿpú4‰Þ·IúÒáD-M!g¾¨níó””s‰køñ,œ6ZÂÃþ—PEðjEF¿ºhcúÌ!Y/NsÉš_ùàVe#I×jP‚V cÀæž8ï—ˆ«eÖý-•‘¢3Ñëõ`xoÔÐöÂ#{Êš_Žìºi‡ˆØ°=E§8Xþç~H„f2«[ÿ¥µck'}c˜“'ÊL0(¬êp†A’“òå~’qb´¿~£©ý4yæÍç«­íåõøs)ßß*#ãë­R’ö÷•õŸWÔ°}ºÞ‡Ì܇ºÿÝíeD>ó/q±ªú&ENr"-F¨Çômμ/GþC}1"ÇÍ¥ÿqóÿBä{uÍÎåɦÙéˆÑLj"›gÉò"Þ°íqÂòê]m+CïtÖeƒ*~±þ»bÿ¶TbáM²zmlDP¥œÖ0¯:ÍÙj8¥·§Ú3ú”pO/&WßeGï§9·\–ÛãÒó²µ7ôÍpÒeyKȕßë•äÿ«´Dªšb…xÊîÍ2Øâh¢¼â–ŠçûÛÈ„/Dë» ×ž¯àáëù°¥)GìÆ-»ü—Ôwo›bÐÂ>v¹d@ìHk¤LˆJÖƒë2N°ÒöŽ®(8E ÐQ}²Îžt/^«´‹É[ÑžÝñCËĶÅÏ(¦”Ÿ¤ªÏrX^N³0Â2« ™ŽøÄAŽ›÷+Ôð—«$Š0r–UsÙ†M>’ÂŒKôs %Ú†ŒUî•’#!((@&Uê@:nq€ËQxö«¢…MøtUí:Èv–!‹ ¼œ"¨™ Ââîx—° bSµ%‰1eçÕyy²÷5¤{¾8‹£6¿Ð›ÛµŒ*³Ûiò‹jÓ!¼‰ž®3AõŸKo÷f„ĺ˜ÿ‹ß%‰ÖYnÄâ iiS©ÈÚ|9²ƒâзìÛÞ¸*rŠ'1¦—²ª j§ÓBÞôÄ>]¡^L‹·G†VÈqoC’Ög\‹‹àÕZ\´­>¶yAG‘Þéªð·jAJ7]i“§ŒæÛ‡û+§Œã+Á® i3HPNVfuðk÷ܳózªWIfÜý³µ|ìòkÊ]p-.Ž`5`™PËŽ¹=" ©êð®*LI’€€ŸYv6+VÐHýN÷”­³êq½RMO Ørwd¿“)jQ ‚WdÞVúYÔ¬5–î©×Ó ‘^&¼äßò›th&0¨#6ú°úÏDe„a •ž®;¹u€7Xp‰=/ÙŸ§æ½yˆ<åº7$Õ3ŒæÑg¯¶ ¡½Ýä7ƒ(‘O¬î9Tj¹×`0ZøÖ¶jsYž.¶eÿðÆÇEe‹ŠV @¢ÞÄ$ôÛ¬s ßU@Ø}êb‰{¢ ÌbfŠË@Ï}—JJNÉí´Ež›dÕ£G(ê6ÚXƒç×ðF¯ ÁÜ™ŠCéµçЬLñ¶ e²KBœý~‰Ósçn'ïc^EE Îóˆ9ꟼÜq¨Åسڸ‡Ç"xÕ×?Üw¡*çÔ°´Ÿ·/Ó3°Ù½Â?qÖW‚)P´…‡x¤X% ìg^b/®Reš¿{è ù/Zîîü ó¦ÏŒƒ eþÉ|Ö-â†?z<ŸZ§e¯¼µéM¹†}ÉLœçaRè8~oÿ‚É÷÷‰FæÍòô‡>X‘ðfŽ„=0œ¨™ÿ×CdÇ”–>ÝÏ4 U5 ÊíÛÉzMââXÜêTÈ^e ‹†¬FQ–”!µ((í?ü@‰öz&S£<™ }­~û‹íOÓCä˜ãÛcêøºÛŸ¨HIÑÍ Z/#‰'´b(d Õê˜IysºB ”ef(N vlÎarÊô¥Ýœn9­6â;é?û%š¯KÐ~7]ûn°Æí76¦§Û•¡¡´$/[ºàŒÀ^oÞØÚ¢‡l+ÆÄÒ¼."%»núDš€pæÏŸx@8µƒœAá¦n©gDB/ ÝÂp[ †Û¾ðñOúÞ”þ½f6£`.ÒŠ-ÖŠqx³ApþA5¶å`}B*åšÏ`ó.fC6ŒÉ:>¼S7f!óõWÓhÏ ‹çï"/ܦ 2‘ÆzØ8Š™sø@3$Ï pð3‰ÆdÛÓ„ ʰŶb~wé’Õñb»’€4’³M÷¯°ù´±ô8ÑðŠF'0-zãV¶ª5heCq)ÉŒdX¼ Ù;§"YBúÓ)¤WhöTÒ×o”[N³g…ó’E‡ Áx›Q@À:½ïG<‡³K ‹ÿàÀ/ ÅÊ¢m³J•-°ÎÊ3‡À¦þ1¨VÈL&´z AèxÍЫÇ$ãŠ&v h}¨â‡Ê(7ëF- dÏ„âތż-ÃcÎmRåæÜBbp ¾>Ëm¸~ìë6/Ä.¹‡|PsµA´œÞÿCðSf¿š½M³4Š”ÙúOýT i bù‘.d t»+ -aÜs×HBng '2Œ~ YI…äÃn‡S ÔÞö¹¸¬½Zµ}>5AƦ¿Q¼&r«’dö„å ٧H¹M›­ûù0ãyæ_·®ú_WpáR¬Xœ¿Nù£&bsÎ)€}q»7·¸ ž:íã÷saî?€ëŸðê'jר&4iR¬EÙwYorrhïrËá4‘j¦o÷ãT©éuQÂÔÈ5ŸÓÅwg€‘!Ê,'/¼ÆBŽ¨Ã¥wr–L'‰Œ;ÛøšMÉû$cµŸÔ!+*ïŒKa™¼}ª~nóÜDå\]YpµùZ癢{~çÐv¸ª‡V‡vý‰j‰woÑ› #$OûX³ÖÀÙEÍ)gÙð臭âðùÞY‰½Ë@zÔ jHº‚t}ojFö¬ÆJÉ´¹I,„ñL?Ý{G`z›ÇØ`‚]¦¹Vž®Ć‘ê+u3Gùigz2^q@eÔõ¹í…oÍõ\×zd¸àUÈ>uXèçY½ÃsÇÜ3»o–&LUëÅŽ*[’=ø¯R¨¯)ÖIˆgnwÝr.ô{ìž8ãár²F]Ù…³VzƒA‰Ý(²˜È×Òë£R7Gqž ¾U;œ×ä¿ûîZ@$:à¤)Îüõ”ÜZÉÞÙ{Ša¤f|4g_ ×Ûü(BÅ/HÉ4Ÿ®m åŒï:3¿W9ß)×Ïbk°ñ{±÷ß`xP<ýçïÓ¦’¾k=òžûø¥ø»P”û“·‡|´ë»¼6ç˜0wúú§Ì—9x©EÞýȌ̀I-—i¶€,3VŽv ÏJÉê3øÙÁÂè¦ù;J…›– j—âK4 ƒ!µªê“¶]ÕÇbÍlH’€€­kÐs±ª-ý òý{}Ižýã‘qÏè$¥8SËŽ›s%Æ-{ ŽCßéÿæ?‡†€ŒïœÊÅ Ž¡Ëï<Ú€‚›m]|i§ºëÃvOûh#[M@1ZXÅGвêõ>q¸¬Bl(hÌ÷ Ê`\ýƒ-;äžy/™¾”R*l–¡Nx6¹‹‚Òáë«#dN5¼S¢3b ¸)6¨Xí Á¡åÝíoã`¹‹JNGÆ(££ƒÔ£áÜ& †Î•bù^XP6h6eBxmâ&õ‹ËPK&%É_Ó\0é©'=ᑲëïaƒ&ÜB4,«hµ(u‹N…—›H{¹Ù·œtÊ1l~*`„š¼ªë«A¾^¡­{Îùø/Ó£hë Œîdú\‚·GÐkXb"Ñ•öŒ”] ù¶tö”e2D“µª ز ?Ÿ‡»°…4ÔmNÞ@®Õ ?›–iùXïôØ“—‹#@ä·ß;ÍÄ}›V\Ú t\î½$<# ȼð‹Òõ¼ú“"EäõK"luD,K™²U’ØÀMpŸw&ožÀ'‰›G;èû@J  ¾!ìÆKš”·_‚µ .>¬ XÍC½ylÍ£Š\Ç)hüzë!.]ž½lPð‡¢¢X{Øp_êñ0†±.R ªú„ÅãÊ?˜ã62Þå¡êê7iø p»a`÷UòxÆšš§^ƒO@{£¯*Jñö¾zc8ª.³¤·Tj[Ñ]hÆ/¤ø~û@ÿ:œebãƒZ‹6Ê«nÞ´EÔ N±éÔϲî).ؘ)«Þ€ï\P'øÀH•æ+4ƒ½q°z™ËÏ]£í™;ß±î€1™Äw–qÙö§ç&G”[Æؾ³²Þ;N«°%.oh²“xœžsÙ$ãìø0l¶@¦'ÀæË’€€Ï­…öU©B)/\$Ë× k–©Ç‹ Ⱥ3(˜>ÉB-­œj­£yê£“É :ºú'Öá¯%ÊŒCƒ°Ç5}¿*~½Ö v%È>¨ù—*nÚ %óRþôø'°Ò§‚³pŽ>„`Â_Å6Á@dIÇÉ$îûØ´À4 ¶9æTä:ÿ’¹’ã9†Ñý³DÞ' œýSàósc÷†ÖÆz˜FšO<–„fü[zÞ³“ÏñÊ!sèÈ÷ýH¼#îˆk"«™^º›ü ¦K¾ÇcûOŽ,ýÆòé ¨aµŠØ|¨|Hjct4îHÕaZ_T’<(ü9pûiP¾ä“Zµ¶Gn¼ÖkIV6x&j !c@•+èŒëšwJ£É MâM ýO;JñÄÕ¢y܉¥â“´,J¡‡Ú^ã‹tg˜7Ÿ0ÒàâÒ;?ݬRÔr»Š†2‰‹ÛÛk(l4ßVÅË¿¶ï ˜uï(â8>spè—‰jìSþ‚]V…Ð\Ä4¤ƒs‹ïêŸ{Ú¯÷žE ¾æPøôݼÜo;“ý¨Ë„رyÒˆ®õO= ð@YFú@­“³¦ÅØc¿ÿÚnt½ÒÈôgƒÂ—~Õ¨±éðËjãW²aÐlû¤k«¤Ç““°-í"Z7úþ)F¡T’õiZf$;±ž>ÙßÝ}’«H©øí‰ÚwUôá(­EâÆ0d U†yØ.o#_çó ^%Ž+ a(€…üD>œ³™K¥Ù:U¥]DöV sÓƒBŽ;HëþæÎ°nOI÷D£©œ§)¾‘™˜*á[)ëÑP ²ì½W-(:w b £D*ȯ۷y°ŒeÕ ¦rþ„P«'b[¯Š}hL_´ž0X³šz:T= ï<ݵOˆ*±j¼Ùˆì¢ðlÚé*±’.ÔC Ä´;Å*ûÇ1«ùLÃTNå}މ‚Ûc±TÓU|› ƒv¥?·ŠÞ½v‰\CÄ]… -N€ù¤ ÁôÄ8áAºke+n7²'å`\ 5î”Nt  ÿCyD(ø×$dÜ-;ÞxHý4±hP÷·J€ €Êq:qHžsÅf¼ËFÔ Ÿ +ˆ9ô*¢h¿Ž°·w:°uyD5¯^)ÐÞIB€å¾oð³`ÒpŽïGaPįvÆì?ùéÇQù°’€€»8±ie¬íNçæ^Â…tkx_/pòG^Ù¨ÁRñ'öLÞ£69‰ ¶§X­‰³I üªg|ˆ<9 _*òÑ”`îÿŠNMtÙÎs`˜÷º.xTlZ5РH » *»꙯iæäßÚ#€0úÞפ)l6,˜¹˜PåôéîoȤo"« (iâ}ÎåìBí°Åo]g7Ø”DœÿVŽDœ uÎ#‘bKçøz›xRk¢Î3ÇrUù|Ý_!‚»äT5ôz{|–ÜLK+mD¾_ÖE=„”éï!ÔJiýµl.p%„â×N„˜ôObb_cè›È­.‹€dªi½?$l¦•FÙ»C>¿Qk‘ãCSïõNì™ËÂàáQÅ!di±R)°t#®´÷·š4Èç],- ø>Ôx#Ÿ„‚OÑ)šßÎèb¾S7C±,³¨´_![Íв @Ñy5#d'ªYèÆRaWC«U|ꛂ‰˜øëÊ 5ŠB¦Ù7µ»£»53ôú9PÄG‘LÛ”n—“]_šÉ[~¼LõêßlpÌHKÐñ–ÔÂ,Öåsà#–ûR^*†ýLdßé¦Su²SìÿêÇ.—»Ÿòp“ŸU=I¾PkÛÿÜ-¶5Ð…D_´Ž~’²e YÎÒ€ìÛ¨ ¯#‹!æ“£³AŽQ¬ó:Ç.yZ”73ËYQ¸Õx&Tî¾1ÚwïõS[yìªÖØDAıí×ÒÜ~ø•‹ë+©‰Î.…î:„Tm!j_2p(S²O˦Jü0ËfÒÒê¹›KAeÂ´Šº9­~€I†ÈT“ŠÒü¿®ÁšÙÐPüó§÷«ƒ_´ž|êØ<­Ÿ/ˆgM3•ÿ̓ÃÝ|Õ£ü|Škë…#"KÖŸg&l<ŸpÉMº›'!9éƒï![Û'4ý"!Ú’ÍŒ Ötò÷Ð×ì­!7kÖq$îÜA„ÕR¹›´Ÿôê?õ5&ÖJµ‡êݵN~ô ™×sá®땺^Ó…ZS°ŠO‹š^øK’Y"N†±PÃÃÇ=»ŸäÔ)è©£¿-!‡€ûœBrû*^ÆX‹õtÈ â·³¾ùDs^œÖ£?C–mÙH“øJï4½¾r^Ò¨n}Å!_©Œîü†4°új-¤[! 8GË%oo’€€»ž‹ù‰h «Î›û¥0HÍ…½Œ)Óp/ò-3›$Vô±Äu]ú:ãýa<‚z¢W%§g AGÇ&ªj-e>{‘±$¢ŠÈˆ¶ÉßåÅ1"ËR“Å3Cû´œñ\)—„ý4N¡4¾Rf3Ú1ĶþÆþûq»e6>H·É÷fÖ“³TlކÐná‚>·nk¢äcDÙø£Çÿ:™ Ô &³%.†Š¥Ù{ôÔ=?>gÑX}í ØDŸƒRÛîêR›þìµZQÈ_² Ýiµs1YäXèöLû ì쓆‚§ÉRÂ‡Ì Q§û23ZÞÑÓLX5ÝC µb§†@z,°G¦. d¡Nîç<zcØœðµçßDbh¨[Ò%½!Íd¥‰PëТ¨ˆ©7[:w Ía˜ýp9R•àCfÃni¨Áý„¤ø'#œ0ó >‚éŠoŽtÊO¨û?“È‘ø' ’uå„/¨Áÿȃ`õ y÷»èÙýÎtk“ýGfK¬—nrú>3[$s`YOPõBŸkàñ†=“®?«ùº€ÞåÕÏ}ͬ6—UVÓ!…6Èuæm&œ«)ÏÀ<`XÂKgOŸÖJ°yËTË0L‚üë†âºÔ$º˜Ë’¬d[Äͯs3¦;_>KͯI9!˃RÔô3û¾£A?$yŒ¡žæpG¬Kî¤Pú\ ²Â˜¡UMBÁé jßnW9Lµ¤œáù~ÍÐqL ìSµù[çòÕ:¦ pÂ@#œ”‹ÁcsÍuåYÜLao¢¼ÂD„BndnâªåFöLyCá.²!îÔï»ùïŠms‚-þ(+ ƒÈÉ QLr™”½Šñ c̆ڑ\Su@r<¹jòoø¼#¢ðô×ÿ?ý[l¼uO«¹“YE ò E”æÍ’vç1€sYBG#Ø3ë¿d3Á{Š4ƒ¦ Ãgèúº~K‚øÓÛÓ·Wšˆþc¦® G®+, &ÖÌxÑÓµ:­& ·Yö0A‹‚_¥ÿPbBfͬ¢¹@9bSì§ãBà'˜Le‘p Œ© ©¦óÛQ`ª’€€¿~ Õi1+²…ø ±>K#Oh¸q@ ¹^YÁ‚ݱ—×Óz?1‚6ÚTXbWXÛÐw„ÞÙ®³l–é^ñ¿«øƒÕyÅX$׿:lRV!HRgWýuËæÇüÞOÔ·!kQMÒ9((2 ‹aø ë¹tRUä<ëhI*zäf 4aÆjX+xFVJƒ@çWwEÇ‚ãÕmúèmØq_sßÎ…$`~¶Lg¼°Õ³êÞëÛÏ´‹reª×ËF¤t¿­V@®¢KqŒ‚Ïë3˜áÓ§Àªª³µ‹%’ø5û`œkȺWÐ~:É‹¢*â…Ì– ;g iš¹‰ÖçíÕЃúɶ9gcóKt:EBÜïrJaL+D».q¾÷¡³QdsƒÖ8Ûú55ä“‹h¿çº:};~çͯ†óO`>®¹:ìµñÊæ6¹ˆê¦ÝHghdXFÉÛBÜ 0ˆ°L‡øý&®wBªÛ²Pó ºŸP&З«&j'l$p‚ž2Þ¹5â"X-ÊÖn&O%ggw&€®í1MwzŒ|nÌñ~ö$[¨[ Yþãûžð’¹‘#Ú'­/ºÂ«ÊPh‹r"Xš¸ÅGc`#Ô¬¶¿O4¶äÐ¾Š”^ª' UÇ“ƒÖI…öB¥¯N·¥àÝZª ‘Ýh˜×êó6–N¤ÄíâÃC–µo˜_V¹–WeùØ@AOV#O)Ï1h‡ÚÓ|µè'_©=„@y½I.å‚rm—VtXY`žÿÓ^o0cÌ´ÂÿjøuÿºöH¹âüᙾr?b×3ÙÆ-\fIÚXÊôÓÚm-&Q†Œô©™eAKdÛ2Ëä“ Ý¿ÔáÛÊ*˜´Ao 2Ûä÷Š ‹fiÁg"³uǸ €Q¶#ú®á,a"oÆ>R·yƒ“G“s<µbÂåË#1oƧUÐeczÔóÓ³¬@ÿϯÇy‹˜D³„&bæÅ…´ÒñczÕF{¼üÓvh°Pûd•žÕ)çôf‚…à:§Ù‚Žfûþwž«tÁsÍOÍÀ£gŽ”ìe^ï‡@·ds#­¯³qŒl±œø€+öF“üíÄE•c»¨RB—W¥,…Øèå.,4äl©æHü—°‚Àî?F0æ¤û’€€¾ ÷!µ0æ”JLílùa-ìÉ85àïý/pºàZ}^­;)¢šÑ>ñm>KW[wÈšŸE`>ó°AfØ¥]î͉ôJ ‡3Ÿ?Íuf°âĘDQ<8qÜ8¼´tà¶D2Mb®ØÆ*$ŽŸ(~"¨÷¢¥4ª¾„˜e¹3?ÒMãx|~ UYy€q¬“ clÓRÄSLým¦í¾§/Ñqô ÓŽk Ñߘ͠bïqã?¢ï‡c±™â{[ÍÆ&Ì=ÞE…(­*š+sô}UО±©ú_;£×v/óãÖ˜1úw+ÓqÇKÂI ÄÁóL …ŠÎÙEAñðêêm¢[¨ß²ùvd|¢,zåæ‹ÍÛëý¡¯Í!G9Q_Ú[4[_UA5 ííÛ‰acòí9©ûʘØÀȪc5<̾V.oÇC ø©”ùÊSnc&&‘áÖŠ=bÿ›Éçí”狞šâÅþÌ |ç“Îî&2mžn¦jáªÕyhó¾ÁôùZ€eòÎúA›däMÜü6¤›c„+pP™'ž\N|æ Y_}ºÖ;¡Ä6&tW—ïðédâ¦D‹»ÛVrþ#Yþ `¿Ê&vL %†Ìa~¬®–î H=¬2@ÆöEãP^LÜØÇSçÀ\¯ÌúxaU Ý¢ó+.3+Q3ÌkòŒf¬ ì fuu b6 §‡-ŠÖ¸j³è¢=Ñ–…Õ.ûÜ@kº÷q.‡aù54·ÖâµË0F 0Õz–”ãå Éac°µ|çÈåp¯Ä.ü¥-_m’Å|-¡Ì÷v«º³¸>;?«5÷«p}"Ü“3²{..K¥÷¾´cÌÔˆMØå§Ͱ–Yoc)-@)à­_åf–sëºã¸‹|®äœ…â1ص¼é>/Ú½wji<\8n¥«¯F’.—-³ûDuÛ†Éí÷ýéQ ¦ `ssDëQý ‡ôøã+=>zóè;ì&Êjš†Ž ICb‡ýf¿û‚Š-‘Œ¨/¦ün÷6ܣͤþs™ý Ñ9£@ÝK–W½û^r•Š{–µññÌÄ'Eù…µîÝg.šzB€õÓp¿è´Í±ÝwŒ¶&ZB—kéLn×i0/+µ›ð µïsPé ^n‡²ÚV<æJTñ4øT€ÎÂ+’€€¬x85­}¤AS¤Õ€SY»ý<7X¬—ªy]^ÞYÿ7CUø4¡C2D®cªß‘â"1ô®I4m÷,ãýŒ~§u]‡’lºGtSØÓS"xÂF}ܵK =W‘õžÕTÂR_ÓÆa%ÑÑuûÄNÑ í4ÐêîT¾(|;HMË‹7‰œ;žC­¡Ê Þvpû:±„ã9=—6¶º» ퟄ{ßöÇLP+ñ²ô{ ¡µYc‘kÊšøã;´‰¿ÑÙ_¦ÄêMç‹wBʳ #sº±›RJ8ŽØw°Á=‚IŠÓ­GüM”ö#i&o1ÁhŸìS{kéQp8=7¯æÌËí6沚ßÛ*Syl³;Å437“…zœ¶éMŠÛ”`ðÚÁÅþ­L邹łrõ#JìpÜ«¹2µ®ZF:æ€é˜SÿÜFôŽ\6•*—dxvýÅ+q%|L<ð$LðNƒª7úœ8ÎT­Ú&ô]íŠ-§¨ßWg»¤*¬ß,JÌ´.œ”Ø Ö †¯ˆž‘TÇ6eNU~uòƒÑ@âf€ôHkt.Ÿ÷`¯±Fÿó†MBà@(…ïs\Ùº{4—¿l¶.Éátäü[, ÿ‚)?fî´ùI¿HÕTx©Í¿‹,úC|%aQ ê.UöNtþ0ŸË0ɼÒùÂÂ웎ô ?ͳֿŸÓ ¬k§ƒs|‹8âè1¹S<—¢ñó¥+V®»%kD>l3:´bŸ›\×Vó½kÒááܪ‰«„Wÿ(måúÙOC Ð.™áI‹øš;ö¯Ðñ:ä•<çŒN5¦]r/¸ì½Õï눰S‰šÚï¥9g‡’.ˆŒIŒÉ›u?‡,~:1–l¡øªû„žœ!ÿDYã-¼Djq=ü’€€¢òcÌñ³Fâò2ß¡’”M¡;v#ÆÜÄ…ovZ·“#b “QÕhþ|žè»ùÆ“âö?ÐM¹ÈbláS;ëÀÓ$ÒDžë‚ ÈΚs†ª-+Æ..”¯"ë7Ðèß)ÈëôlO³ŠXê.Û"qNö°Nübßøì‰’ù-Ç:GÉçì³]9¥~,DR½Œ— xtX@Ï%cR¨YH\Å8wŒÎ*¾'ðý6œ!Òæ«ÚƒÀÅÓQ±5S Êq¬’æ3]Z‡<"Í=B×7…ï²7UÍ{â\¤^«};2<²'Æ/œÙîÞ[ßÓ¨’I¬å¶º=h8fÌí-n <’ù#0\F§¾Ÿ>Áˆyí™­y<QkEÖê²*p‡™º«€AA!Wf]å/,XYg?MÁòpeC–0À–Ô¶ÆÕxN-hwüž€ˆB9ÑàÆ7?ÃUæÿþ›/MjÉEá›ßhyÌø0Q’ñOˆòFØÞýyÎW­—T\ÅÊ{L+ÿ»'ª z:“"×%PÞa@á¿yy¶¼I_’ó‚3Êá¤JÃÒ¿¡ƒQƒ²JÔJaѧ}ý SaYyzúµŽúôJÞÓbD•´^Ö 4øÏõ°ó}šúå–;©¿íüñv0$àœ<àa¢R…'Ný ïEž÷©¤Þt®ÍÌô»5§ØßC’jƒ‡ìDôrÝ{ã†?k^W—‘†ñô²¡ÓÛà»nÿf[©Ó@νU$²×ÁK·7= ³‹9Q-L÷ÑšuŸŽTçDt¦Nî1rÇ3ñÕÖBç~e‰«_íXOíáþcsδö7 ¦þûr†W¼_ÒÆ¬äǨûº¢?ïÀXv{ï´‹.ÃeSñ¾âe[>¥Ÿqÿ„…ŽE–Š>‰6ħˆK `ÍFõ=8WUù©z;Ò—<ì—NáÞÑñ#RJ=I’vwÌ”^¾KÊÇk´¢ò–ûÚÿÆCÄQmË«Š  #‰Ö‡ñ½¸¦|Vq­£ÖdJNóôcÖ— r–Ä í’ËīЮéÈA£‚æ*ØÚ,¸.á7Õ»ž¢ñÇÕ\{¸6¼¿•ݾP™HÒdôX¹èeD«]ò¿¾ ^­ä9ˆI߸ÎâÉéŽÌ‘’$=Nx Їâê!õ†¶|†ÚÌŒTg뛾! y¿&‚À‘Ö­ m8¼’€€%|lŸÚ7–˜ºPsP”8Í,Øsщo¿B(1'³y^S·BߌÜbâT$~/ødöæ€Çú«q=­2)Ø G $~£õ ÍN ÇtQÎÝÞ]yYî;‹´ÙUüžùMÕ~éBwÁ+åÜR難•8õ±’°Ù:Iw$JO—£®ÿÃüu÷·Î‰“Q'TÁ-BÊÖÇØ„zÃBüÑÌ•ñ„ò­™–ù0éRy`“âN aæ“S–heýŽÝûµÜ¯jmÃPPœÉú/„pCïsƶ,GR9TæÈ~Z('ð·Úþ<ÛÙÊi±Â%qu€Ö×¢T3”½£‡3L šhjøˆÏ¹BYÆNa³ëÉ·,'¥9@—ëÀ˲oïÆÙ,‹u¸^³8KãzÙFÎKÇRNòuê§Öä2ml&O[d2Š!Ÿ9E«T½ ×̨Û`úúvüµ›¿­¬§ßóJ'±˜D£ÓÝ0áR*±%Ûëmkؘ~?uÉP÷‰#ÿÕßèuÿåHx‘÷‡¬+Ì› ¬0M'ANuùÐ$%KÌ05õ.`PdÊ—±¢rÂQ´w<¨\Éðc7¡M‡ÍíׂÎ;M©æ­&õ2þ Ð]àS0{ï=X9ŠØ·{! u¾"½Ðs™ø\ôdÙíáð®r¼TxÓvaË¥vd”¯ì¨PñÈü"ôGÎÊßqrÝ{(Y!(žX_¹c+!°\46Tf~uÚï½V›ü»Æ(üç z'nhEA—#;©iÇØ_ c7ì¸-qŒ¡ñM¼õ’wá¡/$`å ¸ø´–õ†æH$€û‹Ð#¤C­H>±¿aÅŒ)ÉÒ1È?W­Æ†„7“õs¿:ÊíÂǸ5ÖWÁî:²R‚U  ì†'”mzý”F\tfÈ¿I’ÉY%ô¿• .‹°Ð×¢?Ý$¹5â5 ɵ!âéâÒ ùáTèjujòè tÎZ~¦Ò:‘½àe•Xž‹1Ë¡ì&í3>³hºÿ ÂU+nâT¼eèj œ@ßó_É÷CQñçëîAh*Z@ÇaÇå;Ìn/Éd•KþDP.½eI•ë¢W³.³QèÖr¤p Êг:L{J ðýçÉš×n‡º?‹# è“|¶õ/\%(ëüµõ‹ Õ s¡Õ\¡Ë’€€Ë±mvˆc‚¢Õ‡Ót ÒöfØ)aaÑõçWðèUª¹öµçãQ,7†„¼dýþÑžh£½ñ -”ƺˆ™–‹¢k“ÅOKÄèH?î¸Àwrב) 3®¡Ã‘^LŒÖÚÍÙ'¦òqGV0C„L›¬@uV¯0ºÛ°ozN!Ò–ì¦[û–Y³ÊÓɤMlm/K¨£—çìUü`Lä2Í<¢hX4>‡‰ž]®•ë¨Þý)¤ÎFq&uŠvÖ5+ ~«uœP4HnAoA;•ù¿Å-î¢ í w¾jÌá ØÊN+qtãÈf¾Ú€wÓÒT)‚R¦ÓzÑ´ÓLy9O.Ã!ŽÂ¬BØ®‡ÅõÈ{#¦ Ãū߄()j!|YþÜþ¼)H-—^ÑúÚ3.[^ð‘Œ0•÷Öªw>ŽTgQ`Í¡)䔱Ĝë»°²U(O_`4´fû*ôŒ/Zb"K%æ=<£wøä;6^ˆ4-…UµEð°ø¢-jß¹j’ ))Üï\qWØy"•¹xñvD½%ýŸB'w´Ô;†‘c©è`*îsÅ,ÓÕ"º$öQ[àƒª%'ÊŠk[Ý7æƒS pÉЇ„Ø®ŠfTòêOÁyA:¿›Ã‰E#Ð\Ÿ5-BÈ¡_f2™ì6ÐÉÑô‰·"é)W¿+޻Ρα§G™$ŠMO6öz´q¤n@ùMκœ•Í‚¸‘=7všaýÄZ劵Š[³`^­âÉü$FǾ2^|«Ø€dóTÄ1n¹¹¢>jÒÝ2ÌAðŽk:Æ×ò!,-I°+z-§ûx|«(èÛÉÕ=™ÁKÀÎc‹žšg;Ç ÝŠf½È®NØšC»yáfOeƒT½X õû]à¥ã(_¯þGO_jãÃ¥ºè„e¡ŸÿÇ ¡U› ¼Ó ô¡„sÔjA÷Z ‚RL]G2eópšPíOv8>} «+_°Ðؼ.ïr±ÒHWKa5_:Fý($‰•ø}9ƒS•oSRˆˆU´}Ìÿ ÛCƒµÆå%yÉ5§7ÐÑ  µAFmB OÁݰÓchG©ˆ9±>óÁÕQöìIÆ\xûFé:,±çâ[c yöÿ÷ J‚Tš­I…šQã³rÉŠ7CŽ’€€±sï8_GÚïÛ…Ú8¬`ùpίÊdȳYòeÌ×’ªûMM›Œ™`ykœ˜ðhý$ oѱ~õàÂ]¨ J†ËÞÿ>Y­áCɲ Aµ™ŽÚ€"J*ꟷOWÎ3ˆÚÍ.¡Ùôœ~¾¿Ùµf=ʼë/_(?À§åΕ×TÉö¥yO÷¤ Áz-\Ž˜(Õ)xûm¼Ç+hö àY…¦­íɘy¿ÎíÏøºd…J.a¥0uxIè ±jQYnõ¾ èRJj >ú\èÛþÚÙ8ŒgÊøUo€’ëËI5Nˈʉ'Ÿl@v›ÖÍ%„¤Û'üÊù°ó'/j«+"Y%"]ö…A9/Ø4žÈ{äÙš ¯´•~óÈ¦ç§øs¥,{[?d¯ÀW—Þÿ‡ä§_ýïMƒ%"©zŠM|líL”lÕQ©ï„xH/ÓÂr»¾ÂÒßfêÉ•he½yÖMn-ròòå]㮌ª{QºŒRÏ|(*át *²¿CÙ¿¸Qô¡k¨±&Æ J,XPÒŒYc-S@5RžïÏ~ð8Q„¤!Š®qϬ* îtÚáÝî(v¸ÝDPü®%«ªšªå‚~XŠîNû&v…ÅôæÈ–.]¬+¼GZ|Bœ‘]>Svb‰ä€@ì&úû3]ç·ÅA°ª*ÀÃoçr/jר’W†œ&ø©§­3»µU˜Ækù¥ò+€óP4”¾™®$ÆŸGÎj¶‹½´8EØWŒëäc+ôœW!ЯCR8_cj&c+dt:`H–~aA¨09$`J7Vð0$¤k‰§{h PƒEZ#Ä i˜÷ä]‡’ü Zéçá%ßÚ7”ˆBk#‹ê£oŽçÁl¿"z¿e]ðõã{ ùõ²õ–…¬}Ϥ˜¶ Ù¤ãS‹ô®îÕ+vK[må,ƒb=Mý\µ’½i ÎùÃÖh¾Î2ˆõUp»þ,¤UË´1ö ÓÈÂÅ…ˆÿƆ(©Dt n¼<®øâßiìès¦¡Á_OV~/+,™a]Gq¸#@{Ðg"É#Ý®kIÕŒ‚"ãGÕêäv–°}fnä¹Üÿgïp²šU+bKšÄw}³;“ÔÅ ÑÚ¦N°  ½dZ$¥™^Ü;ꦿ¿wt®=c«’€€©Ä™¡>9ùË0py^w•XÙ1€Ü ›ÍT¬·œøÇM¥“ÊFJÁÞÝã¢8ÅøÌ Œûº/£µ”WåáJ}¾BÛÇ0­éR¡'.È8žjßx²Qœzwþቭ äªó‰p篭”Ãíza· Fõ‡èoJÔسøuÂ3‰ÈŒë}/âÓ®ÛÿúŠÎÈ“e˹ÉQŽçn8eŽ×Å÷+cóäɰûÅn²+²¹KŒå)[Øö‹eFÇ’­;³$EÃ÷a²Q/ ˜9 6,pÑc4O¼êØ1©hô6uAóWTàZÍá¶ÐFîXàM©H«_¾'©2¥Ã¡ ¦”y~8@ Ž¢ÅÒ<÷89Yã]€EIÈsòÌÿ­ª:þ`AìÀó™uQùȲEØÚ,·¤ÓŒ²Cü¾`¸I6{ME£ô<¥,îLþ*æÀ6K9JY*µ¢Ø‚^Ý_€¬ ‡›L^@´ ;H'¬ëT5ÌgBk¶k¨uÂá¼­5¦Èù·°æùh*ôaéØálgú$FÛã…/˼nÖ`Ž>:&☱j÷US1Z¯³ü¤›­|VªóèØï<|gMzèk&× SE5S?-¯Xëñh½ÕWýBêI8lV¼£÷EW_à´#íl?ö(QËwüôù×W`â‹„NR u~m“Ç…ùÖah¬ï:÷³Ö:\7Õ®BÆ l¹¸4ÖMØ8t÷"  ¦xãÄÞlRLq÷çÜZnÁ)j̤Éôê0ä—¶2Ë#E8G×4àQ†A€ ­n‰~¢©6(ÁѲLÊ Å¨vvLз*z0;©JË»•$‰Ä—'ÑÚÿ0ªWˆr®Fµ«µ%-©c£¸H¼3Þ\Ábý®þÛFñä³fL6€¥E¤Š(gËiMT,t ç&?ñxÎòê»3½ÊQÔˆ,_:𗹓7ñ9\®ü±Rô²X[l9œíþ®6¶OÌŠF¼YÍàÁ±÷¯7ø¼“ø?dŒXâ·6œÍ³#ÝΞ!:÷!h& Xý‚†JÅ% ‰‚yfâÓèwHgÂ;І§ôi¶´2`Ž\ :m"o–ó´×C1“9˜=ÌÔÎK›/Bh=תLÎÑÂ]QŠr®Ža¶ø°„¬7ïp¯² œÏô °Àç“Hw6Ãù=lnûàûÌ–zNf®úl¯e¬˜q8Ô×’Ópš¹üpq•Z(lþHjâÄäË~jrTjM =}è6é®°Ù¤üx ?њϓÃÉË*¶¦;ˆ¯SM­É˜S.Ô»ƒóááĨ†y¯Ølž®KÔ ì¿JD¹×>ìo“CG£‡«»Ç/¬ÿ¤=Ó®€Q¼*6ÅJ1Þý÷#ŸªV+%yXp×Y"Çy¦ëµ?öÌÊÈ…½÷Zâ§Ð8´ß9wHCˆÆ,Üîx: jÊ`#Ae4ãQÁè]Ó½¡i>“:ªTŸËgÙB’}ýì'ñÀé¥'l£¼Û%YÐO19è9‰‰z”3yàì kîm<âŠHç&“ÎÖDT‘•ÁÁ0m(’J¡©áÞè¹sÍ¬Òæ¹e ­òþ<“†µÙ"¢K)¿arδ"±ª(ý!tOƒ¥ýZÉÀYÞ]¤Ü­‡9¶S_%H<)tÍðwׄ’C .Edðš×OŒ,H„Eˆyv{T«Õ®—´ÀgÈ·mÉÌ*5‚)S-Ôq2P[(Aò ³Ä“ ÊÝþH®i7ÈU¾ySv°ÑŒó²iî?sãp8 äý¶,-Â1W〮/c€m’̸"Ì,±í™´{¸¹“s-Äèc/ÇÚ®>ðÔ¡}ö>ü‘"G=ŠjW(× í–y’€€±*FÖ óø¾oó…øë±þ y¢:æ ë¹/-_5ŸÚ Î“`'¹N­¯:‚®P‚Ó±äNñý£uD²°É‡Ë5ï¦5zoå`gÒu]O*—ôQ] JG‘bÎÜ…ô¨i×DCò¬œY_‘5Ï ªØÎ©ÁزlžJKÄܱš?¬Ä &¿o¸½©'«fR“¥ŒŽZ–›N‰LqBÏk,¸Ì}{镟R-*…Ô·H¼~$Z­˜MïXâUÕi¹’ž¾×u‰·Y\ê8nøÚçEËX”ž#Aø?£øø.XÆý*pÔÖ°»Õæ—á'XS>®uBc]¸£ç0ž¢!dõ<Ì-Ù“RÏŸ¨øK@¶ŸA ÌÆÙÑ-Õv’†¸est‡ýt&™N« Q|¾íþ)¤KbÈ€ï!¨hô<éýè«ôÞ%!óhûC,êʤ‰sN•·T;c§[_£Q.™é^„5ÁHh ¡ä­²±ã×/È,íðä[]ˆ$¥Ì×FàYÐK·ð-f†¯£_µ/òÒºàh˜×Š_äÀåcÓNàêsE0’–±Óod¼Òi³¤Ÿ$3 c °¶æÐÓ[8°6£‡˜”ö–\š›ä)Næ`É¿&bÒ° ÓZJ³e_Ö+7aâ¡ÆÐz ÊD½Üó‘ùæl‰‚põbZVßie1-S«@^A¸d„¥dém¼˜›ŽæÊÈ¿ö .F:û  Åps_ÿµ•<6 €±á‹ø-Å»ãWMà™ÓÒ€¢Ú¿8ïwÉ~Npe(:°é°Ç£¸ö­«mb¨öšbÌIvp, øzƒ=ÛyEª·ÅÔ"íô°÷Äáí_kèc'B±AH…£YËݺæ‰íŠEå¥Ã–MY.YÿõîW{d™e¶ëÆ ­â,8#o·woôÇW„â¬Sí‡mÕó°.wâÈ€5àÚIe¨=¸1·´9õ'úâ|JÒ?ÈCL’€€¯Sç×Þö7 ÓT%Bú'wó9/é/ýœm¾€wÇç•oDb¤NEôH[ääçHÓÉœz©×ÉVõé°)‰%ÌŠî´ËFt˜ˆ¨¦k•qûc–UOh'¾a Î0ºŽ,IJÌÍÛΩÎì„6á`¹PÓ=Äh¸gËìe¢´K@t&9çô3]pJÁ«!œîþ蔨dYÔ«Q{Óß úIö…íÌœAMѬÍh#Üá8±Á†X“KÓDµñ‚j¦4ƒä„ÕÍ0öL½Ú^ Û:ójš/;à›@6*Êt¡n`r”š*ËB.â÷©Ìtíÿt9¸rºƒÑz™ ýyùí3Ê•[%;Å—˜ÈsžôÖÁz¶âK««ûžÑ¡šµaá êþ`à·)Q/ùûd ~°.ÃÄút.Åà[v0É„"ƒÖòaÚ¡“~Ì,0U€(Öÿ˜7ÆÿX$5JÆmpÖ‹÷m¿¤B&…2s:ìâÎòŽ£#¬€öÍÐô¦&¾O*éþÛG ‡x ÔÛü]ñ XÜÑØ8°|+NÖ!ƒi#µ/’¹w•ˆ–Á’ꉺqt¾pHa0ÀacïÝ6ÌðáÞIÉ‘( ¸7ÖRE"`Õ bÏ}Öô{ ^ïT^ÝR¬³b._òZÌÓµevV,££$£Ù]0ÿ5”_‹QO¸3Þ|‰ø¨¶‚nŸÏçt…nåÙÂtÅáNœ–ЩŽ¹ù‡iH™â§Ã!x¼ üØb¼h(…ñ›Í,s^Oɸ™ðé?Ó`Èô3Ï÷©9z5e¢²\’|~е}ÊËC–•†Ü‘¯q?@—¦Î}ërH»®TèÞ z>)“FÔbµÐ¦@1÷Ö|‡ŽJõ![Ũ½Ðƒú_¥´ÄÍ_ ÛÍøþ¬bV(W‰!6H‹;¤Å‡˜]‡óÕæöóÜ¡J‰®šcÆfò!ä:ô/6MþÅù…–ø»“G“|Ñušüž´Â@—1YmVD™Å¤™¨Ç²­E¤T´Fw»ìP¢Øa¢WrCY{Æ1uþJ› éƒ=÷–ÐMzAØb7 œ¶Á+S&}@5uõ½TÈx:•J¥NƵ{R<–·ÞÇ$̦“Íë-h1¨¤Ú[…ÆéåºÅìS®~µƒ¿YŠï'Çâ°J³º ¶%¡5Ê’€€ô¶™Ïg‡$1 Í) †åÓxxú=BHþUíy£½:ðÿ5Í÷Ú? Ø6-,ö§h™•C眚ƙê‹BäPDB^è;›Ë˜¬àò ¼Ù‹wì‡|à˼„#˜<[¥˜Ž‘ü‡&hÆÜd÷Ž¨Û±™èy)'‹g#KʨYL{­½Åãݨ4d\!¥g„‘CŒS_.ØÔb»Ã Œ\'d{Îè/ó«2÷ZBòMõŽ6ý˜A²ùöµë*mã)Ë®Ãþ™1UµbÏwˆ©°uD驺f’5YVh÷€Hã(ÖY^ÖLlñ;b…¼«©AþñÔs© ¥iÅ•ÒØxéF÷(6rˆ9…6äålù` »œ168ì±%äË PóJRTãiÈ6"×5)'/n« Æ¡? c"Í>Ë™NBã÷QZõ£ôÑ(¥Ã-TJÔ— ÅÔœ=B¸ßq'm`}¹¾–À´µú¾~åžw[ô£½XÚYr8qQ+OÖʉÝ9xß·t124 ͨ¢ã`i¸?Œ“ÛK6V¶Ç¦]š°äUe”;ÒUhè&ö¸¹+ödQ_P^n¥L½9µç´–[$'´xÿÐ'jSOн‘¯FIƒœ¹¢6œø¡Ê}26wÏ!ª²dÆ€ Õ¼Þ6¯~‘"_4¬¡VÚõiü–ÎøÓ¿²ù—#Ý>•ª¶œÂfo¥» CÜ Ó&~#®|D( pUð#rðù¥4œÇjÚ^Gìឨ»\dèŒW’ÿÃ)r¸°hµmìe>†˜A™Td¶õèö¿Ò(&¥ÓѸÉà Ⱥ,#òá™SkmùþÏŠŒ•”ýøÐÝOq2Ê¿ ÏŸoüLÉ–Ê)‹ ÄÙ@Yº»ºDòGìEhrfé¥l—k9k{8áÑ?¡«Òp‰ubWFƒƦƒ}Æ-ŒªÍBg-ú9ȇ}J$:!Öñ“`ÛfÏ@Au#¢b”ù“Ù¹†R€©¾`ìˆÇ×¥@ðêÙªíPíï½,ù¬Û@à~<Ô}4†2S{–¬µúV*þ2ûx± i)¿#3Øë&ó•"Áìø Må”åͫۧ.BìÖGΈEŒVé’:ت—’—çeñ^I³ò»@1›Eý9*BO|N´¤þ ÍŠnÄ7…ß0©}Á=· NëñZ-ø’€€ª%èž` rð÷o8¹ *ð¢‡Z·\ÊƒŠ˜u_eówûsÜêuØ"nÈné×OxÛK¼Høƒ±ÁFâÚœð”åÑ`p†x‘ÞÜÔÑ= óÛgðyJN üm螥ëcšët{¿}Ô`™×{³G>åÉüúš^ˆŠ¡ýv‰ý‹­ ËÇÏy£Þš¥™?÷$¬J:'"ž¨>ÍEe‘вf7Ò3dnÆà|(õ÷´b-CmÐ:Þq›3¿úZÄ‚µm2òbHIŒå¼§:^¸²Áé ƒhG²¨“±»‡¼›ƒüî®eÛã…Ôxž™þLØM'\¹Ò;× šlÌuº•»Dò?#íþþgåø•ðI ÚЂøàxV¤$tT• ¡¨Š˜ê]¤%FyòNP55¤ã^×%ËÕž¦Ð,yÞLÄ.]z`m9n øþ™@—ÉÜ\çš¶…p`ý¼ê£éKÏ×ð+eœz' Øy£ÞÄ¿ETþ¬ãQ9øæ¡ j¸fcÔÀx&¥ô¤3.Wå×É|H+¶Ë‹ G°•©èÄÑìV‡o÷ÜØ¬ëK?èe]rb€'IåY Ôö1jY3NY7 MÖxgR¦\rB/fÝk¬MtèùüÏ€´BL® –ûK$SšC˜fÛÂÛÌ,ŠëŶ¿žx…Ý`hNœ°lq®€Êíø“ï,Âß)Ç|’Mw7d…O£3¹åËÛ,7ŸˆñO2«ŒzØ,ÓÉ{EE}Pyý+¬H‚ù^,Û]˜•µ}¼—Û¹fú¼Cz®lè†&ÄÄAIhi©ùrËú,Ì#l%* J²ò¡‹S\ýrð¢ªÚß53ƒòÛò ÿ•vt4â=i !y ¹\Л±éø¥€·‹0… 7Ù3Äì[s*ž÷÷›Gš¢Ô€Ÿç¯mvr¼’€€¾Ź@kÔîŸkгðA¥Ì_C6 FÉ>ëõ6å!³R„óœûâ…ÍìïóYcTºó2Ë´+WE¨!K1œµãi?‘ 3Éÿ­ãg÷Œ.o“¹^o®xØ~"ÚÌãÉ_e\eÂÎ6| Nß@tø«m2÷¾G^TBf#þ5§tçÙôe¢# ü+׳DËw¨/Ne’«?YD[u– áö'S’3©t;—BgdQ{-m땢㚡¦ RÅüÌ>e1…¥/¬—1Ðû%yýp+ª7 ‚ëÍ>IŽZfóŒµãÚ¿EÐGFBˆOrAN’(ÖÅ£lX@¨W=´kþ¢ wšeÍ(÷4²ÙfH³¡Ñ¢ÑØ‚ØôI¯f¨ %“(@I«ô˜“Îð{‘ ¥ †ÚKµÄ/¡à÷• ËÀ®µm¥@‹µ•¾SÕÀ¢ !’óö#§¡©ÁC^Ôà]…AÜ6Â;ý”¾ëDea”ÊÌâßÑXÆ••¥BîR¸uбDFP ºèw}º,À OçÀÜÝ–Ð+9š:oH< (¿¡íiÆ‚|'3RR%–”¦ac<¶6â /dêkb¯—ܾMÌØ‡ò _Þo¹­­-ߨ¼¬(‡èw8ll÷ôåèJR-iáŸÎÇP–žVá*³Œ=Ð)è:V±5q8ûh󌻈U- ©Ö—K_Û; _ËSýÿvÍ`ÞŠƒô¤’ݧé=!Õ ­5+Ü…a¾‡†ô ë{Öª2Eiñ?ßÓ®ü‘-ahOcEê- ^íhpï =Íö.¶û’V¬ ÞÜÖ°–9Iw îä¹$Ñ÷цTUÎQP&óvþ~ª3Í×’/“ýY¸ÿtNÆØÕ,¨X^%; (¦ü_^ò¤?ÇN+X.R7¤/-°>̼fÆu’€€ÊúˆŒß(…f@¯ÿ`Ù£|¡ESO‰õMG‘ÞÉíƒ"{7P .lGZ±³ÙéÏèô:³EtêÞ>7¿¦­lÌ­à;s™#,Ò{õ¾yRcÚúP${s¶¿µ¦B*qD³ßý´pœ57ñj­›+÷4ͯ\_;K@ ­<಑U¨™'x×eížÃÉPèY™©nÉM7B)Zö™íé|¦Ùÿ¢Ê®@F„’©!.bèt·ž„fbë¶Â\A]æbô˜dWi-dL(=+ôÄÅÀ‚e¨ Ü€-‡××~:*ƒcõE¨¯wo]˜ÃÍÏ[Wy9ë†ü¼0ß7§—0}šXè…h…SX†‘©„ÒY+Ôd¥8µ3ˆ®üº 1¦R!äAå© P¿±à–B–LÚin9£\f[g4áñ8ôø'›%‘‰©ÄH.¨cãþÅ\ýÁ‰zk¦Z OÔ€=žxú wË/¥Y݉c¡ªh"ÂÝaÿä­XVܨÓJøEç@ÿœ:ï<å²¹USš¾éU¤ç¬™‹ÓV¹åzkÎø†±‰=2ºé¶å-(ªÝtLèV¢^UÉ\&°¬ ²R Ü?¸õëÂïÞ” =0g+ˆÛõ)¿íÞìW|õÒowÇ‚:gÈÄ#ØçÿËðßA¬@ ÿH-êvC"rµà% ®°aFþ ‡EúøµÇw T6†ä¹“°–oâèév€€(7¤ªÒÀÁ}½‹›5ô3ð~* ËqIÍùc~€‰\€Ñ˜ ŸÇÏ3ÌtN9êFT?×P÷ÞÌÆ£éø›Àt|!S[×bitŒËŒ±Ó†ï1Ç»>ƒâƒ¬wi#ášÄ Kè17áBÜqÀ.z_Ì¿’×hyÚ*tÑ“CO€ðh{ó³ÎAK]*p>\¥l_ØØ ‡ÐK@M‚<†0!Dã5Ï`Úgd5ÓTO‰Y ¨ÎïpvÒ[±¾kÊë…mbdg,X¼+ùΚæäC´EÎV¥ë˲ Œ†[»Ù3¤æN!­¯|ÒЇkl[kb„Þ¶ÄFf‹1fåíÙ˜l:O0¯pqñ±)˜~E’+úýIÏŒö½6üSf;õ)GQ§Q~øÕizüYæñÏSF³5K–ì*_J²){³ñõÁÑñ’€€¡],ï ËB3¢N¤-™T´y´³ÖËþõ⎎1ÜÚ¢ôGñoÚÀ¡mÏÓÔá(„rß2Öðò‹à£ÏRÔ§Ú•#ôá¦öPÙÅMtuc¤æVŠv†X5¿-‡tõS¾tï1ØÊj8ñ±…6)¦ÚÂMhÆýC«²¯Èláݱڦ,\Út(P«vGÁ‚×a‚Ñ“v<p1á±ó‘dÿm;IN¯œd0³”:+s{PR`û‰6ŒŸ‹êS®ËÛ.%éÈœÀîRñ8ý»XT’NK1žÿi5¨Óf›z4*}Üô÷86>&&%¬Ìë²éä£ï¨DÛج9>Ê¢pŽI …Í1t1ÐC1‰š6±w›°“Ø5°&Ÿ@¦:‹ÖO›iýèëk/Yñ§Vl`Å• ;D2}ZºÚ•LX:1i“kHJ†ÁQèßËÕ6h‰rÂ? — n;â.µ‰%A9Wo)îâð(mDˆ\ÞHÂø‘<…Ùð ò¸£ÒRdŸý¥›=¡PÖ°t&ÎÀMÀ‚ŃÁÙë Š v[o:ïÂÉ3~Ãi;H¦ nœÍ"^Òd?ätY|H[Vw2÷¼p5Žo¬½/L÷Áb9cŸHt û9PFV– Úcü©lîqjP}½…¹TíH:*¯B×0>yʸ­/Ôo;ÃP²‡­[7ewáå$ÉbrˆÖ„‹BOêö·þ~ûb’Óê)†00¸ˆàTSS´I¯)¡d‰ü=¤%ö{eœ” 5ü.^d}¹)­³ƒ‰9r bç`s¥P&‰ô¼6êÖE ¬\Ì'….=‡üijÄÎÊd)êiªÞõðŽÝª4Š¿Ât¿æݬ CBÜnqëâ݉83¶œ€¤¼{ó4wüÅvÖ‰“ù°[Qíl„ÐÍ»÷5ÑÐC«u–òü^Y†ˆ@}Óœz·]9ÀÐB8Ù\—öH4ÈÇ"0å=ŽkšÎ2éÞ{*6eñî¦øùi¢öëO¾CâÔP»1Ð\¿;ŒEèŠ×EÓ®a2Å5“¦²0_£bå}b† ?´]ÿÌ5ßk +!=H] é{µ¬¹CÁýH-þa«tv/œñ› 4Zû H°vB“Ë8ç.HæCçþ%çô>(‘¡rý|ºt<[ó÷JÔ ["‘*L!®Ã~N¬’€€¾óÒªÕ [†ûš¹ÖQ«DÔÐËŽOqÜÒ«+^û_'¤ÁäZ â§£ww$ Ÿ>o™îl‹°rsË—ÊJÇÛ»çêr+šÅgE›¹ï>“V_Õø¯‚íºh%r7_g3{üfgÖ rN‡šýáeqžãr”Ø‚ŽÄ„É" ^ì(×ulK=³ö± #Â÷X!>ešóÏöS–«\å!ÄtH:yÁú¬¯—¿Kÿ>Šf•Tó|ú«ºÉå˜S,ÿævÇz ˜Íí‹*«ÁpÎT`UM3QTØgNP³‡ò¾!´ãÞ¥Ã)\Œòb)ÌÄ@øÕá2ó®- àñ.j{ðåM+ÝGMߦ%s5ÝšØæ)Œ1eŠ9qŠÙƒo(¿=êÑ6-ƒc»€ œGé _ûÉ£‹g) ò¾(†v–Lî—wFºãÀ]ýàèYKGò «©8N—}8ù,UJ‹_32&Fl¸:F“ýò©E÷哹5«¢"¸Ñè“x™CT¨; {âk¥°ü Z‰v3˜»T0úÎ1ÔYG5¢ÿÞØiõ‚7´³ŽSÏCç‚¡ˆÅSýûüÉØ )4ÙiØ›ÈÑ€"ô»Éõ^ÚFнØ5 /Ž"4ò Eeͱڨ!á‚ÂõÊδd¿zç‰n§FåB§Þä .ÀO:ûud'Ý¥¬b ÚÇ<å›Ú›-ŠYÊ–¤<¼9óm¬Ôu£Á¾\ìK³Õå .?`ñÏŒa=MI)„ý¹"°ˆŒ½¿m–®®7ð|‚f³ÑÍp!Å›-Æ7±?Ñd(6+ôr…øÃDüO¾êBõl™ç.G}Î-‘Çùê¥ùU¥Ï|kîâ)4~72¤"oü/º:~S\TãÖ52ÀôŽswV)`0¹jáçr}‰(U–ŸåeVñ4pŒ>;Diµ–P*’€€ÌÚBPêá¡(Œ";±¿ü—YXÅXV3ÌÙ§48’ö§9É¿¹¡ñ•V;-EDiÀv ‰“™ST/±·<0'Ìc šjˆ~ô,í|óêd³h×!| ©j³JDÈb$ÄW;ßb}yªô»Ãó ¥Ú úÔzVþî9JôŸÉ}ÑgÓ¨¶i„•À{uÇ}Œ×xÖ9!yøß>@n$&›,'Kùóe"pfÀ%u¹þzú¥§¹IAe¶2K{9Sò¤¢Ø ÿ ··Ðé«ð`¹-W†¾Öé§À}ñ£°Ÿ’ƒ‰­LOÝíû¹±ÞÄ{»¤‡4¥-L»aÀˆ¸Ì¨y9g,=L>­=3J!Ï9å]rlRv0’Èöèú5ŠGûÊ¢Öjœ pNM’Mãð`$ôxÀÖražã•ª¬ZÖDH(xW!ªÏIN7¸víÝsaƒ¶ìÕŽ‰°Ïùä©nzöP§×Qb‹Näû”U¹û0ÕŸ&rFÁη%…åÚ ÐÓ[kyý x 4 mÔÜ Ñ‘çì‡øã]a ëðžREî–šÌ,5‰•:«;{,‚cZà¹e”×ä‚]ëù1ae/¨#¨ðùÿîh±+‹>XD*úwéõžÊ-d/:¢S \oÒ^ˆ%¶9ô)p˜L¤š(îåûŠ^ƒÑ{_ á͵ì]ÕQÇJ_-?Œ1ö„¢y‹lôº¡È3M×^»5NÞ‰D‡8*]q„olá®Å±ÜqÙ¡ºÌÑ“ C"õjV™Ù½!â"-¤iĩ뼕Ý%rò_"Ùƒ©„‡bG-ZÝS,Ä~åÔihn€@áû"Dî&¯8hÅÍ¥N°c Þ( š†”@›ÿ¾JæÊ<ʆ7B×x<Ù»ìR‘UTMˆCC¡%Ìž*÷ ‘©Á_5é—¹¥¯õ–-®.-½<….²E%Xó5'’lí*¬P#Çe™ØÍ{~ü¦Y[4TE‘YNvØÀ¾£ó¢ØS-çzd™AŸ€yó«¿]AC)ϳ ÛÁ•}VýcöV Í×;1z²íú¿nòâgn—ï˜br}2¸³ssÔðúíW`RG ‘Ðëd%†s¼Òü9¨|Xp¾?CfÀáÞeʦÐR©hçØ&#i´­ëÏMמ´¥Þ‹êß•b5Ž )ØJõnòŸ† ö=ÉkKªÇQ«j¼ôöÜßµûÉP C׎ÌÌü '3{ÊcS\ˆ£`pŠìŠ’€€¸1ôãÁnÛÉ%–7¤ë๞e|ú‚ÚÉ¥ÞïêE¼^.Iîw´·ä°ÈÖ ×⠩ߊ%+`koÙâ.Ø2xšîiŸOÎþ»B•J†É0²fzsóu™{_+Õ< çÎÞ9©H5é ¶¯°u±D²(ëùÅ÷ÅË©–ÆüqìhoUúsõy¸À°’x>¸ÁoÚ3û){¿lF†€Y· ºš)ÃÊý³íSœXøZk<í1ø6Ýi[;I&T]yþNŠ>:}TÃÈ‹GþæîX8éò‹,|ŽÜÚv‹´ö#âP-¹ é'ž¡[ݹ³Ì0I)×) 0±,¥7ÔÒÁªÁÛ~0\Ó逵Äià6ê^™??+êøfamù¡RŽïòR_ 15´÷[2ñp„¶Éw5Â3X V:q·2æ6d^€J©gq;Ô?ƋхâñaÛº6OþÓrôËÀçý‚8–ðJ«b^ôQþª•áp"ÑÁ}`Ä<¶òa÷A$ÑÒ§¸V]r­AñëBr G„¹uã¿B1©Ð¾@ÎWÛœç⣛i‘y»›zŠÆ%cS/û³þ"êÞ÷Ë#i39Æ02¹ÐÛ’ço©K­„®¸’üvš$4±Â…‰A_îHH¥7»ÇÅLôqHTUsTgì("Û˜rrð¶[HŒ>W¯B¹C± S¿ëâ2á“Ië™8UÀƒ¼T}Èe88r#e¾ùؘÖZÞGMZ8²sZ—¼‡ÿ§Îúßþ9ñZyhÉTûÁÑçÓ¼åò¥½:ìq r~“tÀ·7ã¿ÖJ䟵šæÜ7M݆g¶w²‡¶ÌÖº7këÓÌJs°˜ÀÞ·ªöØT¹  `5VÖ©“bµ°•Ë™ *©Ìzk}ŽKœZ-‹f¼ø¸)P|ü8®éç´o¥·}mW\›8 „å´W£/’¥îﲨ¹²ÓÂ’€€ÎW1€ Üoëf°X¢UòwžÞl"»ÎmRQ©m‰¢ÏTÔ'st8œ²¬PS¯ 0a¢²-h™sþ’)Þ"ai» 45¹æÚWŠ[ÂÔYðsu¤«‡OWã‚>¸ºÐݧ3n\Û-Añ¿ûj\lŠâ ˆÁ±ZHsæáMó£Yj)J<À/b†g ¿MƒZ²Ñô8ôFÖ>Û£ŽÌéi d%ÖXH¼é–;ëe$™Œõ;L“•gÛ”—a½Y*¿¥ä®Æsi«zO³¢>rÐõwuzßð¥b™a˜õ®eç8©½¯&2êS¿Ô¹«¶iGR²[1¹`óµ>0­‘{ Ý"_Ueá€n°+N37érI[ª¿“|&‡uHš¹˜YY*Kdà¦gXTƒÛù8Qï+ÕÈÝû=m}åŠN’‰5?*ؘT€æUý,ÜR!fýiò,mÖgÎäæI1vj†~®a£’„À 5H_)ä*ÔÜ”C îσƒ÷5=ˆdb§5åød¡@M;àpõ5|\4áGà-2Påèüf€*Q«šèë"YËš®®§$G.ÝÛW®Š«jÿ¹½üËX\ÊÝþk´ù{˜»ŽåamGDßÇk“aœSÚ>ëöL‚YŸ"°ÇaÝR…Æì¯˜_|§5Þðÿ$+"¬q z{íE0øˆf0m*þ'C¥ÑĕܿK—q9µjèVIÙ%"ÜV&ÔŒ3¿…L‘’©æXÔÆN/!+/Ì#ž9˜–²%â¹ ´&7¶Ý+«w»¢¼ßŠIxíîBšü/GÖw³wG?·5[ ¿Úú_×ÒúӇ¡kZãC÷]ÅÅàÄqXÍ7Þ½_|5- “!ÿßfÑÙÆþOžó\u—c¶Óíò·ÒCüz91 b¿lÒ}‡ë{Õ礂Kïì Wås †™LÑAz¨;KævƱ­Iž3véT)Ûõ”Wgë'ñ3™£o1#Z´ÞÄ%Â+ÕÜ<1L@ôFÛ%›y§‹Wì¯SΊ½iŒÿ'ntDI»Ùq ƒƒ´þxÃç´×B|ûü°õì-Gøžót z\Ì;'Gs«H!:¡«}ƒãó‹•ýÅ+ÓO¡« µ€ƒ!øUlVõŒ·`ê⯵Éõªüš%.v! }¯<¼¦ZAƒ³“q¬iê PEÄò `ý£ÓÇþ§·ˆ0…Ó {¥$wªåïZ}KOÌ9²þig¢’1»ûØ5}pw â†pfætãOÉ “´Åé7ãÅGøê©ËhƒüÉO¸kº ξŽïŽgur÷KLŽDÿýÏ?{ë¶v(´!‘¦ÍÝU ER a& él¤_ ƒyŽ;º~‡ÉÙ&™ŒÔC’|HkÜç¤oƒ‘t»î´aè[+Lz1¤ÁþýŸ)ËÆå•õó EAá˜pü¶ƒqH‹*’ÒfN>ïïÌÓ+ÖB“ð’È‚òñ}LÞ´¡V;$d¼T­æâAY`éB$Þ6l Šñ°˜‹àôXcå]úaA¢M^èì<Ë êƒó*¯í¼ ù´¤¡ÝÂÉ>`(y7Çš®J5ùõ”"F}&E.«à9s…ãõÐÁħ!Z~9÷ú1Arz?Zx±nÐÂ0îy, ‘çɆ4=úÃ'¸ Q"øK”•ªw·"ú“ ‡×rGÿ\GQ˜šBÂçlÍ|r„X¯ðf²¿S©åA”TàT+à k´wÛþË»§7"ZæpCÐÖC˜Œûæª)PG3hq%·µø¸Jï;ö»Y8ªbGF«õ Ø.ch@¸Õ6Öc|oâc>"ä`•ß#5HPñÃ-ÒcBY›ÝíË x[ؤ·¬2Ýãk«?~2g(ÚÛe»ÁGš«dKó-s±«YrVc¿=jœå+޾>t §œ³FB«iRœ ±?ü+ [¾HÊÞ‰ÒüÈóþÜŒXg€„ûïDS±} ¾ë-uµ³4;èÇøHÈÉ©Ã^Ÿ«<ÉÂÇDo<4ÖúÖÕíË×8fV |tŒòÉ•©I)-èÈŠŠúú»ñ {Õ©I(Aªa›g’€€¨¨~’èï£"§4è:Ÿþ±¹·vÙÕØ²ÓT,„Ž—/¢ÖÉØ.™`ga „ ­¤Ýl‰ì²|Ë5CŒšÑ´9[}¬¢yf¦ àíáÝJëaDÆoŒ*ˆe·We&·xÖZÕééÎ-”­ÙÝ”±gõ]Å™¥«]5S>¦zžýžYð-¨yàMW•‡Ÿ®q2mýo k pç2HX¢¡˜=ƒ§â²•ëx°­¯ 'Á6“%–ÎnÅÉæ¿cF«‹Õ½­ïÈn/eJ t+±Â> ñ™C ‡)W±ˆ½i¤ŒðV;ÜlÞè«ö²Ãsõç”»œó<š3G®ÓK7§üÁ3‘Š᜛QCJ#wµH?ÙÖ°¸Ùùù5w+üªÌ4Ï¡mkXŠŸ«Ô¢0f…~¢ÒmÃG2sy›zuË1ô¤Àw.Ê‚yˆÄDQy°§[)ÌcåwÏIÀ®º÷R÷AÎóã 5ò(äN' 9A–Õ4}G”™õC>óJNßÛË|+k{BçÀ¼Ð¯ÔNŽðÀèFƒk”“Ÿ2!2ce°Êè×FiñÁÖ̸—9¼Ó§Ô˜¢²[8É! 'f¨TÄ6,{@µ½”¦îÁéˆ{[)Âí¬ IKkL¥+!·}¿R»vÈX(%—ÆèÅ%J¯uþ¥¦¯LÒ-–Ëùr«¿†Ê3ƒ̯…_¸ÃQïØ5·‘“(xu#ÿtì_LÎÃøý´i^xVì? |™ïêU\iÊo"½ŸXA¦ÜÛA_="5аãh4 &DE3úÏU¼‘0g¦ …OÞg’3™× ×JÜUÿ™L滼^e&ô|P >íÓî¼Âyuõ“òõÏt²ŒÄÚÕ"‘Fãý¦#HÌfN°Œ¤Á¹aŽý[ “É+’ˆÆ’€€ÀnÔ * 1ëÔz ¨µRMQRw¸zÁÿV¤S¾\ÁùŬ²0 ÑâJv–.c¿0"›ƒÎ8 š‚Ø:mÕ,ŸhPh¢Ï&_oE—¦<£TcÖvÌd8qýO{žk´~6UZc2,Z[(¼ÝôÕ„òe¢àéÍ#@“Éîçtó"4™ÈÇæ*U½­:øF ë‡f£êtÿ ò°ú8GI d¸ÃÑ­³ÊEwà:¹˜Dõ­÷=Jü>¡ZaË¿\ªI.SžˆDÜ3ómÚ`€*–š¨ðMÔ`0õ|“HÒA$1È!©ÞÅn·ðgÅ4x ¥+ÝrŽ@GÙa5R?|¨çto³ñg×׽ʹýPB ß WsZm)lúÉ˃õÉ7i] ‰½^øx³ yœð…ÆøÙý*Ûyd:¼"Í‹¢ð¢ÆI#Ôù}óŒž×<£¶²§µŒYÛ”uZ0r[‡½ç,šŒ²¤×SnÁ5Cì(Tø•ì´„X’YYœ”UoÖ {P¡öuÕD FLñ©5~`TôŽ:0±Ê9²P—ç+Ø™ÅW¦Ká´)ŠË%V¡X-ÓÊw]ê+º.3ŒÜ\ ŠáP¢ËfððDoN¾²ßfôZ7¥’9•ÈÀÉVL¤§T¦¾ÆCD¥÷0‘ÏéY_¼¥Þÿ—Z@{z-"jŽN%¹ÆàÑ•šç¹1â9\©Uòo)麜‘+B—s$¯½?ô” Y`FF׬ڜ;ƒežrRÍcòÈP²|#ô$oÅzžAQÒA[¦§nkœôô¨Ñûƒz¿A33a •ìÜ–g­ÌFÿ|$Nåå¾?h@.qO,pN;i·‚Fá<>b…´QÕ Ï9ÊGÏ;ºvñ%tø?ù¡ÖNá>îDŸ“œc6»z¹!¼a2oܰˆ> |ß ¦JdTÏI’013ßP>\ ¿Í1ã³h¦Ur Œ ËB Êlvck g"ýü,—Àò‡_÷s‘–u¾Ýƒ ¦KX­<’€€·‡}Í|úq„¾ßr+ÔÇog:#wM¾G@P½ŸVû½ æ\Æuú%¾æô£Ø†½ãäÓ%«Ûà+ÂÚ"™á7H©0¯JÏ*cø°Ï'K¸d_ŽÒFºCÝÁâßÚ¿£¸ÑzWüw–;Ü{…To©aõÖ2¾Ô˜6ƒˆ½›:Î\D­Ùn»šÄ¢õœÎÜ`6ê…øÍ7N÷0c[_€¬¨E•¹Ñ7‰üº=xo*T.Oå^üù Œ· ®/]øk²=¥X4«>22¤æÒ?Œd“ÕXn)¸#Õ`h|%¦Šé`Ï4iòŸ(Ș9é䤰«l¬.$Þ›>l)ªc`0¥ŒÒ]ÞÀËQb­ÚPtÝ5§é1žÏSoÏÚéÜ#dÒ¸:¯JXÄá¥0CCþòz²ÐšžlG½áNÿ^NèäÍ $+£Ê'»V…œË j½¯Ö±ËÑTeþùП´U9¦Dx5CYðzš›ˆ¦P˜àaäÉäOû•‡Ô6d†HPfj? ²ÿ-ÂJ‡/¯µ Ì9ГÏÌ!¹å%ƒê%©“ÚYư÷QìOÐhþq/öf Ö…áØâÓbö§IÝËö„pQup@µ¢ æ‰_ôÛf.Š ©“n9×½h[ï™ A]¾«@…é!éЇ})K¬Ô¥:%©tL#»ÞJµ}ܵÉLÃ÷Á øz|;óNé×åGÚºµãA9R>ÔmÃ?D¶ûœÈ£Ï‘ó¹ñøŒÃ:õ‘½yóK\.–ͯËQ¨hxÀ´ÉC‰’ç•=Éb”¨ ûBØKêhV*`çt}-WÈfBæV^ñ ƒž§•î. ö¤›¯Òò±ÄŠ\™®Ñ'O ›â;8™Œ£¡©‰Mg æpJóÞ4jÿŸlŠEÁyÞ¥žÊÖN#Ž¢EuÀYBLϜ]cƒó¬~ÈÐg_&A ÓÕŽCûtÇH,ˆ…¾ ”„S)ÇÏ»RÈ+} ]‰©"hä R'4©e†jp¨‰WƒI‚.a œ±iá T¬²Ú8§‹Ý úyØIðWuDrŸ)‰fÎ8ÁÊn’YcÂO^'­Å ®²Û¯!Ò5^ì9$ÄSÃWЋ°Íì9ùÖ̃˜!gŽ¡QÞ~…À‚¾cœ×¯‚Óõ8Ä’€€· %Ï}‹Ñ1Ž•öÕg•·[C@¢Šú ¹®º­fÉÝÒœ†ü’;ì|—×*>ËzN;ù\ø!«”㾎OÐØ3ÿÉÞ¿,§>¼'6H¡Ehûð%m~ûCZ†vÉs‡ôRd„ºÿ@ñ½ª÷HÏ7|'I]îOŸ`€šyLE6þ¢p¹<@‚j2Nõœé²m ]¤BC(åìý`«žî[}1Ó®úK£”#Ùì<¸^²uiD›†4END/À5œó΂ߖ"a®,Àl÷)¶"XÉŽòª¹ $œ£‰žxÌLÊ€–íaÅ$ëf ÙÎM£ Í÷)¥žŒgñû[“…ž è3»ˆ;[×À5& ¸5Á¥ã,£x Z2ðê«ïÐ@·W àÔl×ÖôQqF‚ÑÌx)É„J'SHg£OYfWWä,=·a ¯¸m™›è|X¸IÁãU4I#Ô/£À°3nRQµ(Á Ío}A¯óŒKèNUEªùfÅòvû{à;™\ï¿W—{m®åÇKÎVwÇÚæ‹cÇ~Þx n«öýÉ후rjq`oÒ¬7Ón: `é£ÃÚ&˜éU–kmÉÇa:åž>AÌë™Û²¥¨G1΄rW\üŸ3Ž/CRŸ`wK⫤n0/ pÆ6Ç<ˆ‘f-¶ý÷!"¨ZZºã#‚À>iä?tNt‡ø˜]ŽWp§#$²Öú»^’äL¬{½Š_†pÀ·2 uð!­'Kj£î/ÐÚ”Zo÷Z:]GhÓ¶@ÚŽœ}Aí“ugC#Û—ñ 1U‹ô7„ ¢)å%μ¤CãQj YDw{»U$ä@j×G2=Ç y8SÀË€§Ê€5ë®@yl ‘ $§±?§‹Ô „HÏö‚’»èSŸ5ÑaÓEœg¶p¶•›uo©Hi‹…zîÞ4X­@xla…w¾0Ä™¿·ë*Ô:ŸÈÊ\>üÈFŸ<7=ÍÆC0¿¼Ú!ÇëÙåÏõ÷T~ƒªºîä¢R¿\ØÉ6…S Í„˜¶[÷}jè]½YhÌò:®ú‰å‚W Þ¶÷À ¤+¸Gƒ1ÊC$v%üq¢\^¨1G_Ùò§_½"eVüWg\m’€€£;åx²¶H°¶¼ìÚStÿ\žß“›[Í`„aLRå$ÖjØus‘-êõ¡bvYäw+Ol©¯È«/§e_8w“"QÌ\VáþñX$†‰=Éy)`FÂ޲¾ý³8†Sþ9ë’oY߸jáï·†¶-µ~nWm»iZMpánUþ¨‰îó sµŽ¾°ª°Ä£BìoĽ‚:D©Hé<ƒàQ;yó/:2.úx^ »áàÕ“°Ìzô¦Þ'x4r Ô¡à·“Ù”ÙR°Â$„eìhL{‰ï€ â‚€pù’°BH)ã‘ÖÉÚE6²óÊ‘mPðiPXÀ$NÄ'+ É!hyŒ¥.Êä_¼áPÂËy ²Éh$ÑX´þôyÊ+ê{ u}3fùEá™Ñ“O—( Ï{¦ðœÊKèŒÞqµë¨cëVëϼ‚+%â,2¿S£Fت¨C <Ò›âo ‘V…€h£üÓÑ# ó @lB¶ÏdSý+Q§i£j¦?ÿÞ9¾FÌG#eLª g3ÃX¦üIRQd@ÐD ”޿[ͬ‚u%ì·ÅEçátÉãÖùGKèv^= Éý“ç„nÚ‹ÊCÜŸÏý„u°O&ZÆË•jfÜåÚ hŒd„‰ü=ÿåIo"²¹QäæÍíž%ÙEuêe’¦c¦Šúc\æ48;œ–ˆ/R[93¿Û÷߆Ëõ yO2ilH\ãÀF†®âeìCp ALôb„ asô ÞtMUå¤ÝŠj×Û}®H°¿øÈN+—Ú"ïJyér~O’b@ÖÒº6§c6ü á}7o9¯ÀT‚NòñÝ@Q½“ ïˆcŠ‚¼§!ùÕ/~ïµf 6`8iHl«l¯ m *ñ&}ô­ «²JÓC÷æ Žƒ6¡nç ›Åªc`q¢¶xX^ ~MoÖ2Äcîß•P¥ž$8M),fÏ:)C iã®› ‹ àÖrÚ¸µgÕ¸ù…ÒM¹'`þ©õD*–øÍÔ±œ©<و̗sEM3 Uz:YJY¡pSÑîÂÉÛSÙ¬–¤“6wAÀÙ¨ó4†÷oèÊ7>Ùj‡6Sa.òPÎjÙŠâ­Jc6ï"”},ë%ìÚik£BǪ©ÉBH+ktÃÆáJ’€€ÂVN_ãg¶´4éu᜽8±ž‘> ­ÜK»N1 Ô=¹÷ˆ£*Æ µßÔ^GChÆ}78<2K"Ó°ÓQË–×äË—[ƒ3ÈküSÅÃ.¯®kùó,…ßL’úgézMÛ"Z4kQf{šÍ„…e"ZTØN иE5¨XfêUÆjøæN¶VŒ¸¦—Ж(€4ÏN2À ÝTÄ¢C§<â<\ߌå+P–±EL¯i}eDn<ˆúûÑx†Í먬¶_l8U³¸Èw¡üÍÕ'›^Y¯ˆð2æ /Âí)ÍSgíÙ A²GÅúÁ—×.20ó¡ðä–ë‘oÁ£ ,sVÊ»‰QÓÄË9oC'+ĵ‡·©JL„ޱ¤V Î»ï—§6¯Œ Ï =ÏbßX?gDÀŽ09hR?¬jóÌJä€I(;8t!^cK¿ߌ—ýI…-zäΩS]\ñaÕå]‹æ|V+"ùÒ¤Ï18ãu÷\_1ÿ+ )í ¥—TYž‹Ïèzóˆ"<ãÆ ãæDâ,´¤„„i, Íl[µ:Íý” G3Úzïpg¼gaΜÚQÌ/eÅôšÿš˜Ô~ŠYEŸBfXQžh`Câò­GÅ@@€A“I”å¶ó´}rª=ü‘ýÏL(±úßžìdè!öZl¸/&Þ\ÆãÌ„: s,‚¹ü’)RŒyì9&ž;`Pgª”ÎRªUâ2Õ3,óè7÷±`‰ZšILÝ¿ìn‹³úá–j¤¼Øq—XQ1:zsÕɺ(SnõøŒŸ¡ÕMßãݹsÍ3,…ä0³gÅþÂ6¡$Í;¯¡8M-~ï覸ïûanÃâ_<ñ´`% ×4CÏaî8~s²·Y»O•t°F¹ç¢níI.&Ÿ~äQõ‰ ×bìÚ²–Æ®O9T;…¹S%mW¢PÌ_’¶éÆL̼ÿ÷|“åÍ e²?v2¸§¸žh¡Ù¨ò”d‡® ‹äþ¼Lß¶PúÙ! a ¹ ™œp@îgk1P= •!]׆ÐQoCØØó‹»Ä«ÇŠTñ•ª„‡‘Kn‰S4È‹Ç&£ù= E±Ç¼³+¢ê h13Òú };‚KQ’Ûc.–f’€€ßË/¯‘ïÙáìƒËhA~Lùo½Hn#™[¯×©E3 í°®+%öi\}T TŠºi³ ÏÏÒdñòò–-(™¥!¡`µ“‡72€˜èœœî\ mý !tª$ø۶™qñÇÏj=¾ŒÇ¹–kïj RÞÓ‘l[^®aÖó]ÞJå Çiª #xP29¢ÞAR?¦LcÁT0›”œpޏ׍f?‹ zpRRs-Vuêòq¤“‹ûPAÃ*ò%¬ÀêB{{9$›½šŠ±ªNmÒ[+Ÿ’¥¾J÷cØÖpðÕF/é™wÞMÝaª¬²R˜¬Übû ƒuȯ†öX>ƒ)º¹B;F²Ýy±Ë«gõœõ5aKYÄ©>ÓâÚÕÿ'Áàp?žÞj×$³à1Õ5kµÉšä(mûtÕøS/È­äâ|7®{Âåzºt5¥dÄ;À;¬/$d|B¶-%m3Ar&ëŽg{¬*¸éµ ¨ÄÞžLò>ÇõbBm½#Çu˜½ñ>íçɳ§E¢ùO- "AŰiU€õÖ]ð³`HãÑ|`vr4ZZÜ…D]¢ƒŽF’µÝF‚ÿ:ÓN‚Ãu?B€9Æüú#áŒç/ž,elvø}h¶šý¡fHœ«€U)ôNéoèÄÅöSQB$—†Ëÿª½_;}Ü.±OÑçÈ·þÙ·B>5¸ÕSï²:7ŠZ1ohB‚î6%ŸÖ…Ì]ÙAU³¤iùÝâ/,Žj}Ð ÐÜðÎWݗЖvr@¾[cƒ€›PºKÏKQà­z—.©«Rbz–z(¥ÛJÝ'].>Puè•RýZ£nB­&؃³Êã¶U%æIaöXÏbïg8Á=WêGFP^ØÅâWsÌRWêI@™ŠÄ.aéÔ.‘f™Gb‹Ž¾ët ÜOfBàÓ;ñiá¬gÑ–&G]g§l¦;_q§3Fû‰6δr„MžñÜ¿‘ÌÁõÆá¿ÉêR^í;!.6‚bJ½ËY#ÍÌvÓ:Œ5½]£:Aü¤¿Wl­mn¼ ¶’J‹4¦ÚW×FfDÅ1ÃÝÃ˪q¶cÏßcÓš·à¼óß™gÆþe 3WÌY}¿´ ölÊ«aljKí+ ì“ÖY ‰j2S·Ç^’/l’€€¹¶Ë—5Á‘†dµl‚C7g6È Aû®øC½;5,¯ž2>¢$SΫÎ{ås9ü'#b!ÛÀ¥jqôö'˜KÏ A̸—+Àøë¬läíM»‚2X"})ü|º[`ç¿gÞ¾¼Â‰¬ËÅ~}À.Ÿ'lWÂÉKµ`Z/09¶ ÖuºE‹†<Ì´ŸpÕëCôzcn2µšµÃƒÒÜt0eL18hz°¹»F~ xÏÇ’NF„dDS¬h1Ï1‡A$ê6üQ½´ÏJE­p sµ>óiCÆ\V&f›=/ËM·ØH8ÍYæ“w˜G<änIeAVX€t¥”ÉüK³[å,Ñá…âýò.³3|K@7G!úŤY‰ûß}-/«NÐRøì8ÂÖA®{XWjDðö°H±µÛßyž’¬Ñf•W¼gýg/¤ÆŽ–XoX «é8Ñrþ·u-br:°Ôq&¡Ú/üºxçiWT~Œµ†\Ö$^× ÝˆV™Óçãü;5«ÜÏK}Ã(HáŽÙóVO'þ¯—¤ ©ä“1¸ ›Uº6…ôš XélK»N}ÕÅ‘iZª¡!¿è`(t™ -Ú§7&SNC{umV™8/mqFrJÆ­ÐVN;*»UyÒ¹‹EÐQÙ±˜ž N_ânç¨Y¡ñ}ò¸©<ŽÑûÛv&Æ]›]#+r¶¸¸>rÓ,Øøod¬Œ­ En²üV‰PdaÜp¡0u(\n6GAU¬g'åóEnNd‰”­2¦:üÓ'ÓÚ;u__ÄdZ4` IŠÕ •à‚&ô•д<‡ ÒÈÐ Håhk,Óß sþQ_j/Ãß½©³Ÿ6ŸQÕEÒZò`Éxêÿ¶J™>ð’$œµ•mš„cîz¨ç&•¼Èƒù]•%cpw ˆ§ÇU‡Q‰}ºw­²5R>•J‘Gh—:Å Dõ›˜Œ¤UþÙðlÆ6ýOD’åíÊp˜õ{áâ(Z+£F¦¤þ¯Áâaš¼OÛ+ÌK†PCÁ ëùÞž<í«xÞ’µVßcŽaG“øh“†…Ñ¿m‰Æo…R¯Ró…Ûc«AÛlýJ“ñW5Ú–|©.˜~òöâÓÅFøÆ°K#ŸÚ9Âó0ouÀëŒÒßÛêûiÔPJ Œ¹gŠ`…’€€¤Ÿ@Ì_‚d}0c¥üç ´¥É-ü§è9%óÿ—I¥òŒºã’ÈÖ†Hß8.ŠÉ=Ã_‰Ù}¡zÙûqXBöüK‰LÞ ãÈù²~°cU¨‘Üá@îi,T‰mdÜe×ÛˆaLQò°ë῞T}½iÜ}–(×Òï¥wÛ­LĬ¸_ŒñЖ/ÄûŸGÎW6ê´gÿè<á³å?ÉtXrÕQtex5íoèÐÏD)ð験½Ý•všÚ"Åa5œÆö{íÔ=Kf ßj™~ÈŠ–W]À Ç\ˆüZÔO#•±ŨڲÜ+ašäÇ€?vcÒ+‡“J&µóÞ,KL%†2ìˆ` ‡ö>¡å ÿ µû€yN§} žª›F*Q ú×Ûí?ì)5iJVú÷|œáÌ_˃†ü¨ý³áѳÿZVÃø£©á J|KÛ}ÎIª Ÿ¤œHVûv*^N‹«‡êòþBX©:Ñ€ßæ;s’nüå"•»›x+q®Æ7r8cuÅìlëŠ1¨,ËJnRpÃçÒí ú)Hš»¼gÊdÜ7ö´nxœ<¦™ó Ê-R«fâÌåJú+^T)BùÊì§ÔqîׇÝåÌÑá{prƒ—œÓêó¬/îcŸÒö^â$vÇ× ­¯=-t«úéüòn~Œ˜Xu×X{æ-R嘕+{÷(õ¡/#ó©‚»-ü,t®%TUÍ”?ª#°‹ùˆOá‚,¼ü‚3(ÖÍ’0sÞ¯¤Jï,JÇXú”˜¼zI«áº£±N“T|3ö} ýëÈY´h%©@–ˆôãºU´Uaä¿TïL¡°”dŸ“sb–óU}ÃMR¼/YðåV‡O£Aй'N ç.þ×3”B-Åî×H‡±Ì`| -Kä*àˆB}ÐË›=·Ìºò -Øß2”ê0`L´7pÍÉߌ ¦§v_\1±®ÝbÙynXŸHOƒœ³??¥Üïé{í–,²(^ÀxuEá¢óÐ{uü,À®©$¤œø¨ Æ/?·Z`WJßô뺺ү‚ÃCtQšõ n¾$­ÜMbW,+=F5Å]ÓËD[q~A_Ϋ±†Žj^` é…̓BÁÅL€±½…–>¿O^‰}ÞУ¢ÞÉÆ²HM¥rp¯Î<Ô? ì¨ täz‚‚ueƒ>B íNžßi'B~|d¨NüoÒ_1[1ñZ|mñ€ôÞ½º4ÏéÓ4©Tnm-$ý\À€tT–@]Xµ¦zóš–@°)å—ìýÌ.ÅÉ+¡?¥ïòg»¯F5#·öãë(3§9?5Åœ7¬çÍB@¸ô,çC€uÆßãþ3kì/ú‡eG©˜ùõ0û–o¡Ãp6Ž\0¡óÍÍX.è¾±~òbù@Ôœqâ6º‰—?Žô¨aó@C÷‰¬ð‚ œi©|}Êžö?ÙL9»ç[ÆDi³³çäaZ¹%…â%u('Þf{@Û*ˆ6±â*¼ûÑâo'Ó´D^çFÓx‡óAÑGXIï!]ÿG–òÛkàœºU¥œ­˜F óaÜßÿ\Z!®—n»­î†vñÎï†ÅËg‹Š²’}@éÕÝIÙI™tˆgi¶ìÙÙ¾ M½vÜœbOë=ý€ùŵE訤²´Z|f!]Ú+7Æ}GÅÝ{.9hߤ=e‚äW\ö?©è­ƒýG×Ûûj«¾é,sÆ×ÃôzA½å×_SÏÌR^üÜ<ˆ ÐA ªg>ëλº¯ØóܯP×Q· z¾Vs¤’€€°Œñû6Š}DEEÒr•zlÞÿÔš˜bÜáug1ðäN`ÂdIÍMMFŸDœHlìBꔎ'35Ë¥à öq?üfØ9¦`\â•r­G<¤¥âþ×z¾Ó²1.ÈÒàYF´§«QŸ›$ÃÑq‹;–_(Öo>;Ôë¤QA/.Õò;üúºcæÐ\bTvFú·Ý<Q“•²¥‘³_Úž&QÁ½Aà`~ÛŽ á´‘êý±-­ÖêPýÕ-rsž9ž[w…P-¹Øá%+qJ1 WÔ‰Vôk‹àÑV+Š u/w$a"JQ…Ž|1•æ"´ãY³ÅÎvß=ú=†ÁT Ø’ åSKò‘¶þbªŸãc‘jcJ„ ̲7Ì—Ì]”S&’€Å¥žôæðAÔá ^çAÝͶ-Ê¥#Oo,yÞ!1o™FýhT 1©¨)ç4 •à{ìŠFýB¦·k!áøâ 6*#*’Nô{8Ÿ*E!f‡ò*þ\{çïS$â@i«IÃñïè(ô’>«¼ZŸAㆢœÿjz55pù˜Ñ7%lÙ'Ë—"œg⻋_uv°HÁÛµr½ãÔ|R—úÒ)J)Â̇Ñã×¹MV·Ö`¤ ¬Ë¦;•ŸøZ÷Ñ»«:뉸µ›š|0šÝ¦PÂóöJÆù,êÅ>¼šä(»|.\»U2–ÿ²ÚèbÁÆ¥/¾pŠ ï|ÃE|Fö>g«8‹c}¿üf+ÿíû´ çPf™ûοzb‘. (41e8Yf Õ‰ôÁ¸P|¹2*ß÷ÿÜë¬vCà\Ù™uœ_nE¬¥l¼)AVzÀ¬“0Éo¶ÙlÏÎ X¹<Ï.ÁJ;ÿõ‰gMèFœqåH´-]XUY*AƒÈÙ(ý•}#×c¤ÓkÞR7Ä©§ÆÇä¿$­]¬™Ø×Æ‘Ô;íšÔÈ¢eŒ\N‹õæu¾í]¨^’©ç÷ç븒JÙý%<½ÑbxæÌP-Ê ëz–f\m€ªÉê,($T;XY¥›¾•´{Å¡¶‰Lº­ï6–ÔgöÓ¥(B|U_u»œƒb6sÏI3¿:DSâøÂ%IfŠ0:=ã±Ð¯o§mOÅS_Ÿ‹½ÁÀO×E¢в…̵¹.¦Ñq‘HâEÜŠÃU~µS5–uV’m ”-$bÉÍêˆ8<ù~O[Ô·Y’õúJÚœ·’ÁE:ÍΣñwd¯šFÕCïŒPUvÃ,<ÏÒ ⻔¢¶˜Lýí¸uõGèËŽ›%Yþ®¯tk'¾€‰*†™£èN8R-ZáÝG›Ö±·*2[wgįá:vÈÞH V5­É*kFÝÃ?¤ý=(´ê bû~>dᄜó MTuÖn¶Býȇ/) E­‡ØÖñ)S¢r§Sû±Þ¾iœB½e9MR¸ºgX%¾Cë pF¯kJ`Nq õ!¶\„Ò¿¢Õ`J¼¹³wC àÂç‹/§ˆ7™eß°P)—¬ˆÿ.¶ªû\# @3ÆS$ýAb'k'™œ<Ó'íÜ„Þ%Zª"¦–Sõ@©§Ë犞áÜaºoqO¤Ä ±Ò.òeó·Üù¸Ýý,y:%e4ã…}Ó¢{>YžjGsõ›¦6ã[ÖjßZ« ‡vTK…¥Vš3STW(›=l²®Öà–$¹êá#¦ý•eňHä£ç?ë‚DÊܽ›'õŒg9a]óÚ¶ÍÑα\Ž}Él§eæÂZä ¼ëSºGÊxÿ‘ËÐf‘=öFÞ #§ØïG`hô´¨¤Ù>¬…Pì–»e8“ŽÆ®RÅ*s3‚¯®hÄ”>|gaQ:êɶ¾?R$œÿð²ªäöÖõmº !–¾o¼Á·ÞDÃ5’ñ o.ì<Ö•„iZf×Ð2ó•A·–Gߟ •F¢j°ºÔàA0žù9þ'6ðxüåóÑ:ðó¢Ž äÙ“áÒ[b‘À-» ¤ò¢}¦OÏNªÕh#ÜØØêâÜ J踮A0”Ç´¹Y™ uŸ,ûƒhšLFJÙyh1@3«ƒ”ÄÝ ÷û) ±µo¹I,2Ï™ÄwjÄ$> ’€€¾])އ7vû»c’›¦ÎTŸW;4’¡>w×Ò¢Ò¯ïëÑ‘1²† ÿù/UOÏÄ‹OÚ\ϧ‡Uw5¹ñ|ΖUP[5cÃ4þYÝ*gk¼jØn©¨wODáâ°qì"‚õ²Êh£VªéÐù9i8k H@ž¯Lk•¼Ó]ä²'\}ÌúüðùiÌcKES¿4QF'Úb3ˆv5Ûf0Zâ Ì`JR0jjסœ¢÷Z<õ^ƒb*„%õá±^;8QŸHÎÖ<oŒLq‘¡ÁY5 3ûÉüçgÖj•nŠ•ÂoÇ@‰q°U£À1ÿÐÕ46¹©­–Yª›Ú(˜VÚT…ð—àüD´ã$ì(°w3þ8^ ©QVój°7~ÿÁå¤[rÛ ×ö´GÄx]îôÍ3üæ¢ÚˆºŒïãQŽòè4¨F„Rt ™0oRIš\Ÿ™0;µBí[\¤¨Ž –²k=sJÁ@刃$ßÖ°KwÛ®–ý,ƒDíˆÜÞá–&TÁõ ¦"]aTŽîØÉÉdh‰”m°²‹ŽÿQ ŸŽ‡(J’Ã"B2cI«0H9R3ì¬ }ØÛ3EY5lêOfLza·]û®I»ÍÏ‘*™Ò‰ßâ7èÓ0»Œ§øGÞzè #ëIÈd1?OàOøD— ¼/rñ\…v¯­‡q)tûi¡Ct§d¥1ÙU¢L2Ø.îê^ãá4äñ÷ì©°ÛKÔD¿ÛM2”1·ò-> <,èׂ/M’AÝu:ü•FNªÈ9i¢/x¬TÕ¨~ÖN::‰ŸÊ{/Þ†2KÿçŠD³)5(Δ¬“ÄJéÚ<ƒhž[±J©rq«*^SÐRIO#å©»«É¨±Á+vþ…Éyü?Å‹cØ;d-ªÐ<^°ð£m)ñÒý/a”R³­>€GlÒR°twq¿h!ÉÙÇ4qX´ª4ë¥cž‘nC+\‰êøÂ/håNJaæ”°©Qzã.ISQÌMT=™H*¾c Ò¸»$ƒ¡µÆ»€˜H/h~‚8üÃüömžjuoß¼w·&Ñ` .#¤kiˆÚêýÿ8ÛG7Gb<íÇûqÒ¡à ¿i$ };—ŽróO‰ÞoLxc´¾AA2Cºüצ·v6Ã¥~˜nßI¿ ’€€±/%ª~÷en/¾$©FnŸC‹Sä¢ã¾; b› –I¨#¤Äs hYÁÍì{˘ê±D#¤{[O ü…Í·³."/w @Sÿ—BÍö ŽQå·í>ë‡Ií$µ¹Í@)t!U—sZ2Goêë´½ ·*Þ ­Ý¯™u¤ÐB/B{AÔG ²)+eÐx>GPåI bŠ™®ø¡r…Â;´ÎE-Èg'´÷ºsŠëBÞ¹r.ŒÝkyø€âDvA5Ò»^N}OOŽu¿Ž#h¿`¤ÑYó‡p ÙMœ•Ê\r£N¦’8© ¼|¿>² à–ýäéÑmÇU% l¿?TGÛÓ´ƒ‚¬üIâ{Y»úýÎÅȧg‰!ð#Ô«š`Þ>ó »Ä<š²L‹ ® :ý†ØÛý„㛣®ÝßìÅž"žßæ‹}Ä´V$PX*(àù¦ ÛZPѲÁ æŸuU:ë)X¤¾³®Ž¹£Šn+5<ùޱ*YæÌV`xË)¶Ì¬í“,¶Þ„G›¸{K_C³ 4©@‹ŠS7iºÓ„\mxŒÒÈÁR´IøCÂDó×_¢xÃÐjÒë*Ù%k-r=V%#ìæßÛ¡¯Û‘Èü›îsìä±Îzr`› 8“#Ç·Æ ¿M6Ö¨óèÍÔÿnE©dí‰Åµ\¢•ÂÍß Õ5ø8m£Aáª?.¨¬€p6•|PM̱dpe±éCN¢’€€³Á½î·PYNÍL¢X-|KðaÃ?;GØÖ޶0H}”puà\ÿz£MŦƒµuªÂxKÄ‘Èã æKb1ëˆÔØúªºnŒôZç2êÏ{ÍïcµÐ+ÑßbºÜX&²÷îý©>Œ‹Ð©”XfwxÞF–Ù4 æ½³³ßô'z-—£%(Æ—b:],1<‰b3WÙÑ5dFèÒ•¡6˜­K:‹¶ c$¬ß¼n_«-kAxþ zÙk+—}rŒ•}G"3:¦«Ì6Þ,åÓóö³˜¹`bÌ-Wë‚eJÇÖŽ¯Éz⼯±˜ÓbÉ>8Õæœß¿Yñiƒ¾¼N“¼DFæáÖ,"ýÀeeêîó­ÇÆÛÎÂX®úpÍkе ½,~¸˜é? ø‚Ž6˜W›gsÐY?‘Ž0­%³š©Fg|¢å\{ýäJUÿ£çJd9þ^ÐÐ3Þ9f²÷¾¶ÄjyúƒèmuÍÏ`Ô&5j/&¼;%v2*(\#aC«MU¤öwÿsõ§#>둬ʽpm)£¹'ÂÒ=RùÇg^³_þ‹f³Xä´gaœ“´ÖAn) XÂâ†1°¦ÃÅÖÂÑÍÌñ•Ý…LŒdñý–h€Î‡o‹hd,!_àLpn ß5ë™Ý`¶Wñx]ÂÁÏnQù9sƒ6ô3W“;U (C¹>[ŸüS”þŽjO Ø/]™àı¼–¯ý¥íulŸž«`EÒ!:0Ç)f1g·EQÕüÚ\GPÖ8‰my÷ÖF14y’ðd`1,´¾m¶™237ëo/Jô£>בò®&Ru¿5o‘øôÉÅk:¨¢ß±ì!¬|mŽ$ 6N¢‚ßm é/}–ÛÍâþ\—êe“­„³¨L¡GñeçŒA~ܦ oü“ShòÌ,‡Ï¼u J“[³Õ«î“u¥"§ægFèêµÆ»é”¾´¢¯™1†¼]9RU;QðÞ<™ìmÒ/…†‚dÜ„ôÑb¾&>vNû ¡â@ySÜÚ~ÕfG’§vBï”>¼ÚLÃÆ·¢ú‹&Æþ·ý]t)q0†ykIܯÌT%û¤:"€JÕgý¨ÍŽ’€€Ö² îä†1x¶ž#³˜†]‡e‹…C_)"€À—ø“”ƒyîâcõ¼—]1Ö²½¿M <þ·çð"µºt§Ö<ß>&ËrLi—C¨Á!1•Ü@”žË¿e$EùÑ´ÐAV>ƒVt—_{P½¿ºeœh,äU5¥ˆˆ¨Pœ´j sº!+øæ¥öJ˜fϱg\æ»ó\ì›w_yCCÿ¨ëG嶸—º®pNÆÀ+æß+çZ³)ÛÆ¯üDe¾°‹ZRMãÎc™Õ^L~‘IK§K~Æ4u´kÅaÁC•Q/<Í'4mAòÔ9‡TS½ÑœÑ&ïØƒ`·ô+€¹¬vìGCón _R›×2'z‘1Æ)“ã–g7}¿ä9OŠO¼åªXX–£Šk^ݱiY°Å­Û))Ì™§CƒEE ßùCÔ\ãŽ^•N¥>MYžz.HG¾m㼚±h…O‰~ëƒÈT‰+cº;¾V¶šgGF®ªÕ*¡Ì>ø¢¬ùÕå–ýHƒõ‘Þ›$ɾ}'¡lny{Lø…é¢ôtó@ÊK¥jÉk>ð)>æ·K êcÂE–v]ìZ䟂ÓÊ*†‚|¹æAˆ-©¬ThŽŽÞ .‡\EsulŸ6Yu 3£ªê ûe7íx÷Qrù“‡–Åá'9{JxX¾8ú¬ÚNî™*“y<§ .{WÖñmX™×Qýõu,l<{pñzJl:8Ô#}U!€Œb‡6vè¼æ"Š´ÙD¦5òSn -U0 “¬Ža/2± Î/VÝañy]qŒÄú8<å¢û0S,+ñÀæElIqÔhýõ8'\Óµ4YÊýUÏ"ËæZ™T¯VyT äPi‹ªóÙ„[tƒ’R ’Ç?f¼Éå{óÊ«­öm²u¦Ð°òÆZûooL¸xTŽ€KýÙƒ©ß5œ$&ò5/&+‚*T™J‹sÜ;ítÌY‘â .PbLG†J .\Ûoú_ŠÃI Õ˜&+ØÎ’€€Èÿ>Z=5ZxJÿ…!,ù: ð6b³d°ƒ"¿¶|?^G+Mçªx¥~âŽ|çqõ«?+SQ@HÔÎèöÊÃy¿[31ýïcýXùåÓ]?”¤>•é…\í¨Ç®DÂçlèìÌnïkFJßûYöøôÖS:¥qFýÉÎBß1VÂ͘tK¡!åÿÊÉ{/ö¹þY–S"”Ê3UŠÅoNÜKΤ¯ ¼«ïÔZnä$ øF2‚ÉüÁ=˜ª±¤scÌRÕ0ó:ÐA ü¬ø&wÂ/նȯ7šn™¯­Â¬çy“ÊöA04˜%9ÏÀÿÉj'a`Èœa·bÉØä‰22 ¬°ä»–žcðä Ôqüè&ãé93ÌÖ[°¹ §}P/›Á^çÂþ›Vîçê©™†ûQž¾´xøè ßáÄÞ%†tyˆƒ¥¢rƲ¶(iʱˆCP¶TGéT9©ýëÿUÈÂ7ÓƒÌÞ3|¤}f»2Ú_Ó_ÐÕ¼:7î—OŽH¥©ÈoÍÆeƒ7ñ¢"œr_ÎÔa¸Í”TÚk'ÅÝÔl=p™“–÷ŠMçÕ…Í(q´Åw¨×¨2Ù:ší7ÄT,€ÃjÁî넇G9¯ ùsf¹]p5–) ï„‚|ò`mCïÞ Ÿ†m‘ä”1éˆÖ.Ì0¶2kÓ¾Èò\ÑYÙƒ¸0‡—0©kB>“pdÜ üùT;2æQl¸¾ö«¹:¤³µÎl(»¬8òô2ÙY S®Ó?§`_:¾ E Ëðq;M†yé!Q’‡Òzkú2L;ª m€‰Æ=†N*ÁAú‰áþj¸Õ¢¢eÎ:t)Øs^v)J_ZG0üäª;ÉËçёĀQC«¥ZLkê4$××e@Ù¤š¢ô,‰ƒ@i=nfÔ2¡½¨kN½GO/ø'雜.·ÉLŽˆõçÆb‚é Åø"fR­Rî >ÿÇ‹ 'ž`½Ô£eÏÝ„1ûÕž±+×ݨµ«lµÈ/ü)É’ÉÇ~þí*¸¥ÊZ”~S'‡ƒìó¤ß1+“exº!„%sã%zɺ¬ «´ëÛo’B$ûƒ•޾Gçþ=ÎLðàØo¬Ó´Å/KŸƒ“’öAïÅ‚X "„¸)šÄI3­’€€Å5 ]ÈsÝ¥0®1½˜M0UÚë“Oʯp£?&yÑb»ÉTtã^ æxRØä1a9gSÁŽy’‡ýU ?ç<ÿˆ,YØîjM¤ò6e(Ó÷±‰<ÑØeî9ÙåÛ›Ïê’ÁàØ|¼ª+½äRn¸f²€àh¦Râ(_(þ8žvaÞßÄ9ÐŒéo˜<ÛR%‚îH+Ѷ®¸öÐÿch½”B¸Œ¬ÐF`¶_šš±HÆHÛ)f }{­õð²3”¸HN8Ëw_£š LêKÀvHDw‚ì ¶Æ0XXçðMßíeá˜r‚ð˜ÄF îw¡í…7Î uA*$räXŽ#\C⥬Ž¢¯È%ø½ ´™‚ @Äs0iïáõåFiÆ-;F÷_ÉÀfEÄ¥´ nAù|åý>œËc`ÙÑîNjâBØþÆMn龊eA¨ °=èQÛ†i&äS×M™j5gÌÆWdxÒºfÀzø"G\Í“c”ÉdÇn§ŽÜV~Rÿ ƈ7Ë¥J„ÞV vÛÂ’˜ü‚ót(×èåˆò ¦­œÌï(䬂´QzÕw•!â ×”f—„Ä BÈßSx™6u«œ hUP.‘­«õ{ôjÁœ\À–¤ŽuïyZÙC®9$©ãyÍÔ÷Öåv¤%ô5ùlF?@jzi§‡Ô™lÁ ¾‚á™ýEÓ"È[/ÕžÕéCç\÷A˜ébiÿÆÜëÁ(æ¯zxb‰lÕ…AŒ´?¼KäÄcĪy.Ñ'‘¤B/ÇL‚\£!ïóedev× ò>†«ØPÃʃ¤Ÿ´é}ž;×qÖ „°Ü5Ãe¯D?κ-ŠQ ö$,iœìmgŒÎ"‡h¬Wœ¤Òcˆ,_5d<z¬J!£7’{õ~O°µ<.CÎÀú}ðDhdLYÚ=î„P;1Ú–dõaà2ò¦¶@¾zF /N…n@!¦{Ø=ëê_ÑG™» Gø³ÛüØ_<¸K)×¼s%F£¿…Uá´šeÙVPqWpý·´8ÁëÑS [OórT)Ød£„¿ÃJ•Ý\›¤÷³(~󋸜àBSò¨zmô¹>#à˜¹ Æåß=¸÷Ï÷­°ÈBVï}–Û¤ãœZ=Jb‘¯Í¥âY ñFÁîÓFïšiH³Íû)–Š’€€æÑ´2ј S{úêAÆýˬ²i ’¡älŒÝIü•Ë<üSbv²©VõV:›‹Ç(’k›dt±œÚ¶žÈ¬ò´Ì×’ôÒŽa]–Ðóöð‚›Ç¢ äˆÒÈsYÙ$· ·Æ(ë²+%|‰¸˜¥¨ŒÜ—¡/i‹X¤fÇOŽâ–žÿ‚cL Û_Õ”GŸAMJ÷Ö[eA&À7w¦9;ƒÂ¾æO@=$ÙÀ…$YŒÃΔØöp”I©‡‡%¨lÖtÛÀM¥_b˜¢«àÇÐÆúeœÇH…TSÎÚÀe£Ë›H»H:K[K‡áò`âMX äûj Ëó »Ó³%Éæþ\GA߯¸!}´²”O4Y6ÒË)Ò ZÙ>b:q'ìÅþü÷‹J$D¯‰Iÿȧ\h–f]Ô%8º0[jü—{7Ó4^Gç}]Q°«K¢3–ü~x•WF2Ñ4KÍÚÛ l[sPWÁãc¬„-ðr¬»e0p¾Ìq@±¥˜,†î$6”¤¼+¦6bÎu•Ùoà»KÉdi#ÙÕí¢^røP?z“Øx.úp0‰9œ¥8IH- M™“ŠŸë\8è¡ÍŠ')›¾8J´‰‹lbv­:_aåGñbô¸zyÚÇú| ¹AE>—;’{²;B~°6ìù \žÆýìäoAÿÜ‚E»Q—Žû«Á%·,!ÃkeÊ’í„3<̾ ¤i#xÓ£Øw‚¥¥—¾î<Û7wBDÝm¼C…ý¨÷SUJºã´U49-C¸(Ô¯ hâÊÉ­ ÷ý™€#Nòñi9Ñk$ÃG-±HÛ8‚ý|Í_ qŸñ×Eoª˜¡$kæñ¸€}÷r”Øw°H¾«>?ÔB<¯cdý%IâuÆõ ’Ð]”­Ó|MÈZn"ò9SªeŠìÂÔ RP ÉIxbŽêÙÞ•}ð)PÿTßx³éÒ±EÚk¶}˜ìùÄó/¾ÖrËlÎÃöḥõæÌÖlæ ÀÙ\ˆ•ôŸ|é­³…3ˆworC%öZ@/ß7ß(> ©¨à % U‡[è@|›¶ø$¨ï娖&%xŒÏ¤–”¥3hñÖþ_´\õeZ–ìö ¹ Q¥§D(7û±=!ù »Øs0˜ào–zNÏ”gÓSÏotÎE!)Ü’€€À/±ÄÎÃ0â&q!l–/Ô䜑¼”âÃ×)j.fKbI¨è„Éɶ®µó.[ã«þ¬‡ç_}NÅM"—Êõq’RŒò1MWï5>£»ÜõKl#ÞVÈÏŽHÒaJ« n­¶„_l‹Æ‹ö¯m%‡1³zúx ’Æòù.üÚ`±÷Í#Èl¯‘#ªþàý.Á ÝüòŒÊwE°ŸI2Ò£µŒ@j³è ªËßž5{€.sš™X›Ã¨"É~qcÄεÐt=…Š}k<øJ7΀Rõ Õ¯V˜V½«@“wÿÙÆ‡ûKÞ^¶ŽÁ#®‰ð¥%õØ ®ÛŸäP+x :d/ĸ=õÖÜÆz_cÀ%•°(•4fñ¼XhwU,d}ÉÆ²[¸: ¤Ø ~X±,Fý±rP‡ G²âů½œ|üWÿšû(Z‡êsí*¯L-(fJ_aD‚#~ÑFWÊs[<\Ýõ; €°ÔR™ÃÝ`TòŒ÷Ï‚žmO ÷W.#øßŽd¾À̾a3< ²¨DMº.f¸±¸Ä0ˆ)qÒ-õT[‹íÄ%^`²çÄe‡âx’®Q×Ö, Þ€¯*·Ú˜˜EÈdËu5Ñ”cA”z¾m+N7A†%ÊÔ³½uf)Éý˜Ò;hÑû*”ã¸ýh+·5"Hä›#Òðß`-S’eŽwÝkDnºóSëÁï±ó¯Â1ÊÿzÕ}Y§XÎåÀâ’äÌ߉O8OÑZó4¾Z¬LôB›(õ?Ý,˜cìuõ'Êî±Éˆö'6š°.wlk—Üï—Qº£²Òü“—è9yxGðCFˆ)Ã=1²lÉv=ìm}©jŸD8VF ú+—‘=Iè7ÒׂÎ)á#ŸÄÇ/kë¤ÖrQbž‘ù.3£ÀŽÏ  /Cô¿ÎòòKÅ) êFïÍI ±q//Ø_^ô¹ 鴜Ӽ¯ŽùRÿ>Ëþï:§6Š+]ŽÑ†X6Gé[ÙÄ¥ÕOøKˆAb¾ô¿[ëe§*o ˆåÞ€#3¤äÔ0ÖŒD¡Uؤ»œ‘©æ*Ô>Í(Hì^4 Ûúþðjehà«Ïev®Ñ¾°#¹=V„f›ˆ¿®òÆÜùCþÏ2ÆKÛ÷ E*^”Lþs•œÿ˜°ezÇQ“-’€€®HYÍÇýU— >(¿Ù+ߨ:±YV‘º½©„…¡fÅ!ý}†y«"Ç¿ýgW5ÌHp×ÓS8ïT'é+–³í‰†$äɧˆ±ð‘Œ/( Ö}n¡Á„¡}{÷œ™›–·ÒKü̉þ褰¶Q±S¸]ߌ[²Q¿ëãëÞ Q›95 Á‡êíLè)°1&&Füt$ºJêO‰Å—ûŽâŽUÉKJ@=[Á>¸VÇ®·ò6‹¤a—õ¥Ü ©ý^õô¥ ÃCrG_<¯ÎŒj{—Ç8þy3/M7[f0ÂL*öÇ¾ÕØD…uŸr#/¬ØeÃw¶SÖ¶”µ®>÷6íö4»TǨl]ßËšƒ1’§êDgÈ™ÊQŠF»ç@г¬—ôŠ›eÍñÙÚ•ö£—y‘kL]JQÉð— ƒ sáÑéƒçõzr0ì/n2²¸é{ÂMcrÐåL[§Sh iIg†š á®)ùåy&öD*ëâàvŒ”–¶Ä¬gòq{ô’J {¥ëùÔO8¡Vî>ÅœÆép”èAƒzþ~Äö1âg‹7e q2™yöàã€ÿÓP³›˜yóE«<sIØPÕ¨Ók-nã7µaŽ+OÝ“§gH-Ø{6naèôºy© âå›jdÿ û£`‹Äghrèx€ä_D7Ÿ6µuÊXG8Ë4w =F¾»EÖsŠ·Úf_}4‡üÝáÕ-mpñO ýIÈo~mvìp S’f MÒhQÑT—¾N}Ó|þš±·IYÔû-ÜÖp¦@ÇHY<ä„ê`_kÚX\û°ÿ °¥þq÷j;OÅ™(M* ô8/õŸá##»óÉ–`ÏRù.-8–JºHd¯E,¯¦ïqUÔÑÞx§Õq©ZR`-&4ûô%›êdé‘,Ê—L¹+8õèw  iÈl¹ªÈA ŽíËÚ #÷2¹‚`·(Do9ènMGÝMÌ÷š#Äje¸ÊdΔ>½\Þ`¶F0mSˆèëìÒnoìY*ýŸÒÕg\ U÷š˜‹*Ñ:šBÆê´vÐSü®iPÐá ‹O’×Ô·‘€n*ÈòЗ8ÎÑ©’€€êŠØPÖÃèc+¨ÏÔùZet6EíIäaËš¼Kž{¹òä}0-qÿìn{¨÷Ô†k‚wr8¿D8;ǃˆeiZ³p‰­a {H¬è³'ŸÔœ ¹Ï-ÜXŽê‘ßšMº0”É„\[oÔʘÏ×¾lïãtéLÉo¨é»L•ˆ§‡ŒÔseyúx³àÔî6rÑçz ôò(‚žhIý´“GÆèy4Y´krX‘^aíº¨áyž7nþÐï‘Ó}ìa`aú…Qy¹FMÝ¡FXcqfÄ4ËoìSÝëCìP/vœïù,ÚaŸ~uÃNì‘*ê ¸b^g@w½,id¡Òâð¿hÛªNtË¢§õ¶/QûökÉTÐïè9 ÙëD%R²Ìø½ÀŸŒ7…8+üp$Eõ@œ‘`¬>·˜ÿk“40æ{e¾zº[…”¼"çH«#ˆé¤åthú¤#«ß9ùºÍ†dÒ3wÙ!ÈfÊâ«ß –Ý€˜ëÙ.ÆÆñ{€(Í{¿zV&Ü]ÈÎÀ>H>—–P$ÙS" —ÞÁÂÕº[mΗ¨â‹‘û%kê¹iÚåfñÈcAöÈw¨Ø2Þ^.‰îÙ;%?±JÂË Ä~2[…#=H;TL¡ç©IE±®SÊds¾©ßƒä½/Oú^µkgŸ]}åyÂÀ SC[¹q;¸k/·ìðrüÏÆý=ÓŠÄ`^^ØøO˜U%­YK‰p æŽ@Ñ¡óMW–áÂM{¯nêb.üú|õc<ÓP‚O…9s>Qµ2×ý·Ê-‘„EÎ"{›ƒ|k¶(¥1/„µÍJ ú~ŸÁä®*äf”豪^„1¾‚ÓÈÑ8(¶4“X‹l#iþ÷â¾¢{©˜8‰‡øÇ‡àaËJxï"ŽuÉEÞêÈ¢ÓœŸÚxýþªþªÑË›•D¢Æaù•Ș ¬³©5Do¿îôt¢ŒLÜr}f÷4Dœ~¤§lÂoܺ=@PCÁÚ±ð=šèA 1"yý…DF €¾qàŒ·ŸÑ·f þ9póØà¨5­õªïµ sü(Œ3R÷’€€ÔB-6ZÛ†£¯op4¾ pK¢nEÙl ø`ßž ®©uDzÝÙ/åŸ#| ´–†qácüºFxîbʘ±É7Xé -㌠Îs(ÉÃßöô£gý ßànØ:2µôZ®ŸµUC3-ô"4©°$•T§X]„à’˜Çµã·¿†)6–†öeõÒÄlõ¨á¤óÆBÏ8h Ø4GÄMs3 ®T†GÙù;aøv¯¢Œmº4 Ì:þ’sþ«?Ú<[‹ìV‡—- ‰¢¦ìŠÛt,Âfê^õ0äƒÊ!hMû¨d­ž}¨å÷ByX…ÑX(îYøOV)$÷{®ý­ª€±öI n ]IzÀ±{ÕKÞ£а=KpwÐdF\)OKUX…Ý;Áè÷…–}çxß qGÌiÖ¬.+>ÀG’‚áƒòÆ÷?>‘i á?xºå‰=Ie‰J`9¶R¨t…qÏøéÇш<¸Çì^V±Ôè‰GdèxWP•¯1©(Õ¡ Y¶Î‡¿éh(¹Gs”ÞHHIö²,&¤Ï·Ò“tÈ£+Æì·i׿«êÄEcˆçr‹Îã:”ö‚ã1ûÄzªdvËÛ¿è³ÞâcéÔq^Ü’ÃлýÞ„åîB—aýÇžïꡜw ¦u°o»(­ùÕ® ÁH0ÎD‘Ømõ–QQì8;nÏP@òý(›§GøôBwžˆÆÇ+ØØð>äŒ"ÃÙ µVŽJv¤ O> ÐËaäIsè=˜¿ÌHD¨þRkþÞI³Þƒ)¹\²9¤oéûVPâ™vïD/´‡¢Í0|’qݼ ±á9xãÖиJ¬.Üô×ÄTcçÝSäÿ#ïì¥@õêWuÓc¦.®¥#Æ€žAfžýt/y¡Žì\¯¬yb¡ž¶AØm4 -wb7†‰~xAYõ¨†¾Ö,iìåÂI3`çó¿©.ôÓïü“çCÒ/âÁ”š¤Ý¼¦O¨b!Ë N) ŒÇùõ°¬]—8áõÂa u·rDæ”·”¦Ü#öËÔxðitÖˆ—®sh(LàÆm‹ßê¬O 8Ä·ŸåmϾBÈúÔð›øyÂW#ÑÓ;+)~ü«â€~5$ËxwoŒbÌ®¬b¸kÞhäÃ.o)C”“µr¬¬È’>4&‘‰Ø¦pÂæ*<ºEö15CÖ—è(3÷)ZØnՌ터»ßÁFHü²ÌÈ-¶Y¼¸CWíâ"§æâ<‘õ²æ½ï>¸p܆ˆâ½¹&Á1’~í;‡´q¤ÃãB U<:“×! E¤¢³®QýGàe‚£FñÜa›û mÔÆl­“e 89ö8V€Ø68+ÀÉ´Ct]Ë+NɪMùø½ÚÂmi¡%†A¿ß~Æuakä7¨˜Â¹éȱ³·>xA[ñZ…4™UD¢è²E,=´„Ò3’€€¡wûÓõ+õâ„$6·QGýú³ˆŒü¿eLìàUvçÚY÷°àpdsë·LíP†ulÓÂÆ4Ò•TÎ ‰š€R@¡ß™#žÄÊðï2ÂB€ý…þ6XQÉ*,©h)ñhõX˜úB_豕2dVpë¼ÎH€=¹ÊY§êÚY6HÉ8{“x¿¢@]ˆ?t¥ßÐ}'YKOýA©ÉôeZâ]f®˜ÙvªC«˜p7…Ž:Œð¸õ¥òÛhªxµ/Q£Ò]# [N¤Qdíÿe½ÇÈþWÌÀ,k¸YÛªÌ.‚¾¤f¬8Ž>Y ÎKÖJÞö@Oÿ¼s·Ð#ý(V¼úÃ5 g_j×x–¦ØÆ;n~‹ã€b›Ð™v»½3ªÆc±atGêsø†’£a­·Ü³•‹>¨Ó,¹é¨K¬c÷¶£Im@„a«X,@7÷}KÓÖZ5eR•ÉùŽNô¹GUY’Þôg:ÛT{¹r…ÔÁë¬n …P /L—°ó†å8¼ŠA1ѹD4Dî“.­ùÿ=dޝ”‰« S5¤ %È Þýæïw¦šÖGÝü<å£{3ß¶|¨‰²‚Sõ@c²ÚÔÄÕIgú<4†øw¥Í;ê%ôy¸Z 4-Ve(·Mk{0¬ã™èD?ƒˆ&úóYB¥KÎ}9"Xm|D¾Ëw~.Mº{Çi[掄߿o‡Ÿ=¤¶Í Ž0v_dÃ@g>*pü8.‚­ÐºÜ§bT™§Ü`vs÷Ms‰ÁT×^ïü¶ãQ¨béb爼lTGòSò[$A3e/ÄÞË9μo÷ûŽ*P·Aƒb‹Î“±ÈšàI‡|Xº(z¤eoKVrK—Š÷½ÉÁÜí½X<™!c. Owݪ”äО»ØJñç¾DsÐNpÃxãtA­ÐoBÕ²gvH¶ömøôEÜà ºw9ý˜ÙÌK£¹"áÀeì¬D7âÞÞ,Ò}ž-`¹ßðÒ1FûˆÅ–Í,Em±£žš¤“¨Åm|ýH0 dG‚kyM!*Á1z·½†Û òi¤è~S‘3£Hr,¾äN Dã!;fËy •­ˆ“˜c¥ã:§¦œ®€•RßçU¸¡+Y'÷‘Ÿ†è,oH|<©y¼.øzß>6òÚ~äú·ìæÉžyDz½gV…Ô~ I¿=ŒXém1Ü_àÌi3D@ÒÛêû1ÇýÂÜ®bšŽC™€Ú||M“!¿ñ2§’lŒ?åµ¢%ÁšNô€¹¯ï0cŽjñ|j¬c:;@–4¯p´˧nõp*x¢D?F£¬Fp“û -œ –ZÜRcý ù„Lc®è´0ñØ ¥›CšW×IUΦ+¿Ä¥ê õ*wŸ¼ B‘rÉs5Ph®T3©f~ñjh?‹–ÌÒæƒû¸8¬£þx&DÝP  _8~6:K÷ƒw‰í‰÷üR4¼±&–騵´×@Þ™±ËÍ‘kãú§D™‚xYHFžo®³nEYam¿¨K (ËNÑÃo.ZwÝ,ýþUˆ/¢û]\À„ÿ1õµç"}rÊ2¦0 ïP»øÚþûYMø•Æ¡ƤÍÉ/ötN°:‡ ‰gÜñ’€€¿9¥Ít T'Åb œ´+_+ÎZ}ÿòd2¾"X2pƒB£>‰¤>Ýç—R¨}Ñ®aSÓÃïêA¦/8…¹þ‰ßhôÉ´² éÅ—ä;¬”äÊgbù@ÙÌM™ÝÅüæ7´ñGf¨ßG’±=X]ÁŒ,Ãn«wz]¦ÑЏ¤ßBQ-+ŒÕroÚ¢ãÝ[!œ?bÕï¼ LÞÎËeZÃÕõ)ÅI›þ‘]¿²ÜCÝšûm|+ {ijXf³ ˜R˜AT^ž›‘×= C n(­3†væY¤m)’7’‘¯ß_Ž;­\ê®2—ÿ­êPÏ×åsâ ‡!h‹zïãtï?”/<_Ê@xw ö^É/yªÇ³_HØÜ¬±ÃµqçfWÙÇ"B¼3»\3®ÆF”@] bCˆ RˆB³Wåj;^6d– ¡S@ì”í½Ð1Í–Ä_S”¦á\=L´OÖ´ØW|Õ¿v¤ë÷ B”&R¿f&ñ¬$7Æ ¡­<v㺲Û5"|`-ërê‡ÿòÞ‘¦Â¥ãÚXÊhfìèÕrœÁTÀÜæ‘Cxl5e!ÆCaŠàt×暑;5½ôá“·€˜¥…*™Ê¿‘’º¹i»´Âß¿Ïw÷ÕYZ ji×f†Å‹>ØÆl!ç#¹Gåѳ÷ JÓIº” 9õqPIíÞU{K©~`®¯€#&~¶¿²ˆO©ë ‘„XŒTEæËú/NQg~3clc‘jiØÇm½V-¦ICˆl ê)0Õí(Ž6O)–îî0âiËñ­¾‰Š¡ÆªjyÓÊèz„êÌ^UÞ‹Eõ!Z›('§É‹fÐˆá ø5÷ÝëKýƒ¦™}žqcAWãŠBx¤ å¤{œyÝ!NéZ¹¨´‘Áí”q~yU#eòÞãBÉæ€hÁ©EÉeÚÊâçRSàDމòŠØH÷‚HD”Ÿu¥ÅN6{”ì#žÅþe·Ï¯˜Šü÷”Ö+ÃFJwbäÚ¸¬ä”û-fobµ ÏÍ·…µ :ÀÂ%:’÷g½Ÿ« $åìêLC‹#]-üçÓ¾—0H_‡ô}ðbe°¡GœLŽ.²>Ó%xú-a74ˆB2H7öÑ(é*²&U$×$Ô„k±Üršè’€€ó Áa¦î¬x,ìà•³ŽÄ2“<‘ª8ˆ gQ5è°ƒipH2.¿› NÐ&¥¸´=š®¨[⡸ŸàÅ„€ó(b%bÁ*Æ^IxUÁþÓKȺœaÏ¡Ž¥ºÏT Ã炸ýõô®e<¯|©t˜¨å¸Ùãþ­œ5Ëuò³$¸IÒM¯@)6ŽªD ·ú€ó“,Æ/åÓ;@×ÓjC5Å6 F™¯Y¯do²ó>R¯*8뺔@*×ZY>gÊè©V[*b‘AÞJ{N½â™4þ‘aëT7ŒIë<Ê6ZøìCÐ>€adšÙi@EôµÐ·{ï9ö¢ð#·„ŸgNiµß¬¾ÃšóP¿„ûÀG8¹ßeÑ…yMñ± ÂPצ€/L ¼ €jn‰o‚D"èãŽÌÔÕ9\O©p>7Á.`¨ÿ¸ Ø:R¬-ÂLÆ¢l²—.Ùmn×]§¸b/äQ™1©MiØiIR!“=G¯"o= Bs+÷¾¥×º\ÔDÓJ5ÚËñlçg­L§üplHc;¦‹O¡G¨‡ÇúŽ÷É?iÛà‹hFŠ+ÝD”üä!Aá«KìO4Ãô›T_³¸ÜHGVHªŒÔÂIm(­²½¿/œB*5„s,®h`Í ê^…û¶{É©„ÒnßeäKXKaÂVA«eªÐÜps´²ý9 ¿Ù[û1CPz* ؉ƒpF.%á…a«¡‹‘|QjÒ¼­ÐϽ›ê! \Ìò)hŠ˜Ú‚zcE–šhCïV‹}dÀ†|H¹wˆçÍŽäÍꃎMÈãAb0˜5ˆš“Ä6™hsqgS¯qLÁÕÍ›qvi)¯¬…*: ½mjQùÕÌ|—àieŽ ´Ä„Î!ÊÙšžË¥åOÚv<Ù!œ Þ¬z\¦#KSN¥r„H¡nòmÎ_ QÐÕ•_\'Bó¦ÿuõlk¬þsZPt_‚pV¾³ñ™ó²/š˜„R/ &û :èüOj=ÿŽ­4$‚ÜÑûBjÞýXâ)ÌJ2=øÍ5¤óm9`fOÝ´-rOZX¼U2ô= µ,·ZÎáOôýQ*çŽVÝY“ÆâÕS2*È»dX·B”êE‚r–¡­@ze8¥ÆØÊ„¤©}M°ræl^¼ß¶LUƒO~zUOÁ54Ìé(¸ÔÑM»*(26CÊň[·ˆ _Y»^o§]Ò†q×èñJœ‡9RÛ ²Ë‰©Ãÿ*_ž"%†ÛDýÜô›ò“÷‘a'qíƒ]ûƒGïÿÀ‡fåb­£Á‡Mñ o5"ÕèA‡j*©CE:$Zû“& (Õd+uVþ¥ªç‡¤»¹IkQI5„{Øçaº±Õ4]þá?Ø–ØDbeŒý« Ô ¥sŠ¥Cf[’ޝù?Ê'ªæUçâh˳AЦk,—ÁiÎK Zƒ8mï6Ã4ª®éQÚVà˜¸}ûíæ'kh“ñMpXÓ‰t"Õ•Õª—àÌýøV{’€€«ø+r_¶ÚËûÚº&U–4UgØå]¿Éˆè˜¾q%ƒ7,v-!'?ª\èCHÔîË&j¾æ*o£–„´ÙH˜n(££RYGQ¼;ÖŸ¢YÙ@ÓÈý.}Hjkç¯É}[ávÆXh³_ÃdiàNQ§š³£"NH¥Îò Ù¸øs›¥-?à >³!êòÁ=Wa,ÁR1?“MÑÔ[m·rÛ8L*‘êTH¦œÐCéŸúd­ô?5üSšn@}âÆ±sŸ|jG¹·Ž¬ù­`p6oLƒn9åI¢Ýú]Ô‚ãJ±}GmüF6‹‡ˆÂùjTžº¦»tnIËC7'&VÿÄ/…<ô´›Òk3ˆgÑõ¦–vƒúéo=ê7Œ¾…Òe’¯ä[n H¡ÏÄ9My¾öäˆ"üÉ[«.yëÈËÕV„ª /n¾Î"ý‘à^@è½¶U~å¼óòìvqŒûI……÷HX“ĘTF-–åRD6|]gã½<_÷Øàs-÷²×™ˆÝ….HÕÛþmV*P˜ÄzWP8Œé¬ž˜í}ý/kj2Ù±«»W ¹%êBÁZ="wA½–bø*m)’€€À‘ªæ ÉŽ“ñGŪ(Ôë–áœ~9*þþþç~Ç0ç’­â 奻O8gÅiçd ‰Û>ëìÍy­——7,E:^÷4†–xE8ûx ¯kä2-©L¶Uƒ>3ždz§ÄÛôáóWzj=Ãu‡"Jâêx+Çýà™JUÆ=àæ¨AªˆÎxÂŽRÏò¡É\˜„½|Ë‹!2¤X"C´ÎÁº½Ê=µPM[Àm0ŽnJéêX«ŽRÎà6‹©ˆµ»ž$£æÚ)¢Ø'>„ÍÎXL2a‘°ß„SUh²­Ñ$OªU+08uï¤#¼k ©ûcqÇÌæ²hn`˜¤L;L· ¸"RŠS™ÆÂÅCvá ×°ì,VÈúsY[¢5Û2ã©„“Fñr½> °uß’B æjn&¿kž¤©ož½õvÌr2 þÂïÇà?YúÄHV ÝûÞ…åKx±H?Nyš+Ý&X™ÑŸtí°zÀTlþ1o·ô°›HV¬0 Òˆ`{[«½û®Ä ÛÚ•2¾Åyƒ\ó±²zQöÏþ´àkHx6GðêaD‘‘'ÿf¾D1ÄNLŠvÇ”V鯠26 Ðž…ý?@1 Ÿ¤w[Ö£yù»ÉFÔ¹¬jKÎSVÖfjCs!-¨ ¼‹0‘Þæ„–÷Pœ¢íù1BH’o•aÜ%×ÅÎÀ(ÙK.›ò5ì¸wô´òNÍï:cÙ™6°°%šk(I·yx~8M¥¤Táœì/T:z”Ð g+†%5]H«ãr./F·A Å;¡ H„ìî¯,›lWØû_7ÉÅßl“™!‰(QM*KgT¯ÛÅÔhã_– à5Ãvtïy…Ÿ˜Ðbñg·.\ö÷¦.Sž.NY‡Ä|Ë[Ö(3*‰%nˆ¡5Ýn‰ÆË,ó÷x·2Ê3ñ¾Cw(i¶»w]è+q¿µ¿÷Êÿn):•ÖˆbýT^ÂF)미ÐkÚ U&v;›’@îêÅÜk-ó©•ßwuŒ[}—fÏÜÜ}V-f4Ó*|c†~EsÖä sðÊ<e†ôaÈ6ø?&¬/,ÃÑ`Cê6•rcWšÌJnjÝûÄ£Ô‡A)°ŸõÙi¿ªb,d4p;1]T'çQ£¶“&‡×’€€Ó$ò§Cñ˜ ÐQÅùwˆOçÐ,–räþÂÓŽ-‰^†{Ìz☦öÉûžX;p ÇŸ‹J Áƒ­2«Æò6{&Ó:âóvç»ÖsÍjvwßf²—=ù5-ø³ÇrS¨ÍTR¤â®¼¸*¢9Ãçwf!2 Óœb@ãÔ¶ а–ò¾©ð>Þ¶yG+†ä[ }=ú†>'QÏö©CT³!jCßÞ¤DXã¢#ÙÓ’ýÍ>VBLàÀr?4ÚmtY_TNn»÷Ã&I,ȹG¡„.õ:¡cb+âá·” 8ÄÜZEFܱ¯4›£:ë=‡¼^C6PÁ‡mÞÆÝ`òÃUû`³Ò3}Ã9Þõ~š?´Ø€uUx }ÑÀ<Ó8¯ô}ߪo‹q:+ƒFÃ@Iê@ØZW}ÝPcAÚè¤ SÐËmao%³­ŠZ0Û>9|¨ŠF—àXsäb@Qa. Ù>ÁºÐ,¶ïÖɃDÄNþK>ÖsuŽ}l{µ¯ãÿ ¶Ä¼ür Ó Fn\^î%ZÒcW}ßÁHÖ½Ú®ûQ‚laı¸¢5]‹ótºÏ©Ž™þ¦ôOŒÖ+'{šû*Ÿ¨ewú7ò”¡ªÄ1 ÁáòUÛJÆ*>£ËdñÙ‰I…ùIå°XUa jJ_J«)Sy[¥~ˆê)þDör¶]^&Õ^µ³ÃJª¾C1¢5 õVTóâê´Ãj»ZKO¨ GæuHm…7–Áð«å óÐÜ¥-sÉ ÞHXÂým|œ•gÜ“˜aÊØû× ®ÙÏCwËý•/câNkp¼VK@J MC@ð¶E¯Ç’†CÒ}úuRët5ÜÛ¾œVghÄé3êÅÃL„C)ªGvpâ<  ³»oW š ©œŒà'ÏÞmàóŸªö¹œO):…ñ”ˆ—@ŠQÔìÀ†ÎX¹|ÝÕE×áÇß硯ÿ½5§gI¢G[wÕpã¢åŠüç‘.”eì3¶q7á,ÓSžìßÝî…Ü¿"Ne­N«„™ººAÄna˜hT°c:ÝnT$®Nº£w†)ÚµÎûÕ s„+v:Ó'‰Ûí8¹¡ë˜*ƒa¨Èª GÓÞDÄ‚7æ™eUZËìh ÄW®ù¤ž¶;ˉýoˆ1mGëñЖú@mÙqŠÛF,¥»Y¨ ¶_NIÿçÁZrŒøÆ…øÅ³Ñø«ÀN•­´€.j |Åôѽᒓ€7;ÄXjãdˆ‹AÊÔõúØ@^Wãaçã{õŽ„b>’1ëLˆ[LQ¢ŸÂ°ÑÈfÜUN6RU•×}kÈdœ¥­·BÖªU)ø3d[m<9¹’³m½,î” âÔÖbÙ*æÜVðëãIåa =¨ñ¿µ€¯‚bxë¾ÕNØÚ$… ‰òD”hõµXËì4¼Çà?UæC•Ú¦s×ðmçeÈ>áç ëµL±2P6X*ø—»£‡¨É¢ÓßûD^jŒÌiƒ]µ´.h §³¡’?KÙ*Ô Ztµý¾Lf=F`žª¯5¯"ûºŒcÁç¯"¯RŒ ê‡sVô”ÊRm:ˆž¸Am”>¢˜ªg,ÈÀcµvD¤Mß¿î6† {ÆãÀqâ“¿6îQS¢µq¦ Ç6$ƒD‘54y´Ú ‚tsEÙî¿« ÉÒÖüj²5Û/ØRUeIºëõ®@àV[8:’€€âúXĦLF9Õý:ùš&íö[”FA?ôÿœïO÷MïSÇd’k a¡,Bº_,3WX:-ïúëa”̶¥“”´óÇÌàD"Šá¾¤MlκÌlÓO]yödŽE–Ël71?0ƒ\²Ô&Óv0=%"Ö3hÛ‘nØCáQCnm\‡k_U:X7C xÇ ÿk/&„ÙÛPêñ±˸ñÈx^:GúÒÉztò1™aÆóa37;¬H¿åºé&ËJb£•n‘¹/5¥¼úA|~úNsÐgNE¹8Q•2@µ× '€9Bg9Ž£ÒŽ˜Ãl¥Ô¹óï÷¸>Ѽ ¼åÁ-O2Z1-[wçdBúš:T¾$tÿ5Ý¡}}¹$DÖÑÔ©uW…[Q³`i? J²ü³KC„–Û­þ­AØgN«Ïð/í;hþ$°º‹ àü*iLõ”ˆŸèlñ]Î $˜Ÿ»éÖ`ÌzÝõ«"Tl? 98 7Z‡=¬®Ö ظ9ÐÛ¶þLhHc&eÁ¿H½ë#v%š«’ñ€GüÐ~Ìo£ùM“§€ ðﻦˆ>‰oP¶" ž _À<Ý^Æ9-þÜíúš„»v!ÛºaÆ-ê©_‹¹}¥,´ djÈ©ôú6*õÍÛ‚ö³NÑñ[e/±Až¡ÅϤñ-–ZÜ”Qcn"[ãä…Íš ½'3ÍÕJÏÖdÞµcí°<T)áuê<è}Èž)Ó¶Ò×íÆ¥ï¿¹&ú,œLÝvûÞ„8¤ædt¸Èë1OÚ×ÇPŒŽ%¦¯É($³Š=z]`ædu£•ÅÃ𿟸”#Aô‘”?gfJ*~›cú²&4¹ã aj’vÇ<Ì”ŒùÉ" uÄsäñÝ|Ò’kÐÀšDù‚”ýG¿ñ|"΀Â$ùÛp¢Ô‘:š.û,h•L9mš^Ï UhZ¤eÐÉ NzÐÙ£ãRo>ÇÝk^¢‹t†Ã»—e½îêã™PÕƒ)õ,©B"½mäIQÂ7cîÕç-hþ¼ á ±B˜?홟²Æï÷‚×=DêìÀÒo˜9C»˜hù;*ºË^ ñèr%5XkE»¸0ÓKA¨Xƒ;gK´ný‹ô9Xªç7¶j©%ë?þ}ÕAœOÒ[ˆú’€€åŠ'( jö$tézó’Ñ÷í=¶ØßQï'Úùܪæg='8gÄ!•5k’¤§c¶‡âv4leüçÁm//2Æteî˜Håìþ‘“ñG8÷ÅK7ÐpØéȵäcsǹ/k=ÿ_¹)Åšd©½][λ0ÔÒ:4B·SÂÄqK6C ª•pÉϽUKFØÇêPw«*š2Ñ÷㊼Œ¿ÝOR ÷Ž®·P:0œif+~@*ýþ<=–·ƒ·û†÷V«p…“‘ó:všÜVl™;gôþÛÑõ¡ÐÓJkÅ¢„ë’â¿Ó-xx°òVC[b· e¿Á^ Åk§¯ŒŠ_D¸GÞ`¾w¨6ñ—…_–AcO—8\·½¹;Ѻ^œN)$Iˆ>+ªÍ䂪+ªS4Ã+0™ÿ™È¨³**Ó=ç‚‘ô.kµ­~AVëÂ*çXÉ̇›±±Ñ¹"‹Ðn-ãÝã×LᣨzABeÍa«ø²¶o®4㈠TLn¢6:ôÔ?üNöB³{²H«Õ'Yë]\°$±d£¾Z³©“+žRñÕ»ŽUhóW¬Lkl+ó±GtâÌ¥A®YoEZ÷Q¹ýGOCo(¾Ïjõ¯¾Áò۪”/m $LAàj°vÐôºaòš.øŠ^²èEˆžkÓ €ˆ› Þ×HphºØ;šú\o5W80«$é!åõrùAµ殹<43¹Pçà*LAã÷¨M]þ[ M¸HH6P% E2ÒD;¸Ck2 c?óÄÿ^!gqHöcŸøØIsesÛ•ôk‘{V˽1J¶õP8HUÈV¸Hƾ©âgâ9¸ H©ÛSHC • :Wø@££êæ’¢*Ð}©,}S é!ê’1„Q­à~­häÞ˜ÁÜdÿŒAì™0[OZ[c%æý; §i¹ÓÈF¼º‚i-ƒ{HE))l üÏ!Ç£ðŸBþ›~VÔý^Wã$‰‹A3‰:¦i77,`œ‚ª·¹È¿^ç˜ãžŽ˜ùð¿`¥Ö0{å¢Üpà$‹JÞ¸¥ ‰É:¼5© ®]%²ÅÉ]>È~ºKxß/J^!,ÆmØmŠŸòþ¥üø;ƒ¶,‚õœ¹ Uø¬±Bf ÚÑä›%Éesrûg#¨g5ÕF×× f“Sny÷:Á‹, ˜A•ï Z/°øaE …{³F¤…ã ^Ñ7¤WÅÞÓ yÎOá†.éJ¤I€‘nÒ n‡ëèíxùà¹R”^b_X3˜…0¸n ÿÂhýËP2:£pбEȉà<ò],›I¬ôÀjjC!­@ï\0Úüÿڴ´Ð̶5>æP胢†«ço°`S†«rÔ¬Bå>îÉ)SsnŽáW7y(Ý·»%kÅ߸eËֲ߽íøçHeï"Vx#âÆÈS›(›’ÖJÌ»åZLâ©ß{Õf¼ФD4ÌOÓ5ÍÎy?}Э³<ˆdúü7&—r¨Äۊ赉–í# yøãûS'æ!ÕÔ/Õ™@íWé‡ÖÞ÷†8™Hïµ¹(ÙÊ H~ùÁTx¦·«FœÎ`Öç±A Äòˆâúµ×4“ã u™ì¿c‘Jø%ÜÔmM±"/þÜe3äµN™Öê‰ì«R¦.’€€É£Nòü[FŸ_Q26nÚ F€ikº_ºMi»Vú­·¥gâC•ONMîÃ[]C¾¹‹Úî÷°÷“i¿ñ¨>TðìAzc¯Â}· ®u¦QX Á[hH¶áO4ü\®'¶%*Ç÷‹ûÙóF4¬Õ¦ B‰Ûg߀`àÈ*ÜU#äÍÍ‚ Œó·“ø‚5O<ïe_ó‡å_6'Áú´5<0Ú5 NdI35jžC0­x#þÜ}ˆ@À³ÿˇ7`µB2¸ ‰P£›R ÌÀÏâóS·zMÓ(Äîæß‚|_§ÿ úëPÁ¨¯`R[Õ´0Rås+r()@´õÜ¡ñ¨Sfd}ó,¬&ä£%=;%J †öqá‰vŸwäÚ‰Êá®×FæMÀŠÁ0ò%ñ"ó·Ù%8bÅ<CÔU Ù_åÈë(}Ëe€/NF×>§Xäˆ!©ð"t—¯ç)„Z¸–ôá¹î‡;–èfÎ[.å*•Ü.iùüÇEÝ¥˜áËÂR °r$Â˽eäëÍ5E=F ÁÉ^ Këßì±ñ¹²r*hÁ E'Ì_ sÆSíûX˜ÂºáP°%ÎèA¦äu•Vˆù¤@üo¤Ã ¢îÅp̆÷}áø-úžÄRëHˆ«¢95‰%Ö´€v¬Ú“!ú„ée1ÙfÙ›÷›ErÞ(xÿ¢Á¡c"ÔfŪÔç2C6Bž¯o¦'ãеµadxDÍ5š üÅè,E0â7ÚܲÛÁ¾£½ÀC9ÆùÿŸ!°µc@¼:`š>ã«¡äÿ‰¿ÑÔ–Ú Ó)¦ßNÔ\üU®V¿C®"·ØGúÀUÍùŒ!ñbê€Å¿r¯×Ñv&þhicÃzֈ±Êäÿ)ϳ–FdîU!£D%¶Û¸G–N6R.L›…-Òƒ•~½°AÙ8?NºÄ>Æ¡hÞ)§l³<”+½=GV¿M€dºG‘N†)L^0žRx¢wñÛ‡³œÌHºª &š÷VXo‹+«mÜ5vNáçZƒîLƒE9EHŒ²p½U RªEñÿ‡Ÿ¶ñæ‡Òy‰RÙú’ßî6QýwÃHƒ`Ëz”7IŸòèÇí’ˤ!•ê‡À’€€ç›fn%¥YÓ^O{¯d$Ö¬G”\º Zþ¸Ä½…×C[ÀØq‰TØ-©;G’½ÎËŒûèõ­‹{Á÷ø¸ËÛ¯;®¹æ.zÇýð.BeD«bg&Ôê‡È.?¾Ðæfe'::˜‰ó¯æ5›@­WHÓŽ,nÑ«d¬.T&Ê?ò¶3Éù¡ÌmwðBÞ—Q6Å¢=mb˜è€©ÔýxÐÒÔ|íÍa9œÓlÎæÒ(¯‰Ž‡–ž³hãoÙ.‹<Ë~hRï£!O;¸|n¶—³B–fI‰¤œÄgoŠTZU†‚!1¦Xƒ1†°|dÒKm$¶™(•§Óº\l£RùGæš-ñ·Í»žéI¦»˜ÉijüÈTÄjJÔ ¶-søüÚškù,Ä% AxgRÓáw61þšµÜhnê›1;ÓÜÜ96é$±Ïž¶ü;ÜÃöÊÈ¢„{{/”‚=üâåóõÄPqdžœwýÍ E“·F=>šâè¿õbÎE蹄’Vnã#ý¹Mu€(í¡\þ‹|ÿy/«eìYí÷–sA~œÇ€3ÁäJ)]¢odä5}qÉ2[9˜½vó«O¥ë€ì9‡ÊÓ!C•dÙ%KFü{[Ów˜5OŒ4ëtçÃ$§ÄåpPßnu´´ÕÍíãý«b™ÛZ zæãMãô\’Y4#íå*wÀ‡0K©/ð^Â#çŠ0\µÇpˆX`…ÙTóåÉú¶› ¾bFÛ¡Š®™™e¨¤Ù«¼a·Î/ªK馔GMy-n2É/a½_‹Ž53B˜^ªä)yù°ñ’jG5Ñ ï‘NÏËñcï„äÄ£ò£PÑ8¾Š+õÈíZ5c>k!jÐ×»2|Â*ÅÍa?ýJŸn´Æ§"Z޶0ceÖnc˳(âþô¬Z»4dÎN蛑IB¶!ãtÜ,ÍO_ö•¦?ø=†‚Lø‹}€TÛošdM,!ËLYùÌü.”ˆášï!ó'³ÊÅ ü³OT~0çFœ§.¤MË1WZaû™ŒÐÖZí¼g¶6ÔØ¿à4e¤NaÜb~î+@®0¬ÈÕ›5´è´^XÎ?$³¶[ ‰® ­¨£—a5DPWùôSÑió^œžÉ¿rXÞcl<ÁS;€0³˜&ŠY5È&©&ƒ|üæ>“þ1mJ•QßÎÈ41zázA¡|æ¹éØžÊ0Ò ±,<ä¯ÜÝ!å¼/Gv'Ο.³îe k×RH¦³!Wmš¢èQ]óu†¢?½g#r>$Ò‚˜õ*z R•ËWסçbsXQñ®owÿ€…Jß­Ýq*Ì–w¨um#Eðänð7¥©·¾>¸sÊššs}£|¥‹øÂõS•­LåIþÍSøE“™­“"é>ðsøêr;?Ú#-ÔÂZëØ@PV«¦sZ«%S.·ˆØuÎø¤ˆãƒLþ’x4±];Z^œèßÛ¥‰€…öMyGFÛ~ãzi¶šX¨¾ùHÿØŠ‚KH7î‚K~~_t:¼Ú¥,QüN¿á'ÀÈ:ØhÛ8êä8YgK„÷!ÌV®â‹s>‡pQ©þŽfHˆÔø%ïü"8 UA%u?d0Èù·xT°Ð’êÀ™&¹#f^6ÓÉW\H8¿ïÅ`2/‹ô ︚ݭiÀ¥<á*Rƒ¹³ÇŸã>1ÆD`éí¹Úª¢ Êí+K¡N“»³ï½ä¦b í™§Ñ3i\lMX½€¬òú`tEõwJ„ï'UíU>fmÿ–¨ š¥ºn‡áÜõ†|#cͺwà–¡Rõ¾.¤ä^…nÛ;wÌ/N@`ú^õºE{b‹øv? xó'cÑv®c†g (¬ëÔÝðô¶¸}Åžü’jr~rÞ¢“7a.3¦R“—=òö" óåÓøkqØ¿¡`I<νÜÉÁ©\„‚÷³* {Þ*013 Í:¹³¾ÓàXBÏ×öŠ…|A…—Ä—Þþ|Ò !¿²O`TO²'YS.ØÍh’€€¦7G{á_qWžJIÆy UÈ*œ)â ,¾oËcdgÝ)džGØ4ïº×ða€¥`aÚÏ­fP$'§f§ã^t™äà¶/ýØÜñV}0ìtj~QxH©]4/b¢O´¥\qóå^'ízœŸ¶v‚ÿˆ—oS^•qË–²DùOƒ¢Zök\Ás@Y éll|a3â¤ôÌ; ˜‰„íÒm÷0‚AÈ å6s;ÝuæM8ÚÜÙAë[…Rp™®1ÉCUîüç.æ¯Þ1Ѝy+ßPÄÜÿz‚r>X ŽÀéwצg ¿‘pÓ~hSuë´'ªÀ°%Yž«ªß'ÝéçœXé;J‡Œu¤C;^\¬óÄ]N¶w¬j¬üô EÞæ™e_¹|ag1î&ðTÛà©äèΓûX+€W(•4#æÈIêÛªy£× …ÇÒá㵇ùØD½Òi£ŽšÂLIì.¦hÔÚºÀíqK;oPëÂOrs°¨rH°ø#Ãs´z¡˜-úÙÆ‚rlZèrÆHà€iã?Ìü[UH£ªáОãE’ÄÒÌ¹Äøã¡†™ÿaXåÇh$f vœj„­?WK¦èãWï0+Ä® nvˆÃž­m Ý1SÑhØo¥áÐýÍojZ1n×o.ºØMû+Fj@ž“0QÞoö Q<·º ãAg¼*÷®fâÖÄÍ€ùPã±ÜþÚÃrïŸú 9ÃüeÌ& hž°LÕûì–@‰r6ÍÛJ8ê(Kߣn ‘Î8Ÿq8.Lâµ*i =ý&º¶peñËMÔ3Yi#,NÙÏ_s¾%OãÈPÜ­Ï}”ÐH**¥¿t²a~&ë˜OnH³U:Òq½ÉäÖL•YZªY¾]›²fœÒžk<›!~ô¶#–6Œ‚™UX¸hò †z˜íÄŸa>(€ú Ù!¨¤úaûàܨgBëݪ3ËUÜB~£¡¡fóþ#þ_:u¤æ3ÿÉ}¹è¼'OBkÂD]þ.¾¸õœÄ†„÷Î`£äd­HØSÅòêX@[‘õ•.—Ž>êÿºrW’€€ìê<ï²vl_ŽWÚ<Üݘ7§«³Ó00ÞæÈ‚Ý&xÀ&J¡ro`î ZQC}Z•cG?G\…aÈñ%#7¡N´÷t¯šKºïÕŽ¨«C+îï’mzÀ$'—ð1FXn[HÃb¿Axøe iláD§j'm´ù½`Öª‰c_—©¾uÇ]'©/9 g+ýæH iPI=–¦#©2RÔ+”Î)+CuÆ"ß‚õhõŠþ,€Í¶ÑµgË@ŒJLŸ¾:Ggˤa~ sÞ(Ô.Û“®[p.Œ à¦Õ¨rüK×ðç4XJÎV鬽C:ÚZ‰XCy(Ð1=Üy¬A›¹ ljƒP8m;ÒÆ"ú‚Ž A!Ì}c¼;>ýÞªHÇ׫_÷r+Ýó±ÿ+íýŒßkÑYäGið]÷³ò‹ð°ó¿¤ á <Èô{),Õ׫µÎ²;ï#Ö¨L}I^šËÀ”{Åjzžx£ÌU²q14U©¢Ë¼pLkg M#A¶,Œžß=ɾG›27Y;¢¿ìò{R²—ï«Óª9Ê/Z+,d²ÅܦÖÒ [6ÀìKv#¯…± î¶Í†j©¨ø©×°ñâÒ]%Ò·õÒ’‰ŽìP0”*_yH¯’0}2›=45²bZsflú¥ÆÞlá8;&…­z€'ó„å8Ï3ú~«°('^1ÅÞK0LPúœp_ndËHK*T·æB_ƒB%YsÉT·ÿ}Ùt• ?Ú&Ե˯´H¼:]«ÿÚ°3`¢3ïRvr›ÅÂoc”iôH=øÓÖúòì2êHÁ5÷$B—ñùcŽ¿Ä˜êÆÐzöËï&ñF&âëôȘäç‡ÐGáC’ȃ’îÓÖã^~µš(Òhq笥þ˜lWYh›ëº7ÚG6Á«E±"J;ûíãêjZ|{jlæß,çÂ`ý,•š„×M(Å+ÝRÚ`+² aƒ¾ß7Ý­«â‰ˆæD‹ñ#½ ‡E·ƒ“ÄVD¡dFA(&i&ëo!"ÒéK¦gþ—Þd®,Ž-1j%`î\B¸%D£ÂÝuâ”IÊÊé³}ÎfÖÒÔš÷wù{oEOkDvà±Y-"ß6_ñ\ö…Ä•\óÈy1c­Õè·­paý{ÄŲ/Ì´¬ÿÖzµæØƒ*ÚÆµ9­A¾£ù r+YöŒr¨/ñOIÍÆ \‘{cQ¶záØ‡¹z•i2"S5ÇŽ#è:Ó]á®ÂHîÏ9õ¨âzB¹ý˜×›ñb×qBó€ÆUˆP« S5ÊšAwýîÁ ö^`ãüç Bx‰lxçáW¶ä•1$y+žÚUUf:Htu[Ñ"<|)TAŒ}ãÂsm¿­(€ÝÞDÇk'÷x»÷ÛŹZ_…QŒÕ—›#ui-ýý‘Á {% ©IÿÜÔL_I;d&LþÖdbpýÊ}j—õÖ[ñ’}“Ù1ã§kŽ"ë“ò¶àÉQ’5xBÈ}ÖŠ”[*ÔAg@ßnnÊèsª¡„£‰Ë" µ)…"™œ"â{ø>lÿ4FÿN &9È(.²ß€8´Ó§Óà8ýüˆ&Ùœ°€±È•žƒôÚ5ƒÿH‰ kdtåý"µY8œ¥ÉÑbwÙ°\ºÎ殞¸ñ®Ý ¤§žC£mÍy Ä`7¥ÿÇ+¿X®ÏbjĪ˜Ñczî[væÑã%½é¡pÿ)Fös/õxJýôxEèqIü5ÂüN…éDšêü5ª‰ŸÃ8Í?²þz`}v±jëæ¾ó0‘Ò¦ó!4®ÔªõR9<0¼žCÌ¡ì}ñÊ k ¿Ñ Ë>Gùçy‹M’€€«[ºM—o׋³¿RÈܰ}“#4й޵E1oáÿóYoöä`§yùO$úü^©^÷H{ìu¦žó…áö©'…T–_ä›ù#!© à)]U¤ðŠç-ÝÐ\J Èk)ä{®êÄP†ï£ëO°d9«£¤µ€òµ¹ÅĽ›7;ظ/'úùér}E#Á%cýÃ$%›µ&ûiY_~ûŸQðäÀ$rB’³XÄÖð3Iš’ƒ•V¸_U_j²6BaËFL5˜iˆ£[rÝê,ßåà ¥ê|µþ|~VG«a˜ÆÚK••–—LK HWOІiÙÚ#$ÀÎÚ¤̤µ¤S`b=XòÍt›°ü‡‡˜—½ jõp‡ñ`vÇ÷nœE ¥eP­ÑšÁ7Kí2Óaé£;~bÆë“‡¢®3x¦0‹kéûî4¼{ÎÒCà E bÆf÷6Ÿ-úÎ6¸8%eLü¹àq@Áµ…ܹÆÖ¹ª|³?œzwhœnDçCî:‡¾nu—ÖGŽ×ôþ:b?šp"káÓHÊøÄëÔ"ìdK0ó i+Ý3Gvt,´<®éßù‡Ð]sĉ® 0a"eük‡›†³¾DöLHµa¦#}[¬ Ô3ìj8?6J0Æã^64Sƽ‡r1ºëeÀ\AŠ… -œÔ+Sì=£KxSb»Vœ«)¦ׂdÃÿ^™÷Øe0V, µ Öë¼Ü©ý¸\à5¯W=¶+·P ½zQnGk6I‡"ðôÃÏT‚Ô¦ýšôïŽÖ$«SßÄQ¶-o6£l)ÔG¾u©\+Û%/Éú y d°§à±¥öò»†³gånîÔ ƒ€ûAFù䀩 ÑÓý3ªëÓÖV3y½õѾH¹ ÷eBÈBÃÔÖ/;ÛÈ¦Ä B܆aL´ö a?3ïI«¨Œy•6`‹Î·>°ÏÈ8ûÝøõÌ¿’ð0 –ë‘éŒ3¬¹žNô­/uxаPüÌu†Ïû×þ åô7‹„VmªY,Œlü/Ê+‚ó°çØ]UÚ]×ý¦Kìþ›aÍþ„$„S'õëÈH^—º%q1üôë ÝVpOfDv×@òTå,r@thx&M> ÉoPˆ3ä¬Ca©ÍÑwò“1 }D·¡Êb¡¸IêkFz ªÌÇÊ×Ù“Z  òÒ9‡‡«¦:™%Í¿ÐéŽä•iÿïÖc0Å)ížføn©em^‰¿7Í\ÏjfŒŒÌ$^ƒþÔût¾xX?¤õ_÷½CðýWÕür÷ õT}E.éK&€Uwhz4ÚBx×’dýÔ.e·ø÷׿ÿ¯ã˜ƒÎ¸ Û»¦=øL³uþ1ÈE vòq² jîX.VùÏ,›½å‰­4È"L ¥‡øõÒ3É0ë÷¤="²E¿YhB2ô‰ûµ&¸2gÀú-#3Mð6pƒßJõçˆä}Õ,Á5Šáä;± â£åå{$ZEq×µ >’ÍcHaái°µlRwÇ£?6ø=xÚ‰¸:‘`,{¸øÐó‚,Zh`ÊœƒasIþMœ‡—^sëÂFEG÷ÕÊQ"ÓÄ;ŒâgÅòï‡Ð}%~B;àÕÓp`»Þ1o6jb8ºûa– ¼;šŸš.—k|6Òýý{‡Áj7yäÁ)ŽBŽ1âœ6\C©ÚPeaJ³w1rþUÞiæ$R·”Ž&x²¢î1£øÎPs |¾XU|Â'äFTKvý3žI[Ø?ZÀä±{ßF4~Wßô`rÚƒqá¯<[$%ua(gôCþ×yÔqw‡¼D®CûDçˆ'‡ÍŒs˜ÀÀüѳÄöaèÅCóeC.ß|‡BÒú/b·ÝT²A1aœûÔV›O1$‹’-h·G¶’€€¼QÃ,t`£Ékþ¥à¾º]÷•Z£j‚}rX³ˆ¥¿ÏØ¥û4µØâ¨Ó¼”Ù Ò™éør0ŒþÞÙt5gLFŽÝÍÂÆaáËý*“VJcu扤¸{©¹Øîs ”¶Xñ9é*µÃÒeûÚ’â³õN*f 6ª9Q®Nrc+Nmb=ÓúG7¬H±\‘ä9ç¹PòN+Oׂ.q7¯SßÜŠ¯äKä׃‡FªFÖ¦ P…ÿp½ ùq<‡¾U2;0@ÄoØäI¦À ¬€?8I) < $’oYËX.ãJóì„ÔùÎ~ƒ"mÏ÷ÕÝÒ|¢Íñ]·v±¢4cO¡¸fh>Lä­¸¶°‚?f¸ö¤>‚y(°nôOZö ßlüT±µ_O`ñjÎ'î%ÌÜk€™½ünt)NÀžÔpؔ݉xUJ(…É”÷ oÝÃï]’V«ˆw7-”*V/º°Î»¬üô^J/q·Ó¸¼5õð”} öÊd*½[ýsÕ‰žžÚ¯œ¨Xù—¿õj©®¤ãò—£¸ãÂ*ª±ê@Ä=\f[Ù§H/ì…ìRc÷†í…»…Zÿ5Ág–ªüŠÿméj¨üd¤þ¾žtÿõy”—0Ñ’9µe°JS#ïœg»ÑBú²ô¯ë?ð2º"}•ïèíh-¿¹I*ã+Ü ›µï!ûp»pIÆeës°Š×€Ð‹­›Bó‡œå!•˜£võ—&RÝwäåÆÃ=çƒU~x$à8"ˆt\qq`ÝÐÁȾx›<ÅéìM3\òá_Ž™™ç}q\›NÚ ¶µ…kþ‹œ"«€+È}nc²òÔè¤M]¿É¬O¾=&÷gm¶ýo¨|ñ4§ãã‰øZà{ `ÿŒÊËL‡{Ä‹.„L¶Ã;Óˆ"*!ÃSmÐ+ÀÑ"øÆuºýG®Ž“#.áì–êÍŠèò‡#ŒLx®숫hóre”ô‚I›A­ –º ï Œ-H—$™h™Î _í¸ÜlœdéÛä 1yÓ.0`a#‚•ëªÝ|œàUÛì”ø„˜Q÷MÛ™>÷èÑ3“1ó6û<ÿ„ŽR°^qgžÚÎo¾˜ ÷õ+ùÔ¨2‚‡Ñïæ4f]Ó—lµ/š.›Ær±XUqXÎ=Þ«w¬a’€€²#ôæ $OšÐ®KH¨9y3hn\Ûz6Ç Xe}GèZ ®Äzaò"Þ ]þ?›\.¡:':L„­ ß/Q•DiÞ%5•3˜GdÌbñLã%õÒX(¸Yý¨yL³¶ÞHõ#  )ýB·úߎYlÍÙgæg£ÚÐÑmP|¼›ûÇ/N“Å'hZ?¬Çä“Õ›êØ»ÕÀ0Äãã‹ÉšFèàm‰_­ˆ]ª ã'LmBàOÜ ò]¢é›@ðüÏœ+“¦Îöàà‡ù¡%§5ìgbe§Gdɵ12NãH(©ŸÕáÝõ|l;pr@©4Ø¥ ¦ § FöÙ"â{3 Ëõ ‹¸ªŠÙ\ÃÃCš<x|ðÓKm4 àúã;:m¤¯–˜Ö5¨¡Qr\Æ ™›ræ™u:éñNé}SØÿÚ4žà>ÝП›,,~ gı¡îEQ]¿_›t¡”¤pšçø? Ðï`úæÉ_êFJý>î¸xÀ¾»â\^D-{Ï*Ø:;ŒlréAhe!t5 DÚ«!àþ–VúþÐJ!‰5ÓFã«A,;Ÿì‚¾”+ü“q6©®¦ô @JkÃy6£‡p)YæçûnùCÑ~çÏ gæÁù›ûèU+B§ì²í¦ßÊW‹ÇM-É-tJà5l¶ËL5ñ;û@:¶7:${kAàñÒ¬nÇPc¡KÇ’²–Ù×N̲ýô@žàlñÀÕd?Á¾Ú¾ÏX>—É+­“X<…Éþï‚áCõ·ê%œMÑ¢ÀÑ%³¸‘òKK¤“ RK¬á)z6µÕ•Ó-Í»Ea¯q ËfKÒ;Ü,„¬ý™’ÞÄô„Ðú\I þvnA¬Þâ@á!O¿º³&ÉÍÆcX>kî¼ ƒàÎ$pÀ…Qibn_= ­x Ç›•ø ¥¶ ½”wž uÆ­h˜ñVcR(YC%ᬶ& è*Ô8ŽÝ_ˆ¥ÞûWk áÂAMž2’ùÈ$Ã>¾±AxOYïèµ|Ãýž è??ç´¸~ÿÉø)/  : Ä#'6Iò>9­7O(?ð¡9[üFØßáÜ)ù4¹ 6C‹ÄB#7þµ™Éw9€dÕCž=€äè݇[¯Û &T!¶$Okl6Ò}¬ñ=“¤Ž’€€Ç÷fìWÇžÚÚ.?ÿy; ^˜ÝÝòÞà×”Ú.µ$•gÍþ0Ÿ§Ž ØRfEÝï´‹l«Åšu¡+›á*´9)±£D"c³p`ƒ""yúfzí;e#–7SeS0ÝÀBÓìýñyêI8pï±ä)å¸Â»¸@÷0/ôæâ¦°bSÚÇ&:bKÁîC²‚ŒÜ~•DwXåS¨¤D{ŒìG‚׈-¼YCùGÍvOOà }Œæ@å’5Ö£ÂÁäuÖ\ŒJÔ˜9}ÂhÓR;†=Æž•ªæÆP*›_m—‹Ê‚N°ÀìîvþŸ‰¨Î}²‚æI?ÝúdÙkî€ò'.Ï­7 iæÔ¥w8ç0½â¹½t@YC ¯L}²m—ÁõMyJùšþQ5¬ò<Ä×6Â?ä”TÔñ­Q%à —nïpu–2±êçäéÜoG‘…{_ß¶^ùHùÄjXò“s!Jò{Y^w‹ò€ÁÍ ú ¯tÅÖŠZ¯^æöcóPQ­‰®×/0Å]ŒÙ[¶¦<ùƒ4KJÿÒ7K¼6QìVDûÝ4¸óg±„?92heÎAâаWÔïPð%C” Pg$"HÃy(=5j8uôÁßD¯ØÀ××ìâwn:Æé®î}Ĵɹ›-=}'üàì|=˜Øy–qr-¢îîýæØþèæJ˜ám:]&,1Qª­Þ最‚“ô³írÁ«1©üý“w¹ÐšÛ¶ƒ2a`ÛÁè›éÓ|Ék9m ípå{ö Zp¬g‘·ƒ7r#ÓÛ¡¢æºNòŒ´Ÿ[‘rLß ?ìÄ!Ƙ‚6’‰îtC@ÞãôØz•C‰¹†÷ñ×?¢ð{—’€€ÀèŽnMÿ‰9fQØyr¿ÙõRZµb ý£ÂÉ‘TH/ùO½µ[^d¯,«Ùx2¶h’…’ˆGÕ˜s¢øÞîöm¤K=aB_ñÅׇçW_Ú¬pU·ÓYÈ¡,°ûÅwÒÜÖ c]óÆ—z1ñš÷G-Q‹x•xzH“¹r¸X¬B0°OAž:ÖZŸ‰ÞIÎçµRT)Kb©8`¤Ê@ÆÁiÐSì ÓiÄì~N®È³©Py;sÍ1¿:¿+ä§ì¾©gÐ~¬Ìø?R“ö霆“–Ë GÛnËRŽbƒ˜ÌàŽ]<¤½4µä-¬IïX#Vî0‹ø0¡ªJsði0{4‘Ö~É"Žþ½Þ/§x ¿ö ¨6[(ënè§Ñ㺻*¬œ×_&“Â÷\?Ç“y¾«*?¤­ç5tçXýp#*62»Þlí!îU쬠Zý,>^KúDÙ{` ËšDJ———†Ê†f¿U¨cÉ]"Ÿä&i†Fú©ŒkÔ¸J/JCòÌ‹yâ¶`z°.ej¹ üña Ó 8øvØî(•iøZ-¾›}BcoYgð<œ»nÃuœ¢œ¯‹ê˜û£Û„Õ&â_H…U_'L| ¥zKLüïÛ[ âqãfípO¿ô`Í‚™~ ÔþÄ0>IUÙ Cþ*ƒ!™ën¬"dµ¼-fÿT¯[ÿ Y¨5É×iD¸>­mËœ¦8‘¶ñ UxS½Y8½é¹"¸»·Þ,M¨šh¹áÔÙºMhñ2^t b„æm½H×” I+.ùŽIãµÄxn  Ób9ñ5ÔÁÒâ2Ê~7!ý|ÉÖØ¿œ°£çù°=A7Gù2‹¢˜Ðõu1;†í ÉÈ‘!ˆ*VÙô‡¬0ø{ˆÆBr„ÔA‚µ‚ôl³%ì…r ರx¹5E¦µÉ„žî¢Á}.Õ³¸É´ÇC¼Aîeøû©pÀ@€§]!£Üs/©BíP9:Pžb¯-CªúÎç ½ßh“]æA~Sg”­¤ýOþxåJÄGI¼Û(2!ÙtÏ õÏéšémXÅø(HD˜̎í#’Ì«2÷7Ëß°ü* ¨¾nÞ@,² >œ¨5ò#²ÉŒÑ­Ñm7þÑù³jÚŠÓ°+ìŒÕ?Ä”Àª¦á°â颇6:Á¸Q.–¿!À¯Xö%3Ö`ÒPÆì‰>L!õÔæg9þÐçKþ-¶é‚¤a鲤PÉþ¥sp”-wui$I-Ë83@’€€°3ÄhUWŸx²ù)ŒÓÖïÅ—MH/p·€é/‰…ÅÅîÃá¥Åñï9 …OÍÉ;¥ NŒÒ¢nǧ¶Ï󺮻©â<×Zƒi ;&pŠjÙbOBG Žô)´óµ#kcß’¬R²ÏÆä»ÿŸ:bxy‰öš^‘"}TÂZ„7/4±„‚dÔ„¨câµ S [½aNØY¾>1OáˆÂ,Ÿ£¼f~25ÄÂ.˜ ts·½8vƒ¦G§Å™ä„îîÁOP€^•Á…Bzs÷ÇI)eâ%¯‹âÌÿN¶-—®%Õ¾ðÐ{WgyÙë»S8•âç,0pmøÓ.Fo;Ì­Mêj?§é§æe£—ÈÃn*â$4h‹RZXäz¨Å¢ M2ÈI~vÃÉ¥’úÁB_)) Yz/@F©kzŒ¨“+R,ÞõWÏ&RÕ0ú"® üdž /êÃ7¶âÉi•&mˆµíY úõŠÎöU!öˆ0ôJ;’öµÞà$åÐøãQèô ëJ’Ѐµ‚âBGjD§¤ ,—0;/]£årBH,©==Jò æs'Å÷ÖsŸE e-8¢–íõG9ÓÙÚ¾âWˆ à4„ƒß»ÆÑeÍÔ–ISµZã%ÓçÒº«†¯÷¤‡_óÛ(B‚á×x4o±-H=Áw‰þhŸkA^©ëxW2• 9ãØ‰Ç’U ØÍÄ‘Ôçô`Á™úyïè¡çÞ&·<¢p’4–ªª8°Vÿ÷ÉŒ¬BwÔœÛÒ’”ÿuP¥bªñÊ ‹¾6ÖÃѴ'îo®©]@“€óîpƒÑX«j¹ðªO«Ô¡ªMp0¨Áiþc?Øå^8ºx˜eðt“ä¡×o×Ñþ5P±@qØ]-KMúê[-rDÿz»)gä5»!–‹¾Ïañ¯›lØ+NÒTÿ8s–›4×è,íõ™—ûEãZ6˦¥™GêÎÄh!ºœq¼f8뺬N„2Ú–>°ûØJÐ&Tbfë kÏöÜÏ ;*úÕŽeSè„ÕÏòïÇ#‘ç‘1Åó «Ÿ¿ ›ÐîüÄQ*µÔr½l§ø@ôLÿC¬•<³{ÉDªÝ5-èj.ç”®”żŸÖ÷ÓÇì;éÂÒKF?*œVX†Ù+ëQŸ’€€¶ŠE¥2ñÁÊkÛ’ÈêVòË 0 †—‹îÓ5]°E×öï+S¶I=Èú#•šÕ½‡0aã‘|p«Sã­G0¬€Hëç×Yzå‘ñHùÒ¥¬Y‚>›dE\•ÆK#”tõã4´ñ´çU~/ç…m=tÍ_´„Y×ÀXÛ4”ˆ-ÈvèwÆò`Œ ÚM4f°ÆayÞ÷M¾Ñ_ŒYÚH¢ïN/6ôßÊôÑ5ù“Ðʾ#Þ Ò~¶E2•ñ<þ¬¨„[Mr´To„ù°Bôsf Éñƒ¼–ZÄ6I°d¥¶]ÐÜ=v²{Æ’€’ªÿÜz6)ÌZ;I®©‚ÈT]ØáZv¼äºŽÜv,Obq«3zÂCŠdªñnN&]ÜÕ,Ë ¦Qç2s+I}LRp\¢I^f ’cb7Ü¡àªYòøÍFÖÉ ÒÔ§²:Ù‘¸MX%mà$8°¾DtGå·!mZô-n<-TÜ¡Yaá”yºÁ¿t®|ñïe¯M“!Õ ¬àŽP÷3çóg2¬ ÄYC†,äÙSsææ±ú¸÷·ÀCƒp¶nQ0óMÉ{ðéKd§+“E*ºý?eGú߀W, ÎÐM…+Ê{Š£QH®vä ©–^F¯d«Ü©·¼É•}`¢ˆWxŽìî3R˜¶a™÷ÓZŸ­|ÈUAßY¨³ Li̤€¹õ_#R– é—‰€ÈÌ~ÔŠ¿2,Zë“’} ³šý“y¤wèöÖ»³h EÒšb+- ¢ƒzíÐö;±ŸÝËãôhQƒßô÷”…}ÐÚ¼Ào2æ½”«yœÍãÍh™Cu8ã"&Š]ÙÅ-µ yºYXF)ß7Ðÿx£ïÝAÃL±§@—nÖÍà)ωQ°BÈo÷S,J˜eŒZ  ÷tÌíƒ\Ä©kàRa…‘8ùÿZº›Þ|ZnŒƒ­Êªí¹3ú‘Úœ4ïªMzö’c©Pd54’ý/ÛM¹r…jg!"=xØéò+꣒Êeõ",Ð÷Bw¾UB¡·ÃGßéQi£=ÙÚNøw ô—aëùä-‡Å– å/óp·ÙáSáèΜ¼@ÚÐyš#wô¥ýi[Kú”N$ÿ8RõðåêØdŠEs³¿˜H= 9kî>’ïK~'ô묗—„6ÃÂz¼2Ÿ¤“, @§›’€€æ}Ñj@Åk47üiÉÈŽ)öPU¢Vö„ÅÐA‘|6™ £ ÝC¤AôNq“Þ‘Zþ˜{‰p¿Òãp¢éÕª·b¤¼üªi¥;K…) ³ºDP‡“üÌðs iEÎ^8„Ç…EãøÌZ'̧‚|ˆ58x^±Hõ˜—Bí=(µÌÈggÕ„h:T÷?jݘ¹óEoâ,:‚JÝŒð¥f r•ïÛÎ1hªV+¸äP;O! Яš‚NÄ<Ê­kÔγóÅ›‹c׆}iD´î:‰Mz«¡W_qhÞE߉Iã CÐõ>2¥YŽÌR8+Ïû´Þ×ôóyJuÅ íž©aô9‡g_QÇE5È]r3ÕÀ\É=’ºc>f9ÛQ⟇äàø»Íƒ„;uL¶ Û&”E3öÑf˜ úæ©®‹z¾È“°ŠÉ´—B_âCaïç/å'?†Ñõ![.b{Ðà2¡¶Áà8Žy…ªùÕ‰S8c¿Ðrmù.͉ÇaGY2hJ¿çŽ‘4ŽâF±kO³ƒûŽ o'Kˆ½ÇGÍL¹2}Dp@·“Ï”ƒFji‘Ý»=œÀÿÀÚÆ%TÆM®ÆU© JëF|ÄEzº3¨ŽmÙi»³7MÝ«®œÔ³Ô¸Õ–§"Ä´^™éȤA‹Ó´®gŒûËÔ@—€vNøíÎR³ Xn`J‰—vlP^]üQ¡oB„Xºdx‚äCsš·’øQ:pƒÎâc“¶3náÀ’€€Ùn{J>™ ‰³Qö 'kjH®ÏAÞ9!õôz6“³ÓäâšÊ­.F,ÔÂ~zäE_hÔKQuÑ/Üô­—mUÙqáÂðÁáɦ¬ÞŒ-ˆ-ôÖ¤FrïV´dnór³h ‹Ç,<ÈHn®ÑB\c¦ÃBÎtÄ ÆÅ‡¤<H1çBiä‰zÙÓ‘Z>o¢>§E•”3.ʆ°äT¾t&žS&^ë‘ýaÀË|‰Öó×Üÿ ÏÎ3Þw:äbkð#Ù¾I%ü–u’\øZ /õÐ1/ìx ´©´®U!ÄàB*õ7³­¨d‘{S–‰9òWá\@Ô…ÑA¶ÃÚMg]ÂóKLÀ³]ù…'0‚¥h}ĵÌ2J®ªÙÐÂÊ«‰ŒØ½:c•$7æE,¡Ä1ˆµZþ¦\|{ÂX™ÞÜ÷`™@ò¬pÎXœ˜Œ*¿ÒÐO ‰!v¾ëu«õö„B}”‰èž[†³„ª!OÊáFÒ^ºT32"/CÁÉâ‰OêŒ~~ ¬ÊJ$h怼á±45²gœ;|›‘• Òý‰É½œpÀW…VÁ÷= !è>‰HµåV¤¤¢.ýæ@B”¦œÇ“3öåù® ìG3 ¨Þ­Îp LÒ[Ö¢“òmyiôï[çˆx`FEE†|Ë6V±Áñ#­Æ9†Eì†äá_Í‘×.žÌ2•Üòßè/Dìb68Ñ¢.¿£ N×ù{ræšj™žÃLÜvÈÛwù3;÷êü§ø€ÿ _‹â00ÐTý‰³`N,)«( ´Ìþiĉ‘@µì[r<#% Pè 80ùÝúpfI.M²¾âþÇ7Xʰ½¼qúzÈCIyŠþt*”™q#¢\1èYº~Ð@áÙÙbr«ÿÓj8…xb¡õx«k½âŽX\cŒóº2XÓ òC×l@±È =0¾ä‹fhªë¼}[§q¼Œhx¶_/ 7¬yõ;Î2°€\‡—ˆ×¾¤””O²~Â弚—±±ÂââŠÁ|Ó´SA«è¨0¯ï**í–y÷KO«”YZC@­ŠÁ®dâ5W­¢IBAN°»ûØÀ“r?x1ü^c ò²Ñ θÒH¤^âP€Õ>ÀE‘í©]¾E)àxvÅ ÆD¬ë$,*C.ÙÜ2¡¥ ‹<¤hIÖ§>ÖTÇÝŠó»,øR°)§ÊŒBçAв¨*oG¹þâÎ\òô’Oât” UMÇl¯Ó²×ò “‚×ÚÛv ¿ÿ•Aaòƒ®ƒšeâ.9„¸©XE=ú\`nß<™ì¿a8œ@wܪÄUÞ{70C@ΰI•e1K– X~98Ùµ´L´'dŽÀØv£[š™ =${k»Uc©@Û}{âFˆÔѼ~yOΕM-—Ÿ®nc3&G§áTP¯´o”ÞÝqäÀöF¤ÐÁó$ý¯ôý=:E#ôâÁñ”Ýn’$2›Š€§ÒÉøí9€ÔöSìœ÷ I {ÕÑ–=÷Pë"±*îu”é ®"¹G•§ýŠûÒV?¬nvŒ©ß£aðE£~¶}ñ7Á£ðÛKXäÄÒ[c­²qvNg,“:¯Ç­¬wš2åËŒ2’€€§;¢5¸¿Ó†Açêx Qu’ÎødL Ú4vHH:âòî!}lÂ8凩[=Óï‰÷{ëÚ„I~TñãȸòÐQL¸ûIi@/Ú9­šÂ$¯ÕÉÐèÈ.k>6ñƒ…Ð;³¾¶Íc§–Ñ6 ^/䞆¡¥–9Ì;¢7•ï·>_o‹|Š—rßâ0Æñå=ê/Zxjèø 3®b°±RÚGڜˬ!  )SEÖa5(Òaú¦ò)y-ÓÛ­„Sò°ñå¡VÑâÔ3ê)̶Ðsxnú)0•Å@ë öNAóÌMæn§†5¹Bä”Á»Êcôc#Ï•&:´¼{ØM¸ü£U¾9¿ñɧX(Ûº/ã¦~—ûˆ 2ó±ãPT]ö…<>’‰Š¢¸ß•Q¡@è$âlŒ*]òÉÊð½„;Yàk¢à ’@éKƒ qŒ`Úå ¼*Ö¸@“£L‚RTÔk7ÞË¬à ­ñ»Ù9Œ¿ÜeqR>)‡Oœ½ðȸTÐÆ¬£â&|šUC¿òÃVúgݘ ù£ÝÙ13Ñ:”Gúk ü;KûPøB¹F$„¢BeÒúÇ}Ëÿˆûg8¿?íUòŸ«)ˆšìZ×Í,‚£1&òc=ŸÛ"‡'l@”¦c“Ÿd‰]]6öPC8ICïÕö…·Q@èž¶ˆ‹6°#¯’¡Êf¯ïÇwáà̾Ë`W¤9,¹Âù³WÉ·‹¾# ÉÉÒ×ߣçL“ðæ×zOp–'b ¼.Dw˜¾U‹MJ"±óÙû±«vH¯pN=Þ9[q++ˆžƒÄ<6ˆÌ ³£ò@§~2ÜtÌšÔ»PìßÛŽœ¤¡¹9ù—毹ƒXU áÙ_#jkÊi4õË‘{ËŒª†Ãæ1wÑ ‹uX E{ü[õ¨»á-Îd±9+ÔØŸ'Ç‚’EøµÐ–}™l[©È×g5þq°H¶ùÐËýe¿·Ýí=¤yxVyŸõµ\ßßüz$/áòÒóéØ%÷x­T#«2ªJA‹%þBºªh„/@®~£JÝg[KÀ‹x’$Ïäj‘¼9^åÅØÑmÔÍU›HÐ:ý„qf>ª›õ %ø,¬k…Ó„  6ãÛSåš eÃOÝZõEšHâZ¶@Øè‹ÅϘ U*MÒ€& !Ï~DË‚wðQ<ü^^Œv‰eX?hÜœn_ %pu"miHdZÁùqЋ .´Ì–BXcÔª‡eÓaN*ž±5ÓAÅV8ÜS®7gòÞbÈÁBß»mª˜ûZ’ÊZÁ nóòžË­ùD)"Ç9KY·="£ÏÚŠZþä’®|3û¥Cá’Rž{îc== ¨Ñ@”^jbô›¿Àt|TÄ×îîá{á\5±ª Ò¦0j{útÐ7nõ¹g½`ÙÑŠÓþ0¼Ù…w‘© 2 ˆ«°w£6”u+Ãhܦ³`Ý07DÔ\Á8£#ŒG Éuƒîr7›ZX ’€€çò20Çæj+nT#!Ù\K6ÿ7$ÀÉw-Üç¬þ'P$÷§2z¿^™)Ó’ªE‡»Vñ<é8"¾¦‘MკŸ¢rž1á‡ilž-ì‘VÖ÷]šª¾±m´hË;vÛÐCî¨{’w“ï, ¿ï?^}•Ãê¢L-(<6tGŸ¾vÚ;-µø§F–F¯û¯S¾jº$ž½â|ó*’ï ËìªuS,"Ð’Émº +°`Fe?_Tää±1ÿÕ‚A$ö;_{OøÞ ž^'âÑéÊ0«¶Îà›üU ”Õ‹è’R“¯­³‚pкÉÐ'¤r8N"ˆŸMÏa%FM.Â&­ Óì{8éƒ^¶á:ë<²BW45¿‰›c½ú òÂï›ÀxØ7ë8^"+ù1Ð|—WºÜ2¿DïCƒ±4Z“^Õ‡=Þ»Ôi6©%Me­Ó½„|ÚË‚r£Ç9ü¢=E¹Uµå6öÅL…¿GÈÿ}xì\€†¾lÙ®‹Â ÞV,7§Ù†â:öŸYRJ#'XSÕ(?Mû½èc ÛèÑáhˆ$c„„UÁÃÞ‚ÛòKÑ‹âN†êÌ‚› æ¶M9aÏøÅ÷„×z¹ÂE`8"¿Å3§  4ŽÓÚªÇÌ¥bìb¡…Išk‰ÖvÁøéqýc‡g°7 &„‚+E8`ô«Ë²ï™/FtÞÔqñçqê>ˆË‘T@AÔ}agL öº]ùTÿ‹~J0}ûðÞ°CøÍwí>®—\%†2))ž“B\Ãz·S¯ˆ‡0VÕyÞE eÎB<“ÃAÛFÉ¢-Í¿êV.ä»0à±Z¤oÏ–­ëHn‹ÉúU èòŽ2ç•[}-8zØG™Ä­jjn^Üäþ’Jj`;fÚã·00t7¹|ð‘uË¢é ì§uR§‹i—ázU'ø].œ"'ßH.Z\Ý]¡,ü>ï‹Ú¥‡êo¢þÝ4‘Ž;ÎÄáñ.rIaÆ•íï<÷ ”° ZðªvŒ9I«Ì0-¤CRᱫÈA*+ƒ^#‚™ÖëÛX¿Ý @ßûµE:?ú·1^JK<¸ƒð¥¼~y*ò.uúÒ\̵¶™ÿ„´fæßÊÉÑ/œÄ©Ÿ'ǪsÙÚu*ö@Ý ùN4Õ‡XXX’€€³IöÓµŒ"$€”ÒóSóyOýÞy®«)­Æ•baPÎ`æ.âuüóW–»Šz}É3ÓäêïÅ- ÏØŒ—èuT·%º†vŽz3úWNKgº_ @ÐVM¥—Ófˆ¦ÁÈiFND¬ù>uókÔí6ü1ž§@öö8„r€x­O4žŽÑ1ÿsT‘O‘BدBUœ^z»;v ­ð\ô£ÙæÈ®JZè,3Ÿè0vËóQÂ2¸àSs®,Ì~9TÐ6pY/ó­I ÿÖàP\Þk|sz =7ê1J<}ÛnrùÐÍmÁ³$o±MP!÷’¢Ú\.;ôp¿ž¬jXEAW¯1í“qÀhv7;íHØFæ)ZÁ`$\AÅè,Ã@hYŒÝ¸7 KÀ÷\m»$š#Ú`…€C­Uê'å–>d¢BÁû i.€ƒÑ×\·@“¾ŸHÎaà€ú{o$ ïM¥Ip“—a·=n÷O=y–M!b5Ë…ñÀ`À@\Â,òF«wðv®MYÛÅûÞQ–ÃØGUBPàynO§¬].žP÷¦;ª+lmà 4“%OÙÓ[mõ¥™N€\Pñ·žkõÊ4S¤ïöÇG2†äk"TIÖ¸„È£» R‰Ä› –_wå0©ÚcàsyÕèT/x¢là# ª¢QÀ™°¬oe”´¨;Ö$ÞëÜI(˜qí¹d'¬áìÃ&o ç5C±7N²»ÙüÓ#4s©¨[Þ U¿ÚRaÏú£©jŽkúª>ÝŠ ‡m¿.§G&$L8ü´'Sü{ »ÈBõü GÓ#ÔŽµàDç¢×ùà‹6¨ë) t#’3¼Î  k{é¿®g”µƒ2'ÓM#ÉÄä§îã:­ºõÊøÜ3¹Cfëzn°™’°åªa¡ ’% ‹èstNràºA®(íù6¿kYÀc[#y'ÉYl$胶•RŽúú³9G€ÎV̰£çNQªtnmù,~h¼„AwBñJo³t¤)Bêeú£†q¶êýšAǧ ‡»8@üÖ øZIä¹Ñ*÷jx4­™Ñ´ñ:dù«Æ¿˜˜Z‘«¶ ¨ÂÖÊÇ ìu”­nMÅOV ÈÈð’€€ÍR¶’N¦Xo¿û;pùrL^¦áj— ÈSx$‰ÓL=XÌ °¥êàS®W•"Àø}L‘Uœò~øfX3³Ý~ÆF^a¹Ñà-€‚ü<ÓE­ –È´‡cðDâ@¿Ê‡êY’˜øç7;ÕÄK¡žaòíS¦ KQ`?cøC mß’Y§R[­ãgˆìøX÷ð]†\š¹ì†Hë€÷€íÜ—<æöNUó’wÝ}l7ð>×® Êgy_p'ˆ¸/AYøl׏ÞTŠ)Ù 5ä µ*)HJ<+…;zª‘g:`ùŸ`tˆaÝ4h­¨lºàÂá^]WN×ë—3 Ò°…Ã¡î† âÖëØî¶P1¸`¾/™Ï`Vœnr÷ÔG-ö^&çÏΊ~ ª;|rT#/TÇrc0h k”|<9»E6zUQÇ‚ã|wõÀ®êb&ÆLü¿“0¦±°ÙM7 óÑC#o¬}þBDþÆT ¾HÝ’€€šeÈÓt*Õ±ݯ¾XÚ‘¤3Ùx2‡ris%ü5(Õ¤³ —`)c·ò/ì)‘з>lÐ'9¨È;ã6•É^]Ëë‡+wÔ_÷.|;®Û”•šJGqô¬2Žü8­|4üa9žh•¶?§;Iÿ*b3’ï *”'l¡šWÏ ®Gh]F-ÒØ )Yù¯ €³‰HR‚ÍžòsIÿý³aðýö^¦” ‚Î4ZÍ[Œz‚Úß×ÉMJ7‡PW¬K¤r¸Hß[@Ëñú×-mô‰B$bùkU•6¼Š§²BDÔKÕ9ÌÎi±w·"Ñ0Q§Ecˆ’Ô>+1&^kõ1©c€5`™!ªq}±á’#©R™Ê¾²äg{1KÈÀ„ñÏz0|-éÿ²ÐÕh€„~¡ògŽ=þ²ÍÿzuðžB´’¹L,à VºÎ«ž}ðÖëP8˘7K€3V‘Lî %fSdޱ1n¼‘qPú"–¶ ‘± Ê÷Y3ÏV YÃ%Êå—¯rɘhIXT‡˜3÷XÔ­«à ¥¥-Ëg;1üõ›7â¹H{ö`>ÌÏ=ܶôð¯ò)±¼&¯êHÜM¿[®2G§[Ü«j®³ E†¢çßu?#¥4Fœw·#§ÆÆÆÂëå1ËÃV4½#ªÂ^ÀÌ«MëdSÏšñd0¡·P«-±WèÙôÜEÆÓÙfÞîsNUM‘ha62ÏÁðí¸ÕÛR/–nÓ¥gÚ.0ž¾ÎùŸÿ>*-O.Œa=õT6”°uC9f–OtÔÊ&V’µâóÒ,6t¬Ê¡9=ªÿ‘%»ÁúªöŸŒñN7’G Ð2z ÉI Ñ RËCHÁî+ðWfØŒ0Nà†WÛ·ÓX'ô7¸Fìx+жí‹z„°Ö|艣-Ë“eë+ ¦)7‹åÏÛË¢^ÔUžøÍóÉOa³Y“ª7°ëç¡(é£ä0m°˜®V&^ä½Kˆ|Hñ JÊ@O!–&õÐáÁªãý“~;Ô ~‡‡nçy›±ÝäpÕ¨Ö“58ïŸïF`¨ŸÀj/M´3s‹Ú{%0l=M#*¡xNiKmfœ>׊uÿúóËV(0ÜWÉqòC†®F#å\MöfáTý&ÛY3 ñ|8«ˆÍ î‰Á‘’€€ÔI(‘ÙÕ ETSSbXI‰÷ƒÒÙ~aðuüe€×o ‘…xbNºgTIt%ªjrýôâœër5×™^°`?ÕA@=) óC‘n2ÁBØ™ÊñêUwä»~ª°qz2ëå 2ÕZ{V–T7®w|î ¶ñ ¶lÂfÛØC“ɨǙô,ƒ†õÊÕºs’ÿÿI<®5OÑB‚ñÞVÈ’çÛ•ºA˜JåZÖJˆº»»× bl‚­_Kœ÷Kªž ?AÍ…›ÈLáÅpc1:ÊðP¸ÈþèÞöæ0« ª˜Íݰ­v>#ÔMºåÂRN¯Ï#¯PßþLüš¼¹ÿNx­`¿øµ¦ü’Ûo_øøhQq¯*Ñ$‘T±Uå⨊ ¯Bóêq‘éMÞyÍt¥Tè˜ÕÉNž ¾£Wª=厀¤ ¶û@/ÐjW~9”ÌF ¼9}´)·¸9Çê2&¾Ë4¨Ì`3x´m[äÄù]þX_ƒî¬ž…¥C\áF›Xb€ç¾¦q£¼¸¨Ò¸F›âlÊ”%ý&£Ktšk£ÜÇØŸ6‹j 0y4eÁŠ/)MèÐ4Œ© &.½8Àƒ§¥nuÌdÁଚɜžOÅ»œõYB;è¢ÎýË×cs¢qÕt+šø’²ÙÕÙ=3,^Æ)A‰é31s[˜óCs}sž‡¤ƒ©Ê_™û½VÙÙM"'æR»÷ÙaCíG¦5ÝÇGá…#i¿àßš?ÍANWEÀŽte0 _$-PÏPõ¬õ8âIcpÃÔ~Y˜'öe2¥|Í»Àmʾ,<Ú°Ï!„¨Ûò¸Tn¡RˆãZÛé €a7–A¤¹ žuùŠFB“ëôd¶¡wªKß*…ÃM3—{Ň·±·…ô"À†1³öülòÐ~4%*[RigøQš‚ÕEj ü·ºéDÒöê„t[ÇI:vjŽýñÿÇæ­*­ûÃ.Ͽ̗á^Ø×f—¶Î˜*õ¦üw<­²eþKò”nÑ¢ù!L;_4Zô¬œ^ ½1ÜSL)EèNH„ ¸-ñ5a“½0µ~AàœÒõ¥ Ú1EÅ`Ãìýñº»SFád¥Ì*šÊ9NÚKpèO‰£e‡Ùõò#Ö!g£kêÇ6 óÏW‰)ý’€€³o9¸÷¿TçÞ0Ìž"xS·–‹0¯‡>'ìZ”&г×V-ìFYÎIh>$´NFãË_UžãÄ(ó~‘¤ð‹*óÝ.®µ^ Mn.¸½–N"ƒNUý$Ëè «ÇxÝèŸU"ç u;'¿bÒ üÅ— &Ö%=IâTú,Py$C?…ŒÀl†¢é¹µ`4œQ\L»/ @ÿ5,­%¯Óå(lMXØ´XŒŸ ·¢uáÎ6¢jÉlØÐªeœRdCÀ6b°Cä¸Ú¹‚¼ÕâÃ;)6Z°+YTùV»1ƒ¦Ý%™e0Ÿ¯ÎLɪêΞ8Ç›@r¼¬•¤[©á2vÛ¡ÝÂÚœ ïBTýôç;ú6‚uó™xjE˜éŽõx%ÀOqA`q/ÍRç»ÉMh”«O2{Ò6× 1€àti‹(Uµ°}à°­q­8R[]¼u’Œ¤7Õ§«£AˆÆwå¾Z{笇 C\?s­&]‰¿$ Œ*{èpSÔ§ÿ_LhäQVW±Gy|ÌŸ"*»ӫَÀmk¢ÚG>ä€OðoÖëSZx;3RC;ÆË.6Œù‚&¦Ñ0’¬†¿$ñm_ä:?Á§ÃñÚ‡¬©`îA„ïTÏÍåsÙ_‘ƒÉ9>û:/>H"’tlŽŠm’¡òaé¦v1Al Î‚ô›F•ÉË é‡êtpã{ „VVµb Ø|-ƒt3çÖSmuãNнúâ3‰M”êø%gÎNO'g/<°2qOŠ\Ã{28¥=‘Ý·ÇhüFNÄßÎõnH÷š.¦ûßСM»&_œ°!±!Y™Å ýÍÊ‚³#zQs QüˆcfÍâ& è“BΆH=`-¶Í`YÄŸpb†^växJJu˜ªðé÷ýd°ûÊrxóÀ–^åèUIÿ¹ê'ëµ­èÑôœãâŽ&b]Ë‘ŒTD¿˜óßE>ÉÁˆAøÔ)%do ^ü‘ « “–:í1ÁÍH&"hð¬ö…ÿ˜½x3€‘fé^9}N.³Nü“| 'tIZšëoAFÁ,d|oV΋‰ ô'¡¹fÃÇšGK˽>w»±­n‹*t—ë{ÐÜ0<‚PðœÊØ5ш9ÂZ¶%i¶Ù‡'¬†Ÿ@’€€×3ž+ŠEm¬Ü4ÎÙÓ«þ~üªêšlçx7Oô·{úzþóüsõ°)jF×–;Y êîD[PgôbEŒÖ9© s·ž5I.\ïÆW€ôLŽ‹†)ÚÓp[‚—MgðK[×:}9ƒ-{•xÞÈ2÷-i.(5ïA¯ó<-­À`œÙQ놴ÍJLªSìËZñ<.ð¡. 'q®p)FŒÐ­›Fݦé}§“|íæ¯/–EMöœvefz_àxYÛãØÓ±ÐS"ر&ÄJm6¥……±dŒGž.awüûðUeÎ[Ûa†ÙÏ‚ƒƒ0æÝ¶·"èƒÐôÉ¢^>Ú ”޹©%„¹r\xÅ{Ô5 ÞC €]ëîîw9Q¡ ¥Â”Ç–iþJcŸNn«±´ËßôHU°êªº$J¯Kœô[¶è•I×´–ÎfÚ—„Gìw‚ã 6ˆ"G¡;²’µZ“I…V8ºtXŽËðx.™‰šôÀD‚Õ «—,.D©7’…Ñ#ph…ÃÀ»%kð„üH-Ò"ÄÄKÃïÛX T^í”tl¨ä’_˜înתPCý¼½‰lSH£|=ì¥-ìrl=(­óÞ²o¢Z#ýv^Ò´˜¼B8]RF¸ñ5A ÿùñG@G9û ïò‚ž¿Ÿ˜eAÓ_ÔQ*’]:ZœMAKM;ÊP¯Ó©ÏºmAŒ Óâ{¦ M” RÌ‚?M´¡~‹Ž§ÚìÛ³N¥ø(>?È'!gKÖ-ÙG€W¯Úij•ì¦À>và¼RfñmÙc‰ŸÜzHŒ¾²ÂÑ µ"îþ å™L*ŽéÉlšTw»jR6ÄŸ<º÷6GÚ™•Ÿ;ð)Eõísðñ…5m§Ñ¶±vCðþ¬xT– Dz<â<ïŒË8¼éHo 3ì ›©|Œv±UC)^ÁºIþ|ˆ[ 3!ƒ¹´;ð+<Í+ÕU<]°•P>“ï[›Û8¶+£SHÞ­.9Ï&¡ùΠCNqµŸÃmT"Ú<ÏoÞô¦é;Ã*·›¼c_Õ‹Z…Ï€Üi|ÜbøQj|t5IŠýÒnÇ2 Dÿ¡·îRç­ šÍ´ÔW$øº×;‡½i*Yc_×"Ÿ-O1¶³ÏŠf:‰Äðój¦+EÁ5C./¡ä5Rp’€€ÛZî¼o}œIW[-GpM™ÊÌ$Ëê!ÐrÞ£»+Cp»|UÀA4÷A\*@²EßPÞõ‹4~Â|þ›½?˳¢T´È &hlé¥kÅ78\úþë4ØÌ‚¾ý<äÒÚmQ“qSžßZÆØs×9}²¢JbçrÁ‹/ñMß[–ì6|íêee{\FŒ¿;A©7~¢¬,RZ)’„ï“ûÐ¥¯ú¡¾Ùáwf` ô'çÚ-z̬äv/‡“¯>„·>˜V4ˆKóö'²â§ôß4År÷ñCëÈÿ]Ë–&-¬­ÜŠíWoR8þpöç+ýþ‡6–qšø;KFQ‰\ÁN¥†‡¶B!·…Ö¸ôƒ¿T½†êËÓ³Zµ•¦–Þ»&¦lVÝ.(ßz²'XÉ:„¨©©(÷žÿn·æ‰a&#M!@ŠW¾M ù(&ˆÒ½§ÌyW$ut”ëâ-Ç`®ÿåäRC`)à%ˆu 3£ë7„ùŽRG¨ÏSð7ÌãgÌÚ "6!¤*{…÷ÿ‹¿¾‚Ï–¡ ”EE|¸²¿¥´Þ©©ySPù— ‹€\áû¦d ªQ3`QË %ØWønyføò2É8ÓU9óDzÌδEV¿†"oÛœm†”y³4g´”Ç©ù z,ì¹¼&TÙÒHÌÌML—FeÇ» `. O`{ÏKødJôð¹T?¶”Ld‰×ë ¢ý+Åx€#:BÖß#5‡÷)±ÝÄ9 ŠII:F¨è«~!£oq3¤’À±b)ŽE›ÛëÄ9S¦TظQ/ hÕY^òßP#•y£‘­%áäLí&Óÿ–þL^•±J{é\ke™Íu)û^À§ZÒ ß2½…ešðžgѾc§iž0Æ Ô­OŸ«¨‘ cì“ º5µ×»Œzià ¢{Bçð¨ãÑ G'¦†HÅçIî;Ž˜µ€”³TRÛëq{äZ®³Õ–H‹;G†!N™NugçÚЀ$—~5ˆH,Žê´•ÒE¤žP»j–·q“õøyam‰®Å¤ä‡=ÀÇžö,|½–™=Ýüþ»ý­›10t°H ž:€‡k†LÉä›lOµÞ4‡”~:$ÕIQ^/ò3׃ç€\ ‹ñ¦’€€ÐCü·ÔbLXªl’œ£ÜßýÑc;sß©¼0w¯»ZWŠÒÖé¡ÞQ•2QŒÕÌ眫eY›Eº_L5bî31wÌÛ±ød™¢Ëå=Ý&»ÐÏ%‹SX°=|5-W [¶àÅ凹d2¢¿-¦Ä¥ Ûâ9äáµú“aöÆ"6X%•ÑÊ#RÉŸ8^0ãü°þ¾ô·rVfZ1÷½&nùTRÿY‹[A[6æ›5°×W`¬pð~‹a¯×zxÿ´üAiê¶?óÑ>¹´R Q¥qSJ;¢œžVa¢}W:>ŸM©#ÃV{ÛÿsÉÀ¹Ÿ Ñýð' ½/BÊÜÃ|¬;™1BzKù±>¬~[_ZºE°k@¦¸á”Ru]/ªCZ.i‡ÿüvîk¦ráÈ«=„#¨B 4ëAF6jL<ˆÕÝ-‚i÷Âd¦ž­Uu¸féÄ•mQìÌš®›(Œ½fðà¸4Ô—OÍW± N’wfÇM“·ïðfhì »¨ùuvPÇRjü-U[ï-Š-eÏu58€Þpˆ=£˜ƒüŸWò)ÜõW4Ž–G”T¾Ù’ðW,Óó[.=õ3!ëF9ýÚ´>§¥Çɨf\˜Ýðpc©Îݹ¾ˆÅšÌ¥_kÍ<°åml"×þr"°éxmƢ筂-æ?íT'mzUáÛE¿»Èã<AA>l£Œâ³xèb4`™è÷Xn؆´Œ/ÙL§ÔgdzÐZ>¡öu!ÁÚÖ=œÞ<Ýá✬µîK# ÏËP%D÷w¾keîçX¿Êp«‹0hàixž?ý2‚oªÜú t0¶-ÔAÏ ¸ž8xE³Y+É“­YÎÔH–“`’Û³ÍrfZþ¸zÁã¬{æ¡…¡ ãJ¾ŽÉ6Š–ÕÞùRŽyÌHTˆe-‡ÌÑtôq~ûw/YÙrøë\œD€ÌÙmIŽR…0±RE[W¹r?ðïþU¯ˆƒš~'–kÇîÒÇþgg}Ùˆl7B*FÉýZA5b+xy ‚*ÕÂ9ðeiØ$Bµ»áJwêâÀú´ˆtÏ™3´$4J¬Â!- AäÞûŒ¥´’€€µF_5ˆ¬âÍÓ  Õ¢cq×ÿ²#-ÒQbhÌc/•øæ1ä4†u-횘s%Z'¯í §¯|ÚŠw ¼µŠ“AZ«÷Ø%„&¼éNÁ) ~Ãë m½;Qõc°Môû0ï¦C|]†Di·‹€ÒÓ×Öâ Ødùa‡Qu¼Pƨi±»Õ¶ŸÓ…›JÏÞ”#$1K&ß ,Y7 u¹f3® äñ ¿òÜÄŠ8ÅÒñíEᯥ? ž­K~âüTÖ€u”sÖñIýóЬ?¶¬«'È9 Ë9N3}Nc(ã6œœü^Ò&þ’)Ǭ ~]¯Ïi¿Ë#OWÜtuºõ·ÌJbœ&0T"kì$¯D´È¤íˆ&æ&b÷w`C£à³·þ¢kàµsæŸ%JÔÐC V=†2+5ð£>r×H̰×åî²1È]¢É# nËû…iI]Ç•L\õN¸”-ß JH熰Ýr_¦¹Íáë¼$ÖsGÉàkÍu*&©hðž ¯5Ë”!ª³º>YwÄ«Yî®nG8"§³TdëOr$<È“¡T…£°Òúó‹êÿx°Ó.Cí:}CI¶ÚÜçÙ*<•)IÞRþ3ߨ¶N»8cò¶×±øX¨Ut¢ÎÚÇtÖÖç­Ã7HY7¶Ð!…qᆱrY®Ó`GÁú@ㄸãx”ßÕéžo}„Zî›K#1‚>:£}÷D¹­˜0u‚Âgè#…ˆ3m²œj:ƒdï÷h*un{©÷-õòï`é¯:òR”Ïq E&¢*”õtÿòÊkOtèeo-÷›’°òð—21ÁÃb®,zl ÷|ˉ髴h²mÌD=Æš;3*£[ä×’[·P ¸´ú›žæ…gƒ¹ñ7Q°§šã)‹½;Û×Ú ×숆ßyÿƒu>툯µ ‚ÛîapT¸¨IP<ž*'íéù0ì È^Ó­ºì€â³X5$ðµ{4΋¨C®ª8°[ª…+Ù碲!\íœt°>®ö5«š£™ª9º+QðνHH!®“ãaÎ ¤\ó Ui+ñ¬ó{‡ÝµøT*é[&zïÜvÑ‹%0€JÇDË/ë½QÑØvÓ:é2% ±3k­¤bå¡…c Â7M’€€óhZ](¼ô€ªÒ¦ëÓ+šˆˆ÷„] [ ˆ¨çëRÂ+€ÚÁ«ºâÇoùÔÖóè.GÛÊx"JÜe:ßuÚùjÙ>k‡Ä–/ #ƒ¸ˆ1(‘Ƀx¾_» žÚØ ü yDQ®‡¿Ñ&LDÒí"åÀ çdÚ.È“î5¨N%ÒÊォ0ÔºE:’™Å„z€È÷{@þ„˜Iáëm²ÃTë…ë§²ó} Ä Þ2;. Ÿ¨äîjhi>ïÁ™èFpäpÓéYí[FU9ïÝ7"! …ึ ¼µ ?ZÜÙßŲ_YŒ@ ’}OzŸß„ðÌO°XÒfð2J é å;~…—*'+ÿ¥”µ¶/–yGæ¯bCÊðIOyÒw°U%wYã¸ø_Ÿé.™êúàYìÏò q›$€9uÑ>êb/LœßÎúX -Ø-'b¿—Qöe邃CrÒØ¾ÜÚé-Ac^Ñ·˜á7Ý= HX‡©U·æˆÇÅû¹8aŸv^Ý;·3î·Z¬OÚÄü²§ wº{}¿}©q(+£ª¡‚/¸”Jx‰ÊD˜ÕðöQ÷Èö+™Ç_îž°aú_âb~ðnyåsâzk‰žPçl£aÌÍ.µ‘•(¼`Ǭ­ý?¬lïøÀ.Ò»]+Ÿùn‚¼jM‡)_¿1ös¡S OKCMm‹†×«tt“÷_TÀG{rIœí?N`65‹ÿ#:W½7f5ÐsmõøƒwëµÖËáøàdç$OæH,8Å z“Ƥü1UÜÖ.Ëè,¸ÖÜUÝ.¶ÐHí÷ÕDžèáê“àŠ&p*­ ÓŠæR9ýUY»ã„š6MÉ-S~ˆ@bù{¨ã[ɸåƒ òØœžßæïÑK=¯e”hÖžQ‚åî!)ŒÔ’ØZ'TqÆLŸ y9o”fÝvç4<·ð6¢‹ç6}g\Ê­ùZ3¦Hö|PÚ“g$éá‡ð›ÙÃ,}‘Eݨ­ì]Þúzm2< ;byIg1ñ¿óÀmf$‰xꓟ&ÜëG|Ì%c+aFÁƸl°v åôÚÛ•tg”råŸô›ç3õÁ©, yzp’€€¼e^c×è¨n•NßÄþnLeß'¦1;vѳÚÒnØ~c¤JÄpnáhl0—tSå³?ÅÏŒ•$‚4&7ÕÓóJÅÉJíòD º V —~OÓvÜÖòý0;>ÌY¢I¢ÄÌ?ЩÖfhJ¡!Cÿ8ŸŒãú‰FMêróôhö$‹´*ÎÎC*­ónHƒR[ˆw¹µ={E'¨AA{ΣÎo{ÆÜÄî‚/>¡AEö: ÖV²ÛªU­×…½úâÏU…¬ÉåB–'oÒ‰S¢‰D&ƒ× d¢âéx.j7Ðþ®Pw9×ê’mc|m‹'žø~ø ÜϦ ðç?Ƭg†Ù=ÿ•(¥f‹ëf8ÛŸGü#:.)‚âùÛ5­ì4O)_2ÜùÎÝ\,šRìż@¸ò˜Ðgugí3 mÐ [‘Nö}‚P–À±Äb£­4& ¢3q2ª#N³š:Ïp¡ Ó¦~(»¾î"ÅJ]ú«*BÞh­_Aˆƒaùíû«n£jô§¸_BZ±¢R/%/§~‹‘MP@ûÜÕ«XƒÌߤ\Y­Æñy {K§mN L6°`tçyŒ¶u”›d˾ír’†;Ä«<÷‰lªNRIö7Àíæ¤Å`ÓûÄ‹ßçC™.º°Òs<¨EÝ^(¹`Ç>XV¹R)¾ED_ÆöŸÞ¦,•êt ´Äã³-†…y"’¿HënìÃî Ÿ‡ÝOEJÀ^C9£ Ö«€æ˜»ýN†oªØ°!7e8fwû:’€€ÅÑîqæÕ¡è¨Ì1÷%|;á7OåcszD„A ºÒ½ƒA[ÙÇ-oé+5;=tqŠ $™¾d™%™˜Ù{xÂ}¡@Ì ·z”&r? l.qp¯h|!A¥;~FSs*¿¤Å+²Íý\ÃV2ñg‰XSxTÚ›Š±¯ž‡ÌTL¿6Ù÷ ‚]±EDVÎ;=ÍÙ§ä”’‘'Òq߉ó&†J+$®“Zqi‡¿³ZuÓ¥ý²­DB¿<ȳ+·tTªE;c¤zÊôÅ6‡÷°Ä'3©Ûyu,IëÏðÛµì<"(™fA›Qò¶Ìq5µA½çˆpð¶švÁÀ´Dþ¢´Zì`û#ÒN1]4Wr¡ XtÞð_[–¿¤„ šNñN }n†/¸Ai³’¢(ý¸ŽÈPÜTæ.Ó2ƒŒ…Òý —•EBà@ÜC2›3d nì €ÛeQÂØÅy´ŒÏZ;é¤Ìÿµ;´—Ìü˜­r«¼n̬©¶ÚÎã‹ÿ;¶Þ4V:ÍqúÀj?Íz^Ô»™°§r A¥ÍD”Šý?i¾ÜÕ™æºÇ^«·yܵéépâ]ZÇì¿g)eå^&f‹SN6•"gFös°œÏôÁ_ãV×'ǾöfGÖf^Þ½…iƒ% 8Œ(ŒòúQˆxÀÃ"ì&j2¿b÷.P·.¥ß“øv z{E,Å 7Ýÿ&«u` ã–ljìÆ£ÑZýê Û|nNß’ÞúÝ€_´ e‡aQ¿H凖öé ³ƒ ÷íº%tt×Ò¾S>‚ñê—YrL»’a1ábfAs,gó_nÎ<ûÊ‹íjù5@siÙ¦—á›`úíXEÙ@‘‘.:ƒç-¢ÖŽZ:¢ºýÝÇjv¿`šK‹¾öQ¼5£»Âé¾$0l¤´IžÍݪØcÒ®Á ;ùÀ`_rŒ*™…¡sÎŽñ¤p2’üÜÒâîÚ[ºH¼¬d¶l‚ÑZê mÅ G ô,S£8:Îág$¤¯u0ۄ䀪cËT/Ø@TàÜ]qüÒhOi+«iMŽ¿‰ÿR×ú½’€€òNvA_ kœ4Þ ê1gfBt5sþŽðåÆ6&Ì&ŸÒß.âŒÒ葎8ó@%ü†Ò+¾P›Ùl(º„¼3±…*µ0O Å‚8¡šy‡ïTf 7Wõ5jn‚®;Á$•6/ìtuî4Ï\A`¹§Cßb:Dâ·ëºwÜ®ZdŠŽ&&ÅÛá^!â`mß}uõíõÜ*ÂøÈ48£0@ ÍÆ<X†LtèU7?vqò"©‘ ¸ M˜ð×  Ññ?H(°é‘áŒûÄ!Âñ­»WdŒ«Èë® ­`›š®€<5ëÃ3ù×FWâJÑÓ÷i1ýVí"Õßö&ån‘²,qJapz~¡î9¿íË0 nzŒw¸EѫۑÔË~/D”y¿W9B2ƒ¨Õö˜þ {›èu·ˆ› óüÍþÞ#zlËAôâæë`@òêñûžHßÖkÇîõú!žÛ í,þ£GÓxâ}vˆ´«5zKò+Ù³ƒ"¤/Åâ@ðDzåU½3hz t’Û¡4®u^課º\šSYh—]ä\ûMÆEŒyÓh{Î6ÓƒÊéAk¾~«_ÂOIóñ§Ï PoÃò±ÿ©ñ*O×#cÀêxgeu½Û Žûú¨„ÈZãéÉ©Ï!YQFUz´ÕÉǽÿ‘7ê7>(¦rÈ)J^Úª¶A\š•¼,Ï—Œ~Y·ž*mê­*\1—•ÖrQfãÞQ9> ¡â[èF,eœØh2ô/NåùHèz&›0ߣܑT"ìl.Ú·é ÿPúClJJô–fÁЋ¹ó´Çs”žë_O\‹ÈŒÌzÒ`•ò·~ÍÝô*dÔ ™ícÊÎÖÛ’iÂ2yFY;.»PSö×^—3)LŽ%x\Ü ƒÆ;ƒyþ3¾rSnq|E7®l¢-ô…ªÓT1#@è7{ž1ÊÁcõŒÜK£¥ú¯Pø>¸Éànô è±Bùˆç´¡â£V\”Õ1=µ}"?~sº¸|Ü(üGÃ+BN« Ž(ͱ]f vGFˆ¤ÀÂùˆ´4•è²huò?Øñõ>؉ê–ô$ÎCµîŸï§tÆã¿\¶îa€ÆÒÔ`ÜŸ©m:£m§pj0û0ɪP”öA ©8Évû~o¾Ó»:ó{y1’€€¢Šñ01ý¤tíß.bfß²H¿ ßýÒOÙcf'âž b@ó3×(ÅîGèÙÖC_<ý"× ÷?ý„{¾{ž¬'¯¼ÃÃ÷A›§I„QУœˆQ^é}„8®,¼ •DURÐ7ôeúE±¿>—²í›ðô>_Ä^˜àŒ(9ã˜C­Ïäèv`,4*Ì_7vA™$〢èä28}¿ø®¶Nyxó`ݰM›‚yÝ™­¾É¤vbÔ’£í¦#»/ЄâÀÏekjë´“QJêpûÁm®B €Ï |ÄURVá®DG:—üªñtÉ`zEèF“.ˆÞ!Ñ?Z¤æÈ¢ý×ÂF!@ÜØÈš7FH· -w˜¿ó²k€(ÿ 3Þ ØùO‡ùºP™vò‘óÕbý0<Ï!î°*cž«çßuFÀƒûŸ;3]ã·t犓ËÎì|uM\iþBq`)Z'Äo“*mr‰7%"qg ²•"ô×7ćéÎ>:aá•ù3 äŸ ·çAÏEüøöÍi.´oáfñaN}0&_ã 5'à”uañ ˆ"J×$›;m>.·›}†kß™k¢ú™MC­"6žâ¯Vç(/¨co.;§ch†9’ÆÑïñ©•BøÙóöv¥u54lô©«Í´\ÆÃ®Ä"Úçid6¹€ÌîªÃ8$½±EâùÀ ‹5‰h,6‹?âŠ%¾´õ¯ÞÃyàó•Ïëç‚Ó+4BwÕ'Mò™þ‘‹Eü´_Q ­á”=0Qés¹>ÿÛŽñ¿/²M`~‚E!œ‘v‡`7Þm5è ý|L¶•:VLÈt§»ÉŸ5›Ä???O8aoÅR8ù¤c.hîbµ¯‚ q°wÇÐòSX³´è$6˜ÕÅÃvo,»B¨ ÙÖ…Åj/äÉ4y>ScÀ½é4tfR”î…ýüÑ]Z]X&N5÷~÷rz=hQ.i(`úIÊ{“[%„ *ÿ<¨ lĽ óUi#!Ó¶½³–wô35óY¹„—Ï®n?ÂÍò ]! ù8Lâ½oN.•—¡s†7*­ÊËô#éìW‰qæÂ¾ê‘ûâ–ëT^p®0ÄpHÁÅ¢awõ°P¸<=&õæC˜î¤ÚÅ)0xntøÃ¶k€…·aŒüq¸ž¢t“¥ itàE"…÷8Èu’€€›yÚ'Óc:ÀƒV2é×ú‹“yªÄÿÒi¹¹È›ï0* Ï›%£0¸Tô^úP#tM7pޏ€¢4ÜÐŸÙØi.HÏÄW]‡ …=™Ëó‚¥"Œ‰G8VA%š }Šq/¸4 )J)¯ÓâA¡îqô,/KX[mLé…¾íR¾Œå àþœóGÏ)$bŸíŸHI‘WÑõ ©Ü_ßñú™uLMá¤sL ß]î×úæ™#œ߬Œ2ÎÔ?†Ê1Ž$@иOH.iˆ žŸ5±@í•d¥«ÜʸÕË]€”EÕ+%tvòÒ:TwcÈ•4)XãúSjŠŒm &ßÏÉ©\eúWÞ¨ãCC›½c¢Ø«Y5™? ¼™ã¯gÆ|¿oìû4S +Žï´þ!Fa‰xÞxݾƒ^÷Ç#ýT cÝ#˜±waϘ–é¬*(^~»JŸ¢žoÕ<ž 4™§¾ƒÁcJÛý°Z¼#m¤åا,£J-¼@&Ó½¶oU~°ŽìÓY¯¤©ÙW´*±õâf>µF•¾”$Küíg!Òû.Ê|wz"QSëôÈ®) ÃÜm. ¦.z®qmLö‹¶:ýNÎ‹ÐØ“³±b~ZóšÈO¯5ÇØœ‰µâ[4MlÆŽV±¨05qq¾—9×Ö=òåÈ£òÓIˆCù^ë§pÊT>|Ϲ©^7æäÌzžtgKùéx3À‹ÝÕ§ÇÒä’ÎtjAuЋg¨˜ìNÚµ|<_†ƒ¦«Ô æwAé)3?ëЛ&]+Óß§¬Zè‹Üµ1”êÞÚˆX½:‘ýš¯Îáæõ$z)÷‹º¶xeŽàóÆ_ÁM¬u­;°Èxs–˜´Ò_yNG¨Œ—×@¾Gø‘‚¾É?2mžCÅUh[ÌíC3þ3 àæÓÃ˘$•ªŽÃsïœxV_ rˆÊä]À±/…'§ù‹ž™„WŒt›C õ·´7o)åk‘ñýÐè>³ùÇžà Zùÿ²„Õ†±³‹y(mña¯å]÷P°M‡hÏžÅ]jQäÏÏàfâŠn(¼‚á|ä[E 1m 6ëôpྈÎ2;q›K–Å &–á†Êz‘~WŸˆûZÏ.]$ Ú1:)óÚwbâ‘xåp¡ÌÛ#IDwÂÞó ÓÔO]’€€äsC;*ägLXµÉê…Ü$_£g•½Y.7H[,á¢1z³”Nâ?ov¡èÎqË$\@ÿ.Ö;Aáw…FÇ{IÐîJt'}müÑxÅ|þ½¥^£:òé¶LaÀccï-a 7æ>gM|>ý©“”<´Ÿ€È3/0™ªV‹Vt"ƒP ±ß"£9ò:+­-d“œU=«XÐæD'Ìs¤/K’~е<ú-4ã#‡nÞo\‰‡7zWx*düɉœë•9ýˆ¤ ZaýŽ£ý«ôlÉ)äÅÅœÁÝ©¹JŽî7˜Äô$gkî••‘i:ÎÇ…#@ËÀ¡­;[ ÿUzWŠc ª¼j[§ ÉÊV®rY¡\éhL(þª)õÐ]Ðå±²“}ôžûVjò¿Ût"ÆæoµPÇ-Ða©ï—§©ªg`µvjoq¶#­ûF•[ˆ87oTå¥î¦^JdÑO=1m]HYyzi‰a‘G0D ö@ýhÍyºA̾jI ùÆ1ÿYÈi[†>ÁŽ{xŽ1DÖl7qw°Dîøsq"-8¢(©Î|û¯®›Þ“:ÈRSÖÐ…6}“´à£ÙÃrr+Ñ ©¦Ã•wV÷$×Í8·ˆ¢~–œj¡ÇVå,'¬? ó1·6—ßsà4i-4 þ2—š‚zñÍAõò›„Âá{]<,¯J?âÍÃzï´×æÒ˜|Y1]9óP°Ù±yê¯ À Íóú›Å«&³(øê»Ùdiðç¬ÿ:ÃÇå(^Ç$ÚosàéSí_¸1Xù8K<}Ã.rbâÚ×EîÉ S‰ƒ@í¡ßП”WI;¸÷‹L Æ5yíÉ“„­§ì‹­\$ÖÉÛ[MfŒhãëçWc«…¾@/.˜È$ýL¨œW¼ãiÄgB­0e< &‚_Õ Lîû–šˆ²ãñL]¸‚÷—c‹®”±ÑÙñûË$0œ_"ìcb³î}Û0˜Ê†vááFßÁ^ë*“»ÝC¿WÌš¨§ÐM/j±!*¼‰tZX‰y.£Úù˜£üÎ,Ú~¢Ê¬Ä5çt„‹m²m^‰±?<-œ¹ÆŽV.<†²ë*«z ïúð¤á«“ûàB´»\ ¶“Ô²8ÑÌ1 $`³¹Hä…㽌œÄ…zÓôbª툥-’€€ò‘Ôe›#HP`Ë^fgóu7°{¸°Ï~QqÓØãê 0Þ2xËn¥Pƒ«÷mLT(%N0‡ ¤×ú¢áÕ›Z } Æ)¢•Š@΂¹‡ŸúI0W 2ˆÝ®É9øMt8Ær£n^›£.z‚&žÝ–®h9/·µm¶ÈÀ¹Åð|ŠZ9 \#¦ÍGXƇÄ>]°XÐW~Aðä·×:RHƒÕ²âÊ[×êÅöâߥè$‹Ìƒ’@bÙgù°oÒ;ve瘟Ùú6çÕFÛ¬M’Ìò_C pµy…zqΰ}×;n—ìç÷Y8-›Ù¶Içg-•ÿ£?µ½Âß Zsr:P¯¸øo¿NÉÕ]AtZc÷¸_Ö`‚:nÉZR4 :‚ÎÑZÀU€.r¨Î$qgP»^Ünv.ø)–cús€•ÝšPñ¼ÁŠ´BPßs¢ÐÅIB0H$É8ø¡P“]©5ÙUß[ ÏþþñdÞp)‡ãyVà8þ6‰ñiyÔÝ×=ÌyÏ ¿ßâä÷L)Ç0 }Ê’Û1@È—ÿ&EZibX# º©ÑŠ&‹+\3ÆË–”u!øñªãÓåð¥B‰9©‹‰)óc‚ˆËqè&,´cÞƒóÀPwŒm ·®©ñ™sÆÛ@A•\f zMÿ ö³e3ËËÙ Ø1‘ì+’?ÚÍ}«<ý6jÊ"‹/o’€€»ø\ö*{šjÙßLjúS8{uøÝ•%¿’_à7ærZnÝ(‡´Ä9”¸Å©fȆÂíJ²ŸÍ¶è´åÁõÙ$±ÔÍ0íÆ.oS´çäñй#lpJxsÒŸyÃ’ðü Ín˜7K¶€ÆÔɘfûCËjÍ%\š©¿¯¬ ÿr¶5Jcúú.ø/œ™…R¨ ZÒ¼hãÍ*%NÈTCpâS¶QK·$($pdÖzŠÊˆ Û^{w•Œç )ÖÄÔI¼ŸýU£yÉŸdݪ”}@'qzlÝWˆJ^+òÂáÛi!í?¡QëæÃ+­BDå©åbÂÀ±;·tÑ…#uø/È~®EÂðÉEžp{ªt5V swú pĬ3àè J'½ ¾$€4s…¾Í°Q,ÉȃÌH´-*»½o&²-fÛj‚Ç;{)+â6GŸ5véÕˆæÕ´©ˆ˜oµ’Sw¤î`»ú)ܘN²ªU_D¬Dϲw†IÚ:ÈPý˜‡ ÏZ¡û L °}¦ö”ácz͹“NZÒ¨BÖ¸‚à¾[ˆ‡ sá- ˆwlÅ©; Û€iáwÉ­5ô•.Y¥lÀ#‘¢T%ÐìŸB®mDXe¨aáQœBeòýûr øNGΠio’lÍO¶y§*d‹oæ¬i ü˜·á@ Í rØ^«;_éÜjÔÔ´h£ZðžÊ«Ý—ÙMÍF°9Z^Û—¼gœ¶þƒ|Ïr¼3º*O…Ûœl>V„Óq‚N#÷óë™äwm~I ¢þl¨ï'NhC†T Œ\ÝÜ#š)b|¸WF¢ä„úb¥EÑ+MÝ´ï™GjÏJèæ&ÉQ\ô§º²W’²æó›j6Kb'{ºRí‹+ p“m1==pI «âÈàÕšŒù:Q=$¯Ã~;ÖóX‡öº¿1=¿Õõ?${#@ˆ#dø¼aGpjL›8c‘3=w®Ûé®mgŸAœ”O¸Q |6¾Ÿo¿ˆ6¡Â%_ŒˆVæ 8pÒ.[A\ÄÝV†ƒIX Iò3Á9äמWuð‰«$Õ¾o—K—GcÑhÊÍ`u"šƒŽh6R˜Zþ"$ý ŸÚ.‡¢ëÁ]"Ô¼hF+AîoGvvN ë¹ôgfÓr X ’€€ÆP-ÛçjÔ⤢1N| ÕoUXð]q±”ÜT˜–lg¢6 JÖðÍdG‰‰© ÝRÀŠdÙÔªX kÀ/î®·O‹/ê2Ã…ëVÀ#Œ»U× 5ýŒlÉõ ãö=´ð“™Æ•¿â­Ã°bØC:ì½j©!íYRÔ>ÖUUíÓÀŠ2»½â"X5ž¾±-òH„"ßvxb:êv„wB cø«Æ‹*jJ3 vÉZfí6¿1z€I.šaý¿èñ»=4GŽö—"µøÓñ!g†h %zOȲ4év7d ÝZ››ª|HÞò\% /ó`ñâɵóB^-«K0¶\(d±â­­ƒ ¨>þ‰·WcT4’2u®Ö´Òà†·òXzFÒà,´ÿ![ÀÇ®€ÕyÝLáòƒ¯+0^{…4ºÌ¾†Ï´n¨Ôªõì[`EÊåZ=‰,Ï `ÞëÍæªÈ ’[Ì‚sü–м( `BÖk¬U‡V}Ãð˜é3ò’æ§üy0öM‘«Îȶ59þ—çÁž2m+Þw|åð9Â}+ $ ¤!pî%®WóaЄHÁïF‰é9E¯Av1{mBýôUk•Y‘õÒCûøÄh]ÔŸÊA[g¸ã¼jA›/8jK¹Ã’µsB-1Añ%iLAGÒjŸOÅ8gIÐv®w'œý•ßç«Xêá›úð Ô1ÃPCŽÀ† Â+‰ "r¤¼¨-g ìâþü‹ñóÆ'«£ÝX¡c$Ú êzHª|ò…ܯæ÷ D’àtÀqÎî@ú£ˆèïLí#t[2¿ðÒ‡Xg´Ë¡ÌÑ`/4]VßÔ¯Q– '.IÃð5^®)#ç¢vò5­Ë2'’ÚöqJ“Ù>N±…º@{”\5Ošf b”jq¤çQe-ÇyjWðÚ .™x./-©–j³a9V?lÿæÈ’às^U°ôŠ ¾ýûÅ4ßaIÜ8_0ð$o1ÿTfåÈ©wÊ/ ©VT£·†á¥ísT•=f‘êÿ!Ù`öÚ's¯\`cŸÑm´xXùjH`Q±™±ê¨ö5 Œ~÷Ð_Åññ›G=Ü””Ò×Z¤q^7„AMUjxú”õkø´[ú›š•ØÍœ`’€€Ë²ªÜE>Øíï<º¡5_r! ž…u²¯¤åÝ¿×X0«22À•ÖK$ ,E s‘Ѓ¶ ç뇆顚;EŽÚ©ôäÿæ@i PóC ¸Õí+¯$œÂhÿ ÖI©:Kîû¦Y·YA§x¡ÀÎY’gm™D-‘)Z°÷>gEµæ^}‚´~ïVg¯ñ ´ä܉ ¯M÷’2(FeÁ„ÑéK1`˜žÁ½†Ú$«ð–ˆn¨irëÏÊÌoÁLÖF3±^^ Sré­¯"›sRèÞ·š™ÕÕ˜¾¤ô¦V†<íÚ+…(˜Ã*­çNv“h<Óù`žG¾3Á–,OB÷ÇYRƒDŒdRtúfiÓ6t‡ þn…¢ð¼Ø¤‚¬A¼ýý 9W‚ìXV[ý'ÙˆŸ«ðæ7xæQÅ–¥‹<ûÖ(N†ÈÞIµ|ƒ‡À¡â-l«Âª¾žÚJ›wÐ(ÝÔxÑ^Ão^\m›2 ºBË;7”þ=/š†å£§.Y`{¾o1ÀÒÚŠ‚Ÿ«¬ãö5ÝÏw#Ì&?±vƒDÔðÅsÔ1;G³žé9·¥¯™#k ‡d“•’ö’?O7OðaÂϼy’9 _Mµ_ÊvØ{¦zŒ¯-ì9€@*P(¾ÕÏX•DãFÆåÍWƆq°§ÌùÒ~6³üüé‰À¾êá60Ã0h½í§¸É¿$§IÞÐ]«)‚!nY~›Å&Tð¶ù^¸Ò>~NÇ’°i_¾8Wc dö` ðqž…‚9Ñ·u+&˜À…Ee¬HXðz¬å®T®Fq7S,˜5ã2oîËÉn 6fùrI¸ó«õÖ–îg†@±˜‡¾}K Koáˆkµ§g)@Íì¸5kAxÈ>sö0#"ð<[„Ž^DÞO³­gÖ¶!…)ÞY9],Üž+L^}i¼ö÷v‮g’UÖs‚Âxu«¤÷ ž²jíIQ…i,èÛbZ©á<Þd"Ä{µƒÛS‰=ŒÓ|/§)‚^§S‡ùt ëvÓøN«ð"Qȱ’ йíŒ.5ÙçŒÿ^½–T6(*°œ-+ÚBúÒü¿”tÿvwñº\y¶±-ƒé3î =ò›àe&6ÏãBŒWWÖŽVþk|Ï7i狉!·ƒÌh¢èýnD…æ¬ÿ±7"øjR¢Ù^}hEÚ÷mìNp1§wœbŒAÞ v—'ÌV68z+Áé2e;m¨_¤”Q3(]sþ ÇSÇݹYµ• O”fGë2óñ"b›ÂP¬š¶<Øt_ˆË;•¶Fƒ_‹ßa~=ŠAëxaµ¦_nœRQ-óåõò~d@\ŠyŠ™˜)Ô72ëb):/¶YâsH›4€ èØ>V³IW¬ z%iO~«róA߉ü;¥n'ÃáNÃ8¥ùéä88ÛڎǃРFÙnñ[PoêNêðbUñ¾fÖø›ú#úD(j |‰wSi¤á¦(tʽ[Ù™~eÛá%ûéÞ ï™¬ï–”ðæBtÎ^@­™ËCMÂÛ‰I«mº £8ì§×8I†û z°ùibÈ&zÕ姆£ÊoŒœÁ…‹a˜™Ž³ÏNáýŸÏö ¤ìFB}Ðиíb!ó¯tùA8.œ$…þHO©ë(à¸ìæAÆ¡ý««¹Ý?Ve(jƒžòNú¯ü? Ǭ—R¤ži]cT…³Åƒðɇ嫾^"Kkæ…‡?ÙU7§eß2Ð<¸ÿN¢§Ú©5 €f°ZkÃüÑM70j?ú]pÕº•ïØ~¸%ÖÐQTòs ·¯¼ÿ¥öFªË|óšüS”ša: ò’€€Ü’´Ç°ûçæò+ð *N ‘ ¸ñäl%ð1DycŒ™ |/Ý<>†÷Â?¿ª^”¾ÄŠž2PéÑÊ— ÿ{èíEÂé¯1W1Osä«~»ßü±Ú$¶`þ;e?''Ec¨Â^qÊ*Í0óˆ¦wį̀§'A¤Ë!$¤íCvÛ_ÀJN±8 ;y'—i»SÃÓŸ’»¡— Ó1T \ëÚkɼ^8à—í½±˜“Xë.²¹Q‘›&—Õ&Ž(ø5ªs„6 )ePNtf±IíqR7zÙÙ›D8Ïí?ƒiîz2ó]DNzåýµ c“Äpýr œ+7lÙ8§â’Å)i=U.4÷˜b3ð×*å!\•ô抖§SŽ—í[Ìî9 R6ó4ЮŒŽ:µ|×Ùª5–MFB±ÙG¹½TuøþÓÓG_Y ƹ2ÙÕ6”E •S£¼¸\Pws>––=ÊÃÞnƒÖºrÞ¢½U|¥¥™ç>àLz„£rE›ûkjÞÄáªn ¨ð"€’ŠÞ»DVºc#Ê’àO–2Ç-¹,¼˜ÏIÈ Ñ’ñœöÂÒš1Rü”:KÍæo’[=Õ\ .wu@Øý]°#h¹ÒsS1ê»4*”P¡•j–çä…©Õù»¢:ÒVrj+Ôz¹ß_‰ …%`êPŸ×éðÇ4¢x‹XŵUDnLuõ®p1D¬‡Þ%mZÅ [)‚” ø-V€cài1ÄGHÃtZ½ŒLFJÅÕ*nU&ñVkÖ㑜ü˜†ùx$þÊ•+¼_š-ÜÜî,¿¬ïËV"DòvçÀ¶ö=’ì¥p£P“o¸Äð‘úg­É9ê„€!r[ñzq±:?÷‚¿1\ °b€')v $ØÿšÇÇêV¥4g"KôÞ&hWe$ŸHM°ù>SŽŸ~(z y„Mÿ‰×bÛ†ØDMƒ/Vwv»j†}SªÖ~½Ñ…ï†ï,£Økg*)8¡#y©s\’#6‘í·þðe\Ž6ŸÆ UîÏ~´^£#C_3[h~~ë¥+ÌI‚¶æˆÄ ‰æèÝq)nší=ÝÓ‘üµ”ʨ”6Lw«1κÀ¬î˜úIHIÙ·;0ðhRâLøµ'†°ÖR¸¿=µZç#¤•Êu¡Ÿ8‡íz‚Vì|Oì(’€€ÂyMš' ÂŠ}uÐvú:€½™›PDd5”CÁ·Z&YïWf3ŒŸòkZìòÎðwî4sóÈ##liûe¡¯•ž$—Tmé{ÜLnKñ!ç8¢%íŸøa[E‚F­OiÊj,Ì•u,ì!,dM{n¦á$cÚlu tË|¾¡þW±©#ØÆnÖ¹ÄA 3ù_ÈîçDT,Õwa9߸Ö\¥3MKJ‚ºq1j?ËÓ~DÆ–ûvÓ\Q}}øé³üÍ9É$Å”Æm–©íÓ´óVúGS¢¤7×Îå«Xà,ËwE‡D¦üÈmÊÇ*‘"aÓ Ðr¬'fB¯5[k¿ÒT ngéHM k¬EI£¼{Daø‡3pNÚzqEY?çaàM«6t Àl\°µ‘» ø¦/,\?ÝÿYÔ6³Ê#^Œ$Å`}°ÉÆöMoüÐï~ZãÜÙzsO€“9ibºý“6ø»SÍMÿÞ9G£@a²}=©Ù't¨r<àÓ2ã tTÙÝú ‚ €DS¬µ°§­|ë÷€ÞsÑ>B Ýq‹5u³ÓßôqȰIñþbˆÈÏûIε©‚±Ë™ƒfÇF¼‘-m½‘C ã51ˆéýNßwªÁµž´+Py‰D™Ãç«<ƒ¼ƒ™Ác¥Õ«b6ÑøüvP‚Ý…€€#™Ù/¶É¸âe†¨Wg„8ÀGˆ©´Iñeé Ÿ˜Ä‘ÜJ¦äˆ7ý–ä2LP ·…õd`™ÏüE…ÔÕuΓôX/lOYcPþ.E ¯q_oßRãÞ{5¶Å#yű[ÛáÅÐjD>Á!ò¤òžNYP¹‰s}8Ž*˜Ç€èÑ“³íÍyƒ—ʉ•P“Lëy³öÚ~áÓÝô7F.É—RñNÛÆ*í_{ÿ&w¹A¨fl2‹4Âe˜;u £KÙ†g# §‡…ÆúÅ(ßV¤+¢>Â<¾£¯;f_}OßɤíVY¸§®Ñt[î«´[¥k OäšvCg¢±.ÍêH:{㸋‘§n3k`/àI™+-=N|ñ÷Šîè™PC‡µÁ4¹szÊBd’€€§1²M™sH]—$ôÖ–ž<'ÎæõÄ"xjG1TFÈxã'”иø¯à~o¶[¹5 ÏÌ+÷ýDô™c¾\z+ù9Çý\äK×Jdt'ð”CRãšEÑ¡ç÷x}§l79à·êGÝJ=˜ÁììŽI.«ŠF~è0êQï²P&(?ŒÝ}¨”^#‰~_zêð±——ša‰´tf\2²“£‚õPý ¡¤øâá Ÿ>1ÆYÇÔ­÷Ú#ë3+§>Ϊ·FÄÆ­oê\“öAŠë˜H›],J/à#ó…i+‡Dz “(°0+Ò> ïÛÀ0²X9Ó µšU±ð€äöv7'[âÀ–-‘ ]ZàûºÝ‡¯¸¬çÿÒSËFÖü,>{ä­º¢^4Ÿ­â«60hE ¹áÞ…^ž<>éê(T†Y PŒ§¸»8³­gVSæû¥$Я[2:ãýãÌÆFæ)ͺÍrY±Ü½fNüd§âK] ?PLw+½„#çù5¯! vÛV£ÍTuª=$ø05wµ½g &tqÁeðÃ÷ÛžŒŒs)¤ˆV^Ó™2íÂÁgðªåc™Çx¶‡ÿ¼4ì~¦‡Ÿàeb{€Õa€WT†rý"Ígï”æ­óP’ü£›yYÊaš + H¹ƒ#?í–+²ú̈Ý- } âT†ñYªˆ¨ SðiØÞçþtû‰†ç’*CJþéŠ\lPÑýuéQ¥Õaƒµš™omÉ©{%vç×#±Ï`íÝ=ÆÄ¬Ñ ÖªJÑ”:#%ßA­[M±*##›ãN¡h£oý>äx)xºScœ½ïAi¦ô;«We7Á„ÌÞ rË×~'sò‚#£B?t÷¨ÞYÕæFÙ~")þ\åeoó'OŸŽ;‘öò2MÄï‚{NsýêeOuÍ`{úæ¿:WÆü¿ŠâèÑÝ U±i…>PºZ1¦ø%HpÉWÓóß›"›ëŽ©`Ed*´>‘"g<&?P¦þpCƒ.ζ¿½Ö.:K=«Õ_,DLyræóÕºêA%¾Üƒ‰]KN¬Aûj?.O]ëÕŠ≯! •ñà`<™]3ËgÜ …Øú•ëâ8z„:¦(–V rè¡^ÒÑE†¼ø¼Ê—ˆ¨:Ïgµ¾oû?ºZÿHÒ8“q±íeêE„–ý°*•Åõwšx®vNà*‘cçʟF³©è—ó‚3"Õ\®ðmepŠi Èš!Û7 ¹*È1ÂSÅŸ”ýÜQRÆt×? …™0z£µ‹· P”-pÐ>RMcUAšmi™j×ÓöŽP$Ñ îi\­J áÒXDuaÛ¦¤'-:“QS'k¸H«[@Um¨ w|QjÌeçPZĬw1‘0”cí¼úüŒ¥ËFZ”ÛHvj÷6n\X‘Ë9&ñdÌaÙ6|Á íÕ)–GƒzYP~ëRù o«T(çâ„~bdzËïgw¢-ËïdÁ7(^žŠµ±qž­8JnH‚y±„‹% Š¥ê‰S­ía‘ÜÍ*hŪý'ô»C Éâ1t0ð‚¨'Gîw=öË~S½=zC¼BÅo8ÿø–^JËjàòs‚7,•Wx"Å<_„~x"z¤"ë>…59kŽ¿=KÐî`1J fÞ†Èþ„£úpUn½Ñ^T-ú“Ì{}xŽ)õ÷Nd«…J,q\Ms ‚óÌþíù!ÞÈÇݯU„Ø©·“W@–fã÷ˆçÊç¥LÇ„aÏQT–’™(ä»x–wŠ#Ë\ݳAÓ Óv1ùXŒâ T[œb”µl=ˆ÷ ¨H¸¤®ÌxH>Xhi‹?š$Ì,É8;ÔSB‡bÿ|e;2DÃ÷SòCÌåÛ¨t˜¤.â¥ÔñÑ™Ä÷£™A1¯’O¢>÷ð>ÉïF<­î97± Î’[ޝ7³Ùª–ÖãJše’€€¨a®5ÿ¸ôzol’ ¯åèÛhë @çWa7h‚˜ý~>èN`-Ý4ç<ô‹òß]7 (ã7ñ`ê Òª»W*ÿwCàVIg'rÖŸªeþŒ|xHL, nÕŠRÒîCð±û(•¹½ê¥¦Naþæ¶á÷à8ÅIn¥y>]‹™eµUBñ:jg–‚”6z7­ïà죈úz5Y¨z·»½7 wÆ-þÚ§Ï2d8,žz¯ÄPIAˇDf>gïÿîôKr$·wÚþß²fTñØo¹Çy}tṄl­áC:Pƒ£x;d#ÍÜìð—¬&Mn0ëcµh½æÄùXEÒ8ueœ ¸âe: 7 Xìôªæ&”‰£™…Gˆû-6¶•ªáÙêÿm´ÖKWÐ<œ²œü!ÒJÜ5±ú˜hÆS= Ì¶·W3þ1<.]ƒ§‘w°Åu‘ÚPºZ)þ`M0_{šë›:~ÍEÐU*jðüd@D¢E†¶q}ø{ei£Ÿ«G¬ÖdU—YG< _Áâ±»ûDÃÉÖ_ @ਗ%‹”.îÆ£>%àv°sƒ.e~i¶ObF]#Þ°‹$Ù¨–øä§oúV‹å<׿k ÑßjŽlà¯N¿< ý1˜Ÿ cn›ŸˆJxNä¤Úú¨kéæ(ãÐòñÒë$ÍùÏøÔjÆfÏ›Ö)›×£ö@PõX ­7Ò6LiœÒKÑgx*y ÈÊ@ñ"ÅeÈ—Ò`DgìÄx`ÿ¯ÓÕ[q}`J(íµ°ßiPöŽxêq‡ýÖJ&òÀ˜ÑÄT&s¶Ñ¼Êµ#‡…,yúáô³ö}F7XCõ§СBKw†˜³Þ"×%M‚ìþSåKê jbLhåõ"ýû›éÑ:ão¼ tð2ºŽ®žAJ1/kXsúŽ¼ÎøóšÚD‹½®RÒ5¢­’)ê‘¡„V²)Ü€JyÔ‘ï<’ɆBXÅØWþ'¥|, »ú£´&%ØÀ Ü|3‚ Zzè›ßE¾™÷b]fªVg»u(F?ƒuÜØ7‰f¸í pAÉá¬V(3Ò7}F݉ÏC#“PŸÒð>j›ÝÌ×iË64•¾4•µHψZËó»/A$Õ€äózç,︸&-¸NÅýôÃ&Ñ ‰%à“$Û&-)£ƒêP`ÃW§]Þín™FÖ®—7üþï,óPͳïË@„®·¦óyŽ­Ä|Å«ªsIÄ:ÍLµ©¾Œ~`yyøT;«`F’ }Á–œå"6Lb‰¿9ß3ýU=ÑF×·H6ø6mË{K#¼°pé/òw¾\ÉF¿ù^õ÷àR«¼fW¿E$öˆÑ3ƒåüž¾¾&ÜOW¦ñ”TW)®ÁØ!îdøã·G©¤‚½=×ç­ã”nyB½•eNä*à°„CHÅ<Çz]ñlÞA0ÑhÓÏ 4-81IŸÓ–4þ|zUøŽ#:‘•IÁ‡‹N‘ïåî?ÜÑ'9"d^ð6¿›-¾á^™Š»Gì$]§E?=)6†ºŠW8 ¥ ÆWö”áJÖ˜M›{Gù‹=:ÎI5R~ ¦’$%’š0™Ë§þ×rëª,ê÷éGîÞ´¡˜O€€5ݨ­ñÜœm<û- >Wù¶h8á•Bñh9¿q˜âÞ軸mÁ¡Ï:â&7ùÜ&I¦‚®‹˜àDÚ”Û’€€èûsµgúQä´4¿¬õÑjø­ cH=H]zq+Ñ•³Åí©C|?í/*1×ìyއ$áx¶fˆ\. :Š£JR‹^²Ñ™X1VÑœtˆ×“Zb9ÜÏO¤ùÚ_Û‰U¹Ùî%}V“Nï¥ ú½„–‘EžV_Ø"%P?B ?Xî0I •ÁP–ßèÓÖ] ‚Ž@ '±Ñ|ÅRµÈÄ 4‹4!ù€?âY‘ÇRwƒ ݹ£_]sÑ4âý‹{{±òòYž’_“IY%{…jA$¡75°=èµv¸1&øBÿ*…›ÁÂØ˜ý¡Ï¹†qÊ*õcAðÊi½§m"þ½9©ÇŒ&œåîJŸüÝ0DªÖr¯•ŠœZÃ{8¥†‹§ÓÕ ™B3îàW?]~¢¯+åyÆú¢4ÒZÉx+°æ{vã¶ ²øvªMagF¼|àÉ[MŠ_ÂHòêvyáFTõ)¬xa™{‡÷I2YN~°ú (ÀB„ÇUåGZ344æ`›¹§<õ»éòÎpKÊ69à*Á`H$+”®u¦Ú?Gbb– YÔ]Æ!‹¶oË€ö 3•³5§¸²åq™šsìôS7bÔ¯ø«¯ª¾wrXÝcÂÉæÛzk^};ùõ ÏpÑÀÊdRðÄi‘vaüqi¢!¥p0!<ÅNÉà N–l#˜LÇ^ÜeÙ :lg²è„ʨ>ß\;•:S—/s­Õ°ÀRÖߢHž¶«Vˆã¥Tz/…h»¢{äðvú€r€­ð( ¸Ÿ/嶃Ã`Ì=Ó5ô`îרœ“PXËôgÇì Vì3¡Àו ¼à‰¹2²ÚÔtà€¡šC¢IY!/ï—/–Ú¸ÞoÎ[jâX_ÿ£Ëéýc¦g7vÓn%DçÐ E3õv6¸•\m`'Ò´yÂ¥\ÁY{‚­k…K«]‘ÚÅ™Ön¸K"á u½îJ™ –4/àZ»!¹‚[ºÕ ¦t?¦(\ö,~ë„èO8Sä7"¸uÞW‚«!T¡·Ç[´eOFŸ ʵJE¶/D|"è÷°@äg(2ÛÅ ¹ù½¬göÍL?úÛ³sÅo?éûºÇéH MF˜ªS4EE¨íéd'xsäM£ÎrgAzõ·ÿß’€€Æðˆ*á$iU€?uuÔŽ5Â#±Qª\Èx 'ÐwC[sdQÙ°T¬?¥œ ]!Li×ô…2ü¦Æ ãf§CA„°»È¤cò®ÔqEklö¿ö?—tІñoSg…ï¡ e.s3ívéí &lº&.F¬€‰bÿÞPèè2tW17¦&ÐJ«Rê¼A|YÛøÛî nÅ‘¬ÐeJF”˜ÎŠ71ŠBïñªõíÈl¹%ȬòѨ4Tž7¹çì ¼´N®% e‚(õž:„Šx¨TYªbkÚ+~aeL<°ÕE{½§Û7uVO²ÇÎË‚ ‹÷m°ö©+„Ö·m;f,U“$lŠXõÄ·ÀXž»Ï…kßEì1祱†¼­iù¹á:I©g‰Ã8é|Òºy„Z)’ÚúŒHX6ñÉ7žÍ`sØ”"1r êÿ×-‡Oõxàa©‘ÄKÿD¯!^¨Œr§¬xÁ»ØƒÞ›ø^^c?×cŸ!â 0RÀDÒ™í½Tû_;R ÑôU66Þ…Tã¥ÖGÞ»™º¯pÿEGXEÌ»È×¥ËwäY·,c•+¾ÏŠóe Ò/\î%öL]åk]LgÇi Žó¿Ù4aŠÁÛxwƳsäÃñì ”½ 扊·¬Ì”BðFD: ©ÑÖÓ;¾§´aõ/ò‰©lb¥/ˆ4å5ûÅõ]l-ÙþÛQ:^ ´Ä¶zu¤Ö³>®Ä×06]ÚØfBþ¿éP?„öÛXIt´· þ«â>?,g{‘Åz…Y.¦ñ/@ǧ23ó+å¤ ?ž®××ÀF!™»DŒe ‰Õºv¿úðÂŽuUM² ‘-ÄSÒI%¡ùôM±X$$ÄX)Tø™®&²)ó›r³¡èÍëú+ªÖÀOËgUPåQãÁ{\”‰6ìÅ”¤ÃQV¿? ûNÆÊçk³z7¼ëÓå Ñ®˜­%zxÓ¦bº%Êï$ŠÁùË2ÕÓΰ€„!ÜÜ韒#9Âpá,ö&©:Ò1®«ð±ƒö†«ë5³mó…A6ƒ¨ÔæÍb¬ Ž®H:`Û'Ý| ´ä+Eõ4çÒIÛØ6¶ï‰¦ƒ46c{¥s;¯´¿xY>K@so¥ž|…m"ä!4’€€ïlHsi/]b­a)cÊ]|¸ÃfŽ„€ÁY]ÇóvíòÔB3ÖË¡Ìê.ušGͺÃJ#ª¹³ó†ZÉ/Îï K)•ˆ˜£å'DHj4XµŽ°~á™í« ‹#ͺæÃÿ$Oé7ÓUÝ{'¯í­ˆSÙèømòB?R¯|çfJæ u)x˜%ÍPæ!†åÊשn+5ˆJH…Ø{<½ ˜Ã6SÅœfÀ‘‚§ µ#ÛjªÉ€ãçS¹•É´Ü4õP,·7ËÚòÌ«§’X˜¤Fºa&RÜ‘#+ÿ^´‰@Ðè  ‹x Œ+­|µ=Š@2låÚ‹sLØv%3Keãé`Ì¿.¬ùP"F©—ݾ7ŠQäIÍU7Bý–TQI:ˆÃ}Jx]°_夥¥]:+§B5𠩦kÆ xÓB‘H¡t8²‹zRu6…©\\cc÷xj•ä×ö„ɉ÷tœ€AØYÜ/“ˆk†‘´¿àzfs»¼"=ªã¶(\ šš;ây²ÐÌt?ç p¸ñ°tJ—D*Iýª˜Rÿ „!øaˉ@?´ |¤d¾vÿ‹ÁØde–ÁÌu«åØ,åiýìdm(í—„¥ä1ÜËjÕ–„¡+WÙ+x™w½†JÚ‡zÌuê…÷¿úmýuÙmåñ帯OL ©T1­'µ‘h`,íL#Jòû:,ûQÐ;}[z“ìE¢°í4 õâî¼PPBô2’*0Œì[3à™³¨ÉÆB©à;x!N¯[·sr-u%@iÅ¡‘8C^µÏRqT×Þð†Š ç\á%µ¤³UhºÛ-ñÒ²±sDÔð‘e£% ¢ªh™_W@’zk­_<ûàñvû-ps¥Ù4}n`›G ±«ÎPé†ð3Í\•bÀžÌ3ÜìC¿4¸³:”)³[d ¡G§fy,êp¥9…tª)KmZñÕ줂Èþ+nSk=sŽŒ`ç?Iãùó½ßΤc—ß+<|±†<+üvlô‹ãrò29ϦØ0Çq¶J™KROôË£ïƒëÕayÉß™ÓÂWÕƒ—7©"¦BëRo¼“VÑâqJFïx²æ)°»Ôëæü¥ÌGIveQqØM! è?NŽ„`9d 8R ]Ä‚(­ ì/eL ’€€¿4l·¶Çˆ\$‡l|…ÐÖÏq(z,¢#r( T>º%KÕÕ,åˆâ-uªÊÌk€iÂ~àº€í¢ w('CÜPm~ñ‰#ÓµTÿžþµ$ "H°k¬³‚w oÈH&u „[>gj&¶HU–à7µ¿à9‡Ñúöm-º”Õ®´$˜–Ä ò”ÿ”Ê ´zr764.†ü¶¢Þõá¦â$\†K\Ó$BçáqñbTS6×Ñ™DqSÓ™/›•껃ùÚ!tÐçK嫨;‹OHÙš¶žh_«fS¶—ÂW ùÿ¢­—7R„H$Áó½@¶È´’Â#ñ$Á=#?Fß ó6½ÏZbº‚=o{¶hd§œìÊ(œCÔǧ->YÈm=«±H^qU;˜Å|Ý›Dc[£'ÍÛQM ð@Ÿ˜ÊxÌ?ðÚ…¹G„qÊ¡¡Œ/–Ä}h@ö«e€³²”ãü ² &Î˲)M4‘ÉóæÕ–â «On·½¸ [¹‚ŸwšøïÓe ¨-@u‘óÀ—w^…“ƒ{9ñÅ_:ÞH4¾»sҰ؃[Zó^m«•£¼öȸ =…nvèÈÍF»‚Œl-òç}Ÿ·"z–’aѯ¼» w{?”¬æ¢Cy—#GÚ¸´;ÑdLRäÅÏÑ@`‡ÐóáÊI±ñ[S¢¶;&ËðDõY„ˆ©Ì‚©R2u¿Ç*ÁNîÒž§öËÙTe´ ]¤Î Ô‘Ž)£`ŒUˆWô"ñ«Çº™Å‚öð #gdå´!bô*Ž-Y†+ìñÏoÏ‚yG²'“ý_\+Ó™´æQÙ¢y× \“´þ‡'BÍ’èÛ}•ç¶Ê?é+©ÂK¶ô褻Åü;½l†Ù˜­À±tϲp³%7ŒF“ø€fŽŽfÄI}ÂùVE÷z¢7§olýxz Ð,Û‚üÌ„y’¿ñˆÈæ©&èü¥g1”f¼Ñ}[DÛ’€€âH*DÈÀjHýÛß‚ø ÁØVFÝÝ’í7]ìP~ø†5«H`RËr¦„¿Ú¥[üK+ŸÏ erÙ|ÌeÀ⋌ s…ÂÓb@3ª;·”Ìv Õæª1CJüÏ÷˜éYU…§K™è-ôtÌ,¹*P¼;DKKhô7Í„8HÒ!ðÁˆ¶Î/y Þ׸#ãÖ¤^݇c•–áÄÄ8V ˜KÑRÍ æ ”z=þ‘ŠÖ”S5ôp¸ Ò²­¥~*¶ãtdkFGT% ypu‹[C£yƒŸ<¤ûMöãN,@5€8ËBOò$9ÉEVšhøý=ÛK6&…B8 ]$QÏ”¾¬”‹’Æ¡ ·#VO#÷îÛ…zysEåüW” êµpi„µ$£•¬¥ýìë^¾ X?VÁÿ‹Ð`)n˜–ªQÿ+±œwX|[÷6èWgß%Ñob‰æ1£˜é§”Ÿh`Ôr70s^‡­(Ü~Õ· ÎÇÖCº#jY¾#FqeÀ‡ñT[9@`¨q"‰¯ÆëÍŒT(V°Ç  %HÆÉPåðç4rœp+ øqlú½ÜÊ)¹10¡8²§ÇÀœÔ.ï—Ò@Äžï:Øë Fœ*W†j(°È©ªCr%Ã¥9”÷`ü^w*ˆ«ZŽ‹• €êjMÛ v¡ ß…ô¯"`›‰IˆþeÀ9!y$ñ º('Fnä%iŠl»¹ „}Q-+š—¥2Ù’€€¨õV™/G´@ˆ³Õ¼!Ÿq¥ d¾€~áj8`Q@1“· °Ã­W9Ї¾ †î=ÒVŸÁ’%Ôzë„]2>¥sš cõ®ÆñëþÉUTÚ…Œ¬•ê1ô”ccR½íçùæ7ùk9$‘ ¹c{üÀÞK™ -*ø:AuKùˆÕ-tÎi‡_iH8ÈY¦äôót»YPYå"„_ÝAuà©6IvNªŸŒ®üŽ[U¶8rÂЯæÅ¿øÔ!êf¡”µG£g-¿ö\˜Í³¨@˜ú¨Vu”hü’T Lp¯ÕëDÙHp–n$Ð,ãÒ½IáMqÕ›’±Û6ú²±¿-%)"Ü §1Qî¡«ýÊ’j-C6!®d€ ?2Faˆz"óËrZlÅP{G(»<­‰À_«øU=Þnƒ-ôo8rR1iÜ͵$(s€Ø>RÌ">¨YÈSåN„Å 3ÑÒSŠ9MyÝ>/‡z—ê´>f‡l–ôkü+`5áZȳ6Uj3sÝ ½C™$ŒÿAð2Vº êËÙÐ ]H‚e@økJätå œÏ°~!}ê#FSKË®A„q—~³ÚóS‰ΠýQ.ÏÿbQ². ˜lÂ/™k‘­­]MÄõK™±/¢ãm'¢âÑ¡AÓ#.‹aÍ}©8L$TL¤‰þc¨ñŒÈiGg6b Ñ8¹¼É¢nÂŒ X$p49|9~<‰[þl°ê<£ Mf„5=²óÚi(¬4+ùNºä™üA©ÅÚ§ŽÍ£‡íÒg_Ø ýÔ €gJäk{‹&ä¦ÇÔ¬”‘øÿîÈ* ãSKæî§¿-¶©.¼*ÁeºJ:\œIf7m§ ‹ø.§WŽ¡á;¤Õƒ¢"“:îBYûª}cuw(U{!3«R¿˜ aPÄXwN¢â,WÏÈ!®½ŠÙ/Zj‚™½W“ pÛ.w| K]àKf)ÖHš@LÃk¸õÛÂ&¤>’ fü˜¬Ýܰ Dz&nõùQ_oŒ¿§»Ü¾¹’€€ÀØ ûwÓߢwÙSUXñšôðšÔ]Ö€T)ðŽ×Àèµ$´½ŽÓ¨š®ÖQ¹¥è£ñ†éÀ‘%éåX™Ø¶ÞOï'’éߢÐ>Ð*Ò&B¶y¶,ÉgTNHųÍÌQ’®t=/ü0ÐŒq1´ ¼‚Ý>MQã°L)_¤:„KàŠÎ‰t¦ûd9D[m¦¼ÀµXSÚ§ûY§+$¦9.ö¬ÏBß–êÔ¸›!*—ŸÐ|×ÅÌ6fQ[×µÁ3ž Åvó\(“¼ªâµƒøKb!hp„ÚD0÷×oe¶]+Äõsg.ÆhðÛ¨Ú½»ØÐÚâG¸à‚¸nÏá­)G‡î'Y’PºÚb¼A—#âÒñ¯´ð5ÀÝ­p¯9ÔÑЮµ>,EÔAb$ ˜ƒ* ³­õ ¸N™$¬¸mÈ>toA5÷ÃÖÎȆ‘¯Vöf´åœ ê{ë¿|Óàd)Ç€ÂÁšë2‹ fÌݰ¢¶ žØ {­ ÑȦ֧ðú†ÃÆÅÒ—®krÜ–kAÊbq—âúNûIÅQÛÑÏž Øi%6«ñý÷ €Ñ*r}9ݻńöç÷Ÿ-Ì©SRZ^vf†Õ(JÑ•Ëæ2É\į9sšu>5ïß$a¿`…^6~ñtß›!üO€ðgº¹¤Ë#/ÅPŠÙs-?Ü(7ê×Ì+Ï/µûï¬1ƒ)Uÿ‰þ µ=í_«õ6žpÞ/ûWPj¤.ǃԡ‰ Ç6¢.†vÒª„•Ú¸î=¦ðáÖ)ù ©[q&”>Ú ¸²}Èsºã²ãŠQu¯7MU Û&ôÊãßI·š¹}Ï¡´»»ªÐˆÝBîÃÇt tqUÇ*ë‹oÞ“ðÔËcp?u rþίoŒÛÐçZ `\ÝvsBPËfGeŒT΋];&×+‹å6®îãÚÚ H= œÕÂNxQå¾v@Ä`LŽBh1ûᤖnF!KŒL¢~ç^µ+ƒ„¿Ôs=*ýº­‚8fcýó¦élô¤çÓ­rÀ¡M Q¢zÍüòÝ2&z­Á¾ßQ ÍveEÓ_S­`.3l?¹4üæ{|ÈÌyc}LÎÆ¬_riK‹ ·šØðï×dp¼‘µÄùŒJ`í:¬(¶WV·™Ÿ5èš8õ¸FÚð¼Ê·-…ìuCrq•q»?ŘÎË©9ºœ‡Py‰DkÖ¥ûåòFsx€G#µ=!£§jšÐ{ϦŊsX®‰ß<ò ½='À¡æûnó.qun&^”,µHÕ°a6ùü• QÖDÌûÔ´rŠfDìàØÓ ‚m2Œ>cà]ÕvrÞîJQ#Y,DvÕ˜·\ø{î:îJï–ÕwZš?JÝÇ•ëÜõ9Ɖ^æ—2ÀråîšÜfhùJ“}âÖ¦ ü«¦ ½sÅØÙÛIFheþ— ¿ò7ªæ¸!‹a@Z±Ø’ »ªÞd•Ç Í`ÝœíÎþë[ùaªWë™õÒ_ü– Pü.•ž:’€€¿gJ3yj3›øß·0@ºð-“ˆÀbõ¢{îéÕ‹ÔA¤O£^ÏeɃõv‡"žúâHP5˜Ÿ& ,Ñóðyæ‚ì¡1Ÿ°7Ò4…ú…ºõ­¾l`Þ$¿1öŸqƒb#XL‘•ýÎ#Ȉ‰Q#jgdïþ U¡\4릋%{öÔJ×uXñŸÖœ {ü×Â?»/âfþP"âtÝ9@°µµvÑ}y«úîÈ'I•ZP0ãó}e“XµQ¤RŠ6œCð…Nú¯)D+諹N|UšÈ…U2œ-@TÏkíþ+¿QdËÂF²{âæK5!ø¹µf"êÎö&tU±ÀÃQ/*7¨´í^‘ÒS áDáuÌ5Ù6wýÙ\ÿZß»åvá›6¢ðÎöÿù¦¢0òíײš3ó}x;˜–‰[ãU‘V Û^5>ämw >âgùNôD“òøhžY¤â ß×§K±4ì­Ö(¼ëœ…ÈŸ %DålAú}kú"¶÷ 6F4“FÁ¶) wPÂø χä+Š…b—ñ¹:ÒnH3Óà_>JXÖ Y‰c>ûäÈè+iׄÿm¼ß­¾3Áª‘:ù!t<½W¬(·ÙÆgµéuè–îtúPS øý®E)¨øðZgÐ"òjô3æX.{×ê-‹€ÀÁÁùß—QÓDn{3̪ZxÚ5g'˜¬=ý^3èS¼ÈP?ó^L¿Í@w+>fÝ£‰ªƒ'ýZѰ‚5,vd„cd¨&ã͘7}zÙ!ÈÆŸâŸGޏ‡|«1ä”öj,¶RàèƒÄýšÕÇûÐkç#}”3ïÅ*×Û)ÿÑ̘æ¾(ðf.°ÌoÑ~ð¬×¡‘Ãç-…—…‹$·ò׋g¯+ë¤î?[^&0ŠÁ)^³¹‰ þ AO|¸ãM±»ÕƒñŒdøSãÒ$ô ëèÁ„Ròó¾\ŒòCŽ»€¶A×3Û&›,¾’™PÔ„xÇkYiZMÒT…,—€Îè]ÿ¸ ¨¿õJ¿Ã´%ÄiŸ²'è@2¢éYOÉç"7ìgÛµŽr¶ÃÊÊXz¨! @¬ŒÔ7­Ñ—±h“ůsAï7¼9Züëö씵µÀÁ½êTÿ¨Õùç}Ä×*¢ÜÙ(†öj6èwº3?//yÛÆ+’€€Çº@a¼ZÌ[¨xÔj ýèê¬9/‘îLiÃHãÛ %ß,A_O˜ŸÒÆWdcôWŸ¾963¾®›¥°•á.¼êžqT‚³¡‚ò¹B¿‡=׆q=Ö&›¼oï ¿“ÈW¢˜Ràà•H%Мßs¼Äl,HaöŒéHïµU˜(¡G«ªb@N‘Âm;7H9=6!°pO`§ÝÁ(Z&¬‚Ó@À-ÏT{uî_Â' þT@qPj‡ö>þ‚‰Ÿº$Æwºcaì “iD‚P¾Scs—Õç¾Fl½¥ß2€#'n'dtÖUuá ò˜è€˜,öþ߈&¯!vlòÓcPT¾‡3|ì5¶|öªPÚñµŒPsLÅ]!ûs’ì¹â/ýB¦^öâÃýšœÈ[AÉÒÞY¨Óô~>ýºëgây~ö¦h¹¹ˆóY¨{R–ÞS€¬ò ·8z¿°ŽOO1‘b_Ûôuoû°F…,•éÊÛàœ¡hÓû²n&/¨¾¦h2¾…Ԟ âÙê‚;¹þÛ@ÓË›EÏ[S§\,-Hä  :A°#ûý(¥0Ȱ¨AE¶ÕGOÂ?7v,ÁÒ |&eàªÂÓ#(Wx(\?y{G¤b¼øìN—B¡ÛR诎¶Í'y)æ‘dÙò Ú™¬ù(Žß¸÷À~œÔKV<õ(OÛ:yéXØ÷W'Àƒ•]|¬l̺_i€¢°K½¡KÅ83¤QªÛ~CØ{ ¼Þy.¬Prv,«ùªêüf0Ko7)™; º2:dåyÂL fãÅà¢s—SïýGW ¾¹È Ö"T¡ÜÓ:ÃÏYÙõA늘T.Ü#åT†ŸjŹô4ƒM’€€¹j+iWëã|Œ›(³oô‰ǰïÛyÙ/:ì,•U a[lj‰Ó¡€ê|³É‰jMÇÇn²¨%æÉæNzHøÇRW¯ÜØ„¼¹ûÿM‡Eˆ3¿# Sê®ÊÚå1ŠìE]ke_ƒ€¦Þþ¥±Qޕͽ)×%+ýA±Ã åËa {òHÛàÓ{h~‹B¸ÂQö"i Œè37ªÚfÉ85^q&ø¯Jò·EšUÈ ·«-^åïPCÛc£T 54ðpñÄÆÝ™¤1µ™î`Vµß׺¨‡"§Å*ßÖÍÚ-‹ªï¶¸¶V _À £Áϰºqm6°ä õ¦q6ŸF³ð­¦JÊâðq|˜CY"ZQ½G]ÆN@(èB‘·>ÀÀlôÖ-Rû×OKf`>"Be±µ”•uZ”§¥ß± éøË–¨‰íµÃéÏÆ×L‚¨Â'÷ß .ŽhŬàâ:z¡©•ÿçv,¿"5XjWÝM‰i¼Pb5Ár³gæîâ›oJÏŽËÇ)¼¯”q²Jݯ®Km„üw­–ØÑx&Paõ<ܲ½ë|9u¯#Sy¿© Õò ·ÆSñå'²ø\é… Mð÷xûxžÏõBK&¾Á†ûô s—ˆzôqP4¶BE¬(¦‹+A~Kaú%ßã0»LPá¼ã‡cïÀÏÅ8… Q…¯lÒ>žä.U„› ‰–ZÕ ì³ßgúÙxU£žOËE|:¡ £]G%Íá«)¹k›ÐhÉB.f·ø†:($œ3ç2ùÀàW!ˆà¦^êœêÁ¬€ |¼&ñX€h ¤¦ßÞá!q‘Î)9_<ë‹1$À¦{ŽÊõnÍ.ýĈºœêIkó< ÃBZéþªFñn’(¸ga\=HÆi"p]ëµ—0<ÙPïUÚ½Á^ú»ôÙ º®2"Õ™zË ^bE($XŽŠºÄµ4³†(¨Wûë†ÆhÖF¡j|“2àš#Ñ2Ù–¡’€€çt[žŸ/þ÷=W/Aö.ìóy:9íÒà:˜­Ì$J8Îx‚¥‘ÊÚkíq+Â1“fWtíý̳WÉÄuètMb™>‰X4«ë'¬3s†À3°Øî¯O*¢Ó´%1‚—AúAQ:d×ùGµ »Ýšw½[ xyk/ÞaEË:´“×Í%ܶâ}òb!Š0ÇòçÇjÅËöÆöŠ~ÙâòÖÈWîc}UÿeµÉ¡¨ÚVMÜÓ÷ä÷´€ÂGå»?‰Ê”‹ûÀb, ¨ä…Ò>Û• ï4=a±WS„çc:ñV€×])ÕßB•X^gcýF}‹ƒí”ß+´D¬”m „Ï›«BÁ͆„¸S¬ñ×Üÿ5ÒJî/8\ßçâóøe)PàÔ\hª£1í4Fýd-ê’Á‹†Ib¤ ›R’kA6ê•,¸ó{CFÄœ üýö´+§4jèžúY*à+äÜ.HZ,ý”¤sZt6ŠÁŽÝçøº5’—IÂs†¼þ>ûN—õˆOS·¹]ËUÙ5Ë‘v°7(ãÓá4ÙÁs¦£Ù[:KŠ9%—ŠK`~4EǺ<¼.£W5…‰e<ý3+ÒîMØ Q³™á•˜DR­îå/‹*õË”ÈõQm,²¼ü‚ÜÒÇué‡vèÐÈÿ–Z¨b¸$¿ôæa`Gy•ð„+p¤ƒ@ËIóEy~?_°@í-|ôߘPØÕ•kÒZÛÿ²Iaj`€ØŒÇ ¬~gT·zöÄÂï݆µ¿ÚózÏSõËŠ;.Pg.Æ;!u¨ùõ¬ðýÄ<ƒ¼fŒ,$ÿ»^ø‰”‹ðµIŠûÅU\ gªÇÖ«ññ÷Ð ¸‰˜»ªµ­[=öûpì×¼è¹Ä,½Ð€ ¡-¢lدàô‡/KÃ÷ûUÉkås„1qÚ"Q#R¾O±“4ô³³‰wœ#‚BOe›wð33C“dTlÞI‹’ ·W(¸+‰l³Ìœ‹kh@Y®ÆÚ8ÍMí°G) Š‹Ôwzl†>°¥|-l¿pV¨iꡌ8NÝø¶XÌ‚œÔ•—H+ÊêbÖ´˜¦˜h”Bðö°{SMvà?0YyD±Ûë] ôûÿîìŸn¯×âxÜ¿ƒ «°Æî•Vçöhø+#±•ƒ6ÐroéU  oz€ÚîdÀ“¯é’€€×tŠw\sŸaÆi3=nšc[«T:0InTƒµÅÄâ•¶Î÷*‰9j0êì] ÞñfÛò€PDwºòI™hiÅIö¥Bp/3ÄÎû£‘‡'ntPcüôé?°l{ì/êi“ÉÄÁ3)Zœ¹Üð7´œ•ã')}Rõ‘±$ä,<Žo âÈæÎk¼ÒЭ¨YÚ&¢•MŸ€„ÎzCØŒ*¡/戉£ÃÓP¾QJ4·4²p:­«œñ¨™BcØêõHù÷º!gÀ0¿Â™ñçþç±BT˜±G|luvfIsØÉ›Ü±ÞÑ쬼_K´£FÿN#Þe$êeì!.†=šŽ48Ϻã>ÁÂö 8t¥CÛ‹^±*û‰eÌð| !=S½]´¸ÇÔͼÓMQLüåͶ™3" ~5 !r‘Aõ–ˆ³PJ¼BòÙ–sõ 7üczヮÒßÖ±rö¸½D3tу¸y›E ìT#õiEìpI7L§+GtƒÇÁ[!ý–7X7Ð^0ïÙK¢•nÃ>·ª§ ¬*]ÕmrÚF)`/Nž8YW!À ¯s ;³RºÈ"öúãžûù·«<¨ =€BüÊ‚DÌÏ«­l- ÛØ¯}/ѪSìëiÇÊx‘¢ÐkÜûw§ùòEElÓ0t§n*ýqŒäËh¢Scp[Á:2úH¼[°½4cUÄ”bæ]A ç`Í<²ºªqÞ±y?o$æJ´ºikP-YÓäPòa‚ `õ’­¥´¢7áƒß¤¡´l`ݳGÙúHâ”g[¶ 鱑t1Mív_‚€·ÒQ¿[ÛmÁêU½ãª?LÕ»p"‚@%8š'[­Æ¨‹èZ¸ò¿y¦r舮úÊ }àéoÑ ‘¿jü¬äêbEŸáÊ`NJ-!½ËÿÛÅ ¦×ƒ`DíŒ/o³| ñŸÐ:¼¤þ ´h_¡Ý4ùæ´y­AÆ ^¤·‰·!½…×iš½½É/a:9áQ Ƀïá§àûG8$áÀ¹Ú^LEŒ—“>Å·‡Ìdvˆ”…§¶ÃGÛd¾\â‡ö\´9±. 0ÿ®‘/ôi_lxR1ßÖÆ‚‚¾~º§§qÒ¨C6ðyGžÔ˜1¾ú’Mغʤvhõ©Å?ÓìÚ(2»…§{Ñ€8ÿ[.Î’€€×Vip4­<èÍlËp›Ã} ¿ÁòÍâÕž-á‚ÊN²oÑö¨µè˜iä£+wBµü¯€i»uÕ©õò@å”…Ý%é[æóÑRÁÒF¥á8 ¢Õ0ZZ ´ ÁÒ_É· -TFr0õ» Põùú„É{ ÚûU¨cÒIDÅ$EdŒ'¶~Ô’lÈ‹-ÁôÒóæƒCÞ6j¹ü‡>*¼R87I;TwÎs‰¥® Ÿ½³{nþ’óêždCeH² o;¢nì«FYãDŠ€±ÍÂåxCû¿ãÓAÇNÍSï5e½;‡ù9ÔÇ,ÐL[¶[ÒA¶ãïüR GÚ6?„8Ðʰ vû"3”/µˆ…Jê3Þî_cJH\B F\DOƒ›ÕìAâ©6Y~êù{&L)(¹Z¢ýCUšgy Ûí«¸ÍªÎ€‡`‹òßPþ]k1é© Á«øMÍ»Ý|iøC÷{G’Nw¡IÂÐ Mí¬ø{HRÒN·UÔˆ1¹½‡´­òÄÁþɉ0°÷{O_…­~a«ý©ñì2c½ЈÀ¤ÁüÜÛ€[|庘Xžž#Ðï²Åxc¨¦†%ó½ÉÑÁ”‚ ÆctÖ@f0 IλsiGÐ%Ô×=Z.C=*øËšÙ– 0†nºèyŒ5Ú`YÍCVÄ:¶Þz…£Åœ‚£¾žZ `ñÃ(É;êHzGîÕM¾~ßÑÚ]ñêüçZÈÛ²^ª—ŸÜ$³ 5öF-ÓZN‡ßÖï‰vJ°Wƒ«S ä•ê`òìž-/󑽫ʤŠCÆù/ÌioYo¸bD&“„¶§À,$2 Ÿ¤Äñr‚ª'}Ý ÑqÔ°Š§y³™:kñ.Ë#š-®|å6 “‰Îéçóʲ`|ÉÔ÷L‡QËùKãHŠ_]w «ðüioYÌ\'‡BBÙx0ÁKgž†èÕ´î§ÉuÍ«¯fÉðfY-cØ•~Ô*c¼b‚Ö*vsžˆ:Ãã¸,Ü(¿b-ŠéKÉtBùJ&»3˜õµ.9&Qã™FTfÏa¤á’€€×¯~ÞqfEþ+[I9B™œz©J®o—™5ݘ¸ÒvKÿ‹}HF¨Œ?U2t\{ÛÐφy`Hˆs8º»G|»«×\(¡Áß žO’úëX/y»"ñNÊß'e6õG¢àÀU¶¿û DbѯÇßðïӼȢã$áùDѬ0g5âÈTÒäI¥ŠÒ-Ûç¸juÝÕ´ãÏp7=¾Œˆ·zÇŸF+4 Π—²€~Xš)î¢ `ñï¼{vV!bœËJ$Y’>è|I-s’ëm|ÚÏyÍk˜Øã‘wsBö>Êïõa)´è\1yú@È"`­UðÛÿ±ûÎÑ‹þ\§N¸?W;äÂHlBkúûoCµ9B“_ófoÚÀRûØØe– U¿¹ß:òp÷F®q; w8š•ŽÔv,éIf#ŽËL´¤Ä½9B›uËšÐ8ßÈ{-’€€ÎÍdDCņyðp©¶ªaªµTõaÿ³kp·a \mÁaî2˜³Ù©ôfá=ëªÉù™$%mGmûûOàáBN´ÃK;¬Ã Òâ²Ø•]lD“…“ t’ß¿Jx‚G0G˜àŽJ˜O'A¹Ñb}ü\ÜËãyý4øöÆ8f _³æß–A¼œÛn†ÞŽûaÓŠÒ¿z i:“r3Ôaf‘€oc*«Ûлßû6n"2²tq³¹¥˜Â_Ùœ‡üK.Ût+GÀ‘~>9Šbä®ÑW±¿=h@æÔ¾pG-¨GñC³ âxv\Ö›¬Åðl09þEÏóÈ‚iîì¼ÛxÓ¸mÁ…3¦ˆ %ö…¥xT/"6RÈ ’ ÝXîÚ©‹2=__h^+:Aó “z]g´“¸pK$&¡Yu^¯´ótJÚ ˆØhØÞ!ÅÏâs˜{Oȱ«:$'…„¼‚—55Úg¾áÏ\ºËÒ±7{uƒCÅõ,¥Šaâ2žÆÁ”‚pC8°áL®ÔûSn隘­jÄ¡a1ôÃ÷ ša¸Îâ·³²°ëA™t8”:yHR~_aªwíÍôº3;…Rwù ’'îËð ›ÈDýÁÛçÞ˜“¸µÙLkv=4éŠV(qË ±ÁÞ·±NŠè_îð¶ñxËv Ú¥Òé\†gÆýæQ„Ñ3µUf.˜±ÆÑñŽŸÇ²uTdÊ÷w}Sº)`õÑ r«V*H3²|ÁNáê«cØSªK(J@2j•šó;kÀð=B÷ÊC›i\¶n`õ;µá ¬Yå(_ môø—¿*òÅö[$š)7ÇëóýHÉŸæE–9dìŠ8DöjO³&½p=ÅãW”~\=¼bQsD‘ˆàžÏìœÎе€ðˆÝ'$â-„¶€@w2)œ\ ¶V¿²f†f¸ 9Ùæ!vÈüç †oª¤-åuK9‘c¨OJ…,‚H¾0‚Àôù‘GþÅ_‘ÄÅv ?&Riwó”1¤wýëxZÛÙ? ÝÕ¡¡›ºãÁáqkÇO  “ñxͺà+rví’€€×SŒ‘FauÂ;;ðÙ EõˆXwv㎑›Ä·ßªšÓCØ×ˆÕÆÔÌÒ(QsÇ yO<úŠ#¼~Øu“¼~/”}Õølá}NÂO`¤àwGÊÝÑ*Ïÿ*ƒ:„ãÈ¢ Èneÿ×B’?¨;&Eû”}ƒ‡ùU¸#ésIÑÙ#×ø©_7^oð÷á'Åþµ"”f?o.!‡ ³CA¹D¼™ÐsüõwNì÷“è¸ðÃÚwDY«6ê×ñµÂí[»Ÿ/'¼•²ñ¨ä¾^¸ŒÎ'Hù¹¦hU?MÃìÉc #Æ“ô+ÕQȪDw72¥DX½)–.?¦€Ï„èõFogÛ•7€Œìú¯,0‡ì´ˆõYäîýϽí†Á<`®vÑV¯Òl0•ìIu;¦ wŸD›³}ž‡‹Çb4ú–)ÐH>òw²/ÎXtÅÌ“XçOyæ9Õ°§8·¤õ7»ìdüÚt”MY%·2ܪÜàðãKÄäö56ΉWÙ)\¾ºJµ'¼d •«“š:ÃôTz«]Á I0Ì©ÓK¤w(ç,†7zO˹¿Ñ gZµ[릱 w?M³Ã@ ®P ‚<3nH¥À…áz–TÇ80ø8;*b”"ÌfºbžcA§¡ máû“i² øXÜ_SÆÕÎJýw¦ær W/ãUšµc×\ù¦‡^{»_ Q“kì;ÚOx°ƒŒ£A–`\“9¯>…ãúa“I… >@X;§8Fœcåd.`ÇrÞ^èÓñ]eˆ…¯û ÝtáÍSbvBaPÃ|¬Äô¯ˆî(–øç݃ÕÚÐ}U¯z¶Ã<4¥Ci'ŠÉæ ;꺕}½ ÉÇôd»×õìw–¸ãEæQ cdNÛh1tl‚'7±€JÑ@Ւ‹±9È{Ǻ\ZÐ Tê´í"Aä*÷ª]›K:ähûüç%EááßÓYqߌÄ|è4O8CK8^B™Ï=5Ò’IñÇ÷Ñ8GÚ\¶%Œd¨¯Îš£rÂe>…-µúõº±úŠ˜?‡Ò‘9Ñç!–¢´vàcð }È:P‘åøÌ Q ˜;ËV|C‰±J…˜EŒ£r}`ò2ZqÃgé• Í!@4СO4¢éÊ"Ù÷—â£íúœÇ{®¿®’€€±Þ´ ”ñ…ñ+>i§ŒÎ5UH`м`³Wº;€î¹³ÌƒÒ¶¿£tÆû½"üઅ¬u¥³”‚¤ÅÆ_‘‰IdPèEéÝ[¼Ò±¨ê÷#m>ÁOÿ?¬0WÝŠ¾ˆRŸ-ÍC«Qº™[gŒÜŒÙCDméÇÓÛ‹ÜÒsVêé«Ç%"§§è6“PÆeñOUÇ ¼9Ù?¸—|øÛ4ÐÝy¬Ã›-A¢Ùü]Y¨¹²ÚGÀŸ-³Ë)C•ÚÝÅg-âñ(ªÛ¬cŒ©\d|gKÁÆaû,&Š0çBßð¶ˆv]9d—é$³ZÐU‚‚ ù©b ü‘Œ†Á#¯[™£òrû wçÚ(–àmÎiQ#«èÀrõ"Ú:q$ÄmïH¦•Íõæï…åŒþ$z½ÁW]zÝW–fX=ö³Ã 4ÌÝÉWº<2Ù£ÓvgPÞ5.egØ%Xܵ²Óè‡Äw5ÿ1 `Õª¬Éz Qí°dhÔ—'6†²!ÄWMŸÍ7%9üÝMµGpÉTs¹g4öûŽ2xF2~ÊÞ'ÎrÓÿ!RËáçR=N>t Ñ¿’€€«V,°þœlLBdðX½pwàBçàA·üC¨³mˆÖ3”œa'bÊÖ¢ Nè['ó #ŠÖÒ÷UT¤±Ç(³íTG VÕìb+¤Ò:®E °»Ðm³Ñ©j9qǃÔ(v‚€ƒÆƒ'>þ9ø$»;˜0ø2ÅýYÅ¢’âf~j)5fYZ°R´ËfõÁÜTV&æåÿ~¨-@Zh<´¦B O»N›Òµ‘ÒfÌ5(¶’ÿ“ÙbˆUgw’Rž÷se øÀ©ðýhXôáºõWM®¹×ÐT 53ߨçÌ–¨#~òD•Ș*9ÔD6Y¶=üCåΫ̭™a¨”¼ö›ö¡“Ct”Ea¬áGæÔIë©+@š³m§XLôMZ+#ù‘¼êWV——&™d6ucí/;i¾õ®é­&@‚TEtÈlÞäcúa‘Uwr¡ËÄ'¤2l²«çc{Ð÷¢8n”¶‰«ìj˜G‰XäØLXW òàÅ.(…nìBvëƒÂîÜÿM`_ Â(©pbϰPŸSÎ,7 ·\™íåO)F6’¸A¸Á²Õ0ÖŸ1y»Ç4sÆLd†XX‚ûŠCíª8Æ9BÁÂ+ÝbåôéÌZQ߯5M*ß›?󭓺ÿÑ+ öçÄ@Ï`*ñ?S*hƒ¶ïð÷Eeá,Î?8¶“P ¥t›½Ì9ÆÌÁßòÍVpìîù^o΃ׅ‹)Íñí† rGàßÃàvµ(Ë<Ù,tÖ”Ò³ïà 0oÜÌPÖ-1~R®½"á¸^·[çuÝ9ÏÁêŒS7†áë§ÊŒà=®QƒÙuy?«õO^a­¨.†ÛZ¹¬S…êKÒ/gjóZᅕɪÆxy"+jRÕilh£w0L+i1>Ï‚ut ô=ÖpÈT?®}ñ¹ÀØ—ÆTϹ¿Óp¡A¾‡bÕû ¨ˆÉ±$3 ÒñVhh¿åk0X 4ÎrPþÌç‡"ø™jÞ¹‡ÿ‡˜m]¼…4‹žŽµ’ÏC¥4#=Ø­}¼‘Þ€)¸Iê$9îÖ‘¾ý—rÚZah1œÔ¦€þ&¿tFÅùKzDË®gIÓÓ¶ãTš7òŠý­/³á {Ü“qº±Ã*ˆxéÞYYnK°Û((³½ë¢ïôòÌh­/EP¦ ÷úÖ¬ƒSðË÷Ôùîl{xÄ;Jfl6–¡hm±ø’€€Ì”[Y§}±‘e‡ô#¡"¦ä¨¬y†z¡¬†Ç§Oâ*{ RÆøôgoOϪWñºWæþ m Ë©rhoG+q îoOX¨œ×n˜Õî,µ…•éå.¨´˜îJ˜µ÷ffumD±R˜†&eRþfŽ-·†è²³0įB!.÷ïû†Y§ÝÏ?Åó6‡Zzµ;ÐEQuÞ ~¥„–]@¯¤p™¬@(šÝ$8i™À„˜D†¡ˆšvódý=‹šg̦ÓHZÛTŠ„Áɧ+dà„+Hý‚È÷úÛ婜+üydù:þJˆèI·ã bŒZã%¯3½íDâ3·t…Û Z±8i—JÄ» ûÆr?< `hÚZ{ƾw–¬–­ 3!?@flºõžîeÛ6Ðâ¢ç[º7" ãL`mã•›$ñùKÜýÚÓóæ¹!_‘4ä'©V·C1?Æ2‡ˆ7‚„+éI%Zè–¾éÙôÛ0B»£½°óÖ) Èá°®–*’¼I¸ñ;3jXÙõ—Ù´N¿W³Þå;<°Â7‹yÍWeä.âsC„œŠãIºUì¬ð$³ï…q˜SlyïÓfNʶzIì¯lwëoÞ«ˆ™ ô0 í%ÝsyoED¾€ÿ²ƪéüL^tþÈìËj Ê«DˆpíV(ãØÿw»ú¼¹Ë´±$I®HãoK1~DõC1udVÿŠþ¦¹~õÐe£Sk÷`¨®ØN‡7<@Ý„è5ÞãÚé]@+Åf2¤Há¹ßæ5‹kÖ†d17€—s¥DibÆiÑ3ÝnÑ"›öoÏ”ÁŸ+ÓIp¤¯|#÷¶{ÒΓ»OKŠ,ÛÉ5'•\:ilî)SG~Jˆ†åËz0ýx±<ÀtNâŽO™Nÿ£DÐÓóå·™¢¨"_Œ¼f™Kkm…ü$®`£¥Ë%ª3 ²éÿº`à¸þU+–ê¦ Ó%dÁe…S¦  ¹÷ÚÛ—Òűˆ¡q?£M‰éÓW!º&ަàй &ÑZ°_‰ì <n9EÀåDôJ{Z¶±õ†QxxObÞûgöN|žÆRI'Ž’ÆúYöYž-K Ýå3åâhíôZГaõí~¼uJ³ñôk^àµK’€€°ÝeŽ7uEp–ß…ÚÀH^Ÿ§ÀaCÕ˜çˆø©Cõþæàñ•¥:ždLÓÓ#í40BÊÛùŽNÃ9tïÕþc‚%Ê$¤›×|&ÚÿÕt{Ô J)&›ÏiKp)€wŠ+#äçÜn¬?å€oòžõ»àR*[J¾7uT ´Ä Ïœ]¤F {ÚV1_ÛμzhVOç áf¶Ù>®lI$Óö† 8¡)ßçOiÅY„ú,QÄ’>Pçµí·ªÂDL·<¨òR|qycýÕ߉aå^dÎG|Ÿ´žr4^•¢jÍÞ>†É3pÛQÓ9Ûò·¨¦²f|,'Õ£?¸)b_ö}ÊxM1ì@ãf0ô{£E]èþ€šo7x°Hñ²HtݵNìņOöø¹Òüzw‰7-)mf1¿j“­™z·ÉAn¡á °ãˆÉjZŒž&Òqp£<â¹X?X`¥nÅíqKpýÏek¡Ú'\U9Jü^†½ÈÔÇ6?dšjÈ\G Bt¡¤,FôË;k-½{ÐPð0CÇž* òaðeA|üeGgïÑGˆAz-I G:JÏlRmBô9ŒÁ¾‰Ðônš±ÕÔ>ï—*Æ$Ó- ™øð/çZfoé9añ>G™˜ ]ä4¼#é]zf½Ð‚¹”"‚G èÄÉLÃe@oJÙÔu½S,æê ©±F¦êðTçx Š`(‹},Xޤêø nw :c“}-‘ x•æé¸}ÛAAUgP²È‹‰ŠþùÛ “’‡R Zòp³`}G ¢¯rSõ2CÆhÁÿ~ÎïÑëÛNüiJbŠœ+hOÔÒT¬Ív>yÏÈe¬.Ã+Vßô €Î’´Ôë¸yÉiËYóõbÀé•Â× §Ä®äØÒ ed|…}Æ•dpé˜M>RJù S4 íôƒ—×hT8x¥‰ØÆÔ³GÅ\RZˆ÷Â!>;p vu«~Ùl¦ûˆ—~}y!føWƵ Gíô–h±b1û?k \<ߤÐåñË•fChßÂ[3€Ä;™~#É:–;"ýì;”ËKáBS…機ό*¤>¨|gœ,õ£.Ì¡ÐÙiæøÓ' 'iׇÝèÛ¢Ͻö’€€ÅIÄ¡.®0¡ÈHúbÔQ o¿U)<̽ý!3ß=óß®M?×éЃBÆ<ò >_Þˆ ‚Ý=ñAÃüölùºÜÇ®E=H’¨0oä#ù(^{ýba|š$‹†[lù;àÝÚ‹Eñ9¸ðfè HÑF´áw>¿þ-L}»—·oúS(™ŸáΡõ;¿­:H÷$®Øðð´ŸŸºÇ_ÔRÁK&p«xhýÆI¬î-Õ}Áb{Üo7¤{¦Á1~‹D£{›5‚ÿýŽ'%GÒ ¡Ð@_,éL éSmK³>Â@«]Ç^“ô'SæG¦† <û ßO¾11}GÝIOµ$ûî ÞSA˜žšÍ# øwÅšª7öjuxjoWêP)Ǿ=Íë]™Ï$—»KøÊ¹D oX½KQŒaEãQÈW¥Ü÷R}f¥Ñ¿ýͤêTìD¶ÉØ4Sÿ îç{G¿5bíEKIà1®‚÷¸Ce·géü Äaç(ïWAÒû+ÄÍL“Ú~‚{ûEé4b=Áˆÿñfå“¿Þú)þOŠ–ÃE/75b|dŠL|ŸÖVÂj3g W¯üDIJÌ}«›j¨ æD×"{°Ší—?§5éÚ˜`ÖzÈ[w_Ø ÝZ)-ݼ›‡°pÑÙ›ƒáÁG7V^˜%\ðƒ¡ÆÃ|° O«“nc}œòYäWªÄ"÷Î~&wÕácã–OíÀ5n«Oݦ««5ZÎ:ußéVÜlî«’: P¥2ïfv³'kîƒ{àF$Q/þeª7dÌÞ¶Æ—Ín%±;F†!1µÙˆ›4ׯ߸)–¢-$‡'Z+ŸÁZ1G?´^iõö Lv¥oÝ4ÿe+ƒ9޹Òb˜)±cªR¦ÉbË}‹XáªAæÓ(’ òF’ô÷¥<­¼—Ø€Í^ºô•…ƒ 6<ûÀlF ¢cKL•ž+qpªKègüàqÿigŠïŠª7°3iú°U.ð÷ѵüà°öÿO!˩˕*äÛIÒO_Xvܵz=5‚؈ԑÈÅ3ÌrŒß`õLÁ‰(e %•Ýãÿ”zÔÌf¦„[ó:mý9x úàX/L;g°Ôß]Lø³kZ¦€}Žä‰f<ý\”´2b¼ô%]U¹¤½Zb +Ü’€€à ԡ왽}#cŒP´½²×7°Ù9À+ðÝ×ÄØ•EA›ýh-áŽR¹f¯œË[ñ% ¡áè–º³ÌA“(<æÉ(ˆGà1ôþB˜f3Ð;S$˜•lߪ0Ò·Ä¡H0°Þœ$&»Lìá·}žd ­?4­~»†èUâOœ½©ÑŠý–ya¨N96Ž“8Íö²‚³P‰ÕÚ)-¤x¿”MN EpFó!»"d1¬Sj„΂¼Aêég`§h¥'Y>+ØÔJjŠM}u,‡§Äy·j…éòïxaf‚½Œ#0_ÈrA¯zÎ=ë_1°¹P¼ñIæõë>þùD÷«°ó÷nñloZn31Øû=þdt'“ØYÝ[U1«nz̬:®>Ì€IF@ ?r çߺ 룿 û\¤FسèêòC~ Q㟆r¿éTxlrxrU“WÞsP»ãÐ¥œ>µÒ{\,þ›ÚÚÆLQoš “ñ3~ÉD“nqf®šû&"8¹ñþ1qµ®4T–i\ éÀ»B¡H+ˆhæ’BÉ;i÷/oø¦ÏY|Þ—3TîK‘tï—ÈI¡øKm]Œë1 WV!ŽA1zÀ >‚*m}“»§ÜÃŽ8žÎ²q²Æ-+²|Yÿ|q_/éˆURú.~Ñ}ÒL‹ ›"Z¤âÒZäd_¹·î²]• ß¡í]IÒ¥õRb#¿ÿ§<ÉÙ°x3‚î\©Åà•ò™=Øèù¢¬ýíšEwPCÝ UDäôsi2k«_¶Ÿ£5Dµ’í¥R¤kü&ûm–Í:ŒŽ æ`asÇ!]à}19HB‰\{žñð'íÓ`j»‡™ôÏÐîij©þcÛït\$2‡&‚¾ÇRBÖ[âjìu*­Î6!éiÚ€yAOôËó°ŠIM­Çs­ÁÓäê´a„¡ŽGêi°Û‰ý•Îè#"Y¶6®ñ‚ÍÄ2ÞÂtAzZ"_ÇëÜgË8ö¾@w9t㚟¡¦‹%ÊÀJý‰âîõìÌЖ¼I¬q|k IÖå|õM8M;¿LéÔt§¯N,Á&ˆÐÖñUÂu„R‰è–yšñàø‰'Kô¡§Òo«SÅe ½¹ûø…Ç{Ëš@æY±CíªR¯PÓMeoŒÝnî’€€ºõÑÜ}k±£ó˜wMñ;?I$Zø”„ÈÀCÍ“Õ^=‹ÿ]0%»<$ÙœÀÆ\nhè¨z™/NÇW íË_âÍÉǰ¬,r÷߀û^ [=Ò¢Óóü1¼Ê\å•>¯7²¯.µÌw{jõ˜qß«¡’Æ@JsŒ±þð‰GÞü/C±lãUìôôšÅ«Å_Þ=±‹Kæ.®ðÄC Q¬ˆh ç™°}³^Q¨‹U ][2|m#`ïB¨›*šŠ”­ÍÏ^ƒt±á¢w›L)Ò{BtFhÖì¿fÇœ£¯ÏÏ B?°[¬gWœT.Öç0&ͨ.+óxïúIÇóvoE±Wf…ûâåË\‘nÖ†ò B5ì6íïG¡4û!¼s\xN¤IÞ³9eoä ¯|y”m ÿTÄù÷Ò'Ë4¢õø‰~½{o*˜®½;e_MÅ7‘NòNdÏ|1Š5I&KPŒ‡Jéõö¿!é%@Oˆ™•;D*œg¶ufJŒÇ=ô¤„ñJyí›9Û£¹A<´¢Ï]Üš{!)¾ö KC£>c%òÙ¤ñÌ‘]d¶ÁQò’qh”…ï·š\ÿá.Ú!ˆßƒ¬S|”ï®|*~‘a°hý÷UUZö„cùiv KЧ¬ eîAÏÏì9 ¼H€b@JÆùäxÄM {|ŸÙxß ª1‡Þ­ðÕT„¦`€Ä1£(F.¶  ¾fæû^üóJc°  ™r1OEq%g«•‡VÓ‡ùø`oNϲÛíw±Ã iuåì 2kÚý„ª¥I\´›hè§dd°7w÷H–òÞýµÁÑÜm›Jb”ê'¯|¨{1ß‹:¯òš'€‰#ja€OÏ­40%‡’mbéÏI[.l†íP6áè)/ç´gÎÄ?ú‡S%áÛ`U~Úú­GÞŠ­ƒE_…=üðAüh^æ”JøwVg Œ•¦ßKÊΪÄ}ý‚— ’0[ØÑ‚…7ú&ÝžH²(u¢ªÞƒå)á1H¿£h˜…£|e¡ýM…É—¿Ñ fט+¡¿¬1 ŸQÀ«pY8Úbö}/LI˜Ùçç°‚Ì‘íÉVøê ÷.àpn'Q Š è•¹Lúà” 0Ò<«zu  Ü¿B„&ˆœPÊ«ÕD¥¼¼“ç’€€Æ:ª«?&À¬^§Ä¥e;8ç ñKrE²Äï5Ã"óO¨Æà-ÊMUL6ácÁÞ+Q9„å²u7/Z2Õ°¥¬èß Gx_Æ#_ø"ò¡1Swpà|˜CªS^lꃹ1úªJî½ø›)Src'Ü_‡IÒ~Õ¾¿}íGH\úÔ¯®k†æ¥žîìVòâ¬×:5öû«¾VõÚcN‘%Ãß‘5*ÝïQ[Cà±Ûä~ÓÉWÖ)ÚœÇIlŧßïÉ –~£õ£–ÏÞ ·,ñ^ån'€ÃHâ•ï¶~v½ß¹.ìj5WÎñ£@g²}-­k¸ Æñ„…m¹V 1r úʾCq&/Ž-Ø0ôñk|a½2Iïbøí–sH®_»BÿÙ¢µtüíý—Á/E €GºÃøNR7•ÙCê9Z<}™÷ v‹˜ùi”?Nâja•RzÇí1||yÑÝ–A?óžDÈ>e†sˆ‰œ™Ô0H§r–˜Âk“+í§v(M½l{ï-všÒUNlj²ÛãªRèøþD½ïþç/B‹øDK&ãUYI[.k[®|(RöŽekx~€—[”{¤­!°0”ÿvr›„U¨4Ù÷˜’áZt\‡ð™»‚¾‘!Êv:’ø!þÙ3&¿‚% ײoÇ×M&FíEÍ¢ 0¢±œؤ8¦£‚!;«ö|<×ä“…‹ûå/>3T}bäº+“öÐÂkVùr ' Æ$ÝÃçî\ZbÝÔ¥.˜4oÑD—91:aލ=qGEš’ –Î×ãÚETŸèú-âÏ(ºõè³ÿÅ™àt9iðªëNœ> ÉWâ¹,xÛGƒÈ<ÀŠÑ’ ê,/ôð5SøJ 5²I°nÊÖö0. äM²BàÁFõâ¬×ÛýÕÏ7clßÚ˜È=•›i~oÿË}å}…Æ\VÀ?¿¸;ë (½RÔE~xrVç«S}˜ì¿(¼íÒ Å’€€ãΟyqO­ß/‚ähÇžC,+6ùsN¯âz‰J¶'1•Æf>5ÌXÐÂ0¤ZM}¦«q[nc5×l(Ý;¼•iv¡]†©ì®Â R.Éí^̧­dy õ!Í5N—µ}½ç$Éä¯oc1j YXê "&çû ~Ò`í¤bXM¨g>fŠvUc ä¤<(Ž/ åÇ úå€ãÈx%kˆW…(g­É–•SŽÑuˆª®YBv惣ÒE{Ñþ×{¹öI´ÑÇ þêÑeæõN,¿Uœ`5r/ó–«\ò E‘2çß>×çš‚¬ëÀQŸ%‘xsM†»lE¹ ë ó +ë=Ábeõ ·nž¬³A:^üjIksç€×Kâ†áöž@í@‹ ¸wmŠÐœdÿ§*¿j÷æu(Îþ¢"hÕÜõ)GùQAÌúБh¿¸²…ÈlØÛ7ç¡ÖÉ@¡lRŠ)(0bÑI[¼&-d>e°ÒÉGE ÿáZÔž»P"ë¤*5!dø˜8­­êê*±‚ZcÊXkí¦þɦ `‚¶æŠ‘à50Usÿã·ã‰2MR‡€Ne’zû¬_ßפz`Ž Ðn^ûÚ͸)Dyý!¹)ìÕc\ž%=î›°±9äbð[ßaühí^)µhqY÷? J‰øù•ØùÞLh Œ¶U¨±¯.4 vŒØ†•À=¥šÑL¡Î‰šÚ§åýˆìÏ»q8¯Å]…7Õ[øO¼çØÃ_Må«u»hAŒÖÚ‰gû‘«_›rÜD ½ 2¤w- ¡5ÍÛzˆÐG:Ó.»¦««¾ÖŸ½%ù].ð‚ Aö;¤¾K’€€Êç€â°*Íæˆü¾å+øSÝöšŽK勺LW¤P}Ìg¾PïªJ—ÛV¸yRâÎśЅv„;k&ØPè2Öo¾ #‰†EJf:>“[ÿ«6•„üàð1Œ ¸”½“Ý9Ô_F*7|Ù&yƽzÂYãfˆ§Ã`ä7iÅ]rìÎò»°±ú.;·9ñsbµ8\,1ðR¸¢ïï`LÌäà‚2úcÐÚL϶¼O¢º©Ö‡=iÀp +Œ§’ËÏ €aBãM‚Sâtr4ó¸Lœgãl-ЭäT©l}x˜çäeÈbÌ¥¡o"[h=ÔÉVt Í%¨²ã3 |Mu%·Í$m¨9ç[·pP1ãŒ.9ål¸&j&k´kæ« "¯s668¤K„2R ù õI²Úµ§6Üõ‰/5’“àÃHŒj45ÓB×?!ŸÞ·ÐŠ˜Åçäu”WaW™"ÔÓgf/8ÑC*5]2fR‡iÍÇ»ä²9ò1Üd;–m¸œ‰âë…Gƒ)4¥©ðßNi^×_4™*bø ]O2¾¾ßOiëÿ"š›'’T>áhèñ'É'r;g¾áÝ'YÜ!´…8¡qý5IË©S°÷ñ¤|ý© ¶IÌK‹z\•–×ý—](ÜE[F}Ûñ¯t›™1¬´9PÍŒAI]bÊÛLå(FØ>ºkADR’ô¬ }—H¦ðíÍ6-ôý#YF½>u`.GUÃÐ×pX7FW‚P&‹KâÀ¤'J§,h•OyéæšÏuâ¥Éæ-ðÇj\Üdqw^G|zóí\Åšá+{ÖìF õt§[Br~Þá¶-ÃAå+”}ýTý}ÊX9-5ÆŽý[Ö/[Œ ºK¨t?-½iâÆþÙ¡¹†ðô9ȧ‘,'tT#+öN»¢¼ô*+ 4ÿòE¡Ï¡K׺󃢲Å<6« ú3Ñ1á ɇ ÒONY…Ô9ÊÆ{³Ö¦X èüqØ «˜Äœ¯V–`™%ÿT)·#=&W^¥îkš8ϦÅv|B žfÌ 2a†A‘L€ºù{ŸTUùÕOþsCÆù±+r¡Q.QØ×{rO-K³Ÿ\“-ÂEzÆ>Üd¹ðqû²&£ KÁ¡Ê·‚}æ«’€€¤að‰™º£5À‰ÙZˆ}TŽó÷ôe{þ}à—¼€ÖöW’Õê¨À´‰+R È"70mEãeõzwŽ—eZùb!Ù3.t ºÆêÁc"”ÈqÓbl•mæŽb2:Z,epÒpá½_5K”+ˆˆº—ŸÜ0ôÓoó¨G)‘µŠžlxI–ƒìwMœ]W5I:C6¡dÊ<Ö£‹_§oÚ3šÎ¹Yt"œ”àˆÎ¾O‹Öz˜ÙÿüÈéš‚dTeÛ-Ϫ+»õ¨›ýÛSøÖÝY÷åí¡ü8“ÓÕ‰1ŸÙMöT¨†Qf–¡A3éŸú»Óâ,{d:_I¬__¬Ujá–îh_£èŸ¦ˆF’§t!9ãŽ*ÖúÛ©öVim©Ì›ªPd»÷mNØwç˜ØÏsI¸5$uè¿¸ŠØm\­ôà)€üŠTR½ —.÷?»ÌmÇK^®Ÿ¤¦åÄêÚ “'° /b/ºò8w’£&…¡ ¬ |0cAµq€éú œO˜¢ûÓ'}2G˜OE°¾.§¥#áÔÅøñhÊ©o¤b6’DÚ¥&3¥ß¾”%wÀç=¨§‹ØæÍÀ=]“„Ž{ÕsDdØ!¹«îð£¿òMÓæÅú¿X6áñï™ì?}²ÿ+¦BË5.›º©,;±*òÍb¤£)`÷šDõçÎ K“ÉJn\Â/ÃÑÜn2CE¿HŸ¼ÁÔã¤("¤¸ÒBÎÈ[ãþj Ëd\U¾îT¬À?¾ÏL– iLX½ /'»FëWD™F’qÞ2„—aÞ™]r’+ŸÁè+óôˆ–æ !#ëFô™ùëg-Y“vƒ!¶M*VÃÌ=Ë—)"¸8ÁO0@ãË©nxðb6É=«K!“5á¤aá©<<éEÛºÖøýòº>»”Ãâ¿^k¯›Õ£ÇöEĽȣO¢SS&,ìÒ?ÂÃïðLrÏökñ“6_(ÏRz“,:aÓΧ´ 1]*ª®´‰«Wˆ3ùîÎɦ‹Ã;Êc}xêp;:F,êzçŠ(}AÎ$®¶ƒ '‡xºÙ V£žfD‚IHÊ@ä×u…/Še çÄ6#Å-¦ö•pÎ"óD 4$_8(óhžr ýg¬ÍŸû0/aß༯ƒ…,ð¢Orô™Óp O@g›BO\GO|÷’€€µh$81­*ýÇÁ:û†çA¢:þ¼¨çšCQRÁ&‘nÎ/h¾‹£%mPš<¦‰õ­ßpF+`Ép@y7Q.hÒ‰F†G¾£'CM¯Âƒ§ YjfÁ8ïhP˜Î%ú‚¾´Þ“Zt”Ÿ:äk¶þ,Yý+.É×—µ-‰`„ö¡žù©–B§—è·TÞèÍ.$_GmU/þ•Þ¤è>%pðmü3p›Ï ¶  víˆÃßµ ©LÖðVø’’÷ëA½v}[¸m?Ê$ÎqRK“7²Im¹¸òªÈ>fµÍŒ<ÇÐcÁø¥Ý¹ô{ŽäS¯ .ONPÙÒàáWR‹2ñ‘ ðÝTï PGë'—iBPOê»XnC’6•ŸÜÔ´¿¡"û\ùÜÏF^¨^íRHáú8uñesöXÿ¿4ìk–ŠVŠ *ùMªòË& R,¤=wÇ M>´Å&Ó;Ãà0£á²°ú-@¢ûØE(eJ.½šr|LÓJ` $?8JÂø 9é J‡u~¦ÇÚ >§7J:ÈçV5[ŒÁ=›Éª¼VV+VZ·÷ÓB/sSÔÀFß¼¹A0 1ÁpÌØDù´J8Bî±k›<︚)ÃÀ’<ôÝav@¡4g—ó3 ‡FDŒúíª×wŽ€ßÞQIÞw±2B>ÊxÅ8 0q K‰,ýp0áÕ;ÏÑèô뼆°–ÙaÞþÎS º½+‡ï®y'Ü;?ÝÊh’À~ñç üaAvh$A„Ó˜O/J5Ú}ئ¼‘Ç`;qÌxÚÇ5½M_jÌ q§ÈOd ¬“áJñ4­ï=ÐÀ ɺíJñÅ‚³¨rK4Ö†fèwÛé«î#@ªtP‚;(½µ6öò^VO49ÔÇUNÉ¿±FæKô&n:é@Œ˜-n#¾ûܘT¥*aAªa¥®:ñÜNë5¡Èý| <ÍêóK®lž73·™·}Žþ H¬†£&å@¸9¤`\ާ@ÔÐ1œþßQ/ÚúÖ³”5JÐ)X÷ƒƒ­ü|y`g¯¬¤~ÀÅ1´1˜Ãe9¹Wa:;;sÒIù½—⹦<£!£¼¤A¯­·zÙÒ¸ ÏÞºÚßþ­ ,¡À×€YQ±B5W÷ë܇‹Õi¹e*œÏé0š2ˆ‚>b¾.ä -ÏIþÒ —'Y ¸¼‹«$w[‹ÊûAMMÛ Ö™Ä·xgöæ¡+É™b %`Sr¾pÑ÷ë.™cw³Qw³4:‘PŽÛU„žh ]õA¡ŒùX˜ú®NU¹C«µ±/xüf}õ4ãa•À±71õݳŽk2ìîC?¢ØI ýÏþNäã]F±GjñNç´Åé_õ >ßÞ¦3Ân‹ÿTt­AÅðÑ×üÕÔf®ÏòAj¿žiŸß(;Ť ‰¯ó’dD¯¾R~í¶øËxÑVY÷é.1k¾?/YÕ½dö­ò²À¬'x]Ó_#n=¸Ùe´‡þ§‚/»å5b­od6 @†e#•‹ªƒ®FB€S 9=ÂÊö7Tˆ_åqp‰h™Ì;%Sv,5Ï|ñ ©âÕ:äg‰"xÕgÙKNŽìN&TÜÉU|æsNŒ jŒÇÁ[o†A`Ç0º:o¼"&W7°*¹[™Z‡$j>p~ø›R»ŠŒ~Õi±ýCLȪn2‘’Pá÷a·0„Ò²ïåwvšk±Wîê2žŽ8lLñgÙÏDë¯é¥¬²Vúõ?SЗŒ#«vë~‚Ÿ•Ž»öcߦqUÕ¯ÄkÏ9H»$Ù¥§µÜOÜìÇJ‡ˆ Ðë:áô1Ô`¨;Þ³#Iš+ óŠå‹¿K°%^ã™Û<ÍBPRålõ L6RÖñ`×Ú¥Ÿ|TGpa'Vµ}E5õdg$å'¦¯Å2•.º=ÑÐÅ,bªf‚}¢ÿ· ´M 5wØ ºO¿Z4{fP‰ Þ[§¤ì“ð- JHq¬êp–Ÿö$9–ßJLZÂìYõïÒRZݩƴê1wúÇ¡, ¯d39ë7×ÞêÖÆ­€‡/•:™aŸ„*ÈBO:üѼæw7µ†É*ë„q^éÞþô}¼¾‡?òAÔa¸:2çOTÆQ ñDº2ÈåéøK‘(0ÆØ;áIr|8çèÜI÷–KäÖýŒ…UiŽÔŽY8Á5›”¤Žè°¨%fŸ§5ö¸6…fž’€€›B÷4¾ÙH\¬iÝrñ¢ÒW|Çñš<ÒY#ÛÖˆ£L¼ò€¥0-\ŸcdV–Ë»bb€9™âøCóVC9’òÅ>•û“§UWŸÅ·© ×Å^Ýþ)=µ,[z?Ô0çÆ­§*ís2š›ï‚—{^²ôÖcÓÙõº=Æ¿ô%ú¼A%b群2f¥¹¥ ðkZœ|þo·Þqòz(æb¦Ö |þê¸3v²·Úü¶¢«Ò‡%IôäP€ ¯Æ\césøà>H¥…½Q¬ÎJ¹(Z’N¬S|úø?±aM ‡3΀xRSô³ÚÛÒˆ+²å7p3/ì[¤òK“¨ß 9sµMníäâëÌýœcX™ì8ëŸlð¼–Â]ú³z~‹Õ‹Óæ÷•qûœ†äR­äÇ #íÁµåŒÅÊUJ3Ïb #8û3óƒ¡×›ðkºa¸Â(JNÜänÄþÊÝW¸ETÈ<ŽSÎàT@ó²í]¦9r‚½1Œ|ª‡Ze‰D"Œx ‹ûTá1¡æ_Í)õG£°_`Èlè=añUfîàŠÙg+IkH¿ØzI% ²ÍfL^¡&&T“¶L +vÄ•âeɘ¦þËuèæ‰%œOþ2Ö8EæÝHüw>_œËÐVŸlëŠm¸|ÏG–HP„êŽÂ˜¿NfHßNÁwÍAÕ>'Õ8Ó¥½‚™ò’·Á²g-(§áíó•šJ…ÇüCtM”=Ò h=]6MН¿/ô°êW9beE•0írixGšSc“/ö|5µ§fÑâÈy£,3é%qˆG›M¼ý¯kð3Ë+Ä®ákÐŽŸîá†ÊA©tUOS,t8ìýº4PYKoôkdËÙ­%iõÑ‚_ƒ»_Þ¾á‘ðœÜÍxÿnY¿G¼4lñã@»Sæy€k™ÿ^A,ÕëÀEŽ2$æðqñËüfEõˆï¸ZöB‰LðdÃVø{£áÐíßéÓŒr•î±F;EjµæÏ݃Ü>æ9²±0Û7¡í<ŽýìÓž¢Éï#+u’€€Ä!½~ÉÁ<²­FÁ hæÌ[MÉHås=ÄaÁ?ˆYÊ3ú5ˆìøô§c —»\öO@“ÉTÔßa%ÎýbœkãÔ8ð7v›ý•˧öž•ŒÄ÷ºåUŒ—½(£Ø)cPYÏ驆øq?1yóV¾-V üí7ÕÖ 8ÛÊ‚Ÿu=ÉKQÐIœ1´lä1⚯;ä¿]G°ÁïW˜ÔÓ½~é×ÿþ„}ébå[®[Ú £=˜eZs¢Èõž ôô¼m)í‘´ºJN—ú’Ûél$ˆõé*„ÍîøSÜîý=Üûdû­‚+°’q¯e@±ø4|„NñΊ‘q^¹¢ôTo#­…,æ5âÄyÂY—fc–t9OÉúÿ’DB¤s¯c ¦½Rç™°H±­½Ú½[ ß¡©u>„žI†D†Mˆ9;;27Ÿ7Œ†÷­Óx~.Ü!~EîyÒÓ²?ŸŒ†´  ôKR|éùhz8³¬Ãƭ嵺–"›pÀÚÁ3Mï›2ŽÄ2åZv*Ü—ôµ‘mfy޵·!îÇUãAÉò¸†VI'Øc=2«àä Z¶Çò4Á¢ éUáÅ8`'›¶~líªËÂCãQ'Á¢Þrÿ€ìh›!Ê¢Pö‘ø© •Ã~i 4¼öи/¯ÑJÙNųvëØ­Š1¨À+ádˆ@f'@HÿS®ÇbåF/·oFîÞȱ\êv a:ëàJ‹f¢wÏå2ùäÒoÂež-‡ïËxø™Ì!ûlB_Õ‹0¬B€N7]Ašì€b ¤u¨æ‘qäͰ±’€€Ã„G=žñµÊ4’äÐÿg71«-!;‘ÅY•‘y‚SŽ1vgO0ñǹFJkA ƒ Ö4Þ9ɶ’Jz}Ñ]XÔ`­]z}J4¤cj—|ñô|ñ´d´ .¹.N’póCçr+ )ßtWŸ×/KÚë͉M¤mœO OƒxåÞ~T›ëJ ÿì™x°p‘† Ñ>Gé¢ìÂÍh\‘¥#Ô Mj*ýtVr±#¨™¬Å÷DŸ²½ûFs¥õÚgœÜ§j±[…\·vÙˆCíeYL|Âb,‘Ž„áýx_w†yzí.øÖ€ÌiÙÐ,&W²_Ú"¦uÔFœñ ,[u„j°«÷QÜpß\¯"ðÈT–[]û{¦/ N„’Ó¡Q½_:Z œÏð7øé$?ÔÇÓ•MÈ Á$åëùÝÊþ¤›žª&_ÖÒ¥)õR|ž§š1Ã(jzn¸VÝa ­U:ã,µi“ß§ù5‡QC–« ÍÛQÍÂA;Ëãìu·W¼gñ*nòÒ³¤ :n ›y u8ñÄî‹EäüKM“l)¶žå]³¥|}ùšê9ìöûšF4’ ”¯¹/—ª’Ñ«JéÆcáwžÓ:£õnfÐhYè K!Œ­ ³×n¯Rêç°A&gJ ü µnAë;€aœÍ÷#˜ ÚΡEWèÚím¨e›`Vþ($ §uAc‘Œ1ìÚú¦NœTÔ[ÜAšDýüI @ß•~O+Ž*±ôžmmI7šÖ½à[MómªeäF€#Б‹Ä`Ãù ) Í¡/h1PÓ‰h{’€€ñÝ\9…+6 ÈÙôñupMK%Љäàáa¢0Å®’R ûÁSÝózˆ ‡³`¢i¾tÜ¢;áW.`¦Þ£“)ÎmÌ牶Øj¿îbX9> G¿À^=!¯ ]ÆâÈ–ÊÄD[|}WÅ#’6Qò“З®p…¨Øç žà¯È°–—4qyØ„ f:x™·ºä°@QìIßüÍðf“õ–ãM£Bͼ[>‘®vdÖnÅÑ XOCʯÙu>rT÷Ñ!,WžD2'Y˜A®giªJNviÖSUþækGòSy½É2r2KðtÝÜÉ9¹2‚ˆíé)uÎC"4~}é5Va½ ‡PYg8<Óˆåzd;wa. Œ§­>Ä §òà3Ø(C¢úx…Ï5ZzI þJ!ÖI²tÞëÔLt™zÜ#·dJÝWa[Ý.@¬H:2)3löÅþ[½yº*[…*«“ßO¤þmn$–«mtèx:G(qΚ¿­âÙiŒ­&cQ_\¤y¾›ÈÀu0|èþK : 7nÁµÿ sEÊõ‘^‡µaÏ墙Emª?ç¬;Jëd;øÆÚf‰×Cu#íüQÜ~hnTeÄÊ_¥/Š†ç ¡õa §BoCnZ‹ 4 Ù2uù¿&t_³ÉÕ<¬KMa"£Ó¦š‰úôŽôûÇLÍgj«/²6uoÁôÙã@ÜÖ•Â!%P¬¾ÑBm,dàQŠï;êõöº&Ú­Àý†âšOî“CÅM³ÒÜ]ÑQˆW]ø,£8_#ø~{B`Ä×›-0$=È»Ê z,ñ—’¼S"Z²Vçç&¯5àtË.õ³¤Ps±{|Ô+»z\z=ϱù’Ö°þ€’ž A¸¡˜šµzédqp£CT§n©ºõ‡¢)Æýl1¾D䵿·TVÄŒ¸(&uÙuˆmsåAÝlúƒêÈH¾‹vJÞ÷äÁ]mXÖ$%"Âçv®‰T€5¢,¬ž‚ì‹a:Ƥ,ë2ÜVŒÐ'ÚK´D¡ üØ U9“e‡šŠ³‚㸑YÐ÷vIL«Ð§'Ž!’€€¸˜5ûèòăj“9s¬oUN/xεêë‚Ð8²Z´g4e ½ö®†|ŠÍÌÇ6Gò‰e++©šÉ#_ö”,¯ÅZúŽOî‹«nõ-|¬ û+Bï;úÂá+¥IépQ!øÆ.\˜7œÞ"¨¯ªû#¹†ù<~îZËúŠö>ÜÊLî  s^:äþ¨1²¥Xw·EJ´¤"÷ìËJ«þ_¾^Ȳ˜Ÿ¡*è3 TâŸÚ£ÇQ—BÝ}ëv%ÝShíDhqqûöIá¢Ø#'“nòŽA¿ 1óˆlf¹KZS¦iYfT³:t¡€ý_™ÃhÂÌãŒðßT*˜³Ã0ŸpE+¾ƒÊäÖ²:¡|Ö¢ÛTtµ4O%MÅ;Q ŽDŒërQ%Ūd2ØõëìÞ^\—ëÒË©uC),õr’þ]׆/ÝëÈKV˜2“Rƒ[M]-š>Õ±‘ž²ÞŒ%`v¡§}J ÀˆáždŠôDuyprÃ: e¬'1=ºcbÇ¡°^±©ý·üÛÙkv\\$¨ÎŒ”–ï ÷†Wºv¨Ô-õÓW±²¡ÑíÛwäÒZkÝel6¡˜Ð6¿›•Â¥ |â`ˆ«‚å.y”,í—=9ÓÅB€ § NóáUõY¨õSSþWà .¨¼úÙbéÂþ©;¡ó4E*sEAK³;Æð]TäÊ©7%ù¾Œâº$n`­kãõ©¶ 5;Md;w=¡†sÝË Ç ­ë¢Ð7¢¶Î m´Ž$Z¡ ÊZá¹ðd·Ãé{eÓ¥fÇŠ7¥œ5 vŽ~†$üaAʬþª×¹Š Ò}å÷Žž‹pãª]`€Õé CfùfßW£Êgô¹„ˆ•ÇáÄëlxðò}s( þŶ2 Á€H̹uf#׎÷üÉ›†²ÒŠ\dƒ 7tãÇJ:ý¼¿cÚèÆ¸oÕkëí+f‹oÍÌÁ/û§äöñnÖr2hª»þí/ÝFý‡ìXä>ÑV[Zï§ý:ÙðT{‚e ëÙ“HH©T²ñ/[Њ=#<:Ù¶ÈY8Å-ú½Ðü’_Ó<3s÷ À©Þ+Ò§ßJy&°ÅÓ¾È)A{T¨… &p¼#éy0Š—¯ËLhÝ9¢Îº †“Œ9’€€ß#ãaæ¢áëýorJn™Œ†ýæ`/¨#`âÿ³ÛZ§ji»x&_šûçÿ¥‰¡PO šÂcª„:v_‹}¡±ð”,Á Š=õH¸¥*Y  ÔÙŠÈ R=€"ÛÙ{Utòˇ.3¸å,í¸ûÜb;dÄMM²,–ÞÏš¶ÏXÝ®´ò¸J 9/ÃŽm>~CDÆO`üã=˜’NjT‡àœ“¾] Ò>~{ÒøÛ»„ÆÍ<çÉò_œª$#ßPñQr–í°tv­ÒÉ”^ͦ­ÑD°À0ƒÁ}À&C įªÈ^K2ô/t²\D€)0ÖËêX”µnxãËðëîÞ^ÆÖ6—ÒÈU£·RŽ!#ÎÜlµj»²ÎþÚß kFž¿U, [Û² ô‰Ü~I ‚Sµ§ø$ôøBOñÈ ¦+êÙòËÅ­,ú°¶ñ­B†ÁbãÚt$ú€ssiödºcɾ.y·UŽ“hÆÍ2ó{éÍÔžyON!=$tqiœ~· 1‚Uã°íÌzˆzõ>ÑJ•Ws]u Zä™kÞÁS3ÿ¦Jï$ñÙÂôÞšÖ¶t+Sòv+½£§ÖäÐu_s à㪾“‘Cv ð6ëùÄË(Ïò²gnøQ:b¯þmWøª¬ÀܳAþ›[MßM‰šmýـ̨¡à¦ó ´)¥ •íN»UiSWNó.t!XqsˆŽ³H5Šž$5À39ÿChië2W‹TK¶p÷ âñþv…ƒOÉÆFÉ‚0°¼¢L]Ú'{ÉFXØ÷®â’¢:]Áãu<“Ñ£çÒ'^ú…–uÍà\tJö|ÆÜ<‚`]ä¤( ÿøØg»d,´íà]¬w÷à0~A™†t›=c6û¹¬È\…—âÑlh ÍgÔejÛ×gçyÆ€W—å:/XSmB4G `)\²«cÐ=LI-€®Žë­)#òz'ò1ö‰ʆw_¼šúÕüÂÁÊÇyJ.ÂKëµð“^딜jTuWØK!#(qP¦aàJ¤±¾ÅPyʸ¥|í.qÔT¶2$¦MxoK ©¸úÛoO«ÅÌ $‹ùª†gN‘5ÂTÜâêéÛ8w?Ñ¢{¼Tq?»Æ¿3Ëú?…hL-òÂ]„ª×ôô›’€€ÏX=`×Iƒˆ[¶ÖÛJl2žéVŽº°1Söm–œ>¶J8°û*æ• ÑÇໂñŒ^ÇéV½;r×wpúÀ÷0L´lŹH3eŠöÊ^‘‰Må öyV<äêÔzЙîc ¬\WÞo}ßþF¬— ÀÇš³öäž®q‚zhHS;ϳJ"‰Øµ(Éh”9àeÈaÌÈä…ñ¬|©(Æ ÷\ÎqBÏÈO==JRB”9«­«‹ÍdÚ#«E®U–Zz'•|sojõŸ“fÚAµ“žµ›®$î?›Á“ÌÑÏ hɹ µ'#ÌÕ¬·½#û_ ôÛ!EC°Ù;¸k[HÖ/<Û#\—Ó¬ï5[ ÉxW×µ&¥@„æ^5š¿Ú¼­fB£Wàô¡SvÅ(¿èîÙ©Mù¸VÂÕº»\%Dù¹wš¬¤iJŽœ—Ǭ1 xnN‹ïÑ¥È^å<cÕ;E>Þ8H¹#s¶¨•¶õ°ÂÜ-Æ$âQ´ÙÏ9”丳k®îx©eósœPƒ/ ÓA“)Mio‚‡+ôÒw5 ð@Ÿ³42üÈQ›RUii à•äi¤ê)Û>d‡ L¼×¿;jYùd˜u­oæ“Vƒ¨xóÃ`;‹ÝÊç+` éïã=ØâÖ„µî÷+©çC¬”¿²íiÿX'­–†¡3ïÝ‹ ]vk˜ ‰ÆÜ{@£Uènre¡à…BÄÐÕ´’䀦’É–þä³T:e²—º˜˜Ó\&}z\Hƒ Ï[¾/ŸŠÇ9ß>MuU²öâ;¿„;›ò¶Àƒû® $nÕÊÀÒÀˆ={.ìÈu’| 9á»VáëIC»i³_š--pû¤`ÑTxÊéjÙºÔ­)¥ F…'‘§kq„”£ËµÌVÜeqd¡¢6- vãÈâ€edžÒDŠ{±—3™2^±ã8ôBƒÆò:weÈîßí(¸¬¼X°…½ë¸íÙnЫÔ%ŽæO@ÜðTûçKOXªèäf¸\­ÿL-’€€»­Mýqx.9Þ¹F¬GêdhÄõ\ǵW‚Óy$ЍãGP“×"à|.hÈÛ Ø` Ð'LÚŠ› ‘cð%ß8ôVŒ£uhð§(ˆ¤ Á…—¨ºXn›YÆ¥{üŸZÆW¥ìg>G¥„ÚÄ®dÏ}_ÍÙ>²Ÿ¨Û«´¨.É|Îc,‰AxþëÂ_£€]ü™C=Ìf5 LŸgA„iÙ´ðBn^F]µ)œ@éтȠ¯PÝ•Ý,T 4÷jy«í¹¥iÝÆ?ðç 2yT¨ð¾ µÁ…¿€èç×°õŽ;OÖí¹Ê+W÷NJ¬ K¼ Û*Eu¬]ûm"š/è—^—¿úù HY%Õ‰=Žò -™Ô†*ëÌwà ÎOdzR{Z\ 0’?!Ñ´ç¯ÔúS<`ÒðVà š`Ætï{­•8Tµ•n„Fî9JšüZÿ‰ÅØŠiÜ”#s;r«¯dŠó™ë«Ê[£^ïœ4 9h#̽Û?PƆp7»îÊ‚c !³tˆXàæ—¾ÝƒŸÓþP˜è¾×·‹$¿—V ë÷¡ŠºŒ)büwÈÂŒéðz¹àsxÔH Ê3TÅ5Þ§Ø É¢«³c.ÅçO`¶2v§¶aø,(Bém‹e l{½Q±EÌörVÆ€¥Îzì´ÊgKëk½Œ„®‡à[œtwGÂåPÑGQ³’€£òB¨/Uª*?ñé!ôDŸèÛëØUx­¨À2ŽeµÜ›ÌÓ>JÔº­è`ŸAå?œôàV6àÉÊr´œ Q7ݦØÜáÆØ÷_ˆ9ê†Aâ¬Ç k GP®izßBô[d-cß«/_4ûè]+ooÕtç1(Î%/Jg_k»¶Rr:ˆ‚ ¿T5{ËüCo **Í„£ÓÖ-Æ›þŠ’7þƒÕPNôç*W»LP)=¹ü»vØ#Ào).â Ú—Ô2Æ7öUôtþX–ÇoˆÿNû4ááèÎ÷óp³r_ŽOEqú>Y¶ã?\zS+䃶¤nÅGCÌßêŸUY ³ÌFr Ž{dúÅ|™þ–Q4˜ýÖ!ËÑ¥°'óë5¿9Ete„³£ÂT©”\­5ukðù竬hØ1†BÓéæQ7Pµäâ^7]ÿНÝ×["žÍy¤¿t0ØšÁÆûÅ@UVUeÔ/üFÓô‡…$ãdVq ‚:޾fš'\¡¯oê’GuUTfü± XuÀ3«ÕûI’úÓ‰8UvHd #«%Ù]R„†šävk½5CA¡óø’é™ÝüÙÑ壟ñû‘&a¿ô°›‚`þ½ü€QϪMš¡ˆë½/ºÀ;lÍ™«ßÿìMKÞtAr™*òãr2ÿÐ7Ò¨3=8Y@è‹Ö{¾ùMâ`æÛŸºMâ³{ºBƼÆï>kuè6'A@l§s[A³¹ñg?½©Öbϼȱ7¹ûzPçg`“9ˆ‚+êÞÄ:¬h”}Ú¯¾uêµ_žÕœÿ ÍQ–ôKÁûO»+À»ñU™9°,Òå2ÇFr±]3³Ëà?á“æî€¿Õ$ Á3šÜº$·õO»®ÉË×Jäÿå ØlóÿûÆ_Q$MçŸQ!fyžÃÿçÛw?ÕP‰%ù|`5×G—¬—[,Fa2Ô-4¯—šŠþ3)µÎÙg<´BAu¸ YÌ#§•Á³Ì¦HW¬0B·ö\‚’ꃩtS“ÞP»½zYÃÅ7rÖ¼‘è.z~œp~¡à&%3%–QâÓÏç54}íK¼òÞ -j´áE[>'8o&´þRU^²ƒ·Ï{®kmœš«O7jC‚ªÍ.Ûëo~&“9wÓ²… …B)X·ôrG‡ÅCÑý¹3íg€6‰·ñ|’×å5¸åÛi¢ÿJæ#ã]MoFwŽç&KSL.B… ˆ­Yš™SDücž¡ILóŽG–Ò­J7H’€€óå“/Áú,°?üK$ÁdaâNÃ|‹ë½‘«çŽXXA¼yóàT@Q…ì"Øf{ žˆ¤¼þÆã1šÃBÝÑ;ˆ·i¼îlJÐæ J âIÏù üÄZv|q:ö÷›ßbQGUq¦ ²l#ž,;Œä¨ÁçKч©ñccÒ[ÿ*Á¡¥(fˆ¼¿Þ¹³Èì ½å÷æœêyæ¿*Ô¶5¿ôÓ2§6!ÄfEã4Xý¬é;DëÖ¤½'ꘊÔÖ¡’z¥Wܸð‰ÆÓ·¤ÄjRìþ¢ÃÏ[šª!7Œ_|ÁÐ#;丈ï²Ãºë~ªËÖ¸s„×·é Õ4€¥^ZTd©rÍœ&Á‰Í®ß°H ­ŒÃ'q*Ò4æ7Ýìvø;¬ä¬# Gy)I5è¤Kϯõ_(þ‚õú¯áÚ«Ýä£/ƒGàÎÎáÌåUš©KE6Æé[LôP¬cGº´¢JœÏF´•!(-ƒd6¯‰ž‚®YYe‚O{cï!˜>I^þgào+ü¯CàTˆ4A>b—;¹ù œ3òGQÂtBhø´]ÄBP„Ö¦{ãÕ”ÀCÙJ‘&€ªË"+Va™ê0|[¹­2‡Y˜Lø±Ohw¹@;–šö»¶[Š_Þ)ÕþÁoª…Á“H8´äÈ“Ùÿ!•Ûu³v¼åÏ*Á&ÙB))ž/A“GMª==Á¨,N§Î‘*æîû¤Ü GPAbiX8H従)7#‘°ñÂFû=®õË´°MÍuïÜHMáïMì±vqØ­å¹3Å;M è*[ŽsF('J¨ƒí•}­×*lj·©"€×ôº2@×ÿâF¬±‡È,¨;W­ˆo ˯±ÒP}8B§[ëÝ…$ÂvÉ%0ë›Ââ©Æ¿DkHWÂͧ¦e­åI@ãº9©‹—kEÀ;JǺߊ’¹ñÏn‡!ˆ,ØÔNTTJåÛgµg„MhŽ?­9lÊç¾)zQ&¨k¨‡3>–jÝÆDæF¿Hø’»T ñÑgù£‡CQ©ôœéïQ>~ú“ÔÀÞC q×¾ò&D½B±íû|Ãü‚ßqæUÃPY2Î9ŽG±Ç.o% Ó[nkn½ÑŒ–ÅP›3÷y?›Ç«¨«,>y®U›ã©$ò4&Íä)ÀÇ×s´ó¼$’€€ÃíVÆàÏ]yÁYh”~‰EiOv·zïw,˜É@?4E+ìÅìâ¥C›×¿7 ‚†µe¼AnÙLFl‰š4yuçRÜQ76ús«­Õ>ßu>Ëiç×וٔc©ÌÎf‘ ¨ËX ãÊí2]£ÒÀUЕö]û°vºÄ²ê„¾yâ#À;i‚yfhGÖrŒDI)úÓiÉ3ÒeO’v6Âà9(~‚ÅٖŸ U›Äšóûö§ ùe7ƒ“öª^—âº[¹äØ—P¦î%Ì~Ú§T€½Š0 «odVž’Þ›T½ÃÅNEÔ‹5ÙÏàH‰ðÅËW×q:®A/uXƒ¦¶©Ñ 9Ãê1“MÓŠ ›šý)ÆE0œ„*(÷â:u;iÌr°¢žèf .ÑßAŠ•/㛣žê~g« èDÙk™±+W-È·èSØWЄŽZï^kÅF+ük8ßN1ýG–aÚØP i?ŸK x¸˜Š²~’€¤ÒÄzU¹hµÌ—S…3h”ß<šr̉®[߸“î‡ÖØIÈ—Zþè#š þ½\ëüf' ]rÊõê®b%b#îqï„.âµ £ÈÌg|Õ[‰Ê‚Vš¤?Jé·…¸«æU ïu^Ÿ°-ð­Â'c>5ñ•ùññèÃù†f¹D Ýõ÷üý—©ÙT»[ËÛf4z/•³ßÈôÓzýûe†è€ ürø^¦è.7¢¿v¶+îcDÚ ÀIKÄÕ¥´o&›B!òµtØ#Ô‹î~"+—ȆiÎ`­‡"ÝnÙ§UýÆŽ<ÚÔÇV>2ÃÙ.X… 3¨ðâF4óÓËA¬Ä][HZe·`DiܧÑУ ”#.]}iB!¶f}äá Gò€¥†®ú©*NXü ½vþ7ŸàéC^'YIƒ‘É’€€Ö»?ð”>ê³yw*kNžO¼dVRÿ»¢ßfÁ>‡APŽ<ÅÁüs¡¹nDÓä ÇÛ¡t †¿xðŸ\7-èY›€ö^‡_qzåfêµðü)3Òì"É[·c6-+t~Ì’*)úé FŽÒ¡ev ½úžD–“U­"èWW]Pë “ÞqA½³u˜Ìv‚UHÿRøô]‡g­”3ÿÿþ|jÎtrß²,ùŒ!²¥!xœ~X55«.(͢ͱñj Åã|Ç39-À”§),TdTæìÿ2ßI`gd]Éx~NthÊäþRÛt)ˆ‡´x—ñ‰ö›t:Q_%»¦ÒO´OæÌ£HÎB~›-Ôª×  Ð%»Ò´™ãÝä)®ŒhÙP¿QZ#à²h>uå‘­R{=¤3` £7ï‰çVº ÍØ43UdÃs‘¾‹ÍF¦€ü®¥ˆ—…Ô jz°UöÏu¦ókÿš1­ Œlî­yŸê»D¸„¨f8± AÕGLä[w®/ÀÛcŽRï_£¯ä§ìƨˆ ™29÷ W3p÷ð*.žàäm =†Aæ¯ýÖjÙõÿÞîù¤}J´Y• e#ú £ûûµ¦ÍDmÖîEýY÷¨Î. ²S¢äÃâÁf.f½7'ê‚›åþ)ðµcí)]þ3v`ë.:Èä9þöE£ì¡«±VËm#vÙ[íh§+— <ü5¤É6¡»ËÝ'싲¬ÖØÛ™8ÔùûQ¯ßE®ÃLtÍj ŒAg:8¡œ<<× : ?²Lç f¼1²à4øN°#ò›ÊÄ ö-ÂÄç6 Ì0³ä °hO{ó&+±H¤¬`8»8ªe"\dä¶2îçºí– _õ:ã)fx1¼SÍ Å¬D¥Z®„†I7Åoœ„±J!€˜U.´)tÓÁËŽS£@ L+ÑÄYp‚‰üø¤ ¯öYŽ‚;I¹‘}A×@†–¬QH«¥bë²*œ킹 ÐKÅÆ©õENr€\îžø³$`VôT\ÓwÈ:™)÷tâL:× [Rc-ß(ùëuŒ¿Šò gºwªÇ1Ñ»#y<¼SL·1¤ÿ¾œX«-›²²!ð‰2{ÈÔpú‰Ÿ›~( !Ý‚|¾àFáȪð¹Óͬk¸Ý¶’€€íR,ê;íbG*¦{)Y$÷„îf¡­üý¯Í;þ^CcÚvC¢ §Ssq§ä )ôº í©›æ±”Äã4àmälíuqÍÍ;ZÒšqðetœ•ì$6<ˆÈï.¥Ã.‘—å¤-Æ—ö¯l^ XµÙ1”â…kñ-D¶Ðnä—8@í0´:Àv-s!u2¬m»iäS_æg¸/{4æ ØHp`s’tššxVнÚÝrjV9,MC6±Xpù§qOÐ_5Ür+(šiµb?B{å¦Ò 'Ë))Vú*,)¿aO1©–NåtÕH–ìLˆŠC‚à»9O2ƒÅ½`ïóà)FäZõ)µàɌÞô™ÉŸ-‹°ôÅ·}óã¸l ‰Õo~m!_¦lcýžLî+D߃ë*Σ\¤îeXiՄà%š0•átý au‰ÙhWXêÝÇ5Ñ¡&rø äö´èv󋦈‘JŽ‚ÚòVÑ„ƒÈ"͉©ò<è0 z-¢ã©Íà@­ è¡»Ìêi]ffSèâ+§ê±/»3¼røý À­˜ëÍ«Y2°(³¹t^½Òzdu³þDð¼¢Nï)Ú û^6Ê)eζL•ýؕ˖hä©ìûZ™ŒS¨Ô—Ás#ç¬ç¤ç3ÔC …5ö .0„ÄByüÿDSi8‰M÷Òu¿ó¼‹=r7?ËÈ5gMdk[4 ç®î™; s& ž’©‹Q'FÑs’qQkß„²ÝÔÂnb°¶Ñ ÛK^ƒ>7‡`xTéË-ìt-ìxÊ?ïCQGbkâM±‰ëØUÒÄT°øM² I gð#FÊC¬ â_ám¿Sh0ÿù÷7.LvƒfmÙ’xR*סªB˜½kŽ šüú·Š*ò¶'J÷F¡Š¦b€Éé1´¦Ý[ÆàD×°’$—ÐýŸÔ^dŠ Gø¿-ð¾¬Ñã#ç¬Ð"~´Ê`v=è)¾‡›6âÎu Ox…(jF¥±épˆ‰]™&ûýd@i-y§ý$¹+W ûjr“оfËíKîÜ»Œ•N¤®G.#öyi”Áfé\O«Yå ¯¯ìi(Ô~"w‚ Éx¿g~¥MC…Ñ Á³Kæ_X Ô@+…®5VÍ&Mp7yÌÛ¡¹S¬»?'iØê}9’€€ô ××ŇÛ6öêÞ8'¤ß­NHÉî)ˆÇ$ëˆa7ü¾Q’˜,i¥ýÐ × €è¦%fxjÂê¤2[,énFãA/JNÃåBW‘s¯ F‹»Àºº£ú×RSvÐÖH¦®Õ…ý Y XI “jÉn¡]»¼ÞÇèª#¦bVéeO‘¢zâ#([Æ#Ï ¤m¡Cžcjƺ¶©ìƒ‚ˆ<߀vyýJº@'e²tš>Ïl@¶\êâ;¹y¿‚.Éßö¶QÄ[ûF­ã´Æ&&ïë8ïw¹ò1wªcë‚DúÙ~&HáÑ"ÁdFõ e]âY€\2˜‡*MáÌ„bŽa*®„+£@¬šj•«ÊÀ¡' Ê`ïá†=‚ü:p'4€‹™<ðð\e“™—I&úÞ€UœOxmøWú.ÑÛ±ùšµ $îð´$j15‹˜U~ñ›>’;N[­Kîú:—¨¡wéÐцfÞ|§%½:ÿ9»û1OŠ”Ì—^¹«`7Ä\ˆ3ÞTÜ’/þˆXJubˆèXð"gÁµŽž+‡‹ØeßœA'¢RÎ| Ü$Ÿ‚ç‹E›\ Ì!Ÿ‚>q»Ag²767fçëŒ ññî{ð@ŠP sŽ´‡÷y½(]%÷„”'dRú6œE7ÿêyÁE©Ô‘¾>iö(ín»7óL`[í—^“-a|Zª†^Ð+Z°6 &Îc:¶ Ýž."¬¶ëÙ¦,[k^p Ñßý°.á9Eåxa]†RA´‚žŽZî«¿TÞ5/‰>´^ðùJ"-Ùòb N!¦ªËþ\Š÷ô _úê¦ ÈXCSù”ôžã Gc„kFòuEÖUó¯q)vÉ]”ÌÀØp»9¡(þ®wp|ØÇ;,ï]>ë“>¿ÅTDþnDfr¡éÇj¼•ZñãáÁâ͵SÌä 9¬Rž´—QØõ¾þÂ*ëî…™Á^à©Aô1ì”hoV¡b[Ü[„ˆûµ¡wE·@gK»Æït`ŸMeI¥]²rzZÄqª0_ûƒ±­HrñÔÁ&œ¸ÏûëRd5ä5ím…—cØú‚·±˜ý)h’ã zv¥ý¨Yf–pÆ6Ù!&Ú?¤5»ßÑ ×ÃÁK¯dú ÿ¹qƒím’€€á¤“¬Ót3ŸáØà•Sv×±Ýí¬þ~´‘zˆœ§ï>‡º~«Ñ¨ä/pB¤ðÆð0§Œ?†âð²7ù}‚Um?¬{¬ªþ”Y»ø˜|ùÎz„Ï„Êï@¬HÀ#PwCµõÑ;úžÎ`èÉÛZ„VÉ^®ü& žéÿóiºhà9N:Îû‹Ô\°|2ÉÙ›_¸wáÉUùŠ`扣 —ÈZ´@µÃËL6¼e' îI xl(¼O!ð™„Û@ÌO¡ã,þ¯F'ö|‘‘ŒÌž48Ë0BÍ"“‡Ko߯yîèî#ëv4h5¶2ó_Ú‚ùd¡FÞ^[†·{6{VkÃÖ'ÃÊû*¢Î X9pâ*¬æd_¨u]œ\js^9ÅïÌ0Lߨè[OSúÞtY³n˜K §6C_7f7Ižƒ:F¥êÍÅpùþ÷eDÑz9”«6ô3ú›Ö) B;Æ@Å;ðß}•‰pýSŒ^:yý ¶¾è²ó»À1÷9Žù$÷2+â÷td>á}.ü6¦»Kbp€æQQDÆYÙ¬Ûƒ]ꩌSã| rúWÐ5˜ŸòNâœ(XÈ;#ë_¸\‹¹ÀÌ’€€ÓÅÁñð)óJbÉ!f5:®ߥ%âÉw;N½†hSö²^ÚìCj.®R‘?@I¼œóÐiºwšËï³y“ˆÓ{#)5ç4ô‘!xŸÀc^é—Åô‚YgÀˆ²a}èuñ–£ÎR½{~s®V¾„DÐ]ð¡¢™<ªªt$¼ã_ñ2HJœ¥uíDO·k:[¹o,÷òì§€¸£U£Ls@Iõt£JÔŸOH$vÓçk Ãà×'ýV>‰Â»„—iíN¡UF Í‚¿¤DñiR¡–Ž‘·+”ž(MTª—‰rqÒ '½€‹§–‹^¿7o®<¦£ î¶ÓÛŠñ:¹>á/ õð]pwŒ\ž™ZåxèBðîß c‚¶¿Ý#·g$ºͺÜnΛ¶+Ôþ†ñ”„ xª)³ÀJ´Y:D,?àeÐÜ^z{“æX|³:ùd“ˆ-çtjÐÛvÕ`_*mÏ|Îó pTN´ t±û…4 Z–ãÆÛJsv†Ø•o‰Ë†yß%Ëò’ìãv¼i4g8ØÊŠSþÚk×ÚŒdËJý·„åJì_¢þ÷²÷úrBãÞÕâÜa‹aˆñ1¥¯O)®NÖj=Ò·àt€éœ>mÌëµ5Ánñ3N÷>ÚMJІÍ~`ϯ+ âèó¿€ç=Ê·“ïù®òö¨d¨Yðc_àöîB›Å$ Åíü\mëc‰Ý8ÿlÏ L蟓ѯïm>&ã›Ú/¥ðv¿µ;ÍÌÔPu=…qò :añÁà&݇U›þ r6ÝLEmI3r‡+PuoUÕ=àîÛª{¹šÑôakÑÖËž¸ž–½ª`£æÄ8ßt®lƒÁ%Õì«›¡`ocã&†Eg§"Ú -À­KÖ‰¥¬"þÝXŒOÈ»öÛ4#…ž Àx‹âk~¶^j{¨±—¾¸ÁY|êjcöÛº”Õä­A^èMx­’€€ºÿÍ5£õZÛw0@Z RïR…Ê‹P ê#ÜE\–?×.óóÃÎ{Uˆ%×­ ŸÙ-8¯ÝÌÆ†*<tmLÌWX—P7Ëßã®4ÆþEtiUÖ–Œ¥yhÝ‹Wc.pYîd¸f0pN£Ž½ˆ­iXÜEMâ•sr«Ùryµåë K”[šRºŒmJ^sİG|qÿ¬eÖ†î}/Ú"Íjë”6”Oã«•r=á¦Z¼[‘Àsî£Mþ\"ƒ± »•[´˜Ì¢ñYVž 3:›#­­ÈGhõ¨5hù–Û›E£MðÀRöB[`^Og¸ÛÂü;kÓ÷ÈúÕ®ÛÎïPá§WP—™‹O²ãûâ»nÅ™FçÆðL9\djÕŽU\M´¥ž*Ÿ0âäìÐHÔ®ŒakÆË¤S©e~Mßh`o:L ù.bߦ0Ž\ß¶Û~j¼ÜÌ„q÷«ñÒºà ±„êû¸É³)gp ¨¸’œ£Ø©Œœ$i„$çòYlÀ­ l–°&±ÇR®(¬ý\Û]pyÇÕ_ó×gPOøNZÏ`É]»*´ÚŒ³#@5ÄËŒnÿujP˜ËÃòÞS_jÝîÁ´zýÙ_òðÂÒ€–Ž*zÆØ uu*<Âô:ù”XÆxT8v汨¿5¢´Âþ0fø»…·³€ÅÛ¤DÙô~g¾S{+hÚÙo¤2¡<èkÞÊÑ4$ÂÏÌ®0²‰8¤‚ïþóûuÞú$7wÖ‹ÍͰŒô%££¹±H·ÆH´ô ÐcXà Û·´Sn°Z€SÕq_%ôÖƒÞªáªü$½í¤ñ'|1…pnîh$ÜäØ¡Î „µÁáÙô@í ëv(Ô¬7XñÚyu~7'Båx?@cÖi#³ öÖU1ƒy÷w­ç,kÒëåo$Ïbˆ3ö…ÝÓq¦š?.eRkp3>Ñ–Ì?(p‘v¨åuÃG)s®G˜lW¹1ÚØ;IORwTRPŒÝÉ´© ²›UógÎé=”R´$‡eIO÷"ù°¾]ifߣQH|5i°c¤øš€•ØF’oEnÜTƒ4•Ñ]É«2ÍåÛfa¯')BP5‘ Žíg$›û ÅÊ(‰EŒð@eÃßî§#ìA®`\kJ žÏ–¡Àc¡ñÌ&[‚Ž ìªÚù4ÓOÑIµÅTûiO’€€³‡¬í¦‚–;÷:ìå?n&AøÐ%½RÛí /apþ¡ãJ0ÝÀVÀhöi·K&Ó‘#ýnÿm¦sLF)=gÀØ„¥TÚ5“m1mÜó±Õ²CöNÚ}ÔI$îœÃ¹Uϼ2»ß¥Ÿô– l:Å!,|{Lɶ£u8Áúòi0xsx³]¥¯ªS0ê»ÇSsÍlÝ2@Â_M=§½ AŠó…ø>Mƒ‡hw7UºNúi‘„ßZ“\-§¦Œ#q‹”P+3:WñGxÿÕ¹sâYgUj¦%]÷wNÝv¶†¯&¢g:PøÍÚ$ôÓSÿý®Q‡%cY Þ(ÖDâŒáþNþú¥ð, þŒÏi9âµ6Ï!ëŒ@õõ…íØt”ª]0¨ç•â³ëú;PF·/¾ZžÝ  0já/ŒL ƒäy ÎM„èŒ1hYxÁIb¦òhámtËÞúpžÏZ÷±ËdÍÿeW}ÍÒÝ qxoîQˆ!ç?ûò°µ>+hL©ãcxؑ酯AºŠj•ºä!W&øÜ˜DÇ÷WI²[DD¡óAöŒh0V ,Ø+xg¦îbÿX®ù·'¡³êIÞ4¢&ø¤¡Kãùà µ„ÑÅ®0÷ Yk¸è—ó^f,S¸êæV1$þŒHÂÐï[2 £©w%ò®úYéŸK~\:wß<„C?Ѭ–Z7T˜‹ÁÍ>öOÊ}ö‘‚nŠß„£Î¼–ÓÕÀ=+]%IZó4ÂòX“*'ò’…²g‘×ÃìNšmx5_X¡p·µ’€€ÀÓ„:Ï(^“Z@Ü †ÑÀ6½ÃÔV/i ¾³+ÎVÉjïSëߪ>ÿ6\?îQk)ר*hÉßÕwÝv¹¬Tâ‹ѳ’ôƈøÆWZnG2¢µ>ÁúÓðõÄXôuhR&<®Üæ:üvòVdg!)¾Ç{Bgú1¥3¶¢—§^é‘âÉû׿ŸzJf"× òî{®á#÷ýBŒ¨«%+uuCäR!£FÌR©Û Ϊ$J!VAÑ+»ò›·›u×nüÊÙŒeUT†’IÇ$oÈ™/´K*\ß²¹B6°á@ØeY2A5È%Æèè^Zçn,làMÁ˜@’kÞ¡Ðñ%B !ÜÇmW&j¥ÅL—¦ý±¥ñûsRO’Æ’dÆ)LDù“¬éu¯^:Us¸ ¯‹‘î÷jâ²¾½vDµhgvÒÿ#E$H"èî9¾gpxéÚNÌk¾U®p) …7çòóPÎÁóÎ9<{ðµ§P¨šˆ*úódzÒe”v}¯Å¤5 ŽÊ׫Ñò¹ IÆÀ€`ºÖ¸óÙÊÆ žìÁÐÐ@P@–‹GÍ **škžÂ›„Bà?/}Œ3_ɦ¿›ÁI 1Ãy™©~:¿ŸQädòxœÌK{·r+HåuŠò$uÅžÒ\Xƒ,0©æ™[¿[ü9R±:¬w+­ˆ ×e)ÔéH¾ž1bISr\ {o‹3­â8Ÿí®íºÊÇZÔ[g&¢íÑWah›”Xb¾²xÉßq\­åŠÇOG7š…v"¦Ed¸ÃQЧ^n¿žÐ÷ëA¼1­I‡|²‰pú¼&‚œùcPp#Ö„";Ì`ä»0mªJ`|îαñÑÝaÚ¶ ® $cP³×g^M²J”õÌ ]?LeãBõȲ˳ˆãqÍ6=‘â½ÈâßHTÄæ=¬Ìè‡öw·&Û-FYAø\´èm“M}hָ˯Ü.Ë–—&ÿÕ­‰ß¥`]§Ü?@:1/pžÝ_À\µý·Ø{ ˜X  #cc÷#qkúä¶2ö¤¹c:̆x:îšD (kíR9N¼ƒ‚Ù†ðž ÔÖbLQBfgÂbÏ䙈@Åï{¾«JoäsBõÀù¯v¬j…¥ö ÍSÛ+Û ŒûPèlœÀê®·"K¯I‰ýK Ò‚«îÂQl´Vé gw£¹bäÿäªxk`ƒÆŠù¡›ÍD"„Ñå)ŒV µrVЇÅ×½SONK¯.ÎùY+R91ß©L‡Z\ $O^£™@¹=¥º–¸º³Ò{ª‘3Ét¹×¥”M²e ®úyRŒT8.M­)S²÷ïáØVmˆÇqU³w­=ËÂNÒƒ›)hŠªÖêŠyN“'ΕF!?l7 o†Vrloiv ­"ª–ý ÛŸ¼‰G€ Û¿—w‚faþ‰4^sô¶Yë—_Ï2lRùLΗÃï?eÀˆ¿˜B¿ûc£Q΀=ÈÚðÙ>䬾kÀ“Ú¬oW>¯"šáÐ^fÑ%+DʧèåL’ÛZçd…R:tG(0Å&wthz[¿¢ç(ÛÎ÷ó]m#ÃŒ—»åÔ*µíìj¦iU/Œ3âm÷L‘%æîì¥Ð‹r}h÷õãk.‚uiD™™ÊHpÖ™Uš¢3¬‡ôn²RñÌ:ì×Ôí:Ùý…`ty8Ç4m«ì`rjyÖæ¨ó<’€€ÔuèæùÓ¼Õ[›½BÁG.*ÎQ]J jÙFÿ؉ ©FÛ¦®–ÔãלÉËÔ3½â;ŸãwDðQÙ¶Íå&¹qÞPŽx}Ö1:ÜDþÂ0Nj‚:ñ?g¤È® î“\êPžñ{aÂ-ÑÁ‘C¬œ°R(·!k*Ãf!*ÊÜv[·MD5´á-[r­`k×VĤ•”ê(Çù,†•ýó=RÁ4uw¥Ãº^‹±÷+¨Ÿ›Ò•#Ô{–O—``|‹ošÊÊ‘ÚekΦ {,0O— ¿U@)¶"XÐrrÚ©†âü.ÑGÒ]k’±MY¬Õ&HèO“;Ø“YãXRòG@„ù°„Dr÷å#H‘"v~Ú`«‹P.‚ ŠÅ…ƒH¹X8pDnÕ¶Ì6Ä sNã— ”žÝ­rã8—°1{@‹t¸ã¾µš¯Å¬í®ˆ%ão…}Ó%„CÔÌÈþ®˜l,ŒÎ$a×{C÷<ž=ÖÅI¡Û ÚÚOèM½ÆƒÇ…\“¾ó`³fŠf¬ ]øò¿ 0“eè—¶8‚/!o<žàíåhºî··!ðFðà'îyœ„ûRMµ*>¬¡½üŸøT¨Íw<°õ3­²@l¼`2šG¨1XR>js!?†¿œ¼ÅŠÜÔ[?‰™4º…)0*ßìUÁF!µ-ÀgÂó;à fÏp±£Lž<ú=@²Õ©Šã$1K§õÐðu®2ä.Žö†ÖøŒ®£o—Îx bÚ2·Hã¤:g8#UÞ™+ƒ¡5Yf‹Í‰rþד—~‡Ÿ +xÂf¯×i¬Gt6I hs‰=Í ë˜·áæ#™ObÔ^PÙ»wT  å½» |X EÉçÞ úÿNælŸ÷fÈ­r-m×ëRpÄgR2®éŒfûU Ž¾Ù äÕo6¶€³×jkž)jµnZ!BFƵÌI¾ —*Hóåý®b„÷ ”·_¼Ù¨:ð²¤d—ˆÜÞrÆñØ&ê} ÅìüÒ…ˆîZ‚[„¢ ’Vf’iæS÷ÝûšAIØÛ0\c w™Nø¼zÇê–¯D92¶”tmÔ Ähk!oด­9EqJ Lv/ø'/<ç"q”çÊ-5¦{ìæc¼Q‘$P.v? â•!Ç˸­’’€€¹yÞ<·y“BS8ŸÀºÂÌ"W‹I}I¡BƒÖ…¨¨õôòvE9üBã ÇÚ¼Jw‰ò /»0ž5ï<_•Ô P$õ'ÙÓ$ÙD¡f>df˜áÄ÷3>á!aûAÿ–~x§¡x¥§šæÌE”;íÛ¤ÿ–èn<$iå&ÈÆË ÆwªüöØïó·(gèvÌ«¶Â}Y`¨ôÑnÕšm¡ůp©_nw/õÎÇý‚#>qË sñ9gÁ°¾ðdÁŒM?ž"â9ãåÝ’ƒò³ ´÷<ê^ZèhiÝANåê Îȸ¨j”öI©HÃê!=C,fôIÝ „É]ë¦bCÉÒ† ÆX¿ü„IìºoqXE¿bs“>_YÛßoÉf¦Ì˜£¨Îú1š!I[’cè*陽ÍwKPë¼ê @ù8`Lïxµ4W¡.³ ÅÑ—å¶¥³r[:”²›¹ˆ2•óG¢ö-cq'çC5i 7Ê8Í-¢då±¼o¿š~-…é£ïô8Ÿv¼!‹H%Â}4Ųåt†ø°tc½$SÍõN‘±êBÚŸ ®µ¦‰E•î´èLƒ}Cƒnç·i{Y›6 $ö=Ë)×ö.9!Y^ æâZÁ[ûa¯ $0•O'ñ•öÎ5ôÿ üBV^N^¥„’Éð]Ó‹šÈÒžu?ÎûP\ÇwC8‘´Þ}Âð[4î–ú áW ÃlÆ–ºÄÌ8¿Q­®¼ªéVoSh.̶*¦j”)ú¸ªBRx–qîöìDtFLŽú?©Ãà@®ä¡*îÌ3Ùy ѼîåíÆÊbÃûÓw³ÅÄäƒÅÍÖSטÔÇôØæ³i ÓÜ2$+ëH5é_ü3«:5Ÿz]Ä$“û‘-©,ÈK[Cåú%¡ýkñdN6‚Æe 2C·ªÊZ|Ò5&~îh¥€Üvºû£ËuPñB9è¸{ýk0aôªfù8œ1öAÃŒ±p/a­Z´ÕÒošÀ!Ù n¾ƒí)`0:’ÃÛ\-‰¶ÏÃÿ÷”0gëEBžf„YAuÚ-üC \êL¢4b«¸ ¿ž¦Há¬Ý3öêÚ¹h¥ú”W5gv·àÆI |<[Ñ\ú ‘È&<Àžìy_íæ>ð‡¼Æýd“{|ªýì’€€Ös-kÇ„T&‘®zô³c¥ýe øEÞgæ'B ƒ$‘ë“‘ô/1,)©É •€t|ƒ8û•N]Žr¯Q„þa½Á?|,W ynKHă8G³Ía¯Šá<´½ózÆÙQ^áQÎÙzA}•NXoì@ß ­¥ày¯ã|ð*Öqu*­7æóÿFoSy[)ßž8;µ£9Áý [H\¥ã?…Æ|éË$ÇÞµ¦o–TxrÙeF~­˜ Ÿy©¶r8»¢ºôZtš÷·ßP!ÀÅ[”´ì}ûp^­o”èTéyNí-‘þ¤®é›&¶n,¸é2¹)˜õ2:W C ˜ð6l×Eà~Ò>|²Yx BѨ ÄÜDÛò"+1â© (÷Œ&­i 27Fnn0œî¿ëƒ/iGJÐõ#êi–ØkÏ”¬C}“9Ší—²qpž- ‚3ë?Hñ»MóÞóxÁ¨OïU~ç·òeù¸²€Œþ8@eî\xÍì ˜ŸÎŽZX]ÜåVkE½>)IÍG&Åõ—°RÌ_‚èjìƒHëÐ~¯Ü²A¶Q?~ó¹âéqÖ™‰›ër"È%dw5Á¡óFüçOŸyY…sfî ð¶Cž)oV~]NYÐÑdX ƒ6‚7æCÛˆDËÙvõ ­‚ï)ÿ;@o¬¼kÙóäé_ă\¢)šò„e՚͟‹5ò‚î9»·ücêŠê2>‹•`]l]Ëæ­,»‡h¾‰?(Z!L­è/4 ÷ÉÁv\7n»ýzŸx!=· ³”=á šJ„vàÔZ±t]ÑäOÇûà÷@]#áÒ–ò <ø0¾ ¼& µÞûY/YkAf°åx{ŒkÛÙï ܯ;5dˆÊyÙæQ´-‹%àé±.¶6Ï%1ôôñÅÀ½ñw| ‡§bCŒ+}Ÿ‘™Á°AË™¿@õ!ž¹»8„ž|­®‘Óž–ÜqšX[Ÿ*I:§7Í:åh $kðÜøÁ65Ê©©0Ö¼®™ŸŽØ¼R;Œ.ÄîI>¨?*Eæý˜hd{Ê<‹‚d&Úµ­ÓžÒ™É§Ì%¥áœ{Å;òé0ËœÑúò¢ R?¾ß'ÌJŽá{Þ÷8ì:l ™tï¶«Ý=¤$¶ñ‘éÜ*ðU,µË÷‚i¸}¾ÔUJ¡ ,ÃÀ dØöÄ£&¡á˜ô÷ í$£ø!„¬#]&·P•ë¤CôeË¢%Ø…ÌØ¾ñÖ®g ¯ŸS=º¥ãÀާ ôoÖˆ‹·9>ÈI½½Hû¿Ô?‰ž´‹¶Ã×Î×ÿ(‰%¨r`•ÈQ‡·•Å­orˆ;X•;¿2Éœ¸Úh&ü€53Rä‚Å&cΨ-Żġ•3øë$#-QÖ­ G ^¡1QË>CF±§¼º£ç:DºÌ¥ Ä)oaþÍŸß›žù=Óý¥ ±X³p\¯óµ5EÛ&ùzA;^ÎÓsô~ñ"qæá8šF@’€€¶, ¯ŠÕBl)9ߟƒÎõnƒØê2aªÃÂGÁî-|vúÃ8íœÜrðï` «ŽDžbõÅ›þ^EêÝLzþíqüΈ±/°<œ›ždÖûyûñŸŠÖÞÇäJ p\ÁÛˆßi0ëMÀšÛ«d+>)Â*xfÅŒ‡€æFß!0Ç_ÇàÌî¨Úöˆ¤‘@ÿLI¤^3¿¯"É¿7¬è}ŽÔõ~Î/¢\¸¡ Ã?›ÂÊ×HýÙ2íFò¤¢ÁE1›Þ¯èCWuRd¦¿¸™Ñ¯”3°”WŒ[b{^IsOáAð…Û%2W|–¢lå‹ÌëEί¨L¾ˆMÎXÍV5gôÙ¹{#"«ò” ²üÝ$qþV §‰7‹Ùe| !ù¡þ‹$Ëù=ü¿_ÆÙÊq­"¿rÞB%œ”zd¦[jìé–Û©&dÆè´óUmóÈ8ĵÉçà°Õÿ°—ü6käU>[*“O’&í›U›è=‚êhð+Üœ¡-uüÔyÈÃùu‰›ˆî0=ÈHSP©¯´7=[˜¬Aµí”»JtfÓ`)î~ÚÆ|v­ìÚÍŠ¢çrÄ娵e¥p-À‹Æµ£ 3`„N›øŽèO¥9…Ô[3†Ÿ G­×äF1~iGò꓌g¤wáBÁ„Áãø‰unŠHW6ET,Dþ…¾jg.Ê®y¥¬%bQþ­‰£·D–ÚN馌§à›w"ÈkX•¨h‘_^̤x­?JnéÝ—“yA>£-v®?¡Õ„t¿ã~C„‰Î“Eà‚‹çéw=бd½é©^&9*ÿÛÉIÌ‘ù“ˆ¾÷CåôˆßEK5ºFé( Þ&5Þÿë­%xH0PBqéÛ9tKs(õ4N”ß‚¢Œ¿Ž<$™»lc¬¿ä¹.öÅ8Æ×¼²·Ï³<%´_zºC|À¨ˆé¡ŸpÒi)%çx[SB|Ä>ˆM8î­\7 g£(íë¾mÚ€²qM¾…«u„dâ”HòBÁ°™„¤žCŠ›ÀiÊÇç¨ ·.§V¤Ð¤ùLgÔØí=ݽÌÞ+CiÏ/Žx.cÈ6ê«Å´¬2qQ-UILTÄš¿WêHä¥uÄàñu˜è¼186Ø%Ч÷‚€«‡ž”’€€»Q§¥²Vˆ òÎþÜ”û¨1OîlŒàiA˜D³H0[cëKðÁþ"ŽœžM›V>*GV±×WÂYwª$eˆp)ÔiV×ë`®„"wKêü«ÇíàÌN¬/O²3||³ñï±¢JÌeñH¨‹µÁ§&3†oŠ`À‰õG ®7šƒÂƒJ R—J¹Ê/ñßYdˆ*ÒqëÙUjp"8C$ÐÒÿÿ9mÌÈ@F;1¦n~] 09=á3D*l¢©HlõB°áU´Gqò^{m·ÎÌèý5æ~+¡º*ã°f†¥”ƒ©ôx F"FL©(\з¿½$#²ü±ºVIù%æ¯=©é¸´nVwêRð¬èxÀÚàŠ²Ýn]×öÎYjgƒjXÆöÜŽ¿Ï• ¬b£Úô®­Á>üF"± &ÿä·špŠo-/2þK ƒ¡ñ@Dp’0 T–¿1‚@7Šù óÞ7!¹‘¹lýpøxÐ$ôçŠÅÍ£†ir?4œ¨RÐÒÈþƒs:ª?áCôkÉ+¹Òø¤–(’iQí×RzD™êö6`<ùËÕî*Šìk÷õÆA%/z³‹zͯż±¯9WtªFg謟DvyMÊúu¹% -­ZÉÛPÞè!¸³ãÄ‘æƒù^Ÿ9jÑæýá,°3IñÁc6‚³žTªßø»]@©ý¬9ZM”Vp ‚£Àë‚®öºÛ9è=6‹p,j(kªe *c‰·ðiÊFwý£X[¯7/¯êð­RH—__V«uc@£uœÇqŒ·æ\q²x>À¤ö훯Ó¿Ð"08€%'ƒÕÛÂ}:NÃ/HÄyë+«ü}lNÒTL„Aª°Ì`ÀޏM†—ä6tsa;uu³¼[׊šŸ¶ñš\»PÙHçcs ±Ò²œr4Í ‚Sh®óÙ…'ò²°†‰BX—>‡=¼»ZFWéƒA1k“pJý”XˆÞmUGêÍxú÷5R©‰µ©õ¨:Úz86ìIa†Æ(§GC'×(;h d½ß|”ìןD¶´26Ÿû‚Dû"UñTæð=œ¾ç©còíF$ã_ÐZ±ðÔ=;õl èw–õøLyjZE.VM™ÏÓ×ß}¸ã[@Ú¸âGæÜ’€€•¹¯a?v:"X<þmŸìã]®t ƒ‹¤múp /‡åëáXÒH«1‚¡f#Z,µ¾ÑžG+-TDZeŒ…ÃÝ ã"ø uÚ±ÉAm´=gyö3G˜²ìl‡V?åï÷?ÔDR8¨¢„Àr_u[Ç'v¸¾Þ…ß¶Y˜u+šõÏÅí&ä)ã('ý*½QMÎ Zº‚cýö'°×«:šs¬å…@x8Ïœ± Êu„Op©QG&6 ¬!·1xgɵ [-P·ÿ%öcå+¸9ƒbfæ„ß:b³lêhXˆxG0Íéø5×ø‘cìq×ràO.Q:¯SBYë¡ò„Ê<ƒ£–E<jÂãð@*…)‘×Ç ˜°pèPz‰ÐBªÃÌÊÈÄY·¡ö‰Ó'£Vkd¯)⯤I†Ã±çÊì†G@½Â¦!wL@¾îŸ›ËE Eÿ Âä8¤ Ⱦ.,qö'ÐïE]ÃÎðÊ7#÷ø¨Ð6¹Lõuh Ô<²Ï—R/æ™hí:¢Ìà85;íyáè~:EÒ4S‘£ ”gI䟘‹Lœ‹Ô_«Ì-7I&Sîîž\Ì Q,Â5#ik‰½æô4‰ÀMǬ²ðÈ©°¤ºåªƒAK•Hï†ß AÄYdyê`¡¹s¡¤g hðÁ7¦ÄÅY“mE–gÍ7#e¼“D?˜Ïôj´($Ì€W"åw"ÚŠS¤¶ÿT.¥Jµ Ê!Ÿ¯eí7$kúÓâ{ƹrDÖð'A[Ÿìbâ/Úo¨²oa逤±<Qàš rᦢämHTÓkñ˜îÿ² „1…2"¸] þÈV˜tn„ §Âñˆ2¤ÂÜãÈX‰«Øãï8;dM1‡O ù]*í˜i™ÕÏ—6åuÈg_œz!$¨Io…j\¸¬p3‘4Î5Í>0’®ÖÔ¿üÚÁƒè¶ršÃßç0*ïÅ :E;IP忼?u)W»pú5¼–6ï6AÝœx!i+» ¤6üКz#›ïD~ïöo8pÚ£5'L¢ Â8ê)·Ï»:Ù¡2´$Š)­cÜèÂç,ˆÖP9±Š& e]©Ç8¡Ý™@´âC÷ã!›B dÀGß7ÿ/}SäÎü50ׯ€ M^Ým•)mãä§®w惼§0áA‡"ŒÐ’€€ÍâÑ$ÎxµÆÝQ¸Ömo–õuÁ…´d­+ ID#:{þÍ]ñŠc¡Ê  )»ÊÅ€d¹GÄ×Ko¢ò7èuq<ý’˜Uˆƒ5…~ânü½3Ž>Ûa¯°1Mo¡mÂÔô£¯<¤q¬œK&|C™‰OÍG_32óU,ƒ­ì:õA’%·<¼©â´ÍÍî.[V&dÙ{U@KÐÛ=D²Ôºþ™²Ê ]I(b6BŽl¾Xþ¢#óò›#ˆ3ÌHóüö¸¥“fŽSÁv¤Ì2åÎ6¼t¢Í;î+LT›Í¹Æb Õb<¸EËe"ä·›ø‹lt”¸>ú¸'œ 5ä{KIÞLâU¦ë lXÃëë5^ûÅ­‘2±Âàb¼Sà§E‘£”sítwh-ð\fðãPùMøeÛgšÌÈñY'Ê ìkôÙƒà¾ó=šaû-/Å#˜"´<ñ¼.جì¹vˆ”%¼ë`0íKëÕÇ„Ý5h"#9WßdD0.óšB!µ …|‚°Æ˜ÙìXŒiÒŽ®;¼!ÝØÂ Ú LT cЮ:ýbA«|¡ä«¨,²IÛÇ÷ߤ›¶,H ‰>WšÔ?^í_%ê+:Êñ;DoAú€4„õ;N(^´Ê:M|I7­Ê V[¨(ŠÇED¬ïHûmãŽUæXŸºÅÿšªìyÎȲ¬€ƒt©Ñ¥p ­ˆãŽìA\™ž2C°\º>’€²ur"—ªo $nQ2B— Ñ͆/edå)·‰?XU>Te‚…VñeÇýUñà|…ÏYL@±waÝèf¡T=àÕ’5å +Ôͪ%÷>s'å"¨ Xµ/‚yFÕÒüpp%º`o;²Ô-•‹þaª³Ôƒ<—¾c‘`äïÑ—HBB”P!8§£ú{2õê7m’½}©sŸ3š“P¿­ÒÅN bÀa\š¥¹3€…D~wsøn±ËÕÂÉaéÌ-T¢Oè[Øj* øò¸»ð–ÈvØà¥ç5³•'ú9 š=ª Fˆö£–³ªú ¹o£8…°\îÇ6çY¥e\Aûvi¢‚+ô³VäµAˆ4ýê2w †Šâå\]3´Dôª¹¿§­ HáV'O¿`ƒ´”?»n5àÌè‘’„N ÎM#\dµ¯v& 8À&’€€Ã–·d¶=l¢Xv¸°Û´½%ý wqnŠšÙþžª¶­“ö«h |îà­¿¥¸Ü'Á¶p¨»RÞ­Á΃>(«lgß‹IDdž|+ØËçf8pkŸQïYúûUÓ¥ÃÞbŽ=Ý M·¶D·éÃFÓïéSüUfËZ¸A{Õrl'ZJMš¹a<Ó(ˆÔ>…DjÄb1*†–ŽVë°C÷"<€x’«¼îXE|Kz¬M—ƒËû’¤ž}íDŽ1„›çF¹-³m9wj)>nÑqÔJ®Æ}®†UÎV*!È/~øY¼¹ %âW$¥ÄšO¦êÃÚ®¸Üs_!våòRß骜U6%g'AUÍ:(ÐÜaßC-å^ü6Š´¼õ!;ÄÞÖ“Wë“~Õ…|æåÔéN;«[ðå0)²ÉŒ+û¾‚`À¡ÿirß „7´×ò¤Æ»í3ìÌ;´î§wü8ÀìÇ8U,÷b3HÜðEmÃbB„+f1DÿfÑL;wœ`ÁñßÕêR":ž(s«b¯²é‰4Ø­ôàBfZú?'´Å¨}@ ›ë¬5û]“½-];Rÿv¯Œn/>tãn¿¥]ÔŸùÅúž–Šy²Â£‹3»6L؈2gë@.ïOG¡ƒjâ+nàs¿°îÆÐ¨Iଘy-Ü?ñªäµw­:eºa¨ÓòéGpŒU¡ð{Z(ä8÷qŽÃQüR‡OŠƒ…“ÿ7R­x»^,— Îò7ܘA¿õ«ÁÄMtÏ“3‹†„¢½©¿6%^(1K ô"tÔËÓ.Ì6¾ù´(¾í‹ÐÎð ßlEìDÓ¸…*‚¹ÎêxF[x„5~L§âDÿ1P“¥lV@ ³E¶âfëg#ÏÚKžî9"0ûjHôþ@3àmlŸž?Òfaì¼À¹6õEt‚Ä&ÞˆE)#‰2©´Öç!­J[$Ë‚8å}W:’ˆp^-Î֜ħИ±×•»ô V g^}•ê§öbÊ9ˆCZMØ|ϱûk´ÝÞ֡ᢤŸžrpDÄøº°œåN˹x• fR‚ø°7ã¦éÖh¾¯[£‡¶·!‡|¢UCj˰¶ŠCz³êÄGné“(ïþ~ˆÛÕ»£IćQX0’€€¨±–®ÅùW]hÙçf±Ê»ïy$1îž×®vXG ]õSÙe©~/«pk¯pÁ4ŸñÔãÈ㯴8äQ1Ãû´ ëºøI ƒÊÍ5wT ¨6<*dn(p/…ìwXd˜*Q,i¾'¥ƒæ€TÅh92”•äÏ©ú&M›šÇkÅ{?ŒÈµ¶ýeoE^S$V9ðŸ×`u£¾k¬ÜVŠë¯¦ð,Ö¾£×!¤íÝÊ“R`Œ)³%$[hýÄt·KòÒS9µ Ûž±ÈĆßB5®òç¾™VÇak¥ŒÂY^áÉ+/µI‘Ñ(‡äѺ§RÓÁ¯™aÆXÙÈ1œôõh§•ô|Âß:\*ÿ1uÂB{£ÃùnšSµQùÖ)<ÿ­ ökÌ&!Ÿ;‚É+~pEçAÁ}ÒQ½=·”NÍÑ =ú „l×’ÃчyeGqµD Qåk}a¡ €Õt;0Ÿ¦ãéATæqÙE•¦wq’ÍE8.JÑÍaÆ¡r°ÍÅÆõµù‘{c”Ë’Þ·Ko@ÜW¿ÓS_’BZb¼(Q”[—~´aèœrO˜¨÷Á&Ú:1ÊÝŽ[ÆT#T(u§g§¤!Ÿ¸¿E`ü#”£ÂÓoaÞþ¡•rŒé,‚jÙ÷„r,ÙF×Û°ŒŒ’€€—‡9FêÉRXLu+€²•G21+•Hç¿D•?’ôú÷f%+Uk lŸð´ÑNê ~¢d㯾.T;UWóP¬úÏp_OÚõ‚7׺€lTöÐzœŒ÷iŸ˜U0ñ‘iswg(­m¤U7Ñ‹ÂAÙü§œ3‹Ã2‚"ØšÚÌs՟ü¸B‹wã¹úQ?AºP¬Œó¦“€up´¹8²q’²Jã5Ši«‡‘<ß&ÿg%²Š2ž¹éÒ`D -+´\µ0za™¿a´'âMcËð‚Ì ¤æ-š6Ú/ª²-Mß­ÍÙÒò«¡¢3|_ÃåÍ'Y›ƒôkè~iÃr.½Ðß!mz.C;žØa:MËàd!ãBê “bµ™àÞË#9´ 7t°šýݤnÔò3:Æ ´“…%¹(ø‹˜íΞ"oÔMÈï@ÎÏdãô€';û*‡ôJ÷ \åte)N£©Q„»ø‹°Tåiü;¥W ¬"H­þº`â÷ž_%e€aZvk¹y_ qrøM𒟹wé½g¹=`R’ (Gz¼§å†*j)\àÇóùÕ®³ð‚4ÕÚÜdZ>Cˆ1ŽÖÄ`~‰+é+쥉Fl¢‰Ó¢0ÕšÁ$jßrà=±|ÜýáÆ{~›Ù¨Üâ_ H1Ô}g0©OÿéT| n¤a}Úll-!W¿z]Ýöà[Goù)¡Ú%ÎÈ2m…O9]@ùéJsá(R/æ ãVÙî×<Ù¾e³G…ÔS™ è$Å4äKÚ¹IƒiI3µÁä ÁóÝÑ ÒÆ¶º#&Õ™&oeÜTþ]sRœ²ßõîrjô¦ÞýÁN¢[ö“Ô$å>Yó ÐOõÅPO4”¢lÞ¨8qÀøFý¤ó–U½¦ˆR§ô§Ðr¤FÿšN@¼7Éìðv÷r³¾=xÑ?ÝÞÅ]÷‰Pr¡å%³’€€¿áMež‘øD(bÀŸâ‡.šÚš›-j7S´¿ˆM­h!«³?ûz›®ÿ¨Œ8•\EG˜ESR}ŠÂ\/ÕÜ´!xZh²¯¤|7=8ýܯC¡“b-gƒ¯UxkqÕ&¤ ¥™}zÞ-»g7ØÃìÜÀ<>„a®|˜ƒáC‡É* õYU|ŠþS>@:0£=1*Æy8Dºø)¬ÙÜwóŽîaÖÈ[ °^¨Õ” ÿѪPzvŠUðóMl)Þ_“Q‡°yûtFÈÑöh HS0îOz2@T»(#šØA×gw HÝyã•ãœç—±÷ííéÈ®bPLìøý;­k—Õ,°ÄêÜÉÐÁÒGP9â—½B8k¸‹ÅRr*ÿƒ–øq¡¶õ<\±ÇË1˜ap[L¬º¬ÃL·ûöÞÕ"cðCùG*œ 8/\˜bÍÉ3£m  Á6ÿ°Hç+l+Œ“Š”|X!<²Üóž’¹÷Q²´ÂŤ‚‰µx0(TyB ‚ì¨~èÏÓÞO[ÜY‹Ëviy_æÙ&E;¢k¥£.ye¼«1q`}cN¨*è©Ág9m$¶Ïi]àÓøß•ó¦ydŽõ¾­Ø±] Æö¹¶+ÎZN†&@[V“4²%ŒÕÕTøƒä8¸Lv/(Ù¦fÓ‡R%‰øÃr Ä×%pÅ/{áž5Naô ×ýÿ”g»¥jÕ”.Õ¥èD"jý¶†{!['™S<¯œ¨$ñÇvp²sd$¢ â>è8ÒV©AS@B„v#ɾO!Ù!² NÀtÐ4i¼ÑrD9á‰êßþAÎÔ^^H%*ìRoå± ç^7½Åv=èO]Ò)¾·Í’ð.s´‰4tÝÄr§ç˜Öé ¥¥›‹Â õ¦¿ÐÄ3½©?pÙx4°/ä6ÒǘË ~[úE±¤°·ýÒFu‹T62€$×2‰ø(ÔÙr&]áדŠò”„Až>°ÒÏσ¬Yèôûg²_ •– :9v‰šbw™ÜJlù$Êã2Lj˜£è\‡JÉ—45ƺÓ=„1hóˆvèˆ{7ÒôŒNÉDhôÏæüaÐUñÊ*2× eÈÕ‹ù.)±…ŠzmòŽ’i§×fPë¤X¯äm Õï¸\æçËb¥i—'Û¦æ»ÏS ’’ˆËêÙ¤ÆK’€€«½úÂ#]jJƒ9•‡×—£\€³@ÍíH¹¿‚¦Â³yi M”ç-wÆç”£I {oý–îzw%ó!²åÄ;¯¾tÀr*&.¦ü?²¶’ˆï fM}DÖ¥bn‰èª=t÷öã’þöœ"†ÓkCÿÝ*aÖ®«î€. >„7ðgKëz¯q|ënI¨Æ SL¥fs·”‚ŒrÐÃ|;-…ó“¨B~?DXœãf© ƒÍs›öþÜ'=ÐTÆ_H„<«F$*]7øwS3¸Çüízš&3ƒ^ôý BE¨?:IëÐ2g‘w³Œ€µ¤ ê|ÜbîAGøB‰R !b°GªÏh—,3[fªóa0>IêØ¿ÑdVFÙB(QeþCÍà Ûôe¬:=áË…ò$¡”«ÈrÈOe’ôiþ>%J I pýEílIÔâ·q ¦Q ±æ/küí…FQ÷Ü©óÍstB‰¨Þ£TýX,†—YåJµéçêµÍxhƒhî.FJAr¶Äš¨÷°}[¾ÛSªþÕÉÉêæVdêF¤Ê ç€^áTOĘ„ÝËsý>xR"j ÛùÚF’:ÆÂŒ»ü4±Æy»¬|E¾HÞ^“–˜Ìn¶¤$ãLíÊù*Õãl[ü¡Vbƒ„ìÔ­Î~r Õ|:ž+^0ñEÅÑEð苌¦ºEU«ÊijvÉ ZéaªHOjÓ‘ßv+UÃ;æÉû´L¹ajsØ„ãdm[9ÇÝÿQmVíÅ ´ËD†@¥ãþ©_L)7XõžŒ"8šýeSºrWC‚ÒÓHçõ=¦—Ó¦Çü·‹ßtþ¯%-cˆŒ@þÒ1ù$Q1厘¬°•Cç‚tЯ}¤‚±•4µ–O<¥<œcL)Àücú´ÉcÀ_üUùTgoHxmQ­ÛåÀÙìA6û–ÎÔÅ„NÔHˆ¢uãuÛ‘öé|¾Q‚Ų͓¢ƒ,Íp‹±©\Vœñ³Ì$ÜšG\*[²jçc¸Y.J¦§ÜôwÈ1WHÇÌ}°Y׋ɀ>òOD³QGš6p•­[+é’€€¿½[‰7•o®3"A&øØ|`Û>»g[°Ä;tqe¿'KÉ À+é">ž’àL‹,!S¸žÖIš½U>[nw`q3ÐIàåt6èùqÚq.øÅi†ö«6m*¬€tõ\!ÃMQ’D52#Žõ• Z‚r`(sü&Ih»,s6µkÔ”è]ò¬<‡g%.]C<0Œø—ÑÚ#)OÕk¥¥¢ï‡¾"àVø~F:…¾çÊ®³wK8 pw’"¹cè÷§—ãK˜¡]qE ‡ HpûÔŸ7¿ü™*XboIïä–€Ó ^¼{•í¦Ýb¡‚ƒ6÷@X/Kƒ¢Ë¥ƒú†³µˆKHo’a*êÀh»Î¹Õt*^¤Õßáz²a‘7ÊÈYãj© ¼¾Ñã^]¢I–âWcn@$òÏ>˜o~ÑãêÁ¾`ƒŽþ /‰A_{4Ë…h/"£Î6-–]†l»H¡„¨à{ Ÿ\ÔÆ>ø±9Í’¡µ\ Áz£AuKÆD@~ •³cø‚ï’€€Á?)2‹¬Ÿpˆ¹©†w\å6‚ÍC¶Ñ¨Y2dèÓýZq:…Ï5©`‹îqÝ\ÔyC$Åb‹?ò~MÆ\ì Ì…£xî¢ʰè62¸R­Éyká’S“yV…a¢² ÓMj’‡~ ×µ›ff*#!gœ]¾,CßÑ"™QAnq qdür%ç“ì‚™YžAŠGMËÚz˜ÂPæ{ÿ¸ß'cF® T%±MÌî*’:t!áþʱJ%´°Ë»ùö ã¦ÎZ ƒ{•AÏÚ ìµI#éü´³ÚËø_Lº$ú˜1ªw¢òïåX2ʃBI®Çš‡ÞCE ˜I¨]+÷“ÚÂ/õ᪤¯P Ü ÚW^Øêë ùBœ7su",–>ÒU„` ·/¿eB§‹]ÁˆÛ”&n wéË¡ÐYCÕúHÊd%fkѽ«3´b?Âg~±·‚ Äk¾Tû½Y{§Þ} 2/»7÷Jð1Õ¥|´°º_•|c€Õ,wøÂQ¢¯ßõæ˜w­¯K´ÔëeJ\› -ý硹VEçxïÆ-aQfÅÞKÆ{÷JÜ+’G“áÃô.„‚ap/ÚÔÃÝ׸ƈ›7^ù[¸ Óðp£   ÔÂ?8!ðë)•I“÷иЭ×ûnäE·ÈBß¶+ùî<²g0¬6$¬[`$…Œçô®øM¬2Co‰¥Wb鸃®£dTº#¦ímmŸElÚ†Úˆ5Õ}‘xAqèéÐ¥ȨpŠ5ä~ÇQ¼¢’2#Z²HpùT¦í¢Ò™D~¯ºG3IùޱðÇÖÊõ„«ï<Ì´FðId‰Ê…½Äùϧ¸¯ºŸ'àö áõ_–Îü X'³­1‰¬øXzT9— Økȧ›;6Ò6.OË,íW¿œìâ¥{ìé4…ÔxMŽ\þ6!O“â½O'Ó‹%ý5X†g0ÙˆÁ5 öçÎŒ2 !‘ÜûøàÄX*gr Âñuäž©Ÿˆñˆ5%­‡ÏIŠÚy­)Ø~„æÛì£q”¼8Ñ^œ û.ÿ±1½¿7 B1ŒUÕåþ®6<Ϋ/“ËÌ¿hö›Ð »ï}ÙÔ‘i#k–æéFºjh¸f¿ÝžÆža ¿ÐŸ³ogÚXümC¥S†È‹óãå!},Êø\È'‹êÓ Eþ\þç =Pw ºàw(ÃS´ò?4–Ó8‚'á…šk™«ƒº8¸MæºÚsŒz@F†s=Ìz!õ隯{¯dL%uªç!õ’ùþrñ-˜FJii@Ô`¯V“z°:Àþ'ØñS ?VŒ¼‡,ñhŸ,?Bö"™dD;0ØÇ:m–ìD¦tfTpO±¶@ö¤+uß„eÕQ/»çâ^o›Ú)~¬`"T4Å%êóï„/í­düi£ÎB2Ë2Ð/À¯ÎÑóÏ17zÓYh±Aì+K ·ØñU—dLµë°O}i™ÎÈ*‘zìYð Ë‘Rnt*À# yöITÓ£»’Q  ¢€uqBÌ£*¢{þÀôª9Ḁ&ß1—¾n0êö;‡¢q0íÔ‡ì+’dÉ}*]shàäæ +’,ébà"öçôp $hƮ췛¯jw¿Ái™°Åt`œvshDÑýK© 4tâŽÿ+d§ƒ¾Ì#‰‘K»y~ûǤn{ÞMúd¾CVà[tÍL]'K)Ê©,!þ*wh•]ñß¦Ç ~¸`vdº=?Ì8bLj[½#cÙ#'GñýÇÛ(ß{E€>ÓÃ…1“!ù‰•´ŸñÅ$5?sÃõ8Çà=f€íô…aE‚oÁö\}6Í›ø\ÊåTûÈä’ÉNXˆ#ž«¢í’€€ØË°XÅÛ a–Ë"ŸŒW^)TÁÜO¨[ÅÈÑi‡ÛÜqó•EjÌ_˜"ÒÙ]xö+ó.š}¬’(N”@ÄiÄu`Ææ¡B~³+Ôi·YÚÖèÎ) ÕCþ aoÀûW›%[(Õ@#éµ}3MŽf\ j?ûÈÎs qu[¹U9+œîz«øF&yljE1žÊ×Bo>îVVøQ§ß]x =@†~›ƒ[Ĥæ:¢ N°› 6 ë%ir'€2#݇h†n“ØnûQ§Â£_ ²ý3³ÆäŒUÀ4XŽOæfë‰c…±ímÖhŸnÿ‹äW‹‰³HÕíey9΢4 àzÕv  Ûg÷´–wròÒØQ X’ Φ¿ôÕÛS  „aë•3åüÚH\Û4;ãp1 …Á§@Btï’3Jü+Çe½ “©åY’ pê¾Ï«nÄ>üÀ”°ù̲6ôå•§9¬–ï¦0Ó R«ÏõFFÉsÔ ÜRðiÃ[\ØŽ(¤"ÍpÏÖ—¤uQE5Ѐ‡¬Å:Á•=€Î]—ˆö¥»Á¡ìD£)dòõ»é§¨RyU\×ìúi Is¼€žÏkú†ˆ5)5c:*ÙJëB"åõSʪ«f‰€±DW•¾uÕùÙÝ_/ˆå`"ÁÙòÌ+˜Y¨j¿%Ã7õNõ«¡ˆ:AÖjæ¼åj-rRç9âMãfX?Œë#BX ±lUJÍ‚Wù=èbÕ‚³ÁD«ÿ{òuø[Ä+ƒ®uxÛÐDéµ  Vªn¡Öˆ’„i¤ž”sàœ¤Š¡AžhIBS)kd·|ý~¤´X™àÚ‰cVíå1˜t2gwiâ>˜¸•Muߨd *º¦¼öÎ3Æèטëýw±°ük íºÕ’Z5ó¼:hør š»æp2 ¾Yø¿s‹Ú¼á×m°) ϶\.Ê£)™ü2謜9‘ü“»ÿ•œU]Ÿ5K¬¤÷HŒyîö”ÐÎ Å™ˆgCÓ× qÆ Œhr?D\|œ%Ûõ༑¡p¾¤ Ã:û¦ŽÞ†Ï¹[© ¿·Oû ñûâXÛ¢:O9¨møø!Yâ¦èËF˜.çHÙØÝ±†¯!o©Î+ÇY¾¶½LQJ`<ûØ‚µœB£ÂY0-õ+ÄWkh ´“Ö²©&‰’€€§{^G­ÙðfF`*ÅšÁƒ†‚ #';·g!Cœ¸1“Ëü¤Dhä¨)§s;ýFö¦Ë³üÏhçÀY©)Yɼ­Î ÔR·l!þTÊg\i­c~Vž\‰8)æÕ늻âcˆ¯bR4 Ù¦MNŽ Ç‚#i€” •õ.çúÚŒS´)/nÈü–…Ê;&$YP5SA®ŠÜ ˜=pl‚#Hƒóo^d¥£¤ÙâÇí}Á]'#¯¢wøÄ' W€ ÐóÏV`‡I([váåዦ«ÀGÄT²Ü2¸Ë¡¬p£¨H±sd4Çó6¿qž¶ãÔ>þ¼Q³ÇEƒ0¥XB_’vÖpØÂéÇì KôÿO^ÖTÀ$M(¥z=·vå.RâÉþÊÖèE¡¡˜Ê€7KÛÆž’°¯”Ñë5ÏÕY¹Ä6»„c{Ägpœ@Ë2ÚM.Yýbcf &·õEÒg‡  qhœCðrÖÐù*áŒVR ú„¨†eŒ-%ð‹Ì@ÅCÕ*íPK®G•gû7n´ˆr„aÒlÇ”q½ƒè(}%œñA¶_k%¤~UZÉ‹Ýì Ÿc©0¯¹dŒš²¿"+fÈ/œ~«J€c<À²r\»pÝåáÓ«J[•-…×›öJZ©ÌWIÝ·À¶Œ9ˆlC÷SõE' {JzºB‰ŠvÆO£˜Î¸ à,õO>`á)¥È!|q.ÿZ,åƒ6ßt®­4OÌmš$|Ëõ…Ë—2Ô§)æ’€€§¼åÝÝŒûÒh¤¡*'é‚_T•æ÷py·GÝŠSGÆÊ^ù{õ¦ºÄaÛ:, ˆÇ 5wøì>xµ¾+(Ã,‰+áƒ×„ωá qÁeìŠKÊsñ‘|zNðؼm •ŽMaû2ÜReG3MÌý¬j©zñi¬þÌèC&Ge§én»PÑæó]U4«ºôÑ?â"î1v€ëw’Ù»áRº7¸ZëøÉ‘'Å3²Å×dV7c¹rÒ§\}&ÉL,mØBkäi1B˜åÈP³æ×Ô(eõÿ@öóݬ½O–9Ç©§PQ””òhÓ68=-Fm›ü´ª`¸ÑKÌv4QÓMÑ’‰x>_éà°"ÜzFà¦MúŠ˜Ðmß  r=€(½z{!§ù*Ü{‰[v©fÒÑ›Çp>n’þ^ôÇÎG2n šUÂÔE›. ÿÆÛᔜ¿å•,Êø Ì ìg”w{šZÐQè‰îÇ’ ëj¿rŸPÒ°ßg]awÀ°Õøôð¹NÎæbªx™»œ}*bŸ’WÄ+IÚçƒ:#T•ìš6_Kµ­n”ÖEdÏ#£”Ñšéf²$I‘ß&(f%”~¥Y8w°îSq‰Pñ³VY¸£!Óa4ã,½4D–n|©bl,Ù%{ØHY­Öž…Hx9Ñl’¤À“_ “öDD’ZI$óà"@þ¶N!.øùQè¶£Oó"‹rî2ÂSnèimÚ°ª^fÇZó"1ÒPë,`Öp2TÊ푯Šd ­¨’iÚqº’ÿo6‰æ„6]=An¤jÑ˃G­þt°Â>2*gÃÈW–R¿7h‹2ÜVT#ƒ]Ê=¹™bõj¾ló”1‡,MÇLUŒnD-G¬7áWÕ¦Á¯H&Ñ”NßáÎ&»^ |’AXþµìØê)ŽÎð‡ “ ˜ókDÉçMøÈ‰ß š¾¥6V¨p­¬›´H&_A=Ó„4dŒ­æRxN­10/bÄêïø³ÀšcLèÉT€ü‹$E%ßóc%³h¾Ç'fr-ÜÇ]2 „¦ëT*ÿ*¶­c^÷wTÀŸO°\§ÆÃG­%w˜Ó<`n¼†l-øÊ¼4PòHŸ©é}jKeác˜æ>+O’4—â1…ßøóëÞ "’€€Ùåí›9ð ZÅPét¿ô¤²VÖÓ¬Œ9"v¢ðÌ8§.äšt‡R_)§ˆ_èI£7¢á0o;Šñí8¶Þ=Í:Ÿ7^bugˆ—߯³9XûrqcƒWYÐO÷íX-£DAŽ%Šs6Šmeú©Mu¬¤ä¸ÕAÑ6 –XÙÀ#”w5ÓIØvsé£{™©•eÒœ.måÂõ2®ie«^f ­±?QuGDÅo-‰1ˆë–M±¤ù´cúF‹#ÇQðDè-¥±A³Xå®W‘žÝp(ÃZªUò?þ7»±ÛEîŠ|½\ähûm)Y÷'ïg&3§Î³'?ÉcÙg';¦Ñ„ Á6ê¹ÎugùŸ¯uOO#›:12©E‡âYá ¼_<ú¾›€|ljEõUÚëÑÉZ»]Ú0X¯É^õý¹æçŸjÕÉš1åt[t;‰[õrÑ÷.‹yNÖ°œl«ÞfÓàÉäÞ°¹2Çì6©À«wN%e2ÞkËsC(1(Ú÷j~Õ¾¸$€Ã[DqÙ‡~M¹}õÿÞ6’ïDº‘ۆ«Ôˆ¿Åfç_û=æÀ'u-ÉÖL¨Gêû¼Ý ÎqòBüí&LW´vñé¿ê?»pŒo«©œš»-¢©ãÉòè<:R"ŠškKhG{“¹xè&+ÜBaÁÔìÎý'Ñ{ŸoPAàJTªÖˤŸÚ³}1°¶uP$ò ¸Oû×ï=„^b2|”K2…”·ä´…«éÇYhxp4ù”«8j±gÁRb¾IÆÒ¨Ìðƒj+O¾ÓÁ öÌbàÞtã9S(÷ñ@cH˜È//Îûè黚‚ÍêEw}Bíi©J 5FîôhhÚºû2ž¡"Ý¢´øIÖ%î æ'ÞxÄ%÷H÷CO¬cþšë*YF;dÎÅ«ãZµ” rOˆÍTÏvî;ŽìK¨äžéÅ_Í06¦¢³}ó#&^ƒÒdçˆÑÁRà:-ùnàØ+9vÄŸžÕuú†îbß»bÔì¸iàᘄïh’€€Ø”iÛõÒŠx F)î”äó±ýÑl6ýt+Ý¡ò\o¶Øú,oóB×õ•/ ¶±HxùûÔP¹pNÆ®^ýA‘ζê¥X #md¬Oˆ•T_è:åÚd\f`È lS½ÍYû/øÖ“dš¾¶Uo9/F7?wÅ€4~¥œr×ο±,"JÍÅ¡·†èM›–b³^_çôø7X0ÿ;õ¹oýŸ…Úõj2 ¬f1^–2¾wR›®©˜6^ÐÍ9ŒCNYcÊ”J .;ÖQì´ú}U<ê–/]Ú=šÝêü#…R ‚†4צPQ£|93àfé(Ww4w¥!ƒËœº÷¯Á¥k¡'˜\ò l²ðÍ2½ å´¨!¸!Øâê <ÜæL—Sr/Æ÷Èp,¤ÍÀVçY' ¦.Ë9ß@dë·±!^ap¸†moêPWÔ’xUºz½Èp/ùyÐkÍÚpö®-VtlìÔ[r“—æ±TI"ê”XÿHIY´_u9pb-ÿâ F—úâ´ÙSb6[°Õz~Y¾t8;âÝ&ÝúQëp:€T³ú®¨€CƒÈ¢qŒW ÅÊìUäí¢Ìk»oîÞ³cÐk[Nxñ.ô ä-Gœ½À­íçvDpEs'-ôü#ǪãÉ@ð¨À¯ðÿ»?½*¿ûeØìÂe½¯h§˜¹VDß’I+ÙVn}°÷QsWý‡ÀÅÒ"•ï7[FøäH¨OöÌL ëÒ=¦™%µYú㳚§ÔaÑ'‘½@äæþŒÁþ¤Øpì$Lƒò‘j®uW`·;1@ ¢A‹æ4â1a”ÕËæÒÉõ$¤¥ñú[ü‡–Ý¥äÁ=³;|Æ•Yå@Þ¡¬&°cœY™Uª¶s~NVy…fEhKI£2ÞŸÕñ“}5aºK$+õ <!\MÏò˜ÊÖxå„BÇÙÝh“мÝóNà>¦›ô½Y›KðÄ· ô I¯Mç5b•+ÂÝ©) }ªðt{ø898(Ùk¼E¶ ¼‰¤£Õ{Ç´×hBOƒzO®£OkWÄ"NÛ€ ÏiS˜vÌøÿ›xy·^ÙïSyY¢Ô«3XþÞyÕ\Ø™Aúzx?ãØ@’aé¥Bâ}¦ì*Ï’€€­½Ô9á?‚’[[O¿kZ€D´õàÆÛÏf¡-¬gøU=Ó¸S,;ƒ¥Væ¹ ~3cNӺʫ‡Ò(cz.X3L2BY¨Yž ]‹r Ãáññ^.1údÙÿ?NñbnGM'°äDÜ<Žß¨ üç馾Á¥j¹Lì÷÷ÞZ\¶ºÞšŒ—+;ÊV. …ä;¡û7S˜JÇÒ9b#܈`°\ƒ åÜ œcpšOòÄ„â›>d\ƒ•›Ê»!Žã8*¶W©Ÿ, aýA£µ›<Ùh,§]ò!boëÛ¸ëÐ&±¨«1E+ݬþSîg¡mú™{“À»;™%1 ?"9O¹>`ÀGxî!NN'"”„¡ÏôŽ J©Ö¶ÝK±Gýz‡ÒD,†FÎ&øERÝ$'“wEOçAkÙª¢Oûh^(DëŸõÛP …MLÀ„Äן÷O¯/Æ£p56 5½ý‹Ê›j_¢ Æ?<Ö¤·'RËW ÿ܆íPú w%,ûXÑ×?Ór ÜsàÆ°»±œÂ» Ý‚IÄ\hGðCèBnûgãÝ$åcp9ë'Òj¸=`Åø.YÆEÑo~«ƒWW÷ØŸ‡céO¡œç”š³êÛŠK4/ÚBªÂʼnÂmƤ8“)¯Eò*ì]Ô÷:À/ƒŒçš÷Òd Á§t¸<눵‚^w éî¨GÛ°ùz’Ó /â°÷‡jºCjõÔËä·…r˃‹ÒíÑ*ÒÚ°}|&µÚ»©U”ËÄ]‰².lÇÅûItOHQêG‹Ž“L®C“gñ›pà€ý*ÖÂ1p—ѳdtö"JŒ% ε’.o2".r\ÈcNÚ¤œÎ2=o¹è0ÈÙ'ÌèjX $7²þE«Æ»Â@,ûB¬vùµ;Z]`ó©›{#Ïg|›ÉÆÙ¼öË—Ù¹1‰ëÐïÄ_åcæÈˆu—Ì·xÒ­cpèµÙ)„͇âœ8n/&V·ŒÂÕͳn-N²l½• e «aŠžÜBloôÂ4øpГ J:üC¥x˜ÉKqfP’[$R†jÚŽÓÈ9©ÌÚ©ÒÉHð»ŠR½Öø0èjÈQŠ~`Ä&úø›×z<D;PÞ†‡éöùSè=¸xþÝ=0ržÏÈ“’€€ºÖêí0öV f(<(ËHãàTö§üÉ5[3W¿CRI³ Ói_oßUL‡2—LÆÝëq¿oæOוm¬?¡eº?sÉõãªzšg0øâWÍéJª¹l…‰ÂEðlj—‘d Ñ縧#LfÝEYñZìç?äSÑc¬ ·;‡=&x›D”òô ÏÑÓTÞ¡ 'ºC¥“ø«],)†+ZÁPÇ¥º*‡ûQÂðïþùB3åÔpž¥ã"Uèç÷kï¿<{Ú?Gž·™Iæ­øµ¤Šv Za7+w›ÀrjÙþ,evQ›7sÿDfàS©<ÕhEíÆË좸ø/ ß‡˜Nn©§%gÛ]I|Ò—^¥†¢!Àf#\ïõÙ‰ùÊY³’s®Ói¥hx]êrv-Dªl=uŠä“¼hš\[:÷|â5?±õ…©ÌµÏß’p"ŸëZ%t)®ªd—sËz`iuôÀšëÇ -›Ä)Ìǵ•:U©6üWµù±¾Í£$ÁY"ï§gl«…æ÷ 2.›Ž²ònq.4<¾ŒÝbÄ Àý@o õÏ`‹¯ÝÆÈ¶F3·œ"AE÷ìÒÔÁxÌ`Î1ŽHrŒ%øê76G—´†¬nƒâ“'‰Ý@\f7ðF2db͇Þ2¤i”NõͲê£ãÙ£üè_­5sÿ5V”²Ÿ}RÐýˆ}ŒÙ#'5Ûÿa…îÄ–Z$\m'È–ãXùLõHŒä.?=M<ªÊ0¯Ï}¡”rs9*úƒ7 ÿ5ù¤’Í’€€°— âQ”\YóvOpDïß# “GÄñ£Ê Qz§œrãð©ÃsÛŸ7äfl’u?ç /ƒ“lÑF|rðêX^œ/µ9c«! 9‹3P`¨ªð(fbñŸ7¿Q–ÒÚPý/aò¢Ž…{öpʪ¹Îö„eÊ<øôak½Ýz q3w'?C$²µ<,²L°=c÷YÈòÕôÞs²^ÅbŽ¿'}/ë\ 'wD2b†ÑÅÌBònÿìÌå¹Á뙩QAQ_ä~[¢Ê’íûØs®Øàyµ~2ßdêÝÂÑF×ö˜ßD‚£0Bˆ0fÏXפ§ âS”·±²p=Nd-…†àå¥zÌ`Y¦$$ÄéóðÉ4?å¾ár+Œ%ï‚2F¢U¡×ˆÓ>1ž÷¶'[‹^Þ;œè|àÎ1&¦ÅÈ÷•¡ËÀ Ætð;a €Lº1Ô^|”ÇAþ¡äœ6ÚY^YÑ^ÌdÍ~Z¨`ÛT¬ÕH;æJe½ç+ ¶ý>+d(tƾ @Kš\l¿[Áœ£œS—HwÛxx…{òçÒÕ„'n¦Ì›ðdôM±!iÁ§Ô“ÐÈpb¾T°G ÁMô÷¡dçù¦uò9ò¶‰ÞÏS¹·Äé„bãÒ4^,cq±ñ‚ÓX¦øÄ¼b µÀðkuÝ`†D²}ëÙ/ [ÚSÇF@"¤EGS©8C7ËER½ÄÿjÌ;›‡DÊ06‹a=LïÙ)î² Xèpÿt—üÜZª×ø˜w_a¾Î¤7ÈÔqf[zÅwÓºËÀ!ƒhöW«?žd2 åºJ̈YŽ9à(¹‚•íYyGÀkØ@x _Ë:Ñ CXsÐ&·W‹¸ÀEUšßZÝ{Zëvb¢D|—ƒeV=6¶®„0€êˆd4M¢|ߎ‹­¯¹Tà~¨aj“¦“¡Ù]žv«O侑hŽ\¢ùQlj/¦m&:ü]Ið÷lÆ‹or1u²†Íê2±Ü[ôº©dÊæá¸ ð"Æ,HߦpAn$C[f­/Æ÷U±dµg$ʪ7zÒJSrbà2¿W¨çf‹ðŸ&»‡ž -Ðýå$Û½TZÏ8ðcWJê-®n,ª(¼8†Y1IÞºåÓWƒÕµ€-–f]T־ʨvf88«öèîz'Hizéªüû¡­^Ùìp ÅXã÷Tòq:ˆÃ¿‚Y{z_e £;†Ö{cJ|SÀS>ò~'¯´q-®ìŒ<`NEK0/ô"™›Ö4#“)·ìÛúùÓ Û\£õz†Yg]šŽÃõ“Vãów‘æ! Ü3?iŠË|Ì*H0<üÞ+LWVò>â"¨€§l&(íÑôg¶h¥BÚÌbIͶ:‚w3ðŽQlÞQ@,¨’NTPøœ~¬–PСn •YÿD1K'°9E=sÝ«¡”k-§Ù›p?É ¿ÝÇ~2%ÚæïE.òöiH<:o,ØcVé’¶¸±zºÏ’6+×ZbIE”ÖŸ¡%$Ö†3þå,2–!£ï]¹qSZGØGæÒüµ¶´¥ÔëÝÆp˜æ‹‰š;åöÖ‡Tèüüäïdxp¼<,$f7òI~ £ëVºv¬³ò£d½Ö‹vAä‡išëh܇lä¦òGŽô­ÑÎ\à…8Nì™ûVŸ½ ãw<˜Ž2ïŠE’€€µ6,Û–5*¿$v—€‡~²}Gç~ @¬ÿ#­Qµ¬ |Ä+p)è§Uï*5œ´r.bê¨êd™.¿ÌÎ2ÍP$S°×i2y&‰·êŸåmÙ©ßšv…(ùÜâÔ2K‚ŒŒ'ÏcDk¹ÐÎ`L)Hàò7ö=„]ÁPZÐq¥ð¦‰zE  §ÑUŒÏÔ_æî—¾Á:7o›´†­ïØÆ•$Mí óåEé¢ðpd|ÓØöú°Ay!o(QÎŽ´S°‘70,1&¾,é„x¤êÊ4eŒ5kN.¶ž·>Ô­õkÉ0µ%àc‹Â£5£Þª‰lÁK¸­\iæþßVØM¬µ¤åòkµõ!YX|i!*Y‚H “À¸[´7ÛÀŠ ïÇûšL ü&â/ÿ‰†h»ØÞ[vŸÉç †—<ûehÁ4xZ4þ±ö˜”T|8/Ié`³«Aõ¥·1í+qLì.Åø®·’E%ƒ*6ƒ:‘‚‰E)¶’~CSûfO†„Fo)œHå\P}´ÀR°Œ)ý˜™%(z×@;;âœBà8ê.<…Æ Åß5‹»Õ/H¯F›=»É•bj±æ4­þqØÝO]i@/öv¼JO–º·Í´êj¨Á–>žã@Ýç“eÂÔò-×8AsüÑÏ!îím7ØÃ&â²ùÕÄÓïø¾hºí&QZ{…F2‚²kװݦó­a?ßæ2l\fŒ%.7í×÷ íWmHeЬÜÓ%èï`¾U–„Þ>˜û7›#¯E>X'Þ¯*Ôœæ°Àp[sÝî³ïׯ& cÈØ+Äm–.©#Ò$ÿÃbÉÇúªÝƒÜ°$S_×Xû…izNP¦/PÌÙ<àž›Ý‚ÝïÚ^WN—Ó7{pÄ׈á1Œ)(õ3¿Ù¶¶$ £ôÒÚ0Mbt±¤¼•ìTvôO‹øÔ‡X®õ*B5ë!cì1ª¼fJ€CbÒ!d“ÜO¨ä@啘+ð —þRzcf=„µCTÆôB\³¦9s¯xy~Íòúìq¤d×\íŠøŸN2Ÿ§U×çRóï-ÂKÙ€ƒ‚ðüàÿ#F1Ÿåã†=ÿQ"¯s¥ðŸw•ݦ˾#ÿ½…òž1$„¤DïÚK·5>@ä¯JàèèFÍ’€€­¶Î'Àö¨3ƒ>>¥ôžÒv9GAœO9^©u1„µÉ@ «RÊf†Y¤Z(6Tå›ÝÀWüG+]£õz¿ßpg }i›Úà2_o/T/,ÃŽ³©Îf,[cð!ùi£"| v›SŠ”PÚCjJ]7 hžo>ÛšhçÚ³ ØéÕ*­5—IZîqˆä¹,iÑ)RRû˜_¸ù™¦¥_ÖêQ¬5¨Íê©2oÙÚ`[ò•Y{U%³ÑC¤-îlèáQÔ<+>¤Ì°0˜oCr ²Æ4AB³:¸}Žä¤M*Þ2KA|ƒ‚o,§Ñ´?Jÿ„'nÎ.7Wy‰’qB©´«ËW ]‡Lèù7jIµG£…½„¾ÛaêkÈ´ºúÆçÅ›äØðš·*¯àG2Õ4Mÿ3Ù|€nd{¼{ŸøDÿ±eÞ¸åK+\ÒŠzû¹Ø™ »€ÿlGåÚº·«P[x¬m×” † ªÊj¤ZFÆ5€ï´ƒö2çûn4¦ ¶ÌR–Á¼M?“ˆ+É:Α…N¿ÁRº¦—‰í÷Ç·wi¦é:[.dµ¿í½Eþ!_ }ÁŒã£ñæË¶z¿P•Šù‹-¨ñƒ!Â÷ΞsÏ5j¦ßTq.<É›Åån»7úF'2¸‘•ÐxZw6¨Z¹oeÀ¤<’€€­æ-NòJjãS×Nµþ’ÚPkÞ9‘wÂÞ<úrÞÒ+­ð&÷–ëÁ3m ɡԫÝëßÉ–q¡,ææw|ÇšØÉ¸?©´@EhnFii±ÿ»0äˆHžè…hÒßÃ>¬1á šw*ÓÖ[`Ÿn¢Ë¿’O«m…A)\…ðÅrƒÛBN-ÅÉÚÿ«Àe£3I†vG$2:9"ô¨™ÇäÃØÇ +/H´ÿ¡«úRÌf Œ)ÁRM£„Ê þàK`W¡ØD>Ÿu³Tµfèúsã)Žh!—ž’ŠžIXïy~ªœ¤¿‰7ˆg¸>­ûVŸRÖhÑímJÑzá¢ïÀd onÓ3rª`“Lòº Õ@3–á†Ê_šØn ?øŠI ”ŠjÇw= ´3ëŹ 8¡\NXŸ› )ƒ‚»g @¶òdæ‚{;Ýé][åÚV©Ä7]ZM«?áØ0m›0ûlR PTÜF¦Üî£Î¯Þnë„7zë'Slç3â±ü±ÓÍu:³ .Èo/ùÚoòfN«2 |CA€.wE'¯Ïÿ]aÕaö‘ŽÇ†Ž2gѯ}‘ÒBå êoÁ»û~†IyɃ‡åg‡Ëú‚–aý°\j=ðJ0ŠqXC;.˜±ˆÿAÙð@&à‘â•&÷ж±åaŸMÏ"óAÒdÖÖÛÚ’j¾­ŠŒ\#»9qÌ+Ö_W[l± ˜ÚJ…—h‚; XR!WôÕëöï(HÙµ o>¹äv"Æ^Çž¹€$¾YKeF*:ËYcAæ³^ÎÌsÿmCŠi{%R‚ïÄša)}_Äy´mdÕÚØ^#?$Þ_¥1Ó±iÚ„ nÊ\`êüqŒÅèh J$6XÚêàé­`H*f…´ˆ“ÉÈñÎP9b[aïg™sR½á°#lõZ‹Øª…%“Œº5q¯Íxä¦u>D­ÎÇêŽppìfk.»Õwq„c+4==Xk¡ 8³/Š+1•YbmivnµÌ–ëKŒØ§k·% uÎ(ý—#QÃüfá·£í!QIÅ?õÑ>"8Y£zÄð[u†÷žî¬‚‘ÓWý¯†;1kŸH^¦V¼wFþ“ë5w|™Äâã°C¡dTQdÔ†¶WÎMÒ’€€¹{ÅfröÚ©Ì!˜ÁHd’ J~Ddê%É(ÁRc¬¹¸å½WÚ¦K^·áÀ`1ó»·+‰’€ÂkrGM:9yv-šYƼ¶:8vãýuÇ-è¬L-}©È襸J”î £beì9¦Z:éÿda}3S¬O À¶bxK,ÁôI³îÇVï2­¸V'Ž«à«u0ˆZµiO\=/›5„Vë¢xAç*§ZãRþyÝö>|ÓëÛbúwïâø[<¼©tWÏ@h*QSj®h¸nb‘?®CõkÓêSàƒþ¥Öºé÷Ö8²ßk©Mcù3ädÑöûûI6G¤Ø¥¿$•W»®\ ­äÚñõ §²ÀÖý\¨L~_u!\OªNÜBò£¤(*óÁɰ &5Yá+ŽóSÉ7oGÆÁ^‘r›†ioƒÛ ÉŠSýµŠ”§@„­9ÅzõH ž4FÑî}3!gÄsg|¨1ßOz>®êiÈÏ…6–÷÷`^é {%ä”ôô`CÇÌhcɹðë5$û˜u¦}7!€ëv*¶ŸÀ” Ë¹MXM’¸Aï>°±O´øƒç×»éq†É"îêÜ·Hæ•sõHwlÜ3”.wöâPÄŸ›ÐkÉ\Ž}b1c?+ÁÈM> »ßŒë±kÏ(:¬\0ý,-ªªŽÁ¾µžãw‹ˆÚ>™Åqlg9¼l‘®§ÿÏ0ñ”í÷  -°E ˆ2³‹ è>ÜÌø*® öÇD¦H­Ûèù¿õPmqw ü¾wcÁŸ]=¸5\]}_4®<øWwÁÈLç®!ÊAº KmÜÝV8ï[|z¦ÂoÄ‹ÓXeßzN,0šC¦‘³Û}*ö™*Ô5HzÍU´uy?çjrÝ+rU«µÆ†(žqÖð¹ðY†¹/ä£ó˜Í¥L€½ ÃZÊþKÅνÅÇB{®õ˜ÇÒQãéóŒÞØï`͉š{@µ{W¼®Û¤»5zŸÙÔæ‡£ ÷[Ø–÷!˜ÈÈî…Ò’€€«kp3šð ;P¹Þ5'¹P¤<è`Sÿw] ©ÝÅ‹GØÛDôv@q:ìOl¯bÖþîÎíÔá1 }¹°Ífæb_gξîçÖmô»tâ™ýƒZñ`p $ùº×ºtÈ1‡ìüáËX²(–@·ÄRug"@k´`BvN|Š*ŽþƒtxÈ"å"ŸJ.â#PIÍœžœ®Il ÓìÑ/5$³4¦›Wëþ+„OJên©/T_‚—¬‰×¯=ãÓ{5ϱ\ "©Å?žïôêšjbõ8Àº¿¢ËЗvBhG«ìš;”‡?‚-¦—h‹…±ìŠè/T+P®à&Œ”“ü €Õ”uQMEïAH™ òbo44`x¯gQ&"6¿‚³s*b¼°=õ¤f>é|x¶½â‘o®qz­v Ýÿφ4v  Š=j84Í&j\Z‡¨÷Á†¬e®õR–aFZ•Ó$dW%V,žPò"ta;󷊇ÑM}õ X……ºÉ²Ëü“@³®èg9£’‹NWŒEÀÄ‹‹‘žÂ»–Ø&ÛX÷;Ò¹½¢–< •‰všÿ‹Š£ãZWÛY’té½âCÜ- J¨Q\ øk)_ø×oYú¢÷›i~wИ:Ç UB7Få­¨yÐÝöMX$ÃÏ¥aÑ`Íûû`TL¯FÅÿH ¦­±}ük´ªG> «Îs|)éFd6÷ŒëwÔ«˜œGt¿T+*³½2dâ= ´ûërÏ1ÿDvmš ±ÁÑ' JÄF¼Ó<ðW’.ŸÐŽZªëS±y žN½ïÔBîê´}зÿ¨ë1‘ÐýWÕâÝ Ûï³3ü3åË]ö¥.Oþ°Š¦ÌÍØ$œ”>Ë¢‰äáÓw¼›ÈÌØCw`x°x`†m €´À@g™Oh+Çz;‘“нxοØÇ§^ÎÄ%i¾™ß@Ú=‡vT®LL/³|15h½‚”I ð²sšlŠD¿{üV—ñ‡%ÑóÑöÚÎN}XO¼D‘!?ª´Ã |Óþ_p©îb«6Û³®ƒÄEiîŒÐ v¯²ä°w˜!@ŽlÂLNû÷¸„í£Èk)Î>4n´V!<5É–yÆ9þ`¤9ä$›…EüÂðÀ„Æ„VN+ŒU¬^çÉò’€€¿ µQÔKübNÝ¢S—N]·Â‹@ø%¬ÈS$ÖXâ [“!CÍHÉó+A®ù¹¸}å1³n¡jp΋R¾ Xº.ç\‰¢ŸÓˆ[íö, b]K-ÙP§ Ý‘œ÷QôÍuKÆMÛ˜y›É•û©pà õ=\vëo°_è+ˆ}åy¦°çs“e×Ë ÖµQ°7âÑøx+Ô½U,ùP²š 6ßöhbô‡kgM²ŠUû—îp8ýÔ`±ò•òÍû@ÓHjÕ¤Bf#‰Ø=ñ[äú“8ubÑÅ▶é:¬î«ѽµëŪPßje9±ÈoDaˆütmF¬‘>e] ˜Anp›³:÷öžÅ¸Ý±¢þÈ&ZàoÓE˜´é€¦Rå‚$Ó‡@RÑÑDÚO‚¹jÅ­ò5¸CaòÎMjñxªª¨,%„ŸSÐ×±æ¿{ãAç|BER‹ ³-RÃ}P±‘§À,²@°àe¼ùªšÒD«Ò9 d’Û)ÿ¥gdÍÓ—«.ýÉRšúŽ $áù̾Rã;†,ŠnÙ€FsxdÓS1èzI~ø—Øa-’’}¯ôiï à”Wó5à¢[œ¤÷•µâ ]ÕÎ0Žûg˜öÉSÞ_ ±gžV1º«4XÉht4°yæÇ²5™LP+ÃÎ>˜`sýš5¶_¤õáêBU¤àSJ–àÖÉ¥¯9ˆK‹(G’ñ?4lÌ‘ÿæØg=QÁ°±aÅë6 åÝIgÙ¤f¨ûv–$eô¥h;,Ãp¦‰åŠ“Ù«\#7\/¤÷¯…²]1ØS¡¸ðÓ((î~wIl=û:ɨôŠl#Q°;õ’'ŠõÐÝ¢s;D³x¤PÞc;X ÔzªH ÙuL{ßû¥ëâp.URØ[6’<‹§¾ƒFš îÉ0î?²—n~|œTôê ³XÙRn{£Yáï¦5› ƒn¡¬ž¡Äb¤áØsö$Ãê™å…@½PøfóœFP5Á§òû?SÑûBLD‹Xõ½2‹Ã½ýšßù},åNAód;ÃÚ­ ‡üo?ƒ¼éjau±uâ¦œêæ›öE­êt(†€‰hd× • æöC %îжzâiÅ!¾bŸ¹ë[Eñè^ƒzŸ2aµvÑ oPÛLj÷#”[Â71u¢[ Ö8,¶r3.iz|5Ï?/aw~ÔÚñJÊ« uïSL h¼ ìšÜÓ¹0h r'&~¢wcu;]öÕ_þ818¶«ÐËq;ÔlR`êê~…¥ÀòîCùÔ-ÉØF ºr gTºQŒŠîQEpP´4yO žŒš¸úé0ÞlËÒz™¹”`ß_ëQ†ú™á¨ Èñ?ˆÁs%*pküF¹î®»íYX”‘Q*‰¸Î²“nßu.ÂZl¹s¹×œVy²SÝA™`6Üele~'ðí¥–S@¡—‚M"£ŒâÇKLCMþ1ßßBk"Ü,¶OÁpÞ@ID#›½ƒøÌ>\õ«QÉJ£kLc'°œõl^–8í)æ#¿ ×Rƶd‘½Ãåž¹¯éÙErsªN ÕUU¼¦Uj’2CåFÝçO¹¶LxŒDï‘õ4)}„,•â$@ÏLüLá³½«z0u(—ÃgM8ìÍ#â<`ªÞupËô3ÜéíÍìýŸ‚“¹Élk&òuinuí…¹#o6 *þeWüê@½]K“ ‘Π¶¦K™Ecw9ƒZ3eâÒØüGm+4½*åb¼mûH¸b<"A†£FéXSaîÞ2üZ(øªÂø¦We’€€ÆaAVûq06ýVºk–ÂB|#ÝdÞiU¾*¢eè€ÍöÏãÜáÞVl §ŽÞœrE¾1ÖÕ—FÁÝw›þ×ðgÔÿFA6¶î*%ª%ßmSþé\l|ÕÛa[–Æsã®»ØhäeÍqÞ@5-¤ƒO‹†aH3‹'‘QB”†iá!xtšô B,oN«9©»15¨ävDu„ŒüöLÒ¥gnó€9à&Ë¡!ËEáƒUaéÁ{`ag²Qå ¤Hü6†«I…=g¾®—Ñø:/KŸmÞDoKQ0}á©ôwõ+Œ*ò q©vñÀh®ƒ7“Æ™ÜÚñ›óƒ¼§Æ{ê·úï' ê¢ý [¢RW ,ÀxyÂm¨?ߦálõÁ^ÏÌ3ï­Ð47Ú±5Pø«4x/mÅßxSnèzøÖÁIer-De<ÁÁZÊÕýQÏòu[<ÌXFýß œÂD0aŸ×¸Œaý@ŠÑ} ß¹%µÀŽ2zl"Èã-xŽƒñýœ‘ Àp¶[z6í©_V5p.OŸ—ÂÖE™¸B7#"ý%‘>#S@íñßïÎPçëºB¿Å‡§Æ/s+ÑELcv•™6^aKn<Õ~Sãc—½w:„¶²VL[ÒÎ÷@Æ­½^1ÙÞAí„OoñðÅM+PÞ8òc¬i!n!áñ7Û<;ô§%De`åÅ„˜Þ ŒFÎWñd2ÒYo/Kü¾p„Õª·½Mß,Ï_ÌЫÝ(¨}² äÓÂ;öÜ}ÃÎ@ƒ}8¤uÌUúáˆîÕ®\þ*YªGz¶d€QT÷¸ÕÑGaQvÇ4`*Ÿ/ŸÐ¥Xœ_NÁ1ކ–ø†=R8>>GT%ÛqÈÀÑ"ªÅòÈÄȨ†½8£µXì’JáÑEóÙ—7C*‚ªlºMß„ÈPÍ®¨ž¬”> ­E<ݾË+ý+ h örJšSœhµá1ï6õ­³Xל¥¾0†lgOa´.‡0tR»²ÕwIÕdTP¾6zH™C¬,H_nÜ$F@cªcËøýPYl¼I³þšMQg& ˆáÊ% ¹ Šofu:—ð½ö äÔÞêËD2ÓžÉL÷™4¦?ÓýÝkàU¾õ ÷˜ªVRW­~Y§È#›Â5r’€€Ê¾ÎíeÇ8ì/°m+cù½k ¨2ˆê~õМ[*¢Šÿ°¶ÔÙÁšu;è9Ðî]Ë+§Ž\‘è9GÄò;ɸ×+°_ö$Ç`DâŽV“û¡„u;ë=É…ûyåNÆéÍÚpü‡’â_žJ±ÕUnt<0ùǬƒ“ýÁÕ]bÑ ¤þÙ>ºnÂÁ“Ÿ;7h ~,²… ÙMê{ã­ñGTÙ&Ç1¾ª¼<¶måÖŽH <ô9ÚV¯@"9½u#þÝ ×Äk­h¥ÛÏJ)£è½ÝEY¢o³7˜7m<ºXdÓ))Q8.~“:!‰°bº«8—_ˉrP6hjÍü ^.óèÍwö³ðdw”œyФEöÑy]‘ ÚÇ­Q— îm.W mfÒ.Æbœ}H/î¨?QE9¾*L[—(¬#ÉTÏ“D&ÒJÓÓ4O©Ì "ŒÚ:á& T8øŸÁèqSÞ Ñ å„b¯ê«ŠÅeHÑ'Š›°å#ò9Š÷±EIq[RÚ¸Ä!ÕIº)ÉÂð€O;+œ©èa¼Â+âÀé{HÊžAÄÄÁݯÈ54þqýèÞnŠ(]g1­gu1° ôî²ëóõœ¤?žÎ¤XVà!¤ï,!„ÐàˆyÂ0evL¡£ÛdðƒåÁCY õ|ûø©7kÁ€+ÄDR_ î™j½[)ÿUÂ%‚QôÊvíæÐÃDo›6Ïœš·OšHØD¿kl':%aüƒÎMs«B‚¿­Lj¬Áû^U/mSçs³ñÄ]"+àÊȉ%D„i€T¸AM³a'\*jåk©R)ÃéI¡þJKmU¬2…EÌ€S¨ª†òúhO~Ý]ÅÝt~Â/Ë[à ‚¶TÆ¥ö¿Ju!ƒ¬,^D‰áH°Î4 ñÃí)`>»#íLÆ*¬ò‰Ž–lY‡Mú‘å{kKÑ(<Á6SÀÊQÌNµñiñé4áX·QŸ¦ð¨ å@½rS;aJJ ¥Zww3 à~Ë7ïÌ%>¿õJ„'Q.›Qyò!øÂ1!>kŠõ쥀¥E΂ßOe €.^‡/l¼s ”hy޼£¤È=’Ò‚ŸÛ4ˆæ2ú|#ûŸŒs Ÿ@7¤Þyî8 Ae]¬ˆÃl²•Q_EŠCÒþ!i°O@*ÐCž©.æv·#üŒÍ"GJ’€€Ü!óšyŸ;jG|7pýØ`TÏÛÍ\(-AÝE 8C›ão±±Ï*ÏP!YÓó$iû§©F1YØ…Ÿnú”~b$¿èYÎÿùÓm±i»ýzHÿ3¥Ïb"à k6¢Ù—1²  ö\ôÙ!#>±ñ"\ÂËéãaöþ¶Lí…ª¾¦MjwNCàfñvÿP#Î&wzC…ÓNÿè5$0-·ýÏâƒÈ:´ÌŒÓ fíI'lʱ¡t"4³´Zq1“ìÏšÑ^O_2OyÁÂt¸OÊ5ކôaü¯ eû÷4Šà–é`Üžµ=|>y¼˜¬¯y§‡£ /ÿm]§—•KWb·êdq9Éã»H¾2Uå_`îÈø¯Šbj%ÿ"‚¹ —tTC[&œúëê$ņ÷nÅB¾42о®MR„ºkðéÄ ‡¾ÕøJãý`ÕíXyÛÚ7HV­l^aKµ0Ÿzà y÷Æ ®—;X›çö'#Ý<0ʵëá§ö1R9èëZ!‡g‡1zí%QåpŒ: ˜¦·¯àý¶~qD¹ùñ¯ [J↓:{ãÓUÝlÄ{VÇ+íJ}&þaâGüÜÑ.b~­ge6º´›kE4üÉ1 v“<VBÓE¬Û9Ù¯;ÑUÓÄD®£8Š Vc”Å©ñkômmP?Yß\û– ÁvN.+Óºey»’çÓH0˜cб½êj¶ )·õ¾Yw_- ÀB`n O»ùÖ®yþé»›½:OGT`¡.ý–vBQšõÒÃaß~‚ó`îj‚¦u‹Ëú ÝuôqÔ«1Ç(u‰±è®q¢‰éalÆ!Õ,Ÿç>S$¦r9Ú3|³ES¦›Ûñ”’;}¸¹©ŠÊœÚމ5"Pä°Z2bìÊŠø/¡ŠÝ.24€ù™\Љ¹ RA¼vïiÉq÷'š |ÚÝ)Ëý ~…Æp¯’…oMågdh#—!¿«e<õïãaùQ«rPÊ¥AÌéAŽ qüg t‰|áÎÛé;zFH× rBþqdYýÐõÖjkõ~ÿ@¯¾ÛVÌØ8É'ùòpmBÅøwâñÉ4YJŽq¤t#Ÿs´2éÑð÷ýžf³v£n› Ptš’€€«ž{ûÿa¶‘Ÿ®[/D“ssŸö7¨¯úÜ„PO QXtƒm¨áêéé_ýy7X¯ÖùK/%óV“ŒzŠ~6-Z°Ät‹ûž* :tñð ÿ÷•%ÚdÜMìò.Äj²69‚uR]U7û³Ma±ï¼²Å©b2 ծƙî‡a­@¢~›Ø¿´ÓM VOXÛ‹xÖ„…äý/Ì´ÝŒJúxZ˜Z þ—©U½Uê1J¹K•MjùÓo[”9ÖQ¶%íîʾz§Å‹¦Ðb]l}¯ìé@Rô51ÖÓ$Õ‘·uTÈóœ+þ7i[>å‹‹ÄñyR>‚"ç~U¿k-"é89º³XB²IŒ %ü•jÖ fd¥ˆ/=óñ†ËË×¥Õ?Ë>)CÃJ#Rÿ ¹8?x|1¹”Ö}*?µk9—1ázwâr‡…æ3æ™ÚŽI¹E(]ÍIx— uÑäCNE’i în|¹Ûæ#”BÀ'ÉšˆMåïÇè†=¯Ý O[üEÓ€ùhÚ’*×®ôs,{ëßk@½o%˜8‡‘>Áþ)ò¥F¼^€w­ÄnåáÓ–ËÇ׺X~÷x¡àwŸÏ;í-EéŸaTR­ß5$@[LµLCG·9^TΩ+ÜÞëÓ»$.(9°Eâ§QpËIy2\F¦66Hãrü\üN9&ïö’Þ¬0 oůµ´[ßn§»|~jùI×b=¹Lƒ£ê«2LH¬RŠøgfòœ_ÁX8ÎàéàAä žnÊ.}åI‘ ¡]’€€»ùi¸†$pŽÃdŸóðó;Y¬›ÒÄ´°¿ØÌtû¼)e)ÿþÁ_äMÖŸõ˜äñÄ‘)Ü`½å00z‡öFÎÁnZm>e[i·0\IÆô‰±¶£*WiÀê\qóg¨È€±•÷Ýød~1îáæå И¾ÖB§ízÒC»¥>=þpýøŽò?{’(^ªl¦›Ï‹ú2ýF‡ Ù<ÙæaHÜ8ïДŸPk *#ÏèªÃè²f]0HäÖ;Ry€žéQCW.BÒ˜ë¡5ŸÙð+÷¯Âe#‡ôý‰Ù˜ÿ!SI!#½ˆ[lÏR¿6ªáŸÃÁáfg¿]ŸÆ|•²…„ºÏ’ /Ê.KRZ{ÒKIÕ©Ô x¹Û$Ú†)È^ŒÃ7”Ý›G“ZÕ‰i.éSð N½#“™ |6w=ú3ððÒ§)¯+Ýó¡aÉêõ®ŠoDÔkìÚð tú0ò&РSp÷U `À“cZʽ” éÏ ý®HË´™bÔZ#—`U2? û@ÑUŽA“>ª­“r^»V˜ ?ï覈{ìÐg>šz?¤J†òð+ç™>ÒþXÇ™üMÈXå‚Nô˜0?gæ9÷‘g]“\çHÓ·|󡈱û–~‰¬"“¸š¦H9}KU€ïâô[+;AA€Q¥Ör9àf”®">–šty¬Ýð¿áÛ-zø4ªVËUBL† [QQ•˜ï$žÆ] q}Qd÷Z—cDÝÉ5Žd£²as‹ãùã1¦ìÞÈ?›tg”7½ ¸ßí.iŽÅ9›[`¥y¯][æ‚Üá;ËIǬBÞ‘Ôõamx¡BO´\£ÔÓµL•‘eÉ!sÞ#>¬bÝ_ûU–_Ç6&k´­ïÿÔÎp¿`8@ZTÇíÖþh©½‡¿{ö¸uÔÁ$³Bfìñìv›ø&+¶3ª¨V–o¹òßüÅNô?³´±¹ÓQz¿Í·Ÿ£+’ö<Ì^<ª*ë§x©O$ýál§„Ø¡£>u°ehùð”J¶É ,ð»8lE?»º®§F1yÇáöËN ážÍÁF"§36¬A¶…HR_˜íüÌ*˽$Ä £ï°ˆ# M¾@Ù|Ÿï,-Rü³ÄC´ÌÚáÓD~èÃÅì5¶Â[&·’€€Ø Þ«Nu0 Ó¹Åsy˜^§µù™/ªîäÁ×^Ò7]ª¡œæˆû¬¡.3áørÑ¡’‹Ç kê…·yOä„Òý炈]òŠMðÓ‘ý65›`Gx‹]µw˜·R¢B°®)í²•¸Üêb~;ò©B©ÈI'DS€ë‹Ó³£àÞ±;Ù|”,BªD‰b7˜H/‘€|w#–ìïÈÀ‹ö^pZšIÉpS™0aÚIAhÌ`œA9[­ tÉ ˆlÜ)ïßÔ,%·âë–O¿]»@f¬¸»ß6ORÉbBÚ_º¤B¨ž}½þŸ‚5 숇hNÉar¾‚\“™³ 0>Ri=›ÃR¹äX“u×|#46qÝ­1Zˆí>lÃTéÓeE³Ã@·6Hkøïø2[ævHoµ2T´§3D°¬¹]å=Öþäƒ`†Ó5¡¼ÁSà õ„§"ç3¡:(€ŸgU¦Eœ¨.â2ý€ÿ†´¦TPÎÎ$èþÏqcã%4’€€Ð&;²6/@CÁuë‡éª*zøý£-ÖcX-iv‰5Ûš·¸# ~›8zœÒ¹¥-ùòÛi½Ržüš úódσÚOÖêê4øÆ"—Ì‚ì ^Ýã2|£ã"®wá{Í„8àhi¤$ÏøÍ¹ÖOã`£ú3Òõ1;¡D½cÕ9ñÀQɔԲQüÌÈBóÞfÔ¶„LÍ•‚‹¸‘FV£ ïÒ¡v¤\çsQ øâ¤¬™¥|R+R5Ö’™´ [{„Á¦4zÞaŽ‘Á¯—â&Ñ×£&ÛYˆv]àŒ5µS¸rí¥øÂ@l¢šP*`£¥¡óç|ç v-µBj.˜K&»–æß‘'¸U• 7Zÿ»J¹jö¯«ã};ù:™Ø°ºø®ã·,ê€Q óæ‹iùWÀ™–7°Å޼o¥êVSE6ó«mndÙ€A©¶ì7l s Ë€j<¿Zrõ 7ÒÇQœ}~ïjRï¤7MÔì#6/Lû‹‚Mø[ ¸yÄã—%ÕŽ)?Þ¨+ˆÅnðo=;%ý6ezéL‰Œ¤­K ,yѸé±V¨;fF\Æõ¹´3JÍnyLoÇ3\W ÷àæHr) Ú[_Ñ$ÉSþ°]‡U8ÐnŒÃÏæõL³¢Rs ±ý½Sv•÷«‹P$Á‡|Áµ}mšya®è‹ÞÅYüÿoR§'C¡¯j|“š`b‹ûaÔV#Rù>µ­Ô}×€í®>Œå]Î:Æ+ûR€&ú NèÊt<äð0`üž%E²ÃªæìL¬v(f¼(&‰U‘oâÏL½jWÊžÕ’€€àÁ–<–ûY ¿¿û6“LªxAÆqÜ‚ú¶è8DŒœ*°@W % sM¡Ÿ§§'ÿÎ œÝj9}77ð! ¡µË €½g§-Ÿ²J–X®C¶¤gx8]˜\Ü$QŠ,<"jB³"®¦¨ŠpŸÙ¸ ŒªÂ³ïÿií1˜ðôÁËÎ}r{å7òýžiŠó%E¶‘EÀ ÜÖ 5jÙVÁI,egÒžzmzXþä…–Æî)(±`ßûp®TóPÒŽ;ÉqéÑórå±´,‡Z]›GÞ¤¤È#ûß{Xé\ÌÉ1lžXæÕW«\Vx[¬{þS‘ 0Ðå%¶Çõ3gKKË ÍJñòbÏœÒËy£ÓTY'!k_Thf‰¶È9^õ)õš_ ùü§‘7ÛQx楀Ñêu¶ê§ìû•Ÿmê`jÛˆŽ¨²È•PìÂÇ’$ðñì~»ïÅxÂ/#ûçoœ#(e“óç~á*ëÛO³œ*ˆ´+ºèdhŠ ]ã/?-ƒÈ§^!P ¨D¼ù„ìü‚‡ß€r¿=œ#Qí<$1ÏÉź8Ýn‹KDJi°Ì$¸ž˜±LgGo¥E*JÏ•œ¡§'[|oí›={ódO¾jïµÊúߢzw¼MêÂfÀÅa¦Å‡eö•˜{$Ê7Æ<ÿ´£5ªß¯[ñw„ÍÔž™H‡h3ô¡Â«îW7Aâ(·ûDæ(On0ÄN{÷òàÂM\¥ßÔ /ö CPùVî#_Ýô) çLý:ð3Ñ^ aýøpe›òŽ_³RqFì2u™þ²j©„æ ØPf\ú]Ææq†"9œ<á´k)õ„@&Ÿ·îH—†¬ôb³ˆüŠŠŽ§ö­eErßk/œÈcˆ[è·Â\À`ºwðûh”ˆäYÆÚyçD!n € zƒ‰cYÀõvÅñí¥ fËE9ˆì&p±cZ‚Ù–Øh¿}r`ÚDštòÑÈf7þ£¨h} )®s0ßå,ö‰1«÷öeU¼| ËßÚ‚bÎ8l‡¹P‡á¤äzÁd°v ¥j²õœ¢i¦sêâá-Nº.²bÌBÅshêÇXÇj °XØqõÙqÎÖ¿¾Y½å ³hõ;Y ‘ð"<ŧøioz”AßÈF>ÌÚmNB*™dÐÝR‚Loß ÖùÍÒôB’€€ÆHAéüó¬HûÆ¿3'“9šh'HA8þùõI5:¨4* Jø“D9$¦ø•ÅÒ¶âÆ”F÷îÆVn¹K²H[hù× ñ’”â{éåJ4UhBMùIw®tºÆ$ÕL?θ‚Òâ ]»U©-jümíh5\1nÆûxÕW~ÐR ”EŒ€¾¯Jò}̃§“œÌÑidm?È‘ÇP]Ã9QÆ3d äÜäsÝ¿(cœ´bÿ‚j<Â/¹ ÿh$—î#':FŽæ3tìµêXûöu¸Ò¹:#9yÁhSj’À†Bº¡ó8 êåtïCßk¬vA›2v»6+,‚¦v)9Û– _X^àCy l—LBv­¬9éö %abëùÈ&v¸àõ_ÒÛ·Âa–ÉÑBry9—ÃÝ…ÍN¹ÏxDÁ™èÔ–€Ìº¬Œ¯‹‡‚Ëú¬„æH€ížf0w¤ÎÌ Ö2º:Ûž±R‡~¹«U꘶ð¡^¨1×VUßs|þ*j½`Ñ?ÃfYÃ}¾ü„vŽð=}ËÝ7u¹+‹ Vé ´âÓ›rØOͼE¿E‚GlÑ6‘»G_ˆ¤ z+íò-‘z”,€A~pgMÓ;ˆ ôxYCÜÔ©\aÝlIîp%Wˆ®ý]:¹Ü¢n°™Q:Î#c<Þ5|˜rX&7ŠPŸlŠ™ÜiI£«¶jm‰ ÃMWü§’€€Ã@Ÿb³ô›9™¡Iëôá…½˜Kç¿z˜*Aéf–G¤ƒêÌZa§$hᦘÀ @SƒQK¯ƒãSqôwQ#ñ@¶M«š¤ à„‚ÝŸcÔ´ì£E¢Ï’h_Dœue³PØÁôu±èŠô$³IF§u!ÇÔr,’FT‡?‰àÂÂãå+Í&ÎX^Èg Úã%_ÈÝǤ‡{_ðrÅ8ë ÀÄOçyç‹V(ñ¤Å=¢ë³?Tý-xäsÿ]Ð/ÛúYÇ6VùÚhÚô.l 5‰' ¹ßuÖûheÚhØX`d$n”ûMÜO -^à€ˆ¦ðž¥š_8ð âÏ[})4EšgØÏQl¥‰›¡CÕ~âlôí"ƒF]~y1ˆ“;„½÷à–áï= ÉÙ¿šQg^)„p÷É|ÑD]il M -#ÝMŸ60‚#çæ¶Ý Èœjw8”>`ÀÎRc#œéžžª JšðM%¿áø¢!}›óëQÿå‡~ív»^˜+„8å*c]2Ãzù#Õ‹4©±•„áqê ¾¹=ì:I ö§Ùe[Ì·9³RC¶;+ÇÅTæÀM#ýPÍ“»•ùד’éñ~ëòÙÀ¨\š±lh)„‹úT%ÿØoW6æy4¤‚ÛzáãØ!ú÷¶w¥0GÀ÷¬àx‹XÜ•àÐ:̉7 ·‘ÏdøþªS†„7ưû†÷æ¨:=ù5¶"‡Ôµ %³9MòQX¨©øÉV©µøô •Òª<¡g.™umlìLAý§¬°rž@· ªC}àÄÐ\û\vVs¥ê/u)›9ãÑÇÉáç?Ö„MÞ|!õ•üýÑdyfèQ1“‰ÄÏLŸÐB`G9VÞáÈc.ßõ wz5p/«ZÆdR›é;LPá£ù‚œ:¾Œ8˜[ Ñ¢-ei©óÕ$Üɶ4·‘”³Ý÷a²´,M©µŒ«PPã27"@(…ÑmÊý/›·êö­j¢Sý(«?C·¢Ë¼f£ê_ÿ7ÌZÈŽ±bز¡£¼jþ=VBÄV -è¹Yn|‚ß?rî|‡€|"¿:œ¶ª’p(º}~¡'…3OöxÄðØ"”Š¡¬zjÚˆ;S×Çè’8 Rß®|LD^öäX¾ì3¦i“9Yë•‹{œìë’€€Å“óY¬Ìuf§'±Ù×I%b“…$áSukãðHaû9‘¥öæSÐ1ƒçÐv”?Á^¾"ßp¸°=ŧq¯J’+Ìh‘çÛ +ó®i +q1^ÈÓ©8™þ3« ûâ@á뛚¡y<¤ƒS0®¸Ju BŸ`(x ’X“d¯Ü‘Ã8.C¨dw¢( ±úßÏÕèU‘‰7Cˆ&ä}¬%h-âÑ;G ûßgß;‹½}|RvçqÀ±ê8GªÜ“nÍöç¯ßøàRÎ$ëÝO>XFª¤,dŠig¨g¥‚ ²âÌÃ÷»ÉSL$$ÐÖšê8“ɫX…„ö“K_ÏvB­;ü `â8螃°Â‚1äTgÃüÁë¯_vÃF¿qn5NBõÑc¬¡aÔ[C•XR’äŠm"xuíè`äë(‰ÜËS›öâ•0]ªMz rA÷Ó6Ž©ò¿ŒöAÑÜz®ÔþªDœeZ¢(†éçõ3´v¸¥ž¶ Œˆò¬BQ!9ЦÚéÿ«ëö˜†{Zy½©2;ÚEŠÚŸ™à]îß4ÍÃ? ØE(„ͬßðÖ!DÿÞÌ#”î¼fMÜKg®6¦×¯"ä&ãZÃnrNÒï ž‹‘¨„GDWPßpÌ{<Ómþ0èá¿UÄ¥_HºoeuØy¼xMƒ¬ù7œmEˆ’õ¹À÷8}ãAx׬C‚˜ø%Mr’”„¼­®ékUò˜@«†JÉXœH )þØ?°£?¬ÝH†Ð?¦Ãdy–Ž£4y.¼›5‘~ÏSÓÕ¬1J²‡Ve2Oðþ_[bto>,¼ÌrynhóŽþŠÀŸ¨„¨3±*“;¬@ÿÅu/~7»J%:Åì*7ôïH–¦wεŠb2`=•Hp!¤âöó@ …7CÚ§¢ôúY­Ì‡ñN{šAë‰6—ñ0ªß}U­§žî Lç' ¶ÜgB=p*SÓÈ¡ïõ.“Ç¿¬Á©Ì[*’€€Õ¾vù+ï¦Û°B„©WàwP^®6¼ô0õ!·<§ïrðÊPþÇ_ëS!éê*¤½4­Bàû6aËGY—©bÏIì€ y,<Ðk`;³Ù³N¥ SÂzlO?›H“B+º“ŸÏtln¦%2ïè6·x:V®Ú]ÄŠ‹Ë@9ùžÝP«=Ã5%Mêêã:LÀZ¢—4èR· ÙL¾L2Ò1îÒ ?4²¯m»Ç©Ÿ”`5›B RãÊ2yäÐ R°»š¢ÛŸKXá>_Ù¬æ€úƒÅq˺޴bTŸ2Üà«¡¸w“c ¦öÞ¿oƒ¶Hb뱇ÊooGÛœ^'‡9H0Ý V3¢À¥sæ”~g†‘šXx]ÖH€.7}«Hp‰$ó™ÊXN(ä×Kêa3ܱŸµ‘»Jþ§=ï.°| \)ëÇÆM(nmH - ÄêÙè³9 ‰€]T†;§pj*HäæEî0 ìÇŽ·À4žm˜4¦’¤¢AÛØ‰ÍiÐôá¥6?Ê'IÜ"$;B¤ùv(ŽÏ´if@Zg6 Ü¡kxb>îîºQX$äÓåHvËS&ßp|W’ eƒ¯ùÐ&¢S›ÀGËE5ƒ'q Upí`ùbÛ{‡ ËAë]ò“åhMÛ X³&kô ÀæmДiC&€¢æMùÜg &Œ±ˆ%aúÜb ²B¦‚–Ø•&xD½<Ç‚6ÀÍìN4‹UˆôÉo¶ofˆåËÿX¦–)ZâºAwOMM’=ì]ç¿æÀ¤Õ寫\û„xµ ¬Á…:Æñt/Ï¥—…Ï©Œ¡Ëï;gK$§³¯ñ<+ø:DÈ\‰ž³øÚþãþ é©À-ØžgèÃK4 \á2×H¾…s‡8èÐdm¾5°hD¬ÛÍvÒg ÉkvûK³wVÞÄö½=÷ËéþQQ±áÌ5¯¥ËŽ ãœ.„çPŽÖ]"‰"bþ«2Ê]ˆA&_ç'*Ù„ Ö˜½×éÁ±”_©}DiIñJ~]SpÀ ·iŠ¼Š˜œžÿÏHÕ#ú€/Lž*_÷ø‚\m9Á%á¼Èл O‚ÞÜøE`Z¦º;x7[h^ß•‚6Ÿ^/5\ï9kìYÛöäLÚs.€tëpw„}o½¶è­Ân{+J4 h„ŽŽ!²z˜ý_v}ðUMYÞpb!lò›1UÙãÃÝýï5u¾­–·¡é“Ò0N¡çÅäÞæS#ó<ëV˜æ¾X²7HÙuMˆp$½Ü©¸ÏŸƒVw R¥ß·}ÐÝþ¸Zœî0= «éúÒ°¿‹hU !gŒ¤­›†oÚj`Bî[g,LkæL:kÏþò̹Z6ز+ã-üB¹Vᩇ¦øE°8üÀ¼?F$tßYP²§hƒ}FÔŽ«ÕTCÓ‹§5¼¶°m×]aÖRK®™AœuÅ*kô™i{™‹Âû ßfÐÑV@ÛÅ‘©}cKDE[“j€¾¥OD7+«¯ kžÃ|Î*hµ~J¥*ßÉ! `¨‰Íé§Šµ”ÒL`Ædá_÷¼ø=êìEc%v’Íáe0_è«Êe$HÊ_½våïO n/¯²R©ˆžo^1°13#3Í_ÌY¯œ¸³¥"cµ]S‚|@4“o—gËÄ®¨oÝpø ÉJ§“ŸnÄùÄ)U™ž äÔIŠcn• Ã{›¦ÃvÄ¢ÁWÊ)94°©I±Ôµè´ |,@;Ô˜h†æÇS™Ç«ï‡ƒn ’€€½úŠo69ï—ãMFªD\p µ[ ¢Ì»/ ? Ÿ¦úSó'‘4é/h—s2ÄÑCfõ$~zJÆÒH”W— U41Úƒ³ñ@tm@PÆEŠK2€µË`ï»´yû©n1z‚¯­–b±ç±YŒn¡ð–-Y_}ßÀlz¡([-pê"ùÕ‹y[Á È÷I½^ÕÙøÄÿ†Èx”ëdnÄGµÿ/Bk 4 Õ 4~<7‰G˜á62ÍŽ$èê,·­†Q7Ñ£bÃÿ¬Ò"óæéãS@`Ô(}MŽrk•²x'Y S§T¦„.ì½Hül ²‘Ì)«ÿ÷³KóÜ›HJÓŽÌŽõeáJ.o>}¾hp0rÙ_Þ_d'°PlÈ|6‘G>°{ÉN¤ßçRÍ$×¹U<â?ηÆwC¬ ÊTXwYưOÐÝéôµ‹ 3Ú±8p$-’ëï—¼¬³»7ʲ•iï§¥ã³ÓÂÅÃ(µž\r¡íòÕÜû—fÓs ?"&Ê÷a6¸ÝB†çpx8{ÿŸ!Ù×F)÷8‚ÒÒD76Vãh}HX*†œÛ;NA7Hl¬Ø7§tUª¥½;vÌ/Ï,lLõÙãŸÄ{re@m€ àmäMÃÉàщCg¢ƒ:ƒŠjvög£#à­Ùú0 diSIVè8d(néè[‹#Q7íqöúf¨ÛQžq­ÑkÀgmµ"ÍXš»¿†Y3£¤vv)•T—C½®[›ìG0—<âk¨TªƒÇ&&O~¨áv@,€O»¨È^Cë’ `!¹"¬…Áf»=—Ï÷\™þÈé¨vÕø ñD¤µ[XÄÆàcÑO2 "»ÒB•†ô=¿ŒÐ:Êå£]Ydß]¨çÑU4²®à‹µ»Îf~Þã™Ôa×±ÍÄ w…TߟDÅŽ8³yÞq þ¸²ÚÑÏïŽôO ‰ðÊ›P(ríÏÜô›EDŸ>!÷vHa'ŸúÝ”ÆîôÈ¢Ç÷Rƒãé|BjiÁ ãŸ&TWþöÄIÿ'c—h%ÿ2œá'.½ãÕ£ôd$îþ”0W_‰ ìµË ¬Q­i¯@pÓË IèQ`-$õ‰‰ÅÒ3}Ûöž­^ÁãþB—dªå0Dô¸…ý!T¤ãÉr'öשb> À™Œ­Ó±õÞŒíЛ<¼\ ’€€ËÖÔß+È™¾~ä§’²ÿÌ»üRç£ùû®'Q…”:;„Ò³¸as4Oøè«ÁšvDU@²÷ÖÎúøoúrÌ^ÆE ¶o“fVhˆ?Î¥5ΠÇ<+½PSB×òèRóq–8Å¡ßP¹C—yFXÁC¶Ñ§¬……R²Åzžô õe£ði•ÜF©‹ó%åB>ò]'­EF?ëƒ~3°­o mßýWlIu_«j‰Üϸñ Xx¸ÏüþbãÂW£ßt/ªê¿°ð/y•/-¦Ïi€q —»x¡vH’& ™8'CywÄ´Z:¥êš¾!òw;ñ®ïRCÌmÅÔAIT/ËE,“%ˆìh¬ÆõÐÇtL¼tìfE 9²¼vvt·ÎÒ· -±ôwV†Ø?!J’€€ÅÀ/­"(J:dïHø[LîðF$r4¦ 0CÞå™Üò$ Ú š#™·¾®”çÚl(¥sÇ<—¢ýÙ•D—¬…[3Ò̪½õà ¡ ÌìM?ÎJ¡øÕPÊ6ÅbvATàæƒý¨ïWÆóD`±Pÿ²r…;€^ºLǤ€1„Ï 5ø«Œ»¦êxªKIä?ïþ»a&b¼¼¥ t¼q Y,Îju$R$”®*ëˆ\IO€^gþ Âcáñ(BéxÃr5É‹/gÁ¸šº\RÉßõD%’]_žÁÑa¹Ï>”x¿4WßÚ ÙïCîÍ9Õј‚îVé¾ Ù©°{êêMÍK‡™ÜŽÙòñü“t?wË”‚Ch²ãç:N¿Q7|¶Ÿ«+UyfE& Wõf4¦û(Ùi@,Ò÷_ì’@i·¨Àãîu‹Ïx>¶°·åˆó±±Í.u8þÛæj-Ê/½#°{™5–àÑ)b¬f÷7Î×Uâ]“ýtÜ x«zB$±.ÑjV6ܘ q²¥|ïªx|' IU"óÝÙs¡ÞÓ‹3羊®Ñ<â=ÿA¢SKFµ}” þ•ÃC/!»M—µ +A ·"[Lnú{íÇœÖÖ­·}‘ué#³±nw8•‚“.¬ÉB|Gâe¼VùÕ?ÁåÏt—rÝ·ŽìÑl‘ i¬%yÅë•"9½\OmûÖÍ©Úö|} ô2np>ÉiÖ_z·ñÚ1r´8¢yoŠâïwß¡}¯œtÀBî(…ÏcxH,™Áêh’¸ñ¬ÇÁ‡ÊÊäGò˜ZO”ú #s®+!)­UŒ5ÑÜIjªF­Þ2×ùRcøWvÖ~ìåùÄ€zèBcÂ}ŸHLq0Ä‹¸½ý©"ÍRB¶rNs€’”XFC©tÕ±JTüdè=­'¬ÃÓ‚>ÝrîÔ8Giý±…™„°Ra|Ú(<´÷ôðÁÙ5Gqê9­x¾´MTCijOÓP$–&5`›¹QÚ ßT–©qÅuCJÀ5›&ÓÇ£qò³Òx´ˆ'fÿ="§Ô]~.pô¦ÂTGA†é«ŒQËì_à%Ì7/9”•ùºÍ@ú–þG³Lšl¼r¸ë„Ћá‡$ãÂ4±ÆF’@ç#ãÄèý™H˜àÚ­”'0*’€€àÆå„DÀJj`§\´ VG8¨k”‘Ô]„‡3y}³”Hô‹ëzÂSÂ)€‚ž¬\lnQrg¯Qc³çf+‡æFÇ*e¡ÉœûK6/´â¥LXüLUšTj-ŠsZÑ¿ù2ÊÒrl–6û+Õ½©|‰ÎM¥W¼Õ_®cKâÿL-¿Ô¹¼žÆJáw­MÚiõ˜-³T‡Ï v‘„+;ù>IÇ mü%ü‚ÉRž ÍËS!:X'`*dzת» ˜.– Q·†?%÷ÄÊ&`SVQ>©À‘ÝôKdhK(p Ñë~¯ì9óÄvÇ,ìè¶-Ø”ÓS±D&eA(¹á8IšŽÃX4@˜^°êÏ5p’¼oÝ8zÐ3G“üªs»oH¾{Œ!ü÷É9ó5¯Þ&°Çe tfpÊà,WA´"q$à¼dþFhv-ÇSd€ëKËÅ!ªæËÆDçö8ÍpÛ½îk¬•“?~`¥ã´éTÌ9z½y&Xg›áôŵvy–ˆ§­;‰Ï!ùQ¥Ø…t†Õþ[ÆC‚:ªž8ÑóË;°‚ªaSµï€! Ü6ëÅÃr‹ö-µ¾ˆ®=êÅGæ4ø­É¡)Åo^ž‘ä£ÏÔeÓrr?Rõ ˜n¼Lp:†ô8£g£ö¨Á#¸ù¹¢ßô9ü=kÔÆj‚ḟåkœÃÙhë@ø2í u“B*p@' ßuK j„T.ÈEs©‡ åµúaLèL9Ÿ*¤Uyÿp^–IíÜ+ô™1sŽd¦$¿‘çÛâ¦úˇ—7©)jÙ%+ãz¸â·±P [ëœâ+ÌÙJ&ÃìÜ”ˆ–v%:î.@ŠÜ¸hK6m­ŒäFþ&Ñ®î¹ØÅˆpɯüŠ2\ȃéçE·%®/Å&ßÛÍ?æÜ5³êõ…pPéü5ÊÓn%èïuÒNq`·pa ÞçØO ¯½ÜV)î(R‚ÎtMû•¬©r?ìP1 ñ‰Ÿ8í÷¤dµ>Å(—º¸U´>1ÜcѽYwÛ¹{ÀBæ'+JÙª±Zh“âNQᘼ– b«£‹KU6 _¹´öÈ:þj\ƒk(¿æºmðñ¤6³ EáŠ]Eâ;˜Ï F )÷êÁïª×‘: -¿JÀ ’€€¶ÖWÍü·ÏÀ2¬æAz0ÞD“’¿UI¤>&ËXvŒWct7ÒÊ*ÆgÚw-ëº)nœA”ÞNy®ù²{6û.$ðPäÑ$=I;è-Ô±N¦d±ªnKÿ^‹`,Ú!¡UÂ0_t‘pí-¶éé'–áðç¶íc0 ¼Á3—n¥ŽªÒœK² 7DMoé8eïÙ¦ð†pÓ(oK¡çÓdw¿ŽÕê¢ç¢P7JÐ XcøÑɶ¿¯7Y5Ü¥­ÙRÅßÎ¥ž?ÉÕ^˜ƒ¢çšM,qÕ!"N€fh½¨~—‡•[÷¹À“ƒnI³ Y ç0g3!6ǰ¸<ÆKD8„¹h.ž"JV Ýõ—åEU  }+ =¬Häéó¹ƒ2¦)½A5ïÉÃ8¤õ£ý‘~ _›7.:˜khÚ b¤`ux€ÓÔ7àÌÑž¤ˆS{ôžMŸÝ¾_'£ÄÇî!€¾9p–mí3´­GéÜÕ06žÚýÇÒzIÙ¤j]â)j;jŠ¿ÅJ÷!º:aÂ+J ÃIÅ©_p­!&m>WZ¼—›0"|çµÎ’âJ÷º¥,Œcü¸È(J»^O( /l‹?^´#[¹’±iù°\ð—`É¡àÊ,ˆúoÁþ[i/PÌ£Põu dkµß‘‘0,ÂäP–6ÛüZ?Ö¶Xƒï»¢}¥H&ÉÅrÅ^A”ô’iDÚC4Ì #ÌšEâ]û‚˜™%ŸŸ³=¹·Ø:uà•ŒWÇÖ •@7·­atT"Ò] ªûSø~‰¾ùc  ìo3òΕ(Qõgý:'¹+˜×Ñ\-ÁxƒÂ\Œ9ŽS©˜ò+ Õ’ŽŒ™(Û˜0AdÊ“1êóuåË=­qsË®èæSÌtqwD“¡Æ–´gÛ¿MiPV=Á4©ÓRí¹U:+t6ôª¶T­<[Q_иnÓùÙL²åƒO%cѾƒ ö·<Çmæž({¿(¼:÷éKò*¡&NôÊkXéõ5§ôvÇqþ˜ýbîƒ7]ªº'Ó4õÂFk ‘¸P\ùMÆìy¨é[ѽª‘h*@ï€E,Î)‹_øß±’4îà@ˆdíP.>ú(a%bKä¼nÐÎTR*“ÿ"8Œl °Ü3vr*’€€ÔÁÇ3@D€k bçŒ+LoU eWK–ñtb—ÚsŽjÆáøŸ“pÑD[^PÒ/ÛEFY«p"§üÛºEºPÐ`„”ûºÂG‘RÀv²Ñ×wê½[¯t؇¬âŠÑU|::t :•×"»Y8ÿG_“U–ŸHIkÆ! h…G Ã_Ñ,ó­‰p'´«L jvý0*Mè.ÝÔWô³fá” š·÷ª)XâZ‚±FÙË€É…Í ;ÈiFa@š°Ýh%¸{Ñ;«R§Á´ÿÝ?ã@Dr©Š@Â'¬#ÖLD5X-Í6äýæùôêL|®ÞÚ@€ê%TD¢Óø‹ç²ò‰¾ÕB¨áןþëe0 pxÜôð8Å{l Ì:E£$*^c•»R&®oœ€^Oê6=‚èŸÌWdKo.¿i ƒ7ë5-*Ö{Rn« ‰N>œºÊ»œÕÓÚ|XX§¯˜hC‹„ìJÜoê¥èa”%8lèv5úŸ`ID«°P$ç†Bö7b#^ÓfyÅíçÍæìväxÅÊhÕÊ”¬ ƒo;öˆÅ´齤pÝc(—ªÃý`P¢B‹Ÿ¸ÐÇ»ÆùÌ I*€ª›#Y.kDÝ-JݱôåõÙ 8|Ú™¥ Êjï>‰gÏ'T‚¡}»88¥ããîÒqÑš½)¬± fßÿw*àœ¨ «¨Ë\SkÿzÁ“,DÀ›+Ð#sÓ>º÷ <ÄØ¹Â’€€Æ…š…$×qÚ2™„«)PB¿–ntùÄ‚ãa 4åï õI¼î‹‡èC‡IØ:s¡Ž±xEÉâm×\» ®X>%Uì½Ã$ùè¹ô“v-2¾¡ˆ©ÛœëŒŸŸsš2Õ 8în¦Íäà÷‘8)*ëÃ*¢U­×‡¦;râd’B¦¥ÃÚäµñ®ö°˜vŽ?D&-Òðìú‰¶ŒR°âC"±Ò5‚ÄŒ¬£hŒŠª”E'Ò>g7òæýø¥FÔξ·ÔëMêy0¨¤ÇZü«†èZ¡'“âBiË…¾˜ÝŸ3©2$á9@;v;šõ³ì:‚ŠÉ”xaâ…בÎú¿ù5ëÃZ W™úx¦ûlWDX]˜åys+ð¸Æ@ñopÇ{<Ô É\}nDŇԯ¹;Ùq>3$•€ÅœTh6$ýÐæQ‘PÀ_g `àÎWž=ÃÃËŒcËÖùrsV²týÒ:8ücøEÞ¿^Z!J¸ù>øùǧÇzzaºú ã€8±sŽüͱŒ6ÑÇ¢ÊvEHHxS1óƒ…Ɇî‡DÍl4y»H Uõ{Ð='×¾ì‰èÏþÃ%.Òß; pk_x*2„Xã˜×NêxùDK ÝüÂìªõ®ïóc­l®Îà5ΪÛ,ZÑáúþûA]éÍ¥­Èaü¤£O¤AÖ6ò«âfÅ~ºG×¾XöµBKºè‚Ý9xO*V—nú¨è£±‘.¥Xf7«C©ê B×ñ7ž¥…~¾Œ1kP´¼í\õr¸3.h¼G[Zº›~Äh¬Ã“À¸*´‹ƒmkàäÐKª ìñW…jE.ÑñóßÀæÿ) }¾‹h{±ÿ†RQò3)ªrþA(v.ÈhýJÓ<Ó—9ŠiÀ@:› UÓáþK4Kñ€1¸ö§ DƒýÅ •{é¸I£™x%û$©¹a¸2d°—478mÈ÷·Q´ÎIà ü“”Š8¢psÀ\—ºvgaÚÕ£¸ˆ'AÒ©'9)›ÌB‡·}›H*øñMó”P=ÄPM6i@)^9N ´…H?„¬AØyvˆÎ‚øK‡Y»Éó2XÏJ<CºÉ‹ˆÌ`2£Ì~Ï%޾JÏ]idƒn?¯övgï®[/n!C­wŽnÓŠÇuvͯžþcm õlp1j äÒ¨ ƒi?óü°õñtⲓS[8°EŒsa¹Y’,‹Ôø€¬žÁ€’NæÎA×€†Ôèã¾ö‚šT›V3ºðEŠ5-ù×xç¬|VCÃL•ÆCâ\H–VàI©6Å‹¡]`@Ú]‘RÍÊ„EÍE6‘mn޾§Við^Ç‹Æ÷% H?Ð:¾ÂÏÁ°ßøí‘Ì6"¦tÛ†RbTaƋߤ>5*7&ÆŒVš_{¶ÜM¬Öl·SÚܼ+*V f`ã&LF#^ýⱺoC7kŒ8û¨?ú´©3³7\±tÛZ$`åv•¡/³ô´Ú ® 9Ç=õ{—°ZoÂ0È_ÔœcõëÞ}ÜçÛm yª}¸÷ö@R¢ÚãI¦Þ8„-¢¥#Ø^úŒÃ“'á`(iDÛÿ™ÙLU1YZ2ZgPtõ8À•Zã¹¼ºÊE*,»£#$Ýú!¶È¢âÝ>ú™ý㈰6’=·¤"hßyLð1þþû£¬¯Í(H;oþ]Áä{Ûçibe¥M#¦–4y¿Oˆ OpÆÀÜýx̽MJ Ê×Ìol> ½³ÄÑ­è$Œ&nê¥>Ô¤Ö ¸M/úe3í<ÚB`—r'7Ê!&t@B‰Ón)G;#,;þëë! wÖïMú±²-œ°$¨9üë9šû³®7üuõÐ Ü1âŽÉKÒ×~›ÛŒðÄÔ°Ñ@!%Óa‰íL£H±ÝV Km>ƒZJ0W¥Óói*óvÅê)s#êDW‰ÆqpjR,ÈGE²9ª£ÆsMÔj t“ƒ¯Åk¯ëì8áüÁ]¬þKj4Ü#Ï(û§ÀÓyŽq¶Å›gj&æÕòOôý+ž¢Š0áL¤(‹ÈMÈšž!“(ùBÑó]@ Y0Ô†)„—^ã‡ûðÀ÷*á$¿û À«|"Š1¢3Âðý% ¹ÿ\âô™Y¢x+¬•D1,d|ÖÉf Ç 5h ãÖ›Ás Œ’€€Æüg! ž\ÍhÍ¢ž kôŠ¥5l0¿}‚–Æ”ƒøäüqÞýCà0Þs£ï¹Ø?o¨Â*Ì–(UcM>2¶¹ôt°}V@û„{Ìš:[ßÛE¸ŠN¦ó_÷¤íè?¿þä¥ûuZsr'Ó¯Ô)®+ŸÂZÒ‰²æÌ"€ )äÔ>èn+S—¶¢á©7n—ÿÁ†`Îp¥'”N¨ÍH†…§U¡·)ê§©š*áÁÄî•’A±[˜áv%5Qj8ÄŽƒ&“­ÂvJð¶IT­?‡úÅ/CQÃŧCB®@¼bätÃFÓccqÙd«Ïæöü?Ý»cØ’^˜úVyn®èК3PÐ\N4V#ÜYl'ùyF¤ày›I–Èö³Òàó~ôÿ3êðD t:¾åõ@Œ‰ s­ä4¨ÖýL¦a/h‹g­¢Ü]¯“bß!ïDvŠ5˜kéù"m¥paÎÐñPk’u&Ó@ùH×®z޼l|õÔÎÕãâIÖõž´HÀí"ýüŒ°¿ÛëEf_Á+Nv`÷mMžºyH·í‘R³Y@>ÅÁz=TTæª\®Ùÿ¿uÒÃq"fPÙ ÜýE¦¿õ#¦âž#~€À-ÌK§s鸅F§ ÈO'\“:õĶŒ½†Žn-¥öD£“¶–ý€.õ纔[Ë™(9˜Ïʧ!x 491ä "ÉÝ`;LJ'kì=ÁÓ—.E$^‚q/íj§¼ŒÝ4]ËZ§¦×ÏÆia=“»7_áA߫ɬÁ1Æð8C³‡öÇlHd¿“üæônBظ©º¤¨Ô<DÍ8X*ËÙCz|.¼ÍAÎ:Ö5ã–ÏŒ:\”Ù¾u©ûS+ïi´Ã%ËÉ;'Ù½¨ŒäÝi«¨Ž´~ÇÃ=XYc<ž˜+ÅØÿäGÍRSuÛ£½õ(A¦mÃWX=—·ªªd½ÎßÝSn2—X-®E‡õq.uåg;y Š µ5lÛ‚äj>!ï=Úðã9h Œü¤±?‡A›ç꣉7ÄoÖ˜9Tlâð? $݃Òïê¹F"[ŠvË´) *Òs±ß4¸¯ìã…\:Ðɾ0Úk„C ŠÄÅ)¾ö•ìw™3ÂÛ­Z0»×øPA>Foý? P4/#—c[½]j:Þ‰‘ÒaÅû}ªÚÉH¬$s’€€»#?CEˆnŸ i´/I%`ûÎaÕÆBqƒÑ2DZ°ˆ,zÜžËú~Ø­ãq¢¹M=re å¾cà“ ÄŒSû=Шϓ—¨¾úˆ+Pû-Rr¼¬¥Ú`À³üeØY>Ð ?™sçÃ|xáv?kV›"yÐ]áæ¡®ÇՈФ¦J!ˆìj+¼7öý/7_ÌBÎ,èSxVÞ¾‚ÊÏ_òñ@‚e²(ð`5¿b±$l„Ý%0aQs]P+‡*$ñˆ¤HÂ…\7§ˆÝƒYùÍMjµù®ÈßÏR÷æ[l»Sá5'ž›ˆµ pžì1ùÃÒm”©“ã%ëÔf•Œ cKå`•åÁµ4ŸZ}»þÌ{ÉxÅþüc"çKåäÔ¨À§‚)$òƒ²4gºÊÞcã9IÇwO¯€ôV¯?ƒ“œQL|ÿB¾az¼Ë-k`«×Vú¦ßæ…‚•_ª"XÈ .-Äý+e•5}54?p€Wá¯GQ¦Ï¡ëÄH²FÑì³*Ç·ÑšqsÁ°=þ¢€7zÃ"@ÄHyðzífã’¥hɪ#xrmÐDŠ‚À¯ Q‰d˜w}Ç^C¬'é“ï:0GÚëÈ!X,l‘Î%Ç‘.*œô07 =³¥˜ôHÍÃWè‡ÙÝÚ¿‰øºHKþ]ëf 'H96^Ù˜)ü ¨Qÿ(U6ëÇK¯¥™Y̸æú kåÝ©­1—:Gûѣѱ×È~Û®;œ;Jâûy[M%Sƒ1®K¹•ùWµ~0)Ò@Ç¡W yòæ“]ÔEH¶ùP= ‡ U´]Ø¿¥#ñÑŠšèÍtô½íözs.h£Q¥rždáž8ÒMQœõöm³ÇŠ6õUÿC³4žàSt„ŸvÃbÇkï]š¦h‚à ¨SL¶!R=Mv˜’$ÁÏù³ˆ4âXÉeÌD»›½âé°¥÷È|›3|4%€d©šE­wÅ/|Äq5Pk~R¬Î/¯✠é \¤þê«F « 3¡°Œ•–p`-Á®MÒŸ_¢v_ÐOҠͦ.„F¡ •ç’]cÄÁoR¯€ÛüüüH8,ˆ gYZ Š"  ଣ¨ë«y¿4á0 åÊø~{Ì^ÂÈé’€€ªgS} à±kïIMŸ}¯¥F>\Sºä¸QX v¦¢Ô“OñŽˆç_7õå¼úß ‡qÛï÷3<,G¦Ðæ¥iß­<ÇÔÈðÚPÊO¦yž½C羨jäý£#È“0¬õ8J"¶ê}Mx„á‹ —º9ËЬ¿Ipí*ÒP?Ïaœ¯PãÜ]hgõL¯á)ë*MÕ`¤({Å‘YÃN"ÃTÁ/­R<ý¿*PЬ¡3»ž#Z%ôÞY(;ô˜n;R6°^›ÞÝŠä:À˜N`=.Au7ÅDÃW´9[Í[šp‚§°§cÖ—„“µJ—'¶eIÇþÀ%?’`Ât}0»î‰ã u{1Znº5à åºÎhq&¨C´ŸÀ †Qn™±ÂS¾Ô™=SŰõº¨ˆH1ÁôÇ3xmJò^ÜJ\Qà5¨£GË‹s•§²ýÁE€swK)4íõ³•b"†sJ¯Ç_b |{¬¢GQ™û®á*« APؼ|ºXµ|05ÉVÿ¥K)Žˆ0Ÿê­íei6ü¯M%}÷$ï¾¼¬=Ø!{9OgqàËÔ?¤º˜œzpHa¨ »‡ÈˆOF)×2êY|&`§èϰà °¬ ²«/ÌÔ,÷à|BW^Ò'Bº”§w´=ðØŒg@9ïo{Þ(2:Ä—‰QëR&aîFƒhUX™Ã^?IÉÞOJzâ+­Ž/UäP®%¬Ø M¯+õ(ÝïÎÔUJˆÒtž’KÖ*ô’ÕØ§s³¢ƒþ=²M®0Ìj·dìæJ[‚‘S l¡$I7ãcv”ùÒÊ2PБ‡Äd× 'oGH3ÄpOFàBöP³¬à´¬ ýWa½0Üj>]1éáÉ›)YMrÌá6¥#á1ÞÑ•x$Xåý_¯§1ò@ç™Ó{,´ëZ!?|e6f@óž?¡—.uü0ß_X]<`a({t¹Zl¯£/#_N‡=Øu\Y©¨x¾i—Ùª` xxïdtÄ<#ödnù%qTÿãov¦iâ²°^£ÝÓÇUïí(5 ñ.#¬ ùÐA§¡´Lù üÔdÌZ¢¥ú½ªîöQx _´™Éû‹¢7¨kDù/¤i0 —\µ½#QŒÄüï”vbúá9üÈ„¯Ç+µÍOxÖ’€€è£€ñ^DjëlŠ£8ÊùOøÖeÆÍ‡'öãPŠ™oUŸWJ)~\jH¨8’¦<~fÀe'h£ „w²§_ä6—{ Íi{:Àк$NõÄ;Èð¾ ™é©ÖðHd=-b0èÃh9 bÌ?¾âÿ€lrGº'0"ªÆ.…8îÌFñÁN½!°ÿÛ¥A"¼i çF/èo´Ì4"/5âçÛeþ˜½×k~»H] ÁRvù²*w¥³ú_O[,ÎêÃ` §‹¹(Fv™æhz{÷ô°ØÂä– ù³¾oõßYG¦øëwÁ’£×zàú'ºøØy²~Œ+÷ U³¹ô·u¸ëRGèúòÊUbüüÇ;õR=gy«¸aœ¼›Ë„gáºlj( ¬Ñ‹džáàŠH! ¡RѸ‡b¿+¢Ý(õÚq55ß¹ð]¾L ?»+ÿ!€ä|lg‚àäðø‚°“H±Ë |a•}†µÁ 9N’ÇãÙ@£•«=×ßVk4ƒSÉôT›_aî©õîŠ4ªyÃ.Ü=•v<îK¢öqÑC¢x—žœ rGuãÍS¿BÃìAÃSÆ­1ããÉ´Tg¬óHru;Ø},z›F!Ëü8¥\˜;.èbõ¡'æLèéK0’[óücµV%¨51ø¾ÉòøìSµ! !¢„Ð.w1ÒPÛFãVðü&ÉBYØ0úµK‰ê§dšÛB•ñZ© mžóþ™‹¸Ǭ¹OŠÇzyÿ¢D°t¦’çÈVþÛòîùþúF\{{ö&ºŸ·ˆ+´0Æžó>Æúƒ_Ǭ3HÄmªf7(è:Ê”ãïlu<Ü›ÙsÇ)aØAdú‚g=B…LÂÏt2r$¨ó>úQMd¥í2$&÷˜ºÜ*ø‡k=%þÃo\Ô†<}¹c ]ág¡mÓ¬%XÉiÌš™›SäïZ!‘›¿q8Û'‚àê@<_-”¸ùù ™«ÂF91NI<ÒÅ ÝZ[^0O#2ÿ‡^K^Ê¨Í €ú£us{úû9nþâbv[x®×šª/RŸÉ6l7d´™Çb=F›¯nÛàÂÚ¿šd—~Úà#„b›`qËŒßIæk‰‡Òÿº1c¤©]ÝKIÆÝ©WæDa›Qö_® ²Ò»«"—îû,’€€ä5Ó„&¯q4^ ¾&›¬‚_Gò•õæìf‹bÆ_BÞªÝNHá!£Á}µI„ …©nY}6Öƒ?í† 9þu7ÑòÃ*GÙ!‹A/õ\‘¼%·¼5+Ì.IŽ—&wm¸E÷¨¤0ªµ.s“º\ž»^€›½cºô¡þ#Üsp‰hA¥Œl”èm3u–2%¬è,¶e5©B´ò‘™oÛE5A®*µi7ßUòé`©ü­}êDc!´•6žH3 7ˆ.ò‘n<3Žö"¼i'ái"ýúzË-‰š/,îÕÑøÆ«"{.–o»ä_Æu¿Ýî€q(‹¼á%m8£½ü‚7,ü4eöOÒøéº(ôœñ¢[Ñî Þ¶Žj D€ [¼˜ÿ+ý°GûWa¾yîèAù2œ‚ä×jæêŽÔ®W¾‘ó_¾*'ãy‹ÚEœëŒù5"`?<%‘à9ON¯W‹Ö.Þså‡k5Jù Zpc›OƒÃ¸QR›C³6y«.GUlCgXÚòÅ©¶“Îþ%öQr°±GI:è "‘M@n•”C²ÁQ2zûG·hÃÜdÆqSÍ üZY¥õF7 •\º+8`“ޙ߯¢ÝØnï«öp«DªT'åtóZýo“˜W¾Ë‚¬SÏ!2™76 6EŸž°5|¹6ÌÝ!ë´Ùig·iW×c “~–s)ù…ŒÐëo3uÊf¾é5+¤W°ji"ç÷‰E¤Î#C>l.ôË—çWš|ê‘ÏXQ·ösdŽ¢©Ê,e"ný`Æ E|¡.½¡m- Ûîá¸( ‰ƒ°Ÿ#ˆï{U´Ðfû,^wç©€ K¹¹±i§7|{¦½§ÎÜC˜ÄbM€£yà5æì¸;Râÿáhe5ïÕU½çÄm¼ë"}Æ^iOfÓ’RRÜ ­_Ô`mrsázu=^ÓÿXíöƺ†‹1ƒÚºp FvI DAƒ²Ž3.S¯³¤%ÍÃÊ“\)åBuF¸"qðz‰<²1ZîÃïÀ’R%Á]˜€üœoÆvçE8AäuÙæ©£ÙƒS`$üçÌ ÙüÏ0ö #ƒ¹È×aæö¢ØÊYeYŒLe}ÙTq˜lòc9ì ªö R" Aë¥î @«è;@¾C°Ö„7‡¹]ëcûÔ¡¦¹-ç oÿÇÆO4ÓÅ•É=¶Üú/„*#Ì>§mçý1±ï ŠRWìiã%8Þt¹Ùªi4JÚÇd«“XŸt’›Û7™Õ£Ü`ØúìÆþï'ŒLÓ“³¤ÒÉýuÂlWæs•í n;G59e'™¢¨ŸÐ>•'{F9ƒf'B3u ïˆWfÈ—¾·ÁYM:e„1È”|ö™¸rWÎÜÕX»¨(f‰>FBù uÿ‹6“]àëÆÖ u'(è' ò+ ÓªÍd¶aíÙZ5EyPèàm5ëãî<¦¿ÑÆ^·¾€7‹Çkm8-¼­%½÷UÀ‚’ÃÒ²ŠR¾pEjÏ«BÛ ºñí¤Ç.ºžÍÞþÃLÝÁn×ða2{1 jk©®uH<¶&±85ÖR7‚CêhÑ ™Cë~PLhN)¡Þº3™(¡³÷>ß鞂҈Õo™ P’€€­SÐë÷Ÿb¹÷1ΦÿWë5°´·—rå¢ßÂú®·(’äÐàý}Výß‘ê¨)‡ƒ{ófjé‘:{qi€=Фwó] /NlräÇ÷çd£Ÿ$V´s2¹XJ 9¨±»Q*îæD§ÜÁ¢XtÚœÉô%Ò@×ÚÀû¸¶(L(H&Ó\{"Äý€ÁEfxj{ºÜ3ð˗È…¬g”Niœ°qr}.r“Þ÷ᓪ¯±À )ó]xùZg¯„‹ ƒ’™<'éJT¤P¾”– i»ásÑC©$’#ϳL8­ ù“FÂ~OŸH“|©» ÅD¸A*Õ®c>¸º+5˜\ŠS;‘†Œ¤L&ZÖÏâ"šÑYïå,L=ÝBŸù ヴª”‚“§ê³#„;†¸ @V&ãÛ·šªU©Y×X%@Xþ¦h„ÍÁ¯!lý¶;mD©Ã‘oÀ-‡jݳY#uyù÷.#7Œm´¾¬I A pøågüÔ†Dÿ Õ¡¶¦eH7ÛØU¥â€}Ú0¿ªXo£ÐP›™¨ñž#JAÙRÅXÇìbJ´!î¥É`6c DU²ù²Š§Œ†Ù~X•Á½œEÌ–~”ÀžBÁ+W˜ÑQ*-³îÐ9±ïs4ã//°XÉwbòKÍ[ Q70 ª[Ú8Œ†ÚTËÁBRYÂç@:»îGBŸÄPBûaeá§KF›¼«]v^cåXÛ1,³g:ïŽI”È‚ R§óyÑ/zèªéïv™j,ø¡ÅUb&J¿Ý ¡Ë2Úhæ(œæ,²YÅÁ»Ã"@§àº_T‚ŸãÁ ìO2’€€ã$……ò +ò%—íªC)Æ‹j´š.‚iŽ‹n:,Ž,DÎWËz û¹èv»('­62Nâ³5*óã/µ§lö¸”àùúèÝ8« ÙžÁŽN»òØ´uÇ{¶Â2B´Ë¼¾ÂDm*œ«¤<ùŒ±K”ÆMAþÜÆWùòðí‰ æøZ@¥ ò\ùélù^?.ZÑ?´Ÿ˜fÖ2òm$kófãiZý’Ý£?¨ïšQWíÌȰÊè68‰fSqÑm A§[`[´­ß…êêœ ÍõO`y ®LŒ½ÓÔžM¥¬BœÞ¹Ù~0EHB¾7_Æú¹±yôåqæ4™‡À$øˆ-#¥[“¢á|þ©`38 ”YôûJÒ"s­y‘Pýe%²ÿ&&"—‹i”Ñ1(¬ñs»i qòûxA ‚›-7†ÔkôôiÚôfÕ€nâjÙcâ@¼6Sñöû¾fÀARX ÍCÿ»‡—éPOäxdè¸ÂK°nêí„£è¹ø01ù¦;ÿŠ-t§{C h6K¾àê ØS–â15x.Q5CÁŠš½±8¨þp ÛZ&=‚U@â¿x·ÛóÎñz µÌÇ'Ìæz+µ^nOÈYhÜÓ}r_í¤RϽ+64|èû@™qBD욯ט` Pƒ"’€€ÏÉÃÝ}êR˜…Øh9pâ‹ÝHð>©RúÑ­'!6mÆZ¯-£g¸ÀqmÛ†ÚïñP× kÊx€ñÛš¦ÑÑtÆ‘—€¿ËvNÐýmÐuD¶¶S`EüÍ}à&ÍÔ7B‘™äÄ1ãÿYÌ®"vÐÃù™É @Ùëâíð̆·i+xAVšIŽE©rìH:ݧôx[–rª²îɦè+/¶Ì­9¿ù½Œ(Ø |AÇàͲx‰¦» ùRöV]èr¹ÊUAw,½ªOl‹kcûÌè_Šø)=3 Ôí9^ÉAÍ-Ñ*ÝnÂ?–âÅkŸM%/‚€·(‡” Æ}¨TÆÒƼ×l?ÅA‰)ÓÀLn¡"Fè´t€“.|O!!’īڂÆáiSD€ÎGy_.l䮯힢4Óô&›ËÑáõdeúÓȦ©{—ˆË†Ã¶&XC¯Õɕѭ¦¤Ài„y}>ãCOVžCûÆùð³¿|*Z´öH²Å’«woÓ«íP Cã®þ +ÓñxÉèŸiÀ°iç =™T‡bÍ7ῘáÕÖÿ÷÷.…À´dC+DØ(xîwöéD’,Pýblú|þH’] |¸ô2*XVŸþqªRVÇW‰yå:¯žöT‚K8Î7¢E‰ btЮ9†|Ÿå¦Ãê·Òû•¶uâ9¹lÀN+õˆ‹x~çÔP*‡ñýR“ݦ¤¹E“ädQ‹Ý†°¸& ò¸ÖæÁD<€2ÆM-Ž"qòN¯’Tãêx|ÖÇçdÐЖ÷ôŠ4Ø…Þ^þfoåˆ#ìd x‰zÒoÊÿ4ø+›n†ä㡪³´Ž}:B¯â Úê{ 0Ó=‹xøé³/Ÿ½8õÿ›S1Yž‚þu±p± le—cCÀ4óC%¢¿Ú©Êà Ýá&2K¶üC1¯IÔÂ8u-›òŸ ÿÓg´òp¢Iû«?¥j4H7œ º$ Éaàc]—ã¿^¨ï÷­ƒ3ÏMè™lá¯#¤ôl€’µ¼J‰ÍÕÂÓ“ÏçÜõòìäö[1M‚z8ñT4ª§û Óý1|–ñãEÁÄ«g²øa‹rf7!UÎ¥Û}˜ž{«\m‹åEìyé¥%qŠ/ßLñµï†UÍEå|‚‘äµÉN}ù™ìÚÕ’€€Ç[ÈËÿÞv*éÓm.õ¯±ôøO65Äþ·ù Á 0ìkÖˆ!ü+ZËFz„ kÏ,"ŸñÄbª×NÄ}é±ccQ1*Xœ;CÆÇ ô6þ\GmêÉ'\‰ýåîÔâQÛÊÕvh¿¬[Ÿ_P†žuKJÁx?Ú• ãÇï«HX#ô;²¤)D®{3AHuÞÑ©ÝyÎ(”¦µ’‘YšÆøÅ€),„˜#“ªÁt˜BOjgñ±{û5)Mݘ¶E0 Ó>äµÌÅ©3—£0B¸ ù)S´¢ ¥¯˜17›øÎ1 È—ßQÜ3V+ÒTe‘g/E¯Y†ûÞ±‚Pß-£Ù,šƒ»=:PS1Ë:Ñ]˜ßuEÿÅJb±(*g4(C€ü¤Ž­7e¨,XP³eD²+AŒ÷skð@áfpgkW÷EE½ûTdÀøíìm´+:ï—ƒïÔûÇxEˆðp{U೘PEö ·±˜Û¦€£u&|¬»˜úDeè¬4XtUû²ØŒÝA oÈenp¬À¡ók ÖÊñkÎà(È;+ǤÎë~¨~Þ¯û>ôÂ7‹®6B âg°õòFÝóÞ¤¯eôGt‹¿Ì.Qø`¡Ä÷jÂŒ3"jS˜–Áû~ÌðþëH αé*cŽj€ÇtÙ=ŠJûEïæŒ£x>ÒággdÓÂF¶Fž{u¸G{L]TŽ÷œ»ÒTDÖ¡ÄÒ\àégtÆÐ"›´x¹i ©’ÒÐÊAÓ¤)—]’|±çÕNݽø’´tä²=IJ$̃$$¨Ò0R¿€¨7Í…Ú\Š4‹ÅOw­Zþ¹@#`3Äfv/ànÝ]°sgTWò Æh‰kq™ÞŒœ-ç%Š(?øqS¡’7Û/E yÁˆÔÐŃÖn˜>Ž¡¡yð{€O™Cfh#ÐX^0?vldÿ÷áÁÖS·Îkòõ8”5>Ãm23(g¦Õ–ù7”÷ ޼¹ÏšgÛ*š¶ô;AD@ñ§VÀMtûw sÏ#`bXäÞÍ^?V(xi\͈‰óÁÖP.Y÷àöÆõ8"–ÄÍl’'q¡¨·óWhœ¶ÎÔ©ÿŽÂ|ÌŒ¹UU£qÉÇ—ÌÚRù&g@8Ý+b±C²ÛÙÍÞ]O1˜½·¼«pÛxù¤:b­0P~™\—ÃkÊ·!’€€È¡ß‡#éX©häÔùA°,P¬„0iÂÞJ?þþhžLª`\žhãEhM[ û°c:®€*y߯5~m·ü”øµ2±hD˜l–!˜N³bPͯ Ò'”žC5mxVÈÓgöï‚Ó­þ×Ï×jÂÛ{ÊLâ#ëjƒÁó÷Éow®Ïþ%Í ¨Òß5åDÈ”ó.‰#B’^7÷])Ò臸›Q¡áV˹`½ú$±Šá$ßÊê>\`2lûÄ¡Vº x7öž,?#ÙœkpÞž¶ L#‹%,JãÊ…@^àÒ"ݽq÷]Kº|ÆÖœùT·ër”½èJù@ù4é-úâ>…/+¾—8WLkawi«Êùű³ÈBŠŽPK±ÈDzu¤ü¢[ë (HRVwQ6Jb{‚|jƒÔvx æJñÓL‘[ºTÊú–Aˆ¬Ä—„+NK€ê šœ£- |¤Î'©ödä½–^©²FU'Ý u&½y3Îe•ü—ðƒâTçLÊI-Ì"QP¸;²½lÍbÐP…¶ÞQÜPÿ†'¢I{çÚIÃ÷U”èãdkÍ'¥LÌê©›@9&¶nŸ=ž¤g3&ÒßDÀBˆ37”ÅRܹT¹ÃŸhâl®Rª¸b+©12ò‡ÄðÀç4H9.\™†¯6Ãó4wÀ±ò±’ø¿º\p%“a8ÂAŸ©’Ö \¹]Ïã_y#”÷+i;µjtc_Ï ¢Cµ{J{ÀnA¹ûMÏ þäëO¨æº9èíñVåm "3insö›N2ÀÐQMßVÅú…×2¨L]ÈšÖ¸ÉÀµ¬°ŠKŠª’€€ÎØ Ç~,s…‡š*¡æ€.”%Âßé¥Ém9I1Š#BMÁv ˆöÔâST²øÌèJÃÍÅÙR~¡V¿ û´¯µ[®š]„àËÃfGp×N8½y'ºÓ¨pW»/ _vØ1Ï #¶Ðõn3Gi¾ØÌTD‰«bG½%+ ”Ü‹2¡¯Ç×§ [•ÜäSyêÿé°`‘{ û¢C3Ö‰'MŸ`™M‰o”ÔçfVápñüÅxÇ“ŠN•2X:›U,îðš2ÔŸG]óP%KE¸ÏœŽ;ZaªÀUñëÝPËn¢¯OJ®•q°ÔËïª4x_ë^ÀM$ž€=yëf6ýî燅ÉtЪ{r0C€šã×Õ?©•Wד»×ŸîU=»Ôâc9Hdñ×–+ë7‹7îá ÆCÅÿi#¦ü.ɱ짽-õi¬W¡ÿ½²ær}š3ò ¨ù–%`{å*1Ã}8}Š-%°øÈâß–uçæ1Óí©,D ÎÛýj¾£™˵ˆÆÉâq6)sË+ú<¶NvŠ6–´„/6:¦QU·ÑëDË›ÄéÎ;12ùð)‘¡ø¤Ï^þ.7NP[¦(:RŽÉ™ RåR”Æ}],ÝZ†ä?1_(`«I#:íü\àk¨Ã‰•Ve6ŸkŬ-P^Qý±î\fH™×è¯NûåØÌKê}W¤Š–äëm÷Êïôg#L+ÝC6t€‘ù™`¨ó½ôË-ÒÇœ9`O"‰g ‡\ž…HÐÛFä‡.E)¼Ä]~‚óæL&0Ÿ_1BÚHíÎæW†ýZ«bZJ,„ |²+ rC è-q éÞ&¢ÜYSë—R|›ÎoŽ:|:]I;&Ö;‹é9Ù (ÚŸr~@ˆß§Àˆª’çÂÊUÂÄ Š–ÎýŽÛÞýqHO~hD å@‚ÌbKH¡éVð“Y„{j(Þ Ç\±§oe4ÛF¸GÞõŽ»¾Âé¹âþþ&jõ¡h××Ëe_³ ÉñF?AIÁ:ÀZŠ®bˆÐêIÆö»®8õ¤?øÿ[`´ãìô*‰å¼èÃO{¨ HÇr„L0ÛÖì‚uØú4اÌôJZe 8´>åþ¨%gV2ÝL] È“Ç0nG1?Ë3ÁÛQü¢„±6Ò€í¶ýr,å¢<Öô8¨IÏó¿†o°’€€ù€+g²s&UV'w(Ÿ)9Éàtà-tŒ87¹KãDÚ’iE²ŽCà0¼··4®÷ çÆÄÜã'Ê @a†–DóÊ„2ʪ¬2µ„TϺÄQý‚Þ@‘üùucÄL‡U½ OÇ4¢p>Î`gá)ÀsÍ[Åœ^>WX5eGàxqšÅ[A:ºôwksŽ`wY¼;®T½>鞀hìm${sGÀ‡=[ÙÚ ùÓƒ$;Äk yʬ'1 ZrDd]ãê.~šL‡¤ sþ\+”9ç¬Q†Yҿ®yQ><ðȪò×Lªöæšæý©èŒ[«NoÄåfáÜkfkåý>˨£d?B™£ó‰ÆÉ.ÑXø·?R‹û·øl>¸$¡‡Xº›Ær¢ýúé,™ãèÖÜrõZÆA[ŠAôT³}GVc‘éÖ „@áõß»¼+ž[„¯ÁÛkj.[jjý,4Væ«Å|e‹øÂ 7ãQ~:æk„ljF¸!ß35Å;H{ínZI,Ëü~ލrº3ì}C†o*âþ¦Ð]¶ÔÅȹ›® E× ÷”ñºUXLû”Ž5ü’šf\ÞJr¢¶Qú-ð+´§Šàúx°$gŽ¿¯²3û컕k„ôU©î”->!Bç ÉÉ?sX™_qfàmˆî¸ôÔÊF±üÕo­t¼o/$@_ŠI«À…+ßAtxÑydzގ „'i­ƒ»%bƒÛÔÓ&@6B&ó($CEðâÕô5D0¹¤˜Ü±Jüº•ì7.HÆŒ¦?ÎîËŸ=ÝùÞ§ ºœ¨4U¦£àKÂH—¸ÔNpìJŽDþ$Žjþ–MgYIBâÑü  Þ—tÓï–fΞWnk¹l8þöù”ê2¢ù[_~zˆ&4˜aY¤¶—òö›ó+rà²4ðÂW¶Üù…ˆEGÕךշ Nÿ<ÿ)gæá%²¼)è¶(-ôRŽÀ{ˆ“óé3Vo0ô 櫬HƒÈŸ Dü67‹LÞ€cßǸÉ|…5~ô4O\}ŠNóq"’€€Ò•_ã`==ëÒ~]µÔ÷Dt9¯¨BñDžšã£“!à-“ü°ÖÈRv_!(Ƕ÷×Äyšu‚mÕ"9u¶²T^]ZUmd>ã;^ê1OÃc9xŽy8ýÜŽ$ØTÔƒ(íTzaâÁ¥=±’ÄRÍ'?P}þÚGù¿1èéSí73NÞˆ+öe¹V&ãíŸu ›å~ÈŠRÿe£5«y%àû ÞeüA®[écCùíç¯'þ·J'¦¿"cBûrk~-òÔôu=Ä•þf2¹ÌåÄnÞc®-›·Ë® p=lOן™QH叿ÆÓ¶äîé¡uZÂS·?À®„§Hòbò×—w´ióæk–(Oð}![Ÿ R¥A'*o§ò÷Wî6Õ«ñÓ²­4¿ÊÍ]µaÂoáwîž—lö+®¢Ö=vsŽ7pHQ[!Ëëü0¹gØ“â¹ó;p­Gþ£Ùl:­=a˜ˆeK¹`¥=©ž Óƒ"Ö¤Ià¢âmr®Î‘ô‘n,3ízÉ€Ä fBx]lå:©©Â}²j$‰‚±…»¬êœFf%ê,oˆáïáèX¸ã…Œ]¢ïn}Ò=PW<}WÉ™¢À\%¸~r]ÑÞÿ±Ð ¡¹Þ)PYr ¹ÔÊÒÁ鸗­á´ËÕÛß•¤NÑ”àÚ̺Ó0!VL’Iµ›þ}_ÊU‹{¥“`šÈ?>®%–¿õWa]Ž8=À´E;<‹æ6¤FóЭEãi¬»ú†Ö‹5 Ûó¼E‘*™(oûÓ‡ „æ…G§h,)>’‚}nÄÍðÍ(Åã/‰FY`7 ŸÊk&tqÊSYlølJ@ëŠ3gž³„r¢»-U:3i†ÛÚ74Tk#ìr:×±T²¡øcM€©Q¦³ép:ý:Ä­Tí&µ-øê¢Â÷ì?½/†Z_§Üí1¿©.M¤‡/mŠ$ŠÄt"œ¯±ÓUX£ÌÎ-MàÓ¬Y­G í7­jŒM=•ӲЈ§Zvaù;iT…öóPŽ6ëøµíœ^6)FX…î¾LÄÙU í#d³×~ëŒ~œÉ’€€Ú^0³Ì°}6ÑÄ0¤A “0æü“‰dvu°b¼Òï_ð¯¹]9Àìãc-;…VFÃh|KtõÌz{¨•çP¦ï»Éœ$=dÑ—hnlj¢ýuæîE¬¹àa§†¾Ô(ÇŸ×'—=^l4òîcÃb­Ä¸ÜËk_2¡$,+hNàÆZº{ðcoÂñöG¡œ 8t˜wÆ7¢Æ¯áðõç1tÖq:‡Üû:”_{9Y]$qŠY„ó˜"r1Üaµ]›{ƒÜªÄ[üÑtÌý=«˜#Él~e—÷‚>營8$mÚ³§aßf»Y/¢çqyì”ø%ãˆ^,+N&‡ÙÜß.ª^…7ÚÄÌÜ{äYä|s—ÜK£ïÊ€õ¯òØ1œÍ °vÊF·Q·5B°Ìü+-8QÙ®=¦Ì`ÏíQa"Tà—`qåÿ¦ú{="N~9o|ô¹ÑG6cl"J­lßÒö’€€¿ÉÇÝ"]ˆ´‹S3aÛ «4§, ‹Q«…ä]{¨‚¹®½ÝY—íôÌÕ¿¦Vž¶"q0)˜mÞCòºÄT}\ Jcêè-Æn‘ôJ¶„!g²”d>·ï½ïHYc Nš¨#šÄS@ʰ÷ Øñü‰Vƒí”ÿÂ’¬òzý²*HÖ—óâ·”X©ÝaülÔµIoöÙW.C½l§Mß/Ðû4b$;Úá%õn\z?k’§¬ìªížž¡bß 5§,¯S:óÔÜu–-ÑñtÓv®5q>ƒ'~¡öéÕ¢(›i‰7¯µ»m›‚ïtù®b¼Vtr,Ö§žq ‹Ñ6½$5maÑ#t¯–pÔ’ŒÇ±‘)yV ‘õµ§H_BÔ/[\ FMn£™AwÇ3½ß]dKß~ t˜Ñ \ï…‚LÎe³pJ3øßZ"Á‘8…¿^ý««èŸÃ DÍô­ÓÚÒ°+œ EŽÅP‚®t¿)'{Ï.´Òîç¢yÄwÆwàã twéÙ#væ~OƉkîS ‹²Ñó¹(#Û¢WvÏ¡ŽW7W×ðDI)LE½PtWס›éÚRÒÒÃâ6½á§UóoÞ± m3•÷$´t¸œžWÃ6õP©Òܶ@FOèSì­ ‡ŒoÄ˧%™ ´ó%R†u¯¯»f™x{y†—˜s k7Ní´„ŸäT[¼Vî·{‰îWî@‚×?Ô¨:¿¡Ë:xùh'[X§‡ ·ôw?ô %™¯â`u÷çѻٟˆ9]‚>·ï–ãØu“}£™º¾ë#Š$Wò33ƒ÷ÀŒr:¾ »ÏüØúÁí|õÉíežd |ìª%©‹Ø…îâ¯ü{”×;/%Šá(ѤB9sm!˜ª¹^ìg„f‘®hsÊ ÞJ¯U‰³`^6ûWQÙ)ó°±ç61Àµw¨H×TPí8ÅóWè¼6@sñ×J³aw®Áí´Awgóšue‘ééM/—¯–Ií œzòøMpìô©[Ýhæ×zÕ£c-4A(™ÚÍ€©œbõ)¸¨y÷8¤cþ‚äÃìõ×.Êù¤¡m·µ‹#GáÌ»3Š:)7ÄÈm „8Š&|W‘™O˜`õ-shÜU[ùPÌEÐþBd XºÔ«ÿúo^íU¸ŒÇÄk°(WÆ—’ÑP´Jùaë"©ø¡ÊvíÒÎÄQÖö²\sq,µé VsÍM ö$NÏ[W­Úg¤©?§ÿ€Ø9׬§ÐKÃ$@’qŸÞV†ÑZ ]“a3Xi·‰4=Q(G -±ƒ "‚_ÊùÓDûÒw13É6·ôõsÚ3uû*xÂ1l²ëR {4“-² ½¡v“–¢úL™,6':tÔ `Hov«‡X6½­ì›D|cÄÆLÉ×ÊxkjŸ7ŸP²|Áð‹Elöß BÛ_…X€O\íб}>ˆßøÑÒ¼í>‚ÈçTéBøÈçɵtãGÊD7g¿¿B×q]•i“²PÜ÷¿9RA¿J4-7÷á`qt+‹e¯ÅFf8fOnî%¯W„ýé³ðÿ6µÑ̆4š3¸7Ä(ŸãÕ!’m ƒ«Ñ×»“BNõæÏlG&˜ª}{B2Œ¹‰U¶‚óóEYâûnŽëuöôïŽË“6òõÁ)ÀkTP \Ý!!žËÎÞ¤Àm÷bdDcê.¤^¡>ͪæ\í³3„ýé™jWæ£KÖ*CùÌÌøqE1Gñšœ DÑã#’Œw›x¹áÔZ ¡›'×M!,3rôŒGŠ3JÔŒ=mÂé¹ çb¦_¾þ »Ù>WûÞu”L¾—ê}B/“õ9üºûm>f,¶…ëÁ”Tœª÷l·C!ŒõÞJ1X…oôŸ ¾X 1Þë|ÅÚ“bÉj÷}Š&ËÎŽž{§AÊužƒÓ¦3ñGذOW=f [Û Ø˜²~çqàℹ/˜íçÐq‚eEXƽ£Á9!K/Ì GwJ],ôP§ë$Ã[ k¤J\Ä™vž9šÙÏ´¯TÈâ¨)Ù€m°£Â,^ê8\õò1÷{Ù[À¼ý†X™23i#Œ‘ÿPØd€ä…ò¬&º˜‹HùÚI •ñ?Õ¢>ç/«’<žãÐ(~ðÆ`ì6ã>áºóÕ”8¬«´5œ´dÊ€á/i „?êÇ?Š PDZd†aÛÿTUéùhÜS…Ã(ÐYTñ¾Z›ßÀöUùkrϘœ¡’€€óí kíÊy÷Ʊ’ØTqÂÅ|†­€Ú1Ó‡ç,*Þ)ži©‹­z/ú¹ "ñTÓo1ˆa•J|8àM«U—ÌçS߀™{ HàkÞ‘ßHóÚýbû|M–3YòVþÏhÐXx Ö¸dÉWj=âf@5[Db£ŸaL™;1Sµžø× E÷|ÝFº§dù)Òk»Ëï·„~’üqŸ[u_¾‚výŽqh$9jçÙs„iÐòŒØÁ$´´oî©ÿzWzòd[Ïì}vÅ­VJCË!¬‰æ]¦ËR 19êDÕNtò Ñrçž©¶’I"YÏéeÇTA)"c¹E’²Ì±iZv˜3æãþpvi•µçk³€ ݇³+\”#Ér³âgç$‹E† -͵ƨ~%¢ +NÓ|? ÏÙhEº/.ºƒÖ}2>Öª•;fUžò,Þg C¼WaÓž·¤gÛ÷s€3ÍC‘˜££3î¤Â/ëDñ+8«â°ºR6ÚÔcP”ò3¢"9ëf‹1^}S(ÅâI×aPÛÜÿqÇØ„…¦hµX¼¼Ô¾wrl«n€Íg²99*~ Œà”êÇ~a ÛÀ7. 0:.nÇ}ý«¨Þ°ÙÝ/yÆ—I?vÉʼnÌ!šõfWRس¨‚ˆ|}–µXRRû]ú½Í‘Á²Ïe´JFo¾Ž—K«²Ëœ\î­s Him¤ûr˜A›ÁiV9çÚS/·F­#< ¿Áý×ÔÚT§ è‹¡bç²%T/ ·\Ý@sÙ"[)7ñ/è|°]d—V»zì¨õþëÈ^ã‹&¡ÆÏ_qÈB‡ªb±8V÷µù »ëP÷Kœ#‘bæ ”Éïþü†áCd+ø|Ê&ÞRm–Š/l.ÂÍÍȧMßô$ãÿ+»éã«õ²Å%T 1jêå¼}WæÝ¯{oØÝ²ÑYY£ïûðaþ>Xó–J|-é¶Ç~vã#àX¶tyò„Q*…¨´æË‰ô/p^̺qhTš¥p±ŠÑˆ¡¦1™¾»eRÄíT÷¹~e˜zÞEŠß Ò«ùØ„lå’hrkS41`±¸…‘Îw Æ…ÏýM„¨™—v„‹Ï;Œ d©¸`?ëÕ —G0!á õ1A'mðí;ň3ÜÿV<ÅIhüs^’€€Îrá–,ñÁ(ªÝS^P®lÆ–m_±^yœÚN¾:Ë/o—@b˳¿ZÖXÍ^<*f‘×/{qGŒO—Ð<1…ä茀˜6ÒàO»/=ðÛÔŸ½K„ø S83™O*¥_ŠÓ°ý¸f—üÛg†<‡Ÿ¯â"I™+ªÂ6îP,ÊW·ïeû ôå…yÖªÜÕv?P[0ßøè{s5OœI’hn PÕÞ‚I|‘¹Ûã‘R}ý„˜±jêwH EZ§“¨ÕxÒ º¸‘S[T^$h[eü{«zZB[¢ÑøÃ”$ðœn}—GËð}޽4ÎFYÑ1Vƒ®ÿ öR6z‘ÞQI¼sí¹t{.Fv6K‹ú³+ôµá—IºRB÷ÉÐ-qtÅ“0²küè-I¯Q.4ݘ?2ØØlÝ=u˜^¦¾Û¼¢éÌO-Çô!| ½GVÍÇH´ ˆØ¼>e¾j^—Á~k§ä“sn=måž—,<"q¾6a$Ž{ ÁŠôöSVÞ9Ð÷CáZ9]ÜŸŒé[Ë!×&Ò™î {>8Mø†%…‘ݘõýuêë YVcó‚zâäI…a%H&Ìúc"ùL}:y±¬b‹~ÕìS®ä…“`:aÓ0"`9ðŠ€sóèàõk4Tí;¥²êoÞØ{!k nÝDè}í ƒà:.G›£‹Ù?èaàƒv€mgj­0nmwè÷ã.à‡m¥ý~À¯nÝç‰]O²êÎÌ©kŠPÆÎöVi!£ö~ǸŸ6βø{Ý䆰 =dºG|WI-¨úp9³Q?7ì¦zÉ™Í"}¬§¢¬åÔü©ùVf—ûå¹”#Þõú»;\…C{}‰1îJÑ[6F|qÔ2µöIÖTØ-»¡t.btôg¢‡…*œ:%±•üˆ2ªX umYö\×*Ó¶j]åÓÚVÒhOJ®„ÏÔUkç $†È¶Yÿ ¶ö*²?ýÌ@'o6^·Xª~P¸uàû‘?ɬ‡>ÍíA¥<~.Ï( C&^ ­‰%v¹lØðÎl Á±ÕÎοúw áv®Û>º+%P$*OÒ©rŒ!Íe òî2Z¡:Nâ¼é9Ü¥>¤QÈP~óU5V\&üð|z0Ös~(AÉßdx>Üp›m©’€€Ù¸3Îlö0ÈQº'¼H¸`+’BB¶Øƒ:"õoìÆé0tR·C¯\5jŠêÄ,’³Ð`ͤ\²l ü1@ËéçålõÚß0/T0&¼Gì®!(ËÍæ²¬[›c ýž‡9ˆÍ¢M\“}uÀ“Ýb,>uû"€Àh¬h÷^B¾”ÎÜqN'dÓr=OæÓœÚnqzh±áéFÐÇ *†EpÇý.‘ðÓTŽhÛ—ELÃM]UiË~L«ìƒK…+ÈÆÃ/ öæ jAZquÂi BhCkó[òÜ4 ‡ÐFÓ¡dˆMnˆ›¿^ëlõí6Ý|UÎ/j—&• G20I¯¦]>J«—9¢÷;7¡Jæ'Bq¡9|¸r t…^G¤5¶Ò˜5Ü/XŒ,Á„)¿yë¢'q2‡†²t‚ê|˜ 7†5|>KsEZ‡Ä?sR ކÙþ_h÷n*çqC!ùÕ (ú?]yuÂÍ}^{lØœ´†68Lþ-æŸþÌ#å ÊdÄ’ÇçUÌn”‚PÆ3 äm*úuD:|]ŠÏëBåy~ÌÏÍÁàgÆy@©°úÏ$‚Eg}èœÎLÃú³¯ÁJ.­enL²ïí a“IWráj^ë$WK)Ý(1§´f4S—C¡)Æâ­B×ò2³$£Ç¨4.È~¾Mú€™†YüÌWä+ÊŽ—>Ž\%qþýÙ ¬]͆êíÈÿOÿ£Gµdw¹ü·‘È¢äN2{Ž ‘›ZÜOÓŽA½æÅy€ªµ`èh½Dþ¥ž¶HŒ:|~¨P0q6Ó>F*\¥ÄßïàuÞ´íJ| ü{5¸à­ßÞäÂ:nÕÅñ3­¾©TG†¬ô‡=HÚ\ »íVôæˆÕie»‘ù$`_)ç°ê„æz”ñµ]Ãïjû™—éòu?Ø?Ð|útD?Ÿñ±N†!´(øËš¿R}ᬶ˕s±h1ÿEóŒ²Zè8°“åcR߇ä\v‹|M€QÖ1%Š#V"XÏà×ÓU*М÷q¾’ØÈˆÉ,ì '÷Gð›^sí»ØX0m¾ê¿ÚÚX&6{Ò”©h˜¥øALqƒVUXIÈŠûtS½R2}DMè-â2M ,ƒ4—bEdâ{c¡Xéšþ2Šñr{ºS"’€€ÂÔêï³Áëž…òk‘¡Œ2ìRüÑRYeA ¼²C*n¿«½8ÒóLNÊýŽ]š1µ´8ÑÙjïÙs6ˆœk<òú5ˆÃ¨½ñs÷åADÄ~ŒHu›~Ä)»Ñ3»5»dèsçúFõ£Ó*½¾êÍAçYMÞ²ýÝ¥Ož ‡öyCa¹3; ¿;Ô*Í&$çÜareK»qèÂÓ#\°,‚Éhð†“ŒpØ}ºÒîØ”ùpÿºït?ù tÉÅŠQ“ñᑳÔ$Ű;¯b„~™Mê-«2A”’VGÝ" éHö¸í±‡ÀP ¬cýóB úÈÉÉRÀWÔó'èI}Ÿ  Úôù2ëX›=¹SyÕ Äo®ç¸èFCÝYóBg-߉ž¹þEeÄ–I¶˜Gòκlv1Ø•˜m[~F©H)ãPdSžQ@dÞ‘=@´*U¦R’Ýø&c>[“zȘò0µ§Pƒ9n~Ør]-`Û´ÍÃÞÈJ±æÆêß:C<*Ô̬Û0ŽãÅ2ѸÙ1OgVÐÓ”š+©·‹{E¦i lJÎ%ìÿºoÞ7sÅŸ=©ýÄWïv§ÃR8ÌQ2¢¯úÉI¨ ½ÜKR˜Z¿×x36í«Aöí‡[óÂeæàJ­ù|aÖ-o‰ØØÉ$K{Üàõñ۔䈜µ²A žEûHn§ji€ž) ±²®ÒÏ!B†©DŒˆ>»ì¶Ž¼{¯ÿåìÜû§¨ûAƒ±ñ©¶’€–̃'fÌ»É8xË@%8w0û÷·¯ ©V¸íÿÜ‘Z¡#I/K•®¢1œbÝOF¥ñbðuKçq’Vð½GÌËL¦'®ú¥[8}[ˆëúÌ>“wë˜]³<Xì³è{Þ3:Ù—‹¿‹:ºÑN)2™’€€Û©-_r†Ú´¼—úiûË´(à HÏLù4Efs¼âÀŒ›†ŸˆÿkPVü˜)ÿ]N$Ù(Â@MïP96|OµÔ2=½!xà^Ñ{@ùƒŠâuÒK<›Y–²ðÖILC æÅÂ})µ¾‡Äñ-ÃäU›¯5PUÆÁxl¸ÓVMƒ5Û‘ªÔKTi@iÿÀìÕÎã'qf^g¨IofËw -}-Ìwí2YÕĘpŸUùj­ª§`Iëâ\EAHawö$ä“gîHæÙ‘G|›hçå è ›¡/N¡S¬—â®aÿ å¿’€pô [|Äɤ¥IÙKIyü^‚™tÈ>rtŠº}Ð4£oCMqæ:Ýôhzõ &ÇÎòEZU”åÒc64@ŸCUVЫdÎÙzx¿9OýIw‚ùJá›×ËIêÞS4P(: "¡ØÞsv[zh©Ë7}åXÄ3ZõÍóòxvfì¬Ë¼ÈÓ¾:¢þ ‘˜&Tƒq[¾îµuïúïB*é»ÊXÿ‰ê1i©¶Å}zσˆ'ÔJi:Ÿóº+…/VYçâ„ò>÷ÄM­>PVqØñEÛvÑqv®š€§‡~Qňzê¡õ¶_X2§»D¨HíßÀ»¤¾´ò«çëDûڊס§Lc…½+°¼ ½ˆfÌîæú”ÕáeKdÛÓ7ñËß,/$ßWÕ-(w뢡HSÿÅõ ¤ËL(ÙaåÛý%ùΓ^L<¼jÚÇŒÞüÎóÓÈϼ玲H A½O®Bùñ“ŒÇ[ ý6mo¿^ék€V²áÔ2˜â„t1¡—ÝèT3àäƒåŠÆ ºxWœ•õ:Ë;ÈKàcÿ¬ ÿ‚-B³#ÉjúçÉ$ñã(ë$Öñ&™x¸ê\ʪ0041ÇX"Yx ±^«Õà-ÓâZÝah‘HR;f=ÇZºx"ÆUÈÙ”´¶?R©3J2Ä„Âá¡’€€µ£éÈ1ÅG©u¬ŽÁîB ŒËþáÉ$h*ú©aÓî=6cØ•Û3zv¶[×ÑFbmLøn ¹J¤¥Ëš÷ݬ̅Ø*É^r~tc¾þõ´ÓE„¼›à ßS.'Èë¸I žx‰,GÖ§#Œjr¯MÈåm²ÿ“?ØZ6ìôÍÅz.R¶Nôiý¯É)ÖÔwÏ›„<ËôÃ’OJ¿7Í ŸAÿÝxïwO ‚Ôñ4Bx¸ý_Íÿnží$uü‹ ¡Ï É@[ tÖ?‹ã–·_¥ïæ8S•¬¡ß4½® ù¢IñÐC$5‰â’LçAÜf’OÒ¦ E-Û;50ë뇪ÜX # ÙÙ¬}.hiÒåÇ%΋u=N?Jì‹TÝHf7Êý +Ñ1Ѝ›ØQSÿQ\œÁÍN ©ppJó„7ËSJyѶú½–š§sâqÝ#‚ڸǕrª¯Õ†fÕ¶½Ñ^oÛ Èœ6|óËÝÌëêuwÜrPb×FÉ$èN AÝbvŠRêàô©·ÝÃg«ã‹èé_­ý>HªôpÉrœ+ÅBC}y4yrX£¥ª Ym2¦OÂ'~ÆQQ^.2Ñ8c¼x3³£êR*Ö_ð 1æI`“‘ÖÌV\ —Uî6ÄœÍ:wJb£­u_ÓÛ‡7á]îƒøáE_¥[¹[+rɾ>²{w7_' xꃶò—¦ÆÅžöEËè²û”y¹9­.îïîJº¬MZ—£ÙoãU iú5ý7Ò…¤s{ûšØêwa޵ÉM2"«Ä³¡ gØç´ÞÌÃ:‡“ô‡ ô;ìo8¨ïïô·­ÂV+§-Æ2,Â!|x‡ðY‚M‚ .ä–1Æöp:?%è¼n§Ö8 ûÊYu»ƒØr>êÁ*æƒ_wï$ÛYQ±|Ôµ@ÆÓ´ã/_»û"ºh¯Ù.æ9Û‰gÞ™+ẫbr¦C‡µ7$Ë*¤›P‘ð2ç*Û‡X¶á²b}ÏnZ‚¼[5>Ê pÝ6RÞd Œ%²?|Ö*d#?³“8aìÓ« ÖÖD³T4r->§¤ë!ˆ{xù¿S·ØòìÖ»m’â ß0×3ø•NR†©o4í0 ¥å¤z~çεÿ’å=bµýÀ±:Íž Ë(™ÕÇ?í„’€€ÓÏ·$Ÿí¸C%ÀÅ÷ðeðÚiÅ5N²@­.ï…lFl"O¯-¨²nÄi5Ô ù/×fWi5g$%pép›s%Ê—h²œ{P/+“Ù$^4‘”•=£x/ß"~‰wïF–õ+È»ßhª%°–N| [kñŸ‚Ÿà”iÔ¶7ŠÔ[ü x«ÊÛr)?^Òp¯¨sMw?µùòqÍÜÐágøtæEº]t05z8çPxhð}bÁkàq×j‚¬Ç±þågÚr–AÝk‰&a9µË„_[ä¯3* +J“QBuþ ysÿ Äœ—JmZªH+(;)E¤^冸rÿÊ-%ñ0(.ªûÖÁW"È8jƒEºÃL=ÿ?qák櫃b-§1LRí]<†1qH׳¶B«bI{}àþ;šï…!«Á6[†Æfý\€…<›ÙRzªC€ßB8“÷™Ó ¡aÜ/ùwRJu\•ÒÚFú,|Œ¢(wêλ÷Ý똑…z±5„©'ò$ HüÓÚôo}w‰~¨3jž !g-…ÂB•€ó\¯”æ1ÓÉg²Ô™iO)¯¥iÚ.yËmîN¡zmM?ˆG3 =ó<ˆRrh± ^¤Ò ›2½bx‡`d‹SN¾–ÝYª 1»Ù»öy@˜y]QØ¥ŽÊÚ*,Säà½,Ýý®®Lôú0sœ˜$fÒÝsx·Ž§’;švpÍdæy}ذ5ŸŠwXÅêh„ˆ ã¯TÒá}ÇÙäâ^Âé`·i–º'Jí)“¨¦ÇôxèÖ~ò˜¿ø :]*í†J)WÛÿVé9…„FÓso޹POGJ·UÎ_Õ™ëÒŒ#-NIêù®Ñ‚ä €ó¿63 ´)cJneÙg:±Ó&‰P“Ò$çYmO¢—a:Ê 1’“Ó„ix–-I “`„•QÄ®…vuáû¦ù»›¦¿«´'Ö³pád7~o7À<¶šŽVÁƒù|•e‡,—útLtX¯yŠøÙvçý³PÈn JÄ‚ã%EL‹Îø–@u<åÒèÛ[Õ<€–ÀÕÊ܃E,àC¡X­aíCsû¾Ÿ§\HËh Æž¯˜ò±ó– ùdä8g¥ÿ ‘${©’ ’€€±Y{ψ…÷J‰k/E¤L•+AëÁ¦qýxTK\­gÏ“ý®¼n},°—°x© oP4ž+ïïø³t¹s?ÍðŠR†U°WJR§WßR¿{Áp)ˆ×[ä_ÜÌSL …¦ÃÆ`çJg[ÍS Zl hZÏÅÓŒ{¥à‹ å‘å¿Ï£È ´°ÿÂó<;à û÷™ßˆ-,u¦©Žc#:±•¨áÁVÍPnkóÊaûûF›óÍÌs3ÝÓ!·æ´càJ”XÅÿÄ¡/þÎë¶—ñm¬P#ÞÓôœJ÷ú º†¦y¢›¼ ±âÑKØL8“èÝä礸 >MTÕ´ÞEpKƒc"š¬ÂÙÞ$ÏÐÀ ;á¦(KÌu_Gf~e¦õN—¨T¾ ̓Á#5ÎB"]=/è¡O¢ÃÊè×k=èáiËäKñP%ßž~³1°!ÒTä/ßð‘åì@CpŠð¾D;Oà ¨V‰ùõ´™ 7u±±‚ ï%߂为FÀôÙèÿbc­šbߨӢ”ØY-•ZEé…ÌLO€êÔ žiíÕü½÷öšAðê7Õ»JFCÆ &å\òÉbù·꟒äúÃʽÉnòX©µÁE¶[ ýs¬@Žãì˜É|ù®¹sW¨-• ËèI!Y£¿ÄR›®lÙ+Γ™ *‘ÓCÂ1nKl7ôCèN†Ág¨pšè^ø`ÞC]±!(xÎê“Á˜+bß›5¬«£0ûç0…\ 9Þföì1è‰ç05ßt^‹ ?þðÎËeìB”›¬ðᵤt²ï‰·%AüšÒ©êÅ•Žûªú\†-м¸3±¢^ÌŽKL¬kMƒ»°Séwx¾÷Bq±v ©¯w‘, Hulêí¾ÎèÙ£EÄ$ZKG=$C0¢à©É7dCh¤Æ’€€·œù§¦‚!äjBnŽ¥z‰òÆóudã }¥²‚¿3Rx­o@²ê¤ö…óëípÃ/ãÄ›‘‹XÏÔ’©ù óµ­÷úüãgª24&ÏIl`ãæ¾ø'¢£P„7t.#¡;iU˜oŽœÐw â¦q´ð=Üîoʲdþñ‘.oÑÅÄ–#¿È˺êã¶ÄeB÷’gšæÑfm}³æóÍŸdùZÔ á&0ßDi×¶þciÑu/_;)[,±msé ÈŸ{äÏ™ˆ£>?ìpßl±w¤¡ví=Ìê\NjÃì&Ã4:úXšVö\/qg9JmÕRñ,N£Üy£/r‡¾“‰âg2”÷yì; Ê]X_q‚„„B>Æü-»Ç·ÕY H‚qêUÆâr±HQé‘%I àu‘ê¯úþ(æì¤cQ¨¼""‚Ú(q?r31Ë¢~=,·F&š†jiFˆÇRÈQ¶2RXG'øÌ€„l»îÊÀnÌmˆé¥ƒZ t13/f™2Qú6óƒ¾Ýžé’µ+¡ÄâÅÖîÀæSýÀQ^Ìš± +^˜L}† ‡àxËC•„|º„°¼VUî¾õÚÆþvø펞á§ËeKÉÛO®W¸Ú{‹Zù•Aâ †ø¦ ’H™‚‡Hb‰­‹ö ŠùŸS¸²¼»öIùcÛ^½õµaš–#~»€ô ò+*Øï¯ãgv®!ÁŒnG #MUÕ9R_¶„Ç–i‡–áÀì£Â¹îkÙX§,o²]ò¡°iÌÅ1\B Z%·À#œÆu6»+Yœ H()Ïïó¦#pK©Œ3€:»æWÔMå8€îã¹øeüâæ Þ}C=£i‚YGD;GöU̘c=7‚®%i&*±¹­–Ùg>"`Mf×g/º1€EºÓy¾üÚ‘.bR¿¬v ÿÄB'‹tíC>ø)ÏÔW‡5X4õçžiŽáb]ÊMÓÈu7Õ£ùÛ7bê#˜ƒ0ËÖЛuà'ù#õ^/™O¶X)9„þUv ½4¤* [½Âû‹¢A¯ˆsÉé“ ÂÄ#Ët1§–AEݕʧú ù¸7F¤ lž«É;'Ù+݇¿íý(§5F7L mx£«v3§OÝ«ØüÞÜ’€€ÜÕ¿\¼ë`‰Ó'-ÿ[Þ—it„†gþù/cÕÊçãx½ žåL¶ ÓÒbɈ5êΆ&Õ8°‚o$‚Ò=¥\2¢Voêv¥ T1e»4OR¯èiö¤+Ï<nL–¥D½gQ`SH(ÇÚ‡:Þðxc¨ƒ,ëðÓ§S«e ÜA^fœ v³œÛQç‚éb=Ò±Šûeê×Õòs’‘«×ò»V5Gd¦7Š´ù´…ûû¢†»×‘*³ùÀse¹Ì`C¾ë Smž?•T଺ƒÏQf¼FË©ØO!Çý¼MÇß]â7I»v˜ú`q‚2ÀÏ1h™é"ÕþpmÁ3¹“A™ˆö |—–­‚£?¾ñ3¸ÌFÎÈÕ¥.þ¼'¹¯¶ù€¯”ƒ˜¤¾cUެøA!ÔÞƒµ¨È[Ù…ðyxaH]´É°à·¡êdËG;xT‘d»`ËAÊ1>ôá=²×ç1•'›HM¦=BÀJA53¾@'Ý÷cs‹Óe]Úut”>H 1SXﯣ3®Ûìž^üjjÕÃõo´NëÐ>-¡4®¼íÙ¤–Ñæɤܡ.:ñè ø£©'_¬ ª¼}‰H¢Ã«Ó1l˜HîÄCõt‹­;1xuó°z+ÚŠ_—XÀº8ÈQÁûYteuß+†TÐn®ƒõÐÈs·'/¥8Ä¿Q'cÇóNn¸µ`«Ó¦­[¼ä3)¸‹ »Ì"ov U%aUû7¤‘'u Á&FhyÒ.À3Ø<´ÄLk°@«É(ðϾ¯%œnpƒ^_Í»Ú(“ïšY8C½—-vHŵàýwÛÁàëÂé =wôÏÿYo°° ƒ["À¸˜ÕîXXš¸¶˜„`#ú;«èÄ'jì°5¥;QW™K¶Ð$ÜèüQeøÌ< ßBB®‹ÌZ…8¯°7˾³UÞ…¶Ê¾r|.Ÿ®«y³Î®E²K`{Òª)"õ=&é¹j}ž@݈e‰þ*Úk)׊,2\¾MbÈäË£M”˜{JG5Îu™ÿÀ™?pAWvIêQéº07ìÿ÷R¶«­sÿ# I]VÉk3úe”¥ÒН|ŒHp1…ÒÒ»jÞkµùyOE}MÜMë²X Í$M„„ê•ýŸvDñ m-þ€ª6£S„M¤®’€€Þr~Ïk‹Úa£ ƒìå…úÌ—Áá§I…oô$ë gˆ‹œ·àÏνhòÏbî7àKX¤þœ¹ËM?Ïkû¹ÂU狎½1H]W×B\-¬'ŸçQ˜ÑK²GÞ×2Tou8,;Nê±×ü±?ø7x·í[9•¾µ??­ÀIÎþ˜î» ’º7?’ëL'àÔ°ÞÝfT)y­ù]KœÙ)#O ¨v@…‡a?Ì‘O<7Œ’î·L>Í€|9N5~L|ì|^4â ¡LhÕÉî›õ;ÀMGŠWÄÏÿCEË[°]¿âúãü}6ļ7,\³znÚß=‚i™ªó“P?tßÝX ƒ¯)!ÂáWG8†Íî<~šöŒäê!¾{ó60­Y"Np™‘!£Ì£z®{ì6œ 2AYzÇÌòµnÓ›3æ,+´Î›,™È˧t eMTO )Ð5'˜/ÈeïLU¤VÀ ÍyE'69›€)K( vá(ƒ—#Ó[ÐËä.j‡tãìõ!É L7¶íS“’buÌ̲ѭžRè–p̆Ñ'ßY¸5‹OøjØ]éâu‘ed0›Ë‰—˜ù—¼OPÓã¡A­i¯XdÏOý܇÷.’ºVõñfIÔÝU­Ó8ßCàçýv®Ee±ùƒpnrð»Æd–¬*¼äòï–îd\ì\`xŒ–¾;·(éóN2ËÈJ§µ0`y îc|û•ì çu3WGZ-25«Þ8ß·Á²ä¡‰Ä´y³ž×:¥±¤®k­Š”e‚(jòé§"Ï~ç‚G\¢ CRX±ä;8ϰ "`Ðîp²1”ñ¦U×((ð,ɺ£XðÅN¬ÖLˆ÷¯huKT|«qõnL,8©øyŸáÒ_…4‡%ÇÄ(Má7ÍÆ.£’¦íˆr× ¢ètæŸ?±C0/<>–:±ÚW*÷³]BoŸÿé½í­&>Wb¼-ç‹[´-¹Ì¬é¢ÿ'xxbýâófkõêŠø Æd¬"Ö½µ5²Étó¶Yç Ö7ø¼…¿,¯úA0eÅU;§B4§Áåêõo²æ\™Ï½P;¶ÌÅÉwïætÇuó+¦’sàkÊ Ô鉩Ü|úF¦qX ³l²ÏRç3`ÃÉÚ¤ë­u’ßih*{|<¡>,%¾-$½¦ÝH»Ÿ[÷]qk!`ЯÝPàÔƒX~…\Ö°C·‰è?gÚj©Þ9«»ê™!ç%¦?Ãe”@ZTN–ª|”u.^ÄX%³‰Ñ‚Wó‚" ˆ³¦M‘ñÈŒ2'zlóX‹ö“0¡‚^í(øæ!ªá}pÙ¦ûá"w.q]>‡ G à¾NÇÞ'”\¯“™YNêÿUº—­eûhó¸Ê{noôŒ|oUÙ¤±’{ÜÉ-º‚ 0|¹·Jç*â°4{ÅY«ÚÀæ9,£Q&Îj›‚î"xŽNK¸^33C{¤[òy2òNµPÐÅ9ªÉº"%s±ƒíï"˜É¥Ì„“zÐTÏú¯ibrÁ ƒd Qëi„oök ”Rš²{WŒ˜X³•± V’€€¦¥Àmï„=±ìHSýDj’Œ_î!(Û­¬Mu|–Š8 r —:æ ˜JuÑ—ú®\;šŒvÜ+ï´vÜtt~: ¨àIÞiUëãøýßÄŒ„ã;p®ÿÃ@äôEƒŒ®ô UÃ`zõ}GÖ3®Ô‰^Ó`ÕiC®R)Î÷>Ë|cûZÓc/©e!èì¡Â¥sï+.ÂÎs„âe±ußLQN1{ãDn•­ØTÑRûKH`h9fÚ7ñSÁ›Ÿr0žìmûT‹“–x|ÂÇÜRÓÝ¢B^DôžFi–Жò-Ræ®'êêˆËù½q'HrD¬|LÞ ÿ%G^ªÃ—»‡Ñ%ÉÈ©«eüá\G`aÄÉù×ê¤é-ðdŠ ’DafiÄ×83ôæ†jy1ÖDèþ€™1—¡›…™7Ä›ó*ËWSl¤œ³žC[IdË÷ÁÐ~µÌ]é#0ü‚3©š¯±"—ÊÁñ‰·ü«}\L÷õáƒýëË=0RäûÃîT)ÕïàZ\Hç—O!¡ýÙs@¦tçY;!-’°sQ–0H µ«HÝ Ãú£wÛóL›Aªöjût7»u.rÖ}•âÍ…ÚÏ%Áæ²É°C%%ƒc#4TK•óÖŒ|%Eöa”ú€Nm\ ÿÛ<3ðžŸvö‡ˆ©œ¤]Ÿ¼ÄÜy<]Õ³%# Ül…+Td³Â°3™gÀD \ÃÏ£UöÜø·Å_˜¥$/|>‘æFÀk·öZ1_@dÔÕ$"™±p\XX‚®MSwÐF ûÄœŠZÔ…"ì§®Ì1U9° Äù°ðâ&MK h€óç‡Rw¡$M”=¼ŸFÄ Ùs­è7È8£Û©R^Å=¶'ÝäOÝÜÇÎc}ÒÕ8C¼–ñìÀAéD®³!“ ÿ€Ýä'´‚ÉÑ3ÚT"º)ìuú,H­–š¿8+˜›îî}Â¹Ò 4íÄ„÷o­íCüñ²k‘®# ¨ ÓîØbñ®†ÅÅgM‡®ÝkƒU¹£ é% —ªøÕäß” 0ÍŒuY±+åÝÜ žÎ•wžL­m2ϧ?Dÿ[ C…­V²êHÍÿnô~ô¹X­ÀQ²:Vi„B[ëD`3N&¬tn &ëÐä‚7Æ^Χ~Á¬[ÞW—] ή{ Û²¸5ZµªåBÆÈÂ’€€¶ònÙ5À‚èâÃ>öˆ½ 矦ï+iN¼¼ž¹Ÿ½å“’{^ôdK>'Ã<Š÷Ï ²wºï‹õq*PIM(•nvRâ¿‹Õg]L <º P{S™D¤M¯’ PxuʴݬêÜùæyœ!µý5щ٪ëìÚ/W°Ž‹˜Ml° +5vš áin„_Är‘ dv½Š’û¾‡6¥r­½®Åmæk0¥Ï[cQ;5ˆõÄ ?åÌžÔ‚XšÝWÒ•¸«*…‡þ‰ZIÁBX‘çNÜ~ åÁ· žä?3&îEJEöhÏùVcÊpá³mÐȽÆÚr‚º¥ZKùÖÉù6¦¬_E˜Øô'gsû}šLt©LÎL¡túYQÉÔY¶Xðì/ ˜BåÑŸlFYå²´RÖèÞ§9©Ò´ üõ@Ö9ˆpH³âãa&4ÝšiKd2YV¸“ïpÚœ=xñ¡í“çèÑ}I7*·dâdžéëâö­êßwÊÅ.|߯½ü/…E|±³pÄá¸.ÿŽÝvý ÜD³ûuAÁ:#é'­jƒ2]5. „M†ldW5¹ùÐ`#ïJf1¼ðí[~óvºžL$–t}}0˜i>LPøÉŒ&D×Ô˜ý±cá!‚zÅóôóE¹´ü¤žãò¼]ˆŸºèoð¯ÎÖ ³‚™ÂömQõ”d€K¹‹B6s…¢=„ìÂëÆVéP_— ÁžÊÄ­28¡I:…¤–o~óÊ/$ÇšCVZæBuSăø‡ÚªêùI­šçò«„ÄŽ @Ò1¼2tûxÙºìx,ê¹t£1ê*Í5܈Ye]ÉÝ@ñاNþ=Ê¢UÝ÷`KBVDz#>¾Óm›¾P•*Ã4‰~C~çlé—…(ÁL¨O£³£ïµçÌzr™êÎðÍxi½po«6¸Ý#5ĦâÝ™W)åÕÖ)=Ú0OÄ‹ù®3Ķp'œ0šÇ0~ ˺8<ìŽBÍé·ï Õ‡é‹+Éd×S€Ö èòjáaÀvÓª’1]ÞŒN²Ø„aœîâʶN™ËëЄgMGdö\¾g´¶Ý­¾ÝQ44'8ÌÌ“|õy‚ϘA—aç^ùø®¦ûôO„®g,X+\+ý™í+q¬`Q Ü mBÀ8ì~’€€¦U³ƒpC’‹…÷‰ÝÖ X( /,× úñ„0[S®1ô½™×#M(Ëy*h›/î¢d†kÅT8½™Ñ敾ÿywžÉv!:$g*yf 9ð¡§rLM^‚% V8m@‘I¿\ý±`ÿ‰Éÿe˼sFßOÊÖ—‚…‹;gÚ– óÈpõEgtÙÏ[(·×nÕEÅî=ý2“’èÇëeÝfiøÊQœ-‰—p`c¤Ç&³'íœ%ñu˜§/z1qáZB/ò’Ðn‚÷ÿexO¡Õ†WqÀ“˜¤18nUÞ¹¢MŒOg4»ãlÏ럩p2£ùçÏÌ“ÑÁÕj hþ)ÁjîÄ=Ðß÷Ò‚/Vç±ÐpÐc"Fv,6}QÁìK»z¨bPÒú—›\åJ8µAƾâ=¡¶›œj.Öµ¬Cø Ë/ £s†³B»wz%?±_¦+B/ê§Úòž`z&VÎëÕ}à}èÑéöbë@«zG¡¯›¡$£p±>Jºð¹}kßúÿ AÙüî>¶R.†aa „C5öª™.߈ˆ©úAÜÀ¹Î䉨ˆ¹Éº™ÔÅ:ht§#;‰Í7uGB,¿~©;OŒœ‡¿»Y°`Tì=Í[?ãN&>mJÛîtu¾÷¹’PÈtÏ6JZ¼7­ïµ™Ë\î¨qý.ÆÆ¤†6£>(ºâÄpù­³ëUÆû£P DæZß½IÀä¢ò*µ™Ä?m€öåG)}³íý¸ƒƒ•¹OGpÞ0WB’Q å‹ÿlö¥­ëUŠ_3€!"A‰òýAùÓ„i‰Ž{~IBJY;ê“Û ¸0¾,K ›jä NÈôöë6¿€—0ažÕŒ õ®'db¯ Èxøýœ-oAjì_œÛÑa—Äfsáôzw’5ïs ±ôúèåfoKqÃ$pu"½ÑJ6}ær™àD¿i1Õzrâ½¢:¿+á¥äðƒBï‰W¿ðØÑæ…t,nYn‚‘äÄ+ÁG$´Ú|®miYúóiéÃ…"ó®ÕÒÞÑ2)^á4 Q’€€¾’ƒh é¢x£~Psjœ°™X ð1=®È¢·¸ÿ«µPv-ol®µ“is“7´P×YÓÐzÙ´Ù MÝšËÑCÑEø8÷òœàlNiÕݬr ö‚S²¾­f>Õ4î¹ìß²çFb/bj<†¨!µQg&Íô«ÿ•{ pE39Û'è ñG$…Ô_D=?!t=œñ78ݶíÃGÞ”i¢¸œ)'Äk,\÷5ûI€ÏX+)w"Â%¹ìQk£9D„Sæ¬ÎmgP—­ó”µZ‘ä›Íw)ˆ Oås3°3oVk Ò9W·Ž”5}åhÜ@îKrLʼnm•UM¯ D∠—E¢ÌØ#‡fÊïÿ1?2ʼnüÛ6ùigÉLÛ E}]ð·”9dïg¬…š”¥u·ð´ªÁ,,DÑmÚ+„å…%¢âX%y•0õ6RÀÃs™éÇ2úpdôý¶I˜¾6 ÜÏcæLû·o^Ñ Ùø’¡º])GîÀDìôÃÏXlÞsÖ¢' ²ÁG0™ÀñÅ…ŒAÝ`ÆSâO—tlÉ»Vn.!EÌ_’ÄCe0#y&‡ DóT×Z´þ4\¤kÞÿ£PÑ>à}ðlzMA¬Éf$½@º¿’…'^…¾Ú½/ekµ©ñq u›p‚0Ó˜Ö +U¡My qÎí„âö‡z“½á5‡ƒÃ ;Bš‘éC){5 wDF!g⸵ìø+ËüºDdK_+\’Q‚þ´<ä,¦U>˜è.^°¹¥=„s,Fê[V…±,// Å’7v 7·ìgg¯j7§h —é/›0ù}üÒúõ [ÞjÙGß)çï]Šàn$q> ÜíZÂôIÄ'n¿BnØ–ò˜É%,æ4g®õ@ò­¦Ðeé^Eù5‡Ø~f8fZÛ0Ê 66Á3!Ô_j߻ګ&PÒ‡Æ]QˆÏ«Z€ve·v¡jðÒvM]ê¾ÃMÙ”¢ýp°¶Åù›EFñéèè‡-2;8*¤z›ES¨…)Œ{«UÈ0Ì ,‘¬  ‰]²´¤OA+Å ÖõF´çù[f²„0&"QæìR¶™¨ ݬþ'â…GýÍŽT|è¹óøDp¬µ~•ªql påøÆ8®bL¸%ã¨ß Ã3ûÞzP(íRGÔ†»©“?]¬®&¾®j4vƒ§ÛÿEÀ¶3k¶[LC@6ßǶ ¬8'þ[pcÔk¸}Ý ž‘?ö"ºÜû—5Ñ8p‚ÿïf×£·ì*”p8­ z…rZ‰ßç É;|c2ÂYá[‘…n..és1Ûv‰I§P/1¡uRD€màÉD"šá«0,Û5Z Ò¢-ѧ}iª¯BYm[·Lžä‘´áösmòwi”• óh²üçüÈ—5Û|Hù¿aKÉÜ» œaO²÷2šÕC(5Tz1|^ü_J¨.ôŠZc„ ù¡‘Éþ’{«RTãŒÝ8k¯»Àv AƧàÜJ_™¹Ûíö–KÊ%8Œ`p‹ÿãTÓ^V\«>Îf£u?‘ÄAÏ¥_þ1KÅÜ=;ÅÎñ=lç š8þŠ.×Ý©/3<‡rŸL¹Ï 9.$Óý+Vˆ…ÜÉ¡yõ‚ +Íý'G?N K'ãÎ'õµ*ë=aÏå,•Bp]6cÓàÿ=’ –r?¯n» ãõ’¶wu 9¾„G¨¶´¤··%‡‚‘ê€à!8‘âà#æ—Ì¢„8û‹*LüŽ´ßÝ$¥c¬Ç¤©‹2F˜9H ¿Wœ…3_WÅ_9¤i\•ˆÕ§¼X£5&\|xü«ÅÜC¿$d ù]n´åÆ ®v§‘Š Ž|¹â¦\« él’*ïiðÿ–óVÁÄRù’€€²½pˆRþÕjÑo³ÄzcåM u9Àqž™©D«Û#*¦¸ÞÊ–êø=iä½BXU°2øÞá[’ZDE?–â²M”.DŸcÕ®ÓÜš.ëéOœÅÖ¬tªê(Èš]z㞇bWÕýoÀÙ_ÔC®9Ãz1 Df+Ã&õÓ縲Gc£;hEcöˆ— À9§Ë_ŠZ Öi„G=Q Ù  „Íú›:°Q1ˆRQ› Î7çƒ\á.Y£ƒJ—‘BÒ•ãö  þ†í\¼§@iÌ:)l˜@0>ŽPõbFUŽ×­‰ê€Àâ"ãg~ÒzKM¸0ç8û mpª0bA¶vs¹BÇ\uXÆÈ€/G¥"ìË#t ;“›x@^¬’Á°2óë÷Vµ+l(º\C…‹5ÃOB4kËŽáË7° ªu=ÌŸñX¶÷µ*ÍÐPÒÄ0ŸawW K 2Zû¼XèÚˆÃ+fÈ4t\¸µÛë:2µJ:hœµ¡’µŠ.%fL•²ò°É²Zš$¿®Pk( ኵv‡ç`°U/ãê9ÝÞièÚ©‚þýPþ¶ ÷“è§‹ÆpÖoŸbìû–ÌGz¡¸äÈûé¶OCq_]ÕI¦&!%zêÙg;ôͱZÏ©`“{‡…¦ÌÞ0¡³–~å€äM-Ì4¥†Ýœ½ŸÕt÷›IßêÜÌ¡F(À< TñAf?JxX—ÉÅÏWÄÂ%Âl¢§³ö~:~SlhÉ.‰þŽa¥ ÜÿW«OÞ°¾J×0“ûk"6N\‰¤¿¨w.Îhà£sCS­ ò3´½$qÚRxz"ÓïËÊÚ¶<« D_Åw™;Ü-£×Ý#{éÚSìö½W’¢>Ÿus•…ŒËŃ6åmÎW˜UQ„‹yæÖ2Ó#‹¸¢’ßž€8œY c:ªh½Ôø<™±¢º`÷š¦ŒÊÐ õÕ‹Z<2;Qk˜w&ý°_ „í(hÿq›‹Ó"Ô¬Ítû×Û|”&¡¿¬Ya5á—–±ð<£·´hÖj ~•L†’€€“#Þ‡{í• FlR-º NÌβ­iQQ¶uæ5¶¨§N!ÃMâ@«3.Íå96˜=ï°@cùèj°Ú—¸"CVfdè>tÜðÔ×&›KˆÎú,Ý¥Y÷ûhðlœA2ÝýÆ•3üðžl þ£OáD‘;¢ íAk¦m€ð(eÂ! ½äT×Å9­é§Ë^Ä–öƒÆÀ®Ï{q¶iR¬‡^~XoxŠ®èôºâvÎV.¨­ZÉuÏ®ÀºÅ§½t5¾@h«év¥fN)E¦Hnƒ®¾"{âƒgBÅ0.òÿj…aï‘}̇EÝnÀhà!léoaX²×‰ sZ!n6¾Á´¶Îlk†¡^Ç.]×–¿²¯‘¤WÚjÂOÊØi¬ /0ÎÙ6Ì«˜L‚”%Ÿhg2õ`p™¢8(;Ææ\cœ6 ÜDýÒÎÇèCH9Ó4+x¨–2IðâuO׫ü¯_o”PmœÁ|>A¥êž}ê÷CU8œr^Òt÷ØiÍø\làKæõŒ£¶„²YŽõ(¦F„åÑW‰Ò2þ¦ÙGTS§z=›ø ( ´Ñ¡° –+jòVÅ0°¶CE3SÊžËdå½NÕ©«–‰Æ©*¾ÖõZgåCîÃ%³Ä+Vb2{å-Ò‰½ÜÆ|ɼ¦KÃt8ðž´ìBNrQ³A¸³EäB*pË»‚æì÷Ôúš}Ìlêxoº{º¯B©ótr>áoŽ„Ø@”g† £'ÂýÊé™§Âm'­c‡µw Õ!Ú´Ï>Ë…+õnÔ*ÖzNÜ-ÎÍi¢<«"ÛÛwùÂ`ˆ¶÷ÎÁ•aÀ¸I¹ìµò’ýÿÆ"=ÞÝ(ˆk5?>sÝ‹³Ýº×C•oˆ›Øç¼Êѵ”%»ØÀ…H­Çs0ä‘Oç¡qSI|kV.g¢©{i¯á4WÊÐäd[v,k8@ÅóA?X2C ैK30>.µÔ+M_2Wgž€b×¶rB#svq…ׂ©0Ø#S¥«ôl®ú/æ2ý²ŠŒ“»}ÓFéîÔÖ˦ßðªS AI{å'ÜnG¦â×ÐÕòŠ…S¤ßÜß])÷0(G®pCDQ&;&ã¾®0ØõP?·1^+×òQÍ'3Þ.+¿ HY½à½4àtOa¦‰°*Ú¦Cí\XÄKÑæŒÖC‹¾Ö%mô0iUéyùÚ;ÃÔü”çBÇ^ ¦½ý§ÌÕÆÑ,à[1 zíÄÔ[¢·ÖÙ ïtRŽt_7CÀ`k6¸{#ßñÁ-ÆXÜ6aG¸ç§›:)/Â"›ÑCOÒ–vSâ éO–ãÂåýzð؇\²<ó&c;cG…#ä\e¸¾)¢Ê|CØåöaÙD:àž¼àz8ap} gþ¼|‡-ÞÖM<%**%ôqÏHë¸{O6NF« µ|OÆÞ‰¹O©$­öÚaêôYBç*«{i©_B²§T¹d؇ÛFÔ%rÝÀ™iÄìÔ§oΧã‰ÌIÁì;†#ÆH¥ò V3‹ýx¥ç@WÒY%öøè •ë[À=ê„£æËVå2Õüö‹Aéé\o¼7‡¡>9ð¼jª\Ï æèsš$>K0{áò LÔ¢u¡KÉÿYwKnœPñ!4$PóÏ“ôšŠ¦å!pø!š 1˜:ç7¶Æ–öÙWu¾)JÓR¬lð€‡ÁrV?‘½+ †[§‹ÀºÑµ¯ÎK@dkhäƤçÜÉ­ ¹­C{‚£'ìÀ'­üåÍ]‚„¤6ùgϳ‰äÑ©íqYÞ,?·ïö:4†ó l ü®)ØŒæÒèÚÒɵ’S¥°ÿ=‚olw2…¾¹õ‡Î_êUX$rRUwdžiÄ)EcœfÑÆÔ|øvT”až¬ñ~Šcnßì2ƒ˜bôZöŠ/hv÷Oc«þtˆ71tÕþ³?&áù%¦dÚsý½š£4¡Fp"T)ï¹áSds”##¹ƒ­/_ÊÒSO²ô Êÿ‡ÜCüº-®Ý·Ý–ÿm>tììBù0ô¤:cns)-¢/ ~I±oNâ£Áö%tˆ”lb ¾{´ è$òEÞœ$R¥8K!ëkëúK]¯î8jBÿ[7Wu$‚Dö$cÓí“¡¶ùDƒX{q¯ØªþpXî*PÐv¥}T*á«C 34;‰m_IÄEX_ªUFO/Qø00CF|«»`ëZœ<mІš_ AÚDDÀ þ‹Ü´wRD®2nƒW³ k–3ÝŽ5˜2*ÄT8?Ò¢‡6LˈÉeÃЈñ3µ jÑžÅt ,ÿu‘!šÅ%7¸<)+­•ï1óqЭN“WŠǹl@«¢é¢tgDìžÂN#Ð…FóŽêõrb7jQÕ™×J9âm¤`kÐxeE•cîXD°IOùaê¨Ù ïŒÇÏÉJ²ìñ€`öƒcù>¬¹·V%ô„]ZíyÖB_ÌY”a¢òtFVÔVaÕq]i ‹@Ïýè º8^Ò]M0ªçƒWO¡§“˜—Úì^켂ң©W§=¡ôEB¢Dÿ’€€ä¿ä*ŒwãóÂ_ÈËM „‚=ŠQ+:A¢;S´«KûÈÖ‚)ÿåë2eCŠæ\·Gñž<"éK**[2yâøS ½}ÏUãù&iYµ—I¿¼ûñÊŸ`=D¾Í Æ:ÜŽŽ§ÏýSBËÀMâv]³àCŒan³=eÂuìê©}¨¾+§ë¹FÏ?úÑbÎ ”IP˜W¤PÅ?²½}8Ù'ú>‘ŸY'qC?’Ҙ΃#¾hË2JG¬~S:÷ß÷Yg&.! ÿ_È/ìãçzÝmàåKò/[ÿÇ® ѧsÓA9}úýP¸îظ9†´¤Ÿ(<ºâ²Y˜ÈJqÑÜF[óßÎëŒ( Ä }&Ý"ÓO$û—WWLsjõ°ÏÜd7ŠØ¦7Qbv€ÄJ€ßlÈRIl­=–Ëõ<öA”J¶‹<݉Om𝻗¹ýŽ{rY vm3áÜ©v¢À}Ìn1‹…àZéü­êù¢›í¨N¨T@ Ûy:’€€ð« sßý•¨ÌÄ:]6L¡>Ú‡9ò^»Ú.ñ€#!+P¾?­ëîx^¦È£ÿWðæQSœwÓ|U­zSZ¢T3‘"wfA4‰>2G6Áj—V¡§d‡tY“«O#íè´‡€úúéh7P³ö÷z™•™`Õ'Ú«[rR¦¨ªö/ä€J®ƒïPö`a”d‰‚NS>º¢ÞÓ£Â\Ì7I˜R÷z)ú93eókÔ hcÁB¼ó©‰w-À`‹E¯›KYÊn(8ììán{á"¯‰þ²ø?º°ZòÕé‹ÍAÙØâG‘ƒ½guÛU”ªàY‚~?&HÂÆ|íð[ŵpêÔ? ’ÐN ¥Ã’'çÀ*¦CB뇮Y˜ûìçyãêÒwœaȾ R8=ú0ñÕ ë­C!™ßÒQéÓ»v>æ }QÒHùü¿/ùè,OŠÿKâÎj0D½ãiv%â)õŸ\ÍÛ*í‰l˜¢róHdI%€3Õ!Þ -šlkÉ ðúS‚¦d=\ƒ¶„˜ïþ=€{5!]m‚é¼É9¦¶´ B`§ƒÎ–ŽeÜ™¤òšRöw7§tÑè5ÏpÊ¦ÖÆ4p”ótÀE4B®ú„8€¶’€€ÃµNlÉ£äk}É#ê"Ç"?5,Ü2£¬5!¸®á[wŠŽ½o_Ž¢·î¶’,’>h…Ǧ[!i‚‰ôµØbw×Ï8xÚNápã­n DÄÕG”õeá¾OŒäÏ,Û+ãý>;E§âÈ~K½îV°CLÇM®„òRXøüÑ<›kcÙj~DÆæK¬ÁÞUw¦?xÃb®,圗â)˜´ƒX¢Á=‚y7=Œ ]KŠ ,ÖÚúS‡ÈrðØÃøä:¾&r¨cƒ?_% JŒh©Ñ['*8µÃþ´hÈD&(@§°6ÈõõI,Ýëè´¨h£ 5GQccBìu’uåÕCÆBÐI°¸¦؉韶¯%çS”e ŽX…òÆn]úѽn1ª9]4l£Z²Ì ¦‚^$D‘€.3ÂPçRèÁEÄÝ&¾­²Œš°º"Ñœ‰YoàŠð9nŒÿ{-ô­íIûʉNe‚Ò5¦|´m÷}x¸xˆýáVç¹5Zв_ÕÈk:=59‰Eéî_Vc„f–Ž#¿(ľ"ÀÓ«!o²bîuŠç…Þ.æ*Þ© Mðšdùb\Vwï ýăLvé¢Ü%²KóJÌVdt2ŽöIt^Å?Y–N­#kr¦%*4fÂ"‚Z~6ìÅ~mM鯿豷mWæ˜-ÿ‚ˆ  Ž?D!;ˆ£RÓä`€üVÙq£à4úK+XF‹³ém3ôx÷«¼CqÖÎЀeó[¡õ1˜ÚÿX´ñiáç)Ë ªxëâ ë—¼_~Z6iÖ¢ªï𻹇¾—½.¹•߆éMXž‚ÿõ2 ÚýH<ÇÙèfIçÄh›Ÿƒ·œ´Šcm©Ã~l1×Ãô´Ö)~sP!žd€_¼°¯Z)£Åî±||ô8kͺÕê–.ع O@e¶k8 Ô©(*‰ "ÆC&þj:"*ò㔋¨mø­¤K*@tdrG‡k¦2µ¯è 8‚ù5˜M׊'@l[Ä_JëL¤'9¦ý‚Ïùê8hg“q„øü¥v©Y§Í«Àèä4ÝŒNj.;‚¥( à ‘–\ O-Å1S½¾×œnµß*ú4Yú9~\ûÐÂ<÷–|Ú‚jgo 8]³ÃŸœ¶qZê=ríøë@X¤0 š8#!»Žv±­öDÿÑØçóÇõ*Ï÷ÉAR˜š;ò®RFk®e£ Ä'6Ø}-o ¡ÀãÜŽ…÷F— "’=ÈÈõJW祿;¯bÓæ'È*ÔBHE™Òùß>1ßÔÖd> u˜D+Õß©RHít!¦x~ÇG žB4óÒ2‚â@ezÛ ôš"èì¶)™ÍeLŒÔ F_Fwï¹äÏtû‰…¬k¦`ýW®©›/J7/O»nËÕDnò&sñ¡™ˆ¦BbïBNÔú\޾qaRªžX@¬QÌ#_+]ðÿiØ’€€ìûʲˆ*ûÄG¼E–À‰Üجg—ã;ÁrUEU KdY)ÓÓ)TÜæróG†z[…*¶&Y‚û§Ê›ošh^‡„>ò†€¹ef¢ÆGª¶‘æbI¥U.í€+XµAã2ˆà‘ÙÑòÒä6¼RK0\ÖŒYdÞXL›Fþ×óá?€Î/”~ôÁ10~»í¶°¼ è®(D·Ü†•²[ o­¾å øB«ï+Ûº+¶,œG^ñ´tÌÒ©™â˜lœç¥ç¾˜S¿-²¹ÞÅ%ÞºFÉ^±ñÞèW8/ïðªWg_ 7åi™~ï}w„ÜØÌÜØmîÌh&DS°8ÓýLÅøQˆš&÷57Ý/>mf)995!µ¢×ÿîùR„,P*˜óÝû5üXy0\yô‰à*þ´§1„”ýÍIü:h€}dÔ³1÷Gå­´ûj­Ö¹òÈþôªÞï鬼þ¹ Rh]–ù¯ä¦ü³Ñi¬>ÁqÉû«Èç#=âµbÄH‹×Ñ+k‘êë iëv©áLˆ^#Ãjƒ_¸Xò*æS2¸Ú•;Yf Bû‡ï&™ µr’N D¢`üžp ù‡d•…wùI¾f掔zµqØZtÇi¯ˆË´©Å[Z¬”^œ£nk:ò íYDçU«¥)ßÓX™'÷*ðR¬cØÐ7¢éÂÒÀ |!5äñPĵÕc+½¥nR…ãéJì9E‹úêS ‘P â¿1C¤t Ç‘4µ¢&š…˺ ·™$¹f4©™&þ¥,œ¥(d)ݾ*\¨h{Ì8{R°/›Sª» #âÓÙråð‚÷õt†u®ÉÛêž°'ndÄ1Çíø÷›H\ñ¦¿vcÁl†Ç›žÒ„ý0Ùç9ŽîðƒÕ‚›0V»/uk/<߀ÔŽØœB©S6dûøfz¬Ú}^iìÿ Œïò’é„ õ—jF§y§$Æh›*öZ«®z–Ã÷VbCpVße›ó`ƒ,*/«¯¢…ð„é¸Í°ús“'Oú ƒ‚¬~H‡Äl`¯ÌÇ–ýJßo©@ƒ~è"Ù|î4Àч¯k’ÛÖº¬oÌáa» @ziCrTÕlÄÛ)Uɰ‘1 #ÙAÌ:è?i"^GžÊeò!¬ºÌmpñr‘„®æ’€€—¤øµ¤ýž&S!‘†è „ g-Bº¹!Fýi¨íüW/a/3f¶À­ÝW}’)U@Òèë«îáhj†wÂ4§uÀ…ƒ‡×Ä1"7ê&Ò"³þ·÷²ýHè²…Œê÷O”Äü„ýñgÍ(ÅË$²ô;¢¨‹!Ô*y÷ D{'=l&È&Û÷Zy«ñhNÙ´r}Ë–#‰Zf´Ši9ÜMRøG¾C‰Ê0’‘U¨&OßÐG®¹­wË´¤Ê,ë˜3³edÎ!]2¦ÆK[ÚŨªveZzX/'”’A°Œq˜~}·Ùìbaop™ä’»<ÊH¤·{ÍáÀ„¥Á-Hž¾²Cî$ Ûe‰ôÎЙ…¹zуm 0ã¥þëaJ>2àKÀ°'¾©ƒ+ßñuYþeãuT {çƒâ3 ü†Û¢aìq~khMàt{ï§>äó‡Ž Hq•ßËÅ!Ø„:Ê0uUâ°ÐÝÑ ÝDo–íMgîÊÒÖ¬™˜›;ÅæÿG2D@À›È4YÔ.J2â!Dœ oëÚ ŒÊò]ë/U ñR-X˜=’€€×éÖ¼ã³@ƒ­”Dœ3ø%[ ¾©Ý8•2ë?´cCÐo÷6¨‡m­,HŒ¾‰Í‰1—°ús†ý([kEW&ÎD^œêbÌUßäOn¸5N¼à€5¬R‡¢ïSZ÷—]Ö÷p iý^þš~£àüT(6g3Lv&•¦¶ ÑjŽHÒI^èbÛ€¯BsLdS|2È6$Kñ&DU9Îq@×4#Ÿ|âë@>¡REÚ?RþÖsö¥èåm“#úÂÒìNÆíiw°uU“Îã¢Ýsî|³Þ–WÁÔšãv@4»£;Wþ¹.Àã·ßóPuá ¼ ~}“3‚ã±ù]Y ¢Dc•qòùv cØÍ ?Ò+£°èŒp¦¦Q!–’’ ´ä‡êÖÐã;ák » ØMª/N"þ ™m|—Ûu*ùþ^pX&9R=¢Ò‘Tì~áÀtÂYž™õÏè´X´!§ß¬v¬Qé3YWnÄÈáD䶆/\ÃÜÄM›H†ºŒ‚\?;L«“µS–ºNâ•c©˜ê!œXÔõ5Œ*á6 GÍ4ú“ðxp `.?¦IvÛ³ù¸ö\Ö¾¼€Ü•5oFsÅé>"UM)»ÚX„Þ²/|æQÖ¯’b Ï7Ñ6¿S­(É™âk›å´ƒVÛ ®$†rÿº „$Î7á=уÈÉ%bJ †å4ˆêèñ„¨tjY—bŒu1É~މhó¿Ì%æEûÚýÎ(  ÄÕÁÇC|¢rÒîÒ#ibïtTQr uëÐ!Ò'Òb( aU'°bÈjJiÕ·¦«²» Éçȱpôß'€M¾YØ$çPRKr›Ðßgí ʨӾóDšûûÇ•6_ÔÊUöÜÛÄÄýä[º8‡?·ö/“›ŠÊŠA!÷F|ç Åmä²`›üíó{›)£3?mŠ5cæ·ãß`²% ¤ÂrHïPÍÎîMU™±w" ‚±ÆRøZ*·ýÕ@û:ÄŸ»¶Œ³5«\IטýjWÉa›ÙXHÎ!à9 £Ø°‹Ž+¥ÎÉŽrr;î2Þá ã“§¤?¯€˜¢Ÿ³ú—‰¢÷@µÂ$Zçܬ^§3³Ý -ZÄÀ3) ±-wXIÎ{•³w>#àJfBºˆB’€€Ó9BŽ_ä¹l`" ºF±LŒ nêåÐãf–p8°1ဪxÎ4 ¶ã<#çb<ŽÝbÁTwÒŽžHØ"ž¬Î¨2Ø¥HÞDÆ®{¶%î_ ÌwæŒÂ´íº…ŸY%Ë'Â:%öƒ'(z‹7\°Ú£¤÷p¡­]íÆ«D†µí(ÿ1cêZV“üF¶uf}— E—òÊ'X£NKX~Qšö"k’§†y¦!€§ØºG ùùj>ÑÍm|C g›­rwë—· @^chIx#§&síaLÈf›Aƒà4Û\ŽÊ¦’>ôI'MŒ*øµbke¬Ü·\}üÛíJõ„øqÌ$D;·ÆÓ©ý¨6„tó¶3K7âˆEð“FÜ9k(oÏÓ«ªñZµ´ä¸H ^!Ÿý2kÍô‡B:ßã+#ÉÏôóm3ŸSe'ŒHãâJ€úŸxRíÐG_,Ö]JŠ–×ûÐ×}[ƒ}Þ÷ïÍË™wbJ¬Æ(Òq_ª²VˆodZ5±‰ €ÿnŽ2Rl’;¦Þq Ñ‹ÉÐoÈês„O^ CŽYµŽ‚ß ½ˆeæ d‘ Ý÷òÔ$§ÑNñóÀPXñr ï¬.©o¡¼xÏËxA®:Í$@ß6®‰!ò‚€™{²~2)20 Ïå&Õ¯ØÒñ 5¿Ñ¬ÙÒEËÏi Ç ~] ¸;wW:ûÛ;1’L”Þæjˆ—it^,â^•õWß¡¶ H¯Ô¤“NÃeÚþÅ#¸ð-?²|a;3DY†ÚpYFÓO˜œ~®¨aû†Uf#ò>«HHŽmP‰±|ý±„´îº  °gùÍví{®Î§Ýˆ/ÌŶÍW6¢ñà FÊÛCGƒ[Ÿ­)Šžè}*á¡"„ ýHže”wªØœ…0âÿ#!•Ê;žô ÉÊ;$¶b±JŸïk(ûø?¾õä Ô쪺ܡ!ç~²Î¤Cc€ÿ†öy×Ǻ,ùµ€°\f,¶hœ,Ê¡ÀOSÒtÁKiµæ°`ÊáïBô|¯’HxQ猧w.Âmöø[ù™²ù bŠèÛG|Ä:e’€€µ Ì=ìÅHÞ‘Uêv`ýˆÕø_í]s¡Ú†Î-ï° ?‘:Àɺ ' 7–¥\¨ÑØÃçaí˜j¸2„þ“‰„*Dd!lÀó ÙjÄÇ`#ð‚/¥ÄImtODиçe G²[*]wÈ5c|c¥§õ]lf$fixy×2L Ù¼íðWËÞüMÕõ0x|B±kÊG30ÝÂ÷ã$Ùh(.å ú—¡öù®‡Òinä ©uøg—óúf‚ûtk,¸Ä#0!?’|x$£c¶lt¬Ü”Qkàíz ´„›­Þuðe»—p~Y[œ^øèQ¼}qðÒ¾šÃì*î½ÔCÉî{™Ms d}è¢çS»•Rh’yô`A)Ê4Œ·ú£wøPäâC©òÙ øXùÌÚ ­ó$êJñ5oyì}äãY€z]á–®2‰¸]Ê ‡SÊŒYõ±F²¡lÎHš#¯(¯ ‰ˆyZ3'!c·ÖÏP(`¨ukF* ³Òk`BÕžþ»Óbb:h?d®I[ĶnGèyZtô¬ */§GZŽQÈOóÌ,ØTƒ»DIçD+chÚ^%ãP2[§L ØÁQsÚ²÷®öqå@ð½´oÖ Áˆörå‘Éó‡pWÖ/+šD}÷7Rpˆ¿l&Ùø 2…zÔ†(ô­¹<¾ÁÑîIΧYf¼ÐÄk–ƒ{ƒQŸîƒ•Ò_*jÿD“ô ïÍgp :œ²hËE*£—tñB»Õ»‰!€=¾7™ lWCI±,VxIBB¿9,Ñ3Gò:2O)„B5—_‡û @V‹7Þ–^’½p_léàÙæu‹!'lQÂ;]±‹Ms;R–v`:ຯZšë< bþ Éb©!Ž2§Üý.­¾çü³3`9.Qô0Hl‘Û-Ó0ŽÄø:´ ‚ ê ê@DsŶ®¹«ùcó¼¶S~å!Äáæßö1¡ –ÿ¤C&£{Ö‡d-¶ˆ‰E«^Ú#1KÆàƒ°t0Fw æ3"k,qŒìTµ~‚­ßÔ3áþ^í3¶å5Ë¡Hj2F™¡õŸŒg>üi›"’“™ÿôOè¡x§o•Á§bWa˜€]Ë)ñú®ŒÑϯ­¼!•6úêX.z¢´~ËûsçKqÝÕcÝ¥hîgŸ¥£¸ìgè’€€½bžôLVõ¨»¸i=á¢_ܸù!µE:~EÝåö$dzu¡x“±ä\:¶¶L+F¹+4/'ÄP¹L9õÔš;x&PæÓÌ[ߘ! Ê)ºzçT†lC²é{ËÄ‚¬È üY“´¾ÅˆÛ3/>NDZ“:ƒ[ÈkhK/¹dWT ‘[ˆÜ“¦‘.v)­ï¦Nå¢áëƒÂ°˜“ÓÞ^‰a«xÃÜùœo?¦6öt¼b™½GúË@DÇ"H v]dš­$R‡¦ƒp¼ÙÚÆÜ%µùkÿ=…vè,SîPeˆž„pœ¼Ù¨Î%æB6†¯J…tVbo%×ðiMÿ”XãH{U] í¤äŸáo7Λµû0ñÞMÀ°/™GÇØŽáËòû\òp¿âýßÁ ÕúÌÃåø--Æ.›û<ŽÓõ´DÃä•ë>vTÖ—>ÊH>q†_=ºêŽóØý¬°ËLa£ó ]o²êÚJýl›™»IÓ1I•]xz¶Ï| >¬”žÔHL°·r‰iþ|RÓOÚ¡Bñ“2—ÍîíX! E2Vú¾p½Æ¬]|°DŽ:ð0-b4mØò›CBctâ…h÷ÖAl:|Øžô‘ …ºd"ríS4-¯€¦ØãUuæzE$äSç-Úá5Ñú¹,§5€õÖ—o¹ÒSa̙Ҟà¢{Ñ8m†nÍÖô7Aë÷M 4­t¶S‚æh®š>±_Dc…7k»Ê@Ñ:ƒqW5xâ¥{àÔ|ã¼}haR4>ô0Þ0s^Ô?+]¾Ó¼ G(¦ÄôNüßi ÃÓe¶gÑ—HKI}Á^ùp _§ç°!4†)jXÌý™ƒêf’~¢ZNuÁ4n-w¤õ±#0 Ÿ!: aÜïß<íS,=ÏÜQ²¡¦åZ(™$fã¿UiW€ ˜n¯²ÆÝ(§ÒJÅúòç§(‚Lïí’Æž@I®g¤§o¢Ž:KBð”¢tilÉ3`ó¶Îø¡Ùª\s§CÁâqÑÑ$w¬ÌWaF!ëåyÙLNßTÔ Œ1«Á·3Ñ%¬8‡ìOík‰X gnļU{2F‘‡12L„JnÊG–Øt‹³s$É1îL*Ø÷ª5l('EÛÁ“•h œoIFÞlc NÊ£iÊåÌ’€€¢Ø¥çó`™}­°:ΈCú!"‘d´cöº›:èw“€—gNôgBB/c¯ŸŠÔ¥)ºoÙ–gXO¹4Iùw»TKXÖ]À}ai ÷:¥dHü=S#'· 6Ã"JN„[»An.Â2îµqª¡r/}…ºbχJR¸tÙܪGß¼"u›Y]úå¶™5amöõ¸cgTRÙJE¾œ’MzÚܵ§^›ÛM" 3 *ç´Ó½•7%ÙüŸ%ü¯…™KÂ*Žø0F–'; š&}š¯ÿ×½2 8E7A‰¹+;âç"àxô Kz¿a§ño} K\Gê…:–ÿ™ ­(x^ˆ°A¸åÕé1 ŽÌxŒ~µs8ÇÔýÑýNkaúÐÿ„Ÿy•]¿UØ85É­% ü9Õ˜DK÷v3¯°Óî«ÙäÊâc‘ÑDÀ Þwx’î¯ÒLzÀCKià {/:äd³ºí+ˆ!­\#碉àç ýâø6Dÿ2Ò­ØMe€²*Aß¹ÐÇ\x¶œÑ‰‘3:œHÎ>³x9‚…,æ¬ìÝ5 xÉ!?CvXŒ^ÈA°À´¨¿oýÔ™hª¼ä¹Azäq§ –¡éž\þ1j%m*mlQ÷ÓÐ}ÉŪ^ xºÁÓú4íÑ Û}އdêÖ#ïüêÄí9&bÅk“IMkÊú£¯€=¯XP˜ïù¬éâ=V'FU”{6#Öƒ˜Ð8´A7H:š#Ú>t…”DOHE~ZvÑGùzý¹LC ÊÝA+¡Öûðø:lÅ^?ÒÀp¼^ŸÜ çZ‹¥ÙĪŽ_ÀšVëD(î¸}(]½¹‰ÄgþòÕ#Èö{l¾ïÉwä¥_òûy•¦ñ 2²ì­ÈŠõùhЗˆ ¤©÷å¤?¬p0PAŒ“y¯F¬;¶\KG— dWµ¶ mm·6dÑ©Y={„ß?÷£‚µJá2+6=ËÙÕ6KŠ:Ÿ²C¤LÓ x[`#]dBFèáᾺScE® ©;‹êGÒ¯xãÕE`tËìÔþ5/(|¨Ë0qúé@—wõ×áš0á^Ò,‰mEé–¹9h¦R¶;U›Ê!õ‰¥~„ðzEööŸ8$Ó²fëÏLH]£·ÑMžX’€€èÛZÌ"¸nè·ÐXW×èFŸ2³V5­ ¢ù×lÅ?€+"ǯk’BkqßìV&ûøAÉs'î¶àUñSú–›3ÿ2t›©L‰R^Øë¤É-Ù°º)hÿc&ÂaŸÝi{äZêñe­n5ÒÒ¹ÈobÙ^`¥EÝ'<’|Kü–TÑŽ:Á§õ”E“ð9·E‚áÈìGH­LÄÆr[]]ìØå… Í¢KK+-õŒ•}PÊL¢Ž¢÷¦c]³ÁÞ²®TÑKø Î{o¬ä½ò‚Û؞ʵ•»Ëy7\¡Ã”¤¹Å*€ÂLîµµ†3‘8 òŸÕ0òÆí* ÙIÀšh®? SbŒkFº¥Ã™`LEÅ`e”-…»có?Å —¿[Öé'™ 3 kž–Pü§¯¦xú-À3þJOlí¦c’dMLuxÄ=ö{|†Lp°p¦_A7 D9ŠÃ‡#ƒ œÓš-ZD\düÍEkçµfOë¦C aþ·8ëIo‚DXi/š7ãtY€`þ‰ôâx!Ù0ÔX³’¬‘¯¯!”ú¸‡{ÇnÝÝEÃÿ¯g Ðã hÎþõryðU½;ß é¥Öh,×,Тק²Ž/oÞLÝñToöhÿ@¸ÖY»³ÐÙÒ¯w5ußöûàR±?¶¥D 4ÌcŽÔ¶ûqùõs®ª/¾¹…±ƒJõò[¡å „œ#-k®W&©«béR‰pq«&Á•WIÓà‡ÊŸÿZHaRÎö“޼ûDÊæO0qæ£Úü žÆþït-É"»Ö¨§¢¶26T¶Iÿ™|îÅdô³â«)ù$î*³¥áR؈!OgòÝø‚Žçß… îæRDè-Ũޡ¾B±Ý¿Y~¯;Ø_ÑAîtxþ2÷øHw¡ÓäڳǑz0Ø(Åj‘Éçlê­¦¨€®cš~]¤‰Ò.™xbkÒœ³ï±çdm>’[©}º[ /,X¤C¢.ß7Øñ…ºžœy1}L[Ûi9rÈv‚åÔ ñûO‚äÇÇ»;‡^«y Sc<Ó¨fóvŒƒt`gp1/gµ„\È¥ã·>•lð-°Vpš¾ê€>>ùnã¤ÐeŠe ¬Å¨Ï7î!m ®ÐʺUÖÕ‹ í÷HqB[Qå¾ò¤¶N±ô He*¦¿èǬ¸¶yÔ„’€€ºò¾Ø­4ñ&Д1z|¿×)¼ñzN­[´êP"H¥]X™ùã:¯êUݶ¨håËuÇx扜ƒø &÷Wìß§KJ°vUÔ"g‰«/°Êû„»³q ¯ ©à¥T@’ #‚÷ó¾CÙ™§ˆSð×:ttä2§z¹uªE†ÚJPÙî‚MÙ™RGj¦OH‚L!öÕa Nø(š@o‡Çˆ›AKÒØkàC/XºÜ[ EЃWÿ}1õÄmRúi–¢AVÙìB0aòŽI•½ Î[â'“l;í¬ú_n+¢8] (Û.ÈÎS9¸.µ„´(ì) JSmØÊ_ГÔ9n÷ Œ\Ó÷øªÄ)õdŠ ÷çǼÊ:8dsuH•PSvC>pÞ.WàF¦ÕíÌ= Bì¥L¥`i-X’ÎgÐy8æc€^o•,üÉêvŒA¶ ‰Š8T›æj'{3¼R®ÐM<Ç—‡@BA²QÝÑÙ‹Yyiu=~š+êº\3û€Î¯dÖÖ›Sb´ Qpr—Gä3»_÷7ÀØJ6ú¿ Éß’²Ü”IÙT™',a¿}ÁI§¸~>Jiú«¸zßô-«áÈ ã!zÇ0qXª@¼}ãÇwe¶ñ¨GN|+j?¨ÐöõŸr`6CäÍøjJ̳†(oúV~š‹fúÅÑ ¡iW(Y€$»PÒebœ.•ñáâ·ae7½ûض؈Žn0êz«™Çá}á]Okª†6(ÿS†xº³:’ItÙ(7ð°o»5DG×±v.¥Yӄѵ¬Z:úŠÂ[´Ô5VÃVósÁ?À¨LÈ%1™©ÈŽ3ŸE:èŸÖ¡a9¤O#WÚU¨eQ4› u7Áwà a8l @.˜û Ö\FÌJÏÍŸÅ®æVEÀp¹Q«ÒÙµÔ‹[ ­_ž¼jöÖưÂÇ< 'ˆž±{·[‘æW.Óy1rS—ð'÷ä Jí~Ì S¤AoŽÉFMnz5ÊÑj%ìÃÔb±*î^%·tJz-I)·†¹É#:*È—'ñÿ’€ M¿áÆÀŒ8¬£’ÙÝÈïŽ^ÛÀl<@ƒ:ó¾0¯¿Ã ™Éa¹x\yQmÃâºAË-hL-¯MÖâj4C½ë/ÛjT·’€€ `÷k¥]ä÷”cÄIúS(aÞ|“r®Z ø.äÇ´&Õc~v-œvN÷ù` ¸r%¨Êz}í³öÓn‡´ ÉÕ‰,uA’ð…Ø×v` LÅóy®š@jLBaB¡zU÷Œ¦|°eh®éBý­ê,ª.hQÍÅÙ—MxÅ|‚rÆæ_Êx >^‰ûþ^ôàíM“çý°#v 9.Ãx~›I{#‰÷ÃÕ}ygj¶tUýn `Â^¿ñízÖØá•24ã/1ò8ÁAÔ 7~í²cJ¶Ä®°"0¬,ˆLÿm ííàr,\"°‰‹óÙìlÄ ‰N‘·ZI²­Q ÷Ì^gzÅŠnº6éNS´n–tpZ¿òr‰¢†Lɼü?™çˆá- C«ñe5·™+¥À¸òðàrôúV©q‘€˜ÄR®9óýÁŸú§?ÄÜU‹b§˜‹ïf‹Üœ+?É{R»~ÑmX,q³†a`+ÙOÉV-Ó³þuh7-Î ³ï¥í'ô™Ú‡vÈÜxç ÏAåÂ@Œç`¨ó”ÍJc¤¤Q8/–û¶ñwä¦TñðÔV}R‡$liÁ§èÓÕ¸`È+*A™/bøF'ÃÚÉ}ñ¤§ŽL¡e!mt`²M%©©õ³/Ž~p’¹žD÷°JŽ£ÁzÌñWîëúæ¥K ‰J I"UÔwâÿ0‹8ƒØ"»G© ‚õ€•<~ÇM¹Ï©cb«¶¶ìj‰/x“ÇÈW8 ׈þŸt4£–ï¹y¿¿ÿ’€€¥˜Áµí5À¨èjÍ(m—¿½VŽ4ƒ¶o ÜBiZz@›!c°w/r7T¦‰ÿ’ݼV€ü Ý”ãcF· Z‘Å#´;¾žÆ+P| Ͷ¯¶"Ü%†ð§vžÚKZ!ó¸‚ õØq ­C2¿e$\4òK³S2n{±¾—ExãF¾b0!'‘x‹üMé{ôì¡bs¢€˜ú8?Q¢-eCWÕJþgþOýÏÈ¡jªÚîê1ñ¢Š+ÙÆ”¼†~ñÞ‹¯ÍóÜ×#bÆã^fv©e gǼœÛí3NzÆÛî‹\ìÛJ´Qg¤ZrÇF§¾=ê “MuÈE&aMü°½öã'+QºÄÜ!³ 4½­CfšÎ¸%ÿe;¹µWÜ–~6Àð9w’êÐÝœPgön²Ã«¡®L$8Yþæ—-<†:áØþç‚''êM]ôá6=í*ypå“j®õIÙõ¦n”%Þ¼Gõ*OŽá&—m:õѤ¢ñXÓ\ÁdQ@>yDïgÛªElÞ\m%¶6âž1‡_Y[ ðSzMæÌýÇ0gdJÅŽ$)æmŽÿ¥3&èÂÈ,7Å{ç…‚ûV2XèK|¹(aZÛWŒxœ’¼àÍH¹ºÊÀ.³ûš?_ߟ˜È ÈV])¯¾tèÙ6ÐaÕ³¹Ët±ãýVðÑ„¾Œ4 Y_äy5}<·îb$ã2Û6™ÂÉ™·eð¨ÈK©QŠ—e­3wH>ÏÛž‚ªs-Ùp„Í©Êc§<ÜA,·G{‹2ƒ%ù.ÞURm–~<šê—üf%'¤»v— YîZDÅðí=èÛÆ_ˆðó|“ˆû‘U~h¤$ã¿-ûƘw1¾Âˆÿ„O\”’©ò„ø©q©kW•@Iò‘QöÈh‚vg—‰ð‚‡È¢!tú1­4q$IwLÕA³€à·¹©,õôÁµÉ~<¨¿Ï´e4­³bŠtªvC¸ì¢o¶ònbŸTíÕ"驯ë¢M»-Sâ7´2”Ñ<É…A·M©dÙ(é¬ÖöÇë‹™¯;ZËû¨™Žûj^vmm‘Ba”ÕÊ¡?±^ ݬ³–et‡âÿN·žÛ›'Wzf›ø²aw§®â±û/< =䋯ÒsmŽld‡õinC5àGÆPÜõ„×|’€€¶È!¡Ï A.÷ =¯G÷Ǫô¥RÍ? y<­”Ä+jtæÜ»…˜t¦úÎjtTCÏ¥ŸL)€¹¸ µ‰ã+ò­[¦}€\½Pþ (Œi¤ñ^YÓøí,'‰í_*MÈ¥}–\®Ö©´‘J’E„‹› mÃrußä¢Ç{zCd&k…ÅÜÔc«šëõ®àp <¾H‡Q“Ó K_‘¤|çÞ&õÖ€›ä㔋û0W–®¾¼N`YESXr*_âiIŒ“–q®ô…ÓìÎþü?÷“À(œ¨tÛ‘>÷~l®]Ö15ü+ı”Ù—­EHÐ5«3úÅGvf瘇ÒS›Ó]"â7~W‡y)@‡!ÆŒ8k®ŸZ[ò1 ¯½· tõf­¦cr«Ð}„÷M=øÛöÍQ O»ÊLôuƒ+þ¾ªv”À·=½‰:}ñÐÚ(»ž æ-Í"âÒQ‚Ï¡ì:Ä%§‰•þ§š4\Éù`½Ž†eŒphõõ.•&ªÍ:æ"€ü—N¾CñŽWþ%,K“»r†¥µ¦ŠñsÜYÚ_nÂSµð_Q¶G››Gn$~Ü1@ Ÿ:ʵ”!öb€M/¹®D˜ñD*G¸ÐÂñT~¯y“'Ú¬iQUÆ>!¼g3»Æýú€¹, Òà7(A1õP•eæjåÒ7‡-ìKao©qËü’Kj“j¡FË+š½DïBñKŸ°²5NQi`ðØ´£Äåsùré rFÚ‹bŽm™Œt=ö ÚÏb^б ðÝn½K(eáÿÂm•AÁuá£nͲOÚ< !RÏ¿¼¤c$Ãh;Î#ƒc´ez؆ª…Óâ ~й–È–£Ñ§çâwî‚ÿÞÈ‘ÌÊY‹÷eIž“Ž­¼ø™:ˆ,ΪÕßÛ1„¾ZÝ|òjšÌl÷˜®@0r(HZr¤b SŒy–o(ÿ$ltq%F¹ç¡æPý Dzl骸IÓÉéœþ ¼w´)\†¿÷Ð%h™Ó&6€~‚=uŒŽ"г™1œXõâÂÅý’æ÷'‘Ìzšg;Œ*ldÒQ h¦!YŸ,A„b·èØû®h«v¬1l†­–wžeYV1Sè{àŸ‡«äp«?ø­g¦X…IÂ.ã¼ÌSs>zÈà~Ø”0!žÝ2„ÈzkÚS/ÈŒº4 "Í’$Ýp eæ |†±¨æ°ÈÁÚ*ÿ,î\æ(iõ\ é}¡R•Iþ’€€¿ßžNé¨MPßÊU Ÿ´±”VCðË*©ål{Tyêó×BðçVÕEsÒ¤k0ªÞÔ,•IYPÓŽÜíÜ ´*7:j<­2’\®5ö‰s"_ù´ŠÆø1ù™Î]çñ ÙVÊQðÌä®Ç`’èÐ…F.Cò+W0w@û8×ïEèg| rØ*«cLY&1P‡í2‡"G þ!€xÞ¿'c¾QúñûnÚ&Žæw£9Zí×hǪY,@C¾ÄAäèk'þ%gÙ{׬1YÚÇ Œ{:•>0j!¬[ÞŸ¬MÝË()³¬Î º­CÔêmhÙstu‘Qjðj6–ª:5„Ÿó\Y±ç·7Fª-wAxº¾žW*‘éÇ»ò½“ôàá~’ã²h$‘Hû÷o1ñeçqîk‚™²%³`Ĩ‡pú‡õï /[`1ÕAÓÅ×tyuËÜZ2C%›âÃØ/<ñSéC¡ÀÑY;ÛHAî— –%0‰|åÖ]FÒE÷´uW6×à#&…sU‰Fé$½´´i‡Ë­šö!1£‹¿û=Å¢§¯Ômñ‚m[JBÀ.Kê"PÉ¥>wÝ™¢ÔŒ«u䄽ÜëDš¬ ÊG«éÙV–‹Ûïš³š3Z0×\ü)U¿ã¾ÎB8#?!­¬§ŠáÞ«æ¶Ëë´Éÿx…)©ãÊxCâ#Î ·)#¥íƒg¢5¾þÍØ³Ð³ãl N&N­4mŒ¬#ÑïXaˆ”Éú«v»7 4‰ÐS ð ³*S0f‚‹7bÌ¢”p@îÖý¿6à{X ³\¡/>ªŠÂ]5Qް—o‰ñܘpxEûTͳšq$÷Ø{Eð¥r,½ â&Œ7J@ËH'sÓæû®4™»?}:¦y³….²EU·ÎÃèØÙ®´W½*ƒX²C[d`aCåŽÜªüÏø©öÕµk;ŸÉÓXŠÎ l ÚlÁhUµ¥pÊ!Š/Xþ¶%.ÅÞ>­Ó {›ßvñUòû í‚2¦=Õéxk[³ ùO‹z¦s±ZÔy Þô&¨–QPnÕ£SK !«XΡx?µ¤Å9ý¾ì¥g‡ep-;YXo/ˆà²æ}^çy¶ dç5b÷ÑÞµÉÍ‘k¼;­ø8L_2M„Ï ‚@ªÕÜ©5’€€ÈÄI˜ÿI±DU—Ö×›*ã š¦gÅKp‰×w#÷ÿÌ’ìüeŠ…ÝŠ öz}³+pv᜔:˜±2°_›W4"QJ£µ,®é0•.2GKýç,-††ñ‚bàl›hN/ž‡´’dq ZŽ»Pì%Ïän—Ð÷Pçmù ;r΀*¢­f¼³Í¤i²m…KvÀ>üÎVý^É‹ŠÁ½«Iz0³[i?§öx ë¡Xëg ŒTd­!ôð1PD)Y[(bű‚7Îî1ÐÜÔ.D×#ÛzaáϸîúÉ- cLØîÂ7­ð ¼H~]•Ú `mÄŠ¨a’¹yÇQP"U“W‘|®Ç ÃÏyÙ{¬'SÚí™zø+V6é%_Âl’(ÜtÌÏ.NÝ´žV윴ˆó•e¾A©–ôÙ*úB™ÚÌ-k«ÿ«`L«r›âv1AȘ¾!'™Ú •Py/ ;¢1Ê ‹F 0oáD¢ã1:½h |\J] `S¿³™EcœJÐDýÙÐ#Ò¤Gºð’ŽEÙ=[ªºØP´uØ—˜g!wk°*Õ¨–Pà¹þ+Œ¿s Úy³0f &µrv`â·± ‹slyÓY¶A¥^já`#ñÞÇ ±ºÇ{y!3óª™M/w„֚ϛ€8%›3ÿ'Œþ$€ô‹v9Û'=hÀüÎcª,j͹íÍm¼@{G•nâªÜß’²\ätµJvåNœ½\ŒÐ.5Ìo‹nÉ0`O¾UÈÞî²ÞfV´‹ûÖM~BšÀ§'¯s”@C_‡ž¼ ¡Ôï˜txa ®¥ P}þÑ«‚ùñÉ çÐjÇÐÔ ™IÝú÷ÝËçÚȨ÷Pë“ïÜäÅЃÔå±]ç_‰”AŸºÅï[ï–6Žx0‹ZŽG Ñé™MH—X5ú}ˆbƒ•ÌØñˆ ð c->¡½ aíøHNô.ð^Èü h5³Ã¯uŒŸ8ȲÔÔM[¾úŠ·ÒI¬°]ÃãÕµ‰ó5x^T{X¢©%ØÂ{§ÂÕ_ªnM†Š hCØÎA¶8\“׎$}[ÝŒ4‚ý<ù÷ú¤¼÷oËÛ0ÚRÆùzüaKŸ ,D÷‰ËÊ NÃÑô¨PjÝO(Äd:ý8cHçhè.ÑûpuØíÕ*6X·Aa`…Îf¤Ävâ’€€ÔŽ<Wb¾ãŸyEfüƪ–ˆ\Ÿº¹¦HÊ|›‚|T]uc¦¹-Ó0Îi_ 'okUÒ87&ƒ0@÷ãa†š:ë’Šà0˜C¯áOÆÕ¿b©`°âÈñ‹RÅ6…½œ®úTæ¿~Xm¹MÌ´˜«³bK¿Tmc,Ÿý Ì);R×ú%—¦1³?òãÜÖ¿B '¡¯:£¶h!K ýhV—Ÿ¹Tã5ñUss\çÌBý 1Ç`dè3|d ž†G–Ý ßárùµaÿhí’…ÜdDd÷)»[}M 91Á¶Vœß*hý ˜ÀôZoI›¦á«ÎsF‰5GË+Or2j[7¸÷wð)í0pÕñú Ðâ ¯ Kr®Ÿ}œ»z.8‡w ‡\@–&­ÿÃVK õ†p#e<€㊅«¬gµ,ªºÙ>BíJUAžäæ!YªÞúÐىÙ5¡^D8Zh¨Í’ z!N,ɃãÝc`ì½|‘¡´ƒEµd×]“]{T<'“¡¥?$Ó°Xµ†‘Yûüë¤&”öª}*1¾9L°„oNõ]qÕÔÀ¦8Ë?E,½8gÁ3¹×¤ç‹VŒ'iî30ÙáïÑe!c«‹ÈƒbQI6䯮·¤†™{ášÔuÀ³jiþá'çfØ‚_Àz Ç6Ê*ù6ÆÞMdJÔk<¾3ÞýÕ¢LnþÖœ4Pg°(½b›} ÁýG¤%î-‰=Œ»ÑÌtWŸ„73<ÇSAã÷dæÊÙ‘h›A!æéº\ŸþÕ¥ƒ¬Æ_Ñ]”ŸS‚¸„ügÓᡯ–8êÅÂúöƒúpë8ñb®Ø•·@šñçÊbWøâݹÞ삇٠v·æè«ùQæ…2þ@¾›\¸“A5áb!’€€ÞM.6Pî€ý8M\ýJõ®˜¬[FÝHU?Z©h ²Î &Ìb;úü1<ŵ( ©íŠYÁü~àN  ;¨ç®õ¦ß•`m‘&VµÆÉŒæ.€‰ç$:Ñq;M¶T—3†¼KáŸ>xwBøù‚ÝÚM§™)Û%SQ-Ð+Öõ:eUwƒ"Y9¨t2šv9­!¦ž54¡ò|½Z934ë‘´ì‹ÊjbDmDÛ=­:)“!`´¢uk®Îßâ1˜W>ÞÜh3+g‡]g.qïd(Äõ¶rŒ²u9 Ã)æNÜ[p©|ãÍl,‘¿‘@MØl/%…áÞ! !±˜1²âhÌéâ¾b‘Moëfì{lã;v‰ê¦Ô¼áR˜§y•¶áOôü›ngÞÜÍH©BßÐc§¤§~U`ÆE¹žï|¹êo˼Íüt¶dÝVÉ;03>F&œ» —/qÐ\¸áë|òó-¼‡£ $3¥ ógîð½/…2ȧÎJK”:9鈹`SàU DĨ>EÄ0Õ .«î£“yâ( ®ÆÇQŽ¿Q¾8._@™Ôq¹·RqÁ¹ÿüÿ² dŠxV^¿Ü+àÞðˆþQÞͬE$G.çÊcy¢h!·HÚìMVTZmûz˜öG~ž%PÄ û©• )Èiûl€­›†b( üµ¯ñ¨ƒ4¨nŒ]ý¥ëç'èšçž08„ËÕ:/ß8ÎùÁõ¾?)«KÎG¹Ìþ ÈAÂ¥5«¹ÀôéU>ˆ|Z§Ý¦í ¯ŒR=¸ß6_f“MO‡_M¦;F˜U탑*¯Ú‰l·ˆfëÁþ³ÒA6e‰˜+Ç/xå”.Ï„ƒcTJ ë £`L)‚X@àW›£ÿœXJ™Ô8© xD‡x ð†œÓ;×Sá}µUâí! µ*2Ë:ÞçˆÌtÀAd&0ÆÞ•Æ}%öwÆZµë±ip¾sçM};† #ùÃg=‡;õg±ŒìâñI'#—~ìòO#Â$~±ú³SigJ{s]¬ƒªöЉçå²¾°[n$!—oåÀ§¬ãDù÷}©ÜA˵h X]H3@MèðgqÏªÕ É8Bsœ6(èYÌÆDxʉ~NÃn:qϱñÝÚýÉí‘_…tÀÃywƒbáGo·Y¸òîå2s©>ãqô>fÍâ eôpiqKÐF=/¥ž»áð+)ׯ÷³à †–bzµÀG{…YJW+€aŽ2¿á¹Z­ä€ËijTFõh ãç.¦$gW‚õr‰FyËñê$Qê0ΆH¶ðÝ!ãßÍÝ=û¢/o» îLlåJbò߃ù4-/ôjµ©…+`4Áx­^C°Rûˆõæn3Êð%áJSmˆ»ÕŸTˆŒ£¥G0ßQ¬× x¹ìÖÉÔ°¤ŠÄ烗dÒÀt>RÍrmý½ê”i²­ÂÙf|•Á« oD~á ãOæ>Z!thÜtJ]²@*gK'óñ‚n‘ˆŽ@W3M}£ cWÀBŒ¥ÿsÓ ÛQ °Olmö|®[û•še¬ ë½/èpŸ9,®Ó5jŒR£Âö…´ø&×b±Õ³BäDZ³hÛ¯†IA€Véñs¸MFóÖÚúéÞ´|[ ”¸i¯ùê¡-úa¦“¸šEø$j?l››`,Õ8¬ºç¼4E¦Ó1 ÷à³÷!UGÛZŒFÍu´@>$Lµ–ÛŠi,½%NßÊM) Füî« ÌÒa ‰oP£¬3!0€hrÊÉÒ Aî.Ú^ɬ¾„bj'Üᆰº­âT)äýU63æÆi8®_¯G)ÝÉ[4%:MÉ¢útþßú~ÞÜ!{>¹ê“ýÙJˆ"ÝtZ°¿MÔÓ7ÎlãPè>Ê*l\d)áG]î“„¾üËÙ}BêÇek¿ìuATRn'}Ì*S鿦{‡PÄlJ‰xɳI L·…c nâõ¢ÕëåYx>¾RÊß3oÞ7ÅG¥ä[vÜ–‚1Ë,áw bÚ™„š2£N)ÀiTõÁ¢ ¼ãn©u^§:|¾«°Ò.k=n»á®±ys‡©yaDøp•ÖlN¨¥ÖxZf¡EÅ”xÚ8¶U$iålKìx·Q>+ræ“Åe»–‹qü‘£î½'&I~?8†)‘õƒܳâ·Jï‹Án1ïÙO¤úG,Ö{ž3˜:ž’€€ÆÏ!±/ƩޙñX“ûcq)IvÃ!D^ÊX‚;”9. Ðß'²^õ$ c ¢¨½¬’§]×½[PãÅ&æ$*;^MîÃeùLsö¢¤sf±Ñ䔈~ÕjmH¯Ä÷ ˃M‰o`ËšŽú>ÿ¾áÙÒ×öùu ‚ºô·Æ§¸K§' á"/[ßRÍhfZƒ•ò7úùèÆ¡“¼‚JZ8œñô)¸Ð©þm+ɵ‰ÕŽG‡!aÔÐíÅô¨jl× “4åè3VvühFÒMXµ"a BD‰ñ4$ξkáMÁbCïi)Æ [AÚëxpJ”ZºK¸¯¿?o IwÕÌœ°ž¯¯¶Ï 4‚‡ø¯7%ª¯ d?Ô|C×jB „‰ýP“%ð)âÞh‘ žÅ#ÑU j+[¨Œj†#¶Æ^¡H¯üùë 1+tçÔ-1å<ÜS«ŸŒñ˜hγÔÛÍ„I| þzX Ù£º%,O¼28íçNá¨RmÖ§íy8’t![vK¾àäú¼4gš¢üU&å5Þg¯°Ge|« £TòˆŠL,e×xÆÝœ4Äð4œKkeï©ñU-Ä„"ØñÜÆ6 ¤UâL]áÎþø?nâ›}i+ÂóÃá³í¹¶Zã‡sNL]%Ùòz») ˆçÞëš&/´ê¨H{‚éÙ~gÀ_§ÆÎkŠ„:à„µÞåã7 Ê ªMf€e½é㔟uºªXQ.9¦®¥j-ªÆŠx>Ø}(Ít´‚óÈ Ä9Ó:…C®Kú„–!Y $)œca¨ø$*vü¼(çÎ%–ÂY]ËéÄgÑå|w6Èŧ'‹ï\•KîZõ)k+™Sæ ¹ÏªÖŒhä%Bjk^š†¼,Ød/©W•%“¼>ÒøD‰=Ý.©?-¶û•$¥=ÐPç¸*56<• Ãu¡æ{]F2MXnN‹õV±HšŸÖÑ0äU~g¸ÿ¶@üy"þâ j'¼ö#ÐqMêuњ໊˜gkë¢vç¤bm„pþºÝ¨rÎ¥+Q…´×H¹o”;qééŽáu n¥­ # ém¦A§ÙÌëC·ˆâ/#ím~Cî•Büö©¨õÏÒŽ=úÁ›«¡?V %c‚ÓìPƒ«d‡2­¿œÐûD߄̒€€¸ìyyÔšˆ?+¡¯‘ºëóC¨¡ñÓÍÇEÛPïUœTþ¼ ÊÈÄèv% ®ƒêçaCa*†£öïÁ"üLÃñQ­xx8Î÷Šì,`¢±r¼+P—ÂCÝzGœ¦ ò×uºêœòSÇy6¸Z­sm|1ݳÿy&œ™õB_{œàä)k¼Úœ3Á¼ÞˆïWyZadÿjë}ŸÊ»'6‰á¡UÙ”–ByÔz^DˆHÈç<—Ïfø*ÂëÑ1…þ5 D3 WGú%Œ4—\­rò€.rö¤åEUµ H¤š(ºü:¦À[Ï?¾cí½ ’ÆK~Ã×i`f &Úñ– ©/iS÷Ár¨`]´›‹Ý´tb¢ \žéÒpp™â,Í ›Ä”ôÔ ÀçüÓŒB76ÿxí¨n$˜ÈoœŽÆ!j~¨À›`Gï^réxØ•žÿîåkL~œn—¾è>úcK‰²ê’ˆ•ü”õí3bö"tO¨;RÒûy_";L±V*aËÝÍ+åÖÆ©ðmµ¾†%)éÛLr¥Ë ü¼iT”×gƒQ¦’|Þñ7 šÓ@Ä—ú¯H8o,ÏPË›”pXÛì7àScðïqsV·,<§¦ «¤¦ Šz·ÄI{ ó!)æÅ\§ÌdB› ë2áöB(:$d^¦¹ÞºXÔmõt_±Ô÷"1'‡ÕjÁ•nkkG5ux«ÚÍ“BêcêEæ7xEöP¢óøš¢Žd^ê‹­hVÖ•ÎEÚ¾Ÿ«{íƒ*3 ­%ŸñîÊØ8D0ÆœJ“qKg)CŒ !5l\~ëÌÝ}¿6œò3\gíëZ²í¦Ñm“;`?{ÊjìzÖ’J‹©ïrûýsþÞ\娟…ý>÷)¨'OÅæ;?Z­Zºæ®ªŽÃžàËÇ®hž:µ¬­³zϰYÉÒtÔ\8í2û:­À}vÍ_-©7ºÐžøø1ï”_Ñx‡eÐr¸ƒ0a_¾t9äbTRÁÍö'O)Qå ¥{^” K—ÄuëG"Û"Û¿ÁÒKíØQ[*-ر1Î%†ššŠœ,1WSö­´zjM¿Ä…"¨¶Ð’€€¤E¢™¡B? ‘ñ“á¥$ý=V’ì›Û¶Ç·ÐÖ¾L˜^Ì9õ  çæÖPVÙ{ºÿs¶÷É!i '°e«=Ž BFk”h‹7›ûì R “g¯âÄôÚÒ ­pOÀÀ#<µ~‰ÍÒ-±êžg“–¹ °ÖX—}º Ešƒº®6Òö¦™é@+“䇨ÖDé /«ÂHö6JŠØ¯ðÅc¤ÎãImVŒ§u‘+›¸3‰þÀ0’š^%Ǿíg/{ÒÌE­˜|J„ZŸbCJ‡«>ïïpO°L¬ ;ã×’¾«Þz(â~6‚» ·U'Óþ‰íÂc 'ß):.ñÃ]ÄγtQ µ¤wZgï&!ó©›@MËRÈ*"A ÓÆ|*µé4^ÙòÂÚ ¥ÓË%è8òføïÀ߸yæÐÑY†Ä ymy¦]ºýH‘Ç#5r9p5[×¾fñ'•D²U¥þm¿“ÉЫ-¬ ¹ú x¶c¯Ð­‚Ãå‰== <án.ÖWÞÉï¦)¹ª^aóÿj9/¶¢êR_‹¤a^èu_„ÑÀŽóÕýuLxMRº 91lþ3qÔö’ÒOu@*kŠ¥BU…†0IèÇ… 40âøXGMYrð~»l6wžN®²gã=‘ Œ¹Èó‡©s¼cÜ®¶¦pñJÚ?ˆ ó²ø«å®.é¶ ùéàpyu˜Œì½«ý²^¤ËÞÍ„³²^â¼ÏÔ|‘ˆŒ;‡ñóïÅwk®Õ¦ß2Xä ÞÅëõ°_É¥Àa§Ê]>Þ,c!_‘¨Õæ¼6Ï6!øaEÖÍ:§!Z$F=Ù<î$XáA¶ÙE'”pŽV˜ïó„Èæ‡|»œ¾ñΚûÚŒ»½ÌÃG†BUŒA–â(ÆŸç{š>Íäh.7[%Ô¾. ",ýØzÑÿ7À¾ºèí:ýDœPiL…pÎÕ7®ãä®<\åö u#Í_ÑssžV(ÚQ ¶É¥lPã(¬,†Þ_/ŠÈ«Ê+OFeÌWëui˜5Nzkìa8 îï øŒ¼Bî¬îÉñ‰sÆh³ õn½®úy[â’€€¯ºhµ:ä¿)&q+/Ï-Aûd¡sQçE“º¿]r±ÁÂËdS‹l¡S£[¿=‰ê5¯]6Ö|Y§®ÒîÈ’é¶ÒVØ>:…Ä.8T²©à3QWµøÉzþa‹½¦ÕÁ4Ê<–DÒRàØH©›,ÛQç“«z¸Ïöb—KŠ^Êdÿç”Z ßXÔcâ_–Vã0+>jÐMŸKë}™ ªºþFq›èH†½ggã­3…îß¾‚»Û9l¢$L.”¤Gf¥Íc°í‰oFÕ瀚ózup„¬j—n}è² r2 4V ÜÇsé\ð˶Ú9Š ˆ[>Ë¡Ìb¬9ìÌ)”ú: ÒŽ­‚2n?ë3•¬¹· â,@àãÄ^vöï¼½ØQÚ _¯ÎÈÿ›ùÐÓ˜Ë9vÅ‹›TúÌWòÏU2ŽKyßá+ 9ãä΋.S•&÷ Ë“Í~ücÁctJ°Pi4?¯¼fwó@OfâC”DÃc*ÆûêÁÂl¢¯}1•l`fXš¬ù1vj(ÑãêÒ6ÇùÜo•Ž5R%ᘚ4ªY4ío„hæ +¯•GÐ=EŠDù-§Ôx‚Ob¦häƒ?†ÞC»ÛÎ叿a—Ã÷ê÷¯NZ¨¹¶ñ e¤fص³lµk·ùçxÏ"ftSr»žÚ¨jRJÃ÷ÙÔFýèK9Ø<™oÎH—[6 Û7ÑHs›%SîÜ—äq:Y¹”‹÷Ù×`€xÜI©€É¥¡•4üá™Tl§Ìa«@¡cäÚÏÑ)HÂSqê ˾œlsÏQb€·9é~I;:@î÷í:¹{jõÂYm3©?aê<¤¬ÉLðqr5«ïó hWšHkHum¬º¼EO^ÎÝ0”ê4²ÖÍäD#EZoFžÁÑêæ€j –›5f÷-ÅÇÿwý¿á¡j ‹íŽ©ÎÄ“oênÏÈà =Ée 9›¶úAÙ^ÿYÂI\@–µ=ð cyØŸmâ!+V̺‘ZÁ*ú Ýþ’^Nq)]ªbëS–MvÇ ÙüaH±FÔ3£eù¾ßC³_S÷‹•éÚ  Ê.Ÿ4'˜(ð?;7ŸÕFx»^\u_Ÿþ­ ^ý^»Î2= IÇWQX‘ú¨“×@ƒ^6’€€Ø@G'#&AwÞvH? ©“ïg§ž•U±eY†Ó †[4Ÿæ\coðƒ¥ ]~æf*ÖÈûžÅ¨BŽðuïLŸ¿ãÚBªšû3´ûÃÞ ùHóþ)òèv¨Œ'²´âØQÓ+Ú^OI;.“Ý YBc‡­,)퉻®cZmÖËé¥ýDŒy.‘ð ̰i[ñ »$Ñ-.y ý(¨ „Ýo(¦ˆ¥dùË$æÇ[V=Fá +hÎAbHÄU[óA¤NÆmÒÙÓ)IמÞ|OšÃ)^uS╆ÊaŠrBßŰb¦ðˆüíYñÏùDQÇ/³NÐÀƒ©›6Eì[#AF×\Qû-kuÏ|©(uF.q¥Œ|‘æFax‚@ quQ¦‚±gÃQʧ¿‡hQ;‚#ù©·÷‰Ö¶MHn\qÎ Ý +Ð<%oml…Éa(iJGÙv‰ü–ï®…þÄ5½«°[¡˜{3í²Ý{¸^©ž—]Kòzî¶Öy–vY?øû¸­P|›B©r$]NK^>×µÙÜ7ðÌìþÝ^¹*‘äõ0ãø ï‰]&Mï_ðÕ!S;ð_Ÿ°mÊ]QVôTïõVƒeoû;Ìödì×¾ÛæoP 0Ú,k‘¹|Ýò‰>éZÁl¾IöA éõ'q[ÔfŘJožsµ».2Ê?7þl÷sË+̆ÿ>TâOŒ¤A½\ÍÇ :K¥+Åû^ælomÀQú}±ù=‹4¡8=ÑÊòÚ¯“0±)ØÜ ÂÅÄ!¹µ»Ø s믔¸®a~òt*¡ízô¡¬mX“õŒ?€´†Éq}ºeU—·6ú€x~ ¡ œ:Ê¢ô Oh FY°O2.ZŒ5Ú5»W¸èã»çA› V¯âš™·˜Nµ3=†I˼wž{Çën@¿‰_rr÷'>… €ý¶¼OGXÖ3…ùˆ¦Q¶@Âí¦|M0TÝvsÑ EªÀ=•æáëíÌJ=¹9Çz>yGY=pLõ¥MtåU©kvù]âüHÐ~>\jÇðÔúË îž;G¿íÜêeÜIÖ<íõݲ\MGÓ|o9•óE:JóoJwRhPë˜îrVDG B‹vAÅm¿à†1Gƒ2ÔÏ9†Pû—zÈcÓîb¨^Q1þÞÓ5Ïë2€W?ÉÞ­Gxû ÆüYö*hÔÙHÛ²k–2fjÓ@Ñ9†zÎc»óÉÛª%ûY±@ýa:AŽôÖÔ @ŽgÖ|…윻[òT£0¥ùÓw½¢aX…¯€ó)ôºa{}ˆ}ºæ鋤ŸVæ¹I{;Ûê`hW·Ë÷é³£ôqAËI(Îí85Ä ]Þ{Çé'+L™Â.Œ\äM=¾bÂUCŒ×28%„=oéŠ/hÅžúáf&®ÀkmCv+ÿ¦Drxí)>zï•"Àðçuœßü=›½ñ 1°7#À§Ží µœK'IßÂh­È¬Á,L{g͸˜¿"ÑsºþlŸo¤ *)ñ¥Äó®# ñ@­Såð 0+-c>ß?ô¿Ý»ôP 8™³ ¦†U#Ì‘lè±ø]!æ¼/÷?«ë$l,¦*R¤\åTØþêÝÍ÷y)BÝî JD\ujœ³”ÞEz£nód…‰—S¾V§W›ªIÜ«R.k‰mƒZ!Ï ?´.hñµÿÀ^Æ´±ôTf¶Öß×Ó., N[G/t1 ;ÄW|>{G™È®²&}¤:Z=„~l,ûØX;ÛL\ Èï4¸>aa"°ñåâ9*ð]‘Æš÷u\šnBô~â6Ánp†Õ’€€½álDñTpвNÛ\Rû,±ZäþC0Dã+gwü‹‘¹¶­Ùt†°hãX¦lôI¢ÑÜ-Fí‡qk’x‰ɦü¯S”›º|ª)Ÿ‰W%…`T’Ue$Ÿ3YqÛÌ€&‡ÍNŠÙÇbÏt/ÃuJ3&ļϓ.Ó(šð×m9îo,:{à»)ÇL®Å à%P«@{ò•7}¬D`¸¼Ïõ)l(éÛ†lY4 aáuˋ֭ä²yì&,ºœçT.cÆÀªV¾«l¥ô7ã:ÊÈAÞR˜Àžƒ­\ËácæC ƒùçÀã '$ù¦Ñ-ei1yNíÛ‚oyŠwÑåfÕ'ºÓÌ@8Q”°îUšošÀv™ªÓ¨sÙù ØdÀÉèÅV ÏadçEîb³”ö!òÀ&É7É‚~¥°–ÿ£db!»µ®/.DÖ.Y‘w'îCê9CÃO‡É2"Ρ)b“ÒYtT\«—êqë0ƒfËscßqªj#}^ÓF+~x1—˜Œ(0öÜr©øÝŠÚ®ÙzAgÈ«¨ª"SœkÉ]a`®àÊ®?ïÚ÷Â[*[ýDÀå¡ê¯ÕBôî°ækZØ(ÿ¸Dâ£b¦Lªf"YÑ5@Ó´¬…ßh%ñYc©¡7b²"b ÑÚþ&¬"üÇg&“?#º%‚û²uDf63lxürÉꬢœf…ÍÔüÙ¶$æ/Çü8¦èª/µ0©^ÝÀ—ÌFÇúb£žåŠŸÃ2f\a]½H2³h÷U¸Éƒ »<8$¥8Z&©¨=a½ÏÉh3©#Çü².½¹¶SÞµž‘)À÷ÎãÑ¥4[äÞ c1l›Bй² i*nuå`щÓÚ%}ùf” 7S³Œ>F”9ô²j:æxôºO2MN~~™œ‹Ø¶L·çhö°1؈Ëj “ @”L—žTØó›4 äjŠßâ!Ï‘}éЄ§x…rå(}ø®ñ 2£Êî3»ÉêöÖWfŒá`;+mã­Ê3¶:®Q<ñì>µÍ\ú`b’7h-§Æe²_gaÒ­¿w>åð²w±à0ubÛ27-ëáä@â^ÃÙU7W·ÇZ7Y‚éG‰h¨.¤.zOpiÞZƒn›¸Ž’€€Ñ—®8’¯ªžð¦ÊŽÍãa”h3{Ÿ­eC…ñ0G×tW¡¯=Yu¦ìdõ&9D+¥vg¹ NÔ‚7í¹¼'òCàd`W"{ÒCZRЈbë~`YTýb½ØÃÜrÂã—h©Ü²H‹;¥õb;{ÁC4§ÑŸb]í`x´é5pM!¡/M7t`Ï¡‡ùÏ^‰ •à§4š~9i€ys›Š4[/nõêPXÕ1 "“lºÝ8µfY²›©`;<¬>„Œò~Ò„kß2šùµ0-åG4—ç>¹uõëA‘ˆáNs}aZ÷ÓÏÂÞP–ZÚɰëêÛÖ‹"öÓë½}}X¯mä°}˜Ûïµö€ƒ»—9RÝ€k7űV[3cY0·å9án¦q¡öjÛ†€^ ¬ý’èrëäSÁ[¦€ ¼Íï« y4AÈIÔp^§aÎõßkøãùå‘þT“Á'»ŒØÐª)ØØq,?5 Ðêæ [·­YñÏÕ8 “Ê£…â ¡†'•L¥ªS€!K]_hY„û©Ó·X/BJÓp‡EÀD· Æj³dLÏ€aµU ·¢3YôRÓ›ê4Ä€Ÿp6'瑚&Í··ìÊØÛZ“Ôbƒ 6gtzÚÔʧ‰‰»ZZŽÛF`º$qJø˜œ@Ë™Y¿±í÷YWªª;ÎNªêôšðܕڸhr„ÌëÒ«IîbV„“icú~×®>#ôx'äˆm^±¤RUå‡(=© \,>¯n;ꃑàsáò×€ ?z=Òã³Å—]smá0ï=?˜ÐhÍ*kj¤8[Î9§ŽUMš;‚ÁØ£=sj¯ÖEôVÜ#‹×ˆñE\ºÀ0¤~¿Ç¶œ‰—ðò+wÏ!³•ú9’†°<~rÎF œ£õDÙ«,.5´Ã™"±†Ø#>ez嘥xmÚ&ù‹â÷J_]F§ÿpŽ’úë»é(Òe·^ÿsD r¹à¾3¦ÝK½Go*¶lêØ´³w3É¡Tñ=‡Vi~«%‹«ª¥DâÍ[2–m kC–W* žŠNèCi‡ã'NXû ¾ÞUSnÝþíâIutøàÝìÀöë_IÚ¼)l&-~ÎÖGÅÖxelEÿÜþXº:ú=aSžLÇD~…ÿ_<ךµ’€€õ’l‚‹‘B6íjÍÉ?„Tí­¸æH÷úQW¢p¦Ñùà„¸ âOF}Ø+&p2°À  1ó€Š @Á_­DNUh ¾¸—h§_ŸÈ6!¥¿÷!¬–:z¤q9Ðà ¾³>’‚Ä,]dbàJX¢¦ºZb˜ fàÖsï c‘EKýïDÚzs ,†Œ¨vé>KuŽY-ŠAÇ:¶þ¥Ü»¸ºš•;ì/üÿú˜?Ö3Óîqiêz^]žˆfžÿ2ÐSnà´¡ö³9»ËÛ)¬ú’EÌ\\6Ôö89\‰Q»¿Ç  È}ІÕ¦ñÔƒb}GRúF²v£6ñqídô,3#0LëÇü<¦ U/×á‚Km×W¤¨ÏZE¨'/ K‚Òqœõ”ÝV ¦{ÄEªÌïÅÁ’žÀ^OðšÔ)A–,ÓGŽçæ±IUNÙµ˜i¦!Še rðÞE2[ŒÒ7£Ãµ/¿Ìh÷»-[É›ŠËPú0ÙXPŒ$UŒÝp{ÓÊQúþ»X_l7é–MÇרӨu¡­¨DòÞú@lqŽN›QàïãL†3­=avnÇ«ìs”c7?œ0÷[ퟅ¾ßù‚SbQƒ³˜ëL(ç¶1™Ÿ^ÁZéb­Ô¾ælZ…Gß;ã!Úç•£î-z¼îÓl(ùÛáü7iK=ŒEt“Ÿ¡Ó³=`Êõtä4‹ÙG})´©ÑU9Êåó‘´×äA%nbL+ÒŽõ¥£on‡OñœWÿ$§6bx²C°QÛ¸©¢0I f_‰6lxß ôÃr“Ä/Î|Ù_S|ÚRw}n³GAÆ=X‹QN6Û¡ùA~æÃâ´²ûßõ?ÅÊæxB¬Î\•‰èĺs£A\ ý²l(»ôhs×~½°`VޥݾŸm£EÅ'eoO¿¢â_KÕœí×É¥{ÃñíQ*bÐoªœ¥ ¨Ø¥¡‚~¦Šâ÷¡“ØÞôeñDŠW` ?´ÃZ$޹ì^Òíïã{uÝx®ÆÙQhe¢U6š“6™€N÷éÕ[mâ€Vdª}“.L6^Ä3mIµÐ;¥@s/IÛʇcš¹W}븎?ôeˆwrO¾I£øýz{íE¡’V¿LñS¶YzJOQÙ£B[Ã<š’€€Ò¨»"ãö}c6²`Ä_SäoKy˜ì*à±…(¦Ä3pPÖ‰T¾ÛúNæ#Ôøk³ýð0ä{ßw÷øºÿ]BÿIt:qº˜‘Ôê¢oÂ:CÈÁo(7·`º³ûcW@péDet[®“ß5gƒ{'=CôKË“4ËÛC'˜JÇ{§'YA>œ­ØLŒhÀœ–LŠ^`‡±¸Ï'¸Ezh¸‹òííBNûɈ~¸¤›-…iinKÝܱBˆ2HîQcn+¾ÛÛ‹âe(â‹„)µ ×¾n »" %±ÂWCn¸ÑË_kC©`¿ ÷Ûms‘B¼CÑ2déDžì´.™tk±á&¡ ®˜TéÁ>çØ!”2¼wdE¼¦ß}ÑŸê­ÑC¹¬¥%â X\z@o;×ßn‹{Lª×} ;6áЀ©®¬ð¥¡Ò»›ö0°šmd|ë˜ÐL\=¸Ò·ñʽ§Škˆ7Ør-Lv*×Ñ)8äúà C¬Üá ãÀ<¿ºÊ&jɇxD„èòS±¶+ƒÔ¾þ³£Ì«éÛÞzt€ ÈK¸žÓ˜Ëcá®À~aªùÓb¡ò¯ôö¡¶vQMK{{—”œ¬è¥ÎÅ_¬Ï~Õ“c@¾3¨#È]+„õEƒ˜Õº«"S¡›—<£î„?ù]fdÒŽ!ÊkBÇ;b¨²ÊqDåôÂzUž-øÇ€òTy¬DÄeÔ›N@«kD[j¼¡ÀG²é†itàÆ-Ë{• ¬ –$Ѓ¯ýÂ…ÚÒKÌ—©%Ãp§¦f1¡°@*P3–É£7¨A½§ïnær¾Cs kزa™ØC­êöʃ¶jž…cÝæ]ÖA¾íñ"—õî‡4A€‚ÌaQ³ñÉsŽp‘ @ç‡\ðkÑ#/TÅ£5J÷z¥ì»ÿl®¦”r#K’]É­³ßÆ%‡þ´øbWðç÷”i­AçÜp2\lìi8¼FÇžéš7^Vë÷̼¬£<3…H¬™ '^ ,´ûÂv86Àù[L¬›j¹Á1¯_ô]g¾ ,'yDì”?Nš#ÏG,°SnXcÚ×lEƒ)2&Šð™gµW‰ƒ ¹Ž›´åÈRKµÂë2ÇJÀ~|<¬¼-ˆèS’š2èí·r£CYQƒ¬ŒÊå^ƒM¼‘Z¶©ÈÿFÙ=ŒB†QÑOQ‘A¢ÙîÎü”ŒCžˆ’è€w©¦Â÷\°6óÓÆ©·ÐÞæà}|îÉ€e2ÒÝ„q ñŸ®fµêOó­sïÍbà¯ìáâD‡zž~é¾®.õš––tû8PP|ïÙbÞ&OJ8ºï"/B)€ùr(oþj¢ÈƒnK ôâùMn÷Ö‘ße¶kB_NÔ?óHÈ„}õF¤ïa%0K®÷0¡ï¬>£7+¶ñwä‰ËX2WI:dìèš²õ e‘=Ø¿J;A¼Æ[®N܈èßë=³‘ÁÕTTà‹z~óBÙb”¥5ò뵄`·Ù3¯Ð]ÛC5)êã £NÿUì‰ ê,5â…ÔÑé/š×#÷èYÿé¸[䓵èNiÅ3Ê}) ë=])*S»C¶Ë sgÝr<øž'azU?—øj¿MA?»W•($Y79ö€W%>…«ÊF)“ù$îœÃ¢ÑÝÓ…—Úß-LðfÅr®\¶Í¿L’€€¼·1Ä@šfÊC'ŠÎZIÖyn5ÕŠk. ¼~ Å0a%F¾:Ðú—»_½—|´U ¶uâËøŸÍË_·Äb§©‹k.ø8sª.Hi»÷8H×#‡\o%p|ÏKí#ºË‹Náz²oJ£F³î.¹ýT=›/âR,ÁùtœÚûßï95@jš}¯Ô,[Ne‘’Oåì… ú©¯{öâ¤ù©¬½ ¢ËW$\G&‚‚÷`ÊúÚ!U#¶d™=r[©±\FB‡²ØM:ÛtÝPH œ¨w )¡ùw™s+˜µ@ËlÞèLØOÞïj#5 áié¿åÊ’¢Mˆý¾0i£Åàâ™üî­u?AÄxÐúeŒˆÃšQ²¤ª$%…­¥[?ú|õV~NËvwØ€*i¿]D¹ˆ¥*ãÕÔl,¡hÏák,Â-¤ˆN`äâ †S#C¬,¥Ë@ Š¸´Ð—¦„„û½ß¨+9ë`/S8öÂ*WËĬ 3â@¬)L®àµná'V–Ò½G­ž£^Œ!%¸_s=™^­Vqîò^ZT¼åU)ýþ“ßð]²í/1~‘õd”Ë­Ûê% å5Dš2Õdժ餹 T@õñëafß÷ÎDWB®ýîÄÆUÆ/Õg2Œ½g+j\gÛ4™Mš3  ç>Sœ¬Ï—´ØäÙû8àØ7uÙ4…gâ´´2ÍUÓÜ öá;ò{jA¦¤ƕ̊rJðHœ0µ(%Ü'päÈ¿œî© ú›Ó‚¡vì†!€JHI{É +@µô…ýÔ\ì£O6ojá¶u *¾¹Mþ™B  RÊÂH}dTAFV?±œ·¨ÀN£Ø•Ö·¾H0ëW¢¯»ô8Ç:¬1Ct#š³l!k=Ê4–=UZ»]5²D–ÉW©)ÚSö%ߨk‘ñ·OcßÃa™×/*b$å³ îo~ºA³%ﳑè48Zr³#_Z^¾Jú¢ß2öý!,â¦ÀØIÚE»ž?+îu1RGVĶ%KjÂnéð^_"²ŸÑ˜xËÊLön¼§¨6‰Êo7 XB·?Á8±u6¤ÕÖ~ùµÎú‡T°[Ó†Ô°š(MŽ‚.a5׆¦ÿi 4ôÄYèRµÑ¤™…"DθüñÈ%A€"ä_'ÌotE“Ky’€€­LËyŸؕݲÕàV2-«MŠG®¾ð/ˉý²Œœ‚‚ºU<Þcv¢äKá7÷ôf<ŽÎp}â(bG¥xºíÁdSƒcóÈ|Oë;wq95‘;>·§áµ½šPéùÜ’jr ïôR¬™­8Ne1rè$r¹»ÝËÔ*f¢aX¼\ûÀ.hk¼>J%{ ˆƒúÜF΀Û>AjRŸàúùG·OD†@»±ŸYzš ž¾X/Ö+eñô²÷§Îïz#÷b¬¼–cL$P²emùT×h±ØyÖÚ0âK±pËU†ðÀUo*ÈìÂVˆËwBè¼'Îãðéz𯲛bNUÅå Õiº·Ÿ±05°#\§µ3ÒœºÅ[:$æHf§ðHÁN‰a9Žw@jÀB–ªrdC¤o@ôbp{Í*Â{[[>€õZ?b_‡?¸ÈL–:èP8J-rŠÀä¶ÙÛ\XÃ;•qt5£}zwžÓ}Á ƒqLæØpœ•@Ô/;~·Ó’82ÁØGX^ŠNCuÆæ6µ™¹èTH9á(hç$j‡RÁ*GürTZ³Á\¡ÖˆËsp¨²¦)k]sEBk‘ÛyÒÌ[uâϸß6t]ç&ðz™”2æ m9.BÂã¥aL}e‰Ù Ýø\ZÔÿ­rÝŸ(ÑØ$rG¥~£ñÕó8á`¼g»Ü iÏxn½œéM™TS0öå8*Êb£NMãyw†!AΓd“ÔÜBª~óCØ&ÉøR×àë|~­5Ç™&ëƒåíýÂŒýíÓ›@z6¶ÖÙùàá¥]¥.¦5<€Ö@…v£b! âx“…¯ŒãüžúaAÀö5Ï[Xš›ýzÉ„¦Ë©uGŠ|ÀÞ§­÷·}4#µ°g}9(Šha½Mw:õ߀¯ÜC|Kz6]rŸˆ•ŽzmÈ”jPÛjÈnÎÁoaÊ·»²RGv»ò´©óé«‹5—º]Í´t‹­ç; Ìk°5-ÚØ]ÆñP L—•Íu.ÇPè­¤±=üy=" 7`$}Zkî½ ªQ'iG6p0s4Ü•T'jƈ0ÂÀ”Ч0M–oTÕ‡èÅÞ¾Mû}ÿ½œ™Q÷T}õñUB1¤É$ ê’€€·‘‘lÆY”k¿×ZÜ £yPô°â¨ÄTð“®ç€Y²å5í<ãË)yJh‘DЩ|GÕï„EçóSFÓU£Ä`ý8K-¾toœ±‹XbË6ÿáÃbOùÙˆ—6›q~€rHëëVÛ/]-ÊJ¦À»G¨›< mJÓmÑm“çU ô{¡(ih¢cà À0p'-ë×Z6dJAã9µr·¸{=“D0¶€uÒÉ VkSõ÷œÂú®Í}ìØØiÛ¹»;V5Ñ pu²ö6?u÷ÉܳAÖ‰ìqÏRW –¼]P-˜®(ójá’€ä‹wo™³ÙìœékHn?&6µ/ gQ3QF,ò0L¯7¤Ô–…7Ön™'œ•wÐvJ3‹W5Þ[?­Ã:ïé#¶¥è©ëw wÕŽCDUq˜Ï¥Ù·z¶èW“?g9+Ä3)˜rC§’»ÏŽõƒŸ§‰¡È7¸¹¼î. ÆåÊí—¢«WHvô]áßFç×@rÂ.S;ÛsQÆé×ïæ–Y~oñ=ƹøyü”÷ÝáÙmi°Þ‚„y9"Õ4òù·ÃöKöÖêˆÛçÞ73ç«’€€¹Ú!,že 5Æò>Ѝ~Èò…,:Ü…kÂŽ¢ j 9RØ1Üyü*ÄË®Å@eåi”ÓÏaÞG^ïÇ6ÌfõqöÛž©C·ðó>%ŒÎ<ñ‡š;~¢P®p‚éVË쥭.–XvVY„ò5çZÏ>P¬F¤ï¢Ïiž >Êâ;ûû\0“ê鬜^\(ÇÇ5Ó»Uì>烸 þ¥#dÏG;‹“ÓUwÐÈᦾ^aÙO¹†Â³sótö>VÕ_À"ÖþñLþ DÄÄK*ŒÕµöÄ»ÁÇ.h!ÿÎ"¦Ž—Æ"eÌòa‹x-Õ×DyMy@€/¤ëÖ”†¯DN^›%ßÛXˆš’€€´¢ˆÚa2 " DTmµ©ƒA”w)Þ•s^vŽÑD•¦ôU: +摊Ž2ÄHË‘QbË>œj60l,"ox- ãc€å«ULŸ±)YUë”Èèaاì×Q8±gW+Ï€ vö-ÊC"ÿe¼ÎE:‰ ßV-µÍ¯Â`ûçy{MkZš¥“|j„|𧆫B'Äœk÷°€>3øTŸ©-ét@¢:Ü‘zö!á¼Xs˜/Á…MÔåæ›KDl.#è‰ÿ™éÄ*J—ä.çp–¬H.+œJÄñ ¯sm´óù¾^Õ¤~ùŸ#T„Ê!´üPÕÃt%Z¹â¥ ÔÛ"ãÕŸÔˆ‰ÿþ9§Ê0›‰²v&ïZ ôBy!…"Ãô_‡¿EHž;ÃD®ša„qÊræCxÒšÐ#‹_\(ݾ! ÇÍ=/õÔm[0¬¼øo½Å(,Éqkäç× +V7"6Ñ…@=s›^20Úk ;«px…D±Á„ö¼['t«ÀJ‡™ ŒKÂhü*¿”&+z,g01?Mdù¾:—Èœ4{ÌYvq¸1ÀɦLÕM#ÀFà|eP¶ #d>apa4«p¸ýc…y¹nj\6Ó,ÎGŸ¬q.‚Dt¾ü|ø«þÊ 6£-ª‘å º¤ªoc„ÁB6Û¨—M×½S¢'h±VñTÄûðÀ­¼_ÁZÕ52é¯íy‰¦¡ºÈ»×ÑP{<¥R‰0\cÛ7œs“Yç!mÈÓ3h´ú¶ÔÂ}T0DŒUP0 $©ç¡5ZÂ0@ª)O±Ð—¢“ÄÀF!hÒÏf›KC¿.š^Paìd¡Q£¼D~(Œ¢ãÂþ¶£©ÊM!Ô}€Tm¶;†º@zÊ»(É:œÄ !“¾$‡¤éy8ÖkÔÉ$+:ºTòaæ&ýÔj*QLÕ› ~aú‹DEƒxXŠO(ëû ²ÙÅÛã±°Aÿ4zˆp1ÄKò˜d Ô—æµÃòÝAG+AFx"œÅº%³æv©ÄüKíÏäÏMhÁd°Wל¸£°Ó&H‹7u ™¤œg_]²íô½ ñžv‚¡ªv¶Yål.÷oй¡ÄÍÔ· ø<`î"묔m;àKï .÷ø‰%›ÄHp5 Æ?ò2Á~î2Y*Yç¬_'9#h%K-ÙÏÆc`—#übÜ\Ù¬ày×C'òu‚v…šj™ÁðÚ bH¢µ·;¸Y”êé:4•œËÈ:\£zºÌ·Í}2 ïæÔŸöA©”‰"à‰¶àûÜøžñ ¢=-!„ÿ‡'Å·3ô§$lâ6Б@AjD_âg¢ÇðlÛºúü$c:¸Àp÷V¸).*iÂJÍmÕïñÕTÊylR¾þL¡‹žÔزÄ-´¶ öêÑïíü1¹žî*0“îŒ ÷ZÞž_väÔ¯H¡!¼ßk·O^µæhkE’€€ßkÔÌõò²»ù5œz²v÷ßxn¦éWÑÀr¼0©÷(lM‰«wÛn(ùËÀëëWbâÆ à×£ÛÓ À—Ì•2ðJ/J\¹ßžÛÌÁÁ7½‘Q@è.Ò&Mxª¬ñ±6M\ÈÉYƒôßfñÊlq ?®Ù{²Š7Â$šÍßãÓkïç „ g³’«UþñÓÛ¶š`x/Ÿ¦æ„n̵í`±?Îì¯ù¢m!¹q<þl¡–l˜ûƒ¤Î16kÁôe#j­¿®?§·JCfZ‰ŒÿÐ&ÝŸ –·ñüðzÒýï²S׈ÿ½¸9ÜXœ<…GtrïdCr\I16Äęְ òP-TÝ¥Z£ÿ;×–—ÄwÑã½êžvj°{ñý2ï5DÊ `ôÙè/%Ç΄”[^¼¨²¦w`Øã¿DyމÕÌl%gPVXúô/V`ùX·úˆñŸY2*Þösí‹ U¤°Ð¯'Çä#bá"–0\ˆ.Æ ë¢ÒÌ}ÊΧ•à¾iK š¨  ;†Óz÷ðò"©”(2 E-í:g¨ÕÍ' »î6i¥åÿí_V•o»ä€ûx{•‹To¬ÍRž³Îóºú“mÆgŠ|­Q§Ñ,0`ã,5éIÃô0E»EÛtÞ3£ƒÜ h+[`™JÞÛà’÷[/ì´Š­4¤Êû¦ôxëÕØË×S&Ù:ðoæÀ £ÏTíÄš”Í]wõ9 ý¯ÀcŒLq{²O9½eÃå´®*È W‘îã-=4÷}7h!Ãê«]¬×üí¶ÓÊ,Õ²8ø³ü\~A}X3éW˜$xÄþÓ*Ø5ÛRó‘U15ØÎõHð˜!¤(¿D±?ˆâžtVÉßá,eWéëŒQÓÍð©€0°¯WûÙ•„M$`­%0·“†c5„sžl~;l;욣ÉÉjêö%ûNDÄSHš_ <,·8;$üpõ˜Å~m`AHú*Ï )S~ZœsïÔíãLþUõ½½šË*Aùäþ@w)8}¼¿äqÆ’´Ž†ÕY¼7÷ªÂMÓ ú¸«]“Èá…¯)O'»>ìК„¤Ér¶–€=ü”é¾»µ’€€Á³°›e«ÚÕŠA›ß=Êæ¯Eãô} DPK]U·ì ÷/1·¦! †Ž¯lòirŸÒ‰Œ­:  j:"Õ8ÎTâ|ÑPྙ!æÙBõDØö½#ÌÛ‘×ïëI|{­äWÙqQ§qõ»ï@}æ\±/€½V­fnO£ÕìzÑ'¼.ðþi/Î&ÈJ0‹¥Ê±2‡MŠ_ÚÇlî’÷k‰–Q^Ÿ”¨d!ˆh’UHñ ¬ƒé0¬'9B21Œ²1ìUÖó‡RKíG'÷DXdÏJW›=)Á Gðn‡öÕí“1ù'ô½W‰ø‹&ÐÕArŸæ@ñénâ…¼Ò‰¦€ÜaÅcâÛ¤WÜÝB8é£a°F$Ÿ–ø.·k(­¹‘ «3~xHбb•†.\Yà"7ÕÞéAö”R­âS×þñÑõÇÃ]³ŠÁ,i…ÈØ ³$9Ü{-ùR‹K¥º8 ØB a…Å8 Ùf¹»¡ÂP9j~Ë¿¥o^IÅ”¤/jÐ"ìú*lu,^(íÇž S«ÿaW‘T˜ý¿dë•™À¥ï¼¦sPJ”û¶L£wäTå ¸µu}6®"N§Gýél`ZNeqWD1Ÿôì\°µy”ÓãyàÆC¾L÷ ÷p-·" èfZ}Ð5;—L;÷쳡û_úhPñÙ&¾S~’‚¸3¦^æ<)Èz¿ëê{,x>Y:ÚÖÞ #¯P¾|j¯.W÷‘êñÝái"ùýÁ=O¿z6¸{ËDE˜VV ëÆ'©Kæôæºõƒ7^5*Š`ÐMç±L2÷°CÃ2Îk0i|þß’¬O¯»-£ õ‰^"™k»â÷ÌNæ!Mµß ZÇ€íh©^¢Î‡ \¦ÑïozHUAÅç‰üoðÄ'X÷³3ûQ³8 @ÖÑÕ¶ÄÃm˰yò¨.V[hrŠw’€€µ­×dy˜®æG€è=‰h˜e޽Æ!8ä@Ím.ÉwÛBÁèŠÜÚùY¶ìó…p¾ŽzëÁ-É]€ 2÷ÊãšÏæ=‹êÀ‘£j]¨<ÄG¿ê:|5“ù3t8;Œ«Ï­ÊÇêƒû l`Xi3»¸HtåñøuQŠøÄÁha¢!x¬#cßà´Ä&²‰›¯ÝìSÚœÇÇá±;zOè並§± D6%´<Û+ë\ÿÎwŽ ×0F¬lØð«m¬Ef,†ç¥ôs²Á»0ꌑ`Ê +132rˆÒ”³ËWßP…[d©mލ‰snšpIoʤ­÷ÍPù¹¼(2&±ë!*׸" Ûʺã’gÌUX¦ÄÕ×DHpHÄKslòàzû ƒÞõïT¯c6Mfã:Wsò2 'T„a8‹¸ÂsÙôý¯*Pçܽbv„‚|ÜÄý³ýfF³(r€üõÞ̦þ{o~d7¸cÁJ<0B–ßè€ã_C'è»ÆÿáaÿpöîØ ÈÏÂv_vX»ÿRŘäÛ¢TçåR¤ãW ÞÓw«Kj»û IÑ&œ YŸ•—áÇèaxA5$ý¼Ú­÷ û€H¡Õ%*(®uhÝÿŠ¿£mdØù°ò@¹#¢Î~éâØ;ËIsÁªçÆ–O õŠFÇJ·kÇ×t˜/NH’9³à2È›qùÞ–E–ƒ‘¡~«ZG(fÀóÝYG‡Uu›‡UšãŒÔ5DC»Ï€Ä§§Ž|ðûˆTŸ7 •†¦v» lˆŸ<¬l“*]ƒÝD¿¼Gvï2Â~øußµh“ú $_A …ôÝúKõ>†jq'—Øz?æ£ìfw«½Å¿fúÿÊ¢÷f<žu‡â;Š­$w¸Û?·v«Ò¶1Aªɱû·Y¡ve`Z=×hŸ¨§Iu&ðýÙ»£·ÛÑè”æ¿ø‚Óùöüm—žÆË›ôݦ „[ñº—ÛÖþOG,Ú~惥ŠR¨l™à2„¨ … È(¸ê’€€Äû;ëdO`‘G3+Ž™¾©ÖæòBNð’%uÚ„‘¾zù‚±ÊÚ¦tŸ©yû- Ç$Ö¾©CUêûª' ëÊ RÆ‘zªN$´DÝ·Ÿu̓‡ú`i”pÁËù倻€}rIßQ4Ó>îEhå’Ø7¦¸uÑa¡6®n¶G¤!= o.p”öì÷ÝѾK(¸ò¶É!Ã-Ïü¡¶W!º¥¹‘¥˜³·rSÜT³N£»è×¼Ãòhý{w4 è}/ýÖ{¬µñ4Õ˜5%÷Öw¦ŽqçzËt=·ÝÜÓ.¨¯½k*Ïœ\d¹଩Q–h^ýÙ\õ€L-Ô¾»|§‹v™—.ÐG9´®=”™¹O8AÅ0š§å&ÇþåYµ¹X$µÆ¶C7f­(½‚oYzä\_–¯)¾ˆ×ÖÓŒ|uŽIeðžp’lj?ðn*n% õLU·R%÷&`e(þ5/7ób•¬¼S˜¤­ ]WTæpÌN¯gûHúо øKµ˜vÀ¾B*'J¿›ˆ¬LxÜr´!xÈ´{ìáàÈmqš‚Zbô”Íz+-©èwEÿ§j³š!¨ìJ\Ç£†ÌgînfZvø—%óèIÞÓæW4ìå‘Ð¥@⠡Ω‰Mú,¬"…ÛÉ„ì/h„ [f2bPIþ™þåæ>]$.×’^ð’ÜŠ>ü²'чÜHfÙ´†rsø1øRI‡^ óp¡Ìô ù©_{îÍÿÝ`ø†Ö<î%C÷™Ú»51š?Âê+ݨ:Š?ˆXù£â>ä=È&hLØw™¢DÒè:ÔHW­¯çA®sVCÆ7s10¤“IC¡ý?¬´ 4'¨yOˆ™z¹¬¼òt1 x .H ²a ZU‚b†qC‚Ñž+Oš¢‹welÉ‚¤5$'yd6èÐôù`Mö?ð˜@ÔZÒÞZ© üg÷Í·WÏ !¡ŠÁëœ&pc̽ƒc$Ó(‘0Àz)®³àwNc ï1g²ª@Û=KÚCÅi¤EÇ)”€6àÂi°½Y@­9“_Vì•üïýîxé ®ð?uªe€8"¶”]%dvéýÏxj3ãŽ=F91âù¡‰'~¡Û8>a.ÝÁ‚ÑH=%Î%ùm<  ¼œ’0s(Dl(ÔŽS%òù@þæ2{‚¸ 2´øaIú§¼žéúã!m?¶ï~jµ˜Nò›D¢ç v`çâüŒŽèé»”ûŽH$*oUk®OŠ‘?> s²³œ‹€v#Ü„ݭˉ®ÚE¼)àꫲŒûØhPÞ‘wšRGä’’›Quƒo´¤Â`Í,võa[eMŸóîb–,£ÊxÊRQÛ™ÖÄÛîeu ŽË’^ðÞ[ÔÔÅ6·­‹ð ¡©+Œ>€T°ggõ—L9œôèÞÌ­¾3e£AD™x‹Fû¯‚§Í÷Ž-Œd Æ9×ò³á¹hü§„n— °7’ƒÙ€õh§û·#™ãú˜»ñ$ ìŽ‘á"ò*•)>f_£ŠƒÍ[>z¢Ëб•¯Åu¼tgº¶i­‚:åô¾„ú 3W,¦rOä…Ú­ºšÕÙÓº6/x÷ܨÍ7Ltð€ã,Í)÷dv¢”ö@UêbÅÉÆ%ÕÖ3`ãÝ[€Ü]C:‘N’®o§¹?ýŸ)îubLòLË+ïàüð€`—ËÊ öÜãäØÿFžNU´gS1¨Œm;”‡itf¬‹!îÕÑQ¹NÌ‚(šqe(¥¤jÃ.%ÚÄË“Âv]ñ"r³j›9éÉ/MÊÚòÁÊ S΃ÆnœŒèô²î0ɳî40§•|tÙ?“ÀÔÎos¶¥»ª ÜÔÂnzäß>ˆm½ìrÂbíÄ[«ÓjFèV#àS¨¾_ø#A“Âlh,J׈Ñè³oa+®Ò#¸ïC Ægº<,FûN&¸"áÂ.Àªv™¬‘«l&ýwaMè«mñÉÒ¡Ö \ÎÒ&ã÷À 7Ž{ øš#vx³%íD*–ˆ‘l›{~x…Ó?t¨±Ë^s"9”°†äÆv¯áLדiyLmW^=<˲­°)7ýrOvåÄîîÕŸÿ¹Ð§ÅBZT¢õEö,]­oÜúƒ|ƒÕËþ õ  L¥T4….éÆJüˆ¾)F¦†.“Yâï}%côù¢R½¦¤ÎláF0N™¼˜6d™Ð¥>ÚSÝwTîuñQ’É÷S?3&çP’€€µmT‘yeý¡EÍJ_Á›ðÔ㬬Bk”o„ î 5‚8,}†–ÆõxAÂaÁ ;æpbˆº.þo+c?©5(›ÁEr;Û$>rN/‡•Žxj•âãý°|[P{ýl nN¾Üг8­m?‰y#Ù¬WEʼ –]£â‡W v¢6 Õ:oQ´iZ…J¾&„ˆþÛY?بšoI;?çàÅÇ”ù’]åµý®ÆQÒw¬?}óC¼9…\&#´2Û&©àú óÕ K!'gr ØqR ÿ >‚éT fÞ[Âg½Ìâó2)Æ€R¥C_}òg—$ƒìÄe°qßè'Qˆ~åWÆ·¬»ÄokJzÒñI$3Èx»‘5¿ìUñ^]º]8Vdð@“V?æß( Ãÿ±7ÈEØ=/Éýãó»áô–dyÈ%GEÑçyOHõ¦Gݰñ›'w/WS0\ÿ »ÒåY݉ÉÈÞ…ˆ™[Ä–¶ÉPÃpTÓÖ½a'æ/­èí*áž(\¶¦…&á„Eµ>Ô"ø–¿p8ï@Å(¦b,°kYÜ ic0û@ݵ¢Î›oÙúñ¡È|Ýo* öò2Ÿ€YQËà9 m“SfA(&œÄâ{Aœûr(´×œ L<Íxg5N ­†,âˆÖ¾8jYç*Pª³Q±faŒª`ŸÀ°ÍDßþl[‡tŒ€š~‚SA^žù\À½9VÓM±—Ûkž2àã"”г¸±ñ]ĉ©ÉcÞOÀîÕz×âÕ똹›~$P¼3ðÈÙ"°ø ?—F¸Ó\„V¥£³rIœãé#É=!‹ÙþùIziZ-Èý‚¡™fn#D4ð<$ßVÂJÞÍjûãóõ ØâqîDŠǹL#°½±Å’ÀQ©Èç/ƒE~yCÅCm«˜–0]Ò´•Õ>ø¨V-K ÂIÓ™’•ïà.{\®CÀ,mà™ý<èêBV¿â~Ff› †èâÓf‰ÅçRÅxPù>蜘O»•ÉŒOú‡ð÷·ôèAŸîãÈké ò6tß«—˜¶`À±€'G»—Á&§Gsê=P˜‰Ðë:,¦Ž+–éÅmÜñ´Y ¥´µËÒ_»ºQ, ºâÒ”À ì Q½dåîhL)Zv:-òšVÛ²u’€€“"\¯aJßb+N¦\lû…SêÑÜ1GvI›L:ë‰]ìæNó7I7nä^šýè¼2fÌ_rré&Ô7–ûí÷òc6´¹£fæŒ4È盿À´ŽuíŽ0qžèlé0V÷6«qÙÀEID6üŠ®gŽkf¶{L:ªÃÌB¬ØEh7£uàýVR(%éFÈh,+(Í~S x¾~G«R²òy®ÇäIBT"~ž›¾êÓli]æ;xÆnŸ´x³šú|4BSÊý˜6Ç•lzÔ~ä?r)}eFÉD¼½«¥J=7{|ÿ™—[~…*˜Ô-W{0ðRIw6_ľ\¥:~gíÔ9ô‹i«Sƒ[!øª”]û0‹Ö¬Ô$=a,mX&½6¯\Qã~&8[šów¼_T.Ÿ‚‡Ê²Çòøà¿Ýib:ػ۴då#¶’$I$[3áE%“ܾj6ÿœb`aŒ'¾uÍ·PB>Ñv±L.×_W4öäøúª·£\py¶ó$µL4ªþ´ÃÎPIÏ^u0ä•<åÖ˜8|ï`ç²õŽBÙÅé°vê£à»J2 aÐÄôª5ë ð’ TͺpDbÖ°ÇHµœ ,[âPŠ·¡ûÁ&ŠgÕ¡µw®ês³,âvú²ÂÆžgsgC•D ³æ¾EÀïÈÀ 0¥íˆS•Š£ Ÿ•hv«ÏL'Ò!1Üé¢A»-& ±÷î—ü6Џ É‹ä2HM®GÎØ/”3ÿX¼”OäÒ`¯®v×® ö¥Yr®GÎ9KÑ!>ÐçÔÙœT<ÜsÈ’6Ït¯ÔC΃7;Áb?¨ÙÅæ1±s— C]æU«6=ˆ&mtáæWf<Äôê}zÙÞĦ½³©P"÷…À¬˜jéˆkVøÜõÀ¨¤»žŽq|ЭçÓ¹Tú¦ð :;àÝ…»®JŽÒÐóz꫽}­€?'®7ê=Àß*ªI>Åojõ0«áö'G=Ñ¡¸QÙ€Ó¬âðÙEV"'&š¿&³4½ê¦óÐÿ`òNc›•Œ±?¤‰Q6‘¨6VÆåÐÝŽm§¿r»¿¸ce´¥0èó)Æ+d€Z ¾šˆ€ð8ÿQæÛšZ#ªí-ËòhSS¸TPq’€€Üß°Ö¨Éb "ƒ ³t>óçÖè}ýnƒ˜ššw—À «µMîûáùÜÁedÑ\~aàÏŤ[Ã_v£Æ–˜À.™ù#Î þ<-SS¤%ñá:ЂZnQã¬Úêå¬_¶ˆg/´ƒ6>ÿ‹‰£Æ˜¢ùZ̛ܽ ;7v¸u³òzŸ”˜²gá3Õ0óŽ'§X«PÙ¶ ÓoßdpÚ>œüXÌ„ù*–~°óâ£ø/Lß³ŒþßÎ7±Á›¸¯hª(½5®˜$åRCÇœ™Îu=QÄÆ6P+døTï::-¶Ò`¡Ó |(—_ø58ÀF'öÿ­æh Ø„‰œ»=ᳫÌÖ¼ôÀDÁè!“.C N÷ùþÁ†ìŽâ¿î£§V”¢5X¶×?%^ÈÂã§ßI)FOéå Ë’}\ýøGÇ’se™ç¹µÐPÙÒ5#g=l]׺VB8²£¹L¦A·(¦˜ñÃwv_©ù’CÄ `Ê‘[„ä8'Y¦Îƒ¢h!Ÿ8~W‡]n/õ?ÒP˯®…ÆàôóUñqòŒ˜·%}c±ò1¡}od‡÷g?ËÚ†Ú„øLƒÚÜ#ž0TïVKûæ¿]Ë0Š—­¿«/˜RG³>•ùÍÓK\šÛ‹*à»å†ÆeM…Á%0¼ÿîtfǃõŠEýó¾IŠ÷€ rAÛÚéZ~9ü{Í*‘¾BzÕÌV¿“i}ôX~çÝœleŠ+‘ .¿Ý));]^t„cwl>’ŠÁ€²ªµïü®¬G†­Ïm3‰rwÛž9DÂíyj„-¹ë`ãØë Þ&¹|óÀEüéÜîÕ,¹ý·ösÁZ[Éiã#k6Q䮺~J¡ jîƒ iµhʨ`•Læ|Vï0û §èê”êŒq.šÈÅñ††]Ä=†™½›évª€Dt®í[!î$òv2 \5WEðˉ0°(“½ˆ6W¾MqÍ6údböÏ¿ÿø‰ÀêíýÑúL~Þèä=¼¬QŸ\K ,ÓÿçŒL0ªm!>0Lg™ó†®×–‰bÀ!eÛÙSy2ßHæ õ”~WPz½Y?þæ’B[¯¤YÂNH°3UËBñÇáê WŠ€ (có¿ »õÝ6ÿ—cu¼³\' t‚6Am’€€ûT”„u¹(.O<;¦O뢫íö†–…fÇÌAü}D'ä5Z‰¢pí:­5Ç Œp특í2Šãî6mR†Þai‹Ô¿œûQ´oi9I¢íh8Íœ\®Ú½sSÞGÖ„;ÁÉ»œíê@fàΪ„åè)c\˜”Ðä:—W"J<ñãm ë5~Ï;¯×挴fùÿÛ?ãö6 °{äQüT~ª2~eÆa`@AÕÕð{’êóû°ÚCˆ±É§žB|{"Øq¢úÉ3¯ˆtCÕ… ¼]G'v’ ·ÔP+ÇŸŽ“?–ÅÅ3[z‡²™õÁÎÁë‡L”‚t_ñz>ÒÑжàÍÊýQÔ³ê,"váç«4½îoÊã§U±ùÂl4qöYÇ€ýmôY.P?´E‹Ÿ£P÷æþäî Òöò®Œ0+G sš€”PÞÏAZ¡›7-‰íÙ;Š«˨¿„kgøK{c‡“9öØ/:ß8„Jyèé¥5g§ð࿬”3pÀ¯ù"Šå ¤–È—<ù †ÖÝ/åό´ÿÛtí䕹~7‚€Š\Øÿ¯h¶Íqж˜í HéÛ/_hd<ÿÔÞîöÆÄ8i_RÓ¼E¥y룱oùí©ø·È„tDpX½?…¢|ê¶r ÿ뢄NÈøÇÑ?Y˜­_”Fêør®p~^\´—éãÚ^Ê& ’é#R;”Yš:!?0k!óMpäºg(5\Úè]M._n¢‚}ã"‘]zÛƒRÀ„’Ð(™ zÖW08ÎôÍE—æÍpÐÝÏôÁ±™íK¨.×U«åwnZ£ü:9“„È(~óŒ¨]CRÕÀ* VŸô9ÝK!5ûó\–ŠØ;¼ö ìN¶ð®â¿âVÒ–v”.×–Ãþ#×¶Ú{Ž€¡páÇÚ¹¾Ì.ǽ¯>5vYòe“š=©±q wúñ£Üqoùý‘¦‰[‰#§k¢ÍYø]¿ ){ÑB¶J«Ô wvS X1{6ûÏyûØ“RyË|l›Qûº?†¢yq¶ÈfOÕvƒ‰ÅËV¹4¤7û¬É}­=.Xv§X˜"_¦:¨ðZfše w†5d¦y…9*°{(xðo kM=ªMé‰ççø"Ó´ XþÚ´šg\ð"°ŒQÒ’€€¶çÒH¯ÚíRB¨úžATâñD!!XŠQ²xP$äL%°ƒ&ZBöòîS:Uo#Ô«…•õçŽÑ5+Ù¢ƒB¶nTëÉÇûÌrg¹ŽSÎ ^^º‚PøA;ãÖ9AB’–âzwåú¡°lrÒ_j%/Ù·}øIpå8väw3 ^L§åå+TïÒû–%Lj옇F4sXÜ£z«ŽT߆é]ü€1)wòš·0/ "Ö×À çÆ‰s ÚÓ@t’ófþÅ™ÂRÃŽè»Ç¯3Y*/ÿÿSyf]o|7ÔÅF3³‰0ÙÆPžÖ§!#~B§ûJpü ¼§TíŠbÿTÐaP´_,«l¯þy½˜Ù_)›hûvõph½i¥f=ŠÖÀ•-ŒC~G]–.µr3L™æËßC×¾–æÎb+bµk XTlèøêðñbT­†R¥M;gDö ¬i*á‹ù0'­Qah”™¾“ÅÛQç$ÂŒÓÊF?¦ô¬ú½u:Ÿ†tÖ4ñÊñ-$¡ÿA|ª&7_¶Rý!IÄ©¤ª“tÉæ7„{- ìȹ@½Ý™ bÖ‰=PÐo¾P¦§à3¥#¬*Ú|–Ê ¨¶@Téœéñï(Óa•={ĸÉè¸ sM¹Š¸Í¨«ií}ÎOÏ0Ž…Jõ#á¦òßßÍ üºO$/;9i¡8>¯“”šl,†>ü‹ï3)C¯l,Á|©'dŽë-d¥ ¦Tés<)[åh9ßúUΈºå…$Á½6­Â|=ÐÓ³î¥,°‹wX½ cCÛÛ&(Ï“~­èlŒt(0Ùi‘=JöSÅ(øÚþVŸü“}2ßÂqðüjDöBòAwa–Hǀ˥Te øÌá뎊òrŠ=Ç{ìuŠà}³s?RG©0û¬‘å…HPï—åwX›ªÉh«¡F³0×z`d¢`Táéƒò&ð|²Ì>öúéC†Óš8 ̼K 59E¾´¹6;!Úzƒ)5Ó#ÍiñÖ W¾^øl6霋žÛ„Ö?ð›/°¦bžU±kÆ@2> g8T|IjðÇ8ó•¦FZ¹{ /±UÿŒ²ÃF‡eú_|8Uè[² bÒÑo(LÖ’²À<ŽüŸÐsPa˜lœÏOöúÔrõu%ˆÁÄ¡’€€±¡šÿ{fµP.&_4£6ЬÍg— >8™ÎñŒnŸÄ¬Y ³FÀì€%ã?buÝzÔˆ0Ìè—.^”ŠÌs”eÖÍ>/`zêkèû4¬†¨;¢=á| ©P°ELv¨ æ…±IŽS§RK—Þ±»ÙqÉ¥…pË/4…âþStD îc’¸ãÝb¡Mo/pÈ€(N@Ü?©í>¢c"7 ª4vÃ×1˜D(…ú”o¢’ÐDY´ÁêU\ôd_†÷²X¸­ûì:!ùŸ˜ãE¢6×1‹%ÿwFÆ®Î4÷÷x©-œ: rᆠ *ai§4o”)„5ÝŸ­Ó>ç¯œÑæ@$[ V±ÃŸ4Î}Í/#r¢D‚ì .–ØS%Jø6mÈF›¢DAщrÜ×È/¶û@¤!+¦Tpö/%RËÒpåÛYˆòήu ·žƒn ÒJb-J¬º4yH m×ÚÍè·jÏ‹ª¦#.2Ó3®Š­Àô}N¹¹n\¹ÈGê£Ñ<:³jºØ&áK&ùuÐçØ¬ ls}aöHSKÏàu×¹ã)áç‰E¢¼-ª~ÜWÕÜÊ#g‰¶„žT\µ7Ö¯=žxgehãI¯LË5ãã"ÎjÆ¿”àÒªë–5èÛGx>uQ~8à²È«¡_õ}5-»'Îuј¶0ÇOSð4çŽëOލ;ˆ–8g@í¥Î~rã•ýÓ.ÙSg6Cyìd–æª7Š*Ÿ‘g ÛÛ ò^w^gÝíÏ·| •‘³'˜f;ÏAh ´¶ç ¦ ¾¶•b×)ºÁf‚ò,_Ô˰îŠa_«±‘­â:ÿ& 1Lë‰ÎG™=üŽ;c0òPéø´¿Äþ8?¹¥äT!S‚ï¹ö3œV4PT„f7@ôœÒ.y+®ÏFòÂ|;Aßë! ˆY‰J6úNû࣒tàÏ()Á{Qá’€€ÜJ?ö6¥®À¦×`×B 3ø´’ lA•Ó·,ß–R¨©%²Ó>ìTÆ..Y®ã•ŒÛoþµ7A|8ßäTšô´£ey+PóÐŒÀcQ» ‰þT) ô`ázršH¿Í)À£:}?_%3iÙ¸ 5r’,âøª`)¯t3«,&¤£‹´»ClœÁ½N€¢ú_IïŠËÎO ¿ßºæ3"]¥Õ 2L7-vV,2Ðs8õžiÉS,zEK, çÖ”àQnØÓDxŠ f®Ü†™…ýß¶l‹¨«òóLŒr؃…Nùªô£í©f$WŒl¿Fõ2L‰žÏÆ}Ç1`Ü%€ 3î4ÔÐA}†›iø÷Ïä‘ÞIp¥eE.¬"ŽËnü°ÁçtæXmã‡òoéGNã‘q»!N݆as§,œ»ªYb½ n° “z¦E‘‚ ˜ëþDáFE™*\¯æ™ƒ&i Ç,Ò™ yÀêy1NDAŽ ãRáÕœ®œó½‚ÏÏ»o_À*Ô§lÞ”¨¾õún§M€ª1´×\_ˆ­£–6À¸îPÚmØùtY§ð–oð ãT?qŒÃ?ÀÙA,dz}ý ¼e†ë¢»Òj&šFó± OWU›X—º‘âCýx½€3†wØçBüx,rÓ‘br¾R‘åú5ì;§c¤Þå„­)ç¢Y Ûú‡íkþ§ðÒ÷x¾ëV4¦- fþ XéüvBpŒþ6èyö£ƒ"A§ÕÚ|·ÌE—‘^ÌAQAx†@gœ ¶ÚØ”LV­œ\{[;ŸHhzÔKÂÜâòÝ ‡Šã£e Q€ÊÉìåúèq×á’ßeéà{¡]¯ßßW»»x%æpeÜÿõ²uä,áˆ|dÔQy<7*ÎõÀ¬?ÕM†¬Ê›º‹÷iX¶ £Ýú8Áþà0­=¨E埖BGý³¡‹F¯|‹a<§}ï÷kÖcäL+j=†À×¶Ü_¬‰EUX°Ïöþ7a|Öˆ)€oR©55”¥(§š@q8»Ø|œé΀ŭ½1rÆ»%£Ö%’. ~ÚŒïÂŒûÀˆêíÊõ2c_aClð×H€‘Âx@â.­Œ·Ø iáô;ÇÖÂÂuºƒ®©½@0m2£:²*<§ÝÙ'2øP+÷Vú°Åú’€€ zÛDÖ¨Ÿ³ÅÕ£H¢væ«×$™ŸÕ;Ý ZPçÉ÷,é`7ÿ¯F¥KÓìš•dÞKäÀ=÷ø)èÈ„ ã ŸÃ 4'÷ÚÏŸ)Ѭœ.pÒÍŸ`׊ÐGåJcOþ±A9䟑réâІÚOL1Nç<–Ó” #©0ds8ç#†P˜"E¬: {ç~§ñL-gº—’d×JÃÃ$ÀGƒÍ”ÌQ5¥-Gc8y”-î‹ÁÝ´˜ny½¢ ÙõÓë§ÝV§Ÿ÷Ò7wš˜™dˆÖ¡ ¥×ZÖ XõmëD|»B¢©Ô_`øtþT¿>¢•,öýö¡=†4ëFߘžfÄýÐcÒe4Òä"ª8U€2Ý,ݬ+Þÿvx’ƒå’€)ÒÚ[vÒL)=KðHF_‹¯É¦ß´ÿ´  ¸PG3÷åGX`ƒ8côJL¸½l¼²Ý.)¶qÝN¹>-i(´ ñ0ŒâæãEÙ¡ãye+"ÁÁ3U ³¬ï”@òZƒÌ¥è·KÿJúUa\*t¤èXý€Õ—ø<¿9"2ÝXu¡ôÎ±Šª±>Ä- ,š,#pMm ½]oq¶¯ÀM=iN2ô}®XÐË.é¹áóþÅ«ùIPºi#U?x •d¯ç¿˜óyvr‘2´õØ ¨¸-š¾±}5 ÜËEúdÏc’†ùð¿ÐÏ2ùÄK=õõ £ƒSÕûÁõÓÎü^ß \ÁöWN¤¦­î=ÓZ ‚¸}&¸ N›&“ ë75ÂÍ™€†î{êãŸ7Ô´ÔÜÓRt×·ãù‰¬H(ã/È>™•§`ßô*1H,z±b¨i\“.úÂ4Y²Edoˆ"*Ĺ„Íý^¡sª‰s ùР”ÊÈFVgOü²‰8|tðØr‘¥ÁÉÑ}“‘ÛjH]U`ÈÚú® Î#û’€€Îô¬ßè_œî‹ÑÛ’+úuœ²?I~GŒ œÑ Gv`w\_\ƒ…ù:Ä“O^Ð^i“ÎcœôLÆØJ#û gÄö¨ÒÎÑZ¤‡¡ã2åæY^þÄí2ÖOÃԻ„&«ÖïHHlŸ@I%› ã‚uÏr§SçFG×’b"°õä(ü†'à¾j¥Cúùòz¦p>Ñäi«yGQñ:e(ja9Ü…Ó'(.K£¥¬Ú7¦{Zv‚vÛÒA ÂØÝ½t¯öACˆò¾²;ÛRz® fò}ǵFù‚ª¶I¹å8ãOM I¥q‡h uá—Ó‰3®¨_:OhÅÂÃÓlÎ'$ús^ðóýèÝITÚ¬ í~Œ`p벬–³˜s[›{xT4Ó"”½3{¦bð¡y‡6 œ¥ÀvÔLW}ø 8ñ†“U`øšCÉÏÅÔø¥ŒÛ%Èõ?&')u;>èxßå÷ù¹H\¬`ÜS_‡åk«`„ ÿvs¯S1u8E]ßëh}©ÒËãüìF°‰OŽØÀDúg²{_X©fRðN÷¡1ÄõƒGN]#Eè<¸=pËé´Ç<ŠûJÒó(] Â1‚él`¾¥äÁöÌ”ì Œñ²z‚äîÆ -ÔÊ€5‘Fº°Âv>tòÀ†ûú­'¿Eßq¡l/o©çòFEFð£‰Fsî&yç´Î‹³pØG½wþêrÜÌ> b‘›„Žß÷˜6êoíü›Jb”b¡Þ¾¹¾§Îö~€’ß(ƒ)†üð_í¡“^|ÿõ^à˜›{0'“xN%;tô]¶-"·Ìª×Øj;À|lÈKëœ: I—ÈuC#Z¹p懑Rú¹Œ„RHƒmO‘Ý^go UMÖU¨I…-€¹íO6ä?ç!ï­& {tbÍE„œ×¸ú‚CˆðÒáãY£;šºm}½ã[·P¥øsbr!RnÝüá’€€ëî¬û4-«w!Â"12Ͳ¸ðëܪämû¿Ù¹avFW!Y.ÇáïÉ}/ô7Œå÷Î X”«¢}ÀVa•:9™ëv”öU2oêÏ™gd¥ËÖ¯.Ûoó<:…£®3å‹0WLµBêsvϵѰ¹ Ëc«ÿ)Vu8,L½ 2«ÊAC£¨ÙєѱýCûË3EÏÇ.1Ðâf‘Ü€p½×˜M2÷Ý­[+êk:RrN²bŒÞM I_3â™…ÞTWP»Œ€XÖTéê…‹@W!ÎåÖ××#JŒóe™åoDÇ· +ž ½À)!f ºÄÁ~ÏŒ=íAÒáéèÜØ'7Vf_ýÖô²ïŠÖ>b}?uz•Ò)Ô*¬H€ò¬êcPÛî¤éS‘™„‘Có-m‚Ö9÷zt­â³A(æÝe7uƒ"cÐf»¯Ã:Ôì$rZºÇø%Èœ×aˆö¾§D…IöUÂ)§V?¥'Ë<ÜË·W=×÷u £î"Ždï9ºê}/M·Ûw¿ü‚iÆoU#xªe;f8<«¹l?“ 7& ´„j“;jÈrùk·o°é‹\z<*CŽõôK¾”îHªîÉrx¹iž$EÜY›%Æì<ˆÞxR.õIíÿ"¹£¶±eu¸*Œ®É¿¢‚5†²›GMe}ªâ±éø÷ÆxVô;:âX|£±Ì·™ËZoaÚž¢_ÿïrŽÒ¥t/¨¦¨óÏ TÚ×I(aÄdÿ©s$;–!êÈù ®ú–þøø¸^ÀÝžC.ø'LK]áõ²£^w0&Ö|.íŠ~cFl÷ùö:PØmƒûé­a4¥, Ç^dt»‹1VÖ/ý¸Áy‡œD"qE#×»G%ñ¥LòýRh)Ȱ6nC‹Ns¿~ÀY£MÝ¥S4Xz èoA:Ž$R8ë’€€ÐÄÂ*0ä–7¾øØžˆ†Ë>è„(ì qÍcž°S-Y€rAf)î»'5^b$@ÚN¿ð­âйa‡m ×ZX…̉¿åþþ›"¨åc¶Ñß݆'H¿UwáY©›×3¹YÕWÇu˜z¼sß2Ù/tj”gFý™%ÐH"è$1RyWÿâMÝŠçÒf?{ZWr!5àñƒyAó¹D`4DF·Þ†/¦Qü )"lú’ì€õüŽaÌ¢æ†|ª{Üv?÷Bàf^èÆì™A E–  ‡>±‡NÏ¿OÕÏÕ%¾ ½4Iæ&`y'ÖuÑj(ÞÃóšQZY³D‡ÜûõSþ Ø£xK÷÷kzcX)^Ø—8ÌýÃ_tÃ4ó$â$~ðS_,ùÒ²BOÚÔrSx¾óüm›Ñb阡KJX=ÁP\sÅrm±ZëõòÖø2»øÉÙKÐ>„Uº[“Á vËÚïKhÅŒ­‘;V¬×‡ª²@˜ÄÃ4>}1wÑ,Içlžgê° IÓÀ¤SKaZ°$ó££þndÂÝê=Ó¾h8Y„{ÒLú¨„g¡„?%g»CQ®­¡Õµ8íB%ÝÜmIk9ŽéÚìXõ»¡Í&͵PT߆ €þ øè’‹ÈºÍïOؘ¬E–¶€ä¸M¶!ÕnfUwÚÒM—Î>0.0‘ÑðÔBaÉ5/'¾®béiç›Áªàkùౄ´’g’¤æÉœç©ñÄ„³‰#vjr©ƒ0̦¥$Á?ª G;`#Ãéiˆ1üZQST0Ý®fïáû1rG[ï_®á%dÞiSÁxRý)žÜ.‰q@¦sÏ› ÝÉ,©7wæcÛnˆ-l<=|ĺ“°€Áº‚½nªÜ›]@âfÐÝ9åï6C•>!¤ë%™ïpWi VB¬®.+ñ ôM¢’€€¿ÌJ±%‘T§ì gI>ãÿJ3²þUYa=¡1ìºü±MØ9ÊGøKóbj¾×;;Eq4Z´b{rßÖÜÞ „/ Ã>”Š&¼ÛSZ‡»'F‡;+SxމÍtŸðÙàG3'–ýà´Ñr.Âd9bÓ ´ÿ<ú´’µÅ¡É$â È~ìøýl †+˜qDì«,Š«Qj6†AôsÌ‘Oe÷“í¶¬A_ÎÝaþ{$}z; ‰ë¦¼ÏÈÁ-;m‰öÅÉ"ƒ÷¦Œš÷‰JàçNÖ‡åŠu³}G?d}ZuÖ¥ æH7JÒå¡IÌœ^œº’JßuÓÜ£z¯#øíE¨ˆ‡(¶V—ö7ãdçnG­V¶ó‰*1¥E'›It!•`¸Ý„Ù9 ¾ÁolÙ¥ L£F$$¨Pî½û½¹Ë˜U—çG0aïªcöûÞv€£eÁ\Zí'G‹zŒÈty𣱗1qL™ÖË“ú fK…Aº¶ç9&9-ȲîDúåvêa`r”UÛ^8|•söåDFc¼ÎÜ.¹0¯ šg¥·P©'™ æ>vûß&ÕîQË?>.‘˜¶A‘b©×ÒXî„e³+iÖå§‘$tÅ¿ÚÆq¯õË{8{põ[ Î^0) Ý©iÆ3%à~ê" ¬Z$¾>øçc2ÑàäŠ1+GüÄì ñætâïÀà^Ô`·uJ(}7ï5î©0Ѝâñ¨Óbž¬“ñ8Z‡Ù–c>ëy'ªšø‚7ô3|UŽ¿VâÄ|Úï¤ò8E{sÓÜ–‚Åóýw€Ïl—m3^U§Ñ¤ãH$ì.`C pTÎ Ð}|ŸÌ¥ o>&2>°y“p(t3H5¹_ŠÕ]3“í6£©’Þ¶‚W¾¤Ëaþ\t$f­«JöÝ_°;PÓµå8ôÚ¼MÃ)\yvG3êúþÎì)¿9¾|k¦BMâx»—õ„tì ò1Ç,÷>§Îh?# êtQ„ϫņtxX¥ rÿØt¤[È%×üüY# ™ù ˜ ó×ø_Y…ŸÎmQ>z+Nýgær9ýÔï ÷Êç±cÇŸ›ÝâöKófÝŸöû˜Y{³v”bå{EÉ“r"Ly‘Vú̧¥r@é;ÛèÆd|÷QZ-Yˆ²Ê+ ómÖ“óÆœX ßÎR é¤ó¥îft-¾Þ^0O3R“䦳f+mêK~Mÿÿ‰TøUÙ¤½¨°#çÑTªó!À¹V’€€¢º_LGç#oÍa~S*±G‚¬´P'AÍ8?Z±“÷ø¦íKÚ¯ª$^ff(÷u®Ž¢Ì•¢ŽEãúR‘Zâ=1j 9a$JþH<ÌçÜõÜüeSÚzÛ15ß&Ô<EaáÄ´n¨ Ü#7;Vl(_E^´…¤ Û𤋮¸TkÙý¾§âqLJ,»y´, àaîä¯`ÑOL¹~–-#„|VpËÝŽâÞ|O¬b;W¢FþÈIå•ëÿ·_Òï6ÑW·‰TÔôƒ.qG&~9Ó¿}“»·cW‰ŠœD¤}5CpúÄß¹É-]ºÕžO7ddä€7ÐПþPræ}ä ¶Ákõž¸ÒÎ4an<´ÆA‰H½ƒÐ¿Ô9›•Õ¢m¸ClE†·²­3 koî ó*$Ÿ)šðÎy“T¬jŒôo  ù a7H융dXÀˆÏÁÛYþù¦5>NÉ*[~aÌ+Ë*DÊ=Nß‹b‹9~XIIÚL¼"Æ ü>¥õÀ¹×\ÎW‹`’Áæ¯gHäƒ67iÆE1!%oë¬#ãºÑ2HL9\ G™<–q_,” 1Ò¿š)'Ç ´Û˃=C²nH(ÍØàv©¶ñ¸Ï´¢~¤®[(n¥‘0WuãÂ5›³9Ursõ‡—(Þ£ÉÝ.ä60T958=Oî>¹Ói Ù1­'wBiåƒ7àÛb&ù“"¡ÅqK ¥Ë1¿éÄžYÛÉÂM4‰Å«/è·c,êC@—åÞl­½ç¶š}ÁÁ å/!¾é2Í/ÖäŽy@3"í5Ø“ìhc Y¹¶¤w¡ú òßo½0aô7½åFͺ…Â?g_`ät$4LLFÐrÚ#E±q¢ÖïÊß €§=DxWÆŠIL5tÎ ÙÛöêÏ»6Å ¶¥‰Ã"&ìTOÁFðdAµâ)_ ä [E=;FDGvPOà§åÀÄ3èî–²½‰üeÆ¿Åüç+âÓùV½D¢‹>–­M°B,a’s“ ËAYzHu[”¯J7 Ea‡ÀæÌvø$ö.¡Î'à’€€ß†OèÅ!/s‚—¹™"_)¥vKK¯òÕmXæ!òâ{'²§Gù/„~éú ì~YŠà¤´ë#Iw!ðÒþôÀB³S裓ô‡¡oJŒï k‹»Ï0~BpˆŸ.×¾âöЉŽÕÌΆ©iWv ¬Òõšá¥¨C$Êíù&mþpÄ÷·a4[ñ¾È·T÷VˆE^k?*åõW9cµ™ßl(í]€6,R-Z¹~æõ›øPÞê~¢?#@¤ª|ÿï]gggV\?ËâFüÕ­'Þ c‘ÎÓޯǽå^_»a“ŽA¦Ÿæ°9`”„n™ñ&fb4.cd׈™Kù–⫼«GY3d:þ¯ÕW£J¾f¾3¼ÿ@2†´šê+zrH&¶ôñüef¾ ZÕÃ.ëé¶vÖo Ö¢Ô¡lk€b+sD¹—ukaàiàùYé¶ÿ ú$r“Õ~cˆ­wf¶Sü¼jòøýjØæãôƶ|L‘’Ä_:ÑÍð‘¶ÒÝF hm%.û¹N7 7ŒnÙâ)ö;*–üKoä cÞnE¨g˜hóK_4òä¾z%µ•í4ÓAžQ·®Ù“™EG'ÙÝø Ñfd«è6X¸nÛa ‹ºäÚÑz‹Éø”êsp©bÖit°Ý÷w("ÜÒA¼W‰*È]|ßñÄmRን#æp#m¢hgÀC/‡Hh%©„k“ÆZ‡h²Ã\5˰çöü›‹Á„\˜ô¤Óåó$ÃÇZîbÆ¡`¨Òkl¤Y3ï8銩ÀÝ2m¾7ήÆÞRI­ÈHÞ\ÙÙ¸JÄ(¢Â.ó&Ç›¬I¡ÿù³Œâjûì®õAƒ ØcÊf¬ <ýu¢Ž(M©NÂQ’©UP\æâ%Ât02*eÙŸ53žÎ‘ê²Iê/·EÁ.r ÆŸ¡µÔ„P <û¯Ökòî2Æó µ_¦ÍÚaØllójÓëRáç.»¾æãS6È59N½¼JžDF—nê‹ó%GE›¥¨¨É<î?ýÈé|ïa ظë-ã?w;¤e\“çG†z”„)l&77]u´ž¡ÐCµ¡aŠ¿”ß(MíúýI—ê‰m]N‰ÜhðPvÓ啕ânJ¶“~ò°B/ÆPOŸÌóÕBDøbZúãÜìíðIÍè>VžßR;’€€½.ï“Z'ñp‚î´îM‘jƒw:©ý¸gKçE­Xýºœ²QŒ þ4v"_B×oúPEªË!„5ÄlQZ¼ñqjØh݇>õŒtâ´ þkCOI p@ffj¦9Ñ—âÅQ2¸ýe(ÁDÄqĬ¿´}aug¸t“€Æˆ¨pîøž2\Úþ kçmg1î¦}âiټȂ²Nh°Tf“´«6PcLg•|ê´€>sCèØi­~Œì6L¬·¼¯OK§ÒX6RS:ÙÙ¤›bÍú×'W»ÕŸ 6¶Ðĉ#yñ8há†áQByî+ŸLt-§DøÇ]X5²“j­¶P¶¶-纩l1Ç’ ר³j‡ûƒ2&;·ú¤fLƒTqŽ«tN€ŠðÂí1^@ôêGbÚá¬`‘ÇÈŒ—‰.dÆ„€ªKýBòªYô\è.¬%%À‹`UÞ¤r±ñ“YÚµBÆd(Ö%|Œw»•yäÓ˜c1KDš¤¬Ë­h?+§9èÔ­#V ¿ (Ú¶ˆ¬ÊNìý¤qGäϬÒÃíùñê EuùPhõ1±Y™ãìçK<¤ьŽ>áÏæ„ìˆfµ¸ùÍm©;ÜœyƒÖC.{:¢E‡²¹ú»¦ðÿl¶ü%JÕ 6=…/„žœÕéüQI(†êXý)w¿²Š/^KÞ4ÑÙÛ½ã$}’@àrˆ4â#;uX ±ôß+Bp+»Ý$–Þ°§@õ'¨û/qºÆjLµsäFªìßë½ÜfUsÚ„*ÜÞÉÆÑéÇ%Ške±e)#I¾(²ÝêÛ~åôÞ ¡ûKÎúêG¼·5XAØ}T¢Ïr¾ ^Ÿ-ó5c ¬7£Ô`¥©Ž·i!¬ÂgžYYˆWþK×óÅ$és¡Å$ÿžëu£Ó¯Þ’>KÙf¾¸•ݣà rʹs¿òÜ“ÛRiÛY¶³M&{Ú€|ëŽèìf®p>e—dš†;sg¡ñAHYS³¹ßÛPTÔÙLzÅP -A¹½ £fJôï›éº:T¥ †©}[ø£ öC. ˆÜz”þ;Nx†îÙñWÚ çí÷œª6<õ¯Ã>& ö&S8$Ê+!oôÉ=ÍÂ7jw*|I··Âá J¾ÒæþÕ&’€€·4C_Y@q c>òe7±tö6üÀøu×Ô5U¸vÁ¸ßTî«ä¬[l‘¥@¤:h¾¿247¾ƒ”¸jÞ牃F§PQ8}ƒ4á5ºÈ¡ ¬Öœ-Ýò/:Pþf^r€ªùÝñbCoPñÞ—è—Âø±\Ÿ¸@¢ï# ŠÇi`w›’~þ~-gGPÂH¡›uÙÝL‘i|~Cv™ŸÂÀ‰ªµRåÃÜÑ¥iÖ1¨žÎØÁH2¢·& 6‹U¯ÅIiùp3ÒÀòýu¡/KÓØ•°\¯ ¼‰¥ãã wÕ›ÛïA%¡Ú Ÿ”ÿøÓþ·vW¯/Âê·=¾Ö…G||¾Ï Ü¶ºáŽÕQ/×| çyy®prFlõ}¼ºB–…mqø&Îöö,˜Ñï.û®çô{pÓ%1g•ÅŽrW­”4¤²$ÌCžã@M é òÈé-5'~LkŒ žÆOÜÚËVØmĽÚÜðìþΜ¡2û]MDÌù-‘HU#I ŠQö`šš£ hrQƒÆX5ª¿·Ì õ°AcƒO M²¾\>¯£òñfÒFoUåÝS6Ë»\ªy©OØ%Åçÿ7äúœÑ<{r'ÏevÆIŠððø¬ˆÎ€Î™yÿœpè?9¥£¹iryñ2ŒyKHJHrà¡?GÏQïEP¶íº]hÔóœŸæÈ·Y+vµÁ©ƒqøZz‡Þ CÌù8ÂÇ?oåÁ¦®‚{+± ¤„ô¢»0s ÞfÌÚTÅc“³¡ÙM™¹{®°ä^D¸­´CôéŽÆwÄð¬:0¦ZÜ“Âr•ÙÖѯØç“ 6Dl½ À¥Ì?]Ñu«—Ï)õ!\Æ›ÃSZ•YæêÌûWt©@ÊFqÿú}Ѭà¶8œü,Y¥Â‹Í[—ž)óå…Œ?eÄ—ŠÔ¤( -w‚ÕdX²‡6þÍÉy’vÑ®ÀðËs n£(–ÎõN<ÓI(õA¯“‘!Þ#ª†‡B©¾‰¶¶œUt­5fA±yIüJš˜iJW/3//''gvhãâþU™vš=QS‹•Ÿ—¬U§¸2ø?çøœ$è$*àùê'þ>`çzý q>jˆÙGËóþE‚–’ŽÛP¹â“©`íøDŠùO,êG’€€š<`Ðô#òµôYÄΈÃe»õ:PØðˆag²ÿb¤ ¢ Yå*V–½ÂasÛ0?: Oæô¯îßDã““—Uû·o+`ohVwŠløù’riRoÏÝhÈ|®Ä÷´_ø(ô÷_!Ï—ù•Núüý¼åEYR뙃;;\ÙW\F}%ÅVà,3jH7ª§Õ´ùù[ƒ†ÁKçÄЬ!¨ÞÒ¢¡cÓ>»0§Ü“ÁÂbª•9òTï²õV‘š´ÈžÃù¡ePyªŒ ümN]œþž*‚rZ7t·r…)jðÃ1:¼4 Ê4siNü+uiq1)dš{øFÃ466i}…rÄ·ë–Kä•ÑÁ7™ßˆÈõD ùD:K{›wzfüpɳ=›‚ܠĸ§ÕRVåH—Ñ…¡†çQ:,TsJWØpñ®\«ðßäüÎ5ÉÚd7ÅÔQœÈ(F8$ï@„+üX%g>“*¬ŸZàQ˜øbËEå³m¾Îõ˜½Ñ’‹Mé§8÷‘Û‰5{,[ÐLŸõI¸\ÏrÔ:¡ºÆ$…ÇHdÌvY‰vÎüªÆ ôÎpF“Ÿw‘ Ü[¶ÒDfxMæ‰Û™Øö<÷ùJ¿ñ6HQä…²7 §ãuS-oMW›|x–´K?m ÙÜ!Âóâ×»ÙùÁÍ#Ò< Šéã>Íúi©"&t¥«RÚM›™j¥Œ¶›à—´‰ˆ#æÐ°–‘†WRO׸¦$T¢¿, ±ÀŸäú“šÎØ^± /¾èJØLÆ<äØÿRcž Z’å¶]Ýå?QA­SŒQGÝ‘4ØÛFe°¼ÿ²m˜ÙR@Lk¡ÀyWÆ9H ZàU=[ís4~Àƒÿií‰" ^E¸UÏÐdóÖá,=m¹„Ô_!F¨n+ÿÑp(%påL·Ä·¾±ìY©‡Ìr¼èÚ2«á̇˜ÿ¨øŒ¢¯8Þhª»ˆ^i•B—ËjÛ:z³D<?#8.pi„>OÃfÛ wãwˆ¶{ê7Jù²SR¤”‘€@t¯U$'0‡–ÌçÑ@wéy*?·{ß# ÷õ†Ê *é«ò®ý¸è5ÇÈf× œgš^4Í'Ô¼ÎABç#,fùÿŽ‚æZà`’ ÿjZ% >¨Ã¥=RÔ˜«_åçX8¬wMf7°rÇÖæÙÐCØßZLÏ\¯÷<7IÛ¥#ª×]F}5ŠÝ¥÷€¦GÕÖê6™rä ¹˱ 5-Ž$ZsÄùˆt˧üþ"gMƇéÙ'•/œÕ yBGæ×á>ôŠà{aZp`+â a2ºÝs Ê;ŒŠ¸8Ï}·Ï ÿ„êÒj7S _ÖavqÌÝÚÄ–N?$LH)/ˉᖡyí2Ñ«éÖÈèý1ÁËê¢.ïëØL©d·§xÀFDÏÖ+œ»þvã!ú{d`¶ê·ÑI6(þÂØTou‰wgwê]CTY­®@è«A1*^”¸#æYõÆmoÇ-ß¾ä¤âÙh¶ª*…æÃ™jp=ÙÎÔ@ºJqõr_ü±“7UîÝÂpm¼¯^¼‹)Jƒb-ä Ð 9„1 –1™n¥–8 AÚM¨ôгã±!ý[IJ¬º‹ è.ù²5`m¹ŒU«''ùïZºFæÛàxSïþÇ)/Ù¤ï^Þ;UÔïÖßuïÙw °¿¦ —æIH0nÀîòb¥Ù£™ºêH !õ»š ]|„¤k\ò ’£×•$±Orb^(k¨öá¸oî)§Ø1`$±È\3$.]žp²Pºî„xÝçåOÞ½i'ÒkÎÜtH–?“fY’ŠDy,Ü?`ëà›€Ÿ×NÅà˜¼z&©Ý%„—feŒwìÏ ò;­/Óèmc¶Q1N˜}sÇÒÕð¸¡ñŠÌZfñÕ? jãXÙ³ÈïR6SÑׂŒeÇÓUÄݶp~üîèñra1F3˜{˜òôbËBG˜üµhýìãþ2'3Å•‡[dp+?-‘øJ|)A²î”»rÆÒùC«§¹ÄšègD{È[TQ÷npè¤{å|k‰Ü€b]¥#¿¸û|ø×p÷†¿AÐîJÄ/d»1"þxjˆ’€€Å‡ïð A¤7Xb™ûßI¢Ÿé ®b¹ZÃÞª¤¿è¯qÍæ”–(µÄFåEp·{®÷òD4s-×¶].7vÿÓ OÛeÕ)ß'÷¨ü`9‰kÖøNª§dëUG|x+d] ‰H(ªNþ”×F8ê¸_‹?KHÞ€^îà xA>'c,­°9R# HT[…5ë©é\üá$¬›Lcál«¦Q±ký_Yâ.Iÿ›”+)ø8U g6b£ç•b 2í]$Ô‰|Ì õk¶€KOðÉØ}[Vµ™éypÞ&Þ7ðo{ëƒ(å#ö÷ã˯}ŠúJ>𸱠Ìé&¡ÒçÁ);÷f/ÓæܾtØ/qõ‹"!Ø|i%ˆÕQ†€ç‡Ïqd§ê¿ÌoX9¹³¯…óKJ˜\ë±î\…ão͹40v¸ÁLe Ò(x˜¤žÏî:ÃÊ@ŒºàÍ÷²Où¹ö(/3³ªØS­éØ?ˆEd@V’~;PIž›òCÐ{U 5,eÓ‘ñ“QÛá¼" OåzËN”=~¯Ø^"ˆ˜à¨‚äÍäé³<‹)„l©(`&|ÿ¶"†øšªÁ”Áš,Ð{Š¢^O[_Ä5œ\/¨sƒês7+H—­Â@p)›¬Ø]¥Í”lÐÝ9I’”eMrT*(e^rba25ëçËG¬nøR•œWÈ‘+S½( J%ŠßµòNе^r¤F¦ È(›]ÿ¯Þ‚³Nƒ§^€ôÀŽCí’«šÖQqøÂ« œ‰zª»uÒæ”E€$³Þ¼GäÑÀß•0<éÔL ÅUœuµ—Æ^Eç®ðóÙëj“a¹ø­¯˜««Üºf^õ7æzúñ¢;„Ú Snúj–zžs° °õ|ò¥Sû‚MðãJ“)¡nwe¿\œ=R< "†ñÈ œ˜Yʋֻ‡_pªsÆþ3p˜š3{U½d†6#î¶â3jEtÓ Ÿ8Íâf-û©tphëásPPbGÂç„“Hé$qf3$ÁÉád^Y#T»ë…y®ZíêÇÂõNí@TßÔû$,—€µù=ñ40p/±öÞw~W„n7¿Ë0¯7Ñro$ç0H©. –ûPÍì÷¢êJ›'šy¨0¼‚DõÄ#? H(Óv@ëeLM¹J@[Ñj—Ã`.Ÿd¨žæ ‹ÁdÒR¯É4¸°…µ¶XvÑ7‡xÑö5)CXÆáA /.åÀm¥Ö×óQ¾Ëf)¯ö²e•+à\©Kv ÖVò=QùGEŠÌ ¯sÙ#â$«JéBJ¦\¯ÃiÕ©½“4[©LV¢~â¯9¡]Ê_{ùåŸ)…ýäç(½ûcuÙB/ óJX_½©|þ~ðïÚxÃyTOa-ÞWA? R¯¿| 20’2¶9ÅDPQê€ýÇè5õ_ l¼†ù©×é iÈòdzòìú×ôA¶cÆ€ê7ÀæCU‰„“/ëaÆ+)GÿuÛ(ø0B4bÝ×ç9°#ŒÁ a„¶ßöÞ”°WRDZZMG¹Pœ([P~QîßÕï?8ó•œÌmîZ3ÌdÎÞ¿qjξ¡Àádcëzž÷YS1á]ÜTw¢ôªÒØìrb?îVNX!4{M}>@ëÈ ‘™1Q.s´#+&¥kÀU8èh1¹¯_]ë#F (5%€ul!Ú'„i¡¹M9ïô ª¦Š9¬2°Ár]EÉ„áXÒ ¾ò¦åö¥ê\àu’!Ýü?¦(.¤ `{û¡(ãÜ…ƒÈæ:7·£ö—Ð0R‡šÞI&–ƒˆqÆÍcT‹äÓ£"_û†ÀC‚³‡Üòày]Â"䨲üæpÞú°UlÉø>E+¹Ï¥)t͸Iq£×aþ\Þé^åÃ"§Ñ>i=²ÞªÔ Ï\æyÀ뀥[çÏñ–ÓÉIëm!«p¸µþY›M„дþ^ÔÍYmËY?4‚s0^µÄq¤s5õ¥cw(™cg”Ð ÀUÀbZõ»2ƒV ïè†s†—¡Ñ9×(‘Ú~µo.„Kñ̆”2øÕéAÁî{Ÿä‰J‰Ð½>g.‚Mó-¹†9P [#‚\N èêbù„‹6c±ŒÎoa»xeÌÞùOÚw0gƒ©SŠ,ŒÒm”H³ÇÂ^éºÉYˆ—\ªíYWf¿¤à:Oz6ñǺ`$Z7ŸÓÞ§&ÓÊé›0C€g<5Ⱥ‘jÊ ©&Ð׎†nÿÄÆ™››ÌÃñ½R”ÇX9,M*leˆ;yo,¿àЫ)[úÑifОÁ^eš©=qzÐùa(Ó£Cß<—ðª¿CfÒºˆ²Ýô-¤$åêTk{rÙŸn{Vü˜~¤[’ÝÖUÞªM,‹. ¡úýgx*“ö6Òß—ï–˜!ª;‰qÌÓvŒÞ«û;ØÁØ­~iÛj`©;ú¸ÜHŽ6ÌUÜÜ65 ¬Þñ«p˜}½¨©±úlnÑ;v‘ ãKlq«õx®îk~Á«Âm·þˆ,æ®l| -\ÿªŠ’€€ßðÄl[çCÈHqó¤­VnõWŒO« ÐSƒ¿ÞˆfgûvAÀR`Ì|"Žn5<ÿ·©”Øþhaã£àCŠ»dµ*/"—µ¼N<ÀZhÀ{Ûù¶c×±£Y0ÍpÏLôûbýxòâê £ûO­'tõdú¨þô…à”9ú"Ï£7AHã58~eÝp”6*¹ºvc9ð×}Jmò³ŠsÚît9. rº(FŒ øÒè³<Ä«ˆ*l45Ñ Ô^ÀIX/Ð*ÉJøP[|§"{Ë^ Õlº8‚>+Ù^rÄ”«ÒÒ %±lèýõvÓ>êzÝ‚zÑ ÊÆTÎŒh¡s ªÏ…^}"ѳÔUÚ,Eºm-Rü¾u›AÖIuéaÌšWIõ£Ñ ü‚ùš[x`õÐÜÊm•vlCå”ZF–¾Ï«L»Ï®^JxBÀE%ÉTQ¸œ^™ðë÷åArŸÓ†e?Âeƒf„ŠÌgñš×ªˆ· Í•>V¥‡]Õ¦‡¸;@mûÖÏê֋ΟœF®RévV³°×uø®ÖpŸÇj¸`>ÀÇIĉ³¯¸R•‹AEÙý¥/ÜLFQ Y`jžøÔc˜“ ¾DãWtšr¯P¤Ý`‡SeC{£ÛßEÓ.¡Ú³(¨ ¤L$¬W­üaÛ±õhq³µYlu¯-ýƒ!Cô…× þ³÷Zb‹jŽÃ¯ˆV˜¢€õ¥‚±åLºÚ×L¾…èT1,’€O{R·ÕÄèERK á%ia\_«û®{7Ç+,b˜Ž‰\”p- öÞв ܧߖ ½º÷ylYAê1ÞjìÞ¤&æ/é› —ÌèÀ‘, Ù½·pµÏÀ¸# ]ì í蘇­Ä%$ÏŽr½üÌêÓ>›wªÃ0‹±¹w{ÍsÓñð-‰U<,/'áMâ¼VjÞ‡^ÝI»°?Õó«Yc\t±8Ÿ¸Ee×ÉJ“BIF,êkž9;Y2Ιh uIˆ¤l‹×-ÑOTþâã²ecc°ž7C§´ø>aÖw+<ÌœÀDG•>ˆC"Wƒ"YRP “ÔgÓÝÀ¹öt™ö?vŒþFÁ>ü¦«LÛÓÕ¿eJt€–FÞœ„‘°+cÚíöê/õÄ ÖN¨€ÅúÿÊÜ9ºÊ2©ý¬E-(iéð0NVb:¾{lgØaBù¥yêZÜ5¸¶'SÚЄT‘Á¨/Æ2Ó”ÖÔ×ÉŠŸ·LR¤f˜ ãO!裭Ô8­C@尿BǃFw%›pW>Ä¢ &k{¦¹QÊy#[;ÿ¼Û²¤§ÕDÊÈ"« ‹ËAp°¨–§™øºòÓ#„Æ–ú\y.íÅ=ÄqTÜlwñåÕ‹Öx©üïMãy·æ7üQÈÁŸ]Pvìï·ºZ•޼U~ªVNíÝ2µÔ€Ù2¡J!D­ç†ŽME(3Þ…oÓüÄöH¶XÜ·ëqºe2SçyøŠ".i¿Ê-% ó\¶ùDÑÔ°.1L(1júÃ&ƒ%€f!WÙ—ßH º¿¶ÐV¹>ŪnOõ'øBJ¢´M)áĵ2•™Cøâk#¡”û…0vU¢x€gÛQ­Êº¼&wj€âG¸ùÈ¿—!]Ý‘sÄÚˆ/B諭mãp„=}ú*¿ê ç ¦;N$‘Œ¥Ñò †“Ä?Oá134m}îiÓtP>7Þç´š™¿7$žËßÏ¢Îêíý=k…%fKò2ê••MÁÂ/ž°%) 8ì×åkšYßù”ÎÌÖõ.tMN\‘M—q}Ћ7Ç8­•E8Þç‰ìjŸ¨SÊJ]ôB!_YüY€Åd¶G#‘Œ N^éG,V¯-ÒÖªÙ»Q諼> 0Í,¶I#$ŸUÝ:«9PÙL¦D ¶k@€r:[Üê$49l>Ù¥Â:NÆ›…ƒuhù1T¦ÝÙÕÐõË쀈ïò”FXˆÅµš¹ú~…k€.°üŒóôÁSYóŸîÜ,1dÆÅ-…Î+m€ÅßäXkjKiýc1,‚‹ávvÁp-*à»Ô…7RÀ Äðò°zþ‘nªuš›àí7m”Š#Më3“åÄ­Ä\ª’€€Ê;·¤ì÷¦Úð¬ ü5\6$SFÅìÕÁ‡aÏOúqÏÛ4dƒð’h;¬~p³+SŽÏrŸjspû< ‚Ô ¬ä׿®Üm¦›ƒciHS°/%¨€]ç‰9j€u fÖëI›ïº¦Á"k§T£fÍg”%§J Ñ@éq Q°ÞÃÿ°ù£Û.ýinÖm!°\­ÁYòã7 ¥qfÇÈÆ Ó¿UIY²5¯«I!}Î땬Rïzj¹?žA‹¼”y6_]D Š&bz¤òüܪt¯úÐY+>–¶:™@öçðùŠàz$Ö}Y/Œ UHæ1Ì\VШ>³Ÿðá#”`>þ‹á»–0Pó£ MŸœSm$x´Öú¼|6Ϋ²”„üý®¿˜¯/JèËP *[ëÉS²ùWÔ²Œ€3Àw²‰O«e(2>ºÆSc8r¡Þ{¸¦­¬z³RîÓV}QÞ-:í.»xïGtõ?eƒ¶{-ͪráµ!azÓÛл.ûuñWÎ÷©½£ŸîþX„š€ÆƒäbõaäÞ ÃñŽFODUG–Miqx>E,ì®–òê:[Ç ?’TH+ÈSÿøHo³Üekĸ#Uß Aq•QUÙ5ydxй—Y&Ãîl“kc¸“qs—t·}Щ¢€ ¼^ž ÎPüØLCÏ©·tæÉäŽ0Å4¾BueoÂ'6ìÛ^âäa7â ye 51êÐiÕR:9Ømô Wü-sYï(ØL×*Ô29Xä»#Pò¤±y›râ@:ÀIó£»fIÅ ËCÙ$*Qûÿä7}iÅ b £TÎòmùß¹kï`)Ò¨ýJJB¨§óá I&S_ÃÝÍmØ›ò2ˆÚ_A3t¤ê³ ý¼ª›ËN QøQµŸE‹a©ÅhïÇ¾ç½ \1|ÒJÿ?ø1 ìþ’þàw2NÆBë:⥮½^®Æ"Ž’& ‚S&QGhMvfrù+¶LDPðpf8ÊéÝ_MØÀ,ªi×± ¯ù<²IKN ác¸¯•OY&9m¢ëD¡øž1©Bojå¿Ü>½É461X&ó Ÿ”\–Œ\¯Ø9Í7–û½éšÖD$¡âãÕÕeW=«§‰Ïý’€€ªH¼ÛU6U¤Qñ“Ï:-$a9®i‚2y (¥‚gL¤›8qk8µû%†þÒëYdÅ0tªSžØ½Ò‹´¹“Ðle§JäÍãOÀ½S>“}ôY"6AªÁVlG¤Ç¿û&d›ÑHôšìè+êû#å\a)MõÔóý7Ë*ª¥„FuwÓë:;÷Žb’c‘z A¬ZK=7Å5÷Aã|ü·S^/÷ÙbÍí쌘oî~šéR:ÂÂÔÎÛØ ¿MÁÄQ1$`Å\~½M¯;Z,xå/ƒvY7ÅóéÝòGaªÅþÐw™^ø”^Îg#«+˸^Ú¨&Ã’L™|¥ŠH»QÔBØö¥?›Ð7Òû}³YÅÝÌ[Þš?%AZ}êêŽÚ³5¥´ó5e:´ }"ú&¹Žœºg(jfO–maª iÊÖŠÈ`˜âs5yEáaþôx œû²."mÌQŠ€ƒ§Î㟪VÙQ{UÐ@žÎMÊqCe}N²PþÚu‡ZlÔ ¢-ú•ôTc¾p‹©¾ÄdÂÒçFI¢ïs-îG0iáý¢Vú r#€òîí,‚}3´/ X%œ±GŽÚÇ;„ãmk±ï‰Ûž•¾¥×oŠãÉxBÌ!º††ÎÄuÌơ¢!]Ï#P 3h<øQÖÈ÷A×¹S a‡EìzS 0ãòòŸÑT®‘. 5è`é¢:>úÈ+ÁîŽVæ’+ÂÄD9±¶8øOÏK¦ÙdJÏyNÕNqì¥?ƒ Yÿ9øÅÏ3Ï%EE†Ï ‘þ}™Úž -dmC8cÈÝ“,'ýóÊö(xD›_ï¶2®x}‡ £ž:5ƒ\ô€õ¡ ¡f8ðF@S«U°[ -ªÀåVÁHæ3UèÝrtÖóÇ7Ÿ,µiš'øû3ñ’:DÛ6:\fÇ·Þú¡ûö¡+cÖø°÷´ô[Sußýòú§=èÎÏÙn·¦= ‘GJ’±@Øù ÑÆ¹’ò]:Wîñ†:,´æ5hA,–YÉé‹iÃÑ:Š´ƒûwMäæR`Œwv·Ë\š•—VÖj+½¦z¹Eÿ‘‡z@–,ýYN„ƒíHA?ß´@|”Éø)ˆtï•,åf(É¡ŽÄk˜‡ó• —úö—Âï<”’€€À$pkG*ÔKÑ»E"ÕúG®KñI—¯D_Oeö1Õ"‹Ú¿‡¾ñ&~‹XâÈK¾„+Õ7´ó»£ØÝ°ë¢0QA‡hŸ xÏ]»ž[`Þ\&B'{Z¼`óIùÆÅ<‘*ú‘ÿ@LD"xÝh…‘‰„[Ö_0„Ÿ®E盓²ÛO%Û #Å49 %gñqéh KŽŠü¦žˆŒ¥7³çÐf_<\¦eQfn|ˆLãI 6uªÌ©.Lm ¹³…8Çñ‚÷«u§RÔ$¢ï4Íj-VÕžï*þ7 áè×YöÝ 6‰*ëŒ ã¬cGkMKpsþtÿ欻64¸¨þ¢mR&¾ÊJ…ÉŽ¾cqå“I´H7_=ž©ñ¼5]íy]$l(ßZ_`[†¿ÿœJ (rI%xêÝÊ8ÖìÒãÖ5lëÛrûýº,Bïj Û—¤õÌÚBidž:‚) Œ¿6}|›·ÿr‰x½//€¸LÿvṴ̈B‹D"“7z \döb+²ÈR ò÷€Ç ñ}„ªÊªµ…ÜþP'•$m1!ÈTïBnlˆ#Üæmn!Í"›¶ö–Ûh<è´1'{Aìó>«Bj žÇ „tœ:npò5¦B›V¯Öq®ká sÖ€Œâï¾ü™±W±ÞŒ&¸ÈK—™v…a(‹P鮩(¨ÏÆî€È§E侉ÍÏkLúnã!ˆŸÏe¹¨¡Ï&ž|Õaéšo7Ût+ÎV˜—å¯#¼'xf"Vû¹µ:|BöÚ$ñ (þbf/YôlÞªW_ü9é1<“ÈnÆ+ð@˜>-0|ñÝD®jDaQÉÄÌÝJ»x¶žVUpfN–0¼ •0Î!)³¢ tæé ·9L&,{Åã÷eÅl)ÅË ’÷0Ki‡R§ƒvÔS««æ0iKðéSˆ4mŒE©mÅË[[e¸—æÇ€µTA†¼p£åí ®É›Ó,Yñk@É`975©M>>ÊœT1ƒ¾úp­:ïB ¡¶!éP ŽQ²÷>Ör;Ö>â^èU\ø`¦íù•ƒZA‰@ðx13fÜæ·i>˜0V0T&÷?`ƨ©™Au -7x:¦dõ­ËÈyl¹X¥¦à:ùÖ‘ 쨎²j¹ÐÍT=q’€€ä{|©j-*J¸ƒ8‘1øV²Ž¢‰ÚÙˆ€OóM1–Þ&Ü×ðH»7­ÄWu9bÈÓ¥¥z Q„·S@KtT$¯ÃÚT°ÃÃÚ6g‰“DÄ>¨‡yd02(‡yYÅðÈm‘2¯²û+ø¿N!]ÅKL œÉÛ´0UñœH/ðj£ëë›NžÛ6`­”'s3òC™Ö1 Û׆T æÓAÊ´}£ÕÎL\±ì‹í†`þˆ77æWô{˜ÞÆyrJ p•18sO¼>ð×îì›TšóÓ5Zò®f] ‚ ÌJ}©z„ýµl¯æå1x6 _ˆ“Ñ Í®¢R:Ô;½ÿ©YÒrÑ?òü{̸!Ïäö'îf}ºMÔùT0q·Ãi_¦ _y¥Áˆ,¡h }•šÛÓ̸ʒR„œ2Pw‹oª÷)®ÌFÕPÝ2sòÝ Á‰¸2?yÿdVpÈxoiÅû«§–ŽC#yCÈF=fVíw¥GPÝ”LÛCCù¼‚¨tÕc\Í…vq¸ƒò;§>ÌœWcL¼wQA"^ðÁ*&^Cv¼tlB“fïe˜p-!{œß·ó`«{jÝ Ë9Oýª÷‡~d²…š¯ ?—<ƒ5JÐxÞèî8¿A=òµ8œtH³Ýj~}l¿?ò½œAî)¢ÚûBþ%ø$æ4‹®÷°„ü†Üm·ÏwÌm ïWrP:ò—€;ŠkÆßÀºú¢•ÄýWâ‘”?%Äij¤ÈË‘4/Žoʼn|k?}2ËÛÆù#ØÅ/¢ü-Ö´6” !Ü_ÁÉK·Þ5‰sO&™aê¨|¶+5¥3‹©èÊ…õûj:«+È™cd8ÇÐŽ»Î©á½ûÞ\~Û£KMosWHmº3zo:HCY­;¢®Ëxêr 篫Q+ö&Õ5 ÙHy½mÝuóÄÊŸ4BQŒÀ&1Èðª^‹wUvqK¦GÇýÎæp’bÎ3Á(w*ŽË m§áàôÂi¨V/íÅ›kKëQþ»°^á[ÙMýPÖËAd8[hžZÊËÌÕRTyô×XÑÚ^ôe 4iDØ ApfݺòdŽÙn ´­·)ÑÛ«ÿ†Qæ0¬%c6ÊçØáÕÁ˜]NŠšGÇõ#[²;$ë™NÙ'ö>A™Ášèâ·Ü’€€Ùp,Š[‹Vfçb´ÏµÿHË®¿çx¬ E)ÏÉÐa©wß -éé˜{“ÒжòÃÇ?¡/óÞ ¤:‰W+„Ǩê;‘L3µßR›Úñˆô0œ€ƒ,¼Â—3€Ñ½}À=kø™ö éð7Œp²¡ŸìÞ…0—¹ç 3lãZÁ+;£ÐìÙ[Ó¿Ícæ³¢­8?BÞ4•Ó¹ãZuS²D£t•)¡´$8"Âè$­ FòŠ…ÐÍ]kdBÃÃLmäìÂY†Æo¤+j>¹R_ȵåó t¦î³H„e¸œ@:[°—XÍäuRÐ+lu®NÓÙã HgC¹ 矞U·.rÕËyå±ÃRÏY”ôûM>ßÝç*.5ÔÕæ;"MsÆ»ú \™{Þ= ñ€H,[Òž¸ïôÛótU¾Ö¶ôÓöì|Õ}*¥Äzãí~ÿƒü—&éÄÊa†žîË¥i´¡G”¬À”Ð9™iâmμk–=qÀ?„/˜ÀÓ$5üOëûðÇOÛ´o­C‡Ø‹°Z¤×#WSè}µËSò—BFYÙ«™õ®FÄ.Ý~p¼I^3’€}$‡Ò*yUm¹XÏ΀6Ä}¦ûí#µ9½†³9²Ëâ³êÆ©ìîá~Þý©P"  (›öüëeáü‹W“‹Ã!¥t¯N#C$ìNF¯ÑƒÜ'¹ZÚŽâ›ð Hÿeâ/ÝqAP£#kZæËÂÛç#¨÷­ÆOü/ ]ßPê2)ûdÈ[z r˜<—Õ‘þ ÜiÛ»Á:½: 3yDFÛVƒì9’¯èx ãxg²®¤q‹ÖýDœØT/ã¯Sº=eš2Uéfæ'é®Rj„÷EþÝ>YÚ”@ ðUùÇ7~îÿëqÊoA7¢u#{Q„µ¥5·ÅÈÞ÷±ÃþòÕ—Èwðmõm”GcÓªñ„1àÒ/xè: ¢ [½eîÀ~QÍ*JA%U(˜`[a Îûˆâ!@>P×£Âï§%tðØ!¤$ v_#>0²Õ;<›q—õ25‰„(_^á5q(í^hœŸ´P×xG¯í€´Ø 5ÒLœ0MMOÿÉcÏ«="G[ÿ¦DÇ8$×T’€€ã즡ç3¸Ÿˆ“&JÈ×v9žbÇ™zG4€LTÔQ”‚—M?¦y¾åX‘Öp·‘ú5¿b²™ ï[WEÉrßȳЫGË—¡*Ý_¿¬Õåë‰voùezÔý ü§¥fiz¨ê«v³ûXx•[”DU/V,zú ÿéG~ËÛwÀ¥Ï¾±AºÍð€Tm6ëó]ˆìcy0¸%úƒ˜ §P›uµy•NLØH×M¦0+ðï2ÕîqV,àG‘<½…d@ÿLèkwCe—>·Ê̵áŒP´M[W¿ùçxNÝt#ó •F’ù©y¹’&=$¬Ç˜u ùþ¤€m–IF¸à4^N¦Q¬"N/UáããÕJ–2yÁëW mÞôJDŸ–Œ¶zš “=žÕµwÚÚ]»{ýÑH@{ºïbH©{RÔ’ŽßéšÅ«â¸W5¹!µ|ëúñ -Ù®[iiÏ¥Kvp´Ð Ó'ºQT)4Sù!$~„‹½#}ší ZC‰ŠÜ oMeR¢• ß“j4{!:õ=ýeڜڛ=h[O|²}YoìXôd ð˜ú)ÌYëk)Û#pc$¨¦S$'&ÅSy³Š[þ•²þ•S#.L™%É£t5áôIÿkQiž6ÓI¶‹9Ÿ–Ó©_Çø¾]•5¼~DNDp“j@¦L>½Ð+,’€€Î5™-Ÿ”§RPÿEpãÇ¢ÝGÔGÚ¿ýu¼otቄ>$=.Ö 6ø/Š¡ð’ÀÝìdaö²5щL (fÎûµq½í©®C°—¦bÍÑ$0EˆTë*¶“!lº~IbpHtÓùCvQyÚ±<5­ý¢³UÉœÀðQÈ,<ÝyLèÆŽiå]Op’ôì&ÚcòÖ¾~ffŒ¾ò2pé0ýÚÇž+èN…œýÖïþå÷O ŒN¸i¸²u!êGqcÍÄîâÝ›ËeFèl£iÛ9ý`niÓÿÃãÕqX»!®Û6å~ œ•Q o‘f ·>€ÓÃ3MÒh\ŽªÐèÏ9ÊõËõiŠ©ßGUÜ1*ÈADøx²ë)~®¹Sh„T,×Ä}/ø¼çq•q”³üªØ¿¶i‘ïž3å/p½¬¶î|Ù…f 8LÄ4ó í؃9Ë ÒLó?3îLÛ%h°oŸJQgT‘t@í [E7jUç:j øç̦o´® ÕT&œoèX·•©ãÝZS-°—û"h¿YÀZˆç2cÛró7ÚÁ'Oñ²öõ'˜Ò·0/\b—³œÎÃDÜ;r²_†A® FTUÓ@¤háÉá©p©{Ëñ eeG$~A–ÈÛ#F_JvÕˆ9(~ì¦&:ÿ+ÔA™›–$‹ & kƒ¼’fÃÎeÿ„‡À3D°0ŠuAã ¡7-À¡X`zD[–RÀ¹.Bä¯lŽûÅfüøwft‡íÇ ª†Ç‡8‚&7P¤;ùyŸ ‡¹ JO£fÜîhêL'È\ƒžb*W•Äl{f¦ÿjÍÎJ3ÿÕWàgµzE’ŸbRÝÝm+.ý¤àس©YϽ>A¤dàë ’UæœvmTջƷø© z:Z(¨? x·Îi[bb¡é‹²©\¿µuMç’¼ªŠ¸RØæ ?:U»°Ý¿ÒEµ Nù´€I¹8††NåõÚ[=Á’€€Î±>²_¡ç¥˜æÞ°Y“´!¿ìǘ¤t˜îòö'í(øËÌr”ŠNFÝ+G^õnsgåù~i;®ž‰¹®ï£@ÐcË …LÇ`¶ÁÕæÍs@7ÁùƒˆÓ[žÒI±p‡OÖ~uûDÓ—j ë™qλ›h+–.çF–J&ôLâp«yîZŸ½³Æ–鱨Ó¶]Z^º‚x0.H]ºïñÀyÀD ðC ùøF0êË ià·9 ¡Ý>v…x z4œÜà#%ØOÖp¸Îi‚!ظÆ÷~DÌL#íÁ]åõ„AÑð-%=&áxÔ½c{ßs’/§cïd^¾  ë5Œp7l}s>-Xe“FÍ£j Ô…É溲绺“ü(bS´wËÜQóP+^bfão'ùa%ß]»ã ü°´R";×ò÷D<ºûˆcüM›{oaÕ*”nt!/KO¬zŽÆtIF:û°`zÁõì ñ#›Sé¡Ù] èQXWˆ Çex"”rµ°Öž—Â)IûÄ¥Ôo´ÂüÝÖÌ.Ä„¶z—W>ÕZ]y—¦w.ÆvÕøš„k¥ÑúÝiã¦áQ0¢%í]7ÍòÒ2n|u«l`]ß®zmè7Åï>°)€ —V °Dì5\(j±æÖÔÃñiï1ák—Ò7S‚¯ÿlÞÚcò]ŒÄè¨Wõ²ŸÜÒg¯@ERIØ?ÐreU±Á}¹;a=¯+Ϯܨ®o¤¡ì†’ÃÐjÊ,y¹ )1'Hê£~”¢n£Kdë×CB¼Éà¯-i8^¤Ñ—ç>ì¿áÆuX {Ì ¥ƒ$åñèí´÷ø´uðƒê›ç¼*ß¿áA>‰¯¡Å®ðQˆwqnmbϰGÓõ‘Ñ4¯-}'AÀË«h–—FùX„0ƒâ¬½)yÔÔ»Î35`ö%ælˆ  iþ –ídEP‰7ï•çãz-â+_¿­¨ÃÅdA)¹³•c}Ø÷¾7êmr‚7}’Z%ñõ@þ§È×@OW÷ÌœèØ¦\NV¹µ¸Š)Âàä΂÷Ò*aðË-D°à}›O97bÓ˜éQ<ž|îM|v!¹òÏ~ö«Æ)‘Èu"au¡ó©­|3Ñ–ì2ý/|J$û ¨;"‘cÎ’€€Éxï„“‘¬ulyqzR]A¾|I(+€æ*H4ù‘©WBó×í¹W·Zuåÿ:¤v`Ñqe$1œuÕóíbé ðe°–þ`ЀOÈzêz|%ÒN w"-×éIßµ53R<Ší„ûAN©ÂVÅ7¤á¹ËuQFñüzÉ>í!cR´¡ÝBßð—úiÊAè‚ÏY@a¢ÄÐúàBSÖK‘µšÌ«¥|û¾ÊûáòÅP[ aíj”¾YlJPþ) —Zs&…` #SÑËëï ¥½Žý{¥bÊ‘R7¡ÃÍ&ŽOV^Õ’Ny3"Sl„2ý/LfâQÔêNêæmi®–°#×@×f,+{1 @„U§OE>‰×$1ÿ?ÆWI¬Ó¸ÄS,©Ÿ‡°ahæÃäY‹Ô9•„};õm&èŠÃx}ûØ¿p+៵ؾŸ‚©ã âI%ãÇwÿ GsáðÐá<ŠN)ÃI¬z=ü‘»#$EØdX‹‡‰®iAó$ŠZ§'¾e¼´##žÈ@ᇤ!~íkð…Êt”Ýþ÷àl*G¼Œzú¨xÀ¾:Uì1'8ØM×Û„7õn…ÁÖkeÞ¤g›åuß…Ý[ï¸'ȹ¶´5×'¼Ö0“®(ÓÓ»fLN_²ÿ- z˜:¾õÏé@ÁÔ9u°¶®Þ¢”©û›·§Én*Ù½M‡_&¤2ˆ(­;@+¾Ž½Áf§u¯"ºÜÈ{©Î¡WM[Q8ž²güç{Rtá`Ðû—*§Ó\ãÂå(w×J]ëdؙۦ›X"YÑx2¢µüÏVI¶€øÇèhµ@yu†±Å#Íë>WN1’/ŽñÆ^ɜ˛èW™W*Tÿ±_÷ZügR¤Iš¸ë§|R²bÊåJÊÖ|5Ö~žì@Öã^™³´{¤++&$¹æa«I_—ã/ö bYÞHŽ-ñ$Ês…0A–ƒ,Póž%žsëV<ó%÷J±xêY zä -’€€ÔpÙsˆTxAf¬+Gœ‘…þ© ÍÏ<¥%ñ3}ú\SÏ€ €ãùc†ÓkO€²j”¸SŽÆ²óhœûöª«°…¾_¸ƒ-r¤¿@9AÁ _Í õíiY,´kIe¥I3Fs‚OtË4wQg±æº¹F°õš›ù²¬ËGé‹Xv©ôy¶0¤ÙGMˆI÷ÒÛàÉ-›í'b ] “8i(9§…nœD^ï‚~ %çkÿÁ•ü„¤ŸMôÙç3ùwã!ÆFzÅਡ‰¥œå—&­¯Rª4¥–8žý¿: )¤«ª= í¼_AÒ˜¦!EÓâÀ^{°w^@Wj(T¦–Ñî8iëúyÓoÄLiÚdLQŸ‘|ö¦¨åXÿõÍÔ\núÍêÉ#ŸSn‹@‘ˆaGLžF´„{šfc;ü˜ ÷ï¥:1VãD8…ÅReo†>yÁÙŠ¹a×Ò•nÆ‚7´]2©¯Áa²½¨aÀFņdi€Š€>Ñ`þ\ù:í(ñÃ*aÕa!lÄSgð•xÈ߬÷y°5ó‡Ñ ‹œébùZÅ[´s ù7ûéq< Dâ"\ª×Ôkࡉ«Údç·reO:¡ ƒÍœ7xx‡uÖÚ=|•Zã¿’ÒÝØÿò¼‚DJo¼¡k¯Bº›fti—!æþ™Xùbmò£‹l²ƒó°}#xºÌýÐÈœ9z{®‘ré’€€»»¢ÃùZ›KÀæ9è' ð9bdÿïH^í•5›=©6žºËîGv8aºô|:ýÙûs„®¡¸Ý¹RãÒ¨OÁ,×ükHstSm€üŸfH÷emƒk*šRU¶n=ÍúrÄ›´…½¨Ï*ócÉj•‚·<‡:Q>OÙVë•‘ ®îPʶHš8ïÎÉ7‹€{‚OŠÀ}`‘á:óúÿ{}¼{b´‡m[rCæ¸XÄ [nÙ9›ÕQP–|1OT¿¼ÆÁkt[Ì}HYqV8@Q=õ.·“tÞF¬lŽ—Â4–ç÷ÁCÞÓÊœ«W•5Ä$ `‰Ñîm¢×U Š(-G×)£$ˆü0czxÊ–ÊO-™O-Îx¤~gÑrH]””ÂÔ“zn㪇çÁa$Lû¶ÓïÅ<ìqÑvMlzí– o“?žx»'ù»+gù¾€üÉuŸõlÖuÚ×uß6h#Ÿ=†¾ìE”™RÛìy|FÏgìeÊ\õÐÐ7àÑùÚä¯\æ×âw²6ZÛÖ>—øY~p˜I\J3Vç1{‘=1ëx!ñ4†šøúš˜NÎ[0‹?`#‚…~d¹{_«½\TÖzMßW;ÖGÅÊT¼!ón¢V`ex žä¦ôÓãmkçØ59?¯Wœf¦ý<«~æ ¦B¬-l¡Á9§KNTËÍàS²RBÎwâ)I`3¸í’¸¢-„Š#üì'yA ËÆ<ú½žcR?Y§=­Ê8Èœ¿õ´-ºcmkê§œ…68XI5ض÷2½Z“ ÀùASŒêy§¡}î•~¹Ó!&ø­–Ukx161¤‡ ›Îàå{UaÏoO5ö¨^½Yeµmd¶~*±äWì/{›â^¢]QÞBÈ´u½Îô¬1¨¹W@i)ØlÌ(°ñÓä`U¶>ûæk>ŽûÉñØJt‹—¶ÅbŸ €îwíªz^||è£;è.´ü¢qÓIÝE€ÌnJZ¼† À!NÇXè0¡Ä-òM'=@A«;îN,Ñ]™ÔðC+À"ûcxV6Ð=L'^7ïmz~‰ÿil ?šQsš}aìÕ£·¯Ê_/”éhˆUÝ–ƒn1«LT±]œÄ–ÝÃvºD(•Ì´i‡¸ p Ô\úÔ’NP‘Û8 ä½pÉ8½ªYzׂiAØ0ªZ.ÎzíÄ™ûïÉI{I}ô~ê *PlpH‚Å¥æ´"ÔêƒÖôv°^7 ~Sö‹ $÷Ìé××˽¦YîÉI.­Œ_ަ"HðyrFô×›ˆO-bzm=Gvl=³™®Ó%jÁâD)Q0bvT%Æ’€€Õå’»’@/ÛΚŸc Väòë3òÿB¢á'}4nE8öú5îõ)ç™ø=ºe)fíq`tÉ%ä‹k§£Ô£9ÿÝ„þ÷θOéŠùÌñ¨ÿC·§À?èk¶Ov:Ƭhà%â°zÍG¾ÆJ¼”@{·OµÀÐÎ1+éˆðëçZ<\ÆÊß×õÞu,ª =ôˆj£OÑ‹ºûFDî9~DmÖl2jìÏñ#IøÈuÁì¾=Ü›xr„ ]ùîÌU\8]žQ$Aëm]ä©:=Ü™xÚ¶óÙ}y г‚qLþzNûŒ×®ÐËVa9È™wi#Ê7ïä%ƒ€n¿ -[è\à”1J NHðÌê(fÔƒ,€ny­û~6*õž¥Õ‰§™D‰ªvÖ 'aÛµ4XJ¾³ÝV™Ñ_ÂüÜŒD½ÄxŠ­hÅ*¼µÄ“WAééñ äk,Vô©læÑ?‚õþ& $PÔ˳†Ï¶Áoõ‰jzüÜ[KšÁî˜Ñ”htu„% ûàÄËÉ vê^9„ÉÂØ¶½Þ-çoðM£Ð•Ye2ÛÞ7ÃÒ>Wå¬XaSó†?˜ ›’s}•ñ¢>”tûœ ¤d hxwÿ&/³~uŽªfÝ Â$R¬ÖÓ¶Ž~†E~x†ê=o&϶ÃÅ”þÉÛ~ÛúLxu¹"× Ñ%¹YÇÂaÅ3LxˆÍ^Ï4àžÉz@´¦•—ˆzàìó€r0‰ôÓ=Ê#]’gÅ õ%«EWÁ” Ñ³É ¨š‰Ê¥“|ÞÉHY ƒ} ö®7eôg†gÒ c\Éæd”s:`´m¡’à*i/èX³xÃÚħExm/*?-ø^ /Ð+xOwëQ¥Ö_CgxyΠ9É «8j õM4ý6TìÁÓ•{Ô‹P´‘ªì.ÑkÊ;Û¦l±Ÿh[-ŒÐЦûÂ6<Ô£8gk|: ž¡Låw‚ 9‚´<Âg¤þ3ôȤæ¯2U s0’ÔìGv¥ëÙµõNäø/%5ع Îü4ü–ë’>„‰ð ìÉÄñxn~ª ]ªI!Îà º<®R¢ÔøU¯<¥ýü±!÷)ÇÌçÿIyaüv×9g’€€Ìµ.Èëfbe ,{°n$ñÑ<7váÏBDBý»J{—›´3ùág~ºMzÀ âÆ:%Çyû‚͆½è¡#èbœqC5½ˆI¡Õ’Õá…æ4€°·4ãå$†eëg©}uó dñÒÙï"és¬ J'µÕ~Â7pqyÄ/×%’ÙŽ€5. °à7µøä='ÏœŒT½3 f_ß•®ioóxä-‚™mÏV—–÷ RLæØˆàÓÞË,¼òŽî‡v,;¯õ¨~¤ITy‹M”‰LêQ®4†”ºtw©ÓX™›’›S±!sûØû=Ø3b·È¥ç˜™óö% {ï1ÝèEý–’0ˆÿ¥‘ØàùYØz<¦¿G_9¶¬¶²Ûr„MÍp¦ÍjµZù0'™›ê4ÿJÒ æ±ƒ%7\Žf~RIe8ñÚ“ÞázÆ <œzTk˜p¢-(®×_j.²i' Nñ¥46…Á%sêC>ñ-Aù—(dYɉ‰ºB;©ïz÷XQE·UuõåÚS˜˜öáð€À{—¡SH;ón¸.èFt‰“¥ø‡µyú+)„æŒêÝ‚9@ëø¡[ºzØÉ[–k&4ÍÿSÚJ§Å2ì,ä 'åĺt>èïhiáhÅž„:4r¼ó¯ƒ§wÒe=ê˜%ëÿÿí¤wŸMÀZmI5ŸB¯ž‹¬Ìß»Ue‚;`8…"~±/[Ü×Pì1Ž¿ÎkÎÑWå´|˜oCÆ=ã¶¾ÆÉS“s‰ö»q³ñwéWkêkyÇ­H’>²…snÞ›uÝÌUçV Á»÷¶xƒ„Ç"ÕWë:õßñ®Óçí)1°U‰ï¾Nï j)ã}RÛ¤›ÿXo¥Ôð$/4 4®?,ü±1µY£é¿Šü€e5¾*†VSªqÜF-º~ÍFNÌBA-å‚W$K_É縘g—²ÀóŲLTdžjÃ*ßbîR"YAŸÔÓͯgËæË-sÃodAX“|Q@Ô⚒F‘47¼Üy«@âàó|àÄì¤2¢);£=? Œ!Ôr¼<ªäiÞ³™tÚrû½Wâ:Fp^ò­9‹œ¬ŽÝ{ÁGS½'’)êp¼×Ω5#ñw Í80 ~¤sf@mµ=ðþB¬’€€äe²H˜ƒðb3åÃ8°¨Kvy³ÿ'50ÁIÒ}®ÌrvEOœâ0ØEªÀœ3ÝFãÕ¤í”1˜Xh¹OؼûÞr òæc"“ lù¥RŸ…3,d ‰ro6Ð^ÿc”n-s…&Ö UT}+x]¢©¬Û`±=KDüœEpþó%‚ÊGÖPT‰ôáÙ·ãûÔ:;šáú'¸ HŒîË–ò&·›ÿ\§’“@´Ë{>:bYVaB'ËÌOpJkHGC¤ ç½= ’Øhf üÎ.M¶pˆóñJ¼dÑQ×&Cxº”je_l2Q”%þ:ªv¡u5øßþ¿‹l=ž¡;¹1¬ÄôWÙ¡xKÉ Ú4é»Õ[$¸µ BîžœƒcÈ ÄFɽDª¯Ú¸³è›Æ ¢ÂÛF‰5ÂõÓ„ÆmMA"›ÉJ[©hLýH¯-C6Ï6¿¬2ë ‘¸j`uÔœæeîNa…¡ˆ"eíN°æh8óo9iû\ ˜g#÷-@¯ëç»ÝHKë¹_ÜÉ(v/7^þË8ÿ¢÷¤?(nk&C.¥ åÛʤSñ¯q‰ý :4æ½4Õl9 Em¢ºuhtàŽ‘®C³à'—Û¥´‰Õ²36ÄÈ·QBC>†qx*Xäè_eµŸ)ÕוmIŸk@߇"ߘ¾Ií¸’€€ò…Mg¾23{Ðãuç‚igŸ_K|÷\p03…Èö„XGiçVM.ÿ;˜EþÎ7V9dðËbµŽÍ2ºˆ_fâj*Õ×,ÏöÊåØÐ•U¢×w ¥ÎyèIËš¹AOøþ9¦•Õ §,6wÇ ‰Y+_²ôøæÑT’”o(H§êûurú¶ÃZw›8?|uBéÀ@«!Gxh+Æ=€:'¦˜’»Zfƒ¸Mxþ„Ç:XÈ;8žŸ„ËÇüïÑ¿â`0ƒÅ”ÀðA|}22àzŸ'ÜÓèéNë+×ùý²µQ¦Žäëÿ'Ìò#`:,GNzœßPÔÒK0øäÜåi¸?NëÏ£kÀܲòJ»v1jøf¢àÈ–…^PTÐ"Üpȇ%Ãßpã\lÇÀ±•5òRGzC'B%6Ù:êeÚtmÇP:0+Õõhä)¨²7öhÍŽ]5,F¾2è4YaúüŒºU,*@[(zE ͪ:{ÕÆÕ$ºW÷«{ZóðU~š³šòɉ§Äö¢:õ‘ª4¥´ëGo]ÌvÒ $•‚d<ܪ&Ü•Oè`Q„ë0Ëô@Aѹü(©;%ÊΧ0p£µyÐ3â¦1yů’Çð˜BÇRo7÷]v1›&3Üþˆdù}WCš¾˜rMЙõÌèfçÆlÝ4äWÿÓ±õ ]_!•åW6Úèê¢ßŒcŽ’ïÛ(O≰w•LÜZªŽOÍ^Ir´6=QîÈŃ3jî´ì8Ót*'û.³¶ƒdqñ 5tø²<]úK›„<=ÐÉC˜„«ÂŽÆK*F/™8›wv–ëCÉõE 2ŒZ@Ö=¦€À•ÖãxúgÌG»|5;ìh4ácŠ”çívå˜to´ ÝGÄqš)D&/“‡óåZHW'õs¦ÔizÊ1A?Ŀ殹cëa}¶gNä§© ¦º÷ß©ÆTfh’€€ÚdØÜwöBZñ•öañýÅIÁTIœf ÀÅùÀͯ¤/Geö¶¾EFØt‹ xmµr~¡T`(Iê2“Íñ|}NspÈ!ÑfɳP#çTô±Éî95ºi^Gv]ìšdCÖô¬¶h…ÉÞ.Ú‹UפŸÔ><6¸Ø½g6dzD¶J]ŸÒž:'‚Ú»„flîXÑ2Ì?ŒxSͼ.E¬çD(>v˜ò1XP˜²‹ío•O•ŠÖ-—[Þ ~z4Îy!ô¾¡Ü¨3';EIÙM™JXêEÉ<$F±–IZXI`'BEO‹ (ç¡T畵ø7Î;4ë©xèUTújKª`{¶Jlñ¢›¦×IÇ|pPǺ’ẪÔÇ[ ‡0²ÄXZç[³øm8N±Y_.Þ˜l‰¶)Ro cE[— ) ¿# ®ï^§Ì”šúxÒ<ßñ7œMîÁo1 s„gØûG“7H%bÙ?3;¬¢â}¶ó >Ž@ö×5w뿈5†Ô5°c¯OÖ„_•,÷#JA[šUÚáøˆÃ#Ëçdf¸»Â±•m0H"×mÖ£üÈÜ»Óçd3¶ù×t Í•ÊsÙõè üΖ°=@Šº1LjR~ ƒ±»Œ9º:i0"A‚W¨óGmÖPù¡þjlµK±õçµèoçó^ ¬ù ®ÿCQŪ+@2ö›ÎÑÈ&&3Àÿ):ˆÇÉoš*1oð;øÑDûhS]5¤4ô ü‹Ð×ê:ñ×rÞM„ )ÖV†÷™¾àÄ‹_‚röUÛ2=!‰n¢²/^ ˜T>š1F÷ÿ Ìš¾ßÀŒÒ|Ýcã\(–—"Küâ´hÇ2Klñ5{=ÿp£pžG‘ü§XOÛŸ$årêƒÂ­0þ?Ÿ‘^áÝBþ˜!·ØŸä1…TöS¯ÊI»’¥yPØì­ùt ’XbgMÙ©û%½ IoÂܨ"’($‚eðlÔ:¨jÎç*Ä¢A2Äçn`(kcÒ®˜² ðM…UøZÑQ1!f g,K5…óŸçàÜîu x}N…–dŠ0kPÿÕ®p£û[GÿJG“ÿïa#l‹YjIè&gøh- Æðò*ë`Îø–Šõk”Ç”VŸˆDO®øQùŽ·êV4O­L˜ÇuN”,výU¢øBe[ɈcÁ¨kgêA*æQÛóC¬aæÄQÓ¦³÷yQªD…·Í*¬¿­†øÌÿë±ß ­§àÛ,Þ Ã‡§¸D]¦ aTÆf]YÖØ~ÝÐ?Ò„Œ¶%¯ÃÀa@ýý¯=¸2E-} ÙP:o|ÈCsì©6ˆ™lûž1([(¦ÖqøKI¯öIûâÕ‰ñxþKþ¹nκ”Åð)·¥Æ9ºFîod[DX…¯à†97a¬PDÐì îSz‹!QÑFÛ˜ â‹Í!Mj±ª,Äüʪ9Rß;ê£Q y³ðõ!€‹LÊ,ñÿñGÛ³ÖÌÆ)e’s×Ô5ct> Ç~–!Gñhëm5@¦±Þ/ z­¼fÂ7ý’~ú—ýF.)(ÎŽA ë bN‹ö°å$z]ÈŸ’€€úÊ ›¸?ªÃ‰Ùe4÷Mu·ƒVBD§uZ 9"Ñ_ã‰ÒýŒä6AHwϼcÖÑÏ`âu§<^Thùjï1lF¹Ì¤CD¢c¨NÃÍÞè9¾ïBæòŒ)̃Y€Qs\ÍúQmõtSB:R ‘';±••”qP²ƒXñA"½'V碀l}¬šñ $[¡V7p4DzaJWšËMp{Sfß0´ᓶâdp¿ÂÈW»-:rÌp>ß™ìa†ÛlPÁÍ5f8Å% èl©MòàØ§A p°ÿôuÞ)ÎLq‡ˆ4׿½6Ï„=̳ŠsS‡Z!#ž/­€³× aŒ€ÁÉ+4>uéö:âö¡ƒòçD¬_ªj»Ú¯»û#/ºfƒÂ‡?p‹¦Ð¿q~–æÆ¤òVÖRcÏêåRTkîYÂy?Ý,ÀÔ'²é/˜¡¡*r€;#w(©ò;CÇhvzÕÛ;© óÝõÝÌ[]Õ³÷¤Ö‹¥îL×|ú*›.qên•àwǯð5Ôm“…õÏ-ÑÀ²çl÷ó“I8u¾M/»ZÅ{Üï=c»Ñ?½RèˆVÒ ld‚M’qƒÓ3;Ÿ· ¶o… Ÿñ/5i1A|µîd ‡Aøàûhì¼J#hˆš ®“ÈaüÛ3ÿý†´)G`À”½xݵ±Ä5àìIÁfìÆ«¹lz=ÃÛA*ƒÄ#Ÿ½½!vï¨k§ÉÄß´°Ä-*å䫼k* ­¤A+¾ýrqëÏ—vß E gè]xdùЂ;\,À°ö‰R<,„‰Âc£+©øoË>¹Éåæîã%ý=“QdšŒ2­ÏµÌ¡£^+‰òŒÕ‚bWóŽZMþ¿¤rl æ¡ëejRd1š<„ŽTfë‡å{g¿Ä£Sj›!z¼) $ù\´J¡bzæn”dð{Øöcû™ÎL ÊE|7^v¡{…ÝÄjD!$?äµ’±‡¢$KEž¾–1hMT3;Mbáü×ÕùEÊ&”ËsæÂð"|­÷\ý*£¡ ûRðÉêUƒt¥¢ ߨ&p;]Â[õn+ü¨cÃ0©O~ ‰1›¥s&µÔº®(p²')g¯J×Í8 ûŸ‡û­nºÄíŽA¿ÆÐ—ê¨Øhè­®‘êŒâº@—ÏVCÈt²üwÛ±ÁTˆ<… BBÞ«yâéØœëºÍD±•Ž^FžùÏõ‘< †Ò–s<âEõ7ŽÙ‘ž Ëo©ÝyÜ\– ¾kd´VT/=y‚:)‹”Wß ]ã­qï›·ã¢er -î:¨]ç~m”ª&ÉÚÏoÕÁc‡+† BÊɧŸ[ 9)Æò¥ü|/åë’ùðÇ•-ø-³ð0:&6=#˜¾Ò? €¾‡ß=GÅrm§NqN$U¬ÆÕDþ3ØNéŠÛUùeöy‡¼2»4êÍLrãã Œš"g?)ô‡dÌ«"¢?8Ó¶ßu“Éh–ÎK}vKh7òÆwy¢V ³£AÜ£p Çó;»âÒ~ð j™ˆ¯&…”EÖÍ!™œë&ÚßÇÒ`ï#îr©»à¿î8´ÝÛ’€€·xCûwüê0³ 4´wœ«iª¡Ï¥]+ú76ºàžå‡Î´ŒUj¬-ßažt†·™-<­U:”gÅ@_ vuq!b» OVί‰?›ØñYñhUñ×sñèHÑÞCß/+Úöwq xÀ£UÓÊ~éø»•^MÃ(Íö`êŠF©É Àå–4õâ»QŠ"û_“L:n^£aûó–`y¿3SØjÕµÐg"[Š˜éà ¼ß3Ò›Û«ˆtnV $6±/=¨;.€øÒ‹± GÛ’㬃b¤~Y‘ZiÒ¹QüšöÝ‘„ [ Ûp1 1Šx. bã„§LþØ"Q_"šbÊTÅ=üèypøéÌ]LåM‘ŽÆìXíGìƒÒXàYKý¸&çJ‘Á^>ShŠâþ‰¾8UD}«ÕÙ³N´ÄžÑŒ•oìXÊ>vN¥üèõÎQ½çàDKflJ`Ré OœÒ¯ é&[0«Y!Iüµ§æÞT§3Âÿ1Ç;µíP«ÂLïyIéøAD6J÷jÁÖBˆN’]à©‘ËÜ‹/Ö2^×:Xê©í`ŒiÃÑÆ3ó£w#aÉÞÜU,Èj.£jÉ&17·™êV];5¹Ùv–ÿöR ì(|‚`Aâg“ßâ¶ú²¿`¦²jù;7¿yIë öŠ»»ŸðMœÝyÔ=½tµš°ªf©Ù~ékNþx~{{CãÚè$ŸÉÝMÿŸ‡ ’µnaê;ŒZ[4Þeu›žmcž|–\„1nFw&“i1³W”†úoÇ Tçãß@NÄM÷™,½ÿÓûÄAÏñ+ñ˜®ø ¥Â˜Ä=/"T” ÌQ¼µ79Åq‹&Ñ¢ZîŒà9Zß”›s#Õ h™ÏÇG’˜PÉ…¤¼^ÛÖÌ^Õ¢x’’Îì l VûçE=ZåÇcø9Ç£îFt 9»}ëÂ0“${õG”n4Q¾ÃEgxªÒfk èîG¼ëñÆy5ØÄct<›S ŒL©fhUP%ð]Üæà½/Áó’ÈÓŸéØôY«tU”ª‘ìÝ¥‹Þž•é„Y„bÿÃî±óŽÍÕV@ÿŠ)E;Õål&I*—Ÿ¥T݇®°S^¨N–~ÜšÖGuâ5*e;‘Ƕ™±Âö 1’€€ÃWÞúÑ‘ößÒÒë‹[žÉÉtê©ËUÝZÐ¥D“·ä§ácG¦W³²´lckª Zín½¦Üi%mu#ãKë*á–?Ç2MѺ(‚$¸•9‡æÕEÚ†øÚ7–TÞ§ËQÌhLgCS`Û€„\–µ+M'¨gôÅ2`š¿á?øÜ·à`Â4Üý°Ùø‚z~2B†á… úuK)Âh3´#ºU~ï}漤º…LŸ˜: 4®U3MñÆÌãr†¥ç&‹‹³”“뮪{–×Ï™‡Dü(erÓedo«Û~Â(ª`Ý;‚¯}û<_/éjóšCL‡€ä†¿ûsmèÐzorUÝ¢õ· »õºk ôm‡ul¬ÆsµÑé.øV‘ÈšÇÇ%ùëçu&h¬(O ~ 6ù lêÅýeyçû]ÿ‡ôÒ]1€Æ3¨løEåæ`”¶92§íb®êl ›„!Õ"wöOáïUë†N*œ£‘fMØ÷w7æßˆ×7°~c ™âŠ.vl‘BaµØ¨Š+! öi€oä1* `ÁëïÝ]'Â#üaL:·ðc­Ì¢l—àÄ«e¥ ˆš¥}BûÁ8¸±ͱ*²ˆ142ˆŒ<¼ŒÑÌý،ݡõšßìôŽ“s2y–=A”Ãá÷„Ÿõ“uPEy©µx©”.AoÐÓ š*3,LÈ’Ò¢WºZíæ•C«Í3P×PSþÊŒ¡è}¡IKóÆ$VÚ3¡’þ8J¼ÿ@Rƒ5|?ÝÄË‹¨„¸(“~øÛV–t§x¬ xê-Ɣɒ¬Ì†L€Ì9ôØç¸(Q!ÊrQ*›( (Ñ£äò:œÖð}90z¸>씨*'»¯Dë ?Ê?l°“KäpÔi{++F¢úAÆ®Bì@ŠIï}“Ö®¥ïÚ×ø@PÔØ«Ð—!Š‘ßÔ'úps5„pi`rH°]|QýIŸ¼›ÆÌµ@b@'®_l)…›½¯­l2.ʪ~Oe ŒûY×Þ(Ù)Ï›KºQ“Ê‘µü9[¬`RäO1ÆUúøøµ”Á~¯-¯@¢Ç| €~){HôH£ªá>[ô£OëøwW9½ ªNœ2JÛDà©Q¾Ñ›:²µÒKÄI%”Üà‰ ç’€€ØŸHúýh›'sÕ&jëÝVþU´`9l.un:‰„úñ vLϬ·öÓ=ô(â³âòÇK´–^acLˆ|’I¢ñH¬Kí™ö—4ôËÏöí‹ßL3¥`?í'ˆ„äÅÊÞý&)4Èê–Ç«‰“s§tÒªDõ®•ãh‡·­Ó)ª€#ºvÀbo› ñ™ò}û(M¯=!`°¦vÌEüÊÌ]¡«ÏX fíÍÚÇê8ï}ÑGÕ6ô‚H>Ió//Ç*â ~6ûå/nËbk²»Ò&ˆY°ŠE¯–œ1¯@ï1®ÐxoUC¯}rMÐ/¡²þ‹PÝŠšªšDürÕ%9•Ü9u aSètžöþ’<ÒY¯†c!á1Õ_;uÚ<~½õGÅ.mF=åÞ¦N.Iƒþ†c ì6†/bT…o(ÄQ¤o˜z~Ì¢Ô°Ö …çó­#ÄvѦ5 4±ÞÓ[yšði ×Q»ü-# X/ó•ÐÓÀfâÒ[ðê}ä}0oöÓº_Zщ{…Wßçî¬*[ÁÉÖ™®;Ÿ\âÚúaå e–gûOˆ‚nIhÖyâëÚs¨+jTÌ&ÅÆ¹Yï&#yilOÓ²r:Z¤ˆ¬&9*'Õ!zoS˜€èÉŸ˜Gãï&i°MJY£LÍŽÖöÓ\ßÿýÌ¿×B¤}Æ]á ¶lF²û»¸i+Òœ5Џô)»eæ½"!GŸ‚ |ˆ¹ÂXI#·}ÖS|O€›æ Ìe92™îñåýM§IªÏ¦l&¬R0Lòý`ã?%o]ÊbØ[•–œ'¿4˜“Ô·l®áê¿+G@V£‰œ ;ü'Ÿtk/ ]ãñM[¡¬=¯NåàC$’€€ÊC4ï熣î4>Áì…múèÔ­SÌ?íÑ1- l€Ê«¯²Ð^]– ;5¨ì]E!6ØÆFE=£EÅÞ³ 9küKéo™¢µì#²2"AÏG5vÿ­±Ù´Ì¬Ò+5¬ëw2üREðPêPÚÃíü¨º[†‹RÊ.@4R°OÕUÕ˜l"+k’ɧ˜xÁËÒ'c7 ðFÓ À!A!rÉŠ¨óêzè¼€[ï;j'°³+c’ÅÀ~¸hp&¥V2ªT ½D0þømgÎR;LcE.IÀæ'‹Sз$Vͬ»'®Ó9[K‹§Æ“í-UÖJö¾ŒöŽok^q®uÅ|zµC.:“Ü}ð6žòÎyÎQ]Ä;é1¥G(Ãí´g:= ÈP{,|6^öV5¶­anv{l{šF?3f€‰Íb¡MÕZÀœ©É³Öã.Žlù¶‘¥ap)gyB Bµö¹ ¢Þˆ[>ñÞÁ~8RéXId.fôs¤²Ðy‚—b’^9}ÞûyÏs¯3FÍ!sƒ¤q8Ž¿öz÷£.´æ7&Óo)Uo©GVÙ³èýë' #£>À¿ðÜrRp:¡My8½–kàõ#_lz©þAAƒž †q`Q†›a‰<î8é“ý“éËç´Ë2bùúÑýóhzk¡'é8îÊN/ [ jÐyâ%Åþ¾X^ü®ò ˆ^åò¤ÓKÅ4º”\Í6 Á6ÃM"g®-±!‹&~©Öw$qì…”Ø8·zObâïTž ûÒ(›è¢f®y¿~æÚ¼„å“"@›M)él#^•©º¸d*èvC%Î0BÕ£¤…ý£å9OË,á˜"²B”Â)vîyõå°µAûæ¶¿©ü.rO2YÝòÁk7v½JÏ…ð©™ih8DÍí¶ÿ÷“ƸqhÀðV@üÓ»ßpÕ>WÚ1Ì ôŠèÉÝÆ@ŒòChãR[Z›Oš&‹É–Lò]fš¸`áPò-(aºÛ g"ûg÷r¦‚CÓ)6éšR OFHÇAÈK4`9ÖÚq‰‡9XÍ÷¨“ ÿf¶7-ò÷x»¯Îh<ö©*5HLÒ §ÍgéO7÷OTäúLùô áL&Ñ’åNØwHcucÅ Ä•ÅÞrzÕnŒÝ`’€€ª‰ULÔ¼¥ÂÁ|•ÈMo‡¿&ïÚÀZ|MI&‹Ü;(•[Y‰è‰¡sŸý±ÔAwˆ°´ŽGOçGäÓë ˜ÈàÆm‚øŽ3µ¤g,??õûJ‘ò&<6ù«YýŽÔô‡‘PÃS²™£Õ¹Tœ2_]c4’zñ4ÜTo*š³]ï"«]L–w ¨g`ºã[§bcUo;û¥8 ºì²¼Ù÷—¼paêÚ¯B‡&Ø«"£L¡’^¿CZ¾(ôåw+&qêCpG]RÙl5.èɯ«ß5Ù2p2±Æó½º^Ü H: ­ÌžØ^kÙîÕzŽ–XÉÚ$þ™ð™>AQð7†? §ËPŸ8óã²… NÓNÊcè.uA‘«5:T~\7^ù„yoHIR/tr‹/Hß4lË 9Ö$•lí[|}¨zÓ!O§Vÿ3ʈ™JM\=M*.}z'_hž ¶©@‡¨ZÌ2ǺS‹+~iå/Fk,xša[}÷à¤à”çC:#xÇx|[²oðýáÁ`BëÉ böÛ• a!§ô]nrøoІ}8§ú}¹ úŒ7É„X±=õá?Êç_=<»É¶¬I†í€}cç ¾Ä Ð·8EõÌ»>^Ûºõ*…õ<šŠ¾AO¢æŠ!ÝlÑÝ?t0‰m¤’m‹S膙x;Æ!“õ.eÇ‚ê­[ËOì»Î? J@8'™áF‡0MðÄÎ2O˜½NfÑâ†ïÛ=ÌCŽ5œ]Ó-ÐJ Ú8+@í4 ‚»™ÎqÙ¬(A6t7y]ÍeþÛv6ƒ¨56,™@NhåÉò#‹wå÷Å*NXâYFŒw¸í°ìYÓ$‘ޝä>ï)ñˆTc®jARcðù2æÛ )6(“6 |^yú¶- ¸©’ïzï}Ä/tŒªà)ÛI6Ã)2Ù÷ä¢bˆÓ]4LoúðY`sÔ á1µM9¡À1Àt Pè|¤L‰l ÁQ¥áùn ±üÆx. p…za÷šŒQžZÂ[Ëþø›c ï†Ù¬íhµ¡Áÿ5„x½X2ô'‡ò…ÀýØQElÈl¸ûC¹S1.JäÉÑ[¶Æ?”S:owÇcÊ&H°ïs›žŸeVóeeR32â…䲓œãjëI͵Î’€€¿ äw`í|©-Û§{\z&ëµ}É{_‡Ø@\ÙS.Á{ 5âmúß 7?+´LjÛ3®CyB'ýð}ð=»(ÄÒCŒĵ†Úî…wÒú«Y[IpOæ¯Ê©†ïÆs¤‡yÄñÄÐÂmîÉV„”*½àšü`,ºúñ‘üA˜_éïÉ¿°®ÐÆ·c¬ï&P†`¾ GØ–ýíËVÙ_¶q õÜ"é-Ó_Œ¿n˜µ wäkóȧ0•òkp§K Y'o×àSÌ|ËИ@yj« å¬ÿ†7SêbÄÂ÷½<õR©erb?ƒì/B• •>Ç"¡¤@ÝÜbeµ´ý„芰ZnÏ"÷ì%<¤ Mâ›ù|/B_2‰ì¿„‹û_"Z9J„jl³áæ)Eš+2Žhzj˜QÂõÖ}S¼·ƒÆ)/®ÛÄkYjPÚ\³`LÊÝÚÓ —^‹Úi"LúrsE8¡75ÄÞN™á\Ýþf• ˆjŒ¨ìmÒÞA¼£Î&O6#±FÍ7ƒRŽ/hM)öy3î§QºOYÖʳ¨ð¤Ûº¢œÇQÝWκÖb¦ \ô¶ú§;SÄÅyô€Â±²IÉ÷’—Ãmr€^Æ>9¼Çãsâ= ZØÔaϦTÁxõG ÕÞØXüaæt³Ì)‰hU÷A&»ä éUhfãç>¥>“³÷€wI°gÂèëê‚z0`ôX:Mß¿mE6£Î-‰²ñŒ³!@-wÎ…˜‘›²¿ ø†ìо —Öý(TóîD<i;Ä·Nü§§mêǛ֗ž\Úd”%Ožá@] ‘+¿›wh_Y½•-yúü>¿§³Ø²1†Ð}22øØ?Õ,DGÙ rjo©ÇFß§nc•í4×@³òG?ÁK^ê³Àiø}KÝ.—Ù<¾ã-‰•T®JõŽyEPEEï>4 (œÓ¦iý V‡Ä~üpû¬Õ§1÷@@Èì§tUÍû?9 éσÅ9h]Ñ¡ `µ¥R@î¡Êú n鹉 å×\¢5éU2dc÷ã6ƒF«1t]§PÑ”à”” ¶Ú☈ºj™˜ Âx]p# ›hÆ¿ÓF=·GK¹^1QêÉú š$³Þ€[Q³I—¢²ÄŽ™(údÙm2™0éêøÓ–ºÝ­h¯M”ÊTI¨ÌЊwµoŠ\If>™¨ZÒÚe"¦Dy÷ãÆÊñe*rTLF²+}/°»û3pF‰åJˆ|dxÉÅ•eaö…ì&c’ÏÆ<€ÿùݸ¹]ÄëK€ä(ï°<îë‡h$˜EÚ5§¢ˆß Ÿ*Žç²Ë<å@õá‰xŠ2ÕV¦#„ÉÉØvÜ®¸ºv9>GàfG’¢†….P˜ûS@ýòuúA¯À›vç§ÀTù˜q•Xf!œñ>Ú‚áI"ÕbÊEG_}žÖŠÓÇ$ž® QL”’€€ºUŸè‹ŒDh_™ýPii£ÂêŽÉÒ¹õFRSóµEsu„R gcxÁKû]7?‚2ßTVx€ÜjxŽP߬þå1ÒŸ¼TKù¼¨/«šÄ´ñ;&³ùBð½»0ú'ØDmtUzyPðöðþ²,Ï%ªHÛŽP÷}›Ë[퇛|2^qçRÕÍ@‹-Î åÌ(ÍbrŒJ¡ì&0z²%6–ê¡´üuaDô´AËí>ß`Ñío&ª’ÚªMöÙòGfeuôØKË`®(ÆÐ%ÀBàVÔ•vͳ|°!וxr[ XpY¸ e ÕD¶§Õ$ šló<ŠcEK1@Êd ç¸_•T¾ž+V¼#ƒæknó ƒ÷/øÛÌõøf²è Ù3g€1ã*ìÔX7÷¼‘vnLdûøô/’.ئ!Ó5¥æ’hŠè’5y&@pr+Â1f˜qßÓžC/b„w#ï.o+Þ£ÖFŒ—'r¹0œiG Ô§÷8¤9ЪÑzA'þãìòµó¥ŒKˆ¼¹ŠH¸}G¼>œH»€ÜécÛºb0—Ç ÊÑ¿P)NJõ$¢ô¸ÌuÍH îAöA(¶.ÔÀ“Pyœd…ËÚ8,!48f(ІÜüêCäÄpÎOiÈ)^… Q߉çbfV¢?vÈfl5Fᓈ¬DâÌœžCE¼ÊÝ‚”e6IòbÁO–½8”Ç¢<±×a®A¶m¶uÛñ¦¶–SþØO…ÆCà'hð¤úv¾ñâQ°ïW àó€j}k àä*·Ë×üpñ*KóŒ´ö!óT³óùýhÛ°l&Î; 1Õd¥ÈâÒ´%J–7N›«ãa™0ð77Vtì¤:ï¥UíÉC·8­•qVù!B3 V ×jVÂzsÕ"¡T”3cûŽ¥'ÅZ33¹j”ͦ}³fšpE|9dº=cÛN½ûýê=þRX&”»£.*”7š K†A®¤}]œI?øcŸo›eÃù 䳪'›êž®5ZÏta.cqB_×_½î„j8Q {ðñîÚ$ \! ãü‰âÈÚ@,ZTH`—Lª¿xlqú‰„[ÀÕó»H¨Mp"cåƒÓÃkNÆWíÁ»*"mËkšFnàþâÏâfQV=xÄ÷ ’€€æ"¹ÖfÂ>Õ¾™mI@e‡Q÷9t•ò©T˜ïó0&­:”-¥‘Ne¥+}+«ñÑfç¶é¸,¼ÍYÞ¾_¾]àwb©'`Q«ÿh3?¥ºfxIÜc5\Zþû’ÀýÀ«¹w4ÑšK¢Lþ­…líë#Ž:D3Š©õ{¼=\²á?¯œmaGYü ^Ì2[t¨ˆ‰­ G‰QpHi1¹oÊM‡àáÍt] À¯ª¹o¸\ÈŠ- cUqR·y«p¸îóõU„ÿžÔ’kä·ù A~_P-)N:[tÔIŒÑ°–þ±p³Â?6.¸ ^”9)@’ -ÿ‚—~öÍ£i§Õ,Q¨s,%grºRS„Š,ó΀ÐÍÿüœ¢[ÙúeK›(#¥±T òª@QÜçÌ‹÷F­ߨÄ>TA2Ý@£æ+9B+¨-LE¶ ¤‡H½fmŒó\xJ™»XÎÃÍ(À­a’m|TƒáÌM:ÄÑ‹Âv±½3¡T£ž "l1žÌ¦›QôS¬Šó«k°TËâ¹fúÏÀ·áMÑÂK˜ >r=q«¹%ÊÛˆuQw`5¾-_£kĨ÷b„Í—˜ùÖlü¢©jôÃ3b¦<¬X9mU5µf‘¡ÉcÕ3-ÀÐr‰ˆv4¤fi/סùÈbï{Ît)gü)¨TSR.‘Dÿr¯èÉPÌÞ°kZ¼Í›ÀH=ë%œ †¼AÅx1N=f˜Cáí^ÈtÖáÄcLK¢qPˆ(UÕ`Ml{ Ì!X”Ä$éÁ^éMÔ¥ÄÓkŒW–ðÈHûÔx3D‰Î0¿Ý”[·ù1sᕌÚëÝ%òÄ Ð¥b-œ 3²ª ®(@yýí[^½Akï¶ó‹ðÍH+Ì”“– ,ç5‡`‡ÉžÚ2ªç"8\ZÚV ŸçÂ_HnD¢ïÍýÿë“kƨ…ºexCu°Ím§°þ}Æt‹ÙÊŽýßó¬#×ôI‹Éo<§vQ}×]lÙþ%—-´õÌ6ÈÚùd+>ÏhJc|#w¨¿óý‚2`UÛ«¡‰`•µ$øzå½ÜíØrÄ7ÕÈáå}X°NÀl« Ë2¸’ç¿x–:r(ƒ‘¯(¿À *öóyaùu¾f[žÇÇÝ=4š¶"ƒº·$ÆgÈ’€€¯0á «ëª%¨I3ÇËŠå3xÖE)¹3RE1ówaz³çk‘j]öJ6ZyÈOdÛ±%ITgé§Î»Y2¯›­ÍWö½‘¿9²…©Â¿0a¡Œ£¨™ƒÞ0Ñb•†„÷ ©Ü±x¿±µŒ!Èš\(9=Þ©ÙºEZ9>}Á™pÏöØßÆlçÂÂÄeyB}âÆ^áF}¬ÜÀ 1aéQM+TsÖýzñ„ޤÙI€Zý’ÕîÛ~©Þð>ÄèõÉÜëÿ­6R]‡HñÜ¢5vm?M8ŒˆÖiFâ[ r5TÐYáÍŸN½Ïï¤È»+ÿ4$Z¦ ~½¸‘áJ3»öm€áˆi,½«f‹ª™I¢ŸÀÊ«8x«gž-Ë«‹@TCäü<ò¤wÎ9æ*Íž%ó¶—q¥»4q4RËסW?|ñ0 WŠ‹„ø9 ¹^Ó+M€ ð˜Ôs[=¹†ÙŸ¥ôÐlЗT Êu—‹ ¨Yw¹„JôwÇ?†üÛOÖåÿ‹ Åît'‘Œ÷¸837»&z9kâƒÝ¿¿xhyûL 5Q’GÁFDPA#©Žïÿžn­‡¢;þR$_>ˆ½GŸjt·±e8Ü´9éd+gh”KˆŒ¨2Çu­;üy£¨sù Šç '>Y8+^Ж$R§ùqèÙt³/ȹG«¦«¤iZBYöد(Ñ6bmÜ Ê2G´Á*üݘ"uùåñ­‘í$žt(¬äSD˜—!Š_Пæî¹AƒZsÌΰH¦‹Ð%`Ý)Ñ ^˜ö•`O }š-iL{±k…HñL¹¿(ç2û2öXe” àªó§À›âfFÿÍÔbÔá–†N®dwàW*nêÔ産?zbëëÝ×\•Ñ$¯s¤KeÀEQilÚýp>.ž=~Fù—h=aŒ×ä“BÕ¿¼Ù…kdk™‰9ݧþî£L`só©t Ò“pmKõÝÁYEÁž|ô h¾wçDüݽ¤â¾‰[ßm´Üœ­bb_È6#!7œ8íâ×Ͻlô6\³>i¹Üžm_~+˜ó¢q’ˆœ0.~X”Ÿ7’Õ‹{‹üèĉTOäœ ' `·· ’U[ÄI‡£W—¡¥†“¦«R ï­y†“<Ôƒ‹€ûE’0¨( ’€€ÛõõP%bú:½=»öÀY4Á ›èƒH éÔühwžl4Ö²Û*c)`ÐHÈ3ÀÀbŠÙŽÂd$´‡$h€|w8@5ÎB†×âB“ Âd.™&ê~"`LpB0ð‘“"2!:¬“ìÎr*ÐüÒÈë¹t³aÝ~ìLŠŽC• XJŠõ—'ÅdÑ[•¬ûW™-•cÒ×~ýœ¨Í®õ6̆ƼÒfó7Ï€üÜ3hC?o¦ÝáÇ›‚ÖnR¬øŽM‡ÛIuál—b;€ñüŒºÊíH±[,I$ ç nñp᫲ÑIÝCsL솘2Ö ’½`ÃÐè»ðÎBóC¹±¡ðìÇù’døªÅ߃Œ}µh•´åK°£-„Q²šûºùРœÍ®”dz&fÍÑÛ×1ws´o„0ãl`Áâ@Ò§ æ800Âê½ïÈ"O!£_ý×°CwSP&á{’E¿Ê¨Ë]žæÜŸ¯ h´åhöù.Cɹ%]ìëaÅøþIGþt§P]€ãåqþ¨a.b²ˆQ¤ëLB½j¾ŒKlúp½? ‹Â±§n«8¯çYl$˜³§ƒpí_¥!sçØKÎk ¬Þ„àăhƒhÍ È˜>äYÔŠ‚’<íЪŽñ™}žåv{XMW(/iʸćOyî”·ÎluQŒ8vîÌa"Ýðçüáa"à@!fÔ׋>[O|5OöЯÛÞ…„&¥ÌÉÇõÜnn¤äŒþ“%‚ì²ó1âX¼?Í#|¾ ÕÚtÂ"Šg¶ª—Mfkž„D]EË ~°7\R>õ•á݀̓¨Ÿèˆu 0l3õZЄÕøê|Ä¿™Å Âò¨Ná·²Àkט>‰°å Æ2“N&\ulNÆ:u7ˆ áyø¦Îþ¶±æÒ–v,ÂU‡±[4 ¿«Þ“PÁÙCñ#3JFë·K»à‰>é†W›JœÅ²#—RÙ T‹Ü“#Ú—ýá&¾/¸:ÍÕÊ»LOàKÄÇ.GDNí88mdÕpŽrÄKÕücd†×kC¼×:‘ã3Oq •K¾1¦‡}v¬Ä×ãçῃÌÅe+•­¡õtŠ¥ÈzU¦®E;›ÏÓtÂ55¦gœ´3÷—fcGép`´ó‹R@ïcú^ìM+ßn¿¨@´y7ñ,½sÄðnRÇNëšó£,ª±.ÿæÄÅS/.õŸÂà¨T™–PÖƒÅH¡p–èß|¡.¨‚'Ç âK ²—2aÒ eïj'¦ÔOÿ]tò.»ŠtöÏUñ¶/Åtµ!D¼äûLúD0ËVGV T/u',=â–e¥¨î®à}¿§Ð¡Ìß) ÞÔ&«ÇgS CãYàSC2üm:R5„×7˜¥~²d×$ïí&E†ou-»ýÊ1ÓÃéZU;“ `­õhHógÑ•¨yô¡®7 nÇ4kø½(dÊž¤o¦ -ee’ÍAê‹ *¨wௌ’€€Ð¨hRª­J:Ãà qhyÍŠQÏ‘qÎñ+Ζ>Äj sÛ¶÷âOP÷@N ï¹7¬ï=¾Ê~Àƒãœþç$+KI0Y|>!|IuEDhAàÿžéÜ(~˜á"l*àé4"ïŸ0Ϙ@r‡x((}’Õ¹š+)µ–ê÷äß-æ|lÿ3á1YG&± )Ã,;Ó‘< ¼e,ú4Pëê ã©Ô7úKKJÈæ’}c‘¿.kú±tð¹‚9Ïá'3,è+õ© Ž ±@©ÑÅ/Å“på+ì`¿!^VÂ7l >6»< ÔëÎ}¥EO¾J+ f‡„ÄÆ%¨µ.÷ÀV¥<”•îkÄÒÞÌËŃG]—o„Dž%Ç56õÀH+ýS„fávŽ«BèÇF¯í@ó /±–M“ý”,1ÿÏ?Km†¿]8Ú»m7ZW(vvj5´L¯1ú³ï¹ÁçÏ%°Ê\¯vúÕԩ𮊎ÕnýÝ鉚–=7 óB?ž÷þ†{ö‚¿à›êlè“ qޝÀj­â‘I6®ÒŒ>‘O*R•DêîñÚXÒb9:éž›”NÜBý€ä ‰ e¨Ëí1K‡/á!ºñª+’ÅÑWIâ-HcB~äÃâx*F g0ØlîoÜéP0Ûot‰TH1íò£ ³æŧÒGr…#¢ù‡e&)R¼ìá¬A¿4|Æ- ¶ëW#]'Ù$¥õNhŠ*ÁÔý† ]!؇Þ6=98ŸÄõÑx‘†ñ~Ð" bV{OâH¯†ÂK.Ó-„›­â4z%ôå’2¢Ì^mhÅž ‹úf©¶ååÜ"µACróîA•ÿÿ¥áw¹x1þs#8< "¯ŽBÉ/l ´{Tþ­ k[(ÿÓDt„ºI?àJÝü´¾Üæ²þwQ+}8oªy ké“È„¥ùQí]ò]Kæ¨su½Xƒ°~v‡u5åÕc3ì Kጜl–F3÷”QÈ‘œzÿ0@Á?ÛÒC'ͲÀ)ÿQYäkV¢ê;¿«°°È1÷–õ»Æ¼ÿf?×õÚæ’ö°Û š‰ßï’ÏCÆZo¸YN4%«Ÿ<ÎUÐ%P ƒXJ‡Y,#‹–£LæÂ®NäÌŠ€P;ÔuÔùüVAEk;µi9’€€¯’ð1xî ò-(EË¥gû5µ˜_ø¶ïè~Lj_/ õcÐÚŸZÒDŽôÝ»î~`Ž/J‘,[6{]µ§?méOfá e0F†œ»‰D»[ìk&^'Ì8!‹êÜG]µ ¤­ç|§’«îBØëˆr&©ÖÙŠïF+—y«\4^×Ût‘ðÀ` ©¼±’ \ÊŠK½¬ )³†¦ !­¡‘Ùý Aˆ+àrR\8t]÷û–³Lr.G½²©§ÁÆóäC½IV°1û– _¸7x!irS¼ÉGvu|H“µ…þÀR©K˽¢b¸Ôzߨu1©\÷P™4‰/ÛÅ „§7æãÝÖE¶ëQRÿ•”Ú黓H—Í‘QêÚ˜ïm~ȽòB]¯Ñ¸JX‘à*ñëFt¢š^¸j/<Ã+xÇ~—t¯ãbLNª¸öoè9¥Ð­“ôðA2¡Fá¡Ï¥˜<–9—ÜÁ7ÐCZ¯šñ€–@ü¤9UªKòúÂWE1DªX¿îl4}ø8¡q4uš„edŸ´:0ÈÁÙ®$aˆaþÖö\ŽîÒ•M7oÔÉJòܯVŠè“ÓfŸ”oºŠæ÷}Jîù³¦ð»5†ˆGC.1‰E¼&f³ïd»«â¹}Œ°JXÒnÁÞ{<ŸÙIÄÀ@ó*˜WZ΢ÜyùSÖ-KD”%øN7‹\¯ÑGźÙsæÿ— A€s*ùiûRBKa$€Ñ+âEã—³n©¬ ùšÿÀ¦õKöœßo½˜9ßçK±óÇÏ4,c™ÐVϲ8CMæ‘ê-Ф>£@ÓÀÝCÌgÊŽTÄõsæ<Ýxåò™Ò fi‘%P´ÁLìÈÕÉîºÍFJ$õT`‚¦«”áŠÍkpXɃp·âjŽe–öm÷>'š|¶WšÇ”Kh„*Àߥx¼»¿(o§uXB¬ùõ|F‹:-'F=r( “¨ÒŠœÅmæËßöÊhH©ßV,WcHŸ>è*ËŽ™Þ?q%•’¬Ð|õ—‹€²ß¸*¤nXÞXŠ 2qB •!8d…ïRŹä­1Ųó-Szñ‡¶9è¤Ý"X¼ÅÆû j£ €Mɼ…®Å<%;žáƒ=~*VkP†Âæ—âÚZÚ‘O5’þ¹c—Š‘*l Ϋn¹æž³Ra€ÃZ¡ãk6 Òªtl€M“F×) ÔãÝdfl-Cyìî›y:ñV©M”»À”ˆòK>Û_£µegÖúÆ€PÇßô|Îq´Î ›€j"|‡Œá.6»‘÷¾[C p‰Læ]ä’jÀ€L`³°ÄÒÅŸu»·=Ò¶'{beïkÒÁy3ª—ºÄ3z|à5óùy£ÕŽò‰Ù±Vѳˆ+æÜp®\9±T 'Å.{˜_­Gê”óµ×ì°"•„Dö„˜öæ©ß,¬º÷÷=%Õ#¢f] 07J¿™³§b7ûdN§?ïÏõÌÏ_ ÇÆãC~2=á«BüeŸYö‚±?×8عÚ~­¢Õ™òg&Ö`|ûL‰K0å²e€C9¢ûø£Ç)äQ‹¦Í²Õ©»Ó±eAè:¢Ö ÏÀç0Ì’:_¦c#Žâ·ÒËŸ!¥Ó¸©÷_ÖŽuçO€[/i@”(~Ñ©áüõˆ,h^ìk' [Í<ªKèž-qà –¾ )E¾ãÙÚWƒAÙÖÍEªBxõ¦¼äry]íS]ë b$´‰š>"8‘¥ ëŽ@±ç2Éðôu6Am¸³;±.¡Ç‡J]‘,±”2ÿ‹1F[YªºJr\F…\=B°)XO.:V_—iÖêåc>¹%É‚ƒu/}Ä—Æ(ݽ|õžÄÛVNYqhIöîî+¹6d4sÉÛ6üŒ8œeªlUðjØ’ój¡Ý¡®Ö}Fhšëµ1T *$Ž~sZÓ‚%s~b Dÿ.ˆ„ó·ŸpZãN:¤úÇu[Ô¨ÍÛ~Qz$nþ7„6»3Ò ¶0Ôî’€€¤À<|Ê’4òZ„¨øAìŸÆRËBRÐölÓ– …þ:‘‡ˆcÌ£ª ?fþcÉŒ’á,GÅ`ìoúH>£¦üåJqkn£ð‘ΧÐåç2m‹âéÿ)¾.²¦óp+ð¿»gâ?³¡kßú„)ÇÛ–²{­ü[BóüæO8]§H(žQeÓè0|gË‚°Ìñƾ)h´ö#±˜t¡¦ åŸZù<ºñ¼‘Û„tù8oªÞx )ÖGZ°ý”Í(·J6$/ÊöJ±EÎÁõ>Žø¢>änf®RÔ˜I`J‹³ ®Þ(`åŽî¸ëRY8´l`P!“ Ð>°‚‘<ÖpD—Á†ƒ»ï,ôW}¹k4ޤ¯7TFÍ={"4ʱ†ÒäW©˜áñ´MiHÊTÚÖ6—¦HÔ­R-U|ñ¨ó>ïwT_v¦Á&mÑŽ•eØ?b±_xUKyø„ÿ¬}àÐK ÉYúÊÅÚ:=ØÄðM)_h”kcU$ÿûþb%ö—á>¡û{†:ÆFn½±Ð'@lÐõee™6M mmYÙpÒH湘¨£ÚlŒ[†¨}®a‡©:ô¢šÒŘ/ß^‡½Û*˜ê„M8õ+œWÙò»Ã”iœÖú1»A‚g#äuŒÜ‹ ÏqJ ›ÊrðLóÜ–´Þ¿¿òè—UŒwÕ'ºiÎЛˆ$8¼{ëötGp "ngFöÞÏ”&hÆ8)ÔÆ‹¥kDµZƒ…±çRé´M—y¹Â;h`­ýiEÃí÷zsîŸorïÄŽ -bºëyIŒ¢»Ø÷ÍÖÚàä]`Hy½ê–øƒ÷’{u^ÉFß ³GÅÞqÖ ð TÈ{Ô<šÏÚŸ]\»àËLOÜ]ÊÎ:9I¨?]ÔâŸ~sÞpPLùÖêÓ¶ú8¡G˜å÷€×uzÇtiƒTU‹áï¼{Ä#L,‚¦Î8MÐ5›jS—«VÜFn>< ƒ“6|î߿՟„­¶ ¾é®0ä1¿0•)–%P æÖ á|^y,c Ñ -ìô›"Þ¦EO»fEöÿ}ëí‘x•åœDÅcC‡h8|‘<ÿ°Ó»Do ºkû½¸½p gùM’™“ú¨×K :.–Ôì¿”ÎVEj 8Âq=Õ9j²Óc¶]x«áéç4=ïnòK°]ñWÔ›?1I Œ}‘•'³c;¡{ëíÇÒ5{sÿšÔcí=»ýŸØÓ˜Þ»Æ7™ücr§Û9”RM­•8ÈrÖ˜¡Çfoùo¦—_}‚>1U4ÁÀoKÌóSñƒBñCÀ±'—“›˜©z}*Fº9ÒÌ//£,ͤà­zûFΛ–^“œ{ »ž\“ôˆù\ (›=À¹Ä´8b:9…ª¦˜_>!¬xUOoÄ™Ï=ĘÔÑ_ ÞÐtiš¬Àæšò>DuVùÖ/JpñNj(C¡Å+ös,Å ê$zåFÖú¤˜‡qXoõŠLa]zU™ªyËI r0xêžÐŽÑ¦Äň–ÙƒW”}mà 4Ìñ;üæv PŸ”•LºtLúxߘ$ßÞÉš[9Y‘„#¯ZB¤ÿG°Z ?°ºx _@I‰Ñru_¿î]Pn7›R]O9Qh³Š¦Ñø)’¹ãŠ÷£E5n‘Ë´Íl€et¾îOÇ´àÕbàüm/½~Z÷Ô^Ð5ÊUG€¥@wõ{"õÙ]ü †*çÚl#ûK¤ø'ïŒ-{{uöùnËæçˆf÷‡Òا;n+Ø™½`%Öè·ù&’€€ÇÃ'[PäõËø÷Ås|WoîTÃk1…s•«DhŠ¢AË£—ÙX>%Jõ`‰dì/®8gh®%“ˆ ¥x¬2ÇBà÷!ž v@˜NŸ¬½æÃƒ|+O‡éP#§8òpFi£ØØÍ‰CÍÞž¸-*›U‹^< PóÆ ©£} 2ï©ÓA7Óǵ÷;Ê¡kJ§DÏž´ voi!øÈ2“Õ"U^ÔñVl»î-LWï;¿“ÌvW¡WX¢¶ÐøˆeÆkÂ*’Çq~ŠDs\Ü-KÁèÙÔ‚'ÜJ¡PŒê‰ (nˆŒ hñoê]ÆÎQÕª- AÈ})~©¶c·µ %;ç_èä(w޳¥ÑçJÎyËšÐqÓf@4P½°MJè~ò{À@_¦ˆ†§•´ƒÎ*”å.˜‹+´ËÙ,·…èZrþ‚ÒrLÉè= å/p½lÞJ¯IÂ|ïY|fs^…ôas ÐÃCÂ&Ê–ü…+îË[ÕÌX²f:{~ç Îz¢(‡ÓÆAµbþ3Kb21¢J _Ò†ó7E–kX§ÑGb…ÙtÔc—F²umØÔ*'v Õó(J=åu"ËÌW¢yô+pÌJ4σ[[m„‡ñw€%4e´ûªüâå‚¡"ßç†@‚Õ“ nÑ5Ø©e$F¡œvÚ»rQŠùþØTj^âoÔk¶Â¯>À¾R™fg}œ, IÐ0&ôhµ¾e5>ü ?Ìã±"'ׂZg¯Åb¥(ƒXS#+–ºË˜­1[)‰4O ÏÝ„SuM ´#탽s›¤ìq²û¾ ah” Q’´ê 9îæ}HU;²Ö>ßȪêÏZtK®€ Ù¼&Ö,vCpψ7–D «RdÐkª¢QŽ!ë§Ü@3y<ÐIò»¯‘®ô1^ Ó(ž"†+îl‘¾¯ëâCH´¼^ÃÝjl]óûâPùúK‰ŠÙd‘œúîé2â3®ÆÁøj6†:åkz1Êzï’?!Å]Elyâ¡Eù¯“ú¾yµÊ€w_–± `.Àz¢¨3†‹‚.è=_T×I.lNJ‹ÚׄK÷4¨¨éu°mºB e‘KîhUW1Óuej'Tñ¿žéu…ÈW®ï]÷ßC€ §{æ×9ÍE ¦b‘}¡îf?£ xØ6QÍÍpu÷•oGÐ¥ØJÇQãû›‘›lGr<ŸÀPzÛ¸}-‹t¼þnç~p›me0ßùôø?´kí!ÚñÄ®¬·ÅmñåÞ§éøÄÂ÷ÜûÀ'Ïô­F­^£óõ½ "Ó &«º ]ŒöùÚ’yûÏìuÅÏ&¸kÆ·~Ãb¨á[_+­F~Ã_,Æ—Ÿ¦O6F¬¾Ö*óúÄhù¢ºÆ/:,à5ù R}¸Áü¬r¹£5f¥ï(!æHMìÂ’&l|Ê­„(dŸ˜‡C®ºWÔ—C Cç\@-!°îHªC îÛKY&ÚJŠý§]ëf`b{¬™‹}Ýš$8ä E'}˜Ž8 vÁ³0Ä•L‘œÍÜ«ö4ùU°¢£¾flQÀ›cúÍáû¸V ¿ÔtUá@tœ‚Õ– =ëy]õêòŸ{ºF'Ò ßÔJ¶ŠQÀËDÍ¿?, vÖ_ ‰"§º·ZQa5•‚|€‚©?ÅóïÆBB7á¶¿ -‰«Ÿí‡í8¯s@İx´£ÖöwèLˆ](Í¡f­ìÝûÌ„µçñö>´ ªFâR9¥3SrÝþ`ùœ®(fDe°Î°8I0jçúž6Ѷ K;AçàÒóïäÛn"º3qÅ $~Ùmì(¦àȾ$¦$$‚ç„n™ûŸù2âÏ8¦{˜¦D6Fï7ÃÇRyûm{Œ<>þ†ê2ˆ™ŽAðþÍ3iöœ8¡Ï7AY¸Ù¦8Ÿ8”˜ú#hí—·õΠ k‰ÿÝèkcƒéBnwÞâ dµU{ ó°yF‡Äª\*æ¯ê¦1>r@s“õ‘7\Œz8H€Çógñ€G‚ÉÊ2 ÖÈŒ`üñûÀ”Ii ‰"N'Jͧ@lœ‹â’€€Þ„c½6&&˜ç Ö0¾þÕLjç¼õ¹¦?•XY³3q]P«¯È@mo˜ÔÑúä‹Hh íNÛБ·×j]`ЇýCõ;Fó÷Iž”¨‘œíó¿ÙñµÑ:]bÄø´ÿ£ÖMGɪ+ ûŽöŒ Ù]ŽPÆÄˬ0ÝéR+kXûg\*ýÜ”/“”Wpÿ‚ öççÈþä,«,ZÉòN ¥.2Š#ê§,+üi(›uŽøÚ9}f ïrç+sφ‹Ì/zÆ 0À_þÙ®‚5m¸o¦M°ªáÄ­ÑOßí88¯› nQ!MÑ‚=3âO k˜qƒD J÷P'ËÄœpuèÑ­ßüÜ®+C†ÖPQºj5°ïRntBnhÛqW:\f@›…MT6¹ío)Zàô™ôä/{Puñ æà ¼D$ÿ¥^OS.ü’è ëŽÜÇíß¼Âx¯>=)SÕTÉíüX”a‘ìÆ=Ç¡ ˜ê:§oÞÖ¨>Lƒž{†{¹6ÅñyBV³Œ!b¦g[ªZ<Ð{¹Ì©þ™­‡”pÒ£QK[oàèŸçõ^’J¥_øp»ÞÝÇ¥¦S¶Ó™#®ôÄ•è™z(èp‘0”ÝGúœ‡èU—•Æạâ\>A!ãy!˜Yþ„¡ì¥2ˆqˆ‘(Xf¥"âf¦YªYÆkhT–djºÓï“ ˆÝKiÝ57šñÜüŒ»½_vsô/]î- Î^²6xªw|,‹+·?:{õôë65gNf³ Ôb+ãôSx¾ôœýRP´Ø>ã‡vøˆTÀ¬σT¢Þ9ßЗ‘½Ú€zðø1û¶6 º/óMwL!šê03û /Gë|a`7§&“â{ ¥äöxwʬ¾Ì#­§¥ƒŠ=ªzž¾wΜ«óP—žf ïc+Êàaé?ÖÖË:)n„(IeE•µƒx*%8½]<³c±j&‘Y3Çco°ëÀ˜Ãˆ„¡Øù‹ˆ¬}݈yNF6 ¶¨ÖÝ|aÍÕùgáòÔBJvüÞhV”'¹Öa$:ü4RjISû˜ƒ@†PÁî= ëÔ’€€§4 ÿm›ôÁSÉ®Ehôü »’á>·}¿£UL–A¬áÑÂHÎà’ØŒL¼é1¨'¶pã¹–SÕ$ØnÅÚ‡Na÷ $û¾áìë׋°WwçÒ]­Ó¢ U{;E^ŠX’bgˆî]"ÖÚ« UtÆ'ž·’4nwxº;àÿÊHkú‹p;wŠÃÜTƾOkIˆ 8“i¬#,p#¼›Äˆ¬`«q'xˆgÚŒ•&ЧÖá•§¥‚DpÌ€®g¬ôèWD (¶|º‹†ïÀma„}…ÌöC·Ê¤z/›ŽøïØål“k€™T²zÌäëªêtÔF˜ë‰ïƒËmUL%¡Âié³fh·Þ3]E_ùd­¥qºÜâ;Q]åRº¯u¡¢òHr¼‡íAÅAØ`žØ¦´ª‰ ¾Ì«úmœ‡mPêd¢ùâíœ?œÐ÷Å>þ_™°<ÍÉ"4ãûÔ1œ˜Lñ_6BCÖa§W±3Âïûs P@³ÄbC³ý;.YÃÛ¢¼‹àí;6©Êù}t÷]þù¨ ã4îÕ|•cØðÞëÅÒ9b5¾id eåE°›çïù‡^X$ûÕFtCøq¾&º—(¨n9èÌùÙ1¶–?7xC¼"gÁb«“Œt†G±à$‘ŽdÅ~ù-l}šÙ~w×` *`=Çu~MK@Ðj•²Cû@y.T”ä*ÐØ%¡ÂLƒé³³þ%‘è i¢5 ?1MuŸ ¹Ï޵ƒ…êT…œPVŠ‚¼Ù¥Ø]³fÞS/»_,üÒ:i ë6”†P¨ÊÅÅ­|óîwOd7‚e.*¬ãD†ƒ‘\{œPY:ÜζJR°JPP V±ÿó\L¿{yѰÛàøòÖ,ð’€€Êúo[ ]Z„ãG ‰æè­a¤*úÄ 6 œRè’õ]ð tÊGf]ê)`UvNÅ ¬ C˜øèëw«DÆS‚Zougwû_#„þˆ¨Æqª d 9-K ȸÿ ÁâzŒÍR¯pžªÀ‹©™&šÓp?_Ù[e{Çe%w7‹é×ó›*èR|Eòÿ½M¸‹¥Ü!мñ$¥áºr£à r¨Ð?ÛHÞ^—çÈÐò*äj¢Ëxb×½4Š~ÀoÀ¹¿„ù•Éí  °óÛ‚(*Ï<ãwÔÞR¸5ïá××¥ëõŽÕÕÑXl¿ªj(=´»íZûdMïNÛIá ´‹,=PåŠækûFô¿ªPsñ5ˆLÒæ³bË!ß¹²€©Ü탪 »¯™½L$ÜŸ­6D×¹¤RË—ÕÕBûY,‡ªóŒé`S%.‹æ,¡Ýš©>™ù̺™/­­» ä$x=y·©óH Æò®?è0’D“KJ(U?#ŠæÀC:ĆŠ6F¬æ!â“rX Žàs\fàÁåtÜû†²…ìf"Ïã2~ö~Zdlô)Ñ,YkÙ,»w"nõ7èÜRë4¨xÌLõ|W4ŠV€aãWYU—!Üi¯“ûš›»uÛÌŠus±g¸Fàɦ~)ePçZ§g”c“óŠøùü°¶N¯„;°„”¯ü³èä~ï>wËãD®T-qÍ}­"ØÑ¨€Ú± wAÎf±xK„öÁì©¢œÉ…,œáú‹}UŽ æû¨Û¢«³¾þÏ'×Îssª|’SÀgû„ "¹×ÒIŸ Á[ò»Vl‰õ‚—?D.”‚éñºúÔøyRLù1ÖŽZ/™F«3J.‰¬næ‡ UÀêÌ"j’Ë?CY[Náaÿ¯’€€7¢{2#EI%Û$â(œì¹Ã©†È’…¸l÷K† 64°ýƒÌ¬ ;ƒŽLß0Ü%„Q^lÛãCQh°YÛ“3Á7 ðPâh"щn,¯ÈMžYC#+×­]õ ýÜ¥T Ý½%=·œ¾s¶êÀÒVD!ýÜtÍŸì%Là´¤™PmxEC²§Ž$Œä‡ HïÑÝÅ7êŸÈßS!öJUt*h½÷ ÷†fº Ö)(Q±·Ö&E§Uéü\ÏQà÷+Qpk‘éZëÔÄ[ö}bƒ£JRÐþÁøƒW’P´@¨ÿìjfQLþ "ì‡:å¼SÝ”šØ°” gt÷MMª÷µ¦sˆROŒšµGq[ñ~×à=“2oGä^|1¥3èÞ»òºÒV ÿ l(ÉX¸Íþ×Ú8.¶Â>RÄ 'CÿoÑQÏÔe˜ë’ÙZj½1Ùv Jó§Á1g÷¯}M<$:êÒ!å¥B%Ô¡Yíé x/†¤ßd‰L†Ùm§òV­™ÉÄŽ&½¶6{)€á’¦í®»ßá§›œ¶gtXÝ"Ù?MÕy·Ð†àµFãI }‘õ‹ïü^·'‰0O½Í}ýøâëLd'Ùn-w'¢,©»¬ì­›¥c-ÈKö²B»øå¹²Lö¨oœ8ôª´Ÿ©Êñ•µÍ6°boè.ÁËìüÚÃgó=Û(¿­kÿ*ÊÂÄe'Ó!€x#dLÊð{c‹!i­:Çp¾éKËphÝÄ|º-5k(º Vˆ@#¸­Ø˜ƒ6¨ß?hßNšÈÿ­ä`-åý‹DÖV¶ð+î&±%tæ"? p²}Uá'›ï)8•6Õ~X­iѺ¢/iÓ©Ê´ )˜°³þµq^ælð˜tÒ:úÙò’€€Ãç_§‰Õ*”Õ‚‰ôaûãWÉ"çmcWèúf š³ N;¬ýœ]Ì5;Àø r1Gàêªáh÷ ¥\ú\ìÏ ç°æÀ!ÅKòFpÛæªíýáyŸæ|Ýu¡¹¯6‹ÆT¶)©¬XáFψ+(˜Ÿ*JÀÑøE¼¯5€9^é2¶±ó´#(øIE³‹‰6røIHö [ð¬2úï4Q•ŸîLÜé{»ø¹âÔŽžHOTáÜkédˆSA€–6ËEÖBR=…ÉU°3szQÌRqǵPZÀ[ ÔWè¯Ø²3ÍÄß÷¶ëÈašÃ:Ö>|¬ØõVÊÅ¢„tq.©Í ½Èà•ˆ%`JÐ"~ÚÁÎ IX:I–ØR>Æû°ñ^-gé¹¼¡Œ<.ÛÕ$tR;úÞ¾´ÆÈÎR2#GÖ++èɆ4u³YS([‘}åŸn´‡©†”ÅýÌA"ÒÖ[ÑÄ’ÌÐgÊ=×¾Û} ö<}ÅÈÍQ> !”¤¼“A˜Yÿôk駉ÐRм&ZÆËƒR¥Q´´þ‡å>¢Å™9¤RËäˆóXô!âßoõè6è3þR¤>| Æ;O–ú¶j†‘ÔøéãW/ÑI·DœÇ]í/æÁë-§¿DŒ–aaÔ>U¹ë¤›N«(e…e`ˆ–¼ “ÜoÊEKl’‰¿À¬¡EáÂö«Såö'î@Ù‰ º™B ùb—Ì’‰OÊ™…üD³*…|dÿ;hˆu¤=)î(Çb¦ïÍêJŠýmYiŸR4;b"'‚Ê1‡:çm±SS<¢1#Æäh‚ðßEÍ6‡ÔÓèãG|]϶«"S~´{£¹a×ëêK¯ØÐs5Dúqî$‰aT—`¿õq4  2ÃàHøMdåŒý„ãv“úÿJ^/¾ê”„ _ïŒf²fÚ÷§jzUz \¿ùHä×úäªc[p³š#!Öêt_ †¨¨Â7¾–9ßù¹âNÜHèæ÷„ð\Mmmm–ãŽÇãÆÓÎO\®4géÈeÅ·õ*ø¼z•^wÖ~gXÊ…uE”ëfÄYsµ—Yd†qÌÚÎ6(©RU¥Å|IÝœ¤o>|•¥êV…$7X¹³B`ùf0å$a{jÝ)U{Ÿ‡LA¦Ä’€€ÍRT0ŽäÄRµˆ„#­[¡G‚xú‡ì87¾`ûîŠP½çî(½Ÿà¼€ä|…»hÊ®:_v †Ã¤!1Ç£ù-ËЋh†‡ÉøRW ûÒàt>S6ewážÕ?ß'âšÒp*« šG÷ïÇòŠóÇy‘DgýÜC‰bcdýÁCž¢Žx“ÌíÏõ¡ÏTÓš®”hòË܌Ȱ1~IY¥žµ;×|öwõR¤öÔ¾.ã[ö¿£­.}0`ÝØ*F_Ãò…ËÆ 8YvÿQvÂ~dA¸а !⎠@¨Ö´´As%Ë< C"¢…Ác7†S‡«/ëa5Z„üÈH0¹ŒK¸.rÐQÝv¶/’ùñœÚMÁ¹.TØ%áͦv¦òTsþÞÈÙ²)l°^t|ã!éë2¦:+ÜS–Ä./_!Ï¿!8Ó8ˆÎ G½JÖœøw/FôÚˆ¸§¨†!_y^ 0®¦08Ä*ÚA„ë¤È|ÅCk–Æ¥YÛG_ŠW|±XRÞÖØØ§i:D- Ä8¬¢'ûh •°cÄß‚Ô<þ"\d§ã ºl›•ÐŽ§|c |ªø °£?Ë>·îÝý~'-Æœ):DäÝ›qjq?/ár<§dêæäaò&‹Œò®…Çç®*Ÿ¸#†ØY%(ùën)•uÉL×m$ÂŒìõ¡à¿b}Ö€†Ð/oà#¢ßóC¼5lÌ(ß³ÈûMjØ^(.lKÏ´ –H;=ÌßÖ²ûÑdó]»×<ÀòÀ:Ûˆòc)ô‚ÈYqÎOÏï!í‰ žÿ±d£+=Ùê-}Ë÷ñs[iéÖoÌr²óµzBÌ b´@n™¶»RV°†Ä»öˆ0$ö ÙãÔymߢKŒø…F1†w•©(3õ޵­öÔÐÒ?2DYõ:ù.°Úáï»{ ýF¥ÅòiE¼*jEC ñ1‰_Ä£8×_ñå]òL!ñí_U\쮜»Ö­Ïˆ®®«oR:7ILL=°ÑTš}XïuDZóC½@¼ÎÅ©ô :•Žÿ\yvãèR$daŸ Až™¿B+O:¸¹UùTÖ­“é…Ãwç¾c>£ÃÖœŠ*_Pu"©`ñËóÛÞøSYúÈ æ.F’€€Û:³­ÁJ¶±#œFSœXì%ÉZI5ÝJñZ¨ôL9S‰s1µ|%nKÃçÌr%0Ë£F1ñîÇkˆöãeýßlícØ¿ŠIàn_œGÑšÃ&h ŽOLíaLÎÀŒ$g[áÈsG{yB¿d×/«"‘ú¦èø då½3êÉozˆüSh=T÷_‚8]‘âO)|u ¹­2¼Rë•T{¡XпÒvÚAZø==lW:ŒUOTq‡V¢1Šî³•ÇPeåÿBø¶¦ý7^*Sí¡Õ÷cûÒ:¸ÇÏn–5ݦÍIh¡t`….‘¨×Û骷ȴ „gÌe~hµ€]{6˜Ö™¸ô·‘U»Ù2Ö›º×vQjë¾~”yÛUvöh º×íƒv|ŸébиӨœê‘ º(£6Hýº“q N§]ϵf1µ\—Îáç²PÒÁ)/$ ‚†“C´½_rlqÞÑ-žL|(%„6éP-’¨ ;`~$ùjBI¿mRqûsøSvÂõbçÇÍz,›_uIö‚3¥ÊŸeîÁW#–â3G„'Wƒyfdgý¦М’E—KP•É<âãü/v\º%¼Ê€$'‚hëê¢iXJêŽZ7ƒÇîžÖÍê۳᭸  üõܳkÇvH38èaöÐá“…¨Å¿g ÙXÔÆƒíDÕF¿4”ŒÐõiL.Åýð×| µ˜Pî&›Ã.4IåòBºùøùw#Q´£)e©m/…2‚Ð|zÛ~¯5Ý瘨À¬•áÔ¶[¼ÚÕìS[ÔMvÉ[]Í>š´¡a¶ø¾YÔãc G§Jÿ`™‰‚fƒ¼e1ʆԺ¾è)ôšÁÔ;{´H¥=×O`Ó‘Û‰\Aõ׉ kIÈ»j‹/¢Z…ŠþB¾Å©;JO­ö‰q!~‡»õÂ\Û<”}Ë?1:±aX¼zîå)¡eÖkXª®¶0®~Þ4š÷%·Ï~{Œ³ŒÀ²gk:šO†„å½yýk–ç¾ç÷Á€Ó ”ïIÚýAÒØ1^ƒrah‡EѶvgéC!æDíùm*/uÛ$yß‹:X±«k솸©9ºö(˜«žà%…º<µÚôâ’W?VÐÆë|áù×~µiÈF„Âb³…2û(’€€²R%¤Ã‚û4{_D¯ãlD-]v–çl_¶Ô3õËZûöì˜b3_LQÜH©ì—öJˆ¯Û&Ÿe½ tµ†Ýl!Z#-Þ(ýÐu-õHDBH½:ª‡Ãº­$¨V„7Ê!!_4fÙÿXsµõ\_ ,I ñ¼ÎmõººR¤¡{þí¯Ðé)´?WªS 3Û1 k˧}“"ËóùGôïnWìËߪ[* ǘ¨Wr}‰÷ט¢úáÏõm5dÉU·M•{˜ýa–ŠñÍ–_B‚­nÃ+U òè”|‘fmDê•==A-i±Rm® ½/V•ƒþu—IuÌ8¦§VA§,ÄÑyÛ¦i”]pCÝ· :fMòH!ÿ\,Çûü7úµb»ÒÈnƒ)ài²LûÕˆ©Çš«½O~Ù»¢m Âõ¼+Ò¼³SÍö#Ý |Î{O Ñ–'É/ðÎ(gâßÕõ[£eÖ“ªÌµÞJYø?¡Ïé3T…@&R‚ð‹6ö¥’¤¡½7zº¥)Ç1ñ @¦Èbd„+ÏjÖhïõH†~Rsݘñ¹ð™x]Ô+á n}'5ÂVÐ@a«6t5±+Í­|†Uñu¬;¨ˆ³C“9lð@{ç~X@‚ãþÃÇâófsÉg-ÛùܧÓ*•¥!r$Dl’v¶Ãš \‰±€ÆÒ¸Óf‹÷—ŠWoäø@|î¼ìüÑSŸ‡o*û3ÍÚ¼!© ÐócÙ‹ú¼C!3hàØoš¯Ô~¦ e!¬ÃÂK²‚á/Ï>Èïm?•„O}Êóõ΀ŒWîœW…=ccÏ…ö…„÷€óÏükã ñ}¤8WLãÎÈLÐ~l[ršv€èOûv³'ïYûZº2ƒ¤ÙCé”gûŒâ-Ì5 8Û3¿ȰªBÉzÊ­¢ê±%’×ôãUž( vø¬«>tàìmá#« £+'§­çô|…Êf¡×sM=R}­Í""ïÄqbG"±Ê;ªŒ‘Ë{‰SgÔèUJ›†uËŒ‘ªl0?&™ë7»ÑÚÙ£ F…_v%eؚͥĞ.HØ;G{Fýˆæ¥a5^Ñ‹Ü$„RHœuÊcM?Kæ³|pM€Þ,8WnS¤Z»ØßçË·ˆ'ê)’€€¦P?ÃíôpÈ%÷,3¿*^~4UWò–­Ùíé˸¦Ÿú¯Ô¢W¹,à£j¾óI»!Ë™q»͘Š5hÞî…O*Ç,…i÷Oûò°J±Ig2ÏŸŠë£¸°CbÌÕ:¥r Y}(µêÞÎõ£Œ_ÙG#³Ã¹ :$¢}åêN&û%R$+JÇ ÒG‰ºLîI¬iYvcaIq„SxXã’’Bþ9·ŠM¡PæzKb•_ˆ(e´¬‚X¿Y2EæM㳂AëGCBÚ¨Œ±›ããˆq”hÓÃÂva¶ïi=½ÐÀ$ÜÚ¼ïz">Kÿd8×d|§éŸP»o ,jGþéòL\Ûn.]c¹ì"1™Îp}R•»kUóþábý]èâ®iª‡÷ÑÌÐ^àws½šIzźìôÏKœQr§Üò” ÀÑ~§¦JÙ‡5#u¹ƒ¨ÞžÉº{7ÿ3m}&+4ÂìeZÅã ³]§üÞOi¿ÛòL¯Á‚5@érÞ|ÄáS©ÒšŸ+Gòñ»“Á(źËñÑdÆ´`Œ¶­æêÍzJ ²º¤0ÅSúð$¶©ï¬DŸ7ÏGÑú¶H7Ž$ONØ%Ñ ¦ÇĘ¡K^®Šn^°–ì1`^°¼jò NÜ'IÜæõkÛè#x¸ÑÁÁÏn ºÆ´çÓe¯×¿ÆÏºG8åZgÇÖ¾sñ/fÙ”Õ“ä>ÚnÅ} :g’YoÞ°¯-®Z1%WînÏ[ WN[+8ûÔ"†l(+u³½ÚÛbÊN’€€¼Ÿ‘`¢´ÑÈÆ>7ôâ€Úu•³Î~|´Ç?ýÒuÙœrM¼ p2ós …g‘TÈŒÆ*A·Û¤.ÈL—Õ¦¨„¶î^¨mà±~š÷œÈ- 4†ÙWׄ ]&B&[o“•”s¼!œifTéGZãšÂž‘—(rp]›#¸b.[k~.„zR)”t“©’©^nÙJmf³Âæ{Ý&6¾õåpiˆŽÕ¢;†-BÈ• k«|®µÓ\:Ç3PÝEÊ ïô­H{ÀnR¼v[V½ßL÷zuÃȈJÓÄÝy‹_YÝ’ÃÁ¼ãl\ èý*û¦|&°ßìÿê¡¿Õ„Œg§“Néi³¹öj#IlQi¤eÅáÙÕ´‘ØÒ¡ø=/ü‘¶dõ "°xÆšð£&Oö6<§`œ*ç~ì¸ñL›×“˜ªäj^ª‹÷ʹ ‰œÆsLJc6÷º¯îø£¥Ù„f¡³´o~\µõ&‚ ^.?GF ª,¯=™á·L ÚåÉѺž£Êk ðÁ|6Jï"”ÛÏ.ìô¬X#¾¨XÚWCžèÚ>Iˆàó»f={ý–¯•€²ïê¿@%¨ÌÓn¢-Ä !´ɇ“¡ÛáôOÝ¡½¡ñ“¹“Lýí×)ßœŠg?Í·Q|!Æ.˜½ËéßëR^°`àÛ•L–ƒ-Y |nªf‚(0ÆãSh±3 Iûœì£Öwö…SÞ­Ó\d×·Å¥#²”dÉÒAmAˆ‡ãÄU{Ñ$ÞŒO—é?°+ëºA2XäŽÍ5©ÆB¥ F{ÙûÜå·N6RT„óúmD0øµ×ë9±#’PŸzOiæöö¶äH8 F­?Ñã±Ååm5ùaÝ–ê0úùW;c‡´ÆÉü*mñ÷~ÅP+¶˜ÿ¹®ž!âql,3©«‰‹—¦/ÌówuŠ\pèc­Mq¤´X’œªÖb¦EÖ’€€ŸÍË›=9ÉÌŸŒEý´ý(8]CgQ#X ™©<ôòÿ¬ … ¿Që‡çH£µ.Ë?q>â×ö¶$Ù„ø³F‰ÉŠ×¼"¯=€,w†Âã³à ùßÁHý Ã,¼V«â¦mÎ0˜¸-ŽOóIäÌ ÚÝ}Ï)ô­Þ…Á#Mð_ÕF ¾ËY>—Hd¥¬Ðu`ŒÒ‹}­©ÌË"ö¯Àýå™éûgà©å~9}:DJn¹IY ,M³²Á1ýÔhb>Ff]uyô SÆ»Là.m›É–Û+XRGžP €ÎêÔ\eÿà26÷§»Óm³àkðÒ/VKAËjWÕJWÚxÇyê›Iõ’ÔV;Z cü åDZ+á;CÏ,ÿžÍ=Ηϳtç÷­#¨ïŸ4©Ô¾ãuEesü:·wØÂ&8g`ËåŒìŸÀÇfR5™dÎ@þô6s"‰/ÃâÛK®gö›äjTBj[âîS{GÙ[ɺï=~m¥áo‘á,À…\ê yíR€¸áùC{D íXi‹Œ…E3£¾ÚpJ ßÈЮý ÛŽ–üB4ò‡+”+î¯^ÎÀ•¾ÄâgÁ3‡ß¡ƒùH…o„éo—¥8åc–kGiÐ1$ Âì'Zþ‘vg ,€îGvp)ÓB7N]Îo¬ Fo.Wß×ôwÊÇiÎEµM3ÊÛ¦÷›L‡ú·ûè]ã›—€O_ÆÈ»É)žz#WêÄ¦Í Q„Pö•g6f¹rX~:|·Éݼ:jL¡ÅÑ3€“€K)@†B%©N2'¹’åºî±LŽ~]ÁÑÛÂW \…±Žè€ ÷{ÊÞ)‡ê³šëÎsz ê±™ù ¡¯–1_ù ‘g#w`ú¥40’§°,°ëÜ$Õ|Õ{Áý†Üñ9† ²ÞÀ™G}Z½JXÓDíZ»vjÛìü«‡š”o½öŒÄ)¿fOz»– Ç­¾b~ÐÞu?usTÑ^•‹Yp3¿‰–;9[š¶¹jHpD¼U‚5r0[´:‘lm‰‰"¼–•¨¡GǬß'°­ÆÌ-êd$V­HüÝ=,þ?{è®Ès e¥BVɤÿî„ ɹ†G"a¼ßeû¨,V™óO údÑYÒc’€€ª¾àÑÍÍRD¦ŽjiŸ¼ûç`樘©˜+ÚáCÇŠ’’ÒH‘\ÚœŒ¦3Ô$“DX3!bøXë( pü¹®‚B0ÍÖ&Ëf‡¤½-*eèðßq™>‚ùàotÇ…äsK¥¨Íá‘D‘é„6¢í¿_c8ñæC뙉Dl£^)]KÎÖMw]Ö¬©e]S`Ð*†æâIHú3Ë}Úë ü'LÐsÜa –¹lõàQW Rß1˜·^]›þp©{í,~íÜB"ÿÝÕ:!{pÓè,£td3³ºÞP¹À¦ë£s£„(ÜÇo¨51Ñ}˜¸¼}ïÍñó ŠÀ3Vß½œ]‰p1Å×Ù,Õ´Är‰)‚S†e(ËÊΚ؈w•&R]² â¶V4¡Ôµ\2ÃÿKâÁ¢˜&J,Š”f1A»X(fÝæfMt–ü¥ˆ™ÄÇõ†ËÍÔGËÉxNe©Y…¯žú «"báéi…ÌÓ3'p ~pÖUÿL”KªY£ '=¤Õåd‘ÙiG>¶äÞÌ}R-t¶qäe<÷Ë´ÜøsXKÍ&ˆ—3ò ìîLB{ý1€b›†E¬}aD,žÁ_²„žþ¨6dý±« l0`ªhG8O´¿¢5¶ùÀháOì¬åÒw…Y"ò‘„h¸hßÜ\ˆqš¨ª–w`Ÿ¿úß*²à°7:~=}aìžÝ vˆ¯Î.µ`”kß/yG¨¨*²x×'¶é–GiÆ÷öò-G.ÿÉx0…‹ïªò¢¦¬b­ÚWmÙn|t–°Ü9¥ñãi@ÎÔÊÁ¿¬t˘UF‰ÛøèbRe×Íÿð !ìxÉ 0㿬%æVùcWTÁÊ» ™â”¬a3h0„ÙкâB[÷d€°=§Wˆ‡ŸŒâ=«sk²íž{óR#ŸÄ|™FçÙìzSß‹u*„àÙŽäzN¢`Ø~ë,.…~È´>‚}G¾ƒk2~rsW2ùRrdú.»yÇyè%jšk³‡Ìoãuh¦!öÖ€‘ÓŸ(ÿ‚_:}OåÇ „5wR‹Áà…a ];çê$.)E8S ö­é¥À‰Cq{„`ŸÞuç!ï9UÕ2ý:¤j {õH¥Á|n®ÊàÃôŸ>…I›ñ;r–s'Ù Vãæþӽɩ9äöðèØ__ÍŒ7l [ÆJ¸×jüMq‘Y#1î^6-CvRH¹ñÔV«sÖŠ]ÄôÒj0 a!›±f®É¹¼•Ž}{“0:#p í±È_™=° ‡ 3H_埻ûc·?Á ^]™“!ÂcñP™Ã[Ú´C¿ðÄ­·l š‚œ7#˜ÓÞ+oV±]txöÞ?™ô¯]¯“&$h¾cM‹@H(÷âhqð:` *Òo&c”³ÀyæI’/󣋥 ­'¾ßýt, ½š„§š¥Ž¶˜áN«ÿÌ·‡‰)SíëE`Òöõ;Òˆ½Ü¨´®æRþ{¢rÙÕ¬E0«~/î 2«He ž[~‘-k´»m£âÓ›ÍHI™ó 43<)óûÉÒPÈú ˆnúJ:!UÁdÛvØ;@E‚ðQ<]ÍY¬6ÇyŠš>û•lö]ÏÝ>9‘[ß¡q^e–üz¾Huóø€—]_É€§S³áWC0Ûø©¡`ÔˆJaÞ+x»ËE¶øKR1‹›ç~©ÛOñÝW®á].¶ÜZK¡Õ”¦ÃP¹ë­?Ö®!ûøè0ã‚ÙP\OYÊœè¤bšcžS¤2j¢3÷e;OÆ; ìcªC4; /‡¡f Â{§"¥AÀ ­éªÝ™¶­“¹08úuÌè)¯x{.ÊDdódp›¨%ŸÀúãÀ<ª†d»%jèP•zÄUŽ¢ÁøÄoCСì·u¾ªN]ó²è`ñ#·ùª|yÄ2 ÊXî5‡wXá# Ñ—%O¥bHñ+’WWmV47Q Ú •=’€€É„7´…ĺqñ´ìùH—˜›Ø‡oÜA9(ZIÎ̪ñ„Aðçeª & ~=±ù6²3iþûX9Yÿ£ìm½º?ò$ŽSaêYﮬ‹ßî|÷­w8H„ýÁÊ`ï鱺ì5R®¥µDÎüBÙÈéTf¨Áãg^€¯'°ºLî—ü§8ƒŽi¨œ©LÅñ ÈgT-;ŒÖ3Ö¤ g„Š\Ot¨BµŠ[l@k„«¯Ê¢ˆ{4m"‹á˜¡ˆúÍk2ï)5<=V2mÉ̾rÏvþmHý…ª¶G*¥È°òðøý/¤ð#êRââøŽÕ; ÝüÅ=€3K¹Û©€ »/ŠÝF’K/ÿÙ:6ûÍÚ·à”Î@àú²\-Š««Æ™.V8;æÖäîYeãzÆBs±+üû­ym÷à³FxËëÛÅóí“!R¦ÈÌ@t¦‹SÔ× ý܇ùšPN²ËX¡,r&êÀ–è½Á‡.ªÄä«•o*äh(‹:” ¡¯®\_«FR|L.ŠJ}?^‘Óñ†P'išÈÞSjƱ„£¨..&¶‚’7D­–lêXwÆwöËÖ(E%ÿ=Ç?©´wèÊÉZוž°Šö*’áÚýÙ¤ÓøÄøQÕ>Áö†3üÈjĈ/½»Ûè´‰ì9˜E¡ð£ð£EÞof›95f>DmZáѤ†Ï©øzBïjú—T…FîoÙ«7Šä…ªð×’÷Šë^ŒÜ)Vs¦R&‘Ãë4Ÿ¡ËmÊOŸ±W¡Eö<õ®gyùz÷‡'vð…což >„ÊÇš·‚ï}EQaßÉÑÙÙÛª%‘€I:ÎN¼Ô|BÔòõë+ì ÞT6Êb’ œøÓþ?Ëtu¿Ä”ðd‡À ²$вú6<|3¬âe}(Ę_¢]ñmÚ4^}±ªrÉú…ÇÊ%E³¤av>åä¹Fá‰Fì¶Ö€ŒÛŸÕ†t‚Vú©„M2ïw륊+"‰CÑ£ºD@|æXt{ÖÖ®ÎìtSbyñÏøKáDhôÐÀ?Œz¥ÉçEŽˆÊLh­ø‚ºÎн[7ãeŒ=tð+¬ôÎAí.¿Øðƒ–ûŒ8š6 ˜Œ™)ôÄá¨ÉcJ<× (õ9¨1}i¤©iXè¡§Ág£Æ¨’€€ÂƒO¯å“rã—WYÆ 7Öhcܺe:g‘ñ‘®­¥öOÖö™ßq`;¥Ô”€ÈAË ¬%¬>åJcí½ž×ö•ÏNõFx§ê—:Åà–Zki• o^HïÁ7^ |R†þšàèLŠÌPvÓa:œçC¾Ö*I¦º) -ga,Ë»Ùà½ÖÿDÕ¼¡×¼xKU þò^?:¥ù[s‘âðDü­¾‘À/ºÆ¾Å+™.¨\“S“UKˆ¿Þd ´ˆ$7t5´Ë —<š‹Ìn°;…³$=kjÜ[Ó à$¾Nd;ZÀÙý0Ã×EçN[Pá;D¶U¡ïH&™DµÉýæú‹OŸmK¬‡æ7ùgKÃÇOD*!ìnÕÞ¯?JÆ+¼T!v9U׳Åðþ®M9z l;îOð·Ê)›,§~®¯ù7ÝåUÛ{‰¿n¡o†ö ÎV…ÏGwì_ID>¤¬H{$5}Íx‰ìxáE’¾¶)ô¢wÓ>Þ8j*A‘ˆ&._ñiþX’_õÑà˜£àèÎÕAtk‚FP9»UdVèQqüó{ôÁ20Ah‚RV¿×Qæw,i~à$P;+èoò]`.Ù‚ßtÀ¾|µ*Éý×€Ï×âܕǠ¢Kx« ”eëãŸÄ·s")È¡{»·ÜÔ…å!N¡ìšä—Ûêá¾²0þ~xdÕ”òÄØUU¯N t©Çg¢i¯êùu/Ìii8_©A{CaŠ2ª·Ý/§¹Ò#ÛI ÿ`yˆMÞu_U“ÌBZSÇñš¬÷ ‡Q[—·½³ÄÑj‘<>A98°BÄ0YbdfaÅÙRÃîhNh݈ÿ¥$\¼ y…•Pßr<†ëoÍV [s‹ß\hr²D1é‡\ÂÉþGôDè‘k3SÁ½™¼½ §è'W4Šç‡÷ÏÉ«O=Å|»“ÿg\ðýþ8Ó íDµ3ŸQ0åQe™ œÄ â{^w‹î;5~­ù]ô¢Ýd÷SÈzj°ÐÝu™¸‘D²Çt ˜zuz®>„¦[©zÑpï%‘dxºBˆ WO¾¢7C7ñÈ÷M›ˆ§J»<»k¦šK*{î³Ha: rë3®kZ"Ž×ªôEþ+šLî‚È0@àh®Ÿ¤ñÂ’€€³¸èyEÍZ;,ÜÅó§–ægª\T¾Fò‰d&0•ÔèGqJ<½FU4 "ûþ_Wð¹8H4ªœr™\ÇFÞ0¬IÊÑ8,:ç¿K\ˆÅ^?ލ÷LËæ{îê­Öe¼\Ú¯…“^uê5‡¯«ÚM¨Q*þ8•ä]WÆ&Þ¼G‚fñ­Ti-Æå¹ÚOeœJ–âýß^fèhÒÛiƒ(šóJŠË*;l~v7Æ&ËÓÓa¬<øÒ i.ª«²Šð¿ÚÊ.Ó4¡²†?wõ…'ž#÷ ¾¢øf]ò¼àW ŸÏTÛëÒx>j¶ÞYùRöyß4r¹b%MÛˆú[ÈåHÐeC¥glR8Ø5ízÜSçýbªCüãÛïsó.l‰µBüÖ¯?ƒÌiÙ£ƒêÃÏ !-˜àâ/1ä*OOH,ÈnãAÉJÑ@zºá½r~>H÷É$«# '邟yÕÖ´èÅú|ÜÀOwÚ‰ð£F ¢ÛÚ´LWª¥‹¨Tü¹z-î[·ÉRwBç5V(ì´ á|‰*ƒ¢\õ—²^w÷! yå^)¾?IÊÇXO‘åc;æ†Ð„ô…ÎX04µ0€iÐS ÎLN×ÉIû. .'3ÃÒàÈÍ’ ôèîüJÓ¢6! óoÝ"îlfA­|:°»pxY¸kûþ·ÞÀ]˜´SºzæoÖðÓÏä)άǤ1àx)â5)Ø!XÅÔdú'6bŒµòÝGÎN©øÿc ÔÔiƒ†àéEÍÃTÝ:§nÝË+Tåk¼NãµhÕå´¢z“m­…ÙÆ s¡@zéZï8‡wjmx‚ty=ô9N+)Îþ“«P'Å(»´ö°Z“¢#ôCÛU. îágmz:¼Ú©ÙX̹òÞ”|“s{îý…l6ù€ùxÓ¥ÖË}öð2!‡2*,Í Ò‰lÿ¦bÒÇ•$é+ÌQ•Çáí9;eVáû¬¨í]¿ó°D— ÏÙCÄ5ƒ|‹Ò¤xѸÏË=ˆÈ¹ÁÃÖ¥¸iùñnÃóq;Ïtd@ôä^ÁúîˆêÂVæJÃí§£³¬.£ƒÔ,œw´?ª:Tníl†pÝW3[’í;5DHÆêÿá!…Ð;á ì׆ð){ïBVx\¬Öƒi>Ÿä !Ã/ÿÄt‚#{¸pà/ ù̇ß÷m/ y’&ÖXy˜ê ã (ßhxƒV`>¦kC´¼AçÐyE Ý¾†ç×HºðÁƒWŒ¾Hÿî,`5åC+–Œt§YÇä‡yçÚÈj@ð,F'PCÛAºV®rŸæ=Ó8¢ Oeƒ ùTQȲçðŠRHÇ-Ý©à*,9ã•£J8ÕíÔwåwúy4f¨qy¬Õ¼å>£Ñøê ,¢ûœÎî¿IpÙ«;Åæ…?'û °HYÉi uÌÍú¡wˆHÊÂ癨zÅÐÏÎ\Aô +ÁµA±…Ä·•Ì©ó\Aáá‚|дÊÈ®ƒ¿wÙ[Ûº ´£ƒ}“X7Ì)Ÿû™e±!²Eë·É|o×ëϾZÄdkž½×LzT)s8QÑ"°ô)Ó±c]Ogý3Ã0ÇØ‚H§kõ]V › {ö7PÚX*ñOh·šDÉ #^C\Ân(§›²y^Ÿ‚À—7ÊÍ”´Z®ëJm§Ù1–áOV‰Vã\k±†DØJ6o´^TªžŽÔ¢Cж“lϼá¦hâ}ñ°~ åY@AÓ;&g@hô¢ü¢“Ê’€€öŒN³xÎñ&ƒÕ-°™¹v4©¤£Œýì5º¸VÇ:/†ðLÆ€v_ú ·<˜¶H+¿ÒÄ:ÎpbxŽ‘UÑ„“Íi)Àu,SE@d¡Ú±óÜaÒ¯L¦N~L«oçGÜÀšýôXÜ 0Ì_34æ²æ–éP(õç{ð4W¥L7n¡Ü²ÁÚ_ËÛµó6ìAªwÀwáT_Íð‹„Ú |(LåîµQõ¼ùøXF±|Lÿ©“ªG­~a™ÅP=#Y7¢{¾kk•O; ;‚Eh.;”#oÑOÏð0^$¶àÐo €“ôjÿˆ2ÌòJ Üíc—Þ NAFSyîUÛsG`Ïvå,܃Iö×M  ïjn••ö¯Uq¹Œþé.üBÆ–ßÆVëõ™åè>ciHæ G¸·&+CÃc´z!DÒùÄA–Uë±rŸ!„!§¹Œóåíþ+7)"2·¶ô)Ê•.kH¯%ÐF‰A==¥Þ"è?xgÅ¥4m…jå-$=RT,˜´¡Zãæâd÷Õ®Ö8TûïšÕa€Ú´¿Z›(=¾ôKï 9„ÿ=V4)_Cã€\¼ÑCI™€§³'IØ ¿…±NüORˆ‡IÒ·¡ó¨¯([œuí6†:›óOƒ7]Cä•jÙ…x.»¢ªYþÐryåâhâ.a‡Va!À¾$V{Üñ8ÙñeD3S6îÆ-Â[tþü¤óç@(hf® +÷·NúøÉi‹ùÌøtaiº‰Ž Ñ>À£x "ÿìKãsƒ>qÌ·”)Ö &DØÌ¨y 1t82‚ªñ•°ƒk<Ó±l+á¯÷²¦¢›%•¼,“äpI9_Ü%îCW™·Ê1%E~¿ÁÙ‹/‘6£üoá¡( sÍ;Ú_¨EG1'y(’«³JwÒ–¥Ê´ENýYP§ãˆwR,V[߈äèãÑFº”ÜÆY÷+%'iÒÃ* §>øÍ®ý·&÷™ŒûkÙ4˜ì­&IÁj‘ò3zH× [¥¹&—µÏÔ×}„VÚÔò%ãÖôÁ‰.‘ÄJcDÒ;ž‰ïüá†ÐA™Ÿ’wÓC:AÁÀuëëý²ƒâÔåwá'jÍìÓ4g`?+ìε{¦¼§&Ü€!Že­…ïð¾&n« Æ’€€¨†ÃÀdÚäQ?Nƒ•[ø!>ÓQtA§ÓùQÈDó©ƒs‘‡”ó­åõËÞW9Áµy‚бøýæ Ñ 5C눃<#¤NÛô:ª¼ÞôDPm½{4p"AM‡Kô®)ž¹¶:ëæÙù°í‚ÓÜW‰NPHÙ!·P¬öh¾¦ tü™>`¨¬½JM3嫈öÐ4‡­J] ìñ 8ƒÐ¥ àQ¨ïdqæE2Y&· ²*âÀê&#ùГ wýôÑÚadzoÁfsÏ’µ1‚²¾ŸhÕ˜ÆOUç>þ&ûb·Æ1ýĨb¨Ðf¦=eßVì³Á¤[€õô~ëOóÑ*âËÙ ‰}¨bÔ-‡VŒüjcºÐ@òIoÓVwïUü, j‰NüTúkãéù “Ø~—CNò …·ÅÒ*ºr?N¡Ñ¢&“à-HÓH‰£v+ê_„ÒŒœOç ïyŠtk‰vè[&zI;$¦ÚÓU¥P–€‰l5 0kPžLôȇÝü+uȧþšö8ðÛmæDäe:*Ãþ·ùŒÏ&’NÔÀºjä~r?+HàFª‹ôS¦ïÐW¸ŸÕ7÷߬tÈZÓ¢o†ÖlK2÷l›˜Ã–R"|VÕÁßÙ!·È94vø¶³P–ð“ØÌ'¹Èƒ—“õò¬%ÂJEÅÞƒ4:w’ó;1Ý5B¢ucyÉöGRA«T(^=)g™Xl‘ê‡3dw¯Iì¯×}[éa“ði‚î>¬>@öè0°ô›Ë¹‰å$Kä R¥Ž¨_lêDÖÇ ªíÿ-Ðy¥Ã½kñœbT e (½’€€Ï–a)å¾6Ô«LAl7)‚Ù–r ÀAf Ùª?=Ÿ†bE11¿n:”ÏVÔ=å*=ŽéTÿ©‘.ëûòdàd%šàVM_QZÇ%Àäk n¶¼×þdÅ‘ ›"”ÅýåÔÉ}1¡! Ò»GÂ5Ç€©o‚Õ\ “êÌQM³]ÁtšyEÔí·¢‰7m ƒ ¤}ÔÇr›|ZA×ᆼ ²©àmrÎ.zwžhöÐòE!j]'†ŒçÍìê>;*äÛ¦Èï‚q‘kÍ’D ndÞ`®li*A'À&ähL¡uÒÔJ8É›•]–ö$ÖÒ¿—ÇF‚ÓÍ{AÔáʪÒbÍÂ`iã%6M‰Ís’h B¨™R+¾…PSýlw ínsc ƒy÷§}¾+’KÂlJæ^ jL7dÈ9²Ì¡í*„¶-8Õ j¾aì>Âæ¨ayõ²¯éŸ´¥|Ù×Ó}Èw¶ÞòcvþxtRbð¨€ñòý½¢[9©ásææòA³ŸY¸²Ûò?'eb!!PJ9v€_úNÖµËÏ@A›k0@aÀb&}Ú¼D$«û£mѰSçRw´õ¿ÅŒe„+zyÄxöê…JnÏßIß OPAbÄJ©²õra¼·ÍàE^Ž' Îü* ïhÛvñÌ:]Ô(ƒ†Õ©/G»â`pï„YÚ.‘†²]ÞÚ 'M}YšÍMN.ÈÀžGÚWÜ•Ñ %åA2ø»±’‰¶3¹c–ÒhÊïØéÁTk1léü´‘Ä'®ç2û^m=mé÷Å_kf‰½ž/l´âHˆ2Ä3Iyñ™õº£‰jKÝøÿ¶Ñ?¸µØ%0ÞÕ„ü#Ôdå%±@(íºä S¿r¥cèidñHÝ·š×JÍ]šG úvRÞÊeðÚ ¹2fE«Šæ3n†ÃÑÉÁ¼jª¸Ðø{ïÖ½:bÁ_4,Ðû½%Š]p¯ƒjØdÝNY4#ÙÒ´%k#ÎUñU[²³cÓ6£Ï’µ 5ÞyñÜÛÝ¡ÎuºØÊKö¬\Ì9Z‹–~¤ò6<6›Ìââe#È”¼e“š“ÅPÝ(]m’J@àQ!Ê€ÓTQD&çz–LÅÅ%SpºB‰0³«dIJ¦l Mؤϳ½æ¾na>´ µªq(þ%)Ô¿ÌÛû†—èÈŸ§R3Iæ?‡bYžR‹ †( Œîú¼›ŽgKcsÇŠ œ×² Àß6É­ÌZjL?ý»>|²ksÊî†!Þ}[XQ<ˆ ïൠà¸î­=0Wÿ"ôàî©7*!tã¿W=gxNé½ú«ã¬êi+^çmûCÂíÅÄL:ôÆJÏ"rƒ§«Æe@LT;GnE£hÜòM¡ãË'ªïL”s×hÌý‡×­ ˆ¼ì·C¸ƒÔ|VÊ#ïÀÀ›'Ei|tñ(/*Óß?fôg¿8 •ÿúì–™Žü ÈÏ»õÑݵLÊì˜Î >$º‚“Çjq²!E6ì[N17‹^rñ.ã*ö˜*¼â®|Y‘¬M­*oΛzü´Íðv¬¸‘‹k%µÂͧÉÏ/ÏYЮ —}ûwGaLÔe »rŒêü|N} jl_ 6Šã\‡F5¡ÔÞ?‹þ ˜ÏlÄ6ŒñóºÆ2J\r7…Áøj!¤^N…\ßÔ¥Ž©Ša¸“(8T-÷Õ,ÓVâÞf¦62MÀCµCÁ=Q<ôÆ„aK„¶èM» "oSS;‹ÞU6Éî©jC…zÞ7Y7r²™í=šþ(º^sÕ ì^›C” tÇS ]l‚å}é(î Ñ«ìcpfÙÃŒŠdoß=ÐBzG#¥Íþzeoû|^;%T»ßCƒ€Ìt=›0Ëæþpµ­(õ¢[ÚbUƌ’¬lX)ãß.Ae€NÿÑ€äÃý1^¤+8û‹c’BäÛ› W]RªlóÕsí„5±KŒêm¢Oç£fØWS­yy1é÷õúÿ—OÇN÷ÍŠfÖÊ7EÿMÎ}'Wå°!‘ƒáè'½$§åíÐpZW‹ÑÈÞâÀÕ} “,9>›ˆf>{‚ÇAÏ h™ÞH¬p%ojØM°_ûâ§V`©•} 2ēݦ¹8^ù9&«# ÎçPä+\E îÚ€á¨ó©Êi²0¼®5Ùý`dƒ$’€€¼åÕ2…¨&e£ìkj|ÝÆ¢bÛ~ÜïÖ Æ¦eRÖ^RÙjSÉÔÕðÓëÂ@!º»»a÷KïX{j}%!RîLðÄÏ&.îlÓD´q“Ľ"æaF|ˆÉ&÷%ÊÇhk=§¨¿Ð¼î™Ú¼‰¼”ùi@w­õ)s#¼Í$á¿çÙHÍ[ukõ´oá̀‚¹V‚Þ±á*>¯wuò†™,áV jc @xõpÂ!@/áAÞ°K*رP­½f¬†ˆÉÈyŸ‹îîKN×´kA’ ñ=»Yz´Ó{$å4%Pý•Hh|‘,i2|‰‰¶Z‚šõÜ¢ ËÏ«Á$Ó¡´"¹++èO$÷cÂØá é‹g¬ ¥ »Bᮾ 1ê³7Á˜TVé„öÊf”ÇkûÂóˆîš‹˜‚¹!Øé±·–¯r=õÍŠÓ'yfúaÝÚ­J‰I‡8~YfŽ™OÆý‡¿!ôœº ¿ï¤± l2’8•ˆ&kŠèpipaCÁp¾FbÕJÆ¥MººÏƒd¨ÞMˆXÕ%În Ž)S U°á‘…`\x‹~(‰S1 ¤ G]^··.Ÿ±Ç½ºa{YÔåboò[éÍ-·Ø+¾$¼‹áO^êèÍŠSÚKÐ?òom¨Ùw„SÒíp™rЄ~&l‹Í°™œ­æ[©¯›ˆj@¿Ëùïêöè‘ íµÃ¥ÉÐ?hÝßѸº”Wáz”v9Yw§Ž*/0Ä]y«Y§"½ÙCÏŸ5â âÏ×ÖÔ C±­ýëy\Iº”„g úªI¶ïPŒ4ïõZ$%C=Æ¢üGGªk:G²O·ÛuÖѱÑëѵ¼Ç€Ç­ìÄŒfUÙW·}GÝ:h ¢ù#žæDÆ¢­Ý¯‘–@ÐN3ì|5*HÍÏ-› ÕâžC‡K G•æ­âÂ.òÒÔO ¥P¦§¿&ƵKµ "×§Ï÷€ó,˜j¤Ï€³}@ŠZÉ«P¸%9ÿ®Èuš©‚Ÿ¬IQä‹W¾-(³ ®Ä ×!Ú©%¿?½ÑKhö®esèÓ×à©ÏÃ0&µ3 7kû{ŒYb‘È6ÆKº4D½{;Ák£Cæúô/ÒIV)„_¦.(zÅÆW}àÜ ι;nh`ÐÕïgô¤Žõ°êÎUÜkO±áH’€€”ÙrÖ»þGyËóÌWy RÄ'*Àñó‹Ry&8®ü5W¸xú~ ú‹OkÂë)Aß–>‡7 .µ¤oý9B{c—†Ÿuv¯’CÄ¢¢eÑA½w+–œ~ªí²>x3ùåì˜Å²NW³„Ob‡¦Î‹ƒä]bû ~9ÂÃk5šjIü7Q‰{¯Z€ €ú·[ZáW@¼‚µµÇÎQI‰Üqs4"1ïB¼M®lƒ«aÿ©ž:£1{&yýI›@‚ƒ§ÐTFàÈ´ 5sœN>_+L<ÅÛËà4î­èçgG A%?ø¡6¾ Jº³ìzT‰qY):u] Š2mü‘v=ÐÜ/†e—u_~ž}Œ yt˜+â¥É¢  £´@d¨Ð/ Tž·oT_c|êpqTz´ºÆáçE^¥5Ÿ¢°žë> É9ÏmEÖÚÀ.e‘ÜoñlÉwÉ­NÁÚ)ÊJçPb–é¬ÒŒ”/—ìô/9që³êÚ¡¢á­ƒ#5ŒøÌÞT_â¥,`{Ô„,#Ÿ€vêHkIÕ%2ÔÁà+$.6[3|xópԧž²m:±æn²—Õ4Ë•¼¿t¥ Š¥\(×›Ô@=øSŸË‘ñÖüq¾9ÀÎ{Þ&6§E>D3üÇÏWøE €](¤Îç•_é\È·¬mšR:Ú ½ØG„Vì> ‡}¡"'†|«ˆDñµ@¹Æù+|½¤`£²‹FÂ9»!€?Ç÷Ò†® Õ«³,ne3P,56UpíÞ¬ 1€´ÑB‹°ê>Øöá<édØ­kª]e@‹Éã¹F¸”-à- ¬'“’€€ÁD¤ˆ’ÆLÃ<Ä6~t?}k‘X 2 wDʆ X¼ÿ€•)©šüYô¯f͹¶áM-¡:w¾¢îTZ;S½¿çØ¥™p09[ÎÓ1Üq¬­¦Q¾ý7múÑ åtV\8n[{¬¦\5T’r ü샼GW’™>·&BÒY’‘tÙš}X ¿«b´Û¨œf‡º$õLk_í¶›d”P+´‚†õˇ4­>~4´Ä“g%ƒÊsÀ¥èÞ…q™—HI¡õo1r‰‚S­ðzr?$ÊsaçîÛ÷y(ür…@{hÏu¦YÝÊð"íë$Ò’±'zýQ™ ôŒŸjd- ¶ÐÜòÈ<û“ºÓxM7¹<_)XIèÙŒRDÆc«#O^™û5` “Àu†WˆÃ½aí?*°3ûrƒt Õúʉ`îÊêe„ƒ@jƒZ³<¡å¨¢ª Ý´ìÖá<¬C”sïQŒô ”௽žðhK×n„‰îëcŸÓ€à¾î%ƒ5åT¦QHÿX&‡Ê„U³‰™Ë®¦\ÔïɆž°å\!wÙ‡AjAšv”†„eö QNÀãÜgÿ5ka?Ë„û€‚àVÀ•öêø?l…3Wþ%R7Ü¿<›aÔCƒ0º¥ohɉ̽ñú›b<É™GBï9îI ï1µ"탓MÕ‹Ù‹Ï¥X%§ÕƒÚ9XFið 턽¾«ÿ.ÞÐÌ ¬®Q‹£¨¨¯&ÇU̽cÙJh_¯Ûª*¶öæ8㈔!ˤ‡H2ÿkøþ¼í V=”ðÕK£Q<'ÒäÑVG·*\)kät‚Q½Ïß$T[ªSÐ]·˜‚ ‘³¶p—*Ó¡³rzÞ“‚:ªJß7½þT« FùG~_†"ñ–È)ÈÙ¦N=U|þö$v Ó»nƒ¿(+&Ë•Áú~¯ÔÖƒRM[\íåôǺŠ'C£´æ‹ûeúÄl‰ï*!ûÄ©‚§*†‡×É¢‰’’ƒnkÞ+óGÐcûûX)ðZˆ‘_ʸ™øTœµ…€cå•*]ƒP-Fº¡Ïfå…@`”ü‘vI»°Ë7B÷ž5rŸƒ¥“–™O¸^cÒ·Ý!²Ô¿\ñŒ,ªÕ¼÷WJ'Jᓲ‰Ë€¡ÛËx’€€à‚A&*'®Ù§cm¯†¶2½Ó†ÿ£U‹³ÆE[ «'´ûú±°&²´2nº[¶´Žüå Y¾Sw¿¸Åq °Mé&”~ÉzSIø’ù.—ù|A>·ÆBGº·y\®n½X´)4^5»*úKr]†C÷êB3R@©Ï/cý÷ˆqĉàò¸ú •](BfÞ“ÛzÛÑ^ΣE=zp˜¾Ë^ïˆÇ˧H8f¨Æ 0›@¨F@nÍéÓúᇌ©N(nÞKÜ' ë,äô`ÒGãS²±ÈûNÛ°“ŸªÓ®u>Û’ƒò+gÿ ÐJ–Ae¡®œ»Ù‡÷þB½wIQ>—F _à=Óúýž:‰fÉ¥PaX²,)éš¼’ŠkÆ‚ÛR¤å-_™æ(³ž›8ìõ¢OÛe4Òbï‘ ¯a#èeM‡8¹UÛ”­2I<°…­§^µY{+êÀ, e’YiϵIS™ÎÔV£#‚—u/±ËäTŒµ2zصˆÖÉî®·Á„Ø $úËým«‡¬¶ì_ð·O¦È8¯évà‰ ½Gð õ(QæñôdÙõ¨ÝO”¿Pá ŸáQQ7nBh³;¹6xQ¬&Ùi üM•2-µAfì ç³{Qó‘×)Æ*Øôé·Êÿ^:ÿ‰ÏsLÊ1>øEòDGµ@f>Ôâ M[în8×…l7¬ŒÉE9ä1¿1޼r "Ú¢N ,÷ .Í=<+@ä#Bà™j,[Xß“[h„þ€~‹U"‘Ú8G©ŸQ©mL!Õ;í‡o”ÄAt¹L²û8åㆭ§ôé|óãÛÙò»1¥{U³çíI iôyh'Ü ÇðSÿ3Â# ñ8íª9iΧÝJ½ÄøÅÎ4àJ[µû½Y% ±þ´!¯u’H QßÓ’rÀµA^7öžaàÆ–¼4s8'5U¹)*!T¤»‹ë”sD_bR’+´²hæ:µ{%˜O)s‚‡¨ÀËsVã–gEVH³$áT[2è=’³Œ]ãucØI¨|áþ?` ân’€€ £¦[põã¿1kH˜Z¦AvËÈ­0ÅÄô"ËÒsYR¯‰š ì}5>å&ÄIémŠCáQTðŒb¤vžŸb’ÏCXûS7Àv ÎÅ{°âñTd»Šô—eŸ‚”œÕ½»Ž˜Uq¦ÏæÆ¸ü†]eÄèfp>ìaýDܘæ€>Ã*TŠ/`Åa3úÊ/P«0+Øu¯_ŽÙ™I6¡ÏƉg0.ãÑG_þdÖâ§2hŽýi„c›9£.6x8Ø=D<—ÐÖ1² lÚ[Bj û ó…óPíS(›hL„Ã%É£ÕýnãÚ¼ÐÙúÅvçyãcÌó¾å 0î˜ô5 BæZ%ôFûÄÜ`¹Áõ¥l¾"Œ*}h~ä¦$·ý…<)S$ž~Vr.ãÒ@w£ùàyòÙ®A¼O¡0rÊÿç ºÛAmj(ÿWÕT¯=úTÔ–'4ô;$ô°™ÃKiEÉÐU JžYn™ÕˆJFy‹†`§aœVü.Lß%ÂKïÚS5$/‚»íÝŠpSÙ~ûÿ¼”ßCëK”e£õ¨Í‚UðMCU&ìIi¨&/?eöâ´Ÿ`ùĽ®R½è`ì§°k&êwix©»ê¡ò“ýèˤ­3Û‰¬ÖùShAƒ„múꩤ%Œ@Ga« ÍÀÌ=e„a .4ÁÇ )ƒÎexòï`;¨‡é¯†ÀõúÒÎÜh\{tž}#® ÒÍ‚¥µs\‘-ô¸vé©ÓE}·nï[5‰‡» ­ÁñW\}Ÿî ÜÕp.¯ð@2 òWÔ#Ux¼yËÛX«È[ƒŠÉ­ÇÞpz>ð[0ƒÂ4ƒ ú~£k]Pp&R¦#jÿYäñ=xñޱú€»½%FÀÏ·îÑ ÔšŽ­˜\RäLx:ÈÑRÅ®†2›é¶ìNRæ¿_„¯ ¸DÞÈ‹T1•7Çÿ)CßM©0oä)–§K@þ6¸û! SK£ö$F=5©"S?§sWÉÖ yÞ útùPÃ=—ÔÄjÆ¿Íø¥—jðs;· ‚K·l`±§§ÜþÚ• Ä%ôÌ´òŬZᬶ44w¶"XD7pzïíqÂJXãot^½|½¼|æq¢)¦?@žöåwÿ©2öÓL$åq”hhÏÕ£w”Š$ijÅHÝ¡€ÆvÃ{ÃMTýȽ¹)˜êðN0ÿícDSµ•⌊!5wß’€€­SPxqs2È¿›Ÿ2 Óª}Ì÷WY7Zv“¿¦oJ¯9Œ€#Ú}üSü‹qÄ6W‰Y8’=SvïF¸X7.?ÑÈ?ðFe °»^íþ‰@v¬k‡Û–l(=*w:%k®¾N;Çe¥õÎq8’Ð,YB±Ù4â™=º†¨kZ×hÜñ4d—å WÕ‘&%¼P|–©·3¨tlNÕ“–é·6¥€¡By]œ"‰|>LXŸ²Eÿ4¾a‚‚ØVµ¿Çs}çØÚù»’@)H>4‰¿¬ñ‰¸¹];Æ}‰Áд1É®š=!OO d¹ ¿0)ž øCRÝ Ô´ÃCæ¤ÀÝÉã²ÌMNlB¿'ñ•ýú—»<÷sÐY°søy€XcSÍ;«}Gf•àŠ½AEÞÿk$ÂÊ&z«ò:4`:„‚a„Íìà¶µ/@×þ{˜eä0SÏ+åLÈ×Þd>·‹GÄ¡G,òG>úø91eÄ:Ø÷_Έ¢4yÒ b5ÿz öƒ0øLtcöŒIšÔjÚùzƒðÐmÀ²‰aäµøþÖŸxœyâüP«áT £PêôOŠÝáb¢s’Ø"ýÁ6ȪëÅÙä.»­Vð)ì.vs1´,uù§üÿ>è¨É;]ë°.FÛ1õþë%!<[3$˜žŠsˆgÑx´1fà:ÀÉŒõ^ë–ýX S³‹Â•ÅÞ÷äŸ µËÒ{M³È£6¨Xn}vä4šòÓ0M9dQ6Ÿ£.¾ ‘´@Y’à„âø}üå‹Ì!£”T®R“kæÊáÆ(Ãïû#°Âdfa|áßÔmkVyîhmÙFfÕï&[«F‡î÷Pú—‹¸ÌèŸÜ‡Α$2V, )‹žs#'y´àHÇß4òª@ðC-4£žYrùÔ}n«Šø j ]…Ôvö7~Í’Œ)‚ߢMEÕ†E»î;õA ·œ0XUµü ¦¡g1ø iIiþ‘ŠQü¢ qîˆÈmš®UëNçk³‹ùŠÕ²åè×S’€€ÒM¼±ê€ ¤Àcö ýùï„|J< Ékº4Æpþ'ÎŽLeK•ƒ_¡òšµýkÀâqsväMÕ½tÜ&F½ÐD¡g!D²Ãkh9v^¤gCÛ‚¸ú­ÃHüšØBªöh™„˜–ÀãÇÂté x¦ÉsÕÅa÷a+P\®RîãT*4yäÅø½s—÷’;sïQàN  $¼35P´ô{ìÕ½½ÞCÈ2³´§=Sa "@Æ$¤3èÆ¼]/w¾‰¿fY>ºÏí逯ÞQã;fÇ› w]¶W#\L„öLæ~ ½!Æ;^P*Îú\qiðÝ•@6üJÊü°µU\[O ÒÒó))›º›? Z²ê¸ÍðÏEkõŦ î¾>e¦4aˆ'×ù°…G0ÑE˜6q«.Üñ¡Ð³Ÿ§nì­úë‚Y¿xFºoŽ’¶- õ齿î2h"ªTwŽôJßb GŽ€OÇ6NÙ¨{}àû=#¨Fœ•s|þµ_Î4£T&›,[Cá¹^ˆ¬‰÷këö>ΖùÍnšâùÉ·t³ïPäá!ú+(8øð»š&0ô Áßucé¡mU”× Ö4w[ÔܥίîFÈ]óôvyL‡¦H¦7¡,<¡ŒÒ-îTçISÊÍ­2‚&ˆ }ënOpì’ôÌbúì…¥såŸ[Æ~û$4ö¶Ì‰´½Ìáý]µ49ôtŸÜÂÞà?M#ïŠ/Ö‡]¬Ëö£gµf!|ÇBFÜ¢Á23^*Eqpöó¸:ó Ò ‘,»Nû¦Âû– úa_HPBzJ¬íœñá#€äEæœNñã䬺âÓ6ýhóŸ;·”fKZ¨.‹K‚}bÃ^PæX)[`Ó»ÔPꊆ&·ª™ÐI8Ö¡î¡"8×M©p‚êGžÎÑØ·&i@@(×þ“êîºìXHÑÎbüô2¥ÿ‚jâhÔÑ ð9sö}(™‹ôYlmâ( $#WÒ¨B•’»AµöÕáýP—cšLÁ°é«C@>O†+@Ï5uÂÏôzÍְͤ¡#áÐ~Ó6¿œ¸ù:$]Ê,6l:mP¢_EŠó-U÷Ê9R(és01üSãÓ’[ðYj‰àžn”ÜdØ ÚŠgq=A·Bv´Ÿ¿<ɳ§{@•J’€€Á:î!šÇé:u¤å©3fmtÚtŸùÿ;$É1j4(¦ÊÄ–xÜ$úƒg(ʼ‰VÇ^ëãüX«O³ “f;4>mÞÖî ¤ÒEô}¹pþ+—C6á’  ö×8RG}Û³43TT[8Ç b)윆³v{I²@x:W%9GVà­ñ¢TžBÑ{;½·ç¯–˜ÌᶇȊ¿k|ÒOR Ãÿæ3&Æ•Ô:äKT^æ)÷˜kÓ£>¬ê‡ä¡§97së'Õ¹{¨f‰Š` ¾YŸü? Ú|JV[À…wJú©ÞQn¸Àÿ‹Pýq 皎+’R¿›\T©Ìûa…¸¡,rr¬Î.®}+•¹zŸÚ¡|cÇrmøêûe_OÔ²××tT›Ø§*‹Ðh‹€žúE‚ö•¥¶p pð}ø§¤NõäŸs7š'ìJxœkíš(fߘŒ¶™;ó$µ, _}µ\“‰™SýIÜ%±dðæx³@+©þE:+‘ ß+Ø7[µ#€Êfª•i@¹ÀQË{[Û&ƒÝ%èë?Ë“%ä§Y»Ø]I¦MßV®Ž·%î€Uî£v´3Íé,Þîkõƒ‘M (!ȧ™Ž:î“:q_=™öQyˆGmÈ/¢X{0v¨ËE^Þ…:,+@Àvy¬šd¡ø#ÏŸSÈ„Š9B+›übò)¥qyâ„yC ìÿø8ý&l×CšÌ•5<Ãݰ£Ã°\"m‹Vçb!˜±–ΈÛÒ³-ÒTÏï|“äOñh~ØCGôäAÉYˆK mb#M!æÌvu¬Y¾„­ˆÚðs]^xM³Æ0íˆ]¼Î!«[sŒùÇYÙúë‡blpvØvTõwÁŸ'îMìØ pOšî%õ^!KV6¹MmžóX*æ¿ [„ÑT<Òsß,Á[—¿ù"`IKPmÍ×^±Áþv{pw½†„æÃáf_uù6Ôé„™fOzˆ`’ª“(ÌM¿Ž7@*²-¡59ta1šE,~ËòPIÖvp9Âk\6Î%ÜàìT(@1§‰ø:+bf RnMóY-”x‰7ovÜ韫ێø5ÿbå-ÄÐ>ÑévPèLû7„$”mÒ‡Ý鸑 Ã!>x ¿Ê=rý½vɨîºã-!ÍT6ëQ Nó‡Ï’€€ÈÛÄô*Mdö”=¤_æíyØv©€B ™ŸPpÙc¨ýOÖÐw í¢›b‚eØÌÄêûÿ)êÒâr³6æmiéSc÷òùô¶ ãj)–½-®X»ñ«û¡—ßNÙàƒM ‘™ "3@ƒZ´²4Pøn—D••S#gì1yvÑIÑÃ4Ê¢ÝÛç³4Ûãuæ‚ܧ9ù© 䌿7Ú1S×HN¬¢¹ *¢Ø†%XE€Í!W‰ºÞVY6Ù5½“€ ï¹cpœ’ 5x¬è Ù ÓØ'ÁBI}Èí·Øÿô¢&q#ð³¦×o`óŒÍÖ,à\€KÝ ™ËÀ’ŠâÄL¾ªš•?}.[ÒìÕ­[lç©öèT‡kÏßî¼U@OIYªîc#§Šœ˜ßŒ£^´‡Eéεä£mƒÃ+gÈ•žxr’ƒ¤$ÑGÛš‘aŽC-F3#0(bl%L¿@jˆ*\“àÏGÔ Ë?t<[9„©xO?áQÆ‚JÃ¢×æÎD?¹¹xWÞ>Éd–„1á<ŸU¸œ‘‡.¸óŽÑ÷iü¾žziÊ Ç¹˜ì#ƺtÖÊä µE%Ó°¦íª¬¸nc}ÄÂÃÀóO7kUy/_[É9` gl¯NÞ˺`b¦¼ZQøåœÅ¦²iüR4çaÿ퀢­¶ó®6Duh F„”KFì^&k‘PÒ!ÅY½{ë==naä÷SÉ .ÜÙ˜E)åïÉŠ¨T\ñšÖjñ{@1dcbŸ&–Ý™„QPÆ {ˆP/ÈŸ¦6âüVYËÕF~U–•ë\ tÞsæå÷^TñУS„9Fþ|¯ÈêIb˘ª+Í4+(”÷o‘· ‚ @²sC&©™~Äã+ÞŒ<6£ÀVts‹¾v°q/œ“òñ„U:âû Â+£®qÂÞò Hц| Û'î›4ü_Tºèóíel—õJ5KNyî"¢Û0D/oÏéÝ«&"Æ""²/T¸):ùë4Ë/&€æ@FnF¹ÀNéë’š‰ýû›`-¤3èc›‘_ŒÊ¯-àòÊiq¬î|ÿMÇà¯{²2ŽÑÅ«ÔcrYèË#L! Á«OT 'KëÝó XÅ”«Œ8„6h1ìú*F ïñsô:bÂïùÄ}Õ Û’€€ÁHS¢BùÒ€€S£DÑŽàOZU7“ˆîF¥uáW⺠EºÝ‘¤²à¿FÓa•pJŒ ˜QúN5ÆôÿëÇùP†:ˈ;·i7¨*€6wë— M6*Š‹²WÀõ _FíKâ%aƒA cb“ ‘+'Q¨§‰r¢quZ ¦{±—5µ®Þü=°…Yãoãu{ºÍ}…CI¥„ íBí7#¬–¸Þ6@«ÈAʘä¯Ã?«õ5z[%ô/¦hñœJ‘ÏŸPJ á®ÛƒkGãÍÎøzÿš‹ŒQ×<¹YíûìG* û›~ÃTÃ+€f†…’¾ö¤Å£+ýÞÆ-êÙ‘øj`"=¨ŠÕñôIsÆO›ÝŽÿãŒ~h3©ør#è 3å ãAæZé]˜EŒðmûÁiÌV±~Þ•‘¯EÑÊÖÛ&#ºU)¤é‚ ¬ËWóÂÞ˜Ínƒø®­ÏùØð¬ƒš²ì›kýNJG!#7Ð~þ2t2êD}› XÙJg¶f4aݪ°JŸn±A8·¦V-ZëÁf±¥f @”XC˪j`í·2®A—ͯ¦qÌÀÄ(ƒí¯X8“‘ðçq¾Ög‚ *óÜYmb&¬}ŽÉ@2¦}¿ÑÉŸ‚G š´æ‚œ•¢yaÆŒâ%l!éýWT‘2ۇƢw[Ù~¨,¶_û.2í<¼S¶%kZ¹=ůüÞ—(9¬ëöÅöfp«5׫Ì›kÅx6NÝ]€– ZI bkFÁ–y«†}µ¸ Š«âùuZ£*?ÚÜÈö°yGJщ¿@ölà™kMjdÒAÌä[’XgmŽþøOô®(a#AwË ŠR½Ñg¾pôfÑÉŸá >dþ©Ö»©«Ýib{Hà"5É›kõÕ1ô @ÏÜTŽÈ8=¯&´…“ƒcŒ„ÁÙŒG´Ãu9ƒ•²ÕowG»“Á–nÑ›¤ýfrlûy¶°ÌÖ r´_vdLPË”)êŒ 4ƒF¨²Èé;ƒ¼Ñ¡ amU©Ûü —j²¶Œ:]6–ÄyâÖ¥j{,·uÈ„j&£øS»¸4ÒûÅXOá\o‡úljªLôlÝi‚…›ò|,I;Ý]²5Š}q$oIFƉ½ÎY’..R1„ºÒÛ–®t—š3 Á›‘ï¬Øí†·6¡^AGz`…yœÎX-è+T­±ç¥q#Teñ6RŠ ¿âQRLÿM¢OGI´8ÂDJnó;陫§éÖ¬ÊM›')rå,Lály8$ ÔE3½A\”ݸé¨Ú (:QÖã êMj„ôÑã]#ˆj©õ¨X0Bž[>ø{#Q6qÂD€ãXG1EÖÿ 1–àÂÐjò®ûi‡¥-ªh9nx2}7¿åëUùÿƶŒÎ']®Ú’€€Ë$W6‘\OþÏ€¹]^ 'P¶PT; EµíľÌ8:+é¥.fûyiVèÓŠ00e¶ôé-?@ÿºK¾òîe|oËÌë5ÊÖ¬&ØýƒÐ˜iš"uƒêþÜlÛˆ˜¬£=š>‰Êã®Á§b(d«à”6µiŽrš’»ê,w›m³,6”yƇ¨©Ä켘›ÚY‚u„@«°r;ÒÑé£W ]wóÈŒv²G9œ¹ŒôKf”6óÆ+×Ä,€W´±›% 8-Iv}65i Ÿ|˜DµXî'–‡½¤-å'‚Øêqºv8œi§ëËc¢ýgu| °ËÈèÁŠ<`§=þÑy5È{R¦ƒ”qÅÔ[ña›átÈÂ0À\‰{ô&¼gˆ!Áˆ eÛ¢×7þ{d5ª¯D¦É _#ˆ±¢;å„yuRÃK¬›p–½ZÌ™ÅËu«Vo¼œMÀ¾]öý/¬Xßÿ!k__<É(žf«éûˆdgNô ¶°Ñ·öŠ„ÁÑwP1؃~ºËîyôƒ¨ýLÜ¢$Yˆ‘áÀvÍá ¹%âI)ÒWÔ=žÅ`xƒªéGX-‹¥‘— ÇÙO¿™ÜŸØŽÝKÜêõ}Q«èŠCÁï÷ ÁKÕ ÿ.áqê'ÊL|Èœ7—·wÚô™s¢µì, ÷Ș½n¬ÈxD6¯Wwuºdzƒd9ëpü[|álÄõ`[TšËS™nihA ˜¡K"hf–;=êà3öĈqíô–P;:0ÏB ºï€„çwŸí` ÓÜ;%÷ž1·½ì!Ñû§8r!ž[tBMgÃÈ™ÞþcI”A³’÷Ûäþ!|ÝÞ'J"–fÝRˆÚ²$A0ìÉ*ßîÃt)/~eÆTEÆ^Ê’ßnÈ7ºÑK߉k˜J©»g²БKdÿS•š1O‰/H¿¨ ™e4Y²y¬ õÜõ¯†Õ`Ĉ4]uÍöBpƒ \† éJ‘üp¿U4o͈Ã#ÈÌáv^‚AðNÒ‡œ¸L…r£vï}Rô >މ ¢{iMÙso{êöÃÈÝŠ²rçZEÊ)×ß*ûë,¹ßuaõ$±IÕBw˜|ë ß‘„qWzá£ô_‡—ÐôíhÍ×@åc¨ %溟Q›÷)l|}4’€€ÔØÓնàDögŲ̈Ÿ¬î .Ú+ÀXÎfBŒã·â§.¾‹ T‡&޼m¦fM¹RÂ#èE˜gpý$Úƒôe±ÑÒsñº5Úgô›k "[êÌk)ŽX¨¨hlŽ"5CT»™ð3ÏÁXd Mc8¨®£Ö_Yë¥Ãó*ä^4lµ.2µoÎö °šsõ¯‰)þöØÖI—Ò#óo0Ž|]+_ƒ?š.”žÜ©\ã—äŽÁðò$](t”ܰF«ÿHQÂK= 'œL4íìª$õaÂMfö´ §.ÚæåŽö^âs­N>X;$PŽñhÊÕ y Z«4^Í•^<[ž…ë •ù]~ÌÁÒíš­’²wèÃFèñÕO1²…ƒ-aà}VÉ•fŒ €B„Q×I8<‘ºWo ëÖËþ‰òà`_5׉µ¢˜È¿Þédú?Çá‚þ|PbT¥ÅVI~[Ï ¶j*‚îŒ2FĦK7Â=Œê6Ç4¢xíÃÑ&îZˆ®Þ9{ãÝ)²ÿ”?úÎ AtÎþˆHªèOø¿1d8=Yª2òî£(CÆ,¾œ&æÏdB¸ÝAû¬¬òAAÄÖXÙµ‹dʉt:§ªPÝKFùkO!Ài¤Yõ8°¢•çSYIîkF³ÃvØ‚JÉc²*Iê¥ï ÿ¶æ>ÍöpiVgàÍ#ÁSÐVÔ˜ °DFÀÊC§,Üä?sWþyqþ¶ýáבLS]Ò#DB˜Ý$«ñÝJ-ªžƒóñœ>É2ÖA¼lzd;r èÜñé:Z¨>Þ= BIŸËÖäÿRì>}ŠÁíEN»(¼‡…çÕõÌŒk#<䯅œ£ô´o§ZÞ*ç¾·*KT9QÞJjbkÛ´šDÛ•_kéyÖä.« ®¥²0ËÆnèNκWCµHÁãåPàrÎůï^Ä—ÝvO™õb±¬t±I͸çU½D¤µþûàañDPÅJìo"žµKg®aø7"€¹bCÛ¶G&¥UÔ@ØAG}(õ ´qc`™¤×†aÕ(Ôܺd‘4ïDݦx‡;Ãâ ÈÃÂÈSA›YÒ1›X„+ˆêždÇ%ŸÏ̪#ãøÈ¿%͆ÝÒÏå‘k0G!º¨°fŸÅ”÷Õ 8…”’€€Ä[ij4¹âœíj<¬å_¤ç^Èd”áåþ>7ÇÊ`³B.õq‘,{Ú «Øél::$–4oÿ¨qÞÆ@>´o43šlc®^t‹b4s|ä›pý[ Ë>ízN4ÆZ÷æ€ý´Ö œ±æÍU×]ü…7:Ÿãh“4•Í]Aå6çyÏ/ö Ü€tþ›L œ‰Çøt¥7-0HµDábº||$UÑ›7@euK³Qˆ8â=u ¾å<6Ž¡;Ÿ’dÑ2Н‰6Š‚Êäo´Fü%xŽ…úäòÚ€±’ÍþåqÓïÙ( f*äO®:Ó´¶Lqy=9HüÒÚ÷‚§ß=×f6Ý3r‡‡k,6l‘ã]…ˆ¿c*2@¢•hzœz>Ì™9#^ÁI(%£ÄûüW´qŒ¤m—´<±äíFÓw”¸"êÎ LúÑM—[aƒ¥²Yž"Ä--fƒ “0F›«Ë’‡»MþÌÑ¡èÒÁuËøk¹ëhHÊX(³óD31Fà q µÖË fBëw’€€®ä5Ëk#CˆK36dtÇ=ó²áŸRpÏÑ©hK”ê`ùòc'­'HâÓLŠù{Œ’±[ ¯ ÉÓ— 1)£è˜bÊ\‡ATLðñ.Sön(é¢5raH§ŠgŸÓñe·¶e­ÉGQpPó3¤^’ns4Äëo°4ò#Õc.'çEæ«æiW—©xTqw­,ê"³|QáˆO(½ßÁ›Ì{´ží Ðæ8~k¨PM Ý(´Ïܵ’íÎp –>-0©ñ#…) aÚò ÄÆ:µ“‹tû_ìs·@wN¿`R>µC’À*! «*ÀÌöƒr?“øžÞÎ^Ý­k{M˜$ƒáT÷ëÔp*4¢Á¾Fw—‚uÁކ±¶Z$j™àI¬äJTâ­í£¯ Q-bÍÔ‰„}û(üå]‡¾"y¹óÖ¤ûËÅÊ}’¹CêdQ™7h¯àƒ@̯]5ëñïÁ ûø¿íÀ¤Ü¨©»73#Ô#08Îs‹ŠÁpøÏ¬ÕÑÈï>˜`2a÷›o:äÞ·ëd¸‘xº¢z{.¨p¨%ü©:£%ÐGoøYKÔÈ0^‚’€€ªû ¼(Ü…²l’ÇØKRË.†Lèªlk²X÷MتØå¡[²ÆMþy$QÒÛ o×3ò©Ù„Ãï%ͼr#¹…eXÞgšÔIL32ªFº9âx‰‹Dº€K+='¸97F­l3ȯ60ëd²hµ¿€LçÄÕMy¼±ä‹¡m@&A’o};“‘÷\÷Ž3AÒFÇ7[âÊ0Óqå̦øê<âi4ùË!}[ Ô³&F)ׯÉr@‹3ìaU/Ç|èܾ_#Àƒ³ãg2KV uû»ŒëG†0¥W.ÜãqàÉ_Òš]Ra$?bEƶf\HûzÚÓ[Ñ’ýQþ¿Ø9¿DíÒò?¹IfÕÄÏ8~{èÕrÁ.¢öZ8Nû…Ï:µ´]pÁ]6" ©&þ‚Ó”öËÓzðÜr‹+o™u5}öïÏfJªµð–$zûqspuöuxã  iÞ["qhÛ~£c`pyÉÏ™ÛÇ7³¼ëÉ ë;ÐÛjz\C‹G¤‘7Ó•? ÷L½hü¿Mï9+cDÕ|Ÿ¨7 &{ÌÉ<êç`†ö(ÆõÝãžûXMµjwÇHþ~øÏ‡DåV9í÷ݧÚ:ëÂõÚm}Ó,.ªï,ì{ñÎíÛ–ô ø¸NäÕà¢ÏêÃ.ââFÓ_#Ç~7·W׃ø…B©Ù¥—2‘ùÞý̆GsM‚z&訙L½ÈŽßØD“DiÝ }8)ª j‚”xør Bòº?_PùB;%ž}9ïêJàÑæ¿-ŸÉç¹—Ú†JBŒ¢‹š@bJj¤¯——¼d;b`÷Üâþs‘¥ÏÞî’€€Ÿ*Ææ“›âç®vCõº}<>\ÊD«¤Ôι"«)@¾‰€Å%”a3WšÖU»3oO6G¬¼ßá#sz­¦W*»ŽVW«(»û[(»NfH ²2¥ŒTÿ m:–Âíºø®¾£ýÀWЬaÎuŽXœ‡ôNmyð¾MtÊ™ûÀâCr…)Û¸PÍÝbžÛ…OoR-J˜tÊŸêìk½l—YvŒôQOòEzs‰˜ß£Zß–ûDç·ÄRÅiÏEâÍö,t¾÷èn¡Çõž¼w%ËÐ ²!?s?’Y`NŠ|:–3±ì5=Û0N~YúçYŸßCSÔ4€,ÀD»Š ©C /§U|©çÒ;©’~ôA\Hhĉ^ü žKÖ³#~(p\ÒŽZT:Ê[K9j»­˜üÉŸrp¹@µ•ؘ)»øæaxví12’«jŒÃÖÕkG7oä€n d <=§¹*£ƒ=R¶þB7êÜš¸O£HXf{ùð\hk¯Co¡± y:s«ÙÑéðÆ“ƒØ(”3:Ö2}MáKú:“AŒ\åÿ+ÜÚGùüÜèn…Ì(iïçwg"Ïo‰ +0ŸLqIöÃðÍðê ´O¯¡3ÂíÙ}ÎÉÑ5]ÅϬVƒ0•"œ t)ŤWТë°ï¯«Ó–£¢‘ó9ÑTº}U9¢¸6ÌÆuì¡M žXŒƒàÄ,Ðê%²Ê=c öƒ|}Ee¿o7Æš‘»Që† |œÇ;ˆ -‘à)ó³ò¾œpЀڷ¦Q™å`N¸°ÐºäÞÉÕ{n÷µiHÁ°ÉïÌÁ„*AŸ@ÃK÷B?çÞ‹_8‰c ³K±‰ Z´M{å?eA}:<1æÔµi‹¤â¶c\.HuCr]yETÛ¹ã¸de'óM”Võ·>ÃÒ•4ªh‰kÏÒ7ÿc+ªµ ;0B\ЦM™3µn®N"]͊ΚcÙ\uEmT¥Uçv•1'ï|Ð`Å{Aˆº˜Ê1'§!ä”dªÿz%«ãWíw,æ^<àÊÕâ·†ÌÙöÞ5I ‰ýÔ ,ç«6o÷(q·gK¿£ ·àërÁ8ÇóÞ¢à«;dh„€ߟöŒ¹TI ÎIžŒØþdn €RzQïé·' wº½Ö¼ÏÂÐñà*¤N@p/™ØÄ™{hÎI™¦E¥7-OÜh¶‚$Jôƒ¿s›ëâtšy-*™LÆçÍYgÓÀfT§U/aøyǾ”œÐ÷ƒ¿RxQêòúÅñÒ Gæ6“²'Bíÿ@'n€'á®8âs5o“m*Î’€€Ë,âmK,;÷CD˜ÛÊ ØÀ§q¨ªˆäƒhøûnB¦%¢û]ô°óuÆmý—½:ß\°à!ó¿Ù¾ÐWß ±Îƒˆ·3ŒŸt×TdRûÛàr°3mÝ/”ä`@‰¤i³P‹á*`ßrn²ÃSÌxðþÀ0\=´DLE–A¬V˜o'0ÿù2«ÍŒ…j‰8Na£Rž›qn¸‚MEÉÜSáS‡iÌèGPWr= Þbב5Ä#Ýwác ݰÑJðeò2QàL‚Ž0d T6üº}Ï'uxîWuÃuY³)wÿŸg †Ä˜r±Ec ƒZÈæbhàÈOA8›DÇyyœ…‚Þ)²;¨ §‚'Q– G¬¶¿è¿ì°Á¶ïƒ‡C L¡†œ ¬qýcŸéÒ¾Q#Ä»`Ê¿ãôÙõ®<ˆäJi 5OzµáPÎ_NÉj-‹»>¢×~¬‚3ºÚ{d‡hö’òtwxOè[C|ä•ç2³ß‹­Á—`âS‡\I,€@1FùàW!R„«”<©¥Û]„+Z{Ù-þß"Îÿêö$º,âf!Ãè»SI`û鈢¨Žßó%§¸àÑ¡Ÿr¤G}…ã=°íŠK”“Ó.ÀÏóX@€¢°´Ó´ÞE^ ­*†?ª¥—¶Ÿ4¶Kû?’pÖŠ—:Qˉé:eÿ2he,‚·…k±×´ïU5ý%Ø—4‚ -¸¼ÜÀé°=9Î{W»h0ó¦·¦5[‹%slh¥lèÏ5I^ pÖh«yGÎK-ÀýÇ=÷ÑÛ÷&ìcN'£_™E¼ÛÂâ}ÊXãTí6ëÅ([ëã:ðú0äw¿ßNévüèšI›dTç„r†Àwï×áóTBG³znŨññS|4è§ë)%JzÆMšøü´eñ_˜ÔzèÏ3æFEþÊ£ýŸQú ‰ñiC.Í»ÛÑãíÅMR<=­ïíh»@[opv†@zÙ*(š)¿«LÛÕì(;m¾%K^´ÍN¥ ~W“™‚(ø¡ß(dÒÎM-ÏêNÛ^J8±M—9úœ1òYi•[÷8«5tùÿ+ §Eþzqjê “|.û„޹<鮎Ñ êuè:^FðÑq¨w‚" œÅ.±è4d(&É:¹@y‹`ÜY#JCÄ5’€€®Î°ë暸ZÅ]ž4©‡Pü›j ˜àqvIÕ7wL¤m€íè¥-žI»Ö&ä¼¶Ñ@AàA¾‚}YïWYŒr†¡,Ýàd/q„ž%“ø–s©FdFÆR%€’²ÔÓm¦˜W ¸e“Võ‹ïMþÊnpO¥ðY‰åëœçðµ¥ èrš­hKÄìÈ0\§p¡nâ&6ä#þ?ç…µ>6ŽVÓC× vìš¶ ¬ERÐÁ}¡»ºèîjñÄr?Þ ,ItBbyæIJŒ~Ž9šWŒ '!˜†öXÅ =p~eë×ã÷%;c¿™4®Æ67xÎH›¢…¤+7ŠÿôÌI}u!@õ%Ú&`Wnn2:JZãž\²È/ªüDu?Ë>È_~ ‰MŒ ³–|q!B?Ø!Dî!W;ÞL¹±‘œ&åã2µ/‰|­FÙcaÓŒ&²F¸LfÕJÚÊ÷pöŸ]²ÃõÀ¤;,y[Áˆ\µ;^Up(d ÒュÁ0O¸Í~ ².ÍÆÝ¯Gº¦†80%$X0É;R|ø—Ø}¥üšN ¥d"K[Øÿ£Z>#úÂ3`îUÓÑl_~FOÎkZŽÍó7¾uLšMû‰MLÊô/ÖÝíÚJø(_$©ÿ$£KNdçî-tük¨Êz9Â_;DLjô"‚5$wØ)К`=‰çLâÒú4Ó§ 5½%úY¾í–@“ƒŽt«LHD\)X“Tyi…{Ú ðÊ8…7øƒqP?Åh-„fŒ ÷LŒ‰€ºF©6â«^ŒàGO—ˆ‹ÛqžgH¡AÒÁ)W¿¡ ˆË‚ÀÌÒÐ!è¢;­¸¯ÜXŸKÏÇx38¶¤Sk[‰§pí8¾œeô•Þ ÍÉ w½8œúÔéÒB±2$Ž3;´üƒ= œ¦ió‘÷˜JÎÚiQ¦Ò†ù3À¥’€€ÏE”Ás£äö÷z*êy£E”í&jeYóržFá¨1ô…³Æ¿°ÆªR½›Î)¸ÚØôŽu eê´‹øziîh9 {ÅN&l¼,f8»ëî(Ù_Ib¹wvSеÅmÝ"‹ \ëkbLəޘ÷;Ï# ØÂü¿öy Qée×9›Í±u,»F‘…<ÝæëÙÙXRvçû`p×nèÍþªßÒ)¦©À©²Az›éÉ¢ðH"m~ïR§ç6ö-80Tkœ–Ì(ùy`핊£ú-ÿÌçï8BBn;~m‘÷Œ×ÿž·dD*s5‚\Hw¼£ChfôßÖ(#ÍÚpV‡ø(Œ]œî;GŸ¦]lm†ÏíY1÷âjj`RÍËq" ¯~å`-R}Öά‹B/†+½_ŠŽ=—ÑDå èêñÞ“­J@[Î~[óefË¥Ð_xcíÄù™,F¨Da¡s÷“HqÓBÕãòãà¸ÚYbÌeˆî°MøIhÛ¤Hª– ŧËl+ :ÖTõh‰&ðÖGÑÍ&W›øòÞyIbÌ'ÎUÏ\€V£›ª^Jÿ‹° +r¥«Z ðØ8=VpêZ…ü>sQ*Ÿ8OSidAôl5~F(˜Øý+xÇTOþ·u€xý+P÷ܺÑKÚ‰K3°ÁmûwÜ”oõ©=lUyïùZºV¸SjìÜÈh.Qºµ‰e+ôGh¸spUtn™g±†….Â\Òçé].’b«ÌG.kM²íã»7‰Á2CªGi7.x¨ÁŒ>ûÁ‘žÛYÚYÕæCG ¾gBD[B/‚íûLôµðûÞY€Eˆ$ç`»ñŠ—?Ý$p•1ÿ‹²pXɂȪf3{a‡0ÎôacÚòfœ]0Ÿc¤ÍpQˆõšõM­çùÌö¡Õ娶_ïx»=X²T€ýk(T]õƒ>õtë^KñüK¢KÞïÓ”¶™)%ùº¦ŸœÍš¶yh¸è|¡2äÞ‹6ûÒ[Š|1c:À¨ûY£¿(Ñ o ®Q{öÏ|ÚÌ*«PÁçþâìû´xæ2K€ªñ/~%Ì÷–›M×%9EÄa…3ìGƹ³Œ»2D5’:ÉÞ•…à>Ü7à˜Ä±‰ÒŠèss>×ç–Æ,Ý+VLñ"Öò9ÞÆ82C'‰—­ü¯0’€€çgFâˆ.©ÙàÿpF0µŽ. NÉ^u¨¢Õ]¬ù•/Ì ŒâG;½ª’·¦6ÍÇÉõ@C2ˆøÙË¿ë³Ð–2 Ô×i_÷YJšÙ¢Yþ]>³ý°¶ ¿ñEE§ †D[ÉâèEúðn!ý¯­\““-Pü”õíÖàå”îæâb§õL 7V¾{÷s8‡eqih Æÿkß•03¨s£²”~þ>®M[ CV‡º½ŒLF³È„†¿JGã%ÒM¿e»^ž hS—â™lŸCÅɆ<õêC¢aÝ&Ýæ¢Š^.Z~2à%‡},J›‰@b»QΪ4w(ÁIŽÑIY;˜j·áüÚ€h(;dªj/Lßö?u÷.W0¬ˆü}àÏ8&|z‘‚‘îSݼ¢ŠSêK·*5GÄ8÷„]üž«È£pòý.ìýxi%€'·÷¤õê…JÕ‡Ò.†]‚óØ4—›ý—ueÍsïøu>&û£ÑrÈk‚ ©µ:.«oÑSlØ À}ÂJó“w /œ“wÞõBØa=se2•‡ìCõG%Ä4¾XLi€.;xõËd)NÿFFê;èHÔfš,x4„às‘Y†mé£sÍü!ˆ~]#:O2ô¶¥ôݦ·Œo¶'SµU½×Ì€uÝ¿’ PÍéòNŠƒ?R{Ä~åŒO:cÝÈ«LSå…•òýÐ+óÈŒóÖÓ`1rÌCI5¿Oit„ÃŒˆ3ñŸmkMýG¥Öý´¨`ëxGÃúÀróÜ3Tói÷lCt,Xyݺº{ '÷TfÈâϸ6AmOûAë×ß ´Âõ¶´ávã7/ß‚eÇ:á#¯Å÷£”;Ç­á|’(aË*èÖÀö6¤€UÔ"; zm`Œ4 z“L”¬‘¦’€€¹¾ÂhZ±Ò´Y‘ ÏšQdàƒa¥ ¬‰Ù«¼òôÎuº¡C¥¾š=cn>BaÁuÈoF0Ô¤JÜåó$ýTÅõñ{dáO(Âÿyƒ…ˆ¼Sßœ¿Oª´Ê ­="3w6+ŸÄƒXñpª#¥‰cÉŒB¨,þH?DcÃ\õ¼«vȹÀ¥p¡B†{÷gN»ï×3ˆ¶¥ÂQegnf¾6–xöZl•É–Ô3º}ùõZq3SÄ%/Î^›°•ìgîè®_üVëûÔ b~×3n)¬{è1³.nÖ|(ýTÚ:kD–Š4.Ì:Íç¦|[ÎNÝ3úzªÃ¿yp‘ÚïìØª.eíerµœ§æÃµ Ž€õ°Ê šàctØ Slå<‘¨Žp·êµèÎIŸRï`…±=˯Õ?Ÿ§t]‡¹Žv4Ÿ4zIóò&lU·’ ØZy»å*–`x3e(× —"O)×S6×ÒWr¡üH°Žqî0;ßÁ– Ã$J½ÐسŸ eé³4ß>©C–{¤–YnJbsØÓ5ÅŸqxç #¶‚º{¾Ô²›¢ç,5Òvkö¿[(@¶Õ`ŽÞw†–½:¦8ö¥­ž B_ÌŒæP‰zOã R@Ô3¶cÒE=¹òs×<¦ÜI&˜™eú°ÿ9YÕR…‰%\èè1ò&!§™gEàÕ  îH³¤ŸÍ¤ %Ñ]¾”y¢°C‰ž.7{šte)nt…]–Aï˃覈¼¡ŸË½âƒÝ¦SXüMé§¾Éûðx;£äâ–Ôð¥â^…­ Øî¢ªÀ7Ž5(«X fŸ×hu~[‘>±r†ˆåQ} ÓaKII<>ð#P} ãí®–®axRFì#xÁÆ’;x ŸŠÃµ …þÜÚ4o¿Œœ$N<¾'‘ÇŸïPºù+¶Q뇧־Ÿš½(ÈUßqï÷Ã'#æÑ¥Ýjvû¢€,vüawsý«$î ÄþmläÞ2:±O—Áw®çÁ³ÔE£º“¾EÓÙn{i¯,ß_Øsx_‚ãÅv!› ¬óù>§ÒÌQ IxDÇŒ¶Ç_V'B2fÉØWŽéâòf]°Ã87ެ͊’€€®N=)Àj×Á¢Ø÷Zùήڦüa5$Ìœ´"Šê× gÓhy~gö"Á>NöS?h <9¶ÖÝ?¾¨õTà7!\Çá[€ŽüA|ðWʦ—)H“6!^W±<ÊNo ·ó ?Q壴®¡mެa‚Ü~þº8‰×8“µV¬\‡ûÓ‚/Ö‰@°ØvQº n\¿Í?F8`le[h àª™†bß¹¤)+q+` jE-"*ì*ýøæ%àjwGOy§)¨¢ KÕ“ÂàÐÚㄎçé*"̬u(‘6à6"áì+%ÌÈçÖo¨†–,ØMÌžÍV‰«E‘ÒìkáÏAx¥Zøª?’˜ÆŒMUÿ\4‰äH.¸¢i²0ÏëäÌ-HtÓÁJ|üʱc™ÍðÜJ fô›>ì6UãeÆ6)*0Œ›å…už¦Œ¥DŒJ% zÇ,sY’÷d œ\bì,wp¯r»^9ë=dsèù„_­3Â|Èz!$ïÁ0ûÕVŸô}u‹™š8:”¥‰š6V§gçhP³ÿ8a²#îJåùEÓ‹îv(wäÅ1ëTÎÐ=z§/!QM%^ó>¦HÕ…ÜŸ ôH8–„y7G«ãjZÚá„9ºòp{Y9W9W¾‰iª nëœÒv÷HZi#¥âŠÌ7ÌšrmQme$ЈÐ)þ=„`_€ŸÝÔ Ù쓨×MxÓáìÁ0H)"Ë0™. 2Å ×q˜yº9°•v¨Ð85ò› Ö“xwòØŠ˜ÒZÙÌý£Wq壟Ö?_aÏÅ4Åjþ+!½þAÇGÚ%P%™Ý@[4e?Äø“LDÎ$Þ½HÂÈNoðˆ¡«º¦`OÃ$[õæ×Þv!Ëë5¹‘—,ãe™l¥–½Ìrš„El.”™ˆÖá¦Íú—”൩)l@%Ü^ù DlN>LQ &S<>xîLq”=XÅ/¸îe“Ùh8¥Ùþ,Ø6 D†ª†“HQT¢W³Ãï§"mtNQ|pÐ_º0yYrîW¿,´íâJ•'ÝŸ°NƒeçòÃQ–Öñ¶@>Ÿ£ÑÛThßz££ôp貓cü¼áÕû‡TapqÖ.@hÅ?ˆ(âRÄ K³yÑ.—¿Anü€•$ä':¦%ã’€€¿Í3ƒËSöÚª9Óô±Ĭxô Ûã§ÇÒ ôÅ-Uq‡3øYN'Zúœ+òÆÆ(’ßö£A!'qØ£÷ÍÎÙ —#x& 7ì¯æð.ä Úÿ¦Ð;Ã0#8áØ‘0,%{Ch–²O.á±ø¸K‡5 Í7—|Ì(X&”ï¡çÝîþþv]Ä-á0c1EXž‘~J36îŠ{³‹o*7kdÖ›þÏÚ<€0iFÙ–bz*ýhd(0½i`ÇžÙ3~QÆÚpö+PAG.ƒ³£ 7&Zúø¥gßfRCÖ…AÛ1ߤ™«¤óº½nV·Âþtu¼ÉT$I,:Ñyè…R€Þ%=á—j¦®¹}Û›Ù,Ó¾Ÿ*³ÇŒ¤N\[-èW§_8ôÁU5ŒÓ¸µç]å¬%èZí Ó¯qÐþ´ðv¤•ÇÕlî$nÕ4:»M³Î‚Å ®Š=êϰ ²ûLæ?(ÆÔÞ"v—õ¢ÿÄ×&øñ] ýDà\Ú.›³Ç&÷§×î*žªr@š~¹Âœ­äè—í•rÇY„üS4ÀX…¦ ±+ua‹ÕG‡Ê¢lût6о’•2}ßeø&¤éfÏ…_9C¤ï¦·µ,c ‹B';ìÉI±b§Õ Ót2s'!·í¦ÒÔwÃw ßåýl2_VfWt/ûT¨‘Ö×Õ1œ|´YGÝ&èeÇD]ŠX÷“AâS> ù<Þ?Ïc‚bê´j@<”*ÿ÷å)vähRèzïš®…çÉ’ÅKNƳõ\Tª{„¿†õoWû#Ýå«À&À²ª5T…X† ÕƒÌ_“"íÁÀ‘Ü\?´Š/FïlÞ©)ôÝ™þt™®ƒÝ[ðõ÷LU©ü1òãNËÐê…ÃF14½0¨Œ5 ’í¨8¬ßI|ËmÕ‘³áHjÿ—é *d˜XØ@)•¶ÎáÅ7‘ TÆ’„Žße/·.räY/1qïÚ)¶‘´=î,l\ G\œ¥Œ¼m0Ç\ú(Þ¸iI¨Ù;S"D§ÜS@=¨ ß .Y3°ã}K§!w¿Æ½³JÔÁ(CÙ>w9 (x\†¿U›’ëÊyàXXìVˆŽ’ße"„JذñÚÞ¤Æ"SãSÝõpS´+Šßu˜Î‰’€€Ó«–K’Ê Åî³`|”†§28}Õáç79`‰FÏ)mËAà4"¨tŒÔß»ø‡àoá/4¡,h”[½òwfãèá³c‚kò†ÊS²m{Wf³·Ø—‡!ß³Ö˜™ü<Õ ‚î@{Ú€ ^…:±6j; ÷åUpÛØ·7éÀa KHÈ#»†­X:˜xìåuÒêŒVïç¾Ä¸ ¾AV…<=ŒY÷äsÑšIùÇoÏ1k³‘¹ãìlŸ»9Ægm-¾Goêè# ˜&æ…ç©à6˜Í)Mˆµb (Í#ï÷•¿`£©Š±Žã!‡UÄÚú¾ùZ¯¥›+kì¾…M©ûG¨ö pdGæ'tK¹šHÕÔY娼 ÙpÕÉí©™´kRÞ²ßKúgÿ•Pœ }tÛÌTPøZq³&ù¢\cØéõqÁúß2ݶ0¼Ì—ÓÚ#°I‰aÜÊtù‘žìúrÓ8áEJYÀ¯*μ€ñ4®„µ¾RGÆ—ÎwÜ0¼¿ýØ>ò&n¢ªý>æâ®‡Ãì"1h¦)–S‰FÂ^àä)Ö>`(ŒEu;/˜²P ëíóƒ-~‚hd$˜$ThkÐ5ñêÐþ[¼k´[ä¥eWÿœÏÍœ‡†í‡@­{£åP?¶ð¨*s¬­ØnÑ=ìw§µ_Ö}=î•gd9´•Ñåf¨d_ÛØ‡‹u6‹ÑñTÆësñ¾ü&¯ 3=ePf!_[láXzxK;_¶Í+Ù†¶d¤†åÚ~HТ¯{¥T2½Ê˜¦ÌŽÉÜ?eí9ÔH½¸ãP–-«¦ïî¿m¹rÅç ûg­Òž6O— èŠz0+%3«èéT!û?O õ×”kóœjK‰â:œ^Î]ÛV‡\?‘îøZ <õ¼'ˆPaŸNK½>ra¬9©;߯1páÜü·Êð»Xm“IÞ¬ünÒ†÷Èó•õ¾ì\‡þ.­¿üÊ™è³âSµ¸ ¦.<ÀÚ˜J?m[ŽOBý<ß¡ÆNÕëýéWö"œ_Þ ú™œ^ÛËùadYðíKh›™É›lGZ„!ža0‚ ÆKš’€€ãàGz”n¬Âím´¹ÄkgR†4B÷uÏ… Í›Wf0ˆ# *p€7⿊ëe‚¦‹<ùÏ:Ñ17en&XÄX‰Òƒvf™œì—¼9E?$ç‹CØÃé™õÝ©eóµt êí‚)àSKõ^FR¥±…O¼¡†57‡fš.Woƒ[ïßð§ÆÆd?7µxø5¯€ÁUÆðBÊãýƼtkpÈEØ•¤^nˆC»¢!¢\.@½/&¸—ú”¸kÛ¢F‰®vÍZ̸Ò”zFt½ˆu€°ÙŠ·¶MíCÖþ§Ž^zçï\äáìïFïq~…©n;¿š¬´= ¤1é+WÇó°¶°²¯"J™=·Ñ#Æ {U2MAþuà¢p\(œퟱ·ÔV×½ÞÑAw°Õ’FNLÖçþ a×Áþ•XähÕó¹®}0™Œ;+ðU5¥—<†ÏºZ^#ö<(·-]|\øéÅú<#¿µ|E÷ŠÒ &%ÀÓ¥¶ö©BbŸé-+Ûm²ÏU÷mçÙ6"†Êü·(:-„³Zî$ò×ÜŸäÔü#ñÉ78¯¹¥Ó=»T8*ÈD[¿ã‡ë°ÌÂéÙ¤YsÓ·ðs´Œa´ðQøªc*ÃÏåÓPªå`<ö»IÏ áŒQîò7¢ö ¸éÒx«5g†#IüJ·yÁºä¨cއ¶÷Òˆ/“ˆž2(`i®÷㾎̀oNÔÄóWâtD*™ÿþ@·¢çÈ«¤5Ïu/lB/ñ½G;‹”Î “Ås[P'ó4dK0¡—óP3§Þ¾ú“~üôâLЬÿçÙ[‚ìÞKWïí/j Í¨ÐfÍðbÃßç9±Üdè7©ðƒÄx÷oÃ^C}J)ê,µC¹Ê ÜWe<Ð`½±%nü4ÏË#a{r9W`³”Niÿl8<ù_ÜYÄŠÊ£]Ⱦ€ kû¹-ÍrŸG‚¹Î†¡}Ëq5Œ1ÍŠK? ÐõüŽ˜²ñ9'€“P,êL$5Ï£ÔàMª›!É•"Ã:^š4ŸHëY ½`Ö`?=•/|Ï_i`””ëñ+¸¨íMßé\‹À D-¨ÄT+xé ~ü¬ b½.ì½£À\%²8x¬/ÜhÎí\“5‡•O ûÚgý„‹Ÿ'VòuXïcŽÚY•ê0çW=cjÜ&² Ü’€€²S,Q?€)z²Où(wJµ™RÂYbXbš6Ø…×jÛØ'–?`ý6?ˆ…‡l¸¸Hm ‚£¢‚NÝ Õ’GÖ 5µ²á˜?å‡zrñå§)B>?p1¹O°Îõ‰:߯q:Þüh)‡.†Óæà·¹p‚h=z©›E˜'oPF»€FJx3àCÎßE©1ªåÄìå_?ív>ê|r âRÈõ{*kP0³o³‘òó vâ{”0sß*pïNȽy(¾Å>—4òV/T K³]ØÃþñµCÚÃŽÀÔ?]÷—P:± @âð‹YþôeÖ1}Ë ›Rª–Q[¿SpþzP¬¸cZÔét:R\Š(mÂËËyÇ_×Ld¡‡L0¼ŒÜr/Ù½Ä÷iíQåj¹Û:êl´|5•tYÝz¯QVñ½ëùþü©Yöò±Ç/éå°Mæ,¬r·síÍ;÷h['ÙAÞ®v‰FÆ4 íÜÔ¸Œ·šxôž¼ i®òø$ÌjÂ3gnå ­ «lH4*ðyRˆ à°’þç%øò}kyBHï´oøGÖØõAä + É»w!k¤M‰ÂL-ì;R¡­pÖDÞbþaÁy‹3¯¶@u¼“§ƒü±ªjB²L †ŠçÿÃhWÚ¥„ÜOmÇ“ M‘/'0ž¥¥0äÑ®k×f’zïaû¥^òþ9d–©Êz“ˆúú¢BìCvJÛ uV ÅŒVZDÐGy¯,ëFñ ÿÓŽõe¼%éK>küròzC;’€€¿L¦3 º—þ®$#i>>â{´x¶†‹b“ñ*˜Qé•çJ£»•o­Ãb¥i× ½ç^| í œŸ…ÐÝ2Y¼ç7®ÂQ=©(/W„!–$T´žB›Ö ;âãó’t¥<.ÏÌmÒ«Ë¡]ß.lÝpOÄš#ÿÖ>B©i7ãc¡4âb uoª¤êôƶÄNm¸òôÉæVðE>…´*ÇjÂx_¸ ÍŸ=í™Õ“†Gwµ¸>ø›HBv#ÍJEÅ7•Qv]Iƒ¤9^êæ£q®¯.C§‘8…6 4J«xúïB2úz¶¾9õznޏš?¦%Âß3«ö•Û‹ Àl$¡ ö‹”1¼yœz8–VìÔêt«I§žò€Ñ\·nU_×yZÉt:öʪê cÍ(¯óÐlè5ˆ¢1Ýrs‘V!›öR£õÊX²­À0^¬†ë݃Ç7õçDÇž¹Rd¾"sŒ/òi‘$êYPeeáð¼UÈ\m-ç80žz³¨éŽð!è2ÖçA‹_,=2+mÜ yÝáåA®™ F/Øpzró4Š‹÷¥·[êØÐ_õù[gˆu Üäçqè þEûmÓb—^–ˆ¼ZEäTdÔ³˜„¸©*ÚÙ*ÛL(+Y//L]s–€ i‹ËŽþ;‡EÔPîWÚ·Ô4å‡#&ŒØåm¢ é3í¤_½—~ÒkëL-$°*¥R®xÒù2&ë">b}ÖX¥‡ž©…ƒ§„}MfÅ2ö]Aµ D nį'±MçKÑ¡¾°¸–j:üC1¨Ü‹øm+2»£¿Ñš SZèß>L«Öi%gŒáÍyTf$ÁflÒ»U£rŠ1B0†¦5{è*5JsáÔ5"( :©0½cã¨??ãs–Ï3vÉcìM\IwÍþÈ“ ËeÆø;!4D6 ÇÁ`a«+ijap®Á×€:«µÿ\/ª›‡æ`ßu†#ù‹ÈårxVg©ëöÝW)Æ©ÚíuM\ßÒMɨXý=l™£YhSÜZ3•É,ãœPeá¶P@Ï>C|ük~ˆ™M}]¿w`¦jÉ傌>žÞœõJLOJñÜéh/DqƒjuŽ÷ ã=—G¶à™è\WõªÓ/|‘ý.eÊ2% 4Í¥¤úå’€€°¹ïðÞ¢¤9¢¥Í7ÂãüÍ:ÎßœJZäÏÅ‘´_V¡”·#8 Á®É׆ø†éãÕϱýÁI¤¿ muˆÄC½Ð¹mÊ,›Î ª\úÖ¾B ¿é,߉úZÈ„=¿ÆL'B1ÎS‡ç¥Ö—ÃšÑø5¢{)h}o¤Ê’Þúº<þÿíÑјe«ÞÚ qˆ0‡3ŠÇ˜Ý†o2ÈÿÐà…õà& Òs iöÏLÉ^yQ¨=.L¡¡5ðòÈ—ß!_:ö0.íP¹¼LH:ðÕ—šîñæø“=Wmÿ/Rá߀OˆÊÏ]ŒÚ{ºQ¼ƒÍ PšB—MС“=õ;‰šÊ´>AV—À¤B‡e.Ù¯EÇô#Šü"šÙ±€” ô\òsbVG·•²“áGæ)°ñ㌨S^Îp†¥+Ïuà/)/·šx1ž9{•†Åàz° ½XAw eœù«¬°Šˆj g¥¼ (p™#ŽH®‡èm, Ì"‚id_«÷¢Ò©úQ D´:IÂÆ“ü¢öó<¸€ú[@Nf’XØ„ÑÁŒœsLöœcÛFP©`zêbü~ž£tô´”t ˜cÐM‰3ˬ+db1ˆ±­4[`dëtr‹O0÷>ØüÞ].ìÄKL]ÅœêB;±BŠï3„LTaQᇼžéAÉøŽžû’ëu|,kZ7‡mSxœ‡H‹|Š-U<†¨Ž‡INDXDÛèÙoγéŽ*’n€á)¡…ìle8‡´\@8 ]'ŒÁp=tŠC¸nƒŒÿØ’32‰$’BåwŒˆ)I®Î/dŽdo‚GvŽóv™#x±Èf´÷ªç§+.ß«¯ÝO£MJ4¢íB‘1MA ¯m³9- †%Iz˳žZŒµç!ˆÕøjÍN¨ù$5ÌÒZIækâLý!.|‰84Û/wìUˆƒ§ë.ÂÔ¶‚Ô±D†û¼¹‚v½$K_6Ò~?I ¢|‡«.± ÈmY›WººbÎ>H¡O}‰þ¦äšä³±©¼ö±P)Äm«·¬“M\®^~+Vˆüë!Ð’|§é+ûv{q-LÆ«´ùC¸rЦòÍÙK?aâ—O¯é>l#|§ÌÎJ¦b@êÁ‹:4ÙCš£èU|+nØõg/ÿ.’€€ÀtŠªŽ;¿¼çç$ž_Ã**òÚÑsx \+Ôµõ_É!îuZªŸ~&æ÷‚´»L?:Áý:ñUÞ®¬×‡¤JQNkG­í?id¥Œ3']“Y<ï“)^U9a®Vxö|ä_2­f…¬Ñ¾Rá nløå?™‹ÚH&ç}¸Ù“$i¤#â} ök›Ÿk´Üu‡A²£zô¶”ƒäXǧXsÞHðwÆg]ïÕ-=QœZñ=]4¤oÖîöð«¦PD´G¶ÇÕdB Ÿc%èpÉñ ÷»[7¹ûÒ/Àœî?õQóŽ ¯Ý\_(ï’ê?\ªU]›LhÞ”D`>þ=ŸB¯›úý—A]ˆÄ<ÄÁ¡Ê¯† c½ëYî2­ë²ðhSW®Å`þàÏ}!„C“Z`é{Áy¾‹("?À,«KÎVBUOªŽ ùøš&Ô+ã¹hoðRÍk8zàgª 쮳¶8?¢uuQå¢MÀ9„˜¤ÑSH5`°ßãqÞ¿¹…AàœÒõj;@™I Þ{kÚ4¹ØŠ\ˆo¢·ÁZ×bf~–œÀs>Í%†ÞZk¡•‘JøÎªƒéеû…”ŠìG(Á¤5îöPLóL½¹1 ñÑaYÅè:ü¢YR\Ҹ笋û9AèZ}í%'ê¨ p6w •’¹Î¨b.ÜÀïy¢’ ˜d#KÙŒò\¤å©(t~so':L‰˜˜žÄnÚ8M£)?äYQ=êÿåín«¶ŒMáÌb{÷}·­ª}³‹Rip^4þ©ÎàÇ©5JS*þ.¼Ÿª/­ŠëX QêKÏÁÅž¶köCqŠÕT;¨$‡TáDøj`¼·¦t×W(Ãßím}1o%©—Ü'’œýŸ‰ú @V‹îÕ®V&®3¸‰ßš%cJár¨Ý8õ š n¤cög6`VÉæAö–î‡ËST—8±d×X>¡¨‹N°4ê$2¥ß¬oÝ-$µ s‚D‡oÔM%M¶¾È˜5ma‘­î{˜)XÁïò’U·©Œ"½EѦuxL ÌQò¬]Õ^:$—@+zå‹ãñ±­Rüóçõl½#Pws6§jlMZ«aŠJÞ5t×>{a !dB›$v™ñY¤ ¥ª£’€€­t|q$®ðyU™§X@0¯Æ¶¡qÖ40QKnýÊmõ»ÊT<•ØnÒ{Ïgbúí•áZ öá¹ÕŸIBJÕ:º/íà€©èýö•bæZ÷Ð2Mê Uí¸iz¥¬€Ë@³j*q´ú×l)gôð¨”Â^úƒ(Ϭ‚ZèSÔ˜¦b¤‰DjÕ‡3%M;©@ÜhÑðŒÇ§¼Îd?EqºPÔLPüMÂAQúâºbÈÿv;UŸéOE‚²«"”ïû•Mì>°|«0ŸÍY*^Î3·ƒ¥Çì ÿ˘¨>6ÇñäÀÊ®$"Ö'JEév&sÓ•V%ª{þ†?iµì‹}—°…+˜ õQw¯w´L¶ò†™yã&¥åËÆ‰jÌÒöH™&߸»Æˆ„ºB€dŽËÂ.YY›ÆW¤ŒÔºa‚^œ8»ñgx =;6Øž›ãî[ÜÏ¥Nˆþäû@Âùæûc ×¥F?—çÝ&\¼¥U8.ýBÏçRÙ2û&ç0÷¨x ¼Zd–§‡sëutïèk7ÊÀ™ääš n5 #žfÖ äÚìdu}k|ò Ù»0ê (ÑGt̺©•¤2`š×8u˜úÅÐâ´Ìp)Ê—×nsì2^5Áî6`û,?ºJŸuý÷•‡ŸJ0¦lI-ZT! 7Aä [‡XÓÎÛ#OŸ‰ôÔǃy+ŽC$…C«ã¸$|£]ƒ‹¥ìdy/ö¦¹lù©Q:¼2Í6¹¥<¾¹V:W¯m”`tØì_Ö¡0ÞßdÓ—ÍÕ¬q…¹É"SNŒ™ø¢0‘‚y;…£o¿GõØjlòœÏ²3ÂDa& ° %Njç\5–É@ë:ƒ¨— 2Ϙ¥H£’Jü¯UcYßç²O:p/R‚(DAë¶57þuˆ \ÙªÛ‹ü>-¾={lœ­KGè‘rZMPóÌëpÆV Õ^:—‘RFEä¢ÖžVZu©)ŽŠ3oì«T×0MûÀ âÿ¯qÅ'Ÿ®„Û§‰7®ÅÊ- Û∵\ˆ¬;m’¬Ž!ØÐ Îr•‚ÁÑ“euíkepgò#¿»o¼J;`g’sº¾sç«qáZr Ñ÷þh|<ÃT—_™BL8;úVã³ý~xMRÝBÞ·ÏL PÙ$ßÝàfÓªƒÄ}‘±’€€î{·'‘üÔ/ÃØëM°8lB8œz†z~¸÷}àÑD<û]sdÝGfUb/>ÃWH!™³ KåDÙnt˜?Ö¦?_v‡¾‰ ©'nyØÌÃ/2d %îTDÓÕºoF•1ìAöryìÉœ\VU6qò•ßô¹ø¬Û%‰>äîqQ Íß9m²jü¤»—ï$ëh_œná“4"¡ù'‘uD·\MþºÄõDKãë_f6í±gDÂ8Ï{UTKÈ‹¢BîQ( S˜dž°'ÖR$3wê;“ÅJųŸbíÁmŒêl9Ä«¥2¼¾©gº¨åH´52ûëyzAhùÒèÆ ÅBîy|·_¡8ÛàòtŒ")ž¾x«Ø±µtÙÓ#AÞíš«4E¼'âkOÔ€böC™ Ú¤ ‡ÆÒ+öÛÁm9y ™ó íÔ ™Â.ƒ¤­ÁN븑+ÁEŽ'FT‚†5<¼ÌÈcÐWæ1)¤Z(O”$x»z4>@½.ÕË:é ™eÇK&Æ®ÞJ€iõêx%Ë¥†}ò˜˜{­ì/59œ¨–àvÜ—¥‰r\¿¨„Ú?¶á¥ó&Ò-®ŽÔ,b `±¶”ÕI¾…!œnÐàBiiŠÍ<ŠO™h=õ¶Ÿáü%8ñ'lžS'× 1WPùg3³ÄŸÂ”r•W™È'|å_[΀A¯ŸGÃt=c¬÷è‚#&NÿŸ$Ÿ‚hY^´‹â¿A Ñ]Ð0Jûö¶7ÁcWáï¯áÒ¤ršâcŸ!Íõª4ß:ƒµkèÉLœï ãO7ò!*ÙtÜ[f?úÕe؉bªžt@É º#}/D4ØU‘Ó”Žç”Ñ£$$ÑŒ–ã™M,zKaƉê–\²Ræ5;v,dŸ°˜J­ªÖ¥EHåZt~çHoM 5á¸÷ß¡‘#c½Áï’gqýR·°Ÿ‡C(6)ËÏh«®RššaB]§Í¤ ni5÷øbz»uV‚:Ò¼†œ~ ¢‚ŒóÈD®L‰_†”‘€Ð#ˆ–ÀÍ“ü×”#%˜—z©©Tº¼Ø$ï1‰·‰ÎX8† ýÊ©ä=N1Yƒ PŒã9G`[7ÚQ¬„²’€€þ›Ï#çÔ¿Ø873z&çÃ+–ê>Ž^uÉ·bTGKˆäíL/19íðâ±I±ÝÙkÚ:&B¸¡ÔHÈI ¥‰Ì ÂöÞZ†TO@iGb$mËuá±6F9&¶#CÞ{ý£Š³íŒ!|è7TìU‹aaRY EÝ܉Z F^ò,ȪÃňњbzŽ} »0ÌëÓï‚yõªui•#ˆö^ßáVž6uºžQˆ<–Úƒá£Q;»$£ëAψ—É*bØ‹u‚Á#§á{Ó¦ À²}å<íª‹~3†DÙ>aZys¡õø Ï>^¬4¤5h䯼Mà˜W"*aу1à‡Žõ8(3J}oÏX¬ˆh6±&Nä„®²ža‚™O"œV&8 ¨ZÁÂä~hÉhˆ0J *H b®£f›1µRõ$Íìk1ë[QušŒ^m;ö^wXœTÕÉâ+Œ½MÞ•νk.)í B…ë¡ÿht{ëÌ&‚ß9ꪘ51ƒëèÌ â~j?…|TqÛí¦W,ô`ÿñy¢Zr¾AVü®hC“ùÈf÷ MçÒâ²®‹6>ÑÌåa°[tç Óz4†šþpU‹oÏ7nšÇA\™­·»ª§è £”P´‰±Å¹z=ö^®ÖÓ•YõO8—ÿÉK@Ð2ˆcx¬ªY@gM–ìѾEƒ¤@:øL 4êyv·…ã_„v³ýLh$-Ń«P‘¼Q±õü¹ ô>·f Q˜¶ÂûãG… ìn`/E …Æ•FÅ¡W`o¬íý© À„ãæhº(V*•ôÚÖþÒChE®.€Þ™÷5nå™ ò>¦X·ý-"á¹¶¯wýü Ø?›_"Bu%Ôäú0"—†I€±0ë‘Ïš ~ñ„'ʦY_ù¾´þQuŸM-„7¶«[½Ô¸ì«94òrå+àʯ”f$6vãC3½k%oúú¯/¯Q§Ç®íŠ?N[8/~_Ä¢€ò¥ÏÁ™ p_ûü0a¤™yP¸Ò×ODï¹&šØ—S1 lÏþä£R]]|iy¥ÖZém­} z ¾ãÑ”£À‰/\|õ®ÓZó*OFb'b æ›7ÃsIF &›{l3²ËHgô‚öì¼¾5—’€€ØÉÄivÀò,D@QÝ¥—¸Á¬g&æ'©Ÿ~79Ó£-&è6•1ÛôÒÁ€íBÃ7%Q3ÑÈÆw™å2²Ä¥0oƒ&Ò—Þ=›š™òÒ©õ:Ò‰#§:©Žkª ¢Úªlì»»‘®Õ5×e×ú¤Š)¢Œy8sÐ=¾UŽÚXÙ`-ÂÚ¼Ü(¸èÈ&5jUØØj ý!qü”@ü:pi4it–§aÇ¢¤ÄPD³×®Óì*mÌœ´øï÷—Îõª"¸¢…V÷sò*ª‚`l ÌkÓ!Ð+©ºzËFÁÏP¢}ˆœŸ ›ÕH³—νhMD/,µ™åo»Ëcy}7i zEÌÚQÑðqvÚøl ‡"äg/øñNh~åVÏ|UkÃcŸÿ©«Ÿs‹OizÕ€’ðÄ+1BjNýÁ'tÆ'ÌõÛðŠ#¹,Ë„2"a^-$<ê=0ÿ›·šST#'Ùaš¦èh^»Áb˜êÏ8u[ö¡¼*XGSL¼š® y’€€¥‹8ÌRÇ+Úù3ÈTgÃg [f^ìB˜3ŠO8HüBµußê–o¸cuTMê¬è¶çÚqÅ´ü‚Ôƒ¾—AãÌ©ò oÀBf&‚M·{@ù¸Ð ç4~#“ïƒÚB²£ÎÙˆ“yÆÖÂ…´á:SwHÀ;Ì8Òeݲ†ÅzÊN}}³¦³ùÕ¬°™Ê7Ç×|Y‰ù¢ÂJ.ìlhi9ÈiøV ø ìk ÅðÁ F‰Ýˆž¹À,^ ëú9ÃcÞB`½1º£vw¾.o}E¯ ° 1ˆãg ââ;ã3Ñ}¦oSÂ~X•Œ~&tjÏÕ4 i[™Å=£ÔÕÈlú†z›C¾Ÿ„Éýq¼²mná.YÑ´›ÒdǾZïéFãžÍE®%´Xƒì*Ù÷½+“Ñþ´õJãé9ˆé|ZR»Žåþ‡ãàžrÚ#¼Ž‘¹¬B›gù<ŠDQg—1ׇ"¤-X')®‘ÅŸÆB‡óßVsœþpPeÚ˜)ǽfÎJŠãw n5„¬àµ¦ ÈFÅ:JQ­†Ã…ÎwÔQUžB4ƒ’k7åɳu`5EA£Ø;žÞ…_APÖ Ù-+Ôúø,;m|ŸKIîxa•Þ ‘=bŸWìÌqŠù×Ù ¯³5ÈCÚpÆÖ/Iu‡à[@Ý9x}xŸ\#¢‚4"l‰+üáøë*é¸4˜vZÜ—ßø–ï‚®cnpˆ·ïçÁkÓ¤|áìç×ó^Q{×ÃW±!<­vë>ç|uM;ÔÿušØÇJadKqÅ)-z“‘½ #—4AÃ.öÝX„ý“…,Ù»]û€‰¼ƒŒÚú³Nî" ÝÜ “³ÏûÁTŸ@y6sþÂV¬"‰ãêvwÒÚ i0lûHûÀA^ÕtfÖÁ¼Ö©Œa*!‹´³qqlR—v Ÿè$G}_]ðs…r¨<ƒôcM'ñLè×Ö›^éWwÑ2ù¯{_Œœ$ÅØChï —V‡ÄUg¦͵˜.{¤‘õÇ®RÎ+T‡ÒËÑtxØ ?’ WVSµ—Åjظ tÛå?‡Îž×žA'«&«»ˆý÷0,oÚàJž§ä˜|öÔZF]ûƒLÿžö³øSaèh(¹Üª’€€ÐŽƒaw1_î½pjߦ/ÃAßE?ýO |äAÕŽ¬%}ÏÁ¼}DL­b€  ù ñ»(%Ðj'ëð/,¯Ð¼&å„8+Ó,xN‘ÞÉvØË7ml¿8櫈~¡‰Sþêúæã"¡Õå4½é/äšutbpI@º d¦êPtMŽsa Á¾ÿt\´áFUÆJÔkÇ…à©„ßÓy`þ×Ò+üÐAXJMYä$ú Ϋ™ñHåæêݧ “HªÅÂÑQ@t×·É2iÏðÑeKjÇû«?`ÍlˆK”E¬䳑×ÐÝÛIÏ^ð[bߨ&XŇʼѣ ¦_m+þµœlÈsó²9}ªàîár³[VlÌß1Ÿ?ã†è"ì¹Vì=†SI<9×;¹¿Ü² p),îú-„Î{wÜÄV>dj Øl¢—Lƒ¯î º—˜Eyh2D†?®uˆæõ;Ó^§hU ?Bt€^¼±ü IY&3A¯j&.³¦ÉW9]ù>ñ©ÑyåÌ.Ÿ&<ÿ´i;“Ò…©jòãvø‹3}…!ÊTÓ{#sÛÚ~¦ûãÂöV8qÿ}>«ÇŸVó6˜Hî»ÙSÔþ5vÀË2FŒÛx²ßMˆŸþ)JÔÊ]d†²Ù=¯:D¥UKu-kÛÔQb"¡øIg¤}ÅPþPüï ”Kø²½2µÊÌà\®‡Ïü¸iÉk‚c+Q!”Ÿlæp‘Au<üá\ƒÑʼC@]•Фvº¤2 $¦è™u‘sûž æî4ÕüŒ÷L%n«~ë „Ã=¸"<Éõ¾r×ð,• ÑËVÅŠ…Öù¡·*”•ß|§ôÖz¹”SSo ?²¯u„?@36¯®´Í[•CŒÛë…m :Of’Æ?=0&á-•qkÔ°õëÔ£"m£¦êM‰AšªÀvû63*À@aý*É©ztüI ØÕÔ¥”0«ÏªŽF®if·üÐÉ=r3Âq9É0TBwz¯N£ÕÔé¸k»Ek&YØ•—þߌ¯ÃK¡ïwƒ.OO7;v  ¸°:Äkp‚^Gc@æ¨PÝrójénø¼—#ÑMWÏO+>Ùøe _R­Uí©GlÈg1Ièl+™»úEÅ°È Ëß—²E9¬ ¸dV®3ñgј’€€Í$'&ã ©Mø¡Í/LLj8šzÜ"ˆ2Ã* ž1NØÄÀb€ãñT\{DìÈ$íÚ„Á•êÎStä¶Þ¨jZT¶A [/ °¶ü±¼&Ø÷ÔÙ…%üc2*ÛðãðØ'j£»Ñþ½ o(2™4ÏqÚsK«ÌêRWÑ–Ùà¤ë<ß;°KTcöäÔÂÈÛK[¢¦ì_’¦mrÔ&È[0}öœÝ¯ÊÈ„ Jdh0O·¸šÌdÊŸq”L^»Fˆ!¸m_ÿت!,XŽ˜0ê7OŒ4!*­ê.^Rmzq–é°Áš Cìνz{p¦Qí\~Æm\LÍ·vÛ½}¡ôÔ±v=ËHÎ…ÉgáÇWÿß×<‘òßÄÅ;(•R¡0-|(»"±ck]÷(ïoå9þìßßCÆ$­hk"G»XˆfU1ç_±Ž†Ýw]üzr€z•ê>‰|W¬œ‹è„c¹¼¶HCy‹€è=(í)=½x“Ä?²âu¹œò}eqß]%eiA<@:˜I#¸¡CÌXX¹­jNOq³Gî¢^.¼WÓ‹wI /ê#Ñ9 À¡åœ[OrÀ(yÙ&Xwèç«^ë"Îi x&iÙñ³i ­)´ˆÄLõ¼°^ƒ%À¢f‡UèpÛ|YŒyÏÑN·T1€]w¼¬$ФþwÂà_e k^ÒeË”öñc ƒÚË"†¿×´^B„ÄÎ7æH¡@r™:xNüÝʽ¼ÍÞ„cñÈÅ9ó&â8wCÍ›ú1ãÆûÉR´5àćrÐh9Fcç<Œµ!F©®°j„ˆoáîóÁ‰>××–aÄT+Ÿ§ÅÆÏ7j¸u`j<Ÿ±aâY~Ä®ýÈPÃ1ƒ—Ö’HNû¾Qkîßù²Ô'ʨ¨~’YÞ?¡SzC³Œ9øÆ/¯$év6g^¡ ãÌñ»36NˆïpqóOZ\o!HUrgÇV&É%@ƒNÛås"LJ(18¿lM“dœ“µ®k2 àSNU"Û`­qÏç…ƒh¹˜úôd~$«¸öfqtǶaü7zÜxHMÛÖÆcUXÔÉúg!ôdÝñÂŒwÖ“ËÌGrÆä­YtÖ=º×'µš ¡I2sM)¨ðLÊpMü宓`-ù?î Éµ°_ŒAhÏý4‰RÍÇ»žMݹÎûóÂäý¶eh¶¯¤þWX’L²Õ5ÔŒ¥†dÀÅñ’#޲:ä‹Ó:.Ÿý;%(†—ð áè¶Y¾sˆW)ÿ—{_ú#k?E«;ÿššâ©tmtß©ùzã¬ÄS››‘b ‘õI´°±§ß=2Gf¢ý°>†º&²ËTArÆMA’Jôv=±[PØÖ#RËnDR¦\±x½;) j̈œ“%ÿd ¦´U`Ó­Y’¿mÌ—P^4¨Ç¿Ìï€cÑ.2Aœ­@ÈÓþ-T2ŸsW ±ÄnÄäñ?  °/ A€c>KSáY©úRÝÀ>W´:èu“Ÿ؇t™š³×ÌתøÌMª4 ] îÐŽ0à-×lkåöE┚†8Ýõ¿ø8+A,ÁŠÂf…ßdG6Ü U€‹€ù䬛Èz‰]t>úîÉ®ýoÜV\ˆÕ*­^›®×µ!âÆJ«9‚è@Æ7_g€A!E€Ýfç>‡‚µ…œ²†è ³óyï™Ï<ö8Ž_Í-Õ¥¥÷BÄÚ-Ǻ̺Ôc̵F¨üׯ3fFwŸÂL#|ˆìú©ˆíU®%Qb ÆS 9Bä£úžy¬íl ØœíÄ G'A •u_’ }5E<µd³Ÿ¼ùÒ_Ñé±ÕUâÆâWªe-ghNV[Ã-ú7Ä3¿Ý Ù•]ˆ#äEþôBëæÔ¨…§ùHt×&‚B[Üåym?vr™8ŽWb¥é:,”+4÷wbPŠÏ«€ý·ŒíO¯WhÿKÿ·Ñ$çDÑE¥Œ–cÄf- Bô%«úˆY%¤DºNþ{.Éî÷z`¼ñ¸nDýj)ÿçàÿ ã2¤¸ Åä¬G«³+}óÆ‘¦Ú™ Ú;ýËõI~’€€Ãl •C±Ù‰«$(Çes7i•K³# †8p)!¥‚ý<ž©)Nò‡Þ‘ÏK ;Ý.1k}ëRŠX8\“·£10Ö/ùRðêD®7C1ˆ²^Îȶ†ïlŽ`)v×'Ä"Üè«éò4o×s GF.qyû’VMÓƒ QÕê®j0ÌY/ò`wíŸÚ(¼>2Ýi}¦FWÕ|VÔC¯»)¢0*»=Ùˆ4É£ø³œþÏ? DÆú‘£!S÷Í:áp…žÐmQo“žˆÙˆx»B+Qû¹^#€©lo_Z¹’8…B#e§[ÈÄÅlѧÏÙŸÞÆ·j£™.#ÝÒ wHmÍ0ëmÍì°t]“ш$õ¢0¦™Â‰b²cææ¼Ð3·²€«ü”þ­ˆÍÍ CAÝàöÂW,²…2ü=6Õ”ÞÆüê2 {Û²u™w=Sðë0Ãåþä_Ť½g³‹ï˜2( ʦ¥¥ÕPÌRv° rÂÍ\ äBKF;H×Ûþ—j˜‡óµwU0ðÁB{|e ØþŠ”S­ QMºÙü¦sï*¡ÝÊ+Ízí ~H'3–KkPkü”êü/$ŒËh°N,meìÊ|ÄdP-Kä7A  $mv^j ¯·F|N¿ÔRþ‰1é6þ ÛÛ……‰u|ÉÈæþQgÞó¹_}ðMЫ)œ*JÄÄ"…ŒvTá+ž>ôÓ‡‘âf‹í¤IV—„F‚ØáòŠÖñpt æÅf Èe‡ÂîgñÂá°H  »g#Éžùç ³`Š‹•’¸,Öù–,3&”¦äw{փϊйca†%BZx¿9±@UÙ„¼÷Ý7Ðyv5ž“€åóÂ|Øpͦ¢÷,¦Ç/xµDÕH'ï.æÛ™gŠÙ§øq@&k‹÷†£iýôdóÈòQ :ã£ÑŽ|»év“< \WÀɆ |_¶ØS:ñÒ£‡õôPmjÐú¥jȼ… PÝ9{ÉbØ®÷†µÊ?jH“y—ÇÈ+Ñzúä¼V=ÔÉ•"Ÿ;P6’Y¦o EPa ¡ù˜ÿ¬±Ä”U#ºr|WüiK ´rçèŠ4çÓ Ü“"PYNd7+Ó• 6ø°ÀÚ AsÝ$¹ëö¬Ìîv‰€s#CI ¸¨Éʈãâr‰‘swLÃïýìléJe‘´±)À©é¿_ËÖVm×âxΜ5yè>Ov‚ûç£Z({e½ðv žìÓ'íVèA”$êÊPÌñ °¬ÚUЇÖ~š/ °q…õ¸äßÊl5]ô#À-Өإël'í6}/­öNì7Š>qÌbãÓdù£Ù~9„OL‡ØƒB¹¤$˜×ídYd?b–îÀªÄ¿xÚXy²àüˆ(ܲpú­Bi"¤Š—’•ðxüÌŸÝÒp3Ú—DTš}žŠŠÆ9~l¸”ê}¾´³¤ÛœÎA÷+:«6yÙ1N‡­èH¹ß}Ë €Ãÿ sÒ8þ«qò¼Âs´7GÁðº%­Ã«²Ðšû"X¥?ƒÿÙ Kð³Ï¤o TèÄâ²×…³½@D™dçû„xNµAäè‚’–¤í-¿ã0`Tq³EzÖ÷ÂâaÚïqûôøeÅ@ •‡ð}’€€åÔÞ0 D-MÎ&5–ÈïÖið•ôº‚X ’„”qfêðo±tÄÑ’>bY–ip®ŸÎÑžû—¼=ð]`å0ÏV›<)ÙXÎÚZöÞ«&&kWožQ‰úª´Ù<^¢ITâwÈ;B$ •bNú¸c@+Ððž ¦63q«‚Ú32ÐiiÖLõZíu¨ìâ½×ÂUºñ8(îd)¹S#ò'&òȬ½KGã?¾KµÙQÞ ¯á!BÖšéI¸a:ÊÔ#¥ò§!±Ím!B=ÓùEU$¡þ“©v§Íý/kþ,·Wpnyñ+áóħ´Q½© ˜ÌN]=Ôó—”ðôëA[$¬¯$5=,8 Ä_«; ^yòN’-±',#_Å>¾ÌVå]º1Ì+n’v–Ôž&¿ xŒ ;]2úó .c!. ¿ŠKÄ£}ù×çʬ»Û)ôîÁÄX¾Ý *…°$Ž,Ü*¬5ŽN{ Ô¤¶å  xÏÅþ¢‡hœN2!ˆôoLÑ„ WÜ=Å:XIMk¯ú_‰vººœ¬ >®å Î)ÝLXÏ&+‘¶Üþ¹t•0£w"ž¸ÂÚx¡càà•Â`¦Ë§Ø?ˆ¡ä»U‘#ùšmé~ÈÌp»tz£ÿ)×ø¶Íñ',45Çû±«Ð®¦“<ÀM«³|:x‘ž±oAäÍeøµxgîîÀº…ÌŒB  †PügÀxŠÎ3RFí…Œ‹²¶^Ó‘§WŸ$~ äêÉ–ø¶6ø"p|Î•Ô De¦a4uó€k’€€èãô1D<`0üGñ%Ké rrÔ™— ²¾Îœ>d’®7 x!’»K¶R:ŒÀŸÏk¬[´‹êÝ ÚbÔò¶k‹vQb’ÖÀq ¤±)˜®-Ot—œzµ|SäéŸM¦œkø0#öÄ,‹¯` K<'7GLŠ*[ºö‡•Ú ãl´ÖÆŒärš+õ€Åx†ó‰"о ðpMÂO™0õ‹¬uâ×yïžpš]+©éòàJL~[&a릾KæAvÓÕ³hú¨öÒÊ_b…½Eˆ®±€0?!ÝŸ³Ï˜iwÝð·•ô±–' ¯Ìk¢¾WÙQ"òB¥s}=ë¾w¡AÅ\À{§q-Llÿô¹1ê°oÉqd‡=a¸õéVì4‰aºê…èõ~Ë !@d»•^['Á†IÞÈl;ÇÜgei³.íÒ¶¿±Ÿ-éª_è£ ›=UþÜØ)òž5±õÅý³šò0ɺÒe%;iÒx·þ‡¦š†Æ:8ÇQ …¾¤/ ,S¸b4ý“Qª¨jï(e¹á¾øÓ‘NY¤/ï_lÛÌv2eQEé®ÒMÇ 9ýÄ–öWkþ»"G#¼ Üm._³Îp¢Hk!ÁõŸrŽŸ´q¼’þÎÆ{?Íïú;B‚q}ë}p-“yÖ:L¥öš1¸™¤—öq4¨„±éS௠U¾j#„½Pøua¡õ›±‡í >4‡kÿ¦^o§]~ºeï@L Óν_¬¢¯åî·š.{«t:M@:ZCtu ›¸ ó;P†U½Xµ|ºecŸaá@Ï÷ÑçOjkøÎZ1e…+ycñÃý:]UÚÒ95ÿMgk¿`5€i fõ%´äiÞ¡§ðçã¸üçŒe_»–þQ=@P§œë†Ìçô)»À¡)%”7ÅÓ åƒ­w¨^£jv§p«í £9 (}V¡\3tZ´jáõb^.É)$ÍöãǘѻûîÙ°å‹P„ MP!U›¦³|ºÑ 8zÇ5ÄC‰1”F-Û÷mÂÓTï(÷PÃÉ@gc •Ú¨9K\)¸FX)üÊß¾I‰ñáÝ*Äó($ÏLÒÜ=6iâ<äòH˜Ùéé2´¶.>J_68SÕ÷Ù¹÷D¾£D³aÖ-‡þ ‚#’€€ã(\ã 53hI+DÊåx”ì»ØÏUz„•¼Yb¦ˆ¬Ÿƒ‰_÷V@¥:µR¥BÀ¼´9‚€sY2õRñNžÝÁÆåo³Ï|¯—úÜ/|îì·=QÁÎÓÁ)È[²ú;jEBý 7­\Ül µe¡QÞVÌÄK”ÑÔ­§ƒuª€ˆ°X{ˆÀ/®ñµ®YN®ÅOb¬OD˜B_b%D(ƒÉž&ÐÛ.× )5ã¾f™/ WÂF@¶˜kyÌFP%צùÁ¿©?UWkƒZkÁ©ÀÄS¼{Ýjõ§˜ÿO~@ðàø1Ȇp›ý…´™ Oì½@å0=›Wã$®PV¸žøˆxÜ‹Q2toÃHÛ„î¶åuÒë=ƒ„ø…y”õ†U}GÆÄëêÞ&>§#/‡¯£ÍåŽSäË&÷Gmä¸gèy"ƒŸ_ÃgJhXbü·¹ã$/ ¥U‡û RÎëO hü‘*nÁ¤CµðÔ«MÄmdÛÄ?ºQs4šªI‡?$0GÏ‹çdG(C¹XÎR-ºU*¶igO<Îã}æ°ÀŸcͼ®$~q©VSæîÌ®¶BDURý{”S\?Éñv*Û %‚lqýEê‚´ÛW >[ïïŸáºnk¯aT°›ÐôqÛ§O‹¥´ÿ=LL‰á,Mªm"âruóKÕXF`\»ÀËËõÿc°*Ñ-QLÇP›éűBœ¾ÖaØÈʇé"!Ú'íßb gp@ò¤`>T:èEÙQÇq+^ÔîÀit±¸Öpj» ÑUí¨z²ƒXpý ˜‘Ëßì¨ã‘L—?ÄX€åá‰ÛÉ•ú#D“ŵÚwï}6Õw䄵{xì(ÛÈ&iퟑƒü~©‚h«wÀ µH¡GžŒ/>ud¼ìÓœvæñkÃWn…ŽaZ«“!süúÑÞ()¹^/^èð‡ååÀµÕ‡Dô «JFî'(ÖÞ^-”þšFˆ¸Œ3©ž°ø 'bõá;ŒÚH¡…ÜõÑøÚ·Ò+_÷CšÆ’\íÒ:™®$k¤’¨øˆ{·öuÜ•‡°ê:H†m.Nøß›°è(¬ÕËíûk"Þž§EJ4ñ¹1Ô]MPwjÖÃyÕ yã³á»¥ˆ°»¡^Îî‚ZB"Z]‘(f)rBûsE¶5R^ðgéEʒ€€Çx˜XÇá¹þÎ(}'ˆd8N» mð‹Ò ˆ/Wá#“ #ÏcÊw4Z¬št¢¤£;-V1ë¸ì‹ÆÜ¸õµ»r\äô{ˆ¨+?Ù ?ËSÀ™8˜ªôÈlå ŒßÒVvo­úÊÃæåìï·ùS»ò"ÿ©ÿÙÃë- (÷Üým£ëÒ` {É`* bšÍºFŸ5?’Vß2Ù¯Vñ³'Ë›¤ÿÿ¢³âiR³@7¬ 1`[÷yZ™zO÷ÒhŠÎ7¿Vñ¥ ü·c8 û¤YáP7ÍPAà5•DhfŽ‚èŒ¹v¢ôE…úÓ«Öâõ¹vº»G7Véµ¹à´ö7í-§^—׿–5hm›â›«•ãá@QŒ=ì}q™‚"µ<™—“±·Û Ë”´åÞHî]ÇŸiAa¶ r[æÿ¤ZZ×Giú@*T]ùps#uPÖÕì%íh’F²Ž<ðÓâg.„¡—ˆŸÒS¡Ã’¦Ø P¸Ç²ÂƨÅh÷ç$í–øN‘æ†è `„ ìi 9…QøkcÿNÍ«w:\wzH`>àG'Ìoã`?M0S ®A¿H‘az4"Î5Î'ë¡©ç6tþ4¾Ý4›ûÝd7:æT |â.!TŒIŠHce^vCF@,¨Ð\à‚½nQöñ ãß\A!Ë4@J†qíåp£ÛŽãº÷?E"ù‚8“H3·×ŒÀÅ>OQÁ®ø•ÿFÓoG5VÎDðrJ¥b„’Z³ãÝ$M;TzF ™¿ö܆È9‚Æ^~ù%ÍÞ.Ë3<º_Coü“çNË~Ÿ>‚ÒFI`êïÎÉÅOÐÃ@ñ @1u–Üóh »Sxˆ%±…εXÙC)Åœa ¿Õ¦é®Ù8¬hŸ— yŒñž€`:7Œo…Rll`Vì{š”‹ÃV*gÝ[im \"-a¨o›“¸–äü-ÐJ¼ä&x­¾`ê›GÌj•)I˜À…U¸ë};—Daô]4{ŽÆƒ)Èvõ¡œ+»4„‰;œâiÑ+ŽI½‡sÞtÀOG¹W’3âYðM?láíTkïÌNÜT¹"Äð'7¶Ù¸ìÇÀŠ8r®PðY‹4Ž9(h)u‚ý¿ŸGâŽ|ù Í£è/ÃÉÙÁv…èT‡’€€Æç|® õ÷òØ·®·5¼MK7dk2ÓŸ’ø£¹ª£NkÍ6isÌx‹ðbö›©1_Â{ W§6 ±£ê&“^gë«–ÿ ƤƒÇïú÷òñ2ÅŸÖŒõ^ç‚o7!ÄyZô¼ÿûx]Òw“hbàÈm‹ä.¦ÞgŸ¨E'}8r84˜WîA%$.j”–Î̓gyËömдíIü–r¹É¢ÐÝ€B¶ïŽ6ò1ê´¬+5ÃLh÷r99ñ. "9¼#êQ½=ÏŠ\ˋˑ4Ë2üÄ¡“fÕŽ'ÀSŸ¨4è€ç…jËu"èäTé¢K¹ÒaH3„-â©ñ/™M°³ÇÚm#³\¿vhT=Tz%›¼>+)ð­•2D¡+fîc%6¾ß`eØŒ˜Ã˜õÈÅ啾nrI,tÊÛ !ÕHpVTz½Çà§KE—ZX!ÄF–[ð­(/mEáxSj~ëžqH òÎ'¿æj° n*ë‚bxt:|±°BÅÃÜï…Ý7VÓ ¨ŒOûWå½wS@k‚€âj?qÃí8+›¥2“ «<òîÒºÜÃ8Y•µ nMS„si1v‘u/À9ÒÛúoÌÇU\ã“ðÛ=kÄù•ôÊ÷ýï-wlŒk¸<:3_£aÎÒ,qõ˜cÜ\¶QéÿÃçá~ç[}95°¬’OÍ®ýò¼œp lF­ð±¦¨Š#^i#pñ—•iO<ŽR]8–蘠Ëf&ƒ*7fÚ!à’kf°÷Pަã7MP!ˆ¤K[¯Ö‘ÜóX·•çk -F·Köó¨‘]Œyé ´–‚Í!bÆ©ÀUÇ8£†ÅYšw}"¢:sšF¦y‰a• Í5xÎ|;*à€ ‘ù¯ !RjQK±ZÚãWiÝ…xC±‘¾F+„ØÖç†Ã›–ê>|¬°zÛ2B”Ì.¡T+YyÊ=¡g'ë~G`hZ›øÙ[62 ×e*ç‘ugí¢·ä,O–- )ú·’Sm䃨ߢ!½%mw.³Ü9†Çb~Å¿ø£ý !v9U7¦Î¨óúV7¾–ñVR†½õÇžZÕøuÝÁ‹9o‘”C2·C&d#`V X6Ù*ÕfÁÂÆ<µl%¸^5?Dô„~§ôÏ—(aÉ*XEÞõè»8}Çu¶RèK€Œ~ü¡ÅóÖ£¢uV^å„ó$N³3I‰˜JžDDîoB©&ò—¼ú"‹ >Šé/ÊÖÁT3r4œªídÏ¡IZ¨ÔÚ M›+sµÎr1 ]ÙCbÜßÎsiëÝ¥¡r À+ÍtˆøA¡…ßl“Õ9šÇ³ÜæY)v—ö Kc%½mïòذhùê+=[z ¤„É’^Q½Î¿Åp&?¢Éx¢`b<Å€W¦ÎDC%¥Í¿åäÎLÒz– Ç£¼ ü‘$`ݾaIÔ{€zÇèGšÇW2ÉËš€ifr žRf§ 8Yí¢EùÊïØÿ’ƒHÛ·rÒÿL($ëf¦ç±ÌöN`öÔßí€ÑA¬M5E5÷µ/ç°{þ}ÝZ‹m£†¬þ$ºu?Û6Ò™ö Ch•Ú×Î=ä€1’€€Ý!èpľš½í=ëÃBvݽR"ä?F•n1ŠTE@cVVséLåÂxY«ÕH1‹D éR:ÖïÚ‡ÇÙ9u¸ý-Í0[‘HÀˆéKX1b'Q¦‰8þŒoàó*0°Ò¸Âq_õxªÆS`Ú|Ž¡”+G¯b¦n[eñ£ížû†m06ǤYÜ9¹C,©½ÇiÀØ­n+.-¼©›$œ™³(«O…ƒ¦µÒå Ýï-gĤ&dìÅÄDJ§2b.„ªñî’çÚaLæ-qKÚ}u¶»Uü|ìÃêõyúŸ˜Ó &2Ëÿî‚[æÑvŒ.þZÿ1zeÓD•;¼$¼/{;pms~œ–¡üÛq\;tÝúôجÅHïÖX£ê¦˜7ä¯Uïe~ß6dÐ0»*ýÊMçÀŠ£ çê=Ö_ÂIóO†&º>VP» °D1ÓÍ¡•õà5T‘·¡3Oi—Ì'NÛ»†\¸#¡0™Ir}vú6éãE½²ˆTìEðd8ÊdkÏì®­Í;íž4éÂxüv '¡(³TQlŽNiÐZóxѸ@ʈ=»~ÿ§’OŠ ¤„œ/ÕòN$ýŒO-îc0þû»¿-º‡«Æ„_–ÕÙºYšsHk«¼"*Äȃ?ìí¢®«{ïíL|š@nvòR!©<'*6T^h)› ­ï4t‘tíç…Ô›¾Ù@N«èܪϡ %«êc\ZÓSý\ hÞ00â«ûÍpËû¬SÀ¡,bÿѱõœj2}`Æc•\·gQéó„ÚÉjùÅ-Й´ç?Ë×™ÿßcÊ08ŸKâq ø¿Þk– Ëb'b¨SrÛ)ÖÄ¢aØb‰>¬‰.=?¥±äcbúE½(©í,áøð¹©(ŒúÖJtÖÑhu±ˆ dì@BÓòõ6ÌB©[b:öÞ7»–šøS(£r½®‡.ª.ÒÛDÕ-øBüN0BâÆ¦Ëuß\¤åLðÒýFk›ãÅÙÒll£v§²ž?õ´Ox5Ñß§r¦€¬KY;c‡!ÏÓQŸPÁm§»Pó/aùïeH(¢œ›•U™àUáeDq¿#C*cÝ,…ÆôF¬­^bÕwÓ|"¡:®**!’æÏÐó´ï v¶E:— '§Æ B#÷‚øøå¼4øž>{lq2o&\TcÅÔcçMñ=E`²›8 H@.ñífá&ëoJÕ%¨‘½ ¨M"‚Á‰È<Ít½•à>2ÿÒ⊪3Êÿ¿>Mc»üÐý{¥ûÙWR VG-/(ð>Òìœ#NR°·1û+GЕ‡üAHÓz@y|‰?Þƒ_TÕþ¿§Nlû“wn#h|Šjç¼²Æòûm 7A·T2Š·ý¤ÈZÏ8ÖV¸ŽNíšôM•"±|V¨ë•ô@)bzá’ý»"æáPÞ]ÉdÇTU©4ªkŽ@…5uÞ_€•S1å½¢/÷v@¦‘al6‹J\£ÿ&ÏîcœK¦”’€€Álh|`Ìjîßê{áÜ e&fÕ¾7¢úÊ¼Ž ¾þ´´Ktrp%wè\LÝË®ÛaÌ2h7k_'à…x™QX f£FA4–˜^'¢åàHl³¸'Ížü(f·Y¯ª%çCj“ê_Ürßæ ÿ-ð*üÈD§3]ÖÒ‰€ÁDf‡Ÿa<Ÿ¦¼d$R<-6FôÅ¿KÝJ_²®x"ÜÌ6£Uà/ ¿Dÿ?Ï·Œ‡k…ºIÊèUÄB\%–¦"M¬ B=r-šl‹÷ó³3G*³ «“ú%«FýòœoZ®»(Q‡Öy;&%®¨Ê…3…̬Îb½¸uù¿œUVɸ.õÎ{²¡OuPH&ƒ•’¹m†{â¯ñ† êÀ$®xêHÊ ŠJ-‡Ð.Öé9S8–4ãbéú™%ɤS¶ãuÚÿ¶µ}¤¸#B±'Âû #ºP^ñ{“Vâ9¾Èõ-ˆTÀ«².†h\W&©ý¾®òÄk]UIûLC—cŒ|½P·>К ¾×*ÑšJ¤©^ðJN;WŽê2ÚJ/±IºU6]œu@s2û,7C^7iôeE{{}ìR§z Ÿuoô¼¨ãœlP0®Þ¸Å—ß¿Þ51ÄB9ýkÊ­¾RÝ®oìD€éxpÍ”ß g¤W÷…Sþ!ì•€)¿?µZ!µU~{È2(Ôõíï¶§¹±u”ù‹/ÈQWǦ‚ÊFÎ’‘¸À´ãtT\6?f]a.:‡vŽb³@Mf%e,NH'§ôð×>HZÔ¾ˆŸî^C|W:³‰/ë>¤ - Õ”ª†‘YÑL„£iU¬à쿊҄_XÅ(¨lc`'²0ž„‰v¡¢òj)íæc~ur®ˆËÑó÷™X`oÇrH4Ų–?_ …e*ÈÑî,8¡Mb‘¶6)–æ÷xãn]‘Þ×öxEÝÅ9êàeàϺe,ßã 9›ù“£jHX’€€À2¢½ƒ ¬>Dºå½÷Kn=èB:K•î¾þ¸¨½è~§±˜®SÜìû¥ ÖF2›¼:ßÉѦwg€ÅÁ“kƒÄìÆ6ÎÖAƒC "Çî~„ÞÝN¿™4{øN2­ømÛŸˆcyƒFîw&À^V~ª°Ø¿~s¯J‚Kùå Iž”!’¤»Ó°cì÷@`¹M"L ä®_ä3ØÀ¥—T(wÔU#xú€7ˆ ÓŸWàYåäC5o9þã(gdF¤4tˆ2;òMѪ—ØÀ¢?Žž/sðÞ5-,cfÀì¶Ÿdˆ‡µ8òÎìôÃ,ÑÁ€ôÛÇh€ÈM¼âžäsµùš³ŽcÜ/\»Ë¿RЋ¾bHþ›ç਽?@Ói3kãh8K[`œWâ­G)u<§JìÝ#`fþÂÉ×ýí”ʰ°ÏXÏ“妉>}'Q½jã>´}§']?ðU‹C$= '³ây®›J ðÐo™NÈT ‹dûÿ¨NÛ$ŠeØk˜DܹâÜ“äL®Ä¹ßñâDö¾¼œð.…_Ø-ÊTÌß½¼ÕÃðß­ÐwÎÞüFd¿ 0ò`si“‰ÔÃS¨²}}¶ú!3-iµZÇlf [ÇÚk\<ÀSãtuÑ 69¶È¡oûeâ,=ÙÇzÐÖ aaûŒ)À ÿº¢ê ÔÆ{Ñ•.3Ÿfig=€–AÜdj„ËŒ˜ËbY›ú@z(Ž­ýZ¸~>6dzÈ' ÿ‹Å•Ëg߸}'Û✜N+ùéÖV¿ }- iíkH 0–\²(Œ¡•Ò‘¯ßÂoS†çÁ#Êm§'C¢ÕÃ™Š”KAÇ“@l}Ξ#‡!<%Pýü‘j”)óï#Q/(¢;cœÃ“3_¦r/(~£À3IÝÃ{µïSògýÃË^ÞLå{üÃÞ¡˜n«ìïæîý´9›èœ?о4DÒv°rZ졌Œ+³ÝcÀ}<+¸öÂÌ]ó¿<Vx¥é]œÔøÇ7 ûç­;qèz7Ö•"¡m××zƒŸýB’9˜Iù«iY@`sÝ}O¥ø­ôòÜGB‰_ö?™&מ”È€·Ÿð£ŽÃ¾”8ÁȇA‡ p'ObNYÙÜ:^a»Ör7CqCû‚@ÒÉ}\D+’€€èY„È ¾òÊfåÀÄÅ¿6Ý’ì%•Å‹Ídšñs·óÌ.³}9ySkN@pEë8ÊäÇîÌ Ó‘¢„%A`B)!Y¥±îŸ"K.FÒ:Ÿ¸{ËÉ /âÅgé½cÌ -L9Òao¾Wœ‰ç[-Ä:QhM£·º%<ùQ9.ï YéþoýéZ†ú“ªáö.óÍ üN0ê]Ê %Ö\-«mÌ2â‰4K|q¶Pª?¬Yb!S´¤wzVâ0þoŒiê«mýÆŽ9 ß j}ÐÂn¦¢˜­® æâVœWWŠAʪ„ÂãaËOÍÜlËPz!€ ¹~ßõ´›è<5  ×$ƒõìÜu5ö$ÍÔ6jeäO¢Y”›9KA5™”ňt·²‡ ÃÆ—ƒbÞ •(Ò1µ²Ø»’ÎÃ2>pIqû=þ7T‰Ûã?Ã2;ì7D‰ÏÓ Ï¤ë»Ù—üvÍÀNÉ&I¥¾£>›2­ô´’ÎÝv¿·Zv•Üò@ŽàèòLWØõszm”'nîd÷¦ñ¨ïùƒøÚáÖL˜˜DQÓ£gcdô¢âëMx¦· ¯X&+×Íž¤†—g¡È´íKO„:¾&.›ÖÛG=%(ÉêšZ%ŠÞ§´õš*Zúê(7ëº/X¸}óó,üÈT"Iì“:'"­„nÂCéz–Ÿ–;¦c^ úîMtýWB À¯>ÛÞÞ—%= 0¿ùÂ9ˆ–gOí-Žª3TÁ÷v=M{ßo1¯Ü¥qý8йê1q[­Dä J¡©vŠ3ú•¸ŒŸ¹ú%òÀC€Q‘à ¤Ë c4Bðe-.2ÿVt<½ÏågÙ°@—ÂÍØ»1Öü”¸ÀÎV)öæíM"ET”[5]]ÏÆñæÕTîq¤›2ÎÕ 89ÂÚÔà¡Ô ›ŸÏ¨ñ›wæÓ¤FSâ)³Éu²À]õ‚O¥«¿¾lõì¥Åü0«ÄV;ˆ e`8¼;°(i¾’€€Òo™58¥ÍTlÍá›~?ö)MÅÏ ÒUürCˆ¼Þà©}´ Î[L ®aUOüäÂ+T»¹Zâ~ãj%³èCEfE°RÆÈµ [ÜC͸ë$Þ¿ºÆœãüô %§°?þ‹®ÿp¦ìÓ¾Èà$1ÜËPuã[x'Å\¸l”ǹÆqI°ëAú¡(™¾>ÇÍ`Þ»¡8ȇéYÖçVêk´ã­#IC “1Ý+Ñ=ÏûÁÒŸ`Z—„¦—1¤‚¿)mÒ_½n‘Fïð´ÓkQìZt±ìÎ1AoØ”ë‡ò ”n!.Ë;×C1º1#úKKúö"òlp„$%}‹“×6 ”šäÓÆ÷÷Ì@ŸÊ_¶êF7?fzld„Û¬wýkÔÜ™R`bêI@Z¨LË3kÇ2ÜOˆÜìâÓÓv¢ºýd|Û T¢Ò„»ψ&¢Ø1{$]]Ék¿wxÐäWf9žž[¯Y´âM|MÓQl÷¥ï 5¬;U„yáœHàTªñ>cëuÞÉjäW™!•±KÁF”Zó.Wµòfi/×#Ê'ø »ù¥%iu‚öæ].;<\øì ñyþzdƒ®lyW בòõJ6eáÉÜÎ`ÈÅDv.‰ e¯›ÝÖÝFîÝGœ²5Áº¶`©ßÿ°ª„<ê€ü?à}ƒ‘ÀxmJ§ÑðbE Á$äº&øDÈaˆ#¥e^·örUÁ‘¹úÌd噤ç¤#ì W"@àÄßR™ß#Z ~²@ì5˽@Q´œ'Òn84mŠp¡ð`çÏííz+_L­WK'¼gd“*íkv§A/m½eü7ÇrÕ)G' 'QÝ­Cáà¨gWPü+z„ó)‘0ƒÛ\Æ-MåñŸóÚñzdÈ}˜n’Ípw`ýN ´˜‹N}4whœû³|É|z;¤–|®Å$9 %œÀôêG®ÂÞQÖÞq€ã×{aQׂ(nXZ¨ ãþd1Âal¦¤á5ñÚÔ‚wF1η.â‹>[—y@¤”ä¼³À{ÔD®ÐØ—@}nóv¡rؽRi_è¶/& èÉ‹³šL(VÙnTÏuÊ4‘)Ÿè”§P¾’€€½Lƒ^(邎\Ê÷„öž¡²“Ön’‚²íŒ.ãRjãpˆ¿Ç”éÙ§¦yg±ý¿²‹…X Û°Þ½¬ sCÿЈ,±-Mõ'`OÍë¬9òןwj&‹XæAB kbØ\B|›êªp…Ò…Ç_– nK,FË%<ÝÎåïs#_8ÔrË”úßZîpÍÒsm)ýîÛIˆGÎ0"Ñ«V²ˆ{µ_Hcæ#õ;[Õ¸Æ#À ¬†,Rõ›€a›ÛÏüÅò–0_jëA¹5¼V Ƙ9N)¯˜÷Ÿý$YE©Yî4Þz ÍU sæ$¸²lg¨/µ—È…<ÚålBÍ_ý!TvaMmÂIÉßå”<ã\ã³Ö>’—sñ¨x ñ=Pc@Ís¯vÓäý/ÅÎg²S`.úWxŸõPµóm2’AXƒŽWùH¾Ö_f´qvºƒ¨óûߣ¬u±P“˜T 0µ™'_/ñE[ž×0€=gáZ$¤î”Ó€´Œs![¹Z­fC¾ Ñh±­E˜øéˆI¾èý¸j?rvò(35ŸVƒ%y’ Zˆ{’ýß›š¨L´ï *ðäQÔޥ̶¡ñji ÛŽf” úûÕù*+ÞaVŸ´9-s¨b¥}çï:‰!µ ?QóÔ5Á~‹kîÓ“f ùúl´ ¡¶GoèÃ9†ó˜üs“DzY€ÌÄŸç„‘ß®ÇÅÈ•0dâa %8ƒÿMŽó ÜçÖE?~v2‰ð‚¤<áü‚{TòFZW1} dS=»¾ÚO·Êæ/f¼7?÷”F`Ù:î2¬é8‡£g’=¬ïK’‚éôr$Áƒ‡JÍÞw\óÎP<1‘YÿÔ­˜yGàf}Áóañ”BVšÙÕ‡‹jãT[X“ßÀ_á¯Ib”˜Â„ Ð@[_0Õˆw»kV{ôU’ç_×Òòßâãû'½?[ª y·I˜­‡ô“м¶4~Í"~û#7v¥”Fø•N,e…äwk~Oò’ùšÔY+Äõj99ÝÔæj´N]›ûMŒh•"Ï<ÿ,7ìƒÏ‡îók yêS mvŸ06P öSS*]ì…ˆñäÂBî…Z $Ù¨ô šÖùes·¸=à¨d¬= @Gšû®†ûÛÞ 4C®A^à«Þ¥z’€€ÊL*pØ––šõßqe§êLø¥L“ßSéïÚ.”ówuù€qʮ~D¨{€sX³ÍLÚAYrHþEÓ×ô•¡òh¸?úñ*à²Ù‰×¼%¬ími—?oË$æCj8¯T‚&b#ñ‰ ²»ëxä¸ÍÉu¦‰‘F%, (¨­Ú=;‰$ûEqÇÀÌË.­© 5©ßvDÈ=î´B­hÈöwK*Œ¦Þmà€Qö:.ÇÓ×/B´?Ø…‰î{ž ÙZ¼-÷A7ªm5†=,Í…Ú(À£aˆä?-¬‘Ý6Mœ4"H S¸—vI ìf^Ùÿú#ÏȨ™GwQ°‹·¥¨â·ç„áQ›¢e‹iÕ²%Û ts]ð1ùè:ÚÄ´â—œ>rø™D”`ÅÚ”&I~Ëí½ƒ´t:‰¥¿JPdÝ2‰\eš™CÛ5§7+ï¾È~ÄLå*؆íhþªRŠÉËôì—æÄNÃÌ.•‚@o:, “€fXÉg¡:&˜ËV«oÈúŒ ½¬£ö}ØTKh:L¹œ³Ó¥µñ&Õøûv!sàÚêxÝŸìŠ ~õª8µó-o7K‡À¦Ä’dµQœø/BT{‘›wZ˜#Åoâ¾ ³ôª¹p«§’OßÉO¿{tËp‰%鿘S 6HŸüÅ+:' &ÍBõ†,QŸqJa‘Ð,,¹w9ß>c˜yÔGð ÿRUàŒº*ä[Šº—?´äAWWß"FÂ?¹ôG{-æ ý)>w±:ò[qsí­KT} ô° 1· Ï‚~íhz糨ðæI¦€ºE™d…_Þ#ÝŽªS.i ‡“ÇØ±®jCRõyZt‰RÌŸùî)Æáêš<k¤|Ã4`s¼¦ô ‡ÓÅïØaN]n¼qÅá‡'gü.ü|ÝÈ5öUÔ3N•éŸRýø²ú‰Â¹jìKmˆXy°™twý¼$VqÔÆ>Šç9é’%‘¬<{M*Hað„õZ•†¼ÿÇâÓ³¶¾£™ƒÍÙÝC"TÇ£NÐ’}äǹoÉ@Cír¢Ûí öH¬™@Aɰô;*ܯù»¹þVü7Âï^—u¸{eü¡Z€i{Õl×amô£Æ9° µ-2Ž8‰Gœ‹Ï h 0S ¿’€€´?ßÎÚ˜©µƒ¾Çæ5Œó®*ßÙ;óŠó-'pù'êÕ‘0…¡´ê@ZÙ!;Ô[ç Ç8†¿‰h±:€_ˆ Ë“Í!ZüXpÔåġڲ™Ä¹´éØ`Řa&T`¦³ ד„-ÉXŤV‹™@&yrg²ûô ³¦ã=;‡‰¯0nU3ªsI£úxúè T¨šä8·þï”D³¬{7ÓÈíx¥ßZö8¢Ál±x‰¤FYÜrÛ+3¿@*å囥'ŸÖF·À‹Ñw>æ¥óG'JB³Vœ;Ü“Ìf©Ľ—PR²>7`ÄíAkýÆÈŒÃÓã‹f«ŒâHv”9ÉEªÙúkº½X_^vï)BˆR ÐlJu¸àYü8M𘸩D‹Â²7œï£J5‡nÄ a1&…§òá •~¤j%]þ)éE\}%¶°åQúG-i’{ƒ…³jó5ë¤ LîVŠçK£_¢yä§"ÜÓ}¿ªE‘ò«ñwRÎP±õùQ+—öÆ+m¸¢mRÆÁöuè"Èû©’Õ»ÙEB,í’™øca:¤pÀ^ W—ìÖ\/³onS„Æ¿G‘ŧ³ú1"§ÒúDLA+n/Ó30·Ç P ¡÷û¢™ íîw˜bó/tP™Æ`ÇŽ¿¹ñáã®jÞ9™ 7™õ—U¨Ñ¼‰‰º¿N?>ê“Xfš^¸Å)xý0–|A÷dróQ3~Þ¥PÒ¾»÷:|øÃÀjb”fïj‡%O'´™ ÊÃW¢Û$À >ZÝ{-Ì„¬kÛ爰Cþô¤3a‡Â=‹:-V»—gVpÁÉË,VpcÒ_O1pœüwsžÛ~àÀ$Èr«çäÏ[dIJÞàÄhf5•8ÉD0Mb,OÔj6QÕ+x(AñªÁà3µ8u­äÓöû¥Ý ‚xÄCÌ#Äò~ÚU÷ñ˜èàCr›Ù¡Y¯4`)†:\gW;ö5azÌ>MY Fe¶4ÑöñH'Ç&´¤izÙ/æß©cÇÜY —Uf—¯=‡â!-ãÆLšAs4ÌìVuœTe;Ö+£È ÅW›;Iëcß™ÖÖÏU&/cÛ3AN®p(ûGø –ûk ³Øöp=3È”âNé§ñÏp˜MØáŸ‚÷mŸš›èÿÊBÉüÖ’€€°¶™¯·.sFS+üÝX Œ;ƒ†W•õ¿}*ä w)#ßÎNÞ Kµý« ðþÀÝU,õuNE‚в™^ù¾|?™åt༢«x èAÝT_G<›Œáƒ0D ¹ٿyÒh°*\ðV% d_MߢHõäòCìʹËCùqæï÷vѳºœ7Ьg)$‰º@-*%îù¯V ø„[L Zr$N¸Î]nRh ·=Ü‚vRþWÙÀny•}Jbº^CÁ3mW,ñ’¶e/%±Ù»{˜.Úà,ñþÂz7ÎŠŽ˜ùØÙ2ñ¢cïÿO\ úê£ ú{«Ñ|x¯æ¦±­b¡† ¨@_›fLýýn%d–¸vYà•Š‘Ê’w–4^ÞÇ=y ÃFO¹®}ÃÍWz{¥\úBÞ)rú­´,$*Ƨï§ê¶àL¦ð•ª¨JŽPLmÀ,k‘Ü…%ßB+â܀߾‚µ"X(3OzÑLlu‹šw‰CQ—…#þfæm&Ea³óö¢>[·ŽºÑKÒP ,?Ë] _n”§wÑ×h[mÕõ{œI9û5Ózq…›¯vì÷œ÷0X&£ºïwQæ;G¯aö@Ž$jÆèt“Pº»•š$C¹À0³,ÁØõ%L_}¦-ŒöÎûŸÍ»t–&eS eFo†»t±ÌiATå8‘‰Z¦ÿßóàÚöŒSêþ-cØD®ܾ–ÇÑ ##ãŠç/£\q\Oï×St7!ô‚Ëy {=ÁÄQ6݉Ác!U¼C|纩9ü|¶È!ÑZÖ:éo‰s‹&”;¶Þ™i3ž&Í€ƒBÀB$Š<·0v¡w“n ˆ%>³k+6|î5X}îý2i)W>a£›€ª¡°ø&{‰ZÔ#кm˜hIÕ^cÃx±VqˆÈ·Ñâ›D%ÁÞtƒïFú¢ÙŸCc±ˆ)ÍTeÐÑeq)é±q¥1O–àË5‚ktýðlÑ3ý×§œ‡½óbÀP]ÙÎ6†Õ¡@Ò„§e¬|ü*é»/Tåhv¤ÝœO4¦T½úÌCx³Åe³À°×n{ ÀYd±¸nÊïç$!éÇuóg÷ ̆ËØÝŠT¨¦J¿’€€ß»mK퀎gƒš¼åÓƒø(NVLº/_^É ïm¸Ò<"…߇VÆ× ‘^ߥTô´vLüg|Îj=Xô\fÖ%‘½¯HR1RžÒK2³K…Ò²á ¶ø'uÚÖ\[c¢±z ƒŸF£–rÍã/m/¿ìØõgKë®-˜ìÃ#•šïÊF(ÍoŠˆ$Ó¸%\¬ú‰HsÄÔºRXîªð¯5᫨R ̓.6Ä]G‰m(VtFÀ_;ý…?/±ž0¨ù™rö±ùÞëë²tøÆâ–…;f6ûŸÇåpÎÊ9 Ž[ç°h%<«¯ ÓÁgl#ÎíhЪ¬:vüâ‰af œl‰ƒìûͬ}?¸=Â{c<<Äbʬߓ.´x Ë &hý¾HÅ6Või>ƒêì%@Ü5uÊvFÉõw‹%«×¼(2ÍŸÀ‘׿Ê_%°Ö* 7=Ö‰”¡¥2M ûU´Á†tø,zîŸHèø6 ,ÿ=Q^(Ó)ðìÁkìƒYv#^¸Ì S(Ýsôý§B³Dz¹c7oÕ21EW›DNk˜ÿwáŒ: $Ñdß©ò‘ùK]äžíÈÉØÿêç\a(«Z„£|£°r´|u9èN²ØFÆå±Z»÷‡õðø˜©Òô`b­vß÷{8üà @e ÕÉÕ«kþ#I¶4=ÂecÜ}³ìËÚíz¾«»€2 1í"h   úŽ ÿ^3k]­M³:;ò_ E—ª±FI!vïQû:´Uçô´ ë‚@¾×ÌÄRÛ®ÈÜár2]½ÊÛî‡÷?¡È÷}…Qrƒ–2Ð,Ù´YÕ-ŸJý±6Ï—w“'ñAÄf£zmælfäå–Ð’s‹Eã’I¸=ÞjzõÍf ô2ë¾Nð"Cü¢ë9ÐM¤ÂI¬"+ùà§W™as\TàNÿU;ÑCHøühyþÆó·ãú3ÙÃCŠ£_øm@(JéC(#T~;Ü•·‹û}Wó»®#P¿ËÌÂsálÑï]¿{ŒÅ—™iz$ ô¬ì嘙‡lvâþ3—yx·Ã<`˜c¤â–/ Hiã«ä\PÐ5>d ¹p¡rµ°ê›æ²•-æ$*Yµgý ô³iYL3’€€½Ó|€vA=An8uƒÿ?Šñ Ó\/èx)ò¢t†$üéð°ZÀáÉAýYö¥ÃM\ *&…Ô8Âá ÐÙ›¥O;D7Dzšuƒ ´Ž<¯ìÐåÀ29îìë@*jË„í£Û¬Þźžœˆ¨x¼s;pÖéŠD{Z[ÅYY‹N¢3ÁžsµeÌÄìø¼Q²ê|ªñ5ñuv!À:¾ÿo·bq=f­V,´ÃYȹt7MsjL3û–¹oô ûu<âI,ìýíŒ%]‡öéW»–wBV!›) 95þï`y›#W ›‰½ä[Ü+Fª{ãáÙt 6ÝJø”S=ÿ{U€ã|\„ÆÛAÊ É»AYB„1A=gÐqšY/ ?ÁCÇ‹%²…£Ýv¿b¸˜„³+½R /Äb~Y¸@Á•‘饷Çq±îcÖX ¡”'óµñœÄa&Pi!ã ­<^anðŒe!Ò«aYYø\F$Y†[sÃBÃç:‰I ë~UNòš¡ù˜¥”]ØÛjj…WNØÙÈ0µ‡±Ùìá/j–“I »-Çy³…9„Œ“sð5}²k9ìùb{ß=s¾Â¸®Eò$êwLZ\k0(y3¥Zn‚|(bÖ ºÛn—á¯pöé×kÌQBò!±º†’‚ Ù“î9^yIkè,+? ÐÑMž’m‰´÷zùÏ›àÕ2r ^B1u½ó­ÑðþTt¦˜Kä9#á‡fñøäfêÔO›E€"#tz%ÆB,|èšëÞ&þÓv*ˆ3®Ç†…Ï×R†RðÌï[« ‰}¸=匞©äÏ0q>N‹×å{%WÙ˜0isq @ŽoOÚe^£.Á£rö1³ççœØç>Jt£"dÎΜçÞ˜Ce’üA¯\†<¸Jvmõ[ØxYáîD¹ôGáAÒÄ4ìh\®sÚkJÒ(dâ¦Äe3Ž’&ˆÌ5C$·€Äù´5Ñ= ÜCkGén® ÛPjeÀ‘áZ’ˆnûeÒLTfà·h’Ÿ'ô8ȨPÎ,Uü´ØØlô¼mxŠt‹À(F·&¡¸wÀ…p^àÅÅn–Û'·Z ì¨ Ðµ˜¦GòhJ¾•ë÷º×®+K SZyÿ’€€þèP?ãd¦/bâüüÙòWWdö­ÚxORÿcç¥Û÷¸cϾmžWýÇΟžrc*#FœXkl¿¦¬õCwyZ¿WN?–ŽñÃp0ŽãÐå…1 µgœJzÿü5ä÷_Sh<®42úcîÝ›X<‹FBû@Öì¡Ú›}oh@Ú9‘Ÿ¬Éžñ^Ø+#iúÔ06M† øn!IºŠU›ºŒÍ;÷‰¼7 ŒR‘p¨¿`Wéú†hã’ø,ÇV×WuÔ˜š½·ÞÓ]pâÞÓ¿$Þq]^ö¼ØÖD.`¾haëÕãÿ‰œ±t‘¸/l%ýpŸ+žÚ0[ ‚cÏ“²$V^Ðs0”Þ¦½åÑ›:|õ#ûòÕ‰IaaTœ‚Ä£ìâ°l„|Ð oå±K¿‹«QÈwòPÉ=Ì*æ/åàó¢»QšAg¾­öªf8K7u¢±ÒªÎãiâÀµ+tÂüïOäH“JkŒ´|á=¦´lÞÐ<ש{O–ëh„˜ŠÃ¬±¼ñ2ðoâ¸pþá.aU ab®8ÀR‡¹ÓÓ{@û‹~AÜ‘Oya¡[eÚ¼Üä[wÁ]ð¼jªÝ1ô¨“XW£Qñ+ÈÒ%áÿtoSàoÁ/Oküõ„z>\ZÕó&8°¬º D&=ÏðübôaóRôÅ&hÉÛ(½3CGOgºÛXŒ S—¢Öô­»HtIXÜ«‚ÆF§Þ–6$JYf#9‹&T¦Ã±4ªðÌ8þ露ÔsoFJÚºï,5§Tjw™ÿNØhš×‘Ï¿¾Ù° O#Ì¡ÀÀº†ÈѬ”…»eb ‘ÊIJ·ž ¤‰Ùò¦o[Ôn ϹÏvwÂü,ho¡/,ÔåžO{â¬bê¤×‰p<—ÍHqqÚ²:·i€j¨‡Iå‡D^îçíb`&iˆ!u¹Îõ›z@¿˜Ÿë Ï Ðæé$vË—6lJX­†Û4âù"æC´ñ…uaêû’oîåÕÅ?¼ÑD¨ËøtkOC2Ã9¶QŸLsê„\)JÇÁ\ܵ¿ÃÈ„–n2î–ON’ ¾È |þcéns›3Ñ9ŸkfPWƒÔSfðܱÌÌQŸ’€€ ÷Eíd;rµ;Ó=RÛÖÒµñ°·Þ²À=6ô®$6‚²£¨¶ø.9û“—B„Èi½ák&\ÄɲÐ[~¼MT7R!yì„<-ßAT¡|®bs¡Y(/yÏ\f§€ ï°Î>µÆÕprGL¿;‘*­„íAcl¡ÐÚï51hÆ+JO¢v?D…EÀÕ@ƒýgfߨÂ3bžw5¸3°ÿ}øÿ2<Ðuª0M w¶¼ ò*›ì¹\ó8…éß GÍ ÅüýÎ`4qáûFÜî:qä±Ç¢×¶å²j~$0x©ÊYs‰FË*.±Q‡?±8ng³~Œ´ÃX¢SÆÞoð«$'PÛrEß æ’ÿ4’ŽBá·6HíéÝÏv~,&ÝÆ…„6^ä9âvüyÉã€m=”b¬-Êž®³Ñ9¢}(47ýéfÜÖN–ól™ÚF¤ÀK@1x€+ùl¢[ÿÛ<´$ñ[rouäS1•–"ã?›ZöIvimêfúŒ x„ÖÈ’‰ýc×å [záѪ ÷0+v'ý–Wäϧ‚PòÂçµvxY¢\)ˆ)+u”dÐM$¤6#2‰S,ê1!ªßí›@l3wQ•¾„-îÏÇT|™•Ñ ˜Xi×kc °ÿƒ«nýÞ Kî½hRâ^;£f ¹G%ðWáÈïÉ¡SM«ÛoÇC°Là:-¸ÔƒWïçJd]N±iÍ,F¯ì‚¬Ï®œ¼ÃHñ–#( ëk2”*øØIŽ'{Ú‰d†X¨µK7~Ú]òšÙèðj4cé/ÄÎ3¼/õ6û^z£Cb¥4k]°tŠ'ÉBmÆ~Ά: ÆésWW°«óˆê)=’€€Â?Ú¸2FPJøVQ¾Ÿg=ó¼#v"ÚÄÞæ•˜k'–k¹…x˜d(À̷ÄýížO–C0ëp†¿0„›°Ó²½kr?;·ø÷Ëýí±¨™æOZ_3F± ap>BLT‡ð»ÝLÔˆ¤¥›@µIÁGEÌ}83cþ½ŽW/V¶×ö¢=Ldxž˜ÅP‘qöšß2Q[ŒF°H‰8ãV×þøKÐüÍ#%/js¨>èÑè…;gsxLºCMŠãVOªB#*’TN÷ÖcBC†õ M´ð3äó·ÂKPMI€KY;üåa—î@ÜÌ„Ÿf÷ÐtЬŠý^'¥ÿkôcØ`7 >ïSP7ÿï ‰Ü ÇÙø='ñŠ¿i~]äiKšÑ=7,†Ü¡–Ë‚ëoX|Ô^ÕàUàÊgçFúp…år 4œ„7UhÑö²cìk A}Þ&NÚ{0ˆ0Ƶ&ôXYín‚ù“X1Ï`µÆ˜ýê2Ubüª-Ô’»CåÈ3^WŒ(ÞÇ®¾ÈU*™õÿ[\k‹­z¥<µ@A›ŠU!ì@ÙoUÔB_g2€­“úŠLÑ;Pk‡­©M„潄5†Ë³N8Œs’¹j—NxÈúdL¦õY«7ÉìºQ Ø0Äú,ôTÍ çrÅ~î‰ØvBIùämð¨-õHK¾kìª_Æ\gLÀdíÒ~ñyßxzåæÔÒÇtéšÏSžF/–"UÇäàH轫¸}Úûî ò£³ ŠA¸ÃÍÅ»›û9+WC dUØO´3j'r³-ˆÍ«ªQž8ˆv¤©ÎâŒè£ÅÛù( äz™Ù±Ð ióg¶z ¬w¯ÿþ3 …d™d%(¾ÈŽP¸s¼—mÁ\ø{ æu­¯8=4q”“¥Æo“_æ÷ÏAíîz©4—ªj—ÀýA«'´½wù4 ø0&µ#íÕítÇ ^t¹-f›Sf!¢  £É)¬ØŒ…"—i¼¦ìöòí_o£æS»ÔnŒh”tdÚ®I?ÞÄ%4™d9{mÚÒ¬ôÍ£vª©ÀÏ3®¶„^DIÿₚåG«VOo·_ºHø¦î?@•d‹Tz³¸œ\îÒÙ%WÓ›w,›´q@•Úüаzˇôù„Ù¼½yhnº2 ÒC1 ýã’€€Ï¾ÙõcØD¶+\¥àEi5%!‹yp ! }smŒòm)LS¦wšf&#mÛÚþPß¼ºY?T=«QÚâH†Ë¤,‰:¤güvA­­È;Œ2%Vþ€Ìö*2"xXw[´ÊqTÈ+£5ŽÝ´F³Ù Ò`—kaÈøu]2æj,4S]3h+aЧ·hO×›g.mÚ!]Ù×”,ݺpþ¤R„O˜l §¾1)øèô±b’sy‡ª:¡aªA®·G#í² j‚Ý ãçkÜO7ñö}šCÒ%Ûºþëfrû«MÃ_i0P?1ýYÙt'w—7T–ñ;ßÔ°ÿ‰âtE8ˆ棟w{d±‚xn”FÓÈcî©ýOŸ~®†F@›™c=ýÁ·¼öv2I •Š* ¶YÆÊCSôcÛ7> Å3¸ÊÊÅc_êÃ9ÇÒ:ÿd«™WY•"GL¾$ƒªg).RÊðxR_¶o5‹£3îø% £®õéÅÔƒÙ7Rû{AWÀ<&®ê›fœåÂ×çŽi€ªþ~¢ ›ÓÞZy XÌãsÑ+/ÚT©t”™å²iÁ¶‹ÔrúB†~Œ —V"/ÜÎB¦¤oµË³çn»Ä#ö|ª‚ÿÄ9êUžYØê,øÏLü]d 3ÿöøÏ |’Â3¢‘¨ôÜ o¾³XSä,ÚöLº*aÊËò+(ó/¤™EÛŒ¨ôR*ï%Û‚w´•›ñ@×Íœ/æ ücôå‰ßß*Ú¥¼Ô'š´.’„ž™Ùï[,jÏ•ŽvIÍ +þ¥g¿Nýˆ@¡{]÷·*bÓsä¸$?${×Vô ]1ÍwêõâIýó KOó ­Ôáyà®tª,² Iቚ{bkŠ4u(ÝC…n Ç»ý³÷m@=ä!íö-yfK⬆¥xݯ+ñx¾®x¼€÷ò”ÕdSáêC¤År "Þg9ÃrOB®llü¡k®Hä›K/VÑòûæãA¸ò·9!Nîô‚CtÓ &B“ô´±õ¤Bª­I¤DÔö²ü)R†©÷]i}Bá1ïQc"ÁMS¡0ªAü°kj¿›Iîy<<5(9,™À³I-nèûi%ý·>z7Ú@™!мŒßRN D¼ÿÍ ”„*×6uÞ܃¤—›ºp’€€ÈÀÿXKoþ¸Ü(\ް'ÉÁn5[[ ÓÇÞÓÿ^M`ˆi‘*)UŽn›¯%š$ ƒ™cÍaêÿ·fÚʉ±M>LDȃŽyøx "G´Š'%®½ryO5FÞ 6É¥oÃõ˜Ëþ¥ô‰“›ž§CÜòLv¸!g¯7ÓšÇ;Œ@ýoh~|ï÷ìk +Lk°¾Sø”(a>gwÌ(¤=#k9ŠŽ†Jºœ2Ë ˜Ñ…;||ÄpÜúÊ“Hûyðr.ô´†Éjͺ¼ÅÝEÎߘ÷³­O±†6•dýVðŸ&õüë|Ëô‹}¢p4Ý1ïõéi£ßiŠ­Ò õê/Y·§Ÿé$Gó^¥€9ØŠ%Z¸ÆŒ-05´€£"n†…5+2G2ùí ×éi?ò”þÞâDÈPóY±µAϪÜ!&Äš"E…Z¡n˹³‹à‰Áª( 0¼##+µ^7¯vÈ,">Ú)ð<ù‹ò„w_ Ú®SHâ…+S ^¢“R¾»Ì~3žh2œki÷gõ›Aíb0gõ œ2лpÔrñgÜ.ª†J‚!É›„—R—Ï#î Ž×Hí˜wB}ÉIéù " „‘=*÷"ÖUªUØ„üªZá')öRŽg†ïÙgƒÊ*'Šx’ØKz\Kg“›Îú_Ø:öoâÚŽþqñLð´¶hµ"¿(!À@ÞWm籫¹?Ó00Y' ­„¦­» ‚{s ®’å©ýbaxÔÌ£ùÊÔ'£lÄî38:‰4I›a½cBýdˆ¡®roåL™M´&Í=î±Ô—/-ІÀjÛ%}·<C*Ëo”fèÖØ¶kiwÏÞ›úÞáë¥]Ä«Ý$³É›éÖVs‹Jl,„’€€ÉAƒ¬5Šƒ®ào3㨹ױ#uâ *$‚T¹}hüÈÜ·¾Ê!Š_óñ±FmáÈå6h²£&°e‡&¡gU„Ù ‹[;—òå~b /2 RhAŽmä<%โÑè¥u¤OŽs|ÆÄ…o°v„Þý”€Ä€›\i %ª…6.mÏŒÀ¡0ò*ÓN›µÔwêè6eÖ l¬uäÑèprnŠË¸[«ú¥‚clc»¶[ 'Ê"ê\(ófX¦Ùuîà¬-6hA“„Ö+wqÔl&¡äë¶¡ŠÒ­W’(Ⱦ©T@ío³†~°I¨ÔîM"ëC±í"±9b\¹GI%Vÿþ“ÎßÞøÕ·Úˆ°p °k§“XÓH¼ëqݤŽì„N\N×ñöÞ®Ç-àX¯H ƒ³[Zý%–Ž>›ew_¦^/YU@65gWð™0Óaë‘û¹^SU“ ˆ 9ÆÍP|¡.ryd ÷¸;ˆg0LtâúõÈŒšm¨»^{žœ*ú-½_Óþh:Ñ8Á ´EV 3â}Ñ`ª1µ÷yžgú¿»ššÔr\[&bI×4N'¢Gá`g¦ýÐ.˜ɊCŒbdÊû1ï‘l»6êûgÃâviùHf¯\µÄ5mBØú>??ƒGš”ö¡ê&7ÍŸcv"B¿ç„õBÖ¹DP Âz/¶CqˆVÍ긷ƒq®`âꃶ>‘Ï“ð¼ i£ÓQ4¤wu“ô ­¾N<6‰°šÍ3_°L#X@¨pÛö:mü rö°lkì{KÆ(pј¢¨¦™ýë!܇L…,¥‡*€o8à@÷ ÞJGIåZƒH8!žy¢Ï'ÖcÑÍ®³“¤›JÚÝŸòmlƒò­Ëÿó2/Ç´ E®-Žó0ÍÂÀÿ!^²b–ºöqu³@ €e› :.eè.™-m£€ºöú)¼R,Kø¾åΩbÊ ë1#=ÈAK~6ýËžÀ‰ùàS_Þp#†cVº4ŸsKªqáä‹wüÖ‚cÇàÆ³‚Ûó6Õ±Œ™¶ƒ½0û\>ÇšŸ<~g;𫈕Ra \6L"ìÕ beR&j{Çœæ¾G|UF&«´3á¤kdë‰mT}zéÙ6qëÆëÍÔëŸ:ÀvÃò†X¾ÿ!# Þ¦)öª>T›^Ì-@|h°PÈQÌÎ>êŸü÷샀œ69­£³Xµh¼û(ÜO„¶ ™ðÙ1ǰ9²³b|O°šz_ü¬Å3ñS=¥7¹Ï6¼;Î7 ŽS2]Ã_£˜Z–H–^¡>Â@A•,Õc±‡@sqý†Âu†Ðºàv>vzPÏå«]A93Üq…lЍ¼DÜòÄJt—'®GqqåA¥wsNDÞˆÏtm†Bùëf']BUFÛÖï¥eåC÷Lý4Û° ù×uúºÚæ‚rç0= Ë£]Úé«IÃû2Â:±•B—T^ 1ÕcàJÚ=ª># F<äÈ, ;±}kJ ÍØ®À(®†ÝŸ\£ ý‹© î¿#ÏïÙ˜;ë+u«<öÐŒž­ÒþÄ ÒÍÑSd'»ÐpìgV3Z”ñ-æAåÔ/¨lif¯8µàãJ>¸E®üßât ilôÒYôeš*Ÿz6é9ÓÒ¢9 œ×S ªwÑÖ†½†½E¶Ål¤hH¤ uU˜š&\Ü“O,ݽÊìG‹O>ºðlniUCF±0ù½3Þ ÝÓ9˜Ý¥Lüä\Ï¢«÷v1G¼Ã4G0P%ÛÅó«7 ƒ¡+3ÛoèÑöä˜þ‰þOø¸4€Ææ(û…/J3ïg¤ÇGnª kku‘/a€%­œ9$(eÖ•ÂzO‡¥Pâ¸uϵ%Û nìeÕ1‹ë«W½L+îvµC…~=¶ûuíÎ#f¶$®©Ž0Né¥Þ*¦ÊLÔõ €ÛŽWDØ6Sxë$È€î/“4FNäX¹2¼Í’€€ÏDˆÿkÒ=<‘>ýtõ:Ms§÷aßQ[ÇXV|÷ X„´ÊqÔÌæ0-ûsm©'Šìö~mi?ßøâ^§K†Ó†þr!WËP“>(ÙiÚ>¿ *E'µ‘,»µxór.%,P[LÓ;>ÎÞ:eø^ B–Ì‹QBqÞÄÉ!Tî[ùŽ“®éð±…º¡0ï1„˜’ òú{ùeî]ŒEm!ùa³D¤Ãfo¤à%âo=zxJµL­ƒWLGjV%Öà˳6é%²´;qqWIó³©Â+j@¶~cCß•P?ž‚E‘a„x/÷ŒÈÒnÍófTÐóç¦ë@W5}ì½w[Æ+ïÅ÷µäÁ&œZžæ²%„ZÖV™“jÝ>x±^õ#¼á诬Fî¥Þq!°—Dp•¡z_áüþVáý±c@”Æì4…H‹IZ‘ãýíøê‘'ݾs%ÝyYZøƒ£äª‰DI™Ë o (¨}ÀP:ò#®ëÁ!Q‰–_ÍŒö¡¿qWn÷|ÿ”ùé±oÙrGl@Í0P‡1cMibïž=p´±Gúo÷1#?f ôèAXÅ'Ì—G(¶øs|Ì,ÛdôúåPòÿ,*ß°Šc‹Ôè¹[«¦cµ*¾ÌD• žÙ½±D˜v’®¯xp0œórÌâ¥ÚÒ¿ôüxp×ô­Ö—_ð'WÂJ¬ï'üªÞ<›Â«Wó©Eb!}×`Þ†–Uë'q©™˜h¼þjÔäþœø²h(l-ËI”ŠÊŠe(%.}qG8# =õgjLœ^ûzÙÚJ #J2á÷Ø—2u²v¾0ntyè«ò¸Cä­ØÛ‘ªwÇø,”^&¨zavûj/~Uš;üSDI…Öœ6ÌÞåol…ÍQˆ×¦Ñ*¿ ß C¼*PXí•*`wþo\}ÅÌÖ`âæ›ý?BÜØn|šGæ¤ëôiâ+²W~É5æ·qÌžÕ¾¼ï"ÒP®HFJítF ©¥h/oÀx•ç¨`NvïVgšpM)ÀYåŠ2Ì´7kʴ̉ÝS—yXsÑ-kÅ[,!eÙÛLΠþS'H$«J]¨é›“¿I/àØèØCäée\ð—5a4‚B¹üzòbÆÜm”\}¢Ð`î·j%ÐÀÓ&lõ‹>ƒØŽu–åg0覒€€¤ 6kÄoÚgvîo ›¾-Ñ»ðð²EÖV /i×X8€Üe˜ôçêÒh MBe0ü{iwñ0‰L›UÌmŸÂoÇ“§©(ÇQ-¥³MŽMßkâ¦[ŽŠlذϤÀÈEVÇ$NÄá´áƒ×Rø ±3&CBêÓ…ì¦ïµeÒØæÜóa ½üî‰Â\{qò8¿]9Þå;º‡Õq˜±˜kú§SòÕðþpm©¬©·®ä¿cFS•ÄóT%ãhÖZr=uvµ|ªÛ-µ™»¸ê6àcŒèœæ ¦€ÏŽÿ{׌M­(k¯dË?[Èv· gª¾¸þm|ÿÁÍNº 4ÿY^eYFt î&¼ñ¸„s ´×?Æk¥œëè@[ñš=áůxPª˜° ûÉ4æ @Ûäû\ü¬…)íŽÍÞ„ÎùTCb Ê#¢Þ*Yvö¹dî§S#s¯…Q.þ«#5Ô´}«ê™ã_úgJ_¶ãð Æ_Œ¥ô3Ò¡÷d‰2l*ªçU{«ßI ´ÖÕŠ|ãg\€ã¥4™ÜJ›ùêàæ­Íñc%âZ’çé­ÑK/ÀœÎ®YÞX—ᾦ u«ãK<ü™î©~Þªµ[:%_Ãa9X¯&W1R]S—!éˆZ*V¶Æã ¶QÚ‡eu0„o(«kED¾MKáÁ4ϵ‡‚{ny¿ Qzí½õ ☰ú…1ϸ5s5Óo²[GíkŠ`®>ûyž›yëÏöaflN ¬dæœöÜ:FŠì–ö¯p9ŒûEV€¼¼Fu“¯9-:ú(N^,öG°Ï¬ Gʧ9À.¡BU™·ñz9ÚY\Ðrþxoú$¤°©1š®ï¼ ®‘Ý­º”/Ëï}V™âñ+×{lÕÙÿI©ôc–µg0…z˜ð³Év¬™òB¢ŽUH-1÷Ä¥Õ½£‘Õkn'e›øÕ ®gç&u‚¼4XêRˆ<Š÷oWvý1€¨Îæmoá¿ÿS¤\›Ÿô†•ìäʉ/{u!KVj­Íšõ¾éƒêK,åýâ7Ÿ®ÂzI“ÿ–2³²ýŽQþ%O°É€¥èÃwT–æŠ`úÆcÒ$3 Ýr_ÜÞyr“«jʾ/ÿKÙ"ßÓ=¸ƒñ =%Q\’€€¼Ñ8f6ŠÀ]æ–Ôì0 "µ½Ýù=8…rÿF)èonÌšbZ<²E¹!ªˆâÙÕ¹W‚î\¬EuD艜†ã2c—‰túv+CÄŒd-ân©©MøÝ„š¼UK×u$Ät¢“Ô‹fû »øöŽ?϶:D_ëpW!Ì+"¢+^‘ǽ'çȽ!üU7£¨[Yåï2qþ2ú,­—, h3sNj)yEl Ž׊U:Ó2ß9oråvý71ýn0HJ£ä»e3–÷ð—”}ª6óü$îmi˜Öv÷GÞw°Y}ŽÅV„Øë¬HX„T­ë¾Á³>Ï Í/£C: …á©CxJ,;!ØP;yd;˜&†n{i&Vp6¸`ÐSQÁ¢áós­µêS­‹hÉ8/_9ï°“/Hš‚Š1‘Ù@ lÞb‡ 2·qn·£›tXÁ­‚£µœÊ²sä»BÄù¤ò´ÃÛ&­h}3åV¤u$ƒ'»²O¯\(K³‚í¶ wà¢bsükQ,…²?}r*þmntîx¶PÝ]E‘N#XÄDï½ËÑèdu˜ZSÀŒ¥ZabX~Â*GTsÞfDK_*$ųòž³9ú¦Ù¦|ŸZóöß ´·¢gðnõÀ´éÂÉ,ahï«áó<'.Ti¦âI÷m°U‰d¸„å›Ôxó÷Í'2™Ø’vÒÒÍK¿«‰÷«&ŠZýÏÆ±/ÝVê,áˆî”¾ÅÏÏ”# ¬‡½(ìÕ|‘rÕþ°iB] íœ\ïK&9*eúÜÓîdKœß¡=¤B:ÜèyùeéYßvNÖªm¥“­ß¹•Ã[½owß®Éôþ×—ôaTs ¾5ª2„«`¾²¡t͸L‡Î`J¡ÒÀ-cÖF)0ŠÄ ?™SW0 ”áyô(Io;õ{°k¡šë¯¥µ3¾š ]*ïÛõ´%Hô$§×û ÉBj ´áæ~[[£q‚0Ù(z~9·B#wò÷!§ äs׫64ó%ÀFsç¿ZÙ¶SOûQr¸Æiëõ±}çbÆDU´|Ϩç|÷I¹ÁÓül]ÙmÛù®r¤uX݈÷sI ?¾ åÒÀªPlÍ×vÚQļ˜—¢d¯·$¢}€zCœ=n—ž­†9ÛaþxÆ’€€ØŸÛsæ[W8Л&Ê~ÐT¼|*jÍ–ZÐÿ tÇKW­l¹SK!aþââþ‘8ìÅL"h4TÊ€Ú§ƒG0·e¶š^P³½1›²£tìùq|u»ýoèôy¬SoJO“V,“k°æªì<Ë †hЈù2BÛÔŸ¨Ÿ‰¿âÉÏò fg#”Ú]˜tÄþ WȘiñÖz/¦0ç›1 Å-244ëSú•àŒÂ:Lí ½ÅBèíj1´é'ÝP OIKÕ*ÓßÇ)ªµV7@ÿâ=ª80)SAF>zYÇå*zs'\†7­PšJ‹ëî¡“iÈ•ÑxØÎøJ3Û¨œŽ’÷oiÓÿTvääQ4@Ñ—¨ cÆ}Äï-(,°ÙšoB ajÆ¡qG‹RÂ䬙‘Ÿ\ WÌ8tÇÈTêæí%ûÖUó/TcExãÏÎ@¯õéøî Í5…9 ¤¦,Æ ÃÆÝZßÎ$n—=åàãØl½xÅaÿeáp»yM+>ê÷AàÖWáö_¨¢À-²nìõ/úõfàð&çÂÝ͹•Fáø*˜@Z=–ØÃ…Ý‘'Ì‚Q´äm7Ê I6HÚV3§ÜX‡üˆ‰ÑØíðê8¥æGtÞÙLäÚ7Ìä$aXå%½=õºÝÙ[×([iÿÜTÒžjDvc™Ôoƒ$µÜÈ©ÅôÍ!T  Õ—'kP'çßÖ@†­{ü7­ÎÈ™‚RH,Ÿ3¹¯þ:Òî`¤èàX¢ '5Õ ÝzǂƵRky*¤á/vI ó‘FŸ5¯ƒó¹Î›B_âG$Ùýºá ò@ÈUàÇĸéõP­t¾(@pûÏoÅL¥»¹J2÷Š·ne ý!^±ÈŠ÷ Äb>”°‹Ã”k¹•8màb\Pб¬|Dz¬å…"v–r±äÝd¥Ú€²GØAEgä_ÎbÍ9Ö’÷¡cSÇŒz™Ì´H®#Âl\M ^ýÃù:F¯è¥Ñ&åHù+‘ví´}·Rjº;LƒB-H3‘ëJ]7ÿ¥NiYžâu&zá š }ϼ²»‹þŸû²Å ó gôjáô»s¿}¤«¯´o5€Ù?&hÑL‚}ØÖNœ÷ÈÖ)=qôARš=o ÀdØWãäÙž4“»ú懘ÕhÿPo°×› 2ï#7€°Êì좿• êþÈѰT0‹½ÎÂ¥Lú‘)Aÿv=j+´«3+Tj¹uk0Z§é‡ôh‡âa:F¾¹eÆ= tM ¾àVA™F^à­°‰c6>#ùîöƈ2í²,Î<ˆÖW˜œ 9óÐέ#1¿ ²b¶Ä¶{¢¢á(eXòÑpèh0g`}Ú>Ù3 U³Å‚kƒ¦QG«ß€%AÒRIÚÐ\Ôg,‡"]\u“0§h7ãÒa“±)¦÷wÉwÖ:M'Zãë²?nHN[Ž·NájÌ)®{íÉ ì“.ÊF¨¼EOS߬0%>’£pÕíµ| K nÈ:²LüÙ1©†›Ýlt)\£c¾ Pœ^x•éD^f˜eÉ#.LlKô’-º3†âµu}½h¶c„§§øvÂ;»hî÷ róp-}4‰Wjâv—ÙËðéká<áåžñ´:Æ_©ÚäŠP¡M+wàR©”ITýœ·àˆ öÓ&wEmÁf®‡Õ€”+ŽÖÙlnR?ÊOϧ Cn-:^&î±ù¥Ý¥ƒ/>W¯")Á{v¶Àå§! ·_CÅ4ÙD MJÎÿÓSìíë#‚“MKäóè¯Çû&ÀÉ¿QŸé¡A(A¦pDm‘ÚFlÞʽO‹ù÷¢#ÙrOô¸ ½ò0¦†¿&g¹Q+Ïm <®sN\E»ÀdymL4æÉ%¾‰=Y$³:·?RNÕÖ‰½äómùme!‹¹»¡n£Ÿ¼FÆYÚJ±/_›f$u2äÛBG©n²š8ÍŸÐö™#Ý Êÿ»ø¨èœ¡xZ¥KÚQFª 9±51/«qXûZdæ)Ùä–"Í»YÙ¯âÊÒ2úèl…ÄE„ùÄyØ‹¼ç6²y¼:Ù’€€ç?^ýïËË>!\EG¬i7ü <þz tìú¯=¥·Öp€5%û°´âSñ÷òøÂUpÑÀJ‚%Ù%¬ª·Û¡¥)bÇ€›.Kô sºÖrÕt  ”êh‡Ïoøj ƒ+½޽Ą#ƒ0$dwÆ«Äuq|ÛØáÚBW}œ6Ht¶]¾\ÓÜÄû9ªmIæó»Ö´¥¥ÓD¿–9Çœ?ç’Ù jüel1zd9Ot=j‰0°¡½‘íÞ~åÖµ ÀDl"Ä ^I F±Es*Œt3îZ+Nè§jÇéòiø¸¤Nßô\¿ËXªF—}„`»KôuuáC@É ­½³kEã•ÌR)þ¦fª}>%£?g/'t@”zx6Š'‹TSH¼U¡ºCÑ#w-ä³Ü'Ž7?4oXÃh<È” E§…¤=¯¶{Û¢;–ó)º’›,øfÞIX¤AHó1VcL“»…‚hµߥ¼ë‘ƒgì3YÊö‚ÀæmŠX±+70ÛãH¢´-“ØÓfË´òo(RsI({VH8 @ ¾2õî“W#HvÒJ/3ØüüMSeÒ< œc‰$9óÑÒxwio“ã bÒ Ô”ze1Fñ|~Š8žvCŒ!À¡­#O¿ä°ÿ|’0ýH¿Qcø±,OÚ™ tk}ZGÌV*`kd5Šêß®5ó‘ðêÔÿ[bjxrv<ö@%Ö ýdyxL¦ÝwÁÑ–8JóDçTqu[Ð%³þxÂê¾€ÃLYÂζ!(4 ¶s "<óD|ð /À…5"u£ ”Aî |ÕdÕšN€0]¼X3rþ”g¹—ÿPê{i¤É©;èE܉ê`·¼3ªh® ™&%u5¶€4*ÆT±Ë,ªùTÐ/‰ XŠVR³¥nÔl€ÜNW -±ê‡Ìï;%r6É\T_Z«èåå*ÆÝY U–8es`Ø#CƒØî«nvBÝߤ„Ã> `1Òï»ÑŽ)hÂp¸7ž…Q›lÈØMãeÇ—!¨:qóSÁåh+¦DÔ~³aR·VŠI"†Ç΀Ž= ‘ A„6ÀCAܨhàñߟb ÁB Q¥Gy–³ÉnNKÍQI¯…ùFU¬ºûŸÐì¤hö’€€±YUr¤.xO3‘ý’À;#cù«ºà蘧qdo˜¾`_\«;b*¬Q‚–å i £Ñã«ê¢–uבFDï‰2—¡=©Êp°Š8v½óɦ}3¿M]”ú&nßìç¼ÒÑi÷'QÓ…ç6uqf±êÇlY«{þAÜñ’…Ií}‚Hvî/rze>®Å;¥ãúJÄëv×¼šý>±0Ü [Ûs±1.þA÷‹Ð*ƒÝ-¤)!o’òÿé?¢n2ÞÅcË-»~R=ñOü&TÔQÇâ,ôèø9Œ­q×gÙTŸI,fUËó#†Á¢àÔÛ„F hÿ§Eã}ý%üó1ÕÈŠŒ…È í‡êïëµ²˜~´âÇ|a+)ÍÉMÈ4¢`﹉6­äÖQV,™nÅùyFK9>„¶EÐe…Žv~Ò`’`d¤CòÇV‘ü5ͪߦ=Ԯƨ³C\ñ_åúQË´Ä*(ÞQ¹B z¢ç¥ }Ô>bdl3BizGGÅæU5~r£¼ìùg™Ý‚µ¿Æ³«÷Ž¿¤¬s¼¢íø`¹“ÿÒ!äÏÆ­HIèÊràjT=#”‰æ”ó¹ÁŽÉn T"U«h±f+—º"‰$ôu]’¨­ª¦Eãÿ&⥕’+ ºÂºá؃vP±¿RkËK‹# àDã|ïø·¤˜³ÈçåæYP®D¤ Û˜”Ç8%ÊÏ ®ç:N`T«JStî0 Àó‡¢ñ·vªì+ï¯Ë.Ûb  j£±Œ Å®Ãä .wÔvŒ»Ðé|á`úßÉÞ©Ø5b§·t2„í-®¬¥Ží£É³Ñ±][Ì“¿±¼©¥¬Íìs,]HtÒQßá.ݦ†ûÔˆ©º¦òO¶Ã<Âu]Á€y' 3¤ÉÉîjÛÅØ7»÷Ѐªc‹ÌbÍø)Óå ýúÄ®y¾ZROËPËÄ`ÎŒþ1R¤Èn¨£(8vDd %„»(×±DQWý;ViêÍÓ‹Â I¶IýÂr¿¸ä ¾ÍmÊ't Êg؆}y«›±Ùæ÷ŒCøü ÂsùÆÀ &Ký´WU£ß æZœ!3íà”]pZ*Ï K~£7¹ÞøcF%W09·ÌçÕ©ûS¬Äõ°q9-ÐTŠÕסÓo^Þ¥ø©,6Çyäº= på ¾VY0ñD—7üÆ×oi<¹ö+Çêx&!“aÞû‚€ß_«ùïN v§:'/ÒuÅÐÍ 9Ny˜7CëøwÒSö>Ù9ä™:‹%«zýAÿLµHƒ)AÈfèþø–ñ‘­dp²ºVûK‡O@mÃenbß,()8f€u‚Y›–)ãDR!ÖyÙV¶5ä@k¥ÔK~aÙ®a)ñð®_eÛs&|§OÕwë|çÃÍ}ÊXÝ×à6ÿxc5V,àJ|DôXo˾.÷7G†&®Gq»0÷g€Ž–®å`8þf'Á<í?ÕnŸy¥GCÒ†FnHTxùV‹Ã¦l¸2L’À¯2Æ.aÃè ˆ&sr Ðn¢Eî¿×Ó'ëIêg†. ¥l—QñÀ4ÉÞ–D(þoiQЦð¤&­4¢QKäʪQ{…n%ò̬‰d6×ÛÒ§µ’€€”„XJ¡Ë‹Ùp8¼g¾LÄÆñ ½ñðÌ‹žœä›$ö`ž}]-ud1v°ÍMc›ÿ&B5²ASú0®„õSÿÞñÜ)d‘—–™Q\\¬&÷Ï-Vl¿þû:q#¢x„€æœØÞ4†ŠØÜ¸-as*¹–}nÌ—ðÁ`°Æƒ/©‚«§ç{›Ï+_&fµè49ntÁj¦žÙc@cÔÛÁÞ4^YA÷zH:‚’áUƒ³Õñ›ñQÞx¦¢¥ÀAÆZíÍÓDµ¢Ðå+qˆƒ*$pÄ{4#D•½$2J³ÁL#ÜZð±þMŸ¿LÐG¾üp°çÚ·š.ÇŸAÙajÄ­1AÞ˜—厱(_F&Ðørqv-E]FñS»yèRLÁä½íÓ{t>=Áù: ÌR¬vz~œiÃŒÈl¯K'x‚qstÖéÀÂÎo0œsúIÎFëåàiÔm9‚Õ—Ênd5*úÖÈ•ÀPÜO÷Û©Æ´‰(/;Ìó§o޼q‹wÙy¾ƒìÓѯX|ÜOF›wx4 _i 2 A[œø<ý÷ä`÷š0÷…ðU<ïHˆ'Á3¿ ^†!>€ÌÖ}t&±K‘Ežû¬v|l¿˜s4ûÕ{î~È»pÿ·‚¿Eªù³&†Šé°%©Íåogö&UÔíÄ*»ûvê¤Q@P­Ún ëÄÌ…Ha\éDB#Ì믒f?wh7}%EcSôÂË£ŸÝÏ‹ról6_&·žaYÎm0WLÒ8×¥"+{˜5# !“ÏkGõàV¹X:e ´Ûè,¤ÿƒ/_;µ'o„!¬çyk;û +௚ïVGÁÐ÷/õFK!ð £íž!“®Œ§Ì?¯LhRêê2yÅ媆ïÈð‘qƒH YTU^‚ÛóŠqÿ¹ØâPò•1C`ǫ̈Q%`Œµ…åeý;]§“ŒaëI˜ºB‡ƒ,ÆTHy¸®ëVÃ4c÷ôlŒ*U("=:7(ÜÜqMÕÈ0ÿЇ³~»à£#—FŠÃá—ò‘o¨ŽSNWNUø›–ÙMí @Õñ5¨¥™e`‚xŠþñhv=Øé¹óžäò¸|Ÿuˆÿ×ç=© Re´dèý”vQK€pÜÁX;[Æ{Áë.ùÈ[ïØ†¦Ï*è»–‡gg°¨’€€Ú&[ñLŸoÀ)lßäÝ|-6l Jˆ_¼ö*nØ ý¶±p*ýŠýHNç>¸ ëcÿJm‡2©²_b"Bs›4*FiÐ’f4X r±*—· QUýÆÅÄ×pU~'ǘ÷œ½ Š¸çh¡=þ_²xbúŸ(`Ïùâh‚±1zBC!R"—y@IÝ–Ëàs¥œE!íà §Ñ. ª ³.¥¼•„åêóëØ›l’ÆRæ¯}#®ýb :’EŽ6 U={H+èX²غ‘~ÆÞêgÙ€¼H0ïÅ©Y‹r3p0l~¢OrR¦QY€Œ¯†Ñ¿S#¨yfεG°¼bËï)+ êL·}.¹ jq„‚À·¶þ×L¢gu’Û ‡•ž"Ï-ìâ^ã5< øÇU£ÝIv ߇`÷Òü¿M|èÑ»‰µx[o%tVzMä‚I1·zYè_¨}UC¸†*öG¼­ÍYÌŠÛûib® ´Ýž?ƒ#:J£<8¯!¸V°:ÕQwZáG SQÕ4]-dLVöê;@Ø;YpëÐÕ`Q†»D¦õ!“/éˆD‡ÝžtûÙ§l¼’¦¥ë£|иòß\lÈw²^¹ ÊZÙwóÔ"øˆ‚Ißz˜mN*¬D-:Yx—D:[ÞY49¿d§$Íþ¬l¾+¹«Ô/0ã¦á5ÄÿÇÙy´”'}AO)²Œ`Þ~Ô™‹¯¯@¡Œb—-q\®ë‘º½µÅò-d`>Þ¸OSY8ñƒ9ÀF‚»+ÓiËfny"ÌJ°4Í'mi æÜíÿžÐÝhDÐ 4œpÏ×,ñzl+í¶kF[ÛI_©#«F Àð㈡ò¡qŒ©­žgûÔ莦=òôDø\¹ˆK;ÓkFÔbúsõÆK|R¨uÆÌnwõ¨f·¸’°m©f)ßÀ%Ó;æHêpÜq]¹ýØ,ª¿¬ Õ’N ägå¾ý~ÊÚÉ Ðu¦Îç£Çý$ Öˆ^ÁKÄá‚«E.(QÂZ©õo–XŒ@D:Åõ¨`9¾"ízJDè¤s€;žÝýfË c úW¢¥IS^±¨©Ã{Oþ©þi9¼ÈíòV#w½ã«=ñ7âà‚bM(0™Ò#wj´¸ÙHD×ܸ ànþt¡§ÙpJ’€€¯ Ã{¤•ýâr–£2*¥¿u´Ï´½ÿ—nbÊ)ºôxJq²S&ðÂLã4\@P“B“Õó4^¯IÃÎ#«çÑ¢1°—`!kßqp ˆ²sü~ëÚÛUXÜìœÊ þºÑån8ÎÔONZ»ü­â(Òtêv=Xü÷wâ¶’€€ÁÝqÞ–¥•Z` güp‡Æ/«nSç‰2EñNc·ÏĬ¸´ÛDHØgF4¨îݩѕ±´ë¡½3ÐΕF”£Y®å}\°rÍKkô`é –ÕosÆÙÑtÊv×ðXÀ†ÏÀe}ýYÜ4¨‰Jy9ì6àY3ö¹ƒk@¯8ä d‚UFN6­àq0Ù‚4ço®Å'Q·GU|gë¾Æãœ~_¯Œ+»(CòT:]kÊ}TN~u6ˬ%1cúG±\4¡¡oàä÷™37PçØ9k“†?¼ŸNÓSð«&qHbÞü ë­Þ˜CŠ™¿m¤øÎö63ë»%BÂ.'6]¶‡š$9¹ ÛîŒ7lJ\™TŒ¡J2Ù2!\YÈku¹'ÝÑÁßUž¡M½·xã„ä¯k/‰ŠX 9G®§oغãœòÝ…_H5R4 B¯À`wÅ6p&‡á¢xY©l¡tƒ°’ã[Œù/ÈÆfd½1bB[[!æà`†nçˆÛŠZÎv†|Óå#ã‹jS²éS¤Åþ)ªÇ8;*vµ#œ\g:ÁÈ^À_@}syk¢ô!T*.Gá\7((‹«=FÑ1¹œ¤¨£l_„ÑNíŠBšÁßhd/¿UW:áT|wNrkòŽê­õ¸ÌÍS0¥s<×ìëÿ,W¥#(yãW8.ÎÔü/„Á6rÏn€%£ôR aoEE«-ÉÁ,IkjßäòU¨ÖI |ï”Ý´¹5„ÍîÛ3„¶Æ‡:Õüo0¬‹‚ÿ~Ç4#?r{,É,ÊIêߊ™µ£|Æx–Í•;u&ÇìÇ%oÆ'7Ñy ȵˆ·¢äæ#‚ý¯õ¹¡#Á:Õ$’Ê‚‰¿`ÂiÕcÏF=CGy.qÇs|‘¯p¾ÕqW‹UW Pr~n¨Áx™ õ—ÇPÆ®^ã§ü#f(CSëË‘ ߸ñZñOú³èdA8ݪæøLç}&ãëx¨¦ƒ „6ý«84Å/ƒ]8sCV6Oºw®/%+L¡xð¿_oL(1ûbòÞÀ·†!»»y…€s8ìªW$§}µ+•Rh•åJ13Õ $+&"fUâ\13ÒˆìøàâpóÆž0ZœÃ+23ðI%êÀ^þŸpåâY«´ÝÐë<’€€²q¬Ql’+ß8$,¨å Ï@.Pª¾‚LÉ‘©ˆáh°ÿâsMbG–ü3?ý€×÷o–>@²7:o’IqK˜xÞñýI´hßõ»¯µ:»Åþˆ,Àù½#p£Ñ€’ΫCÒ½Cg.¬Mr›ï_~±àœý?âÞÉ¿ÕYšAÐNØ&žðäðrÀD”,Ú$áG{)h® ?¤)ç…²ù>W^ûiß&^R[,ˆ˜ŠÿM ˜oƒ”¶Úš;éô*œ]g”Ó¾K#Ù¨ZûTN•‹·ÝØE¨–ôUr±€ÍYéKÈÂtEÒ¬|Ä›«(Š}zaˆ|1€t ,#N—?Å/Ÿã¹î}ÁÄ6x¤Èƒ=M¢wˆ²Ô6I¡[<ùj2+n8<_:a2/ñ¿Õ°FÚïu†ì‰l=5Nu påd64dVÇ¥°%™3Dî„ ØÀ€*ñ2-M{Ÿ°Ð¥ïMd…˜žˆä1Cןá²WfjiÒH}¸8O½Òga~¸­/žýu¦~7º©“ªex…¾|HfROÅ]‘PÜIÖ<‘@àœ³xèBZiÜÿâ[݃õLpªÞÙnVY2:Kô¨½r†¯‚Á,¹Ëž²®¥º0U;µãI¢ «SlqÓ€Žx[ÆÈà§Ks«¨¼ƒ Ô^X’E-³¸;á›ËêÚqÑÊ µã?‡¾ü¹¡Î:óÏP¥­Õ;`ÒÄì°IsÏ©93BÊ0ÆÞä¶ëh¨ qœð•9Ü»…«“-öÏÐy|H+5ÕÚÏúb(_K*6`v˜–­Œ¢Åïè|yǵL7(°‹°û ìדAK, {Ò‘j¯SxŸ´*Sþí'âïß;ùÑjPÍ'ŸGøáÝûéx£3åÓ°-† rÃêVf‡[ƒBÚG{ݺ¥ï®j!½­WÔ+±gì{9þ»øš6¦EYišP‚r%£¤žå‹*`´Ç–äÚ éñ­;~uûÈsûúl©µÚöïÁâØÆ+_%!WL>}S·k·FÕKeq×ͦl´4mŽï̪’€€âF¨8OWÀÕY™å^ÿyë=ùà\À| ŠD臘Ú Ø&FƒtbÞ!Ó—¸ž|ð›áöÕå;àéøù(l7ü:óÉRn\JÜýq@±<$´C”ýâË™ÛÖÔð„¾-´;Ž $’2â¡´’7‚µ‡GúÿšÓ£Õ\¸X‘\Õ6ù¨k‚qÖF¼/ÂNÙGtFs»KàZ€nï˜ReÄÉ…lÉ&U5÷¾e<1ÙÎ*â©jÁŠ#J˜’5#ÜÑÂóíƒ,¥œ§yſȒPŒDèxnÛÕUk${rì ZŒø3Ù$ã"í ýGH}—äwJ!~NÙ²ü›sZ9¥DÓ¶dI‡·Êðp«„Ï‹=˜A%Ô ¦½.[æ0 ðÊÝ oâÜ¿‹‹Ý‘Ýíh>Ü®ˆž’›cFj*ÞüΊ5½Ñ­,öjqm~#2ÜòèQRúž¶Í˜`˜2o°»'°Œ4¥è1ÛcUê\žŒÔ ^›ßgå¬ÑP² Î>¡¨ÖÔá­Éñ¦m+ê*½FËp›& ç6?úM c¼<¸ôûÙ6?@ÃpGüî„=[³„ÔWY+²áãwØ Ë’ íÂÚïÔË=ÞÇ ©3ß=I¡ð’ô:ÚUíìêiªy!ð öq¢ÆV5íâóÕGw¬õ _تÞÈ-ÛÂ[õ•ÇnJ\µšo&} $ÝzŠnJ.ßê?#&…3’¢ôûgÔˆøì-Uy÷+‡¾uÔ$„„ˆx¦ôÇ }Ú›).­@8í½ñ œ¬Oå¥p­ñcß4õ×7¿Sÿ4ü¿{o#AºñEóŒâh#U§ †ìš5r\(Îoëß?@oøÁ_o…åâQ}=‡.Ðë:驸§0p#×·í~M#„ã¿GÙ–pWq/! )tÿ…ÝÑ8$‚¢I €ÌGæ&»õ·µ¨o¼]᪟avÈBµâ¾Ò³¿_™ ¸ÕÖãº'íaAãð·nª?ò†¢Ÿ›PAOÃ+MÁÃ;òGôw÷Råp˶ *½ß SF¸4Oyév”óÿ1RלÀÖ ¦E2€¥c³õ/„¾ó¸1>ož> ÛX›{ÿ+’áMkih‘zБ›zó lðNOÝšbà,î^^‰ocÚqàígnyÈjjù(«gEék$»X°;U’€€ÆcÓ‰Æ S1;Šlo×ì‘ì¢ oÜâê¨óÙTÏ•jl^‘¾w ' »¨û NÒq)„ýñn„ûzÅ3î8oþ p¼ïY³Óqe3;hf '‡¾êo„Ó* ñ'Y‰Îoæ€ñPGC‡_²¼±$x5cågÏfž0mÖ¸vºb#lâaÍËü˜ïäËÂ9ƒ¸Æk×-¼ªi ‰ÛÝ™âr ½›âÜ|0ÙòÓ[ Q³#“ó2èeaž¥£Y¹Ñ ó'ÒájÍzÊEƒ’¶/ëlìñÚÒW0Sˆ¹Ì^ï§@Ô'ZŒ$; 1+@´ ƒàâÁê+Á‹µpuÍ”(\ãD$F)žŸ´½ ÿÝMHâ£Ùv¥0÷DmD,zÆ¿µžúÓ±bÕ•Ž Ê£­„N}6Ð}¶©CEãueóq†»²A¼Ñt·\Ÿ»Ï}÷1*9jïaÉ¡ç—ÊFè¼M ÅÝlPª´75|™M¨e´MàF‹¹€G¼Ù[°UþË6¡³ÍøŠ;Ú‰éÚ‰rÏÀÆRkÄkVþ=ÖéÑÁôÑ/E™ ã&ìq!€äm¥ÉÀåÕ-Â78O6¦!ýgŽ‹–ËW@M‘U'=w;=wÔ¦¯»kO°Ý}v> Wvbûëwz2‹ Zk»éÀ©“üü+Aë¹ÝÚ©)“8@Þöëèê²ÇÉZ2=€Ї”wOÖ¸£°ky° –qk‡EA‹óhp†øÂÈÏÖËë¬nÙBkªÆxTVN(\µ[ªðÜøñâ”êåR ž´5pŒÏ±;Wwð„qR¡¸î˜e§¾È!†_’|ËÒ¸wü×(0ƒRœ\Ò.µêZÁ´Â-ž=†{ð¬09Ž^…øj².ÁSû"³H« ±0èZz_‹ËøßÇù;è‡|mÀyž3Z ÈAL§oìƒóäÑÈÓð}‚Ÿ&éÙ åÙ˜]+eÉyE ¤ç@ß²©]êriêîq]+}°åBŸ¹ šÚ§Û¨7ŽÒ¹R=Èà«3ÍfP†˜®k%jŒ:¬.qqbT[¾Û&øv§0N¯×Ž(fûtâ(Ѭ÷t¨s@¨§[¾j D:rPÏ;w-šW`¼áI“F½¾êy§*ÁQvéw‘¯Ú×9u¤CŶÃ)aŒÍ_šuš°!‰~Oƒú½k’€€ÛYD]r R~1g·üúAû¯Š7r˜´¦Œ³Sï=uabî"“ˆ”øò@Aø7Nb)®¹ssbØ+EÌ‘>ÒƵC¢vNNë Î$„ÕÐÙåuäTCß?j+w5z§‹Y;…ÊÄ¢Î0„ÿ1ôžÔBÇŠT ®‡%òÖà]š(¿*6íöz›íÒeŽYR^P¬‚uîTëlc¼›ÃÜY øÛ‰s†ÿ7} EXöÙ‡}ÞÍ¿œÎ‚«º+ÒwÈ3A8ðb›¤PõdñIJÐìÞ_R tû\Y1‹çÙ¸4’t:HN^Ywé‘ÿ£AJ5Q SYøâÄ×ë=Uÿ}ÉƵ°sÖ¼Éá(¥û*ݱrDº©žÃ"µÅLvŸÇíy¦0¡6›2Ü ßH¯ŸŒŒ½)åcÖI6Vôdt† ›ˆ§ç ÅdØdtîÕàVžx.óG#` ¹ù6º ½Nð›(þ¾ü¼#¤é5Þ3føR)É"£–5ø¨q@1´+tëýÌe²£bæ;/ŠNÌÞ'ì)†1 éÑC—®ª×cÒþrDj;w8¸‰¥fè§>„á9ló6ld“/;C`tÔÊ© ·2ó\ÉÕY¨³ˆÓ¼¯úCÙµKà 3 AµõöˆØ 16éNâa4Uû‘*a•Â)bI,càóÐÛÍ×^Ï<¼|Îd£-ß.~n%@9w)­t"By™üX“ò‡˜@ú?c˜õõÉãsy½ ƒLuý‚ Ýë9U¥‹Pѽq••Ròˆg5á·=åLÎ~œVW¥ Ÿš]"Œ×ãÅøÒ |I5(RµBùµªv¬~,öRÈNÐ-ýaéÊOû7ÖÜêòª¡q7ºÓº8vË÷ZÑbªB[ƒÌóá`âÌa©k5\†hô¢†°N”°õå#ûถ«Êö6 ˜±2¹£ÑŽ:…¶çÁü™ p–P¬Vhr³#>ÓÓ…M-ÃE¹¨¹`ÊŸ!m[·wæ2Ì}í,ʸßËy™¹ªÆAVu7¡ªÆÎ`+z |\“Y–éˆqg 4=–åmÈÜN¹|•8XôéIŠÁø ªì÷[ÍÛ|¯gFOï"™½‰XÈ5tJØž?\P™-~¡ã;9b±‚÷>ú© k’€€¶}6øå3‡ m_<÷‰J¿¹ŽNƒ¬ѸxÞö¯tnÏL|6;mL.ÃDôž¦”5mFÞž@è26MÕ8%г ÇsG#KÓʲÚn#O*Jðoð…ýSÜÙVOÃ;/%¹~:¤3~ÎÚB7M4ÆTAžé.òíN;—Iɉ>a® ú?ñÔ$êûG¤*O’äðå‹þ”4y¡ï¦nÅ?£= ÕBQ¨ €ª˜:ÊUsHÀhªé6HÕ¼´•ÆÎGÊÏÍ£as+Ù.ØDsÈeÍ\9ûtvó!ãæ¶!Ls»Su)k¿²ÅzËñ#-{O/0ÓŸÏ&ç3ÂHƒðx`¢äxgU5|GùÙ–¼'‡ û_ª4ÅîÞÙÎ:>jˆµª‰gÄ#H’© Þ©©\¸ÀJîJN‰têg1ÒY$ätsÓ0¥½âªqa¾õƒ;“,#b}÷l¦bžÀÕ $ßD,É…y(ÃmO§Ö둼E™£æB,L 4•F/ÙµËWúHòC$ùç~‰ÿp8ÚÔæ fƪçÝH@Ó³0•#<¾i]Ÿ‡îüx”B¢EËæaïôKÐrÂRkÕëÓD|¬^‹ˆRßÑxémÁì‡M÷=¨á<š@ „àv°u(ýÒÙù'7މ€6Ü{‘‡iƒOãýà ÁòpÀI;P <-šaL|þ*C§!ÚþÍý´­£ùõöŧLm¾‡û¿²Ò20ýž†ÊœÈ.„/ÜÂŒg`¶ä±‡kÍ\5‹xßöY&w·’*% :uïÜ©ŸÓB`Ô¥$ðÊìôIãp‘½¾ D;Ÿy›¨ëý"¹jðØËÀõüS+X*f6Çäxª Í;׋æ‚°ž²×üUpË/G¼×q˜Ð'¤¯?E*¶‰[ —^ùmùSí7#íd媃¼œÕMåÎv3c¯û…7n'1ïÿ)Q2/(ÄoD.Úïæ¡¬cfh»¾ïr²yJ”Æjë«Ã·‹„wmÞ80)¹’Ïöˉ®õEMÉ ’´¾¥#nØÇ¶ÝÆj’€€¢Ã×ÜÍQXCäXW¦œ+^jS‹‰5O:Û>,”Žreôíh,eÖªØíèWâlZ1)²rpB¦ÏÜcôh<†¤ñÿ•,ûç­xŸÓİ€®ÄÝqƒ¡VÊëÅùGµTâYövÀ¨³?@›+¥¦Ø¾.FV¤6§jWmVkg{—em÷YDv‚FžÄdú‘“þ޹‚ç9!6Oõ›¦Óu–{w™×í5á´5¬V@y&†ù·CdÉE6ÇI›9©¿Ñf¦}Š÷üÔÅï$Çj<Õý ’åªs…¾S(õNòo‡¨‡á‘µdä ¸ý¿לÛÒÜøºÒTñXI⪕“ŒUç[>og º–ª"G2L…ŸíÏÖhmðb”Ì!<ø_(YÏÊMF2õ2§²:ÉÊÎ=HsçêaÕn|¦#/±ÂDòjx©xúE峋éÝÄHbM³¶ÝX9éH:…µ ßÉÔyìÉ‘OÕ4ˆc®ýµW‰mF­ÖßÒq% òÆ00öÃÐ:¿™õ ‚÷/½1>Hh0u­¦•´äïú>š+W¯¹V–M5¡ôF<%Р£’É"¼‰â šñSªÏ Òoˆ€¤(Â;¹‹bÈ gÐé˜û0»vßé»”O(šyËéǪˆ\6q{¿Ë¦|¡×uËO6êäÄ5™ûã ÷Úã08÷Rõ¥ L‰‘äBÐGr%­ÉÊ÷%æâ›°ƒºõbµÆHpóÂãï3ò†3Ý$Þ­hL)åW¥a.åÉäö`gZâÐ^¿ßiÙ³iEp«K&Ô©fÊeõ«øU‚ áî•t•Ã1Ò§æ77@ì­R“m!â&N1Lt×%Ú}ZÙ‹†ÉΘñ£rhþóF2%ÕWñHÎw‹™êù¯3 !öt BËLíM>&ŒÒRÂñz®é’h•eê¡(ίeø;òÇ3üˆªý÷–úóE8Ülx.ÏÀM(˜¶2ÎR$}Ëk;u9KC€kÄk•.M%)§¨Oxoiƒu&þxdšë[’€€·-¼UE8„ÍîKOÍšiotuÊW½Z8Myà s½ûí¼6àO›Í™»>‡³š·n8>}_.YBqáÙL[dñ7§G¶o¬f&ngqdo>Üo}ØxÉD­sW|ÝWôÔ•…F›$½„€¡!Ü@dþöér0«—›Â’–¬'þÂ0+í‚Â%8!‘Š+§]Í.fV:¸®ißs’=V(LÀ¹<6°xÕ»õ¦rðz~Ñ­¿ß¿AK£Ï'ª§Ü´üz<*²—n¢Ú¯$áÝ*Ö¨eäV–QBØ+ ŒlE½àýèÖ‚úMmß¹RM&½í?P¸Ü]]E¢Å›hcD‰®Ó¡ª#þoíô“EÏú‘éöKZí²ôØ/}ïŠÃýÞŽÌ™÷%8)ÞCŠ•Šf?áƒ:Dþoo‚ÿ<ø_cJ· *¨·€®Úþfòùz‹r=jv£VsÍ£ ®ÖY¾É (O’íšL¿æàÛ¹ÑR‘UH´e<²—ŽVìÌú7²ÂZ”"üqf¨ö˜ ÄEûa²¥†ˆ›•OÅ5´RíÜ|P £è_KP¤Z‡µ¤dê™X%%±Ä8Þ¡Ci ™P%D;3´‘ÑÀžF•÷µÐ»[º_Ÿº ‚¡9ßîJŸ\BÒñ*¡îÊkšû¹•´MÍ<«G •LttÌ&ʃö ÇÓ"Xûß ëŠoèd2*e”L±‡¸9t{”-Ô'bôˆoÔp®&ÒG| Õ–}áÌË!,ÄÀ2Ág]öè‹å„ Z¿n³Ç`!Œªó+×ÛÕx%ézT¥Ç»*•|Ö ç!Äñ°×¼ãtóóœžÄR{~Ùhj0 !~3J2à&*  L•;êOIÀ ­§¨"mÀ’ƒäšJV"L¸åȾÄR®"ÁÓ`Np|W•}ñ¹†ṳ̀¬—Þ¢Ññg:¯Šú¯MŸ×u c¹VÚq9d±ôZüí™SMÙ)\{Kb–‡ ûòî ˆYx KÃéÇä½£Vôç *¸­7U:ØŽ``¿-KGýcó<~MS÷%Šª]õ‡ÌŸÀ·é·ù–Xöñ|Ó68€ÛZB1tP§ITBeMþ¾Ÿ]ñW‡-o°Ëã"õ&IØi:† ^móÌ{ýgN³ØÍ`’€€ÄÙð«2¸ª&¾úèûÃîPÎáÊÏÚã5Çä,ƒùß4ëÉMõ,`Y÷³î0 «]|¥(Ñ 7×Èï*UõvÚ€€ í²9'ŽA÷ñ ±CèŽUã¶5=o‚–šfʇ‘ßÒŒ ‰ê™˜¾ßMo¦jÿV]Óöµ‹¯ã+ñ.t6«½ §²}7+|•ÛW•¿ý‹–h™½•ÄÝSwÉŒ %Âå­Wf“VŽÌ|K·Kºu á ¯3Åb·ôzó.Òâã]e•ÏÁê¦% ‚—oy%09á³,îœÕ­áb6Eœ•E]”ŒýBèåчMÙß»žJ’YR6¾¥‰[ÒhB1`g‚Öø×}…‘Â5ô°ä§¾Z°/Y²ÃU%¾ÆÒâ=‚“2%°ðqÂJ ”>6_¼—ÐwÍiT¿åJWu’óe[KVÕд` „ßœî›UÙ, m’Ö¡Õ› ÂÃ}g°ÂÃ_KÊÄ)üZ—c*A¿‹ÔÕÔªµîÑþÆ9¨uoHÌV¼oÀÌË%MUa“~÷ï_!VŒk5¼Äß>eýKÐj4f§›è¯ãÙÂi.| €‰1g5åF‘©¼ÀùÂZkrÏSEÔõ+–Ž /:_Lµg{ƹ¸òˆ5á÷\…Ç·­¶„+øš›¥•žå“è‘ߌ[ÌŠ*6ç¯lƒ;¬…ስ潷< )¾4Φ/só}qÖŒ ¬ÞKò~RE¾årÃÔ÷=©²v›Ëg¯«÷ ɪ0üT™³Ee,€ýù&ƒò!£iÇ­øçUã,Á)FÙ˹×n§‡*±H <1à‹¾Å€‹»¬âcM(XÒ;A>s¿Šà¸©"L¨m²M<Û’`ú™ðÀ%…Š ¦¡(P°$(ç3›}ÀþJÛÌc¡ý${Õ»æè,ö j©ŸÀôÂôÉ‘æüwZW·ê°¾Yê^¡ŽD‘l‚|Îo’ÄÀ|`ŠÃ•¾ì?_e›‘ݹ3ƒ>·‰Ê¯w´À›»Øò¸2àŒ¶­ø{ÜÔP;ª€^’$•:æØ¨Î±þøµGB Œ0â»&¢ƒ)¨og"bsg¢¬{–Ôè`¸)Æ`hpÀG…O8èËŽYNFn‹*åT7ù”Û–X{’€€ÀÖªA¿©÷ÀB5¯jb3 %Ù ÁtM!…Dʪ„ñÖ9­Gàÿ¡¯ˆH.µÈžEê ~kN/@Þ+!]Ï'ñŽ·HN¹.“J° ã3“G$”œ}íhÂ`ÅÃvÞXÙõ³[‹6+e TÆ Pñ:aØ/™BN¶­lÊu+A?#Ðrõ[ÕзŽðÚr€åYLÿ5Õã™Lê2\AUÂß°lUkì—={Á¾¬xÕlçaß FÁå5!iRãŒ£Š„Ÿ‰Úõÿ…áX)ß6H #ß’¹IKL(ÊlÕ¬<™0äBãÆAM‘‹ff”tð —ŽL-¾k-ŸqmðèÎЦFÁÝ VÊTQdÞºË\Xñr8Dõ8®EÙQ4Š19íÑtúÔuƒU|KLû\ÚƼ·3TÀµgSÙß·K›Í”Cªn@ÊEùNõuS_‰j'–D-ëõÂŽ™Í<ŒqÃqL÷ŵÒ"À 60J~æú87§'ÑÓ:c²´$„p…ÖK$1ú:‘U>Ôà°p»òD›O2f%èVrBõîö®üf;¸v®ñ Žþ‡B﯉¦Øæ/¯`V~®†§ì²;)Ñ)LŒŒÇ+KÔÓ‰B2Ùim¿2%Dð@[±Þö£…ÐŽ÷‹ Qße…7Ë.4kWøä#‡²²Þ÷Š©ÎQ´Fn‡H rTŒù»÷¶Oôù/Pó¢ÑW_”6·ÚAµUBåÁ¹ nâ‡/¬’Ñá³*P#oŽ›R±W 6`ýÛ,ü*´ŸŸ{õËÇûÛ&*«¤¤*¤šœ¹`£5¤«àÚÑ…•„a&óÜûq¶ýÇ{i/­Þ*£Èô1}ECô³¼jœüyãŸw}µ…µQY.ñ ƒtH5|ü”qcP¿¹Ao&ÖR°ºÿ`“Ì›,Ñýü`3sÖ°™Ü&úÙïŽkÝ3€òÔ#z#j§\ºn#¾2¯¶ÒR4oŸöM®Ï×ÞŒw«ï,&\î02S¿J™Üˆ[±*œ2YÓè{sh²Yáok7þ~å$?î›/#Þ¥½_üÕä M’œ›®úïÁ ŽÝØéÍìÌF‡Ö6{|ÜêkLQ‚<<Ô–ÍË~Ø Ðßþ©áÕøŒäñ‚ÆÛžÍÇñÇÁ‹!97ì©r ’€€É–§Q¥O]Ž™ÉK,ÓO“ˆö¨[5–<Úhçx8|„9÷ Œå#“Á±>Ž<}~àá GJ  W|"+`/FS÷=Üsá…-Úñ«qÜ¢¸{ò=0g—í)ýLCˆÉ„¬w\-»hšÑfüØÔV-é¥è#® ëEvºÝ>˜|«ý(šZÆTØQp${ƒã= ™øfæ l,©OW´JãF±=Uº²ÕGË¿ÄÏjR-ÁÌ”‡ú7c9>/=DDCLI­ŽI¸È¯ú@Åz;ÙìÚ!zŒ…:"à ¥¥ ù5u=nÑ“¡i›¿˜{Q„ÚC{ èÁ»Íh`bÄØ¯ç‘ÆŸbðë çñï'74Þä8kšêѤ,ô $¦_œP7òó#‰ôŒÊ±fßRÇÒQ/ (#|‹Ý‘êÊ­[\·©ÊÑÁË ¬Ðé3½àÌ~JéìÇ¢·™gšÁS9ãÍ£ODù}•¬ÙÕ¸=QÒ8>©+ýü “³Y¬Ýà“hÇî$U6ÐL¢ /îÄÔ™¶º¦{èXÌûå ³j¶Ký‘^vš;ëÝb2€”rÈØëÉM›·©AZQOc/Ô#ßb»ò‰²3‘ìPzãªdõ*:î4¤’ÁÁ, ¬Üú¢Ü«Á;.Yd{æ–­2?žü/±ü†Z¶*,q,VwÚ–\Ô´VÓçÝ_ÁðÍN’0÷üûRÜ„ºý^³]Ãþ ‘P<—ܵ­OOe.îi© oIyfÍ£p4_>!æoWîg¹/¡Í:O¸÷·þçÖ ÚŽ—_“–%Þž+ÿ P ×dkàÙç³nþÙ^¹™ÛñËÖv}ÉF$DFØþ‡ uͨ÷\Š¦ÉœoÜlzÿ„Ñœu= sÁtÃT“œCÿéc°–“Q¸S(ņ®zŠw“Çš†Pñ˜ìJ­<:YwÐÎ/vœ`ß´t ëãVçøq+¼å˜?Ú[œ0Ÿg6hnf–ô+WÆœí­ì)`Xç‹O :ÆrŽ×´-=>æ+Ùm®íçÓ*³âd ®:ƒ~µW ÙtJØ5€ËP˜Ø vü Û›&±¢LIÇjÉS­ÂgsamYжeèxcU¦ ©™qT¡)Ä0†M·Ù8u-/p– í‘õí<àTf·¼’€€Ú)®Fa3É—Zäž:ݫ؉–sv£ék’AðyZ+g›ØÿC%y}²}E‡únlèJPäm ®u8†y—–&œ@¹BÓt÷g p fm¿éF2ø%m8;^K%<ŸÒX<­|–iY"h×ü)U1Ó‚µluðìÇÏ*éŠõALú¶@…¾±gÜsÏ …N.r~2“$˜·C9Z8Á¶;r<÷R+ü®k뛵/g“00N°£ÑgJÄ"æ?¤¼ÐÀïg!4øJZâ¿‹ôû½©ïžË,ÌH¦jC7Ùúñ>1$2#Ð{§´òš PKÖØËw°?ôÒa¸ŒÁ“LúÜN1?d¥°²q÷jœQ¶þÑÓX&@¡Bî|†3…f•]ߺ1ņ)s¬èëÂ8@psü7pËE„£t•T™.ëñûΪ«Ã8‰qq¹’ºÀ˜…Ž¥ÝšGø#€Á³„÷¯HC•÷ôï˜ÀQWìPšPž«­jÇïO6ìójLùq‹€$Ù.Ú«hxL}‡Ý(?„“KyàÈXýmlû ò¬¾‡à¤Â0’Ë/PDŒU:ZVñ)VvºäECÇbÛ?ÒÄbR| ;Óš¤ÕÚ˜kté<<ßá,Zˆhƒo&DNõÀYœˆ°É¾ìÖ-ö8ÊMAvôdå ÆWÐüÍ—4{pL²6¼|Ôfñ¦(`îÛÇØS]_§Û9M·#1NM¼åïW†û`ƒ6Lˆ½wò é5ÊX“bAòp=Í]£6 _fØñÈŠ§7&ëó*RJ{Š)‚•ÀNþ¦T7a;š‚âQýKÇâÓ¡žê{ˆ¹sÄ‚Ät–4ww¡Úö[ë΋ò” _ŽO$møtÆz¶²¬ÂGÈáÑóª©ï(zM äÙ;{2ù‹öé/‚ÝÚ#‚ Þ­¸à~T]l!Á‡Þ·Å¿U? š*Zgë$¡ØYÄ]¯M–ÓvõÔ¡aÕxï]µU Ò×·úeþð¥2›Íý…7·€­VÍUù5ȱø4ê€äy•ûÀXÒ³é †cóÙ10Yb‰;3Ã!]u?Ó²êÔš(¬ª–Ñg‰l›3’ÞȨVÚF§hÊrƒC¸;köÃY¹ÃÇ•} à¨TZLêl˜ zg’€€Á̬"-N¬X.7¶»óHDà2{Ÿï‰‰ñypÁ* ÉDHf(”Ó#ïTh£K¡ñZ囡J a@ð¯)º–Ÿxgußò1¦‰È9ˆÈagöI¸ú$”À2·=J{+Ð(ó*yÐL¾ô“_ äåpÅ SœJWü‹n²åÔ­®ÀB½uj3èÿWûY¨pñä^ÏÑ_‘®ž™G^4èÐÄÄœ´ØÔò|Ajc…ªÇïW ®ØuÿÍ-rG¾ÓÂäÎF§/Ö¸‹x1x¢Çy[Â#™f²~­Ö©y⣠àY’ ŸHn¼nASV9.&]³ÈùÑKïdæÁY[áËü4Ä{«I\m¨WÅûf`ýÏ™ÚÍ‘ßÙÖÕ^™‡®Ûø$*{ —Æ–ãœBÈv&‰Â–z‡.÷‚IU‹’±¬êfP€EIGùÿ'ë<€n¡~–Ÿ_Ïo_„Èc*{Uçés}Tºï~ñ\6׫"Á÷ü ëbAét j¶côYÀ ·¿Pa*.E%x#Ƽš3Ø‹I¢š¾ö>„ø´ KÀ~Gdèg‡äu- ¿‘¢×Ø ¤ò*?"è²æ€Saî©ÏMÈ5³GÈû,·žƒÐ6Æ äW›+êº-'M5‚ͬ•” DJ#/¶íD7XuÎŽUç['\Õ䀺T»Ë ôÖŒüìâÁ83VyÇ'–Ɉd¹&/Iì¶#A"Hì›7« Û)§ž<Èþ€b•Ç#W8YU‚Ý5ñÁþt~õ ð“¯ê¯|’'© üšà>8Y´<'ߥ3*b'öK´f·¬¸ò_ƒs¾<"pòlõѾCM׌ðdŽíس¥“×DæLÝ™µëÒü,'x$®Ý¾mŒTà…=MÒp3€^ˆü%Œ £Ažq²¾]Ôõa7jÂ剹™Û¸~Ó-þì&áºÌbIä&‰r’uÒë1ŸE§|^Ô4[©²÷¿ß{>…·0".‘‰ÁeS=äOwŸÿþ ö·ç îÉÉ—’€€•×ô§$7ݬuÉcòI]Ç¥ÍN¹6[_rinð £ò2„ч2"rqpô-ÐE7¼’òW»§¼P/­©BWÌÀR#]WýÃþP) ù”=Jd#.í†Å{Ù†,ùØÔæè@è…ˆ ’ÆJÊ }Žíª>áL£Mn3_*!Öàòzëúíÿø‡G¢W; L,h_C„Ùi·Ÿ½O>pê¢áw^Az`Ì RC¶»?TîUXw¤¾‘EõTrÌ9Ë¡Ÿ‹_ÐÒŸ|•J×%¾´ç0Z10d$^nÓÊh8LHëÒùaÁ¦œU#°àžóÔS#ˆXá>‘=(ÆæÆåæcÂØšë[{^ +ᣤ ‘$ @¹ì¬u?{›ã»É¯‰e"† LP˜v’ˆ‹™>dËè¢HƒRE5º ÅF–“¡²ðh¥“ò»p"¡‡y‰‚èk¢ñ&yþêuM€PɾØÄË ÛHP4Û䟃ƜEƒÊa×`IÕÑj€1|Û^Ðêµ´¨è'8{‰Ñ^•GÓ²ŸÐ"n-=©ïÇfRñª„pôeO/BLö!Ñ%!ýËÒx¸|Åe"ŠBÚĩϩç'=f‘Kj“KÁ÷¨ƒùÒ/BSz^u¿4 /­ŒÓìPòèàQaèÒ–@àÕjõUÄNcbÛb U,›»F¾þgK²õêМ–:r¨W‡ 3à·ÿM¿˜’Ùˆ‚XcÕ®C|² G^ÖQIؽ f=õøßL3ÌZ±‹‚Ýsù8?˜Õ¿Lê‹9–§‹%ÐtžÓmœ ‡ûªUN¶LÅP礓 FïH|²oŠùpÖÔ£åMÃh¥Àíy#éb Ë ,©}ÜÕ?UÆhb°b¿VÿU¬´lsý³ð^ 8ùMÑ0f˜ùÎdžÿ¼j XWƒŸòÆt0$Òl60°ˆtçtæ]®KHxÍUN?ÒA¶ˆ\ù3’^Þqe‚øû#LüÀðí ÎËÙúòõº!£±-j#³o9äçL$™þS¨Ê¹¯‰sÑþ•–ÝÓêý–ËÄ*èƒqSÚ.*e’Xª°Ü"ã‹ã¾ŠP¼@%úùMBþæZ¯9•P æ -S—‘0_Àß+²8-3ärYm/Ù“‰ ÐRçÁÄ}Îi¨_jnÓ·<©ØQŸÆ »y’€€Á%¹ïJK-L¸ƒ“ ž~yrÕÙ?˜ð¬NÄâÖ2‘rÄ4RºËkZYS*[§|g«[Äáu4n}Z:UÚU=#Ñv¸—û!¥Š‰T¤ÈÖ0~È•|“x8܉ÂñÅÖš§ŸönP•ÙWvy{·J”m§«èfÿâ¿TFŒø=nïg7V†|“Æô—ÓÏw-Èc;ÈwÍ8dîT {§1ên§jL£ÜFÑlŸž, EÃs>»F¯´Ï×÷— c#†{x¨AE^KmŒ+À›¸h‹Í¶HT×ÛÚjîÜH4—–füER8ÄIË™`¹¢>Q®N­ÿe0!D§êû5YÏLþ4ù†ÉXɲWYÁ×X‹Ì¢"Äö¤×ÂöŒ†\Að˜´qu ¡ðt M$ç«×Ætž¬jÌ&cÔrx±Í4ÅeµMž!ÙÉe8Þi=™…láž=›Óô1Æ¿†ý¹Î¯í¬\;’#ò]ëD€>Éö{ÜscŠÐ‘}¤a4舂Ë0dutÇ2JgkAröÞ×êËD:!)Rµ𻣒Ï‚[ËòhBM) ŸÎ•¸f¿±Xªb£°ã˜ºï{¬ÍqJŸÝ±+W'f¨ñíbø™]= ¢1òmöT ¶$6º=]W®ë/~UÿÃbUÎ÷¿ýXÒé»þô†—~é'NPÓ$ì…àî2CË–¥w‚H*½8ÿMÛ«$o›RoZròâD‘¯Ê`"ç]sÊºŽ m fãÜ…åÌDûr>((w6nœÞ}"å¥9z3u‚]ç6ö¿ø2EÑPbuœ!ïÀf,‚̆ÐÇþCÇ”§Áð[˜™.´‡`Uñaq_a5»| =M˜¯pµ|kEÐÒº#!Öwy}É÷ù%K`>\Ûô®<Ú>1¢ËÏ_vP(Qà 7§-L3S׿kS&OÈNÊ!xCg’95GÄê«òD¿É#߯'1i]@\Adúvžˆ—@ÃÆ’c%¹§¦¯¯Â …´¤…X¨c“â§ŒË9~‡æŸ3rÀuÿôŒÇz,ÉG”»‚#ƒOÌÊ“ïÉ’¼õâÆþS‘€o‡(á$ôÝÏÿï½µ¿’© ‡Ã„!¹W<‚°Dôq^±Àb8ÿRVóPß–ùt²Ú®xí‘É»’€€à¼Í¹fÔ1@±0î‘sb•Aˆ)!Ï[ö]’[kŸÙ;Ð 9FxáÕãJÚèEÁ.FîU÷=2Ô/,Ѻ­"eÄá#—Oi©°ÝÚiP=ÏIÌ8Vß#õx[è!'©PµBÆêCDm%¡Y¬~,lê=êr|%û`Îâc}œ 9K*ûª©üüôy=Õ¢×ÿ¦¾`°Î‡º”ú™_oð ÜÜìÊ©£Bæò'òD$ÁÜn˜Ë[µf&±”J&¨ _³*“,gJ7©%žOÒÃè²°ºNZ˜âuâuŠW¤*Iv—êÕ8s“¤ƒS¬ÎÜ s­;æžm“»¿D‚ L Å£óâ VŠe£KµÖ%õv“I6q¨÷‰¡_sçpü¾’ôžˆ"‰X¢#Ü˺g·ÆX8{¿nÏ6ÅäÚ¤¡ÚødŒ¡W2ÄzªhÕß?ôîÏÍJRŒ=Ú¥¸-Ñý7ZR,{G›‰@P꼨©½õ©rõiMìCœóE¥?-î×Ù£;¯û|@ ŒÛÖv¡¢È·•Ž;«HF&±ã2¡0È Â?Y£¾×<îLÝÞò&ñ#ž =fßiî§y\í»Eñ¦í÷+¹·ÐÌ÷*4ô\á×ø³4’ÿEôŒKAÉò«ºù•¥¼þK´u—ÿ4Ã3з_ÿ`u1ü•_Zf$©9Þÿ_®›†Ûí¸œ®@ˆý§{ÔÞeSf­;,Ëô²tÚ(ÿì0öx¹ò†³º,‚Xøsé‡ÂБ~ؤbRÍß² ÖbM+vx;w/&à¨è­ËS€N4C%MÙÓ¢/pþr=!sáI‰®/hebSp…ã8Q•õöORJèúˆÅ©@5ç†&ÔëN…¥+>ºfü@ftNØàFfÞB(p]›ÄœQ·‡8ÒÍZ€æÞßLec]ÓéL›£„Úp4?Gë§‘dŠbzÎcéä6Z'²ÆgÙNÃcyTF4e+_ÜÝ@;Mk: àɾ²Ìú´x:$⌴x‡Ðð? PY}‡¬ÑÃ6ÐD)²L^3Œ›Å‰–Y1JÆ¿MiÄš˜ë‚5ÑsäèM×… þÜtÒT<õd¤§Þk=n“ãéþZãà"vÔÜ“–ìt6løM&"ëÉapêjøÂñ’€€á8ÉQm~㚉\^*Ûé†t€€¾^)"ûî<# ?ÇÐÿƒ†ÐÈé›ÙLZ¾­õE‚5*Zí˜ôÉ–ÉžÅU‹i×\.&Yù»J‘é¿x;˜\bÍ|ƒ±Ñ§÷Hz­2.â?”GR¦”{P•ß=¡eXµ¡5ik¬ßzî ª\„ërÐl½r“BðÂĘ®´Á[„m§‰¡`çm¬MRðìm¿àxbfr?&'_£\ dÞÄ´Ñ‹“% ¿fî¯ÞXï–µ%´ŒU¾ÜüË :F–áó¥ŠùMQÿÖ· ÍègQGÖaä•2Ý9ÆÍ­ÞBXßI úZvDyD¦†VMô Д–8žs5*ÐZFäü«˜¦Ö—ðJGŒ¡~c]jRþ•Qêbx u_¯àŸ6Ñãò÷%Ê,ɸû*ÕŠ#ÛF#JSáפ) ?Tˆ¸F-f¸#› Xæ‡â`y‹”'à}¼»ÛI n¸’¹wÅhqk¾·q¬>Íç‘].;ažŽˆ{u5…`ŃK¤åAð¶ŸuÕUC™jôË*ÁÚ@Â;£Ô(¤“ºê[f]šíou˜úí Ó·€bƒòZFyŽñU¦?aè%Ïk–Ù ™€¢²} £&gôüz[èI%4æCNʲø …ô)¥³þüÑ„ÐïwLˆ€¶â/àZ–˜ ôÊÔ—óºãä4ìágÚ ¬EЬªßAÌò?-‡aŒ?fÃþä`}t÷ÎYé ôâɦÔû´  ä,¡·ø\ð*Õ00ï5à5wà±ß DÓ^1)ƒ4ÿÿò–ëú“Ø5 0)mËÔõ<;Ò)®o„ e ÀåçÃõøÖFÈÄZ ëC‹u2EÝyÌ%d@úcj?åÜ»^#J4­: Ž}e0 ¸mý/M=Ždº´Þ’É´Ò‡›7꤫³ˆø&F¦yu[q¶I%ˆã{†ØÉ€&Aó/«iÊðWëƒëUç²¼G´¦¦l=î‰&¢†u{€':'Wý9T·j*JõòÜùLQ¤Ïsü‚’¸³8Óf#.)§–ž q¿HÏxªù¤ky9µˆ"Àî¨À?ë¾tºU8h‹-Gf– ‰Ü¿W1ikã-²ªÜÓ_O|}úq_H¶–âIÈ ôâqƒ8ê@™ :yÈ×lZ»™¬#}ÐÒçŠÜke³ÂšPaÿƒSôÊ %5öˆÌÝjUŠ6eôžûC4¼]vùñÈ€Ž‚€ã¼öµæ1®†„X$< ø™\µèÃÑ’C «Ï½LÄV@C5”TôVªwÇȦºy"ì2¯ã\⨪ԑpP£#®ŠUt¹á¡ÝÒ}ä}Pÿâx9Ãæè5î×ñOÞ°¾&à\õDžÂ ƒ»eô4†JÌ\`ž­53Þúÿç¸ÇSïïmCÎnû! :M"AÔÒÒfmÃÙRªÛÂÒ4:þã#ezÓç╊ ýt]O€-¹é–K3ÇiP>ïÂsÕD%¡ü\måmù$Í*Ï•-´\!ËP9¶KÍ£ÍÆy4ÇHN¹ƒØú_Í‘?6ºÇ>\ Ú!çÕ|9Ç¡<Y?òh(¹—ÊÀ3 MÛð{çþb$$=þgS×ðFT”È0›%™¨ƒ¦[V§‘Ûšx÷¡ø9Ѓ¿w­ßE:éüÙz‘¹µç[)òäóP9Ch>¥|=ƒûP%õ0Ä2½ë\Ï‹Jk Ÿµvª­ÁF´e2ZUÊÑÄ<• ÿc3›/Ð#¬ì‹þô`-ë,­2±ó§Ã[þùóÎLtU«5 †–4U?7O³¾a¯ÖùË#C ¸RÚ:<–úR渥²âùrßÂ!ЗA=Ò°ó ò툲c?½â|Î’€€Ú€}gy€¸4 7ÅŽç>…~?0‹ßÁT—•Œ;éËš¤”£2%÷Ëô}µ#)PD`ª Mª Ù/%qEÜÒ. Zê¢ë¨ßÝA¹B†0ì ´={4 6[HöáˆØêþcp…Ô$ùk%5 j'p§û·VçÖ‹LƨFA-®7!Ò™úS}š]?¢µÞd’å°È…ŠIÄ[ Ú D/®Ð +Ÿœï«eÉ”Djð1$éfê½å´ò88óÀÖej²&\„´Yú÷·‚Óîxâ‘“!vñk»fRÕ²øñ;¤¯Ç Äã”ÇCÙ“8É«ÝæY="Ù}RûÚŸR¸JÙC>ãjàW$Ę­±»)ݾˆÇØXÄ–;ãÊ"¹+ùW¯¢h§÷”¢ÌèO$+ì¿óSAŒ‰“@♌S ¢LcâŶiS]·fCü-"U8y7Üî¢ g°[V,t7å´#•H°’-¾ÝhÊszÁx˜Á^Ç[H~Ž¡9”Š ¨{Ös͇»Ÿ+ŒŠdÇ×kÿÃ=æW(ª¾h×C^ÆIÅmæCbAÒ'Q¼á‘ŸÌ.»¸òÍ};Y;DðZÙŒåÕC: _²—½wKŒ„•PÜØâ˜S[J+/ OÇ-æAÝxY˜²xð–Ëx%@¤•ŽG­4ì°jšÏÅפ)é—>`Ð!ÑÀÞ8ÊßÙo%©VßÛØíX Õß¶Ýr„6ˆÁå`+€èLí#SùI<¦ä?h×wÙš”ÜÚ£š'="5bÂý†¸nHîù¿íR*{νچr¿Ig”»€tëÜã2¿è‚‡ÞÞÓ˜è¡M¡¥e«¶:}âå”b³0/jÕû‚B¡Z›ït’X^&`Æ—›´ºêRÜ7AˆÑƒíâf¶áTMt…ÆÍï™ßõ+xè*ìPn.ÁÀ¸GÑ;œÉul$Ê{¥|v‰ gx'Ÿ_]ðÞª“>A3OeNO{cÉ À­úÆúúºóPÞJÒØ@~KÁ*‰“žG~áçFráÍ»Çú—«ÌÃͦtÖx«¨¤UCÂLŒÑ/¬Å.õªî­I;ÆsÝ h®äE±¦cQ'ÄÆ‚ù¼¥18[Éz¤9Ž™ÕÇ£ÂË)ÖÖÜrx¸Üçö’€€§ <š*I«ÈÐ\ Ðc®§K?–-zˆ¸¦È_¢†r±ä¤a«ÂQ“OYÅ[SÇ4ptÈ”§Õ&俊SnVË ZÅãɉÇd(}›ÔRïúÝÍßï/ž‡šË¤usÖ¦aÑU/U4‡»BmÖ 1yí4€¯¶TaÔ’GòžK0Ƕ*g;t©°¬mê!€Ï}-z‡éõ‘è †Ïö¦¨˜ÖެšSdXÜ_Å(Ÿ&ÁõÐ4K"wÒH „„nP³gQ ·íRS©°‚v2ÑÆÇ²[×ë@—Z…É©³ Dêú]2©çèÉŸ¹Òmõ+&¾56tÛ›` @u>r¾ ÜU±ÉϯG`]X¶ÿƒ“1òt¨¨öNÃPc$šënjt¶8ºÓïŸbì“ÒI¼4F‡Y."£"‘ŸññÇ|ÔC„=†  þ Â+ù°‰VR1gLÕC ¾ßƒç‰wY“ ÔÿœÁØqSz ¸E‘G·¾R\Œ~|·Þøµ8Ä ¢d\÷jÍ×ZoMÃ8„Žå¦VW ú„þþR‰ÍéŸõ˜«{–jöüÀ+~ÄW¡7ÌøßÔµ`:[—HnCV³æ\˜ç”iïl3†l¡ý-Ü0+ ­.gÉ.< ‹`õO#´àbè²G«¨‚™bNž¶Å/*ô…LU§ âïV ‡¸¿¦M‘~¯IHTæ#Q,(Mÿ+®,÷‘ÐùøOƒé%Mó[æyêû2õLQ¼vŽvª¹Eì-ÜVR`øåb8Üþxë`6Кc><]IÛÍï_¬?×6÷°f¹™ßSù;4¥ c0„[g¤ÅrX«àÆ è3ЧÇ$å;áð†¥aiÕH ¯ÑÛ·3¤eø|lfÁ÷ÛÅlyÕ}Nþf^7 is¾hÿÃGÆ rÀ³ü]×þÁõI"} ÑnauÕ‚/[+ýÔ«*,`o†¢/ =@õ'OÎ9’€€Ät.ò+ª¨õg®'$ùaò7ŠÎϪÐËA¯õ©hgN³Y.£z R3mAÂ'|œhEaÛ–×'w0¼zÈ-e‡Ù’Þüº]¶¼n›Ö˜ç_’Ì™l qâÕäà§äc¿êsĹp&0ôcp³¬ÁSêdïÌ9[`ïã©âФ÷/ÞxÇHE©h ѳÂc©Ç@g”÷л¨@)‰Òeëłɩo‘ݼú-×¾Šy—4bŠðž¯À—½pÉú^¿(ÿUÔýe Ù ª«5L°A×5Ÿ*ÞO²[Önõ¸ãÊåñ+µÂòw §ÆÚ =[{UP]†Ò9$à "Gmá°{Oâ4r÷³Ñ­cõ ¯Ä±.Φ®'…w¾Ýó¹Ú¢Jñ1¦@¹ýBC0»ÝF”Œ|·q$¨Ü»¥ñšœhÃÞy 7_üb—ý·´ƒ³o‚žù­Âñ‡zšÁä(¬C6Lo7îGÎC\Э5ËÚPÔ¶Ü„q¥énø½qûEÃþ1Mè ì K©<£ÄíÆT_þЯˆ-ÛSb ò µ@9¥ÈY“)-]˜Aˆ¹k(úÄò »ö&o³mb´ë{‰ iMåöˆÏááB­·@9å¹û†e=A¾g1lœœ×¥%,HDN©öia‘ª˜%üéÉuSÊ=‡òq¤ dnkF¬RÌ6YGE¥ƒXÜ,Ý…íE°«¥Í£«$­‚¡Å¯ž.§=!óp; ~†äs¤¶1ª´C8Ón¹?bt?4í“3¾=Õ'슠XD§Þ¦?¦åV÷$µØ.v?ŸmÃ0O5ëõî,ÀÚyx û^¶#ȳMFšœ¢àîF'¯µnø·ÖIZé¼:Xjf*¹ÏV`,»oé‚Nª=J©d[!¦LCûÏ8œiÉtqÿ¶Þùè"sâ ÝÇANöY…/ Îϧ)˃ÔÓO¢ƒB2åXf,Xpš[`‘ÊmºÅ0#!BŸØ’"NÌrtRñ•ˆ6´š_:BÛ”F¡Þ+XL“ÑÀºîöÈê¸ë~˜}|j^©7Å[ù¼Ûú x"ÚHCùø²ÓžÊp>©Åɸ„‰ùiH¯ZM™O¦$§›«Û«^i5åV÷ ø‹ª9uÂY¼4:(x½UÐæ»šü§oe±Ãíõx¸\=æjH7½bw+qòAÌeNþ&G‘ï É;³sµÿUðµî¤Ì*±õ‰^CÊiÙø^q+)\x9€+ÎèáÍô»Óºò£bxGvµfÂÂÃΫÀ\ìgXf\×¼ƒ³Ê³`ø¤8e£9é0Ý¢Fb׉a©pD ôË_VIøBö*àÐ@»éPwô}C(VÚ覰XX8'ûó©!m)“A‡@.fþwƒ EIÌ[¡Û¶/ð6/”0D(W÷±¬êÆ~cÏ, iš¥µ~àÄó6V¬ïíÏ»Q¢ÿLœ#Ñ(²‡Fž?v]ÎiAó!ó”À{7¸éy{á—›O{æLÖ ø^ˆÞqy)•Pü©ÕIƒ’Sýt’ÅrÁ̆ÛbC~dê;¬[š*_c‰|Í@u•é¾M²“eÖÛâÀÇ·¶IÛÃvñ¼õ•€åÿµœ3ÇñvÂ!A³š””rfŠYp±.ÇàD-jòöþŒ%RÍuùAØé:“°íßÃp¼%fê«";{°yþñC„«d°?q¥e }½r>jÈúÔFà&túKqs¨ƒ©³¦¨¿c¡¾‰1’€€Â>!ûó0ns¥ëâNþ>“3•SœMmegRÈ‘îÚÿ@Æ ·¨,z¥îÑ*v!¶-¡­p[=³Ó0¬Âw}å3i:Úi‘‚b¥”½ö’Ô2õðûu¹˜›Å<Êì{¬¼E¼K$‚I¿|¤-ߊt”E—‡‚¬u"¸/ee3"à«BÞÆã[Jæ´º´¥¹7 íàñ,Ș…²ÍÏl›‘Rc<“€8åæZ¯ßò–á7À§õ“\Á›¹{V·$\ð`Ö•f\E”ýšüÕ` *«ÅR-¯Z¯ÁSÈ6ºl­üê ØÇÚ¤sš wx+8ŠÅ†Å„$é|‹{1Qf°èÀ™V%c܆ñ(mú%Òlï|Ë…oy9ŸÜÆ´Û1 k ½j€2zÄPô#=p(QIL\Ù‡ã6€_ùG“{Ol| ¶uEŸ³ b/“›!Õ»ÕRÙ¯Ÿš5~ÎSöS÷å˶·7ÔÆr·*¡f¨sÉ :м©sƒ)¸êå˜åäÁð6u¦$¦ä›g°ù“·û ÷ií5e0ÏÕšÖºûA?šÈh¢¯ ½ãÓ8rÜ e¤ùjS6ý’‚mru¹ˆoÜþæùÍ5¬ ŠõÛŽÇk_ÏqÒ ‰¡ü:d—ÑËžd¶ ±E©˜_P“ƒ®£Ë–ЫmYCèLtîX0¯šn•¢I U]ú˜pwó”G]ZpÌ ”à™ŽÀ'ûûy¶'è`'Þ`­;^ ýNŠkÄaçÔxV Êå3™ÜžÐë3è5~„v䙯±RBá=þ°í^~‰(f›¡‰‘¢áûRÎn;hHÌîðØ:É¿´l,w¥fLOòèÖ«¦,ÐÇŸ<†Ð@½z!àÞ:Xƒ†Gl•KÀiù¼ >Kg§×cf–¨Š|ßW]Ûõoâ Ž¦jä ̃¼q¬>£vVêÉž`ä}ÖH¹ò+€ÍÍ^Þý¡W˜M¬™¥Â¯ýÞÊ» %-¼POp­±$¿ Vü‚µêî‚£tÍQçbù¾6ÅI¿D„Ìð©Ó€Bâ/!!1È™¯µ$ú wáW“ŒéáyŒ G’+Áÿo‘Ω·Öúz1ük.øqÜYÛP>V@/ÔlòOØU--‰Ÿ³¬‚OeM­Ž¬â¼U I;ƒTÝÍP®§QÖf·²¨½·ž½dÔÜÁcå'—>ÜÜß9­…ÆÖãk|ÙÄC…µóÝGùN5™¿E»o\Ò±¯ÁUæƒÙqØ=>KtÐ݆°kIãtª|µJX³žÀÒ|EYg´Ê—ª¦4äÚç_^7­Mxkf¦b'°«mЮòRÜqJ{Àš3¹B4ÑØ)Ö›gn€ð†e m~e_*.ÇŽ®åi7üíÁ£Yê ‹·<„žº;ÈÉ~¹H¤¾UÑј‰ºTًϰÞ;0)ÂÂ+1–MT£àd夗£#”ÔT'ÐõAÒ¸U.9·zVdvLV:ç-¾†¨u=NM‚Þîj 'V„.coòè‘ éæ“Séƒ`ÎR,@Ac·Cpfã®´e n,½{WÒBúbæ„*yl?[½TÁ8Ä- çð•iRÄéä½±‘꼆J¶Ç×.a“äUªR˜^ßä!ÉF iãÐLdª§n:Y+Ê%ì`ü×í8°¼¹Ó·»žª$Ö/k]‹äº®îMuËrn¾Ý®Qj—,§‚"wmd©@WzÞf“Mò/¤ˆG¶Qè^BéW3vçŠ9™~ÞÏšFFKŒ¡«\X¡ MZX' Ö y àpí£E+ÃÖž#‘ù(‡Pö<›Å Æ–aÕØÇ<‰±Á›Á„Ú_ñû¯™$ýˆ×#MÍõõZí-ÃM>X¦vŸT0VãvÁ²kÓÍû*OG’×\ít!ÙñG?¾A9ˆiõœ£Œé¼ËMÈDïp/M’€€¸ˆ JhË㣣ôRºWU0ÿVK&OK'vâ%úm‡{¤‡Ý>çO9öîÇÚåQO§§Ns6ÿFh¡*ücq0¬Ý³•³í\VÁ4¢ Â4kM»#±G&—\ŒŸy/> ÇrÀÙ´G›\òà Áº3f͇Â~¥?¼þD¤­ÿì01ØÐ¶Ù!\úQQé…:9Ù•žfÐé%^Èk­°»íÆ]¤¨õwWugt0£´-yHò%3 þÎÛ‘AvLx¼`&ÔYz=}o³îÚIEê5ØôËOä֨dz¤Ô‹HóM°•õÑ?ª‹Þ# †,#G×nl~êæØåv!™¾È‡›ª´h´k7^tFe“ô«­„÷òfÔâ/Ò™¢:éU”b×¢-ƒaÜóKÞ«ÑkÌÅ­ëÌ.;Y¯¨:à¨ÜŠ^‡gFYÐå$€ÐÝ4në‚VÆÃu¾ûè|{9@°Uç‘uXIòåâ–â³erû¾ÜZ+äï#Ú ä@Öò=Ù¼‡Ô9>ñŠDž$ùAPéãÐu¬ãcS×(d™cW$þÿš ﳼΊXêÏ¡¹‰‚ÑnÅUÎ&PÄ%xŸøšªgOçâQóZÃY 2í2c^!|ÝfH|È1åR~sŠŸ ½OÚŒÇ[‚†ÓÉCS¢ÏÑn¬ ˆ!ð0€¤k ¤o4 õ-!–²B°†ï-²¸A¤œ Æ@§e+‰ˆÌeqó…­¯ÿb˜Îjˆ¨/Q¡p¿ßÈwHê°¬¬•RõçzÞ1'jUJBÍCD¸æ¯fˆY±ýÙ¶1ÉÍ*k u²J X†ŒÃÈS`ø¡C|ïöûÄÀ¸¼ÄêCºó¬ÓH{kPíq" Ÿ±3ZS#´©‡Æ'²nÖ‡n·Û Ž@žÃc`ÒA`üÃöΰ°,l7 £æÍ¾»…uýðË Tfì)&COÊœ#Ê´’˵±i–¾‹)¦uÁW¹„ç¦õ¸¸œ?]*B€ ÇJÉÊB>ƒ±µ{RŽëø:>aó–ÑAM5Ùëëa½±\*­^åV¦{SðÑÉc¶ F´á:">XïTªØâÍœµÉ_ðõ'æ90ð'ÞfFk·ô™cËÒ$ÀLJԫFPHq¾Mü¸Á,ÔÜfËLs8ÂØÎuùXñîõa÷²MGpÕ‚ÉTû’€€²èæÞ³[LQaXég?q Ë£—¾òf^¥|¿cAgLO¼AË/¥wý”_ÎD¸)qŒ‚¦ª0_“s„ŠdCãÒvã‚ûgÐ.›}€`}ßÏçaÝb“ñkžJWbqK[×&ÏpÛ|#öÉQú)ªW”»àýägix°2ü.«‚åžv&F¦3E«¬uuv)dywÎ8ÒÙ-ò-࣠™£×›ú•²;ÄTLûಢ/u4ÔÜ­eSDËdš§™1†hR¹ýí9ÜIjc@@].m³y·¨gE´J}’Ñ ìD(·P±6?†ƒô®akyÆh¨Û­¦ö4Žt].~èÂx« ³rTàX§´ÍU,Ó½ùu ¾ºT,#Ô—ˆ¸†þ<}Õ?5w°øW?·9ü­h4¾Ù½R>ă_p ?'µÂÞbKR¤o›ë¢(X5¿±æ{ˆ—™œ™ Ö5’áZÒñ#ñkkó8·¯n,›'gT:5êÕÇ;ÌÒñ–Ç4vD‡=80}ûÞ ŸÀy÷<¸|#IOyGxU/cÏÀfþm]L9Lj¬A ¼Î–›[ÌóÚÉÄ*…ÉäLØMƒhuÐLýö…d”ãä`ãë]¿ÓyÒ:“oÀWœIhn8Ä:Ú²= wȳ°ó+Jk•K†ßÎ?* ìÑ¢ÔÆtÒwø•½1©2 òJëÃvýÊÏÙŽŠH03721Ä£tF3CæXJæéÏH÷ã³Ætº«Ð–<¹{…5ëÜK¢%S€Gt¯É#_,Dé@ ù®µìêO\Å•ÃΨ8·g…åD#"‰†?eŠêGüý¢´™ÛzL¾³»Î{GUQ™šV½UgµÇ»üÓç F9üYÕ¸è„_Üá£äR{3o¡®¯òðC´Vjj‹‰ÝúÁÇÇaÈ9ŒWsâxHΠ£é|½S*?êŸ22rè;w›Å£Â„šoø€%sèÒÑ@úf]2ŒP‡ –nê»Ýωa5j…2óH´¤0ømÐûF£x~,ÀÑ«›Ä1Ø&;¥~3]Ð/¢ ÿ„i¯”?šuänªc’€€§>å¬! !+³efqð‡c³ÁU§‡¡ã–lÅóEb'ûyB¥–¢Nq\,`]R{[X¦–ÀPýt©À“¿fA^8w^’teý-ò.&Û?x1Eÿ8}?pç,$^>øüíw êZw¬Ö<Ðꟴkˆê§ZÖhî ü 0,»}Ò€ˆ`²HƆvþ†o¤ÇñõŸïŠG‹úoøÌxÑtÄÅÑߎ¸~èÚgtæK÷¬›þvDÂèHKÈØäj«¡…9`íßg𝲢GÚµÀ|Ï$ú@ˆ§pðÔP ß Ê"ÆP QðžÄ˜nCdZƒ×MõsÖ­¸ú³«sºCëDè(v ä\ºyAááœ6ÞϦá Ö _ºDÁF•°]—KYšž?ûð¿Åíf¯© ¬ãó‹eÜ íÀ'”</=#I|ZÀÖÍÉz°@ {l’‚Õ$ĸGÛщâ¹â–’К~0_ ŽÄã;1ìâŒ)­É;êôÌãt_XÀ°U—ÑÐsäSÝê¥df¹†Ë2à“fk¸¥,•„Q¤S?J{’â÷?PÉÖ>—bÈ®T;·@’FõW§Iü­7Âl·+ÞXLæW¡Ó50Q³,[}”dX°jðhY ¼)ë›O®©ºéÈùpn׿šeÝÑ=ßÛ=€DW#°ù uô9ÞŒ]¼ÏBVLs03.K‚Y¯‚Ôß a¡ÌºœW¡^^…6úÚ…¦Iæ§ÕNÊÄ¡ª¢ŒéŸ'!B)U›êò‚ “â?hx,r {Ìéx‘(ô¦>c÷^uW}±Ž W€SîõàlZäÒ!Ô¥÷$MÁɰ oæÞöOSët”—ú¶†…ú´¶õ¹qÔÚ)m‡ì»'} ʃŸö ï_wΊn³}#¤ñ¥˜3Ñ~|€ú`ò:%‹ qxñ¡²œXt³eºýÓYŽMe- Šý Äê ‹q¶Dg—N!q"š"7B—™u8É ¬LK©…´ôyôp(è†âÍ„“Žúųйõ=ŒIç®»øAÕ{ÛÊ;O$Ú®…ÒTF§™$ó(Cib'¨O§ úUøÂ$ž°„=˜'ßHÀŸ]Ò£®dߎ›çž¬_®$«¾3ÓÐæÒ‰“4*Y‘ñ™6Áû¢ïãüoAiè81‡0Æ’€€§ˆƒ†‰©þ¾÷–u2sh¥{‰F檴éR*ÀàÌ(ö•¤/¦æ¬9š9M£á•ÜÕ œV£ý,IùÈv ö0–?ŸímX»ê¡{93Æü?Eœég]3¾C½3á ÐÑàn‚|ß³'“ÊS¯ÍS …‘ûªŒ­ù?{ z<Úˆ6Lf‡úsÝxcX¢šqLω+V¤¹{m¢A™O fF’ó sǰ­_Yiél„ÈÁ¾(ñçUÓœ®/K£—ÆWœþ×3ûÅÑŸa(eÍ’?8rŒÂ2Â[yÏœ2¬„™uÏá0XÖ¨Ž/Õõ€öÛ#A`± %h+„×–ëøCÇdDwµ ­8Çý­m¯Ð}Ó„‚ˆ7­ ±9¼ow‘v‰O£p*yp/7úNÍ„ù‰éy´[D»ñÒ »µðrÂ?Fwµ)ÒvèsïÕ¬‘’a[€6®jˆªƒ†k¿ßh5îÀ˜¾¡IfîdßßÔ£)6„<* U?@pÅor€ãlE£²wüE1ꢛfíBáfQÒ{]½j´!~ouϼ=Þë=j´“¨'´ÒÃÙ·ô¼ìUÜEB%ÃÏœ°ªiQ ‡S̽¸:”«[¡¾‡¬kÑKÌ ¢÷Ù$™ÅÏ* è%M¨T‰ñZ™Î©Ñ‚¬˜ DNj.f ƒÖ…Š|н“N·Ò®÷ÀV^öVÉÀCŸûh?“°¹csóA(1µþiA%ïž6vêù×Õb=á\ W bDc ¥‘Å@°o1·c£ÄXx¹1æ?Z^RÊ6…Œ+{4OoÀìÇÂq¡,¡žÜ~œ}dmÍ1Q³ òã;7,ÒùN}ðÁÑ 0QœM¶ Ä9]™å)7^Š·RU½5)×¢p¬Ü>¢‘HDþEÑ# ßä„uR7pó¸Am­ëk†«Å¹«x›÷º2¡‡œ×7Q‡´ƒn¹gܰ‡Äæ+kù¡r¼S†3¨²Iu¿ž”ÚÕm˜Í‹‘q1wšÆêÍTZ„£KïuãÔª¯”?vUW|Sh“L…Ò3ÝLÄæ‰XÌG¨é}®7öÔ¾bïc©…½½ì¶è_Yh¼‹G$zÿ%.¨“ǵ"ò~!Õ`µ™…"&±Ô¯…ÞŒ» ñ3²¯èQIߥù0Ms‰ƒ’€€»‚¨ö»íOh `ç=rÌá-w…ëñꤌi¼é~Yäi` Þ'Tol%°(‚”€“Žî¸4Á"{ôÉÝvþf8Vííà 0.­ÞÚƒ"!ærýwOK?ž.Úë¢›Ú 2¯;%ëšè$Š„®¾U:h¹< šuŽ=œ0”ÛöígOÐ3›™õ ´?ô3“E öØl™6þ@ OÆ — ˜ÆêÒOv.m›éôesˆþH¸+Ub?«UÝd‰v𠘘>úÓxvF:©5«Øç‰ñ=[l[ô.š)O˜ª¨¤°”Ä,Ô;C!önÎvàáu)¿]ÕŒ†)) k5É— 7—¨£ø§Òk±ùÔº‹NìÕxеºlòF‡$RúE¯7y§˜ÓT}ú?4UZyCFÔÕ ÀYn¹µê,ž˜Ñ¿ÄjLw¹½nÙà¡*C><‚&_üÂR²jœÒÔmÓ~»Z(ŠænR.Ú¶õ¿• B¶èŠS3£PUòƃ †Ü&¬¨ßý±µZ2lu“7Ša Ÿ HÒÏè)½ÁtŠ–+©@ C}ûIô¾~âV¡( ÁÔ{ÒQÅ‘«tÝ¡xÁa×¥²ñl÷‚´뼜Hé¡õ«›/;‡žX–—±¦{í%Ë:„L5åãÔ+~b´¼•HæH‡h»¾o‘#¿iá·à¥Å›£'»y„Ä,Ÿš÷¯}'F¿·c3²¿€Ò]JG䢤6¥}Ÿ¦³›xeÑùu„B6ß‹"ÉA.&ÇkЉ&հεw„E8ÿ™²KD@›z®¹&K¯I_BÊ x¡´—k¯O]Ò²:)‹x žÞ K0{‰F—J2sÕ·ò®ÞŸr.ÿlOÑ àùåÒVb;|®“%O¥Pø `þ€Naü쌤éÞõ§ÝÚ¢JÃC¼Ðä«‹ÁžP‰zÏ)¦„î¥(~ÓÍ×­’K¨;®>Swvz¬1‘p}æpÖ A=V…èwüÍ¥qv@àtå‹G.P*G—€…½NVM Ê©M»Ø _~„e&Åä¢A@²MƒËˆu4:AÕ©38Å 8ZOÙÎcýÿÕ]J:? *x&N'Oi¤gÈñ°x˜¡šä3µ©ÐY÷À¹qñ+3 á°ìù¥m@å6h1¸’€€®w¿¦ÀÜœÃ?(­Ïó„ZÏõ¥¬t ³ãù'-W–ž0K9(ûW0?ˆ…€e êÓÖŒŠSAÚâÆ‘²`¤DZ÷ñ(3òÇrñZ¼!brñ&Rw&Ïó—j€\¡ŠWyq¡æ,iLóíÉrü%áGr™ -–¹õhËOrYŽJ¥LçW).þe®ÏÚBÄLJjìÛT` ,ÑÖ–ÍcÄãÃò ¬–2PjãKÎ_2°ï-\f=tÍ6ݪø„ü5Øõަ)ù>íêÿŠ& ¸DÝ<ñµÂÆÌ^–ñkç{÷§¤©„{mŸî³ç¸L*µ =ÿvËßê(„ã¹z†hußÂj¹l~DÒHIS­Ÿ4­ý¢t”+ ¬~qzUR)Â=ð\dýsö ™|ž†{),Û­4l§³š/¹Ù¨OEŽÞi3ífÝ1_HÑRwL18êcè’ÿÀ𒟹ùÂ+4YH+bhµÝW3µ¹A€I3Pž2 núLr+LoPKmn_Q!ŽïEãŽñ ¼Îä>-ÒÁ¿U,ì»Ëc´ðW«®CÏ_ܨ%VaJ1ªR%ÍÀ;Ö_ý3,R½Ì(¦’÷¹|°_Ì­ªÂŽ7]ptHŸ>úĠшSB…pÍÎÿÒXÈŠÖé8xÏZo/Dü¹®«äM;Z*‘…E¦`ç~@Ñüïr¯C‘»ÈÄÌ šÈÁ)•HþJøýÁóoS|;+8¥–Á)Vq²RÌáÓÇc…­ÚûvÁƒtÑ'¶\y¦´QÌ!È)!šˆËušZ{ˆmRü©v=WÛÝýÁBò´#‘ÚŠÿ7ÿ?šøÏèçûTòœ#Þ¬ö“FP„Òüu u£¤}Ù,Œ˜ç„/RvUE°¥nonÊ —>¾- 8g8¯¿zúà’€€Ó½]ýrCÅ5¼‘¬ ­›©4:Ú„ÄïØ:‰fDv(ãòµ\ó°j0"zÖ~b •u‡A>¥P˜Å.W›§(3‚SAD·ø_õ4N<}›)¼AÇ'Iv™Ó±Òèl°’5ݰ%ôÃÀŽé¤¯s^in¬4œ3"Áyu²ûwr&ÏåÚœô2CYk¢25´`áp«·ãª4ž)ÿs×#Rþà‘o|昫Úß·Ö;ŠÏ¬ q$›ÃyuÊîo¦Z˜)»Å‹f"ν‰õÉcr¶hÜ|ˆ¢­òý²þÉ ÅÀéþÃÿYÎRöN ,?µÑµDô _ô™ÔÊÂÕaßY¶Ù›j>.ºJ× ”Їû}u`°ý­7^>L½ÿ;˜ÿh¾±R6*v½‰(CC h Kõ,”¶}R‚ÜŽ…òí|SA«ŸÊ­QM‰6é€ó„5Ê”ý—35<eÆ $ àêGŒUo– * A ª9ÔxSäè\Æ„Rà#:ÿ¯ÄuY_Ÿý)Ÿg%°Ñ­/6{ož N£6]&üÎNµf~”š¬O ‡rKH’ø9µ;ÇЀ1§~UXL%¥ÙDÁòx@o9.< °4ªH%±?YÜû3aùŠ0#ç’azoØ÷ËÈ1ÌÃHdr8¢¤E›Ó>õH,’Ùìæùë–.t½•ºb{Í4îâ[•"ëÐSõì~lj^^¶…xÓ9!ßZ z[ùžÑ±Âd‚RSMbÊMÈ—DÉ@Pª³fS„$1‰€3J¯Õ.7Cq—²Ë]»$~Ä\Š l8iK€É86 (¢kY ]?Îǯ5˜Uå¬6»?ñT Ó•×òÆÌü°š>¶Hâk®(ürÆQ8KÛ}ã1mtîÖB…„j^$˜1ÿŸ¸0§~²£“ú¤&sN÷nbj;½P.ËzÒÔ7œYFƒôNºÒ ƒvYÛ2Ö%Çʫ› òŸûã8MÛjºªUuGüúª©/ÝÙk›OzI&´w¡ gFd­”{‚Ñ|ú«—r»Ø.£…"üÈð\d7òbQ6èÿMqLY'ðH^ò£¡§ÌyÚÎ~¯E@,¢è['H3{`Éí-f IæÄ€±ÓÁþ {Ûпo¸¥âиϸr,¨­ô!>¨’€€Ýðvé7.Õ(Ö,õ¥!äÕcÚWJ1uC5‡ÇDôH]Ö଎QÿP_‹ªfK.j«H`÷q¹xñ~¤ÎV“kZîÝÒ?¢P»òÅ2WãŠ1ò 0ŒÜù³£ ­o¯tÍ{Bˆ+ì°u‰jNã¯N›$@eûËFBˆ@ÑJôåÉÕ\­Ñµºœ¥ìz P:þù_tjÿqæ _Gò\'àaÎýýL@’7SS°È\¹Âq- {÷;M¥VGwK)ç Õ.d’\“¦ NXÛ[ˬ–wzî{ïAÑh_ý¿a­©O±î¹F‰¦c––l= „‡’6!håXHf‡2®æwYË » Ûþ--@Z.éÊ¢0ý …1A`záKxnL~Uî”›ŸIƺ9]»'Ú-š¢c'T› •iHIGq³†Q¯ @«Á{“ó{íËë×Nb’tÐ@;…GñΡ*¼>‹Ýñ7îžêºì1©!‡oãÙâ`ÊË#f°‚s§ÝËtJ=H¼¾¾EºþoÎ+ W澨U.êz’M…Õ G0ý¢»<Š«£èLGËjò0ÿ·Ð(}Ò\ 6ܶPëEÒíÖŒÿr¥UMÿÇ'Æ2paožÿÞp‹¡Ùí¦ªùͼSÛ Ôº_7\…yB@½^;¹éÁ%œ\¶VÿôÝq;ܸ= |-4’”Ø¥ËÇp eúõšþ¹Ç(ð’õž 7Ä LGÐ8ˆ©PV u%ΜB–¤ZNŒª I5å:ëÏ>¶0Wu¥- öí¾«±{;Ÿiðñ[p™$ñÚÀeFûBýº«7Õ©N¤‹‡ç­b¢›Þ]òÒÈ w”n¨>» Îr鱿K l«“˜Ò= ‹ÕX8L[·;¬FFZúMA«´”Ê(ô 1ÍÔ|H t£ˆ~0ÚnEU:jóÃñrWœeJ2–ºŽÏÕA|ÃûeTvÕ(¢™A7íÜL,•j,e½û¦õRà€ëX&(|ãLé˜'ÙùNÝœ ÄÐumˆþå#t›8ˆ3Á¡tâò”†ˆ¼kÖêµ_ܹNž FÊ522e6×}í°%º«r((£½cÆîZ›{ñÆ]ï ©/)íÌPl8h ÄK§ûTmÑÙÜœ€v%¿¤r'-åJ_'#v·ÊÿŠ‹aÔnIxDIF,’€€¯žÃWÃNî¯{Ç{€| •3N® ˜tb­ÏT±U'Tíi¯ÝcY0GA vÈá×H–ÚsR:ë³…CD ´˜9lßy_3i#›ªÌNOxŸ7O#Ú¥ÕZæ¡ #ëdO°/³Œld:UŒ´PªUµ­-NѲH J¯âå·æM†Oí0»Iöáø…ÎÿÖrÇCé¿ $ &ú÷†ŒÚZU¹`Ìr?Ž¥’EMGx….QšÖÉŸ-±Ú…ò® ]µ b j#X²¨\n’Aäh1ï·êâKÖOó!ó~ªñ[–øÑõ[æÞ@­^²etœn‘/ã“‚ãn¿)”'¢¥…¨7ªÍfö×ÿÀ¬ÈÛ`›ìgw†ÝÔLÊ7oc?x0”;[e>»ƒÚZ¾ÔéïÂÞ°šÉ ê+p-$m$-À+°]“a¸ð©9ýàß8 ì úUgçîG%Ñüy 8ÜW=ò`=¯°.ñA!¹èj§Æ =g–³ÓQðꟇת(íê$¦;k톀°8 ´š"tþñ„fÎÁ?púͨ‚{XZ1U*+¢è›HÔ"E ´p›º#}¹KÅìXI¯Y­ÅmÇî5»8ï“͉{e™†J¦±¬Nq(]:‡Ú2EäútI¢ÃgËß!Û}boi 9èåæ |ý.…ù‚œü¯ß¿×PüŸ÷púü£ÕÎÂïâÀqH9HôNM®l” pÚQ?Hq·¥^ßkÖ&+æˆe”7›É.e§^Mrù~ן9Ô†åK9‚·Ÿ·&ƒ¶ß&´§‰o‚ý4å¶}­IÉêG 73}Ã1!–æMó·’Õ« çdg±:TUçŸï؂њñzM«œÊSÓé ,TÛäAÝ@ÁͶ»Ô‰ R‹J IsÅ]/`ÊîùÜúQ2M`>ƒCÔ‡H£’€€Á)˜Qªt4C *qübÅTKÞÌ÷*+‰‘¯™ m}_½ýîÈÓ©&k›o݆%ªWð©îž‚Å‘à…¢A´r:i÷n£…óW3ÍÇkPþï!&C^²–Ͻ/ÌöÚ9n¹—”4÷¥$¸4o¿¡<aV+zµdu,ÝiåWOÞ >×+]E«­¬ÑŽ’ÆYe–M6ØŠêìŒWÛ+‚³ø{M ¿mhÌxe¥Ë8uÂ^´~¤8–Ö+ -s@'I'Fœ9«aƒS›ÅѸ‰ðJ­é)o{þjªl–{g"¬\Á(>W£ó®Z½5ç×\,d›²ÑÌÖ•EœMù½ †¼„eö!›'™ õh³6y–6¯漪‡ 6À™¹ÇE)¾ ‰WqT™i«6afóÍC] É!il æS$ˬ\;j6ˆñ¦ ·5 ¼•¸C¤#.%Úÿd6áŠeàQÂÕ·égºh£Ì…à„®«´N.Æ Ì…©‰ÝÚ3Æ#û7®Ä¤S4=€ÈŸ£!¬öã ô-ý,„ß^“ˆ¯+-¼KrÍH~ðÁ5bBÛã!Í…5'HÎD^ùy8¾ò~Þê¨ÿ@ÔŸRE¥ŒY“àp°ƒü—¸ø å|bõƒ‹_Ö7 Ë2ià­Ç¢W„6¶VœŒ­Ô¬Zo/¥ß¶¹Õ¨#®×Äz)s†­.RaÊ9½º*eZYÐûªsÕçT¨ÚGõ¯E Ul ÞÛJÑCä©jö¦ÈO¹îéK“£'oºêp†w(ª6*š1 RHU“ÿ¸U4$g!v=.¸$¹ý§Ì_;N/Y/(¦ÔxÏnn…`®Ï#ùùÚº“H%?Ú\°h¦2㛣zÓ9”N|Þöõ%Ë"Òþ¡k@›üÐz²U)™žTÜ`_`Ɔ¶[®Ñ‡f-ÛÞ¥~½vì~o‚,Ê€ƒôÁÁ1;4Œ†ñš»ÃüÛ$%dåÂåZxÄûÞiQ»H—,žëø!ÿ‹UCÊ-† Êÿ÷z7ÙÅ0‹¾Žƒ;~UÚÀ“{s9`Z&úa¹º¤•ÏÎ(ýÇ 1À¬¿˜O>$îy\[˜ö^­k7óä“«Û<û`%ƒ”¥co¥º`æpKh7•@˜¥w½u/ŸøñüYdaEFågÜ¡¯Ru¯ÜHªJJ¿m §Z¦>]”jíÿ€o¸‘•ŠJ ¯2]À.åFï»[/ä(›n ¡¨€D°c â€vPâ5ZáýÐb»l‘à ùÏ&-™ÊÕ±åû" ·×óãšü'l«›í}ËB=8QÃÆì¾ô¬AR9?:y%Í7˜ëumGσíÚ d­vçÉozåî¾äš Ü®áÇ q`vœá × $Ø`¾0šf~¿{tÉ| ”Ć·]§aÚå‹.NÌ­Òô£(Ý(†ïW\ö Nð“˜ñ2gÝk„kõWòT¦ÄÁŸJë@Þ'±u,°Ae¨iA€Œà•MÞìSúMd{9§ØfP…žÒÆèÍæVœëè(Ûïž‹u/(ÖZ&Ÿ:ªˆk>Æø‘÷fImòÎ|ìy³ÿ·ŒOÏ.HÆ×Dò!eÍ ³G{n=ªïétÆ2ó?ÆðŽeØ‹™ÈU¨»#ÎÅ0úéfD\™ñ¸D¹½@ ì àâ1’þ€/Ä*Œ° ’€€²Hì×Öœ„Û­ØÛÝË%ˆyE”·“€¢P.}ï%¶¶Ù1«C0 þK üãFUÙì@AgA–€Õ+#·R̉’ ;h‡Ñ1xç.²w°¼+‡Ñ—EÍ'\v!½ç‘U9€"$Û¯*Ö%áw¢*Øsª“ä²²«yåS¨ciïo°‡}ëMÇüiX‚eæÛŧ¨`5k¾œ#0Fßw…ˆ8­ ×•#z +uë`kóÿ†c+©›*¡P¼çjîp"&¦<ñ.ý AÜÉW胋­V§Zç9Þµ`„s¸¯¬`µøñ›2J·ü•å® ÇîÓ?ÒbºÖ&¥M,ÂAsïjæ‹m”¥¯!“®CJ_V·"i»¾E³»ÆÜÐv õ[‹‹õ&kª¡êܤ1¯ËWâŸsÝ|pH*œÖ8ûÌV¬ÖÈÛó^ë2V¾û*c¼‚ŒËVã¼í&Údô¨^Ÿ§¾ …Ç^ÑfÎÐýU@ÏÇÙt­ÒâÚú9Çï8ëönÈõöÜÿÀð{ Ý 0Š Ó±w‰NÞ'‘R_%¦ëà›8*;H~»ù¢^™!V=`‡¹{Šji |=0–GkÑ}Øê èxES¨²aÃ`°ï™„ÈÁsc×'õBÌyçªÐ™ôV ž\áà]¯Q¶yºÉ[ÀÛØêQH,ë6pu•-ªà¡•ãý/ ªÜÄF(³Èò©âùê­ñ\#­.,Wƒ›ØßVÜÝ:üT T[Þ 4ÏÔ~j+ô²y¦…T›UûÖMš‰žÄœ š‡Q9±|C‚P^£73 ½Ëkú¢U.¾`ÃIÍÒ*ù2œŸÇ"å* sùúë%0 wúÇ€b÷¿–…ÁMÅ3X2k’YL¾QSÒôTU?¯ O-ÊIäR8ÑüUü  ÎFb‹DUŸ?¨7á»ÀÑÇ~2ì> ^vyì’Ó*‹E@(¡¶íð®Ï`Û¥qÌ¿“L"NÁŸY‡t꨿ÐÜÕqU‰¾xs»W܃ôlhi|ÛÌÕcŠ©Qu"=ö@ ´ÊÆùÃßËv’y¼¨–QñôÙÊ/¥ÒV°ïÃ×7]ö‡ÂÀn¾ºa‚@ýA;¯yG8›©óDõ«P 2¼bº|›ò*L“ÓüŒK·IwŽ’€€Á˜‚Hq>°|œî)J€¡k§Dq‹f9jL,pù2ÜI±PåW2t&ç OŒg“-rŠqèñË®¾Ø×z‚<¯žpägÛÛ;®ä—#bˆr× €óÔ,Ÿ‡” )Þ™)Ó çª0cG‰gëȨE6‡·9‡ãp¢ä/[o“›„ËP¢ÚcóõQ;®jõ11 56Ì–ºË£O$ÊY@†¼RznãË Š&MŸ-ÂÏ`þ öìŠ#S:ŽíâL“üŸCÔŠD†“]NYÃT4ÖQ±¶ú¼Õ¢4ðP üø¿K3hÃ2®pŸr,á$•Šg _+ò¦Hس]B§xW¬qDŒ©¦'!š¬`uQá˰ WìˆËüZŸÖ=Ž™û4ý ¶¸Ù”j„¾ÆGŸ>¼ÓýSÓãS*£Pü!µ_9Rø™Ó~¢Žé=°†¤wŽñà+«jrBî±F›„ìñ'2LÆ5Xq^ôÛ¾£š†ìaw’TÈ s6æaÒr˜ä9 ÀdöÚË!qUÔ ÷à´Ò>Áh ˜ôÞªª×¢°¶ßø3KJ0Œ_ªÌÕ95½ðË-ÂG×ÿÂÅ^£T3ˆÖ¿¦Ò÷¼Ûj‡¨6Þ„¦KBò-‹çZL¢+ÅD™y‚…$7³Œ„/#„“´ò­ Vþ&E®sÂk’ê9¹d¾Þç®qŽÁ¸-òkõìLV*YYm)åkv²æõB†wö´Ÿž 㩼»/ž@_BÞɃëY]M½Š·y•‡»þ4ÁJyûÏ%CNÜ1Ü¡G,ŽáÃDZ¦Uª®š:ÍÓ§±ŒÐ8N@ǻڢyU‘NaÜ&#^3ŸÚ*ƒK:ÈRFŠƒc§÷…·1$•²<ŠBe z< õüÝUÞOÊlS‘®A~åN«I!QDf˜ƒ(èlu¯åÐÏ/Pš›>Š$t  ¬ì.ÉàÊ/>¿ÓÎêäA<ø€ûoøº–)îÚQ ö}\œuÓ4I½MuàW‡ôåÆ0°Y$¢½å¡'9’ƒëÓjÿ³Ç/Ã#G×÷ìÕž“W^“…½0ïÄ„€0:õß&á çx›ªeöè^<,ïǼ‚D4yB’SAiïdÀnêz›V…i«Ýí/P£Ê&ccƒåæóZ8ˆÃòèËáÛM)é QS#Óh{ð±é½­ (Wâï’!Þá¶h 'Oô ´ û`ðBh¦çCøœ"Ù˜ÛÀ5úzóÉb¥ª‘…Be¿MýÖ8^IN4®~e  ÄkÞ˜jÖ/•·‰þ¸õWðþñ=õÈìŒå:ÄqÒ†óÓ(üƒçÝ­‰U¹%T-³vWÕTm‡& ,Èr–ÿqâö_ ä»_·‹XÓž”ô!ÛMͲ‰ Èü˜ @­Òqœ, D…¬3·D~V~'l÷T¤hy´ø ÖŒ=)µ(46…[¸Vž %yûDšJ¾F ¢ÊóLÞµ,,f1ßA{ÐZjÆÑnÚå ¡WVBó”WªÑÏò8ö…Ø­ ã{rﬨVa,F¦•)ÜNý.†H0˜Ê D 5¹£¿Úù—5NOM3ØÛCN2²Ó]mÙ1–oIõ}6»ÓhOƒº{g\&®ŸvF«Ó@ÏöwË‚Þá¹Ï!îË‘•ÌöWÌiç¿v¿9{¹üµË…xhCö8Ìös ÓäCbì-°ƒ“îa»*ÆEVÙ-¾ö.Fç×èð”èf”?-S;ÔF¤VÜËáI.×f"j´ –§½Ç×¢fEÉW3Çzîa4Ô†84Á~°ª+,š~%EHW³öä’€€¬ï]žóÅ%ü=@ðñä;o•ašZ—Ó˜iKÖªþ‘‘Xa‹gI¡u6£È¡Ê#ÉûÚÿ@ÐÙk3Ѐ¹:@½6Ùï•Þ3õ,äñëIC]„«¹Â«µä‰ÿìÁ¹ó>sÆfÕTà⟙ñä-RR_3ÏMK7s‹ƒÐAé~º\Ûo4¤0g d3?³[Ü®‹P±Koæ°Êl\ÔÎ8¡¥ŠMgym1  egxÙ`vsÞVîA••.‰-¥Qvß ÀÝ2¥¯€+?5£Â¡óî8—¹ 6çød¾îËqè„6ÚåN9Ðà?q9Ôûazìˬ“ùæì—½û§Oz»g¾‘Z¼~˜‚C„N0ì"™xæ†Q¨Ð€0 #Hë h<zg¸ /‡©$©V Á²²ŸÙïâ«}]ýžLóÑ©˜uU½”¼=Ä(eñµ„r·!ä%v|(0v䎒Ë­D֟Ϋ½ãáÕÄ^½õž«¹fµ’”m:¬ ­ƒrîQê¢ïgíÛ5Úã¨ÇFj4¬>*rÖªM­ù"’ˆ’Î?;"º^z}šÈº›Ú½ÓMçFL~q½NÛ´Õ’€€»1iÿÿOµž%„ÿngkÆ&Êäl¦¯RbÿHÞM ô<Šò)ën*°N“z‡x}W`!Ɖ³3oµÍ6qJ‡rÐJhA¯‚§…kÆçg¾oö®ßí>wÖ" žYü¢ M“¨&F‰âÌ‚iç`“cÝk²Ímm?¦¥Š±Ò¢&›ùQ4ñy±YeŒºÚ…b}ø9Éó–üÊ|‹Æi¯¿Øç€¬iÉ`!rü¼q.Žƒo Ûmuür—ˆ¸2g¨4E|î2ÕÆë]åZ¶…‰Ë-9ìò òæéÝÀ±JîÌY!Ü0t†"[}(VÆHæˆö#„åÜEЯ6rppªtµ‰joëC@*¼õ0t/úÁü²ûÇ¥9ÐGvûÁþ»ˆ› à2Ðr¼´5¾Ï’Úˆ$„07_‚[¸MÒ3TZÿxš¥Ž«ï±CæH~u‹\bJ5s~i”!Â:¥ Œ©7â@Í !±! ø³"2ÙXAQq5ñÞd h8KÓ-åDc¼ð:¹·ªç UÓÎÎJw0ÿ¼EøpÞ¬ýCàvM u>>©£Å3É<Ý/©[Ü[…UhuêÁ ;ñBº0]ðùµ>ï¬×œèåXW³ü^·ÖéRR«‹ï‹3eB b+ß3Œ·;ü-°‡•€õÎ<Ê’€€Èg©›ô]24’ýÈuþeBͧÕß1¦ ÌGí€ÃY™ËB*ÊñmÆÂVÍé‹À¨4ħaþ5ãO¬¶p‘[«" aZŒQ Ӯȫèà@ìí¬LÃÎ)µÉ1&ľÛDã§h× ?¹¦EF|®sÐu”á¿©¿pôs~5¦M· P¼ ŸHl+¤ îѵ[*þY± ÏeöÔÿð¤þ© § œ÷Ÿ®¨7G0¶çg&9”¶e€kK[Ôì­FÐÀ ¤LÅ=Õ}wÒðV2Pb¯¹OƒRÍБ2ümHһʺ‡ŠZkÂj÷ø*5‘A|(„ÄëO+G2<=ökùä Ô¿çP!áûç\"›„ERª¿šR… ÌzP±?49(yXKÕöN)‘¸–¯Ú²´Î–ûå’ú[«å»¨»Å} òk¾å¤f‚›Œ[Ltú@K:dóµ vH<‹|UÅë’ Ï¾öõÒìE‡yP1kgŠí„±„»þ-Ü®©ÅÀ!Ke¢˜s?RÕt“éæ_¸(;(Yþ}Ïú&ð÷µB„X‹ìQñ A„‡{$}ézùE-_à]ëk`ÖÐEƤ¼Ÿ%ÖÛBΉJ•ÆRê]ïÞ|Þ/z÷÷£^íÔÒI—6mÆ#ŠFÑä”P“õo·íkl‹'¿!{ÐJÄ÷´ ÝH¹]õå5+íi˜?ÅEÂ9æQŽxW'¦ÅÓGU‰¬N’+îŒÐA݃^xaÁ("¡Ï§ìÉÚ¼×cèÐgf 1ÌØ å,¼aÇñj±Z­ ö»¨*?C°8W×ËöàrdûÈñÂ,߃r3eœDPÍ7}¼±­EŠÜŒ&óCi¨zÅfâ ¨wø±žˆÝ¿Ñtíç2 àmÑãiúûøj•éÛ\@J4ÓÜ®„ œ›sæA·ÙO)Ê9w4kzÍÇFØÓøôû½ƒË²+Žé|ú8Ρ9¡­ßãj?Ñ,1§MPÏCv•† ANO·«Ñ’Ý=ˆ¹ªi—åäÕºïY@Æqü7ÍCŒ•0N_K[›ûVÖsÍ b""'ƒ³ÈÛj»-Y;|÷k(è&<ú7@TžR£ùí¦¨)‹Ê¥I ú>0Z³‚+"ÙzÏžbÂ>½Õ’€€¯U§mʆb»åÜE.ê@Ðjb²3.I×­o¢‡U_.É 7Šd»Y,þ¢_y*Å8ŽAÍŽ拫B–XŠ‚‡g|Ø]¶Y@YÓ®n9…¾H¿#uhZ)µ¬Ò²h‚$ª÷}ÜÜîøv€ÿàšм5|åûùÂ¥@Š›[ÅÈ&F0Ý܉±tlùç¹Å;n§¢h¯¾Ɇý\ASvî@ÜyÜ ÖÎî]gÁOÚx5[¼…8%ÀMH‰2m!Ú»»RŒ³GwN¯NŠˆ· ùž6ª©!4Ù2 ^ ùo~qá#†Á†ã|šÍ,] ­Ÿ!m÷îÔéxLçï:ÎÅVϬ¼eâP ̵¡–^¦ú‚Åóœÿ½J$=ó<ƒOê­µ$4ëÏ÷Æÿòkp Ä!RÑÿDoÁ¥CÏf›Þ¡Ê"sV"Öko;Šg¯¤i›@ÖoÙã«­L°ç'&Í9ä!’qÏш­äR/…yÛÛ] !Ö,y|瀞«äX¶—Ûq_[›x»\[Lp­nÊ ·"Þªö;?3DçÐ÷Ôׯ…*º‘­ÿÍØÑ’¦ðÁÀEƒdÄ„\»ˆ"}f§ÞuÖ¤WèON·8ª\°= ¤Žª“_oáWüT=ªW8¹ÜMLgïø0Ln·ûŠ'tÜLl_äbÏCÞ¡´"íü³É@iônÙhçÆÇQHgWWy p5¥£ç7 š?9ìÊçéÕ ìÐÂäåù¹b¡éžåN;ܽJ~Ó0_šüÒ…>žù³Ú˜L°ô{ö@´Ž'‚÷ j{ÇzÞ˾ýßÓIt 3KJ(r¦Âø§! .î¿Z§>²XsÉm¦Y$Çßÿäx_Ó¥»‹±ÐÖôfÑ~C÷Ý^úõe šñcr|¿æÆíØ)°s‡á‹ewŒà0"’­­=-d&0Æ*àY˜68J”Å,=÷œiÌú½<ü¸Ñ7ÛÇÝ´(%Õ¾múµ‡\sR:˾۹÷ö…¶†}w·ëûÿÿ—ÛŽŠ=íþÝ~ ¥˜~ëJÜÖÛ¢åâ݆|l¿¿Â¸È#¡Ê³ KáafI~´"Oeû¥B)Œ#¹—ßÊ–1Ô‚=9º.Ka ßâ¿ÀØÐ æ¸ÑŒÀ¿1¬¤:’€€¸Ÿ::Úú2ò—¯¾î¡yËÈ[pfb¿ªŽÓ;Ûƒ†U¤œ©ÈGzè¡5ÈœN ˜’Cºùµlí&C'u¥§©5%YÑ…ö@tÎÿ\áyÄü©çáøT½EØ{?%”¢H‚3×r__®?ŠÛO #|ø5jùWb·f‡ìƒâˆ@Nâí„ÖØ–YR;jböžW_? ˆ~ˆN~DHéÄD¼‡ÉÞþ"®./ºD÷•=V-| ¿Š™‚‡t×ÊmÜÒ5Î*ùAµ’æž@wNTÛO£QkBÍvS3h®­ŽBã@†ö#xƒ¿Q<¥£ça˜¡^Ýcî·›k~¦·¨/Ä/Õ›( C :M0*zÇÉãŠ=»À´j!¹%åL]ÓÌý–ALIï“&Ñ¢M¦õÂm›³¹þiÝôc1æö¢=â<ïUkqËš'Tõs8yìf/|Dü>Bzᜑ†JÏ9r÷+ÏC‡Áááˆ9LýJæ? bŸ ‚ÛD‹'hAØ,çJª|{·9ÞCÏcNkr\N¤ƒQÉÕŸ!=_P˜w§2œ‰wî?é8ÅÔYIõÑ'²(Q$D©nÁê)ŒÇr–¼`þI:R,§å%Î$·2ƒàçæÛñ¢€+·É®Ñg ™­õ xö­zÒ•yefû,´#EåìŽ_šKî9¡¡n %¸Þñ§è†iÏ’€€ÂÇ…”[zûO½W’ïÍøß5‹ÏEÍì%ÝaÍ ó}úåf,Ò ]b-DèW"ý)ÊÓ¨2ÃHÒsÑ!î C] /Ÿôù 7â1Ï­ß¿D£ap,iƒ¦õ+–½gö ir?uDdõÿÍõ¯0¢Œ^>õØiä$¢†‹ú#Ë¢[Hˆx„ѤõóÉ8œ ÞIz¤3âã¸ìçäú÷ØÍY!"ÀŹÖÅ„awXBvììïc»L ³€ªÙ4±ä“wDÉ¢oþ;k:ǻ،Ð>«°Îâ´óª^IH³x—!Ç0ç6Åñ÷" ™¤P!øà¸Ü QÔ½váÃáŽ;)N+ÄQ(…úOÔó?.m—Nô«°¦ï±uÙR1¤­<™žEEtàAŸÆÜO'eX  nßî¤\q6ÎêFÑM Dwœ†! ÄÕ—²ÑPç5’”¦º¹¼Ê@ðÖÀ’ÖbpdªÓ‹iîÞìí­4ìÈž·Ç8A›ï"©ïµ¨õä,7‚Õ,®”.¤1B1G‘Œ® 4¨Ýê;(1¨ƒÃôíz# mY Ž fþîî’¾ëÌ#8Þ†ÿVCd™Înwµ•xÚvPÞ/âøSòQsÆ]Ô2<†HF‹†I@‚ÇÀC BmùöúðÄ.!;Q, ÷†ú0µkžÛŸ[Aã÷4Ç7•׌³ Ééo«,œBâ•ÅTÍ¡0p¼—_ªÀ¼e«ÙqBæ@8)yÐ(D _X¡s~x›‘»ü¯wµ·ý‘¿'Œ6R(­ŽV×-àÊ/= ;J—8¥É唹¬þ{±݇;VÙÞÕÃxÁ5ô<²8aÁäý€kWU{Ú»¼Á —Ÿ³¶óÌx^cë}b¶Bãb&4}\˜š©Ÿ+j±•XþT( |ƬÃù´ÀœéPŒ#E ;3á´XÆò'Ô³ªTª‘³L¸£¸³Ðí`Sýènªü¾`£`t¿âüÕš }º1±=މz:1ÎnAãOÞ …¨®¨‚îÑ~±5µòá¶’  Òïã‹pQgÒOè{';f Õ52´e„9²ý %Utù”2ÖÞàQnö¾¯WDn¨c£ëé¶íòéÔÚ,òè>F܆;ëÕB¼…ÂÞ!˜X¼zì¾%Á|Êfx,©—µLÛŽ]äÕí’€€°ßZw÷‡ß ¬8.sBšÿ·’ó¦ ÅØv.¿8ôŒ‹n†ËŽÞÉò2^¤•Ãç=Žœ1¤¸J­p¿•_£PŠ;K©ªIkÊB ¥fÅ.Ô1 ‡^3¤IX"OÃPÕ›Ó–ÄʬÇÙ+ËŒ š‚ª5ùŽÈÌÚö_½}ñ©È2ÝO-ãz• 4M%ºªŒ#èÖ—566]Øzð²ü ixÀÇçØÏòÛ„m5[4Åi–E`МªòË7CÁN1ÜQG í­“½4eòõ{ ]ÅÈ%ÉÀû½Û è0! †HNööoúl-ãÈI„aŒŠbgþãÌžÜç<6âZ»øºNÜVøþ ¦¡EÔ¯€ãIV„eC×¼Sûò I¯m(Bþ2õ“zÜ ˆ}3Ü—‰üŒ¶¢=åɺ§Z÷‘«b$–¢9­k…]зªbÓx?ç|M pK‡Øm>&Œó žRŠ`ÊOîî´$ðTïÀé¿cç*Ÿœ´’ýE8öwGŽVÕÏ/Í 2ö’U褟Úwiûn›¨lû;½{T»¨×já!agƒÈo€†úwÐ]Ç“EŒ•aÅON«Þ… bÖ$L ¹ÇËÑ;*ø) OT5O’‹±[j.µß[P‘!ÀÐFºSÍsµƒ âoôÅÔâX¢Ss–;­V½2OZ*!ïìyŒ¹ß¡÷Až©³û•­µ›cŸŒ!;Y“<Ï êȬϾˎêôÅÇSõ8 ¡DgíY›ù`žˆb²,œÃDWÐÄÆWõ¸}@ïΣ¹“‹ç¬ÉS$ûN|§99,„–9_ì3Œ¹¥5XÇÎÆÅ¥q€£c¸åAèNÿ¯-ô¶ eÊ*†²h¯Þ8õÞ}ÿ)·èx£ŒZœ.æÁÕWF0 j¯.*Ǿvô•SBf‚HÐæúò:¾pËŸ¼ŒTasºÀ§Ÿ äð9p*XìÞ)TYï4¨.ɧXƒb¸~ÍrÞ0“‚y|ïÁg–å–ßxùÿú»Éø|(‚Ì,*í¨œòÏ&¦x ôŒ§—šÇ·ÁÄ—æ<m1}%6íðtCG2ô°·ƒ²,¶Á!«=¸oB|^¾"Ží6ð}ž¥nv«,ËÔÍ~mb…$x8¤sØ»QZÐEv£²H›T‚|/ή•`+%g’€€Æ¾u Ÿ„û´A{œoZc_§7c ’Io% t$OÀ _+`”\ûò¨+róR[¥:Lçmz‹M-þ »q|¢Ý"' é'>É4ŇQ©ÆÍç½}4ÀÛŒ”é^\»é:÷wÍ’º' î©kH’ éÏ´VIòƒ”ïe‚û.ì÷&Që칡"mšj¹TÉEi^ËW€¾É.ÆŠ#ÇÄ,xÕ) cš1æ‘”G¬­ùÿð´TíÞÔ/_‰ÆZ€¡ݵ^Œe =±ÎÕò¡ !D@ÈpÄîPõw¹áüP …?ôeпç‘’ɺ|‹ÿU5“üXqNªJbàĦ3/pdÅy“ ¼s2ƒù$¸WY¥Š­â¼¸I^3åDMœ¥…“éA @Îo …9ƒëïp:gÏȒø²tËûÞ•Àü‡#ÚsSΦ _º›ùÃ(å¿QÚµQ¨  ­`±±5À‰¸V‚40± ÿwòä-t+#GšÆ6ø¥-øú-Ï¥ ØywÛR* œYg#ÔâõØ›Y±2&gdY Sý'’V}ÛÉ2%µ5XÃêž½@ý2˜à[”Å;ÍjÀ>Q´R‘ÜŽ$éd¶ÂLr8h&˜™δ’«æ»lY“²rbn/‘™29 VÿWˆ*CjڌǞ['È­Ï©þ¹7ŠSH~TùC×»ì*û¶ï~Xy**ÆA’[ÝÅiéQ,vÚù, õéL˜À (yÿU£-^ªØµÉÚíb'Iš\hÀ7ù]sœíÞÌPÿ©Q×ù÷2Fk½CÉÌ„*o¡½`3ß-êžéÕ…ª©ë×Y^aZÂÝô+ÆþÄoî9ÿŒà©ì˜IìZ‰A/0H*ÄÐß›?s]Õ#ê.‡6 tRÝU2;ÿk$ïÝ>î±¶èo}!¾R•24þ$ÿ‘5Ê’€€µi//.Ô˜äþB°¾Ò$ê­“¥)„“€:»o<xF}n ÐâÛ†X1rÈŠ6-?hç­«±ÿOg¹EHOùëÄ ¤ZEsÒ½q­(V2z%ø’`+qä2¯ÂV49ˆÎ•RÜ‡Ê ®0)} Tx›éjûÞ‚¬°W‹om)î¯*us™£Æ¡){±˜M™G/›ar]OëDôÃÆè!_=Ή5Œهtc:®9ïmKD+~§lçF?…r„¥uáˆÁYi™°Î5‚ÚŸ³g6F„K©T†! ZÁäÝ68ÜÐä2ÀîÙ½Æ`]‚¯ "fŠ).)ôâ¤ïIªh=-Ô²€B·úá­ºŽ4dX£‡b>,gpb3MÑL ®X>FpˆŒVdF-ÉI¹,ì&R–Œ¦jŸ)¾Rëž–u¨jrÿæÔ¸CͶ p5<ÛÓ}ˆ À^ ø* † 4À5£®k!Í=obNTÅ? õ»¦î¸¹_Пfù…]7¿zY`M?`âΫ¦ t#’€€´ÿf*¶:ð'TkuUS÷5) T¯šë°4™ M\º»XØ¡z·YÍ"‰Aœ CûAŒñ@’p”ïó9Gb±Õ Èüó¿\1i1ùw6ñoͼ˜Å4͵¿þ•OT¬)ß§‡t…Á½ÁnßîÔË¢ªä Rp+hFó‚'HêwàilÙìáòI>b_{C|þÑÚ“ˆ¤({øÓæÕ%øúþ79¾[z[•œ.ŠKÖ§J¡ùv½˜t¥ }å‚M›… ÛúçãêdÕw™gÔ!2Ò•ßA‚ hòõ ‰PóáR‰ù7Üu²’¸W´’UÍ›=ëÄô5G#0ç+'H]ä)æ’DâêaŽqBÕ14Q†‡ã.ç1åFâÅÔ¦öÌ*×C|{}BvÝ“wÌ,‰„È·_êË.¶ÖݽÕÖ&V_é HM +V•ÏKá}C®éÚPOaü©>þß0¡<†y›ÓµÖHˆ™Œ7ԛ؆ʞ|²CŠôZ 0—,€).qç~í``´ÒÜ·Žôcþ(Wra«ü(HåþŽV˜~ÕŒGócƒ"q²¸Z¥g%yx±¼ étŽºêh¶(*5‘©ˆzϾC0œ-×B ó pûýÿD^,:ÜqEUR’DKÚ¯v… Üj°ælë'Z½^)éž®÷™÷{¡­°sóÅSNyºñ£h÷ rñ£nÕ—M•pÚA;³eÙÿ Ô¾ÎÞ»¿\xÙÁJç)+¡ƒØã#ÀoUCú"úвš‚"Mü; ïƒGè¨MJ šF‚dyuiež†ˆ¯§1V‡‰Ÿ9}_¨T¤½Ü£ÆV4!½—]z,díSÆg…azÇÿô&gÊö²4Ç>¿Úñ¢Â`Ùn@FrÈŽ/üž”Dñáí%»qW;†+V8ñjÆBÂéÆ?fÈð9«_¹v/lÔU6ÉüËú¶ü£™ŠeCÊ!½ ù.à½wâÂ#¹@˜‚ «ÙÉ霅],cÞçbòÞ+P•˜›0Psvj®kû­57†Â^™IòÆ÷]ªÔ áýdÿ¾ì“zÇð‡wÎ+^xs}%j ,¨IDj¥s¢ÑÀ"6ù’â£ö}g:¿Í4ÿúG–¢þ5HïE ‹üF¢†-«µÈŒ}ñó¹’€€™R•üùES¹´©œñE~±ã¹CFG%Çn—Måzd’:6sh¿vç|½‘Œ†¥¬ePÎ#%<Ñl/iùÿ¸îêŽúôƒ%ŽIæì»õ¢ê*3 [Nflidžõrâç_xH­ð÷_ ÒŸ¼´™6þ‡f¸ ™Ä xÉZÀ×Ù…þá×…§#³º†Qjjâ­sðìDS?°qÙ.Ž€hÃJCDUòð- äøÏ%"~˰¼-ñåM$ Ã_ëd«ÿê¢é ¢Þœ›gdú²Rå\Q}Ú•Ÿ¶UÒï/¾ªíÉ÷¥°lXXñÉd„p_°ö°$ê3,mè⺪™ÅÝ”öCâW"-©d}ù@rí©0J`Ó¦ñ¾p?’]üµW½h469Ãqœt m£f%L+ b}5v‰_è¿Rïˆ'Kcêìx\ÛAö²·n®ÒŒžUݶ L…KÀllƒ¥éxUyJ2ÚF!ká1ÂåS²ða£‘J¶ ¹áŒ=íQ-&úùؤÐë@dL/俬•ò°º›G=Y%ÞÈ; nÑb¯²BŒ±þ¢¶Œ¶„÷ÄÁwôÚpb“á‰ü&Hr.݌ƽ•L?Á2×ÄÔ)ȧ•®w¿ëqîN^ê!‚‡8GQh@xˆœ¬ƒ e~å\|?©ô×+yãiKæœ6B¦A·–_öÚ?…ZϤzC±VñCA)èNzö ¦D̳ޜû…ïNX¸‰V[¹$y:XKÌEð4v†ùi.{gª«oFÂæ?ÀArøUwYœäPÂÜÞU|öF®)×Yøß[µ(Ié¾’€€ºä˜cI‡>4¡a¯$.?èÆ°á¶í5¡8k·9ý;øJ£ãà‹í$A1yC NÉÔ2ªïŸJ€jRvm¢˜D%Š@½ü1õcõ:8Æ¥>ââ<Ž:+î+‰v­TT›GhÞ¹fŒ’ˆ´WÌú‰ÇÁtn9^s†cF°Æ¨*ÎSEÃf®Ï”?¿÷$<Å3SlÚóÝQϪ;áÇíÐ<_ˆ]Y_®–^w}Nb =ig3øïŽJó²ÉÝ‘ÙáÁ:7Ž/ø+©b€=jKvŸLqÁ{sºÕÚ”qÿFΦÀTlCÉÐñ©ºSÈ,—‡\3oßÌüŽM (%†þ:z?¡€•ZGrP¬|fõçæñʪ{ЉKOyWȉ„zâ 3;'î¿L¾Ï3È©¿îd•qßY˜^…Ñ^\¶TõÞâ>±N[õp»ez„Kg5¬WQ*åXß¡ÉIž¹f÷•vŸ‰y‹Œ:dæÅÕÓßQ _†ó­×yR…Ã?ùWꚨr I½a¥Wé=Kswq·îF£fe‰´xšðA¢ó3%GN¢PYÍÜñ£ÑÅ!)1†cÝ­m“ÒYâ!D1„ÍBÉòãÓÎà kõ3bt7V_ÏcD<©ñ3ß]©Z7›7:G×€õ™7—¢v.:´Ó÷åÝÛbʹ@è±D%œr®7Þ<§h õ¶öâ臑zt)¸HvYPp£å’#ÒGÑ8Ü–ÐÅÌ®¹$¨n6ÚΦõðNâRö6ÆSk”³×âþ?DÃwÄ98¤¼h# ÑN²“Ý’úW8lÎ&Ø_NíÁ Ü©ÑDYÂ^Þ©oÒí¥ÚŒÉºDE¤BN•ÞOž·zíb%ûu‘9-AØÿ‰ Î¥»ôºDÌ>x1ýªÇX)n0€íÂ_‹Ýø%¼øÀ ¬å;®ÄvΕ~ß­Ñè½ÿ2«ý]‘v"âž5Ù€r ¬°³»„zšï!_â}¹+;X™€äQÖŠéiy#$Pjºm\™†ƒ:Z›‡ÚPM8äe¨î…9û‚صXœP‚:§è=@ÛåJÝb¦ãb¶ 2k¥Æ½îú¼SÅT)²¼úÞÝO· ÈË>¬¥. ¨`Ã;xY­2…9ë<é±î3<…ÿÜøÚûRìW±‰k])²™wžÏ6•’€€©Œ‰ò†#òt?¶e Y?¬0; º]—†Ì{ù\‰­ ü¿©VŒžà‡Úóv åÂ~÷û1ÐYõޏõóôAY2÷ôw—~ã¨kzX‡9DTtâåX7;±ô6o0GÔ˜jÏ„õÓ¶z ;Xð¯Æ‰J¶[Cæÿɷ䟼Ûtwbh~:ñV2¸Ú |â#ä´!:ì) CÇÁF‹+Òä UºiÝÄQî™–\I“&PìÍIå2Òˆ°¿j<<’—Ó‹V“îÓ£§¡]çÈшš‡XŽ×4 ÷òX\/¢ï‰,YÑÓ‰R{hØ eñ5Ã! #r29YÊ ÃŲÓRËXc¼¨„×&Ô¾Fïù«F&C~ÞÄÐnXfwO [™éÊÀ¯3Þ»? 2phջ襖 Õ¢ ˆ®Zßœñg9‹)qŸhýME¹­wA„jT¿C- £ÞLéÎésHf,ÈU÷ ù&­ å×ñ̘ÊÛ¸GÑDQƒ:3iüAušNÃ3„•U…²Å{KðÜ? Ð95oÓñCMò:V=‘€"à´‡(Ê3¹¤pʇ(}Av$ ¡‡AÛLd® Lõ³]S p!ĉ>ÔûDº­2Ù;âðS~àþޝjöu’«Î ƒ¼›\T[Zƒ46–‰/,w1ïôê=ýжhF@/kÇ}& „¤†JÀ[#<Ûú¦y²ùï£G¯2[­~ßÛZøtåhåŠÏ&4(pÖV%M¼­”þ%¶AB›Œ°‘1¨ûŠÔ¦.gï„°½Éi{0È«ÏgµT&»7ñ'+Š_ Å›k·–Ã7#ÌÏ;Ût+Mö÷_Ïõó©½1uôPa<ìnê Yº‹”wÁ¤¢1Y;q`ŒÅ‘ÌÒ¯Í ¦´A¶êUâ&ºÑ)¶°³ ˜*è¦3o·ŸÁøb¶êÇü¹Œ¥WmºìOÜêtpaMF’E6üˆãIF;G™àuE÷Ú—©†–©À±µ‘îG-³Oéç¶jN䉘ØÂJâ\WÉ"úsaúž[اç ú¢‡BV¸±=3ï!ÞØŒ Õr,ÁÂm¡†ùµûŸ^gz­M˜çn¦4ñVÚÑíláÚVý‘Š^¾%¹Ûôk#}—2ßL*ò’É,£à¨d”šnëruR’€€¢»Ð²$U‹·]ØÐ4!„`@‹V-þ®5MŠHþj]Ð1¸‚Ž®nú«"—«yH@™èçFw'PmB¼Òÿ„gµ=e5  „-›’¦êk½—@=™ìö§ë–ÉÆ /˜›œFݤ"a01 E8ÐÓ:÷v—|ùë¸ÅµTáëg{8–¾m2À„[—ëhúgx_þ@è‚:'Ãߌ”On³\” HÞ™¥ÔV½O;DqˆžzŒY:æu±57órDAgí/1ßö½¦¡F̉N¦†z,rÀ¬\†16è7LëuMÆÅp­.,I¹£9’ñµåǃ±ç3)/$Ìv&®Ì ­zä­M¥ jéÞÊÝa –w°ý;lî9`¤ð0šô  D¶Æáfsþ¿^F¾¸[Ôº('ðÖÒ eî±Éhš€[: ¢ÌrÌPE}YèŠm~.¨@ÙƒUárÊ´$rR ã1¤•ÞûÖèãfɘOo•Ešß׿/=ð§&5Zvëäw[:ÔB×#M*´DÙj¢/áf%G÷“@ÇJ³hž4죈h&¿ØpÑÖû=b®)X 2ƒ°Î:Z®­)úÀ³®oàƒ˜¿òÂ4þÇ&U| ‡|}k¬²_Ñ«åB*dñw{åYÕ-[µ*Jó¯+t+÷ÆÞÙÞÅ—cª†ªð“ÚÓØ9lŸöÎÁªY¶éD†ŽÆ˜qï¨9ÏÓ媓ÿ\µ$Ø_Spp$«eÄ`½9uõf ÝÝ-‚™ª?j™šÿ†Þç}ÄÝQÞp ëwIÛµ*;5eÀ’Eý° a4$“ -ª@9Ãle¸hÆlõé±Õ§jô¢§¦bÿíuûU€_h\e} äY›—e" ™æìN)Áë)ðç5÷6L)§˃ؚœ·l²:ë ÐûG¯¯e.е +ä*>³v ð¤OY›¬‰7á_†3¤Šr`lõB©Œ[¿ƒùÊËÄßÒ8=õ·‡/No@ßïï{»;Úâè6Cqèé™,WPM$Ï&Ô=„‡œ& *ÖÁÙà\e-÷kànÔ0ÄsÑlöwMñaaoã «©ÜHéüÁˆ¨}”SîûøœRß´JãÝ<‹ü_£E¾%ýÁ›UgþHz-è½0®×Y’€€ÅˆoùV…u^š¿î9ò¼AÛ_ö¦¹V88ªz•ø5¼ã Š än…@{•@‚?È‚K~½vò”Ñpï>Z¼ÜelÛ\C÷qáN0¯œSdw*„Ÿc‰¾"gð•÷r”Mì’‡Õ~ÐíÊZ»~ÖT|ª¯¤™$»2Ä™Ê µl1íLò£=(a¼̱_ð’‡Ï{þ"±·Êt5Œ¹H>&¦t’â‚Õˆ=p>ЍIñC€I¥¡Ô›Š*Õæ‘¯Ù“]·qâüœñ¼Ãt¥þ+ugg0<™°”!°Â4Â]ìIê)Ñn¸ì‹šn¢~±Ìô3šî*-Ù-,Å…ô‡huGn½7xR©Ê¥×sqXï×±ˆ±õ³Æq63;¾Jë&ÅY\‘ñn,EY“Ý ØFÉèt3¾±>æ’“nƒhV ì¼ÇCP¤­LOÍŸ6/相n~SêÐDTÿî-×+pÓåx^½Ý¯Vv§ñ ,8Î'Vqã.Õ§ýS¯ª—æ!i(ŸY46Ñß1ŸÆa¢±×óü >S.KŒòœmÅÂ{(k“¸àÊÖR´ÎNÓ´—¢Áð@P€À4Æ‹b, Ñ.ÔæƒÒŒÃYNXØÍ3%T2ÆW¦X_’D»™ŒT¼ìºY,ɾÈÊÁ]цÛSÇ%ôŸlñì¥d¨7‡$Ã0³Ìyý°œ”Ζƒž²æŸA.ï?öš½üJWºE>t%Ŧ"­_©"«‚dŸãßqއKT¾*™C’ünÙ9d='‰ èI$Ž”Ù÷ð—K]@ÎìwüÞ8W¶·ªksœ6¿ƒ@çVW θW*Kr3;,·“¶D¶“ã7ÄäË$2Gú1@ ¢äA·HZÏW9÷`³ôågßPrnA¯DË=ˆVΧ“ên£ÑÏ_\ò¶åy¿ElÒ©·°·þ•Eí5š°?œ 0µwÏÊGwN\ŽAûèû“èñ9'Å•¹p6¿Ž¾@i ™O˜¡Œ—ü•ºÐî.È=ÎbÅK{0efG;…н’bfä7–e3Âø'ÿ©ZIffôYÀ³aÙ ¥,ÒžèMîA (~z0e…Zj„EÈ̃µ¬ˆ¥J¡¬<â×u¼³ë‚yT_šò¹­VÊ.túqàÅž’€€¾“50¿+90*Wt¼éT ùÊ9kú[ˆ¯´¨.È œ ¼>"kïì&«M³Ý”ïßáݸ be©È °º2¥vðÐ(Zxßñ¶#?M>+ÊW«0Xè|T%­.aCÿwÙMW"î?Gqc¦`kÜRï ôCL¸iWŒ–lzš(¯ :ß ‰Ð Ù[pùD³Îň=ÒØÁ ¾àvѤìGªËd‰”ª¸UŽÅ`^³ÜZ¶"2`ÓÔ h6†ÏÛ =ÏhþÞúu¶ðH´Éßrz-ü‚q ˆC†»Þ¼ËüäÍÈWeO’zwÅú!ÅiÃWßDÚ6G:¾ ‹ï™Ø)ƒŸ|c'r®¦tz„Ô€„NE<Øb•x‚À.š˜õÚ ?8-Íîõš”°og§)påhÇ©½t3Ý}0°CeüÒ~OÊ|wåD .ÑVG'ʨ³Ò× ÆÅ´ í)[z13^ž]$}p W‘Ô†ôhú§‹«}3×É2ù:JhºpmL×Ç]¦±]°ŽKÇ*,k¬ë³´6 ,4i¬x!_ΘèêðDŸHã·Vrfƒp#‰?¡©ì9Òæ¿¬b:®à]:…ŠCW5#à_8ˆ£¸,ú[エr#¬,ŸüæéE—Õz÷ä$Ýä•X9ö™”ݦw¹ý Õ%­ªldhÙÿ»ÜC´çVôtLÙ­W“ð7ÈþÒ.¤ËÝ…„øk{Gr±–9í¤ZŽßÂhiA³˜—?f¬Ð´Ól„LË+<|ŽZÙìó LÖ1ða`^o^˜µe(6ÿö7_¡^EX\ à‹Ï…ÕnÐþ†¤CàhÏ÷¨ûÔåЇÃÚEïC£dz®8µ‡@x|™¤Ï{àêíNTXðò­€Ù5üíŽ5}¶Ö¼R“§¾çÆ`‰`¯ÿù!5– }¯FX4Iœ’ÃétŽ£YÍó Ò\J¢±tøÖjÖêBŒ•»²F@,š+’à§įa`'(2„`2'òafÀ½æ.H§Ç0ka/¢P<©O ÷ï¹h©1œëŸjôôÑôæPàÜ‹\ÒŽbzHÞã÷gBçM½b#Ѿ‡=ý€* À-n¤>åÊëØ£a¶€C#X–Ÿxn³Æt* gV6±´Û6>’€€ÃÇ=^ÓóÙËå%;Ͳs3ò¼°}ªÉeêûæœôJÊkYúØã”`«ôóÓ?öZ„˜½DÒ™9}{ÅüVÕà[îpz’¨¼çØÛ”ÕËvʵÂ×®…Œ¨µe`ä.‡ÃÉaGJŒVšìtãØï¥t¬@ˆ'¥khOݵž%×Òrœ½ÛÈŸ¶mV2ôÊlNžߦ–›¬3’2õ"dgæµ%é†$Þ éFÜ×Þ×+VS‰+g”.±UÛ±@¹@,»`ó ‘ŒšÌ3ï;ÛQÏfõ×"AÄΨ4&ÑÒ¦Xü)ÃY¿ Ú¢ñÔ¶Éî†lùÓkž(݈,ßpfcDÄ4K³xêtpr«ÿÞú3£^ÂÈøïB8]o ÙñÔ⥳Òl·ÇÕjÃ40ºAøçþÖäömìØ¾PINbgMERSD4_pé šIï*qôÆ ,RDÑ$¤E‹ÁãùÒõó‡ÔmŸœóò†Õ í̸˜â¡a–¯f÷ô³SÒ–ê2Õ¥½ìƒ­f~bóÁò;6U‹¢yaÖ£ÑU»_où\Ã÷¶„àÖà‹ýí™»?6¤®Ìú3ÄËâBì «¼–ðñPQË·¢©rÀåÆ÷ã`JÂs†ô‚QF¦pRæ%ËïÆè§Ï…=3Vv»OFà€aYVóƒ”Ð-ÌNiñ‰ìPëÓìóZ€5h$¢,Éüê0: ê¡A7jj;‹Õ×ñ4Æ¥i×í—{SEᲘd¬MuËÇöùºs+ ®ÃÛ‘YRó: F²¬¼1ªv¡¶”½ÐÓ[¥êü(á*iòi‚û±‘ÁVh8Ioß?ªÓ³Aÿ+Wݳ HÊ/Ž~©÷ŠÔc@ 긕|>8øz‘—¯|†ÍÃqÝ¿ø^¸…# d˜(ù´ü³RÜž¡=b$"ìOQ%}Úµt}ØA`‰V¦¼¤Pß,Õ¹flÛ3A%;˜‡ g•9%Ïé¬æî’‹}K05ÛcÄÿe­/¡Mòùv¼×iÚí*œbh`çÁ9j˜¸íßá é}Î{ÜÌ Cg3ÆÕý®ùKi`D‡-ÞI²9ïZáÉÁß ”ýÉ¥Ùݹ[¨u‡æ]ߊZe…µ}ÞÞ[ýÚUæÍµcA$ ›ÞJ×v‰ÄLB'„Ïë ž<7çsêÔ’€€¾9˜q„= K<‰YŠ—¤ vƒ‹ç®Sï"aÿO%à^8¡c{³vÍÁ<üâ¿Ç)Àfšò" Þ뀩^ƒ2ºK5Üšy–=qÚ _1Éòt˜ ø‘dã,7 •ß“óQ'%’ƒû†Il∜ÿ?ý1BÒ,[bÁ²6s;™Öû‚wO>¸‚iÃé"Û¥ÛǢ͘¼_îßÈÊ—Ë5xC–Ü&ÿd¼ú)‡»“?ƒ›‰rƒ ¾ Cë¹Ô0¸qvµK3<ÆK V÷]ƒe|ßßÝ?ÒŸÇ$ FýìçÎö2æä•x%E©u |ºHÚE=§‚˜}SãÏKÞ1Wð`‘熙#Ú~8óæ˜Ú™åKSÚ{ %¡:-pä#7ÙCñßî|ÄÃz¼¯y9P¢4ìÅáõ‘øì”ñÏn"±(†n+éãCÙ•ÅÍàþÿC¤@´o§áu ÷Å&×U5óäPór¦ ¥6ü"½Ÿ×i¼ê |Í-Ÿ~¢cYkv}ëƒ4“h;qQºœ2™í†œ¢öÁ_†šrîêw$2X%×#ʰ޷aíZå ûÚÔpσ©`%žŸˆÅ€W!÷Zî®BB…Ñ®.×ÍŸQ†cà|´SÊAÛÎÔ'?¹3:¯£.ï})´Z½ä®™í 1ô@”ÌurKÏ»¢$j ¾U‚À Eþ¾Ó‹± Ô4*ºVÒ†Inõ„_ÆŽ¯-êïB“MΨ­GðÀ­#Ômé}íQz½X”qݵõ9$ïÀÍк£móå¶Ê¿Ñó$5'扡Œ…À00ãÃ}0±ûIžE”µãOfßÇ`7£¶:%g|ÄôŸ èËíbúƒIµT3pˈ%ÇÅ kåæxQ¶À²:äÕóRž½¾(§¦=i ¶®ˆÙê¦5=œú"‡‰‰KÐÜç­O*6aޱC'“"Çšöî[ÐÔÔóH@0Çoã\>?”ñ~fÎàSúMíß臚8ª.ѱëvÚ›?Ä *½Ü­t^ÄL’ëu3ÙÇ|Ý's}.6©„°½ü›;&@_ZÉyzæáÜ)øžµ—ÉÕ©Ày¼Õ‚h<£lº¢}¿:¦º%§[Øñ,”Æ5wù‹¡ ¤ÛÅã^&×=°:¢aßòÉÏ b5îà’€€Ë4LÛXJÉqipbZYÑ}Šã°ø+”½œä’Z•hã­c2øË r {Éž›wÄÖ_v-¨+R#MQqÔÆ{#ÓNð=BQêZ' Ôa£Ì\|U&‰@äqù–a¬Bku`_Ê«¤R, €tâ×d Y]”wI8"Ôz“G@›ý} ‚GÁ<>"…¡ø6>jxJ”¾ÝûLLºUµ =J,­€oãöß{ºú ¾„ù²9Œ9lw3µé霼OÐÄH¸ªŒgvÛŠ¬*kâýíY¹¹;32¥_°›smG.E„Ãr†ÊðÓÕFe‰ßüd2ÉîýjFëû-vÈzÉ‹@åÓ&µaéCJhIÚeXqw;$4Z´oÄöít&ë1ï^jµ60… Ð;?m¢Ð ¶§£mÜ·ð‰Ö3L lVVÌss,‡fãƒC_,ŸˆKLj}É' áA›‰ú æŽZÚßzÆ-=°È7[)˜?kߺÌì›ø†IoÚ†Õ¾ŽU³Ÿy5AŸ™†.ð)Mªó½ ˜+¬Ý¯ …°]9Ô:ÍÕÅLó0H(Da¡|æ–äøË±7×Ö4ÛÐs”ìýùêWÔ¼$Jq$à਺¤G ¹‰ü®æ¾=›S¶ÔH„†Uç¾–#Uèïü7½ÎõåH5J~àœ“(}ü\wäÜü"††²Nõ#;C`¸ñQþÝÄV®”Ã&Ÿ[Õ&ÒI$—6k¬â¤{Amî)ˆé†sîTã!h±ãFξ|%µ¸‘©¨;c>¤q. n ÁT¤pï_Õ6>Õætðɶ3ê*Cðjì;ãEâáÏJŠ[û'~gÔ9[s|X¥¥ˆS;Õ—ny62õÁ9¶ ÑvY@› 4?Í//Õ»ס¹g"@²üƒ<ÄŠñ‘ª ÚgW)Ée¶“ Äi>V5XñbéV<~#€H'ëÓvúkQ‹ÝRi¿RirCÏ7<&îG?-oVêÐB¨Âç:If7·‘.Ö˜y@Ë×:O’„¤[3±Òâ·ŸÈ]·;> B?ËßXNòŒk¢ðØ|ÈhäŽoÆ< › =¬M™ý…Ýv#™¤MÖoxçjDz}Eƒ¸6¢’]Õ÷o«ñ¾†VbG=îˬè2ãl©éÁQ”!¡’€€ L E¿–¦{|äsfƒ“Ž;½ˆãîvg8y—þOÁÎÈ’v©J¼‡`ÏOƒ,è† ¹áˆ¸ÑŠ&(ßì×øŠÍc‹ÙŒ^¼jwíD ç»…¿!XØ×;çþÒÝh¦+Ü’\N­èÉrÚãÒ¹õ3c_—±g¤pÓw¼|òf7еvAi×áµÌ<Þ†:¾ ¥i’ ä$Žδ*$+"ÓμÔòl± U­ó.Õ>ì¢û-RF‹âb¶ôW1yýƂõší—OÏľi˜tœ­@:sa„ ½r(+¦¦]yÉW_èEß"†oÁZBÞÚŽÞ—¥ZRoñ}{ÍDL:—½µ:úÖð››ÀgÕñ«ªâ¯^ _EàÇ;GÿG«†;.IZ[Q1jJó7Yûšçê#}8C„IµUL1­,çwr%dçÅ¥0’íÒ=áÙ¥Œ(øÊ‹Õþ¨ºWÒÍÒ ‡Ù¡`  +)}úǬ 3^ÏèöÎ"¡OŃ·ìÆb3ûDõ¼dôº}^/¼ðôÈ•*£‰›Ï..ÛÊNµÿk¸µŽK»)‚ ÿ»ê¦Yì¢ ~yFR¹°ñÁæJ/ÜΨ9 Z²¬©Š+CNˆ»“?³–R.,ÒÔ­ÞÎrGe{VÇÊÁ“&/è|ëÍÄ“oï\ á¥øÜ<…p 6RáÞd2Ы–m^9®+ Ú<üg˜÷‚ — ˜ïÌåDð8¥‹Ä‚U¤9iTlŸ*†§??ÜÏÒÅ$+0D¨L©vµè¬5Nï—–)è³x“XÞs[ÂåKpuëì4 $¥á~{ËL<t2Ò‚«ÇmÇìRe|Á/XÛ5cHwLÙLx5[(,tZÐ[³§6 ŒW¼‹¶A\gàe?üBYçjhsÇ'ãôØ¿ÕpS,”¤µ†z7›íROÙrs4ìÜlP«{L›ø”ΙŸ9ã oÉz%vŽ*Š=þ¤hVw‘}Ko§~'’ì»gnªÙáXŽÄdߎ)ªåwgõ‚R13y€ßP Zδ~¸V!(~!V;)É}‚9ü¾,ß$±Ï̲ˆNB®ÿ+rj×ÃR¿®È«¶—5 ³aÔw×׿¼`™_Ðz¨:ÓM­I/0°HÀœ±ï¨’äëtöj ØFQyk’€€´ƒ¤#{Á³¦A—c'ZПŒõ™ëKÆ‹¼^Þ® Ñ7Ahc[ÂÎKc|é ^Ü2$žêûèjfT H=ëlø¸#Ù>JëÛÉ•ÁryºµgžˆGÞ¢­z¡Éa#u‚#/iùsU»‹  a.jšÄdƒ,—Þ§qÐÕÛ£0x1’Ž5Ø}­Âp–+.—öu(Èg7w'íºEÐlC«¹§§DK%F ð:¶N%g'ß#C–ü²ü7Çé™ÄåÒøÀ¬ý‹Q»×̯ì*-ôH¾ëî6Y_'¿¾ÌÔ­lºÆ#G+¼bØ–Äö¿Ý\D¢±€tt:$º„Åâ¸Ûå@ž°Lt–øÆÉ-:g¼æCdÚÁáo >ºìÅR³ßëD‡Ó­Õß§VÌKunQÄRÏ5î a&_ÜÖkÇê 4fŸT½¥G{€ðà¤?ÙWååíãS#4¤Õt¯¯6åØbbBÇNW³²{ ÞÏ€u©zŒü0¶V?gN·í}³‚Qo/À©ìa•DÐ!hJb‘-màÛ#ðRÛ?_¶V¸„ÔôÜ–Ô߻؆jg׬̡‚H“ââç"Ùv*‘;þ,•5¨ª0ðÉ ,ÈÊ- Uý½ÒÉ RƒÁËÖ7ãøGëO8DB0tŒ-ºÞ‰³¸á ¥Ñàx_½PTü®f,7ß^'÷ˆ;;æÐ€Ðùààu¸Áÿ¬qÀœ–l¥­”‘ŒÎy"¨û³ðÛ «E‰{òßœ’úà©ïé—ªõp|{°ÿÇFu_Ñ…‡6©Ï¸Ó¶± ÚßSÇ‘ÑØ®¥]¬Ù”ü¦a"œ¬ 7—ÍÞ¬N¬€“ŸW7öW”'´}"“õ¿9­[É/ô+âüç@tâµ.œxï\´¸p0Q³{? Þ!ì5ƒµŽN846—SFOÎÏDÒK¡F3ÚŸÖN úXûj:GK®ésÿùÖü`"wïÜÆRÉ;Wƒ>Îä#1|Ø.ãrÕ2ZM`íhÏ7yÔºeƒ¤@¼qÁÉ;NFÎU…»ú?eA‰ø;AÚTš ’I(ÈE pÿ_~á+ß.9J½Âg÷8n]Ôí%™ÔLª5ăeŸÆ§#,/uF\nÆ™¡3‰¨D_UˆI:»[T,Ê|ç“ù†J F’€€Î³h®”B KW_i{fêÂËK”r®[$‹P‰îrQÑI(£ë0Ì:³]L?ñw2Ô4v_ôÙ8y®àŒà^ d…_#63¿H¸‡Ì?k -¡“"FØoÛn€«ýØMOØ™‹Œ‡_y¬ø/Ÿ%^åñ˜÷¥ 5’º„çþ¨A‚ÞÌÀÇá0Ð?õ*Å”fBΚIþáÍvg€È[B*?Þ™oA,úöä›À]ŽîÒtr\Òô~™‰ŒUp“g…» ¬eŠO™í®å/0î9-Ej†±¦ ‘¸ðGŠÍ/0>Äó?üU†ÇÛ”_Ê ÏÅ%äå¨ÓT~íƒn9!¯y :SБŽßãÉŒÜÛ…—YÒ aã_Ÿ1BHÍ™zV‚¦ÑëD9T‰å¹çŸ+8ä‹,W—qBQa?Œ}™I Ä4'1}ôº ,œ ®°bt°“Ê'Ö f™LÞ¬e áµ/ëžÔÁà|,š2­6À…$¨Æ3xŽ‚ºƒäñ#i$ðñÙ½;lå]QVnàyÑÞÙëîæPºO·‹ÍNjž­Œ7ç›üŒÔÿ¤mpî9t*ÿÙ%p( ¬‡Jåùƒl›Ø#î–ÆÚè ³]y%ýxøŠÀ=ígÅxµä{ v·lá™ód*¨)ôçÛ€Õ±ñàŸ_¿õ¸§}&2óTuàPœO€u¹ܹJÿãê &ãë÷"SñÔgÌ%0kÜ•H¡€3’Ž •+BÍk¢FY¿ÎjÍŒý­LžÈ ÚpÚwçÐ9óÓ{V»:ôRT)©è–—l¹%Nµ?Ë·\êÞ®ktt™Š6#ä9QákN‚ûŽCæ3KµsøàÀâ€âf^aüÿQѾ9±æaØkÿ¥³.ÆY­°zd슗+_‹JÍJ$PUƧÍ<#ÏN¡ŸÖiÀ—t¦âñVF×¥‘5¬¼/¸Çð†ºû%ˆÎ<…ÑYÜÒ>j@96ç@Eª{ù%´:ÐI³ð¸ÏP±Ã›¶*ï;=Åë¬}¬j üΉÄÜ.}d3nM›T`„ ál‡i¡2·±HùjŠ×»aÂ5ù¾;æ>mò#DƒPÝ•À=&†µ9N³Ê0Æ™æÏ~Øé3Dé¶xg“´ûÖƒµ˜³rœBÆ91’€€ãÀûEñ¦Sö_€4ãA³3Ê oÔTÕâƒLq.gýSld]¢žX5á<ÎÇXõôGA¿Z¶ùåЮ—ïˆ¢Uïv“Ñ>¨R¨É†ø 5ì–yÿ.t÷½¸ýkÛØFPæh_ p]‹.hRó€î£¬ʰYþzÕ™ãÔÕQ*KÿEk–m>X¨®u`ý£ñ/rýxÆlHàæÐÒÕn?ܱ}ãQŽÌÜŠf¨ïf7&ƒØ÷…É‘¨\º\ «Òýn1¬³fÁ Oͳ÷ò2Ò¿fî1V[\¸l“"š$öóÕ6¢.¬ÜH¯EjùSüØ)d¨ LºTÝë×*‰¥w¥©†7ùîÎÅfê¯Ûy~Q–ƒô©«``DÂ˱þ‹e%Ptë”ù$¨§dîò>œW_ÀûQ˜N!úë5v@úÄÊ´æ¹”ëFs¨³ƒ\|9Г߲ü‡‹vBJäFÝå¬%ÏBGÐ⬷¡‹3|ÆïþàÖ1Úÿ¸/Ã(%­¬õ›kS°·¢úUú#\Ô,Óà’C8®çê^^a™âÆñž‘Y¾Æ†ñ1Ž ?ØR9&Ûô(š ,ʆ„šî%æ qñ’¾kдIÕõ××ü4")ׇ\XÕïãâ`•Œ4в«s€( ê)ÀÔùh¾ÖjŠZ™!éMFŸÑ õ"ê†ÆU‹†±>]Ø5Ðß¡,<Þhت‡»Öµ“JüÈPQô§<Œ7e‹/©¡VOsûL®È=§_ñÌSÁ³FÛ²ØÕã9²ÀZûß4mšþ³ž`‘»„ZÅ*¨$=$ šk78,15c½éżÖíCù&i“¨IIHé¢@ZQfÑw ˆÖ¥ Ÿ%Ä>k$äÚ²äjx²ÇÀðÁ™`7:ÏR`uãùŽÆ3ô ÂÍ+¼ÌƒŒ¿ Û5̓j>ÄI“‹Ì"@¹¦­!Ï™[}á{–‰d£¶¹Þv|ž?;¬É²óqRT#ë6}#ý-R€_,²¦ûÖ=R]eƒÖS ’Q¨ïÍ(D¯Ï#&yÍýÎôçî9â[Û1Ñ])¡ 6«K¢'¯/ÙÇH›ÎX;_÷Џïç¯Ì=°éŒåѬj÷V¿ÈÃÔ·ý…àÉ¢²ÉvÿfLcÐDeëÂD}pŸ ðÆ€Cö’€€®_Àfì}Ó¬/`¬35â•®³]öµUûûÑæzÂG‹a·Ìî \7FžD‚§; Nèé³±¸§Œlç]Ÿr ø!=þã1i¡š{_3âÂ_žmO½ÄvsTšÈîƒWzΣ²¤Érlº‚HëGkñÏç ?XOˆA¶MÑ åÁ¶E5µÉ3w¸x?*Póº«\ ÷+@9d¥Óå@_¾«ÒÎàdÉ~Õ c£5ô‡ž\RY?”æî'Ð’çÄbÖןo×»Ô_x²Z]û‚_p´»*?Woßò¸×aê|,ªƒ‚Qjd ýõ$ºvzÃ…"˹±¶µqÎfº¬kû¶}ϸÊÚ*YÀ+Tqã[M DVJÍ8/ãÖÉ\,"C¦µhðU…£ìÿˆ¯ÇŸ ·1{ñI¯à¶ ^Éd+ʬVº¨mS”¸õŽc^§XÃê2‹ SW˜ÑÔ ”ÙòÕÌ3î2S\¥cž½‘³S¡ê"·þßj«Õô‡M œ¦3„VÙÌ9SE4Ñ µ¢-ÓUåƒö'N£”ºèG3ŽeÔÅ®c¼G„ºb~‚†=þµOª¨ÿð–P΀”f©Ã¥aàŽžyËÉ|¿ª ÇÐòŒOü,¤Æ¿ˆ ÷0¸1=>úÿß/ [/æâ‰Ý(nèJ¨òª¥aM4K6ÒPù!ö°çSpª¡úâp|.ux׸bXQgDÚ ‰:Þdú]ƒ2‘¡Ù7D„Íä³0ñn]i¾€€=—€¯Ó‰¿`b7Þ}^lCL‰«£òOÖÉ   í¾J<¿÷:´œ“ü ±+Ö˜AC ÉØwv[ÊXm¥¾bjR;vXßæ7÷Š~Œ¯¼hÌÖ8W{Š,Æ0ç½V[ £†”G¤FAšGNÿ5FŒ±\wÈ ª˜¦‚H¾n˜Ðƒ0©§ Û:Iót-š± F*Y~8lÞÜŸ˜Ø”Ñ®V 2Zñ¢ËË kWÜôdÅ9­Í zºm7ÑäKDhÔ1ò5]+á„6BÒUNç#a)@ Kb{ËSSg â*t³uHÑHk²uÁÊ^ÆáÆH–³R€~D"å.ú Í;°8ãsÌd­šóO‚EتQ—ÅÙ¬ÀA×?/±o;äð‡pÊ–XQ^)·Eµ¹=FÐ’€€¶xôÒ/ Œæ2Gh¹…áÐô&: ÀÚê ”k{%æK™«øHmz ²ø‘d8V-ØÆ¢eY8.ˆÝâ$-h‹+ù}¥5-ÀÖ¥ÒµÍZ¡Ñè©Üýf’£ôr:~¡övÏ2A4r' uªaw¦~øÞnS›¯Uÿ#–âN#vÃ÷ÅÈÊ7Ï©xÆã3.…ꄚ§ gÖ–|¿ÄU†mè¿A’Ÿ˜ílyF®iñÛ;À$2QbÍ€kÉÏdæiñoìñÁ( smN- í(ž‚!;õš6˘Êxb1Fö™r@±ùz[>r2ýÑwìÛìê- ßˈX(fY—Aˆ$A”xùí·±{¯)ÄÄü3œ\†(ðŸÖJ‹qOáÔEÎ8j³5vµ TVz§³’p 3’ƒ9“<ñ ‹ªhF`E ‘%âªäœž ×P † òK‡¾d](eˆUoS»·‡”l µÚ]^J–VÔa_{˜ÃAƒ¸P“1'Ìb‰U(½¨øn–4`¸_ùË ½ B;ÓÙ­’ì„nøÏ6`È«·éØük&§”¼0G8dÛ0·„î+Lo¿'¬¡Ãü{Bªäˆ’K†bÎ:ÞOþNIÙ[Xy5ξjt7…rX ÁºÖ£®‘¹®ß.iŽ?·uâ—ô|8¶8¤x Ã$J]²ìLöãsC’)‡hðûZõø˜`ÙÐϫáS&”"|oâÍÃ3ÚÐ|MN©/ÿ*« Ê)AÑDZédˆ«i˜bÍû:Ÿ¸O˺:Ê®¥p¶—+&hÊÿÕÌ* ú#êàáe›cÜ[ËB숗Åͳd¡Àî!¨GÍ–$?„ê÷ß~¥)ÐMM1ùB»†¨óA~ä;3¯«TÛc4$"ѼªÏËo€œÖveq™Ö '–+ÝT‡)ˆðö<Š"þ]ˆëL‘DÛ{L.=)›˜ëÐðÁV¾ó¸d{;¢ïÏ5xûðk¥«HQ͸ƒ1#uŽ.œíxY¼!ì+A7ŠEÆ^ôÜœýY¯žëèoá8W$®]#ÚS¶gÔÎ*pü‰xDè/1×­ÅkР¡ßˆ8ôø­i;:›’Q¶1Ð}¯=2*IˆÖŽ$v¤“´ æ[ÒÁF¾¡ÑÉ”ÂZ—ÂI‡0“Ô½¬’€€è P+$²J‚oR(<¤¹uKž²øª€Ä»óbõ'ÔÜSÙÕOƒß¡¥YÒÌÇ9À·8 Øõ®–Ù·‚\¥#~8·nþ@eËêy2Ö3¡˜ä á‡Ñ›·u’A¨ Z&.ª÷èb×!/ T1PÐÿìqB8 )Ü.Fú=¿A”!9@„¹µ ""éhc­9b:ÍÔVÎ×ÈÈ—-isÙŒo%>ôL±SPL7å2xß|Î/Ì}Œô\0!nL.ÆÆóŽ}·µß[¤ØÑ¡êp}è㥯,;”9C9Qä+"^ð–  ÕôXÞAI||ÛÆ>M°§RΪÞJ° Ïû*â׈xÖ>”Ž› ±Å{Sï˜YÛHZ‰öèÀ`ƒ{f(´õÎÅ{|ü1ø¤Zœšˆbɘ¨ìø`,ƒ¬÷̹OÈdŽTÙ)X$ÉôŸÜNEŸÄŸêf<ñ¼^Û:PKm’ J 2g·o·Äši`;ˆÑÄgO7°L^Œ’ñ&yúŒƒ}CÀãX옦–%#Û âÛsä!º)À» }âB×>?œácÍ“ªÚµÈßÞœ`8APM#ð`­˜sG(¿.ã7xÈIr7~líæóòç­ûvÿ.Ó $%ß:¥€=ƒ°èí«±]è>¨U^OÝ:Kk¸õþò•ÚÁô1z¥Ô&0¤gM÷p  §ÛQV©Kä*»©Qä³™ohx·uâMœYÚ±,b|К_¡AiˆçI­bcs_Û›æf¸$ª €yM˜Ò­(v¦Áðr£ãµ—ø#…®lP-]§Š#±Êrö¦Žw]fi¨TNî‚ }42¤¬¯;óA\s[¸ÿ/§ÜZx̃.J­— Æ_Ë(ÌÌ ÌÞHS#ë{×0í>ç€5yñðí­±øxvËuÊþmŒb,”bø^§L4K‡|î—MJÍqƒEÁí¶œbÅ£¥u 6¬¬w³;Ö\?SÞ×ú¨~o7u6µ„¢¹íšÕ w›ÖA®®ºÈÃMn>rì¿Ôóttô‘¸@øò‚Ûòc‚@oÊiM”q_ ”ü]>JNäèQg輂TŽšR‰%’ƒD×/L– þÉæ}°Î‰c_ÝsHÚÁ{iwâ>pÙ®9÷ÊKeœÌ:¬ÃN¬R#ó³ˆÅ˜ëó9’€€¾B-ü–ÚD]]Ï¢ÝÁ×Ð-S+ˆà“íœ(Õ–©ýk&4Ÿ¨nÖ-Zü|¾Ø¢ ßÑíGBQó-‡ ·ºXí'mv½»éCVø¶¾Ów¿¾ò©dŒ3Ô|düÌ@(Ö6{Z2áÒÎ4›RЙñ•)t¼q¢rÒOŸŒY-hê¾ ¿H*7¼Ñ ˜>v×6Dª}¤Ó’Ä3;I>´çÔßôo–›eŸXÛ‚,¬7 oìXè[z#Ð2÷~t´uå.ùªÚ`[Á*F[&[©w|i /8Ù´%c 6íš²»z3N¦ý ­NXQ§ø$Ö &§äÝ¢®µ¼—Hë‹&‰yÔãùDи֊f&d†`a±d1„©Î™BW—#/?•Ò áDº³¦²|¡¤ýmƒ‰~’rüAoÃsËß›œdhבeMhô`~‹»= 뀯B®“I‘²ãËŸŸÌ*Kè«8cóJxä^Ü_E.X†9ÒEÖFò™ò5·[H¾lTç‹G\ò£{öò>ð&7÷Þ‡ñæDʪÀa<¦oy,liàwO¦+¦#1ˆFÐ×'@¿‹„E4çoŸ™£q†'3Ÿ|í‰RiTÎ2‚c⹯ëQ?Yo5¥ýãËÚ–ô#·?àÜ9Á:JbFGÄ<]|°àÉ-1œwF+bÙWR5—6mʘ¸f֠픾ƭÅVŸ.tˆ"xÝÞXÉŽMŸQu#›Mvã ®=7ÿù¦U”΢meVOZ±ŒTÐâ?ÖÑ'²ü9£KÆŸD¸u? [èåoœÚæè5#5iź›xëv9ê#+­ªóü{Ï’ÌÌ–ä æž­òT]¦ò¶¿š1¾è· /ÿéÍâÁDjè«ÓŽ•„;€Á”à¶±Ó3|`†¾m] ñÛ)›²Ö“»é„ëØ$—Kn4[èàÓnúåîMR]›bÛ’€€ÏkJûx÷–¬Ÿ8Ø6#¸4[0fÕbÃTÙ«•uXWE­v2éW½ŒÝ†¥#§Oü‡fêDÒ ÎÎWÓEV-IzMR†ß=\ÆÞ|T øn¦X÷V¹paù¾«²d~NurúâIøäÛ­A60ÚjÓU`S&«c^„«Nð„õ:èÓŸ‹UÕž¾–w;š- »Gê°X÷>)0`g_(êo»îZxîHË¢EF%U(>aNUïYìówj(llöC’SÚM¡.nX²) =–‹´Ÿ1ÁAÞ,³e"À M¦”ÇÑœ¬[O½Ü™]Sy§f0Z|\(ø±ó”ÝyÝ~g‘šÍôÚõEɯ[¥CoÑ!WùAòþ¥K:®MÐ>ÏÚB |錷ë@wl:âë›ÂPò¢€£œ*þ÷DÛ2El @Ø9ÂQó‚Ôã@•ø›ùGè‚„»qÂï<-¨‰ÒIþá5lûkIEMY·jëCM~Û&e´äLˉZ`P%1L§“rðtvUŽ^y‡JJCÓge¸Ožñ\©97 =þ"h¼¾Ý-‹Ÿ @ܵ%ï ñô…ÉìÎ?u=ÿÑT p§‹½fXËÜÓ]¥ÃxJí¯)îKÂ]ImYöëÜ]ó§¬ôDhÕÉß4×+‘Þ ™º4>e÷_³Æ"VQ÷êѵÿ4·mžÌÐXbezƒHÛäúN .óæîO¼¬jú²¹ã4Å™axŸF,¤+fõ$’]Õº”ªÝ䇿‹´Z½>Š•µˆ Ê\éX°%Ópç5›^c"{Úé‹z™wù¼ä¹?,¦-øæw»9ŠWÖxîd°|Ý|{Ô, ×2%Oë?ÊÏ.DQ`¸èÿ'r¾D03£MŸô %µ‹D¥¤t’æýŸ×pd8Y;°‘øSß#_Z<(°Hvn[Ÿ}3Ó”Ãí¤…t4ËɘïÎÜdFHüŸŽÉh¦3¢Ò5‘Ý® “wRPŒ‹Å©ªwêk€ž¹Ák Ð,¥@rRµ­Ï‘éÚ-/˜­Ip&,—8PtSæb°‰‡øÜµ-°?ìÑYb… I|™c&¤Úxvî4¿´P^8Ã{Y@,áZžGÉÏb$–ðÐçCqcYáð½þ.¶G¤ pZ¿²s.‘‚Úœ\€‘ÅÖ·“d™” Ë'åÁ>5§ÙßÏÒ®fB'Þ˜ŽÝæÃÆjos{ _*wï´KåFMx†Û¬¥Ç·R«'UH;8f‹úRV3}_‰>¢!ƒv }ïüJD¥©QInçìgb^/)Ù!yñ¶<…Xž1›Ç%,u9ójéAmÌ$´U¤§€ãTñLò#J\oTQgL/Ö7žê&K(Í7òîŠw PT ñèQ)<¯3.âžQÀEþªåóä$ïú)² ” á4<ì„/óè"Çêð˜ãB³$Êfëlã-ˈÌ;Èvî„_‰‚ë¥ÎÐåIº ƒ(<ÙóžÅuLØö]×'Â¥‚™QЕíøÝ,í¿Ï4¶£¦N¹-2¦žØBà“h%nȆÇ\7|q¸`Ï% #ÃÈ»0ÍtdK5Ô‘œ‘‡ F{›«¼Í×±—™$I7LåÚex"‹Óo²ò`pN6Ih“õìv\Yc;êÕégP¡ª{†ÀûIª#Ÿ” !@_bÎÝ'ÓòøµŒ£—@<2î,©T$3er¥+äK"Q["@¸¢µØ}•¢g˜Ûë¸vBe<ÏHXH°Ž©„Ñ/-oÿd©uàPDl‡ÙÈñ2#Ù•Qú­rîJ¸>·Ó¯mŠkÆrŒ®™¤wPÁ iÐë´”ï{5L¥”O>HaRÄ-½(™x«ª 97Úú/àØpï<1ìÕ¾»mÈh⯰³=ÇV;§Vv6^bZ¡Ö§‹LB‰[ð˜)yÀÍÆï`ÿê4 âÐ1](,ï]Uòh@»#ˆ‰)¯å!†·¯ÚI¯^ÑÕó©.‚ W™C“–8ˆ¶ Z ùwù/’€€Çm²{+=°¥ž; »Œ*:cÀHm Q'HDKêhôƒÜ {Ø£ë|_üîD…»÷&9sôÈîçÆJRõædJLºŠkÍWC$KíafÞb÷ÂWðbE9¥¿°C46GÒ‹“÷ð¤EZYÇœm±-à´cyÁ¯ ÝD¦‚gß+•6ÒAo@N¤©ÓÀ‚µeņmŠß‡;B•°å1<‚0¨ý¶Ñ²’Á%68ÁZU3ËÄN\( «'-ŠM¿`RÜNœ :-¶ÕmnddýöàëódC^÷S‰Ÿ0 c½«1,ûU¤Ýà_(ó9˜"[^÷‡Ý‡Zò'ìÅÖ(u ‹m «ôn¹“Ûèš;e›ÀrýJY`a*ËǾž9†–Crȱ»ƒú {~ PôŒT›Œ¢úd:!ú ñžiJé'¼Éض†÷ðJ°'‡Ó[ªÈVÉ{’VÅeÔǰ9î0lpAöŒð§ÜhͳeE‚ Ëø¨ðCü¢¬s!0µ߃hdàèuY^Hhi:rp_?yœšÜkUS|Û²Ú\ó õÁتçA µh§ê3üûs©ÖpÈ"\[ˆÙ–µšU{fm yJìC(zZbœ—ºpf4Ø3õiüH¥fÐ ]sU> þš3ÐÖå2&/0å xt±\ÐÁîÑä¸à2-®å™¶ÁÖJ›àgè~¼Î¸;´ÏR1Ú»uÞsZcŒu-›‹Xw÷Àaó.ìV$¤7|Ë„ê­ÿü]µàØš"}Ïï;X6²<‰{AÀNG~P]µ´6-„Ÿ‘-9å㸔+U!ec”)PW!þ%˜\EàUÕÆ_m£p_›ÂªÄžJwç÷5„-硬ÞÜV£ÆáŠ_HK8Ƴ¢¢/{œOo=­Xæ«#oTó7©Åo®ß†$> ÑÈÝþ]Å·ãjÉYôÈQ÷> ÑT5ÞÉf('Ì_Û'–çœ!,fwf÷åÓsqtzÇ¡)»<ôý«¸=Ô¦ŠUð‚q nhf€‡®ÎÎeCÄ×Fi† ö”Š`ÿËÖ\À]_ûÖt ¼ºš}èêz£äG*Á©ŠÊÅ”†Z´éOÿ»€¯•«P½Œ°#üT×ý¡î×°fs“VPƒïì8èe-µ$v’€€…mœ{­ƒ+|çI£²™-bÈŽ¨h_?ªÀnõÚ&¯\­‘átÐ3v’0W5NFJ»õ*­LV¦z` È#öKT43Ìšpã÷ÿx7eDŠ… 6ñ·Úë¤þš5WQàƒtpû•Øü®0àªC¸¨ ÛŒq/ßG¸M#3pz\!60µ\Zk¬`¢ºW2ç+9ŠToôå’à]Ä×Ȱñq¥C©Œ³`¯Dòй"ê[,õZj£„é†hê©ÇBzc³3\IKò«˜&£ËÜ·À3 ϵÕâ”ØÅ%Õ6tk3Ys%}•g®öÒá™4>oKÒ)g檙և•…p¤–ü$Ф…ë_à; P¸$±r«t$K6³\”N]^'Æ’ñdU“S±Šìâ”xM«í(F(… dˆÌÖô«D§pJå#×ïR¸k„oš]ô£‚ Ê\u»šuH.¡´œæsȼ¡±Å%1œHni\¨Fáý]—M¬u{T™‚«¾’\V‚%ÆããÅAHÌÛnCcdàJ»žr>óƒ^I¼S=OnÔ¸çx ްò$qW'þ+±é”!X]u|÷!“¸8÷+QެºÐÏ01 ìI¡ÌÈÔK"ã©í©¤Uj(zÀ1Ï⟠öÖ®»¶»=w%x̦U6w¢’èÐ _ùZmÎ"WÂkÎXÔÖó @ÛÍÐçâ²à$c*ݪàÞæ^²º%•«éÛÃݛ͛@¨Pç {c•%Œºk& ¯u»ÖgVL”x½®kPLGè:ZX^”kÿ¥òùÏØÛÁú3ý/[±C¦ƒð†QY‚B,Û8½œ7B¥x\ù÷fA .È»~°F3ÁïOJâhcqþþ«´©P‚†çBuœÞty¸±ûÃB™—÷án~\â\¡C!Þ."¬Z„ܪ±O¢Ñ)ìãJ‘ïqZ†ÅµUEN¥ ž–ŽŸ˜/sT<BNŒ›º¶º^©Þ<ÝQí çùÙ3†¶U·:u‰µrµOH1Oqv?“´VêÏ£U¼CIwžNK"E!K©,CÞ &@”—UïÀˆ˜øïV¹#Òwšœ¦Ì{Pûíq•‘­ÚˆKY¡4AÂPæ½Mß‘ô·2 \bm¾­§ô궈Š>2BÜ×ýF‚⃜=£Ý½óSOL¤’€€ÃœÚxÏGÅ£ìzJ)°o¢Y´Vÿ”G¦™†Wd^ùpÇ›ÓKkNxÛŠIœÂüÅPyèêw­W§hoàÔÒR1úeLuL¦RS•iÿL-c6‡»°áúŒ=&$ ýàÈtúAæ‡ì Å…¬m‡&Uvâ¿hÛ«íHÇmûu¦,çé“;œŒ6û¦9ž´-âÉñ`÷ëª1JJÑ °Á·w²"—+C0³‹?Fs.4Žzѧ,‘=‚K6;¡]wüö° ~ ~HeT’¨…̯‰º(a}Ú¤F,hRuŠýn!Ohg2èÒ Ê4jÆ^YPçëU*ˆš;^l$ª}`×òPHk:±R%/°£¼qm³ÓÓ5‘]CQY ÿYx^œÒÿä>/“Õ.ï•JÝ3~ê…ðßÕ,¥6€×=ÍlÝîÜo;mì°žp¤Ò³˜1Ü8šÀouÖÛ{?^ßp.Íuä˜{)ý?é`Šo–’(H®°}>)àX½“Ö¶ÿW’´Û<+ñ3¡°wÌ#œ©Þ³£¡ÿÿï‰î}TÉVv"¼ï=¬Æ«^÷šAÍ‚H^œ^…|M5ÜnÙ®^ߘºÑÿ­XåtS<޵¦Ã ÐøÈTÛž5ðªáÅØ|¾N…Içø‡ªüGŸûš= œÖÙ\zÈÁã<þ3Z4e“ùÈ”ȇ†‰]ð§æaìþ Qß°Ð:ì$và—–òM¶æ'¾}ŠB\7>¿Û™Çò„°¸ùýCGpŸbù ¾Ó9Ì? —Ê^PðrwÌ~"3öb°Â8ÏR9/E_•Šô$Š÷òܱÀ18˜ïaŸ·ÿç}1Ü_úZ)mCûäDC.M Qý!ÙÛØ â[8’ÞDò)hC¹u¬Çß—9iRÚÜÓ¢µ\Å[4²½ƇN$oò‰"ëƒëKéÔ0Ö͆úC¥„æã_)ñTñÓÕ=”‚¾¯÷þݧ{ÿª•`ÒëĦÕéÓØvDøÜ·¥á&ÔùÅuvfá ¿Frc·} }ßÀ5÷r­¢°ØSolôM˜A@G¥Ä¸ÂÏE´ , uG®ñq¡2 .`ÞËz«»újUXØ*¸G.Ã"›mz”Ñ‚._r…Õ¶é÷‚Ê$'J¹×æÉŽz±óóWc%‰¤4Üp’€€ÊbKnñKÎè6J~ò`&™û"½Äb¹<3<â½C㯢ËS¨íéo"¸Ý¼®óñÂh7a•šn’„Úæ¸±Êû yžvM¥öÚ)ÿÔÛÛ§Œó»j÷ËÑ19lN9ìmnqËæ.ã^èþ›Ì1îë³#°Ÿòh&xHûSƒ%§ì£¨Ž:„ÛZ^{QÓ¡>b×½{L<0Þ¹ú®Eñ¡YÉ ½Ï¹rˆw²ŒsˆèiÚµ¦¸€úD1­||L?Òˆ(Ì1®ÅñëÕnšª_¾uNm¿@<;rG%H†ØQ‰mýrVä±ïØƒó¼ ’©fhiÖÇÞ碹‘•¹”.v#„>hpÿ %™`Mòô§;”ݼ“Ã¥ßpþ˜¹¼aoT¡T?9anæLôÊì½Ð «š¼¦ÚÃÓ›ŸÈ‹Ÿ"ÀÖßåëò1—…vˆt­u°=¥¾Ã »+û]+„Q }¢í©ÀžÆRÿ©8=¹è¹Úî=\*ÍViE+»ŸD°WÛÖ›ÀåLG))oïïÂÓ]Æ1[ÝÓüK»#Þݳ…sNINÜd'=7¤>€^)°Ð=¡þŸ`>ûΟW}P«3¸kr(]?*8WˆÏ5±]Ú➄Ɇ©‰¥=¤P›ö:z|*€ QªÏà#„*1»1\!Ìï‘n® «wÞ–B_„YS×,Ò‚ùúô{:-†*Vî¿fè•G(Þ<¥H·OEeÓSô €93·Ÿ9¨X ‘)Z¤x¥æ4H6A€;á#ϼ·VÂööktð ‘!è+ýªRf7A¸³í¬µQ ÿ•P­‡¬åØF"”„7ò‚JK§v¢Fÿn!{¸…ÊAT²Ýó¼{ŸÖ$ ±Ç«óC~KUg##Ýð¸adygúÔŽMUÙ$ÙÉA^ïú¿ÜMû1‚t³œ“ÖÅ6„ä@Ó=HÿÁ5ÉjuÈ¿™AZûÑj<¬¯Å¤{€q¶ñaMULáâ!öÛ´0+ä—ŠW¬“ж*“®zåàÔ/…Þ+] Ço6’Y”–=tê¯Ó½É>ˆÞ÷© ÷”Á£âãÆÍsȯbï}£4¿OÝ)Ú-I Øà]Á 'Öˆzç©Êzc¹ï ''-­…×d¤¬èÞ^5’€€Õ¤!´¹Bu-$Ï.Âò’õ I Š Tñθö® Ƴ¢-uW`üÃ#'{ò¼Í÷NXdÿÿÍWCå¯-Dë-ÕWo•½ ÍÀÐm ‡ÖåwŽÄ¥€XºXMTÀ“ö<ì1Esw$—Ft{,-Ì%sKêM<ÛY¹)ŒÕ;ÛÉÆ˜ßØ1NÍÍ»÷Œß'Á XÕ5·*ðÒ{!/Äk+èÀBs½aê{0ªœx3û´¯ÇˆW¦1_,X~èSþCg—mƒð%=:Õã;éÿNœïã48nG,‚ݦa\>>{Z][Ñ×–o“têÛÚMÆ{²åhªæçMõÙM‹eve܃a:û›$´gìp·K+‡“]c±¿åtýzmjx=¡6Ì%·E:ļŠBúÉlÚQùö¸\ý™\ûœå|Œ„8`ÜÎÔÈ÷åëðв.îøŸ®ŸvµËTNú¯,Má"€³;7FÚÀüÌô$_ðʃ/JxiÑ4߯W,Š–·Ÿä³´7UäÀOnüðëE1Æäl뢺‰ð<º#˜%Ðç=‡»&*òŸ>=P9XP‘ˆGÁö5FZ¡yÒF²ìœñ–*6öáå4E Vˆ w2B`^ÝûrÑzâa˜¢[‘Têʨ´WX5ôÍT ¦•Ïõ•Æäž WOôGÌ›ë?÷æÚ ›0s¹Êšè4Ô–eP£o&NÈW­¥â1´éº.¶û,Å¿øÌ6ŠœOÆ×çèû®gAМ¦tr‚ƒ¶¦L·ôË]6aDP¤ô܉ʻòèØÊBQÍ…O ›Ï é”×Ñ¥zÕà¤9ÌßÀ§Ð5ºˆÔj,´QcõFuòÌy"+1a9á&ü”yâ:":ßÓõŠ(mCaCU@ …­Ú šþjÆïƒ¨Ü ¾ÿs#¶Äc_;Æäe°¥DЧéü#+ÞN¹=”!²˜-ÊòPˆ'9 ­ïØìÅ߬fXCËØ<ä|Øvüé·L»E¬Ë„ê_£Áxv«U§ü_p2º[ ’c À7rTûŠýÇZgˆ,Ñ'zÒâÏo™|›j]¸Û!œi¸û,QºÅXpá` Kå)€va¾=`jî›â3¦\ÑãkÄ^ýn^}üà.òHÔÑgÞþá ’€€èmbØ}§Þªjuj?2>¦Ô×­Ö‚òG§À8ð(oE©_;éÍMZ§5zÞÂÊj@K!êœÍ]r#Î8ëm¹¢Éï»/OÂ|n‡ü¿ƒ’ìs‘±¬è§¢uÈÙ3@Ä ȦRk^2&´æ8Ó›ÍÍm,©zQÃùëÇ+Ë׋™OšáIïeJTKÕHCI5¡,1{@‰ÉXâÓCŠº½è´°,Sl`1Wµ¬´À°q¨!Tgî=­®Nç:K¦“©B9ÀüR… ÉeYhOyˆ¢k½(Z#ö$GU1ìóA †PaÆ_jµE¬h&[5-çÝ ©zb»œÑ…P釀ƒÁRø Ú\8 Lã«UðÐLdeÆ•¹#ˆz¼‡ƒâwR»6ä/g• y‰IðÂD×Ác<ñ­ùW”ùÒ›Ôè©5hØÿx磢‰Ã)ëTÒ‰€Ä'ø£ua™([ø†•Œ~†|¦Õ EyKˆYA¢8ÂsF®Vªí²A€»@¨Åažÿ&&ãà£jÈhoHd/`ø9ÀýwÈÏ¿a6Û)œÌ‹ü“‹)«’­tG¢‚‰ ¢ß‚?œÀ°ËŠ.1xÓü|nóÂü„ëKpО%†¦œLœG5·Õ›¶–© gYÙP¿,NórYP×}ZOÂ/ìýIôªz ³­¾¸{=xM0Pà7›n}ˆÙoSu‰]ýChØ×ûCÉ:„ߺ‘ëë‚ÏÉÅ ö•1²_;!+yšžªþ½JÏê>z+"C,h0Ó%˜2€‘¦‹ÞÑda¶Ø“!{r°ËÛ¨ÌÕÕ:¡Ük¤›".ª—{ôl{óDŸ›±lÝvðjÝsuK¬O Ãܹt‘½ÇÇòž•Hx6¾`Óä—²a•øÐªÑ 3‡®¸í­,–„Daó]ÄÉÀÀBakB€Øm€Fˆ3—ƒ¯Ÿm¥ßWéxKÀ<(õvr’€€ôIð´Odžñ„¶ÍÀÀþw&èeáld™Û)-‘Þ§\ƯAé±iAbW87]†.=ÝcSTPü:špÊI(ÖÆn®.yÀ³â“#^Ôîí;b ~ÉÈh˳µeXŽ˜Tú甲éý\J·ùfïÇ‘¼¡œd¸’ÔwÚË1+SYÁaæžΘ2Ô­Öb_ v6^¼T9VlÛÌ… \ËÙ„Q:ŒÈîC¸V ýæ'iñÏp Ÿ1X „åEEY¢¸áù=ïd÷V)‹j~f^þÕ¼4üŠ-uàÿ®§YS(çÝÚ÷±).³C2À®jÖ~cÃTŽ«þ]çïÓ0‹áñ}ø]CtƾYòÇHt>ý`œÛŠ$åE"§ßš”ËÇoåÎ5žGñ9z `Ë}¡’€€Ó›LêMB>' ~U’ Wºçåz§û„q½>KÄ'%úB+º†k"ƒw 5âCê˜7ÇiERŠ“¿uE8Q¥N¸ZG(ç4n”“Ø:œüÄè@¼ni࿲ j}v&¢KVéwI.€ú!é¨S—>¤ù0‘ûñëÆÍ›åNÃg ã•Ü™ZO¡NÀ€ºcà††{µ›}+FÖ÷r%ÌRÖæ­WÕ·1‚ÑYb Ÿ+HÕ  3ÆÚ÷e؇<éZ¨ÞÿôMƒO¥¦¤RCÀ3n\¹8POŒmœm~ í1Å}óp"“ÏT±îô`õØzJ…A àÛrUTÄi£7Ä£mù™y4ketb;ˆ xíLr¢$G7X"ì—n/hwꆸ='Ñe$X l,yö:">ó:©#^gð^A@í2¦ø·`µ¼D,ÍX¹òh´mgŠ™C|ZU–~ÀÒ·T{ îkaΨrIhCæïØãó«Pý/ÄWÀ´Mx^>D¹¹¬¦í•ìI^ƒÐà.ÏnÒcˆw±·#ý®òçEÀœ¾‘©ãæ¶oo6à¢dý£ÁbAÒ•ù©BÃMN‡€nZqæ¢[V;nª`5œ®aO7Gå*Jèàþ½’ØK|~âw‰¢<í³rÛÍ} Úÿ‰µìv`Oºðò1Ŧ[Ò¸Qt׿˜Ü'A E%ÃÏc¿¼áñÛ»~O²üésšŠÖy{Ôßäº3qº÷ïÉ ¤ÖQ=¢Ow,Û:ÁB_¢ í¿Ê_«Ïè?™ï@©ªºA‘r ^»Ö˜ñp<©üðX£âÎ ¶ÛÝ/ÿå-œÜTí³ 6:;]s{z~}Åzøøòq f-5ã>œòu k›”uŽÀŽ„a`œGˆèÙy=!ÿᎫi§ê§mS£-Ù\k>•h6»uø»ÿCª ³%guK¿ÂÄ"Fß~Ò :bT–qÈVm±™øðýä»Å{çÌä[Q-ȘIÎþDt^J £tDˆT(Þ®ˆ ÝŒMKÍÄ·³¦pÚ4í÷¡¿-í?a4eÚÚŠzU¾uË0¸6¿ÉóÿBä 7-FVx޲¬¬¾l+2¢pÆR£gcTÍøZKOq|:n aCåú­Â_è´@–ÐÃÓÖ©!ýƒb’€€ÒÙiqõ˜)Í𤚿¾G‹­:6EÑ‚¨€ÝâJ%s$åð$ÂÂÐP°ú­X¡ø‹­„Ù'jSø1¯l€=•™;öƒà¸@¾«Š¯öO 5ƒÍ{L Tì0ÞËÅ–_¡=ǵK…ÔgÚÊ…ß}6Ó>F‰0´ÀͳcÍÊ)cªäóC …¾P‚a»N0%È(¶?FF =@b”œo^¬±v'uqû¦mжOÝÕÝœ…ð Aw¤­Ë«ë£ÄzöÈ€ES ŒDCÆüV#qáâûõSƒuMÇR¡’梻սuœS)a'ºŠ •âEMbN¹ÎŠX³Á7Éö 9g²ÆÉ"–„@.kêö:ß$Rs3#‚¸7ãÎ$q[~UtOlSl– \‚ƒ]“Zk«žgÖwu¼Ã=cn¡º±<>Èè )|Áûq) ô  ZÚ~vF´y¦ÕJ‰ß,éJÄÇ£ò+&hؘ©æ6Thç‰eDnuô¿ÄÀzdš6®ìÃö©Ëßæø4µ3gÝ¡þMæªKRCx®ß†² ÉtÒÆ^‹8¿©à¿nqfsW,àf3r3X4‚˜¥”ý&¶ )ŒÆ´XÁåS¿*(¦“¯B˜îd^¨ÞZ¬Øü ׉œòÀl„²Ö=ƒþÚ:+€£QúR´FÕ_%BÓ A³lº=¡•ºðžõŒ ‹|>»y#«€Pì:¤(z#© ¸Ð4â…ÉYf,E ·”£ä?¥øršÃHœh… Ù‡ß<÷<þé°Éƒ¸lÎÈÌ‘œÊVþf)‘roŶÌY"îÓŲêF²jBqD³zס‰7þž˜oêUûHÍD-÷:{xè[Á‹Œ¹‚?_œÃd-æ›°sáÉ¢q’KÅA7ÛØ©4ˆPæ¨:ÊÏÌ3­ÑÈ2,_M#â4}?ùWs k b°vÌùxf²õWDýÛÆ½þ¸ëÅ'å¤ëmלªô`ë9jOÝäœC?EqyjZÖ`M`ïÁŠ2è®v‘²> vÑ(—òµWµ[0ÐùJÒœT}—Jý†eÖú§ßôä`ˆ°ïÖ6{©È˜`:*+h©Â[#ô©o}­î¢>É;>ñ@D ¿’yë·ÅFìõ½»)ü’€€ª¸Ž.R2DGG¯\—ÌìÔ8ÁWt/wnKÔ‚FÃÙçßnèÃëߘ-QéB›Ø~UÀtŽC±$“~²WwÓá_ÍÝG@7|¯ƒ'ùÁ@+ uq_mËòv͘ÄÖµÙtdÖ$À`Ò³'W‚p[Àa¼ ¹1îQýqfú¬¡$ ®¼á%ƒÅ#^`C Y žV0?ð<ñ›%³ –õ6ÑÆeö8ÿÄè0óLÒ¦¼f¬ÿŠ‘Ü#Æ—\c(}D!7S(<ÑõJ%HéïÅR_ÒjÎ’øîyZkiñÏ-ZÈ-“—Æ·aÚ½fÓžT”.J6D¹÷Ù”t=£ >M Vš1z¹8k_|Æ"]˜µ„É´Î|‹7ßqŠˆ³w?a%%ýgio §òVúUq3ÆúJýýOÉ+›}l. ”‚vâI”å)’~9}–Ü,QáUEýÐ.EŸRS†¬Ž´'Š9ýte<'º€r×!·9^î¼y~¾Õòÿ&ÔÜÒ"œ« ¿³lï·¶~¤éØÌ“ЖK Áôøü&*¿Uzܵ±ÜFw¼Ž_-1’Á:Oi¶D 7%¿P!…ÊÈ·t®‡|¯¹²ÀµïðÄÚ¢NqE•ÞœŽ/ÌÓs‚ÿ ñ(¡÷†õ×ÔÃ|GØ´»jk8@0†ÊÊ>¸g-²ó›]­Íf-û¦5‡àç_³v>à»`’·Üñá’>*?oãíd‚®Ccæ{^Iºd@Éè€Ê²ãµM:¬;Ò¡9|òÞH½sIO¡ÇŠÙx‹ø\^cWÆ¥œ[º\ÁO$ ÏB óÊ~†Gö¶âVF ¾Ø;×*9'QÑcx‰­*t¾);aµ– Jþ¸Z*èúKÄp¿Úm áõ¸yú‘Þþ»ó–£d–®¡4ƒê¥,ä+2¡OØtÕ Óë%á÷ø*VË<ä¥t~8ÚÌ¡OWÏeöúýïâÓ6ç¥?*{W‚s,g&4¦[s_Nýÿm­F'æNýjÃ@Ad™X’ÓŽw’G¨ÏNÆ5±,¢Ž„'hfs{kmá¨Â›¸üÇñlz/HhCè¦á°‹…Ãa¬ÿùi Í®°ðü¼˜Å¬/e|1sYÌ lÃŒf>©}?:4ÐìœPetáœÛRу^Áúo™|?„;Áر&ÉüìóÎÀƒL-ÙC]KqMð¹ß$ é—‡àÛ¤áê,fÚ…x•áïµ” ÈŠ£;‘ñ«Æ˜ç¸áxꩯ«9ó¦3ߦõêÈ8 I3¾ªŸOá:€WÜÐsÑ÷:؇‹SÌ¿ ý0æåÛyFégAáÈí ÆéÊ#÷‡:ÊNÈDÜ%ÇŽ*ñ‰¥ã‹T8´&ú¨{Õ1VµEÛØ6,¬»®(g…±b<\Ÿ)€ÛUŽ[íº¡RÏ©‚t¨g9²·/]•¶“-=’¤‰£nÇÒzìÌ bùJ°-:SبwàZú8:oEÊÝÚ<›þÿBDU•[”VЭ5d+r¬x4”Ï¡øé=€K¤ÇÙˆbSo$FçŽõ0‘_kƲç%‘Yü6ŽùpII‡caël}í¡ã„âÁj›ùDVyØ—|PP£k`À埰g¶¼ÌŒãž7×AV*…T : x¦ n ‰ %A·…–‘– ºùApº·÷œIÆþ¯&H䛣H{uç†åý?…[ïV,j÷XÉZ·|>Ì×û6;Ùð ï!àuÚuÊ]ðl¢(,‰ºMöÞÞ¨c<“‡(Ç}Ÿì€¤LrçÒC Ó3‰’(9x¸­ùQ¢aš‡HòY$4X’€€ÐœãÁ·Ÿµ¬=>:œn⸮™1 ø@“Š……cÛìE†wW즨aú¸‡Ââ.ŠT;\™A9”ºk#cš’ÍV®±)w+¾Æ¬ù‹/2þ3¥}@x¾‹Ò”V¡Ýÿå1“[½&ZÝŸYºh 3ÖâÛe*/øÐ‚ Ù™#÷Y~#"}_ï|^çÊÜ…'ÖÖ®m|yAå‰Û‹qŸiß³ôPÈËHYg³²’U¹âÜÂWIß~"×è‰6’VÓM¡ [¡Ú$ýÁ¦`аLŠŒ¸ò®• |dÏÿý_QfÌlÝÖ8‰7ð…¥Â‰xé,Û€[ÖQKöäc¼Íƒþ-^ÃQÝÊ$hoœfÎ3.ñ=´›h9X>ã^¶)¼øÐR©•_‘!¾ !Ê‚:‚’ÞÔ:¢ÔÓ˜]}ÑnþÄÒ•nñúZ$ ;i3©ïÎê .sæÊ~¥&ÌlíXà×LúSJ¦¸æœ®aºÓb¸$nï ›ã@ :ñ¶uÏáÛ{>û…¿%iÅ…óCŒ`èÃ6"‡Å-WÆOŒÂöƒ‘b´šÑ¡¹åÆ«"ú‰ oÊÈ78šñ‰^7CF1_‘œxׯRaúŠUŠçÛJïÃÔäs‹–V÷ÑÑ.P“ÿùÊ—ƒ1• 䯸EµuÈÓw¢žZáqóŸ¤×w9J=ûÞ=‘Î9=^¤F3”/A…B`ž·¢öÄ¡ßqЋàJŽÇ<»¡Ùá<˜ÝD””cÉtˆ‘Fª†üEñB´¶®ösÙ°f®~2YØð ªå—Í¢”ªøzwxè*wÀ ¶ÿà–>rú¬ÕU¹[ÜèP¦ðb¿¤‰Ü;Û5í'_¹"¤Û$Ïç!hmæÿ*Éu/ Ð]JözUöå.CôÉÀãMÌ9CÂAÈójâÿdæxÙçÉM›ú²þZØÊ6Õ˜.4«•Ò¼ÔÙMh­r Ò9”å3¥òÅîhÅà¾çæ¨m0ÿQDêA¨ LÓ8ýƒž=±dÀñ¶†ø%2ÏMyñ³â2AŽWoc$ØyK> ‹÷“W–ñ{ûn›×êîZú[/&’5Ìaj;u3.Ò¬C°WoË¢k×,ìVp @Kˆé³h[­|A˜¤ºQ Ìp$E=+¥G˜§îPçL*f$ƘØOf’€€Ê/D3¾©ÍÍÑ yžärµÞÐÑâÏD_dN’-¡ÀËÚ— ŽÓ§ú:‹E$;ïËÁzdãËDÃ|¦Ní£Î—×Å)ç«B_@r`y jx ²‘·ž²û!Ü+1uþœö–‡ÈRÚ½oÀ§w∆Ǻ¹i[½mš=‘÷å­ìã`UÐdb>YYÆ£ç®p.&IöêÞ@K¼tXÏB:ËÄíØ-ðb϶9 Û&–\•³GXiÇ{MÀ“‘sêµâb^ìÎíeGâ÷™ e©NëEcòͼ±¹žËÏ„2’€FÛ€ø²ø="RÊAq06ô„ZÉrÎw4ÿáØ…¸–<@ìŠx’ÖJcEµxŽé)DÖÔ‰s™b€a§ Yìi0Ë÷ß…aZlÝ…‡©;þF .FŸfYðò»êžñ¦=6+l‚“v× VÇO0°íAÓ¯€>ßÅ;™hÅpÛPq)fS3ß˶ñ<æ×®Â”Þ²6Z©Ó)Û˜-"§à—XêÒn6¿lÍz\=ˆ‹‘£_¾ûþ£¼ªtiÊWŽ~õ»1K_ÏÁ°ù°/7ÉÙ°_nö»+2MÑW€H¢‚¢Ï&÷ßßn|WλÁÜ(ÁVžµ#Ái"3(m›ƒ‘§íÕÿŠB—ÿK_ ^‘ë~~"3¤~GðÇ™ïµP+Ìç»Î“K!th©54ÁÖaSº’B õï&÷~ û`¶¿,žx½Äœ5ËD$EÇ[þ€RLgaVÐ&¿”‘Ë©Z‘ïºWÏÔ¼mDú‘íxW†ê¸÷u"»«šµ,ÖN€K¨´B늡QÛÉûÍÔ··ÐÏŽ¡F¹dd8¨êØ¿gõÙCw¡”ÍW“Ö¨n—±X»êsBrPºxü–fÆÐjú™7ÍÈ—}‚v—QL ŠÉ¢É 3 ©ÈPÛ̃ê•GŠjX>í¢#mö¹¼œ7e.âó»BäÔ´¥Ë.Š1£i…]OLRÓ˜Ð7G~F}±¢a0ˆ&Ÿ“#äHW›õ—œCX÷C»€¹ÊHš@ØË3Ó±WFCÅN±ã$qŸU’ŒL%#ø Úæý^qœ^¦°­ßl¢ƒ‡ñ3e$oòt¶© ‚kyËÑÿh*â=¯Ð– HßÜú‰ÞL¯k¦’€€ÈäÎ5ôŽ<ó8Nê!Ö0eô iå[TÐVélhZ[Šü›Œp+¾ÅóŒ3£.ûëyåõÍ# Qòb1†Îª5mJ™–ÿ8×fk\LvÉåF@€™{+1‡ÃÉBåÓÅ;r¾z©Õ–Ùùý˜€Qlø~1—@òmêñ€½©LÂWÇ<-´îœÙ 1+²¡µ…? eæíÿÕù•Þ9+Õï´6_a¢X~€ñMú¾a_ûÙÎÜ:‚å|·,¶ÈOI_o' Ê19J¦¢¬’øÏ$ifO=T_…n+0Q8/žh•*¹E­Þºóa £ëcèÎ$;F®ˆ ħ–XÖ!A™«µ±WÚq«ÈP#°v:Ð(#‚ a·ï#„…Ó»zC¢”ÄÓÓþÚhÆÔKöÜ;ïB»OlgÓâ@„m‘^çnLþ'é=HF'Þ÷;ûÀÿt.Sm;ZÈvØȲ¨E‹ ™y’ÏëEümü´ÉP"‹wüóIîU~^Ff\@¶Âf4—¼Ò°e`±Ì‚-魛ļ ¨nºsGR<Ÿ¨´.G1²ü½8-O·`äð%¿mTmÛ~Šõ¿ò‘«–±a‚-htJ_ó†·¸ê,h?' ²­ïšƒ—ihûeªñ࿌ngf™pätzª}. ²‹£8Ê‚å üEû‹øyö/˜<©»ãVùî´÷ãÇi_„+<¤Nø$'Æ ¦u¹¦0ÓA)ß!e#Œ~D°¤6ʬ}áß‘:¥ $Ç»fCœ£:lHp3š;¥ö²p³ø¶¿šçÓY\R;ûõ0é#‰¢åƒf¿QGÎXΦ3\: d ãâhýÌt ‡¯­È>˜Éz"m´É^ê;£gò{æeá½¸ÛÆ%«ÜiðsÇ#L§»´O ó›Î<„\´@þ"‹¨ò`ª¯ùÜ%J‘šÇΈàì¯5zŒ'y²æ1òÑü»¢îÄTmAQߣ&=U[iúq+êšë*O%@)™\#&@´þ•À(»sœ¤*Î;ÃÎ 6òç¹Î성™Àµ‚ø[Ι©ƒÃ*Ÿ”ù* ü÷7yzÖ^¢xù0e4E§‚Ä’Gý-e‹5½„e2}{¬GçSJË¥Ë0Þ %|´ë»å€K; ÆD,=¬îJ&^@åÜKå2úÅD¬Ÿ‘î\’€€³ù«œiï|cÆ{fc BØ9ší$â0oÍ*QYû(AšjjxÀä9Œò_»Ñ€‘*ŸN?qJcÇ0ÌÀäÕGgÜGq5—3e˜ÕÏ g§«c„õ7ŒbàŽ°ƒ0pî¬Í/)J£`êûÍéqët9DH¶+›'„ÝŒHr£¾´æ@¥Œ4fcÚÒØ(é‘$ChÝuŒ•´7Ã7J–²¿õr¶ÌŠ.ð¸†Æ7` U•xÅ^™ÿK†íù]¶H@c¼ê7>"QÈ1k@w Cðo(GöpÎfkìü1“še-.?|Éþ鎩TLÐ’o5̅¦ÌTxÇJÓ™Ÿä0c4óÆ÷I«©×œÊ…sXòc´ó¿¦Õgm8ÿS8^åÙd˜ÏE¢*øc‘ ÀH±dˆ’(SëÛadùó/TGèТî»Þëƒ?–×*8ÜÃ×7¡oúd©ßº0™ž`5ØÞm\ß»œ\væÝº%jÍØwÙ@„€¬É±—d!GÔ™ªÄÑûCˆƒúŽÃCå} µŸ@ò o~kù/žqó]eò‹ÃdqÍ3$‰fû=Gƒ ó¯]{°ã4'4mø9§¨à†yDìËô¹œ¾\nž©±åbÁUò¸¯GĽ„#úêŒ& Ë˯°YLdõŠhMäZ«àÓ¤që3Þ¹PG ]Dhµ¢œ{½é¨XËÔ«RÛäø¤Fægu ˜«®T qÙ+¬KÔCF`â¡G±y8âì3Oa®EÎ?$DVs¶›C ŠŽ,üqlúãã~”МNU§By¥îa Žé ^ù•¬¤èdL|ÝAn¯j¤à0™U…§V€”{õ+ÛBj$X@2€Ë{“$p~Wk €#ÁבWºâ[ŒPÚè XdsdN'Mr£#3ò2ÿÒ•;¨Õè~=„4-û›aŠu ø|¢0U’€€Æ`œÆd•ì-–ûo'€ý¡y²ÚÑËÑÙˆ$tXª‡÷g—O¦ýÄÚ•g\ŽÝ¸|N*6Ȱ^ ÕgÀcö|v€[3•Õá»:Þ²'%ðÞ“Kƒ€4g¥xq5 $¢yî†~>±f§ø3ôÖÒ4¾§XóõB' UŒÉôh Ä:æù—Ùy<–לB‰;Ï9Ã#†³¶z&škäa‹î?èWJ'ö5Ÿ»# qŒ.m{%O1Ó†õùXÑÎíÇ(ÝÊñøïºË†“ôøÿ c1‘Bªe`Šzƒg¬Ëå¾;½ë§}¿ ®AÏ% =¸Ùìq:hЙ† Këo$Ñ·¬çð­nábGy 1 ›àç}ÀLC‰Û‡—Åн¿5Žª4— ª›:¶ÇL™ü)H,6¼-o›®,NÞàcÌì°ÿ¼‚”)¥ÇSu²’:f j&ƒµ« €ô £ƒx} &B3Ÿ…(!2^ŒI·rC-´ ‘´PODë±D{F «&䩉ŽL-Yï¸ÐebhÚ9¹!Ãè0s_­:½* 4Ò$]UBöïøŽ1 Ò…ssg.iùhJSi …ÿŒ<•Å-ƒÛ"­/­~ôNîÀ£ Ù¼k‡".Me™tÚ̘)ã­³ð>_Ó…„U2Z…müσÛÞ,æ*S|Ðó²|\ÇibŠ‚x# ‘aT\k+li-OéGÔÇË(_-w¡vÆèЮ:µ[»€ž¡¥nᎦðx¥efܪ*²inŽ8gêsVmŸk`àµ9úæGÒú€×»˜_‰Ÿ•#%Â1™áÓ€Öc&vº„‰¤ö¹dß¹ÿLê} ÐXØ’$AÕ Di·EŒšB>é^¯³F·¼é:ò-&×·µÈ 3æ~Ž7Rt-¥J»Õ{à Ẻ·^Q›Sþë̯•Zù2S¿UbW ]òNiµ"”ñå^¨‡í x@¹À¥—AÿI|åJ¡OO­üjäƒÕº„ÔBê—/ÃïÈÂÇ‘£Ø˜j/ߊýtUU¾—×Aà„x– 2íëð¾h³¦ÈCÌŸ^àl¹2r9S‡­áÀW  wÍ R<„Ç‹½ÔÁ®Eû¬¦Àß©vþ%œš„¯W ÈÂ*ìJäö¡÷Ä7xîYc:··Vë’€€ÑÂDèÚP%Æýbb ‘©¼1ÍŒ} +‹ËÒÛ-º&æäý—ÒȲ¶¤76œù†#ÂÍÅ-Éív™.`4Vð5¼nç¬2¾ã  .–Œ^BÈy]ò%…­–¡z¢åiÞiÖ¸<–ÔůiOÍ£GX!.ØÈ*AùÏUª’'ROj*±ŒÏ=kC YŸyEËÅ6.“Q+2—‚ÿ¨eµoyZà–“Å&`v–C2i¥v²«T8‰Œ›¿ÆUI°/b_Îêuôè×ve¶ÂýÚ)Åï>/-ž[ªDýÚ³ ܦµG›8'•d3žC+(õÕÒ‚*Žgéû@¯pöǵ0A—dßž¯§”næÏÍíd æ—¦¸!Ó8¦ˆ¤Ç(1_´x©ñ%‡wÓ{QEIíÒȉ©•¸¬ƒ¦%ß»Ó?qKØvØB<(¢5Á²4Ôdw4ÉWž‡*@mù þІýáÓÒ~lõ1ðBíX‡ùÆ”»mì’ƒøÕ,Û¿Í)©.}‰ï†}»é3Ǧ.æþ¿µ'’€€Ær.?Ÿ×´qäŸá=ú-ç·,# ¤m”¨TŒ_¶Úv ˆÛrÕã˜!¤ˆNuò­ Ñü’Ö©µBÈ$] sGë ¦/¯äèO>8È>kià09³¾qÉЫRÒÂ̱u¥¶iG‡|ÁNxMÛw>ñZ.¨'õÎ?p>¾·PúëÉê1Q#Cϼ¡ÍÚXäi-€Ú±F°¶§Ç3ÞÇ\5§pø *Ø5EÔh|Ö¬#mˆ¾ø¥æ2´ 6u±ï‹ïš†A!–Ô˜ïGB®_Ö/‚'â`ø~#_¬I¬Ð)nS^Ó°˜VÙ#ä!N… €±ç˜’!¥]$fDE£Xi¨m2w´ÊÁº¶ vÇpô“ÝY¨"hšbæéÞðX]x!ÖÓxùÙ>‚‡ÞêÐk÷µM™øf%º‰¤?9ÑZùl# {_f+ZÆæýÆ‘›Âžîp­¡l©mDdÉ…M[e^È* K’šÛƒìÒ&écšSd óQ +í—œL¯Í0àÆ.\¥HÛwÕ­)­²RòÓÞåzÚ½À):˹℟ï7©ôHHíY8Ú~xÎÒæt<‹Ø-¸Åž2¥Õ‰Ã§8é–F@9Í7"Òh4U) kdr‚Ýt¶8rî˜_ÉÔͨ։‡³¡è°mRì‘é`ÚòdU³~ÄI$?m:ÒlþO9¡€´%–y;—õ…OÖËF¦ÍŽ;Ý*·×D\$xìt·´1Bé ã„°Î€5]%ÈEc¯AíFÒQÔÆíõ®E†âÃ4Dy†]^ô§næ±ÜYÄa‘jë}îk¯ ìÎÙ/£}uÊÑÙ®€&L£2®ž£F?HïyB矂*PÜ5ÌïuÛ"8.¶»´"K UµÊHŸ€|,–™<Žçÿ\-:ßáŶЖïz§?Ä’•ú½6lRÄE·ÜUÒþ†ŠÒåÌ®ƒÕíl‰îµ"£Ì³ó3® ×ü€á~3á5€3eø/pÝ`_BA·ôO™òþºSò÷“œÙ;¢Ò (±ªP–ˆ+Ïl ôõS›û‰6ŽÞ\0¸oºÒTfyÜâz€»a¬1ž^£?öâtdu[}Œ Œ%è°å– ÕÞqGE4†b-Rf¾Ó/®¿À‡ê{†ì£Ç’€€óß&³ñvìïˆyžC·u5UÎ?¾µBhƶàbõ@C.RLA#B<îPs‹c;v h‹ìQ»?¶½+ß½n,‚Q쮣‡µÑ²¯†×]zU± XüV<?œ ]"j]iÐݺÁPÑU—Ö˜ÚNq¦ÈlÊÈäÜUlŸ*‹¤6Ø 07æTŸà„˜Ò^¢Nq@ˆÚ#c¼š¼ êÌåΔ2“&XU@K¬4&)_‚4ªKR°©’’pGBÜ:‚š–x´]th‹‡…‚•ÄR<޲„«ÿÄOß½–6c\ ?7¸'1•-ÃKŸ˜Ì—á¿1F‡•XdçõØ»§=ß(ìÇf±H…‰i _k Û;Þ噫G>• 2Äã¬q“BõáDíeÌ©÷E¢Ëtz‚v¤ýñ$¨@T¨’:‚¹Žn3O¢Å‘{— ãxe½ÛÈ{¦ÅjšÚøóÛH~Fv€õ;j)™8Æ@3/” Àž[þ‡ºÒ ¹2§xPå"ä,Ï0qï§@Ž–a÷üús«d5•SõcÐÑèùÒ \9ÉPÐÓüW…ß—S±'²yóó+TèÀOh³;£-©Öéuòpª‡8Y3fJþ‚+ÔE7Dï Âj`¯Â ßYa7+h q]V»(6 »8)t©žD2)ù„%Çi÷–•ƒP¡ËßÖ7jú~7h˜#$& *0O"¯‰ašœèר㠘?Òµû$æÂÙÆ¬ü%{¦\cQ@O {áÀÌy¨#$yhR®Æ{©9å»sx7fª¹<*Ù®ôî¦ñö,NC³‚·ôô†OBÝ›Ñâ̺)ùmPé )òn`в ¸XVðw`òã*—–g‡<ì‘ûŒž^Ìž|ÚÔ§ßñzõw¬YÃõb ‘+[;Ý\§‹¨c»ú‰M…]—'y,X|¶E6c3à&qpmæ‘ðã}•féÕzÑ?£,©àº7wµªc\þØrg('¼ C\ì_¼z8_záVƒÃò3¾$¾]µLh+ÌÑj²Þë‡'OÜ,¾^ZF§RtJ½d+pšjßÓ°Mk¿’ÂwyãØgî¯ÏÆêl! TxÉ iE0µHø4§û”ª&!W»&Ä>Çóûg§¬CÄö\5ì÷ô“ÿðNVW’€€«¡PúlÈr#¢‹Ôe~J3ç nN×ÇÌ#eRQ¨H<Ûs/_ó¿×f=tgĺ‚oà V=ê`‡\,¯`|BÃå­‘(Cã³úfkHAeËÃ%‘ÚïTJ–´„±Äÿ\J%¸€Ìž'TXjzý‘:zÛèx^‡oÞ’IÆ„rPw>ç@Ðȳêw |˜àVyS*—ªœLôŽÀ;ÛlmKÕÕC |ñ×!3ªî㻑ñ ‹®qž¿(U¯L»sy K±¬Ê:’à/ëÕl°@·–›ôÔõ¼ŸùV2–ÞpÏ7cŽMZÁ›r[{âR`¸F‹‘ú\°þ7B'Žp5ó/YŒ?}›ÅƒÕÕÈÁT =­Ì¢3QÙØEy/Œ¿·,6£¥ÀwüÚ’k­í/­‹2êT,O»+е¢¯h϶*™‰DžSic£¿Qt µ!"Ý¡gxý:*+çl ¶ï|ìë áâÍïÒ|i;3&P Ф©‹Ïõ¡Q…p£ ô\Ý©™Ÿ¦±áœ—Äë;­êû?_ç÷íÀ¶„-KÛ' ç'­‡0f̉¯ÇÞ«|ÿF+%1ø»º§+.­>¯i©²²gãŠþ2q?U?¡Ž¡ð»¬‚»ÈÊ"iúrn¹ØîYšÍ 2¡ƒÍopwó„M˜íP¤,7FƒqÜb]O_˜9­:Q> dp$2FÅ€H’Xl*¿:šKšWWøìücÝÜÁˆ¶MdïçBM™íCÅwSÿîH¸õȬHÁŠMmö„/‚ÎeœåP95¯÷ó»³ ³j4`ÆÀÕù¿•J›Ýžlăká)úLÜ×…ǹÈSùä…£}*ŸÇ]ë©+ŒB¨Ðsù(Ä$ŒMïîV‡˜¬ y†r,-í%ç3!;`ÌKçyÌ ‰Mô‹Ù!vž#ä€ùØÆaƒƒ%1&{!‚Êó÷þÙïÏGüÀ¸z¶ø³éfß%{ù´É#6³³´MÔÀu*'Ð^ÅrïËŒíã¾YC7OÛ"Z_ÎA¬0ò RX ®! Sï–z¾àAÊ`årì­N[¤„R:úò$sf‰]Èà‚˜ë³Œ +?é[!‰RÄ¡ ä PNù0Eß@~ën/êž/ÁÊ”ì.-£Û¬H¹§ÁSj¥åƒ ´f'Ž žÉâ@æßùöÜ?>3ñ_öO¸õè’€€Í±Á´ ²Ã ÑÅ{þ e“‚áH ï¡ýïïw`|RÏEOÞ/îB*Š{äu½ùxöˆÖÇüP½S‹C• Uäù‚¬~(Æ{ˆC®”0d¾yù ÑwÍô¢‡Rp¤N)cÚ>ʨ“Á—õfóþšœÒ lÍ;šË¼ë l|%sl—²³Øqû³€~Îf×àŽ­‚¤Ïkð³±²Šâ)ˆ[°æîŒµ˜Œöš¸¬ß‚ç™4æÐG€:ÉÚ‡Ô‹Z+Ǥ¦…«±y¯(cèŸãâ«î.‰ ž.Dé nìW-w1` ­±™X{ò:þ’-J|"ÞžÃbl™pr-î½|n¾ >SƒÞ7ÆÓäü²‡orU€ìœ}‡¿µ\°¸—LBŠq—!v|ådo4þè­ê±˜ jJûK‘¸~Ù÷–îú½Â@A;o› ŸŒºãN àbÄcÁJÍÂá€Zgn<Ô­T­{ÒžK`b»Z8 Aûª ¶HuÓkôÇT±€PP›^žèðÖ`!ÐV`bë<à=×+…(®ýúÐ_÷ê# ­ Ìþ>ŠâOu4ÄíÖO€1*pYŸš€Êçu¥ðvUéïÈpoà)vëDÓ0’GÎ¥Ò;Ê͸BêéÛ9î(Ä|R.„æ{¸T´ÿ>ðIø ÕD¨„ØÊ$¥ aqï‚<ÛýyÍ×GûZÀá7„05]§AÐí„jZ‘ê…ÙWqkÚÉ 1çëظë9™[¹vëˆ÷Y= ãÚ"+yÿç¹*° Ê`ŽxÊ¡ŒŸ?ÕBÂVv|—»c¼¸nG÷§W9xâîeÈÂ¥;7D.B±`¹Û#Ë*# |zàq°Zû MÆà2“r¦Üo†üÖûä8}$©±åi¼’€€Ð¼ìV¶¦Í…/ôkxfÌ—ê¿’hb†Œ] âŽ"Êu±“ ¡Â6ÅpU,=–¤oåÐêĽe÷%d‚”\œ)³Â|º£Þ,`ž $d€qÍF_Ó;\kºœ4Òç“êPžk>¦ÅÃäíg5±˜ÀQÞWYëwá9¥«TôO+)&DËoŽKPŽnÒJDû&»#f¬ëº´-‘<1á”’Û.,ÞÙ‰¯ßLf¢c˧Lbà6tKqX—ry‚ŽuMœÈ6Ji×ëšÁ¤òÊDD¨Õ6—ðMfl]î‘Ó1Ò%AyÍ€âý*>jè§P»¸ÝÅe-93û²cOZYC¹a|êÅzžŸwÊ­õ“}îvq¶·¸ÔÜ•µZ y/ì fÓÝQ§"6é»[¥ÁI#£ ‘ ëŸx®Òï™ {Ì'÷ Tz\¾0v–ž¨|~rççÁâO!×cõ×”Ñ4Þ6ATøë2ňàa X*¼M°4†Ðú‰Zï‡ë)v*<•¶*x–'¸!•»Ì­Ëˆå¸.ç VÓ)Qß_+ø' ê—Pò®4} Ðc—'º¯ÜN¸öãÙˆZ¯ŽÞ³©ú€`x'½2:W€˜½é&œŸò¬ ên„>D‘|æñr56^£ó'ÕxÔÕ+¨åÒ#MŸ'©­ Ì<†5Íû9"ú‰‘ÈüìÐõ„)|Žª;êsB8•ëÓõ ÏøøFößKe®æÕI×~]µ77²ðnñ8¶©yHŽÙ‹›•Å‚ †õE³šrâÖ¾’š@-¦ŸÒaB"cþ!æ«Ò,ÃÒnEÛÔ‹.i ËõZQ"Ös¾NªS Þžâ¿Î!ì‹1ØC÷¦°QOÀêɶuqqìì_o¡OV†äœn;Âð¯Mj×G/ìt:;à†úª²zŠã`‘T>L^nwL&¬‘“?º"°Aœ¸ ‡j€ŒÒ³ï|RI$ÆE±­¡¼e<ŠDåò$1¸Ñ5ºò½t8[.Õ!~»Í Ó-¢Ø&ÄöÁc/2GHMv´ÂTM­vIôp\ÜìuŠ£¥î{€AÀZ†<Äé[XØSEÀŒ8–Õ¦MLÓæP´/6/òç>—ï,³Ã?µÍ° ÍÉt“ãt­Ê«Î’€€Ðó«^‚er§Zl}§>eá…>ká«Ê¸Þ¬ñì.†…ªƒJãK Úé%uþ› gØmèùÜDö¸sç螺Æ,H$Ú2o*P×9oÌIÿ{e©ìí8?(ÉV”Ó¨uÔpþ­]j¯ ­‹q§ žÿ*K”ãÓÔ ci7•ø³Ïâ67:Ù(3DøaRÖQnvk!óDs̼ßÿD":HÒÁ ð+TLâ\F$È<^1”ª£1²ÃáßѧìU+¸i7¦´úªëQíÇLµs°ï³17# 9ä¸E,I,ÿŠž÷¥žM\®DjÏb¾Nûý?8"sï´!wGŒ?üHßÒÛœ¿hýÅØ&å¶yÙ•ýna]È¿ä.—Zÿ²7QÑ÷¼Pz>-b ûtò9)`<¡¢ˆÍs(®oÖYÛñt â¨)ôÝC±ã‹ÿ´20aT ƒÁcI' mM0UB4Ò-2îMwj@c'ÊY;­NE~]ü†* Å¢­ýí˜Ä<‰o¬ì$;,3Óô"YáåÃCÛ«?=ì†àMeGÜýSg= -"…¼Ôå®îúC’€€À…ç=ËUóXÉþâ#ïö×þc ¹—pç¡ÂÆ\¦Î£›žèh¦aåZ®é´Ñ»Nšg £¾DßÅRˆ50o«‚¤ÂÃk®Ø¥ y«Hµ}¬l[åþõàà:™Õ”ù I›¡®¯‚–¾édZ.£Cö¸/‘¥œÙF”Ð2żÂÞ:?û*lb@bç8À÷B/ñËõ08Gàü«®›¡IX¢Y‚rðJT¢É Tcê ¢‰”²P£ AD'ËÔL.UŠ—[JNÚ×"i˜'65¢Fëå 禵þn.1=±c¹ÌèÝš=m²½!¥€`’D!E¶‡'T!Ê=$V9 Ëùf÷‘A¶þÌÞqC˶K5vú³Lèx9SCfv6?E„[¹IŸþ«z•Ù:Ù«tGaV˜PÇäfc†L!¶¥pœÌkÚ6 ¡(DY¢b*Ÿm¤ÂÕyåCîY–FͰߛÔD@XR/ÁXOZ*S8Ä»¨’x8•Nlp¥´”´DÇæ€k¸¹ìŸ·ñ|úfÑî¯Q(ý¡…k]Óœ7AáWrpÆ}›p.³õ¾áðir¸’µAã'sÇ²Ñ ¤ÑÖbݻޖÃ&›ȩ́ŸTý,DI "vÜ¿BPŠäµh.œ,1ã¸Ë`k=Fb\Ô!éØý¦ ¦*Ró ñ^¾°P#¿!–¾2ùRÏ FŽ›°£¿5-¶OA à”®»ú½æ?-‚Žž*yú"ô- Yti’H­ÎäN†–ëÏÿÜMxÍYÅö'Õüʆ (äf Zó€wN骤z©ö!SŸ;&˜"ïaÒÃ’BÑ;ºøJèó%ú$0:eáèÿúÓÀ°¥©¬nU±óˆ3`yÚë¤Ø¶‘zøÖžúøf™'™¶Ú {Å„¬l¬ªÊ)]ÈÂüi>¡Óö…ô3ëJÌ”غõ¥•–ÃüÁ0pƒ°€mÝ:ºdεsU±#3 v甜[c¢èn·è%¨r›(ê‡7Cnñw«‚Ë ÅöÔ<ýÚ…œU"òI ŽpöößÂõ0‡Û쬤O˜vû w—øîâò´|Ó3K9£á¹Rž÷T¹oX812ºT{‘º§] úÕñF9ô±ËߺEš¿Y¥Va›VòÌSl<éë£&XÞ„¸£óÖ̰;6#‚`g’IDìú‘œu<¿²e¡5'ÿí%ô\ê¬8']99ô:æXȼO«Š‚çªÆÂ,ÃâåŒNå½kŸ¼È”2e»fpsOÇ–ÜÉa㈂³³t7jŠÒ‡ûÙ_&,(ÞDqNÿ Ö uWŸž‘ÙÊLHòÂ8,E5àWp6¼ÞžŽ ‘ CÃi¥ªt9 ¥ a.#,ÖTs¤…ë,Ëìå{r1j[×4S>IË7)/«jF nägìŸÕ!Sߥ0<‘óITúŠcžÛ\³Å EL™Ûd.²²?p2_D/$¯î:³¢˜yù‰!¶®Qo¶)zÈA «`­ë+¢´¾Ö°²™ewÕà2+¸ÆF yÔ˜¯ï£–Ï {“hpò,–ù«µ«Wl , «²°!¿ÀdR=äe‹ã Z\á¤H/o*$mÉñœ…0`÷„†u¡,É“f<Þ¬GiÀž”N©è¼r6³ªØËU±ƒ½ºwÃysclÇÎ?ӑ믙<Ê>“â)‘ŒWÅ-Eÿ"^6’¹r•!øÅ‹šL€ÃÕ¥\›¬È3}6ÿÌ|<.-ƒµÏǧ|s8”· AKYyž™@¦œ¦žÌX>bØXÇ %Â×+úÝ–ˆ„§54cÿg].¾"8¿¶¡<¥ÐR¿†K’€€·¡3ÊnÃYE (ü›ÍÁóò3˜$ d1pç6 n h¯ÙÈtûuŠD.Ii4a?m/ÛWèÒg‘bùZcN¥¾ÎÊ$.|LŒÀò7ñýÿã+¹Îû¨v2ü™^!¼­JfÄŸQ¿‹¾¹A†4£Q¯ëçåºUG“Y¨×pi¾=Z³ðøN tgÿ›«¿Ÿ6D€—ÔiŽþ•Êëá·8.&‡{#®¨4'h³ƒzÊã ìp´¶ìÆu‚ Dˆ(aM:nÍÚ°lCz…z)<³l[e—èþ'‘Jâ½ñìoAüŽ› I¤×P÷¶µËis«,3Õ¦¶¤…K Æ% 3½pôx¤‡_Ì5å…Žî6&2_”ÍGþN-lц·?IüÉ#ý#“ CxG´:Šû´´®Vüå85=ˆ)jð`yÄ$ïZ€ì ÅÞœ§ÙkîmàýÿqQ{s‚eN R2)j}9•VzÅÞ´zÍS5^òWd…ÞjðÒ·ÆÑsW‚MãòJƒ‡ôÕ+´Ðñ¦¤Q~pç)a•;€,ˆ¢w½¹+õкž0lJCj.E3^»Âº˜vö3ncK†í] bž«h„[{:N給¤8&C?ö„ öš{„:SŽ\vÿ³Äô£¡G^uØã” ©îíÚ›rèŠÒ<ÌF10"ïiºóú„Ð,‰HûÞ'ÑÛM­=5ÐJ2ö„¶°O*”ñr)héÄÃi\‹G†Ls(A<;>ag@½N϶mÁr¼FßB\‹±@긔ìÂüq Ä¿ä,p¿?¤B~G¿¯[Éï»B°ç-Ë/Õ"7ëû"*ö“wëŲõS€eTƒ› Ò³«Ä6d({Ü­d>Ë ÙŸ²¸Ò<–ù•Êñ÷ü‰Zø™{!km$Û–œè ¨°Ö:Óí 'ÓÔ¢J+hRm®D¼¾gÙ£>áóyj$™:—RèV@€³°÷z<(?gÔ7#q6W\8XH™ú¾Ã¡UT°ŸlþBÒí$Øv+Æû ³˜$ÆÍÊìÉgèYºt¥’ˆ´*7,†‚DãlÜB Rùóç9ÝøœÅo=WÔqôâŽì'•¼ó\ÿ¬Xé€k%_¢’£Ž¨ª†–CM’€€«aÂÍ_šT¯x|±NÈuÕðj“÷ðC%U í#öéSq•1––û"¸FÓ‹œdcY1&…¨­ŸŽnà o/¹Ï/7{ïØõ¶Å}ʼnÒf˜¦¸¾XF3ë"¦dCªà1úRÑÜÊöFtÒ¤sœ¬{ëg0êWˆÇ7nh‰Œµe0¢ï ,MøZ‡´'l ›½³n`|® ¬-pfÐúÔ» tÚ¾0Øuõù1R ”1ÉÞ¡¥Ü3“ãeU!a§Òâ뙌:ƒa°*`ô†…(ï¶Ö\ÈFq•þ±Ä°Z~#¹Èv.EÆUãðî19*ý=/ÿ:»0Z8º†þqíîªÇ“óGÀìÖÓSqÀÙ Ü«Gäâ+ê9X’#4ùµÕЪÖÊ˨nÅp–&Â.9æì¼2~•cÿ…Ïì 0hðùJÓØ·fdÖ{4Ùr-DéEÉUHZ³µY¤D½_εݡJ9nM»•þ¶PRJÅQÃ¥|r=>Þöy„Ý[ªK”P£Œ¶ÒÇøÇ —ÆÒNæisu‹PîÓ»Þ0•&Ÿër£ml¥¹ü>9¯#^£þ¥iˆWfQ.Š1˜¿}*âv†SÙ¹Ì3½Ï`þ¦nåx7Yì;€fDìlbËOwl??GÔéþKªQÇ„8ld“‚Dy—Ÿ¶f¯9ìB ºËhrý…¯tçy˜‹á@á†×ðvÙcaÌðñÍU+ˆ³m"Ÿ:Ÿ’¶ì i–Ê.+g‹Þ÷¸ Ù4kLПնzÉha."Ó±+IZ•B<õݨ„0ªn½Ã(ýNåGÚ3¦$Õä³ 4„„Ce×`“•V¨A=B ²QJ .óx>ºYGüC¿®»…lL’€€œ–.,¢ÊÐÆt¾Œà¤~Ü£‡ýÞ±° Zü´FŠô–Üû·ÉËÒ#øA´ƒ§Ë£_.U×SJž”ŠI€yf¯sǾ}߇i¸lÛqUtœ}Ôm òbX=C™e|{·ßãùF¦4e²ÜR„©fµ& Lh*l(n³HBºëñå}-;¬,‚÷kê|jŽE3Š–¢vÏ\•¯—„›^ðZœ ×6QteSÒh ÍÞS)œ>÷añ‡YëÑSðÙDÀTÜ<ùÍnÓCÖ‘ Øh邌ð_¼AÜ<ôÝQÍÕû¡÷Ì{Êm½ÿ¦zÖ+$‹hùS%¼½POÝQ Q7m#¢Q‘ܸ‰º+ìéæéIJœH¹a0ð3ªýp˜“ Õ‘âZ¿FHªWXq‘¶ÖÈ_­uQŸQ¡)’ì`_ö×Zª%…ÔÙÃ!Yš2C³ùd­pħþ›¨è­®ì86]Ñšìî ÊŒzJ^çxûÐÈS̯ÆSæR^¶?üYr´"IòLNZ;2‹ç©ÎZu3g\-” ËâS$¨ZVÍ‘ûnEÏ Vþ" tél­2VöæZ)²P²{G§‡DÈebä( HÔÁíO÷.k(–7­™ãâóá•[V&ÖœärŸ¯F@ÙxlxŸ¥_ÿ^§ÕW°sßzRUuÚ¥‹ÿ?´:ÉZiÆ%—ÿ™Amd¼Á|‚ŒËômnK¥‡ÞutEzâx<çD@G¸­6šÀÁWÚ„{°+-’€€¼­˜õæ¬0[…•V¹œøÓ¡åfü²àª V¡Ešî.¬-Çìˆc],I÷u÷Q®È œÀD3gœœÁ}YÇeî-öžúTªÕpjO›®=°þ&¢ýúb“%Z(1üÍ{„ Fƒ¨|JZ:ZWÉ~L!wÉotë‚¿‰ëRøvNÌÿ½‘ÍÉ“FbÝœ7S\-wîõÀânFàÐ^ÕžAaø§”'µ¦ûÚBžþäךŠ×>usuñ²oû©Ï増¢B!½ný+(G#厈ÉÙ’æ ™ß IÂÀBydjň¥ÐúXã47˜*Ny[— ޱÿ°õ6æÂî۶ˆáólîUÉïœõQ&_ã¿l‹*ª{^ú¦¼¸"”_ìPÙ„k¼'ËÓ x‰øÏ9)µ Ù‰ŠÚ!Y^‹#Ϋà&×,:z\ÜdÖ‘óy¶Ü<¬ÅýÄrAâ­S6É—<Dz«›ÕI?`±ÊfL #šZp„3ù9Ž;ÐíÚ *ãI÷™ŒIוݥ]Ÿ€i¬â…A"^\¦•oG¾Èv`])`Nº¼ò†MÙ¾7X̰H”û@åüŽî6y}@“ª•ÔTNÝgüÀîUoÊÊ׈C± ¬Ÿ‚˜Oq4IâõK7c-(ÁÏ+ ÖÄy€Zs]?s¶¯MÂÈqXwÂÑýbt)Q¦Àzœ3ŒU§ÜdÝDêV•*XYÇm…Q ŒäÉBÔÆI×fyÏ$wc¯N!C‰AÞß¾ƒ"£ÈNµb8¼*³ÕÓÛŒÇÒ‹]Ôâáä{eÆlú¨ ÓYòq¶/s0{È0U Ň·ý•]œZ¡ßŠ9ë­)”rê¯ó¯:ØœÚ̺§D]`XÔç¦H¥²‚M$mäà˜Ó±#A37\F¼ÔhÖSÙK9òô×`MR¸:¢jBøjÌiž4x4­®FûŽzÕ_%øéÉ$¼"B(”óÖ‡Z’€€ÁQŒ¬ cË£$Ý¥l°ÃCÙüýžÏJ^.¼ùŒ¾¶=jF[>Åó)Œl‚Úh^XãéÄø˜Þ0MÛ²lHA©>Z‚'€Ó…Œh”{¨&ºR¸yµkõ¶K:l¦MíŬÇâây—uZ;Ël4ÉŒh›µ8]ÃHd«~Š7v3`Ž£Oœ‘\a_¿ŽK — ¹!Åô`·L¥_x1 dÁªÝ"ü’Y|½¹WFYtÃçÌûvâ-flմѬûµ™£ô;Dz ­cÛl°@_¹;Š­ic“ÐÈ{Yàè ¯¨ÒµAþá§Œ‰ü“[œò£¦›X‚„uþE+kFOO‘"ŒÐ0ù/²Q4Î2W㫃õÇ¥~Ä.(ˆ;æŠüÝ5Ð \ÖäYÂ.`1â‹û¼zߊÄãÒß,6/õšõ'Œ3 ~˜ ì!÷à ªQ.[@~ˆ*×n™cÅöÔ_4Ô´'t&7EÏLQ5Ÿh©P„TY†f;“hrÙÝ·à~0äì¿6‰íORºÂê÷SÙ_·¢zÍ9Ÿ:"§µìûYð´y~Ù7rÔù¥ÎT¦Ñ9~ ±»P×á%°zªªqh¹i„ÄÞB7¥.Çô¼È0h}éÞÔ]ðž‚Ýê_¡ µeí’m§^èXã¾e!ÚaÙ-ˆQÔËlzÌÑ. åYe~0Q íhÎWþuª2O+þ/8¶ôCˆ3 ~K²AŸáÂÌéâïOy3ƒÐÒ\É ÷ÛuÏöï5¶b@;[‡dîBǪËTLnƨ|ÒÓ·ûHˆ_Wÿ¼ņ%|šúáw/=µ–ôžûr>\.kZüµëôSÏïÈ42Ïr’ô½²xËoV\؃’€€Ë û}û_¼û†ó2Ê8•Ô("cqÔ–¯$üFÚî2F›„A{ó:K>¤‡’mm³ã=…ATRS9JŸÁ¬ÀüG+Óh=” Ò„#;‹[®!íaoÙfï¯ÅÀaöXF9‰)[|<ÑH¦Y¦\R™«}Á›N&FQ $ž`kø|I[´9 Î¼cè.ŒI¼°ÿG爤Ôî:‹™ŸÜhš V 7yàl/v»o›sŸú-¥3¬‹Êbƒ×£³µ47Ýv.–Ç:Ä®²-{ÑTx tƒ² Ý™Nx4š8†.`àT q6¿|îoÁŸ>Fïgû<ùÊQ›É—¢²ÄY½~CJŽ{‘–¯šz0¹dŠ8tú©k‡ ¢-Àô9kJ儞v 5ó áÊÊGB[„¶3a¬h‹ó²×ä© 7êðg+³o‘Ñ;8ôÖª¬6lëXö©rx†Ûèé‹s’E*´—{Œ²ZNüË0¨’íWÁÅË;¡e‚È¥‡hÜ<Õ&Ù+‚ (.]­T0ìõ"×ܳW÷"4e…ë‰ÆípÓ‘é¶zƒNc V`À:¬«1_ Ï\Uâé¯ÿ’;FÈ 4þ4NR|Ð+LvuŒpsc[l1N«úÌ85¾ Ê$FAnœcDžUOVG\"¡(ÚÊ¡ùÀè€2Ó"è¡Ã\ƒ%Ûjšï¢p¨ùÂí$ZÆ‘Ž¢-ÕTáLÉê¶ÖX†(ðÅ7Ÿ)Rgb›*@c?pþ¤1·bq˜ 9¨µI™Ç2àowŸ~×6r)¹·X}S 3ê©Ò@èìê<»Ãôöv1]Eú naq¬9ЮP£²;*¶Ì½gÇSŸ¥N¡4¨Ôî–¿¾âÖ!VÙF›Ñõ§¢ö–#U\Ð~#¦ÎEÜG#ì“ %âÓÛGgøÔz¬MåšÅ ½ãµ”ŽÔòS~/IÂMï˜$Z;Ú98!<Úñ”éaˆ.ðq$í4;1þªº1>ÙDá>í"ðDßÎ=Ôo(Zg­²Aƒrt!Oa&²µôAC+´A\œ¿ëqšW)`y«ÚÝëòMEYÀëòaèj¶Ê°ò«°œ¶L·Ò¨ØXñÁÃenâ36eLZÈj1ÉX—x¸l¯½–BŠRóGY±e—Ù¼Að«k $¶[ý’€€Æ)Â%ïDz[®Õ¶\Uù}öÅ&–¤7×t×&²J ¯±–?þlØÃc&:~ñ°Iržk²€´)pLd¹.šË ¸®!ò0ˆ8n~!ú·šÄeý“±rC¼ºñ+C¸Eq1¯²—JÒ äA#ê\Ë©8]¨ÍödhC[ør~´™P¢œœO°­hKÔÒJ·Vc•bÐ+¢ƒ¤¼ŽÓ^tç©È¹"±_ÜöXS€ˆAvÀ$?Ã¥À×c´,ÆçÉ%£¥h'–ê=‰E¤i³FŸ¾D¶«Yè-ÃíáÔýçnÚb9¹#|•cšè„«J\söÁCýw†Â·÷‹M4¡Ù(=pƒž Â>¬Îm£ñƒY;)Ï·[|©'¡i³ñÀà~2̣ƽîdV˜AUÈçÞ,äÕpïlqeòcЦªMÖ, šôAÉ_å`)Klj£BxoI¼i?¦Í-òE#~DÔe¦Eû.CÃÈw”\'¨§ƒ‰ô‡ùl­À0ÄÇZ'bZ`;³Ï„BíéaÓJög®g*×HÓß÷¨bwä%7wú.¡ÛÕ5–àe<ÕaðÂ!¢aXB“I'TžáA?欼(Ö8}24ôêi.­[•K&ËKå>NõÖâ³x; ôŸòy!õM¢!÷´~Uÿ;+]îGi êÄT¬©RBd|p¸Ýé¹öQ9„2K'ƒK¹vöI¥‚ôo‚1âZ_wb?’½Ìð7ÿôD ÊšÅñ`IÑ. õå¼þZ¬GæBqK 'ÂH!\×¥¯=KånDM)!©œ*ÚÞm¿NMWQês×µLé97ÌÌŽ?ÑMï«[‘›Á&Á)›iÕ.yË¿"“?¤¨žáBhZœ‘v&˜àÿsXÏ’$± &3ó¿D‰$¢-Õ7É‹pŒnïÈJgÞ€a¬m'kéš7ú_°/ÆÙzFu«.b»,ÅeÏd?2_`=$w%aÀÞDmuNMt+½²óÝÉ ürH#zt ´ÂîÓ¿äæõ&rÁ©xšG‹Åüb^¯Q¢h<i_—F5ìG(5©m"ÙaqêÝ骽à¯×ªÃÈØÒˆžô?y$NÄ_g™ÿ˜£ÃæMI³‰T†ÝœÂ6w8Ñ_¶”74 ‚‡45:ûW’€€Ùxª%VÜx,-™ÙGíüßf¶çüGð JÈ·AÍ3ѼÝâôÒʉÔuQUÆpæ'²0'ŒuíAp‹ºUlþ‚>š¶å0‚t_„òvw=¤è3r@P’úr„c㇟7Z±³\.Ó€€oK«‹l©ìŠ J¡–ší߸a[_Òèzœ©þD|jÍ¢~<›¤H€àë¶¹N#VAWpƒH_¯„/b^ >F‹ã2!á&ü7‰o¡Êèmx²{L ÕQ¶Æ«j ôT/o 'ƒPf@ÇoíjëÂ#H¸µ-ª¾%…ÜÝU÷}·qï1‘\«‰-ب^FÚ ºwx•=š 7HipZ§äÍ’ƒ÷Ì'¿VŒMýŠt­"S»†Íé>E8QvªY0×Àtß¼¸‚œØÊŠäô±1×¼èWÀKa…Ãz·H©åù»"ÒÜÔ` ÐUô&(Ì)cH£«ÔüE¬S_? ë*'aA.E–†@nàm€³‡}­kÅä¤ ùWÃDç½e¸Ýw¹‹é¥ÍöE‡’¶…›ôRôÎ"Œò ®q¯’oEÕ|x*èÍÊËÜKÄgWô][Ä;F`Xs¢-IM€ë^îD_~«u±¹k‚Áöš+¸%Î$ýãØ¿ý¬/ñýNeþŒ=´Ó]P,ýÙ‚vž£ ’ÑÅ•É1_ÚB‹JyöÄü 1”c–²i¬ouº ’5ÝÉyµ*€œ¾Ä¸ÇêµÃH6%\¤f1¶惋Í™àXîzzBdäÈ–šhK¶K´FÃÜÅú¿˜#Ḭ̈ê:К6Ίg¿ÛȵŽW;ñ”—DÙ¼‰“*¾FFÖ,{ã#Žx¬Õ(ie¸5ÿCªåÄ“¨ÀK(xû:÷›×B/Cnkf—cèbTRåÕH›êÆU%¬©Àaˆ™’;/ÌÑîrÝð2¨@#_5\ æèœ©ÿ&Ðl›#¨ÌÇïÑ·•ö4TƒdºB4; ­ÂO¹3`î;ƒ.ýâ^+ w¿~Pøy]8\׆_oÒ(Ð9ù£x ¬K«„,á®Ì….±>æ›á€&ËëÙŽ±#ä%ü9MÉòœfÄhI„ÔjmÀÀþ¬€'­p7Û弋=¯_£KËè)±Ô–Æ·’€€Ô< kèôdÓ›Ý_!^ƒìãJJe,°°‹gÒº>&s2ª5zÍîŒùl<³G¥,]h@kÆd3Y©[ ž}+³PÍk¡¾P?ç3vT±®ñº€Ü]hkl]t¾_e•ÔnMÙäˆÆ® O¹ig¼ÙÄÝâõŠûöBìÔ“ÌãvÐ †9Ü89Ç‘¦ü[–Ÿ¦üílãÁ’Mœ0J>U§=ÿ²ùA&¦'r×:éû³é®ÃrúR;±XM†ŒÇcÓqv°1ekôjY[SÙ,ÐÏp‹Qÿëžî=šˆÖ`ÿÐë;IÁµ•­×®‡Øž–ξZÑÖcÃÃP¸ç¸\½z9âaYƒ¨•äìm*òq©áäćW‡§Þ3ÝÄs)âwî±¾« †eÞ×B”\Q3äTlÖ|¯ê"Ø…‹>9HÚµ0 åÙÛ¾¤Y»O Êew ˜©›|áYÄlUyPÜ ª<×µ÷¢±XÆ' 0/]ð¨ÿàÀ3¯¬Ï>|éÀžZ$§Ý‡Öíè]ćKL3.€ÛèÓ9¼Ÿjƒþƒ‚÷›=Ÿ…¬¸§Ûä?Zƒ\ÒÏ\2„2÷]š !Æq¡ÞvŽ/KCrÄÚ•…ƒ§ŸÖ0I@دVÐåX/Æ™m—±œÄ£zÝûÕÓß»¡Ï<‹_Î;ãë¥Ùïòhw§.§Ë¡ß7¤jÐ¬æø Æ”!ï ô)¥ùKߊ8Z^ȵ÷Õ”0ƒÀ}6¶ˆØ€FlÇ<í@µÔë*ÈEVû’ÞüÑËõˆ869 |¤‚úe-­ÛU…y QÑá¦k'¿ªÌm&²Ô¶šŒS-LÍ’Ó`b,à"uøt‰µÇCµ8ÿ-QÞ02„Ï-¢a‚¾ÚžG¾Ô>¿iIÓJR›s:õÈó]±¸7ÚŽ„r—]Í„÷€.¡!=9Eæt@ÄèXt)³"/f¦• {n Ü~˜œ®`‚§„ö,î²{ûøÏ%Þ(œÁ7gß|s•Î \½à½·ªŽ$¯²h5KðÄ+<Û–”¦:<$ÙÖÜYØŽÈÅl\“¨ê%!zÛq\’²– V¦µo„Má¾<‘ážFz³µSžŒÏøÒ…«î†O©câ(\XÀ¨ëÁ¬‡ÞƒÞÖãÕ)7}Õbß Cþl°ɜþy§ŒÄ8E¾’€€Ä×;k°eΠ]S¨äfj½6u¦¾‡/AhO{SBD>j-0+l°ÌIeݘa Î¦ýQ­7‡ìnó•úî\ÓÏØý³ûràT_`Ïd?jbcûˆ4sg_ö:êA؉PEo—pç§€—'ÊCgCˆ#wZáunÀWÚ›\²£¬¢vCÎ¥ÞR–{ˆ2ÔHÜOoÈçì8`ãyÌCþ$×€ê -‰4wÝHÐïMýF#-f-–µ=¸H©48‰ CõS—'užvL„{{-»r»ÍADmÏŒÜWýûöµbÛ ã­:‹ÁÃڋ¦-ÇcçTŽEÒ4ë‚(ÿ7ïÒARêè/ô»= z{aì}ßdaäF<–ÈŒˆÖž;­uûbÎ0é vˆ±:3C‹’’ŸË²¶4Çt¾d çßzf•r' Ê=* j@Æzâ aÝ9ƒªðuðrì§AÇžÊMK»¦Ñ;ðf6ËCA3ñLýtü  †1GùRn£leäÝÒýµ7Z¹$ØöbnÇ" ÎÎÖXÊå†Ù¬fNWjýÔL›k㺊ºäV $SÆæê¿°KuˆÖ!^šŸÞ cFg F?~T,äJßãöÙ“ŸØdÅvXÖÇXv‡Y×ÖI¦ìG=v^È´‡ëް¯Mì²+íôÆ™‡Õ‹ÏºkÝnÝñRcyƒ‡”+j ÕÆŸ øAs“ÂW td4œRŠ'[ogJÞÝâ´ o^FÀ>±$Ý_O:…Ô= ØÇPÀÞ¨ ÏŽ%‘6ÏÃ[´cà¸?ò]Ý$n*QFB€0ñ@p#\ÄU]Õu«o“ã¬9 lFx‡¿¡+—ý¹T›Ïe²£ï¾U³vø›d’PÿÌ/²kjêg•Óê!G ܤ@À!E;îÀ˜$2vþ4Kg˜²7‰QþKçN=à Øèºúå²Ð´¾¡WV`ØÓÂüc·ž®û'Š¡Åjé»"Ãf±ÞŒð>4®U’xS¬ì`ÛÎÞ]èŸ}6½óGX%5oL€ÊGB}ª:øa½æ«;ÆûŪ¥b†Ð$EN)Š—¯žH5æâÍk¨úZX¡„êŸÓ²gžÈuåUKÌ:‰™§õcQ±~"‰e’€€¢Ú~9áFœÆ¹‰BòØŸ×ö/þup±ãzØÑ’öG.ºø]«øÆõýfZ`:&4b1›3²Ý¨ã›Õó彊Ÿ…iGŽúŽMÿ:Y¥€4¿—æ"©Z˜À‡¿Cò½}†»‚Pm>Œ]F烓 ÷¶R@ÈœÐEˆ‘þ»d¤L7ò¤3ßë”äÑô„5d²¯ŸÍŽGä·)q Âo·¸@Ê}ØNèE›•A-Þ…1K5Ö~jšC À\ëŸs°ýèR:üÕ~Þ!}DìîQ}XWäs*¼«íÔÐLAQß»²Sø]F[ÆîB·èʺ_x<Æ´á9æòܾóÙ˯-yã>ÒùÉÔ€Þt 5r¨l&ÛýÁ?¡Úúä;™E¥˜ïjž6hý5v˜p0WZ¬ior†8’û:”­p*AQÁl;I.¨Ü]‹\3·Ð·Ý;€ŠOüá@Šp–˜­‹§˜ö†µÐïÉ=‚þêðç höÄÌùÊÒˆ¿ÀÛƒÄ?ì‹´Ô:ÉáÏÚOâbì¹k©=d¨µyXŒGpë<0TÕîØhÑ MöBGÛ„qXüÜÇ”ÌÉqÔÀNÜd•ýøjû´(Ÿ¡•@Ÿ2Ù,få ‰uUóùŠ^1ûmÆ~a6ŠîD ¹qeõùIòÛQÍ-DRC –„ǦóIÝÙïÑèÛ¤÷qȱ¥[í•QpJºíð&ÈWäjµC-¶ºÈÞ5ŠXרz¬¢8ÐÙnÒ„ä¯Un"¤3<_œ+!0×  •€©·Njø™;3ÜŽõü1Å#îÿc&Ne¿ýà·îU™Û á‰i•Ë1h 4òš) À²D·qô!7ùЮ”DH2«º&YÛ¦h9ª/‹?ÐM•xíåGÍ'L¬¯Ûz¸HU /a‰Ñ·Ñh¡Ÿ†\ ðI)–¹|"è7õ–(™W…=³¥ÜÝ©†Ý˜Od*UËëNßÑ_ä¡+dµªô%ñ}ã°½ŽÒ—Î"ŒÔ"ÿF²t…å¥Îêà<ÇQÖàÌ/ûŽI83‡$½&¹Çñíß ü¥Ýbk¡¥ðK‡Ǿߣ'F^-Î\ðkÙ¥w§ØN]º”Ž ¦äz7¾¬ÄÎt$@¨gFÓ´®ŠÅäºZr ÒHÞl2Z±¾=è’€€Èh¶¦¼[S-.}…}SÁ»óÂswËâ¿5®Ñý(ʈ½ú^TáTÁƒÛñŸåED|ØÃÖE¬SJÁ™GxSH×ë9ýçC EI,w£ÞmÝ2Ìœ< jɬ#ÚY£E a¦."UÓ››êy/*’4Õ¶¹öµHLò\F VÜ2D´.ØÌÍ7úû—:¸bÁ'c©d9Fd—.rG?Xz¤çü¢bPd¬Ü›Ì±s‹ÅäŒ[Ô»5U¿éçÄ0F ÁB¥µÌ”Š…/ì èEé)ï¤;ÕDöÆ$‘E? Có†æŸ¾Ö(ìSuÅrõ‘⠵ܙúËÓÌ ¶Æº©«Iz SŽzÜÆ…ç  ;ü'î%QŒµ¿ÒŸŽ”D/XÕá·uYðš?þ¡Œ¡ºaôK,ø€líã–¡Ø'ôšH½Jz“Å‚úd[>Àz® må»åµX0¢½U¹ Ҡɤ„!e2Çi’€€ÖŠ_u°û³·£ý9 „šžr†/ ë9è„.òBI$ÝXsµVB˜Xû² yæÞ{@ë'Ut¡ âxE†`aêžø¯ë˜êñÛä3¸yÞÀÈT5È… Å-ƒ÷†2„ÀÜŒ9²Ñ Ç\À¹ÁA–Ľ^t°¾ º¨moTÉOé@?UAÝ.eõá?w4v²\ ðbZ~^ÁƒØàZr ‚Ù QØŽÚzóDM‡èxl;õý6=‹êÀ;³ öÍâB‚)E/Ï*Ä m—@+g2K€i;®g´×Ç£D<'¹p‡€‚ô2ºß…’:'(\7$·¬ÉV+Ivµ¿7Ž8çw”rÒÂdJÕWÂ%ǨzËý'„‘Õðe2 ãGo'R ÑF4*&®Ö‰Õx`öïAßÈÝÇ´Ä8Xj¸Ýˆ ½¬8YêñïÚ¢KqJ}(4º«u纑>ô¦î‰UåwÑ`Ò›ïã½[ÿ¬͹†£B[é;÷€ qŒgÓ|!²\Xô¯bY]¢@W}—¶‰ÛŠ8Žl8i–µ”¼#ÞØÉì]êH·8Óßõ…ª‡SWhÔòÉkß¶„ª–—PÛ(,5L¸Š@÷?dÃ4Æ3ŒJÁ7¶ž—sÖ@hHð0â±ÓÈYÑ›FWkç–äß<ÕTÄýÿcCó¬gHÖê:V½=}ÂjÃZ¶ñ6ˆ-B%ñZ#ðý5¸b1b N}ö:œÿ«#ä$@°1Ô¥Õ­Æ÷ øÃ´º VpåwàY¦gßÍdÓ\þ4"n&Àlf‘3-®’\Ӄ›×û–œϰˆËx&ï˜~=›Xs)›Ù’XCö¦ ó^ˆY@ׂÖc# A¦'úõN¤§Í÷Qnk‘¡Zp5f¡úÈî0·ß=UøˆÔ´Üù·ñÌÝe8°éhN«H!y0máy†)扌Ž;öʼÐ,ÃʤëWžYÃNÓ~`¶ÀR‘(høkb±^þ¬äbÇa*Üö:”ð¼ëBšaR”±BÈ„•ïá™OWVrL~p.Ý`[oïR-žéèÑïÖ¬!¤¬%*Vy›‚¯Xç­šá—Ó¬Û‚S×C«‚{ÖÇЊ®m‹J®:&,¥3œ †¯†‹Eß$H÷¾ÝJYJÇë¦Ma¼Þƒ’€€®¬gX]›ÍÖŽmÐckȦK^Eîð‚£Ñb÷üÄ¡[þîî0¶–Þße=ööX–½ÿÜXdu1%žŽdœL‹Þt¹Œ¸¡YzÈ\W“lcý¦š’ì®®z^ÞÌÎeê]õ[®5ïéðcÚâEé©ü“J]kC—»K¡&ýÖD­°švÂzÆo~9©ŸyÅ®FÃ@•)sf/ž6ºY«éœ¥4¨‹àÍuë;¸Še~¨ù©ó”ƒh锿;|jÃ}Vº2½ð¬ŒžOåŒk_»A©z”/î“«ìÇ-H!—¿À½š!qÿZÑ߬ñZùÜàƒ9¼Lñ^Ûë)‘Æw3^Ò0™0ÕwÀp´*ÑŽÕ°,*‡ -z+)ì@_¸Gä¸Ú%¥ÄHÍ'Vâ”Tü$#D Ê5¢Ù—E|™³Á\Yk†l¢•»n„ª¢ ºÛ$Ì‹ôúI‡ªÌš¼â»ìÀ×hDÅQäzæÉ  -@BïNcú’á´1÷šKjã. n/H.ëP»†’hã!0ú&œÆñgî3ûãŒìÌ ¤Wüé|z:;Ÿå¨l'´¢%C2¶,^ƹõé©âLs ¿7?/^C$ŠB‰ÂÎÆ7?«\4ÎôŸm BL~¦Óy$:Íâ‚jr£m¼¡ú1H•ÞúšÙú2,Êoã)˜zÝ]Al5Ør[]ë ŠÊ±×ûqK×å°ý¾ÒçÜÂQŠè8ˆ¨#šªyÏb‚±U­¨gS´ƒêŽÿxæK€K'Áê®ýŠP{Dýifá ¥@þ¥ÿVsôüû·Ï‹ÅJóAè_uú4Ré C.=Ç-mFÁgɃn†ØµÿOmJIelzxÿ6.ooVgy ÇYʃ9y)fº]M>Ú?C¬q‹ !iì£ðóÆSiÙ®‹%k³¿ÝIcn³èn¯O[<äFeÝ/vrCµ âRDÿN—÷½·\¿°]-ú6Øòì¡QöÄd®(Y9âh—ýºjý\Á&ÿˆMÁüh²ÆŽÓœ!Öº1zyð\…»w„Ýåùì'Ö=»­³ò³æ“¯ bl8kgE4•ÿµ%×ìx ð¶¢½=çÛ$Žÿv]OL¥ÿR¯¹Œôñ¦–Ìú’€€ÉÑÌÿá Ÿ,=zvÝÂhôy¼b@ ÂòæçQÌÛîoßÔü! ·L&Â=H:ü:äëTÙE QA=%á"j£º©. Q£|¹(®,YØ@¨ÍÄAÞ?Añê_¤¾ ƒ¡3Sýèø¿&I1S®>É)ùÇ€ð³)lóq £+AÕ¹¿:A¶m6Ñ…º–·<,Å¿˜ö:þ`Ũ;»778µKG`ðG¥µ6¿ZG˜˜*›ZÙ¶± ¢ÀJA;t ÈêIÞ­Ü*;`P"ªÙ‰d¼¥¿¹ßÉ'b_$h¿œ3ë‘vŠ›·5Ê13ƒ°øîk¥HÍͧÞ8^å«ÇLõ[ÕQ!Í"f{ÞŸö£z"š¯-sˆƒÔ¸—Ô\ééÅÂÁãÔVÐ>þw"ro2ã—”Ú>ÜÔ“ìBéær:ú °/qEú›#½ÔØ"B†:d`Ø¢”·‡£ù¨¿¤”’ Žªz‘sV¾ïÄDÝÐA]YFOŒ)>ù}!ó‚K•¿/oΉHWyÒ?£0ö%ì—Ê»C±z›—ÈNÛp•‘öf=ØÕq¡äùàiÝÏõ¼åøËÇÔ_e´°‘ã â–ô¶D¢SWå&ž4Mbôù·ì›§ëA)ÑiŠÊÅÍJÍÆjUZ¸ºu&— §„æQëæ¥ Sià -~6ómzbò»)FkÒͺq6ä©ÊÍ7í*©,»«ß*Âl¯á;åñ–ÆST3ÔaôψŎ߂``Á3:ŽãZCµ™˜PËÊ«_9ÂÌ÷3Z9N1¥Š„ „Њ+ò=‹JÎ}“û‘«bu3·;*¥ÛÉã:”Ààgáé¤ÒÈû}°ClŸÂùäÚ×¹ÜI5DŶPPßGíiËç=\³·M·Ÿ“ÄX1}9 õ¥f×G{—w#ZÛ¸lÖNƒ¦]©ÙJ5³*íÓùÆt.`Œ‘h‰åÓÌIZ_½h@z€e1¸;‹9ö9À½î ‚ºŒ¬û|îF'7&mYÉ8¶´¸¨¼R\EQôË£°Ü.ú”ùa†ñ 2 •ÌûlÔx_Ú ý=ÇH¡;mÈŒ ç¶†&w.÷˜¡w†€(¡Éצr'ŒEšš ²Ð1|(稼Üßë‘õ¶gqd=†§“È5ÉxFIö€Â"^À“ˆäÁ7ÒÉ×ÿÒAÂL¶ ¸È«dgýYÅ»Ø`<ðO„Åóúóå¥I´M*)§pŸ[ð <¹çÆ‘zÁFÓ*K¿ÃàÛY¸\œ[í©Yu¡FdÂ&æXr‰àþfÖp©?fÛVqÄÀÒ¾|žÛѪŒ‚‡.ÎZµ 9t‚‚À¡°ªÌ;ò|Hº{Q‹=(U‡£WÚñ¢Ñ½&± öU:m˜âbyņáðž~ÑêÛ'õ²¤Ì¼ Üþ›@«oDätµ~•­£‘áÉ^²º¥¤…X1Ý‹?A3ñA}¬t4 Ø»†½Iä·‰°ÕOT¶³ÿÇ8²Sú*øöN¦àM Mò#Ñ&ù¤k]I}ŸŒ9ëó?õ2®so‘˜ôuÑ G»ôÏý}ìu·ßVÒÓež[Ç-°ŠMU~~½¿1Ä!´V8…tý o‡öã5M \n¦â¤ï,J<„Óz?£Ù&FÚ½ àÚHP2cóUdæ ºÐì,n±zéžJ¬ýN<âaaa{’ŽÔÖ÷¯.GñÄü#];¥Ø¹£yÞâfâzRÇàÈ3gäêm˜V„«ßŒ»¦y+ ß£]{0d•²â©UÓ‘ñ¼¾Â×n¿ä׊ìBÀ <é°Œ+‰’éOjFÅ"©Á\oÖ]Ǽb”&ÃOÒ¹Bùá,‰ØO»SâK8] ’) ßéºVeõß@;¶IŠ bª )I}—<¬øO¾u< PÆGÜÊYR¾3‹¸\{Â{¥ur¿ÏiÿTõ’€€¸ÒLÚ T³A…ÿ’d5JØ¥=|îé« d•\YQà>!b3ƒÍÇ{‰•-[~Q°eZ8ðØúvæ5ÈìØÉíïþâl¤Sm'¿l…âe¾>,ó2Ó)9:ØV3á嵄à~M8ÇÔz÷¨þƒ,N÷t$„LœÇu Ì¨ø©¦ ™t€OÔb )¤LÐ<Ž¥¶ž8â@lÝFb€ Cʼnºa]9æšda ÿc“vT ˜Êøœìš¯§ö Ã÷€Ün XÞöÊõ㽟GãÛº¹„vÔÒ4d¢í¶@ûù¢Áç!×h¯ -¨…š’d ù»'t~‹9’é®)ÙHuÃèY`žO”2Ùñw£×PŸö. +« ÓƒµÙo;ÉâÑ5צ,͉QÇ&¾ÔDqäíIþ¼—m›pŒ.4])2yW`£mMðÀy¨LEÕâÊÔÌz1Dç(Tüè?Ev¦O옘0¿’¦ÛQb¤Ö ±¼ÃÁT²ÕÜLðÝ&E>ÕÝpÂ_«†Oâä*Ž~L¾áüIü×ÎùUㇷU'¢êi(;g3ˆ—¥=A÷øÃF)’RXõξ»YÊÊÞ½>“hXÇ“Ö]Ël%П¹Opðîÿ|gB:±zp»€„·_BýÜìÕ4¡ï  K8$XKkõfŽ–5õP÷•äC‚Œ­°ÊÆQpÓ/†=8.3ÂÁÀ• Yj;q~Qh…öà ЊÖYɤq£¡ô€->«=NÖòÐu´Ñvþòn+ã¦phò–Pl¹RÄ¿ñàõâ!›b»‘Jè¨3ÀÅð‚4 Öµ™Áï°—håíHvœqY ^å'ŸåccIÉUxø`*ÄqϪ>¢®ã4²‰%{GkÈ…4®5 m  H¡/¡oªÐÔ@Þ·^"bgHºÞqL¥:ªË¯èPý§ð=&#’€€Íž@¼’[ƒ°[®®úâ/èÝA3ñ\;ÒB¸ñ¯d\¥G!SuPJ•QA‚çZrž£›HÃäŸÒ=‹ ˆý\ˆqb¶9!ar^1A•pqöµ-ÔfVU¤yÎ\ñ¡ú x¯­dò<´SÖEŒú|Š. ëõòÇ)G¿ßÏÞàƒ 6ÆT '-¬ntH”ëDk5:‰Ì‰ ˜i@óNüsm 2ñÉÙÕ<Àòʬ×Oú%B_ôD¡ãr$|=!Þ S%ÅNÃaPÔ‰éÅGì!¨â›" @*4<¡×oƒä=H "ˆ£û‘̸ QíL8%ÏÑez¢‘¿5u˜Ó‘ÛŠ¹,C)žžœ©v "‡GTï±ßÇröñ‚E=yÞòʦ߻ÞcAîp$C!˧[KaÞãX:¸­,6‚̳.[ðþûÅ¢ÐPT¨6â¡Fˆ‡Åï!ð.‹’È^üæ7TÒ ‰Td÷ áš^ËVkˆËizÄ*Æôì< [i1n§/ïóøâì—o7† ,I;VëuŠ5I3Kºsðv.z}µQ‹«…†‹æJn:f‘A*hÍ‹0ÊÔœŸO%|ú ÚßlGR.7)Ê÷¯œû7c[ü_¬|êl€DÞužÐ žûÆë¿cvY7—k3¼°8¸ONkë'qŸÆ#•jµ‘R¼“oãÀê6+þD‘„“R®ëÄ">0|ªµ^ƒáuÿ´1ÖÄø Ìâ]9¯ˆzvÌmb¦‚Ƀ©Hß/sP×ëŸô¼s¥"zN&nM²îl}¸„ EN†¢üEB+º|x\—Ç-úÍ“»ß؆þãY5StÄHìÔ¸57Öî]€$žòEè‘üóQÓ½²INEÙd-({HkújºÒµI²ÎU$F™‰ÅÂYäq'$³J šŸ{Ñ•hrÍÐäy¥Ë/‹×óø±¿i¿ºÆêâÝF-Ö~TÝlç e¥+ÏP#Vù#ãæ—Œí7É@ô¼3rlÎÿúßÃl{4ÈŽI+¼ÞѤ`Šõ`kÁbËé{íûw¸tO«ztÖ›ZØ¡°W–-’‘T5& Íû<ÇÏòlNÕoÁ&Nûßøå"@5JEm‘ê4 Þ9/~oZjÔ+¬²è\X–(’€€Â±’»8²,´Ò^#H‹å âTDdñ½e•¡ÄáYx4k²ËaäÇAšúþÀ~ïíùéì8ƒ :²±Ó<µJŽå~.«fvYtn<Ÿfn$xÿ0%£¾ÊÇåY&Ïç Ýzíu$Aß<¤Áv7ë‘Àå/ÝÞàgO«BV­¼¬±‘gÙTôU°€yŽ--¼ûžrËéPä@ h[P„8è–zíàMF}ùWĪžSzx« °êPwQ؇Ч`±HDt+\F ‡{~t¡»üÜkÒ5¤Äñ^á\YîÙ3+Ëã8¥…¿Ñýx|9̽»ûrØa×’ëf’ù /y™„Šåx—ÞÖ•:eÓhÏnNøúQdäŽ™Š²\=‘¶‹w~q‰âŒVùäþ'NåjÂru±üòñš†¹\Ë9`]NŠZÚÿ3Æ”h;}!êÏ(LöLÉ^i÷qèÎíëìL„ŒwF,RÙ~ ’- ‰05ÒtÎ à"§øë¸ùèt5ŽÔ9þ'\Å&uOÙav0©=Â#׈ÇúòhüDÀ¥4Ù Å-ÔgË~å©+´Ëä n^„Ìû=|ô:ZºCת#4ðo‰Ð뛑ÅTÐY‹ƒªår—ÇåeÐ.ÃW£f×Ïճ澼9\5(l°þ‘Yþ¬œ‚QóñD­µ¡ 4 od5^nÕWÙ=&CÌÙZ£7Fr2üwÚå"àüä%þ¶Ýˆ5·'G@dü|¨•ÚT:Eø×Ž&:ܘк1JŽ‚|¦«%hÕm”ÛA›~Ýi3ÿ´ùÊF's™Pœe°Òôà9õTŽ)ÀâywRî«G٩Ε^ rÛa±èÃãÓ™€~¡´6Åî'P èðW.ÆûRä+yÒ‚ŵڹ˜SÜ­ÁD»k7åþáSZ$%òI¯½pWÛp§Ô#éÏ`§u°QC€ ,âV[³¥?•øÏg}G}Æ–‡(/dt‰UAï ÿ/ß¶œ$Ÿ‰Ñ0uæú½è<“¢Ó±PœÒ(Є³fº¦ÂjûäãŠY0Û¹d³cVY0Xwüe8U¢€eüškĆçU2>1äÌíQq66­T&êA&;à|䱤ÿ²%ÿ‰ò²|Íwp’æ0X2yñÑ1Rû«ëg€sþ)Cwað8€ldôÁŽ;*lz vy[GeT¢—«·íÄfŠÁ+IpùÏòÛÈçŽ[Â!`$!öX_ãÆ®ìªv';”êéKœvØ©Jó×7I×[MÔ1<›}y‹–åPô1ªYÌ=K5,!çä·Ygɯ6y:]¯Kj¡h©×pÏòºI<M²ž â“ —¹tñÆ‘lÿS…VXÓdªêðÆ:ΑºÕÙ7ín®€F/dÉ“äÞÌx°ÆÝ\_Ÿžé­ø[¿8Ë2î<*pê0+å°‚Õ Í¡9ÇÇ’ð7Æäiwˆ],o3Mú¥ê¤(»îÁ!ï² ’€€œ |¯ø=6 ¬Ç¶U†Žê[ùa“çeIËÄRƒm-(ͼ¹!]ƒ+é'$%œª ¡ °;ÿ‚ôSÍÀ_ÃlT¢óÍC)mE³Îöªùé£üx™l:êÏ­Ãh`Y›ò# Ó¼»"£l™³ qöj±\˜‹ç÷ÙiHýÔz–BqûÚ ÞDõóíLfÞ§-c¤üJo*‡Žè! ƒ~›7@œ¤5ŽP>2±%=€B í¨¿<€ùQ±áRuº§|ÈzDh]通@ðʹObC¦vàIkäÕ KùJP8,ß ¶¥k–år—…‰ÄIÏsþ›´6+.x˼s5¿ßq©,ÆbË­[Þñ¤sB¢ªÙ*ö¹K€6›â’¾D¬Ÿƒ‚ìQÊÐOn‘w\|1èß!‡Bs¸ysJ`4Bµ²e›Fƒo3@Rõ€*mdá¶ò+ïuÏ;¥¡àå¤F¶Û2bìZÚCS__R'W³o)͘)B 0J‚¹¤ !‡]Ó«B8hÎr_6äb%ˆ‚*8CV×B\jÃk8° {±*Yª~k§O”uf‡Xzÿ ”àTÿ¢í² ﺢ–ÝéÛ#ÎL(kìòÏÊØKÓvM^$²½#ß]}ã®'ç&R`Ïž@°½¢ú3`Õ>€¦¬nRD‹ºÔñ·Í +üç59(©Ëí¿67Ùð¤m7ÒêMÛˆ`ê¼¹ÏÙË’¨Ì¾Æ—ÐÖ~©eD€œm™„ Q[/©cÉVã .Uªã>)Ž?¶T˜™ÜHä8G¸éš˜Ü› =/¼ìÑ5³­ëœÚëÒÜ"ÕZ°â‘vVå$ÂàH >Ñ5É:âüÄŒØI†R–U$¯à, !¼š¡Râ;:õOûÉxvG|\­¶ƒ/ä¯Ãê¡dÈ•÷ýàþ›5ácÚ²U€ÒïVÔ›üP#¨‘Þß$:Èc €Ù•¶Lop÷KUÊH§ÞýðöP7iÎOÅxÀîÏlPÊŸàL9GÅ.r”à)¡¸?ìµ¥â`ú”Þ{ < îG[¹$^§¬Ü멺¤å—q|J¬FEþe_¿œMÂ(Y§QjI›LàL C¦“ü`„ŒzX§%z8£ÜË’¨ø˜©î¶¯1kÿþŒ‘ˆòý#‚¹qm2¿&¡Z‘¥V^"±…©Ì¿ Êß®Iˆ#’:X=$m ø‡‰,ÓØœb謕ÛÒ:“PepùXåêþ´Nåa-¨C—©_Ľi¢6|„<Ã*œ'4:/KaMfÊ‘¯o 4kàéû>Øìé¨Ðfw0 ãþÑí÷dY |W™UVžmÑ{Ó *îc/ÉV $ÕÊZ²éëeú)¸+¶¬*ÎÖÊú4Ê—ßjÕM)¡Ž¤›21;`ýAÞÊÆ×ûïoK´j|Æ¡½JÚDu‡í}OÐK7g=eÕÇ~æ·ýú"Í/ØI;¤¶¯n{éøR l01õÂw”ãͧ›èÖ8 Ím˜Bì<“rO„e©",'–¶v³K*U¢b¤éïÇÍV¼hü\–¶ˆ¶BÇÒƒjÃVt÷Â1`ì]Í+Lüh‘Cî{>Œ˜(¤H]—º §j­fÅ5§ÖÄq {·¡nªÓQá=Ä$ÊšªÛ„øË0Ã`¢í² ’€€Ý5޳•‚”/Þñ–@*?NÖAp¼[¾§.þ(Œ„\Ô÷Ô›t—¢÷9âìÇJøÞ.*#\R:¬u— " —¨X)” 8É8wp=7îíHl{²Ç‚ÀIÚJË"êó¸$ãn‚TïFª·óyúº›ØUHTŽdYL©–B#â«ì—öâ³€È Õz\|ËÎ…ôlÀ…aí:…úˆøjEÜÃÁÿäínêžBdzfÁ~ÿ ± O—³ÚIùÍšpÂmü ã8)O¸¢b4Á£ïU^³<Ékc!¨<å¹P¾D>Íî¢?-СÃkcÓ>PºM'À(Nˆ€ÕÏÌ›Vx5CH>G8øÊbh:AîÆÚ!ñ«¼5ΊÚëÿ*Ë¥õU¡eß§}ªcÕÀ4åÍk³Î¾#š­[XÐúÝáÅÃÒɉ¶”[Kß‹|øSÒùÓÂÌâpd4p¤¸9ûAl^+¶sãï¬òäúšÈ%ç”S'£Ž£C!ì«ç•a´ lჸþ#âäÊ÷"‚×zÚ¡Uo+R\˜ˆó·;ñBßÎQš%EVMvÔãuR\–m¢ÁÆEåç?M^d ù“LL2·ŽÅNQAšûª¯3}¯!‘Y#r!­ð À9hÁT¤ ‹›‰Zh–tqÆŽÁ§éM2h…&l|Ó>hD"QùwñØÛ»3—8‡òˆýÕ%¡U­gýzë³û˶é½Å#§›>©w@AR…S°„VÖZJp®´FC Š³í¨†6>Öbï×Úžk*¬";žìt3ÂŒð¢Xî× ë ºzSP¬Aëìö'=€wAl2䆋í“ÈIœÜ‰§j››îgɼCèÒæ ^ ¨Lü‡gïHwmÛÐoë£-‹söyóC xñÿþÅ_ ú—)­ÇÇ’€€³™GTü‹-c+Ì“óIÃì, k?ZàO)‡‚+<ºü—Qj—}Ÿ5É·~´ã×JÖÙ£2¤t‡’dÏ3!o̙͌· ˜êâ7Xe¹Í"VÞ‹,@H†'<§/üúðø~EaR‹‹,"_J¿ª­´µð™×ƒgæ÷>æži# †Zc‘‰Wþ³Ñ&@þfÒ@r8)þZmêE¼ sOH®dAyÍŽ6¿{E›e9KŸžõpaJ\¢”[ í˜!_ÌTãµý÷ç¾Õá ?–µ§áíYt‡¨(èÌ4ÊSõ»îšPtofõ†86@s’ÇZ¨ý—»©6Uæƒ%„“'í6ø¿ØåŽe!ý÷ÒÆ¿| Sâ{¤w>½9#ô ëßЛÜÎh:rÅ¿‹Q*›ŸŸÈ “PÕÉTux¾ÕzŠc¾Ðzɽ““ÿ1¹s}Èß-"0ï ºz?š»l#0µúŽ žK%wì$(@šiä`ý™þ´wu‰"^®ÿÖâN!Ì­©7Ò|ƒÎÓ/ñ M9¸AáÓ­yœ³Å_î±®ÁR *nŒ8;Å<Ê_æÙZø¹Üd:” _nX–âé y³¬ƒÆ{€$t÷î‘hÁÅ_7çrÿÁÈ|®øe ÉŸôïM$=a ù!ÏÕXqÁ®¤§ cHî)I6Q͆^é °‘úû LL³ø³ì;­Tå}Vn0roK¬K÷@÷ÛƒTê1M9lX·$'~;# ÐÊk· ,ÁInj!‰°^ÄêIAnr°J½{¦£Äȶäˆ&]ÌÆKéÊ)ËÜàX+`›,L0¢¹°«ÛõÆV} ÜVôæŽÚ†J¤Aø7'f䜆9{zú¶”×õ6"îX?Öªì S»I›%͈A»VgíÒ±‰NÍ¥*‰º°vM:‹P SÚDÐß éñså*δÒFc¸æ~ƒs,þEÇ žÀÃQŒðLi8öÂXQH£ä3íà¿R«t’ZyÖØ¦èA‚ë„™‰bŒƒ[& ä ÚúÆÝyYlà²^Ü:Ìn4rBw„À¥ò&˜Ìž„‘ñ’€€å|Á }2K5ÿo¢Ó4ÜXøà q «Ök “Ì]ã|@Ôh¾áì1•7“VÕÜøº8Oåœ÷wûm%Í×k0…(²„âKýgäÀ ÖSØCÃ}¤üÖ@ëIÄ Ëbp®q[´wfr6·g7{ TmÏ09Æê«'\è©+¶˜~χ`N…NzóV³Á<~À‡¼bä§ùqƒrô’# *gw~ëšÎX:x+èAç…¡ù¤HáiÞ [t…»¾Ž5<»¿”iwz$~ü ¶< *5Å}Eب¢9!Òÿu²¼G9ÍtcÑK=ï7Ä>ˆ—]ôe=hó£g÷L´@ìhÚ³'céT„Ä]ÕoØ2k˜VØ~ø~ÄDÿC4,ƒõîÀE¸aüëÿ›…í¦Ûn_†Á~gB7V>×}^-F7Pƒ‡¹Ç½­ƒæ"'\ˆvÚÚÑB@ Š;ð<É´ÒˆiI^†¢Þ°Imß<}§õŽH€÷Ëõt£`õŠíZ>ò‹hŠ!¸GŠþ™à@({k“8Z˜8YœƒÅÆ÷LÏßüùð¾gHš<ê†4¦±gÃúZÒT> Ô_DùÜs1Ï–iŸZ°G3ÙÀTµRC·Ý0[†Õå àÇK!›uÙ ÈpFñµ›ú-Š3<1Zd˜q'2|ÆdêrŠgô™5°WÚ+ÕÝ®ÞqñG^ÝÚ3LãŽ!ð ?>M=r¯›>¬¢#e’€€ÖÈ9냠©§à•|€ƒà¶Ãe>{²ÜÀ¾Ü¦Ã\œ½aõ]; ƒ×‚ð)èÏ Ôˆé(Aì:“°8½Ï^- G -¦n ;¶L£Áw3 Éwy`ïe@ ½Äv¼^úBË^-»dà/>J4æ³ʼ¶g£p<ÚÉ« ú+ ã®ÙSOÁÄ0¥‰ KñSЗÓÛl(ÀJM55ãR!iÒšCéíò·Ã[–a¡8ØgJe33Å%Ï´!غ„#u´?ƒPEë\Ù×.c<Ào!•ÅCt$KÁ «e¼¾x'EÖêWÅ£bÈîóÎ.â“6y(f(Æ2ë„k¸•s¸]úÛ‹‡ë“ۇK8ïݺHÂîòè_ÉåùRû„l/ /Æ}r¹g*ííÚ帞é€rÛa°;¢\Ó¯J¸{Áœêîbíh‰‹¼9ñjUIµ(2|* éίÿþkN»™><%¬ÍºìpŠîaçšÝðJ¨¾„PoOFxìà”ƃÀáÚ…~¬!óoøËKO¯º£9€RguŒdãóµÜr³–Syp{î˜Oì§än“~CâÐ` (»]sf eÚÉú ͽ £“÷eP퇈+1æ÷§Ñrurµö\ $O"]Aoï¼½~|i¶b9§™û…$«$U$- «ÚÈ(9Ãè\2Žßˆ¹c³|}‘’éD¯9gY[RõÕ1‡âÊý]С­ÎÑ}tL(fpì&»À'˜‰ñL‹<ÏÇ¡±®Í¸à(¿Ý*l ËH¸éÊW²©©esT8 ‡C÷åúœ¡œ»•iÐŽù#4‰=>QT$÷ÉAC&¤æü"ó&YaÌ{us|³>ÀA€òÒ­Á„cÌ"ûÕîK@(†ß¢`ììÏÜ_hP‚5i|C`·È4uU¨â[ﺎ©2Âh”F¡ÀËæùQ&_{Æ«ZÚÌÂ:d_Aêqoe÷"Æ™tß,h™C‡súXѦ`ð±T½þLŠ_D°Dº¨1Š c¡ NˆAIKeÎM 굕ÐäºÅŠL[y'saÒe9EI]ÝV~U˜1¦j‡þöðT±¤Í zÚ¸z‰¥WÅÇhóû‹S¢±̱夗LÂm:ï ºFS†R¨ýu¢wåe¨bu!AÜ´•€¯»v-œ ÉÇÔ—r‚ˆQ4ölSèö€#ã}i›A‰³øbï} é>ns!åöÚY£(¦'òß:?ÿ-R»uÍ%ãâç¿×$NÈíÚVä­üþmÅ„'«8Z…ѨQLI(Y$7ìñ¬>Ô5Ñ5º$wÖ½‰¯PO×+ˆ‚ KäÜÛ2 ©F;­¸j|*ïÖˆø¥?Kº„$¹-|Rÿt±¶]”ãèÆM‡‡(ÇûÇ (—½¦ ÇäTtÒàÚí: 5³ÛîsqØéäü'•“m¹H¢öl?ÎBáÏ =Ô.|q¨$B€ˆZ$˜E°Œ†0’€€ÄÈVÍÈYp·á#Þ tIcó ÍNî8·)qÑ5FؾöoÿÜ£.ŠÃ1p9”œ 8Ÿu?•S1¼À“*JääTq7b7]½qm]X´n)k¶&EÀ±£‡å{1 §ÿÈ6WFq¨P âj¦:žÈßJ€¯)ÈW¢Æ£'8ÄüŸo4Ôã¶™Ž×Fòôß<ÚF~ë_f¼¦* 3­ý¶r¡7R4S@R™ H ˆ´ý;8e6^¥FÇð‹…Z—ß]H=(r¸ê " —¼Ä©e›mˆÕq iuf5x_0X»Ÿ:á`‘5±lBId mê ƒ.öë Âò´#ÝpFõÑ["0nîßM¸Þ~ê ~~òÑ:—Å„Ø0„³EÏ2õÅ?Ì€NU= ÑÜc‚dyVÔÆIQsŒ€˜k¨´`!;Çi¾Ë¿ÐÔ®ìnº5Æ—œ¼„7hx?Êò©z˯û´œ——sóo›eÝf)˜háú~î놷{èÙÀǿ̥•ÓÞ±Kgný¤‰ø›·\?f¾ éh7[<Ö‘¾«¿òn>€Oþþ@Û ØÂ—Mð+êãÁCkÄ¡_tŸAë ± ~÷W>ʘ”æêjõ;ëìIi$Éâ¥j¨ôÀÉ<°¯dêõË0U`ýëÉôõàñ)Þdˆlˆ?ôIÂ3peÖˆBÎÒ)¢ëù„×` u”’¥œÈŽ®zÅÔÞ>¿t‹ƒoª$ÃÛqC7' © nN3v Ãö'Ì03ÂKý50e;#µ…kFsÈÛ`O’ßYéúÍÙáâž‘²ÚŒiͦ¡0@H‚–®²4ÁNºóð9,òXßU Jò7\Û]pøÐs>.s¹è4è’%Ñ >¹p’–œtz)°xa¼œÅH4‰½HIÞ†RähkŒóܳdÞ7âYè|sô).['jŠÓB_]Rh§gÅQÖCaÚN ä¨ÉÝ$’¾Ù×Y §a–ôd`ˆúm"$ìõÝ(r(½ÅMŸæx6¢ôÈÏœ7ííŽó-ž.âܯ5Ðÿ4.ßËǨÿ“Ð! ØlD¼wˆÀïv¦mü­þÝ΂x%mÛ© Q'aiP|èõ*£{`*˜¼ƒ9Q£@>à–’€€®DÐsÇ=óY’ä„G¥`ñèR«r!{„…fam‚C”0èÖïµeGðq½ ‹ynå@+¶‹ow‚Ø)äeÊJªE?@´ñ.|AÇÙ6u×^r.¢>”?ÏÛ¹2ÆX!×~¢á­ãé»ZÍÔT,'¸PUê}¯)b5€æ«ö–¸é  lîi²™-ȵg¨rX² ì‹±Š¨|ì³€`Ë0H¾0Öcá»&™È³Öavß=OÔ‚È ³YÛË„üé¢G.W¬Š@æ'><¸·Y•ºäQp¸MäáÙt¸$|Ü S>K¾%dר€|/öû±hα½å²Z'¥˜ñâÍn¥ÙQ»‘:EŽ®Ép9Ûb³xçY¹ C-i²á Þs…IóO`tâµ¼¹&frDÌÍ[ûÆúþö&4#3¯ÝÜ]uâÅo× Òê 6$Ø&,…ì0A§ôkÂËy@*ßr~Ÿm3C 7£#î®»hžã&Gë®`Î"+|ð`?J8~*²­uáÈ ÀÔz¼êåv(æC‹íø{ &ø퀑BQÍÀsW&“fðüIã83á 1­] cP?­ƒáç¨Ú:£Eä4[ׯ-j±Îç|½/.}!w²‡c:Y¤IçUó“Û4ã©“Ñ©³9áI»À Ÿ?:E- £[0ugõƒ*QÔ5vÔùØóŽŸpòøº‹ÁçÐîãŽë¼€? ¦‡<ÜæùÈ—dÄ”Ñ"›ûËí„Ü(´:àæIÏïzp»TÏP3Kx`‹ˆá_›<é´ÒŸfȽÏȵUü,ó/Î$nÍ8÷V^p·Z¼Æ^Á*•* WÀ]…¦â½Ì/>’p9åÒ:{DIDã´E윴XÍ·]uÉaº4Vˆy°ÃñßSs›8•-“W.H{qqsG†0Μ†Ï¢;PvªeŒH¥RÍ5’×pðêìø 6j:"hþ¢PÇ}ØÇ2º­Ow&3[/OôX,qüÂÂI0rSÜüï!~»£f0dÏ}›â…_±Œ v3uöm¤S‰ì¾A1¡UŒcèIuY}Äðpµ^Œ‹Ü4%—ÛpÜ·y ØþZgŒh‰¼|}Ö« Ü3áÐÿ¤±V×SâÛ7È™sÄŸš/ æ‘+Rq"&[ÕÔ½Õ?@]‡j1°Á>Í ™“rU"iÀ?Ü •_§Ä§w±&;m0õŽÛniÞ°%¥˜4‡„¹§‹ê>€2žM-õrîA)Ey#Qa` ÝÍ”^ú\¿C 7ÐBj‹­)ÚýH‘õš_zSªìï»ü?”ÊV]ÓlŠ%Fg«Ûä[Ûìú=J`…6€n¾›CJû¤¦ÉN¹ÄÄ€—PDÞ¯Vk‹Ä•\yß(aå 1ƒ:û0G¨ ŒÉeɈÁãú™ëe­ðÃÏh¥•uE‘”(ûsûÀeñÌ@AEƠϥ.È3=˜Ÿ0¬ºáiâg¬úæ£Y†¼(hž —†ú,á w Ÿˆ¥Y äSHúQ¿è¯d”±ÄŸZéß1Q/€¸A!ÑêR23œ±óá¬sÀDPÝÔ bÛ4·˜Å¹"»%ƒ-È^¦.ÇÀfÌ[R/zÕš›øߗΕô Ë˜þP¸j 9ðK•°G4m¶Àe2£Â·eˆAJQ;‹m¨ÁÍ•€…Æà?úó=á[rŒéœ(›Í t!±ºÍ‚÷tÑzX%¹U‘EJB«±˜¤S03¢×ÍáÊ}½¯·¨gÑ©°]è p­2e4Kå˜ñÀþùhV»ŸGq­¶– ¸‚ÅÒàB¯§x 3 ÷ƃ—ìá}b4ÉlÏMPœ ‹7™)–¥Øtzè.W†ŸLȉ×`ÏÑ3&ûÈy’€€ª]~ª*%î?Š-åMZ HwïaTC?—u±XÌ—‘ó^ýj»ÑA’Ž$^5k¹Q{¾Ñ/ï¯Äú‘¶‡Ç áŒ&(аåv"ŒÚ+dWý…Óµ@¢5¼ùp±ú´±KZÏ:Ë@ÂP/ªQ‰8ËrêJý\%vÔ?k‘rRîæ–iØDÔLÖ­Ëo´A-QLÝà­'OEÂEãÑæ !¾ç­L—c€þ1Žk²d½¥Ñ™ôÒqðTk™ËÎúÐfô É¨`bM/™”G®6-ÉðøègZËy4¿ËÔãÃ*%u ×&c3|EájB'nÊ‚w%`CÕžæTCÂ:,Å«|öw G²ÈôK)ö¹Ï’€€µ««Ñ~ðwºX£•GiÊØ¦¤À@bÒÊXë Z#QíA ás3ª*ë/Z޼­³v­\Ôy›*§rK;÷Üš›aºÒÐåè]{÷§‡Ò"Í {ã¡‚w³¦I¸§ÏÁÚÈi…#´%Ûwh& 5Ÿ—”*®Á± Knývü.ªe²¥âÁŒu2u°žÇF­>µŸC'óÆ(I_bà …^J,ùº´ãã(*jÛ´M¤…ß”HNg0#¶ˆLø–’þÏóGvŽraBB[¯%²°ð´QÈʬA¥rþ pV*<·¤ÃÞO°Ê«’öyCÅ1¾™Aÿh'ìíÊ QÀæ ôSQa3šYjcYعj¸ŽyãG7M­%6÷$Ž’‡~u>Ó‰n> ¿˜#bÚ6J‡÷³ÔX~ðˆž ‰6a§@ÕydáÂΆ&‹ÍÐôÆ%ÆÛçl|‘ˆÞCöt‘ÃzÌ––PÆ0ýa,[9¹bP‰;rÆuÛP„¶År÷¿ïtÐv4ëýPÊd“ý{®òôsq%æŽYÉZücøÈ11\µÀ5ïæý‡Þ 96TR~] {¨­åŒp^‹ÒhªFŒ¤2ÐȱÍ--éoT5t{4Ár1æAI#Z!W›v8–AÏK©êÝë¾µNÞDL»{Õåƒ/4|õ*hä©Öë?¶µò–vû¶ ´sGP¢íßÔ¸~qäðÔý±õ%÷8C*Ö¿k}]Â7oZ WRg$7Ä€£1R´nr¯úÛ™ñ½““u¨ÈÃÉzð" "áÌÑ5µÔÊ~¦ášd*ˆà1¨â£Q,aÆ,Ö)bÁƒÙ Ìš Îì„»Àê] c~™Û9ªÀ/ ú{w{'uêå.Ñ© €ÀݯßJ)·ì¨dcÓ³ ) ¿$tÒ„Nº†Jµ×›Ó+ƒ<Ñð·ƒcÓZu=7ߊê¹i˜7ä+N4DOð8uÚí¡N¢Mçk&}V«˜%ù—ý¨Û6kfï63¶0ГÛká› 9µº^ݹ$Þ˜ ¤Ò5>uOCÖ*@“Þ­zjàÊÑNqæÜ>ëû^v´¨eÅ0yÒܘÉ@Qxcr={€žˆRÛŸºÂuæÝ¹áUoåt2ÑÊÜFšÓæÚº>‰z®ºBïðùŸ/“QßI2‚ ¨@’€€Æ¢o‘GŽÉïA&—ÌZ&.ÞX1DóÑÈVÎBk Qf=T£¾Bº¼™ ¼Ò[Œãk›:È×mvÈRhÚ[#QÁ!ŽU»…é7ýd‚2Hu÷ ׿Mà ø:ÿо›.²&Ifn5K5éîØƒNë{–Ä9ðÀ’PsínÞìÈ 8"åS®Ó2Ñÿ&6Ëá4¦>rx<2=©ôŠ7dñKIcƒN²‡É€µMŸKšX1ó …õdÃÔn•жæø[+‚Æò;F]=hqê×#¯š«ÜYlØÀÎ^¥Î¯TWøþM>ÐiûP˜þRú¢#)KªK»çl*eW£cŽíŸºšŸ¶î¼rY: lëŸâ ï•çì¯=t³©€Ž $6Ð] Ä‰Ù¯¾Ünï }âRæ¬Ô%êavóSP‚µc!Ø+cý4Vø–¡g´{j‚“cq*¾ßâ%xá¾ ›?YZ±ÑÌ#‡ëYÜëKmš¡oÑI¦’€€¨Ëô {ÚžÔU†¹M¯ì~æWr÷†½´ƒ¼N`Á;~‡6©·ê‚"£28OŸ·B5ËÖôý×ë¯ \£ïŸÕX‡4þ©qöH!ÅÍ{ VXü©fòåLÄ+êqÖß[ãʨlïË×9þPyXÕ ëÀ›¹ýÿ<:v»TŠCZ»8²û ÊÁú%Û+qÌÊ}Ï$/B,)Íñ–š(&s±Uò¸KDÅÆÂÓWެ(”ÏUTEW¼Ï$Ÿg þÈÆQ†» GWÀSH¾“ oˆÖØÝ¹1ò”6UÅy1ñªâÙ—Ub?YxYùðB‘£º½"[¯ÖößV¸NùÆßÍ6Î κgÑ #`bº°6M].zǯÃ|ŒK¬²!+~oIž¢Ë„ŽJ™Û¯i–¦9oæ gnx»ðÏnÝ«º-ïwK3_"€¦Dr!¥™N wX˜¿œÅ>A˜W|Ït’R˜FÚcà[¦NÜò¿1à$O­`ä ‚t!ÿiØÙmjŸ^f?©ƒÚ·›'XU¤ëaIsÄñàó¤:?ÕvóTáe…Äœ(w3Ïf ¥„HAô,ùó3ÞYª©n’tÈ#®òÑy±†ÀM"Ûç•jšSb@;{WyQ ò·HËcàtüdø¦ìCì—ã=¿ýÕ-}þ×Õ9˜ÁÒÉ=˜Ç…¥™¤¯_™¿Lòð|ÿüçxìà4? BÄNÍüQ ¶‹ Io_‚ŲùÏ‹¸ó‚Á3¶Æ×T>(”9˜xç±ÏÑÇ>´`2}ÏF²§Kèæý 8ÛÏ/º½ùŸCY¹¿Ý=Ù\ZaƒüV½$ÉŸø†¶Ê¡Íú ›_f!ŽÎ(Z]«ìÝcWœØCZ8Zâ€<Òâ‡TŠÕ$¦Õ¡!h:où[ÈÇI+Í~ØŸWø²$»ÜY+>?öÏaBzôÒèÅGB½Ùýq¡ÑW¿®&øÙ—pÅò±;#ŽºE ¾À¹•€}}í¢õ3Þn΢‰±ý(#/Àf«à?8ô-ÊRÐrÙN’ÿ ìËC"å´]øA} %sÓYÊk·gç«ÖLÁî&c"sZ£ÐŸ¢ñI+v€C'‹—ôî]22ºj†ˆ~!Bç”§p8ÏÏV… $Ý»Nkë²âhh’€€¦À…ÛÌ)̱7eTñ\$}LÅGÕ˘Œý¿vÇÅÖ,ròWŒß¼Úñ͸¶} ª†•HSדŸ·gù‰NÄ¥ÐöÌ ž²hB"€æyÎð»M78‘ ù¸lf€ÑJ–ãÈHF>Å]÷°KXdü œ'Ôæµï¶r–zÔÚ|BW¬•-€Ö°bh%ɨtn{‚#œíAeJØ€ÃX»&}©•|ÉîbNR¡<Ÿ [W}CƒòÓÕÄÊŽg§H8Ñ©ûl¿ìÄi³‡šÓÑ †vJ)_g»–FPèa­»8pg“>±ÒJ8’GëœY|¬§áÎ[2=ùè1°©³cU¤KK>Þ­Kü;âÁrg²„©Ð¥8…qˆ» øI?HŠîÿÒ8䥣Ú%8g^.éb \\öìþkvýì@¨ýÌV~ªðO´XËWào[ø† Ò‘+]ŠC­"€ð0 i½{×6ÞQmEøšèµ01Æ»æœèèË…ÑS@Ç[Gk¹ ífµœâ9û×ÂIF‹2að™l`ŒF€7£Bjg>Á‘wKf¾×KíØ}¢›þ˜¼¢$¶õ%´¤Ìz”>("ÖTpÊb¦„J#è ë}û!=ãâÞµ«‹W™‘³oM¶“Lß­ñ=-¦/3 ‹Ò'+CF˜9&òæ·Œ¶8º Q>môʼöÍXì[º·´÷Š]@?|”ôM"²=™¢–¼Z¨#£Üçßä2ÛÖV;ˆ‚à òžÕU°}.YQaŠ‘>0ºöv^mˆ].¨fÑ*=¬¬ùlpÉáO«1rHéþIŠKì=×`âÊ=ð ¦ÛY_ ±îrEll±Z:Ãúyúr"ìF¡w¼’ž¾eF4’<×uê ’‰õèÍLýÖ?¯» &ÀùõzPUü5…i+jÅFöL‡9?¾¡b<ù©åé<ÈØ¾ÆÒìmã sdÇÚüª‡¡ñÀÃã?e‘½IT^ !:o1ç(4M\KŠNy7x€s…QCǶç?ÇC³²Á”¢ÁéæÂ$¦¨|' ³Ç´MàÌGÉšpøÆ`“€”¬Å €ø[ÙUçôñ×BØI‰y8K>žŠûGh¸u¤¹·ÄÙÁûSoð8¬ MAeÞ©'v%²jü ;Ô’€€×±ï=}XÓzîKt6ùʧ櫵âûMt—•¤(’ÊôêÂÐÕKOޏ¸`*Ëxc;rÒdµ7ê"ò,ÏÊ\EúŒj-z ¢&z#6g`¨jwz™Íóš_®·&•S…GBL{ê–A-­w›Ó¨>‡˜zv¢#–I*Ф•ìY€ÃÀÀ@ŒÀ–¤•…„„wúíTŒƒ”;M|^’ÓZ ·¡vÛªðØR:¸5B(Ô˜HjdWæÃÐ'>2ô! Ö<ðXþL— Á)6Ío0"Á‡„“d ¢Ð4ˆÁ ß=hL3‡-Ä_ g¹sE"™D«ó=r!BHž=W½þ6c 2DkHÖ*Vºê“.ÄÆhzå¬/ÿÓŒ—¡žR¤±c°u𥋩-æñ™’¨î!°Õ *@Øé=y$ŠÿiŽDZéMƬ* K…{ñ ”Íça.Wºþá+¿$NktlôÏ´~êÑ»A®¶°C¨ SĦW+3°7<ü˜LÆ|jß Ñ[œß‹B;`ôð¨4xÝ-¥”jýtÌUA¨\~MdÈ2‰Ž;ñ?T­Iô’ƃ<}muËsMBCDêÃT!l_p«È›ÖUŸ‰òzÂ!}3¹îG½E'ºM]k»A’0Ú}°%Ò!¯±pþ‡Ayž‰ü-©ƒ–ÛRü‘yÈÕ€®8C/ Ï€3ùÃ5P-û×îdé¼?Ì …è‡ÑÄæ¿\fZáÃYø9+(WÑH³DàzÞf} ÁÇq¹S›snúFQ=†üvö]Æ_Ë‹°,UJ¤†´>¥ÎyË,d>(*ÏÝwd"¾Âg1Ø­Úö»ÏÚ©5 Ìñÿ%­1„ڵܻ½Wì2G¦¬»£é—Î-XÐ$ÍIngX§ÐN&äqh5opZâÅ;åe˜bð³.ŽÃäežÐO䦋_CŽ|²­óDØ„H“iVæMrÀðÐi„.«`%W«ìñ´â>µ{úüb¦)Ń÷té W_ÈŠ`‡»V°6260sꧨY‘øY&òø!&ׄ†ûBxKد¤fsûß …ƒVÒÃW*V­~´®ò{ãÆïˆ};vlJBk–1–\[¶Ð›¾A“1qMܾ†E§DøÓf-¿DÕû½Ã'ž)çAæ.²Û³HÊ.–’€€°ùf¤VB6³Nwª¹€ÕS> M Fmk¯w)„{–3¦~¡Ó<Ò“lb†Û;.8^Fã";_³Cšd+ÚTÎÍ7ÃØ%”¥ÉTNyûJÁìa«:ÿÀoÅÜ|žáHv=û¼ŽÙ›ÔÂtSb*ÌÜV"]$ÖO∩zYvET¸õÄá\n½R¤ã³ˆ ›¶_ÒO˜ƒ˜ æ„ë40ùÈz4©÷O}t“øEKÞâÚ›H(eÞí¿¦D¯’s߬ÞÔx=‹zé€ä@l84ÎG9ž‰/&wHyæžÛÙ•Š-—s·ÚÇb…èÕn¡àH'åÐò 9kwøt=‘/î„`™üã†NîBÍ¥ii³¬%RŒa:“l¤â؇ӎ€æ3—°íÁµj²•eßZ’Zeá˜z'g¢¡ïŒªNqR:¢™_ñGW$TÑ©>-_f Ð…A÷`¥3þr¹$%ôÊéʇh(Õßtýˆ».3Ú1¦¢³Ô>?©œ•FÓükü¬¹›?Iÿtwy-‡fúÑc™N–• ÒÚˆ˜<ÒYÃŽ‰ýŵbëHí#yn‡oÎ/.c%.„íÿÁUÖ^l3ˆ¢DŠèj wTXØ ¬,—çÎ!Æ1ãÆóÅZ¶ï~ôeà÷?0[J©Î²^Úo«æÃ T$ö1’çÇÈן%³+ë>UU} à•³È,nîC£ÄʹsW+ˆ%Qï­ïP¤lašôÓÅ<ºMEÁªQaõOúÕ¾¬{½½%P)ΩÝ3[ýÍTÄY篲0•߀Ä-±Ìœò~«’€€Å€¼cº¤í;-,šìƒ"UŠQžä¬àJD§%:!“¦òdÃ!`&Bµ1ü´ºÏ•<Ôéžöà‹’p–¥#3Øí´ rwiÜ–9h%–*õ#ê3Y¼²ÜÀ#em~½`‰hT\öÃiñºzl5]Å­xYÞ›µ­¸ŒÕÂÚü®màe@ÁÝŽ°¾@sq9AEy¡g\§È¾u«ºödØœ³bÀ:w’1¾̬a«•×ó Án¿)÷ö~ƒg×oDÝ»3`7Ïâ ãB÷¡E¹ 2`:d›“Ô=/6ë[ÿˆÙåGútCNê6fÐuV·FJy>Ñ0`ÖégU…^†T/ºòK¯¾õxö¬U)ï…rWÿß0}¬Oþä ØóY°XÙˆ5V¸L· ²8⸎ÑÌ1™uæ2/(Á(#¥qWÜ@¸Dè¬]±u.™§ÞÍPY–y×*‘ Ú#>ÆZ.|â€f½Úöîœôdn¿5šjÉ?8s7}"Q¤ê.`;Ó—$ÁÌ,ëþã·~¨æ>–O÷ã¥çv µ¿ÅêKHônvI)L ccOÜ . ‘+?qj³à£ú'² vü[˜æ©rFª95¿'’ßdãZ¸ºƒl²Ú6=ïó¹r>xØ‚x¿–~/`”S|ý>´éµgý6EÀµåéªê¦NÁ¿[4åW€NñŸŸÆœŒdânöÑò,°6ü¡cÂÛH`'±1±ÜíÜE÷DR¡xæ£Q8¹œïaUUDMÐ$“…â‹!n6¼ºõâ¶”¢fø÷¼Ó@ús³µ€prC˧exá«FNáN‰<'b&©M¶SØ`üRYñ¶ÉýÎ÷CH€g\°ˆ†=ÚzH#Q,h]ß½ <ÇÖ×ù«ÁTÿ½£i‚EÍêÞÚ]·eÁôŒ³ݱ—ÈD’—l“éO›=ãQap5ae7{((&Û{ãRùq™»ârĘýë\ŸÍzgémÝqÞ)k»T7”ÏÆ$ý™Ç®òø\ÏmWn.¬2Ч8å}ESznúí½ù³ýI•"£‚¼$ý-ܳ¥G¿;ñºÄêÂÔÐùH*a"\âWŠ•:!ƒ@nj.&ªßqfY͈u»ï2”?{áC­i ÔÛ0þ×È“äï"H¯Pã2=WSyaY_‚©Z’€€ëpR÷÷öqV™±£¾AËÂ<€o<‰°ìÎÖKÇ­Ü2whcwr™/L8¦÷si[yM–{¼Þ >Æü­*”ÑøRX·MŠÅ-¹:ƒÚ¥ªÐì¦ì0Wˆ¨G+ú€¼ûá/¾d²¹Ö1Y³ic\3¿=“Yœ8ØtXu¯Ä¦)Mxui^O c â]³äg˜“wêÅØÂÞAÛ¤5-¸5ü¢±¾¢!w*?²®,†a›ü·ÿ$9è!zùÃG?Í ´}G…Ï÷¦…ý8˜ô5q—5ç /q6Ô.‚´?î_A® 7•{ û¶}ÞÒ«7ë› Þ4?”78$)'Ù6W?*µöVk÷Õ *”ýo‚ú&£–¨’ƒ °p8Ø,WËl*&Ó—$„6Âæ` ªuô>Aý×ìúõ5Eö„õÉ‘Cî Šò a´^«3ÓkvMÁ§®V¯å+r7Ÿ^ºÏ¾,A©ø‚šÎ—Õ2tWôG–O¼äÁ5—ÈB¤ø§­¶®ërާÌ6Y†"‹åŒ*Ð?ËTÎä{6ÖÙ¿:îé÷QâþtɃ"’ŠÑ bq¢É­‰þp®œŸD݃¶Î?P¾5ަ⮿¡jÍ??äÔ¯ŽßB=) ·G¶#Å_zƒnhâBÍÁûÿpþò\»¬[÷«·¢¹uþ–ï´ï—Ê´Òã]mH:\9­‡œ+O‚6iN‘õOîàZˆ,$>ª2‡ŠQD’Å%âfa1¬¬›ó¶ªóW¼Â/Âl( ­jü¬ŠRTª]ÄiÈ]ºïêZß´ÄÌVK&àr$ +œ9ù*ûµÛðˆf¨ZC/eäÏñyÆ1y¼gãO,± èFJÉ¢-ÊÄó…ÈÒ¹‚ÇÏOzÃÍ<«‹ª;¥þã^Ékð A2²6’º2mfS\>ñ4’ I‚öÐ"Úеܶ¬Šÿ1šÂª8¬³šàÃAHÅ©FÊg’\éUïQÀÍíAáC®Š%®WèF™!”`«WgÐÎ×QÂ1A—£;ǹŲ »EÎM ~Õ O^°Ü‚·¬×Nk½æo”ñxΠýçRïÎÿ;ÐÖËs=&ØIUŠâÝðòÅ™ Äç@ÔéµÛ0Àë£H™Í]ÔsxÜ_!èFC’€€²úÃkÒT 0žPKæQ¯÷i§-#î27ïëwk†ý§ÚÁÃcÒ4Óc1·,ARvÀ}i³½V‰Â— 5XUÚÝômƒ¿ÔŒŸW::? 즦F‡qÇÑ/PÙ3‘EÁQú²?…ñxÓ¸GŸ –³ƒlÝà ÒFöÆ r‚©ö(–U éjËÂèÐ+7ÊZÐB<þ’ qçRï_T@#±)nH¡`z½8tN&Ï!° )´C¡—IŒªPæâýà}×ÒÁ…?Wß6æÐ³BpðÑG…ÊCTzxG÷jJŸ ›¡™ P&F Õìøé vs+ª“£#À¯8J­!óMUÅ~J}œ–øa’¡n¹¤ðæÇPKÄbcä2ÊïÇîØüi‹¶þ2Ê™ƒ*F-ï8©7‹¯ Áà‡û ]fäõàæÒôcxݹÇî"™]ìýÏClÆéûa0¹O7] Q14MnSýZ+c¥mç®Eµ…cæŽ P.S嬖ý]Ï­=Í®a”‡?ý\ò­vqBùYaQ}ž0¨…Àæô]­vê®&j™pN’€ï·ªs¦†î­êK„‰†ªsX‚ág7?.“-A-ÇJsW2—c*xŒi¬»¹'2µ>Hd'F¼êÔø…N¼ÁÊr뮿tÍX7w‘êGrï/ll³åo ¾0Á›ÎOy“ÈVf¼Á•Ì¢ý€¯Úà”sVÍõËѾZLLCzªHçÁ\xŽÚ­ ¼”üÏÉ—OÐþJ‘6Õ@¶!àÞl WêÌ ëÏ„¸Tåx7"ݧ4‘‡·3xéE0¡“Ï"pŠÀTï«ñ¦}9÷±@ˆ†d )'Ô¸ñs¦â»•£SïeŠB\À{3ŒíÃU·\–Ë‹¨ò!àx{×WÖþ’¹ê**©Àª×„=ÆüÚå­GrüQ¦v˜C>v·xø±xQâå³kyx°IŸUQ ÒzsãWï¢Ç¬M§“î¼È|QbÑ”0¬2zr¹„'{{èÉ4§Ð]ôéî„èö6£Ÿ.½ÌîÒsï·>tØçÚBÔå$¦jò HÌýLký¦‘œFz¹DÊ[Xÿ‡ÞØ„Éýz(”záH<ž{Bo¦Ïþd3䫨4„{ZÕ_ýP%/@óE@ O{V:‹SÁ±¨5Ü’€€Ú8çÕ3¢’ûÒÖlÃòY±  ÿHÀµÆ<=ôçTãþÎrçæ´ Kqä!oÄJ‰<ÏÄ3Ø5"ˆWa¸ð>B|ÍvƒÇSÞóŒÛ¤Ø)³™ínÕ—X[S‰nÓVÿ-¨züjcì Ú¨ª¯!Ë6ic·&)£ä`škB^“Òè˜"½ öŸ*ª­iß+xšó¯¥7s}Ï7*Œ5ž€Êy罪3:ӶüÁ(Á¬Ë~ƒN$ –ÿI HóXsó©ÁÍÊàXÆð)ÿ®ÑêBŸ²j¼\;/÷Ë0œB˜ÉZøäHÆ‚¹!I?×-ºù#Ùñ S½t%à+©îÈ2ªÝùíZ–`šU:øZ#¦ÀÇ iµw¬¯+L-ª`Œ/-K<'ÁÏ9/I /#ýáX¨3 O\”ü»¹È·ÿ$œšfÎíHàAX$£äƒ–صüîÄ;a,}d¥œÄFc[/›t=|th6Mûùœ-JC­d¥.6À­Ý{ûF×@Á çýOQ¥ÀÊrj l¨ YØ2tnìÖk„j²gÑ7tO,Ñüh÷Æ^$ß$¿“z=õRçf5 _Q!Epÿ½>yýC‘*Ôe„WT™]÷èáÔ¿d®Kš¹8ZìÅèjZŒ=u±,B[ˆ±MS"$ºësN6ñ²a±ôÅ9Ò Q6=ÕÁA@b0÷v•÷F™V5ª!v;Y/ÖB«èf Ó€Ö³Y蜑 )ã¸× ô½„êÍYwÌ•àSÚ£/ƒ‰#·xíj59½ßÁõ8ª£ØébD|yÝ4.eà ÛC\\%"¨v» È”ŸlAz4‹õ³J¼§\Ƽȿ֌‚ÄÚa<]]$²$÷ÒÚi‰o²ò޹¤qŽË©šãG¸iiÅS!¡A$D¨‚ü8wÇ;Å¿;Õä£î‹ôiiA)Á!úÿ#ê—–Ÿ]Ò-ÅODÈ[õŒGû,¨Ä¬{³pØð ðÁ“Ç3§@êzVËD˜ÜÑ8*mä 9´ DþanèëÀgŽhùç[x ­§«cnî’€€¹8ODAà¤ÚB±ó6ðI„ÿmýØ'(‹±À}9.Jz]îêÚö¡Ûá ðŸ{˜ÙpÝT÷‡Q»•žm,¯ë @lJž¯œžTà°{² É@›N:8{aÏÔÿ,‹MIˆÌYzž¥œÅ t˜ÇûΓÏûÿ(C9·z¦” D»×nÃz~«ÄQXÖn u^­¦¬Ò3ŠÄàVìnÝâY”rÔ- ÐxÏ<¯ ‚`»ÒÐ3K—«¤W8ÃNÅ 'gà%¨l˜EåÓ”}áÑ ”Ë¡"¾ …Én*'ÿw¶œîv&œ}XÌÒE!``p»D!˜8½ðÉ#wWƒs+½ÒkÅ0šóƈ¡¯˜<ë†R-ŽƒùO]Qߕ絔pUõýv¤¯Ì›‰–"_ò¨ ){dâD£˜ÃKo‹…Ÿùµ„3ñJàYä)]oúÂD>÷O)¦ƒ|˜iÐXè2ž†n'ÊÏ›¨ªr$ º%f‹ ö Ž5IœÑ«ä…5×äP˜EOŒK3c»üFÜe$máVµ†EðÊßÄ¢žªœÓÖÚ¥Ñ1ϫȽ­)©¨ïÜ‚"n¸ÛÐÇÆðÏÆ÷gÊκQüZ3|NÁµÏÑ©\Á < è“/~zfŒI³a©1~ÂçPt½g¨à’VNÆïû©ÈÛ¹j£Ò¤…×`Ù·~G³4(O>P2±m娥«Ñ£>u•2‚ô%ЋJm1øtŠcÑZžÍh1Ä-u©A¬åàÝiXT­&Z>Ài¾•v¬gÑú[jutã[í›^c÷¶öpšYµU"ÜÓ⧤ aZÓ œñWtšÃ"×g®(‘w*3u{5`UaݦÌ9)¢Cv=eYáB‚ëu FgÌäš~°QÙkª q%º«×uÙÖ×¹µ†¢¾¹-s…š)‹¢8ïîB’€€Ç¶7u%€jâä¥rªŠ}+grî-¯ù9˜‹ÂÀ8ïo6´…:›O«èÛÝv´žáçN© ds¬ÃûÜ_ ò×Å 0±ðb×f%èwuÒmRO9RÔ¯Ãs¿©Ïßipƒ¹åS×X|áדnë×â!<_Ù§¸õ7§–v_š<¢ñæ’JÌOpÃýpD²QÄXùpWÎ :æžÐ²‰ï– ÐÄ¥¿ò—Bsp=C!K6Ï,ùM¦3»äÜTƒ¦ØÁc¸f©³;¦ÈR"_Ó›\Röv·UôN.ÔÚë² pÇý×™Åe‰'bù>¯µy«.³Ö ×+Zë[Ïxs ¤jH3ØÄ£Mý7| …U‹áLktL¸ŽÂ>B¡'Ó•ûq ,x$ð3ƒ,¹‡Ã%¸<äb¸þríÄqσYÒŸBû#ý.ÇÖ^Ó®1#0µâ¹GÓ]$ÐþSXº} & ¥$…Ó]:“åÁÆ@B¦ÈÎõ$Œ"¿=8ççÁÓq§ç_ÔÏd1ÚšÀ÷Œ$›9ó=’Œw”NЊ) €yª¶÷wRþE×´UÆbˆÝÁ<›Ás»Ì`âØç%¶lxFfv#·Ôú:ŽËQ“¾dl"A ²b›9¥X£àhü̘w¶ý=h‰+%+ùêëŒW©^l´ý*•6ü®Ç”ß_ÃebÉ8XîÁôËzÓ\õ>†›&±E±òò|XÅÞʬÙûóŸr–lNjý>üó Žb峈­d)û¬Ì¡¨é&¯"LÉBÉò3c'ruܨ¦}‘s)Õ‹©ë—*úÓ§÷È¥¾a70µÙ¡áJjE¸ïFݯý4Ü Ó‚Þ_qã"'’‚é­ZöJƸ¿YQµ]Å´·(*9Õ:£rm+Ë€¬]DÓÕL#l-b PËãfêþ”Ô- £¦h¶ëÁó(lÖ”]03"ºwáØ^F±ú–Ñý’O]4_Yo @CêâBŧV%×ÈÓ—z!É{“ hXYFõu„zQ–²Ï—±ïi ÕÑ&¶·*£ŠÚÒIübó`GbK1XnÂYqíoµ8èÈ=™,»¬âƒÉ`˜h\V±—û:­ÂÜñ£EÞfv¨(ÿ2 ™5]ô‰’€€à"u\ø„­ Ì˜¸C4¦>Ï@ÚàÒdã·#Gñ]8@çqHvªS^xŽHß{ÁQ9f/¿d&jBsÁ#7ø÷}”Ññ;ï9›>(nêér$Q…Ò9,»CŸ­vtä<&£·öÔW–ólP¬ iySC·ºbC¸Á&m¬·ÁFÐ]µk•¸õã!úhÛ+m$å]Äc¤vϺ3u6i"«Ðge8Ö+‘\öÿÂÈߣ‹…l8×j¥Ò·#2=(S gŸ¬‚wºÓ´Ë¸JÄ"P]C—À¤=Pfµ!Ðà>%Ë(P^JÀÑœ¶ÐÄÞÁ\œz¶VŸD yK,ÄhèÈ<]Ooña–1¹ Æ´eC*†ÚÄ×°6&Ó=ÇA²K8³‹Ã׋×^«c!#cšÌ¸Þ¯biv2·¢cõ¿?Ž•‚úîe™t"ê:âk´ÿ. ©"‰¬ûnv-5jÝËrØ[‡¼ðܲaCŸü £¦· “—ê–*IÙ=,ÆÊg™Ê7xÖx£› õýàG28 ýi£!Ò­Ô‡1pBÛ§G¥ƒT•<üŸM\Ð !KUm| :¦Ð„mÇœ_Ž@³Ûàü<’ª²zñ¡.ѨÞ1¬¡m 8Lµã*1âÖDs!÷gÅ{÷-MRì5¨6õ®¶‹É§7ö)çý–%ð#%.‰iZÕ=†Ê·µÖ=ýHWi=8¬é‡.góžJGÛ‰~•†)º_Pp~ö3«f‡Pü†1(¢×’•o½ _›ÃuчÕó2ú£2µ@EŸYIëÊEF@4*ßy€Ñßçë¼9KC;cCXzPˆ4ÓV;®cìKNw_ñº±nö€¸¡Júí™ÔÛüN·zöIE ‡ !,~­t0 ¼_™÷xdúƒÌòäÉÅgÏ~œ8"k„E%k¥Än+»¾!ð]6®U…žWn-GówòHPO3(ïê—zTÑ3 Ἡæ$¢å¡'6Ny›ÚÌu_ â'!c­á§  :e†ò½!cêŽa1ÙÌûL£íö4sÙ5)³³5ø•ÄÝ8 x3,Ê}U"îy ój8ÈR—M›XÜœ$°¡<ÿ¯·ýI*u$Ñ„Åtíuêã¢@7d]v|³j`q’€€•ܤ%£Æ[¡®¶ç•(OF9tôqsˆJë{J›Ü/ýêþÙk$T…k_HíÁã©&À•zú¹¿ÏX÷ÈÁ~ƒ’Y‡Pºâ¤X¹Ùmõ‚–Ä] =†)ç28Mƒ‘Á^"Œ°O@‹Ô»ºÅú |šª=r‹£ZOE6$Õ.¦·¯©æ`e(lT×zþ¶jâm<óio÷y¤Æ™BHç¿Ò–1Ÿ¯v/?]ïí©¢Z·–ú£uä‰Ñ|ed«ÓÝ Î༈;¾ö,ºªÜÒ7mÍ G.æ^éãE·IKð÷˜%œ–,¸Ç-ÞÚô-~§½¦wÁ›±:¢çâTŽYƒ­DïÆÉà±&Ñ<Õ׿HEíUkŒ'Äúþܲ´âšLfœVZí‡ù³/ú"Ë Äoūə² ñ‘apÁwŸÜäñ…x'_;ÿ¶¾lõûŠKGy;`ÉÃÅ¡ˆÀ¥òõ©Åü,ž ;류ä­¾õmdú<ãxh ó†;Eè%Ø1ã†þNß&œ»J×3ËÊO®—Q»ÇGJ Ÿ>>p‘ߌÁHe?þ¹Úðe÷š¹™TÓŸ*öά¦@"zîìÅNê½¥1ã”[¿pÈØ›Ò2qÄJ'Ĥ”ÎeÁƃ3¥1µùsÈûØÀ^Áu‘,A}/Z¥£âó½>Oüòs#€ˆBÉ;è§×L9ND©lD€xœE6vYÁ" –2Énš™ ´P[ÄX³nÖ‡í} /B‘¼ìUúÚ2ѳŽ‚zÿ¾£¨ÛΑ榆ýñ™õ¦ÃÇ¡­H'—ö ÎLm¾ÝòäòÁTÅFÚŠTÚPøw37Ë"i[ò ®ù*×2‘á–V? ß7X%Û°!O­ ÎôŸ’7¢+Äâ|0à½'b÷Q«»§!Ê2ZýLЛ/«A<<'-T=O‘À}µ“KäЙáfQ œ —¼äM®¯MÖÀ’€€¢B'ƒ~¿Äõ"./õ#«Œ]kRå5ÏmöA¡ sxH…Ûvøß{«¬ÁÇÃ<ö~eø .8 ;®õE§6 ló‰3_½ÿˆ–ß=1õì˜íeXáhæbo#£#`rSõß*)q¶,ú+Ý>Ð!Ù4vpÏãÐVR'²WÒ6Oho"·sWS} ©È‘›Ó“ð[¡U¦™É”ª_uÆ’ÎTþbZRl9¯? ‘Ç|ë ñnbsoNÔwM/ðÂ(O‹øg,døŸ¢–K ä…%o¨µô”7¿=8d3BŸ##Ä’…PN‚ô'ÊÐR½°z¢RŸ¥ª ¶&WÇ(ž!jT·èw€ü4é¿#ÜÓ`~ øÂ½òµn`Ž íZcUÛЯTÈž^ášÁP‚qcßàhýܤ´k µ6† Îh¤T'ó²¯i¤/–/rÜÃ7ã$°Ç³ ÑÙ¶ì4PpÊŒ9g!l¶¬%‰ŒÃØÃ…œ4´8ÛÉ.”ý”ï6þð•;þ|ýWÃ`ÝŽR¨Al#P!+‘ÌV-0Aa½A^çäFæÊ_øApóšÉ\Ÿ­Â[ ¾†êš£ãÃñ„ ’,Ägk‚K[@;ÒR«?á[CcÏr‚IG±,Ÿ;!´cðN7m8=ÏÆåƒtx:d+¡OlZ”¶œ^mö.ÉCÅ’ö‘O¼B·U‘£`ãC÷~«æOShzAl×} rÞ°FãòÁŠß¾ŽšÊ6•ñíû.¥s˜ýêѶk u¶œ*²]a0 Ë*kzQ·ë\T¸á¹ñ>†añ[Í@Ë‹¦¦?פÛÇêÄEJÑEkħØóæeö,WŸÚjmϳ]œ">d¹IúÜ78mþ˜ r%°¸¹çß l[ Â$¿·Ë¡z>’F¬[·³ƒ±KòÓ·'=õs›Éš¡¥lkÝöû“‰W޳OгŠäœô6[¼[9–%êCrfÁÈ´¤ZdrÇœ3¡Ñ}ÃÇ=%=²Í•Ú!“Ð;EtæÜ÷1í´;L:\…#öéhíPάQIØê›¾„§ŸèˆäÅZìÑÜ35¬Òâ…‹ˆÐ¾Îó»4õþž·éß} © ñÞ $DÏ™ÚO¼o*Z)Ô¶j*ÎʪË-,Ë’€€Î#™$o' Ôôn›ObR·Þ'…™ 3»Æ‚›^敪düZÏÚ`bÃ3„›8ɺ¼Í÷ó: gG¤¼å1¤ëÑÅ^D“h¨T­z@QÕìfè—œ£ŽÄzÊnQ˜q‡:^“Ù“Èw#6@^ú‚™¨þ­¬¾?8‡±³¥x¾|ĵ1Žÿ V…kˆ5×Hô=X¿… 'Ü,Éë\)g}¥NКCµçœ+wâ¥ÞtSÅéÞ¦QÔbü7Å·‘S]³¢pE,ün” ¼’:m DǸñQÜ["ß•¯_²,ûƇ Îe:W •[åÞët˜¼Òö›QJoN–E,ë´>vx÷ûP5\úyéÖcGï1ò¦«–gf{‚|ýVî#cÖxËÎôzw!¦'§¦Nnʱ•C§tükNÁŽ.ÒOöW6ÈaÞ€ïzíχËÀå™Ë>Êô šœe"A4ÈjŒ =Uh3G}'4±M…~ÿ|¤0 Qµ"í3Í÷ʶ½Wébòt¸Y;Æ×”×kۑ⨽&Z×F%ƒ›×uVø¡º½ß?à– ‚嬑—“8Ìëͺ\º‚r-É~šH!§›µ™I݈j›ë¯ÈîE ‹Û«­¸Ù:>Ýöøµ¶ëKë"¸°½Xž&x;*ßDs)9qóódþÛ\{ZÊp¤–•”x+#„µ2x1@“ÐS¬eAÒgð><;ÐŒ|Ø©â¡wQ¯nÉ࣠«7 #þ,ˆíà}‰è'í§ÃI¥èøÀ'”TÈ».[3S unÀ‰à3Ú”Ó/€QàÊZQ€ZoZÀ;\Äpµz°Ô­ØDáÀ×|#xA¡Ó˜` ÛÇä&+Œh‡2ÌPßéæµ^z¨‰|3@¾ä3×)¯®ýTÿþ‡€Ä"4@…@DopC[É¢³é“¿(~Ð3ÀÃx>aƒ~[6”Œ§³F.œU%$"ãv>â~št'òâ¸7ãaãÓF£ Õ˜ìåâÀš3™.óBw§šÈ#-©fk„~ç¥FŽÅÆ¢.È´«™Ó‹Øk;á>ðû°wj?ÖŠšÔÖLº(«ß@"‚wa­¦±Ü. Š|¾œ ,Ûµóþ¡g‰sË"Ò9p4lÖ?‚½—Ñ…c¨-'I;ªí™ê0بÈ’€€àÂaÉÛÉ@¨8… *¥m:ŸIYg_&º_vXkj±ìJ|vW¥ £ùÃÛuµ´¯„ˆ–.ñµ£$‹D˜•E†x¹½5ñWAVîÒH8'õ:Ó¯V ÜRöo•Uå¨Ñ6 v…ÖÜw['ûÒÆVƾØ.6¼¼ø¥» nå}·Lª Ur››Vª&C2~,Ää†Ó¹&]»Ãr{&Ø¢`­A'eá#©æKðŽ,˜iƒ ¬‚ýË`t?^1o5ñ!£J3“}±ãÒé>¦ÚÈßAý ê¹ÆÙÝ£€hò²ó…¸ÜöL™òjËòcÇá®hª•îH54øñÜ–÷ÙàŒ‹W„‹ö×™u†B1÷w¶ÇÉ£äÓ`§×r@ÆÆ/ÅBzß’iKHc§ù ËŸ^‡?26—ÉÝRU}Wø||ѲêÖU#²S•ºIõ)`¨&’d{…Gñ-ˆ5ݹí°pÈØâÀ>A¯ùÄ¥ \’o×Á!‡L]ç!׃VÁÝ×hL ¼Bm \Y×!©Pã:UCÜ3V¦m½øÜë/ 8§Ñ;ŸzŸ_p½,qô°§õÜ›™%.Ex e\ö:Á„ø†ëò2&%(¶§‰ÂÉX¶Áài%‹w ݈ƒÇ­JËIoc_8ãFƒÅ£U±Áy.-Y°üjæ%älPË“çë1þË{%ØÂò¾-»Ð¥2ñå]Ÿáêh%|u]óúÙè —"¥E rƒŸ™˜B<¦=&Àxíj§o˜r¾šG2¬ìåøm«÷`YGeýt@³³ÊïéB„©’Ÿ6ÁœMÙD¸X‹sÿìÙ&tóÒðâ²’€€Ÿžß‰2tP Ó¥yxíÕ- ;¶§˜®+:¯–v+üa_µ Qô,Ο[o+[sùzˆ(#j³>™8`fç?ÿ"àFY(ú}Ñw—UkÅ×ýzDŠÐ(‡Ñî-”ÿ\—þ‘!æï‰']/7ßÞÄ@Õáè¹ÆTnõ5§a9&§Î4_/‚Íj¬h€qWÉól¶eÜЪ¸Ö6-ôUGu<4ydÔµYKDµéØùþT3p;—P) 5‘û´Òæ3º;íÒ[/%®ð¡m£ ó«ñíĺWƒ…ƒà4§$åL¢Óæ( ¾½Õ´‡í¯àNi…/Üp|yIIðàHôMO–S; ò™JUìÕᤌ³¬›Q»4&QŒmæû"X“–?†úÇß]ì=çV¥ó oS-&–DJ pbWÿšxç…“P%Ø´kiGí¤ (fp¢õëÂ×ëÝ%ˆ,"A£üuóDà1’.›mEi ÕÀ`ä¼®<èc|‚z«”«hX¬pJÁåïÝu+ëºÈP÷6‚$_l¡ñ†v2ö)-_V‡Þ ë¯lÿ|qHäHíú³ÒØÀ£ƒ¬"Ÿ¯~[{KkòS@žŸIsšÔÆË¢!}´¶ jêIÙ0GöÚ ´ÇØoïÈ5M_½že:dÔœ8ÀíQÓ"™-©’ÀL£íÿ@dW`kD쉯ôÈmº¥¶êýhTítÙ4ŽL%ÆhÖ|t@çágÓsp7ØÞå”rž^dW…ZK ¥èwÙ.<ìÑÑɬ"„9M–ˆn(<2ƒ_ɹ1µ5+-…häÊÅø×Ód·ðýÓÒc‘þ›ñ+Á5IkIæç·´ƒ–£ãu=l¤ª1éÊ=»œ/¼ûìÝ]9÷¿«+¿ÙÑ{…¢ŒMí›TA‘•À‡/„AÀëM^l )tE®¼‹_6~cÀõ$v­ÊÌÉ<Š!f©ÂZðzç6÷’g¡§pÈÜÉ h9¯zƒO[.@¼ŒV›@/‰Ò1ëpRfK¡gª9‡GÛ†u?ëy“â¬xwÕÀ6ÄŸ¦ê<„rfd ßQ2pó[×ÏË]6åp2;äaØœœ? þGG‹;–Ý‚h<æì®ÉE¥ª2²4<@LÓ5ôS¯¨2pãã?K1YŸàAjÅå )S›ˆaöhno’€€t[è±9ýyòÖºøõ@˜ˆœõ» ,ÀŸëúñHU)eI5Ý@³Ží_ÁWhb¤Ñ§zÜuAî1ñ¿³Ñè; ‰ÕÚE‰!{ú¬&PÎÀ|¼Ý ¨åŒjÓ_÷8¹DÝ%ú¶·´Kœ#jÉâz1ej£ÆT51UÁkýH nO’ªF$ðJfᜪ̶º*œãèëãéC0¾D!|ë“È$¼t´ª2V#$¸ACàtkâZ(,UD•`ò„œæ…UŸïGâ8²eï¢MŠêœ€¦ûŒ‹ä^ÔM›¢î¸ÿ® ôê‡hÇý4³p|óÀTÛŸë¢>¶`Í"ÖnÃy$o’¼å©žõaž,p½XߎÕVÍ+t®2ÌŒ\¹¢¿o¤MýæD”nb# HAíÒc3Í¡ë”\»¬ï†5LÚ|%ÑÐûp*L& œöK¢j×oÌÇðšn®ï«‚ßù#<* ×Vã §ƒ J€@åDBÔcÃ㆟Œ+Sv~Í£½Ï®qá~ÉÁTh…Í,¼‰ñI«¨ñãpü³8‚y_+áÅÝ=þ+ ™©Ö…Ì'ð\Ì¡;Ü;yÏÓ7¢ý{uYüg!Ysˆht²¾+‡êú ¹õŽ‚u´Øè–!ûSÆÒû'Á†Ï¥’EðzÉÁÊžÖè¥ì9wîv’¬$Ñ7=,ó½MP¤„˜Ê­šn@*p®°É‹êâ,›çMüÔØ;ñx0Y%¨WòCÒ 6íMßéB­‘¹°|~yGiݽgµðh»­OÁÃâ¦%@œr3ñ(Ú™f4•0­Ÿ+95Ê=£GåÃsXÌ”×Æïnl}#K#Èßî(•>OUµÀrÙúWû5^Ëü ΋¹âóðüO ØœÍë‘ò<ŒÈîÁ)3Û”ç”tÜÆNlÒ°ý,ÑË­ç¶_Ó¸4z†ñQúˆÿo€@ÏÊ °YþNe;o’[òz®{ï¼¢?8“ÕW plÛ;î¬ÌúKˆžÛÞŠÅ“µˆÚÙŸ±m6%jÍÖ“§·ºï^PqðaˆÉªä^êØHN·Ò³`¼Ü×mH4g™Ê6Fð·ŸìŽ×uå.Œf²¤²"t% tEfžöæbá÷ÕëÛÍ~?Ìo\„:Ɔ}ôû«ÈD hKª’€€çÙÿìÛtç])î“Iy½ªäóµÄƒ ØXd9ó(L}Ï´ì²v²&-}ˆ4+ è ^Xí6Ãî]ü5“‡ŽÛБcÜXì"ç¶Þʃ]l†Í½Ä`;í=l5 o€R0/DQ K ¢,\vö½i'–uó U÷×ò&FxR–Ñ'œT)!³UÅÆ¸è~M*0€S Dô\.:Òš²ÙZ<ÑÀnÂÒ#ì:å´ãË'`øî2`&˜¥_š`7#¬ù=Ú£~†Ð4TÉ̃gpdš_F…D™‹¹H«•JYˆ®·$@¾(†çØ&¿Ö>¡îLÜn.èµ ¶Vå™BÏæákT"#üN½°s‚r\й?4‡žïi‹”ûO‘÷\À/ŠÒHVE¼zY”~M‘:æœc§ x¯ÎjhÌÞµ}/y¹'$ì(°4ÿS÷¼ºMtØâ¯0DdMÛ ×ÏAC¤™Þtt¯ÒCîÙ©ñÄÁøUìð ¹?Àu6=b'±†h×þ‰]6/á©›´ “?Á º‹Àª¨ ÿ]­Y=\§ÂĕӃ^Ý »`×ð,äñöÓÙ˜§² |{Üìƒ_Å•¹Oñ£ò pÛÞ¬žì5ÐÇtXždà K7Þ’Í>@ÑnHüQñõ+nžË¿¥_{YOæÐtÑáÐÞh"\5ÀÈɉ¼JG’(¶ñLmN/f˜C†Òˆ<ó¤%ãW—N´#–wYnkPÔ ],ø/ fÔ\8—{šV1x@AÛñ"Å=â™ÔÇrÙ´¯Ì¶(`‰ }k©™MÌin,^±ñK€g†›Ùé,yÊú3ݶrþFYå‚… HHÿ?j{hEÄ5ÜsÝÉÓ áÝ8X:¨×;0ogY¼ y{©º”\  ê Zi¾?BOÔÐM C:ÍŸÍ“_`çÞá.ÿ`  cbÆWÆã€ Áöȉ m¢Ã´@R6Í&)ªÕ¤ù`y4+‰ â’IK¸±k± _—\¸y¢ÚGÏbbÕ¼sê<ðMÚøÕ°úàèËÙ;YaêÀRz··†dÖ‰³ / /Uð•¢ïŒQ—ë¹<.Çl(gíö-4k€Nu!|Iy;uxL¶Öcx€^/·S/àü<(RL3&ÆåîsC^ª¾n®.a4îeF/?¥ZÅ¡%Ynœ«á$ʾ]ÍÑÆ½æK»Vr þnɰ̨¯H§=°`¬'¨Æn›Æùô~`¼» º ~µNIK'€G!“€fbư G\¤%¶‹V*ÌfB.çÌEDþ20Ü,pzÅ(vÊJ5:c2¾*CtÔA|æ¥xx`K¿ZOâDf‡ó»uÍÃ\ÅE,/ ¥Âr·Tø4 š%RA”æýÏuAp¥ç´ŸàóRÂä¼3ÍìBlÁŠUç➇9·ƒÉÅènx"&±æšDš‰YÉ̆ç!wo)ÓÙ×­µ Y/LFV£ ç&)ÚïܬUCjº@„y‹Dúp}#©sG‘èñx)\hÏ Êh%”‚¼²°ðäºv&FÆÌKÈóJbAŠ~Ãî4[äp§U¡œýpÝS÷˜ÁæÇX#UYjÿeàÈ—Ø”t‚obV0ñöjˆ©t—OHÁa’;¦3jú9Ü$tÔüÀ*8lìß i6>« ¶@ˆA%è¾éŽß߈c]«ùÀpî6 t¦fÙcùæ|¿‹üôàM·±Ä¥´G±(ÐäÛC¨VUd ‡Jô힪¶€ „º—Ã-Jº$ÂÒ.úãUïñuO@Šü4gó[g÷çíåq±,ÏÓTè…,zóiÕ$(67ä¼GlµŽÙã³ÍÔI!74µ×!À«¹>{)íø–“¦÷4Ñ‘í>‡hÐ^7ðÔ]q9¸†ºV&õèË~ð?GŽ´bB¨úÀãߘ¼ÍsÀVPPCV\5á\Ô®Hh¹U¸O‡² /u=¸ŸGÒÿ^V~Wf’ÖóÝ›¿÷ÐÈÿ«‰w·éΘ`mo ÝßÃáÜ|·ô&‡ÏJ9ÏD{³ö€|ÌPY–c¨Ès€é–BerT›1¥¥GGÖçÖùBË ¾,¸xÄ6PD€ƒ¦%äÁKn|©`þ»É@©¤çD*œóþúZ›¹à&ðJ¶áÊßDœNpãݧ(R 8J¿·ß÷Už'7¶© ææè©Õ^&áõÓ'ÿ°RޏÍ™ü+YV 4¡<&ü+4¹xp‰Yº³¶¼ë¶ÕNBL^<¶Õ°óÙW­a]kËúy/(Z*ÅôUÑĹdʺ{òj±|VTŒíkôç_$TŠ„v»+XÛ`l¥Ï)+x­JUµåø¢åè ßÕqÜâUTöœÛ›‹Hÿw*É{tåiÔ+äFÚ\͹ÆÙ>¢F!vǪZ17Æ­…¸¸¶žJ±¨dƒðÍÁ°}éï\»½EçÉGIÐ)‚×¥8š¸­ô©+öÛhŒ“ÿוȱ‚?á%Î8Ž)ÕsOCâ~»2rŸAzFreiWÝ1T¤C˜¯ÑvQÊ€R^k*¨êàxR@h©¦ÅÇ8h(óÿ‰?œW‚ÿ½K´¶1Ë™Ðø ²(ÊÚž]öž:£¯aØ¡¯†yªèÉÛò“åå‰À51Ý;ô•’á÷ »f’·‘¬ÀBÇÃ%¨¯[#) 3LUÎë ×Q€m%O…Ýd@þ< U2'¦L7Ë·‘7_ OµÉÏgìûÆMžùOÝзӘm¸Ú÷’.èšHC=wýüÀIŽê;¸Vîöì ÷Ys/]=>S ûæç“hU» ƒ{®œØãY\Hñ±ãwa¶v2äah ç¯î_"`Ø3rn<¢îù8°ÙͰè?Ó Î$ËÔc‹îU :êGQ™KH'‹H:Œ]¼N«/<öêÚ†.èÜÐ}ÄñUÈ£ô™l‘ØÁxma9ÓFb©ë阪C¼–±>|iRÍöêËÿ{Ír¬„”Sæµè¤]%„Ê ˆÖþ /_ïíâÄÖ÷—‘ìû€jÄ qOä«j%uȃºù#ªÊâ¹+|qiÞj’€€ÅzöŠòCy¥˜ónKPz?mÂÛžòN†Bb >ÔyÀDûmýªz=3Øê:Óó¦m’“Ø*+1y&7-i«‰ÌqõaT‰s-žw¢Ãx ¤á \-Ð [£µfµ¸W혱AG=}2˜h¦Ëk˜¡Ö°7ÅY¸á2œëñÖfsžo O›SóÓIä(n(ö/-«+Õ¿{œ6|sdåêÕrä&÷âJbªDmT@a“JÒ¾]5†Ëט Ï/ve†ñ±†È˹:ÂcHg&O}a§tŒÍŽþ%þB!|xl‰û?õœLý®iJ­z­¦šlÎ_’‰ñõ¨»od¦ –H0œÔxJQ§5u·Ž~Þ^÷V«ò¶?·>éòÓ §e’€€ë/ˆO¿ÅŠDsœk¤Ýð‡cá”oüd v틹Wû?è«PúËv’åU…Ã`ßûËEí}z9êèì]!c¾Ÿ4FZ-Å5ÿ{"ÒÕ"³ ã›þU ô(¸É D´É¦O¿ö«ÔB1:¶Ú?¥ Ê@øÈeW„fOîÏ¿X3l%P­q|‰1¢µ/7%ïwml)ÿ#ÀS…ð:Q*y´~If†é¡©ÿ‚ùšy‹ãšmB¿]©ñÀײÛý€³Ó4ü²4i>Ò ƒF„T0rñ%Á~å³”9rï6îépêô^µm§´¦ Ðj%qX> ›r¹SFžÕƒ§•¿YA˜L3ì”›(¦~: dF›ª¥¢Y×Vrl‘ÁdÒ²³•Ñ¡‡ªóH"»¯êˆrY«oo¼Í™û=ÜUP6Ž‘RTÓì¸Y›·»¬fd™Ý$Gû€€/ ¡s†øæ{$ŽËM"ì/à}ë÷á#6o4Åàà[c˜é|y$¥6ãÃÕiõ -Miœ¾ž¨4•Ž¢ƒNwØ䊅fqM·^Åq†`¨b]¡Œãž¸jYï–µxT)®à%p¿ýNˆºK¸¼M×ÉÐsR´âíºhļÇÂÛ ^)ðt>,ÄãO³ó‘ ]ˆü2Q ÿ™¯…°†õ63Pɯ£‹:´ŒÖ"逭yIƒ«@ Y*YQž\Ä¥¸/Ý^½K8ÄãÅÃO_“#ªq®U„S‘nþí{“øuýh¼žz,Z’~©þ@3$Ïßw¬|¡v'P+„9_|Ñ\!T)–§¤` êÓKëÿRÄ´~|ÍYöÂ…‰,¯G‰é/û0³"1Į́¥*@Žkл¬Z9^^üÆ“8jŽ'É ÀráÏõ8õ°Ý •\qlò¼"¯ŠOþëz™”3Ûbs±•úy¡8˜/ZÒ^yÛb¾2²º5LAl=èâSV)†¶½: u‹œ‘¶Î¾B7¼Ôɇ^}37Z4f-/^úÖ3”õ•^MJ&N¯[ùñËá^Sì’”¨WPŠ ûZ(pþR(xVk-œ–úr(¨ÏX\r°-^šºØ·T‡ŸG…Æ ,€…èØ 1™äG¶½ÙÚÓ.#û¯Ê@Ň-Étœµk’€€î yõ‡+S•6ö5úîI>z:±!&È­a0àq4 q0Y´½ÔÓf Ñ™/ñÇÎðvj.‡]gÿüîþØlH'²Ž“–¿%K1‰,â9U„¼hÄ ÄXèì›~ð[OhíÃöȨ{Òìu<ÆnËaþrÞÕù³Õ®”õØfæ~Ä'Fpiiséô“ýK›˜ZG=ý#p¶[4•˜,Œ¥Ö0Ý+º*šåp‘°¡ÝµÉZ;O¥÷pjÞo“U½ç}$&YIS»ý¼*H¬ehM褮vöáÓwúI…ÓÈMU²â«D8Ó¨ºcíYÁd™(¥×µæ( ²ÄY© C/”B¾òQ‚¢û ¬¢:6µ‡cçœ:‹@¨N™ožç„_!íuPÿB¹ÆcÀ;£ÍøÍHƒ¢)ïZKÄ;¥°D0 ÆÆ3^e}ù{tzàØfo͉¥¶aGŽ m«’€tî¢t»]ë»çî¦0&}áÞu|W˜ãÈË0Õ}yXy!R²NŠn‘s–zìßU‡Š­¤AJ°˜ÕÃJù-Ühªý$é-Ùм×ö.Ë^ægäßñ¥‹!n5ä–×'uãqt“è¡>°uq²öìóUrh°a”S)N•à¾$ì.½à„•µá›JÏIVg®°iÌaЯpÛÖX!üù$9'yh¼’ðϬéølÃx‘ŸcU¸Êë:â—xBXe™€ˆ‡¦Ô2ÉŸ©Óê§ ±¸3é9kß|˜K´¶¥F¤­bCÿåŽN¬­ío†iŒ~‘GøÜ ÂôdS°_> &•“ ÌrúG¼n–úµ ‰G‹©4 5ðä›óÌ$õ.¬FèXGß×3b€½ ¸²¢Þeê[,YPö`l >­s¥Ÿû€Å–ÆnðCåÜŒhó¡% $ìi3ê)‘w"­ªå‘;x¹.­¦óÏ*õZ^µ×siÜÐÝC 4ç3ïLÔˆ3u4÷Dç+¾½h‹eX6ÑËB'.l§š™%§àæ0 '/dÓ8_Ì/øO{™>T¾-è ÿv*ð"„ƒ„Ø€6TO­Ê€Ÿé—¨à½MŒBŒÎ´ÜÿRŠæ)öTzøÿ.’Ïfñ^ñ,žpmÀÐt_«YfK†ïìónV1c?Þ‚7ÓÌE7(»å¢NFg(JŽW 1’€€¤ë‡Ëh4ö}Îè'°òs8g¾™÷b>"ÚaTj0w6,¦Äç‚4ŸApï\d©;ÕF™@ 8¯Hùxû¢Àgsat¢hJÚö‹Íëøq@æµR]òP3’¶èÙäT ÿ ± ÆÒæ8ÆqbQäf§µkÅ!v6BšQÄÝxçÊǃêõÓNq‚7…î;ÝÒÁ«Vžƒ$²ú0ÁâÐþrȸ‹Q<ÚtGÀ*ÿÆðrehŒ¢drs¦?ÄYSœŒ?S¯«zÇdƒØÜ#©Ò[ÇcOÍf± "xGS_±hªÿØØæò¹›”ù?ñÒ‰D©Çùé!!l¶PE5ÒÄ1%ÌÝ|é&Ñ¿‡'!@Ñ ÆÝËèd_ ñž» !é´^]€í7JÃÙ×l1_•"yŒÞ^Ú²ÿÀ!u­ÂÂJ$Œ‚¸‚êÞŽ‹È‡†¶¼4PØñ°ºØ(™d¸ÞnÊÒ¿Fú@ªu6¬lgRcì™ùˆ7}:ZÁäàô¿æµî7•-ã%àüüvjº‘ZBÞª½šÈˆ2Èê9ó6…]¬ž:¨åë©M9¤_rš%¡Ÿq~ß°ÿ„“ÎÆ–Є©Áô ,„QšGiÙËêBD¿˜¨è4Ýåˆ~ŒjßàÕ©´×[Ó—tŽ|ªÑ­Ô̈¦ì¥îïõÂ%û|×è¨.ÅU¦½€Â×ÄÄÂ~^6Õs‰ÒP'¶@à ;òŶCb˜Òb‘·ÇQŽ$kÃ{ÎM¥àžTýztç;ŸU†x6=ú›ðn¯{š!?ßyˆÁrãˆZ-¶øŠÄâ±"†¼ƒãÕÖ,jèlb9†yÆf©'4°š£ç©-Ù h>ð˜Ó—5ùø6Ã@̃ۑ€Íjz0ý>3=³:x°À#i~ç%mNbÁÞ…sºöu÷†'ö &tì^«;_íø—ð™F;ûŽÂ|#xWÂX î‘j…häwÁÇšÁNà®q£^Òå<7Тƒ$^ðÒèŒEÿD›á­Ëñ賓òñ™µ¦Oö‘ù¬Ùˆ>\{T®9v¡©7P{ç‹ þÕ#‹Ö G V&Qƒ‹XØ‘Ð@ ÒØ0€q8§=n¯|+$ºç—Ò¼Up–®è*nR34f·æÕ‘ę̂‰ka•Óþ¿ïÂ÷»†^÷­%ñ’€€ö§h6t8%é%ª ×÷îL¥mìêÚä1±v=³ä£›xàA.T±I§—YÌ=•±ì•5¯Òîý•é—Èß°t•Wú_&^•ÏX  °1‰™h-¹3›É ŽP"'„5 ^PüèéZÊV£­9üqÛ”L Pý|yßÛã¶f9Øê扣!¾Åsm´ÁâŒÛ m¦]àèØ¦\‡Étà¬>ÂÑ3ž]–š^¤0™ÚéO+œ¨ˆ~^õœëTÜŽh6ëM¹E~ìQ¾'øb¥ȇ]ÁŸk0J¶abö_àmÈ…ˆÉ,5V8ÁLž=‘.’Y®ý»ö¡Ñºvb¸—7uU2soÏ_:¨ãû“üMv-³ÇRŸBÑKQð^µ§ä°Ñ<`ÙÐ ÿ®Qì×`H”Ý)vìüjƒÿ~D"–7§$¨eøwÕ êB˜þª«w¦©?<€Ç5/ÎÜgz(û™Ò ’!@Ó™ârpðßo5[ÿ&Pžâ¢°†^¦@vP{_ÅËpw÷XC‚D®§'F(Ísš®RnYLpÓ}z…¨?Oè¸? –]øf0‰…A®”ýí£Üä®öþm~› ,Éqèë_{’í§[ûFÞÀ^s˜D1ÇzŸæ;ê2¼_Ûe†'Ç×âïj&—8 4ÊÉüJdjº{ßt=®]ÿ>dáŸ2mÛ´OÆWмcö£q„²t‡u¶°<@iÄÆFüX>ΣBª¶³ùÙÎTyö+Áëtê°MªY$mö3ø‡ë‚›¨íBÔG½ð³VZÜß$‡ìõxuc+áŽW01)M*„wcôº•ÞÓ8‡é—Â|Fx{±g÷b€5bhôFz½«èûm¨òNM\¥+æñ‚µžÅ9Š©ÂŽ ðÅKRH΃K %ôºwîBsæˆÓȳìΦl8Ý6³Œµ°;.å…5ù5¤0Ô¿«u“©ç·Ÿ´e²xÄ“tÛ¿7kêù4½2€¦¡7ŠMHL–,£B"ÆÝ@I»ÑH\>VóUåÄt±Ž ‘lÔ{ DV-|¾tYRÙ†¦¢n¾E ÿWë"~œ@Æ(/  w`¯†æp|泓سU³&@oAë27A²Ïر}SŸ½¨h\hEÒزe—¿ñyZ 'Ñ)‡V¡fz¬ÁE_—›fh’€€¨7ƒ‚pÀ5\¢íÌTÿ9ŠF¡ˆ÷æ¼VÐå¹G§BÔ¼†Á5­Ä•d› |&£t'¬;Y¨AÕC'$ÔkÐ#lv½²ÆŸ&¸¢aBÂ,ž‰’ĦxVÖ’û‚÷i/÷¥(…'Ü.Å>C€O]k¨Þ ~ˆ/xRÓ0 I8ÒUq@‹¹ ¸U®¯—Æ÷ïnGN·úw ÿ‰rÅœ±F¬s‘Ž›€Ý÷N(G“Ëw©gtŸy:Ì &?¢í>ïHÃX‚EÛ9Á¿¬c2Vé]1`¹Ãù`]å1Ì<0/»Ä++•Xþ «ìÅÍÂÒ~? #ÿS® )Žet[ÑXuðá;_œ"Dx‰¼qlULTíX7&P|7š(ЄFZÕcá‚cÁrÄ2­Ä}ζ ™èÞæïXËh÷ôÅ’”½Æ A/nTð³ó;ï0™Ú¤³@dK·ñ‹•” IoÓ]ü‚/Ó`W@t¢Oƒü®u€eò"x>Ã{?O¶UAd2"ûŸøþ](ýîÖÁ.up}renic¿éÌS¡>\ oÒИ­É?@ÄÖ{ÑMÚ1¶BPJò=l­ˆ,iÌÁŸ2ZövÏ?ÿ‹ÕuJĬ/æ%VW~ûZq)Egk"øíÑÕ ”búµáÖ¤Íjhjßq(I'ê€ßÜS¾¡ù5ÓøÁñ‡Õ±LÖ'Þ]¬þ³šÍÖ5‹@€ý…£V·x›@\z9ÌèõÅåW4ÐU}@nÏ&ÞhÕöž´×Ž•RdÖIp± ë.Ô!À~öC8wy õ:ËuwOSY*xðšGoZÜÅÈ ºf—¹‰ô!? 3ø$@ Â$bž%(ÄçLuˆëE –t¯‚q¡­t âÔM’©˜í}jâ§m¯qŸÎãŸûÍœ&ÿâ«̯²›¯Œbï¸ø@N,a4´ÄÀ¦‹x­NÊ^d=¨|¥b†BS©){Tu.* JJE!k½—ýÑhÖ&HÖ?Y‡WãäQëBÝÕò*q2ˆ«|3S¶¾}[Z®ë(’¿Bæt ªòms ÐêZØ_Oieœ"ïã—VWÿg«ê¡NõŒQOûÒMõ'Aõ>_æåÀ|À¼nÉ…›Éì$ÓÈù¹;·49É&’€€ÊT²MOBÇ«§“ÿàx)™e•OÛ¦ ›Ä¢óþ61¹à¿> A'{‘1î:0gƒIV{ëKÕc•݉hVèt WŸVÏŽúCr m%<ÕcC+"mñºO{Š?,µ´«²ªG€Á2ƒ©TŽÜ©v~IÖ+£ ûoºËcÝ+7˜íín›´;º´ûAÝ#Cg›; •1@…€ßÀŒ›>‰“Ž·q”Î[ô§‰N¥8S—r%ÓTôÿå°˜‚ŒÇ±Dá ¹ˆ¾ÖˆEPÂHA¢àÃ!SìåÞÖåOT¹9¢þ3qÂK¸e~'F0jíçªß«LpQ¼5I¦ðè§¶¼É•*: àÜIT=»Ë&Ðlß«ÓÓ(êro«OQŒ} ¦Ú ,–Õ« uÅÎ(Â6ÿm;õæò-ßZwl,,vf_ ‡º@š“# 3ss§úqv¶¶3o1ûÔOŸc<žØ~>´£{Ai¹¡XI*¾`~ÒÕL%Œ5A/®0D+æE”ºUssÄÇN¿…ƒýXýªÝÝÑ´jìTö±±Y$2‡0ÓŽ_Ž%ÃÎC­AƒOˆt2J¯ŠÔf‚œ'/œðDð'šùÊÇuQçz@obJ ‹¼JpưЎ¤µºìe5Àð£’q¨ÐHìMÿ£¦Ä6¤ ÊæYŠ­¶a´o¢*Ãïr½í @0ÊŽåµØ¾/žÎKþ¶,SÚt¢nôâK£ÆwATqf±Û+\Œ•nq],ZM!§sxó£§*¬¬]FW˜2à#‘8èbh;á(º†jn‚xÙù;…²óçÍèøàÂïYÊÉ¡òK:SéÃɹ-2é‰_#b›¾Ýà¥{@Ýdæ–ú9‡èÒÚÖQo‡º!ÂeqUUºY["(æxù"èÊØ”äBúù{DhoΞ5×?C—óµF8]VI&[É›þÕ«Toøï”£§úž«\;¶Lô¾LL‚ 3ÙË…´zÆ' å~vEþ@'&1öÛjŒüt~xƒ§Üæ_¢ [ÐÙÌI[cþrö^í6€¶óßpÉÚ ½u€eô ²ž9 Øvc¢è-à”ôI·Ós;î!G­Àð¬ýq4jÂã¬CDQw–ðdè=àk1…=–ÚärJj•æqÆìÁ¤ëq˜á¦1·tip|r!#N,­Æ(ŒÁGŽ–jÆ)–åì6ú·w…¼ %KkópŽÏ`êhÇZëòYâÛðQ¾Õ·Ìt¨n×øùYÊÎTTè$m¥Œž #‹ùcÀCÓí>€Øò %'ít-£x…c ßLU?Õþ)RÊj;Ž3;‹ÊÎ@(¿šøÄdý^ârê´Ûó´u<(î’‹`·¿cQÜ—L¹>z.÷¨(ÜÖ È]æ^éø I«4㊵kyÌ3„”¡¹ Úd£[Yk^œDó·mç.[û_ï?Å 7¼YŒ67Üs©[…:¢ÎˆM„@Ü»íB>æDg’º•|Ã!Ýtz„¢@âbâ+<íz¢+ƒJ˜î#ã¡—ýañåRvggªãäõýŽ¡ïMyÚZf!²u¨^•³Žšs8A‚=+l£ˆžvy/c8™I]LÅA(΃¥‰ÕÒ½x—÷d¡ú UýxÎ\I ¿j媞)äŠXÉN²{™eqÕ›ŒàLª!*î€v»é/Æ ¡ËÖâêb^›ŒÜp®gVʇ;–3˜€ŠÎ0ÞôžC¢'ÌØ¨ÊDúµ:xcó¸ÏÝ^÷°hên»˜T1ú¸òõâ+|Ùr=µÔhÝNÕÑ„L¹nïÂ+‘ƒÝ4)êIý(¹ÇÙ$UmpZ÷,w)[é”=“<ÓÈ_I ’ÂÄYÚûÉU€dÜED¥Þ•¤„ràèÐÀšùYÃÓ¹‘Ýö•ãϰ°d—ÀÂ(NîV"éË‘7õ®dÿvÑG(›siÓØˆ(Ž ‹\}lÞâ™]|‰×ñ«3U¤…*3é‡è°s~Ûqî:¿‡W¥™Yðs_Áþ.]+€Ñ¿ÍÍÃ'#má}MKüñžeó•*PäThPÂl ¿×÷»á~+ŠÇDÚ±tH®ÉËÙƒ=¾’€€¸ÚãÈÃRh· %½ÒD¤ÁÃPÁã2¼™’ú%¾f*ëþCb¶•@&ãè8K.ÐV¢.€™õؘ,ã ‘6àùøÆdÃîφ•Â/vCþÅhL>ÌÍ!–/1M©:WYqëó ’€€ÙäÞRT*éÔ˜VSSG¡Dü.5T}vmPë`5Ù¹¨O¦íÙ) ™«÷û*éfLBþèGó ‹õ3­‘ÙÒ„…jùîdZáÐñ+°Ä:ÿôsCC잇­XuÄè¦PÓ1Šî Ìôì®(ÖÚy”QÏÚ‰G<"dXCÍhu˜×Óy¾•®é 󸨞Æü‘½ã‚Ívm£·(D ,Âeã$¸úN󊮬†6¨=Éü j¹R&^ÑWËôÃsTí›4†§¶ ïËYÇ›WÝ¡^UÖò•Êð¸Fh>7k¦”¥ª† ¢¼?̾œ£ÒFAß®¹®ÎÅ æ›sEW½ XØjòΔÄÙÿvN²H’¼v%Õ{­:Jˆãõ|žì#ûæ…†ÜV55å'6# “Ð%N—x‹ -ö=-F¶Y¨“žK Åx’&=‰æ’žæuPg³B›ï%0ž]R¹xÔÀT:úObBñ Û'ƒÉ–Áž‘:Ç4¿19lñy'¶\†K*>¬GÚÿœ¡q|wÖ#–J¸‹ñ~\k¬2»Ý ß}¢Ùk]X¯ƒÆÄr¹!l÷<ÝEÒ)¼¹nƒl(5] ·A««F¤XdUÁ˜Íuáå|×Ñ4ØùiùÈÂêX¨xI¡WN6À…~ùš ɹuj,# lXBd§«+4¼|:÷Vä vsïèÆr@žgHëìì¦vM€Iæãêo]~n<ÁtTÜ/ò›DÿY"åV΄à …@¢—t¹÷=»íJ*?ðN°¸Y<*5ƒ‰ºz™_˜Ü$¾¥¤Ù¡U¹!E“hÚw+™ç×ÐB0¥jR e•½ûkþ(:ï;Šô˜Ö©t^;¦º¥•›n‘3®”r-2A+•€D´¨Mè[‚Ìû3ØšÓÉ?ŒãðKÒéO{å1&ŠêÝqà´õBˆ¿ó‘j ÛHÂ#½éŸâÐWËš­jŸ°~±X$Æ•º’Ô‰¹Á£¥%'IŒDm“x…ì¶—Ÿúª6eœßð)¬vz§Ûb½ì™ÈF¾CºÔ´¾Õ‘ÐõëNé+±zT¥×H§åÆl*¥$ɯ0¼k½[i/‘ÏGø@p¼û²ßÀgâOÙá¶@ž&ÞmbH6‹Áš«º«PJOp ŸïäáÀ N=ÎI„‘ä?x|Y¢ \HÎù!ð'!cmBÑ´p<Œ‚€—Å1½j¹÷è>€wd‚jøXÙ½&2N#Y%;/4›ÞÔד#ëjÚ˜wý-Ê×Î]Ýx̳x!J@O©ká_ZØó½±MøØÖœfžîº ²n–]QWÑ1ŒÜµC¬üŒ‡æ„·¦á&ûŽ÷2_c_,¨‚?"X£¡ùé¯ÿpGÿ7X‰‘±R þRsª¯(Á¢ô¥sÊÙä*äçÏŽbó+gšITŽ—ýùI}…$B|cјÆC_ÍÉä†|»Þp4]¶â ¡Ÿ î,Å ?×É›'dB’|be}²'[Æmî»h…Øk;b‰r!ÃÝXÍ1Ò†óMík@}4…2Ђ¦l ]ýÃS¦Jg1/óOMžYöíÏ›;PŸèf¸Æêji³gÎκü9\ÒRÙvE}\âÍÃ-Ä.þ? õíÝû3ÓÄØÈöICgx9œ±K±-šrjDö¼Þm™Ïj£=²Ÿ’ÛÑ.õΈ}Æžò¬¼ú^ÏìŒfO~¸ôغªÇãòoŒq)O^ä’€€³©5RÌ9ׂî}œ°‘^ñt@¨Hÿä7qä¹Íþ-#ÜÐH˜H«áû‹®Ì MtØ×ôwÒ•£‰H:<Ÿ%Eîˆþª½¾uÜd&À+ ž ³³Qwÿÿ\EsB,Œ[›­øº`T8%w@U ZùdG•8§È(vÛŸöÊ5Tã×soó0B­ZBÚ¥nh‚cîK¸Ãâàc]àLçÃ×1‡°|QÎTÊÂûöÒ\ ’sœ»l龄ÏEbØÔS¯>G/€§Þ/«jC“Oñj#úÞõÌbTÇ‘,¦ø.½ê’zÙùƒYULóƉSF××¾ú¬£~>³JòH‡Ýñ"•J(_6Ÿ§'ØÔ dÌ/÷"ÕB»'>:òÝzá R‹ ÿü.1÷ð>I¸a‰éG÷ :Ú”ɇáŸâ2ĺ­FKÐxÜÑdŸ‘߈µ\ï±}ðêÒQf™BI-|?«”зUfú„íÒ­©Ùáq~ 8OëNO „}øí°BÞBx€3„\iy«ˆž#Æ:(¡=ÊCÁ·B‚A”g+vŒÁÁAo26z²4í¶P"wóz¤ÈôÛ$p<“ 4 =ÿV=F{vn…ŸŒÒÃeÞž'Àº…#d[ÒE;u:¾V" -XH¦c12tÓØM@v Ÿ}ÔRv`RNsO´D´H#o7™éÞ1qÊ€ôØU-àjîe¬½Ëñ§Þ¤Ð”ÆMH\¾¹Ü¹æÂËóÓ£ø»¡L|Ä3…!&ÏDEªò[‰}¾ïÿÛ”gDojßñ59ôÔ tÄ•;¢bÐrP\ìÅDÀB š`Ë%],de¯ÞšeÌò¦mÜZ<¥ Íl»órãÄ©ÄÌ›™§þ$n²„?wqïeŽqGˆ`HnÀ³>Öî)ƒ¿—°à¹Q`&½þyÕ½ÛEômõér?(f ÕX±M7 ‹«ÏäT²(ŠW-8D¾™áÚ±‚U [àƒB9„•ØRÖd™4ƆºUíHOÂÎ\$Ô)s‡m$®xV³Ê¡†*œWÔY‚|¹ïˆß× ’îþ®ÇŸtˆm²Ú-…Ý@Yr™¤ïîGÚ%’‚Ÿ›^¬L’ãl‡8Vxßø9×u Ú­æ#Új>`TÈa0bŸÒRð‰u7à÷Á4AÃVïÜu¹®êæêìc¼â ÆÌóÇ«Íb4Sßçëý_rwŸ» ÝfïdÌWQT×ÍkduD˜¢ó1—¸¦—´PHÊ …»°?-3ólæ¾$YR†bÄ7k :ÿãënÔò”õÓ‰8BIBˆÈ÷€µH·vyÚÉ·Ÿþœñ¢‡T¦üÖ)Ðö*{‚û†85f]è{$j0ú`Y-Ô<êD,ê§êo1Ïð,°D]ï¦eU¦eA§¥ ïêOQøànû !…pC9KÑæŽ™ ¤pó™ñùˆÏت%/íó£|,a…ŧ g4×Ù£ƒj÷6éÒLˆ•Ï+|͘È×]ðyË›n\cp¤2—gÑø5š:` N ¾“ÛžQ ]#AZ'[Øþq­q€¹ò¿ï§t … ËþÂ=‘ ¸s”¸IG¹]u†Ø-³±3§‡y•‰Âm*$›þ]`‡ÇKøÓðÒÇßÕ®×uÖÕÅs) ƒÔ!x¡¦¢ ]h í{E*™¨BebÐ%j ¬Ã[ÛKc34¯Ð,ÄÒ µÇƒYÏn—z ×÷@R™=” ´ô Cgô× ê\A°ÁÅ ²–Gš©RÑcd¼äRa®C%ÍWb|Õ·’€€Õ–s¯_i_šÂ*…›®¨“Aàž`ZòðA,ðcéÁ$-xGˆ¸-ÇYA½c½AÊÿ_àÛ/ôèñPø06J ³‹õFy(™å*…w™ýíÂIyï À_ª£Ud¥{X ¢0mœ°ï†Þ~ÃöÆæ˜(k*@âµ^¨êÑ…•éÏâ1QBÒÈAhÊØ,¶µi®ø¤ö‚<õÝ¿<ƒ·Býƒ5ˆ¶.h?”‰K"˜ ~ÔÖVþÛô>KÞ´²›!hÓ=TÇä®#ARl]'áVDD»pbl˘WØvÜJ²Æ¿ê%¤`f_¥tmáÝV›Ó Qnvy¥c.TgÇÎÒËU~¿ª9\RiÀí83ÒbJ€ø ’ß(мµÈäÉÎÀ!æî"Ýæ8ñ[ÆSvׄÿh?Š·)ôMÅ[Ú*j•y'©÷ÜA#?š—²ÙFÔ[w&K°{²kÖCcYÅZL-?àeþ)“¡„qÔ¶VFaèW‚ߺ‰ñEŽáR¬ï„¹¿ÕÕŸ_ˆ—šŠøË‘…O,©é \ bË…Òˆ¨%Äg5ñZêÙÓtØôÉÌ3ÖjN,hmá6?1Îô×6ZæÜj€Yõ ÐÙ5t|C„;! îËå¼BPŸ»27*š#8k|Ê ûn™Ñ8K²œô=ÍÏçÓÞW‚PìÚá>©‡Ì»ÖÁ»9X’Y*“mË2_¹«ûÚ§Sㆮ Q¨,¿‰BPy8Íbñ¬„†)ÙnÂE×DÀÓuBxí¬/ŠNúD³I© 릻ߴ;"§pW=Ó’âF„„Wæ¬Ó…’M% ÍQ—¬(Ødlš;„·-_MÞ;‰œ“Õ+ÞÚ<~µ„u 3Á$ƒ§SGó›ÓÄT¬fŠ“âþCÝå½è^.éœûÌüŸû)¦FµÐ¶ìuÉÑX°çaÚ¡¬T";˜/”ÿSÉG*c‚½Ií\÷qý5s¢·ƒ1Î5ýc!4ÞèöãW¾ ¦ZL«‡D<²éô›Øû{õOÌù\J•.¢Ìï8ï+1%~V-:‚(6QÜ øÆøÀ+T¬-‡:âÇ_÷KR=œ Z|ó/‹0ïpÖ”Ë ¯Øöþð[@µ2é 4ÆHdÒGjžYý·ëÖþÃÚ‚ È0óWÐà Ùö]<¯„ÕðCJzÙ°®›3w=)gýÒKW ªlɬ[Q5oÞ¦äK7@PY‰é€´}É;N+Áæö`@‡( S\‹«{»'²À€ön‚ÞäO%›,N ¯Ú¯c“ÜÆ½ŠÕBŸ³Ù˜“’Íà#^x 0<Ýê2<îQyÚË›ˆw¾Ö¤|Áõrª=’ÃçòA Œäã#Nó°u†!¬’­Õ+ŒÞ.îü;²;œÐK¦¥‰az¯_ej8ïQ‰¶h¾ $†Í{ *r^ɰö`ýRV öÁ“Çüš)Sªr8oŒš?Bÿ!ªeXgjó}Cñ<BûÓ#û#c¬|¿›¼%Lh?ÒPÒçdÒ°q¾I¯{^Ðí·• 3Äú§‹!@Cÿú”,£Îκ¯Î[©ë ÿ¹W‡¿ÐªƒÝæñl«Óã±ÊVSiSÀÅw¦ xªÉøô·ïÅËS‚>Y+Ýh^îÿ1!Ÿp§g"ܲGØf¹ôç^(d¾.Z+m­y©…¥‚®à eä’Éw%;rãµýë »“9£eÇIì3åjg™måì?mšaåÍ×|“ '×øj£N8²‹.aß#QüF½Ê[’­C* s_ÍAû•ëRŸž| &0Κ¸Ø™1•ÿåúgA×®CùâD[.W½}œ¹E/Ç•@´¬èÏ®u­çeù®¶J îÕHqå=së[ÀfÓJ `*ë”[9öˆ¦¹äá‘’…îC­e‚]^‰i:h›HQåxO¢oÙ£›9zùÀvÛ…[„fÓj^j½i­hÃòY‡Ç™=ôd‡Îæ¯æ ßL¤[›–ñh¤`°ùΟ!ÝÊ,1×O —éÿG$ˆÂÕéßìúb½]‘-ŸeíowEŽ’èÂa|¡Ò¶‡¡‚)ºíj?²SÞ»u"27#%› ýÁµcbq”jÿfãÖ¦+¶ã[$òø“„T[UMÉ–7Npi®'ü­ðV1×¢\ë]¤ÞuTàe#g@Ëj·oNéñÜÍŒ¸2ßs„H!vÍR0qSâoW%š°ÊzE3JRF7B?â7Ñ.÷x1ädghØW,|øNÖùgÌÆ_ɶSµä±³’€€—(µÃ°Å¶Û÷ÜfôAÌés¥Ƀ»Z£ÝZ4ÛûBó´ãÊ l=ap¬©;S7úæ]³Xófp¨Q„'b“sò¦<…Éx¶ža‚Kõì[áófyŠ80^H’q¯¦ÀXÈ›ªþÞ4œVdßÍW)!Ó€JŽ”³ó¸Íœ²A±Tû„‚8žßß¾øhqöŪ_Ü̼XøjmÇ Ì‹†çLú‰AÑ«ÞÄE#tL¿ªÙF›ž@_ù;Ø6Ú'%ÜÀÖí©éé*ðÏ3Œìú„Ì!qëÊB¨š™èÊÈåÛ&¶`­vë6î„×¢¨ÎzoÅû‰ˆ&#>Åñ§ÿ6ª”{¼Äð_»ÂӃÆ.dF7€Û]à„OÔ>C…ÿq?Ç_ø'@æÿNO­'ÊÃe“ïž0»ÛçìÖ¨ØY†Çþê0Oß1’¥Ùœè€j›D–ÊÞy$~©1àPÌÇ3¹Éc/ŠÆÁúÿ: ((5iCÞ¾Qhª³B&©Ý0iqõöÄ,0ùE`%@Z˜db#u'LÊ1L’7¸¦ÞúT1 °S¨gÀ@±$úÍTu°‹)jÃlík ôØKAmÚ™Wk‹ªuN bh$£Î4^²$m1¬;wjþÞSkîÜnµv |újÇA”„£Ãú›S)Se¹ÜdKnõÜÕ,W©‹7°P¯ZÓúv ½9¿dYþj™§!`)Üß}º¿w o»þcä`•„•æHIêdÙIÛ¦äØ"ÌÒM…hшÞH~Ta3’vÓTü£ÕI@¥ƒPw¿?G÷' !*g§÷²gÐÚ ¶U…û‡¿5¹»ÛDžãoÅîII6´|ÛJ„2L~ç\NÐ#ünüK¦ýl€/µòˆl$*:"Ð’-)!Í"aäT<à†y0Ï.à!ÕQcõOéñyâ]òˆÌ±Sô½>ö˜úžE4÷>iþ‚8#Õõ…dzã6>u™$'äþÕ7¬À{_ß…ûKë•P­ó'okèóx5©]6Ä-UÕbYF)zô"Áð§L[èo°,Æ=#<ã¢OQJmʺ†¶€5Þ„“âT«‘ÁøH¥eÛz•r#z‘¢žŸµ¦“‚ 2HÜ聆º¡¹ QcõðÀ)§{Ô ýáä³Á`ˆ(æþ¶?ýr¬º/)˜6.7þ-i×çCz®†Ælö8ýnp7 ð/ð?´˜{H÷Jö‘¼N£…0­–=~÷ÔÅï~ò¨9üÑX¹èùpKùã†iá»ô5¹b$>c˜°‡Ã(¸rB2Àç}Jô3”"·Å¿Jwa$&«{~îï±jW•6¼šÈ&A)KÃO®’á[› ;Ÿº­ž­øÎ°2:#* q²(àšÊJ×yŸ8„"´CN)xS«T­W­\_ñkš¥ÒYÊœoCÌ ÷Þ-¿¦u£m r1„ýPo¦0íl _š;°•>gËB'äÏÁ½oÔ»=ÄE‰#¦¡Nß}±!ýÄ=“§+½u3]Â?{¼j.¦²¾”…eËúÉ¿p©J^¤PëâûÎbÖà‘ Ø$çc6%Ηç%ùùnUÈ$Ú'q÷JVòÚívгyÛU¶1.Ðm:nñ˜êXÃLaøê+JzcŽ„/{qO–›üNÄÔŒ98ŠZbÒXQU¥·ª$NuÑÆúކó…çKMyø>w¬JÞPrZÍÞí ZóøQ"V½;ÊÂ\×—¼@BÕàİÁô4ð¿<üèš1'×’€€È{)ôÕ–¶àºÛm…sÏ›¼'”LöÌ’ýZˆÑOç<˜›°4øÎ€GT˜q ã}t5X£îU“ˆ1¸L¥)9«Y(¤Q£Ä«lv+‚M!»R8Lí¢S²nLeË>?°35•§´_¢_Ë~»î<"¨ÑðÔeË@,8&0Ý5ã ‹eM3YÑ…ëËežc‹[÷ùì€jýCrœ#'1 F»þî5ÆŒãsÍu…]p]ƒÌ™´ÞØ8µ0ÙÌš—}°%7êÁ5Þˆl$¾»ÒÆa6ñ’ÿ€Ó5¼`G0Cc{˜é‹ˆ6'çÏí1Ç%?/'Œaý­ b½˜;Ž+Ù¸³¢70¾CË”í«B£\d^t‹mzå(rÏÞ«a ÑH–(û'J¨@r(ÔhûæTEbß`7I¤(ú:Åï»L ÿ–£¶n¸oéLâtïZ¥(_ÖegZš´yÛ‹ÞïÅ3dz0 ø!ªIé_à‘\ñóu{—Ÿ…C`nˆ•[³H³dϽú½%P8žäd5We‰ÎºVšÍÛu•#·µÃú¹ŸS° ©YÎ:_ ÄoåE{¼È~Ž«ê82³ ×¢gu>ÝðïΪM¤þ’ÐÊqǶûMý^µ)>Ws¾òõÎ üË”e½7žn|=jÃýÓšr… l§ê¨àéW#^Zƒ$s¬N€”ÖÈð²|p>$J{vxãË‚8}|ŸQ­}:v˜Ã,ÀYèÇ”y…¾K09¢–Ãß>âIÅåÕ¿©xχDÜlüâ²§¬³j(ÙÇš³Æ®Æþü1ÃòhàííŸZé+O±Ï¥G.~ñÝj§!ƒÇ¢Ua¡£+Qï2ð«7´2Äüó¿Uº1v§ñR#þ“'Eë`Bcz ¬ßÑîχ»i;L#'NYÃÛ ²OtC Ô‚ãÙ»<ìYÙ—kÍ–C9À¿Ž=¤Ÿ}Ûdïf¥oÂT‰þ˜*ÇÏ `¹…­ð¶•Tx$€.YpTÈ«}Óè5ÜÑÕˆå;1-i•-·ç-A¨ñº¹²!pmãi7+¢Ž #áœd$ !|}:6DÕQÌø;–dÆÖíæJÃí¡º  OÊÝ£OϾ`½â== f¦˜2—n¶%ŒícÌÀ³rìa§,dš{5T™|3«´÷ﲞóÂï¶pö47½å²@ˆƒ¨"s\·Ã¦:S¨›Î Y¬CÈà‹²eó×*/A£¤Oßi7·J³9g†É”}G‰GÛ©b]›°íú ¥T/ƒö쉀®DE¾·*½È¥Dkn®¤¾ÿƒáv“¿Å×s;Åχ?l·cÜÊ—•A: ò…A'ô’‘¹êžBâó7Sºb57¾šwsã±rF·Áõuªq2ãLäªÃ§v=hËÅÏ® k”T“È†í ¸.c/Mg‹z½]ß 4§rpôªwš£SŠðüŠ©÷’ƒGàJy¹”Õ‘‚Ö…`Nc èµÃoµNÒâ\¶€½Ž¦.Û8ÔÞ€ pÛTÝÁÏ›Ÿ¢"!ÙòzKÒÌú^2¿Ã K #ξE&\– V¹ÙÃì|Ü¿4^r‘ȨóaáûÚ¥'÷¨}g× ÂþÛ¹IõËŠX½+è¯G÷Bgør6‡úCSîÑËPQ¨òུùcÕ û—{¯ž+ëCeÝÁQ5MdÊM赎6ë:SÙ/càþ„Öø¿òš•kÃïÙ¿È”)F0V¶ Ê´ˆÊJSwSU¯±kñÙèf“e#®t×|ôõº~²]=\•Âèþúl ˆ¯ê,‘™¿Ö9.{Ž™—¾}’;„†R§xŒ@ã<úâ§¾á=´Gj±Šã«ò1)ªÜýŽm4UÞ‰º# yúï$Ê:’€€Êj¸#S¸úäþ¾6D×ß?E‚Ó˜=› Å ?yn}P²œQðkF.Nö‚:#ôë-ÓýZxGJ&Ӫ暷–VÅL˜"uûhçÚþ³Oç^lè°,3ÏÀ€øÈ²+z4>¼jãÂoø— }Ì©dðZ„©Xït üÒª ËÛa.%…‚±í3"æ.$í$iM ‹Í%-s/¸­ØÅ´‚ˆREJ.³Fþzƒ(š5Åq]·˜ f¨ìY7ê¶4³üʵ-t6:ýöÖˆÔ”ËM.¶$Z=ƒ®âŒJ§§¢§† *÷Fê‡ßCPeÿt©!Nd;Š=&N¥cýÃø•5ƒW-¨ÜáŠU~H߯€Ñ*œ¥ÀÓ[Kò5-yŒ™öÌ:Ó%¾ s/bíúYOZ' …{¹®Y`‘GÒju'Ië}Ú`t¨¤.üðéËæ¼½ ÅÚ7§PJvEÐyNlžÙÂtìéáÉPƒòë ?WÐHþI=µ!‰R ót‹ŠñÓI'„—¬¦‹¶Þ Sx.\Ax(ÐJ3í¬ 8~ÒhßÊ-jOWÊ9OÛ!£n6¨j#ØÙ…×ö8ñj¦p“`Þ»+RyvQGÐ6Ï#½9é;­ óŸžø–µ7ö g俨Q]öÏkÚ´®;øÇ.]–‘ÿ{§óB:=[³Ôæö}V‚[Döƒ®“å†,EoD@ž*½`îLéãFüFê»À¸Fåû0¥#þ­Žjõ%±`–þÆÀWÏdÃW1ç!Åä$HG:•lÌøOn’¨ŒÅ•5 ?ëÝ–ÌÏaNXÈŒwïβÜ2ñEÖSWp(]Jzqh©ÊÓ’ýñu–\ × å Æx_U•F}._ê š»*`'}#à…¯cHÉPÀ0Ü;2T¦FWmËqñÀ?´5åò@†ÂÇåˆnÏvFí½·/=A›FÓš1÷‚Ô ’€€Ôjšj2ÌìN~«JƒuwyNÌñ)p1RòH–Ì£˜ ó\S¬£Ðoà,„!v¹b\Ü•3äT ½Ý@>6‚«°OpUÙcûné!ãiß6Eî;ë§T±•¾óè¨×¢§Ja\Ÿ~Àý?ß©m‡áNè¤YtazéNé‹CþÕ?Ø‘m¿vqIì!Ô”¦§ ˦g"z˜¼B«Ë)x÷ëlä(ÛkïÊz¾zÝ5¢Ü­‰bbMÂÙ'¾£âa5T|j¾¹xçÚ×#Ê¡ªÕ¸¨¬ŸjÍÎÒDì©Ahü‰n34¶†½_ýÖ¢g»Má·p{¿C©°—Øœ*T’ ««›ÍêN®`:!¿¸Kª€)ŒŠ1o‡ýþÀá ãðe¡ÂA¼5ú .Ž .-óèüjå]bhÙdñ9¾¬Æø<}Ô½+cÕ&~ŽR&,§§•ª‚¯Öï†m˜r© ô–îWQÎúϯ!©¾…f…êtý5½> ¢»yêbh@ZwNw;jÌ#sßíDQ•éø…öj*ãÒî"¾’”KL¦þ»phae2Ô9ÊÍõVö9jQøÀ® —¾ h‡ ßŒ¦[ࢗӭë°ä d«7<|[œ;}tà廩:uËwGØŒ‚²vJ"厼• ©Ð¨1Þø‚„Ÿó=¶>ÃÐ5˜´“‰Îăs–Yi€é? ³O'u« Î ³íÎÅbl%eFÀ­C£úâT3m}Ý¥kEb$^åÀ >< «¦ŸtÓÒu (VÿŒ:Îä®üHJaÉäq÷Ïü@»¬Ô,  ‹nD–­€*enAªó&-žªSåÿzü\³|ÝÌýàÅypgcÒ¨ðÕ°­„d^ufÙ0|DZy‚7‹0ú<¦¬öFªMµ¨ÒÎo¨÷s´÷ªŒÅ­ ßo9-ý¯uÌ!¤=Ó„(›¼’…ÔLEc{ØÌ,qëØ´^ÐWB§E„¦öLÂ?å—\OÎÆ/™³î…ôâ *dzz'Ÿˆ’wßp±ì Þ¿äðc‘Æ0ܧþÅþ\\‰×¡ðÑòw’€€´°k°;Ѝ“ëZ8*=ÎE‘_"ár1³†ün“•QQìLÆ€aHí`òºLg0&`í”Bý_¥)K^f2þýuj¤Mœ`ú»BÝjýEºíÊ×1ËAC‚¤3| ®¿ ï²aÑ7îŽûÍD̲}›¨9þ'i¼j&aƒÕ¼alVÅqÁ„xèݼãæ«‚|×4~£¤ØÐbyáÇ ‹]üËmIíÇ^Ù]Ú:,³Q¥Gó%ð½´€™Í>=F&M\],(¤ „QæþÿП÷Tsñ¨õ=Þȉ³_`l¿/o8‘h3?áØEZH¶¼¿ØÞ‹«h¸²ƒAeo»T:(àïsØë¢‰“ÛîÊÒÈ4v£{ßÊÖŸ`!ßó¦ yZ8½Ð'çÛ$n!sÈiËnnìsˆseÙó9ºUáŸ,ù5D„í¬æñÛ¸+µcâR„,•r† ­BQæqì¶u('á~r]ËY¯´&íUbÆš>ч•¯êƒiü†Û‰: ×hŽotÀó±>¼Ì#r8$ûmD./Ë-¯æ"h(îäòzO¹ËF½&ð!ÖúÚš 7QV^eéF+.?Äù y4Çzw.¹–5T'|—ôºNsÍŒO6²«HÞ€é*æ7ÿzš:þàqpŽqÝÁF½?S&N´|× zÌ5/…ïaŒ3aâh¹+^Ñ yÀŒ:|„8JOSÜ«Ñb”h3±Ù ‘”égŒ˜]{ ˜D9!ˆ@CŸ“i3 ¢Db‡&Aêi„ÛSÑj³å€ÅÏða,½ÊÞ‚@¤c†ç<:3wà;Õ7+З­aÝ‘!$uW0‹þ/gO޹`Ta3H µÁ{'Y¿3¡U;fë: ¥JåN¡ÒÖ;sçN è—&®Ý#yYÆ%™§«—ÓRHʾU¡hQjDû?£ê³ñhãFcjû›½Þ0’<n¯ùôux¸Tš½dÑ`V=¿Â/ªßæúr¬cYEÞä Œ¶Ü“Þ­+ží)Fº¯*)FÁ§›Ö>ΑWAyœÉT<=ù¼Óñ2Wâ­#Êqï§^ˆ-],Wº-jIVµ ›QžhêÐm{r\áÝ)ZGœ¸dOÇO·xbúò2êVÔÙ(Ë¥°T†F¶7Gq’€€§VßÓPÙ“ýD>ŠÆ\ðNJœýeD+Œƒu~TšóЩ½ûhAhUÝñ*â ‰êÇ5¦žxª£?Ãh¼Q´µ1b£Ú6&fú“Hÿ‹?A³Xð”ï¢wï.ÖVjYa}bèV‘6aJî%Y›<ª×U{Ýí ‡ƒl¬q‚“Ý™TØ©Èo­ƒ’5gù7ê0N¸óŽ'{Ƨšq©Š ¦…7fÞăÄ]´¹´‰ æsCì߀ÿ×,-X©BÌ æDE`:à,Qªªé1bÕöý"šºxAñ[2«¡wšEcÕpìÏ·|Ý#k¿žC}²åYD@„ xUW6¦ËÝ gï€Ì%àþÇbã˜öd PÈò` Ý=¾ÉYo(‚AY#Œd=¡ ñ|øA,`;·spdÚÏY‚YO[~ãüAñy:e¤|”áoó_ž$p,5eÍ6})·„@ÛF¼UìôõõQæQUJÐ=Z=_FgQð»uÍ®?Š84æ¿;ô… Ý6ûè‹ûÇz-oʀ˥YÉì`˜¯½·’¼ã"òŽS¢`œ°¦¼°ààè¨b‰¼ÁÑ ˜.Á!ÈÕ¦økŒÒ+sðI}ÛcØuÿ +ÑÍö¶gÖ4Ñiž7ý‰ë°…ñi¾µ y6OgëPx”!S¨ßåÍ»¥Œ…h‹la×åfl ¡lø>¶2¹ßvÿ‡¬ˆ8‹Ò~϶¿M­,Dòö"fpèÍï(Ø-6iÄÝÉXiPƒ¥¥â…û=¦2ÓÙ(Ù^œ„‰`Õà%k)ž#U»a‡™'Z­‚`0Þ>“†¬³J }ÇØwõ,* ÄÙ ûrŽ¥¦rT±ÆžÉª3ÚÞ¢QMå«t©®KHÂ0?tò–•Þ„å±è5)ò0T}YÜ€ÔMq›ì!Éra{bÆ—îšõ™—ünzEX”_SJìÐfÉ`„…Àkb‚^­–õ Ëì(°ÒãÄ_ˆ¬ EGT]AOv°ZBÓÒB­c o¤ÓU!:ªôŒ@ïû¯RN6®¼Ž{zÔ˜0µ/«‹~ñÅ^·‡Ñ—lޮձÐiÝu6j›*2 -al&ˆFXzˆ1¡,ýÙv±?#ƒ%Ô?÷0-Ëò˸_:Ϫˆ_tO£à†ø¿ ÒPÿÚóNJ‹ª4øE}ò’€€Ðß.°ñ½’†y^=«ûJã!¹xè²C jýþHq‘-n‰_f™3.{>»AY¦Ï§[ðý€¶A .Þ ÄHñ>“JM‰g¹-àŠ;Àìø5G„ÝÄÕïÊ"cC÷¶îVP€µ€b-~”¤:K®‰^réÈ…€ ÇèImnâ‡%¦_¿!eºu&¤_ã)j_›¶Õ%öå'{øº¿¥rJl«…pßkå„|<ÉqKÝ—ýPbÏÀ f†àçŸX%'h†X8<»"±•î­Þ\úÿ~ŸŠ¶6ÄþFû!?1„%›?hûá¿"EåvHOd¶*çT\>¸«)ï«bõ²K5}‹”°[®`ÿ‹³@Žð âáÓȸ'”Ùó%9N9A¬ºÀ~ù?­Nëš#’|Ipð™ÇÊaëåöú´E¤™— vïÑ •úc¹»ùÌ#à°Ý(g6®j!}f[coÙï¾Pš¨@îmb¢^ŽW‘%Ü—\QÂõ¯½~HÞ³LטMdYV4û¡dÂÁÄiV¡AÉßÜ)dÖ»—ôÞ-)ãO~þ—\É…—^­ÉüãšÔjäGÝSàD²Üx,Íëiîʇ¯Íú(g·±ïÅü6k9Uè¶ò¤äÿ+ÊßÑõqkV?‘1ÏŸœ¦“3«lž  $N³¨LùñÁ–` ’w‰¤ß‘¯mUËÕ–Y¯’’Ýî×Ö”lúä )¥ÍÓò~V† ·âlJÞ2:R¨¢÷9„:=]ë› ß‹ˆ€*~žê‡Å>Êâ‡/)ßÕÄDIÂÊ€:¥n„±˜3Îu¥ö ï®Ú‡?öælúÊ9«À0g$˜x:2‚ooK‘þ$â¼iÏ3²‚ð ¸ä‚Ù•(ó¾‚ßV§ûAÔž‚@¡Ôcz…ã GÌ2 ( 4-0, €"ƒ^¸!âtK¬˜rƒ\Q^‰›»%t… Ú~ûÜ•S$2lGë©«@ÈÈ!?’Ó̽’€€¥Z¸zå·»?Gœ$JžOÛÖp­÷iÀ2 #ƒ–ؘARqcg5ªOg¿ –IT×Wß¾ÅÙ=_}ŽÌœXØÿ'Á‹²lï½_¹L¡`„ auý$©edŸÖ+¿Ñ“Z²fÅÙÔƒ]éš[íBß})Ã÷±Ñ<¤ ¡ºoË(=³6bù÷m  Ì9;¿b °¡æK*«_MEC/iÜ]oQf¬\,Ç0s;ßñ)‰ž ¶1{#ç‚âžîL»ƒöÏaÏòÌUçµßòpW)‚ë^eâ•úÒß?¦j×ùL‰1œ{²ÊMÙž=Ã@aöŸ'‘¹—Ù=r&à››gPœkÃŒw™üxöð»n }Ÿê©E÷iá‚ç,@HËON“(s£×ü‹%WRQ†ÑOüî!;ï¨V(Û ¶øÀ90‰µš³ýÝΗ\&nL%+ääö¹Î‡w³á4KEk&7Ê-‹uÂ]œ®«ž=¸Îx$ÐF¥¨…‚ÁfÉ·9]]9zG‘ªã‰Ð½íËu\¹êbJÑ*ª’—s=®ß©^ˆÿQjxêhG£5ˆ¬÷˜–}Ü»õ† é0sŒä+IHfz |—•~£¡& L'º!TÌ›UøI òHþqÂfÕ*÷ÖÜIqÐo©ZTâåóuç-LµžgZëé…\¯ÞMˆÙ.<¼† fQÍ$"„'ž„ˆÉô<[úéˆ "æ!âE ¸®úƒ@p ý ì$Ë YS\•…UT¡Åß³ˆÕ?Æv‘×À%úU£ÿ#ÛˆÙ:ød{_^4­UÏËSãöÂO¸U€†IßRB 6Lß =Gð) ŸPs»¤@F$"@Ÿ;¹I>@çy¹¢ª ´sñg}#g×ì"ãµXjxÀ“PõMýÙÃd¡Ï°Ÿ¬ÏGóîÓåYöì0^tBÛÖ vD-Th„[î41Ïã#ÕýS1Nb|<‘BÂ3uf®å.èòÞÊÑëô‡Ûý†ì~SäPV'ÙnOX:‡?ÄÚ¸<‰‚xÞÄ+P™ 䬚Ò÷ ±©låEcªî>‘Z¸Mg‹„Zãc^œt¥.|v#2 Ö3N¶¾‡Mˆô™&<³,,Oã_¬§E[‹}w¡¨Á'<w’€€­"%¾\†€‡YyH¯4¼”߯WqOÇÅ{“Œ"‚‹³Š°£¯5Û¤zÅgŸÃ?²Šû¯™ÌüÃ=zÔhyÃ<—êC#3tavg¿Uœ%ªæËHEÙÝð$Á₌ýEp8˜®Ö8€†RlD¯k‘}Bôø²aÉ cË86º40¶Ù„ìÞUŒyºÄ©{æÃÖ]ì>I™öç`2)`ª¾­TÚC&í¿MSBô˜­_iz”S¾º¡Á}{ª"c(~Àeiè²E6ü< Ÿ¿Ç&ÁËO oˆu‘bùè8Âïv ‹ã9.`_1-3þ«¶£ãõ¢àµñ­ÆìëæiV ±:عYêHD’c÷ª<Å…‡&Ѧloê^ßêÍÞf‹ÆëÀo>*„2±ã«½ÈôÇî­=âggᵄnú>Žq±Ø˜ƒþoÝ£Uƒò¹¦æÑFOõôèù[–hþñrpáhdmUöÏ+ïø§+ôÍ*{ÐÂÛM¾ÈË] Alͪ=åß(7guUat±â½zU‘‰ÊÙñ¤5Gêp¥Ÿ˜ú1<¾â·£ùÁUТ$ªI¶ä#¿' °ÑínRBÏ@X O†/^šÚm‡€cñÞ[ óu³œÍÑïQ¡ÕªÏËß—€ á1H¦·f<kœGzqùx»¡8MéD@ä0?áÐó±QéÝc5ÿýëèM(²Ú Å“âñ³! htdÚ+7 ñÿZ÷ïârÕý¦‘—ÊÄÈYÔñ;Yø-ª¤›c´AÍrñY$éÇT{XmDoèK¦–fð+(äîÉÁ²58‡§R)d™¢9±ÿÚ8hVÔ—1'§;W{ð4|õz³@b@UpÖ­ú:¶•Rß¹xÃrg!Y_´ÒûDV»}Cyö–×Õi€v=KÃ.E›áiLWÉÑbOluºÎ®ðª˜Ì–7}ÊÔébìgâhÀ€j|W;T¾š КáHoø0¤øe5[s„à ‹”•U3 nrãeϱÿÞ=EÓŠ>‡P7fÒUbxé²͘¿™>“ž\gœ •u›8öÝ>°¨tÅ£­wÀ½< iVn²Ž6›¨’€€ŸuÃ-:¢C¬÷uuï0d’˜j•uLj+cÆæä0±R` Ѩïq¤4ŽÄ&«bœçŽž7ÐgïÉ+<ä–eܬ¼À_JÑvcQèÁE.Ø eß*jQHHۉ´‰/ Ñ=áÝÑÖóžCz+T°Íî½ÐAæÁÚË¢€·Ÿ¡²UÙGÃáÁ²o7a/`8†§‰.7w{þ=.jE鱿äp2‰2p„–åü8ÐI=ac»îlŠ3S‚*$ i>ö*vx߹ʺíT«Ûù‹cŒ[äüûí=ÂaÌå¡ûñ@9à¯%³¢šéÿDÐjËÉÌ÷hæYi6”q î4ñ_·›˜ø'7ueAÖjâ>oà wŠ;£»~8P’ÐîI:æ0¦Q3U¶®…’€€—0Ã+í_Ã?, ›o¨ÃHåœÅѸ:T«6}~"CPö„HšÆÜ©JŒË°“}Hoûѵ9¼á|—*X•Œº¸±I€Ì9•ÊLó5ºÙi¿~ăk®µ0á Õ6Q†Dï ˜ËòðaØšyP$)Ðx¾’³`’ò¸R<‹—=Í ûÞW­¬—ÈNþ)à˜˜B×0’;ÒLð$‚çõ}·ÀÕP_ÔB½€q‡yDhù‘EÉ2èñˆ)äzø,‹ÁúJ]ÖƒÎÇòqJ’E‘ êa«%² à‹é$6†üGQÌù,dè*â5Ûù ]d±Æ÷ì,ª¡DiÍ+L9×Q»¬š©ýñ³Pý˜è·1LfÕ…ŸG0%â¨N3ØÈTL],Ø_ý¾VÊÞL ×[ÍíÀ³”ìZi^·"²A“ß`õH¨ÌyÕëãuÖ#Óî=]ƒÈ]HÂò‰€ÏZZìßæÓ¼mb)^âf‚¸)2äÙÍØùµJ¼0#æÌäCºU¸Í7_ë¿}~¯+zÚâ;Zc(õ×kûÿ¥˜¬¹×I±œß?ã81 ¼üqЯ×}¦Ô È2Ö½ âªO\ í›Õ¼]йrÉëVö¢ð«@x<£jUn%E'zÉ™aú—°ø3·‘YRö³U¸8"`Uw²¡‚óY$#* Y| ×›Ðv`†UªñÌ[hã½,¬¡ökø²ÑKò=³U ³~ŠÄŽb袙2Ñ/’€€Ì(*¥°ÕÆÒu¿øisçö²? cþ|V@Lö÷ÆŠoÒþ‹žsâx+®Å OÞÎ`ͳæx7|ZgbqÍž8¶äj_lzl1f¬pý¾PŠ’š†m[ü¢áÑ <‰ï½ÞdmšA ·©É¸$”ü{0¶¹Bùð­aË£FÁEýë197{è'Ÿ¦1Bp0ŒZ7ÝÊG bê± ˜t¬j.Øô HÅù²\[ÙéPz¤èÌ}ñʪšbW–ÃÌ,‘ñ„…Wz`žsë]2Ÿ†6=»Q&QNìjÐxqßÎ$ŽL¢ÓÅh‚Kj‡Ýu¾nû=+yLÊ’üÑ©Ž—:Ýî“úï ×rƒJqŸ~°ä¯Àõ—À<òÇûh>ºÑž´¢ý…À«öX€™óJT'N‚gÆ…aq[ ù&^4Zäµ WWuÆ:4:JL™Ç'A`YÀÎ7ë­ªŸêYt5#V¨ë©bIMÈzù"¥}ýô€m1aìôÇr2ǹڡÉÿx RÛŠ*bCuYÑœÖ÷ºÁ}wçÔÂ?Ói>XÇAcÐe5r/CûßYT˜8Ê(“ œÜÞMxIÀÒ)¡ii¡„<=&¢ÉÿćôAj¢f^ßa `q]z…±œ1”úëÔmÒ÷*¸ÇC´þp°qy3¾ø’ë{…¥ßy Èù£ï:á‘¶°LÜÕë-M¦$}÷|%‡E7¥]câj]Èï­b;­eQ¼¸ôðuu±joôϧñ7€Â^7é2ødtÎdŠuïw#ãÃj]Ü“„3ØN‘-ÁÖs˜·F±sé&[›S¡q´¦ÒY™w¬¹6Éã« gÅ’€€ÔíÕ$¶‚0i–+Ó“wþ|û.úÚ$ Fnp£Í‚t°6[UäÑú±& ¡×LúÅúW pŒ]¶§ãEÇMK¢<Ïùâí Ž¶ø)úv2ò×§ð+ôؽÿbOÿ '´üH¦Ñêž3i–Ô˜ÔL‚Kqpo²è¦48³À[v@±ã÷§Å?gh£l5ªŽ7aÊ}R÷Ù9óÁþrª­¿qj¼ºqzÊg±¦·×™ßUÿ…ÈR{wuÂý#`<™³q˜âS¡æÃĘÈóÏEõO_ÏhB„Ç¢æÉ¿ðÆÙrÏ|k¯éŽd«Zß@\̱^OÄ,h]s*ô¢¯UV*#â´5îô¶.ÒúøïÏ“2Ø=ªó°ˆUm^{Û‹þ§m­7½G°@~øM’ÚØ„ðÈ=Ô_ÔÙHqw=@CìÜ«nåë"gK\?ù˜C4ØWh‡÷¡ ‹”ŒùƒÿÅÎvlxzL:°ä ›z3-‚´T±s´UòRJQÖJ¹SÀ½vJMêøMô‡\ômú4[?u´ÛqyŠâ Ç22o§ïH ¥…íP7 r:º¶Ê…c‡$ MêyÖͰm³/ƒ«#~êw÷–¼Wûâ_«8YŸ.tüŸ4VE,§­}ŽŒ¦^cŸPn‡$M¢é+×’‰B <((ñr‰ P¤òQ îâlŠÍÔLžðmI’8kK×Ês÷LN\T*jË”W€§Sq’Á|:0Á]€•ŒŸJÿœ@öÙ’Ôá'x’'ÚÖÇ@X¼›˜•=̽+ÒÑs…%3Ô9ŠÚåR¨~pûé+Ž â*¯¡¹g¬ƒÌzH£ž~¥» šÑqáÂrbËx rMjkZ* ã§î!$é_Û¡ÚA4!­ëÒÿWͬb Á~GñȨÄÕàX Ã~O¨Ø†ŠRÜæTU>'ŽæÑA–”®h†Û {hÑ÷uóø©V³d;«eÚ>ÊÕǨ<Ë@„[âØ”exµ¦œçöG½Ð_ŒÒó]UÖZ\*’ÙUbÛ^ó ×U ]fYƧèˆuÄõÖ¾ÿßVËéš ö*UÄvaÀ¯Òß&­â¿CÏÆýöÂz ÁåÂÁ´/~týr Dò•øè:ÊϸØ’€€Èé‡L¹رn®ü‘‹Âóë©?_xãÞÜ3ìó/û?›âæ v›1”é•5‘€çy[‹qfä~Lä‰b ªð9[•²†a¬èýæU89™¦M_®@”b£Ìãw±y©^À’gõ´ð­;Çq„ ª=WϪ3>“Sb%JÄï·7­œjäÌ/…míäƒË-^ßÇR¯V!¢$@Ûþîë)ìKDvqU\:ú´—a_ÈY×ôÁÇߊÔ\VeÏÅÌ®NÛ´/“¶ŽaÒ›jF˜àhÆ~Ü¡³y«¡çÚ‚üˆ !RþÜGbƒÙÇmA†Ê­H+qÞõy'èÅCˆj#ø}™™ ¯V´PNqAÿD˜ïMÑNŸåÏ®—844ÚK/­Â © „¢wâäug#KºY_G59wü†l[¥_9@ûÃÛN>V±7’‹S•ÉËMRpä±A—S)¿Ùé ˜Ž Âð_L5 þVËΧ+ý1°8n$1m½ä´@ÏÏxö”Hw™m·•2»q©2œg»ñÊaqrÉ~qï‚kÿ‰¦Îf!©=ÌÜ’€€Ë/ÚMxwc£r¡¹Ô¿-øâh°,lôöÌÙÙk^ñ¡ŽÔ9øáXü9a‹‚ÖL1„½%-=k`^ìÖ ‰Œ9Cÿ]` ä:”@„Á,à|»] *GcmÙÆÿ][Y±`nlë–¸@Ë>¸ˆÕ+„ÂÖèO}°´< dÐÞñÑô’ŒhÉõÌNaxÂOæ›[OWI`爑JîÄ#4çZªi N˜£"¶­—]"À&^¯SÚL1ŸcÁ˼êƒé5 £5ëíº {ËSÞÄ#xJÈ·˜ß¤HÙèæ!@@ûåU™y% 0Âb\Áâú0 @Óâ,,«Ü|3šÅ·g nVq<°-rQ sõ„:ÈbÅûª8þ6ù_YêåÆÅÒ5†o÷ +·/;¥ckL‹‹ ¹®xÝ^‚;Phm3ÌclL7Ppòþ–Ò†ËØþÁz%z"j­ã û«hg4Ñ9ä»ì´A„pNdרöR˜ÑÆ1g»t ÅPdÊÿT¿UfÒˆòˆe¶B5å)bf)@sã:XÓ¯œDƒ¸ÏMôÂ~±ž3Œ}bùûn¼ŒA™L´·â:ù OÇ8äã×A6=Ÿ©x±(Ö7f*T%þ9®P÷â¶ÆÙ²Ì°ßk¥NZÅmðäÕ‡€ð×â4 1ÔXØ#(’Ûý¯|jX7qæ»)38¥…gY7ŠWUíkíçÆ‰Fõ¯¸ ì7®"hne;Y‘þéiÂZE3iüDÖ²\ç¤mX —‚÷H œš7£ãr5Ú÷×E¸›Ää〩»ø;•æ>Û»eí§ta85@’=_Ð|¬ ˆ%eÉ”Cáptº–y`Êòžɨg0 ªW(¥£ô/›¢ªÂÐZÒ¬é¨?iÙµ"o-´üt¦T­^³M8ÈGP“ Ü(¥K\"ݾÍeø92ò×qnºj1L\lEݹc—ÌFNÖ„£ñÌÎù~Jbþ ˜|TþéUøÎ&}àc‡rìù;½/Áþª>øß¡Jé_:HDÅwŽ›n¹1ÌŠoÉ&70²’LžézKÇ—!ÿ\·X¼ÞÛ–ºõ©§±Ì¥Fb=”ÐG Ad±Ë*éÇ4ZyC=p踘ÆX>Üít6äÜœšÏ£­ùo¸+‹f—ÒPHm`ÔñË}D’€€Æbà6y”¯!ëz½¬Ä%X@¡ä9>¢[ërl.:±9I ]ÉÙ…EDÇD1Þ*WU¶gÖ~—hƒ¡#n'¾¾ËI|Ì~‚93“á°ŽgÉ>¸ìž²54³û8!‰Îòd¾ 0û¬z“ ò¤¸vÁ®+ý;¹H¦FþÈUÙÚMkœ‹ÐA~VEíAã™·&ô6u€JÊà«P³6ÈX•˜ z©òM¢r?Ž4F¯>E#â~»bÆuRT%øŽç6æFL”’47XrpŠ(ÎÖ˜õ~âzZÏ/³lÍMØUt'¬!¹Å4PÊï»û-Áy M)Ei¼€Â°(¯Ë Íœ88ÌËØ¢&èÿtâA–ªÎð?üÓXw“iÛlÑ„V€{;3–òƒîº9¸‘@Ë(µ:q@Ñ–D!ƒé=ñèäÉ™š\“è—¥_sTK…õEç»ÛØgþ­òŸÓƒ•õŠÎFÑ&êd'bJõº™•—; ³ž ÿû¹( 60I÷:Äe¡ÖÌÜwFÛ„4Àlõ?EÇî%;­AUã˜i¥ˆmŽ2Ø5¾ýÛ'u~$ÎO½ª_6ÂÞX—n=‚:!LÑ6 HÛ$õÚB|©J;ÍšY©>7£öYߨ¨ Ë ?-À¤~·Ï{*Ѿ!ì/Íô ¢'m«*½”)Î+Ô0 £jÍ$ƒ'´ûÀöK2Jpr_¢ñɰKZôà ®ýê+¿¼k’CûØ™ÏDëm›ªG/é±9#õBEã ×'ü&#Ü[IVæi¦MÀµa ÏMÖâ"të¾×q‚º»,ŠØ¬;Ðö²wã™Ú°ŽÅ^„e.þ‘á.%ɼåȰdéð\Žï¡mÀ·ÃR’€€Å¼r 0+…ÙiEjr€?…î‹€‹Í-Òªœ€’bÔnrÌé•—µ£Ñ¸ÖQüë[§Vý™‡5ƒ†Š°¬öîiY-Ô D‚ŸË²,SÁHaXãw¾m‡´®;Áj’¤=K)ÉÝæ•ô±ƒû ÝWprâÒê eá VžN:3¡Ñûä9ˆÇñŒ”S}r©ã íf¢ÿÞy)JÝ\ûsž¢X¢<2DºåºÙ¿h;.Ù+¢®ˆ¢t¶Á% üCÔ6’7‰7ƒ¬‹õk-ÆO Àº«Þ‰£QL… Ò ÷j]*JË“·öŸ‚Mk¸á¢^DcöªnLès§jζ•Ùÿœ=5©!q 4€Ë»ÐÄæ»)¥tÁßMaDŽ$®›÷V„=±ïÑ6ì“ce•îϲ‚›êu¨C&jž†ÄZÓ]Á¡e½Q}ÔPÇcÃä\VßÑ‚ÝþYîUßCáWt½ñ9$áРÜN€ÎHN‚ *Zk:Šse?»¯îâÆ2pŸXa¾Õ£½}ÝÁÝàp€N©Ì„S¦.'Ò’ìç 0×þwÒзyhémMTê$».´~ìÚ¹yŒ=GuŠ?ä¬î6¥I8w‚wž4J°›Þ Ò¯+,ð…¦³jd#…äNˆü¼J líK5ßâý]Ï É5qìQ4{å³u‰ù{뎷_ެÏ7;ûºnõ?„¾ªÝ÷š5|ý£NÝØe‘Û<Û†¿Ìz6 #ËùËÒq“ØŽ{SW”ÍÛ·•p¶Š`†|f¶`¸t1)Ä÷͆xèYGøï¼m¢¿äf6Ã?ÂÁ„,ô‚Á.ˆ}¤Vš -J5x‰Ë9ù¸Ãã•dñ1Í= á=^”GTJžknª¾fçä^\±dqLìºïrøŽ{ƒŽdܲ¤£‡7 )WÆÙDÃï (.×l<ä7^ØÄ·×Š‚ÄÍê¥weõ ‹Ù.f3ÚËÒjS;a¶€ÌÀ˜tk^½j‚£-‡¸™™ŒWLt(¯¥gþ1¡ç/ØH„òoúòå·F †é32_Ž É­Üò³[ˆ0H9̧êB%x"éúé÷=’±Þï—Jï•xMô@ kó‹$Þ¤c^̇ùnÅ›qá<½}û¹LŒXðI¦•ÃK^Lö7ü¯'¨6¶OèɺÅɈ’€€·üPÅ1ŠþCU^Ø, ,º{@Á²{X¡BÐJfpËb¾`•놋&J”Ï8Œü(ÔΡ#MÀÖepÒꪟY‹û«gúŽê`·§“r%&Ÿ\T÷¹ç-\!d*K˜”kÉô‹4“»°®ŽŸKÙÙ:|¤ ÿž-Á—¦(꟟¤„³dˆÛ=5 éJ ßæRn¯àðÍ6=MÄxüÓËnŒã:Ho«ûç®ÀaÑKâù;$Hfꌥªœ—$ÑzLŒÌ/È Q…œHË=ÙTªÕùCÈ0µTQ´¼yaŒ¥ ½ J±j<þŽÝíàjüqi.ünsXpŸ¸»‚FtïEÍHÍê‰Ãÿ„8Ÿƒ79P}¼Yž4%Y”¯Ü+k+¯Â’${;ˆ%oj0 ¤Ç8+am`@Ïý§¼íålõw¼Ä<‚ËN€=Ó)—^ÙSD“Wÿ€[±’"M1‹h Ǿ$…flÔ”ãõù,'J¤—ÉûÍÝ–ÐÇ,\-Ȥ·WmôJÞrš{ô’Gtš—ZhÑsljÀ{Z¼Ô“žeµ"„Ûˆ>$ó‘ãîûÝvÇüÉKl ‡ãòçeχxY;i¿ÛÚñ!U#¶ŽyÆd9Ò ]4/¤¼ÛºN+y òu´ÄŠDdÎ<¦ùçŽÑÀ®ãúH»L@u{ †"ž£.æ»/iÇ(¸Ž ’™zHhóÖ¹€¦Ñ¤:ÁigÄAàKÉlþª¯oO œæ%Òã³)÷Ï(Ó ;j_Ûn޹ÍÚä|Ä7 ¹ ¢ª{‚#(ä½WgÙnºÞ%±çQu‰ä×ÂB£Sµáé«c©1¼š&ëòS0·¢Ð3øåI!E–Å¢Îç›ýa$ä€9y(¹Á´¹ .¯éÄåçßæ-186™ŠW¥‡ ƒæÊ÷¢:á£íÚm³ ^®×VᄂœÃ€Ûâ“ç÷Ù¨Á®ºDZ­#ãóVÁê$jóK!üC†–#K?bpÏ‹ u9§Ç*¼°qɉ m¦-ÓFR;ÁËÔåyIOâÏ•¬‰D|*´MñKå\¾Ðþí}y¤’ÆÇÁûRãש´‚’€€¿åÓ¯Eè‘ ¤²W}­KM~( †¬Ý¹â¾}ŸoÙ/ p×¶Ã6ñã~?Ê3”O8B;.«ÑCŽH‡kHi»k¥*—áDÿßÊtC¨ëªã™×ÁMEp䉄k©¾†ÖvèÖàÈÛâWuG4‰Q7XÔÂõߤJäÅÊSÒFÝzÒuv33Ä:¾zgÙßÕ–¬wÏ;Ÿ0VŽ 0ÚtýJž°«9Î7ñü…‰Q:( CE Ìíés÷"<~ 7É»O·Ž&V£ÿT¤Û>ðPù fÌÕ±”`Œ ¯á«÷Þ.É ß÷Q5±ü"Q?®#&bG*wïX{gx1*ü&Ïì ÞÍéqìøOü¥åˆÄ†¿D±¨pìôÙ!¤&rm¸ò˜TÅ›*J‘‹³Bå÷ñÁ’aÕxN"NÈnbîÂTF¡½=$¥É «¾‡ƒCÔÕ7˜ƒÄ€úΧ*e²l2IôÛ*bHœ”ßo¸Á M'†«ñ='*÷×â 7…ÏÎoC’²çÒK#¼o´RjX1Éh„¹Âd’¤†á «l~ÚMŒ9ͯpúÁÊ-ØòŸÙ¡™@ Oò½MHaÍ#L8ÿ—Ò×w‹q*?¤iú¹à˜Û¬dy¾Ï œ»â¤÷Då¢"ð‡IÕ‰BO0¢}‡ÞO)Á=‚4jy­^Ó¦«›ç”ó¯t™·ŒÁ1¶U¸6-`¯K Þ0ÌÃÙ[Kµ<ÀgdgÙÈ9·~ZÆÁ$RèhÃoø}}ZU ”i›Ç¼»{:Ç® þÃ,ųåìŽ~[åõÄ3“á‚ak¤šêøæ¢c•+ ©tŽã°"M5_ÜúÍ‹/íHœ¿›0@º‘j71q¥ ´W’'ÝÕð¿«› >Dl${hp4γ}ÌÛM&’ùDvç#àFcÜnÓäÁ(V„÷‰q¯±¤±<wA¾¤|~€¶)Ö†aµ´¸@Ùúáàû‡m×ÖúƒÒ)&N`ƒ”¶€×XÊjýo–îpÃe–i¼¡O7òD›ðÈ)›åæ5Å—ô #êÐÛ±–× j=‰}ïw f¡X*&ׂc;uXÌHÜQ*T¢±0âìt®…fSîErC£ÎRÓ·nÎC;/@ÌÉk…¨'Ä/Ø5.{¬ «âÀTä)9kåÝ6¶}Ž’€€³õxUE±ï|7Eˆz ¬^­Êg†kùü1NÌýÿJôÁiÈvpú#»R°vïˆ8V>zª?§¦É^ð»ÖŠâÂÊ‘­¶D§I˜{Œ67q5±CdgèŽ šÀ{¾Ë‚¬ Iª0õ|ÎHU+o—æ. /K˜þªÓþNàzGrt¡<œÓâÑY ¯ø³ø?EgÒ$˜´ g_1€ƒ§?Ï?9-(Ï|¡HådÍáÕAÑ…¦“!»Üêca\Z…5t'ÏøaG*h¥AN=¤ò6aö³ò·à£çNoÜñ3e‡ÄÍL8ÄìD3ZT»G±×¨Á1M{¢IÃ:wŒKq?eà ¿ÒI™?`0doEÞ­y;‰Ã—îñ YGÑÃ÷×_0x±’W„½*xâ´hwP¼*d_Îý‡fP\Þs¤Ÿýr›Ùº$ŸÈ°)d‚Ló|¯¸fu…×ïf{²-j Ôžõ›y´‹ 2º’·¦«³Ý…!Åâ9…N/¸Œ )賤Fý´Æa<Á7cb&áµñ®î,–cÚ‘Èc^¸Œ¦§ùÄ0êP×%EÍòÔè·—]\=з©&jD¯øîB–—tà²*èmÜ® è{–Mݬ‘¹náæ'”â:=Ã%P®uÿRµ<±¨ù/“k¢2;BSÙ+‰íåù“Ù/.Ú”¼’̲MH_†_× ëNý“ìçSL+¸ºì9µ‘·óÔÃD orMõ.„eoNåE!AÕ5M÷7b}ÔÔà.u§[4ót¸ÓBº‹ :Estˆ‡Í^É9¤ç×Y$?†cMB xí~E×À×ÁeÁ¦ä/‚)ú—~ŽöY!€>¬Ÿi¥m {ÉT9öÇ4ަ…qO aŽf´k¤ÝS*ÿKC+ñà¯áüQUl`vcšù¸q‰ÙšÓ²™úyŒa­7?µ1†„†A+Üm¤Í„f†Ä©a õeA ç˾YæÕ«¯”ÉFÙ³ÝÀ4:É(ƒÉºâ@§ âï-á´W<Þ ÜÌFDïˆMùcNáŽvoØS.¶Œå"± Wë8H첞‹ýòkÀªŒú‰¨‚×­¬Ö•”5”:º|—zV°íC¸™HZ^<ùœðùâfpw¶´.q!óƒ4y–ÍÝŠÝ5óÎw¦’€€ŸE¶Cød–ŸÜ6 ri¼ø\t“ÏÝ*þ¬¾÷õ!Ší´dyÞ…&Á.ì Ùb‰ñR À.ß67KO&êÑpóÐÖŠ¸Á§˜‡ÏƒG±<Ô¢f/½1w I6­,æª'ô=³;–d¦© U[‚†øÅÏÇ›TŒ¢ÙÊžÁýŒ%@NyÔËß,a&ù~0Ù/]ë@È|ÁW’˜-'mÏ…a¥Í–ÆM«áçÔä#]Ø6þK¨úº×GƒÃ—‚ý4Þ¹ \ÿº4LµÄÚZ;ÚÓ7®.ˆ*êõh|?dTs|«+‘8ïá‚1bñð´*Åÿ!àŒ@n: 6^' ¢Y%n;—:•ø¬Ews¢'­hÀRŸeNŽs>¤45öëh’h¶ºš@ï¾¹!›s]&àNZj…òÚ}°OeŽd à—/7ãÈ :îU. 9» 5yÁLýµ,¯#{ó @/7ç ¥ºÌCÊm,4Ë OÌÞbðJùG¶ñqÕCEr>2À4æm-m>DÙ õ[sÅ1XIÅH .Ž-Ý^&ÞÈ”íSßfÙÆÜçx¸õøS˘–C¿§€’œ*wYBíP)*]™õþ|Íi…I$œ}­ÊÖÓ}°6Èý(¥üÞ¹^½1‘¼žV3*Uô^Ïy©7Eàó dÁÍÑ>É!¬-CzüÙSë€æB^çÞ©š\\?\•Zói!‹Ü™ÕD…N‘©—Ñ@«l:™zSÎuVµ¬YƒS)+€±À(€ZóHÂTà_,!®Vóëã‘ï’`¯yTŠßº—FEX¾³Û·lb¸ðñõëÀíÃ÷ï¿{‡ê‹4—Æ£dI-p9%šÜ&(±»üû<liê|”uL?‘uˈü÷LUN9Թc¹Ò Hä*¿< =”¬f™!åR"Kˆ[ãvÉkIûÇAR¸yVŸÿi!?f¦P %ü”x›j+AÓShE èBfŽá·7=XÔ„ñ³b¨µ _óà äËa“ç@Z²ç{QÌÝŽ”Á‘–-ˆa¤°¢ø§þç4˜Þ£ŸJ¦*{³ËÁ²S?à–Ÿ5Zwáª#…•8f¶‰pþ¼§MRÒ-à—œ‚@S2rÚÇ”âåhˆúÔçºK} »äGHz’¾”î…[ã4Å-gÞöÌ’€€Ç /dz™ ªÓ´ß28œ¢vÅ…Ûãԡד˦6Oe}Œº²_ôÊBéRÈñÑq瘖ꮣœù´›éïKƒ§°–›¶}ÏFõXO­ÓS·¥õ d}©`X¶ ÛCPþ`°ÐžÃÇI.WêEðÑ9>§Úž”+41ZZBØÐ‘ ÞPeoF‚-Ç–ÎèƒjÖ¢~‘zÉ•-Ij~R†ä ®²fê@#My°9ˆ“gz„zž–4ôÞøÕØXÓ‰’œòz£¦|C5Öt°]”R dËLOaš.m`‰´—>€€ž½—T˜aÊaùù°y5ÚH)…È¿xM+dÂf _ŒŒ§æíg”>Ô³˜Bú­û(†Hã‹fØ1WÐÚ–í©#Ï> pr¢¤@¤Ò¶¿e ºï,˜Tì’I¸ôx *BÙÌ´ÄOƲÞaiƦÛ©³Wñ-!~ ûò#¬MóE¼fe”}À¥Âñ 7ýv ã͵³€uŠ¥fíÐq? ž@U—†ƒ«ý â/ý7ȯíŽ÷yH§Ÿ24Õh ¬õ`%ìð6Dnæ+bÄÛßM~àš“#@]ºxu*IŸRÏÓ†f|–¨aáŠû˜¾?‡90ó±eÇšÇÑÔ*‰l3LŠ€ /©0‰(݃RêúÚÀ5”ì[•‹•ž2ZãZÏÞ¿ºr/ºç{ÿ—ôEœC¢…7 ,+2ÃèùåbB¤›®ª­‘/ž0M×àj«™ìåD*µÏ~Éî vzFý–‡HbÊÑ@ªªâ"Ð7—KrHº;j*¼¦“ÔÕzd/æî¨^y¥}’È>üýÝC|»â‹ñys€ÚK´Dµü¸ëÆ:2œâû~òÿ£GúÏ=œõ%­&ößÇ7˨$ëñŒ l7X¶óéo¥Ó§yã•0 –• Ñ\OÇÒ^ƒ’€ŒfY‚,Ã[hJCƒ*p’€€Æý@Ya{cž½¼Ò§L. ¿Þq¥.±7‰A|VoHØO~$qrú²vdå`ìÈåî0T"TæÜ“xáU¶uõÿJ%¢@i~9-¥/GßvûÖ›¾Óg:ݾ1Ó$q÷Jú¢Hؘº´1µÌ¾²<é‚–Û+üƒÍߘwP™:‡:Šßd½P'¶«‰|Bdô“Ðlí/ùï¹ÿ@s_oáŽEhd5eúlJl;Ø¥z>_QÝ’»û hÀù±<ÏÒ5šº ~ÿìð‘Ö¿f¨Ý{6Çæ‘´BÅCª·1 \Ei¯m…¤pä—ž6‹QBëð€’ad[y+8¾]qƒ„ÝY€B7dÖ7Ö)F,-Õ_†¿ÓÒ°¥¬—ÀTç"ü…YúÅXŠ»‹Ó¾ó9@‘ˉHŸD†6öÞÈf=¬.³¸öZ­3°zOôà‹õûþ·W;1¿¡|#Ž:Z~óY”6çÏö¤j¼œtµŸDÉ„ÿ/]ÌòPKÅ"‚M=êrŸhÊËæ Yû òç_`‘­1˜l¿Ý{3ž0qc,ù¡—„sæ]ôCÖïR*~G¦Z™˜˜‹ßm)’©1ÐZzêì4ºƒæ\£¥ &¥ÚQei(OÜ£†”ÎO¹o¯pu0›"ÝB 3L4Œõev°¯">b®*äi¤éŽÁd¶æÑˆJ–ûŒ—¬½¬n¶¶ÇTŠÏÀ»@¯ó³‡ÉÉ™×töZ¶€¡—ÿê p’€€Ämi‹úìMÉR„KÝ¢§P´D¢€,¬Å ’‘pÅhÕÜ(+ò¢7 ÍÝ óÊä©§%5ÃÑ"ócƒ{9Þ•(|UZbÈs' ú_VΕªw„¯ÌäZï¶ Z†¬8ÔáÔ½F.S˜Áùý [[cr¬;Èá:쫊kgÓ¼Tßÿ1ö`kfVã:·¤ÓnÑRËI‘¤5yÆR!«WH\úªâŠjÌžz¸Üñ¡MÎM­{KšdkùH7‡Ë¦À­§gù:ë¶|OÿNÄFˆ]^7YN(ÿäPTp#q-¯ô|ðT7ºþÖúø`ZC@Qhö&/à2¯'­¶Ó{Sn3D©r|òN2ÿ£§~±æðŸv;@5pÙ?süp#¾Ù:ÀãI¦>åÝý¥2R½$ÚDÔÜ1ïRù#½ÎW†4jQucî¨"3µ£”ÖcÌ[û!;!¦gi'U×¶÷°ð3Ófš2bAÏV¢àçŠ Îúiž¯¿S¥ÍîXܧ5a‰Æ»׹ʿ®qÔˆkheðYP´èaJêÆfVõþØÑ†¦Þm•ÀŠv´É6U~P‰mˆBÓ…[„¿Rjˆ¶M„OAÝ’óÌŸ+Ô¸<Âÿ¿ôÙŦ¡N¨‹ù[Y­ØOE©i×µ±zÄj·0p¼þ/_cûže_B9øn­j³›³÷€iÌ!Q’VoéŠ6ìº;$ yXñ-Ïù*ÇÇ¡W&ÙL<ÜŒJIÁqqä ÔÝ, CÔªË ÒjÎÎò1Øe\ÅI%ƒ¥Ç´U›IÕë`@e^±*IW¾1³Èa(øP~<Á%®N F2ÏjxƒNNqŽ>‹ÊPè)iØDÁ+Lf,tfb½sµ–Bxõ åâ8 @r\ÌÙt:RhxüỳƒuHg’ •Q˜dœ%7Íø¥øíõwèRZ€,^8èA6 Ä¥PÍfñ nl1;t … ÷µ£%¾ÕÙ’†$§Ï׎†áDæø–—¤z™æ¸!UÊ&"KäkÐî°4Êrü¶;’#¦Íß“éÔJ§„ÃV„ÑÎ4*/0O¶`v· N»¡ŸY^ê¦|‡$Sv«¨A>Nº;iqÆØ«±^çÅKöÛ9f°Ö¨½s—{æwQ¤Ó9¯mùdÏ»ÎaÔµ»\`_à Fó¤xˆ’€€·IÒlÒs¬I$¸Éç§T\›¦X•j~é˜ØYEêvé@dìI»bþÈ¡6­Ì’úÎòü`Ƹ@n‡MöQCKíÜà Ëð‰üÏ€E-Ñœâ™HN08ω\8´zu"û÷!»Šg!ÙÔÃIId$9m§mGå´D¢ÔsD °‘“‚@ÛÞ îw\“À匟Ò…‘–ŒÓëÛ.Fîh`5æM 4ò°:ÂÐňaŒ¸±…"ߟrZ#OÌÊu†QÉÛC÷>ô¸ìë¼ Ô3˜V®ãCPÝô¹Í1ÕHÏ(e\ ‡tfîP—>ÒÔÁï#Öã±¢ÆJQ _Hà—Ò&·¡l7º¼q7‘7/?½4Xs(Ézd‡­çÔyà´œ]#+£Ÿ$¹î]—òWé$ÙÞ1|bF¯XUz1»­/ï³j°“Ÿ  3eT·$@@æQ¦mÙ­²Ú cÿ¬M‚“ §[åôæ)GóÚl´?V\¯¿'å^ÅÄá¾_ =üµë0çA+o‹€¢Ž:! Þõ/æuC܉Ú׸¯½\5J¶8 y;nºæFZ.£ÅÂ)®î1[œ}Ò=7¢ðV·o DÞjä–S{dq¦íŒß¦ Òëj®ÚÅT(ˆÔßA4¤ÜŠÉ+/eôCçaúÙ½Î:8([‡r¿JæúÅÛ2To6ZÑJXË\;üç™ÖAË¡Ýôy„LfóâA<÷BßÄRYÁtvoæÜ¹ˆ½º¡©…\ïn¾Á–oYS¡Ýë‚nÀÐ"4—¾áTÎ78Mº † ¶"®·ðw Mæ3}Àþ®ëN»ÍyÕGEjí{–¶r.ýAw Âƒ²^ïô¾%Ì/ì¦Ê"Œ»mΑÜÏFYg©hP?忽f¯ÚÙÐA³?“°ŒULY÷È æuWî4I"”|ËÖñß]%U§®|¸Ó’àè1òz˜yE¥PòR5ªçö‘>¨Ì‚Õt˜}|°–f‘nPøÇB²‹­…ÐNK©¹£Ï×죻‰Ë¼M€ݹX‹ŽË.Ò’Õ}»(Zâ°p lÆ‚j  #ãqÞKQòŒLkzØ |cÔí÷”ŸM׎-p–Š[ñYî@6õ”'éµÍ"V ‚µQ²ùÔ¸áRŒ¡ˆqÊv#H’€€ÈA´¯ à–ó}ïÌ _³ÇÊ·BSÅšåÄ=ù`²ÐØ'xÉ4²¤!»~G$Ñ7‚ [TëÀ g]¨DÀ Ï„î%íkád)T„zÒgÊÆKI´+,ÊÒÃ6^·IÛ8 q‡ù_À€ ÂZs.0€Ö«Wƒ‰h¿ìZŠ|áó‚c ®}§MÃD ³ô¨F[Âz.ùðôÚ£HQëîŠ6éö”ê"ˆßÅÇ&P9ü¯‡O« ë•÷û—‰?MððpÈÔ@çûŠÔý®–j>®wfXñ|ü-þxHÎÐâzƒÅξRÄ}¯Ìˆ/A˜y-Ôß44ýLƒ˜æ›Öë€ãÚëÞ/Ã@ÜA« }¤·€Ã^¬Ç^4 |,žôÿÔ=ÎÏÒî˜pˆ^ÚØ‘i£ßÀ>+êh'jSì6ÌC¹}SÊá.EË^³%þµ”’¹ÿ6“dïp:ÃògL÷I9—FIì8ÝÓäJYô(Íœž=tSÁÇ×!=E9âr@ñÓ?­­µì=¿BN/Ö Ž·(„vÔŒha˜ìÙ€Âuba*DzB{C8‰SLõü´3©É©]á š<$ :¦ëh÷8ckÂíŠry®ë8娩l‡•Ô®„ŸQ‹7n…jóBñë&èù¢¥n«vhxaÎSqeŒ f9qšÐË5í1&%O˜ºQÈîÌ”°T„üë­žÚÃ6›¿j"@‡ÞÛ˜'…¦ÒµÐ£]©'»tšKÕúW 2öäZ·“Äã°„¸¿ç!ÎH§ëV0BÂUÖÈ¿Y•ëHô®SH6ùÚW¥èþmwÞÌ›ï¿< ¶=­[Ú¬”ÚÜö¦¯Åž×áßícï*g"Äe&?#ËÃKí‘ñŽòjSDV¯hÚ˜?ò‘‰·f 58­ƒÐ‡QE%G£¸@w0%B%Tƒ½ç;Ö¬ä%‰F 5ùdÏå"ó|ÿ3÷jgFfÖx¨—¬ýŸø4H !!{ µ¬w;•–°‘)Ÿ…KÖØ¢âŒ&Ìb2nÎ)ál D&É"K;ÌóÍÌ•ø7< JhšÁ¥Ü h£Óµ¢Ô¤M3ÕzëÇFwTPù -yRšn5ˆLB*jé"(¹ Á«ÄÏšgÊ Wr¯áÄ‹´WÓ’€€üòêbr/Æ#'h^Ï¿cyüB碒«°gœÀyøìšqúšW#°XÜ×ûh ßý[Ìûb¸KB-=æ¶½o6L¬½*PÑmÿ½‹³¦l› >­5aX…b9vë€A¸$}$ñ¸í_ta1qNÞí}Nü¦U(¶½¤…‚Ï ˆ6ÞB0α™ c0Ôêðˆfí¼ˆ#w`.ãÄûø#U45ª ®ióóº§`5F]Þb ÐF}ñáç@Âû‡óÑÞà,Ú¿Ûè™u\l¨Ç.{äy›xò<œÝðÁ]E‡Ýùsºã¸HCü˜é̼‰Á×BÛ}À4D´RpHCy O`ò„ª6¸].Ž`\*íj=V7,uµ Oj< Ç·yÜMñ úøu/”Î=±h"¦¹¨x|ë:/»&KОtŸ´=tœ[Ù²–@ép"Ê?6‹H OJ6}O»©·+¢ÅQŸá¥â€sÝÿ[w{­s‚F;¸ ‘+°²ôgÁ?•ˆôå€ì;5Ò¬º%nÏdø–-ÜexÄ ü`£ô@ ‰¤D7ì°ÔJ‰ŸîHº©:™áO#À`Í$l¨7´4ËÊå"ËÛeèÕøD±ÁÉÞ1” Z—±]v‡‚;&Ò O-9½e™¾ý•å¤Dy¹?ºƒaÚîêçhB…Áìf(kóÞž ¢˜m{*ÞWÏ•PÄ8ü-,V hÖÿÔÜ8ü«Å@•"¶%BàÜ×Yé¥uìö âÍð$õ†^ö’çv•‰·_Ó ´ˆ?œzó[Q˰xg·n÷Fž·•ç–§SC‘•Å΄ݷç4¾0‰à:uQ³VfIˆÿR˜µ´Â—Úƒp_…›.fÇí\O(ì^½Òš¬ªöØîÚn¸5 ÓôàýÏ]N[…ÜÒ‚(ØrxÌðtEd ­Óä È;þ5Š‹u¨LA&Dðo­×€Ü…b NI¼…"åbmí5ò¹ûžüw5xè%’€€®.4Ù½›ÈëBøTÏ'N–7ôS2UŠ t;á ¹Œœ}þï"0ÕDtYD”%Z™°ÌÔ ƒšj¯þö^‰¸‹JzÑÀÀñWVzûïºuR€^%J…| º¡(~r®áóˆ¼BvBrû[êŒÊ¿pš½ Uðç×iK,¬êþî:ňD}˜WˆxW²Ã¼/\§[¢Aæfizú‰ßë­òg|M7vƒ¬t1à>#G2Ì'm¨ÕÈ“B·:K“Ä#J$4|s”žÔñ‰òÔ’…\AÔ§ÊÉ*íáÃM#³OuY‚Ð’ŠiÛKÄ@šÀu¨®ÔKZ÷ù6å¸Âxl‘¸Ù–™øÜ®ÁI5·üRì$µž#ý0„ø‹RWR~¶œÝË9yfk?a?×Ì×¼ò¹:ví%kp±Ï®>ª±ðl}9¢ú,ŸôGø_­P‚ÆŽï%²‘c¢¾²T¾V߬zàéÑ_Ù¦”iXü& ª®`‹ß¢bw%ÙԦĵUmƒ¤Y %¿¾a`wIkæ 62W Óó‰%†ƒTJÚnˆêK*È¥ È‚¯@ý¦ö5T‰ä¦=šYm£H•ꀌîÛ2rNg³ìµ0Œå»è9Sò¾q“¬×È$TÎö(Ï«ò<…ogAiz¦ÚÆàkÛ›vƒ ¾ôÜ.¬1H™ED:¯*¢2\\ôÓ÷ßj¥Ãca¬1ir[Á‡Xi^¾'`¸VmGjâˆ)å÷˜šç—ñµôÛ9·|9÷>FíaÍ©ê B–³B%Ýc"v ¼ç& ¦í¼|ÔLD’ù?|Wfbê :î™æÝ°…ð ·ï”!pR¢àNTódR°¶dTÛyX?Co“>g¦À\èKf/Nr>,ëAÈAêÜyn¯Ûç‰q=NõP8”5–ÎD€ßbmØÕ* ‡ˆâP±“„±ínÂ×Ì’€€²×hÚª¬ðp3s¿·`á¾È«!‰ÝI¶…ï’·§›ˆ83‚]e`ív6Q³缄ýˆÎ’D¦½G®vÏÓiuEÔgf«êUK?áà™‹ÙE¡mƒ'ë©$RgÜææFÈ—RàêXØèÝh£l ·5`ÅÍÑ"bž4öT£F%{L“Õ  )Þo<ï$ç- 1±NõUÁfƒøÍÁñùB.ŒÉ/êêÎl5©„âܳD™³2µËÛ£Þ¦²Y©žŠ×^ûïGöý¤&#û;AÇÜ®D/ì‚—Ø=‹<žIÔðU¢[… Ù¯7(õu„]ÁIùÃY”dH¢¥Í,.Å€ÎGÁ¶”2é†50 ê`N ï^Á’+k¶btÿ^ò±Î]·cjÙçrÕ•VŽYÑ?rUî¬ó¾*ì>ÓŽ„ö¯zPD%¬|>²T[ "ù½ŽÍ€yf#‰¾¨e^žž8 A¬½|èÿHLQø\Û£~ÉÁ]Eüʼn¸O ½ÊÛæÙUÅW"-÷ÈWí@m®ÖÉÏösÆôòðÍ£ÓÏ™—Eû(öoh3ª'î³ y‘ÛtÊ ˜0=É+ 3‹ô5Š·1%;/¸ˆ‘WÜa+ÿQo×£¹ÒªšzSK¬Ï9ÐY‰ ¢ÕüÚœ©²ÒßèïÚ¼shQ^>D>ä9ù —Ýã|_àºLÊC{­d8ÆìÙä&ymbœñ`%¯‚~l1O!h3fÀH[þ]~ãÏ¢{&B ‘2ÖöO¿·2rc ®¤7°ÂyÀÐL~e?;}ãÞbý=I~ôVçJ&ŠýÖD³íÃ{­ûWkOÄŒkð%T*xæ©ÂhTä±Hrgðý%[Šˆ †ÝÌ©EO Úƒ„¨ÌúeѰöjä„(ÆÇÖ‡žy=©{­É"!’Ð2o¸¥„äƒf^FՌلVya·4ÇIJ¤ÂØKpàê;l’R˜‰¾Ñæ­¥Î^wô7R'*Þ†H# ‚|pKS“ÆÚf3-aÖ6Wmã*°ÀU¦³ÐÛ§gßÜ^CP£¯”E˹"pƒšr¼ª3³:8g“h(Ç÷ ‘œGðu®ï„ÉwൠWo²³娊ôûµ½<N:¯·hæ•݇V†™Ôc@³cI™Õ;\]Ìz¹Õ’€€¨ žo[sQ6Ôïž8Wh+í#3)úE+TRðpØäžþÍÚ®±Éþ¤îÀ¢õg¯·¬£3½hE#Šß ¤Ø¦£Ð§±¶„T¾{ìÉŒ‘Ûß´Y÷0i<Ê&r8!Ö¨ï!ÖEÚ“ÌW‡¿-AüY*ªSŽwÙdÞ ÿÚ“¹Ðƒš€L;þU~±]wlä¶Z<ƒ•!è“×ZTÜ;Sò³tÏ´˜ôÕà¢¯äÆ€}À‡>š¢ 6º}&ZuUå,ÇP¥eD:"2ü–Q—ÝNHAËÎj\Æ®âÙSr¶)%vMaÆ;Àö•)ÿåÖœq¤`˜ñ@YßÎŒ‘  ÌÃ7ý¼õ½ãø†_íŽGáâÁEt= .Ô¦j¶w2”†‰“‚ç¨+1TÚ Ó’"ŇöíÑÅzp³Ô Z©÷™PÜ»T¼7µ×’B²PGØÞÉôCôSâIVb²xMÊKŠpݘy(VŸ= E…2ˆC®ÐD¼ù wnjí6ˆ%ìóž!cûßýq•Ðù{L±ðFÖ:ê™ ;ºÂæ=g0Z€Ï¢ƒ¸›ÞâB.Vê|95·wU(1—Ã*D¤?7\_M¥X8‰LÜ?4—•¬vUújÍ™@-Ëx¯ÿ›Ùj–ë3Ü÷´êï“Ñç_}žŒÛÉ'a|›æ’€€«QLÅç­ŽÉ£TOÏ,—\"´ÓVp![Ò"ꄉÛÁó¡DÍÔÔ*÷—À>èé™/¬ã3ö"àò½™/(W¯TðLC0ÐV Ï*ä*íf°¯•…þxHÿ¤£à:(Ùªn}×ê!}0Ö fÒ–ÿóŠ%G À™˜8F“hòvÿê{¥sÙ8ê4=ü)ÅÛ&âIßœˆ¹æ§„Úd;™óðÓ{ªj»¾SJI‹Øëa:7û<$xeÍTñ½º‰KíÞgy§0´„_:^‰|›‡<‰ÑFEð+Ôs¥¬·g$y ‘’e㪂}=Îø›E¯&!ÿøÅ$tß³\ä{åeHMçmYÏ^‘Êå%#›#ÞkBi}r¼Å¯e™†ugY†@ˆòo®ì›`wPˆÈš`?¨záŠÈkBøéüÞøC©oIip…¼±µ 8` ‡É!M×wl{àœ]¦“R¬ÖŽåáfŸP;mÒ¤]4K<– –:s½´û’úÏKÖÍv«ðñ’ûŠíìí#™±š5Që4—}¤éH+¨(I>š¢ް‘:>ÝÍn´%õý¼‹â……ÛZR€P£nOYyèט„^û5H_o€Í’í0Ü7Ùî3þ{=£Aç¶H V?qà|‹ê†+å™<ÕF4ëTïWñ1l‘ÏAN‘@›N’lÚì`»…ê([®qG Ú¡ê ¼xµ†Ï–HA…ÅrpY5Z¡@‘ò@Å®yV’iФœ\6ÙÞvNrwPAÀu“xBtE}’ ¢ÿÌ•Žèú8BÎ.jÊö¾å?Z^§Ã^‡“ã‘2Œa83ò+Ô2}W°y‰ÒZmW¤ØJ›Ã€z´%~H¼= ’ÿ“2!ÔŸíÚ0ÇÙ*!"pZ(¼AȲkg)Ä#\Úq(ꄽŠ—‚ò;lÌA@˜èVÚ*ÜëY…•wÝ^ÑE€®šâLÓ Ú®rɵ¯ yÜBejK!ò†RLÄâàx^×þ–Y·y ºJ“øëæÝ¶ùU62óœø+C€–BDéGnP¿ QHdz¥Ëùgf”‰+ß«âàLáÆ."é#+R"¶yÉq—`[b9Ã&%,ÖÔ(x¹)î,EnåªÍ+ŒýT°¿` xã¥q‰„’€€à²4¹è€šUL º"à÷À fý†™­¿`Náá/( •Æ{/jªþèóË4Ÿðømt¶«—‚Ù‘NEÅ2ˆæ{éNÝ4Ÿö>š™WÓHÒƒ÷#ý `Ó‰ÕF…£˜ïü)~µeôê\”E×§>EFωž ƒhÇKá˜!uw=Úÿ&ïÛ«Å• ¦r¹:ŠJßPR Þƒu8(‰%SGŸþrþçþ|Lÿ>|†Î¦‘YW£à„6¦|Ù|䪥CWÆ~Ñ8°-=¹…¹Ýó²„x;yÙ- ãÒâTr©JÄÒÖ·'Ò*¶ÆÜ>o ç?†B‚’"¯ÚT]¡ רjjvÒ¸âûÓÝïoð¤:s´Ìg>„ù3NtüLÌ¡œ|ë}èØSa;k¦a¸©÷§(L…|~Þ`6ex •nRç%‚Ü^ÐÀ•ĺ&^!w½ò鯑TvaaÙÑ»½=ëyôŒ ¹6Gî’€EÚÊÝþ r -»Hܤ”¦¥*ÆÚ7q$çÌO¤%k¶.c+q yúnÌ”â…ÅìmIÞISóu¼ÔŒÔ÷CZ4†p'ƨÜÿ‹‘RÝ…öpš8å‚7†u£‰O 9,Mê\G]?Gc.p·Ž;Ÿ<`¸=#Tð¹°oi Y3¢µÇGƒG'æùù­ÈˆB´d(‘\{é$äG®‰sâù¼>’’¾Ê|Wg Á<‘bÞI0g4ò4àåäC-¹í¥6¶aÖãfù»`|–O2xFŒ;e²êûûúø\­r¢KQ§ªÊŒý¯K Ç7Ô17‹ÂhÞR2ÎLÞáÞ;„«¹äNø–¼Œcuæb9µýÏ{p&9Äøö |†èàÕò ÷’ŽéÖ^Cä‰1gÚK'n/l'¦,$ª½fSP™«ÊñðYù:ú[‡çZlê#æô ‹eÞº§ ;µQˆI½¢ìöåÈ|“¤¸c¡ýöT„€”?)*‡z‰w<Á†+ ¤ñ gýŒôwm˜)ÐßFÖÕ›,É..V‹‡ÅMKŽœõFi0ŒFõ›È½R€Õa%kx†VÑIÖfÖ÷#ÕS«˜>][ÆöàR”8äç^ØýõŸ=ưÖr^ ¸+õ¹TM39cÄûQ’ÃÞ\Ï.ñÂkH1ê•Ä)êjlèÆ.ùDÒavsú$ xðú’€€ÝÑûS= 90!C* Ì }‰ÁÈsÅÇ€Ä1A¬ãØz'¼t™:¥äš µá¬ïj}ƒg¨ùß¿Ù|„”¹Óh^ž2N°wާäû¨|¿hr˜‡£ãL [ráb¯yè'Y!Ñ<Þ9ÜŒËÛ.RkÖØ…>ôp˜ÅCîeÄ!4O±ïƹ<mœlS#Mq;Ò«yøO”ÆëìI5´ø†I|Fªß%ÉIMƒ]ÑÑ÷æ»Da(»œ^Ô²øõel¸#‚hÙ¢‰ø0Jh¼‡½·ˆ!³öRÒ Z +DÜÝ$U\7‹ãó¦–9kVWÿÜf‘IõL±Ãß]&öÚéxø{`…–WG³Ê÷—¨S¥Rü/6IM‰‚=ÄM)ñ_tgèwQ4ÉPêÉß|†Ü܈³®—O{äPÔoâ1F‘¢j†clâ÷> þxŠ3+ú©Í–½ù0íšxA¾jbž^õ•¤õ;w² QuÕ©¤Ì™¯Âð¼Ì=S=aH&ðÆÏyÜïkWiÌ;PŸ D`tž¦Édâ¯w÷s¼PZæ²íú5U»¼Yó&éwË °>¤sh2;@Éxµ®Óô†ØDóÈùÀe-@Àá YÉ"Ñ9ç\Öß©#¤¶ö  UošÚhAÞ=Ç?€‚‘³°ú•¨ûVH€ÉôHcÎë»ä,-_|¯Våñ-aØçìc¤ž*í$–R¼1šNÓ„lÉf«£=1o÷ D Dä‚f(×" E÷œrŽÑ,¸¥çvÑÄ¢–-5øò1%B\õS~ûD’¾…Â-ñM¥ë+L¬Ëï<ÛzM]!ªÝ,¾ { Ðß5Š¢¯n6‡ÇKÌF “{¤ö¢ËÊ´É|‚ Èk üFÅàûæ~Ýh­Åc„%'=^Ûõ/ÙѶ%z ’€€¢”]ŽÚ°LAªqŠi4Dñ¶÷¬^c™–{M?q? bj2,X¡ê‘Q¬ÜsʾڼñÿÇ,…híÉ’æ¾éÝ_úi1‹3æ:¦ô “_]Oöi`~#ƒÉÝsxu¢Øõ„ m-•Þ‘È\µ™•øÀî'ð2¸zÄîð!à[avt oåCi ”ž‡_¹a·5uýo¢fñ&cõ;º…vŒ’Ì»Ü&À¼<%IN¦üIŸ}¹‰Ç÷í‰há033 ëpw1þ¾‘Þý>/’ÉåËZ´ð•sgKEm{`¾qÍ`F S½èýŒ:>¶ÁdOV3måñ`¡õjšˆÖ´˜:È*ZäPŒO¾‰fålM%_õ+c›Š—©>d¯ŽózÃ6³²kúŠr¥Dw?÷±žKè$^Áƒ]Ý}®Í¦®j—×¾È]x1qÙªKÝ+ªc›¬µÒˆ$YU·>2]å¶>ææ²¾ñXâÔ}°= ]XëT–¹Èt>èΜöǾ^@9©bP#áYÛa¿‚;P:»5 œê=²°_åãÈTnS9ì%ÄŠ=W`:7¾Šî<üœ’ xÆ\*óòoI¿{]´°l:=AINrÜÑoˆàâ5’`PìÕ9‘öOe.¦MWmZ~]·œÑRѸ“¢=éó«ã2V‘èÔTeëŒ>äcE6|™à"rDö4ÁŸY™äFWÜWXkE±Fº‚ò¢Í$º4%JM#ï9Z:Í+K}ùÃÝ(yž\È…Nã ¹öÈ(NÛÐêDz°qC:!°àÔ×B-¡šµ€øQ3‰^z‚‚}Æt´VJKDfâz™˜Füß/1ùw×S²ª¿Õw§otN+=›Ò>ÜÀu¯ôòpòåEbA¦C¡jGµ³—0­.a¬R¤šž™Ýÿ2¨«žº;ŠúÛ±ÿjtúÙ,Dÿš!¹Â¬~¯šÍûú÷9xËøÙˆ&Ú£ %º˜¾¨…·«õX«„¸ëæÁ&­6Ƴ4¸v ®~ WÝŒ 3·ŽÏ™¿hñYV’yp¿Yä÷“N2\ßyµšë+Nç’¢¦(B*ÜŽÅ%ã†é¬Mθ3åDÿ+Ÿå‹&z@ü¯¶š›¡m±@#[ÝDó(Αi1é:!á¼þ®+s–¬’#xöÜ’€€ºž0ª AßêÜ|ð$ᥠT¿ƒ8 Z…iG BYW‡ëûÿPcœNh'ö"=\Ah¶úõFÀ‹É¥ÊS–ˆIV¼ø/„Ü‚f^lŽ@¼RfLݽ¨À¦b/»bÅÙ>O”xÀmiwŠÜè­ð…yßu0f êT*3´OÿÏÝ´[º½“÷KB#úôÒOÚø’žÈz“™öÎFã7®Ë Î5Õ÷›EùëÄVŸ yhgFja÷yßg–ò:++Ÿ‹Â¿Kr0¥U€ ºå¦€ÃÆTMÙQÐ1J½çè¶“.IbîáÍOÇ-‰T$튪ÔȲ¼wC4G¿´+F’“!™ãîõ0›’û0<”àè‡ÔˆšP7#=íJ¨S¤E!ò@5""/Á @s­¿7íZàÄ´5Éreª’cHÑΦº×\“oBå8E—3Tƒ8n,ÌV0"f0–ÂP…GrEÛÉ4âç¶î4P5êâãVü’&¸7p ÚP÷P»@#ï&ë§ :dÄåÌ2>WbTÌ×nÐu‡VŠa§SËÒ´l#´ ÿ˜p¸rÒøW¼&rê½°\Úná_=>Di?3ùG]¸l+5É¡¿ü‡ÑÖ›Äíà€ s†J‡o nÃ'ù‹‰v¿¼LGy]½êŸáèþ§ã¤u–ó*£ÀgË§Ú ©ò5b²ó=à2¬;Ý’ЄÜÑ¡¥ÙèÏÎç‰Êè7Φè¯pj!è'V'·RšÜ))ʱ¼Ôy' äYÄDÒ–l¾8æöÁ”ÙdÖªZ ²KY»Ï þ÷>4º“ ¹eœê‚ÀÇ— büš!¨›ÑÝsâyƒµ$]¯xªå½àyüÄ 6ËuõÍûƒú/ä°nÓÇò§/¹‚6Ff8Äåw­›ê…),$`5Ðâ¹°˜¨àrõ(/íî*‚-¸ï¬‚¨on¨¨<ÈuûTv£l=™F(‰1Û4N•]ˆV Ü×Âe± 'óØ7ª×/~’Þ’õÛeØå¢Zv»p-ƒ5ý( F\¬þH¸‰™Y3Ò C^a’ÍԬ˲×Ð,zÍQypì­+J ¼ðüy˜V‚£3Òê•’Ù:h Ðæ±‡µÇzÔØýš$:ËJj¼ø_aÈærtCó+ª#3Ω7ª[Mø•’€€Ì…–)ekuhMBáýÖ@ª8|· Ç?4ÇÀø3=~Nã/Ã?-ár ÖDöïx¸òw¯T LìÔv»,d¶nÆU³Ä¬ê-õò7‚ä;¦ë&kO+Aš„dŸua=Ñâjýu©™ÒךtõB¢Àá#´{­'|’À–”Cy !PLN‹²òÔ3´ÐX\giÅkRf¬}¶²åSSJ7µh'…‰ ï£ÂZW(,3.QUÅÏÖ†ï.íÕ3K—ÞP«î‚ϯ6Té:ôkD×ù–rKkÖj ¹b\|”#*Æ ùÛi§=‚2X8_ÃÛ4ç}ß͉µ ï1›áƒ W> 9Ómû 4ãfiK‡l@ìFFìÞÜ݉†› š¹{ÅÔìm…Ör⬉YÊ´JWðsš‡²“­e'ËO˜unÌÓ^v”p;X¢=L@MnQ¤K퀭Ö –’›Ìé*m%ô*Ó“ý;¦5¨³T£Bõ)LïfªÜaïÓ\Ù›4*TQx_1±3wÐ],6·[ƒ›C)†/íÄ:±÷l¹ûÿÒ‘÷D4uǾ úÝ¥/RÏW¾—(/dŠÓ8ù“¹ÖnÛD:®`rý&6çËz^Ò>43Täg§m'q,jÜI*! ùÇYM;¯ ¿ªÀŠêM½ÔÓ?ƃµp˜¯òÂ·Ž ¥ÔZœGGO`ä¦ Å—¶¢edà Z/[8•Øq/OL”"å‘е!›33¼;º”N÷ü¬…]H³7•7Òã-Î̀܇zÍ—v0»Ö–g‡FÝX–J-§'BaI›#h\q!,¬!ϺiHÓÛûva"Fˆ&Ì>T‘Ô³c•5,0@l_†´X$šVnÏ 3'–lù4÷àø;둯ïùãîÛ.²JM,9s®ZÔ3«ÂËé]¨£gÅ’€€ž~#&U*yÜ —ÞŒ‚¶U³]ÿb¦âL©™ÝÖ¬j§³J§³äk0ª!:Ín¦ˆÞ-û_ˆ5…öàT¸²ÀÖF_†[ጵÌ×T¥œQEyôHòö´¿]7ºøäÄ;2Äl’1ž7E• Âè¶¡¶­=²{>¼‚õPøâ _ºRClF®¬¼CŸ³å&a…-¿²§IF¦½Ÿîw‚²ðÐXI·:ª—oÑSêŒ|˜"”ñ¾ËtêŽÂ@õ1PÈ1œ]"ÔWº¤dzhÚ I o+õ*)KŒ_ŠûšƒÄŸî*¹Ý¡ôÏYÅ7*aR`È;.©0¤×,¶ñS¿Þ¨Ù÷™i­,=å_ì2 Ïs’Sâ%×fì_VÇm5E“ꇨ²•˜ÐVÖÿ*Z->Æéƒ„ޙ֓ô D,ý±<мIB:0”æ’Tp“{(X…¨ÿÏ!ÌÌK|ö†COtlCûk¡¬úX^«<|Oì#Õ7â„.4á—dî Äk«K(ÆÉ¾²ý»o3ºVÑíöÆÒAQr$Ú¼ðO\øtsbsÍ4Òâx@d›WôbESs%ëÆÓ,œ3M]Ú^}ækóÏ 8 ?ñ¹ZšMãfvÆ Y#~r¡EÓ°®.ψdù…UB'7¯|[eHçÖÌ—«­iÐ4÷JŒ‹OMȹIa¥„¯Ì¸Ñ²¹ðNíxNÕã}ø\ aÂkwrež|<¶´z¹ï5Q’¯Ì RޤM„Uÿv>Hé1(’D,‹4-IkPiË+3×ÓùËqâ©J˜ÆÁæ£l°p½`D岑Ö@ž5›/L‚1JÅLJ‚ú¯Â‹të¥×8%»$«‹’Ú×0RhkªW‡øË£° Á m…Ö*Ÿåu€dZµÉ¸`*-Ãv÷=§/ï°”~|%˜B{–ZZ©-4ÂTŽ8µu×VÂgÝq1ÛŸ™§ZÕ\cîÓ†Z~¾tÿ"fý\;cŠù† œYâéâY:Ó5:l.|O¹¤Ÿ´ÖºNñDÁñz òú#Êu¯ †¤_ àN¦ý^iì´Ì]Œ!f0Ñ·0ÈOiüÓBÌ‹j©vHÌY”µ´p#$XÚ(Z››Uw}³tçügà›ë™tîy~ÛT+f8EÁ4ä‘) Âö- ¢+’€€›õ€P&2ZuÐø ù’ê!Ú7#àJ²®<¨ü{Í䤡zƒ¼îVíÆ¨A8Lñ1òµöoßœE$ ötô9ä–×'¬Ê"\ ô+NPÞ€çí(‘èC¢™±=A±7M¥Jé$½Ø[Y‘ŽŠú “]‹WÛuA07E5ßÄQP"•dÃ<$0µPך`Íä[<…Ð-!ÏV éª¿6߸°ˆŒ-ŠL£ö’èZ â6_ÈWøiíš#'n~ÌÉØ?8çIc}ÍðRˆ? ‰»º ¢$Îÿ4ª(A tbb0ÚÄ:ŒóhÇŠ‹$þì ã©÷â•DFm¹ÊNçŸ0Éùã ÿ}f§\Þ µˆaÊüÍÃKû:ŒˆØ3­ÚoýzšÊvâǃ™tž…Ï$Æ;‰¶É… –ÌÏ'Ï:ØQFg°‹š7J> c'$v,æ¡âž <2mºö0Ä÷¯¥l¦Ö)a¿2if;§ÆÊY¢ƒy3ùHxÑç\¾âŒä¬+õØù<®˜ìd•VP2Q¡—í”cfbý™-ŒÐ)(µåÜ`QÀ¾9GÛ̯QôÝ_ÁØVz.Áb»6,æ Aðy^se•:`¨ÈL²f!ÇÒÝS*D€A!GFxЊÚZÒe£ >ï$ ´Pµjg„ÿÇÕG‹¦ ܨ³ Ž$a§ LQþ4…Ü"}ŠÌßÔ˜Ðj Ú¯}»år£òÀÆ@‡‡Zt[¾^VMP )/ýMÅno*×Ý•ÙEŠÅ:yÛy¦Ñr&õŒÞç±³µ¸WÛyêôt’øÏ÷_*RôòTŠ[´aâª@YNhBmäò›'ùUîÞ¤“°ÇKV©ÕšÀ{ïž4€Œ\[Âþ´C£ß`L¤‡h2ÈÆj[­oà¢&HZÉàÚþðÇ›­r ÒýГì2cÀÛ‹Ànä¼g¥‘¿%˜ÛuåÞ†I(Ïk…ìÜ(&BÂ]…™ ñ Ã1\O ¬ )€4þ8ŒéçVƒ39tŠpššºÁ®‘•Ìö^3é‡Çëm tw^§ÄÖõm$íÜÒ`öÍ ÛGE¶àCžI<^¼œç *÷ù.Ó~$6r{yO̧»4‹Ð) õ†¯+lÑ–ñ=+ìKb“‡a¼ÛJ¤’Ã¥ pÃ|¹œH]Ô ›Y"JÅA&qT‘¢•¸(ÄûøË™Rþ‡Í/ääg„&Põu^ü<ü7¤ôõnÃ#0˜BcTûIšÏ ¢à ˆ>oÄviúEQ³š’m{,ï ´6\$½u˪ÝÑo‘÷ç°„‰øÿ¦oC8Ô¸ýe›|[SšìÔ—Éj/U,pÓé1”«¥OD´ÃÑÈboë ÑIô})êu~®doëÒ5â9ûŒ&^†ë²eb+c²bÖ.ÞlÐ_M#ðsãÃÂò:VN¶ÄÕ’€€ÞaëÈ¿{ßá<ß)Š¿L8J .3g Djy}"]6ùÓB6™½@â,k´„Ÿ,Ëuε‹´P˜ÙJmÒCÛ&0¥9v²Ý!¬ži*SVº( ºåvhЧɰ<½íB;’ÄÜÇ÷Úì¤7û¶¶j£&Pæä©õŠÎ‘-tÕ14kuDúõ®ª §¶©œø ßÍqaçÔíÊ{rô)¹áÔEòãs ã¢çZ ïg\ ¦˜ÒÑí—Ý‚*?¼wâÂ?ë[&s×ÜZýß<ø/ªœä_B{ ¤9Cü×ãí‡zù½Ûéᱠ܆µ@ÜzÕWkZÜÿt§¥vhþP»— ¡lbõ/Øq3³îOje®ß¯çEØ(Ϩm©ï¯¦ÐçcÍIs‰“×ë:JÞ,?ñ—hÈîÄ7î>ð´|ܧìÕ"t‹[핺O'#ÒÐÆÚ›F þ¶œŽd9å¿ß-‘Þ|í鉀”£É©ï™aÍ‘4σQ7‰Ð±@Ï#aŠ×ü¹÷ÆßÁtäW€¸c$ U|î›Ù— qدH”!OI¥sÛˆøþIa½ø¿èÎþZ×°ž¿Žžé49Ç+R.cfï³,õ,&TSèMŒÇy“JmÆÓ$É¢!'˜ìÔSaÂ_³ìÀ² í—¨÷JaçKê4 ¿­ññ]ò:>Øí” 6e4Èø#cš5ÈËWCÉ^79ðùÁ¤àžšö{ÔMb2r?hRÌâ°Ï½é³Y ì½g%~ü‹ŠÏÃb]A‘cSM ¨÷~a“šµ÷/}4µðEòùVq–¤4@ÿK Ï3•TõÖZÈOD°>hM9¨4Q딣šG½ÃÒK ½$¥à¶‘W3!¥âÀfh8Ù"4õÂþµ?‚p–¶ltÄh™>Z˽µÁŸ.p|܆ 4¶ç¼*ÞxèëÊpŠ,üÝ÷ÔT€ì"报~Q>ŒN/Šàé2¿®a‰Åßì' º ¤ÕàM¹O$_ĤÒ!Ö!ðoÏ|>âE‘iv´‘6âü€oÖ0±g¹–ñ‡ö6^”Þ¼wèóVÌFp_ýêóætq¯©JùrãÏjgø|IÖ9O+%F|qۜ΀HÅfÂá%¥p/ ­T{ëBëlÞrœu”©îŒ * 6öap‡°ãƒ‰«?-¨ÿD!±yÀ’€€²¸(,HÉK@ƒeàE0Óˆ‚CåoWT¾æKbʾ­HôŠ^ »´†NÜQºL¨Ö[Ùb¡At ’fÕ¸}ÊJÁÒÜQwRíÅà9ÇëþÍ&û}\¶P (ñ|ÆûÂG¥0Y´!_ g>ù&>»éGÃj‡µ|ÎõmìYD—³n„Ͽܥ–R1MNP? ÝqQGŸ.4°Œž3ŸE»_ÁŠü_m‹{Íèeç$+ˆñ Ø4“÷¤",eEFÙåæ¿Çý-’ø°_ ò£‚ðiHA½5Ñ…)䎰¬6æÄÔ žØoŽ)«,ƒ©泸$߆Z0XùþU9^–mp!çweAi B·W®‘©dÎI‚K©û®²y«0ës‡âïbÄßu0ê{9CƒÓD£òц8Mjfƒ .7¼qUdø&ãZ¿¥'ú(žÜz„³#d×Ñœ‚HÉ\Žåúÿej¼Æ{{è}1ÐÛ¿3€¼‰ nŠ=û”Õ©M[ÿUÈ/ÖDücq»à¼O^‘úÊc!û'(š” #07vô&üg.Zo¡åìùå•o¤)øÛè5®ì¾—¾DgËOÝ©PC“‹[Ç$¥#`WkL­ÐD‚,à]l f)l{³¾¶šÅ°þš¸4E¯ðÛžißµ˜#D¾Æâ;—.L¡ÉC¶­—oÆÙ*3úT@‹ÓŽêE› º?ãÛáuU§8O*àÿã…÷Y¦šÕ0/Ã#!±±·,ž¹Ð³À2` ¯_!XgóŠÌ©„»Χ¶w?¸˜u‡…KÜ¢Þ (I¿–\GÞò%k_FsÕ«¿º$ÁŽC'ƒ¾àò%•ôk¯TÿLûQ_]Vè#¾‰RÈÒ‚û‘}ô¾mQjªò-ZŠãLˆ¸èv^©;M¸íbH‡ƒG@îFL<¯zúÿB ëcS¢T²íìןВغò1£ôAФ[mò˜ÓTQYo;nÇÓ~Ñë\ÔbäГ]²_z^a6?ƒ&N¤c»ÂÒÓ0Bo³@´îbƒ?Då׌gïðõzë6‰Ê#¶v¯÷âw èZŒG”üéõ“s"]á’yXnUæ"¹VÃ'‹©xB)wQ!6cE{¥E×ÊÈ ·Éâ³e?Þºö» *Óvñ޾6¯u3–GöEØF|¯Œ—-5l­í³Nä9œƒPC¥æiÉÃÑÓLÆ”ë`†eLo"OØ@^¾>lÉh™skãEzŸêol óÏ [(Ïë0®J9llá{Ñ6ýÉWžÿ‡§œÚFZþögHþ{´Æ›øQÚô÷wVÈÈ4Pu/-¤~Ÿ ‰Ê[îˆæ]$´Â§Z¬Âï bM àF«'ÌtïÏÁ ⽚’ 3 ƒ‰8³æPmqHج¥r2ܳánt,9‰„Š Ä4ƒ¢bn Ë„yŸI§Îmx€Æ1µë¿âÑ*?€Sáp‘@Õ¶¶“Ùóf Y¸*x+¥Ý›¥H|;¿C†³³ª `Ìg¯º/£Þ ï—<¨r¬ õ’€€°Eʬdƒ”Â,§‘¦‡òDZžBdßKƒ³Õ® Ýp_š,Ûö¼ãð-+Å/¬¶ªÜc&‡#²ß••™ê†»fÈ÷“1†Øä®0FÙÐã "íQÍ5úbƲR\¦X0õl¢\EñÅ&ÆüBÈs˜É”æ82y}^ñðqîC /Â"¸=tvª#µÞ ˆqaÓ.[íCú65Æäе~ï:W¤›ÚôoïXÀ=—¬ÑSûv¾A‹¹É? ¶L]RdO ™­«ð†C|&V"±é>þ‰. Öøjü×*šMûÂnñ«+uý}ÕÖ¨;ÛýÄ]Miƒú ­eѪî.Oùï˜Õ¥óàÈz"ÊžGV‡R誓”0H •—®ZÅ*%„fNãÒ¢àÖ½ûOF@%-ÅO1”_»Ât—påQ=“ÿìUK l!ûé5=¤]#â³[¦ýK72-ríw¶¥;»Wƒ ãNjLÂÉ&à<°É#ÌŽE[ÑvzQólça´èð.È@û–ò~g´—'.üTä`9xã/ dÍ(†jå¡+PаC›ðR„º\‰1{‘Ý~GŸÓF Aâü †ÿµ¯’z‘ 3ÙíÐ¥¹Ô»“¬î)jØ;c&U»žÓú’€€½Æ4ËŸ\úHµÜ[Ú›*-2`ã¡«µ@Øa—À¨¶T)Ôí=yжh¿ªÒªg…çŽð2µ2JíJ+àêéI*;ýÆÕÏxXÇôÁcöëšJ`^w–Já­‚«jt··¯÷ô‹ÕA–é}#µ™çc%ùÚ—OáQ~ÝÕ9[«1Ê ÃødZO$xZ¡wa.*¿[hºßüM]‡Ìˆ°Ôa#ÀJ[:dêxΕHÚÏ u§É%6û§ÿÉרàªÅI ÚExËÒ5Gróg]-¬5\sz†Õ"…JF^ØýÁ™¨;îÈå¹ë vëz¥A•Ú Ã‘=Òï±û–;¤Û©sࢄTctí¼qU!v+8êÁò=·á|œÏ¡´ÃLxx¼°Ñ2N#äºaoýebˆ‘¿ÐxŠõ3³ iÇÜzóµ?Û—y\‚ (óQÙ$ÿ|÷¸I°0Níòd‰+XœÕÒÉ"Þ3¬´·ÑN0#ñëÝŠ wè›Ùo•Y„DËÑqâj«xØ¿ås”+ß߀mºê=­.®0gJÍ®À´¬lþªž·•.®wÚ³9^(“—CQs’€€è¡\Ÿ"›þmJœeÇĪY© ŠS-…;dº*BøÏsº < ¨ŸQŽCóTæØÒ#I99eƒº‚EfÚ±n*6 :М™LÌVÊÜO‚ø³àÓBr(Í]ºg fzµzí!™<ƒî|¢;.#§[ƒÙ0ƒæÎEEsD’Ñ Ûaæw£a&=© ›‹xNZú|ô[1Ðv`Fˆ.F¯D½c¬e€µ ÊTKYRçÙì‰p­ª:¨Ë@Áñ\†Ánöd;»}uâœ'ÄÕI*kÔdþ³vcf„± øÊPi,NÁdgCÓœµ×¢B‚ƒ†§L£ø ×TMeƒ£Ù‘PysÜÑ~:Är2Ús¿$½—•?Pô5aaú¨Éî-ö¯8{¢æý]Q¦{LTsV4¢‘}p/ê&i݉"1>#oaÁ¨Mù³š2òè!9ìä]‘ñäq»vìpâ™Ãl÷’€€´¥‰ðs„Ek9ðtq}1?[|IOA ÿh¬‘…«LlŒ"¹L<ùÜm1¹æ§ñêºçJžAï3•÷÷‹öÏìêOc ³Z/Ån¿Ç<óZ­evÖèj)AÈHèoL  æ0å…A~`´×`%\Óíé_bV@™ˆú,?®l!¿ã=\ZÌNé§ÂÀº]êÂË¥ÒóvúÛÑ0¬»Jc)ˆ’žj[·%(DvXìáÙø}ßj(կߞÊŠ ‡ÅEtâ†.ß>ëR¦Ñ:ädüiOÐOø¶tR]{WÕiT2ô3é6§3U`5B¢iC3?¹~å c®š”‰ ¦ü¶1í_‚ ÕVÙ!«Ê£ò|@â×z#.ÀCõ-W³«õãªÃi¾‹y4JÇp^£ÝFüBݽAzôscö¨yÚÓÈŽÍ´Ç;Qß<ùaºœÚ “}ï1&¬«ÒãK®ˆ„ë8+æ´.ž ¶éIp÷¶P™w·é­o 8CÙ/<âÕ’^d¨d<òdmœ»'Ú¨‹ˆC˜b!B› ‘a:%¯|å|í}B§ß]jg >Ý÷jÈé§eÒ7Oˆ—*õTΨ±Û(F¸åÐ$°ÂŠŠÕ«npÆ6ÛÀƒ}´ˆXW‹n›Pkº¼iàö1>W€)¡ŠØds]z£ Ž؉Z[Á‚zz™ÅôÊœïÓ×…vÎ{ƒSµEý±Sç·ŒCSnFTã˜x*&¨œ¶gN¨ Q)4ëd¦4­òe‡ÔfŽw&^ép¦ô_Äߦða?S†'‹ý‘¦ÉÃØÕrx7ŸÏÙnO4mDá“‹N2ÅŒ]ýxO¥%¬¨2‹šu ÎL®ŽWñG~Êvì¶¥,Àb¿×pã9â–™}áœkÉ ÿŠS1ët iª'‘yæ¦$Vñ)aüü•õ_Ïsp%r½Ç4Kœ-¸y Cš^ âv©­ ™o–têô(ÔÂÆ~ÿËŒ“<[:G«UÈq™O1„ ª(‘ŒL ÑQEZ6ù‚šn>Ý’F¾y2ˆ&ù¤ó –Øß}-¯O¬´¢§hΚ÷a*õìè9:çÏ@ö vVÿ®î”&ÚG3R©¥`†7mV}ý~r²±šïÀI¯Õ'`ý xï µ…Ȫ‹KñõuÉUËsfù§«—§‚ÏîÖfùÊm¥LÝIŒÅÀª¡qL9µä'Þ#«ŒSŠH<1ßDÝò9ä޳â·ZCד+m„$$tÌ„ñ¢DÞgŒeÓaVzË{Ë~5àN;´ðI ŠVìÆÀˆŒ,@\ê-f•€ºÆ$ΛÿŒ3­ûŽƒ‹žjðÑiQ vQïúàù™|—`kA’y<µV¾‚#Úd.§ZCûje¢òðŒ®lÀVÚnó­„ï*ƒ°ænæM‚øVO &®Úñމ¼!¤]SCÇh¢$æŽ4»RŽºl5\®ßa©ˆÏØ)§ù5‹X˜~Sï©8sõU‰&P’±óo«…H°Õnn+™_)fܵ(â!$cq® Í1—®LÎr>Ê­; ç—é€s-—$L”þStvØJ3~À¡ —xS‰õé*=ièúéú1lt­‹ÇÁÊRËJLÒ#õD‘¬HhoЇî5‚#W:Þ¡ëˆ~Aõ;ÕÃR•M/¼Q<G2L·w¿ûïFÚí¿¤ uïý‡Ï_óL/N_B?7§™ÚƯƚ’€€Æ­É.‰Ž1” “[Ú‡GPµyµ.Û?¿¨ô£ÿÇeïé i¿Vpf »P©,e²l“C²\¶&X¡|2߈‡FϤœ%Í`~M‹¤Bï®ÉÂút˜\=m[ܶ[F• fð.‚qi˜ÿd*§Z×íφå¿8«ùa¯°¢)a\•é%¾ÃÙ¼Ø!"AîÑ·ž…%«‚|6HÁ4ÍÜÍŠ7̳ðv`ò?`~þ'p˜ô‡ëŸ J˽éPËÚÒc¡…„¼ûÖ¬€OÇսϣyÛ¯I(ä¬òmDghÁÍ•#Õ},JZÌÒº~©R(aïFP‡œëƒy‰.¨Ûg”ëÁ뙤q¡± ˤTR·v[0Ô áý3º­B $–ºvªÉÀ’p< ý±¿ò0xÞbãJ-¸¯Ëé=H0Ä.ÑU°½^p±XäO‹Váq»TѾ2«OS|â%Ë ‡Åî¬ }Iæ¸Wºø5.ᬮƒ@ê¦ã‡xÌäþ¸÷2O¡ ¸ŒHÿZäýi>mäGÃ~N~zÿ2îó´1 㟉™ÜñbQ¾Îñk)^¦àûl¸ädµœ¹™Íj!åŠZÀ·‘f²°F|Ñ¢Äþ >˜©Ó¡D³ìì¼ ý¥©\0·iôˆ•Ù4gäbp³"¬Ö‹½, NÒ8Ä×½ü<ʯî(–Öò–„•…¡XswàÕj#/\}ÚÄ^ñ‰JQê~•Ü#;¡Uÿ÷Pçýk}ïÆ8'ò÷e5mÜy˜lñ«aúÑã n•ÂÖÒ<©K\“Ó϶Ök*'›¯Á4ÙÉîáùçÓÆl]ïfRh(ì6ÿ.1ÏÄã—±t‘œx±?òe3€ÙÚÞ”#b½Y %ÖRKZ„èÎ`‚PÞq«×‹ëžT;©¢©øù¬†±^kQÿÅã…G£‚fÕâxŽ @²"Žüµ¡L¥}QÚi» ãÃDxçB+½ÄÁä9-Ô¸ÂaéI™¤µ­Ò?°MrìØ©¶ûGß¼âÑ)סfº&«ØàÒÝØ~NÒÿv-?žÈÜ]¸ð'ä¢bCô ‰ÇN0Ǫ?»bmÇ®bE4ò5»»| ~¨b0äC8ïXäþÐG³9ïSÇ×)Nå0DœÎÑ™/ ,Å~–eªS“)z‰ØNߪu_'ñ‘ÜÃ'®çR³/Û¨Ç8¡vËó—÷8P#a w¥X®ðºÃ£Ž6Qk¤”h[zhI×3N?ÕÂãÀBâù£±"Œé$Ù¿ýFìòÓõ•F¤d»Ìyà4Ýê'é£! \øO®5ùù§A#4sîÑ9™eGÔ‚ïD๔À3;ÔõyÌÊ•üBá¥ÿÔç¤X©^Ÿ¥@B”W[Ç`yCzøc¢&õžI~Oƒ5×<¼ /‰¾ÇÌ¿ð— Æ½ÄÈ솓­z–IªÞ/_%øgæÇþåVɶïù tß’÷¢2ZÁ¼Þc²?36‘”.(aòî†àØŒjËŸ’‰ÿûî{>­»!óØ Õ8{”÷„mAÅlG+—{¸˜Ðqjv¨ËîÿÇ`jÍ8B+A#g@ýDWæúQ0Ÿˆ¼I˜°ê¼ÙÇlbÞ[çíPk:DÈ¢½X]È·Íßa£ËŽd‚šîk 4-¯àHk—Ô‹©zeéå%¬ §‡n˜ÆÖÈ,f¡' þehc%‹Ë~ñõ ü6˜ìôªtYD¸fè¾Ö¥ÃƒU Q%‰»s³¬Ê–öÁ>54й¢¸qwãpÖQoRƒ¡ã¼UP](@Ùú#”gú8S™¶k¹‹œ!¬éÆéIB{>¾¡žNÃ~LoŠ(©N× ®ã#˜cÃCƒ~ °ô/ŽeTÛ“œÿ€3C!ùmT²÷hGü/z§C~ºóH©,;ЩD{û~ì%Dôc©é Ƀº¡œàí ^ÝÖø¨C ª,ÆÌ`@êçùaU‚nGž|µ,m/‹îøú|¼“±r&r©Ú?Tõ.A]$£_sŽ«Â›úå¯Âè¯EŒ:¼kYYÕJ~™ó@-Î] ¦ÕïlèFjO3äÈÄðe}'’…m R¤]D£‘ƒJ’@u?²ì$+ÿÃÝ£S~s²¾PöHˆ¶ rþÎêy‡RžŽ AqéBf/æ€ «Ë& LV7ì˜A]´Æ-â—ã•Dß™‰ÏäBª•;ç°'}Î_JúUÂUèIÜŒµ= Ó@r]ÿ£¿Pø‹Úž˜S÷ºWè¯å%ª8†I*ªk÷g+ôâ2”'T@Wðk«¿l|XGN¬E/•ïí!átåì,¢l©ÙÉh¬!$I êjçٮϱšgØzò«U ÿ%6ré x‘3¾WD5Œâæ ^¸›#šÈXÙü¬Uñ O’€€Ç©ÂÆ¢o‡“”u:—oÔ µ&'ƒ ¥$25–dåPÝ:SÂmí˜|ÈÙƒˆÚgê0¥XÝ€å%€m`|Ÿ¾ÿqSkG îàçààLÀbX±àÇiDáRzQQº‡ªOŠš2"ý‹o~õä%H«éüGX fY …7 SÎôpó»ùØì£rñ‰p§|vGU1ú¦9W×<¹…¹ü è–ƒ¬è#!SJÚúw+f%˜÷Ý’„‚SªØv;6)Ž…€bdQ²áö§mØ–'µ© X(ו­!ª•Ç* ¦)gM›ûr%•QÛÞ4 –µ\Anò³ÜÀé‹»4þ³2ó2:D^ÒøêÖ-Uu:édLä!Ÿ¬ce‡Mâibˆ#ó ¿ODŒC yßCw<™è 7Q!¥³=·Ñ¨G—`¤°·õQeL…­§¢Õ4„ÚæûÆçª™{0Õ¶ÂÙ7NþiÀ@<ì/>çŒ6HðDÑŸä3<Üj)ÈÅ_è#yø³)ËóŒg ÏD0j5Ç\ ã¤«Ôj–)p`G{ÇðÉBò’ ê-ÙÙnÐ*"?ŠŽIÚCÓâ¬ÃZPpG;@6K õŸ¨N]3‘¿5“¶!XÕâ%]ÇÔåÙýMê7 âöNÇä„»,‡ÿ(eo'Gßn¨?;;ê¸"ópgW»ö¹”BSŠ=ûj^µ·¿.*·’²iMZ-×÷~øW„cVÉ@HøÅg¥{;Ÿ;¬År õVœõí®ù7‘L‹QDÖ€æÎ\K=rõ‹ aå³LTåKý¯åádŽsëæúJãÖãÅaµÚ°8ðð½b!ÚÏ+M7HO'¼æor¶ˆ;WÊK‚„„•9ÑÇBø=ÆÙ#ˆÜ#Rv Vu r¿y—G">[ùT…y ŽÚŽÅe[Þ(´øB8ú”j8¯iä3ئ¿ï½59Án[’$¡ùÌêZLT ÇžX ìsbcÅm%õ¬­½/7a»‰[é+KSÏpu(u¬Ø‰´Æ gUŽÙýÔÐNôÓ'O\ßÅeKdÏzõ¬¼.þÅ(ù†ùdÞSÑ^å’9XÝæq¿èo ïw Û»²óžH{áß—íì f‘ZrKM&q]Ñ4ï–F6@²’€€Ò†1ŸT¿-{VªÕq‡£ra¡¿J÷Æa+*#Ê×U³ÈÉ,TĆrö#lžÒC2úW“,Qu¨êi®á¥ÙaÔU"aG,tÝœ¤NDЄNeX*ˆ£Ÿ9Ð8f/—¼´É:u¨çLðÝêçNÃeìÛÈ C²±);¸TœîßSí<ïÙ7z9#Ìÿ¥É«½'ÊÃyP x…)¥­Î‡Kxé¶u‡å” ÑÆ$‰7Û ±ð2Å5b[EÎFxáŠja)ª…¦FdJkØÀs2ÁÎÒ÷©+”‡Ù™öp˜]%k¢ë<ÂîÚ®o©9×ñ£é”eÓáoˆ{+ï£i¤V¼s­-Û}Ój¶gèõƳù¤œ"';j¶-jJž|胕ú5‡`‰$#0Y³u‰AÌÕÓ?Ênô²:ªwú,SØJ)¿”°hlA@‚®Íïõ°™:nnØbgwØTºh "D™¦ÃZ'w†å{Ûp³i&!J sfÍü4ŒõpQJ@ZDýƒøîš$(›Ôë×/‚(K~ò½=È‚‚Ež0‘ÐþR§0ªPƒ½[†^ºÇ±Jî‹›¥§çªDZ&eL¢¾’µI«£Åpö|TîU7mš[Ôí»§.û®$~á(^XÒ¼»âÐ*×:vÕ´•|Y¤kÒœ+rEªg'¾àNÍgÐ<×A5H5³ ±j[×G½99sû© JSÌuñ¡^//“"wa©Ïü ãÞ¦£nWlìÐn>OÆ~e9ñ§h§qdlkÎH§Q"1qü,pè?ÑzÈEÖ#7<äab&èAôek Û-ƒi2à™åFèl¨ ö’…'êéÀ€˜R­‰x—©t~¬¾M®@|2ˇ $ÌôÚŽº­.†NP¼Á3™Dìz¶~-€–"ŽuI¹)íòrE«þ´ˆ# M™¯ƒ} ‰ì®ÿ^™Òè=‚ßÚ«dY½z;"-XÆpÄVzVþd“ÒŠ"{­¿Â%Þ—  PŒí2B· ¾]éÏ_'yKZ¼C†+L%Õ®ržLjSa±z!ߦ“!SðòINŒg'G(UR´F tFeÂS¨L^ßr•„ÿC¹Wât¡­;€É8ÐÁ’€€§ên¦½5½B}§a¹zøi×f”£_2´ ]RÆEÁ2>8>ùÅ—Àž܉K §*Ê Î<Ë'Ù9xÿÔÛ9kCKúÐU-—=¿ ]*-Á…tý6Ž"〩øêEW]DójWiÃmyc·ôy+n „*Aè'Ûlœå*^éyÔèG§Ï°n)ÿŸ×ð»o¥ÝÆ6bƒÅ9pnpáÂâ*Aõ¨Þ¶çžtW©dü@·Uw ÎþÀ*õmÔ"e8Ï+OðÜ!Y<±vÓLU&³5-ëM>ׄàzƾ£ŒÎתL„zÚ¨ñjJ!ò«E¢¶£i…½Qœ ì#{²šiºC7Ô^®/Z 4]tÓÌ'5™›|Q”ëUXØ¢ù…<áŸB &å(\Fòó!þt„Kÿ2H&–®Â¾Å¨3e­dVØÌ èØLŠðé8ìw3pðøHýÂK¾9ú:K‰Ùôƒª§xÿàDô•¦Îq`ÿSeµÃ¿_„œÑ°¾Ó‘c-t ¡æ+(ê’4yXÛô)Ò‹ ©ïiìtH¹=A“[ÂwS|¯0¡ÏZ5Åï¸ F‚ª,ÍFækÆos¡±U+H”ŒLN½‘@VNhÞÞéN¦rÇ4]ÒGäû°…8­cK°© ¬Ùò==&U3EÎæ‡ táBRÅÎcæZ}¿R ¤%>ZVÏÁlâXZ2 Ë'¡~ë£Ò©Œq¦rà¥}±ü+Zgð5V«x¸+üF¾Ùhᙄª>f)\èáGÐM·qJ£W£³{Ús± Œ—¤G†æ "T’:Ê Ö°Ô¾“ ÖLÑ+zCX ÙCõVÖ:®7Ý‚Q¬T¤=I&{Ô“ªÒK5¼ÐEШ ˆ@1A¬³¸Í­àå£Qé¹»ÂAQÑâk’ÇÔùeÀ®×ÿð,Dͼ”kœÝ:=Å opP½æiÿ A#š‘Ù7‘¸€sï°.nËPפÁ¹q‰±7˜Ê9´¯d ÎoÆ‚jÝ[ ôþ–wš§Tßú']U凒€€æiÔp ºÏÖƒ*ÒøV÷ï“w¼nöV )@‹Ò]úT›ê*Á8eH@/¾ 2ÅÖêCåÍ1ŸÛbñ1’fĤKñ"#=N2àniÍ7ùçL%=nÕ\…ëÂ\¡Ók\ßê|4.Êyoc‰ôÃŒ3µw0îüKöˆ°m]Çäíؽ5šggeJ_zé«{E‚j ¡á(ù›ûcOÝHß›¥¬ðØÈ6ó„)löS6†e**f‰–“¦JnàœT·úý˜QÞ‡«–)9vŽÕ“Ê[ÐE|xu^â&Ëj@âóqIIÈ~tÕ}º9`Òæ ¿d“3ùSWß`™È]žä¦Ÿ»xn1(ÏœdÚKpa©'³¢»è»À^q]Ïvôuésr®æé(‡ ˜/@äéÞâœe¿œÇ'̺¹Äʶë@HÏà“kãƒÐ(+4Ré ˆ gìO5Üܸ¶’.Y=û %¨l-á ¬Ùšah7°_§)`wŒñúWÆñû¯¿óTWý­d£ózeìº*‘D?p+ĘA*|è)qm­äÑŠ)‡¶0Ò4Œ‡Êý”žý‘ KF“š+ñ=a D}ÕP*5ÛáÚÃ÷ÞrfŸ&ü¥+ï… À¤½?¬Ó¤ïúB[ŒoúZF›¦óšùd‡16I¡×YŒÀR¯Tß3åœ&¹¢¼Ã!,ÇHî2?#„klzìÏã! ¤äBFÕäÑ?·o.×¥‡ñ¡miáZüË\—P ùŒê~a$Æïÿe“µ‡+ æ|’WqOFži: ‰èM-~¶Kwëœh‘ i呇²ÝÚ5 ÖévS·!G­b"I{$_õà<„„¢q‡&ô”ý4FedF¸#CT¤L“¬»RxV@é¼ÀÆ#ƪmgž¹¿‘êäáSÿIº”4VwŽùÙ•¾lƒ]äxð²ÄõñGC³EGEoòW/“€ô›eæ?ÇMm×Ë¡ «(˜ÅÁÝð,œQTô èëˆ0oÈa ìn¬ô\ÙK†¥ˆ5ìïØ_¹”b‰…gÅÀSùQ´£FÁ­ cŠl}<)0b˜I€5F¿1{ó)ü/‘ Kåþ¥áU¡þŠå—‚Z&€}&W«}/¿ÄvY]—¡ð6)©èœ©’€€Û>PÑ œ=Iý®ó`¢¶9°œY4‡gLièmÉÛ™gr^ùßÇØ•×fù·ý•ŽÃ–»DöE²ê}šWÏÜJW }¿ßCbK8¹Íô I*7·÷5ŽâbQçVò°x[Š}·f,I`Óñ-ÑSÒQ¾ŽO)~YõM@ãøU;Çžç®—D!Ù (pô¦w—PÅc\üY¢Æt¯Õ£t) ËCwÅ(4ÒágRySr£(#íùPwï.Éó¤øÊ(­¹K3ç{Ó‘´ÊSÈÖ<‘ËW=xœXHóx6}%‘Ýh†¸ÅWHŒÐ¥/#ú)eýy|ra1e#áoÛ8Eþ;šZ•ü•ÀÒzð²€5í>µkkáev" ìÙº©2|qSh §F|òOuV’Ф’i—sJ,=²qí*Òƒ²¶ËwÝYzr1ªc‰zŒ©‰.n˰-øW%TGs€n+äD½^»¸[;O@Žð Uã}º¡Mº68ž±"\[x% fqùBµó¡GQÍ7L롤ÿ¼4.Ç|À39·àü14"ÎýŸ„a]@°²Ð~ºn¶,¾åxN9‘”á½Úµ‡ ;[I¯Ý^0ÄQWâB_ù/§aɈ‡Ü‡æàG^Cd ™Þ5Bx,µDâv°Ð0‰í^UÛ«Ó[š2(ϸ|‹^§Ž…€ Þ©_Ǭ=“$(c¦÷ë\FYJ˜3ëeV"öÇù.éÉ'´Ì{¢‚N×ïã»…” õlÞ…}µ)f)%~b^ÎíYUû²4_ÿߪ×ÚÃ…ú¤Æ!‘á@AjÙšWú ´=ºÞ¹ìRCã°IÍØ'Ÿ¥leîk&¢ÜRØŠÒóùÛ›<ç“4Þ×ëz =³”m0ܪtô®1ñà‰ÜµåvíÕ\ô„ ¦±úTà t¦­sJÓø¤9‚PC?GJÖº‹úPˆžk…ó®9¿´iÐ Ù mû30':eé½ §œé͎ߨŒ¼ €‘ÁéDIo\ÝFÀ(ëÎ Ó›mk8è»ØgôÈz½ƒŠj "àÅ›$‹Ží@ûÇ%ÿ.‹XmH±­GÒ4¾’cü08Ò¤]Ûp^hù\äЈmuw _ª¥+I‹óÔÝ2 Ææ>]²eX‚}ší§9@%–Ì=½’€€»Ð·À££KÿZüŽ—úLÇû?BA µ}e‚u±Å9ÈòöØ ¥1™Ãñb•¥í©´âÈå Š|ÇJ2FaÕ0Mªµi5íš½ÒgØÎã°¿ŸÆù7ý3P‡±0þÆúVëއÐÄïî<õôB»p,1ŠÜd~òùöz(ä"n¸ÂˆAn³Ï•væu£5“‘P4›I¶UÃRZ¿`Ëèòùõt~—zǧï_C{#¤©äŽ¹â‘«‡úûå§B¦•±"ìÁª&§þô´ÜÔë¶pÆ]¶qÙ•ÈdNà•úk«h¥×1…JÏ_'!*vÂ'½âùU­¨ò"Fá3qqœxi M Z]#[€ÞmÅÞ°KžÇŸ²†ßuÎ;OËRºÈÜ+ÈTT¨;“Ncó¹w} 9va€lõ_3)q«ãÛp¿=8|+™€úk°y£õ§¹É—–3øÿà㺿Côä~gŠ$åa¢¹P¹¸ZÔX‚2)2”ê㉹üÀ߯ÊÔ!dKß ÅÌÂÆõIõÔ*æM×̔ʬ!Ñ;Ó´8xü5=ƒcßœ¿\TÜ–ÇÍ’/ò›c§VO©ZÔ¸"V£ŒÂ'ø—°ËeûÛ<xI>ú¹#Z½…µM6‘6\¤Ã‘S8’!§ã™“t Œ=åŒR$ß]ÐêY#æ–B ŒLi`®@±h'ÍÌ»ìÛƒ ÂðR|SrPBóþeÞ´ñ= M‰GûÉ9' nÊ0©¨¤6$)knJÊ StÃ?:† Q0ïÛˆ ‰Á(ùýZ‘¨°åF}]ô€ÑíZ{üµ“V/B•›º<'©= i?Ѓ´©©Z«ôàGâd7©MÑã$z[£¤y©ñÌŠ¤Ñ0 ú€¼–¿D;º†¹¬ ŒÑ4“]Cô,¿ú:+Q¼síýèÝÎ!Án(©jžž:dˆYEâ¢&S˜»¯¼õ掵,æy[]n9P1° oX€1úŸ®XÑ _…  3ç¾sÚ¤îŕɆ6Q«ðjY©£ÌT¡I:Ø?ëX7Ò; #Œ$ø¿gõš©J›ÒO¦ÌˆzÃÚí4¸ŸG¾ŒàjuU—o5‰ÁáÂû0)½äh¬„wô}ª'KjÀ3Äw4=ª—« ¡.D² 4ÒÒ1‰1ƾfP¡B⟲[n Ò’€€ÓØ…7{D|àå9ÅŠ“9…Ä· ÁäP²ošz^mK¯£åð¿—º×{²¼æÌeM íÕFMÎÇédZ!Ïö–ˆØÞ¼ßþ×qá@œÕÄÄzìrA;×îè\ú^Â-¦ÞΰǺN½‹»ÈrÅË›»áH©n'ý¾»,¥ ~FÖú™k«ùÑ 0ÚIk;í-¾(ˆaóa,1UiI?]DØN»Ë†Ž¯X=È*ÍKù…ùœ?I‰F- °SZüF/ù;C¶Kí¹\­U{Ñà¯\ÚfýWÛ²Æ)@o¸u>ˆ «žØï "zø‡É«çöÚO= +'›–?Ç5g ¯\ËZŸ0¼xû®4áo¢Aì¿»«u d0n¬±C2Žxž©ã©lÎhýHócÊs, #…µð£TH€äc²70P<¨?ÑÒ`:«ºÑaÜ(%îpY€··ï…à_äë_¯=q†ë¡™ÈBRñË5EuT2_ÇZ ÁÓåJ{rG'ê]"/3ñðßï û¬Jp™Z2 ¢.jDGW•aö`ÎMERÊL_É#ŽÊ5©<ùS¶Æ#ºÞ÷V‘ÁÜX÷E.ðûᨠáú{ñMÈS;å=f•ÁÝ4^a–…R˜¤ Ó´}¾¯ôrVø·PB«çÉ–^ª'IB-½íà\I ÝÉgÎIòwÏ#kt·ÿ`Gamó :IÖL ›œÁý…ÕŠf ìµ.?Ëâ ÒnDvÖH7ûtk®oýÑe}Hó÷ØJ׌ûáô¾Ö®Æ4aÈ·ñêÈiÅ@2’’€Ö}Ì7õŽ/"Fõý1ê’ï«£ËOí@Y‹—ÿãür¥ÕX}¥xå1QG¸Õ†…æð:Š?%AÆKó5æ,Ì'‘üÒ¨õK÷âÆz5ͦ¿ºŸºî¯ª.S®qJÁJ÷©í½{G<7ÊŸŒ:k+1åÅiÅe§ (0×jñzS„hn€]'^¥Ë”ÿ`±o7›ƒ‡¼ª5qÀ˘Bø•£ ÊxM’ÐîMõrzÛÞ˜ ê˜H?Iì2E… f„šTÍíÒtÅ»[èT—˜ð*u––Ù0ðÄ Ë$;}j¢ EœÊõú€ÙPYµüfµ¯=^»<`šNG³á7ÎÊVw¤6þ†š)ωõ$Գ˚¾£³Ý“n’€€ÕPr!’qc§‡áÔWð¦G­|éÓœ*Ãíkbµc Jý¬_Kã³’Q kö`ß´´¥“2ä©úäÏ3Ã&…Kš mé÷AŒ…ûmì³áeÅnÊì¶Y,tÜùcû˜db¢ÁeŠ‹Yƒ(ÓÍ(¿WÎßìk§vðbü Mil4Áçõ&Ò-!/¶­I¶enø“Ä`ÔV¿\S¤~ û/ž H¨7Œ³æù(gå+ùØä%ƒhg‡$˜yr`B†áÑ$ð|bÚâñeŠèŸr¹rmà‰°/YëúR›ã=[¶TU,ôoxù³\ äo±T…[I3Ø+.z£¶_’ûÉmeéØK'¦×Ñ.óP¹Ê.1 €¤Ð’ïŽmVu¬„B'É$…„œº¿ÖË8ܔƒñÀ\gÊQ*Úþ«]b±@ïÇ¢2{ì={Ge‚3ÏŽÁ CGæ!cmE݃RYÇøoì€6É?¢bþ„“y‡±©£gèT$Œ'¶bŒ#E &I[QôÁ™0$zÿj!'ôðûéx^ §”Ó©ƒÊR½×Ú\á›%Â#Öï‰úª=Âþ©—Øœ~uTÐyÐ9dž\ ҂ׇCuJž[kïŸwUImÎ[X5Ë@µJ/3Êf¶R5JÅ~up”HçäôøÑ“‹…„‰òÇ2£Ÿˆò´a`­ã¦‘~ð·ÿxéY³jQû?|7‘˜aɯ‡UËŠËW"‰XÖ¤86°r°]~âã–;·9¢–1Œê…Õ~o™/i‚QâŽ/n°¹W/мtŽÁÔ¦jˆGP3B+{Ÿ¿ñ€­Ri ™çë™|"ðØ†¿®©àîvÛOÑ4ó»‘ðH^|ŒMEnV¶š¼ƒ!Î Tz6uù§dõ<×; 5GVœÒ@õ•Mž¯¯A!Ø,m!åÅÄ’BÚMò"H„¹!öLžQ–,Òý§Œ_@ލéÎ ¥Ç—²S*×ýL©WÜ´Ý'èÚ¿â€L‡ i“P`‘Ú²›V@tÔÅf–Œ91çikVnñûZ/Tˆ)ºÕéT²åDuÛ˜mc@‚ ™VvJ“rŠ?­aCO%&Ä,Í.…æ†Á”shª 8—Øjànm%ç–8D¢X®›Wä1Ã{ª]¹-ÝÝ#tM$-í^Y•’€€»S.³ª¤ ßÝÉ3˜mwy'¾úX؈p@ŒkÌAÑ,[¼jpÂõl?q uˆe÷az¶;/5ùd:õà À‡iôt°~Ù¬x$  ’öØämkh«‡ŠGNhÏ ¼&R¼þ  AÜ{sOœ X2ùc†°,Ã;Ý÷¼ëÉ‘8HÕÚV•£ g¼ž3(ß+þ\ƒûÓaPkm -G(péZ4›÷IçwCÉ]H¶|^AIìñõÏQ,3Sõ¤p†ÐØ2Ôj‡R]ÿ ‚éwÎ}À¸¼(„Þˆâ0Œ|}.8R„¤™Qé¡|?g‰ÔW›-Ž@¦·q›‰‡¶§lÇXÅ»[Íš( Q ŒÇâm+¿.Nî½óÙ ÙszøžÄ4 y¹¡ÝÁÍß7“3q**ÆQ¢ÐóÌ7þºS 8@mCa5\!͟ȾcÀBýÛÄP‡e*nÁ1vZ2/Ó…û‘u¾ñžáÆjŽ¿üK† €ôZ9,}5ã4³·ZŸßªšÛ çõSµnûæ˜m•¾Ž;GsLïúÈ-ëÔàx ùd:ë ”l›eyùØRùYL"BÑrU|Õ…-¬$¬ yªU•Uÿô;óü¤²ÀÁ¨(CI8ß0É£Íè‘c<š2fšÑ4IrPŠX@Hai1°ËþÃ=_ç|4Ï¤ÒØdA%¹äg>d ™¨ÒØçÙÍC¶È"ºx€¯f”¹Qs]ð>à-íÖ‚ùä°åõÄ)—í’„š‚U Ì/T¯äõW'ö~×™ôÊ^á­Î€t1vo{k]žA&Y,ŸÎ2Ø=ïFòî¯=:±Ò¤Á@J»@üLä‹0MöùÉÃøÌêó is‡ ×ÅwåG]74åãκ/—ÜÄû_¥]…A1²rfß‚I&Ò° ½!w\¨ìirG+*'ûïâ§7r«Íݹý>Ä2™ù¤y[+ǵ¡ì˜T7…¤‹5ùŒÚ’ÉídvИ‰EœÃ¦7< Ãâ@ ÄP_¿F!5Á¸!7(àØ3Rb/èɳVì[0@‰œ5ºÊ‡wÃ@êÿOðÍÌîÚR"r, Ó4€¢/$Ñ 0®ÈçNi¨Díoÿ@…VóbÀ^`éX»Æ^k]Ýš¢÷B«¬ %‡t]üJÀ‰Ùe1¾˜XåÐÜÅÞ[×E½È¹ù现d8ýãÄ™~õ–Ñ<µI§×%Hßš^ê¨Q>¶V²„°]Á=ZX>Ãx¸ð´ŸUm1­•l0ªÿ°2€5àÂæŠ«Ä£¶ÝøH8\Q‰rû:“£ùSœ­U°šqW¥t×1©få·é‡[íàNÔk*ñ¹HÔ‰•ktÙ¡„]B’¹4óšÃZ#úüJއJª6%bM¯°Z•Á*¨hò3– ~d~S´„PtuæúQÆ{Ýhb õ‡Úb,ã•>'ÆivßDq͆óRŽÀ ‘Uê̶ìÀÐrÁv‹):§_')ÉÆØ&·,‘FÄg…àBµ„;ˆo'¤¯+©á7±Hò˾P¶É<è-&J “ç"*Q…‘òXHï†*ß8GM¢¿pO/RÂõàQX׌>]J6'b÷Œø ’O½¨þéme™P£wB5îüåÓ˜…œ©{''ÀEÓ“¿k¬Yàû1 :Æ9 ÷Û"?´8@ÚF²hm¨uŠ ­~°ŸH¸¦¬6Ɔu?ÅIm_ý­‡vùË&zçK>+¾\’¥-g9Ã[¨½0f‹ì’ÚÀþú§º²Ä¨£Q ¿Â¹©g¬%›õ:¸DK~þSÂqê1£oЩy½?#±{ç&¦d­… ÷„¹¨†vœä5Ùe¤;Ù@\s^œyÅjÕ°Eó!{žØÏÿ#Jª0w5…x;™k-åaªYqóÛ)\ ¶¦Ì?mOGFR³'ó ‡–ÜÓ?OÝøa¬ï¸îC"(m¾ 0ÊÁ({Õû8ÚÄu®ã”åCPûKÇ’€€¾¯QŽ8arø’IqòÑZÙA£Ì7@eTDAÍ9 ß¾v4€‘ QXwË8Lþs4lX:fÍüÌCÈK? |½ ¨í½ÄCMPw¹…é£6IJþÐzqBªÉËf¦ ³ÖªÝnžþçSï+ÉBƒª« Ѽ¬×ænKs;¢uILÕÆh”3ÀójùÓ»4&‘w1ƒ¯ª–Ej~Ú“ ÍŽa,zôähBT¸ò*‹ÕÖ“Ú6.`¡ ¥îú¥"㉇‚/Ë3ûÊé—…1¦¾”µ>ú(‚æjMÁÌ[ú63 vËV13¶×Ð`÷œ(jï+’/ !$¢¯ÉjùTa[5XÉ„)mÖ|>™þøDn~\©¯=ÞJ¢kme{[d®€„cå¤Þ ³ÆL $Y¬ejkQš0õëÈ%ø‡j7ÌÅê£mÀŠÌ¹4üª÷ðÁ$Ûû±ß©êàš°‘^/­É:KúИY€êm~Ë(ø@à×A~+¯^ƒ|êÄ¢W^N¿5 ¦} åG,†å~ËÛnå+GhÙbåbÕ+`·ÎלƉ~¦ç˜b ˆ &·ïžW9îIþ¯Ø„¨-ذ\`ªh<2•ÙAU?LgA±#þóSæ.ù6ÎJïmÃkfŠï: u]yC™ñß1ðûp¼)ÜY*ÆœcC˜U9¥/K…Óùy}v`àÊ\~Öªgåžš–×1ÇÜ©ç1úûÛúŒªT»x35¥¶Uª€£SFk–kƒ©ÁE?K'£‰Õ´7 a³éƒ²ôÇÈ]˨Š×{1AÈy¼«Ú)þw zŽ,®ë¶+¬?3ÉÒh óazµÿÚ?Ia…57O ú¶€5¥Ï~AëUªì“‚OocrÿÈ*…–Ë‘ ì ú»„ÉwW2Òöà M¯=÷ÉYîÄ[Í2úßo{N+•\ýЩ´Ä|5\Ž!|·•aGËûB;Ó=ÊDǰû¬@NÈj «¶?Øfp¤øä”ïa0†¾xµ?g~L¦ò]¥¼e}àî?”:ƒ•ö9+”–œ\áûAZÇ/nÓbÀḎV§|‘w?‹Ô¹”Í%q0î:ÝM¨­¼Á–‚þ¨ô9ø2¥¹ ÿÑóghæ\ü‚ÂFí—¶+ i%h» æy’€€Îã'ÖðÆ4¢WJfÀâ”¶¶Oú/DÖî'`T šs^C$Àc¾|‰ÛùOñM.n0ÂSª/O3Ãxž+¿(±yÌo¸Q -@÷I’³›Ë ÛxâíÍË©%´Pñ5šmT™í\Ñ*?"ǓͣE#gGføË™­†Ò4Ljc€à¤5ó{©Íë³\*à4bo€ÕÑ`Ê?v ýÙCÏÔIi¢‰FÛ0ËÐë™Ð÷…´Œ’• À;Ÿ’ÂY5CQ6 ´pª5ÆÇáÅ;<ñ¢_uŽV.?È#àäE‘|¸Ë¸å¶n¹>g¤r8[ ün¨¸š‘Ä~¸ÏÖƒ¾Ð6-¹êBP©bìKÃzqÁ®¾Ø2¨¸£ÒªâiÁ™W›hcHîDõ¨ròϬI´Aà¦{¿¸ûÇtœÃŒn8;¥Ì"|Ö:¬óEßó–¶1DÆM…k)¨'§Vë¢fcÖš½Õ±A­~Ή½ÑíÛ×ÒUnãt̆©!¢÷×§¾§]¬nÝ ûùÍ%!$ÐWý[‰õ\λϩ]U¼„ÐGä{£{3]w45ŠnÜŸe"~“Úâï–äíE¤±ØJN,ª~ñ†Ç-j‡ËˆX=eƒP‘0 ¾Óï‡VI™Š_Ö¶G¡ªçЃ'Ž<Ÿ§Ï4ñ/ãÈŸÏð&U/)% ñ^öXµ°"ìÃŒ¼Ý¯WʦJ“ºÀš¼¡â³8\jø¥ö'îÌt†Kò¥; +wHܸ3Ã=úa^›=/¢es}Ç©èB²)¡žôlëúÈ`ÆàžL®^2„”gMÞ†’€€’ ;ͱé@’f¬l·Gý€eòò,»–ŒöáÜIûîüÎG7pðEïV¡ô0¼ð¿’xeµ$‡g´• ¡Þ&˜ÃQ›õ8½Š0φ×ÚaIU!Qy³êa9Î×5'\Û×ñK"”¯ï|#¡¸ápjMEº`XW«ŽdûÒúv“N 2gŒº6÷Ò-©qæÎ»[¨nJû»Ú]: 7æ/—Û fÓ½ýˆÎþù…@›a÷ Ìf*œ9âw?¡ˆÿª¾×;18掘"‡ëùÅB³’&O¤å‚6û~?ÂFGO†›Òú_u;Á‘ìF*«,ÅC÷DØÔ«¨oó…ýç#* {ͧŧN_wõ‡³ç$"ú}¼D©ôÊ’¶ölfŽ|–ùq$áð†¨bn'î®èwÞîJλ î5Än¦l]Ù#RÕŸ÷º±µÝ>¾<(ÝDÆhæLOR:ó±iL}©DGü+B}:Ä6g«ŽSøÆªþ»šR‡UAÎî£ñν޳4¸ð'ÔÀ/é’Fv»Ûn“œTEŸr½ÿ¨~ huÈZDmL•¨h8-…¾D52>GgHrX—2iT‡H‹ _×Ã@Ç=ÈŽ«1ì¥ šÇò¹_fŸ.˜À˨¹ëË5¸ ðeR´{(·;å±Fi„÷WCÙK-þåÒÇUAÂXî†ÂcÝ> ·ƒ1#Q«1¿Ü± ‚XÞkSxÒãïÜ 3áÖ!œÎžU£ºavÐó>õõÁ:‰ñ§,K¯35ȱ?;麡Õç3ÌᙟNˆ.ÿ«+Ö÷ui„gO×Üø—kB‰Zñ¾ œi•·¬£‚¸'`È×°l (  ¦‘À`ܶÄÂí„tM¼lnj£ë `ò‰“E!5Ê?BT«Nƒ:L»¯Ž%xë|Ç7Óûã^àtj¯`k0u»¦G©ò¬V(³.9¤HnGØQo§“éŸäó7”S¡Æô ³–òŠd?âŸÆÜ͈>òƒýËw$ÉrQLS!²Ôs™%D8£ˆXã¹mßÝš\O‹KÕâWJöÖ˜´.AØ%Íx .wÒeËXßàž=ÿVÝå}oÚŨh©Vòæðƒ Ìä ÏÒ9x<l>Rõ—øp‡„¨| VîXq±´'<ô: Õã/”ýN³D'·¾ðDë–:Ùöå_’€€Ô„fnŒù¢f°4}KáÙ¥y¸6¹Ð?ºP};“Ü9´ühUØ4.It\ :Ø_Z°Æ´iˆ œmdêoÝ—2#™‡›ÇF¾~ݪ`ëÛ.xÞÌŽ€ÌyÌt¦-ñ ¾YíFçÆð»ÜØ*˜(j‚ÆÅ#Ä»†f qå«'GÌ öô¨âð9CBqsí–äXŠ0䨻éš8³G˜ôY\{)*(Õ{¥éJó9.väÛ<ýâ„Hæn…Xÿª²Š…fµ-Aó®(è¾ÛGÊà"–޼Þý¤"œ ºŒTŽ1Á:ƒ_e}xõн™¡vä'SZ\Y¥º½*mUøÅƒ?.þz$Ù`ŸWõù-Ÿ47£8Æ`Â⪥ÉòâIDÏaõ1`ÂÅ=<»ðóüJcã †GGãÙ;Ž ÂTûEpúÉî%öÊ:Ê®a<–¼ªh¢´/毳 ŒÙÌhÓǶ…5»³üÐ ð’ùÒÿ¨’¾ÎËac ûŒ– ОÉð ÿÕ-8Èk›J3™`dû~`–T5=^¡.¯¸í’^O>fô’€€«Z6ušJ™ìpᑲ(¨X¦³€ýå{šqù„Œñ€ý¤ ¸ ìIÖ;a­ šÊ¹EFl|F-—dÑÿ {'{˜8—CV.…–!A@1^f6·C¨¡*d@2#AѧF&:D$šÌ».ɘs$èÉóžð'ÒóëFn=§ii$Ò—¸[õ“ºÂouò^-¨Øƒ‘:˜\;5@Ú;™äz¾P|¾"WÜB”I¥Iÿý¹+‘¾«…µ÷¿IÐÒ1Ÿá<\ 1ÈkCç”ÁE¸Ê ÆÿÂ6YuÕƒa””N=°¤5ä­¢>7ËÁƹ(Ö à– ÛUQWyA#oBô±rCÀ`#¶é£$*Øy†-L2âRE¬Ø’I¿ ÖÀúâ)ت[5Ú\ÛÔ öáÙ+ B¬w¨äï*máüïð%Ž%¨f!sÕÍà™ñžÂÏQô î-ÚUóïéx«ÃêÖl^¡Å36ÌCá™ßƒÑYi%Ú¦Û)¦Gk£Éé‰üÏ]vLÁœ;ìd‚¸\¡ œ6ò¿ÿÌÞÄÕN ÓHÛÂY€Ì½—’ôR4A ¶LÍ­Àÿÿ²ƒ>H˜Ï«8Bã>ïyÖ;ø%ƒŒ`ó§“r£1—w\hv„Æ«בQ±p†cf“£c†‡YV"ÏËEÀªØß–uPÚg‘u‘‰µ/Ü¢+5±Zso{ß3²oZ_h´SYÖãÊê°Oã{¢¬¼e:äƒ_‰ ¦0© å Ö&±÷Ó måÈ= Ó{þËál½> (x¡]æð3¶' îÈ)@¯ºçqøý†}† ô€s„}÷UÍF}Ï?˜c|¯å†Á¡'Ž®ÿôžBØV‹†<´‰$Lug#W^´¹’€€ÒÅåÃ(6ž8¸a´ËA×Q`3Þ'†5}ð¿XOMí†Ü\˜Ž¿[œº|î[Ò_€P…­òƒÌaÁó/¨=¼p¡rÏÑR_€ì~Q¨â1i^Ú”¯No²{™WY¶aP€VñEL¿h;çS|–³}1áë÷+MGÜa1Vݵº¢ú:ÐþV¶j§jkS¿ÇC¯ÏœøÔ9³îc¡{ǯ¥¯œ vàÚfñ"|*½PÉ# ×¢ßìtc[‚õ»Ñ:üžz!Œ­J¡­6?4ÒY¶ R³ô¬¡ NçßègÒÓóãÌîþïª4ˆn¬Ï£O^e|rÌC†©®]Ïk0Ú~´šÆtk÷I¸ÒÕþþRÖˆ2€&HD! 1´xbv¼¥à¬Æ!HŽIä[“®¾ÖLuÔ”•mG•r;…Ü4›¢¥3mK¦ÆÍc'ªEGÊ^SŸ$&·Öä9!A ™Âˆ² µeF´M—ÜhOË¢`µÇjq_Ó×8Íô¾ž‰lèbI­¾½t>‚5"Ó.u|(ØqvŒTVƒŠó^þ”­ÌY%j¤ïìÛl¤Diúqáå³°B£8p¤fɺ©Xàû<÷J<](àâoÙ+IúuekRÿížv?¥ÎG£è1C†)ÉÖõêòrÂåL’±RÞ´ô3{?±™ý~z«ý\lî8ûc?ÈCËÎñÌþkâ‡CŒÊ ‰Ú•5cç.ø1â ÔÉó¦{Öé©ñU“r«îšä (Cõ˜YÀ9G"‹¦ê"˜¬|¯²³34BœåK«¶÷ÙSWó KQеkût|[Çn@6K•̵ù*+ÇqÆÚiçe›(ÙªË%—”™ºV£HÏêßÛ§Æ<©;våtªZôÛåÿ5·ïâ02Ð×GšH•^€ òÕÅX »8+2Ø; ù7~jiÐíñåP6ÈY‹<õ_>KI]Îë‰dÎ[þ5’IÅÃZr+%8ú}& ÃËdZíÈ{„¬ÏGŸ×¡–eD‹çbw®ý;Ù—ò67“Yk‹X‰~÷­áUfSp˜0dŒ?“¨Gç $ʱWøõ$6 p¿“ÍÐè9ùÞ æãõ-òýMê¼øM.jhþ«Ë´¯¬Ÿ€ûá·ƒõ"Þ¦ªz ›Ï?&•°äÀëöòˆ8ÉÝ Y»éîž¼}µµÝ×9P^Ûém­½É)Bs¿&¨_âײ׃KpHrB ð–ÓJJ`­¦§¸.ŸDS7ÄÎéE<ã‚£h+Rô×M*â@ÇÇ5MÚ¶8©3ÚMCkÒ’€€ú™ñÕ%æ…Œ{SóÛ RÜ]×mɤ8²rçÃóÓ$ñE»x’ ãÌÊsÃV ò{+_õ¾+Ï(£jav¾ ^üÖãZŽÑ¦«çSqX̧t¨üêg¤ »´³H»•_çA†=EÌE$¹›™ì;†ÞÕ©µn8gÂ3’.=·ó]eÀ©G>Ì0Øð›d[ˆžMScóXV°”³è>\pL:Iw‡ØHû÷Ym °ZÜÓ]g">ÉMÁØR¢€^£$RXÌ[\ê<•ûà^ƒÞcï3„ÃËõå=êµÌ›#Ñ~ô Ž?¦hæcBkg¯‚þL Ô©Æi›-Ô$‹CCdêz•ÂAóoŽ/MLÚÃ!â žgS†GZ£h@»åÍnþ/¦•¤sÄ—Pê0Q^ܘ/MèâXÌ´\Ž Uk4¾×ràÆl§CÊ!KÒàîIR7Põ€ÜËd™ù”«SûLlVÅó –÷ºDqWÄè_=Ц9­ùqΤЩк%hp6¸VZŸEÍL‘PX=vXw]š½xßÅÝcÆ4\‰Qt£$iš‘þuôÔoµm–òƒ¸“xˆpÞÑà…½Â›5jÂp€Õ] \q™—«Æ:q6y~=ÐTò˜×¸ÌS€Lá–^!p¼]ùïA"ž­×a€$«Ó=ú ¼#ð3ƹL£L·h[d¹ÞY‡—?ŽûÆ¡4raµ §hWZÞ“CèÈ›üиƒ¤˜%µ§‚¡c@š±‰ã8ö÷"ê¯.Y5ŸôôÜ›ÙreŒA«ñ ÒåcrAŸú¢«5³é5¹7q'ŒH¥@I.gÇ3£Ê#¼ ««h¦*f7Wz$wìIc ·¡SQ ØCyÅã>:¢‹õö2x@ ೓‰EX»­Ó¿þÞ^/0òHeO­¢Äcˆ(Õ „§ÀÒ bæ’âV0ìÆËÏßÞwˆÿXÛGŸ´Iö£Šž3Wö‹jRÐàcZ›Bg¿0¥Û¹6èwؽ?àt¤`œ×™DIv}ê:.KOˆ–×Wl`bÕ çò$àæŠn+HF»Qê?ø’€€¥ÎÅ“ÈzÒlk´Øì9LЧwùÈnö¶;_¤iÎ(‹“C<+ÒÎ[=B³ˆDâÉne†ÏŸ}y’ùèåBmü@Rìx-ÄXWifSkti•üÚ_¡…ðdÈTž®Na¸ÓlÜ7­/­yðœÕFâå'¦<†y¢Mǔ֡BK‡?FBÙ%Ö5“Œdø±>8Íjp4z³°²¸>VP^0úš÷…¡tçÌý6©BNCk°YM¡4¡:EÜÏ3ãš°å“ó£+} (~p˜ ât¤Þ_ÌØà¥µi¦\³¸gæ£,l+”™Çzg\ÚÈ™ -ÜË1­ƒé‰¦Sö¥’©»ƒ‰²S`þ @ ®€[@co’ŸZÔv¸mÜ<ñv›Õ—x‡uBó¢‘÷”Þ¢îFä(Ì.Ÿõ]¥:ÒM×ì"oâ ©ùX«“B57 iQví©íÐl$y¹t9& 2 à UޔϕrŽÄÈjX=¦ä쥜 —p|ïï@ªí'0¼M¸•ßñÃA9BöéµöðÅ›Üñª¡QC^¡AÝ„!¹3Xèýp¼X»‡*A3qŸ©Ðªö 0¦ Ä›¹Vq$~÷cUF­TÝy'{_Ûe­3.¦ ™žWº<àV3öL)Îäv\í!ÞãD–ƒÀÔw–ØönÚ1FꙆ^~ÑIŒ®yƒx£-в߇±%g­ªbÉ@6bÚß“ãmJÉÃï1™‹ÝÚ#ãx@ž‡Ó…T&±B€uå?ÃsèKyC  •3ÐàON¼¼aâf³x§Aà5Ö0³SáÿîaO-Í)Ú@´…åq䣈xøºÖ1Út ›Ö—ξX9€õjºŒµæÍªëšðÑkP jŒ(cª6︦CgPV<’—ún3¡yÛÏ'Μ#o$¡¿Úz3“C0]WVóâ"ì¬&"GáHÔúŠÒû“AkÂúŠïó?ÎgB². l—&úÊ$hu äÿµ` @Lþ(¥%a¥ǘ ‚T¡¦d™Úâh=?ÃÞÙ½Õ¨ôɶÄîí¥* “j`)¸»&óñ7Ï–¨§0qózZ„æôþµÅý6©Ê[ÙYz çn&T |¨Ô¢kaümYF!ß,DJ‹s ÷)˜X4|>#Dj·Ð»¥#R‰¤7s­sŽJŽìy–t]®Sú¢óXãFæ’r¡Ÿðy¡(ö²ûÑéý£P{AÄÜ+ ~·û÷—Æ9ž©Â„þqþï0}ëŽ[ÍK¥)n&0cýã²Ü5$N]ãm­ /5կϭé¡IÐZ³Åž ·¢Îù>;‰<Ê$à0/‡;e@°a7ºAÓê2Fw™æÏ25‰i5q]7Xò=?¡n‚ÂL9¨8%ð–fX´µ…×pã*üÕ¯¡¨)ó?ðb±V)šK𺌯ò¤$~Æov«† tõôW=â qC±âMº4$ï×EG6Œ«PJ!ýl5;œÍ;ìœ!‘1¬ŒÆª0t¿1Ž¢h~âgðºPî¿À$ i‘£ýºD<†¡Áü N2+UoƒhvÔx[cÜSç£n± Ú®~<Ä£Å@†o\À=æêñXÒž[eI®VIJ^Ɔôñs­’€€¥’½ò-í¬Ä»ƒb€Ö]éL²g´‘¢úÁœ×lléA]ÀôGéÞ‹óëÚ#êŒRX¢@ËuÕÒÑ08lHgç8Õ€µ ÷š2òO-Ó“pë©ÏØ©|vºÿRX dY¨d”¹ö#r—Éì² ³ c ;??³SóéÑ WlwÝä´ÈîÃæ]­â¶wb¦}Û­ A™„+Êdµ¿©­c+´õ§[ëïbëoo-’ò‹¨ˆÃEu†@9¡eš ˆ,¡cSƒ†÷}è {±:·)rñ Ï@?ÀB߃cÞ÷s'¶r ŽûìUÁ_ûQŸWN($ó Ýíæ¬‘*BRÁ%s=bÁÃŽ7È‚9ëþ„®«b{º5ñ~˜ ?ßé1 f]ºøEiyë˜ùE81ÿ_NÁä~È¿l¤G#í®tz“Bžx¢S>É›´ByŠo±QÉ/$'Qµa/í îÄvpÝ’ý„cIw3\D8ªa¼ö©î } 5÷€ÓÖDÔÌd·™N*Œ\d o{Œ¿óÌwšÝµb~”sqši æõz„‘ºV MU,»LrÅüb|àŸöœQôÿøä¹IÓZ”õ핪TмwðE]„7¶ñNvíÏðö©3z ¶‰…¬÷;0 /Œ,GZÚ'çZ™ËTˆÁûKk¹|f¬ôá-•–h–ÖXtaÜz(’XÙ™Î+/…ÊÙ°çÿÚŠ‰Û¼/Ï3qfõ!ÏÐöÉÅFÚæ U¯Áú-®š¡ Ñ#ò€R®ujehOïø)Èn¹ÝiÌ6(b€ËVKwÜË7“±ý`°’-o yð“N°gP"U¥Éh½s|»înÌÊç5A<ÅTz„ï;¹Øþk¡‡Úâ,y}Èö˜]:®¢V#„‹BÀ'£=M,# §êîÅV¤¾xôçØ¨}«ðM,ÎôaM¯½¥aÛ-½­u·ûÛü¼6%¶òÏÑøÃ-F¾µC¥ý¥§/ÊÂôˆ6ð©n…Z”^92‘ 5gê¹@&íü°Ür~¦8FU"ʧµ‡è"w¹CúL¥Náó4D!DY׉ú¿ÁûÇ”Ž“(?újRI£q¾¸/£ßù3‰bƒnÅ-®=D©’€€´&pIÀýw%Nk±âÐ’!!EXhüÚ%‡G7ؼîûÖ¬ªèœ± 0\íÜ6_Ä%1”f¢f¨gã$ýµºœš4jÜWŽ$Ž&Ý®ÞL¥˜Ƈ/x-úF´.K×¹,¨@K”—w‰Í«F9×ø“c=;”òôÛq‡¬ô¦å<Weîç°’Ìw“ì8fÎÖÑÖê€dé`;ÆÕƒPDí|cðŠèD"ˆÌ*¹+0±²+%õŸg̉µtkU"iˆ¯BÈüòÝHkÕÀg1å'âé8®)Wf äz±§×‰R)ä0Èzay&s’C~ÇÉ^FÆú¢TkúæŠñ¶ä1 b‹Ã†¤ž•<).:ÛÒ";€XÏð"ÎYÿ;‘èÌœ™§Ñ­p±-h­V ,×iƒŒB´[Ù-^ÂQb·nuùÛ=·Cßå‡ÔÆP¾›Ÿö±:)—›S¦^(ÔØc/Lì-ˆòð„dƒg$Qö(Rpç MÇzÉb³W®__ü E0‘A€˜ñ¤oy’Üj©ð…ô‘’¥.¥’€€ÐpýTÅþ.O’"ƒ…ÈÖ™£ C‰wºÔIÔD4À¶êà¼Deµ%Fn)0kŵZõ˜èLš(µm½8¾‚pVäÈ;Ÿ<›M•_©?ît}1bÏÿïS·é·4Ø9Œ©@±\†;®œÒgá“Ý®ØäJž8à7Õ¤;0ÅB¶›ø-Âàâþ¶.«ù°e‡Bܾ›0ò¡g=F&ØK´œ-´‡Å­qŒÙÅo/ñ˜ºÆqNË(‡V'ª£Òéÿf_‹« øŸ3ö±È t5FŸ_ iÆÙ™‡Û¢:î=4ïR*,p»´Ta±ë /ó­<ׯ®ï1%éGÒ¬ŸÀ8OöÈÿ-§˜µ4ö«Dn«×œÙOŸó—f@<ŠqÐöÙWs„ÃÒN[†±@¤#µÕ³Ÿh½þ¨ÚF˜Tãlr|ÄÚ[ìA"Žìã%l–’댢¿5=›¬° oØ&,N9,$dÐB–õó× bw¨tOªqgÛa'›OAÒ=wwÖî]`N ŸÞj 0¥Äƒ_É{%Ž'å3é°;a¨ZQ”ÄÂåBZ ¿³·ý_ô^b®m´ÓW÷F©­|e…¨™Æ°>)êØÕžÊrLíTgnÊŠ‹ü¯@ÐÜW£%1# ‹ñ·CrrЬ¹Ö£î&àø¦¿Ü;÷­ëV«QZ+M¸ijß¿¶€ËQ£›1 ²d ïª&AžtÓ­Pt·6#š@4¿¿t' +M`L'!QÏnéÌm½ ª^0]§™J.QÝÙb1ÃÌ_ ö©-b†Ø÷3¡D…çÇWóÀÆU±æ—„hóµ]°€, 4u7×qžK9×NÍ}’"t׸ÆÈª¼ŒÊzÎfn,±^T¢–Œ}¾ 1 YÕc¢÷Xc1Åâ†ÛÿiZKeÃáô‹Žƒ©ŸÔÌ€îp¯¦6(£MT,u|wb8%›ð¿™[œ!";-< ?|Z]Ó–ðÒ*Ä{ÁÃ…ÑA>s­i¸ƒ¤µñøÕŒC¦Ù•¿-ãyÌ×Môò_ì\‚ZHÎýŒà %‚Þú[Ñ!üÀ¤]ÃŽ5¬~ áléj¦«º-À„fÄ*’j7̳º¿­©sRØdËdê)Oz,EóëÏâÒÇVToYÑø݉7)sdëu ›’€€ÃºÄ“[Nº”÷(ÅëÊ ¥-ÍåÙŒ9*ü+^™€ãÓœ* µ0N”tÏ¿`ù(EVzqÏW=œRããƒÒÿùí¥pÓU§tÀ_탔3Ò "V)&L‡'>¯zL’™€ ´ª†\äº õÍ0>p)×NâgÄl2RÄö[I¨Ân‰Lt3`¼Á¿]Ëúc/Á§á®1EZ7iM°¿FêT(œ5ZÊvæÇ{ó¤ÛÚ)#cü…›ÄÈd.Ë¢ä¡}çÐqŨª³á–ómÇ­žtúí÷ò¿ì…\'ÉÜKêF"¯•ö|I¤n8Š,êfÉÆ=Ua,¾ð§l|ø– Ç\ÎgÉ«*™oVPb}M²‰•3=ïÆÂŒ.ÎR½è0#¿¼iÅ(/áQºÃ„ j .Šè1ù礴»yTÜivn’ÑǪãk:W)ïòµ^D!8Dß ¡ ¯}bO€N»½,ÍHÞÜgPeAªÅÏY ¾FkÖï;±¡æ¿©Pe-^°²G˜@;9²É`© *‡î8³Léé^ø£Êò>d§DÝÚu € b™ëw_…‡ˆ|>‹gêöG'fs–‚RØeª”Ä Ô~¹€+T [¤|¢i ÜYYL^±‘2cò½ð›†­f€ýék:šjÙdˆôæ°?=€‚Åñ¡àÍþ‚ætž<ÌgH%´½”]3©.k¡mŠ‚œÁq­Ú-€“ÄÖœ †¦PÀ7ChÁ‘‰6žw•¶­’ap˾¦fÒ%~yŠ(ÜF6^?”˜Y»¢­µ;(}Û+¢: A5¹SÃbZÇü£0k]••tšÃø7~Ù>ä5!(¾æôn.–y2Á—èå|£Áï×õ‰1ߥ= û…ÿöÀÒ(°£ÊÇ/JÇaá5Ðn¦Žr!R°b«§ÛF½v"ŸÒù…*ã?ƒã Èøysh¾KÓ pJIÍ>O>#•§—ô·Eë–çkË ² Ñ ¯%Å| Vn™—A¯÷®|È¢_ç¶ÜŽRÌ£}S‘ûøÄ:‘R`WrÌ…ý  {Ã&Ï£É-Äö§Ä  ±ÇQ¡&âò—ÃmÌ}liÝx‘VßOláþaOï_ ™ðÝ™"”Ùïƒû‘¡ën)9ì•ÃÇesì¿‚õ±, ¢u÷éñj²Çò“Ôߌ>?SV®Þ¸¯‚ ÀCRægÜ ,ÑŒ6ñTÿzeÎ@µ×¹"«×-‹Ðh~ -W“páßwýšá{~«•_7CPŠÿÝ™‰ú’ y7xûòÉ‘˜?+ÃÛx;¤¡#NU\=XŒ1‹ÀÜÉɶթ„“3>#¤9CPÕº„eÁùýà‚þÅaɳ³=ëàkv2Fýu`Ízá‘ÜCBXó—2P{’€€·©Ü¨®ìiøëÀ€–§aPÓk¡ÀŒJ♹—‘¦¦b¦–Õ®W“å$ÃÉ“•Ôç¥d T_½9€ÍËåÑ”·´,©‹-Çu™i Ì©ùÞf6¢ÐÜÂÑÙÏ9âW¶ë"£D7›mo…WŒH˜ñY,ŽÊàKq£0p %<¨¨ExMô(â&èÁitƒÃNÝ0qSLY¯a*5¸ÇÏ<³êr6fõ“Õff>íúBð…Én F0ÈÞÝÕÖ×Ã¾Ž°pDù¥žø{ë¨VT6‹âœã{ÜÈÙ:°’Ü<žã† oG“”Ð Û–ªµý!Dø¹IMU8Ä;îžaDö‘9ê…˜Yúã-K~™•bO£KÉ!˦ÎÓ“½ú5–EFñ-²©$WÊ0Á'ÅQ‚Ã<ÿGÙq‰…¹ peƒk2 4 $?²óÄ´ÈP«‹ä6d9È8X‡ƒ¡w~˜(ab]¥8n‹‘º`,DñÐmž”ôi*CIcÖø€þ3Ù5y9ršíqðü{’yúk‘+¿ÇÃÇ#LÐ%WfP_²çHR ³ËÌGg¨GKi÷<âèyÝúFœáت/©¶!&„Ü!WWØy*•s£”±pLŠÙ]¼’–&Ë*€õ:H†Ô,.²ÎßñúcÚãšZãº5>uÛöfêîZâÜÒúÏ3×{gëáÂìƒôªÈJ}®%^ªð ²ch½`¾á6´OI¹J(ø? t H6 blpé@A|+÷êÇÝ£•]YyºÒà<˜Ðö¼~²Aâ°áŽ/»gŽ[¢÷tÿä¹´x¡ù»XL‚Þ¯ÖÍ_(è`Ô­êi†éê}ŒÕå £(CJU&„¢\ë¾òb¼íu…¥„#ë<%¦êÞ%ÑÆd¸[~N+žqŠi¶ìgne‰\ê£"³"ÑžPx…¼®fÙ,Æ]Ö“íl’lA« n DµÅ=¨kB°Ñ&V8j'üqÛâ©e ï1t)·Í6fáPâF:¸±iî¶3LùÜoÁI½u õFéͱ·+ÅDW´6%Ø.æC'¶uïɳÄa¹v*ræ]³ËɧLFÈzÃúqsõ„uâmj×íê!Jšâ9³H'ïw¢´!UQ#N°£¬ÿL’€€Îƒ¤ùÅqƒˆ‡bŸìƒ!è6Ÿ>Úðb {ëk! ‚i¬¥#¨#ü@‹"Tôm0lVÒl¼xò/t‹Ú¥ìeÁŠÈQªW5ê( ÀíÜ™äŽìωâ¾;MøÀÎî2ˆ=ÎëÅýßÇ'ÕM‘ÓÒ:d½d´²üŽðxÙºf;øsï×}mnâýÄÐEôX?À£¦t­G•î íÝ))Š}§^¶‹ƒ8k¤ËHAQ㡼A$ ƒŠB˜yÄ!n"?O£°9n f:qg¹-ÒA¦- ~:’pbW„ËÌ‹.®ÊR!9<øü–¡E ái„\xPÓîÄuð´ø´/M9‘ޤ2Ä«U¹ÇŒÏ•Í=Ú´f@e#3šÝǦ;õn·tÐÍÕ²C›Œ¨#FwôÔ=èL)c©Œó¡È=Ùb0¢”D¢Ï5 Uй`‡ÅÛ(ݱ#^´1üL)hX£ãnÁÁ)NäûÚ íá-i"GYÁJÛ+U'òIO*óäB–ZËÊÜçS5cØÙbЃX“›Ž ¼E¢¡ ò/Æ'>ܲÚ¨0¹5H¼ƒ¹Ðì1v."i#8<(ÙvÞÍzÙåŸ*c ¹ëC²Ýw†yA®¦ÿ²zÖöpD£óÈCv"‚àR4Gú\Ô9°!Ƙ\ŒSañþ8ZgîG€ö»“äi«è'#Ë~óžBìÃgÁ.àŒkÌc€)ú¯ìúú µL·¬·Â|©B§ûâ/?j¹mAàS Be¶ h¤zV;§eöÜÔRÿv ŒÓ6q%-Ý¥Ý,î9C· ‹[N6:ÈšÚr–=T\«5[ž¥¿N_r*hØ}ÚwµÂ}FcJr»ã!1&ã—³4(çÖU5g¼òU£¼ÝÚàÀn/Ld¯”§íƒòµ>_œmDy=!-Óýã‹¶´ËŸ-Q9Éc™Cü%­·à eí)H˜™òÉsêçÃwsië¡ý"Ã@Räâ2dªöTÆg¤HŒEg;nQ7eQÜLº•0Ž_îM(ÑCSÌ@¹´Ew£ïqzÉ8s,F~ÇŠh=NÍæNlRFŒ«PÙæôˆ°xD,ŸÈœóöÙ@DBìÀÁs2NÑ”Ð×Àl£Y®ô¾î®†o(úß1‘fѬðz8J·ŽZ4”ެ’€€Ä…B~>ïM)Q—t|ùR®œý ¿ „¸ùOuI@lw)¬R%‰&\®d=079Àô^3RÏ-ý™3Ó©Zt4¸|“ÞêÁÝ}³?ŠßH}UËó ÷ò$ÂXZµ€"Ãï`Z ö ïãpŠ=(iºÚI‰ìUC†Ldð3øf†ÞJ kïÕPÇ·RìSÅõ€<²¿[n.ø²õâà/Qö÷NÑPƒÛÇ*.%V(†ÍÈÎÐÿ¥7ѧTÞ*ôÛ⣠v«·!ƒ¢z#Z†¤šÐžt³þëE@›¸ƒ„ƒùÊ[{iúöwkÜÚ¹'B5ôAõ½FÝ™¶U«R•¢j×µ?N K™‹.àÉqO9_èó:K/·KÕ쬀šù¸îæò1ýuÓüZñkûÀè¾16¼@a{Ï¢†ÂcqDiá( Ð7gg/‘Nã'bƒ—ת8äaœ—ú‚ë¾êy|€öÖEïD®Ë†Bâ*pc³RÜ×![Lí§­ÿï2„ E¤UÞXI;M°ž,[+ÑA\í‚Ðw÷_»ñ£ G1“ͽ]¨~øÎ˜96í¬ÆñPÆÒBèýÝ¥ƒ.®µÐî!]Y%×äþ ýöÈ„€çùQ”†ýN­šþ’ej˜—Ù+¦Yİì¶Ã@Øð6uËŸ,—bhÁä°”¬PdÅ5^*C#.ê C|Ëo¬ï}š¡Ï˜dº!×uT*£WFOsS÷‘¶£™ÌˆãûïXŒjñ dyJ zCY²^Ð9N4lWz,\=7/'ON]gãJˆRjhÏ„÷!!iŽJ½Î˜ŽÖÿ0½â-Ló77×D- ²ïꆮ Ó¯NõHˆË‘›E®Uÿ}|P61øur”‡E-/>ñøÏ¤~yÑÝ伕˜Ù¼™Ç‡ìVÂKÄÖ‰¿¨”¬´tWŸ÷·p:gšÊ\ 餑ö:à…S¢õÌöREEÆÇ’I‹èN,‰©Þ[Ka rÄy¤tœ’€€Ï󍯤5¦þEù¸u¤ž(?È-ÇÈR-)5¹7<Òc.ÆkÃËo e]_é{†‡#è´ºí)tˆÿKûIQˆ ¼zîS‰EŠXîÔLÛ÷˽ýò{Š Ñí©Ýi¤È¸j»è˜~Ÿ0T·!×Í Šº¹RŒæÍÙÖÀñW™e¨ê>ˆª hè­ Zž½u¥M$ðÝÛ›-¡rÔL¢–^@–¥k +b#wç*Iå²oZŒ©‹¼,å”}kbšáÔÛùú„²%¼>Ö¢Ÿ(9Ãngy—”mÜEð̹d¸õµºî :™œ¾&êÝbŽdYííTœåz°óS ,ÈÓÌ“<ö8Òê&é&‹-yÔ²ÎK¸·C ŸdèŽ0ËmBôÁiàâ‰"d¿^P‚ÒÛÕ»:Äú´°ˆQ,DΣìÌ鮲½¼x%|IòS½S°£ï üÚ½UÆZâe”xXj›ÙƒªÊ3"7‘Ê}À`z3¿•¦ÖO‰ ¼À‚I™æÉׇ—¸à$/ȪêèˆE¿ñÖZ)U ŸôÉs´×_sOFˆE,7ݨŠÍùºM Ó>8I„ð²¡$Á T4ê_ ™OúªVü…6×dàsdOµ–¸E^³õ Ʋ°‰/ß3ê8J=íˆnæN|—¸¶“ù«¶’NdÕZ¬6†… wƒKXž‡^¦ Ä×¦Ë Œk޽#@Ïçk7aæh¬µ‘l6†{á¤ëw4k4fŠ¥.`jÑrH5b¤?¯ÆÓ”óÊâ(›çJ‡yÒéãÜY”` 'T6o åÇÃóãJ ªW0šÐv~åÁ„l=aXÅÊ#ŸG 4ãøëÔøÚªWÇIyˆ>”.Ö‰û~¨‘ü›ÎêšØQÁ)øàȶ%†>;Ë”•_-”>¯ECÔõüY¹ˆŒ8Â-ÀYÛÄ4ÕéH*ç¢>T6j+Iò]tx\^ŸÎ®i,'öÏeyG`y½w¬<Ý̧‘޶¿€ø žyœTé\p.K×èð„–îÖ^œÖ:JMÝf¾¾Pîäî!ªsµc³æa’ ï7üëj¯Ô±Þ0ËS?L¬[ ©iÁ¾0§ w¹^^p8›¾ÿâÑi;u¥åèCºÍÛZ ý¡’€€Ô–©›Ú@ä]d2퇦ËÃëÙ‰oÔJ˜†÷\«t àÇ:±hŒæN³â(žJÿTV÷é±O­Ú•’èSÕÉ=m'ÈÆð¤cq E³ÕPÓíխѳN¢Z¸<ŠA3ÐeΗœO9Ý8^öA§.]ÒƒŒ۔̖@RgÇl¨€n€“iŒg¢BŸ²&@¥–•gY„,üþz¤Î]J6<(D–ß%@><´xÕ’Z µWÝ0nÔ]Vßÿ‘Mw}w:‹–õV«ðÀKs0Q’²›y+%Û|õ›òIló“šý€[œýU =8 8€Çð2MȳRM+V¨?Œ穤tnýhÔ”þ]^Ú„Y¸ß¯«É9¼?ñÅ?JybíÜ™®¨ÿìtù±üÜõâIýQV> VY1ÄBÚ~ÄU^º¢üš(UÑq3ê Ÿöô‘þÕÞßa©}ë:pN1ì«‘o~ðŠÌð¾¶@Ï8°Õ­´¹ÆoAbðÚö0¥Dœ¾Ó6À òƒÁI”Q»„ž…vL‰Ñ}âmˆìÈ,“—ÖO[ô,×bžQ0ë¿ÿ± ÛuÇîlè5ªvÇÌX§Ý6*É–I¹·KëC¼¥ÿHOpb2£?þÔ} |;?34•®h_\¨@ •{ ¬ë;RùòC»p§ÓÝÏáÐzcaH%Ù"Fû:wµé¤/.ø‰D(WDì.¢,z°¯ÆVúñÁ@­¥AÙ1gB¼˜ª‹I†¬UŽ^ Oýd–j›4²¼ñ‰* |Ÿ¦ gý QÅÖ#Ge²4€øJTv‚Ëæ KÊ·F—”/à!G ²ÕƒB;Žw`Î ŸqutÏñB;cøˆá:ƒU|ïâΑ¶KÖÖá7ìæ¸øîE“ððîÀcþ°*ÃpOÀ(9¦Ð"_8¦v •4jãe{WâYQ|éT¸!šôWn7þŒ‰Úæ^)+í¨Lí”ËÅà¹j¯æÙOÇZ1êÿFÂg!ú8Þò_Ôð³¶K>aÛð,.-Y½8íÀÿ{ÌÍP¸÷Fzva4¯¿éå7´ùÏC¶™òøaú|PCçhøk¾9©ú?§ Á³õÖ¤h !ºµ0“˜Qdp\KS£ÀF_p–\‰äÙ57ÏEÛ)yx’€€ÏµU¹³jq§Q™)Ùh81ÿ£ÀwH‚1ùBÆ…Ã¡Ö Iþ¯©øLæ]x¸T„‹³JÒ¼ ñì¬EËäèw_U=¸ý™¿S…–.ûWÍa ËÕ_OY›¾ê `ñÏ 2ž«ñX[ÖP9"ÍEÒ6YÚk(êTõŽÓË‘GU㿵Ës=Ü ×v‘#»‚ƒhÓH¦ß½=ªà®ž‘ÆMãR3´Ù£ÙØ]ª#’­ùz®i“¯œÙÆ1ùá{7³úDdã‚[;él9sÔÒ:rß(xx`bûņ¥Ù柤G Éeƒ5£ÁÛ [Sæ›K’<ÍgBsë„›¼•8hÈè§^¢’k1°”ñ^–„OµDžä§y„„$9@Ûk®ŽÖ«çç`<¬ìH.–í¤ J)Ε9/„£ÆÆ ûÏßåÂ.©„ÛÕ1kCùóEÕú(Aó¤ëãê7Ý–r.ÍM ÙHN;äFÂBÏ´+¾îk¹é¥äkôŒO ˆXÆ~Öólµ}-Gožº¨Ëÿ¦ú,>a96d?¡Q&¾ÞH)Xm\Æiè2Û…D‰=Œ’ ¡’ÉÝh ꪑF}¦x7Õù ˜LGô8”z·”ËË»>>KC¹©FY.&6kÓ~>Y³H‡?$[Ü)­Ã ¸_€˜' a‰ u7 ÁÌ×lß¼¹÷©9&~ÿA=K=U)ôRú× ã7ôÔ¼µ†_-1WaÈqQÁ¿Ð' AË%51A÷[¬"GèvFÉD´Ð%òÇ.Në°õª×‹OP178ÔøÂðg!ƒLÃ÷yèvçV+à)\!V«¥ã€ª¤räHÎ=Ÿï“i/FDò5Üã¿6~— *C6Ó9p‰:™@±B––á¿ôÕæ‚Dgäé—Ô:,ƒëïW¯î·£/ò)aÁ«uþ­Šrgæ#UJǮϋ–â³aÑ÷t“AŸq+ѦǮæºqmÆ{dJª?í`W}cñ±Š²1†ÂèüÊtTz\”•…z6õ²¯X_ÑT~`”ì-þË_˜^ûž5 ê®$H“•žÆßÁÙÑëCTö¹±%TV°¤/­¤M¹,ü º"e±u.ËO$ øÉï¸ê¦dE»†taáÞA,[ÎaÔ¸HA*\¿‹aNYÖc½su\C”RCÿÈDÔî¬fl­ïŸ¡¶ÃƒZ´¸Sÿý’€€Â†^ñhÉqþn¨ÑÜLæŠ]Ÿ/Œ–·£jý¥ž “µÍm:`Ñ×GŽÉOUŒ`¬GQušÀ.w!8eÁcÌÍéʹ€Œ©&)/éÓ»˜÷¸p"Ï7…¦Õ[aFœJ‘UL°…9ÛÝöø/Î?­Jµ>Ã> ïâ%‚‹îíÙzõ‡} Üóߨ*0}_gØ‹zN|­Ö$Îݹ œËOïíýyf|Tu#d!‹áŠ‘ V JF6ˆ|#Ú²0•³âJÞ“çO~Ï~aœìñžÌ[-búUP»?Ó ¸q–3~tèú¸ËqRÔÿ‚DLùø$"ÒZ1ï« Ý4íUYUt¤q£âgZ¢°›v…ñf¶ëXýÀGˆæé ¦ù tGk”8’ÕX’·–Mk5+<È¡ i`Ã;$1_Š’îÆÎrx}ƒ  §¶†O›šƒ1±®˜.‚Õh¥‰+,5l0æQá2š®E‚\V’Ô‹i ˆÇjw\¡¤Ü¿‚’ºŸ9m¹Çá'Šò†5=ŸÀْ̯ëÖ&$/Ã@,D9x×>7ú*þ­q ˆ¢z±ÂÅ}.ÁbÜ¥Ú*¸s܆d]r7®EàÈ•³-Ü™ˆzW:•+Y°= æZ4Ñ=$_v´[v ‡tçú¨‚$a>ˆ%„vi刽Ån8@·–J_hô‹ „bìïHÖʘìû•qn-ìýÌѲíZøiÀÕ­°JÕÏcõ’Æ‘(œ~x?ÛMƒpd܉Úàù«ÜÞn‰¾šD]w‹t ¿u¡Ï¦a(]z–ýùãÆª”ëÒXÍF™hñ&æJká⛳®=祮^‰ØôØ((ÀêŒÁ#3íw0Óá—|™P¤À =EœÅ‘_Î)V‰ÀSØüVR8GÂ#ÈÈkíì°ãkR…5þ§"AŒÒ®€×±ÇõúÆ‚]ÂÄω3Ð$ò™R|VÜßoÕ † m“Aÿ’`ý†ÑãÊípïÁÐPS¢SŒºvÉm²«A,ÅR¾M’à×ç,¼ŠŸ´Üà³€$vOH§‡®"˜F°\Ú$DwÙüªÐM¿—ÿ~ˬݭü÷iÿ†‹mäÈ¡ZêVvü–^z÷® ó†(ó7lîLï Í¢½f‡ žÚ´†ê†bk˰ÃKÜdÊ¡¤à?z;ð’€€áal#bA9+’Æ0•{‘+8ÀKE‹º{Œ1HfÁèRxs]2̹è4Ké›ï¨¢è‚¥|‡HÝX·_‚Ž»ê]Z0[/O9#RÜÂä‡)`ÏXuç™zâxµãM¼ñËÃQ”õÀ©(?©A?°ª›Þ‡ Ì(\"\9×ëñà­¾èXˆ4 ÕNă‹|WLJ>qûŠÙïµ¾ɬ<5DÕ:s ÙAFâL¶Žt*ôCWJš (ÐÈ™QLlÔ§€ÎL.“ÎòÑ Ç‘÷$R°ÀÐëOv¢¥©µnf¤[Ãüö­3¤.Ñ€ðaý)%ÐiqƒµÄÝ`Óö]Cã¦^Q™•Y¸íª½€ÐáöU3ú‰Àg˜8–·Q`fÈ~iºÔR¨£P ½ {âE+þÝÂu~¦_&” é@Ëð,¾RJ™ÄÖªOçtéum ±3|˜¡çBÆó×ë‚ô¥ÆÐ‚S/BkwÁl¦i#Êt‰¸^pˆ]ÛºuÜU;5ÎÐàöoâû®‡Õ Ó³ùÞÂÕgêF Fkþò-¤Ò^ðå…Gå_†çZl&‚Jßo˜ZÜ?þÁŸS·åYýŒßqè|øñô#FãçßcçÄ4 ‰÷N$zÈFvb°³OT˜v©ß‡¾(þ‰]»õK¸x'ÏlâvÝ/:Ô4áÁ´¼¸M\ˆ*Bí^ê'gÊcع† » ˜¤šˆ÷7è3 Ÿ25÷¯HcTˆ\t×~}D8T0JÁÈ„ØíÄæêU—&Ãúà!’€€ËwÜèÓCÇ·Ö8-ÁmÖWÁ"GùOë¼ö@ê°PŸ*m]KL%óCÈ f£Ñ¡Ãa;®–"a¾ÉÂL¤ò`L¦Püo ª[ïwiµkw-ÖPÂ{ns=žH'Yš´,wéAß7¡ $S ë‚â¤õß!vWˆ›–ÞÑ,|¨F¢®v6lÄé_êøUÚXÑe*ÞŒ/sàÖ`!Êo|<„a½Êœg'Ø8&`û>D),w”Ï"_½LÖêIޝÚY×Åps­°êé{‚†M+*gmŒÐËEvT¦Ã_ðýÂkoS”°  «ÏFíL{#ÀÜÍÔM-ÚŒ -|ßïѱA[=Jtx;åa#É™ñvÿW8òàš¥ô˜LöÀ›Âe2u&˜Fˆ1ͽÙÈœ{pùûà |Õz3cìY†9;™Ð Ò Öh6v@¢Ц3T¤Tu’ î†c©²Ÿ1—õãì÷Ì8ŽBÏ–eKà&µ“nÎáã«=+k•hiù]/®g㋟Y>C³Îü*üù‰›Ø®1ήûmâ&ÈBÙÞ‡’ô™™N¥œua¡Ž’üñÛBʾ<49Ï}¥êkûîÉ›vì‘ub9t–~ _¢åq:p8\Ýqë j"üÆÝ½~ Ënºm+úQ”à;îÄ{}á'Ý3$àABFH®Í-”Ë2Íň… “ÁÇã!k¤˜#7ÓèWŒ©Wá d«ˆ­Èí:»/›§m‘ŒÒÛ¤9¶›ømÝñle%8Ey>®A—‚ÃÏËC[ñãpÒŒY9x.NSÍXgw×Þ]¨bypWZâþÊßÁ»B s‚¸4MŽ“'§Uó®î‡ËÚÛÞ:ŸBÅ蓆¶`Éb[“ɸZa»cþ­¯:ã'O#{¡0„¯ n¿€i2“济 ïòµ´ÀËI4kêNýæ UKA¨ÑÚ€®ÄÝcbãùÈ ÇÃkW‰]”¾àÕæLˆµ®Kv<ØV¨Î‘Š.@ûï°È”G¶œJÍqן™³çìœ1Õ8OTQ8a,Œƒí¯Ô+%ëßê/fŒÐÕ4ÀÉM ms)úÆ’€€¼5¸=  ês=úí9ioÙ&0Iþ.®¦Uþ 8i4MšW[ÿ€‡ï¡Ë…7‰zÈr†S’$VKX$‘^. GïЄ‘v £o‚2€Ðæ[§õ"Zj*oU=Ò‡Ò¤òÔt©B§jrÀtQ†"èhÛ| 'yî8’5˜$ž±n°'Ä3ÞµW“ÕÓá´P%ÞûØ„ˆÂö¦ëiaÉ!QWDZ»É‹ƒï° Yn!ؼÓ2gEbw+ùªZo1ݶR•U óöi•R»j5§Ë‘-̧ô^¥; bP”ÞŠ§o'* i©‹Ty¸$,þb±îXäGEÕÒùwó ©¦ôÚO° H"j¬-@hQ™·X†“ø) Ò«x`,8±²îÖf&â§àvdÙÖ7„>àLJÜUˆÌŸŒâr7sÚ"úø`1cûÃTÅÏm`ðzæ4X2êÎ"XÔÊ»ª`´Éc—&ˆ±ºã+n¢Ê1k´£'Šúzi¾¦Pz6I\D“•mU®“Hrôëg iÍ‹Â<ÊْN‡OyíÙç“Û¬|ĈŸ¢íµHHãnc üT ÓÜ$ª¦ÅÊ?awoÔÛ_K>À•_äÞ9ÐÝè÷šäaÚäR,ÐæŒÝÜÜÿÆ!¾lxü0b`[h ¥¹'\Ú…î¨5)o†Æúz¯ÉÑX“IMHÆÞ/ÍŸ-Ã7@-;×ÿýªèoÊÐn‘‚‚yè.ã®xy^óMÛzçÔÌ’ø,þFz™3í,æ±/¥×`âÉÀ¤ý(î==“„‰2m)ªÞ¢Èšvýž]éפ\œ"[á •’€€ŸÃÞ WEìü÷]v Š.寧L8KêžÈ««>f`ŽÔ·–†Y£é›az«€ŠFc§Ç¼¹()mÑÌVd°Á<‰£nT”X°³=þ^'J”e©~ Nƒöšè%E¯E ´4­qh ?•Ìôrå×zÑÓˆîöi,&Pwk4¨Èfé ”ª·±IÂ%ã¹ 2šnÜ´sp)T=Gs_8¬¤[b+ú´hÉžeh°8c™¼³ÖD|˜–¯è€,Æ¢uw-Q´øÔ‡Sµ‰tÎØG)m"e¯ °:k±`k¿¥5•ÁâÅ;yŸ“Š"fòÂÔE|¶¥]w°br×®N¬Ô¬×Eú˜΂­pï£áSxŽjþO|.ðHÅTo"þäXjï¾üH4%ut¨®î¨Œ%»sõ«´tcfÆ9ãíÛ1NÛVJ9ÏzÖè¿ð(ÆÀÄðõÞÒÕ?ÛYR Œ‹Œ¨ê@–LڒÀØ[uí$œLUÛC>l9#Þóîµn[¡ÚÈ-œ°ó @×>5¸½>th›½º«¿ œ×\wçÊŠ‡Ù>Û—%èT¡.)ˆZz0ñé1ïg©åß²–Iö¹âù) ÌZ–w•pÏ«£T¶ÚÛG뼇ׄ„Å^_/¹Ê(SLJÓÿçËŽÖìEÎþþÛðÆ^¦ì•Uýè®á€1¨=ö`ÏÍë= Yš’näòßY9_‚ ‘É"‘¡„ž[û9²…_2·$”_Ͻr­_ayà¼×M¥ËÛ»r˜t¼Ãánh˜ $oà«I:»ËȈªiç¶"„MŽ~ u…¾eÿ1i:PÛ~ìˆ>Yb‘……pKäjâõ—®M\;~­pœÖ*Ôÿ ð]ã>Y× €ëmF}9廃eù$C°â$zÿFÄné.:'ê="<-UÒG*‘£Ùì@Û×"Ô‹°šA?•ëõV)VÞ¬¬Ïµ†Pmae]mÎs%NÁ_P=·’€€¹­¦Á¢@UMàÉbôx<Ù¨@µ€sÅM¼Uƒ—ö.Çk¦úNŽl…l…|¶Û©( Þ”ÕàºQ·›Íc–‡b «ËELxJŽü–Ó¨eúÊr‡®ÍNâ1éŠ/´ëáš/¢NVµÖC¬%†êô!B—s&â˃ڛ¤¨ˆR-KþžY;ÜôÔ£’_ñŸp.ˆJ,XŸ8!ø…š£ÆÇ%M@©j—•!Ùaþ„' .^h¬Ðû÷©=ïµè>ÿ§‚R|0;"BÅs±ùâ‡ìt`6i&!UÇj»  Áœ|Çïð5-LžgÿÚ ý~G4šÒ|)í¿ šûökw‹( š`L¥Ø‰±öý1ýü N 8"2W¯Â4¢2Õ {q•Bô¯ï<ñi×lñGv¾·>Gz ŠÄM8Û8ñ³þäýá´idÆÓ6›…æUc¿©D [púø³ëÈúÄúY!Îo~¬r£AY¸ÙiŸíâï I÷ÄP¤´ñ?²ÑäÀš@ÏR—|FÈÆ< /o.V"Eò¶òÇÃk@‰nË‘K†"íß-Ÿ½#Œ’ï5¶l׫/‘ªê¾H]ö˜òËå”'kdt vàÉy쪖ê?Nôaùt Eã¤M™Ã‡~ã{,.ÑyrC(DIò˜› öGZÉ@b„UæH†lCi3<“{T2S9]Œél¯ÙÏÄ}L<*ÑÝ?¬¯’à^ pZuꬪ¨ÁÞA.ÃçaTä¨à“ž&&ù”M<Š´ŠÌP~ÿ‰»¯1p¶½”¼u~”En^,ù‘™à—eƒ!É áâ£hcÃïù:¤ÌA\³vÖŸ§;¥OîܳÞB’BÓé< ÖykZ¥rIÞ¡KÐsÿ‰fMé°´|En‰þÚ !—Sl9¬Ösú‰>1Ddªâ¨I¼É·¬ìO/­k‡†ðî‘‹ µË»¶¡¿¶hªž‘¼—ëLž˜ú¡Û(+W±X¹5ù®ZºÏÒŽ:*Ä”Cä·‡¦Gf~V @;|€;¿ ÉRЂ›å0ŽŽŸ+êÏÁ^³3aùM€Ö|ˆÂç[ÿ¿“v!SC6eétÐ[¾êË€?f6&»NðÚ°Þ3ßQoºèŒvw½§ÉÏ}¹XêÙéU¨„áà[®"ÚÏ’€€ºgÿ=è³@¸ór`t*bvXl™™Ýíç…f}PHPm¤ºè T÷4oMAtE΂%˜Epùâò…¢Ë(E‚V“£à&Nú¦3pß@ëÕFÄí+ve]f¦¿`¹?ý CEû,TVÇoÑii ˜ì†U¯–N;Ó‚Ü_Æ{ëG4üs„5ñ!N`–‘íRh­ŠWÐÆµ9L#/À‹<—ñ@3·øC7ÙnWG¶4C]Û‹wyFWAW*mÅ‚>PRͪ{Dì}º£êp_RÊgÔÛá;à’¼Ò)B²ÅlЉÑb}|ë"qùŒ5.ΪHÝ"ÌYïL “Ò³d{«ÎÓDsËTæÉo´Ê¡ú„+…ßIzb^ú½kÿƒÅŠËŽoDô2˜qÝY/yÍûøP¨.9¶ð[šœ¬ô»ç/šð}óȹ<]â5ïâ…£0^ëñÑÇUor•lÍÈòz$àÿïH§Aj£úíS²wYãsJž;ÔÄR¡_Ø"¥œúãÍZÝLñ‚'I&C1Åä2ì ÜnhøqRéY»eÊú”¬¦QìngË–ÐK5ÏiôG]ÉÙ ÀùÝdýµ¿çhÌŸ(êÚvF”–íÜ€õv0ǨMYt!Dcfáâî¦D »6ÔÀÝW_·>9ŠVóþÎ$] buCåtÌCäÃf©NV‹[A¢€•<ôÎ*Êb±M·+>B9.-ŸÎ M·´ûs•S´q€§vP}:r×ùç‹áVßžÀüš2åÇƤë<ñËÚ8HÚRÒç{<ëÍcOŒ26ê7¢ÌTórO©EDö'ûÉfíI,ûìÒÅædƺ1¬ dkƒÂLgír3Lð<ÔÓ*%KIéкîQîåÇ1 ¿;;Äg*«9`¤Ë÷(–ÅDј_÷¬Ça‘ß)r@Ž"ßYÀ>½Ï>­±&>J.òXÂMyÒwÆ#0#UƒQño”U¯.’€€ÔãâvääiP…Çe…H p‹Ð©ÑõUCj±$þKÓ[Ó”ÎDÝž'âÝÿ½;uÌ/çZoÄvl>3J#@9¼ÜÙ&©=/N¡™ ™ßЭHG¿…ù‹íÑr˜BnôŽx÷Ý«KrŠØâåM‘¨¡g/kK" gEs‘¯½Ž’ “rf‡³f <{SûÚ¼5(óü‹Í“*pt úžÊ»qÊï5"c/ J¿1ÛXYW7¨üÕd>#yÜ_üãaýz¯"ßÖ É “ ÎS PƒPc|Th&¿ޏ„ªTàèò®¥Í¤«€ î3^‘.mb :¨³1³µ^NÒÓ§׃8y½cQstXÜ£OÈü t7bc&_7¨¯t|”Äg P ÎüŸ;ÎÂv»v•,2a£¼†‡B€dªÿW¾¯0­p­W˜wüë±S‰G}͘ãçÕAš|„Ì;Ì3ÀeIpúÚ#ƒº)ùŒ7$ÿû"˜aÒax-ÂY¦ ˆy’-ÍA²š÷(¨ñ¨œgÓ‹Ì¥ùß”,1~®íâyünƒkãHýVR›GÃ14¥ŒÆB¿Lyò×n'ô+c> £ÀF Üï¶*½‰ h¿Dãôtª‰ZLá"NpžG—€ÞVm¶¯1¸ywÁ«HJ}Þß¾¡‡þrÓˆaì9õ¿><’é»ÍGÞ]9}ôàÈ—g:È‘§JÖÓ·ÓÖܸÎz½"›WÒj®Í¼ËαprßWc–D™±P‚XÒRsqg/ˆ~`!XíÄna&´––bÝ“‹ PyÁ|}d²fšïÞÇÄ-À‘¼#Þ"¦ñ믢œ-æµÛ¨ûôÊ—ÞÍ/.ÔQw-M¨P¸Ê"µIW^%Ï×ðçž©c¨ÚZp ÕtÕ6<ôãxËÈçz”Å„îkdÄÊò/E_\Ì,¡F19Oêßí®H«nËðŠÅÄeu.I«7}õÿ¤Yžæø ùÂ3k…¯Ùz_.O6úƒ´4½©__sXoŸ‰U;ƒ¸Ž8†Çeâ»L¸ÿÝ.@ƒZ­(ÿ¨¹n9ʽ¥´Z쎈iÝ3+#2ô"/ÌÕ.¡‰žv-íN»f6σ^ã>ÕìMóZŠ Úä÷N[æ^¥‰xsµVú~zŒŒ~8˜¶1,ÖÞÛü+߆«¹’€€¹X¼æ@œCµ÷¿„évû‚Ï5êCÁHwc ¡ë±‘!‹ ã¹Þ³¼õx+¢B`©-!ª mr2p–©qWÆú¾¥Äž\-J15æoZ" ^wÝè¼)h”Âi§M‹åRÙ­Vëµvs`ùè Ù/jìLM¼•uº>5¥è~÷á²Í #˜ç>YÑmÐvTh’ÇkYíŽê$"Œ<]f¼¼@»D¡sgÚË7έ“B~<°†,D÷iÛôÌ& ñRm1½ë7¼üT»»hunC×€jS&åÖÝsÖ#ÄžÓÌrtsÇMŽî0 Õ'똑1k5:›#…18>LŒå™7ñ¦ëפiÏzb£Ý%È8D$® 9ûèøL*Ãk‡jë9X>¯¡‡ ã";‰ß. K’»6Y -ev›â¥tW‡­œCfÐ˲̃ˆ`&ðCê¿ ´ª y¸`Ÿ šð#'÷k:´‹Q0âDmr‘lUlN”já¦.ï]FFibö¯¬ï¤›«–Öi³ áÜ5bTû½ îxÜžÂPû_LÄòêï¨ÙǰÙa¯2Žƒ¬úìm0Óé=D!µ;M^ùíBŸ…TK|Gž9—ÐËøDøåw0MÒª©I˜ ‹¨¥Ö[jØt6/Ãß°ÎkðöHЩø!ÞÚš qÒø½Ò‹Û{ðsâ‚,™},ù±´,$O¯ze,·´Ppì æ@fQÏGo—;é ÏÁì»ùìៅ…#i|(ÞN’טÌJ¯"뤶¦«‚µ¥ó„0þÕî4õj«Äñ2ÿ±&Þ™mQróÃ+¿£ú§n– ?@ød¡/öKKÂ*‡ÆT&ñâŸÒÓÙn=rÏì¨1¸ªÙwáVî¯éùMã¹Îù½ßœÞh„¢p/•"­ë§â¢#ÈÎ5°SÛÚJzãúƒT9š\‹[TÆ.O•mµžÎ8 M¢T.§×ƒ½1÷ûÔ.¹Kš¬WG`çþsÉ$éI<ÇõÜÍw¤œ®òö”æÂä/ºväºÈ”ñ[a%_MiÔa*©ÚgÊæ*j\¸f؈AóN°ï^Hìø} º\?…Bð‡\U^¼[ï™W«¡W°òŒù8Ýzfä«ÏʯéhI"¾ð&Hªˆsñbžb;Pa~o]ç¿ÅþKÄŸ²F ¨_o+®—à)q÷Lp2ÀáØ?BeÜZ'Eñ]B)Æż×$§Ýò=ÉX¯a]Tìõvåy[” á³½ÅF­°;<~±2(“LOk£¤c®Ì>"1ü¼hޝ5jDÑ%ij¡õÛºZmŽÖÚgl1®+©ÐʼnšHfXµE{‰çèùËv-›voµJeö=¼.ˆ¨=ªNÉ•¤§w¨öa}‰z\µ^N|¿¨ò2(NþiÚä5[ãÉùr\C2FÇ)]#½‡ŽŽ°ËÐ¥%M^8™;cFbQëåZÿ†5S¥[ýNÚsŠÓp"ÏËÌ-Ñ5ü±’¦òfÔi}&€^׿’‚]›EÈæiá?v±çNX)OYÊ=W‹£’€€Ðw™¶>rëzÅÕ)_,ë½èÍmÍq°ó3<ÖôõŠW®ÙÙÛF9PvÅ‚nÙF=Æû \ ïOxÖYÍädŸ4Ò÷Þ¤ ý3¹·@ÏzVænøÈÌ„Å>‡DÑäàùÁÂÑ»gýZð=Þá càzc™±âvGáI”Šô²l3ôH h2 ‡z¢­tñBs·òš#àz‡)Êæ5…ê$Gü)¾ˆ”Sê=ElèèWöשþbãmÛP=®|Ìü`¨ã„‰M I†]ƒöEkð¤ôÞëÄioÝøùlf–o×§Gß²¬KÏ͈ƒuÏìó¶“‘Œµc°³…›Qšp¿¥>“QÚ,:ÛSœ¢Aþj´K¸ ëÄ%ä[ñ'ñµ¸ªÃ¡…mßo—Ÿ©¯$ÐP)Q”ÂV=}–Ö`íC_ u9…^µ•Ršy:º–uTeó;4¯-ÞŽH™dݱýÌ×=x Ê`¯8Ö-‚Lhzû8Û%˜mÙ»õ™ýrö€?›k½7!Aòò] KÕLA wµc²—çÂBËG€…t¨8› U丑”ý¨ý°Š-OxmH" x°õëË%ËOÇ×äRr5Msþ)O IYr‰—A%q×F(¸6MÐü yƒ¬±¨ÜI{Xˆg¼èÐîY¶ìä:˜‹z=Ú62QÖ½OÁ‰ÏÞ—hÚ’XÓϰ{ÈB ÀpÔϯôJvtv¯4‡0ÚŠŸ+!©Ø45! £åG[Ý^ûÛ˜¿zž ,‹J߃NÈ8ZˆKÛÛÎþ@ñé\aªç/ÌĉIè… v”[¯˜Õddk:'P0e÷‰Šë݉Åà¹+Q4»©¥Ôx¶‚Ý&zÿóœ^õÇýÕª<¸Cˆ¤ÑIJdµ‹¨ªR šØÜ‘NØçjê…p>æ`.ÿ[üæ#õ̆›ÄáFN¹A˜. ±Ȧüà* ò$ÄÍ:¶‚5i6râi­ˆöòæuäà›‡V8 uE.…'zF43S¿´Nk™­\¾ûýOÇ©c…Ušð\Àœ5ÓiS2€Á²'KÅáÞÑøg§Ù†³ñõ¶‡|, ê¡ö9†¾¹,†eµÆ—Øb’€€â¦Ê®pÁiÆ\s!Ej ߥ÷h(Æ‹¡†g€ÇsO󲸔ZN§%!võUdøÛÝSz„hGpZ<ÅJÞ­~b'1ñYN®@ÍCɽ–mt}c±¢ß“öj·MC­C WÒtÊ@\dÞÂ$Sj¬r-_‡š®eù£¶Qö‰nÖÛ!²Óín"¡/qÌç©ñ˜/Y»€2®›ùpv=„|ÿZa9XC+¤õ´Ò)øí-®¿Ðòåh®YþÉVå‘ÈÔÿägc.žÉO‘\EACãUYž+=¶Bl1õï F+µÐ“ž1ÀÆ-q3ÜÞC¯X#¾û¯ªQ!ƒ>¿ßôÌÓèÌæ‹ÃS•!2¥ÙàÚXJorG²A SÉÑL‘šìc²S˜7K«ün>¾2b˜B" ™Ù)q<(Ül°]c_2žË9]hu)NÁ0ó`ЄÅÖõh¸VÙv`Ô£hO£å$<ÈÄò ÆØ‹ÉŠ2Y2à©„œY‰™t×å]¯’ß#Ä+Êœ”’˜¥®<ŠZ¹®^.£ÆŠ[›:å°‡] ÏŒ  =ÕgÔ¿aNgq‚†\)lúÙ€Ÿ¥¾fÝ`ŒäuìÀÈ^_:»ºjLçB+‰‚Fì4„6ò*þòñÝçË×TÇËÛAý+µ¾Ñ8y0ºJÌV/ÏÇ}£tN’€€¿ŒÅÀåºjŸEÀ0-À}P 5ëÃ.÷1|„áç´›†P³VHøß&ÒRÕéïx„>…×Ê÷{Y‰áÜ õê „w6`æ¾u:þN!¹!ZTÕ0õ[þ~ÉpWV²œ/Ûÿ/€_œ´›J¡„ ÊMôI0¬½’â§…"Óc²Ë§Ÿä½[ý/6éo;P(·K'Àè[)§SiÐÍCä³m%^xÜA!ÿV ÃÇÕóPnÎé­M…eÏa‰KêÙèGã‹Þ!–I ÃÄ’åÆÚžm Ê[½Qô'd§Û~ÄUv@ù=…qÕáøÁGvƒÙÔi2„ùÉ©%\(¹)Ù¾ù#“¹šNiœf¾ù åÄ?Æöãúë4ËDLOí ‰æÛn§ÃbFØC¡9IX¤™U»ô“=}{ã ^ÒiѰ®“ð nxGä8Ÿ/qI€Có0úPJ[Âè—8™h°}S¾”ñ upŒg/dN៹.ZËJMd÷]“I#S7$ÈUÊKø†|Ýäñäõ‰þþ¾nêÚË0-wœì‰w&GùíårÅÞÉ?/ê†Q•àŸO¼‚¡™G´¡­1††0 BÙѲÑéY úL?^žToÄ…ë’ø…_Fq?B’¶;ŒÞYUèã=t¬àé?g¯šÙïQ¡hdvI­äåè½T—$.ÞœÊTö‚GÌÀ¼£Tb_DÛü›$i—.ÄxǺÑ[¨Q?8:†µßB^é€PÜÉJDi輌¢ß,,Ü%"ÝåIß¶ÁäFªœû(Æ4ƒ§ÀÕŸnsDw6$3* ËwÂQŠË"B­“Œ9+'ÌæÂvF`+R6*›0?ÓQ:ºùß?ãfLLbwÝìÝæÌeó)#S8_´ƒÛfBDhj°''qg4Ií'žoIA;*ö€­½7 ŠÝ€«J¬üZê÷ÏÐÀçJÉŸ'É=î“Ñ]+5Ñ<‰ä†wy¤±2âë/Dß‚FèήƱ}mŸÄIÂåöôÙ„œwhCÓF·ì ƒÅ.Åâáu•µZ—±JH2*GÊ3o Mž/œ‘ë¦Ê2µéX’Yå ã: ýmNÍl¼Ó…1§Ôeúêð’E%7àã ŒO ’æ¼¥€àsÁ‘l‹–h*’€€£×ºA$‘í—5Œ‡€+ögBW&,Ìõs“é /KBŸ`û(>>¥MGTÊôÊ&Éÿ™D™jœ·‡eÍÒØŒ?0¶SÅV2Yî)ŠìÓÝ´ßÒò ežD›Ã©·ÝIp0\¥Ž¿³á¸>ðÓ eÃZÒ3?g5ä-¯ß?ª¿Åê9»éØòaH9q¶æŸAýÍÔÉpÃc”Ñ÷oî´À­ðt1·n€{©®DÌ:è`žîžù4QØÅSÊÚâ}ky#R~ö îz»RÔµïK¼å#ƒQÁ0…K‘Y·T°…ÚDp'Ì9‚Ô¾ËʪÐyß C›V²¿?néúW_XGdào…÷´õM| €" wàE$„áŠr¦•¦»_’žÿC¢)‘Â8Pè‹ú€¤ø„ÁÁû.r}ké6Ú¤Î,B@O½ÑAUªæ¼e«Eþ M^ní&ªœ‘ñ¸Ñº¼:GÃWtË0R"ù|ÒᥫáŒ@rx«ñ€6ú´²ûªÙ,ßÔÜ­ŒÃ-Ý 9ò&oD¾ó¹>•´Œ“ñà×/ ( Ç‰x;;]ª`‡Bf µ°Æ *>t˜ ÷~«‚wÞ†û|Àqø›ܬWÀTdëÙn~©¶Uî?å)/ÈûÖúl$ySÑ0N×Ð0 ÄSwØk[G=©Ñ¾“[n;“VÎ#1uäí]¨¤F dÞ_+¿”íÕI @¦­øW8þ@þ¹ÊúO`fÛÐÿˆP€aÿüŒ/yŠ‹ˆ/Ãr«ó–Ö?€e½ÊÛ†^ùg¡ß ŒÙ¼óka‡ [=3û憓GpÚQ-z£ù ·º/~Ç‘B¼<‡Çù³ÖIdCŶÁ;åQô‘†aéÀª^ËØD:ó‘‘ ‘`ì…Žb&²¸[–À×NÔiÿ¸Xœ‹æêw ç°áRa¿j¤sNk’èáVäLm—¬“‚r.@^ý÷yöªmÅ×OÃK‘ X1¤Ñ»à‹ã²"ôšª!ŽI^ “•ܽ>hÓDæoŸ6­##9©;”¯3ó åYVâÔÇooŸæ¢¼X[¨6ÍTToõ¹F¸íÜãÆ (Ȧ邴à%¿""cjã+ú¦¹l¡­m9 4`è«­läæçC·ôIç¬Ò·õפ{²…)1~1«“¥äBï’\KÎ:’€€éå”gg=¯².Y¦ö`~•« ‚\”>×äu6ËÂ9öê@ª—H®…—}Ä–/‰Q``UðRÀnôn+‰'¨æÓ¤jz&Q×yiæ)šöŠÂû‘Úš>ãOv&µµJ¹••,©@ç-ø±uâœ~×=”¹¶¯¾“õîˆ3¸cÄîÐXãL× gÔŸ{Í\pWŠí¶¸žØýÃYàu©hÄ:pBa%MØÆ¨pIx0sv_9hZC ÔHzžXñ “!£b­Q˜ëÑÖ‡¦Ý4èô±œn·ì™;b0å1 ¹‡ÕB¢t¹t€IòBDÔDá"|DÇ~‚?¬1+ö³^Á—3UArQã$‡ àÝK¹Â{¿êDÚÂܬµ;“¥]M#Vy• Dü®• ác6$8nÉéF)8MÙ)¼Û!? d8ÆÃj& þ¯‡ZjìiŽdr“ ÚI¢(Ÿ‚yVz¹ª° æcðß®•’ÀÜ!°$ HVh{?Õ–¬Û{æ2×±a(Éæs'›(oaõåß½ <¹zÞ_ã—ñ³ýÇYä[¤F™S2À0\ÄËÅFÞ^„œèêœä£#…@›üžÁ}Îjëóîe‚âù甿yÅdvMBµÊp.ñvÆ™»Üùo)fV¿¬YQÚ!F³%»â «µþó”$àÅŽ×ùºÈLÌ™¬H¥+!Î'9h,lÒ$lé_¸qæ'¾ÔÚ6.# Ù˜.®B9û@oí/Åù UÄää² Ý®¼D•2ò¸ÐY\³ÈÖ&¿«`3à€¸APÈ-k‡[™Æ ”d›qÉE„íHe°]Ôe·á+¼¸Ÿ?¢[‡êÛÕ}ÏäÈ1–«¸Qðª†Zoâ£Þ7ÊH[C4}{ÆD÷4Ñ="¼¢ðý±KY“‰ q;楚¦Ášû&³_+§S`;e'—«2‹0rÛw&SŒU¤Ô¸”w%žÝìÞ l6nŽ­Z‰“naF Êø§3Ç —<_Hª¡õ UÎÍúÛx1ÔcøÃ;óúÁ{by’UÑTÜFdÐÒOLû5“¤üj9ùÐUúnÈMj õBüöªEÃ.ÚG‹¼i“ ftùzÔ«'Ò5uã(Ý$nwn,J{›±Nû…Ë…_JÇ^«¸ LÝ«C¦lö}¶C“pfw¨|Nܽq¦s!’€€ÆŸœ´Ê`F9zx%×FGðŠOÒKKÂð´*€êÓÈǦ©Ê©ÏÄgÀ뀻ÔãðšÄÊ›³ÊZT{A2EÊS—å•ý™ ãþWMeHD´Dè‹f4 ŒIaþÍÙ¯¾a°})Ç"‹j›M‰tà ʼnl†¾ÚØ’{ yC P4`~[u×B¶LPiä‰fóp«J.7ü]©¾ÊXcŸOKË;½®‹9Ë蛥Ú}¸QÅtßæÃ|68ÑîÄ :"»ƒi{(¢Ý•B«•¯l€I©B¢‹1x¹Ïµ:çw mÜnÃQwkÔtæ®å.-nZ«Ñê3L1™Ú@¾Ù *ÚKPƒ‘lØ„Ñf×?r#é$÷P‘æ4F@æ*X¤žKKB¾Ï™%Lÿ[;él¤¥Hó-Ö_°©‹ÒÊÛ:üjŒq¬ƒJIûMËTKé¸JáïM S]OÊîôZVú=ˆýx_(„­’&äïÍ /÷(üÓõ0†ZFA“Àê½ iQML€êõ¼Ç7%²$ü_.=ûó,·1r 9²ˆÊ4VªNø}Ž):–—‚ðÎß1£ž6(;cé)*…8º‚IØi¾êÍnî½íæõŰTaÔ{ãNe±‘÷vVˆÝC\5üs#ª-ÇF¨BüáΨvÔ `öðŸM5ô†ßÊ+(å0&í?k¹ÓjÔ:‘¯R*>1[>8æÛW¸mâÀ%Œ—Mž‹µ¤î¬+ì.\³”•@>ø—ˆ¾ò?l*)‘³Â[t´¹NÓ´µAϰ»yúZÝSÝ$­eFHR‚þ+q7¹~Ü„´DÉš¶ä¯½òÇŠ6 sà€‡¥)V s\Á„Q,¶]ŒF¶}sß¹Ò.ëµWÚ/»qÝB‚È·¦ªžÛ¢¬ÌDiï´¤¬=Øjc‰Ñ Wñ.F6 j~0ÝŒV☓Π’€€íéÊ'p®¯†Ý¹ns–XU,Ï"‰žA£(=†1UDá•ÝWÃÑkAëóÇØõÒ;Îú©$ü§#ZÚ•UÍ·1Oj4IAi7B¢o™nÁ˱$òý/¿<ó¤¼u9Þ±¢Vž<µ/‡F¡ŸB˜`eVÓjO ¼Ô nâ¦Fwš¯qÈ‚hhüUhÄ C Êl^ù©˜â©&Ÿœr:R£gчáONëÝ\¥øÄ¡î8k÷ßnM[¹•×Ím¤T¿¾“MDýÕýËñÝ"šÊ„Àê¸úw-Â1ØãªÙs—ß8A˜ìâ#-õb@‘Á¹® ½œÁÞP*¼É¾ÿ>`I‡Úyq‹WK1‹@"Y ºö1½ ¼ªT^pOKvº‚ÍêÀvs…^®ŠO"¾|¢±/"J±‡êßp˜ìÐÕ²t.œÒœõ©[ýVŒv]ðÝ#¬ÿ9M¹'jÚìûJ‰T8Þ{ˆ¸ŒÈ:5EÕ/^AÂ[ÝKhÄêÜ´\G‰I¡–ûÙ–hx»;áp¥ûéô$ßÙI¬wB.È´b«æÏÚÜ`ŽvLBˆ¥ÄCŸzª°CT7R?Öù¹TÛR߇sª»˜ âß]Iç »ƒ"Á-T&ËDöj—Zö,B>¶EÚo5v!/nâåP˜©Dàü‹¡ø‚ÂG@@ÿæ˜F¢=2¾Q˜¡³÷®Xº¾y¼H+|tPÑXV®Ÿœ1ˆYÔ$ø+ ÔÛ÷Ö/ÈRð–?STPž’ó°êdšè–åP¾ºP†œ~/Xª|CpçEÛ{ZjÅÕê7Åv7”¸ ô!™åò»–µF~ÓèÕ„Ò ]©ÁîѶo¢¬:h´Fû£Ó³ýe+Ð6”Vø¯óô,Ô¯W¨…'ȰS'%æIh÷fœ_]Ñ*/ó·QÁ I%¼CËòW¼®&Ó&X—xwãåžyVdâRÆóÀófOŽIÅ”’VMgòJ Ä.¸ºnƒõÔâ¨ÞÍO/Ük ÆeÐÄÛZOÏ〤>òžâ¦“÷`]£ å4èÑSöÌðhPbg–wHVä´w¾{Qßp‡ãÎZVéo¹±ïý3Û+íXmŠÆŸÿ¨]´Ôá›8<Ç/XÒ=o’Äy®>!›RÉÇ“¿Îu|Y¶eh*#`])ù¸eÕÞv â€dþýP,3>ù—o±}ØóŽAŽo‚…ÅR ’η‚½žmAÁ6>ɵB=ÇLïš 1l½–7™õÛß.½ü9,Á®jV:®N5Ø Ë<^ÜÙtÅ~#±jíXÆhí,˜Ò½8£ßXr‡ÞÂfH]K\û|43o(ñ# BF¹¢VðÍÚa˜2ÙÝÀVZG(µaúŠquúr$ ²Â{\ ¹;™g`U´†šð¢wŸ=çØcXrk36Á]‰¶QÑŸ=¤¹¹±aWÓõ@äá:=M“5bBE.á;ø‹W‰\½&úOËî‘ ³^ˆ›g>ì[¸àÂ>®)¤k?‰j©Çm>C¢"€´ºå#YAɨrÐèXB9LÕâ(R 8 r&¨Jà§°8A¢ŠÚ£÷! [Z›FiúfŽÏüŠìE^iI+i=A—æs03†NmZ£<ÏuƒE –+³H†5Õ·±ŠP»½àìþ¾¹U^NæmËk@1ˆõ§“OÓ bÑœÎáI0nJ¥Ã©,úŽ媿I5°—©Øûýª¯ªË "Õ­îI4¢iæ´-ýûtŠ Œ+鸋÷žâh°sì­­×.nÑû[)‘5ŽQ¯ ˜^§•Uší¹ªND_F‹‚ÒU”yo.¤ÎšÔ"Ê,´žÆ€ŸS~,IÜÏþ[´¤ûÊŽ’€€ÍElÁ@Á‰|Yác¾Æ‰ý¯UüC1‚ó’å.ë@‡²IÞÑŸ²»4é›êZ,=‘H‰+ü¡ŽoRfg,U3D‚|X¸¦«à;äOÐ ³èÆhSJâw­~¢»1UÛæ|úP‰,†·*65 ;G·’ƒÇ)磑ÃÓi¦Ó3Ð>X=ÚÛaù4Ÿÿ –Q D0_çÐðø ˜ŽJ^Æ\RÐbäWÿ3r9ؤ- ßÿbK±—3ôù€÷v;Ä ™ÇŸñ£©ð@í>TáA_lxªÜ8)ĪL[´ÈiÐÀ§#FP(± ëU–àçÏÂçóÝúc¬ƒ9g±^u1ÜÎTDÂÀØÙøV< ÐM#„›š±+®ôŠÐŠÕÈÞY­s‘a©Í5éUXô¿Tp0»„‡ û ["™½ê`LzúQä¿ UŽIª,;®Œß‚’Sb¾@7‹Nl‘е¯+&7SÏÑ*sDê@~¼ ´õìŠh`2»¼„xò$¯ Iƒ1q~'•ºÆl¯#‡=­q]Qp’Y] JôÎR!ùþ)l×C a(¤Ïî$ÝMù«VV…Á[w*ªW™}îx«2Âòzi÷HI¡¿šÉï!ÙáÞ.~«™Hç–K—xé,Àù¯IhíäO`¦­Ýñ£/ÑÛçžâ^0SFHÊ1ºç¥Â¿Of8Ÿú+Þ£*¦€œ·• –föÿ:Ê\„”óä‚àK¢‘[Ì_?.RIäÍÂèùdŽô'«K9hZ÷ÁÐÜê»åF˜ºÞA˜ñ·ð§%÷U,yŽC!9ø? ¯ß‡B#Ê5‰ÑR zwZ³íÙxá^§ÄeüKÂ&(Fݲù£N7ÖznÏhwpâïî~‹ð‹ÁÚeíØ‰ùP¢4M ³8!‚%±}%ŽÀ{âÉru)c £ZÎÁÁºÜr(”œû¾p(üPîŠ?þàì/}€¾êKbc4*xâò%Q]¡¶ãôw^]bd±b©UÍÆã Œ¸ùî\íÉ70!^[‘`ÏßÿˆÔ#Ý…±»EÜÆ¹a«â}{zýÚX..ªÂÍvŒ ¹f}/·d6›xž •yÖHÆíàJ)P â#-ÑŠ8g ô| ­]ö˜0ÏS/·IÙ›L@ØÑúT­^Ù•~r:}h’€€Äþ¯àÄÆA«‚¯‘`‹¦Jô¸.6%Ú¯©¥·FÉ’iWÌÿÆj`&îí—}Ò`Ì y=×Ä/«sVצ(!C›†D[¹±úÉíÙZ€¹¢J}šoá¹½‚{à¤u±3È“2×Àù1»ãÂÉõFVà¬ü‡âl™Zÿ5,³ã#©HŸ¿• `g}ÀþI.DLà˜¿"Í3¼Ý´ãR½¡”* ‰2ÌY±œì…ç`d7£"¼Úײ%’™®'‡n¨¥éþoaùÁXKÃ#v¥"^©í€í$P-¿jaŠ`?šÛ¾q×ïûÒø1l¸”Ûú¤ÏæcÜýÛ`âæ`û¥µii…Œ^s9´^'É´§Ùß#jo¼ùEÞ%˹3B©ÏTX†ð^!Ïú=S5+ò^¿´úäÉ$¾òYnˆ}§FYZîþF),ß^öé Ø{è¸N¢èÙj-×Äæ „0Mc سšš[™4³`yK5 ùßЩžÑv¹™>GA÷y‹ÿŠÀûë}rÆZq¿l±J(#êFAmnP3¡µ¬j¢hpÃ;˜žîAÑýöZ°ç³=~ïäïx³¿˜ËHƒKÇ DýI‘È2Z©q…¯Ç5‘Í£vëötÓ6Í,7ßú¥‡W™¸Ã–›>ãÿŸt¶Ô@ä f‚Q¸¯œfæ›\BU2Ä£Ûc©œºùÞˆsv7™m jÉDzäQè–·0¾P,¸«õ¼€Íɸ}™OÓ¯³–×Mñ—Α0l†¶—¡dÞÑK¦þ]‚$ØFgd9„”†Œßn]~-"G0ŽÓ¦­ô©‚@ñI;H~’€€Èñqõ;×#º¨œ‡%duPÜéŒE˪Dxz|/9‰A(¿Su5ÁCrWëÙ7q}n…ê›9»*XSɬÙoÖ ×Oæ’ê­¢iÜÈûãD†péöé"‹D2²7̘¬/Šœ”èÁ>ªÊ‡°b‘nÏ ”œrV9|¤T—ÍTõW-ŸõXK·žŒPk¯õ˜Õ.èúÈbš¶WßC˜¦’FâÚc…ÅYRXµMÓПqY«s9ï„‹v€}WJGû±·ôgW§k·³š£¦³Uc’u?\¬‘m]çs¶8ê0mÉ÷ûnÏd•üBa@pÑë#í7cIQ·ŽÒH-%¹Çò†K¶÷P0Hƒ«g´pÕv9íµ"Eo¦A¤ó+\ˆ¿PÅœågª‰'‹˜KÈôk/B¸ÈY-—ìyQqb„RÈç­"X„]y1+]ªn[­ˆtOÿÆ­H—k¥92À\OÃ;X‘ôZç”÷È0È)sB¥ £M˜ìô(âßæǨ(H¶Ô;I}U,úöç‚"_ÃsË,`šÛÝMb—-•ˆŠ4²yr— <Á ý¢°ü5FYªâÇÇdVr­å,ذË8÷u¤j&æ/<™Ñ*>Ï…`"úK]@ZEÛ£¡èÛXiÊHÐTŸÄT÷9ü¡p‘I~c¨u¥êökí©Ø©Êãæ‚ôñ[Ž Zjlò“1k±ÝŸŽ A\Þ5ñuiŸÛa€ÕG”ôÈçÒHd½›|¿/š€éÑšR󹔈÷YÖØ@O ° 8QaB·H3-¯sÿ†vdð8ëCÿéËŸ‡4àÊdœ··œ!ð Wc,oƶ]ÿws;®½µü‡ý¼¶ W¸;!}˜™€ŠXÉÀÌÖ¬³,~ÄŸÓ;»×E…-ý \q¾¤(S%L6@–|3Ž(£§ZæÀ¨CZ»vèò5îpy¡®Æ»a–Ç0è ˆfM\Žk&l y@®€îþI1†¿ŽÆŽ/±ìy`Èzž¨MC`\WîÚëx½2Çr_íp“ˆVÀ+ƒ³~¬æýmwTˆÅ㻈‚f ÕØWJñöIØfâ:Z Jù@㿉ÔÉ.C0¸+ç)bÅ'¦Ì‚jGµl¡Û¦ªÐv[Unìñ’€€ÝùlÊ0^ž&|ÌNE´ùõäAw{B_œU0‡9J?6öÈÃóÿ’"R?ÙH8)DíøRÎ(ü˜¶.P `‰+ãÕÒñœú3g•Öl‚K?Mç{ÞHâgéÏÔ¯›?LÆ.SUp{†ÖÖ<f¬¯•SLheÚøù ý+>@ï›I8È‘?hr¸ú«üËÖ}¸2y¬:":!H;{ÞRW±Ã¿‚tÞöB·áKQ÷Êmªწ¯U÷Y'pöRì] ;C³fnbž8-eIbÁŠÁJФq+c>J÷ÂÆz‘ O»,æ¼P½Ú'±úS .úS¡Ø´Îr±R¦ ›HóbÁ\dpý\jÍ$bƒzÁã#ø„÷^ÊxÒW­ Ô9ƤŒÏ]Ìä³hô¿|ÂÆ5ü¬‰œ÷V~Ÿ Ô]oíî4·gjØözSî 6mÔ¸¡) ¤Ù°bcáÉSù ª˜Y*ù=$#<-²Ê§l+S˜c’€€Ë=\õÍgt ¨jˆ¹oX²_>ÿ¾áθ„^m†G6¦›?€ kK_[’N¶m”¼>w1GgmÅíTK³Ù‹›h¬–ŽúheáfŒÙï´ÓÉ|’»¡—Ögg“ާ´ì4|vUÕ‘îªeŠÓãÏ[~¦åR#¡¿ ƒéIxpð9#ÂÙ[ôDk¬º½Q‘™)ÑÜNú¯˜ò Ó x‚D‘ˆÿçcä‘áp…ºØÓݰx®këüTŸ`]&IOȽ+SÖ´¯“(Õ4ƒß«â7Û;[3芛 U¹ŽßXÿÊ$"àðïœÌÔ‰™VƒÕ—=HEñä^ÒHÊÁí ÙË[3N{UÉI`÷ » G8SlOŽGHµµ³R²…ÊÀG™?I„ ý’ÙsüõûS=£ªåÑþRG†£î«ÔHxŸ ڳ߅šÜ²`u89P×xðÅ]~‘Á\q³ˆuß{wW,:Û4¾wr­j£ÒðLHÚ¾!m|j²°M ãÉ‘pÉÄP³sëw$ˆaï/æ#áyÜœïÒÄÐ;èœTÿœ á¢~™¬òË%‘K#×Ê9’7\ÕñÆØAPàÜ& êÒx6x¢úåŠEôP¹D<ˆ]wl ëXGkÍ)SÍ[Ý=2i¸×8ÑöºŒf£}À•„7DåÃÙöì(_yË– Hiݵìü,öJÊ•"A`°qú”œJ`fµ1*œâ5€C&–ØÄ>ËÉ91#ß¹Xøq>{L{eslÆN·„t²:ï¯pGÍ9¾ÇoüšÕé^ ܹP‚Üãi©*Ñøáƒôg ‰“úº±Ça-äqשèz•Ò¶$ßÙ °Ý€<Ñ3€÷ ¨é=•WÍ}¤Ú%øù +8_ªíÛ›Òó…oâòÀq¿ ³õr(”¼ÑÅ3¿¼ƒÍd}„;¾dóJ´_Ó ÀTêmÒñ§ƒËºÀŸãešÔsÕ÷I 'reEú⸔.Ád%Ц[ˆ¤"«ù½›†ð"KDn4Ó6S×4/¨s×ôKÝ‹õr†r´©å[…©!¡Ü…áô!¨¼tïý%D1†¼\ç7¤µ¨ÛÊ=iyíÙyuÈ’‘.]¼²òO~0SÛ >Ò³!ái §‡ÏLu:Õá–&ú6Žø_+­‹ÃfÕ*à˜¥TR(2ò·’€€É±tœým=Ò«€ª(@C€"Þ’OÐ/6àü: DwA6Çz½eÀ÷ï­‚~UÍŒ¯D~êÊ'˜æ˜¾——W"×àñH¥yñˆ&³çò…§­>ìì HÂL/JÒØcÇ#,ž8ËyãÓ{eûè2œ^e|”ãO~ÖNT%ÅÚÊù=Äð¨8ZC=#ó_¢ÈöaSŸž>ÜË!9‰º`:Ìì.u㲺œL%_FßX›Ø}†++œn©µ´ñiÉྗ]8!ýä#qÆÊÌ6ͤý¥xí¦Ü÷ùsº !º€ Ú*ü2bD?@÷¬‡ö›Pt̼tãE‰5Â9z‡Hr˜FP7¤k]ö—›cðUæGc¾pºͿÖ U«Ö=‡f·ªsþ&¿àò%rö¼ôï ^r`cMB­™‡|¥¿åu­â‚A¾—Í[©!º§ÿ…å|9:®Á”ÔI,é›.¸è¢5 ¹±¥-—Ø”‚လæ»ËŒ±‚⹨¢&Ô»£ÝáÄE^Úø‘c!W—“¦Š^ì/YþEýÛ59ÝÜ,¯Ê{ås*ÏÚï3 îã²g{‹ ÿÊã­­Ÿ]¢©®þŸÓFàuÉ<ÁûÓß&ÝüR’Ž)øÚ8«>uãaƒžˆÂÔË5iNmwš°óÎ哲šYÓ~è6kR@Qo·%)éOB'a¼”&¾@üÍ÷‚Ë‘óǪ&Ìi”ù)þ˜‹è½.´'ó&Ü8þ_Z~xú©ÞEþáVê.Þ/˜|>ƒ²ç0vî gtø7Pâܵ[Éþ "ýßpíÏGÊ“rEŽ_\cšk߃ÒEeïc2Oþ Ç›S¨>Ro.Ú©°^`?ý\þJ ¾ø\K® Èµd¸ŸÂaÂ;_àlDZU± ħu«wÒxÖ(1Ò¼ü’€€¼xÙëK’"gqX~ì`ÊçäDc9ÐÏ-kAŸi³yÑ·Aµ·Ê4ïõüâVüÄLy<ûr¤®;ßÄúG—1+´\¢E€è¿¯ùÎv¾š„…À:h¯\\î9PGsvDÊkàk< aÔª1-£vÍ ðq-‰>B>ƒ Ákð…g»7%ÉO\(äTýà•«€ƒÎ|Âså5Ê’ü¸) W*_ óñV-ÃöbŠù-As¶ñÚRQè3,¨¥å®¯i[©-r/ä£ƒÔæ*.ÜC|hG‹V¦æ„Ä sâþB9qøòYäÓèÖ—¯ázÁDÏþýov¾‰|o•¯+Da ‘*”ì w®6õÞÊ÷éBk+ÌûDù `ì»/• ®ÍOt}ÙmIIï­‚¾5vR“ÿsßËð&f¦ö‰þ³þÑÿÚ]0;Yl½ÕÔ¨çÄh?²„£5ÆE²íÝÒ5ŠW:vŠ ÌOÆ cü1˜Ò-›èÜ.²ðî4ðš€:²uÊ#QS¿ž?˜[·é#A°ºÃßÿ[|háïË”9%ùjcFF7Þì>M˜É¢šxaìÙ. žGR×ÖUó€A?ã ¿Vâ¶ÚÕ+å_l¨¹}'›gñrÓ0fÂ=aOö#ÆË.‚õQSÖøð!jÊ%Ërõ}Å;ùñ¨{ÍXò‚` Ê#Ÿß l?Rÿ'T,®,ÒçTÔLü,~lÆ EK±÷A†ÿÁ­XÉ’¬qa°‚¼L2ê }ä†wÐíÖgýmày“G9û– ˜Å˃Ö›Ú»õ—¾JÛ13š0ymʘ¯K9ÎOÒ›gqZÄüµÇ¨P6¯™à‡‚À±Xçש:t7 PIÙÉ©Äqy ± ³.YʇÉÝ0ŽÎFdJß³²0‹,ÕyÞ-½{®ÂÚLÁ£ÿÕI2TÅ('°\hjOsüÇæI4±3 îI©ã™?§²¸| Å·Õ›<Œ%‚J¢8xåíd-L\q X`}@J±…kµo-æŽyP¢ Vc”¥64 µÕÐÛÉ ?±DòFBiâ.pŠ=QK‚1‘U+>ޏ!0…†¨ß´êO· õj ŸÝqü_ÉLB·ÓÍMª8ŠEi,¦¥w¥æïnÍÄ€mJZ=öaâæ±ªë^ Zòµµt’€€­ì„žW{Wb–XIta O†ÉœÄY3Ží¯Š:û>}8¢f·f,$M X&,a{æpw¤Ólü%äFæý¼È©¤3Ÿ%Y¡YBÈ~ÉõÛ•gÑD‰_þYþ)UÅš’„8¥îˆȈB*øLuAƒÍB/€ü1Šýá\^\gÜÜ—|»^ž86æ|£âhT¹lžÁY+ ªCšŸäïÏo—*¹<Ñ¡¼­c1…½>DZÑgƒnc±<¡5ü8Æ<£ådäèuåœg¶Ð(G¤~&ªëí ö-‰b¿!§íμx /¼ØýQàó½dŸú=¤ßCÑ©3ÕD2ÄÒÕ6ì†Û _´•Í Ûñ mâÝ`H\Ki}k–:]ÍÖûÑ25±sÝ΢‹*(¤§e!tË`äÈë?‰«•$.ÃÁ±éa] òDC('«ZRÏ6V1Æe2%EXßø„4Rçd¶´x~³[žÂáÌ5ìZ\cÓ>Øö’O3 ø_UèÈ?íV+°µ5B‰ÓF;ö—{4¹ŒŠb²}Þ N(`>5Fƒæt\TŠß©[·>­¢lmŠÏ‰íófÖNŒÎbô¨ Ýá)TuBÕÍ8ÜkÑ@´sÑ¢'lxPÑ(rÇÝG±ñ?HDÆââŸ=€a꯯qÔ3]ñCvG¹ËÔ` ö³—Yó<™kž^Øør4Å9¯B8¿³g âna6™TÛ‚"oÍË36 c7„U éu¹oþl3YW_îoÍÿVcS³2Î¥i›²—ÄxeçÈ@¿?Tª¹ÑÕ`W½yª³ )Û¦® HåPlÑÑÒ!á½Ö}Î軞çðX°‹M£p¤-<ÔsI¨5Æa(ÙÈšwŘÃiº·“ήb\þ»3ìµd¬’+Ni¦"P,ˆû7D=áÜ´ÕŠ³ÙŒ[h?®jÍ Ë_õ¹¦AüºQû·cF ~c-‡¾¾ey¼`ýïSù&:=òï;@¨3‰Ê›ü+u qù︂îǰ®„Áv¹UCE‘ç`'Ñ<˜sr]?"äžú$9±d;Eª£¶a¦qVµ·KDÛ6{ÍtÓ¼€#•OœÚì=ȰWúø&Á“Å|hWO.mçÉÉÛšòê/-üžcÝóÕŠ. a€#'3‹åÅ„£¸wKÙC°K‰ v¶I(8F £ã5(†¥8%6i)¨>Ë?Œ/«‘jïFie»7¿Ø¥M/¯¥ m†]Ûv±7-p³E~­r0™•ïÚû¯b鯩ä…íùw~šøp“!4A=ÊøÝcDÏÅ£×KᲨmrëÿmâ Ž`6‹0Ã-±Õó{ŸÅZ³?*Óê‡îw¸®«›‚ð4E?­)°h¹rEÙ€ªL\›]Ú0îæ·lëú£^nî‰aÂÌôFiCÌ ûaF79 MÊÑ*pX³Ë óG`ãÇD1³”[à_8º‰…3‘™Æ,*(Í "ªÛl¢EÀJQÓ±L@>„éf ùÉ›¹Þ˜VÈÌA¡Ø„ ûýœFÌ2Íi}Âç ÀÆŒt|×ùGJ ’ùvqÔòµ :ùжš.¿io §µþw¦M»$ ²ÆC[ôßqºm’Ó¸±8(…=VíåÅ”X†âÐÕç nÁÜçÉfߘ6 Æ_ V26ÁÖãî–Ê-ò@Õr÷Ìrh`jÏÎV léª^è,<[kíè®›qV†šcô´«C}e»–L™š~Ìd@¿sŠÿpNè˜óD·€òÎà  €³@‰"ÖÆ9˜º/sA÷ó¨˜ÁŽtBr¾ðIwåjÚ=9(Ô ¼ðM\6TžË4j”+¿jßsvšükhEôÞÛ€-äø(-ÅË!6” ŠÈvKJy0˜¾‡‘À™÷ÏÊ(¼²]-yGÓwÇR’€€—‘ÁTHRžB’×Õuî‰ÈÛ±jµ«~–韨¶2–©\3;£%^óÐSç5:Ñí£( ~,šQ±üê”xØ­*j¦Ëݳl–8…U P¶"¡å®[Û ˜!Ýe{å®uÌÇÿÉÁ’(µPC9í£3(ó$Íž’tØgÀe[‹§ª«O¾½1æIƒ¥1 ŠwÑ{±ŒL,ß©Ø8Aeú—¾×Ö=y?ŒáÈlJºÌ»_‹ŸË'’ØÂïÕ O8íõ<ètB“ ¢JàpøÂš™Ù \r–ä“[gyNðz¬Ü*hŠE‘hÁø“B%äv8 íU¨=y(DäjJmiL¼’¶À¶éÔAΦÜx¦]g¿?«®”Àêë´eåoq“*"ø§_Š8¨œ—°#KqñIhƒ•Š<Ç?ÏÕµ÷àòä™UÆê|½ ‚?Â/Ž×½! ð {ò¶·Ô4ÁpàrbiÖ#¥3‹ÈýŠ)α¾…XHí¨ÍºZ68eþÔIºÛé·ó¯HÆY¹õŸAÈ^Š·é.ûÔPŒ¯ èÂTŸ ðõ9ŽL£­ÁŠØRg“ëÔAyüÑÒ÷Ÿ¯vg.€Ñ­k½ ÝT¿U¥²X&ÖÔõÓ02æýDYTX²ÿ”œ¡xì7£FÔz‰Ð±Šn!È6ñ&ZIYP•¦@NJ༠¤]µqä#J,l'_h/ét/T‡’U”IÚ—ØöM‡Á¶,œ.êg< ÂΜX_†w¨9mˆ¶]Ó}Ÿ`äÀèU v"u¢ÍA¯_¡B1&âšéƒÝ«âRÃI#aʰM­Ù@ÄYžü ðYY#¶~Íw•˜ÄEåöPÌ…Wh_™b*:Ìç^9Éþ ìEñŽu­—@Wœ8¼·×TAC4¤Mòä>äÍé*k‰öº Tbå*üêR³"ÍžúŠö¤fÆâÛ†–¦9õªäÄPõƒ°~Cüc¥dNÉ.›¸ZÜìòë!Ñ…²¯AП‰¦®T›5¹@ÖëvrD<þ Î$Q+šµà<9÷† $  ǃWΙ´±åžCþL¬æ`0ÌÝúøAXþ°qîì- aü¼,=X!g 1:÷àQ¬}QçÞÄÈEiî ¾ÿõàïºêP:µNoý?›ž¾(@óœ=©,ÊG™˜žÇu!0âÇ»>§4Ñ´#õS¹SD$šš½ˆw,« ²ß¯Æn4âšrá ©x&f^ /7Ýê¾m~îìé™þÜÛo&8Ë“L xŽy0q.À½óÄ®mÜLüyK¨±7VoN¯i¸oEÈmW¿œ°0,dŠk}|Ћh2’%þx‚ÀU¿B0ÑL›ÀDì&/æeL o4íSj[êĺ–ÌÖTEú+ùQË GǨ¸õÎú”RsK9˜bL/ôòbÁÁ9|b<ªà@:¬ëG]‡cSV#Jð×Ò- ØeÒ‚#’jÛ{÷­ø*£¸È÷¼ [¥÷ S”iâïzQ7’oÎ6ìïcû8©}ym–Næ1Æðüs›xUdaÆœQ’*DSD·ñ¸œq½š”q9Q,Ú: ϰLŽÊSÀ‚QÊnއ·ýAüe 3E{ŠÔe¢!9ö •‰î5g/µß7•Ë—<:uãìÃÀä¦Gµmd³ãdIÀ T'»Ã'X;Üリ ä37¨W ¢wZ!³%¥ÔïYšèùÓ°j%ÐéÄt©'ª¿V8ÖúÆJ¹ü»[hvºH°-®ºë£ŠMa/Ç5íÌÔ–q #ÿº0¡C¼³<ÇÓÄO°ÕL¯²ÆÄ(­œ L " ’h3fþì{ê¸Dˆ:Åüa’'cRµ-4âã¹’€€¶Y¯,áÙÜ‘oòßAK¸OøÎz ”ôîZ­¾]SqXuQì•zp›´qžÜçÚ9®‹·õ0!…¥Ç7ªŒßÓëjßã}ŽŒפ¨»ÏðO}Þ`Ìc2`Pú­kÊIÿ}”¾¹ë 4@fQK‡G‚U¸zSæâ†»âÃiþ¨¹”¥ ÅùŽòs.¥lIb¸¾ô8BÊ?ûjð7¤Q„ª•ýê-6¶ßP‰¿ó¹-?ÍLDtÝÀ4ÆÛ*íDœ!yæ‰Ôí‹1´ÔÔýèdgpˆ«fý2»T(å=Sà´3†%åƒÏ¦¯v¦%þÛ0ÆL2›¤`eðîߣñ»ÑàG†Ä!s¯Öl¿pÃnK ^àÃwéß_®2V±qÌ/ pÝŸAë»W˜vJû$"‰ñ6r_0­æ7Žér¾ÌË—'©—©ÏŽ )™I ‹­NÒ,¬œÿWf'¯#¬ËùÌœ­mX91ÚöPKw®ÍúH8–¤2ó” …;'†n|Ó?ÇGVŠ–xšþVŸH‡)³¼§¤€äµ5Þu6X€­Gáó-XïNÍôK¾W¬¦Aàèn.²ø\¼AÑ/SZÒu$¶çE¿iz«­yj“¹)ÂA5ï«ò¯Ä¡,¿Ê0—N@ë´‚çsÝÚUën´fxFZRâOÒÔRã’–¶ 5Ä#MØ}µI`5™ã¤m[‰ºqý‰³y}K?òcûüàuŽŠ·øo7œ-hl1­^Ï rf“¨½Ì IZ[Urv&{ñrÈ15È™Tß;"£”,I2dçá(ÕL¦peìÐ3µ4\  å’Ò|W>zÄèÆ„‘µ5=¶ëb|ˆvºÀ´@¨ˆ¯¶3Ⱥfɳt^scÊzd}XyÁë!ÇÁÈdg×)šA½Îd¥ÆA°Íq\·˜#l~ z t…¼NY_—M0´´&it™ÌÝq÷TøyI£î6Êç®Ò'¼l‘…ïo\ćFº±Ô+ DLfJ)4\AcŽnÌürx'ËÑÕ«åÉçØãè«™Àp¹QZÊù0C5¡í2õ¶sÙÈ©1Îo’€€Æž*R_DÌ*6ùMá9C¯jMë›úØ4ÀÞÙNã gîÄUÙ|R4þ2W‹5ÐðæãTݧu³ HyHç¿+ûÃ%ay6“GÊ]MßMsNë¥yñwá ƒõmq‹!ÚXR*q5çb†Óžßá´™p•>(¶…AÑ—÷„«æS§,AQ$•sìéä¤ioÀ H=Ýf‡Põý(* LµÂX—”òÔc‘ÿÞ2b³°¢òH2 ~ÿœ¹˜~7²Ç3Õ;x¨!Åt7{#;4 ôvèMÆöKÕýó ý'QbƒlRÛÑèŸâ•‰¥•­i±Âvvµ¹t"çs¦a³ ©¢9¾Q]ÎK‚Ž"«UÇ÷–üns)0å)_}ªëEعJLW_=õÍx¡Æÿ­‘³Ÿéÿ–øX}(¢dîTã~=*To±¨Ø»¸‘¾ë‘f(I2¥eå>TTû |¥)cl),جžÆ·H‡ut ©Ø·&Ó‘-ç«ò|Œö‹}‚73ë"œ„À‡ð¨Š¥¥5ßÄý#Z5˜i¼@hƒ÷g4Ð:žÈßà‹ WãúÔ;„Äü®æûIJa/@tX,†„è¶£ÄãIUü;ø*Y™Ú 2J6æ2Eý!þ?õchÌ5£&C¸Þ`YSPSú íg£#låë¨4!ꃻ47ýß÷æñN ’‚Sú>ãmn`Ba"9Y7ß@‹øS­Ÿäì¦$i×´ž“CˆI·kGqsWÈ–[‡>û‰.éàÊq"Äþ¿èg;Æ~Y0¾—Ÿ°çd/„>;ÒÝå½À£ä:_â Øcg‘™ð.—L‘’Ï×Ãn+Y?6½üZ¢!byþÒLr£úæK¼nhgGov~I`}¥Œö#ߪî¡u”Àšè6ÜŠ ²I€òDé ¿èzbXæó2VdœÀ²bD&.Î.^.ZŽÄúP4V(Ii¨À /Âóçèí}`›9\dᬺOJlÄeÝRAîkÂ=LðªDÕãy}:GÅe&H7«kîh‘1À•Ó ¶0yª¨²— Ó~ ÷I;èÅí‚›¾ïùCÒWVûD†(iæ¡v:Ê)˧— ùš:¸{i¸1€þò¹|ð›k¯Ô8²2Ùùņ5jå^—‰ ®’?a’€€íQ&H»Àm¾g¼¡šO™m[…ñDΡšõ²6›Â ǯrPª¦ŠLA4„Ä ¸'„]¹ ¢õØ3DdÍáïMª„tÝ/ÆnZÞÊ4®lsì<¶ö/W‚ U‰8ð/) h³£y¦í"ãžÈ÷Ôéé~!³&µ¾çÌg·åàì7r‰iî`ÿ¡˜=ĶL¢èòj;›üª*'ì…qiЇÚOßtQD|LÒVàÇîö/v ¬©ð8°Ðo¦Z{ƒÖù…g‚ÑÕV‹ÞÓ[6¦ÄN ‰àKn%Þ4“y-|YiUÌßûVFuNÈDµÑä˜ï—ŽéîÕŠ= IXñ)?â¢Â„N˜7\Üd¡½zyó_²B$çm̶8K\xæ>n’GÛ,’,Ï -º‚Úµ§PL4ü¼MÎÙI ``Ž‹ó—2·ŒuË‹ Û2”õÍÚ´ñ¥íuQy ?¨Bpü·#è“ Hãþ²} cÐdb`rÞ'l¼Ì¥–¶ºôÎa+ûQ×V¼<,šyLŽî-p)H"£MùLÎ&: 9ˆL«>ÖØp!PŸS¶Qbª¾tzù>öd‚\1µQzKŠKm'ô ÒÑ,¸N9ˆ[¼’9|=縻E.ò+îÁŽb=19JüKß½ú_­‹ÇÊnô¹ó_ÆÝrråyl×z®ÕVOÎÓׂ~´©Ü^4òC½Gò+zí¯Wè çW?"{‡í¢×W…4½¼/(YÄÖ6’FÐw5fUߺ¹ÁˆfKSè½ÖS£ée®¼GM·mN¯–6&Ë]¼JX°§_ØÌ³Tã âx»5t„ ¦^^hˆŠÙÇyÓ7Ìã6s{°búl…Ë|Õ͆às/¤÷ÃV¬›sK“"§Ðà~ ƒÒz¢2Y›”¤HÓ@OÇRÕw2ÕÝcuÝXEíþ§iydí–{IOD°”ØÓ4'÷e¤¦ØŸ‘F$ÿ ¥õÄÝÜ<½Ê>ß…¬ª82Äq­îf=H($æ+6ÍH¨÷â)áfÎèt‚u? $¥£Gmúã˜Ø)KñlQ5ì™8¼tÜΓÑÅsf»ªbøN`å?ï±ü%Læµûý¢ô6V2nõ¤`çÜM`YÌ™÷ ¨|ÇÂ+†YÙË„èBž–˜ýË@£b´þ<ð1És0qª»%UüŒþÀp•2º|g îØ4«jŽÈ칦)=XW·OyôÿÝǘ"$·ü‚,‚ï–é ûäò¨<¬‘eNŒö UA̹CGç"©CÖbaéXp$¾&š}6þ/ 4kš•Xw^$hË Ϧ‡—ŠcwsXxîX*n׋¤€´ªoU:9=\„ÜæDgçż-WfÇt×ÕÊ64DŪÛ Y>uE­“šw¹ú—’×á³0µ¹Ú`‹æç¥!Í>½k1:"vw Î׳]fúÄ®R{Ûñãújž¶ _õ/bCÈô,ã תÙËjfeU2¿?çBa?ʾ–ŽNÇA"è¾®‰,¡(“ † ˜Á:¨’VÄ9ÊÛˆ|?a¬¯z³XQ]2àd‡FnsÈrºLÉÕĺá¶=¤ë“õñâw£´Í¶=‡H|(Þ!Êm:¼/޶9޳|û %Ý(¼J(k—¥PG°†0‚í;.\—ßO<ê5²9Ñ/Š«mm#¤ßþÙø/ß®GwhdšÜÇ—¨I.¯îu‚ v¬åEE¡wœ®¾¯ì iÁ‹?;(ñ{(b¡”^smûK‚CV2’€€Ðå]¤ž‹’ûõ7ý€Ô…*ã‘.ÍÇ"m(bÕ¾Ò>4™7¸Â A¦(FÚ*zÊDPŽ‚Íbã»n|¦ê,>urãÊ''56D¶2ð¡òWâ*UŒ3°¥qWÚØ^¤rÝtR¤Ì•Ê6¦ã¹yz½ž?Ɔî¹ÐÊÍïN½ÍbA/ü²P9,¨Œæ;„•©}&î…t¨jÎcNÁO^êË¿*GÆ®ÞÆ--YÆb=Þw ‡¨~Í($Ó7™¡~©Á~©7S{ÏsJ«0®D|Ó…Žýñ†¤ó•AÙ¾œY½04 ù :Ë´¥É“…ýÒÇΕ.±ùÿ'O`QÙþ´®ìñ(B•9‚]?É‚×~ì3OZåÇ‚/È~3Œdoáéo|Î7¤JPTw…$±î°™^-äb:jHúk.¤Ä™@ÒMXÈÕø^6,ÉãÊf2fþ£¨Ó-@j TdŸÀ=á%…K¹‡Àòc¶•ª¾œ1”,Y h“Cáý~¯1MCŽ´/§sC›5|ÀuTA-,l9Dë_hë$>ï%ZQç*¢g<¤®Hº\ðo!¾NËÒÖ¡-ÐÕ.›SCš×âkeª§„1×w·™,»JÃÚzj?ðaÑ=5ôhË„›ˆwßÁ¾óÊ3¸Vˆ¿ªÓÓÍþÆæ£³ÈJLŒ¯oª‹2vIïˆÖGK¿zŽ{^eÂQù‹¨½ØqÏž¾ÄúÛýzo³•èÐ;Ólï„<ˆ-¬F=¨ìG‹‘ÉíB±ÍãÊjNb…À&»êbºTìX46kF£r¡¿Dý•˜×Ù>ÇéÀ¡U ¦—Ÿ×MÑæ¿!oŽç™g€ÞY"ò0ìÆ1+ºÜ"YÔw ie*÷;WóˆJ´„X‘K|‹r qhÚÚÆUå±þ|µ¦vÑ–¯…¾’çøn툄‰5SÚ0™;YÛÕ?”Ü2 .éŠ] ³Èk3@þæÛü w "XÜÞ+"¿ !rlÆ2¦ß¾D¦°0âÑ/Å—ý±Wß0p_þãõQ‘¨”A »—.‚ºDƒí ½®#³HøÂlSãN‡ª-7·Ë„îó•e¾ì¥‡£V8Ÿ™~<äÖ¯`K¡vÝUÅ‘Prhçí.¤šÔ¿|ip»Š-y’€€Ïø[¶x?Ah‰ÿ•žëziËÚB­)½Ðã@G‹-¿téÅz¸„²Õ"@¼æÇfò^ÄÅï…âWx¥¬D¤6FÇ î1 ëÕ¯ƒoyCÏÛ„ÞÀ`ùÁ¶ ¶'ã LLˆË鈻 $šŒe°?™qÆD¹%Ö5¹ Ú2©¾¹ a]!wb¯K‹Û&‘JùD€*9ø£Úuhµ×Tåµ£’TÕí‹òµ>È¿Àfäª5lßg,ñE×N‘ì¼$š…sKaÍ êrçOEK Ùà³¾+Iz×ø©ýŒ9çF6*Kp(ãØ/IÃP4¶'†Wž”²¡Õ#5c)Pô3%7A\…i…;!öçTP>—¶.Fêܬ8«XHN/Ë4¢ÒÊ=rÆË `‰=d%le"¼{+Í&ÐîdáÏjK‹@‡Ò þ t³oF;YÕ3s-äÙ´?zŠºü?Çaw[ê‡ø˜ò™¿> ­úÝÆåK3´ÏœÞ¬~ÚݾäÐb¯™ܪ¦n=›êëâÁ‚wªlŠÔù4 mFv¾‚koj1&Aý"µŠ¸­0±ÀÕ¯€{ó}8GÄUl ¼á¦æ R«„×þÚùí ƒöˆ)A/¨¿ké˜Ñj—Áºá'ß"ÈûRù°¼€®ÌÃT©;9§*k“ib”™U<'ÿ3âN eÆd‹™'Ö·¹0÷?ô4Ì<83¨1è´61âM;$1¸ ŸÏ…©Èh©CC"/Èÿ,4ý–æ¡Q° «roÝAoög‰à˜¶Oa?˜™²†šc"øy/•ž_³óš*áè9Ýg­¦½íT-ÊÆë"‹-›„k·¨% ŒHŒk„„ #~@wÂ!ÕÄ&õ%uè}Upà·å œáÔ°Hà× eøø)GLѾ[IKÅD¶ó3çåòiOº‹‚CŽ‹”¥¯0aËè”ÍDŽ=P5’Ãÿà HP eǾ¢ÄßH98_ Ì7lÿæÄn>ñ™ªpŠý[¡´H)W Üþ²ƒï4þ)µUߢòõØÐ¸Þ˜¤Ú}6Õ¬Û»DÇ-ÃÐ=ªsadã¨ïTxWwËPÙ;?5f"çš’€€«q‚„?ŸÆÕy-\ñ+›2]¢ ù?à˜ò|]5x´”kº<%iÑ·üÊ„ÝaærÅ&´0LA >Â&Á¾À¥ŸâOm37®)”êâ« C[‡5úšé'1‹€/šÀp¬ê Új{)®ÕDn¤. ¨0èçj³1,ç¥~ &±(¯)5xj«íhP:çûᙪËEtËKiõ|±€§OÁK;9Kp‡œA~¾U™ІRú]Ç0!p…ö»ÄìÍv»”b“/æp€'‘íÇ ‹žÇŸ KÜ…øt'$kg§9Ìkœ§êg!lGš=Í›?1QLDô±Ë©­><æó²Ãk~…$ã@@~ ÷hßÈÿžbʽe)?U>a‚o6{Óà¶{Ö¦‡‘| ÍÐ,B½;$­à蔟¸‘ô?OÒ*¦… Ãï°~h€óªº†…È{âÑÎjìò‹x”27U>‰žsÆÓ©¥1 <-cñ€ '$ ì.x8¢Ÿò sé;úF ãdÙ¼w–ùð㺞»“ÜÉú©¬ûšBB.Ä'Æ©Ö-Ö ¢0D#Æ*LßgñJÐ.cà-sR+gîlh/‚ðq´/GµHÖÕ|ÖqšS»Ï¼r¿2@_Ü[Z ÙØJÔ[EÌ=!EcpµùM .ø7ãÇÒY&à, Ìéuî””!H£¾ED9ª-&”,|GY^¦œƒ;%-ñèš¹ýù#lŒ,ÃõgÌ, |ç]˜ì3ÎÈôtòªË]dî´„`Àé?m@uÎá:‡Ñ±/ ®À¾;÷VTÈl=‘¸ðì“>3ˆ®ÀŒüâûXá›ÔÄyžA¤HWØÀ®íu%¬ ‚–’¨“Û½S¹N–Þ›–W¶3>;Ín â ݾ~‡Ót!Ü"Fw::X¶ÅÁËMÉŠå·ø1ÁðÔrË@5Wz1?FË)ªŽh4»Š6†ÛEF¸’«=OþKsÀ[Jº·¨Z•÷üÖî’r‡ì·à6àn?Ì”÷ffÓÂ]Q<Š$ x4²{vÄ2>AÁ)ßõ Üd^ñSæÃäo÷Ÿawµ­Œ‰àÁ¯Ôc\,~›Ô ÝíEº?µƒ«ßmªMO¼T4‹°+oØQªó…‡Ðýó…~›AØãä‰ÂûY“}‰‘hò/RØYRŸËÛÐΊ$’€€¬œkóÓÏïåâè¥W ºÑÔPÕ/v”™‘¶Þ (1»Ÿ€ÃrŽ‘ÄEƒ­ßÑÒ'?i{`x§RÍÃJDlÌ/P%´®Ó%ª©¨Jé’áAu 0Àøy\w‰öýĪ9°"ùDCÐfD£kñìXé0†œ9±ºp6ÂéÓ \7i²~ÞÓÀW[©ß3BÁÓ`ºÍP=JœýëâÄ—'m0¥&ÞPýZ!¼j`gQÛê¥î;aÉÀÚkÈ´–à}³|ƒ”7H¼o¥B÷Ô×?ÍÏ·[ì!&¡f¶(¯9¸0勯ð ëM!sC'^õ¼<½Ö`.ÁÅ( ˜ý‰m¡h©`š­kæ½6õÉŠã ä\ó(ôóÈö:ÅdU m­Fûc ó劖*iÉzR/¾ŽXBtj½€-0SÔ¾9¤"Ê\@f}Añ^:²x‡øÁ¸¾O,ÅAœw\Qý˜vÉ*é![.“>P+ñ÷BŠôÈá—Æ;b'}|gW¬½$¡Jý.²¬dè)1])àªB Sšgwc㸓Ɍ)šGÅbÁ'‹‰Y† ï&êsÿk}ÿ†zjXÅTTÈa¦tiDª™ZªŠ«=ÈÛÑ[b4*E×yýúÞ)ƒ=-寫Âeìá/¥¨ÜÓƒ0cxØßS©T_Ú6‰V!ß4«Š2¯±£aÞ<:”bLÜQ[±HI« qm¦íEÜ®‹¤#„ÖPzY¤õ¬ ò¿“9Ç‚ýÌ›Å:Tmï©rÒY/J´Ú†AA]ûj£oùÖØê;Ou“¶_”΋öjVñ þ&c1mv bmÅÝH´/Þ¨ ‰p.Ô˜œb\ ºõf¯´¢~㊠eŸêµZûû`ï_»¾=ìÆï ¢3Òu%qš¯fOÃ-š©Ã«‘J¨>dl.7n¢å0ctô“ ûü÷ôLD/5ƒ7¹ò ŠTé…Ô~ î`Xë+b@… §ác™¬¦ª ^$uüŽ‹Þ¼,[.³Mqô ðÝ9ßÉ9)œßUrþEl•¡®í¸¿T/ù#ÕëÓsø×hË6kˆ|Æf¶O,4plô{zJ w͇Öϧ _Y`pØwŒ2_¼Øá®¸;‹ ½ TÜR><‘›B‹Z$F zdríµ_’€€Ðù9!…ai|pŸàþç€_µÓ½ë¸…¹ÌaQ¦YK Ûh®ú…MSó¸¾Z`„!Ôú5ïЊ5¬ƒ-=rx©àŸ¬Â¡Â_ykðèsV¶Uqdqœ*äžm6ÃC€k0¾5°{ð­Ü@zqàrLõm‰—ÎVÖÍÍ­ÙÖ@µs³ë:DaÛ a&"›£ €'•$“ãBIiñÈ »†ó ÒëÙËúù=u¯ñ«hfƒNXîNù!IzZ^ûÝÞP\­ÇŸLâŒòÉ®„¥¶A)çËŸ«Qw0UÙÊý¿»ð <ÐâéñºËBwØÔLÀ["EIû›¤± î~]ˆÖîGß!ÜbpeŒ2è3 IÄ7²Xx‹‚à5`e¤Aæ?{=ÁþÔÓàkJÕ ÂC1Ëw¯†>” ± x§ öRwR @"ɤ:E×ÑÄ9/ø‚ bôéh–yŠ »“=µÀETuwØL£E97¯ø¸Éoû¨u†aêê–bW&ǯ;‚s"Œ›póçÇP5FÎÉ7ÿC¯aæŸÑgÔJªÿpÔ†ë}Ò4«•ú&Îz‹<|Im0z护äVœô´KAø VÄ|QÔù—¦Øûa\ÏG uÖk'9S£ØùŠÔkÆèüÜÇy°âˆ/B¶’íÈë]qÌK|‘šª '·rlgwV±Üî [3Un¿(m1åz+¨ãŸÏ#4×'u:7P>ÁáþúðõûIÛîc{(E·ž1UF# †:Uv(þ÷SMW¡ÑУ¨%ps!E™ ÷nN¥aƒ›Ô˜äªü—Rn'ÖŒ•$›ðEè’Ó¢'biæÇ“h,Î¥‰”åÖV…tà¤C?(š¤ƒô§h³yWLô¶ÕO’ÐÏ÷]ö®»’€€ºZö$”ÉÃ’8‡G|ë:•…õùI˜ø:¾Žäâ²yÿ““ìžÌ …jùNTéûÈ~—‡Ö7àêÈvÊ<:SO»8ÝæíZpÂÂò¡(Xþ—YIj?oëÎn8¡î室wk»‹]‘ŠTØÙ˜0+RòÄËPõ¡#¬wúˆÔ¹F‰ùF¸É¥¢`|DúYa6G ¤!滣Qn¼2¥ú¿\×Õ’zùéýs±÷»ÉTËd|ùî<Bb½+ï¡ÁÔlØ®‡ìã¨"1uÑ 7¢ð4Ráyâ3pt–9Sm³*y½p³ÓƒzË—)Èj"u¸éû4­Ùr “7™o]Åú·dûjÌ[ìÚøÈ^”Ɉ|Dw”©GÄp÷¥S°‡†èõŽÖãîKÕòµGۡηWZÕH^ò¸ÌUFÃN¬-.î%—Q?Ž{ŠÄë"ÿ“?3·ïVjC‰é)mdrÔFÎw®…¡ T¹k×a^ĵI‘qÇèÆºp´KDlì»ü„{CŸ)¼ øÌ¿"Pà»t yÓC´Ï0õ)è?_G™µ¶ÎTDÁÉõ30`nš» ™ ÕW\¬[ÜÊuå å5i•é-\û,>&ÉlL1Ž4'C™~*@Ê¢4¯ÎY¦™xY9 â§ÜÙ»óáÓÖÚ ¯l'žšG݈nì´BÓËÜáÈV²ÒÇCœqúõQ]qõ¦íŠ?ÁΟËÚsFØvw”‡–r î ÓΫ~~ÄP)c ‹Òç+iD-ì¿—´yë’ø˜†Î¹ õsÃ’MF¯Á`Яe)ªžË'`ŒÄ¤Ý_%Kÿÿ^—¼I)ÆðRˆ’I—=ÿºŠœ£Â 8ÓVãŵÝEºˆ]2M5aÇßÏÓ«'ÔDy§ð»€»Å‡ÛÓ˜½…ÿ éaV|‘hXI«dµ@qBe,[¬aH³'Þ¬ùˆáj‘jQ€/WÎUÉVg1½.•î–nfé‰ßüškRÓЉ´ùàmA·t¼¦Ù#Ó™Ü̃ßDYÙÎõE£ß¼µÙŽ˜Q³ì܉¢6¹(Ƙt¤ÀÈ]NX¼‰Ë–Þ‡…T ÒÍ¥;Õ=Ê mú’€€ÖDEu€¬­úclЯáÝ—-¼P½'–5ÛO1o¿3EÒØâý¢Ÿß ðuäd‘QßqÎ2™©qüÒ¸8Åùowl]ÐÝb+KàÚs͘:k1ô;¾20þCÒrYD¼ÌÓïô>ä«Ö×±^žÜ+³/kf"q¸a"/}CÄ…H‰Ëó6jc‚·ðWV öa±ŠÁ›‡XD@3e€ÜŠš¨¦ñ“’ %Ü¢ÏÝÔ6Ý7cî?®ûèSþñÕ« çS™¨ü¤ò/¡á¼™œœõ;P°ºMP ½–^¾ XX •6×Äò‚¯ Öž©ÝnMáóÃI=[’áHÓm@}›ÿ Ôç;È>DhQ$vŸd"¾ƒš¸ü49·»Ý>#St†…HMÈôÂÕÝ}\ ©ùt›çmKÏY7ñGýþ8Ä ]¾¬krÚ–$Ó¾²Öx0\IŸÑÝíiTõ ¼­Mã·”%Ã0ÐýXìÌyc*ð ©–w>Ùß¼Y§ÓEôaÍ¥\ä,ò`Q2Ôÿ§_ó*nRR0ò2© :ˆ^-ðL«$¼­lèb\dýdÉz³ ^¡4AC ˆ7 éÇ”9+ÿ[¹Wøà.i¾tíá(Öèmß»Ìøèh¢m)΋-IIýµ^O ¿2¡D^À›?qñd ü мf‹<þ0¯ƒeÆÉ ÕàLØs3ïe"aÆÂÓD ðš²'—ßEôÓ[jÌŒ,¬Œf7¢‰ç¥]róO3ŠÏÝ]ögujE8zf½ŠNÖ倘Á‘‡ðÎ0ÛÓ¦,eìÍ•ÿgT/^ôÄ¿ióØ3‡Ç ºU•‘ò=KX0JZ¤‘ý|³GEÍ,öQiâÐëL˜³,gª‡[Ì‘o÷4‡Ó¦˜Ñ4]VKIÂg¥ÔšKïÌу¡îtÛkX°šgm^È:éí{¥ÿŽ-~‰ö,g=mÚaìÆ[:qždÞEí­ iuŸ?7eò—UºíF>Ì9ü/³còR«à& tiíùoqXR¿›Ô˺ZD›:Ìô/ðᦈUÓÈC~á»bBŒ„|¤¥KžßMž¢ˆí°Ûð%wiÄ86’›´Gô¶ü‹`w®AÁUÜ€žó¡hÕȪ†Ê. E_ãò}ÿñð×YÙæý'ž©’€€ç3@ôyRI{ñt-Ü :¬O@ÒÒE: ÙGzó…‹0V~¹?o·œÁ·Â¸o‘§bÑëLâŸpζÍËâçûô®$É¥X—ÀN“íB¦Òçˆ-l’Ø -¿mÄX)Ū«éÆs0Ï,ëZÇTCü9üJˡŌLúðUd°Îœ6ã'ÚX+ãæ%)*T¦W@þH3õƒ‰¢>6-ú§)·bÇ^bçÔ “(N#ä– †êkQ@Tm³ù½W9í»`òüèñš°\wŠ3RøÐvÞµÆzµ™:·â¼DÛbqžUÈR©-!1£â-nG&;ÀpX=æBð#rWEÚ¾þœ^d›Aô  Tl»±åoì£RZ߬O6òÃÚ«F¡8Wë³ÄuÛ}¬¬OÏxzºvìœÖÁM•ú·L#õ } W†/j_¸êKŠO"üÁZ·Ú=8øÐQ´Št~M}J^y¾îHÀ»ìÁíh7‰Ò: —ì÷¸ØEê5%fR=õÔ…«õÞ$b*vl?.àXgÆú·Ÿ;,À’#•~½Çí«àíôa#"#$§D`Šó#>J÷½Ã,©RˆÎb9úìÖù!œ!aX’ií-¿ò1|]…¬¹5ó€4»¹/FÛù†p úŸ‹°P¬"Е¸»þˆÞXùÓü¾‰rnü¿Nç}åoϮĜÎÄOUÏ!ëÇÚ^GP#ÿíKýiàô•'´ÂOK—®ÔãÖãÌî9ëÂ×bò”'Ü—ÿMa°­Ë묉*1j0¡Ô ¦žRR™îTü–RíNoÕ}™ì(ãRÛ0ylœßSÿߣñçW#G|ÁèDé/QG#Á˜¨™"®©ÐA‘ ¯-\{׺_t¨o¿LO£ASÕ‡á7ép}†®ÏßX][Xxý°È¯j (>†CöPuw5 “‹“9m’½ _¾"²‚…êLi’€€Ü/šãÔMŒŠN³S;¤äÂYÞé7䵕lç,Έ‡n¤±ƒøR:˜+Ê0.‡¢Ã2¾X–Œ–áL±ó”ûžTåýôcéyBGOnúJ°t ¬1õWd]n[­7i²pøíV{¨sEqàÌ5K\ïf~ mˆ«@m Š„;.@H’JÍÿ‘J¹w;fN>;@8^–„ÖÅ4Å!üÕöìK» NG‚lÉVšÊ„É­” ™ÒÒ; Á¶K%Œ,iÅÜFP¾G¨c·¤ŸÁ NŽŽçÔ 4’гØóH:QJï{€§ÝH4ßÃaÐÙ—_«àŽÌvü>Úû=Ãwåñ|â4ÍÔÑ VŸìy‹Þµµdj¯KÄ…þçy÷í1 =4 û±ùÞ’¾¡%77-+cB6p…SÌû#F<‹ðÕµAˆ±èº ž¢C06 3SBÆ}'IS8Aˆsì?Åg÷´Ë¤¸ÞÁ_gMÿ8Y“S®ò÷À®› ZSŠU-Øúf¨ ¸‘XÅà¡ami™ŸG€¼·Á®(£4$æ§,¤É“l’ koãÒIãê+ýëTÕëmý“+ ul/õJ®`ÛûQ,qgÐݘE±:×ÏL“ºoý¢Æe ø £9f wJ±³ ¿R•Þ‘êø:³jÏÓºè=gÒ[áf»B•‘Vþî›3 14˜È›ÉœêœStZ*ü‚sxNÂc "=€]“8Fmø%MWü#ÆÛéƒåáh¹tU X¶ªœB­¯§ÖÌ_‡bÂy•¥Ž¸o@Ý-ô#¼ž–·`¢§È„‡´Š:º~ÕM?U>qÝÓÇ©TÏOÍp›1U[4Sl!³Ì³IgVy™LæIÞË“c^,ò/ àk”iôý¼cß Øœ †s(lvR}à ‚ãA¦ ABwkþnàÁŠò(Ntn7îÅ3¿¹msí!œ2¢™òä”g#I#a‚|9 àòNP±Ê%‚LžfÛZn Ûà,Ÿm>&5b$À¤5jÛ'Y/ÿ Ñô€mó!óÚ z»Å‚*1… éÊ(«ï]é‹ í(²C5)Ýùù’€€¯é<§¶Rüó^¤—å"s€æÔV³Ëä(—h¨})?!·wâïÔ÷÷‚:²ý$@`ÍÙ•‰¨OüB8‡‚0ù TÁœ’b* fˆ'nñEÓH‘ç·w*…Cu¯£"…dQËû8ÕÇ[[Á‚²qi÷9Ž%$‰8O០¸Xù5J5sÉ‹§»é¨6$I ¹bzUâf¦mÈF…š–q|®‚ÆQ5¤ðzÐîõþŒ° 4¢ž¢ÒP¥\¨±‰°Jí<ç§Žü’C¶½x9«œ¶­Úê c!êÆÈ05©™ÁÄÛ©úä|Hã–ìF)F²‘/z8zŽ'àÿŸaƒŒÄÇX³ºÑ1ë9è[2:¤ 7¦KÞšÕµME2‰•É7öibMLPZbZù¼Ô¾¢ëY99<俯L’Þõn®²?Wí ɲlPìÍÄ?ø=œÚõgôÐÌ£Áz6®U"ïG×ôï587„|åÓ’éëÎã§r[X‚ú·$8ûÃG4‘¶Ì•/ Ð"å»Ñç©v cLÚal¨$ž%ÃbèP’C0†óØ(km,vfÙ¡Ç '&Úž±rétžyªéØÅº üŽyµ†éh3y4EQºÜ8¤<·yðÀñowìði-¹ždÁñÅöœdPwk‘?1Ú&PÒ²Và;O™-11tº/×| Gò. œqÒQæû¯„K¢0Oïžî "õÉžüßCŰ ˜ã¯ê?ƒV¹@6ÓL[œ™Ý˜é’ß@[ÚëËÿ#È~v´WÊ̓ážMÄÅÉ ©5¥œ·0xŠÑ¼~è0æÙ:0iß JÊ]kÍd)÷×ÊÈ"âáB?9%uoâ²šŠºjF Åæ¶G–ÍÉ0M@4Ëgô½VxY„Y£ï#×u+;äz¬MÙd*… ÊVII\‚lÑc&ÄÖ?>³ÎÌÃH´GzÊ_¦¿RÅŸÕÒŽ>ÓÉ›|Y|¶ÇÄ©º3Ú‹õ®e5Í`Pň¥ ï#FâòZQ›s ¿DBI‚î‡B5be'h2('à¾+6Õõ#ÓF½¥Xî*½$¯í±×¦ü)ñ‘T¦Ìõ ÂäD=ìê³%®D¾)åWNyb¶ï–îsÕ6lZõ:È P‹Þd:4ÀHGÌÙ™„ÍÏÑ ,†ƒ’€€Ój a¹þ7p2…ÚÁK ;dg.b01ªgK] þ™r_bćŽ)rÖNˆ…_IâÒ V#JWѧžs6u/÷¦ÿ>j mÓŒ#ïÎà :•á{¡ÿjw¶+qyiß–¿ïñ¶™P·.ᬔ-ÏcIV;ÂЉË"Q½±þ‰©Û2›MX]Qˆ€©2©~‚µ=ÕÞW’Æ}]¾¼ù\Š ¦T^u?µ³@Nq…éÙíO80í0GTõ!‹nI àcÐ5V_MXG&¹ƒSˆnÚª6©¹_ 8 Ýõ]ÌvçÃØCŸ…{½¯Ð›läˆcr{±ÒÂtÒÚ˜e— ó‰üè˜}ŸL¸V x`à6JÖ¬ð‚:ÁøÉ+‹YÜI’››¹óVá¿z~ó6ÏP…™²+àÓ3Õ¼æì½<ÛHã°˜Ÿ\Š0$âªM““"³mGRé;¸Yk·HUmנ؆æA £Í`ç:o•(§"ˆÄÂ6¼Ñ[Õ=?*fÓ¨"ê誱VÕhEp¤dÜ?—NÀeÌmV1‰~áßÊ~»¥Øø1ò¤–Z…Y~ÌSvº?Ž™2áÎGá!:QDÓŽÔ­Í‚ÄÓ‚ô/›x\çîVÚ}$š•ŽÍ*ùŸ!à áôWƒÏÍYÜ-hóM¨ëN¢çýKþŽ1×ô>þx°9äHm„Z»päWñuÔ–xŸáÙwÀ±´Õiµ-sÖÆ~Q3ia"Ä3PÕ Gö{]WÜŽÈ&OäÅb]Q·Npb¹›Kûµð@Çm.*gF ϼA³+ìN¾ì$`7eíÚ±hn9Õ«¢‰¾ÌÊ’¾ÄÛHmŽŸ:&þÝr:q:š['ý&ŠñÒ^™{nöØY€H}V#¦I].ybAŒQtR`¡¬`ÞVë‰x‘º\~=þÅžÖ´@k²˜cºÂ íbq¬Éd¼<ëòµeÒ`}Ñ*…ﺛhP•3rOó1¬&ê=ñÚg6xÔs—*[YšÍñòßòoû»§ 0žkÿõ:§*Õ‹Ve˜ä»Ì Ó{÷HL£:سÁc4×»/PÚæ¬[úE2¯Ycw"ëš¹Ô ïxÊÛ‹j3¤…gÖÖ6I4ý*—úåzœ=÷›C^~ú·–G°[ÃzZ—ÁB-E~Ù_]íù­-_ôBÄÃvŸé!.þ&'t¤Úróк˜Õ\ŽÿªWóöv$#¹¢® >0|G)±\µh¶´0úÎzâÐkðç 1³3ÊUë%øà]9ß‚w¿F¶³\¥¹>4d~Æ‘q@ª.[Ê9» ø0)ÈQ‰ðïõ©¿zÿݼ8$Ó,IÌÞÀ’AjFøµéüi€¶mI>Àþa‰w‰ºLÜŠ>ëûÏáééwœ™îdØ6,îö%߈¦7gÈSÄ:‘‘ó¬®J™;…Ÿ¤Ø]}¡i¡g¨-iù–KÉß”9j(]Ù ¿÷¶kºÚsx— ï)Q&ml—«¡ki²#¹?í½µ'eIùj‡/x7èîöŠÕʆ˜XÜ‚,{ sú^PEQ&ì&¡Z'û WåÆRS›ñât_—ü|_s”÷‡[J€ÖÚl¿K´÷‡ÜÍ›ðý®Bçâ±ëÒ€ Lk8!ëâdDb‡Ž¦"IÙéñÅöŒ‘WtúS·t¡|”Z3ª^°y¿2{áÑŒb¢Øz%̼ ÿ|¼Ù…àšüT aVDæ;÷‰mÒ)1_nsݾl"hÕðÔ1|Ä­+dq—@›Å~Ÿ…à5½~Œ€#³@FÕ¤ÛOÈ‘¦kGÚöh!! ¿;ïéKÖà ÌÃÓ¿t¾ìãI±®½äI/‹3t-NMJÇ×÷`VëŒä×,Uöu";pZg³¯ú–QŽÊ«® {Ï>7…ð¯n‘8¦½696U¢>¹ÐÕ^êÚ?r'Àíž$Úh‰NàÖd,»‡,™Ð_k2mløZmP!pÉañ‘„•Ó]´‚¤†¸ÖF¥[¼ÂWÓ“5о=üŠ.¬Í oÎDÛ ¼0*|.p‚:÷½S~Xz@ ÓB·¾göß{0¾MÉŽ !ãÃØÿ^™š[å¿@‡aKÖÀmÞ7”/a³AlƒƒÊÇéxxvòèÙNƒišžõÀÛG*É7’€€£>U#mæÁÍP¤€«£ØŠV~€šrQŒIJ¾/•‡Gqìxº[eÌÒé¸~æ‰çæUÁ#;&üõRBX´Ætä9æ’ØÓ ¿äÄíÄ/ýGÅ2‘•ÌH5ytÿFaûý×õn}‡?|¶CùÔ¸§3—§áè‘”æbª‡þÛCÛRk–Ò÷Ã幩3ë}­¸•w’(z¸¬[ç›Ìoã0ì£èí£ÀuŠ H¾LD4ë€ÁM¹»x6—¹Ç3t¼ß–^½Mƒ&{ˆ " Ò=?íÉßCTÓùçcÎ# ŒÔbì&`pi;Fô‡uè6„Ĭ+½ïŽ‚eõä€áÅé*ׯÒhþ Wž9Wc‡€ñO&…|™ÌÍ`Ý% `Ž $Õh) rÍú` s¾ï©ˆd×JŠß ÐÝÔ„Z! ’uf$u‹²Ë· òÇØêÝå0ÅkÀ2¹ë)<¹ ;ŒUyò—FYo–aVSNÂPÓþLám*Ä$˜¶?QJó!Dy4o&= d!ÚÇÖDý lÖX³•Vñ½Þae^€ìš7fJû6‚!¹DÂ&Ó¨z§;Þøô½J÷É?/FÂà2žõÌO©2ír ÂÃDŽ݌¢[øâ>y»nœ7Ïx}P¿¦„|?¬Y´â vßú"Ý-^n9Ú–ÑÐaÅ ¹Œá •Ð'¯pí›=i™oOoÒ™ÌAšépHÆ=)(¾1Y'‡V{CÐ/‚âV8Ô˜m¶ ®„BZ|/zkü„v­AšÀj™Íf"&f†¥ë6*‹ó:#(ÅÉz¾W²;°î@JïUnÀ²»FäÙ·ï¥2÷ãr«ñÕÇ-HØ{¾F!gj% ˆÍ¡jžÎ¹f¶Wº ñ\Ñ*}1©GZŠÉÝj’SPšjØdº˜ˆ KI–h%(¯éÆ'‡!]"dVž‘;)í1ÒtÀϹ¬$f’Ó Û`þþþ×…žÿqð;›j¡Ys›F^ê7®l@¡>Qd;e8! œæ™_:›VÃ)~ÇvÿÀÐcðVvçu|8ñm6Rí~M}É”L56¨÷.žµÏ¢Î+˜LvHG›_ïûâýd™äš´\Å#ïR³õO€`³²I¼¤‹]ņÙÝ›lêv'Jý…É 1³!¾}k !kŸAà’€€­3'm×/ §Da8¶ƒ8Êê™·–¢€ EÝêËü9îÎù¼e-& ´“®¹ÀP,ŸÍb5¡LV§4€}ckqžu=˜.Œ¬æÂ‚_]k` „“*¾/@îUÇ›äŸé°Ï ŽÀÄÁ™!m9!u?Ó›N!óv4tψ ÛÎEåZ¸v|²¼.¨,CÞ–X†P‚+Æ×¬üAÒçQ¯œ)4È¥ßÄ)Ž4½ƒz0L¿wWȽ¬%Ø‹r»«Þ8f¦àè@?)Sâôå.n›#;á™û„åÌ®¶y«ÝKÞ´ W¶)=¥¡ËQ÷ŽlKPj€µ'px GqÙkœHà§+úš.Ô%™ÅìBé%œÏb¹H<.ûãÔisI{€~£ÒutInÕ1ëêŠR{F* Më¸àdÚz¥K^ýX™Ó…YìòŸéa[mzö=éåÈýÏK×ýzxâü–J×±­ãëQ%¤G$w#tóefÒ„á¬BŠ`.ôe0¸´]¡ûÛr—a¨ÜõøÕ´§Üé½;*µ`v§xÊç–2ì_yuÜ„ìäŒWÁý/ß³èo;µ1ë^ê ¦LÏ£Ñ{o ŠÿœPx//÷pý»úL,éiÂÛǦùãéââ„2_B_§¶ g`y¸ëñ©Œeä–ÃM«ªP°:òÍ1º¼°g´¸~‘bÒ¹)|0 ¸L¹: Æ® ýbäX¥ûV¾J+Húá¬À<„d©0©ó> ¬6¥®Hõ[Q¡Š‡¡pà·ñ›ÙßCÀnY´« Z![½1óÓ)‹*$ndOd¸âé×Èët.ŸÂŠeÂȧ3HÑ0!çw]X†3¿Ø¡Ï›ÁA¼8¯Þ±]ê#„;Ì5“>Åõ2§®-,âd*?ûÚ#ÿæ ªôâêÈüZ!÷+l«H ÛŸ³+Rµ°Ú°¦§þêÜï€^íÐQ~od³í‡Ìî€Ûž™;ÑwÈzÔnSd×*,Ö×Tß·[¹ …QÒ©ÌIXBRœø®Ó,;¬ˆQ”¸d¯¸Ë†+r?ô¢•l7þ${eëóMÚ¦¹ƒF»õ˜WëÓáªÕ~âo±u$^Òä²1‹d>]º#*Lr‰ÊaËYÓX_k,aå£á…çÉÃâ!a§ä}³áðt€õqx͆2 ac1Ê óà‹{¨®N£OTûÿH› ¸æç¿0T4èÐ.3 &‡{2ì IæIÚöšÕNaÊ_ ù-ÕÎ såz*¸ugÜ<°„igš±!¡ø›1˜E蹨ûÖ­j»Oì4­çß?‚BǽÏ*x¨€åó,#o9qCÞOjªâûÿÅ÷Â=!†Y9gg’½«W ^.ôV"é÷r)âj‡}}ÚÛN¿|cv_–Êï>ÌÏÌÅÌTé¥sumo®KŒ™–Ÿó‚® Ìò¹ ¼ù­*ÍiXÞs„Ò‰ˆÓS2øýÿ™=ÁN#v‚øÿ.yÜ 'Ì*À©×û9Â5US…Wžè+$-qIÔŒx‹î¶÷|…k2ì âì`×äøôXáýTQEè×eá[e7:P$ïö:hŸM³EÈÞá-$[ øÑêÎðh8Mü?øÑ×Lc™Î€d ]’€€¿&v#0¥^Çhú\¾ñçñð&u­;DÞЧEµÄcÛKRgwgÎ3÷NÕÐpã9!Rp5„çhÄUxYÞÄ#{´1¬v#lƒ ]xOÔѼü 9”Î@P=ÒâX²äŸ XÞÜã^½ÈÉðt_®€L¢]ß`Q™Ñ盡Žgt¹/vú%©ÔD¾Œàw¤±%‘Å¢—ä"›m:¹ÒŒ †89M´>ž¼r¤’.±\P#Æ¢%O %ç[ìE½ кK8(“k@dV5cŒÓtë’tüÒUã Ѓˆ-~3[.`L@¤´ôÏc À6Y¥[ =˜ DÞ°=O!Ø[þ ùÔÔ ”Q—|ëß/ŸåB/K<Ãø5YÄa©¿úžw¯»í¼Êin=&©ímåbH\\“¥6TI}u~4%8ÎÆù@(LçtáV\ÞcfUWaµùCD§{™q Ý©iu§ÊFwÇjn¢yöL;zñu­Tß®ì(`¦?&C{öd; gX®Ü®A‰Kjò™†MÇr\VPÌ[ú;ŽDw{OK=‡ðÁYHU!z —hòÆNÇAìèKPÃ67e¥bÃ?&ÙnT6ëseÚ–1Ô€¶"Ö›äŒï¾w‘|ålX–|³Ðï(CXkuŠžçÆGM¿Ý1¯¿®åÌéNóú€‹×bÔ«A„ûžåˆ/ñžf8CŸƒÂvÆúVÎÖð¦Ð¹%ÂV;b­oªGâLe]_sÔråÓÏ~¿‡ÕÏv¯Œk ¥`Ïå=O—uœ¯§ ¶¸š±4O«~d2ÄÓD¨ÀH¡ZD—z¨¨½œ… …ÿšçÝIuWÚ¿k SÆÌbN‘tÖFLO£ÔWºøE[]„î»GÑ"T³T­Ì¡Ï;ô |çÄg¬¢ª ¬j£×êå]‘;wԤƼqý×¼m/ $Û~5{Õ…j]î¹O"‚aÕ±_Ï c{BÁ%¦Vºxã½|€{;|]­*Ÿ•ßÜUcÔ‡ò@}>BŸ\4:\EtK†°ÔHô,„ÇŸ³ ÔFîÚÕ)IÜMOÉO¨ wª—¿ÅÆðÙ‹o7âyâbdÙOå¯ѽZzÈ/;;¬W‡W}]]ýcZaÅ8Mu––í R¨>€YSåÜrÆ¡z~¤’€€»dÅâøy] $–:™­à*zØÒd--HüuQo`Çõ,0Ò>ø¶4Ü8ºÐ.ã£$‰ÊpÊþ0åˆ"¿ù”|é'S¼~©ê±Äø/¢÷ÍÃÀ‡;o¢··sídð”1}¶´Š}T+­/ÂtU`oíQeчî³ÎZÐïwÛµ03Õïöó°?¯JèÎ:²ôÁ¢šXwÉ»Þ4—ÈÈbe¶ý¦hƒ3 F­{~º/Ia“ì¼vô$Bf¾ns}Þ%ipüéQÚ|kÅ3aÅl;Á÷d®ÉXÈ–vö¦€_k²ƒ^ŸrÑd’ƒ$->ážV}óå™™WŠ… N[9è‡ò˜©Æj’ß3ËÊ{hËê&-Œí. ¢ÕÒ´^ÆuKy¥‚ÊÙoKj~êx¼i?û_4úÅT]9z´—^OÎPq§ä!¶a9-ŬL)Jÿ?ühCX`Fb Æü"y¨Lˆv7óB*€•ã•%ý*œöxºöcÖl÷Æ­n#É 1’n'ûÂZ t“ÈB-7×·œ_z·>˜õü±Ö©Á÷g“e[ü,kã\3²eít•³pàésý&ï C„3kv5¹fòå6<`1ÔÞ->‘E‚c·‘Ÿç_üæ°reMDG\hS™ä-È앜ægH‡í•ÇÛýŠš¤ºöåU5$;C¤Ð+WbC‹èÉ=ÐI¯¨Ã¶³ú׊¬áA@ NÖÝð(}+ÌÍ"íÓC¼hëêH‰Nö„=»ƒÈ1ˆ Ä8Øp -édÞp°¸0hÊ&¢§@4Q—×Döt ”!ä Ü’9Ù7óÉëª È 5-îq7æÈ§‚¯ãˆ\yJ,à}ÜÐýÞØ~ ÝÑÚ ¿›èÛœ¨‹zãé ø..ô)uˆòЬë__cíkÃÊÐäÜXgnÓQ¸öB”Þ³.q9€VÂ7;èýÄc`ùªÑ¸GÒ±³¾FZwÆÛq,ôé½:^ln ‰§lVƒ¥àý1›ÿÙcÉ ó"úü j!,Z TÒÛ‹p?"ÑÏ©—jCN M–áLö€ H5C%ñºY7 ò•°œ:Î@{<@‘¿y¢ÔÀÁô÷Ld*BuIžY¶…| XÕÁ;›`€>¤±qaØ:µÙëNæm¹à× §Þ¹Ãëœ{v2¤ÞæûH–¡zYäîœÓ‹sFm+ª&ÉQ*H ‡Z䑨IóÃWs­‹1/v{‰•ÎÓ+_ëØ`&åµ€™ûÉ«ú –õYËþW5ùŠŒÉùtÊAÝý+ü]~ç™M­¸/Ç" ÷Qfˆf z ¥â3¡ÿà°sc£µî…-$¼ß¦gñ U÷]}©p¥¶(- XÏ:v²N{'˜Ó¯‹¥î¥ gþÈùx$ÄuNîãÍ'Ãul#õ4Qpç~g ýJ±ëb£vhg¿‚~6o]yW(ûéXªç½¼à@Ïòdu.ÎΚiÔqä…•©Ô/wßFLH.Ô±åŸ.—lH[Š4º®ËpwÒ­Ïc¸å‡ *o£FÕØ²ëCQaÛò-¶H"±Œ8ÃÔnC\Ãâ̹‰|Ðççh¶ŸÂãˆîÇŽc‚*šbÆ›óÝÜŸG| 3âöß«^ZØ{£Ò§$sÊÚhûV‹iuº°_#Ld[è¤O C“*»÷8UÑÔwf³2¾÷O㇅µ=ö€j4Ø·\ñ²wË^‘Â:¨fÅí7ÌÙ\ôìËÈá¤ð/‘ìÕDàl»UvI6|<öÀç¡'­(kˆÇ¾,<ÜÃE¡â—»¬ÂûûçÑbô3;z^ÝéO 3ÅijòY϶’€€Äé9½ªáTXU뱉åcjí$áxñF*¼@£‰q?›iŽšBª°6•÷OuîŠo:Ër"]Z$p/Þ0æ~”Αa²úŠ5Úí £xDeWÈÜŒD¯^Jø`Î.ÊCGí±ÒÁu4žE?iá…4æw6< Ÿ¬Ô}µdÆ„é]ÓyK»kÕEÅeCâ›É? ^žÂb#Ë^”§ô.Mö Ú7µ$*à ±"JaÒý:“šI%cÙ· ¿iÜ- ö2¾* V\UÖH«qGê”þõ¾qI m$‘¸byZ(Î^ôAš“ö¾ÐdóèVæéÎ3åUï‘^öz£¡Zتã~Aÿ©ûŒ’(ÉÌá Ñë?ŽÃ×)0¤OƒŽ :b.ÌÍDŸ¹Ó?·ýÑ/ÍÊgú iÍÊÆ‚ãºU@ˆ‡o“éîŽÙXI²'…sˆâ}|É0S?¾^ܦ¿S7Z£ûíi”¡¯ÄELçm0`RÌbÜC‚9d¡!¥Ê\9ã¢Y¤öpÈxô›i”?ˆ–?é^”¾£2ÄQ.ƒƒfa鳂û¬埵ùOl´·bâkiQ³Uœíèãœï‘žêó¥o™Žld7ÿð~Šy*68Á< H1ù%æÒz,q((~Öˆ\K“A}¹Xàã»Qè²Ru®†5”h-YðÔM3o强(¸6Qv¤ ûªQ¥ '»5.mÃÐkRƒ¿·}|£k]ÚvÛ*^΃ÜZ8¾¯¬÷o¹©••õïú ª §áE K⫊…´6'tYX®SÄB‚³;SÜøg­¦™ÖÒÌ¥ñ&¶0ôÆØ¡vÕÆ‹ÖB4YÇáè’Í\ßÁ¸ž*.Áš4VdÏ“µäçx£å²* š±œû=+ öÚùDtùÆÜ•¦™¾9ú t³Ä ÊNOá?Ü1'ÖäPÐjÔhùl`XX³ª¿i7©‚½ƒA9ìOø‰QeØQ;gй]86‡« w¹ïñ(ÿ_‚·3%ác+Ä>4ÊØ{´FAð¯\,|E(ὤ_ß*éš-ï•7füMwø±s‹ÔG)°8vº=16Ýo)îÇÚà,k+kQ-ת<`\ö.»vBßó‘,ƒ ËòcKŸ38Äû¼ÿ’€€¶D©É“ƒ¯¢K©ewU¶l•úƒìåtŒ×²Ä%Lï6ÏðŠÝ2oí†móRlóÔ’?ad€ËôÁÖfr3 ô\ó¸!èϲö4»—ÈDh½ýõ>DªX½–f®ï‡òE,Êß´$«Ï–y·p(»#3ZÇĨÚú¯³ƒ$èÌX+ΜÞ†ærËÙÅ¢LìD'¾Þ'˜äç¾A?¯µªÓ>w!Ü6áeH=CœüüþWrãU³å”–›³£#tø 'ÇIóæÖ/s̚ɭvB©ÙúÖ?îøâ‹›Œ¸Ù:Càûuêé85 MŸ¶z)à¡êH L¬ ¦Œe©\U‡6OùÝÕÆø¶Ó²’¯8”Y|=¤ŸÁÞä&ïþ2ÀÙ¹J(z›$.<ãA kÞû[‰ŸVÅÿýCųx„ŽÜW0üƒ#·®Š‹áV“³¡ÞcºÒ;fY̯Ó,Yšc\w‘(wIFk719ÐFà°Œþ¶À—JÇcý}#Œ.Äî×µp1˜†CëuŸ4ri/]5󻋾çý·ÝÇv±i%üuÁ£Ÿ^ìIƒ¿–gØCò‹sÆ([Pfǯžå@']:ÇÅβ(( Ùâ^¦ d )à)Câßúq\H¡Í¡8E6O_?íLÉ‚†Õ qt›aì°?X p÷Ú_õ¤EËý$z“jéË•ŒÉèßÃ`3ÉÿØ&ñ¼„÷ІÎÛË\ʼßМ+Ä&a`‘öqÁ£]Æíyõ ¿E1F?.5æ¦!B»%9Ô‰< \f ‘ÙŒ¤‰„á"Èp°Ë~ÊÇøg5^ó·¿òúÅVEÄò¡ñ~w+²X~Ê/kâ~6°æ rÙÎÏ¢ZÔ1ùëR« Æð5¿q¹£ÀÁ_E4ç ‘lCA®xi®‰,2ðU×Á\ŽZFWtwVˆÅÊk¶Î¼¨*±Å<{¯áé# ‚bÒ¬÷[ÏPœÊ<Î"HŽ€mirÿACìüO¡s-È5ŸÐøÜ½ˆ mÈÁj %‘3o¹ÚsÀͽ}[ƒ(òVO"1MëAâ`‹5¹’‘Óˆ•<øq>Šëֆ© Ó[Ëù{äÒø,ÿ4.=¨o­Òƒ¶Å9¦!:‹ŒçB)¨Öâvq²ß¢Ï@ÉÎ}Å0ÊŒ}ïHuæˆC’€€Î9cwŸš%ÚòÛæ›åž…ß9˜@Ö )I]'s¾+„&Þø{"ï_”’Že Ús$[÷’Û?»L¦^%Ùæ&ä½®´+ÊT [æ!O,”aÈOèNSÆu=I¾Tš?‰ï=€Æ¶0°ñ—¤´ˆÍG ¿ã5Jz6nL b!éæâ@TN1à‹§²Êûò‘(¢rºSÍA‹Í'Ìü:‘ä¯Èá‘O:/ó;Ïȃy½¸Ówú”ŸË?̱ÑÛ Š`ºÝ8 }îçêkÛfÅ*Uû‰³"íã½öE°l:YÅ éºî¼ï@&3=s­(m²(°DƘ0¦¡×ýð=[“”Vª8Å;ÊëŸ"G&½B%1ÎÙQ½/m‹ Ùz­-+‡ê¥þÕæm>HŽr½nóÇUlK«¸LBd±¯5à‡Ì“`5·g¯E›BËËümÎÚBA :«>œ#T¡ýi ,Ñ [b²UüSðÚAFÇ­œâbãèe:¡xÅ^1R!DP\³Ó#w× ó‘qøq‚åýôy±ÿDAær(§þ{!¶’Ñ6ë-øL´ÿgʰ”*ú¶£g·úTK‰ð… EPv¼£Š]H]`ìXìoþà2LJ¤Î¢€r)»¦Yƒ“Sÿ žéTºÊåÂä±\ÚµN–XéNi )w»³=¯¥ S»©03`ÚVRA?ðQ’s³³ƒì@Wܵǎƒç;¬©9»Žè±bÐ(µÓ™ä‹bLŸë¿÷ÄX ÿ*„1ΠÁÛî\§Ÿ/â1øéÌ K³:×G ò£Îîn¾{b?¤#Q ã“â©-*•ñÕ­‘þ`Œ§[šMËÚõ5KB“ :VÃØ`¹ýq”˜ÅiÕ£€;{y¨Ósz…£ßÖ1+€vªvwÏœ×,å©Þ¢Ü»‘ÚiÄ ¹ <:~iv–oà­M“‘J$Q¦˜2`3|Ük9¯BºÒ$fì•óÔh.xÊCA²‹øïnÜk²K„ÐÛ¶øŸ£ cÁIà¡áë@(Îàsˆ§V—qSÝòÅ'Þ|Mö.ŒiÆàªy»|ntmÖùW¥BXJÒsKó‚ ƒãür’øã[@_P&p¼Ìˆ”Lˆ”Î’ñÆû»ã.ð’€€£Á'ƒvD†,ë`ê[áððÍlMÙBx¿ @w »Äœ_]ˆ¢vaÅ®S kØtø%ùR0NN[Eljq.0°š¨D[pçd~\×dŒ“¤vÿÏówéwmϧ˜on5;(ö…”1Œrœb],C,å¿i÷Èd—Kž§ø8 žDyv÷Ðg¯Ù7¡j<ÓEÕj¾#©N W¦QàæÂC»” <‚–d\½ª4í6+G-Êé®·iv­ÒË@²]™Ýl¶ôÃ7Ô’°bÃ@»¡f ¢{Ñ©ýo{ºåŽÎ¨Ppʨ>R8@·¼v#5¼:BFè=øØ™ÁbBq {üHA2¡í«¬iZXͼ-—cÍ-²ÁA¯8vR¯“ CÝsNWSãð¥ŠNE/# @C*Gœð‘hþr8éXDè¹fêf¬B÷ smÖ®1:_``Lý[ã0&ëÇ1yþæYî=‹.¨èzXÌ”ón{œéW)¼*…hÞ?C-©û’4»¼:-Õ¸~=®ÓÝh šñ±ð¾XšrD–x`"‘‹·:ŠÖ™˜#èLýy¼£Ç« NkŒ–̯NŸVâ`õy`û2ܵm[,²\CÚÃÖ}ó-añ×ö³=øëÊ ZH2 :Á’‰ˆ ¥ØÙµFÌ´ÞA4󈣟®µNŸÄíéR–0) n‹=ËŒÞõ£ñ©¸‹iL/¼¯8 £Ü-ÔûªG8£.³†c2G'èºÔ7ÚºõÆhÙ>$kó^š å·£N ûñ¹½_e°CÚ1_Ⱦs ©@õR%'¢B2KIï‡kóûPÝVßtãQ€/6d$úî%Áè0SéqÙ©æÄkw¸5:OÕŒ³í©MñÊ%›NØö¸,ä_~ûÎêCÏ -*Ååú‡„ò€†Ç¡r‡ºÝ>×xÌÙûÄ5h6ícÑ^ …P¿AÆæ—îpf: ­zV?{”D~!ÄûÇeiýqU'ÌF4@x¾«™|×y€Ãl=;Êú d¹7Ç¢Á÷`a±:ÒÆwJÚ{;QjX¢w;5(‡<ôšŠÌ÷«úÀ·Ú´œ ¾’ðxÚjiçáÌ'U4¾d\}ËKÚ•’€€¾]ŽÜÀ.d¥‚ÕÝba¬öS. €±ÚTÒÁ5\û¬LŸšîÂ_%x•¥²:e?‹Ã™Ø¦gùÄHüÜÜïÕÔñì6ô—„ã±)ß2Ä먭/`^Á MD.ÁÉháɧ÷v#„j´]«ÒÄ)GÕD]FkQ× ] 6–3YóôÜ<2—…t}È‘ ½{ª…ΤuÈFŒ}I\*6Þz°4£'_‰Û"Ð\Ý©žåz~ä!"‚a_Ùlp¥2F…Œ§ú6;”ØIÂáçS¬cDâRo+£78†ž_+òèá×®vØíãW˜ó/ϳuʧ/ö¸C_Ÿ.C×Aî¼µÂPjª…Ÿ-¦yeÛ”ðõx­e‹´»ƒm™¿Ôb_Bìz1Séç¦á^¬ðK¦3)#2R´òuïïi~f¿•¿|s|eÏ<Œè‘˜÷Ÿ‹†þ˜IÅ= zRT¦êR÷pb¡Å(Ã+ü_’wÃ×äpï~w_-^Ù2.üUÝæ}mƒ2ô«~R˜—…}N`ïÄÞ׊ŸHÊ?:ýò]"œ+A?)G›:¶1èB‡UžIÏòUÑÿÖJ²XraQè»øÃ½E5§Öv4bEð.2üʾHdÛíÂÚ©šDî¬?§ô“ ÎY†2uW¶ ¦„{ƒÑ™¼—›k|ä'x›šKœ `ɘúž·ˆ3Å^ãûøŠ Ú•ÝÁbÛ†6Mº= "™IPL˜¼ÁGÇœEÛonŠÂ+Ö§21/‚oû—ÊDìë÷ÚÕÈןÜn#Z—«ü¯£òŒóL>)8†™W¯f–åɶ֣<Ò£-‹ _ÏÇûêôöÃÊYð±êrŽ3eä(@:EåûïIyñ£=“"s+h~;ùX"^[µì‡ätú7°‚Q /Å•,<ìW Â.‘2ṂÖÄ‚¬Â$ô¼©ígªäuT×R*ÞH¹½¤ ûK¸ñ#"ÁÅdféÃGLMGIÑPðÍ…Œ–ß´ÛÑë;xt(ÄrZŸ>óÕÎõ{,xÖ2…¥zg·ìÏ“ü‘•^ÇsÎ_«œ®_f¸^TÚ‚[‘倖Ø-³èïшm¡ÎvúÌ#´Ã÷bQª×ÝbÆã8¥Q2úŒÉ?¼tȸ|§Ëée¾ÏöèË3}P;Fl®, éöÅCL-+r <žQ™¥€Ë5·õ ¶¦Bm È]Mx*­ö—gÕG+÷04ï¶ÎóÝ·¯E…ýÅx $s8ô‡h—f¤é”.¯Wj£+m¨@%ª¯" m BL§Æ{ï4YÖNÆrüII‹aÁ¿Úmî& PY2èTížEÎÖðñ.p­À¦0vÅî€=2¹ßl~­üi©¢Æè-ÒTºšáa«üÐØãšM+Øl"€ÈÈÃc5š\»ÿ²›ÍM¸¹öŒš36-t)ÛB–ø”«;+¡†(®hq–• a—’nÖ1 25¹¸8zHä‚¶˜}¼g9>‰€íâ h¯P‡ ŠÝ†™w<ž+DÝ$ëóë|à'nóê¸åҒưmøsüÃQïÈ%W9YãŒÛùw[ iG1ùš(hUM? –TëÈFÇXVòB¡4M/â¶9JS4RçÐdMµ y…—ZÒvä`¦ >ªu±Ûàñˆži\ÔL—–ªT_îðùÔ’eG~«+³¼—Ù^ÚsÀÙ3ÎÊ>Â,ØÇžÂœ2_äÖèNU~ËÏJþ×ÓþA=›Ýmmºö® Šn ü´Árõ>jr{6ˆ’&Kê¯""äjžìs!eŸ‘õ¡dv]–Z<$vÞ¼~²¨•Sÿ”]Ë ¶¢dŸé^Á…i®¤¨ñOª¹½;¢ˆYŸmrk5VeáÛv§Óîòf5#«9GC êò˜'=ãSb·>ü.Ol kY=QˆqL&mÙ¹#¯…›SÄ2 øAO£ÁhFGûøÃ'>íÕ%éFFÊ-_''‡NÄê‹LCÛòg<è²dA~ÞòÈPµK°é7–¯Éñç’€€²(©Wäé¦g¹•™iÍÇ¢ž¹?üxJIãA,?¤ê¾±í.£ÛZ!ºdOõ¥”WL=Á·þÅ&à"nÂ:†,uŠÃŠYaϯúÖ„üÖø›~¸%Gé÷†’°g0ׄM6½Œ_éÌÂÛ ,× ˜êK.I–ÜJû‘©Y篗ØûK[’UpgIŽÜW“&HoªâosmØùçG÷üt½'ù#¬§~¢”SámMÖ5Ùò0V‰yÊ=¤Ö3¹ñÅ$`…Ãó`y‡ß)j¸…èT÷{NÝV§ÂZ¹d¼ËÞȽ¹íñcg,=“ªd™Ï%G>fgUiµ¦q«[TàÃq–Ž>K‚žIÌ¢@7Ïr2ë7soëS\P$E´!žŽÿr;•Ò£ý&Šu`Ê‹€;@…uÈô>M:ßaç ÷<à-‘U_„€|mêkd7æ¬ïïž6xÑ^­ˆSPÂIx Á7%öÆ B‡”ŠÀÞ¶˜ÕU±½‰žlé¶!¯lÖ×FW†$xC Vê×ÚØýâ€ÁàP?’0T:ŠpOûÚ)óƒsFb–/gE>ÊK:œ …ÞÑR›)ëõ‰¬è^òJ‡¡Œâ8 ŠEÀ€/­À•ž¯aR©4µÚ@ë;1zòjKYÆ–Fγ™ÀÛD†ú))Ê óo¾ò£Õ‹x2KU7>sãÀÚð‹Kk~˜‰g?¸f£ûÖd­Í㣨ÓtS¿R­ä n{y®3OÝa½ØÖs‰Á21¨“OvÁ>FùkîCï±þZË¿Ì\¤¡`z'sżùû¡Ô*ìT*sÉ’RuW¥Õ C—.àç»9m¦ß2Óp†ÁÿÍèùgZã´‹„8ÿžBµÈûæFß„ð½õiÞ±M)FëZg½]pÒz7š›n4qb%ZFÃVP?ÙBœPÒ›FX2Ï9º¤³›B‡"» Ž% ÄÙR'•kJbäÚõq|7ÄêÐÓ¬N¯Ï-òwãë%í<¿EáW÷Ë3ë]ÀM°î5ÃÇ¢“˜š§2!©#qjäµÙ›x¹=å+ŠP'ˆ+P´ š’€€¶èˆqõÏÔä`ó¼&^Ÿ¢{";ËðêÞej‚LzE¹_{\gšÐ&·1ÎÍHû¥€Sq1Ê]ã{4=÷ÉŒ%K—xøòö<ßá|¦ÏE±—²Ñµšˆ¯ýºB;ª>FÐK[ä°:y‚”Ál’Û.ð°ÊhÆæ/xKcx—ñ´õ‘o зÎq ‘¹£tõ^-ŽòVº¢;µËÅÒi8t%¸g·ìmàsfD†¥WœÀa+lÁmŠˆ&îMhiž£ß?ª­…q Ô%I§þÝZ‘üz˜Ÿ±YÑ*ÝÍÂA Ð Z«3¸±µ'Å[ñ’î'  ;¤÷'t +!@ý¤–_+¶ö‚7,ÌZ»Á†zl6q­öcU+oóûú«Näç†Uëp<½c$Æè=ŠLΗ Ÿÿúª,YIÚËvý°ÝûHVC&%f·v°^0#°ˆUñlÝà#ì"p*|<#¥uª9FV¥gd‘ÌŠr¿ø^¥yæü›·û{£…°°$ó8Ûá½çµFŽridÕUxS·OhÒé^•;PGÜSJ: Ö”/¢ö[²e2.[q’’Õ±÷O,XŠ&Ù£Þ>“Çe‰÷ǶÙÉOSÂ=K3§¥ÕE{& U±Š`Œv?•±ï9=×*dßöœ©;³äœYKh« 'Vw…–dVêîÕ~ã‡Åµ{ÇMÆm%ô´Šú—é‹Qa>šÈGlžÇ¢’a\ªË7<¾±šÿ˜h[®åì~€é?NëŠ8ÛRˆ`Ô%ÒÎŒ-΂£ŸxD Ð7¾È‘6RáVûM.ö¡¦MüDÐA™Ýΰ¹ÒŸQfbô¸IåP“èSÆ ßÒòåzÄPŒT\CpAz|*ûy—Q^p¾ ÄWÌÏ>KŒ1'wìL1ÇŽpA‚Z Aye™1n b‡6h º®ÕÚ¡”u·§à¨½sÝîØº’?3@™;˜£Ò”ó°0ée L¥!+w“­ š[Ò¸‹¦>˜góÙ²IH…„ñ[çÐÅúh?‰É£¬,Ñ‹†´­qƒbÝ‚ž¼®2JYqËÙj¨ú_–Ð"fÉ΂³B$u€¦d2o²ºÜæ²¥#Þ¾ëpÙÌjŒœ íVkΊ’€€²öá.h¯à–ôó y&x…P–•ÃõÓr3<ó'þÜ™ g¾¤X¡[KÄýŽì¸Õ–™mõµz •tn{)VðúÌ9½K…¢í¹öBtqÆB”?¯œÐhm‰"Ð"0VR=|wÄ22 UD§fM¼`·ÿ¹,‚ “+³ùŒ‰Ü:œÿ4,hþÚj;ùÄÇp´Ô78”î§r®O‡k®) “šn]ŽcXB âJ$Hl\ ñ[ð)åæÈ"ÚÎèÍUWLk‰JÓýöbÉßË®´ìÙ#Ø^n‰Åf¡U|:"»ÅdC™¶E½\ÿC†óÏ+9zÿTZRÌ› Zn;nþè1vâ¾GÚ<ÝA;ç äy03¿ÇLÿ{'*œ¨PzäúO£1ý¦ñÊÇUõ~'’áíÀ¾H§.'­/U(ipi>,¢ÜMqŒÖfDý[7² æìaG1fí³Gp[á$žGÑ"öšÔ62ë/r®?ú–µ®­‰¶Æ_¦å »!-Àr(+$|1°ÊUhE}®ÙÐÆ†–”ïéØÊ~Ÿ9—Ä<:èx4X³xÁnÔ¬*sVtÃydÁ¶|·#܄ލÀ[-¬2WJšlQÈâà 2K´£•¬L¢oÌa#¢“IÉ¥‰Œ¯Ú&«4úß_O‡ lvÍ©’¿ýì„I}du69å°¡±ϸÄ6€½Cé·7–¹(”Â\ ¬ÏupOØ—c¯§ó.ÀØ&¹¸ÛÔø»ÏŽ’P´ã`.R¤±0¼Åàþ síßÓÆg¿ÎCÃ'IE3ešù›bfîΓÇäÔtŒ¡|°»â°4Ðk¡hV­;“Aæ×p@0?p¹Ã'§I¨-€e3HŸaÎÝLà¡MÇzá„ØHÚë‡t©ƒÝ~}ÔÒ†u¥÷j|~–â:²Z›3Y…¾ùP6¿r™³bݑۋǹAïÁâƒkР µ¾Ûvþ¯y<Ò Z"b„¶•”fÎø±žÕŽ•Äú/““õ 6 Fǽo„ £ÃO¬’€€¾Pƒ`Ö ìsjÚ"˜ªî¼q¸×Bw®Š©ȉ{üdYb„Ï?Ø^t&§ß“J}¢Ó*Íæ#ÉjV/HÈXsNº[O3†Þá—°³3øÐ2¾²ˆWmý‹ƒåÙ«z Eð¬9„±P‹ÜÜ&¹U&룘x;MYHÐ7•Î7Û à^Âz|âo½]Ø‘RØÜua`îâÀ›ºLØÿ‡ÇÉ36Û@o—&ãƒ^v|€2KÂRø×ÜOÖ>â8ŽŒDv€&ë³ÏŒ@ ÷¡ýÚ‡´- ¹œ*kfžmµã®hyaÏ2 ”ìu0qظ”¤°âí™ú$f˜!'¼B–ÒC™‘íéñÖÛÖFViBöß7ò‰¨FÂÌÛ^h^(‚y1#©²ÁU¦>ˆ&^Í꼸´w~kA[A âåÃÞá.ˆÊלš+ah†ÿé¦aYÝ%GÛòÏ"7ùz,&¯šè|Rù.áv²ô*+%¹ ×ÕQ+JyM.óðjDz›¼*ÅIù?kaöhßãýú—$‹ê±]›K™\p3©sAl¸~°'e>‘$£<"õªs=D48KºÜ+†cÐ[ñþ(ë ãWÉÀ,ÓDM€U_'ÙÀÜ þ#C0Ìó¥v¿±ØV­1þ(<—î° ’1àk7ñ½_dyÝmyñÇ8«ÌÞ•Ö®&×;W+ÿ~‘Ö r®«ãäÚòŒ9B™ÕìÌÐ>XÅ÷Ûí¨Š—ÿ¯%PÜk,™Ð3‹ËiÞkâþ`bn¾ ÌŒÈÊÁWô¢¡Ü7ÄÏaN/pf E ŽyK‰Df*³¬F5èjå¬×0±ãZ\i‰3è%;QRqhoß&ŸPü(ä–A‰Y]\LÒĶßýc1*óT½¬Æù¾7µ³çUŸÕ«¹ûU"aË-o>q¹"€’€€òÏ´/ØÓÒM1­ê'ÔsvVu£Wš ´Á®ÒÇ™ºÇà'¿V,JdÀlq];J]¼ûÑ")lUi¬M@´ùF­4 ¿9Ås¾ÓŒ¸Á8sa]x L [E=ضÝÂ×á´JæjÖ?$-c/-ó/‡¡Ç›ƒ²£¯ÙçêŽ÷AÏUQÉÁö]ÑM åHÒôÁô¢ƒÄg]Î<´éœh>}JØoõ‚‡2(Qï€Æ*û0(µæž ª=Sc*zD‰†¨ªÕ¥ÌH¦ÝH剰ôhѳX\ö®;òCý}ï¸å%Ìtu/K-à¬:S>a}WëMÅ#¡{e¸,Éä½foéÎ ¥ŠLò *Èç³q‡Jß$*¨SH‡§Îxó°Cg­ÑTQÝX£á~…®ö{ð¤Þ|a—`zêõޤþÝ™[®v ÀG¦‰PÒµþÀ™Û"|²“)àæ¦BDFÉR-5jo•œ»ÞöÒ5.‡©y D9pzʽ{ÛPN?u¨4 +V2k±7øîX†çðxµæåhÚ“E R…Õøüƒõjýï]}Þ«Ð<•R•²ÌRý~àyA-t‹÷¼]sJ LÖw /èÀ…óÿnêäYM©–¢>ºÂ‚Òh%.†ÉzÃÁ yȵ-uOP×_>´Ñ­N3·‚lɽÆU^wëÏòBäšâ÷e>s˜xtŸ‚;Êå,SÚø‚‹à¢á“ çKIg £ö‰ÌyÔŒçØJúXÝi,ô(T‹oÇÃüòº Vœ_Ê ˜ó¶Äâ$ìeœ>mÜXR|Û3»ƒ:„Ì…‹ß¼Ÿ&1éÊÃAV½ÆÍá·Ä{oÔ©€â¦b8/þj.†Ÿ:”•Åœèìo@cHHÁ¨1s€ÉëJÈ Þc:Rª+\ãN¼+†@Lg =¨²”†r_­•àÀyù/çK·ÀN7"7­’€€Ó1{'eì">VzS©KÕT½¶T}¿‚%:ЦšºK2Lru“äÙíÎG2žÙ<Ã)Ð5þ‰%ô9,?ó9ÑÛY‡ 9ÆÈв§õ'r‚Z Ka™m@âð6žæzÌ‚ÆüHu;…U’b™‹ýþ&ž¤sËС¬ÒûazŒ \vûp묫«U±+Nt÷‚¢óªLÀ5dÖ9Ãô”9eŸš@}|’@UY%ˆâé4-¬õ÷ºxÑ%»^ ‘õ¨ü.…^¡„WnúÞt´®³‡I°šîAz†jÐÈ{=£òÂÞÑ7ÍùAcȽÔË/ži+ÁWç´–5‰I?IH ò=­OçÞ‚r)l¥j{ý+,÷WÙ=\ýC°ä¾XO•þ^R!ëD(ê*Þ‘ÓCÑö¯ „¼?Š•ŽñÉ?š$vJTlÓ¦z¢ eL& ¬¢ûò{" zÛŽuÈ\31Q‰$S™,xd\®¨Ø ÷]T7÷­ˆU”t¦<"{7ýÔ%tÄßlÜH³OÛ•|•TÇ×ÌȬñ„¢;QU€ÿ™ûûñ|ÞÅWú·}rkçñ»Ï½›N`p5ÖtÃÇ\ÉT›iÿ5(Yl×ò<óº_â.ûÑzLóNX¢À•ÖÕìXú|ž-\çÄ’âÙVÁ0K ŸêÜfKÕ­¦¼¿·¢µƒ'¿;€17Ã\mÆAçòSeg}¾ÚÁV¬ñµ¿L¤+µ—âÃïÕdÔÇé¼MüÜw¿qTŠÔ‰kXç0³„EàºÇ$ÐXBêb}ä‡Yq-6D¸5¨qˆÌªo CÉÒ°^‚Èá«ÑjÚ‹Ü=¾”ƒü°(óŽÙhL:¤GØCO ¯YùPfÎS:J÷HX'÷¦Å¾ Ëí—ù¦6¶»÷Aʵ)MLÝ‚gâ|åçQ_QuC㬠'%Ým—Åš;h‰†gíürãTr»µ¸½Ö2²ŒÜDú¬ ãQŽË¼Be“©?ÉqZ_"„\®ª˜ªIÃŽ/m ’€€ð Œƒº7¶ý,·¼K®ö_põKT§„+gw1„Ž©Î^]Çåà1ÚåØa6ýTe&zp2¼_Z@s,¹³~¥,w¯‰ËpJ‹[M&Q»JÂYšjF ¸Áy°`‰ýÓ²gœ…Ù…Î)7¢oäÊåܼ¬ûXÖúýFfŽ1Ø5Íç¾sµÚjì}ctÞÖ½2°¸¯ î}0¹+«óÐ.ÒS&Eªî!Žï',K.0y/V±ŽâznN£Øfœ›hï2K®ríÒ È®ÎAdßêK î¹Jd°ûZç\¯Ü›AæŽ1œdÔ.4âãÃ;ûã«“×Ü·³¦Æ‹âßèlU«ÿ•lþ·øÜ^2ðîkC­³Ü÷év|-’è(Þç_Ö…¤´qe$éÚ„l…aš_`•xX@µƒÞ)^Œ'`¥ö>>ﳨ£ˆgw"ŠRÝ$ü ô‡³Ò^Y\’‰•÷iÝ:ñÏ}Œ<›s¸I” ?jÚp¸õ¼í¿ éë`ìXi›êvh h¤v™™é¬.ŠSÁögÒï퉷ý÷/i{³nň/‘;Ì–oÉ6K~{}PNW»â[®ÅÃm8¢i:*KÜÕ[ðËŠãÇBvžÞQ¶ƒMêeâ^GuLæ¢215K“ ©*QD “¨—è§ðØq=© iüoÌ(i…Uµ/‡7=Ÿ}ˆJÁ‘33¥ÓÃØ”^Ó0¬ÁþJÏšß½j)ÓT’C1ÜÕW‹+|_°¸ÀK.âè¨ §š>Ièp1¹Ò?l鯉{hµçÙ´b«o7‚£š>/ìÄZËÉ%ãz®¯˜÷UJœìwxɽü’€€Å×½#õ|A;æèæ *ñ ðjGùÙ]Ò½À@'½ô½u…›SRí‰s4õ`A+ÇÒ3úLn‹É«U´ ŤaˆÄo]·OgE—xƒqõ¤ZÓQŒÝwÖs”ÃUŽF€¡PßË4ÏÂyŸ×8¾öÕþ‘sÏIÀEõ_Ë+ô£*¢+5|yŠ}ìë  Ûév‘«¼MBaÔàI™'ôËñ‚mý/Á‹Ã…¸’ÕkjB›ÆjY°>Â(¢B5RÒŸmv˜¾­t#Û`Qõ8µ¦2]Ö’G‹ò1p¶[Pv6ÒóÉTld}Þ&ÞcÜèÉB8%óÀÛ}ÅdæŽÚÍ E† QDƒ‡¡É€Ó¥Ö”7XbŒ0‚Ò÷ ÎM¡þWÄQ+êÓ|Rг¾Ô¡Šð½W0#‘%Du%Ùd£ÃX:Ìd-úš °„4º‚ÔçѺeíÌ ‚@7e¶Š‘jï¢!çß7KzýØví|  ÜdbÏn$a±pI;ܲ´©ø5¨si’–jrS¬âJFâÂÜß6“3äµ4 š\@…Àˆ°æ­Âš¦kìyK†5mü؉ YgíxÙ¶›¯xø#ßNP÷7té ™X%m¦>ëQ&üÿ ´=IÈÃlŠ -z*¼ë*?ÓÜÆpÿ6Ë·nÁ»õ@åèòæƒ2ý«Ræ¼}?H9Ê#ŽÃ¶`Ìt7╳8ÒÕÀ _º!8]”KbÌr"Ú¤©rÑk,UW—ˆƒM}#õ-Nw’9´RE3¯ŸÓlÌNojDa ˜ûZ`R$ÚTýÉW)}ÑÞk}l“l¦SB»Ì‚ÃŽOý9%ðEš9]–/ÙjÙV\Å(˜µ>Dᵬð‚¯÷–>Ó—/šÛîF³¸ÂƉíÏsÑ(¾[8¯i`¨Õê¦H6{/Ô#@u~[ŸƒÏ_‡¦K¦ø±†~>g’å,¸Ðk¾F/:2î,:ñÞ—g8Á UvdÿE²3Žâ†S"MÕ©[¸ºGÚ*ê|_¥pR„È’Zo÷âÎÍ{y‘7Úµ¤ìÿ«Ö~`dAæ¼c‡Y uϧmí©s‰*•ž\·Â/ÖΩ&ê¾1Æ‘cB”©8ÏTK¥–cmu>áˆÃTøõGVyzm‡¨žPï[´)‰+Ä ƒÐa’o ªj’€€Í9ð5’©¤H¯#¤Gåowö °Û&Ó'™ƒ–[@+;;s,(gó JŠ‹ve¹3ÄÍÒˆ÷ªï 6¬?{’bÑ”²÷PÆñ~ˆit¸Dk€X3+Âo%%òµ ³]@xÇŸ€ZŠøB&’-üZdTJÔËÕôëeÜy¥U¡73ISÜkKŸdt EZb2Ñ«%à”›w†û}%zë%F‰u_um%&U‰H6ØÓ,áEàºÚ )ÓÊC ;ƒÓêÁ¨šLÑ?GP‚M‡?apõÛø ¸¶mb»:g%Áà¾Ä3HV¤·¨¹V6_tb‡0s­þÁ#¹'\ÖUrÌ‘ ·ÝkþGyx“)A 6=E„¢¨Æö–'HyÁ°áåÞÖåÆ-q…Þ4 ÉŠ%¿ À †Ž65^*Óï¹%ê:Ë UA7Gv²Û“NÑI˜eM&e¦î&^, 9M³_Öep4É6&î~ÅÌ©%ý÷Eâ8÷¼’ïë¼bš]lt‡Ôŧ½l>ÚGÊóú_‚$’œ3Nö¢8ëN>ˆÈfû }\ÓôãÛ_5+K­`ÄIµ n‘|Gü—q›ÒÛª !BF¾£ÕÚåäBüªf> ˜,EÕ“Ù}.›QÈžÃç¡YÀ¿îtžvæµÕ5ŠD/ÞÞ(‹Ö^$û_ÁÝNsætÍ­ rÊ¥À“×ßZ'53ˆ®(Ê"%Hgbì4ùÊš¾‹ëôÜ`é+Ï$MDÞºñ¨VÞ,Î<UaïbBˆ»Ý¶Jb`øzŽk; )РÕ(£hȺ*äÝ“!¸`ý÷5 B¼¿\=zuÓ°@òÖ’û‰í/°ž&+‰»@šàÅ;Y.•ÂmV4¹½Ûlzàö„1›š%p»ö^X‘~Re]©Þ‹ð¥ð­I@N‹3#ìÐèÛ’Ò}Àwáe–SYÿä#Fžíü0Mh¤Ìl¤Ågvé~íwB»C qóš»cÒÖqx›¶Å3·²B6ÁO“2SVG.ÎTl œ¹¢…YŸfT³9V\» %éÚ>Zxš6½“,dûÌ2fÜÃŒ®P9ì.~Çæj,Ƚ¬6¤û5$õMh~„³GCìÍ÷¦„·| ÔBvlØí}漜"E ]ûƒï{,¢•ß»W%ëeþp7·O¥SɶîUýÞ:ÆiŠÉ!6ŽôZjVyPÒ]ó ‰¹{˜ãyÚ’a²ÕoÆ %(ŠüÔw¯•|WÚžéÄck¬" ºE¬lÕß3²rØnôW•\£}Û•´¹¾ôã-kпfP»Bë4-™$ ¿>#͇²t~`ÂiN®Äg¯eª„~Ùý“:žàòƒ«+¹ø¡5{¥ÎF4€³dŽR"YÙceEƒ¤V-Œ3…È>ŠHÕ/4xFn‹bÿbáÄ*;µ-¨Ÿü•Jñ3šâ&^åñùâ‹ÑÀ×v$’€€¬Ã~üìeép®4"´Ãdý}4k]ðÐÝPõÅ듾¯Uè‹ ìkÇÁø9’GRÈl.¾ž£ÓêOÖÿ¯ò>m¼³­™˜ÑÖ_0Y#ƒ UN­z¯p%ÔHÍAT˜LiJå3€zï ð™qc‡cÜјÂj„1¿-{uÙqÕÅÀq;<)¡éÊ»ˆÈÏl£ó²_ë !1ºÓå«ÙÅæiýgÜcu†ÂÛGúHؼ¥ø¥LzBô½âN ë^ ”ÓWíÓv9×)ÃÐ(˜ôÛXR*þ&‡<) Ú­n963’f=lCù‘ÃùG²@l®r¶‡ÔdO'4:@ˆ³eW5™Y,šDͧyH©Ê4ØÁiÕÆœ~üÍSÉH¸4Ù5Z(ÎXð_IN±dí†fô°ŠÏ¶Ò#Mâ\¡¼'YîÓÜh¢šýj=캇â'ņ™5ÇúxlòT°üÕð0ôT ûàò‘P<¬)üźiýe92º¸8R̉=ª ÐWw£§ä­1‚é¶¿r^ÖÓj㸠òmäW_W×QA±ª7PM%é²²ý¬%~”Ý‚×tzI’ô«÷‰þ€Ö•7ðÕÙÝl%0pIrŽ äèÛ]å2ß3"ÄøÕ¾0³gØb@j²¢vÓOÑ‚¾f𽨌‰o' õ ÞèWŠA©Ùq™–d¿*…†8âT¼_[¨©H켫´*<]ú¦¿ñ3a hÁɯ×÷å ¾@)•Úyæ¸öI,oëõ+H%Ô¶ÍÔ|+Ѿðs®‰å‹ç ïâUþ:0ųÇÕR3VšÍ+­V^sŽqè;΢rò[ìf¥CÌ2X­coß"¤aæ ¬\"7Ü¢bÅbÎ_^Æñô~û˪èÉ''™q ¦Ÿ,u 2Ð[¾íwR¡±vzË€¬F%d= &=—4l®FE’9`*]©LBÁ^G®¼ìíP9Ü/BÜÿßÙa¿Dð•öËJžyȧö3Y’4_1¶Yí’¼b'jž!~š¾ÜY}>"²}·Ó„W8«8n‹yoÏhh`d¸o!l¬Šì“ö”;Þ8Z‡’€€Øß6Èó„–»îÑöÔ³¢4òjD­-¿"!BØ\.–Á­¼: 2F!‡2‹»·2^Ð]Ñ ›[ÂƳð•˜íôÐ]Ü?ȯvÛ DR¢}¨‘®9…€ý*¹¯¶ˆë˹ìÿ.$ÿèj†yWÍuNM Ȳû±Êg™öÄhS õ§è»]Ñ5Öc5S‹Ú€ÿÿÍ7ËÒøX:™×9µ‘+8 ëL4õ}÷÷»‹®ÒÉÔÒ9î‰ö4+“d³Ù^NŽ´Çë\Òù†ØpZ”_ߊŠxÆ87õïCÓx=°æ‰¹;­òpÿYrÀû9™ï «Ô¨Þ“ÆäñO(ÿ†ömnÊFš ÃŠ[W³îƒR.GþÈ7bdïj©={(«@ÞÕKQ_‚Ô%½ËuǼØâ§0ÈR0Ú¾yaŠØCE€Ô´E¢,Qõ¿ãsÉ¢i8 ˆzƦ|Ôy\jí6XùMw8Ú6uçç¾V,u‹²NzÔÀ4ˆ„  V"¹ìš¶à(m ¢&ë‰U…ar7!-z9sõB–ëûM}n:·„<-GW>¬h£¶U»~H_ø<©’“?¼°šà6$ádp|,ØQúÀþ&œìJ&Üý„鸠§P’レa6\¢¼B§"›KñÿB\‹/c °*0Ù™}¤<\ô#Ü<ܰP?8(À–7¹:«Žnf8p–R´Id.Û£B "@!\ØDÅ CF£µ°>pÂC@Ò—SxK‡ÃænB‰Ïߦ$øÄ†b¢„2sˆ3ÀZóšþ|Pcxz|ª‚7&;c*=¹=½–Üs$ÙQÙ€Ug÷ }KÁcÔóm'Ö»°ÆÑcÂD£Ãæ›5ù .®²u<‰yùu,›Î6cÕ:f.ãW¿Ò°žœzðÂÑ5@9v¦¡ëM½@~åFCé¡,ÅJh34«lªÇ/;˜¨¶tû†%Š«A÷ÓóŽö¸ÛRf“ÿB-e;D—^ðÆ»72«/ýòWTùn³WÊ{<WÀÕ7pS,·NBŸ¯ˆ¿³êoz– Šâ£x*[õ‘›Ðÿ­9ðð y©Ï·Kƒi\W—ë%ð+‡*N6C ~fb—Úê¸-£•vÚ ñ]èy41nÆ{'¯â ¢’€€²¿+š{ÎÆÓ)02¾vJX(~o%'Ý%~IÂ2)¬ç(ÊõÖ«Îúñ…¼èñ ±ÁÉU< ýòfŠ®Ü //<)ÏüŠˆé¨Î”nÄàÉ$-Ø€_.q‰„'£ÜŒ ”hc¡7 'Jú"ÐײøÚ›Ö÷û¨ó•ô3ß}û ÄSªgF·mçî·ñmŒÏx/½ÖƲl/òŠ€é;d¸¬VÚòîd:iÜŽÒÍÃxìWš9\K£î ‹­ŒÆSÕ¾!ÅüýŽò¤únËÇÆæ|ÿXöûÿÐlu&)F€­Š 4>eúü^ŠUì5ÕæÕ6¹šÅcÀÙ(ƒy^M~bjS8æQv YLݱ…?Š©¨i^„]Òã³å# 5$³µsä´¿îMêôèǪ­b9Û«Ü‹IÄ… D÷€7ø‹.WOÚÎ3!*Ñ÷¶Ìi>ùOFD öæÃkr0Tl?/–íËžÍ7ÜœƒfOZ’pÀ¬2ž/NfïƒùL¾¡;†¼îÈå RJô[µË¬±Ž|Loˆo©ÅL9UÈšVý0(SßïBÅŒk|‰rÙì¿÷p G[Ì»[¸ø?J:ºÜ 3ïÌØwoC_mþ3Uø9m&u‡#Ðzm/”Þjv‚‚<¾WÞ¯CG‚_ƒäq|eå%`m”8œÙ—ŒØ¬6ÝîW’é4Û3°ÛÑ"I“¨"fhÿwóONDØeÛu5Í|3Ëž‡YÊ}+X/ˆ6V$³„$T4ŸøË74œXWRÈÌ튅¨/ùà™<ÍWŽ4 Ã-¼¬NرÍÃçƒÐ¯¥¢÷fSV÷1EDZµfª—3Šór†â?$Fꙉ1I÷¤Ä,9•QâÑ7A¥çg§%ñÃ’†q_ŽÂK8‰A1Ó'¡wõ¨Y›5ÝMK”ƒÙ!…Ì㜋doï²=מºÃ©é)ù‰ÿ󯧓¬VuÕðv{9Ä|:%W¿rÖARº …\Ý®U/}NíÞÛ­ýNåʬ¤Söø`%\Üãø¶s̯¹¼â²¸G.Ì7JàlëX²4·Œ•ëiÝ‘ä_Ovn¯üœñ¶À" ÿµôÙRõ3#ÁWÒ’€€Çíñ×éÛ–vèËOÎ…—¿ÓOrEŸ¦6ÙŽ™& à ƒ.uIˆ?r¶>†°œ±HÂâ.GÛLU/mhç1Bãh)F¥C'É`I; ¦úјQh ˆoð¨rÑ[7È2 ó­(à ^N Yn&4 ‰}&  §á}?A¸ù-ÔÑp Ó¢ïi˜`,š>ª\ÞXïS;ü>_.;Žö£Ãc1²`–è GF³:Ža“å3CŸ"µ‚2(EÇnÛ)†_a•#£;œç€Dˆ®žAH—¾0*êPƲȪÒÑ ùúhÖ‹9€æÑñkÚCöCïâÕÕ Ù>›ö²!z¸_ïe›{4èbì~¸rÀ‘š‡¾ÐX8j†Âc¶A9Ô2&¢…,Pk|PakíÙEâwEZød¨±Íùò¾ØCmæ”å6ø¸Rf‡F±‘(Œ…­FbY2 WG¿é×$Ó,ÈìÎ'Bèg¾ó×Þ5˜ŽŒÂ#! —ÔG<{¼·è ðNFcêy‡êËÁwM‰Èi`Q[º×©HÎ04:GµRñ£Ò;ÓˆÚܘ¡o—c§d·‘¼LâZ²k1’ôç‰Fûb½-ݘ™±~ á/=Œ¬{ÁHµ/Oòâ^wÅý! f­Â=sþ,¶öþm»õ>€|œåRãf¦íb ËíÒn·àÑ?£IM«*Mzom¸ÜùŸS´ñ´‹ð<ú6àí8Ìo(û5%wí¾NâVc'9xr’«±1Dpk冥1+N××íŽtÍ®=š øÿqè0kÅ1…nI V {r¦¬˜FUq³,#Ðàয»ÌYû'’+ÍËÚ@°ÅTÊÖh¹âC¤/bΣ€/uÔEüxÅLUòîðˆ—»õG‘î’aýãŒã«ÐMz‡ð¥Ršð3HlÈw'Çs Šõ.c+!9Élì«ìºN êÝ—!œ}í–â•ÚMQù§>Kyv¯ -Ý<Ó·‚ß-Ø%ïH‡Ž5ÍÉÈjnìs’ֱܱ´¯W€òø–Ûjp ¹5›Å¶Û%oÐ$æ½J8„?W0ù{½;ªágȽÎó¯Ýi¿cá¶,< kW‚1ÚÞ.ƒáñÚÖ9´‚…ïFÃó¢Ãí’€€ÙIŒ¨ z¨OÁKÜ5™¾î|ÇyWNü8_ ÂUüqÚ’l§ëSüE½È[ _áô·8ñÚ0„g¬ @M»PÝTïk7Ù84vªNïæf˜¡#m|ü· Ú̧ wäË<”®yÊÖˆ^oL.zVJ!Ü{ÅYµ¢°TŸÝ5Ϩw{‰"ŠÙÖÒ¼+€h¸P³=ðÐP†¢£ÔÍlVºC•¬iTö¤ÞŸˆañÀ©Ðtpu¼N³¯÷w€T(Ãtõ¯k¿I2›(}鞯š)”'èÒ¼T¯°ƒ°Õ8±½®¿éé LyúÜÑNôÉp…qx’ÿ½Ï¨éÍüûøDc‘Õ‘DÖ]}³~5Tîôzƒ(•U)uúQA§LV£Kê¸ç²©Îþ:Eú[EÀ¾Çt-0™#H›bÑ ×£­Ïù]Ù³”@ÞŽ$Lë(¯é£÷І‹f(Lºb®u›*;m‡Qq/"€‚îÞ¹7 hº=ÕÛ€žÊÑÈ#ÇW΄¼ q]×#TPÔQ™^pÝ6‘,(†øÊ–½*p˜Åޤ ®=3â°P´-P ”’žŒCª¢„F㈖.{±ª v3u›Ëª£ûyys|˜Js”yO ªÆl¤Ø[Ýîì g½¬çf4"uµC–2Ñ^;ûíÎAgí Æpc5q¬F· D_Ô+´Së Ê‘E0ZÇÒt´´h –ãä.¢²óöÇtÙÚp·³½Ï*'|.“Ë ZÑJmè`al-¸wA&: ¦GWRˆ;ÍãS€š<ÜÑ;÷g³ûSE{æ–P€£É"¦±7oËGééiîEo´Ø¢k|ËAf»bïÙÝ_žÊJ"ŸK­³RÙƒ.oòŸÖg/í¯ÊG铨¢avÀùuxòÉ«ñwúðÚ€­b6M?XsŒÇÈCÈsúIÅ’ðX„d>îxâUõl "š6ƒe NÑÞ·uyä‡XÄ+k¢OlOSÉúel—1$fN(£"»²3Z9“húx.Ÿ5¸\  Y l¹ŸœO¸îdY~î}Ži]Ûi] ª‡†© ù“J¶ì…d÷`‘A­žªñ‚Ð&_qÍû t® rhPÓBpÑÛÝß³ì6¬wOšƒ¤ž ?ÅÔ3[^«\k„ —‚’€€Ó)NËŠ /¸@—CEÎÜë{t¯î§¹)ô£ãÁ¦D)®Ì~­mVî°iÓ:}Ø ¿Y-÷Ðë8ü„”W¶±N¤áS?Æ(•Ø~¦Ûx*ˆWeÙ¤@jî/ÕôÛ’—ªöÙÔA Úÿý¾ÂeÜp‘VFÛÍcÿ™ž¾>¿èPF@b§3P}B^¿¼Iážrš“ö\zÿ¯åc0ý¸žת¼9½†=/V›p¹Ï«‡iL™´€5ïØµ]ìWò6[%yà¹m² s}¾æcÕâ= ª—É—Nš–Ü{ä·Ê-7Kƒ¨?TnAìž§AÃæQDÚÓ;¤`ñðøö»‡Ù}›©ì€™qýÏê Bö=Óèô±Q}}èÚ˜ßGgójæ),D;^çJ8ò¡ö­Âõ=ÖŽ´[È3õ$rmס:ÐõI¤Ã=ynãXüåÔ’¼ˆôÞ“Œ°R3+ÛöZ—”ãœï¹#uÑ6’ºpIu®ì›HŠ<õs4šƒ*´ã ÕHÒ¹A7À<~30-;öX!§Ç·J=åõ®Š£cÇìM*ú¤[õÕ>×ÅæÕØ˜øÚk’€€µc¥¨„nÉND\¯ØGg8¢»1š{wT$ô_äƒ5ðÝ‹ä>S”ô÷»wU~8~×Ò”„¢cuQvVB†£DUÎ!®[c55‘âe]·/×ó¾UÙ-îŸBqÀÈ ÛŸX-âìÓ×’ÃÔÉ+k²OÁn\4®‡8:´ 2­;ìÕ\lÔ”Ñ×Vq©-°—F>Üväñ:¨”…Å%£í©˜ü,ÔŸi™b-Ùÿ"—Kº…ò*ZAÿË Ì`¸º¡ŽW2ZÄ8aìè±éÝŠ×CZ†¹¨‘GƼÆÔµT7\üFû3âlñ\vdí&Ë@–±¥$ÍÀy+ÛÀÕcýúpscþÒ|¹úäâÐJ¡è÷mù븲¶Lˆ¯ßG¶-nã¬VÄn”spž1àDˆx(>ξÕ%­W™ÂO† _<Õ%4sAÛßÀâ¡2MK¹ÔUÊ)×x?Yzð¢£AO†Š•ª mÀNÍí7« ÿ­ñ'º=ÒàÁ‹‡U™¨òµµý¾Nùª«fÛ5&n·ÿµóX \‹ÈâÁ‰7ž} LU€d–%0$bÞ_ðÀ†è^VÁV’|)Ü Ýñ}®1Ü5–‡âô…Ú*9»¯oq·k ïÊ^Éù¿|̯ó=w·™Œ â ,Ñã¦ãšØÉ}±éÿ­Ûƒ‡Ãg¢è»Ì¨2jùŠza‰C°TNÆ7–™Î?³Ã %ôÄ~åŒïâ:MÆ´ƒf\b›ª! ð| 85@Ç;gµ‰ýW*F“œc.©a‹º:ÉÉ7¤lN1š…Ôå®)4úhisjöB˜—p=«Éx*ÕË‘óùn$áV!ŸÝ—ëɲÕI3¤²mLÓŠ Ý"=O‹«ƒszGÃÔïf&~ðjó4ÏìÕTú„—F ˆZèiÍé#›T$î~‘›¾Ÿ´©r&â“})SÊñ”u‹6”·AìBˆÈ†¿äêµCYʧjj3‘€£L}ÑÑ0àµ[™K±cªEôÎ@H½ÿ^Òo#·M¤ JëÈ“œ¸aHYÁê1ʵ?y¡D“ íöyÑð–…s_O˜áþí¶Ø«&ql(/ø ;]`"$‰#±aÎkò®þ¾Œ(=ÚacnÚ³[ .vþçª40ÜÇýwxÙ>§·ˆªÃ“•fÌ8³<}EþžUìêÝ—…4HX°¶W´dÊúÁ¶Ñž8"ŸëW­L©?åÂkèP$¦É{ø"L5ýšÌ¤1®ÿc)ÎC>ÖdèÁ< Á'–žüšvrya®[5êþGæZ[y™äŠ–þ ¤’ç ¯Á¢ì”xfâZô+³€%¯»p‚º"&1YÁ ½CFË·^má)­ˆ\ì²0´C-O‰³™Nö±öˆ²åôÆcܺ“ÔðS»,e31tO¯Mù¤zý£-•Ř-=y1l >”–?•Zž x½5&4úº)»iïüY½*»ad‰yžvgñÁC#9™çf³ƒxSgåû1ðD3×/cÈ»ù‚ÈÒ®v͇—ÅÍœrn3² T1Àé‰C!yoçäwc£þ5¸ «ÔÁÎ ê$/9á†È|Ë:‹eAWrÄè²ÌQ¢Ìçƒu49iÚ®hóHBLÄø[™XÊkkxP~øŸÀ&Iá”—F© yS‘ŸÙ½ë•_Ø%dkø¿CÈ<§ÊNëŸgJ‡âŸšm]~s?†ýK]9èáZx'›ß]œÉS™t¥xõ¤þr"4CÒ,Vð `Õ^Ÿ§ÊÖÂîJçÿ6ßø=ߢì¨MÁ·GH‰”-RQžû3Yåqb¤†ÎEzvrGý 5kSâ»ý“û›Ap¤«!9«ŸZý¯'î3T¼H¶¨Ø‡8ûeÖœ²¸è*´óI•¾Ì•&Ø sÔÅñ±4þDÓrëh eh‹Lvob"“AÈ•˜;¡$k ѯ‹|¶É!È û.¥›­!Ú]‚2'ŠlgP®ðÜϯ -uÎé¿w4œì[øªÁÆ–X©€Î Ænå$»¥Kxêº}áó¤®Z’ ë e/îS6ÛÙ^)êH7L‹./È;Ú&»C¦{~`Ù{teÀI¹VÙâHŒç_Søç|$p&prÐ|Bèn %ýnyr!m¡ª>aääó¨1‹ Ðß—Ù5¯‹y]¦Ýý‘»"ï Z€ÉBG骢­Ö&Ê·,F]3ÌLU³À-a¡³¨$~“W/YÔðÜšFñz¸FÛ¼£½NŽøœø+˘ÃMVx9 c%»»õÉ aì*®åæã€ûJ¢ßRIÁßÒ Ù6×ԡΕ®U†Ìÿ¬îxkúµEÖÁ…ûØæÝÞœ•Mñy‘K‚_ß{-Xå³o”ѨˆŽßT¶ÍäÈïóOgõêMáýÈçî1@”“.K4°ôy2Æîý©ðpÝÁ!28d¥(yaÂsÍöû­Èd¸Ùt @ŸŒ2I~Z†d`™J'.,AŠ„^˜<ãìrC@Xñ£Bú»³ Ôˆatx3Ⱥ¨´þ³²îõHs˜BO+ý$º›d]Öæ0ïΆ*͉¥Ëd‰ÔTfÑHO÷¶–´&g$`RN2©áÿE–Tþÿ°ßë³^ÊÔ¯lvvIÕ–yBâ›*Þ\?س]$¢zÄ/Æ9–i­gæ|0шL¹zu¥¸‘°ÚcKdŠ€ŒŽ¤½Àõb[n‹ÅïÄÌÝÇ”)J"Š–/kãP8%ØÔÝg˜O®sea·l5¼µˆtdLÍÓž#Îü!¤”˹”’€€©ÌÕÊJNÍnƒÂ.tð#‹T–VÉõ à1?y•€ê`–ßí©z-ˆûT·+`ª·õ„Bò«ü…Te€¥C瀎qå:ùùvh¡n_) Ë®ÂÚ&Ž$®éQKQÍõbx†À(3´·‡ïÕ.¯aÈÖÓ± (¿fˆjæ÷0³{½Ú) Âý5 ~µlè.¤—a<†×'@Œë‹ÖÓï%{B Jñ}”÷çh9Z°]ªê6.ZÖÅ: ¢ [;°2MÜ—ø³e‹3ðç!»üKÄžH0QQ~²`EO E«¶E\ßuŽþt ÒãªJʹçö9÷½Åß¿hW"›Ðîs¬t*MÈ œx;Câa,E#ņþdŒ¿šh¥2^"[¢æv„w=Êë¢ï«$ùà–»Ï÷CÖ;בÔ}’rŸ»‹Ë}uû¬f4I9@››ðvmÏpf^ÏíNYj¨Ò /!ù5|{#:6>°†eK÷AS~ uæp|»<‘ö ñ/Y^Ķ]nã~Æþ3æà¼Yy4…C=M®E¤÷üäg’M.ô@a®ƒ]Ñô”ˆM4U™ôic®ÃQý¥«àçóoìBñFÓ®qÌCÓ)áÊ7%¼îDMP ª… uZœ¯­{ä¯Â×g·‘ [ú!Þk®tÌ›-w5“Í•ð÷Å)ŸÚ”XlPŠH]jzŸŠR/PXÆÎùR÷s™O8tÈš·IÖÇÆ'ÒYŠÚP6Pžöó(ƒfM5é³þÙ8ǾVy¢EñóS {8Õá±BjXìFÔÍÞ’ïb Š‘¡ù”mc‰>³Š5V9‚àý_Ãnc}†å[I!Ë|sêdƒ  /•cžÛn=FpŽ×QÎÄ€#ulô0Z-gà ø8¨"Ý{]D[> Ú¶Û]€ÂB¸ï‘¤©–_ÍŒ›±…0y¸‰‘phpëÂ÷M•(@¦?ì„GŠ 3Å}iŸ„>ñA°D¸à"â†EBÖ¾ãA©˜Ú«™Fšp!ç¼ìj Fú\(¥Êâ\ö!0&qè¥2W½µ}÷’ZEðBi ¿ÿ±O×g;#­êOJ÷-Ü`ßTÎM:hœ#µp@$K~‚ps¸±—óôDYpžŽ¤{|@ŒˆPbç”ÊTÁÙ¬4Ì¢C’€€à‹™Qç7·ý)°1—/€ýäzIåü<¹x¡o ðC›-Éz<: n®4ç¹3Ð'ƒ=¯}s{Á÷ä=Þ«Æß§M{ÂïËÝS„ kßTŒÈ$”ÿ±-D.hñû•„Òs{úî²z¿½8hŠq–¦ÓO©|―†’eÇe¯žÛ#øqóžlvV2HÓ(s¤õŒÛ4tJCºˆOäzgäGÆotü¼’&†×¸‚¤ëߩɦ[/݆®”ã½`üóÍ{dÉ¥;êÉÿ;À™’ˆ0œ/‡æ)Ú[T­lV¼+t=£rù78s×Ï8„Û{]ÞȰmŒŠ»<Ó¿k@*‰k( ¢÷ì›Äºätã×I¤y†¯¼‰Ç@oùYmNUñ¾®BL—ƒ!zœ‚íûSÙ}7:?»†nªˆiÉÕÊyg'`SX#Üëì«ev>f©ÇæÒ]²{¶Ü£|½<›úA*9šDz‚¢þÞnóCë9"ÔÐG5‚YeôØ«Û8~‚ÿ‰$’-mð›È#D²µÑ|Ó?ðçl&G£lþª«B×®âó¡o›ÿ2-z³_µº ~[¸~ð á:£_ÏÂÔ‘³òÀˆ2BÄ,˜ªuþù™Êy.9ШÍ«B_URÕË;c¯ Z-çâÄ8\AšÀ ù÷ø@“MŒší.Ð’VÊê;Íag¢)u©ûÑ`ªJ~½í–\m 1;½ñ @Ñ1´jlö©vsEè(Ž Åw„ A‰è£h·ÒükSæ@Û%} ر¶38&*2Üo5HIöÍ~›¾´Œ©ùäðw›Âi¼9²ê³×ý9)úàFA¾…ÏÙçП¢BÝ,Ð?p¶Ìuø½­ólQÒa!ç”Í)ÓDãÙÔ?TŒÎ…—ÀFÁ§à«µ9„^&&^$¥¹‰²ÎCsç4ó£¶dÛJÜ÷Ä\ú´Ê’C,ÑŒíW<Ñ u+ÎYŒ3w=g\úgñÐÂúMöæ¿4ltŵ۲­X-éãL˺aj~<ûåšæÅw3; ºñ0`ákÞ„ï¼L¤{tkßpý¿¸$.Á÷š³<Ç«òkVØr»€Mp­Tf\Bn|¢mèúyàãÅï!•ù÷Ÿð¹rKYÄ„Wu߃£cÔÁ?)œÆ¼<‡cÔLžš¨ØàV§Ê+}'Ô¸g‰@´_On‰“’[§×bx]”†·i… ó7ÿ’í¨4H+&ÅñÙtq®M½tV¼Qänp‹$õ›¾”ÑjôÕÊ&McbGž*'·á'J­2f3rŒüÒâý;{€ŠãÌû¯±¬u8ÊîAø·&‡Oõ¡!œ‘Š"‘LUnÅ3î¢Ü­Í‰q ’S]ŒMË(·ã@—‰Ÿ×}Ÿ™?”?òcÕ‰ªê·—!)¨Ä±µ½âãÛ7Ъ{+€âµ/˜àèÈÁÍóƒûz¡–ɳÏÚŒŸÌ8ixŸin%7åš4D¨$2` Ÿ™e½½$ì!ßZûR©íÚ-‚áð×ÿߊœaÀRW¿1Ædà%5i{÷Õåü´–‹BÚwyhÊF‡}Ìh"YÑ)£÷:Ê2²åí°Kp' êévˆ¸‡žc¦Q]jCºhÆú3Ð<«ÊqB6»ÍXe‹“†„.Ø·y=|»ÕÕBƧÙgjbÕà#•CÜ 3GU1ᆤ@6$Ä›©¢týCüø\'Š=Aaë$ZeI–‰|;>oÛ09¨Au— Ë‘Æ Uy&þ€#wç5wžýäT‡aØëJQÏq†’ðc×SÖXÁ͈>‰ºOnDòïaÃ;Fãˆ;Ò é2l]ò}.c/Åwn/ ¹d’€€ßªè×ÿ¾MžÏÖ<9ÂÃ'±‚Gý¹¾ NêN÷dªO>â±P×pfHèÌ^×ÖIi Q0]t0™Oì<˜®Ùn̺”±¥*œÉ[NN›C§û®Ø¾"+úD€p«jÍ%ƒw”¬ yÔäógú L©Öõß6>­Ë'†‘dír|©ÁtJ8"ž6зLž§30åÑø/eL€A¿Ö|ØRÊT…¹HÌš+“kGÔ_Jr^ Šl•S¬þp1¢¾M.W÷³k¾=òJİ}sÒ¨-^êÂ¥$ï!ÕU7<‚‰Û!¼%X Ý ‡Xû-}~ÑÈ »¨†¡¾6Û)ÆE?˜¸ëÂÊûü&äfn€ðX;$ne=AŠdA-5ªD—3Mñ7-åHcC¹¾oT]ñ@ø}'ýÂFÕèçÔvå·ØÉþÆb™Hñ Yg¶÷ÅWX' ¾äÁ¦˜Tƒ‘†ÉZ«Ë=iÝdÂÕ'|ß? ·–ƒVÔëªlã )0»p@%½75«dAðÓ=½5ÒÅZæ©èŸr¡Td£5˜òÒä)oÓ;ðFäòÉÿ=ËÃŽ¿RA7y¨»›¯ Uz{£æUM†Ï#Á<©ŸÏ ƒt°4µŽñ©ãñN˜%3Þ”8Ï'èiÖ Øiü°£sV¾Q@ “VíöÞÂDUJS¢âMéâ7ªŸ_ÀðÑä|OÕ1¦ÖjN&åQ=5{²eïÞ%ÛNŸ’²Çô ÅóÿV™Y#’ü¹5,#ÒE‡ÐY·®znX¯‡é ³tdÞ]Ÿ(‡d+‡ÉhL#”‰i£Q<¦‚ßTG y5™ k2ªÝpt¥U çðzU$'y£Ü:ÙÄç·û!]øXß§Þ)þ–Ñ:Á ^[¹cż’ÙHÿãv}Öä—æã ⎳ 0g;Äm†`Ãç úû¿±¢Ò%q‘‘½ß:ªWµvœK}h–hiT;‡|â)žYY„N0œËΧ‡½ÅÁ˜ê<ÿ•%å¦í¹‰Ê_ì §t±)×°V©kŽlàÜ{Ll˜"¨Tf€©/N3ùó_~¨˜ŸAgž…Ê7­€ê”¦ŸWbÌ ’WQu•Ä®ö›šÕ“kìßGƒc˜ÃYBšâÂÒÿ¯Cö4Ý©Z¯ŠÈrF¨Jò±fÄž’€€ÝšÊ«·?¥¥tí±Z%! tc.ûOß8'çûMø¸©A¯5ª$P –.‡w¸U+Ïy_:‹~ƒ¤y|ÐEÅT[Eÿ«ÍÓg‰©0sú‘9¥°Qĺ¢hQtIÁ§úäаs9‡ÐìóÇÿºmór¨cve¦g3¡º(u…,2úý¸ÙhµŽ”Agv«j°ßT…••%2>sÔà÷îuõ|³Ï˜UÍhó'ïâeI§|Ø)Úꆮ]Á¡e+@†0òcÿô…iÃ4ûó'r†µoõ Ÿ””¸ûÏrn¯ %Iƒ€^ÏÔlœQÜ}O|Qø±dm´§S/À,Óvvp­g 1 Þ0meü•þ¸üÔ}xÕ¡8Âã ¦4ò½çýë¯:«¢aÝx¬Ÿ sUl ‚èÐA¡’Å„yNäÐj8ls€8v^­Tg-]%ìçyÈ=¤µ, @Ô4äÆ?ã+MÔ¹~5ßkÄD‘|go*SFqQ?ãˆ?0ë^»ÙнçIª¡3nÀ •ÁÙ.Ð#†ÂîH:ŒFcß|ø[=ä ‹¬U7»QmÝÚôþ2ÂöÇÉQÐ>nˆ+n.º“F£VàÇÓŒ‡ZE«±|«†ü£IZªÌ‰°M)$MØEÕ¢z§eómÑ¢5M,=þäËÌá< €uöL¯;øÛLJ«Y)C“ ÜÊ šû£ý©F¹Ø)²kWhBƒèç?p¿ì„ê^«AÊ8$Ù¥ŽMꕆWç§„¦;Ql¾¥±:Œ4æ·{o-M(Â7nn9¨ª­n“x¾ÿ·et(¶úțÿ£¾[Y¾F›¾w6&ÿ$7æUòºÞ;pGfdí¹ž1ƒÿÀniû áB`\—^ß¾C c}*t¦ 57Tè—ú ¦l©ú€±.+³¯NÆ~ ú~VâÉ":hO&ŽíGƒ€µ¯R:<îÊvP ÉÿE.oøˆƒ/Àúùrì¬s=P…¬ÛüG=ψQ„¬ùê¤Þ?ûe>P âú´@RARä&YC„òoÆ®løï¢–sÞϺU< ÛŠÇ?rS曞ؓ8õ6çÌ0˜mP¡$_7à´Ä8s• Sš´UêVàg5ž8·WAI#lºo ®³UÐìÊ@ö’‚8’g°m±\(’€€ã䟲ÏÉ[’Û|{§ÆW Å™µ”Z ½¹ŒÖ-fðp¬‡&´ÄçÇD<âߦI¸µNÝéɱhÜ\2[]j´–É&ÓbMû¬q ~A¢”‡McÜ}?Y…6 ½”½P&;vs€$þ6§÷­õÞ… x]-Y»\ñfÝàÅ5ÃÔÇ{Ÿf~À+*Å'†®oÓÒrÑn½3SÞûb„f®¢<Ø9Z°d _þW}Fhhq 2ÀlD€$”bæôrûx¸íš†ã¿Â¨fwØõ­‚—ÑdêÁ!íÞ-f§#쨗4‚×á…—ýŒ10á>6¿–ºxµ&6þÀ×ÚÛN·§o€ë\ï>Q‚»®oD°ÞTPd ù²<ºY™Šw¯]²c½öªÝ7B6½Ÿj%½¹6ÇB÷æ·2·§þÐyսƉþ€!ñu îèvƒ“.,´Ï£4Z9—îû÷h†²Ÿ3ѫ뼱I#r;%¼¹ñwÆÞ97N¼õ³$V`àðÎèepÖÈyKQ)EGB;„J­Ô®ø¦mG“¤†ÏI§»S×!™ØCê³ËüËø†6‘:tiB_qéüÉùÙÓ:G‡eZ ¬ «˜ä4¶¯UP (Ðü'·ÈïõMÉçÔiT¨l÷/ô,NŒEK š5g8ý1ñ"âÚ %ákP…òˆ~›µõS/&‹ ¹å(튶O†#â>øP7•× µôö®¬œ ²£¶óM¡¼ÏݾŸ¢¨eÌM¹m¦åÖ¹9sÃÄ´)Ênµ›"ážoºÞ kiú’wfþ/2k;@e‡ÀôÀµp*täz;e´õ´ˆ3"ø{&½é»â©7ð$;ßü‚‘áånb«È¶V:~}AævŠOÜ×E}Ä;廽©–ˆ!¥i#t„jÄâ% uÇXÌ®u‹™F}”lã¼³èfî ´Ò¾ch\–jz0q–’B¸*.}øu ]ûƒ¥H‘zTÐ;ŠUAø®ÏÍß'ÊÝ„WÈñ?“B•¦TõÙ¿ÚÇ…*é@‘J¿Ùù¾ÇñQöàÎ¥Ðå{î) ‰G§ÝhÙâ/"Pqf'`¾wàÒAÊ Ç™Ë€–’7Ô6cU໎à~àR îm9ƒºúÑê‡àë!‡uÐ+ÔWY] c02M3_š8¹¥]ð¸éý½ÀÌÊ$|Z§p9 tu  <óÁ½´wyãs³À3OUhMó3r=’­l¿kXÚ±—º›oŒ~‰È¿oë]kNÈÔ·zp˜‡*èòÍ Ê3jf¥?UéÃÌOR(„Ëú=ef¶åÇ)—¥M­Vø‰NÕ}³Äª’€€ç Ë«o áíÙ6ŠàÛ×Ü\â5»É8 ÆäoÙ-q¬MN3XFLâu?vA—=ëkÙÿècŒþ‰¿_ï;J±9†jbJ ‹ÝàTùÆÛ±òj}25 Ú¾½ý's–‘U NU_èE©¹¤1Éñi‘T® G.‰œI7ew­ˆ¤3ñ‘YA‘¦-»—_µ(=°,R ¹™E÷èjî»f; ÒǵdK”¶H·é œTb;ŒqÆ•h9`MŠãa%ù®ÿ¹¨+]…źøU‡Lîò¨#*#ôÍ„JQÝÕAàô^ìè ß«PÝm榮U¥!úÇqS4küO?MÓió-MòÕ“<–4#œèŠœñÕ•‡7úäRʾX¿îèz²ç.¥ëEy]ÌwúDC±pãç²YpÔÅÙ®„‚‚qu”;TÂzß¾Æm„CXýåu÷8ls¡¨V˜ÍTî¶g`¥l[íݤÀÒP6\O§”`/HÆä4FI+•üXð³ “æ‹x¡*"üCÛĺ ³_AëHs*§k[¾Ws4‡—vöªÃýÕ /½´ï¢NÁPÇi*fÔ'4˜z*È™"h?¥H•èd¬vÀ2yÜØ-Wº ä7ÀySLJÁKy™q?W_)‹á»Ø`l ³ÈÕù¨w‘¦\6OÒh­õFÈÿµ`ªµSˆF¿…S:¾c7ÆQ`Tˆ5†Å(6„Ü0ÍÒ„£UøØ˜u(í*nÁ`,]¦BFO¯I_t$›Ñ=4qëî?ðäfÌ Êf˜îäœQÈ£+Ï»%`ùk&ñÖ"Œ·]2XÛ)klì´W à3ìÿÓÆ[g{úö°Y«!¤ø÷êÙ~j«2¦,¾7åp+j* ñß|üPAØ“¡Ñ Ñl­r_”Hý?3=üjf{âÿïÌÕ/Y„s 08,δï¾c_àolÊÐÔÂôVRª&ºç9Ê bñ¶¢ˆh(\÷Tet€Í¬ñØ’"rîFDéœÁb¾4 (N<0Ò——²ÏšH×F®4gÞaÅ€*·ã“r!W£M®0ªmÅ=5xŸ³ÔYr.u¦µú[ã:Ô‹êIéµ ]Œ›’eúžmÓT­¯ö˧ú®¤w"#¥C †s»üÌÞ_H/‚üÁ‰tpÀ¡¸y‚áš:`g.§üÑý£ÄØx Mÿ>N‰ŸjOØ¢Åè·lωÙÒ\ÃîêÚò7ôëeì–Ë„Aß$»‰¦·ó„šÛ|…•·ßèãCéì±dpjÞÄȱOY|#¼˜³rš-qÀ-¢aý„É{KG‰ˆWÍËèB¼(fØçŽó#8Þÿ”4u÷2ë8˜5¦ª¬ Æê\¬˜Á%`âËw#j¼aO²ÁÃL¡PeE™rg5UÆÔPBúìèk‹¥™¥úÂñ3l÷¬BŽ,nÙÚªŒnÓH¿v¬,vhPóweÊõiÕ†§ Ëf]VäCÎ?²iRÛ#ÉIñp´æÓÝ"žÆ¹Õ@gþ!”¥Q)gtü¾ðUYe:¯Öh‡³9Ý9ªëB?jŸ2çüëéÀr÷ª­»)%FÃ!h`ú+»ôVI®"R ³ ÷§ÂÃbßyGa6¢í™ïo¢J!QÍëœU"%ø›<ÿëÜÛ:xÖ05é!PÃHf ÅFkð Ä3´Ã©‡nÞ•:år«G®qè¦Æƒ³»ÎÄxV—Ëá@úF™/€kr‡®¥‰hƒ}Î’¹ Þ­+Ú‚@!@‡H­_­?C “yIå·S¯V^”gJÑÞŒ@G‚Iº‰þH:Äãa»TÁ×Ü{ Öì‘É>ÏF¦ŒüãŠüNÁüÛZŽ÷yû…Xá1‚É’¡kÉàÄÐÌ„ê%'òodKDVÎÚ<ßßò&=F[¡VT^´œI’³”¹©WÈáPÌËE‹ =’€€¯ãc€NV‡Š+ ¬[k¸\{öÖ4,\Œ4æ34·i‡; ú'¤pàA5ÊŸõ•­à^+Ÿä:»°Êá¡ð{„6ÕI•M8Ø}Tù}©ÇŠ­y\*íe¢ñû§1;~_=swišdþ’§L› »ü'^Äu/ΆD:%j µ>ÝMÚš3½žR_÷ߞǸrS4ÆÀV¤clÿÂ#¤§BáVq ¿{Å$ƒÄÞ|¾;Ïí'HæP¨ªØ44y’e@òœùx»fôá|pcxü”éݤ¾V±ÑqŠRESÂÙ ÑS¤˜LãKõ;bȦ«f˜3&›(.$¯°4¥Šrz°CBu1òrøc@.VÆnÚ¦›ÀšÔ{JaŸ>@ÕÐ~\3`íø Ü|xpš5u¢E«µ¦hÇ»ø—M »R‚ý'ÏMÙÉY*Ä¢Ÿ0ØÜ¼í¦©#h,ýÐ…%t$|ÞßõÐÌ‘ »îd„^AË»­7| €¿‚=nÎ ÍŠBjÊäzÛÿ·J/§ä}“–Td›µmwá9iP¶élP½ÄÑâßá0tª¸ŸTbLáŒpÀL/&#”úŽØÒ.Ê#Qà… §š“nL¦ÔáVJHýƒùAE¢$!ÐýÇþøH‡M$´‹D{glé”Ä]†oœ%Ý×…¦ïd9pêý›_L$K@©r–Ͳç²ÃL_¬˜¸Æu1–àÚ™L„›ˆÛc® N ¹Õ.xü%cÅ ‘xåø†Úa7¿•oABìs°%mç8+K6 =ÕÙ€zÉ<Ð¥›D$ȼ¯Ìqìm8+ÒÊe刻Y‰ìW†þ-Ê„½™ưK½8¬ Š#Ê72†È,sV€Ÿ¬<© ÜÆúîÇð*²&ñqB:6Ÿ¤¸ZžßIОܧÁÇùI>:a¬ÕÐ'ƨa$°Ÿxtɱ>)ý6us×·V{+[(Ó¶ÝÊJµÈ‚ø©A_›“ ÙG²ÃÞ/¬IPÙôÑš^ŸÔÊëþnaZÒ…ßdUð(pË6¯é›wÚ䵟âïÕ|œ¤Ùe_¹"ÐË#Û…µ×bœ$UÓä(RqáOŽ©óSæˆå[ö­@é$Ô‡C—úf‹K©™«ä]ÿ--j†ù$d›¼éÃ/×é*N¡L„ÞnâŸFæÊ * *Qà¹Ã†jkíÛa5Ø©7Å›öòë9& Ü`ägSø"ßò³Ôß*ÇpQÛ§A%Ù01˜q£ÉýxŒ}æ¹dÑw$ùz‚t&KµOº`ÍØÌeØèöDóá|JÐø3OþÁpžÎ¼ã,H-Y®Lî·xËŠêW#:¯ºµ/Që]¿Xè‡g“÷VðÙÍ`5‡;ë\¹+8ýïùÛ—ÿWp*i¦ýããßâ*©ƒÜYf#ƒšª­ïT¼ÇÌ…¥m9´3ÿÔ°ëiýQ÷Ó©wë4û¶3ár»ÇC¸£9âFù¸ª˜Í÷Ë)íz€Mw”A«¹œ´/—ÀQGR}õù›Û¢êÚ9j€…ªÆÿ=+<gPñô—R„ÝLª§»S«-v`_©vq?²ïãQèü:—Á©¹¢ÓrØ÷SYV÷ÅʆëG>sRG 8bgxŽ£ú¥+xV¹q®Îvvc¯¤½A#%¢†{–¸¶ÝG¯×Æd¾>Eæé;iˆr å¿ s‡ï&+‘h²¾˜ûŠ/õÕÞðønûìeáæ§ÊËñÝ-Á©µéSò˜s£¿F¿m¯iüÆú[uùºi5®“ûæiÕ‡E»R=I¬ÏJ-5_Xù|¾pà ×\ÏO¨£w Àv0ýa½:ý ‘󤍸\BGíeh’€€¶[ãÓžg8[¬Ö¡²»¦T©ùºO`êâÖ»ÆÿˆAÙÒqŸÓ,Bœ$šÐ퀞Q¾Ý‘EöÖÔ¨=¼˜ÚÌÓÔdqËø˸b" pŠÂ#zí™@ nüYˆné¤Â>4<Úg1¡ÍŽ”Â¿ÝºA&M4¯ñ3¼z7Tl-±î©+½ÄCì>Ø;ðô^Pun{ë?ͨeÚ?ކøIþ°(ü:ÑMr/b Dæ(§±–ÔÖ¦mÉ£K{Ûd¶ñ#K…ïvÖ)&@µ{!9ݱJ¬¢»—D#;åQ[õ›¢•rÕÅÀ?sÀöÝÁ¨$AµÝi,£îÇf}Sd¿ÉYsã—ë)ÕA&+HY*’Ä4)>¤øç=|Y ’¡n’4¤!P}›Àø´yÅ3}å¾rR¢ë5ŠŸÊ÷¾Ý[B\ÚX½¢€ô¤©"ëž—@NÜ‚¼þ“È^zž¶ó›6½c¼˜zù„_w­¶—®ª0˜F•£ó Üût1bγmZ¿§¯ªx’<5 Mdßö5x«ÔO¿Â;Cê Íæù%-Ñ(šßZ)é߉áãLÓìí`ç×4l,hXÆ×òÞñã¾ÃÔä‡(9q*‹ef@‚$@ï4Z_ƒÊ’€€ÞSXäÆoX.t‡ç ç eò6TÅjàPüÀ–Õ<~ãm!¬#Eë•çö <¯þ¢Ñ´²ë§O'ܹ’I•lò‹™lz ¨Ÿ;¥1-¿²pŒ»”ž¥ò!àöfÊ-€Ïu ;8ΑJ„þÏUEãÎ… lDZSG߇pvÁ÷#t˜!wAæè³XÁf"ŠùR/lÁ7©z¾]š|ìÑ&'v8dÞÍÄp: Lvt ÙBÈ7‹1fÆ'ùXw2•J.ÐiŒÐÙלpg;ä~|j©›ÒæKÿ†p4uã€QÞÐüóm¡;5CèVŠCÅcê¯ëL;G­åCB{z5ˆÖô3K|êhDÝW`Ó¶ ¢Ï½gî\â¹­|m;ù€‹¾cÃÇÃɘÜÀFrßb³y¹ ¸î|<4Úô·±VYÊ2Îø†r!½éœA=írÄÂÚ¾Ò÷À â”ýq„ì\Ä¿ˆ$âdóâݘ¢˜ ÇÐñ6q€Z]¿I«¾Õ-Lå ØD•ÄûL‹V¸Ê(²±T¬‹VQŽj.¯)ü( t+Á¼ö£i—Ð:¼…¡Jç¨ œd‡múT¥„´ØöÿŠBcÉCF±æjñÜù8Àèö›ÿ.6³}Ì„Ñ.1b-PÓ°kuQ¿ËðÚræÕPŸ­æE2‚aV%*ßâíꈸ£X½f 9wþØbxRD¦¾ós4´J$ z6¨Æ?v%Rý`ß쎙}âIõtãR¸C(j'p¾M¿€ dðT¢ûYñ»¾á›[3àжy!ò×-zw5—Ú¿Ø: ±êÿ¯ìN¾@®ëf|ɦ‰yï£ÒÐÓ Bÿ.¿×SpµÅÉRk…1²KB°äEf²ì¤Ç]?*ÔØå‰ø‘ëz n Ôd e°«»Öš_rHÿ>l J1פÛG*ä¢ 1ìó5šS; ßS%dšê÷¯qíÖèñß[~çÁý9¼Ë§´˜™í9¡Mù΀àèMh`%Dü›ôf*%‹øêŒÞ°Ÿ}ÆŒV0ó."FÍo E}…‡†á×øXvñ¬½nésãš{>BvZXß͹özºÏ{Ï'šÙ»oféWÂxg¢D $,·Ú?n¥•EÂÛ ÇÍzëB’€€·ÜâßÂè*É+NÁ®GúŽ( ýÇžïV瑇yO y)X¤“€X*¥CŸ‹Ð9jÌÜ/A`æ—Ò•—SZrÏ/¦IqmøQs ÖxÔÆ©dÒN½ÀM_‹ù?/ˆÖT¼~"t— :HÊ [¤Jb^è?ѧÖ&hnöVŽ:»½‚ né„©wmåÅ£!Еé‡ým®ÊSCÓƒ4J˜[’;¸\" ?ÈO‘÷~Ç›`<}vU‹Q@©æ•ÝÒ…á£R9ÙÝ};Â!É);Õ]Ê"Îoú¿¸.D›7u…×Ô{’ÐD8]Ø(á'& Òßx j+Ù…>Cè•fšÇ™¸ÌÎeh=Ú)õ½ £EVÖ6Ývª‡Yf,°ãÕ*%èa ¾Î mò¸Ž’A”ݼ ne'tk>/ßZýo Qû g~f¡òÜŽÊaø&°œÍ—¸sŸe†f­?G††öˆG¶н"”¨ƒtidQ@Ûzw!Œ$®À RFÁ”“¥èÜ•àw“%5ÓÐá'5U#–êÕn¡âö:H6™ŠŒ?MuŽîUÇG†Õ«Ÿ(Bb*a4Ç®¼F Ø´Ééú E Úˆž~ÕµÐo8SïÒ qdÉ" î›´Dæs¼«iÉ$ÍoO\– ,_êmH1é¢Û)0|˜PÚ‹âãOñ 2R36A ·ËØ-ÓtAâU®#ËÝ+îÏD~ëÜNÒ©¥³Êvç8_—蕈ß-JM„Ðùöþ3ÓŒ¡—ûÙy€KµŸôÜL‰oÑÛÿ?ÙËç°4mDr™û ¥Æ’BÇÏÜ6ÈT÷9E˜5¶‰à¯âô)Év[¾ÿšsÃWáÃx÷Y>émŲZ£=…?è'@“¹Y€?é VR jÉ™9ÛóŒiç¤Pð toiÒ.á8ÙDídñXʪ#R0Òf8BÊ?ßVøÞ¥#µ}).Þ*eçV¼”[“;þg ¶ð lo¶•dð*Ì‹áÝæºD«0‚ŠÈ*}gà•·#¡^ ¤À÷!‹ù²ú\ïcBWA}ã{wÛÞoZ¿(ÛƒnQyùÈ鯽»¥U[ ¬BÈÌîÂG §âsS·È:d…ƒ¼ëº›ç=7\eÐ’€€ŸØM0–âˆÀ˜tƒ‹PFµ*\4;‘¢í–F+È*$¦È‚ýAr°Ôó`wKƒ}²bUTw“íOxœÉBå§8ˆ\hÓùqÕ}~pÞé/óÊç -[#±»øjQ¦{€Y»Èö*É£ÒŒPZ@°Ú÷i\Žû£UW03kpÙ‘ª°Ý\ñTë£îuZOEXâ¥G$SÂE‰Ö‹Êî%¬…ö=ÐÖ†œ£¼f›ÿ©èŒ7•Ê‹Ÿ?. n[üÞ_Xý=ú5A*`QDõ±HóGWˆë…VýÜ™“W –¦;'3å}qu+¾&<ÙZÇy€x7ö€Á:›Aí¢Sʮ냢U¸…ñ½Çi@Zûê–"Ê@¨ð»Ñ$i sß7)/É—è#²-óøÌãjzá‰2m}³ ‡Qj>ø©è†¾¤!MŸßù¼”Í«Z^AN„Lê–˰ú‚|¼ƒ]ÝZͶ؅cÎÐNwa+w±¯fq*&X9Ê'Vg±·Ë,ËjE°Ð¬â]¹ÿ5“´û zÁÿ/WÞ…\®æR.k3´±¿Ir€}åéè©gßæ0ƒQ¾)$b:1˺ìe§rÚ*ŒÐ3mÕE ØP=4u _Y#.,bôΘ±g†öóY8ãP® ]¹š¨Þ©”žºQAäà]/¼´»ä(2€ùþ@N¥-VÙwqŒÛ¾¥-°û ¼#Ь/)Š$ËÛx+×ÞcŒî\ØZ¿§x'„”Ï/qëA9؇ß"ÐfBY!ÿì+ñ|xk¥D¤ ôÁw@"® i‹Æ›qGÄi?ñ¼£@×-ŬÝ}Ô?UŸbÜÄL]ŽÖ¢ã³ s„¨Ú¢“]( -tíT´nšÙ 5¬ÉÕà?¹×Åì˜}Ãò¨=‡I)ƒÑPöƒnÍpsEú­K«Ï¡eý²¤Ü3š¹'ådŸáÅyo?VVû¬K}òœä¾rBsÆíK9lÚ@¯gæ&á[\ “_ÕÊÙKù˜ ×n¡<\k*ŸYìÁ¨ÔHüUì{†›ÞK:ÕèÉœø2ù£)KŸ´”@\áÑØkNñQàD=¦hµÌ¬zÆá6ÀkA"1Ù8O€ÛocÛwðpZ„¹-0¨ò/ ‹ºy­§b¹ C# ^N4”®Ìî§ü£"/ž’SÕCS1dVRÌžB>¾6 #6>wI;ÿó€ Á4o¾$Ö’]1~¯9õÒ&j„`Ý·Ù¾wñuùú‡Jýˆ¯JC:÷ÿ ibù–ŒUß[UP–·ÌNáÇ:ûÃYðÚmò‘Ù´=×Ö¶¡¯g•ž¢Ï¡t¼@ LÐìÌ;|K´—KÜãg Oœm0cèÀ’€€¶ÜÞº•…Õœ0èìœs øÁ 6çÿ²÷ÙÝ”=á»0g+öwdå cdàøÆÔ÷kþy!ÇD·ß×>mca¹éœe9uü×(|^ü9¸}G%Ë˵‹± s¥”- š­œnîÅgFØu¦iÕu9„ gtg‰eïYóg>Á֚ʶ šçç…ØEÑö›¤˜ÞÂðD…^HçüÞ"›8\«s™u¿‰œÄîBÓ´5vd2—0†<\l[êAáJ‰§µ&b®7 ­›§‰*Ä,QÉ)Õ™¶nÄpõÕ~>Ô½0èòå aâ´»]Øo^’*·d™–;³V®´rW%ÞûyØÃ¨Ic´A×Ï€Çx ±ƒ{‹[•á\^†*@ªx®´aým«ÂŒÈŸ8¼E§1ó_öU®P‡jÔLÇI¶P[Íú—Óm.òÔþ"¥;ÈúyéúYÏŽù£ïìUåGiµ»@©Nö09ý½V  À"p:Ÿ•X´J}X/v (Ý»=:·ëõÜëO¯JÓ“f¤°ÞŠNµY_Í`oÑ9_ÍdÁa˜öÍðgÏ#ZŽf.vߨImƒÃvö¯wðš¿àÖƒÒc8®]ö ¹Wy2×G ޼V‡½BŸihÞ:Þ³—Ú[£H@Ù¯ZTr?þw$Þ•ÑÛ€i\ówŠYÇêSì‹ñÊ‚¡`M¢ÂÚu“¿ØôfrV! nAðWOéNȯf§-lÕnèžEš — z‚ÀÓÛg÷ì'œôeØN“ù}ö£´í^m÷n‘e”Ó’ê‘WÄ˹3çøá€ÄÞ/œ6U6“[0e{Oþ`Hm µŠ €WÃä½^Ç-eç$X&¦ßÌÁ ì[VFb ÕBU–ÊøæF1¼õÁ— ¶œ‡w]œóÕ˜‚ªÓ2obI$k;xuVÿ}¨qøQšzœØ¤ÐX§ ùƒH×þö²¸•©x%7á1ßøfwÙ;~Âñ1$ˆ“,ŒÌ[º+åöÇûÖüõ¢ª—’J`͈ó#Üœ§aK³/³þ%v¿”¤Q#¿ãÕ8CJ1êùB%Sá̬âPv?@¤ÚD=ÿµò7‘ÙTâ¬È¢ÝÏ^ì2SXÊ[G-Wɶ•®¤y¤¯1vs5ÖÆlÚÀ7®-—îënœ‘qã©ïGG®y7¬èDS±·Á ñš˜Í#rÿKmP'z0žê5e/vÛß=úÓã›Fn¼ºt ùhŸ¥‹îkúݮʀ"·'º)–É{_ÞC1”±¸'õ㳕Rb*¢Žú¯ï[Á _c„Z ‹¿“†©–ƒš(tp=ßõO ó·úÊæB‘›{RHqßÁ' żO·YRo‡§“‹)9’—S,‹¬'bú<:]ƶSy•ÈC)‚2õdæˆ;'Nn‰|’€€É»ä_ÆYºS†¸6]6Äwmä`i®T“™+F q?­±OVù53dò¼¤uv> yæj-oú’Æ INÛãÝÿÊ,)Ì21ÎD˜ ŒK5·ê¼\ã©âaؾi¹Íi'Ë/³ò_qqcB®9~UŠÜoø› ¶¥¢.ªB¶Ï‹IcÄÚ„ðŠY›'þðÇ"¸œÿžžÍÚÆLñÜ=# )MFö¾E‰µ}ÒOO6w¤Å,‹o\ï2â­`8ý*æ®ÇŒßÞ¯ôS³,4 "H¸3Ú1dØ|$55S³¶‰HõVßÙ¹Ù8&(~еØ–9« gÚ3PÏV¹ZÒÓt¼w¿*ôª{©T“¤_ÆXžšpXòT¸_Áåçìæþîsó•5C†!è4•¤ÌÞ$ª5@BnÃK¥³j6jlXŽ«~­=ý–Ëý(´¾OÀ· „»°UM¡ÁÓ̸K\ÁIÖK`ôÁüŠT>š†Ëö96@¢¿‡»JÖ’80:ýi±?bÕøÒÏ òõrP`laœ-Ãã‰DÖõe+ûœrOìÁÎU¸ÝšÁ/r‚ǯø­ûŒŒRó^b®ÑfêfÄ"D.qùš™A%€Ïô½7újÔc(+6j€MûX’m‘ë–ìºËÜëa‘>1~®¯SAä4¸)I»¶ÌíT‹ JYMÅWXæ?…&k¿X&ÿQ3åñî—¯}öx_ Ù%«f储è÷·~"»°,°e¢ˆ×‚¼˜¡É­ç¦'üy!¢J<+ýªDÏ+1Uz®ŠãƒÉ?Cì" …*¯&zêëqò²x\ $8 LgþjâMÌ—šTKÊzÒo9ã÷ÄÆm¤°¿nZï”Í“>ÑæH•Æó¢Ÿ~¡Ý©p?Ÿ:ºT”÷~ÆË˜ZŽë´“'ͤ#þØ$¯¢ULt` ×Uˆ9 ¦âèìih$ÿ.ªíZµ×ûm¹¼‰ºˆøêQPáâíw¬£´ ÷­‹“õ0È!äßÞ†ãð‚>2[ÏÁ4³u)[~=_Éà-ô[béYª¦òZó:ÛRNEÃR<¶‡úWläã®ÚƒvX~fĺ~M”ÇžzÈšÍVÚZ7tË}ÿ,”)Q÷ŽMV­Þo¨ë~§Úäk¼˜E® ª¨RÈ4„Ë’i0m×ò’€€ ASìŒìИ.²+²ƒvÕºxaw Ù+1ßL(©lßêÑt¨Îf(z§iSÜ#[‰u½LÒy’µUS?@ÒÝ2änámÂòcý Z§`Þ8Y¯ábqGWøB#G“ͼºï_ì>jˆ\í¡¢¾0ôÞ̹¦xh¥D `jclB?•¾,E°]òß®K º´À¨-. ^ Ô Í×ú¡@2H9¤ùNn%ð³öë—ñeÁÿ –™„q…NbIOhA‡gðužé²ëXî…û… x îGÄ{É_€h9ÖÜ`Û4ý @ „þ=›µ×W¼+%ÑýI’7‰!óÙŽÏ óvñt|qÛ§yÈ·{%š>4‡*ó  ¤N *óûôÊÓIZ†nkñŸø¾ÑúßîòÈÑØ`–‹4¢t°ì´º€üázšÏG…L²e‹ï…£èרaøu‹1Ň{Ð%ÆDiž*l|¨Ô—‰ä°Õ²Y¼Š—ô@ï~éµÁM7UfþqÞÄÑ8{畼= y ¡ø„?VGuâAr7c—ºU9lêØu°¥ÁB©‘Ú Fbpô ý[8ìd8Ÿìt+Bìîߺän ÀÑd2+F@„Áax%r›°¶êQ½à…sùBöÎ6ò½‰›Õ¾<é¢^[Î…È’¤ýpÖP¢ÒмZ:*€c¹0.eºë©B°úÈÙî2Ânüœ¹Yç ¥XËfÇú•…ÆhˆŽ¾îŸ£Ö‚™¿0„ˉ¯Øûìßaö•ŒÈ2Dü™žýUÞ¨GWë¢pÚ§ùXB Wçeµ^‚qGùJ+K†KíîëÔ˜ÃÆvº˜H¸æÉ)m·›xŽË:þþˆßaL‰Õ›Y({CÉéùŸO01è>ÝÓ%áw`FZ ÇòŸ–OQ,zÿQÅ•Dî|#˜áMëOføTùTݵið[îö÷bÑŒN&Û‚ƒ³ÛJV×4 çn‰ŠJí囿ø> ÃoÀxîù›×¢àäÁ.ªÁÒºg.³$êªÖPãã>Ƀ°†8~<Ã|ºG‹=ûØ¡øô(@H…7pÐajÚDÅJšîÄ<¡`£Szˆ(ñAÍêjqÅ.˜Ù†øöÕw·Å9g}Œ¡ŠÌx²Õ`ri?¾ŒæÊÕv,ÈËoÉPSO%„’€€Ü¯Úó¼~ñi·K‰Ô‰osṵ̀¡U„7ªÇ¶…`CÝoïnÄFô¶`Aœ1)¬iÐúܫŰþ±“  ;‡¶°WýÀàSa߯ñª•žP$¥±Ú‡rËíÕO¾æ¤ðÒ§˜iŸêhLüŠ¿(#V¯ìžÍ™vöB‡÷“ß Ö„%áƸæ'&Eéň½ ¹Ús ñ›³†jÔÑNPŠ0…Õ¤=´x9ÂûD¦Êôöáö«F\Ä{™›ÁCéëYÌÃÍ´î0³+xxœ?öÐOZí‰^N°z[ûêðµ±éæ’õÆÚlÀœèŠêu1ú0ý5{˜ç.=Ó¡òšiJ› lÑñÔÒ†)hEü‰~¬¨Ú8ÝjEáR¢1ø{raW&›ëòbüSF=ù¨IÂv›"ܦºÝá|ÂeZm‚q†s å¤©ð`·‘ˆ"Á=0€]ÄwCû'µþÁïýXN¸Mp;áú’»n;zÂÞ¸àt³AŠG0ñcèzCJCØp›F©½ÂI-·øqÛÓ›@–üª¾æÍ²wc£]™†»ä¹!—"1üÄ!_,2ê!(Wnø5+Æ\Gù?Aù‚Ö>ÏŽ!iB|£xI¯-:º.é0N* ¦ˆÏ³«¶ë×ÐtCH¯Û‚\m“Yñ Œ$„;Vt’ã¦ašyW”Û‘pªÁÊ“wˆõ;¶®Há^\Ñ’)$˜“óC ~ìÉKÒLBßþR±Éèjf×êÿu}úÃl(GŠlvè3âmÝŽXð¦þ<9Ðåñû“þê£iR”åòŸÀù Š6 m¥ô®Œ­ÇW÷‰[ »ßÿ|åÛÈ’€€»‘mM8qëfåâ³÷_6(ûa•–L°Ü€þ3Lº^¤=SÈ!ƒ —“ù9±˜¹Ãd£òý©„¶³Ñ‹¹(G :©ôT4²¯Ü¹‹J)Ãlšî¡B»—-w 5hQï© ¨û‘¦7ëšs[ Ø=ð’Ñ[a"9C›¤h´ÖÈ/ÔzÇs(j:•wr;X-«²NÝœE^+oœ¯·Áÿ躨&à¹?Fc„}T‰¡r¾a„ŽhþIíÑëRÙeZî%Ç:Q»«‡lÜô»s|Ùšsf jYÚ8t´6?h¥¬ô³[µg=B)ˆç÷©Ýû)–èÒÑ|ûŠvÐìÁÝ”.ªr•HY0¶£Ëd¨¼h2‹Ú±.¶ˆËÊ*>rÖ€ÃÀ ¾®`—[)þ-‡O×m‘  _OzÓTbÌ6¥Ç@Fn9Æ/¾­jCɨŽOmu%_ì"”â°aAÉ¢=%PY±©W±òY쀙U(Kkr`·VG—ô€øŒ­šêâñ5»2þR`ûǰôåŸçhç[×Tõ°3m޽¼*PŠªºzŸ¦ø©ïÇ»ÞM¤?Í&y~!œ‹Þs¨Òn9·û =â/9­ 8qUêéÐôçlÁþ¶jpâ òârj¦6^ÿm(ˆÔ¦–ýhÖT¢³®/Sº“þÌ[¤Œ“Ó Ó+ÓŽ”B¨P‰i£îüe 4®RF{›ÁDÏϽôŒ¾ˆ#èôæÙšÀNrÈ6 hø_ÈÕ†ñ…·J½Ä©-ðF®·ä…$ì(ŒÞ°‚* u•ÖÖócBðÒ “ÀO¼ÏÛCŽ?z½ÖÈÌäƒ}ö=Ú†(ÙýGŸ9>‹ÓñO)`n*âñÔ@ŸöTêVWú•¹ù½Wb~q9:Ï<þø'é’+Öõðz{Èæs0¡¡¢´s-Ð2F¯nç(³Jµ·aQØ«hÞñ• F*Wl7¬~eŠTêœÖLúj=kŸñöNf¤ëê½2æPSáL’€€ô07ï¢îÄO1­IãÒrPTæÅÍRÀ‡Ú,À´¬õˆß÷„‰ÐŽõÅ»]:†‡ªA}¢ûeâ×ã¶.$|¤°ªÖåž?ׯ‹k§ÓæŸGUiÍa¯û7’þ7ÖïÐðÖÐR¸ÒõÊ»ˆb@ã¬-V.tA@ÈK¹(˜~ÜwÐó§|D}¶®lP’¾Kõ"KÒ°õ¥¡‘ÿ*F€.Éå ‘ù9tJxÂùsë¹»ÉÚ¦Á\;A¸e#rSl¹Ùg$mFEEæ[hÀ=&MTjÜ\­c‹CºªaÌð§À‚UfPíFÌ“•Ç»| ¾án6DjôW§TÀ r&³œiÅ:wyqä¡ Šè“×í}}è~âg†!#(¾Òx" 4ÿ£­þ@Z½s« Â,£-ÇàL°)‰”¾ ç ÈUcámýµi5þØ(Î2žf¼ŽI¡¥/ÖJÛëŸ'ô5OñQÆããVWW¶ÊœÄgY%ù9KGdn@6Ç'iƒœí_ƒ„êôL˜-F‘›/ñ/Vùþ®š öÍ0æå6l'ÕõÞ%‹J<µ„¶"Yˆé~"jÕ”ñxׇE,qu¥›®?‚r$ÚØá¯Ë•ð¹ôX¹qÿ“AbÃÉÑOìè_n/ªƒØ¦ÛÂ|mv† )ZK¤—\æù¯3#]é¼+ã‰]ÞfÚüïZË *–:aû›_çæ/…iÚÏç¼B8b¿nèÖRR~ó0­_‡Ê—ÃŽþœŸ+Žþ]†í“Y%ÂqâW ¹öd3 ÷þ®›ò~Èä¹J+¾®ÜP’x_6û‚ÁÅ\`2ãœs©Œ¸D„>ß`Êå\¡‹CJäÁöïÇkC;Q³›GZaK.6íä1™ÅRðX9ÐØ_—’€€´'nÎÈq%ÝèOÇéëôË_r.¿U4®–ãþ¤`6½íKÛyŽ8¸;W” °jø@•ߤi›Ó<Šñ±Âù¿WT^l³~’ åxõqº1æÁ½àéúÈ`Oúóº <ß-ÂxxZD±z¢Ž[…—_À‹ 6a$Ð1ƒ[yÄmÙ[ü|Hý±Y¸w:#‰`Ãä÷ÇM4”²§€Au”¼b^'1=ãO›Ð=t@ÛDÔèOÂY#ãh‘lígYÒD¿rzêç㕚ÓH† °äÊõÃÏó;ù†¿.Y¼„ñîO‡è¦ "|HÍÏÆê?DŒÚ ü×™E Cº¿öþâÿ²¸ÈTgH÷B,ÏÎzJâ,ŒíQ³\¶ûð?²’œZ=¥£×ͨ9ã}Rù‹N\0 ï²ÂƯO•ï(ö#ÒY•=Ò`×U[Âv[æ=õT& ýòÓ;‹Š+@ž|ÖƒÊÜÈŽ;t®ˆ^_÷ž â~+Þå§b©øn>rš©DÙ›a#¢'D´ ®’°D¶Ón¯‘¢?bXà*µ± ã¿¯+¨ÖÐ\o”G°Ô!™ÈQµªÙ;ù#jžĒÙà5H¸ŸÿDö6˜«Àà¦ÖoläHÁ\nÑCéÓ5c••5»”nQÐøngµj2>nz"ÊÚ¹ù¸³åÛçVʖ禆.ÅDîx»;׺W2L=š¢|¬er ñÓb?ܪ<¦…ºíZiúÊECt$RàÓ}e½œ mEm¥]©iõSyׄG4¾j6tÑáÀßs¸Ôaç?‹ÜÞ‚[…AxÊJªÌן*ßÜÞVfÁ} ©­ëÇ\|ˆCžãÁö¥±.NètÝÙ5 ÈÂè#ΡþýÜ±ë ®ìf1hìHsˆA’på·Jßbhf=¢C01†£CŒ=x‰#^Ô{ÀUU³ñJ¯.†ñÇv©c;øá–“ÉJ—d Ü?òlv“mAÚë  ¸àD½šü8‚û‹ÀØøá½ÃEõƒô„FdªÛ=‡DöÑ9&&T·É˜å€O'f?ìA7ܶ6ì¾ø|ݰQC< þŒòSZ©™XŒGc‚ã¹3÷ÄŸh íØÚ%/Ù¬êÒo¾òõé ‹O•Œ¨då*¦ááž-‰¸ÝNLg±MãŒÛê/Äý¼ˆõMÚ’€€ÊñÊÛ™Æoèĺ—ÚLĉcdI€hƒ­5†tÀA6kÚlhÄÒMœ‡XlI—‚té=¤÷¢ˆ²²(rc*€¹Úe)p™ØýøœØ«Ÿ†²Û÷[bp:踶‹Of0»™JChÞmKgsTI.eT«!¿‰À>+÷Ò­§žU÷'§Ý‚þÍEÞ)]GÍÓ™õçP•äÿ0>Ë©Zû µbƒ4{ß?4J*õó|á븂 ¬.ĘâÝÏy5ÎÏÖÿçìJÈ‹:›AɲqšëáÝ÷ª€ ›3ûÖO×GL¯/g¿…uÉú”5,)”>lÆß^Ï Nç4l¡¯; õw~OÚDú‚\õÒ®òMÝäj[;1é MD¹v¾y½]¸~OØZq (è)¡Baãr¼}äèGPiO3½ÚŽo« ]eØ‘ü²®çzH›=z¨5Ö,ù©Â5ÉCr^" òç•0«*4/ºÔ,4å’@K1±G]±¢¿þæ‡l#»§ñ«Ò\¦ƒeiKHœ°eåz²ʶâ-¦˜82Ü4»±MzF ³ôô(ñ9fà½uûc-%îa¬\‰?šë@´ü\à|¥+\:n)¿'¢úOø˜0â ãpUqFÖ|÷6‰¡LÔ!Pnì •šŒ…¬,9ÿh~ó³šr2ÔrͱtCÏx¬Ñz6 8Áóë{9G|‰ÎÛDwоMž|]sΙ£™QÄwzõþØ‹‘R­½´Xt:¼±HzÂú€wÕË ÍÏÀï ­pÐ6¥Ibò>Ö¤9tȰ’_5³ƒt7yê€D¿[‹„JòÕH)Ëj-nðoý€æÄÐëÝòp_ëœoâ¶6¯Þ°±÷Y×™SÒˆë0yP d[ºïo±Ó³âœÇâ”ÃÒy¦Ÿ÷ :xN·]`YwW-ŸÓ€ÍQ+PÞ3Ýò«¥þRô®Á´-?°2¹ýÔùƹ|òýçç¼Gµ‚^ýš¥Íí\å˜Ö³,’4†=IóhüYØe™f%+j©ì©î¼nÔž°ŽçÝÂ6a+ aäª %âw¬z¹»Œš^&ˆrß:T09ªlÃÆ`ƒ^ŠÕ×l‚WR™Ÿè_ˆH‘õe¥øR7Ž¸Îæp|ÅüЈœµ&]Ó¦’€€’×#И¨Ì÷%~+D‘Qw.ùio#Þ‚Üœ¶˜‹ÍFE´þŒ[c¿pëëoJ#Ä÷“⿨í0Aeþ ¼ÀW°êRtÉðžJɲîÍáΕéÂßr¬þ)ˆ±•&†ÈùÔ%Ã|mªùZӇ哸¼_茮ê÷¿\Þežv+?ËhHì”=w#Œs/^t…à^;|MZÕ¾QžG]ÛRíH‚­‡LsŠžêPY RžÞÛ(šÜ4ƒ7¿Y!)&I²Y÷áüƒèÖ UxS…oQ€õ§cš´•T Gž`œÌçn$AÇWÕÇ6kò`o=\žÏ•c‹Š ónh£‚_œäEÌfϹú.‘oÒ¯£Véóì>ŒnœåSƒ.gɆçž‹¢8X'óMÊIY›dàà”s_êZv@!ûáˆo=Nªš–À¹'Íx\le–>Heæi°³,=n°”ºJs¯¹¦ižµ ü!u©Òúå×xÀEìp—i-7¶¸Ÿ€F«‡b|ýë¾ØàŒ´Ñ(hÜ´Y^½Qža)ã^žµ¿Üvô kuØó¶ú¢±³w&·aYî(ì XèdàZ?Atª^W#ŽTʸÖõ©²|™Uq/‘¼°®ƒîªàµ'kûXãOÙAÂ$úG–œÐUàÜâàOÝD ["u¶¸ÚˆY®êÏZÙÿÔìç=¶ˆtmŽtÌWs+{ BA¹+—þ3¬wLìì%láÂT¸Y£OÊ™µÄsÜ^ÔSñ%…ué†ß]Èeçñ™Î|ú.Í`!r6ið•?¦Ø,z …Œµ¾ž™ÁŸå¦½ s¼:ô ˜¢fmHKKx>øô–lÖuŸRzöÕK±C–㹎²¸VpøÌò˜¿zÍQâr.T‘} ¦ýG×úÒùƒ~=rç‘2ï6æyø>áÙÉînvÇŠíµ[å\FšâUQž*ï‘––7uâ¢Ó¬³_Ë·‰^Lø¬Ç?ý˜ " *ò¿j#×R$P‡ðºZÞr¥¿ßäSÅß¼úª˜÷B-Кq£4^Š>ltßû·þ,=sСQ8\ x·ÉŸx¢nàwC æÏW¢†.mbׯQ¢øZe<ùK®ØÕ –# ¹T®eÈ•ò2Ä]$±l’€€£6Üè rQËIH¾tèØ¼ˆœuã!ú*šHf£ÓZ/ÃßqÌCÍb±7§ 1+Õ_W`ÂÓǸצgPÆÖ¶‹;ê€!:Ú ¶ÚP¤þub6 A:R4^*fËqFϳ_‹?þB^L’ûœ8Of<óˆAóO˜»Öeö)oµEtæš¾©°sN¤ÜÚà¦zYÍ//jMzž¢ô]èö[AÄ>‰:Äná;dAðkR^ïh–?/¥D Í(ŠgœG&Ys­ZŒQ·Ðu–Z˘)G¦Î-SÛoükï›6 œTÇ×"PT"3×(7ˆ%½š&«ÀX·„à•«‡êÅý‡_Œ'IPÿˆï½ËR[k‡7mîÐ]ÁA™púÇ5>`4ñí~1„Þ–p5’¬OÈ ñÌÊ$òÂå\£{VUD8 9ˆFCÎ…7曆îÉš7¢ì9 þ21…lªòøCþP;M¾ôtíb§Ð’#t¦RÃï+ŠqæFCíwˆñ½³œ±ÒáBFü 4r‚©T“ñÌ¡ ù¸áÇ$úätöM>þUfoö¼œÑÿ„º©åM À}³ë‹`²džU`"fý^.׋ÄßBݻ톘@Êë¶€hÏ ÷U7ìÍ•ÓêrþÚ”=Fᾌn\>ÌèêQ¯“/Ù 0ÛWÆÜå·Î¶ÓžI’²Þ¼­,+¨õ’k‹Ù q=%)gÇç¨ÉÁ<Ó9ú©eŽhX#õHÞS‘¬lk%Ìz]¨’ÅùõÄK¦-¤_“}S§j”Î85MAg^™©§ÐÒnù5¸[)ôgÓØÎ8ñí2¯U¥EPûšƒpåi$SO~‘rÁàÅÛ²ýÑpk~Ü,a„¬É ì_ æ$í¬y¼15Y_OÏ{2¦«Ü*䘑þG÷ Ée:LªûìŸu²¢n¤Þ!à5íÜïÕp&´Ãs¡Ë˜E³ª:Øsk3ò–³bM”dð7¶+@çÑZj;™E÷h¡,ë©]Rn¢Åžîaì$;sñn`óÔ}Ì7ßÛÆê°Qº\ í&†‡-‘@«ÖÊÒiÖ=¿Õºup§b$—PÐ,áÍnT ŠÍtØ–ìþR‘—[sñÑkôYO‡ßã#ñY`ëI XY¨"ò_´²Èw°iVìé¿Õ“¼•2 ‹#Q†#›L'rX ¾Ua5rpҮȒzí¨çŽh˯ւuøzð™žH’€€¥ŸŠóì©XA¦(à —Ê zÞ*±†Xº+Òº­)RçoÇù).f…f @ˆ`-nþô±áª&Dß&ÄøW‚Á¯N™ÙT°:²èÌÜ»ýä•_‹ƒ·ØŽ¹OëŠÅŠ2Oõ¢õÃŪ³Û.MÇ9`6´Iì®XÃí,ÌñÆ7ÁÑ ‰$Œ-j,¦È{딂z(+Ééˆrné|ô²X!—õ–V"‹^§À«îaE™VZð<÷gÞr¶Ó®¨Ä³ÇO… Ph0šYcù*¥óWûá1¶c}÷3¡”•‰£±£Gjx3ÿ)û853¾…†= ½E€¦¯y6D66׈5 >˜·c-d(¶žh·Œrg¶ÆdÈ0X÷Ùg<ž;ÕQÔèct m.·ÚÔõ)ùe×3õ>·^EJ–f4+Öþl´”ÛkÛYêÝÎßþA…ò¥Ò¨¤<{,¾Ç³dØ®ü®ª™Õê·/ôF6Z•ó¼ÍÌw—žSb´[|f,šŽûÜþ_’&wqEã¥X[mNªÇÞÞåNP¿÷ ° ú60p3'†¦Ñ2þóôžön¢ŠFXó!1ëø‡·-,Dе†íþŽ ÊÙ|b5n?\ß;r(–¹ÚÕ³èN³¨]ЧÔ)Iån8'SùIE¬êlT_Ò‡çÉ@˜ÀéÝåØÀ àÇ®óT<Ï83Òÿn"ƒùÑI!Ý#ŸæÌA@ç?ý¤rœÕ¶ž2TÃÈC7OVä ü¢*gãùô] žrµ…íNôy€y:š\ý ʱÐ,œâ2q°zJI;Öλ6tPùdÜËÉ–F¥RV )?6 ºGÓ9~ôìPH 3Ãe*a4ž¥±RÈÎö GÎ`w½Žä¶™‹p©ô÷é´p5Gñà /+{p´²xÉõÒ]Ey9…vTµBÙò¥Ö¨Á5´ì­4ÈdlòÁ(£íhwTÌåLÙÌ[üúÓ©Ã;aèÖž“µ–9¥”¦©ÒðÛlE.j÷_›AîV¾Ë %#‹N ÕçUB¡8¹Á`ï¡•Lì réæÿHûp Ð¤6𱝍N˜pÖ^¬i¥./2™õ¼ž–ljߥ TѧVJ¼j¤ÚˆÑ]8y¶h‘ãØõ*?¢xTô¾#(¶‘•[‹Ð‰–&TeÒÖµ0ƒk$l¼ 5í‡S’€€É÷’Ž“ÞØ¯Ídoíÿ«ÌA4 χeÖËÏÎw|r»Ãš7g•®øÐá—·5bôÏ´bñ¼õ©mDJ]üÀfOå^ÉáºãßÛŽÑ⬓9Cá´è¼ÒG õÆ ¯c>yCá°*ˆ;(Ê·ÁÀ†HAxB'.!¥pwësEww-%¦ve#·Bm'Î ã<´ô=xTû(•zå*÷Y€moír¥œb˜ »¿Ë¬>B}K?kE »÷LÞ®÷ŸœC€Þ¾KBÚöå® qô)>}…ªCÁœ˜ã¯‹)ËÖÔ#——£¦•RãX\÷ì$žø{šy®Œ‰¢™mãÃÅ É·Þ|-Ü‘!!R¶,bk¥RŽ]Ë#ÓÂ.þ'¡^å:¤\ïOÂ=VæQ’)öÉPÚ·1ø â‚jüW*¤¡]QneÔ:âúcè_¼ãw‚¶â¶&éhÀòt'ozÌž:à H s‡ïtlXE˜£2ÙeåÍ$Ò§ Œu¨qÛ/åWyÍúxí¢aáßÌW>BAWõ ý¬WÂláóSªË;öo[„‹Ÿƒ_ÚÑíß!‚ÏêSVĉ¿ÜýuU¾øJ×FDØËËÃ*ùÆ Î‘iò8)±wŽ4ug™.C„JˆYÞÊ Âš=M¼€Ù1U.t8Ϧ´õÆ,:0¡çÄzß[Ö}°G¨zÊÉTn©ÀBKžgGýÞÃK?„(õT¼ìW4þ#$÷×X ÜŒ¹ VV¶TzX¿Éúο1£><.Zÿðì(ídFÞ˜4@‡Í¬”aô'çiWw"Þ´G§ÄKWðtþì¯Ì Ä…4DTCÛRÝ}ßsRÐM›t|0³Ô‹ R‚JïuHÓÜ5·$'‰@"×ýN¿Vr’¶„/4Ö¹FÕæÓÙá²W·" qV—¸Q€ۈ[¶”ÏÍqˆ\ù6Ùµ¯=²å–iQ(E¿1-Ý®%Ý·#¡œÒU. ¨:•µ¥¶¨ÖGŒxqéŠÂéy¤ÌóÕø8ÍP˜“žnä)‰,žš ×dý‚moó!N}é+ åHî–ZJ‘HëÇrIMÎS-Æ‘érœ¦z²P­bê²ß¤Kê!äIŠ.ÑôÀŒqŒîÀÿ¹ÏíÔÊ¿CÛ«¹]$Ë2ÃÃÜ•‡’€€»öº;m¡>ÿÞ mì :íÏ:µ—Kc”æ¯!ÑY"ì ê22w}Ì–Q–ƒtÌîö,u*3—}ʵ•R†B¹påÔ×­´„CÊp$#KÂÀJ5è˜7M ~‡ÿ¨í‚¸•²ÐfF/’ÙG DÚà N3ø(ÉÎÇ69„µQÙ@ÿó#/ùþQ†c8Ï3Â1;=R¥Ÿ‹TsyÙ{m[ên„§ÙoðÜYš²D˜m¤¢(à›»pXîGyúöåŽÁ8!·(4h;3{\Îx‡qÂ%7ã£8±øyBÑîÍlîÌ)£鮑6y¬ž¹Ñù(fH”ó ¥ÝŒ²$б J±ÜÄ+suÕ~)&d½¾©;Í>²ÞxHîKJB{§ž Kcò]cÇ"âz `^n?ue.÷¨.mm˜Æi‚MÝwÄpfø_SàÞW»j’sªAÜžÞ~§xÌ! F-…âÃÍž¨Q”=_âOó–V—š­H¡#ÝvÏýo¿¨Dý=2»¹uÓ0™*©&£rÍ1!¥×·‹^*[LºßvøÛ:-dïn|¶ØÛŒ;óNT:Ô¦Z$;ÑrãÀ‡¥’ñ¸b*†|à xv-í$ JùË$ª€¹ÈƒÊÿNåIZky³ÿ1å5<í8â÷¶ˆïjh@)*Ô g˜/ëçsÕ­ˆO–¶þlo°Æ¾¾CŒ¤TdwÝ‹kºX>Ué@°pà4·Ëbƒñ'ë´Œ; ¿ÛÙs™¯m´9ö¢@e¸ÆG‡åìn¿~ÝtøŽ:¦:wÁ,Cf˜bB>䯬îUz¤3rNvh½…ÔË#÷/h#1ñëÅÑ(pÞ:Š»\yJÏ•Uxß«”Áj» šö*H ½U3}NŒ)@5ÜôŒø$‹% –,Iô¯¡¡QI• €¹¬Õ -'{'>I“3‘+ôJ'O_5ìåCïpë!ç‹’9¦=;zžû¿­ Úgˆ\»[QpI+O+ì Å™‹F<Ù¡¹½&&ØèßÍ&¶Òñoø|À^uÎòåÃü*.&´çEߘqn•Q¼×s=ž²z„ÆõtµÈXŸ4q³'Jq÷ªŽXA˜yƒ ðhXHÄûð`ÆÄ• K!|ošÑÓ.™evÞëXZ;á’€€¯Ãš]ëø¤©ú²öàV´ð{ï)m~q:µa³û®êªZŸÔ(U;¾÷ËØ \—óÖðaÑMÇÖ>Ã×#¦wöä-©Y¬—îÖq÷W<-t–†'°NÏ @hœën™IAxÅǺÐÛøŒ°iì)xÿÕaµ¯Æ….Å+eI”Yh”t˜¥+hîúÃgüÕ†±ˆp/‹ýGvçVHd‘ž*·^Ï: iÓøA‹M¼ G?Kõ»Sï?Ê1åŽôÄEL¿.GÕûì@÷\¿w…ŒlT;Ãoëa¯,°apüó©ÏÄQÖq9"TÔ,.¡´˜5;Sèž">×\±ŽG‰qÝņÕ'«:]Ó‰ÆÊ’>ªM²ÁYÝjuØ­Æý‡ïÿÚè%OßõM-k…‡Y¼Å½P0ÔOî'é0ÁoÅá¬ZÅ+†ëy!âÒ¹±åXü¼$ÏØ ¹`½ä;ÌAÀ¤™¸"È,v?³€‹#m/l­2È‘CF7¯Ëê#5ÊäBžU‹Œh¸¨YzÊß$ ~òø úq¨ è›8àr•61©ùÀö²rBt÷Ù­)*ÍûÉ¥TU”bûMõ%rŒA’_N*£1Eàbô—+»ÖJH‹)ž5¡ÉPN1á£C4íQËT[pQIãÑÃ㯫ÞTî‡Ñe“|ØŽœä þw*]ý‚ñ&aþ;Nèä=fNÚŸ5êI‡JO°]MˆØnç+¦ª<†=zÞ†<ù;¯áÓóZbž¶™Ö¿Àù½Š0ãô\­K ßÏöºªÔòa=ÒáôKO¢ +h_íÖ£aˆbFvrj‚”aN}³1º² uÌ™’€€Ãà&™ï7{^ˆ]ìxFJöÁgìwÄÓɃóJ^Ùq§Î0YYÓb ãÕOEY鈭.Ç)­ÆÜ‚27Löªa<)IÍ3$ò?q!Q›Ëvተ~tðËâf­eZN<<¢Î$¤ïàUDÞ©³»ÈméfkÇz[²Z7Bï8ªj’SÙ1DZ@…¤÷‡ŸÏâ÷D®±¹aޱvi"ýÒbWoG´_åx}Ó`âÅeá¿õžbaD#+û%/CûJâ2ßp—æùOù^ÊùØ£2¶•¹‹ÏѾÛã.€`>xhA¥¨¨ª•AY^ètŸÖ}?°1Ф&j÷˜˜ÅÃÐâckwü|thðö^M+¾Wb¸“Ï;© Ì*±Âö2J†JÞçOünDN°€¸dšçš Q=Ê䯔Û9)¾ ‡úõàœF–òí£$ö<á—á üL˜Ý;¶hø¨¥§üŸÙ˪J ÜrŠ®,î ~Úø.+#›/®¥±Ù´qž²Z”Œ wÊÅËÕ=“Ct¯É¶©€½ÜhO€ªiwÔC²§ºvÚ°W‹Øz†Ü‘<Ñ„Áó(ÁâŒ|ò¬QÆSByNäÐîø7msºb >|{œ™ì¿^c}ú…&$yVÕšVRÂ`ï u5—e}üϾ+²ZÇÚ…aÐÿ‘‘tÞâ/£«ÆŠ®Vr3¸º¬íõå“o¢‚¦HØu‡@eLÏþ•ó?ÉIÖùÝ7á§SÝVÝÓÈóí˜à² ˜P`8t4iŽ›¼–!jùïÒ¡¿i/ŠûÁÉa “ázÅö™5FþD{œ¬‚0@äH‚ãp‰hv6%A œЀ5 #/8&ÖM'H³Žà. ~¢‚;Ü׳Q̯» @!¼ƒgŠÝÄß`ò´e ó[5z1ùZa²uuâd]Ìåà²0+ÊÅŒ¿ž:ЉÒMâWË8÷óTþJ´’t˜aod¶cQ˜ì¬ 8–ÿi±DÓ‘Ó”[b¦úvOÅäŠÄ¶R¹°:-qßYßGÄ£‹x(%Ì¡µ§ßí@ú&ÜPÚ÷ºàJ`õ³áÇ@å°÷dݼ*°’€€·V;®yêkÚV1´aþq:jåþÕ‰vñ³Ð˲TY[kر¹Se¹ep}=Œ¿˜iM'¡:…¸vÙQŠ ÿ÷‰wçéÉ':Ô2­ýŠAÎc РϜ+.2:ùöºx”´˜KÚ|n@›:Fe+çÔÏ9ePØ­äàÝÅøô1+/÷‰#.#Sq.ïj]†¨eu*oÎÓ»ñ`b÷Êt,Žë—G2¾?¬†¼±Ó˜#hÿ¾š K݈où-¤ùxCŽ}hIýÔò Ç啯‹ÿV•woôß¶=¸Ö˜?RMõäĬÑðœÅ„¢a¬´þlÕS:%èíÖò$1ýb4‡SÊœ)#ˆÌ'ÿà•Ô +¦ÚH3¯MŽ…ùEí1¯Ò:9ŒÅü,0!¹¯ãr&åøÐp‡‡;j>³†ß¤‡óÝXñç` áóùvœGV›–ý‹¦÷VöW€…{jAVw\).‡V_¨­š‘«^U†öë;b$ä¹ “=dteñ?á–ÒxÚt ™¬'»bÓLNÏæ›Í¬NTu7²~Ë„QÉ*ŠÔ¼–ºI§!œóC gã7Œg†Ã×ü¬$(¾‡?nÉ ƒ|o>¹=‚ Ô·|‚ìø*NþMT03;ŸhÑ;;67KðKU€®ªàÔR€âGˆáá_H¸„úHí!Ã3Ì›>¨åž®7›L‰—F^:Ø€( HûБ¿ò¨¿¿ïXXΙ`j²´½6µ©XØ5…C3ðŠ\¬/”žšíçÁ‚b‚þŠ€-?ŠG* †sGhT»ó@uaÅH2y‘}ÑX ß$ãx$¹ƒÐ@‰0$MxÚc§ñ.ÁÛ2xbêÜÜ4+Ëh¤=‚¯:{Òìa³„‹[)y’ÝK¥¿Ùç>Ÿ“ñ\¿ˆ'lŸ÷`¦ºö]YB¶é]£jŽ9lCdö„tIV zk‹/[Àô ÅÒ’ YúÓvx‹dÐ.•ŒN^HŽÃ&€õ—nZ ±A;¯¸]ŠQÆaÛ6Bk&ׄrþ›ËXÑ^×L´4ìËI•µ”PuïàÛ‰¨S¡_ìvýý°’~]3¸iñœtÿ¸&})Å!˜¡ÑMêSPÑ\‰=Ês÷™ ¦­«Y7¢Œ$¡2QÐÜuhÜÎŽ§çã³~7œó³‡ìFÊã[£Ás>•à¾Ê§F j¨ÛŸíx‚ý?æÕ¼ÙÄ.ëþ6(1æ)ÈIÓVr8³bܽ:IX8!¹»ä훿¼5a#»Ž,¶ãP†<{ØÑ)áŸÂ*«cí*KÝAÕ®%ÜÔŸY„Ð(1‘ÿ¢Èó2f+•(Qê¥÷ÒâGì¤p[4._Þ=‡ë=Ïû^çZa]ëeRiEuДC†~‡àMÑšêýï9¥¼Ô#QÎ<õ{u9¬i¹v#-âwxØE¢ÿp<À< bÐúÀàùã_v÷¼fHÐ+,®‘ NÅBt{ÊåÕ/U-2-Ú÷îëË Æ°’{’€€¶VÏfG³Ž’òÆbˆ‹QùT.·F¤Yy;ê?…I­öàÍ+9Žë}f%]?[“u•Í4ÃÞ€• øØM»†æ‰™á7;gî9ÛUú´åvôO¶ìÙˆ+ÀDšWá~}_¹s°×tËÓ¾4:·0 &(ÏKg¥[ó9ëIo<Ÿ§‘Y,nmŸÙVŽ+JhW{Ï›C•÷åh‰Û.©;˜@ËãFƒ‡;†ÝryÀä{)¹^²°”ÿÒóÌÿjc¼Ïë/0ð4„â¸UÕ »T~á‘M›n©Ûÿ>ÜÑ'YÛ~Ye\q÷ ß y9T§?5o_Ð&Ïh˜Í[½H[Ã*Ó2hú3iÃ}Î3?i æ‰Âó}Ì5mºß.Çp¶+Hð&»AQªÜ­?ù„9&:¶ÅÓSI†™¡®Ïy§ùv{zœÒ^ˆGÖí%M>¾×ˆJ‘YM¡^è“MÐ*žAèÎÂÆž¬£°18e›‘½B* ÍÔ¤)û™mxòsÓU‚`ö÷¬`Ê$^§Ô·MeT°–€3(§¿)6CYCoÚ_O¯œÙƪýX=¶È–ŽýRô$³‘dÊŸŸ¿Ë 6ÍÿR–&ª]=úEÅ[H{ß”ú ½84Fé­o§FÉ”šß¾ëjò©$…èhá&C˜Í˜„¯í¹ŒêÂÍ—-8MvÔ„“·Ç þ˺ôëˆÐÇJ4Ó÷ÕZYª ƒl¼¹+‘¸2^ ‚¥ôi…X¤‚Q»Êþ~ä]—òq‰ESçÓkŸ(¥«;L¹ºâ¾¸-ÙI½mûÛõ™+-2U`Gy!íè0>=xåßÈØÛ5uµÂ8GGn."Áà«ÿÜ‹]¬¥ë ¤™qyà÷îÔ1>?›p]ÁYlÖ7•M]Â,H2ôw’‚¸iæ\åBÔØ‰ôŒ|L7™ïÁÃWn ] 8ô 2ð"‰å3åJç´o ï0Ú“Õk…)ʈ2­ºkÎP?€cíÁ\k›%/Z|©Ÿ:çkú Ü‚XÝ5 7Êcžïy+#séhKê‹ œVý Èí™@Å‚qŽ0;#[An”Ä~é–ƒ“„À_2Xp\$Ç\ƒ|%l}ïð–ábFiJêö½²?ç­«¦0míôžºf±rÒ¤«’€€ÜÁ¨_$ÍFx»"P6Ì*è 7l¢•&Ɔ•tÌ¥›†¾¯ìœÌ«FòiB©Þ@×ÔÔÞ1Õ€vºÏL¼÷¥ÊÑšþÍW÷ÐùßÃxãU­#¡Yîý]„ñ=×'^Ý].l…/R]-ÏV?Ÿ¿=œ©¾ýëÅ€?P‰$û•clç[v¿þwsdí R?ÛIJ°!úÖzš¥oÑ'ÁÁ¢ ÃÀ„a½-‘ÙUñ~ø(û«Ñ{‡¼%QqºË>Þ,ð'˜hke’UËÓá‘ w%`MŒx‚ËÛT <:4ýO¯Ê%ËÐç&G´ÃmZU+ðfb:q‡^K ò–Ä^Çg¦®${0£r4Œçâ7ú?e¨z '˜Ùu˜A9ØÜ± JT ºß¬4À\Ær%ˆ©áë õà„Ãïƒ{|-G§ÿè=ŸýÕ¬ºGŒdþƬ8lñQ3ß­íØ/÷;!8ÛÇGþF•z^8:w rËK:@6§&BD/¸³.”Q[â=|ãt3{î®áÏ•@n¤e×]ÛO_õÁ¡÷å³4å ešû^ CY‡Õ°Itî¯=:z™ßmÂö=‚‰Eª±çæ®7 ±ÑÇN]4‘­'ôϵÅÉÐ:pÍç îÅR |¢w$ÙŽÊË (ÂBD±Ÿ1p×\Ë›ùû‡‡“K=]=¨Ê>„×ù¡Ž½ߦ‡1aë°(? Hª˜, á‹S©ìèpmeyS]*ÅÃÃÀ ×ë¶Dýuƒ½2‚iª;X Ú/Ç9·8,•!÷'VœƒÆ´ ÈbÊVÐE¶ò+ô rÙ• œ†tD]D¨à® ÅpžCU­z¹=f˜ükz7›“[=}œ ïðR}‘Òm%Ðçèô¡æxo{”Á@Ûïi1#ÒiüG?²œß³÷í éñdXC”Àbf/]]Ó1Ä4Þ<¤aÄê‰×~ñ(‘V-ûž9»êoNÓÈÄQ,¯ÇÕ‰€uºÓVÞ¿dãˆTô™õ¸”ÖB4÷x´Uiª¥ùØ1õxü‚d©“­¯´ •Ê¥ÇH%_}!im«îÓ‹Œ@doufŠ7•ðå3•è…„'è§ë}AgKQFSc|©ú]³G %ÖÓ?LÉ‚ õç`Ipþ`P×ax’€€ò‹l(î_-[$Ì(P¹(®Ld=›èTü¨„–{+;ÐöïLU}';¸ã¿ Ü^q¨YP!Ÿó²ÚXrì—®Œh0sPuУJæNË{ŸÂí”Í€2óϪß>FNáÄ·~w¸EÄZãw½è©¾J¦> ô—Dˈ¿zÌUb»Eo•˜Zžç€"2«†{`Í ŸÍ^I°¤‡€q¹Þ²ÛpoÞyû4»üªá(,ma¯v4]RPïu¶ÁNBN1 ×ÎÁpe“—ñKn8±Ç7„_‡,gÐO\T^!9>ÐzÖIm˜˜á6ÖòD'àI¥P|“m¯Úß°þ¥ÿ`ÿû;ÃªÜ ¶ŒzõAR¸O¼=ðQû0?­<‘‰ï­L8¶;æ‘i %yßŽç¾ Îÿ±¤¯„Ò¬â^×þbÈ;¨¨BPœ“›àßãþÑSyZ¨Ê~ë …šäöT¥Ö†Í›œ|ÒsCüW_•cù®íß7œ›Lá5–ÎvÝØŒíªŒ/‰ô[ù’ÚÊb"éô7q­Æ*&ôºÆYÔ>³Ü¨ ÐlO:Ž„ùS8_¤˜smSg•ãWû!ˆ¸g–m~׌L¾d÷xùá̺H_|^øl³eé‚9”%0Ò$2rVc²™g¸—CE¾â!ùÂ]þ ›‰x¢w~½cW‡A8†Ð˰~Âè¦ùDòÖT§…ô"ýH"` 0ÈÓä•Hµ6|_Ð?>?Áú%á.v¢ áõ•ÕIÁö ÛeÒ¯ó'cÁöH?ß½×-tŽƒÒS'ô¡¬ Ž,qk´^ØöS¯[-Ãøšåÿúð3æâ—4"nLÇ•«ìnöó•H³f¤%àÊ÷'¼ÿÂlˆ+`å쇃'uZ²CŠäLÙk™lH&ÎâM ×K t‹ìñ Ã|ÙÙë¡òDŠïqŠî<{àX #¹&ÓNc´|qô‰Ç&'€ÀöRúݯü›¥K)Ô ¶¢§Çç·LÌ›ˆLStT‚\-½nJ\s—@áHF‘´Lõ“}øÕUAná¢*®•¥3pJ—»…õÆNq\z¯›X¾5áù€Ôe"½yÔ“û Z‚M*)7 hµ¦9à’~ÇJ  uERõ²2p·€jô\ ’€€°Üm†¸DÕkIÒ?dîùâÿ 6¸MÜÈw…ülÒ Ü €zN¡Fð~rüw ÔJéåZüEδ‚J]9Óøm‡FúU»^ëÒ+Ï‹›ÿò·:®ôφF¤€7$߯£wÓo&œ¿œ‡½ò:ˈnQ¼\ eÊ;Oïù‹…hü_Ä`¬”™T¯Àª‹7C »O®R!¬ü7øÙ ?¶þ³»ñã©ìm´»hÒMó¥éÔçˆdÔOªÊW:"l)’™¯/Ì}MÿîðÔ'XÓ¡y1©®p’½` ¬±ÑKÇw²ŽšÀÔŒƒ¾9C¡·%bË,Ë ŠfÿS,ÀØ¢ßãW]A- ZÙ‚Ó]›ö]eðÀ¼Õ’ hìëF]vµº Õ}ãë±] ŒFº I‰±#tÝ»ïƒdß=bç9ÈžÓ*^ Â³—2Γ«p´†Ð°fnMm±Þ6Þ¬\@ÊeYÏóÜ›ŽäKwkšfî´®Cª¦n¸ »ú)”PG‰ì F`Tí´Ál—ç߯ñݱf-Ë zÑO2õ²ûa„Åš´Ÿ^®|“ «™ÊŠFIä,-³ž¶wFxC_6vÈê}Ì“ŸÐ‘º%È?àTÅ…v3¥¸ƒÑKz܈DIÃøØTœ9a°œCãvhƒÌáâc€* ²36ѯºªøRÁ­ñÈt]¿“ ‹›7s;úõ¿¬-YÑáúx†àåÝL®ŸÀoW,Ñ¥ÔÅ•Â>0¨Ã}uÖ(ù‡½£ äq"¤j ß,¸ÚKËð-|Ù…³ŸsÕ.í<¤ã†ÞPwà"@USÆ&Ø ‘Eµéc‹nb½ÛÌa#6ð±EHüÑSB¬|ðƒ®À‘Ní¾âS¯‘8BÞ_ý¾ùi™†ä1Ô‡q¨ãFŸŸH¨›_D ¡qGsyR[xáÂkyàÛj¼DŸÌ‹¨— u?Þ†/‹§hËS ;Q9%£©ÕgBÕ²˜ìUPÌ9#—™B¢ìNevÉätiä×HÓd¡–kä{$¡Ï{$õ¼Šm6´VÑU²¯ë\E+ ço9ÏüßÜzŠMø+ wÑ«ùKÏ¡ŽÂüAàñ˜Nî°‹vÃ<+³rc45™*b²Ë5lœÀýËjÆòi wG­’€€ÊÌ‹vÜ\éCN “Ö+ÞåÀZÂ4ëav®%F¥Oƒžú>ê3æ-€ ‡L¡¥_PhðÁ= Á·g±aèw‹½yyTÁàg-‰•Ùnh:ªúD®FsÖ›ç†ÃgÊAвŠgø;ÑE§Ö#ƒA‰$ú8'­T`g­ è eM‹òƒª¼.56.eôUÉ"Á‡%U­2ÏVéªÜä–'Lf‰µ,ü)y­ÁòîÎ8 1ŒHT!ì6‰Žj²x¸‹<£®q3 #É|8ÿà×[&U»Ú%€‘ÊšêDnsÊlÛ¢óy¿èFb&ÿáÜV‰=q²šv­œ_­AîZg2€'@¹½9y·*ß%jïÜÿºæŸœ4_ñ^Þ¯—è)>–÷ ÑÀBòDìCe«:ò›PÅøtØt° ü Â’©fr°¹ÃÿdöIí±E¸}ðÄ”EE[l?LD‹=€E^}Ù&,ÿQ/áO§CD9Ýžm4ÿ|8÷BDC ;q•NÃvD µæSþ\ÏNqHæS{û†D³jE”L“ì1Ö:ºésý¬tÈÊIÆ\¸Qú¸8–H”äÕ=ýn÷È(›+·"×¹†3ûÒà ºnø‚ªXÓaðN;qÕŽ¨ãBã!T›4Dô¥Ä1I£üO,Eê,;Î}xd…]‰wAJl±<5=²z‰C MoêÎS@Ä‹y,×oÍyž­O’€€ðŒæeGZàÝNúZÝʬÌþ@òS“¨U#+ Ÿ>¢ϘGafGDcPÏqNÐ}§ð?Á£sªgF.øŠwµ(Œ¬ÒåÖ•ÙøïÂŒ&êmK–'Íã=î¨x™GÝÜsQ”ç9㱿Ú{—â¹Uß‹9‚²v’PFm\b™xðZÙ†q·/Ä'a" »Z¿OìÄp®_cªµyr;!?œ,ŽÍìºê€lolï˜ÄõS"S˜,3R³Søk{\œØË& ød·SÀq“>Ï š»ãvf½jz¹‹ýº yXžåû ÷ä·ùÙüŒv7Ec?Ü‘¥™û—„Hk¶\öºÈõ^V¸²'vc1¡#Sýª_$Š×¤2ã?ªudɺàÁúË!Ä©û$ç ›DÃ<öe€ÅÞ¯hì‡R¹pP ®ïË™¶TïÔQk{ïÁÅŒõ„ØSÙ7º*Z¨#»+@Pç#Ym1Ûí`Õ!Ïkà—˜ùëöÇí³Z4pD¤Ç'ëðv¬0Ó´Û#‹½;ÑÂùÝq qÒBû=l8•>­¸¶çur’Ë2Ã‡Óø TçJcžÆ$,ïsŸÑß—f,èI3âcQ9±éN†dž 5$Zk >WÁn{à3ʺœXÊ1)L}*JŽVK¾0[)úP¾ñmÖ‰ëÆ0´x̶ÖÊzîD]žÐv&(*]´Joo)ëÂ3î¯bÒ§¹áôVYú™¡ýÌ4KzžA ¥)ê¥ñóçsûÓ®=sÀG+ –J¡™þBX­:]\+ }ÆKÀúJÃ#±!øM5ÙYßM¿ùІLv7‰/[4¨ÕÏöb$óñ!¹wª|ýÈÚ@47ÎÉÀ‡,¶8ð†h.9ç × À@bs?aa·iUf=ÅѪ©N÷í^—Â@U>Ç!'˜µš,Q <1‘a¦$ç-mµ°1U*_êFsŠwyþmn¿¸>µÂíw¯¦Q•¯O«˜£ð, ¸šª;ÁÂWΰÖ׸O·H޹JügÜÕQÉ4ÇÖ/ù›˜‚àèºß®~ÍgCS Úx¤'2kóQ%êG±_¨rD—-vRô^`ÊÞ¡¼lEŸ²BÙãÚ®Kò'0 Xbæûp|¢½úÑù ôóÝ‚¥L´äMó{’€€Á7Ìüµ’‘ˆŸ•ñºîóls{/*t#–jÖЫÑwAeTÊ Uhär÷ ~dDWÈmJ³À‚…ÚÏÇ—ê¶«Â: <Õ·’N6å„ù-ù¦Š²ï€/íÁâ¹ïÇyœÁ±6õÁã«(¢b «‘,-ÆaêòžŒáöZe?€Œ ˆ“é¸Kl¯L1NÑ_I0®YÚ îqßl?i’÷þ¨ +æqà!’’Ä2ÉŸ¦$TÎ,Ï L¾•vK8[ „%”ÙjÄÈ×H+¿ØZ›këò8^1lÈæÂ¨JÂÔËÆ&ßUëmZx`8xæ!ñ‹5÷ñÌ3ì£ò—CdMds ¤ŠºykŃœ]Ž®$>A?¹ ô˜3+tÚbƒÒµô l?%D IÛãÞvxj™) …ÍîC',MÕïTçË~•§ÔÖîwF~j #dì)%­ƒ.òUcú7 €ó405ë¼KyŠòbOPßsUø¨ÇvQMœÛGøÄ؃·‹C4ÿ+×þëÝ´rUjÊ ) žžw–âÆ@ð"?ÝN—Â蜚9½Ø¡H곿§ããC£õðPz/Y"ô,*ûs˜ / ¨„êæµ€&C¯^Œz²Fžo‰¿+2½4ìîØ ™è­–µØÒ ðg-q´[WÛr¡Œ7C©oá ÷æœt­råÙ`×õê8§ÙÁ/ Šv¦îtZ1ñïZ£uìÆïŒ…Þ@¢Jg/ØâPýÇ¢ÒQ€þßO2]8utí¥K9ÓéE*ICN›‡\žž-c> ¿ÈÒ2d•TG—Fåbô”^A¸$kPˆCpUÑÎV!Ö„:ô@ƒïÉf´Í|[5Ü«NÈ•±?ȨÙZ¢dº,8ÉÅ› AAìÆ¹"A|¤5s—ºd(ù4ð{–«ÅpÄB"øw¡¼K\ìbOª,jª‡$BØ ˆÎU¾šk£“›O­¶+9UÀ’ËÝòf*9¾Øàãk0'EŸ\KN3ÂGÁÀësÄÄÐËãßS¢"ȼY‚¹n9˜,¯€•={çUð¦êµê’€€ÖÎONÑ0'O¸Ô¤ìå{lë2»jQ#gi‡ì }>ûA¨k•ˆ÷ÚÚrWg3fx˜5ÆÁU¼ºi%ôw‡³YÉ”¯¿© Y+|à’-X•Vy}Ò†Ü{t º‘X?U³WLÓb»þa^wHÝÿDhÎTCä¡ ‰û¹ž„ ìC/C*OÂeD {ê„m €ÿ “Ê0}÷yqüZžZ~‡­ÂÝ"™#¢ä4ú*ˆiL×aÎ1`à*h¬=žb‰!ãí‘àþíP{ökQ}–þn œí„¡ýŒÖ0ÖX™‡Aïeèl6iŸéýÖì $[²¾ÈÒ¸õ¸LŸHÙø¡°Í™{†p®*fc ñ}€H3~)ú º.—†)ôy`¨“V'µmØ‚*®4>Ë„ î³1­“0¬dÔ™ ÕâF$h÷:jv¸‰à–cÓþ ·{¿P¨¬á <´÷ €¹ÝÚúì¥ÖÙI@âpìßêLƒ†Ìéæõ;T|³•®.#\ÈÒâudÙ­#Ä;A0ùÆÈȬ£a2ƒJçxû3`QœñX†R.^qó`·AB$ q*ñÿü¸ÐÙeÊTÇÞv²Š.äkõ÷¿-d0èþ\¤þp’\Q¡‹!ÈÉÉûS&K÷uö·Tê»×œ(l+g§ ÆÝ|"Ö¦ ‹,óÖ ò|þzM#ñŒýûVPMæýªtL&àÚ<9îÓµ†,…»ógwLþü³ä[CÊ»Øë ¾mÆÍ î¹ÏUæǘ8g?kÜ'¡©‘ƒÀ°6é•hý2¿IŒË€–‡¦l߃•Ï´‰¯Œ P±&zžmÆãê Å®òG+‘ÿ‡WWR©àŶÜt½ñK€:Ã:p•º– ®H’J‡¸®Ê¾Ç.bóé+:”oÃ2;vµÅ5åÐ/†ðêœ;uÀØ>òé·¥PmO¶plÄKˆî}Œ:ýíØƒµ:¦B•°ÙÊ1X‘+Àq ŠßÐØñŽ[[KGþ«=îzšF2º™äë‘`¥‡ZÙH"^d l>йrîõÓÝîââÐQUC½£EÖ‰ã™{ОƒNÛzy.^ž7ßÍÊSaDÒL ¨(œs¯»ËÂÃRìé}‹°©zÀàp’€€ÆL®úºÿAÄ)åx(œ%P¶Îv›–…cްÂé ‚:ñ^úé¬!Ξ¶*EÜ£2ÓÛK¤¡sònØpÿ²ZM[sšP÷“Øñ}‰Â{h΀Ð8°àñRÊQj‚ʾ¬ZŽa#8F;GÀ1Àc«¹¬øúà5À{dK‚HýÛ¡Áv„¯vùâñÒ F˜ˆ3‰ðšê‘z¥l&&ßô˜còeËÄá·¥Ñ5kÞê ~ëá²WfÙ9GñBÙ†e–ÝûFàã½Cüít› M Ùaƒn‘”5ÑŠef–¼:OíH.Û‰JUç§fÈ®æˆØç8sžê„!mí+5¶"ÅQ—’Ÿ£ul»nû.Ã*Pà ¦ˆ’‰òñÚë÷&€äNik»•©ž¥G°Û()3ÔjíÊ$Þâ ÷RoFáuÊ©{XU̾@¬­Þcƒ.±¿•„—ª%'täÐâÒŒ˜§ BÜÕ5¬id,gõÉDû«5Õì.Ï!cÚJ´x ¼PqÕ7GòZáÞû‰ kèåxï)ôB‚lüÚàIâ[ƒæŸàzçàß?S¶:yVÁïW®Þ‡ÄO« šéɉM}ÄâÁžú´*ÛoÓëUZ¢ÂÔ!_9ÒRç2j踺ˆ¹®2¾ {®€.4ûm‡óÄ•»È^x¡w|Jõ ½’&>uØP ;â íç­á¼ŠÏ­ s^éIˆîŒï½‹S…†Xfr)Dðd½köÔ‘Gõ* JÉoî Æéö ªò‡Š»tˆºÃ1Œ7 ß›7_r/*?ÇÙlÃß2¾ë{dqÅ_dгÎD`BÊ(¢é½×è ½˜?pÉÀ©Ï=9kyœìsL´Êæåx n­Xv¥Y®Í¡D†D÷TÜ>­bª;w«{¼äž¤ôwð…œXKRD1}'TfÚtbTvå}õÿq‰ØÀÝ$zýt>6 ¸‰Qš<é],o @¨Ó4²e,Ê=d8¢1)øwÄu·Zzòd!Ù¥_¬x–ªë×j%ÌÅœ2äSé=ºø€ ·—åÏ ·MiDú6´ö«aÏ!5S¹u&w#$ñæúÇ7ÐSLÒìçñKÒO@ CìZ&ª“Rr™i†Ó°Æûê'òÎoµsZ¾Ÿ|5$záööœ^*«õ´í€Õb'¾@׿]øŠdá’€€—o­*E˼‘>H>õLaØ ¾cNMNRnÙ­®K\¼á èº^QEã+þOÒ%•†õà˜Ò ä +½Æ NŒ~QXçk­}QrÝ•ˆtógükŸŸf»¬í øô‰*7Ô’®•Z’k[IºÿtŽnìNDˆ¬Ö%qÆ4æðwo#Å@0—jø2ZÆ¥Ák8Ï|Iƒ°è_¢§í YEY“Ý×øBõ^ýŽ˜Ñx§Ó(Ø«*¾gjœÞÖêvÙ_50H[Igæ8±µe¢cõQ‹èï2WÕÆ ny*µ3ð1Û¿7àx¦19i {>åµ´ÉŽ íAѹª÷ È𖽋Ø7³PÓS ì¸(š?€AÜ-õ=3uˆq }eØè­ä<JE@%Ëó|aÚ_O;ù’^{UëN„óÔmµD“˜Yº£6Wrê@n:贳įWR0V솔#)3h]Fd®Áœ"þµ¼ßŽç6$ˆ÷Ã)¹ÂNäbhÉõW_™Ÿ ô x:` XѬcwTÄ24K‘à$OR_þ¶²¯"pxz4¦Ñ•ÛËw«¿¥B7¨ÙÂGŒOÜÀ1kç{j®ÿ“u(ª\gÉnBÂDP9w‚i^“8f>M¯|$Íy¶ý¤!¢öìhQ-üsbÆC§ºÅ7ÿb$°Ê®Òç[TÐBA$æê±äž˜*çÁ¥Y D˜®5]6q .K#µTúõF«ðFïѲ?ÿíƒÙv‘ûOø§ZÌðŽÃmh¢°älý-ÍR‰“8åø »Ö >:3{ÕUÖ‰**,l1ºÇ„‘É *ÍëfŽßpReÄÚSa­'O¸´»}úZ|%†Ã-0V?0òT©2¥·—C2 }»† ¡Ð$çÍA_ô¾ôõâÎቓÝOáiœ+SÌdWøC‘bOYþž¡`?Y¾‹Î¸ÚÕ8ÌŽ*“pQihzqÊ0‡6þ ÄÛgBí(Ý…#¦>3d +DwÒº—\žÄ‡ù&õÁ%´$ÀÍñjŽäæº[¹R™]öD=8syŸj½6#¸€Œ4©K\ ¬ 1ª›ãéCO]t£ éG!µî7ºâ·zw-=/²6:ˆÑ |…œ'ÀDl6u¢ÖÊ͇O3ÑQˇÃzBû ×EXÃW…jT²•n°JÖé\8YXçzg„k ¼CgtñÓF»~'¾ÀM3]„®LÕ$ÓÜÙ7 zÔ`â¼PU£sw‰DÀj/¼ìŒF¢í¦¯ B½j­T>Ô›މ÷(/s%CæÌ(rÐD|copÎëˆ1e2šÐttɸØÏ¼‹IÝëXêæ/Ht ÅÛ;¨Ñ EuGÊñ‡-º¤©»Cñî-ÛójDiN$ p6÷M¬ƒ@Ké€3”Í ö_©#ñ̯{’–èû¢ÚˆÙ”?÷¶_=1ÿUrÜ1ÊR^>6Üig¹q¨ŒØ=“e¿bUCF ?’ªµçé—ÑcÆòIN‚ú麅ƒ†:Vvï‚@ñ@÷…›Œ¼Á²Z¥®oˆãÔf¹²ø~FUckô"NßÌ%'ᎩÐ*õ{°„þ«^ˆ3hÇî^µça2‹^t«®Êw_À1.h‹·AGê4«éÙÙˆ–ó’×—ƒžlì<¥"­okæêÐ! ׉‚Býµ”¼ýÕ>„[l/Z{ñ3ÑxG^‡ ¨h½¨Ì¹ÁÙ½”:k ¢ LÊ8|bÅñÄC¾FåWž– 4NMÆJoO)[¾ ÿÆ)˜çyJÒpûÐ4ßîØRgÒ’€€Ø$0.‹ýÜ<£G;'w€d!š¿Î~yô—‡ÈfŸdÐVÓÁ€‚© ™°c!Ý”èß…N|Kû¼Èv8«g^½üÈ+MtåÏE)xâGlVªƒ'›}“½ÄÚ{môViv?Šã:Ón©¸LŹ9ˆ®¯j³F¶½šâ;¥’õj‹¤Á¶àV³bçd?],…xƒˆÐJ½¢-sT´è]œ¥f²5÷;² [ªý‘Äq¼ëè/~SçØš¾À„•߬.e uÞs-®wÿô樚§;ÚóÛVÕ1oulPZ4W50ÊøyóàQFH¿?›‘ÊU/é·™Î(q•_ÄÎþ¡¯yÂt{NF .!: „‚fdIˆ¸[qy=1Òù‡¥ö/ÐëÑâÝkøI­ØŒ¸Þ²|ӘΕû3}© Íâ@õ)E0M™ŽG–´œðZ}&‚Ô»JòÒE‹~ZïÏQê,ÿó¯˜öæŠ/ÑÂôÙ¶ÿ)aÃpÔ€1 RÇ¿»åá7C2ÉW;ÿ@¾~4ÂyéE-'+ìµêf÷´1ë¼’•ZèVȦº5ä|¿Þá÷ƒ‹Ñ:D3‘ â4Dô<èyŒIã; Ø,ö˜ÐŠxNÈø¶¿ jò¹û7²dQþãÀín `AåÚž~³)Ú¡Í÷Ïp©ïö5ú h*RÊ$1ŒöÁë¨RT"ê°ºŠ!Ó£“½óhSiUe!MˆRóÐä]ȼ}ÂÿL|×c v=Lîý^„ňÎX‡jvî¬×ï´Ç,Y-‘5+ßAå¡?‚¿@KÕ%#¡é¶~ܼÍ,Þ:åþ<´ÝM©ƒŸ™æŠŸÍ(Ò*ÈW¦MdïŽ7ÁN{ež7ÓÈ€†kŠæ„Ýeª¿;ºœD]ùà;˜T!T©o–{¢|„×1ssI ¡rP²]"”ÉÃ&„Èò’€ þ±» ±5ò’GÒÝoÐ#R‡»p„Íjq:øŒ…¢V+( édì®åÏQÆ| ­#Q¾SF~„æ¤è×øë‘<Ë¿ÎVgöÇn=÷j5^÷7÷›âCÇ…_˜ ¶ã´&6»\Œ¹Ç]aU<<ÉÀÅ™ žëh;NU-g¡ûO鯀 B¸€¹#ùÊSß/ð­Ù>Ë#Ñ«K[nÿ¯7u‡mt4{BáÅ•DTü’€€¨N®Ê¸vy¥Øpå;ÿ‰¥'~©õE·ôô‡¾Ž{æø—ÂQ*ª¹Qu*Ûž5³|Ýy¾ìNpåßIù¹Ó(3Ž-¤Ö•ܵÀD<Æs%ÏB]©@ôÚÖO?T5q°éò=ãZÄzšvçÁWÜö:;…NrÒÁè–k¨†¿RÜÖ%˜¼hî<‹Œ¥ˆ$ øÇc·S5Ÿá'´Qk×ʳë¡÷öó²¶Aí€q…ÆføÁùÜ:º‰éUtáïP²¿ý£ï"ðÿ¡ N)28Àv;º) )vÂT_dÆøiN¢ :„A^=ãôôBÆ>Ó7@ ©bÉг~OÌŸ$ˆÙcœKLØ{£ûÝÚ’¢º­§c¾ßšz‘µ«ü* Tò)ÀìJ^s¹G¤Û™z(P0ċдüù=±u×5§ïûà¯À^%ìšnÙ·Ø2·ÊXñQǘ’Úç)°–¿§ƒÅVoR~ÅOω"ÿõ¬ø‹N"”75 Úˆhäo60ý¨çcKƽæYÑøÕì9Úoz8=¾ ?õÛv÷yó ú‡Š; ŒæcËšJÚ$Übè­Ìî“n÷Èð±Vvðî›Ò´Nn`j/P{Qèíw¡ÛRnÂû½(É¿a=Ò³ Æj«lÞy@6Ú qz{=æ*|B»ØÜ%l'ÆÌœ“*~ˆo)¹¬Kœ'•ªÚð~M:àc7jó29ßå0”>¿÷£ 4ª†d…> ·äöžv7œ6 b)žBëÜFÞ‚5›Þž=›…Í`|".¥¨uÛG‚ìÉ ²wð85‹ö„±<%èÂÆ­Æ¯8îÙÁrx"ìÓÛíHIYÓkXENKªR¨´ÿÏr¼ø7ìq­¬1B·–¶[¿q½sv,¹"¾,¿ðíWÕ7­Nï® W75R£‡çwGhßÚÎæG”¢¡oÛ2ýèä'D¢nèçÚŽ¿:¥v¯„RTŒ¨E¯ì^ê t¿~3o˜¼$Uóû!&nB’”­iÃŽvbäãç†ÍÞIqP0‹w)‚pz€ ûL²¡ ÔÉ,}ØÚÐËoM€$Mă1ä¡Ç)TR êƒ;ðžåý„׃6úÖ[h/.0„B÷7§÷’„_-*1ré¤YÀeCŸ–:4i$8(Zt8| Ýc?΋±Z|’€€§ò8Ø­±UgȽSžvXVNÔgRŠÖ¹›]nŠ ¦r>O50–«ü؛꒴ê‚U;%l¥úZËé>°RÔ¿RA"Þ¦$—k…—xÔÁ,\f ¡êÍN˜P ž¼‘ŒJ+“àâÄ4J˜”c(µ%Ùæ9c4ÀÔÎRø>ÝÔã‹ðüíºªKà_O ôä‰C¥˜ù]`>Gàšw Ó°qëÊLA]¯5 ØkݯäxßÝíA͹TMkŠ×ï¢ä‰ÚX—IðÏíèRˆ÷k>µ•”(O4D¡rW\޽ tàêòÏ54Ù÷åà]ö„ÚÄ‹B7#ßÊ'ÉÕþ•öòX@³O7™Ü·¡TÅä$(²}7òùümaŠš’R–€¼Ú¨£Ð/ ‰¯ß¢ýƒJµ[ñ\="BÍøY¾ *˜¶ðnÞ«5òšÈ•H?§¼ÜѼ–¦2½³/Ò+ʲ¦Ø;ÙZTZà¿_qõtø 2½ØžLwÄиÌ3¸¨)¬“¿iÐ~$-˜q1 k›Ëºþ[žµÇ™²5ACJÝoãA¸+Ò Îõì+‹O¬¬Xσ¦Xqu~׋è\û 6T˺R³ƒ9V€‰x’ò‰“ç:¤tÑìý¤¨ù«¨¶|ñêéÍÚ{³“è (/¯Â ­²W@-ŒQ†AÑ®çÁEö WøžÊ1£õáÁCÅ>0øÉÆŒä£Á5è’ÏÏ3ýíwaCôB"TߺJÁ¦Xü ¨$c&â1„&¨Dôº·ÇS‘oöf°ñöCæ~nf9«m!ƒ)ÙÓGÎlóC33Èf‘¹ ãÉTL²<¯i°œæî÷XñÁÌ“3hâ¾ –‡XdX;~¦à?L“æMºK?<ûu.­ï*ÝìÃòø0!U fNOÀGB™°(Åb´Ö8a`Õs*Áq3 å$fS¡Š¯Æ1¯ä¸Z‰{œ¡°£ö]$$»ï7nf☫¼÷•ÉF)+j‡a-„ßgszaÑíÀþ1ˆëù©± ¬°øÕ:pvÈ¡cEMê5Ô«HlkpgçbK€ö¥ƒÃaB'í½&«JëOt™Zl–(çi9…©j"¿¯EGÿ,›äê<0t2žUK-ÆVÓì„á ¯6+îÎ{TS5gFÕìXãÀl÷²6œÆí\’€€ÉD:ã.«©åy5i^'FÑ›C^´âîI=M¡t5]“VóŽõÇâòÓ2–EÓš@©›ëßÙQÿúmÿƒ&d%ôhY¡Š%‡®'+ce!Ìá®(‡“Õ-x‚À¬| YT1ä+f^.Ia¾e+æÉy& ÈË×-éÊ·×|$ pXÛ âÎöå„ÙjäÜz®ÜÂLùjåªòÈZ/EðÛƒÌsô¹cK–·×I{˜Ô°D¸ÍIåó"1.c'W'‚¥š-ªù™ïÁ9åœ8¼ÓQêÞz9º…m¥½¾ðØ1u°)ÿƒ¿ý+1)[•ÁP…»ãYø}!.Þ§V%+Ê ’{G¸á3¿†íò{TÑq5]•œå_.J NÝ$d÷¯½Þ~×ÓŒ0IØ(ÄDœb÷8)ê°)´D:ó® dr$d÷)#±#4@EÃ5ŸÊwŠþÉed¸ÔOÝ’x-ΛéùŽq3fÊ`1ܼYí¨ÌÆ4@Ú$rä—ý''üÚ@®ga÷-{e”¢´$²¾ ±¼…².|™í+ùKÅUg±Ÿ½²à™ƒ…Íéðª–#Ñ=ì÷ÿb;²<¼øF>ïÚÂ=|±Èpö ÉŽªO^wб¬Râ+FãŽjoù ïçgîÄÄ`OC·Më*t7ø†ÒCâe€n'¤A1è׬~ú+îË#ÙŒh5…·à·Œ_¸‰‡œ{Å{sWŸØÁu7]Õß,wRý¦µÜÑÑ¥joÔqe˜õ¸eýUKx0ÛS# “ä¸ì•/ 'Ê+{®¯›µ}\"€œ?9‹v ·ëH®/j5ñ/>ã98‚=x¸¥ ;¥ÝH›—êú:Òtö¶÷Žè%nþà5ú…dY Øšͪ©¹_¦#Ò”9#–u ˜æ×³e ”íð4(ëB¦`¯­5Å­ÖKø»;=Š ]úôˆÍ¸E‚7¤ÅÖÍYðZ=2ªe²wx,\–™WÏ †È>DØaâYgxî'È[i¡¾÷|Wüõ9LŽÀS–’™ååËê¬ð2J£x5r€‹­ÐZRŽÌWÀBHG¬Ù‚0·ßD9Ü&S“3åA ’s ¶U5‚4å¾wEHüå|÷¤¥ Ü3+˜°z¸Û‚ …Ö€UèIk±ÑYò=Éò‹»'N ÷È€÷Ëx’€€òÌÅfâZï°è1ëN¼¿1TîŠ,ržLì<ÉQ4ík~Õ0-dŲhÏÁõ€_zÀ®ÈÔD¡w¹úîÌØÑ#z4S‡N6ÒAÇ)¼OÓýà+ F œ8ž§42 )Ê[›¢–â ¤ß\@_ˆ×Dcå#›´«Ô­ ›‚bj~ÆuçÌåz[5—÷S,f#Aíâ”DŽÿ¨sˆ20ÜåÛ8+'³=P›·?Û¡Ê"¢¡[Ò…·P°ŸP"ÜJÇç×d“’èa³γí|ÚÒ|ügg/õÅ]ù š×Ä0Îâ¼}µ¦þ;|7!tŒµ6̓&Lé‰à~%Á;HhùåòÉ?GÉ›Ní€ ·&1_üHՈĖFò¥˜ÿ¨ ø^]P~¡Ñy.ÌdˆBªŒÚ|>™ ÝÁÒF²V/o6½ô@fgˆ€òäèCÌx½¼õ™óÀJ–M.ÜŒ6Q¢ÃW$çøqNŽ91ƒÒ&±ÊŸºœì2/;´oô«{¿Ôy&ç…Þº×m¨/·\L½:_Øeµ ¤J4ó5z‰è( -÷?b„E1¬ëMo–BYKfÔ,Õˆ¦æ-{ßæ­*ïõÍ&b@xLTo³Ç¥¢Ç{¬Å†‰ˆr“eÛöôœF£ð‘c‘T±t*R%nŠ…ûn‰¼}=9©.UhX´_eÍSt•Üñ<¼þ¢jä¸)n¯BvÕ\8ûv\º@ïÑŠð öQ1„†¿K8$-F[é/n†h[ü5Kˆ¸²ª%Þ êÐNfÈTÞõ¶ n¦R•ä™B,MÚ‹9–Ì…eCÕg3J­÷6-ì/!U…ÿ&œ·LʰÐý‹×Ýú^ZeÒ€h:4lHjr¯(EŒV8#S${M% s½Me¹“I>àŠXs¶˜«Îrú©nyqI¢7ôBüåD“ˆô©»®2\6µæßP0õWÍu %1ÜáIèaœs lÅÚYÝå^;ÍÌ¿žÂõhÓöw0m‘ç0ÁÊ/ ,`wÑnÕ ˆÞ’Ë?äµw…ºzZ9ôòÏZO“&â’ü>UüHá’·!ç"óú0 èò‚’dü­¶Ü”ßFk²’aðò¤5vAC/o²’€€»P •žw„Qñ¿s§êÓøÁ–~ª/ë\£ãD6 &7F+pYÊûøþy’(úUe‘PÝ+ ÐÆ·=;BaéŸ4–ž s‰óz´á¥_¢†÷MÂ`eY;jR€UB:mº’ÙO’C|5ÆòA31¯~u@q¡Wf 2×Aº ’´”Ù¼jx¡}Kç¶)!GírqŽBw³@BéOTµLìe-#’$²×¥>ŒÅ­´ß«åêdÃÇ)¸ÓÂ^S,™\D;\ù®é£Ðï–¸{h3±~æ;f ˜œçxn–J$©âÞ°´ê†Ÿ£‘F¶Î÷Þ(‹ =Kä‚VR#E=vwDið*>w”þQÒÖy]{…¢&1/¡´›sSZé ÜÕÛvܤÁ­oÍg~2~n“zau¹FrŠó1$›Ã—»*¹ë–Içs ²«Ñ~—.eAßå¶f¥·t)v-fHo̱ò”²X¾öÀ& ó|¨Ù_ I¬œC+²uhxëUž0å;AìeštÙHÂ>wâvB²;WÙc™T<÷‰´â¦{KÝæ8-÷w€µIÈÃF–¼È¥gE hâ´Oï°M*º¸oÌU:˜³Õy«ˆ†tf­#-3qÑt]nÐV¬ÊòE/1oÕy¨ÚT!c’€€ÅëUÁÃ+XÝÿ)lûJ‹Påwãì…­Öô²³„‚þ.w'ÙBPÌ!´¹ðÖàê娕yPHSIÒysø¼l<H˜ßBm.¡¦ÿ:"¶.¿:ù³:µ϶–Ê#x…06©ß^:G„þª«Iz®“ú(Ÿ@Ìt¨/2™B3¼<â1ò¡U?„†]®SNŸÒ–´ÈG2º³ƒÆÈÄÉŠŽ?×Y⿌š¡V·9¹ÍYˆ>ßX úpî~ÀÜ 63Ø`]Rññ±öMïAhb)âØâL×Ó"¿4Ïy0@’fxFÃ[P„æÂxÁì{ó€ùÕAE9PI3<ùßî ËxËÅe”ùF\©a´ú¥Õàf›g”¦ÙTë R= yÜ1å‚zPò´|j·%{£hæô¸Þ„ƒ¿ÏO"Nè<{ë/៾ð€®ÌúÍ!œ¢4vf{‰õNÈIN“ ‡¼Õ°Ç9©>ו&gQ¨¹#üÿ~²òÛÅ£Q¿g ß3øÃ¢‘Ow_µ!fÔùEÖ=רH×7) »xH"ñ«¯{šÏð=µòÉJ›+ãJÊâ~ÔhXÀŽâºÀ[ã9l*îz>5Fõ¨FŽ7e|PWðï.3[çfYÉÆÖW>‡CÈà8¾Ïõà ÷ùN»fbÌ…3, ž¹º:fZ~?eDÔ}bIŽ?ܸC‰ÄÄžwÇà,,'è7üt–*iÄT#ö 9j➆;š Õfé.‡†À€ K>F‘8QRüA}ǯᄦq÷ðšóFx¢—YѦÒK ³Êç|‰ ×|4oÌSGm.I+Dš/ñ6U ÑS×TÅÐ/‹X\$ÿ ô9 ²èYMðäëY˜M¬­¦œ†µCø–¦aØ›2KØ^ ³!è8½°Ü²ÀšO0® ¬'…Æ•Ärã< ß®¶{f_Ñô/z·”}¨wÏð²ŽRVzA%­M½/³Œå”œÏõœ«íKË¢äPe«Ð`ÊšTf%óÚó˜íËÊ“ü€ñr_’l—8ý÷f÷´Ê_ý y{CéŠÚÝ\]ê×~mð´ £çÕ×+Þs©V«I»¹bR­¯:¶‹:r­¤’Þ)jÑ2fÈb>Ph ¦«"Ø’€€¹í·Û4•xQÌ€ùØ0­[25È C; 1•Q9J †of·½LnXUëeê7ÖÂ_Æ~7.×ÖËÿ¯ÒG!‹%õÆÃsq˜¿QiòAáèëÖLÖà¶°»/«<9‡x{™±ãÙ!Æh…AÑ]™F ôënÇArÔÁ%þ¾¿‹ ˶™–$~2É.' ¦qÎ:î(ô&B›ŽÙаPc®!oöNˆ/ëÙUȘ”&Cïkà=^«® $°#@ÛÍ8?«ïà¡äÈ­D°rŠÇJ¨:žxà.xÞÙÕap÷.<Æë›WíÀ=LuÅwüØ•‚4$,n<˜º»L¼­¨§¢WRžû0@l‰ùÞûô?êŠ{`ÚæÀ·,õ ïòe¿’ï·íN©W¹Î,'(isà$à+v"¼AÁ53PZ¯a-âB¶}‰¼I÷Pò…ðиä@1úRÇaËþRþñ1«©O½{Ü…Üáý †ýª‡ UvZr±.ІÝå…c¦† ¤•wö7>Ë‚ß'øÔÑö%+I:px»/cªp(чm;Ž{ÔŸǨ¨]9s =Z˜1(•ð :Rã¨O"øbÆxðä·(+Y[#®¹CXt.»‡VœAKTîVk7<¤€Ÿ]ɪ@8äg)iSRš3´Q‘Ên~Š®d'AXp²øÔÎŽ³R騅Á^ºdzý½ü¯ò ªlbÜáͰgÁPÖŒš[3e±þk6.î»P òY-\ü7©yUòí›È'‡žp.:»¯Á ^±Ô "È~T´ÍÎ'U·ì(t6îÛ¸hŸqz1ïÌ™S0ËBV™h¥TƒôÓè,Îóô«#³_EyÐ8r͇µfœ GÆ2¶ŸðlrèØí'Èí̶+l½=GYàDœz‹xYwÆe!¶dä‚ê#Ì[“¢Ôk•²“µ*ñ¶üOÄcm¡Ä¤5pŒ¦ñÈVæõ½þFöçkÝÖòyÁ¥”3IÕ~¿ßìr)}´$ÐEØÑ+Oš4œÓ äw‰’€€¹ýcΨ؇ÎÞˆ×@`^ìªñ‹§'ÚsÈ’ìe±Ëµ¿V÷ ú ßD¯uÙ!éF=¢ä„¹¸oÖŠG<·ru0ºº†¬†›Œ m³?þ='ØŽ&fÕ Rˆú»ÃMà‚éc]Pµfo¥í¬'Ü:)‘8Ö¶>7ùÊ»áAeI`ðõ÷õ y8ÃCSXrDa*ãU‡ÕÿˆËW¿P¿ÚåÒ ¾©;6È›E÷LÏ»„”?æ5sŠ…»ïyâwEV$–ã¾W;ï„C±RRöÐ):…Å/‰á‡fIŒØlt©Œ0𯄨¹>Ò3ª4ø»«‡0c7AàÖbe ùÞL´ëÕ®Áþ¡shw(‡™ ºW„ìEI¿ì@rÉ{¡X ç§éË‚xäH³õ\¿rã4ÀÊfÑœ—@wítÛF›0r£ÛíV±4Ž3YšõCÙ«ÉHÔN ¯9´Š±–hÖ‡*¶»e´Óä’{»»rÓŒEbù†Í»¡•\8`]ÃÑÁžIü¥Šíë>ù º¶Íܵéܺ¶“døöö®Í‡ ½Ä#r¸[«f: 'cöÜuWÊSå˜Æ6ÜÇqˆO›‰î¤f„‰?KÑðO2êsý;™Âs2^Ľ›~ÕŠÄ®ø^yç<..MÎ…]Äôã|¤èäÑâï9—–äÖŸ«Ñ$Ñ’Ý«IPf>ÛÁökF9 ÛIÎëö ¤s»Aæù¸ˆ¦Ç/|²¦ i 8t6.G¨¿/±¢ª6)M¹á»D’g¾'ß^¼Õž÷úŽ`+$ºÉ| ÿÍ·Y’b D\ êÐ6tð®jf /ÐqhV†ØÁ }ÑϨµ <¸J…C×BŸó)£š )&$æ>ʘ­:ç•“-I¿sxpn¯úgæ¼àÎ*‘ÔÖ7NJJQˆE øü¾ä“ŠA ”þåÐ ß¾7„CŽ¥óApP|Y¹9‡ñ»Òð"’€€®ñ6£Urÿ}”'3ó£eG záÓZi­ÂLÐÚÔÝÂlg¸½Å6IRa¤)(§Ÿ “á6I;›I Ž Þ°aOè“lÄŽ8p¥‹ª (š±ä V}«*­ßµQL‚s±2¸%ö¼¤2Žô‡Që©ô)CqEÛA‹¶¶b/…ôíatãã2$òº{V{¤‡ È7†nL0Ã]:MËX!¹=f'¦ºÉ %N.Áô˜_©_p hš&l˜­Èž‡‹ÄJ>ˆŸ#_¸gwLëuÿËzŽ®4~«‹È dMSA(…—Þ¢Ý,ßÅvük={* ˜hžP&'6`”ìy­°ý’ìKݾ¯@ö¹HqëUt@’ÚXå%êËsÚ•DsöBR<}ƒàåPU·>‘a™ŒÔ·…ßs\¤²+«øå´9[…£á,áÈþÜþY^;LÊ Ú…ùY×J¤Ÿ™¹šàá-‹]°WÿFuè-®Îþ]på/gpSMdø¶P î=º*S݃ª,²ÔjÚJ—Z©On¡úù¶b040C‚Ó•Æ2վ˿Gì$¸ZÞ0"PÇ,¬:ó:¢Õ ÿ™*ætâíb}ñw±«˜Rx¥æ7®àkü! `@c­Ü¹*=ïÝÀxîí òà_wËŠT>ç©-bÐo ìØ THc ­k_ ,ŠÎ 'Äé\<ôå8ʬ|-h2ú7Z·ïJô^úJº5ù3::ä`†?  Io£_þÞ_}NC§(Ô±¨Qæãæ¬í¯ÚáJEã&±h'÷_HÎ$À”Œð¹‚(Ëj”‚ ®ŠE–„„øó›b/¬ÍC€¢árf%s^­.n&‘FIMfrø&0G~ŸËýI’±:R°LSÈbz ¥ ŒS–·¾|È@¯@+sö—¾)ÔX°•,óÜëII×Ö³)¢jµS¹ãœ÷*qâ¢dYÊ’€€¾†Írõe­M]€Ôâì# <ä2Ê&ðÜÝ^Þµùj Vâ¬ÒRbÍ1¾Eæ2FÍ J¿õ™ª]3}Rfå°/nöí,ñf¶1+øÎîO³ü0: ׎¹k”Žò­¬ž,"_5h#v­¾ÔÔ)4lºReFŽ”€¢¾ÊG£7Ùÿ®ç”.÷hblOýÊdDd‘ð24¢»êË*ô¬5àÇ»‘R-ü-‡M‡ó¥ä䤤àRð*ö±¡<’^¼¥.(4wæë¢Ãý‡ä*{þžl¾œœÓ'prqUÊÄÚÎ_þ9³º%žO¦‰®E/™iw,{ çœ8e¼.áN O?uqï1B`¨.wüÝõ+1î’¸–c4âÅÒ]Bwyï>F„¼Ó}pg©µšRW}Í;Žsl*^5ÜÖ¯ž±Î ¡¿Útb#­Ó ¦ÎDúMbìãÔ´mBîÄä?hà›ýRjK‚„1òœ^¢' žב¹J0¨0›Ù!šAß3¬cñ¶åBà__ƒÁp`B¹–÷•ÞÕ–´ØnEº>tà\{Õ>@õ=­`wO°'õrPŒÿ¢´…ü‹„z0ËŠ¼Jç65}DŽjK’>ó¦Ÿ7 Z­ABÛˉ­\N†}qÙ)Ù•¹Þ˜XŒAó-RŠe·IöÒÈë#,ÑDìÝÀÝ5Jowº™õ’¸aq‚ A¡Øc¦¼eT¼^²óFûD/›ø~!Ú]¿õ¤ãõg{£xÇjcÊ¥°ptYUcS0_‹9óݸ'ŒÒö’,"[âNs#Lò+ÜÜ­`€ Ï7dõ-ôàõ_ò©È’¾ª¬EÈ2ôá*mð3ºkßá\¬,L¾½åŽd ÑÇò7OýŠØ¤@l]ºõgù§Ä*ç!OE9«å1Wêø› ˆé‡|OA½ƒžÚ?dÉ,TÚ€?=yšç'y>-6ì-Ç™ý~Wòt%NÓ£ÎTqózN ¾/vrm7?LÈê%Î̓t[‚kd2ÀC®¾wYšI£t\²ôP ÒØ£õ8§b¯ ¸òú~äƒ;³L Ë'/¾ºï0¹PÑû¥êâÖ‘…Gz&Ùiû– ÌΉ3ÉmšÿʾvœË¦iùDéÉhfÃÕ#™)ÉœËH0ªv€¸`ŽsÜ’€€»§u¡R"¥QQÅ%¸¢ÄŽ Ok¨ ïFp=KmŠF”R»óž|Õà ®úÈ{?!±ÂåúñhgN¦-¸(ÜÌá‰4oîé¸ív¡NZsô V£*“Ø€¯½RÊv\%²iìÅJš Ì˜°ÇZ¤5–S߀v*³eiPv^΢í ZÑ÷L™XoÅÔBQÕLH–Kÿ—=}zägpWÇU“¹ŒÒD5u/¦™_ ·úŽ+È/¼(íkjÂgÃltɃ[F ¶†.ÕpÕéc?¼.²ÿ.ËŽ*åÞ2·š©(©ÆXú0ùŒ÷½×þ7Ñ<Ñõ³,¼ÿ1/Ž¢^±»Ýç|©ŸÁ,ÖrI ®\­ˆnþ5;íQú‡X×ÿöÀ*­ƒÍ ÷F‰#ºA³óÑ•Ø`tÝû(Ý÷avCõxO¼\v0¢}êS”/-å‘ï>¨³)ù¯!ÇsèK_ôÐus«GFÖù¦ÕüÒˆañä²Q0eå™÷G°/±ûI}„¹”i¸”œ“³¯ë @MG-,âúd¥,Êè&Tåp_éƒL`µ_ še)UO®Û”jmrÀüv“'Ç%f/æxÆ ª9eþ¶ôÌÜôãY¡øm«ãH)†E6ËöÁ:ʧœ) Ha`¬ýJSKÏÑ:Ó²?ÂûhZÛû3€ç05:^[˜Å•»¨áåì‹¢;SÓb9¸æTé.>”~û3llÅLŒ ð0ãiÅvmXE'HÛ£—Rê›[÷éŠ*"eX?óD³ÅrÊ­žsX8ˆ ê=WÌÈÐ…ÉE‚ˆæîþþ‰#]ÞmqGiqlâqÇ‚ýIlDö©~W×wëäe_ÔB‘ǘù¬Ú~…éÎ$͉ôVB.îxHïÊ%VOŠZB†ê¦|Q[$Ê[è-»û<¦òI"`n¯†œt%%÷„”‘äÏ º~`[:Ó¨…$€¬Ü€‚S7k´Û‹à2Ðb±ã’€€ÀEª ©I7AÖô6œ‘†Ó© \‡{…ìÞþ<Ón…|—WÜ}ÔÌñIAƒÌ¹“c6í)@W¢M01‚0E¾Dƶè‹o‡dÃvh)­àhzÕÑîÓ›Ëdî÷ˆ\èzãvÓðªãÎ.#¯ñLH‚‘ 8²ªG\Œl[ù_ÑäØpÕòK:œ’^} Ó0Á?Dpjˆ(á‹(T;ÂN¶ÿ rÿ¦Ÿ1Aî²YK¾=Ír”7M|+æÖ_Oòä›Â줚.ÇÝsAKì*“¨!Á íàxá—.;õT0…,d±Ï¤¾eqˆÅ:0j&ž’–I2®©¼KCfõ8zÎëÝœ=}㜻N–µ?X°yß0:<}8N†ã%w§á âê¼kJ_n»é ÏMN˜@¿0õ"¡ †¿¢ð[§à||±Ò>Ókú/rÝœ ×K´ wUA^¯\ø' ¨¶Üfâµb.Lesy„;ÛÒøÎgžË^Å)²V4±ŠÜÎÏl±:ÊÃÐþxÝé&RhUÑTù÷ì¿Hy¦^ ÁakÝa ‘B?W–Μ['NØ8m‘3ü±³G¦ÿ˒ЄBYáŠeG«ýÎõB\‰~]«°æƒk a•Àþzh ”ÎqˮΩÇÞWߦpý&Çg”§z"ÛjjÆ ¥æÁĽÄ7²üÇM1l8¦”a^5È*Xid±YN&´w´ÏRTÊ×Þž•"•›]õ%ltïqÚw®KGÝÖ¦œª+:¾j«mBÏȱˆ$#xßÊ”Ú×̺4ZÒ`;÷1¡[ÇÿsYd’¤(KëÅò¶7I®-KåÖ­ýıÂv™ç#|4JÏÆó < iBÓJ,^9=ö4ìɵ?Q:Ë|z›ãUÚ3aÐeÁnU{.-&æ7(Dη¬ïƒø#H„ ¦ÉTi¦;éa€ ¢$Ô@0©/òmñ¬1¤ú…Èq7ÓQiCyFÈÜ“Qa³?-*4‰Ìv×É粉§—&%¼…Kq"äÓ,=·¦O¤ø ¦Iû¥Kd‹¦æ^gb”lK;dŵšé÷Àõq€°t7©mu1J(1æN–ºJ5X¨ÑÕÍâöî€eØhؼóÌÛˆRÐ)É&à©cë¾+y¦Ôt†b+•Húñq®µ‹@GìŒBà áýx;‹·ëtÏo+g G¾.€Ð‹CY÷FÁ°Š™C[ÐìÖûkœ\EÀmüh¨FL Çè¨Ú© ¬Ãiñ‰î¡g Ñì‰Nürvÿ"LÍK80Àè0·p?Τo÷±ŽÔ…2sÿ"…ëÐÑÈ‹Wꌘɺ¯=Š534êX¯ ~·éoý‚#ʪh:±r˜Rb©*õðÕ‘C(±$€º£x„Œ´ksŸŒôÚ8îT¿”’•¨Ëë0_ÑŠÿÉ¿ª–32UæIêè*¥Š4gAUü…G¶eÓÔgÆùõ Šd ®›ô‰C»’@ç”8gˆöWVÀvQܸññe¥@†çR¼pÉ&óD8PÇàõç;'c­í‰q¯L¹3OŠšZ F·6®ÇØĵtk .@@t¾Ã¶ÃÁta³É°E4z…Z&Úð‘Î× «„ÇhïHav`mS|¤†qm•[{8ÕK…7½µÃн¡Š¯’±S/‡°CœrÛZù_Á‚l‚Øy®¡‰6Ö¿äõ*†Ú…Þ> dD¿¥éve<;Û ù(›ÚoiØãÃÜ”?ãßU’”¼²0ž$¤xëÑNºäÜüWȸ•9¤¡Ö†„òJ²Œ¡‡Æ=ðäKÒ_¡\&’hw†@ OÎGIèò´oÛ8ĞǷ ¯ïb£\ÙnûäZŽHskRý[”P’€€´¿Éüu‡; 4 ò@ÂýýÿÓ•ï¦üF¢ôlóü¾ÂdfEÚžâ4˜˜9Ÿ¹ÄìzŒœ>q¤kâRÃÑýäÙlÓÚNcfÿåGgÒ³X?Ý÷èzªá,X‚°¤aD-WE-±1KHÑv©(relû²9E>ÏVÍà‡¤…‡äWK›ãÀõ38 ¹Ê¬ýßÛ÷Ó=d é{ªj¨-â"Oç¤GK”Gûñ°Ÿ†Y;úFhß" ª–Ò¯Ð`Ñh3I;å"nÿp¬4mƒìã¦c¾ª©Ý÷¨óÖÕó±bÅã¹ÜT*“·þ¼y 0܆*ê½,ÊÌÏ¢(Û¯EIÎŒy®Ìj˜Yû¹¾=<5ÜæèÔå·øºøþ Þc/™Ø£Œ»pƽ“GŸŽÏ£ñ¢,zoFLî,ÚQ“±-:ªà·‘¬ôQÕœÊ×é`›m,= •ƒöûбlÀœÏÅ^069äÖ&¡¤Ô|°ø¤téü օ)¸Ö}¤Ç Ä0óÏTyêžgÓ‘"s1õ,—„XTz¬U7*Íø’€€ÞãgÓEàÈB¡Ó;KÖý1,‹2í¾6¸ý}ÝGƒ£¥løE íÂÛMèœ×JÒÁZ//šægzEe5‡‘ê0Zžãˆ¨×ó¡âBg6½Y‘h,°=1·Ú鬖H¶ €58P´®¤‰[[Ý0úVYjS“bMwÅá`ìŽ 0zòÅ’ÙhÔ³”¤LÓͦàhÿ˜a¢uw‹‰ òñ…ý‚;Ü‚#ð¸Sçð]LÔ@;¬_ñµQ>³€ª×<j³æ„;îáΕ²ƒôDÜE-ˆ¹'"·Jg9rŠÓ· àW¸#Ùºæ×k¤Ö‚” šZ\FŒ¦>áp~£M@œ‘9ÂÖpó$Óí“Û5yV X))Ô¼êµêúUy¥þ8;´w¹ê§Íx¬'—$6]¯m§ŠiªI¬úFöA¹¬ïhêÜ>R~R®›3Ä<ø± ݾ¾%WÃÚ;ÿÞáãÝ2¢cDûËJËèîgEV39lï »Ímžúžàóc=C Vâ61\£ÃBJ¹p%‡®g«˜ÜŸ2IŒ¾š¬<Æf|Q„„b`Ý£N ª80V&0ÆgÖÀ†;º½¹u·*Få tÑ÷­à.Ò]žr"œ,ªDE±’ú9µE"ÃÒÈàà/E—Päº9dU ™µ5ùø×¦–‚º÷ïî­sðÐX±Ò=ð¨Wq3gEiÝiäõML•NƒÃ`‚“ùòIèF„\K®ÉÛ^ûS(i”ýZ·¥XäãDY“`’Ï7æ:mÒAPÎ’Óƒ¼m-@ÞŸO(À ‘]¼Pf{V´\4™ A@ðÛäC]„¾uk7‚YõÕæ iœÀ¥­MÜ"8ŽQ³ºß&ScŽ¿ÒÀM/@cF.МäZ¶ŠY,¡ w…¼Ã%g0;Í¿ åÀÔF´2SIóN’³Hl?„;‹þ‰½4<~;Ž l6ÇtÖ[Î8’ÍFFƒEÍüå¹äÐÔst{u7#8¼;PÖìY^u+WZ¤¥¤J!`Zëƒe=2@ª>W´ÁM“A‹ˆ9s£‹H,ÿ§¦l^|Áþ8…–ñr½j ]ìÃ(ÝçöÎÝÌ~gað¯Ü Áógû„HƒtëYˆá*%EýcãôBƒ±W{«ÍŽé<‹aÐT¸0’€€ÑÝm`Á¦ðŸDRª7:¤ûz‡‚A  ´ÈÈvˆëÔ`öUÂ&‰YŒµ`¤ul%˜Ãyp Kµ”µRÚ¿[Ifm2}˳¦‚µÁ:Ë®h·Ýº•$oeô'÷†8ß Q‘1úKdfÌ„×óöf[¸«çD4„­JƒWl;2òeµ‹lÜ.c#)Zff´›‚ªýLä7§kWŸáýû0­ H]Зâ¢tœ§³ŸØè’ßfÔvÞdØ´=W60ÀhÎ_ÔÙB7·'  ~AÁ›E|ôáKNðVæ•Ú*Є!Ýo#bç fñE‹c®cM CZít¯††ú¼Â18ÄZ±/%ÐÑ¥$À[ŸùÎ_îZú%ËîHq„ösÑBH†ÛŽÇuòÛ>ë7­4oŒùN¾“Ò_£7fâÜŽV´5t€µ‹‘¾;çÄëòê«Õ/´CÚÞ,ºÏµaåÖpO¨ §êDÔÊžK‡ÖLûX_|×€Í]¤¤þúÕÙž¶“"èóÏŸ¿_‡Ebµ€5"WÅÎ[NS‰¶[¬Ïä¾/ŒzUmò]Xr@,œ{”étÕ¤Õ¡^™Ó$•ú1Êtëz!ÖÞ«OîÑD¯"» R1„OvRsÌïg‹mWlºÆé×Özuœ¥Í¼žðC5ôÉ©j0ªœþJ psŽ„+3ÐdSb•ÿ”òSâœælÉÈ7•Gˆ7S«»Ëm.0g‡áÁ·§p(ÃóŸD ·àaM”¶.p"tee3•·þã»fá_Ó·O­ «Ò^!”«G/î}Øt‘y§ÈÚžô#@Ã+]]-û§ÐV¨Ypr RO¡Cy>³ìí-¶ÈbŽö}W-ƒ¾z.4À n~V)º7”ŸŒÌ…¹)‰ÇÞ9Ú…ïÉ#‰QL_à²MIãÒhœ$JÈNXN¹ðÚYVfk‡½h¿œËÄGz[ŸvÙ÷8ô54gDRHÿîé\±ÓÄsm\e¹ÆÕhgJ² Õ×…ƒ¯-T\p[º‡M”#¼wŠÿé¶u“m›Óê>Ùǯòî®Q™Ï?Iì²¹M ŠÖ1ˆ\?|¹_EzL1˜-”-8ÅÜ—gý‹¥8W6ÀÓãTµFéiãLW{Ìs•’¸°Äcÿo¯–Ùkå§ß$B<„Æk²¥Š39x0ñ³²ô‹}?*(ÆôY>t~[DC7¼]àñJcM»oÁ ;Ö›™ã:РâmàØd°Þ­8Gó=Û¿–0Èð•’:Íå TO"g½súð=w)ÄÑÛ×Òas n¹ã¥}OðôšDi™<ˆµK\3¨JÝ€Y[¼ï9³¬ãÏé À}­S¤[à® ñÁ<aÎñá»ÕÜ˺P·#¢}t†ÝÌÊᥠ;)Dò»AhAصÕ£0 +UÿSnœ³DMk´N'¹Ç41Â9¬vÛ·Â*ˆ%¡”ÈïûÅ%o"5Ù·8¬ÿ‹jårCHçµwI@šà ßÒÇc>£‹(¨»th§µyï=ŸÉ€äIl ²]¶]Ñü®ô† ×ìL å;pcŽõ2„¼•åŒ9Q+É~Qñ«}y";÷LËì[¯ð»}A3 ú;ÿi“‚'uBþ.…²-Ðï+ê«©Å­¯r«}ö 7^߇ V¼¹gtƾo|ÌØº¥i¶ª‡åêJõèd –ÍhP»=ÏGôin‹M÷:ØÈ Vsí‡>з¢;`XLJ*oœ|éLÌ[5•ôñ˯†ãä™–ñgŸ¢ŽN^‹qtQf'éAÓxÒ Á´gì¨;5*ñæ¾$bø¨‰Sa-l“ÎÕ+s´þ»Ó@Ð.Xµ 3üº/V/mjM 'ô.Ÿ’€€¦¨çq×ϲ=UÄN#jÙrÆgP$ì«2Rg Z37ÅW03\=æKAv?¼*‘èúc÷^5õgÚ†:½68{>ÙH 6CIÉ%mX•_©©pÓˆ‰ôÑ2A3ÝÕ0AC@ÑòÈݰ‡¸ÿ4O|ø‹´öœìú=÷/aÙ¬õ–܉ø À1ý*…Ü]Êuíè˜3»pzÃ7´œT>ˆ‘qr}žÕ+S s$Ñaîú?ð¾ì¢X–ÕšCyu)Y„i‡é$_a§í#­éz‹o›ñ?š²B¨Ý­ÂOlÜæc¢hÙŽöê˜qµ%*å=çõ,þÉHϦÙÑ–®à˜@BÎm˜~T.$pëBbYîR”ÝØ©ÿ›P¯X´€M1ÛîÖx~}`ômD ù|¸‰ÔPŒæÌ߱צ³Kuš±ßAŸùhÀãê}ù åÐ׌äÎãظ EŸ,çëîJI½“ʘÜ|‚bÁ“/íÍïT·t÷ù´j¦.ü²Aܱћÿ¥[Ú-YÒ‹¼À¤å¹Ø+=¸Ed]Vs=ßáªÀ{'n3¿6®5xÁM3ÓÉ)F‚VÁØÀú°—WêVpÔ­"NbT[¯ÃW‹d@Eƒn>?`Šç6› Õæ>‹ëœ€øý˜œ:„ïc»5ÃKö‰è挥%Ð%Y õAÁR-Æ*›¶;áÊŽŠÙö”Þå.V»”žC©õ%x/Ëjö\wá|tª yÃÍ¡®DØÎð§[ób]cfÔÜš¦—µôµš ˜DÞFhkf*1ÚKB…H-ßšôŠO±ÚoÆÂ˜H7ã/^¼L¶Ocƒ=Ø#Ñ5|†Ä<%WÌá'_ò¥¥P86¬NËÀžy—ˆ|íIñài€ aµ¾Ö8áÎK{:$“³CÞKa/Š+c@Ьc;§OÖdù®qòúávŒîËû¦˜] ¢‚Ø3£aœÇ¢èâœÁ¨<>ü¯ ;t}bùFZ$ Û|÷N•|’€€©¾K7Ág‘úÉBÁí`©kà˜£Ã{ ïD¬È$€Ï$­þ˜Ô‡%ÈK@N]g»Œ–é® ƒÃ.aµ][³+Õ¥u×¼K°X÷îÑ]ímQ La ´k9–{S›çÂï.4‚|JJÅÌOFgÓÅ8+3O,¿èp×ä,øùŠèËJkMg¼K°O=Èf1Õ|OŠ¢y"¿ä|C¶ Ñei'aÄÒÄí U\X_r•ú¥‰“_lÜLÐWJ…»ÉæÂ¾ÒV/ìqSS–¦ºõà€ŒL.S*€mše‰?,ÁE7MR=gÁ³j¹ò±}@À„ _%)- —@£›$SŽš`-I—¥±÷ô3ÕWèâL²½A&š[åñºÆFli?Æi´SÖùÜ4ïßkÈ£Ó8éip†ˆ+Sν“Å®”NÎuÙ, uaÔ”EuM»„®¥ÙaiwëEÂñ sqŒ~ϯ¯\%éå·ƒlÑu4IS„-ÏL#Ðp_0¼,0šª]ú»PC+@¨EÕî¾3tÀ#¿Šâ3™åŸSõ®Z½ÃIKÝîìN(dƒ†PS'ÏÿÔ'Kw{üvŒ0ÙYsP ë ÔüBŽ\,€ýo"¬ÖÒ€ uÀÚ2›Tòv¾Š»aÓ±bPÉŒê&{)ÚÆ·5ØS_ ôtÜ« ×Tž NW.3ìABÿ‘=æ†E->š [oìôÔJݬñYt–¥˜+NŽMX8º){—“-ü¼¹ñÌöÝå‹BÖ7-ç‰û<©_î¾QyF µKÊqŸbªêÑú÷(ª–Z±ìfª>3b6d^µª”äº8Jù €9@L®üþÜ€ÄÁsCÒ-*Œœ³¥SŒóùA k Dˆ‡¡ÂËU Óh9l•¬ôfá5_†:·©˜”‘”ÂNïa‘šNêNÇðøå•êà§Ç ¸Ï»ÏMOYdÂiZH­<ˆ{n”{‚vA÷øÂøWe&ˆöî¸hÁVJª)/æ³8×+Ø"¹?MÌó5WJÿvÚ“(¥¤sT3kD_Œª‰‡`ù5Oqé_gá"éaé?[ÀE€µøÄ3õ(—™\­'ÀTE}äÚ¯ú]åÊ#äƒGFÃ4/W¤Üº6ÿ¡óak¹Žš@ú5?Ú‹Œê.±Ï“”Ž&á£â¢ÜÉš³«#,1ifx­»wõÕ 2y®þ½ÕêWß/?ÿïÓè( uh}¡Ú]ñÍiÇššS>èö¨o] ¬JkÏûCx}¿7Ì‹nÎîÃZqœ\E"‘1¼Ü™Û5íÒÛÍ.ãÞTøöå„hM€ÏœWY¸{öÔ\ùR¹›ðžÍÍßEîdc¿Û‡'3ñ£±Ò¢-"uusá_Ãv'Æf ¢xo¯èòÍÄ} ×ÑSã} ÚVúv¹b—ä§yGåFm’°FžTjœp Y‹Ò¸ÏHi6²sù÷< ¨bœˆ÷Ëø³1úŒù^þfæ;-鲄Â8c˜º¡22ë¢ µWÛ$®õßÐç7Qæó™Š¬¶vyè¯&ÁÃø³È²-T¥¿ÛMÛAà¬ÚêB3 t À”þ €Æ$š½JÜxJ†Ø<稙Ìù ÙË„¦àŒª¬fàÓ”QV‰þöWÓ]]dfDÊÇ'LÒÉÙê]€þTæ<¦—%ŒÓ9‚”ºzgÒRïCуs´– ~-’€€½(ø×¿¤ …¡”Òîî9‰UT Ê¢ªŸ¶%æøª¸ÇÞ4ojö*ŠŸQµʸŒJ[pOÉUØ#>¹¯;À¹^ž“á(‰5Ä&??õёИÀÊýûŽ,àRÁ‹Ñ›Ä"ã³@Õ–ãÆRX)W’ÉïÍ3%¶]8âû N>–<|C.¾AmøuÙA’ Qoagü¥›–š{#¤W”Òxì^"‚½ªR[·¯¢Ò QòƒvÐ"à"ÖÝ,ÀjUjâƒe—‹Ø¥^ñMŠ>#ûj‹IĹ ǵ<]8!é² Â=€ÄJ‰sö… bî"`V®MÔåX®<¾X’Ѩ¦ ‘‡ÿ®ËÕÀM¶æÁ¤^øŒÑ¡95ýãj Ç_þVXÜ^>A$ ^àÛ/;„Î{BáÀ™i§,L Y+- ¬Ê|xòDý›J1Nj-‘ 3<ŠºÞÑËdûIÞ†Š%"¿ã`Ã÷aÃ@'™¯ŸÔ’ñ”ÙÜ•‘“àá}<Ÿ†§80À”à¸?ˆ.UU70åºæ¥õ°» ’¹¦[M‰5ïÝY=ôÊ‘ïÛ´’ï§µV'p§Ü 8S‹JyÖòu¨tXݦ<]šeQÆk®YÁ´kò[¦ðâ5.ˆ¾¨Ä•×?m×âb7 ³8nCuÇÖÁúÝo+çt r›;ÏçùÝ’¹CMìôhôIô-ºp:e l ܆ˆ.Ù>20V±J¹D½™–ý={€“6w %œ²nÚ 75=Es›°P«:ʼní'6Ì=:ZcäKtâÙ3¨Ó®ìÃËíìÙ¶ †»p„‘úk*2£$üBí•bª0[‡Ùø&Á Ó"…/X²|mÒ¯û‹ù¯Ð ø.3Qº*¢ÝüóSþŽë¬³ÑÎÈáäŸ>âC2(Ñ¥ÙêÉåŒÉ5 |{|å—òÙ ®¡õòB8©÷ì,/7c«ãÈA˜RÉê¾ô¼uÉíT>šzêêâ–4¦uØŒ,êV OtNâ©ÀB¸ÀçñË™]>û:á‹Ti›…z¥ÿ. ÃÔÝ«²@õa†©U@ùÑb™x&²Píc>yé¼Éü/“’o„jsÖ¾>Kš0ŽyÔn1`þ #€«;Ð33ÛôC)»(€›ñ”xân›R¤CmM œðè’Ó"~O¡Sc´õÔE®ñ_™¶bMüñå&æ·³ª,òrXÒV(²©%¨¿*_lù…§+Ò˜‹‰®ÄàDË0SXXÙð¡êðŒ—¼. çŒ™f#‹éð ášV¢Ê{ŒlaeñzHÐEÓR9I,ÃZ@¾{’»¬—añ[¥Ò„¹æÚ@åj’€€²· ¿‹ãg“íübu$”ÄñÑ‹®›>y½VÂÚgL‡?T« €–qEpNÀ<=ï¾zŒ7òÇÿ¬?‰[kÍB~†^¹™û8ŸÓÿÑ®3¿*‰3ùv⟠Oo£ÓSD(Ƕ­ü.+t·îi°†7‰Õuþ}&ªY‚ýåeÁ}º?ô¦E" Ø‚ãŸó¥"­ÿ"Ýì%XYÏô œNÐ|d¿€‰{-‚Óû—ËRa6튷&ð©Ó‰˜¹ úç*e¬—MB‚¼ØCƒ×i{þ3ÿ"Æõµƒ€) ‡ìpúàÜS2 ñ¯+8¼f¡T–%?k?¿±),(>ë—›LäM:ߌ‚ÕÈñÙÒ'ýÑ¡-ÑaŽö^ÍÑŠÄÁ¾³Ü GÐès™XòÌ™.²•UãÞ³yæX J4ÔÜó˜ ë—·3Ù/5z3E>u»gƒ™j}oÈ_­Ær-uÁ‡·…A@ç ¸ç#ó8Û?’kŽ×嘂¿ *KA¡Ð÷ä·Ö„U;Ÿ.–t.@7.·n®VåØRjêK- MžÙ`|Ý‘Ý6‡ê¾w¿ ¾8í—jÛ¨Íò„Jÿ~Ek×=Î%q-ž} 0“ßyyrÈõ…!êñ~É£6<¢êJíle>”Þèiç1·ƒ‡Å Yæ$¹ˆ¨å»Í½¯ÁËÂx8‘•¨5”Êñ‹@žÔÐÓ°}+’¹…—øQÆTj@x_NÞÈK¯xùÍJ?Ó,¿{Ùûõ_‰Ï#þÖ^_ ;Ð^Xi±G÷mzNdbìöVo¡)ý¹Ï>pjØF+·¯_S"+@7kb5Æè..ø¾|ºyø1îÇrÓ§µ½:¾ue!2ïô †¬ý˜u½m^B†Í60' P›!´E nÞ% Po¥ÙìBÔpãè™Ná0Ûqz®Š ‘ímŸÇÉ=:)çÄäo¬¢5b¯x~èOv¨O6ûב/Æo&~–q¥¹˜HfÆR=NÜ:üê£âý~‹¬¹ »J˜À½F!‘øé´Å÷˜l? ä»ÀÎ LKRµ;\w­`°Â~dî}®TLYÌÑ1Å•³í}g[ÝWZ*³ÕÓ*ñÉófävËò@3í±fº“]µÞÈÿå²%û˜„ß¿A’€€¸8•^‘ÍpŽ—n6¸cÖM°Ç6ø«”uOó Ë…{ÉÙëçilŠæ"rµÑ%4`Vb]¾É¨‰H²$,qxBÔ ùÏ:2ü` ·rôë[íéѳWØpÀ”PI ˜1Q{k*º“T›yž“õ ïl6;°©ªû „õSKAd•Õ¢õüØkV|1pñˆqÔù;á8”~‘èbžMËmþÃë‚©òëò#Ã'’0‘É¥+r<}¤D1ùП$†àt1°kñ Ü9Ö(ûº#þ5uåD!³ƒ¦­§‰ãfä·—y9™¿<þ=½T*5 ;¯°-ËB/9-55S@ŸîÂÜé—º^°+ÁØH“s×Iê_×N¡ßïòf8¯\&û¹YÐT,0óK5Ÿ n܇ê΀®½2,6½u>u´{>…ž§ßð©R§ð!z{ÞÕå˜Èsà­»óÇp§ *šz–ËbOjdó_sÙ–1†–qîȧP&MüÕa7ëguMó.‡v¬¸v¯3ÿcÄvˆ²Ç:ÍÖÐÐÒšºõ=XÒþtFÄ— ù˜ñħµvµY•Úk¨m­y*5)htÚa')‹>j? (¯Ã50¾»{ÿȆ)Á¿#½®ÉJ'uÇÒLßæîx?\AÞÆÉîê¿ê0ª´è¤3GÏé—'ª…ˆÂ6%C-=×ßüŒ¼àÇXÞ¬î‘{N¦}d&>A]0kâ“Ñ`Êi8BõÙ^;õLˆ×¹Ëª÷³=FÎÃÓ=;åàÄ$—šà‘HsI9Š[Æí3œ8ÑTf3Ózcݼ›¯3¹)|û4u9¼éÅdÃõ:™y#¢Â9îwÃùú/ œ¯¶z³¢Î'ddE.‹Â9Ð4 ÷²wTç•w¨Ò©š!X'8õ±Û<W’.á¼OZ¼úR%†j-€õë„÷êÇq¬È<ð9Àg»ùèzZÍÏ#2Ñß®ÕEêª_GvZþ%Öm$C=B'±$Îd¢\2u¥®¬^‹ÆÀ‡°€ã†£0MûÌŸO¢gx°—¿§ioDO¯!8´XþÊ¡¯¤ãì,Σ¬%±½ž­jî+æJ½¸ŒÝRË ¨>ÄâÇVÆ£›(ùц­?ÿ’M0‘o» æïÜ …Hq¯jH5’€€×óÈÇŸ'Û§a1ÓÐ× —ØþÌO¹Î-cBU H12¥_\’¿ž żœæÈþàV9PL`XüTx~^'3ªy®^‡º¥JG / Â~l×”†„ÁúHÑvö×(G—ÄT[òå·˜Á¥h8!„eg|$7È´Yþ%«H”^ Dú=ù"R­–¶7M’6’=1T”›RŽùº˜3ì”L"ù¾ Ï%æDÿ„øÑF©5’’Rè™ÿÖ2 YC÷[Ä!yaĆ8N¿×kK/Ýï‹Ï pM§PúêNgKƒeÆ6Ra4ƒÂÐ(ÐíÐÓ´üQ½ïx¨O2;%…)6Щ™¡ãºßE<¯W=cŽ+*Á¨çülÓƒü¸ šØ'øh"}Ã(·-¯~sÎ.û—ÝËÒmúª¾²ÛZÇþÙòtK3G„´„íÕè¼;—±Ø+ÙI'w|1šQïÒıÁ-9_3\g"«Êé”±ø«UïÓüJº„Í÷t¨£3Ukç¹áòI7 S5½›««J=uk6X¤; Ãrwhx`D¹*r@¡oÒ=j3&4º¸²ú;ldÛªþX}2¯lì´¿îfóùòi$¤˜ìã¨eý¨bÀõ à}E-špø4mùz0Tèú—ZJ*‘0\½ËÕÃÄ?XÁ+èµÉH<}±@üäØn÷C…8¯:J¢-Œl±b½ª)©ÛmhQiF£w€ÍvÈ lQ _óïüIö©Ù[]ÎWQ2ÜPóî¼ Œ”êb-€Íðå!FÜ6šLÐjñlooHƒB÷EJ}·ñxéfïiß3ž›áï MXçzóZ+J;l€ÙZo.Æ¥•ý'ð.b pM á]YGbxèÅ‘7C¡PL“EðÛRaëëL”Ðß¶Šè‚ä¥ËÏý%‚¤Ç§æããIagi‚R³Ϲ?¨ð¦zclŸÞÑ^úøL±²–E{óÝ-û]à²G8lðòê„m¥Ö¶uJü·3õýI~Š6ëòØ»ÚþŪèÏóµ–¸ùï¾ 8ª)=l‘aîÒ`Òi"d;è'Ín¸d±ï%ã´ûhâä³n20g)#ïR[» 51˜Âa»mç¬ûAŠR °qÕ_`žçXÉ`ö!UàT€L×&ìÌ9¿íH)·ó€§d:ßÓAZî:ÏD ï¤mŸ$î¸íÄWs ÊÒùûÿ'oZ½fÓ¤ŸËu#ŽòÛ»ÕJ‰'iü€³{ÅßB]ÆU´å¦…Ã]y¦™µÎy—œdrž¶†ÇþàÔ“]ñ6ö¾+•H²¯Sãû‘þ°Ù:ÀÄ=΋?ºxKÐÓ>4èåÕZ@!L i»”è½6änßžš…J¸[5Cšåxq—_A9s`ä‚=¸J‰à— %æ.Oq-·=AÉÎ,7ÿÚvø0¸ S«--Ê(eÒòìó ®E·GdCüš Tc"2‚ºó¿ëSáL¦\§˜ >Nû1Ÿr“Û.Ò%ˆ¶]Î;"Åè^õyb:›'$›içk¢Ë3óˆ*`;uK<ècš=ždnAs &†N, …£ÄÆ!p›\žšÖŸ]5š×ZÓJBÀ ÿ)Lû‰7•â1ÎÛq†DyÝ&öײ¶Ü×# î$³àÀ{ÿ+‰ø«A}¦öO÷[–«u¹™G”…*ꦊ ”ÁY}’U¬²-štñýÒ{tN,êÂÞ‰Æp^Æ‹2â¯Óò”RܺQÌV%ãu©Üg+ÑwÝÿšmìVÁ ÕÜá¾Ð™›»Á’ظœ·ÀG%ê§%E¨¼©Š$£r¾êréÉ6½ïI z—t9bCÒƒ±˜‹ŒLÈ&æÎ9ÒiŸ“­kBýC eA(¿ûg_ad6_`•õ½¦ðu©Âx".Pn—SªH{ñM¦¦þ™ ¿8Ás-"… }OâF¼iú{÷R§&a&)v>µ!1²Ã¨§ÖRnT·õÁ°—‹1dò䳞v‰äÐ$;E¯¢æS°md#{®+¥ÞñÔ§W4xï+W©?'Öšý¯mB=Z¯õ°»ßâ«­s÷ oÌã~˜î½AÍÛ/-Ñ*ª%ôÂV°é¨ÏQh¾wØz1Jß]üqÏK¶@áI-Ù°?d FQ–·Ñ‰‡Ý¢Â,:“õÊzí3E`+!­‰ˆœþôž1wƒ¯WµýAuã1„ÀF‰y]V§ð>èYtÊc;#´%®¡‹øÏr¦{í˜y< <˜æfòDšÃž>…µ]”¶lÕ¡þ/§åæ u©âü =ÚžùI-ïŒW†§Hm-ù‹ "Î*’€€ÇЀyÄŠÎÌ©7ìß$Àµ¹ÑDOüf¯ )¿^–·/Û €âªy¹²Ò#' òiœ ‡Vèû¬Â–Ç躋RHý’ŠM¡œ·ìÞQ.y ¢¹ˆ…cñîç•$‹» Qî¨ÚƒÎñ»-:üÌ~êsB’Æ®ŒÀÊÍCT*Þ¹§)´‚è=[ÀhO‡jXµ´mÎ|Çœlp° [çù§f7#È#´Ö#'¿ö·´Ð{švo/øܾræ5ú´w%LñÈœ£d$omT.ëÝQ€Ok|ɽ ni*±«ÒñöýÃ쥀%š%©Û¦*Ü©¤1$_A­¬»T5êëÙIbøütû™š$=u¦‰Å­&Ü7Åió¥<ˆæó`’/§ÙU°2RœŽ‘ŠMS)ÆßšµÆ\ Ÿ£8t–9DŸÁ¯ÀŠ|—Â,— Ï)Nƒ‡”†$I7ìŽÃ@ r`Aá©Ñù‚_¿‹«35,0ðÁN-œ ®Àœjõ$¾ è·«³ŽÑLÉ$}%‡ p¨<`b´ð‹CN}=SÞ88r©!Ä3*ÙøÓÀ˜€ âãq´Õ±60ë÷{OL¯¥Õ8|®¬_BC÷½n„¼Ì‰or%U½‡Âd~ÎÍ6{ÁöÒÃíÇÐvàÝ{Öã>øZ<ꯇ´?oŸ)i±"»ŠIcÐV‹Þ-ÃD¬LÏ]Q®‡MÕn$¸óï3ËG~¸¸¥¢z@Yi…¼„Ú4•«lIFµJâ¼CoÆ}ÔæSóøÞ ¦H‡¹îǾ”‰ü(tWQÁ Õ××t!ŽÍª qQq±3=¡áõê8a4›8*z—<-´ìïïð÷ìL0°…_V¾öùD¶„xþ^QAñW`r¨Ñà£#F}»ÙûqPÿßNm~à$ùϲ¶Ù×@ pf13!Q…Ã6½ø 2Á¦Î¢ôg—çárvG8eïD*+ºã®§8Ÿƒƒ?8õm4Œ!ÿ`:g¸n¾Œl™qu¸á™vf·›ž{{Ï$!½«èÇÙak?­¹äŸ*޵oß=k³â6`Êsö—‡2lñQ0 PÀŸ·ÔÖŸöÀ]Æða`8})]AôC¡TÚ¥:ËÞEõ2öÎJZ«ÅΆZ˜€B»I}YÂÔ$X#¦*ã’€€Ï¡ÙítP/¦J¢ îL~Ìz 6˜{q9pö›ï/ßOÞ£;Ç]ßÒØÍ",,D€›cãq©ÍäJÂsáú Þ²gë|ŸjM°_ñÿŽËš¸­òŒwUë=š_ÀŒ-ü2C3ôÿA].§ü¢¾‡2$:‘õµ@+9LlšÏ½opÃaˆçä,)Lc‡yÎ4Å)5åK¼¿–Uòb=^§Åk“©ŽbDÍQ4r­¿½c1ÿˆ&¤´÷ëö¡Àl»F—]Ãw™è¨Mpõ‹Aš"öÛ2æu¯®¸2ÝQ î3Hh­ áZd7÷us<ßòé³#ÚeÄÀS‚%ì¸tCó9®œ S\zA š¶p'¯:ÍrMÃ%lUjšZƒ—Ç…“‹{ÄpJsûœ'~Ò Qnàƒ~MÍ4ž™ö(\xg”´}X†Æ(˜l%üƒoö7Þ÷k|Ø‚~ì»hÇ£?µ|žøn«\©ç»çNífžýÈÌí¶ÔÀžé[@ùPTtA¶3¹Œåâ5¤.×p í10¹èœhm×èÙKu\¸Ã‹ýÜ´sîè}É"£SºZÏÆWMþÇ _íÓ¦}náïJ`5öý»qïoâG¤s lbŒoÐf¹¢éÛ‡·“«œ­AîÙØ¦³baþÔáÖ+—!ñö|P@&x0sø(¾ ÜàϹ€\<‘’½Ók® êÏöóâ*ÈCNšŒ„Fxzê™@­ó»"œº¯råuÖ¸‚êºHû*7»ÊpD!*±zðÏ?ö6 5KŸv\²‰{³ÖݸѢq’˜ø©Ê]pIBºŠÆ ׊wgÛ­nÌèg¯¥ñ.u{Øþýí"w&Çðs¼b^¹Úì²)9ó |•žbOÌ’ü™v³=þ™c”¢7¶Â©°ÃKÁÐ\“0z¾X§­y“œŠ•Êê£Ë¬*¶f´Õ›æóPØÕjz…80[‘ÞmªZ_ï¼ÜµýÀµçý[÷¶6õPŽ1è5qKQ£=ÿo‘ï°øxÈ:(¢'4Ææ–¯¸Oq§ðð½šÇJÃQÍ)–'õc·8NyÇWáe:ÙZÈ×ÀyÅ:R»§ò¾K,=äH‡\¢ŸujÊæÉb_jY7°¹(2jexYà÷²~?éRjƒ!+¬™îPo_¢¬µ<ÆðšŸôbT’€€Äs©úÚ]E V.ôÓGøŸA œ) {£þ” «R÷ÿ¼dg‚‡÷Ì]gðC •ýîûv©h¦’¦ó%kÜ.s?ó¢Mº"mÁ :¾©q5`âE5^¬ÊŽšÊÑ|Í©Ÿ­¹¦.£sOn ‰ðhñÓ†WV’IÀ—~/Oï.dƸ‘ÚÉóï#…†ßQ4ž˜Sçï©åÇ:ŽÕ§&”© äÌUÑùÛç`ºb„ãT\ÊSèéA‘ßAPÊZó?îǼ–ô´£‚j¨pÄã=Eñ.ÿRMÅÛ©µi(Â"™âO"Ûøãðˆ ‡!ÂŽ£Ù)Þú-m Æþúeòëü%ÑŠõÝiÒoâ?’ÆpÖØµjüÞ> óÙ]ôu¾:©ö\ûž¬+ÒÛêŸé¾äî—ºh…p:®¢¬^ß#¹‰6„–¶21™Æ½äÇ]gÆ_Yõ@ÊQ ׈l\©LÊ¥^ñ-7hÖ"j»q––vBÞÀó½Rp„ñú•Ï¥R ÍxyA™¸„e\§m)ë8†ký©ÂuAá ‰Î‹Ê¸êö­¸y”Ç‘¢|1³œu“®c`bïÄ1;'{Ö ÉEz×ä»=ñ®×ykÿªl­|# ‘*çwŒ—´'þÑuc›Hö¾°(e cVž•¾«€õßîä ߥúŒy9—ÄØ  8ì½€žeÞeuK¯6ê‹@V¼ÿ‡Ú÷Òg°Lɤ«¿ @ã›Ý¸\ à/F“ìd¿“ã@Z Ì׺B_YêÆw6g‹ÇÌ„&âƒ!@D’;ÜáRK#f-%á†gäYÆœ³ºÉÄÅ »}s8¾¸°Dt!/Ⱥ/—rDܪè Çþ{ £›µvßü¿Ï"·yýAÙtOhœá5´È͘Ø ã5µðuÝmD6é<+)‡êˆ±·?e«¥E8{l·E¨, âÔÁÖ´JÁ6"UîW°‰©Í”%¶³i’b‹8)>¾˜5´vTJÔ窖ôæëîK9ZïVªö%§îëØC>$›ÝäíVOŽ ô™cm ›Ž&¾p8ì8Žêäá²ÂÃr"À†)3n…T¶-— Àµ¡¨Óög6î寜4 èû¶Èe{ Dý‘ÜÝ\>mì…”WÚÝÃGs}Å¡'æ ¥ÎŸ¦8a¬j’€€ÇnÈb ‹_üá§·9Jã ö·†?Ìs—‡3…."¼-ÔÐÉÅb€i¥dWfý™¦â¯Ó2®<Ì«+ ¯3XÔàtæÞל8-híÿþ“0¢#Ú¡§PÞM‡“¯Œçˤ䠀›ôdÐ'üM´Sçû/íõœ[g¯^\xsþ ÛÜ{ÁШAÄ6ðhëünЙ‡„¨û»ã=];gWo¶¿exÄ0ÉEf$tt‹rÔ½m8·Ú8[²ù°P 1¦w²@¼çËïݛ˹HT\¡wtO«Ÿ„!¶¸¤F¡ñðõå´Ý†[qL'©ð’þ\pû{!M]ŽôtªÏ²ì§ fm¥4dD/†!6KhW~•)çü+`1: >Zt“ên {8 *6‰±šÒÍ£E]iõƒ³‰åºäìÃ^È„%{ÈAM®Ÿ-,›Aòô°Í`”QËœÀhCœyx5­“d0-µOx:Ã>Ûñ¹e—Â'd6+‹Ö祇“h®/”ÝØçÇ’xoEÍ×WID‹0.Àµe—¹JuN6É[vÛäH‰+¹-iõqaPº%(àné9½VTžN´µè‘j^á*ÀsÇ.ÈM4 t©‚*ºK£ÛaƒO¥~²Éap^׺/#FT}jñÍI”&/ _-oYnåMDùuÚA;¡Û#Ò•À.ÚÄo÷^8ôOb“ØÄ0lÏ [ÎM‚¸µF—Lj ’€€»ÑÛ•ª˜hkh™÷—r1Ë”ý²‚>~òýR]Z1@|k¤Û£l×ç¸:“æh·¹F ‡!UBIÊþ ÑÈhç3ïcmY±Ð µ³Ür¤µ¼ Ρöj˱‘Å–Óoò;$©l´÷Öuõ÷t¥Œ Ä^Ÿ-ŽQGÑá(ÓI´Q¼›G'ÜNÆ;‘ͱ]žd!;-iðãøª¶clày2É‘_õÝÿÒ¹õAÂç*² 0 Èï¿O‡ù@`£TàÌLg9qjñœ8”3©vúâQd··ãÛgiöQmùT·yuB_8TÚsÝ´¯ðÐüm(.vœŒ²x<ž7×ýÓþ_‰CZ&ÂK‚Þ?Îi =‡EݲÐÑšô:½Ý,a¾ÏOý‚ðû[3r#ùñmP® %“0 \;‹"2Æ„I »ÿ´ùuÞ]lW¦:QusKƒ‚>9,b(ˆ?ÙÊlïªÑ;É:pÀãæiù c¿¾©ÀÃÛÍ·§l´äU¡"WG‘ Î#}øC©Ú åëm‰vb“ÛX}¾®°êY‡]°)Ú‡8z]j(þŠ*:+´N=\5¥WÁ}ÀÆLcj=*b<–²¼#xd0ÝÁâ½1„4Zu—(3¡HF‹c1Á/j]¨%Á2*´È±c^NùÖM39mÌ–›{6‰Ö‹èõ¹fãPsC¬xpÄ IŽAÅÚH§}Kkì»VHHeÉÂïˆZàêU9”Ù~ÿ;–Ÿ¹ k½ÚÚ-Z4誋©k5](­Ñ®3›ZÃÃ!Úz+±IËë¯Ï«°EÐE:„u»CC­19»3ËÄ‘ÑoJÂ.• ?T²dïÎe<îœ?{Íﺪ·øê9®ý5÷ð$§!6Ömµ¾(d$ß °;]H°ZÊØ Ï×óSúP)J»d€³¾ºF–#‰ƒ¨?6¨¨½·iõHº‡ØŸÑe„tœËœîTÒ²?ÎØGt椌â³^;3êd ¾ADýTÃΉ§tyé+3Ñ÷ ½Á5¤u 3n7•NO²9Où£¼|'‰n¥ ŠjrÔ¢¶‚Ò% ÿdy ‚‚É“ySÊšßX¬ö©,'ç…Šú²’õ=9•ÙÌûÏ ^pÎöìFMàé÷øøÎ‡Û“:A3²û(¤Â5˜ná)å¡Q»År£vNê\ûÃ’€€½Á9Áè豈uJõ4½÷é SŽÍ§Ò“AP›×@ý‡=»¢ŒŒŸ4ý*ðæý9zûêÜǤ™è÷ Áürw~æV4Sø[j™Ï%éÐ9/]S6äã A”«8_Ô J2é—mƒ;r*± ª[ ’ €;w}¼€|É›‡†^t›Ï¥üæ5ƒ¢(¥ÙãfÓ¨—d4c'?Jy l™—:Q&Õ¬æŸ*âÜ.ZcIþ»³Úü;Ó1-iEM±ˆ×k7ñg …Mš¤å¤Qœ‚½ é1ðRȰ¡LãöÕÁZåëQ’‚/}9kÌ ¤³0[üa§n~*ª#4 ¨¿'|gÉüª#…€²åßö ïã”ôC:S)‰awQ€>Aê2óÀøß8Ó„£°­²ewÎ~|X ”1:Êž£Ä­Àül³1úà{àÓ럓ÖÇAKøx®X Øë0¾G &‚4áäW¨·8±a/úÉhwð09)4QβPS.Ð8K† tÅ `*qW¹¸\Ó<¡ÊXø½$Øï’a+*5å+1ÂF?û˜o‡iñò:Û X0mœ|é(ÎÂ䦷ÖdšA&Ã9T‚¾²¤¿Â`"(m†-ÿA\_7Á:Ñ…”)Ñ ÆÞ]ê±&ág²eÄx [ªÁ„ø)„Qx@VAÞâ5ûŸî¢ƒ&+T8õpkב}Îì\]_²BMÞf)“³ßÀ£Z˜ÐæVu.{½tÒ»ÓØøn&¢šá”ã§`ÌI÷pÑ‚á>€}"òl³ÙæöºÅyó ëaázavò‘1>Úƒahz;$æLÐÊáÉ0î’Uä¸M]èØé:‰ÃG×@â’}·y¶…qÒW3{{Ôøm-JK[ïN4>qÐþ9¡PsŒÅˆQî`¸Wij`™ÌŒø7 ²]†X 9f'ª4¶(X@Ó 8Ég]ñbÀâ5ºÕC-P—±!&#™êS‚þ½À°ÒXnF–•Ïn9H†ÆÌùYé Äœ?å²ÿ2˜ ûžFtŒJWÑèAyújÆv†@±Mö±AB òò¨íç ÜÀPêíLuÀv¨8°“ þ.ÌI,ÊÆ¶¯ÊrlE¸ó7=ê5•NWЉѥS?†èoú 9OgÞ‹µÙ:;Z»fY߬!«s(™b6’m„ÿ¤å=þK¯gGSŠ4L¸ YÊ ¥ª¤î)qã )Y Ì©“¾„3b§=ëwë:¢v@È"؉Ü\yyÔˆ)?ëè ,¼¯Õãÿù½§ð÷ÊŒÉï©ÿ%Ðy3¨.]Îg( ]šG¡Ô.eϸ|¢Èó™WÑ}ëÆXŽ!Ç÷AMáð+Ÿæœˆ¼siÙÖ‡ÖΖöRõI,ÚhƒäË] ¼æ VóëôfáA†q ½<ö>´j_×¼Þ‚ ;ròlÖ4¾2dÒ¢¶…2š7ßþ3Ñ}r¬m±ü÷1É{ä5ñ!8-ȲìR‘`wÎJ¤âÚ7-[ÏhJí)t•†Œð? г˜9ò†bŽ:*µÏSkñ7oŠdLæQÚ-ãi $œŸ !‰Û‚U®ÛTé°Ñ,A|ªÉ¹½ž®ýà…º­~†0ÉoËâˆþWæÔÕg£û™`z¥ÔÍÖŒ±¥.U¿Ÿmœ ÍÎ¥ý›§Â!FPÜi{øÈ°èxqqÎAð¼Ö§1ŽÀÿ’Ú6ÉlÏP„`¿fˆ—ªüóüàôt³¨P$WJ«‡!Ú›t\šXd¡½¡ÌP8°pPûà+,謂¤…M+ –mÞgY<Ä¢˜TÈ–î%Òt}øÛ溚4Dfh/—á@æ.y4Úäô$/½œZkÎÅqéæ9Æ÷•cÓÚ ò‚…F¦ ŠœÏQ_OÙ—‰¿{·ûü6(ÚÕ—WW¥}MƒoÝÛ$üÄòDsßþ¥êÅ/Où¦%¦Ä‘C²Frœ‘]DaÌänä²,óUv»x˜¡’E(so £¡C=tòOÿrã,*$qÓ€ÕCµÆ¹W«t\÷¯`F‹ÆiÊ,ÚRÈÁÌ >G¶ ÎðEšœ–›Œi!µæ´Ÿ%Ûà@«RÅD%¥fÅó¿šÙ(Bg_J?ªf‹ã¸+|ÈIa8qŽqW£­ŸIÕõ.J¸„+h˜¸Ê?:Ú”qa€Q€¾çŒ¿ÖRº×l[iù%À‡]þž˜Åø;¾•a ,¨[‘QÛ“ñ»ˆÒ9n¯› \°veÉR qQ •æ’€€Æÿ­Kn°éfk¸iT¿yð˜xwf|_‡“«Ž(*A~©û!6ß¶sÔºÒEl:¤dÚ‡PE°Ìt“•Ï 4§ÖÞ~»_cÐ.›36‰7JäÎ@ˆ¯3ËÒfó)žóÙíƒØ698ÐIZ ß(q‚UÝŽ“]VLµêHMwvƒ½Ø ›ÁöúÆUò#tTzmhVA´òQö`àî RKß ˜Ü4ê–´r¢ÁðÜú„; ¬’”nòŠˆ^å‹Wýqº:ðž1Xüp:p A×`ò¥aY´…û¯²{ \þȑź³3Kþµ“CW™Ü–‡c1;ÛÄëî on73[&ý*dɆ[Å%l<#cX_H+) 3UÕD*À0ùm©RßbtfK1''—]=§âÅËðêü“&©Q? üßc²c7[KMx1÷œK;pþ/ kçÈ4K9GÞßÇw{:‚d'ˆyÆòóSL‘¬WÞV‘V• ð\¦l †€{øÄ®ÍHcÞµW?ÓÑ2A§"s6â),øCjòOÙ‹¾Ñ<6ô #Èä”5á-.gŒÉ „úÛ¢X§ð‡š›¹zí¡û¢¯¢Ö­Bž”g@r•}ðT†ÏÙ$¶jèøç Ý}V‚MÎ'žÊb†½u{¶l™:£Î‡Ñ+YL²ñO•&™/qðZw €‡÷Q•w~†dW6hjÓy·VêÁ ºà´Ôøøº°M«"å\æ ®CªM¥7ÐY aá>¦{ŒI­!ÊsEÐÀê%ÊTò-H˜áléÆQç ’FIw'Ó«ãL¹Ä×s¥"/½6‚H?ˆÐdLYÿ)HÚL—Ø·‡äYP«i•±=AºP†±0tǹuyòÃþPUžþ°¢@OWäUÖ%©VÏõ×þˆK»N…c Ðð­Mí4(çü]¨YüPÒŒOvuIó*þ+2L¸6ùTîø>Î÷8ÒlóýoœbØåÁáR!É ¹åçm˜h|«kRhß>!k8Õ’GÊ5:?øs>lAC«ow Ø®\*WÝiy€agÇÓûyfÂÕ.Ö…•5 ž®W×*hý{’€€ÁÑïa#ø)ÞaÕlo§sL› Kýƒ¼ \“žÏ•„¡’=÷]Ì¿œèjjìü›ÉT6ÛŒñ©d­}g>< ÷¬¯G”$îg,Í‹"ÑZ1ß™“LÞe%çÍÂe¶ÙÚåٻΆ]F}³nQ£!ÚWž®&‘¶`"`yP•2ì3ш~>زïÚ¨Ù€ÇË#•Ê‘"4FXÇÎÉhHψm8Ù©2ÃS(²„Ñ(5ØïŠ‘1Û– Û“éÓ¸ZéXº ’AAÇ·Ò¤óWÐ(³s4Î ßßWb¼×äúžyS_ƒÉ–w©¬Œ‡ü+éuaœÜ ŸàŸ[#óç‚ Ç€+P4ë¬ TR¼Áü&ÐEé,Á€m‹îLm6ðª‹Oö`{BÌ7Ù®w¨®ƒÑ\Q|‡jŠð?±…·kô0·¥0¢ ¢€Æ ù²$Ktsø†FY.?MÚð× ÞÉï€ Û—Ë5ä-¿G¶_ñ_/§Ç9Ý…×Ð8-¯éIZ­€o°k¦ ¢îb ×½{‘nF‚5’f/½yؼ¤î×kÍ çLõ×öĺP‹­ÎD,T{Èlé‰lî¹/7¼-lÜJF*˜Öe:ÇÙmË®<ÿëѤm”üul3 ãGÛ8ùsˆ(k/‘Y!ç¸Õ¸%ÏLq¿ŽúžÌä^kxóA™Î5 —ng@Û’HÅö zÃ|“y;ËÔC/Šá¨bÌpÀ1|Ût´7NY1¹g·þ®WÁÚ1tøVÚ„{…éúHÚ'Ö›uÛ¥qxÔá‘ìCë´Ø¢OöGªÖj¡ ½èéõV!Í¡ÕBQ?NEŠ0Ï©,{s /ŒüytÕ×uu5L>p‡¾qÜ{îcrðÖ‡R(û;ÈЗo Ï€,‹T¾· » jô×O$;g" ŽS[aB¹„ƒuø¯†Ô³É ¡y{ Ž—q¡È¸üV$F8­îN „&A©ö+‚øŠqè3³ë+œ¯³¯³ºF±a…Ñf,yØ®µò§òЃ·ÆYè1â¶7ÐÔ#ðMxì z¾j£Ý…D6?û±Æç(þPd%o‘~@êÅM¹¸2ÿ5׊•Êð{(ƒ¥è> V¹|ÁÇEI ‹7ÈRJ³äÎÖ‚œ|Éî‚’€€Í0O°âhTªsÔwp-šý5>—ÎsbCis>‡gÄVcÇÆÇ×uõ¿X2&öTå’³DêeÙBå•9Ë5´Pg†H,úû¿Ë¥6¦ôk¶ž*æÄEȳý6C8uFÀñoÍßA$,p#Á§©ÅƒÝ4UÀWë½hA‡Wóž]^ä¾Ê«$‹PìÆ‘å6ôåÀ„¹`Ÿœß –›Ô–¹¡b’•?Yfš¬‚ûK¤gˆ/y Ù̪.:_úÚõCvû­)e6ÍÅV-#xÏ*ßNG(ÑMþ™½3ü+hNríLåBb’Œžâ9mÂ)”ÏBu‹Á ’¢¨ñû£®ÖÁ±UôÛ³½`ºZ[N8A¾í¦€}c(àÛÄsÜVî`eºŠÅé-­¦ïh$~·éÔr&ñŸ$I(ÒxEK­©6´å½ÑåÖ¯INTÁy£rfç¶ROùòݼ¹þ‰±š5Òš>”¾¨K&È—DÝhµ £ÐhIY/È—‘Nå\•PÜú•¿Ø~î™ïPw;ÁÞÁ¶ám[r{H5 n‹tå t@•åä Îè/°ªDÑIø›ê3_Ldœl˜ÚjÎøkœœ¨jlKôŸ¸Î‰âÖ`ûå!v‰…F„6 ¦]ªMøÆnnúòQ¹©I“é–e%±T7¶% ù›e^¬wôtN¸Ïti©ˆéÿŽ®H"îx¸NÁý\u\®÷N듳$f3`¥å!ZÒ–é·-/ñËÿkÅŠ‰Sü y ù:Íå¡p‹fϹ0\rñew3Í£S# (e@Päè’y!î3¡]$"uà÷fÆcN1è,CWÒq­E0ù˜ÇÀá[bÍ8«ß~wNê/zýê“RëÕvRË).¸G‹4<îvXÍIâ—€¹|iW~÷Jµ‘°/Ù¶…?¸Ü”éx–ü|^.ø‡ù®éûyßþÊ'›68ö¨­}k(ûÒ4ée€}®ÂòäÌÑöÁ´çk‚’§N E‹ÂÉUBç·š®¤òFž˜çº(?b$Y=þ—àV¶ù$i#ݬ 2ø˜¡ûô¢Ni…pÉÎ’è7§l‰-:ãÆ\ç› ûVžnuŒï€¤R>ºj"ÛócSjÑȳ³<&bÁkSÄ5¡ëyÿË{ïÙž2ÈÑŲ%_¥‘¦òè’€€½ß¹è¬Ž5Ì#$˜´ïÌ=S¥¹¹Ò1LѵÝ׎ õs,àñ٨ǴVÞÏ#å`…“qéÖ˜5þ´Ã@Âý·4g¬4û†@]Äʄöø¯dáu™eçÔ£êÍ&xÐvô,¤hþƒ8ò[¬0lèc¦ÐÿšvÛ ˆŽ8äö—Lʨ‘IYLp[š3œ‘'Ã^Bvª¯7ñ6^_Qú‡½ö Ù÷aaÃ¥BzFAòMH“º¢ö-ë+Oòc3Àn:, ÃCã(å/5¹¢Ný·±ÑLñ›¯‹Ä¥>•`°õ“OôjH»n#ÁºÌoýÞŠšlük;:gá ²™ÃÒ/G ¾ÿÇika—ÒÔs'³ŒÀþE®I«EøüOK®K±Ä ¬­Êx{eߊw|çÉ]—ÊsBOW6ïtYL€+°0”æÐôÿ-Cdä?é¢,~][%Yc¢úÖ(“˳s$ªcKêÖÆÔTëp% øóìþKÁ$Ñ  Þ[T†º¬~3ÃП‹pN¤î%FúW íÙÓ´‹›Y¯ #ÛzÀŸCÀRKG P¢Na4| µÉb õ4xï˜Ñh]àE>i ¬ šÌ~g“‡²ÓEÂÐʵO¤ÞZÁ°Ãg¾ªRY"x%îLoÑÝÄA§þ:›¶#ìx.ŸjìTŸÛ^ŒÛD!¼Jiî}£\e4öŸ}áXÆRXÖ¨àÓ)¥E¸R%N±µ9üê¥ €_· Ü{Úg\äÂaöWt{“ùkäPíÂ&•rëú0‚6ÂR¡w-äªÿK†çö5½ÆbÇÕ~CóÀT°åo˜s5켩|âÑ__ET÷1óKk8¢¢.wÌpUÕœvƒäÏÒ[¥¸Ž[ÆzkZ¯Î´ M‹¶U¬f-× >dµœ³mì>ok\€ù«Ø‚VfÏ zغ2p׎à/ï XoO;iü•;U,ãñÆyø²Ï$’€€½Jÿ¶ïU.ïÞò@•ë;Éö?RœïK¹2N£pKa2(=˜®ƒíü)Wã¼YlÉâxLÐöRq'­Zêõb;/²ZX|ÐÙÑ,ÀEª2ËŽ»IBwî‰ê&-½÷ g¼œlÍ[+–Œ"Ðê”rBBŸÛ¥h˦Ipiõ†âRãàc›]Ϩ ³X×1 iý1^IîÁyP;Š8ßÿÿÈï讨NÅ.÷¥ß^D„SÓ‡M×{=Þx³¸;ÌËsܪ‚çKx´Åd¶E|¼‰þ¡¼ï¿Ù-ûˆnV}‡ÉÑvœNœçø½—0 ­NÈ9ƒL™±6b·™ ú Þ³Ö[áwPùö£í¢«Þ×JTK1/)Ü*ºÝР X\([ø9Ê’LçühßcL›e5érÄ]Æj­ÆìßêÊn‹¢yÓQQ`›e@‚~:~ˆ–ë©‚ØøêZEF쀉+üðé+³˜µµ5Û% 4 K‚Wà&`çÕóf€Gu÷tú÷ÿT|ÝØÚ›p,×ç"ÂJˆ-CqÓ/üQ⸫{Sv=ÇcQ§ è¡ïø±Tk ¥{zÐVèßÄ#œ¸Izñ âsçz×`/|½pßDmfíÑ.ư: ‰ÀÙƒl¢Á:cRÒýb€|ÞFéõ‘íÉ’NŒB¤(ú«ˆØÞÞ¸X RÆ9ÍËìߎ¬ó<§¥µ’Çz ŒÅ‹IL»)¸Jê$ìO±3 ÒòNÙÕðgVµ´˜²®<<Û8§E ­ÿ,çÆZ…èøe¬B$ÓAæ,.jöÒ‡Ï4EjÈĆQx±þ bu±ÿ©ÅT¸¦Ç• }¾Kß&iÅÆ'ßûŒéi†T¿xùå)^5m8s)ºUU&íÿµÇã6ºû%Ö¤heûô߬q )wêþ>´O²R­®ó©9¾º7AB¨ÀhÅþ'=uº>"zèÑÜjB:BRŠÊÏ•k­§"îÿsõ?œª›KóN9e±Gº—ICÁ£—LaK®rˆ‘/¹{i„‹,Y¤C¼ úðU b*²(lxýtîñK "r‹!âÒÂ)ʉ†?øÞ%ª+NæK˜)‡³²š}LH¢2Þ6Zç‘/ÅaŽ]/—±Ä*í{UåN…tKŠÇZ’€€½°¶á3D$·¸ž$ÈÆÉ¦e^õ?Ìû7 µµ"jéwŽ!ü¹6!9²“îÊw;lw@ÒÚP!ö$7z¥¤˜ÜüùUø¡«^Зõa>¬:ÏEö¶Ÿ$·cèìºF¯2îq QøÆPÖ ½Ò³íýù[˜‹Ú‰ÙñúU‹N¨ Mp)ãhì õ–¡VøÝþ*qOs(†¿E7ǵ¾ó‹UÒn²Ø—Ï©pw¹÷0âÙ¨ýöƒÑ:+…')ŸMü•šwÖמ%@‘eÜä ¾½]qñ&µkÍ Á †9*/iâ4Èê¶À²@̯dò7¢\ö~­¼Q~u¢²ËCOFú´(𰩘ìq5î©!¬ª©BŽæ¦]ÚFˆÃWZŽÞÖè k®G_ Ÿ ²n=õá°Ï(Ö·Ÿ  ½s2ºQTdö¿AbЮaæÑE‹°,U{µ5Œ²…)öZo^ ØŽX·”õ”û¢¨z:V29æ6bØêô->­{Îu2rš•QÕâÔ7ŸŽ­›²pDfï_LQÔ`=|²¢ÞQ†ñó¹¥äQ¤o/iMâ|5IOÇ;gº«"ZÆ%ÛŸ·Œ¨ÓGÔéòN¢5@:¯ÇoʯAPº&›HûUuÈ×/-HóOè+ÈÎþ®¾„7â $‘؃!qòãM „uäá·Íæ†Ãê"±qX ‘¤ÃI·ÖXTå¨ÿцÆ+ytìõ †ÛïK3!L, NL•Ô%9Ë?éÅ[œ²?=šQC³zÈhä•[ë_§Š¦.ß×€•tÏуíŒ&åRá6¸¦‡ÉštEÌr¾*‚X x¥Ñ´âÄ{ç±×z N¢*ƒ¥õôÊá_¯Zñ˜¹.Ö“~ªùé;¬€T6†¤“å¬?§ Ïëá^1a­ˆÔÊ?tðÛ«D¡ &K§Ùkç:yC%…˜«9$¥,ª ÌÍr/ÁXaXå€ôùríhQ0ÞO¸—ok­Û™ªeeT=ר_áC‘ò^·{§R¨IDÏ ÅXþa„8c·\ú ŒŸºP3+\ãy¦ÃŸ» D–²eãÜÑÞ'+”.×]v­:¤Ôû÷ë"¬Ÿ¬ûp©<’€€äÅÌ+s<ðrôíÐÊFÍïþTóî&ºh¸ñ!O ÚßOìlf®d"$ *ºˆ‚EÝŒ*¡t#QškZèÙ˜ý‘F<ƒpãOÔˆ%pb`ÙlÕã6¹ÿçJ^ÉüM‰dä\OàëÊûËz<€q=xÝ»lþQК¶(Mtáûð+PlÈâÄA„r#/Ï’eNmr:"ßL~Â}[£ø_H™¤­ñf+ZôºY|¸;Ì4üœëb$#ÁÔÇÙïÉYlûEIÕHì\0kôJL»–µaø³mÑTtŒ*ÇûÈr1쫊Ëó•lž›I…{ò!c›Â°ïÀ•‡[¯å@;"b[ä§ùiÇcà~Aµ\}áä¹ LøÎŽÖ"r «ºK›„HA+’l—ÑC©KÆ&¹AðJÒà!¿e`¸§ïÊ[Œ(Åòjq¹®·ÉYÖÈtŽqûÔgÚÿµYK ôç½8YótÄÙ5˜Áúý¬â­4\™­*l5ÔÊ…&TˆGŽðÐRrÒOy¤Øn™6Œžüé*Od"få˜bÕVº7;g¯(ÉPq -Ñ‘¢gÈ*\ Ž ‰ZQëá¢Ëé ¦ÐÃÀÄŒ!å8yè¥Å2püiå#”©\$§naíÏmΰýCTr8bŽ#¡l³g§ºCV¶ÊÝC3¶<]À´Þu“ÉNÕy™fúƒ` 2y÷ÝJ€·ßžc|é„PWný,º)½Ÿït Æ·={³]¦OF\}8œø1¼¡¥²½[Ô“½ÿ‚’Ú^‡v I»wÓG²m =Ÿäí$Yovu1è6¨õ5Ÿ‘]6sœZ$ŸŠWDÀ}%¨¦á!ºëN–àHÀÙ#'b¿îâ#ç~Uk©Ð,°¾Öe/óÇ`ŸBÕ`r&×ôgôH?ˆÀoÝG’ Û%[tN>$N€PïÄðtÝT’€€ª"ÅV.ìÉZtê½M!¬ñ 8ƒTËÂЯ—µ|=´6KQ¢’gÜêy˜áÁÄf³Hö¬Y Ó%ÁÞ qÐì@”yàk/­ú4¹‹“5Ý𤽷½- &Ï;4¡ë¶Æ×~*ÅÚ/<Ü+…jóÝÞ÷¡éP' …€a|üGE‘mtÇ“ïÆÞ©­ÂÞo«äÕá0•'/ÒRÜÉŒhÊ«ms³+1šË­…+ê%.ñʦJXs‘q¾‰‡û=a?–}ø¡ù›®¼ç'Ï3Á̾rv¨°»ìÛŽx€‰­Ä„ÅÓÞ#‹G0¿­fÇ/ªbÚX@aÑþ~¾òZ•C`‹/÷Ê–YÎûµª(‚ˆhñ½tPÞ¡‹ª]ŒeÍ2L3 Ø“ño ]AE3ì«Æc^è5ïytéê"ÊvçUXü_MæÄíüLoWv70»ßœk:#%÷ôI<×¾¨ —µ ‘ù;PÊ †mŒÆU)r‚ÔžÛ>L!4@·y»1[ün¡§¤ª[vÕ@Îþ„'ß¡Í_]Î5D79‹`©4åÿfNh¾{Ž·øs!t‹ÔÜ­Æ0S”ž'ZŒÝ»#­ŽìùTt8ü¢c;ÅOÛæÀÿª²™r)ò´8èòk¤³)-w÷9Ä2ÐCÊSÓþ¼&í¿Ž¼„ a ˆ4î¨7•ìLÆ×•Y1K§)˜) n-n˜;—oé¡I¤ò@õšÿ))éQÐÖºCyÒÏŸ³þs\Ç¡3 d+ ·;TN¼­oÚ%™Ñu9ó+ Jéÿ•:›B˜<—D¿ò¦úS‰5æHw¿·ùÍsªŽõªƒU´4¸ÿ×6H†~Üp-"?)+dÀi¶è£ÁI3¹ªRÙ£'Y@ær •¼M8ÀÞNïžÇ 0º¬È>žž{¨s­°¿Í·¬nÑZM§èô­MhpÈA7~¦7t<¶8 o™ZÁž$ÞD¼þFÁ(ÒT-D¿®`Óç5ÈèLÛÒšB¦˜8Q3ftxÚ‘œ ¿¥/ ¼ Ææ)“›ÖÊ:¥mÅ`’sœåÁ}Ê~ºˆÇ¯‡Ðqe%I¼=¶¯(ÏûrïðAÔ¤ô´¡I,·ôßÏw½‘ƒÄÑ£§Ÿ¾ïg†Ž^ Ïw)¸!~䃵ŠD†t’€€º”=sq õLgÖ߬ZÇÍÍsIv³½ÍΛ:¹áü³6†0Ü»Û=1f à7Š<õ‚f#d[.Ï€pF”˜è·+qôW†ÕáÂüѬۀ2åº÷ Ãá‡üÿ$<£VÁq>% ãå ×õs’Ï3^ Gƒe—ù¶’c†>Sç™ZI)‚‡)­c8–¾F'8ûjl2P$ÔG›2T=ðÖã8QFàé ÏM”'ðùÖ«v\ë%èê`7†ÖŠfcBHœˆÆ¢B*t­}ñ®&Ñç+òx§ýè°»•=Ý ¯9²¥}(ËlEé§QÎdê/ç¶¶,gE¾(‰ÔÈ„ ê²öºQôlíQÆÙÚÁ`”Ëdt)»­º_Óûÿ ìÈCÚ‰T'û Ĭ9?¸„ÈÇ_˜‰:|t‘õûNwe ³kiÆ’»²p=‡&Ceú$#`qC ™Áò&…¡c ¸¡õ­,æw€ÈW:Ý\UŸ,ÈWÖ@d‚ƒ0æ<’ŒWïv\÷žP§Z}F%à~‹Ökòf¼˜óø±žðÍijH®Óá'¦dÀM’?àlGÄ» ¸í–.QãhI{« ŸÿWVAƒñF‹œºä¡†AG+8´†÷êŠc½µT¢·ê×;¹ƒ’€€¿Ëxæ3äo*°éE™–_¬µÛJWô(ˆAV®  ^—+—½¨8|¤õ áí!‰Ï¿lôúÏÝÈXáË"I³ò¼Õ*â×ÃY÷0zúCሞþ‡Ô7HA¯ðˆôz ±.`méê™L |ÔrBp ³ŠëL°%QMe{d„hPÖÌEÚ¡ƒ(€Û)ì{˜íàÐÀ4Ërm¢lWOD‰”÷ßÁgm•o-ñ…T‚Ǩ% nÛËD>˜Ãx§Y!À-äG8èzq„\ ³Ž‰ö‰Ê A×ò†_^èp¢o(Âq¨=OÐÉ*K…ü5Z›‘hR®¦h*šÃUr–ùL?+²1Ÿ=1ú~qKS¼i2z0yðZ×SR­?ìH²ñûÇöíT¡ñz{ìœ#¾Y“C;7&Íð4Vùì‹ÊÊ?ìJ·›u†Ž2Iý¾ê2`p¼Ê™.³:M4Äð4Õ…†(&ð*–Dž–VÎ6qéÃõè$tÓýa/6G¬^lpÁ§Â"ÊàèüHܧF¾¬>™ÐJ·:ý‰ÙWåJ§´§ëG¦vÆ i_qìé!;“­F2BýÉÕrK¹ñ-‰¶Ú¤D(ä+4hѾ±oZÔÂÃ<š…‰>5DÁ  äÌ<e;4!µÉyfpø«¾<ƶ÷¼§gú§3 × ÷W÷…röE¥òlüÎfªË¹¢råR·ÒF>!Af‘ ~=H©® €X ÛVLïñwÝÔmæÒœðîoø -ÏyÁœ7ï~û—®€ä c%¯ŒQ*¸ËÍЇq.)<?KmÄ6 ‰Ž „†6À®™®Â<Ýbî,ˆ8ã ^i x•<yÅuñ¼öʈ¸ƒ\ÿ:é,Ž™˜‹méµ?vÉgŠ6Ï?ljluI5kq¾ŽÍÊ>¤¸Öò £ƒ…Z ΄r/W|’Êú1ô.wçz·ùL~¯F–;žÊm•œE(욣ê…ûÆö¨6«h–²›‰=!Þeÿ{« §èsÖ§ îGG醷÷Dcà½r ó& –ÆžUX€Vý²eÑÿ¨6$š|TœB™‹W“Qõ K£Ê.ÙÔ~ø¦¿=¢„ ýß‹ta·Í Ç®ùŒ¨) iªiÑz²´¢Tˆ¼û‰’€€¦Ç€*ÓrØ óMÚ)U9íò­–7„÷½âiô¤>˜d…ü¬X^¶²’o¦u¹¶}¹ÖmpQvgޱÀÿÛ/xSöü½,vÜ]“‘<'kíïî룓èÛ2=EZ´5m#&g•Ülgß»&»Üp˜¡,ñHy94òP¦#ìH(Kš­‰B骼 üÍCîBT5°žòZÁñXòÿ[Ò.–î_;¤N™5ñ3hgÇèM6g¾}ád‰ÍBÛO­éšWøïoUB÷ôî¦å/{9}è2+àÁÑoIíî‰u±”©çµYÉ’—]QKÜ ’¾è ŸGÑÁSk&=\=½ho"ß%mbæ‚›ôŽÌ§þÓ§Ä¿k ¿¹0Ñý±5ü}.ù®f{Ù9]²køìÓ†e¯‹=îÓÃbùM>î¸Ú¿¡§ÔÕ€…µ]Äñ°¦!©î}â±&™Ö=\ªàëê~iÑ®e¨Š–Ë·þ€N9ÂÌç2Wó¾”VôéËtàÇ óŒl®òŒV–qˆsµ׊$‚°ãW(.Da–Ë` z¿1ŸÁ\¤|.¢¯¡'Vv ¡Û)¹t²ÆºNŽÂdºL MódÔÓIcURJ•ßÖ¹¯6 òßÙ—ßRóë`Ñ9é^-M ‡ÆhÁ•rTGˆÔÔ?‚‹ÛQ‰"ª~ô…ÇlmÆÞðO(}§Æ(@‘‹BÙÏ¢ %A5906ÇLÑ++ÀÈ5Iaï*ÓaźJ-·: ³"¹ÒðSŒƒ¨ŽHEj §ˆ¢$gÁ¸°2•ãpVIÑÃÑÏÂ]°S•UÀ8Ÿ!gD{u2EI‡º@yhd}4qsâáº9_(±)èZÑÜ÷Á%²»ÖO¯;0Äö§ûr ¦=‚T;ƒžÈ/*}Èz5j‰[ NôÒ‡·U#¹ iG¥D¢çe{Àx$ Mäh ž4Äj•ûÙ‹‰­kr=ƒ>¦Iw¨ã "È ÿíôwé9ùBL›± K-`3KS””îÐô‚°QCé°Á‚›ªa8‰A’€€¸)ÈŒIÜ÷fEú!]šÇÌ/V7Šë½aIïßp´Ëd°U•ž¦…;1R‹¶bq-!ï4dwWÝö’LlAç¡¡.`k-Zsé®®ñ&tEcåÄ /¢6×Õ>)Ð8ü"äºT´{Ï Þôx ,6tB݆§À¢2~¹™Y# œm´  ª`B. µå‚æm£Ì”Œ*èC³.C… øJË-­ –qôÎ'£d\@±n-:hнéYY™Øäæ9š7Áw†$6¨RI3O"h™²96¥Ý¾˜Ø:Ižèbš]ܼ\¶‹«/Ͻ#l_/Ì·ü¥÷ù¬.Ûp âÍœþõÚj¸üZïì˜"ø.“W#½®ûAÇ–«Ä Iâ°žåThã Š8>“À~-E‹øzj÷è`$~n’€€á}½*¢à}g24cxÎèÀzƒüIÍ*Lhê=‡ä.•Ÿ³¦pE7~éú˜ß«çžÜhî8ZÜ©ÀP·¤Þ€„ОÚ%¸¹³·{XSÜ„¥ø#iº~?ÿâ>Ûï’˜MHp=WÕªRµEô¤4„Ä”7ø*&Îf1i*´šv¨–×ßd{¢x}Ò:€Þ·#,ú „wôé#á6PªÇÙÕ$…Øcvah™lƯZU@åµ›˜áWRôB`¹Bi‰¦ô£¥1=|\ñøè?aýKÐÒÆÁ6Dzх^ðOK^Ò«E™' 8 ¨½(L¢dÑO¤þJˆl˜ä!@‚æ€È^‰?˜ä@4AÌäªÒù'ÊQ‘L1s}ì±|x$0­›ð¨^g´ž”ôÌÖL¦”Å”PI›µ¤·„~'H)îÁ‡ÓÀ O¬ ‚ƒfn>$ªYôc6'1æ@>6ÀQ~CÉBPɇW–Ÿ‘æéP4»¼p!ÿƒníL2¡^íi1~%'ÝÈô¤¹ýv•ªˆ¦â¿ö±«É>õ*¹'Ÿì==:1üìq~Œ芩D êËã½ÆPÏT0WY]gŒÞ`û毌üfËòqÓ<†äF‘_°6Š´é¼HÙ^è—»‰Òƒ²‚Gl`$^>yÀ¬˜Èhg‰ UK„¿38½Œ$~™­‹¼åîÞm'HÜî¨CiSï#j>”`2`ÞГâí oüÜR_‘êÂ/ÔØ×HŠåSó>n@:oüˆõ¦9ŸOá”Í/9 5øœóÝ£ ~° ‚ILî½ö¾›òÜÏT7;ö]‚Úï ôår³?¼jJU~׊c‹ÝX1´ÐY¡& »§r^FñДëf±TùøbÊ·€#y ü˜m'wˆ#¨_¢7eòd´âæŒØçA˜ÇR,¨ôÄâr`F”ÅgÖ•¶’ßÈ^ÝZb’€€¸^«Lf,KëôaÏø'qÇR6²,âßJ0öÊšØr õ/‰ONRrïÜ‚]j—ÿ®OЋO¸2Hnéyä)½¿UàF¾Ñ /¸´ãQ^áߨÇüŠÁ’¦~Mq Ðô7+ò¶Ý9{ºZ0Ft‰Y#3dó„q¸ƒRÅÇ´Z+J¼ã€Íã­âß7‡ÌàÕ's%;X2™7âIЮs-®×„¥[üsÃâ?XNÒu,:[~Å»Jã^Ýè„k`K>tÕ›4ã(äðK´èVÚ´HÏQÈ®§ígJ!¬Â÷Eô ¢M!äèâñ¬YAµ!Œy˜ûQ9 â ê7G0È]#'õfI¼$+þ®;®UÙd…ôD Âx?,¿ƒËéu[Ÿ˜(÷¨Ð@Y.ˆ –:ëô.üílìGãI£·…ðLNÇŸ3›ö§§~6v™rÛ9cÐ/FNÐD–Ô sèðbEgBÚ¥Oƒ3Àºòg*ȇ—–ždgñ—iv»§-ú—¢áì?ª ¾‹:þ˜1½{uÈŒ‡óYPª[ÛÖ0[/3Ä9Ì9¾ÇÇfXk)TY«1Ðãº|ß;ŸÍG“Œ„¯¥3OeçñÐÀV0F^°#δû?Ì”•eªò‰N»ÙÜ2 ð^+_sx•YÜ…Gél¿WªRã¹1Ê[×xË<]û¶ø`£|ÜS”ƒ<Åž4&”Û ŸZÕž“‰a!0ºÛî‘ãcRÇ­­ëÔ—uØé~6ÛmÇEߪ2‰* Õ FZnJÆq"$Uš[‚-` ¹£Ÿvø˜ÿìÈ Á'·0u);¤h°ßQXµT¤Q2‰²,²–kS»Û/Ð"9²(ܵ(—‚ Ñ0“ôòׂ«­&‰˜ÃG’€€¯_ÅãçO¤¨ÅêÎi+ÒJÀ(„ÿhndz¬ãyÜ—éÑçm¡¥¬fçúTó4£‰Ë2äFz(LðµÆâu ç¿TZåÔO~•òÒ†X~Ô ò§†w³ëÓãc_X_âÆ)X¶ó¿t´XŸ ¢•StŸ… ŸÏã:Êv"€þÒãÔÚsðöé¾Wò[@¹ºpvE6Ä/)…íž«JÒôbV¦î%‡Ç*Šq´FÏ œÂ5e–üRD}86\tyæ3ÆAfîNª¤:¢¹ßÚÓØ¦ ˜^/¿Ö†®ÆÁyý†n¡ªËzY›¦3q-N7ƒgµ»K ñ þ†M6î¯ mÙ9R•|Š)w b[.]rãÒ¡Dý`'ª3‘<£ÝhÃÔÆ±âøy½ø‹àóqïè_É  %‹MèÍìò·OEÿC»’”FìR`M$)„VÍFa}R.ê_ÇG¸¬ÚÊéIlq’7h{=€«~û0æ÷ïœ`IÛý’ŽÁ H„î ò@É•QÉâÇz»Ÿ÷“÷¢|êï%«X¼+—âZª½<‚¯`{=^Jöªú¬Àv´fïJ7cç>ÇŠÖ ‰ëpp7î‹3=ÌÎ\¶©¶àgƒo Ãm© Õ ñpàU¹8Joƒå ž³±¿[:µ™OÝTÛ¯¼…IP›„”Û„½œi}q”f‚ƒìǯæZûÔj žT T㸲…º‚O¿Mœ. û=˜ðæK—¥ÈJWãÝûX¾žEä?¯ÿQDš€š°œÙ½:w”[ŽaJr9¤T§%Yh^r¡-™·XœÎ芲'd¡¼\ßÊØ™X3î( Û ‡«$néAªÆ´;U}Up˜M…p]€hQø'Ø:È5»ARÉ÷pº(Hêâ{WÎÿ »À ¶±'©ïKb]f„É ÄzOæÂ¡Ç¢¨ü§Ï°ãÁµœÀHPýÛ_­Ó¥ýE?Ð29L›Ù× SͱÿáPÁÏ$ÌÄŸa[ŸH½ tuâ2Ì)7n¡{¥Jp?ê^mß  KuK£Ÿ!:€ä{ôK ÃÏ«¥< L÷¾•ŪýÎ27&cÑ °¢iÇbz B²®F@Ö«£ÚV‰ë+gqt¿ïmZ`¸MÂ,Õ/¯Ö‚Ôó8¨~•’€€Û_•å }¹¸EâÆ'›¸¦j“w¶'L¤ØìM/û‡6Ë4Pnþ©¾ÿOµ$@†1²ëmÆ?]ëZï/øHárm+y“i3N%ERÛJ”zaÁeÆÙ@J–º“pGŠ K1õ‡¦Ú qj‹‚1‰î­þÛ3JS– 2_¬§ã –ú®zE–èžÑ¨:ľS¹ŽTÄø+Ø ÍWͧÛ²_Ejf­|^‡|ÌÉdÂÍÏFãmƒpØ#xÂÀ+&]€%¦‹¤ÍkR&Ÿ[½Œ]hSñ3´¨Ckih‰z6—%ÕÃ{{«^Óz s©`GÝ;á<ôPbiK‹Q\k‹) Ǹø\õŠ}Z B6_Ÿ]Ÿü¯J–Ó!Sàó¢+Ýå¤ |ÆG×18DiðsßÄ+„Äm‚Œ16!åN Ç2Ñe¾÷«œ”Îü_Oî,}áèà;D³el²®¶wé»ù[Þšj5ù ~Hò?xóÙW‰+¿Åf“€œìĵ4§%×ÖÌüžþo7{¥ˆ,:VÂ[Xëë7“yÒLtËËÜ\æ1”ÇŒIácZÐÑŒT‚ÎéƒÜ MÏÙbV…Åpæ¼ø3®"ôüác‚C¢Ö‡?Sá¬ÁÇÑ¡ÛÛ¦¾†€=*Øz£ý8Ä49ÛQ è=ÆH$É'o>L+ ›‡ÏÊDÏúúÂ^ŠË†üÚ)·´’€€ªšó/ìÍVk~6ÐMCñ42£‹p˘I˜®®O6is?ú‡aÊ$Ÿ¾•Ð?dž„»¸ vD”s,«1æçl±²)ÈÊ’wPçÿ[Tì_tÝ{¿šÀím¦§÷åƒ`9…Ù= BÛó Ö¤Ös4iKAÕ$:t„„˜sÜj¶$ðòžËX”ÒúO!Ù”ÀÞÝuà¢úTUE)_̉Ç7åjd+:ùšÿ&S¬“Ínï¯;—¢HP»~‘Ù/‡*À ÑH&’ ½~p_”ц»@œêZÔÅ:GèPZã Ñ»JªPn3-ðD/9±Á–{2èL±lj‰T`ŠŽÂ—30 “ËGHÞU膫Ò®!'0 Ü”ùœ1ïsE¤øAÑ 7…òkäø+sgª‡8'c o„zj,ü¦¹i™eš‹ï²2Wðbˆ~ֆף'Bq_ýSrç»MKn¥­õ*N?s•éË ‚Hæ Õ0$%$Š1nèèÚbBš(e™wšmÕÃà$\¸x:Äcü*fZ)„Ù$Ú¼”~äTÔìNTáæ‰Ìc•Bä>S˜…øëâ<üÏdFÔå#Ã÷¤QŒ¤kâå…L”Í¡J.ºVËì¤2‹=Ipô¬éµµÑ+0§2\ šAhÅ{içü~ùÂa¹Ú@îÙöb$¾ ¼wF›**ÐýF «~€Éë.;dgšÛt1iwÍk¯n;U™EG$&ؤ^Ûœ\ìŒX%"uý=P8éÜØ8q5‹f¾‰‹\nÞçîRäEÀÝG”'%ÙénðK»ÊÅSÖJŽA Úóé¿TX¶Rü±YÈ`ÄO).È e4ʆS•7ïD/'øMGZ ûià4ŽB2ZÌÉq½Ñ9‹æ±¦ùv²œØË1¤Ã3*‰I_“ÓN4¹¿g¡‹]ªWA³âÒy0RÌÔ·¾µœgmª¨#ΡDºµA’êåM×>¹}ƒ|‹? 7×OkiÃi²ïjï¸çóÃ2•s˜ÃÙR © mð`…­ˆ²©ï•pÞjZJN¨G ë1SA‹Ãſɓ=ħäaNÞäU…ÌÐØžâ™)èaÓ¡‘ žu\ƒßÏôW~¤ß¨û~Zßp{©ðw¨Ë+0¥ÆìÆÛv\ï2êL’€€¬ÓtA_VÄ@}X$öké«#öcïwk‚*ZMñ˜ýß%÷u(îD¬“¡ùû Æ‘lP¬å‹ïâÜœ¦ó²1Fl šçˆ FgƒÂ­þ±Wiß5B¡Ç }Õ¹–tÛ"Ò?ûÝjMÚ]Ù|¤ã}WØ]Ê⻟»“BZ¤Õ (ÉN:‚‡Ó2uÚý¤E@Óø-¥/ó½Mpu c¯h¦»U§ÅËù¬†ZM› G3Yzä‹ì¸EdÙ±„‚¾Y 3S¸5#TKFÞxeÔî[¨„¥†Y^Çd«¶0Q2f7펔úˆ "z‹)œ«]<Ó××¼ò1Ú £´©­‘|ÑtuP&ê݃Ç>q5wÀÎîî¿I^ÞŠ­J©z‘Ò ÈÚÞ4}з0»ÇRò¾„/fÅRk›ï‚ï¬"¦ú·Ê ý#˜v”#ÔŽ7&€ûÙ1Uȹ>ÍŠËd'!ÞdDO(=´Þ¯FH,#‚lÛq—ÒÀ“–|P¦'Ø"PÅÓ±{°üÄy ìp:P›WŠÕÁ˜ÀUv`wE*ٙĊ®PHÅ0hÞRƒúéþ¹ð?4¡ùC÷÷LšPï>ɘˆ»Q/5,ªØ™$4Jkž‚ÐÆCËbsxŠ DàæAp)ÞpÕGÀRìoÏËÏj¨(g4{¹Únˆ¹‹à…4·ðU#{>ü vJáZ³‹qß°5äR$‚¶qœ4Ã"xŠ<;ú—v m„üþeU±uakϪ;Ôp—+ƒ (û9Æü¶¶N{´Ô¨‰ö9ý—æ!ºfçm+Jñ¶´tó²^¦“£v’»ññÞéÍ—Ÿ ±%&1ɧ‘wƒvô{|×a–z•Hû¶˜*„ÈÂÌìtáÙæö;o >\Zë¤Á˜Ç¹,& îg¿²]à ºI˜Tb'—ÉM0 4•[+Q¾6 Ö¾÷)‰<Ï ïvÿ§)¤9EžO¿ìWWÊmNŠ¿ `q”ªû×…[i@AúpsùXÁìÆû™+4ç6¯9«ð«¢ž£NYQ¢=§r¹µ›R&šÒk oÎ'±Í1’eß*ˆJéâˤÁrømÉ_Ä œZ!øåF®ÝlƒHŒÕ´¦Þ+1¥$Þ&çtxôÁìÜ Æª´ª-û‚ôüT8e= nÀ¿i\¢+2ÿ=’€€¢XÂìªÌ„xãªÆ?ÄL£'óŒ˜{:¨"žÄ/+¶ñ«à^Jåxj27_!iÓ‰'ÚM«åà”ÀöÚ/ #nºÕôˆ/äD1+c–Mп+|åá1³_šªYkô@“eŒ‰­\—6:¤W«é‹àˆ#Þa$Õ7/_7õ1´&c³6ñvV8­½/ÿ†mÀm–Çoš? tW°O_ÂK0€ÕqÐI¯ª8ê@2ÒHÖõ¸¡Ð±*Zs‹ìWßeùʵÒ ûúZÈh•j‡ÊfÏ˦øUËX9Œ˜¯o~N×%ýÕbTö|gÒa—ù{Ð:æwvÕ½ks­«ÿÉK–“¥å(z@pZ³Ã/¬\š÷(j!<™.^`! –ª4µm¤±É_[¿—ñ]þÃíx ±Þ%«òFɱP»³‡$oúè ž?VN=òÌ—IôEú*äÀ±~ô ‚!+EOÑ<ý/"›91\sMŠk¤Ü£Ì?¹Ý:w¡:ÿ‚ä²(ö¥¶Ø‰ãõÀ—ám:cc#Þ\à˜BZÇØkçÑ|ñ*o­G;þV”È€¹ €ôa—´Ü%üZE¤ÿ»`©9З„±«Õ›ßr‹›qëœh­¥§â^ìJ]ʪ‹^[Ú…È€ Gs¿yiÄí'›š»ÿ×£x¹TC9÷'hĬô+ØÆ6C·Îp¾f«©•òõ˜9&\‘F3ÿP^(×®.CAwŸŠ2ºÍgÒÑÁËÝ„®Nœ8QóâGƒø˜*+â­‰ƒÓñêÃ-ki¥§VTf>}@eZõÀ¨´¸™¯ <•m,ñÆÐ¬ÐGí`/jÓJzàú¹á‘.@sÔHõÑ[¡~jÅÔ¢E‘{,wuÖm:{» ##Rí¥¼ž|…ˆÔZd]%MÁh±YmðC¬{ât€Œ[m¢$@­¼â@±ãW¦ #ñ+¨ò¿eó\¯‘n³ÞD®ßàÃÞ!5êq¬Ü|…ç†ò‚e\ØNÁjˆŽ–gEá0¼s~+Íòj˜GÏgG–UG¸“gYÀâHð»ú® æ@ƳÊT%Ø@ï%gÙÃo/Wb%<š À¤CçX†„å3¨=fíÍ0ˆFôQ §JwW&nŒ)ý^å~ðKF%ËE<°ÆÅ qÕ…£Y6ø£cÁ¡Þðù ”r(E·oWE.î6ñ7†yWŽPÌI¼sƒ|g½TµV ¾¯::TSæÔ‰an+:¬†›fÍ2…ÿÝרýêWâÿN;ê™®HEC¢©[»hË%#¸Ø0\e0½Ös#.XëV 1Úh>H Ë)ZØ]” :êY«­+ ÇkÊKX3–ý©Öì3žEù€æHC¥kH¦º¦ª[Îî5êtR­WoGf6dˆHDÌ WÆØªN)á‘q\¤ö/²÷µ9ɺÇ=ÆšÝñ™)Ì¢šn&PöK\†o¹è¡;­°[Ý8m`’©ˆ\|¬Z ,"û3i…Ah3@¥D~. ¨uMóéÑ Ñ™RÖ°2r²©±TÞgyF{íJ‚rDõ2C%DN·Kîkūݎzísš nÜ^ýxyñƒÞBÓ•û*¦FÌ'©„û’v @¢,ì°-?ŸÓî%Õ7dá“ÄÿZ;u¦D²'ù„°œ‰—4ìȱu{è‹ß¥ÃNPSÓK3Е÷É¿™(ÖÅõ±,–ÆÚNùÒ`c:^; -@]Ç,ÑDˆÕ|.?µ£}ò¯&ÝÒ+%vÊ'Q§bMnC´)aÒ:Î!bïJu"VlG¾•7ù>k£f¢ß~%ꢬdͺl ä@y=žðq««£Åõ¹›Ë3‡j¦7ÛõÈ È«IFPOOÎr÷ÁÿâîxºB—[KßäâBùË,Ò8Ë: >ýÒ×ñuDF<ý‡öb'mº¦ò<½[ä4¡š6¬rÂ&ó±^’B’€€Ä¡ÍÉþt¢_&ãåfÇ©÷Ý=fÌü5³“ ™’lêRÑaVd‹"¼¥§ñïîü"UèŸë ÇX|ÉÎÕ'ÎÌØ(¦F»ŽÆAàÂ#ªqä–A¢âùOÍn6ÐËA»Ââý‰‚†{¸UR!jß#Ô4’Œ9P®“' ' žl9{kÿÓ´zÄA´i6Â2!Ú¾m¥•˜¨§G±Ü‘“W¶ t}M²iÁÖ!öþ*Ò‹Àc²1îaš¡ë£rPFüÍGo‰dv±<Ì-éù©TÊàÙA@ílC¢;œ ÙŒá•ý›1H{9¬¾ÂœŠ"è×&yb£Hc±+þY6ÜÊEªÍ‘ªRÓ²âÓjÂ;›4b§þÃä­Ð’ã½Ü+1µß`ìrÂva*w>Þ¬“#‘9xÍ’tßÈDóƒ A¡uVy±é–T§mjUh{]–ñ{) 8¹«ûHcâØŠFí·â„¥M4r,_Êå™7Ÿ–vÍ”âEâ-¿ñ.| Þ× <ŸŒà(–@”×Úº l×ëÖWÃ4$1³z|@±˜¯sBÌ%F"žI‹ˆ™ g2Ÿ-ê°ÿbQ±?%,õ +—fÐd®™äÆrÆŸ‹çŽŸìÂðé¦óðÀ®8äƒ{O¹ceœú²a½¿ûIå~Šë>\ÆÜ5w„Žƒ¯/óa[ËOÇ]$‚úÿlÿL‰·×§Ë¸sù+†Ë,ÏŠ¯Â]‡q‘ßß´‘j„cUߪ -‹ÉÅ@’Ül㳡Fu2îòÛœãŸDÃ7ØÍ$ 1™õŒäZ®O Ú.[o‘ê…0pÍ6A ÈQ’•óJn€+èIšÃMðt@Ê!ÏÔ|—=p†Õ?Ÿ…¨¿9ÎD•ãŒg“É%±èÞ FÚD‰~emæ=äÇ=Ñ©VŸGlÓo8OÁOÍɽ¬t_Ajóy_ÔèBiùÊTQLiœ3'ˆ™säzÑ(Ùò”€Dž/€=¬Âfw^©•ZÌL“L†IG­…ÙÊ‹âÞ{~¹ŽÞt=’¼ÕN@Í;lÌdo 6Çåç4¯E–7(®*@èÁ9Lħ"®æß»Ø³–ÿòïo8È khšSm'/|/HÞb¼#gKJàânädÑËôežý™¬ƒÆùo3&–škaÖº’€€›Wí÷5¨£I Šd„z,L"Å)CVMzÀM°EòWûÆU¼ïhJ¢á:õ³IÕa ˆûŒÓe*öº¢HT0ûÈœâ¼:67®µTx¬qÊ# ï°pYÝs±6òêÍéo1ÕþeËz8Ûd!0PÓÊ…Qq³÷`•­:%£âxne{ƒ©|Ë¥ …`-AGÃD‡»;V{%UAÞæÞôÛ•ªÞ($h~m¬¸¹4Ó[¸F¯2B%eËZ^c˜Ìe^}j×¥|ÜÇB™q¼ôÒ\÷äVz®@T|…;¥ÎöM[“˜™¥éˆ JývÉï'Ž_«½HþHoµ¥è•wå4ëÞ#hË%‹l1°H±‘ª:NÞm¦"Bß×]„û=t˜Ç#ÒçµÄžté(h¦ÎTé{Þá\êЙQÙ¾ãÁOÑй×ÈÕ¥5 cœHßȸ½|ðb\ÑX=m-?.c©ÆóF^ŒÌi 4)Hƒ¡ŸMÆG̤ø wƒ5~PcnO+=GÉgç¬Ã$²Ô|¥sÅݱÔå[$N~,‰BÀù¢__ØÃ|Ô_ûùv!A ¢ã,.W®ÿÛ¶_\°À}b¶úfÙOXé+ëEcLtlæPï_Éúü¿i˜|óÌÇɬsGÏ-ø£ö• Ô’’Ù†œMçìbõôøüÇ$}–}›ïiKíÏ8$èY ¼ÿ¢L5Vím­¨GAyÒby¦e ömî” ò1h‹æþ>R¤<„ŽqÛB(x÷(ZË%N'YNSú©ãXæ2ˆN@KF¶gxùÑÂóp@\ÉÅtQ‚”ŒÁ»PE¸YØú‰&YñA ÑeUÎTÏ ¨Ni$ÀóÈð¦å¤¾Í7òHL¢6] h"Hô­©UÒŽ³áÍ+=ù0e¬’d`ç•L¦RdqazhÔ·…•±høMà8Þ1Ò¡ *—ŽozyR—ê¼×›‡à õJ¸†:oö<úô|` ÿ¹¨ãÇ5A­ÙƒÛ²GÆÝ€€·»9vñ ØÕSÿËæv~οèÐQzåö$nè¼îŽÝ¢ˆ{³ÝËçJߘW¶”ѸBi-®×׃`†i®Ò'z|±úaš(Á•…怷gÌzV³1‚Ž"@Ëß!»’€€Ù:@Béø›Øý6ª¶E?'é—f%Löæç†^Á;ÔxÚLê3<ý²0suoIu£&#qŠIhi~(˜ÝÁÞúý«h4Ïö"rÜÄ'ñN ž¤ø|@ù‚ èÞä÷‘ÿwàF‰ÑÐm´Ùî‘z¶f!q“âWuðCÎ6¡Ï ÿ•4N9V21Ÿk7b)±AÝAÉz^(å¦Ù·«ç~”¹ÿl¤"ybÏú‘2ðléù|´ð}6§'äà%?³sh-Õ©ÎŽÌÞ¹‰˜""zqÑ³âªæYO5Š5ÇÌ„wCéÄE¿_çk‡Û`–Ÿ7@·i;˜§âæI½gi6ï›N^Ø øÀ-»¼ ÏE¡#”Ïö43²8ðp·ØNNPèŒÙ~¯¸ 8 ¿&´ M‹=³]ÛBƒBl¶xBá_|à„çòÚÌPÖdsùŸ¸NòNB$\ak¥¨^+‹Ô;žÕ']tËbRXêÑ™Ð1¹¬a=ÚBì¾IÃGŠF¬ê¹T|¼Ð{Å“c™ã±¬_8$_שý[Àâ|qQ?`ÃL¢4ÚǼg|ﵤºåíÀa[‰ÂÉ[Àe3ÜTÛ^‘ćºÕg-)Ízª˜Ï³~äuu\ñ@ÀH ô’q»s°<xì#øASý1õ”¯¢ýDÄÁ %ë±”£¨È°¦Sé9mMð5÷g@ˆøgyÇ–RT yÎnÓ¯YP/!jHš7q¡Çÿsˆ>?à‰X©˜MóéSÇnÁÚ8žÙ¬ÎÂÁúu[†S‡°>õ};¼BÃ,a†u0û^²üQÏ›Îé2‚*e!Vl‘×®WëâqœöñZ¹ÇgZ§I©?8ªn[2¶Ëá"ä²}ö’Ÿ’«'‡Ç¡Êâ¡29íëL…0Í&žã4… U @ª1}´ÌZ)@Rcå|i_Ñ${©üʶOçÛFAÍ–Ÿ:€VîÄÇRUÔ%­çÜla¸öÓÂ,*e=ªš‚•Ðse~Ù$vU~žgVÑ4É1D~™ßÕÍ-~sý’)Ÿˆï!’#¦ùšùiDUR¬`:õìÓØL Ǫ·¯Õ¢í‹=ðoÔjú{óˆéøaˆ‚I/Ýîó·™„Ž,c®Ù‘Õ0D¥‹Z—L¢Ñ¹k#ò„X.× '5ÑhbÏ÷ù›’€€ÍؽöŽäq4&´¢4{êÌ1Ä€TzÌól Àª§‡¨ýè/…6eéø´ú×®G>ðS“hRÒ+°Œ`ª>…ÓE¨i¸/YÄàL¼‡qÜÛð©ÛÓì£ë£dŠS¨ÆF«†{K¸-A L¶wûvIÈùþW´Þõn35cô`¹Ò‡„ƒ–NKcdJRܵ„ŒY ¼‘c×ê He€ç¨"Åݪ?綇ʞ$êD¿ÅÔæ¡'<mdí°ùm[ Èñ¿#Ù«Kê'>u®ðC˾ÖÛÀB õ,•ÒªUn¬=UzÍ¢œ®ið‰E¸?NÈßã€Ü¤d°µž¤ývë*˜… äŸ)Å×TS«Y W»£÷z)t¡Ùd±ÖNŠïL÷"xçÈ,MÉ:fÏš…¼R©{I'z¼ãã‘‘ØÂóek¤3.wªk#X"S ¨9O=4’”î6¼sbojGK©Ò`³þ½ë〼Qšà¦|ûÌÿ‹¶Ol^ÈH7(Q@ãéî™ã\5¹måyõ‚-¾X«nš|í­:,xÿ®!#‰âb™j:7ô½]õxo!µ"ëu©ºg óÅ¢v¨³¢Âœ˜huòùXЈ“=DäÒTáU QÀÛ÷ñ£…'F¨a‰ý  ¬®{qÿ·o£‡ÒønÀÉñd"á‡Óã9[³'ˆ‚õ“k ç` qNîrÛwã¬ë+/¼X·Â½g¦,n/MŸ]Z_ûãwÛ0霆¶”¼¾I!¥ÏVng¬F3{ô¯*Û>•H¹ðí8´Ý}ÙöxUƒê ’.¦¥)άnÚý/Î(ùÚêÂKªÄËåÛߤáçÑÏN‚¥¶*!&@¿ðzàoÌÍnÙL ²·i*‚Râ ¸ŸFbÛvè\ŸD Ÿîɶê Ñ0ܺq å3€³jFâ{§®³¶?ºžûþYc®œË!Ë@Ú”à_“½'Ý‹?D³ƒ„fà‹ãÑ{6û&]æDÿÌã¬ÔÆÓæ»"Bd7<À£!zm%͈íò„6¡»ü±¸²O¤®<{¥â̾ÐÜæËÛ(¬A~Ëâ®1òîáL4´ì,·Z·m‹q ¼{è•» +ö§Oºñ’µ Zþ ˜ø“›u0þïSÄáX‘¼»OA¾‡Å1Š‚4¶Ž’Js^D;§G"WËŽ. ðqƨ W-шÄÓá?ν¤F¿Ìþ ÂA—ÈÚ»qšWˆ[†XŒ¤Üx—`Æ]»3ÊHƒ}Íå‹Õ^6…À¨ÃÀ *îIíAïkëáÙ\1a Jê ÙçÚðꟇ§ònxšZPî6pqg«„ÿâ¤ü%#+9ë(†Í ŸÑT’±«… ݯK{†då^Ðp”U«ÃIºPl˜7ÕÇ݆kuFÙC†¯3u¤FymöÈ›´ïæ~Ö‰JñÆ}ê}>a7VÃj¨®eˆK–¹l °ÈKU*Ž1 p›—§ƒŠQjòjqF6ƒÛ3¸&:ÌLyðGA þrR™£s‰ ‰4d†Ž¬V‹ÄzÓ#ÌíôfRÖá¨L¡) –þõsºy}ÑCVþä]"±²Þo±w§D"FXI½èìv¼¸ O!=r›ܨïê ç7}ÎÞæ“øÿ¥#'ËVŠÓÝú]å¢âyq_X5ŶŸ;m<˜}i,¬c¦m5“3é—•½ÚÛDÑÒ†ßTëc^t¦!¡ÝRý\Ú€åáK¦xÊW9©‹šl‹ è<ªEkPA À ƒìâãUzC"r(y‚7týçIÍ“ÆõþsÃge%Z“Ü£Vº¹ ”gCÎ}dpN̆¦[ÐŽM2qS2Û^^`~"R„jö7k%ºŒ×ý,ÍãϳIFïVêÇâÈu¡££¥Vw³÷îìZI•ª (—WC¥±ôóŸ{è<J©_¬ÿš-­Q cyÓ«UƸÝó2 ì²} ÁëŸ)#ßªŠŸp^ÞÑjÝÍ”\ka–åçÝk;Ä]ÉÀ"‘]|÷ú\'æã‡ÚuŽíýÍ·×aêuYNhÍ`D÷kv]·.öJÅp—U˜6Œh¦5ŽVG²)¦¤ÿ>y_ažLq"/Ýã‘Ù0ÙS–Á-\Ÿ6CCìÓ%>oQ7ÓRäÿLü;çò:vóÁì’€€²®T!j«øÙ?’ì†*´Ì-²ÕÇñ‘¯‹mϕꙌ]kff$I¾ÍÄóW¡÷ž ³²ïíê'äÝ;¬[Ø_×ÑçÇ^O)¶¶‚3öñu2œÕMk@ÇPÏ–µ›‹’V_©öâMÔç/УÎÚ[ õZO¨KSÄ @À ]”`5¥ptnLáÈ”¾Wo˜rHJu-½GþÍ>{ÏëãÜÑFeVÐ߉4Ñø¬ ó˽>¥1½®q¶jÒÔ]¯¼úîK0ŽâðæbÙØKW¹°ŠÀ†´YDŽ#£–b?LIJo_ªöÊG0ö]g2³Lã4éñ?rá…l™\»ƒíIñÅ8üëk-6÷áb÷FËg;aZ¹Òkk¾]¥"¿ýR›éÎk‰aã׿»l˜9†£{Žcã¡óú$‰]Qt -ØV$©uqêâ¯h̹ ¸£Št¡·Ë˜¹ã…l.$®·a­›‘ƒm*¿Œuóm­Lô(%ÿ¾ þa÷†ä˜ß2t°7³Gõšô©«‡[˜”3¢FÄ Ë`|t,wFëGÁn«]}A$šJ²u!Îç¼_Ùk‰+ –TŒ•l¬m¼iÑ«b¯Á[c”zKß ¯3ñPIß\›¬”Ñ«>]ó‹Jt æN¯ 4eœ­°¬3Ík µŠðhͫ݇۵ÏDfÓå,>AûŒúbú>ûŒy÷77±Š`Å? ïü’»p[¾x´ID,©²4†Yþ8Hpy b³»¹<(ŽâZ¹Ðy‰Iœ2§„?×ócv´’n°>‹HèV[ž3å:K´ºsÿÛÏÔ{Óñ}÷— º>ATñ«³bèLöÍ/>6<ÉÃXãË8ä ®åiàKæÐþÛ³ì¢$ú•Üp °hp!–„C“³a^J½'=P©³™8*Fn†’^DYöQ§:/)h®.ú6Ìoïd—ÿ\\§lÕ̃÷­Œ¬ŒÊ â6áäzt½†o~<ÔQ±UïàgWÜÇÜ)ªîC=*}› Góôâl8uFðnyøÔŸR/ Z½ò_ß åð¬X 沂±ság§Zɸ5%ý—½Þñ•™è4#p¦˜ Êùè,ßbµ‡Ð.wàs$ ût6cöù{/bó1ŠÙÜ Î6]”‰kŸËt5f<8 ×Åq·Ã eí_WÆNIÊØe ñ3?^l@&’½¢¢„ýú(íDs4*­Žº›ï;Õ5?ö× Ò¸´ßWa|¥2¯ ÷œsȹ©WlU =`Þ"aœejŠfJ4ôECÈânW£©!«å$Aºœþ8 ràY䳈‰y P»ý»´ÑÎݸýPKQvDZíuµ ±PÓó ζñ{Ÿ1º~Z¨ØÈ¡O°Ë” µIÿª#á;eѾ¾îÅŽž4¬ôPªÌlši´¨c'h>;ºâÒáÞ ©@²ÈÚ]éÐŽ¶v!tÇÃYh~9Sc€]nPÅ‘F¿x Ó.aDÑO•P\ÑSŸàn =ÉÛ¾€øcÞÁ&lsó¨ï©ØÁíõ‰éÈŠ~#‘QVä»Èn˜S¯óGç}v…|­%µ9Ê=…e³ù®A'"E·ýóg1´MøŒŒf¬)VšÐË×óÄ<#½d³N 7¼QôÙ¸œ]îüoV‰ÉSô©Ýz;hc ð¼Ú0ðý3¿ÿÂY ¯ú7дÆ&Ëw§ÒK #›wÞSU1°öj?׺‡ZxÒÇÈÛ»ÚIïü—°ñJõT.¢Á7C7ÙpцOï–(µ¯rM-* " 0·rÐÊå\øOï­ÖòAÇX"£ÖV1yŸ£Å«KædL¤pw19ì&öŧ··f׺%MëZ;/\‡ú–(%qößw:‚ÅÏ’€€ÔÔ…6•1j#´8ñ°Ÿwe…Ì=©2bmÐ.#§ŸÚ‡ÍºøÌÏO3f;<߆?çì©ñ* .âN Û—^;ºÑž™ÞB‡ÓwŠ£-é95øŒªébè›êÍNv”ç?µc;k,°Æi•´ßö«„–݃T~ ˜Ì‹%îë0*zC²°ì˜XU¥êŒ.[ðL“G£œ“+nÂÓ£ÇVIúb˱›òï<鑳 &ë6±¯œ}1y¡Ä;áIžøÖ¹Áw,·Ä¾ÖˆWÌlïT?%Fø*è U\~~ò¨r£±‹Ù!‘¥wØ|#‚2ù^7èÝÿdÔ#là„ç ÐìiÌÄ ü»1÷r˜³~)‘…Xc[1Ãâ8’–왦’bo ÅÇ„ Ô0 —GC³uhÛ¼Í>P¨vþ/©¢,qR¢Ž‹Å/×aëÑÓg`>¸ €H‡b²½ùtËb¡^üçMfœÇȪäŠ×¯rö} ‚vɘÓ÷ã:ÊÆcy£¨¦Å“ã[+P‹øG= Ù1PÚr)*Wù#YËK×™ž×½ADHoì¬ðtijlÐs0ˆU_0ªiþX|c]ô¨²wHM$ºµ÷rUÄ@¿y•pª(·Ì4CUòK#w¶¥}BTÛ.ìƒe ÙÚfÒÓÇ šyìˆMgã«ë*¡i³*ï[ÌÆÌíò¦ˆ8Îã‘Ì]˜Ý5—½]\t:Y™Ýp hi›ÐyìÜÑé\h(7ŠÉ€YE–ëOt:¸½×0ô×°ìúÀe~å}‰aªÂ<¶Y"»²dÜw{™å„žü¹šÐ6 Ø?#r&é§á#Sbßåý' }tQ׈J»Xç„wð*æ#'âð-SKY‘ÝöLBr7#¿#ù¾&!<$¦?ØÂΩìÍÞbøNÚêD–ßeì«0ƒ*3çFÜxÇâeW*Û tVxZé –Êö1†2Q¿n†p+ˆý$H¶a¿Õ'Âvç ˆŠá/æùb")Gøcµ± F û©Z}–íp˜8*¢&D‡=vÁ/ncW„Í;Œ#µÀq騦UëG–š¦Û•u©þiy-ù33 "üÑÝ4 Æò•?—‰LhÚjÚ¢×qGa¥œ·e^ô·vQRìùð "¨g‚s„Ær("V0’€€ÎþtäÐn 4|dÏ"Ù?¼ì´Åã8 œÎ73kÁ0ÿhévÄ)/Ë“ÇÅä4RåýtDç$hŸrÑ”j¾¥ ¥ ~\5Éz3õ³'Œ¢ó©“$í}0 F_vq'Jú‡¥šáFà¶i¶iMe{«yòtöFläa9)®ÖçH÷AÊ‹œ"¥íùþ¿WQöá¿›G{i#Ř?Ôé|öB”E/+à•èhr‡¥ø0_%Ó_’!]w¾OïÆ‚Ñê¾.SɦIA¸uŸ…¦ ngyà^«ºP¿Z ‚rôz¹3J–¶û+ú÷ZJù` QýYÅ‘IVÏÆ`w ¸%å²Ó¼-G˜ìœ•7Æä•¦°É¯@CN8˜’æÏqM$uÀ2Ñ>õå¤gûƒ_¼ î¢öÛ£|G€}nn«™dOŽtLÏÚ‡§„·È$zÕª¹…Vça¡ŠÝä<¥fÍ`YjаIÍ‚*êÂJ\\Dwïof¦ƒ‰ÑÎŒ]eÉJ µþŒÉO++ë)QZØÏuP •P½¸Wi8”s·“E—i 7€îXÕ±ÙßQƒPUEÁ0í²rfSÃÌôox÷…ö+ÏF ³æÑB³09hÊ`öjáÚp1Ä,Bè©-p¢—ç_܉ÊsiIk°u“;¦èyW1ÐEÁSMíf(õ^ÓüÇU ±hÀÇ)q{?¹#d\)-PÕIõg«ëômG‡TÜÍ\(¼Z远ìó«ÏiKæ´ß W:âÿÜP3ÒyÇ Ý´=ðAñfB9!{î^‹æfÎ÷â¡Q»½Ø–3ü³2Û3ÞTº}‰ æE €qäL5X» pµäü cjMm·;q 53Dfu¨’ÿ)í+±#ÝóGe}ÌͧÃ\fa¨ÑØ‘[ìÝ!}yØi­;oZÝÞÈÄÈöÙ`n©v‚7:ÕÝ^?ÄF ÐCêîM¸Óö7HqX¸õónUBf{ öú¼^œhѤМ˜éZªCyùë-È_[†µÔÄîjtw=`YŽlñËò,hv¦M]OQ·±¾‡F›bZ°åŽ ÇªŒ8ä ÍELvŸ8öAí¯~zö󛵺HS>ÏÁäH®}»?êÿá,1H)yÀ@¢¥÷ôÖšßÄž–çJn+Æç ›’€€Ò­V½]92â Æª¾¸üžÔµ+ÖøÚáú”ã‡×ìÀ¡¢òh7©2!cJ‘üÞ9°8vÏbŒ´`œ³¬‰ß:*Ô_RSÊð7Kqر_¬UÖ¼¯Õ̳âÁ£t)qeÄ;8ÅZQp ˆ‰ý­_iBéÂ|PŽîIrâ>C_6bâŠw‚ã0¦BºŒf‡üõÒ!¥÷‘æ‰)ÜÏ;°­òù~6ÂÔ¡Àsä’Y<™‘h$Ö?Ö_Ë­ë*íI‰;é¢O7Fšd‹zЧmðOáäø…xIÕœˆÕÓ³­y1–GÎõXžšŒ}“®$­i¾ÏCÕ¥hàñí-ê@þòk–“7ŽÛÚØð¦n—¸=ŠZœAgöº±%éê¼_Þà…Š 8„ÄÌ>ÛyÐ!«ÕíȲb5φÝqˆI •e-p曲‘/Þ¥Œ©>E ‚ ùüYŸnªcEQ¹Ž*È“¡]•®s{"ÎlImuÁ|žKz"À”œFræ$ b…l¤ÍPåîY›ä`Wá|½B7Ž’±Îÿÿ´ðû#⦿7¾P7Ó8\Ö®÷–¦v\+ƒ]جõÓ©Û*å…)8M‘Ðd+’€€Á”Xr’½˜=uÓ®<}ebˆ¡ŽŒ·&ïrˆs÷§_À*F¼ô‹n[žiÁü¾ q‰ «v–|ñ•bΛjs0 ƒÒD¨Œ <€øÓúéû÷D©ð(5ÈWÖº}qçæëdº¦“¶¯ÅcÆBráŠÕÊŠAˆÔ—„Œ °)Î;Å \¤YfŽ|Æ­×ÿçnr»ïbü—ÊÝ<|‰®³)”•~-­~Œ•3æÂ}$ñ¯þ!ÛXà üµëØmg¸vä4|Ð$ø6N]ÊîêÉ7G”8%À·³‹¸³´•Ó.íÙJÀµ“Þ$ºXç‡-Á ÷Ý2šs¼ÀõD»¢äPú¾^Úø¾$´* g„ü 9×>V%=ŒBÝb1Åψ_¢ž cQ–,ç³Aj#ÂtZ.+?·¸ò”u?S¡^ÝmÊ[hü…(Á‘çHŒÃ§ÎA#w‰„DZ–ï!3¶¨~— s}&’9ì9/¼JoâÕî r“øfv»šÙU9(©Tk"[ÎÂg¥ §0ž'¨µ^¦sè_+×hïbh3¡Ð·½(Ê‚ù£]wz,é6’Xk¬ˆÈv/é‹À6FfѶĔ¦½–7\á]ÜöeÞâ¸//\qÎ+ê¸1¤È ý¿àãž™xChEÁë’ÄúÂý{øŒ‚ýãˆI;mDêk¢]Òœ–Mx?Øç/nÔîö#F\ùO4ÛB\Áp>=M¼– f0ñÏpAšýÐùÄrodˆÛèë3Õ¶¥Óz3ÈùVn²j¾„áíÑÅküÄá[D1µ}´=ºMÿ«Q¹z½]­¶n¡ÏÕgI)\§|µ¸ðÖÔŠ„³x_c7¤ÜÖ0ãÈ]Þø‚c6Z¾uš>æÿç}ê±™ˆqg!õC¡ÐW€Y!½1¼x.Ÿ"VŠ1¸¹Dñ$X\öÓ°· Ïxn`ž“âÚWƒRFÒØzY1¿Ú©"é«…¬’“]äzOL~÷ÊÖ[¿ª++Q\é}ÈìIã Ï—gé*¤µ$Ùv*zާw‹L$¤ åHdß5 VéÒ«ô©:`߬šÓ×1[ÔZ´À±ûUk Ï{tž³OélØG4††’²ÏJË·HcI lýߺ…†·‰°kÃ"úA€¶eg³ÎÉçwaùüý#Àg¬ñ:³4.E}åE΂¦Çê‚‘ìðÇ7±!RÚˆ-ã! L˜'Ú(섪wu*´# T#3û€LJâëÁ,Ç925B¡•Žf-ŽíˆúL.:ïE¯¯ÿ¢±Üâ„U)®Ë|J*cÔxb öhÌl*ÒÙ$0=lÅ~ì•[¦8g£—WŸZ`ø Î t¬ÕéœÑ-œ5¾¤%nw_Ro'ø•t¤ªo~˽Κ;úÔƒô1m‡ÛwCÎä]!²:Ç  w¨Ë›hçî?rÍêTÎѽmu¯¯û”¾-V2«X’D>¶…½xßa*áRù ¬ö‘ݺ[ÓøØ%´[·Ò6)pW<‘_mmæ½Ü‡iZ¹W P²?«:¤¥öH˜Yç-þaj 6:Sÿm*™çYÆNæl*gXÙ@Ñ[‘’^FýÏöz¢TÊO¨ÈŸ}“ŸDð õ¿Œä%&Ç8BBënaî5ú#^Àþx¥v<¶tb3k]¼Mø[&’€€Ç9è¤\ç6ö¸úJ&»xÁ»ºË ©—"j„9«ºÐr¯Gš±#—Ûõß2²Î@ Å ÞeÃ'†M?N¢iË€eI­¸fr׺«ü¿Ðc)N•[Ða?9ŽV|AÅr. ë®pZæ,»v*½†¬[º:_Hª³î|o:å mÉç^y?&4ì,ب¤”Rï¡;"î© ?Á•%ÔUV% 0¸¢m;Ùþ gZ,à}¼¥FRGX˜&ŸhYÄCŽÆ(Wûü¥ÞÆ)ð‘TÖG{pEHºiúE6jÍçƒì(ð+&C‘Ç%Ïñƒh°óˆÌ—xäDLÆ<æ@oÕ7GÓ{FXÔ\ÑC¯EQ5xyÊ^¤&÷î"×°ÃNå·F”‡þ䯜ƒ°:Ÿ¥¤'6:~²ÔG3¼oxíþŒìlA¡ù f¾¼äÕÊsÅžH¢Ã×,üˆŸºqì'ìKHjXgòY¹Wä~Y"dz!©‘Äf§â¾«½ö½˜4²ê÷H±iPD»š'èz¤¿VøYŒ¬:ƒ1‹Š!)°ƒÂ«©ò¹rªLOˆ"/5™9 g9~û0oD½gâ!²ãŽç2iøX'ûÐâ.٬¤àðJ%,Ç©±qoÚÕ!…î c¬ðÒFÈ3©E:kqöº>¥UÐdœPå©úcùôç,e9‘h/¹-ÖqyŒÁ× sŘÕt 3Ðq®8ÙÊÏs–²H4Û"Ýû¯¿4Š£œÀV ué#ÕÚàf|÷öT£¡Ô©ë6ð¹•ÈmÖ%S‘/†—6Ó >n­Ú3zŸÖg†YpòñÁÿCe.¨÷Û3ÌÑã]<ãò3íK‰»¦&¼™ »‘¨*P¤V€i6'( ƒð{[±¹’K„?Zb51‹`Úä #Æ·‚"i‹|•€”ä—á(€Õí„JŸª÷~…üÃ…WRµzŸ4„™;ån‹Ï+ UjD‡\½%q-ƒÈ_›§ÐWµ}ÌU`ý•´—[npxFv«Òmûœt׎¼ÌðÝÔÓgWØe%cîæ,yÖfæÇn"b@Þid`—"ÞuCf]<¦RSЎ掅 òIîF†˜3”Tå‰wòÄ+;#PñÉ)ü¼£î ‘Æ*¾¯AqßJ8K;g•Ž•¾¦’€€«Æœ(5›ów8xÃûÓ ­‘17Zä­÷‚;ÒÌÃ%%o䞦©¼“Jd ’Ü?¦¯ÈõL'£Šçöfþ0 =F‹'YÓi<è‹NÆ©ƒ«xc s•ÅÛ%$æ||iBòÑ2ÐÑ"£õúëíGS¤âÊ«'çWÊQxÿª! 9“æœDÔs‹ºh Á“ŸŸý¸ÂPÚ\®zØé³ý&8Ì‚w”´ÉTH[YBºPìöv+jÊ`c/±ulpàC¶.°ü†„ë…ž D‚@FIÁFŠÍÕp…Ɖ,¯¢Ú^ê?{}.ð¹FÑ2ÝÓ¸Ë]÷«ãzYºE©º6òC ëø_BÈ»Ê`[gò›\¼—ôY;%ž QµbT™Ú"Pм։8À+w¯xþ²õ(nÀI>d3N[ÆÏozO‹™{èÝÕ' ¤«¥ AF~¾<ùÓÔ¹–î^sí¥Ž¤WpŸxŒ(%Ðf¤éϪacg0âlˆi¬5-d¹Q2hÁšÖ°Ú‚%ÿ(ÈäÝmk­¬§ŽªQÌàNCŒ${ùˆëÅRÞ<•ì@ñ¼+¥A LóÂk'¿¼ñlælN%ܲ âA&4̦ñ ëÍ1I´ïîmr…j§­GJ%»Œ¨M]L:¦˜à­ÕøÏã ÐK‚iŒC?$sÕëšÎœä”-‹aÌ!‡Ì&í˜Å›õ½—ùíMÔI79Ñná2…æ°zÝ•ås- P¢ uÃ*ê({òÀw¹#É*XL ¢¬ŽEa~üu»ßçIøPß)²rZùr #I@ÖK "°Ú KVjpäý©U.»±ÀìÀWÆDÒOËp¬>rsÞ«Ž‡•x4›vtÚ ñ°)¿zoGÀ÷õÛTýÅNÄ6—쓺ëq‰4C›òN"I G6PÚØ°lÒa¿–˜‘üõÑÑÀ1,(”¢$®/Ž®¢õF"L²¬Ç yD¤]Dçn a?yZ›+Á¨N¦e>‘­ÑÚJÚ¿J÷[R"ÙŠôn¢‘ëRB=W/™È `Mu©@TETVÓa*¦÷ 1{é- ãA}n”“ ¡Yý¬|äÆâ@¦+mœ)‘?HD9c©`f`Èõa•Wwkì’ÒbÜ´»´•ÄI® µªšRá8›‰´'•ŒÊ7¶‰ýÚe1Aç6D‘=ÿÏè”NÓÓlƒÛ:¤-]&¯¢†üñ¿×^ô¥L»úIæ–aM‡EIi‘\Û‚ÞâÖ[&×þÞ0]‡/–´„—Õ–HC†é;´ núóAôz,›m}餢ë 3©>"XTN‚ e£ÒòäAÒyš†:` „0Œº;x£J£6!ǯU¨žVû)ÖfÉ9D£uù{8Ë£Úäoxo;ÓjÒ"ÒãÈ)(®¨`”R}Þ;jó2«ÛÌ»(ªœÒŒÀh¬R¬0•»þÎ"VCir5ˆ‹–£ ‡Ð7 j†§Œ#ô—ÔñïÚU«SÇk´É£É®¥"~`k‹»á†ÄIæì½MB¹ÒdIð¸;tЍQôÓ;þFŒù_mèÙéQ8•5Zà­×µâÙHfשÿÀÕ7ç^ú�P 㮽)ÎÕLÌoéýVn›ü°WI}ÌV႖І7.9IB#,CéI,²öZp%8š¥·Pä´‹ g—þ{>:+w"‹’¥Â_KŽ¢û§· ƒbU‰´™ G‡IUsƒ¸物ù((ìb_Ý|(>7‘k’|£ãñÖOÔ›è Ä_ޤ{9ÁÖÚŒÙÆ3adë à±8dØ?ß¿ªLCÖêmT¯HIßcÿ•¥…誉þßÈòÍ øø«©`ýäë‡^5—!ä_É\˜oõ£O%ÞT%Úa³˜Þ@­-H¾uÖfi‰v¯Ð ª_˜~²d#·vÆ15áX'X…?zYntÞÆŠ­G]±íRä Â!ÕuÃ1'’íûEÞM¯§MµQiEŠ:åØw úÇ1À8ÉÝc»–‘eîV£ï«¤ƒ9"OR–~£ìŠ[Í‚UD}W“»8j¯ço˜Û4%gÁר’”š5[×4^&¥¡Ä‡ï’€€µxÌjê40´÷=Y-ƒJUhÞ‰—nMmoM©±ŒÁXzXh’1Є=ÍN¢Z#XÇS'ŠÌPø£3ÿJt™ôKæ‚rú^­Þå«U?Jàú4ãÚÔÍõd3‡Ù*FÊ"U>3^’€€¨ó"ÑlÊ›ŸLÙ"…í]MÉxwüC—ÀŒ,ƒ¹°£;E%ôfêä_HQ]ôœƒ»¢9N`óv>ǧqø’Æp^\z3Bë"²õ`C­NÚ€n#*Zo‰Pj©œ2p¹ æÀÂäú™Øc/1zq‡Îľ¯5UþW!¨…Hø„š§FT£`v¨îŠ0½zµ•Z™(•ú¹”¢i˃¨Ù›oÒ·¿ÂKGùÓ-ùÛÙ0…9¼k%1 Þ•¬JG¹%fN”ia~± b~à£ÄLÀ¯Òõ­Á^ç—_4í¬O‰03¡ n$DFþ3®^~¥/•fºõ`œ{ÀðŽ—8ÝIõƒ¾¶Þu[ÎrAÅ’4VfpV9#曢ŒšëñÂÑôiÀq}ê×ç?¢àJèÙj ,IÊ8Eë¡V‹³–»B´¼›kó„d¢;ÓQ‚âTBLc‚)Üieá)ì˜ñí©NÓWU¥÷‹æQΔȱ¼vóZ4<4ªÆB庆ý¹0ñD: ù-Zµ®9A¢W‚ñù}Cÿ;ûé&(ù’0ûÝ+,‚mC× …تdý[Þšm,‘§Ä0kó˜òPu:ñ ~ƒc./…ÜéÏ}œ—J@qXÐ ©&—G«©Hó}v64œ"™öC1ÙŠ—¡ÅË'×î½äÓ;·éÉÊc1ƒø"šxâU_ö†¯W*¤9^ìÖÚJQ‡týh:ß?e õ¸Ô;›öan]y¹i©îgÄ8ðÔl(ÞëIr©Z¥ÐÇÿg˜û€N*ê>úä7Ãt—8BÕÜ¥²ÓB^#74gÆÑ×:ÉyÄ—1Ž[¼‹œѧÆD­¦^ æpè1ì‡ Ò` 0è…|ØW¥Î|tÊ€Z,È`FoÂÕ—-š¨Qéh-ö}'ʇ53dcש%[NpyÉŽ‹¦‡OÑ£V!%5 R7ëoV³ëŠ·¤/a_‘Š F~)Q¢)æfKé@¬:¡ÉzB–ùÈ÷DÄ0Ïw¶=ÁÈÉÝ´"ýb§!¬ìDß»t®S#ä\Vg[/‚"¸ó£´â„w:‰ß‹ÛNa~9ÚK7]*Œßgª2Ò?Å)Uz&y~Š ‡m‰¿ðrvðNä­1bÔÕ.Qèz­’€€ÑÇš×…ýÂ!ß;0‡ –ð÷÷…àŽXt¡£,ÝNâ® {?`ݧÌ|n\Ѳ[º×݃8è<ÑÁ¤òB¤Oˆ©˜¾SC𽨷ú’BÙo´R’sÑGÂmÆî ÑêAªw~ÍÙÊŒêÛÄ»Êì*øÙhlÐ,úª”^ HÃ¥W޽RÊ¿$›SwÊpøt¨x…h‘ù×^çu1êC¤19OàI¸ã*È–*`óx ˜gÛÊËÙž´ÐµÂ`IÆpr庩FkzÙ'¦Ù÷éQ“oÀ…ìå‚6_âØÿà ‰†Fý—!bÔp]óà´É:$ƒ(†ÿcÍnpÅ ;þÐ$»ü ;·ßžÏõÝø6ú–Y|jsñŠÝ{啯5ð$ÓÁ¡‘3¶ø­‡.'üýÅ玪nm!>0¥™Àäý Ó´¼AïbBÏv>Ís"÷[)2]újZgrþP—‚…"SýýìÕø^W$«>¹@X¨(;ðšàzÊjðx„ Hm-Z?:1G™E ÃAGg™óÍÇEå¼ÈðB͇hüuRUÛ!Ç¡’ì÷‰¾Où~ÛFè{J’é’ôó^ÅÉ»¥â¨â&q/!0¢˜ãºcÑîÇNjÈÔˆä¡æ¾éÖ.Lð\,H «ïŒ )ÝðÇ;§©™§)9=ý_î^Ô4ÔßÌõ¹‡ëÌu9ij~Ò³>®¤/îhÄÍ£HTø2õfÁwÉ=£.wW=¹ÝPNS‘4Í Ô—«‚72\Åk¼>Ó× »UuСJZ¦%½y ïHßíÓËZJÃÏÐRAá™ç;ƒh¼Úÿ.W‹lÓ:0ÒÓô a¨YÇÇïS'¤Ü&"|YZ ]y”$½R1j¨¿Uw§Å--ûsiiÆÓãÆJxùTì¥1êÙ%eòÎ¥1g“ió†zâ©,.ˆ§—îÒÞUi¼Ã'—D’mç‰Qcq™X©4ªðHls—ïð’t[KO}otQÎÑ1Ç"Bi3 HI‘‚êñ¡Œ§3äD]í"@ôüI‚Ïâö³àÖYȰ:ÜðŠäE|§[ Ìx¬fW…¤ˆ”f£èU‹Yñ'ŸG:ú•Ĭö_'¾,‡O¸J=yUª³—CKMÉ5ŸxÔ¯‚~* >.ˆC¶z‹rƒýÔj’€€ÇEÃ<&úJ†»ÀZ€ÍšJ/‚ë‹Ç;'U„ü “(aÚ.P½õŸÝ;îZNBD†ÃóM¸½i1AýŹDS¿Ÿ­ïtö/^o‡åQu[ÍZ+iƱÅ<ÀNâ±_@½´­œÀ@¸„;Å¿K#ðÃ6•77!Ò³1¸ X\è“öݱùs}³0qØBh-hz¸¼+rx¯ô6ÙQN6c)9‡&ÐÆ?©UâñÙ6~”2Å6 I4åAùð€Û†þWHö7üOˆ£6ì,).Ó ÍöZ÷õOäØä—îÔrx/@>[º:tøÑŸiSeÜpÏfðáú¸í{‘ª×šóEȽå4Ar‹§«È9fjÝjÓAr”:é!ª)êa˜–*q Pcä~J#£n]b!*ìto8¹Ý2ÿõ b¿F+2ïãØVÇÄâPäᢖ 5 ‰ÃlnF†5>ÿ\ ¢u“ˆ²X$Þ¦™ÐÑ™‘ UB#ÀR¬Íåc¬üÇ=‹ÅÔB#gµF`äÚ[m#Ï?2OµÕh9ºþ^ ÏÅœ“ôÛ,Noù7çfFìù*Æ·k #iXM,ó wYH\®B3õdZÆÎw ˜è+ñUI¶Œ-ì£G?Êl±TÞõ&<’‘dWÁ—‘LĘô‘áÇÿÁM[>§L zw™©ì(ƒ.Ķd]»Ôþ¸¶ÔVY­µúæÍ¢JF)„ Ö ¦¨ìÜgª2˜Ý^’µåcyÐÙ»ŽÌ8JÏYxÔý†î„æÏWAiÅ72¼ÉÜìéƒFÍZ›BZšTaÒþ,*°ûˆ8,a#äÄœýÆ<×¶=‡.ËY÷4v‡“åË£‹ØÉxø¸”Èì"€å*„kûD»ªî¬µ˜¢·}I ee´A+›‹Š"Ž¥+q t=©þ¶X¸Ì\Ùhš¬Ò‰×c*Ex²ïÆþÿ¢rX“¥Ù‰(€t6oE­%ì‚dw"M¹)©É.ÜN‡= bÒөòøSÛ{Ok™;–ñk8T§+½’ÌtÈRõíåJÉ`hK ÈÂ| F÷<¿­M"}j†ë’_é§~Œ¤êfù& æ$ñ„ÖíPXP8¨ˆ7P”’O,£-ÉT‘ÛCÍSÌÏ6¬Á‹êiSÄñù¥—úÂÊÕíjúÔ¶bœÈñ:le‘á›nCßòÑC’€€ÅSÉ*Ú¶´¥Ö¡¶ªàQ?\L¸H¡úŒ´ÉœM¤P 0øb[aÚ+pˆ‘"rÜÖ°c™–íY1F Íeƒ´ÓGȇ 9«£•Áí\Â.DÙP\NiÅ€_ 5=¡„?†>ògŸq˜Üpc˜$áEieõÇÜ/Pž<æý`„[åTX{¨S^~˜–šô ùO¢ed øbÆç³QW ÞH}2ÇÓ²ûÀöרï¬J\‚PŸ]Êo÷õLšuˆl·>,³éXõÊàl‡ë6+&®§NÑGö©D9~~cT>æÿRÏs• ˆÞ¦€ä"(—¡ùÀT˜mðBÁãl%+ªƒ5Ä9xÈð]qúœ5 m~"¼a¡›œk_²Xè>þ©Îì.P+GÈY4ïLõbˆ+§½ª¯b¼ªìî4¸õ?"¤ºªVÔ*úìažQ=“”«6Ð)øsGm,×úÄ©ç¢iÓCf»òÕÔ<+®l 9eÇ ½ÎÈò e>·M|]çj[E]&—"ÚŠ¬,}UýÔv(aðQÝÜPB1–ò_GËð<…‚µòãiçÏÉö ë2÷ý}U=}8°œ,áHL!j»4¿ú…þy8ŒY< l²r/ïÛ:aݹzV¬¯%¬¯vþ3ÖÌfgnb)ðEa=¯f—O¦Ì«LQ•L”—x‹ôt0ÏÏ’5+{'0üž«Ÿ[®:j¼9™ºQ¤Ë@Q ]—i@¸ýITpd:™úB¶ —"M/}:-H¿ê¿î)Ô™ ¾†/Îj?þSIÒ)& h‡ìhïòô½ta]`›“Kì??Ò’y¶äx«•æ*¹…„¸Ô™d•ò¹ ¶]Àܼ€¨AN&°QÔ˜y! ““죩i}JR8 ÇŸ¡>/ G,š G\qÚ–Þáð;ŠbŠY½×ÀƒY‡Êþ@áǃáÚÒ”S§TH´:×褺*p†‚4A2Àa+¨ôœ 2´ú©'Á sÈ?³&ì­å'.ÆÒüw˜{ïC£SE×$6âèÙ1Œ«#Y÷ø<­͆7ó)Àb~ò`¾îp<«æQšº.q¶o¦€7j*’'ªJR}ÛmÊïM{-5ÝsH\ž×' xZ{Á¤hÐRuTfu*±LÉS»¡æËÿ¡qhUB÷¢É&·©"–KÂôÏI¸Ç¡—³ÁöSW”b8¼±ÎÙ ¯ßÛ?¯êÜOÁœš*éE>D¯ªj?nd‚¸ž0/•¨9¨Ýí¼Â *e”§i¿\,•T³—«d^뤽NXÒ57Èö- ¼#MnVœ½®$kU’¸I/ˆ¹0¸ß-ËdW8¸.*ÖíÒd²„¤$Z›¤, èÞÎLþâR%l{ñã»6ÔÕ*'Ú œ±ý™HiÚ:ŸeIƒev~딟·ør,¿QgÐê‘SYF—9XI5‹§!Üy€ˆºÊQH¶¶3[ä÷ß{-Þìßs`$Ì6,æ¦Z«ïôª7ª«Îÿ8C„NÖÅ'9ž|hÅ.N'nn°öňØÚ‰¶Q;¸„Z ¤ƒ<.Cw]{S¯x‰Å‘¼¦“»O¯ˆ°¢‹Ÿ®ïšk9µNôÕ@ÐüRƒyÕܽLPSU[جƒýÑ4ЕÝõ']œ ê{5R¤”¥˜ŽŽºËÿà¨ô ¾øuà?û® Ä ³Ëö×Ò¼g|¾xfßÊ[£E Ü.šÂ*¾¾s…¡Þ{vOÍë΄‰< ö¥ÛûâM3ÒrKOB=îûP’€€»®™äÖµCÀ3Lôö–›xuh‚Á,¥ÞO“¾"OÍk覒@b¹ ‚–ááìá‡õ+¸¥ÊØßø gsÜâÑÙK… ¯ª° ZPÏ•·PÆ=ᜮ ”n6QûU™0L`!qfÁ?Ö•5ñø&gy´³´ìO˜PêÜîmÚ3:¶wÕ[5;-nA~$SÚx×H"çZüõÞyA-Cþ%!}ÂLÒy7­ùé¬b$wC9ºtÌur]5àa¹ûÈ1 Î"UŽ _Œù2ïß?µ¡µçëbØy{h±ûªÊ)Ýé°C@Sþ1ZöjiŸ²oú‰ÌH] ©ŒE½ö²w¹õ…)[ŠkJY^ÌàU;ASº,bd³Mn+Ò5öý)*(Á¦5W‘~üØãYäÏ+Õ­¸sDÚ€Ä_ Ä5='˜Ÿà?ëH‘Ç”64Ùdîû7v¿"×8ç3Ö&`2)fˆzX¹/¾þ]ÉíE&ØÝjcHͱV7yÈ=½¯ßhz‡ úÔx× ¬;Òw>{ñÚÔKfnY÷ü„'Ë’~ãUŒ}XÕXv)? 22 HAO-4"°ØÈÇѨħ¶. Êx³Š@Sz’Qá•ÜâUÓÓ×DCñ®o℈L`ÓîØMMfŒ\³÷Ú—4†n«m=âFÏm:÷Øôбõ¢«òÁKš'L÷Oeì•1|ºÏfx….-Ý “/¹iÞm.Å7¢#x½àL³-eä.%vвz•pCkŽ;d­B7wÇêç QZ´Â2ŠFÒSF²uº½3JW\ò×¥á?çÌuþSvüÞQ‰ ; µjqp™ÅnCñ+É‹ yÄ ¦EZÏ8#FÊ_ñÞÖwºá;hõý¨$a€¼a¢ƒ#$ÂD§#7Q±&–€‚ËÒ!ÆéŽéŽV|uš¦åø´:{gxIcrÈdòE§ÑVÿÓ¶!;ñlój½·LH—âÍ-šš€äÒƦ›èÜmNÔ·]y° ßXæåÏSé3MÏv8èÙ5èÐk˜~Áƒj÷°ÝDŠƒ36&“0q¤ý®¡ØœP×\ª¯ÅTY:W¶]Šó­6‘Óœ“TêÓ¤LõÉ%wÞ,§œ#™œštO÷]è<Š?Þë½&N­©ÀZô‰íÜQõY4Œ’€€´d tÃoãÑöòÒÁ°Ö2«®ý÷ýZÃMû*ðr9"×;¢k³¯÷ aØ&%XG"óššýë«f[¾¼ÜÕíÀ3Ír¹!8æ6Õûþ÷®il§¬“Ý$*7¤I²D Y¿‡$ó;bÕ¶œâiógŠ 0šÒÀ+rwJZkÁ·€¶ïHÿ­íwü»ƒ·Zn¶çÈõ ›•ÄBéÔó1­ªûͤ \ÙN"ÂøÇønéCT€¦Ù®y%È蚪b•ZÑÌÀЋp·HªËy…»þMxÔûe} } ˜“óü¹‰Ä¥º»¼Ù¦9ðw¸®Êó!NçSû¸]y’’;Àð ÿàšDa³¨aD&+»É€ŸÆ`5œéDæ¿Þ!Ö<"—cz,^û—àý¤7²sE¤ sª­×‡ønûxowËÎŽ÷ßsÐ\ÔÿØsù€VVô¨‰| 5M½èÄXŽHXÑëþY£ãóÝi¼†)Ø È`~X®`¾Aæƒ#| ._0ô®ß˜¼0{>If¯Tfè/vO–¨<†½Ú2œ=“ t+ =8éwÚ’h^bñâIß~È›Ÿ ·I ™³J†ÛôÐq Ú˜ûKif5+ Ýq¢ÅzéPºŽ·!‡³nŠ[LKlóu7aÓ˽®;Ÿ éw¹û4ÈM?Ç(ïiš·ÝÆX€ SG´Q†rÏ9ÏÀ@C½ó¶Á2¡×YäÓjû¿Ú,§ˆ …c{ŠÅ'Üûó íuFG¨¢RºW¿¥ë\-lyŸæib ¢79xœõ›ªmL!@_ä›SjuóÞ{[#ƒøWäF”ãFÿÉI‡ø)gIÀ°ýÀ>KÁ‰A"УœÏ\"ÅbÅ59ùâvÐs¥(¥ÒyÍj *dù¦)’€€ÖÎ5ÄÎ0V 'µ°9U^¡2 {Ye¥LÐ ±hmdý.ž¸3`JGÓ&Š‚æ´/5ºóÂ`m@‘¬1,)˜jä÷N¶}V®þõmê[Ö±ÓèÛ Ïüju¡OgŸcÆ%~ê5ˆXylÓ«q6qöm«1H8–ëG ò„åÕZÚË-+é4­9üšk¾Tº…ôjÒ¸°‡_Sƃˆ;±|®¥‚ûV><ÓÔ6)(ÕÙOuÃ/Wü=FAll†›‰pIBäÁ³4œÅUŒóˆ=ê¡=tSLîömr' Ñ?×()ªÚ‹v„DY)­ìtÖØ`rdÔÒ/b5p=–÷ @k€qÛ X÷·7ij‘‹Ö–ÇùƒÚZÚŒÒVâÕµÞÓD²°oÀ–¥ot?k½‘PHÿæÛf¡;MDzr¤Ð?תõ̺ŽÃBc¥e9,˜HA5Añ‹ýôŒ¾³‚>APÃÛh¦xÂd˪Ò|6ÜBc•¯oIZî@žÄbiUŠ˜¨·p$äìR_®-É,óØNš$ížÍ;\ÏW¶¶Ü6&~ju<¼¤õ0‰€5|ˆŸYä\•Zá'PɆ¦ÓBÁOEЧ/-Ó=½ì´Üeÿ®²GiÔ%Þ¬c,í KÍ é(ºeÆÕ>qeAoÝNô/4DvGå_v¾Wý+w'Ó©,òî™o&G¶®¾–ûƒQ:{³ù\€<«î¤zg슋[ÁÂý–(Ѱ_?æ"B¢ D˜žI ¡Pˆ‰?àØêÍñk°ÛŸùUv”ìc¬8îñ;·Qî, ²á3[õ”#u&c[á3]Ýf¿:Oþ_èDs‡u{ S€‰ —²«Ž×#Ò²c]G¤Vbåa‹Êúª¥êGÍé:óGÛmÄ;{ñ~‡PÇDK&Éæ d1ú’hzlRâ•…MŶÇßÐ$ÐÓfZ¤Š¼Æv¬¿ù+TÇ¥´Wš¯,Z/‡÷ã6€|Px/9L¤Ç5òÙ0Ål +©Íx{;“NZ¡‡5±×®ülBGûD)ã§¥²ÕÎhgš^–¹°Zo2Õ'¤Pj·f©OOó‚ñC<ôV~\æ%U¹”ÃAKá>ÊíãI?þØàóWâ1Ðaè­_§íó’€€°aqZ ³7ñ²b!šímaV7ÿ™Ãâè ì[i(Úrsû4 Gô/Ü—òˆ¦)Þ¹·®'¸8Ï)€A·Fª»¦ ¥}¯gÍ÷z¶R|¨6 ìÚRQ|oÅ\ÿÇs­á#¬&·ŸÈ"¢çgK´øEÙ)RpŸ¨î`_ñˆözö6žš§°ã¶Zš¦ñ˜ðž“K»…~PgEٵƲÀ¹8NlQ‡zíÊÑÇÔÚîKŠã`y†u<ëæœ{mûFÑAŸÊhÓl°ÔÍË’a±b¨l”˜ë®ˆ4i…VžŽ¾ã> ü—ÂLÔæ'«!Äò”¯…8x°ÕiHêXÈ„ŒtD†â½H=‡àJ‚]i`(^ ¨ wàþÿg§ã¼oB+zÅÝŒ=’Zv »±cûÎSê­ùc9¥ï¯1±‹æÀZPú,i0nÉÖF«ô ·t?*'Òì)Fù·„ ¥ôé’p¯Ú°ì°~U‹‹ØÌ}E9jO2Mx«-0»¼· ec ø™.ÿçvmË¿ß*(Iú—Úh³*µ‘$¾~Å>îïÀ1ÁƒÍ¤—XæýÑÜhÌ|¥ª`u]4r¬ïb™:~PäØÝ˜[‘"FWÍCØÝÑîf ˜°,|ú¢×71dÌë]¡sy] ¨(/VfÏC”_žÒ$Es{OÝ%Áãi@×<ãÜ%ÿfuߣt§K¡Õ‰G¤%VÏ6¸åöêöE9×éKt(ܬ€žáO­B¤X'@™y΀Sƒo¥k˜Ú mô…³ú÷Vêª^×¥ƒiøÕ+È’Š ’ªk¯é±óÈÐìç„SЦFôÜ7—ÙÔ¥'P5Ê™=hæuÆ!½ï’1u8[±!À„‰–mUVS×ÿiè-I~%Ôs?‰ó™È¸:,‚¨ÚÃ)Dó/g'TúPúr¥(ß“É(çô¢ÛPxÝÕz‡5_á;IIDNLKÔuò§Y AXêáQ%}l1R—¤&Êøÿ†(;ÝB]X,梗ÀEÑ ×†Îpœ›'¸Lš/Ô†$VqàŽMÔ&å«®‰hXœ$V²“=Ò…æg8Æi©® éÿ½üÛ¹”VUU%˜ `å‚+=žÆ®´¿ÂÀŠÞ-RK¡,Ãã–hÆqóÆ=Ó¬GM©CWéªßVm‚­”§ÒÕÄÛJôgÀ’€€Ò÷ íTM«D(}0Ãâ[Ô¶£x\Ä7¶›‚xÈß8¹=ñy}æ5=¡œ7ªW3®Þ…¸+LÃgr Ö±çø­æDü:Mÿ‰¯OFU°4DC¦ô+ÁÀ/r=â:Lß3E“‰ç:ªþðöTú~2˜Ç«ŠcTÅ–…Àí¤B¸9–ž¨”­$ºvŒ=v¯–^tü ë¡?]Ú'Îų¸±ÔFóå„/Edp¨çÁM:ÊÃìó³s¨Q¬Y‹6Ðcl¾ïwHJ£îV±<*ï¿B*kÈÎêß•u»£s¿…ÜyŸñ$¬Ô¬&,@ŸIvRà]´“Néýx4VýRÞÒíÃòAgÿ ¬œš[ÖwPWE“…·+™Üö}j<ýei=:süEV„4åÊýüíÍ ž¥D¤@ò9Nû¦Û«Æ,µ[ÚnÏÁIÔM7›ä÷ÇÅYb_:´¦ƒðFÈBÛï8þ;™ÿ¿Raæ‚MSa+]ñ4=ìC¿®Ï°ó5!m娜z´¶Äló«@!¦?8îQ’Ë\ÊÌfEâà \–©+›X¶‚n!Á7«­œ8¼÷A`< CTrK=`í:¼m*ìHbc¿Ã©Èœ‰|ŒÏ8 k^½GXQáÙÿˆðüv‡I…ïAQ\“n!Ó-R.ÎbC Þƒsþ.˜n­Ó=yìܨÒsG-5!·äÅÕ€_çi*Ämå¾<¿ÈšèpE¡%„æW+Ðì†; Š”I º¡V~þ ñܸèýZÄQa­…eKÅúÿ\ i”ÏKÁ17ÓÅÂ\9̵˵Á:Ö¿DÓÄ$ì5 ýŒâßùÒ˜ÂmLÁ_ÓÆÜòXåËûHJNG¬nlð!‡ŒŠš•µ;?C?EB‰è’õë®ñßx!~ÎuÛÓc1b’Œã~xce%usB0ÌÀ 8ï;À]­YEªÓúePX³?d#0ŠS6ŸR?Ìðx1áÂ1ñC׊›f^¿£Ñ?0~µ›ÉøÇÐÀ(Ò‡>ùÓê¢{õ{ 0fp(ŸÞ²­V+A‰^†0`²8WQѰ%c m;„GQÀòšß•ß8šU-:óÔÑy˜]Š#ædÕ —Àd´ã“ŸX†¨28iªŽ`#çû€ûM#Ê^_Ǽ}çt¤_„…¡!¶sVìa´^¡B¢Õ‹VŽŒzòids ›ÆLØ”aMØÒø ä]!÷ñ^‹‘Õ1ÍSÔ?Ü ÅXÆYt€~”?<÷0,·°Êe¿zwÿO1©{PI|( €çH'pœµb ¶CIï|ø&/Sü¥ ähŠÕ²$Û” ÞŒ?òw¤\?wQeðÓ{Xs¦TšMGZsfð ÇtÇï¾)u úJRZ›’€€õ9þŸ_î£ ™ßc‹t]Œ¼8oÄ•¶üˆ÷ÈòÙñ×_6Ìú#¬ø;ZWæh$\S·†ŸâÀ:1àAÞî©ã-½mv4;¾¡1ÒÙdc%V+´v,wy©Sêª"kS^š½\ ³z  .·›TŸJ¼‚šyÍQ:ô~ϵÜi~+¨ý5ÓJÛ‡q¢0ÝŽïòz—´Ñ ÷vž^¿ÌîU„5]pM™'+_`±¼þD.7¢C4ÀÄ„ª^µ÷™DÓ0©3Â|&P vaN‡¸€8Æ!'ˆÉo¶¥¯Ä,«Ï®T¤sÄókû¥Ïf·€ó >#?9˳&¥Àk¹ãîÓìÞOÎq Ú¾Á,e™®Ä/{¶¸qù^qжÌÃgòu/­—ŠÀ'¾S¡E톷ÐûPP¸|g’¸JzG˜ÒëQ&ªˆº¸ïÑ Z§Àaˆ„-ËquIÿÆÒ°¹¸Bn qƒŒM—7±´#@ËGƒ±P‚'Hûÿ €è¯Vxˆh2gê¬õ“ë[s’ù¥ï7ie½Ñ$ ã?çÏEºhÒ… 9·\õ½1)1í;jÖªÈÐnãá×°Òv5ÇqNvS^˜CîÁ±Ú?¾Z÷YÔ‰ lQiǃ sµàµ˜¨6é[ýFÕô”tmDŸeÙ¸¬ßk‚…ÿ9û¸œec@ÀwªªO™KE—JåhÑ®¿ÃÌ*fx3˜owVcžE9¢¬ó(9ÄаÚ';"Á¬Ã«Bàã]J”‚kª ªk •oë–Ò>ú /|1ïë$‹`Ã4ÕöP‘Ió©&J’BR«º” uA@c·à[¢FÙùe¡Á¾ú¨¥S ÓËú_´Æ3ÿd·ÙªÒÅÅ›-•ºr΢xgÖMþ%Ý)ö™Cè û >ÒòhW]|/ ¥w;]>*ïÐɱK#\õ,K½â[=îm/_3qø2á{Tãˆ]ytšÞ5¤ñ®ˆ\Æok»jXGkk\ÔšK1²MŽ!µÌ‚‘ï­¹â¼Ë‹ L‰ðTÙ+t Ô@/Dtöí8K' Ë»´ByçÂðE¯†d[Ls‡)‘q7>m€¬¥[¹kߘѺ%ÚŒK:\)cxÒ†Õ¸— ~OÔ°¡xÖ>(0ÏB ÄÞù`¾ø=Þî÷´ ¸Vž’€€Àf—å Lûñd€Á(ZÒ~z?-(*yäÆ7Û; ŒMîlÍÖVmi5ÐÃîÜ—å_ùáÜô2;/³‘Š¥úBYÒ‡NoS÷·Pˆ Ð(º ç×øÌte¸ƒo¶Ü:8Kb¨ÙP$è7Ì &Šø|#[ÇÁ‡ôÞý6Ó(“4—ô`ýü!rOöÉ[Öì ò#ßÞ™A4CÃ΄y®¼þïwˆßÐ 8Fh5B³ÍèÚW#Q(TqÿïöPñ ‹3}iÌ€©¢ t§O)§ŒgF,êÎZž©Juó¶´<RZe­Âw²¡Ìp˜;#|0Kƒ"DógD º5§]¾ü š[1¢ ûþg»Çq!ÝÍ ©å΂›·ÙÑjRñ {Ô ew.çT Œs9[÷`›ë¾vXž\Ÿ•ÎÄ®zfò En뼨®Ö¼ýÃ}=-ö©4ˆyìdnü·ÔׯñI7QÆ}\ª˜6š û¶mŒ2ô…ºÖš»Ô‘™ˆU°® ÍÀ^Nb«ß•êØ$ÝæPþ±àª•[;ø@dG–.ÆTDªÙ´!ÀÏŽx«sça‚JôZX:ÏŒz¸ÎmhwZ5æ\ªG{³šÖÄ5qÛÝê|PðfFä$ÑkÓPoÕ(¶µõ3ßS!âv%ß&!¨¡+0–âØÔCùæß.uH:µ¦ýû:ƒÅýÍÛs»öc¬êvwVl˜ï_ãgCAo*qgdД§n‹Y~d¨Ù7_6r6~ØÍG–͸Žpëa08²­Ùî·ÃvpËdq#h¶ÓDA²§ìžqÙvè)¼?Gz .Ÿ¾Ã5PÍá&ÑH@i‰¨_þÖ´m¤^'sùã”w,¿ZÈÇ‚ˆÒ¨™zœ{ªµSô‡ÎgÓpaQ*ѤÙwçûùº~¡iÁ®]ú^I.ð-ý“qGEbͱ-è ñØN¤× ë"š¡wÖ{7ÂÏ7AЂh&qpä±.uG,œ^Ù“ÿÄ¢V—´ˆ>0žåýüJ±ÙÀž˜Òÿ׿zéá6-" @†p»=ß½º>7gïÁÄ×F¬–Hn´Ç#gà V”KD‰ÛUdoß!XÓêð1 <5Êè~*]â_îg€1 ˜Aq’€€ÀÉ«:Þ€ƒ7Õôx![XýÊòˆÔ!ȘwGöéŒ ÝcÔÌ@çë^µÖ,ëjEbµíÅ틞Ǹȷt3}ó >dVj¸ åÅ]þ¾*¯Cÿ¹”`îžh#ð ­Þ&Ž¿ão˜&Â.<‘6uÆòŠÌSXøHí­¨)¦å¾fý‘)60Œ4½J—•úù» ÅžînäHû9[/¢âñÅpèn½ø°•yí‚“‡e$™å•O…ú:@£ ÞæN ]óàí;…d«6Oü…éølž7°q‰7ôùÐÌL´Ã¾=Éëô²Ç ‡ô€m4*®Lž¹°1ÎüǬóJœŸMTüN¾6L»äàäÏ=&Üz‘Ðr  €¬å$¬è0ðô‘žú\ µÄ`àDXmÒvllß‚@‚-ð&Ý4ª r-Ü|‚Ý›ñè0³¶˜:Q¿…¼7Ÿ" ² IëÖQ¶*˜0ÎÒåfT7òÅ>ômçï‹Ý¼Qr1‡ÄÔŸïoÉ:ôÃeu~C¬"¥uVìhü67/·µE !_ŽÉ0ëcÝOŠå4d³Uc°¨ü¢{sõÝšàDZ ×ÿcÉÁ-ÀÛW]1!–vg îoyŽŒ.Ûk­ÑÚ“ ĺ¿£ÀƵvõ:nó=‹9PNµœ K”3r=+ÀPÎýOùê}UhA~½,¿B}4°÷þaî߇þ>»@Ijîg"ß§›çÀ%ÈzÏׯðR}lQK‘ø¿w¼~8èfJ¼zd¸9`°žd-â âÿ }F²÷Œð™…Sߪž” Ë!î¯ &yÊåèmgÝè7ùQ¦A†.’¾|±<ÍW†öh7†_2B”Bý­‘Ó!oÁi'çZ·$‘Afò†päÏ;òÖµE-±öK[˜.l9Myºy–÷dr/È iB&±C‰”Ùùåø²Þvþk“Æ€£kÎÚåÈè¶Ù¥À7a?h*A¾j „èÃÜŠYúŽêä,B1=xVJ!ºeéìºzÌ®÷n¤¼®º…[Kgâ+˜/MŬ™âs ®W›†|ÜÆºÕ&ˆßcžn£ÑZ¹ÑZ¬'êâéORH+ öSµ¦Ë5ˆós'ŒB ×ë×VÝ]¾‡"†uÒ–rk¨€5‚’€€—0žMÓÝ{[$0÷È xQ={Eí”YBüŸí’ïÜ‹.õÓøzK¾fÖd<Ò¹N\»pÅûJyˆâý#êq2…†‹d³W%þ_)Â…2a#¥ž¨ê²}?ˆDo…“z<ýƒbé×;2¾ê1_a0æîæ¬\T#®`¿S~`XÐÒoØÇIíJz€þF;©\á>A²fåÿª'òíyzI^ý™`Ü"`Ӣţ!˜gÚP%pø·+®v±óŸ}ÜHÇïØ·ó),Mm<=_cl9g‡ ^Ñ‚@Œ}j ý 8ú$0(”%¿0ˆ¢aq”2­“KÝŸ;„DåñÔYöCÅKÀVv˜õóØº uÇje.;-®9Í}lª¢åörE{fã…R{ªñì tS´'«°ÃŒàè‘:hU€/¼ÿN®ó­Áà…¨´E=@Í#hžFaQ…ÚIAR‡þzW 0˜+@¼™s7~3'õØ×@(ùºÀqäý.]K‹Þjî>oV1¼<<Á63VÙj‡õ_«LÂd> H§BDÂjüY¤§”ø‘£`4ºéå"¦|bÏí·ßŽ™=wA5‰ç~‹Còg'0&„£ôÔÿJ-ÓÂÀÁZDþãÇl™ Y ëFÁÆ`Ûz“ ÑN†[€=H‰Êz‚OuÝ{¯QŒ¦Eœ“Ë?-åx ÑæI‚ïr+ºçáfO«¡qád‡¤ØUy¼LÛ⬛€ ¢GçQ±{ÂéM§Ξ£JîPªåëËd O5î¾ÏÍ×=O]KioYªoQAÃäÆÞ¨Y¼>òá᪠‰ºÓè·0ìPáÃGÓS#·íb·T“Ø>b£?Öhôk˜—xPÈ@°¥sHÀZ‡q©¼ gÃ8¤’ß]¾Ý¼õ4é¿K/踟ö¸hÃÌUp¿>Xƒ¤>[+.Ùxÿ|„Ò'ØË\ƒ/èÿnmš5À…»õçÅÍ›Óm…ð/L£Ç ÖË,\£QÁ‡ßGüoLš­ 2 à'ìa17´‚”bKwœŒH>÷c×Ä"µ¨ÊµUñ?V( àž5ôßh‹ŸÖÁ@  æßb‚ÙrÐvÀ"­Fã«>žiXV;=ý’€€âU0£TÇvP»`ܳâ’·ÄñûÔͯ‘Ø´¤Öz¢tHãooªXlÒÍ W0¥°* ymœs•UÍ‘…Ú'ùu†yJÿ.fñåV6" ¬:Í ßý ´¶òc³“ <4ÿ˜]µÍ*~¼o›&ã[áXNØ8.ZÓŸ¸Mw&Ž„Õóëž&yz¡Í wbT2¬òs¢ŽÜ{NÙIMþ8Ñí *Å(¥®C– õA„Å¿HŸ6†Å=gW0ÎãÒáÜ úzLëÖ#ß?ÏqÙ¸`6a `ï»qX}èã=NVEX^Бn©+9Fú‹ûÂ5íIfj-°š/·³¯àÑ5•£K!װѸ9¥„a1¾¾ 9G&,ìŽÕš ZrG¼[}¬t®N›,;ju¿Á,©]-j:iA{ÇYÃM{1ˆf2øxOЀIN•EyœßëpÄäA•–›ýËÒ«¸·ñîÅœ¿yAGºü|Êf§Q5KY¯D¼Õ"ýÁ‘\â,f^¼“xCÇ+Î/Æ[ØÉ¿áÅ3ðWÚmâÉ|OlX×›ðc!ÑôºF؇/5epyûÀaÝYhBµý›€¼ùßèÍã««9Óøs%KñZ°¢¥QI.ø[’€€¿)!H,uà”¦µœú æ“-À]„‹XÊ.ƒø„ÅŘ ¶Ç¬èýq•Ê÷ÙXüör‚~‹¡Žû¾À¹úÏÝ×{1©÷f·íjŒlÀIJñ2.Y­'ç‚k!Ì©„t-çÛ¢f¦OܯÑ~™C§obóaÙèâ^à¹ã­É4œÞ⼃= ´ÊQÅØÜß7˲j¢o y°^ç2ëåMEï»3źX|ᆘü;YÇœ<àåb¶Ê›’fnY—_Å‘¹»¤óJ{ð¯z l¡~Õí!ÿ´ß0³ƒõ÷øL¹§ZJñ5ºKQ€Ä¶”»¤«}“s c€Ö<ä.çb_rF~y´GMV¨°†úxØóJìXîŠËÇèº*¯ZÍ”=¾ÅḧäcÝëh¤Ñÿ\±g%í´Ùl,ù¯Î%?øõ»Â‡ý*Ú¬•¬•—7lópzÕUäibÔ×.a(\º,š ¥/ÅW‰È—SXtdÓRA©[ˆ+¨Ï/û)þôVè,lS¯~@¥W +¤?Q£ ûâÙùoOÂq1—›˜š2Þ맯ßuYhUÞǼÙÓ!¯ºý[ùf‹3.¿·n¡RO¡¸»‰yÓC½¥Þ[¥M·qDÒ.U!Îx¢g:´j4ŰZ´Sjñàm˜î[¢×Uã4ÞÎêj”sgñ+9 qµyQwon›ë€E6dMÁ\ £¯6¥¼|“M¡C#ïTŸåÞhøÕBȈðˆbŸõãÿ©ØüE–H¦\:Ò·J`¾ÞX´Æ ð–4SqÍ'OS‡†¸võ Iaúa¢ö¹C²ˆÕ gÿÚ v Nå+?Õä#CíèNµ™—Áç×)ï,óO ë3sFý–˜3˜Í±SUà‰N¶>VY¿#xÑœ¯“ºþ»šþãM‰>òÔŽ›+1o6˜ B¬`\bØ”Jˆ"3 ¥`È­£€7ÜùgìPO¢“n-ÅU‹ò汓Méå…¢]cƒu ÝïY¸ýÍ#»šÿêÚc+iK|lŠ­œ“.>ƺ±–¥+úD@d²ËT¾Ø&ºržlš~åÒqNAU}QÃ’Âxb™T|ú%Ä•>ƒ ˜Hî¨&: J–Ç6›ˆuÖ•Õ¨2I6#r´Ýi¨ªñvcj‘ ÷X—Õ’€€³qÕýd‘ä•Êæ ÊœjØû(3ó#í$4» àw‰Ã1Lj\¹f|"~xƒÌšF1üû’ñná½ã!e¹+¹AyÜtu{1á™RZ>V§q±;6uà÷OäšK*gðNŽ£*4ë©°,Ö)) %éx‰ ]'¾„\wËŽøžàÈŠåß%4š¦Š!(Dk{E\ 1 O”Yw$ÖUðU¬EȨÎqÀŒû3«<ð;ó`ù@,,›ÓŽËltIWËÉ.uÒ¸bAhŸõQÙW¨n>ô¶]hƒ‚]$NЦќh1ˆÜKgÜ}6¬ú löBù2(p‘@ºë1V\y/¡•lD6ŽæM 8ît¥3Ä.Wƒ´ô lu,  >is’~» ­§—k¬MáÐ\ñA.)lÇ›4À8빑.¯ÈeñŠË¬e¿[‚0²?ð8¼Q°ë–UÜqy“ø=Qk¯ÊL”$ó$‚ÐÆŽ}#*Û|š9TÕÃ0òBû9a[!ñžò^€š{I¢8Ÿbàa!X”ÓCèý5ºZ*¶<Ie€@L[Hé˜ Ää 4åè`ÆÐï»O¼ÔgîZ Hö×}œ>fâ ¥x‰W1æùdžºçªœ4öLÖÚ”ùࣦòÉLóä{³m.y5n“H¯$Ü]ãéÈUµ<­UÞB°ƒ<¨.Jòaªé“ñM†Cëø/ª(?ÙÜ~øRËÅÙÕÿQ5vXY•…îÝlú ²“ãØ¢k¿ˆµ­Zžƒm¬UWÓÉ¾ÃÆâѧ~›ÚŽe… €™¥àWŸvž}¦9£®û?¤Ã~kHêO¥îè*ó&ç'Q#›dûëIõiö(@¨à6» ¼8*6ýñ€Vd‰i4GxDØ#™‡¾Q©DGC·%«±ÑÕaèŽ=‚á4žñf”S‹t,\¹3Á~»ç D×è_ÃÔ¦^›1ÝîÍí]Ô…¯åy@T"í<¤x§Ï0ˆåuÿ?¿dJLqBð¬Õ¦w²TÙ«wª›j~‘l½MWÐAÍòx5àúN)]?¦°¥¿½¼Ñ Ø(zv‰ý3bÛ†%# ÜsÏŸ•pzL²ØAËR ǺT–u+2è×’€€›ß™&¨m€½sÚcžš›ÙÇ­ Íe™D ”yåוtã„s€cœ§’B D‘?)²¯”€ñœ0‚™C_MlÚct>¤aoЈí£á»ln“¥ZÈÐHø‹êãïZ `ãë(éC7ÌrU±<lH40MŽnï< <—½Ùýh«d{Ò²Á1r“?Ï­öêÜá÷¡m­]æ°GgŒxâåòpÏ< ¬™“µoq ¥¯»oAû2@ߊJ”–§ñ±PæþueïAµ_O6ÓFªràKO­÷Tâ(×Y@óCj}GwôÊ"‰à©äöÍPZLQ‰g.Z7™ï”EU÷Ò‚> ñ $þéeên¿ ,”UYq„Àp.AßÓÕ-µ¢Øj]C@YK #S>ßÅŸ·¢# Ì‘øÕt±ÀË^x8êCDÓç ôe!²®¬_"Ð~˜a0&Ú±4oÿ?Uýc è ©;9±;—õ)ßÊƾäå]N|!!nŸ†Õà9±­äœ:öÓÔm‚röä3 fOñw+_ á3hˆ Œä$ó1¦'Y¤GŽQcÀX8i ûMב5c×WWË#›/ÜבFo_ò‹SÏÚô¥€UD‚ö…Å–\XBcþ²4¤ªCŠÅʸ{,ºš°B 08­c#È13õ— ˆÔc_íDÎRÒO€†,ÎÚxoìi(4w§¡%ªÊ¼ø÷Q]}=qÈk?ò¦_ÒbúO xs¾lê]"î7æÇw²ÓdÛ³K Ya,ç²boñ ()9óÿŠæKooìá/±²0—d5˜V7·ð®=x]6toÇS‘‰_t&Œ€ÖGÍ’9!rïxí0+~%6û)icçegÊy<ÔG„{Ü›!2óPØÿÂb·æ …¡•>™Œ ÜךµÕRƒVF»Ïõys)²{ùNgéô_’[ó"ýÂXß (M3±ŸLqfß5’€€·ßÚ÷³3¨&º$,Ü]®g}+Hƒù'À¬‹Š‘Ýî™þÊT»Êö#£xà`X<›(Œ¾y" Z4êí`5q åÍö¡OÕEX ­>žJ%#4Í?_¸²æ• )›öp¿ß©Õå‹ð¼… ÃÃÄ䤮×E\¤Ð§³x¤ Ôʲûo‘{§â>¢¬È/Ñ0ýÆ7l!Âæ èI ÝøåJ0îuÇ ÏüV8…¼{M·v³Áß²ÊIdçZ‰P–„Ù”‡Í±âsÅu꘢“''ÞÃCB»Y‹§g¨vú^ÆE(¸ùd¿ò©=²­±(»Y`uoa¾‹q=ã@Ê‘\¤1ÉHìø¸(¯v¡4;~ú•AÇŠþ©Ò;QCÓãKUá‡Ôô>†’Bг\lW~´F`bÈÜ·\ްÃDOm‚KeŽ•{; àAŽ”ì=ÈNËe«T¿‹ÈJý5Àÿ ËÂ|BðdcÕäVÖ'¢ÂAÅñð%EÂ!èKX=ñ8Ç`ûÈ2½™¥·9ý¯aJuœþ̆ÃõÎÕ|´ü+¾ÑRø=¶ZŸ‹§((Eè͓Σak+}¡Ãµ¯Y˜³ÞVÝi–BÞ»w*S.ºŒ5Wü–(¿…è›)ËKOsëeŒûVãWrê“ ¿òAžÝD$£Šé–ð`,ºTy+!Aé]r¾ý=¨¹¹Ú70\„-#~u°a)|)©¸ÃW Ò‡R‰¸ØÁtLЈ¸5ÿzyOwáßÄjUáZ³Ó¶8zÝš§^a¸®kB&¶cb4ÝTµäN‡Õv æl‘-0oS Ã3v݆¶>¸n¶Í¯H¼â´ÎþBow¼¥œ»+þ$‘aÃöŸ^ƒ?¸v¶Ý~ë³É£D#ïñ›‹€gçNäA$ZêXTßEê]ûÓ*H££KÍìv ¼"‹²ò<ŸÔº( oS8ôfë>ÙùÃkQM&( Å4CÉCÍCNÕzã,3x­·ë|o¤·& ìr¾£B²MÆQÅTýáýù‘zq!üÁ¼}¯zçbXM½Kcb)¸!URoS¥,0ô՛͓wzµ™Ì+§g ’€€¥8ºTÑÛ÷/23ÚÂ(Øö²à…’“¹4Z”Ù˜cšø÷&Hsü@À™°ÏºÄ3wkÉ#þTd‰n;"äÔª3b¤[9°q¿½;äMÏXà-gŽ¡ñqQÅ^¿< 1$,žëp‹A4.Ì2„u‚›ePì‚™ŸI-âÎ5Æ¡GÆ—¤­6aó³#ºj³•äØqWò=GÂý¬§ZNé‚ÂÎY‚ï@\T|Sl–²Ú$EÍ!\Ã!'\'×hìîqO‰‰2œTp×Ò*leŒ]€àÅê­@àõÛ²8Å`’§c>Íô6Ö”\ØjS4 ÌàfzQh%ãt‰âoÂ3V)³ ÏÄð¨CŠ˜€Ý‰.Ò}(‘>ENÎdǽùÙ ‹î¯l+Æh Œ9éênàE|nõ.-I9ýóI‡JúûÒK]–GýB§æj=ÜÁÆ/¼´é§"EfÚöµÚ ßb[-íÜÔ9àæZ´6Çá4£âkêÂzš4Ó?="KÛèŽ|Gú§üWHáÿß&»DÑ@è`î4²oVRéEFøç¯P¥uáú#l0}AøNŒXj'2@ÆB]Ì‘¡•'„ÕúÜÓw¹twvàìnEögS žW> -Ý,à!Ä*Aµ{ÊEÊ Á|¸Ày'5UÄb‡Í3y._qyT‘äª[C–ñÔx—ã im0­W­„/ìJØtðt Ñíq¹5²Œ%îø´RŽ„¬Â!bÓ©°,ëà]»ž¿4/‰½J*c/ »æÓÑtÕ8Íϲ^À¾°‹Ô xã(TÚ›¬å¯-”t‘Æ6¯u‹;‘®éþÚ~Ýš1¬¦NÆèø[{ÿ5Ç2¯OØ/AòeD55ÔXšr—)ÚcÅt‘ÝýÇœbJ.¬|RÃìÖ=Âé³Ö—¾„`±Í²ÍGB¼M†LrrÂqs—¢ÀZÿñLVB& *=M¯Ï7;†‰Bó+·²Ob†“Ly C¬ä÷És±AùËú±–·0·Í®‹h Çʱ n’ÒLvøÊÜH^\ÂÈõ]šl‚üÅs[Æ9B7Ž ,2b½`ö|³:ÐÑ9‘¾#´ à¼\âA|¢®²¬­äѤNˆÊà9SåÉ„•©¡aý<ÊŠqÏÀ¨E… „¾Äƒ¥x†Ê„¥‚‰½Ô”ÿ˜ÉI8o“’€€ÊÉ? ¹9êHÌ"ÿºÖ¶[,¦±p÷Á4¼;ï F+L¨˜/Ô‚¦•åâÑúÿ9áEÜç-âY”Ám ®‘—¤GÊ%¢kG:ûìÒ˜sÃÃsß0m£Aˆ¿žšF£r3hETpÍLNzXÿ»FYBq³ÀÆ)ƒ˜•ÜW&W†V‡#;Cñá…WKíˆÿÙ™Æ)!¶~”½@Öü“Ó'Ø®º«¨g"7 $hs™”xo)•7…U´¸Ð’»T¨ÝÜ„ŠÖ@=þ>_ˆ¤ÅS^q–dœÑáZ©µ®é>xÁ}ÞÓ¯ÔʤhÿÙÐIBJëìûvØçÎ9º<ºd¡Ça<çÌ»šUY|o àÞ¼ŒÝL<¬æ](=Ÿ€T)ž%Rp¸– »Zürf¤ŠÉ`0Ñ…{<ºø©ÜçÌ‚ÅÊ VÚ¤Õÿkå}yyÚuðÓ\lùoÌà±sD‰½œÑǰaVòØšÔe à7ˆcà ‰±äe9Œq MÆký Õ¶º‘–hüÈ,ƒùr½”yÐk܈;s‡;éÐÇjÌ:gS—Ø)jËæÅ$Ž’óBíþ,¬´vA]ÝŒ²àÆCÕf8¬×Ü 5£xNÍ8J?0S«…§S¸ o>Õ7ª\ ȈO#²Žïqj¢ò5Þ÷NjýàþÞŸö j[ýO3(‚² €Ç©=„ëà΢õLyáHD¥~&ËŒºLˆàÛgá…˜‰c«K€æƒh=%5Y|lÎ(î¡'€Ë|ª£@ÛÒß)‘º(“ZX+0©¿œ ubw‰ 6[ª•Ï.û‡7dc¬®´ágY& ïD(xŒuNýè+ÉxÇ(ªÅ'™ò£Ž~6Õr†ô`Às»Ø À…\»Ï?Û•õ¸V쵈0KtÿàÿÌ úôÚ b:3¨¯ÅÑnCBô%Ìê{œx!S:áP¾Õ(~\ÎÁÐ9,—* Óª,‰`6˜H):èç0±í£9¿+6l)~‰ %Æ¢Ž9ñêÖÓŽ²Ï;uvÞaYÓa-Rö¢¯(µM_Ý,Šæ4²M>ôy·¶†¿}xûLe_†Š{—Ô÷t·>ÉôÀåĆ\$Ý3Õ(ÖP™a;*Ts>Ôv¨²5{©X~ÿ ÁôEf#XC8LUÌ ô=yY·ÍÒ­³î+æqrk %TÐs¤ÀÑ3#[†$ D-µJzI˜­ù…Ïz½fT½:ö!د[™ÒYÁ"“9@þt¶îP½öÐwC)È|+&ÀQÍš~äÀ!Nb·¥$ÃYØR!„õ`4öv â«T%HõTFS5L*\¼ð§§ç1lÒ,6 ÏÅ'ÔF*™’€€ÊÈÇ{œI_€†æ)¾=Íu;¥’ÐMÆËÝRx&Û4V;pEÈðöpÙÇ5'K ü¨C"d‹ò {à¬ð9¿>Ïž«–Ñ öíÞ¸v\7¦ò¬¿“Ó•áVCw¼Êö —õýq.Áé©,·ì$Q»^Zƒ°( Û&˜sóm™2ݹO$I^} ,0Ñ¥’nðüVšd‹ŠÕ!ácØ1TŽs+Ó7ƒÝÃÀaXÍK§käÐXRèR IÓŠU¹€•;»<ìb:÷ƒ±LçV‹u/ùâ—. ÷ij²ÃÚpæK.+]DˆÿƒyšÃ~)¡{a}ça×i6¨çkH:“ö#óþ§@ä;{lßàœiX{«ìœL 47ìЀ㠿bˆiŽ£.èèÞš¹±”eƒ¬œ…Ì?¨&¯£¯‚¸rìª*„›ÏÛ.w¿Ü¹ù\ÞáÈ-œŸu©0›¬û7­Àöžƒ×w~Ö™—RÚlzǪõsßʳ=a÷ë…©@_È·ªrÙI+¾Ãe§Rk CÇa}ÊØÄÉ' Âç6ÎÞT&>¯¤å7ôõðl늕›üFzkýN÷²¬¢[aÊh,.`ÖøjÃÐŽôS§žêv³n€¬$4‘ˆ:Ø›ÄêûÊhØÇÿïKêôIbûÑd¬Ð³¼ñ#u‘á‰Jöä©xLP¯éô˜mð^÷ˆçæÒQi“8Þ%¦”Ü0 LjúìÃû)øÍÐ}+õõ`Âè­.ÄH ާû†&ùao8a"”ìÞñ%«z­váõ]Ã`ɲÿëV‰(O!'tuŒ±Ugz}ó‘´^òµØaœð€ý=Ô€áXäZ9P 0¦É¢ >÷R½t‹|žˆ8¤A¸<Ût’¾¢/dcjÈ{/ÛEód¡7 Ü=A|›Ž・ÃÀ"ûçàçèÚV²"UÚ•o²ÎÇý7!¦íj#;÷Pn=½´H¯yC’€€²?ã™ÅöZ%ÀWúÅ0ÿD>|­’ý­ìdRÔáâš‹¦ TîòX~' $ËNH?òYEãÄ…'ÚPÌ™mêdõÑ;Ò¼ˆØD>÷m+Þ¸7t£ñ5¡ž G¿Hw噳Î'ë 1¬ÿ¡¿•µ7‰7.|Q'þP#ê€áì™øj¸!=EÕÚ 3H˜Ö ¼ú5ìQT³öë ¹þ–Íwwýÿá—,ª¥òW±FÕ9…}…/Þû uA‹˜.9Ti7éÆVþÛ1±:šÌ}¶•ŠO£IIü“Ú@ð™Èí^9j–guÉ5¼ÿ¬“i…H•©<£¹%tüd2Ä?¶Û³ õ¢³%?î?+qò½ÒW!Åßì¬È= $Å¡}-nìÚçúˆÂg· k `ág¢./pÚÿ#zø´"ÄÙ‹¼t’®L#wÃŒŠË_–Hkÿ펰[9Žë’YĤïJl…^oÉTåñ³4_ö°Ý¥ ·Œ¥0"ß9aþƒŒEíøt°:CíÇ•ÖÞ-oy`‹]™Üû½»â)S&O<˜ÀL€5xQ¨ß«[ƒ[ûýÝöÁ ¬—û,¢­¢Åð[e÷ 6´²ì—Ý= R– QgýiZ —ÓŽmQz³ÿ2ï<ßõ„D¿yìöèi^övˆúíÉ"{‰ÝÕÄ-=+l¹NDË=¾Œj]ãÆ­—¶ï I3‘«ä‚ =múDS¾iŽ¥ÙÍ$!=¯ßa¡¨ÀjÎ5tU…ÅÉÖW8 ²9 } ߈¨âœï `¾;Uymù'¯“”Å)CÓtçyaæ&éý¹,®}e'À’=öa¦j5!œ“›ü„µ#TZh´²• Ïñÿ@ èâ÷§ë›0ÄÒ·ð}†T†ýŒµmzF¯)86LŸ¤5ûQ×Ìè0}¶–”'á©n:Y^Èž ºf²ŒÀ¼¥Xaœ§œz@O×›„N÷eô¡F”ë‚÷^‰êÅqÚèúêwÒZ^P.Úgãp)¨ÊŸ×Æ×‘X€7®T–ÖP|ÌŒ\s.sÝ*p§Ïjv¹Ä‡¬Ô–ïd¢¼]{² (ò}á)"õÀ8§`LB˜Õ<\e)õ÷S É=ZK#ªįÝÂ: ÈÉ~ùN&¦Ç~‰XhÅ‚L`’€€ÇN["$¢VšŸ×¤áÝI7Ì=4¬T&(xÙÁA…Fu³á ü´»Ð¡&T)áó¥âÿWþíF[[eúz¶åGâ·m¿¿àµ>*óšÂw]‘í{¤õùùäVšê˜§IëÂÜ։IJN^8éýÿ­Òýt)·V4Y?Foåçµ1m§$X{Á×¾ŠåE'DÌíP7ö‹ë°¾ £¯É™¤ÒËýà×݉îö¾zö.¾Ü¸3V˜0ßqjÓ¨d\Ï•€²u´È"܉¦yRÑ]È:´°’é8´çQî€Ã;Óÿ6Á.ÓÛW¾ØnðДÈ0ÕÆ‰.ƒcC¢²àù{þ –ãë)ÓdSÖ¯ëór‘P.b—Å羘ÆõÁ½zœtVÜN ßÉÏÇ =XÝþeŸu?¡Ds6± åÍDìÝ.t‰1Lä,ó(Ò ^ C1îùîbfÑ#ž¯QµÔP•±ƒà‹§æòÛܾU½*@Û¯:NuÈšÛùâŽÖÐ5%Ö‚V0ðS!Á k[Á¶­]3’ö û2ƒ¶Þ»y;¿¾£“¨lqÀÏWX}Ú"'™Ã)Vã¾êbüC®aëÍâêT]ÆìàK–­ñ1ÂϲxÔ–¼f>7m ÌÙôA ßµe/ô¾ÊV'”ªéõB›oX5çÜ-w¿ÉtC`“Žìg¯¤C"6j+×d?ƒ5ˆ£¦¸hlxÃd‚2¦…ÏÅÐùéR>.Ü/½KФ@Œoé3.´I$”nF¾ÿ@âš,Sr•;*ÂC“ƒÇ»"«|ÌuÖeúk ¾¼Ä ~ žÒMЗÆvR$ÁÐÛbZ&I±2”")}fÿ¬Î†T¢6RuË­å= ´Ë‚´3y1]År)=ÌdÒÎÛ4vžÑn 0e)<óTá©84LƒW_#•耆•Ìw¨ßR/Ë[» eøð!¿;Ìû©æ¼úÆ£FWšœlvÆŸ§NܤüL¢Â·M¦ñKP[«wfJWYc(ö=]æ|“׎ªÂj“^‡™pyÈt@›û‚óÚˆƒ~còV0µ×¢]Ý$††O<¶>7¿5Úa -f*%ÉS*Ý@ívWäo¾6ÁhE·SËðmvðèEÌ5BœG/ë%×l¢ç*ÕÛŒæNF¾S’€€¤z™º΋·ÓJúmë|u§h1™˜±ð evÊ{œ‹ë¶Ê×(ƒ:ÌßJtù7NÛ¿9–+ZCD`ŒƒÐ¦Ð®W„®2õ ºqGM0æ|­n,,ó°.ÓŒçRRfeO´²Cp»9‡3Ì*€ö+¶Ïb˜„Ñ7ƒ¶]-;“Üö¢›’^–UCCœ°Èu±™VÂäbs˜Í1"U«c‚Üu¡rPþÅàK¤Ö8ª/ë"–Ÿ®À¶kCä €®âÍuOK §‘ïYH‹™+`%ÅyGyDQ )×!SRAªJÒ³.V†úMÎ&Ì®ÃÂ7…1š›BJ'›´ˆX6^HMp‚&Æq.ÛÖ™Ä0µæ:.€môÿÐ|84ÉYUŠ'þÂvº;è]È1òE´ÈàÍ¡¯òwÕÉ’Ô‰-(ìäáÀ_+‡ô(ÇÝoXG‘m™G÷7ê®§A°µ-~éD¬4iÇ [$òXQî«k[‡Çy¸Rɦë¦Z e¶7òL?ï›üØËzˆü c޵͆ÅXJz§d{hIð£!WS3AÉп†¾0è¾çÚªnM óž—äÀX>Ež& IP¤¯m>¬“8T)x&Úe½ïº8œÁ¸€fšIá+´ÍÇGDÿP#3Û“g¼ƒ&iÎQíaÕªƒÅg+qû“fíUgB—?2§ÞïŒy»ÕCû‹²Dq[щˠ…ûåøb8£À¯Ö@å¢K6ŽëmÉæÜŸQU*EöH”Y7(ñ ÛÇ΂ðê}z¡õÞWpåe"šÀËŽD]çè»0•Aä¼ƒÈ ¹˜Kî¬ëò ˆ6ñÅ;è…{9&]9›a™—Jx¢Jãh s‚Cû˜=ùÔÿž}h„üžw1AÑ ÓO)•¹>áw ¹–~®qý˜ÏàÀ`#ÆŠ“2„ž?(­+f^÷b«]gôIß[¢‰P¢È5î‰_ñRqà¨cl gˆ*a¼'ËŸc›·¶†ë–ÑŸúu×b¹1àçÖw†¹nʯ-Ê€ÞÿÚâ 튇ÿÍbéÞºo·†?—]‡M%œ1®eÆ>móCuÍcÊÐH$»j…¬#)¿¹Ð¦VJóK˜–Ücë» ã•‰ ¢2qêØYå²6nZ˜¦ðÙÛG÷õ’€€¸Iñyk¡N@Ú¬RvtÙLÿÅP½˜Ü˜É' ̹†Râ¥Ùw•%‰%JZÀzïŒkÔè ·¶œÕñ¿–,ícåŸh©ÃÙᇘȵ<¡WcºT§"¿Þó¹Êz„ë‘—g³ÚîLq× ÝÙJi®ï·äh!sHø0Ãüä¶Ÿè/T¹;Xê“Ví.žÖö÷0Íáš]ÚWÌ9>¬§1‘Ïi’Vê>E&Ø51Í<ò—b„˜x†ña‹ÖÃax½{…ñÄg½Geì~T¦è#œ‚H Îí‹o¢ó.`Îø:åþŠÓú5¾©!›˜+;óõmìò «È^â¤v–·fc)àtÿ)±uçò䑌xž9IÙN‹IðX+SìSHïʽIxû Jz~Ss[cGšu%Í' û‹x\{/ï3F ÒøDvµÑ3u„IžeÌ¥ ȰmÕBßæoÀy9˜<0`‡HFæ ©F§Ä¨N5E·ÎÏ"FÁYp=Ó·ïuÒ/Þ *A —0|E2—‡FB¦ļ×=oEªšl˜$'>ˆªfövʤ¼êžU’K(ÂxBªBnÀÛàµA¢n7’€€À82dŽhX}µzVŸ¹w} Œ>êp£·5¦He‹®q§Õc<âUèìÁ *_—Lä±âFv– þÀîÕYÔ¿ˆœL™NöÐ/æ¶ðÞ“³>ÿ¿ßXøsð2£hx=Ìn%%pímÏeu!›VíÄjWBr ¸¾~C v9Ð|èLí4³òWß´&¬²ÍÉÜêØrØ»+áyIÌVf=]•+Ç\•ó1èé\r»äãÊ4¯Çw-ÂJ넵kÙ£Õh§oT'ÛoiNÛ¼¢:ÃRP ÍË÷ãöá;ø}|{ïÔÌåm]i¸î2ˆqWaæl;ñ[éÚ\¾yîÆ4V† Ý>O¥_v_ ú!̬«‹HuF|”› q›¯¬RßJ3n.wSÆæšR I>‡¡ø)Gfhüw8c©¦s²ŸŸˆÛû8‡¤4wŸêçœD«ƒ”Ãdó““6¸M ñ1°Ä`[¢˜¥uµmój»Ð^Ýפ ‡ø)]aŠÃž-®›Iâ›ââ싱ç)-Œ®¶hÿ®ŒqÊÀ×E„÷·Ò—Äè`ç.²„F޶rútÖû÷Ý<„I IdØ/,IÉ*©ýG×;9ð n‘D¡ ÒHÜìÂ’Ž¢>à™[¿Üè5)†‹òˆ ï¦ãðSxdú¡ËþÑÚ•ÙÄxQ¿‡\å~’Ý`§^vPÌ"c9ÅPí¾í·B_§œ+ŠL˜§\®Ç¿OÒÃ3ÿü2 ܵǦ¢~u¥¼Pe5ÿÃC >ÈRkF²‹Û"z\ £H¾–¡è&hÎ+娵“±[‡¿ìÈAr›àîÊ×Á¹IÉù~V¡2*PŽhÝ•˜Xº Mn¤¼¡»:y)ó^hº¾M̵7µ:³œËϽ*ñ¥{‹h0Ï\–…h$Üù€ûŒê¤G,‰±AMÍ%KßNÓÓ‘;øÏX*ô¢‰ÏœMxÐs Ä¢ù-éE¿‹GŽî¦´·'©$7²ÀQÇXã²ÅŸiå½ñÑ0‹ýxY÷Ôixx5q´ñ¸ŽZªhTô«(T“vâÏeŠiÐËè Û·-'YvwvP€AJ†ätP²Ã_?!<¾äæ’ Ú]%@£G d ¶=Žã쿹 õ_Ébwpñ¥%ˆèUˆ')Öi•·Ÿ’€€Ýik¢y¹5v± Þ’£„"ñ)=UOx$€F9Æ`a'-&ÍyšV&©Â ”M’Ö›=<¿¢‚µñ˜W˜7mÉØ%Õk¥]•à€1pƒ«ßîÕ@“g¹FlÕ˜1>~žŸx [hPÑ®¤sgéƒÖÓ‚òíÆhÖSܹ^Ló»ÂΡ¿ ½o±aóf™ImMHïÃͦ —ùý‹¯U•Ï[){ Ðî³ÒJQžÉõòMΠ“ø/~Z8Fƒ CÊ#;î!¿×}ó5ƒ‚bÆ®SšßDFn‰wËlåÁÞÂbÞ´&¯š¸SÒèöœ*2lÙÕNÍH¡gÀe ð-xèåÚ8Š/¿I:Åöû7ªÓì|S–P_êôVNÃíoËölw¦ð`ÎÕïR¯N“¥º„¿Ó…KñÏñP;ün2£År"ò—Ϥ`d+± MšLŠ9Q?+0‡‰Ð|FĬE+Y Ѷ£í½5¦sÄ]Eí¬¤Û­:ÿ{-ųva礪›ëlBYZ{ûwºõ|:\þn2 ò‚¦äJ 鹑£ˆ¸îÑd˜÷%q‡Å ÀT—¬I×´Ï­æ×88÷¤©©M¥Ë¥%–7ȪRŠ~ºî®“ö¬B#@Ïtµ¾ÝZùH”«©XÀ„ÜÑñ¾—ÔyUŠ­ÝÀÀ1|©ÆŒõ¡->Iöñä´˜qTÓÌÀ’ÃXó±q„KØZ!²ìñWây)Î^ØøÒN…µNžë»ì²y48¬ t0Çâ½ô.×ÜíR¢‡¸Ïû_òw‹'ªà瀺ŒÅ{çž¼ ýmðz £/yZB¶Ø-„ ¿«×½gOXü!úÆ­õÒ'‡ /ƒå‡Ø"pXQŧWi÷Y¦Æ}˨tzØ=þ‰t;惼¼x ¡1½eöÁ®§OßK…§kìB•Ä©¼@ºNjXÄÝ磊˜5v[&ñÅï†w-q˜"¹{@\3s(2:Û2Òøéã3w,*äyª5Ø`ñÒ»n&ÃˬÐÇÁwõ;Žæ*–ØA =²vYþJ.Õ>¬a){^LÇ A[»Ò;¶ ]Q;¹0žÖ÷’@A\¿Îžƒ«8 ¬Œ'OÕZi€C\"ʈ;±5 BrõˆÂ"kØj§yv ¶™c¾«XP)ÊÉòC–ÖŸhVÚ7=å-pÝ)’€€È6F»„ºŽ'?øÇøÊ0ñ>a0Ý ö7Õ1Šj­°ª»r?E5Žìü¦¯gH!ô-6ÄZB…K xpð™(Ui^s•â†i!g|ûØ ÞžÚMvÀ“Úòà$°ÈM¢±(dKL­Ñ®v,«]êÂÈÿû{ìÕqH­/Í2ï©Åó>ò´wé]è®)X<ªèù´Bòä#H‘ÙúÅL‚Îaª‹ãà'—ŸhÄ`¼ºMQQ#¥•uÊ !lD:*à§û¡·6ÅvÙe4yêNNÀx½üØcTf]Ôüˆ¤»»Om°¾Qôyñn«¸è4Ô¹1ƒ×•Ô'<ü9Ó ¶U Pškù¾3dYãuÊó†}£ka0×4l¿’šj¿«EÑIe<ùe\[w,ž—Óp}À±1n,æø@7Šo»®ü¼SåyÊË—Jz®Y("ø‡iEBœ*o•hÃYl‚ô ئ¡Ë É8©ôÎÇvÂe÷ƒ0Ú‹ü6ƒ× ­J—¨WyX™kL‚™Žª¢ÇÆ.ŽªyœÒ2MóÉØUÏÔö¼ÕqÏû)Ò9¼—’¨vo–„øº„ñ?@¾jâ½A9‡Œ=ˆÀ{ ?øÙ¥kGˆr CH¡ÍüjÏ&§®À•J-(—ŽÅ΀dƒš*\ÙQ&ªE§;=)º‚C]ë·ˆ·k>&×çE'úzóÀ¼4-•% ¾î&CÚ—¼þY³Ú¼ZöuÓ°°*Ëâ]d‹Â§ýi¶‘~ Yé7rùŸ”¢¼µ½àå D¹iF0ey^3™%ti‘ò™> ¼–eó3©)AêoIVüä©NªvaÈ—i‹ ¥~BaZü›ƨµ ™Û½FY&ÔH z¼¼ÄZs$šr•L@¿›ãÔHösZ?—°®Î¦çqöøÇ‹k‹c0gB)AàÚšyó‰¼@˜ö••`б!Ò æ«é@²è“‚¥E ZCÙS)?J´ûßX .[Pn]hg—KÒd&©pÚüiÿL¼róº*\ÊU€iÀòº>ï|²«¤RJ2-äj=çàHAeŽã» ?ÕiC€Qœ*H\:Ôã²¾y…(è߆â‹ÙEL_˜_bûPEc= Sí¯‰Nÿ³é*¾ÙNÂz¿ “3¡ò@xq9²’‰¥Ks‰nSŽßf1¶Yb³ _ýš¨¥×;à/á^BáÙ–n¯mKõ Ÿ`wË-¬¸Ä><•µÏ¯uUî#Ý+ÇÿA2¸4_òÖ¯aª}O{ÛÌ3èœ:yÅXR5ŒzOZåÔ¥C4|ÏqFzv ¸(ÆxPµô_„k2‚ˆ*Ñs”ÕZÙJ£¨u¢‚ÝáõÕe%Š)t”…<¦Î\Ȩ~ŽºZ ¹ §më×­ïùµ©ÔÒÙT ú¥ÑeÒ8Ñä\³­2?õ0Ö]æ.PÉç`ðíÕéTpÃd¨Yv½È›iúYŠÞÀt¡tëçõÝ&Ž „ég<\ÝË'úùR-~3®:Bô߇ђ€€¥XÖWìó DßéÔg’Çúy`/Où]ófXíKœèI×£7üW–#̦º+³¤ä¯ì¬K Ù9t©¨QgHa±­þÿݨY*ÔË…aEd€Dƒ²¾žÚK%V·K¸K©Ü¾e œ™ÏòÄq„‘k€aöiδÔXéK5ÐX+Wê2ÀÝ…üA{Б ê6DŸi‘ÞD;³Z@Ðo)ŽQKEØ|2жéñãS„Ò&$Ä™t÷£ ï<‡+0¸bÙþ¬·K—Q­÷v F®Çêß„׋1¸~flî›ê±^‹ø¶?ïâ%Lk§Nž îC Ë«ŸrkˆJ”ÚÎ@NÛçÓ70yS[º£9F‡÷9ïh2Í‚uÆ :š%Qr1å=„žW¿Nd‚ÒW£wÖ[ìË.\¬ëuÜØ¢·ßz¨G·%¶¬»‡Ð•àYôÌÛσ8ºuõ†Ô]mÙr|­x œ½Ù±GÑíÖñ–”ÐV€ã4ÍâÌ݇{\¦—û#©wÚµÕ!oK6δl£WxÅ£ÒLûT:«GÑbÜ%ÔØndž ò…bcÄ¡N@Á5µ§"ÙV¥¦G”‰ŠbqËõ-°SMæ Ñнù"Ë] ³êߤ¨°5¿°›J„ÆsŸßX·°èÐ?ØVn½¯ùê„Ê=ÛSq“b‰'áCfä§…êø£ý54™ê·ß{h¦/ 2ÿD0Ïw›“Ãë·°FŠ r7((þñ1=q°ž5¼EÓB gç]â½ìá\ISzã“Þq£ÔicÄôüás°Â™I•Ù)åz>aV=Ööíé7ˆü‰]'«ZúwøÎÑmùQ]aíÏüññÁ—ªó«Û)e˜Ÿ Cž-€Òívf‹C=1p˜½hL¸l¸{×i½¦LHÏÿûÇ]Þ~Xš¾b ¯åè·6,jä¥È¶h퇗>¨IwZÅ[™—œH)T'5ï`JÉw1ô¢)ªÄv‚ 1¨à"Qº¦ Ûä~ëG€[ßtº6è™P/2ßÁ©eGÌ Óp*ÐÝpùS¼^ñ»¹ù‡Ue(¯X á€Z]& Í̈Š™èF,6l)*¬ƒ5 œ…Ì—á•5¾õ®úŸ˜¤‰ºIyâø·v‹j¼s’€€Ç6øÖbÿÁ~—@ï$'¦{òñ}p‰ëP»þ93.  àyy&ëj3Š˜|¨>%¦ÐŒÑî×á2Õä&{ÔﺶÖ;ð†™ü‰íQ-Œã3Y" îÃÑbTÇd+•œ ÿÆ›}réE÷ÛÙ?ÉòLß%¥ƒÂÕ‡ 3DéÄìãU¶á+?Â5‡¡l†oš˜,!ébÚ„Š£Ø*½hzJÂL^#t‰í²Âàè)Jªo÷ˆØ[’%š¼PÁSª@ÕX€ñª‹°C9hå9«¡Ê¯LZÂÏô ö?òÂþÛ}¦™²ÿ”!í)§çÔÒÓôU—#÷¶]تÌé衺"6¸$©S á-‚XCÔ ÑV3$Ìbé¥dOÎçÃVB‡ûßE2‰ù|~pG«ˆkPšˆèµ­˜ác¶}æQ>sÿÇËïIú Ç¢˜s Á‘Ö"W:1,“lG#ÊÝ*é¤VË}›SUÏpK›ê.®~ÞÚÓv(kÿ-'‘’åý,¦€ÑËR‘zv}ï©8Sàl®æV-w¾ØÃÊzÇ 'KPƒ ¿Š&%ßrVñð0ƒi°NNmf¢ÛþVûõbƒè³ gS! ÿ•ÎÌ¢ú·Çð:íc­Ö[ìô»‰.¤»½UêFÇlf13iôÃÒ§ÄÎ`ˆ¼Ø™¶Ê·Øž&¢ÕŠÌ{ ždGý_´…yUÅ#}³oæ\¹4Ê7]¼ÁB±ÕJ²¿$ÃM;]‡à0#·ª$´Œ$6â ‘¬W ‰^ä&7÷e¨é¾2ܪÝÑçMòg>4à" tD²Wc+›Ò&ü¦&f\ÕZéµgOoÓrêªv! ?åuï­ÊÞãÈxËÕ­'‘Ÿ}ÑüP+¥†&¼LkäV’€€¬IC—~/è¢꯲L(ª >õ¬$VÖ‰ó/³#Œgùq¸ì”~d¿G?-krÚcéai»BÇÈàw VnÁ=|ß‚¦ŽŸ¸ ý+€=ÛK,üØ å92ôõ ½´Ó_z›Ç¬`í(Ššr#V6Ý,(ž%K ĬvÁ6‰*øjNyýŠY­ÀàÔüIý_b)ñS拦­ Àš8°í°èe žîPwˆ @¸5a%;;3àaÒØàµr~\ïboÝ=÷ÍJBÁÒ±JèÈB_0îõ#ƒÆ] Íˉõ~­1£«wã<äU,öIºDuHwB¥   š‰'z †)Óp|v͉p1‹ócªk ±6TYnºëF³õPÌœÊòÜs¹ï!âsŒe‹ÝÔÇ»°ç[ÛÚ–Ûm§¹^–Ç(’uYê¤ÀD¡ƒ\ÌäùÊì|v¬0×®Iæ—5› '5…inEªj’eYÄ HÒ¿Ôê¨[M#s›¥+BšDìÎÑsD½¢D#6‰‡ pµÜÍ7«3¬°jox4ZÅ™{ ±2Ô¡¬/5éÎg&ׂà~ø?6-0ûà …ïŸHO¾@ 4ꚤÓ“²¼=ì·EL“0/|@"×c«7Lwý9¡¹ZSÜg3œ¢ŽT‰KÏí3Iñ 491…¾(s¯ÛÎÓËE/ÐiÄ—ª~47ROð}úšŽ>k$Ochn¬ìàˆ¦Q¨Ðgbµóþæw·%â àpòÈ·‡°\øG;œ£õqŠ™ µ«7·.É2ÇÆ«yëïsv`ÄÇÈžp|`.ŒVŸZUGcú.B_ðÐêç~ËaúÛ"VÒó`sàd”޶ÆlS´q˜øºÓÅ0‡fšðç®*ºF ”{õ«=ûÔï—g`êf3a= 2QÓ+nVÌ}šÕ4¥C­ÅÍÓðyÊv—òP-üF¿ êz¨ˆwNby3Ëc{–\Y’7ÙV{VÒ=ŽÜæ÷©§…lF­”¦“™k±ak¨ªó//s©|s¶l²„¼®Œ¨ÛT’€€§Pâ<ç÷ ħù|͘ƒ«â¶w‘ædYœö;^¤ÑFñûf ÌëghL\'™Ò>Qº7áÑ\ã9Xu’¿°8> /ö’w¼q Î°Î¢ ß¹Y‹hXIÉøj(œ|ýðõjÓv¼UQ¨˜^¾Å„;¹hŠÞ…йΈЩ+ÐN#삽Z%)—qøåwG?I<Š¥…‡ìQxÅïñÐCŸÞXIŽí†Þn'°Aû…þù”Zõu_Œñ=6ğ¦v€^ôÂ9)7† ¼…u‡8<{!¼`ªe‡À#Tm·p€‘Y+Ök:ô¹„ðÏÄÆš]0^p,?r‡µýe)‹V" ÈO¶Ml· Zä–bËÒHÏn + qP~4s†8/LXWÒ¥}ýNâ:HÁIÓ# ¡K¶Ü²Û ‹mÒrV[p¹CI &ZãW˜¦uk´| —:HBþQ…d¶¼i¢æ¿~—ܾ5o‡Æ¶†©é·Åõƒy«ïSûIëʰޙö6¥#hÜñ†ZâÊáuùš[‹d­ë«²¦ º%Ò<@h¯ž“²ÌÞøà†cw8@Æ2[Ï.¬ßØ]÷ÓØÉlÅ_K§¡©ÈÈ+¿á8‡-Î~ŸÝWjé'r™‡±®ÁÝý³½Æ–èžÒ[nà;÷;T ,s}~)v¦×°»¾†C–y²gý{8ãVs7E|b*MÅäHʵ°f›ƒ¢n++p?iºíûR«Ú&3º&Ö­š›þü*$Üú´(¯LÙ2pËb‚¥¯úÏ(ø³~„Cf8cÖi¸7 æïÀòßC¦Ñ#úÌû¾Pû}úÒ 9?l‚Xt_¬ àˆœÞÅJ=¤¶òù绬;…]­PMˆôkGÙ tnÛ¦êZÁ`vù\{]ˆS—f¢±´?/‹ì)¸}²"ŸàT2šlo+Õ້b…(X »q*€pÃ0Šgÿ,ôtv¥¼÷á³ÈZ7ÂãÚÙ ì«¶3­ÄŽ!U»8Ü‘“Û 2›L«{R³PŸcä§ £GM10Ü—zÄ2€@{«ðÅr4¬ñáÒj©á¥¨™5<–4ÓXÐE±œePoõrE¯¢Ï}9Ö Í?mÍ¥²³!"Ë"ïû4«) k½íÓ Œù,Þ¦*ÿPUÛãÿm«óY3Šà®› á— 6Ù8]ŸA§³ÁS [›‡Ð¤g½?Hl%†è¬îäæ ~ñ}« ï«!5#†fLÕÍË:ólrä‰gY ¯¬Ë´Ö3|øïã‚ÿÁ¸#ËT§$Vˆl0¹³óI³÷.Ò „³ÿ3ÙhH™ÛÕ³ <,6nÇo-µN‘l¤Ü‰~5 †LLšþR¾ñç–Ã~9˜'p›gÆÍ¢ò—¾eþ—ºl¯”°’U¶PF„» |PÞ@}ñÐsçWóX8Š è.µ«íÎp×X=Çm¼‚¸î ¤ÞSG[ >íNS!èºT|ÔVÞ³›q›ÀƒÌ$¸ê…UG|¾¡×(Ç‹ï×8îôÝË͆— |ÇËLø•’¥Øp‡ùï掗JüÛîs!m_vBMñJ==ðÈhf˜¢Sæ-ð6:ÇT§•Ç "n׿óÊÂ>LÙ™oøwƉÐÝ£Êð˜Ùœ^vdî ÀÐ0¬Í««ÿHáQGæŠ1‹V]ØçTêà_' & ¶öÔ&òB?W¯˜²ðTÜ|û!ª¤,«—ØézÀá±T„, Þaú±’ï ÎíñsÓ_§ö"@NX†æ‡S…–Õvátz-¦ÓSÇý“ª‡OMž€cШµ˜=’u‚Šëž† øTùz# 8J°™ÖïÆ‹›#L’€€ä€2±C“ªíU¬Âd²Ì@LP«û²}‰sÝ)‘Ú9´°S¿¿ï*³í6ZÉóî¢ZT·’èR5¦ Ûk¶áE$y.G4^² «tÄ=ôUÈVW?M$ƒöRt/Uö<’EGC©GXP ÕÌŸºî>“R%Ò¿WÒ‚ õÈMš9.Õ>²áRŠç«ö®€ÁÒ#–á‚ÁrËV§ÉY3îm’.Mç¶®ºchG%ñ¶ßÖ¸#0qsèV2dþ¯_EXøž8ca‚‹ò&hmâºˆÏ dÇg'­ó¨$Ü’cÕ>urÑŸb`DÈ-|jAIN%¹¶Q›v¦Õü² N°:V†«3«·”Í<鈠@# “m’„­±ÔX^›'\™|°à»|šÎø¼§´•ƒóV°kU*rš6+“ÿ™nBôð5íê˜!ç„å{ȶ­êÌþü7lgñr/Ÿ/ko a/H=I ~ýJººû®N4Ù=µ+GŽkÍú;­…å85 FÓX ²¦ÚlÅ“|C‰Ÿ•Ú´Á$¨X”p±J¾=HFŽæÈ+s@« ë T¦ÅÕ%î¹?/kÜûËz—_‰RUÖ…}ÔHbÚ?} ßâõ;¢ÉFG/Pa`-(4¼Sj“‡tÛ6Jò5:Üt>rI{,9 Þ-úCÐ] SÜ­Ój -ý2 6BóŽŠV_í…CSµ&s/Íb´gÐAHƒoZþ÷ÄjvÃ}wë8©Åˆ¦#{zK -{ÛüÂîwêÔ×]>»^ŠN/ߨí2^‚iZ›õƒñhÞ_2ϳ“,‘)¹ "äƒǃ¹`wŽM zª©3µB#r­é¼´I‹<Ð÷»•ò¼C¶PT, `¨ý¢:›n‹ÑK°­¤é¶]{¨Ú§ì~Fº9ÔY9ÔíØ ½„Çû¨\âõÙr ¯ºÑTDÉËŒÀñaÙÕ|X âÞwõ|Cª÷èÜžÖ.DÓ€ý®ÿÒ»öÄX°ŠQ"{sV´:8ij\bØ™*ý9­¶"7 ‚ï‹Ã@º.Çl’•õGSJ2£Nò™ªm÷º+"鄉;û—0DÑ ¡:Ôû¬ñ7šœéºMOHùME`OLáuÓ‚éGBCµ!µÐ³ð?™8:¿D½¿l6Qàtß›yP¢½‹aå DŠqj~-ÏŒN®"0•öt#mJ°Ò¤7,7°ð²‰ØÛdtÚàoHü’€€ØGÃQö1c^Nƒ¾ùÒQ–ÚBôl8ã•möÍÕŸÕsËüVxtÁÉýß/ì0îꇓP‡¾tcCåÒ+­ž} Å>žs}—À]y£hæ¦ÂB{Âpîƒ’Í ñÐØNþ›Ûë…¬ç¤Ñ?þ“÷Óu=â±Iß\hð \!,¢jõâ øgFÉøeÈÞéo ý•%-™øbÞ?ÀõϦ¥=jž Šloîÿ®Fñ#Jþõ‡ATª2Rßf\ãbRߎé~½¦âšf~Óœ¬jê g”Y äïø3†*—"zÊD€ª„¹þË̼ 2‰JÅÔ%Ð¥T5*"}6íñd$ß»ìñ(H¬„R,ÁlYÆüïÑŒè7fçŠÝn¯ £¢!+ jaØùRß&í÷ ³“7‡‡}‡ò|œë.õš:wÕÞÍT7eBlô•Õíº}Elxé•€¨”»ä+<×µW¾<>ä{2jÙåpï4þM2‘Κ¼¯ÂŽËb>®‹ðã‚wÎÐ\žÚ=êA9ÎÜ-´Í‹-.ŸéÃxm "íôµ"«’ôÐÑc6À¹×{b«KÕóD­ìø"]„@­kþÝ/0G“—rH]>¾ ÷·.£U×\Ьné‚JSõ, €” pèCÎRž¤t;™ï¿¦íðf•×Kœò<û,âÃD¿Jm§3ªÃ%ö2•ϱ(î­tÇ:?ÌÈP@©zÕÕ õ”d[Ò!Gé·ÄŠöèÃw:ü5ÐÕ⇽øMB4)wÏ·Lc')„mËK‰ÐIÏ¢\Sdá4 ð5ЦL ŽÁÈ1Ç>šó±w¹èësæPEÐÕ>4ÈX³¸ïzáÀz•ŒÈ‹wùØÐÀÐm&·H¬›êÁ/w qùQ´1Ñ$QxŠ­§Î•oÌž÷I"l;߉ˣy¬rWxâA¤O«æóåè¨Àùí©8Fâ°Õ_´ô/Bo7Pu¹j(eVC™1Œ…ãâð ç«\¿5ñ1 (ŲæÀ^ÀÈ7…îW&€RÍï€,䊩6¯g?ÛéèF± +i8§#_ëµU\ >‘JioÝ%F`vmã¤üMB¤è7Q–©|‰»Ñ¹G ™PzN@1l¼iÞª«Í4Åæñ+ç+„0ÃPµãü;ƒ±¦˜£Ü/Œ’€€»‚»uöB…œX¨KUe®§ `(j.Þ6ŒóÍkDÞ‹1•X]Æû’ñs©™× °X¢ŸGæL§B´v R6o¡Ô*Æl 2—ãŠu$Š ºl¦äLµøÀç„ÞKƒ2&þî‚_eíŸÂxψõ:#ÁUá£^2Œ¸÷î–ûÉñV¬xßöõ#±AáÌOVÙý0¦ë¿<÷oI)gÔ…†YÓ“[Á-™Àbñ’w^ÙYï$鑞Š:+Ïp8Ø7ŒKDÔLé!Q¹žû“õƒ£­s@V¬‘Ô'ŽÓRÔ°Îø\؈QÖŠê€5¶‡­½0_ P+(~ªÖö…êåGiçlx(vôÓÕ[ìJ ÑÊ…ŽÉM?ö¢cte šöm2e„ }8š™(Ÿ²qÎ0@1,8Ý€Ûîª}XGù)MûÅ ±3»o¶ü¢À1ÆáŠÖcF#ùíýÕpŠÜj¥ûVü­ud¡ó±¾.:1⫆I²~®„ ¨s'çë–Ÿ®Äg¾_EMî¯L"wbNNé6lXì±]ÄÄ"~Œ•UÚ7}ŒW:¸49 Z‚oË’ÝÝ “ºž'ss‡ryòÜC£×ôA,/mLÏŽ4\d÷²å 濚:Õ?ç¶;#/§dWº&©é+H1é:œµÌtJ°‹rŽ“Ÿ²lVqõ¾Ê7$_F º0qš_·’±8§W92¼¼ %MP]ÑÖ轇†ªÀBÃJ‹í¨EèoHP]ÿ9/0Ü.}uœ18QijԚ¡Q¶3NdYú1¨a´ý6ZíuÔŸ]\ÏÔ ª–Ø;8QbVÍÑlOøäòfÎ{ðuàiSTõû2ÅA‡À2 BH&áÑ*¶;i2°þ í›i·ÀC¾<|´dOEJ߇§Üä>Hl–lÚ‡2óÑPJWsuYb5b¹NØÔÇÙÄÛ+ýY±Àðo¦2¿^ç=•[viéúˆþoá¿­Èa^†õöûõ²Îj-AåÝ”5Døèêtx¥.un¬î.¶ž&JƒHÆÚ$ÛX_@|¬6Ab±’€€™áN·£­ÛùA·*AäWÇ{àknuDA鎂¤«ÊNßSÂAö=ü2• öaéuXÓ[dÃù³pý#ëëYí4w÷ø©žÇÓߦMs¿Ò#€B»ü_Åéñ™°£ù'lùF _ë*FîëBºÈ)wGI¦kƒ¤²:¶í#¨!UO+ŸPJ*b_R‡’™Ôú@ŽL©Gµ““m-õóΙŸ–˭Ó=(î…5V㛦ø[ujU"l¬uœX­aBaL]f“NiVÓPa™Þ:éÉëë´Y¬I¤¥šÙêx[ÊÀ·V¨íà ÇdŒÚTa ·.—u&ì 4*w¢×V¹ÀúdD À¸7 ˆ<Â¥Ú#6·òÖV–Uyý,Yáï†àv‡ºñГâä -^Õï1áöáÁ±7öíØ’O% ^“Ó§#Ž ËŠü›Í·e÷ídôÕÆçÖ!9.q”“qL¥ýRÓÒ§üeý°‘.éÓ2¨vZ§Ù'6Ï„¶g«ÐÑz¤Ãñ¦y¿Ü[œYóYkΆ:FŸÕÈ”é G?°1¨ídÿ¿•ä Ý-FDIGŸ ÎkÃŒ}q"GµÁ‰ÀÉ©*€ü’Z>¢aº—-þ3ëÕ,ºŽó ctÔ»PP’æ–B!fËþIGCn-ÊN>ðŠÔn´i íˆGÑ ý”áçk>§tvøÎØ£ ޤF_PU'¸%y‘;¯ª_:_¹ÇÜÌÀ÷\†wŸn…Ý%ù°ø_FðùR‹)e_ÔÑòŠXžåàڤtÍeY¸í–ÄVø÷ø 1n´~Péüû ±+ØŽ:gA8ÏÎ[#N‚Šqé ˆ6 hÿ)i øŠ/´µ£P‹s°ý6Ò‘ß xrç·iˆx.#ƒŽ_=í63ÇÔ8Wp8\ñB Æ’€€Ù8÷䯆K0ƒÝcÚ2ì%…}Ûú 1üÑPê±èÙÿâÁHNL¬÷¤-δ bùÉmeÓq2~Öÿ2„rσƒI×ö@¡UddÙýÔ:jY È”7fŠõ!?²À…,FêE/®B}^îáÒ­O]Œ3¶Ê,­öYæä{¾5#A†3Ý|%ìíA—$àŽyËeYAY+D¢¤ÑzÙS™é­ÑÓ‘Omßÿ.PNш°ø$»›F¤sõ;WBwŠð™îà¡Uѳ_õ¯qÄÌ-RRú .q‚4Öúµó/0œ{Æg®X!è,F§²”DDÐûüÐð^$ Ÿ";G± ×DÄ—î]§fôú£ÅtJÄRh´˜ˆœ¹Ã8'lƒßAôƒ©ÏoøeÂÁœ2i‰Þžrdz9~õ4©œ2ûÝM(tÔ \KÇv\¼òȪiO¬µªèÀ†n¢éÀ÷Ù1ߥ%·M}2Å›¡lßÎ` ñ e$âCPFÖ‚­Ãn‰·&9äžAR¼eT¢Ã1ƒ±Ýeךº—³ì¯aûÏÚ›1Þ2–O¸W‰òpÈuO2.š OŽå~ØÇÝÖBÏôô³Öþ ®’Îë•n@ù='ƒ“QaZ\j‹nRê]ë<¦A3¯NR–?Z…Μ¤A Ì®ŒÔXð€ÚÜeùQŠgñüßÙâOÞKîÕDÙªùýŒ'¨ a™Fj©œ­½,â½<æt夔‘¡¸èSˆÐàêäwy›»\¦§O™5—’«Êy“eM›IÅ>‘ì*•cî?ÿXZ5åo–È‚÷êUíN¥d0 U=ï„`@¥®|ï>]uö…ß ;_;ªI‚Í„‚ú[³°Ÿ±c(Ãóæ{ÕD&WÈñæð++OHéôB©~JщŒížï™ T?_0mYG'BMÓ=h”¶ý‹³ôvþ†Ž¢K RBå¶–Ð<ÅÔ׃î7PN-€÷ÊLŸ¹HÆA¸6É7mƒÞJÒ×õýÓòüù @%·+7H3 rѯÖ]”å Ì,•é4È æi;w¹}‹ç²{‘ìæ.§Åœ©]­Íyë¨á!…*{Ï.o°‹öùuÔvŠjç•Áè\ñ8–|({Pè1(Z] ÜT ‹ØçZ€O_[ƒfS¹±H\,e’»Ùußá’€€â±êM üâ]“Yk[á (ÍOf9O Hj#4õõÜ®‰Dèp ´ˆá MðªpÎ_9‚9iÅ5£þü­#d$IƒiÚâb:+ûWg4ŽPõq›Â¢s«0¸ñƒô-ý·«0rÀ#QxV¹60‰é.èÙûôZŒ¬lë&ŽB•>’4«h” Ò©¸¦Ä–q¾~¾oßvEíì)“’ÄU‘ëlæìô6-Ñ4ÛÁ{êªÖp5ÿà/ÓֱަßOÇ[L“2v*ì,"Në~‘몲ÞÃ<Æì$)5NÄ=ÍΟ¼ ˆ"áìN¤Ù±ïþn´ïh#·gECC :Ó…`+"–ô)l¢­xs9I?Ã1§%¿ShŽ=ÙÚ±¢ƒÕ,·sï3㽈Ó`{}ŠÝ k׿ˆªwö¤J®D…+O›¾v©àë “×GŽí¤¨} ƒOóbàNöhMÁ5*ï]t‰Ñ^ŒH3:]cONnÏqØ(¹­*—Õî4ª(+#ýM¯ ûNi¹“·Ê*¤=;õm´ë¿å€QùBTz©=V.D{š6÷=Ϊ:¬ ™áâ#ž"oUÍ8>~°•Wa*‹wá7Í0ÊVu¾h¾f¡P…£Xµ5‡*Ü|sØ4;þ¢^ÖüÉ*yx…òµôêâóQá½X)NE#Ä·]f©ŸŒÂ;•ü˜@"~’ nC›ÙLÌP Ž/ rP¯7¼»ÚDÆ'°*Xƒd¤iÔrnå´´nbi㦮¼àÀ?,¥N™žw‰{´b¹f(㪳ôá-˜#×PÛFrr±3;ˆÄ½_«í =\b!ÅçÍ‚‚M•ŠŸµ¨6­»é6/*V oj¢Á}àÌt”µ<ç5$ÁÎc•Xºê×NVYƒ·PàÁ‘¿Í~(c\–ŠÁÁç:«x„3K\ì=mk¥h4›ð Í'é"kÛÁ å+Öd6Ðña^sËZÚ”™¹vs5B@kiD”ÏþC{„Õ4AwÙ-Øõزó±†=z+Ù«¯a}»4¬õï/Öc¹„æhÇF/[W§¯ÓOACÖ‡ žpòœ›â³¼/Ô½Ö‘÷–q)¬^ щ!kÖlqr‰üt˜¨Ç#¤„KU*îɱºßôÏŠçÇØe’€€Ìöû NŸöUÍ ¸œi¸A­IbÌ-O8su&Ðï¼ìRlÈß12S3÷ Ï^«Xåh·* ÷\ë­n€!¦óë†^¨’;œ}¢!¦;BŒræxa¨­"¦Ìèã´íˆFÐèn&s‹IÂì+¡:ºuZ5¦ü¢ 4õèe~Ë·Õ ½VÔ… zIY»«Ã9ð”LÅ1ë¨LAðØ$áAÇ‘´¨oTׯòkÊ)ÆŠÑæÛÇâW_¿¼}¡´Ÿ›Á`kòÕ…Lyi­­V3t½)5`Î'Cá…nxî­é–r ù]¾f þ:ò¤2G½]‹C¯KL)žºì+)‚âÝ -xþ[I‚§XÌFä b]4þûõ:¢WÐÇÞ¶9 ø,ïò¶ËåÃÐ|'¬‚ó¹J!õ îL¹‰¾[¶–æå9˜^5M™t²¢ Ïxå¿—«Êå(1J6 éa! Ì»ª'ª¾CIÞ­ M‹~.j—ü{ôipõ]E9bXÊæõ ø¿›Ñ úÆ/n±E™ ‹³}è”lÿÀ}…ë0Ðü¶ÈK¬eˆ“~I²âÄÙ>Ž^¢€ò&ô? TPÒ’-é˜[Ã×ÅÖ:f9í^©ÐÑ¡¦(ŸC°yø…i õÿJËVIxLJx$ªaÙYꕱYKÚɈؿ}˜†oÉü¥9V¼í‡ð˜ö8¦³†ÕWKŠž»ðƒ‹MŒ¥…¨ŸÍÌwßtý¦X:’€€®’ö9¼Ô&€y°”s­ì ñUÆâ–ZÌB p+­ÈÓÀ…ȭߦl}˧‹èøT,RqIÍiy*Jl‚·’®Ä²§E˜kDÊéÇvÙä‚ÑÎÜ ¬ûf+nH,óT£;l÷ÞÔpþB‘p–˜µùßs(Œ§é7­p¸ÂEbVõ)‡a¢@öåW¬•¾MüÉRiP¿ã[-¶aiŸ–sÖåò[׋¡bÛrüå¾ü§Þ*f˜ ]°p•þ϶40ôA§Ð¨Pöç•-ŒeÙè'5ˆLÕê!ÕÖ˜Im¥’éÒèUg_»òÌÅt@¿ˆŒ~MÙ¤”-S¦a²3*Ôut#€_µÎ?CìVâœE#pç#|[[[˜Ca•]µóñæDÉíÃaÕJZ´½b÷¨^{Tœßm4ç&aK›MÈ2¨! =­¦£øŸœk3Ò»ø’ $½sû|éQ\:iÕêÚïÖ+ -üOA®ÚY.dÁps%Ôý¿ëÝFÕCá²`ÀÈF¼RY)8¾pE/E7%–YÚêr°è$ ]vúõ‰‹µ³Ã¢Ðã§4ÊNA/95o7LÓ{áäë–p`‡B«ÿ“ &̽¼¢{¡WqÞ1È­g4GG õ0a”t`ÿ=»5r7•¨Z߇˔ÁÛZ15"ì¯óý¦Ù‰â¼Åy ¦u&[Ÿ71ɉKŽS¤Ú*æÛq¨\)¥Ó~Ê ƒ*sþÁë.‹ Û¼Š ”ßb}Qý øKõ8£ü̧c]"Æxðw»:ø'L:HebâõDïvç$t½X×J$EW@ª™Æ>—¶oc*Õ˽”ð‘Äïš°dWciÊ™ðPrxŒi¦„K€97‘b¹VìªBª´ºÕÁ`ðνUÎGoØeÄž)ØðØB|Ï»›½ÝûÇHO)ô±ËC? Fº*6…­Õ‡¢°ãi5Û~TJÂÙϰ öG"‡¾VŸóØýK/Ia¢“!—¼ä'Ð Ó Ý™¦2€×(úʪˆüô½ŽÖ÷ù¨8ÚÛŸc d?ì/5Et3ß/Æ'´(š t»ñhîï­&,“°1½?€ì¡H‰")jAZºå}]–R§aíž °Û ™[¯Yà›ä¦]ªì|l÷q |’€€ÐéTwáÏNä±ôcânÍÕ^8¼)«‰BîíêÎ ŒøÔƒŸÇ‰(þš©e¤W>ÒZ°tJ-zøAª%EMdV-V s°Óo©9yϘ·1ÜçÂçó3 ·Ž›9×ûîÂÔÁ†¸yã(XÝ ,ßBxNÀѯ 5hÛã$.þi{LÔ²‹*X¥"A§ÚgKS™½<ž1b¯M^þ­‰DcñYs. t™JúdPWäyºfÚC°ÖöÑD#õRadŽåóÛsÍ¡ ¼I0Õ¿‘6ðN!TnÎRþæJsÝ! P‹:6,K•¬ ïcÑ­¡¯¶Ç½½ÜÎðÆwŠWFçèå~†ÕQq{¾•-¡8GMÝÕM±÷×gÀëY©¿Ôd@« ŸnLuM¸¡xÙý-Ö cô°‰8‚¿Wª††£ßâiO¿´A‡Åßîê°°¤k£há–Í`ËþêÚoÕ÷•åøVýi‚sÙ4M›®Ëráyä ånvÈ_ˆ âÓðÍŽÿÓᮩI{½n/uL}+£“s»' ŽgPݬf t‡Št" —A؃eÈÒžþ63jË0|™’m¢&²ªÀRZûR¹ÆÜXCw, YR{L´G®Taw]9…œyñS¸p_T8½ÙÍŸ¼µzÞ0Z¬‰=Ý\悔 ù_š_\dÝË~!íîîÅ‚s’€€¾jUR²m-`FƒîÌò%C d´2¬ŒQijÖf;qŠCȢľݥ™ä">Ô|Hï3¤•Oƒý=•}:? Š`âGk÷hG’\‘DVÞ?" =Í-BØ“êÓFŒÚÈwYœZû°ÎnQåàܦD‚UìèmûÀ‚«ÞáÞEÌ%°Xm™£) Ýîl¦ú¿Ø#áîH€Å”Àb8à>–à+ý½««Ã_K»æîý[nÌú¦Íx=ý@åúÊh+â}UÕ nSyDí €¦ç|«ƒ•ë8ÙHr²Îq+Ü×ÝKŠ»S=0ì´›\;ùÅbyü‚I¦ð(‚í¬Œ!™S«å`ˆèÛÇÉÛRMk2ê75ý’½‘söO1úÆ/‘ŸkHþR úÒ›K}¼§OîrïùE9ÑÕ¶d"i M}¤íG_ίŒ1ÑK%åïFù|Þ¶ÍVS Ö±’óµÝ>¦=Ij<°šgv¢Ìéú9/2åø)ál)Fë¥ Ñ¦§4¸ÿù4Wg ÛN¡¦–±ÜØ'¯ä´ø×H!`Yk=Õ‡ã)‹½À.Vv÷qñŸìn¤,ƃ¿0Ä-j$üwIË/,{ïphœ[4'ÕxØž²v·.£Ào>ÉÀ@÷zz‚çð€;€ó ˜ì´špíq z_Õ8þ5!çÏÖ÷_^oF2XÞ|Ðócãê´« ¸–á]ֿ̯ZT_›_@l’”ˆ¢2Ѻ‹Ž‹ÏÏÍuˆû™Dª©Î¤ƒ/AàwYu)üöô.ï¤u*”͒DZwªV;×'ñ‘ÇÈ¡D«x‡¤ž ®³¤J7 *àòm-Ó+J“pÿQ ðÏWì&ûkh:!å>{• ¹ƒÖO·öGý.®‡Y<|—è&å ¾b‚â³$9‹.núÄ—‘wj/ÇD·V Í[þy«JåYôv;…¸R&X'SÛ›J$:~pV#Œ¢ðo„•…þãåë¢[À< ¥˜z#!Б8Mêàü„z3é_³¿o¡;ÎÛZªx‚!NV[8–vq/u”ÅÑ™û9¸x–ue= {ÌL9ã‹ú-úÎgàtãï±PƒÙ‚×å«j’˜’>ÙC^ÅŽÃd}›«h2‚ã^¯J­ÝMï]¯ÄXE?BÙ¬‡ ­-*£^ °Wµ„¹W¦8Ë jM •[bÁut¢IRê–”åT2äèÛ‘ê©ý"–‹wØ„FâcÿŸ'x¤/úõÝVÛ,ðš”±Ôšbå:ÈÄaö`§‘TÉ´“Â+avQ³R”A!¢èÆqà×gßùðïiÒK€tÇõ×¥k5a]á¨e?Æwå@XmrÅ*Ùl½”M Q_s˜/ºûÞf¯Tt¿?Úk³8A/ý¦3ÞP´™\<×"€ #(Q5¨‚b¤B‚‚E]Š Ya@Ær«EQ’€€¹„ KB=xxg`ûb›Z™‹èiN^Þ©Â1:Ùkš„­fÿÁH0¦ú…"…ž¶‡;¸¶ðx¼Ù &%\£Ý( §”BxNboc&eÕf¦“[v«üŽ63{xqFgbVýAFg2Ç9~žSRo>©:ŒOQÁÏÞ›Z›wxM¦ò©xãÔT¯1U6Œ½J]ÎŒs¸ØVš4 ¡àÉjÒvî´nÿaK!Áœ©aÌ·¿ÈÞÅ^tV«:þ?3š"rƒxR*9: Õ^ÆÌF±•tM‡ÅùS±I<·3L:ÓÖ+Ž& ‡‘—Ä1‰~n;i²ÛmGSóÕyØô\dž¨hJñ%@¯€A;PD˜ÞBø5«6zðØêà ¯8g§ýÔ¿ÿì”èòÿ²XËùn¥[ë€2¤j5ƒb³:–®åÈ´Exóïä“F v¹—™o!sAGèYEéJÆ„¼‘te«.ƒWß°(Ìkïœß0õÉ<êÇ©¿†mYT{·«Çb"léFnþ3²å¥€H¸¦Ó «~}Zòôö›Ý%¢—^l%ûüŒ»ÆO)”K¨hƒ®¿ÜüðG‡M¼¾âž¤?÷6Vg–ãh“ºŠR¼%iå ÎZ€ÓyíY‚a4”=š$—@æϔvšõXÓ}àÙÀqáÿï‚>/½§`ÙsåB’>£nVR*„Å{U’ ËyÓ oã ÈÈ)éÅ(·C2öxÚÞãzŸw™ya~êäÖb8Ô‡wÎ"93W¿â*šðv-±]ŽÙ½F•±º/ý”>DÿŠÆ'yëÈ—Åpqmá\àp‘Næl:I‹ë¼A!m¹ñ '¹¹‘‚ ú«u§÷~2oú³ñà“TŒ…É:©4ói©5º¶’ï0Aã Ü®O†(¦%ÔS<°{“w” Ç `†’€€Åí†u|˜Q‡V¿‚‘–YÃ…¨ {6,˜E3¼uNGºLƒ¥~Gn2k£“ (/@PiÙÝÛ+7¹'=7éå•&xºUæê‹J©õ`}ò=MÓPw¼ÕŒOÀïÇéÌû˜ý£åç}žãif3FªD­ñ¡wÂ7lÂðœA eiè!ϲêI¶+¡ëF¶Ga Hæf#]*£‚Ä$·®oi»óZêQ—³oå"Åi¢A$¼]ýöè(·i@ë/m[Ã^yZâ?Xo€ßH?í¯oE;R7¹ù…k¿‚&H<%Æ06ɺrÇý×2ÃÕ]Õ«ð(KB¢¹Á»¯¸àø•<Í]8Öǽð¸øB.+ÉR½XfÅ¢2Ĩ°Lß Ý¿kàãÌ9P934S“1n@Ï·úžärõñˆù,©g§Ô~A©6€{çO6ÒLv÷özݾ[S±Ê#•ŸQÎé´ñh‘p×ïW=Ø0‘ìÑìáPþ —?ž•¿YôU 'Ì– —:ä[9f¬‹ ´uN}9¾2Ð2G»»°™  ¥œ™À0U²cÏÃÐ× þ6Ž=e€¡ÿzüGõ#¡­ì¥ªIšW!æ°¥Š…K¾>ñ^¯ =4e£¹,‰9ìäÒF—I9?÷ uV‰\l|· XnÐ ÄÑ=ïùðR^69Gfj¼›R÷ }³£mJɤ ßTeûM%w9ùüêv‰NRsôówŒ¶^á ÄÉ‘J¼Oöñr=j_B`†hèLŒÙˆâÁ؇gª{‚ò-ÃIñöi;ô:á×òå[¨K¸ #ýÓ5Z…oß ™e/ágƒýkWÂÔf§Ò×"ÎS×ÿ?Z«ðÑGŽ×ýÂt –´ÀI1HTØ#W5e®/µ:û"ÏœÈkUÖ–Üs…®ñb3©qÇGÿ2˜¶‘ýf6âSDUvsy7;üø&-I'mW›)Èh%L\ì8ñ‹< pŠ›ÉF‚GÅCc¢W¯">`$p”ŸáÆø°¿ÄÒ|š‹©ˆ»ùw©ZAÞ3JÊŠMº½3 þ*- DF˜ˆ,ôµº\¨—P ‹ ?º“Žy< ½¢ôÌÖ;ª¼»iÿ7iEášQ¯‹ú-ŸIÄàópä¹iŽIQüŽ-æMtÞ©’€€§1”Õ© %§©%׬«/ɼˆDÝ^‘%ÛåõóKÂT»@ÄvÁTsçqùLXq,Ž )VpÓôTx© ?Õ§Ët%¸f¥Ñ R¹¿!š`q ËXÝK»u.ëX3¾dtÕuà~™[YlSmŠeÊ sÐÔɸL –~Q„U#Ùð3÷8ýÃ[÷…ƒr/xúLïn7¶¢N`F©m€€í“ƒABÿ“†xÞ1#lýHj$ßdˆØ6òj,ML‡Hð‘ÑËÂ6:‡|èr¶œgšž“´|–B°ê›Æf¾¬ê›¬ u­SË] æfëâ)àœàXð¶~˜ÁÍI7ûÈ]?Ö>ïoª ö‹Ò“ž™>'s#”`´c×Wâ¥+ƒISš '_Ð!»»ÏÈÈû/èsÆqsª5xÀ@÷[´ðÌ:ôàÁÓšñ„ËûþíFÍ Z±0¶ºÜþ‘fÔ…ö'”c“é’Gã¤ò>7"$(pçDá=¢Ó4gwŽˆTÛÌ|Çá•Æ%®6ðèVt v‹Â™„+ÆÎO>£}Ø‘ŸþÛçé,ŽÉÆm“ZŠnÝ7ET)Ò1!4»˜!¡ûô˜K´`‰Š’²Ò›ãß‚ôD†ï‰.ÝîwvwtÒ¤[ Š @‚hQ QÖ¦%±–Ù©×JužT¾v©¡•¹@*L{øãòôõ<€åE—t”©C"y‹/Ü,§ÂVÌÊ*÷F©D.·¤+Mþ9ì‘–a›ëuœ“¹Ì›…êµoFGW|W¹I:âùÅ¡T®"¸=t3?ß9I#‰T+tæBóæq M ÕÇg²q¯Ù‰8ÃRË·Õ°I|°¯è-^RK¥ÏNöó¨‘×W^Uœè*Žæ0ÃH¨8X•ÐBG¸ywÓT°àÌ;{´ªû\+¤ÔîЛÅÝœ7¶³?[Õ¡œ¿H~0î¿~ÉÊñH(üVRF6TåО+U3Ba‹>š´ä¡\!uUî6e/¾Êé-½qÒVÁÐîZú‚’Æ7fêµÇŸêަ¯H9N+À;.ñ%ŒËÕyûvé¹ÃË-ë`ÉE <¹‘Åi»-Þ`…ÐßJËw@[*“¹\÷ìë²3â9brTW‚4gL:ñ¥9HOãš+ ‡æ,/æÉ^"†¢ ’=”šÑKÁWz™{xÎ"3¼|@«læ! s~¥5‚ǰÄ}»î­øäønúÀòÌd_–9ˆä ý3(± n!\%Ïò·¢· ݹfØ®W\ˆ† »ÀÒîÒm Ù„·­>+_%3I/¢n8E6Ø|š(Â*ÏîÃ%Ïð$¥rŒn£Ýgï­B†É\üQÅ–Ü´Î͉× Œ1i ôù2ÝÉæÈaZ7˜w^Œ„Ï>mjÄG/™5°¾"_KÏ€K#ŒŒ[@LPÎD|´y/ZãÂíÔpç´³’€€æÇÑH¤ˆ39`¹‰QçKé^¸ã8l‚Í£­ 18ªßœïL³¤b´ìyÄOB+‡ì€êÔ%Ú† *ÅÉ=ÈW)¾:™ô ×›qâ§ÙÒ¸ˆ³5 ÞׇÛtÇI½^¢n“ 2ã¨D¦ÿºc0áå¡Ú d5t˜PÄÝ·²f":-Ï2p”¥Fö+È$7gï/@Þzyøë‰zêÖ¤h¶,ßµ‘ûAS7lè'ÃÜ.N2E¡¾^àè¿T6fE„ %¾ÕÑ}Œ‰áÜ9ªò‰là :ƒJÉʲ«qW\ïÓd‹=(•c’"A=< ¢u!GÈÐ©Ö «»c“¼ aNy™ÿư>KOPDÃOˆë›u­oŒ¸†ÙHù`gFÒ÷Vó>œ`GÆáxlýVM²Ëx;\@!ù¶•qà!X“Z¦ÿŽ‚©Ö\#Wµ?Ua¸0½‘+…Ùî„ )0°`ÙH{Šï0nf4ĽM_êßèŸþîÙ Îîø±¸ø<&øÿ«\ö‘jEÿfc*òöÒÂ÷é"áÝD? '[¶.¦§ª•ØŠ“èÀUƒæ t’Ø7sœË‘×äùýÂÇ©Û×OZ&n#¬„™Uœ‚_­~HÀæ2uô SÔô£öO‰^v‚¥¸ ŒOG«© öŽ ò•â§/­Ö@ØçÆ+Æ­xý²ÓRÆ_ÓS÷·Ì»tg†ð~Ú"ØÆë¸þ±•=á•Â’–a¤œÝR²®yN®‰Œ%«19‘jæd>e(MΩé:Q,ÉZò¹!»·ÙCê›[¸ ’€¶7 oÞãIJ(ìVÊï´aÀˆæØ;¯ ëDÌúµïÄrµð^€¬Ÿ§Ö”Ïæs"˜Ý’0—Èß6¤ÄF ãæª낲\ÃŽÔÓéôûý6èøVBüIBs ìíèš[ð‚©º•°`¯ÈË(@CÌè. ã'é2¡àN%6o™éÐuö™¬(Kàs–â¹KŸÑƒÁ)! »d¿ÂÜùãhä¬ùúH[@Þ¿Zž’€€½üW’»Úæ&†rbÛYOZVŒT‘»°DèH2ÝJ‡ØFiÎcßô§PÚ÷JƒùéìòÏBƒÏèÆãŸ#d¶‰ÁžB0÷2x³BF 0vl wÓ0ß% ÕøÚF]ÿä·RPÞº ¢­~ÖIóÂN™½ï 6w3߉`ˆê’TÇçæ.WÞÉi8(n5jí÷-$2Ž05‘ÃÄ6îš½‡ù]›ž¹ÙÊ…‘# KVË^pN–/Ǽ›¥š™ ܹv!ûfU´ª*þí:Hc‡@Ö²xP_5€õá=¸‡ Â g.xûD²¿µ£óŠd©²–ŸGŠ:q¼Xmãä,ñnQû.ªþê{(6 >«/¢èf?>L)„ó˜ÌµìÜQ˜ˆfR›Úèœ8ÿN^“¤Ú8a/T2¡JOKø*¶ë‚í¶Ñ$!ñ$í“Y|ŒÝž ïN²‚Ð3ÞZcˆÊšüäFi.‰(rXÕ«ä}ô«X*‹ö›ÿwzÇã‚Bb»@ôÁÛíÀ´Í¿Îh@GhSg cûÎK<"ASô«· øä¦Øk£ är}¿Ê¼š]q“UE*a‰Ÿ›–e–!k´ÓtÉ¢íÇ@†Í§¦þÁ¶ `˜‡L=úà0šH6•…Å™Rj¦s/TÝ x$µnŽÛÄaàû r §õz*s­r¥“Hé–F!~¬Ðìª+Ÿu_JM°nbøÖo17_ÇCZ?J®ãNZæi¬ìîÙj®RÄ‹8÷ƒÐ=÷OßÅpõ·k…Åo°ó‚üˆÂmkLEâÚ¥ÍæÏ1½È6Å·b¶U܃„ü…Üä–„UÍ>{R×Å„ÄQÞω2rÛ¹êÊ\WAÌ(¿Aøeѵ´ùc…½|/sÌ;U%’’¶Ê¡-ëä],p‡õF(â«ZÑ—¸ÏyN†XóÍ: Œ hñ9ûQØ 6*lä$)-Žü·F©àEÒdíE÷­k >ÛÙ<  á¸-FH'Ï”«¥²-?\šÄBÆÌàßé9û>-{“S:cíÛ”ù oþ]<ùÿO©ÆÅ– 5ªLö…Ã"Ž–šÐâ(½¤L>C“÷roZЃ©=¯Á·IM=>¨óC%ŸR’XIf»¶Wø剹[‘yo’€€´óóBò©Êº–¨¯e€”’OŠÒhM¸zä:ATygüzI)Ñ™Oçîìó [»/'¬…åäWJ‹D3T|ït#y`OC¤ä[›8Ûº†¶€x÷ ±¡yò¦¢+Tu†Fõ|SÍñ^Úã@2ðnÜ;«”Sç÷ wÉûÈߘ >(ð'²ø½™±A#¥zìÌS+Þè©ë\%NGLS˜˜/å»w)îZئ-“?}K=Õ‡øÏÁ¸ ë’îG·ÁËxÓhmjžrÄ ˜#À@ÇnRYw3*mª·¨ê÷Lý¿ž·n°ƒŒ ã*³ã"=  ˜óöΪM?MÔµØGîà–o{ˆ ¿Dœc%æhUå”|"È,ôÙ:¿¾»„§”›B³ƒ9WT$'¶tá›YJ&EçE%Œ[ó¹uob™®ðÓéÈQHs‡ ž«šÂŨ‰ŒÞH·õâ³î!ðXqÂ3:ÝyñBCgUÆñ9.5uªQ€l@úçÞ²þÞIN=Úÿ‡í¦´âŸWÚ•}¶µ`ÚZÈ7£j" Ú0›°Âk× Xgè”ÚºÀ=ð-–,â±.Ÿxf0æ¤î´JÚÝQï‡.û=mhçÒü:Üo\‰ ux–¢Käãîz‰…â—kà)/‰SY[šÔäøúðeæ üØ)V”0O¶šœÚ Éÿu8È€ËÌðÕÁ£Wj8ãO®ùÞ +@¤ž¥·üMÙîÉÁ&{”í£çÝ.ƒ㢿ÁƆojÕ>}ùÎ1a‘>ù´ò£*µàxK´suϨþ±g蔫!¯—­’€€ÇgY¸Æ©J<¼ ¸µ|üþ7¹Dô”£ QšþÈMÝÆ¯š±¾@-+SEE¯fÄ¿ÌM šþFL{q&LÙaª_W$¿±åªÆJdš2J[¤u}«3Þ›K\æ¯[/mò 5ûOi*5£Ùê–§˜«qvìêMø¡¿ûìaŒ¼‡|k‹¦vo?À¤Ö„rÓ·,›ÓD>ÑàóÄã䎓˜’>ðf¤¸ˆ¡ 5«L»“ñ\ÜXÒzsBKo ÂßS|:à½PSb2@Q䊵ëÒ”R¯ú£³¾^?ñGp°¹Áíð)0uf †!L®Èc1‹í/Me[ÅÛÎ8¹#±øÒÆØBªba‚.}ŠÇ ‹–&¶§s>%x ‚’GRâŠiÖ»ceBï2ÖóM¸e¥Lcpfò±ˆfÐ#”ð¡{ZèiŽö“Ú§YÃ;?½iã€ÿFIæ¡áQ#®ìO )¸×–½ÍÊÖ¿×ý²–^Æt©„K7d}WÍBÖóz¢‘¢ÙGeÎŒqÒ¯H䛊çTFÒâla髵ý+O wܰZ„¯ 8ÞIxbV÷úRvHm̸@š*’¾U´‡0)ƒÖ99—¬Yª²uUß¶Ûän 2ñÛ¾‡ºÂ®@zG%x2¨E:F½þ¸y‘`Ó‘ú¿[«YŒ(Sb1˜<+B—« ³Kè¹ò÷áÑIÕÿ¥§{ìakn#©kˆÐ‚«D5gâxUŠÊHl“M1è#ÈVíÿ!"2Hbxãû5}Uí8 Ëñm3]±ç1mxí'¼‰(þSA줔_¥ WYÑd<ÐglË”¨ÝàÙÓw)x¾ÀAB.Ð9™X*Uü Ûi>¿¹ô/G?#Þ)@ö/ó<O꿬·Èµr /ûÀG}±¨ÛêOT3Y"‚yí„ ðÊ q—3òÏJ|ŠÌ`y ç?`xŽ®Ýp| V>‘\(o‡ ©#êWÀâd4»á,ñeš98KëW’·wUÅNbgMå0ÚCbŸ^Æ7ôpý)…Dc&ñÏO³n£ªf·ð|ç;îe õþˆ@ ‡}m‚{µ~°ě=t4…vA¨†Jòƒ¯,÷}ÉÑm:=Bé¤[ûœ²µ²F7Ó}xŒ~ÙCdóÅù ’€€áOdÝZèh\T7‡¬J¸ßS_)‰°³Ï4 §ŒR12±W@ŠjìåÕúÙÅ×–€ûȸª}nÒo>Å:ÍóÍ«g}â'¬È:U.÷4VL pþ`QÉ" r'_Fc©š¹öîM”ÿôo!Gʬ.¨’üøó¦žÞB¡'øX‰Ab#¨5ƒ ¨PHÔŠÏAÜ=eGªã€t²ñ¼ýsN.ë?JHVqÒ0=Om\’éWYºÿ´Y‡K¾Ìxk¨<Ì €‘¸6eÅk w%w€ †63 ïVu¯àu];‡ù\©¿Z®é¯¾—˜¼cK˜ðÙ´áUãÙ#Óo¡6}os’¦ê=¹ˆ*“![®…®øÒŒ ÆPPBºßæÉû3Bò4 5ô”áãëw°‚±(§þÔÓ–Þþx¿oVƒ÷¦L&?ÂOÉJ+£ëoD°æ¶órQ²ÌüŘÁÛáv7krÔkbr¬ g˜?}¯³to  \Òrf oó]… ”éþ7°°›ZÇYû³Ëðék”^K`”`y{§®‰/¬“Å¥CÄèK\ ó†ïcÂsMü[þu’„ë(çÝ츀àx»Õ[…ðœ7ÆÑäÔµ¯Š½wp4V\üQq´ñ{púÊ®ŽÔ[Y~pXSò”OïèMt£»-µóØYY kU"šÈŒåùµ—[Û–+¢ÊgþÌIXùoiÓá“ÄÁ£ìÏáÙ‘WÑÖiÒM[2?J0b皣b|„ÊÕwNÑRqª9“sA ø)Ή\‡c l`P‡àƒ B^4_.€5£;IƒßíÆ~Ì!…ª‘‘Йm Û—å)|k–ܼã-œ¦7!›Ç°¡D½ñ|§fV Š Ê¤bös­h{# ì³ZŽŸýÎ÷Gôò:ƒ†gº¯t‚¨?õ;Ûwº3 •W逈,J¤«†™ˆâwe5£¬·6òÝúDm#»}@› qô#†da¼êœ|¨¥ál”èaH±°¨Þ ÈW)r¹ŒÚ°3ÇDaì`§ù7¨—ƬŸ|†Èë]ŠQä‹­&åïp¤ÉÜ2:ü¥ÂDÃ?Òá CÑ>]¥–/´¬¯ÍÉè[ªÞ=•H1^EÉÃviƨ¨±»•XÖLLøÎ§Õ¯‡°„Ûàƒ0½È‚Ü bv‘¤4Ib‰€ZîYîà½cµç¶ÞþXëØî8q-ÊœiÙ˜ùs©O¯¡v¿¦¨‘Âp„„56¹^é¯ëtQŸ%ÓNz 7Gq¤¾Á•cã—ÚªúGœeyv}ˆßŽ’Ù_SÖ¹J§( 9«Äœài+– °îN¬ Ÿ )ê‘ÅDþŠH|îfã½Ä!©tS®\ê_‚um^JHÝšMã©W¹þ'Zä®ô=ŽŠïº[z ¸#JÛÇ’€€½1í—H|5y¶–ÕĉBMJÅ8È œâÙÝ"Ø?²,="¯+Ó»¬uº~±è¯;$«Ì™eì9cüþëR²Á\íÁb% mžÚ²µ²Y ¨3›¦²6¶¶ðѺԠ©³½m³p'òta~¸ßf·Ùh`”ßÇu/ëp— w2û ñ7ù&ú½3< Ð8ÍMÏê &µIÙkõØ+ÄÒƒ#Èó¶â•ŸŠˆÇ(š$ÿÕþÌ{&3ásøÄÞ¿3´JãŒ|QÙùv±æ8²žÜ­g4÷ë/O¬ S zIOz°;ã ëý‰ÊUSmpÛ.¬° Œ*ýxF§Å‘>§S½!ÈêHCýËú=„Ьè3–YÌ#l•$¾ ëyà;Âåsp±ðþg3…“ç“á^ï-ŽØÛ=‡.Ó ŸF8çZ=e'jÂtÓµx­ûÓ-JÉa ÝÒL®w¬˜ÂÀ+`o±LÆ;ðOS3ô§wž úÑäM.S¤Ôú•É£ŒàÂZ·[]¶~i^K2¦%°Á/™}Ë4®1Wß®8ÓÔÊãFHë矶’ÜXZ=l»¾`È‹K"šL!¦unšÓËî¢@Yó«tè“nÁ€ÐÊ5>Kò Eí7m}]Ç•F:¨Eâ6Vjšüq"*ä P–ç´<{رû‘¥‰ 7ö-ÂÚ-¾d­‘ óêmXð?ºÃ ©{_’¾¤¦Ÿ{ØBþh®zPܰÞÄ´@aƒ™‰K…¤F“@®¨š}2¹Æ;ŽW›¥î2Q’u EœjÄþ Hæ2ÝF$?ØÏÛ¨SE2Âbàrr-8Ø"€g4J¹aK¹(æÒ(áFݺÕÄ{œd/ÿ³C±ßæžâyô×ÉU[^opÏq-µÉ«—}[vŒ@…;ïV ¨¤0¹úA¤nøÛE¸ QP9Ÿ¼;µ‘™R%w¬¥vLd|ý ÀÌf€ùsÑi•¹©¢Î~¡÷/OwiÒèJêQ·Ð55Œ ,aü–W÷…¤œèoˆnO Cɉ7oEmš¹ìé›N)&°@£ðØFˆt2ŠúX !Dñf+{ øPv89QØBoG0XTBðÁ wr ¿µ¬R¹@ØYĹ,'Óž`æ»t"[Ï9 ˆeÖÚvF­Õ.ý’®ëå]çç6äVkâ^L¯«ˆž'›{%d«3«ì©wvÚ-ˆI¢²¦üŒ¤…ˆ-ÆH'°—çCŽô@ ƒJ¼ñ Œ¶·ìv/!pkBé$³Í9h-à°bÙbû*”¬9¢æÎrÂÎý;Pnd†Ú š‘v[þÂèWSeU°15޲lù*S’®ŒÑñyÈT_hò©åÐRy­²ö Ï”.·4#³fIQ˜êû˜T# ¶Ô:ßV`ÿ‹"¨Nˆ¾%æŒY¸òª¥Bã¥+ãWl31¿G=3åB¦úF#>èÌ>€H£†¾×ŽdîÒ耋 5mÜ–îfâI!ï’ÉܹÆ_íB»ÚÛìÎR®”‹¢ìk˜1£š6Á3yVý†YÎs#ݦücT¨°\žÁ…¬—á˜7E–?^áOÛòXxþ ¦³#[T}®ÌrÈr.¾ÎmÑk×è€ÎøwÒ“ÑUòÃÒÇ/‚·jˆé(шÌåÊÕ³¿¤¤S˜ŽoJ‡jwŽç·õ׆«÷kÿËSÕÕÜ‹~çöÚ¤<’€€ ¶Ææ '2s·¾ŠX„ÐZE”>ôu?gæ{µ ?<†âçBîÄgQGƒ´'k.Úlg™mî£Oº)÷<õZQiOZ âX¦u—ëjï’ð¬a¤S¤ -…ó¨ ù ûÐ/vÙ†T™þ—©k°äÃû4=æ‡òHò§4”ÞÕÄÑuž¡AþÔÓã6bíê_bW·TMÑMó× Ÿÿ¬ƒ›µYkÝW%´ë“ ý`Ènq({zt§RNj$§quÍ"zF|–ªx/<ŽeϺ,—_Øÿç*&žÓoTBϺ뤎õÐÜTü#Bn¸¶ 52oâÊ >q÷êöuWûF1Eëâ$‰¸e¶^úˆE^’È#ð+§úâ3v¸BµS”cæØ£Oa~§€gáWmõ|?»?,àB^7Ö% [a8™/‹e§ µY1‚\Hœé· k.FÚ×^~÷ð'FºØòrcD1e•dCYb•ML¹XÅM#¸…ÅN%î)Õ^8À>Qpôûÿ³¦ëòZÄÍðp¦„ºS¥$dÅøìȰ‡~çî.–Oß¼ùù0Ò3§»ºìÀ×­õð ­»œ•ÕG†ãï/¡_ cËR|E(†É™.š²§Q/GC¦|ÖHÚHJrzÄr;ôCûÇš+!P’´])ä< ¢¨Ž÷зŽQ¢•˜œßÙ¥Ùäd§GM òê‚˺t,\Xù—ÖÿÀN:Oë4dMšKÂ=*È€|7²Á€ÈµÌãf¢EÅè€îµ9^nfè i™òðžW‡ËìͲœgaÖÀ¿%+JØXà‰øMÇ<Œ‘΋Àb¾ÒÝ®Í{ÄÓF¥fÆùƒªçO†KYÞ~_úâ|AÓ÷zúUW¶I©‚¯;§aÁOlàÿà#Ëm=Rô…~ÛxáßÃÚóv'9`ÿÕ2.¥nùþæðLA),ìΨΛ‘*ÒD,÷U,]KޏçõAW瓊ô$ ÕPg]óGÔ_œä§SéKw ãp|j°‰[ëL œ$…±çmw ap©/¶²ÑìLŠÃ5ÖÐÁ„•Ê[Ç– Ct9Ÿw¥Æ’ßÂÁ?¬ÖD»6 –YZðÛº‚¹‰ ¬ÿ‚ùp¿úMì±`3bÕÕw¯Öœîñ%Cõ{’€€áþ›8m$R4›ÚC§ š3rÙ›qU¨9²#šÙM?ÃwDDªépÔ=¹¸9¢P¯ÞY]Ì8¿´ü8èôBò þzIl̇ÍŽë™êjœ®Å Yéá^³[|v´³;ȉ­ò:±ŠâÕ^ö.„Ôùw¦%ÿ¾ … ¥…Ã¥ºé µ~ÖŽú1ÏûtÎÚIQäò{<ˆ•hþûln+·#5Z ^ìì4ŒyrÆíhó5ò*ŸkÎ5`AÂÄ«NÎ"ó/–ŽÃL‡xý0‰RŒg_’¼¤üöµD?ë öj~gr…cƨœòy ù^èƒ2¨õ’KJ×ÎÏs“1.ýZ3ANüé¸CBàÑ©hK|{´ÀLMŒ\&<·'Í6„y5‚S®O‰?Fðq7Oü/¿l特z¤–ÔžVP».ŽÛ’0tÄŠ÷\éù656>É–0F.ê–Æ7œ ¹$‹eùäç¾\Õ¾9]ëŠP‘3¹¾bó‚ƸÍDÑIs6pˆw6­n]wZî(ð„gžg¿&c§õmUµN€†%‡J>&»–»Ãà£rF¸¿Ž¡qØôgÒüf´DwNæ -bŽÐŸŸçÚÅÁa †X§IS`<0i¥+ª=u‘\%x§­6>=s†ŠˆfÁ÷EÌ%¶õB—Ý,…íŽN+g&7vˆƒøÃf°œ‡Ÿ'PÖHºgó»ë•àˈ3žךF!Ø·„µŽeÿç0(ñ6¼¼QÃñÄ+ÊwL­Gš\ðä:Ö#–k¼oê;u—ÑJZIG–Óf;Í·c’.ÏI §3 bÁú%oéø ¦#z‹Õ' ‚µÂ®4Ùv‚­Á¬àPX0Ä*`¾HϤ¶ ľ܋@Í*GÑeD¦Úš"CéöoDõ„¤<¼¸½Ñ¿ò硱ãÚÃfÇã±@ o„jÙ&Ë0¦JV‘ž¥Ö=ÃÄи̬°v>áSm¥ UJŸ³…¼ù Ÿi ]ü¹ùq )µy”÷#NÃs74ñ`y •–Ê7%È_,s; z×”5ÙJ‹µÑû|ÿ£¥Ge€õE^¦Œ‚ÏŒ¼®ï(fÞ/¼ÏÉ$B¶YÇ~·Z]’ä{Ù€˜*ዎ)eȶJ[*g êQBLË[RþÆg†0M’€€ª.Ð{S©î!‘i úfµ‚fšDB=a‰9=ÉÚüª ‘ôþ¡Õ;§|¦G? ˜^ñX vÆúÙ¸uMbv°OÇ`–ŒIMæÌ,ßX(ÞLÉáЦ—ð4'}DqÉmõàŒ7pÕ0GXþì9•¶-dJÙUã㲸ÔêüŸyààZìÌÐWÌš¾¡³õÒ<6ˆáUõþ¢É"ÀØZzNË:E¡ØMéD„çýwËëÚí8U/|ÍϰÐD±àÙ u€<ÄE²B\ÛæŠŒ{ºƒilá«/×t“l,N“ZÌÄc{÷ïZî…a$CÉà,j²eÀÙa †V¦¡$»M…˜xÕ êÄiÞŸ…œžPŒ"gL²éHñžx]ÜhJ'*«9*ÙâqùÄ Öœé<ÝÊ1jóm@!ô껑Té>xæ[ª´›:¿D<šÅPq×éO®pô1URç¹+xN29Éøòíèȃ1hã&ø]îF¤grœÖ@&dž–ÏäŒË}»™D8ªIšNÃ븥MÀ»–4 ÃÅì’Ãú ~I>âC£ôt, ˜YÈõ›€Q)£´¹ È}‡‹J¦éf ‡‘ËŸ[8½õÿ;C”S‰”2OÇrVÒGŽ$A™dª½Áe©õ%bH&RÚ´uÂTë(ûÝ ì'Wyê¦9ê.¯§=ÊÃxÏârC͸­·®ÀÆ1pJ çl…ûÐàÑ{%)¾‰½À-ó"y¬ºÂ]Ý™ä!F}I·„ÜF+dä“ <–Ò[C{ø^œ; 7óÃu‰ÆCëw‡¾›?’€€˜¨Ó ïµ…,ìFvÆ€Ÿã—‹ž:·b`Êuœ'³î>8û\´W ÓFó5³Û$O“ŠimR—,ußo³nú·õ"ZÊA軈Ê.#nš?ÅÀè~³²V²¨ n ¥:/—6„ÍxYŽ©´ÖZgÉs&)«$hæ)]6÷„çõæ{&²',r.DÝUR{¡°ùV‚éèç†:¨É°›}Çe5= ršææik†$]BÙÂæØJó#!¦­‚K/‡ç¬—.G½ÔwNðà-íÎäY…¢‰JÜ¥|™%lìmê£+‚ñòx¸X^7…Íó{ýº—E㬃¸Öå+¨ÏÎ&«ñÃ=åI—>üà Ùþj“ÙÕi=â>…Ï–’TˆÓWÆüŸ Ôþì73¹œ['Åpö-¼é¨\úÖ Q¿R™¸C 5öJþPõìÓ ©;.†—ǨŒÌ=…›b« jOY¡Òù]2B³ïûä^é'ª°z!hçñ8+û¼z¿´6L¬„ÈIzX‹.Ô½w¢=ŽVõ^é}ùö|ÏxG×ï4Q Ñó4SÈ¡x¿ÌžÒT €›:ÚË ‰½U¹ >¥àø2Ó¿ãŽm> JÞ­jMM}§ôâ+¼>Åá³ÉçLĨ¥l¸k<¿áœ IJ[þOœpuLÈûv´w­&›kUU|€¢cÄüZ¡W[[¯b½ÀΪ@ô—®jf[¥ˆZñd»¾Ál#í/žxFhXbƒÃ‚{Á¦èÖ%a tˆ†ñ“§kbhaÃ9I¢>k£¯Áל¢ªDˆ¼;?¿« 0TÙuÙé©Èà¾Xá¬ôJ1·T¬´äv'=×¾zÙ®½bÕ7@œä,iVÆósu6 “ (ÛH«TUOù¡,dìôÈìöé~HÊ™’*Ôbòõ÷÷˜pCz0óʬît¥f¥â¯ÄD!s?³{YÏ« û¶$œC&󸚹\<üa9SîÜ[ˆ+lWSlàø(WZÄ4¨°¡ rÚHÀøIWµ4;Š0ïìIkŽˆDä °ê©…™'b¾Z?°´õç Æ%<XÅné-Z4-;Šˆ†Á£ÆkQ{IÜ^}×vÝçøžQ!Y<ÖI B’€€ÂM t\ ¥©Û£BbrÙkI âK=`?[Úc#ŒuH„æêЫ DcMahT"¤ØI7áÎ?±ÄH&Kð,³ÖºšícÕ”ÈÉ %Le%þûôLE¾`öJªqÊEÐw˜F,öù¶Ç@ªcãƒMw«Æzµ£ºK§ÚÙ“Vñ„Ì8aѶM´pßÜ^!`Ztr­«°c1–æÄéq#„{geBñ ª!Û=HÓ¦uíhüǧ) ü}¥üªKí‹ÓäQ'æÜßÅ ê‘ç½$Ót齯Shž³a,.̤’xú×ýhß~rcŶÎ? »¿ÂžIŸïSBûïьѼ»اXâvýørk_›"‰¥É¿_¿G¿Îá$jï¶]±ës¸ÞZœÀ-%ƒ·ˆbí“Ò.šµrø?k{béiì‹íigtŸ…ŒØãûÚ¨%’zu o ²ñŸO –RJ¾ð©„ a…ˆ1¢["("R¢Ë-ƒ˜$‘)JPº®)ƒðB—™Yí è@ôLPèLZÏ"pÍ-17`ön%Z §<³=X‘z#üÙâK¤fD÷.„Þ<×ËDêX ï.IÆÎ±¡Ôx¸3†·r¶ˆWK«+„xéÂf82 Ž$úG0p"d:*+³ZÓ¾Z¿òF%¢û‰ç u•ôÄ…Ög/1o>&°q¤6=«73›ç*~õÜ^Å’¶évÚÛå¿aÒ‡;õ†m˜êàÔYg; »ÆÏ%‹éøu}¢>Õ8Äê¦Ûä #yžïܸB£AÉFB„£ôµKZ'G³'QÀàé#0è„ù™¾>{÷Ýßò_êÏÇ‘o×5ý,g¿Îd! ªçᇶ¦ÂA)BbÌ+‡Q¥Ù7\·‚^þ¹ž!3v9Ô’3æÓ>š:«<R8"?¥’ÍÃ\ž¿›ßÏü l ¹PQdunÑ£ÆY&Ò__‡‚AûE­!%T‰ÁT¶ýâ.8¹­ú'yíµb¬Ð·^Z­ûh¡êŸèNnʨGè ¨+ÁK’Ü4 4$î}ý]ú3ÿï#0üp²ôÄÊ]˜9ànË÷É)†«lÄ_ìÏ_’€€¥p?’íÖܲFk·¿]ó…gòêšT3nÆ‹t’Ø"[ãÏm §Øµ#˜>ác¿nŒlÈ bi÷ÿ£È=tÒÂÂØiÚÿÚ•ÆeÅøûÌ ¬;Ÿ?£Ÿ:8÷Ï‚ôB¬á_–vj‰gT[6c†É1«Žå}õ¸ÿDä¨k ²¬lˆš<@¿`Ü}‡^­ U¤]ˆÓ¾ô¨owBâ#ð2}cçÔšBÑ¼ä ¾Øâ(ù>‹ƒ"eZGý÷c9ê2œEºËi†C÷_.«A¨;_‚Å?Ó¨\ȱӌ¹Ü©©Ï¼1ìH@ÿùnr¾oê…†wü[CéØZ²Qº9>Æ[Ùƒ´'SDy5dNãCŽé Ä¯âF—Ê1;…^ͤ‚WæÞ¼§gw[9WY´öZTù G]}Åc°¿Ôä^’ƒ˜,§k&ùÀ-ðë颷ñ$OÙ žløl·0o¥øñøñø‰šÈÊž%—šôõ.]½›M? ggZVJòû@ ÿêÄèM:¤gå9n_÷`Üu¿Ogq ©Ã>‰~*3ÉÜsY0åVžGª³Nú4žŸEæÚ 7{Ûe¢†ŠÝ^–ËÀ”L¡Gáê"©)¶†mý«˜'÷Ùƒ0çû{¶ƒÅÖeÞîo-Íž÷—>è*ú Ù¾S:ú?z4,ÇhšààjÝM0ã aç)hl§&«ùIm+·Ø²R—·Ü—¦±CÇd•Ô 2^=´8K캑X–ú‰ÌnÀúÕµxµ!WtÁÆ>Œ"êÕÞ9cX|säºw¨ã«™eïü2#“(©Æ •[o²ØI8a‡åÂXàgÛJ™ëL”ÊÍžôÍ¿Œ­?ûíö7nPõ …âv5È{pgâ6´Øž8éÝ´"ƒ¥Å ñyùª»¹}“C‹~ a0I†÷˜vó«Í›×uªÌ޶•¦+W¼YK€‡ª€û©VÖieq¶âÙýV“”Š“ºW&Ó♳»oÊþˆ7C? “cå¯k›ýoÙ·¶P^àjf“ž¿‰TÚmÌõfœQ©žªX¯uŒZ%Ü„ôLÞÔíp#‡ç¢ÿJ“ˆ‘^¸Am’^C–ª)¢¢óW¹$ív>\_èH|ƒÂ°sãñÑ)Œõ§\d@[Ã’€€Ô)Ê9³¾¬jåÀzÍÔßž|×™†ðnƾ|„³Y’J¡4ÂÑ«ŽÔ{ý¹,Û¼:d;‹í^\Ÿ0âŒå²ñ&þ/¦Ñ"håµMÁ ç–d× 0d3°|ß®×^-~µÃ¡G›Ðºp¿e«ÌS¤Úbr]Ú¼»ýIƒï¬Gpt‘J·Í3ˆ%¤ý¹&¿ÝzkMÆ&\P!E¼ÔuÇCT”p={h×Jcã~æS&ÇUÇ%m@ìfûå¬ÐÃ&5=h™ÞËÇ#ýð!ý‚H¼+•¹ÆRïÃÄa ´MÐñ²ÀëQk¾$›÷:`‹ •Þ¯ó÷·[§ýßzS¶+ü¡œQõ,…DíÙvÃ/O &.øöjž®ßu÷u:I¹DiŒ5ÈÿÃH¬ýæÁÞínŒé>ÊÚbÈžØýq;ÞùŸ>¦þ&Ÿ(‰Ïòõ¤a1—<}´<¨‘p7áåG‚”ã‚Tfœy͇¢Ì„É*ž5l¾&O)d9ÅÚ”J„èx´HÅ… þå³Â… >ŸÞÿà ~¼KCŸy,RŠ­bÉ?ÜëK®a`¤2K}œHÐ eÑ©žyÅAÌ$ãoqòC|ËïÔ$$ `›zâ™—êæïÝnf&±A@ºê¾ºpsŽA6ƒqÍ.£«Mï¹÷«œ„%üדŸ5y¹‡È*/ÂΧ”ૼŽbÃådZIZÙt"ÖZµÌÚ¹®_SŠZEÏŒiCjßý@oj‰tk9§IJvdG‰_…Â…_'äÇhª97DH´€pè-r£Ôâé‡i®·-5ú^!˹¿SÌ5A„Ô;lInSq» ÛLx'Ž79õ hGŧMËMbŸÖYÏÑý)h¿è=bG6‡^vºy‚ظBùÂ1c}gÌO2U 4ÁÓí| ßäH ÁSKï¥:½…“ˆ}òŒ¸§û‰ÝƘ?ãO{HFŒ;a[]+¤ŒK{ƒ# Š pLöÿ¿q–¶uóòçf@§M˱ÅH{-²eϲÏà‡µˆ;ãá€ðz²ÜKltR¬Ñë}O8l¬9‡ô©›N:HòQK“@­Êr}¥'Üvj t€2M!¹Ó)M¦'ë’€€ÒøŸr‘oಠ‡öpЫ4x1 }ÚšôÇÊ—_ZÎM²#2 dZæÀ/cªAC=kqÆÚw®LmŸÍMõ&úšDT¾žtU]Åî¬ãgš PiËÕ.¶+êºÁ•|=L3ÓSÑb£q;ÄÜ¢Rƒ}SbÆ0fYü††Žå º¡·û?ô`Hêz%‰úu–‡)”¡Sì"³¸Ó¶ü)Ó'™cw˜v1GÀé›\£i»í<—!Ij÷LïUëÐuálNQQiOÊæ«‰8±é š ï9¦Ð³iñp¾XÃ…©ÃÏ0í€*€WXËë·‡W,Žûm÷:H«9êg#<èÌŒ½"Y3"tÕ¡WI°35÷Û Q©Ôc)>„\>–Ÿ_í7lËNWš¹z«ëFXÙÄ,5¶dxW)ŸT,±AªW¤NÂøéŒÀ–ñ.ÅÀm¬äo²¬àÏo¢¸›ËÇÑ_¥=:‡˜Ì+,³¯EËÅÛÓÀÖ¯ «3pôíô£nc Âd¢ Ê¢'¿]ÓN¿,O>ÈÈ͸GúÀU„ {v„”è±l·Ÿ°Ò–‰záʲ͛´¦€`{!—$€4ÒƒU-À[õ¨øHÉ[Ðð)…†Ù®ŠnûÌH“¥£ÜV>«)Ãwâ–Ø¢÷)z_[DÒŒ¡¾QâÊ'‚Qî›§È×j%aäã‰beOdÛGŸ`³c*C•&®<,‘3Riì uBu1´á¤HâÁ©I¾ÂJ®¿YRàÖÓöfPż(X`ROßN§€ ¹z‰Íº¿ò(ù‘Æ LÝÉ’R 'ùç}ú˜_­þ·q—X|,"iâYEö½… §47סwüšr8é'rÛ,…ù£Î€fi9“Ì2 ³|Â^‚V3Â=6Ãßù%åd€4X0ýhz2=éçrä°&R’®Ýé÷æRá–ó3°ß FVì˜'Ÿû÷€:JD)6·Ýç¿KdnøgTßm½­ô Ž™Æ2w.A_ãøoí¢©Éÿ”ͨWÀ¹pNK°Q¼¶[Xic©BjûyðÈd•ä¡8VtíVd†'šüiBC‡Um…­ÄŽoBâFà3Y“貊Yþ…f>¤"d,—Q„ à¤ØW”ªQž3ßÛ¦ ´ÀuÍq* ‘ÙŠ~°á’sÒ‚«<] Œ÷~’€€ÊÓwʹé- _Ò<—;Wué•@VHöò ±tƒ¶©?ûFŽooÖ¢¦ñµ„zÆÝÿûÁ/ŸxÖÕ‹o fÆ×¶îÉa£,Yž~"Äs=Áuá“flÌÄÒGOx>ŠÜ‹d‡%û|ß»P5Ń›J9ÙcIó£(„’¯8þPºY0xônÒÑU:æVíu©þ0 4½íů Ü · ¿å }ŒM-ž ¥‹‡”Ìm"Úm ‹â¬*4r}®%Q°ŽF—ßIá3÷•Ô^wcø¯Ý\åâk5mÕi¹éü[aÂú@°uì §<€ÈÎI¨Fö¿÷ÐwÃÚ³Ó{¼ÁÈB¡ øÀzaIŠE4 +Ps%ôi z„ŠúÔ]šïA¨7%<¾ê#c£[Y•Š“µïtÉ¿>œÃº&²˜ßÁ#¤vµ{ÀR}ß’å€C绉a/}±¸¸‚çÛbm‚@Âëòø ”½Þ'íÈ!1É‚¸E²c,jíìz‹À6÷c÷5g±1~œ\ÁI­ù ¯ùÓÓ«ÃêqŽæBL ‘|×¼ô"?_½siHÃîhÔaŽg;ÈœeÕ[äG²jPDˆk^æ†æ¿3E¹dtº·ì¿´ºo1¬¡Umy†37¶Šžæ`Ñ¢w‘Óךn_Ç Ž&U€N¸B ¶X7^CG‚x·æ½]o,ûq ‘Ô„ ¼!E¿hpi¯ÇöCoÜêQ‡„œhwØÌÔM!yƒFÄØHAªÎô3;yH‚€Õ„Ä„Ç)@è[JÝ}ŽÊxíR ?œ )—*8!ÈäFWwÓ;ýKÐ],~2x¾”èI¸1%Ï$µìz¯CA¸ßYwx`xÐK•¿¶CUUyºèký6&g^¢‹•mñJuÓsd;4ŽÖ~÷Ìê—ÿ³u¯Óÿ§–Õæ¸DÈÄäê¡’ŽywM7ñßí'ð¬À¬uÀka‹Ú÷ vzT摸`*‚¡N+ðô‹s.M9ã´qšàc"§ú¥¡;Âó¼+ðQ8Öæ5J4øïÈÅhôö O%#x!QL„ÓfŠ “ÍK]Ì䇊‡¥]¶ñÆz¨V@/¶Ù’/Vr¥DoÖ#6dTƒ[ì™æÜœvô«TârÖ1“äpá{r3ÒÎP޵þ·ñ§—JAî··žeô'5c}gb§^˜²G'˜½Fâíþ2ņýa„]!±Lxfr«sÒkAË@í5-­H ïîZ¡žd_@)ÇnÏ„_É[kƧ ¢«ëï>Ï'ÙˆcÖàè––Úd©¦ú:à¦ÆÅÍØyg-ãǺÇ¿wuº¯J,Uè…ŒãJê¹?wlEÉA¾w3b!пÐË8„¦ó™äÍlúÌA¼ CD@b¼bÒÇoI„îiWnÖGNxOqüa]ˆÈ{†òó8M9¶’€€¡dËiýiûRÁÄ×Öç$+V²tjÇUO¦bu<kò*±ï¬^?ðNV•{B­ðc”*__~ˆÝw!Ú‰³pÒ©Uš¸;ŽA¹Y6ùcV¦mEe“B°ÃèL¯Ý¯  ‰ø¾ ‘ˆ OJ@zˬò:ÛïšFÙý{¿@†˜E;”„ónï 0 ëõÆlyõœ7‘ìKä ùêe`5¸ŒË44ÜM;; Zÿ‘2¾Üx:¤äî4Ж4\èÁ—¹´ã w÷Ù'‘?”.ðÆf LV4•Å>’1@•3y.˜¿Î™°Š9ç/yM¹˜ cZËzÿ3F!™Í«´PÂrkÈPÏÊzzŽa>n¦ëÆÓ«Ð dÀô·Vq&¹ÛómTúT9‰Ó@+ÈņŽ|¸!cÚ Òé¢\ňG53xDù-y‰Tu›3ZphŽjw»e"´Ð§¥Øyí§±®Û!5#V,–G…¿½a*u{Ì×À¹ â'L§ÏT¿Ÿ–ÐÒ¿Ç‘1÷qÿ=…ŸåÀÊ0›S<’-fà‰F$»L6‡’U»Úo=Ýå~®%0¦˦n:ÚÕRåt/˶Ÿãè/’cYÀå¡Ú¥¶´U€}·4ïñ=×=‡ ,4ÄÃÝÓª kØñÝÖ&ÒÀy—ªýGb7‹J´óQmGDBUeÃæ¦=gÕ@ïÇCSÀõŸÏÄ ÿHHmÉ#|íYÍÏÞ›†pÐXŠZ)[ü–Ô©Â ì°¢0 Y«˜¦ž@´?•LKû”shIBRµ2×–¦Ðÿr%Øoƒ¿1ÚJ†Ïê?YNT…ê_Tfi®ÆU’Oyì4‚ðµÿ³‹G‰ù üXùW¶Vb÷ä€ù’ñ-®;ðIJz9ôêɇlaÀ0ˆâÁÛ JþȪo&NWÒppÝôÚ=<)«Ú¬ @¥jØ1‰Ö‹}êÚPeµÎËîP¶áƒ ÐbÅ4‘F ñüáÇ ËÍ`k+•lÜØ `óÉ+:wïý‡9³Mèê7<óïÿVZÕ!×ó=\6÷´1Ëzræè$ª­pÁÿd{Îð±úLË^ˆoI`5·³Ï/غÏ:ÆøL¥þoä©óŒ»×s6å7ìð¬`o¿ÄW™õ¶x›X, J^/•B] Û¤¿¨Šn"äôE×ÒžCö£ð?9Q°ó±4ƒ}æD2ÙW‚½mCǪ¸Ž¿µFÀº€ Ç_NÛ§Û}èò±ªù#o¬æi9Moœ{ûÁÐ`‡E){DªeŒ§D”T»K(½¢~9æÇehvùø$¥ñ¶mµê)ƳQ…E)زoÿxG–Ø·Yªü$ŧfªjå7ÁÿÌ€½ìˆ’¸r™S%]£a+1 Dì7KRáxÛ[¨ØTm០j÷l‰ÛB\Ì‹è‰]¼ãDÄGsΞI×v廂¿…7‚‰ZùÃ|òŒ;†èr…@GâÊ/ß‚€ ÔNZKÍÕn®:·¥1„ÓÞ‹4=âõîêA£ù}rƼ}›Uìäï’´k¦Òš¥žôbj=žƒnr¤{ýP4³MÛëMMgöµawD˜E |v͂۹j­Ö˜Ê%š‡Ü?ißù”frfSF°à×ܺÖ4Ù5½²ìw’€€²†º~|\!iïmë5±ŒWÕ:OÊC¶«­¼K¤9?á;…ï6௻4<-•l¿ãKØ6h£FeaÍb{8ΧBf•mãJ´7`!p†|¿/ þ'û.Wìz=F@Fa•ÊÓu0lÚËûñ6k# ¨z€å5,¯=<Žhá?È*j¸f9nU¥£c Q· øS`:7«n¦IÞXÊm3ˆåEVÄ×Ô[®óO­1}˜Tüј*œ=6ˆ»=™´d:žU?mEÓÕ‚Qp°Øg™U»Z« ÆLÓìŸpãè­.3¤DüOY€_E¯œà7ÍG-ÚQÜ"4_Ž\=žµÜß8DJŒ±P´¤‚tMyñÿÕWú$¥Ñ¡b Áh+Ã2ÖŽ§œ9'ˆÔCVä¢hC%‘Y¥Ãs¨¸Bßé M¯JÓ/FÃ'{‰æe [¾¯:CÈËj<=lem@:7yÜhwìÿË÷ZØ(bTý:«kE ¹v\Æ«´tš”¯öÒÛBÉø©Ö®@5ñÑ"3ºi%ïx=ÓäÙY†\؃#g9< ›|‡+hŒ…5ŽS®%²” ÐuqxÕ7ºö×½X2^k-x#—fM‹Dr³¡–Ìò¹7µ€s!_K¨X‹å¶¯ Kf+M‘½n€tÓ¬`ŒáçŽ ;íÑã†K§VdhJä1Dþ±yë¾\@F ù°_·±ÝîX.îÈ<"®íx‚¹Dã5Šô¯nH Ê€ ¸¨€¾tüaHN) \49‡¨²uº¡‘›;M©LA»ÈH‚ÛB•µ!]äñºËÕ‡Tˆú®Ì»Â2’t¸ÂÅ~xÎ×ÈÞPvètŠTfþ¨uö$‘ÉÑ*ˆûÔ"†qË©Ý 'ÀÿKpë–Æ-B:{C†Ø>€qèÂØ/Mû˜‹Ûz^rÞrµÒ*3 y¡£ÅA>i¥T¸9K§‘ +ÝCCÿ¦*KQñsù=lŒš•·ý¥ÁSt÷P)Ÿ!ªO9Õ9$ìÏÚ»‡$Í(n2ºùæ³"Œ Öô'H<«åjr]iíå€ßÙ‹õH4_8Æ¡œ¡§íu L<r)L… ñ«£µ Erb{-yªÞ#—I™ØxOé;ɰó²ããºò{¡ bìæ!¥®zá39ÀGóWoF/fŠ[/’€€º˜p$,ß¨Ó U+ø=8KÛ@ï1ñ|/¦xcÊõÈö‹"í½-¯ÒžQÁ_¨¢H²ÿ-ûFÑ4\+¥7꣔¶  n¸É½ù×Hоì”3¥9"(šlçý–Júkùúe<ˆqŒž§„ß^¬ò¥~´OZI`»èƒ# Ù³_„x@Ï!å’ Ê¸ŸU´œ[±Ä_]/`iIŒŠNBwj”¼a¼xº!ëÕòêô®:gw²Û=† õ¨A¥5‹-¥H·™% 4)XL—z bCÃS -©F)…¾6 ’)axÁï œ©E8¦˜à.¡Ü³tÒìv—R B¶k¼•¡èT ;Ÿ¡ÙNþ9#o÷TƒK„vZMy§tÇ`¹ým ìX¨§'r´}Vå6¾êtÒ_qaiAzí<õñÐRú¾Pwœ5 ÿ}ˆSt¸i79̵°Íê2õAéº Úü+Þ”/¿{y(W:Xµ:Ï}ã"\øp¸L³½«5®A3uÆ ý«Å IhM}ÆCÚ¶ mjn¨UPÔ•/Ê#2pš#âPQ{SóG XÞu,ÄU…š(W¸_À,Ñ•]•M* ìâaÚÛ#õ<3øVN›ÿ!ç]g\Rªe_W‡8›ûõ ÉÃh]À%~qWu üfc´mï–ãì[ÈØ“o3âA›Œ²iÒ¹àjVöõ¾Í[;!ƒ`8ˆœðqQÝÑ YX»gæ•9ÐÁŽ„-O±IJ\báª-[üqÀ=Œ¤Ð‡¾ý›?˜!`×ÀZjì0ìVzÔt¤ù]Cµ(

    T÷±ÊA1'ܯS<Û$« jš"ß7—UeÀ¼nW¡•Ÿ°6ã#%s7ÌÖ`íÇíà§h0ù‘¾Ö{ãk%jÌ ëP€z÷úc{¥¯&1Šð¡pc8Z¦ùÐÍž B Q¾›¾ñ7F%ü´Œý)Vxš±YyuM’€€¦/^½ÎÅ6½;OOZ±-x%›.FŽ)¬ª/";Þ%{©ØþZŠQ£œ±­¥< )~h$HéÎ×üî)`,ïÒÁé€H’y!AYŠŠPÄ™¢¹q§Çb ‰ÀÏKÔ<ð7T“òñVndTöfá˜ë‹ý0#þT7„I6h½ŠÐ…ÿto÷Îg¢"p¿Å8Ú¢Á’5·©¥uߺÍÈ(C|­.…..–ØY¦Â™ çuR¾ï¯ýÐ0;rÄ-œÌ 9'ª0o/EYãAˆr£ ¯$8c\Ú_J´+·ÏnæÑþÔübf.IÜ¿£Õæ±W!^³ØÒ¾.<ÁIev#m9ØLÁ1‚Ç‡Š¨(©"Ђ¸\³ŒÀÔ›¤hˆœz½âµïëÜýdà 'AˆÔÿDÒóœ W7 ÏÌPY·Nퟴ´'v;¬6º+òüÇ£~ïÛú—9JòJZfÝٮƦÕÉprºEÞ_¨ú‘Dd×íj±™ì][a’KÝSG$ßõgÀx ­_gÃà™X°þ"ËH5äOð)Jx}˵:Ýio©ŽÛDᬨë©Dù:Iïa’ay’n—¨…ì)ù¼ÊùåcŠì!U'?÷°=/j6À@TÀ’ààÝT¯ëÕS²O0ö$ߊtŠÔ ‚ö•AÓMZÑšËTÓ_©«v/ÜŸàÅpYýÀ¡:Ú £@¼‹ÀP_M™`ÑÏK/NäÖÑC(Ú¨ ŸõÏ{óFè\‹ñ¦ú‰\LͲrÛÞJC\ªê. ¸V>T2WÀýaÊ ½JZ§§ºexeÆ„>{™ ò#mû_ ]˜ï{k•ÉVɨd@lóµÛg0] n&òXѦNÑ•^üPÆŒÞR”¬@3­ØÿÕÍAƒ`†ZUÆb¼:@`è?l~_FÙx“Õ‘=’rÛ­LÖtö”ó3Ìuè!ü­nÎŽœ¼úˆœ£)Cô*¤Pè\†î„ ¤Pöô"sçÀµËPahcj¢y¦hór÷6Zh}ζ{Ÿu4êÌG¡®Ê½¥êïF”š‘è‰C!áNAj›#nwÀ#k/ɲˆ;·Vyõ› s%oà '~XuÕ|Ý×lvtw~­Í"½ù“4ÑëÚ-蕹}ìažËß1­5æÇcv7Á¹±ƒ’€€¸uïoâIHéÊÏ÷ìtxüæ¦rd@÷ú¤½n$ŸJW¾¾¼Â´§m.ËÂP`c*Œ­jþŠlôò•%BvÉS»NoÕ6çV‰¥Šv,Œ€”bj9qѰa‘Ë•š¦]jÙYD–_Ø1žmƒN¨(’ño¦ª{ Fù¼'íˆA|ªò¾ŽR¨†Ân’tÛ  -ò€‘ ýÛ³§7G³Ö•™ÇnŒŒ_žéÇKKÜb‡ê’Z8wÙ™FE± Ó½þXð×”Dp:Ë¡½œã–-„[stFb :X+h:h,$‡MÕÃG‹Oˆ«"Ë­aªÝ$ ÿWæ§p¹Ú¡Åÿ÷ïÁË¥rIÅ`; º³ÑY%.þ¤F1´ø¾,5Øëêý2gmÊçOšÜ5¤ë½{j4ÆC•E&ÔD\P2ãˆL¡>RFö5/‹ÙNóY·•ÿ¾Z/ªÉl7Íæi/¯ÈßÔl·‡ê°—Ò 1Ÿ„ÿM4Æ nŽùKÊ˼4i¹ñmÆæhlT©¥¿my¿LgTs1Uj48šr C˜¨ˆåŸ'–X“<á¼p &ÂQ;ø¹—ÓÌÞV@V‹ç f#EÅh'åqbs¼èl OÂÊL’ƒéZ¹vWȯƒ¶=iü»ÅîðÏ;Ÿ™Ô&•ÖÅÇoH¿ç -4:^|y—'ïtv¾+×2ØÄÐûúÚn`:} KH1q ›Ôo 0¨¨Û!vd¾Hö~^L¸øô˜ƒ8uøk>¡ž’´lt’s:>Ý®ÁïT?Ñ9Biû%î@ñÑÊÕéwÑcyTó.<ÉW¼ñÄVc&:wa­ûºFÇ×ýzeZó'üøR~Ú=ÍäËU›(0Ždëô¶kI>g3ûácÝCSOd¡R Go?8QWËOÝI¡†G'Þ|µ¬‰œn.öÐý¢×h‰wT,‰7Cº—3W"ƒ½¤ø¤’€€×§t»[Kʦá<Ü¥+á!.̲1®!{ŠF@OJÎŽRÖö ª;yJVúxƒe·š’­„DÌ·×ú¥\"n7ŠMΤ¦-¥~ Þ™šªâ­ï„êJ­dGm[){|@]!Ô2%n|í”jÇŒ‚¡âU¹c!¬LÌ܆㔸~BjœËFôDµ%ìS÷îýÒò[ùŒÂ]Ç'¤ .{ÓÞÇ.‡µä (])?•e}Ñ"Lo4cåš5püæ$¤Ú5¥¸'\><€¿Aù…ýÊKôˆ|Z]Âú£òÉôÇîU¼¤Â¥ŒF3,¦,ûÓh¤Û ¦çGß@9õøó½_LÇ’¦PÐÆ(5®Ònnš”bù@èÇùÃ4sx£Xþ>•IR‚v6¡ 9Ø>Gœ’dv{Y)V®~­©l­ÀqƘA­"9ŸÅ‹¦Ø·)޹Zª€±U,èÄ5"e0äo3µKø^9Í“j<­ÃDt<ŸÅÝÈ¥I?ÕX Fïh?±n‚•ã ΰäÚ«B_á~÷ôÝ´B×cóåMdò¢¹ŒeƒŸèÆØ7ZNT§×߯´)±ød¡……©g½ÓßȪ8 m;ý "vqnl܇?ÛòYÌq‘ZÚ@ök;µ˜#?Žÿ,ä÷¿“O‡BYÆÅ’!\÷Û ÌGä= ÿžå¬Ëš2À³ZåzkóØÂ•ë{Ïà¡QEòÎÐÜËòz\Úci“£*¥Uäž¾¡Çl‰Ò0×·ègÁ¡ñ-r8%f l\Ð}¶ £å<ñýߘÿ'QéV¾3Y,Ý `­’€€ÁZóJ“*º7Ú—bßxòÌ´,±CÝ“?ìÉIƒŒ¼ÕPÄŸ Pª%”?·"ÃÜùÓÒ«NŸ0õ¨|€‹'úJ{¼îU¨õÅB€ ‘Yà×c´«ŽmVż˕‹æ™©?8ˆºnØ!zBj‰‚Ô,yµ2Ê·l#¤Ž—'ˆšû/ƒl'=ü:³Ö7Ô-©á,6è')£–ü‹¹·4PÝpɲ‘Ñçô!wq‹—àwÐ÷„û‰á ”/zTÇ­0ÈzŽ7 ÞÒáˆäáiì Œù:ÏÀš‰•3¬lÜ^E‚pµmb8§œA"f÷ïhߥ€¯¸ 0&[!°óÖ×¶g>šÀ|6ö ¬¤S¾"AÃàZ×zåý2Pà!Åü—’ön–ytT\š£Ñ#‡\¨ê)ZÉ­Ú+3ì6“k'wwÃјŠò~ÑÎUÒQõà—ž:²xk0%‹ãO•Í,yÇâm`Ám.U dã{…Cq’x¥Ç…-€Z?<ïîT¬0ŒÎîôF>)LÄ®ߤèh¶ìéò‚x1­ `%8䀫¯q!8jX˜É?û †÷4Ët‚¡ŒÕ”oÝ2k´§ÚÍFÃ$G€w§Û˜Ïß͸ðÚøÞ7Ê?ñ8 XÕ)m÷Ëêú ‰¨ÄþWÙšK2¦hA܃íéäþW¤2;6¡qY5§©N‡¿½ Á3^©Á=B%¢š=¼$!r~¾t¦HÕöå’EBCÃFio›MÓ¤½âÆTæÝ­ë2•MjtÛ@(ÓóÕ0+KúÄy1DÇžºáóîykû jÊV?@,¯šÅ×6žE™F6õlGØ'™qXèßx³Ic²á3Bõ72£Jõ¥\0&”þê¶;½m´]Œ#„šüÀV aµ:ÁƒÞ¨¶‘QÁÕ Ó6„ûÊ40{s3Ú²Bµøqiéc3OÇa‹¼Á¡Ÿ#•Å^ª¬¯¹Ö•äûÍ`šÔ*·Ô&Ã²æ ¹| 8ÖVÚNz<й8ãÅSêþ[&ï0­<€°¡*ÖùìI{ö5æ Ûh ›ë—#RÊ"_.œí¤k'EÃÉO$Ê­M¥¸UM¨BßëllxÞhS¨­£º°v×q¯§Îù1ù¾”¬e£¢7n5s!§”º~ÏŒ™[HqšÁ[ܘË«éA7!/’€€¨]® ãpïf+[çÓÍ;Ö\NuuJƒúç¢Ï©¨PR}.q=ûà/"Ðå‚1û" À=ÙÉ sâ¯Îâ–t„ f¥V_$XŒXF f€§gø[ðêñlÀé[•8ؤ_ ¹F›þšŸàµ`PEXL?+™e+Œ[é WÎ õ h°×¿¶mb½YìESÀ8ß-è…œqºî‰oêÝ©"ƒtpÿŠu |TÙL«?a¥`Œ'ô·=C±lÁaEQÄ.oøóu›³ ¼˜Í!ýg+àÆr¥d®Ñ]n»sȇ°¶¢OC, tÕÅùÉúœIÉm{ï°±ØÃ¹$›éÁѯYˆÃ«§“Ïh8~ÕýöGðùCÔ¾¼n íGéNQmtלh[ϤÍ0¡ç‚þó0&Q‹zçÞ¸C„T£!)¤è‚¡àÜ>MçñÓq™|/R–ƒ]0‹¿Š‡Ôê@s¯Šç±Ï1©¿ÒŽÂqwzšÂÙ“Àä3¸©ïó†¢ëQÅÅM®”${S²^þi€ô`LK'l°1¬ž² Å,ÈO½n¯‰œž Ñ\ŒUöUå †1BZ‡‰¨Òi¬QC¸R@Ø&ðÚXíTÄÄ­Wí'È ÁÏ3³´5Å"žÈ”:ÜŸ(æ^(v´Ç¥°š“( ±hIù•”[šäû$­&H<}èõ@ûUJ"±¯1]ƨ÷ˆàPß)Óë*S¶R¬‚þä½â×¹ØæÇqVyz’n£ÄS?ÿf¼À¸iÌfx哱ÂÿqôŽùÐZ_+_:Gà§«ú36ú@17‡Ã]Y ¨º¿œÄaiº®WeÜ3›‚h æ€Vï[fÝf7›'ÚGšìM` ó×çMgMÃkt=.½ ~qpP 1<…äFª¥U²ƒvÐ"ÀÓð`r¶Þ{1S±Aðÿ»Y@°¸"J“n;Þ,ÚïáßÔ¿`ÏÃÃwO·ìA£âM+x[‹¬©ÅkêþÕ—„Hïá ÒÏlU4ðn™ë®½Ôy(â Áˆ­Š‹#¹;Ê0Žèg.žÛ|SÙ%ʶª[Üy¯$˜-0 ɃÀÁ?‹=­ÒÌéñ‡¥ó#˜$º›xÃ~Cs˜Õ}L«ÃbÏ7DØÔ¦µ (Æëíg8øšH¯maÛø g4@(ö,‹3¼™$ëÉa¹¤àu(õ+Ïr˜¤ˆ&XVçÑ3ëN’wÿêe\á/<‘¦È€E?7]n8÷ÿ Û17sÜ2KÕ§SÞ0”v^Úþ›ÖqâÙÔÓ¿u{›Þätx Àì¤ "|ÿì0ý`a7Ø.c}n]®¢ï‘ Fót4UmczCZ› ­‚&O%ÅÖɸ%‚höH²°´ä[x¤¡ ¦·°df"¸IˆµÎDÁöçb®yïŸ*„¨4õª+ñ×Éãˆå³SæÚñGKH!H²ƒ¹UNµòý†<þEGµ°”0Rá×ÃQ:ßO= ’DÛrþ mñä 2¦yü¤å(˜rjf¸Bò‰ûóc3ãß?~ÔÉ5øg7Ä48Öl¾ÔÐÎBjÄÑñ °\C-IAo¹¯äÀR¢8Q‰f›8†ƒf¸Œä%'£èößùB>Õñ`p”s.Æw ö³ Ï=# ,ÊtÓHA˜T*R>‹åÁ© uI3ÏÜ9N`Ðÿ#˜•õ .bŒk8›}'ìç%ù¡P—ydË ó•ìX `®ß]¼¾N¿a?t!wüónWáy¯Éœh?—ï;ÐÄêwµ´XÒí[üo‹¹÷gP/WFühV0ÝŽž±pˆ0_En…ì’R|&LëŦ¶ìâ8÷´*ÕKe¬»|X¡€É8%ØW-w*ü%¶èˆBPÒaBE@æÔ q"ÓËÎÎÒ£Kܘ‚´Ÿf™ñXCw¾á¼½P€Œ!/¯õ!Ê'Þ÷.‚Ú¼SÈ€á +´„O<þå¸_)‘ ´#Qå&ê_³TòÄ·ŽbÊ¿eäù€Tó«:ÈÑgA-x(“ ó¨Þ{ÙDìñðM $ Aê94\øVÉXã3mÃï’€€®;Ž3»ôlÛ0.{=è]>ã¤IX!‚LC*”,ࢾa[W¥YàÙãºóùóNcJ4¯þ”–– ê…b @¯Ÿ G6CÎ =RÖe{Ò tõ†òê4ã}Sun·S©óú +fNÑ"5¥®=MþÖ$ÛÆÜ©_:;ã ýC¹êNsµIÃE ÅBéÆEÓ‚ÒÍGk†1}èá!°‰ó¯<eA•êBI~¾Ùóë¼’¾¯>Øø6¢éʈ}Iç¼ÃóS´Ïž<”}ªÍ L™Suß±,¬yl£þë=PÖªIˆUFŠy’êN5ÀÕ4õ™ë÷¤ôZ»oø±rºV–iȼëä%åv–$‚_Žó$šúkŽ<]Päò¯êÞ2Æ®ÓûPýòƒÃWSr|çŧ¾›»ég)5߯ñ>³áÅ„9÷¯V ”~Í(nž'æVǹƒXGü„Ï©Íb.D𼱦‚"(¬ ¦¦Ì9L½\u;4ë¦á}ûA¼b[öꓸÿx~2áê™É‹*™ÈÊÈî$‚Ádö'ÙVS/*ª§vùkÏålÝ¿PÐeÝè¤wî:ÕÃ"W[Ž|úèÔìÝ%ºüFw£#-æt®2¥µd·Û3o:¦ÔýáÄV; °“*ÀX…íê¢@e™S¡ÍÙ„µW×4¯êtó²‰[â—i 'óCÕ‘v7熜™‡ßY|'ãsXž2ìGýzN`| ò,¶u‚ècoR€ñ ç™È›Þ®Úô·Nˆëz»¼V©Œ2Q-üìÖî²Í¡O“si nSŽäX”ºØnÎ'~þl÷}Ìç=+)ýkd¼Ñë±h8¸6¾J®,ͨ7J{iâîa<ËHF›ê£t™Ü„pHÎe¾˜ô.€>d·Hº€óÞL\{ø¤8š|6ÝUÐ˾íN¹­„x…‹ýaç¼…Z–¦UŒ}@ë³Ð‰‰•ó’^”0ÒšÉC€v’€€ÕÎzýÍlŒô4€ÿT&å"54=貫/C^ˆ.‘p b._7ºdÖ6`ÔðpÓüà“¨÷Ô,ÏtÅôáªÛŸ8e³åq–,j•&ŠËzÛÛ÷ÈžߤLÛ‚§\Þ0¾züšÕ÷º1ËhkAŒS•Ú¾ìhôÒÆ@Û…{úçUrª‘CØÑ"ÑçPÂÇH½³l—•¨„ÍãÛLµÇ¼X;i@•ÅÝ)Gâíý¯|L&hüÇhËÙóå€îZZÙ’Hº™½i0Ò[º½¥'N&Áåã­âxiV¬qŒì[mF÷¸¨×iúºc C«0ÛÎ$lëœË)²Ñ5µN/5%|94m ¤ß<˜¨!.î}Æb‹çc»F¼Ñ¨º»þ%í÷ˆ±¡•¹‹¸Mƒ{—¾¤à€sÅêôðm6_À¼Pš6•U»ýê9cGno]—äQ¹qÿå®@]-âÁIŠ›Ñc–1oXŠû×™âòÕ‰¯ ͧŜ¹• &,ÜE™Í€,(‚ëÑâF\ܘ2zL‚.¸JŨæÀΫ²X”à¶éðg£=ÝC”úq'e4Žœž$”î;¢ÃL ¨']z¦.Œ/ʬòA_˶ꩨfÕzŽÓt—×r¾2‹–—´[õæè)óÚÉ’r€Ü‘ª¾·¢C¬•œ³Eù3’²7÷‡M²“ʸº-u©§Ÿm£N£BÈß~a‘©‘€”G‚e)uÚ)Òý°®g £HÉMÉ*s²¼ÁŽ…ùÈ´Ýý(9§Ù?4É÷Ó[Çç \Ñ îI0ðÚ<–â³jhm'*ŒÝàt’l´ƒ•M̼{`X'h)"®Äy 4rw8ˆÕüAŽ\e[JTQ~ý¾èJQS*¸ÀInÌÍ8gÅÔ䣱ªê¹À¯éVÓÆQµQ!P?*Toöãyhn<µk±=ÀÍL9)˜ÐQ•ýÕ¸E*ºrlÖ’±é õ¶4žÝr7ïMÐ؀Ÿ’ÀäPJ0‘5³]ûŸàtâD€ž¿‹|å` †ÆÐ dc4©ÿý~á÷\¬U'H”Fé+{ç÷Œø»„@‹ŠX#’€€Þ—©¡¹ÍmòèÕ¥õQ¦SÔ±Ç"|GF®,E˜ü,5óM¬ã–ìYí±ÙDŒ’ @Ír‰ðâ&åhßÿû²ûEWœk‡Pc1’¯îuño¦B¶Ÿ¦r¢ß ÒáBc;/9#Ö Ýì¢Ãs—Pe¤G…H…÷Sút¶+W¤>‚ Éø‘1 ‚ß¶˜Ñ“y¦¤OÜçÓÍ¡¯ÞžáºÌÞÃ{+k䎳‘íQ“ýþ’kñ¸GVJÔ1Œƒ.Ú‡}À…eá³—!áøEqÝ…ÆĉÁì,£ªÁ´».Ä‹!ÔgøäŒÿӦ»—¼a¬N®wG‘ßçSUÈ áT¡®w’n“’,_ÌqY?¢„óï¼°³­¹%ìo^Åõʹ¦Ë'vKY 8†Sä_¡¿}4ê×£h÷àã›M ¨e³ðŸÆ)Î`H±|Á¨¤ì2.ÿ[é51ÕR˜à=u¸xØTJâîSp„ îG{ìu(«÷ê™­à÷¾uó£’ÿ<ûZ¡ûÑœŽŠ„ì@á,_5L·àëtYº±^,-%W •Ë u›’‰úp—Ö·*,÷].T7]7L\:0U:¸ZÀjåïÜÂCb àÊÔȯ•É‹tu4ºˆLCìÔ`Mv—R6 ”=ô'Ö×âMùI5°~\ü®z“{—øüò\¸e¥x:¥Óœ2®ŸV¦nÈFQ¸ Ÿ>ÂŒ±\Áþy'Ïów]ÕT¤£µwÙ%IprØ»ï%îSGñk5ÀˆÄ_÷WŒÚ…|‘~É`­•Ä;h^·SÖ:ÅãC­ GütÖ¶ß}ŸKkÇ4Ì=‘ã%¹_瓇áG€s„˜,š1sq³|Š ·"Ð%¢û«Î@¢V:AÚ_Jž!X˜:²ê^ºw`JâªFìR†ƒA]A )Ù¤l3´0¹ÃÒJ_:Òü`ÌÐHúÜ–žô~F&ÚNž•9G¯™@¸–eÿ±4P–܈”ýx-y‹ÉlWv^mÑSÀΊ°Ðûöš¡‘qMÊœüÀÖ­ð»æ{â¿!qBÖ þǼs\¯nÉUd3‹·Þ-žõ,ÐÙªŸj¿@ýp9~|÷Š ¦ú¡½± ŽO˜*·BÖ¾‡›%V)í1õo¿ðr;œ–ìšÔ?Ž\1¾ßcb¼Öºùç’€€©e<³Ÿ†Ž¸Dñѯ¹êÍPÞÇBT ·7jBe^§ëS“ñµ¤Ðh¼qú¦V,h·—Én÷}å7/$äçܳu”_ƒz}iuáPFB€7§:/QT0`ã®®º:¬“¡¶©D ÊåÏúvçÄo†wª»#¢h =2üKyÁNt×5/é—ïŠZÜn{º¼IëâÔex Ð J4Êë›4[j– ê5æë~n§þ8¨OL0¦4ª*mp9yóŽ/#Õ_í[‹ô¸@Ý ÈC‡Í5©œÃÏ Ëj |7¶s±_¦¥bRòëT-Z ¥â`/p>ÒȲgq ÞáÁžƒ~ûÆý"®íY€Ùm†AY/¦å¶µXÚÊŽÝÃö<÷"A,õmézR.εΠ-‰vè%%â¡õëN¤š‘/5ó®y½Ÿ èBfaàùÜסƒª8 g%^”·Ž8ÐÔèjºk) aífŽúòq­*›N}“RË^Ú?ë#Oi’‹Ÿ£{ăôªâ@ "—¡6àÈÑ\x˜+!V‡Èãâgë÷ÁO£è5 ט©•qˆç¬¡ýÇgÔÉ· Wà²ag‹G˜ÇÉgk0!?{ff˜!³ë°÷'„ÖþïGn-†¦¸ÃƒÛvA±ö¢#ñØ`µ@Ë•e/ïᕪw•Ï:ÃÎ@sê¼ZRïÍ­¦é}ž¨õ°Aka„3¨2è­R•ܼObÌõK¯éUÅ+aù]êÔDl2G‹î`zL5Xmª±œN<:¯k§Òq0Tì¾ß&¬-ìˆÒ/{ìù㟷ÚpfÒÚ;¼¥PI–¶4Àee{„(Fþ/{m»ÇRÊ=†úÙ™‡ÒvÔ÷ZªO2hÙÈ'’ú«…ü¤›\R¶Y4H÷êÑå¬üt^ìPƒS3-»‘6úÞ¶KøûƒPÛ¦¶*v|c è8¾¥ÆTФzÒŒÁû+nš { áçúmÐrX[÷“(¹ü…*Ðý'üãÄ.å3ÇË–’€€£PˆKõ 2×F”t¦A„oRS³â5‹}z³Îj_Ùb6]Û™ç=0퓳ßøá"âýô,ÂQu¢[U­ðùž ï}½9¨9yâŽIØ›M¬¥…–j 3»[›wú¬¡®Efá„éMëÔÿ50V PÆ›¥ð]Kǘ¦¿ujÀnlDìkÕã$¾;ïÛÈø …5þÚ ’V=Û/÷ùŸ–/E6öìà9QŸùx#´35:Á_Zÿð&oÏ ˆï†k&yŒ]bÄc}’]Ý?„ªÊêËÉédž‚ÃÅ÷¯ØHè…[€ýÜ .`5LG Í‹‰ÅÝ‚ÈæôÊ@±²ÄÊ'ݰ’»ÓR™Í§Ôà0-=P3h4ª°\Ùf`n~ï•J<¶šgÌýßW¡F"­õºÒ.eÂ%4\w´ûb„ÝrµÁ4ãûÚ®fì ™Üß²ê­}|W#¬€(ë%Ì»z<~ýTa·}x¹BüDÃ!O‚̺(µ¯3Hµ$ëõ—Å3 D*H¶Òß c3ª„™y÷|Œ ÖÙÕ_òºþ OµžYïˆäÜëÊV1ÈÒè¼îæ17ßuõǹY¬zL <æHÿ…<»ËØÔ뎃ò,‹âó±úÖ?ç6kÑmx»W8­^F'ùÕ0]L¹Œ—m*X˜z]Þq«˜uáØ`=RDõº$œ(-@—·ÝÄh‚ú~t ×T¢ÿ:rü°`Ò("d«ë¬ o ðËs|†¹~ év4÷ ¦Ó™­Ø|ÞŸÙ§ð×û˜ÿ^¢H½°u¢Üpcÿ4hÓ¨kµÃqÛ}Ä9 ¶ò¹<…ƬÁB9& ­0aÖÄÄò<ëЋ÷ ñ]|>ºpÑwË¿á4',AÝXJ”]$]³ÿÙ“4<ÎŒŽ|ƒ‘íØ¸øÞd‘ôÀÔdˆ{©Eâê;›Ã GÄ­úQòxht‰ê—RþWYØ•GmP›¾.ØPE³÷–‹À³_‹â°|JcÕöèí5„éÛ Ï&°»9íss26‹æ,'êYþ¾  •ò¼/øYû½5‡Åjò™ü¨ßÅ”;|òßÉfx:´‚jÎ"ɸH•Ï¿ªHÖ¾±öŽ6( ®ê´¦Ò~¿­`G¿Ø¤ïÊ"ttßãØ’€€±Æ#|\ÏüБ’{q¤¨­îñ¦vüJ%1¯oо}ãàN í‚ÜÔ=Ðûp¦MHÒ¼%ˆäŽíõ´½‘[â{u}ȵdòÕŒ<¸”œM%~j¬Bæ𩕠뙪ûyPúžq*Æÿ¹XøÂ—ÄEÿ@¹Š¨5Ä¿²Îþöô©Ô¾›ÉG$+Ü"hîÆ_ØG'<¨ó>£½Ùãd}É­ø›có¹yîÁ]QÙE‚—_Ÿ7>Ä(N7ÂÕŒŸã–¹þÍÖå´"‚RZ÷˜Ç¿U `¸¡“صÍ8Éî÷»!p”“„ÛÍòÆ!,iϤJöÏÒ³éË(˜¦gÒ+ÂVzl–áí«uyä]&¬TÑ&Ò+ÔsyÙfT7u\=9©sxܹ¤µ°><Äeÿ´ÙÏ…NÅNâvÞRê’%vÒ‚P'jQsggŸi­Œ/`'ØmÒAíà&+¢g@D× Ð–§Â¬cw à-¸è¶–ãò«ë%ÛCóuÚ­J²î¼8%íìrÕO£·ÞŒÿÆœ6L#Šƒ x[íwXÖÛù˜¤Ù;ß©´È$o ØðØÉO_ÆÔ`"‹÷˜g®!#Ó|jU%›ú0ƒÚš_÷”½µÞÌÐ,-©p»(uÏöÕ o³]§!Bè¯çË' ÓÉŒ6N ·fâ’7Àÿ«ƒX·&Î÷;G¥î†¬œÝ%ð•Ò¤·2Ö†ŸBêDl=ˆäŠ8"¨ŸEeñ!’­<î0Ë›Ž×#ÝyÞ;Û-ÿÿæ{<®q-b Ë‘È]2¹‘c;Òøñ „ûªA¯3ÓäsRœð#vº7ühF±TâWG¡3Át5üãL«£ä¦–Õ铃8^ µ²‘Øê.´r âsļBºLˆ‘ß o›Œ'‘“ï Â(œ}™Û¾Ïãsм°fM¥Òs4›8°=_ —Àb©°±êíDv I™-!3¾¡|lþÙ’€€¼Žñ‚¸|T{i/äWdwª •CX92ÒA»R|´^'¬L)+@ÿK~b³dîô±Çq3l¬3ofn § o‹Àø„DÖfK¾eyYk_ÀÏh„Uú.×·ã8âþë?žô7#‡ÞúŠ~±ê´;µWân$6S¿i2Ûø)‚ÝtNsš²< öí ýoð2«Î(òç1G[ ÑéÏçõ²dÅøÒp>t”’ÝÊ•Ì|¦r#w1¡öãÈÃäV…£­mNFÑÿ³Jªªµ$Á=÷$A„)âO½­¥í¼—]á§—d“G -0]êLÌLÓj(u¾ ìÌîTDX{Þ˜ó"¡C'|^ꔎ,öÆŠ&Ý˾ ‹ŒŽLGžìQOù`§Sê+o·¿å¨’ö¤À ú~ &J#F2[¬ –›Â0úÏû_žh0ñ¾cY”*îѵb”Å7¿á×DùýÖ}x>cz0Ž„ì5} Úo'¸ BÔUg}ƒáþ_`V¢vËdëࢆ[b£éFv0JºA:gR>õµ‹Ìª‡ØÜ2ß#Ë[•åß6,S݆¦§¾ †˜íÝÖff³J ïÞïæç&[EÌ)ÊÍMûÄÿ<‘´©^°¢7kÕZŠÈ\—Ý×j I\íµ0â•Ó¯<§5»Ááo¨jAfTDƒÙ6¤0˜/ãª>Á¿›?Ù|>áçà/iÕš•!eI+, G„oÁú$óÚŠ•Uå¹kÞ¹¿ÍO#Óg8§‰8|2Ôý¡¶?ãyÈ™š-x? nufõ½ŒcñUÆë'e´“ûAœ?qƒÁÚ1AzÎÚWÖÛ§'§ç€å}y›™“H õÜJ§i¡ÚÒGž§þó½{˜¿¸”]D`Ð^- €òèG<ÿP}qæ¡Ô·T´2ιñ ì¡IG¡Îù‰-#÷gŠ[lƒµd¨f«èéø·î) ê”§ ü¥Á¡N’|ùðL;«¶¦‡?øyÈö—TFe¹ûkÇg`ÑpÀq“#sÒq™&øñˆÿx·'£‰–ä`À‰yPí±ÇÅsóN±ócÓ¼~ãá`0ç›~¢£Ž¡,½9+®·¸Èø‰Ë¸ã×Ì£FÆô®9‹ç4­rHcðóŽg>âW³“Î)ÓÑ“ÿ6ËqȈ„Ô’€€©H*„©[6G¨­Ú"iÍ;¢Îèþ«vŸrièòÝù†5îÈÿ™F>ćFHÜ›7lsª¨3¬'ý»`˜«°ëeFùl´À—ˆâ˜ŒnœŸÉ>7¦¶Ùªjâ`$š·ŠªôÌžüX­¥>è¹RÅiñ¢A·ç "Dq¿˜÷©ñ_鑸ÍòŒó/µ/IÕA3r”ë(ð¨:  Òb«`v–…mIÅÁ‚Leª¶‚XpÖÆ_»»”s ÐP×Ô¦¯µRÂÀˆ¬10yÃ!‡†9»¢µ€@ñüzß‚9ùthEð&*0©»ÌGgpÅd3öPZœy'¦mVKd‰ëÞÏF(S€í>{qå·É¸Ûå”Ð%H©©¦¥Ëd3÷™ç#Ö#ôUÙn2ò&ÈpŸÈ#,=ûäÿ1– Ó²ê£ë$ãfçÜ2ÏÎKÄ9òî:ÅÌ­É.åžhJP9Ê?„Ïþ!RÐYïè1ûÒ•X“‹qxýÅ®fCý3…ôv™ÞèT‚€˜’ .¼„ï.‚Ý‘~švÂI›ô“‡ñÝ^âŽFÏ—ˆŒ[1¬M¥üZ‘7!¦`cæó«öh} ´õRgÃqôͤÏF²l¤Rg•UMFåUE²|T¿µ/ Ãç?uãpm¬ýÅp›BRX¤ùa†[ð;”%çö?/ŸÁ‘JèÒúFuÑa>6«å<„‡g@ºþ[ž ÁÃÃOi¼¾dIWˆ|_ç«ãGÒÁtqåê|{ŒáÓNâM—p0M8"F9×·“sÊú°à‘'úEð’ÓGýý›×¤kúC¤7ª^ñšîj(2¾ VŠ’§†¸E¤HÖ°€Ü(iôkµ³£Q‚w°ê¼ºøн°½6EÑ m1·tážBN´›ŒÇcn1D–¹hÃèIU5¥ÐÂü亾‡8s–Xøüç¹ÒZÊårÙ •©R„¶0 ÎÁ¶¹;ýßÛ_Ä—  g÷˜†':;„Mbtª š›š0º ÑÄ/¢˜óó «L~Ò‡0Æd½0Ìp(¥…`¶?PÒçÞT1 UÁ’€€Ð€jÜA ïz4¬ 4`Û|ºjDC>­VÚ’p]ŽŒ?Š(€¹]n§Ût-|¿‚)ŠFUÒ Zо³|íyæ‚{¸ˆ`´ÀqX"6MœÌÂVý :úMigALÏáV:OÉÉhZްÆÛ”'gtù[ÈL¾æŒæ¦NÞàù.J½ˆ¯ªœç:ÛÎÝÄ(kŽ˜Ñ9îú ƒ_žò*äsÀÇJšÂ0óAÀ¡4å×ç7µ±ÄÑwa§+²k½1o ÈÏØQã116Ö.[“ÔôIL[RÄë‚^´ùvd]û÷á°NÕeƒ¤Pβ&5òq¼Þ”M´ÿ˜ÚÅÓm—1h§¸­Fã¬PQ|»ùòÎf»ÌBûÌ1“1Jå=Ò¸‹v8°üÞ¥“ÿSØÔ9vø<2¥¯ÚŸ—ïLùžÌ Ä8]üj.¿RÙ¡ú]kå\ªÖôl;º®z$Píç’-Ÿ*ÆlfÓ§6UÑí—¸6Z¼ éD«_•,¹Ó¤9ÀW˜XÈ-×6ÅçJ R±ÆÚÏÜŠÜxÝ\.„“ð)A[× µ¼5©¹iïÂ2i{ Óª–A /™°ŠÑM¾éJ˜íkx´¨/ï­RÍyfÞÙËJhøÆ%™Ì‘Oõß­ó!¨Êž,é˜?7ËŠ7›¶ñ·ŒZÔEo˜u ½‹Ì-Œ™éåo:”—’€€µ¶²û«·WkU-ˆAˆYAV¦&»&½$Dxí+DV( ¡­nXÝþ*‚ÞÊ4Œä÷{ #šh—bŠ«olÔž*ÎíË8¿©‚´®‹2DÚ>]ÓÜqp+¡zë¨v\ªrw t ¨0‡7ª©ÀQÆ}pàó¶{˜"ßý†WwßÚY>ÑÐRë›xî’ BOŒ5CÁ†ÃÐN¤Å×ëÁùÚÿ´dpíÆ[ 7¬XjÙ.¶¼ó@V¥… Mòë˜[®­”pоm7¶óAïÍôVøç!¥.މ+5d8£nÌàeÆÉÿnÙqø¦sEµÛÒGÊtZÀ°~ DFewR¨Ø¤E‡‡áó$`²ÃyM¦r^%×Ë׌Ϥw ¾™D‹Zée­®¶qd5yjZ_ÕÙ®ÆAh…lzÌóMb Œco<ÕK¼pü•oë.§åz}P¢­œõ?ôgCsL÷ì7R¹óÀì@¼YÑËٯϢËÄ¨Í ì½Öb²5ìݹq‡.Õ_wÆØwÒºæß±lÕÅV‘ˆƒ¡P1°5ß–¾Ø¯1QÆ2'Óž ÉžU¼ñû¼ â7;, 9ÖµS»çèQVÊøó›x»ór#˜‹üSGâäÚœL–eeŸ´åy2S¡ækï42¿=¤«ò3±çNˆÖM¦û‚(u’±n|Òõ!ç2}™p,lú²YxŠU¢ Ìùý«OµÒ•¢2ñ~Ç=ÌÏ@¿øÐj™%áª/-ðR€kb.W÷E’@g.ÛY„ØÕ’äÜÌlÑ;a¦#Ó‹Æ1cf‚y?5ÉÂ¥5Eñ¨RäÄnˆR°qö#Ó2ã- ¬‚0Ê Ej=zeÑ«´NtUnoƒ2þ¸¡úì×bAµ;qΔÇVÏCҡɹɀš;m®­“ó\og´‹‘GÒ¶ÞtÄßbÒüB³ñh{Cñ½0$Þäcè×qX†¬“æjÆø)Ïœ.t¤ÑÎAD¦Ý0˜­{³#NÛ ªÁ´‚RÉv'-jÇ ƒ@Ç œv§C¡‹ýx¯Ú?ä*É /LÅö2\õkØ‚Ç3Qê‚ Å")F±îÇlDdᢸ?w¥ã펧ƒT%¸ÄYˆR·EAet"2†ó_\ûDD’€€æTùÒÉ5 Cò“óü €±Á Ô¦@5%ýà=Þ¹Êçî·†·mejî×ð€ö^ÅíöIβҦ(íÏOxQÄi1:Þ³!|À¡zì¹£g™Q”h¿#ÍIþíW’¡!jTPµêÝKÉΰ Ãe.å+ÊK¶½°õ™ÜOýˆÐÞæ²ú÷R;uO(WÁ×쟟$^$@h$cÄÛ«‚òlœA·® w€JÛV1üÿI[ë,Äͦ >˜  Í­€–°Ð öð¨ŽW|{cŸQR1¹ ~·&“uy•"й%"xº›´£¤‹QŒ¯h@ßòG0ÙgÊŽàŽ£{j4!‚;ìªmŸ*É{]’¸Ùnnxv¡ÀxRp¥^íV‚é‚loüwdƒŸÑÇ…‰khIÁ%[Î_gÏ"ñ„ÄmŸÊæc\¹1Îp¹×†ß´9éŠÒî‘ ‘ꃼÄðob•"äwZny>1c†¥×$N,çÝeîWÖ@ÛÓä•'t Z{׃P™Ñ~åŒl €Ò¬u Rà”€Àü| ",ÞÑ¥¤jÁUïi×XIm$’‚û„¦•ïUìH¾ao®+^Â3CÀ„[Î¥F|z.¡Ûݾ„q–½0Fñ¢ š‡Ã|VJBo¬̱Àjqüý,C¼A½žÍük6 úÕõ“É„²ºìA•1aCiï7÷ŒÐI¹fÚG®šxPU{Ž+m?ùÀÿL‚.‰;ÿ†V³Þ Á¬ôõßã?P¢ÀÔÍó±õˆUhªíñp† ªe#~@™žVƒFV{LL\1þ'ÃZêMj\ì8rßçê/ÿ…â\…ZYñsf?ë×nmW••è¶ÿs¡…‹Þ\DÁ,GÑùH1ÙGI$Ê—=V´¹Ž³^eZßZšŸß~N“œŠÝï·òý,ïl‡Cà4% ‚ql‘z™+{pÑû‚D‡iÍ}@ŽéÕCë!ï”hd59ÊòS´8Èp wØ”ƒOn°]­M ØÍÅâÀ4<˜N)’Hà§—h»ŸT&yt%{»,ð‰([·(;æ!j…<$fíl‚u ‰¨h[£– /-”ó¿L“º d±Œ|è¾àücÈ®àçhüz ႈÓ \Îî]ªZà`¬JŒØ…A’6áln¸.v)oZÑ´_ ÇE0’€€¿«ŽG}pdúçúø–ALÊŽEvÀŸ&óq=ž‘½Ôu2¦¬þB˜zT ¡Ù$võŸ/ͤMßÏøidüˆ ¡ŒGÒ—SžÈì TôQëÁfç¢ÓÛ~¶’/-öåv€aÚqýña¨y@OÔ˜Ðø`Ù:g'ÕFàâå /¹d¾ŽìR  ÐCT F²kqº_3!€-R·yôy:jfaKŠK òò¨î3ÚÑŠPÌЮèAŸ¿ý°M{ ÷vyéÈm ÿn¼å29Y³¡“îyÒµ×Xë#ÃwÅ\{þ)ùôcnB§~¯†Iÿ""rRFâÍg¶q3ÚÊåü­D656Ûæó]ùܶ¼_i¯Ú ÜbáxZ¯^IÎàu¦ŠDïsŸT}­ª¡½¯@’lÓãv×Ƕj³ûϰ7€×“Av€Aág…Ѭ˖»òK' ŠFd`Ï1E¸G>Äy £UÈ)p;_ðÑ]o<ðÆŸO ÷Ú:¦.¿‘”“—^N³†Î†Û䊴²³1±÷ÿ¸$#:øˆD»Õ9 ]Thg«ùaU4º wÉ’¾÷þÿµŠ î¿«÷«ôôÛ矎g„¦ @~‘Ài›e¹ÔgúV2²—It*`£r2| §ñ!»Ý\5à ñ\ç`îƒìÉ¿Ò7Ã÷ âåÙö¥›Ùh‰þZú½<¶ÈNìlö1­6ç+WÁ-Vãykz7ˆßÁ t­Šêmô캾Ä4¹…UJ¦ðþr´×ÌßÔŠêÉ¥Zc<pc˰Qb€S÷t Ðèìgæ.ú˨Õθ_¡TòA‡Ðx–)øÂÇ{ÔU5×Ï]T˜3DžßÜ(H<•r—øØíED>Ï F’êˆ&Ó¦Ë )æs"ù.“"Ÿ=Àp0¯“··5[UΦVô y*¾Ä£M…§¦&zhF<»–ÊÝó[/ð°˜ðö åÅtŒÑ¦+‡6;]³ç‡j¼7Ÿ-Ú{Úc šXa³òÞg—ØßúËíˆwWSuž@Ã3vMÚ_Ôþ^Û¤'¾æ’€€Æ4‰›‹€EZ¡wœäA‹vt-e(çŸxäù"Ô{}k’åMƒ|[:Ym|ôôX-y‰‘ÙV.÷&UÈɶcó‚]n4»±<°wJf_õ6Q:@8èá­d¯ ]cScªçfy/éS~Š×4I03£nO–\£‡É´aÅN$Û»­… J»A'†ûo÷PÌþ”.n~f=VЗ‹‹XÙõ¨eû†ÐÙSq®œ½á[f•Å )eâ[Þ1ß ?òÔvhÏ^#è,¤ôºQܧçÇ.?ë‰< 8ÑrÝÕ`Ò’“'“µz`°EÿÒ®©¶HŽ1(‘b6î(@ÂUÃ#Ñ7™(?1~Í[UøWü…²Ùu–ÍÀÁÙ9ï&Wy|]yŒš'`y°ŒÔìµ4§JUϱØ[mþÊ.ÝptpËŽÍ4ë>†¥•‡1±ËýOg ÞöyÔ5>O—R^¹s|Áõ °ß½ýgŽ& ¨ë3©Ä´cåØE@R­Q“”u?ËA”§òìÚϵ¤f NZ"ñ0"O4”m•©û‡Äœ ÿ¬ÛÐ)ÇvôÃT®9yYðq“ç§7F#4«'Íšs×áÀ=§»Å;Ûì3cÎ+•œ”tO-aPÖz¡4z_’z×å' ç¾ñø‘ú5øõ«òAµ²ò_4µŽ0®9¢°Ãˆ®æÐ)-ˆþù:[ñ΢C^n¹'Ü„dà«Ä>ym½ñ¾°n;›Œj¬ÇÈ&bã`˜êWõf a‹ƒ{K3Et°…UžÒYÔ®—LVášõ÷^#S¯úÓ¢h3r®ÛÐ>ÇG¶½;SëÊʇ£ôçcm(C´ñ¿Y&$JŽÚ¼ÄÛ¹¯”%gS9»”š±WxQàDÝÀÃIVU»è?\DÄíX…³ ªÊ¥onv$Š‹h´ÁJ†¬Ë3ÁXm3¨z§ÑR?ÖûŒ‰ø|®¸èTb¹†³×B"|Ø›ŽCËS±Z±#4*º|dó\33#­ÉÌÍ{úSUãEÉæÛûÛŒªAtä.vªŽ¼¸Û»¤>ðJ ¸°%•qpbF³ÁBs§‚Oךã·_¦ƒý†ñÜZ¡­šU¢7ftá§M¢ñsJ„ûYuT*ƒµê)|áâÒ¥°+¨ èÃìe4•UuË’€€ÏlrŠ8t ~Z‹çAÀÀ&þ&~ÞÎiI¡¨|…¶[ºˆ|b±ò7Ô«\• ó qF9,þ¸Lø‘ˆÙSL|4m3ÜB„ê$®±Ï´Ïžž¢~Ù>ÒûVjY{ñÓ»©µ{‚£JPÇ8ÙgI ¥˜âgIö?'«°™]¬˜ŒŽ¦gÓéæ>‹ÑIõ¨¸jªJÓEù†Š¯3ý¸òêØ_Œþ¹ñó×È< ï‚ãí, iÆÜƃ>I,äÞégGeYf£Ÿ»×Ó±|æjN)Ydkö«³³;w³axl5mDSõŽy8}¡vô¿•aOV¨F¸µÜ?‚‚ð4¨/NI͘Æ`%*µ™i6³UyLÿ–{ðŒX³$ ŸyHeQÏ•Öð7(×ý{ªlˆc8aÒ:I‹ž”F}}’KäP «:öiJ8rFÓHIÆŠC­Ž9®H'´¤ D[ÏÒ‘íñ$¸â™ðo²úÏîþÊX­ MºS–…øm_â*ât;⌠;¦)÷8ôIoD†¸c ü„×ú0Wkn§d W ŸšÃ vÛjåð>Û’Æ,vÄÂ,úé¤è; » t¥Œ ž}Èg²ò·ÛÙíæRÎÌ9ö önêntvŒ¬ Y3Ê úLûÎ.~±Ý‡§&A= ®òÀ•ÌÚÅ]«¬.ŽÄ€ ´˜çÔ›rU¾?– ·ÈxÎEÆÖ^p l•ØN׋ö:ÄÌùÎ:j¬eá8’ÛöÕRÆ„°QÚƒO Égg93'>‰J‰{fµ/™sz©MX½¼Þ•$Y§©ûô“,¿j¶t”=‡ºeŸQÿ#ŽÌ-·[µ””¡o®F>L§³ù³sNÈ–˜CE™ñß&%×oqC µ{¸†ˆa±F•§?ÌVƒyá>¯q|éOŸ¯´8£ïÔÜ%Cò´Y4eã4'øfWA»¢šžû J) Á§Ms3>h2ÑÃMÉL‡Á@ë{eM~$"4€þŒ”Ç>K2KF@úýâé¢R6ú1Ú¶Õ1ƒ—×3S†ùb’µ +¸sDˆ¦àgíÐm”R‡2‰U¾Gh­Ò-›hK}öîÎû,hx”ê\¡Çéß#k/$Š 'ÏûþêÏÂqìêÖÇßšÏëF;DïìK>829Gѱ!FiEY®|P ÏX†kA—u=v [~â_ß <Ês0CTSÿ䄘9ç…™yÙôÊÎfT|êMŒg°% §C7ò¦ð•ÜU:É6Ðeùi’aÉžz^{Èû¹ $;ý©ÏÍŠB¶Xb¢lê! ˜¡³­óN:Ú)Éæ¤©sØ6bŸ4–²UO{yê ¸R˜´éÇDhÜ( g,Õn‚”ÉŸÍœo¡Þï“=3ù/¼JK+ê(ît|ôËRV¶~,*c8Åæ»FD‹l/¤SšÐlrŒí½÷è°±PJðGÅbYÊÑ­=Ÿ)ÆÈwº7hæa<—L´˜9K£”úCÄ¿Qçs]@êÈg®ãîgN—ûpV¨†JœÎ"¥6æân Ä Ôé\Úf¨P¦‡¡ îŸsA€œÜ'ŽìÔݬ#T\6SDR¥få1Ų¥öR_"á Ü'ê”8“xØon¹%u \ å_³"X™ŸOöî„nå4{:KœJä­ òÛÚ̇x$ÈÙ-lô’¨¼ÜN 0vZ±†²bIŽ×p½|Ñc²f–Í1mzíbm¾-tµ•ÚÆ¼òm®ý1Õä95˜Ñ­£‚P%yªoäÏÀWõ̯ïÓÌ£{Jƒ´È žz—¦rWŸUG]臻+–ÓÍNÜt[‹-rÐ$BþP&œ¡æÒ‚8Ÿ÷ÎáõW,Ìž¼Y£ÜB’€€±b¹I÷ŽX +g®¬ˆ{ åf¡•0ÖÈ(Åójhíi"RžMZÔqùÍvÎIÁ?"ºÔeVª‹ˆ ¬³Å>Ak!߈bo¶5•±Újõ 1ê K:À4Hö{EjÉúÂÛãl‘†°ÃÌ&uQÂc‚/òAmˆ˜â¤ÿ`5„–Ç—†F#ê÷KÏSÃZ÷5ˆ‰Æ ®m–ò–|rx¢ï Ã11XK¶âDD„¦Ük«Û¾o°xgµU+â8Æýޏ­SÚS?1üˆ_Õ#¸HܸJ’ÓÿZ«¶b³{ÆBŸƒßçé.Bý®øw̆—vÐ.cñ9ã¥ð{èãa³W]†wÆ EWS^ˆ¼ðß'R[ÈfxqûÑ-KWë0À¡,ˆÝP«.:|Õ9wȧNz)WS©^IvÕÑ÷€ÚÐHå5Sw•,äC­3?‡‚ÄkºäË ‘³tÊ2kùqbL–!™ã”1{DåBò¥b-²ÖQÈurtw³TþsÝ~׫¿ÈûÀß"ˆG¥Éžb²ÎX;¨,Üyuîb¾¦ÅÚýI×¾v%KÓø–qî+–šiÑ­Ò£Ï>÷£ÊqŠÜúv”îò(¶õ©ä•« ï&”D£ XDãƒ×t"aWî ÆõrÙ2++ ûu§— ×ìŽRyTf!åþ7pàw ·Îð˜ßÙPCÐÝ΋U˜µˆ_òË{#ùp RŽØ‘¶1}Sé(aý׿1½k/Ÿð´ 5Gžejžs þ¥â{ ®ß޲ ‰P±'¥ðTš½þïØ^½h¢w ú ñÀrÕyëÐÁ¨´CQÝdª&éÏeÍm¬ŒRÛºGQn”Ÿ¡.`ñë/úgÝ ¡!X-¤ãZwöž&ƒ0S–r¦%þ˜ŒkgØªŠ‘û»ÇÚ†€4E˜IAeK0k8?¤÷Ž¢%|ÀÑdAÚØûs4.˜W'vóGìfe¨,dµ!ᦓ±¾pCOà0îgüQ˜öze|/Ðf·Ó¡"öYÑÛ~вä¶ÝLïýjÖÑ%¬%mç±S›ù–έÁÛ1ã‡íÒ~“OÀy8±¸³£ìLOÂ;Ér;7Á¨¡"æã“Z,—×Oä Þö3èõÝ„¦al¦De ñ ËñÂ;’€€«GdýÑÄ‘"L•Mß¿ý°ÒaX¥±Û £+-à9?…¬>úQZe9h–_·›þÏ"rpå·XK36hꤰÑC®¨h QoYbà—¼Çt¡WºÅç<¹ÖÅ·©!Ôüµ÷T…qÕúRˆäwËN Ëüa¬Eÿ²˜ œãŸõèÔà !Z°Ó+õË.yþÈWFyrqÆ“Þ zÈÐ/~£láÌû·Vn”î~þN¿ÌÉ!þË •Rø2¦'óQüÕa"7ÏÒ.ž¹lPž‚ÚÛæ½¹¥P{] ÕjeR£ÎpaÀî}4{ÿƒ â}k®†+¨5Š[y½§ÄYyÀ(‹V³ñÊ;V,ø¤=Åv<ÑegqÙPÍÁ@µ÷R c¡Ú-ùâýt§ÑÒùïÀJìlË•Ž]K×@©zþæo3ÏJa³Ý oÕ™³Gª…öëreL¬ûŠB¤+ÜYËòz[Ð ˜Ö8=¿‡ÐwEü,Ëܾ$.&Ö€Ö¼’žå)ÊWjŠÉÁ€–†/æ ã›|…³c:#ˆ6°ŠêèŽW x(cBF÷Ê(·íi¯{?»s²EWîZÂu¯{Œ¼d`"áðó~<Ç 6öé7¾tÉqžš"§š±pùËmÛÃ'ÿÂï"^ˆÞ1úoIg¾@JÓõ“E éM3g%(å¼›²&Ñè•:WõÁï(å÷L~h5PƒÏœg¿zFv ¶ú”½91»¸¡ÄÒUÑE®°U¡‰–Ib¯ŠVS $ÝWïôð ¦ ™ÁB—Æçã;lÚžóý£®7Ñ?ûÅVUÑ8!ÀÄ8ŸÜ uÒà5#aÀ-±]="æÌÓäP"®šÑ¾ª HPÎ$n¼:†:S/™;Ε¤'CR8—Nø¦BùfD€0ÏèÖ=h·Éá  ‚1:z™ Z8å(ì©Ö+·Š¦à u‘Ïp’Ú™ &¡ª‡í5¢’­n\&4‚ȇVJCÆc~^È{×ß @G䟂‘ˆÑDÍÜã—UD_›ì åhÛí½†È­fÚÐÊ„¼/aœ’ÏìºB"ndÿB™-=M|ñùdÍ;å?—ÀÑ/ŠVfî±ÖçHá+UXNo¸¦äy7’€€½-Àã‚ãÅa”u‚ ¸-ɧxF´er¯.…û\âæÛϲ/èÝž!ˆ9çþWé5kÖüXÏ%h˜Œ“¥³«ðm‹zlÙ@E¸‹84¯¡ò7]±ýº‡eXRgóÎýf·tD°ƒL˜Ë'uJ/ß^ N)lÑQ÷ÂòÃŽæ¡@ô')\߬"Èâ´Z^M¨Û9 ‘Óa´JäÙV\ìb^,Öß@’f"y \:å ×ÔÀÔ®…kßs-pWe¤²BI9Ô×"®”=Ž5Pé„¢²²ñ¼j[¨/í/zÛÈò¹æ#X- ¶ €;þÁTqÐŽ·c î×’åg>?y»˜QЄSg8ÇD÷ü¬®mõõ?m*I›êÜÓÀîœMUvÚU€Íá m–tôÔhˆ½SÙìï!ÒêŠYSçpMPöEn×\zW KØ(0KZçÄÜÅÛó® ˾Pf)®h)Lk`>XÖ\ÙÌ=”ûËê1kƒ¸=32ü#1ÙB¡ïÄ×®KäÓþ´„ nü-±ª\æ/dü¶§‰Í\)ˆçoyYk5NrwÍZb AÃoÃÝg%X…D¨¨wÊÄÄ#5½Ï¤éj^ò±Xr¶õmÌÜ‚8¾Ñ¨ów¡ëHÝô¹ÆPwÚXrÜc× ¥ymÓÕÉ/Ýpe,Yù4g¹»^j”áÝI'¿¥™©*ÛÙ“âÖ˜!Ï{QÀÀ®¼»ûâôV  <»Û¢ýS%º¢—ÂU/ÄÇ1½-¼½l¢Rò›ÀÖ´#~~Äë5&¶ LjÎ$ñ(æþM„º‡FLt§¤á©Û¦¥¿EzÇâ›DXëŸ1†ÁÒα¡Î‰ÿ9ïÁþ½Ÿ ÷'âÍ´¤dò 4†êw©D †kSÍa5ÙÚcŒñ¾AÑЄ¸K½ã˜œ9^$ÐÀ@ ‚XNu¿t8i‘ŒŠÔ½UP5‚#A¶nt+Ÿ,BÄH«ójúP+¦Y@*ÚYB ¹ 2þÛìþSëAÃ["—+ŠïÍ×âÁí®ˆÍkÛyðzå¨Ú,lS”Øk;ü¥uw¡ÍmFJo‘hÉK*ï8cÞÙ¶‹.Ÿ®„:ϸ3_@¤…åßÏnáœ/gbÝ{* K†²“b_f[‹ítX—&ä+£¦¤›³í«Ö’€€¾[uÁ¬Ó¾;Wí¢ô£Jo‡óÉ’‚pâ•n™•KJ;{Q]z](i¤‚®9c"¸ba“Gz <Fºjg‡@­ €¤q Êš°‘wÈãÃç6˜c‡õ+¯W@ªîãÀzAœù+qh³#C ö,ÿ)lÜFa0ÀÅe óÔÛZæ¶Ð7|®ÂÍØý„¼xm!Ùñ½¾ðˆËà$¥It¸‹±{ ;Q|Ó}Ì@&P½Õ u3Ä«·Èøò«Î®Åxºb™¯¾Y(o¡”U|6ÁéüÌl¡qFúX­kY©kÿØTn´rI Í­DÏÞFãt8iÒ%¿±¥öýÊog3ÑÀúJS ;ÙõYcÒH;Ïbq;XCJ¦Êc¬›}×A 0ÿ΃‡xœ’üšùfeBy;¨D:Sͽg*i%X-Ýp\|.S!GlZS"ý ¢Ä¶'?rsë€bó ihk&Â!Pç"%n]›c÷ÐÎ$çî):1€Qp,šd~,ý›=á4iúNH©LÉI ?yÃz÷ü³Я ŸZ^H²ÿ2¼ñv0.±z … óþÝ“e`÷$d¬ä|ÆoŒ¨ŒíTWÑUO×¹îdßåìQøºøa¿ß†áéR¨ÿŪ,¯vc_ …‡óaU滾†Bý!E`T7?¸ñã™ç‚ôðÍê^ÈþòÆ©Üb²]ëX$ž¿¼x¨¾&_b¹zýÈ=zI¡øúûÃOY :÷ÿvÓ“ ~Ë ¯“±g÷ãë3bš®&¾ï²êEЩeÍ/”§Ù¿¢/VÆI[FÅp “D~c¤io`”ÕÊGǹû’5ùì§–ªðð›~Ÿ l«Ê^˜@b¤Ûg^¬œ&OD&B¹çèÇ]nôd*p qtÙH¡ØË ¢IWyÝ&¢£>îjëUs¸—l˜~ £Ÿ{ëNÔB²_#­£Ã HÊ\^{‡ã¢€ÃÕ$|«ÈçæH‰ò)úÆÝ¯¾vɬ¦ 3äPiÊhi=7ùÛ™ ®¿æ§Ítf®Ñ$>ç¼ë!d&Äâµ…Ί¾e%{,ÑÉ´ÙD¿wƒˆ'£ îJ'8øû”ar¯¯Q­ Êt(Œ9Ò· ÊÌŸÛOö/Ÿ(‰ó⨘^^dÙÊ'µé–Ë$÷ ™rusëÕÆÀ9Ú+xv—Qçœä’€€ÐŠë.Qî“60ÿ®=[wb‘Õ“ôÐLVÉMdÚŠÒb:vœ_Ffªì_M3.þ 7ë03Î)¸ž>Ô<ÇQ»Eq¨ÖòcÏ©jr.Vú¿u'©ùƒ>ôÉ´ÏÆNòWcá^¸qå «¡Ã-/" yv £ O‘Q©-keL²èì“M_–Úßùz4Cx°ˆ¡y8¡…RΗ]9îF”k$²ìÅe •dZ¼¨âË'D·ð56!(3Ì5^ ±4~C±Ö³ÕëËG’KÖÝ^㛃]¦à+DÞ¯Æ:28H˜ç*ãmfðÎ×åºÑv‹þðÎË™oRi©ù4'"?eÈ{yŸv_ü§5ð{æC7oÊú)¦C];r zOe¯ôÏ¥GðÍ¿G‘-lùb«PǨ.2eÉÒ€ðL1wŒ_+·šÐö¨ª*¹¢kÆçpyÕ~t‘ëý‰‰ß¿ÌÑšh_cZìÇC…Ô‰|­–‚p{—®w¢ü&|Õ…Qx˜9) ,M}ÍLg$½fsYv4³²»Jî·üÐDæÏñig©|*|YH`”^À¸Œ'#UñJgåö¡9,€ß+ø.–nyžL×JýÙ~tÈ*›Êa…KËÿ‘¬’ªë–®ê1e¶<ðw¦„»ö ÝåÏ?—†>¨íû±Õßâ„…K³I£ÃkógÚïøe:ºPN¿Sù¿± Áh[[sùBM¬Ù*÷3bwçI0KæøXT€OÒ݇ªŠ;Í®hÀï{¸GÞ¾³-Î.GâÀ«YÚq÷i¦ñ*F«TñÑ) X ú,£®^¼(ú‹r(¶8án©àT¤‘Ù°8ל[eW¤ç­_g[tI5‚¦Ãä¾ì(/¼ŠP0©CiæbîÍO¢¨Gêu±•ãüDѨÚkà|v>î^é¢Í¬ð¯Ø¬~‡HÀÊ©£.¥õ€éèˆ^Q1#'©°‡¾æaʇÌ?gÎÐZ99&„FÚ‰Éïs¸Q”Ê–ïL'¼ëd$t7¢(°#Ê…V%3êÇ22jøýëÊHXž,a|%¼ò†jNàZ½6î~¯àGš{ƒr4º(†{¤ž¹l¿Ü[ºê_ôשçǵ“—МŒ*O.åÚ¾ß>ŽkJˆéé!¯l‚ô‹,ê.gÅ×»¾ß»Ï @+@òÀ’€€¢6±’Ì ´þmJ6N"ðü×oš´s­ «÷Ð'Œ?ß ‹ÚºŠëhÂEß»÷m™b+jµs[§$‘ŸšÂ¹u¤ã*Š x€†ì„š”韩$\4°¡½=oÿ-c¨(ñSdÚuð`g£„Ì•µ=C‡£ö/´’ªoK²41{+¢‹5cgö´ 4õ£QG2IN;¿Ì:G8Øj}ƌ堗’ƒÔ6{‹Tå±L¡êËìhq*s¡U1ò ’û9ý³Õ®¥íÔ‹Ô^Ù,\]æCÚñ€ 4x®ì²} '`¨Ô=¤†±mþƒ '4}Þ;(g·«®i{FFˆâÆq»#C­/ñh9®çÔÛž‘×èrjÖô± ùþq4W ™XZ¬‚ü_¥ØE;âºOù¨ ‰®/^õÖ<­ $mÔž¿8Õ@‚QœËb4—’ ƒâ'´ÿöMI©x'úÕ!Í7(™ÄЄÞ3!p–«Ã˜–Pƒˆ Á‹Ç?hÕJÿàÍúÆC¥ëTÉ0SÏ­öD,“ÏšrM£¼e¯ƒuÿwº{Ú I—‰ìQDíÄ+œÑ&‚€fʆøÉA(AÁ*ƒw©FÖǶWåÎM÷ÙjéÏ=ÆÄ}‹Î1ªÑUáçûDW÷F–m§ ÷y"‘E 7yÕ!DñM[בÌq‚•í\‰yZ#³q0†8ŒQZXŒ ù‡ñÍvëBë8âOy2ïwa³š ‚ÔmoáMSyW£©³$¸6Ì<¹ 7á˜Sôð¯Ö-ä3äUˆí…ìË1Ì,ÃXŠDfÌ`¸!DÓ‚vÅXZ+ÿM8lêpRzZÿ–“oôujEwËèŽk¢go؈nÒœù –³‘›™ý›7ሹ¶Bÿñ¤ ‰FÑÙ¼@QëE‹N€5ai„’s®/0âkþøg²ûDÄŒüNÛOÚfCÙKuûMU÷sŠîÑÂ,º¼ci:×›áQ&ab—ô#oà£èRJ¤+ÙMm‡Y9ï|vüfÃÒ><€Î70D~ºŸÍšý‚ŸÓÁ7¨M¶º]’€€Ï¢ÍèÆRÙ‚äÞ>ã™ CB³ƒF•À•±þ,©Æ Ù¸}õˆrú`†S?Ϫ_ÔÇåÀœ#—/"%aYW¼n¤k“{™.€$ìJü’ŰÿØ'•qÔùÄ=ׯ²YàFHÚ /ƒ >L^k<²¶Ñ`‚ÕZt1K™úú.!äi¬ƒ¹L T*ïAžÀeÎCyC.OÉ÷n™êTÛÝ‘f=³; ,Îó±É =êò`»,H”?ª÷Àr½ß-ݰeÖ‹¬)œ¡áéÂ.@>*´«®A“imgõâÔÌ-HÇã°Y)u–ñßXuÃI»œÞ%¦^°gkáñ7Æq)›¤ÇŒYQpd¦—2:Õ²8ä®qÌPý¸fÀ—2‚Ôâ?K¹ùÈ8‚ËkLòŒ?i€zã¡ty-+'šy+\óæàŒüµÐô'P«KE!7ò~jÒB[Çàp›òîyãw>µÿi€Ñ—ÈHìoäcn<÷ˆ>1$û ˜¶ï9 ~uiµ¡œnزÓ–(•Ϫ5²ÔÝÌÚ(ˆéÄ|QCEÃlYöˆ¢€òX@#ä'­/Æb¶·¢;_.OæJÖ;KÎnÕ¶ô‚ù1I(„>éta|2V3›UÌñV&¼Œô(íqo¥ÿƒ«Pç!ÅÑføLßõi È»z$,ú^z3_‘œ€$Ôa}~óSVPœºÞUk ¤n&Ô¾“…,x;ž)k ácļ˼KÑã®>ÞI——ó{¸ÿêУ…Áa$TÂÏ#ÄÉqÓD=þÏ­ªíà{:tÃê`êr¶yŽ£a‘5c?ÌD5—}žKþxöؘyÉ·÷ÆSÜxl¿”ƨ2ÆzŠó¼¯!’…våæ±¢ƒÿårr뚯7"vvûx KÿŽòÔžoáæ7W.˜oÆÁRðÞ8¡·}-T:Ø»e¡:Ÿâ9>º²¡^íLgYУ/Œ‡°ãèF¾¥Ã7ÊåÃü[°F+wÓ Áªòé+nO´¸Ù_T­Qlïíð†ï—òåîãI ŽºúàhùþwÒu“"ä«P¾&w®yØÐeh¬ _Òø×ÝŸ ½æ¦Ú¡®4Ëîzh6Y¯°æ¡y¸pnÌ(`óîÆ3n¬¦ÐŽ—yqZÎà-ŒV ¶ÂÆ9’€€êHb8ƒþWLSŠ9DõºIÚõcÀ-¢ˆ¹ÞÎÚÖßLÄ10Û øÚÇŠ‘är …Úr)óz×W“íŽÃ[³ú–í.-ØVyÊ&?–-¨äŒüwü·ˆ[½H²eâ:|å°g¢•ÍY­²‡œ‡AW× ò ÷JØÔ„“AÙì(ÇÚñä¬ë­Oö!¬€Ô‹ÆÝ¿ø®Ìä)l⟱7‡à2œ¿:=ÄUø;ãØ¾:fvׯª×ÿ‚Õ‡„½•ÃTÉu3Ŧe\ÇÜ\*á2”È,êQ®‘ð¼Ì÷ñœg¹%ùûÍi"»3ãH»… iÞ˜É0@v8Ñ6nÐE_›-ßζöêWÏj¨-V/½µ”>™ê…k)Õ{;³Ï#7û¢ªê`Ô×:Ñë'ôŸ{bø6m…'GÒó+u×Ê£:î§½u™í9îBÿ»S_ýefwEÓºÃïO&CX°J¥Qâô!ãUn¸jiãž%/I£t.?vE0},µ†«M[ªþ1Wö¸p B/hY*U°­Ózw¸ãÍ87,Bóík®—Gÿ'µfDƒ#ÌéwWèã¥hk‹Ž¸þE(ÿúYÉ!2hÜãõµr» ®è?„7z¨?È$CtŸt"î4ÜH|ö¡ÀÕK|ÁzÈ™³h&©ûÑ"Líßo¸<\Rúˆíúù@áWË«Ø}E¡¬ð£iU –‚åä}ÚÊÕÚYçóUéo™,oñûãxz0G‘&9l‚j´&> =ä´Ð‰ÆÛráJR ­®NÀí 2¤Ð·œÎ¸¶Ÿ[tñ Ó9ÞíbM66Šæ3î,Çÿëå‰ò·Ã— Ò¼ºÕïg¥9žÓ©~ÙLœψ ·ƒ÷Ä6¢Râé¹Ãü¥ˆÞú"éÊט‡ùyˆÞåa„UÃð* 2ŸÔz«/Îù cxFò8»£}ßI“éQÐRKµ#“Ú§j€X£b#H!ÙàîÌJFùàÇ7åž[oÒz¾¯¡JXü&èd# a¶ þ„“<]Gó.ã§æÜ…Â›&GÜ+ŒgÚñ£v_»£Ž?n6¶,~‚.÷¢NûÃÍÉ6#§~îÂ+:áï4³8GùIú!BœMà ÿ;(©nñ•žYºaf­‡4ÿôûö’€€ÐŸ’ȈV3+=37>6Ó"”ÎX¦ [•‹¢ãqÙ+;O>nÌÄ®f{’ –zQD&åfC½µË9uœ³ií9è¢üïs`4:ƒ5{²Âs Ò Ü%ÇÍÛ&XA8è™è_ pk}ŒPõD„$ñí>ËíkÌ9bbä„°³s»NØZË«m’ÔBµ\:ê_&xs .F'—Ô´H…wŠy!¦&âûÕð;©ò@3 ±á¦•¨UþCúÝïKfŽf> ”u¿Z]hu'Y®½RéAG+ Z\L2À#äVO±mÕG“æð£±ñ •4ò Á>#S £º¹TšOz@mÇÒ8•i®,eLÞ«Y3ž2­Æ¾û0ñâ<Œök-Þ–Ä⑯gÇ¡­„µ“IÙÅÐ÷^É Ÿ‘ x>(1H.1[謺>jýöÃl‹¦!HaSèŒÿLuFlëîä™Ú0E­1Ñ2—¾ŒéØ÷û9¡´ýö§¿~öŸ-Õæ޹ÄO°ïé§bÒ|ËÙä³¶LàJ¾ƒÖÚýÉ~‘"¨%ÑÀ2»?¬BØt.)ý%ö•‡žÝ/ÞX|ô˜Cªúzó€¹øì‘ú©j‹Y÷˜—J83¶Ù}ØØi,b˜—mr§wÏí|0ÁÉ8·ð$@‰F‰>·q{ÜäP"CæWªŽÉ¨ 'ÆtHýNÑ·Ÿ.‰ó ©c-Þ¨”}¸ªýbõÕ:]9ž•6Ý·q^û¾Â󦚔h@§zÊé )¿r½²7¿= ØõÈ|uB›ó}ƈ)îØAÍŸŒ c ,—Yê¼é«²ñÞf|'‰Ñ¤·eTâÔÖøÚG‚M¯.ó• ¨ÈÊ ® å¿(Õ”vO¤<Ø{ó{¼Â•ÁšH¿hqWÇl¦‰oâf¼Y—Ò»ƒhZPa—£ê‘dR;9Ä1—–RŒZ¡ªŸ‚ Ѩ•üŠÆ…¶Cœ²mO?äj3o-ù•¡Ó³¿.ì{²s°©¢]Ëa@ òÓÂ=X¸äDÄV<Á0Û!X=ØäÕΆšË­›qíPÑÖfï+l…U*Äò#îµ²é´ëàÅÁÉxmI×95l3©­§öÆê>¸ flD Ô ¿Ö€…å¾å(ýQ8/‹ žîzO.EôKEä,–ä¼’€€®¥µ%(üòÏuïW‚}¹» )_–3›Í©Qoî;†âÇ §~†fÖsãÌò€å„6c½Ÿ"ÂÎRjæ=Ôc)~÷ÆhÁ¾HÎÊÂÌš²ÑXPéX9yH;[.Eºs!4?‹,—a »&¬,dä—•]èžqë ˆqŒ7ÜæÕ#ôŽ×¨ê”z)<ÍPN©ÛÌËR3³º‹Gwñg±4ãb£²ðÃù€t÷è?Õõbâ 8i2À®æcÓ*S¾ëd¨®Zγ°ýx\°ŒW¥>™JÛ00fÛutú·ó,9ÝÈŽÍ矀{dö|_ßñP¶U?L_Èwµ8XHÏØÕúɾ Éß#nËŸ#j[¦–e+ÈlêrüÙìûÁ2Ü—÷ÉiûžÛyz5+ö¢žê˜~^ÀB->„ÒˆÃÕ,kcW¹S !]eÚ˜Ï*‡ß‡®UÜ.ž³â-Y3ñáT]Äh)ˆ+ŠÊ«èÊšïýàg•r¢#~ƒOðd ƒUÒýÆ€ñC4Ih_Z!rÔ™ËÎx}ü!ð~†ßöSÁࢠž­2ß’:Q ®ÖÅÆÚ‹Ÿ¡=Ž™5ÿzÔ¦ 1=µ [_šdáÊûš†èEùyÈ_Èü¨+N›¥ÊBwå^Á9é(×ï1§ÞãÁžÝ`iâ2aÇuãê6 ôÀã“t6ÇcHÌ¡ú¶b²TàéWD3¶ìYý¦ãKo©ï®ño×C·Y_¨NÜg Ƙ?=½­L^ÒŨŒ¾\´fÀÇõM7À\Ë‹ªã´Rþí…d‹ ô‚íöOšzË>óû @¨0 ÛÛûR×Bä xР½€È‡²°”x·´Ó÷ã°ViCÈ‘¤æGúÊh+nû!@ΗKÊIáUõo§ †’{bUqV² ÊÒ°N-Œ6é`+ôb<ZÃ"‘ƒš‡TV·øïÖ†¬ƒžþ¶ÃèÆ“ _ª ŽÂÄ?f e¶ÞS1*lbÁPRNàe·Ø¬ËU¸öúó*=¸¶&Ë0 M˜VÈâ•%ÏÞûo؈1÷d›G ÔÊoÝárÀ):t7ø’lnõ²§ì³`äJ²sê’€€²Ì›,0£‡¤l-«JœÉßú8ІšþA¦ÅïýŸõ–Côg „‘’©­ú(kÛʘÈÚÅO”j¤w|[uwø¡h¾[ÿÅFÍ¿Ës|nïIÆT1bùmš6|å¶å°æÀJuûOãz#ôñõÚÒyßîüiHÞ°ñË×ÞÖ4"3qO=¶Ê+)'ØMÌÉiõÐw 61Ý7“ã¤%?¯¿-Gr<˜r3É5cCúÁ”«|=RZ IìÓ’bŽ2¹¥ƒmš‰\¢òð Õ¢<®^-¶«\ÀHï¡›û¼¼¢h&¨ÄÈÛ²ÂÊùežŒ¶µ_ßý+NíU#É…ÿL•˜?áæ\à8ØjäqãŸ=6˜*ÄÈ BVpUýnžífB+¨0jº{Aj&nÛ¬'b¦¬zr}Ü_2³‚Ùôáæ¤þUx;urKÕo׌ë§Ð„£ð§ÍæÏÃaX‰5EqÏ$M€‰ƒý$À×Ååz²üë‹ä%ø®™»%~,—_Y0<Æ4 »Ä¨(Õ-œzŽZ^:@£|®pi'v{*ÑƒŠ¶ñ¾î„>Š…)¹g¨vá ¼S”ƒ¦¦mòñ‡_.ôƒo­ÂÙ1¢&w—_jáÖÞ×”Õsð‰ÞµÑ€J&þ9¸’\ªm”±7é'.F¤ã×0íÀÙ~ö„3}}]4ãg¨Y-àTúéÜ+:`%¯žFŸj‚ Ý‚M±7Àr'¼oîüO_/Ó^ÛÅÝ£¥|V&Û#9¬‘N< b5XpЉ="$õιðîqÚ»Ÿ^ü•Z¬ˆ ÛÖßüýg5ÝÝ2ý: >f[ÄQ†Yü9Ê.iA7VÔW¼ñÒ%¶l OþÒ`Èñ(ãÂÚB¹„ÙÆƒ wý©ù8ݬ;æiǃAМŸ¦¯…ú;P+'8-ª¥‹Ö+¥q©š°Ó‡ YÊ DÊøÿQœ×¥›e®= ñ_«g¥ >ƒÙEJ?äà›”Žj»©çé†ò·¤d©Õœ;Ìì¹* y—ÊY¨8ùTÎùàôæµ(× å}P¾#®+W×iùõ0`¨ÌÛ-â‚"£îCGÜ`œNµ\bã±ÿ]Wò#k“ôÑâZ´K?ñ"àqÜ“'•TÒeµ#p»’€€¿‚%XMêT5ó 7ó¿ó¶H’”ôÍb•Éü9þË['9‘ÑsÃ`—ѪÉè$Ä÷OΈߡֲÁí­¤FêÐ~Á[ZE¿X Þ` YÒÙ.HXâ–ÿR¢ÄéïGEõǘÕÌÂúl¢a„nn³éÏYVpZBª3Ì©h­EQ’úq'œ¯»xe˜]£}ñB0w¨8Q[ݵÈæŒ*´ÜE!˜-Fë¯ùY,y4°8Nt¯X»D Øxs‡á¨Âê$ÃåǶx”·¿¦XPÐéç±çF!¦©ÉÌ¥ÈPÜØSs·ÒIG ÚBr÷â>z*yæ¾ë°>Íå-tŽW²ÝøÂ'„ÐøžN”Úp}SœàÐPÉ­ÆñgPnzr‘›Z)t§©¸‹£J¹} )fÁÖ.m5*ù즅?C[<ás‰\^’ÔiV°Œ¡\ž8Wı1Œw„'iÔ–[o¥=sÈÅŠÖ­Ç`è°`ܱ¦IÑx c8H@ü¢]rÃaÚÆói¢Pçà“Ç8(ï$þr9ÿW•M޼4 ¦¾ÅOx<›ª[~¼oõa:¾} çôá÷÷÷ɽ<‹.ŠáñÁÑ …ÅÙ¼­ØŠu€–à ` æÿ~E.æ+ä°u@!º ­²»ýì}fµ[áZÕŒX“¦eUFðQ®Üo» Öi¢ØñŒùãÐèg‡Ù@é]f„¸ .­·¹X“á®­m–emNá¨B°‘úž»*l•Îé‚ ~Ùªà|üËÉá¼»{>TÞ¹gÅ »C=–Ók…ΦFAI_¶b©‹h ç^è¢}€ÙÏ΢655¶7t¬8D{нľC›ð]ax—Œˆ•¡ÌaOùÐZÔ_ o«En{ã)2Èg!z‚»+Êχ€ôÑøÒþ¤]7ã°f³HîÙn’€€¸!Ê—J%Ñ‘€ÕfBqˆ£ô²l1ÌHlþ¬Ûû±@Hfqz.O›l¡†çÚúÉ9‰,¿JæÄêÊÎ-kǸ‡æí7ªÚ:"´jf …ý…,¼Ð7m‚W³ T¸É›†­º°xÙ‚8d%aå>›´ö¬xNÞ\ÜÛ•Hzž!·/¡Žú0SkiÍON¯Z Z/@Ëí]Ç´õÈŠ¹ö\(]?½%Á©CK/ê¹3›šWÅû®@±;wMÁˆ]»!Ï&ö[x`ðNJ"¶d‰îœgÓMb4w÷÷©i¤dHgH°H ÍnÚ畸F¿ø¶_5ŒUi%ùë[Ϋ­ülö)‚«€A@ çÁ/6ïƒÛo¸y¢>¾wDR)x÷ö K à…½Ü¥!w‰s<+%4"•æ6PèAÐÅyÁï–¥çzÈNÌ—ˆ#B¹n¢Ûæ€À;öë ™ïò©ª™Ü"T¼÷ðc¥”%1ÒáîdÕü“Û9ÓcQ„ü¾ÔP{ Éš*1س"­2¹5(¾”P ºÝiÇa¿õü„ÌÊfð7J¡WÞ1õ'9‡%õïC DçÑZk °U‡>Ÿ]ö˜ËÃg `Èô°_”\[Ö_ \KÞL/øò`1Û‚êNÙ°‘plYÒU¤>íl-dÒ»¼2!²+\uf›jÙi„´]½½hŽ£äËZ_*מëzmVdÊ<ÓšÇêUd`\ý ý§ÁªÔŽOÑ:ãggåj&;`ž0³./¨Ý3é¿(Ëw÷G‹¸¡*…)gÊ¿œãsyƒq]o„åæsûT±£Œé£Îë÷Rr¢ÖÎ[~½¼Ö© PÕãŠm ÃÛœNd˜ðçjª®kå…ÐÁÉ`_÷ @¤Ø ü%¨Á⬪¨ß×õ÷ Äâoͳj’fïaOÉ’€€£J[9ð0þ˜BöÖØGÄE@"‹vj¬0{׬öVY’gF#ð2|î*0HJ'H–ôøpQ‘Éuò¸‚D£DmRÙÀÑ” Ž ,²5žÙ\‹œËÍ3cw–ýVX¿/@ÿeeL”À¼ô#ŒŽäªF‰ëÅ2{ï¡ôQë5’<;€Ýaø\<•ùÅ%ZÓ w+ØÛª'þ2ÝžÖ‘;cBK Î%ã ƒä1’Ô]g®™RÉÒsE§É…C$°‹4÷„,5°Š?Ò­Fd^©¤ù>ž&™¥çœªûŒhfRTE£È¹%ëZþ_`™Ç©*‡Ü>½×–Ýö/”ÈòR˜ÑFSi›/³è¾AôÜÆkö­w!uÌA…“ýzö÷ÒXpÄuüòØŸàt!èÕ"'Ï—NCË*e©µð®o ÈÜ©Ÿp,µœO¾§2ßÀ °™’wUSb§¡<íhåA¾ °ðy9½ì‰;øÀ"ê¯Âno‰@¨¢¶”ï!-xÈbÙ[È ˆúúTŠñ‰•—R`^›”!Ë_Çÿ¥îtà }Owëµ9d6ÅS èZ°ÿ*G¬|kÏì%L‹ ±‘ùÅ¢ƒßJmª¹ðOÿå=ã§Z³(vì-ÈѸ×›$þá5w®j'è¬úœå»J˜[3e»D?=,\¹õ7D,šµ}+è¤÷ê¦ìÂÇhñˆ÷²,1ìE9bœQhÊ ™6k‰§‚Ã8ªHX¡q&Šè‹gw¿CrvUºé[’tÎ3{l*eˆ’€€¿ê6C˜X6ï¨3Ò`»´ü9ë²XÆ+è2ãg‘æayE~s£ow÷øÜÅM…¸Mý\ƒn‘ùÉöqF?ªWJ8\K{$h+PUt;F”jœOž1³¸ŒJ-ñ**’gð“qa:¨2<ÌiÐ!ÊQ¦Ñ¹4˜»š›šqGU´÷ÌëÖuØ“An™[LÑpl–¤ÑËÆºÿAÞ:Z´F-/ïÚÉwÉOÀô]æ‰*&Vû,>^|:ÉŠ}:¥¢â³{íðŒÓ}ë¬z÷3çUí—-ª5o©©×ò¤Òà¸ÌfÇ~ LâܾtQ–G§€L5ÃNh§™ãhmÞ"'…w㣠Kû©Âzdàš=@º}` ú½w=Ô¸4šqg0Ìݽ+'+³ÀþwXij½`z{çÑò  ¯C›ç^½éøjLe%GnYº»0i8t{e©Shvã ÚaM6¥Uí/<È..¬÷úobÓ@­ÞX<¯ŒE»û;&ÒߘÍ/åÑ ß E¬ß™-]Ѓ¨8ø¶ Ö¾ íF×7BÑK¯Œ—¾6Ê‚Šº¨Ùè¼.ÙZäÂÑÿ’(YÐ[Z5柫œâW}eÁ¢NQM Q™…W±ó‹qáªJ°ì„šØv:3™-N\ÛÚêÖ@z©å­}°1pöEê+þL¥ûŠ˜QCÇÞ Æ$–B¾w›‘BäçfE 3^‹>Î0h=D'ooÕèÌ|Æ8K~Èù2¯C`p3Óœ×R³~‡€@Z z9Æ‘!©bÜ¥ÝTЊ1:¾%‰´ž ú,Zc¸YøCsùí©ì6É|®µá†S§5O^™çaiòKɱ湞™&qB¶\ú³0 Ógí7ú0øFá)‰®à:êúŒ+q´íFsîE_ü ¡Ìoº` õl®t EŒMǤåGåçïÕÆ¤èa#§Ù,°Ã©šžÑ:µÄ 5”E|m0Çpß±×ô•¦mŸ©Ëúˆ ÿ“L«>óÎ0bp!=ovfZ‰Z¦øø óŒäaÂk±"†ù÷¦³WC7’n’€€²™TZÃàüÍÜì‚ù´•šö«õ#|3^µØ“N«È¡K}*|N§j„³ÐИÉMïäv#±´%¤˜|–5óŽš…Ðæ={jðæy)Ãö¼5¸3$‚šÍ›ÊÇÝ ˆÑU¸`€mSã1µº7¹å !ˆ#‹;dØäÉ8@ÆÈÄœw •ìì»á¼‹?1iò¾>ì ª<6#-ÚŸ« ÝYøû">ûP$$;êWa¾à·©É[¢@‘…f­’èÇüè²û‹ëää:‘e=a‡GJî¨{Ég}éÿnþUµÌdVlÿ @Fbóóصˆ\«¸GòjÔz‡–rç 4§òLõz vü’¢°PœÄ<{ç[ü’'Îàñ¼“’3Š>u'Œ†LܺJ­²·ù@”s ¨+ˆ ¯©3[¢Íßð_IyÐãÇ^yG®J¯¹Å>G;®;[ɵus™X¨‚’5³N:²µ+´I⬫Ik ]”B>»Rà S -âùÛû˜jP‚5óDê–­Å(ŒÕã_ܯL„Æ4àT7¿/ÿC}¦ÇÒ;è:°…¬Üh¬hõÚLä{Õµpži|bd¦®?Ê>Ù©(2D iž­µÆ­Œ\ƒchßÊ39N}¼·PkXe×¼>ÔyâÁ¶aÏÜ<Ž!Dó1§fNù£oƒ YLᆄO§eØ»”,!!¹O,¹æŽëÙ+-Yò £“ݾq®{Zð7ïþq–›±¦D«ÿ\Oµž,6CËŒþ¤{®ñÑ$ÚÜt{&y®_t JÁ9]´ŽÝÚEÈ!#S§`þ¥OVyÜÿ† J@otNâÒ—!­×z$㋪ýø¸r÷dD©}€Þt8æ)޳ WLö‰÷Ùž.G5ƒµ&¾á ¸(v5[V ÑŽh6Ê™h*Üœƒ×’€€»V½oãÀ$Åû 5'¨:ÉÒŽ»¨š]aø.ÜXWžsµ™T}¨p"6R¨eUô¢ðvnu(I Õ^í¬²$sDxTœZI ’‰òo,/ãr 2Ov™qS·(MÐ}G´Í%Ttqzn0Pä!þ~vJAàÑü¨wžáÝ.£,Ç¢<;Ÿ©˜ý¿Å†L%¹ÀŒ/õl={4ßG±‹±ÄXDç&þ—ðJW-©\­±™\ßa€Ÿ,mA4ý ¸*D÷‡og°Ñ(2yÙk©ˆXì„EXQ°£ì¬cÉñ« \1ÊR¤ØÝwýA¾Qâ‡À—漕ê2Zœ¡‹ªÇ¬&5ïÜÓ&EÔ—P:_ zl5ÊD޶ÅNYÌÊ›.ïõÄøøÚê Þ%óm¡xú|ßÜÛÄæƒÌ})Ø,–hÒïµ5S(ú)aU0©gݘôUáêžçjº)VúQfïÍÝ2‘cÝÓa2ò ŸÀ!$w!ÆÏøÿ±=ø“'[?Ѐ {™¸#ìŠ$ËŸš¹^SíòÛW|j¤zÓ‘çÒ/k =ä¾-„ÝЂ Å%f„j¯~>åäùn_P¾ˆÏB ™L* Ã¥ëð°ö@5PÿÞÁBÅ×bc%X˜×nn¹ãyÜÐ:3G¤9gIC)k«]éMµ¾Ã²[Ì‘$g»t­làŒ}(ÛŒåµí¸w7-:O«Éíª³Ö¾Ìp>%yíQp»`MÚ¥ÉG%1"‡u¤xÞðûx4’Úv+xÛ[`U ³äwCU‘kÇòEAþS³hqATºÿ«_ß¾³|am ëpŸæþŽ ¡ŒöÎoÂv—9¯©‹¶a¶ÈHÿ@¿É¾‚U›æÜ¢ Mð;iªÍí]}œ7ójÏÿL¼Ëôä…7vÆô¹ÀòÞ¥Øëªà ½+¯TqÅ÷Šü¶ªºß "¿ Óéwžr›‘¬­á윖=¯¤õëe¿ió(µ¢sëÁ_mˆ”ޤL”ÄN ÅRtTßßîí1Y»°™¡ÌüŒ°¨{³õ›J:¤îˆôGæùc©ê:¯JròMQ™5õŽÔÎp´¡¿YöÝ¢ô^âÿB<ýžtju½ñáá¼1ãH0“ìö _!D¥üB¤ê*! ŸDºç èBchÜÔÚØûR^ʼn™Lj݉òtŽ ÇȤõº»@ ±Ú’€€¾AP$¸CÀw£/W0›xNo0ë#Ù½Kp2u µw°¯Ž”Ê‘ŠŠ5¾§½6ËË¥ª±°þߙȽ<²ßPÒbEЃò¡8ýÒ†IuE¼bŸÜÉyJæ)㼃ۋé¬?îr JQJ=”v8¢Žªh¸ ±HÑ"1k¡À;gÀ©^ãe \%Åì)=5Àç70%W§Ì8 ·´Òê—o@­6ƒpÚÇ&mö©5­ðê´ãT!t@†}WÝóãóã!¢\¬eo‰ˆG¨ìµû¬…Ìè@†ï#» >#sGI“I €±ãaë­ËHl„A‚Ÿ Cæ ¿¤Qk6Ò1¼äat’‴7ƒÈçé•OÍu_Eôõnùø0n‘zÉ׿Üþdþßñ\wLÈÓIÜ7ëÞቖ·±s{’ÜåŸ`‡]õ‰×›f³SýÒE*c£nlb H•?ûçë-ûŒ!£l º[Ä$µ¢©•Úåš.ãj81þ E5¯ÞʘØ:®3á×’:F†H™Æ .b‡Ðým\é–™Êz F\zÃDº`ý¶Wþ>¥ë H½ë€ ¿MC†=^Pžs„=jÖ;6PX?Á(1‹oC¼ 2KZ}lnh-ÂxàÕA•× –­µ©ß“WìÙàØ9JFOj>@àÒêÞË‘Þj‰‚­Êã….ŒM²’Ю@CÐjKqÏ~²|¥2q¸"úl…]Òð1\1€Kžî#{¸2 ‚yÀ)‚oÆÏ³ÞmƘïŠÂÐ`«•€Ýûx•DÍðŸ5Ž‘ª[Û²ò³1gÙh’[㸲ÕPå™'§ïS q0‹Šk£^ÍàÀ­@á -¢Õ#”Ù•!Ó4@Sl;{PùºIAáAn´·Cš“É(¨üûc¬§JDJ…GPLý~„‡°E!¥1gkU8,¶Ê~YÆZª”RIVw~–õ.H³w•ÙizÃI]¡¯Ñ‡”u… Ó£RÉñ#W]³jP 1qÏnt}è2<'E¥ö ›§ÝÝæÎ"ÿÀ§ó|Èÿº²Á(&»?Ì_ŠÃäé¨ó%±ñÈ3E»¡wöÚÀ³Ñ0°˜M•.-…9±¤Ù_ƒ_¥,'>5ŒÓ¶>ö@h V’€€™ö•ˆf÷”6»™.jÜFó7ä €]O VЏ 8V a'7ñ~*Ôà &H©HmјZiκSÑmúêZÇ$ëE¸°v6Ÿ%Ô³ZØ”;¥±‚Jpµ(e x&@ð<ˆ„ãú‡“Oˆky|‰à¹KS“ÊTŒÊ¼†ÀÐQà¢]ÐéÂå¿é‘›²÷käCù·°$µŸ ØS$w¿Þsöž½Ûõëk?lÖÖõq?ߣÄÞU›ín›‚ц©ÆåÅ” ²¯¨?ù^çÔdäçf4´ÖÚQ| ³Îù§‚IÌèƒM†•¦×Y9Ðèë¸õdvÜP¥óï»%F¦qɈeŠŸ½¶„!¨OT›~¢Ô³ú‡×ʈó?ü]>Q—>šD€~%¦ÅÂhþ°ú½g0TÿFÅE#Pú0ÿ@Ð*µüŽð³.\ùGM¨+³‘‚éDÁR ;üƒ xíJ¾#7A´Aq ëæ­>©Zıà!ùœ+¾ƒ†Qû²‹°¸ÈŽ¢K¾N‚BßhZt±¶@>¾ç™¡]Ì‘” êÿD1¹.ãÖ’|¥ÅàáÏ«y‹cºÓUÔ‹vÞÆ1­cgEE,7ó%.÷ŸK’bkF$É="ZMö.tç…ÎóÖQß|ÌÊby A“’ šä G¨RŽ»ôÎdƒ>  Æ:¾Û¾NqR4*“ P pö PÒHÀ„`'?aŒ¿“½ò„ÈÉô rŒ ì‚Fh¥ ›åpø7þn'C )xʺ¡Ï¥댬’_5ƒì ’€€¯è{3 •Ãâré2´1“AËš®Ž‡8xŸ\¯%&<‡V¸Ÿkç¹Y/á݈üº÷k{êCèR>ç‰Y..ß0Ó&QÃæ~Äeû–1q˜]D÷úUýcI~'¬Ç~)©ˆce?†Rä4óéq²N®Äk+’JgÝ{¼,:UÖzdÌ_>ÎÍŠa຃EÏ—Ó5ûp­Ä{R~L‚$Fæ’:1Ä+¡ßù\$c ÂâZŸwK§:ò féj´8Ûˆ›=Ά¼1ãQz Ov'·¬ÎkLÛSò]s¬R²;àø+•6Ñ,±ÏS†­pu§èP@k>‰íäÑc½HîL¯¡q÷mÝ’ì!¯h)÷×.÷ š ƒð AçCŸåp˜Ýú]?c›8Þ4á÷ÚÙÚ~KÐ9óÏ´ntÃú» bÒ'R Õ@HÂQ‡ÚÐtÚÇ'0mKZüÚ¦ïã>Ý$œ¾¸0ð¹ì(è­'£ytU©Ä–",¿žØ–Å8Ñäs¤×m_ujEÿpË>o‰u¬CÓ¯¨eõô=rÝóWÀ0>¸»S{hÇ?{Ó ' ð4-²^- Om‹~Q·hµ#FØNÑÀpeL*}uiH5«{wž™b ê‡;ù¡¡j|!pïWeUà F“Ä¡pª[-JÖ‰Ó–ñ:ur°îb€QÕhï$º¡Bÿ?9¾Í×óª¿ALçhmëüžP,ÐüŸUŽÍêl.göTUÁ‡´û•5J"š8ÝTP‹ý±«Dü(ËTYË–uù¢~PȤlõƒ•¼kg© Èö˲Æè“/rýN1ž?>.ioßk¿²—64Ÿ›f9ñzМÇúˆ’âÛ2hŸ þ.»¾¤ÉVføåØjUgé,;jÐæx>¹‘G15|xΑÖê\û)ËEÑe\ ¦O"ø•dì@ÕÇ:žfÌLì-š{]k1`ÕH*©3šë¸hUšJ¡G¸•mÙÑ! XH“iþÅxÜ»a À21kaE* 3e'пXX«cxÏ c­€ü#í·ÙE"(ÍsÇ͹~ÅÒ*вw)w’§]wCµD¤WŒôF›#8äÝÀ¾ß› ¡.Òe­3·†+¤²í’€€·Z'ǧø9¬°¸Þ?‹Ü/&„J÷ÍÑpcSþ!X°yèý ÇjXÅ œ 6Ylý³í7Ÿ+5š»ˆ'´=IqÛ2þµ‚\Þ@õ9!’ê!Ãâ#ê+@nêê 6œ˜;vcÑ>·¬:Ð÷»v[‹Ù—¤œ á„BÑJ›+Düÿ(VàÕêNlnI‡WRXô ÿ#P]wÇ\%Ϥ|¯™à¤Îqb•ÿœæBꤠ–¯'*0ß)àýÇÜÔ|¹öǸt¤:”œ¢¤ÍT}êB©-°´žm©õ¨µP}þ“º{[ÚÁóc9ÿ¿%ÙdŸŠ"w@ô˜ËÊÈ{Lcäæµ36ï.ÈE@hð&td“÷Bëª l’w~€M€7 c¤ Ÿt§–d„2êtãæð×w¦«Ÿ@¾a)E®Bó{›£K ‘.ÀpQÝ;ôw°:Êk–Ê’O\½ Õ­Ú+Ä%¨ѱ®êŸÚ6<`"ùjj]»88kÛšiVÁü£)ã<…+$¢flC‰oÙ€dÑ`‚¤†6Swhé7XnÂÝDþõü/G €Œ#' Ξ…ìå Róä„¥²2áR«Uj,Ÿ"Á{0¸ä±ùmÔÇAÈ¿êçÍD%Œ´šüë`§a2v'ÙÑŽ™×6×î¾;÷+Rˆ+Õ—õãôœâLJ«‘ÙIÜéÜ…¿ƒšyPwcpµVŒMÖ˜$óID¶oø[¯³ú½‹»%:¶¿‘o€ÖÓ ‹ë·¦wYOÈ!¾Sg.QN3Nm@Ä´ÄXy!3‚ƒšgFÀòlíÜjÝÖLZ…ú™êê;–í÷qöESÿ3ª¶—òA ‚%«ð2 Ø„9~tåÞô!Æ52Ll8> [̃W?"„ô‘v²Ša‚;þ]býYaK‡2Râî)K7cQé‡NVí/¼¼YW\QM§¶öÀ HT`·Oo«è Jª­áûΗncÍ׋¥%Íú€Îª—bC_WùyäèŒ[q~ åö˜a÷qq£™;ét¤]‰áSœ˜½ WÉùàà¸%5ø;ïgÀuÕäYV9»c˾\ñ †-M-7#û!ä¶gêOÀTÖIJÓAªw_ÝkéIJáØ‹Cx< ŒZ³³™–Ü+á¤pR(Δ48§+,~Á¿’€€ÂZÝö)½+Ìê‡+5¾_içö³%¢€ìQí ÷t„W<Ø’±Kϱ±)ÑŸ¸i)7ü [΂§Õc–Ç~{¾‚ÉûóLv¥¿Î´€Œ‰¤§F›PÑB»à I#BJ×âÁ¬!ÝÌܹë¿_{l© ‚è*GT„wX tzhÒŠP6à:|I¯Òá'Ù\ˆ×[\ŸˆïVDl³ø/ä)³UvóÊßwʳËoZ ¸’$öD.a¤;Á ¸OŸOÌ‹c ˜Kg2Ç™ÔÝú±9RÅ‹9 ©máéÉTAX2Ǫ¿]ÄI¦X'é9Ž©¬lš 'AjIµ÷#H¸†%óµåØ„²µÙÿ®éKZž@w òFJ€-\ÿ¡²Å }ï{.]ª›•±B·ý‚äB08Ë"6÷ Eê„÷Š—ín ÁóaÑþ81´•\†#M\\\8™T×RpÃs±Ê-D.ÿ²‡Þ)³’IWËY¢ŠpBŒxà'Š Èx‰5Ã’Š&ÚžAªÌlÀÐGŸ7è›62%Ìl3Ô¼QAÃ5ˆýðŠ}§ xÿW‘2v‘°_7Ǫ_bÕu?®Fwàï΃Cd"€06§QÅ5-¥{øoÎ#3?­z¨¼–¨h²lA¢UÏñÂÝN2ïr²]¸ÍWyú/×üBé ÆLçß 2=Á6;Â(a¹<Í Ra|F=o'pÄ×6ùf敼Ïà^»»Ž×düa¼à‰%Ÿ&÷r»*¡§;Lø6œæ\ Ôǭo®‰Ð‰³ (§(à“ž¶õC舚‹ ³h+`¤oÏÊ2€ Ëùu;@B;Ä" U9 eqÓ®ª îZ®õŽd"ý´…+Bº;TV¼cÂ^4ÔÆœ¢W»‚š¡´b®Lfg‰¢IÆÄV¨.ùÿÕÙ×þÍSM^Û?, £ÅJ„@ß즂ø±;·GÁs¼ŠŒ¬f•€ íÆÿõ=—ªОåµ ,¥D[Zä,mô¬Ô· xšJÓ@ð ÿÉ´¹ ½MÆa¢žc©¸*BàeðyqcK‹ÂÍ÷<™A3ÏäŠC_#]T>æ.¿^›•1¯„íì.|ÆÏ%Rüé¦Ð'êæÆnxÁN.'.U÷g( Ñ ô[1¡aºŒd® Úú΢{Ÿ…æÿã >†}jËʹڴZžªŽ£Ð@À4P,iU;NɈx ]¨ºÞ:¾hÖ+*q˜úlµÜ;#hOÂ/• ¿.‚tÆÌ¼©¾rÆOA§ ¯¨2¦_H¤×RŒ{*Bå¥ õ äA 3¥Ò*éäôú%•VO¤l±—ÑÑÄÌè!à•½ _‘‹´!ÑÝÆÍ¿CµvVÔç/ôIã|ÿ«ÏÍ,‹übw2ù7…Ú;ÃËô°× …½ƒ9† K")%¹ÈáŽæ´‹4IÉO«Ê.ý:øÈ°3ŸI†üzgXÆ¥œ Ѽ±° ø§Œ¿&ÝšŒ[BUÝZ…0}©ïß‚ &ˆ Wú›ýžsø–3(6uÌûó«ÎÉÆMU¹9h!ìS}“_øA’”µÐd¦€4hr™Â2D©‡ícúðœÔÂ罊‡Ãvk-¸cÑE8%Û?œŠûxÉ>§vŸïYL‡Â–ÌQ÷ ]¹%ñ Öýd²¹î&mCðîKѪ ±0¤ê —&ã¾asH¤+=ßçÀ‰Ÿ  é&H¬ Øé—/é8$JOÖ P¸ ‚ç®Ùä"z­çŒ²ý…3°ï€H2d W¢/¸““ž%‰Ôd™µkUcº®aμ•BÍäDçŽ/Ð «ëówØÙ6x£Ot/4îµ`“÷+Âñ´¿_’.nÔ"—ç@5“ØÍð™Ágº˜…K9ìê!¹=]‰*rF¾‰—/ÀŠ›ØR”+‡.!¢ádVñ ðA²ô "#¸YâK¸~Ýä¿)½J€·Ä[¦Zº*Óå¸ÄŒ\uÄHýVÃü,|ùBñtÑ7+÷Ý»—õ1K¯;·ã ¿aí 7, ¹¡ħãù4šz’jD7ÅfR@ÉœÞS1Çß^òbg‰a’-'i+ìnxÚkgÍeî.ÿq³ÓÊŸº©ª<¢$¯oùw§…ÖÕÀf,q6º“+à¼Ç¿ãϨ}Uf„!-ƒÑÈ-R ï§U?ìËéßsÜ”-@=uº’€€Ä{Î>y§±ÍÅ\èlœ(ýôÄg±p}›+ø€0øù5 Ûó·vNܳt@î ¼ŒB… §¦ºò«y½æoHé~×Ño~j¢ Åí®ƒ™ Ê–Kk.š‹–ÛÛ—”nÚ(Cô>hrî¢ <¹*Ô£ªâјh~Õ˜eÿ'‰¨,€2\™Æ¤ÛDÄÔýœÈJq¬üÀ2«8¿"†)ê`Þnï8çÉá0˜Åžö¿ÑÆ‹5µŸú….fã²ÚäYx,ê5º†P¯ýViÿ2^زÚm6e€5½c1táÂ=¶üèkF¹GVñ©÷h³iôô¯$„3$ʳœá[«^з¤|‘.¸ª¹£äóà¦ÝJóÅ:-e-¨Îé  ÒßäÇ£¡í:}±ô¶‘žKßä\×L #\£}Þ²˜\³ÏqÄÞȺöRÖAy¿ÞdƸºm!žyeõæÈþ7Z pìØü —–SêÇ –-âƒ85Oÿ`‰©M¼ÂW¡…Áµ•” ©OuØp\Œ†­ØsZZ8àéö°Ý- Œ6þe¼q¤.†Ú-æ¬,Ïø÷Ñ2ƒˆ]«·ø˜’\$GÅo2Û Gµ$9qDŧt¸V]<Ö­ñÀÓÀ7@´, W…;ÓâÄ÷'þ©·ýÙŒÃ#m†ÉX9d šñ+AC÷Å$¦ê}xû ªhª/4xHÙø›mÝ£êïÆtú˜š$ýìâ5ÂÆâ¥ˆ{bIž†õ¶QÁ_&?›ƒL]S”¿ð¨¾ctÜè õÿ”ȸ¬ç{NÅ=…]žØÔ-Ã2¼œ'\#õáq³t÷L&©ý<ÀÖá°âØ–ºk{Ë>¹ ¦ibkØ +> v,¬j}^æÖ,œÁÞ<±ù{6D"O÷[ìSÀ\k{hŒÐb”80$ÞϽ…“>zT¨¡›Unì"kJÐÝ 9Ttñù(¡J6-õ]YXâýêJç"‘7É>Ø ð Ã%ž½–„‹`‹š˜K°qzÞ,ªuXàJŒÿæ X{ é¤Ð¨)´2É餿"±_à`ºo ãÈÓã•YÇŽ¬Ã]³ký]éÒo93¦Ígf^¿tv…)~¤ à¥Ûé.M™ ì–*¹Rõ؉QQb—®¥þ¶gôAŠ#™vOœm‘‘H©’€€ ‡f\ e£6):ioYõd·bùÂ_'êêÛ÷9®Ú¤Ó³:~¸‰ß ”öÝ=X`Ý#µ;v|—{£ÑUMseéË ÷Ξ¨c? õ…àäEëB”ˆé5!„O—f®Éã¯&Pk}SéÞdwe ˜a,}û^hµ©N|ÿ0TsùÓ„2íw¼ 6’ŸïÖ\Y¨ð;}À*ZïCž¡ØwlïLù(R"Ó†áe*QºÜ¤ºƒðÍ¿˜{åþ—tÉ‘fR)s»gÕÃ_Ýïto{0$úYœ-ˆWÖhؼøf T T“þðžÍANTƒá3¶7øfÊ Þ¾=J¤W;Ý”¬’2u €2Ë,”%TÍ[Fgí)fŠGáì:ér+ÇÁzË6b^ØaÉOñÝKjÌ, F`ý8êàQÑÛ÷¢¢sy¬o0üý‘?UˆËrÚ¸lÖPÛ“9Ž¡ïò—•k@jäÔ HY8–@Q=JØá» Eò±ÑÇ/Ô#ódЭâŽßsÕAÑ9àÂË jw¹¶&ÙñÓ¤ó ¯tÎ)µ@¸q*•¬„Š Aj àÒ¶£¢YÕÔâk\·¯r2 æ?Ú¿mm\Ï¥ÈÈÆÎ_èáBß´hŸ,xh6q¿…îî¸Ñ‹ÿççbãoy F”ÚIÔeOâ|!¹~ÆöµŽî˜sXû ?r½! «ÅGìßB¥G“cs²ßE ¶8{5°Ý]X$‡Õýeçq†36¥þú‘¹T9laž)mJíìåÝ(´_WƒèêÈtX¿¥¡_=ò9½VIZ½œ\hoO`”pHŸ ¸ä;ÁØ4ú€iZ(e(ëãw‘ÊïüÈ"u[Gر!óž/6™úDsr…ó¾#€ÏPÇ;ƒhu6È”è_ßIó+hËy aS €Ä8ôÍÓ¼òÛu%¡}'³$»axA–ÁÞ¥ÌÒŸ¶2˜ B¤%I'S :y©ÖÓ÷L;Hž—çz Ñ`ÏÉÓ‚¯9À^ª¯`W¹Á¸ÝUªÃ|À4lÆ)‰O@³½<[þJîžÞ bÞ+m¿ry>„4øBÄ©ß1ª îù)×ßQ ª î´"êHöýp%pÀÆ?%NF$x„>ÖE¹žõ\E›9nà;Èøv>Ógc’€€ÁÝ}ëœÍz *²æDá'D’o÷ÐØp^ãíUŠÞÖ÷ÔsÓÑ>ïKgt­ñ¶ŸY¯¹*ìzKwñ)qýˆ ÎA.•à³± mêvå3¾lèëNHÈ„Ì'.¸šÚ“WÏÖÞN%Àæ"ø4ˆ÷<&£ðçèuzçÌxÆj üÀîeºK55§}4ð¾á i'8ƒã%Cl €†ôQe*!ëͱþ¶4T“> Oft?;QMF…Þ˜™ÎuàzŽ®sÆZ¹Z1 ”OÀ¬tôþ³­ib«`µG =`PÊ™—¡Tÿø¯‚{fˆµ.UŽïékxäçãþtyƒ9 šÃB Gxï ó3"Y¨M¢üwŒÐ±ëómÃêÇÒwÍ UõPK°ÛÌþAž¦iÍ4¬zù1„éNn šˆײآ„ÉűZ ˆû:I¤8>ž^zc”q={ܾipýÁß[¦#ƒÿ•Š0ƨ-wã¨/7äovËHÈÍ\b.ú´ÙæšXfM7ug\*ùJ£O) )G¡GÍ³ÑØ'8oS{Gà ì` Üü!¶/×çP@ -;3c~ýªÌ( „ø÷Pɯ æ´yÆÍÝ’ª-ïá/DMWéh7ËÞõ(  æP×Á ëx· ™6¹gîXÛy<‚6ðÔņ!cÒÊâëÓ(^q÷¡¹ëPäk¡’<ÂpJ0Ü»iVNÎzTµ ’€€Å!ä…Š•CWÎNÿ# ‰ÂzgÈ$-R¨GœI_*ø²ü_H7Ø-ª§êÿz*#yãÏ7êŠ t|3ˆÆ@òõ˲Õ¡ÿ•96¡öD¹×©öÃXf£ 2ÕË›VÈoäÞ•É@F¢ßn̸™’=/(nU„ûøg(A艣uÄg‚Ä_& T"*5½; @O ŠH0×› °Jž[,ÄI±ï_5µ‡A6rÓ +nYKå/8"ìOVñç»Õ&²_¸q78Ü}2àœø'„jê™å".<||"ë·g½ã“É›~Ûp@#K§tÜS»ˆw9ÊÙGQ Zîžl\:ÃI׉ Ó†°‰_bf§A"¹# =€^+ ºc AÈFèýkÆZ–¢<°ÒšØAYKAv@48—UCzsȲØ"?õŒ::P)¼Äç¯Óøæ„ì`È ø* xÇÊuGž~c(…C·"ä½Ù)T( øx¸~÷pF «ÒãšH†· f6Ð8÷zØ Ê€i\dIÊPäû5uP†ê©Œ‹'p‘f‹ÐBÍt”ãCîƒt'ëãûñ6ðšúc'â–üYdÔ4£?¥ ߊ)}Œ³î0ÐJÕpŒ ´àRÄüˆE$ÝTâŸò¹* ÌS?½áð¥ù¤Q°ú~92=8úqWj¸îÒÙò´Î˜‚|fPºL“UmjÑ‘Êy†P‚Ñ®ìy¬JýÅùØŸp ØaSÑ€ q¿÷b±Pr¤çÊU>ã\>xP¶s¬DKÛÛr4‚ âsZÛîØYp|wÀAY‘X”eÛSÃv#ÊØÛjèWAß\ÈËyˆ^Žg¼Á?eªl»–ÈÛN\ÚOCÅVûÞÞ‰0ègÙbã{Q²ëí¶KÏÐâ1281,pfÔ¨>ßéH;Eâ‹¡ÁÖ9³–¬\s>ÊqCƒ‡Ýd£àW ú¦ŸÓ×× ªC±¥0Çûƒß®ñvØ?,KA|Í©Ît&MöÊZ^òþt:LÆ*ðØ¿M jìØá6lô$AŒ«§T”8Ò%bÉSWÑÚs: íâ@™ylr>Ó»ÑPg‰ç ‚ŒV'm‚¦¿€žûÌ¿zq²Uên:ÐäÕ¤4DµnÁç3RPìéiÒy ôËe¯+’€€­kK•FÊ^ÿ¼­5`¸ÛâhŸ´DqàÓßC£œóñ°^Þãoú•th‰ÓA–¯“‹{l9*õ¥X·3_ …S"  ðâýSG$cµ4—êÑ©àN´A íimˆÕ0“ë¾ì¤[ÙSQu¬þÛg˺”Ås7½yÎ ¯¯šË…ç6T% ËÖ ­›®6×’)¸ 'QìDÑöÁï”ñ­íán2î·-k>©õQŽ\^"wH^88SäŸbGè/Ž˜sSH‘‡Ì5Œï‚úsT—,´ÏEþ´…I‡ib’€Z.·«ß*d늦–ÞŒúId¹l…ÓBȱ ¥ÀF麶Z~u ÆÝº ó o‡Iű &Ê™®©h=‚,ÿPQs„ð×ã¸@˜NkmP@ÓŒ^úäPÇt¸Qùa=³ú1QP»=‡NŠS\W·5GêÝrÛÓ·#gGà‘ \Nû{<’ÁÜ?i+ãÛGD¹F@é8%D«±Ëc‰9²;Ãm‘+%ƒœ¬ ìl³"Ó½r‚ø»’}9Ûçè®zº³¶X=TgŽ™™zÔc?½4)Fñw]¤7"ýÃà 6JwWþ“Þ:&1Ìf¼ø²ÛÏØ% ?@äÿlôJ]ãGôthÿbÇžÞqdö oŠŸ³%þŒ¹_Ñ2뎙×çËçäÜÍ[…˜ï©ÁÊ„!”2ß—²Ô ¿—òN6a"ê·»à`1ëÍæ9º3Løëº³âθnËGNÂo ³óQíp•47¢TÆÚCš‹«ýl8#,åœd"¿ŠÿW}…­]=>®KU€ÞÎÄ‘+{Z-[ kâYÍ j¦U~'å¥3ðÄf%Þ”å+Y6ÅG5‘ÐAâÅ;ô9õ­Ùùö÷Àî÷ØÃÙnœs0+qC¯|V)ôÓ¤2G`öOú»=^.>ñTS6^7Çå¶±89Å+צ­|ܨ@!ÕÏ{u]€ÌZÍÚh¹„ŽæôªÞƃŸ‹¡}œ31Ü•½„$ÃsË€aã_²¯‘WBHΕ—ÀöñH½§ðü–ìL·`…U'nÏÏ*|™^:ȸίO×ú}ßgjq+d·K‡p^}¨hj¹ùðŠ¨¹Ñ7¼kÅ@ŒË–Âû.¹» 9ñæh„t„æ´Š }]‹tNI’€€´9mª@ Ë£äB¬x„Ñ•'{ÛåqãŠG[øè®z]\D|lHjMˤÇŸ¸‡1×§«ý¼JøpèXñŸ/Î_Ææö,Y¡ªì&”’k³"ÅSIyýo&‡ÐkQÞršëë%¿ãÅÆ®Æª}7í9¼ÙÙþ•ŒÚkV…!|)¢‡Šà˜ 7ÊÖízS4'+àaWRù+bH÷nH©äL[”ZK%9Š/´÷™Ì^›¤&öÈg­ÄÍF•.Rv6Ÿ("ãF¢‚{)/žå }½“ؤ¬²*©zÙžW$ò|ûŠì7Âjò§ïyr ‡¥Ã ªîÙ´½+û4dÅcîn‰ó³2}©.³PHý¨Ù @"Ï#ö͘o˜f}”IzþrŸÊw{Ç7= Å*.šYŒyŠõaƘÄ0äúÆ’qƒB/ÚäÝ$Tà—zïéßNûfaN[óSëþ×[Bìu¡ÊXE²]Bž‰Vœ›°—¥wÍ‚÷¥±t»™×“X]XÆHh×1±FŸù$èÿÖµð‰þ¯÷µò þ²›É­v4w^Ò®af©=CV½JV›Yä!‡}²hIB­-Äot¶æ{Öuà!]sb¯ãLr4K„xóÀNÃÛrÌ¿¸CIÏÌ»x›í÷Àß—tŸ{áLNë´ AÒ åbmXy.¦Áïm{Þ›Mé°YGL@TO2ÌôÈIP YâÙkÅ­ú* +ëD¦¤Y=F숑¯^)úrHð^O~Ѐß`2Ÿ¢6~ZxPw‚Û¥KáUÀ}ß–—Ü›ÞY÷ð´ryoñ…f¹Oœ¾yÍH äô×s&ìÜO(Z^î†Y^=Ï•ñÇÀ²å~iõ@IŒu‡Oà êäÛ©…ãF[Ú‰„º |fcí?ÇÏ,fx+ÑBž˜{)MÐ,ô¥‘EïˇO¶Ã^Љ§K|J¥O@Vâk\G ­B; U>»Sø[ùþDeþÝcVÿôw÷aìߎb”6>Ó2…w&l±*'I§“ä;×Jñ¨Èï/hkÒÛÿtâH¯;NÒ¡ž´·&ÚÆýX3ûRpù¹ .]Õ& \mlT…VÛò21FrN@"Vœ·“š—£PQðu7=›þ££¹*‰…láèLmá&7ôè)¤05ô-‡;ÙlÖðÚ‡©à}|6Ý’€€µÁþÄ:Æ' >“@~=ŽëP© Ja´`N××)>G•ƒ|Õ“ˆg/õÍźz5:är·(Ò[½9Ðotn;íÕØ2ÊÃQ'Ë_™eÁ÷886(1ÉÍüsæÆ›R89ku©´Z®´<Ü"R}ìù¥­Æm’Öå6[E•²\j«ýã~ªý~ÿ8ZßÞPÄb‚vQcÍò› eø2ŒÑyT¬°Æ|÷¦½ÒVñÅÄfíú”¦”â¬1å'ÔòÄ IFOÌ,’d {ÅR)Kâ­¯ '#¶#Q~Í*G—fi: ¾ÍÝû÷÷K$» ”O‡¦¶ ·+JÈàN§qÿÇ:Øà½—-lüw(ùXa=4†¨³×©µWø'Wú©;ç+„ÌgK®¨k/þZ sEŽSª™Ìü¤%úèD3b'ð°ÁUÆU‡Qé´9ÈÁÓl:6[’Ä„˜ì«Oƒ‡ÏïCyOÐÙÿU… ”Ò·[@‚Q):„@h—DÎa„ï ýµ[µäx’&¶‰1èŽè‡ÚŸÑ8é]T£VÖU0SG¾´}H”bò@gWïX %¨¾lÒ·Ú!i):kz¨3,ã}€òŽ@è:ØÛ!œñ£AJ¹Ì° ý±• #HoE@xû|‰èS8™ÃÂY‚k$SÓéÏ—Jg÷ºq¨QÃj ®Ë$U‹mºÅ mÒœÉjOû[ÿŸ3å½ìºOQ‘„‘¦ø² üåÊŽ²Ê¼Ê7Ó¼„| Ö¹S@Œ/æØE%S!ƒ*TÆbY& ïÎç]˜q#U€Âtšˆ—ûeNBùùZ˜¥”åôO÷È Jr÷¨ðëÆ¿qjq‘°³™¼ø „®uOPX«q‰Â籆tÜ¢.“/•~$-Ë{,‚^Ì›¼¬7ýœž~ÄÑö·]D—ÉÔ)>µq "¾âÌÜÌ yˆå3àÛØì•~E9 ,ÛûL·æD!­Ñ”“ÎÝ*öÞ¬4aózK•X %£§!E;=w®Šx )=ᚆ&­KÕ†–2xb7_¹Tx…¶É ‚„ÔB.ŸvVgʸBP/§ñÐÿ“KõÉ®N‘•~âo=CûÂ@ cÐð‚ॻ‚µ‰ä·õ‰Li×äZ¹õ„ ·²{WüîÛ)v²Ú‹m @ц”Åc­ïOÔž4T¶ZW7R ›Zf]ÍÖgáDEC¦¿ ð§¢¬°Èò¤(ìÅC5EùƒÆœé÷†¤í4Ú-_'˜Ü”þ9 ˸‰ÿníròvVlv”áSu#±pà‰‡àˆVF~þ+ϼ¦¸¿‰­)‡!lšðt6Šõ³5EƒÇ¯y¤X¦¶!Á—·n®DÓ-Ê‘Ìs}gÏíù„ ´cêHµ¿#lª3–‘àÏ !.þ¯Ã³—ò O..¿DY>Êo’€€³ô&[è5ÈÎl"¯´±×C’`sP^pü„›”v ýT0”K?†ävÖÅ'»*Ê/‰)Ù× €lÒð3„©=?xc÷;±ÿâ30Uõn¸k€Q¢ÕËyóóÏü„ÝÒ#U ¶jUÝÜ­G¤Ó5Ø>uîÃ[ˆžßB›¨³ ¯å3ù£)Ëí åׂÂYfºöÖ¥Ÿ5äº×Xþ°µýÿ[Xe!s æ[¹ÀrTG“Ót&ˆ]/a£6Ô_Â÷§ÙÒë?~—n°k$~å”]eh ÃÉÛž÷&mèö$!N úÆ5Ëh¾vLÞo2êlî‹ÓÄnR1<€=;Œ–WEDñ3ÐÂT<â©bIG¿ 08†É<þNZ¦Õyp¯š•ÀJ“-/Î<÷u¤¹·âäÁW ‰ ißS˜¢WJ2v°#МrÉIðo1Ðï?žw¾úä²I‡*®ØT+1úéì‰ÉS1ÚL|£DHÛ*žø‰ÜE?û׌شÆAÅÖôev|¾J^œWæcÎf'| ö:Y<Í^b#óêôtyP Á‹þÐy©HjxUFé¢îôÄÀ\lìR0,: T8wöz¤j¯U³¶W·š­úâÍÁt]¡U¡äˆ-˜G¿Ç-¶Ã‹ªùä’åóÑb‚À;¸¹P-KKœEdõ7Ií,|9foæ®ÅÔÅÈcÞñù+2:ÆíìAM)øø–kù×Lòô­±‚ OsàB‚–¤ªàÆÔðÔ`U&ݳòkÀQ5ç4!šR^ñˆ,P;? UÇ„bL^©—¶DÀ(ﳦj|n‹¯ cÎóVÃñ–Íû€KÔ[ï¨òÂÓ¾ÞËÔ3÷~ F\(“ê †?ç{Јªµº ͼ[šÉÖ[É×’Û3è›4gyòmcÀg•E& ÈøFÙM#jzíÆÚ]7ˆÈ¾’à×õU˜¦J †DÁn>í§Léf+4<ó’€€ÆÉ¯‚$­m‹~¿…ð;™Bÿ]Ô£´èϬ‘€¬¶DÀóàíoýhîB*ö§ñ4¼ç´P¶¤evñ\ #ëßxÕØ¤|®PSvÖ>¾s°Lúv "ý.îÛšÎ”Éø@ýºŸ8Ä»jçñ?…à¾íp52ú96Ç|~>þý¹vµ=?ýòWÙ-Ã=ïõ}Kâ2#i\º&þãõ»¤Aá꼯&å´x¸Ù£ã_…)¬S¼ÅšËŒ0}0  |ÒX’}Ðð˜RÕ‡²)‚¢2“ºSª˜>1(=3*‚–?ÄÉr–'šÂmû‰ÖÄlSt³„à wï[¼WëÄÇlèÇÏÞ1ò©Rºß‘vyf)Q¥/É7^dé¤ß| fî=]™Vé£8ª,r'ÁËí êÐPÞ,áÖ6<Ô]¶Ë¹|\7â³ZýL.K.“Ë6á7ÅtËï³Nñœ¼7zÇãÑ ‹ãì@óq6uÞC®é§¸cw<'{ŠQ™ûÉï5OË6T¼2Ðâ#ä”>ÄAžºj„éšÓÌëUþv+f$‘.&²Â-(nRØšÞƒ.Ø?×\»«Ö° Ö9Ô >áÜdÞæ‡@¶?ØJ°œŒgæ#\ˆ¯Çv2£„|`¦."‰¿_CGa"¯Ð}Ó÷sÈéûI?½ÇÛŸC„õÏå“89$Ô¤DAÌÔ@2ûÚF“mï½[¥Ütöi݇Äðœ%çA}obH®yô}è+ördú¢Ë¼Êš+¸…ø¤¢B±Qš^Åí½oȌũé1¤0“ÚŒþ^ÕH ²íÇÆàb4dåúBçíל†7¾`{O’€€Ø¬7_W@ÊÂÇ{@–›>$_Ä#ôϨÓ• É'7ȬA>:§g›y¥±  ´ð‘ª\£¶ïy‚û4ú×òëÕLÝ_¢g@dú1Þlùï^ºcRÁ· {d gu› Ã™1z¿©Ð®@ª—~DZìs8lŠÉ–bUs¢|猕»ëÇZ&Ô§¨Bò.«a…¢ë~y%õ[×ÝÙ¢1)Þ/Ó‡×1º*S‹®—.¬t;Bk¡¬ØÊðó­H@A# šTCãÎ0Ž“~ŸÈ3„{ÿá’”>å cmèô§î‘CøyÐg‰]ŠÓS^I®19ûÑ GQ—˜“f°%/Ý5‰l8Ø·ˆfd{«tzz‰ »ãìÏ"‚Ž“9³jç zÀøÆØ\&H€±Ql.^Þû5uî¢Ìgøˆá3—´âÈ:“’„âð-OèÄ%çcOGqª‹´Pd3Ø>z3Vp¥8a’¹Š9Œ LwøÕš©¬-áñèˆÊÄØGè7º^h(÷á^QÒÄ“ó Ô#ögT´ŒmW—WßP ü¶Ži<õàÀ-T€!:’©Ó¾”Mþ]t?šÄìLž:Є¡r‹…¬¤Ûö‘IÒje5;>è\,ýO.D€Œ—Á=!žY‘Ü•¼:|[ÁíÈ!<÷ôqyÓ½V Áæ ·¹•„ Pƒó&øeËW÷/Dß8O\Cݪ‡‹X¥³ÙSLºpþæÛÌ5nøÀ^oöáÏéVêy3íýtˆ$Ý\7³IŠÙ.Š^{Ÿ,tB›m.ðbTÄø„öx9V•b‰Iõµ"ã×é|k ûÄÚ}µç§g*a’Á¡µýä Çíñ ³k®ÊÿfÎl»Š.Ðõõ……M3jÁçH’€€±0‘ zz}—#CHLj·{Ýä7a3Ä0yÙn*{§åäÃá65 •bvdMF¿‰½Ô(øž3‹h ߪeTGp v¸IHÌH–ÙZYA ÊOä>ïkï½hv‰Éåe,Ǩ²}W¹ðÌâî‹ù5R"M1ν´õÓê–GÔ.Ä;¶ãêc\ì†ô¯ª6|"IxƱÉý(X‚_Ú6´D®ãÄʸ#¸ë=\…æe/fCl¤Æ\4äå*ù]âÖí"·¤òZj’Ì g±‚Dð½1愤:¢õ¡A¼ÿ„°á̪…,*¸ 3Xæï Æ‘èfžÓ¼¬[Bˆ²ª¯2 {ÜüTá*•–ëî{*â°ÎÕË€º&ÇáÁÇÆ&¯¡>µ3ÿ3y)މyŒOH/jéâv's—øF}¸¨¶ûŒ8H!ªAî Ã×/™%°dº© ýWƒÍÒ\;M¯Wø¸’2å¥Ý{Äb²Û°ŸË…6ÿ¡©Í´³/n#¨8ßÖs5àɹòú­§%H|—žmϱ-ûP­Ä°_îñ‚|>{=¥#÷í ™ê-NÇ (v?¢®@ÎÙ7¢â#îvga0Yðµ2Æ4¬Ê“t’ˆúƒê½l`ùÖ˜Zu-ªî1˜þôY ÈØÖÓù¹4©øÆ3–Zy~›¿×@`{4iúµ•¡ýõÚcB<`Á4ÂÕçÄgmçñçBâ±wsl=¿Á³ºæ(‡)hM×yºâüÐ7ìáô;Q™¿žx.©:ö¬­±W/§ÌXªªÝe·^‡U`æÈOw G¤wAûaM“TcáŸ8äÚ~·±ÛoQ$bùËZ„~ ¤÷«j$¾-(àGÛ^©Õ  ‰ø¨¡Ïß6ò¸ãçÕ±!v|,­¤âÊ×±ªfÎ2qøÔÚl¾¶÷ ’) ›þ'#ëþCË™)îuÌøÁð?Ì …ÕÏY9® ª—«¶¤Î¬úÂŒ¯°å’%+›"¤y¨†þÝUqÁŸ7úZÈòs¡ãl¢öÍ#z^Ns2ÚêÆ¨J´AŽ9™’€€ÃWò§âÿ;çÄè%¼"¡†ŠZþI¿ƒª;¦$z{èNÁ3í¸­ÉFNl÷p„s¦?£˜{Q±«.š¦@íNmÝ´ÅŠ:RKרЋ†™OÏl»êŠ~e€#"‹`pËäF©ïfaª"ñâd&̧׼Z~ Ú¢Ç_4nVÊþDÔ®ùZÏèݼäÔ†¹Vó ¯UU?MáuE¡à‡Ò ÍL®WøztšT“0Ï4É~ãîv§PzÊk÷·Wʼs ðÌíeÏÅÕ™$Þ…HÖ–€­úb}C%FLfƒ±Úìb‘jBk«w¾'~„Õ Ïõ(Å–"„„ܲi¥Þh:º4ŽI(%ΦWlpø÷­Ìò©vÇÄ\ssñu·«gxü@¿f°••2ì`\D%:ÁB¶( ¶3®‡X]§ð‡Å‡ðR+'51?W¯i„}´lãU0)FUMÙ Çœ³vÃ"¢ ÿ^ZQðÙCί˜ÒérPÕ’›®Ok³Ä,ùžk6ž +Â3îíV#¾·sà¶>š›o0e.ãG]-ëk±·YO²ÌVHä˜=¯@iUà¾Ú-¡ Àø Õ'%bÊ,l—¸•Ê“‡Ï`’9r€7ë×Ä"‰ ˜÷<ÌË  Kìj=ÀšSòd¹ÿj#$eäüÑjdGôn‘Ø‚(äkŽÞŠ Òð¡¥’xÎæ÷ÚÞ)F1Ç¢p˜mîžéQ#dÃ3°._ ]ZÙù²òü_cZË(‰òÁªx„4•ßqÞ‚¸ZŽ2…¥ >ÈïàÁ÷Û5ª|Ù–8$x—eñÇ»“&ÅûØü-¥þ‰Ê=áuH•:Jx„ÅÍ­»Ï|¹ãý-m tGJ­;(æÖ]ÏY‚¾ÕêÑ𻦞W _Ãôæx´Œð´ù]#2Ù¶¡Ñèå~Aê"SŽ)1¥Y²2@9ÌË/Ñ¢Hl§ßfÅàuq³}´£÷Kvl }‚bK¢Ï K3¤h¾píP“µ W^ QœV¤¬ak)ž‡¯ÄØ|'ç…þòÑsÜúy_*¼¹°<“f¨†5hå‚Û¯PQ£îJÞI‹zo ÚÔZ§6Y‰çG¸|³F1ÈQèpèT0àߣ—O8JêJsÅ…ÓãM3"Åôí¸…[­«‚BžŒnÞQ¡­Ú( ÇÅÖH›Œ[qƒLÙÐŒ8†cËÎ3¯ÓWd~ôŒ}X“zçÆ ;`¥$øê&:‹ù™ÃOɘ6LšCqôïNé*šCíÙÖ< ¨ ?G&´-f7$i#g¨NM•€ôˆ4½E/Ð_î,µ¸vµŒDŠú˜ÝôðÏ]Å#Ó@ Zl#x…U=~«’Ìõ£4N›îÇ— ¸iz$þBÝtãûf°q?ƒRe,<î¼.h<šºJœJUòñ¦qâÕoÖÛã¸þ!^ëÆ¾S~û"è¹Ì´xn ›@‡Ç¸‘V5´¥b¯9­s5îöc¸©û`µŠÐ‹ŽÏÅ1·÷0£‡‹27mnAw¤‘ŒR;Ê,©u#usB]Âô8˜ÙÔ šš+\«H±D9¼AÃV ÐNô JW]tJæåK¾šòðiÎwÔx¿µ¥Ö+t¤«¡ [>?æn;Ý‚|±Â&Cv–…Þkb±-´üqÎwsÉ”—.„vtaξ)(hÁôóÑëPωÈ]¼ezaÛÜ-niGÃ>¸Î˜Gûb8Ì} °@w§„Dæ2;Àoòî>pWÿŠw»^Â"¢ BK úñµÎ5öó— ™]¥MÎêÂg@‹×VhðÃ\´ö‹úÒïè_†GV±â‘¯ ¦Ü3ƒxo—¸ÿXþ+b-™â8ìääóM%`÷COQHnÀ” }Ë‘‹†ñp#„Ñ®„SZíõIÕZé¦[ñžlXxÿíû€ƒÇIÒ3@-”®„9¯ˆnl[SÂOáKq‘I¬ÚYIœDPâ§Õ€5Ò‹²ŠMˆÆWRúŒç!üéÄ4H½âD BÏýÆhü1ï]kûå¼.¤Q3–Z¿©;uçGͯ ßYç Ç¸oŸ8Ù>ç¼yҜ͂iØëÊß4µA-NkPju4ÃB:7þ“€9PZþˆ(•zôŒC›òá*î—‰|Ù[gÚi…øEQï‰ îŒZoZ^½íØD ËKíšKÁîMt!lÅÎòW”\~Q©¾¾Í[¿›1ݧŽN®¢~©TOHð Q êïÁ{ôh4`ÿÉ6'R̳P$úÒ[µõ\³4ôå'Â.JsÏÑF=€Q”ņ¦ í7 úAë:e«xŒ( Bûúô0íú¼aYİÅvtoÿåo®«R–á¡ wÇø>@ÆJ¾8}`v†(9õÞÒâ× óÐJm7L-KzûóJ Q› ¶ãw°CB²%`­½»ryfG·a!úÿs¤UC÷V~:Õˆ½Ú!TþobÇÁúÃû_JÆe«…yãðÿäæM‚o KÙNÊ­}"é4¼^„£ŠZè:f>ZÖ±6“úº0\†nȾFúQ‰ õ¤qmRê’AjÃa’-\6¾]0,¡px-®‡RÛYS {i„_7xfû&Ä»2öoLjYùÚüf‚Ø0Y „óĆD»è`‰Ðý. 0wFš ì„.ŸÈ2¬Çž^êĬ•B@*ë†d£eÝÞ’ N}ŸzÓ'tT û…Ú§‚|°Ìƒáßeðnê2u¥ÌmÀî›ÕãÛ/›]qÛ @…àEëÙ¾[ÇÛ¶&±ëYFð¤S¿õ"C/z»ð¡nBh;›¢-G¤ ÿü”鲈Ն~Ë ê”ñ8¶÷[33‚¯ù±T¥÷£7±ü2 …ÍÒŒ» âc²ï.ý}V0‡€S—•ìŒ.¯]9âEQ£ÆÚÙ§šŸú@ƒê$ý¨ªz"`"!2¨\XR\}H²%0{»R«'¹©dm€ëlè=x†Å6Ó,ðP„E ”²\%üQÓ±Âàˆ~Ù”_®‚%„/‹HVö¤¦¦<&”K1•#†—l.ëMjÑqh ¶ò?l¥áãÄ€5ã.€býwï-ä ,Œ÷7&^„aBغ÷Ö{r[ø?ÚúC‘«àXWמ€šífÝ&9à ºUKª좄1AþjÚ±{wAÿÕòÒ4ñXÑkÚ5í#ÿŠÓf§õ[8U9>·¶½‘ÅE˜ê‡`ëË·¨tT)›ÞÓô°‘ë’€€ânŒÝ%˜ÄE²ßDñ¬\“ÑN‰b‹o”½¦\­°þ IÞØ5°+<Ä¢P¯·@È:rô`Fh°bþkD==– :wžcñ0U>LJô½Žüîðâ¨ÙgºÝíÃıù¸­€uûª9=–ãá}3 îØ !HŒ~Élyš†5Z?­Š™PTj0a¶5®Í+M5 ýóÞ6âÖKO>£yôŸ.ί¿ÃáY¬ÑѶ^é§Ó£d–…j±„q¸öCcäh±Þ©H{Ì/¤‹÷GÜT{«÷û¹ž•½Ÿê3íWù»î僛 ¯Ì?>«aYÝŸòˆcw#  äþaÖ|˜çJ=¾€‰¶‚öAºDRˆIq·W‘SÐR|ócyœÊ83¤ua6µ-²è2'<´}bÒÁ<Õü@2‰‰aînÄÓ­\¾p6мï:&«Z¹€QÆ–8“/ Õ.2yçžürNƒDÒÍ3Bî ”/)^\,BZ;HD(º­xë2•0Ÿ R¥´ëç'?ȉ•±:çœàC&j3Æ€©R.ˆS7Â{èá1o§…oç°‡*žÖ°WPÁ^ÿ^é³-èñbÂ1·Üµµö…Ùâü}%*Â7S5cˆ1ÏÇ'„ø‰tú”¼š·Fûw®æd('qâW¶Îò`neÝi㮞 èö^¤˜(Ha˜M5ÐXÀMg|Œ wyRÚƒ97ž§Ú§Vëº6Ïj¾e o/H#|¨èˆãdFu@æNå@3Ä3lÁ…œç<,ÈÅDX]àßpM§å¦ÐQ!²@ ýNËt,~‰\ ¤!¼› d¥Ñþ£ï)ê;x¨ëˆ!ÑBTÅ *––”~šCÄMÍðÆ. N2ûB©Q3BJR"ã®·_Eÿ½‘C·”“|‡Ž*x¬¾Ùdi˜¦Œ¦®1j3íEY§DæJ‡å~Löò‘669c®“Ë6¹ h7D­uÐ\ÈD¿Ö&“·ÄŽªv!„K΂Ԡƒ9›³¹ß5k‚Wl²½ÍuU„â“Ò4uk0Ê)¹a¬˜› ›©jk-äŠCê¾=[ïv­«ar£!>!åÌãm êÌð‹ È×fÆ”‚J&rÙ½ÁnÄ›]¼“TaÌnŠCÒ¯|¨!O¾ÿ†@Ú·ÉçûÄ6¿}ÿÓ’€€ÒZ†£ó¤r((ÞB*{ÆVGË2i2:q¶Òì½Ómñf~šGnèÛ§ï ù7Õµ6eŸî´JþÿD7„€Ý£©I‡g^9<ÁžªÙ¶"¼jÌ]ç†^K9ÜH+ íD’訑TSç-Ûì•r£,†ÜCl_k·‡?%Ò»˜²œÌÇAÐÑ» `ÍæsŸ!å>M¾£6Þý´{½Zݯ8Ô› &Ô½’]Ü2†“©Õ3”åmþ-ñº+OG]ˆùA“Vʪ_:;\“‘øS/É%áuN¾r´º#·Œ´¢Ð[àÍ%• &)œ›B¢Ó¢qpøÒ)É’“E2ݰ,y$„¦ÞQªÉÅÿ\茸'ue6äc)"«ìE‡ëFRoì墈ö GE­>@j"y:óª]Z%ýà×ãVz‚Õã®XñØÚæcËb©®Ê<NÕ©¸Î4 ï³7‹“/Ipå•¿R¾jœêÇ%‰ŸÜÈöfÈz¢{‡Á¸P`ñ -R¥3M9ÃÚÀþYr!§ðɇ: AM¤š G—Ó!Ô 9þÊÃr+¥Õù7)i,‡Ížaä¯41Hj„ “o—ìa<«ª+¤,”~µyF(è–Lävvå87]ªàB= n)¬÷Ôe –÷Vy7~NábÞz$xî*˜gÖ`¸ù“ ¢óFôÔEÁ‹rGà‡î¢ÌÏP¾]N1‚¸qX#»ÇŸc¥U$~`Ü·~¥²«c²>|_#ýˆf@ýø¢±/’€€²35K)á…5þ#Ÿ“éR˜C„d3\ØÎ òä›hþ¶ó0ab·ErSn%cWaBJ3t”ŒNXPœYþ1•^†—šaâc“#ñUÕHõíd¸õ!ø%¢¨8zMÙÃåMz,NŠmÙèÞd(3DÕÞ±}Ù‰}8÷à^^APA›ªI·É¨U—4 ˜:Då´‰ÐxZj*õðyíÛ¢—ÙuL2PS6‰*È÷ö0“!âXV05Iß-5ùE>#Œ2”‘/Â4u1#°fN˜®ì° CYº½žÀ¥kKèû†§ü›Þ|tÂæÈü‹¨ !l;2ÒÊç>bzš‰'ÄÈ×8†Zç*KçËÜßÓ!»Òª[âµøOÆÅ!ý«lñîŠ}i!v| { •‰´-ÖÔý/œ ˆ¤/—Í¡ 3û¬ÄÍ“òÿ¸ùPîËDykfûó c´l‹6Þ–þäÈÚ› Š÷5¶Æ7¥îIØ8éëÖÿ“NϦÄ_0î³cÉy9Úì\?f­;¢‹C?Ë¿­J¬ÃÓÒ©e¼ŸèºÁ µ3ŇÕêG7º³Rßp¡¤­î ¾È°F™Ù+UâMÏä} ¥YäëJíîÓ°þ\G!h{TüE$Q™¨8Õpì¡Ò„ìnv{˜®ØÛˆÐœ1wðw¨´M}[ÓærèB4Ç|ú3»´ÝAò™„2Àz<ÿÊË\¾¥‡\eH½w¬=¬µ¢L窰ffT¼;%µXZï€" õÑÐ )A$òLnÒ\Ô"ÞÄs&ŽÂ|rÓ‘v àÕãÑ™7µMqëUQâ2žÂ©‰Ífyé½>Yi7–(ÁM´ ø—¥lóR¶³¬¸áz¥sq¼Ï‘N{éª=KÜ´×è¡QÍc{Nuqö¿ ç›/;³Ì|õ?ø?}¥õ_×"U›£q×Ì6‘Äá„压 áoxΧ42ÛwúeO^ÿ[aE`,î•yO“Z"Úji¨²•ÃÇô¬pózqŒuD2’€€ÕÀ©…C‹f€D'è=¯G-öLä·¢ö×FLt¾äÐ}’Éb¦–-ª6øy+ÊFÂ.cB[ÚÞ«_"ß>Å´að}~ÓËA걫û¿2ʇR·f<ÃKîø6‘Ûé׳ׯ94œî1åApðtç€a€w¤ý%þU* E¼Ââ[òˆJ;Æ"LzsðÉꛆ&Æ`ckHpŸˆcŽaõ7HaaÝEÉ^±ÖØayÈœ°¬?…ÄGø­ r8s¿Uʪ£7Hœœ°ønŸ;àc/××§ «bƒÞ»¦¾Æ`,½­7OŠ3‰Š{¦«¹nhõxýÈ®c!8Æ;VÅ^¢Ÿä?GÈÊ@4¬b2ÂA }~ Ì¥xªîÚôb]È)ýëÓSOo =GoÙl»‹øþ’¡Ÿÿkbmˆ‚`òÃâèEÏë$ÕLvUË¢$Ñ5‹–™ ãï¦Ðb2×tß5kO‚”q†¯C6Õžú¥–H½\x˜¹ùf¶¸Û4µün\¦Ñ®ƒ›Â4sZzÓ„(QkF÷¶î_ se„5<¥΄£áqúFëŒýÀ–¤ Aeò¸·žJŠki¾`‡‚éÌzŸNùKwu¢³×b}¾…èk:¦ìèJ®<¥\áöYõJ8v‰‚·ˆž$ §îP«¤GÓpi«n—+ˆˆøÑÑsPgbx¬g¹e0-×¥^/IaW¬ÆÖ6“¯{U…eµ]Vn~–}±;LÔLmßPª ºíF82îwS@¨s‰£Åm5°Ë)î£aÉÔÕ1¤õÛW±‚sÉàÝ:)VÌRó:Ö9ƒ/Œ®Òe$†ËØÏsÇXY™ZH®Â$¸õÅ¡K±ìöñ›dº# bÓ¶OñA@; ðJ®¿Nø×˜RaÕÞ`ãWÌ‹­ "éKC¿'n¬[ñì’ÍåÀËκ7–Z¾¯PúfË迆Íþ¤xF>N*Ì¡òøÄM}pâœÉ8¼—„ÌÓ‹ %“… xùŽxJ:YWðª)u«I~]É’€€à‘A„8Œ-mЕ:ïçÛl§¥+¢ÍÄšü:¢*#aÆíù-XÅÈó]®†gæwU ŸÚHòŠ*––}rŽPk>¦'Âv{v êõ¾%ó±Y$`6J€Š?´ït?  C½3íND% ÑEUo6gÔ÷!‰öC½ôÃ8riÑÑazZдß1ª²©$i€¢@2ÒÊËi‚$å °˜‰åˆµžiwÑ⺺žçJȬ‰'åºÕq47Áõ2ÌÞ‡ûLâSw!EЬÅ.ÇTpÞ ¾Þ€çÊécüÄmµåSä=žßC.½"ÏUC‡*å˺ÿ–ü¢LÎk.†Me2usqRþ¦²vXŒÒ›‹¬JB;tj˜sÃäöû!¢J~>y{Ÿ& b0@‡´•šHO•g—ø×eÿé1{«áüW$Öë¼§•i²sD†íØ$šÎa‚¡q§=!‰6v1 Aä+±šå냄í¡¹e…3-Ôë/#‚¸Dcûš1’Ìá+³kÍ܉bj”ÂH.®Ð(”jg0Š‹$Õÿˆdñw;ÝtJ…ù9&N€À©øaÆîÔ²S°P¿.i?¤asââØÌ tQœSîÞ†ÓN¥Â‘+É&æÒ±]Pw“¹êhξ#ÚªTlÍR·<ëlídøØùøbCÒÜì±4j³€|êû/çÎêŸöF.0ûL C¡l›þùýÉ]ä#ë±²»lhpÚ¦'µ–¶¬Ét6†*/ðÐgÝçt  uê+ˆnpÉeÄ`jDî”þ(Áèù=¾%¥Ÿ¿ðtF.­JX‰ß”„$WÑë€ ÂiÙ©¡Œ[,Ü*¸é™8òÑÉñ*¼0©À®è§…V/'­¼Gú°Û6 O·¨-ªñ°DTå¸Pn@hÍŽ0@ ×ÒÂÖ*Yï')Jbzbˆ.ÒÙå”X©U é@ —gÎhƒ 2Sî S˜Ò'ïÁ©ØžâB\ÇæNaŠëF¢«s@!É@È‚œ|œ+½¡Ñ¬”Âù…'º’Y!ÐhÃÑZQ>•’UŽ‘Ñ„:³×_™g$Zé°Õ—^ÕÛÙw_n“§~Ï­ËÍbu¥’€€ÉëêÛñ[òz2ÙsŸ}YÂÀƒé$û¨&" ™QáŒô˜ëi·À¥)°$•ùÖ§­l|¸óÇIÔ¤¤6TçhLúØmö A`0pvbZð¿ªé =qÍMS•£<ÛbŽà-L:ÈÙ Ž`u&N²é—€P¯Ò$í> ð_®à.ËÖœ|±ÿ/ÜX"¸ÔÓËÎÄÊS˜ì(ñY-%¡®}„¿. ØŠ¯&¡“~;ƒøê¾Ü¢Ãk$|„Ÿ{òNQjÚ JæÄz+1+GYÝùÖa-y’¹ozÌHzùYzé•’‹Ó¦wÔa¾Ižo „ô§¼nGWÑ9– ë+ 6Ä)?käPDÀE™ݱ2”¸(žëµàè@3ôwL§¶ž*8å öä¸öïŒL‚Lôoñ-’:"4ÁþJ–Rj“}&+¶¾÷ ò«Ž-€U<áܰ Õ—Uè°™}¦Zæ{Ñ ê¬†~ý=¨J¤/ÏF–h¨ÖÕ %¨U†Q V OWé›Êã ÞÇgjÜEêÙ lœ¬þK˯&¨’ÊÛó·Æè«lÓ‡"ì1Ô¯Ecܬ=”æÃ{â¾ÐãÞMcú [à&Ä÷c²‹)"W@Ô‚"C÷Ì;´Ö¾Å¡5áÞ´»í+T½Ùvû\ì.KÊA5Cù´™î0ºyë›1j[s¥ Àšl(÷ÒlQÏè pϦ"Ô˜‘nj½ÅËëù¡®r£~NI¿2 íe?9Sûè-6h) Z6‹öØwàÜ¿Þð6æ3(’3$ÊXž”·7¨{Ùè½à–óè[uÈ ƒ"n´¸îæÄ¥‡ïºäôW̱g?€ÛfMö3ãKŒ(l/3ãËè¤ùœô¢([@i[Üo±AÖ§¼[$¯Ü€BrZØ­Ý1Îû>Û|SgGÿ>½·QYA¸±Ú­!`{‘)êѪ­LöZ»á>ëÊ.ó îé^&“5§Z–¸`Ê!àB°›}§_82hb?UÙùûàÜ€îÕ·7èç¤c›Ò»*ìÈÞ­w £Ëm]©°c€ÎÞ×Ru i-†o+W-ÖС@¸ÚŽ^!j¶Y( 8n½Ú˜û–߬œpE×åÑã8t%T=C¸2Âý`ig†r]hêH½¥”‚â—‡ܤ“Åû$¯Ã’€€š±(GŽ—EŒ`zT¤…ù¿&…pËÊÄ<ðÀr6*¿-“7/Ó˜[&ꬢorS_kË>H‘.jú/çn”fñ£ îã$ÿ¢€¥ó9L»d0¿®ÁÌpµéË’f—ó±¬ÓXïIPYev K¶?Œ&d1 ÓÚ×h].%?ÄD’d(ßÁNQ;ž¤_¨$àýSškèxþÈhÜ9”s˜gHžÊ™…/'²šSݲ¾ð+:‘[cr,OýÖ”¾•·BÊèN虥†W,vFn´Œcì–¹`ÑðjŒ=T’³ëî¥È´x%¤¨{@ÂÃÿʨ†PB£áзqÐlïÊbÏÐïµn¹ýÐ) eø]Ä#\Ñ2_Rõw"–çµ Ëkä˜ÌG4^<¾™¤³î@I*-£Û`ލä4Ò¤t¬ì-l^ÓN7Ű^€/9šø<ƒró§ Yð’8òÂ@”gù9ç¥ZÃÚû¿ƒf ßBá±cq‚ךºÓ}'y¦äzJ#UNsÀ³þF–’—¹T¯õéº%ëÖ²Ðx™FŸÑ—œìå…MÃ8*=‡y1 L Nïßhü'ß 0Â"¡V‚#Ø3Ø”¡˜÷Éw5ü£ÔÚ¥“Á[&ÑåÕÛ Öº¨’#ûª¥cAŸY"Î?3 Xgh_Ǫ–”‡[ÛÃè:©¥T”Û­öˆÌĺЯjC­¨¨Íªóp“o’¹†Tì}ÌÕÖ²^®;}¯ üº—÷-…4`ñæõ‡»ÐÓヒ?ޏãí©ƒï~XCŒŸ$Ëš¥]Žóeu¥±WÅèÛj<Ö!Àô^ýÇCkOvÅS7s,aÕúƒõ‡óñs{äI͛մçíðQ»çºù(ïxA)â Æ9 Eî®N74¡E‰€ÑQ“àë„Ãï‹—µµr]Ëðöë”±ØÉ]Øî1iJl &(òÝ}òM\A¦Gk%E­†q’~r‡\i± öo*sØ`C®Ò+OÝiHã¶Óû,ÙDåÛß ÿjDeB$„&Úÿv €¡ª;ÜW”êóæ¶ôôë.Ðßàc ¶òn +†#7ndüVÖÕÖ&fæÒb¤€ßBÞ(›Xz³‘Ž/¶¢5GBÞ7¡ÿ]?€ÝDM’€€³£ýPñø¿ü9‘w—cð' óÉZ_C88‘âÏd#(d¦29{uÿ@^•åòá™f 6ëf»žÛ2äÑÛ^a°W¢79æ™(ÅiüùA£n 2–„aCm„YÁ5Õ Yâk$J"+EA ±Ý›SÍy¯X5;TëÄk‹ƒ¬žIàI3šŽ&G<,"ªÎ$¬²ÍøÉ¦£Sç\á*'ä(`Ï!Þ³‹zZ{…d=ü¤yé™1ª¼i>ˆO5´–¶Ž",RÅ\ïÒ¿¶½BÈJúog8¿vô×­îx²wývCFAcqƒT vh*Li©ïFxκtéx‰å$Œ²BAñ’N.A åBTïwÎM0hšÝdzëT¸îªüÄ ˆ¸Œ­žŽ[F Ùñ·üî u*•®7•ß,·Í2ȇ¡~tºŒœëу­ë_Éw;cSÀÃõŠPOp"•õRöOŠþ^‹‘¡ef×ìO‰á#d!î½ã{=[§l0W…™°_\kí©âŠuÙ*ÁM19?Ñ5,¨¼:æ „o9Á†»‘À ;H¢¤ü$ ÉîV¾B“ÛÁFÁæ|,.sÐ:‡jê h- .¢®Ö~Á}žÛõJ|çI{ݦǀÜi¥¶áíGºtUêbÒa=÷7í³ƒC;)Ñf90#¤-,Ãk¡óhg! ¶ÊJhÊ´Wˆ¾'1—ü¯éЃ#Êd˾èrÕ>÷Ž¢/®RQR’¨¸òJÝ»<{%WNüæœCLNÅ·†P4m1.dÀ„¤7p?+˜à“Æýh£”æÙëÊVÁÉHetǘD€€™ Tăb_þö=c‚ƒÅ[²€&€Zݱ— !X~§êŽ´ÿVÅ£dƒ‚2‹'“à ^õ[Î΂ƒK éï5›†¨ðR7Û<ÞLj‚YB‹üG¹'Ž«4Ì¡–ãáßSpÏ ê´țUvç(¿m VRÑûHÒAŸrsk›¢S]úÞ©WóƒÊ­îàìP´9!€  ¿]f´ä¬¢/Gœ÷pá¤æºŽZË5êP—ËQ…Ø,B;A_·©’ °<ßêzßH~ …åå5ú}D/óû¶^yCyŸŒ’€€Ã :!›äYzÖªEåúþ é3ý,îº2òhñ}÷Y(q#þ×EÐsËé_æ•t0¨ŽDÄçoª?”LDáò>ùWå%¸ ÿSíéÍY/”±cd¡×+Ý~0/"•ß,‚ í‰|«Îò¶æ>ƒ‡k>»/3¬Žâ3{h¾‡‚„R Šeh§êlQç9,æ-²}tæ/“€f:m¸/…î$ŽA{tÂhš;Ÿ¶âœ°j—ºp¨lïŠ1c™hÝ:$¤ÿöp [-½„"lÀS¹œe¼¦@†9UuÑø%“CßHýF Î)ñ#KèíMaùl„ ¿Yã¹ B”Äá²®º Ãße7ö5¦çBE¯ñ÷}À«ký’º|L-¡ûûMŒ±•dâìÝ6ÄÙ‘L½‡—]%‘â‚”õÍ@ç{ó DRûjÄ®FoŨœÖ)©@“ξ-ìŠänÃÂ2+RƒwÖÿV½S–¡ã%f–MAû&ÐÍñ½ÝîÜ‹ÝîÝLWæ*}w&,óQkR#Þt$ïø=yBT‚Ê3-„¤ìøå^PÌ‚´äÞuÆ¥7Ò)Bºg+ï˜-ÈÀ4Ñ£I%…Ò‡eMÏ!ì Ûü.KÚUn2Pe× ;ÆÞòžx¦´Þ>2k”Y®x„Œ»úVý~GÝAŸÜɬ‡»d0ŠªrFf$³Ú€n‘É‘¯‹øš÷”Ê›ñ¸ŒñÚ…»tv©žæ“Gý»ç~¥ß9J-{G¢ê»GUx½}È@ðÑo@“§ 8¸a_÷ãû?ä%Ͳ>!ÂüKÑ8¥‚£Å ïºP{Vx¦2ÙÆõžO*!ÎX²XyzÙ•<˜j¹Wi ¶ßE«â|³Ù¡<º{¯à·še –'¯p6ÍG%‹;Â1o|¦xmÇØ•¼vÓ½eÑb»K˜Ú¥Eá´[}b—®…:&6û>Ä‘¡³nþžBÍÚWë8«€73—*õsò\Rœ)l¦¨ŸU Ϋü†Ò‰q•‚8lÓèÍ€æzUwÍê‚ ÙO4“Ì¢<÷¿_uqHçÁ‡EW”Â6dFë†å¶ˆ®)Õ¤Ÿ]oÃL2¬6¤Ã¶áÍÁf½Â7¸S€r뵩ðyA¡xÃSô°pxµY.R±X1…Žï=óÅŒüT¬üñ^n-nWü¶ü]_Sô1öiãP?Áí~ÝÊç;²ÇU‡JIçÎCk°jÑX¨´n¦ÕW±¿†áw¦’!¢¯‹Ã,)n¥¡: ‡p24TkÀ5Þö¤B0d˜[8L,àOîÇ ö\èÅ›ªé55MŽ ü\Dˆœ•ÐC­ïÈ[M eµd>Ÿ"ÚÙúòÉÌñÆôœÙwx–‰Ë!~ªúŽþÅшÒS”â†J¨kæ0©}3ҬǕâ5+úrXZö>'96¸ÅÆãó|À\¡uÈJÃÌ߯C°Nå¼1Ñ)5QÛt‡$ ŸE ]"ž¬õÄѸQâìR³²FžJÌC“‹>´Nß? CadKÏñÏxxÌ“»É&>®v€Ï Ï@ô œ +´«^Éê½øŠmxÚëùŽ WÅ#Q­tÈ祴ì»rœvNx—Nì&á¢äƒÈ¥Pö•Ђä±1µ½BdIðÉ•7ŒžÀ£ÜOHý:ÛêæóŽâ±`xyãÇWÈË¡•·Àѵ6ò8{â ’€€¸H²²#Db’'QØtdÝš~’t?k`‡Cšv†[TòÊ‹;ú_[ J\ ¸[SÝfÇrTs¡ß(( ··u¸½üú¦šhrÓÔŸ+Ûˆµ÷»L:t®;uÉ¡í“Æ¸ëƒ/kx¾ŒßöbÓ5o* !A’w OhlÕ¨ÅðDw%5Ž)Ið2sK{…7üRWq¢Å/¡ _%8Ÿè Žë\†2FÁ˜èÔ1Êdc]¨“郾JœÙÍG )EóauÇhòo©÷Î5E:³u‹Ÿ³eÄ¡\åÑ·”Ax®@°IHg÷¥:Ý}!Áˆ‡pBvÓOþ7u8s;„ áßœY µÓZbQ‡l’våòGi&©¢'xr‚rú•7\[OÔ[),îé6Žós½ Gb®²gòéN’Ä»¿kzæ]¦isÆç’¥‡Ë4œØûÅjô‹{\A,€8pê·ô¨9Щ©aAÇ{—f85¥£¢Ë!ÃáaOø^zš@üBÀZ×4|ôt&‹É¥QªÝÎO¬nq¬›ñH©{D~(hZ:_Ø4Ê€ŠëD21¢í33ö“jîñJìóÁ†°£SÓAª ÉzëOùžU¨G Ù[!}˜¶²†F€W÷Ÿ'X${^%~¤÷rÈ.á¼€;ñ”ŒŸ9ìJØÑ¾ëZþ†"O4%À|¥ò€õ\Á à ˜[‰`È .fótCªKºI‚%#‘-³«¥²É “ëìÞYCOœnšÖªá,mÙÞPþËD|’½¨$¡ÖV„1Ä_ý¯×a6a¹/¹/LD »dÁG3«ˆRäå¾›Qà.ý´ÓsǧgGx•¢@¾„«EÇk<‹3xŽÇÜ3îÄ·)08æ x$cyµ¬­,‹hï@®^ÚćìåH'{åK” 0[JÌ¿ ;IM¹Ì™ˆ™Ü‡œy¶½cžA4ùáú¿~õýH2ƒîc1MŒqkÍŒœëÍQU˜‰±Â9Îà¾TÖyz*êîÞ·¹RM—͸û`-¤î…Aà|d×Ô6éÄ–þ–ùðOnϨ’|ü¹„w§È®Î. \AÆe€{7çøK Kþ݆øàð`it“{ÛÛÚd$!A(¹åÉh…SGWR.$XÎC¡9W4ÖþåßœWzkx1NºÅÜ1­ Xë¨|ȳ:ìdoË1d¤ ƨôsëI%Ë Èxhu ͸)æ7¶jËaˆÉÑ*Ãz]\Xº-lO€/LåœY„o­ï´ì)Ä®ôKÖ.0ûÒÒIGÎ[q?´YVA§»úd«>HYj]»Ì­‰Ï # â‡Ôƒïðͺ‘ŠÏÔªSQ.¸…¹1°‡ÝHÀ¡_£û1/§Ð¥G E3•R£ßÝ5*ñf•~ÿS‚IktÝ/Zø5¨#%ùÇI£ÝE^›fŒµ}Zý\1¥l9ëXÇNNVêÎ Ësa˜¶nÎ7æK'n/*×«í š•f$cÝ4€ë‰Wõ*1 6¿˜lH†5RÒ¶H8†ç ~Mó$3}¡ÈdáSXÖs‡YT„kÇ]¸·@ßÈl{Ór‘ÿiî8+FÆô6}‚*b«Z“6wUy- Êܪó¢b¯nÓsG”çìÏ^ÏêP.Nàâ…Áâéµ²˜fàIÑQ®÷P© ³ÒFd8*[øàÜi!Õ„øéĶdÊmÜÝæƒo©$Šz’€€Ø35H2.:axç¥3åüìV“5ʘ„Ròäœ#Ë쨸4”’Þ™2 ™%©µŠãsïYƒídcQ”¦"Óöx{hˆ¢6ÁkuXи-fm„©ÞÖg1°ùÊ _£{;µWݵÜó(Ê‘¼\ŒÂ¦ ð@?{ÁýÐXH§/™Ä^™ª³bfºpÞzFkEOíp ƒ‰FÌð€ÊÜèß3NC,±žËèM;«ßWîsxÆ•’.:ä¨XÇ £AÎ5‹ž8Û¼p³Y<Š«ÁáçvQîaAϤ\É"X£êêVç =Äaø´Æ)¦>‹k¬uj×nx;·öù‘ÞV]éñîžSn §ßtÍTºù_Òvì Zq¡‹5"7›ß„$Ž7mßOŸº•~P4²3‚-Ô:JŸ’ÄxqÍ~jÈšN*š‹NÉ)¸Î/‚[LeŸ²'ùœ/4ž9eöÀS·âì~D:Èhsòáчªt“?ttè¦Û7]õÑãWåtß²S}‚ÑÅ–.qöv]~åM°‹@¦Za@„œùçPTœø xŒö_¾Gh)qÞÞEu=¿d6&²Nçü~†.ÓëT\3­øÇ£rÓçÏÐÙ»*9¸¼ý…º$hÅÛChéä@¡R7HBßhª,é× K‡å/Eô5Z¿¤ÜÓ|PÞ 8Ñ6 !@œ•Ù¿¢5oïút;53hº‰¸'vàQQX¾ ¯ìu,%_}N “=?œÎXã•Èï ³¯ô鼫ž¯«Š`Xˆ¸"™<ŽžëhõÖº€îðkH£œÈMyM!{þqîBüº®®Ñ¤Ù·Õ⣤ÉRa±›’TpÚó5Þ.5’€€¼ÿÙ~üLݘp; ¤{[øxB²´›»à$ÉŽ¸‹ÕØ\'üO›Z²×=R‘s¼; òò\oq^…²íØ,=…ä·ÒÄ¥4ÔRXy4}^pÈ\Tœ’ËlQ¼æ¡¦]œ3—Z¾*+džeÊjiäÂnPká«\“­0\dáP¹H&o¨‰¶·ÎhÈ›Z§‚g]¡…®j%Ç-V„àC¼”ªùã g—ÿsÑfƒ;±qÆ‹5r¿!Sx!&†Œ‘vê<ŒW`o£@­¦þqé¼Éôæ$ΟÕî«@ð†¦‘µ+#[ŸÖêm ïMìævÛ JQÑ¥LKë‘P@Á6¦€k6>z„™‡Ê'' ÷WŽÀÝÛÄžpéâÌÄ©!ÓeÉã(g§U†ñu_¢âf ¶ôÛw{³‚.žëÇDÎYE;#›uÁ¹À$4þ×ÙºhžS+ÌŠ2](~r£'^`X H†BªÁâ…SúQYz@25,½Ä£o«’"¹OÕ¾|º½Ã©ÿØdÔÅó:›MÃ1 §ì䓃u]‚`›¬Å ‡#„$ŽCß©À¬dß)]˜ÁºõÞ’W^dñ>`3Z½¡;ßÌ©g=·¦çǸÌGþ°åC èÁ+÷3ÿŠPó@(meÍ…ÏÁFA#gþ`Q÷ØÐÌo¦8ž¢Á>™’zöÀ·^þÅ+›:­ǵ±Ô(>êð (tc?Íþ~1×·Ãæ7 {×E“Í;M@1Œê“g”§»Œ¥µÃ ýÞÛ2' Qá^¿=!óN*¬[èÊ.|ÁÀw³¶r}ß‘Í~Ÿ=Õ Á™1ïè%”ì¤ÕÃ7v¥¾hࡾœ!ÓºóWƒ¸(°¼MP1ê‚ÖÏ#ÿýà6MM~œWÚ]nüéXb£Î#z×–¸úLw,u„úMý5£Ó7Évÿ`NV9û´(@\w…$º'u&ü° ¸ÇЕ©vuêN´òi¬óÇJpÈì]OÐÑÊ=N@&c-3ZåR¹$èS'.{.ŠåXTI™œù§  $L`Ìi†S T¹ª‘ÞÏcL ,ó“ý÷©8N‡ 'ËAyù:T§,×ÔçTVUFy4ëžãÛü2Ï ¬.›Vv&Ó“€¼c%´¥QüÙ†‡—šÆÉ+P_è¥ÌeÍf1;‰Ð<¥h“Ÿ ¯† ’ÈÑI.¾!ì¹Ó+›!ý=‚y%Í3;¨N¦l3tþû½œÇXœ›H‡|¤e¿){D_^¥wÕÜQ{´ºËI’¿ôœ½Wü%MdO‡¹#KÊæ!ÂeŒs=H†™p eŽê#Á:ÚÜø˜Hž˜}±áfn÷–â, ë×ÌK05ŒòÁ‡}zGïà—BéD/zÐq´ß®ÜKeå{Ãi­ø‰b?ü»°n uº … O\îUè(Ì:4Lê3‘dp,5J4ZÑ})‘ûHÕ;"ÑR)s<M¸ÂJZƒ$Ø)ç¤eÕbô‰LUR5(îìYÉŠ-D  Gvi‡°û‚¨e¿H’€€š¢¶‡;—øK?ÅQÕ!%¥9my¯h’øÆƒKfŽYFâòÃ]~žTw0´ž°ºövõ0Z~“DdªÜüÍâ&äê¾Ë* å«KPvª÷1ˉj˜ù¥W™hÅC¢fUzúgLsñ°ú‰ËàÁ} À>3Ô麹ëº ÷Z'-¹(ÞF±*TùIïwm˜Äqz7flkÞD¶óâl–Ž0³î4ׯòÐ÷€ö'èkmiŒNœíW©k£:¢ÂªFŸgh‚žw4‡Í©•1@D»ä&Èx¬¼Ù™4ÈÛ,Š/€–ççgUkh™ÐA9CïõUÄ!]¦ÕM½x¬TÉÐ(7I’f ns .#žè½ÊP±ß»M‘…? ð¯8sí¿*\ú°N›Ï…¥˜ñwLÅyš”ÝVÌñ#†’µX-Ä,F2P[Puzryj?|Σ—û%ÝÚ{–òãù¿s¾ )û¨fë¿ê4 ™#*¹‰#Ò çUæAÖWa½K¿Äþyoÿ¾GmÒÌj ¾ Pø=ŠÍÛ8'“öì%g,Á•ÿôwÿþiÏ9s2¬ÉOZG¨¢‹HäfY”ç×Ýv Lö×n\ê7ÚÕlЛYS¿ÂSÿ+¯„U´Í\ßj@pÉër Ã÷/Q ÐÕLnWŽyäÑœÿþ.SäëÈ`‡µõç§¢;äb3¶ë1fzØ÷°‰ìç'ºÒ#ú‰½®ï¶ÄŽ.wÚ'qõðmþ™ këÒ¼W u@Ýè˜> cqò×ç…ÑÃÍ]óq  b~%Ù3p}e¸dÜ (ìÓŠËæÆÓ€,Ø]ˆ_&#ðm:”¾ ¤J$Î/ÅÏõrÄUX£„“¹w¼i2 <ž³šüáÝSä?§îlÿëG[‚0ØÇÉž¢7ªã Àã¡~Ú…îÙÖÇ6>«¥5IR‰$f¹RÚ;»–ñÔx~’– 0¡Ú¼6Úðùì'@`9^ï¾ô,LÐrŠÉ·?ç%bF ?W˜ªÇç×Ô;á¨ÕÑ®µ–ý0–ˆ%,~Ê•ôJ™:o YŠÓ¡bå7h«åedõ„…î ±ô$‰e "ô»3Ÿ+»ù [M4̤¬ÒQ¨ î iÆ4°_z&¹[<2_†ß%ªÉ†«ý`[:¶¡“D®¯û_¾÷›R  ¿Æ©a×ÄÜQÌ”³¨×~<êÃIÿ0×áÏë õ¼MÁ"²¿Gµ`ÀdVÿ”)ÚáäÙôðD½N‡cÊg&B‰çl îEžÞÊC*¦KÌà‚‰¬ ¥ÁÁ‘%óáÚtRQxx%¢K¡" Ö ²ƒ¹§ñª»ÇQkMn?©CãoЬXü&ðG„. rÏ\CPF !Ìc«4û)ÅïO`&ä6VN#Ô5;Ý×k>ÅðqÒ^ä“õåÿqâ%~vZtUwùüç0[0ž ”Ç>S³¬…æw½¤½¡½wh½ÓžS£W ®rwˆ¸|"êèZÊ÷çóIlUÀöΗñ/äÑÀ#»§ü@Òž$øþç.Èôä7èM½Ù(š­uÏP¹!èåL&ö¾Ö¾©ý‚9î̵1—ïÖ_l»”;F·ÊÂrµa?ÿ1pØzBŪqX·éÐØÓl6ÆdjUwº$yy2q-à"Ýœg‡ÄØÄzA vÓ»çœÿjfs âFÚ±3W8ëÔ:¦QÕUåv³çòËX&7 ô˜\„¹’q45£Ìƒö¬&oÙWM*¶E¾È¾ívÝ€üfÆfãôœ52'‘›Wo¼w¿*åF‚S§?9õÛ±z‰0Oþ†w¾P47ÿ…èþ86t§—‘&‰ 2¡JȾ(ïíìÃý†û×€1¹ oñ’¢çWlq˜ÞUéDµ*V  l‹]ÃÃpb¼Ä׉ÝÀR!þ9 “6þz‡áe‚+ AÒrÜwØÒØZÇ +B7Èu5<èÊ}}[ô®óß”œKøuf#æAµ ]dæÖï/¸IH~?Ÿûü抠Ä^®L\»„& .{ø0ø'dkòˆÂÀ‹ÃFï¹À.WU—ºòÎKh#?4W4’€€Ñh´•)¦vî”ôäž6¯Jp–hfß!èøÍ%à‘34Ï…¿Óæo¤‚»Ž¡h·:W:îó©€>,Zÿ™öî9Ä]V!ùnøÍ&Ý(Ê@—á“H“§'ÍNÞ×_²ÿÁ&ö|Ðñ·vÃðŸHñÛþÏU¥DxO‰ÄÚvAoaùËФPÝ· 'wÊ”HÂ{)0ƒt} 8ÏòFØ%érégØ®m$ ‰b› ô„ÙÄÜMõÈOË1Å 5+6†ƒ+¸·ûo#”4Nà Z®ëêh€\…²Üø6ª%€S#¥¢×iÞ÷¹­ïyC °Xê¬ODF8R6,^fD!ÞPlP/”Æ«^í8ô쇎€¶»Ú%½WäôÛ¯>ÝPhòÉè+¡æ‰Ó÷ögfö=?)JÜ…šAða\†¿‹}ÛCM‘ÊïÒ‰ïÂ}(Ú&HÄ(|“vî/÷Žø9XD©º®T¸<ÙuðJàì)Ö'dÆ:Bo 6à}Ü0/å…K{´a¯WЂÒäaTCh&.Åøˆ@Cz ø>Ùe¸ Öµn}Æè¶ î!³I†ÜÍÓîNKçäºîÆí¥¨ÂjÅlkIn—‹|A =ÌMn´¤#²îf±•Õ¤)²‹;FZPé¡&s {‘)îQaVÈ’ ?›öÕý:_²/6õ8EüÐÀbRcHqD„iQµBq×tBKO"ï8§âëŠQò—ö“ìî?)ŵz­;“D¯X +¾åæ,f tBϽ´¨Õ–z”7”e”zOÙ·Öq„„­O^°®¦û0SÇÊ‹YNì@¶ó£]Þ‹²õ²ÎEí»5è Œ?ýØW7Ô ûl%=¯T>½C­ Iû<¼^@xÒ7ƒ…/ƒ!'#z#ãWFkuÏ@ÉF±#§º+Œ·Žîƒe’ª ‰ðSèDìN›ã-Øc¸Ks³h£ÚÍkÃ,JâÑj”{l–{Úc•wTh‘azÚ=e²¼3H«žTlË:\Û—LÓ-Àþ£@á ÓšÒÑà@užJ^,,9d2Ÿ•)ë… KàѸda›àî×°¨x‡Íe”éåš»»‡óý«öU Ü=³ºE}ÑÍiቘîÁÆ_1Íö\H×ÍÉë¡¶¿ /³Huç`–µ‹¨=b‰ÚoŒmyTc¦MÔ£šty ï¦t™uá UbÐ_žóÙxÏ™ßvšúŸ Td€g"1¦‹LºµÌM5µ-—®UÛ -}!—¾n ¬jî°]ä9ö£Š1äËÇ®°íéð øÕï[¾À¸Tý%‚ø³FB‹ÍÀÔÕQè9(öêwÀÏ› všŽ4=ôÓÜÛÝ™­ÈiÆãx»k§´ Éþ©NA¦OáÜO›jàÅ)Ä:/ŒÅŸ©GÔçjC}Ù -%ä-gÈÿ.Y›Ìê™)ê­Î7t…æ§®Ãð}­NQ NaÆì‚kœŠV÷ÁŒx)Šø•ߣšÔÔÚibRÆ‚C!?gÙ¿C»À¯(_±ÅPÆoŠë)Óž—oÈù¤Œ7¼šmnÞ\Iþœ‰M„gØÀ>øk}Š¡¨µÿàQ:Ÿ\ýj1¼•*kQì±Ä9$O;j¤‹o/Ÿ—bóÚjÊðÕmÏ8ºöpsÁ÷4Wè«Ýç.DÔl2¦‰ò|*<`h„@cq†¶1; ­_ŸUôdáDqùŒûFlt]k㤢4²ƒàoúÇ¡­3HàKìÈj¯ãû’½‰”ÑIjæÙÕ}0ÂÈkó­Û„u[œÐpqÅø'Y€À)Gç›ù×ÌzÊÊí„JæAÑéÕpŸ¢~+©&–¦,ÝLô» ‹ã¶Ñ-bÓe¢B˜ô¯¯röîè4ƒê ä3—èhaùLHÍÇט|¿¦ËöMXƒŸ^<Úý÷/À‘f Š¿©ÄË¡‚¬T@‚‚7vÔæR¶à¨éþš>Æ}sD 0[ý'§,J=05Šêècüâ¶H½;õwP·"®î`ýšÓiüÁ ÑYkÓzܺ€—Ü kL€»fNÒv*iŠ!çëIz0Ðxt~iBìÛÃ5Ú3à}ºÐ¤7!o7vÏ#ð»õêînÆbº)³AßâA˜ãÙ:‚šs u#´wv’]w>’€€ÈyV´Œ òܪhuËà§LüEyŒ‹~“³¾kß:)má°8#nà2b_ wjÜ00,í«*wHÖ\Jõ ‘]eA¬%´Ǿ4“Ñÿ•]4ÅréÔEºšŠ¥¥U(™¶tA¦ií]dæx; WE\ x1.Œ”:ÆŠº*ݺ”rï2ÒA쀓TÖ…"/«K­×¼Õc ‡tî{‹']ìÎb`[Ù {7Çù¾À$êµ5É®ÔÊ^›8ÜaÅÉ •x+ö0#±¼ˆ»!ªÊC¼akòp ÀBBÿGµ}€|ô…;I§‰pRêü’_f~/ðsõ…VC”F7O¥|‘c÷™qÕ÷➣ĉ–é@kŽ› ñN=]¦‘ÜÁ!þŠó™Á,îrZ³Íy`½]¥ÙI~Ò1I‡ŠD z±>ú’r=…ÖaôdÜI6ZèÞtŠ9  tòÒ@Pn¼ðÚ<¦îJÙŠ6møÜšÎY6ªnÜ1Ïê߆:wÔÔªù™À-ÓœÂü²f|NN¡‚ÅÏÿÿá0ª¶[‹çÔ7ãÌLHáóBÕ.‡š·zÈÞ¹º7ä²×Î$aN|”ÙŸ^«ë£2q?Äù€tßÓži%—„†¯Òþ¸¦>‚Šlù±ÁBeê#¤}B‡¾î­¯¥ô¼Î ,¸0/Ø.ŠfÂA𪞢š&ØÏ>w¦6ܽ^ N´ÇîM2ÔpOW°ÙÑ„aíV }G³Fåe=yœ3c“fð~ÜÉ«?qK±àhk/Wß; QUæ - ÔϨÑLÇsAüébd¾QŒ­ýó’€€´f"«‚ŒÌ1‡ˆ0ô9É«$ÎgâiÊòÏ¢ðVÓ}Ìk ÆâU#cÍ’íëÆ± ËÀN•¬½ºViÆîµé]Ò¯‰‡>€åU˜ÐF‹G\õ8 Œ€fX³•åqŸ¬”’ŸÌÀ'ð€hxC„xpG„nþÍ`A·5rR|øA¢›?S7 ä€eqŽk˜¢ÑÚæßm¤l×›å¾k ¥ÀðžªPû’>hŸÔ®òèæÓ߉Ϟ ÇBíÜyë뵯´Zcèæ|7ðØ/#ÿ6¼¡a)95×ÈyPqË5­,dm£¦Ølá8W1œD“b9dñ)— yšCó#WFþV0/½%Ÿë;Àxhåˆéó‰¨ZÚ.4phëV"A¬P(L 9ö-çI @?»*Õ„¾8ÊV>Nèl™¾‘ ',´2जk%L}¶úháê9?þkLàô«½"Ù³²ý{zʼPBd¹û›Ð˜îžÈý(à ÿþjtípgì“}“(Ô‡¸Rj®_/I X¹'²§²/±dÅVŒ?ç»L•f¼.OÐŽ Æ¥„;ßLzªºÞ·_ê¾9ô[ ‹v‡Kµ6öö9|²)Í›ÖÞ“zQï‰í›7šúññqLG‚Tî2×â®Ü4%íØÉŽ)ðÖWïLP§e—ÄUÃC=$ñ-p[ÄÙÿšSdVFͬClÙÅ€i…Ryµ (š$\žs.Ñ]ŸƒÚ=­m£È°¨^¦•Û^˜i*Àk¨„’¹øA ßHˆøˆÙ-œ:ÆìfHÃõƒà¥ÂíÜùYŠ5¹¼íÕ™]ïǼñÔ%\Ú!>>º ”Æ$­Ü!UdjÂxËÍtôCñر:¼sLV#úlª¾ùïë#úàúâU+AÞ¦àç²WdÚ»¤–MŒó”›-U8÷3…5³ã_†\; \)šÅsoûÅ6‰] Mu†˜!JVX•„P‡UV¹%%VøéyU»x{ë!lgw§_ÈCikë<§ j¸`¬ÍV*®ÈÉmG¡tžFÍó:¶êžâ°,n³yZë‡Äë£IÓ£·ñ0`W2/*‰K.«lo6„ðFWºžuû¹0O zñ¸Zý½QŒ`ù˜›û~ìJùÊÑɬ½R[½Ei›Y±ëvG û~¨÷ØÙFFøÒ`mÖ+%Q´m™tTá‚ÀΑ^B® €®5ߨsï)i÷/“‹’÷Â(W c{zõÅ&_µßôà v Ê0Åcyjó\#nù¤ ‚¶5‰þ”ßa·ÁÂZöº˜‰Êà þ4×ÔL T@Ù­Õ‰ëvKWvÞãÿ ¿ò„XÜñ@éçKghr¯p¼ªS—àÈ•yï=}T°ŽYºš>s+6ФO«¨za²šÞ$°‘㈻ënEKÌ( {Qÿÿ\’¤†ÇË{Ð)Ã0dã(¯æ „så•§Òh"°†-6 šR;Úàq~3 €q3N]øQ×C`Ò`„È‹¦Œ_˜€§–硤6æÀR äèM9å¯{}„NÜ™“ÕÖʼn ±¨!*I-°ÑliVèbµÆ0Ú’ëVçÅÏÿ Ýû°c}ŸN݇KŒ4˜u4 Þ¤wÜîÔÅLðú’Hrp½P$xG&¾ t´BF¯Œ'fùÿƒ[ÁÙ.uz8nÖ¯¡'QÝ÷wSœÌP¿ž0mä¬ëªRÀûM)pëU™c(ùÀ_BŒPܽtl–YX¿2¡é&#àW-,Œ”óŠ kl&1z°þÜ|ÿøgÓËèN «†· ¾á /ª¬Ý õ«ß1öùõMtÒäóði´twÕôoK¬‹†yYï‹›zÆ™^çrŸ¾‹‡a€Ctzký׺AD! A·X¢¯Ôˆª#ý:.s Þu‚‹Ð´³6õíšüJ_&ÛÉ‘WFê]öŸ>&'nµh<íìàíœÛ™ñIõú Ø5üÏÙCe§Zt¢‘ çÜÔ$4@Žr%T³’»ó"ѧH±F–=â ägˆTA”+(±6ÁÖI¡®,Ð^i@f!ÊðMó3|Ýš¨ '°äe8æ4S®/jÝ ‰ÄœÔ,s+ž *Œ\Úé{:ûÍñ$séc»Cç‚¿„ÔH ftIãFŠ˜„%Jï°8&Ñðj’€€±wRdwtžÉbbøo’Cû–Èvø®´N4¦ÌL^s¨uw¸,&ÿûu”ŒËÁ'Ss'*{õ׬eTOÈâuö^²…ô^ˬ\¸[›2˜JZ7˜7‹#“¬%X¹¿Háÿ‘¾uŠŽcHRö ]iŽ|ëÂÀ¥M®±(Q•IG[~n;è˜í8µ²Š­Ù3œ µÅâ'xЪ7G„È‹¸’mý¼>,â_·óxÜl Þ0‰H ë^vˈ`šœ<³ì8tmN˜›Ùð¿"6¶¿bœíŸ“Ї8,póMˆ®Q]¾ôµsp\ñW™ÅÞÓ'—‹Òl¦Ý½WÆ£[ƒ³"«áC±Ÿ vlPµœ—ûBë=A€´}9OÚ‰æût!E¿ÎˆK²ËAŒ¸A뀳q¾fWí£Dv0{ÄJx™Éïí+0žl&6ºQGÚË®}ðeTp¢DZQ°, i¾Ó*ä×ìkØ}e ÃJ® KX¯K ½Ï•„ óBH™ÿ••^@¼;¨~ã“ê ©ØpÐY„˘ŠÐñ‰ÿ¿A™Ñö]ÆM*o?tþ‡Z# Ô*?ÇÍ·e(“kĵÚÝ8dM4¤³’ó‰(Y¿Èm­×6ªú£oZV©@ðÖyÈL¼g™O6‰îuŽ|ëñJ§d¾ã¦–Äòü~_“™úš ·”ëi ¢pÛo Zë»ë¡„Mã%ÆûP:u|·‘tÃ[X“ ‘5V¬.€§ÀÅøŠxu d¹dÂPìBT<“N2dÍú+ÓƒÅ_¨ùiúùmŠxmßCÒ!Ú„¶ÌuZ›9MçJó·Š\¦ ã¤g,DWÕÓ¤B&íó"• 4UcûƒgEç®´œøñö?±k÷”{qýèÔÑ-¨TJ|ëo£@{lžø®íltêÌô *4¾÷œ«×ôs[¥è Ðk~Ê3ÙpåÝ”Ê>|˜ZGÛ%2D¬ÜЧ…>>ÊùHÕûÄ l’ÆšjSõágïkoÎ>.Æ4ŽvNø³tZæˆã˜-â2׆Y°\pœùÎ`ALà R¦­J9§/y?Ê•^`h]h³ÊÅÆsèIX‹2¬¾§¢ùmõ|Íä$bsvÄ>m@ÔŠêHc9±˜ï¶8ö2í÷ü+JùIJ»ÔÞ×ù= æ°º5ÞX.P­UT5oQóhsEÀKÀ¶•6(ptè›Ì –v;0:h¨ú¼£˜¨yhj‘TFM?çªdK'í~çmU‘7?‘º(Fwè!z&øN¼ ¥BEèŒli1© &¾÷Wy3‚%ƒÇÃj,€oùà°AY…¡Ñ_BÍÕšÚÂSGì1 =A“à“c¤Œ’€€³Œè8Ä‚,º‹uµÓÛ¿»Ý_ýå+„”?½<¥b;ø(¸™‡„ôu•°1—ŸjÐð $XE`‰>±Ø=œVÈŸZ.Œñþ.Ôà*îc_F¬O»ön<¶p8ÑV®‹#ù'Yˆ=Ÿ„sFìJ’ìóIjÏÑÀ²Ø6ý0ÍÜ7€›à÷ÈÄÍ™^Úhkˆ64QsέÞJƺƓ¾kUØýR°Ë²®Þ÷£4B;Êò™)*ð}µ3…Êf‰M´@ˆ½¯Y‡4,7[‘6;ÍË óiÅ0%)úÈdÅ"1c‡”8(ÀØvcï#÷|ŽÀÍGpÊÚR08ˆè—ÛsŽûÛ3³„ãÊm3º2視î}Ð-‘Òlmäõwì/çk …ñYR°-UËgd•W;}kÉ&/š“–'¿¦qù°ÿbS–Š3uÎ’É,“ŽrÊ¢$ß!‚,½§PAH085kw4ÝšlMoË~Ÿô.%ÑÖ˜TÅ® â¤!'‚˜GåÉ{áÉ~ö·€‚`«U„Gþo¯0cƇ:ºŽ=viLªŽAN~ýÏq;ÂŒd`O_[(0~9ˆìår’–Ìnà4Ó12ô[´ç{ÜÚ L÷`²ä]^º¿86dækrª[Eý/¶±mÄR ûïÁZD«tç‘+½þàjhÿUó:«ãŸ%#å%í‚¥y¥tùÕÜ3°ë) XNaFû…Ø6úraµgLo› «Æ¹£¢{È+· ¿G-ö§ø8#é ?0Ò±éÂDpëS8¥ÃÌ\‰œ ÆÜˆ F2 u÷- $н(Šº’¸õYW©'¹B[§Ä}mi+Bˆo…iG™èð+™žDa+â—ܬד’€€¾”½ásÂ$ßKK Ucg]¦ÜŸÁ® .—tµàO¿$tÈX\Z_Ízñ0ÃòP<›³l|éõ¡ÁxËŸæî:„‘”\n\AO&<»FÆgœæÑ!°üÞhСқS¨ýÉÉ/?O`•oYWì¼SXòܵÔ]‹Ñ*úÝ;†DhÅsÒDÑeçgææQs`r¹­˜i˶û‰'uG§M™Ê Úëý•ÆZýÆ­—»–~ëGâÔŠ= užkioè0ïÆŒúàjæ¶™;h§^'&3$Û¾#Ò™ù¢emK‰`]3UÇpt»Q'¥‡N½ZVYµŠ|ò&¦E+ã9®Á'¬iEXX¹ú¯Œ¡Ñ†¿Z·}Þ=%Ô͈³òæ5M–ÖÏ{ B¥9>Ô1?ñv:¸kj„¥ä Úú1»³ ‚hZnËèƒýS¼‹ïŽ#J,zÏF~6T(¯Ë}T/Fµí½Í’¶ßÏkYÒ ëoúíÝ»‚Ö}'¹ÒåQ*Bø÷—³Õ2¾Y¬6oÑW8¨– o?ïºTôÌWé%‘[á%Vi¥EöCVžE"A ÆyÂÉ6m?$ù­w{ÇöšË‰I[šÓ„>îK)j×Çßg ÒÂâUŽÎ[¦ºF·¬Ç OÂqË› ÏfdÚ’UúäÜlDg50“†OáiöæLŽ—Æò2?Z¼ºé¶i|–“C¤6Zâu-ý mØ 4H¾ÐhnâÍ‘­©KR*8õ¸ ŸXô_—εG‘9‘RH L‚»JPH˜ÄsÎöÍRÐ4ÔG­ö!ÆéH(ì|H" Æ–B¦ßYâÊçk ØÒ~žn/Ú\V2%Gb"<7ñn{Ä@{|ãw å®\SæÝBÜì8oâá‘—¥¾r:œ´'Ù×›I÷‰Y¬šÆs4@4 *¦å°E"´ô i« 'M´HóÈì'ð£ÔR»<€ð¨Ö¶ÀÛ|;3ŒfgÒÀè(b´S'ËÌ㯇ê.Ô+tnø‚ ² u8^Ñ…Ì_ô/að§4uŽ{iýß²•®¸“@÷|b@)qTã(¥¬ xÒH¸»£©£ûÒ®¹8¡w錜ÚDy V #ô H!¢@ȧ1fó ¬‰ƒ[þÝÉ;0‘W¡‰ÓøÚ]² ~ˆ*pÀνÊ:’€€¥xÚ¥0cE½-Y÷¸ƒˆ0#F"lFrX?,}WG±zóÓ'|œrÃ=§Z÷@Í3ûìGkVf†Í$ÀjG.Õ†lçŽmÜNðFm ¿3zDžÐàb® G<Íݦ~˜ ü)™•ÒRÀKxù>nÃñÖ¹»ñ?;¡¢$f{\Éo£jöøa4n½ÝëµEÉã+OõdT¿¦|ô¾}cjTÌ.Y{…}Éúò̺RÓDÓ9 üjÄ0 ”"?Ã‹ÔÆÛVÀÚ8µ°Æ=3¯‡¿xÀ†&Œ-}R]Þí!¿$Ë74Ov¶-oyˆè |;´`Ì´´á3vD0‚Á‡pGkë2ÿ(T°l¼pä3ûEýR^ìC«ü@¸/ì6O¶þ’Ù£õ⩱ÿp3 ˜š’ŽÓ]só¿þ:ã!"âÚ¯ýÏEg¯®ñ‡1ì:ŒŽ´A-EšAȈ—§Œ‘Và\&¨s¦ÎíÞ,2×·„0›JNš<;WÙܽ¶3Õ;æŒñC³jïsnÆHV!-æJ3LEƒ„SóÕË~™W_ó:ì”<@ó<è|ó?ÅÚ’[N“lØÈÄ)±+@ê²è QàZб}²-ûÖºD+‘Õ$»°Á­† EʾŽ8fãQÃ.~3ËÓtαÞÀI&ü(†Ý?V£O…EH(õ¡!ÖC´jÈ•HÁa*] ´÷SØ?K ¸Ë´1>I¶ü}R^•¯» 8䪦kçD:é\É=µ¡Q˜/¶ Yr%üQ?¥:5…ÔlKJ…`´~ƒÆ½e’a)m‹…>- µ‰s¶æ>ˆæ_6 {Ó@ÛÍì9Ä ºã¼¢þ)ýýY§m-}I.Yâ³jŸ9_°TÃ>>»2ŸžÇP`5_ñéé°Þ§„‚wDÎèÜ­¥¶ÛSðž@åíØm㣣œFàÔ×XïI—ÃÅVŸXµsólŽÕbË1õ,„P¾%Àõ"„/4úãéeD‰8†qs V@š¹þµ½Ë !%¨çLÊ*@œ (a¤¥}Ë #$¼m&²6Š-áÍC–XÊ\ï8g¸³8/ ¹.<×ôÎzÛ«[fÐf!¤zÁî–.GHžæ^i`€—^‘vî’€€˜Ew{F??¾,cíÙ8Xðí ÚâÓ| ÇßÛn~â-H˜+ÇÇôÁ\ LuJòzÄV&…ôà†&Ù5ÛÙ«ýø˜¿"±(kŽXV²H êq ÿœGÕl;Üü|â>Êô6$‘Ÿ@r}.Fƒ îMWl™©Äƒ¦bLú¦MküUÍ®ñü+»ºÌ‡vÛóL-k ÅÀ¹;ËTÇMÒãs…KS{¤íFp V€E÷”±Î«$«r78 G†TÞ@šÁó°<Øõ-(øRÀò¨{.J·*øTö2³ŠIï8lPå™ A×~R¥µMEíØ ÏæòòXd‘žs@àÕÅuöÍ ñÌ ùp)àÇžGX¬Èưp­ôL³’,2Z»ýô.xp&ŽOª_ò¸qôC?»[ðM»ÒÕÈ i z–Wäðe[úËþ_i«–:× ÊŽ+ž-m˜gµ¿i;w …Åc©ùG¦nv}<à­¡æ‰êKÖG:ÅCÖz[<­E7ȰKfârïÉ%Ž¡!$ÞĘß/‚9Çà¾{«Uý1 ½DŸ¦µz\å¿`nß\ãOÛ÷Þ¥ûÕþÍV?,¼C³ÏïߨjOz/þ¦twd1{…&¹ÕxO(’K[õβæí'†r»%ÔÈ¡k´!~EʇÍÇ F²-ùk¢â G¢:}ÉÛNŠõ=‡¡\çûü¢×ê;:{MÊo—'>òJÈßORÅ:Zù9ƒ‡’à’r/†Fìæ™Í;ÃÿW.¿xw%gœ‡‰?Í ØW¦1-ì–C'¼f2ÿ›ÆJƒ3u— Ýg {Çãœî׈Ú}ÃÕò‰Ùöz`ƒ¥ßØh¼P ñmÐVkÊIŸ”pÇß „cÅ6/!çÊûñM\jõ„œ¿øÅÊ׫Ø]WßjÅ·ä1f4¡ªÞ±Q[Ûÿ´{”R“S?ÄÁ“| WßÀíëˆÙ6-hþZ½Î2=‚¬tœ"à=1™¨Õ¿¯=mèÇV˜Y¯$•»Óˆ^O¶T„Á¶jEŒ!Ág¹©—ˆþšæ!XüQØêâîõ&PÊ"ë³ò6Sc‹W%¨·rOeFK¼hñ²'ñèï̘°gÎta©Ý-zÒ”d•28TJÛ“ùVÙeîÔц«ÔO‹ý]0ìýþ”œœI’€€Åþ϶?k™gé-½ÔÑ»µ ” Ai¡Jèÿ“L–Þù¨ªfÊ bþíe öÊ™³ðŽRìqؘô”²Öv@‚¬]Ä?ñ•±³Ž?í(=”P­ð‘’ií„„]å a,çËDéRl—ÛÙc\<Ö‹ÑhÍö[ÖêèSçp#ÔŠÜHäïf£v M>/ûu¼%qÓ< „ÓrÌY$½³wå)"ç§ý>>!c CÀlX ’³­6>õñdO%È . ±TéD"dÖ ˃àRa¶›b7Ú#Ó!×zä 朡ÚGÜ Ç]„µiªc“˜tcEÓùø,9ò'³G¥ë‰«Bµ ªó/—™-I1–€CjÜZJôÝñ¢£DZi.¹Ÿ‘ cúiJÕKdy`¤4õóm y½RøB€à­ Ï<óqp¿“’Nú)ëÝu¿ýË„°'àâcÇâMÜ¥t|NÄNƒûaŠíhý}–&ܵ9^Ï{"ýÔøô•~‰ïèË­ +ñV¡àá’‚+ľ:Ïòƒ Žˆ:áñÅ)ßÁbi±z<ƒ1ÜJÇ*£·ÂN{”ΫÅâX]€’Ñb]ÜÓÅøúè- îì™3|b¹C¸FÄeÔzgô&ðÈÔÛo˜ÑáÉ#ubOVõµÎíëìWg'—;|\oI…ŸR)HùJJn²QŽSP¬ý¯˜3~±îEé°vg´ƒØä‚…3aX»þúõá¾ï±;žÿŸ¿ñ¾1Ü ¼A«§†A}~#4ÎÈnA!#=õzú`a@ë¤öá¤æ— J `@´Ä˜úŽßIûÎI¹’LÌÓIŒð}…ÕJÿ°ýðSü‹†¹ü1ù~9Z©6‚ù‹"øýAiõftèmXxLÏödRt xN†x¬«¾$ƒc_(m¼*G3‚ÞÔ BAYLÖÀ—r*;kÿ³õ„q÷˜* _èómLõ<æ^¡¡æ”IJG ?È3$eR‰Í;C½i‹{$­íè +¶”;d»ê'Ù©šh“IèÛb4~ˆtÊ1%½Õìbœ™ð;&Û n~⥹Ò"™Oô:’W­6ÜhœLü|¸ÿ"X ‡äEÂP5 0+‘àc¦‡U„×?* “¾GCz"\Ù´‹’€€·’®BSÂŒ‚cóáñ}ô××ÖÊ'£ØNǾZ"9ft"«µõŠèxŽè×RÒI™¡õîOKs÷DtÑŽ”ù°ÑžÄ1uÈÿ#æçà¼V8@ö9,˜-G|6èÓm“Ù5a馘…#˜Ûå–á³`  #·Ø= ð}&XTtf(±'Ã6òA Z'þV9Ùµ>sUlðWÍBÅI~M¤)²™¯Ä¤©!8G[^ t¾ŒÏœ}»…ÇRÓ C7LØtXÇM¦Ø®Æ/´s„H†eüa&Ö¯ 6@ôñ‹s7ä<ÁÔ\ƒ!Gr<0»¡~¹• V¦RWxX¥†°’V#X’yî2_Ü2õt¬Ä4Íl«à«^Œ¦¶ÃEz¸ïŠüÐÏqYÒPž©ðtÄGÖ É©uøpµs"^±wz+]‰~v–ÄÐ’ØиEÀZ¾Ÿ$[çÉÏåîË3ò­}ª¾UGíí­Û¡œØªŠŠ|Û©³ñ4×åô|"pXÐØÚz9½ ±uèÊ:ö[g™,Æ—œY›qûy…{£ä=Î óuʶ6Ý_Â{T&•rOÀ©ªöåÊõïx+×еlY"¥îÚÓŒ¼iÆq>9i•+H˜öQMnŒ ’¿MÅŠÃ×(o•zÄŽ,&ø;*GMϸ%I{Á¶ðÁÙ˜}<â½¥eóf@&&ƒv`€®Eu~s>WÚ¸3\Çuw%ùñí¼½ oÆfš;Öl‘àŸšЇçÚêÙÝõT€¹Ó¯äŠg„]Ò”³.–°ð±“œâ6q6üïc¼b‘CíÕ¨ƒ´‹–žu4jtWo…Žž>æ {ô쳜|¶lkB[ZˇíYÐUL‘Ñ{FG8Ik “ÀeJy;,;5 l — €’€€¤,}6äy¼ËaójŒj.` x?üÍ´½ Ç€ÞrK^?¢%š™F¤i\0(‰m.êäÖÄBžG@b“šŠ¦<à$5N­·IMVžÕ Óþ“Éÿ<·®£LMŸ6×xØ2ÆB—ö¥€l¢«Õ„Ú1Ü!ó~)<é6?#)«;pVžaï§¿e¹wÎ%âÙ~.z9²å¾…‹ Q¸ÌÏ íÐ>q'ŸH{‹Ö£ØE#ÎŒ!þ¢E¬–>ö±Já4xS;"ûȆ”IÑ­Øó ˆ(§ö­UKì UD›ÏÃDý^ NCšÙokp¢y™$LZíÌîeE8Qz®â G>¸e^“nÄ‹™qšÅÎ'%õ0šX©"0@"dk&.Ð'\ÐÙ¬$³R›ü»NÔïóœOÕ¿t^§Ä­âH©ÐC ·{©ÚøoÒDÝw@ÓWæ0*d›gd¥9ÆÞ¾X±¸¼H«¨£{^Í 3IÀ˜ Ù&w«· îh¬Ç6qH©Ð©}…ˆ\YðŸ¿?4ú^@‚ø%KÞàÕ ûÌÁõÏQ§øÍø‰ÿN=G~§S#‰€Û±Ob¯K§fèyŸ?$%¿üJ$ÜX~mŒªø×Ôt™mm€b°ar´>}m€Ç&eß„¹^§;jõ%Çy‡­\-›xû¹Ö†Ê94঄§h¦ˆÛ[µ“迱 Œ³+x ¾Ü~™áþ‡¬¶hó:Jô‰sÔþUeºÿ¼\uxŸQË);uŠþB6Ô­àÛJ„cªV›ÕÑ9¼)`f"R¸ ‹þÌDÅÄ¢B’›OíAÔ„A–½fr€É+J tû€W%Y§==‘…ûîôÃTÚܵ–²„´·ho9šâ©ïÿëÎSc'·c•ü.Ѓ ƒ{¶°Õ-Â0wì.,0À(ŠgY‘¯LO<– VGøºŠ%9Š nA¹y Y»|Óà œÈ³Iî¾Ù˜›ù5äY«jY×Î)åx:„ªSõûÈQÞ}ÿBþzReyN†¹?k¬# ŒºÃ<ü¬K=4vû3Æb‹é,`ÛNÊÕJíÅU×X@s=œ}¨µØãM’xÖÖë=8BÓ¾‘3 »Ó×niz¶Â¸?0M÷Æ´¤WP⢻¨*¸P(Í•_ŸÇ" à¶|/%ˆ­øãT=ÍÖR”0¶áWmÁ–?ÚwÝkƪ¯¼ IÙðB'öh4Ö´¦YþÃùœˆ$Õ²dÍèôÑÛ´+yú+õȳk£Á\ïNDáw×ä\EZu–7F'äËn‚¢Ûʾ!‰@èÄ[j+Û#ëñ'J¾w† ;"¡Á1ë@^Y¯ ¯oÍ`žÈÛé¨.ÀŒ#RGx¬ßÒKúºÓ¦hBu¾§šîÈ‹Í>Ì%û÷¢JD#ͶQ{Z@ðlM.—´Ó›…òôHâ•À–“Óè˜7KÖ¨ÿoŠ- a8›Lñµ–”Ë«PˆÁGX çnX®ö‘î&=´Ã­ö!øxÉ£WŽ*gZ Üó¿{™ƒ=< ë|Ÿag¡•ÂýÇ@öVIeƒÂ8; í.®`ëM3„@=8̶ËñhL?ü›¤²„DÌ=)M×ý&MKÿÊUïq¬ ±á1’€€Õ ­QïMî ´Y)xD9@@™@WÀêY¨AG‚”ir«}iü‰ŠÅYï“§í©«zf²à»¢ŸxZC“ 1–ìHBÛGm>D móÄÅvó.¾&ŒÚž³†:»Sö¥w o–^¼Ûv)a8Íü¾³b)Ò,‰ªÑ]ÏÀßr;[†Î©´¤‚ƇçÀ WHˆk¤ýMÏxìc›ö§7;øvóþý›¤•w ûF˜N@ @Ï»…õlµ?h×ÉŸ¡ʯ˜ª3h®oä+Íx+À(Ó«l–©¹W´ôjàñÇ@@ß‹P¨‚«n3Æ]÷%¿!«#z4è„«k¥ÔÛ·‰<™‰½[p¯`ÑUä~¡b:3HX‰SÁý íÿ‰ƒÅ‰óì‡ÞösˆÎY´Ä /Öå3ÕDuqë”u¢X°D¢:uæ]Ü×!–f»¢Zã.”Uèÿ,o«eëûž}i¸ »×ágg8­ «kZ bc0ÖÀÃ{ ‹[™bxÛÐÕ³CZñ†šõ„Qб¢–qÅÏá•ãO5½¶Ýój>AœëG÷Tæ[ê‰÷Hï™Þ& ê{ĤãÜ*pË^*ž4œ»É¡mš\°ÏûNr»_ú|{iý=Ó@ß¶•é3¤›Ü0:G¼ã÷Ô°É]^=H=–:fZ”…C{K5›âõ¥•-†ý†îsäfwÛ½xJðŒtæ3Tú„› /Œ7IoRO‘©>Úo°æv<†oòPAfà‡ýFÂõ3/UkOíL¢…OÎ3©¯Æ>„—УÕ×]ÃŒF&´n.~á–WZÒ6€UÂz?vÐøcr ^‚£BìuÐÜYôM½«Ö-mhS6’©Å¤‰‡Å&èTè²¶åNŽêä ‹TÛf8à¨1=Ž=hY¢ìU@ÎMåØ;å`IbAG€Ý×а|·€|YRHw~E½s÷)·ž¼ÔÎ{¯Y[–ÃúÅ&Þmز­ÙÓÛI›ŸB#]iÇq)8µ{¯íI–”'& •m¬îrî'y·¿#÷¸ÿ–¿í2b)g,¯žå|½½fàP–DŠu/PïìLý!ÁRºAYu0OÃ%Då*–¥µù"Ùé9Ý3³ç’€€º·[A©^´f¨u›(g«¬ÝZÕû+0tFêÇ8pô „U„Pµ4 ¡£‰âA¯¬h¶Yz±tß~ÒØÏSHŽ‘zš}#Í,á-=(xSH$=d„c•‹ÙUXžœŠˆ])E\d滕9ãx "ÓîêЃõÜòÏwKZÿ8£zÇ-«¹¼•þ; ‚ˆZ~q±V¢Ãz>ì‚–è²$w‘Í·ì°f ÀähèÞ ;—>ÑÎ/6–ËLpï]ûºwØ`íÀâ9£VL5G¥ –à úe"íædîÊ«.ËÃÄ·b{7㣻á.Ë'@ÈÔpl8ðdè(Û)¾+>Kóª\dÂ/âÀ!|bƒ3‡ÓÓ â%°DÂ*/¼%ŒŠ¥#Ôš‹ŒÝJ‹® œ^õtU‹ÖÀkÓNÇ%Ü&ãómÊ´U ðz~uJѬ_*ÓüðÈÆÐ×aó³É€IÏ2j[ª0Wì˜ù˜Û[]*ñu=¦¶,Õ½øA"ƒØ á{°_ù„ ;PVÂåú¶·4T^^gñ•„6`~݇ب‰ª¦VÜD&¥=JsÒï¨+TXÛÉ8’¢ûôosg™y¤/…WMÙP»ûft\= åõ½Ì¦kJ 0÷PEC¹ðÎãy–ŠnÁPÀÂjâ;œLêÖ2=K‰`DYA€#Ðl0ÿ}逰˜ÒîK¡¦g—v\Ö¬Þ‚þ%¦¬0#“çæ×ÖMò-Gç›!I°žâ,“å©‘!‡›ŽÍwë‹•Í úm_ÏãK0_äz«?ªGôÆÊ¦¨MžN²j?ìPЕ' ØqÏ5ýW’<“3€_¶ú _¤œg‹*›Ì´ÌPˆÂPŒu2œWÌ@ÐF(Õ!ûpÜNIÿM®±¯ÊïöÝJ!ƒÅFeÀ¥–Ìɳæ E‰¶ë‚ü£¤3¯>Ðêó®ÑGçÔ³¼\õÎéý¢i¹‰Ç ••i:J³Æ®y³¤ÍâÍ\™¶F,ñïuî¡@+²×eÙ0§º–f+™ç¥ö6ˆ%ˆê\ðxøþJÍŽT)]¤èð‰ 3Nz<–§îsV:h{/Aâæ‘'eTy ãØ;¹¹IpLhê#â>±ý§ÕîTyæþKZùöF(,YSS-qÐ"Îjûàp¢¦:Èå–lÆy@úŽˆ€{­×ùó’€€ÔýÏ?!,mÙõ™÷:xa'•sô9¶Õ!–%L÷˜üÊÜ'Ïèl$§Û>¢ «¸Î;`sÜèÛª¶­œô9PÕø|ÏàüG–JzÝ!e›¨z">•åJU!´P§‘áÜ·~0”ûƒ<.»åô6#âíOMo™u­­'§ú KoU7;¬?R`·% ž±šO†VHÉô•8Åshw‹òƒŽèúñ:ò`1Â}Õ›^£Žw)M¦îÿFmL -ÌW»ýîã<‘ª{ájë5C¬. PC É—cs™7¥0K&_È©õ¸\?º¾Xä:áêpŽŒCáPa;¢] ìÌt ;'ŽåÌj MBlZt[f/æp¤Rcš%~&¦€Ðö!ÈR ±&îÔ¡3×À=ˆ«rûKE\ ™q¨‚jPްбæï¾¸œÍ?Jp)zEñ½œ 8l¬(Nm,q½œžüôAÉiýTvŠz ¥Ks¶PÈk¾$¼÷Côe¬ <íbU¼{Üžòc‚&[g — y×ú\šœµ]Ĉtº;vþXÐ v«i$–áÌÓC²Y™é§¬ ÏP1$ÀS ¹ŽÌb÷ŒÅPJ[L?ÄÍ ·Jß—²Ö=÷À ®´Y¹L{ ›RÀñÏ<48Z¨bÛÝŒÒwê áÿR¼+¸ Ðgò„ NAè´ÓÞôéAMÒ’›’»"ì¹Ä{mæ–{=2°5‡¼íÜYÕs°8@è8zp¹Äà´¿ñ?\­CÇ«eÊ'JÍˎʆKí`§H 1/}&W:ü4Í4't6áb^Tת¼å¥HÏkåÇÕËp_1_Â$ÕŽY¡ÊâXBž€÷B׆sR\‚¡+œÕ¬ÜR¦N!C†7Wc´-r¼à_âÿqž/Ÿàfĵ­1Cçf”€ö}]3™ &s§¡G_w”p¶’§½¼œ;Ú,=Ý‹ô0i¬ÄV8wSƒBt×™ØRmUDIíìêo[°ë_|#§álz~ÎFÓE ä^˶}DeI·?«aÄý­»ï° ¼:7›ç(p{Û ÷ùa*Û4JõSF¹i›ŠÍ2û‡þñ3±kkiýn~Öm^÷«Ha Ñì9¬È°zp$Çô!ŽGÌé ÓVct':9¬†òY¿®À‡C[¹u’€€¼Ÿð4õ‰‘fÿtž^Tw<¬ç1 ú;Tó²[Œô 4&3ÒÉ´ !45†!%V‡s¨p³3‡ `,QI@ÝØÌ¾ô0…†Ž©¹ß®_¦]¤ú©ÿ#ݹCލy-YMq¸ÔC5ž6E꩘ˆévl‹=•â‡J¨OQo vÊ¯Ä ¦ŽÎ¸¡Ž ŸêÓãô©Á¯@ÞžˆÐ,rše—™¡ö?¤âv%<ûãU3Öaz=ˆhd›CÓ»Wm2а{#ƒJeb¹˜ñ›Yqˆeet~µjB±»d͉yh‘8Ãqê·?Ϫ0ÒÜê¤H¢úyyä°êl'ŠÍ`Ë…E²Äß6yæ`½Òžhš‡Ûs‘Óð¡¿ -{ZIï†vê¹ð悎2µÕ®Tj%^0<[¿€}.Õ%/“#¸¥ÒÇ7KïGãoË«Û_æx–¢J÷ðiç{DüÖBÁzW_óií_ØjóKˆù»|fNÅs5¿^;™î† }Á®Nt"n|%iAÝ& ¡ýë© ©;xF¹çà—8½C'…¡ßÆøšm¤­Y~ÝÂûS—Ö§uÓ#0I‹˜òJøˆsh¯A7JZuQé¸iØ«…G›¬§ ÎqǤG¸i/ÕtRl8“é¥íloɤ ûkGóß˹ÁSÉ_¸l:D^¤@8µK`å°…)­Í¸·­OÓ~ßÛ¢uÿЏ#¦€MCÑ¥ÄQ/ þSFñÜhÒ§-GôÍw×Ç‘8ž9ä€5æklµÜ¯Ô°³J ®zªC€Š½£”ª³p"é…šXnvGìq|9xÛX<Ô`ÁwkF½ŽO‚v¿ àßýŽi »¶˜„'kõNCx,²‚[WÎíxœ]p„ÝÊýØyÿ½ÒÜ쟳gÁ}Ž¢Ãc Ð÷a 1‹vê> sa¼¹Gø6 ­©ª2+0¿{Ë` —Z¹§œS®„ve©.ŒxoÍ|7 PL }éHJ§„ük’€€×QüŠ#‡ï~û]ÆêT4#f·äxq"o?£m‰Œ$‹_Šõ¶›Œz¢›Ê@à¹$˜ …?±¿!û±/›(Zb˜À¶ì<§Å˜Ö6ëîÞ†QÕ¸”´Î…àt¬Mí­R3nMÒüša]7ŒÛB¹å’µb÷á@Žžø²`щÕýòâOd‘Q  é<í•ñ..Ì•›º'|¯4ý{ŠÊ.hhÒ]éô1Ÿ˜¿Å¨Æˆ6ÚàDO…GCö5†HšÊ…ö²¬#à ¤U,eÍ û-HF³ °Tœ•‹“WL=Á 78ÇŸ*«Œš òž× Ó§²Je¹¦Fg‰ša/°óàeµ`sŠR{–¤* ï4ëlˆÕ‡|‚EaÍb¦¢‘¶’Ù,[ÅKj¤Ëi«ÄôkTXÙ© ò|—Štß:±”u§DfæL÷pÑ:¨AŒ@¿×ÜÖ¥¨©C䎷³8”-üVÔ‹Ág¿^±N¶Ð®²+àUWHEî¾Ò©£¶-M÷Ôn"œÛµZòé8è¹+as_;h@Õk~†ñ/dGšeÏS€ÜØ“—_LµaŸŸÔH#“3Ê+^ïë&ºY ÞàAdÂr3ίbEå©«JF!Á­e(.àLd4;ˆ¤op2¢bÎÆa÷o€v<¤k¡8ò@ëÁåÚ­²‚Õ¸!ÿ!9M²× _5EøëTÿ^’_fOO€°f±mž2ùâ(Ý|¬=éû n‡€"ÇñIª-ê#ñýŸì½§a£Za4fô'˜«OHn‹œ³­Í¹µkB“ñÃ.PÖ‡°¿»&#»EgÞÅê+G/³ÅËÅ¿¾u g{¥´¼Î‚÷+¤_±?õŸ©£VèE4­8¡ÞŸD]â.qÁ ²úÎÇ ÉöÍ»Þk¨Á3ìö{ Õ‡IìYRQ1«A<¥õcº'é…Òæƒßõ˜*íî{%MºE§Sýÿ»žÕª‰S}¼5¸‡Ø£~‰4*Sªƒ<ék8}yVœ÷º2ÎbFN4Ô„ánÄ„kVCÝbñ“ I¨î£p=ËöòE{¦vPøN6ü¸ðšr¶†rÏ[O†ÐYeפ@þŒp½Ò}aj ¼Ä7‡³®û¯þ}‘³˜Û5A‰’€€Øâï.f—ÃÙãùç–Î>ãa¦úI;.Ä*X… êäd)á÷ÊÍõ®Iô{´@?›C i¿í•ãÚQÖßjŽÍªQw;´ ¥œ¯jt?:6Óf¶Ssȱ(§\: \|oJýâÄ:NŽq])£HIo©:pnâ×—rOs¸ÜD³§Þ†õ„‡­‹šwZÞ¥l±zéÊŒ”W3ÕBûI§Áhb:d{5_@]öö€V¤3ì4[qyu{ΊC<“`5£» )Öû$5çb—šXë09IÅìkY ;_¼lhà+^]}Ã/Y.´r‡'•—‘BŽó”¦NrTèD]é´ZÅï`Åbf`” ƒÅþ{À/M÷- ýíåõžá‡á‚7 ÊG{Ju´–s–[j–yH¼ŸEc*%D€Rk‚„—(¯rÜa²ç^œF…a‹„BŽdY¦“ˆZôU}¥±¼åB Ÿ;ùƒ¿ýB=Ž„%È»xšGŽ:¡“$Æ2#&MvJÍ"ýT9ÈL†ùâÀ,«°Ñ•xË\»fÀL§r ì·™V§Vã DÙ kr&k‹Nh)îSrÑŒÎ^²2æ„ÊA% â}×6 $e´pºO&uð¦T*×úËKòŒ–Ú v;%'q(‚Ä+Ï)ý ´ç æ­þX]§ŽgC=Š[å”I©j·éåÀØËÌÇ%IýŸiÖ{V$Èx€–uZ†¨œ’»†ŒÞ•Ó©Wè:ðÉkVg/‘Q~Rð![–¦£G?AṳXìm¨µÛæA¦ª˜=ÞÎ#Ðbp$€‚ÛDÅ‹*~áT¾l¡Ua×£ª Ú”b.Aª†fYSc t2k+¸¸àËét|a?Ã\R9Í ›Ásgç:ú‰Mk€ ‘[ë`Ë '“=b·zÙv^3ZᣇH?hô¥ ïƒc»iº…jf Å’lböëİfV î’SÍ&£c™ïg[1êdo¸7yë¶ðîFT5³F15?¶,™›M÷¬û)¤V $[ÎÍûóÈÖCÒ!ÏÁt輄ÎÕ‰ޝ¡›Üž½aæŠ Ýú!Ü\>ØÖ|ŠˆÊ˜Ó('LÞ»Õh&ö_˜oW§Y³.ZNrÜàü¦ Ôdª:‡“ýÔÛ‰m^œ–ð ’€€à³ª¿ðké;Ä.S—û[‡BSដxX4VÿChéût¢Ö[ÙöJÔa¬ÝÉFY:ñÀ;þ£°,HŒšåš£ÿ ÀU 9šKqÊ<éŽG~ÿ 2rb%7œLÅŠhN~(xz©8wœ‰ŠúíK€ Èì‘@$ /x‰]ÝYÔŽ Rit¡cçÎtóÅçA÷!ªVž(ô·Ö×Çr•Š¿˜”šÎhj$Æ -ó^q*êáß&¨2ç2ξ›ÚrÆÉ‚Eø©&…îÍ98€.kªäŒµ,èIØfŸªÎ6w K2üLŽž¥3eë^Þù¹X³+îÔU£Y’ÿŸ=bH'µëv×F«QH ¼%^l ”JvÈ=ëøCÞ@qjKSÃsyQáZ·"ÃÒR7³Nöú4~Üí_LjŽ=‰þ…«”;¯Ò&\sluÃ6Ðù‚Ÿ‰î0,‹Ù.mÊP±„þí–©ÒVV“¿c¾³¿úÁ—«Å ¼Y{Þ÷ol-5:ô ƒBpÓ4 0—¶ -D©~$F^ S{ã]_ùùˆꘊ~8áOÒ³[Ñ9.Hzz©ÈÏ“Kv _.“l"F43éùŽž àer)ÌQŠÓÓk´Ý¡Hr:ªD,‡N³oLâ 9ÂåI,VÏ@ Êù?ùù\h‘´’ÇãùâŒ|éÇ¢½Èš¶u(îͯ³uJ:I§õÆ/Àit$øiÓ†mc’ãÏGì]à¦Àtñ@s\Úªë5R~ÃIJ§:O/ÞF1fásGÌôLÉÙ ŒÜÿóÀïìD¹‚vžÞÚ……÷å ð–1™5ª«æ¯/îMÜ= ½Åf“!+Z SO¡£üÖ;eªiplÍåbUs¨É"…¸‰«1Ý‹I)§¶%Ã8f¾Š™ ˜«|X¥ža/üô*i)ñ L‘hî1ªÚgA9»HBÃ*íÓdË2í±‚Ý¬?G²ž T<‰)c;Eè¯ôéÖr÷ñUö:çЂ‡ÖP8 <Ù§~dƒvôä3ñ¥_‹*»ª¼Ýgªô`ÐÕö+¡ࣦi;eYšdˆ -I%sS«@GÁ)Ý ³PkÌÏ—›ÔѪbÜo(ŽzÑ!f´±8À; ÉK ßYJ\Hø ƒ4 …`üœêrf¼JÊ’€€²Ìÿx7„ S@ˆË˜Œ¸äU&W Jÿi´Q~³DsOe`qAÿ›å! å»ïVAˆ6o'#r³Õ†!Ý…¡7WZÖ$¤X)åf¶LÍóÊ»ÓMGÿÄ×’'/”PmÍB­å–¾—b[¤äËÛ÷nÞ8öØ:ë’¡Å­:¸‘,ê—Šz<;«ÒÊv‹®L–YïøåºÂìÉl6¡*Pšc#s“É!ùLù¶M² °hrñ@x\ïd­„ÙËð—-–@mÍ¿ýmrÖ"ug'Ed3Ïù ŸŠ¤©VrQŸs~÷.6ƒr°¦ Ú¼ rüö†Êôz²RTŽüéÏ[Ô'æýËAÀU Åë÷µ˜e6³`WÛx³ø{P§cA0Ó”BÎãllsçåDNUÍ‹"Wåc?ݬ?ÙƒqØÄyïAdAï†3zL?˜sÿû2äÈsŸ VkC’ŒâJFá19ñí–¯ŽÏ £½¡Jnx¯…IŸ‰ Õ;ð冂‡ËÖq—’º&- Ñlþé¦ôÍÕy;ãÀïÂP"u=ÉAØaRÌ^Š%jÆÖö»Ùþ-tˆß£MãU˜Î@‡ƒ™±š´:3ÐtD6¨êèc".éù JUìdÐl3˜QçGíÄÀûà¨@‹†3»tZÿ·&²1¿&:Áãs†qêži3s[¢Wª!¹ÈH˜›;ᆠ,Œ.01=N|´S¹ÈÝ1aê²°”îhLíWzV]ˆò´ÛHGWÖµœ2ßÅ;,7þ6 ó¦ïìë.ŒH…¨ÿI×o€;ßšÚ\Úm3OT6ħˆ …U¡8ØLèuoÉ=:lø\S;*7æ'œ@í‘SÔÒ.Õ×Xš· Ýñ(b(¤qdBí˶j’ê)D%h›ÌJó‹7f 9ˆ)B¶™Œ™<Ë<FÍ¡e’¶* î .Ì…n õaª¡…ƒh/mßÿ¨æ“9ÂÎÿªØÖ¤›mú p Êìx†Õ¿[óDûa,˥ŴÙÄVäHp˜f,—íó¡b÷ÏtnM–øÁp&\ÀB³éÁc3Œq˜‡)•ÜL̬"R‡Ï¹-²þ‰ëµÃJYÕv`6öÃêØí/Nq&üô›#q×Q¶Ÿ &ÆÛb%¤æâ^ö2ªR+ž7k¸Æ’€€Ã”ýR"µøré_g´åžU`bß!QëOº,5èÖÈοâš)ò»I–L·°[Á]a^}Ø“ÿò‚4*f ä9è)À'wÖüË»¬E1i?¢:B¹ÔhßÙˆ«Ò½ÜÈôÏÑ˧øîܽR5VÌQõ‘¯F>ZËqi`éFŒñ›!‘\Ô•xèªÜ|±T,MñKæ«Dyãnò,íGö&¸CªÝÁTñ¾Û-ž»K7å‚.Û]š(A¼z-ÒgÅÙßTSÅåskŠú„…çjlJò1—%‹ý¥/Iƒx.Ÿ~ƒ>v^Æ–k?±‡òÐ72ÂQ‰‰ºÛr7FÅÿïæµ^ Â?ˆ Œ+:O5Î5µYÁ^ÚÇHMH¾4æÎƒ}¿nšìÔÅ¡oåYr˜Æ*ƒ@º^îaæŒ\ZméAŒÉ ŠF¬çFNÈv|¿^™£ÞKÍ„„ e)Ïe›T+ ³‰{òÓ]is웞¥dåžåÁ:­’ËÙ‹§f»"ãÃãY¯•¾áÇž 4­{vìtR¼’ ÁÍ©€G$†€ÀØHQΰLÖõ£A[LS­R®Å  Nï$¾U`=¤¨áäÓžrùùåÀé 2H‚úú¿õ؇P–Ы~ÓÀ»?¿ƒŒm¦ž†ìÆ›Ðyì"ºÎŒ/ï2á\¹+þur«…„£À‰%(5 Kâôr£Ï¼ Ë 1N y´ #`͸?“ °¹>«ý€e ؘÈëÏ0dRg¥E†æ‘æ6aÞvA#.»üpùrÉàu)E7ÁÊC‚Íúå§¢î7·‹\TÔÅáʲSÔÜr•Ë2Wç²îŸBph>#ÞvÀXô7M‘©P¸ídÜ—(ÄF#ªø&Ø;VÞ¨A½Q;Ò¸7Çü={‰ ßóD}d„zÅcÉ ŽýrF ¶ö+&Õ¸éÇ.OYPo¿á W+éMöƒ@ >âô¡ñ* <Ž9^ÈY'»©h_ƒæ 2Ôf^8=MÏjÄ4  %o&·ù€"?û²d]åtí›J,SØ÷ûóÚ²0H”‚òzÝR¨ÄæÃÃ{gðtGôÕdæ©ïrrêª"òNR0iH1ÄëàÔƒµê@·•«È´FU*Žƒ^Ñ’€€¼­Í1È¥)úåzSÂú¢`:.”uIð—O@>Ì8ŽsRRön=²­Ï:òŸÌ,-üò¨á4Íb; IQP¶9[U{ù Ï- ÏÇ\v «ËÓÊ$¯Þ¯Î/@¨PkƒÉº‚-ùù› £Š1!ÜC’SŠ[|ªðä,°Ò“Jèÿ‘™qÐ µCF-!†'ÓÈ+[Ž´âë58XçÏÇ&åK·\~t`b™‰„°²0s¡´ÌÇ´ü4^-ω9ç6Æ ÝmœÌŸÙ¼-t„â‰CIû‚S’y]•œ§3¹tõÇøˆ êEÊJ# „Ä`«†"•W nS]šô½àbnÛ‘&u^€l¥K4<¦o6pžŒf vÚá³ÉÆî}rãV(×áhr©€Kþmú‹êòí±@P¬f×°±üómj¹{Oÿs‡¥Ÿ÷pÇŸèË ‡›]Ïè¦/Ãèt¾èx#EKKÖº.õLÄwdiÅÚ•è7‹A$ ÓKÉåGŒ>bÕŸ(ôÈw».ÃëÊ%Ž@k„à^E<ù$§z¦nŒñݘ+ ­"“Ï&Üé†û^6P:±üýhnÉ!bly„öWùw¡«U9ô•ÕêÝusÔôí—åóá?´TމžXøùÚ÷4‘©ØIî¢HÇO[0pQ³T'¦gSYWye–Š«A•bÀk },!tÛDCEãûÇ4pIÿ'í‹€Ó3*èjNœF1oùÖÊ)7ÛØî©^åw[&0‡Oï;4[ Ã=WÑ>œ‘æÐ‰p—êï©NêÀ{•œu·{C‘Éx(è?£ðâ9:kN€«Ênlaù®¤F¼éºÀo¹Àb:Ðÿ‰rö—9Œö·GºúëgŠÒÊ”’€€Øq@>ô'gŠèKfZfŽsy#ÐÎ’Ï–Ñê,Ÿå)QöF`ÇÅ:³¸ògmÊ/ÔkñÓbÈô¶2xᕬƒzþ#ÃÁÔ¤Uo*4z«ûÕðp¥@±e-µîªAžs|º'ÏØPC\T¾i辎$zÑšânjFœ+åOŸÖ·Å±ƒ¦V’MzFŒfÝ(6dO“Ñ&ÏCìuÏbk·|,…Z9ÄÊÁÓ.@Êlv–Å,öAÒÕÎ+}à,J"öü¤ Йxu´Á–í[›T0Œ¥†C;A´>vwM6Õv¡ÄMª‚ýÞ i‚«a¶Îšèu6?‡K˜2K§Û´®HµÕNv©rcÜ–ä­ÉËé¦xôft˜kÜÃb˜Ôç‚ü왪¹å¦B#9!Ï£ÚƒJRB šOœô–>>tNÖD  jnßø ߣ+zC¤kŠz¥û—ÛÔGlæ[±z R¿ÛÔÔ3qú£×ð€ÍK½øýOð¥;;Ž9µ’ùàºL[1Ü93’ý"â¹µ†äoÙ讦ÙNÀû (/ªE­è¯þü…Bù€K~jT›`âð|(FG⑪»#Wtd’…î/@&› ØMHÐÿ­PÜa‰+Ä´:+Ÿ8 ó%<‰ƒn22èŽÁbz77¹ò!à×úí°h%õB¬5¸XI¹Ü€ÖË`Ù»,¢ãôrSa%tŠ Ù _Q9ð‚˜¢DTçÍØ±þû`¤úàSúÉÕÅõåÜ„þq„ʱ‰7‡\>#:°Þ?š¢ô¸ÈnFÊ !~L}ñ !dKÝÅîÑÆ|·uwJU­(,¤‘9¤s N_¶?ÇáëˆhŸÏ(=*¯Ã_³Q»*°`£ê›HR)9Ðpûª6m¹-eÓ˜#ÓJ»š¤œ–6j`!ʉ~b%l-ƒx÷BŒ>1p8‹}sg4¾„é P¢·>|MÅ`ÀÆÓB¸xé7:Ö”dÛƒ¯\¶ReB–(ÉQî"ikív"~Jˆp·Ü77‰Ÿ˜ݼ?uy¨‡ ”š¨»ØÉ&¯Õ2†/‡^²±æýFD^¢lè]µ2TD$R‹áÙªˆ]ë8y‚NÀ6<ÒÅN rUç?ç:Þ3WýCÏËÓfB‰•c’©ÿÀTÛÀl3ΉæJSžºËp’€€ç:CnŒ=ÙÎ<'Ëù°º9%ÎÎÛƒãB_3¸¦|sñù$’3à¨(gG†~ 'ü£À"6Ç“ófö¥9a GÂÔú˜þáÔ®qB‹–¹>U^ w´¿Ÿ°¨àeäãÉ’š™È¶ñÇù ß'÷Á¥æü¶S^R ×Ù5öCägd$GºR;dÓ¨zw`lŒ¾CVÓ6›a‚|áø ©ð 'káþ ®öOòR[u ¡Sá²ûÓ=¡øD‰ôLfW’5L–Ñ-äÕå".sBŸaœ2kXææ ¸ÑÁ­1FÎxæžâ;ÇÀG%2å监Sû¨5îÙºÁÔëïª0+l´.]äp¡¼PÿXnë`c¹ó¶jº®Gr$,1F(*­ýŠdïèåcÚ‚ÝÓ³Ó%¼];Áo µg¿ú׿2ŽÂ]ÀB[-sà­ -ÌÌØ/”®Ôš˜[4£&¿“8ª™ª|#MqUMù½›TiïȨT=ÙLêÒа34¤í‘T·+Ô«ÅÇ¥jçí¡n—öòOq+(UTþèøŸÒçݳ i.GRY‡’o램óF!ÊÓ­‚í}®÷!³[R¶&»ûØÇì.[¿õ’vµQʾ »TŒ„º¸Þ”WZݸ»RÃ0öæê!Å]7>$;BWºB‹ƒ%»Á<60¯ã#ñ ¦‹ÿ¼,Py|wx6¼òTÒh6/«)ëDe%S*à |’€€ô¯‰æ-íëEc&6i½3:XÂàÄóõ`ñ+æò}  »‹r¹é%»‚hÈ&_æ9æH‚‹.$g¯|&q‹‹‡ù£Ÿ¤{x–Âðà»…[<ö Õûé Ø ~’Îaîå}Ä×ÄÃÃWÒfµÇÝ/ÌΑGÅ >°Aµ Ön”ç""ƒ}eæši1©€Øéí *§DS_+°˜ûÞónÀFIÔûÑÒÌÍ$}ï”·!Ý“÷ŽÐîÂÕ@•R ØÎÏ Ä#n¡üö ›×0¿ÂýJÖ­áÄê(:5Ýv‚©mªd“ÿsn=<%hñªü}ÌÖ¥?°Z©'ÑÚzÄăÈËweºvQ²&¹.búñ ÁÍO]\bYãÖÆ»:*ŵCÐö\kÔrAqÒ©€Ëɾñº½b–Tž¦$$fâצó÷  X‹{4ß7#®Zorõø¦ÇõÆXlv¥d›Ûrô¦ -&Å$É\,ÌÓûá(Ûc;à5!Ôžúß ì¥ÇzŽ£ˆé»¶2iß)óãD©Æðc½1‘¤ý?àî%‰5%ݺÙ3̲6åT²“l‚‡’¿Çwú…GþÍbký³B# æ ‹£lµˆ­Ò¨SÌœäÛV´·‚©Ð6¹ZO¬æ¿;¦ 0w:è•’w¡+Ò¹±oL·ýlàÝM- )}KYê3†|"Y‚¶‹ŸE¡°‡¢Ð {Z÷S¬4` ÉGœ»ù~æŸ_„Q¨•I·ßlÔ³’Eu ¹ZȽ<’€€ÂÝ=ðó«J|%çfÅBFw)t°À8ñVŸÍ¿92ô8îg,áw:~‚ûüir&úÑM‘p²Ôè.CÂØÕçj6`¯t:Âa£eà0 ¹s÷¨—°³Ï¬"A$ŸßçóžÌ§ÙÁÓÀV ‡­3[ºý¥›„Õ<|G ™™<Ë8¥.ºi‘¹Õˆ(MD;xE'ýòòÝ™˜@)Èþ×ÈiábG ÈñÙØš°½£EìùŠeûà™Ë?á†_ú?¥¤aŒ=ëõQÈD{,á–jµ=¢)KÒ:ÝìÝÓÝU5ìÊ'º`:·ûÇËáÆAfÞGN !Ò·}ï2"ÕG8v8'"Ò¯£«Fvš"~EÉ~%¸„åDÙÿ/¼ªgޤ¾ôó“ËŠÈËGi|GÚϨ!ËÈjÞ{ ¼)û&c¡`IåIÞ’èÞ|ŒËÂç56Žè ÚMÊLGº¯œ¯ U´®t;¡ûMSzAÓÊÙB£œz@Ê‚9ôÎPAcåäŠ3ü¶<©`Tï; ø†ç]aø? w3í €WçÀ÷QR°DÀ‡Ù‚–Ã!±£ëÀÅèá¢~àV oÚ+h“¨ÞÌÕÒÊ)£ |{Áúko íúëe5Î`å19Yšl¤Ó·WûÑõr^±W’¸CpºÏwmøkŸÄ«= Öpnv¤n«sÍ¿-ÿ)§ç#/ÐqA­0§ Û ”“øpw° Î(^ôïеíæ*si©¦å>‰¢«€Ò“}›XiéhnUÌf,Ù8z ÈËn ÜÑR gwd (º×žÃeq„÷A¬.†Ò4¬çÛf¹­õ|­tµJí Ãl+ÈÏL[âä¸z5æR‰—j`+A’aÔÂNÎÓÑü˜}êö }œ'—wÓ…_ W<ÐÈ C–×N£Öt=”û¾‚ûÁFP …ØávWc¡Ì¯ô™CgÈI‘¯Fh½ºìà 8+c—˜üißùÿ©2–Q--gCÓ6¯™õ˜Ù¶{!‹¬ÉÀ¤¿<Ó•yZ—=Rê±5Ëå*ÇLÿæQÌž ¾>¥¿O0K]÷ˆ<¶lY-r09Ò±£p±^nX–2zÊœâ3¤Ì]A!M4Ǿñ¯+ªxïÐŒ=ášuÇòÇ»"iïIR,R°Z ³ö~™-ÌÕq²–€’€€Ùâøæg½tY>óºoÁ°¶ØãÐú ëËËç=Þ=3pö¢$á%£W}DÝh—ðð˜ÎëûèrÒ<; kÚµ€äDŽ•+äè¥ÐÊu÷…FHLA~È*:/œOGöúþø‘¹,’Ùh~Ÿâê<ÌýÕ^'œ!UÓÊSI|’I®UÝÜ<ŽSƒüF«,ÿÙËí8\¯è{z^!“›E€~"Z¹Sýy¯^Hl«1×_VfLb;Çe*fHRÓ§ÖËð¹Æñj=@ÁÍéù"Åëxqu¹"Mÿ{òþáVE£Zf‚2Kú!,>ö^#6—t¶y›ylµR.ØŠ]ÕÅŒðW$ú¬oóž“ì8W®.±ë‰Ø…vbUÕ5’}°¤QÎ~,3rÆ*º*ðSª¯^Xã.È ±5›1.Pë`n=N_Á"yiðdøÍ'ZúùÜùʆ6ašQý"õš rÜÿÿPµþ!Й¾Ïì »€Gx6î1?· \Õ¡GDQýÊÈÛ>(}À¿e/óõ‘ÒAYÑþ¥™Wå,6KqÂösÈi–Iß¿üg)å…]gÆÕùª¼ø*êKFŠ^¶¡æ†¸ó5i*W¿˜hSœcŽÙ߸D —$îlÓ,TSE õŒžîR‚8ÑûÀfË~"†º«!+­Un½ÇÃÕI»ÀŠo£Š¸û^ñìæ6ÉÞÍóWWr/Íï•öº§ßOƒä¯âÐ ³¹,ѬaÖ\º‘ ÔDÆ Š5¹~tq¥3nšÂÍ[kL»-GR yɲp^”âá^·ÐÛH¸6û„îcgœ½óܸ„  fŽ Þ H1>@Ü0ÁRaOèî.%Ù­§à»Wñ"•&¸Šü&àB¡‚ìm-ŒT“ú%¿¬÷'æ/q¡rD€Â¹ýî›yí<רdüîËPÆÎ§C |—nº)iÝ»%àÝ a‡ƒ +wLŒ®É’®3aV7¹8-Q·¸ý&—Sl(¬Ñ»qŸ Sû] ò\C™hö-†ªœL»wÔ+=ÝžŠTù§Oê8Ò† µ‹éC´/Æ(ÄMÈ9ÿ‰á84¾j_ÁT'ÇÖžZM±Ü™ùîí7ï^"ÖÒ·îW2zí9l(Ëëx*¢ÐE¼FÊú*ö’€€©„ft¶ÝÊ`¶$´iL,\I¥­%ù{kþ•iy©Ž¾îúE/Ÿµš88Y#Éÿ5¸ãË?tâ•4“߉9—:KD¤íX„tljÖÿ¿‰ òÊ7í"…L´"»·™Éšö·¿À¾Gd(s¤c|Îf IœCñtò.@ÎiHzì^æÑàS™mÆÆ7lmª ÝHøpó7#×ð:!ÿ²»S•xd ©ŸêS´†÷‘±P…:c.4‰)‰δ±Òóù{ýÔoÐT¹ìüdÞ&É?iÄ*·:Ðïã·ÃÅûIã ^xïF$! ˜"¢Ü|IÉA{ùF8TÞ¤ôj·k!ÂM7Üÿñ[áb™'†µ·EfÕö÷׶ξ龓wógéF¶ê@jöÇ—®Ÿý½ßa:rS[†G§ è¥3*ÿAC»ÓÇY~ßÅ•é݈ÀÏ%öqÁcÈWyj¼‚¿{Y¿m Nž‹èS7ú$¶¥.Ýíà‰’‚4×{?œ4¢"äȈmNò(ÜŽmNØáo9 ˆ›¢¯Ú×B•Rá–Óøš j~XÜã7­C*< xF\Þ*A‘éVRÛz<ÄÆq$vϬ;|OîÁl§é½Ãøª±\΂&ÆÈ€œüÕŠIþ…è¥îj,¼ *é_Ü ,ZvÒÙ=,X&•íâ4Ów&ÎE»œŒ°HÞË0 t”SÛØ³_åì‡kiQ\Å 2÷9o'9YPÁÈTáêü¡Ò©~{¯ÂðÓˆ êö•x‡Êekž‘;_—gæ¶^ºn7ˆ¿4ÔãïZ2vÞ¬SrNª¥³Ä¸Õ©SzÛŸM@Lþ‡LÑ”i!­¦\'§ýÒ–£“ ¯-+g¹«fbñûsBsoZ¯ÝØkõÖ‡±ðòžõˆ˜²•¥ >Jsâ¬NÂ&1‘íÖ„á`šÔõ0€"ô‚¡&qb'àx%ü®¿PˆïY-êFI±!Iïr¢uDJ|’ÏL2â[eÛ·z‹Å»”+sOÚŒIx’@Õ€Jª],)– þœÐ „Ÿ*͇þétýMpÒ‚rjä[Т¬\FuÝшy`õü7¾·šâÞ¶ ;þÕ¡·ÊÒFM.¸ÉñC†±ê›`0Yôx¤ˆ £ÑT’€€ËPçWQCY´6Ÿ ÂÞ— .Þɾ1kr-O8¨èE»‚®ÙB@TL”¾.Cg…•Þc¨ +è˜ÑUD]¿å.$ý ÁɰLÛ²¶°ãI‡³t=M,é ÈßOÙðÆ^±ñÀ|ÈzÞï!·„¡ZT"d̳iËéAëÇÑn¶¿‹¤”›]f-¯ÓÌUOMú™Ì™ÑöÁTU•Ö­w<‰kÇë%|ºÕùŨ¼rK;J“L0÷}[?}A‘a9DW¾¥_ª'èPE[uBÅœõÒ¢‘ÎÇv~ÉÇÒK /¿|rÁÜtޱZ¢“ &¼qþ5JìËíyžP퉒€€À·PœæéÛÒæ•¿ùÂé„Àÿ½x¶—^lÆûs(\<þ±€û¨Ñ$ƒBòJþåîá«ï[W0ˆœ%½Ž\o ÊûCâ$ò¦Mî—Òsé‚:«c:jÈÎ?ƒŠûcBP¹(è€`ÿþúé¨C%À­ÑžõÏB¤*¹°º5ª8÷¬Ýj,÷õõo ¬H¡â˜ÎÚ^ŠM:ƒwz%ä§ÑI“k_¾ÜD 2o›ý´u5ìœ#7(CáÈ—˜¯û%TÖGòîM4qzr^$çÓâØNôQœ¨1HÞùs Š’3ŠèåLQ± ½z¿äºÅÆ_Èò…lËßþGÿ˜/+§NþãëåÏSžšq‹VR;¿YNzêû¤®-Â|O—&§›‡Ó°B„¤b1ÝZí)bLxjB"gª„¡»«´Ÿ~_â8‡%“ç‚(ÑY*šr4æÙú³-3Þ&eð´zyiÁœ ´SÒr£|5Ê⑦¢­\|Læ­±‚B‹yy"lL"%…ÔŠ…I…ójª‘¡®³kä4>d¾ŒÖÑŽS9öco Jý*ïlF è㱕Ù F°µªY²¶Îõ‡ÁîÍÁÓãŠE#cšâß%ãaÚÛÝE¦¬@½%—àÚv”†Ñ£aWÇQ½›æw’ÁßÕ"†Á,ˆþ 1›Iä'kŽqgӎƳ æ–†(¶Ywyòäz"}¤Šn¢Ëó'g‚ bTÂýÝ6|_Ta‹ŒŽ®©’k½d ˆ/@ßwów.³|ð•£ç§·(óÙÖ‘3Ó57jX.¯MË{¤ùÆâh²P¿­YÜiw[ôá×5ôÔÌD¯ÜqÖy-Î¥ˆ<º×Óç§RŠ¢_àÂSœUDvô‚œ¢`Ñ{®NÉž…líò÷«vñ¤*Q®¢ªd· $ozÅö#ˆ¼ÀŽhjVIÃl*  {Œ­Oîà,"W9mî+XR/­¥MZø‘ŸtŸ£ ZÂÔ#O¾+ë2ÞeΆ¹j¥èÆøjø>}ÑbàÙÇ k‰×®¸« 8(¦—ÄœWh:î'’³[Æ\9a`FÁrÒ’…`€Ú\Ê€ÂÊݸv²y2 r§0:MϙᎠ»IÛ/ Ã-gäEK^>$HÐt 2ÀI»V’€€ÁÝŒÔJîþáè ¨~ OÞ,‡‰¿^ò‡W…,ÚúƒOôÂ…“Èœî Ï2?Gi§ %måtF¶ MƒB»ÊèÈzKp*Þ©æ K1DN!5»PdpG3Àõ|ü%ú–èn¤Uvp.¸ERà†c-í€×µÔˆÑÌöÕMXŽpÄêzK}d-6å“Cî t“!Çá-aTyb‡)Žü.Ï2jQ±,&2ü¶ÆŸïõÓƒ4<ÈÇ—&ŵS|a\›ýQë<…½’§ÆoOܵ–íRèŽRôcêÀ¢p¡«¸èMÇÙ²·n„?p #Îsºr1(»ÿµ»®‘`Þ«êBm©40f§¶ùi³yˆÉæœ3öfJ$ðg(ꇎ0²bâTÖBaxq‡ ~qÇ)z‹1×ÇÍ7€—5´Z5aÀA}¸p‡„F‹œF¶R€îš­èÞŽãõÓí×Å´oé2_@Õ‡¼ÿÞ€½›`%O ‹¬Ä¼ƒJ04@Lœ¡ê)MoOr;]á$ðA´^ô`5•»žqoI)î…jŽ9Ä·äß|³³¿^ 06 “† aØ'¯Â‚Ú0¥¦9AHØd:Ið'ýYJh`€»ƒ rÒÞW¶ŒçŽ>\îpþðçweÉEXfÎj`4Ïñ,Ý…Ë62H½m¿]á 8ÿþÿîS©÷z¼D‚÷B]Vëg™[@28^B-@ês<’lB‚ˆbœ• œQÇšüÖi.!«ö©#Ïe„nÀ¾öÍq’ºðh iC»Æ°ÃÅLZxM9‚QýM©ÇKJzÁç˪ÎNBóáO ¹§2 Oª„l‘_Ôœø¯$NvL“ÇÑÂEÎn¤W/”´ëQZ‘©Á#yAÁt§º3w§Ð‰ry˜B|UÑ€”H&”¾S’ @›ô”ŸGÎ&(,@¬‡ÔŒ†p\—¼¶gðÖ¹Ýp èaM¢r¶zЄBÙ“ÁÏ÷"dn¿èR ¾ˆ=,{¾¯ïœësœ¼q7ï#/†f¨y#À´##1‘åáŽwϳò@x¦š,ŒŽäPbÓÈ)–6acÓ"W(lˆ'*7X¦‰òÇ]'`ôMLÆ15nŤX½«ew;û5³Ýžêö'Ê”x†‘ ÿŒ0LXzÓz­rµ>MÕ‹ÐE‹qÂFû©Y„` v’ÄÛšý&žµàÛH×7¿j»Æ5c`uI,šâƒOÃf 0»ˆ*9¸¶ÛèL¹ÖËÝàÇ–©‡‡XÄÜÀroÄj—͵,0Á„3œ— 8M›ÞJ†0Ý&¶­šò¡»8A6ØD?'±}Œ*–Ú,:X"XfèÖ7¦+ο|öGÜàk!˜ëo3Pîi’kƤ¦)Çìq§8Û¼Ap(ª|ùÌåÒÚùõ¿‡çöŸY)×ÂÂä3­õÖm‡Û>—$ÆÌÞ¸]™éu6¨å±EÌX—1²AìÙ§]bÊ•¯Ü«k–ªÁ‘a»¶*”¿1¢9AÌvÞŽvâH<Ø´l¸}køžÓïe>¦HÞ»½cHä8Øè@k<𬂠ú’€€Å¶êüŠy‚Úaœv(Ñ¡\}À.<¹/ ƒhJ×ßÀ›KQûofån Ïî. ÆÉi–õ_õQ¦©“Å9ÖŸ—õ{ YëRno}ÕåšÂýv rG¢ÛÇ_ÖÍæÂ¨Øxd4­!ºÔ¼­H;;;7íTr.ÀW-B”•DUe ›ø}CžH! ¢gÌV©DmøWÞfÕ[+[ÒÄ4᪚ÜÍ *³Ò—…01ùøóþÊî5Ê“”|¦ä½ll“„ñ,ÒmÁ NYcŸÚsà!€ÊÞ’EÆ+ÕsÇRŠrƒSS:>øÁŽÀ´0"¿èZYŒX¬“×|‘×/):i…u/Oë9:S+ù^åˆÙôgÛÜYQḚ́¬e(Ò ´™þ3³¨uyá’%é­N4½ÏŸ~ ±N’Ò ¶»½Qª·>·»ºÌû¿#…(¯4§“`ÔËd!È!Õ¨çÒ@lX?[?ax ÛÞrW-¼þ6º–j”¾,WoU6Ɔ¤ŒFQ`†‡½ß4‘d@o«kÛ%¤c¨`ÊÁÆ–w^Ûê,Š _ÿ&Ô~æ³|XkÎØÒì,€Tä2öåLS_aë` 32|ÔÌ”« *4³:ÕzK(>ýÝŸ7üÚ7ëÎk0t.© uz(Aš,ŠÙÎ\1_ò'¤‘ëy—Q7?!@yRE5Fü%JEÔ¾{5,‘æEgB>6A‰bªÇåŒ9§Î¦È$ös1Vï’]§n™Ï«c ækº¶™¬©`z¿zU‡oQüÏ ¬u÷t“솉ÁÁ²:VµodZÙþJÃ-œ¬t2¼ý°Uްqú ü&ÌMÖñÆè7ÛQÍU\5Ų H›¿?éTž\|=„º<¢Wÿ @jÕpN0>ÚãjîéB`8Í\»ËÁ6}Šø;éDz/sŽ@y™­8´…õK"¯fHæUƒñÖzuãÌøz?7$R³ý‹”îÁ¼ƒ‚±0n¬ÛêÉ#ß9U—¸im#VŠÎ§Öô%#G@%K[uIz(iYnÏ‘¶,Gx#—å[pFØŒÖä-0„îW½/²`|O÷i> õ« ?ßyúr1pÕŒ®Ñ1Ðü¼E‰M݈õ°Êã‡+LÖŒ£ NHÐ9ÄB¼_ØÙß"ÛÏC’@€i’€€ rCÖhÚ`)ò](i; ‹ dNYëyfü4L¬Û;L+(–<ö@ñTNºÎ0%¬S×ÑxöáPôÚ9Ød},U4¬j0O¸Ã <ÍÙÒýÀº ˜>QÒÿ“Úù¢@ï“nuLÉzõI0àê eZŽ÷Í5¿1Ö.îH¥|I b±ß°Ÿ)OµxQ«pmX—5žŠÛ~/W9wØÛè¥æîi¥ÈS>EkÎQ\‘0᩵f4{@‡è3c°ÜS§Õl;Xá¯X&l·:Àì{·lEŽ ¿,¹Ý]À‚ý¾q9¯c\ •–øÛƒ%è·Ž²½KËuGFõL]ð 5ƒ{y¹ŽjŠÏÕ[Èߦü)×jÁ††­k+'ÅPÎJìê´çqN1ê€oÈ`áR@ÆK.!)ZloÞƒ\÷DrwîõʦOÿ…F©OiĬ˷֢fžú°GœôX$iÝyÈ!¶ s„¯°=4˜‚ôDú—lh+f%âv#óÔäÛö-–Wü0a!µes<2˜y3˜¯8ư|Þ!2q]dRuŠ˜Üuú[ ~øÍ{á¥X"[^Y9/Y¿=«éO—®Œk¾DHUð #uÖgÙÊnÇlÎøõb )ØeÓ„ï%’‡á›Âs?]¨ÌŠFº<“kÁ—·¶eàhÀÝ®ÄȽ¡‹²[ÒɰÝ+ïú ?}ùêT^ÖaGî±ó%ÜØuªnHlÔ3åq`‹wÏöO†ÿùNj3Û40ä="n®¢K Bö¨ÎÒˆ¾Nt'¯9Fµ¼µAPÉÛî/{ó«Hÿ|.`R¹uŒy˜]6“u\·»E ž2„&‘y“ÂÜU˜ÖÃi9µÔ.¿Þ‰…oCÉ‹–›´âó…Útëβœâd¥Ô÷ž›Î«Ïa›’GzšWïú¶‡Mf3šýüôá °½(cÚ÷CÏkYšŠµ˜»ªûJ+bÛ˜‰0jšC…®Üž}¥ô¾KG+qx ÞC*|ŠLu߂ˠßboG¯ U¢eoVÛIg%=À´ »cœõ¨È-¿“I¼çׇ€"ÖtOO"UGn²~2ÔTüy$^7³b³ðóå? -Œ#’ | ßÅÝÀd•´ˆ•4Ä8Cö'§´K¿µÿûmë• (|Ï#üê0^ôÈ5ÖèB+’€€¸2ÉQœ¬†#›Ïä±Õ¢w’Ä&MÖ*‹êŽSÍ*Žbw—»²ˆ|¢äóg¬ÿ}T…ª@­ŠÑ¿ Ãp~ê*§¬“ôäA(j ye:@ l§Ðeh—wn˜…"eþxX„‰IïÓ›ÖÍqŒ-N£Ãƒ‹¯Ì„ ÔÊ„f­¹œÛgPP-ÁÉÍ,ŠÞz\3«ã¤ÐØ{A¢'¸›taFˆim€:^õTñå/6$ÀiçCà‰†u×[¿W‡ŸZ…pW&⣌!РzïãÔƒ‰]E)xA›ú®Ãúò^õ5t·UIލ‘yܱÀA‡¥•'„ÒÒkq­Óiƒ‹åœ”c>ZWWˆ“G®Ÿe–*×´¹ØÇÌMaí¥À‘Á2íËÖ‰ÍÃò¸±Rù t ´ª@¤,;¥Œd¤ò4^NúG³2PÒ‹– Uã÷¼·Ó÷¦YÒpå&¢J÷bĘ5Ko˜­>—üþšÌjæ†Fø¯ÒaCØ×ãWÑðϧ­ížÚ×À7E÷"çΊŸá‚ö2ÖD°ÀI]H§œš ¼Í@d5AÛ$ð³çM‰Õ&³ú5˜£Ø«>:Fп#öÖ•>T¥…%ÖŒ d\·ðs,´2â=%Uà]áSwHpÓqöØ=¹Þƒö€u:úq2™‚k…Ær øJ½ˆåÞles þ3”óÎ…hÅÑIx !ã ße}ÁSÓ»¹{Ìq«#¬6×Í)Ý)4KÐxs÷$(HçE±«S¦Äa@áízzô£Gí6Tòk÷»µi’ñen`ø‹½‡ÒºH,ULÞ ±Í‡™NÖŠo!•¯›´Ö!,4l`³+*b|j¡Ð(ή‰ÄZ}dRuïr 9ŒE'Õá³NBRçÁbõ=†-tjª‰0Þ€Y"¾®ù¾à¯IR@ýJRÚÿŽáét7ÅÙ“‚ ÉÝâ‰åš@*kýCôIû Žešö¬ 7½ä 㨯ƒ;üK’€€ËÊ”0„ª¤"øú.§ÍÉ¥k;Or}~ÉS‡·š”•²§ÓEìµtàå°†ƒg”ý@aY,íç÷lú9í¬‘ö+?E}‡¥Ð½‡á*LŸp~©yÉ¢šö‹Ó <’^qÒòSáµ~ƒìNb± <-\èàAÛt Éþ?¢†íÞ%~T ùùSWÙ˜K“-šýô£›p,DdÝE åÁ°±›ãök´YHôàÄ;"*@2ní^ ¢&u×¹›ªÙWáu˜IììŒè‚¡Í+B<â…™ûø1q?5ªzÕ™îî¨u'ãŽá"°è`^MMOÖýCY) *J„M,Ô ¿ôðûòy`# _ÝqÝú$<õ­[$d¾þÿŽ'n>¶«ÌǦ¹¼’ßQ¾ZH´_/—=®¯ôO÷˜3opÍ=ö³¸ åjÌðýÿ;ÁØétð,²!5ŽZÃ;[yyÓÝ)äÔCÓFÔb}ì¡Ó€¥„BÏÄ´Áa]ÍFpþßÁ½£¨€®§”VÑÄÒUÉ›”¶ DFßâî>°óTÇGoiÊŸS‡ÙÝúZ¾Rà8ž»)ãB ~›fnq‘([ŠªBÚ-ßîU¾·Þ¯ ‚ •úáTó<²Ûæà¶xFÑôÔxV¤‚ ’EW•Oè³ ù»Ö= |”´R-¼[ÖОËB9â0›75[]ßœF( €H6S 2”{¤ƒá9}S‚;ÂC5wð§“NC2¥Ú<öþ)•D‚Vùº‘iL3Èiˆkü(!Z~´¢–DTÂæKœZåùfÓ‰‹‡Ÿ ”£\,ðw–œ… îÄ0"0ÉàV(Îúž«ˆŽ– ’€€è•;'-ÑÖÃÀ]›Ѝd”jæôÒÐëÎãòK*úæIónøµ>9ÙËó1lö†.^œ*JQÒêiLjz L#p¨ Öçg+ æOnŒ:vD»¨Úf°ª&2ì|O)ÓùIäîvOõ…VÌ3ÔÀFž´&b3mÜÑÄbr+Rï ˆ±5ß<Ñt/\ÊúéÉM¬À&÷FÌ`¶ô—4cмZz_ôì©*¬ë¤kÄ˨meÜò CÒ¶?F¾Íöë»ñšÌEË2Rˆúñ&LôFqèí÷æç>îC¶~“÷‹d#å(?^µ#ð8òõÖ’õ¥m~ »=À扤zêó¢¥9&Wï‚ÆBýe5iKTGÛž‡ª:ý¬©Çß@ ®‡ ac† aØ×Ë9I…Ê>lù?ÕF…u]¾`½0-Ÿq/Ïà’ZOÝ·(,Ôû,B{Ê>°Ä(­[AÔýdtþ¿ÁœÞ¸‹b,³¬8í‚c^“‹t øµæñH/½¡H' tò,U×0|Aåfƒ¤³[Wß›Áºz´ùi@B+þäÒëà Nº+KÆí±g'0S¬-™ñ²ÁÕç¸ýD„Àú*t¹”a|"bîÚáYdÄ‹'‹Lo©ñ‹šØ°a¥@*1$ÂÞ ¦v0£-¼•ùyk Ì¡˜¥Š†âj“3EÚÁ>|",a2;ñ½pUcúê»ôžü‚”¢€5Iù1žŽ²½-¦ãUóßHÖ·ï;Ó.BÏôÏ%Î%“I¥ÏwÚâÁ ²ffZ#v?oö)ƒ:FOždèr’*ýFÒTNÉ…¸*rWÑË%:þjÌ??IOüÅá¦f4!®Hwd{匘1“Ra® lÉOãÝcéES¸ÔUFÞÍŠú6r/Zh@ƒs>“ûØ3‹Vi¥mº‡þ}©À¨JÇ€ÞRÁ6 ¶Ùn2nš — 9ËÀü†E¬ÎÍiÃ6ÏÓŸB;ï 8hgˆ… µ°ø…b_æõJš0ã¡Ù„N‹&\®Å@3uOTpÛ2J†ÖËÔ7u_'oYAÑa¹‡“ ˜¢Õì†û˜1L¦Bò÷hŒq†0WË.âzçeXO‡›ï¦äÏû&]”¢ ?í횔̌q†á£Ú}îmÒ=›ý®ƒ4œØ¼dŠ>KûX;Í]’€€³kCPòÌíÓt6RÖNⱄCòk~p5„¤Ú|ø1`8/Âb^é“<ƒ­&‰ò|0Z§,@føPôdý9¡ÿ÷¼Ó¾6Üm%8QF#zÍ&J%Ï ;» %©Ðhgò?Ì›».·:â=wí›YDw§94AC&IbqËÄ$k• 8¸Âú(}ÅdLH|2¼Ó¡ÌÔ¦d“j_Ó‹ÞÞ#¯'^‡0VüeÔ×+f+‹$ÿmçч×<£}Æ@VðPûeÚúêÉ€e:¹ë%ÇÿyÙ­+œˆ<(v'ÐÐ*ÁÒãwrzMc)Ga ÐDÿä‹™–HR ÝÕq…ä¦ô]oГ‚½;é*î~ÐózV"q‡4$Ö”!Cig]IÞyÒ_$/@‚„^r@hÔt¦;* Y𩮨¸½Œ*Õ¹«m«”oóQʪÑ\q”o?ke¨þÌŒà‹Dš±oŸFܤ©nh»›RPxÏg|îç´L Ë€È{Eœ2xÐ[•wüÃTi‹¸ºÅ)öæâr2ª#pÕ+ƒ©Ö¥,F-èËÄïþÝ- ¬rÜàfø£°°Ì;ÝRå%NÛEÈo‡ËaÌáØ £SÉ?xÜ¥àQB‹jõ½ßI,žO)è]kf¸\…ièùNp§Ò³»9HxܰËwM§yß‘ï%%4Gq¯å‚«)x„E„fGŽÀŒO½‹xÖë8—¹É „ã~å#OÊI/ªÀ"±aÂzïåÚ8Ét†¨)ǰ²cŒèP‰TÄ×àsÅÜÝ3õÏJ6xð™à ?­ÕRfÇÌËeÈ pÇVCøJ\QsÖ¼ÃXn\›1â—Y_5/(‰¸1Ï÷ß)¨ÃQ)¦åo“¡ø·¡G€V¤eÝ£üΠØA eqõÎmït O;%!âuÇ :»N u^kÝãB»ç|.àõÌøã¬‡Ú úß¨é „7k/ P[àýëN¢-5ãõû¸?çû u5xá?^;¨«^åq'Ìz×+ áæÙTÜB[šÊ=²vßAuûäyÄ.d ∩i¾6@LáݪÀ@e•\âq«ùá­µݱ #ԤʆȖ×?™TÝ Wí7¶a£ó÷Û¹Ÿ¤hÞâëà+c×FN"\zPyŽðá*ý¦ž =Ç7¿a8°\f„ê‰?85—5»7kŒô~A^f$9Š ¤b&Ì׬çè,Ü.Kï¯Íq-¿RTôx!ßz¡'@mæ!µ@r6 ²ÖþW8\y4Q”ž¥¼šó} n°0Ö¨@ðòýH_€®¡ÕÊí&4Ø+¬¨B°}z}²Éß|½óëé}…éU¦zšŒéå¿…r8-JÑ‘''[[jµ¦Ú[QLw½êU  ºÙ˜¼­OMºS;/ïÉ’€€£B]jD—»˜…ãàè‘8L”°ï÷ö~.·D6!R0ÙfÉ.&ËyÃM«ß»±}Í\Ø£uaùî®Jgwë4ÂSZ橌}T¦›9ü™2›þ˜@Ù}Ø™=]k¯l.DMl ÐjHí¹îu1¼(y¿MƒÈωtx[÷P2¡ðêm-\ Sb* cC¡Äy¥êÙ`RµðÓŽÂ+Á—…жXºhíØkMD+„Ã…Ù)©®C}õVÅ¿vÈÚñS¦\‹?ò˜O!+®Ü© Žn1åQø •‘87£a)oõlpÕ4œAþHáî‹Ì¦¹òåŸwtÖtNk¶?IWM|½§Z µÂƒ ¢xÇ|‚IÏ€‰58€‹÷ú~{Ç©¢~¶3þ˜GNCZºðæXÿ£ëpƒ ¾‚³qKyÃv%ÝÛùðLÇVä«, ~'ò²>{ž*àd:©µ>šÄp”³úKúĽéù$S~t!gúžq0Œ¥iV ~U75ØâFa÷vuš…îŸhgàòk|ky Õ"š™Qаßñã`ìF%gtîùãáÀæ1®ÀÞãB¢ ŒBJ{¼x…ðœá×Kx¶ÏÑο[ìf@J]Ù/ ¡y)ÖéÑñرaL&Q`Ô –¤0\B¿ÿÿ®[‡ÐÌRóÇy¯ 9; º„zf®à8xÊj‰'h¾]&@@°"Ö%Gš@M<‰¸n’+Ƙ¯DãÌ2óaÿ¹x_q*­OË@Ì((Â\,R:j þl*æÿSÀp‚¼¥|¥¡\¦n‹¼nöCŸÑ@ª¡‰‘Ô ¥ûF £òÁ!cjn—Ê그ѓ`½é’œõL²ãlÏxSC6ÝKÂâ 61¿³… yF\fŒÛÆvÍM®®Ý´dã9ÈæF{ýç"Д š ´„.¦"k51y——~® ²ÌÅÍ„œ@€_¸ÄOKªx;RȽ•§ªOH¤ ÙUÖÀß'岉¶ùöI\\Ã’!(ö¬}Ž.>³š«¸¤Òè %®8g_0MÅxwIÁ8ÁÞ ‡=%NÊm¦ã­†¥KÛ¾m¦+Þ‰Ó!˜î’¾/‘€ß’€€µ^<&°1zV24’£«B¦µ‚å&£Ánшžh/½] ò{èV5Æ‹{}¡‹Ç›,n$³u0Ï@(ÝÓ;æ¹Ë7´ôñy/.¯Ò‚ì2ÔØÙ`dëñ}Ôf’_[V ÙlFƒB¼;å¬\5X§îý©f7ÖÍ…–Žƒí’èø^ž|_ÍrŒgì1"½[ Qµu¡†øÄyáe—éúíæûð9Tç¶ÆNʇ0;v«·ž"dL"0m*II¨®[Ö6G­÷FQ´Ôµ·y?¿&‘J'Ç…àÉôH¯$É^PÛD'?ÿº±•x*|j¿áéˆçž>·­bz ãwJØ?úw‡½¼ô€Ú¹¡Ã ܲ”:“áMÇ{)—ÙEº¦)ùïV…~ë.ÊîU ¦ãç¬ét"ØÆÿ¥Ú^ð"z½xÐ ÿ;/‘5cÌòwZÉd ƒLz9ôè91¾6ÕV&m®ö›å;úûiè?(3˜¦ißC<0,ž-X)•Ö†ÃL#`(d3á~Òe¯ávݳŒ!_+l“¡FµSaÈwu]…óʺ‰„Õëã'Âb3ÀøÒ§)¦Ô™tÊ¡¾ìk<Ê¥Ê ¼äàŒö/;ì·ÈÅÍó`=d9èX…¹´@pj}¦Á_žX{~%MéõG¢-šG1}%S¢”«îvOÖYÅ8‚„ŸýF'{ûumž“ÂLPý‹â³ŠÔ"Vc<( f"f@ÜG„R«ËÁ*ô *˜èó ¨-UP¤^Ž^/æa‹=d!/6õ0¸FÊï¡2MDžhÀIÝO3„°(!™RÑ÷öîY\ªò¾¢‚X’€€¸í”‚T+OH²u¾áXØ¥×HØôWs»1pFÌMW®º)úhe†«ü% ÔâÅ7á}ϳ{ÐJËŸv¶ÒBœfVF|"â}ݸW±¿æ€Ùn¶‘~šê˜z ÚLˆ²–Ï:¸ød&"ž¿—ÕW}Ñíkdu ŸCµ¥À=^°þ§<½ò<úw™P² ÓHzPc!:ˆ¼,ã°zὯ@L饻ÐÏ›I ?ž|%WpÛØym¸ƒŸ>ÎÜ® ÑBÑÙƒ™g×ñu?ÇH<µ<ðù¢p"ÏQﯰÖ]‘†®ÖÜð©ŠûK-ic¸ >Å·æ^ðZZ›ðù½»½ j§Ç0ˆ  d¢bWÚWÕæÂñV÷N ážð»Zlôáq¢AÚ†q¬@u#ƒñé^Ay:šÁ-îøF:ÈVÑe2Ô­¡ ¾˜fš@çpˆ^cpC~$£`7ý×(k3½˜#¦C”1Ï›À›3æS ŠhhÆ^C#XÖ/7ˆÚ칡¦è“–²õhiëG7Ý”Lì2I À›ÆóÍŽ:êxÈÌÜDõwP•¦[ÐGõ€›×rÝÖª™#û)Aø“{×!™ÇÚµ¡0“0¥‚n#Çø­:ÃxÇVV-ùˆ9Ï%dµŸfI5óRí6‰ÕN2t™‡çvÉ)݉Ì~R––ÚèÓÜÒµ‰`TO‰âÑ©8¨Õ”¥$6üB$+€W&5Ú…CKм]9Í#?>ÖƒºÍýfC¬)s–þ­¹h7C[xV¤£”ÌÊ™1"YB7=0µùVÅC‡dä%’Üqã¸âйÁž”¾ =︕GÍ8O~a£è»š¡’öK=,ï×cŠôœÖ™Ü?uäކ±¡zÉJ7 Û­VĪXÙ‰/3aøÕ—ºÊõZ‰;–1¦ÔQ†ÙtÀZŸè6ª¬ø·>:6ãÂöÞá¾èn‰7–A­Î ÔbEæ×ßxÜ0IbgÚ§Ø›¹LÿvGu$_/³jkÒśЇ(ÆJpŽ\šð¥ý[Ã:9›èƒ'$Æœìò––8ø:Æë3]9ãéUÎ1z’’Ò4Ûiå„£ÀŠNmÐ̨6µ{¿0Ú%ÿ™Vƒ~©ÏðкƒCývב!{šuÜÛØQ£þð¤Y©l´«×7뿹 #ßß¡‚=åÀïÌH|’€€Æ!¤&˜í¸:í¾Mz‚"¾@é|ÒOÃhî DÒ~-Ö7ÈPG™ÎIÚgeÈáë ÅSéíóa¬ót,—Y¥-µàè"ÏW'Ez÷ba+aÊŒhV‰â$ ­‚<Ìâ°ûD_8%“OïFahN|–…¡L Z½q÷Zé$ óäF,)¤ØŒ‡†ð ! “"Á²yã¨Ó]DŠÒrÎc´]e9 ã&¿™ ñç#4­ËïCƒglÒ]ËØò¦‚á4ÂbY¹ØÔ¿âõuHÒ`~?¼z ¯Éß·’·:û³Ð5lsdã¦h½`<¨Èä™÷Ã'’C¤¬V¥@é¯1ŸÓ!&€iF§JsßçwaVžHïK·è&hò:"?s‡Öλ¯W~(?oî*“_ÞFÑy~bì þåߌ‚%Fì>´F˜c‰ûÚNÐwAâ¦d¡¡ÀoÅv**îQìêŒüÙ~ÒÝ™wû”sÀô?¿¥Ð焦®_æ£iµ=Wþ&YºU[Õz *5È"½ï·D&âÂó¯ÜÚª°¥¯;!<˜§7ÈŸ÷|(CGÉç©ßM1jjšÏÜìÖÉüâ±–µÿÿVÎ*¸1øtìêv3ÕÜt-(ØŒ,Ä}ò¦8X­Ô,m-9ª…€~¢‹c*ÜDGÛVßîv%Íg¿:¯9_SC{¸çÎe+Êù²>Û¼8}hˆ Ø!Æ"¯#ÛA0ƒ~) DU&*j´¹ªó¹!ÃÈž—¦šBiNÊÛš°ÕÁ“!×=PǼlåô-QK'á'?k.ô1 `Ê>›=}e'°ƒÑ’­uYš×}\”X׉ËBEÿtÕèÎè‡M‰Qn’€€ÑŠ#)Éå"áwHÔz½Ù û×PcÚ5IWb5µ.^ eÐkg·ô3õ0ͲÂ<âYعÇW•8¢DbaT&27Áñ«‡iŸ(%^O…R}§AÚGáó+ìÕd¨QÕRWÁô€‰Î¦÷øY]gÄJ¤Ëvx`èB¬Ÿº°½çÄô8~ÝξÞÞd¨½¸íC‹×(ÒЪ¸ I©aÂÑ@Τ7Èçu›­¹%òºEþ ô‡êòO”Ha.ò*Ê€xà§Ñ ôNq@_áƒQàɤcpn‹Q¨‡þüb±r}{ä0HIðâ6ZBKCáÄGd!˜DûKˆ¡ëINôÿa4?HuÃÃm5P()´÷ ŸX5¥Miskõ/|€ž(=õa­FŸp½·@B⤆+GNþtlD% “BþI,6N§6â¿T5YúúÅßz3{ª:¨U8QóbÍ1S –ë‚~1· ëJ V¶\á8blÚ%úZí¥ÓiRÈSÚÍÞ=ËÄ!ЭL¬Çòß[ÎðÎÑlÍãù™™ ö ÇÊK«.o¼©B›îÍ_Ëÿ?¿J€ý2* rl"çÁKö÷„ƒ@]¤ü°†{Yø²õ$nhÈ~Jí°e:göH=>œÝ ³êÓœÕj)-cøÎÀ³ñÙN‘`|2{Åû­Jèq^}!\™;2ãAFîèpÒ[¿ð³€hmÙ‘»‡¦)€¿y4`Ï•tÕÍ3a3ôŽþ CˆEiÑbÐÈÎÐç4”Ù…÷bBx¦¹>쉔DWÞ2"ºëB¥ðƒÿŠ`$é!ò²ëÇ{•VŽMï»^å7Òö…U¿Õ#‰ÛTš1•]dßiœ®ëEsăÂÇò ežŠl{…G ¹‡lšPã>g‰‚ëç¯!žÃi­áCåÒáfëßÅ”Ðü°S°:ŠJ>¹™v  oXöÞØ,¤±…N¤1¤ClÈ–:Ç |<Mª“âu3Í 9_@TtÁ[| Î|ȇ›èN&­GkVASl‹’. ‰oÀÑoÊQd4Vx¼¼@‹¢s'ÊX²mRO§3KN¬ªJwÀ éÑ»éíºHø†vô)vìF%NÕ73K—¹lذ[eV^¹>Þ.ÜÈrã5H0“x÷±Ä–M'm—º~¶‰D~Ü^=‚Ç3Ô˜°Ê€?á)é÷…¼Y]ˆIÃÌáä÷›:ôžp/¤cm& ŽÌ5b®ß.߀ËٜзéÅ…¡<˜Lî‹ÂsˆcPµ>ÈPú"faøù}1S÷Ógs”ýaÕ+ Þ§™‹QÏÂ'©Ð¶fåöhÛJKïÚñvš~o–«ùùMI9¸‹ñ;KKêóµîOŸÚ# zï°Tz6òÁuÃcÑuÏWVµe¦ŽfÈiªI£|ùýˆ»„ý±A~‚ÄÈôf¦oPÐ*áå ù’ ñ³Yé5Ÿõ…Ójè|vB×à;ÄØM曤†“²dçe?%|¯AaAž÷¢ûŒFŒ(¢Í»¨ÖÕð/uùqù3“ïÛƒ&³äqÚ¬VþR.4uÍ]“Ý—2õéí}Ž#På·òR4ÔPüj`½ë8ºêë"Å8c³ÊÖ8{\l‚ë±L=â o÷b# [¼VÌjäxˆZ7±nWNf 3pX6YÔàj˜ëB.»£âœŠ¸^Ü=¯Éº÷ ñƒÞËg¹ Iÿí+ïË:‡³ rFG=sÞêÝZHéô!+fƒô¿ÑzRI[R*4U¢ðЍ;!€¿Ê-˜—ò°æ«hgâ‘.ÚÆ]>H§°íÇZ¤“>ßø—ÖEb’€€³6‹]k¾£Åô`¬«)0¾oPe7\,p‚~­ÈËXÙì„‚šJTœU£W|{æý^d³ËõlLï0 Eº.è^úŽÜ‰ëˆ‚òbÞ¯%; R¼w™4¬r[zÑØËš[2‘ìvfçÍW~‹‹n¡ÓuÓר0SªàØ.²².ž«ÏÌÈ“°Ê-Vƒ¨ÙÄx/:lÊÛ^Aæ~ }àc g@¾u’žÛ|ýµ³+ð [ØÊ©;[”tLÆG2z1c# ð160ævNù§™œaoÅY£2S‰‰PÕw´®Âµáçÿ ‰!Æ« bÁ+>õ—¯ûõ.•͇¾õ} ­§lR&‡ÉD$İg™²ûFp07=•’ÒóÆÚúË€lŽÊ€ðaÞ$–G…ÂZƉ Õª=çŠ1YFƒÊîRà ÕZô=§<ÂÃp »ðÐý§•ïgo2_ ø .–ÖšËHÍGVàÜ¢S¦Ír0ÞŒmñ!ês›¸”ÉÈf:>«œSX‚!8Nõe÷Å9­n!v%…ÝëBz‰Ù!¬)ˆ¿Ä†1Ê1á4&A-öÈÀûgbåšXÔï°ÿœDµý¥òÊœÄêž¹ˆ†Q­ž÷~"ÞWÂI1¦€+ŽCr‘«:»§ÜeŸ<„},m×!#"Òõ|Vä(ËÎT N´ìöõhf§$å÷;,]¿UbÃI·}]±Nbs?µ_r¤äN cJÌ|77ç,Œ-ur-^åZÛórh#Ún¬ø‡¸êÌ&†$.Yâ×É3M’XS¡¯¢¹ž¥›ê‘K†‚¯g<¤o^¹§Áóü›WÇŸ×5ÝëásÉ0 7¨—5ÓqHÅ¥; B•~_ ;µ¿©fÚœ(·gFoÖm‰ÝO²Ó2yƒdkÌ[8!PºEhé ~àÑd&‰0k3R}:ÁµÅâ ‚íqލ*¯ºB7þªEwÕþ Ô1q^&ËÀ+|ç”à$á^‰z—Mn°¿¿`Ü%QOUÇ£¬Ý†¦îªàX÷z’S/Ì5ñkó‰óôrßšˬ>ÐkÇ5&†¹{@QjoÂÇÔƒ½·õ!Ößã6No7'û€F”Ÿ…=Aö´Á &ªeÕ‰1Ÿ©ùëÌÖ”åðeëÙ±2ÁuðI•V¢´¥ÜÕ”}©ò»’€€ô–«X gœ‚H‡¢hE²©®`(HÁó í+üz_·­ÜÔeÑù__Lœ¦ü9¼÷bÜ+â¥GVÚ= c²¹Ö;@.¡˜4 :ƒT5XžJ¦˜Z8EzR>ðº“Çåïµ€³4µ;¢'Š„ÌÜò¦²=í›å'exæg¡g3’㢅¼¨QUtyê ¿Zlà\¼VÇli¿‚'#­Å›.M·:œ¬Ô…@„o–dºv‰$w2!­KÝÌ7O¿iÿ¢ôu­)*vFþM(Ãð ºU0BüeŸ²D`>ºÊo¸Œ‚)亇åmôú¿ ý³1ËÓ,Ôµq¡ZR¾~P)5Å{Fï"œþŒ4Í"5Í”ZãUŽ€MØö»y¥b½LcgÕ m6—rmØJH’¥Ž÷ídLcŸf8vÇãGR“m„HÊßk>ØÄ˜9M®gO­àÿ+Í÷ÐO™Ñƒû+¢°ð=`>f(¾ÄRÏ0Xš¯ GîÔ¹Eeˆ8¯cÎT}äËEÄÉ©IO–M Q·Ú°ôGˇR1µÙ| ×îr"UQs:¨²F|nÐ×–éXÈV;m*ùH⽿9`kÅIãËÄ;øò/[Œã.îá–$‡õh°×Hé7"%<7niañëÚr+ܽEuçWcE>¹­(vÅ>Ãûê쾈/Œµ«¤JU>§6^>è‹îËEÖ¼"ì°«4ì)§"¤-0œkyn uZߊ*ï×\R = ÉŽ×U¸wÚMd¤»þÄ#ý^&ÑmÙû2ÃëÔ˜i´:q¿ ï9¨>J]ÓQhŒ}ÚþžßáQqi[q søVºlàY½EžE蘙U©fl0À¢0ù£¹pl0Þ f¹ýÞ„wŒ2î®/Ëó\i2‚©ƒ {Ñ«¤Û•‡gâ6Wj#¹Å{R§„SÖ,ÌSE–ºO¸µñãB—ð¶Yï)‘n¾X7¨mÜ)ýô m^©ÓûCôDóµÈø†_¨)ŒMç—bíéEX‡åqîw= òu$·ºL¥©³Á«Ê‰s°{¶/¹ùضT=”a9ÔB”¥ºE±XM ÆôjjÅùPgQ4C¹v4Ñ… †ÑÛßÙÃ}ª ½=k[@ µ8Øñå[s4…L:~%Á ’€€ß8êHý>ÇRî܃êiñ£†ÇË?HpOúKÎnëIJWê#*®SlÕ€P(Û©1®ƒ4‰Nêv,æ|R¾Ï–ÔðRg”DÓÄ_¿¼Hu§p„ž_¶jÇUëÏ·2<)Ôiø»p¢.£Æ=Wð£|áõyÃ6àbá-î…{[|wÍÒÜ©ªFM#ËÞ»•ù¡åõàÂÒƒt˜ž®Ùæ3[1Ü]±Düü¥ùô¢ãª"R5DëÎ×µ¹[=`'U¨Nú„H­7R¡ÀŒrVnYŸ ¥‘×e©¬œts_ÂvW<ÿéòÛ]²È¥ñál¾"‹´côeÄ'D&Ö`Gx¦Gö§Ë•æ±òábpw?1TëSy‰œ\ïB!“´á“¡9¾u÷cý¾Dö¥u=§•/}¡½ÄâÝ'–)™]½2„×sÈo¤3ÌÝœŽ\“+&²‘âmf<[Z'ŠF«‘‘m„œ9‘rÉ´Õl @ß^=Å·3}èv'Ê?×è áàþB0á®ÄÅ7n MÖcsP\9›E@œ=ƒ¿Þa3I´ìŸÄ³©“Ð&ºeô&ÁÀíQ†ºŒ3½ú«–þ#ó­Eº}æÞº²,6¥†Ùq§„ÅÃ$PW¼ŠÙLœØ´ uaþu2Sg0ýº /s&d—\PÂê›cë97˜;ò_›pÌé|yk!ÜȺۊš ÖÑÒRTD37ÙGï˜iÍþ¯9±ØˆŒæ~}i ¤½ùb3ó-ãݼú?3›êpàtñÆj¾Û_‹ÊŸß#Ì[4Kr4Òu Á²H¾ [™dÒÌ4X¢8I^ì¼Ðöj wLÿá õ¥9m)qåZZHרHª¿ñ,3Æ> ;t•ï&ß Ô­ºz |O¼JC5Õ4†ä¿™·uй#@!(V{i ¯ÜPè ¼·¤ö «ù(ƒïáF+zLÿìΑḿ# Lº=¿×5™'ê§GÓ>ÏvØŠ<=yÛOfˆNØ›#ºè&\—rèÛfM1Ë2S GÌ¥ñVO¥• :ɦ+¸‰ãmÌMÔŒpr­îLmˆFV‹·Û’€€Ì>Jcűì°ú騷þh’v‹xfe*—‰•ÔÓÁa…¼v½ïuÞÖl€8Äc˜¹b0˜=Ú†²ßó¹]ânj‹@ÏŠ¦zh"ÍÈýn{vÓ”Ú~Þ¹Š×åK‹RP)âùŽFGJþdÖ!Ûc‡Ò,{dѦ¿¥ü«|Ǿ}13µo3ÕëéàVjF~Ýü pçØ4¨Q±Á'Í-¦|m2ØT·ãbªW[VI[`D‹â­Ž‹/îSÄ»D¿¡[z ”Q-Î]ñÍFAÇ«µ¡ë’œËl• ‘LOÒ›e¾ñȘÉbÑíUpA¶.­Jêk PB÷FŸÌ~ ݉ —§³¤Ž†Î”¼ –(ñMÊŸù†j­O ½ëu:€% V¶Ä+€ŒË΄ݘAþ¼l(^^b;Þ×Z·ì‰ì)4uÙYã§ù¯y÷ùVÐÝ“r »XÓ{ú¢*Q‹èîT§!7;dâÈЬÿåd'˜¿Ê¢ð#Hä½Sð&Ík©WLàÑÔ3[‚K5 •¯iZǤ—ÿ'¨Pʼô+v欽%ÇÛùÚUgóv`Ë…Zw|v€CÄ~¸âU‹¿]JÈ/v: ‰ï(³šR¨ÿ;ÉÛ¾„Ew¤ ÍË%';{­eãÒìŒÁ.xõù×þRUÃýí·VŒáåB|¦ÈçÁ?JÏ᫪Õ7“xØðœAú: ×9‹d#¥˜ge9Wyh%=×µ¤”¯‹"Kµ=Kí|¨&¯M%þW˜jP"©rΨFÃæ¤Cp[å3‚Ú 9î½_ Íç>ÒArú‰¦ª£Ò€éßdµÕXÏ¥$FuÛ¶nÒ™‹¢µgF“æ m‡ß.Ÿš]ýeë'<Ë”eÕ¿¹”Ëþ»> ÌïfÁçÝ1U÷ï²ÃŽßÁ”ñ²Q0âp—’€€ÒêTrÝõ—7'!“3¿RÃð…¼{u ¶8m¿'¨1©è·‚Njì̧¿‹îRñ$o•4‚²Ms™ü–ŸÈp»(1Ûji:qXÙôr$T¦cP C±é4Zv:µ…r¥ˆ:äDŽ“]$¼-MßèŽÚ3%TÊГrhiî ûi”mó‹:P0mJuÖ‹”ìq—ý¯ öA«¨&äÍý™£‚êuv%0\Fc]Ñb¨cJö1nVÿaˆš,X ,i²–üvbBÓòòÅ%‘ !Æ“=u“jè7ò1Ý:Ã{)Ô’ae w|EoR¢‡ ´M)cÛ+íÏC_>u­À…|ƪ¹ßoXâ^d¬}­G”±}ŠÓÚf%ä´½º¬Ö—2ïgô,òËñ#£Â¢À\G÷$oˆ.ˆ©w4–?­5µÜ¸6øË4=K:}´|r\…Í]pGSæÅŽïuãÚ¢)«d~¸é´<)+ÖuЬO”·3åªÙ[x†GZã78ìc—>Þ ƒô[ûuh6AåOÿGÁOB9ëˆF(&Gð \´ñ;T0Üö+.ÆŸ‘óGÖ\k^·B–DJP¤èhq d}äƒ ÍU‚Q™ V´ív¯î,Ô·²hw&ÎPÞú‘Ìþ‹ÞÄKãSßCa²öLºW0ú°gAïÙç…RÑ~ùg†g-BEoÝL.möOaDÉ6s‘;U¥æ÷¾ ôÚ Òà ª{^Øk@õ}óÛ ŸÈ6i)[ÚQa8$3íóOb…ôr_ÂwÚ0 ØÅ۬ŋ¸>oMM& ȳí˜"ã¥w¯³"k…Ó¾½Ëz€ÇÍû.AàA_qJû@”…óò¼þf^¶j9ÏaOxÒŒç§Tž<3 tbBãò9C(ÛIX4Q]Ë0Óçv|½ZO–²Ë•|E¤:rìNaÓX­ßÊŽ—hRÊ“' ÂñvÏùg%ÛäçðÑ~xñ©¯_I‘ xoÙ.#g@`@ä$ƒ…C#6B!cj´<~ñLæZ¬Ž- jb:NÅYXQ˜øþîʼuÿ©Æ™Mý Ѭáöï<æÂ’Qr»Õ=ª ûúÓ \®D¤­Çløb,쀚§m'à᫹q,‰«â^8ÕÈ‘¸ü?ƒ©–9)iˆ©tÑh•ÎìÖ’€€›`ò<òD!å4X’ÇŠýTŽHÊP_°ã7¼Ó‘…¯gN‹ág!íÎ#ö×Í_Œ.¦é`‰Z[ÅœE¦ƒMAëWìï¯9ÞÈ Ú’„ÇTöÉû´„¹èÊ/,Ì¢ÂÙN’r@¥¦Û ¯. ¬$ B^¶?©q>³&#RŒ_Ò*Ô$H)«´ä…à·$¤\Ë+D)³öå‘oþ‚#8:NÈn¾ÊÛ€ãP%ËNwxYÖØÔ |]¢ÌiÅÜ4÷ÇéIcá—DH5f±$ʧ¦{um”èÜ9}̓jÑEÇRøŽå8§0:¬rB§¼]g)™ãâ OÝ?c+”Uæ­é9ëˆ'8²J?Ÿô~áÎ}¶î KõN1 Œ(=æ¼²}¶®÷TÙbù‚Žh1ÆÛ:9Lqqáôv‡·ÚòøúzÙŸhšùÍ_‚úáÞi—GVox f9|ìžaŸß¨Tε¢úÿ¦®q½hrË Ãg…Fräï²Kÿà¡5"„Xpz2D†ÖªtfŒ­À¡ýZ.Ddˆù¯–8ÆQ7Ÿ­ë×©ßšÈ¸Û Bh>‹=È@Èнï!‰‹Áj=óÝl¸WR)m¼­ÆiuïÄröpòiÿüô´]Nù»­‘%ý:}éöÙ Ñᙞùó-­A{ù1ƒ.àD4·ðjû´ô–+³½ `±ÚCHâñd'…ˆ‡Gï/+ÙH"F›B¨©+˜†b ¹o)äÜìÝàrMgu#RÈDŠû)ÐχW¿Ž×¿÷w6¦ª\&]³Ób™Q°fA`uÂŽcjú °hùn¶Î%åsHpÍœû‘:vˆY*·P€Û„Úßi;Àý}IA,+(õNX’€€Â7rd³éRb¼±xËÉO™«—lÉ—ß×M--ѧ(ßÖÕìö·{†pREW E{ÂèÍKzŸ²â1?Nàx:‚ר%žåòòÞ²ñÙt¨ŸýVú¹ç™ÎÛŽ²ˆ_õ¦6(`ÐÌæ/`b†—÷œÂ ¹tÕ\Ï÷oø›Q•½CòŠÜÈçòÃ¥½uéÙ êŒÁ3œ+•ÆÏʪ"ÆóŒlµÆ]¦, V3öM×t YA¢Ó•Ö3©i±f»¤Åó$ éü ÏìØ3G]ÃÏ“Un<yKÀüNÓÏHêÕs¥p¹Å§[§ê³‹##–gÖ·I£푟ikJµGÐN]Çà# .r¯9Ü|'Ú]ÚoÉ‚è7h8ñl#¬º:0Ô®¢`a­Åx%Þ81÷ëš´ ÙÓ~êß¾˜O7»‡A Áë\¸&S$~ÿbÛÁË&7‘C˜$ºòÀZ³z9+üUÒŸ žÍêÀª§ ‘n£OÎ×{ß/.9",Ò<«Ÿ%pï9*ЯX5‘EžláHÊ-ʶ(±öµŽ ô€.ÃÛ šqßžÃ4NcÂðà bM3ä¢ÌH¶ _ÝA¹¹þ ªQÓ”‰ÉfmY®W>£é~ …íÓѸ¾È|ñ°HãÓÌß úƒß³°‹wka¯Az¢+§è…TO^°£*sûùŸ%ß7³ÕkÚîÝ>VÛÃhk(Ñ Lþ²KBâ÷–ìhéOØMI<~š‘Ûþ`S¬gñ‰x6° uÊOâÏ·êep\°#ùTeíÙnâ“–Ò‚†eÀBä$¯#7CªÄ1ycÚ+Iü3b¤AÕÓó´#±°4Gb&ù)K’ÓÕ xo—ïBÚ"¶²LVãpÐ0À—³»s­T?v»—SͯwK…±wIìlZF„Ee\Ô½\a¼¾éW^+K «¡hJÓ#IŸø•ý+Æ •y}йK 6VÁc¡^†X7™ªÙüßj— úú/õÂSIJÉH T/°û¤•^Î-º éßõÈ.~/‹œiºeCdùÞ~’€€º" v5Úý4q17=Ö;ËQ¹Û×–¯nìËeºu¤ÏÒë,rfRÝöÎÎÓaÚß¼Ê1«î®Öuáa5m{ž>Tû¤ß¢‰5ƒídÿ!Ã?¿¸ƒ iþÚÛicqæF–†€‹­†”•;R©Ûß‘ÊbxŒßÓ ÅBöÅ<ÕGmàÙb=¦¢!ˆH‡?¡î3ÙÓªÏçÍãÑ 9Ð9‹óÎ¥kž¾ÔxÙZ•Û´&n8n—œù¿¼hù /܊׷C>øœ' Û~Ú:’ŽÛÀ£¸ü*z€Ä á9[îX3qcœ]úÃWá‹­áP’æÚéÜO%ãø aLÝ•¡·5 öE÷àÖéƒ+ÙÝX×G‡Ü=zòS‰æö¢ë4“õÓçD’yt 7àüb=¥ÔDcé ¹FH"•bg¾Ê_â_¢TÌ+dÙ±EìEj$÷y^ýI5½ôŒsEñþàUYPɬ B®L§jˆÓ¤ÀYÂo@žVÌ>i•*‚ ¥4;Q—ƒýäY_åÎ)Áe:zV®ÑÕÕ7Áú >kî$e!KY>]Q0ŸYí:~Ø‚Í0"}Œ#“ô¢ò»ÿµ3ûH›’¶ºÖ??»ÿTÚd×?µÊÔƒvqD a¨«|Iäƒ!Clz“ì뤯¤-›^ßóæÕs_DEo<I‡~ÈèðX,ª^²G<õï—1^œ‰$@y^†-=aPò«iàaÀ‰¢^ð¥¥Ò‹FEˆ§Ÿzö3-?ˆŠ[µÒ`JÎKjÐB-ª¯Û/›a §ÃmSݽ&|uݾïS01 +'*­¹Æ”ÛN8³ÔRr¦QÓ…Óžu¯¬½W°Îó`ø ”7rÙ³V¡®›6à»EÞ(¿:çN?‡…ŠÛñ’€€èW0¤h™døp×÷JèÒ;ýˆÞ¤çнÁC§ðËBöÍÒ;.ÄçOZØöàäàΰÿUËx£®|}f£ZÛ[\0z#@ýf5Ì'kÁ?éÕ*Œ|“PžH–öCš§•æ3ΩÀ–â 5#]&0âTÜ·b–ü9C´žÑâS4WæqX g{〒9˧”„V£/¦â8Mv'› 7áR;º½°ûi£ŒÌiÍÆz `½Ã­04K¤šš“UÉyÕŽ-5T”Á$q@äŠ[Dæ\µÛýäô|.gfIzѲ㾵"R¬—žIFu‘¶, ÂD·0¿ÓÙFųûI9ŸÕC Ÿñ-þ~ü6P–eœ–ëGWÿ*”˜êQGtºðRŒVÞ¬= <õQé,Yé»ÉÄÂ.pzr°H ZÏÀ<Öj3†é«°tQjqwDPßjÈr´zâìÂd,Q¢qN‹Ðþ$Z²ò»DT¿R™f)BéæÖ²RjùgD0àî&+ñĺ>5“¿f7ÂŒºÈ*A :,™VÅYu\‚Î2+4ÈÛìÔ`J)!A®íd+¼$(€µ‡àö÷cÆÄ4yj9‘Üàý}/q#Év¾Ž¬ÉÀö5N²Êúç÷úâI»è÷ÄO;¢]˜çOÖ‚ÇÔQö¬XæáhˆòWêaÖ„3°+;ôvHÉJ±õ«?™óô‘ ,ÌÉ”Ä.•¶,8vw€üÇÚ_h­@!U¤ˆûÚ½ÛΤ£|v”Bð/èT$³NÛºåD01ÍÆÆ9~*³Ñƒ'…%t/å §g€6lz*4£+L}\O£K™ÔÔÙñ q7ž)giVÚ(f-À¤í0#úèuûzl:ÝT뉯Côa-&<‹F•šuŒ è©Ð0˜¼ÉÓÍžýd~гÛéº* ¤¸ÛÌ1löT%rDgüÄo» rË®VI’FÄÛÞ ¡ÁÓ\{sžvCíÜÃð…#øˆ6O“wðÀ •à»'ç•AãHWAØ€xéãõ ¸ËkDÿZ:Ÿ{:Öïðõ[²Œ– “ä…4Õg Ý´èYD7 O4N ûö[ˆfî`w?ðL?È ñ{Û‰ú….P‚è&(>ïªô#JsÐèÁRŽ[Û;²`ÿ´%-Ó·#7 ’€€¿lOsßYðOÊ få­àþAítkáÙÊy©uŸ•¡õ29õII¦÷î[Óïp[…+šŽv“ÂR´Õ+X©Á×7Þä|‚K»1õÖˆ¦dIëè-çî]}_ºöã^YUP7OÚ/µÖ¾: NT6ùˆ!tƒ ÄÔ}`Xš-iå: œýßó|Û®+þÉž,uˬBåõ¹®•ÐÉ)qž¡ŒÿÃ?ÔÎY!»Þ‘vbÈ7ÖÆ[’ž`Í¿çÇUFC½˜^ÇÂ-ém`MˆÙ`0 ª™)È=Úä!úSm*Á2B_ ÆÿZáŠ3ŽmY¡£Ñ‹“©Á#×Åí6m–t9B¡(´âïªU2’wb%€]7b*F\!ðÐÅqjNE­óòÂ`ÞðC…SÊ7@ ýZ“ èx“ïò8±õ¨vWó®HN²Pù»°¤ãq÷¸zç4LYC¢`qÎuPõiÍZoÒCÌÂ91q£H7,¥˜á¥q˜f\¡mC¤ÀœÁW}…КjtGâ'Hv7Å"mkdTxq"È6’É!.ÔÊtÃÁ&‡,që]›NOcµ¸HÎà,$+[ë B¼„c¬ÏéøÐfõ=DS é¿hÌÉœýcj ?´²ü&½w ŒÕ3A¢7®^/TLf Â>`Msö›?PzÖèÖý]:zYû©9´*Œ@#<à2a "²šPnæÕ#t‚òöä«?×=öë_°v3s»Ñ7GýjX‚Eæ¢r·yëÚ¹9¾ƒõ\¾Ô ³¦)š¾“":ºEÌÙ¥˜y’Ñ®4ÒWŸó Þ^µ$ Çmw‹0±óŸ0 ÝxÇ4‘¹Ôåõ&ªýHrÒ!ÌŸà­aàƽ Ïw) ö[˜XÄ;ºm%®—ßgŽDÔuD=kp7þ7螺 Ü¿¼"+cz‡Xràö³6Hföòãôæôõ­p´€t“vÏͽV©Ë@ ‹BéŽÀ•Ô=YÔÕÖOèÏ+}¢—M]á¹ U'ÊX{V‡öø`ïä„ÂB*”e®Ð±Œh«C5_‚S¿»,ÛB?ñ±dɱ+Z ¢oŒHÓÒd®bá(^öäJµ²‚Z1 \•;ÏѪìx®I%J;bÖ§¤«w±²ïÚ©àE:Ý™Rlâ~ÍÖXõ*ì9ð›4]À¿æOݘ×Îãxü9ÅyÁ, æ+~Ð[ô œË^K Úî⹃çþ»¤rQpLœÆ­¡bøôYúTÞ)jôIÕâêß8 )æÏñIÿ+^tÑ0ëä“Ã}Ö\2 ½‘|ƒV³EÍ% Áß©vNÕÏîS¤ßoõaW(jË^lñu JmGj›äÍz’½Êkàòy5Ó³í OÐñ|dåTT)òvïÜÂlªð1¤¸ w>‰€ÀÃðòø+(þ° †!€Ž=ª#4¡±ðÍ/P$a5söI³\q±â?LgŽãi2mECÏ)&¼´—ˆ >;­ƒ·¨Œ‡{* [w} QÛý’mXçÄ×lR-üßéÛ÷wÀºBŠNÚ¢þ->ñnÒúØÿyù½Vª›5òGw?BH9lªh‹a`»Ä@íî‹w7¥-2ÏÑ86ûF°´×ÉÝrý&\ "‹9B Z’G„XÄú$TmLA¤ÃHók ©u‘ƒËWR«mÒžÝi8ŽJ,A› ò÷˜ ‹Õ$¸q†ðôžø"¥VÃÜå8KU¶Ñ3GwÊÜ0rS„w=/\¸ÎäóæÐŸÎL!ð¦5Ùá »uêq–e2©Ïdq…­5öTQHò{a åüjí N;§U_<} "\–<ÁÜi]+°Ñö\áeZÞÜŽŸÞ!Ù«€H^Mþ ËÓJ…÷ŒJ<¦Æ6ÏÙVg©g<‰ûuò«)bTŽŸ5ÙãI/jæHÚ›¦)H·2Ê?Û]þä<»‹sÖÕþ7¤’ò?™DåŒ:•‘¡7ä胲÷$V|Ä.¯É¿Ÿ¦­kiA†+ÿ2Žr>vì’¹k˯¶I€o?ŸÑhÊ™a»{-Qí:‚a"Uƒ«‡'ê¤ëâÜ“NÐâN …S†r?ÌD)G´LòÁÙO¼]zqñ*hn!¥…™ —}8¼Œ`ö_—[¾o*Yý´‘!ýpWã&äáGHN(“ÎNî~G ,î–K™˜w[3Ô$àþSevTAû “ë‚UHæ‹ü:ãAké uÑÑt éÛY×>ÓÈJxwŠ¥Ç°8ýº®42‚ù÷4HEJLU¦Õ³ fbûh©JS}-\ØlºEÎ"~yÛœ9zWðEó—Jr¡¦cš¹<Û&`yJÏEC ÿ Ýñ‡w®WQê5 “ƒN#ˆ‚lØèÑ@‚8…o"tÈ¢µ­ÞX‰|ÌJY¡}ŽÃ-£†xÒ:<ä£Ît8;PÂó Ô§—=ÑÈ? ¤½…=Qçð]°£S²‹pUO¾–ÅCަπšÅÌ»£ žq—¤òÒ»Ü{¿ÉÆ¥†÷ %CŒÑìßðÆù²íøZ`©Gÿ\¾,Ú`cJ›6ËÂÙ pB0ÿ‚Þ¬Û¤µkWØŸüa1lP›.Í–+1u©4†OÓ$™Ù ñÒ“Õj—D’€€×óP¯þÜ¡åŠ(½býÉjùB0ø­gh&:P ÙLÖÎõõâŠgA&á¤*op*+‡’Qú=qÖFlÜô9ò’·±úËÙRê2e˘c2æ@ód “åZ©­·7Zq@â0ªdESàWjV[úQ{]¬ŠÓ ‚‰ÈÁÐË÷ [åg$¨bü—Ç,_h¶°¸¤aÈDªúük¥W™¿M©T¯!_z_]× o “ŒêlûS*·–?IÒq0^<]/Õú€ºN˜sʹ¦>ÝÎêo‚3”™äcÕÖ†ê!æNraê­sþú‰„>Iøµ0˜(×U¢þj{bšè—(Š—;÷aC°èŠÄ×~Diðy¨÷ƒ ì9}ïÒÂJÁà¯>—ô?c!jq›Âtž$¨¨wï´ºÜü…Žt€Êðô9ò(B«Ê£jî¼P¨suðÁú@aj¤¨Ž'ðÑV ”CzJ·æXÑjëi¿¼hDoÜË.†³ÿÒïVä(ÀMMÝÛŸ×@æÿ¨X‰z&)~ôó¼ àóìcsì· Dôöp’Ìì áê|©£­=Sù´ Q±Á״ܬïEjèuOÆŽÅË( Öõ…‡¦±°èžešB8ø &Ip¯c‘)¼À+øo­ ´Éä¹H –¾æÚL¡¾¶WªZïÀ—t%áCUÏ2Éé·ƒK]‡jƒó´_jtM¡éÝÐïíÍâg†¬"KœëFĤIÜ5E."ÚózÏøÚ%ÅjšäòÁ å#Z×mÈ6Ÿ³ñ Û òBõäÜ/ÍIyyA‹;kg/e±à¢O`¨÷ºëËmJø&Ô¨»s< ðÀçðŽÒ0oö‡~ð ®QÕm,݈©–“ÿ¤êR  U_íiP§Z`N…ÍꌯÛÈ6qYdYyõ“Þ:õ»ãÞÒq/ Ö„Ÿ.=tÏG’oô2Ïn…î6°q±u ˜“gß ØyÎrX}LF1_ÁËX°Éʽlé„9¡(u$4ÈÀ6äÁ|ar‰æ—m’€€—MÖ:Êêà8ñN‚Ct¬V3qó9^òÔ³Ž^Y9¾®W^´Ù_¦Ü¯W®©îó•ïF0Òñß*­D\¢´GqTòä" e9Ê?•ǯ>%„Îv¶ú›„¼y4¹zŒ1w¼ú½ZS”õ3­EÝy~B»lý*ñ¥«GöMé¶òM5’}t^ÐöOt"hu„%#B6®}”&“Ë™¼fëÒX×·0‚C“Ã;!%êüòg ©"öNI¨=༖)«òí½dô ´!oÐO šûñÊù”=H|‹ùÁ†Ãüä¨ÕÿÞ¾š‚däKlÊÉ€ ™a…KŽ:`v–šÙ,ßh§îØwqÉ(Î.i!Ux³ í§×|ïWªÓ™…x »÷Åo ´#WÒ/¾˜nQNøc# Ô½DÊ[®pØA—Fþ·ÿ3PO›Õ­B†§+Ê,¤&Šû_|î¤xþ¹æhvþIŸŸEÜÇÄçGþ‹ml=àjà .êû­ûW$J€çÜLñÊy ü„1€¼ÖèšE' Ô8=Eÿ80¦¯ì©oe¾è)Çk}.pg$Q„œt1w|¥cu«Aú§¨ x9‘¯¼¿œ™¾"³$EÂQÓDül-•ÿ¶yœçžãî¼0ÿîí“ù~.ê•£#À §¿vu CÅÕ#E:Tæ€sµ*™’{Ò,¸iž4¤CVáôxÆÓü„Ï¢‚ÎÁÛÜ+UxÀÛa-îÅ#o Æ©Ù:.ŒQ¥“U'ÇJðKÉŠ› %ÃOK}ì–Ñцܢ¦SHñ#;«uÍ@Σ‘Lñ¡ÏþÍ}‚E“¿<B—œÉBc §aDõt”Ñ]ö`{¢3ý0gUIT[ ¿™°Ñ¤K›¤”ƒV"Åëϳ1wÆ®+iCª§WÊV!‡³3ª“F¬H¦}`8¹¼¤|pg|eD ¤v·@²µ ‘d9<Ù´pl?&ëÃÃæ¦BŒ˜ƒ[;›}LMÚl®Îh-(o¼<\‚²qK±XŒfÉÅ‚©OíØÑC ­[ß’€€©‰ÆÃUïÊ€8¿ :tí¿6¦mèÖd½¨ù,(p•&mÞŠ-¬:¹Ü{páç–s.|Õwúù¹ZLæÉåÞè`Ȧ^¢)SE $øOŠI4}ëvוz(Ðý·_È "àP[DÎ †ÕÐ}~UÛwÆx'j¥¾;G¶pQË' ¸×çV°’ÃÕ×õàƒ-·íÆX©©f{Ê:R¹”÷ëRµNç l–Ob¿^š%y…±EÃ)!”NÑE iyð;ìõ`WVŒú]í…žSÜ4`.JXab`ù‹3qç1§±ð´½¹Kˆ¨wŒ ÿ®¿¯5w åþ 8ð²å)ÞÍÜЊ¿¢z:yY‚6œö—i9ú)ŠÄD>‰¯Û3†Ëõ’Íw}›;¨ÞÐþB·@C$Eûü«k1`hIÂOÒ”Õ€E7¤*d̸÷û¨WÇTÍ:2ÒÖaÕñÑ,J¢é3;Z‚:·ÙÈ÷ÆÌú{ZUD÷ÎLîXY˜¾F*hëaÐS3Å ÖP´kÉŸÔÝ’|~kBþ¶øÏH§øJ†Tãàs4+¬^0ôé6AÚŲ<Óȼà¢o/SúnÉ¢^ëaP!59Wùõ‰Šk¼(Ð&Mµ§C{2ŒQÅ›¤e-—¼œvôÑ6ôœÜ‡ÖLS8äØlUA×>‰ÚQ‹ƒK'5E¹±¼/¯ƒ}ÂxYðK`jQS°7ɪz;¾°¢ïsb½E53·°{›àÞ¥2Ѭ*?{V8Ê’ÞHm„ô<òûPìÁ¿Æw:âodÓøºf¯¹WÆdgñgyÿœˆ†W a¤ý3ÖòêÄ~ÙQE@þóÉ×!µtæ%A_4·¬„¥¿÷ã‹ͽ‹fœÉGéùp¸6ÇÚ¢~DV‡ˆŒIÓœ‡À½WOeé¼Ùœ 'q0U£·Ú¹ çÝz$CÑM*ú·®lÔêD)©Å0lJ6sî€GY”?kþI9;»$_­„ù K±[5öÊ‹ož>ÇšSR?ñç9ã‚  6Ú%b"˜p€×3@‚¦AÇnpìâÂëg¥g—ý®¨òSÒÉÊLé§xäX¸:­{DÚ¨$©ÈßI —Ì Oö…T£wƒÓQ߈¾-Z–@·[¶ÁÇ ­·Î‹.árÛï\Nì/’€€Ý%…½»Ô}åÚ*RÆÞNÀAÆÑÃ|ŠE'Âyéõü|Ì\jÎA“úÀ[…!&ñúmÀv3ÏÙü*o¢aøÑ]‡ ‰W·ØÆ­q—Y(FÝ£ÿÎY©Ùt AVÀcÖ-»Ô»=æ /<EоGŽÅ[Hpnb4«DÚõ·ÞP‘¶ÃÒ¦ÙcÎHÔð ê–‡ ÖW2µX?Dô/ºÖlß S;U´¾m”c¶.ˆðs9†¯—UÜÕ̱‹p´óNÒÚ%(;áûúëÙb­cû7á7LØqR2—pû)ÂU7بqUÅÆüîü€¦…¨½Júþ…âwór ¯¥øï/‚ ‡ïv Rá3£eråë7Ûì½ÂÚ·KÛ ÿ‹šc­ªÞD÷]ü »+ôCêlæv к²}:¼CsY³du@blxÕ]$ü,èÒŒ‹ß·©¡dµjèEÍ’m:®”:ïî1}>ïÐ~ù±‘€pë§5B©L}cp$²Õ]xR‘z¼oΡuB¥,åVÅy|]FqÔJe´}öÖ2I•¸ZjsÅÓ>¡ÿÐòñY'Sû©ôú×]†¼&j^ LS¥dȃó%‡É˘²I%º/ý4jR˜lö‘f?}wpfþ‹q:;›ƒ¨ÔåQö6Gþ­Ý®~¾”¬ÅDœà™@Î^ßlÙ˜ÍÐ&g°Á;U#„µ4eŒã§ôô“¢§/ë%ÜËa}Ý\>t@ëZNe•? ¼SŠšêÊö$„Æ_|èfCÃR3m¾YEŠºV«|&MÝî÷i·}±²ž ôŽõr7^©póåÉIMå&&& à¥ÔbˆBäfå”tä~…6u=¼ãÎ>{Õÿ+àÈÓÚe/Ù þ²|J³V¤ÐU¥²UŠïR”†o•ËAb¾óš¼ÙaÏ,ÑJåtdùþ©hò$®£¨vA6]p½¾ÎÑQfÍ'v0ÿósê$8ÐÈþ¯úV Pÿ—¡å¡¯zÈpKôƒÞR#³ÐG,^lÑýÁžáüXm*Ü’ûtÿL/úg¶-4¤?šg/èpáùQU[æ^oщX ·ú|ûbTIÛ=M¢Ìä”›(MîÍ,”n7£`/pX4Øa©Ôý®ÈNé÷¹]¤’”?g“W:ª’€€§ý¨Nv¥ÚÁçîÖm},H¾ÞûJ ¹“H•UðSÛº¨ÂˆT4H¢ÉRþÒí{ίaP¡.z’h)ªFnÈZ^6jƒ Ûå=·ƒ «…f§#”‹J”«Ø[LÞBÂ~ï³ÙÂû#îMhÏ^ÁŒ2 …fv2  Ü 2â?áŽí>)dÁx±cx×Ù˜±#‘?Ã%ç¾TÅú¹ÁyhŽ9@ðòÚ"oNàU»,¸©8Æpj ºÉVå\éu;×zõ„óæ•ˆõòÈSH†ŠB[‰k‘jÍäLfi-†«÷¶À>¿Iu‰G• è…îã ß[7V;eü½û¼p Ó¡ ›™Üý˜¹]®¾ 䉰"Ö÷ì¼)k,륛º< ½êCµ`¾«L/@óݤásöŽcJ GQR"´ ­bóç¯FS§^í)¿ZGv¾70ù›z‘ú!p»É[UÍì©.í®º®ºãþ ~®ù„g«5=x°ôyóÅ^3T`&`bj™TŒu °¶L‡ ‚Óû• °7¬ã"Êìó*Ë;Á¢+O€DZ˘Wiÿ†šbVÑX1/Dã²áŸÊšl¶°NÑfPŒ˜q\ÙÁ5eQ6 Üo«ò޶yc{ÓR9D~æXèû6ú)Ùb°v^¬-ˆÞ±¢¬§[½i6У{ÎoTsÿ †K¿ÆÖ"qΰY=ª U}ŠáˆT«u!‘èÄÀ›§1õR>0ø‚‚ Iô¼¹¡*¡–PÊ»\®ô}„¡Xt³Ún휡$W†sï¦Ü /m&íªW${ÅÔÀ%ÿ#ßKTL<—ê ŠŒ­hE O—ÊñìÜQßL*ÂŽëe#p@Üï`»·b÷òÆŠ¥nJßáXéâÃ퟽¹˜+᣸…®1I© ¾y´ÍàåEÕWÇuÈB±lüÚ¯ç8¿²Q<¼F•.×7›%s ͱn¦Úg‰Zê%€)ôcO€aÔh“€?!̾…ûšËkÕ ŸHê;/} /vBoÅöìÌ}ÏŒÙÑ”¾ Ƥ] ØÊbâúXáè3Û©]¢šëÐç}ȹ³øçóͱÔ2îοéÿʼn¤¤üíY¦c¶âí÷*‚r~*kó’€€´]Û¾>(á˜R*EO9ë,dS¬~…VÏÏLÆ+ð]„Í:W¬àz´ôéU7ã6 IA®Ë†Ts23ï%N")¤ð#éStž¡;ÛgzEfŽ€¹dý¡2öÖ.8E6•ü¿i56Jχ¡ÒÎÏNä¡ùõQEwÖ佫wM¯ ü„Bø¢ñ-§_c¹Š8B:l«’$’ Þ“3Á¿]IV†áå—F#5Ï]«ÖKgÅÚr£q”•’z‹o#Ö%‰Œ|ÙÉ’5V¼V–Á^ÖŸ÷šÃíõÒÁ@r÷ ¿:hC,u£až ÃÞÿŠ!ðÁ3èúD4v—-yÆÛG—)­8½¤ƒ(}FV"žõ±¨XP—I¹PÝ#Cº,ʶJÌr‡²='ИróRu^×øæ¶ýÓ_[û ñô¦Sn§,*Š„Í÷×am„–1´‹-²‘J +ÂW¹¤%yÕRÌ¥-dþÿ>H MÒXÕC)ØßV'Ç5 56"ÊEXLAÎrüÓ™ã5ôAÂÖZEŽk"¤¼ƒüR5Œÿèáq#|r f1GšÀE> û7ûø'æî±O¸4 ×ë“o¬RsC²m8DÖ‹«³Â2±É‚¢yù+Û©õú¡LWkÜ.íä5dê4ÂZ¯AÉíÑñ°mÀ,6‘8\ÎŒbÜ ¼72× -Œ®NÞüºÈç\Ó²šn¤Ñ½°Û4X¢öüG ªÄIã¬ñ’€€çû‹;qe˜~ËÒø)ÔðºA´¶5¬$°ÚöÞì±Ú2—R~}[ÀžrSIÞ5ªPÓB"ç>ráÇžðÈE“aÂQîPºúä@‡¯ô“Ѕ톹Ùã`û܃iI™+ÎþYÌ8­s¾á˜‘v- ?$KHM9¥÷ÿékžóÆÈka_Á$רÃyp÷¬¬Y^ä”Q"ôÅ@Œ­pÜ«dd£¾¿F÷- WÇ ómFIÇ{ÍŽ‚¦§)Á¬Ôxºtýõ¬à!±ª^”êÒâ<°šqÈ;‡X{¼UŒ3]¢œHêТx9ú®¬€CóÂÚæµ³Bi—È—yªÉïÑ_®y-I-ÆJÙ¦¾œ%,þ®p„ ²¿yò²~»îI«Ò/t䙎 yn2híû=H/J[dw¾èæ¯ ÞðdÚÒšÑqFçóQâHI+.Y‹hÏVÑwÖs¹ÞšÑ;y×W8?’Z®ºjgÓ VYO!åF©PŽ*…q5Zv2=ô¨ä¥>Á34½¶š&ùúêÃkàHÆ&0t›A"Ç­üüc_Ò†í(ß Õ} j¨pñ9¶†§«York)ý±ax”ìLù˜Clׂ“*¤¿¢­ABD'Ái„¨L¡s(\Á”“~ÄÇI®D$g˾ŸGÂïûÊ4WÞiø\úSµ@Cu–‚É]Ÿ{êšÆäµviÖéš*¬žÖiÿŒ¥AÍ}Æ‹ÃÏú£l $2F0XYIL\h‡àÄÜ&:1ÎîÂ/¹+Ó ÃW5¿ÿˆ@¶>Ùžè™lßmL@D—{òON2͙ėÉHÄ]5<^ؤ¡²¼¸hî$¡p7ïŸÂ¡¡…ÕRØ,å¹ðBJC&¨²¦¤ƒ)Þ‡MÖÀ,üÁ›êx±8%VÀޜӺÅ™)^ØßMÂ)K¼öÐg‡ÔÅ’ØiÑëå™ðX5ÉÃ~Rí-[ž$d…ÖçÈ—¤ìÀª ׈ÂÊ‡Šø~vR•C*©Vï¦×Ì7W {õ9Î_"Kƒ¨˜Èµ=»ì·Ý£ gÿ¿Ú¢Ž`Hh¯;§Éq=m$x¨CŽÊ”ˆŽ¤¥ÌÇ{è‡z>rú@l {íߟ=”µV{I²»Ëàú|R5ÛŒnÿž)ÀM®é]i—{³ã㱿àüÎÁÌ[=O¡xêÅî¶ð2’€€Àíw´Âœuwz’ú!µñ˜ì "´…ù…ôà6zú‰ éÿ_HI#×ÓÊQhrª@}E¹¾¯tÆÜðˆFpçà™§á†=(8ŒRÚ‡[hÞuÃ?˜I4aMÀ¢Ìà6¶w^<ÆéÈŠ±bÕð|D·ÁVÂ4Bc{ÂúUHÉêIH<¶f:í|’×ñÔ:™gû°ŒÙ=Wxœ™"ÿoz¿‰bF4´tà…5ïÒ×.¼wÑ‹µ%TÅ•žh¹8B}&lÇoöÿ? ¨áã<0×(6‹!Ò”\:‘ƒ9&ê2LÊ¡š27 Ãûc:—IÓ°þÛ6ðÄ¢©ŒâÑÖ‘²òrï«OÛÄ‹s×®Ö¬Òf·ä³½iòÃG—zöoîÑ1i»¯ªª8¾Qìm+j5òÈ_GÀdaqPLÉ>Õàyñ™‹ë¢ÁnO£í X³ÍuØPuz«È·øeXÞö±œ±Aw§¨hÕ¤/5)JÚººã¡Ÿ€ ðy?¨…ÝóÑ­ðX›nxÎŒ¨1k²RvÂ.{àöúf£ÑÐ\ˆÍëvDôŸRÛ–Š³5Þ­‹ÇAH†©Ñß?eNQNEºø¨Â‚¼îøb$IOgeX’ AW‚ðg†,‹/ïÌEzòý¬×[ͨ ýA|ÕBO‹#âËéô«²Ž?Á†"‡7q$ˆÎ¯Ïa¯A¡’®ÉÏk ›Ù>AñnDš2Õð¡›Ä ‹–Gš²O·‰3Žÿj¸¡eİÚyü2ÇC­ 3ù"OÔø îköÃbMäwÙrŒQ1W¸¦—Ï›3å(“ÏCÖßõ«Ày!$úìr.úʾWTÒJ[‡z88»ý+–šžz\z>/ä„ Áµ+±aìöG ?OÏ¢jlUöú®ƒÄïÙWçÀïéq1gÜ'i¾2å=>ì"C׈­C[ïú#¨ßØ’€€®×G ÈUôéE~ŒôÝKo@‘ð0Äàz—)k²*ù³†ˆóŽˆDàó\.Þrfƒ=Lº9÷Óëû²“CœÚB3Ù>hÑÈ¿h”ÌD.”$µ>ý–ïÚHÄS.¡à‡eHT?ò~JxŽ)Ž$tѤҴ‡Á @3_ÜTàdùs@C½´K["ÞüEÓJå;,8Kî­–­¾:zƒ’$PÈ×dM`mÿbîpíãÛ5Ÿ´Ý͵/ž*L 5ƒ%Æ…Ñù–nné­áwZR5eV¸U©ÑŸ}"Ò¥Q3Ï–ÕÓ*ÂXÇf-Ê’®ÜÝ'Ψk…$¼¬T•¬u4¨ ±ô¹0GWq9vâøéÒä°`K’ÎJ®~L‹ûwÝ”$B©x'‡fȺŒ'Ÿx2Ýe°YR€©rÍŠÕ8‹°-5àQíÐjÞ¦VAÉÙ²$[48-ÉxM/ö­e—,ÎáÂvN#ðìêâ¨. {¯:›óaêŸD¦ÕpàiùEu¯[\íO|²ö‹“ê¨ì‘9¤\ÈÏxÚ>@µZ’.½Å_tÖZ»:tÙÅk%ÅË}Püƒ¾x­!OHÂãCy\&"/GTé 2‹W¸ÿF¼àC’Ž' öö¦^ƒùŠÉ>4Fßø€€D°žMç753¼ÚÅîË ‰ä“Âé/šMR×1ÚÒgø…‘ó(]"­dùNªŒí{ƒéþH^BOóÆÜc ^}þ0EˆP)F€ÅÒ¬¢Ë¹ møhuIotÚ¥¿.f²hOí‘V6¹VnÅØ##»öÞžY°ùAëü7²ì¼C0] ºáKÄ”¸±[ûC¹°L^ëÃÑ ‚ŒUÑuE9Ši!¯ û³ÓÙl £Z L‹«e‡òÁí*\a\°®\¯ì!ôFÏ¿…º]âTÂâñBÙ›->3!=Üê⯾ëÕç×kôELÏŸ®°G<óO¸OjçS¹gemˆˆ"ƒgÍ/Rô-\T>p®Á4õXí©š¨OoÍß8fžyD[“ýî¯fÇdc{¬¯/}§ d,Å_—ÔÄ[ ™E8FNv¹ a%ºªõjÖ¾iüÈÀmE–Ôÿ:q®ð.bS ßÅX3ô©‘‰Êœ«v’b[«5R2Q™¤·µì¯<ŸO’}oCÄIÊÊÞ ƒl¥9%‚Nˆ›J´’€€Îs,;µÄ©{“^”ÖÄOYÔšñ°pOmç0º@P)k0õ÷ßõqW+I©0n–Ëøá€²ä¿D·~ƒ+x/rú¤ÒŸeŸ‹bæ¥s´”_x75½â÷;Â^iJOÃÒ¥%¿ß 3Íæ"ínÂgúA:RrbófÊÓ Ÿ®› H|šÕG„–м’¥›É#xý;Ož¡†Å‹È~ë!’~ -ÀQ1󓺋"U ˆFpÜÖkQÒå6œö.7&¨ì?*ÏÈÌÿ¸“þi0±þª4¥_jqµá IˆVŰ2¶Ò0§Éº­'&]X€¶\¦§HI&²×æ·ª€‰†àæ~ ¢¹'ä)7B O+Ú÷ãL>¨hпÅùÜŽÅ¥…ʼ1œá©;Õ!]L6RßcâEï½ÄÍAÒ©†ú‹¨ÒXÊûG’.U<È’kéž­æÀÀÈ 1å–1å*S7½'µO™T…ïñ2¸Óü9˜a|bÃàƒC<ç.`ΙD9âžMÖYÞ(îVMÐ|·Ùþ%búgVs<1×òÈãÝŸÑ©ßó×X@)æck FjéÏ&‘G·oÓýM£Rý¦”fÎ5&qËWQÛK­ÿY¹®§ Ê@öƒ~$ÇFàW!4Ë;‹æè5M‘߬¡ ™>f:í»ü§Ñ”×SÁkÍÆM \Ï)åÏ„¨xåù'ÌÛâ+¡W; %L^_žìš ÜÖu]#$°¥èXú6qÓlÃtÊxp3$dc |s¼Óë”Ó´n¾ÛÚ* ‡nc üÑJK¡á­…ûÙÅÓÚËE€ $‡7™Ï¥³çŸÂæ•Òiwò6Xå<0±ï±Í^9üú2a<Ü«\•:)³w¿EQaJgúÓÛ‰»ÄYDbÛ0œ–{Ž™Ò#Àþêê$†ÁZÙ• üOGc…6á=¢ ûEå4”OŹ-¢ŸÎ+û/ùcOwöV{­Ý_T„I4éõ¼5ùú­œG¸Ç¾êCLÂ’L+rhX’€€Ð.ÅPOÙó0ËlÖ ÊÖÙ-âÕ­*Ìmîá­úVB¾w8†Ú«q,xil‚µ§ ãêÀuC]K驚ä3A×ÚMi„aLYIÏëýÕ—·¡1;"tp×Ðr³ý{»ËÕ–«æ²Àt&Q½ä¼H6Wuûný§·É2¥·…’G¹®^Õ²¢#²ïõ@DA÷ì룴ҳ¾Â4gWJšœ9R¡DÓ¦S£E±Õ‡Ð*šÃMe²`”‡¿£R<4S¢w!åÈFïvâ)r&UŽ fòd`c]²ðʪDºv®‘,Ñ”Qƒ#‰âÇøOˆšý©©‰Èþ÷EèÓ^NNì9å{;Q˜;n1¿0]|Kú‡›Ä¿Ë½ê–qUóÖt0ÙìÛ`£ðŸaÏ„gÔq ëw4‹µª÷ëÑ+¥‘½P7WóICàÖ™'çO1•‘RAo÷eìšÖš\鉩·c¦]VÁÜ–^Ø6w¼S…èyxÔ$ÒU‘_ÆÉìêBÈT'†æ*,k_{{ƒ™¥[ªc$ùg‘û¶OŒ#îÁÂBÚϰØéƱ^i¯}gªÝGç‚<9®Š2ñ2ßœ+k‡\èU?c²“0¦¡à•¸»Vó½ÞLíüóÕ8¯„ù6KqÝßÏ’ …µhk²+ñh‹Ô7}-;FS5™W™ëüQè·Cí{fßÐgÚñRu.œ¶?o+¶¯˜ÅúÛŸ!–xœM˜~´æÿçõ&ë_B™HI‰i)6’ù€ónâ® wÀItJÙHwË&…ÜU/2)®_íšÍô®Ð+›ýY„¤K6àF-é%y–k¶ÿ`<}œfZGáÖÌ`·2! M',Ó"G9.œÃHj8Z×q£7zÙy 4H¯ßOy’Âß`½‹ ÷¾$Ñsé·å<°Z!Uµ=wj½LèIÛÇjüÛSBê:îĪçWÄØïûþ ´j‡'â Ôˆ¹·PaÂôo¿hÐ8áá±Ä³±´‡¤}Yz¯E˜m,ã·Àé.Q ½døøðÉ< (ÌDz!RìzßMôYìs‚²ÒÁ º`PÁ%Q–ò.´²!q:'Ïà-kSëË0¯‰âE çÉ™â»Æ»zLžMyF>a7 ÃOGüFï÷Fz6ö퉸ªTGoÁLëéUeœ¨þeÀ’€€ª™âRÛ½‚:ä°;ÔˆdÎJx+èGÁúT-ºœü “ðÆ.¯ÓÇ V™”|l³ÚGmÍP묨YI‡zU¨9[}¬ÖMòº{»Ðç"ãóS ÎÂ|8f+åTÆæIÍŒ§† q &¾˜)õ±‹ê8 ÿº`"KÔg¡SMޝÅüU†ú*ØT2*j9ãˆäZè#­ìÝ=‡ÇËë# |¶qv€Ë` ÊÖ¿ŠaCw¤ÞNq¹!\Š©u0¶PÓŸáµt ÛxšòmÇýÝ¿ÕÝÁ‡«ké˜ä}éÿA½é)<ðCÍk¸=¼óP™ÁCŰr4.Acë1¹ÍÀå7»‡¨=„ª@ÈÒ7œ· ¦È¥Âu”*(Øc”ß«U± kãºZTdS¢a>1Õ‰PVæeº¹j°xlÕü 3‚Ο\Hç±î:8“CûãóÜå›ê|Ã5ZÜhm¹>ºÉÛ>ö¿Ê# ýD¤6-Î;Ûªœ¤=tŒbò€Q[[ËüÞ¿” ”Q—l*Œ,þu6©H«›(å\›¯sóYa`47Åá*©p©QüªÅqÿ3òÙŒÖKMpOES (ô²rM²˜bzg¦,Æ»]НšÒq9ᨢÕ-o6©¬¢Úûò‡¹ÁÛÙæ'G±¸hBƒíƒ²/ PlîñÝ5¹e‰iy+Ü{«o|ÝoŸ“’lÍK,çØVJjï¦×h´\ø”ßg½¥ªƒü›uà`2Rá*!#MõÙál„ìÒ CkØŒ¥Î ñ0¹©ó[×uæÒ?AŸŒžzŸahcœÉñkB{¬¸ÆV›Sˆ»ÝƒMʘÙÔ‚œ…Ån‘›So>®¸úì(×–¾êù$þ4 -íç©[ÈÃ5mEàÇtÌ—‹9N_G¬³qª‹‘,*Á£ ¢Æ9ºFh}zôa!nÇÚIÖ¢š-;YÕ–& ·^lCµ‰ÏÀþ?ù²U¢D¨…¤š³8þçú±Ø6\ærÈñà¶ ÀNÚ`K…åÆ ™“yN‘'a{<ùäwš³7 UÔvZÑÇâøsÉö™d¦)LËÁwîÒ½ôÑÌhutAдPtrÞr[~ÝÙ’í—í?·]Í.9ædh¬MëÇÒéÍnw´±!w[Q_‹‰æ»¹†ÂŠ”ø‚( ¦°üiW@à SŽ»’€€£Ø^õCl`di*xÓšÿÙÎyÁiü• `nç­MZFCén`Äü K(W†í‘…Ž2ýÀ,.%]J±¿ (#95ÍiÉÒÛŸÏpL’vãz|•ìQeOAV(Dg°0„îþΩùÂ~Ðö\ßZ²O4 ú7ÄG€yÔÀ¼\ßk±GÚ;¼> õ”ûU 7;¨4ËcT…¥•@åÜÕe…µX« ¤\¯)°DÒ)’eø,Œ¥¾J‚µÄ9Ü8uŠg†­RFóË·…)êM©XjAm”¨ªü€=tÜÏãæ±`XùY×½8¤`ÖUr±6+òÀz°`“¾?¨räÈþîL‘» À@žÝ£|üQ TyvfºSËu V…ydäX]¢Ocár4¤ñ¬ìdE$³¨‚@`q•wîA¸Œ’íÏVÖÝ èÌÙ[ä(ÖFuîkûFþÅr–-ã¦Õ±¡Dz•¿ÎOpWÖkrHtJ0ëDÅ_å1•飯ŒFs=ºfö¤[å|/5a‹Üw¬§Oì€ø{²Ó±SF0Õš-á'Ì;Žó‚> Ê^X’4cÛŽáxX}ºÙÓDbÈ|A›SÔ›3G$x @Bä4ÈòS1…køfb;;Ç·©2»”ÈAe]¤ðÒ’ÙÿGf¢d=i2ý~!EOô=ÐÓry[TòÇaT˜c«Þºë+E­m2м®Òt¬sŠ+G=2¤Ôõf0P$Ú3^l<­<ë.=c¸ ûƒuô¹¤üÖv”>ST³’Ë´0DBR­iEPQÌ[l™'›­sœ\CÆnÕí}rkÅåiw0¿.ÍŽÃái(-ŠÏÈÛ§çH‰ù6ü›×‘÷ô/TƒEºÌ$jPO ÜgУ“*=ñûžÓ8ŽžhqòêÌóÏ8}® ;#¸KCôšÄuÜEú}Ù•#V3ݘtX­úØ÷Õv'2'0Š(P,Ú¼ Wrá÷@õIᇠJòl'ÙÕy«Á': Ó%DD-•U/ë ¶+Uóã$ÈÞs^W,œƒ(T—ÍÝV"ˆ%ƹ{áw¯«Çwü ƒ²èW'‡€"’¶Qm¸á89=³OC¡ŽÑÌÆ|Z]NÂ/vg8ʬML[Æ/Ó‡ôhûøD>èr# *ùf©Î~7³%¥akãjT2¼užuI’€€Í¯ ˜2ø `dêA{"òš•^B2BSn×¼ˆa4îÀp»kQ¢ÜË_òÕ¾¸à=˜Ìf@N˜ÞýMð±\Jȉõ#E"ç—SÂYÞÒL±ö+>ØÐ-íÄü³'³(˜5ß.)Azpó.­ÌË…MŸùð¯kü™åOi•› :åÊ4ÇÀM›sù¼2M„ºèÐq÷3ÿøL®ÍrVMng©¿Nݙ˱ ?yæ}4Ê «LM,!ÉW¹ÃŸ<æ±FØ u‰`Z‘Ÿšh•‰­@iÊ}àó WÀ^§5ñ·ú©èn¼Ùëéo -Ÿ)³v_ÌÀ½sµè9]Òb£“ÓçÃÅÑVLd¿\èM\º¸¯õ©3¾uÖ)g ÒDîˆ]ÕE™Ýäñ}JBšj™&E¿¿2­}bë ëƒg‹I°mÀyÕâË äc¦qÎÀ]e4ù0²ê$ˆ‰ÅÕþ¡ï•/(“ÏÝÞŠ5‹Õšx#úu5×MÑõ¬~— µ—¡&륢Uó‰ý¬èQ÷k/Ô y¶½õ4¢ƒ}V /î#Âß^/éö޻ũÅ-‡¥ÚuëùÁncþùP–Nd¼»ÑhÍDT¶\Uü7²ö€ñvÔ+ï Ðom¢Ñ^Â.þ0ÖÉÞÎÎRálg˜¶è´úXÆšR…äiìz¾Â›CRõ~pÉQ\©€”äYÔí¯õóó÷/fbȲˆ[¢8èZ$àLçô «µ~ ªÌÐøåÂòßß#T÷‹*Aå›Í¤Å kWá¥Ë/Ç2Ö»jÇTàc Qms\cŠcžûo·Ìÿ+ Ýì?X3ß§ ÔMߥô†3Ñ}j…ù<OšíŠ0˜G¨_çœórD&(¯‰‚$f+Doc“Âokt€)Ow5Rôs1Ìt‚ëä|/O-2!2XÌ—t·Ä=°b§W†óq» 'ó¸W98’ø1q¼’cYÁšàu¬…ÏßX$Å‘¢m¾ Z%÷Ƽ¯ß%GÉÛî ò™_6pqõ‘ègÛü†¼ú|Ë–h­î»Wâtc+¡w™TÖZˇLSÖù0~™’€€°¹Î'?‚Ãr[mœñ™ Z‹Ütl:Löã‡ë¿ƒìéè„Ø ŸBF¾<›gÆU_ç ¾å…æ!ÉåîàσKÉ΂B¥w[ÊŠMžxZ.džKŒl-1YýrÃjA½™-¾ç‚ŸèA.ì%ïù)¾¨ø_¥ömO#ûCàðx Â9Ì_ùL = |¨êþìWBà¢o»r’&s$Û±H´h]rèÙ®_‹Ø"å §ãîe!˜uœ£Àå:z{‹Üó¯¨ê‚gxEòt^œulbÂÛ¨Ù i‘ÐûÛ¡{\8•“Àú–Šù!ÿ™€¥:1 û;#Gù'¥°=jÿ·b Ñ™b¬oë’ýÝ7\LåpàµÞ>b57Ú*i,añöeÏ “€Å˜‚4)&3Ÿž äÑJ+sëÈóxê«mh¡Ô>ýpË`±UÇ™’Äj*?dAp¥ hõ,™Ho–OsàÝ—Äýj>††=2º-“4ô¨‚ùný©2ßÂNGœ:)G²ãÜ5ƒ›+Ž  ?ÛÇðú Ôgc×\üŒÞ¢»É9ð7‘ɾ‘ꆟpN¦ÁF̼Žâ2ÂnZHàÉ:mûËCž ÛÃÀl$C`Šâÿ¬™æey¾*/†b¹Ê3& 3~v±ñ ÉÓ•‹ðËôéÛ%݇{àÿÁsI®ØŒ>•:ºæBØ—Þ<™ßÎ8I¦¿ªÙ’UÌÁ°]äËtÜzlÝnCísVƒéiZlxÙ išF!ðþÉòóXâl(ýƒùPo;FŸ•áü+é Thò6±;xçe༫DcUK²2ÙLT±_UÖhµOÎq´Ú*ª™*AÊv°/6o%ƒvb¥g¼ý‡äì2!š§¦ÀAWrèz…KY’T¢}‹ sýØC ƒuZ+ù.k`ؤ5—^_0ë•Üjà‹XmiñE¢Hìø¦®uµÍJ…Ž€&YUtK{¶©&c¾v~÷½ µT.§G—‘°•\]Ñ;ºð¡ÀûÁÊiZŒyŒçØE<Õ}‹M€FŽâ@EØÇ1ÌæÕÈÑ}\£‚õÇ…ˆ«ÃÛ½Kšý‹­!WT׫¢jÔ’€€ËWðIr!fÜ †Ê-ŸÙ–çv¯¾™=@Dðñ¦C<,ò©ÆÞ­Q*G¯p}am‚öp?—ø@‹ŽBéxÓ½¸Öº ’º£­7©ïuz=!ühN:§¾ý†œMuÀ €êYL|ĺþíÔ¦!‚Õ®Q qÅQ3|£¯ò×÷™¿Ë‚ÌÛËñn¤ÀÂUMÞ1Ù€~~&Ä÷aj ±.|ÛrI6N~Q˜ Œö=Ò¡±¸H£·¶T¦Äµlhu½ Pâ¬X¾…\ÙË»tŒ–I±bÊy$ÓqCçr'÷ a*E•Uðç[ÇŸí£ÆÔôX‰$>W”«Ë¶c ÞHË‚-Ç3ÝÏÁêsL‹ï\Î,jY°`©Ûª÷@§r(M¾iU×ü}µ’OiL,ð£øîš8%¢ŠË †Ö¬qVµßŽZ>°æ@òÆ]ËÉ4‘6å¯À¾%€²4R;¾¶ÄŠûøöø}>·ò’¤$D2xªS?Nù~´¥Ù„ËÝ>° *cj-¶´TŠ#k‰®­œ=€W¯û›Ø–‘¼ã^@Þ@<NÖ-#¹M?ùMªÔ½º/i+cVüŒœûVy¯+¤ú!O@|< ôFéÓºÿ¼0³š¯Ân?¹¾ÒÃ[!ñÂQ¸ ýÆt‚¹©ù ªø°ýžZÊÁ»oþ–?1ëVin¦°¶Ü5üL©ñ ÀvÕ —Dè£Yƒí v)÷tõðIEï¡.í¿ù@±z~Q‘g _Êè*è?O¬:¿R1úN|ƒú;^,ãÛ¬#wsì"ßR«ÛçªBàÚo8Ï{É~Ñÿ¤zc—3'Ñâ²-„¥C§R2µf™çP3ñèœdU©ã …"i[ç`kÊM:£˜Í0Ÿzëø¾ô ì%.É {’â—Yà™ ö…•IG/"Ή¥X?äæF!è­6gN-[¶øf‘5PNÏJ5ãf÷ÃÒ# ]eþc'€F¡clYïèÈ'jì8e§~ÐDþºc½=¾5Ö]« V{—‡äÇFo‘aÇöx$Œ ? uëÛ‰Á¬^vD^ÝEèLòÏTš“W®…ϲ@#k”@Å2Š&äó¨ mÒ*‰f ²}ó ³ŠëƒYé¹7?Ör=>+Ójô×Ìòú¢‰Úã¡çgžøŠ7å›Ö’€€ÀC‡YÍï6gÓ_rY¨Ë‰’Þ …ßø[ †dö±äê¦YšÚ… tŸyYðàn4•…î5⺜«=]&{6v#[ í&ÍEŒfëRøŸ•6¤x:¢æ:#ËŽr"{Ì`ƒ÷Kiû]sÿ|iFzÀšÖ/À—eJU†pÏþ¼ò.GÅ¥ÚHn#É¡HæuédKq;¼ÚúoªríF6H-bEóã`ÇL¼VIíÛOÁ¨‹ùe=VÄ¢˜@gdðs·¬À‘jˆ´ªïøÔÆÉö¯Ú6€ûBg‚ñ²\lðúÇWõÉ'ÿ”ßÖÜŠø–}Ã> z %7ç—a¸¢#¥çM~ùòšó Adæ]×çÉžÈÕI§jÑÈ ÝúpÓG²7ÆЕe*r÷ÀNx’fiZ—§$H‘¨É }ÓK¦ùQ0Ø f%:–lÒqR·,÷åeynÎýwW—î<Ü‘Ç0¦‘‘×Bõ°¼¸¢í­@ÖI}ÙDäIÿ›0©/# “J[‡¾;ç¼ð9M”ù)ÝÏ–¸Ø¼£¥™cN§ä˜îG;~Aå’Ê㿜€£C2KÔûq>®9xÑæsÅæ/(;Rõʼ×$ù·Ã[Øtû¯«þvƒÛ©„†egdðøz0´íŒXG«‚È‘­Ó>sI{Õ¼9çO:h¡š•¯G7#Åûböë ñɈùBîÕTÎ2÷xÖ‘\,a„.›pŸ7€¬Ìö› Š·ó\èT‡£¡òý¹ù±1Å?eñ¬†ó#/ÂìS4£mèåÇ‹WÔ{rJŒå¡@™ _âþ `[nÔjHÉÔÉU¿¯‰5Ûæs ¼b½GÉu®í?߸I)X ºK¥Ü*Ýñ}õÝ6âÑ.¢ÑjaC;D¨,G,xw˜’ñÕ]¼¦«¹N®{^ªíì„f> ù>,wD;­ìª Â;’åÅ;ÕB­ëj%r>~íÍZÊ®p‹ϽÍ%8°y‰ô ä`p¦ ÀaB¼k*ô4÷ØýC­p.À®*ïc³1µ9ì‚—eµÚÔÆQEôS§˜YÏ#›6fV_ùB»[GO&ruHPËîEfBk1ir$Ô/! :ÂÈs*˜àÑ›þZ ?’õn›$Ÿ›ÙMÉó´Î¾ž^’€€Ôˆ†J*0µ[`úJ­ÃÂëýékR Ï`×(Øësýϰ:7x¬ëœf(§¹Æhú„eoDo/3í´ ßvÎÕV¿I¥èÈ–ïÂM¤ªÎ;SC×— ava$úŒ›¼¦Z¥÷·Ÿ»"êˆ:°Æ•XŽ£aÔ~Ïœ «¾¶zsš@ B5¥†’Òn-mXÚqgb‡V„+íÊx}§)s¾ÚŒøŸÿÿ\\†Ñº¦R~¯C”ÕÖ8º,¨Ea/ÜìñØü±Ó· ŒíŽëY½´öÙu’Nú¼õa&'•ò`®XVÃï§~Š©rÖÌlÓéùêš OñÜÕé~Bðiòn,]5ú»À¦{@Ý.²ò®¯V?óÔøzÃp_æî¯•TãŽÊ§5¸`ºéyç2g}€Ü¤.61­~­ŒñýdSÆÍ8¿|:êãŽ[øŠlûz˜´¿ÒÓ4ò/0 äÈB¦îç¼õ/tõ H¬»)¡ „“(ÞxWlÇ™f®êaåß‘Wj¤Ë9¼K£ÕOÀŒ¦§X‹_µqUÙ‚jõõ¢ãs0|Ätf “|i=™ûbIήŸ˜Qk·õž7àŠ~‰GfW…À <¸KwQð–”¡ õôºÂ󇿔†Ð ´¾ˆSÈ~d‡Ø+šÔ\{‰|CÕ}}{F‹Ê=¡D7Gs©îm”„Ór äÿ9‰ 5ÀþƒAyëI|Åa ¶ \*3é˜*MŒõ£‘':Ô–¡Ç# ¾—)ƒ`Z§~Cz£"èÊ\bk_Û"„i¿bÀ' \!‡¡ç™"¦oP3©¯¸žë`!èJ2‹Å~U[K ÉJã _fýÏ’f‰Üj.Æ?ê"ó}ô`ÙGü¬=RÅ“,†‚š[V .×H~Ráè[˜6w÷Å5a?hå½—Ú¹½t'oÆÉBDÐ߈F on·gþyDÁIy±ïÛ%ÏN‰ ^jHò‡×ôܺ;Å\†O/×å*fÜ=}1)eGk yÅ% _U¿%n­ÍŠVW,)÷"“L‘Ó -¿Œ êS÷B.4R†±©Ð3kót¬’¤"¡©î ¢±®%YÓ çä~ÊQ–„zà\c>Ñ“ÉôR•!l Zî(|“J ›ÖýdŽPNÁCJÕÿêÚÒC°!WŽ’'W{²i`9űpè÷{iE7Åâ@4“~Ô }9÷R¾kœüÔðH<ìéŠÉ®C³ÈÄê@uímÂôâ²ÞZ†nfA½umÓIvóÜÏ(*"tj#Ëñ2·dñ‚ÇjrèѦN†•¡ YF£“ëG&”\>©bøTÃ̵6Œ&"”û¹˜‚V]ÄA\¾ø¶9XʼûÆ’ e§«¨œQB^jÍë«§†\õDV”t€•þ½J „Ö øi6Y¿˜™¢Œ!U²ÜDóÐ?™{çÇm«kºbÒ·ç1•%eGÅL‹ØÛV05“:_iüݲo¦D˜—rØ[ÛëMûMù©f 2°) ä=¸§Åú(u Á•Û”š¨âÉþö_A/±±2xcCïv­¼1ÖI“¸Sªû8Ü,̬©‹«¹û^_è]å<„ͤù¢Ï—Vm`S›0A’€€ª:?ï2-‰ÒáŠl°!ÇŸaô_|G åó/æÚðÃ_¯äx)bC[gõ1cw³ ÈLy$sVLM¼µÉΧ³ÙW¥IßÝ×ïN–cSˈʦê ò‡ëÚ÷¼÷5úb]Ü4Íb o#y7p¸¶=âr3ÀSXH1 EP¨–ÿ?´¦¢Y£^·CG¡×ð g9?æð¾Žv€‘ŽŠhlx壨wâ§=´xÿS*±ù¼„—¶!pÆå^. UÒVÁùQzj:–…+zÃ÷ÂY“[ÈaV4¢UœÛühc´Ì2UMǺEZDéÀ÷gO%³ _åmþµ\h±ƒv¹ÉaU›“Mc’‹È´Ý_'[Vùþ~ìW‰¨µšöÈ4læRvtRÏ× ^k½ÊLÚoAÉ"={`ÿ8F¦VuȦ·aíí'«TQŸ—%˜„6€¬c , ­'ŸC?úw Íc®»‡Ëކ«åkªÆt<ˆQ¶,˜ÜkCÒͯNæ{ð뛉®§´ÉѬYœ¨â”«Âc„žn slR¨ïáµÁV(=àWÑN“ÐHKí ݨèX. Gx5O_°o£˜7PG1|jƒúì6T‘1$#>¦Xqýf&Ê Äž™B¢™·Âá:4Gx™Ý‰Ç)÷¥¿AÞA],†jICc,=’2lfÊß«ƒWJ®9ôLÝàÌìºäƒ@KÂE+ŸüèÀ¤å¼DÌܦ¥rœíÏË\ìZhq³¥¥söè»Âëì|j–ø e[§FÜVò^â5|o仃À{¡WÈgÕqW;O?P_X㱨\ÊËĪy.²ÎšmpæH©&ñ–‘C! Sã–/ê¼c¯þã ·IãÖy\•ˆkÆ»•|§H’K¥æ!ªÒ‡$^ôű­âÉ+ü$— —Qæºi^Dc"<À}ܦì‚Q)´í©½-dÄ·â|]´×Òx\@LJ:ÌJ_h¢» =ÀÏáØ‹†–.iµYÿ{"„ca*6 9êxˆÆ–-$]ùX)UyV~s釀HÌü¬ìŽó^v&kŽ  Qš"è´‡.•vÃOuF+€°IùAÃúY›ÍlŽ““w¤ò×ÇóÑ:·½Ìõóf÷L\e¹K`ó‰éœ€ˆÖZ¹éôýî‹°¶A“Wek)F3]™ai”d¢Á7—úÁ6šØÿ:—†¼?DÄ·N^ˆì¿"ïÁ‰EwÜ6"ê:Rö¿±G¯•(Aª¦g'Øíú±ˆì@.a¼ßÙñ·Ë¦×"¢ãŽu®Ý›W6Fa$fӳ̲µ 6|A4{ME{xýƆ)¤ ;/kÊðÂ/¥á#í@ØáÀÒ±;}‹GŒ‰üV>†³Ç/„DW¼b]IìŸ4žÓTOäI§ø¹<‡—?¦N¿UWvu÷(Oy7íÄ¢áêr_§8¯%Û+®=hZ]<ç,áد¤¬Bµ6x¢°t©º¹Óãô^è>k‚ÝÙà‰+—̶æ*<È \<²Ib½‘® wþd\Ÿx§ß?UŠã‘dâ6ÖNƒ´L§ÕDÃdOÊËs,¨!‚·d˜ÛlÔò{ŠÐÛéåÑûÛ¬3ýT+’ùñíð8Õ©çušR-²l³ÛÇ#×äÆYžX© 'ó­Í(B;˜ò%^jávº…E°»1ÑO‹)÷*bæñŒø’¾4f¬’€€Öé£4L,Õ:õ z£3£wí뾫÷•a…ýÞ¹C]’$ÞPpÆ&ïŸ3¡œÁëÐÊlþ]>]‚L.¿ó’ªŸ)F®+¿›ZX?¨A§I“Jñ˜ó9müs lÖlr ÃÙÔÚ…}4¯Ý=Ê)!™©ÎŽ’¦ÁÊ[ÛH|œ¶Ñ"a´$a7Õ G°ñø/–‡°'ú §¸^ØÐ)ò\?…׃Ϩdtü‰â'_ñD v¿Ž­w36Mð¶'ŠðC ô-9€t}ßø¤Ýu§³‚=U’r«akñ•»:Œw.ûÔD]Ð[C¼³ü¾ïÿ\5p(!ÁÃfÁ&4›`Tí´*ð˜kˆ+®#C¤ðô9ˆPõq8-o GMÙhhvºÛS]Åßòæ´‡”Ù=Óò¿²¢’€€°é«…Ƥ |±“ŽÏaõä?•Ë›Òñ|†ÚÉᆹ.ÀÄ>YøÎ‰Êw5…ýH»Ð©Ç‰%å„q4‹)Ô…7û逩¢ŽÑø ]à¿),¿·o~…1¡pLà½1NuQL†nWP‚oCÈhZ|’ú¹•˜ˆbõ"\Ç©ƒÆaG™I7¢"Àò4„nZÐôûž¢Û_åx«ÎZ:LjæÕJTŽø¸z¨”7–ƒiÜ‘¦•½]*2Ž"¼H2B¼‰k|ìó »sHÇ ÇG$UcBIˆÚ 5’bo¡´•ŠÔôX·ú!'ÑCûÁd²ÖFD ^ØäÒ\‚Å© 祷’E…{¯4•ª¥qÏ7ÉVKßbP×þ!HŽ ذÍAbK޽=±Ç.*³@æÔ=mÛCVëÖ·|5`ô øÃ™Äô—´¢îýbâ*#é’ ‚ÚçI ™,p†«Q©{ó‡Ï^÷„¹eÁ™¡‚¶ÔÂ]§¾ÿª¢04’€€Òß\{®d©ù áò&„h?í̽˜±‰…E|Ä‘üx„Wïò+䇯¯^»©‡áqM&³yDßÈçŽ`¾ œØ˜ÙƒnP,ù»Å'÷~OµV;ÓA›j{ ÿIŸ„IWËQYWeBƒñ,Dߌ5C7tLæ3x,ÓìâAúÆqöŸ• ³0=‡†û]¡ÒÔ+ hó/¿-q±^9 t¤ ¡)umÜá ÁãÙÁÐÃà›ÆÎB…G>íÖ®FÑJéˆHtÏ”™ðò{ÀÎÚ$ÐÂJ¼³ò¾¡§Ñ”e·¹õšð&N\š¯7àñu|Iƒ;÷8³ 25‹…Ðû?Þeùq ô»ŽÈÓÖnŒ«I,ï`„Ç„ Ó§iƒKY-«6É›P f£ÑE7 ˇþýEÉþö94ö¹€³›4àT×ù¾k=‹,ÑyBÉ ­ äxƒÿ­û32Ç*¡C.UêI.8¤ ÿá UðY®³¬ª±ÛÈìæ‚Ú¨xÛôï‹´9bÕ•‘È <ÕÆ•{Þô„‘ŒÖ§e Í\ˆ4kó¤ÛÊohS:WÚM E®v¦^ÊŒ!£ÿààƒ?« ”ûÂëö©âè³ ×| $$Üž,°Œâ¥ú_XŽYÇižºã‚nâÚç¦sžõ†ü#äWs£…ιü²¢B×þá[Õ§Ì•ojÒ£lGã÷ A7q×Ä(éG¢[j$ éò çÚ †$•$¹­Anªì`í ©±e³×ùprÃAw•2ª¿ä¸”zi ùÐE¹/² œ¥f”"÷l⸥á¤8½#U©ï° †,®£lÔÏÒ\ }fŠj| ÈNQ‹½–›•ç’€€³kïì/5‰„å…ù€ºn*”ä~ÐxíçSRãÎÍ%œïæøM$B4ÉD(Oî²›°Š‹ãö]± ~VökSc‡ÃBÎtBEIz0»prç–ÄWӑݰù’µàU3™LáQS Ï5Ò"7º˜œÒ¿Nô@êË0ˆ$rø‹à>Y³€¼cÒáÌɪZsµ:’ÿ›(a×Õ\'Úï¬ÈïÍêµBåï¢ì[‰kYXvŒ­,®—¥Ñdi÷Ò3‹Ûq¶f’qþ ý»U!Sæ¤ø%…Åè$¤Þ»²Á¨²•ûÁ Ä,a×îüåÿ±  HB=ï>{À r(kг£iÃÀ"ê÷^ƒÃhö“±mÇ3q[]IÊuY™JâC1L‡a‘ߎ©Æ"‘062ÑÙ{´;_§mÝßaÍ•Åh<îJåR¶ÐÙgÄ3¢eçwÉMس¢ø$M÷öÆsE«c ì(6Äô˜ÂœEÔ!ôb6e®U‡œ&ÖÜ¡‰Ÿ÷'* 2¤ÂOÆÍöieŸv j2H"õ“ït¿¤úÿsÂ/çÄ/ÿ=¹HÚ’³{zrH…l«¶Þàé´´µs6¢ck ÅE} Dx qÐ'2•ÄÞTq8ø>´r°*|“6Öù—wT|rÕ‰³ÝôqØ’¼O*ð¡ê¤µ°áù?viPf ¢'>šk¶UÅ;)ºÙ_ÑÈ0ñEb·Cñ9ý¸õµGø_'W©9­i«- ë5عPR q„ÅÑ\°tiªWñ?iWÒééÂÙ!Ú˜½ 4µ5jž´©O˜ŒÄœ t‹I®ÔÆ´×ÐhÑ^¯ŸO8 D&a†(KðÛù°„2$X"·‘(F¤ŒÝ4ºqr¦§ù6¢fš]ì›1׆³^‹D[\Xœ†…øPØÂ¥zV²²ÁÎjùÒ$± ·ý´‚-^Ï=üÄìö˜‡è=)L u˜Cü5¨Ô²«b(Ö&Ö1Eñ#5»°¥Y–$çéúé/2Âõ×w9“‡õ—·úSAÏdkIöTZ ˆ°ßt·W¯ó2—"Xþîš»xþd;2FèhG‹“Vè٘͗jO€—Pm_&á^­ÄõlÝ4¿öÙ²ƒf7áp”€’˜é Q3è"síâ½ë(êy½|é’€€À^ÛQ¹I¼XGu®Àu«– 6 _þ-×…6Eôæå’4+˜MÉ)+­Iš"úÒ=h_ñ”²‚D\ËvO´Í¼¤×aëwÑóä¥d>Š´ºŸèDÍÃïVÆ’íÈèEªle»Š;¬ ð‚Í–µÅ TX ë®eEÒWœ¿œ=ŒóÞÌ5è’L &—¦šA¼&Äz¥<ªš#²jC>ÏÅ:+ Ø;µJÕÙ’Ôe…½ÆÜ³6ºðjáž¿C¶¸>@^„+·Usqcì öª>õ=ÓcÁ,@9«èbÌ)8Î#Q°:c½ÔwÔ°¿² I [ž5àd3î Ã;AL—6ªpØŠN_Þ”øV ªÅ@§Ò°GŒDPE)·xĘ—˜nˆ}Mò_“‚ö·aYXP˜áÂfK•é¸|vÔO¡o°æg:7_úñàôD¬‘60;Ô[ôÚ}V»A7ÌPí èÐ^IZ¤¿ÐµéCo–´c*€þ,Èfš²ò'Ž­ EË›ÌGÞµfj~QcÝŠ/vNmÂZ£› ½’“ñPU4¼¼#ÉÆŠ<{OÂ!d&Tî6ùlŽ\L–üI\tžQÉœÎ$^ú^,´%œ82'GxÄ‹{å˜á<"…âógpäÊ]¨êÖôñîèS£äiÒà"G—Ÿz3¶(¸+þh^óCw\÷µZ~ïåþª§ ì£U/Xª÷o|b›úÊÌ™‚¹Õ…¦1óÇÙH\ã…9–šêUÞ=Êð/rp]ðß¾y„„1EKSž§¾~ã{þ·×ÄöŸ¶}[Fænr’ô ÙȉòÅ&•ÃãÎ"0cÖƒÁ‚~ã)®I”qöÖV‘¹¿ñsW8¶P ¬©Xˆ„…§Dœ¬¨@‡3s”ÞÍפ§£¸O#™¯|à笧SÒÂ&î̿٠âð¶×ÀÇJas$1šeßi(5;‰™Iœ ÄצÛM™U¢gK4Å@œmsi¢m)€îæ8?Èß™6hQu¢R+âZè.¡´U'óÀµq(ŒeM¤k?TPÙ™Š‘­eñº+ƒGó©ãáÌ}Ÿh§4Cû¤Ve­ë Ÿ*ô^/Ã~¾UŠ{6<ðC¹}!aü¹@É-‘¢0s…ný;âDÇ*Ô° !êÂü'ò/ß)’€€Ã®½£š ££)›*½%¢4ñØ-ÿÒÑÑg¨/A‹ã¯"-ýXÌêEwÙÏ8fF†îT£˜FÌèÒ[øÙÒ² °ð×G¾ÅÃb¥ù—^/9=]ͧDB蛟ú­G ¯ªÊÇÇÜ]zàå«OòtÎ.$Êl°:Û^lbÌÈ*E‰d€â*¿>Ó¹- EÍ©*`Yü,Øý ör!‚÷¦â¼n{3£œW§<âhž¯x00pš‡Ž ññj=u…(((kœÊ[ dZ›»à•}úç â”P°VœhK3¤!HC&Ì*ºE®F‘À/šögù1³æ&)4ïyúùO–ãë´\äaýùpÎ]ž#°4‹ÒQž”¦šk€j ïÛŠ›Ø’ª€õT–&+|(Äj³§9„5^ö¾¯áÛË)½|s[ ËÆ‹ß}€°¾€œfG%ÌV‹õQìÇ:| ×'`3¯·ÛÛ‰#à«ãIåJ7\CÕµô?v‡vU¦fÖ„¯kûäce‡ó4ó‰@ÆŽ¡Ó°š„c±Ý,‡#kÑä(xÜo‘a•*Íy]12§tãe}Q%õ¯?NN?ÝŠ–[Õx¡=Û–‡!’Çz%b°±œÄ%N_u ŽeÖâà_c#ûÅÏ…gGcª™‰!/ítÃC?óM6º¾Ùi]÷Ý? (ŸõÒG½·Ã×ÅLhaÑ‡ÒæŠåuÛ¯ÔS^z¥!Iz×;ÍßAÁ_e ~ÿ‹DF~'ÄR‘jО®ªŒa²_öµìÐùÁ,Kpú™¶Toõ8LnTnÀÒјÀ‹“&JïyÕ¹9*ÕÞÇ0¦ãí,-|¸´ycEUØðöxúäçYÙì8°-MìkV¨ j°Bܨö1x Èeý„‹Á´çüZlþÝ_ã qsŠ[ð£Ï@ÿ<×¥× DIêO[«¡æ3•”$¬®VCP îÍQôÛ ç–hÏáÝ›[¶“:Z]³–¸FÉ’=wî[A)ÜÕ†ëÑ#T ÜzŠ»Nðø%¡DKiƒ²éøšÓOuKå~%`Øåù’€€»ÿLò.À–ÄqâsÍH½–+âÓ³|ËG{ŠÑgð½ÐÁ³ÿfy„P@˜ëcªÆ¯"Oþô,5£â>1Û¸áW–»ìîΛ÷2nqx92j+=6k½Îð¼üª¬»#"ŒšQ|‚µHÐV ¾‹‡ó$¯ÆŠÛB\4uÂNm¹­4,"jôŠÎfP†3%p”ΖO±^«ÞkjýåÌ&T„ð†ýº†%A1ö[â€î2»1Ð)ä+X†i/hMô_„µÊ9øyÕ j*8]'÷1íç¥?1ÿçµØ{˜ÚTa½e2c˜:1óÎüÆ»š½[_;ÁÒ¯Žy¼Æg>­ùÅR2²&[[€íì'ã˜v?,´ùÞŽB‡,uªQÐrBnHªOvÒçµ­ßhgà ¿sB–TÞ8oÈéºA'm´ˆ‘mËœÉæê1^D;@ O“R—§Xá5—²GC½;â¹JnÊ<*DÒF‰\¦•Î\©p2õHêéqåm§½ "³ÌŸ»ú˜¶øúßáÎÁ6g5Ã4Å£å ¡`DM£^$>”èÄ­p,tà¬_Ñà^äÚ°ç=ggëëS:%ÛÞ–¬Ï÷šõè¬ë³??×Åí%?1–Ò‹om÷ÌD©¶§¨W†ÈyêÓUÑ 4åQ»‘ÿÉ÷}«eK©ôoKw²eQá×8sP]' …ÑåÉ+u ª¬RAýwT3ûÙÜ:T[‹sU“¾Ço°|Àªü mPTkÝ6uK=ø¹ü/ãM~·—žN$\ê½k¹ŠG±Ðúe°‹C…|ñÂHÀ@©æÖÎú©€;‰¶Š´cýlÒMý“½õ=B ¤ð¤ŠJˆÑÙ²§í”ÌÁgúÍ“ÝZ *ŠJbM„‘Ët ©R–pÑ»¼±Ò7)©ÐXŠzpÑ/¹q€{ÿã RYì¿ë¿|œPjÌ[ÊŠ…ì¸ë7%„OùðiMë͵EgKøƒ•©¹=ºQUÞ„Žxnœù×BHÅ%q§3HšÂJø–j°¤seJ¥Ëù$D8/4ÿ/‹÷ó*75ò’òN8Kž”A't{ðj×A¥ ,– ë5â2šJSZzuÀ òQÎÑ»K4¹”ö½'ÂGL 7û6­eÀÏÑ‚é‚"[škdO• ~Ww[úˆ½J‘D©ºñ¡mWl¶mÂâ~Äåo²$}c|Í¿Q…ò*—Š&Gèñþתx¾;î…~¥ú6y4DÄ2nd‚dÊQ·ëÖ(Õ9OjEeÙɤ²†Jж³)*¢ðå0m×Ìp°x±*9ì¹&7­§v Þ>Ýón©v²qÆ7ÎÞ6Ÿÿ»Ãfm=¼"ljjφHyíº“áÚótP0H³žÃ@@áP‹pd®74‡lʈ3áŠe:Y8× /dÓsP!²ý}ëg ¸Y-%52'JΪôw’€€³ r2£Â9V»`8þjßšbåbÞ;F–eÀêù$T¦úeXàV%Ëq”c¡°ñ0cÛì<ퟘô±™èdQ.g.ÙO Èˉ$å=˜÷L ¢" ÕÁu¬ØçÊÎ{ßå¤a v^kèïnkå6µ}âP±v6…rûΦ— Ó`¬ÃØ+vî05Â*‡9°l’(6®—(žLn3ºê$µx•'@‚\ ¬…'·YËfæ øÅÛnlÒÆ®ƒü,^‘†mÍ¢Äð(5£×G%s ¢Ç¿·dãP›3}hǼ¡“Ú Ô('ŧkfŒ˜Å÷áŠ;¦¢QŒSw¾êf§-“)¬'Ô§ð΄ŽJ¿‹JtÉAgÓA³MúæPöä¹a¶ÿ«ûÇŸ° =6\ÓoÀ™*ÊÜ@ßþî\PÈO§r0Z†t5 ñ_%™!›…µ‹zÑÔh9F~î[ƒ¿ÚœÌ™Ág@Ç/Ío6ÍUÌã`¯Ýßç˜Gxg0Åæ=¢åjA™j4ºÛPÎWb —×…P‰A9C‡«HK눾cÖ JÙ³¦ÜÁz7ž/Õeâﶨ÷CÖáέÃý¸ñÈ«xÏ1¿[ÞEÖVÑvýbÕîùŒó«•¢|£›bÝ25i[Oj)V,ލßÍÁä%°2Ë>6Ü’ú)uÛœœ Ô<)°>€C'†…œÕGaÌ,Î8}gr R¦7ŶÒVŒ]ò­ÎíÕÚõO‘Ë™Nèi‘e^ LÁr(åô«UP F1^ËÁ>ÿ‰ûmN„–÷4ªœpÕæÛàuú×J6ŸhjN·¯úLxÈæÅh–·ÌF Íå©÷z†Ðd~”€Êo¼”&‰•P.ÃV[íÆp˜àÂH ÚLíóÊHÖº®ŠÀUªåäÒ0Waët“!Ææ‰ã÷‚hD³ÓBaÙ§,æωñå)ŽáHP»™¶Åe¡?‡¶pC¥'ž}æa·li¸aÝz ~õ2/¦D:Ôy·Ãø½#OÚÂkÌo™ºÄPÞ£E`»p%+—r :ÎözîÎe«1¾Yåì1¡vg8AÜäk½a´ß«Þœ.aމo%ÝÊš~:4 SúûGÕ+xcò·ÇÑ”e`'xWÐX¿üÀ‰¬U§3ýSÅ')¶’€€ÃÄþ IäºK¬Klëz0…6½ê.PQÀ3–Ó€6Z#KL!4Nl±rçïùÕ)Ë ßU£sH³æ´ª_V%Ùþªƒø“¥>u»çˆ5pd…(’™e©¹ ë‚g'c|³…—A—‹`?t@äo;ÓˆŽËnÛÔÏ~ Ï/GÐäG•üÏ7Ùá Ðbs*ÖkOÑ GUܬò´·_ôš¦ÔÕ,‰{8¦æ?3w%}Aô0¼BÂDkf~ð¾®%…tä¢xcÿÈÂÄhyò˜ß/÷Ï'žd¡'úŒeÓ>÷Û&Ì#.®–pù&ݧpLÛ5±î6q×Ï—¬òi»x§‹ï¢FZ³MúžzSÂz1¨ûhg½¡—on=¨„9û̉\Zœ£8TbÊm¢ê¼¶VY'¯]Nk°Ø­d`ö–LÉ%l“ª¦g/Õ‹=6Æ,µƒôîîÿn¼ˆz–p ǘ&|Ŧ‚Ùˆoü)·f”…NiWÛ+ù²©­…,®=[¢ÇBüYZë¨-“5aj[Š›7=:äÑË8ë×â1Axt®és*à—-©¶å‚€?+Zch§›6—S¬o^„ [AtŽÌIIO\I õöï¼bbwvXÔ«ÏC.Ù{û¯3Lå² ñk²ÿôî_œ8¬þ0àªü.ãã„[%`Â*7d[ÆÙŽßâ ËSð‚£ÖQ6¢ˆ>úTH0€<‚xâ¿7Eû ØÛdÙÞ2‚8 y)Hk·7TCù€å±³Xz{œné¾6 ùAÕ±‚‚±‘*’Ñíg ú\}èã·èYdX¬>G»¶Ñ†¦B’€€´ñSiLÉ=RŒ¾:§ýH=Ð N*µ[S6²6:¥‰ã.ä—jø°§LP—ÄX‘.–“[¬{‚ÿ-XT¦”žá:6¶_<§š”Ñj”-|/èIÐ_0ƒÑ3ÚP -ß"¶ñE9)å+x¹ì°ó¡?rWGƘ\ v|ñ©¼³A šåi+' Õw¹`®Ë²â½Ñ¢¾Xÿ9@ãÉÕ´{»’r¸Ü7¡Œ õî`áѼ´ÆîíôýJuŒ3æzN{¦é#ü»hÕU¤ñþëб]vUP°JÔôÙýܳ@; )dú2]ŽHfŒxnºG-ž‚„uÃÞ™Ÿ;ßà²3½*gÝŽ•ï ž±F‹Df°°¤hm"4‘·7,øÄJhð¨çîuç‹Ã§ñw‡Iñùèû܆cižâ+VïÎWC©…yCÖûd¼ˆ¸E±ý',湎[gZu¤HP:`/ª:H†àä# §„»…_2½¦±F¥Z¼ÿekák¹žÛ@AWB”b}Œq[C[ÖcV”£5Ô0ÒvÅ){¶NùD{Æýá C?˜2«nÑmëe=¦°ý)ÊÆKÅCVÈö/ý UYHÈcSÛ÷ôµtvg Ñ2¬B¢ŸñgåÚÖ†c6õÌÖNzkÖ\ìáß­:7-o¤èva™?ÈØÃæ9^:Y§äA]PÛp£Âr–¡ÇÛHNSzôƒÍÂöª…«·–›I}Îçøñ9¡ƒ­†E /=ù‚ÓÁKßnYo8å<œáã’€€ÁÜC:¥â ª[§Rñ@ØNeƵÉWmXÅ{Ÿr†N‡YŠ”ŒÙìÝÊ•,ã•@²3òˆ8€hø\P9ر…ÿÿж µ € cƉXð>™x•ð½uô¨Ww¯µ†îÇ6™’"¼*zŒ7©à¯”¨z÷Ð9ƒxv6£YÖðMéÚ±ï‘#²œ—‚´õé¾8õCb|~LC…X¸Œ8Mi8†Ã·ñû—¤Í´û‹FVŒ×Í(¹c—¥l+Ê–›×;Ù.‘|üMo)Ì0ùg­°´÷ïW‡.Äš«–R²º’¾†Ïo(÷ɹЯöò t‰ ;ð÷ EàÞç±Ö&%²1ì7uP„è ?àHøÒ¢²¥¨£ A¶|ó¦‰Û£Z¿äâëo^¡cˆ7‹*ýTó ðװϬÅ;Akâh€nÂä#%»Ë¬7ẂRÞxªˆOù§*Òëªó¨N:öîÔÈù¸q4V3$ƒ®g«˜ÒaxŠåM`¬ÓȬI苾ÚÒ§È”£”û•2t81 ¾ÖÌÏö5ñ9Zv$æ*XZ#0"Ý`ô(–°Ñа½#Yüµþ|ã" tC?õ_€ôÙ\>µ¡ AåA®áVr’ü°ðûû»ç¦Ëˈ] qödÊ4ž%üp4†+–j³?/œZ®AŽôå¡\a-r&z£¸ð*­á›)£ªÛD|ùl.qŽÆ ·Ÿ£ë'®©â3,éë-oQlVX"B0¦•R£ÁŒ½Á¿”ò´ÿÚÙñКÆvëà ٞ m ¿Êa™Nœ¼àMñš]ág=¸d¾¯Ä˜z—ÙC¯•­Ä…§ŸçŸ *m³¥òNs¾EJÅYG M³¾¶§¿í“0dàT¯Ê\?_s-ŽTÊòÙ h£ ükÙ‰òQXŽR?B´BÕö'º;›5FùŒßJ¤B¢ƒ”‹Ê)‡bîàŽ߯ìJÌ;[ÊùQ“ˆ4éñûê‘}±Iô„Zý€@ ”BTt×I˜ ÏzS¦“ð¾œõÄ¢z%¨¿"XN­2®³0ÚE:2ÔEãÍü¡Fnycd]´Ô5…‚VEºÇA×íð€iÍÿå½t]‹V+¥zWüäŒñ6ÁËÇê¦Ó–1e*Ê1b¯âÍkp÷©·‡mßqy7Ô=e·–¥n½S‡f¶ñÅÍ´ô_Å&?Ú7 —R!DTƒû´­9äè@YA¿ Y‰ÒðLî -<]¾ÇxãÔ£¤ÚfÏÑÖk£t?§x8Œq¾ŽÓò«?K)>Ê*úÅ9ߌÊ ¯Aëºè®±hnËÀ¯Ùë5à÷0áœÅ)ÆÃØûbyoY`6¡sCaÑ.½.nH‹ÞÚ@ðÎuûÖ}$iºR`'l-s—QÛ–È+…Ø‚(‚ÐukÒàoÃ*7¨K拉ˆ0)+š‡- Ó³úEÐÁ%L-x[ç[8°ªÅvÚÅy&¾…@˜ûÐðåÆÊľ*y3SóH=p1¸…„È5ß#0³Š-5å‘yW‰}"õÿ;íEÊ[W^4¶3…H'¤Œi3çF)+Å„ J8Hn‚, ’€€òK£)üõ™¢®†áÙNkš"–Aÿ]é¾yîÊ=ésÖ0«ž7Î;y¨Çî ÍseNE}…6ë0|»¥Ÿ {^¿¬ÿ,6¶Lzãsâz;éFúšB2Ê©¾“Y»–ò.±þId=Ö8ÒÆ¾ 7^Àh@;œµmE7‘,?_À)i óUQü_[œW¶$Yܺ`¤ÎÇK®#T®ƒŒøkó³\81{T GžBo!“4dŠàÆECtwµ9͈™f¨:ŠV¶‘FÊE/_™}åN¶åm&þiˆ(8A“hº=Ô8ûžiâƒ4Ílk޽‚Ñ2á…b;þªÊdkX' `0•¯*?Û2ªm¥l8'ª%Êhâ1üš n"£b= —Eaf¡©©ÑÅ|!n¬ –FM–Äo¼ùå××ò&ª_à»uÙkTe9˜a“§P§•2 }2HÚâ]äút`zMfÏv£Ê™«bb*y}Xû°ˆGóK“*| GÁ,j%fÛíøÄ–‚xnIqŸ °ƒ¡ÙÔøÑˆD)V‘’ÄY.{9oã¨ò}ò€OW½ùÑcsdtF|èrê"4Þ?ÑÛÇïeýZêœ9õ–º€b,ôú[z¶w˜´=wLy}UúLÖMLœ{·žI¼âÑìD- ²ôÒyûLøea½ûY–«  } c6ÒÈC5bD­¯£p¯[Ž<þí{ñ§È½ÈÁtÅ]èRÎL£ºtDyNeÛF±ÌÒí·þÝFýÊÚñ}´[>í%ÍçíÇMx°Gy ,'nÞÑÑ€(ž˜Äic÷Ð"íΜ/z8d%…ÞÞ—K %Z¯1Üe,Q]Y£¬\þšˆn)FG2«îÖM®Lམþ”4/µNG£C,þ1*ʳXRv¥âÔ§+´º/y[ù™ðK‚Xß|˜Ý¯Î9@ ±øíS) Åá?w†aûÞ…˜ÍLCÂèMX§'N¹¿·döº4c5ín)tÄÞlDßÇÃ*Ÿ¦—…ÐE_´¢xh•HR]ðÂåÖ§ö „DZ”;ÏÂ7â™6ÓK„Ïé¢s•QãÁèçȯ ¢Å+ßN²‚¡-Ÿ4]yŽ] ÀÛÌVHȈÆcbß^#íÙ+}•e5þ’€€Ê”¢“f"a>êÎ͵‘Ä4ºÅ‹cÒlMàéNE¬í»N|xËËðßHú~cBøà°Î»ÃDL\h×áÓaPÿ-ߦÝŠ£Š¨“D3qõç×ßs+¥V‡b:o섳µUìPÒ»WÌIfÿmX™dXO泉§ý$Õ«pCExí.‰Ê /„—ÞÚOÓÍôžÿ, @°Gó³E“IŤ´Áb†g×=KöZ&KèQ;n'z߉r£o¥=.Ìù‰ Æ8N†«Òk€ýãðÐÙ6z핬¤NF/†Å l‘?{OÁ,þùC-A¶6R«rëÎîÓÅZ`QЂ-[Ôu‹—yÁ6Ü•ºRR*Ð~(ŸÄ&Ž’úxnXçž]KÀp `7ëìå§.gLØè‡’óóqìù–²Ï©Í˜Œxw(UTKDy¥?pQµZ¤0.©|,i¹sÑÈ‹}Í‚t DÏ"ËB ‘ª]ΟL6­E¾¬A¡uú1t“¶án Y³™­ž;)Ëæð’&ËíñŽ˜w 4ˆÑ«©­›ÈÒíZ×/üŸiaaJ­IQ@Y3¢}MP™Z£ßŸñ XÜšêÂݧ|.ûZ4•|÷âp ï–מÓÂ÷M¹LTXçý‡I\´GÒxúUõ“}-¢yuÔ2ÜÁ7'‡-ë'Ïx‹Ž]# øb|QÐuþíV˜ß]¶¤PP†}ïÀ¼£c"ƒÏùwó;þAúi;`,`é°“>…BôÄCJÉ­Ç’êAÓ +á·.R¯¿¢½=ÜŠT×Kã+qtóÓÄXšˆO/•HûL:.‡÷§´J ôUDžxÄú41\’‰a»ºíT%¿‚à/–˜OLص³CŠJšðþ¸&§äGë§qú)KÞO^(t*½o9—($&ÿrs\Ë„¥ñÇMŒ!òð‹?šD• $ÌS÷r´|nwEêTÍÐ6p4sÑ7ãÝbãªÛÛ|>Q/@5•ÞÖtV”ŠâflÒÓ_ç°ò`¸siÑí¬ 5E£‹5#’õKðXŒŸq²úÖYÑôm‘ÿûL}Í[{ײÎ7Ù\:,ûOñ&Áã..[®NL#J~W.:Ó,’º¦Ô,¦ªƒŠ…¡ËäñŸ.oÕ[Ø£Ò \¹ÉØé¾"LD`æ4>ƒh„x¯Ïi1õç!@ýš°6]?J?T 8Èf_ü€ìmÀ©ok–Åoæ'dx‰™A`#ŸD!ŸRÏ€d—I»ï¢Gk}dDTqzÔ°ç±K"ë´Âé–ÝWr°ÔÜ#v”&{ê˜ÖN öJ Tç°˜x ¢/Ó~Û—Œ0uÒ2!7mvbC=¹E€MÅÉ/Ù¨££;¦l@¥ÕV;aƼ•~–˜m9Œ™–:;Xh(öÛ*³7¿³ƒrŸ5êUB}ê! …<¹ä&Ï€ EŒ !ä¥gœk¹ÿ±œs#ïFµj •Úú,ªqá°Øÿ_à'\4—å¾S*p€”‰9;'•R>J+Ã^S#»íi‚ÝC :ñJ±¸_6'Dèуl\G­£,áð8S£vê‰øª_Vqw·T¿›&Ÿ™–£|"Bö­S„¾@ rnUèz=¡.‘tQA ¨Æ8|¤ò˜¨×´Éî9;kÆÚ­‰§ÊˆkqìËö,a«mùß,Ô<=E\ýb¹‘†Jþ+d¨ëÊTõ¸u±}ËÖÌHÖF¿Õ¤*îÖÅž èb 3&>¢ZÃ>4!ÇyØ–@Bzo\¤í>:¦n];ú„è5ÚE´›•Z¿np¨s»¦8ŠÛè ‚U£-ˆŒ¿óquŸ©ù öPF¢·Ó8pdp]xòµbs;.ù]nêÈ M„ήÐJ¡é†`:½miYèƒ×çÕ%X˜ÐÑfôFÄ ?Ó2ÕÉÖ×ü"- ©,K{“s“Ö ëw.M^·+g©˜ñìBºa±PS/į*¿Àï"ŸÅ²îØñ/záD­z/ÞìBªÝdN–k„·©‰¯(ø+ã- QËGÏÊïáÞq¦¾øç´ïQßeNq«)ÍWI¥,œéCoùaÒ|H*PˆYÆ NR±ÛÑxà>ÜÈè9Íä”Ý"جQ¾`bYc»›H‹«Ç¶,= WÛ}Ò‹¾Ž‚’;ò ¶{u#ÔÞ”äÒ¿ÿ³]Ã<y &Ua.YžC|{à'Fn_ƒM“gž`Ü#}(I6x¨Ÿ'¡½p,Ó!#tàœÆãXò'’€€ºÄœJHîÇû¡Ö-º4-ÂrH›„ÙÏê`@³ z˜ïª‘à_· ’gOëøC]Míš}ê«Ø«óˆjümŽÍ½žA¼"A3¡eaH»ßCÓèù6ˆáiÀIÔ?ã»Ã †5äÙþÄŽõâoZ“(-&×Ì%kÑ—>&NúÕfÚìŸy9™ï —‘ÀÂÖØ3n°\,ÿåÍ HæÉ« îHÊÛpc@zJFgþË9ʼn¯$s*H]@ðK’M®P‡vqÏß’9£¹2ª»˜O8èIùFšsØFçþ7{ã]‚p$ts$Œµ'«v[@Á¸™ñ?Õ$ '¥ÖñúÌ,5¼ä¥4øœ tæ\í·†é9T)˜Kqõ<´{LYíÙÞ·ðAšP?c&¹ocsÄSŒÃ®|2e-;æ:…ñ͵©ßz`'d@–×õ¯j¦Š‹c´å* DEæ8€ @/ž[ü$ó_Þ6—¦¾sŠkò™z)Øê‚êœûpºšøÃXði¥ "X|I'mÿàYΖtóiÖ­d+ò]åž*Ë¡î‚1ºð’p>js/?üšP*:û»X:T‡2:›ͨr~l¯j¨î¼A‚ =Þ»]RC¡üÁ8^°˜ “ ¶iŽÞÁh3;ט<· ÊëN"ˆ÷­\W*œ”šÏ  n¤‡Ì>Ä÷BÙ!gÀv%Ib‘'CN¥óª¨,9’£ Tú7W ¨¥Z­°‘õXN}ìïqØ1*8™EÔ5§îÙ+ˆÖ\®Ž {ÂŒd´Ì,Ñsé=£ ¢££¤Ì“,gòéÈ•o¶<u~-o’€€½Œ)÷š«eäŒ.»X ¨Yc1D•ŽßÞ˜¡†…1F:óLAþ*üôpnE‡‘{Ü´]DÛ!ÃŽT!~<ÆÒJí^8Éc@h¿»ãÜ!>7Óü…¤ügatTÓæþ’´sSÎNí1r¢§üÉ<´;„¥b Ö}m¹x8r„C 8^D,Sñ»¢ÛÚkO-× ,ôÊ;Ôªë^BN –³@,ù¾Â2%¦T-›ñ›š6v5ø×½Ñù@²²üŠœöïŠG'0BYt=ý(¸P×y‘ SÓæ–õ ¾ Ά‰RÿAQ SVè¬Ý—ÇÊ´õ˜¦*\Ú8¥` ¡Àb¯³Š¡¯VCnhÐ}­íøafÐ’†G"Ñô¿Zi’Fk]<˜OÛ¤t† zˆä¡bã’wZ —8îÞÈ‹ÐÒÃÞ ÷æh-5ÂñS‰‰¦,Ô}]ã]­®ÐúÀä@Rû¢OPÃSÊìÑ‹N­e)°ôwQ3ŸFÈKpA¸ÂþÌÔU-@DR$§šÄÓa¾V6²enFêík$[6³ ¥¼>Á‚ž±*ÒûH?¨¾€HòÕO~W„+^g. Ã0§Âñ XsI%Õ"?Ä•1 “Ícá0{Ó¤c÷Þ· sTIË&R¸ !Þß92‹Ó8ÂÛÑ}µh ¶[»Ç¨¦]6uyžßûØGb”NWürNŽB‰Y“•-@7®­×ÇÈ¡º”‡SOn}côÀ€¬Ù“b\@ö¡„¶¹ZkÅàܾLPçºó‡Ã1§N{bA‹€Çæ••„”5‰ï,°ÁC?™˜]X?EÔíÙ¸Ýç:…—ß~Û–<-I´W–õ›c NÑå>ÆaÌgÓõüÑ&6éxàÚºXÆtåPI ñY•Ìä–ö`rrì)C±sTtú¡éÅÈmçoèUFÙGá÷íˆMëõ¡éÎ0t}øéØõY]*CÆÃ l'O$¥Ï®P˜Wg)ã•uƒ™BÜ”þO¼/*Ì<®~Ä•à»I öJç³3&Ý`žÅ›î0ÓѤ#tÏ ^!ˆkp?r‘ <`ÍŸ³Û{O åñÜ{‚Õ†#N=©z©K^K¯æœƒXåÛßÇùáøpÝèœ`^e}¦\3}çÇ #Â5½ÿ¡!´.Eè|’€€ÄÝÜæšJ÷çÛUü‰7Û´[¥õûC×Y›Ù÷ÿZ«ä¦O@öuKòø°ò¥>TÛ€ìP${¬À‰åÓ¥¶Ì:ŸÈ‘Í#u­A‚ó8=7Â_a‰”U÷/ãœþ‰lêãÆÖˆoŒUCYn”ùWŽ)=ZùõCš8—qíÿo½Ãqǃ ã5<¥­—­÷Ž-P•H9O ɰv24}l_‰É'!P‰1{Sí¨ú7®µ}ŸôÊš3šo·ÿëÔ‰¶þ'0ókµŠè†ÊÎþù…†ŒN $*[ü1mó§Ù?*ÙePÓÞg¨µŸbžx´›Ó „£‚½ ý.ý1v'`½žO +G¯‘S¹ÑäÇ!XãenŽ¿zq_j‰ï.¶äWƒþñ®Î×Hš¨wk¡ëŒµl‡ªnÁKß pþ:ûÀR¦¶‰>ºòD­ÿÝp^Ûa—vl•&ÿ.&csÑeŠNÍд|Ôˆ´3­Zxe {Û­ÏœÙ'_€ƒX ™"0¢ )WP˜ÖXœ" P“Ð @…1Ï%òÝÎyÏnvÌ áF37J÷ƒÀ4µ)£¸¤íûIJ±D¢^Ú)Wé³M½'.cj%`¥FµwZ?qø‰â?=9ÓG bž›“?â¯9LÍ“!£/¢¶Ö$Ü% Å¨¹'›Q — nÒ¡ìyOP— +K±®®›iºäé1ÀLš ²×4ŠÛ:U£ãA[˜>­ÀS#ýŦfXŒ½&ä'  Ez›Ívsu[¨ó÷ÔP[*Ç%´¯D•ò—Ïú«­fdtxGë¢P¦’yе`õ^ú@ †©Öµ³ÁËá+ìr|ûªÕQmò Ubð K6ƒØŸ¯¨'.Ó¿NŒÔ]úÀw0÷-+#'·øÕýTÄðÕq§UR¾òAŸð å©+Èþø³âƒªö6‚¢eÓ/Ù4òAÙ¡jôrÈ“I ÍnPꎜÿˆ·Î’äŒ_æ òMð›æ85¾ÇŸFc€B±.Š˜±7~¬¾ÓÓƒæí¡óðWˆ7l—·'ÇP´ ܈#”V ÿZ¡ ¼ÂKlµsÇ”ÖY¡/$ wõRà ×û+aæ ¾‚ŒÓü’K+çü8=­Mïaxœ,Žeõ7Ž©jDÎßâ}†‚¯©ÛŒ¹F¦›IJo~d§&ì®’€€ç`ÌÞè¢q~Æ2Íû¸k’öÔ‹OÐK:ó-Ð.ÒXÃ8øÀú·æ´õìÕ•§Wæ¢þ“©m³az$Šhìפþq¯WR€è1â1…¯u96ÀµµyŸl‡¹b‡bä!€þ+Ÿóg¡ª¹Ý‘ÒýÂ6ëj“´® >$ׂ^D¹ék˜çdâpܾE[kíÁP$~ÓSIEѽ6B˜cXÆ„s_úÇÆ)T%ñ‘í¸BC3Y%_‚—¾8ƒÈ÷ÇGñ†\àçaÜå¹›1ü[ÌùÕ8w+{t„¾’Dà¤a?ó♹g©}¤¢ëÍBP–¨5øÂ2Éâ…ÀÚ9€Ð¥ôÔ{‡² ‹øõ5߯U yS;Sw}Á"KvPÜÐýÁ’˜G‡½&Çy‚÷ÑÌžÊÐ.{G£¸¿Å¼oj¹u°€è™Ô%U.Ÿ·øoþe½7çCጠz°ü™ÖºÊMö,ÜÜî–‹Ÿ{µê«bFó7 q¿C£FÄ»£ £Ç>³ï*(Ëɇ”]R OòúÏ{A(…”@â úëb¦MЀøã_Üïè„dœÉô‚wçrh+­Â%Ü8ÿBÕòåuçTÕ"išu)Óÿ;çl;Ë!ëFo–Uk?9³›Ã«Dh}tu§ÁMõoÿÅÜ“,fD—H#ù+eÖ×MÆ þ\ÒïÒÙÝ"§´¤]Àû­ÿ}xLÏ8y—6kJCæú%Œà\™n\€ýf¼ƒÄµ×*¡M1]ÐÝì#fU´ j¯/${•TÝ^oƒu}òL«©h¬Ÿ³Áßÿj2éÇ?ENÖ»ñr§Èпqß9ÃíèŽñ"´Ð {UÇSÍà¥BTIΰÍ74›ÑSdN"\÷ÁZK°D!¦¸¾ c#0®§U°šøzNL¿Ž;á<À±tG6‹žRø ñju£.6r{$¶ðsÌÚÚà—ÒN¹[÷Ä 4ýö>\î,Òœ@W¼“êÄlƒŒ 4H%ÍjøF"±FÓ®©cüõJϺߓˆÿ»Ö6nÿaFV|Ar%¸ÞÖ¥wå2X¶¢&|AdKlŠ\$ÞÎi])Åû­ÐÈì Ê´â8g+ÐÏ ؼFT„@k•Å]4²¿¬Ø|×Å%Í$Øï¿hVrEß̼¢OèÓ ÿü0‡gç¡¡FmÕÓ¤¸ù2Íì©v:Mqí‚b&Ö?kVYò ’¢ m”¦<÷QY3*x\:¿`xè‡2;% &'þ.ü|p÷NÍÖŒlv]BzµúU³‹¾Š\ëVŠæPZU#Xx°ˆòüÇø#D²½]‹_!r+‰gw ìÊ+À–Àg-É•¶—DÒú!øÒÇT/Ä0°¢¹i õ`&9 Ó9ÒYÍá[P+>ûèÍTå'BTœžÞ@üSÄjÑ€óµ‹MRÎ;Ì:Ü‚dƒ 1‘²ˆÍH‰7\Š"**‚cÖœü …{Õ_Õ&õ½¦9攀Í2Ûp%+±4‚J¾+¾ûKô5W” 7£' è¡ç;Mê/Õ­ ÊăGœèÔ‹¤²5uÊ,A…©—>¹39Q?xžÌp®•ã]=3ÆíärÁÜ!CvW@húaõ+¤ØãÎcÞ} Á¡:›Ñ¦ƒe;P!¾Ž”ú¦QuS³£vñ¿ã‹:Û65xòÙ\áÈ9{¤Ám^Du.ê'ßL (ûJ’€€Ðln†š¬àþÁM>ç=)‚UÝuDjc LÍÔÊÕ’ë¸q¸ÓKTJ'}´'ÍúZ¼–„V¦•rT‡e€—6“ñŠ[„vem ¿b‡àâ¢Wñœ&Œ™?øŠTÜ‹¬ òÜB¹ ¦@¥o‚ïàñ>7‹ßÍÞ—À›e±*9€‡ ; NìuYL|S´Yƒªî.óRL>°€.r}„ß•Q-€¨†ÑX»7AFòø¡e€a¡ñ!• U$éáªzuw#!s`°¶¸M~Ï0ψŽ%¶ÿ|÷åCÔ¨P+¢É^Ú±Ò±ÄþVƒ±ûèsG1òTôŸê÷s×öFŠZóø*ÄL¨å@>;I}ºÈr“.ÞËUœJ<ê°0ȆH%x1ZÌ*rª—·Õ‚BÑa‘©#o Ä…}DL]Çó £ËŠo×b™ÊXN8 WÉø»úûwE~|OQ>^$¤¨Ø&ÄQµØ`øÍ5SF³aã}Œ¶ÌÿJ‚Þ9ÁvâÌ0c%o•Pw“ùCr'‚²1à… mL-fR2ÒÎOphb¨ Ž„ÍÎÏÞÊs (™¨Ô~q£PáMŸU°Ê»ë´m5t1·ûߣ¿'Ó.aÀ²LÍO¦KèËYoÔ ¸1 UG TÛ~ã}Ì–;ÄÔýq¹¸ÂÏmUöƒ.Õó±­òHŽî„Š@´¢âR\}ùvePZrB²Œôà8ÞßeÁ؃Âuí”L›¤ÊdæÝ8ã”´T2ùëBKÁt”ÊÜfÚPÇ]9¹ÄDÖB=ô¤‹”Á<ˆ†zÿ¥ZÕrb¿Ù_gw„šŸçëÃû1Æð´ dIÉ*2èçØ‡Å ¶í¶Š¸{´7Ðû[ç«H®y‘$‘6íÙ0dé¼´èƒNt!3 oدYô&ˆÖkžy™ÒâBs¤ÈWv[VEò Eâ¬âÈ4-SãKÐñ‡b {A¶{Få\¸ŠS4¦a„·¼°¶dÏzÒ¼ö”<3è¬rìj·¸Y•Fñ~^¶àèyˆ|sN=eî@Ÿ\Î\çѨiv£dy£e/òZ„°IPõŽž/AvެÜÖÍ®švt‚•‘úùVJÐðN‹©Díú)oÌ ØÎ'ù{‚Þ>ÜÏF|‹ÀMÄÒˆl¿39ƨq+î÷rsŸe‘’€€ÉÙûð„DåùËY GÁ—É^£5”½žsV?\Õ¸ÞÈÌ_8ž[ÀÉ‘¶¡^éøm«ÐDY~ÉË¿é’|µÂ`Í(*}÷ð'è÷ƒ„T@——kþ À¦-i O_¶D­RQ’P‰D õÒŠÜsuþõãêØ43I깑”cd>óUîñÊv²o*>À ~Åð åÎÞƒó+åw2¡Ûz]=Ԥ܉rÆJ9™ž nµÿ«€¸™«I¦«ÅjÈÄ{Y°ãëfLŸSuÿ޲(­mºO£%%Žû” HŽÿÃÄ;[äþ~ ·BOL‡”·7ü9Ä¥˜C1t÷©|¤·ÇH…Ð@‘+¶~¿ê§f¡˜ªØ§-áN òž›+ê56uàYbx‘¾Ê™±t¬‰œÀ'<–`/:D)ロ™ è\÷[p}ÜrS„œÆÔõhi®6§}W{èz*<¥ô1Äà†ÿ;’ÍýŒ9~›\Ú“òŠ?ÁJ9Gíi·D`F”Ùù¡PßôÚTOS¥E©ž«Ï‚Å¥×–ù{,C:ó«Z©%o§“˜7Åéß¡)M–d—Ê'àb€{"bÞ\ã‘b²Yœ#iEâÏ¿§f©Œl¨Û4@ÍþéÀë/G½üYCõŒS$¸Î$5³ZÊ øoއÈÇ‹¯ŽVŒ.ëŽ}fµrnƒªñí ”yxF|ÝÍ;¥ù‡ðpoÙ‚…oÌ_N”¬({ß´Útˆš WdŠsP:9‚Sùì%2%ãÂ’£wË9AÂEI žn£7%!IÅ\x¯­Þû‹.xáÛ*ŸIUÔ°pÿø…”ÆDÊÚ_ME+ê™_®hV±ÑA*zœ¯M /‹6½¦ùT2+3ýÚ~¬f¤›xŽ>û§š;ÔÑ*ÃÐL¡ø~ù¸g)RδkÌË R«ìZ…ß3_Ç;F…ƒÆ Ùn"Ý¢¹„þˆ¬ò@5¯Þç:ŸèQ(DæpzÄ=ÿÒí÷'Ëž0è™ÅDïëÏÙ„¸d÷RùD˜6ž"wùUãvà‰´5Z’€€½¶-ÍäËÔ~¡–ÔÎëÈìòм(¦¾X"ë"x÷?&rôMÂÉM‹Û+ê¶ý0=ú õš¾o´Õ¦îž›ÿ)3×(‚øÁo†þBìO`8åëX¾> \Ùþ*m¥—ïPÐú ËF¤.¾§ú!zŒ…ÕøC«Íüësq¦÷î ¤üüRX4ŸÍ:˺èc;£ü71qÏm<Ûªw[5‚`”ecß[gµ’Ì/ÓÇÿ¯üÇžç_ÈSPªŽ~{¸6R˜`~fØá”®M°ú‰&³”ƒåðS£AyZ˜p|Ó$ŸC%èœmØV°jC>‡Ûþz*ÛæÇ, ý)É“(Eºó9=4i–ƒðb«CÚõ©ÕûÉ™ÊîÈTÚkÒæ®Â«• îôÆú–oe­Ùž"Jås¢œN‚x®’¹N°LöÍŸÀëQûªD,X7R°ðÈþÅ€¦ŽQowLõ'Å^hŒÒF} êõ ¾Šr†—À©üZÊ‚‚KwŽ:‡¢X©h *²É‘Jýë¹@/L ¢d’k»@6ÀQ>Wz·m/µ^¾+z &J3.ÓØ“¬ôµC†•´½òüÊóür;tãyŠgè?`<§æôáû„Ý+ËïëmPÏA{qF¶ E“n±É·º}íu¨‰/YšÞ—² ¢õ:…ò:G0Èù0]ùm±2•Yù›¸ÖÅ(â/œôÝ~Ž`ø£k‚—˜WˆÈkÑÖöhp >wàü“‘rÓÅ4u[ÍC< Rqöwö¢Â˜!ãZXŠñÚB¼{ a×<Ù%T¡o¤{øù6[凯5Þ 0G\þ^(ÌWÈ‚HÈ×ÿعh¿Ì¤ê,­ÇM¢ßÊLÌ™x‹çfp9ýÚMsš¤B•gj “ÒnÇX†-ècE'SÊèkXFÇÞN­¨Õ†Ž¢óö»aJú“-zñ@tlí­‘ü¬º€*÷‘ÎXw'Áœ‡ ê¸.>uá¼rê$‹ ÈâÁjô‹aC)(vÍÀŠ7ÁòÓr)?1Øï§Ô[½Qµƒâ÷36Þø²‡Œ„í1M¤«Ì³¶×}9ôÝwv=Êí[IÌ]~|vSòÝ褘ðt¢íÈãy®7:ÒÓŸÓäBÞ"0ÀðÇa4uW×V"4yåaIŒèÇ<̀뼒éMµÿ¤’€€©yè&v®Â­a^Ü]žgÏÚ›ÐÅ_\àÍ™qÆÍV¸ª°áa8Ê3²¿>ó’ƒãˆBC\?ïHŽ­3ûá³Qt?¢zR]äžô;¶ ó.o)î‰ÏX·‘Ÿ†v½®V’¾šåÁðRS”Ë*±]@ P°#àþ?Ðß 3Ü„êÀZÅAì*{°æCQÔ¢§\N¤çfA%IÀõ¾dVÑK@0µ4ûVÜÕ ÛÎmÓ+…® ´OyZ®„â÷ðcÿ—ÆÒ\}»Î ÞeGm•´ Ð Ù?¢ßÕ¾Þ»ñ‰èPMW3£²WÒ–£Wnõ(À¥§~¹'S‹MË_¹MY“bT €™cr#Ÿh6¦Ö¦ü¿ me<²P68{KŠ ÂcÌH[8ü™gc}cP?¼/ªx±29ÿ™KHC[¯51Þ,¿p #_–;ù“2(Ép ì`¾Ëæ%¶¸{ë5”W¬‡]^N+ï¥=AÈÿÍ‘ ¨·ÆÄíœ}æùˆl.sÑ¥•ü~F©b!€2×@–._ª¬ýèX“£T†«0.$͸éé¿>Þ*(bÜ>Ñ@’€€ê ègÿðÐ7oo*úuÏ…ý>¯¦íe ªªß;9ÿñd§<*(7§¼]oÍÇä„Ñ>IìñwÍSÆ31ú9¬öõž¡rí¯œ’1ÄÖéúD÷Ѱ!ÁFv*üå°nï‡ÏÀÕœ‰X7hÜÿ$íôÒ_oG#Ø_%áóß–êPæ¾y™(H})³ØØ»û;:±€Ç f«×¯d¬©‚ _ÚdJ c|q·(Ê»­ÜÐá“óû»?G„·ÀZŸûøC-Vùc²Cà‘?5 ™¶+ìoöŸ›$Ë%V¸?ã{fùtLMñVOH£5ü«R%¦´L·D€áw”–nM±t6jðå6ÒÚåÚ,¨Üè§¡¥X>;#Úë ŠÿaKKÒ¶“ ‰2bä«u¯n\t’+u](™‚ÀµŠ+žåäë1»ù·* ẂljÇV‘aP ƒeB ‚ê¯LÂ袵ÃD½îwc³F´’š(€Eqº+(÷†]¿y°b®Û6êm³ÊU±wwðÝä§ÿ`4Ḭ́Œlò½wïGÞ“vI#ÍÒ6¬d•e9鼪DlzM"ð>cíŠzàIziû<ìˆÀų@'‡¥1]Ÿ6ù’®9$…€=ÁžW¶èƒSØÀìºÛ¹âY]AMüs>{<[ˆóâwx|ö$¶ çaÙbeÿGмLø™[LøŒ‡ÄÚ­Ë ì;`(œØ!޵֕a1RìõìØ ÷K'þT,fíp«´ê8ÙÍ+{üDIv‹.¡ù^¢ñ8ïÿ'‰Nk–& Èÿ]7‡WÕ7»â»ØOg`œ'ûíXq…i¶»Uü(_T$†Æ¯a rv/Ÿ§ßT‰Ü%ˆù¥–?¸Žs%¦{p—Bò„íP¹\ ¼î¥HžúûmÏhqŒ¾ªc·=ÚjE.—…ƒ³ß ƒ4»Áz™²Áv`ñÈÉ(Aý Ú¸ä?#>_Œ‚C(ëÛfGµòá?‰Vâ*Ø;éžë€åa,s.XšcAÄ|4)¸y²4‹¤ZSõÔ¼ÙÜŽìèB0•Kÿ›*(–šqcYµ‰â ¥2ÎÇxa! Üµ×ã¬+‡œC^ ‹ò ÑÈ÷GízÅs*Ïq~æƒ,‹¨r3éîö˜Ô}¡y)×ìÞ/jwZ©º¬~ãJBvƒûÌ>±‘áÃÅí´³ÓÇ®¨aóz[<Ì\¹qeăÌ8{ߦ«¾HÊ„•n5’A9Àÿ8 …"ÉÿÉþÊà…FZsê>Ev9wÀ˜ ŽÒ¿­Û®ËtŽ™2òñ-¸ÏÒw1.áI„eô>j_»žÒ6†üЊ/œø^t{|.Kð»ô)Æù DA xçÿnÃ@lu”_3ìbmwëӲɛv5mVzF·q–Ê žžöVØ‹Õûê)À€VAß[‡sñÞÌÐÔÏ5éCìó_åÏ•Ù!Y²Ó3ëN[m•õaœÞ#åÚ‰ôíÄzaïmm¨úEáj+ q—&ÑpHÃPëöbQg1UQí=È"·¿öK¿ÀÍâÕ· 5OV3€ÀQ”,µæ.·aï sùÛ’e§@¦†³è˜‘C¤üûéÇϘº ÌÈ/d³ÂåשÁûÃìÛ"_Ò¼ ^¡ÌøŠ™I3ÿþöSüŒ_^ïôû)ÌN¸µÇ¬ˆ>Õ±Ç@9{ß§µêNZ4ðÚzå2¼»²åüÞoRB¤Ã]|¡…¯g«»¬¿°ir³“ŽŸ¥Ø…0!I§íÝ2vƒó’PO‰E/µoâ͘ãÒõñ°[ P‰›PÜX-eìKKöd ƒÙÌźp=xÌ;¾Á…Ï%PÕŸÍ¿4*¿h€6ûƒm’ i …ÕØ=l‰Z‰¶Þ§ºrw2±ÎàŽ$¹Axîc¹ì!òá¿I´'÷ ç×ë®7—»æZŽrcxj*Û[¨Æ‚¥(ìvÄ “uûKBâ„yÅéL!oT¥Eæ!gôh4½x=]ý|MÀܾôÒ•WÕ‰¹xÎ;eèûÿCÍ–@KxåëqìŸF /&BlÔ:vîã»íŠÚ&=Ñ&¥æé‡_vm†“}²}µR;}kÕd²1ÍÐ*…^ðç;‹ÓB âR×úp‹#«&Ý16„î:ЧÇS®K‚3ˆ$A'9ˆiìxp™Ô«4Òl{{1]PÙS›b([\—î{ü)ˆ?Û1M·€’€€½`=¢=:6ÊZi/_̪qA;ˆµ´Æa¦aK‡)ž}Ì×nÁERÙéä¤Ns-zœ÷ƒæšêÒáò‡ô$À¿ÆÁ?¾òê{CUï›Ý€'8îȱ3¡ßàÚ ÓsBO×ëø;œ*õ%ò•µf†ú°Ùš| ðÑIvƒ#)qñ¦]}˜q2™‘I ÃcË#ÔîVönê’Íü‘)én8s§’UÏd_KúPCʼ×C4nŽÞ)ÅÇK§BATË †óÇI0¡eÎC^Äjn|†¨˜„iÕî@,©öK.|%V"¨£Rž óE¨cÉÑ`3¡N9+ZÖa(OQB¯ÕóÒ¬øBF¸§—Æ,ܲØû4NÒ‚²²€¾o àH!Ó.{¶Ò\÷y_a¥¬Yj˜óœ,O®uV1èè ßÿ䮟Aò§&§6iÿò²ªúRF ¸8¶%¯;ú¦ËGmr›ŽŽ3¸çÖà¾Æ&õä®.Îua^l z q3‚Âp'Ÿ©ùo¨!v§)á7ò âi€xàÔ: mS?^v¢EEÃ6ngeðd˜?†}µzJš#ÄtY®‘@r,&^9×îbÔ)µ-¯ÛÉ &[KqÖKp¶‡ƒQ •||hÃȘ «ª+Rô> rDg [ûí×Þ®èƒ8¼öü´ð²&Ù£‰C>€BÛ7à)Mè)­.?:¤,à´¤ |Ž–q¤¢˜ƒ¯ÄÏt³y}E+g 2’Ä¡)øfÐ~Xxh ÈØĤ2Lˆ{š3*{H‘.….VvŸ¶ò(o+“ÆçX3×­¬ã˜(Ȇ?ËÕ.ÂðᛜxË8“Ôu¢õçzì#]EÄŽÇM¤šm¼Ö+,Ë NõÎAžÓ)ŠÄþÓ¯ïa‚ª –ÜÄr”ü»ÿ •zð[r”^Ž–sUš±ü·» ,l¦a ϬeUÙxu955“gd"ØEI·J–ìÏ´·o¨iØñ ES/E©÷ˉ͈ðv  [ÂÜzÕ/Ëx/ïŒA䯢HíIjI`+=rCÊô;qú-€ÞÇÝrØêEEÊßK„Ó ÷”¼Œ_³0–iXÊÁ¦é&úÿ¦ãå ³ƒ²³#Æ1ÃF¿xaÒ?D8¨B§ï‚˜‘ýCŸœñÏ Þ{9úþ}Âe‡>KÐàÊË\óÝ[Û£šøšiÆ4M Olh?©]KëÞ¼òü@8F8£Êý8zIzÙ¹‘Ù¹ñ3„ºrrÕ6_a ÈøsÊÌÄtÝtÌV\b§/ò 4Iê!èqþGA«ýµò(:¥»–믖/‘ÏôF¥Ÿt˜&^ªƒ§rDË®WUð;UjYÌNÕrv°È–—/ÝP;‡†o[¾Œ«oAMáyÌT˜®§MŠ÷Ô¯ÈÕº6þˆÀŒv%¶zq"YÆk'WùŽý@ºvZ@·õõ:MŠ2ÔMœ)YNÁ9“;¥ ‡›¸aúÔ,\‹KǧuÍ-‹¿7ròtB¢ö«¾¹uÕEˆ : .oÚí^ÃhR-~áa9öýÏ’óŒm¯<¡hçÎx’H4}fWÕ˜¦¾Èº4¬P¡ú|x<’€€ÜÉd^f%Îp¸@]iª•“úÜăç7Ö¾ËuPõècb¨æ©ØId·†²“Åæ'ø:È$Aï]"B=ÅÁŠ;õIÁpwre…à½Û3ëSdSÈŸœÛ wvÁ,ÇuµÃëúª0ˆ’$’vo» É Êt°‰d¹Ž®ïC/{´ …+}?€yˆ¯òø~˜P\(ÿÀΕ„D!Däy6G¿d™Qµ«,"õ^ ríjÙ?2žË‹~ìršDû]þͽïo<¿1î´§2®ÝNˆƒÜ.d,À»6Š^zu@!üñO|°¡z;3ÿäy7üÞOßcaï¾ófo~³IK?î²åê/ÆÕ¥©© kQŒýßÁ_; w<²„3ná§!¸é0Ux§Õö“™¯ÒS fü|¨Ê´ÍBì¡û+Žû^ÅOá%x‡ìžþ ªxº”ÂQ/§ã7Ð0±Tœ64¼‚“ ¼ßñ#&«5홦u'ã£7iL½ŸWr¸þ«ò÷TâX®v¥ˆ¹rœbyà"ØîâÍìmØs xVŒ4p>…×ÍÁê×}BW–'k#A¼j•ö9Õ†ÜQÊù”мx×m¿xV4KçvÓù”wP{WPÓ«Ú}ºßæÒ÷ è˜ëæBÄû²¦e«­×1…4É Ëàê¿ÌN†Å}²Í AmDI¼jaܹQšþ r\)6¡ùÕö’€€¯;o›h+ʰ:¡í‰„ð=9èùîX.4šÈˆƒSêÒ¡œ†yêy~[ $|þæÒº‰dNL|üi›—Š„($º`iÙDÁ’ú8N˜€N¨©4.»4<üü¢ÀÙµ÷c6Ûî^4«Zˆª'´ë»ÇzÉ­#ÏwÚ0¾ý‡ #EY¸‹”ifüãéÒ^ƹé x¿1÷œêløZKwí80M4k3Täžã„ik…> õÒ6 îlb¨ðqb{˜ªHÒŠèës6»P¾à¦wnÌV¬òº¼ ¥™Ï¶äÔü=[ëò³p˜ɤs{®Å¯‡ÑsÁjñ"ˆÔ]¯–|§—¾>=é§›m`Kì!ø7…ŽWç¼m£‰–1zƒÜ?GÌŸb†ž'¥ñý¾ãi\»H^XÌGv“!û>¯¹é{{‰"ôâÖ5¼X“=œÍI{B±’.G²˜´U`νBè,š˜ vX–êƒÚ40}…ê`iLfŒÊФ§½¯žµñå~?jmEÅIpö(CŒ–½Œ*´DéCU#¢”(HÊôlÆ’W·pnË ‡ë,ƒ=Òˆ â tI‚]<1hê²ZË ª ž":Ê t8ÑŒ<íY¾$cŒLvÙƒõò¸¾†ruæ=;3%åšQS–à$Ï:` 3.K7Šx‚}q´Òus4½¶öeG¬èqưbIö-Ä!N‡>ÉöE^ò$fãÀÙ¯Ûq“)¸””wx¼ã¾èò·áwé>S4·Ú¼Çt\eüÂU2—$>½è/>RÔ <šÎ¶öSIF¡[›–¹›–bŒ´’ùG?ç$ á¾5Lôë¨_ÍÐA5Pî¡V’#ÀyÀÞ,uäò^јM‰}5ç·Æàýþ#õ'qFá o¹ÑÎV9ëΦi¨Ä "%ò ÿu¦pݧÇ#Ƙ•õÜÛó\MÈŒ+ íá_WˆDî²_/o«% ºeõ@g–|´ÜǦºÕ¬ylõ²báDea~SAØðyÈIAês+Iøà;v޶±e憯*áÄ|ô̓…g ¹L›pGˆ2â›BŠGu£pîÙÌþ7ËÝeµém9…¸ì™”bC´›Pó-‡N•@¹RÊÆ[ãËâIQè´x–û¸Ó‚§ø}¡ø6 ™”.?¯Ý¡>²/²çÏâàËü¨P´úÞ8Šè1»dõùy æ‹“³«Šq<ÀF/jâuÖÞ/+E3®g¸€öT8^ž]‡,Ðù­’€€ÏL ìW\…_¾ñ‰_ẆZçØŒ#ëáêǹëü¬d£‡ üyU¼M¹cRõ8yóÉÁû}2yÕø=0òÎa‡Æ¸¹‰ `PÍVήLäü]ó0HqéÔÔAz™§ܳŽmz ˜ý>Ø3¢à+i”ÅÛĹü¿oò÷º!”Yœþ>s ¸ÊLß'xÀà&‹vkLã5tªPO)|ñÑ«ù¯§`(ÂÒ2±¶'’l‡üÊ·Ì!%É{‘’ÿ¤èLOÕ•ý£Ü³WZXmÚãbìÑÝ-’Œ°al?JØ~÷Žó̇ɼS“<ø= ŠØ}¨ë;4¢ží0j5ftÈßþÛ ]±o~캗À4ôe; ˜w%l¢Ux¼É+wµçmñë~ H鋨U×(jKFŸgµŽÍ‰«õi©A’ì­ýÇâ^UùèRT'mLNît! ~Fiíç‘qXsüÝû·¤ëð=‰ä¢¸üíõûmÙÂ…ù$šmw «´Ï~7Ìn`„‡ª àMOè±"¸‹Þž´bã%sO%õ™É §q@˜6OSÜ_¢5/Il¨=*9A£ÿÏB¤#<ײM7_Ò鱿±Úo¦õÎë2îúä.öA§å>ù¸}ɯüʯ\ܰN©ïéóþH÷3›ª9Õ>íÏ<zϯ¨8VÛÎñÀ×µ:5ŽÀ6ŒÃ Uˆúà ”óÇŽFêžÐ«{O±ž!ŠåOl€õÎVÁ€Û%@>8É„º5P2JßDk¡ç;•€“3¾³@Qñ¼º›ÒNªŸò¶–íÏ’›ó§y¯RéÙ{º'ƘýfŠ48ÜÈ­MB÷z6àçâcð Û¹‡N'ƒªÄ÷!ñ¦â–—‘ ™Š«êg¢úc´ ^þö§A×«Û ŸMÑb_B[;"|‘tÃr<¯G­ Ù>Åý‘b¬'»pò…>5Ô ÷v¶íú*΃zSÞD¬¤¾ùDDo{»{i“Ê1 Q©V=Í(y<Ëáñ!X¡Ù@݇莵?Ò¢Ù-®úìR³Í âæ˜—}Âs¾s„@Gú–ÚéD]#Õ®„}©š)é6œ øýÐ9ìáÓ®c’ Þ”!¹c¾DȘjcè NcÁ.m¨µ’€€ÒÁ*&¾±’œÞ:ª|Pœ '¿ý È5€cÖñé™4…ç£HãkqM*8 Àò}bLgˆž¬I„© }úƒ&3žYy¡vît~€ÙÈEÓD·¡I0/šÌYÆ êÈšh?Ýìð4o;6°ÿ)L¦YèãÇ+-bþÉ;'Ýó]Ü(·w³gÐ%’­ÑAüþ`²žF5àzƶïç•£²¨)–Haä¨EdEž;Ó[LJ,dÉà"sD—"íƒ(ÏVÒúËSg· “ú ‚÷.<ž«ç»Aå«4 ~6E_-|#f½}aê?€H{.u׎çLv„ÌNM¬ï+GC§˜|ÿtœúÙeçw&Á/ßðôÔq^ î–§"VVn‡<™ÞHÝA»Žo$^ÿ}PÝH ‘Ë»^ADlӦ߹ ”òâÏÅyZ}ëTpñžŽë*Üz¯FÙ©2w.”1NŒÛè|Û¹f£—7û Y43{î24¬?´[ý N€²UÞÕ¥!‰§ š][ ÜJÞ]ÔDëû ®{ëÄØìu8cTD‚<Üɹ~º¿”}â“fGì­Q!‡ï²,£'E(]ë!Sh±„dü –×Eߢ—1–M€ˆˆz¨!¦(¶÷£ãàÎU(è”%ȃñƒ0G(Ò,¿T̪Ôñõt"j¿5IšØ‡xÚãHÜäõö‹‚Y+‡ŒÖµõàڑ½‘0àÙE# —ÇR¦ãº;¨×G^خŠ^»«\ëª/$ûAóùÍÃ^‹E/ `r!^ Íýêãfo8cü”º²²1œv³8øß§ÅƒMøÚ@“^DzŽð̳WÛÏ[ïìyÞs‡ˆf¿`DLç{øãD3êü&>´½ró+ õ¢h$»ð¡ôsœ,k|.ƒí¨ Î5‡Ä‰®Û•!&›æqI×ï,DÀG­áÚWÂ)é?hÇÙ^®PñæØÎV@ð·…»f³Ṉ̃†ê‡ÓÜ„±ßÁ‘m¤– Tß9P°¥PýÝ0]¾qî|YgÍ\öÑ5%ʯöj^ÓÏGAÛÒ\³›ª/ÊÄß.’(-ñ×Ö’” ÿÏ2­†JŸ¦Kì©w{f„4î`GÈC÷çË‹±B’5ºú¥á€ãj,A¯é)‡´àÀpÅp˜ UR…¿:MÕeY’€€ÇsȰ¶K×xíqKäðUŒWY ˆ÷iÑ0ÀŠ–BvQ›ŸÐ즩w+QXv§xxŽv‡´±Âª†e„PûQäßnщÄMÉ/á+Jk Âì˜ ©IužIè»DËúÀ‚ÞuhÀ||ÝðCUHÿ*xö‹¥ÿ¯‹ßFûtš(öbw, |ë+˜ZÛs%mU¸®Åï)»ÉV­½OõûìV"xŠùL3…€”®àWl*’>;Ò£¸2¦ˆß¤_”xûæÈ{ý)0¾W›"_-ë•Èå¯ü<¸éƶ÷Ã.ãUÇ®¼^ „DE[1¼–‰e ­z–‹ 4ðût¸ð}œàô{ÑË*³ŒœVoÄWPMèŽÌù5´”±Í wæ’?;éF«z|ýö ÷?À ÆH\më5—®ëM)¼H ‘‹·I;UƬ£7nÈ)?8ÝK¯oìo7ÙLèNÁG4º@2·›¹£¾ÝrÛeìÖ{/.Õ‰4Ž£§ÁHåç?±‚S˜ç+^èöáƒ$ûq ”´´¼iv!kƒ±'òÞÏÿÆò©ù)fºôN `ÿyYñ{È"þ!xaàs¼a3útRo„d^õî¼èŒ…¶ÿ'˜ìͳ×+ÖĶ!/R$Êo¿±õ7îZkÓ꺗ÐßHã­BkßNo4ß1nQM©G¥„§klfö1³—?žç²@+Ió;î.M_óå}™ËÁûý¹òï|t -¾XtÍ;Dpœè´™€wHXûŒ½!yÑÛLOb#õ‚0ô€d#ÿíßÂ)êmÄ>iÖ QÈ6h=Ö7AÀ³´æÈIÉÝŽq•¬Ó—º3Š1ò裣œ‹0jÖÅêkÔ!Y&y–ʦNúµ‡<æAò`‰÷„çÞzþ¢™}ðó‰Ûà'øRPkÚågbR˜Š£` X+4 (Dý˜¼Ú„ÌàYªÃÀÀ®ûJG>¶0‚™T‹s›Užg: Ù ²»óJ·_”è<¥rÄ~è”ÀZAƒˆ:°sñ£mË£ò¥ü`ÉYkŒí^4m‹™lꑪ°§úñ,rjº¨æ“Ž˜òÚ)€xÚýÍB+ †nþþn€MHÆb¦¢É´á*@å“%©Ò;ì£ÚFš4àíþ"-Ò’€€á‚ÕÙ©¶¦¾2þwÈ ÕR)0Oÿn(ŽˆÕ;'a[nÙ±àͪ¯¤ðÁÜiã•áðÔAÿE_!'™ð»ùvQ H5UÜi蹂FC“H) MŒŸí“ý»çVv{çmeSÉr³Ô+Jn§VÎB=G®ÑÒáúà…†ã5œù$À×{x†ŠcHe¬Q0EuÇ”a™vt…¢Ürµ‰Uc¶sQœ wIKLÊöm𢻴g¡µsàZèMÿ¤'õ²LÙ5Käò>¶JÊèaýä*Ÿôk µµ¼L[¦þvzuåÙSr¶ ®–ò'Šñº šóðÕ嬑nQ7´Å òUDn –¥‡c;õšŽ‰tÉ8U?"HÑîáÜ€M·­š'#ƒr*b4–P“KF7;‘b§ò׺.ï,{¸óŽ„n@Hþöõှ—˜'^™uW²w7gKåÄ:§ýCͧ¾}™ê˜°þÓÀÑ©:£¾X•|W“CõøØJ]4Q×k¤+îÑäG㺢8§®õ(¼”…ÔÒBÓaù-cO³ý-…¬ZÿKíº‡6ô>Î’#|oÈIÏ<Ïæ$÷…Цž‰Œ`bÿkOŽ,³°±ÊN°¾û,²ß¯)õƉ­Nõ𻟶‹¢„XÏ –w™];ÖJÆ=;Íì_°ôvÄÃEcØ3¼(¢³’€€Ä_2sÓ ý˜Ô§GÉû¤6+Ñ·48}Y8²áð¼Zb)-Ú 3Z,­ß€|ùÖPµ€û¢ÅØÌ€§43g…AnÃ’qwQ"²zÃ¥· ³’yevÚÕ.ø¢ 0+ ž†ðÙ;¡ðp$þGE¤Qù¸I½Š~6V ß™/ºk$>XilôDûv†‰ÍgeË\™€2fÒº»“/¿Rf&÷³È·“Ð.t¨7O£…Ò.yéXj° â&úGzXœ­R¸ÒÂÐÁ¿ÿǶyëJ„?‚DóÏ"¬Ïæ‚h©v ô°ÿÀvºñ ÕÀÒóLðOˆ…~wìéž?ÒòŽeåŸnÞëÌ Èëg|Þîfû?I°,zõ^í›0e—M­É^Åx·“©ú<ƾÉI~{{ ñ,ÀíåõK^Y¢ J“®1Kå‰ÔœÔl3Ë4A½Éu“ÙFAɵ«Ë»’y3'|ÕÇ#Ùk@i3ørWC}áJ …ƒf\oêÞ»zP3-–¬§ Ñ¿û­¨?óªtËìd \N²4ãú– üâž•@'ض×ehð[¹tUQMÜñÞÕÚœnšpíÐ4-ß2Z8}’Þ~dÖʘúƒç:mèí´'wÀÃÌê#Ý›mG©›ß%À#‚M(ºÌÜ,•xídPqO‚F.îü O_Îv+Æ|¥óü^>aRžnÆÆ‡]yõï¬MÎÕ ½"HE1âóKã½JJš' xýÕ]†æïPø# 3t¢”êc«Ü¯ò‹*´ŠûÜL†]ɼŽ1ðAë¯Pö€o8dP¥‰ÿ³HÑ n¢ï” j ¨¯ AIðÚ ý Èëó%i-Š×’Á–ƒþp »p­A¡Þ$µëÎðqÈlFÕÍ!7IÐÿ—’€€ÔâÚiܾ¹¦£íD™òD…b¶X1ÌeRb/Kûò^°îUÚÔ³×J°Ú¬Ê Îú­ÌÿP…äSr-nûÔšÙ²ƒ½„­©&¥sCrËÛî¹Ô¨Ð+kx›ð|™ƒQ?žå.™Ó­4ÝZ…O|¯¬s£N¬QéÝמ\±œ5 €ðÇrX¨»Å–{鎻™ ÓA5FtƒÝª»QÓ/£ò U‹z\®žs<[IJöÒsw%,›QÕzÔÑT­µå÷˜ÜziÎ*Hé«"88·yLÔ<´²A ç†õÚSØHRð=sˆK2ÍÓÔ#&CsáGꯉÜ*Y/7i¸¦ƒ1”V@\Š¡Wœt`ŽZS0ˆŒ|‚ ¤¼&É‘=ŠÃœÛj@ЈDöBž5õ¾½èé)ààõëá*:ÑŒùÿ¸Á×ᑳiãG_«–߯¿XJ]Ъ—²dŒA£ò )'Yú¢£Ke~OR§zÇzCSŪvs›ÒŸ¢ØEŸò…¹5OC‰‹K¸àQ¥, 3ìl: êæ!³¼…$( í~]×´‹ÇD¥¯ÐHk¨rûïËAçåâÆ›Ï…’*gÄ!!xËF0EñÝд]*îIµ¤§ùP·¾ü€<̱ö·çÄ­Å LXfôk‰aº 0P §oð=9”Ió"b÷+öYãÀ3É7r/×p2*Û1'›ZEÜŽ/¢5 xf7£QÊJìäÙJ5_jº©º{$m•¼.M›ü0üŠÞ½†þ£´ÙùëÞ²Òc9-¡Ó ÐÆÌ\<¹x—L3Pìh`MÃr2än`‚òê:¯új <™:6üÖÛßÍ€A¸»¿„°`‘º~4Sî%¹²‰—m5àV@`mFÈç>½¬½Œ¾4‘Õw³ ¶´’r¢©Ÿ•ÒNJÁÄ *ሷE̹‡Ú™‚ Ca¢uR˜ƒ± ¼¯ “=G´!þð¬*Ëû/âZÓÑòöÏ”˜FœæªaK%P¥=ÏÉ`^8á’¬èhmNNÕU0åø3àóá­±{½¦gĤÜY]õ5 Upx}(Xž°Ñ%*…SÈ4¬oư‡àjwFÇŠVLÒ®µLÐøÉm—Vè÷MØÒ_ÞÇðkÿäð>“|0O÷±.iâÀ€Á'Ö¤ìOÀ…ïÚž’€€áÊt¬}àŽ´Øíúý tHz­×j{Æ]ìÆ IFã—°Ëe¬ Ó\üºÖ‚ËV/Çbµ“¹¨ü‘·Dk{ª°U¶YÇoð›‰öÛT…“¸Qª¨Žá½µ;ËuÇò›§g¼”Sgu¾d|ôXD™û)Â>Z_%û8WÑß9öI4@–Fë>å§Ç)bÙG¢› Íš1xÅ!;ZÕ±ï Úq’>ªJÒ£í„íÏ„†ùï¾7À`–nK9¯ðs¬ÇC×&–´¾èo7=Žý -’så,%×LhëÀÀ¡âIS¹Œ|ýˆ¦%ŠeTŠX“Ô‘â ¼M$X§ó¸â#ªà7ùr!Us'ñ+ðäŒ)a½¨éž yºÒ„³‹b¥{ió›àò ¥9Fô§uNÎ~^1\*ˇïJB¯¦©“™šôÚbžø‡‘¢<¸]21Bð˜þK¤3Ù¢·¿´c‹ëóõ©T<{wƒ×Ÿ²?Ä·[/HÖI%‘¸tˆÉßù°%€•òõ΢£=R k6tËx~®ð-B„`.Àu_‘üûhq›×tμõ<%§ÿY‘Â{¶¶Šjaõå02ÆnV®}üÌÿ˜t¨82ýšTUÞèÁ±‡¨4¤Ì•üÔOã¹7ý—ÛŠi˜ðöþáÍPÖÞ‘ )üsávOêuÂJd®j õ6êO†rÏ•øb,ÓEILw(ÊÎÃꙆŠytá(UERulámUÿ­¸H]Öãø&S PaëÄü)zë>Käó:‰é7wåÖÒ"@ZÐðUÄC »L˜5#ÊNDF×RÇ•œ_¹„QF“ù—@ö«UQ½=ãÔ›ïU‚papuã³<Äì…ÞJ¯‹¢5ª¥þ;$¾ùŒòS-¼ËØô‚lUzU¸&“²»±Úè©3"ÌãSí¤»ÿÿz}ŠÃÜ›Úl|_3AåßÓbàŽÊ¨šeGF4ÌánNö»¨…ÓôZÞ–®Nþß+I6°#³×ß²UË3&! öb;G70 ëj@©û—ûäûE”¾c œ "‡œÉ T˜ú¬ß}ä÷îk"}ËBµ¯D¦`„Ã=ò’€€Îj›ï£“P+¡ØÚ÷ §'EûQöÓ»Öº6<úœ×Ÿ Úøª«·éÅ(å9 urÌ/Ê%„P*ûË7“@M &À8¯Q†V}_¹b}Q¦9¹(l I”¡ÓíJâBß+ì§ÅJõ„3Çúz”×¢ Ï?“)c.ý Ó‘þ‚>áÑRº¨Ó”ÿÚ¨8Îní"d,‘ò€´5£]!ÿmÔ›O~Pæ8[½>nþ‡£¼­>[㙉ÓÕ AO©Á“-tÀ×&À‘œ^@*Ä{°Yîø˜þ¥Ð•1³0µ\+e{U‹8û” ´‰šh;•ŒjŠœAŸ ·‹4F 4ï×H¿mÑ7熣.jPàx™*í…ì—Ã}‹ 6rSCJþŒñ~ˆù¸Gup¨÷ü®£`é¾Óè\é;ˆ3\Ûñ•B‰vc¸?zM™¯P´Ÿí“]zQýÔxª*°r˜p£u^Z(`ÒÕ¾­±¤%Â-7i¥B0ì4¤ØVpž!ˆÖÊzWØê½¹^¦‡‚Á댹Ò& Úªá™•Ãû²1yó|Ë„ddùJÒlÂûò#ºÌf);Ïì•Ñ;“Ùá©E”b:—jÜݳp<V<îêè*øšVåϤ¥ˆ¥ÌÜ<†Êߘí^ª.¿gj'©R¹êžÂèùý¯½¸P¿„Þl{ýéˆSlñxïc¬â|NÀÅäœpÄ)ÉOe‘×#d›Ö±æi|ò ÄÍNfñ‚]Ì#Ñزòq‹Å‡›Ç’¥a4–ݽ—Ýý ·UŒÛèZ¸%k÷L=(Mj[ñ±£ï MeªEE´gúŠ …+oá9êŠ2†)àÙ¦Q#”Ä(]u½‹åúåÇû‰â$bm'Ò‡lÿ°x¬ª†D¬¥œ„¾]>ŽÅ/áå2àM¡3nU™Á¢^ÿºµ‰=‹ñ&·6[ZÛÚïZ²æèuO׫×`—ï”"xH@PjIVù¶ÒÚ£îKéf‡i2»…„Ùéj¹‡á{Mžé–ðç™ù·Aß*PðYî®b] °i­þ®ãŸŠ›ËѼž [ý ¨Û¥iv7Aåÿü0*þÁ9©I t‚Íò3…11aàÿXƒÑ•š"…Ê­Ú±Z£*µ×H¹9÷·–§#àûbc6 ‚ »¯pfz˜'APù<Òø’€€Í0ÓÈßz)¥[Ú‰¥Æ%}¤Ÿ€ß&d£Œû,4È—»l‰_fAâçÔx…^[)É,hé-Ç–Z’Zýç!º†#jjÜ@Ï—¥NàxwÔ#ÓÞKŠZ¿Ãåbü—ýÙJsµ%G3‘´w·­)"©Sÿžh—M‰†&—Ú¸§™`k—9‡kûY&}YUÙáÒñ÷í8:°3rÄæAÓ±Ðnw‰3“ñŒ=¥Îˆ)" Þý¿ú@la½³£rÞ^«1º±›pK`Nsi }%ǃîOÌ#­Ðƒ[ŽQÈRáf9 8÷¼:ô즡«Ã¢ÌäŽR}”="cUhÙ/W NËýŒë0¾†­ý}ÓaWmBr‚m®6•þs,7ø r„è˜x³9Ž­¯KCÌÞìxÀeÐLØà¸™±®ÕaîÕ—µ‹ø!Ñ#†Uª„Špeý~SV u{ψp Ÿ¿Ó,Žš³ÂáœÌWÞ¤Ê,µßÃAâr·È+¡qx8÷Íõa®†m Îs&  B—|¾.²†5«0öa²cüæfDÉý®È‰ƒ2¨§mtøˆ4 `˜ˆÝý­ÿSò»ö®|M`.9’"©×æÍ]I¡/ ãyË6µî(³ë5ÂOQ“AQÿ*VõºÍÜZßa¯ØÒ3Xi¹ \ŬÙ1¬C6êõCEÎõTŸš@"SÌ‚Úc‰?Ùøé㱕O¸øIqû_"–_‹™8N6ŒÄʯCQ!tèÙ_Yì:ZqWxˆl„ö©_f§P­­xï­¡nI-S'rÃŸÌØm¤,{Ê„n·‰81ŒÈŸàs˜ç°š Ç»“WÙxöMžsß‘‡4‹‹2ØQ?ªPÝHeRžÚe[܇J¢âJ¸‡—D?jÜ?ÙFýrkÌÉÓ¾ö¼r#Ý~R³ÌR´"É Å–KºjxŠ]ðp1‰õþÖ l.mÏd’{Ó;&XD!Z0šœà3ª¸|³Ì‚âD1{H›Ò–uðƒÙm†Œðó…ql5´yô’˜ÐÑZãû^øIÜ\-…º/±DAðÔÆm£óÜ6$¯»éõ”ïaþ†SÚÖ/ÐÄþ:¤`ÂI3hô9Ér!Ã/ۅϳCsò‘„bÄa&ÀÒ AÕy2‚ì›;1ÍoIUzÂ'^GÓ”Ÿâáš¼ÆÚ„+!Ú#çóx›ýüñQ[1¿hÚÍ çe¼uë¿·¶UÁÅrMJ ôÌ¥†%rEð«Ux¨ksÕáUmÀÆýof€‰:<;FEhgê-䇙ëã‚qeo®‹çxËAþ©ÙÌ̼J#XÑ#+¡4Ʋ} ðN†•wÿˆ‡úÁ³,ôl ýö¢¸¿ºÎû¶‡ôºŸˆ ^× !—ˆ Åzt¡lÍN‡aQb£’€€¿>ÁX©! |0º…¨Þ1ät×st&½óýqÀ‘Ó¹Jc¬ã1Y°—zi§@:²õ2;YQuÊiq]ÍîÁƒÐYÕ€½t2ðÙØfò"f:îME1ºÁQ¤äëÌ9OÜ~øº¤ûO{pËØ¶U¼´ñC¼óòË'ç†3Kê°3Þí5ÒnåDî·9ZÀ‘(nvù¯ªhŸï€c¯ã*]rc´å„x­ÙG1OôÒ:ÊϹýWâ«H½lᦨ%U<ÞM2íµ‰tƒ¶+*'uUB¹;“²‘[¿Ø%¢É£ÝëQ.÷n“î_YEe鉞É) ë×ç ‰èoçån!8ų”vÄim‰Ó§:¾@<K`I‰CÚ¼ŒŸ¿‰Ò½€GW8 n8K4úŠp¦äáÿ•hs!Vo)B·Ù2âAôz²åÒ#Ç¡[´7NØà†m÷\D(5Ò¤jÙ‹³6Sòü„ˆÊˆš•¶¤Í~±:ˆ—XÇDRdeþé`ºªô–jˆ*EŸ&°7#çÝîCáß‚j÷Tá 2xMÀ0£ŠBè¹~¢?U³³YÆØ®­vØt†,u½ºÈ–n>æÍbnïƒCˆ‚⻸fqëC~:“nv0¤¡F=ÕrÑÔá¨ßé WÔfp¸’ûÓè%ÄæY[œýk}þ(¶ÇtÁœ¸OÒ!N…Nƒ+Î÷¬¸»2Xãt˜ÊáÒþSœŸÿ_:WÏúX+gö¦d]Omþ\C6Hôæsá@Fe1äREò úÚ«ªb½šäåy†™ƒh1ÿ?üׇDå?s©þb9v¾ #¶,¾^³8JóD­@¢ÿ®vôµD’d¾±ôš´›.?’€€®à¸ü œ#Û& |®p¢©÷ÞtMìV÷Xu^†­úˆeÐtÝp¶M(•—MMb‘(õ0WÝ@y÷phøòH=“IÖKÂiË£¥É5ð”ÊÐܤ~å'뫒γ> 8@ĘW{s•˜ìì4"›7XºYLÐñ>çÑqáX%´h>³èýcZâr´µj„)Å1dËü“¸Rm(×é@hkIñ_v7´€‘ÅðáÓþ­h÷ÜooæežqâüÍjã¬ÈGÁgGC—öw‘z6r0‚ðÁR‰«|PW§–ô“¾Þùr •¿¼þ;L¹CÉ@GyÙÔ×ñÉUc•V6Îל‚lŽ¢+‚GîÒN~Äœ‹nýî’{—‡Ü:‡u¥²±õ9;sCÇ:¥ æ‹€9=ÆYÆ–‡õ#CâÞhúÏ{0l^ O_^/åÒUƒò¾¥[ã·HQ¨§-Å>óãÞ?y#JõõÌbXâÉ¢h+—•íló$žp§UEÃZ·YíX¿•CàÓnÇè@?³PŸá´"heÍæÁ-'YˆgO½®Î¨›¬îK/—G†¸tòYæ…[_B)öOjœ¶@5aº«’j%KÒƒwjN¬ç¦8ÇV™’ ñYÚxÁÆRgÁSiZÒ̵[ª¬¬)Î×ÉOq%¹#Ÿ eK 3lËâö-xÝÇ÷7¡J£c&pÓÎÇDÀ[nzâËüó¶\c§Ì€p‘"äÈ`è…åŠ;’€€¾zäó Ž’'öVqM'õtyXcï÷@EÎü^ý>S²-ÍçoãWîîU[àÏ ´_«úTé=;YTø¬³ýÄ;Ñ:YÀìóù!wõXí5à [Ч½êÂÖÓ%k–\˜ÐHí9Õ¢a²€l§¯¾ûg½pY©Ëü 1íòb½ïY¥G[Ul£0ŽÚ”æ€Ã„rò˜@DžMe.sP ƒRÇë¶… 3°ˆ—Z‰Ý(HñS*Ê€x‘±Œ¯7 ";}Ëá¾QÄŽª°e8r!à‰.æt>ìve¢•“úz7V¬ýYCo.áÜG$–þÈøƒÉªÔ8ÊeÏgA#“wIÓ¾lO.I4û:s úÛä®Â_O ¸™6EjG!u&>»ä˜4{…´rcÃ-Þ ­ÍSl‚C{ù›03½X:”"$YœDhúVà?4gœÛ|ÊÌ7ô=‡…úÁÆtcªÇ‰îlÖ¨¿s­FˆšØ¬di&¯²–Åך–7 tø“,~#$.ÐûÎûýéGËlƒº>(UHÑŸ¸ÂæäÂÄM÷À¯C­Í¶Ä¡Ü­;RÓÊÈK¥»PŒ-âlÉœÝAvP|wsè{U$ÏÊ£“q¿–_ý’^4Ë`ì2ˆ Û1qÿÏ–‚š¦Òzšôc(ìUyËne+ÁÜü‚Ÿù{{²iåþP©³¨;1*iRÑ  “ËÙ¶AÁªâŸÍU(CÑŸÍYƒk@«!n×jcŸp#…p9:ùìßs@ Ú¬ÜBû%Ø… ~‘^lÒîŒòÛDóõ ë?AAÅõ¡×‚Kh}p6äÚ®RCÓãw¸þr0ãôν7È® Z®Ò–0ÝÊn¹í¼)·Š·D-9ýÁÎ< yPÒqOÔÜzü“—4XÍÓM>ÜC~¦çõ¿l-qËA*FtÕðâCÏv娆·f턳Îýa~ï{àØá¾ˆüÄYî¥øZnuß9ï”–®¡Áð°"ÄŒ@úÊÇMúâç‚ó\.–ÀÂDFì-lì÷%ÒîÅ0ç‹$]¡+=IKü5nX”]¿sðiG“±[ = +~\\¢6BøÕ`<ÿv+7ÉÄ5¼_=+fßóÅ>Á¥Ä,ÇüåXe,ÓSLèIeïÚ¯‹Ëöš*(²ùJ{¯¯#+ájâ3ð:MÊ-Žÿ=fˆWìÙ¼ˆ¹,ÿú`t¹Ó^rìDäa¾pßñ¬‘q@S‚ÊÏz=Ž­`J4.Åå°ŒêMA¡›xŸóF´4Lø®C'Þñs~Y#k-°roO§^s¦öïq"4C•ºšŠmF>\\ÜÈÓHmSÃzÂb#YÛL³Ýhö¦ŸžJÙTPC±õt.8~†NŠ.KîêÙ™%\Û·GFô|]ämd:0ïMè"•ùµõ9]yß”z >ˆ¹Ì'dZí$åå>%nÿ+7'™kæ Š¿ø×ðý3X¹_[Uþ…Éù>1êW¼o~éB>]w 娆¦;‹îíöë“\m ˆ¨Þuï­¤-ý‘¬‹y‡ŸºÂ*nšF` Cí †#qý[8&~Aù,"AVƒàÒƒBädÄ(ôç• ×KòPø3ž^Y—SÑñ+rba Ðqè¬ æ]îéSž`h!¸*kÁT“ÃØÝ2K3 2ØvÃ7 õÏIóÒÑ×þR.m‚ôI&L îCû%3u]º\NEó^(tà‹l,cúÅõ=%_ °1m35H•ӗתú[n“­ â}*[é‰JÜÁ‘Ÿ¯ Á\°…ÄÅW<>ŸSî^f•ùoðJ?uŸ¼ö­îìõLÚѯÀ«¹nÛëÉÔm#i`‘½ á‘ãÜ[—‘èô€|iÈÆë|­š0€TDZ/5?üì€Ð‡fó¤·\,6}õîó v_­À.­6z˜#,žz+p4bã T˜¨y*³8(ŽüaûÊbÜk¾ @ÝVŒ”ÝÕ¡ÛU ©Õ+¥§.ßl¯'<×5c£­a9 ¾*(©Ð­?Ëû/Ø[ "ljO3Åo:-ȪrY¥ !âúlÖÁH.næ:Ö÷ö ;ĮӴR<õ;E=Wâj†‘ +§ ô| Šnþ²:A— ,qõ´uàZs,¾½î„„c±‹†¶>¸E—9Ì%ïÂS!h<ç¹ö¦G 7s:„ºX|ËTƒg›DÒ×l)r ÷L˜º oKn¼1YžâI®t¡ Øš®ÏŠêFlU»F¥³þòçK_j†ã³Çù 8°ÀEè®%—ðd«º-AÉúYïîèX–ž}Q)ɳãÏçÒaü2FÊÙð;êë ã}»:×Ɉ)u9‚ZµG!J–ÿaÖN5W¶€ž¨$'aBwpœÛ\'žfÖÁKÎÛC–ÁH—ɵvuœ²¿¶´®ïlJ;)VKZ½Ð,‡4£sP~â0K®y2gºÃÇ,`áwxŠSÏr ®‘ØE/Þ™dL?4½QövF' ÚmüJêÌí?É8#Næã€ô$ôƒáÄÖ»4{Eš·o®õ§SÚ¶˜4‹ú=!M&·ðèQU8rµó¹VæcFú¾ù-PB‹/:wĘ`ƒ×Öéï½ä·«¼d"-¸«Œe`¾)ëlKõÙè’ãV¤zÞ ­;ž'~ÅYÃ;ìëWL×CœµW3É‚¼J-ÑWI6ãd˜nÚë´¼¸(y¥â‹)Ðáß]Ç—%$~w`NÛãËüx]ð¼r *õ)‚ï-Ÿí²Ã«ù°Ý,SÊ$líŒú…='ð«žW¾W3”iQÇ©>ú7jjÔ[ÎÁ×a?JQƒƒ&‹àNÍ‘Wþ+Æ i+²pLûôn:²kj>àB0­øMÕ¾à/O,+y¸‚·õf¯Œ³¬Â *l¸¹¯…Y÷SŒZª¾8Až;¼#¦1tfQ‰ë¬Þöîø|š~›Çd ž,óÒœE·Ò|Œñ#E)¼#>ÿ«a­Yizƒ}ލy˜£¤Æ`Æ -lËàŒ ^òÔx !c°™ì¬ªû÷!îê˜þR_O@®qLb³ìì1åÈ$Â*.&ÈÃS¢:d·†!QDÄß0aý c7§Ô§µé«Òt)­ÆìGƒ«:;5в‘™¾­¹p )=ôZ¦chd£Í¥n^h‹W™ÁtEú·ç¥_ÛGØj]W;7¤‰àêIw‚=t„3_/wdb–Q‡Ø:`D»ÏvqÕȼ.Øé©QŸ/[C<«€ËJŸ ‘¾_솇?bBhs­t`°Q¶O.O§=@i3eÏíœ.°òÁe—f*-C\öÔZ¥C–úôÎ ¢ëÞcW‚3¥ý1ãàJm¾îìÊ–‰¢b&YðRýLxYã—â %d¤·„ K‚а;§çõ±Õ}"¾›Z¯’€€ÚËy÷9çn øÃç`cÏ %Ó/Â˾’TµYˆUM­r ²Þ¼GsÎ{×£/³@«Ç}¶-¬ñ dhKÄÎZ‘úÿßOp!ÉU‡€‘é‹  £Ôï>÷¯KŸÂB9ˆ>ôQÞñÚj`˜Ú:wwNbÄìVxì&}4Õ&úá)Ándç hµth¡×žs¼D^8ØÉ)Ø·xË?ˆš9õµx9©A%ôY!ü‡ðYÔþ¤¸ÿurÅñt¥fœÚÁ7ò±¾Ž;î²øIh88.Œpüþ<¥,Ó rUÝQŸ9»#5¹CÝi³7gqŽ€Ù‚dÊðñjñž"‡Û@ ×o¿™ª;D}FÜ*ÍÖqh`Q ÒÅ?+ëì½&n6 ‹Ç±ü´DOˆ©èíw¼Ô‹Ä~F:i'T"¥ñÀ)W•>?¼ñ C+GhZ§ðà×JüT‰©zg *ÅŽÆ¥™Éó»ÀË)à@Èíã…'_%“#y=¯™5ÍöÜŒØ>SU±&~…/þJƒ@üÕ2:—øŸÂ\µæ¶WÄBÔIƒZr&äâ)w”‹+òíC'®z²uãkG<ù=\qÌû{<©ÇCÞ;0î§»¿Ï)÷€f6S-ùïF+c®dôÌ%³’c—2e¨ÞpóS-|ß-؈in€ Õ¾¦›€tT ‘µ¤jçê>Ø^fÙ^¡·H£»"Ù’ T4J,=ÿÝ=h!“ƒžŸJ±'È/}ÕJ;TZ[°\(}tP”7ÛÂΑá¼%…nG½eô'ØÇêÔ#Œw으ûš #6¿»êAÜl½ô£¾­r×…Tþœ9Ñt& N†¢Õ¿ë–VOƒ'áÎjóªvl¸QnyRR„Áy\ L½ÄxgRj$#ØÐxàj¨Ï´’RÛzª)…ÂŘ‡Ë #^K£5°‹¸ ›£X~ÓzF«Tytá$® b›8d/.×"Jh¨”í.+ ŽrµÝì[ºŽ9^䞨„;tÂ!^x¡w5B KIoþh,#dfRP¹)­î¢M/I1Ö0åp(ÀÜXä,¶yL`«6¸ó^yÎÙ8†Ì«oÞŒ€œ…ï†âêĂ咀€È(ËQˆDò¤;ª?S¢Ð5Ve– à Òº¿¢zàµôL}M„'2êLy6\¡ïž“Ñ5æá¸9 ç&Ó&u4T¿¶ÍÕ­¬XÀ鈅»¯¯@w§_ Œ*sª’[UÑHd@£Ž0gO=iÿÚñN´¾ûÒ:zéÿ¤¾ ª—J&¬*  ÎˆÎ®Äï†Àõb š°¹nU‘MÅ»*™ÀÄúzïÛ¿¹Iz +žðSÖk΄íѱ³Ö·ø+ö'&å³ 81ø½Z‘%H˔Мª ‚#®§Ð(°ŽÂ}§êÈFqDx¿˜H߯—rÆ4›n/w8Õ¢=4óT½¤Bà†/·6¯lo#†y[9}I¯ÃðØ£ŒpM”VÙ0â·^Ï1šûé PMHeT W?§i!8,¥g\m–!~ù´{B ˜A'j€¡“J>1Ø(Åßn ¬ð\qе­WÓ¬EPÏõYëD¶™ ¸ÕšÞ-Fû“R»H™½û}*xº y#×^*žRÌý‘Øh®pÄXc³ à˜¬,‘xŸS§þøÔüʉ< £²åƒ¤êœZy£Ö[æß;bÖÆ¤sYÀ&¹ù›Ì¨õ÷û!ÓIø+îyry;ö×5¥)Œ’€€ÃÏež«þRl®‰P‡( ì~”gDMå1ÑÇ^¦#ç˜8êbý¬Æ&’)· ‘[$æw‚}kpìJ)‰>ЙRµl›¢Y¿Ûøܹ‹Ö±¿ùtÝèõ¶Q`©J{˜Þ•an¦·ÁÿEM #_zRèª^„¤/^€R¶yð­ÒÞ®Âr ²ÙÈ8Î4©³2šþ` P+Ý|›ÑÉŒ+Gžl]ï‘_­;ÂyÊÇkÐ’!eÏ„U7‡¿RÄè'FE«fÇeîìÎôZ*ö\„Ä 'j{¢¯ÒQHzD:GfšGõMBƒ]Ë ”ƒ‰7&8}o ¬ MUv"D% Id²€ð}eú¿^S\zwH™Å{1Z¬3 IÿîQM3\î„É`Aa¿ W™£Ckû|UC¤¹‘]2‚\9XÒ ;6úÚÄ´èV¥83•®$çϸHÓlÍT Ìžâ(ö˨œ¢ég±å3”c}NÔ!a6çd•ƪuÌ]yì'£>4.ô{xP!0è¸ÇCш:‡:ß.*ü¶F°¿r7·È|=Â…–Tû\7…V0™Åµz‘µ€;Eqê ¢ëüC|I#¹s3Oæ™ð÷”2cûÄ`ý9vbÅìFö‰XZ’ ‚BFd#;P>ËQå¦(!Mðv¾yôþ&ªãÜœk^°ŒpY4‡…?hŸ¢ÉWÓášÀdWž—C š8Èx{D½#B(™óŽVÞNÿ@Ã1ØsU`¦Gž)uÙ‰b”ßM6£/!? ODmHÒœ— ƒ¬H<]”X¼Õ¥n9gHÉg×n‚¢‚W*`…±ÚGkØÅ\ ;1güÏ8r…› (±X™ÁK ïçwÕg«7üãÄà Ҏæy˜ây‹iß œ×RPÃöi˜]Bm›Ñ9¼Í…4»Èp ›y¨Â¡´äƒÞ«=«¥GØ x«õ8US!Õ©_̃5‡¿ÚÕt‹ŽjåEŠK„”}ó(;p{½ç×päÎç\0#˜º—Oc«)_žÍ‘å iBÔ£=ÐÒYš/grE…J‡‚òv·¡:+!ƒ"øùoNMÀzð”årÉ;dó.b[WÇTÑWß*[0õI\6 }³¨úö£WÐàšÔñs·Â“²«ÑŽíæñMçUFãFå¾x’Êú#y’€€ãÄ\x¨úL_½SJhˆs%'s(µê;%CÒE<öõ£CâGhµ\œ]4ÿ™ú%TN²¶Þ‹–¬EÍ&ÙPÁ*±IÒ(eLŸª8Ķ¢ëˆŒ¨ÙÎ΢–¥í$þ¨¿ïበ{žF‡KÆšt&ìv • °ñÛï$ÝPb+wÚº›¢ãvÜgjÏí¦Dûñ(µÖÖWF&‰âJt¡R®kÔ¢pP@ûyüluð½Èh”UÈoTw¸tlœ0ÑÄ—Ö ÷É“ßm<£§Â/L¨\)ãÊNg†p&zzÝ=x߉*ª[²ÖüKÆ+¼P'ž¤ã>a£>Ï?ˆz‰x$+]ÏùH\z~ ÈòÜvc¦ VfZ!+ZØOœ#ÛV£b1*RJƒ¹“ å-6l†±Ÿ°X0º(ʯ§µU÷/²Ïà00ða¢Œžü?½¨X*5„缾•áððª@=À_8éQ @™RÚ V±Tdô7 ‡j²›DEÉ •ÿLo™ãíE¿3õ»·vƯÛ,RÔ&+¥=F›ï?‰úîøk1—ŒÐöCnÎÒ7£¾\Q‰ûtHÆH §Ì!ï³1#x+äàq ²©ù8è#éqÍÂÛ+© ÅK¹á•Hî-Á¶ð¼¾åGšãѱ%©ñ„@Ÿ@7MAA[1Ü ‚qž2\õYMÏÉ£².¶Úe#ÉAzý Âiõðé!’.[”^†C6R ûâJ¼;³PÏ®ø¤dfL}¿ÒúÇ´ ôÙr@·T;Ý´c¦ÇV8õZg'‰¼ékÓ&¼ #ùP@IÆÑl€9Óùñl´øYˆ5{œQÜÎÉ?UÈÞ!ÙÖRúS¤ÿ’OÃûõ}"Ò‹Õì>¢8´‚8p­‰_NÍ7Û¸Y{GÞ/«1EmŽ+UÄWµ­ÞJäD›ÖöêSðlšlÅÇÿ˜ù kn^i>CöJÅæÊ¹³m.seÌ>èÑmWž÷±®Jb#X€ó°Cíê_T!ZFD{‘F‹¦é|lÜ71z#ÖKµ%ÑŒ)îm"&†VõõVj»`´Á‰ì¨ËSZ0CöˆägI#Ù„E±‡u¹û–,î”Î,%ñò_ê%å°ì3Ó†üUÀiŠá“X ä=uÆ%5Av£ú¼’€€ÇÉ•T zíªÍSdm4‡ÈJ°ÜU%Í'Ù?‰Ïôöºè~c÷Ý!Ò«D5D•ѧ[ð‡¶5ÅÅC•výÏÚ}"I©9<=Ôþ߈÷¨.îõhSIa}X58§ÿk@ûóÜ1Íz VJlÍSD‹³g_øœñí­ÝÝ|–>°CÙáNe¤\‡´Ž{×1p4oÄVy|ó‰ÿ• J*ù8/ÌÞ’P–ÃÓk ”T»…‘(g Ÿø5Àú’®ÕÞ@ù_…åc ÄØg³\:pùÝ›hõ(s¿û()E±ÔW’‹9þG«Ú;Œ7ÐÈèD±—8$>§mÑ÷)Ó·¨=?S6 Úì)U­*¬dê94ë–|š: Çnß/èUKçm¶7ÔÛDí̽ý$Í› êXjg¥>ÀK^¨Ð Kø^‰ÌÏlãçñ¨pÁÍb¢\ëQ àç ¿•ûÅJËÿ'ì(éíæ¸¼ýŵ*:¥3K÷;ïI UÄÌCË¡v)é·Z:âgƒûÃÝÕŒáVµþ‚‡?ûOþ–ôCh´ð£ÛåC©x ãÇo¥f·žk +(ËÅÌÌÄO™–ó®fIK¶L¯ÆØÚ0¢›DØ~șŶ†ú¥¢u"ˆÄF7øk©xNWµÆXaÿŸÕ&ì>i˲yè‘ ÀòZ&ò€À'«³vŠó€aL 7*;‹:©’ä…Òô±²»ŸT«‚ž(.Æzƒ0u[Éö¥CfÇ MÑ‘"Æ’-þÝ\Ô5ýØ}­-§T ©´Å CD¥¢KÂ&žM²s€ñ_çðMUì/A>pàãn1U"a½òÇøÜõÂßÔ{ Ý y Ф"ÀÌiÇéTêF_~@ÛáXˤ¯|^åAM¾ ½Gr`Á!ñ6µÂÇnçdJ°ëjpTÇÙA ¨b¼ô¸šnâ§yäÇÕ½ç«<®‡{ð“;ãÁü·elëDÝÝj€„—A¼|þ… £%„¦UõÞš‘°’€€Ûd]·×ºð Öœ ï;f«DCÔnNy¦Å=‘ÎÂL^÷:ÿÔ²û«g&ûH^Òš>ÈÜ ±à _ü«:õ+¹@ κbj¡i–ïØWø¥Û®¬ÑÔ8£OY#›¤…ËÊRÁN%ù5¥‘ó‹†ïk+ŒH¸Ç'Á%Hè›)0ã±±9IFì³óƒ\ðñ R\Qrßh{ßÞ­Ùl:ŠÜ˜šÈÍC"Àu|Y}Ds_+ssß>˜¢Hån 2ûpd""ðêöâ\ùÿàY½(u¦ ìüÕí0û™Q¾Å-BÎì‹RŠÏ®ßÛ]Âü åZfB ̾)8­‘ /øv¨¹YÒ+rKˆè·’ãOÃÚÛ(v¿Ñ ÷m‡ î潎ê¢ßÜqÞ¿’tÈïø3nŽôé(,€=1º±jªÁ¹LsUt+Jô§˜Î„/>Kém8…,ÕFPìO‡=š,SC|ß™æKÁñþäyaA—ÓS»Óc2÷—é‘&'®à3ˆ¤Às%ÀæKSóØ÷ÜÜåºÜA‘xösÃiž«ªÜmË"uEéŸT{°KücýèDFåNªçÊövöåðï&ÚßF¾È¸Á#mª—ÂCb,òlSÜ/yôºL_ÑZƒ{Üs€‡¼ÒÜ}; å9…œÙýü.™É÷›þðÝÌBBD$Qþ‡F’Üiê ³ µŽ HO<{îlãE°¼-­ž‰¶¨€ÏnÆ¢×7iÅ­Ç9æ…c9ù ž9 ¯z×{…‘BgwŽÊžW¾„a\¼j2_èJáZbvRz GiÛß³üêcÏð6kß [ó0'qyšñ·u#ïá®dßy€B ŒÚ$Ÿ¶bœ*Ǩ Æ ø.̸4‚âÖ»9Ÿ ¢ƒ:':Ê8ÿHÈ”rµŒ³UQ¹Žà„x ‚µ•:w-ÑlßYRÕ)‘~§Ì­\`±Å „óg-£X‡Ÿ6éž_ dóòWNÅòñϾ“óƒÿ˜êtJÀùWªAXEÎÊý¯¸‡5ä|ÞÀF<¶›Ûì[øÝˆ*ðá«Ø éÍÜÔTT€±˜Ð¹˜ÕÓèJråst«çÊÉÈ Ž²/3åw>~Ïœ¡7´µt}ÿr´¸þˆÏ¸žE™å$F>v e&ÅñsÊ40u¾ I[Ï-hÛÍ ,g2*mŽ‚‘QezÒÊgÄ£»ÖÜøƒÂRÍF¢ PræÑ’f2n¡²FQ€a’+FžßX>-õW’õ6‹‰£Ö¯/lå¾Üüü,]&Î{¼ë):X¨)·?%°oqU£OƒöFN´LwYˆ¹ø[ÉJ÷ݳ$þ3£ÈƸ,©/…ÅW貪SLn—›«Wó?¯KâƒßøÈÔvusïÐÒñ麚Xˆ¥#ÕƒŸZ¢m)’’3|âdn Þä“{g‰UËD幞jƲ“Ëù1Pa ¢¬ðo?ÍÎØý`³v/ÛŸ:½óy¦w1¹ŸíEN"¦2Ûúë7béw«øa²rn•‡o W@f§Jçre ó’û›W8â÷kMiR4€|xuü˜.W`0XÊyü/\©±‹SÿóQ‹Àx8[p 2›”£Kqd\l—2Z ­#ôCÃÞXMsŽxñts$M\Æ×™*ð}NÈs†›ªä!Ï,[t B×à+X$Zoþ3F#Ók'ç«j€Ãm2 5¹´,¾zŽöæØñ aÔAÎ`8¥ÖJ¯‘ÜK~jCŠ=XÈJiB²ªÚ<Žö€K ›í冰Y9Ãß$E­O÷©:îu¿HÑÀÝWUÎcƒ_½±Å‡€•ð¤¨Wƒ! #­n ñ<·aÌ;Vœæ¿è%P=k°ÐÌ9»c‚zÜNÜÝG:ÜrKÝEÄ.<¯Ý=¨´Û÷Èî ¶þyjpÂccºî+u™GðòîñŠŒ< ë–Â䟡Ã0‚<>jb_¿ýáwhþ›­}–Lª6wª—&éµFÖ*~|ñ=ýuYq¬€´5)X¨ SYi‰{ŒŽX^%€dX|ÁåD¯TQÁ ÌTÎ)1%â'l)ÕPr3ù{Ô»“ëý¨ØV} “f¨¹…²¹u¹8‰J G]c[Ë>º©ÎÚƒ óihiÎ?i—FPÃH¨<çÆ¯ID#P†Ô¹gÒ»ÿôÜT¼8A¶JAõÃD’€€Ãwvv‰KTõ,šŒÅ¥øbeÒdr|,tàD³Ý§¶¼ã«›–ð±¡; ¯ƒËf8P»{É4\Y%)Y̤>ã|ø‹—W¦¶óH;&²Àºæ€eu˜f} ØL‚¥Mâ àÁtk9»ÒzÐ6ˆÌ üÞßµ/«àØÙÕ=°¥ZÀo¾Yñ´Ðj p¢GîÙT;O:7³òð³k ¤Ð—RºÇìÅÌ~ƒï^x²vÀWí]ž&Þô' lÞŠ7 ñõ›> ~àY†³À^¹H>TSêQÃy²ÅMyÑþ½‹”Q4ô<Ú‰"Ñ‘2L:zÈt_ ÞBj%à|·ò—un¡§x°íñ&kœá )š^x–-w_Ÿ6m]U¥B9pn…É^žâxÏkæ“‹Šµì9ÏáSÛäxašGwAu+~»'ƒþkF1ˆº’OºH—ªKk*Ȥ¾„·5S< ‘C#súñl}²gã‚ýÂI>i$„<ã‰|Äg6–]‘F]â#©œúÙæ”\G³ð— R/õ£Ï*Aã¹ ,òÑIZ¢°ûücÜŽªáe dPè!Iê÷a^ºÃ"³½Çø¹Ø&¸]lqÝ´Ó8 Wä”9L8j3ê3׿M5äêüe© êyˆ#áUu¯ÔÖŠÌÐÜšãCQé˜w¨Õæ+v\ðieÆWð'UÛ$´ÙRñÜò´±Œ©k$ÖI ñ(3äZ)“º:ËôîÈÙtž;æºÓatvÂÁ¡#ýWämAå9Ш$éõÕwà8Û÷‰Œ ±FXÈü˜ÍŬ 7ÿÕH2öYY_Äà:’ݧ‹X‚üâÃD˯µÖ6ÎTç×oc{X/ùÓ‡$§åÙ|صF`c÷»sÉŸ¢?Á€TƒöÎí7ó#¦Øåuè?¹œ=pÑë>Xžß—4·+ðü#obšÃúåÝ 3ûÑõ>±ýŸ¶h @n>†òæ¼Éèäö×òp4Ü¡â>ËÉåD-ÕZT  ´°æl±¬Þœ++rW[yPâ9~*Ž®Râ.Ÿ¾gçmä.°a„N½ÇgeÙ«ÝØÆ§siEô¾ÉZþ£µÙ‡×™ïTÖ/ÜòP`$7¥î²Ú[þï.·ñ+TwUC3r¡œ}ø‰;¹`ã'-Ñpà ’€€¿Z¨ð7­d 6u[ùôOx³ø\±n‘î,&ÒY`úqZo(C›zÙ5Z§úåüÓ}å™XI_Åjºúm Òâ†jʲ°V³©í1žö²Å7k|ˆÚ¹—!áÒ¢Ý~V­" ^êÞwV…zÊî—ð¬3Ue!,RæÁÃç’%Õë##:ÍOjœËê¼æéˆ ³ö_ê¾Ñ¼vD®#Ì$…”i VARL£.CtGgbªÿ½Ž=œb´Ã¡5Ì·ƒ0:çc#É¢k‘îÕ9dÓ_‡x§nc˜dÚåMÓ=ÝŽX[ßþ›þW B•Éf[u#*l»¸œ´ï€m eôÛa‹»Å÷s¬¼ö´+¤ qTKwnW89'™œõÕ2 éé²eÇ£2 Éf€ì)¡!&ì<›84Ì„£²¢ò%wבúü¸ÝLnì÷A”8€Ž€ê¬¼Té."´?{8ó÷ÞxûÃÁŸú°xÑÅp{LÊrëC^Åa«n]ü®Oi4 YÓùظTýõ§ñ7$""•–Êc©-4ˆƒ¬ºkk2£¶×ÎX¾»³SÔ&‘hãGÏýDÙŽ†\­)@A¤Š~`“)ј¨•o®â½Ú•;² Ї<¤.ßܹ–à*jó‘ŸšÚï¸:$¥8"†œ×µÓ’Þaôiîù_5ÍG~é>¼¯9±p‡Y׎y;\_P${5üÑtjÍ1GÏMÕ`xî§jt·’’¦Ì›ù±¶ ¡Iz–S$t%4BØ»ËKZ§hƒ¶Z‡@ŸÓ/܆-K„ñàõ°pÒü#Ì8M$¤ùaÚ˜Ìl­c·È­tk·6fb&̱òæV¥%{ùùø:±ëÍ]€3„R´¬m6Óbù&q-B"àÚ¶*Ú[ŒU×a„XîI†"}#´›;iªf¾O²´ÃÑßwá䙡u¾dEH¨Pþ ÀZr› 4RZ|± Ñ'«u´m"‰™“ÔÞì—ƒU¬!˜ÊýšQ±¾Ò÷ÊER©§î=¯ÕÌÒ³gŠ·!ïŒÿÝ+ÖÕay Ñ çˆNK¨p ƒ(DlÆ Ô 1B`?ž»Iü³H~»—ªC’€€Ä!rªU=k£fÍŠ®Ô9OÕ€ÚûÇ3µŠ¡º·jªœ×ZÅ0+Ø×Q£Ýœ÷x$[ŽB‰¡^1²íyATwù/¤í½¥ÇB–»\ô¨â[°¾ÓcO|yB¥áì{}„ /Ào7Òçb- ¼þCwþâ§šI‹!²’pùAõñ¢—Œ÷€ Iu(¹±àeÜPÈbª{×ì+¾£ºÝ¯â±Áæ·3¡'rXÊ…I&7¯™˜Ú®7ut¦uÑ­»‘Þ<1ºQ$à7©—„skÎ?ŠÝ4ùU¢:!‡1"œ f Ã’(Áàáâ˜ëe=hfÓ~RwDMcÿŸÐ³ßB^ÈûÙEìKسÛ*ùš]™ðÖIL:kKfcØâtßo×#Ö<$ߡ{nÿ`d¸M–ÀP1¿ÞIß>ŽæC„.3y…Ñ'c¿Nû», =ÆþR«Ð\Ï’ú»vP‘rÉ·ðÕÀ²é—ØÝFÃÐ÷õŸ£ößuÆñJvîõQ¸&åcv)_XZ™Ÿ^s˜ýÞÏo•0eÂó:À¨ßNè*"žU“)¾úuþ²ø(õ"_ýœùõû Œä/›s~ö™•CÂþ8J(jW:ÆëN¡-/ý¹šV6þ ˜èëDpšî"† a‘ÉÖÒo ¹ìQuyZصÞRc´Às•%óŽæèL”±¶ªù‚6?÷k‘ÍN÷ç÷Àz3$dá?BdmÊVt ¡ä!iÞC‘ÈeLLà¯GUeÊƹÚÞ­èoãŸöýÀf¡2<˜.ßHÜ6^"õÎLW%‹ÓGªè­OžµÁÇÙ«YÔw%Û­Å ú™~§¿ ܾènï+ ÙÃön毕àwÕ¶šÀ$ç›0Ð]ä”´Mp-6e¨ìNº‚°ó SÚä±’iz¼Û¥×yèþ„Rí•ÁÕÖ :ÉÿìD˜/nÄ9ÝMÒͼK_«>¢8ƒ|é½Z=v¿¨OÖÞ/«.Ò§[ÏÏ×Ä?,;·YZ×¶eǶwÕŸ»¡LSçñ´-^`‹þFÌÙaK~€„­Ó@<°92 Ÿû^Ì@£Ì“užÀøÓœ0¤¶¡”fØWbBõã0®Å ƒ»BÊJ‘œÞÈ(Õ…—¶,UãDÇë¦z*Ń:,l2$—òrÖ1xß+Fs^YŸè1÷79¸LðS‚ð\íúÀnŒÉQEc-=!•üÅ÷ooG„ÝÒ7U"eíò¶‡­TÌL ký>ðàoÒê–7vÅÖÍïÓY:5!©T“Џ]* .{féæ' Ÿcº48ôSÎ+‰}4ÔÞ@Ñ)¤¹žaÄ1vBù¦ÌÊ ,,×o_ÁÚ ”;Ó&xq˜ È쿉×;RhKx4ç&ÎLåú0qû w4_»üõxBÆ´µ…Ô?. 3@²æŠ´0XfSN6dÑ…õ¨¡™4éÁ_^¹ãÇ(jJ<Í©O~Kå–’¬lG&BEMæºq$!=©ç¿¥ ç¶HZæ²yÛÌ:z 6¤ïpvcåoû¿”Ñé­x72Û—J. ´ö/ ƒghJÕVBOb„ñdf'ƒ‡x¨JUšQv%3à¿þ“h6^Ñt°ðZ[ÁbdH ´òI©îëÐe§ÿ¥ÞaÉm7Í`ú© Sh›ÄLI|öñùæ*?Â^¬§-ý“Ø»xÍx± ·›B]Ðù4<¿Y}¡ðÒ÷è1Kv&z‚ÌoA`(9¾+xÊ‚,CNu7ŒZdòŽb¾vÆðàÃÿ¶~˜Štß‹‘u<É ÃúÐüì›ÐÚt£µ8 FªmGÏi„EÉœo¦È Ö0òuÝ)ÔlT©¿ÎïWÀØ K|ŲŽÏgVZ &¦¡k©ˆ¶¹šâwž*¨´Œýµð˜"òû]ƒÛ¼ß¸ß *û¬Òñ'«$L6$¾C½íÉŸaô-k‹iöˆMŸescä1`Þþ4V­ä%ôwãP(¢gÄB-h§uQëÝù$lu`I-ßnñªÍÚ÷Ló°Ä×÷“ÊfÇ6_NNœÆ_¥wiAV\°øüú÷¿ïB¤™…œ¾-  Nƒ•§±6xe×:'Ú:èi™¡ÇÊÎScºtÒÆ°ß9I @„I –F&ƒ’t·c l¸¼@çF{&A¥<ÎèDmÄ4§,Q¶`1ÊÔŒ™a*+/?1ùõ9IÒ¶ðß@¥xþÇõ à‡9Owv"æÏg`ÞÁhø¿¹6³„qÕ»b§v#º8è$a™õ¢ó½ÿ6ÁP2Øü›©­Ž83*›‰Ëð™Eu®f-½ý¨W^†E1±¸¿òÔó +9$;Õ«“Ú~þî™Bh÷„X!V$Í O$…DCŒx*.‘øÓz»Ùaú$N„ ׋§Å?®ÉÃØQ“.C*Ýæ:+î4®Cj”üFÔ¦”Æ4c·%ä„1éˆëSK]5ZšÊQÕ­L¹ªx¿;-{ä½q|´ãXÒ4d6Ys·ßæ¢ÏMÈcð e&Ú¾5wTV‘#¬ÐUÝ}þö0^8×”ö‹Ü—>ºñê8ð˜`2þN Þe%Õ¢Íe>Ú/Öm|,D”¾+£õM5Îz໕‘§€U`³hd¯¹ï;žÈݪ•l¹Ó…-üŒ¿’‡öFn6äòñæ|pðtøf%"â1gާW…§@ÀïÅÌæqÀÆ}Ô#¹AYäb9ˇX2Ž˜z[Aü8™Õ2gNuIÕêñt硾iXƒ“¥}=žG_Wd¸ícŠþÌd0ïõˆá?ààQJŽ,þI]͈¬ ?}$7‡ t^ëæÕ®µ}ßTÐqž_áÒK´#­×ËóX`Üi;[=¤(÷,Ì<×à{Plrü£Û_«â 9Ù€ž`ºcê’uôçé”OØb$ƒÞÙ¥È!Å” zdÐd3çÿ-gQë—"ˆ³ÃŸ¿ñÒyC§rW~’€€Ô*ÿÇ °Ââ1öÀ~Ù^û¤>#|›Àkõþâ¸IFµýÓ^úw©b\®…;rq÷Fܾ¸:î…|‘HÈ”=kw¬“›ðS™Ï½ ;ó<-¨Lwx©Á™•æî® ZY>âÀZ_°ÍN`ƒR죃ü‰ãîXmÔXÊr’§O|¼ÇYŽÜã•àmöÇè—ÄËÓG¡= ïwž k«§ªû¸³}8ðýØum«ù ®d2 UZ‹… AýZl!!.×[¢ »VëçDÈÔa)¦˜²¶-³€ñ-×2Míj晹¾…ÁÐ$aàLã{*#Z54~­±ŒrO·8"ÇiÛú¯ëŒž•‚æMxÞÍÛø¬tGüFgØV·åU”d"m‹U0覴U‰²É¤íg¶6öîyÃl4ùáÍ'ëô—uÓŽ˜ùŽp´”žs)$3p„&[^_€Ë}_â%§œ”±z:½ÒvZÔæù—ÄYÉŠkÌ=ª¦‡‹9“§9Ûˆ”ÇøÆSd(de5µØë¦^™XôÜ™2ø‹¢7è–Š¡¦ÃYouŒ9b5Jë§S˜)ÚFf¼˜Û¹0! Lz¦?²ËÒõ—Ÿìƒ2†x>{~}€ ¢*娪o¡:`ˆ¨·Àý¹±õ Ðãº:SëAÛ7 ¤§¤! ´¾ “©¬¿ËØkH5ÐC¥c-%ßïŽPâñ-jqR*¬aÅ%(¶š—îÜCUf±Êâº:«­'ö¼‹cæ&é¼Wþ¾rÑÊn )w[mzZ>­EÍg'¯]SKÌ]ꀺ6RB¬˜Å¶EY·‘UÓm#½Ý¨À= ŽMËCÅ5âÄÞ’[¢;wSQêGffÛ;Åòt‡C‰îèCrOtš¼é›‰ ÀÚ€h1- LR&ÉŒs7G‰ TX/ÊOq¦yLy_N_X«¦dÈéßzÞ—¸åí– ÌlV+B!¯)ó‹÷cs4¶­‰‰•”UˆÈ4qý±OŒD]_4!$ÁŒnÕ0c&VÓ„€†ŠÞEŒ^.T qx‚ÒH%²†{‡Îú~ÏÃv øîµîdb[‹üÉ)ÉTï‡wZš¡âí´yùÜÅÎ¥Ÿ´2Z”kpSÜCËD|(ÿjŠÄä £¦ãwù'¨†óo˜œ8µC’€€ª!jzçQqc?à: $ËâºAöÙâÉ mZ.b_ƒ+té^ܶ䜋ގR?9WmI†S£(~éÃr¢QrBYö‹BmyÍÓÕs²ýÚ^ E_ÝÞ*à]ÿBSu;\…ŠÚ_Œþ]ëÞ @ÅêÚñSŒÐ‹‰øе^‰G:vñŒMGòcDúõv[¾²¼ z#ã5ØJ ±†hg;9§Žô.¹¤²í’·Uç ™qš1F \Wä+h x`×_ö `µ¸iìkbÅ5ô Bœ´TœDÀÞ¹KÁçØz’À|>ÿEæ‘hKÂn=ù’ÄЬ1û‰âí³¯áÄcKÌ%ùþUSã¹<¾çù7°ãn3:1Ý Éõ ­}rXäÒúE¾Ð:m[ë:o7*8\ m/“ùðÔĨñ»D0Æ4Zä+c ¸Éðë¥J<ÇÐ{{bÊ{/ÛŒÇ'äü½ÜÎí¢"ß°X e%Ç(µÅ€èM'Ö ª»  ø¹”Üœí¿ZK‰Ü®‘H­P‹c«S† a—mxOÁk5>f1úÇð; Ö¯#\ž¯úIÂü¥ ~9¶nS"Ö9äU=°‡ØvS>tŠô[$’°óœ­˜JÔß#lïé_I«þÊnüT\¤’KaOEþ=²"Èq–klÇæp †OaØzNÇ»9´h8ϼ›€ã Êk!žþ©›€ëñÀ!ú÷ /¶acNðÉ´à¶Ç £•7¹‰ý®˜Ž4Éíér>yO‡„8+*àù—*.ŠŠ´ý@ˆÀ»§ˆ¨årůüiO“KÄ:»Œ€…Í\Q½z`¿ÉF].DáÉ0ñ}‹¹×§ÊÇœ9–֢ДÖB-Z“óüó¬Tœ§Ý}Z#€å]Ý%­7Ø’;+h¯MÃtû{.o]³€]œ[gg°rÎ7»ìÛúÔäâh‹–7 ”SÜtû-ÑéÆXjXlk÷?Vmf•$:îß“¤H%‰q¹ÌíÃ{ìfèºXÓ 4‡ ìb¯ aü_ŸHçúÆì¤ÉePë¨dïü¹±ªS1›À•þÂÄÔW>¤_Ë>üe¯ûgž#Ì‘SzDRßvE)Y. a:P\xõZEÙí»JVÍð¤÷(@j1qÅ× Ú9ÿߟ0MÙ`”4g{Ë ’€€ÑJ:[ã‚§|ŃQ.„ó2ôÊ‚uöÆ<ºqD¾d¬U„X^ê/½KÉ'IJ$~ìtJ C2yª³ ¬_ Ïò-Pƒ‰O“ Ÿ4j\ôᆨÅÎÜÚ-UUOðš OÒdm¬?½0DTF£íÂ{³U±Q"9LÒéLÑîÊóé0èê±ÍÔ %lâ·ž¦\é·|ÙÒ\e¦-[Úóô uÄÙ< îdCkÉ ¼þÞ¦d>Õ|·#°YižŽM’DW"l¡ßùg@°£žM?J 1j“·AûçU:Á÷FqÝ|ÅwñÃ?3×:}b“\÷kÐþ¾±± ìû#ÔíSwG-›Öu~€YsNÃøí~Ç¢oàOÄG0 4jHv¹–©Šõ»K@ñÂJFÁ÷CÍÖ&“‰#Å‘4 ÿp3aLSv`;^N÷TœQö°trÙ¦$†#qJ/jMÛgr(˸“+PÏàLÜflN+ƽvÉOäp{{óN¢Ók1¦1½ær½~ï©«ÊTªIYëã±VÊhô.$ÔX½/t÷Z¥O™¥ÜôWbû¾ JAèGº_—0ôyÈ<3ßÀÉ9S쫵éèf¶b¤?UØœ7F4`‹ó'nTË-ÀÆöϤµÙ…ý Éë(¥‰¨U£†”-Õ¡ð^„XY¸&8’gºòÇêOœLÖÞœ¾®»ÐTuÝ—°s¶9vS¬pÂëWÅtæq$}€¯¬¡µ!…3¨b-ù¢>d¬½¾Ìê¶*z( 1,~¿‚Ë3wõ&sÅ*@¬!¢¿G ShvDâ}Z´-b+{ûðn»3kžuártöÉÌ’€€ çÍüXüüì X×÷|ŽzioG…îE¦‰Þì&.ÔÔ-‚„å]0€ öiá'«¯s^FÇaž·V‘ ÞX&7š½^ý×·SS*ýV¨qY—·£ç Äò< ÁAsæ®æŽõã½ï¤,ÀØî ×™¡ù|Þ#1ža6´—Þ¸¤Þˆ¬ ¯ÔÉ'µlbê†%s½NßÈÁu[AA.F ÙŨߤ¿ùµYø$ijY{ü‘±C?i’ñPõ!ž¢8éì‘‹›’bÆJÊ ˜Î{.Ü´´îâQþM•‰¸™q\\H8õOêÍbe²Î&¤asÐnÙO¸Í vò€ ~Œ÷öœWj¦á.Êfæ¼Õ(Îî¿þÄk¯é¥´„s¼ H¾uë´bOÉëœæ!m¹ÖÎu>˜ñSŠ¥–tš&•4ïíÚ¿ô:¥ûÜÌø ”ö¾¼JÍî• ÊG‡©²á¯…£¥ÏæZWœJXaÉc¹FN4yst7¶èsæ1Û†¶Ó;ógçF’`W¶“­IÎ:oJA k°Zº°?T>SX›wgOÐ_J_cÈåã‡ÝYPk·GñiÕ\Ï…¥o=¶¹«(£G¤{¾Â«¾¨ô?S‰=aÌïM ÙâÊò,ÌâÔÈ®"€‰]x)[8ëBsþ<‘4Èѧ EÍBË\É«Ì|×ë7ǽ("Álˆ »e²»8ÅG”ÁBÎz‚÷»„™gP¤ÔŽà=\Îñ =&~7;ù³çùÜI øvÞ£lq^DQcæ¿o1hµmI;¾/mQ˜‚4‚ø•‚bfçb¿³ê.˜nKˆ N¢ÛníÿÚ“2î»îî¼[0SRú~œþ©k¤~*Éî_ .ºT0[?Ú;©•!ßù¬Î›úž­™¯ç>„RØQ4]b‘ÛOO€È·EÅŽKºîÜfªÇôKæâ\À “L×´q5`ª{# øL÷M£†È.`¨ìQ%Ÿ‘˜Íì—øWj\dXR"h^Ïç×,’€€Ål>(ˆc„­È$—j¢{že-^s9€Ô^Ÿ9OWç(ÿèTçØ-×YwϨ. ;‡ß“Òôvb5bQ[†I²´ –Ê) £¹Pá;üPSĆ0÷V›…1(KVõ#*ÊÅjúÜŸíϧ€X¶DɈ¥Çø×zsÇJd¬Ðì,Ú1Åg'gp-[kŒIˆ½2çËíôПëèWÆ!„zd‘ÁýØJ¢X>9·{ÓÞLZ¾+Ó[ú_‘.£²çðÉ1šeˆb³ˆ4ßß —Y1¦s½&÷ÎÌ¢»=flwq]§sìX„Œ`­Æ!¥g þÄäw±5Ûï¯ëzõ–±Š Þâ[[ó|(ì2üSó äuºÑVÅo÷JÙè¼gªC°øÛ\‹K’V]¡_ZyX:U¢%7&F]·eßâû7aqøX¤,ˆ™èP*¶h±s1ù÷=yåAT©¾º½âÍòlî†J#Œý1VÂR©s€p¾>šOÉô_ —åiÍÓXLЮ81ìjÁÔÙ'†¢c[s¸¯úX‚DÍÊ€L ɳSš°{];9P¡ ã3üÇv0$ Bíù[ŸtÀìK×´eÖLD8j RÄ‘uHöôT‰)øÛÏ뺇«:G\J3ô|æN$‹Å‹Ržvƒr&r•¸í#ýçðLê©íþá^ÖÝ-Bí¶˜(»toº¦”ˆÿl1‹t¨³É³`^yènèöŒ¶2°6Xe9Tî¡_ÚƒJ|¢¦2«aúV&w°Ý%Ë+à .6¨|^`*’q÷b¼çC°Cì4ó­ŒF!–¸K*·õJcšn³pìgXì1 Ǣ¶GÚs‰’¢+ˆ<½¤­yœñams{‚¢ÊiO]ùK¼È §’½Ô¥µþCú;ŒIE²”E}Ƽåh¤ù!h4èºbz<Ö.}Ð÷Yšƒ;Kº ¶XN·X>Ÿðð¬^ÍìÛêÇK‚?ÿÊ#Ÿ#S^1†}pup½wºjÜ×gMx åxN¶pߣzˆ¡/M£üžä†Ôs\OÍ?^ÃQ`Ó©Šx0")™è.ºùÀqÂk꩘€ÉbqÇÛ¿ªWóxyW­¦.Ï„Ï^’‰;—wyrÊ—Y2ßòG¶S©¢ Œ§Ë8ñ|gŒI«vL­ü„j¢Ÿ,Il-’±¦Ie½Ë+À~þaÎcðø¼Óo]p_šVÿ»pÄ=Wè!–¹ª)ä X­Âmœ«ôª 6s†E-žªÇ×…ý&1éÉ¥ õ•½¿Huù×@Ÿî©ðÞ4Y³è+›muLõ«ã"*DÚ~ ÒêN s'¤Ò-YþqÆ ï•»YÃBÖ0ûÅ}Â㌫DÅ“ñëêg×{’€€¦2òbIñ•jó ܼ}V¿k¨¯"ãL¯Íÿ¡i W×qì-€"&úÄ¬ëø«°ÿ¡ á|ékTCxR…°ž@ųm}™z€ÄhC9 ¬W!Z+*Ö£¸^næM³|’XM?Ѷ£ÿÁ7½é¢_˜‘þs}íLQÇóç`4:H6iQÀ™`.,8ÚÏ·PHD û/ SÈe±Žš¾6`]ê«^ee³ë>á;4†ŸãÆÈ¤ËaæHŦà‘B†WÎê–'µÑØì<Ó%Ò]™ QÝΜpÂÆJâ¥T«É¦¾ôl"Ï+)Z†­ÂÁ+/f6¢Õ ( s+”Á]wɉ«ÝÐ\A¹ÈÀlp>Á—KØáíƒk§9QÄΆ´€uM“ýþ c Õ W’ŠlÔ›^—Ä^ïö¸ûê¤6_4»W<ÅèPÍó¢ÎE¬åÞôÖ?A—Ë]Tx(‘=&½})³D“çe'€y&‚ÆóŠ+S€Wcf³ A ·Ì6 Ýx£€'Ó\m%7!³F])¶ÀYo-c7¯ëø!¥ªPØÐPé‘Ù|>Éý5ÀÑÄÃX/ìsÌ÷/%+ OW–ŽÄ{±~£Syè÷«ÃÔžHÌ¡çü^ulÊllYla“eÌÔj‰{üeîì×$®¶‘·®9Ëf öAÑÝ‚1CÆÕФ¾*Ñê 8B|¡ùøöXýiгBg4­Õy€Ef„³rb¶x«¸ÖOOºN"¯0Óm¶Ä¶»Y Qý³˜Š6¤zÍÌ¥N-Ög –7ô(N XïŽoéOSýàÝØ_×^;ÅXFTF¬­mõ‹5ý¿«•ªiʼ ‡Îo­†6ù©ªê6CÊÄNài|¶ iCˆêÜwf´ÊP÷KP—¤²ƒù‹61ZYˆl6Þ¾°­„@$[!5"6§Z0¥üˆËí¼Cæ1¸’àw(ãÉK¢‚ùTgë"S,,áɰ†‹ªsß [ Ôd¥øJG_U’EA“\©aîÜyYÎ}á°‘¥¯afÚìÃôQΓf^_¹û’=I³ÝSÝc^^±6£4è¥Ú) EsT®/QòÆTnój _cÆ ºj{¦:­¨l­;éúOO}Ĥ} ±ÉïÎÖ§âň9EÆÞ‘E>Á±–I]w<•ðÉŽM¬oP\ÈÇk˜‹Øˆ”Ãe¤mÄ‹=—…FP­P<”ôí¥‘ÆÄ,…Ÿü=ÐÜ7ÖÆà&²=ñ]®9ôÊiâ}¤*Ò›õ*ÆÈøý{@ÈÖ›ò+ý‡J¿ \Jí{ä,e¢R!múŠe—D»¶k)&XqM‡¶ÁˆgÇöЪ+–=Ÿ…$¶:I-åÃlméŠgŽÛ/Èzù«f|Ö„k –Øfic]º¯·íû÷t/ÞÒ~Uïo“ïr÷µ”IvÏO²Ð+ÌIÁ‚Å»ŒüêTqœÏCâ€1^ù˜8B`ndð`¼D kü®Ð¯tÆ=Äú)ÚMFm¨¾Þ§lª´\õÇŽ Å )[×Ô͆ÃB. k$ 5”Y›U¥mŒGȺ ³f[ô{3„¬[ê,^¢ÈNëTÒÏ›ýj³^]åÈT¤^óÐlùÇ‚ðv52¤×|¥Ôu)Ÿ¬„µ¦lØÚr¯ôê*³ÃD!µ|à!š¤ã÷æmkí’úx¹±o2Vþ¾ŸŠqðãµCõY{m½ƒRAwÿÌMÍ\:Hh²Ð}1¦üDÄÝÖdpË;SᯀbáM/Kþ î@Iz+÷ýÅÏØ3z3|Wj¾Îÿ4$èס,G"ó\‰VÖTÚYÊTL<9¦5Í[òÊ `Ÿ‹¯Œô´ØVñŽ6¶êzidâ¾F°äï•wbDÁœÖÏM öƒÌ“œ¨¢Š»’€€É-«ÓQÕm„ƃ@7‹^Ú­©NŸÙÔT‚šÏŠ0òî"éP Ãîy¥s oë€&½ú 1.þk™Î® £ æ_‰ ×n,°®£&«|DÁ#Á¨ªFn{†ÂåoÄKx¹ðÙZs·3¯¹æd)Ê4EÇjç,vи®ô´þµØ÷‚Ó­Ë’ì¥a|ŠâE»b ýëeÇrëä¡-(¤ >ÏY¯Z%¥{Ÿ¥6 ³PÇŸ£±óƒ÷©°«›âW¤ IF8…~÷»~É”ø-‹ÞRæÞ¢C+\,¸¥ô^  'ù*Ö°%ý´î–Ì0¸•TB®œ×¥÷üæ5Ì·¹ž¨¸£¹êÿšLV͈:ý걌.ÙÚ¦j‡Èˆìä[‰ÎŠ–¼ÛJÛ∠³&°:ßîAdûáz›äb-Ñã;®%yEBC¸iûb‰ÿ'bQpƒÜ¹Z%«fýùZ$h 9ËB–%K+ˆyø´WºaZ;²ÖQŸš…ìÏ^†(õ–NU\Ó@Se3Àˆòî·]©Í]ýÚ~Ò¯XzlØçh‚¾KË`œî=¾lF›—apÔvMTtÕ:§>ú—¤éÒ&ü&vuŸxÿñ3}/ÏÁù·½A€ÏµÎм×_\îôHK¸_ˆ,aÖR´¿œ ÷ VT nAŸÖ¹G¿Jv^û¦úö錂†bΓ{D¼Ky>CÿÊZL»À¹ O®4&%ÞN¿EP|ôhç0'Xd8è^Æ¡Ûìv ‚݃¸WÙ6$©ES£SNS±ÂâŒ÷­ÆGmñA¨H0^(öc2HêCòV^’`%eؾIØ !ísóÁ dÉ€]v¡]Î'·¨I^ê93N ”ÂÕÇ!!<—¤Y‚míÃÃý/·ÄÞQÚÛË¥Àqô;Dƒ«iqc'[sPKA¡Ò·";0î+|÷ÓæÊ’€€¸ô0m­‚§HmBâ2<ŒEBì§*÷éaµwÌØÈ÷Ý™J È÷ì F.,1Nߘ8âü¸väAm„׉Lå¸xûÏÊKÉ,½óÆâ¯Á¨¼>¦FD*}vÌ1Œ\ºÂ$égDë>Þ¨þÌ®Û~ò_y°ìl×°nq7¥iyj8(ÓEY¦ÐS0¡ ÙRGÇ® ®²J±£çS$‘c»§Yò=˜…œ‘`Ö.Hü§¿óo"òsYåžçÅRYno'‘ Ü“µ-! ±[ˆÔšªä÷˜Ñç÷GÕ&zù ÞrÏ‹7•¾£cR 6%µC©Kû´ˆééÅ­õr ¯€bWv,`fÅÏH*N‰ž­ÞP`Ò*•ý¥ÄG:U¸õ˃§–銾hs$´ ¶èþ:¢&P%ÇÅÄ“×ï×5’€€ÀN¡Û£‡ø¹ g6 ›ö~š'%>\ÛÑÜo¤º#œa”X ˨W–K¬hܪdòÜ/û>”·Ç±-íÑÏôvEݨU“ÇAo¦Žø/T"ùTŸ°‘3áfL–•¦ïxÝÁ€4Ïb0®¯§›bßše20JË~µ1-ö¡Žç9¿î;¡ ôa;°¦´&ÉS/±Xq)EÛ [¯§?ª¡+mžÁÿ˜~Ÿ¾YyRÝ%í É”mVBì·¨mR³co$.tGI0'J WH\Ø!A~ˆK*zÐ^¿^«øšõ:ÇW8®—b) N#ئîõHö²£ ±‹y È:†5 ýK£âL#f5Èñ1Sè1)œ=“øMÅ>‹§6d›*tèv;‹®âl•l^€¸9Ó¯cAAßMMóVˆëá:_! /|¥—Vázé _ 8Wz}aÌvSŸ ‘Ù F'ìÚ”+[ã— ]EŽ‘kžÀ¸:ø8WÎØß2¨\Þ`*T£~Zx*js'%‰»;€HÞ‡¿µëÈÚ ×ÕÐN–)ßšÕÕaƒnW{4|p‹¦èy´;“"·€Z/wd`âG†‘&]áîé¢òÓÍô>‰ëœ kS¾Ö `#¿¢=òò-ÈZ"·žy€ùCAïs¬J4¸ ß‘7‹‰…[ÇnúÚ:©ûMÄ|ȘP4 E’ê=Öìáæ×c~Ä?4ó‹ L¶‰|d¼Ý_ê?–‘-éd¯:ó70»s Ò¦-x,'^q§ /ni3DD[vèþÎké%oÜó¬Ð↮ Uè0¹ ÈN%c͘âß»¡.g˜xà&¸Çþüf¸Ù*Ça*ñõ¥^ výêÊ”¯^!®æ‚ÅNÝP•Љ'ŽÞöÙ8t Ë”"_üyäדö>uÈâDzuÏc@ãx¶¿‚=ã[oˆ/›|â;ûÊÄiìUzý¶tÔÎùCZ°DÆàÞÁÕ1ž ¥4Oq®üa™›Þ‚Œñ-qR¨CAÃCAn¿× ÂC0¨Ø¡}¿¬3ˆ¢¸ªñsàäz‚I–žžõ«±Bç 4ÚË„3³ÍÍü= áx&y U/BÐTŽó…êí£`½li¦®j]Œ6ýdÔ¬V×É^uz³ú|W·’€€¡û¾òGEùò÷¬‡›Ì:y†¹r:˜1°%—òÒà—zb1ÆÏtI¬t<]qpTbÓ@üi,‹;#[ŪÞr”SÆwâÀŸ!ËM³À˜¤ø—ß\ m¢goîË÷¹öžÈŸÖYňí;8Å#©í › 2lç–„Ÿó«D£ß?ù}î“A «€o `•«€}“2Äý~kþ›r/ 6¸8„óˆ"Ô—UyE9þð¶AÚ°–ŒŸ.!Î;KÒb¨ÐØÞ³4×¥ÓÖ¦­9#æ÷ü ¡aaD}B Þ¿à€ Ì²“FzèAvíÆî^ £ ÖÌªÏØèÚC´ƒZówÀÂÖÜ¡ÓE§ž’}éå ²”+JOx¨ “³õÿ¬Û¾8)‹r@ºM?´äÂlÿ½5aë]jF pH;‚.Æè×'Wž’"6 Xüh{Ö¡ì<70dhÇO§?ÓV踢éŒFëuêã€!WNk|¨T½› ^ê€+†<ì€ng³MèÀ½eŞ˕‹…gkQvcö«>ÏhQéÔi>ª*á Žz Û`a”nÓ@+æ»l G!9Õ}äLJ–þ~E8Ù¤wÍ|MZg·\1Îs#pØÎ¯ì[€!Q-Í Ôyb…Í?î‘`õƒ0Y÷­Ð”’2ÙÕ÷"¿„^¥IÀ-%¤¨R4SoaÊœšFëV@­,ñVšÀW¸ÓŒ44’Aš§s·†™Tð/¶:câ•jŸÄ$_ºqdíhšÓØÓß¹¦Y-["V+b›°nÉš·ôü•Â<+:Ø›]2ã†bAF~Zg©íZGÛ(ÄÍ–Ž=è÷ÁÎk+7°âbØMØöèò&K°%Ö½Ç6WÆUÄT4‚PO¢\p`Q}të^·¶¾.“¡3lÒ‘Å_•[mªX¾Ø2«¹;Eu/Ú+Äi®¼˜v‰pzVß•_}q޲5÷YLg‰˜ºüYtñ‹TÑþ.w"aÁxjeØlÑvYÕ¢»>pÜ…½‘ñ: j Ë/ø®Óƒ6à?\B‰lº2šánþÃ@%5(ëPÍ`¶ƒKOÈd÷mS°1Є+T °UkÕ©0!)&!t`’,ËŸªkÖ Ý9Kº‰¶K‹¸í•2ñÀ^ž”gó.¡§,7SrÓ¶N)$ÊúÔº’€€¶ÅYµé{u:®ÂPª6 ÿ\4Ã-rÐ&ÒcRDó?IsJdÉ—(¯UÊK»F|•gør¼ó¤l›<.½2%9Ý(µ'özœ‘;ã=E·^è†Âtt\î+”l DzqH Ne|Íèo¦©¹8Dvþ/b°ÅóÚæªùÐ`vžÁ/X³{Y/†àeÁXÿôd!]–u{[LücØ] ½ÕG?ÐÞEkÓ넌ʺÏLй›Ðfò&ÜòUy€`.‡GÀVê-Zý!²|1 5ÔbgU>j0^Cƒb(Äg¬ñŸÔ«(‹6ù!˜DL?U¶ùhénæÅð¤L©4…ú• Ëy AÐ!xi%Á Hº8aóˆÏøw7—ßqDRœq=$ÉY'Ý"V#í¸/,»(ÌWh4' çœKê‚èŒ!Ã?”Óÿ>÷–."CƒD»¾[ó Û§gD?¯ e‹?ÀÕ½Yç>QR~!¸Ë@ž’€€³¥êœkIt×®tÄZ›Àö8Az¡69òn_ý3äíFú ô¡¦z€ìô°NmO(òs¢o{²Æâ’Ä©p“–vh5´A¨]2R2VÝäø¹Êi—A›RÊõàb>çðöXNGE,â>Ò]éO€ÛdذuÎJGK @w‚Ð8Y’ÜU³¤ FwË—hxEx-”ÀVí­ç  eo ô ?\óÖ‰™F—£÷ÏÜ82Á¦`UQ_eù§PÀ=Z˜ŠÂ-#jþÚÁµiÃÃn)é Ódv k߉ݨ͸ˡÂ|€x-Ç2^Ò'Y\ d›ñ%°AÇ&Â-yR3ˆºuŒO£´Þ‡¿£äγ¤¢ö<à/³z*¤Œü‹i<Éq;ÈW÷Jæ1ðblT÷"oïúâÛõÅ[Ôyû¹ßuöôlŒ¿ïÃôf8|/Ÿ m=Î:ÔN]§NÅÆàS÷ß}¯.1I;wƒºoP.‹w¢ñÝ|÷eôKµ…ÙXévvj”ÜkÈ,¸¾݉b!+ÄpÉg²od•M9þ 9@jžk5´"1÷YE‘šêëËQ¸3æKj>’> ±ŸN £Î½8V¡Æì‘`Kt61Ä166cæ ‚êwÑm¢ÈAÇÓñlP¹¿´‰ûÇEˆÉÖ¦ØO<ǽ +g™*ü‰ü™»_j 1ü!b8©AÚ\×B[4)ÝwŽ£«YÁŒ ¿vVÚaŸ)ŒÛš·ÂO™eg˜˜®­K¼·2„»ß|ê§mu•é‡>ȱgÈÅ}Ùë@jf¬õ>µRj00€ßváî‰bäBÍFËb™^)Ö?é‹TD¨ç|1¬Ÿã~¼‰‚”Nàtò@k‡öy¶U‹~¥\6±Ú9Þ{Σ¤B‘k“D»Ý^Áqüò©ùñçE#r1CëæÊæg4F|c„ ÀÙZ´wÖª)<Œ~R¸ZÇ¢Z—»ÙÜF—”²îJDƒÌcä¥â_ð ”óú>¨Ÿ°//DÅãey¾÷õóÜ”'òx‚°Ä•%YŽntSÄ· àúöY@OÍÂÿJoeüÊ—Uå0ä¼I;ûÿ¨Ý‘¡…@¼/Z7K Z6O{Y«¶—Í` ¨~ëô¸w·… y ¢E½Éè·gÞ¼û’Å!¸v’€€½qÆŽ'5Áý*;©f-ß9H @®¾ÕíÈhfÃy<Ë8úOVéáèœ×…¸DõÅœ)2Hã?ÓrüD”I’N· ãŽb>Ú¥ø&f$ä/ U)›ñö~·/@|x€{ó¨AjmŽK|Ú½Zi†"ø¯ŽÍÄ%¶x"¼k*ˆ·?VÝ.$¢aÖmÝÔb+µú,°1«ê3?Åjþ^ÉŸFÙÞü*âË‰ß L§]·.µÏXœœÐòmÏë ©SEè$ñ(9¼ÞiB>4[“vxºiíé7B©¹ò\V÷°úè·!ÍÓ@†%ÁŠÏ¥…ðmÌGm4Ë>IÄE¦@?þ‰†éÇ¢—Œ¡¸©¸¡ ð¬PV‘ôг£4ßo00ÄWïÕNTýÅZ_¥–‚ŒŠõVÃi Cm=eŒ¼ì~í®Ð’*Æ¢ ¬€Ð²Ñ@Û`QNÓŠ18ç’ä4”E)h×’-q"ÚŠÓ–àQb9›+_¶¬vÌÉG÷ûß´UúÀØÆ‰ ÷,Ë® i/Ì‚8­ì>±¼å®¨ÝÕ@vbÀ,0ì-‰t °ŒXŽ÷4â(È¥ŒëiÄý9~…(Ø+œ Ôt¸.ýWuV ¯¶hžV̆Õ§“ìûQ-ÓXsHZ‰,Lì«7G•ò¼á6çwØT=|ÑËÖ¦)õ)4‡h¾Vƒ°Fõ™žT…=£3a•%>û’6ÉËF*LÀ° Ý’ÿ^ÀIŒÇŸˆ¨|Û¦Mß÷Ü“îp’BŠBÛjðRìÇÂ>÷Û_C49ÀÞE£›ã ú†R´HÐ#¿ÊÊáÇÉÃA§é ¼vŸæ»naû¥ ƒ %ª5ÓŽX5døw«üç$ûÄŠ²°m+3’€€¾ò tÑW¯§ú„‰{HþÀíЭ®G8çØd#¥ûõFñ°‹“ ç‹S¤ ¹m{éèþéYK ±•$þ%‹VõØ$}º‘~NFøÙT£§÷sŠ#ã ðx(ˇ»iåF7˜€Î;ph7kƒøµ À&ò:æ°òoºÔ™à×6·¬]ñ“[´a‡GöÍ„ôæÂäN.ß$0_!¹§ÊfpBª=Øë:n׎$³¿(A1À¥P¥@AûB`_àÂ|¹7!XîÝT?±,$"­eï/zÝ—ÂåPïºø­éõص\3ÿ­ô‚?q1ÿÌ»«nªó«†Vo>ÈþÃ<b¯!|‘îR–Kâï&Ždö¿Åï^à‡ÒIaŽ"FL‡X7óYíé §é:Á˜¶Aè’\øÈÈ‹µI;üƒ–Ú¨Ý ¼I;u÷³ÑÕúï|,/ µ¤Q¿Ú5/âGŠÑ#âÆ‘cþ°¼¤!‰ªI®! ™æFadˆ q• ØhM©zð “mHQ%÷ð˜(ÇêÊËUS<›ãàl²Â¨÷+áË!\qÄK—çuŸ†6de™Bäñݬñ!%‰¡}¸Ó`í´‘î;†õ€fOðøHËuÆ& YÄ\MÏŽõÛ×mk-ª:m²´¤ ÎGhºþœì-ß}‹ÇQí"l²ò)«nez®Þ†ðs‚‚„…v†G­ ¥ZGË8˜‡ÁBßf!†hÂ14‘i[ìf,÷Æ–ìBP\xÂ3øn¸—M,Ou‘Eó….߬޷Ô&dŽ’\ø¡“p¹HÆi Ñ•¤'ÆâíÃü‰ùÊnK­Ë©úž2íÎ#‹®„bX%iZëXct—§Ï¦ PÚÄ ×Upï{r2ØÛˆ_,‚DŠ…Á#ì>  s,è¼-\Ü&ÈŒ‡M*v6nÇ J˜IËp“V,ÎQ.U1?¬:5äÑC&¡,™ˆâÚ˜øI ÷¢¤Ø9VŒ\Dip5׆Cosiæ*¼ßâ(×…AÈM~Y‘$v“P#†{Çë£ÃϦÀ»@3¿Nø$—¢Bp3åó¤OÒ<‰ïð&"ø‘h;‘Poù!‹áúš?ýªƒ[vEñr£ËêÊGe[$Øš±\úóh“°Ù¶»Ǹ”/ÖlGÿGõ¡Ž²ñNî݃‚m’€€¬Ô^ªW¸ýÎGÛbSt½'¡6 aˆ3p“šZÙë×Ìíû‡ ãl\Žp™ È.N¤>‘NT,¼œ\¼D/UÛ$4…ž°P„P‰oOˆVÓ_p›.(Ž’¶J#Mo$/jàeYÓ:sÄÀý£6Q¥¢Dé­£oG±Bn –µØ¿°rÖùæÚ$zL3Ž\e¹6»%=È”0ô"Ó.¹|YÜ(´uzzb©7I•™• ÊNÔòâI#‘™Á„~ìpRpêôUouĵ;Ùj ÐöÑßf,}yROg„:ëâ·9H…†t“êÖè»M}¹¥œÛL`Ëm[2ÅÜ-±]|ÙWÛ£øôÔ[¯ÀåÝÍ^U2ÒøLÁcŒ[ÊcóX¶Û7> ô4n?ÉÉMíW4®¬ìæKTÈõ&Îß·äŒG6n^ ÷{ µÒL>w$2sBuÜÀ5ÖnTˆàuÑZˆß&Ü!ªuu-†h«­­¥EpC–0j«”õÇE0½•˼§y…‹Dé]zOÄ×ÛÑ!ÌsÝ3HÑ&4Hå¹–éZÙÕÿLœ90ÆiáÅûº–ë“é£Âkm?‚éí_¶ 0 ì}š9¡vukò-‚•¾Æ>‡}Ó@îxîô!t½c,KŒEò‰»³&8zæ/É`²1[+!á`”ø¾îÅg¬ÞÔjB®/£#7ñk.l4±çV;AŠÅ ÙÊgØ :ù.c¿ËÎâE«†{—’>^åø4?Ž\¬*óáa¢^MfTHlQ”ü"9éHzÛ)¤ËÆæ9§ÔQËì…àÅdãlÄãv!NiîøNc|q!µò+{ na”We;ÄOþ6¡ù8ŽÕZ*[ÔæÖ±UÕÚ ™ë-1B—±ØYúOÕyjûp$SÖ-¼×”f!ËѧªšSå éƒÇYâÑÕðâßBíxQ.@' è²ê?IʤIDz¨•¯Uko­U¢çVŸ÷GhlWY´æ`¾6åFýT5T¬ÔAaÍš\àrÑx­„ĸ­™DcÆš¼+l<Í«·^»Â°ìã÷F×:@”_¬øþ€ÒÑ[»Tè.Ðy½3#-œìà Ÿé×ô_Œ~!=™ž¦þ“-C(Ó“g=ûÏdÍ`"¦o¢}­À‡ø gšª†ý>zqão«IÝc?3¬;’€€¸Vs¨<§Ón©K\¨) ÉX޾ž"GçõÕ•¥õ±uUr!ýµ‚Ü ½É›,¦—!;šf‡Ê&dü«Êi°si††#b3H½¼ì“ò-u›&2à„°ŸÍšRŠ僕üëÐlÿˆ,¶l"R®6aoS¤©üc)9úÚçHÅ…p·ŽRÆM¾öÅ.£XÚ ŸÍ+9' ÂÉìÖŸ²úûO.Öz€çÅÃyrß®t¦Ïø £)ö•ž­½ªoóãÀ£äŽó6´b·ò?@i­ÂÅc_h]¾r(¥›÷{¾8hؓЊØï(*Ñ u*úúžÁ´…2…&»mðuâöaTú~.¬³Äé2ä1*ÔŠw\­XºBG<òR5etiÀÅõu®2ÏÂκž€˜´—¥ =ú]ä{ϧÁ–oj|¸]9•$éÑŠrÎæx_©¢Æú¨± éâV½`†3;?­Âü|j:Yãªa».ýËŽ az–+NdåHtpžEæ¨}GĶWÃî°nª÷>FTߘkÎe1¸[KÓ|è=‹·[€Q_y,ßiÌ”;yŠD“lšöø[‰A²Ç2Vn-\Çkgï®2É—˜é¿]¼SÅJ0±ìI‚7]ŽMo/ôàô2/[õ¥Áä*ýÊ!âHi×E¬·Sð!%é@‡&¬iN“HC•Nçê¡í°¯î «ÑXÏ—á)ÊÆ&Ó1I¾b€P{tÊ–@… ݧÃvÕ¸ýé!n^còÞ=8ø}…ŠSéÿNÖê‘J_Ÿ9qŸ(]íbœ¾0‡F§g`-ÌËSYÎÓ4`ô£é“À¦Q8jDŸ#›ÐØdîSE¼£Ì›°,'¯óƉ5ˆØ“Ïð¿ÐùÍ@À­ /ûZ‚×Z2:]›r7Ÿ Cók¾»YA¼6h,ˆÙëå Êœ‰<ã¬Î+<'Ðý C­æàVAk§w3áoUi"<Ô•Ï )SúnûðF37±íèÏk…ØÛHR2²¢ ¯¶&mß‘_¨ ˜–wQ2r÷$âæÏË=„Òu<^úÂ÷H~K ý‡°‘[ô³! 3G&륯òê”»~Ik÷Ùé9T(¦ðX˜ie®O¼±£7ñšÜ$KˆMÈ嬸ª .„Ʃ̒€€èPøZrÕS8¯œ?z7d ®è=þ¬³ÆS8ëí&–½xf³£Ú†¶]Õ£—-K´n ïÂ[åb÷0iÖ.ž.¨…Óš[1HàÏÆÚJÅ3“ñ\Ê€ñ ö.-J“¶†t_WbûÖÐ~¢1Rúg)_jÍã oÅ<3ŒRé ØÅ8ºXØR‰Êr”)_ càyWê«Û'™ÑâôGmI¤ñ½¤Zõ.ž£H¥C-彞¢Dû%-ßÚ–«Á)lŸÎ'øAÄN1'"ë#x‚Àà —2Iîx…ÙgÉ }Œ "xÃfœš+q½¥œ¿È:µ4ôúrî2Ì Þ¹AjÚþqÚ%B®µ<ÁÒPhŽº–ØÇ¤êÜ‹vãÏ Yïìõ„ðòX øŒ1¥NœÑ×ì|Í·åÞWUƶhü¦Üt}(³Ëníêz[4B?\…“`âîVÚšbZ|%eïàÚJ2iJ´ JYDYtÒƒéˆM‡zms«Ãµ1 QpàKÁl@b«//ŠážkOúýú¢/]ƒõ_óÿ èÚÃùÜ‚libÙb HªØô¥ Ñø1‡²&Ö<ëÛ€ænù1êà 'WÒ„*Ê@"ΨÙ+yb¥½^¶{„H4É—Ã&A0ë>„ £=å%»¼êãÞ‰>YÜÑ£ÿŸ¡öæ¼QÈ%“Ä@j±µ¢[ñ)¹gžH¼0þT¬…‰¬&=ÁøÚóWÔ©¥c†nÝšrƒÅ6NC&ºˆ£¹o@¡‹ßIvZœ>x…¨{k b®9HÐµÈæSagcåQ¯ûÏñ‰ Í°cÙþ«J¦//uþb)Æ×jFb¾Ÿðà<™pÝ c±nƒRl›d8šEŠ,˜Ü˜°z¸®Ãºú¢bŒFþïðØ= ‘)C;,ÁLjø²Ë±Ë àߣn¼ÁbV‡²ÚÔC$0—‚N‡úâíò™‚½©Ùî5¤ÆÃ—m`+¢&¥0ˆô³Ó>UÓJa‰ûEWêØÑC *b[§_V ‹mœ³ýóÎ>YìS–áš¹¸¥'éõ†åxn¬zâ=ðï3öƺP¤üž¾2O¶¸úíÚ‚NY ^»Ü"b*²-]&£W¸¬qEïìõwÖ³R¾;½Ï;©Ù‘'3 ¸ÔÚOû°‘¢KÚezú̧å2 ky<’€€ÈQæ´Ž­iÊc£õ…v\b÷PÏQä4¢ ]¼v¿µæ×G޹,þ»?ØQF¹áÈ3hÚpš¡ÒÀ¥²z §ï¬Õ ô;Â^mJ—­=¦Ä›‰–Å]“Ý®X¨&‹· d«ûmw2Ô°RŽýJˆ±g©Ñb2oþ7•°åtûQ\„à|Sâ”É¥˜6ïÀ@ ga.…›˜pŒ–Ñf¡ö¢K9g­¡Od¸èB`6ß'í;Äÿ\©4s%z>ÃüïÇ»… ‹zóeÓRîÅVS'ò àŽÅÛƒä•,_åñôö)nˆÔœCjzÿ+æ˜*{´¦§{C8YÁ¡ËLb÷YÄÙˆöƒ¡"Ú=KAêÁæ4ôd÷.ÙÃbPR ]›Gñ’8–†ŒIQR[Ç׈©Id[?±™^êÕT;b}ê;šó4eqѸòÄÉ ‘Kr@L®ÍEÚ®þ¾)wýn‰3ÂÅâ§ZÌó)ùU‰Ç͚ǸŽ/f®.lˆŒ·²‹9-.4njD¼Å¾k5c°…µ&ô%7ëXã¼û¦äV»ëSë$ÛyÝû‚ŠÖZzZè~[?&ft°‚ J~*d¦;[«tFZ«-@ýŽåÕ )¾åßM9ä”<44>sÇ×™j€Ž<P­7‚ám—!6Iùû…u\'–6³Ì¦€Lh‰•,‘üðÀòÜèô³È»M_!­úg°ì#¬€¼‡E_ð°~µö‘Û%_—v?L€cbõ­žxTÑÝ-{¿³ÐÁ¦$d9X¤àºQÐ:]½ÊQYI¹?Y“_«¿&]ïÂoº,Ù½šÙw·L,ãËã €ïÿmÛ"-uŽr©ýe?œ¬¯Išafmâɱƥ yÿ#7.Zq÷w"æß"­`“³KÅ  ø—¬0X<*BXÖð Ò 0øÝ;cùæná¬#Z ªÒõ¤Ìkί‰œHß° çSá MùÝ'Aµþ'^æB ó§ÿ/ÅLdûHˇî›ä<¹…®äRÒìîpzá÷·[·k Ùs…˜„H³Öf}MÖ ÿèö(òØÚæ8ƒhèKáS˜ïÌûRY‘kÐTG!Ül «‡ŽX“mØð5iHÃl+'ÞÝÇ$<”J¢îvU/©ã¡×â%¸JyJ’€€Å–@nh;'ëò¿}ßÎÍÇ…¢Ž9¹ÇÞ¥xfZ¥¦k/Žk²3vìe9£S9(ƒ”vÝn)†P¨xû®·«~À¹“JJoÆ9ÝþïwÁ„9›01!]5²wO†ž¿JvW2ºýЇn™"eò矅|íHLÔ9 5LùeËJHÙ4þ.€©gæBßÇŽ˜eLeNñBjõöCú1K¨{Iùóß·‹¹÷ã1¦èqzãú6;a©Œð×nٔω‰.¡ÊM›nñ1ñ€.8\¿P¾úÖd¹Ÿ¿7 Âñ »“ï˜kunoÞ L&·x[-Œ±8ê4j‚? ølsX«¶ÞaÈ–ðt=¹p çg_I©ÅŸP9ênhwÛ¬–Òì$Ïm˜ÛhÔQ†ëhÇA}T¢_H7Ýû2<þé/¿ù#™•"åÀÝŠËex\¡;“Ýä’âýŒ¡M_> ¥aóAMjɱ“iåNÓà óm ×B'õHÇ ÇjjÀ;\!¡21 (@Tz9¨U¡qãÏbÿ¦Ç’Œ–¬‚¨ì¥ä,ú7üÚÇF±8ÛK§7ûMՓБ\øÜwAÕ|-ÕåЀ72-2_Ü¿@å’ÓòçÂÁÇ:ió1)¿ùƒ|3ùE«P&E¸{@få¨9ášb|lŽí£»R ¥¨æÐÑÐ9ÓŽÞ MiJL¹ïxŸ,ÄÞ’a•¥3ÈXºë’»Æ}õ´'xë]íië à Fâ’Ú¥©!唕{ÅŸäfüùØ¶Í Öʬ nÑm8«¥Qøª¹ßÓœ|§ÑÎVcôÊ#WübÔf¿'¨®ø3´¯oçx…é‰a¾7Ê¢¾’’€€Ñ -jt’ÉsÔi&)°X«Šçµ†;»«Tâ¹½Jdƒ”#:ÅŸE˜ãÇènm$ˆä/ ˜ôQ»{Gÿ¨ý‚MFuÀuŠXï¼m3ƒÑªîóq A_\¥³½NMœ@&8Ǿ(àðŠê|Y¯:ªM¿ŸÅ¦F6°ÿ“…à/EóoJN"‰(q4h©HÖ–•™,] õeo?7EÉNP¿šå;y¾,El²°fÚ"JùHÖóïHÐàž7"ÿEÄÛ©£Œäxˆ-  õ'Jdk²ùr q¼4Tß¹ ÿß&çí®ªVÀ¢E&µ>Æ}O×/\ˆ­’K{ßÀóŸ|°§,h®^o5­ÁÎc‰M7‚«7™dW^"Ë z ¬²d¿7JƒÕ&(‘>úK¦EœK!ɆtÛÀè=­0èÙɃðÁ‚ÉÕsìÜg(½5]þ)ÞO(f4\ÑIé-_Ìãý—ù•.|ð…/"ŦÜT—çeäýˆ$?#dŒ¾æºÁkó±†Î¯B8žøË—@7J¯üÜ/Ø–Ú–KÍé¤ê)Ê›yÔßi6V-—bØ7ö2Óñÿ4™5ÒâúnÝ|½äø;QØêçÌùß:K¿ÅàþÃú’\+#,Œe^û9-Å"Ú°/)ÎÐS`f‘w|_!Ÿ»¯“áaùNãU³‹2B+%Býi¼®S7!Cäú}Ø4qÖôJ#á‰î >#‚íÆ7*@ý4Ë£WÔ»™«Ãôð9rÌQéPø¬°ð/ràS¥CE7Â%kw%†ÂLÐÝŽvR¼DÇëá¯f»°ª-:M©÷P„ÙÆßƒ¶áKÙˇPCÖ¥Gb™Ø³Vš¤÷…OYô(^®­ÄªY¥ŠfMÃŒM96rýøgˆµžMBåÇRë‡Mâcs…ïZ‚4Jáð²Õ(¯ G=޶ ùxß4 ={àå]´‰d×5\èsêÂ=®r{Ú7ìVþpzØ´ÄÇê¼Q1çWÍ‘.ú5–=ŽíœM¨öâQJ?¯=â¨&èOÍ ú9ªÔjØ9YEYÉ}Ë3Ó䙳!¤BTF“ÁF¡¬©ç¾ÂUÜü¥±£&ùE¦E$vñsP1ùúp/d¥‹½f&»S<ɴ瓱3%ðZµ7„éF·áÄ© äÄYû05 ’€€êß[#ð‚75c±‘'±l6 "Fp»†U ~[‚$ ®`Ñ‹D ÓUAÜÂr%=~¹€ÀTµ‹pnæþ}À<ص Õ'k¡kŽ¥ox[‹:˜²ZfOË0Ĥ‘ ÁÿÆ•g» Rʺ2æ»"5Ab/p­ª£‰¥éça`‰£C³í­áîoEO Λ%g‘G(lÃò‚ÒáŠoëéA+ˆQ‰½*,³œÖHß½kZ%ÐÎ8¡C=–q꧟ͳÿÑn.Ê2þŒD)ü&Ú-ì>z¾8¬Æ'ä-}EвIÞB°8¬j†KÓñQ3Aa .퇚©nwO jàÃÿÿ§âM2Yã"^ãß5—ݵ1¹ˆðD»$Go^0tx¯¸–*ìÆÊÊ‚y×Ök•g8Zþþz’kb- !íÚ+¦7Ó®7ÓK_ŽüPGûô3ƪð.…œïükݯû}ó»E¤ŽgÓ;ÂÔØ/cAÉ^ã)|õšË­_Û•õЩDÎâúÔÛ” ’ ».JÕfc 5ƒ\ëhÞª®Øxz´”Æ •&={MŸvFJ£Àx0rÔ“ì(¯É7X÷õ9/P.Ï1öAmu-{"b‚HWD[ªY®ž Ððï#‰å~‡¶…²;+'i¹Ý½„]õ‘ò³”·æa+/ÂW©àƒi)òüîÈWᲤñ€‘}‘.x—cÅedxç~òñÚô tkÍ™ð,ðõ…§´¼Ø³FpÅH ã_™3…3Qò=Â0O_`^}¦gÒotÈÚ |DΗϰ*:±`ºtëòíC–ŸV¯Ã›žÎkY«=ÐÏ‚*U¤.EG§ùŸÐæ—m¹|Ó¡Ù ÑÓ`¤€%*üGHò¿ßRœFéIþW¡û¹J^˜l=zP],l™`-캇 ZÞW±C’Ð+oY·±…©'ó@00NÆß D[øb.s³½ æ ’€€×Í'õ&Åm·OBSäÑe2ƒþ«kòÎê…¥ U>¸æŠˆ=ìo`o+§ÕÅ… g˜È GºØoa_gÿ#3ä¸ïK¢€kÌL—,j×tXûÿ ÷”*å»Ë½ðÓZo»›¶’Á— Ñ$û¬ÇÚyÓÎ*L/Õ컓åœÿ$E¦ZÜ_È`‚UÉm3Pý ZFµ36 ž´é=nKž±é×*c4–¬á8‰À¡gYÝ[à‰‹ žà>CÚ~’OOzF߀kÐÖJ&Ç Lx%ô”mò˜{m‘¤;GCñÕ»6CÞ—™é§²IÏ=²ÃMŸ]ª´µ[’»Û‹Ì›»Þ[2°[7gë¯a À¯à šñ£µ$¯Â3 $¡DØXùuÁ8 ŒsX„#Žè´Vx+güÕÞ¤òÅ´om/„_˜~ nò'ùT[¤Œ–ù`äg–Mb C.û\›w]‘¿…(y’,àQ¡Í‘ª´/³øfEÌÛ²_|J\N:`wŸ§7xÚ;„â™1ÌÄÜÜB¬‡i¯kwœ Í* ˆD¶bÙ±{ýæ€Þ­—Ì¢ŸÒ“ÿêÀ`õÑß…íÂçÈR›,?BçO Àã(«%ÇüÈ`Çèp™ß„FÀ¯|¨rÿŽÄžICD¥Pêþ÷þYJŠT%2<Û$žXYÊáýo!åvß$Áh!•›,'bˆq°\H½ï0èúøéEo8ë1 #‹¸³ï¬ sÏn¦ðÅò¹ô‘ ù}Ã;µ¦paAy Ðhz:Tn+‰Z-“úÞR^€¾õ9+`À"Ìj»0ëÙ¯Óz½UÕ´^›¿êó±aŒKâ aÙ””+šåýõõ\Œ2Šè^2¥ ˆÙ~u-êšö^é‘¿¤{j¯S;8Ýa(ß.#Õ)™ÍiF`)\^€uSQØÎàLÄhDy3›eƇ/*ÖæN§†› Œ”°Îòòjy«´Ð^ìÐ~¶üVÉ>-´FÇJ—‡áˆèþzþØÈ¢æi;µ^µDÊT®G~†¸ë†²wQO7eúv-¹žÕŽÈöq®~Úú}F©õ¯“¶."Û}¨*•lxÏÁ ÝõzƉž.Öâsô ºÙƒ{|ˆ—Ùž«Oô&…0údVª‰íͲ¢HŒgŠHqè.á´•ªorf qjQ»Ôe¯ªºf$0hrc’€€»³1¤G uÜÃÁèHíjyÅ1ΠïbÚÅŽ  wõŽÑAí—25¡HW G€)Ÿ^sû€i}ûÒUÈíñýµ"4´ Š_<ëfSöxüßàXA[xtêúY¿†»,â,#òö¯Bì[AªL‘ºš”9*I`¾ÍoÙ÷ì\¿ÑÑ=VË0Uÿ˜3³†›ÿ ÝT€ô{ÊDú´x⊆B¸.À)cm;‰cç‡]dë¼þYÈ×BYOéxl²¬0׊Q@Ùó$…45 Ó.ü;´LDðÏE ['×eÉë4!þ»RV_?†9&¹¹UǸ8ÿU‘½OD§y_î Ý;€(Ó§´è±2j¶áOÚúÖ‚øë發*5ØÏÁ¯Ov”ÔGj[€ïPĦ°ØƒK¾·–÷Câ õ¶œÃÀâ×¼sùþ¥šsx¶g£ €žáÏûÂÎæÉ"(æ×LߨŠâ=uOxrTÆCÞH?7 *GꥻqõûˆGnó»m ýÓbJà–Ñâ²Ì‡>lÎ’Ë‚Z Ø]òª2Edç(qj,ž3Žábgôv粊a„·|fÚ±ø*@„Ùàñ…nØ Á?÷Í¥Ç]ÙðÉ}ZNõQP²»§…‘™zÒ6¬~h®³@!Õ$ÿÜ{¸(½˜gV‘ìÉíã ZZü»7xŸŒGìîˆ8/p™í©eb潞TÌ[tR'«×ˆØd&›­P ð–&@˜\çÈÂ3ó×uU• 5¯7'¢ ÿ"†üc–JXŽføîuÊÙµd{>» „OÝïd2Ù8VC„„cÂI~”quã#6!(µH3ÿŽˆ%^ 6kKÕ#À½ä›3ᛑɎCèåÔݤæŸRÓä¥bal?eñ9FGùÑLÍ„<À[ªXéNážu/[«nä_fƒÅèö\-ìÝ×;&ÃÖ–Œõí€Ád47+l½oµM±–üÆ0O焎§ñÕ(³«HË\Å q(°‰‰+G4oX•í¾‹$]¹{3KeÈ ÿI‘ `êt³6®wâžõŸÏÄèÌ×Oõ‘çULµ °My/8LÚÈÁ)ˆë × ýßðüã6ïÀÒUoMÇÂä»q‹4ŸÎ¦Æ\,vÚ_ÃïDx¥ãaE»kÖË«îV¬_p°Î‘]ßãbž¥L/Ž[²ƒ^ðï}jÈ=¢{ñÞ|ÑŸKEÖ_3Øßýg Xy5Žú#¸â‹ØQØŒ-v$º²}i„Ñ›âÆBÄž©­÷j}'Ñ=³âÄPŽr¤ueHré…dݶ”EÕµDR'ÛYs °ún²|{ò·ÞDÌ·n‡]³×Ð6Ó»ÖÙw¥ÂÍú’Gþfo€ „‰È¬¼…m¬’€€Û¼ÈýÛ,¢)bá³QföâôñÁO èØ2h†k©UTpÆkw´ÕÁ2òè¡®©¼ñšçÛKLÙ^~Ë3¯ZªÄ›ÊA%f"X«—✔Ë?dã©EþI£SùµÞâq9›‘¶¤~ô6Ê>¨¥Ob* Øt/C´O‚3AF¤cÔ6­ŠtŽ ’£Ÿ1ÃÞ-ª:&‹Eá?HHªDÞê„Ù_÷K°Vøl¯à È—Çuh¶©eªÏ.Û ô§k•Ò­þâ%søIN¢‡iéuÖ suÊܰ?Ø2o_ÿzÏ"‘3~äL¥»¥jMðö€U<´(U¾Ÿci—úû{ÀGó/²6nVÕE7ò®+)#@íþÚ¬ºý©¿™ÒËè,6y7 |ÙÌÁy`éé©3áò‡ÿo¨”Í Þøtó²}þ » ÇÁ¨>ÀLÈ„ÏYpŠEÀŠxe­Ž/oÚ²‚ØfjŒ­®ºé_W”b«"tæhl†z€ë*;ËÖ@n‚ÔÑížñgMÕ4«äªî½µ‹on,´uUThÁûkX×~—ŸD A_ÏÀúGɇ»S¡p7ÈÅI-»Bè?iŽ(Vý\öFí­ÿöRô'LÔ¨î™ÙOÍÒ³öZ:(qèÜ;d¥€$•Ý÷`2˜›;ÓZNŒâT Wº‚I=ë°Ð]iztG:;ÖþÇ=¡xÆKWN¶¨´Y¨ FQ§]«Îe©a†”Ø ç Y"†·«b“47ËZ bÁJ8ühü@Ÿ9 3ßIðÜØI¯3™zÛ}U¶À|=À$š_,*"7{4uŸãe뵜%¹­$Šª’¬ÆÛÈÁ\°šY’ÛàpTCÂû0¨ËÚ¥¶'þ>ƩŬg3z,D gA•fdùœ|bõ9ODÀqž$äeÒŒ¢ù¹«Nðæä6É7 ·¹ /mÑt¬uêØa¸n˜YÏWS?ÑS-E„òÒêxÄ ¹¼Ì£Š ’û>@}8T;¦^ ÝC“ôºî:ÌÅ_†\¢áT¡Ö4'yЕÝè­ŸK$Ì¢Jþ8wüV%µP"Lú»ˆËÌ| ~I¢—žD™Ÿbø7ö\mw§ 0€Ú àD¸¨V*³‘£Ö»ÀÂÆyÆMÂ2o%Seì+Yú9s@U~hÒ~ æ•šgŸ3´^›óWvyEv bÈ“áÇöù­¾^òeeÔ5{v¡ˆN…·sqW¡e=¬p?yÊF”5S¥ïŽ¡(ϸ¯J~P6çÞj"e8È,¥yH:ÿ%pƒÇ¸d9µ£IB årü9Ò¡ pí¥ôSé„€^Îû-mB›/OÕ¶l‹Ï‘õò˜3ù§†ùN"x£êe༢ø«˜FÇ‚~oDr¦ÝP>øœT_%™ÆëtKq;œ2¦O†%%W1móQaàKÉçT-ù:¬Þ.¡ GÁ¨ÑZKbÈÚG/d[‚{ÄÈÙQ¾¿|•Ž¥zßß§Î93¸Hyä$Ã?üWhYb›ŽÌmó¸þS2bÞt‚(Bá˜KÀŒ}ø™3¨!nHZ÷[ÞÓ-´,»€'¯wjÜVn€ 6éù¬UTäbޱ¡‡” »bÞøÝ+A_"ÄȤ[<åëÇÍobÛaUr羄7"2‡‹Õ)qEÙPð;@MViŽÏ3xeß(¸o§€È–œ•xÖõ†*U<3²$poºˆ E={¥çç×Ù‡ˆéÈá¶‹°ê¶{L‹ßFú—µ‡fHzço¿³à/Æ’€€óñ-ÏÝ2 ÔÊ‚èlYWˆEe»8Ðè(\‡X©Z@.Þ"—Èì¹#@\6I³wÞ'Üd“??źw0ß½™3Ÿq*<ƒæÒvVp§ =ÍuB+þv¶ ®™mø¼Ùòds³»ÑáNKƒàƒ(û³k*ä°ý€B:ñÂ!s¬#ÿ‡»þ=jz'#ÙKÇl”r*Ž1Fr¶Ò¯Q }Dÿ…ÈkØpGf^6ÆÀýžUÀAì6@µ ë¼Ërp;Côòá ¸¢ãù«1ƾ#1#äÅð‹vˆÑ·éÁørû‘둞6©øÆ^L4ï ùm? RâÚ^]߉Ʀ”ÕŸÑJå.]Éø¹Ü•5…ïI´úÛ3|Ž8—Ì·W'Wç5Hü'Ø·|cæÚH9 ö¢íVšÄ÷ͨ(7ÆV¥"‚_Œ’AN,ï“õávù’ud/·9Þ\™ÐÐf¨‘@ó=sB™(¥Ó\rßÖ‰ ¹î±JN c»ϱ-¢¬î"´S´ÙEPîÒvMÇÁŠ… ®£]4L-IR1Ov€Ÿ¸‹Gf¬²òÝ vx1‹jÜÁÇ\Ç…Ü\µ¼Å(]ãL<F²“´ ýÿS?õ9Ò©éB¯ÜÕõâD‚*£fÒç)¹ðèh£œÛý„°„ËÔøàéù&†êßÚx Ýêð³¬6Œ:ÂÔõ.?™‡Ä « ®Vµ¿(N/·™§¢Gú´ók“[^ÕD–„‡ñí*:g>îÌõ§£q ØúÑŽw£L°WL›lëêM$±pw~µHùS±ƒ!¡‰©¼ç‰iÜþðýQöT}”ð,©®VEZD³)æíÛæ¿Wš—JßOðTþø‡ð]¦®è8Ôõxšw÷ëiàƒõYÅvÌ)€ƒ¸¢O¯þ,O(AN<:C!ë÷WF­%£ s"Þ_zÄS—é&Â}sÝ£C ͦ\(ãRØÏ!1òßG61”¥ˆ7øÿC|†~3Aƒ -§¥¹b`oSÀàQTÕ Ön{1; É´œ†Å5—ÚÞãÂÖÍn‰ÎiZy’øBà%£±Á^Tx °q$좆ÇÕÒEÖçÑ´eÂí¥Éóõ±° ˜z°V¢Þ jôèº?YaRõÊÚ5rÑ´u7ÂÞÙË Ü?¿’€€µ.qÿ bé'qåjÜ=ÿåÂÀô¤8@ðg¤ˆæÂCM“ò.bm¥ÂZx¶yÍ#ðžç޳â¦a _Ðgíó06„­©–@:‰îÇò³Á@|d“Ã̈jNâLš•׬¢ò1Ÿbmˆdî6“ ‚´(æI~ó¸ N)¾y¡Bèmj|6G¡\Űç„%P§](¢¸™ {ß(TZ­pÆÖ­¸ïWü86lÒTÅ׺"è±mðòIœn0¢#sƒöîÊ UµÊ#Ã΄ýžöH ¤@Ò{„Á°S+'VÁ6Úœ£8ÌözÞ9¼7^x¶köºü¥…_9Îõƒ·¨§ú€û?Lh01œ¿Ú*¢^ÓßùðIE“ÏÃ'n°gÙ!ˆéÜàÔ®d„-ëÉÔĆŽr±˜ŸF+K4>´l&™K?<μڹ-zBý:œæËBzF«pƒ{™²¤DþkÍZô»˜´ÆRH!»ù ¢çy¢n…'àó¯LÐé õïß6Îe“íIèkb²fòœy§Ùk"WÆ”]xMËîÅæû¡ûØíš«z„¡à§n#ÛSi &É…¤ä@GiSŸ©šä-¨AízCYŸ²Àá7˜²¡qö¦VôÄrè@ˆÅLªÔ´-«OJLie MD±Fyáè3ˆÛ×6üÞ¼âé0TIWl& Ñ7¡îÊŽ¢>1(Â)[ýÕoGÚ»bÀc²vpˆÂXXÄÉÖ|“´ð¡íŠ¥ˆùãx É}F‡ß¥¿}deöêQ­2B«°!•?;[2fýÂéâÞ„¾ß¦nܳ™ËwÀêV«ËÇÇpJ;¨…ž¬„“­ÎïŒí0Xhüƒ!(¯žŒ oç´§R.¹ ?T,÷|¿ááïƒPó“«9<ëå¼CáRfùÞ[ÌðZ\üQ[)~'væL´dZj_Aû´Ùi:¾e¶ %ÇÍvþCaTy'…´]O9.éÓš|3ò ©º¤Ó²É\ ïm-SN®2f*3\ºcÊÉ%Ô^ %Òxy‡T¶ü÷Õ ‡9 âõ8CzÝ·…~ñ‰zßF¨“RFÀËË÷+»¿§ãR\!:ËܱR©³LjÅa×:–•|<É%{Ùb©¯9<Ç XD®¼ÚNUÞ’€€¢Ù"¾Àø»a5]#ЙQþÖª’!°\úBÞDWøÉÛƒ*ºíÔZQ‡tÐÚ§véu°­Žj ÖZ­36<±àgà \‡í½ •¤¦Ûr1Ÿø&a^S@g¥qG—‹€‘DûgåÉçSŽ›¾L7DÁSÑÅBz ×ñ€w£}J”îÞ—ýL‚{RçE(´Ù-˜éVìôä2S³S µ4Wþi#åËè6†×ÍW+Õ]{ÄÅ~á>¨­- 3ná-y-W›hvÃ^%´×e1”dmõø%W”Iª0/`ïô Ž!×ÖW¨Ax›)ñÚhÒëHI“RmùpYéÝã!oÞ*k††çå”gmL+‘F¿'iëÚc ÐûÊ#£ÅωQ3&VФ‹â¢Æ ¦b2+;-@òÄpçÑÏÖ»%Hð(¼âëéƒÂÄ6$%Á—ÿö³Ñ¹ÍXƒ¦;øI/ ®y¼>óǯ&Ì——BYOU¯¿xÛP÷]=ç·—µ´Zà%mìʯà¹Åv»Híd¬ V¡ ²r¸/õR.ܲ뽿Çk;ö~4J«Û˜†µoÞBL³t$5yââ®BÉïš4¯“ *AtiG„ç†auc1^Îùþ=ŸÑÝ‹ØÄàá,EBma×Ñ4ü^øµý¥²¶ßŒrïÉEË0Dõ¸E] :訄Ôÿ ÜLy@˜©°ÈµÎkƒ÷RÛ³êØS%¥¤±ü9ìÏPšXvàabþËjOõ•^6–á÷ΗY—l°Zm C ¯£®óf¼ìœÂÏŽT¸Ä…%WØQþ³Á+æ2†šŸbZ¾ŽK)ÔKæ?ÏR˜6äDUJX&v¼Q–Ü„5i v­‘®i9½Ü`K–ä}.P ÜyÇÐwñ×ß‹´ fùª·õå ®!-ú¾¢Ã•]þʬÇEÕÇØYÜ\þ„1£‹0jKå%R,×Ûvónô½ÑÜ‚™ù¡"Áº¿ôåâ Æ‘½ÐpÝÞFº¹ÖS—‡•0 ëVÚñt#Ê„8ß곫<¥€bŸ±¢IŸ}“Ù1{Ëâòå²jd0›¿áéêÝ„<îYu“õ’‘W±Ê{›,ìõ3ܶDÛ0-E¯ L|o7u;–*Ñ_©n߀¾â98‚+ï.’€€¯¤µ|¹ÚqÓ¡£+Ðh¦&‹½GRIä)´™B¢HsÎ¥»ýéï•«tЪ# ù¹¥[¬jÄfE3å~“¬·ø•À·Ú3@r‡H,gÅöc 1²zä+a÷ÓÉB{¹û–™@±/”,KJcˆsKÜÊ·ñAëŒÇ}ÈçMz?𨊈® ç![VlÖP;QãÈÚs¥›ä^sEN-fø›J’°¥jrÖXE¦‡w,òŒmßùôjÊ=À{ À±”„é—‘œÔ~{"‰€tF”–\Ó¿‹V"$hPîÊNY½ÉVÒc«]iWs4~åçíÐf'a¨BZMèK´Qu|ZRf¦‰šfÄ}Õõ½Â]©„ NQÙ7¯VE¢¾þ#.Òb•ßAÈ5‹Bk'€ý¿5´Á±ZCåæ‚¹x^ê^Iþ¤£…é4ÝÊô×u8|§õ±¦³€Ó["è‹ ÆÞ:€"Ó–wÝá2zL‰¬Žƒû¿p‡æÒ CK˜ñ Âî/ŒÆá½Ô¹ ;µMÒlž³÷ 5m‡ Š‹#Í™£Œ°ÂCã¶š”Û1\÷3Bc=O%N\÷Oû½|J•âôq=LÖÝZáQ™Žß"âI¾‡ ô‘Ê {+«“Y~e ƒ5‹ò¥%ƒÄÒaç¹F6·ö¨…`.½ZEŽ0vñºa`• D(8náwúìÍMý74\ð­ÓÂ-ˆàŽk6âÌ8WF›N3FFÎGû*‰r›àYÖúðdË?“7—/–Nr?è§ Â-v¬²Ð›„w[o'žÙߙƯMdçšÄ·&J°§.“°%!ˆùÂ™Åøïþù’‰D*É3óN=*xKdQKÖ‰¡àŽô¿HϹ» á,²ˆ £á‡!_»»´˜crTZšŽ¡PZ÷Ø1…•ù´Üs%%Ø?º¤ØUó¸þ^Vu¾qCÂÂß&}B>‰Ç·º²ù¾$ó¨Z`Ë(–cV+Ÿpc…*ã¸K”/ôÞ_-ÝóšÿÈ 6m?·½wn†Ç@Õo6úÇæ&#\mNžä?è„bz'0¨¦´yóaò2 œ'Î6ÇG~á®)¶%MÓ¥kfÊ!³þW,ähÛHAŒ¾Òk¡„hçn°¶Ð%³„6å骎«÷¥È ]c‡’€€½tl5Üö”óÙóûµ[‡”“‰üi—¶@iUœ†:€ÁÌ3GA®rm»OµÑÛ\w!’è󪯭èbÂÍ<‚`E]cîø— HÉyÚÃŒ»7|y8f*̦B=¼.vŸæcAÝ÷wnØeC“ÿ‚²é;kÀÆ4{¯jà¯ï3;¼‰:ÃXWÚdœ8Í;úï¿L#UÙ|฻{Ñ'¡: ¼wúH»zRÝWN và_f˜¡ëÛeÝ›ÏgùØù¬=+{· ÙÇ5c68?£mˆi8™+©UÌR@¦ ©¿[X£ÕŽntNú{Ó /5€Û•»~\"èkŸ²ÿ} …•ïŸÆUY@pNë2³Õ|íÙ [÷çµ:úZõœ-ÑTUqÆzˆ‡ÚÀ•Ô„à½]Žò_ LÏ„¼9Í¡XN*#p••O»¡üòŽðÊ3û!ÀG€ìånin/:Ý×Uh Þýa eíŸZS3»„#†7ƒ¹ß dÖJñ—À2šg`?ùa'ŸH”HHãò+ŽO%«'Cî%äÚ»`¶]T’¯t,Ôßt4a®k¬éßâÎS†gÒý‘Vg±zéÆ)‚ÀŸé×ì´ÞÔd6е”ŒÑâ|è5ÁüM¹N?Ÿ½:è½Õ I&ØfþKx(Æ’a;šáðŠÌ´ËrRˆÀ6gŒÚÃ,ÿáŽNì~Q¡ºü]/Í£ò7Á—Í«ÔÕü/ôùLš”,ï´^£á$p ¹ƒeÎßGe+‡SÇ `u»OEõ{€Å=4½©Y7l÷N¡‚2ó q¢ÀŸ™¸ù’€€”p!*4}g€Pqí#’êïÌ@JSÞG»3Ÿ˜&øÍvî&“wGâ7˜ëÁ†®µ |~b ¦ 5Äzoí4hÑío\ä;XÿÞKÖ@Ñ}^m^¦ N¿eÜP£°| ƒ¨­i«wã Ç«í‹Uª$‡Ì'v”„ké×0–+9# µ†[ãÜ*`—ŸeÔ‹©4—±b{Õ,?Ðo¶s™la`Õ3Vë¸,€=ßûß™òq݈j„qܱsYh—ÒZ޸ᒡ­)7îJhDcîZ*É€ûk0¢U{÷ïzs]1QnC;½Zk2Í#a›cæf\™ç˜ÖoׇØ‹š‘8A]2]ÁËô2¢Å£ì(—àÑs¯ñ‡S-v޼1©¹ì2nmaÑ ¬K7»X/®§gZQxšý¢u€@¶^°mÒA×1òòå˜Áò&Š‘ÅYÁ²¥²Æ{t‰”z.¾ýz.ªóæ¯pH¶®d/VXvRO-då¢Ôpz‡Q¯¥cÜñ@wiƒûÖš_øäó|"s%$æì/V§>…Tsd/5ìH÷UµÀ¯zþÕÙ”•ïi”ÔU÷/–ÀšûüGLѧxt¥»´ÐëÕlEÐÙwOzDâÁÛ}\þú©ëõBÈxx4ÉˉÛh:õº~[´ /óTe»Y· sÂù×Ñâ'ðM™ô9ÍÕ¢ó¾uAPò<ÇWº:)gBþ[¾€`mWæ8I£-Õkž1Ñ÷>\‡yù†-ìÃ(ÁJõ ¡¹&íº%OFH’ÙñÂñx?;~O3oà‰oV›ÖÚ¼G-6Žåï ¦%2å8?x¥èô¨”áëȱD¼  Âå€Ôî_Q“XÛ’ ÆŸÉc¯,x‚‹ç!˜Ÿ€â˜­@¹E"?ûÑ.¬wF—ý‹ð9TšZ0s„ ì˜ÄØäÄ—â’ ßgØj©XEë!ÀZ7øÕ)ñø"§ÒÒÛõ-"×Àš³˜*ì7¨0p?ËU<|.Ã÷^p¦çìBÒ.j2™wíãc—ÇÛ³¿Œ­fæ Æ¸<*ÿN‡¿Pƒ¿òGV·âîÞ?·Q‹økø)—ÚqÐξÙú"< 7FTÇIà Týp¡gúÜX®•¨7‡€Йy ¨–zc¼³5’£°±hXWºqä‹0[™\Û¶9ËÙ$ÎÕμ‚Zw’€€˜Dy+Çí‹é ú‘¦õ Öœ'Ø¡oÏ*Œù*£ã ˆ0s·Ì¬që•5hÝÍ×ã 7Ä =ŸÕýL"ÿuîqÈ oŸ!jE%_D_"4‘[šâàM#Å?¼[Ÿ (·;™ãÁÔªBm²¢Z³ÚÙ² üÜé_ÚPL÷Ðá  sªuÛU˜<[D)ÂJ¨G4.2TqPrÈ•¥¶²_½f~)O¤tj–±uÛDß(Ç#. ™ð®`Ü)y…=·„:ÿsÑø àbÉH ×;rÍ»ÈJkå]‘çOÄÙŸFXJ?o¶:jÏç?*u$j:Q¹R_Þ»„lÈ}±u{‰:ÚgÄ¿sÜØÝq~O—<ÑâòÕë}\¸?‡^løVŽ‹lüK˵Ò@€øðt÷„!¼ulبQ¿d43˜>-ÿ‘g0mªEÏt>³Õ¢1„(ëóûÚ‡8¦êr*ž­ 9¡—bƒ70*®¿_£`½£Ì¿–†rI3^7Äèg¢µß cͼWë¬}¢NèêÚ6»ØjáÆ…RM¿‹cäž5o‚9;këÖaøäu:¡ÛùÉîl1¹ñÛý¾Ÿë#`–= Fç|ªqî/n]X%±e“ª –`º—V¬Å¤*¿ÃøŸ"Ióé—W#8mç9É–KuaEèHY⥸lAí ¤rýŸ°Žƒ¬%&1 ÛE±äwÄݽ7ÙÞt‡AÝhÂ¥óJÅ; h¾¨Ì@>®°‰Ÿ ¬Šïf+H–ñjª¦X@+ áS!õ~!O&å‡Ò~½Êá3-x1áIÚnI5¨Ög5KýÁ^/5wIš¤)­š‹ ‡¦R×Òb23þ¨ÙM¬ !GGcO/ë[“b*Sß&Ø! .PÌœ÷aæª ©b÷qŒ]_ÂkêÀ(eåà03(x êVD7ÓÄõ¾¢†lb¯„0RºÊ\õMV;6h©{tƒ”˜(dr’\]§wíòuô¼\ËîÃO—»m}›·Ásóg.99ðüÀrþXcôèaÖ_}ÿþîí<¨´„®†×â’{ÁÉlâWT@ynsÜü •ü ½™B_e"Nä® |u[».R–Ͳ8á¯f¿gÊXm÷NülïdzÚ=q•Ÿ’€€®>·h4ègt9¥ÁèüÔ3ÕQîjNÄ©Hka07Hu5vÎãwîÌä,‚Ò­* Î.mäYV†Ú3óï‚P„`Æzøv·ø…À’“ó¥J|V¦H¾áËæ;;j¿9†k +pâà5ïüÛ÷:^:9/æ.êBòå—Îü.'â(æý銌W8tذ !ùÃóÂYðä͵@.ŠLÕ² ú€k¿+ÔE€2KÔ9îRè%†ö¾YÜ^a­tŠÞ@còŽjPc=›{ÎØ®ªÍÓŒö«ëƒ,Ã(uoþŸnËñª¸Õ².÷àQ˼ªà>2«`C@d¤wCcå#/["Käë~R|kšØsÁ8ožÈá¹㥬ãòÐ2.@P™ÑE¨ƒª3fb¸gðè¼jé,ä·¥6’ Œ„07°.Õ3m›&fa‹ä þ‚¢…`Ê€ãɃoTAãèŽçíâ*«fïñÓì`™Ï¥]H¿B‰Ô…`jÄÙÇòÅÓÂú$ÌCÏA™äÏó‰ý‚ÜZY »~ûæl…A?™Þ6WFSÎ߃‰(ñûuÝ’y'Ò_ ê°õ(}*í~ýA@÷g¸Ì Àr,ó²ÕõØjd®î=²Tx¢››=-Å¥‰ØÐ2;Él4Š×åŠ#Í‘ºŸbÑá†FžÿXlî—)54ÈúßN‚+uK,WÆjͰ z¯ÍZý?oY5FáÕjxsš\]Ì 8š¹ÓsgÓ²ýB{i¿ MSDW) kúC`á3 ©·Ëep£ßП:«yuÌ’€pŒÎ¼´„iþ‹6—Q’?> ™1ÜñIHºuJ3ÅÊJ{éoRªà31ýÞPñm£Ü>Σš E2“ö; ÓºH%`Ê«8§èBùiÍÀÞÝú9mi§9ðt©uTÐÆ ØìÖwUÛÓo(ßg?fýcÌÙV›Si:¼=ýQÐÑ‹¿åÇõOÅe×7=FQÐ p×ïa©J’|n¿Gèî”Ä'ˬ°'¤Ù3”VvÉãæ'²`zÉe òîÃZf3›ŽúÉŸ‹õ€lãÃUiD³Ï¶ßIáÅ¢Þ_Žþ"„à1iŠŒëý+HR9Zï rWí=}˜Êå»3ÂЇm8Ioø&+F°Á•àŠ—Xz^¥e/¬’€€ÍVê×¥ ýÁAŸŽ¹%—U‰ž ðµpý=M00Ÿ¬ï:ªmÕjµt&ßE«;ÿÉktWUÚ{r1'DÂç¶¡.Ö¢;?ßZÀÖ 4 )‰õ-“’)ýX`¸ Žó\Læj‰{Ä:áLJ/|NšE*ïâzB'}ÃÕ’ HÈ~™ÏúÀ<[$¢Ì‚ Ç}ZVѯlí¯,£¸J¡B~ .õ@ŸFîüüj#÷†•Š/ÇÑ~JV‚»C9û¾EÊñ5&`±í^–{P|E«Ti‰f5šB.XŒuòNñ0ê''/½>úf¼˜ò„‹ÄŸ˜‘f\8|MȘ”¥Åfʤ³éE)SOîZȼÜñky§¦†ÌÌ÷°="—¶ˆ*ëLQ–Ã5¥éÆ~o0تì.Ü”Ùɵ¿·,¥ÀWIÌfÂvÚ9'íhfìIÀMH@í¹WPÄÀÓ<êö£ìAYtÛ !¢¦‰ƒšÉY¥Æ¥ïŒÛe˜?aXïl ¡Ý²¤æ0`f¸`-­VøK¢sGPqÐòjKB—¢ÓV]À¿_Qf÷sß…ÐWÔ_%Th+GŸ"L¢Ã~óTF=ߨ‹³Eö±O\^šÃ²&â®®±AÌSßÏ%GTši}Ùk™Gž¼ íýÞ®IM%:!ÈhÑ%çN¡j…yiOå:‹#¬é?Wd2¡êòñY¤‚³@&'H"1¢¡ôýe&2TJõ>鱫l¥‘)÷ dݟظHúq×¢Q%µ[g:/æqG± Ü©Ñ:³ƒqýe”–ð~ˆ?¾Â¥y–íÏýû.°£4_æõaqË4WB.c5r× ¼â@3ÈÔ.Õ+j£²#{·¬Å¾©û×m»­xA¡¥#ÀØ*±j{ÔeÂúØnE™7û¯»Ê#W˜Óë'(œ" ô.-Ù¶†‡¨ wÉ9à…´3JEéÏo…”,¥š3¥Ë²õÄâWâ†ÛLZyyM(‹ï9¤Œ:!G šr&@ôß¿FÚéfë™Ùzá0‰gãr ¦ÿûë¤[à±§¸ñÛïÍ8Q¥'D}IŠ8ú»ÈUZ-1e+ÓYÞ?Çé 74MÜR)†i•¡oZ¹¼ðÄŒŸ—8êÉÖ²1ÒŽ—Òˆq¨Â¹Ÿ!N†ûP‚rÕ;xøò'¦ÿÆ9Ø`,ü&!浺’‘Ö—]Nõsª«Ô£6œ·ßì_fa—öÜä0?ä þb·7Ðk¢Z®ðÍTMÖ’LožåYö\L"–óºVà—U<»£@E±Ãöë¼AÖ|ô‰R2ªãÿŠ*r6I|ì4¾n²â©;™æm’TIЇϻΆªåõlãvåBÇL«Íü±¶¿þ^'2FöJ™Ã|W.b´…fðà÷ÜÀ\ÀMÒ*î—ÿIƒªjj2JáÊØÅý´'ÄsÇ9ÍrNµxB—UÙi«Ïdq†Ûiù0záæàùÑ©Àðþ90àAÖùAöÒ>&Ú—† Tìò|MèÄij1€¬¥Ï¬%¸”ºB Ó²`S§Y‘O |Êʰ†@_«Ý›#°slÚ£ŸBs ¥ß6.‘^YßÅ`ý6y”ã°çˆ½³Š$^"Üó¿¸=‡ ÃRþªG¥Å£âç±ÛJèU’€€ËãS¯Ñä5ô:JUU…CK[^ÜÐÐAG Ù5¦~Ÿ€©o‘«wÉYæE @uÝ?ÔòMxqzeøñWüCô7!7obˆêQ¶ßàÙÇWñíbGâ0¨Þ|¥0•KO}ÛÌ®ŒMn¿"¶jj«j´<æðp¢sñ«AÖŽ.göºt£üŒºå;OT^ÀŸdÖO+KáHжºá·^‹x¾ Y‡þ#Zšôp‹@…³×¹,ÎWæ¡PÔ ßnÏ6;Ùc³¹@/ˆ™ÃÍI©sa*c³5€têO«sqGL¾„æÆ~²‰S#"î|ËïÙ:‘ÝMç$ãæÌ~›„o] ‹ô‹}7®jP©ÌlgsóV–¬tÉÁ–§X >ˆ;›2b¦öÝvÊØà¿²µùøÄéøh4†þ¤˜½ÖôФØþúƒ8-°Þø¾ël"’æ‹F¤ ˆIccï.þñk¬s· I Õç8¹ò‚ÿp1Mp|äÖrãݶƒç_ÎÈAÊýy“'bk­ÉO¿‚pü ÏkM¼–,°á¿’ÉmêR í=³Xt•(,eå› é?4Uì}\;pgJñ„®VÇÔi²4”P9ps…Ÿ*Ã:plKy"¢ÊtìéC2Aús‡ÔMðBŽéó>Ñm%.Åä ÿj |Ù³¹ÏZÉ;@_Vè¯â¬Ö~1Å€½Ý!åzó”%¶´ô6#Ÿ't7[büoõ4¸ᛇöûP‹TòzµFÅßxؤ\¹ÁÔ²£@X-_jÔF:("ÓÉ6?I<1Ÿ01ô¼šèy«µ´f_Ö”?°È¥ÓÌ…•ཛ+ZË7C‹È€åJÊå2-:W¤”5¦Õ­Ò®!~r­³t~×  ÑÚíu×DQ–ü ¶qRyÖÕAÅý°TOãųéóÓ´ •¥1•Éf6‚ÇZs,áÜÌSMhhJC©Ä&›I÷"ú½§à`õyÌ¥`i€Óîº5´_!Åa›ã [“$¼>ûÅæV]’ª{Ø ­ãð6«­4Ä "½Ìœf£ÃPÕt‚£4b¥¢r˜<ªpëQPy±¬˜f½ÒÁ»×Áqî,Êõ-ÄwiÒ“"æ#¤CÀcâÉŸ‘_‘ž¬«ç™·ÎCµ’€€Þ+ 'Úfw|(õ¹z ˜«¸«v°Ï))ªíŪœò.éWR-Ü9å–÷þ3i==Ö.Q>i~ KѨÍ2·•æûRÝ‘¦¨Oæ,Œs•ø8ýå>"»~í ÷tµq¿³ûÁ­u_–¿3Ñ;ÏiTâïé>(kzÁB{·¶]’È>[—*Ü̘‘ê1‰·k ù£,v€Ê” “±Ï UøkM¨¢óbñÏñ(DþN‰¸¬‹0«6=³É9tðR`83ÿbâ€G¾@ê•:¤oUNi øŠÎs*û}$:JoˆáA潈ûzÃÉa¡m¸ý…=›®=Ãw·D‹ ÔTû¾éo;ÓÃ2÷uû+7çÛ2Ø¥^¤Øè–‰]=kZ’›EòB˜_*–§£i#$óø2íÑëö’‹l¼›&Ù)ž5m}›4hËëÆå½G+Ð ©l±ÿ ´ìÝÓ¶´4j„Zr°ï…›då!µ`bž)»´Šg>7Ñz¥‡ðˆØ~sgƒž¶ºc¤éä´¹ë­3HmPeB º¨!=çÎx´šëµ@ɧ€¤T<Û£•i×k†Æ;… «ˆ¥Ð~ŸŸÆ7 Ó(w – ºz’P­3ͯÌ)^X:öS(m& «4²ˆ:Üò¦m+ÝÖ‰rÏß$–ÓÈ ‡Ë‚÷‚(kD ¢¢ Zv׫<ùeˆg•ÉW@fšou7ͪD4 {dô˜‘ú„/Öη’€€Ù´³j/ªú`,¤¸~ïÖ®I.þD»ù”}ÄŽJwZTƒÁõç½=vtŽ˜K'cg)Lö§Òmf¦#q\ÆK‹£¤«@½F|¸4ÁOK Óþ9GEdÅ]w…or0<ôMÀ;µÈ¢"'»Ö2:“1ašrׯ‹ª<ù¦`‡çuËø„d*vŠ–=Ášm‹у<=p~Ä•»QìÒù—u»vb¥è¤$Txïο÷4çjZùn¤UŸä !ùu09ð8ñWÞƒ×züÏ}€êÚmb¤Ýq(yL­ßœi"9Þ r;Áó.×ß÷øÀÚãÏÝJ¾¦§‰?¥˜¢”®ÄË}K‡ðEÚAôÏI̯ž62Ÿïñá²â*T½ÇeìC¡2áø]•›ÃÜqyü"*xƒÍó€ß…}&-¡›RÑ®ÏfsƒÒ1PpGýz©ïèŒôä.-0°\R»KºŒ¸ £%t>޵,Ú»¢” ·{´“»¬£Œb&Ô¾ «|Ùç#^É]Lõ<Õ©˜½[du¡C‹,ôåwb/`pÖ -ŒÚ·Ó›d: ÚuçN†fQ¨ƒ)³DîÌåùrü¿0uQ ^;¥bkbþá™üj›ÙK'l+Ài”çv‡¨¢œJ1ü¬2vÂUa{uLE¸ŸE<¦†«;í¥ü[cïNdœò世þ›µxþ¶®~«Z½9pnYÛ‡àÞÁÄ1½¤Æ’¨ë%•ùbÈ›3í>s&`$¨¾«¿€Ï¯Oâ-ƒ‡wCSÜ’Ÿëu yóÙ¿eM‘µÑ_{„g+Ú,,ܯŸµÑ¦AmF8ts?i ø…'…µ~8¢èPíÚÿ$D§HAEÄÈ)Ц×u‚þî@‘þ: ùä`3Ö K0%Å? ´1ì´ƒ @Õ?¼Qæo# è úØìÜ5CW>1ûi/§ù#J aó—S™“–VAÆì»ü"ŸÑv4˜ Ù%–•ý;Ÿ;ìï~ܾõ£¥jn3ÕŸ¼ØK±O‹p¡ÈyQ(dõÙéÚº$•©µ7áÚ.@n·éƒÏ”:ü%³ú¶ü–;=ö{ÉÕËsõœßØ!Ĭcû#ô;„»Ô’€€åLÒ]j TdzÌ”¬4éÇ{1tÙ]ëÙ¶)\^¾Ó|^l4ZŸ;¨Ãö-œäu€DlÆËõÍÕ"7à^;d‘.Wë™Ã’l7OŒÅN"±s8è ¨À÷Œõ†^Wû†I3Û±6Æ‹IyÕæ*v•][Sm¢pSq¥Â6üf&Gy§DLªsìΡù§%~¯fÓGúõ>Bú†åFDÆ'gÆU A硚Z´‚aQƱé>ñ¨Æ=ñ.\9ÿK¯ñË=´ëÄÂâž±Só)ää(j¤ÑÇd¹ˆë6]/g—Ò§d™9 ÛÏc<±­ÞŸÖµRŽìÖ¹·ù¾àå)ï+s²Å~ruÕÇîü¢ûZ°œ\‚a¯µS€Tï¶'u. æäEñn_’ŒôŠç9·Š¦¦A5r,ëf{bÄÖ7!=VÐzÎËi [`€}‹ 1õ …"N7j£Ï»÷†×mÓ÷Íž…?ÃÛvg wÞâ$ú[Z/† ÒôI¶e¸ÔŒ*^êÏ -DÚF©äÒHT¾91'ø–ÜÔØwaÃpÎ䇤u‰7-FÓ…b R»¤š¯ô1wm§#r´g‰ j1ˆNcr«¹ËQ}Í_gê8TǪsuÀH‚}#–€_䣿ü”&ëßo°úU÷Vй’D}qcÙÚA•˜`/2Fù®½L=úWñsÖ@ɱ«ØbBtŸóò‹)]‹p© ] z^D‚~þ.cû):è#þA€€»µ«~CýÇ\àë)*éÑî­ CëçW ²$1ÀÂÂ÷jzZÎGaхͱ’»þCÑ·íTMBAÏEçµdº«\ºæsžDYÃÞöoª¥IQІ$ãµYß0wÔmƒŽ¢h?Ö_ÐQÌ˱)›IýomiÛìÑá²OÕ÷îgZ^6îôöƒ¢ðçñeâLn«–ƒË2¬Ö¿"ŸºPV®¡  !´Ä¥@òCÊ Í2õ DŸº`N¸ýåxwrŽô ‹[¥±Þó$î>w›Ë¢/¬¯wo†òW?¼üEÜ«}¡"jRÒ+[pœyŒNÅybÊ‘†óšö±»¨å¶1šƒ'F‡‚Y6Y§ „&û¼æê†TY»!¬0ðØã#÷™ÇUíSbþ5’€€½ D•Ê¢ð‹ÛØêñÕ¹KÕîÎiÞûtñ'Øþ¶QûgmÏGùJÑÚ›ý•¹å´Ò{*2OL@õ‘‘N+Nr^®Àš•”•ÆVSüŠGüÆ7@Ãn¿ú›×€›UëÆÄN½Ô ,ăvÀGNã'±\¥ékh¤­Wß® ÌNï%r°ÄX¥WÌDÁ2 ‹TžZs¼ÿæ;¢#hvÈ1 ›?\F«fNCˆà¸îÈEÒUØp›`/cÓÝü÷!ÁPËEUíÁ‡‚RÜË,²_7V˜awaK}ŽˆK%„ˋХ’•úß”8DYnžµö™­=°Óí¬©kÓ“h•O·+ˆggŒÝ¯À{/ÎWdÜ×¢{/Ù¸­¶=µÖYÕ-†~fŠ61”fmÐŒÕS.©GeEt$"pˆ|ø?’bž¹$`UËhv! Ž-¿2])¬>l7•8°˜'·QÿK]Oú¸¡„M< [pPÍ&Ìt%é-Ž]Aƒcn®`1‰â$/Ž~/^‘ʃmýfýØ^£TeÞdŠ"þKýªP ¼*3JŠ‹9ø«¡‹’q6¦ý4®ý࢞¸í÷ ›3ðÇBpöÍ®¡»]CðwÅHóa¸Ýx_ásÞw»:Ä<Íq;“¿ŽpþÕXœIî43 \n=k¯}ØéV 𥠵,ó\!¿ã½h~îñÂäài¤Žjùê—ÐZ0\(ˆÊž0â‚vç«—k¤=æ¬@¼šIO>F5áƒKŸœt{¯NÏi#Å©W¾¨sºjÏPcc¤Æ3ì7*‰¬,÷­Fá–ÂÜlQ a £:ìÒÔ1°·°ì¼N°@œimMè %--#ÀÅIbý&XÃHfÜhÑ/X¹(?¼½½ ‰áz£†gÇóvéLåÓðKꬆ‘E»aºŠŠ`„ ¯T#©«¡v Èb36ÊÞ‹ÛSÝ5ƒl(Î *®HÜ[~Ù–s\1ÍÛÌð ãHyà<±J'’€€°¹'À*|jw‡±ÜíB¯²QÙdkºÏLììàäÞêšÙp˜ù±)46;Qr¢T[-dèósÑáe•1V}Z¿xÈàT9œâ¨= x§:ªõëå´¿¿ûÐ,Ú¼+€?欲ì|~¨ìrñž1cðN5Wv©Ïƒe5ö:°’ SN¿šð¾Â «k2þ9>4 ²Ó`´¸ï¡dÇ6‹û¾-mäPvÊåÚïž{[¶4@3 Ì=N`g¼Å ¨iØT^©€M–&EžÙ>p dbÌÉãFA4îäÄF´ÇiÎÈ æ~xëP«u=)I/ÛÚѤDg±í”áÄ䣯åîðÇÆ‚l³™¼hvW&ƒ?àñm-!¨äÑ[IhOum´SÍt²ð­Ô-ƒßD¶Ûˆ¹9 Zcâ˜íÉUs©~Ÿ|ŒÂýó"^BFî¯àry¾ÙAŒ«ÍcvµÜ°„›OÓ}Õ3+ÀFä´ZJèøÙyãdjÃxž íçÝÚrä{G)ˆ—Ø­í¬hÜk=&Ýlj K–Eaö~•Ѱ»þ¿hI*2\ï½í==6mÊŃ˜ŸB—Yrö‰Ñ¶*-r’›K¬ÍF0ÁÁ¦ýUœ¼^ Aèåöá~_3 ÿ+ÁêƒQÖ*ótuzÈ)(7FÇÑŠü9DáÎ^§AÖ‘ HqÎSÏ;›ËñÝiR•1ÙÑ;@lò:ƒÖì®þÍב«ö€ Üdé}‘R Üpjû¬¤°X'J—?$áh"ô‹£¡½ŽñÈÒNZ7™mÎmfðs"dX*XÓ,ïoæ6ÅéU *‹>‡už%WjI`¥ V·ë,"ìæAÜß=ôϹž)åî7o#•zw™ý1)O’\Ë«À  •c6Î3ω]ðXº„ýú²Q#~ͦ–Áw¸-o³0²ò“Ë{â=•Å…3DÄ-o¨_WùÜŽý¦ug‹ÛGØîÄý×yÁ4¨¼ŒÿîÍȺÇ(·-[½ºb?;æ×Ζ’€€ð~Ìõ‡Ô²®vtÍ/*/˜Ø’J¾%sçqJÎw‡ñò†q8Û`YíˆÜéùHqÐÛÃjg—‹ 8‰ÅTZ­°n½¥9T5[×b©Ê‰].¼a@b))‚7$J 0U)¼a\´øHáR-Ãjå}úg½M7WˆF-u¥ß6ø»eÐ)=¯©(ðÆ@v<»GÍ‘|©;©¸41p½xmÈÂf7Ôûï  .åÝÓ|Œ4 ˜Ž0nƒdkÞ?»xÀ#„ÃfÝG¹ávGŠ÷ÞRI¥ñJ4d2yCòºŸoVõ’Àºwþäõ·¸ðÜÛ’Ÿx©K剖 â0ÈÔ‘@Ñï)9ÌÈcZÑ™î³è£# Òb#DDà,óK/›Ñy$‚Bî8+ŽÞ _«A-z zÜû‹ŒÓ5(…FÖ×<¹^ˆ»6ÁHš ï%j¶u+ŠÆµüÚ©M¼åßÎâ¡oû RdÎ$3lS7Ñ"ROÒÃf³RÞÅ 4K¾Ö’þ¦©Ôá}ãè×,ûª¢òCg4hç‘vÎDÈfó\y™Ÿ³‚êvMÛÖŠ^/cç¯UåT‰ÈՔæ%RxDòQûXÆ'lÆÉÈU„ç5˜ÞÜf2Ĉg£3{èþA‰Œ9›÷ÀîÆä¤v1e|:Í‘SÅ~ü_ǵ߆Ñ: œXw6«×€¼Wc«/üß¹®ì,úÀOÜákuPcmšRÝçÎÌ­€¤E1¿žRR¢\“}e–…>wÀ]I»çb<=ö4^Å çÝçÞ•BóL×çüK¬5#X̺éÜÌu[Þ8©Öý 6‰·LôVÍp9mŠoÿèðäÚt§a5ÚVjüªŒ`!¡]ùõîjAý©0¬–UZÏ÷} šÚ€–¦îƒ¢|¤~Ìl¿OãHLŽ‚æÝUÙqúö¥ly)LL†ŽõÖ9AhdÇc5ôÿWB"!ÑLjöä›Ù ñ—Ifpê‡Î¡±%¢«Rç˜M^›Ý‡xZX¯BT°xlìh¡úfÒÎSQI‡\©KñèÉ›²T'SÏþÀÙ™`*䞪'âã´Qé«¶o,dl6tÛàäVë‹ûi¯›/™¢¾é”'ªòg–oÚ^“òŒ‰Ü2,ïœäCËHls³—¶_[Ø1½>$)u¯?Pµ;AKù–c—ÃEkø¹ú²T„xÒ®{aõ‰pþˆþœd»ª{ó¡\Շ̞hâQgðÒ0‘PWH1Yg‡<Ís&sñB:!/ðþ»È‰W ¿Ža^M:™'ü~þ}–«Ñä›™aªÿˆ|.mÖòŸi”î€!EÛŒ†¬^„‰vﯢ)iÖ:îõDï=äùVú×Ò<ãØ$Êá ÷ Œ§z:«üvÞ“ª7ö§IðàÒšYG­1Åe¡ÈÝí ³\…zõR>Ò¨ ´˜¬)X7‰r«~öOê wá§Î¯¯mÇñ÷ˆE½G,P1{“8ëqŒfq,#»oé–®·œø‡¿z†ÈfÝnWÆÃ’€€Ë'}ÎtQûBÚ?ýC’o‘?¢<¡hµæO­gøl—%´ØöÆ_¾Øjfž‹Lý6¸øá¹ên°2¡õ#­ºsÀÍrÌùeçQ+F½¸¨ï´¼Ï¨Œ¿Üõ £é™òWWöá Aô,~é,$ʪ‡7UŠ©õ¥F<-¥–Û;šÇNùRõ{v2C7*8—‡6<š“w´¾v1ªoVPnhйªÛèÖãHÂd i¸Uù¢¡ïE‘x¯Œ ÌO4¼S‚O2êb |5šÎ”V;jXvñ©NFÓ+ÏÅ퉇y¸ÁL?•rtÓº*ú»Fl—ÚÉ;KÌDA:¼áä–”6.ô¼ìrÄ"hŸ”0ã„Ò½|#¼ŒÍ'>Vóæ]bè:R$`ü¶s=;_•9§'Ÿö’ì꟞‘ø8Ïlnçñ©ÐüïßjäŸàñrÂÐVfU¨]ùa,¤m$Ž…w$œÄØ,Â×îEl¹V9õÿÒ~Ðû ç„•ñ­¦*»ç‹Þf›‚1ÑÛ7éøÝ® ò=8ÏXG׿@±ÿõâPr„Pk9»¤¾LÒŠÔ±©îcöÍͬëûdÅ:êÒ]aUþq0IðŸ<¢¦Âþo‡…‹)ø{Jz7È\¤cðÏ&„HT¬å[Ê¥97Õ~Ú] >p5v÷ßäƒÔ_¦’Y™7lå6µ5˜©ètâg„÷¸ÕnF_áz)lŒsrîc`º# Œ¿q&0v¢mh"¦Ær)^1_U>½ùóQÉQ«ýsÆñcAð¬Y5'ûoƒ *ù} %J!1–„kÈ1Œ,­G~ẄŸžŠ$7ŠŒž0«ã–ÈÎ]ô´aæY‰N‰5…»u,'º¸yÐ;¶ïÌs³ë½Èþ±[¢u$³¡òî©È¢$KE©‡„˜ß«oìúy¼…Lþ–ÝW—ú³ÚYºð¬6Ë—Ñi…ƒÂ¬pƒ%w=™«XÕpöa¬ƒâ•é¿0ÀÍ $ñ„woEÓ;ö§[–ÃŽ:q¯eÜÄHïñ£Ëø<Šé*”SÃ_÷…ùïêw•£WØn­eí „›à3Éf‰|Œ²4SOHuÈ3¨’îEé&40>ð ?Iw­Z°!ZMD¶. êFPFPqž( ú‡cç;æ£%‹ƒÇ<9ì_‘Yêû’€€ñ°Ä¶BËÊÞ£ÐF¡D/ëÊÆ/íî°ê…ä°ø(;9]àt`Dá&<ƒ’ØkW”]³½]ÎÍjLÍóɈ[ö«+Œ3g³»ˆ®ÉtG\¯[ÖòÕKèÀðå¢4jÑ'Ùæí ü¦H3ŸÂMqHU€0±nÓnV¸%Ÿv9V k-šZ@¶Ê–I*€¤H(A´6Ä:5ëz‹`\cÞÐ|…£’Ø€Ç4›¥+ÀüLçÁõYñbšÙÑ´þ™ã7ÞT}¯ÓðqtÉòšP€2ê·jxÿÕ\éí~ÍÔë˜Ð¿ü(®l±3ÊN=ì©û¼މ™H’‰Uò;ï:Æá%YôÌ;kíQ›F_"@s#¢Ž²ýWܹ\%FRbn‰Ly¥´"ÎéökPæ@3Œ»Ij`¥$ü½Îۇ܄Ä‘5—TÌè6ÛõxÚ@€‘›°c¬Š(¸'¦ñ®ë•ZräCäúÑ(¤KC[Þ+77ÿÊ_Ïí¤2 ß³ièÏ\§˜]¾-.e»ÒNåë’5÷<ð[Ÿ‰ó ó¿‹ÓPMÔtÝ=¢´‘·ó²ÕB˜Ñöús/øu%ÌËß+Lò³¼\îºoŽíþg®È²'…}€Þ¥RÜvâ&Z£÷¡ÌQ/•äÎ}!Ɉù¹Ø‘ü|¯ºålˆî7: ½ã4(Lãó—ÅO¦Ò ¨ß¬ û*¶îŒØt¶@~s¯Úíö†zòJ²T+äp|ã‹5ø®ÅœPíiµÚûª®x4“âB?µ.KqÝF¶©Ð÷"Qõ®¤\µûã#ž64[~žµ3Ùˆ[xWÄ»q~íî1õ  fô•§±$iL8¥—Yü²¿¶‰çx™¿ô6 A1Œ‰)„Á†óD¦Óé¥WbY·¤wĢʭãSpzö)¸ ¼)äÿdÓ2ò™CÀ pmË £ ]d 7\ßÂ;Òfé|€†ÑêÖkÞ8ì¬ûÛR‡V®'i{¤pÖ´CVûmû;yÜøÞÖð3D6ÇTükƒúK¼Ø1053“ØÞok¢i‚ècòò|‡aí{×b½•ê©û ~«5òeZ`º €XÎNQ†ÛóRh \ªøcG%óÀwg¸º[)Û„¦%. ñÝiÏW¬@eÔx’€€Ë)4q\ý•‹áëÇ‹]m›Ziõ"Eª/pÓ `¦]Épfèï^VÉKЗ[f:¹`Ë~mÑë.›uÂ8Œ’mè¨ÍU;÷˜¼Ðsò…¯{çÈoJdþç ñþ=Í,þ8ÇYâ"&ãOñ*žð)KújkÈJÕÖ+À2«FåyÌ«ê€-i6Õ±aL¢š»­™î¼'G’uì5Ž4Tà1ãsEóÎd–_\sg”.†—jÅ‚ƒxº»¬¼fåKÒs)—}|âRÝ+å¼UËåRúÎÔ·HþD!dK°µ‹Y¾l=ìÍ”ÓLzx¸ôö…Ô@â=„ q$uN›a¢?­‘îµÙÆ ñ2ÛÏÈÛSs^´ð_‘Èx]3uýÍbœÁ¾Ê`àÜw\©’@ÌRÄÞÏìµ²êÃ9Àâ°=E×w¿¬11ØxªKi?W19 Ã(eë‹ý<‘ÿ{ópÕH€»UK¦1Û,§µ/)ì00™–J2kn·¦20¬šÀvìÎ쉞8m ­ØX»ìƒ$§Œ¡ÅˆðM×Ý%2J',VD~À-áŠ3ªðZmO}"êß_Yèq^ù‚„Pa·ÊgÍW³Õ¡íbˆžb2Ç>xr!¦= I‚x'ìêjï6·ÉÏè|u³4+_VÕ˜•õ{ò¸½ŠN»ÅSn =šÖLJë§ Ѻ ?éÛ¨ü†4ÞÌgO?<õdºÓ7²,÷Š7Ì/4¸E™»µÙ›ìbúø*ÍA\äiçî"?5S¤\R  ¨€j§Æ˜[gžˆ€N×v\6Ÿ¾¶@K¥$~Ôã4lãµø,ø]怌•½”œö/ÊÖ#n,›—F.Ìâ œ­öÿÄŒ¡Stûg²! ìþÉ”¶ôîÀ"|FSH#Ë£éVæ!yº„`zAʵrX#«9䯭†4;æˆ ng§‡I[Q-®8­·"I*q«oÚ/Ö÷ Ý ÐÖ+yÞK³såëŒ-5¸‘‹_Yôý.&ë.«å¾¢6Ö9æò,‰YT£cC’ª:}™Õòg›IrË„òx.ŸßC÷ZU›ü—5Í'1Ly ÓƒÿNÜcM€%‡Êue¥Õ&Hòk›—qkw‰C©…µP^Œq<„Q²Ó®¿à%aZŒÂ¥ÆÃàË%(fÖ&ìA£’€€±>Óu;ÿ¾’ÄáÎÿðgªž¼~ o7U0KP§hÂ$˜É†i¸yÂw…Mªa!"Øà”¬á¬vk™ÐÇ DÜ€Ãé°éécÍ Ýs´üÂyÔíàzGúáÏ'Ǻ¶ôÿ82³.Ë0@ä>¡ŠÝ ,}ŽmV’Ͷžuö¦b.ƒŽõ Nö<ÚÞÆ=Ä‘·"™HvQ¾îAÒ¦š) ã®ZŽñ3JÄ&ë½?þV·³¸Êõ6b_“Oä²%•b0y …Šï/Il&øD7þÌiÈ´€‡1¢ 옵{th1*¼Ã‰`iC>™ÓiI²í€»3ð2Y¼‚Jå*æe=±šVæʈsÁ•‰I hQ/L5¼TŠYœ¦U–”ô<œ±Rv;m+õ\†vÖÖ¬ÀqTÃt/wH%‰°üi!!š"zMŽ¿Œ“¦°WeI3ï7 $8BU(oðß„"f]æ—,ö£G¨e;¿E>ƒ˜-‚§½XŽãÇ0f5³ÆQ{èÍQH6Lè|Z"ãG-nbJ`@á«yS2}FïFœM¸=ª$;› ZY^<\IÞ…˜æDƒsÚž~FFLª°„xÅùÁLm’ýÿÖ¸ß'G-¹(›|eyÝ÷wB 5J’ “áSIñ§FŽ^ÌJ}TsÄÖðøð韟,P3[õDÝ›ÅX Þ½f«Ã|ÔЙ=³DPÁ8ñÝLJ–¼_}A½1nçñ‚X€Dí¿X9©|§çã:Ю@œÖvhwÐ… @“ákäõ×·ë&ÐT}ÔpÝŽF•Ð⪀O¥c|kÄ@ñ2xK¥´ñJæãfáX8®Q’…Œ õǘóï’@/q¥V )Æßý—œ2Üb-î¶ã‰æÅfNº 7µGY¥žœÑF6„é…¾®«»‹¾2 „—?’6ÄGoÞß2j`’€€‘ÔgXy†pKvÎßÎ,ØŠaç¯<~5%+Tqí5@8daµ’†’ãîsÆYRl$0r‡tN(Û M eh—Ž÷FjEšQáúœ{?”%…•üWfǃ3&:çC¹_T¾E+ßúïe RHF6,ä€f»‚Ô¡GÂY»0e @$}׋Lµm®uÇg NM0}ñÃ-3Ž%]¡,­Mw6?$*aÃ4àlU\OÈ®‰ƒ{20Æ2M9Jæ·!©°ÝÐËrTþ‰ Ï¢—MEÛ'4©>a•3jBa†¦ò±\s‚了*Ÿ¸€û Ýâ’§{Á+€òþ¡öøºÌÇ&jxc¿ÊÏÂàC |º/–Ê ×i›ä9q„å Nø ™2Öìó½”Ò Yžö¶³¤l(Øp‘Gjýç œæR-˜÷"d…—%z|T.ƒ‡?mt¡¾Eñ¿ÙLJ]ÿ¥Û jWŽ(_…¢õ?ì<ض}d}ðEÝ&… ˜ñ'x²Ê}’ç ô0ÓÏ”(ÄA×` º~ÄóHX|G¦¡œ‘(uŽŸžö€[­è· •Šš¹ñ¬7zo6¶µñ&³l×d]HO—§‘¡ ;¢ê4ô 5k×dJ…üx¥~Ùz»ßBqx2z8rv÷IØX ëdD:Xëk¦¥š ÂÂa2 [¦Î|7’¹èÉ `™V›‚ºÈ Kp±a¢äÑYHbíEu³ôñ£pÝA®Ê ÅüX âí8ÝFZêt!δZ~b êÆ ž¤x¤ÓCH[d3þ‹F#Œ#*¶'´§pöapô‘FZ_…[¶é>QVa͉%{À'«*ú@ uàrp$ÝòN=F½%ƒ4G .SÆ‘.ó†DŒ1ô<ˆ‚Ã~¶æ¸Wkצ8§_NRãðÞM›œö›îŠÒ­•qšˆv;Î{Göýÿ['#Aï ßæŽmÖÈ$u©ÒÀûĈÌVëÜ9`ÚŠÏKÂq+¾†%1NŸ°¾ch¶ œ®ÕE `¬PSâ¬~õý0¹#1¡óz|úI\öÈ$˜\`Ié5Ðr¬ùéU¥Àû:3_ë×¾Ã6HÛp·3ƈ-ÒçtÒ=Ý›öŠ%ºÃ&Çv²²7Èì"­.é iŸ{Æ]},Ñ-T¾%}lÄ-}pÃ#À¡ ½’€€ºTŠG·¿Ì ; ·^’»>@,ÂW5¯!ÌÇÒ¼žÏ“ÓðUg~zdUnê²ê^ÜuÖ(ÏEU<ù7È·ž¨Ía2 €¹Â—(Ѳ82#‚ëB'·«SîÚh½G²8sî†]#7ým8nhL²kàsh>o÷õ~²¶é$ Ëd·ì}!Ý(3æDŒL©hÂLœ®)Ÿ*X»å,Èÿ3ó–vð<‹#ÅG®Çz·†c¢k5éesb#ÿš„TB†Ä9_£¹aAùQã“ßóö †6FNh}Þ Å"¶[BP¿½m2Á™ê$É<°kîGÈ’3Eåmؘ«}dWä/"©p ËS'ÉðØ>l$®3îÂËGZ#\~.XNƦ㚜kÈÍ!w0ÐmpWUpÁQ6È€ËD݃ÝH©ZýùUjþâM#ɤ¡* ™Þ,)ºµtmݡ †”$‚âšUe#ëÇ_Ü2ƒ¶r ÀÍ@ƒ.4'¬ýb’ÓÁæŽ}n´ƒ Û+ˆQð˜S£’Np!ý·l³Bû™­±ëzz,á[¼ªËÒ–›ß‘G¹iÄz¸‚êLÌå½—*¸SaÃDFìXBÓ̦¶^ʆrßö¶©üÂà÷1_ûsÊ'ÚivU žB¾ÉÏÁ´_öü£æä…z1àæ(Ÿ~ 3i9áZ@±OÌŠ[Å‘.è¼vg癋6 è4»“u܇=Pø[LÇìµKbÍôå:¥=oï­¦R£zhD;ÞW¸ŒKfýj<„áŒôqs}K[¦Jô¢-€¥&9Ùdóñùé‚@¾k–5P6°ö‘+> Ö®‡Y¼¿¥ Gr&«Y³¸Èé—mÓyàßîŒj´ã"æØO»¤vç³´F!n‘¯µ#T zH‹ô¹…ÜAëX’kWïÒ™óVé¿à¥Ÿð›!î½#V™'”¢I¸ôýS™ˆS.ÛÒãC>ÍJG[‡+‡ ƒ*üÓ*YÅ«¦f=4({ ž­ÒBã,Ÿ”cZÐa ­ÌÃLïŸ=EÐp!.XÜÏröù­Vkx̦€&}S&1Þt¨ÒJp”PY_ìm²›5Œ¢‚ƒ²î9ôŸ>€šÔÆ5Nffšó³·èË>¬è§€XY×Û$ì'ÔIJ+.£¡„ =Öÿîÿsw ;`’;/$ÒÐå¯Ð/DÜ’!’€€Ð$wý?ࡈ†(û:}±3´{ÆJÝ“»u"w565õØ/XXÑÑÃÅI‡.Ýdß+»Šª>#ðÜÎdºÜþ ÎPñËRâêåhϺ&ªÕi¦Íh@~Ò¾°‹~Áóôè自ÖЬ߾¿ÓMf‰¬BbÂ÷ˆL‡[yËÝu­z*mÚUA¡/h¬ ƒªh8Lø™=Woæ¼zørp&Ælå†!¸Mœ%ÔçÔé¨}ûà2ü˜^´S[pÓùŒË5;ÖvEÊa`x$Þ—Š&h·ŒµºWê+tS¯\f‚8ÉæÜ(6³Çœ!%ojö:OÕv);t¨]˜“zY -â+8IœöJŒîë¤ÇXÛ…š‡÷¢²‹ƒÿHÖ†kËÚ*ëE”ç5À±ô©,ÏãUÅx惡–Hyj‡€×¯öˆo:H°ó¿ VD€Ç-7Ñ­³<ñÖìࡘÈíÖöA§¾Ž¬Pê6žBø§~pMûľ—ÈɼÚY'€Wçn"µéb¶áKËVBBácŸ5NJ÷ Ý CÓ}LÝ‘³“`¡š˜üÎŒb9ðÌ f‹8Jñm^kÈGí¾Ü¦)Ô+wÿL̽ôdD/ÕéÛ_¸À¨PQßí°Ű¡ÔÒD»ìʽÏÉt[×4þ›ùþ@V¶Yèù.Y5®‹ÁkQÅïâ:+Õ|Ù'CKÎ!®µ Ò®¨07‘À³|†ÇÚbÔ¨ÎKEL¦³v™òlPïɰT ÷½­C·[eš,Í05 „Ÿœ\ïf g¦:ƒðÓÄe+‘8£%gàœàý;¯Ñë`Èrœ£±õ)úV!ÊX$W–¦Þ RtÛùà„&1¨éò(ÔSN=$)ûKÌÊgj^d'©]ˆ,¾2¥¦žˆ©F‚b•ÿO O§Zf®]¥k”à•ÿÆ‹å –`²*ÒÕ!Æ×ÏÖGNå<Ù5(”ØM ÌùÍ·s†IAÝ+™]²£§?±³b=‰¶rg(ÑJu"t»ì¨ë˜IDŸ²‰è0ò1ÑZºÔ‰3¬Ó<‹<R^F@KØOmÇ$ÄM—AÜzm0†mÌ0•îû‡‡lYÐxVsôyþ;3„Ó£‹P¥¶ˆ<]¹à¨ˆ!ö¢°VÉwÅ^žèÂ.ðâÁÄãô:çk¶KŦ{ïøžK_ˆ¨Ù b’€€Èýñ^’u¨ÅÚUV]-¹¥­q<î$Xä©B,ƒùbžnõ{ËÁmÚ²»†8ÀG-íß1àQthÛ;¢D 3u`Ý®•%;Pí¦îžÓ·†¼0PH™^ *$$éå¡Ë˜°Òu€?UÝ6¸á0åêr˜¦ÑqE>ÒÕäë¥úê£{)#|’çWŒ£ðᜃœiRÞ·@é Ÿë€º*K—mùU_±Ï 7b ¼¯‘pßjô_ðD[üú:l:ÈÕ3Áó)»cVƒëA*+­u»rÆo—™gð•Yw0šˆQ‘Ì-à²Q³‚â=®ïoŸc ìFjŒL·õ¸ \&/ì]¡û”t¤ž¹Êp•x«²/ÚD¨•¸æ%L•,RR7œ[ ÆÅf÷§¾HX]t³Ç•ž?N0è4s…á4§  l”"ÉÓšHÅ DÐ%¬(Sç{H€¦T¿ Y¢ÙßÅãœÊÛa›z··6z¸f¸/–leÛrYú€¡[ñ™ì>gñÐZ”½£ø@XíÓ¿ŒV_ø²'‰:8l޹u“i®U•Y…§ ªå¿ÐÖôË?ARÔú?~®'ø ¼ùÓ©)Öý‹áQ)YàKP+èŸþ¬ro²»’­±›ó=lÆe"+Ö8襗·³F;{ãZijÂé´o’' )ýâ ,jgÜ÷$7Vû”µRë 8=fÀé9Ak3\—©ùrÞÕN1šu:zö •ßߤ›²c·2^ÞÐìˆYb)üV¥2’UO+!d¨Ü’€€ÀÏ]kMTÅÉ‹ùη¾ùÀ.㊞ósá&Ý]+ÛÛÛE’/=E\oÀŽq•pué¢ÉîƒÐ"XHÕºów%;· £Ek…ö.4iU?Ý9-O‘¶s9ï.£~Òª ŒɃ­\fºðir¢úÉ|ö‘d>öREç“ÞA´jÜÅÈî7°ž6ÞK[gß_˜yzu:|h©zïÈY‚^,Ò­¦ÕG:€´QÀ]!8,-¡Šx•,9ú`x*uôUæz—šy\ãJGÞ ®Ù×ÖpÕÜ—ƒ¯>zÏÝðÅ,‘èYwá<1•)'û3ÍMt¿÷40®( M˜é`Ðm>Ÿ›áØìNí‹âۙ퀜:`IBPÇ,pþ~¡R. QuŸžHŸ#**-Š-YÜ®u葨á×x¤=éAŸL†¾Õÿ ¤ …&O—Vóƒê*öP:œo|߉Ia›Öƒƒe€òëqÕ(|×i®_3Ó‡1šŒè÷Û ;¹Ù ÌVr àÃÇXv± wðäÓ2Y8£Ë’-!cLô¬z-âwz'ÿ ãR§ÚZí è ›±~fà¥7ý=8&ÎÒÇX²GÆW¡j_øùD—r×7["NU[éF™±•qúd—ìÔ]î”/úý!¤v؇7¦­3¨ ŽÌ†¥'êòÆõ¬žUÙnˆËn‚‡´òj$ÃU_±yõ†[ËL†ª6|‡ªu'Q ³Ìnp&–k6ïVŠøX, ˜ÝñœM¥ÎŠg^s.Π!Qf‹òŠÎÕ¬=±›?4ö«ºÏ ñÈÛ޹F|IÔ,_u-³È/«gœc®G¨Avüü¶¾HãÊø6y´±oòE9Åéw\ø›É @@€Õ𰝩åcpD×ëùÒÓ„°žE¹…øƒ‰ÓuR°´ŠuRtŒâ‚ü‡ô˜WxSå wÌïmRa¢äJ°«%nLTîb­/ÃLÕž`²œ\«p%I‹¢E1RIˆìMmúäW7àÈ=4;Î$}ãÛµ¨à.Î : ÆR«ôDмYù‡ §-O"Ó–CÅ€öé°íåŽTª×¾,ÕC߆²QÁñÇašÅí°äðS’±Ëup6áJB­rîáò7}c,@†æÜ.!׆/mug5߸t£½¬oiÓ?𓃚G{X >_wÈ™!KB‚Pq’€€˜ë-VÄÅ÷}ˆSN-rñ#)§*cÕHª’ÞJàƒ×Qž„KüSƒ„ ¼W¡HáíñA¿¤1YTj£^ÔX„÷ßúƒ1º½ƒ±Ñ„oKλò ®ä÷vÕ­;úm0äkÅ㽌q®¢d" ç™0ÎýP¼äÀ wÓŒá~m“°¿uz4ÿ@¯õZ™Wœ‘~D06:Ù5ôVL籌ÀØ­ð g+ c‰xª‡Ê`ŠôÆÎAˆ ü1äbl¨H ÛÞ%«åÚ]}{Uõ$’ó«ê¡§²4kutGŤõhâ«‚“L\Ø×VâÏf™Æ?ÀÇ=MᕤóÚð—ÁW%Ï®Ÿdƹ ÞÙÁ‚7N¦5WŒhÍ»¤ç;ù Ö¡&0£"ÏÄGµ‰ôˆ¸1ê’wÏÐj+3W½¶Öwl3¢~¹S[‰ ®µËý QÖͯú§Ê3ÿº+Cá:ãGmÏ”$°wc–ÞC·­\[? Ïr^šM—À[¨ÄhwõMœ5b©îq!Æ©^¯N؃2Ѷ[:9ªÆå2Ù qɾº±šGÃLÿîÁ[æjN*SîîZðÄÚªM÷;!·‰køG66ù ÂbÕ\Žë]YQHuÞã¿ÄVqêð¸pþI‚cÆ8¬›b^~;†ÙzrÓO}$u[ÁA¢£D'éDõ6ݸÐÂÙ7lUᢪw壥czÛ¦³[ I‰s£‚[Áàèz|ûò ZýŸhê¯ÃRcâlŒ¾˜ÆY­ÝÃêi7ò€kçùx†ž,ÅóPÌv®ÿ0¹»iýLÁ¹!ÀQ帲"áË'<Ý’€€â2õŽÔG}‘¿e_½ lðËϱå Øû€ÙóS¹«†ôžÙžn³1&­oÛEÇpçŒ>obì™®ÔK^P«ˆ•²GÉ4Y\‹»ØÐÛ3­)]OSÁê73$5ó]BÔ’!Èçû˜HêÌžsx9ÉÚ"JÊâø÷Q߆V>G*—0 4MbÎvu¤B±)J ¥;0ñZ󸫧ã®$6M¦ˆÙ–6l!Y W_péo;œWoøx‘ŠÙ¤å¶Ф&V?6rükìÌ_cKà)öü‡Ä^[Úz÷g=õç†çÏö݈Ú,Õn^‘aG›AqJ®¨ÛV °†šw¬ogßE½6«Æ•Êw£9Y<Óѯ5¹È¹ÊÔë#Ò^ÎWµ8˜.FT’—ÿÜxr\’‚U)`8÷JñA| Ï®%Î9ÿo‘aÌ,"}o~ÒæAêÃaZL¹gÿl@1…]è¢G„´eði‘½E¤À-Z„‡=¯­ý>ÄŠDòëwÍIôÐiÑ0ûÜ„á04ñʪßñeÐC‡éÈ’£8ŽmFÙwÙ7$VMãó~Æèíƒ ;ä±I‰41p”¹ÐM)7å•uÄ7 "S·fÔïÙßðó â ŠGâ-ÏD ]æ,¦_›-zr¨ˆ%Tl¡ý–¸WRÈPZ¹A)@ØMίôMOnÐÞþ\+è¼´Ê&Q¯6#ÓQõ4KL†¢-{Ì£D;`L©ºÜ™q¹Ð^/®…ñ2©ëWžêáh.Æ#hf@½OËL.ñuïÎ-ÂÝ„œ÷霌†ßC*–9²jB÷Úÿ>Œî,톎®+¡äZ6²pë©Wî7m?ÕWöDÀˆNE"Wì¤bo„‡¦1ÃÕ‘<ÚÞÎI:¯a!šà:8âxnwm؆6vxÅ,s~“wÕ}=rhµ¿ÁÜC‚!7ÆJÜŠ¨ª(=ywˆ¶fgcÀÒ¾‹RbV°àÏvo‡YBaK@Ã׿yç²íÞ¡4—N‰Ëåf"¿ÃFÏqvA|ÙÒ!à”û®Æß 5šÜ&°Ýøí$ D†³Ð6ÔÔ.úÙä Ÿþuìq C;€›ú¨š:UˆÅr–Pæ@ 5’CC_I»³FLW­#ÌÜ]Â2lë+åh ñKú”ý™°›Ò®¨kE_²ƒ’€€ÎE^ýÞ{¢ÖÉî±3ÿià¢ôP•¥Ål#í¸èà‚s”Š[]Ó³‹óJñ÷9=Ën²:ñÑjm˜:^û#Àe‡hüê‚à”¸ŽMŽ£bk֖Τ 1ÈùoŽwPl ÚáŒ6Ä6ºŽpZxÁéN¯ÈÒ1'§ØE§ó“ïr%óY˜þ“ê&B  ¦àwB®üç˜ï!§4‹—‘+‰î!ü3Ù*ö˜øºÿ)0ƒ°)Šîqf¿8.}LJHk4>³,448vHIÇŸ é.|Í hH­bNÙ=Zz<Ⱦ‘˜Š¬Kl¹ßX;üÖE‹OÔ&íú”»Cö¶‹)ϼêi¹³b¼» àðõA°QP fúöö«¯T MO»R#„9ˆ${Ï-6Åsû¹Ð±cg"":–âQŒ‡Î{rª¤‚3í"¸Âí– §‘9å;:%Bn•ĕ؂œ7«„Ð6+b6ð›Ø@däúøû¢¤Wn¶×y #5—ømiZ?h¶tð/ãT(—}#ÝôF –€«¨`ôø0YgÚBë90÷nÚ~$/4@×åøŸQ$DA†·¬@‡ÃÅ…J]ä\íí>ªõ˜È–)/æ=MØA‹½ß¯Ód;¿^ [`Ζ±í<îyx'9ÖeøIX¦2ȹgÆ(5skã³?ËgÅøúåu!ˆAιá]ï8mÚ…Áî*lCšMˆ[ÜCÈœµ}“ðF»Š2 Áþ,£CíÉþËvD¿v¸j®Øê¡Ëí|t‰¶Çæ#Q›tÂKëëo$ZŸM´™xÝäçÞ¶“-’<Ÿ^ÐÌããøƒ¸­56IUµûÎ}s°{i¤™ˆHbèëN³•O¯¬VgHÍ G ]aöAW'ƒqû‚©hÅb4HÅXë´$Ô¥ªJôŽô$‘"¥^íê–‹U®ÉgïÉar¤:Ìb¶Kñý÷¶.ºÍ.eÒÓné^#·•5úÁkÌ tøúîKj"¦sS MºÆ“ëÝÚL–˜^ÍÈdŒÆÙŒ½u 2Oúq"QgPÄu°³KnÀNßbÖew)dË(¶Cˆc_„æRé@Úë¥.DMA ²Õ~f»^ÕDÕîl.6@Ø£ƒö™”‚ì#Ú~Š¡sß—rÇoxfR̲‚ˆÈ/ú˜&¹ ¶VBŽãÒ0Zk"«€Aóä¿Õ[š' ñà+L¦Yâ¹ÏÙO#"z?üñÇ’ˆžy/GYÐÕP àGDIÉå‚iù~6ôSçñÙ«ïJ(ñO=Ny#: Ü,ÒÌY~æ¼óÏ$ßñ’®.zN±T9ˆ 2`ÆÅÕôeÏYL¿!*j)xçç $0?Y|­& ”ÖsKFÑ×Næ.[䂎ã„äôï&týÁMíöÓÌÿf7º¶%Úã ÍFÕ½V×ǹËT*‹–ŸRyÊxõ%DìP¥AKŸ‘ø¡·9úÁ•,?YD‡Ú` :®Êd6À;#˜Û4_“ú´ ä_S…ÓØ~¬‚·I éÍø½¶üí'ÅVÖkÙÞ);ÅXÙ÷ Ê|-ô†"ÎÉ÷¦} ÆÏ©r´³ìðógmga15/tlúCÚk[›Æ‹+0H6Ç6ãútúA+©Ü‘'øÂã—|ÖÄõ§ÉÖíqh ÀqU«æ|[^ˆt.¢ëÁ_%€­£Žš“…û%úEWfWÑÍÚ=¼v¼¥æOíÚÐsÕîpq‡·¡*îU-[Qì0ØWkÞ•”iþ}©¸Á1½ó©zJ)"×§/vª2vs*ô)Á›{öà )pù~D:TM÷aBÖK-A>ƒe* ÷J:eº©/¶—Ð+CC?’€€ðGÁr¯_ccZ_Oð !6m‡§Dš6]àVõOTSªÒâ‰[¨k/ù|¤2`–ÖÝTd"ŠhôAEû«`â®I5l°ÂF±ÎȾîÓí ½hÞN´–¨uó ìÞ~9YÃNv<jpKÖãÌb(pËvAœTYmà¦ó4.´©çÐè6¹¸‰'F½?Ê‘3¬g¡-ø€7pЉ}U–ŠÒgÀ·‘¹Ú?îyñ½”u±P™Cö ë¥$ðµ¾µ¦¡3áÀôa¬_‚ÒþJb~<ç¸Ó|¤@K`|¥ &¤;­ÉÎûuì;ëÜòì-Î}("ÿ×_ë¥ú’`ly7²£,×V'YˆZHX™E·N·‚žÅë¨TˆaÂÈÑ?ïïßÐ7S&š”ë¸[Í1•Éqª«ÓþÂu~ãèTÊe¼n›å{‰‰Ê¢ž·í§û¤¸¬Åu4zG”ªë2`<-Š  4jKßf}w–¡© E"r³r¹“¼¯ê5Gzeu¤ŽcÝS°Ä9d¹aZFIzÁâ[Ó׳ßüàËÉùÑSYJ‹ü}Y½£mG&ߎŒÊW²Øti¶ÛëÚ)r¾U Éèˆ& ,¸N•³z;¨E’à|áO7ìKOQÐη—† ¦Ym„¾úÕ`/eŽÛIü?‹§…ƒ&Ȩ•ùÈr×0ïM–Â~ôeNÍÑ‹ÎS0¤=Ÿµ iJèÀ¶:*¨yk2O™À%nšfÀý‰ ´þ¹y¤ ½×ß'˜9žY1¯IJsŸi}nPÊXƒh A)Q–ýâU»ÖïÙÜ öp‰:Á¼"Êz°¨MTGf©ÓÝõ+.->õ~ûe­uö 1‚,¿Êó”0ì©qŽ¯Ý¼=Àæ uìµX]„Ìrïù(*ównTå…LÐ’s Hf÷‹&¨çÙWÝDL®ãðü‡î_ HšT”Ä¢†œlÐÌ qýãh›<<äÄû?âhýÛ2ŸxF¬0ѯFTR<¸€Ëd·GÓ"Xú)ݺ±œÛs'= ®s’fS¼–€ vë7à'Ó_úW&°X9ˆëŸƒ¦K;Ц.ró|öåeöƒ?¤&1”ùD„zÑbËêÆH>*5ÅQ€‡×¬„Š}Ä5í¢Gö5‡ßwJlŠïGÂ!OýÒÉŒ ¯ á\”Õó’€€ÈKX[ç`ßEfkgÔÁv2p­’+è%NžÝ Ÿ½)ºGçß™ˆÌ)ñ{÷uR9ªUàBø‚‰¸IÓàx³8»“.ˆNâ«Z^Èá]úB*pv¤ÏÜ_/£aÔ$lùÛù‰HÌu«¬Ñ·­ãR©#‡õAcãN‰–Ìz€Æâ^VÚÏ¿ˆYÝÖ>ùºok|×ÃþÙ ã)–üLˆ*H¾}TëÖ …G)¡eõ†Héwã!Uc÷ˆJ®NŸ}á¨ÔJwõTõ"w4h"íþLvw»‡P ÎòO±eÿ~b…ºÎÍÎeƒšç´¬1Ö·œšØÊù™+±?µƒ`kY+Ó±¤¡'¸yâ‚øvyŠ”]l/È¢mõÕn[ç:ýþ”NšKj³ÖËðw’5;Ëi;ïqâûLN<–‹Ì?ãĉ]1GÄ–îþ¨æÜ¯k~‰«®,¶•Ù7¸îxïÞÆ3`A—Öƒ[®u{œçüyêZþ[â}}E.¥ô"àækxR¿$Öɳ‹ÐGeTÅ_¯4DBþü[÷ƒNCï9 ©õ9êb„ÙäÆyÿRgëÔ|¨vž%ÞSq1V‹{i€Ê`袶£PC—ÉKÇ)}ndÎ\Q·ø¬ôsÒ\&ïšÇ“À峚D¤Ô[—yyÜ ,™8ªøR¶>Cò,•!E67'¼ ãïš°&ª Å›šHl4вŽPK×$i$¢ŒP!- Ú ¾1ï¦h$„¡×Aj[ß§†í» xU¥70“Åÿ±ßÃf+±¨qñ3¨o´3坬އà-4Ox¹g0ç §¼’€€½|[^àH§ÛÑtÍJu¼W,>3 pP‘ E‚ÈK$kŠÆý€C7­œž³„fÄYù¬ÌY•I6Óy}eµþBеªb 4”õä$Ÿã“ äAΓ¦JÌøæÕ‡AÃåûUÙתåþ•=+xf#Vo*ïLOÆñÐé÷®fO¥TìØ±rõ~:¡åøuÁGü3ÊŒ‘i*¾Ëh˜»àj9¼nxï¿ãàÁH« ¾×æ÷’( ãa¥\íâÿ,1t÷§ÓéíõÝcî“,Æ>Ý.VTy#¯ 6Gókë'ÌÞ/E¦•:”¤8pu½^ɧ³å»º·«xÏÆÉÃjû$qv00W`;õjÓaÇö7RÕLjðà³(®YÛCýTÅÿ‚;ê˜U°1$6^¾”•Rß ›{u (žBðÇõB†úž1ƒþi¥oCíîX€)š{^´ì5Q•@ÅëBÊæŠœz“z§ï©< ªaw[~šE „·æ„l*¥àÅû}Jéëɽaø$~ÛBR¼®ðëâ7,ëôýv\žæö†)1ñªVÈEšR ½ðäÂaz²ÞžIõk_æUwzu®È±ŒO †Lš©wÆ– «]—Ê2‰¨;Úä’qž:¾TžÌ÷êòE pˆka|3¨MÙŒK¥zŸ9WÏyowš…h%í9·¬7~ `ñÅ$ü(ÅâfQtÆB’ѽÍs÷Jøïã!«׋L¼ÓÖ•ÔÛë—˜q¨A^M[,øAòÆ3¹SØdfçè\ö­Årw,î(f€.Ÿ6$»žÞË`oZˆ ÉN*zßi/ÇŸ‹a¥Þ»Ø:ÂÎ3q„-tj*ææL Ý•·Ü™tAƒØR ‡0•ž©;‡1UóîÿZOI –{ÇT:ãOÎxÐø®t8zj&ÎsÚš¬zc«QPÜõÅÿ’€€£”Xñä&30õ¢TFYìja‹é‰ëpµÌ,§ëseG îzA ŽÙñYÏ,W;Žâ7€¢ÇiUî9®çÌWľ:ÆMØ÷ÉÝIêxŠL6‰8‘Oýñ1å …-]¢‹<1SТÙ3é¨&óÔÛ)9¹,”MŽŸ¢möùò¹|s&d*é X{\j_^‘-`<­1¢eÐ+èö HÛ¬3ÍÉɶd¿YGÔ#"ÜØ|™ÇÙaUËxûÊûC)ÂÞæ ¾ÜÈ<˜©EOd^]–YiÏ+?hk@¦JGô—"sVï›ÐÛÙºoËe-Gô¿Ž2H?³=*y‰ˆIBEÏ{¯HVÖ‡ìSQŽ?Œ©+%Ü…CGü}oˆñníçØO Œ)vhFØ$ä΋ë0e˜ÙÌ¿Ío<Ãò±;bšåI÷VÿÓ†¸[³GPÇ}Ù,@¿ 4ãÚ~¦“Ï â#ȵÂõCÜMeœÒ¶³ åQ î°è¹5ÒF À$¹yÜ©‚¿rN&/ˆÆ†Ý|ç1C{ÆU§›1pÝa€ Ø®à›ø þŒoF•œén¡ŸúT™ÈøÓ¶+þñQ¦€fn{M0e$O·&Ü)W§@š‚Õž´Ë·:h·hú4Χù_µ¼“}^Õòt 5d°0íQ»IÐ7†¹¡¹Šj œ¿–HÝÓÍÏõÅ$_Z£šh Í*ËýÁ>na+0*†·é¤Ž3í®¨œä™B×Çt‘hXÿ©ð#ž»&Ut>{|Ä­ùf ð ÜeÙo!zO‚É(IÀ-b"Rì?ïÝÛ€ ^â& Î—"³ ùüiüíÉQ£w¸<;ju〕=Ý?dî_«˜bw»ú£› 󬕓0_&*•‹Ôô6ŨžòÞóM#…c­÷saèn…üvO!übnþµ|Ћ¸âRÂXsÐÏpç[a¾É‘þ”3BA¸XŠù¯‚±TÖµˆw|N­E¨?žú!p©MÈx%Œ¤v0€¢& Ú…Q¿mµaB¶8Gì’ ,x¶~ÉšüIÚeÄnò5 ²Ž,.n”td€_Íû³ê•]¥5;ŸßvÙÜ5Ð @4¬á«ßjŽqÍ;¨Þû“áclj±^©Æ’t¶ä›ÚKBv°ú<Ìîºü²àf Ðì’€€Â¥ìP, Æ,Á8w.Q„#{òÕr ?ÄÜlfx‚ÕX‚ŠÐ ÜQC2BÇÜ9 ߺT–:•U2 {='ü:È#Ÿ˜€Üb0˜ƒÚå|üy!w/О½Þ NTA/a Ð?´: ºÊ WV\’‘¢h°>ŽÁŸÀWTp ÊŠN†Eœøîö“à°Ù†?µÛñ/€‹«=Ëýîê4ºE‹5Ö }#ŠÿH‹Ÿðžˆ HtRæc‡€º””ò®.McŸÛŠMïøjî§yÎväpáf‡Ò^_ª¦-µ˜enoªA¥Õº*ØÇ !Ké(`=ÓÞWlƒ&ÓX7ÈÛE¦ëˆÆo»…ÑæPñú’–&ýúÂÇÙ÷9‘ï„%KɺoAáÔc"5p¡ËtŽ‚&‚Cûóêßs{LùMè_‘!Âõê@£Ÿkv¨ºÌK06‡S‡?E~N3—ñ;á} hõ`äqÝoÊ~‚»Â@§BTê~·,0ŽvyZ5Œ’“>ICÕý÷Íë!b`Ί·¨·ŒûÜAJu«Æõ†Cè>=@Æ,þDªf¸ú­z?<—Ω¤M_b3'¥¦G¶sØ6«u›È#î}ñ¢Ù¬Õ§ZñÁ2¿/É0¸Ú.a5Bžî8E{K¥å#X¤Ír>6KIò·?ý¥K~ÆY覑«ŠIŒøµûgøÆþM$Ñ†ß ¢GJ³(<^:¦aɉæ—*Tô¤u½p¹Ðù°¶²@,^»ú6Ì»6=ƒ'¯ÀGÝx’šÏ´Ï¿Ù%)í÷*¸MåYÛþVü'CÎÆãÔÒÔÄç7†€¸2úü_†imÍM/i¦7É¢#aÓçÂsc\­=•1þí|ÞD娅¡…¸b¼áÿa§ª”(ùΚ¦­×X¾ä4—èK¼Þa# [SØàÑ >,´I‡– z¸$ë)²'Èmš1“¯¢ûา²™Ë7µ{°D7øCÃß¹š;–`< Ì´šF½ã,–Žf®²Ù7¾›ñ¢æ ÉI¨Gsã;m¡6öÔ# Îמ…ÍRr5K•^Æ¢‚Ù>ì+âë¿'ëwî¤êå§«lçÁOý  8¡-‡þ{¶ƒ‚ë•Ј¯ Çc½ŽüÁÊ ä `…ò3Es%D u¶ÇgçŽ" 1ù‘'Ëì•/µ‘ÚmžD”i?~0m%û4ú!3ʈV#¯’•Š?|6#&‘x.שР”²“ÔÄ2@¨ÄĬ!þ’‡ÿOl z‘À!IÆam:Q™%=*÷“tÇ•@øS²åËÔîa Oä5æjüb2‚IE'ŧŸÍ»›Ñ6‚k¬. $p‡6¾Ûln̸Øn·/è¥U¯Úàáaà²<´,ƒ¾¨3ôñR#¬ƒ#ùYˆ8n§]p¢•{~1h‡ÖoÀ{ÿJgýÍ÷Ï4Ë è³¡~lû=Y,¬ÌÈß]¢°¯CI+ÕÝ”f{œ3§Øx¤%¬U–=aÉ<‹P`%Gr NÙþ`*µójGPÚÀþ§*fù Ñ"Î7=ªŠPñ3p¯ƒÓåÌâà.qßĆq¿-а™â’@‡G*¡ýÖ6NÁ¨ft‡ù'÷Æ WóýzyG½ PÇy¤±<|â°$—ˆZRp”ÏP€x’g¥iͼÁ …Ë¿q’ï° Ir$5Z¥§ù¡²VÔæ3¬ËZ?è:µ7¦~½[^< ±tcsä\÷ÐÙ¼üýȺ/6úvàýcs¶Õ2.$à,è ZEÈá7=z$CâhŸ©\e’/ Æëï}ïÑsó·&‹Gîr…/ÀD‹ØÐÝa2Ýšê ®ƒÝýáó †$Fêq™üO@ûÕMßæŠˆ$-&uq Ÿ˜§áX|ì­|›ˆfÊmr6™_8WÑ’€€÷𨻣è馦åc7ÍsºÓèFhu)}eôóì$²ÿºj7«!™™QɃ£[:Ø‘¨`äir­[|y\?ÕñÎ?z²rKæÑÚ‚œ?Q±Èyr!˜x* õ[Ö)Ì©âÈéb\غx¥®gx…¹ˆ·WÁ±"¿{5]Ä2r”ÆB^/EÏŽe@²­M‡ O ¿ÿ1¡¨†€âÀ `£Jý7(ÞÁë{^B>J:å Úè]¸ÿ‘è.ÂÁif_®TéÜ,] 3q¢¯ÐC£b Z(2—Ø¡É6<¥ÒÊ[A;_q¶² qÊì|_ÂÜo¹Ãá.$–ÆsÙõqE¾ª­y¹Íò¼@ ûfò:gÛíÆ‘ŠºÔ/­é€u‰½NËïÚw3Ì.b>µ†ö‚¡d²‰¨¼þŠðÁ €/,²zŒO~cwª×G‡M8 õJn”¸wÆËMÀšîþø± ¦@Ü„ކ8æ±/PóUrޝC榪ÁIõué»m7ù¤Tlž Ÿ¹ÃùÿD¨rÇ4Ò‡àæëØ:€ðHAÍ›î¹&eEºù I,'þ­C¾p¶ø…^k|J”åá`ý‹l¦Îªb´1ä¼'S0'üè3D¿ Ž¶n\µâ^ZÔ¯êH[¸]P|ÉUK,b/áô FqAüu‰TÉþ¢ ™‰4à\WOÿ’“Qb4(³Rzåç ¹–aaËáÎ1uv—B‘Äõp!2*¶2x ™¼ªÏQ°~íDö×͸·@Ûªë€Ñe½#êrŸúS[¡Aq2ç8àÕ§ï”ù°;\‚FÑ$´¸ç(ëN«‹r-4Aûáz¶@ÙûLÓƒÛI4)ÎýßP,$e¨ûÚŸñD„…¸Ö u ([Êì¼+MÅR7;†Ìä‰SV—HÖšËsK¶YLNŒž5—r2¯*•Oj­A…}„?jðƒB(vR°‘eÜÍõ¥Ã…‚Ț¨.)u(‚1â¨ÓÎÂ6ȳÙ!ó~nà™V‚Ûàqê럖´c2×à‹Íž‰K éÌ!zFò¢Ô@Fô`x? KÏÜá9ño>e?ãÙ$‘ÈÍ`b$@æxrc0ŸB¤W6Eµ˜-#|Â)?#.ÆøéšÜIÎù#~,þà,¼Qx‹ ÙÓé2㤷­0m½ ât#–ÎHoÞ 1I?ôw¾É€ÐnlU“Êyó‘þ:©-Ù‘"*S¤¥`¸˜hRW%iâÌÏXùòÛFbY°i•ж=!éE8…h)%@ºÝ”y}ìƒIÎ=‹%ÍϯU¤–/7>ì¤]%¡`(­µŒ@)á"sÏLÕÖ!À8À ¾Ê#úað3¥§¢ÿFv’ ³ZBÐÌú}áö]N„Ðñì•Àò ÍÍY²Ãfº=0ÐmIY„É´Õ¯¯ÚÚ16fœ¤ä“²jeüg¢Ü4G•<Ò¾ÝdxPÁhÕf<ŽFÆ–€ÉCÐÌd$Ú½ºI‘æ ›ÎVÛl» ‹òªÀr¢„NÖÍÀ(¾¡(Ð_5*˜†÷¢þfÌrÓnwdMƒ ¤÷ëotÏëÎJuÐH´Ç•Û  LÛ÷ÂÀÈ™×6A†_JʶÝ- e%UÔýQáŸëI€yÉ¢ˆÙË‹*®´=^eí˜zv™ÇÓ&bÓ¿íbgo©ˆÃâÄ™Y®îÛÆÍ4ø!þ Üíݹ¡,2PB‹z¦ «êx¾%€ˆ!5EU5R°ç¤(R°j•õ®¹‰.l‰hÄv±ªèÁu†0z×ßj9·»³±²Oì<‰ß>–íj`xOOP!4u‰ÓlMZèºÅÍá¯xïuRݨèùFõÁêà)*r>‘!õ¦´ž‘·l*ܘÅ@¿w=$ ã`ÁY³Œ:¿Í?ÚïN¾[+P—o(›oDbI¿oƒðêm‹ÌUyúx¤*5 œ°ˆ#£uÿt_ ÜŠHõ1žkñ~} ­ÃJN²³@’€€¥L)[+;ùF ¶¯«°½lBÃÐØÈ8“ãåZ˜ŸÔ§}ãð•óiN¥{_£§®³ãuDe2牸;2‹—X ˆè\ iqdõ1% »RJp¿•™/|Ó€ƒ›{„™‹]Àuÿþ!÷]GÚå¥ÿõ.œâk”òôܘóê#¼¶áÙÎ_@RŒD+iBG‹ßî— “–ÇÍåÍòæøŒù‹?œåØÔˆHgÐ2a€nFÞ6\ê±Ñ–(«n8ªç¾[;¼©Ýõ-³F #ћǵÎbpžà¶+»SÝ2€ØI¿ÍÖuò!>ô ÜVê/!J¯–ê:ŽR¹vr&x³«í3"Òüð/¹‡kP=“Ï¡-êeå'ª‚êE(œ_ChšýKê¦pÃ):•´Ýâú(ÁûqÝ :{æKà ÞB•O4ß)L×ëD&íi+ÉH×C?¡ [ƒEtYTZm0nüÁ¶_ñàÃ6D³„Oaëvüs s­ëN†ÜM™Hô5Þ¶WqÜÊ‹,|÷ ÆœðÒÝe[XÚV´×!ÛÈS–ˆ¼Î C°òºO‡^DG¦_'Š}ˆÚ«ô÷ÃGàÅ!çTðÆxT¬Ï%×Â|Ö¡;:ôô"ÿ­À÷RºÅ·;iõ‡Q³{ÃOYÝ;gÜÞ¶“Ö©'ÛIQ…½k_”Ôä…V~À˜áeúêÒ~RÖcñ©´üCz£ü«ÎTeU©â‰ªx»4Ý׃ûžZÿ(Õ ç})î'6UÎÏIçxh€£–Ä,›L¡4s#ÿ{ÉAô­Ýíò,-w5Χ6%ˆÌÔפ†X™²†£Å!ŸcúñÈÕCoÇl@âUe¦€L`â:ôý’ÿ槸ßp¤F˜U‹\œ°o´"p)=KÈ’\hcÿ>4õec8H‘Ú8¨0®MèIÐâÒÖÈQÍ­¥ÃæqÀ{*—üÂÐBàXO÷î$–ƒºÝÉ%I_¼S—ûs,q`e~‰>¨ ¹”$ãÔ[[ aq*½ŸÜQ7(Ih¢«8ÁêïòíêÙWXO|vÖpá®ÁŽ4kCâhÖ*0jU@XÈðÛ‚fÕ@¹ÀhÎç¯-Ÿ¿7£5i6©û)¢×¥Ówl~àÃz©`,%¶ôÐöõ •š:ªÙ'£’€€¿dÎJššÓM)ƒ—‘,vD©`¸¼ê|aूٗ¸¡à7G±á_Ò/Ï„ç°2”+C+Œ8 (<æŒ=#[–/BíO<É Ùÿ,tLA›™’o0Bä±4º _Ž÷ër\Ãüé56íýè)äê±sñ¢/¾¦‰'âtØyf¬Éß‚ Ÿº?ÐâÜ §a %D…ïF•(A/AìÍÚ˜«ó,*©f¼CÁ>U‰ÊW´MA€­óKXi7Tt6 ?$úO_¿ÃjkžÏ7 ÷!ÕÙËs¾Ró ž ë¿h14 ÍÂX#Ýœ:>—G™€Á±ïŠ æ‘Œþ}1|Ñ7{Z®öUò’­nFê€zÏÕí 09±®|:lÎMr£¹Š‹ÖÔÎ^Ý*›ƒïú23—’£ÍüÍYÚ×dù•šæwyI&±˜–š‚ï“÷€ „SÐ4š€¥_h–r§6Åv4^ÿä,3pͦƒá\Øíøë¨+³u¥ÁR‹8hGb³Z%'!}tm2+?"@êénê}Á& Ö;U+jƒ;¶ÛÉ ±ü A0«¿p &ç¦Æ²Z’¡ÀœÑq<ž‘²W 5ÀÙ¥x€Ôj¯þ²sñÕÐCÿî€,Yê€I'’¤9ý©11Ò¶} ]/ ¿£þ÷wk:~WÐ1KZˆ˜„‡¡›¾v ¦™»å#Á³hƒ¥õýñP&ÒõÐéÚ«#¥Õhñ¿óÿ «Éšå»¹ä ¡Fñæ’ëæÒ¾‡¿6WÉÀÕW®_ háÖ¬ÔN"õ¶@ä2þUü‘ ^E¦š_¥t‹E¯ÏÀ+aŽ {û›^\(¾×‚j«ÿ–¿„ð9Š›¹¶| õÝ`˜jèkvuUSÃ4¯”] ‰¸]jÿê(GªUÒGr‡Ü @l‡/çž„6¸®ŽÜ¿F¿EO†™V§3’R<‚sýpm¤ˆ¸[¸¼Õ)¨Ø®ŽÅǸÇ"åÀŽ™š€b›kªŽWìSw¤¯ …ìtè:783Þ–’ÌgXM„3„‰ÀX_äÅÑ ÏýãA&Áé a}ë‡×ãµÆ@2«C"QÓ–/!2‚¸šˆ5ËéàÀBvô¦ßÂZn²ÝÚü¼&u,Óè§Õë§§\“*ºß«Yøâeê¶Gþ?Z~á÷Z’€€Áë{&ô4PáwxÓô È Ëfãí,À¡;œøÌ‰9V5úö¬ È&nm?ýg[&Ÿµu ÙWµŠŠ5 f±È³L1Àœ¶Ø`**l`?ᘺ–pQr o>˜¹ìŒ{'«óÈtÐéq {¨åít²ÇªÐ€µÅ’ˆ®}¬›+D¹K7#QUì—Ôy˜¬Ö Ê3 £ˆ5Ó¨bÅëUê¾ùרŠöÝcyï3Á4 oÏ.ºtú¤ÛtÇ\Ø5N@aä ¶œHÏ_|x@V¤#v®›ô¹»j½÷²hœ~¯!cë©ÑêYP”8ùV° ƒÂåÊ\˜‡ä*ÄÑÞSDuÀ3üxØñþcšGýˆ–B·£: ÒÀ)þSÔ2—ËÊü+EsŸÿl/Ïݨû’´A9Üð2#²5÷}AwXOfh`Ì:’E [é=ò¦‰ÞëªÙhU6¶à(ROô «ÓÕö@~B.JÅt1A³5þÃ{áö!ß­ø%àVÿuž0g3[ýaÜc¥Kį+n$ªÆi8É'°J#Ú ‡°¿¿PÑÖÐNœºí¢Ì ›6-Ú³·I7ˆIzî@Æo{‹i ›þ@¢öâu³o¾ØÕ ­æ>N¯I«k)”9~ÜÂK*&n5’l!¦¨UÕ°/ŽåskïN”„3ŸÅBïWǸüêÛáåpŸ“ac–{tõ„$½ôªw4ƒÿÃÖ`åJ–Â5¶¦³ ÚH7±8y¹9±ó4€QºBï ŠÄÀx’TVÉK‰h6‰Y2‰Ð{ó!’€€»:ß‚MI™ûã`¶P±­ÉmH}ªK»0›Ï®9ê…„â’fþ[*ØJgêý/ÇôM@DÎ?*¬"+8Ì9׈¤2ÈÔÈ這•ï@ÃBíò·ÁoOÈL{’¨w¶J32<5®Uö–)§Ú”Úxff˜£R›òɽ€ H]2$¹Æ~àñ뎨k‡\9o/ z"„žhú÷B Ц;ß]˰«\Èä3 ´& ÌÙR0ºÎ„7zoô¹ÀdGÍ …ÿE…0Z fä䛕 ö•V±Óa—že‘,‘Yjç‘zìË{9ây%}41!…s-²J't†mtyèä ÞûûÁ6F[¯»®ãlþQ|û©ežt³Óùžóî ™¾2Øæô7·ãïŒßËp6Ç sHéÂíªÐc¢bþãë¬EN¸¶)Ÿ(I¢ÕÍä=âv\¡€øÒ´+Êc£3Y>§w«XéÉUèÌP’wU…å¡èy­Ùšïí·WGãn%rãÉfUëÒÂîOÒ«‹†<«à»Ó~* ø¼²ÍíPã䦸¹ÕF©Œ«Þ𙓧"å/žåŽð& z-W*´B\g _¶‘&æÛo!&Í$GjW÷{›êŸe‰‹c¸Ù>¼Ã[ýŒ÷·À*+‰òôˆë²43î×½òÌ3ÑLÎ"F#¸».¤ÜR7Ì9ŽhNh!¿{é)òcn÷ : 1Q6 –fàà éÞʬ´´i ¶6K3ÁjÙBF7}_bé1rtù¤Šø'>3\ܼ M;öádÂú+%í<™€cšEs '„w~‚[$ ÕJrù5(mlÈ­ü9AFqø«-ÀÿÖ÷†¸¢J[¶Elµ§w$U«×u ~Ïl\aé Yæù3o}aÀæÊ]›ùé”Ý’'ݶ躮W˜2ŽXêÀöÝINWsÏxãݤܑJãÁu€x>´4l|öŠ®ùŸGœ'[À8!ZLÓ¤¡Gë:—Ð…•S6‘V…ýõŠw†ÆHm"ÙžýH„'¾¶1=×IoÊtHéj<úZ9L0‚RL§%­Nev¤»IÖ"gøhƒ¾R”ßlêæ©ʇ3‰“ãy–Që.grH þ¬yN‘ÏÈ¿RæOò}Çl&tÜøÑé’€€±kjå•e$¶7–d:F&þ“¤¼Y6)ŠSÄ{ ¨Zf[¹ö6 2Ýû‹ ™Y 'a辬>o…âë`y¿FDõ˜cvб~9f«LÖ°¢áhaȆF!CøÊ›‹î¤VÊ Y >sÿÔL—éK®DÒ_÷A€ä\¨°ƒl"¬Ìjü–)Ä/¶ÂÏCYŒ@•øþÞŠýwXs¬ýákÀlnþ^¬Læˆ2õýßWíT¿9"xÆåóEdOË\ËÙ_E( tt†sØ —ðÊjÉÊÍmgÒo;0Á,˜6Ö©^·×ÔÞ¹ÊØgçÅîdˆƒ6ÇíÂÙÇq¡J½¾$‘4`3Æ&Ÿš§`íâ#ÝÑÔÊ)lÉ̼ȡÞÔÚÌ’”>?q¯H4¢X€')ãBÝP=E9ó&¢ \Ò;#é_FÖ@™÷‡:?¿í»EˆOµ†Î#Uº½-¥ØÇ˜qö"u8Š®Jæ ’wr±›¡Óït:õUË # PmJjk§}§Õ1¶nˆ¾Ô)ß…ð“éÛbË)òýšpŽ‹Éoâ§OÅÊùÉÚ žBjÞ‰Ô,¡,·µ­d¨F #.ÿæ/(ý6UNóÜ"Z›× ঈTù Žq4|÷ðÍ ‡¦LaÉn²Ó):iI•oR%KWÈ]Òæ Ø_¤É9VÍj4ùÁs³=Rö==¸3UgcQ@ʉ65]ØC;²bÍÄ_É;FûWšy¨Y•M~Àô‘2Ò"’€€»GÿñGÇž%þšPõ¥ FýfŒ3u¬yw»‚W6¦@z2›üE[o}Â-k{xr•à¢C€¿”äåË%nâºû¤Ay²dµ™´çMy,Cv`U’+?‹¿–Gšž#ÐÝ)lRðÊeé] Ó[‚|p kPtlÊ1˜Ã`f9¥;c—QßÖæ=/é!5ݾɒºïu¦*Ëñ3+v©mÀc䕨w¸w5ƒôLÅ‘qó=¯3ª)»IwD#'Þw?GZw²É‰aà“ÀbaORVK"XÚ3Sy§ÇÌ€™=Ò¹s°7!çãâ“@*©ø¦Ó‹[ë- ;¥¿Þ!w~ö\­HïGp SP}X'¿Xí3]y°¦»ˆ]‡õEÆ©¥'Ù†õRÚ¯r¦zN!¶În£™ l–Þÿ Ö=¢é°‚”° ¾)7çñÕ¥,Ò¡äµU9¤À×Tö3’¬¾þÌ‚ŒËëPAyžü&¹"RÓ!·Ë’%• ß5鄺…lžÀ‰¬YA+¯9®kŒÿ@zZx§™g|a‰<¦Ñb*qéíœMÑuL°ÿx݃!’²;мÖLøJ½„'fcçuõäRo%ˆ7£Kýn”L£pâ@ÆiéÜjž(¤‰ï–gVêjØÒ2ò…¤ö­Ú´/TçÒÑú´_ØïõïM(ÓW –ðMf$ÓÄ\E…¬‘åÍJæ~ÀŽŒ{EDZlnÉã'Íøƒü‘ò†s.í¶š.žoÉ1FËE°ÙÔh4~ºÈo§A×ÂåEK®?a‚§wn>%¥ë˜-+†Y­Ž»e„¯?gûGYÛ%{ ö\+kƒ΋c’XûD±Ad žWzp)ýúºßÉ›D­tÚëÑnuYûg~áÐ@÷ŒZM3hxSæ¡©ð,Qú£§Ià7æÊå¢ÞC·ŸMbå'ì§L„ŽY±!¤ˆIu¬¡ðtM—¸-j¯¹&ò'K‘·º†|± †ó‚\K¤$i@Q-I³’%A/†kÜϵ'—ñŸ"ÚýÞmïݤ¦÷¹uN -:£bf¬Æ{–†ú¿¯‹f硤žEgý‚Lù£Š¥¡^óáv @»-àiËלUóv“îFÚ§YÇ:Ô€EÍPà[ËÝ’Ý`NQ 4~7ž1+.“Ô$ª«Å`G›Êis{ãÉ=ZÆo.tTH‚?¬Ãý¼<^­êS¯ ³Ò»mDh¥ŠÃ{#Á‚8N›˜ß#` AžʺJØBa‰ÿ ºþ¥ ]¸+lšýT—I–iÔ-•éÓŠèeä¦xx"dD›@ï€i–G|Nòø<™ìªå„òŽ-Úª7èÒT“¢'{£`¹ŠúµAÁG3ì>ªšB‹íÅÀƒÔ‘Pg[Þ"ŒóZQd…;ßÙqlc*b‰xöÁØ¢k–‹ L0 ::(˘Êx®O*—8¶ _³þ'¿S÷œ°Õ¾$jOÖEH²YÃÄ£iÿ8ëáHI¥E@óHÃrèºô· ~ž‘²Ñ@ל=¶ó¡<¯gÐØ Ÿ¬OGøíarÞ]Å—-×Äø™çÛœœ>LÓžMŽh$‚±o¥àª¾?rr󼌉ú üχšPÃ.¥3¹ð£òõ^fljË;S±£lõåxªZé]^1!¸ðÈ:nÍtb×'Æ\'ÎfÔ¤cʵp @n#›Œœh@ªùÉŸxU‹{4Ã6„ˆ„fZÕ®m‰U›|w o@¸MâÔï.ÌBf¡vtÆ"ýF¨–/ WúÞ‘/µK׃ôãðY¸Ë ,ã01ú]hkG]¹ókÑ‘‚’€€¼9P Þ„©(†EeQlƧ/áGHóÏÆŒ ìEº+V+5(]ïÑ0™àñl£‡í—äjÚ\¶©éŒó¢þúöëçXjRx£¯=e¼ý¶03îÛäWì d\‘B7„8£Z8?1n ´¡ß;+¬s~*cîLáO?tÔ×­¦º¶\¸üîFSHNøò~á£l–0šÀêý5ž#e$êž×Ý”®Ì!…é^+£Ò¨;g,j%*NWü^3‹þ ï`ÑI" ÿk^ýú9º6_ßµè¯wxž>{pßéÞ6tÈ ˜¦‡cœzEÝófHïû9­׋ÛœXôèKÐÇÃű‚xcê–ÏH^@Ò‰3<ÏO ™WTÈS¤_»²QxœïPÃMVêCÓ`ñMeo¾°ÖæSý‰øh^~Ð|™±¹œÔý•üÕÛ®&/21®Ž^®.l¬w¯¢ÜƒfâW{ŸÈ…Êg[ ‹:¿}ìÈ›‹¬tÕq†sŠñh^Ÿï/q%”?Ÿ”Ã=p&Œ“þ¼I±.}ìœõ!ŽªÃü¿váuC¶#:MX@bÌμwÂek"°±üDb*ͺŒ›l<(]S+aÆRŽ>…àù‹XÀ÷èJäip`¸7Ü’ù¡N¥ádÀcòžæywd ²'Ò‹þeî\€èÉ–»,Û˜ê‘Þ?”ŽB¯•å»Dµbmjí mìÁ±Ãòrõw¢ÎD§Îavå>é‹&œíÔfw+NŸVÍï5³"mU<‘ù·Pðø©É·¯·­ •JV£FÛ—÷þÌ7˜û§ÕÈs««S"PZWÓCrÙË:`§¼ ä¼€ÝcCu y¸õÐû~Gù±žÄ9u¿\¦²ïc>/Þùv83Òò¥~ñÖY6^zHed–”Á>ðæ;” /¹dMDi¤¾vÆ'¶»dÅç”'¢L¢üš–Ïw?\Ù1˜ÃØÔÜÀXÏF}"Y«—àå¤óY8u ZMUâp:ó3¤.:Ï;~,)õ$S x( ^beI@í1GHónš s9 °­7e+CÛB |íQí:´Z<ýœ?Iõf§Eúçöå.láì²€Ñf›õZ¶ ‘ ÎÎ8L¢l¡3’€€¼Y=y@Avï'½'³_üíézé?Ѿ3ê’^Å×Vi~‡^ïQVvü÷)‰E+*`/•ì§È7xRLÅàl€óI¸ï®£ˆïd;ï'l€Ä̼­¨¯oË_u†6’cD¥¤}ñ¢+F«ŒËûÜ'•õùÉ3ܭϯ“Í<픦UÏè‡t;uÕgF0—Q¯ ÁT[ ÝJýy_sx@ÝG:±&Ð ïsìZ¨BËA1 ¸$£]ÃW©<¿.à‰ ÙUFc‡È0$űÀŒ”“ÿƬ< ³¦ò‹¦ kÆœú’1Ô•Œ&˜y›…„i¨ù}I³w—?gXo9^9ñýì7B?Q#HÊßßûJaû5¿œx7°­pZ3NŽMhª½M¬»uñ.ùÛ®¡FÓÚüH¦6’’§3°Œ´Sç»&Zƒ]ΪíP§œn §³t ìûàŠuó¾r†W%[5'ù;ñ«7º4/„5x„ðÿîeÏú²Ÿ¸¶ÊF"¹Û… )Á:Æã‹¸a(ÄàfBÀŽÓ9üUŸáiBu3Ù»éÂÞg5š,8Nrˆ.jãàCOø¬+0ׄku/š÷±v9;þï«-iŸ˜€|rˉãÅÒÅ]¼ÊS…÷ù·9õÍå–ÚUÞQ,"±à¼•hÚꩤ70â¼ åìûBÖ_a%±+­ zC›ÿÉØÉ kG³€âƒHMNmõRt;îDJ9›ª$IXܽV»¹Üu@˜ë²® "Á¦ò&5;‹$‹J~U‰ñoß‘ˆN_¯hokJÈ:„®Eœ •ï쀈RÔ;—…ÙÐGÍ]§µ\A=³! YïÂÏ& ¦emøJ ØhöQøòT¸šSy6–®‡hu¹zÍ` °j,_ÛIóuD¯ÓMœ2Žhl?"¾t°uFo¿g@_FCp’€€£†YEw“œ9£‹0ºâáp€ƒû+JQ’<Þäò!—ѹҊ=ñÈxX—y«Xùެ8^î™ä&#ê"9驉®)äLÆd+Çëng '˜¦&‹ 1“n>Å1gËÞ ÓOa…5†*„oýéÅÎl5„’¤Ÿ {qmۙ롕_¡äjâú×íª‘L %Fï?·pXˉ.ìÅ2ÂÖäô>ƒ>,Sl¦›7¥/›²Ûb#hͪ• Hß©O#Æ}9ži8 L1‰Û5«Êìmé6/Bw$Ì|aÝ•y½nØ™ð8'F1}⥲µœÍ°Âm6›Ç‹MÙâ²~îÓ¤ðÙ "Œ±úœßœgmY)?ðØ-}÷œö„è@ûªâiiH%¾´‡´…ˆÑÿ2ÂÒ5OðÕw×­k04¡_öþzœMÂXæ©/Î\;Ð:ôT`ŽÌÕ¬›LGÁˆñî©ÅéU 6±VTFáÊï¸#W­îw*{ж(XîR¯Ò~‡w>ʪpcØöc¡1ÄÎ…°öÞ¼Õ~¿U5Ó¼V0Ÿ äÊxUKÌʼTk¦µRO;º´ Py*F¬þÚ»ýük tc\:‚ÝÙÞØy õ‚ëh—4H e3‰ÍÀÕâ_v=L¶ŽZA;Ò,yè’žJèAm"í;ñÌ;OMâ9;^T41õ„€µ]³|âù ±é¡ÂÔX—z…6@"q¿§1Ð_ªÕ/Âe¼©'½ó½EM0¸ C6_Ï›iK=¹3k”aìQ€ÒA×â[#˜Zj~Ñ!Îejè³c¯½³ð±ó1X—U:{¦ÏtÀüæ"øÐ,æïn@§;‘KµÎÒ aù›]æEˆNû´–Lö¾hPëRXÎbCÿSc•†„w$^2œÕ…­¯Ú ]θ‹²¥‘Ý<: þþ¶åèd˯t+»q§1¤(²6Hc²Ñu³Å÷¤ãAaÞH*Ã1sYxž*MÛŸ‘ÏZîàx 1ÂRYĹ­8ÎeÈ5½÷>t>-IÇ[¶Æm©“ót½¾i|œZl—&kŠfy=’€€Ç¬pb·õ¥c/ŠÑ>ƒq´Áy~ô|KÈœq<­Ø ”º7ªµyÿÿƒOùneQü/€Ç÷…«\EŽóˆ^›Ð»ÂJ*‘‘*îÿÒ–:°æ&ªa¨¨Õßð¾Î?ÉzšIå"º¸†3k`‘Ð:wS¨åRœ79çƒL‚·…ü4¸1Qp0ΆS(ÓÞIJµMÑ¥ i!žß’^$#Ü ÂGò¥®‚¢p«’ÜþV=I9Ïb÷`K8Oƾüš&%¤~ÏoFÍZHúÒ%ÏØqÎ×é8 ªÀÅÖɲslk˜™2ÆCuQ”°æùæRÆ„¬'R¾~[r¶¬„Èñ > w7–`ª¦¥”|xœ?O] Õ¢…þ€c}%vª)C⸱¶b¹Ò|ÐYË5è¬&/ìgs€Õ†·[‘‰õu"œ4R‘#ÕÓÓ@Ix·Æî„)š:6ô·ñ/#€Ìöp-èä²$#¾±ßøw?”M‹“–ÞK¤„QÛ‰Èû‹ŽƒóƒÒ EÍ¥bAex`Wo[×{ë“øÙ“µÂ¼¡r1HhH› ”<%Ö&u CMC|NÞ¶(¬WTÍ ÝÏÁœ¸}RÔ]fp6uï¶¿•šÊd.‰-ltH .‚`‹­J­°0Ñ‘æg¬{† :]²ø»“³Íø˜Û—ÞDx2t!G+¤­gþØÙ0ø-2d®ìðåÓÚƒx™œ@4Hž`£@æ+†dLMÝD>&¬Ó²P]Î_û»ô8 Ö5ëK~O•Ü~Ž $ ™¯"‘k›S”Yl’»³Ì‡„tI ‹Õì>„¿Þ>mÂB Õ¬?iJ–ûîOì½<ç€NYé¯ ŠΩI#ÓçõþY¹•meÕ·‘™Zó"Ø-ÿékÃL¥ „ CÙ† xu¸æs ·8ôn“êŒf“ ·VÝš ½H1ž‰Ç®€##{E«*Õ‘z"Z®Za±Æ=¹¢¤ÚzeÁ,­A„¤ügÿˆ´µÜgJܬ¦à°ÓšöÑ?PB¬ R©߀Ò^†írSšW¡®y|¶!w(ÒÞ0%ààÌ:À­!CeÙ‚ ð›`ŠZ¶i]…)ú2~Ç—§Éc:£, ðJhùÝ:x¤)„àb]&µ£ñÆN’€€ØïoêÁ"Ì6þ3·8% 1âÓz†"°ˆ§Ôü˜ÁeŸg& ß]§ÔûB†êO¥V޵Jnœ…zn|5Eä^­?ÆïÁH÷¿Í`HYj8—•ËV >mZó&n&G²n’ulîgàœŽ&5å ÍÔC‰>J´Ÿ+fc¯–]Mšz®¦ÎØìŠÈøá3@{:ßΆ¤Ëà& kÇE& +žÔhˆJCɳH%¥/—\.àžü@ÿàf›oYÊw“~ºS 'Lù4ºÈòÃæoÙ%5ÿáhJ¸ÞØm³¤”N"w°næÒ²XÒ<^j¯³vžˆ47X|·=A$;¥Ä²¡éÚÖØ9 2sƼÒRƒ+5ˆK[u¤„òEjà?&Fy—ºZ½øn–°Iûòéƒ36zZP]­QHšþÎ-6!ĩ i6À×^Š}6Õ=h¼©üG?Dÿ5¡(‹üLZ…£)s™C÷™ ™ ,@ÈÝ ¦úbñE—,¿¦Õýˆù¹ÚõvX´A¦ÊlnKY†Ö&ó—Ew®¥4/‘%»¥¢6Ó´‡Û€1>Rùäõí„’l÷bJùË5JM-3Á92'Å6»îFÃO _iŽú³Íîfc7 \Ò„MzýØ¿» #;ÌÅ-†¤±\njRÌ?~F2| ý¶ž¿(¡¦âq5Ìpû°³«ÑøŸiÃïJ¥° Äyzèö |Ÿ™BùçßEw)W­>ζa60Ë‚¼eŸW…•U.EOŸ28íØ/‹ |8üµ¼?è#öÚ²¬}O;«¢ìYIÁÂ-¹%ÖD}ëâVOiD”_…ø¡óÐï¤Ç521ùÚãõÃègÅ~õ ãꉬÓñ­:HŠC‹ÖšGZìòFó]ãÈÆ9Æ9É¢õ5'¨:œ!s¹å|"m]elî-²EãíhÍ{fTX2¬1r‚8z2€÷7žßLo9aÙÔ½ÂÆzÿƒNSGÆ™D-ïinýÁÀâ­ýL¯éùÝ)Ã1H?hQ­D£i<}·Š9=@9„Æ7*å£×í©÷Ž ²ã}Í!šÌ–^_¤{ʪvÀAµJ{ˆÎ¢G®vÄ/–n;yâmí/Hš8OŸä(ÝÎlÜÐ3ÇèËjMA̵ç lbüKOÀ€éjÀÑü’€€áS_ÿc–¦®ÂO2ƒÕå „ú ]wë{ÑÀë•âe¼ ¤kê¼,‡RaØ…eˆ¼Í€Ð¯óp4âBè«ý}ËräÑSP}) éà?‰‘¸+Þ¡&žs«šgb€9e U@dKT¦`P$C~ã€LZ©fñéü! \ëšÈ¢({§43=AOga«±’´ v K&ýÌ])‚uòá÷¦–„h|/Ý÷‘•§¢5ü¢çªxmdíÏŠÛðäpZ õÊ„vxƒLk^îÌdZfà•é…Ìi¾þz¹ZìqÃ)WáOaþ”˜¢„ lwÜIŒÍ©ûÿÃ+žiî¯pã[BTÖ¤l²pe¥ìÏ£cpTc+êAíÛˆ¯ÕÏ.Ȳ¢í–µñ-¡>Òž:XÇÓÖŒéKmi…èŠÄWTÂCa¿ìG…*ŸCµ_ñ¹}×@9Í,ìØýfèÇü]î†ÅËÓgWµÎm UuëçPFØp ÅìwÉž ?ì Á¨ÅÕ˜-þcqÎ@[7Üg,Æf]¿ßŽZç—ÄYùׄ]0T G»Ü!ä`·VÄD’9)²ïÍQK8ùz(ž8e yNF©ÚäÜÂNÜÝ~ò¾”¨@Ø‘jðá^Í©‚ߪ:?6ÿnÕ:{NqÚN%2NJW³x=â~)Ñÿì`¾U8 ¬3¤ÑÈ(øý‡h0ä`Α¦‘çÁÈŠ:ùkcù ³£9w´D¦_>À+ á°¶ö.iদØ›wœaÛýØû4;“µ@!îËkûÇ£šŽ¤®Ó竇±Zj~åðZÝ|œ`ã»Ó3é¨ûÕñÅç(M†El3‘ádLÀ)XÎȱÆÍ±ñk|V¿ÑÆfÈygÝ;$6{¦¶×_vdlWÛ†c×ì8:pY½«¿l½3ÜcH¶½Aìïíûy x¨õ)ym æX†V6Õ©E»r2H:ÛoòMjQ@3g(jª‘qàgE-©êÁv!Yö<HŽÔ™ËŽ”UL؈nš\¡Cô¡CGXðpåLl„êߦËIýµš‰9Xs:í`¹+þeOpw] kõYb›þ­Ü33b# Åê"åÅÂ[ý²¡o‹—["͘hR'WA4-ˆG¬ˆ$oÊ,gvnÀü,L.ž…ºV Ò1}þ’€€ÓL$!o–­¯X„—9×ò]‡ú}R'êÇ•Ž@éÐç‰ (.+šF!ÙßD b'„ùgy¼íPpcæý.÷mÙÎj3éIýf¨:ØÐ}’±ŸJäŦg´ð* ¡»ªþèZ§3mC²LÏ]š¥r.Î:>—‰pg^¨i™Š·ÀËy¢ÓèБ¯¹~mÕîiH‹úí\¡4n­øp•Æ,ß!sœáÍ`Ö+;1w°¤æH<[eÿ"îè»iïÎ/–m­†öÁŸÉÆšÂç&Š‚Aujé ÄtÓ½a¼yÑ%•{EU@TqƒÀknµ 4J[u°³ðÚzt¡á À3ÍBΔÇ*@¿âQ„Z·#]ؿ⠹éh²”åcU‰%YžIöæ0õ5­,•F ÈDXÛ+gSä\Ë¢tƒ ëW*a‹u,§•ÃØp„šî®ƒbuÓiZ»}{Ïýo @éiÐo¤„Â7Èî1ú&“aº‰Å] 2U$.†:•»µD-‹ê¹ æäTþT)…×gÁ{6‹Ÿn3Ú‚ÇY!4.sz-Ãýì€és?M¹ª‹Ë,Â×0q¢R~'åoÒ¹/nÑmÇ5C±'‹WSiGà’ ²hqÑ^-ç‚öº_L©Ì&{"`R\ ÓýÀ%ùüítqc~×´-rެœ–"Àt¹‰[l˜ìøñ!ñO¢Īþ{g÷¸õœn™™r‚¾°¹"kߨÌÙ¾þ‹•œ0í0…êx› ˆºê™ ¬‚ Û“ÄT_{P'õG¹æ-œ|Ly¦>=ŒCé{íÎÏSJL„pŒá,Ï_Ç•x¡ÅÕÝ9óžùÓ¡ÜŒtqÕ‡4’G[Á¢ìùâ¡ïI\üDØÍeé6ÖÏZ–Àä0önÙ¡ ¡ždê‚WúRŒ@tT¤å Œ‹Â"õÏh‡Ø¡#—¹ÛpVcLÝuסœÏ­³,? ˆÖÊ¿?†—¹¼\û†6®Ï:¥S«bÑÚD’‰Þ-È!Nž/ýMRÖð$%µ„/%4D•+±¬N`€c…ˆêeLkã“óLñ!Ԭ݀ ¥CƇÍÇ{1í¿<&'ïs3ÍÖÓéëç=ô £¬Ü²K‡Ò×bµ:Íef>8Nr¹À7íÇ9#Îÿ®1(ŽŽ˜œø@U;Ý a@þgÌþªA‘@Â-¥òî™Wä¨2ü¨ rï/Õ3b›~ËÝ 2]EzÛçn:æè Ø‹u6D&85¢†° þãmÜ[±í푬i5*-Cæ/%ŸÕ‘F¢ðG’ŸÆ¾q²ÑÓ5L•“³q~ØÊcå ¹¤©Îoz©óúãCyÇS¾DÐã R˜ã´Ò^Î,FTé´ÝŘÁr›ÂÙbE‚~-º­:EüÙî–]R¯MÙðlöÂw¢³Q˜ú9[Õ¼nP£¥Aã/ÑBäz@ª&‹'–(Q‡Í¾ß  ´» œ]6 âkÏ=GÍ= ýçZÞU2¯M!šµ¡ì¤ñ7MÈ?ôgüÌ_=v;[û¯×"×ÔDÈaÄTÛs0xDæXbf&±T"K7¸ÈÙbvòÙFÚ†ˆ¦Ó’’+;™âª*Àìlõü) 4…ÉOI ªöÕdI(EæTÌ q³¦TÖóÓ¾áJ\n2üGdh9…p«t}#Éz¡œ–Õ¤ ízCsý¼û:%DkS5¤™ËŒ½CÄÁ%©^²-&¼;üuEZ¿•ii´îëÿXGJ²Óp¬°Ò·~{&PŠél:?á€ëk¯â¥8-¶ÖFlã)ò_*¸|q*íµÚpÀ)·¹-uG B‡†ö¸]_&³ö’i޹ùÔ<»¾.RÛ)¾/J`7Bä1Õ ª+”gð„W‡`ÿèUôâÓ õc ^m‘¤‘üI~ˆ c5‰¥©hæ aQxm˜¢ñ¢œTû®VŸž;ÜïY­R,CØh]7©9Ù¿Á%Ò ~`z ¾4-ötÆD€îí*Biµ¦÷¥$ I¿Þ²$:wÛSUz_Öúõj*xV?“#õÄc!)˘}ƒ~¯å.Àq©*°t¬AD]9î!^™z…ab?ÔäV²°CX+`ÁÔÐ0_KLHü¸´¹¯'ËÄó»µù«|Ê; ŸîÕaÔðKÆu'É>ö—“àH\cËk5|ý–~¼Uª½Î¶¿ucäÌHrëdÖùÃO¥dÿ0`U B1d'þ’óôÒ¬`ÆëRv}î‹’áW7hè}U£kÍ'nJÉ€ÏÏoJ¦Nå^Ï‘'™!f¥>dt¾¸ÑÒÑ!h£ °à’pÙIªá:wÑ¥–W¸‡(²¸ŽŒÀkB¹sæ¡’›?ôí<{µ’E ׇO;˜+Ù­¦læR2{ôÔR¬ èSÛ‰nþ”¹×êå…šÔ‹x5Á•]¨¬D htÿÁƒ j“/ôÓOÚô&†ÐÔ»õŠØlC´Û•G2н¬/5¿©²+ÓkRŠÜC¡½©ñ¼<¿L5Œ1-k9wx82Ö‹’€€·jtŽØ‰ý3G§.â5Ƭ^ªð¼lC ENò;!`ù– ¯,ë £+¼tÍI ­ÑJË›þkü|Q%D¿à50ý„X‘ê„ñjˆÖuðÑVÏG.&àä†~Óø5È7 6ÌÅâ ZxkV+oîw™Ã¡öè%ëÖ+º]³º‰MNƒª‰"2`…œ#A1†õ0ÚŒØf5®V>Ò4Ñœ•ÍHÜØëWÁš6ɃóàeQ¦Û˜ø ô‰™]«uùR“kžg]0I§¦D!Ê÷èÅ5?¬â‚¼µùXß"’ Ìf8ì‡@cGÔíéúTõkBŠì¡ð‹œ©Œ2ò˜ˆLE_±1zo)˜û XñhenâCL'ºK>)ü0…Oª„"Ýž¯Ë7ýºãë±Mp¢w•“' ç“ñŽp:¶!öòzúö,×ê{yžE¤nÕG 6ÃóŒQ¯•غ…ÌzkV#âÿÌt04¸f°žJ ŒâoŽ–{ ëàq­L©>ÙÔ'þ<ä{nÔ;€©@ ZÜõ|»ß2MÔ´w{ü:ëjTNæŽ+̱ Û» #ÏMÛT}ž«Üs;·‰órk=Š–á|R‘$?IÆ!5ɯkK5Ü ýjé?ÏØO\F‘w:<åœ9à6x1qS- $Ú||inrØÂ‚ìH’€€Ñœð3rÕ*ܘ1ÑÔjsÕ}õ>²sx71¨7„«šÃ¸LYT^‹'b·Q°þÕ˜ÍÍžŸx›ÃNN›ðåÅ©Ûp2*q靯S?[%ˆ:ùÉÆ6GˆxW„š™ ®Ä^'Ú/ÕæÀ–b±È©Pÿa·ö@Ž–vïƒi*¢ŸíPÜX­{q@P~ó5ëÇê„eÌJˆ»ßƒæB FÒ!¨{ËjØWGg;ó ÈÔžLµT)É)n*ƒ¹,2ÔJ‚Oùã ÆhÿWmzC"¡áK8λi)ˆÒJ Q½°o`ôB \Cy²‡”Y@‰cB¸ì)ÝÊfÒN4;¡4a‘4›oàŽ'%M¢6WýÔZïLýN§pPÇ áÿüðL1ñÀ®óÎ `þ1ã4ÿÑ.«¢ÔY‰µ:“¶{<ÿÍ~K{Š'‹Ôôƒvv~T‡gî‚*ÛJÂ&ÌÅHéGY_ªÂŠ-ÜV/´Kçã+o±¶¡}\/Øær)ÕD-KþÄ×´/=ÿ|éQùd¬^ÄQ¬êJ¥Ðï‰ËS@œªx¯ d˜ßU›Ï.…ŠVƒc«· `R“CÄõÌMQ!±‚ëàzKSÞq‡yþcÐ9Ÿc¾ÑOE&H\éUcÏÝæâÆ ñ6³uuÍÙɆÏå­ÏÛÁ½^F[é;ÏløT|bñ3ÿ5'UÆ™3¦¡õ ½Nú.Ÿ¼šÛ~‰×·y"xþ;j‰|ðjüÁV8C¡¸Nì‘ó3î³yvçÍõräïÂ'¾Mjp³o%ßösü^„Qª _†¤Ý俦FO <µ»u*ÔEF …YašùŽwŒ§î¥­#t·ÉA`»øNñú±1îJ¹ÃÈ7t(5xÄhå<³¶»@+÷:èÏ(`Õ~Ÿ‰éa}s9ƒ?Tަ ¦tI`¤³&‹ôTÊ ;kª«"–zÆM_‡gÒÒyôT% êÇ}H­X!×wFjF&°µÕŽÎm•"© v¾ –*~S)ö5Š·ðSÉojQY6ë®ø© à{OÿÅë‚>_ù ñ:}sÕ Bרé44Â3”¬À]ÇýZ8hdNîq™oÙÊJÖ]‹»‘î˦’\´±`nHÕO»<>æGgþÕçåä{]þ—Ä@|b–¼Áê®a¬ŸABÞ õ \èÏÉ“,Gñq1Õ°2l°À¯â]iïx]šÀfiŽ»‚Z¨%„c¤xáïZÖ ÚºÅÖÈÑÝ7¦VTu K—![PŒb~ŠÝ¨£ïdEËÛÎÒ%¢µ/å>!šØ^z4Ë¿x¢"?í~#è1U‘:;ãuWA Sãò?Û®Q*š²uv½5g8÷WÞ>h.„EñçþL9úð¯‚Ü‚~ž ùá?I#Á„ëXùÿ³Ø>»mÏYù’¸JK¤vØw׳Hã¨vøÜ†ƒ%úˆy^»˜šak«‡íeѤ‚‰Êi÷¼µýýˆj[LŽ‹5{¨h+& ºm±LE¯H8’Ë|Þ¼ïqÞ™=ªkë°Ró9Žæ°ú;'Ötî‹Þ…EiãÎå»W?œ"ü5ê­ØI 9å á8kþ¡‰q]ª—ŽýÙí¼†ZÅñF_Œb”ãákr¨¡©QÇàö.óßÁ¡qVyq¹Í“m™ï·`sHêµÚ‡È•ûìˆqÖz±5’öØ)çJeE­Ü'Hyü³]ò XŒœõ‘mÒv+CM0¶€gÀÊaÿßô«Ïlõ0\ þ¯c¬Ý›9sÉ h–=A¡­À#}ú¼‚bÝ4©~‚TríÆ$H!™Q„cœë²À³{_Sïl¬-ðÙ›|ë‘ÓBL+7¤¦Â™Ø/HCc”ãÑ*·žõ“\:Ôþ¶YfÊÚÔƒÁàé ;¹áêAG÷s^bß;ÜÂlXQUñ:a?%~(X˜»J87w ¶_,×s8tQ"öô2}’©ˆ@Q†Þ_,üü¡xIï`îý%lŠ;Pr" ¹„WšxÑH„<ÐAjŒ:iEáŒCúX_ÀåÉ)jâR½ÄeªÚã Iµ4û.¦_]Rèšm¬Èa¤Ü‘0.‹s=Ï:î.§óØü¡e^ÊwÄ~ô»ZΛ"6)/ºä±8ÍÑn7H:iò¾Ø§¯¬4ÌCÝo_GÚ?0ýƒ àQcæ ·ÌéåšÊAàQÏ&=¿Ú¿Î««‘ƒŒvÕR¹IƒÑ´Tœ¼™¬D2 ¨@<Ræn–)G±„„ú`œ;(»¤(5¹NÇßrèÊæê²ŸLe‰«å×öÊgð¨YNØÞÏ{†k*û×ÛÌ߱𠡷­£¾Oï]¶žõ (Øj`×Ñe² ä!Ïðæ,“QÒCØU¯«-^JôÜ(Bñ¿Ì?öË€N]Þ›ã1:Þ b‹E¨UÌôRÇxÂ_#¸Hxîæûü‹V ˆ­O±õ1ö§# Ó ÊåJ‹Î1Í6uÒÝá§zözª5CzeFÃ_ÃZ|ùðv!–¼` ÍòÓœèoØ“ƒLúüû.–tĹeàw ràañƒÌü@ßuC,¿‹Ò˹ˆÛMùa4øEéó;ÜÇ]Æ[—[Á© }ÈCå·{Ãs¦bOèI'1J\4™ª°ìÿçÕ1Q1Ê|AÔ LñùS#$¾­ŠG¬6Yéµ³Tž Èüû¾þÀÐ2ŸÆÔ6™é’€€Æ>¬Ê™²LŒo®”OÛÍÄOº!áE.áÇnçìµJTle%«šoÀIE=ݶ¥6œkhþ¨¬Í¶˜9i‘˜faóEw09¨=•ö/f¥(ñ­à…øÅìä¼ÎìÁ=’bgÌ‹ù1óüçqiÚt0õi߃ûjÜ®ÛÕl%[~_0tDšþÕvvû„[p ¹zô&âùYœc*Câ?@q‰ÝÙó¦1Ó‰ä0ÿL±ËTk* ÁûótdÖb~~G…GÞ£FÚ¼~¬8¡XyE¼s#aF/Á%7ÀþDž¨gmY`A=$W J`%OŒF¡½°°6ƒq ×MÑQ ºD€O=†º¿C>“D ñ¸H{µüÇð‘WÄ¡¢.NC$q9˜À³óô-²t¼aü`Í}èÙWð¡¤ô/1¤ÙË”eŽmz”—»I6‡Vé“r;<êÿßÇhVIR“3ŠOr;¹{×ÿ ^‹èxº ¯¤€./W‘(: «€\lÅ:WÞÏþw;·ŠD±%yt…]瓪ƒÔϾÖâû}EwærbwXŸVÆ)Uc^~.ÛãŸ`oÏàûÈo?N/¸‘Zqn$±Ò…³»~¬l‚íËÏÎF…qÑÙîAêÊ|Ø}1 ÒH¡äëÞ5­‘I±Ùh…g¢%ó$ăçOƒR¶ÖË]uئîÕYñn¾²g¤ »ìõÐëO piˆì% žöT2Ízr}-£§C3N¯¿ñù8|FÊèz\ õ^îäl… 9óûê]GÖ@’Îà@ñak{Xpµâg“@¸D(Ì‚±#ݱÞgoãæ.áG‡ EW^kf¦1” ÂÂR½œ[¦ ¶Ix!'Ý.z²3TAJ$ZÆÆ‘V"™ÀécZU·[Ù“¾£óÊRù¬)€ÚÜ 6ÕÜ^«êpbü—¸róÂqÚãÇ£1É;ߘSñ «‘×4òÓÕ†''µ!~¤Uš#¬éÆ}Zeæ¾tssn–s“3ÿ¨ñös„KñáÖ“¯NrÁ©Ó–zå\ŽÓ¥UõN®žJƒ—mY»…ôŠ6§ožÑr>…p¢úá€å: ¬›²Ò.˜½ÊjÜÒÏž}í•mÄä÷ÏTohÜ™½’’€€ãn×RÊS^‡×cãWHÈ~’qÉ ¾0ìŽûyéú¸LxšÀúŠOÄb&çwáfK!˸ù Æßg 20=Šfžã¤Xˆ÷b¾ˆj·Ÿ¢’¾³¸áÌNæûu6ZË矫 /°S">Eá•)(æ+ØBõÆù1³¹üø¸t[ž& ´oÅ/¢à3IVòíJí¦C›”VíU€ì<º! ÌI`òpßGÐjÅ/'z;æòñµ¢B=H\Mônµî(¤0®ÊAT¤ÄW6ªŠÎ·"4BV bqîÀ[Sâ6A$1 â–ç–ìÓºo¦^ö:LQê<ü7èF¯‘YVÉI½·‰?é }G*tÉ–b‘ªz±têCÖö± EŒRkÅNzÒg³­)Ûõ‹ç^½¦äÚ[À8~ sJ;ª“´i¢ÍO•ÿRd:Ìei9ʼnþõ ( ,kXŠq-?/@ü™I±qLlAÈôIÀ¯Ñôróç÷{²Á­.Ø5ùHï³aLR mÅÛÜò;MÌUssã‚H¢–´Å?Ûs#|Œ^=L)®%m§Ó2e“‰•¯G2-Þ¢›÷!VÑÔ'¢îüÏûÀÁ,†*íCä\ü"ÄU‰ÚútÌkð¦/¦:üÃïST•ç7Î`4D‘a}6¡@@¯ö1y•þ²@á¯"ÆSĉLÜžå½ûƒB1êM°ùH!¡Ù˜Ý 6š)•/9 ² oó¢%-þúG/F‘aú+#8ë⥶ú ¨'|I”lý=¾{y uëløðî¬[Nšã6W©‡ïƒÜðcO{ÄÅwNãc”ÖxèQü©õkã¹Ðgà'´ :ßÅä²ÕЋ‹CÄd•D ØPÊÖƒËô{*bÀ~˜'ˆšÕß“ünsÜi$Óx5‘5`8eñüõ—/Õ7ß~Lë«;’€€É%‡ÊeÜ\.žYG° 6‚a1Ó̓¯=4¡M]kˆhoT£msÒ©q£~Q®Ô!­M‘Wk¼t}þ[dŒz;cI*÷8S¸ì†ÖÀãůömÞqÒv`˜kI†85À5Ì“À9,Áž…ÛÌ—÷¢ÃGØb'̲4Õb Âͳ´×XâZ •ÈæÒxâý)í^úÓ` 5X¦®·gs™©&ÎeC¦ëyµu9ÀUÊ9sà.Iþ³"Q* Ÿ“ñ(S4¹TjõÀ¨8Xâ™Rn0Êcš›,šÅ7²x‹u„Áï±C‹ô$y:Ìû™c^PˆÄñ2×Ïó›KÑJ+ N/Ôœ'z¤tÝäÍVH`:ÕÏî´\"“¤bb<§ óM>œÆ¥ö a‘•¼k£º)çÅÓ€TC˜B(”úMgŒ¶•Ç„AM¬09å:§ByªÛÉËøWl_™BD’i"E´á6;ˆq†?BBb5ŸâIC\ã œG²Oøº°ÿà¶(Dýñ«"î>¤XÒžÍóBb”Úôgww§ïç¹e ÔÁ,Kh:eU¦‡…¿²ê†^"žäîœ~26Ÿ:Úô0·që4–cNgõ™QHAOfXÈÓ£ô“¬’®Šq°!ùh›½ƒ±t¹ÇÃ?4¨WX9ïÌ7qùë9j‚'ªã‹%|‰äK ×0º‰ÄÔ£NŸó·K¢)0úÑ…(DVÄXLÖpÜ…§¤aùVN’Çàg¿|àʤýÙ„î]U” ­ábê2ú¥m¥nÊñ¥ié.ÝP8¡ò¿®nôÅ¢í Eá?éR.§jm©,¤nt>¡;YTåÚé˜/`¯Ÿ(DíñáµÇp³9X-é?µü`í¤5yKm½< ¼HA¬œ¤J“Mû¾ãùú…sï1C£-eA§=tç ½ŒAøx’¸à´nÒ«èèÎ>m—X¢$mtåÌÚÙNŸqÓ­”OC£ÑE'oÿ<„^9½½¥œ­Ÿ†áÁÏdƒ[©@L**¥ ù-}t|4ÍÁQ3ªŽQ˜?ÌÚo僻jôÄ”¬2NA1xOžÍ…?—n%åñK¼h䷈ĭO_Ù , ›(}£¯¬÷hûÂ>TY yS cµ+¶LÁÉ­ÐÔë#ñÀm{ÑÃÏ= CC’€€µ«J1HXˆ¡’û·Àm¢r0…ÿU‰üù^ü3ÎÐ+äŸùŠH$3-±§¯•6,¢–™ÀJ„´Ið1ò¬ÜÑ u>“ôÍÃ7Ž:#Œ”Ix óK&»o>ݬÍ3W¬ì²âg»‰^Ñ[ …–oicÚ´‡º±7“ÌñX¬Ð°ö»ó1&ÉpKûØŒ~--ŒÝkô5ú÷ †vÕ™”¦Ç0}{ôç`qL›EîîÒ}Ý *ÆpÀ–‰jù¼H)r#a#>wL±À•\O?9ÒlŠ)e÷¡¾øÅªJTæcy9jj¾HÆ’ó‰!Ÿ³î°K^4.Š ¹•k k–»(bŸ'kùh$bãÖ °,i™áò08šɾg” ¬¢“%ˆö_aµ¸Ñê”0”K¸ó`Õëo·oŒƒ–«ûŽì± D!«áx¬‚ÿ`VcàWWŽþÔÈ|¯¦bDDTV•Û@Åé&ø%í7Â’VQDŒqÒ|9Hq²Í³õåYèŽÝUöß· k~N¾c 7_MénŸmš;À6-ÜîÓR:¶È+h2¬Nð΀ËûïTtBéõQDd?c=Svá\Lµ¸k‰äj¢óÆJ%L§=ˆŒ§—sL1›ªÄþ÷ê2ÚvFW¹žÉišÿöþéÁÏ”?³–Ѩh›±nLÎc!ÄèôÚfžvÞ„êå>nç"½ áZW›´îréèÈX¡5òbj´t¯ÉFˆWÓܺÅ$ËÒa&•ð$àãr…ièÅË›{¿6þ¦FSu.3lÐóšeº²ôcÉzÝXHí®‰Åc°cíЪæŒÊ„µœO ワ6t ÐK)….‹)ñc­ï^ÿÃ0Ûݽ»â…w,Bµ÷óL¨ƒ BF ÛòËÓÌL ÖCðùú ëYˆ>:Ô‘d|áçV!ŠÄÉÍß:ò…¢'ÞÀí¾ÎFkÇ7Á,® ¼Õ.TÓÏ>Ù6¢‚n¡ðꓵʦt æ]æáRäüdÍÉVz/ƒ³ˆL× 2ù1*iHì&õèJ&a°»p/í‡Ecúp—›{"Ì_UsÏV~Z®áÖ†¡¿x>..¼~гÀ-ud’€€Ò®CF¹Í:ù/‘þ}ò·Èm}¦ƒB&oçhëE¾_´¦½÷«r”ÏEO§/ND,•¨¡9‚¾r\³€J\wÿºÚ@RtiÈìsü¶àu6µd˜¦“ÍÖ†Ód™yÖýúQ”a®:ˆ»®ÜÔí—7]ÃÇx5zˈy^£‰õ‹Î•¼ `®åDÝsã3Ñã½,. D¾&`†$7…ˆì…Ú“DècÔ‚¥÷ o# ý‹3Œàk|ýÎ$¢㹦Ÿzù„ê¸m›A¨AŸ¡òÂŒxË{• ª?°´ÑÑHN?wäJÁjuå>º¯Ñ"ËœÛh±»~ðD\¤Ã<7ÛQuQw{r}~ÉVãºáh1ÅùÅê\õ„(£Xæ¬èîÃ=öÏ.-êÆ g!ox扲3G@#hü~€O[9œäÌÇx¨ÿX’þ®OɯPE¿1ÚAðèë¥:?ËŽXG¦GçË ¢*;‰•.£±n¦¼EÙÓ»²'@ $Î0j@½èÿß÷£ÿÄRg…¿ÁòÎòí¾·—s½n.áðΆ>SŸXqžó¦sL¾¦žÑ€'òaUJ¯àŠƒOÔwæg@u©Ëùàýä£êí£GaÂq§Øö¶“öøX»'‘ü{;ä·¨-]îz€þ¬;@¬J6ÄdnЇPÇSTäpkx”íyp–<Tÿ¨µ1ztð ÚjA€ƒE”ü<×n&ÑIŽjŸ?ÌØŸc(‘`öŠ Á+ízë·Ý—ÂÜ$\Û›gÈš`‰·µû‡_!pI/*/­ú3#*=Õæå‡Ð™Ô ˜Ïˆ%¸$—¿µÕS½uo¯_8Ûv2³\«Œ6Ù8˜(דë6®©î-«J Ü2\EZñ@(3Æ«%¬,Õ{2‰IÓÇÎòd'Áý#†}£8.ܬíÐÿ-h“­gJ çšT‹–ÍšÛâ9ÔZO† wÜ©.¾KÞû}Î>,“§‡Zºh‡ßB—¶v‹úµ@`c?‰CŠfyµÂWÉ¥Úî}³T¦u28(nlÇß2P${ûnQáQñs À¿¶Sɤ FÚ",“ÓÆ‚g¬ŸV̶–Ò]쯂fÁ%œ7 hJ½] Ë2œé’€€Ý»8z«¢4þàXäÕ«5Ò2<ȘvBÀĸ‘̼‰­ÝQ!¥=èï±qxfw{óݦ½º˜‘\pD¦+à;õ‘0K´v]në-þ¼ð¢¡§.#§ Š‚á Ø(I÷&—P)t´|Ÿä~4¯dª¢³¾]#öQV@¡kr7‰5«Ï†~£ˆ+Á>T ”5=°è©ÓÁW_v '΋¾àߨºnîˆZrš‚´NñÆÿœ¬‹)Ð%×?è-ŽßÄ,¾å—|¾#–Fˆ¹&›îaÀù²¥¯ß…O—:ÖYĬãu]ˆAª ø&’=!0ì»C/ D¾ø9Z%ü–”Yh} ð¥ Z’ž Íæ¿ ©åt[ 'dÊÅÕ“d¿mh+VzÜVF¥¼–g2ýpäÓ8*zýO½píWuZ Tå!MUJ?™?ù ¡¬xÃ/ ö­úø“I±;%~+6ÑØP[èμ/J¯\Í6›WöQ½šm-m)fAºs þ“ècÙ€±^þý½ÍW$R±ØV»?cµ@yqvU‹§x¦AÄesMn¸ìÉ ñ=Ìp­@å58ÜñÁs¹J¼4Y—%«Ím㥂¤|ÈÔyjÏ9[Å*×Ëq+`\J,¿gØ;‡ðg“ *þ<LéHoèdòÍâXçÜýBS¶ÃQíd¢‰8n]`Ëìôý…6fƒ‘ÛÞXèûFÚhã Iëÿ=¬ösú YâÉ¡cî'¯U7áù%îlP‡ü$ŸƒîzÝ](2؃óßÙOs¥9«3i>ó1¯Q»Ò}ëï¯É©Í€”I¾PM£uMÒ¯ØÃ¶y—Ú«žS£uõã2‹–§€¹øýïì’XT.’½ÛÈ}aÁ‡’€€°Kb÷8àƒPD•=–$. ˜4M6N!à{Ôµ&irâWñú8QÐbí]÷˜¹°¥WõSô] Ç©õ¡JuRLC‰ög£sž½S`ÔÆ5Щêý¥Ó'%Òõº Xƒx) ÔÆñDñÃŽ “¶éMpÓrÕ×çCÜ©Ã6ˆ•}´p8û:}õü*HíÍqQ¬Ë54áøOíNNßПÈ}FÅ+£ÉÔ”9Ö-2ÀÃûÛÊá¼ø%u /ô熶±ßŽ,‰Ø!¢åSÃ6pÇt™¹W½6÷§¯á¾Ô£5‹«TÏæw´<Qô"´A2ðoWl«´íçôCöJZ]ÑŸ[m§xž‹µD[~ý ž‡½£„k§o^ïÛèië~—ÿ>ÕŸDŸ†§|Õ÷¢£wIÀ^œ…²Ë9­ƒl󼫗¾2¼ ô, +Ãææé™5˜È:[ŽHÀ¸cÖIï´.\|7 ¤ê÷Õc §ôÂù dz26‚ÎVpcY°æþˆ¿+”Šç¸Kûþü¹‚=GT.ã9‚ Dè]·Ð6Ço?[j$ÙOÙØÞê¬9Á0:’™Ò*°ý1îîVn%~ÄçȦ'“{_`¼Áq¡×%%DT°i/WZR¨ë ãsTˆö[Ë AêŽ3Xé)õ›À¡9ЦAMñ¯9±»o ÀÃèAâÍ9~ä ‚ÎÂÛ ‚²2ýdÛ8yà…l-å¹aòߥ‹õr— Eh^MZXx4U‰¬¬Þ&þÕ¢G yBP°;`g×ÑŘAPÙÝªŽ® Æ$éÀã`ßè ó—ÝøY‡S±öÛþ˜ /¥F0Ê ‘÷ ±¡Wy×y|E»G!âûoR‚9¤^ã K‹ä €±©êº6¡P5=ªý0é fŠÁêY{¹G×{[æNÚû:e­}F#”Fý®û L¡  ä{1ް#5®a ¯õ€üˆ2¥ùŒ‰z4±C<> rA2)^Ž^æÏ­B?£yP,úˆ®nŽÁÖ²eïÎL_0&@1fÌ•i? "ȦÖßœ5ò%ŒæLî§™Yq­žó' Áàn~À¬âô-Uçì´äÎŸé²½Ž¿A½{Á »Y‹_Þ´›ð ßµêMË,ªËwÝÅh1—¡]bHqœÖšÆžX LN­ZwH* †[8»íÈkUW—™ºuòŒ¼a|W©4‰‹mQìzb‘Éè;ÿ£Yo:üþDŠâ±Ö-1P\ÛgËçÚLS䔬ínÊ/ódŒS8e–ã´å_,×.ÊH3IeRçª;²>• %_n¤ÖóÛ¹$nêŸôš—_˜Õ}º…ã#½0 qÞÜ<Á†BÍÂ3ë¨xŒ=üø,ÁÇ#%ýjEÛZ©|»-©Œÿn÷‘)ùJžjÍ•]Ûkç ÊrA­áߎȧuõ‹gææÓÜðŽí$‹! Ëï\¥8ÉGJ^(Tc™óúç…BvæmŽJýܾLV¤«¬Ñ*¿Ñ“É4Íìíš“ÒQ{ï:»ÀÍjeýÌ£¨Úó¤¬÷ª¿Ÿ£ä!ÓlÒ°#•ôY÷cDKÙ­S)BÎÒNGìÞ¢­9×@x–ˆ†çE½Å¤ªÒÐbnÔ²Ô7Ï'~¤zµ 2Òý÷‹ÿ9æçò '>\øâ/Ê¿ß ®ó“I÷Ž2s7žä²¢÷¬]ùò¬?~›1Ä’}v]ŒU±›²¤“±ÂÁÇyå’µR*«iÔ€¶ ÊPñq=ñYN"õÎÛÅ 5½®æ‹äˆpºojèp}¢\b›S»A/|'±…)=ªÂ‰=´ÉGB ‰ÃA#ÇÈɵFga5ø´µÚ×ýÄö­¤ò›^¡Üԑ׌ ‡9Hï5þqéwãÄk‚CÊõ¯ŠVuµHùÜÛ:Gt÷Úÿá©öÉ ‘’€€ÇŒEaPͯC<ÓM'ÈÉìešÑâ§q8Y1%¾h ƒ¼kÿ–M cÿÕìþía—/zü¼›$ÌbSeí Ìá…ÛöÉxWµ¶)Ô§1´¿#!núîim;ØÀ¹‹ m±=:–Tû-&Ȧw¨B\§3©¹žÙßÁù™b“÷LÙ–ò C\#ž€¯BÙ!q,5¯iËØo ñB£™«ëa:7? •½f?Q¸j‡Ôµ ¸rË9ŸNÞ DbÙSà{´Ð&IrYKtäÚ^=æ1Õ$©ÖÁC³5ç;ùv'qÓYü§5߯‡‚ígTcp’xUag& Bt?Sb›úpÖ?€gëSØúLp,F!ŒKÓs·=N¿ù|+õe,ëpþÌþªDl/»e-Jxñ~„€Ú¶Adbü”é½¶¸)>àeN4ðnR,ÄãÇç˜ÔÁM/5úµÑÊ Ÿ¤ñysÜ&é‚£…OíœøB6µA°ðBÒûæT<{šˆgÄwëãg8—¦7 è´MUòåzË•=oÄøýþw×fs?q\ÏÎʦƒ|Ñ+ö©¾5›]Hcpµv&Éï$ÑM-—‰q ›´•×#¥­—޵c)[YFgá+¡ÃõEaH,ˆ!¶ ƒÜ{ W üéåæ>$pö3ùôŸ“yÒïƒ8LÕÉläÜ5/àÇŘÏq7å9Tvy(Ö ,‹Å´O=—ŒJvýw‰¡á ×yò Ú°}Ìãš-V –"„EÎØ× !ò^sŠ(ÑãuÛBÍŒr8HK„?‡µ/²xIb8¿ÝÕ4»@æH|Ÿs#æ]TŸÓ¥÷/ÐÔ Ø4ÛÊè}v–«Ò SÝ•EM¼Z-+Èv½™ Å@/[’f(wvÜÛw­Ú[æ´¾j8¢Ó©4 וœêÎj€:„C¡¿}º\iùÈ]ìÞ¯ý˜ÂF HI»óL?dHh_§žŠ¸ÏpÙæm±-FÁ~C–†…†ƒ §Lñy@o”Ñ…F³EKQ›0Fkím,€W͵4~˜gx¤=h2/_$̉áL_xÍž¶ís ºw™ ôRû¾5¦ÐQpØq&×Ú¶ï“{UšmÆB$m™BOõ´"Þn ê¸ûÀã ÃZb u—?BÃøà¸ÛðXÍrhHØe•­’€€Ã ¼ŽfÈG`‚ ©»ÐÒë8¥ýçÅÔgÖØv3…¿É"%ê]$LÈ-=æýœ_ø„Vò'y®/šZŽ ªéî7ª%hƒe5†Píºa1&mó¢^OÑ)“”m©þ{äê¸Þo@Pw-ÍÄÞÅ:Ãlë@tn¹ë(çogíB‘nÓü7Q÷3”Òh»kÅÍæ>çÙ$W¢©ßÌ»*VØJè¦ö¡´XŠÔ¦qrCzpð2å/ŠíúJMϧ¿"ÜóÒúK³—™„çv}8“¶œD¸=Y³e™_Ñ"ÈŒôÙª.¹­h¯¢õ݆îœ8ù­Ä|(‡8P=€ÈÁº!÷ÇI« …~·˜¤«ºªxB_×fÖ£ÂôÁ.p§[òý‰ï ËÐÊÅHíhýèÐ0§ä¢°¤sP`ˆìG`RÖæ³ÓÔ&{C‰@Qs€')WRÃ6fx€Æ²š6Éî}å n[c €jly©IÝà³ÁFq¾ VOPhPþ fËTøý-,BBGpoü«û¦#C0ŽY_}œ®D«ÒÕï1ß`•Z™zäe¨ìR©º)+¾ݹ¬z.t ƒ+doMàP­[~v+Pwqåˆx˜òe.ÿâ-†óÝ?îëL6gPœ3øãÓ†$8éc$<°+7„rÓ[ßOçHêÂwæÇï&Ä(Þò \o6¿Óì㿼AlÞœª¹Æ¹¸<cgW%¿L—åO[­Èp"àíõW¯G¬:æu5-ÈÚâ•$!²|}…GL ƒýxPu·1GÆ–aKîtS4 Ån0?åS~κÛŽÕñîN@<½§Š‡h#hH\É`‹ºÙ—ÿ¯ØÚÝÑ—ø‰/A ä…V&ß•u_ ÞmÖW}³/L˜/•?K…Rhðí €5Òð”—%€ÔîJ§n=J\g€¬"(š·$Do9fñ>Â3kÉ¢2Ù!0å¹è›ÔÃP”2*í¬3çèÀAIU›1~˜<òù/g®Úï«´0‚z>ÄG_ˆ[ì]Xy¬pvÜHøËŠ.°¿³öÜ/”˜m7‚Øbë+•–rRV{k¡¦/fO0îXƽƒCHÙåû_Ø«¬†•íIZÚ¨ÕÇrȳ÷°÷ä]1¤OcVî „ü•Â’€€´e=OaÌoÅ÷D¢í“tR¶~Ž`(„E ǼŒQå… ÇO.Hn• \`$ô"³Góþ•·Ã¬Ì;¢',Üm÷²™ú§« ¹P¦+Và_ÂB&LÛŽ°ŠOÙïôÉk·=ZõÍ&†"ÄZE6óI¿@è>÷LÊ‚¼@t“°>›`Œ«¬̾ЂçáàIL" ŽFÜ8àdܳ%juy†âE$¶Ü=ùÐ+ù¡ 9hèo¸Ðî®®%Tª:œõ.%–Œ*‘Ó3©ü–ózžE1'@ a·W2w£ýÙX²Ú"†ŒwÄÖÍwj¤c#R–¯©ç£î†Þg ÷ü÷lj΂‘µQ“®â’yKZŠÅ0˜Ûx€Ðù0lÊèÊgm{oŒÇ{ü`ÊdÊ•ð9•àÿƒ"kóãÏÒxßµŒ|†o ØEgTÚä’“ž,iÆóxÜSE‹¨àøÂàëŠJ䨗S§:Ÿ²iºÆ‚-xêºÞ²Éoß[ÿÀÏàÛð¹CfïkÁ剄fHlEx’†ãFŒ &Ëô>q{4âIéôéý…3*Ýà–(áAÕl"Ð…JÚä1NËÝÿîsÛóçrˆgu´þ1ý5û–‘µ÷®ÄT˜œ·ÎCuBÀRÊW$<ÝëL½Vˆ>cc,Xi¢Rêtq‘uÿÒàÜçÈåu1›-óÚul‡ô†žÿŒ!ç½Âwjøh…_\CA^-¾ z5ÿõßanÂж”!7¥Zuµß¿}ŠŒ}IYLÍܨ%„êiË„—òôØ=׋ð>“5ÐÞ"9§7sW›˜{G°{/~ ‘ çŸ—_~'¯–\æ‹f3óÌD4‰úšEì–‰)c÷`$ìs«|•Ê<—ï»ÓÖªf˜˜œ&Œ¬ž9š½£¢º…ß|̱Î×ÇRé^pc<Éÿ¼üáð-k”P9u!7ÊM 2<Uõº©Üd…Yk3µ ÑPöí‚ÝÃutÝŒO"›zVcÃ=c ¨ü`å“Ò›.'п’LACkh0&y/ë^s•½b 趃b­R0f÷iÿ†ì4f©)¥GÃP›ÅT¶öã€OÕéy8>Ðø#´l§²wŽ5.?´’€€Àzc»©1*‘քŹ (ôÖõp3§ls†»’¦®«7'ÍÉЖÃi”íÉiZg³k4)·u)íS1ƒ kјòäj_\O·&†²¤½É0m ŒDVJþ²˜ԙә˭Ýz®‘Y(œ>qžS5_0Š^÷ß^¬¨Ø[ Þ*à‰¶‰ùZ ½è^(\~¸,„X¶0n.‘±ýɬ°Ó-ÕÞÍûRJÅ'2IOM hUjÝ­þ=¹ô ÃWä¹y0Zasg’¹*N¹Òçh3* MÓõ%B‚xñò‘„aXk„ôB6š¦ÍÖ¸µÜÍStémæIˆ†Ûž9IW½vrP•ÊN”ÏŠ ôääí$ë¹Î½9¤××Y7µ¾Iß²Ø=7T«cu¡QˆÆI»¼ç_cðbÜå5aeJ}Eg5º˜  3'²CRð>’]A5Œ=sô†cb£ÏŽñ;b0&Äaþò¨¯;¾Žel-ù`È9 ­§Ñ¬wŽ@uÂ"+ÀËj\Ás1*ƒ8¹öŠ›n ±žVÑl¢}Qb†#iuökÛ+µ—‹Ñd•[GüúÏ ¯{ö4áÜh3Œxí±`ûÇŽÆÍÏ`D;íöSä4áôšá»µÌ0îÔñ#ß„§zØžü€¦ïh¯ 0/YúcX©ò®±L˜Ëü¿<¡Ð¾í² —z,’–ÎÌÔ×ý í1t@’³vbä/tÒíõ§ùzÌ?–Á×N1I­FÑ}¾>‰n‰ny_(Ò'Ö±è _ f6*dÞÈPæAÚµû3…A†¢³ç†±ï8@üÜ0ªÞ˜€qS’}»§¾O4Ö=„¬A¸†úÂBoP³ÿ!ÆhC>Ð ÑݺC¥ $F]ä@%wIœC0"‡ÿ¡È 2¬ßÔÁʱ¡O€²<4¾›Åæ‹Æ,Ë=îý°¶±ÑÕsIªTLÐ|]±Áj‘X?,…Ì÷Ÿ5Ke †MÝÃZÖdËpÙºwDÚ“€ÂÉ> †/{¯°<ü0Y›aW‹ý« Í|”sÓ.*__lÈæ8Éš‡¬Èär!¡^UkÈfã¶h9Uë°äþœñT&5ûRüTiJ—wžptöŠP^/8¯£èlôfo`Š+ÚlKïÿ·~ß¶Ê&¿0=–ÈbÑaÒÉQ¾°mòU>0Ç|a›ÂPˆ¾’°ÒİZ:Ê¥•|dên¶†£N?먫ûFûˆlÍk=âb!×Å-oMÔ›!Ö¾YÔ.D»Ü›:¦ õp ÚFoKÕïNf=êSà†j³±Câ3\ø ä×QÚP•sõ·Îµzåàã ÐÂDº35mÆu)ѧ´±ìFJT+™]Ü û£úØ¢ÊhiSí*4=ÚüõØñ"·È£³ÚRé¡Óº^Ü$Ъô@ýép“Ü UÒ°}̸¿¯Ì übÀ‹D&Wb÷æ½2§éÖÏÖa…n» (ÅøÊæeÇK+ò Á¿wBÅÌ3â'1Žª26”½b“nþð-©Æ>%²œ—²*ƒ-õ2ï[(±5=úVAP«»ÎòZ?*¸ Gõ–ùx„ñ“¥ f. ˰Z‘ûüÿqî$¤ID¼ôæAJëˆÊ¢´jÏh“ÑÉ!^Ï¤ï’ s k&uL%×=´Mާ%GÔ+å&ÜŸŠ/$ÓÛ;{^'ç+šĆ8·C±ÒË.ˆ«b«ÌP¾Ì’€€¬„;KËDÓöL›âûÕÕù¾=EÚb1‚€añ¸õ2ÍP&©?†•5² QÊ:š%)ÒÆ?1Šèå8ÂÂzoŒŒ37 n"_ѳN<;ãX8›-xºƒ 8=?C;†®0½ÔÊÓîIk!H0À¡ö¿3η’¿E¤ÿ’Š•,Ë×®'Ö? Bê½D ‘õ-X+ÿô=¿ú :?~ï…IÑ<žÃEî(óMÚ„j¡«jòT½žÖ[UÊ]EK'lß®ý‡V ûì-|-‹ïÅÞCÊŸá¼zË üš}N[V!âS¢•„V‰Oo ò÷ :¾‡†X‡6kÀ_h\õ×—ø&7IQù°D4øæoãÙgÝ«éÏU@v¾`t€Oràc ôºQz²µæ¸œº“s•åP¥9GïD‹²ÍCéóÇ « £ô1_¾Å½]8‚›t)¯!‹ÚD)o†ºôz¿És×d¯ØZ¢iƒW‘/RwóŒœÁXóqŽÿ}aXÒ« ¡^§Fí¢¦( åϸ‰¼4ÐàÔSSIú& ?âR°¡néú¹6ñvä”Ú“Ù+µ­htÚiW©`äý%âÆ«ÉTŠ&™ê‡îº[pUÔ¹‹[y×ò(âá{|8ÓC Á4ßbƒ†Ÿ”q6’»;Nfg5$@±õ€öA }ÖNK;ϧ“à·{NhjR¹mgD6`ª¥@ õ¨$‘{(cuùßæÎ2°;>åÀÁ•*8ë?4ŠÓ¬]=*­qŽÙë·b_ÛáQ†~ߤDJøøþ“|jõiªî,¸Å¿gL—®RSz à'¸Õ}µ À’Q`U:…vA£x`Íómº9`WÇ,ig…£jïîÀzõq˜mË™{]R§9 V¤1ØåõIÈ[|x©â=Ä ç{¢&K_aåIËb¸Ò°Œº\älÖž—U|°÷3Ä/³5/olS~R‚fè’€€ë’£ CùEëAyódØLÆLÖ¸¸ßÖኩ L»ö( Zp¯/»t©íuèÛK1\duj&çªñÝA¤˜QtЪꇮÛ݇ÕSE™áNŸ® ôºò+ÖƒÒΦ©™U˜ì÷VU+9íNÎ4ƒ‘™h{Ü€ªyU°_äP™>V]â g•^·Íö–­;ëÁ¤e‘\]Ú/Ý6çå…m¶Õ›s%¢óàÆåþ½OÅmL_‚8ÕAÞäB>F6€q§ñ»‘±±#µkŒFÔ¾6Ã0¯]@äEæp%÷!}Ô6—;.±ÔÏp±êàí ñ¦Í{ì‚%ÊJe6ù‰À 1 ù¶¤‡• % òk( Ü'IÅ€"¤Ã_9zÍ$;Õû›ò¥<Î|aBæíI‡G¶½Cë64^”¨V~‡8žüЦD0*à SçÈÌð·ÞNî¶[@èl mÂ_,7>Gi!ªÝ½Zz~ÿí¡´.Lnô«¯¸£fИJΜóð…uÄ"WÄv:³Rõ„²âbw‰ülêÜ 5œS”î'’P씦N©{+Ã>%Æ‘˘á‹¸zöpi§ŸìÙ?´‡QÒS÷o:Œ#$vD !Teª©¦’ð=Œ•†„Xak~GU>@š÷ÐUÂ/˜ñ³Ö¼KôXQbO.Â5{á’j7ô’ßï<€ÌAl\yƒ~#ÏJ@ºK×RK.õìÁ«‘÷8䨅±­î4Cn¸Ì—µæg· ûY<"’g?Sä%È_Õƒ·š@å ¥(q@M¬Ì'Að3,íQÉ–¡&Š+xú…ñìf¢É|!¡lÁ K'¤ez/«µÛ³szîuhØM³‰4óhnnÀ=ÇÙÄìêüíZr+pˆÝÎ;6ú 07I‘>»®¡Jœzo>m_™JZoZë”®M·&ÜZQ¾þNfñV­ÅZ­[ÛÖngœ åãf¯[Un™xŽÑ`æ$/Jó¥¸[6sQþµÈ›-6X²Æ·%öÅóP’¶(šëèSaé‘ôÆò³Sæ¦æÄ}|¨AÓŸòì/¸’o§{ CbX¡·êïÃC"Ð]:zc…ª-=¼O,­ÑB O]Âeh^O’k¼jÛ*\² µÏ3\-ù´UAFÚò"‹­Íc’¨èTÂ0!-%X®á/j/Ž‚$ƒŠf±„Õ0">ÅîEäÕa‘ä½’0%Û†í£ŽUºR{ï~£Ý}û¼”2å} á]Ktš£É„áí:;Dz„,ž„m* ‡Fä’ˆshíUýbÝý€´š)h綠 Iëy¼ïBZNâ’Óc7[O~x9’˜P¥Ê)ÝÍM×no[ŒÝ°ÎS‰…GoIžìfžxÏî»jç{Æx*¨š©†ŒróhrÍI´>5IÌŸ?ù Ý«Ì_XEMmÛ×Iuz¯FÜŒì×Ô6éL׿)£S3 7ý°ˆá¹Zo\¨µXm'°wÔ@Ÿ…Z¦Ê?³ÿËR±’ûr¥ ÊŸœçZÜXI‹¼yT³Ð%7F_»µ¦©Ã‹#‚ ¾¸AyÉIcÀÙJN5•­w 4#)«ÜµZVV°B=ݨbó ‰ Â†¥}/ïó_1k™”¼m±0‚Ùé÷!ñ06tD‡wÿÂQ¬|¶äWA´ïèÛʼkR¿[¾(fU’€€×mé%AZê¦Dïݲõ?‚7¨áQ•y‡‰ïã á·¹¡Ö±€»B—Z˜•%kgˆL¡NË4f0Zt‹¢”¢LÇ}4VÆßW*'í–Œ7‰Ê%„ü7Bš¦^1}2wO‰…M÷ô$ ldOy(ni˜sÞFvUe´+ ‰µ‰Š Èa1]-ã)tkÌ%ºìkЇ›@é“þ”¡¼ ñ cÝšÙÁ ˜Ã ß €7‘J‚xµì*=ùË("]๎;X½ƒͬ¯L1ÖNÉò‘¹‚¸•‰›ÐÒjŽ ëÁ"åE]ÑŒ°&çšàÔ)cl¶)Å647+…)Ì¡\ìŸÒ ôWÅïÃæ¼ÔS`?Ü-”4õo6Ù,Ÿç[)¥•ÿ±Æê)uƒpò¹U›Ãö•âKx~Z€ßYêëyA…¢ªÿ6æPc’ù8Þùãú˜ë{£àk{f—k^‚IX£{¦jêØ³á˜é¬ã†5OÝKÑ`άZ ¤à÷^_Câeô†Ùó˜št“ΔóqD ã©ÈÒwÖ ¶€I¥*3Œ=’€€ ¦;ì\Ôþ‡®ŒOI1Æn†hVdö€ÇšËa˜ÁþË8NÆIëËçF§ Sc¤r™tCܽ"C‹éo= לeBß4Y óÉßhpÒ‘˜Æ‚f7‡•&?ÁÀ?7µÓ¥’øTLðÂéÔÔí@˜„Q—PÄ“¼™ŠRãhÝlúŒŒdæõ\,'«G—; )ÚsX¼þy¦t.EA¬ ÛJ”¯Ìa{_kvn…ב…úÕ 6…’DŸNÃIO@ošTÚâ)0 Xå—.ÿ: ÇÀ}Å+‡Ã èxšíeÚŒÏy®ÓVrL]šˆ´â8|ÒW $M¶§Qwõ ^n‰1Ó$ðR«0ÜrÔ }αÃ;jü="v„{³(…qÂFh~VÒWöõ‰™èÉü•¶så+&'¼‹TÇqÑnî÷çñV j[˜îjàíêˆ1q„¬ƒ‘›4ùÔZÍöCsfÑžxZˆ~îqu&3^Tí2|†„0lR+L±U°—OðÖR]VÏÙ}2¼-^TbKzÞg˜™ŽJ: ß毪Ò nG€‘ƒ¨lŠ”B²Ïâe¬·Ç®ó&Ú’1Ï϶ձf¦oXoÖ"ý©¾’q ç4óºEÏ´þù˱áÞ:Ð]…ÿ…¢L¶ˆ‚.}Z„œ'&W{ßX›Ô‡Í%¢ü]%eâø¢Šâ¢[æèÅ€}+‚QÒöè&ñ|>D'‚˜ëCJ|¤¾5.üpü˜ãÊ6¥ÍÐûüxé_{’¼¡ÄræûÍ2Й}¾É1Cê¢ë}àŒ…¯@¨ SdM±×h™qÕÁí¢(ÙØœqÅâjšÛ®O’Iæ+ÈyU®dô]ÙØø,'úx°À&—ècÀ‚â„Äå~k¶šµÏ¶0˜cb§ï!\ÑU„, 1å­ Á´à³CÿõaÝ.€áYÒ¾’ªÂŒ“v÷wÀèeºyy›±NnhëX\˜hìn}hNJ8e8‰hþT½xªÿÝ…pÙì!h=çrú ƒ¢k™Í’Æ¿Âïbüš‰*ïLö9M`”Aó¥9¥Þ¹OïÉX(´óX< ù+;|B—öe­˜#G‘¹)ß;ÓàÉ3wÅD@‚èx›9KZüj½3—û÷DËʸßÏñÖªcº ÕŒfF^e âýE’€€Èà´ ®¢cl–˜AE)wi±|=Ö>‘b¦äŒ×²ç:%l 3ìjµ#bÚ 2GÀ‹Ãõæ–ÖªI|áEÖR›'¤"WL æ¸ù÷ï1€R¿…kŽ2ìW6a %–›œ%:`^æ$DÅWDˆýͳ³ßbyÈ!Ùbe¼I%мªÙéÎÖŠ¬#`F„ŽÔ%ÙB}L*í:ÑÑü–bê…D¤z¹ÂcðQ?Fé΢#Ó¼D5·R*~þ˜ë!½b‚/Ìu;V ç“ æu?+x;ÿQ§³g„™„#0PÅš(]eÆR–Ænf½ª‘@âß‚ª¤ö)YÑ=Ê©Õ .*)óX´ƒƒR1J¬D•™t[½8íSÿiyYr†·=‰ŸqßóÚù8/4CŠUlƱÐ2ÚfÍOAñ«ØÝ¢©3iÖ§µ«D\f&†s¥I‰ªÃy®@¢Wb°=vôçÅí.þ m§Fž¢´ ¡ã˜õçÆ¢œ|çèÿ®oX…ÖÏÐ…­ÏÜ/ æÀÒÈû³nÅEØÄ†m[ãw¾Ã}Y©u"Œà–o;LJŒ¢c1…Sý>ˆš¸" ÏÁ½pœÞZÀB6-W·÷³Ô«á¦È“cð(/¤zòÒµBÛ"²ÑÊ„ÅZ×FøëÈm384Ľºë•« éþ—"mœx3ë±¢M;t+±WÁµÝŒ©óüL¥-›TÔ£E¾™~Ã×§¾0-éÙµQU†d@·T),׎ <-äˆÉ®Nõä¬V»ÌS•~LÉÞªípô\ d=ëQ&ßK€*¿Ü«\ʶ㰠uïEn+,DzgÿÉýoÙC÷jÙ{¤duFIeÚàã¨sÙËÝqëã+|¯,3a—÷*R+ Í8÷CûӉНåÝ~£îJŸ÷¥Š£©w‚{©r/Ä—[8YÝ)7âš2J5¤ï(ä’Úþm×.ÁTN¢Š<ùG%ÕÄn9gÈ×Ô[%1ñÈñÀ9D6S˜}{b Þ_Š3 &t›Ùš-°ÒUú1Î0v:PF×õ|õŠO»©ŽªöÄtØ%Kø˜geKâb¸™4ªCÛ3öµbvð"ÀàÓ¦¿°õÏrxwξHCÀŽÜ{Üb#{cDªe7o[Ë´nþP¼F?Û R’€€ëM#]TF‘ˆK}_0 íº–(cƒ"]º„spb8ë±»øÇOØMt[Š«à‡u¸´ïÕ&ÆO6Ê0|p¹Ä黌ɺPJ…a¢|} Ê`|—¨Ã &¸ÑC&A6) 9ÖõT°(Þcˆ>'—ŒA¡A$°€ùt®£†Ìoß½åO2!a…(ôŠoÊŸÁwM±G9·ƒO?Sô)ìÍç»­sœsJî”ÍVã\8n †ákV’Ÿ†¦3Ž% #]ñs¬ÀÞS8Pd¶Ëm£ºhèS=ż‡sv¥¦Ý?í…%¤£} éñWÝà?'jì½–Ì,Ì£TšXËü\¡Q¹[Q‹@ùŠÛýÓÙ‡ŠÑ Ü‚Så'´lkÜZÊß Ö ‰§«=É®4ò"3¤ N»ð{‚8Â7idç»3A&)Ï@°“þf;´þ¸pZ¿®ê ¤m–Sæz´ñ’×ß°ºuúv$ü¡x‚=fª®xdµA™,·•lØÞ·0‡ J€ÊE7fl»çvþ5îvÎ_åÐ|µk H1Í ™- p倖%^ ÿo‹'yfíBš¸ÄÿeÎ8ËS¿¯£…䓲 C)Y¿žN&ä®GèÝ&+j…ΛóýkÑ9lûˆîpfm iÞ¼8RÌÜL9! @zg¡Òþ>" ÑåIYÏÚè¦>ØûápÓ3ðC;ó·ªq¦öÉWIpâ5²Öα¡ÕÌ’ÞÒCŽm>ÉOëÛ36¦˜“6?ûÿA64‡M¦Ö+Eœc({aÈò„Gýq –!šíàKÛvN¹¶‚cMqý NEI¥`Öù©}ŒþѧÌEŠÄüš]ëÝT5F:*òɲ3ö•ö•™­0h{›iILÖxµž$ Ѽ.=GÑÆôÚÃû;,KÚkZ\زÈWçYjØNô-ùž;+”•Ic~‰~ÈׂÙ0 ñ¹«w>۲܄éD×·§^ÉæÄÄô«ªbe¥Ñh–„bñÒ? éÍ÷ر WgrYþÉfÔO¿AèyÜp¹:-‡pcÅ‹+ì†Ó¤„’€€¢÷¢ѱ-÷"—l ‚×s ¤q0¡äΉq{.EÉ–µF€·ì±óêìo²àb=±)†µߌշͣûyÅ!ÌìtÕM¾¡mŸ{‹4yq°kÉUîÊR£ÅótŽë¦ûªØ¢T8ÓÒv£~ê' «¥JDÅzW…æ²>aO-K‚Z"lÔw낎ð)ØQbÞÁîj¦šæ£.E˜U×À$¡f¡ÉÇxàäíÂɆc&q_Êî‘ã:ZOLÐY*ò~Žî<Ôò<w?>9ç çG€yËNÕr'í’qJVSh¡æuÁ¶§ÂÇÖuoζM^à©Ùîãa¿ ,1ÔØTÛ…i 0nU“ dô\ 3÷~4”Y ýõõ-0Münyš¶Lšq÷X`À-{þÌYc[c§ÂTGV¾)#³Ôª·ÁЭmv‰É”rªœ28Ùù9»…§”0ü³Ëš« 5zÈu3’žGŸEéA­ÇN+È68)«všV³HG‘膡µ@˜ÅnZ/3ÏÁÇkToð¸~ð˜mË©RBVËKÂÈ[¯÷cjïAån|3äÌì·&ˆeYÛ­á±…š Õ¹ùMñOØ´ÏÙ•}¹Ó­©Ëžf‹RÊï//bwÜY„ñ&÷dgµ¥;M¼l×;À׬_8wû¦¾¹Âée…S+ÂÔ`A§C]Š¡¶%ÝÆò.ÀÁrÁÖ7$!ô·ÌЧæ7«Ÿñ™¤aQˆ;âïç\À¶à“zùÇžœÒÙÚãkQTè7¯Y\z½÷›À=4A±·­˜_¡ˆÉÄN‚é³j^ÕmãC ëËÁ[ÉK ìùq| ƒ1±¼r:qß"Ù†òM3{ŠA8-ŒU¬ÍÎ4±/k¸¡¦ÕgÖ°h8ÑHêÜê0¥7Ò–‡a)Ù]dÛa„9Fã¨û2ËêØÎö–ÀWF?J*I¹^‰±¥»»ÑKwT2Ž@:1¬Ý‡’rYƒT ]¼‹AK²¿é²ãÔ'¶áSIÏšk•pÖ}Þy9È º¬pãºÉGÉáßno8QJIÐûéáHß³cÒ×ÒiÉèð  Ym”Õ=+ÚUÕfÙrúO…“ ¦¤FÁl{¨ôQ)´k«xÖÖ§¶£þ¾P•ð´–£»o¶Èlü^ó9ÜJuGˆùT°J߸7àêÏ7+}S¼1ø?+MÒ#€8L1ç€ÎýÌ™ÒX`Mëß;Ð7³×òÝlÿ»9Qc®øÖ$¨É G ykÚãõ7‹"fÔ,Yì!:¯q4åöë¤ÎÝÏÛ˜ùÑÌͩñi@ Z‡Mì*îYcÙpߊ—ÕÈ1›W[yv9|D"Îyb+1§û• ‰ `@ïrú¶Xt(qA˜³aüÕBè­ºˆœ’Q…@ÉÙ—)ÅúÊ\ý flßO‹7¨< ó ²¦ÿN¡“ÕÜ ¡v2»ûä<‚¿ÊÑ%¨dž©v“ÐEl¨ ’YÌëXã~7£¿7¿'8J;Ÿ8.¾ÞbSm ¶•9¿•Ë7ðÄbrMdÛHŸäýkÂ}«žzå…–– €ôì¿ðÍ!6z¿«wÈ! ùÈ·Uý7›ís$^Ïo¾—'ЬŸ‚Øž)ó.ûm¬<œCνôõu»£§Ó/¶ÙÎÖlÁèÜx•=¸{*3«Eˆ¦5ëáN®”»” 'füØ|ší¡á¢í·*îPŒd·mr*§øŽl²S$Ö ]´ñx`OÄÁe­}¹õn~ª_Î¨ÏøÐ½Ù¯ó´µTÌ.9QŽEŠlæÃ7Øù‹Õ ¤Ó]ÀÊÕävñh ¨$/ˆ0ìK‡ó˜†V ‹Õ‰éÏ`HdܳX-} šHêj9¢µî0ε´H|¶óþÛ#´¨¥´,†Wß:¤ÏS÷`À31­êÖ™éÚ€ wÛòÏ_lI:°4|*Q† Õ2¶Å¡6JÎæCÇ®oæ- VzÝWÇu 4ÄÕƒ¢žÚ¿Ø›Bë ’#Q¾Iz ³qRï—*­åÿ}¤ [/Ì™N Š „Wÿ]ÃDcÿýW3ã8œúÿCV"F(ü)à#è+ڽɰpéõç¬È÷k#¥.g™Ïi (Û°² ÏZé&(ÿ Í7Ê b#´kV­ Z[º·r%SHIä5*À&Wîì¨E9PµÑs@»õ{¶×ƒ¼µTa+–Y´.ÌU¾hAÔX}ÕèeÁ/9JNj- Êa\¨}ªÇÊNiܾãÇv’€€«ç“x&@ÚMàmJ4v~½L”´ÌˆÍìä|DôÉÕ(J~ÑÓÕÌ“eYH×f% 2fäÌ«fKg’E¬ðrǨí 1(¥Ô à,”Û±R™ÉÚG‰]jǃtfêº&GxÏ¥Í& ILÝ0Àµ¶NÞ¼B(ží°ÃN¥rd‡µXtŽ]‘G;bDq}IóÄκGLC­üÄ›wê`k7-€¾TY€œAG2ŽúrÝÁ,5œ¦¸¾üÜ¿N§9¯^9?íYÉ'*繂0ƒ…”›J%ÓÝSâ¹1Qµñ×S×VöÔ§ò£×fè²zç{óðkÂUág˜P’$–Í<³[i|4Äá ’ÃótQ_gYBes=,süµ€KÞÞ X{Àãü~—ÀÃÕ¼”ý2ò7É䣱ª’·R¤”!rhžï[þÞç»?4œnäoGȸ$ Æ/Ák®>6™æ/Ü*Æ÷*ï"Ý>M@‰Ú|þ+öÿSøHM!$Ç@â„Î"¬þ¥¬Ê&§sÄçò¸LcÞÙå°l—`~ESÝo¥¨AQl¸jŒ©:œRâ‚sÏÂeLJ&^†Žì/m»[‡Cówµ{÷4ROZAõ02¼Æ® ©Ïi€(À)ÍÅLŠVW`0®#ÝÂF‚}¿·Oê.P^cÈ=H½ÛóHÏx» ,ØãôßþdMƒÔ üˆŒ9 ”•å¶Ïþaɲêɣߨ§JEÙŸ‘-­`m—°2UX3@ãöòMD…KèæåžeœÒo¤ÏÌÃ,˜ Š´‹Z}”¨·`ˆ¯_E»“L÷b2™â˜,î'Ær¦¸‡¬÷*ÕJ¡úžîqg[K²0ëáÀ…A†6õœM'ÁwáßI9jÓ@ %¾ú¿±M@ò@—=uê=}j»ö—‘Ì•xß4ƒ§èë’(5Y3‚ŸnÇråãÌ£zYûÏ9:9 QÒø™¡AŠcµmðy_ãn?y^²n¨â(·ÇÆ(-1{Ûs">V®8?ã¡w‚Ã9¤Át×x €a†€ÔÌ¿¦ábú„kÏK—^€Ü#óýrÔ‚'Ñëqý=‡Æ­6ºd\¹|+PÇBº5pbŠ/%7ŽäxP[GˆQ-«=kì¦Ãh$ÀGÍp6w\ï„ôt)ýv†‰ŒL’€€»û…£n߯0øìG¯´úÍ3t#õ0ºö̸Îmu¦k¡y`Þï5äÑ÷¿cšt±3Äç÷u˜|p ÿXÖe˜S)~déùàbWwõ@ĺp¬¿^R|XÚ2Œ} ìõWÈiÕ&€EŠèwÕ/Y3šB7*ù¼ ç^˜/‘ ÈkXéÓTI)Çê^ëX (+ës/9[?Ž,±z—ièÁyô²_{ªë¶Q»B¥®Ã£ÇÀ2¾PJÚb\z²ˆ•‰Bììq‚)CC¢D_ÏjÓöMrd,úÿ7s‘ÒÄ—>›x¬=1$Â.ÝÉŸkU³ÍW‰c ¬ÁE£)S¯OBµ‡Û΀<ÙL…Á¯ªŸ;æ Œ†;FCu9ÿ))ëÎò1Èk`Îz\¬Ê3 q%›€lˆvWF ýÜK+O B)ôfB#"$àÓa‹¾^Bˆ¼_l9¤WWdìH)rµrz +ùåÕ†úUö6þ.m»[-B³ju¼ lûј•¤„ipøÓ„)J±U–Jø\6áÑA§Ÿ»±¦ü…—P"(zk‚öïÖœãouÿÖõŒéXtÑQÔ§(ƒÀ51Hm„s<¹”°I‹0â`¡ž)7>ê¢ü¤-<†ôêÉñšM0µývKþr±ŠØ‹®§éű ‘7ú¥u. Ú©›ö@×–ü~²fÿjJŽö?ç??9ïŽ v«5”ï|£è­Çâª2Ú|‘Àlfa£Ž/“žÔ 6¾ˆ”ùèk±ƒð&U­ÕÞ ¼rÆGTÔ8‰ïŒdlpõ_ºú’”’€€§Ýë¤ÎÔ¨|(ÃOk¶3ì–ÿ²ØÖðɃÀIè9xSwdg8ØLW7A“š™¡SÏ`OPH/šáG]oö:ˆFãÂ:Zª©ÏO˜Ø‚Ô_FÃñŸóe$¨Iј´ì«.zt÷®%àݼMÁÝ§Ò š’("eÔvï6 ‰ôSwÜ8ÙÍ,ò£܇õI¾þž‹ð¥ôÏfJ4;åÕ‘¾î5Z1ôsÊ_@² !r˜9¿®p”zÿY„íWßNÇÞvžøs8Ö¿ñÜr7^Hz±ˆ‹½Bšß‰uì­'4{•["–@¢ Î\ Îúƒ¸¸ùZž( X]Å­Ãëª,+C‘ ¥úE`]rô\zuçÃÂÛ _T ÂÊJ¹U«ãæ±{Ú\É! ›Zašxà†B JR£pêÆÀ4|û±F ²ÈsR)²Ôæjyë Zºb½å3râµy{§¼Ì#®>~^Ç$}&Y/pÕ[q,k`Zh:ðSÓ±tdý{/w'ZhòQáÁ¨hoÐÛq*‹ñè(˜‡(µ†ô; xØw‹Ï”šú(5áÈÕ£¹P&ƒ|EAcop¨°8Íl!V µï <8½°o\8s‘·Èà0ùiŸ)ˆ0sDnÏ µ ëÌø1*Á|Þ¬•ô ÜŽp~h‰LZÕMNIjìð+äGó´‰/â$xšÜ±ïã@Á­…‚ͽZ; à."@RxO,•F/7Ÿ-mLùUn'~5ùœ¢:º®&bõ1á’é´³Ô¢VÃ8í8.ýºÒÏÃL¥S<‚9á~ÆîEÒ²?gcü±€Ê2Â×Ýl›ÐêWŽ}{’?!<ÌwÈÕn¯? Vœw¥ºs”ŒéÛ½M¨ß+ÞéËo¥~Ý7Ôƒe¨÷á9ÓÇ´J€ÒJ Õ©‘Úæç÷î]¸HfEåpCØ0¿IAÌ]ªh†m‹¬xÙEŒœØ0¼¡ZÄpIæñ°¼FÛCÝËQæVYl¼Â…­4©‰‘‰Œó¾/P„ eBþ±º…çï.ׯlŸ\ä¿ÔÉ\?˜ŒÀÁ™&Á<9~Ø Æ#U”ÙUyž³ ŠB\Ù³þ|ô¾gÅmvCN§f48¼6Š ;7¹ý•“®— Á¿2T¤B;§bMä´CÏ’€€ö›U¯±>&Ô['GM-ó#l`9yQÒD3"Œ œÓ^ÙÛ½ù|Ä'½56xã²£7ßMU»9bœ=¸™|Lîº,¿Èìg ÍÊ¥i:ñ+X›Œå'šÿ~žåó³êËÖky¼ÌrúÉÛˆ‡^r:cTnà˜ï%YˆéVülŽ )áîv‡¥n”úóv-ï!k©5k îé_7zIŽ}äËÑhש¾!ô¿Çˆ<B`%LTW/ÓÎB_ÖÚCNºö²08ÊØHw”Ón­]lö¥‚›ÔbÚr–Â,@bbç9³´JÔx–ü¿ï€!×<´÷úM2áIw× 'ƒ)=é‰Q·Ü·šÛpxh&­NدdíçÃ7ejâöë&¡g½-ýy4Z¦Q?ïõ±à/Š˜FS¬ðèÐÔ^Í,\„š£×àЭ4vy³U.â“™Xb5Ð{’€vøìù‚¡/„]·q²N4ÝôµÅ«×@ÁÜä§¥¯ˆÏ5s^ì¬Ê{ÎÝÀánœ¶T4}2©ºÅv´*;v- KÉRÎÇÔ°™Å#eýÓYd–å÷”±qÌ“;ö- \-g ×»on#è@Å‚2d@-Ç‘_0¿¨ß„¡4P²$«þÑ&$yþû-©â%@%ûp7?en7GÝqÂ[Òéd\¿õ°s-Èt|wFíþAõä¿F„6¡ÐG9VµÑ©ᛎ2x­ºM•¨¡ôØ®å\¥çÔ90ÚͶ"YQÓ$#tä…\yÄêþ^6^ÿ?a¡<øGÆŒ(%æµ].,žshí®X7Ÿn³Éƒë~uÿ¢8±°V;9–ªK+"§§RyU>%QHIj˜ÈèAõ¡vn#q“hö;ÂF廿{ä ËFpœ ¡òåõ¾Äá0u†Û­µ]vÕ÷f~]h0 Ì3Ez—…šzW¯H?Ê’€€ç©È#šP1|*)Y×וyǕ͂Œá>˜Š†>üÊŠÉÎ@ã·ŠYþêùW™„3·:.'f]ñèü'«üü{¾5çÆ HþÀº®-öýgZ:uXǧ‚kµ“êSæÑ ¨ËõøõÇú³$[ºŠÒKvåäF¦ÎX–×¾7V°cÔœ¤j*Hå·føã”UIå=ý q¬µbý…ÃWfPɳ’2Í‘ãêiÿµ¥aó¦3•jÙ’™¨gË5ˆâ×—ÖUýî%Aå·L¥Øš¶Ç¼,TC‹Ò®1¯M¾mÇÊIÆ”S™û]‚îùVPË›`ðæ¦.€õÒgÀ•Ÿó8ÉþB\‚jËð=Qý눅*"«ÖÙ¹gD*=LÊ/ß •BäÄüÄoš{ªÁšóÓµ?V[Õ˼™tO=ä3Õn›!'Îâ‹ew×ðl11¯„›}ª»î·[„t·“©šáU\¹9YŽ›%lÕ½oó®ÐÉÔ€pCß©MÑÚ¤W¶rù|ß$êù%»æÁìüá:r2¤t•óÌ‚P ™ú,Îf¤YTgF}­nîŠïð´M«—éŸ8ONº<­Aë&÷uÝÉC%Í¥'\«e¦âê\ ’åBwÁìAC}´ž¸j¼x»ØŸ'žƒYkhf¹æaé«Qõ#ô/Ô)Ãu£Ÿâ1#LŒoYYcSÅ7µ*WE—! Ó‘ÿOGž»Q—e‘ÔGHÌžàgÃ&J,œ°í%ùœôIí{­jÕ&9;¿´â–ëM™•pàÙ,/L"zÊQOý—y«ßdÆ‹¶‹õjj½û~  c\[q‰ñìüÖší$=$ÑYöRÍ[[}‰–0:.9T«Òòm¿ÂÞ ™F§]uþ/`ÀeÓïx¾Á‘ãvì²7¸O¯XâQî9êBÖI„cÚ¥ŒTÒ+¯¯óÌåÜ7¯)·anÜY•¹ ”‚Ùób„û™Î@Ù5‘ר¡Ìº—yÐ^iRÌ8ËsBÙM&á'L-lYò%òSG,é²ajûŠv!Ø0±]¶o|ÃA_gàUÝ/«Ð¬ò®X‹HÈ8¥â¤úÅ5ó²—0¿¸‹VÉyÛ@€ê<ØFCW¢T¤ µ¯ñª[;‚ ròm&Û‰ã×’€€¢]õÓåÛ•=ÞH8ÎgåˆW˜±*²ÇWÁWÕb^þY2g5§vTDŒQK^_:PYTé<&_)»§SiÔö#*B%Ÿ{Ù0íÇj,ðZɳ”íژEaÒAqi‘>( t;ˆ]³eMVðkvø¡`õÃŽVO¿K¦u¾™Rç3(!‰Ñ2èÇcçIoáᥑ+­ÉŒÀ«ã«Õ)€ÈO¦ù| ]ÒÇõõ)ÏA%vA·˜#*•;(`‘AôWžuˆ¦@Ž2¿Üfh¾"?_½_QÎg;¹ž7BÎñ®Pw ÁDÇ!F° k¤i+ùÒåN¥n 9‘ŸÐʺ‹5`°v†¹¨òʪ¦×)ÎmÀ€ÕÂfË%xûG* *kìRÒV”iäŽíÖZIüÒERÚœÏß Õì&í¨Ó¶^gF·‹š‰žOïo%qºNF÷bå®ìëXçÔÔ^F¶ÄÔ‚³6©ƒk–‚–YöÞ6C''¬h¦ÕZY4ã°]uó¸†b1mžÙâÖ·TOdÊ@Ä‘lªOj¦´ !Õkß:ÓÔðï©v¸sgoú}Õ ý@k žÎÞð|À¼\Kø…Öç*¿ç€m+§8å±mFVÝöÐl&ì šéfï•Ð~O‡Ú– RfG*úE›eÞé¬4f™y.öçã6*§íÕ•Ç“¬¶–…ÜõÓ@±÷õ¾`ã˜õr$È-¦îòQ“pˆ;ÅïjVi¿`TÊ135s³rÏ$¶Zôl;‹Øòhwdsúй#§¶¥:»º§”çV:˜Ÿ¬dŒ0¥|j3y,ÕݨZÖºJ@ÚÍ¡ŽtoöæöM¥®3æ¡ ÇJÕùú‘|…Sà ¾N&z¡}-eûIÚïÀí)ÌwÛ­Oû¦„ +qêŸxñyI„ìÉ8¹}\+@wóé£Eô[ww'Ú”Ì=§l€üëƒ<²$@ο_g/ÔòÖOñ¶é£´8Æqé–7» Iž ZÀ±qØ’€€Ý³åƚȩõwºè‡¢.‡õ«LüÉY1ÿÖKË“Wï/·ôÆA Ô¨¼NŸóNæ ‡²ÑÒ;HÂÎÉvÒê—.¢^ ˜ìf×b\åè¢%ÈEÞFÑbŸpi£×ìµöžæ-&)aËÛÉ.ú¥ù¶jvÇHo! FeÿÌhß§Še¢‰qö$¶c-v¢ˆÓî¬û|’¸GfM¼T;”²s»1Sƒã¹Ü‰Ñ5Vú™ cÑ¿:''}¼ÍYÏhIYú _æŽ0Ÿp4€‰/lÛ÷7ØâO)Ò ƒÌv·áóìï«d)ƒUjª0^‡V’ÄQ`»§ä}òiÐøGªGú6BMŒ”yyï€Bõ[¦Cͽ”hÒ6Nz\…¥‘£‹ž´y¥ŽòFXÏ`½“ìòûùõÛ°?{äÿ‘x (|-ëV\wÕ²x˧dç¼­:RD2ÑFq£¼ÃB¼ËóŠþ™¿ËSQ³á;Ö . Àq,€E¶Ü¿`°^Kün×9¶iú5Eô—4Äm|¾M¬Îk àäÅiÿO˜²„?A“Ò¶Ö¤”BÈ[/÷¬NžŒz~6êŸ%íí·4ÎÒ}¹sX ñlogGì+2ê šçÛv“õýá'“‚êRwâP¨¬0ЫBQì&/ÙS þ§0ž3 ö3'åwårªO¡º[”§@É—J’D,.^ZÁz‰5ƒI¸–šh`—ù)æ3ÉÂÍC"ìÓrñBˆÑš½5'8b“(BóÙ3 €Ù‹I$¨UNA«¯ÔT;~Á¼S¨žO.ú«él¶åâ8žéf¡Øºw ¨ùöb…}KÓC»u懵bhô¶b½YóR{¿xï¤æbn™[}’Á×€IÕXõÖ]Äï ï/‘3[¦§6ÛgÇ[¡ q5—P…xÇq&j…†@>LÆ”>[d'ÚùšŒè¼ÎZ»—A$sö#áöOŠ„ÿk,׈vØHüÒra©¨óÌ9Kë"Àç´¢]’âêÆ*¯šÌ%»+ƹ Ȭx ƒØw Gˆ¦¹ôíìXk3ºAÓÁ°Pg`OÛZêÄ*“€ ;.ì‡Þ9a17ˆSM €h5âýøZ©Óº_ùI4+¢3½!„.8å¿çlÞ×E8¦¥ðÕ´óÃ6<’€€ÉWýßÚ¡úë8®èý“í7Šo qÓæŠ#zÊâ|f1Žßu{ÛÒùm¼b̤ßCC& §Œ¡­•mì[+&éºÏìO¨øÿתñI¤¬íÉsH›gžêGÙáóúDm»‡öòOc-Áí°çâK/tH“¤”„X‰{‡òqÙÒªdŸÅ;§š¢õºN’$§ËþA¹m·<¢£çM˜’>!nóØÙ9XÎ8?¶Ñû¾{àÂêd9§F_  ëÊAM­£È9üÞ²7ÇÞ²£ØLócã'Ä4ŠÀá Ðm&ööú A›mcÕÿ€Åþ[@r#JѳNŒ&FÓ빆d4zƒ´p•’›ðøD ¤¬:Ç þ~NEo!ê…A™½Ã†{=ðeê) ãÈ:^—f&{Fj&6Rà0Ò&Ǻ¹žD·oy!7ëåÿfgôV-®Ø4%yê™›Ùn£4ö‡øòÇK‘â‚äz_k³òìQ”óyŽàòÛªÈF÷ Ù~d[>ø@%o«T)%u2]æ.U«(¯êHâ2™™4àmñëlíÊã³Ó¼`Ñë9=]ŸXÐa[¥ôü˜`‹bïþ9»ýÃ[;æÇÆÛèÖ#©†äÆäYö“Úÿwúç°°õôW/× ŸQ¹’Åõô¿…áØVo®å’À¹ò7MÜ%Qëz݈êª>ÚÅn0VÏÀ× LS”î¼,ÓÎÌ·w€dÄ|“£Ÿ^’|ªÒ­³ke:{S°àN1¦Ÿ&‡b±³ë_¡íXB,Ÿ~–ÚSíÀCǶ†rI.±óÏ8UÓuÑÜ"U‹1l¥Ð¥äu›áºˆ+!÷}O®í‹¶¶µšß+½ùz–μP˜¼b‚ö-™ R6ÙÅæc¶“´ñ| Áž ÿ sXÈŒmOó¾ð92™à¬Uôsé!^·} rà°³ò"ÅYˆçª?1ÝvïFR$#t7@WÂ>í?×bXÁÃP–§‚æ'õu’­U— na¯58µÄÃIBà2dÇ/'xõ&Î)-á(U>Pï©^Ûž$žpë!õ|äåtn)ÐÄ×˼mþöß®p%ø¾FoùW!.õR‰ Op¢î¥tîÃ.gìÐ0ˆÒ%4á9Ïû JÖª6-JúƒÁÄÑÔT5Ѓ½C»7Ìivú”j½±þ¶‹ÌÎS¬•«:ݤ^8Õ©ŸRÈ4D‘´ñ+ÂÙ …„z mlš“Ó\ŠôššEŸ¡Ì{ߌ9;éu%Ú…êq5J ~lh2ô¬&Œ*ÌU!¡EF1P=mžsçºË4mÅSQ0¿-ÂnÏ5…ÂÇÈ8c…>\vžd^)ò8ŸšÊø»'†+S ùº'ʯãî÷ª…BG7b“òµq¤Upú}nòÊd¡Ð§é ‚¹’ÐF/Ø ô^;Áe8í®†¯jªÅAÖkW–ùÜÓþªÓ L¯î,€$¶š>jT1å;] ·µ£¿ñÜ"™˜ÍæÓËO@H¯w*?Û6Æ ÛeCøÑ{çJkaÛrµÙÁr!ÕÀ •”~óÿ)’66´ÿ­`·¦¡Bh®eÿegâfØAd)û±áÓݤHd~†Ôé Ý}¤“¯YÜ6Ü}&£ºÁZà®î0rçl?3›,-æOåÄÕ^’ó¾®fÂ~žÅî8ÒÓé3Û¹^…× Þ½ŒìdЈw<ý"Þâo ùóšÍøuÚ-¡ëz¼ëFâUÞº‘i3vB×ÓP‚ì…N] Wƒ©E˜/”(¾W´h2|t2QFöGÑs63ýœ"•]¯• #‚`3râ^ôÅÇ ¸ ~¨vØ6ùEå¶@…T–]@……zæÊ£<°†‹ê©£ïÐ:Äêà4ÓC¿h†S×é”×m“m¢‚ ·6Fóùžóéß,ãå~ò²åÊ¥ùœ%-üµÿ˜~NëQÁ0²…@ŒsµY4ó©ÿF0%15Ò2ü^“ iݯ#±¡4k¾È‘¬4ƒ7%‚XS"Sç~äPpKé‰A”о¾=Ï&ô?·ÍâÄ·”¼ÀÓÿLd¨¡¡kF lÿ帕kÆ8¶7­YÜÛyÓ€tAÀ€ÂÔ2u¾ J¯Ôâ‚ÁâÆC[FÔ¡qñ3 ì‹·Ž–M0™Ì8o ò}†Èùh#ÒqÂ’€€œ rÏš[ÜJ~œbîO<{:'T¿4’Vê¾<é<_œ:' )æÞ_µ”¯‚²0 ɲö¨ ¦¸ÖÁ+?³¶>Žˆ–`GèŽêXHK­'+G<Ïi¯>Ö‹x)L4„féË#¯µn»ÏÀ4v"qE{{œ¦dƸ±{Wœóé¶}ÙBÙ©žqÄ>WÝ“I“È¥‰"«Ùҙ؛›Ÿ¥Ù ˆ‹FÄÈFP€¶òD4Grj˜Qõ;µž1¦Õéᙘ·ì2²õ<#ÞžZç: ¡FµB‘¾yïBü¹ÖÓoç§ èPÅt²(} ¨ÿ¤½;‡òº¾*°°Š…ÇLHe3ö.»˜ËÒÖn'‘%}&_Cžîä«Êø €wW2µÆÂä8Ê®£ ’ªúbåí8Æ´ƒ‹âS.ÊÙÆ1Zc‚D¼z%Z{L ¡Rk²E¤'Š·µ„SŠÜ°0ä‡Ç·¯b‰(´o¸Ï*BRun6Ø„)¢+=Ñ1€•L'ÿ4rI(ëA2»m@ܼŸÎcq€-¦Ô¸ LÅòõÿ4a:5¾GáÅ:-ð½¨é<Ë£õ­Ìõh*‰ÑR(jÞùŠú)Ÿ”¹ó¹Šb›ôc[œÆ?ÂsÓ$þ©ŸªQÿkf̱ç:çm˜uÏ}ÙMn.UaUúºùwʶ¸©¯«v1•w¶ jìoˆ¹§T44:©r•ö¼7ˆêØXßL•iü6ø.XÄŽ7ÍÙÕð$‘ AxŒO{5¯v1°S°áÅ}©} Ö+¶˜8:0žøm9OvN[Û\Å=QÔø…ÀÕÀ‡Ë2ºV)%ó¬Ð·Œå3é½8 <û8iÜ?»¯8 @pnóRbÃ-ÐË,’wàˆÇIÇm*7q Œÿ£:÷ð' ð5gÒ”:†¶â» ÓQ©2å“ÝQ±X'·èà]N‚/‹5õì(E­xò¯Ž1ÿA¿D[tPXëeo¯ðôô‡v_eë\"§Ñ}³Pí7q0äÂÚ#«·i> ön*à;‰Ëá«™s¢…gøÛF’"6Å|ç“¢(pQ8ŒxܯâttMt'³!kÛî9H$(êêŸ £½Ð…ðÿfw¿†¤ØÒ‡AÑëGÏ`=cŠqm’€€ÀZŒ%Ùˆï÷»{úéõ¿‡ZšÈòé§–ÔlI`o{ˆhGµ‡Ù#t^ôþ,»ZN†Â6PwÝIBŒÝÐçÚb%Ë3 œXÏoÜIqÿ8gÖ7¿½¹+˜ˆŸËö ¾gá·áxð¶ÖU§’6©“O‹Ü›† ö\/ÔYU¹)uŽñ*e€§‘”ï¬Ñ®kNÓT®ç¶ ~Q˰ꊀ@þ 3ùì¢#Á@ØrÑUFP¾y%íEKBÚ7°5–* „Úç½F‚1CÒv…rýZ§ÁÜÃ5ä„å7.ÖD#Uý±1éÌJüÕš> Ä¡—ê*›Š‚qEŸÔ‡Ú¤]©Ûª€£CéC•èe”þü‰á#6ú‹ŸEJÓ‹BÓ•ï(M7-|-Q€ëlüè¢)÷GÐpVmPFžHRí%²ö­ÊH#·4énh%sñÿ×ÙÂáo’_Ù»@e&ÓNy`( jy²¹´Ä¹!yλsPVzw!gNB˜C– –^ÍL Â?t   VŽ\d'|=NoM! ¹ú4óˆ3 s£íÙ¯äéóm©_x‹À™"×–íÅ;Vù-c¼¤?•°”De¸ö¥ªE¯7R½æwýÔʺQCiÔêk’]Õúi8- #uVE¸2xðC¥”)ñà6;K%ɲÛÞ¶c†Üõm•}À§©~ËÀˆÄ62_XÜ军¸É ül†,‹%ºÉ?¤g¯K]ÐI@-qó:ƒÿâHqëà/ wMjÔ-÷Í£s²sO‡Óru<ÆUúMd’bf8©üÄ(ù.¡’±zŒ—/ä¸Ã8áÚ·ñõÛWüFOJËáUÐή©}·^v”JÓû¢äòê úðbTñ+XT¬ÂV¯™ ~¯FÌ¡{l6:gÅà7’s9‘ò@ŠgmÒþ"·æPÍ•ëí"ÝOÌ@ï/ý+·&†$¨LRU§¹›‹'»¾äâ°9†ÐHWK3•P»hÊ*ÈýÉQÚG:õΖ)êV“¨í S <–ÿĵ€>ŽÅ´ßþ”¿ùFÓú|å9H¤”‡ôFv GÞ·cJ D͘‘`•|1ĘÀ¥5ŽÃá…žú>ª­÷’ÏvgK@3%Ÿþî|i6xF‰ag wɰá7“ ?6°©M«áÄúüÄ6׿’€€Õÿ—žàŸæá¥¨ó ^›—+ßÁÜ—Дô»÷Df7ª êDæÜ‘žÇOÀ¿e3¼!D&L…¨omó åZ)T›ÿE´dÛ™5 ƒzì¡3û,™ÌO’‰ÂÝð¿%FB“á| ]T­yú/NÒÜ$³å¡_Ì‘ÌþeFnöm©JZ§=¥/§üYRÒÿØî†Þ”{–ž•–÷Ä ¡Å$6Ë"²!9l€áÜÒÕÆÛº0×ѺÜc)Φñîª6)[àÚ 2•£ÖãÐN½ñ N0øÏj^> kH4iáÞè›291Ý‚2-Ë®WЀæÑäÿLŠ•,?‹>W9wOj}‹R‰G݈‹]Û6ó›Ûpc(e(WH-|¤¾ –RC‹Žu !Á.LÛèçg¿' ÒÃoVK­Žƒ¯·Û ;žî›3l¾¨TU‡­"BUpà¹B (Mq;yè(µ°ÔÃ|×÷Ù^ø<-÷¦]Ûox0“Ñ¥m–sRÆ{Ò[º@¼ûÛIvš°óó¤Ìã‘ÿ î­I¬kSYKŒº»Æ ÿ¯F´2í__sÉhGßÉ{èï•"X¯³¸æ.CW z¦ÚÀê$MLû„ èºÂCO£Ú×eÀ2ÔæwC›7GûLì“¢¼…õpÔ8ž—©úÄ<öåÜgø\#¶Òwt5 |X9Î;l¸C_«Eõ{ò=‘¡Æà£(êþwh¡ßr¡©m{œÈç†äJä¡ýކ í;…•5­ °­W@ÿ›ÞÛ<ljÞá‚ymìúkŠ“¸6¿ô1)ÍLAè§éãu”¹¾ÌöÔçò·Úvê XBV-dò}™ aØuFjòe—Òiæð XƒF½ÚBÁP¦êkõu@¿IˆWhè²}ÉÀ,½dÚBÜÞ÷ŽGÉìS”èÅbSq‡Å-Pè%A8¨©»}„d^hÈ™íÊx¡û<ª.[KškË–Pü>¨,ÍÒ·Ç*JY¸ªÊøtaã}dºŠB¥n} ![Æ!ÜUYo¶³j¦éG¢¶7ù‡ÕQµþì¹4 ô¡F˜®D³"(VþB=–/öµÀÞ6›…<ŒÎMæur4ÂC!•¡ÍeËR[Òó1ÅìB¡ølK”ü#N¾šéIf’€€ïâêmöWñijD3ƒý ¶cøh±4 Ê… œ6ÑÄ9wª&Ѹ/-š>Þã‹ð‚?HÓ /ArVX‰™åÄÜàÃek -Ñ´Oó,©4NXQãU~Üß~Vaþ¸'­¢€,Ü,Á/¶u%“›>Ý\¤p~hµØ²ž‰fpÚ Ÿ«ªT¯Ўç¿+/áÝ.v(Y-ûð‹5Å,Öÿi7qÅ·ïà³rïs-ågôîBGâNnL·¸Žï(D¥ÈP\̧ +êo˜ö±ªìÊ1Ëa½ñ÷DO¬(æÞ‰\GFšÓšÙÁ*¦!‚Òû­‚”h@ÔþþÑÃN•ÆþžH²»x¤òË}' ˆÑuį>Âî«{«±9ÀŒ:š‚kÔ½D³Õoé1¥ÍOñUÍe{rQÚ;ŽÑ›ƒÜ¸ç #‰«N•n\ÚŸ*û‡3Ýa.ä³­ }È?V O°òméżë¼(dˆåYû¸ŠxàR¸é¯£¸’} ²Ág†ÆÜëbWBÈpµîêOÕŒ#Ì;#áø?H-îçÖèŠéég<(§zIã¿wÕ¸AËm½ôÒ¹Ï]³Põ© ¥"§m¤ÿ\i¶d”9™295//"Éiöƒf( bpMžÈPD“ÇfÇ«(v KQöÊ·¯Çëò»k‡’¡EŠSÙuë(“÷r)ÿ‹xÔôr2$È) B J6I“0”î]3NmáK4KìÍÜGÿâlQfã÷LÓdC–8z»Ðipô ††RÞ-Æ qÛËÇÙC:yÌ®ZïB”Ô t–ƒ«*};àg¦ÓNä£!é’xL>QÖ×v³Ù ˜<ÿ%9ðPM³í. FåÊ?½]A4Ч‡÷ ïÌà¡qÃP€ðóŠŽ{ ÖUxyzIjáüE#TãKÍíØÅ8Éx¯SíûØ”˜6¶¨ßêjs8Z–ðWK(îP%hÐîv‹šÕÙüô—·¥Ò uD§¶?‘5ªI{ª¦j—cœ8Õ_߸øúÎUÍÆ«ì¬ú2vIƒ¦Ï°- Pï;–è#såªA|µúpsˆšÙdQ…ˆúÖO€ô>¾x•¿*:^ ü”@³UÚ|± vµÈYP×!cA”¯îÑÉÒNbGyΙ l®€8«‹âÞt™ùS•‚í--iYôf¶xÏ£ñMÓ’€€ä*¤¶Ê¦Sç$}éA„Xö[†<•ûK\§ŒÂ6x‰¤>ÛDC>Ž @J†‡K[4–ú.ÙÊ×wÊ|NKX„Mâ_ãç#mÒ-;¢ôÊ -~rSv¸&~—ä€ ´¿Ñ…Ív>«läÁôŠ Y[– ÔÜ×n0“ ž„Θ B MÅ‹(U0yбÑ%›·DùZ¼ÁÜøRaéTÌ‹"×fÐåÊÃhJsó_Ê,‹@I89Eˆ"î†Ûâ…kÿ›Í–É¿EK$wwTí;Œ{ÆC@Qã®Y'ÁÅmn–®çΰÔH9ß&ÅE(•ñ•yqŸ{R¥gôc< xTv3Lµ~É!· G+ö‘âlý¥k4… }Ô*3ñ¬Ê¹\‡æzÙ²o‹½XyýúuYÞ*©r‰>Ï£û3ï³Û¾nG:]|³‡öÏðÔýkó«ª ½Î f›mgÔªâk­G‚ÉÊ@WíùŸ(щ¬'FAu5\›2{B$:¨[û5¸8«ŸBz>é:¼ ×wŒ©ÈP§õCÄÛ2 –zk ÿÅÕC`M™ S&D÷øRù8¨÷ÄGHd„àçü€š@”ƒ=ÿŒù[†pkiêx°›üž•*<“JÅqj¡±ùÌ”ƒØ.ºžèð{ŒwôQvòçö’ð>É„EåÕxU¶Zñß_ÕíaâZ²X¾/t4œßH·¼JN…;ôùÇï¥*¢ï›*ö€Q­±_B_öA}ºÀÀ·p¨*Sžg’á¨tÈjóŠ%P(– пª~}øé °äß6PÝjyBißü÷<¥ªÎv–›ðOÈ"h(~âÒ×’J ƒËŸÎÆ%é¢ãÍT^Á&0ÖT°jRjmüš²—{µ >R÷²$Ü—AHøåÇ+\Š­ÖÓ2wتؕ’NmÙ‹¸ÛY­ŽØà¤·hRÞTÒH(ûXuŽõï–L¸IµZ(|êÓg]¬'fÍ%£dk{­áÂ`‡isA¾olóY ÈÏë¤}aË¡ñ“nòk;8u ø¤®K‚Ú¢ 8ÈÀ½Ó%ç±g+aÛ… Z7lÞ0UãTé´ Znü $D:N˜üÙÌ÷¤.\4qšPÎì«V•bÎ\nReéD®|°‹’l:b½’'kÉ3в>  ƒ­cdIÄa–Þ=Zï¶îì[¸7TðÇE¦b MÃA¾,6b„ú ÂG¶µawŠe© ú¢?¾š°)Êëéý…*qb¢K¨±]f¦|rÆáõŒô$P¡ÐwŸ®[Ýz+é (ªÑàPÇM6“ ¾ªÍL˜yy-”wÿÆ@A25!rÛ)À‡Åa-µüó¨`”Gáþ‰½¾îÙ9njÀ°ßVv",Ù™6 µsð!þ¾€÷¸.T "êµ²O¡¢8Ù¬ ø€qƒÅõÙ]%dþˆ‡g ”;ë¥Li=]œ/¯´½|N‰()5ä€*¦©€A6Mž›»+O]ÿC„¬>/r·Û§ƒÞ¼úÆ4A( ·H硱º5Çéx_O91çêiúÚæ…DÐD_HMµ»àfLÊÈqéoîë¯$CJ Þ%SI¤}Õ{É>ì·¸óe×ιGœú‘Ý<£{Mò­¦J˜DIÇÃ\, ›íœ6±Ð0ÜhíÚ­IS„¬b‡´íy¸òœvÍ}ÎÄ^NåÖõìá=·T®º°%O™*6ŠÝ2Ó’:Ï{ÉS‹æaÄ—Çå<¸ÞÀƒïÎu}?W‚ÃÛñ-Ÿ¦hU–^¨áéÌô©®º„yêhAÄœ·¯‹–š)wÞNÛÇý0x`mx+—¸J<ûÓ+“ÞZ³-"¹ß$ñØòšJè*­îä–ºHQ†³KÈMI·Ì¢ ½|¤ázbåéÒÞÀ‚Õ/èxWÓY;¦¾Ý²²(kf©Æ¸õ¹Z¢³ÞjÄ‚¿â9y˜)¢½y‡Uw¶Cìi¦5åš㜢©®Ü‹ÈéóKèäL– ýñ Œ-’~–{9‡ÃS~PȲìªj1 ½3ëcÃHõ@_ð?k¹{EW +ÆÇ%륺`±’€€Ê¼ÆõÔsuèy‘ѳ3öÚ<*~}ÖCèîx×SdÉ©ÿ‹u=Ù´šòʃ vfe’yˆ_þ•ŽÌ¡öžj…q‰_³)¨Ž •ζ£Rl¹vhµn‘ÏÈ}’þÖ Âª›ÙH˜4Ex×r_C¹ŒaeGD #€žI«=DŽ ßæë½Öœä•—QºÜKV8¨v(ÁñaÊ$†–$‰ýó¿1<ÅŽ(Éïa˯‰ 1W¼J2“õÆšÔ œÆ˜6ÒwÊ)«¢arAmœæ° ý»Ã.f†KB"¬^JgpM]ÉâçQʼnw<—q Ôh^Ù2š…jtc¦”päfVõ&é•‹§ABÇZ€õ(J¸ÿÑŒŒ½d ž<´ªGŒã ¢ïw‘Û¯.¡˜oÀŒ•B9dÅþ ´îAš‘=ïûD¨¢eÛúJQÕÝÍŸ‰P{Ùòv‰—¾´d`—¥Ó†z«ƒ$€Å›|¹ìãÉBÑ‘HnàìYÅ€ñÁî”…‡0×h†ÑúÓ­côøÝEÑÇÖˆ?N`Ô'N±â@Û¯R¢öJkÂQg&i¨æ˜éŒh‚ è9ÔQoHœâÁÓ “‰&‚eŽÞ4*õé-F“qéb]ÖS窚ÿ ¥l×Òœ[Øh zð¿‹ç‹«P×Y?lÔúJcj€cß‚.Xñ_Ü6JåY Î1­4þQbPÏÖ1ɉ`{ì\ªÓjÚ ‡£šrˆ^&ñŸ3fJ ˆŒ/Ä©VRo3(¡ÿ™àŒA†]:à®#ÒêU‡ŠáŽ\]6ù^ø%yÅ;Ç2IOòÿõÏ–D&…á\v 9_õ ¯Çºlbð½çšØmµ\$q`.*ÔW5jÁIƒ¸q’hv_ñ bwÔ××ÚÅÄ9w¡wËDmdϽ‘*3i,=ÄØÎ-®I—˨Î.ä,³g/§æ}hšÔ¬¼JÀßÛŠhC~×¾bÙÎÖçæ€Û»ý‹Ñ^%p9Ò-TŽ/dŸ÷6w•ÎôÀ9òô"Íþ·[ BFçqWL UÂiaQZw0‰U8†&v©Æë›†i­° §i½i¥Syô¡[%æÊÔ'ÈÌziçè=*ðhج#ƒ¥.ÄÚÜÁ=F3Þ%Q†aÆl›Ðw ½½ˆÓ\ I—ÇŒ»l~ØÒŸÉÓ¼TÒ±À>€®ö&†´W¶‰œûP½±~_2ùh‘P²?0Ãä~5~Ä‘5˜8àY/h'xÆÊaŒµRèw`rÉš6 ^zÒnÅh¨—Dg€Oy+GßDQV*$&¡5±žiž™-:çñ ±„ÑÈ­’€€Ó•5mÆPpŸ^žò˜¼Ì{±c-OžáÆ"`.T\ û⑸}7¡é¬ ™­ <’í5ï# ™#˜ã^Tv™–·É®°A±I§Îº¡O _^Üç°ç~%,O Aòª@Tø~£®ÉDññš0•s‚:²¡ˆÏ˼f+5çÁŒÈ ´šÓ¯lFŠÚWÓåSµu½=o)ÇcIƒÃfeÊ•Üá+},ÿÃ9D'[%Ô‘L¥ù?Cm¾=¸{ý!VÂŒÀ„M›¡Øu,öŸ@ô…Äù­÷dÉB©˜ ±(¢nž2gên—=o¦o¹S¾ÂlJ§æØ E¶ÃøqÉ ¿o8rþ Gz-»<—fÙü„µÑPTi¯´4[—ÈbPS/ÄÙl¹%±Í`,ÝVÐÍ¿C\äpJï¡¥¸àf…ú¥½sËóÌþ×p{—[XBLÁ50·'…?Ô/iFÚÍ¡ÜìÒÉ+C]â)ÈÓU:ãP“sÙÞ„Õìœò?"$æå¡E<ý¢Oé—î~¸"‹CÊ´ðgý*±È69ÈÇÁïŒÊÓ'‚Ì‚j­Õ}­Ü\0O¾WÚ¶Ì!Q8Rxqxu~¤j~„/µ•„CVá9°-iMB¦µ4_éôô"ñ^ÖGrº¼K®¶•o$Wˆlö7Péå0×[–ÉA”…È+êÊÖ»ç r<$¼þßÜsâ˜[D$î[ªE\’!È*MQUÛå_¿säW9u@t,¥Wš ŒŠy¬øÌ¤y'ê~'Ë:þñŽPÞ½"¡Áó&úw#P¼YŸßA1¡ ê¸î‹Nä^xq †”æµ§n\×O^µµÑU˜2'õ´Û±Kçߟ¶MÊy•i:J-¬WÏs Ý°ïy Oôzç JÜâŠÙ·b¯õó¾%zc2$Íp`ðBˆd¨ý§(9Ž©bÝ.{JIä'l$‘Åõ¾—Pù£#þSÈB¬;ŒŒê,H²O¶Éå­$[¸Ý–|ï07¢žFìN|dy(ã‹hßBÍ_pD ýVؘ’€€¼¥-ú€Îû"ÁÀÓpTäû;”Ý=} IS^9ê´–"_±L¼ '÷,b˜ìZÈð •ϬRï$¨X€SKŨ¸-¶A6Œ¬¹=ý‰êaåeö2ÜÚa0ð;s:û²^òœþø€E”¬s—YvØ84•0EgAè 'M0L lçvÇ‹1KQ7¶@¤Ÿ9™U}éXÕ˜sw—ñEÜ×Ò–?!ê´à¿•KBOÈ­dhÄM’ÎÉ~wi_߃µcäNfÁÉTÙ4]¬Ít¾˜SÛõF¦&Í8ž—jÁÎùJa|Тӡ*†d,]}o·×rácÝù?;®˜ºÚ‚x•©©fáì‡þŸèŒ5[;:„z¼_U¤Ž¸ÐLg²XåkKHPù¯çD*qpþà…bUßQ%1Íÿ¢ÑåGÂag‚ü=þó aàgŽ’½U"¯†–˜ýPý)ŽJÎn”î‹„WÊÿÜ*¼Á¹¼‚+K Z_G çÝrÃN²ˆj@ýƒ †£Y¹÷¸1÷Ì¥_@ßöì‘$ Ô·?)µ3&²¦I±ŸÒ¯m¤QOúÞ$¡=55϶§6¯Žáè  –Kê ¿$¯1¥ÉÎѽÌhÍ*)² dº¡–¦øÛNxcd1‰Hè’€€ÌQ£d2àFI›$ <ƒæÿ&¶# ÊÈ›Õ ‹ï×ó]€Ñ=FÈkm[âk]ŸâxËDNPÂ/qX ×¤Ò(¸¢™™ÁpE7%Ç%`8ÔMKBV)RWòØnµ]òM³–ak|::0“nÑ2´š1m$œ¼Üi•£ô3„ˇ¿Âæ´! C8kO¥Æôw1™1ô1ú/ÑÞŠ 2ôÖ­ªÿNЄJ¿­<ƒ5;Ø‹â|ƒŠ˜:þ%ÝâÙzi¤<#dîoÏUø”±Býߎå \ø-ßqsì…+:ƒÇ”T˜Eé?PïvïOÐÈp×–è¨5.‚%°´ëT»ÜäyZÉΊìÐÐËc¿ºhÄ”yögˆH8tX4I5ïö†ÝøjÕÄ®mwücsò¯Úæ`É= ‘#ÌMÔBGΑyÍÞ¥­úµ»•ƒzúRغÎûˆ:¼‡Û‰dg‘z6œ1ä`ÛpÜô4)Ø«ç$Rú³‹LÍ _4Tø^Ù‹Á&lºã íªš¢ž@m4`0ŽÔ>+|l2¾®XpäZ ¦Ÿ¸z"çà’0¤ I^™àA+SÞ²ô0Ôµ†›™hå7½%þ~¦wGÅ=ç³²q“BŸ°°@@샎£[´ÇçiŸ}™ýxàq«öŸ-¤âñ¡Ü¿ñN¡TOu_œè¶|Á\À.¯¡¯¸uãí[Ãï°aüªnä±¥Qßø~°39íÝ´¢;E꘧½zKkÔzJ7C}B»MŸLN£sào¯MËhC úTߌ~¿ñ%rtü}…1ù /»¹ÐHö0–l·\hݵϤ3ØÂt&’"Ÿ\lt£Dèj~ó°>ë•:7_4É8bŽø1)ÄH>- Ã’ÌÜÃýmœÛ à©lèç7,AGKãÉ•ý¾“ÅaK⽸3+BmjEGCCž ½˜^ ¯L‘8gQºa?ß¿H±²Ñ qp6 'Ý’ Úø…Ù÷ÑLèµyû~yëožô˜Ž¦Ó‡åî× k_/c@B éÊŒÉéÔõGe^ë`2 ÌÿzFÄ>âßej2šŽP‰|þJjX˜? Z †!/ƒ“+}|ÅÂ@˜'seü/ÓÇÃòôtʽˆeçb™t,ëkS¥]`:Z’€€ÊÑê_Eï㟆W%CÜJvl?Ú|ÏüüÁzé*N^äí)G.ñ§ìÁ;÷À¼œë5’’[Úïzš‡®ø&RNçÈÝåègâ›_á4`ý\$DŸpAoq†(Zv&ŸxsÝL:.#ž0÷÷ð„ºØÊã®kq¬3Õ*¬Tºdú®gÝÓꞪWH'éìNwÛ—<œV¿º‘‘3´gîj%ÍŠ¬c«Éç Vq{{&ü†³ÑV暊y'Ö®kŒ˜àVÚVM^ÜÑ[í`è«$‚³GPBœáx8ò[Òãz¤öP®%88•ÉDq(ÒcàóqÆÝÙ*©ä_îtG”)2Ðp^ôvƒ¾Ú8([Ô~š?²£‘p_®î ʰdYÛ|íå«ß13bW—) ÅkÁì1á4³{HôØ{sJýôÿf*Ç×p”ÎD•ë&.±ß<ÜÞºì âp:[ùðãæ,&×þ$Àú÷È+¦´‰ì>®¿õ.‰þ(Ô å.òý‘ÖÐi&áx ‰‰ž/Wœ´@̯WÜä–G,o…ÃBÅy;óóë9Ž=2Ø×ÈäWHÚ©ºŠÌÈj±Ÿ‹t?qJ ÿ§ßÞÿÁ7¥ÜÍÞѦºò,þ}×=ÿä¢aìž_œê…7Œ>@E³÷mg×$wìúcMõŽŽÏ^—+øjäÉî7v4î~s};Ì R”Q|­ês›QRtŠ´²“_‡FÓ_[´UVA”HS:‰¾HReô µÁ·[-ɬÌI¾ê=H_#ݹ=,á€[I©½®µÃˆç5’Z¥[zaXU|‘™Ñ±x`j±AÓ•¡ÞÖS0 ï2 Ú®¶6±ºDóáK“âä« Áp8ô¾ Ø«Fp/ÇÂŽ~ãÖÖ|%0KiÁ¼0iÞ93M ¡E`)xB× û»¦ÀÅ–’>šKrXU’€€ÀÏ嬧ÌJâã!fA{`Éór:~±’XÛŠèpKmá1ÈœÔÚêänéoô i0RrxÉc"U 5šëé™' ©u?¥-àÚ-»óåØéM³³ÐNä€]G†—,“@#wÁ^/j¡$¨«…bÊüS!ºÚ<¼rÚ§xTG‡e«ñû:(Ï9䳪€X|¥dô¬fìûЀaNÖrR8Ï‹e±xþ’Drf’HzÂÝG]|@!>ͱ ¼YL¸‚{ä`Ú°eèsXh7‰ºÓ#£¸)°ÃDWh¤Ò_‚ŽïLö7ìëk§ µoíVÅ|bšHÓQ®6Ÿáˆ¦ðÇ ˆ„PáÒ^Nå5´ A\Ý nðáy‡y)Ë*åMÔ”:@ùúiöl[îçóÞzæ¯ínjBZõ‡îêÄ•ìë_º@¤S/=ŠE–Jýh¾›‘6=á-ȼ¶$—i’i ³j©øz—£0à¾Á²‹õQqýd·sY|“–ïÆ.ýu¾h"³–†;˜Fæa²Ù¸qdêtqö´þ]5É‘Öá-| ÉËÎT°”{œ™)æ+ÜÔݤmö³rá Ä«+ýóÆwhÒÖW«™ª£©q£T¨©ªï[~€ |$¸3pvQjz^³ataðÙè뮊ñRËiJÝpCD*¡Bî}x6¶xtNÙë\ÅE‚›úïþŸî=¶S:‰$}•à‘¿z©¼§af6 ŠIöþk,µªž`ôaˆ –QsüÖý‡cHêëC%äò‰ò77G¤¢Bè!¨¼Ë5=bÂÉÉUÉ$hõEPÍiŠÞ¬]Ìð{¦o­2ß0~ñq«×ö ‰Éh)…‚¥ÏQpóú"× ôÌ^N½qð )üÈÃj•È(X|ë^§>ò dù¹Ù¹ï•oWâ£]‰jµ¿@dEÙš?1L1° =Ã]‡ÿË´à”ì£ &H‹$kƒT»ÈbVOJöNöïU齺Ša¡p”‡i¶ÿ2ù²gÓf/6˜ÞàÀÆ45ã_,ÏRKÎAØ ôô3·}ìä±Dp¤öI®=Ì¥CI˹ tðD8•é¬àµÕ^‚Mûus3ˆR}§M%¹-E „C…ÃO"‡ˆ9À&ŸãÉ’€€–oúÉ JìL·RX!¾ÐÉ8O]¦·3— «ðŽ¢vè‘ÛÜ–~ÆæÿA4‡}„û{-i•éÃØž]?ݽ8T^lÎùï tÄs8ê5Üö¢Pú`yÑyYÚâ–ãG¯¡$[8ιJk ûÚŸ_Ð*,Îulä ·l±ë¶ŒIÀŽb·®`d°š’qÐÐßò4W:±÷ã[œ:ÃcgŽE€TÖnÁ–üK‚,ò\çF5WY|Ά…Œ!ÅIxq¼4Ëaw¯E‰µ‚ÑpAC¹z£Ž û1÷MøâS¹TlÞmZmÁÁ7ħʑÍ^_rX^ÖØH¤ËÉÓ\Íׄíœl1°#í¾iÍŸc“†¼Á{„2ú×ÍþŸÎH­F¶ m=˜uUȷІˆ‹1 mæóª€x|+{𑦊ÏüX&̧(HUM@uõŠKæï\¡'ÚÉ“ODw¯ÀW“yÛ–¢òáñ–# sÔ `]æA:ªP4í¨£]źœh—æÏ¨÷ï™ÈÊÄl¦¿Î ÷!—Ô§1[Sa¸~K"€ˆ‰uÚ2P/5…ƒMMDŽu4"¥àŠ_]äF%i0Q ‚G“tKááÄó=¯cÃ7*¦­ž Úÿ´qos0õ»KͰËÏ?Ë×ZÙåÎIÙØM ûc«Ó­è¹ï—üzd¢©Ѱ&l— ÞGêoÀÇé馾}°íˆöY×X߂Tù¥Þ´:?-ž5U…*c¤"&H ëgÛ„Õü’×` ž” ‹ªËp·ùõ×°(Ú›}QöcÇ›~OrµýÔ„¿ƒá‡aTWnn蛟•ªq±”¿Ýã—|˜¦‰*xÎú^ÙOËLøA#ÕŒÂˤ<ÈŸ¸·]áÁXqö“I¢ ù"^‘"Eù ˜çàšâ‹pùžaœvû!|fKà/õM°Ô î#$Äê²WGó5ÀrÀsKOÎõøO:‰ª…«bi¨#wurj+¹íúöœ7I%>:Û÷D¤›Eª=a©zHþ ¨ ÎÎ’€€Á *WõŠb$–…OÖ'‚bzÒ±ØÞ[W=áì0µz,F9iššù@üeyzË+ÀBËgÜfÔ¿…& €æ¢‘½>È=-¥Ÿ$œœ LW˧ÀÓÕ? ~A}›éfŠÿäÏò™Iqw â4ñx…gS\ÌÔ\Ÿ}Löu—HI@yÐöñ(?'•M¨È{éZq¦ËeöÊŽÜfP·¤Œ¢—¸JÃ0ÝÞ9nb?ùn0öœµì+ëPÈbÖÄìBøìw‡ÞK$Æœ¥¤O¹ZM_‚Ø&¶É”4òtó4+Ë9f Ã]Œ¥\âÎ"-˜– _MZ³½012˜X¶ İî|IDü^9†®9FŸFåè°SÓüD«M0Uó2Zy=25‰mØÎú²‘MKÂϺ§ÍõæäT ?cÀ‚Ž”æ¡_»}:צîchúæ‡ضlìÊwuc#ëgáp+¡C¶M'V.üâ+ùøQ>!Ç´æSuÖ‰D ïë›·—X4ö)r •¿ NE+ðØh÷=ØØ”zP´ xBLàZAÀí½÷´ÁXòóÜ’ˆk"–“UKÆt¢êÕ<$Ì&~xެ îx5Ò:‡ŸÂ/ŸbÄÚbZ#Ù¶4 g¹Ð6½$*®íåËÇñ„zb¤\u‰µ7,–Ð3iÛÖvrOŽwÀÀY)“OٿÊ8ÝO÷yM "¿Íþá¼ò @@àÑB¾h@RÂA†vC2½`ôŸØ‚g.„ßF„2iÓÎxŒ#¯ÿ Tàï>]¶Š*½â¬' y€}Í}?ŸÌŒ*ài”ºžûu¯žéúí½kwtañ-`ÀÿÓ˜ŠôÛA6¬Šš}«cäd¯Õ¬üþ}çož’"}°ýº¶,1"(Žÿ ‡k'…î^¿9‹¶ôUç *î ®8˜ÞJÃMPÙAv•‡þñé™ä 1ku_>ïæÀ#âA(–8ëôNeqÍ »†O” ^ènß«…Ó7Mô+Ž¿ER$¿+E2uæÂ!U~™Gòç¨Å¦JóE`Ô{X6&Ûærˆkœ€ð ¡•ÇîËoýnBüb~×ÙíçK3pûë}Ыĥ<}7S„èM9Ÿ …Ö}XEX’€€²8ìTr~•­2c‡o£+Ý;_·H»ŸÏº¢ø¾dY•}؉u ÿxÈ[’qçË€H²åÏûpom¤‡Ýl‡>äñ’¼3!¤k vÌQ ¨­àHW¢¸¸‰#ú?•†#‘n݉ãM™»±ÞüG½ôðÑP¿Ò˜ i·kðŸ>Ç—QǰŒbŠ<Ó˜³"ȤÇmÈo‰©ƒ¦x‚ø±ø&AJdjõÊ(sN]ü²Í³$¨y l\‰Jw_@¦ÃCé»æØ¸ÉmoTm]c…|Æ2A WW@E#!`£bNcßOlKHN¡©Ý¸7ú¨’wÅõ{æŠ@Çå×nó­€Û+ÈͳnD<0ïHøP~7Ö¡@û¦/+=uu3ó*fx Œ¤t¥ö=Õ5ÆÛ¾ÐÄû&f ¶«#m€O4ºú˜@Á ‡ñN ¤Õ&­Ãf@+,†‘alÔ#Æaå—Z«ûÛb÷otüõÊrŒvSø« ²G e@âÒjOý˜‘ 2WÒà¦=£^“=7~‚»ÄSÝTé:ÝMhþ$u[wÖ³»ÑŽIk”Ã;õùûÿÁ˜3C‰¢i²¤Mx÷ÊGœ_ ¹ÆöŸŸéLÒTƬʋzªèh7Z,|™½¸ûKû$)A‡ú¬Òz‹„”W6ßu·éJ‹Î'™÷ÉÉ®/(˜ÙÙ]1Xý ÈÌe¢®ºIw±ˆ¶ª5¯fü- —üY-áÇ\%'sUTY5¸s’‰EC¥Œ)¶^Ôé¾M§+šqÕ¿›}3ôÅã¿¢¶ºRæØ¹S­'#ö¡¥œ\¢ÐÙÔŒ”Áÿ¸Ý¿LâÔÈ¥•KÉ×aÀäÏ™3;–`ZÅžÝÄ(¨Ø ³µ․š€QXy$áܽ8ªa/æÜ»›h87²„t Á“ª8D…÷±PÌpÔçú›…Óy~üC”a—HÀo_Ø‰Š…Œ|!jŒ £sͲ}ÐÓ¤üÂ?–qÙ šý–/MœÕjÃ!¤®’€€ÉÞŸŠðÈTÑ#:¡ÚN”"p<;èÁq䔬¾Õ¯/ IêÎí€*7R÷-˜X :¸{„»­ÇÃG—'°¹€{ôÞŸ©17PE]L–~vxÁÝ<Ö·W„zDM8sdûºCݽY"VªCèåIß„uË:÷=G.ñCÏÉie­€7¯L@á9`çP2ñðš:÷´Ôøq `GÔq³æö gI1èúy-¤NãË”­C-Q­YWdO¨$_9>°A†5°Ç"Îöovi½êl p€ûw»åN ޼ÐÜ ¤›ù½’"§Ú®c› ˜=<òüS%V¥D;òµa 4sb-ç­ÐÓ{lwšé•C·†¹ðŸ›sgo ü¬¢g{G”´ájC"öƒã¨ !ÕÁóùA5ÿ[ñýudÒÔ½[†Kz`»6 4Ä’yëÁüfö)k„Ù1Iânfx Gþ_äûQgm^؆ê½q_[…VðQ¸Çq h¼ ©r^(°«H)¼PÛŸU« C·ÂLD£yý£%’øhhC”d‹wçÓáC5ÌÎl^`2•.šeiÑ~˜+ Í7æåð ¹)PpÖ'>{IQUõÉË=¸¬”ð{aÒ8äA·èÙOa€—މåÂÎH䂯*Éÿ‚L~Jr$T}&ÔX>° Â{é‰qÈÉäÿYkÌV½ñDOn‚Z8Àô€¶¶ä^œ$Fý+Jž£Í).êl’”T0G¡"7“§I­Fˆý™t鈦ֺš|ÍÝ$Yv6@¡¢[ R#wEmÚáÀr¸W/½V_œ¥PÌ‚‡–\­ÊA¾rT#õ“°‘ú€\™çbèyXÓ«åó½5†&ÆÃ{.jwŽº¼˜–£Ì‡Ø™<0îYÏœubÚÁ©/™©Öžµî‚½_ä´/?Îßß <{Pkõ@Å> <‡j͆êiÀ-ä|RS« š³²#–fzû<çÂQ2,òËþ-Âpi+¤MÊ¡MöóŒ¹öÌÐŽßžc¤™]„䩿>{jÚEÛ¸“šž¡ŠUŸ³nGrªíΓ”’cÂ÷6pÒ}s*YRˆé‰úØå4US g¸ÁƼ62‚N‹Vn(™+Ïf¸²[h¹{WËrÝ’’€€ÃÐdXÖ“R@÷WóݼÈ%Ä)øÚiù!ÏåH¾7 ’ÕOŽÀ½0QoòLAÍû_s#Ç´Éf( E?å–è¸Àm&ž~ïÆ ˆ\7˜TK@hV¡“%$ùçGœUÃÍóð˜¦Ðîð©óŠL€½E•*j½xó…»/ËÿŒ«îe½ù±e­PrŒ)h 0žåÌŸù²­¬Môæµ"·ƒjúÎ|ø¼¼í»õ¸2Už¤ß'îð |D…¼ÖéÑ×)Bm*ù6gq‰-£K—©ÈjŠÚ^½Ã ŸeCNò6áfyDZÞí–ð ‡ÕÏ™&#/yϱVs+Yõ `©”¯Y2à@ [«Ù %ÔeU{A#x».I»mA‡›}w/¤hÐÓ""ý¼ëþ=ÌÎMuN^‡ÅË$ý?½õµ;.ñæ,rR¶{bÃyV“Ym„á¼7c + *½€ªÝ’,}2°†fí Jô¸)ÕP7‘ŒŒäÀ?ú¿®ñ£{ Œ«^-„ ©Èø¥„„D3UWdj¸úÈgpJÏ^ðc\šLbÝãK0r)œ¾Sr%÷v¹Y²‹æ±%ÞO`0ó¸–çùÍ%-/Pe±»ƒÇ‘b€Ù,#RVc4Š ô2¡é=Gj}VYá:X ];Z¬×0ç}qà­ÑËø8I=ذP“½)¿ÊÿÊ—pU8|µò^ß×Z"ãMÇÜG’/²ÓÍ<í´ì'š©)v³5¢ÿÅ’´œ-^|ÃNæÄG ˜B©õ˜Ã¶ÛîÖÈÚšÒ†’¸°Ï†Ái^ëÏs¼)ÄúGê”Ú̬t·‡Åâ»çr ÒY1Þð6¥p#ÕBí1Oþ“k8îyÃãȾ3I Xs L¤œªE6°–*žw%–Ö„ãe¨@Ébˆg[kÐIYeìäiNŒÈ•„rÉJŸ0¶¹Ôf±]7úÄóW›-ü7Gë¸ýÝJ(¢()4Û(ê|ÝyÙí#U˜a5¢\`o¿Žwºã¯Oгo´»³û|ÆûZÜOF¯‹Qˆê³T°¾¥r/5ÀÐ’“¶sòÔ“b4¶I‚Õz¾D¢~1DBêÈTGÅÒT-L¨Þ‹ð)`'¨é‡¹Ï]c”Á¦åÄjúÀS¼IRõvÀS¡CŒìG;2Æ *¬w¨¤©´ÛßÅÙÜôWã(Ö´ ìú ÃY™6Œõ®¿E¼Mµyä(uàGÚ{Ç}®k&‡³>”é¼ à±#Žã»¹rû.¯Þ Ü×OËá}ìöW›Âm'Q( ¦U¯‚.†±¾ˆ˜#¸ˆVw-BØ‚´µÏx9Muh‹ìSÀf‰È%ï+Y%¤'rF7Õ̪œ•·ì·ÄÈå‡{X3p“æ UØÀ±I´[}Ô@Ðo7·HzëH"]¸†|s8AcþWáHRh­Å›æFp š®VÙ‰T|W³¶\¢L ´êjT¶Š¾·X‡§yóÖ‚>;Çj´½ë‚à$Ú*Ñ(oRÞGãiM@È«:.FÔŽn6UýîG,¡¤4}iú!•·&dJû*D`wr*oº8(>¼D6sšác´÷«|ÇÃÅ{,g9Ö¼£¦ÖšÓfb Þ €¹"wÂ+ ;q™}D3+öÀe‹ë®"ÓÎœÜ ‚çŠ2sPˆs¡Õïv]’Åu„H„PP’€€›høÊL*ÜWˆÿ=Ö/<.õF¿22A!¢Í ó‘r˜+PÑ9¿Ò8Ó¾'%±W–©® =Ï( ;bú×?A a_ò‰Î Ù¶9™Ð”éC¿šVÓ]i=ÍÃuú` f!Vì‡ÑøÄªa%~»Y¶*òÑ¿]¨…á=«úV}ï|„&Ï!åל—º0^êimŽrcªý,Ý•7úš.­|Ñøbó ÇÛL©UR˜~iìp]Fy’Gï<«ˆÊÐÎãÓ^*’ΪhÕÌíÕë¹KÐöÇg™’ê÷pu¤ÑtgñŽ+¹€„VB  ‘•}À%†u÷ †ðš°P˱Œ×1Åõ$_9c(}oó/…N^ò(;\6bRpSÂe–ZÝÒW§´Ë‘ŒÏf‚Fš§r«T°ÐÞ]0cEöRìðê6´€¸¹ùë÷þðÄÕY–ÓçTî?z޽.,í“&D#‚;!šº â­^6ò»5-˜r3"ìÐ.ú<¸¾Q’az D5ƒ<軉Ð? ù6Í餮,°Zhr²ÐÊÂJ5…Ã;8{È¢…šêwáøG’ DË1¯„Z,IÔ<ˆß$ê]ô¿_C‡}¬"4 ¤ =Æì±Ç]DŒ5(ä|}ͯ zo$Sç³¥f«NÃ9Îù.~¡ HHüÚ—º ƒ«F5}ð44æû$E0ž;î2O:6VÚù«NE]èo=D»«’¤”‚¡`âÕ#A±¾G:×i¼ á±ËtÉÑäa|/|sG£ÞcV6tÛšå £× „üïá¦%‡#O¿ÜGQÉü„@i2¤[× À9‰±p4ìy´¬„MŠ)¸Þ”©%ŠZOƒ{ J™}ÙDMjvi7Rþ-uá7SšûJ VfœˆÛTrmNì(n ÛáðXæÓLæ!cÖWPý#»?ZbçÐOC:I@6ux½õVLL3Á¦ ZL‡­ÔçtÄä¿®Ú‰ $΋OýØe¹Ù…ù—5¦“™ð³sN<Ré»É΋w¿æÃi^æ=ÆWÍ'¨Å˜Š÷¼élº/U˜@E§ÈäaƒéÄxÙÎþ”VÂÛ/ÙÁŒÊÞ1&gZÔe¢ûâESÝÌç E>}±÷°½åa££[&³ªI> ’€€®pûš¶Ï\‘š;eÄ÷ /úÕ¥ôÝy…Š­d?‚5º¥ÊˆLúÇf_œPeD6—ÝRS«Ï¸)òõ‰”{ù–o®˜eûÏ@¯î^S™èË?ÜðÀíÖ{ýx‘B¤ï7'„óÕ%ÝWw×4'Wgº³"úEJ~?ržgEW„Cå# œ¿YÄ1nqŽÑéŠAºY¥â:ú‰©Õ8ÎRþ?¸I‰êJwž$Ä}ÚØDÜ8u£ãoF—Ú=)Æ6ž£9Ô´H.5ªÀaù•c7xENœ«2¡‘¦ öIˆÙs•$!$k´ÎN•í- -ƒ8»“‡ÑS²üÂò_›TDR)µnÃ£× yX‚«|<Ä»š¬&Ú‘ZqºšÍm´GÉãñ=+5¢.gÓ]os© ³7Xá»¢Úæi.}Êùª5—c±~`댒àŠEX¦AD¬Ø°Ó¶^ȱ3óªþ0º¼ü¤–%¼Ü;–“À1Ƭè .ûÀT‘Ù€ÌtÍu dÀVÁuЙk> ãŽóÛ¨Yeaù6þ‘ t+Þ"¿ª œ¾¾dù×^çt¶Ýâ’1ä<“NY°ÖûÂSF(mÕã:Õ›ð2˜è.£´ù6Í\ fª g_øÀvy+ôäoí:¼gÙØ*gšçr .aÝIB`3Ç=÷ƒÍiM&T)ôŠüÂ0"íEøK—–Ü.»¹QÑäðL_=\.6ùYjeûu@œ!gß¹õñROſԋ¢û8[°Èk& ©˜½*Å;µýE²Wz=RÉÝâ¼ÎTØ%ËÎuìâVí÷|¹°£9ÃlE5A²Ü/7 ’~ÁÉÎuw}YÙ9¹ÙHÈŽ¦Z˜Žõ&ŒÖ’;/Š=„‡¥¾¬˜HóH"s:ŸcÁKF3bËlñõÉ“©IéàV9!jYnÔ3•"aö[u¹õ/3ŽKYìS'¨~Cӻǰ¾öXÛ ñC‚Aÿ‰?Jÿ1+ÌìU–«™ y¿s׊sëØviue’v^jKdÖ:¾³m)ƒÓâó/Ê'mÛ–“8#ÐÆÈ¹—ë(SW} óÙE#³Œ«¤0!@ [wZZŠžµ5àΟ×1Uü#Bêws.ï®·yJÅ2ÊÝG›˜…Y蜜•›1FžÓ r7’€€Ö4>ä_µ4Õ }4Ž9õÄŠÌ‚®Ûr‡–0f ±C(—¤±‹àBAz*äWf"#7½È¦ó̰ŒÁ¹?·®OC¯ø›ÄzîÜ\VΙeš–o,™ßVÇv(Ù¬J7ð’ù<5)oAÅçËs–VϾ'I0S„žËÃV˜c(§šù¾oß`HDítA ÑÝTKËö× åjXÑÅ3ŽVb Ôn?Úç !&òOJ»9®\¾YpññfÙâÀÿ˜ÛnquÔKÈ„ez[èk¦°dÐŽf˜K€êà|.«\®•¡øåVÚþØ—ñŒFã‚E=²æ„žT¦&7,Z£9İޛ0ÊO‡0qLªõ´7ñ®êî¨Ýx”o‘û™æ ,â-@ñ‹ æ¶!‡wÓB;°]XäÝö×€!è‹è“þÐAÜ—"uðX­`Ö?÷ýÉ[V¾ý€¥Å;Ú¶°Dk¦7ÎY mš£æÊ•±tßKÒ”MlJ+–Pƒ%‹³ò³uÜÓÉúê½ ê5¿ÓVö¶ ?aa•B?dU"ñ›Z>°mµ‰Ø8~ƒºÌ#špe¿ÅÉMv@Ç„ƒ~9 Â>ÖÒÔÜ;¢ŽZ> æ–w3¹‘Ay`ój™ãq˜H éïË|Å€–NõJ›ðÅŒŽûk”B^…õî¶(æEMX-;¬’Û%Í›0 OˆƒªqqŠ”Åöœ¬ñë8D©ÁmšÝó#ž4GÏzw®Ý¸¬:ÐS„½ uFsÂï¾LéÿxõͦiK¥)wÍù¦á½b¼‰ö)<¾_—Éï¢_B9‹ÛëÂVHšD]DÙ´CãÀKR§Œü¡ß…§~Z_ƉN%#\νlp]’ÜÏhž1þ7íÒŠ£Å=?ÃgÀw•¶Œšۆ̃>`àAbþÄc[¹£ä¹Ü±tQÊ»—BhíAÊô´Ÿ¦rÀ‚s—ì+ÊE05F¸_€Z€EcÏ@”¹O,æN…H31p"U÷òû{æ¨|*x¿#Œ§9ZÈÀ|“æZmñ–hÀ\'ß!Ör¡ÞG~SÃs²?}óÂ]Cƒq¤ ñuì„ysЃµÔß­z\ÿZÁÐÝR£]A¦‚ð[‹ñ6')™ ´±Gì‘o ]DaÜz  þ{'›kòy!2P\NÏÕó5ÿÑg-u<ÿ,(žµCTþb×ÿò(‚w?Ì~ ˜’›û)C´RsÛó´a-J¹RoWæF®0ŒhxiÒÞoá-x©Bºðg;gu„IÄúKh?ÑOvÔ/íDà™ÒÀ‡ö;ÆÉÑ=Ê+Kž.˜.ÃdŸR>ÃþoóA+Eܶ"=ª(JO$b7t™ÿ+Ðà)˜6UƒÏ?o¸h«¿ é©Ô¼Y P†¸œ½Œ½xÅèd9e¶Âµ >$+ ŒbžîxÜ ?Z^Ü2èeL¦;ˆz½„Å !ŠHßéçyTZŠÇ7ó0ήþ_ç±JÛ¼T!Ó‘ò¹4O… :¥ÛÞ0Å2“ ü £lù¶¤Ê´¼q]”ÃãiÒmœ¯ fÆæÌ ×Z%»­iþ †,Gˆœ ãü¤Í+w³õab¤ÙZ.fÖÍIñSß™ ׋ǞÇ3z[]NL\ó= ÓÊlç€.pÎub¥R óC{ä1+ˆË[á®'~Ks-l³t#©Èí„É¢o4”ç*›Î^.$2{Ô¤GZ˜D?Nô:GÆÜ¦uOË7™3 Ú†d¹íyñúE\dž#©ÙµÂÏŽ¡p¬„¡3˜>A$¬ªâãN¾uêÏ 8qH·ÄÎéÉòL€¯^¨fWÀaå×= Ïùôiõ0>êà7~”ðœj™Nï1Gg@ò“¾Ã¶¯¾­8¤a[¯Çz ´€µãÙOl1˜âmù¯XŒ#<B7ţĿZFÝßñ]Å©ªBxTtèNÖî9þ•+EË;Ú]Ü’€€Å듾€j™($ä(úXØð¿oµúƒ¸™Uåc<ÞI‡ËDFzx4?Ï‘mÍË™µ»4ÇÐQ¬Qi·×ѻȎ÷Ip¤Ó¢bIób â{‹/Pá „þÀ¥âf¢!•]’_§²êˆòPÉq©¤4åùêH,œÂ¯Tj;Èðê‡l€elòÙ³&ø-#ÝN5o¥®gÜAg Û庀¤¼±UýÃø27ÃPÄ@¸^×ï—:½^‹¨€zö'÷=X Ç8xAñ×ͧ¿°ÍcmÎa$3Éï91Ôjs«œú¸¼ø ‰¶nÍðRgÖÙ4"§ÀóAçÞÛG$ø¢¢³Q"§Á7EMo|‘ê1]@áO,z(Ô4ò€s¥Å/­îƒ/ã Ôæ4¦Ö§èdÈîóírµ¥z$7… Q]Ðé1 ¼áJÍ÷mÀ©ÍO¢#å©`V-\ÿʽ0匣¯Áq(T0ÚD@ÞŠªü) k;ÿ.غþÊÅ{ òÿË5T7íº¥K$5[xã;Cl”çÿÙ;h­© ÕINa«¡—¾•ž:«ÚZ?­ºÆ\„…@AãSÞIƒ —Ev—9ð€¾O7elѲvæÉìèt.¨þý?î ù§-Ù?ŠûçÕ«êÞ¶´ Ût<Û¬©X´£Ñ !’€€·ee–°Ró¿íCîP7œÝìÔLÐûk:ïûWù‰§; 0ÉVYK8\ r O±©ñ´Äåo jb‡è˜‘Dv»´0ãÛfª=RëTýýˆÌ d¤á+ô„ÙH)7 $3zm+ |!>…•3Á|Ûˆ@·¤¤8½Àÿ¾üÃ/—XDðÔÊM¢+xОgbAœ=_ë­x»ˆBÿ+oø–ô¬hfàœÜ!2|†LÏ”9R¼aþn[.×ñ#&o¶7?pÆ2„x TtX3M vE]„=¹¹­ºÎ‹VÒö OÓÛÄDÃ%ö&Ò2ƒ'’ý™iDZ탒ðU›J?ÑXG÷Ü¥8<#Z;Qdâ©zk‰Ñü;´/s.>xX âsIP>B ZñNq¹Þá§ÕûËót<Žc3 BRß¾"þ²saƒJÔs³þà•ÃdÒÜ'¾®Ó茦JE#-Ú¼Pw­Z ÃæmŠŠCHúl¬|ÿMÕÿA¶š{!h@ÆÉ¤ž$ÿQ’¤è³ulÊD©oØg·ËÚ ®!'m-IBÊ,+*Ž vº ÷xwËT­ìU¾O*ûj!š<ˆáѺXF ?ZBL«úIoûç}ÅHœ f¼%dexi£šª£ÁÙ¡Ä!¿†Á¤ŽÜj$lí‹7íÚ¢ôϺ¹òÈã)´%Œâ­bCâîcG‘ß1±´‚?8¿¿|ý¸Ï~:ˆšš(Ÿ )ÒÐFdý'&p…ëÏ)šŠ×ÿ…Qéír•µ(Öïä—¤¡ËȈý†ð“^¦C´O¶½+ñ)ÜÅD}k 8BO§ÎäÓ×s‘ÿ×|a}¶ëNT-yÁ`ó‘èuݘb1øJÜ:ûIª’þvtê àMÖ Ùž*GþŠºf!“€&B5þ°›ƒÕ·¨Dåx({ ,Óu-I¿Xüö?¬uÛ~\pÖ!bRÇ‹Îjíէþ±2_˜ÿ dw,¯œC$+l°ò+åW2•(1JØ|íÌ`£ôé1²?º¥Nþ¹'^Kg2Eä N’€€—|Ë›cn›ðæoŒø5Ѧtrx§H‰ºí Ö©>eòò5Î’cO¼‹6¥óÛ>‘QI‰ÿ¿€ß?:tk›¥'I†ÍŸü^=™ìR›·Â‘^ÌDÉ«ò ¹3G XÇ:…oÿ—‚LQ9ÎB[éî ¾Å"ÿè( oqÌ ¬Ï§Ë˜cYF?€Ã„’ì¨aUtœ‰ù¹ø…BõôæÆÚEzh9 ^žÈi[—Þ·ËmC0;‡þ- ½ k›®o¨æ¦›r9 äˆ0m×ÌÈ„^s³Î kb òÞœùuCÔ¼·´*1?ôªÁÒ‚¥ùw–åˆ]-]FÞ\1îÛ&ì`FG2ÿ ùÿS9È]MbBkøQgÓBaÖœáÔ2\/²SC½Uîá­•öe•q˜2=‚uɤ•¿]Y£c»¼È‹DöÕ›]:pG pƒ¥Å zãNï˜Îèü¯Í›¶“¤Ò>9~©Æ³ÂÍÝtø¬Æd/ü øù·>BTXPqñ.&~¹8—Ê'¥±î.•‘·\nߎäZ¦â*:ؽ“ìö£)nãK†µtÌ•ÞÿÅV¬Š3β¸¼b—E ”s‚bþäDlã< œX^U´– <9¹ËÚ¥3t[ÅÈü±Â c¼&¦åÜ?XÚ7ÅÌüÑËÒùÅiÆ´Ÿ/æ ü'1í‘{?“ZûÝæYäþuQpT–ÙÁÎvÔYÈ_u +äè“ñ9”chL+Ðåx»ü•ÀƒbgWÇpI5ð‹w3÷¨ÀK$¹ò¤ßÔ ÏÃéK ·CyìjeLjóiýø5PMSëA^ÜE}F`3Ä¿øI¾gÛêÜÛ'›]-kXK@FÅî~ù´öÌ¡èôÏO­Âº§K^àªßRQ½ÒÓ¬8T?¾v¾¨W¯ÿ4A¡n%üú‡Ë¸r ÿ#É~ºIÞæ0€ýêÏ ÷ŒÎÍ'Îö0#+e©e- ulu0°aóÒâä}Ú}î¹xJfo¤§%¨üH¨°™lY qdïç®Ú„3)x±1OKÌÈö-ßOo½¼›ßX‘Q€`–äÀxsÂ64ó@2X|Ô g­‹úT4 9_õàEoœ§ÕøêŠî‡zôø*`V¼³ªûûÌ<&PÄ»nÐòÉ@õQió’€€Ë|^`ºy œ–7q“´2 wLS¥÷­  W=¯zˆR—£u&£Ž5xBQüoz®\²·P°vĦîŸ`õ:ÔÉnöNœʉ±Åë¼ånšEB’gÚuËàãBQõIŸÙ÷¾6—®Ö_´±q‡¯ÕcKTÎÙÉ£ u@”C-íGÕÒÌÅ«8›3bOnƒP)¨Àž aJ•Yl¢s|EÞv³ß#ö_OX~&YüÅáTÕœs+ô_Pˆ¸ ²:Η†÷†þügM&›n7ÅŠ°9l™ ’NÅ•ç"‚4îIï²ÑÕLªÆ(gØP‚]@%Wã áÉ^P!_.ûé8¢JóÒ–‹'Ðé/vÒ‘v\ŽŒEua]¸h³£<1¸ð>åÛ°Ã’žÓTÜ Û!;þ$Zéwÿî›æ\ùüJÊå'ª Æpwëziž?;Ëí&@BGy¦¡¹3ft7A±Í‹dÕ=HÄäàÏžÌe-¨^hj3.!ùùwõ^ÆÐeà¦úî»eÌ!U^³\A9òy.`~êUêÐûÓ€³ízW­êëwo¢ïÌ6q–MóX&ѼÄq‡ß.:Õ«JlV̴έ'5­H®.Ý¢a h@‚ˆ„Fï^ €°r/ ïzÎ,ËO†gàÿn¤ÝÕìu”uÉÇÙåÀW»MLÑÀì€Ãj*´»:tûÈÿLûšZ6ïp°‡Ù-{N Bû;ÏA„VN;–‰‰O0íbͯ=6ˆqŒÚø•§:ëÌuÕ~®ÛÐm$þÊû}Ö^uv%¯­‚ü\Ú`……™´Mƒ6{µwÜM7­. ðåažò€ÕýÃkµœÿ˜¶´shrÈø^D8»‘Vkx—…KË>éˆÞÝ·]÷º]q}5¼n¦‰Ðˆn›0פúï·š£@›Õ!‰ÚÊÏIKËõ£œß[·2rµåir´–F&ßIýš>^ýŒQᜠf] :žYhÇs¬êÄŒ§¥r5?]9–³¬Áêß.&¡‹%Óáy¿1Ì>ÀÌÏùVÆgÄbg0¼‰öw=FìI8²ùt*ï±ú{Dÿ¦eócê! äï‡mß^ÏMƒ¯*öþ„oã}ªÞðíðmêGa$ïi¤.䃉Í2W†Ï_[*È#Ô6vcí_(Ãe#ŸX‡(«â³8éÛDËT›Ÿ¹&EÞ ´©¹ ø„Õ…D ïð@t,µbÙóxu@üò0Ïl[¼B‡ýš…Œ+>Ùû³„ÏXÓÔç›[ÃóV«‰|nšþ‰‹-#m™ŠÙœæL‹Äóþho2•š/E\dÒ{ špSRÅ=4È¿ŠNi®ùò]5ÀvJ½û4ØrÑöµ‰9œÈø†“ ÕlJ³ZrÖ|Ãí‘”–Ì ÌPáÑEr»„üòÕL´7Ä=?7}”=W º<Ã÷žÉ÷D›2²P5ÿjÊ.ä’Ù?K›?ÇŽqü2}MõÅFŒÂ­š²É‹3Ê>‡—~‹3³f8qºR'0”:ycçr«§DKé0Üñf VLng·S‹Ô7!:qPØìß­^Äïý=RP¶Ž@{³ïCýb’€€âbñŠ“‡–jdYè“2€Žw .B’£É®0OÊàÕÏ›í'ðj2Éhˆ”Ü›€F%%¥d¹PV9”y®ü”c@‡§=ã *ZtËþY”³JøŒNrÛ à)0s¿óféÝ6CΙIÑå𣣼©´¼_¹€ÕVüðö.#ĬäâS öÚFë¢Ã27 üÍÊäÉß™¦ßÅäzÖüÖtð_¹Õx‹Êm};ÈIg¼2]Ëo¢4ARÍÊ/7ë¿S«2MåÅDÛéô ¥Â—V³¯Éà͵*~:yŒuï ¯ÌHµfæåÃA­‡N7?¾}OÅ ‡*’˜™*áÊÿÿ zùÞ2j¬5…­¢Q-ˆëÿ±×,("¡~âJSîl?¹âÙÌÇçŸ%Óé–†òvØI!§†-u,ùþ‡:†YTãïéŒgÓ¼d]庱 ‹‡…‘ƒ½]q K?w¹–ç$´]çJà!¦8ŒrS-+µx™HqÄôxÆ?,)C­–’1‘;9dš"¨=^ø8׊ðÖ·³ç$Íb8‡Í®Ãa°Do£[s~þæUøå̘«®oœq`D£;úŸ *ÐÛˆøeºdh¢ug4zÁ7»”&g§0ç‚:^ÌéGk0ïÀtŒNìB¾ˆ„Úò?£å>§q7ä4m=þ3¶à´¸"#c(Iõî÷öîj–ï‚@þGÙ¾D _öÀZÄ”c¦×Õ«bJã¬Ý’Nÿ´ô+äv¢ >S€µv­g†O>¼ïÎøž“ÏŠ5œÃl( *:kÐúÈqœ…ŸãÏ‹¥LÒï¦JVbYÿ¶ ý›[AãüݵFN  ˜–ükK£#B&Ñ)” ]"¹Õe;r/1}™®qgÌX‘TÐ*«›éF‡Ô¾„‹)¹È::#ðö»©iœ¤ÁŸõ¡”ä]šÂ}0="¸ˆú" JMk³î-€¡0“Õ*ì` ØÑïÒqPsÐÚBýœÀÙJx­$Ëw×u_ø†’@Q/úÑÐÙÊ8Ò”‚q»‘M(—UŽæÅ%g‰ÕKS_k mŸf¦@¤b³Åù+WŶu¦¢õHïÃ;_@—º5<TÙAöä胦¸wcJhthÜ2˜í8Lr±v>þPÉ©‘×Ryl²¸ º8<êŽékÂÁ^p’€€©Ý^õOtÂE~•ð9{ßÔ¿„)‰ýÇn_î…hÔôÍAíÊ„ƒÓYŸœç¡/‰7+l@Ã!ÞH;>ÅÀ¿|Óè˜b•ÊÊb'ò ê§O©ÍA s#Q^_ÚØŽ³ ª–Cˆ¨È G¬«P,Æ€èèûÑ Z_™/gþ/ׇ›ó9ïF ć‚ì~Â&(›ehçWœU8†6¹‹Fh&,l§À­Ê WB Áp¡<–hÖ®ºé>zÙsðÌÑdÔ·²//sšG!*~‹üS´¶ÌÐ-e€âòùã5¹—4cð ¶YÇi1 ”B=àËÊ1•,w£s™e-𓪌X¤-ÜÆã˜o‰þ²Òâ8^"×ôÌãI*Yû4‡ûšÚÜDØÄБA´ „òB†8.ÏVZè‹Ág龇ÃtÁ§ÁEDÆ€{ä’JÂÖ,œ~¯ÊoÈaÅw˰ ™$(agøV~lÊpI°;‰3³éáéÀ ]Kü#ô«>Å•D" î[‡¥š¬ä`¿TÛ’R<)B^^nîÜ=)QУVìÀ÷L}5‹¡>9 # 1äô¸ìÙñHÄHå”6Aœ4&6T• ™Djê³-AŽsöÂ:é dÈYã‹É-jqÙ5ÌŒaÖ7§I5é'ÔºI<…¦î§ÝàÝM‘³ÌDüª~ шáÅ%$å¤û5®4Q’û3·HJn3¡pJÞîp¼u‡¤D+ ‚q±hô>Ât ^†K•A쀻aÕ* ¹Ï8g㮓ö‰~Â&…‰Ä·‚ÚjJV€©Î|ûâ¡y‚8ŒŸ<À½¸Tâ°üç~qF~+ÇÃüÇ¥©ÈÁr%ºfëÆ‹"C—^P²¥^tÁwÏçñ/O+ù+]FJcú§šÿx«Wöm`Ÿ“zÕnˆl¸ŒWÑ@Nx™»Þ¬fê-,–R«È~¬Zß¿7kÃ-ËÊ¢M$±´HÌMä/ gÏkàÿWÕS<Ò/ożêz%qŸ¬XQŸD¸Ã™;¹™œ”q½¼u¤Ntxy,€ŒSÂFû‹@’ö¤¡ìdœò®]Æ ¾Ç[¿|9µpøÅ懙çAP€0*§I:Sq9„5SIe>«±ú¡×a^’üÆ0Õ©ä×#!«mô‡·m ~‹ Ÿ¥x梎 ¡@‹[3 g¤1ƒù| ßä`¼Û‚ !K‡ÔðÄŽci¹<úÔåíûöËÎæ5˹/> |Ïõ†`gß—ƒ½öyˆ&#ª,«AŠu*…Æ£È1O³}ß#ŠpʧcÅ]5L)—%">%utk²Yò"w:àe‡wœ1f嬹—ÁG~àQn|njø8…Êj6ct|Á{ßð³S‡½Ç¼wÞÛZèRÌF–÷ºŽÞ+ý(½›…Èš RN îÀ•àó-Q‚to/Іvª}åñÆ@Œ¿Kþ³:43’®NÐ,òWa9mp²òV+œÎŸÀ(§¯Š­Ñ1”V‡öC†0Ÿé…³‡ƒ…@0A¤´ÆyCYu`N κƒÌ‡)&´u+4Í—ÐJA+Dp^&ª@K,ª¼^—U.m¹¡¡ÎJ¾ý{U,[C‚µË«4Qßw}O¤ï;j¹n•b\dGXEÅøŠ(ãápsû—¤Ó·7ÓU F6I›’€€ÄÇ_û¨‚M¬R-Æðˆ³­3’ j™rh”a{5 B¹?¿ºéº_|ÖàPï.¨SÇÐåùƒí¸K8j•—tÏ zfj°·‚Jf„:}ÓûÜaJ /_É»BÜ*ëQºU“à¨p¤>O½š[·‰×ºö»€ÖLî÷7ˆçH3)á†ù–ñu¿ ÂÄ2¶ãN…ïÈ+d£dÚyTŽLù+õ– ®$ft“IÎ,Û˜­tîC2Œ2iºäõC?‚¸ç‰£¬Š$ž£¢‚7Øô Wê3m#¬u†ºÅpgÅ”1Òq9«„û“:kQÝÐaü®u {ܤœè”u­_ÀYÆ­†wvDˆ}ê~nhò0¸ð%ðΖÖÇWÏžgäñ&Û8-`PgÒ#;¼+ZeòÜgÇò#7Lžûh/ÝÒéÙGŠ)lS'Ó ɤɗÁnZޱÂP¤ó`õY‰å¶õvóLqê}*΄ås‡ýS=ΙΠWºÉòdÔ¦S,ƒ4HŽFêOà‚‘²°r4=¯Å–ŽEâ|Í©’ý²!wɨ~£Ñ™; Tn±ïD`6ž"É[6J íÓ¥é`àN.Ä4›¬¸n>erú,g¿©ZÒâ?9bçO/%Œ…#”oˆ3»úµ¢æGˆâÓ¤µÒ_)ó}O뿲’æÁ »@I‰`)õŸÝ]&yz͉¢k’‡Cô}íçŒIƒÔ²ÅM‡ýÎ#“Ø,îa“€š°Ïë4Ààè»´<#œü ÓëåÇED¡)ëù}D5µ´¶Õô+Ë?aUÅ^OÇ®‹z{—D^5’Ó)Åä™<©Îã©ÛX£.ùì•Y®M ë•ÏrÆQÂî±`„ಒ­ÐФúGXt^’aVmòÿöŸŠ'ºYë¶Ö—#\뫸¬“Ÿœât=—_~z‘ç2•n“Ã{Ñð…+F¸—ò¼kG ½RslW”ZdeÎ22o–ëCªLæÄ€±U[Öy" Ýè;CYg}üêÕJOSðúEûÇ5Ïõ+W’S_õUSYr¦´EÝíÞ$ˆŸ ¹v·(EK¬)võk¢1Û„9aÉZ„ I^ls¤´à²(*uµ4Ì3þð™É–ûR€oAißÞ5ÿšk}ùƒ[h”º)’€€Á46=ÎÇqÙ êÜ«°øp®I­$G5/ŧçiòpþßM-èx‚ó2Œ?ûv•,•×¢=þ¯*R>~ꫤhâÁჷµùc„ «é²zé¢Kù¬ê³ & Æ7†Ži/y¬=·ðØ_ßúS’³Ò ‰Á‰ ž¿ •÷ ê÷¬áÅ{kXÕ«û%mksT,ò™Kï¶$¨'™Üd&R ¶ÉÎ’J¿–GJé€Î%Iä=Ž ñ€V .¯ª ¾Þ‡ò‚otMïFÌiMpD6OÀ*á ‚‡Gg—Ów"-Ñ*~.! ©³à]]ÉYoùvWÌ×t™.ر>bW;+ Ñ}-{[kk0-ôsX5KÚ¸cŸ‰¦ -½U~“6ÿ.í¡çãšMí×åsä<¾4E,ø&Æ¿‡á”CcMh½A4[þÊÌÅÛqç¡âôÜ>bXU¶€Z™çuÞbí5Mqf¸”½FñO䱪@áÆ¨¿l@Û^¯WåmÛ—Ù | ²ÿÞÆRBíUë¹±x I‹Tsƒ2A§áý˜1Å“XÿŽ>Ï$öbo‹^ëWÙÊ«ç*;Wá¦Â?içžÓ»o ´ÄìSÿ’Å„Æî^†$µÚn«Ig@-%Á%¢"æCÊþ^ÚfÑš1ðÈ’õ;i£S Bˆ‰^ ÿï‰Z ’õ2ÆØœtÈï•sØÓ³ãìªf‹+°)ªò—†àmÀN©¤AÆà·Ã¢Y­÷C j÷úšƒC.U ÂdËè&#~Áìw’˜q^’ûq OZB]y»ÕÚ:ΰÁÂÁ°yމ±í;¢æsíʹß1Üc9ÊÛH³"fÇÁãù"!Ó\-rD©ÇàtáA‚ÇŠ„±:‹¨âß­q£FîVß)h¶ûR!™õ84L¯¾öK2¿5é yn?3¥У[ Ì~])ïÂ5‰î5‘mÙíÉ÷[”üËi&V UatjãWž¥jˆÆ Bc@§q>Î]o¡±›%A´ÝÒ6T–`ž®$ò6ÂŒ%â öýôú&& ëÈoă!=·+F3™O`èlcô q]§5°ÅÖJ>XÉ (ⶤ0¼Qí‹K÷Tû J[Qîw5ׯñ"&çՒe0Û£ßhêå"Ed@¨¢²«Š¡¸-þ½ˆê’€€ì‹öYíã÷ìn9¾Õ¾ê¯×󢕗È÷›·ueD2ã ^GÓ‚«$d£” VRrrË¡ír½Œ 2Bس%£™qB•)fH6W5È(èÅn$x1˜z &áÈ»[ y:µQû’v4NÙÂŒ$%¢”ˆ`ÂtT#@ðØßX¬kgS„7¨ƒ¥‘@ºk®™ÄÚk×¥ß!J[j6ퟎ‹_¿ek¥ìÂò‹›â‰ð(è f~é(¬Æ™_$2ܘvÔK^ aa¥é8ñŸ¼ÃKIȳ¿ŸÆr v•• ÐùØ9,½&ëÕ4¥6þ<Ìëce“³þ¡Ùœ¤êZ}²ø (+t䊫ñùQ\øJa¨^ÝD™'%H÷ 1 Éu,÷ÍÔ¹-à ÝR#˜ñáÁ1ÓJ¡gùõ4L“Ñ`¾X9Î1XN»ÝeôÏ|ΫF]¹æ³ð¤M¥¤^6»yj 寡ð-Ù©Ü™¡ù~mL×9C§xTBe¸DPÍÒ¨·GûYk”¤Œð‚·#ï¤TòÂm”0'“ *ë®Ôd ð$œQ–šÈFG–›§ÕBÅøTå3`·d»†P‚ã‘oßwUœ,àyP®›Ì•¼±LrsÙI.OñÉ'å;Xèu,²5¥W~È |O V ¢K=ké÷{Ç¥TÊ.€dNÏ‹Ã/ª’Í8OÇÀX3ð¨_˜}Q˜Y Vâ"KŸ¢5x㔯F¸ñYÆ4 ¤ÚLq BQz€+-âšÁ ¦"ÝÜpHÀ^ã‘ðEE WºÈƒX;ÕáaH"UÕÙ81R¦Ár] `zè´‘5ô°ŒU7Ð Þæ“SL §Ùù'íÜd½e®Ôs¡«µIÒéf«/<ŸÔ<Ìï:rLë»åæhmŒßöãáÙ6°˜`4ø†”^{묲£çÈ›l›)¦@¾÷¤­IäÇÏú~_0#5Ò/êøb”ê^(˺DVßÀOþ„ ¼Ñ”_ßÚFá‹M½ 7î{Ò©(=ÓYZW égŒÞä> N;Ÿ5x{°A $@¤B«>mµ«-¶RQ ‰è#²­×Ý ̲ÆùeXuVŸ ¶’Ÿ»™Ÿ5ú:™nnÙ2!‘Çÿv’3d2&”÷H§"hÌå6’€€ÉKäkW¯ÜÛÌÂÝI»›Ó)s‡)ç¸CnH¬¯Ài£{lJ¡‹ /Þò3Sá¡rÅiç©’Ó–PÖS‹˜3ì‡dWzá†* äíÇpìT"M­žoœpŠÕ©B ¥fEo][œUž¡kÇ`• h¡‘¦3n¾ãƒpqºd<ü³¯”›=[¨›ZHh´ƒPÈ<›‡ŸZ²|=}/ì…·ÐX ûux"/”Î=ìf}X ‰N¹úƃð€k¿uK¡_!4ã|ªÑ[3©á²Ì63ŸüóðluÃ5ÅØai¥ ˜{aXèýCh8z !M|CŒŒ-ŠÃ”<Ÿ£`'>ø·-')¨óóIÖ‚ M‹ø!E_-ê¥ÀnÓ*ˆ©BROž|©é£ˆÀ˜ò[ª·Z.9Ø£'Tv¯ÒƒA=’I@+U ¶F„Ëôã—el·Â 6”­i)ªS ç”·¬Ùœ<Ë0ù‚’ýÏ d{“aó5ÒÊZ"#X¾öÔ^eËË€Zq«–`]ãw3íþìoó¿žÞ Ó Àà>Ã47`0çx€¤/¨vx `òö»gø­4ëst9Ш®˜‘÷Ì—Í3&•êv _+kÖµ¼Ø³n$;Ë(H >°å¦t’n¼³^( y TW¼௉ý7K9V}%)¨ g8zs‘sÂú‹ŸèjŽ×³A Ôñçÿ_m~gòšPÌv'½M¨/d‰ b†+šYíò,—J¤¦ÛXáL˜DtŸç„ ž¯ã%éJÇm /I›‹”Æ1eñƒîI-CRÛ@AÈÓ5·ïÝhA¶W}Ù7él*í1€’€€ßÔÜÙmfáv¬nø­é:®[}é£Ñ%ò;µ¿Ï×ËÈÅ2W|-ÙåœÖ•mϱ#Ù‡ËÐ?µÁ6,Qàñû-ÒÅ×”ÈÍ‘Õ&µçõ‰©é+eûõW¡çØð8.ÃDrÓ©…Ùü:öߌ»b\ÚÇ@ßæàæ0@R‹?!=âTòŽÊmÜï@køÓUüí£ò_Ëùö6 ¹L14áñÁ“áÞézîù?é`}•é,Ùƒtó>ö¾6{¤P»õÙÚKLæ**Ã0àØ0˜T„ ½Su’f#˲9†â¼–¤;c•f¬F¼ñþùÐd9´¾Z”zIÃð¿€ņɫ! –íÞÂÓøâ'AôO\rƒ–yÓBL¬ÊÝ^Y1â\a]G !áu›ƒ‰_ªì,|Ì)eÒQIDöò`’@Ûa†Ýd”Ü·æšÁ#¦sãŠõ]g3Nym&OPÔîן3tFpþËŽFÇü fŽÏøÏn¥ž0'Æ$©rQ¹ZÇ÷XüøÍÀø¿dš@éÆÅøîÖÂd¥C¾ òÓ>I.ĆÅ|rm+-Q¿„<*Y¾çS‚Û&VÑ'üÆQô¹~¢}Ÿeêé­Ö3 %ÔzóPä^Š#vloµ¢_]Èd¾:;ü—äs…^«÷×°¦D?h^íß ¶°k¹Vü¸è5A²ú…z“–q=ËhýaÒ6ÑÉNƒ$ŸŠUüþ±bôè\ð¥Ðâ—Â6¹(Ø­—yÚ«žwó:y9=V‹j v#Q§²üªF c­”Òss]éXZñ ·eJKÙÉM"$£Dwdñ `¦ ç2ÛP.·ÁÛJ*|Š˜ä¯¸Š[†=NP±•]”¿ØÀ8„ kÝèt_Q.®K)½S³, œ «·`¨ZÇ·sÁÉQ(åÞzÛUÉ»ã˜8¹;ßÖC¾ž»MŠCâ(iÎYǽÙ3j“˜øŽòÞ9Iv EÝJ‘j‹:܆¸ÙQ©/2©sS‰Ù ùÏFÄß´!àþ¬‚¿'ߥb4cƒ³÷ÎÈ;j¸ž®Ú9Zß0jOlí¾Íz°¸|O³á3•1n[j>?]¦ÿ)øšÝ«X]Tm‰´‚“éǰwÙì”æ“Þ 1X"Ë_$©&ÄGO„ szo6µ’‚ß“­óqê1xÉàXëÝš!AKbQßc+-/Há¥{öô9-ž5“ÍX™~m£2$€xM·H“ã>Í\õ”š½½B—j[3i¹p5„¨xZý –ŒlLˆ£Á®ÓŸ•¢ÅÊLì \@2GÊÖˆ4©ÅÕ¡g‘›-Y EÎ € Ûu-Óÿ~8>ùœ™3‚2ÍZ-N›ûXvga$æÌ؉ ÒÙÔ;”ù<×ãëda[ê /ÉarÅØ¢D-”‰ !º Qµ¯Ž ñ°²…ú.f½Jô`G>¡U¯AKT¸_¹ÓL†XÆûÎý€[ÙÕY²ö„q8ïxÌSi!R!h¼É¯µóš¸¿5ìŠeûvp£?ì í­û·ÁMp>>…Iq’,¨CÄÌåU:Äš,Y{WI‰‡ëáú¥ìÀ9âˆßõ$z'Gà‹å 7 g| Wÿ@þÒšÓOØ~Oì ó¯ƒ×9bËYõõkÜžh#Éf–{’YGÚg•­ÛSí­õ°\ìE\€õÆöä”V+°ÒÄðס<½7(÷ðʬ€# á¿ûT%.·FT â§õô÷¶=Œåa›:–­D â÷ Μ,äâuH°VYQËXq5dÍ|QËVÎ:MVr¾¡¡Òt—h¦»€f.û{/ÝuÛN˜Á&uó³c¨«à¶Bv °«ùltgOêu#`-v ÒYn]%äR»\Ál‚X›ƒqx™k†ó–BW`Š= ½~O^šz „Ü‘JQì§Æ(Õñ±È6ÇN%<ÀDãs3 ê‹Ýè'7b°k†xíD k¿j£8„É<[beè‰|„wÒç=ìzhß¶‡µˆJÒ’€€ë…‰å?-7(µš3úºÈÍzŸSà³§‹*nFëÊgu !sò²ƒÆÔŠ žI¦ýr*ZÞ/Ä”9G˜Ê!-Ëù¸†¡U~Ž^;7n˜æh ]s'È*„£v&¢» &¶4Á0ôâ5#?Z•ïÂR7œ/Þ€n Ê%ÑäxŽ·w?ljëDFäI}Û´ñšžî¶ã ‚M’ÝäWQѰ+èImE„í6•¤¯½d %X?¬b°‡ Dsõd4F­ÉúŒej{O³vmÆŸ[ø’∥r±°ƒd‡`¾Q/éó/+ÿƒ°Ï=üóZYýðŸ°` ë£mJA3ЊaÍd¶‹Ð©÷aäGuƒZ¾`äëäô!¬ RÈ'ÁÓiò{Û|&:V—ÕÊž£zö=oCVÑ+2ŸÔv‹„Ë8CÔäñ’ð¼1D8÷B}lÐÚx¢š•írñ3t«§®Ö ™‰˜ÅÉk°ÌdZ8G²4ÿ"ÙB—9ò&ì±¶gó¹àÛ>ä¹#$‡u>„b.Þ¡A|Ëh9Åüjg¹ U®dBZ‡RMå?šÖP?¡Ç†Ã–Ðg‘Û315kŸ"öº‰*Öæ8ѻëf¬á¢ºâí½¸Êþê̵âÃ:ë¼wWfÉGaÃ¥@åðºâ}ã>‘~VËm;« °£”Ùìê§œ1Wx_[Îõ"|&>é.*½+Ï-£rª=V¡‡Ô·’d„º*Kã/G Šþ¦ü¬¿í$TÏR-©>ä~êmR˜‚ë1O—Fì«`>õêÛ£OˆŒÚß_ý†¡š‡°#õ÷Áÿ°Å•'ؘ»HŒ´0(sÕä’€€·£Ø7ÚL/x"‰á('Ü5vÜ•06ßÉ{:éÐ&{i–°Ôʶ”À6^&\i¾|wë*ª—IHZ¸‰2b¹°&gòíìGÞ¾&ßîáËDÚ]Ñï©KHO›.SNpƇˆ‡¯J-ÙĤ‡H0¼Ð*„ªà÷Â&;§ø!¯Il­8—¿p+<ò¼QNCY&S¸X³ð;Ÿ"gß ‘íyEbï1§MŒéÌT庛õEd )¬¢í.ôÿ;yáÅ ñÝÌâCÖR1–áG5%b³Âçßõv%ºŽhôC¦~…»ƒ…+|pnŽ™ãZÉ÷K0]ëÞ¼a”]²5•áÜÀ† ‹Ïg}Í \tB1á3– ×S3V&-Ó^£ðºÛÍJyêC.‡!ù;~%ª­§¼D“Ý3AÌ ¹“ï²´Õ(  ÓŽïkB¢Ž/¬ì·™:l\ç’~º“&Âãà^¨ïì·ò¶ÄÄ 9á#AÝÉ¡à»ç>-e`РܰÇ/н†fÙŒÊ;¬ƒ1}ö‘žÃ²™‹†/·åXº[¤×c¦Þ¿›2é®JŠ÷W,+ÛÓªw±Ni¼Î@ã¥Ävœ©“RD]EûûÈÜá3x¢Ï¤¨½`$5¤§{ € Ñæ„P¯6nïåØÀ}ìG’€€»0¾P]'k}¡#=åTÑl€…Ñêôҧߪ¹H¸_•‰æK×këRi¢Ž1 a±‡L h:ÚHõ¯þËΣÞJ÷õ\Í] }%†œ\z¯F å1L ¿¿Pí;:ý7©Ø›„‰Ó]5Л¹"c —i"eã3…ÍC‚*S*Ûõ!‘®ÂyxßÓ½— hBš]µA{ÐgµÜ©‘:uÃLæ¿}¡%7î yK„í¡FÀìåî†ÕY¯ú3zÃDâD{vø ™fÑ`¨\:R‹<*CL«úÝÆ^ÙÒ¡><©þ8z­foY,Ö¼]„@â‹*j• ­xÇÍ]àï®Ð{ÛLçûUC³¨ŽúCn$dLº9€í(­(uT‹ë®&!̧o6DúĬˆ\âU-gú‡¿(—[73É£¸£N×wÜëþ^!*d˜8']Ðy !m h@»Ÿ9¯ ô. KQßšÇÒ7[h_¡Y…ö©oØ„°¬„Û”qðåyT¦pÞ¥Q_´ÍˆÓåß!1Ñê)<÷<`\ @iµŽ—mÿA×‰Úæ:iTÏ€%97 ZI´_£ä«Ö+g0Àíô-~/ %¹K‡Í9ÒÑØ¥~_c"4*8‹¨{Á~É­4ŒD H·s6‚+ìÐí¨®”®F|~†U³ü¶ÉÆì×…¼µî£"ýÖ¶¡™ÙRØÔ•ÑÛr¼QÏ´ˆ›¸„~Æ8ï¶Z,wé)ÄÈ-þK~¤ÚK îÁ#(ä¿'õÖ´,àn?´ä µœ +pl®ø-#àhsƒBÀÊŒÙÕÚU  ó¥ÚeÛBdzã~*íÅG\ùí"ˆrÂ.´éŸ²Ó¤ 4)Ãzr‹zÀ×°ózAÀ˜Qnc3Yn“d>)ŦæuSl a1!lÚßê^ë?‚ ÓŒ Âédعl÷€ü ‰‘• ¤Ø× lÚýŽ&}”÷ÞM/‘ÔRv6óv-`<åٙؿ^|}F‰"B’€€žz“N ¹†EsˆCp!º¨t2"?€ œŠ.î/Y ׂˆ]þ¬îgùSØ’it.ÖF³6[k1×Tˆ¾;ú[ã… ão<·°[°Ž›f¥B­øg‘» ã˜WÕ6| ÛkP-Z’XÔse­•ç£ÝpNø…fSî§ÇÄä]Ó6 ¦+•vºÕJ_|CxBN¬dïžO6oˆæÏ+ÅÁ£)iPŒÙ Ãl'?•"IjY æÖ‘üàí•<Àýr l6Ï0Oìº æ}Ç,”VÞm% ØèíSSÜ"ªÿgs¾#tߊæ’öªò0Ä<»G˜”OõGyëHèî©jnÎH{Äc…>Ϙ½±¹ðûÉ'þßÈŽGøŸ;¶]”3©GælÕj?¬È‘)–O<Þ½e_eo„û9¸›tˆÿ¼·"=xNí5vÌs$×ýÁØfUÆÊO°46·YYÝ#~Rã×ÓÊÛ%‚鱋¥Òß‘¸)ûÛF€êôÀôkÛ||»ç$Z@Ú±|؈ÄbÒ†È&a’̎ט"PœOôÔ©Kï#-Þ·JM-¥Ç&bIËÍòC{5{ë»7=YœúéÉ.2¸£€Þ;gMÇCý%7 îî|¦b­h6ªï÷‹'ƒ44Çë¦ÿ] ˆ)³¨Ü ÌŒ‚¹®òß8Ñh¿&Sµ…Χ¿RËÙ­³$>JMfü"&Šƒ—lGÖ1ÙX³@Ô:¿täP6‘A‚wÁН¬9oΧ3¦Ÿf€V3|pHД*XOßY—§/8,XxÞRc‡Ÿç{²BjY' ‘¿<,0ÝCÒ*’«™ÆW|;tØ$ÒÀØ€B‘ÂÞØ Áùxõ ,$”°~ ñ€ø—á“Ñ ¯aT¦ëN‡¼ÐÄ,7?mðW¶ƒ3æ”ßóîLÿ‹“(§¶6½¢ñ†¼hsÃÆ2#qFu½¯¡"ëè„ÂN’ Ÿg(ûÒèí‡í”ÔÑGÒu¸å•ÉX‹3ßE Ùä:ÙV²W: ï3¬Q¹îx×/ (ŽfŸìw¦õ9E´t‡Óç\˜U‡?ûÅt–dFw ã’›û3 ·ã\4© nöËŒí首Ån1æ¾`ùùˆ©«YhE9šAgÑŒˆŠ§(Â$‚bnÕ†"UpÒ›kí½XÎ5’€€ÇŽuúŽöö¾97ÒO>©8pjw-°À£s.ŠáyÕožÆNŒaiÐ,Üuè@˜Uš>œhm!ÎúyêøÀ¦ÛÙæàíÝQÌÆ5Û‰æÔ©ŸÐËŸÑéa³]Ôë ÐxC濆%{K¼€ƒ*¸,ú¥9W¶ÿÇúSñ¨ÃMΉPwÁÿ”׃Oã»õ¶Ó_rÙ2½Ô6^ùà ÞÎXÕѰ„ßÖ “MçûKý Ê!A´]€+Õõ2ÖÓ}Xüa¶Ä†±'i ]R‰ø¢ü1†6înÿ£ÅÔ ØŸŠ2ò¯Ç6MNÐìµ C(ߪî7 2+£3£°$¨ÈŒ|`Zõ¬co:ÄßðWƒžØ]Õ¼JW»s?2>ùƒº¸ã¸U±"e%h5­}²>"(…пfÓü ÅðËVÂ]â´‹ìäý§¤ ©§w¯}<Ø‘é?T¼šÎŽr30ƒ“òm¶ ’€€º¥±v²?È*¿™¶r‘›Ø,±Ï§lûþ-è¤ì··šJN1ÎBÞêðåuYäþÞo©ÄÙ|Ã:à»)±H¿AÉL·ÉH‰HÑIqoFñäÚÙ°«ñm97[BµÐ’‘™,Z(¾Ã W5%ù{â/çÏÑÕËYðèm TûäÊ÷ ‰ðèBÞ•^ ˆÎlCÝr%`ÃŽï‹ îHée€3÷¥‰­µÃ “miÿ ŒÇs?»„6«&#¤}Üž>õoí’HÄû×@m0«ÛxÒ÷nQXÂ.NL‡¯™ÕáåOµ$dÈ¡Fâ£É?ô¡šåµIJÌH‡w·áÇ Tª_MÅùíÉ¡ qwl g„ͦ]ZxJÅ}ÒŒ°&/oVNzæ\öÆÀÃQcƺe#Ëô”AœtžUú¤<©¬B &` «ëw`µËw$&ãlëå¿Âñ5¶ù¸Å¶úÄ!$^ÎA±¶¤9§’à\(SÏÍ\ý™_Lˆ9ѵ@D‹ w‰ô Ëvž$È!HÇ8 £Á€%f2½-âÅH6ĶÖ˜0ÛêdŽ<5¦›,öŒQ=“ù$‹‰"ÝéüFá]±hÿ/qïþ¨àgG•yÐ×<ãˆî¬FÛÁVœ°ù3ä!í¾W±½:ù†Ãc–ÿOÄå4±Þó_CäyÉïU8‹È/ÐÕÆëÓB?;Q[öÆ7Ç€;Ùƒ<á¬KŠ©!i¬ÄVt‰È¹èü¤÷Îm #H¨}©ùþ|ãXòÞ¶f#1æqèw& À € ¨#V§¬sÝÑ)9ÉÊ(ÃÈýÑ7À¿0šXÂïñÉqÖÄ¿)R* Ç¥3˜L!zà+ ¡úž¨VœDÝ[c>ùß§‚ZÑÁÞœ]ƒm$àÔÿìç–ÚnjߜJGÈ“üöè&û#ßÔYq¬Ú{ëjDZL³b'xa-¹½«DaSµå”<œ€À„¥'@ˆE0áIz5‰ÜöÃ8t¦Ù_ønƒ“óp^äz“^ûÙÙzd)(0Å\øŽ¥Ûˆ÷…ƉÛÊ©¡ @¼~ÇŸq .T5ø¹u“ìšFÎ,Eºé}F-§«²´/ìmrXׯ9Ó-qõc/“z~°µ×ØèQµ³³(j±äJvŠ^©ÕÍŽiÀ$ˆ¦0ØHǔ “ˆnhh <’€€¬Úͪׄ~À¨qt‘‡’³ A‹±GÂ-‘éé7ÀÙú_¾£ ËhêÖè·J¯3¿ßp®+T·|0”F9YÎ',v)¨dl6űj³Uê‡,ù ç'½g•WtøÓJïx<üÑС™ÖÐ-~-²…-lÛ|íÝœð -}OÐo4W„ ¤·T1kéŸqôü¯K¿SWú>†yyb0lΈPL° “ýHˆÄLlí¾•˜ÃØ ÐFê&±¦~©<ÅwùY:Ê ´ÄÄx"ûD}’ðôßRb²o„®¨AVˆIe £xŸð 8Õо>šp£S4Ã…J¨6öTíÊ+3Õ\.êݽãýn#ºbó²‘Ú8”˜}*n:x_sXYëvvì…\Ã÷—AÎ{éãßk„Þ)ý„gX_¶ 4| _ÜçL›XÐOš&Äòðó€¶ÂUÎVH°ÅLgš®•$‘?(– SnK ÛúmWÉp¯e #Õ ËqÊ'Å"/î‰è“û‘½?6W'LHÝ\”*3q B,®ù›r*µ×#?çÊ÷…˜ÄníÁïˆÈì"Р€Æ*>PN¸Q£D|þî,Æ–þd†*ÍX%@t™(dæNÉŠÕh”ñ‰$V×õÓñ6˾+„?·v‹³ÚçáĤ”¦ Îüs‡™¨;{5[À*p(ç‚:}£–û®qrq!ª®d¡ÝqãOËè[ãytÃ%ùîDþrBË'§,×HðšH¨Ù¾Ö¶d•OÊuر Ð3» ^ðª2èˆìØd'Mè&NàÍqhSÏÐÉ~‡óÒxº 6™É%UŒ¿uÜè!<ý8>ñϵ”ksª¼á¼8×½cãDkž9ø–à2züCk›! °jçþ» b "Î00œt*%'mæL¯µJüñŒ›-ü$n`§…»6‡Yø&~ÿõñgA¸ é 2fÁOG)ëðº-„k^V{ÄôEÚ*v Ö|±ÃsE(+Íä¿$,68ªzFºx‘ÌÂÿ/(Ó$i÷B;€+zh͉³”¼[ª&”z“±2Ϥ·`S‘÷Éùê"D©›ûŠ BÑBA5X|~xîLÿëVŠÃ=œŸ¥76^^àyƒ,äx OŤ?=’€€·Ðœ…È|7°†±d''c~âÇ.×NÂ{VŽÒËDÜ£ñÔþ±Ôh!‚U1×ݲ DhDBÍÐ $,ñ:‹•…ùGúŒÂù/ù¦”ðîÊç©§ªÃ”]¥€!Q7îåbœ´î§2ë¤n/ÏI+!Ûu?³šm‰¼7è÷/”…G?ŽÖÑëX>ëZšÚõžãÎ=i‘#Ùe@á xÇ¿DêâA ó—AéŒLd“ãuŽTË«ôà ß) Uî‹)ò9öÌ®:+ß!] 4„¸žˆ¡$<Ôä­ ­½ÍZéy]•åòqv¡ÖtئwûäµE  Îå²zÌRÑN!Àé*»\ß&Ÿa¢•´?ülþ" .Íõà#½¬ðî6‰–·#¼ÉÀÔ.¾Ú%]p†Šó~ “ý™Ô*;ÛŽSÏÑ©9 Q9 ‹£6z¥ê4t®¼H„Yoî*!ŸI½I×ôoòÚ3ö`ã«°ª¤/åÓ›}¦¤XŠ û¸܈ËC£céÊVùNUë–?!¡:RvpžK+x$(v¤ªåþ-´u!*·ë³¬Ù•=ã¿øŒ#%ÆßÏ5•h­¬ÐƒÝ`ó¤%Ûžq”¸Ði…­¦ûü\¶‡j¹ö_ uÑlÐk¾™äa ŽVÔˆD†Ÿí9“Z‚rì}Yê8fœÈ,Q=%ItÓÑéŠ ÜH¿ß!4kýyguˆ¶GÝp”Áé3Dø¹Úc0°¹q$å{|‰¶v‘ò޼ÙhzØînÓ›*ÿîòÜ”'‚æúW5¨eÇÇ 4ð$ÌŽÿÛΙ¹™UÀ†£3P ðÄ«®b‚uðå¡õ\fî-G©S½Ô ]µÏÓ™Âé¾s-ܶȈÇsòôÿsVÔ9}÷÷P2Ñ4!r£\–¨¹„Elc4©®¤/ßyk\VY[€"|nDd+±3K}/5’€€×hg'Î{»]JU' =O2í)wíå{Y«²“ølyþwòˆ·1B¤*>ܤ·Ö2¶<|ª½Í(¼{—˜\9bW¨ qN¾ÐkÛ«“›_L9©1yVõ=¬êR(}wŒw—˜wX€¿ºOIÊý)ü…Nʹ¿r ÏÞt{´+H­¯øÔ}çy!Òæ‹´A±™Öàö‘ênÑn ‡\‹ñê$÷ ~rAÀ+­ä:|6î,áqÔô‘.â´ààÏÚ†@Â×’Ó¥Œ£EïÔHæ?ý|ˆ4àïH CC{ï¶Äô‰>!pd­}AЇƒ”aWØ£wÓ/m–K”Côçû©ré›B.3lÆ|r\ng#´.a‰ÀV2ãbãëýÔ‘TÛØ›$–=“ý ÷?H«i…lIîÏÆÃ´/Öè0v±PÈúܧÐÓ<£%µ4—e^{#¯ŒtAô"P}tn ÃúûÉ»æÞ1´œ½&ÝgÛ]·Rš~Ô!œpv&ÅÖ%'À9ÉÊ LCÊ“g7˜d@r¹ëù‚!Ê—æû^Ÿ«ÆBí'É\gp -ŸŽzâiâ~¤^lwÙ¯h.»cÑÁÏÌSÔ\nÀ S§^/ìy~»«Q‹O䵕 çó(HÕ”f¾-ÜŸ'x’ÃñUrœ^t¥6 ZÐ\2ø“—V¢Œ«ÄǨ;Ž€ç;†ðInõy,߸J˜‘!ÕÐfk„¶L–‡>¥wEä,£½ÌµçŠ’ƒÔ ¨ázÈs7ÄÖÿoÈjÑ­ öM’Ó}Q“0˜™X G’€€Ä'Sã¤7ƒ@*ºàÅ»',G®Žµ> »±)¾Lx í1UÝëVU7n««BÄ>&SŽ,¬{¥çàƒD`Š7 R›gr\û5'Mʧñ~HiÛÐ3T˜ä¶ŽÏ† ró„Ó;‘‚}”‡}­Í¹lÕPX>1‰f¯¦4ëImŒ‹ÌªW~KY³Á`†8õ_xQ¸ù æëã»Út KèúHËëÊ! Zvá˜<—XÕÂÝëc#:,*-оÓÀ¬T„à®ù/;]Š˜B _ôidN1®ÁàYÚ,Á§H‚}ÙLp{¦Äâµ÷À qxºb< æhULïj®×oÃ%f í¤À ÿ (¿91„T~x@)'‰Zf ã÷u-̬¹··ÂI=‰¥1NyNA£²K꜂(˜É/ð&T.?M‚–>’©Gur Cd:•‹}:wqO¬)€*<¢y6]û2&‡’ÖE¡5kÃ} ïÊOÚTOxkyÕ6òˆ¹‘P‹™û“-óYÖšž»„(4LÈîE_˺ ˜u—þµÃŸº‚ªþï=º ¥ø[tâ«øÚf8W•ÊÀw¿|²Rày4äÜ̪•À¥YYùY<ŽL ìd&­W"˜¥Ìw†©Ø@B^ÛÅTm^Ò¿««™É­ÂÎ}âGžÆPÎ nަŠÙ{vZ”tH$‰[p»ðÄ:²z%˜nL[½–á i7A…DW•“ô´à] Zv1:Ù綫ΓšKæ$wY<ÕÆãÕ%Ébñ<}\€ ê¨(Ôí½¡ª–ƒç/š}÷-¬T@dëaøZõ\þÖNµk~Ÿd„p>$áôé-)\mÏý4•+8…²Ç©? ÀÇÙjܬwü¦BøR»IXü®D+NÑvãºD£ÿú_48Žóê~ú©°të´Â ŽŽ Mz>›]Ë/nðÊ«ãk»Ü{?u”VIÎ9 ¥L¦utÃïñ¤eD!A¹úÆÙ nç“ÝDôÝžY¥bV:2¡'ÎÉÓ—äç•‘’€€ÀAX?ª„*yÝ,Êî”Æ³â¼mJ‰ŽÄér×}K‰ñð;7‡+|ëßñsÉ+3ßï°{ìö&.„kq`Ú:ãwTÕës[%@ÌFŽ7$"߸e;¹÷£½ËÈB'Tïÿú 8X`ïÓãoZ¬"Yê³öLh9ªºUg5_cÂTŸÌùÕ2ˆo6¼ÃH0Ïþ?÷!°©5è›HÉ¢–ƒ²œ9n(}$Þç µ¾µÔºY¨f‡‘‡1lóeiøªl ¦`¯#.ôUmN]H链8b}.ØÖ¿£RóÊwt?e—ÇâÔE³¼ ;òê£W†‡Î¸þêçìÓvrµN à_R˜Nf1IÐ<€m`å ´ã¥]÷ J0‰ÖIµ”†„iÇǰ(N¨j:êù/Åç–2 m¦Þ‘¼u”ª„} µkôHL,sîÞ6¢Œü¯˜-6öuÿð\©‚•hEâo¶!c’w, ³±ûÔ&Ö#J’mr:U yÀƳö¨'7G$Qxp¶çqU†(c¢CAjûŠÛ{)´WtÅÚÅyóÑÒãJ¢¤pûH‘HÎÇ2–k±V’ÃŽ¥W£˜.âítÖôiÁùí3¹êʸPÌ~¬ÜcþFYýÛ\ÜG—ÓÞ•©v€z¾ÇR¥ÿ½´’f„ºØº‚1&߃=®ueµ®Æh' abÑÜXÇêÍ‹#ÇDßZ%c’€€Æ³û¯[“ôÁÇþŸ H`‘þÑGX’A’ñg\:ó¦ëk”æ"%êß}B¾G§Wfƒ‹ýK-4ÏÍŠ&´ÞÏ8øÍYмo»¥‘ÎZ¿'²úÆV„&rlÒ°ÛÚ§®i?ݳ,)M=]“Á>RÑ™k-%Vcq ÁÆùÝ@BÇåÖ°ùÙ’•jÞ’»|%}÷áýØ)sôÒFôà˜Õ©p©²¸÷#Ðs±¸Ïi]|[½²T :rÂ1ùQÎ ÆÃcßoJïŸqì’[´¨$ÌUao©ˆ—šq§,ù7X1ÑXubUâ>I˜‹EüÉ̯UVòõ6ß1‡<ã„Y²~ˆ|5 ª‰¿ð×$ÝR[ª]Ûñí  —úbwѽ;7E<ä>ƒ≜ælñ;oÆy/ð[P¼ ‡>t²>‡\µýTc¯ ­Ì@ <¦•´£¾·¡§.ý‘EYpåìD ízfKWM;ͨ/b¥Ã¾+=Gó#™*°T»E¿1OÅìÆÇ–Ǹe©–G„é}WWB~nÏ¿UàK¼ïéöÝ i Â?…Ï(MÄ$©"%uK¿L¾CK ²äª†VÌÜ´Ecä «Ñà7%‘ƒç†€à¹,¢õ~t'ÁüÛý—AõÖ–Mv²]¹ìÚæÐ¢C’lNÀ2¸¹¾SrôœåÏ&&é¾½ ¯ALôSÑï«D‰šâWÙ2Üð: ™Àe„wÐFêdxX8ðøv"ä/Ê£ÿýP!¹6ú¸S†ìÈlÈ,Ý¢¿¶Ö–Ô§º €똱5„”›ºo,®ŽfæýÌs…ŽS,ûÏ9"EDFiÖßõ‰úœ"xì*ïØ ‡¸bº¸«Ôö-SsÛû›Åï^À#”0æmîÚL%dˆRï=×+er{-í¡{Dé*èÏÑÀñG¶qlg(í•úg /Ý¿Ïÿõ‘¹¨ìxêA—oü”P};_7¡HÅM¨¸¤Å­Ý?ž\kqEíTФµv±]® ï¥{Øøü‡ÿ,’)ž +ý%SIËLwwBL‡>ðª¸?ȹ|9‹%ãOµ1eš¸à4yûvZ²ŽBN¢†¹&?ãƒÍIá|Ü—jíPk<Ý"ÿ¼Þ°Fþ7pf%,¬z,kÖÖ}#F‹ôòðÚË{Ö-±l¤mÙ’€€íoÖÚ)ÜšèX°\Þç.¶ëpåá·’W<Õ3^Ǥ–Œx» Åÿ×pax[Prx!jÙ·ãsLWŽ&Óm5”É>¤ŽÁ]q…™ˆ§°¯Ç9Ñcú[2£W VÔü;iÖÔ¤BtWwN1L›m€†¥¥ Gô1Yp%¹ÔÚpS‡5µÒÝé RÖPB¢Œ‘†÷°ˆê B_2g½ýÅǯNóL‚ˆ>GÞu¯ì=®>S]°@ïó!uonånÝó“°ei*Ϊ«“¤âv5P0ž/~.?Zú î–X™(Ì <×s£uT={lm•aY;“÷½¡Pw ÍO2ÂÇf²y’{HJ®ÙS¤úÓº~=U}ёʣüž)bmXÝ]»Xq  ß™(©K>;‘Iç Žbˆ¨ëd³ç¸Eˆ~ïî ‡Ìa2'|ô.cÄÎxÝܼßÛ\#¹7Ñw¿™ÜÔ‡9ÝFŒm<(ãã8q “¿§¥¼St7›£È0Áج÷Qì¡]ßîû°óQŒ„·¿² ¡žòF™êWמÔ?茙çØzص Ï÷Ê7¨æßÂL•èÏÉô3%WH‰TÉ)`u¸¾· /_yY€zf| ‚Ê*DæQrØKüõ¾ ”,}…|á/Ø3çîÀEøâªG¨æ^xq.)½ßeép—¬“À“Ò¹Œl3PðwaÈóÒ|µŠ {å†ÝÕ9*M<Ù¶\ôÇ5#°³np#P@ñyÿ÷k-q³…j:IȉåLv·õ^Òb0a1\²á±×/îs¡`þ+¶7Ãxu:þ§ƒElÙ©}ô9d㼩´b…ÿÞ" pw€'e |Ů٫ÉÊI4+䦎é7ccºp©Ô DiNŽÎâȵzžh_„¾þõ!9Ù1Ãì2æ8].¤KË5¡ˆj:2@=O·S¹Û@ÜT†.yá°•%jÉÒq&]Ô¥ìñÚáé“#Ѐ¨(N}Oc‚(?kñõ5ætÖ†›Èú£]+}$€)šh®owûš°†h¿iôꆱñÒú½-÷ÿT‰6àj¸ûÅI‹ó[ùre×{»=áY(9 ¯‹ü±p$Ë¿°„Ñõ¾'[¯×B5¦ªA/¿Û¦<øõé¸,³³’€€ªÜØë“ ã<È6Ž‘§Œ'ÁÎ!ÍA1ËÝß¹ßFü®y5Öβm›x!4bpù n£V~qÄ!å&ÜTu`â9n/K§»?$L~ºs÷–€L±ÕR w¶ªD1.Æf²a{n}§Œ6®:#ËÑÍuð•e!h&Ç©¤W¿=ñ#q¢ÑÄäÇ ò1§@}ùEêᓟ7ÕOVÈIøÚåÏÞe© ¸1×÷'.6ÏU¬Óµ8ÿ-;«!-æª_lÙ;â…1äÿ³xG¶›+*åÈX룭¡ðì„ ÓuZ’fÒ¬\’ªÏ^nõr°Iå HVT‰Kx@Ö3†ð¸Á^î$_Pá€ãpݬ¼¼›8~IEã)]'›> I°ƒö’í¦W|Üâ¤ÂýÆ@7]DWsû Å‹˜mµ¹wñQÙˆ+E¸ÌKƒ¦Ëðë¤NÒ| 6þÂbÉ^÷`¿€ZR6·ï…OªAu »û¥@ðÄÝã*£ï>dýÈÉóv­LEï¹³zŒCÀÈA¹·;Î ¡uiØYz&n‚}ד{fì0é!DÙy)X—³ÄLÞz£Ç¿tÕcéLѵÕfPœ6aÞ\ø l‡µt]òÑIÕF®ë ê?ÆYb âš+Í`Špb•]áÜBű'dP‡cõÝ.£9ÐmÅs¤øÔB:Þ+z?ÁEB‰¿ó šbd_É`eà Y<øR M¸KGt‘Ø]2Dp*8¬2Þ—f».û÷¶¨b'ÞÌ^1ÿg“„@TÈ-»Ò{ñ}j€Z¢Ù­|ãJm;iL­‘ ­MÕ’^}½Æ=Û]YþÄC0ø~lŽwíÙÙ^0á‡`~ÎÙF1ã© ‰9œ–M²ÔÚwW0e- O«'ªÚ0„—"dþ.ZþLJÁ˜Ž’ƒrµ³d†ÿ›ƒ ´Ÿ'¸ìU)ež›P¶Ó»Fòº'’o9Ó"Ô·™6øÜ4Õåwa›I`%‰#ÇqI„dX#‹¿¨-™‹ªŽ~1_¬¹‹ÖºiÆâ@éDc’S™îFå'°ñ@a¨g6ü ø¯‡ÏGKÙ §¹#èÏž®÷e¼!›wb|ëQî\"W:²H û §X ¿Ñu¿ínÇ*6e†Õß¼’žãæd’€€¯1¼¸$ì™6lšù—Жû\ Á(÷ÊÆÅïŸÚ7ü_†Ø}ËÀµg€+‰bˆ2‹6— —¸à$ºSÀÃâUÒŸ‹ë¢è•m/!‰’Ý£Y nzÝlÏA¢ ¤ì7õ7¾Í­™Î”4P`ÀBu[ýãÏfg)\Q*ëy—½‘BÎæDítªBÂsV¸‹ï½—5¥!W1reŒ‰9h«ÙÞm ipœáÇÂ>v¾—ùL¹Þ‹ê)&5&¿´9C.öP…îDÅzn¨€s÷¿Z¦‰ì}íÆ#Íøñ©Ý^nÿ‚ј©ÕÓ qö¼àl€æ]öC'öxòpBGDYý~ÏS]ð;·óÏË”±ÖœÙ`$æ’ß¡zªQTu¸ìNi ub®$·&½æ’â Wÿ¡íz bl  ‰H'ËÕ3Äß@!À9“nª'½T1ÒücU^ýÏe5‹¾…üj5ÊM­êáÝ?é£@ößßûòÈI;Ó’µÔG# ÍgÔ­•¶ïñQë$OÉäXY6Ç$ú‚¸Ûn0Á˜rˆŸÉáAc Ëì½?˜Ö>]E9‚ñvƒAiÂ}ìv¨¶F*‚ÄHˆÁ¸€‹‰8ÁÇ]·Á'Ì£"mÌvÞùDŸ^tI+ZàÐ>õºã©é`H”j¼­ ²¿v˜ÿT˜È¨iu@$ÃMÎÈT­â>KÆtA4‚΂Báõd0ì½®)'ø¸'h®žøÞÙÅK²IæTXë§GFĆֲò©tâ”!‹ÏˆuKDq1ÒeÃô;a RЙj [\3µÚ<ûL3‡l&VÒƒÉA]À-ŒÍ–D²p–Ë8¤s&÷£JÔmÀÑ¢Êõáî÷v o•KGˆ¨®·W\ÎnXhï „ˆ½ïÚýC…R. ÉzÄ8¿eQ„æ0׃Ið/èão8—…çºÚØ’?òëÔõ_¤•óïçë X¢õ  í èâb¤Ö܇cy×\DÁª«¾ÕC–{ç±9WF ªòFúàðW>‹9ÔùTÂíšÚÔÝ3Ò¤ ö.If)ÒÐ@VUüLËä Qi·&óKðŠ[o{L§Ù¿—™aG^®ÔChÝöIÌÑéL*9™J¤› «¹¢tõÁs¸t/:+¯¸Û´Øû;’€€ª…lнüœ^Ì9¿ï?òo !ïÔRJ`fJöleÄG¡²™w›÷0Ø{y¯ É-TÀ°>ýf)–ú@„P2œ©w„·sDÉ$qRЪåùàÆ¾s#Xs+’"êZ÷( áµÌ˜&.^"þã—ìÿÒ°¶®Øð8²™Îl/ïÄŒáïث Qß6jAZþâ‡ýÍÔÖ2á=ƒÂÁÑçøhN ‘áÀÁ {ÎÔÄN¯éür¥$äß07•µÐ,/9À¬ïöh/‰…R¾ê`ë=ìè'¿¨:VOºÖxx{Áeëy’Z /fµpžå§ í·_ü‰®zïv™§@µ X¬þ¯+ŠûGw¿ä1’ÝÏ› µ€êÃçÂaeDÛÈB€9M¥¬àY*Aïîaâθ/±‚è—8ùL=ñãb et13¿™³ü—íI°š°¤èïÔ˜bµ97…ÎW¸üÕ»$¼þ`:qÓ€ì=Ì #>xÊ™0›4ŠAÁ *vqì<(B’½¨ñ@é:þÊ‚ 19æÿ1®Å⥊7¯Bˆ†Cm¦ëV¨#“!O sÍDÖåŒm”—ï^â>¼'í6– ü§AqÁ¼ò˜M™#˜øû^‹áëmå˜M «ñ¤&¸U—~øóyätã.k¬‰ž[æÎ1KžÕ§èQøõ‰Ûq^¼´Ç£ÛÑù0§é'2ç%Xi†u‡<…®Ò3îPv¸Ë&„ÉõÚr\˜¾ØÞ7XÎHò±îj«Þ¿ž˜aZI~±Ú¢ô¤–?CVçç¶YMÏûx<ÃÕÜðò̤¶³Øï2Zëp'Ì‘˜HøN@µš"ŠgDX9{ó³MÈÀ¦Ç.ÿÀÐI`tÄ&O?>RHÌbár*WƒÊ?ÀhÌ\&”°¥]cL?½½ñÑw¾Ùugê<‚®vÞá"§/J{¡kÂï„Is‡=ųU¨ü}Rjîp/ÄeyÞHfç‚P¹@â}ZPš^þìä[¾GG˜U™üì¶ï@qèZ:Áie[ÇC —d\Gr¥ë¹‹‹—¦TýXûù“îÀ Êrß…F~Ü—;-'P²Ø:í^Øx¬_A¨‘ ù\F>Q¸ûv’€€¦Áù#ŽÊ_¡v}dØØnnôºsªu Ñp¾’‰YôM¾šóžá@ìG9¾rÔB%F¼1 î;ê\ÊÄéŒúlfTk\ß^9bRo‡ÀÛÅïÆË «Ü’¶ „^ýð­–žvŒ˜Žca7Q:˹OybþQwò‘v’*–$–:¸Ík'ÿÞá"L¸OC™ù]äy¿ŒÇH›ü¶ÆŸþ%ðC{Qšm‡ÝÄ™Àå‡G,µ•ÊÕ‘“D»Õ,„Ð¥I•“íy"“?RT¼oäVìC„eᥧ²m¦EØÒ½èëVZLë#MñŸŽÑ€C| J‹ª‰1{ʳIÑžî §ˈ­—µ£‰9~ ´EÀŒ»íØš)ô¹Éõ¿9è|É2µ´¸ï\h¨©ˆët :í„î0ÕÎéQ8 ¤Ÿ£À>Z=O&Å[WñmiVP/hsèÙ‚tøõ"„öûX¶ 9¤E%µ>®öž-È)èM {N2²˜µÇÖ.@-bߤ xTe .¾‘dE=ïôf«tWG­ è—rÏF®ŠK‚å¹ób¦‹O]¢¨£Ù1¯$(þyDY¤ætôy¸¬ž5^¸æ,Qè´ÅcÅâÆï,nGö¸°›‘‚À|m#N'NˆoÚ¬·Ôã!Ú\ðbë©hæ`މuV©åÁ§D›÷¢³SÜr«L"jg¿šö¬º±ïÑ7Ä=<×Z/DWBïBÑÁ áÔ5 MÝÜicÍ›*bc$± òîŒ`GÞº+0"ΰ€+õÞVédGð¶¾ß#LÛ-wÛÉ:Q¬Ê#ÚdÜÊ?±hØ,þ4³h ¦`ñoHÁg€x²>½öÊ•CòUéUaö¶cN[æ Òÿ—ý<ÒöŽ45¸ jã¢ÚÓÑàâk_âa`¸¡”ì¹êØ´ ¯h°ÖLÁÁiŸàKy`™½tc¿(wÙ[&€¦¯¦%£Ø˜ÜÆÿ]Â5ÿ5ƒ*“–ƒÑ’„ã•¶+†ßj˜hš[Ijâ-3cô¾ß„nM/÷ÓÂÝUrŠêé ¥­vŽÉÐ+ävMÛ9}9…Á½Kýu0Á8çÃ]ÐúÒa_Gù_¿e½¯ñ X#T] ø½ŠÞæÿùË`‰í W,¡$ ŒIæ}>5çákÈòRhW¿’€€Á´€´Ü lêudl/ºŽÉ•Ê$gŸ"°Nˆµ°÷3™…a¯°Ø"œ$¡ø‹«¨­¤Šêç»sõûXÍ¡F,ÍRrRÜ‘„DžísŒznH(5ûèNˆÀÍ4€ýÕÃÑâ å?—ÞCï@øö!ˆÆé)“ØGÊdëäqÒIWžÉÀý êæ4®ÃU'(Q,‰pAžùô Àß!ñck¶ÊqÌò(b¹YÔÜŸOñO ®2÷qEl"–wØÈG©ÈÒÞ^êÐE¨hžv'ªÝ`*ªê¬KVRÙÒš»îFE’l¢§ÿ/€›ŽU‹åBTðÓ¦´Øá\[ê…<°{¤&ÙA—SÖövqx6º¨‰bÙ$V “’˜ýœ®4Äì¼ ¾ÁRí'û-»´VŽF4Ôñ{#º«(tÚ6`ç aE5ð\a8`ƒ»kn±ÒŒ'"Õ.6Ebé´Àú™ß1õ–`¦·uˆŒö®FB·•ð«€q¨ÿ δ2c…ù†ýìF¤×¶¢è#i² wšÜOÖFÞ;$7)꥖ñê*„`cžãy¤þâªÓ 1´SWYÕwô™8¦&dŽ‚µU1œü–Ãs`äÓ¦`Œ?—†ŸâJ3ñ@ꉰ}¦î[Źýá¯ëIä°h4YMx?9-1ã(d\ÅpŽ*¶íÎìæÁß8¿y×dê+Ô-e¹žZ  ]Äø3'wt¶ÿN_Ëö U“óZIo#äDÄÀjC&R—RoäB®åàÇtæ väùÚa‰xféóˆ-ÙcHÜ!– ÑÉ´æQ¨àÁÍFµJPÇ€Ö#Sñ¹ÃÚLÀ3h¨—Ò¶fÒ®¤¸Ö5D[à†÷„“HvaÀ?´¢‰±WºÊI[’œs¨Ð£ïÒ@´³¡nü«ów¤\žÔòVR:y ’HbýfJ”¦°-®5UÉàR°ÿ·µ9oDtRZ ¨ÌßQA)R¯Kˆ©TdGˆþƒ8Ýõ«¨jT,±F;.YLx“H&üNñ£­'çóŒŠdm6F§ìÆúçAL1/7çÂÚš6´ý3.«Ã>mºÞc-$jx b ½ÚSë‡1Ô–? æº.&€8åÓ1N£U(g>€Îœ©®bó8µ"v†¼+?4ÂMÑŸ9 ÂrêÍj–jB’±ù*ÇÉï™>h@‡Å³? máB}¤"ü„•8æ´2Œ"{z¹®€é*ÔþÎúJ?ì¬üP6 ¨ÃdH‚Øñ ŸGVv1äËØ Ôú7`©ûa¡Éš/’¸‡ð?>‡ZákÆ@ö‰ØÌÃÙó:vƒÙãä2äÿb9È ðL—±8<%…=o©] ì$î¦% iy„¯>Y5^M ï–H$†×]I{YYYU/ç!A½ûŠ.!¢õÑd‰©˜ËM®õA_`<;Ì´Wt¥ÇЧxûdžf¬¶ezû­†ÎYáîj/ÐyDÍ9 %·‘dÓzoÚ w壟D#ØÄ”¨"V¥áÎ>4. ™¹O/!èÇv^T…jõ‘ृúHÏ mªA-/úûyLWpvwð×›Äc2˜ñee¨R|[O³7™wÖë Íãèˆ4 átåR;äç–|/Ä®­‰ÿ;JF’…ûÆÇçÃÒ¥+Ïr¿æa‚c»hÚË^õ– ™L Ãâ–š®‘gÅc¶‹®·ÆF‘»"ô?@Ÿ*BïÛl|~âIƒ©ÚŽe5œ³aÁBª¤ð>èΨèÎfßP÷s&`;gð#‘¼,ë_Š«Sûm¤3ša/w’€€¤³·5‹]â~[„1 Z{+fêRp[]gBÀÈY(ü°-¿‚¸ ´·;þÁ{Ø&“aU̸(9s½xü™jîmÃÑ«¬'줲7')zcÓõ’7O!#òFlB}du¬zâôõ¾[“jZ{@£(Mò¹ñö¿N &¼­ÈÔ?*b¦Ö<(zòÒÆl*pŽdHª²:¡ÇßÖ ­ýÈz£Q‡§Ýª®³wè©s•Ê{lÁÇ.?„)›| %†^Ôò`ºvýÈ]×G™æ#y©ÒTë@ ß]¨_÷š¡ð)Þác=å\Ÿ¯“òu 8Å©1o#D4«YÚ3IoçÓy”%™)òoÛ-wÜ¢˜ª^ð]K¼Ý"àH!aÂÊ={t¼qݪ÷%pz'ñbÑç£Sfœ¸ç €Ø J¾2»“cÌRëb™uI7`A¹8vb)³±taAL³+5êñ‰ªIÀ£Â*œ T´–„‰ý´#ÌHãƒ>Òdókæ= ék4>†O€cÛ”Þ6Ö{‰Ä­ú‡è´ë\é^©^,˜ VnÑÞt7ˆ6åÆå%Š UŒ ׫ÂZE¼Z¶†¸ë·7qD`^ëÐîk¯ížÉõy4/˜}>ƒ&mé™ û=·µM]lŸŒk!Uba;G6ɆuÖ‹]–ç›ü¥l4ÒžÂóò]Mh¬µÞŠÞÄôÊz|„¨ÓLèí9–ž] 2âA!¹Õ©HF!2Ò3§Ýq˜—À ?tð€µJ™F ®[áî^U®ä˜bné®xabò´ŽÛô<\Y7Þ g^éF™ÁãaWøx º|( XoÔêCÃÓÙÕ“OÁ—4ã\r½ôà9bÙŽ.ìq7òE9 éæã²ð¶¼ :Ï4óôÛMD’ú,Ý}òÂ@#"^cC =4ÛtFy¤Âx‹á2Ù \›j¯¿ºJS¿’SA`Û¤“P[#kÀIo^[•0$ü #•5–ßÕÒ Á¸Z«¯yµ"vX¡ÃY<@ŒÑž¨ª„F¡Tç‚ù˜²?5ØÆBTÀc’ô,l5$¢(`ê85縤µGzÅ­38ú{~êŠ e§+GÛ¡ç·—À'ï§ôÊÞ¾2x!¯þ¤—BE„Ìpt×VvxH )½ có’€€ÙÊÐáOíË¡L"Ù¥œÆ·ˆ*«ügä’‡ üðÀTÍ|,2rçö( cr•A&¸*²ŽDú›¡F_ `hAýìçÈI¢m96½÷´‘ÝÞª©/j.YÀ &ÿQj;ÊižäºCµÙõžï'±Ç#ù)s:QúÆ'K~(Ñ8 h¦~À\üØaü×R›,Oj£üKo¸•|‡eù`*9^á©»ëÿù^¬lf Ú¬Pkè÷q$Ë$Ú@Ò€®iÐ/Vô@qP^2¼Á ¼¹†6GÌOUM¬…ÁWˆJ§E¹E¶l&¢Óëž 3f©¡¸ñOÊSûóñf¨~³v¨t(¤Æe…Y] mú׿ܓâžk;ª€Ë=ìç–¸%îÀ{L<”EO/žpæŸÔþ—DµƒynT¯jÊ®¯™ðMÐ=QTtú¦,t?’ò«¸‚Óæ÷=ZˆàFÈßXsQŸÚÅTJ{„/È%õz5±X\d8_”Ñs>¿PtŽví=í'dt{0@82ƒñr½zd'wŒz £Þ㉿~.+UT¼.0¼)þºâ wáM2ä0òä]?"ëô¤`—%ûÞ[Râ+ßP6ÊíÞFÈ Òý<^8–¹?×D/¯BSu’Z<â_w»m‘¦§[&qüS;ƒ°öº»µcPr°¨ýûM¿äÊ™Õz«þœÍ•I˜|…þâŸ$·—³‹ßNó O°¿]ßF˜Âä ï1ä¦0:+L¹³û¾ÔŒ&0­?G©yŠ.¹(n:ÚiûuDïÁ¬È­1¿? ꃿø-3–žûOó-¬´§ÜöÔδh‰ò#þÕs§ÌÓjÒÿu´´Z…‡Ò}vP¿9ôÍP_Ó¿¯¦†Ù·(–MP„Ñ=]&€>«R’€€«£œZû \ê,b°ÿ+•FC³¸®ÛcùÔµ1òäÒ*Ž-‰g•ÿ²fb'Ïzb´d-›ŒÒšô¡Æ·67ÞA®ôáÈyŒ—¯“Œ-½˜j€UÓÖN¼8=Ú±ÆC1ü v§xGãªÖj“¡bAÀÐ|³àž9Ï‘xªa’¡Rûø÷w3Å·ü6(KK±ífúÜ`]C;ÿÝ&èÇøOjÀøØsD^<¼Æ»Œ†Ê:i5>°„ð0À²Qõv´‡ÆÖ3 ô‡ÜFÌ~‡ü ybè¥lo‚ƒ1äÐÑêð7u_5çÿ¡ÆsCö‚–TÙñt¸ÚŸ%°βávCÀŒÃ5Æûç¼+4öäÛX¹jÁXßDJ•°\M»·#Å£ä{ÏÏ@7…˜ ¾à“`yn(mI}<“²7œæ§I¶6ö¥ß›þlª'À”ƒ ¥x÷ ÓSàX,8ì»}æŒÖWÆR^„dû€דàêÃôQ 48Guê­jñdVI°Š™âïÐ÷ 9`€2Ífˆšü¢‚I –¨‰íxo TãÀ4cKÓºãèŽe²={½›š½rk{k ÆA¯*&@Ý8 †¦÷E}M?Ú0š˜²ÞTfú–wu†RÞŽÕ:Úy"ìÜÄé£Î-—-Bi›€êƒI»öFŒP„ ªû¦¡ƒ¦-.-bM"©çŒËd ÑJ˜È íÐ* mf°¾âAäÆ Ü¿öN}ý¶N2ꦟoê!%øÊ:[ÀEŽ&(Ž‚jZ²Æ÷ÀµÔ’S^œÕ¶.ÍbiR¤tÎàÇç B•ª”ÌÄÔ™RùéÕ<»û»ž{=ª«™ µ^À©ÛÑVˆ®ͬQÂÅžÚtAaЄ0:¥]°Ñî?oÅ»Û{ØïÕùg wF¦ÖÏ¡ HÏw^Çç ö™<54kòÜjHf DÑ*pÉ:_ÖÞBèH=„le¨UürznîŠRÉ:ÚôÒ×q6Í£ÕÌAò|›ÄXø½j]t‘0*¼ký:åÜ£}•9³0ŠV<FFäÿ3„?Ãé÷A‰ÚÊO;§Í Ÿ¯A #Sª¼ŒÎòS'Š^ÊP¡ Ë›I¡eV=FÒ~SW}ÂytÑ<êØçr’€€ÆêS×Å‚{ôheèÇ.Ñqß+îÀÎ 'gbNnæs‚íIÌ<1ÒŒ¡©ë„-xԱƑ4ÙM]D¼™tPnýCÁ›ë¯kà­ÞÏWé`íå{Ö üÜ»wJï@„Ÿbäã·–¾óT'ØœEŠLê+ß{Á™°LåÐ#££‹î²U:žš¶`:ÿ/Ú퓦ëz÷¢@Øm+cÒñÜo>IBcè a®YlC´ÒtŽÊdÇo&7õƒ<îu.ÙY¢‹+o2¥†Øå¹åcI¶6,) 礪ô4°Ëȇ¿R (ívÍ¿ Û9â»c–FDÅŸõó®~ ­,$@\¯¬×ï8ŽDV š'r89¦hL J¡j•êå^-¾[#šÁN47 àŒ3Wý!)•ÈI‘ìÿû,ifÄ?ÇåÑJs¤K…obFZ¬,«àYZ}«¢ðÛ~0:ÏNMþŽéFÄz¥ÿP¡ê!Я/à+¤$Pb/z!Àieñ2>zlÎ;ú´œªJ笻–mAŸL[ùÔ”=ÉkG”ÞKeßì–‹bÊ"~Çíêgè_C©•)\?Œ¯±¢–ѽJšÒ lymn“Ú‘/+…èædŒq!ÜKòø²g|©±WeØfÈJ^ú®·Ž8KãÀ8bfþ\Ã2ò:ñí€]gªájן6Õè*UÒŒD£ªÁ¹ çþ_?¢Çøq‡7ḴÅw%Jó¬½5¤×`éê$¸ªc€7ÜÝØD¥=ØQÑk"§]àãp9sýÙLìWÃw³Þ«–YÊ]ˆAÿtIWšwǰ©‰§ZÏÔf”?ÝK|r]Öh”US¸ž¢…¹”,©9 ,,üŒ=lôÜ jš±Z“ƒ‚ý8á¹;2jÖ·º ±ë«}H®]Z TºŽ…¦-.I[LÚFà{½n&+Yž÷pF>óå2:*ßµ7Z‘¼]G.þ?ÁI ¾Ü?¼²[Tp¡-Sfä§×Èr{›ÜwêÊ2Cin\mr[ئÎí!W'ÏO½„×p4ˆŠiéÚ «ùÇm¶O!-Ó[¿Wà)ùZ-×Rùÿ b<æYç¤$g|wÊøŒ¥w\ê4ÙÔ*(FÒz…‰üJ†+¡ÃÎpÑOäðÆùÿ½“ÚÚ<Å·…›4E6O°E’€€îõÇZwŽþÅÓ]Ü&C ·ˆ2¨š \øê§.-Ê¥0(ðð͵š’Ê¥7šLq»q¬°î-0È™ —Ð/®ˆ¯[úbWŒ³hG2 Ö8—:+!«½Æ[åuVj}­q±Ã NîY/ˆ>H6÷‘sÖˆü5ù*×¥ÆxÕtî A(£‰ÛW‘–‹yýÇ¡·‘x í¢¯á,ì8 ÛKìj|™ ê*(«"oŠ:þÓÁžï(¸uoÎôrÖTÍCkÝÙqÒøÇ¹}"Û\ØBd´ì~êFë… =êÓ´ñ¿f<ûoWò¦r ,i×H#QÏæK¿ô¡%YÇa‘Kó%@̰Ybïg,+ÛOBÙ àš&ƒ/ªÌ›´×s#ou½õÂ{+}Ù*°è÷ÿß|%#šùXûÏ„2œ"«“äÞ—Ñu‘ à£ôåÌ^°Dò_Xm¹ÿW«¯}$ÏÜÉ—ç“Þ¨Ž=í''ÔÜ:ÃädD4n‘#óa(zlØÑ-Ù+ÈàU“÷:e‡,Ü$Y‘ŸÕ5ßâ6 ü"@ùp …UM²P…¹Þí÷IÿºD#3h·­OjUÀ¼”`{7sпƶƒK×Ï”ª'}íö¦ïé}\ 80ÖÏhn^/Ë„:‘"81Áô‡‡$²Ç? s˾ óˆ|¶6YZÄQûBÁÃ5%êEÃ.ç±YA[ v¦‰ %\v÷J%sòâ% ~-ÝÚ,nãjoüÀ+5z/¹E«ÊÓºóuÕEHº0%%?Þüª»[Àë®Äzë±ÿC¸'å53Œ«xXZ*Ç5ødȦx¬&Ḭë-]û®«Ý¡ûº!‹Z±ów ]Çy¼õ¨KÍÉ‘:™œ²NÅ¢s¦.õsÞÊ] Tµcàïn=wµÙJÅÝP,9ÉáG$+UgÖ*Àüë·Më_ë„7_ #ØÊcgÂ_í(¯ Â0s˜ õè~Ô¹,ß‘ü½dÈFa ˜–aùÁŽNæ_,Cu |©»3Å ÇŠ{Œó ­Ñ´žL„“Ò`MõÂ#8+óFÖ\pÝä)ÊÕ¤G’€€˜Ø+ïø&W,öþÌH[) v Àµ)¹×ãqÏpyžÖI§‚뜽ݴ̕ã'x:å݉±.à¼Þsë´G\X,‚Û×· L¼gdAä¢kdd]úr Up!¾æÜ[u]ƒNøBÞÝŠl·cÒæX”S¶¤œ´¿çcTOš¡ðØÉÁwW@Ha̽áàƒ•’ê§êüäcŒ lnf¡fþ*wa<=“¾n6£1$ï¡4Kèìð}Ľ|:ýBz^¹˜\Àø`£@¡¡ÆŒ8»ôшVàmÃéæ`ØB@qí©©à°.ÓÙÛâJÀZLó8pM%$ãnÏ®¦Ä¼¶3¥BGìòšþºùhÂsp<}çÞÁ¬Uç·g, ðš¾D—$o¨*m~¬(+ÓÍìBYNœµ)ò9;]ŽwIè49Vú+ ÕÅeÎH&^Ÿ]=6±e·-àPá~úZŸ-j£ñC‹V…þ.ÄÆaξnÙ/¦!¾­×-žèÖÀ1J w&¿Z‡ š[úÞiƾ¸H3âu.oÌŠ/¸¯MÌð˜£O$Œ?»"_K ÖY¼72 ’5cx6”h¤ÒqtÀ_Ñy’Ö¼ú«þXÚÔ·#W¡ŒveR÷z`J–Lߘ=Ñä/!H·`Bó(Úª Ä×®­á¡•€+§2jM—®Ør²¡r–Ìj1¦·å‰î0=t6.h'%4žî)6òÿK:#~Ū«™½ç:¥~敟D¾¦Ž’€€¶§8ånþ(½YÉýBÝ‘&ØçqÒP³ºÓJËñYØ# ?î ŽRäXtàLm÷Tö4f&¶Êbª"ò©ÒpNiõÁ¡ÆRþ5M–h?J椔  À;†„ó<¨Œ4Ƙ1™zOdá×Ö=Á ¹)@Reî?ƒõ'Z L_ú$æùÔåÔªò¯©-Ç3ñéÂà¯3L [ê%˜»å9D±W+·ùódŽÔLª‹—É6ùÞútü)ûåPä \¨©Ëúä Ê•U¢æ*†ôôö**v“@_TÍŸÁ!}hVÊ!³×M^'ŸF§±åÓŸæKu×Õˆy‘ÿXC8"ŒÌ‘ßi¾&?Þmö3°ÀÂÉ‹íª±µã¤t‰Ñ&]ŠÂ‘ŒŸ–˜öÇ–(Jåõ3Y¦¶2ÉÚcƒcÌ/¸ s?-_$Í]ýïOª[金iËý¬‘ÇÜx1~·”0‘-ÐÄá’:îËAd—3ÛmâÆ*cs´„ßÍ»÷ɶÅÔߘ‹IðM…Y=RØ>}Ô­bf+³0B©? &aÔÜdQη?þ~ˆÓ•¸‹üÿvÌH“˜³¤[‹H«Ö&.¸B>8º3opT“«‹̦›ÿtã%é–PSª6¹M(›–;ÇEØV?A‰WαÆMA’€€Í•T„9ÀNKÌúF‡oÁm+Åýiˆ0]-î*qÿ¤Ëõåä$[F €¤¹œƒU`ܱéu , ïF°¨ÉÌÔ&L- kPÜ„šŠvýId£ǸN/!“ÿ”õÑÇäáÒßËfo^~ºìü0]@(&rTäIÔs¿ÁÒëz&¨ºNý+fpM/¾ ÝI“-’À¬Hjj¯b¾ðÁ¼6¸8K¢NY¿Ù­O¿r÷¶ìl]œ-¢ïμFlÃ΄œl¬Á”7r9lV½çgðåwF€|ëï{7°B¹ŽÎÜEa¯¢w2¶þ„NÖWÁYÊ9✈pé¾N¡ V,MJ„!ì—i5J^%x¬_.°ïI£)+ç>„ºØæY¾o«üûf ^Ê‘bÁÔ I{P´ž)|¢__°¥‚HޝŸöh¹zl@ò³Fñ¦¹æ5 6œ<ƒ˜Ï<1ÅeSI/s¥Ü‰©ƒ&ÓÔ)¥ÔéA:ˆ¨DŸ8³HšŒÆœ7çØæ}•~8sÜ“ÓÊçž´ÇhR¤LK;­~ýï1þÎ|×F<r˜I)z}Ék´ñwÃ5µÞŸW¥¹eGciDúüÂN…ŒVOúáé=Ñð¹÷}ÐÙcYÂyL,—"#@Ŀ߱ ²m1Ë…“·ª¦f=L^v6ˆ­•¼æ¬îyälµ’OÛî]ýŠæCªoæ©é^y·Þ1ï1¡¥Å"Ñê]’¹KßÃ3/¡5GÀ*5yQðm¢Û]øòË?z[‹yN‡°ñ6øY^¡âl2ŽÏ–D‡o…ÌEê¨Öƒ.ÿï”w CÃ)·'ÍÏ™ µ«ö_ð”Enûöïh°44mÜ1âÃÁnYù¹Ç#|±¢µæÞ¤›Ý2M…pæà}-ÆIŠ£Iç¤nÛ¶øB½ \Šw…iQ½gþ>¬ÀgN’€€ÁÓêûXËbáe¥PÊè^0°C€Ÿ2çþý~VE>š€ôÑYÔ‡î©òt®ÐQïáDTÇTZ¾—Š^«üÁ êvºŒ°’rPšÔærìŽ6E~H øÔ°´Ä@0í"ºVx19fO‹ƒeöm¥$⽕oüŸâæFÔµ²‘ü0GÉ®"FwJn€¯–<^a`"([/“ø¦]jÃ]üݵ°Qvì?)°qe0§í=…–ÿ— cÔ1…V‘xü˜ÏµmÕ-úé lµêyÒ†åA›D‹eôë›[[²¦C3ÄÀI2ÃI,×ßîŸx-d†+™âËx~ÁÏÉìâñ­ÏêuP²üÄ®pãâi´Žz¼Õ8!ã×è )ëÞhtÄgÑÜQ¡Áþpœ½›ÂcÓl¸M€›0ãñœ ÊÕÈÓ@»«Å*JÖ DîËDÿ¢¿iñ$/.S…Œø_{•,­°YÏÞ «ÈcÐNËeÒ×ÅŒ/¿f¥(¬÷†!ëR,ÊÝRxù¿+Õe»)äÖ]ÌóP³ÅYßÛNÀ£ÏƒáRho3eeÅìé@ë¡^1˜h˜i+EùtÔ*á_°º÷ËÁ¼a.lÁêŒÜ³+Æ+«YŽåºî b k]+}~å*~x¬ƒÖ° lýÒ (eAÀ˜A‹î›ÒÜc6:šÍH[ Ù œÌ¯zؽ̻¶‚4whs•ÈY/~æAãHÁ÷'t%â§([âè_M9ë&5·è$XŸaš%Çà)¡å‚.m˜.éx2ê<"Àû®Rj&;)³pkÓYÞ«¡c¦n·×M‹›ŒBQ¦pÝrå^K–ñÍG{Ú 5%þ»P Í<™Ó„´Ê¨6¿ãw9<µô†¹×à•ÑèÁ»ÔÌbš_ú²0`Ï©†xÜNJò ³~Áê¾9j$”Й“‰¡Å2 ìgç¡tX¨tø³, ¼û+¼\#Ä4g}5@ïÇÒM²’€€º“0ôMyfßlk7‡ÇóL[ ÷b§Õ8…ײup†Å%’÷ ?ˆ™LßÓkñÑà`Šùqœn[¬—E“ÑXÁKfS•A¢_·Ð‚Qε$>§#6ªÌüíË<`Ùê<ÁWUUùˆ˜9ÞmdQÄ3[©ÇšíkkgqLž«'E¨+Ù´,âç(!ÕÜf³ d%Ń×_I›Ð!#"¥Ñ#ut‡©ƒÍzY.¹ÅcÆÌENW‹ñ¶.ôŽ£ÿKïðº`¨Áo¬Š< Í®Hê[tj'~¯© ƒ²m[%ª˜^ÿ¤w×ùa”Cé5Í¡î%U"ƒÃÊ¥ÿ$©_Èhß“7ÛUòþ€æ} —\¼Þ§w®¸7$šýxk}ÿÙCCɨ‰÷2ô@Š©=……¸4ÿérRÂǾ ˆC¾bü²®Rÿ gzH^³¡¥Ì,Eár¾± ©–g³Ik“'.VcøqÙž”f:\¢ÄJ cÛ­³˜Kk‚ãTž”FÕÉ®…¹¶oË/ $¸w°­(ãìE5oóÿ<&4†nF­ç"hËä ¢µ?šÃðjÞá8"6˜‚=”ôW ö@ù ¬ô£@÷ÏJ~ í0*D?üB†Í“û‘Ãg=©4›ƒ Ásýqäx”øŽ³Ö:æ]Gdá‚Kƒmâó^¿X×µåž*XË­Ú©Gü“°ñp–uŸWaÇZ™ß`÷§Û¶Û€Êæ’*†Ì¸Ðª¡ ÂRšg&·V²À š¥H³îÛõ†Së=³l8[HDù'õèj%f±Þ¦Ó˜wƒKÍŒE¦ïh¿Äún s}Iæú’€€Û•ñÓDIaËd+:.„ëIàpŸ ¤’uh“ä¥×‘qU%¶fJ—®p•Te€ ‡ÙÞ0+¥G½´e2åscõR×¼Ò)ÁÁàn¸ùO0Ó‰BÂ0•N_°€…šÊü»—‹1îÞÞ-ÏK@ó™Zjð!ôMtõq pŒ´·vœQÓ—`‰O‹iÃCØ í’—ÁÂFêú©šu¿úûŒõ‡n¢Gþ©§ÂšŒL‚L|’Aó"¡&‚¹4S£‡Ÿù¿ŽêÙŒâ‰áÛµªó´«£Œlã'™2Ä«¨`yØÒëÛr$Y·© êfQ£Hjé(–•²óˆ–Ñר7ƒ<<ŽŠ$¨ a!óó’=]niå­ÚìE˜¼˜´q:¢Íx½5­mX1ÏPm†=|lÜ|³t² !¼ÇhÞ(æiÿ€`»ó À½3tÚ)Ç_ù`º©þ¨xn+}¾)@î®çHŒV›ª|Ê›×J·"kúʽÈaªÝA¶+¿ôG˜Ng—löXÛèa«%{ôŸ¨éÚ>?¡ÄòOŽ©x$³ƒüR^æÌÊ'†€Í[6†:ýø£x„em1¨f-Ê©Èÿ †“ï-Aò_á;„r9ØV7,Ê/-á{ºz™>)„ƒ )¯µÚb]S'æ}ÐLEò¤%9ªu@‡ïÕ¨”ýËK úW‚#4l]vêXëe*¹LeÎ[úXüe7§bež¶‰O¯aög¹p½q´?»3&GÛNºq›/éO攳¨:.ª'IrŠRÑeʱV²"HöþÅÑKÚDöñëŸR_iÈQMÀu!±…¯l}ÊèCóÎþ¯U» &$kæý0çGàM£±ó³)3ê`žmñ>ÔÍEEÚ€ š†ï·¿]ކWÚ)&ŽOÈ¢Àþ{§f*1§Z]eQñq?1U`¿¨«ðUöŽüòÝä(v¿yúÛ`‹eK#Ÿp >›£ÈQ]»*›6ýOáGž0ËÆºx_—@¹ ãunÕó@¯e²WRœ¡ÑÉÌ è{¬ Éæâv ×Oï¦èYS¸¼¬‰àJcÍ×Wšê o:òØi0fS†ø¡“)öÓzòûá†;î kFN×0Mu×ãÊ,å Í#”g¯nÃñ ¨¡’€€Ôt+³6Qù+¯‹žDǵ΢ÓëÐ`Q¢€ƒ­2žrq¾0o䊻#÷È’7;šŽÿÒCÌŠu*ÑÆ|¤h1zÜ¢ŽTúþúü*¿b’‹Ê)èáÖ¯ÖíµD°8«˜„³m¾·ÖògaMÈFÇ%SÆD,7 ?_ŒÊ9®œ"yÀüVu°8v¾´©™†.ï~ÀKùTað²õbÚepô¬„ kMÓ”4mÞˆõ‹Õ€dì2¥Ø‘ðî³<'b,~É¢‹5†+®wïÕ‚ÌF>pÑô¿•ƒÓ­^”_A'~«Ñ£Í-O‚ yâ4c'j§Ñ ™ÊŠaÛûw3ïñ1d´gKÈ%|k†±ÿÜ“ù£ î’c»¹ì&T¸ô-ŽwaÔ7ëâ'6à€¬Äsìw±¡ uÿSþþTê®e­éuÛ°¼B® KI¹Zÿú1£|òUÄðêŸÊ0Ýê-$t³ØÿÏZ†Vì{ï$|yEºw«O¦–óUïÐHÒ÷•†«Ý¤> ´.ŽJˆÑ>S` Ü)ÑÁÓf³$ꦽEdoÆ´l•ö® ×ƒAë\}2e—qS2ŽW®J¬¥u67dÉÞŒb×%d¾_mãÿ$ K/†kw)1r¶ Ï+Ÿó¢6–Ý=Õr(íoì÷¯Æ5ò¶®>Ü\a¸§Ñ%õ 6Š;Ïr=Ý #íäuè R DHl°èÁ’kÎŽP?‘ÔˆZö;lC•uÞ³Eҋ˵dêætÉ臯Ghs¦(Øë£zzIÓ…ˆ¾¼› 8Íý‚‘‘¸[*@ÝžwðZ;&©ÁæýK5J6Ï¢SPCŸåa!‚•Ýòóúó¡‰ïc2sŒ4q“¾ØNÙTqxMÙ¸ÚkÖ“¡´Ý†ÙX0‡]’¶¶ßzæ4º ¹nýÖcËßâRH† S®gÖüÝdûäÆe¾DvÝ™Š>s¼Ú’ÒEJCïv­÷×(‡"îñ?‘Øå<=;jï9ùËžÜ퉯6‹_‰ñcZ¦É|æªQðnÔÌ«ßSûKtîÀ’`dõ³U‰üŒËï?|£Úbia¾#´3èb"‚áï‹å‘^X/·ãSEs0è+ÜØ®–‡Ñ(=™u¼ŒÆñ&PÔ¢i4Ñ)’-£}g'ä+y[V’€€µF)SÔ$ÜAyËQ˜œ"¹®9¥pUüÚ¬FÈâÕéèV5ø6¹Æ¿zãŸ3ÀWT7 bæ~ÈX·²“NÓ*kõ›¢àie$øŽÜº­rñ]Ðú6ÐtÂHZ´B÷(N¥ÍM—p«Kœò?—ë,ÔýJÏ{¬¿ ÚŸÞ¼ÔØ"øöÛÕûÌç ÍÜ£ 4άÕ.¤fô„a(.‹Af×ÒÎÆEr6ËØ–bo)IoÖMµÙî¦*d•-1ØJó IÖ|T‰ö=ëªöT‘ÿ €«5÷æK¶/š|ôÀt;1уͱþG6ThÏ—¡IØ0eÝY²ïñ½“,º¿÷оCyÝõ|‚ ÅObj;Yõé°mi½¾â»ëã‰ò ¶g/qçåÊæ|@ö¡¨»)±mò:!ò”3LPZ ŷ|åß܃!dÁõÜŒ1@Ôþ&â±ñ­ ûOGMßÔ‚^þ~úÝ› ž&nyô%µDñ±´aÉ¥ æ}¹©~ºAY¹ê“9WÔ!†Sò`:‰3<¬—¿¿©¦©ûYY¤Zݨµ[©@¸îßœ^®µz-¡¦Õ];î£ õ„ñdIÓ¿þeF„¼BÓŽŠR°ëE‘Ñ«¥xî!è7¥Úž”RvŸ]¦d ~ íñ!5å« M”'%Tjn Å¯(¹†gX°“nƒ+b#j;éAÍ-ªEnú/Š”$E³¶Æ7?þÛû¹Ò‰ž?éõ¯²WÊ&ø¢’õ…ÍV\Ñ¡ø&Ãóå2§V4…*¤›teËRT¡¨¦úÏ·x”Þ6͵Lé_q+Àt 2jD˜÷ÂÙ::£’ wÞŸÇF+} Nø× 9­p^–@!)aªI ý8ºîñ<-üxÅÂne=KëúŒ·ÃìV!K“ò<ÈWÊR7þmRA«'ìí™EvÃDz=;Z‚±<”] J}´’µYe’‚H²×;ý Éy‹…ý_ñ×uZ’Û÷9Η†6ü«ˆÖ@~§) ¹dñ½À5­<ïUlMHáîXC¯Í\W´×F­#÷ÎÖ@lÙ,U³B‘¢ldÜaµÌÏ>6@ƧԾµ»ÆëGªE¼2ÍDÅG?‹ïÍ”ññgS}nç¾/™Ì ³<*Çà’€€¿“1ã.qài9z 0pH÷c¾ÓScÙ%¬.ˆ_Õ¦¡t×$‰w܇_”[U'zú‰·v̶>Ï~Ý'Ò@«&¸½4ðÐÝBO/í‡H>Õ¦B(­®N0~?g™mœ³×º ¦eâ'.hÒ¹ÆÒеÕ,J)cïq“é991¾Œ|»¤0çSË•š¾¡Ã“¨P-Òj7Q·ÕId'gXÊê/eì"/¢¤OA¥‰¹1æ¨ý,ùf`OÃÍ‘‘½ÜV]’Ð5ÎH" Ž›—Áù¤ûp©|[‰ü½b€¢˜¬XDÞ¤éaº íøk3Ô£×BEx}ÁiàìGwJ ³LÔ£žyÛ0Ãú¦t žíôc îÛ‰×0 YŸ¼lö‡¤egùŸðÛû c¯ùõÕøp·¤iëæÒÎéš<[˜8ym$”e&Ðÿ=õX`·=t†*rÉ﹆.0û7ÖawTΣ!…z½©„Ê+²m‘J­:!•[—ë5n»_ªdÕ¢0âl·7.˜…®ÃOi&Ö•?ÉÚÛüd™÷àcVµ-ÕŒüõ¸)È C• ¡¸oàË üš“|®Œ–ÆZdC.Æ0=íë‘)¦ì¼ÿn~ÎýE/7¯Ú‚.Ÿh¼*)ÚÕÔ&“¶ —e(U–/aóXw¢€©ê—{@Ñ1m«®?WQ^•àj‘^5*ævŒ>òJõàÕ‚ ÛÞ_‰ê@¦¦Ãjÿ0×IÇLª5•úO«à1TÐÏ팸œ¯1+W͹ҼÏåâvGâ¢áˆÐ$ž)úÚ³c4BÕŠB4=µŒŠ£Ç±÷“³É‰ë ̾V f8-3µÝï:ÆÓŽ ÜÇ™%!S¯ðr$’æÆî‡8ÉùŽŸíbà1ƒ æ·è›ÂÆF1õFšâŸWÆ×AéÞ:›tv< a«ùÜr„`į)  @>(‡¯,ý‘“¥Dc$b à„}–µ¢øžmMÞxGºMÄùîêr‡^ß›Ë-aQJp?Øó®µc 漢~U%>¹ä&ýb"¸Â|1Û§vÁ&ÄNl¸f‡±ÑOo·,*Ø“U²ã&3¢=ðŽå+×Ð…BØ!°5L{¿f4²S‡NO¿äkÙDMm»ò=™c\Dn«.ó’€€¾/K쌒8Š+j4ó[¹Pc´âv‰TŽoÚ¥£ý.ïU«†ý73¸“·Ã~¢‰Ž{gÅÄ|²’Zfj¿{ùÜ8õöÐm¶ƒ<ÄÒ`Ñç7šw=¦¡{Ë|¨hJóÔü¸OT8nñ9t‚ ÛOCç:²Ž·*(Ú'ÚlwýQ©—$0ÑÕÎèö ˜¤`µ¶g=g¶»Ë¥£¢¢ˆ\…sÆ[ C‰Í£Ð†šQ éeR/y¾ì$LjW·ŽYýg‡VFc¿þŒÀa*ókÌM®`K$ºéúÛUôß ZõÙ„¿6»”yF4~KLåÑÍ,¡ð÷‡¬¥€ñÀ—W3Fß‹ í>ùQQœ÷]tω|w_½Ÿé­¼fäû­toÝ©!J±'m1 L .~‰_“º­yŸ²~ËA-×À­=Špû2-§ß®åÒ=Ìý%ž ’þ6cˆs+öµ€ÜÑŽ0Û6Iøõ¿:oiuþ˜~8ݨÚË=:9­^~ºp+¹Ø4ÚŸß½NZ­1í¨ñÒÝ ÑFvÀ uêpV0½ˆjÿa馡ˆˆ©ãì.Q1ë°Slæ0hÞ/nq0ø¤_A—¸háLÛôŒ$ä‘`R-p0W”°*vÀT{<–ÄÛ0äRTŽ¢ò¼†ƒpyMv™hbé“­ÜøàQŸÇÌWÑáå#h«¡À‚q·õ³¾Q{^uUõæî¢f© ¬„¤,ŠØ!a(­ã~ˆÑª½zôaù2%û„Ä&o­z<ÉDÞ †ƒê¥†D"B€Rc‘7Él@:þßMCR&q'Y<Þƒ@öBÊ`õî-ŠHÉTsYi“CáÁ2áÔ{U˜óPçû0lΗ9i#d…)ÿ«¼y⇿¦ÎX€Qc æ Ô «D÷Ú 7/wu;Ó¶Ô|!Y ˆqxiËEÏW[‡ë½êÌñf÷ý2Äî<ÀŠKÚ¶øü溫*Å‹"[] ˆ¿ü¯€–šzr8Ö2o<6Ì?LÑzÞ&"©ñ“è„‹‘¯˜3‚Ýq‹{|æ@Ñ¿XRjB‚§¡×œŒ'óÈ¿ÚYñú*RðÉ9+6ؘù*]%]C˜*LìÖ×€Dµîó–/.MT=,¹V×jð@å~{±ºü§’—=¬ uŽD¤éÙ®N{j-Ûïp…Øt‰¨nÎnÜ/‰Ûk+Ž_t®=„LQ“ê{AöÃ^uˆÝ §-/6Õwtú‘Ñ 7Á ø5ù³³;’ZìXçÇÏd¸z1öZ¬:‡ãÆZµŠø“þtDz}ífÄë2)àoá'Ã2ñôï`ª·ÓùÅí"v·ðBÞEiòÇ ãÙ(âhvLc÷Uêm>œÙç˜ûùØ|ôb£Ãð^ApÒŠó$'*öù±cjaæÿû¥%„lw…™3« ,F¤Ôö&5ú}’óö»’RÄ57 Óê»<Ciï»Ýã1½ÊV¢ŸáÍî_ð‡‡§õ\öµˆ&”|eí^·É"ÝÃ0¯²Ì_‚ìOQp¡M2kÃUß;û¾~=J€ƒYzVzï¬ëhmzΫæuø µÜÆ+ƒˆŠ™Ï‰~áv„Pl¯$¦X>£@P3.±{oUi³M½/£. õ;i'Wpx²:ÐÖ­°ŸŠaDe}Dû;áÅ©gB•òµtK:mÜG_#ö@H¥;x¹NOwå|à±ï••7íwÚÜvZ,˳oÏ ,2ÿÑ©ó¾ÎÑ}¶’€€å }kƒWØ45°Wèʼ£LÌF/~ûõÔ“—};åúø=¬pµ®EÇ2V3bf0thrG“b %Ñ„Ÿ¹Xè%°ÒÚà£V=œäuÙ uº"¬Ã…)GöÁÿ€Xfµ\©ÏËXå¿>FÖb·Nå¬XzDœYUø[‘ eÿ1§×$Ãi±j^4ea:… ‚‘´}Ÿ£ýO‚G{ùo,˜Ugt \¦[Ù#<{°2A4ðIÙM‡k/Üô¨¸çP/æ5£=ÚW>À‹¾ä$8søbà»Æ,¥1[ÕBÞ‹E9Ë0€Ï¶Ü2kl¾}ë¶0p£Ö•¥H?¥C^ƶŽßØò˜)Нefbù"8`Å„c9DâõñðÂâÐ S£¿à/‚Ϧ{©ç°LÀì¼:N˜Å¶mó%©B…~ÏM[©—0 'R2½+1äqÖ´`Š5¨¶‹z4-꼄ŒiA ·¹\iÏOBHòL:æÌµXý º:ÂYíF§›¬xøûrò~a»þè/^ Èþ«Ž'Q´”2ÞÚ rœZCˆƒ¬É¾ÂòóÆÐ7\Ô)sÈßÿrØÌËx¿‰I ¤NÏ® N/r(ÆHhëï>Õ1xÆ!Lú!"ÛËÔãÓÊÊØ›‰øyÄŒjè")$ëøò-vß׺t)kî-ì°Jœe|>yðÏtLûƒù3Q¬Úoš£ì㎢ Öè·xkGuä‹«Ådà.ÃäXÉ –W›ì*WÚÏaàšÓ ã²Q¡d€ˆÈ¤Ü÷O;ÑsÕÅÐÁ3s…À@»l.›>µñš±GãÞC4SÔñÏìïùSƒ«ÃñÑ-Eô§ÿ~ê²£M/Ȱ°÷uì0`Þ&aH雯µðr£ùñ>ÒódW|­6\ÛZH+×>ɽ­®½¿GÃå{Ç[å—R?~lº=H°,<ôiA ¤îßN;*!½;O7M#ÇŠ‹Ôá?¦~ïâK/œZ®äXÕ"› rßÞtB9íBpŽ|×Ý{>~ÐûVui8È0„’ o»¾ç÷šqHì0våÏè1P-bÆmjöaLÕUÍ÷Uìä¸> TÎÕèë§'µ-LnÏf“MíÙfÙk,@á^òà¶&H·wŠ#+¿ëp Të1šýR_$‰À’€€ä âJK¤˜ÝÝgžÙÏ,.‹»÷ežpb†pw£è/„+œ7¥Š(0û«áµzé‘~{r´³g œHw—lmóÞÓKDò Òƒ´°°ïK|Ž1¸:AÇüiÔÂòù¨|>ìõĪœ„w¢µKŽœà’R=Þ2Òâ÷ÔïÀ ›µÖép&ÖJ]›Ø:²ydƒPŠ ”|ÌQSçï³é¶¼ÌÔ^2JѡĊ­´eÑEpÄ1àDz訃₠Q¹6—ðïú¶d€UÃ'e$ËÝ}*{<Õo‚ñ+wŒü°ÜblŶZŒpÚp+f³S¨ÅÄâé›Åž¤ȇ#¡¹áïÈ(©^ÿç^vçÀ  îv‹©òUA'Š=í—þI]ôæ]ý7GtNúñJ½\›Ïƒ,lÔYÁóÎöÛM–ý>]Hœvÿ8Œ<ÝiÕšî4œ"S£^÷sõß'?{-GkF&- ’R¼Ö@œ=mCdŒg©›Ú'BQ^õsÕ(=¤¦ ã¦Ü>/ÝÓ!vÉH;ƒŸj,=ªdð'KS:îÄìÄá“Y݃¯z]Œ(¯1ÎüÁÿ–1$Á »Ú,Ö²qÉ~3y^ו"ŒO«Ã`û8æñVnP)}-¾ëã}FM£qË^¹|ˆ*^’™f‰49F“93P·÷i"é/GzøY¿‰}µpáÓ&Ù¬[S0_$Ëðys(`u&ð¿-´ìt•s"Œߎcé-äS&ñ.ÿPqÆ´…g2n©SÀ,IdkÛcŽh¼…ÎçŽwöâe}´¤ã⟬t·hXêV‡a¦·Ç ârŽföU/ÛdÌm…ß5Ðã‹x'Ða’㕉cÝL–ó(H[ö¦£¹É™Öî”ñhìTó§îRa)R ±ê“Œ³e/1ÅÅùkõÍnŠï-Êd(;øFpœ8ÅC$^9õ³ý§²MÌhs¸¨i©‰¾‰G›KQ”!¿7Í(†ü¨&‡xçI {w8(1÷q}˜¶"–ÈMvi0…ôë®]pʈrV÷ñ‘ ÛJÀ €M A]½S’€€¸×˜U%©Ð¬:Í^ž3RÚš…BÜ1µÝ·ž…o‹ï`¶ÁÉÊ~ )I»lÉDfº6¸0 ·ÏþlH˜Fið,{¬ï.u·æÄTOï3t_V_ ÕÅÐ÷ñë=O¼óa&á½Â§ãÉiE­q ýìW½¾›Â†J|ŒˆQÁ—è–ŒíæfÕK¢0)DG¶n…³”)ëÈV¥ZZ‚*h´a÷8ö»”Wõ塆rrU°­”É0Zj¼P’s…¤µë¬œ{£f‡° yÎFPqT)íÓŠ ðC@^<'ƒæ×G) ÑY³ÍôjOV¿¬m¶Ð@G»í !É c÷™ÝpVgt6ž^ñ€ÜMÈÔZòäSô$8/3ñð>úŒ#ÿº¦Ç+1{\ ;@*­2v” ^BÚGSÏԳ蹔{ìÒëàãŸæ½'4k Bvw)\nN×’Môõª¸u厩è`ÏPo‡¥‹ D t:î<kmhÄ„>ŒõÜ™/ó锅а¿¢þȧÚÃl´o·+å¿ò·M«±?iXP´ñÖ•k„Ò îÕ,ªa¶eTÏy>UV„³I@ŒŸ{õL~(²«Á}I5¸îèªH_aª!®§òV”šh—PK·Ö¯‰Ý÷<:wú“Ž}$®ëí“èOU¢[ýº¥<ãTZþéfÍœÂS(‹=ÉXÚ m7#ÄU¾¡ó©¿_!¸I å@ÞˆÅÐß²m1ƒ$x÷žÃM1·.”R”AZ) ¡;ì’ YbÇUÌŽ¨ù-¤†ÀâëÑçí [Žñœ^ùÖ 7YÝ?ö8×Ô”áÓ®š ‰œôzi!Ñ€K ×ܬW=!m;˜#™#ðv–øÅÞìák´êÞX‚ßH¶o¾Ô“R­caÏÉ&:õ«œT¬¯5ÿ¾üiŽôç}„íü£\7fèi.Þ÷o¶ºÝ@ý½rÀ~Eùä]•OÁU0hÑû⦅´¬wÞ'næÄèhŠŸôV²|Oç™:7N},Kh ¤Á §°ßÅS¬nî™æ®^ˆA5 ïÎÂü€¨š@Ü+ø[Þ XOo©­¹¤ÏÂ.“SFC'‚ô&ÒÙržõ€ó¤>í¸¥ž¼°¸á¹A§É)ÙœHT™ö¯j³QÂï´uæl¢i-´b­ÔÅ¥®—¹wkRô:Èr4¸ ™—TˆµMÖ.Y÷ÌÞ÷gÞ©§ÑÁ”/¿ñï³3º¹á§µô»8Ú'!óWóàßœè…ÐŒ0ü„„Hï¥M0#"ò£šä¯cPTÙÑ ¶ÄìÁ)`Cüftâêµ½xS#¦ç”µ#F«è,0àmùzr¼Ó1}cš“Õª’cRKW°|7¬*‘èGIº„eAà«×¹ß|áâ;o”C\K,S‹Ùåâ%Û"™u2äüz` zL1t+<ï-wVrßçÐñ'¹¼ä Z²ràÐû¥•+箉Æn% ¦Z”ùêZSa$D$2G×(ôo.Ï`Ô_|k‹YŸ‘BF(l‹D¨î Gîn’fš¦ݾÏ%j‘gßv®ÑL …ö³Q‚} ¯ž ˆî8ÝÚÑŽ/åÐj24Ûn¨¸oÀx¾§¤Ûò?`ÿ )Ö¾åÖ1aàüòô½ì®˜½²6Ipá¾£–5Ìyy ‡7èöòiÖØÿ›ïÍXÜŒ¿À€Då.D˜ÀeKa¤¦…JIÚJ™|úѽ`8Þ%ÐÓEUa=Å­þÂNnÐ DlVévÞ?&ösµ®A+å犴Ð͉ô‚qPÇc_YÞ)5%`Ȩ;6Ðo¤A_h"‘ I8F^ÍÞunükp•ÜÍû99Þv ½ÙaQÆ€go(G"(*9”ÓRQðÖ#.ý;6Vno‚·â¶¼ü>ðQ®2l±ïé±kþÒ,N;bˆãNm]ÕK0[\•ïýââEr@MÑ!rNsKF9 ë^Ê}<]f°­®F³7ÛH!ò°tí¯M5s'ydƸ|-¥\¤ñˆí~©‡*E¿¤d8Å)UîD•’Ũa!Z’÷›ô÷R7Š­‡ËK]—2Ù£ ;œñ~„óî/ž'ÿñ=+ü¸ˆ°k $&Œ€\´™¦N×i|k¾œÊe9}GtÔmeÚŠU†à9•×’€€´ØVÃŽ,Ïay½+/8B¤E$ci:åL>x,Yò±-B\g`26Ò2’4ÐïJMYbEŒ—à´aCEˆ)ì5Ó‘w@Þ~ß­ÿªñ=ÄŠ•ò“àHŸ ¯ø3²ÜrõÀl~XÕÆµõ Ù=ê) ûˆƒô(Ê`,z·‡SQú;Ä| `v“…€^vB?z§RHG<Ú“|®,\í 71à˜.ñ‰*~›DËŽ‘w€ÇLáñåÖÀg4f¼De(¯pVO êhXHãÏW=ÿ½ €-î­ìKi´4†õ_Bpµ°ÎŽU$Ó^VÙ~}ølñ€¢ÒFsAEc{µ9~ýÕ^õ¨ñž5Þ|‘Z+œ=ÎÚ tH·g»Éhú_âBŒfÞõ ]ýù_“8·÷©¢ö?ñ;è×®-ì0‹EŽXU^,kSÒJeš*®ªâ#jÆnñÇø4ht©}—¶qF³RÚÞ;”´5<À+ÖçšÉºz¿¬>mq­ÖD¿òî6ížvM¼–Љ&žhX”sã’€€º4=ß ‘ËJP°p·/^©0#Ð'ß kx”¾ñqƒQ/0}†bAÈio]; &o7Ÿ";4×: ÇÒïàkØ $gκÝVùk'5éë„p¬õ5¾ô¯M’¦Šm‹5ƒULÔkorÒIY}jö@¶*T=”¼#{±bšÜ^%8Rº†ovß001‡ ~§fö³ù. %jtUÞ•z8I’ÀÜ)¾ŽN¹’Q;÷§rgÅaçÄ„Z EFKà6beRYe['±ÈÊ6å·êzH(ÞÒ(7ö—q³ç![ðp¸ˆ”%9ŽçMä ‚¢•Mµð ÖÜnýŒÅ“î`ˆ.8*Y+OM>®aoƒ¡ýäY@WÓúƒ$ÊÄ´¥LŒÉ5³á=Raw (*³ërÔŸ^RšŽ µƒ•ôµeBïvÙt€ 0iÔ)zÆ’ˆ³ð¢EædÇŒ«K¯ÇÛÊIhæõv¥~4ŽÐÛ4œÅcÐ4Ͻ¿º6~Ä#®Óeƒ(á?äÖ“ +î_N)u* ¦¯ð>Q%Ç7_‡l%N€ƒéç†jÞâRxM0Ý-O°»¨zÝ&)nÍ´¦\_šjãØ¯üëØK7ÇFtrÉk=X­¥tDÞQ»ÚÏ0ð¿_¹ßûQÐl(’ò[‚ &n»,ˆþÇ>RØ=ÐN2[ij¦ña7]£)DE¤Kÿ猾Åþ^<ÛÖ‡¤Xp~¼Î‰©¡;-ª(2 >ÍÄ¡ä…ñÊç@®×ÏÆX'ŽÙóm>m½h V¦yÕ5MttµÜ¹¥ó/uïjRÅv2Êy8ãg”+R`½¯’±&qG£8ÛG’Áá‘èKˆI«Ó®…oQq™(Aíns,Š|œÞý ºnà§W|Ȧp«C_S¯…kéâ™ý7TFMƒiŸñúÝz¾ºç¬U às‚jm L³;¾Ó>$hšÚf˜úÐÛcG„Éxöàã°{ÞÈóeánÜÏ1H¡ãQN‡D#ÅÇ’€€Ò6ñÇr™%4£eÕéZ!rĈ¤&J¨šñXv‡°a÷1²¨Öm€Y¸5Y\éÒžÓ󌳔ʱöbÀ¨Ê(?jÔ®©mÑîØ»`¾W]°`Ñf¨¾×ë@Á˜–²Ó³Éýã2AÔ±²—níšwƒ~ƒD-ÇN}n'“5Õ,¥ïlªWDÜáêt²@GϺ±®´ðì«]"éŠF¤b<¦àu\ž¦<† eÀMY³û»b¹êÆ·1W²y]iQ‡ˆ$0nã;¦‰ÜÆO²Ù©Ð9nd¸ÁHóTÑûm|‹ I× £þ€îm”šž6ù¬}9ÁÑç%ŠþuU[´ ¾?YP¨ªäÙ[³à§53ëÞÅܽ*î[„íòó‘>D|ô?yžÑ§ËÍø¥„y`Æ´ªôBâ[9‹_G9à¿…Nû'^ÁÎ2gª)uM"eÀ_ì×V‰™V>ºŽ&o9L²©œ»œmÓÖF¬ÿ+`¦z3ƒ2Õk °øŸ*‡³ w¯¨åt©M`ù¿éÃTYå[ £xásÙÇz4’Uóšâª¢zš÷Ià0ËNJ€á¯Ä®¬Íð“ÒZ%!cdp›Ø5¬¾_/îaæƒ×é·–)ôe(ƒÒm›%ç8•XÖÔ±”Îe'ƒ9ú½¤ ¯æ24O 3žýå¡òͬQÑ¢­(‹k#Dï…6öut„‹z ³9/¿Ú×tIX¡Šnb …ÿê¿~ÛÞ0ö_åvÂEóµµ^‹eÃëm] þî.ɆÊÕEžñÑŽÇÑ4sÚ¦Eø³¯yËë{%Ö;¾ä›q1ï·EÕ¼m'&¤qpãú:ò&Rm©Ø`tÜMù^kÉ­Q˜`˜çN§2:zñ- g¾ÑÆJÏ ™þ›RùŸßirtmžË>"z57‹M·ówÊ¥§Q:H`ôEäMÆdÍA”¸…l˜óÇNês ‹E×…ÔmDÌâ]÷®ôÃ%ü”¡7Ô¾ñýŸÇQš7f«ý¤e„sdpv'˜ûÛ_S)£ív_©û×A#¸1-ßYéÁ¾…ÑÏ|¥bˆ á5X8éE­t>¢Íï]ÄçDµ°€³°„šãuØL“oˆ1l²wi÷9’€€¥’Ÿ¡v[¨“<ÎYeIÐügÃÙdîkÃæ6܈h‘˜ È>)$¼²NgVb ™5©EÝx .Áç†&À4) Û½Jì7.ŸíµþTé-‰Ù£õ3ƒû'2FúÝÌG©ü™TEœ xüM>m÷yöò(óÊ<¤9׋kzŒ˜<Ïó}¯ vs ³yâhìwŒ`ªbÇå¼øå¼HÍAV®¨{Z7pÛÝÚDݺbPj¤P®G•*!RsïÊ@ ²åi›3Û•+¦~Wißµ}73f,ÕàZ+IköQ§ݼ¶Ç„Pß\¬›QÆ}«|k|â#£©(Z6çhŒÕËM¡âA>÷-«¢|¤o½]qfIŠwÁÞãÒ È/ ~“èØióÖúòôоjøkŠ¡Œ Áýéú¶Ãá\páÉÓ~Eêb䪌kV˜Ê'…eZEr€©¾ört3‡‡Q”—“0Â+Æû`‚@¼,kÚåË¿¬H×?îÿ‚¶r-´h@ßm¶·3µÒW]¢²¡·á{Ú'žƒÒƒJ0r$WÊø¬.aOÜľµ§7—éQs„¹”t fö”^Rqã;'RLǃÕú±«ç3•YÌŸz]+˜.TlD6Ï®t˜²îòð ÍYn£åKr¦Ë8Þ#×û{o”SÑiÕ;žxfÈ›xý‰YNcÙŠœn"oÛ¼ÓEè‡R9–“MÉ9Ùºæ’xÕf±èn¹ÂÓ&šuùäïcA$ 4zûßù/. fÞ'M"HG¡H8ÿà‹šÓØ–,Q £†BS ÛUJ‘ÍàüË´[ò lÞ" Y'h -Æâ©ÆêÈÞK#îlÖ±»p‡ké®X¹p/ÊGfÜ^EÖ Vb;ÐùÝ[-ìL_ìp¯³FI‘ÐãvÄ#4aÛý$뤨ªFÑÔ6צ‹ ’ûæèÊcxä6.‹GެÏmªoÌ·ì׆ùÿÙtãÓÓ;›ÇáÂ}ª>«[ì(û1S¼§,0MÀ,캆&ÅAP8-¨=Ao…ê-#ŽÑÿ§ÓwŠ»äQÇÂuñôèÆhIæñ3xEÙ+Š”ç7¶Âš¶d¨Ž2 6±¢ßÒŽnÛøw¯÷›wS2$MT{í®‚'Z`+¾i(º=Ƈ…ÊÏ1.‰aøÆ<FÇï·’€€ú6/§0£Ñ>ç0=«{ðÆ¥BXt)¾aÓÎ×;kû4À÷Ôä¿#û'QöÌÙI…J0vè“2VCI>–~yVqøM7xoø’cîö¼èZFUxê]šàmÍÌ3¼û€VÎq²ÈÎm3Ûó›6ÿƒÊvd|×¾ö²~E…6ÿf{Ï&EYN„¯É ªS]¬hùy!Œ©xNbx;á–&‡3œlp©JU¯ 2%cÆyÜwI#í‚5‡êÊÃÚ‹ÂËfÃ$½ƒgtÄ hÞ¥%w*«:¼Òz`+?zíœðìpÛ옆ïn9Õ«ÃT¥#ÞŠCud£\}žúpàH]ùÑÌ®oŽÊì}»âð+RSù !½/d­‹“dœF§²TAÂßi r¤WȆ”nxHå#º\WU‡gŸQ†Ä`GNc*>ÖÖ¹ESåš8¦Rj9…ØîDÜx(bïÈw›à£ö®ðv#EŒºg‡Â‘BÆÀÌ¿|£OÚzv3ªe®Å`wpdÐ8˜Øko¬7ØÝó’缬lÌAàfF†™B™Û–ò6Þ£ÎÌÛÚ*pÖ®£?~´ši1!ü&¦âiò?F˜zI\û•]ï‹ o“‚àSÉuˆJFÊ(Hv|uðß›èK çiþ¿¿>îQÿ”s…qñ$@£¬å{£¶%»!^(†èëX/~7ÿä÷7Ý a_ŸTBÖnVi®ÃζqRfÞ@'±¦{dƒ¿Î/+34iâ=)’¥~$6™eSS@¡wŽÀ¿Àü±§(·=YÌᢺ۩t·O¢ÞöWŒ9„±pG°ñÝ9úŸzE ¼ cq‹‘ƒ˜BØ»­¹¼#2n«@³ãÇÜî¾Áòd@ƒy‘z¤Gh°O5O^\ܼˆ† %-Ô'‡Øô–k)¡¹+YüÔñª]@€bôvúÀÝñÕäôRƒù·Ó!±—coà0H+=.`ô‘DmÅ=ìws™kà=w»UŸÑUî`2EHSHA…¸òÊØÊùÄ÷üSžN „ú®™!IÜ2{^¦öÉÁY˜_v±"BUÿZ–¹¼f…©{uù’èï þ¼p4‡^ëG>ìˆ_Ã*¨žT£Â˲mèÍŠ›˜úrAœŠÉçû‹~ö›¨¢2¡ïâÔ°Á’€€Ñ(µåŸ5‰$V :’b„·c4S&oí±  ¢éû xY‚¤aÛÏï°~‰W¸{—«Z£’Ê ¯dr—ôªÌŒ_}qó€€ôêÅŒÑzµj‘wZ°ÉëÏþEth àæ¶ÆÕfg~ÿAÎ÷d€óÿŸÝ,‘—zàjÀ#œ j´(9²§S}¦ΞQÖõ‰,¯0롘“…»mÒWÙAs>ºdãOG+ŠE¦©>€¡’ƒo2ƒDy¼Úgç$„*ŒAãÌXȬO1»¡C{ŠìÑzì.Ž 0ÊáhìFMÑä>†¥gL÷ºâ ††ûV!n“!o³—ÿÅóËh,.Ä 5\Î=ISõ<û`QHಅqghœ5?½Ès¸ÒnãMŸèx_¤_ß)›ËrYnæÆ‹>&èòeLì_šº«š•)jUêå}I¼ÅoØâÊ}çÙ%ü½v`§LS®TKI*õìæ¦gI¨Mæ÷Î{Õç•uÔÞÉíRR|±ž¥û­­»¤VhÓ85C¹‚¹ã+àžŸ|0|ù¿ÈÊß`VÜÒS»éZ]æWvæD4Œ¯qÉARCxµå+ÂÿÛé SW¤ÓºžmŒË\ aqÚ‡kÇcѬò¦ì5ß“c=£˜`úIãj-"¸æû1ÖmV³a¹¢¹ d%gâÖß-ÞEÅÖ3“ãa•œkÝÍ]Á /‘Jz ?”{‘®3í㓯åu@¤Ö_‚9gzº§o9ÕÌ«Dý BÀþçñGý¿ (Uî=lCûe¼«ý èXª¦gà‡½Ë™Z¸×ìÅ6öª½\¼“ )—V ßp¾j|™§wåEàÓÐÅ4á¥Ä_pl«ô…Ï·_Án™ß8GN8ËW»í~‰…õ©Àæ¹¥£˜P­„ÑM*9z¢äÃdK—«RPƒ7i_¯õ?ÅÊÑ_Ì/OËÚ\ò¨6›ß¢¥-Sj¾¦bÅ íDäÑè³rǧp„P–9ºˆÖ7¼éPÚ];7{dXô+¢Áƒ V Øcª,Øéžyª–y"¤:œÛå ¹(tçô÷[—’€€¤í–b¡.{R}ð˜'ä䇑£(f_RøÈŒûL4)0Uhq¸¼?rNõfÚÇ…ï@kgå«hȪÝéRèhI@ê–,ôÍÀ~ÓÝ>âG~öâ¿ÇL¸¢’÷•ƒyÔ—s=Z¯9›ƒ¸y}%rƒAe·$ø;ñ=Ù îXSùÁÊ:O2[ì§Í‰q†Õ·L]ÛÓÄ(ràwì~XV>M!âпÖyŒ¬iç\â-Öº÷»Ñ |Ú¦×Khª%2 xys×êÂòU?æzÐ mŸ~P•6n ç”/Kï?üº¬y+~U=} @½¨Ï÷0CƒÆtL,ÿhÒä*< J)ÈFFx¬[ ?Óê[Oؘ wSÑŽ›#iä~b²Ç)’›’˜!Âô v¼4.¸…®j šDÆ­VèIJZO˽\»­Æ¾ªjX/:Ä7,}b˜RÝ4ÀùïÙ²}ü^&÷c w*µú{ñ×ÏÿÆ?¶²†W€„é^µ‚ÓuK1Œ¶ ïYМ*°²L¢(ÊT®¬ «©ÕT¸I&KëÚe0Ÿ´õîÚæO+ëäææúM³Ù&’e:­ø`@²žý¼>ÉOïåULñøûú¯l0‹›Oc™ƒNöÕ”‡¬VÝ´ñl˜Ð:<°)ê­öê¶Å[Z…ìRl 65²=kÊd€ºÆï1Š}#8 öÒÁœçZ„‡Ï h@l»@w«Tâ”r¯¯¥§`yýd¼¢´sÉâÂñ§·x‚XG¥z1 ‚W ¼D~{ùMl0Á\ÿø«E&ø Dþ¸¦[Öœ>3- ˆYƒñ~­«\P³;q™JlðÎ*»Ôï凉uYÖt¢'wó‚CýT’üiàž‰òAu L¤»†Lß±+¬4&3/ÎÌCËTÒ šö˜Y§ôëA)× Ö÷cßê/¼ˆñn=FT |w×çÇ/ÇPlLòÕþ@ˆÇϡԨy‹Ûëû¶¹¾h 컄Z*{g)ª^ao•˜&z’€€ÁÑ_´îz“¼;½öÃ#@$D5»á´bêa;[^´\ÁØ?ÎxNóÜ2ÿÐ¥ ï¡[-€F£~oQIK] Œý´e/@¶ g@PöêRå‡7î0PJ:tZ;”n>T6¥wqš€5¬UÌVÒ7\œœ;>½öÛ>¢Ó<]Lª.JM±ßc*,HË¡R»Èmu±'ø^f~”sÍÝfMY]èr23Šô¹Å¥%ÂJæÊ2ꎑGSl1Þ)¡©D`©À°uP/ÿÙ ØIØø¹ªªŒ‡Œ|+À(C7:ŒìcŠtb¾c¿iB&l ¾Å^i)7ó¶f¡V–‘ŸôÖ;Úâ¨Å¼–®þr㱩?¨/ðj@F¤žX™Yº©ÂÿçüŸk4NÕWlÓ—å@?JRK‹~”Ï"ž†5ß¡* /9c|ýDó ì5‘Š÷)ž†âggÕüõ¥ì6ªê ‘AGVSAÚ(lNßöˆP¼vS4RAÚÿé:áµZ»O™¥ÿu3ñ7Ðuà]¡œãRˆª†g*ÛÖò*ˆœµ¤0%î¬\1¯âh‡@•*ïQÆ ­œìƒ[Zu 6áâÑûü )ò΃øñ”4Ô¥¥9¿:(o&8É·éÆ>Ïø ›h P © ü…Z·L~l#KñÜÉØÛ+-L•z’IêI“Y¹º¡Apº&yÂp?oÈß$fí²h™ù§Ð¡/6Ùמ4dwáÍ›8·l5¼î_:<ø³š[ÝÖaLŒÆØæšn NŒ Äís9aa9raÖšù`ž/¢‚‡«ÎE=5À$RÔìè äu²éÜm»8€t…ûDìƒÚßÓÇ©ââ  »Z˜á)ÔÝM¦áòÚ:®‡Šø''W= &G“Àæ‰Ê3ˆ_ð¥ßß\™Ÿ[>Èd*ÞÊ«ææBßKWŠÎÔ&ù’zö·weÈ…­<Ø¥ø‰ë'eÀPpÜR´ëyõöŠKˆÄéTt‘f óä©4‡8U|æ Ù–-š«œ#¨lîÇúÕ¼5X"ÐJjyAÌAg õâžíW‡&O¥„Þ@˹¸»·Ð*÷hŽòÚA4hš^§cØ™£kÿªç‹d{ÎðTk–6?ˆp_ÃoÆq”›#zO}ÂAª þňu*}Y‚ïdèÎ3*þ’€€Ê˜yx",úÝ͵Sóf“x,ú¨à.„œžûÅ Ë­2­?â2@ NQ7OÂ: ¦2+Å’ü»]”6ŽyûÖ®d2>)þ{Ve¡Ž¾Å©]±•SK#vfhöj>w1Ôqõ¢ø²¥"L2EÇ[!\\íEÄþ¹®wOˆ÷¯™Å¬)#s=Ç3ý?}‰»tй´Ús팻/µt³»2¹¼2¹k=ž-¢ôú$7™Î.½Å‡%ÿ®Kî‘LÑ» ,y­ˆÔÕ¯7LZ[»‡Èªìà1ÓàîOˆÆ$þ멽ã]œö¡^,%™‡T;‰¾Íµ_É‘“}Ï!µ^OXØó›3&;‘G»†îuöêÄ4¥Áål‚mÖ®¯Ãº¾ ž€2¡¹\ó qà“rç…V í®aÓ)Wòû]ƒû?Uý÷1Ø#aaÑ#’Ë-í†ëª•1 º5¸®4zµ HL¤{ÒKŒ¼C,YÞf]t”Ä­Iª Ä}¯Ý¼ÔžNv+ÇVÁ(€ŸÁ¬”¿;þÄ6Ö ’ÚêÎGs|G½‹šÿ9TyˈŸŠoí–6¡(Ì<[í§íºrý˜Xà'|IÀÎpQÜC2f;‡ÏÕ Ú#›”õIŸeÅÌq·w²xW0%ŠÂf¿&îĘÏ4 ºØ^EtV±3&Ì7ºû¹ë«çÍ™Bí&bÈ®XECtã¡Ï„†Ù\±§3½w~ƒŠ[ù••»Á±…Ĉ;'¡kn¢FÞùð}Ëy“Ùá4Ù<ŽàÈô‹†êÛþ†ü*¹‰Úáç3cAë묀LSyÓ‹GÈ{aÏÄù))e"4*ÍÙ”-¾bcíëܰæ‚N¾÷Õ½6`³62­ äZ˜êŸÄŽÿƒ¢Ì Yç˜p¥Î¨!ü1`_W™m8pÒÓh˜ÅØ”_ˆ—Ã[ô"°|<¦|­x“ ì™5»Ý|‹õ£ïIýx¿Û¡H¤PõyGœl¯L¸MÓÝR˜dm†ky¼£jŸü[þ Ùà  (k,µOÍAFðTºí„Ky{n—/ç1a}³"d—H¹ —£¸ÊäOÆ¿UŸá +–èA¾"Á`O嬒ߠ͎:Ÿ?ۋ미oïñ$l-5šPwdÍÊåuý6žø0µs FqÙÆ0¤3hØáp|z…1ÈØt’€€«}Þƒe¥Pœ ïvh&KŽÃ¦l<¿¸{ÁlÀ~h~´Ÿ`ýbú ·1ýßDV °"’Ey"h8 “¹ñÂzþWtup‡Òf'æSšPô›íêJD‡ó YÀºg‘?‹Åö­9ÁÆ{V­[HÎvãDÖ,D"ÎInÒÙÄK «âÍÔÊø’“ úБNÝŠbD¡¦ç$‡0íÆî'QˆjÉÚà79_î_N–4p:©öÂÆvPgWŠwÙX¾]@7«½7›t¹«PtÆtá•(/ø…Ì_<=_´{ Î'ö ÝVÍ9ÂŒ^f>ÐèØ}‡.öåÍ+æT \û¬8m¯éçݶ†×£›ù’~ˆòf÷-%N$^”7ÉnÃä\†®JN}ôY>ŸìÉ`ñÌÑ/YÕdèoÝR?PîâØƒÖßè­§}ÍD¶Ý1ÙœdžŸf¸[x‘i—¤-Cò(5¶!©¡| † U“Ù¥Lô°–!3´…¦PÍì«y³×åJîkWF—‚{º‹DcF׆á´ÿ‘²uhIjˆ0½…Þûh¹–ᆘ×i+Wæ6âzS7C? «¯Ø¯ÛÍoé{$ªt ‹^ŒÁU݃_)…Õ™Ž"æuŸ|È”<¼Á9ºk¦Ck§5Õ­=…••Ýc5îŽ$ÌœóHÈ´°GþXKþ8ÝüF“!ª²´—¨Õ]øa¤é°ß½çÙ!^,ƒûhRù0oAd’ä…î…‘ÓàÖ°ÝßAœ¸ÂYà˜Õ´nN¬ž…wTù HéQ]ÅYl:«#Ȉ{&:C×ÚRž]ŸÍd´b˜#ÆM¡×dÄV5@Œ×S‚ž’8¾õívyÊžm- Lâ0ª$éôn}¿´7ß-îf«îr×.xû°% 3½¹‡¢y $=„xmtJƯ âRÉÖ»OW#ŸLWÓ3¬°ok%^ĸåΰª´ aŽê4[Çž/ÌíxµôϵÕo&êÂöWAWpštM3È<ƒbÚålÕ%ÿ‰{}·M&JG;”1R¡gÞÌù&¶îIÞˆ1<3Ñh¶L+Û;y\²ÀõeCHtð8ÈPŸ’‡/ŒZ×}; WýOøÂ~åÿ®ºÛÁ)ßXe•?RÿE$ÒûöÈõ ,Ï“’€€çZ_­«\ ·ÞGúl5“W *¶ ÿ‡_ÂÜ ú±iZÉg€ ¬¦6IlÂÈ ©9¶PË11 ÷köK\Ùû˜d‚N¾°iÓçáõáO‹-´É&“Àº’1{Éi'ðš“Æò§òaÑhB/yO•¸·*Ú4«Òc¬&$(61ó¡"IÞmãlŠ·Û•á`nnP¥©0}_UimM°ÛäjA|&•6³™½3œ”ÌiÉäÎLO>$=ÛéÅD>+/§T5ï&0SÓ®-3 žÁ”æ7Íè^¢Ë)îÍ“Tn¨*õ ÊTû©¹¹Iãc? g>¼Ý×òdÿ§<ø*6™Vá”gÅúÄÜÃW¾ÖÕÀ·IQxêz1¥'{ôå­íw•õ£Òìx=©Ük¹2µEÀÜbZº>tc—´Ý‹°[Dä< ø™ÖHÀèTo°¥wžå=¹Û=N$‰/˜ _ÐJwêX édª•'5èåtwüCÞ¾Ÿ­N7Ñ‚€˜I¾y›ó[à×!RT­Vyú4ôïÂÈÆÏ4åÜséZò¼)qÿtÉk™@rLÁÅT߯2þÔRÝÙ }RŸq_™äùÎÖÉœÌh0ͰR•£¿V"Èä–ÍôÙ}¾r‘„>ì÷“Í u1ȰŸ à )Re¼žf0eHéí*êS+&$§Þ¸fJ—¨º}ë©hú¥#KVÆ!„k:s™ARÄ”.™3¸ÿѯßÛ&}ÉyóbÖy•m¾­^Í=t»Dî§ÚGt‹¿@GQ¸¨û± ;;¾Í¥+àe¹ýKÁYÖ¨GfM’€€Ä•p“Û\l-9jÕ¾ÔE•”—˜”@¯›œØÝnL][z¹¤¢”¨ùz*¸Š6 ó +g5]œ‡:¢Ÿš r½çœc©ïX`Œø*dA—Ê%ežŒq[¡ÄÝwb\ò¨s²°Ö˜‹ ¿b«%GvÝŒë„ÕÆÆ¢ö|ƨt$TõÛÓŸb»‘äCTžæã£A:°‹uÅãYl¡rÁÆž1­£÷|ô™:³Ž÷ÅwÙK è0pGL¾Ìözó¢Íñ£¬ùUªx~˜üËàîé~}Päûû‹bzý-ßE›ƒ ëî…|S¦T€Þ{ÕV{gÔÞ L¼Z[ÙKã þþ‡C”|2:ô¤|¹à„À` ™È0„S{@9H Šâ…ŽÃS§j9ÜþLÒ‰bèyGýò°¿7Ò4b~¡âùNê·l›w^á…»©¤“j>]koÎ^@ƒ]êþ•; ‡m½BÅ£¨i¤ÖÑ ëUgh†nE¾8{d½}@ƒS†P¢x "?úSª¬W¨ÈÃ…ÜË¢àeKE;^ÎÚùp‚„ÙFK#«Í0A¹К©Hà›^¤°áî=†@LViãù ™ '¥’£-,Ú7¬Š»¼)+]`§&RYíy’ÿÎC8ã…¦X$(Ž6âÇÃEhÏ^v êônWíÛ¢(lÈC6F’©^Ì ²³÷ðjiÑÀê Ùå0NµpXúy;„SJáÏ7¬‚•Bw¶ŒH¿ÄѲŸÅáÕ„ì­“oã‚’ê&ÜÂ.Ù^ï*£›%É‹­«q&#sÓëB£‘Ƥ“=îm›kØý T˜‹Í…Ò°tÔ‚Í*TÇ|ȇTöGF¦~GŠ&·3î°T¦7ŤýoF÷,?øÞGžŠÎÛotuå{¿à©Ù  ÊÖUN}þìYvÃaÚ>mYFŸ§ Nkx5€.+ï#˜Ò]…vè˜ô¨åY.’dÆ©›üCã6äß‹lx¼ „¢$fÜu½Ý¥jï‘o=ÇÓ€~š(í°YïÃýà°_ÉÖÑ ¹/Ú‰*SKßÔˆ;"œÄ3óÜ2Ïë§ËÀoŸä«[¦­„ "ý²OêÑ9ÕÌÅÍI¹–6²ÃÒqœdœOó™ ê’€€š¨…Z6õ­¦V ú>c=e½uFŽZDÞ™·õ‰æQ;ȧ4qTÿÊWo$’ïUÖ(g9ÖDŽW…ô¢eçœ@ÖäyÜŒŽTÀµµÛ÷-» öè¤Í‚ø%øäì`´õ"YIx)•'ŒR÷çäñÿd).œBƒ*Ï·á¬'‚Óç&Òè‰Ö¨24!Õdg“Ì”Éó–pÆÍ0’ÁÞ=¨©ÆíœÕûáÛr)@ Ħ´zû°0É.#-À˜DXSHtPÝbÜ*-ðvÙE–… Â(ñèýµ­RJ–W*,ôLß×–Ë¢÷BÑ­'ånb¢;8Þ/<ÿMû´åŤ»LUÔ:5”÷=ÓjWË›é~¥6žêRíj_Öfò=P™QaÆßzÔ¯CZ¤‰eíi’WŠådä>ÔÌ娉  „\ycHô%Þÿ!—›1Kâ‹P …“¸çMüýWo ©¿ô¹Ó‘—6vd&ÝÈŒé®Átx?¯“ÀͬÈ]o]SR‚‚!¾à‚!~t¶'èOƒþ;¿ÇÁ˺›òòiPÝÖ¿nÝϵáZÛ³òåÏøEhîÄÃȼSÖ¥òª"/àjñˆ@Ò„lðç¼y^ šwmã­Dƒ<ø‚€˜fØ:|“Z¶Ð{Íú™{ÉÍ\M rà{ŠßLze é55:3 ƒ‚K¥a¨¾â¨ù«´^Ì–5†`¼r ^£t.qÀœ×uoÄO£Mó]O—É^ᓆä†éÚäè‰j³§ýbß*î­ÀD';mývÏ6‹Ç(*ÅÏ•ñl<=ê0E‘ö®Z¬È=¥ê„) ø]Ú8p9}N1€Þ‰>­˜õÀŠÁßOšuw)¦@»" ŠŽÂaÌ;Y9¶Ï+% šŸÙ¨Ìh[Oæ™ã*Ñ¡äÂrÿe²Â9>ûæ• À?¢£G­cäní‹ä@N üuÛ°+’*©šÁÅ‚"f´ý-þ¨Ù΂"€9BŒÁóç/ÚרBkˆ;íOÿIYæÂá­¬V,?4Ój ¢‰{PŠ.ÆÜo5´_dBEËÑÊo#¤'jW ãôNã¨öJš’ÊÍ…mÜ“Wjo5ö/œþ”ªÍK|âËC 3¦Ës²JWŠ£Ý~señ,YÆ}”Hž¬~ õ-?+¾%mTìOÞ (Qð׿sŽVp¨$Ý’Z߾ʃÍ$oŸëòÖ.Æ Öœ‚š£U[q8à–CYGÅýÏÙÓgnš?Â¥@¶íå;Üfñ°Z°»{{n39éc»ÚC\ÌÐta¸#m÷a¡ZóHÿ›ŽÛ Vb€G`¬v-&ft‰ˆùGrOœv}‘!›2+5bÕï69¨}ˈŽè |ˆÇ?Î~³ÿi}MfPþêN‡‰ j&àÑ\ÏÅ5|z”$Kˆ2êôïæ!x²ý¨–ðâøÌÝß._GÐYoUÜ^—Ã]ðе"2C_àéb/–lѰ]k{Ûb+ÄÔ¬vÞ3”þ‹Ö÷cÔ²û´’€€®k;³¦Ò=6ôšhÌ‘–¦tö÷  ­“'äç¦<+¨ ÐþÐ=(„FÕX½÷hY• QòаS+¥ÉéäJÒ:Ħnr6Èu²âW3p^i*ö6Œø«"QRg ©&îÉ{B>úrZ÷¦@ ªÅ®Â+=й˜“a¥ ýã ÛŒ|I‰{•}ç†áÌ+¨ ½ßî#w½ðálä.IŒ¸­ÒÊ*©ˆÇÎÓ¦É ykÖ·ö·>Å¢â/ØV 4ÉA$×üvZNæ|Øi¤–¥Hy·a„ª ”’C4帶·\¸èÂN Ñ[ˆ¬de‚"®”÷,T)âÆ¾ûë¹ÍØRHµüº)MËéKƒ‘ÿ‚P«lð¿ýH‰ž»Øís» ¾§Æ±@Á,u»ÅA…ãèu⤆»í+š‡Žñ=À¨˜éJÉ´I£#¾JjòW $2]Ìæ&OŒêÊú ª$&W]“=zsÀ‰_Wώؤ´ƒXD³éÃ$ê0'“íOÜ"Õn\g°ó; p·!}“,pÝ%IïK‰=ŒàSO›Õ)’€€¾6^wftçÜÌ„ðFÚ0œì]½o1£º  7& qvwýË_´ˆBm«@P2âÉcõ9Ö… 7Ä V{°¡×(Ò¶’×`F*äFááf…=¹‹úË)âS:Q‡žX]¢ r’ÄÀ±…œ<€)0uü^üÞUòh—”й—÷ý¿ô-îŠoš!¶!šë#ëOìY5“†Z ­ó0¸ô{ÓB¾™I ‹zö.cÑÕ< Þ…£cU‡‘›= øgÙ;‰4ÔÃEîÁHöYAgS€ŸꦘÔ+%%Ñ3ba˜ËÙäý/4ÿZlEŠAeÿ ÜêßxÅõw=.¥Òµóùh² Ìn ¬<=‡JÅ\$ÕS¬·WV “r3ä¼*ÿä^G1]L¼>Z”PAFM@Ø‚ŸEîð8×Þ%GÇfr2+á—äì\`ÅtÌ0”;Ÿ‹+'Ž›hŸÕÀX¤kú7·$¹ØzFð幥ܸ³àÿìÉ?©z<ÅúF¸»»½:‚)×VHgè&ÆrÎÔ˜_Dq-OxðÚŠ–.*RS>îOó>Q™ùå¸|ì¡Pz›²šÄ›† \¹!8}eºTi6x€EɧšFh°ÆÈ·Ï–X ˆÏr'ÿxþÆùoëe9å–3ŸÉ á.¼»òyÍãnW³/¯ ë$+‡v«hÖCºÞñ-¸7ðé ýô‰ˆV›¹@YšÙ« ²Ý䥩LÉ@§,.ÇQ¸ Ë2šw[‡*@ë_ŠrÀ°"£Ý|ç8ÑnÇ|Ë䪄‹Þè>4‹õ‡åàâ9Ôƒ*þÔŸ…LG»³ÈxA•÷Íëïeu•4¾põ«¯pñÛEwžÒä4„ ŒøiƒØ«DK{Á”àå ˜œj?å5 sõGv½Ðk’Ú <5¿¨B1œ¬“„k»Céy<ÿícóŒü¶†³')‹Êêž… `Ñ_SG%Ìï×9*÷iCa]:]ù°™LºDH?œwEW±à€Ø°(ïÊpºð]˜6DÎkl« C”XïG¥êÍ kAŸÆ•®dÒG¼ˆs ·ÊÒPËh„±Rnþ³{ÐCªØµÒ>”…É0JµÎI46Å &m¾`–Z2a)q*×Ï?M»c’€€§Jç:\ØÏ%d³VDþJô5R¿ÀáN ô¤~”¶|‘£¬Ùtìí22ÑãY+OèèçèeÏ ®¢el_¾ïpØLäÖ Ýo«©n.÷˜=¡ò)ÚjàÌJë;îòZ4ÿÒMØÙùï @7H-µ»9Ųt Wi!Ä©n ñá¥ÑRÄ…fó)?¶¡­ò;QÐvþ°ø$WL¨x‚Êm\o¦N¼-st‰Lnÿ#µíã±ä†YZ8ªMʃ«œ=àƒF[2Îï%ÄIfÓùá ˜SM3w½YûÉ€1˜zƒÎx㸠§x­x]Þð2/¹a’ç$kc,êF ®X¼û)-ƒt¤mdúS*1Êï¨Uø7[å8^>E–X/ƒ7ÐÊÏe$‰µÙ"_D,¥¤ÆK_φ¿«#€ `ëͬ{5sWÁY¹ªa§ ’ ›©ž@Ž ëTRÿD¬œ&YU¥Ìój‹8Ϥ­>/GJþ1Ú,l¹zÛÚ&¶Ï¤uöÌhøG žAe$ªªÔ”†æ…øB&ì‚~¢­ï­‹SºiÉ AçRÅh HNÍòJi:]ŒD½\?SL_nŒ;'ÖE–²×oÅ&ä•*‘ÔïÔnöºXùÒÈñáæ†}´Î,EèâÛ#áÕë¡Ï‹™P|jiA=FMw]Tƒ"è7~¦-M2Cubºó@ltOía‘¬t`9ïrÎ Âú|H† £ùèêñÈgiu¸ÂN’ct¾q=QŠ(b~ýõYtÔ7‚Ãâ¼ð¯5îY²ãÅŸBóëÔ«y´Wþˆr m©£È3¸¤æÆš»UÔÐjžÞ­±}+-BrPùý°óƒ»î‡j÷5¹±pOø¤rÀ*.˜ôí~-*ÅüâËâæƒ0´í«¹â‘Æ^.Þè½ÀGª¢ßD‰BÄœÂHI–Ò79]jìIt2_ažºü®*HÖ@ Ø Õý—b\Öo™,A‘Ùaûhžs ›W£eå#צ®ô6‰Fÿ*eh Å|îjÑ A‚¨õsŒn‰SχkùGø=EË‹Þß·G¥sy5ê¹Î¹ Ò’pîmIºÝC©G38`HtÌ4mõk‘—yXµ*è¤IgV6·>–ó`ì²™ *Š¢ØQ’€€¹Ì#ߟâH ‹Øzöˆ— ¾Ågì‰p}ê×ïDA !x(JË '‹µ+`¢{¢12µÝ×K³}q°žÝ-%°‡kH$¤¼È%¦ˆW~ÆšÌ&´ õ ƒq/ø¼~ò¸x Ír‚É{ˆivY¦C«‰lôP£ˆ ü{¸ÍUB}Oä——3ì]oXýågô}E¿™×@K5;8߬X"á¼£™œ5Ðß÷™3©[8@-X¯ââŠ.«;Á¢…ÃÀr3Ù†ÿ˜Â¥¹¦tKÀßJAL1•cùê6yÏn¸™ŠÅcÅ%à’ À¬7>âÖS‹$Yp݉y±6¥ÀܹMJX&‹=Ë CÀŸçⳬiuù’eà ˆÔÌ©ö81ªN íÚž•v²ˆÒŸBÂÀMOüÔ‘¾C¶!8Îê¥ÖèŪWàãÏ5âjhg¨Ä³M“ÄÉOwêðq2°,)pÇýåºÓ|Ï:ʼvÏ·xB Ѥÿž\<æpf¬öë:‰ãÆ“ÝÏàëÂÙm%ÙÞ½)ž¨Äyá ¶ÿƒ6ïy*¢Q‘$Ò’‹òš¯G¯¸6ÍnZÎÌ%89œÇù¼ä{~m<ä´³Í%(‰3‡* _=…Æ>ÛÙèä¸úñª&׉´Üþ¡hÈ ÿÎäãAƒtÑõ%Ý—ýÈè]ç¼p… Û@üñ„;XthJϵÐCe5¤¹Öæ|"3¼ŸžS;‚¦ûŸX·; z<¿%2ÈŒIµD­ÿ‹Æ˜ŠéÕ÷_¹qRD¤¨†²¥øÍüÇW„œtx­@ÀHr9Ei݈¤ÂŽŽ2Ž}øT¬"–×ò·ÉÛda™Ç˜ß/ÍØÜO쎃H£€• Ëp—WϤbÌ ]jTý¹ˆ¤;½|R‰I™Ë]SŽ—$›û¿§[á9_·ÖÕµ?±yã ú…ø”ÞqÑáBQY6×0¬(Ü,­Q.oÇ YÏû£kÑüál± ÙË—@m{e[SþgØð§€4Ô1ß±@Ã7e¯Ÿ£Ûë– ;£€ën!¸Î,øøF,¨`©GŠÝ<úÜÖcÒŠaµ­1-"èéj’«ýš‡<ÚàËšc¯ŽÜ… ÷YÓÜQk¿4¦'íx<™'n.õæ!¾€í1žM ²,g'†4¡p,HÑ]ã [AÊê+’€€å 0fŸ6è1ð¥¹y¢Ó:XÏ ð^7Ö×¹…×¹‚lÛÈ%Ð%…qK©›Ê˜OE{c/±K]yçU…Ï¥:㽜¬Èuó¥òÁi‡Á‹€GV@eÏ ͫù!åZj¬g#vh)¾÷z=V»±5ÊÀfRÚ‰©åäÄS~ÛpJÄ㕎ñÌpâ[B’Ûs°IdI^³È³zY°Íò"·ŸbuÝœbpª0ýS’ø¤ì£À²[g>¾ö‚ç„$- Ó —öyÄ? (àÇ<ÿùûkÓ1³òSþ5›dAàièc:¥êK[íù!iƒ:k#·W‘ügŽn'rkJÔ“ò/›ô¥ãŸõšXœÊZ3Û ß·Š¦‚'ù!‚Å[ß*Ðdè¿"âo°!€[Ó¡S"áì­¤3ñ ù½ýÚ‰ú‚vݘ¦W7ЗkAC¯¿ðn” ™ÀVW‘Í E-Z=í§ï´Ê¬nlC1§SgãAéÎ`+ LMÌjœmQ”U»;‹2™Aý\ Þ·…#% {<’€€Û–Þ ’M9Ë{(!Tïùv(+˜m sëfá"žSeä5Çà¨yLŽËa¯«ŒzÐ3œÍ¿Ü>ÜÀ8¬¯MîÄÙ÷Aä—; i-O'½k%“áÚ×µ3»3©AÊmݪ¸u[ÿ6\áÔ1å%”ÄÝCÑ$m|n£ÏWÚûÓéìV_ò€VÇêj1ý–껊&5é<mú'ú4Íb¨9¿FµÃÁ“ÑÛRº¥véEð$í£&¹îæ305¹X´˜ÕIËÙnÞ¡Zýþ¢q"3?˜óó ÀF« !…- F¯¿‹°l,çªÈ˜ð*PØsž°QçØf3Æê_ï’½Û eFG9eFN2Ò@§’¡pê3`¶Íi‰xá×5·Î}„Ó±-§…ÑK®¢Q®! ™“—÷Ñw¤ùS©)ø¸ÊB|.(2ÓÁßÒù8JDµTÿü›ÄÍ]ädÍwÈ©L…°E„ þó{mÆÚ;.â ¸¬ŽáªÇ—#Œ hGºwõ-dãÁ%/Ç›[ó˜€ì¢û–o`"įôá˜ñÍ:\¨<8qÄð”ã {ŸGé1WÄÈ_ÏCFìH8÷/¿ÝQk§[ñˆ†¯lÄI¢¡w— ÆÍõ´S¨(¨Y©Å»çuÖ\fÇt¶á7üËÕ-Yf¿_ êă٢ QsD§Mµ5ð]j#*TŒÒ«â%ŠŒ~YÜÉÛä¢M×å&‹îuÙƒ÷Dó¢“ÕM"a­\þ2º¯÷yš„ª’Ä}Xñ·<Fry lÚL/èÒ1UèD„ž+^ïïn­|9íM²ß3”€8êù#½= ˜¿Âp3ÄAª®°ó,Áw,à™_éß~âV߯‰I4y×I­+JZÿ8I?6B3õž Þß´ô50Ý`Í(—±~±ŸÕI›;\Œe±­ʈш!é-ãá³+˜f`ïzþXƒ:Éì·}Ú˜É^k†7÷ÚøƒSÆh y]ïQ9¾Öÿ‘ ¿AV@cög=:˜ 'ÑÜ%¡kÆös54Ýjà­¯B~1Ô@?,áxÛJª/ŒÕ¿ó^ýóNˆ(. ÓÖ륕zØVXÑÿ6S]vó°`בoÞI?ƒî|,H@té~îlí®Å› ¶@Œ·.»ÏäxŽ¥;€Wí!ï௷?S!ÿáÊÎ…5ÞÊ—v'Âáç’€€¤H\Í&ÛúhN½†J|‚ñ]¾äˆ.…ÇöO¾ÐÓ[B2Ø×{D$â $æ[‘§³ í1_Ó¡p‚L{òÍf7 ÆÍ =¦¨”U¥Yš«ÐãЀþ¬ÝM±Ä Bï®ñ±?¿º“ÅÞÉ>H©©¸Ô+"WÊÕE€D"x(ÿÍ~úŸ†òmßš¡íµ›ÙXÅ1¼}hgèè˜ý=ædôľûìôèü=¸íßëª)ÒÙ×í™0!¨åHàÄm}ã|W:¼ÙºÃó©jœÎ¶©ÈFO‚ËKêsOñ¹ýî‘-}?’­–F#1Û][yKÆ£h=‡òø4Pá{ã—GvÆw+wÀ嘹´ÎæSXp¢%öïÄï=jw^è<“í«‘,ìß+†/®¤ I%ÐT€ˆ^Ø ØÃ^îjÜJU¾¸_ä¿ë{D§%ÉÓϬ֋·íüË×`·Ùí’Ûœ–~p}.`›Ùšð\´`· ¦ÅŠ”½#‚óú-½&ËɃýL,Þåæz]ˆÈ-ÜR–aß%;ÁÒÜÄá)üi=‘Z†ÏÐüªHÇ‹F)Ò,‘¨ lu4"·¸¡µYëXÕ_°Æ¯Û¶È2Ì\¶aÊÎ*ƒF§½´ñ1˜"¼Ú¤øL 7_‡¢§Ñö¾DŽl„< aƦ)‰Ù ¯‚¤’Í…Öì¼…¸fãeÝ[‡fE‚½!ý)Üû×.tñwËêBœ­$?JFELÆ]ß|•±è1bÉ—W”†ì›[âÒlKþ|¦²(—V•?¡[/Ë*ûäøW7íîÓY îøÕÇCÏEx4†{T‘2¦>[Õ–L]n XNûÛŒÒjAíòk LfñhbÀµþV]mÄHÿÆEÚ|h¶ƒ.ò ©äÕ<ð¡UWóÉ`ò 9Ï[U\§Æ ”×(¤)¿¦±>ð¢•ÒRÚh•›b?‚G`læSà%™ÿ1AÑbO EPmÆt¤ÅP]ùPhý«÷dÔ¼ïJ¢R·£œögT¢Ï>><-ľLBäá{m˜ª|“²Ì¬,×βxZ÷à©4«„ ànç+úsððã+”-O—ödúÈÐÆ^H[·ÓÁ` Jbª€£â(ÚŒ5øêýću Í’¥}ù­Ò9¿2RH4t†z¸Î–Ù4§§µu7fS‰&Ñ’€€áÕc-ˆBá#Tb3š“÷Ò?Ïì|Ùº]q+;Ë"+'Kœ‚̧ H-¢w ]pdŒ„' @J~ÙÆ­ï!€Fzݬñÿã÷´硓†R’¾ófRO$:ZBp‰"®´ËœvÃy;¢·”~w#%­ˆßÁ‹ºÄjÆn¦dLM<;fÕÙŸôé5“˜$ ÄW>­Ù_ªÓΈø5‰Y† $Ïoç»ýÔæÊÕv€FDKÏNMf "âæ)ÞààTÉ`“Àð3ÖéëƒW«æ…“‘¥Îi0½žaÑeʽKÜéO•¸Ü£sИ=ì:X|µžKbÄüü­_íU÷ÞÌͤ©ÞTáj8^žá7;÷ª£t¼†¬s™Ÿ7ž³æP…ÜaÐõHŸmÕÊ8ç¾ùíâ)EþYöSñ•CN‰±þÝÄ9 'ÛÎÏ÷p­bñ´íëÇ sŠˆ‹×RV¸îóTDÒÎר°ñyÔÙ»ï—1Õ“©„èItऱÇ=Þ9ìbþ„ƒ­$_EÎpþÓéÈŒÁ\®ÑŒ½9 GW·gHn#º º‹Ù¹oV²$rÏæ:µMT<¸“› Ä¿#U4îFrõd[J©Ëñ§¢’¥&”¡˜%‹óÐ/þUU#“Æ ‰€88{ÕŠ:¤#è¨aû m*ô s89Œ —¦"ºV@ÁfÈr– ÝUåeZ¦ùòà]‹sä^ÜÂéËB ïÈk™&öç=ñë ³Øw¯"K˘Éû#Ÿ´¯ Qçœ-›ãû¯ß¨µ)¿™×ÍÞ®,^•·ìqyn<ñ5ØLí«;˜¾Œ<¦IæK{Fø2ÅTͰJq‡Æt±{y¾äŸÒšÝý|ÃÝ㔣—v2sG F6_ÁE¦4ŠwVSðÓñ"%!‚\ÿ@¡Êd͵®ËÙ—²múÀº‘ Ø_™§Ê)î|Çü<ŠºOÖl¼¼v8ö,˜uH+m†¼T¢êa´wa­•ÙU.¥HšÚ”Oˆ¶1¤””°È³{„¾Wqgº£aƒu,,|Õ©ÀÕŠ°?Ž]¹ÔÿgõÁb£ž Nça &òóPé‹Ç{ž˜ hŒ&Ä˃ûDå½ÞÍnñ-n壈‹€Ì§•ã̳@'?³>¯ 2y{ ’€€Áƒ €Àµµ‹:¡[ñËdRÞµ¶>–ÿÀè_ö }eÜ:…™¤\2JpD‘_FNï)#‡¤X%x¹oÁi…ãc<î&bcJN•tC¤fyõ±ü!‘Ë¡ðZçüçzÅTñÀgiÚ‡´¥qB Wt)[’)³Î9ÅîyÚì%ã ›9"Êkz!$¾`z•Åî1<¶)ϸ2¾/JDqËѱ1U’N‚56Øûz¬†R"hpí¶Í*V¡C)®Ó0³ÁaMИV[š}ó\Ø’œËxbZ4þ*.c­ö<_Ia!P}®°ÓYaȳv¿phIP¹¿A'Içþ0¶½5æ·Üú¢» \œô=9@)^‘‡†ùmø‚JòÕ:Î@ÙöñvëQ}²BÍp-\ƒ‘Ü÷ÌÅ1óQAÇK@ø)3+÷œ0¦¹Á PjŸÐG´.¢Á|[usUÌüÂU`ï÷LeÛ£Í(6gàR_P4iæ„æ©l¬Œ8|`΀[Ѹ6èã/ä“=Ëîz͈ß#r•vEÛÙ^‘Ó| !±†Ú¥My5ܳ M–¥ ñ£²ckÄe’Æqíc<ûä”´_§„!åÕ½jŠ+f-2òÄ Ã²üÑ«†o ½;¬[²ð_ˆä€zAáO:ÎÚê04‹~‰õ3Ÿµ'ŸQšEÎ9¶{ÿ¯Tqú£ÑVêS2põqvqJ®¿í‘pô% ós†QK™àãºÙà5÷4~ž´¾ÀŽ»€Ê ˜ë>×aAÖæàDT´"h)± Ù5‰pŸr¡–Ô™Ô1Å™còÔ_»ñÛß©Ž(å´ú} ÀzfèOUÓÐé9w ž%” ¯TšŸ5)÷xPz%Õ!l |>Ò½™l¯K¶}Š–ø¢ JÉáf|®­ŽBÿb¡³ i9–]Î(3» IÕV¬{¤FÌ¥º€GKì3èóß_GŽi}O´ÿ2±ÍüKDÞ6€XÙIÎtLêq >ôpãW2ì9ßt4Kxñ„œO éâl3<ÏqÝtÎÄ“i¬_Í_ZÇ·GîöÎâ(7v‹ûŸš)=´ISë¾ÿãt<´‚¾©9—ƒTÛô{M,Ò·²ØÜ>¸(±†EF`›`É>ß[OS˜I ³©¼IS7,’€€Áª×z"³÷C£¨A&J O‚½ÂÌv÷!‘rbÝ ¡§O§1I"çÈÅýÂõój§ÊkYô²“P2YçþÀ¶ºÎ~m ¢ãK¡uÀ"wãd‰´3ÊÐM†:(}^y×Ì«/ÚÁPú׸ȔéV&f{p~à$Ëæï‡/ƒqä©Å‹® *#ÙU¾û(ð ]˜õVüδï/ËsÔò~†‰eÝâ­ö¥8æÆ?,Nb‡èpOa¬gN´ÞY,X˜¨Æãâ– t˜}y´ õ|ÀŒëÑ eèuAbÑjit´°c¿çßäÿÀz‚qì ¤Â‘l•@ç¿w7N¦Œ¿n ¨Ë"1§ô7“!ÕéïUsUi¥Bðaº¼3Õ´âz˜Š½ÔϰPì‚q=]cúż8òv܇®Jÿ‰TN]ì]º†G5c¢µ;\™éaê‚Pl$ãÕG•®÷~£ïz¸ä•ýš{O7›û œ1TMRÁáím¦)¤ì”syMð]^û?*ÎÜvIy‚aÈ, Øy“Á!nç?‘3ÊÔ;|ÈWÍ\±±Wlyë×êÁÑ`LíKK¼Mø}Ó@º1ˆS­!Vé\pÆoB{“%¶ÏÝ¿SB¢åT{§_ü´S¼F (N=qR=V¾nœµ ü/üBÅUêšÜéˆþ¼±®Ö®¾Ò+lzìPéÑOIeGŒÅüBÝ<úœ—µ}š?  \¨àm˜£?}½<^Å)†UÓDèj\TË@ÄoÀæU9‹pr³’€€¿ÎAY*Êe>ìqâ±tc`©µKü˺Í#³2Òb÷kÿ‡[S“øäxd—I¥’yó¦¯ÇGþW€m#‚œ}ÓSè¶k´û•ºœíð ù#öï w6ªÚÃȸ1]ä\Ó䋽¢#ddùi'Ū¹y¢UL™ÌSÂæÈCÀªw“9_Ê´}3ELÖÎÆn1)‹IÙ ê ·YÐA±¡IWºìm¿M A)61tI¿¹Ú‘"þsýð)I#û=…”½aŽa½Jå›ÉÏ‚pÿ»P쌓>Þê>jc9o)&Fa ªû¼…TY–¢…8¡D ÷°k_ÝÒ£¥æêOáæDàxÓÔ „·ž„É©kÊÞ‚]%T#û¨Í˜ÁŠÔfŠa hú„—÷}kÈéeØœ9¿)Õý­BÊÙ–¼Æ)Ù£sZî°Áõ^?~ƒ¿¿ÂŒZzàxð; ì¤Òác ƒ& —aT,Bg+ô%eIxÿ8¹­~C…M:0?Àû@dÓŽò¢q–ä¼;#hûâ{qhe u¹yäYÜãàךˆâö" ¸©l~Çm{!FX’µ —çcŠÉÃeÀnî­>ðàÄ]]54ÎYÏ’%ö]Ku³ò9 jµƒì_{Ð`ø|u5ÝÖX{|Í÷1îÜw³óf³ˆ²D àüú/€Ü‰Úr>tUc{ü5nku¾Ï}«Tø¯0éU'œ#ŽÍ‘rD¯ÜgÆHHËA´„À©S=`ggÜ„ 3z¯ ×j­¿¹@íe©{Dù2a²dåVÎZ>EptˆûžA¨zŠP6ɘŸ°½}Ä ç >tí§eÞª`Q¤½i%Á°XÅ®·„ ì>Ut-Ák#i»&äi?–Ñ,/)§ÀEá~Å'yäéh¬â<”MkŸu³÷¯¥òõ½¨¢ŽŸþ€&£þKÕ Lã]§ÉàkF¶4uß–j¹s@ÜÑØeÝ–¨ß팋ÙÍÝìŸ{³ÁÞߘÒ`µî3ÕYN°Ä g­µ«yFÅÀƒÒ:`¸’c8öañ¿‘O0:TÁ"8é’’€€ÖÇkvÆçªöïÖü°Ä>À=þf°㦿Ú.fýÏ1ìo£‰WõÅ@ÊF²® Qk×YŠl>$jÕN‰ò%D“¶]SÎç£>r„Eã–<¶ýôã#âª49¥µ&O®1àEæ ×¼y/³$ªö­¡@»Cé$þ‹|À‘'¬ôÑ(oPQ~ò7 üiÆ#ÖÇçr«»!:õ«)ˆ^‡# ‡P\Á2X“Áµþö-Î@oC:¶$üÞÒ8÷(ÔéïæŸ—ž-y(Éxý–©Í'ÿ2¼»¨‘$Ìev‚ñá, C޵Q–?Û?¿LË슉ÒÈWyK Wœö”x±öµÁ°7 Nꦬ/Ó¿~•C,Ä>©?ü˰&…K²‡¥.¶ÿW½~,CÛ©•tqÞz5ò­#ê.xY$Ý%z4C¨ŽUøoïýµ&}Í =õQY¯se.¸ÁãÊÕ%Mf^¬‰sÌÉi¡føºÍ€1/qÅ:"€u|ˆhùmˆfÞèIÌÜ‚ÍÍË"T/›|z•GÉÓ0lçÚHî¹C,ÀY)ãƒ~"ÓP(›¢¯Yr?RGg7îáºNÓƒÿϘ (oÔ4”©VŸ(ÛÄ·Žª9%¤’´È3_ w­íNÏg*f¸ãʶL»^z¾,¡ÕŒ lJˆùŸ-&ïþQ¾ï¬¼•¿N RíLzZÑ‘¹õ?ž©éh1»»S|{îº&Ž.ó“!u'PÎ B¶pÞ+¢Vôw§ÝÅKq´ Þã‹ì]¿C¶ üÈ6‘í»{A_/mù8/v”¨-ŽñÐy³Ïå (,®v&á:Âê$59_të½ä±çÄ»3ÔÒöuÛ ~ßÑ­€’€€È"Ó˜jöDÈ£"K¬7s¸gL­€MÛùIýâäÍÇ×ÇU¸N0ëíôu˜{ÌZª¢-"[xúŠæ‡LÀHØgU6h×–üW ò̦GùLOV“{íò©óƒ!5ß¾˜ =xçMlð«“\¿®_þEV@Þ@ó88,ÛNu¤w âr‘da¿ê {K9îE±<èÆ1©& ?ç©^*ñƒÙµÿþ 3?]Ëxá–éÊæ±ÌjóJ JÕ–u"²J‚I‘fÍØÊ´rÞ€kaHÕ=–à…ѧuH»“Ã䬿Jî™Z¶«)°ð£;ÊI€÷¯(¹QûR›‹ß1ëo Us%ÜKýxß—ut!Ž{@>êUfõ¤æ×ß*›û¦×¶üf%0$!‚ȦxØ„Lœæñ æIƒŽlv<¢çù„»~²LÕÓ¶4Ѭ.Æwé\Éò¾4Ì›àÌÑD.Ch/Åýî¶óÔG€É=ÇÈ36˜r61$ʉSxRÄÂbDÿöõ”ˆjq{9¶úkaÙ»V6÷ÞøkFãîæÞwE ËY¹ÍÐʽEx–¼5cÄ/€£ò­ï«œâÌVkñ^£Æ‚úýiæ2µ-'@ÇY£¾¡%ù6F¾>U†9§yÌmÀ$O ȵ'‰uÊì®Cþ´ÒáÌ},+jÓ—®N@“¾x8}ûnÁî6ÓeÎn܉ ÎT†lú8—ªæ  qƒ™ÑÔïÊF¹Ì¨µÂ¬ :q‚óÉ›ÏZa¹#†O·,O ´õ•Ñù»á$Šä ì&4C¾çXï$•ÂQZ3·×TÓ*fÆê í|¾‡É' ‰j&×;ÃTƒ]NëÈèòÂ!'2Ïü”úH>þFÁÿT¦\Zµ/–þ:ùu¨Ñë‰åë;X§2uiG3;Ú´B,“U×M¯Y<Š(×OŸ€Áûè¯zÿU• h„Ÿ…UÅ@†ó7h¢•Uh¯:£5ÈvX…TrÍ„ê‡Ì)L×µv ®5"¿Œ†¸2ê*xB_ÂßIÀH× Mm?cWw×­ƒ=޹U¿Ë2èu_ èØøÌ[JtÙYÒqTs<àø=vè»n--[&bT²³1QaÐȸ¼ÜGg½öE9êg²ÈéŽF;ñ‚Aâ»·Úõ2 A’€€ž‹;œðoMùÿ¡ñŒ}’c{6óã522€ë¶Ð­fµì8ßáüÆY#Z›¢HÔN€Ž9H¥¤§)…\£4½| Ð(: eúƾþ8rÝùðë7ÔDv 5»Ì̲ÛËìQaõáÎ-_»ÓbÚ0[$Í3`;û?PÿÔHç6 ˆO ƒSVº&×I*KOtÄx£Û!b¶NR”W´æ‡"”§­_É)—ÐÄœ<%‹¿8‹‹ab¶E$˜¶ªb’ F“‚¿Ï»ám—ô¤Ò`±Zûwm2ôµ¿–À÷+ïg”×p’(m½}ƒ¤ ³7ÂHí»IÓŒ¬-¥9‡Ëa.“|—ïØú„¶.¨FÁêl^RáÏ%\ÓzjZ wòf‹?gܬí8Ó»‹>®dG==_Ç"Ï× @~V{¦gzƦ½ QÊèªÊÒ>l ˜H/…Ìä’‡©''1±5)–GêôK‘¿Ae4/Ës¿ú[â2?ê2a¹Wé®…6ë³ÓòzcÜ3-0»ª/Â{ˆö ð}¶6Cû³ë,¡Ã<­þzß*â•]‘ó^nãò/LhľäyKB¬Cº  ”ZÍM·-FG6a]0|³-O§X½ßuTfkuȈ³õ AJ'Ç~&Bi¢¾3%K=¤äß-Ž+àjgS‡œmô*—ú&‰†ÁˆdE \þo#{eKDxO'©Æ¨,Í»ªsÐRî߯»«ê5‹o«ë4ê#–TùÍùwZ{RÌËÜ Õ ÖÅlhYãxx.d~²cLÍrd˜²¼DLû‘ô7)Ä]§ñ"Òz<¶¼I0 &ê-wzŽÊмîÞ·7’î ÞÑ—˜ðŽ”ÒWše‰s<ø,fÞ6Z£ÞÔ šß¯YúÆLBÜí‰ ­ôAó7×öÝr5LÈoRŒ;µóCWx#{¼çcj#&€  Æ÷í»Ð±aH«Áx_·×j’€€Â‚.DØÑ¾E0„¨8ÖÀ³÷ôî<Ó´yJÌ<òТœ³6ÉX¬–£–d~5=`³ÖQÐ7¥0Z·TUÚ¢Ù)]èóÒ—úh²­ÞYl.Ž­˜IÝð åk¥EK_‡„LéuÕlûø]¦ýµ†ZZÃÑbúøE¬Ú ª.þÒ%YŽ\¬ã^}à}@z”Ü3hxÈ+ô ŸÃ56¼²ÃáógyL»ßXÄtF¤ÙÍ-ð¶ªZE¤×—÷ üÐ$ØMâ]©ZFwàÞö—B¾ u1sÔxõ£U…†T¶ÂEpt³dì%_}Øó@[4ölh[!ÜRPGÞ°ísýÅÎj—i§e¨Ær¢!zϸF™VzÐ6¹žü`HÊ)2%1¬–,¸G†ÏakxŒ,L,ïÿÔ7ÐEÜäX©±È¨‹)ëè6K˾ƒc̸4ê¯é Ø.h·.:åܨ3BÑT:òZ4¼=÷ïCËKÓÝMt¢Í.þ¢Âµk^å¬G#÷ n†cÒBɈ^J|мRŸûg˜uï†ú—Àê&!~u¼A™µ8®ñÂ’Ù¬Œao¼—>Zu#¹$*©l!9TòöèÅ7Y ¥d{A,8I9µû<4=ßž ­þs§ _}Ï‰Ž¸¢³ 6}xÌD3üþ3«wB>BmÆUnòøã9p^_&Á1>B~"¿M»¡õI‰ŠÉ{ÂAÒ×{Ó1ÝhKÌ(@£¡r‘Rt¯}4΃[M¡×ÍîT³tPJÄ3Êsãe”óüD¬³oDwý•Œ #×»fÍ5+¤<ѱ×òU(R 7æÄÎA¦oJõÄa­¸1×™Ô;¦/ v¸b«O1Ô¶ÛC<îßœðZj†’€€ÃÌ¥OÐåÚÊ­î<> ]–æª|oãÜMA9Ê×Ì在?ÃëúW‘«Î %Äf1íýv7ÞW~ÜýÓ¨v¥œâ=«¿ r5è“M"Õ@ÎàÂÏ^$#Í`*^Ÿ…ö ™LÒ?@6 »2 û&UÔqCé\$æ~Ê YþÉ5w q]Ñâþ Õ+‹Ýd–_·¾ým“~Ï(ük±CË- }Ó¯w³ájoÕ‚P¡`þõdN -Ú¼•g‚Ù^BG”=Q9ot<}•ˆQ‡Ük›0åÓ-ä¯ü­:ç½±šåÞíÆäª/˜:1<’Á>ÍcÎF¦e¥¹<Ì L‘¥xYJ“¯~Œ?’ر­ò`n~ëß[=Åšìyçš}p³+r†L¨„$di"É^ËÌCC£„ ãeÁHÏ>ÛÅ22¥HiÂâB,zán¿ ¼¸6e™Œjh8ø JáÄ´g΂¯á‹b“Ž]¤OÄzëçõç44¬=ÎÂ1%0Wžº´<>ÎÕªÁzðóä:^J·0N+Óæš Êè?+'ˆÁ™Ã42òk×Ü“"²oÑo¸?—ÜâEŸ¶xnêLÓ’ÖQsWn¡—å!ͨ „3^ööžü i =_,¼1wNtãã¨ú(à“®%Ü~}½ûO=ßAáß_ß "®‰¦¥vÉlfúÄ‹È&ã]ÉÔÔÅ·dŸ%e|½Íì8¶íÍw=(^5°¾HN=uçfù׆·ýïD¡¶ (HmnØø*Àüª·PH— üR frÅå #rû,O‰<°Í7XÓ½ø‘²Ÿ$iP'|þ[áëþaÝêeJ?Vl!œ¦Eó¥µSe¿ ôįòŠÊŽKÔ£Š´…Zž'®ƒ{i ˆrøüêT>eVP'³?èØP÷‚w!N§%jâüžºI„2 ·:å‰*ä+hÜ«$Dý3d_xeã }=EˆñnàL_œMSÁܘ-]П`c‰Ìº…D+èÇEÿ)ÂXæ4vTØY\¢BàìȫɕeIÂRuxrÓT]ja¢3¢Å"JÍ蟩O®0K– 2E¿€"Þ¹Mþˆ•E¢®k ‚Gùkr­Wòuœ­«œNd]¯ï¹ZPâê´ÎÚoOÕለ’€€³íà+Àlþ¨JÖG¥¼¢&ØbÝÝ"¦J¨iJ§’¨0§é°×ò'>ÛäxäO~“‰ÇS] Ĭ\÷‘¢OÚ‰‘¥eÊQQÀ#˜=$­ Ìøœ¾‹'+ËZØŒ(_6¤€ÑCÚñ¨üÖÇ쩽z5ašŠßW´œR¯·ì51¾ÂXMe8]¯zøÚv^žnaaåëo<<ƒ|Cª]që|4åH†eÉÉÇöú,P´énU„°Šsyeñ§]hõ«yP~¨Ø@!%Ù!$M÷¤ Áðã¥î3ai¨&'QV$D{'i¿xþR¾‡N#pÆvo(Ûs„;=œ(æ$v´ü¼ëµC”)1©RñÖS‚aÏÙÀ©'_bUþËoͯëªÞ¯Ë‡ú¼ŸäÃ8B’ ‘®FÓ<Žä;Ù$gŒs ›¹KP+3B3­ÒsšLí‚«cWq,²_·2¡Ñ(2&ûR:ä×î7ÝÞœ²†«|·¢÷ÒøßëMý:K(ó‡Ç”89/a:®\Këô!âÓx:Ù±µ¨_¨áš€ÿÕ£#bÞA‚h‚ošÊ&`¸Ÿ“ÍG¨™Ï««„®vë½àdñ çW’kËî2Ÿ ƒ`§¹kÊžA÷‹Ùáé9öÓ‹¤m„ÏiQ`››nÜêÖÛ˜™ötOÇûbÎ*Òýx“5 à4&SpOž¾¬¢“••Ô_?®äzæFfî¨Ô:ÑÉ»vY¯,ø)°üÞnÚÖ¹'ê ÖRΚÕdR×e<ሠt©Í¶¶› d¬7yj ²{v„É{ þMá w[¼åÈÆÂo5l Ä%›œ¶AAœgó†?|‰Ðê[¬O|ùËÁ[ ÷9Ž@zà·HOw’Nñ-²AÒ=xD[²-¯<:ÜA&œ$<ÌT  ‡÷ƒÐ¥É<Ïø!ÈÑDm>ÕºìõƦ6µ|3 +‹­†Òó[†(Õs¶åã3˜CëΰGžÝ—vy#…ÙE…{ÅD™¶üÞJè²¹5Y±}D¼“yÎ* ! LAõÁ}ì7»“Y´°¥¡S`‰~?…¢¾‰L6c³Œ`Ь*„J ö<ìôêmˆepVÝŠ ºûË}¹X<ÊþèY`ç…R(ÛO·¦ÞDðC¢¿ì^l&ê’€€ÜMòƒi…]¿d¸”CãûæÁ¦ÛËeFhÛû-˜~«d(ú"’…ˆ^QB7ˆ? ×ÊžÝl¿€wâ‰åñYÂ^ˆ±:¡¢=‹ ÝT§ÔŒÛ“ ]TG6ç-ð7QdI €»tnPnVqcˆð¶½a}^r—Ï‚îH/ɱ·1JqUQã<Ú÷Ó‹‹öP³’›½GÕàÐ=êÈÊ]3D³°(›šXƶ˜TåìÅ'º7 >iÝGžÅŸ¦†‘cœ½A%:s ž”6µK¨p?ËÝpïÁKå"¦3Ž»C°‹WXŒóéß×O5o/ 8w´N «.˜ý[&“ €‰ß¬Äµî¾+0m—U™y©ã¬]ö¬bjõy1õ¿„›øúå.’æ½ÃßËfC¯eÜ‹aŠré¿Õ=” uõwOÚÃCãedRßcz& M3)˜ÿØÌ›5OWKÇrG™>!t`¢_ò]Áx “{ªÏ4®à!\2(P«)$qW6A/ùê{X¶Ãü„¥“`_OžíTEAñôЇºùaèva,òJS˜g+ÒªÊïŸ{£)òºÐB™/ׂD€À{ÆÐwl¿+Œï  쥷øë˜T…¿ÜÅnaígð28éJ§ûV©D½ÄÅsÝm*»¶dd«ì¥raïÊàþ}°¸®¡º¨æ°eýZÿ¥÷i À¹¨›Fi•ºfç‘| |<ݬ»¢Uºø2 T¢€[¾l@í¸ÚyeU€ÙtW·H´gj”äÔ/¹ÊC]1aáp!­;M¼ [™!sâPož¶žWeßCÑYÿÍ¡É6»u“e½²‘Y± §L‘þ7¾Ž¾eý;çßÌh»%ÔôEþ a?ÿV‡<Œv¸Vt|Ó$¬VóìꉃԦfìÏÏ7ûªAžNuvå)óÞ~>çåôýqåE^s•ï72’€€ä %ÿ>ròw$7¢cñÕÔœ³'2©= ϶ä–•‡–dØM k¦jãÿ2-“ú!;èpe>oîÁ¥¤z¡5ÉÓ~œ'€6¡–¢;Ãab䆑Ãþè~¾*J¬6¼¤&OÜc1¥í˜ªgQ½QósD&@3áŽ{ë E_WK>eÇJþí[×Á¡RŒÕ·û:(~@Àëx™gÞCðV-Tí,Z Mjž;ÈiÞ_ ÂÛ…ñrqìT_Š 9VJúµ*¤YG5¥,»®dïŒS°½Ë xûW'S#Lå·5n˜£ßJ,66ø©·ížùÚ®¶‚ÚSÜeI{ ya”÷¥1Ÿ¥[…É'³(ýÁ¨Pòˆ~¥ÈZ³'%øÛ#ÈÆý)rAö+Ê'‰° ¬òo5$X˜óƒ¤ÏÆÁ;¢>aøÚÓÌ!ŸäfDŸ5$G£fÚy®ã:ËÕ9»tÔÏ´ˆœ-»¸O0»œþ.ÆrgâÇ]Çùôó· ŠŠ8³XFª¡ùƒ`¹zÝY…Þ„qKÎ)D¿5Š¥ê$䯋6G4Ÿò¥<ÒñþI•=î¨LùXè/s°¨'™uD•Á=|ט1'Øu.t ]ž¦å½6 qFU̡͠_‡M½²”¿×Þx’€€²ç‰&ïɤšR”vgÛ úJP\À¶Pq)™Z§èåÔœÓRP›åëÖóùˆØ4¶’³JªÒ Oc)šƒÈ:/6Dµå²ÒxŽº£äK®8Jû§c3KÙ»S_¡fdäÒÐ “b'÷,ü‡ŽS‘$X$ÄØíÏ7Š3ÍQ×'Œ •ât_ÀLá‘Õ\2¬°'fÄ 0œ,×KãœúzE¾î?/þèÁ¥ÞMîñ•>¸#¿`-‹²>4$%48ì(G+d§Èx,ä®Ãf¶$…Æ´§\Šú·  ‹¶ïQV–ëfAƒÎm_} sÁ¯º!]Á´#ÇšPˆ‰óQr_O| -Zcv¦ÐMÞuî±²`ñÑåÚžwöÆLŸjÀë¨õá0CÐøE;Ï»nSÌEõjKüU­ðJ8_4˜ÎS¦ÁTÜ<þc*hí¨öÃþX-o« º ‰ÏFxâùJ¬â‡lŸ‘ÃØpÊ,÷·üeع­§-æ¤]ßÓBÚt¥Žó*?ˆÖ…—L&·{±]ä8OdY¤°îEŸçÁzѲu꿦›Mßf&b•0:˜ZÎÜ~ß—|ÿ8ö3Y—#¤í8¢Ît 8¦&C¾_©Æ”˜«/ØÉƒóý²°Š‘-œ1ž€ŽÒ±RÑ.GÙÅ0õó)äwÌ„zÜf“{}¶kÏõþK-Uúð20gßvr°’ÇÆÒü'òyø-¢ªPM궨&_x_“£ˆ#7S^ *ÄZ^—g/z°Ž£¬·’ *ûÕÚmAl 6oú²úΞj… ê”~âAó;o P…¶OÈv¶ & ÿ¦i.J—¬¯L´¥Ï~œ"·ü~1ÙTZò†»n× »\ªí„"wQZùěȱ5#éÞÓy?/Á_G“‰…–‹„°bªàFàI/Åeî¾ë‹V­‚òQ …Ž™âIß?ÕhÕÝ@Ð&xúòtÈSq ò‹1Žy-tcLo[…ôÆ”Eø€oÑUG„XLᣢ2-b]âmÇØXΘ—ÿ¾’pÉ×ÅÙ¸â.Na¿6µ`wÛ›ÖaŒš“úf²Ýþy .ùâ¥.ˆ=ßÌN3ýŽ#8t&¨€’³°ÆYÇ#XÚW„ÕºäezâÚ±z»Æ;`%ïŸ&^§o’€€ÓÊ6xñg'L0ôJôÀ69¹¡2̸¦Ÿ’5ÒÔ)kƵ8„á¡q†_…Úu¬IÆ@¢Ü—ì!òvβ‡fá§íý¢óEfS(ÂöúƒÈ »b1¥¼OWú;r…•ÁÜh«Õ#Ë7jãå:§DÚŽÒ’Âþ®Ü»þî ñà%¾¤¢.V’= gϰØÕÁ^”§©?PYw³Jê~ùö³¡RK›qËØ€?¿aÑCMÄÉPWz^œÿ7Á ÚûÕníEЮŒ'?âü99ºúغ ³bâºÛdåªß‰Æ£&*«úä2š,öZ5çxÊ*º`.ùt DW—ù-pÒ¾‰¸eN´ß9ÙƒL»È­r©Ô« gnõT‚ÒVÐÃ/þkL™™Š éOöˆéyA÷½Á‹±ÕH2]ãêKqóPîÉËRØ•˜—'ˆ±yŒµtÔŠa‰k†èkœçwÎk¤,©ñªHù:Z†OW6ØâÞÞ»ª;Vô ¬ÍZ|Y 5.µj¬·¬·íý&ê{¡Û¹5»r£4“‘RÅDxkX!à€,Š¢¥—„¸³i™zaCAó”jû0P2R~%ëî¿â]K1Z3L· yÐ¥ÑMÈ÷ XC0À“ ?9¨Öâ)‰=´J^CÙ"L`(<¦pÕ‘~jï>XT÷sö¸\K¨MàNÆÏx¨†ssíqš™äØä0ijàvù? €³ùY½Êˆ¢öÍ0œUåƒàoß4MX£7-¿¶Ÿ2§Ën×›£'ú°ŒÌÚ"³‚Ý—òP–v¶I,H( öx¸áƒÓÈË|ˆÇuuÅVx¢Ù6âS€[.‚ØG¶Å¼ãMíñ%FY欎ì­;…ˆÁ‰hG,6ñe\¡  m'+Ï Oÿ‘®¥Ù©¢ÛI ‡­rç¡zÈ6O7äÎ{‹"ßWÄ.²…ÍðÙßvéBÓm†W-nÉxƒ-3_¾J#xþ÷«1“z¤^ÈÙ×Us¾òvÈàDMäjOY„¡[AHmž5ˆ$üÑÅ6ôqNr^Äìioä˜7ß‚wJ œ©z†fÈÿ°ýùZyíïÍ|è9÷“w7è¿ XP݃œöóúì«DߘéË×{ä"ùÄ%1D7ËÁÕ»`ã³ÎµµjßSWD¥Ò’€€äƒ¤|ù#ÖrÛZÉb|°, 3:1PÒ¡Ù3{”‡ûÊüŠÙKš’3¥*ž&#‡=εbšFî ·IݯqCœÈjÎ&'ÆQÄCéOíÏÌìÿ8šŽ0ƒÖ©< ´‘­jËpWÅOÞ Ðð˱'§‰ ±õ溚me­žÎk4ø¯î}–õvRâÛ*ªc†Œ¡÷ôžÃiPâa[ÎRÁ’5³0(R5XÂS›°CÔaO!Áì›{_’˜r,ŽÃ¡­©‡Ï2©•*å?eœÒ À)91´T’€€ÙXŠÞ23¥~cRc°m]è4f9ÉíEâòªê:º¹e÷¤ˆaÝéÒè!| ú²¶ÃïàM)î”ÏN`†ó>GŒ§¬ ¶€ûÑ:X*>t;ÕsvÈ»ïj*ñ1ŠãEÖ‹"×¶ÌH0†a?{n°„8ƒ¹p9BV›Y­á&öüƒ‘I’I¬c·~ŒÃ§#^d³¼“±ÿob}7M4[a\ýº¦Ã#–î¿|,Øßçȵ¯ßèDÿ%jSÊhù£ ®Ú®zУ#—N “¦£S_—ö Â§/?ñDÇſ˜ø|Mƒ?ʃca"úîéášüZK³‡©'¨„d9-߯{´pB¦yóÅtÕCªæ> x­cRmŽ) 6ë½ë“ ôÀ#H‘YAeéði·-žÒòwÌZuª¸Ù_r‰ßð†Ó`X«\ï&tvÇh$Œ¸üMïUÀie7z­°¨pgáÝÙÌŒ²~÷œI0JGWC;¿wÀÌÕ@»baïÙCIG¤'šÀ ®åX5†wŽH™žçæ£}J#­µUb5ãUòpr!*vâøoð\Au" –ܤa÷—¢5‰éìH'5³RéÃ-,K“ˆ¶­8Gç£-ª'cì´µy:4MŸ]YN•ot’© 9^ j[7¾Ü™!K;àÒ1ÍÊ4|ÜM¦û¬dèȯ{I⇵’geó²Èµ7M6iF?Q™üãLývú«y†Ñ‘éàu°þB.üJßå-û€·:ü©ž,~ц7e®J¢Rz2GÆ=ÚÂßqZñ€$÷rbj)F‰L îBÝ9š”çì(Ú¦²º¿bG—ã±0é—8ïˆzÙޓǨY ‡`Ÿ= €r›1ß›ƒ‘%‘qA} é4m(%Go“Šž<[“<%jÏ–7Ýý­¬U$Ì©rÅ/?þ&¡µåí9Qq¥)S=à¼xT-èèÉkNràcïv‰ì×Ñ„õÑgtn§\¶©_Oú3Å«þGò Š.PPygöçÜe¼hŸ¸ƒ”£ ù6àµrN¾Xº+ÔÅ_)¾m"³ñõÐPŽVñÀ‚o'>n…÷/Ü—ü: u.óZ™§òÕ–(ŠaÍ89GK§ËužA>ÔÁ)=ûéAAO°~!ÿxùgOzd„«ý!'fÎ!K>Ç3¨ƒ,X'øL¯) QobÚ¼­tÕêgçä¨å6†°IP:P7èý9KåO#l„Æû¾ÆÓBÈxjG‰¯¡3û`ñkNb5mœo0—@dôO7jµdîâÁºþõ½ ;ÂHòDW­Ég3äYe8šš£ÓMâ dÄ¥¶ˆô•Y²ðo˜^i6«j¦z]„"Ê~á€w··3 äGËt Ñ Âöéî »Ù&‹~Ýy0~ªû›Î®<ë• çá.)2§N7Ä"ðD²;ž¹´H]ÌNX’€€Ò˜Å2”z×Ä{fÚÏ2°x!½Ÿ¶L¼-ÎÐÈNP}AØ Íòoíÿà;è¢3E~¤^QÙÝ,y ëiJø‡ øJz3Þ Ítr ·²«ó‘‹ðƒŽµ—EÀ{–ÿ…°T‡Á¸ä½׷=ݤ·”>´íCˆM¬n~A½«»Z£ª‰¼œa–:†òš„¼ÒI€³pª/w¹vãZ“ŸŸrnáDŒÎ©d¢BbŸˆgÄzÑŒF!üí­@º›ø¸h¦Q+ÇÏÕXm }÷ô2{ôÍâfóÀë•E ÑW*-·Éc81¼èv´ž>ÄQVLÌ:ÓÂ>6'Ì)ƒmÆ›=ß<¤Am‹4¬øª­”@ˆ¨)ÿ=iw• *\*.é\»Û{z\!Np`Ä„q1Ù~—hVè¾¾h>Aô§Msùßü»žHÁ6¶VðÝAc¿¶ìé(ì7ߨ]\±h8.¡*’€€Çˆ±£ú2&Ä£ÔŒìKÙɲOÈ–|SÉgøáO)tãÅx à÷èLÈÑŠ1eHN7EpþÄXŒ_œCZ²äò^uÙL´‡ß\ b‰Àˆewj'"D’„O׈?ýæ¾V–ïûoó½SJÇ`?)^$ôåQUõ?­Äíâf´YßõŒ÷ÝHa³ú˜K ®…?öWB¾å\ú!‡N Þš»}"v¾æ6‡åÉãi&31¡us&“WQ»ÏÎBÓÜÁª.¨ Ü|!Ûƒ³úÞ›ï§ùdÖn‰CÞ”‘»$Ù‰àäNŸ†K„´Ãß¹AXK# ¦…N–#–2";zãÓ^¸T†"/áÝœùQÖÅ`iµDÀÖà_5Ö$ýq€ìøgRoEFÔaGî6~šA™ðT!%1³^zî£V:`ñ(/ë•nºÓºNqÿÜœYLt\Ç“UA_-'†LÁK,†!E¨Ö)Ìè[’[¼B‹ÎkF\§6âÔ5VFnÙÊÚÕ:5a%1­ÓkuhêˆÞ1y1¼L“€æRç}­ ãÝV#gîX¤ “Áú’ëBྛž±¸2Î/ܺɸjòç#‚L"‚ÔÍi„·’„•P&ËŠÌ!Öiä:y»—`˜i…:Tþ~¶Ø½ü‘X’€€ð\0R–~Î\“–xgf$þ¿|…G÷±€a© o+ Ik„z!T¼WO„»)º‹¬2àÖ8œ²Ó-ê8éÏy¸:&¶^Å:£,F3JêÛX ±d…z”P~ÐÉ•EáÈØÄ7! Pkæ)>ñVly¹©"/eœ±Ï2Å yýcÿØ™Ì7ÿ­[ Ûž5³Ù²#2ã|>m¢Æ›7gðк ·4³”¹¼âWoª´u³È• ‡}Áèž«VÔåÁ¹„ì’Íâå6O½€äÁe ÖsˆŽ}lPwú‚¬ñ,´‹µ‰Î"À,âŸÇ;D(%ì¡u'×5µíõòÕ¹yŵP×ײ•{¬ NHà 1]²¯µdf>¬ò–Û¤*Süè±$èƒÂxhÇ ŒlÑÝlWv±ùsDÕ•{Cÿ%ز³v¡îB¦‡.K©\É6;g !2ÀòÍÀ‹—’é÷€Èí¼@¼ £{ÏsúÚ„£Áê¹Ûè¾qçý6г-P”Û¼»› ä)ÃP£¿µ Z¤ “7˜=äl¿À%ÿ|þZÃW^À‡_ÝÜ¿#84ÁĽ}ÀFîXgœÎçX¾ç}ðÒ˜â¦\èó¾é}&Çÿ¢nÜáÖ¹£ìÚt›“BÙaË •êáä=|çÝ7¥‰:Q`T&¦’€€ÚËr¡dsl}®Æ0¬tžP6á-¿Á[BîÅÍó4Kž8‹+6&~/Ë9U?c1|á‚íi1½oÎX§¤£oC.J]˜cÄà#ŒK¦£‰WXPÀ‘uÚZM¦ÛÆjÏ`_WIa9jr7€ˆ§j žEpQË‘Wœ-š Û¾VëÜQ’ñjň¯!"æ²;ôÚ.’è2½#€)•ï.(ð{|n W’>"à‘ÈÄôÍAûè9¼#Àae™KÜ~—u 9‹)˜ƒôçÅsg˜Ž¹þÜS Öo«”æ)~@íýü %N™=¯tɵ–hB0‹1A°°pÖË|ü.ý ÛÂЪuqÈl‚ö¸kí[.íqñr´ N4«We¥e'%Â)Ý‚¸¾¼é&.ïˆsDîØy îk,W†þ™ü+Çñøôw¸[üáÛESƒK¸)Bd=¤ †é!äŒaø?3ü!iWý¤å«ßÍË{oAÄ­Sè7ëÅ–C œ+#å÷ƒŽ’ÄjðtåÊkãD–cýÙf•aSÆ@÷÷?|ÙêZÈ-(Ùmæí¯;Áå{cÿ,Z…ßòöÒ}W—)à£çÌŒŸ'îyéI©ëH§þ‹/š¯è¬¬[µì•ˆšøHï2¾9Á•Ø6T}…MôŸd&¸@qß×ö‚ëEUes|]Ú6ØÚÚ]™ìE¼ T©9)º´³ùgñ(§ç9ÊÉ ú²4]¡¿™Yo‹ZiÄÛ{fêµèÆQ…Í4¶]õ½ÕšØ¥0X]k!¹ “×I¿_àáwI’ÃÒìQHæÑ§<5‡̼š‰þÂP]db\Þÿ ·æþã8+²ŒYýV$¹¾Æ}Hë×é)‚Pá!]Π+W– ¼d£Ø#ÀÞ Æ`0§õÞ6Þ­«ëŒt<ËŠ]7îä/×UœÝ'–ÑÀ(ÿ0´Œ Ô¾ÌäEà” ·4ª#ÒUÚ×êð7 3\s‰Éa4uÄ}-”²!]N3Z$¾ýׯò2/=”yÖ°öô®T2,ð]D¾Æ ¥„µSgüî Áå;4–QÌêzÿÞ²®äŒh×ÇJ¶Ût4Ž<ªrÚh­¬÷m €€gÒtùWLˆ¨Ô¶ UùˆñAS5 Z…MÅ‚õ—ÀÜ’_]X®‹©©’€€¼wF¤ÚÒów¸g) …ÏÔs,b%,Õ%}?| ½Ìå@ÇW¯_À5‹®itÐ’¦mž'þ—(& i#Žâ ÅBVîoB&nŒƒ†‚#b1[ 5sµÈ!Õ¾y Q%ù°Oß!ÁMßr­©g‘í—ë}°q¹`å'ŒÄ¢õo.ùWžpÂÎFÖáåû<¢Q‡Yu;¬!M¼F(/ãuõÓër†/ù¿Zpö©$+à æ3+ˆ–°m,žs+*Ø™ß@:µãÑ1ž/-Ò7¿ zLKV K÷›™vû5u"ESf ~àG&:Eup#à¶ðãMzí«]¡QÄ/·—IÀãì÷à|ÆìÑöù¡3‹¥at_­KAÅÆãÙÿmù¾:õÊFÑåÄò_ö€mòäú‚<&E¸DM;mN%NÆaíÏVÜl©:Ou ž@º ¦¢ëû¸`£}Z¯¹°î@ò¾¬&LVñªd—ýAoÍåèÐýç»yOGOcã&:àê~. –áU4™ãÿÕg4ÝÛ:°ÙQV¾1W+‚ñ!¢‹Lák:ÁTKù‘¡ò™bØüÉ Ö.0ïÚ(‡õ ™KÛ {ûÄ(’MW‰ Ο­¼ßIwcçãN›m>ŠõL?…5XJç}¸µDÍ?ÿedeŸÛ·SkûÄ0š”\kšIõ•>å:魯–žÞZ‘é4'tNâ5®ëÄI1ýß>(ÀÄE²#Ñ*å/5Åj.ƒùxÙ;˜{agN^¯ýX7h2Ü)Ç:y6òˆ×Q2v³´¸™Â”½*Kïˆ4y~úÕ¼íýD^8ô²É÷Nk’zñÎW‡Ä«õSÓ7Yx•^c+jcE³(¾¢^cb Õ’€€Þõ{$›·?f”u~_öSÀKS„Ú-E7»³žÍX}»xÏfpûlj»â’m@ºßñ ±,ÍÔÉ-Eî1Ð,Ö\§ÞÈzu59Ë>ûnw¶±ýµJûA Ÿ‚ ,¼Çs<;s©Ü€µWækÙFJK <ìVièØ .Kx¼Õe"¬9E‹ðú7Å»MAD¯'Zlv)£H0 Bhæ‰òtÊ<ï91~žÅlÞó)+¢D¦´ÞÈu‰B­{L:ãpÚaõÝé3{*ßÇC‡‡¥þáø(åœ÷yË-óH¾Jø&ÞnÏ4ZÆÈ¼:-ºÓßoÍS£CBáE1¬"5¢^Qº\í8Fg ÎÛZtìD}2µé À¥ ¸ÛsÇk•9å’ª\0….ù)x• I Þeñ’n0ˆìÆÚýœ¯g€½àbÓ¸~S™f Çò´ð:S$ˆ¦Áñ¯Í6 )’Ñ„@" ã*siÀqÕôËXI}Þ!—cM¼öFní{{Å´B6ôRêó YÆ.›\1x²cÍn—Ÿ«;{{cN§Þʸ©…7¬àÎ%òUƇÖÅ£f3Yó­à”)&OJÀ ª/æEF=—þÚX›ä¡AÍè9N(Û¶7&Bü«*öúX^Òº|×†ó78ÿÅýôŸ>²('ÇÊ1²æQTM&1ûAê€ r`Åù’rÌÅ>æÈá4xŒ¢hÔÍc¡ðz\­ÁmÍ#3CÝOJDOdñ¤8’€€Ú5>ìÔ? ž6«Xi/·Áüt=×’•ëí¿þ˲̀mW\áêS9q´€O€êÄ„J³ü $%2U”3æC’'hÔŠ©©~:(Ò§G7™6t£ÁÂ>R’òJéoa0ÍÑÏÝ0hÿËê6µÄžr¦ýÏÏwÝ%„Ä(d2øXª(‹ì¦fn‹:Œúµ¼`tgòç59·$‹C¾ 7gܼøÔ;, GH q“óÑ÷å~H@å‰oOš­$«äÎßë/cŠ'Aïk ½_U 7ÛÅ™2‹ÑL ù!Çc¡'7Õ°®g=÷8±»Å×L?“HG´ ºÔÝ|廉vp-6OdÒnï]‹J·FÌš¥Tø†õ "ú’{Mù·ÀÇgáø[ ×Ly%­›W*}Ûý˜e©dòmq Ú+µµµæon9éR ÐÑÁž«qYr‘7DŠ;该l/ú[J?eüÅ¥éÞ_-¡=ÛÏ(¥rµ>ÂøäÐg·Tj0¸Ø(àÅ6“~õZÎò§®¯Â£“ÇÁ;œw[Á·P+ûÆ$Ý’$§@fÇ[e&U¸NÿGŽy9àyý”`ckx ¥ÖîC¸G5ü׬ƒûò‰¥L{æ÷µâ¹n›q>ð§-‡Ï{ð[)‚ š±¥S×ãi/ô SÔ8Tòý4qCÕ¢`~ÀQ@D\v¼ÙÌà…Á›}Z<Üö .Ùhëa†2ôz¡Ç÷ãvœ¨A¤,éû\‘,’€€´²E9Ù&ˆã)1 ÀW¬YxêZ3Æ8…µ`Yúײ žæTæÀ060e2 Pš_Ue µ”9Ž%ªõœ±ùÍV€Uí«ŸB5÷bîÔ†™cwü*wIºt¶Šl¡®ŽϵF³kÏ(2Åû›šà»"%ÉËÛF®+"“ƒ?<†XPaÍZÕ%Åúû/ <šÂ_lÌC5„̬¥i‘èÃÂS(÷8½Æ‰ïËt¯eê09{zZ–Çáy¶DÔp×IÙ×ZðŒ>¹r„tñ# Þ“ËT 'œÓÔþa6ÉÎ÷þ@ŠŸ/Ì€Ú©íÃÆº°%ÀÀÁ !qåQU²ðyÚó¯…ÿaìÁeOpO–)ÄÚ’á­Ø4ß:·.ß÷¢Žà‘„Xmx)Œ'3HÐ- ÜíDÁÓ‘Û˜\90P…Rb‡©¼&†੤t‹ç ô# Q5¹C‹£Ñ¢òçW“õœ¦&t“ØM qët£1u ®óÄ·õŸŽ…#Ú¤yÀ\|É™ƒ"¼½ÖQàÙØq(‚üW…lÛ «Œ”ÀàRPòE¦§â¼9`:ÂíÒ–yf5ûŽ™ÎôÒ¡ÈFÎØûápTLԪ结ëb ë®2ï&y\õ¨¬ö÷±u¿¿Äáí)ØiæŸ|ørvq_À¥Ó&Ù”O˜ÓâœÖ²:ÖÉÛ1!}ªF—]TžähêjcWU_~OrwÿY¼z/øV‡öT¦]NùÞ%Ÿ''Ý|xßî¤jçŽrŒŽÑñöÿV,GVŠÀ "G¨ëf{D·ùÄ\nÆwë{1BÇ›G ›ÞÅÜÜ»&ûÆ*ÞCkâ’€€Ñ j °¢voo9û ùÆ‘çC:u¶Õï}¡Ú•=Ùˆ¦J’ºÒooP««íäY$‰d<=FË ¨Ç†SÔ"ÉšoÖyÌðÍ"ÆÁèàAFXé*iZ ÌSBc×TPßµ³‚!Áwü¿mf¶?È+*ßèѪEg^bÒ½<ŒU™¶ »ºRY©5½Ï›NH„6µP¸Ô#C®$ Fï-Njø q·sä¾Êb1ç«Úëx‚…™5M1«“yBðÿ¾1ø lœæ˜ '?5ôï,¼ßiù´£Cz’%|¦ËUêÕ‡½"9‘AB÷Úì1䓯ìÁ]ˆØqDy"úF‰Âèaƒ4zBëžV}ZïáÉ]X–£v¸þ–̽6·ÎÖŠ»×ßÚˆÑÁ¾œ\³ÁRƒš°3ç9 c,线1—of hnó|ß>lŠMØQ¾­cî Òi8—“‰°ä®ÖPˆXS+ûx®± ¨óqÎe6äSFaúß¹¬uK%LqN›þbÚCÏÖ §oÅÚŸk8wÏÃ?Ìê?#9"ÐÉôÖÊ ¬ÄÕÀ2ö-TN’9d‘´KÛ =Ç× RÌŠ[ŇU7˜g}—!]sâ矟é¢ÊrôØÎÎÚô€¦Þ'$5…ÍbævÂ5Hï„ÝÃÇ÷ëÏ8§1ù’H=׈—¨Ý©RÓŒN«Kj…T‹“=ù †evìi¥¿p(ßÍ<.~¸bž~¢A|Z!<Ù£c >?)™½-”?sÅ=§—Ž“eþwÆ`šc–¾C^¥»´…ƒ£áð:…dö­WT! Iy4ySt½ªZ¤ÙÓKW²µ§ƒ…JµÖoñKÝWZ›Pç`GöÃX`ußy! M,y¡Óç,&Ö¤îBÂrõü–!þ@ZÆ%©6€ó¥µÔïÝïù¼ƒ_´Bh,YyLµÎ¾½hmæªjZÙm]µóƒŽwÿDêK!óªrÒËÍ)–Їc Ç<<ì¹5žJ$Êúy KCP¶(H.ñå«Pvg/Ns¶Qb -ˆ 'ðÎ’t—G!7ÌV»W›,oè'Uè æ€3Á3ÀÑ2è 1ä5¤‹hL{ë òSR¸«Ž*/êæséìУó•\íÂÄ þ¢câ’‹™,¢ÊÒuÎÌã¼X…I’€€ìø|_|SÌÂÿ¥"Hú³¥k¾ðB‰Dåµ>Á"OÖûIÔ‹ ­Ó†?^¬á÷{«!¡I¹Û·œáŸñ8ôCC/M*Î^ÚÖ”2Ì,®‰ùðu½,±¨¬eý¯¢ÂF¸ §Â÷+š(Ì¿´ìÄ™×-§ÕH3wl‰¨ dZn§>#s7‚[tœT&, ×ÚÂujvDÜæüã§E3|ý< Â+r[¿q½®¼OÜ«ý /ÉðãþÆÌÖ~C2ÈͬHÔœ¶Äh;Èô•’Û/·”n¥6®v/rÑIˆÀ¯Êc„mï0ÀlÝŽ] d r$mélh/ÿQÞË,>?í èõû+… ´Ì™{YöîÔ…Ñt•p§Ù‹‰´ðë­+NU¯acݨ_|¼IowÚÜêÍÕ ÖQó¢Ò0>:S–‚&ÓgeÛHƒ’ã@!oqûb(O"ÓyìÜq¯æg‹¦>• ¦ï)Gpçå3ç4¯å1úÇš,#ñT9Ô¸-j4rÔ ò«™6ätIÀbaÆŸg ùŸº°|Lˆ]Ì!µ1ÄÓ.ǃ‚ì2ÇÇ…BS‡ÁÕ°V+u'|ÚSžÞÜ5)ýîTLoÒ4©Ðòxš‰}û‚×Û-O†Äåƒw(U1m+rIÀ©KŸ¬jœy¿„]š~,d'aøZäH–vMg>B-Ö7 œÖ³,ÈVÜdZd˜ŽÍ(•x´všÙƒÏÝäÂï/Í= =aÇŽüÒ€\íåÁ'SAÂ6nQÏ2ä`—/ø°]iõ_48*n²øáÙ†gž4¹R̶ÿv"3+bc'û4y¾ü«DÀþ±òyná]è MôCá¾Z†»ý°Ö«×ŒzLÿ.s»g,á4Ój) J¨^/ Œ=õk_5ü—ãÂR9‰}þ?Ýnx&N‡Áš%ÚôFsSQF›ô2ó J×"T “ ³ºf53ºJ)ì ²XóËØùyìG‡†wNqáòw'/nîúvì yQ!œAM˶±DɺRPe¨v®o; 'mgM-"šœµ¹.9[e½­¹Ê/+°o®!î!ß ÈM³»Ö[ªá×ò"¡?¿¥GÉ7‘F×\w/U³|Êö ,£ñÖœX¨òá“Rt&”gv-†²)bózÃxdG#6ô½;d«@’€€ÔŽZÙjÏ/„ÓMéÃ(Í ±„CØU¯)•UÊnX5€ÊøÂ„ôËŠX;1×F޽%¬SdçŸÒÍàƒAö¯­úщÕ:2ËyŽã )PøÁ„1s¶sªÑ²˜d•©0Ú_ÇÖ³[h:, ÝR}¤«`çÿ}oLšzõw—ââ*KõÂÔO«c•f»¸âŸå\Ö Íþ‚…åÝÈä×›ESJýbå?<ø× ?¶0"Šr·7¢ÕáC6nYÝ™u=Cýã{Ÿ<Ò›x„ï°TJ”'ÿö³åyv ušW»×–ÃÌaMµMxò¬’!ø_áÛ;ƒ`òï_à£=¡ìðD¹R ãZ»¨r*)ôhˆ²ª Áõþn÷¹‰ƒË¯r!FªbáUZEÆëþ†<ƒ‘-ÎSìÚßÙ Õ]&É<À£j¼ñÊuõ:§²s-¥²³I¼ûšV:O­Í¤³›€OˆxŽpZWï–Ó ¢üÍúî˜x­Ì¾ ?a¼áô—ã‚FÐÜ¡¯àŸÊÛ>(aÞ#ƒy8»>ù"oTe?£WN4TÉå-fWßãë¾Ñ„¶¯Ðka "ø¾ZI.ÂêIŠR™ÌUóî[þ·áí°;¥U‰U¨¯µ4SYö›\p”²!™4‹]7RXÞæòè¡ü$¢f*¬äfŒx¹´¬/*/W Iáþ¥܃¡ãÏù]|Œ;Ùfejó×ÿ±œ¡Ü2äǬ! 7eõÓÀQ²V!‹z+ǘŠÁ5Eª€æ Lï äC/*Û§ŠUæEyoYQqvÓvWöO;¼–µm¼Gp@Ïÿß"c" 2ÐIý“1l£áź¹oŒnÇë³3ÆzÁ™V¢qz‚’€€Öݦ¸>|Ü-Þ¬ÀvÁCÐ׿—çò¼Ë£ ØÏ€SÀy¢8`¿¯?¿òkè6g¥¥™åøt¶G³©ÌDƒ*S KÛG¤¡÷<~ДSo¨M$â¶¾ya©ûðHòƒé6;qMK®6R{ßP u๧]"Üúâÿ°„/•e¤d›È>‘A°/i<“Y ¤’i“uYcÓ_º Æ'’™ûAùüóã‡ßNøô¼¡¶Sò[h|‘฼vч9Àáê7;Þ.´Qªì³v4{†KÔ3˜½K»HLû”›ÑxÁŒÜÏ3¹ú‚/â5Ã^¸˜äQÊ7Ó®‘¬•Ÿ© ð8î !ÝçL>ÖÆÞðŽ¡ EÓ›d¥ È61A&ÄÛØ;ŽÖ«zŸ¨  àZbgóÅ/ÍÚZ|qe!Œ3W'³ë÷háyêÞ#¶íªÖ »³ap𭣓ÐîÞ×cÛÛ8¸±ß`AJî.¿†{Ö@7Yyv)òØï¦¤°”qÔ vιÏÕ½K÷™Ì*úûálH3®Ê¼\]¢å{N O㇭®4¤± ®ižõßõ´‹¿»¤—yá NmYcmòrR€&ú,½ïeLñÖÓ\ :GœU¥OÕüpùLš¸¾»—0ße2Žj"‘"ì»d>–¨9Aòbfn!çvYª#F]à1` ;"û=e¸žQ›Bêà¾Ë_E:³·hWì•á§ð)sÝ/Fv•Pk±H¬“¨RßÖâ;ÑH´3¯lpt‘K§„ †éä%«îf{(¢IÒQ-П)¶º¢ÕI™ éÞ´’<ƈ„Ìâ§ÎB¬ôSó#z\¸)Ã!ï¨Ñlzß»fCISµÊÒ¹…zBQåY¡,ErF˜³˜?]ýù¬»gA$8ë`úÑе)K.MìDÜi¢"°-’KWq.5†kmQfúÕ(©»BœPÚS‹®ÀW‡ž„ä÷A‘å4’€€ÂMNäÖ½¯¼|?5‰ï~ò[î]y¿ ˆÛÅBw3fÃm*´Z®aW*& [RäÓVBv ;|yl :ÑÆ@ÚGö÷³•ÀfÙ5äÉÅ–5¯…B5[ ªbW!Ž G#¿0ŠºX?e†Ïø²¯…ø/ÌksZæÞT#DèÖ—ÉGÿp<塚Ðßê=(ÓàÍ~±Sö¨mNñ#{Çè9g UÏE¤ÛÒd»T²6¿†Þ6é²|}Hä¢v+‹R%{”¹t~šc‡Gnb´Ör 8í81ŠÌÆÁÉ!ÜzI¥¸Ñ‰D.=¶†¬´>ĺE«+¡û”eC(^á›gbä]“ñxϱ ,³kÜ༠õR0¨½@'>Œ——Rö]8q¯2 L tÙ±•²rÅ¿g¦`¯>˜ôM¼LËV¨[ˆÐènËG@B„Îc€ßQˆ¶BÕ¼ŒÄ‚771b©~ï„àÞ>鯼Æúý€âsƪ@‰»‹E|½D3}¦a'ýÉ>bö:ÞºÒ7ݲ•.mvpbAúqv¨ÅðõÅ@ý=<³—Ìþc—ÇÉ[öÙãmxlê~úéo½Ë48”ÆPØ„pÄÁÛ˽DéP±·—fMh8"˜£s?,“¢A÷N7{#3hËCgýH‰ÅÓ&†¸‰W83k„rc¾ ÿ‹Ï~<Ú³ðwaouî·®³W[}v3:½QÌ ¦øà±î1ýó¤Sð³EðßÇ/nù=t¤u«!eôlõ«Û±b@ßsê‹‹‰1R,9qwZùÞß Æ"hÍJ—»c(Ý{ ¬ÎIFàQ¹ázªRÞÑ#„2Qp¾érò[Ý_‚þ«2GÓÌiŸ#-—Ò„ Mø«ª4&í˜ýÃÌBc!G{Kóèk§HÀÀ4ýí·iõ–RξŒ„K…Y_á! …‡”ü;”ézðךiÌÔkOÕÚ<ÆBž0Þ;Kͼ2þô’­°ã–•’€€§@¼b‰gE%—Ƙhþ¾íÅ,lÔLq1å—’‘ ÞÜ9Z™0s SZ3¼nÅCCš±D~'öRìÑcšíÑW޶À>Ä~WàŠÔÝf‹7ñ¿¾è¼ ¹vm^&]ó“]ôŒúhD¡3žp¥T;„Qw9s£3ö¦pnz"í<öæ›u§í¿çý„Œ¬-/ïƒÿ4Ó@»à ÕéƒÑ0ØÿIÃO_}Jåõê/ŸÍƒ¥€½$ܹ&NpašgÀ{@Ò1[º"oÿtÉÔ€.|ÝUƒ‹ x›ÎäŠ| )/ øǨÈõ|[js‡Ï8më,zKÌòÛ õ)Ë s¬­NŽŽu†¨µhÑ:+ð¢Ó¼ó5pëˆÀи_H-~Oi‰t‘rù=Þš7:M{7ÌŠ°Î‹4|š²zÝÅÀ‚[ åÕè<©oÝýס…2aU¿A‰Mi¸"5«äÕC¬þEù¬-M\³ÌG #?í§<÷–‡Œ§\<®âÃJYÏþà3÷’H)cO©´´–nä++éªóÈêë;kÈ*öðúG³;!`½ß#¬ÁùºØsÖòú i<¸›]%´³ÜÜük>ö¦…þë´´Àcˆ¹6 ¢ES[7¨û«+ìÆ_"Ò¤XVÈ6 kŠº1Îñ8ÌÉT²—ƪòí§º A½ˆ•ÖÁ·&Pº¢Ì#‰¢;ìPžîV2¿º’o16¼u\VĹå¢OÁáÿ”ÜLÛ«jψÍ.EÙ÷ÅÕàj’€€§~O£}R¨ ÔùF‚¾ÖÕwoä³ßΡ¨ #ÝLu4Èz·Ç@¬ØhÑ*˜£#j¡ñ{y€8Rc%z‹ç%nè4¬KA|Jñ¾†¤y»{RÙ;±:0^íb®Ý©Œ…ºîoÌ:ƒ¦¤Z–4VŸ_ÓÆJõ±aƈðÁÛ 9Ç*ðç4äG—0JlL:‚÷—+i§¥Ňµ°ÝL Ìnù%:;ªÚ œ¤9÷s€þæ¨êðñ‡uCAŽ9×úŽà#±Ò_…F¦Í$³¤z.mÎþôÈÎ̾òȹ+y×Þv×'nMB¯Hë¶z‚ñÔÉÃ%ye}ºë%ºepŒÉ”H÷úYH•Ðóõ5ã ±æùõ7>ÈÇÁET$Ö8•3qoïÍn[èÕ¤Üh‚ƒè‚fЍÀÒcÍ~ËJÙ¿žÒ…ÿË1`|Õ‰PYìܸW±ÊÃYTšÓA{F#(Ý3É<òe»X2$Nû¸[‡ËõA©|u HTU¢^aÏ¡D,áÚ]6+¾ÞØø°fJ!&¿¶öÐQ±&³$E]š³©ÕOø]þ0‡:Ä×h7¹Öe^rb[šóD@‰¢¤ÎÚÖ>SÝñm‚­ˆºÿ±Î!H€³QÏÃR¾>NðZU¥8Å)ÏybMvy±Õ¡Ô1šaCòhñŠ`æ·“CŠ °y%p6Èо8ÞP@jáŽNRê'/5øÑ÷„A ,22âMLÄzÑŸ”a^Ý·2ž# ö@TÅÊ¢SÁ¼òc>¿Îrúãr?ê[Â_~GHA7È ¹–kú»oÉâàÈC£L W Ϋ^>Òt‘ºPùmj-¸•ƒK»=ÖÑOK1Ó©n†Žë,.'¨¯Ò39Øk%•e¶94áÊðå5ÃqúÔº`èh­q¦!æÌ[§ÈHˆ¹©5êénÍØ^áÕëØÞRûmŠáWQ’ÅxTómeHÑÊM­lù 4I8ð¬îLÂÂ=¬_^Ó!Ÿ€SbA(y³ÎcÅãLeQ4©ÖÍCÐ#^ùjä-Ø óØÏÞ ýÝØ€¬3P4kIKu“ð„¹HDéB?îkº¼q*T¤8CàAq€d³Èb¢ $œ©Y‘ ´{Q¤.6DPð‰/ß»í¬ùîæž«‚¨æ’€€§S1–RiÙ7«ÍQ0W»"q¾ÙÚ‡3„âÚEløÓVP[±L$kîÍôÑ.A ¢õÛÊ5s¸zaB>_þ£M-JŽìØÝƒâ<«U+=H#Õ† <ú·9ü¯€6Ј#Sï'ÿ™Y±t3úu}0SFZn"JàS0øÎ!CT)Ðê8X¨ð’Ÿ%¦ÜŽ_ÛƒžÝC>èÒVTÝÃÁÖÜ÷ª¹ÔÜdµÊÒbÉyâ)Od+%Òg››©Ml¾{M @XÀPÊür"ÔNA+øZÌXYª$/M$± ±™eõÞð‹a¼õIƒsºmdþrñ€GבG©ÞlaÚ•â– “K ØóG4„|BøCÞXO !™Áád .Ó#'n`¦‡þ€E…™#¿±%²Ž•àlÈ8ç=Â*ªÅ xåÞÛLÖY(røMOϵ¸ˆ5sþD—yÜ2ì¼¥s“·K¡–N뇔m}ì+Ö†Ô:ðÂ1%¥¶=üÕ}⸭Òð^áôvžò—ægëv5ZY¹îiq—«¥ëÀw½äâusvJ´ªrŒ"œØ±÷- ì5ç]öÃ÷F†Ý< §¬|:rÕ1xá±²O4z©øE^U+A¡ßØ*yùZj·¿j8™ôÒ›¸¤:²!´cÎÙYCæaÓ [cÓ·é?„4ã¾QÌ[$ŒÄ‰)ž‹íñ2îQ7AÝóé9 }‰ój¤w¡êB <$˜+ðˆ®S5ýT,ÿz«Ææ[“—лÒòoµ11”&ðöt†@&ãΗ<²kÐôm¤X4ïÏÅ[ò+ÍØÂ?æ÷@SñŽú¯4ë¬ Ï–Áù¤Ê¨b09xÄY ý %·‘GXö8ïµ2 éÏu÷-©#‹Ä†¤¡"•ù“væKÜiÀ†¥À›f ó§XÒ^™í#H–iÀT43,‰]‰¦ð˜yÛâíVqÚGà Ž3ëÿ¯8˜Ñ;`àb5üŽ“#^]3åñ¯tn]ð½‡òRÒ}X@*>Waí¸î˪“)w‡ïUj½ÕNw~qË£`bmòª1¾ml>‹o÷ù¾ÝàTuá-¤÷ãñùŒc=IT{[S%ÙdϵL;x[¢È@ŒFB^ õËàE6ˆ z*¥}ÅØc'ì¶% ,-sÃ%džâõ›ñÏËnÙœís;²=F<´ÒLª«>•z›~5Ý \ˆÂÕæ¸?’€€»_vuê›oMMÈêi‚ö^ï¥2ѹNÔ®c©`dï¢#Eï‡Vç-9Œ¸÷àů8Àò t†ǘ†~î3ŠƒBa®eµÝœµºuª¹Ó»Þ¯² Ð&½,m%Å· ˆåw]B>¯dîãÀ.‘õ‰Î·^if¢´È Û7׿w»qõ=`SUäÜ‘¦ýsÌžü”‹3z.)°ë¤ZaJE¶°>d”ÓД9Ž8ûÿÝgföǹïœËýF­]Ò¶‹¹XÁ«ÿyÜm•·y¬Cuø¼‡È]ʰ·ÆÙÛ&Äúö”tR:å½Âˆ|YˆðC·unßša ùÅ©OŽRj÷y„.ʈð¬ ÅÁ†˜J†Æü§F Ü,f'–nbµW‰QøWï…-LM«¾r£íö‰z£_8Ò {B-–âfk : –¹‰R.j"u¤Ñ¨}9c}A+ñi[¸0 £–ҟ¾BFfÄ#Ð)žåý¥×føÙ€‡É°ð¢*·]Ï÷9¥÷—ª AÐÙ®µJ„;¸%:F‡(2Š\ºÍÍëƒýæí%{/´øž¼‹Põäa¤,hqrÎ(¹ùú¼[”n/þ¨Ç y) ê)¸Nc…õý®-^ ©òÏ+í¼ÁÃèë$Sè¡VÎÁÞÕ!š—ÝÔ1ÉIçL?ˆ]»£Á‘ûOúîºn¼¦Ïº‘ºåÃÑìÆ‰„.Žpê†<9?ì?~4Ÿê–4î2÷<æõ[HdDÐ'úžÝøSÕQÞ®TÈýÝTw‹¸ô­Ò§~9×.”ºíÉ¿Êu³å2mîÖô¼&C¹g€ººYJæéÏbK&º²µ„®ÂŸŽÀ5–šLÒ <úù%JijRp®¸Ý‘{²V ‰ð¨Ùâ‰ðiŽ þB _Ͱ;lÍ›R6•z»[é,tºp’~3æöÚjàÛu‰EO/ö›¿U_õR­ùí^­€ã†a]Ÿ,Ö%(™²#ð¨Í±[ÝQðÄ›oåoñ6Q!Ê}á*ÚÁ|‘œXϲ‹êÕÓºru¼u.22J$Cˆ-ú)˜Ûä9'ú… n´÷Žkª“×eß":¥wȵ-ìÜ&ðµå³×úgKèúÂzÀðÀý“×@ºK¢J†ïaÔMs -¼ ïGšX'1Ì¡¹u²¹’€€À拪&<2'‘eaÇKYݨîÀÉôMRÁ;bš$­xÚ3ÿ!®Bt{haæV¬¹·ý¥"'E¡y&Óc]¶ÖhyC_»Ðp{<¬ë>¡·ì\Bo­e ªd ߯/™ÌÒßÔ‰ñC]ÁàMcvzñÂQƒÐX$ÓYH#Þ”± KÁàIêFg NÞH3üÞo£ŠÞúYxë]òn_, cÆQeñR“¿ ðÙèÀ·Ë %ì÷¾:.χCêizg¾BŸ¡E’78>%¤ZÝù&]û¾ÑåÓÔ[4#Êb‘ó§øïQƇQÊù­RœhŽO¾IåM=7䪿¡¹Œ˜”¬í ð2WøÀè*O*  Šc‰©Á¬!4ÁBêQ9öf|ÝñsO»)ÁG|$œTé•aM/ÐãÒÎâöÖÃJ>óÄM¦ó\æÜAàÚCÀ‰€z-R'å€g´èÿ³ÅHÃn矗û~yY,¯‹MŽf®ø…üÀÛ¤ Ö!Ümn¼iä­òWD®hîýF•«0yÏ Ÿ?H-,!À<·Py`s/*§Ü6I`¨·:äÕ›ŸýAqæ¯|¥¿d.ë¶zÞU"lèóâx½±‘_o©b "<­ènd¡™ÂE$$ò@ÁŸm²¬îAi0wC&Ÿ­.Š:Í‹GÃ<Ãq÷Æ‘¼ƒ,€›#RCbÁà6Ûkq}êüÂô˜üL§he’öcJUð‡yFd=éYZë×],éï3á;Ö“™–ÐNrÏß. œtÔ1ä)F¤óôù3ë tȸÉjùG\Ù;Ÿ-¤{jX“¼FŽ 9G·‚he©óÏZh_¥qÇM¯H¬7ˆv]"osºc¤qKã[yàJ¬ª/X"Õúôr5º‡ã ž–~€T‹ŠÐzLÌ,z-³®ðt¡»ö—$ã/x„Ñ!.Ð0Ôñ°3 ÌÌhIÀÔCýƾXû¨úK[;ŒºpºûcÑxúïöÈ`gkX{/*cÖüZç}óëÅÑc®(ÄëI˜Ö1pvêxÖôrÕÁ­»gJ¸!,ÒZäýƾàÉ ŽîV7kÍ}c\’ýür \f|µ'yCw¬‡£¯ h–Xs”X5™Œpb;&ýn^3;Ê ïë°ÁË2.‚p{©¨óÕ÷æµ™s·÷ó’€€¹*)ö„¡Ä4PnB“5ó½Ù°\{#Ã^9"JäòÂuÉA|õ4zMx–¢Ã!”âôöÞ8y’°ª‘´PaÞü/$©·ÉW×íÔ3 Ø \î·ƒe̱Ʉ„lžšuº‰ïVQ*AE!ÐÖû.Ô“vÉ€¿ÄS0p²wì][¢£7?RÓ~í%9(¹Ç¡eyp7t¡ã臓ŠúôñÈú(õ“K™„äÁWœÚìo¬KMãqÊÂTÕhs‡è±´¹–w€‚[}IT½‰ÕKjFĦnÒ2”aåÝ"jóå‹*ëeÊ+ŒI›¥éÏ6çˆ]ëîåñæ9N,2–dѽê n(’¤¿ž/ÆüBïAf戮ZcoóN]B >לÙª+©ñ¢ç”›ÚÀÈêF056xvÛ5õê`` .b•ëöé{Z`£¨ÆÚëVøþdÇÿ1sÍŒ\ CÛó6ôðž×üeP?fà Ë7åÉO0§¿QôÀWDýýF¨“$Vå>‘8¼têÂIÆ"†NvDâ‰?Í•GÝG#>rµT· Îÿäß"þÅÖµV"ó›†C ËÔeP/Wº™ª$îÆÙMTÞI¢HjÜë!÷¶÷ž« Z×këþ„ª†þ¼¥Ÿtäõ[˜—óÞ¡„sñy¥+àp¥ww›…› …_Û¯„<€ J¨2bdè€Á2­¦Ý­ˆ¯I¢;Fc¼‹Æö«Qè®Ì&Õ5<ûàÀ ‹G[=ŠqôÁ¾+O)¥<Ä8rs{üeEnÎ#Î;ÌÅ^y0.y¤§Xs{-…z*—=yé+|ÏM –k˿Ӊ§©œâ`×…±õEI PÉÕç,ýp` ùøoHúTøró¦œM”„ÛæGüc@mG'm4%E ŽŠã;ò5pÆ~Q‰¤o¿¹è¨¿]|Àá7Ù• ¡ýÑb?²oFzõ>'ˆ`3zZĹ2^C- €K³æ0àíÚðsvv¥¬“2o<¡—Ô7ô+¢åjíÁJœ6øiì† Ïgû,|ºy‡Úí’}—曋kƺ¹•¿ôßd|øß«t¬­ðoyDtµ´ý™s©aš~Cøp 4³'´9øWoЬù¹™ódZ š@Ç€·:\8=‡ªæœs€ïÝÜŠMþ)óýs’€€¥4©cüYãÀØ€“i²¹9¿6Z>€êe³ÍÂð8ŠH׸ëâèy³ƒ&ÕêàÏvcÌ_ü­ÓÐ܉ÏÂävlwŒ}ªåÇò8iGÂ' ³_j‘žËW·Þ ó å¸ÀsÓ`¡Ùµ‘\¯]PE(eª2+Ðá5øM­ö ¬™G‹ßyó\§dKíf<»HIšÎVNûQ#i< ¯f’YÐN[b·pne:œíwë:^øÂ‚„1ðò’™MÌ‹gº«óø GNÖôxyò ô5áPõ5(Dkf®¡Æjùh¹Ê…ÚˆýÀ •õ9†ýDYÞ·ÿ Èü}M†6ÔȆå±%e)hd4íÀIïÛóH%ÃÚ`•IeCø”/õñN¬µ%é4´a‰˜í7íµ*…ߤ†´ooƒ.¡ÍløßêFi.ÓalÏûÿ.¦¥Çì£O† ²¢q”4£×ð[xÉ×~•+ƒ#(>«$<[Ñ*ß<†vÚ@Š/½(ût6·9ŽÚ¾»«‘ÞÜWní+ êoþxv?ÃEä£uh`%Ü…™ }w`ð‹ra]ï%½h sEï#rz-@ÇÄCú ñÒñE._ êc!ùP!V3ëy‰É¾Eþ‚û{øÍ†¨&Mc—úKÆ ôÎîKÌÇÞâ¨*Ò]¹ï ^É÷²Òf7ð +¸¶õëJgÆÜÎ]Qƒ…Œ/ŠF<Ò`V_W4=ÎoçTUn*_º½L‘º±ûÛŠˆ§þ<½ß,«:$‡ˆÈ~k¶?IOíßc•}«Æ~íb,Ö£Ù)†•Ð,‰.µÕÂ\ržvWx±¦ŒßøˆÔT2G>È){U^·–«^ ý¢)N5ßÍîÑ›-ÒçÈŸ÷0àÿžx먺n³%~˜Î½ö$é=û”‹-¡w_8ibK½˜"IzÈGß!¥’v_l*šŽ{¾¨ù$wt©Ä,¸Aª`[D#\Þ!«Ä_ŒíÖnÁ†  êÙ§ú¦Ãö<5Ú¢yóù‹LÜÀI_--ˆÈ+×¼ØLç]¦šRF±ã§j$/u Ä2¦ÊùìèEïÔ˜¨åeé"õ²–:ð‘û´º’€€šøT"m—‚”ÎX†ÃÌ5.=¤ÞhôòlfW¼±?3fW±ÐÖ÷q4Fi?]"8qÏ—F–¸ˆ½ëÿ'ÞoÜTîLᙫŒ}£›˜béçz’Ù‰Y ]¬ÐF£d)–µ@Ôrì¡“%²N¤ä®q[üú‰ ˜RT•š³GÄ×´…Ùî9;°;e1ÔJ¢ñ¡ž(i¼„egOò?Uæçíñ½lÑÜ8()[högô¨>ü<ˆ¶þƒÓø‰ lâx¸^ @XÏ‚‹çÂ÷y¯j*h0bçÑ|í-‹ÆDí =Þs™¡ÿ©WNÍ‹~n€éJͪZ…l#¹•9õ“ŒîBn;‹qëoâBkÁÀ® íÈØ \Fª©­O.Qõ5†˜É þ¬Ê«dˆVTv– îU+YßM£šŠí¢òèQÀ¥ýÒйñ ç¢:£xcè€èIÍmتr/[¤£²ö92q0*q**E†zs¹¹˜·¢¾»§dåå÷¼°ŽJ…¤÷y¢V{ïìEì‚éF¥÷ ZMƪeªB¤dq}Þ5éö^ÕÊQqâûÈÇï4-ù—ÀþÀ^}?Šçw'é©(1ÙÎü·ezr#UT|Q ûòh çZLk wã}FD‰ªß·É×7q\ ž.´©ú¡µ‚8—˜¿\t¤N´,Ú6ÙMxÏ’§‡*÷¦”>à¸ÕJ)¬?²fÑdÓÝ*F’DŒ]Û)Yäë÷7Cp#²JÎåõkor RÁ!>·’€€½ûtâ_äKEo=š-ûC¼+€Q&ÝR{QgIš–µI¸À OÞÂdÿwi9•BúK®y÷§å@&:÷HÕëÕ´Ü‘I¶‰“Ø+¬vÍR_œµ’¢ËdÞ&§×÷€ l¶¼÷üÖ¨ŽÛTve¹uJ0ŽA5¨G”N{”¤¬8Ôb³rqD‚ϸ–,.‚uÉ¿¢ž+k?óþ.ïصÐT¹¨CºC Êx˜z©åΤ3š=´=€ñTDTŠ¢‡ °ô¤y£»‡iáÑίEèæÛ)Sˆ4fý}öÎ-Ð;š›Šåß w|-áWŠd#ºl*s{FºeÀÛ+Ùh2Ø ý¨NšS£r>¬Ÿ$ ÄÿœQ"qk‚¼#ÂKÙ½¢ÈJìÍÎ?AVø)Içs¬ºÞ61üù)WTe5â! rÜ ÓX—Q¥jæ±¥ïŸœÝ !QÓE Õ/„i£ ZÒlã¦Y0´kôðXiÅÃT$. ÿÅs;£gëØ;3k_8W¤z£Š˜ðßlÅô½&šiìàäw7I §ô‰œ+õ·Uµà3™ÓµìXÖj¢K3Ø=íyÏKë}®¡,3˜ü!9pßâåÃK`ï`Þ¤¿(ú¸¤yúØy¶2€9Ñ)XS±÷±M,Á¾lÂðÔ À´­ÊR€‘Háèù}Áà’€€ÓÀ?·ÝÕÀ/À†×N…E þ«0,¼=Âem-C].àèŸÂ6g®íǯ´™+DŒ—8¶Ü¥Ìvùªô–›‚™£gCÞžyïÉ?f¾G#,à¡{EO<<ŒhQW<¯Žx÷G$yãŸÈAÕNý góÊ{f&†áÅ*N̲A–eï™u.1_ú¤Ã¯Â`vR“ðìJC}ˆ»ÆsE3ßP àãH@9 }ðOâóC5Öû…’•ÎÿwJn™“ †Bн {h©’€€ŸæíÐË2^ZDÖÔH§1l –é¨Ó€ÄÍ%ê”?ÿ†á©`c?òx/¹t†?H\Ó]ȃæμh¨SiOk¦P QÓ'îâ‰l5ÖbÀSq¸]rJ=ÀgºÕk@ÔÍå1}Ô™³¸‡ 0È3v‚ºZéïíìµpnõe‰u'NïŽ45³,k,E‹ÃWWòÁT±/¦ÆÐ ŤQ=›ƒÝ# Ëÿªñ8[îüld°‹qÂzÕz;›ô…MãÈJ|^bvj­FËr$Ûwæ÷ûpÏ.«¯w·fË® Æë‹h:ÓL6À‡–uiCÙ15÷=ˆH_@\+­^ŠîÞB úÔ‰¯±TQ‹ûßÈÄÍ#N¡CVŸp‘·ñ髨`ˆaå„ÜÝ3Æ ¶-žÞ‹uYlÎQ/ϽdR"ŸÜQ Ü¼ÄUAVlÝ;f½nÈDâi>·yëàƒ°ÔÜWj:^ аi”én64˜¿rÐ$³iÁ}}Žy£EžûR%|o\¶‡Ëk’€€½¤Y­CŠÑ½Fœ]FBcy/qÍ“Ý-¼ç¤‚¶ûs_+ >‘.cé§Äç™åÌZGv.iZ·Ô×ÿ˜ÎCmÄé#þ/´û¦õÞ.Wö·“r¬Ì­ûT¡Ei³ÏIgmV;&;ôüµÝŒ-^œì¦®ÓõÌ.­sùš ÝÌ[™hØÿ8€8†ªì–¹y6Ř½ëÅ‹Q¯uñ§Ü¤™0t£› Œ¯}¶pǬdÝt’‹­J-BliùÃÚåøî¤î÷Ï;jsd'Q|Ha¤ }3m~É‚îLèQßù{ÚrXÝà¤Æq9œÖíä—›)}ø5ÑÓM~Òÿ×X·ª–lýQi{|e¡¦áÚ‘o7õÙÖÑ*M£ýŸf7/ýë|gwÀ‹#¢Ì)¥ßµÇ7Ñ}ç}iÿÒÛ3ÌIr! îÅ6'êƒÔ¤yq²î_–Áɱc9åÁ/¡)$ƒ»×õ:‘“ÕŠ›jï<7”uJÁß=HBi¯šUä›|ÅpOEÑX¼/ÙÕÔ+åptÏè‘Q›Z½t²\êp:f¹"*[Ž{Å¿°”•ú-`c§´Ên¹ŒÔöLNÐÍaK;CÄ(½GpíýÙkéò¬žNw­“×>ßÏŒ<Ý"íÔ‹sk#›2÷ƒä3BšO)A…'3]!¶VÔ·²‘§¹,Åø"õÓ!ë¿ÀÆ*ûI¿Ürp™ó;¦H!›ú]˜v~¯I‹n«Adºp'|ç¶`:ÁšÛÉ,'aÚ]—xP…‘2æ1ýWèᦲ\8>qs»&X¢ÝL¾uü‰¯v"ê?•^ O8e½)XlæÊlN„?3ákàtüåïaêÉŠ~o¾j…[~¨¶ƒD †÷ Æ\ß‚¬@Õ» DÙ®.\o Ž•i–'=K#¹<¦”ï"æÊ-¢r óy7`ÛEž¦1ûŒjn€¸šýx ïÆŽ]c-T~Ÿ¦ ´f€(ˆ¯z/hž Eñ–j<ž­ôÕõüüÆß§Î$¿É÷Ü,Xï‘F‰Q¥‚žÚkÄT\ÔÕzƒ(x\N„Èe9–•ê„àݤ sÅÓö;ÛÈ1 PÛOÐ]‹q]‹†-Zp–_ìÉ‹Ý÷Hìkúéê·KÙx4'Ç o+‡&õ¥¨êø‡»‘H,/9Ql`1¸óÎ’€€¸"=hÐ ÖÏ೬Îö ˆÕ’%W;ËÆÓ¶Õž`´M-±ü¦X@×RÂD.Ê3ÇÈ£Á"§ÈZTç`ÛDê¤øBŒ¿“æà]x¯úò°‚ùê"JÿTWäöÜŒÈÑù-T"C‘6ì’.¶¼,äLú%\³Ï¹Å3Ëâv}h Û Åñ•ŽÁ•H;!jú½Y†åŸžQTé±j~*hp7&0ÀD­AY0ˆ4PˆÑ›œÔ§v”³®Yl±½_ ¿šÙJZîŽå|îj9)dðäI÷;ÆŒþƒL˜È…¹`ø‚ÁÖ7£¨ãú‹?e܉B×§éðdÔ ö‡êƒ÷”.4® ¤K¬sÔvµÁeÁÜŸ<3¤øY‹i{:¤ ZgÔ,\ßí¢rÝ|ëâˆS‰üe’¬Ê ËñŠ«NèÏ”qùí¿­èu°ƒMĦãgÎÛÊ&Q.9¿8þ:@® À.-Pß=âü+  "óXnb Ôb˜ƒèùÈ`^œ/,nPŒmå^¾…µ4izdV”’æ2xÙ$ÐóÈ< "ÍÎÕmçÒWÄ%ýpMÚãúÙ¸Ö>%&2u2^d¡.Ncï,dÊiÇkti¦çQ36aAáKׇ_Àò›X—v#Â|p†ÜMú#8±ìe¸J0Pº¡-£BÔÏô÷™ÔŽX,›Ð%'ÀèŒç°þÀ¿îÏ`šuĶ ‰©ö+- –†ôÌÄÅ’€€à¬o´\Û=9ñjx±Až´PLj]¬«ìŒóˆ¸yÈ]ŸO1ò‘Ìóç>vã!‘CMÈníðš•oà W$%?OŒÿ„†Úí_߀-! þ •ëí¦\ÑŒ m|`ehrjMþœ¶C… ×wÂ,Ë×"%ò“†&ëp5(mžÚR.Ïöàkµ‘QHWˉӂ³šeÝ~ …R_£¿Í•Csd£0-[´}¸êðÛ0Ö7Ó[×&×–Þèü ²ÙÏj £tgÂ4]²¢þäVw|W§e[ÞïƒìŒÃ*Ụ±$â[b£Lwe̽€®e˜ í‚/p™½+Ƕ¤+‘CˆÁ¡Cˆ´^ŒZšQuì ¢B±¢ëŠˆõé ÉcjAô&—Ùøâ›,Ñæ^±/ œ?9ÝaO*¬ÊãßÓb”AÀþ—ënáù k8 ÂÁfg¸‚¤áÞŸ?âÕGžƒwÌàÅ£¯q†Î2À4®Ê‡až„Eî+Mý¾íÐðÆ4Òw¹‹ ÕJdU¼^­Ï4‡3y‹‰½âQÚºŠö]ç<–Byñ8ÜS' jvèf‹þ“5=D$ãþ7Ë/æð¯óª2 ÞgE‡A9ž>êWok§Ïö39º'ì}§£º -Z´‚qzÍíelL@×mŠtv»ì..yùö(u‚]Õ÷/ütñ2µpµX„GÚ¢Ö¼§ÂðËÜÑq=RåNRÒœ‡#Í-“òS¯8s£™;ŽA}ºâiù¬·ÛÛO8Êá²:Ojï´í„b{ÞÑä0²7¤fø_Må;þî´+à6€¦• íÍ ã»Fo÷Öm߀@#øÆÁ傎›)’ ,&źzÄ1Ö^tz˜=~¹Uüòü›lÛ]#±Ú8vüôGŽ>U³NÈ1ÏÚ3„i·eTl{-EÀ9R“‘¶Ëþ'h¥3Å€€|©pû¬ª§Û%°Ü 5ÑhRz¹s„,®ßÑEŠ»jcCåÿß׋5q^ÈÙÝqëCª$û*¸À_½ºÑ™MG@ç÷€6ÖîÌ=þZñ’úø¢dÅÛñE@ÛÄ¡ŸËª6‰°ÄQTáÃ0[üÑ œÛ3 ™—9f· z &›ë{¸ÅÇžWj+H³Óªn•Ñ”èõþºÈ_ %Íp‰Ñ#æò}ÑtÂ(}"f’€€ª’ïY²qb£îy»¯lÁ„*¼-2«ZœkPÛjžoÆ_@ o?7̹h;ûÆ)ÀÝ,#õpýs˜Ïê¨N׿mDeý~™¯v„PÛ\iíŒþ%ýcx–tŒñk}n ‡<%y6d!)YÐÀÜJÊ8!»©ôW“•O‚»¶Q=éÈÁ[·ÄBõ:MlV–¤ qü¼Ö<Ùñ’“Væ¯ásïÙ©.R}ƒˆ£×²!wßµ×Àâ »¥ö]釯€tûÌ/}¹t„ÎÅîäZÝH˜?q 9«’oõç-ûL—Šk:z‹õŸ2pÝÝåÍ%—cx!Mó.Û+yT¶é$ˆ Ò±t;CrÞ{úÜÒ3AÞ…¨à†m¾îpwÔ¡ýŠ 9œwyv´¤Fì€JècÉÆMKæR½nĵ¿@×iÐË»Âí2ׯSóŸgs᮫Òÿ´LK\–t\‡sö§Ô@:®©³ogÒ –íõrÏã‰Uë.[À—´ ®cTÈwvåøYë‹ô èѱq Œ7›…h vŒUô/ú÷’P¤q]‡¿dL:ÙAûÀÉŠ($â­LSMÎ/S•)Q”úK´ÿïÁ[Š r fûÿ«éó™n‰F <8 zÂé5Y–úƒ¢uÅÜ%0É POW2òV©o°”çF‰ùñÒŸðA•~Ï]ã!R¥öIñ‘pT¦Õw¶Hã3Üñˆüš \õK»ñÚý¨Ìª/І;aÇbŠÈmÏ0¥“MžT¾Šoƒ`özî xX?Y±?òóœ4‹# IVAƒ#r‡4¸©•vÏÆZç!`âð;â#mä‰ò—2qDZ&9¹Æ! á d`qYT³á…Sb[¹šÄÿL]¶e=0]‘%ÂÈÒ– …iàŒqÚYuøÄú ­Ñ¬~JþØÍMÖÜï… üfd3ØœÀ¶÷°9/Œì–ȱ1>rŽO~þ {Ð>*Š5N®Hù«’~»)®«qèù)°¢ ´‰ì% „ùQÀaZ¥Q“2î%=Í© QÃ!ÄÜËj±ïœkÞؼ䉎ÖÛRZ:ádjIyÞØ?ÝÀð1Ëð—ZÁÖÑcyb>ÓE[¾’zÇʾUêm‘ Ž>$¨’€€›Ó=¯ÏküOãÝ|DÀ% Pé\·÷>m>òŽpÞÙòÛŠcSŒÀè*x­;½*2Fa`Vø“—³Q½*U±;ƒ.y+ÊÇšØvOû‰ŠjIïŠeÝǯ§v…MŽ6âhL’7Kç•„Um÷(ÓÁP°Óá4+»8l…˜î”ÎÙ>cH2>A¹Š2[po2"Ô/Yš^ÌSR覉ߘ’ºT޽Ʉ†N5'A *M™ËVöþ[f¼Wû¼Ó½~†03ûг$Ô8¶É€P0‹ùïÄZœW/÷¢¶¨èg_ÀN°Ê.% -¬B†wÖZºëÆ<®K³;ˆ!TK×buÏŒÿ/ãIgÁß2qÒ•+uä{thÃ#¥ ÝUE’½ôNAÁËL¹™­ß÷~Z‡²› S T ¦0^2Ÿ#Y%Þ¾¶+ù­^¦ÙXÂ4þZI9³«çgÙ[®§ šàó¨9Àª<6Ⱥ1B¹Îaõ11Œj²vªÆÅw™Sø5þsÝäŒÊºá%˜ëž¬iÊCúùÎ#ÞΣXéÉNûUŸQÐ="øžôÏ?ï]^ÙÍð‰†)½™”mâ¯nÀ…Öâ0ßÅóËo÷‚÷([ØÙ¶’-ÝÙ]0'€F³AQ4ö`zOU“;xaŠ\&~†"1¶¤ÓKiåËwK'5Œ@ŽLd†öƯ²¹ïŠ<)EÇfí<:zóÚÎPMëàÉíE–óSt“9í¾ØÔ͉ËÄG$ë0¦FÕÏ“Ûr<½ó˃rUi÷]%n¤d¶i,zaHß ù朵 þ.Sa]éé~|>šÄý ¨SK&¾û Ä(QÉ,¢¹×ÛNðeÌ8ýèpç}b¨ì,§?³Ð CZ°›ž€ñi S(LÞ( ’•;EVè‘‘°ƒ7;W|ZHwCþÓ@ÃôZo"%¢ $¥µûðLÂ> *ž”xK¨ªÙ(¹öE´úp˜º ëLøG!Ø4ËÄ’Ï?&Y•ª.¾lh“‰Nžl/(@(ÕçK\+dHhÅk6¬’»(}$eY¥ƒÚ¸›„Z[ÉLþ¢yNèüÅK†As tØ öðéƒÃ²^k†q»ñÉ”ÎqÙW1и‹xDVQ­º®Tý ÊýƧé·Ã9oÈ;.™+Ê·0e6ü8ä{ÜJrÜš³áýó suc×Qh"ÂPxAÙ¦—3mAÞFp•Ř=Šì ËÚ¼ Y.âìa4>Iof½®¡Z\‘òŽü&ÈÃ[qùç XŽ# xÇVt™âësƒ9#UÈV¢Î«gI3g# ”z…™AOØ”Èz":Å϶†‰´‡n!1²'~:§´h#›]O 'üÑš¨•Ž* ’ÍTæQã^›z‰vD{Ó’‹Sž+kË6àßöVHtTõ¦é¦8Wp¨À±¢X ¸ÉVR(GÞ|J…°é³ÜqU=‡’€€²%RCe]¾ \a¶K?È;à×hèÙ’”¯áÆ„Âj{âöm ÏÌéƒgô) yiq:ö–=ÜuÕà'” Î…‰5w¡À;yö0?=·$vmu鯝Ø7°?ž¹’A›öD„ YCœr—ÛJ]gNwDoï —3z~Z! ¿ý³¬ÙP`‚Î_‚Òd|Ê]ré%5å¼¼ªâ‹E ‰ÿ܆CÌštß•56e•Óš§¤}ˆ«•œm¹¤n …Áup«s¥£”;ÝîÕ°utMöÓ;àûÆ!€bÉG4 4^búðÝØ’Šn¬ÝKÏêÜ>HP¡m&LA¿LT'ÕZ»Ûá¢T—®Î•€.—]jš¼9@×O¥¿c™"z§UsÇQ§¦>]Ñ ;ì‡cw¸6†¡Kˆî•ªún2X^|X:XD…Œ 5ܹp5ÛêŸ9ÕJhKÕÌ8‘)×µ[‚N½<óH—ëÏv/yœ äD¿k°"ñÜLÙ]—MØ §ÿ6Ó+FVh»C;nò†«ô}”¹ÌRYj-9-õ‰ˆ²Ã .Ÿ ¿¼W¿©T8O¡l8¡ßÇt£â¥ð^åRØ%(y`f€O0ÂA¥xèQã$T™²³¢“BõZ81û÷@פhÑD¹Ä[|RgÅ`_Æ\:̹ët¿,ˆfR ç,Ä|øùEYŽQÚÿ%E·~r ª \€|žÃ²y?•*;|V£Æè ±ÅiQ÷FØ’”Ë6…¢žH+ܦYÖHß™ ÑëÐùœôPKÛ¿éD.§/Êã˜ë…7Åød‡Ò¨Âl¦Jnê/b¹Á°wu޶ ŽŽ ¥ÕÒCàËð«è°ÀÕ(žÔïE£çD–%”7e"Ä[ÛɼrÐïÆ‡b8ÉhÏ!ÕÖβ=ïyÀð\{á“C2é±ê–Âß(WÒl¤ܤ^ì~¼sûÖ<‰šÐ n@ ±µXè+£Q[3tN5p6ªU, †'SŸÉ?Û%¶z)xÓÝ íýQ7Êc¨Q‚Û¬Êç‹âÌ´$UÖl$?Vñ<²³šÌÅÑ}e\^,ý$T¿‚.ï?+!3Í3)+ß㤷vs3Nç©ùjú`…G_‰aJ3`È-É-üâRÐtæY+'úéSÁsùÃå˶_€D’€€÷Þ¤÷Ëh@­äå±ÈS˜‰ûúI]ù‹~ÏnbGñ¿9\¾2FQ’¾ Ù³wÔ½òŸ ºLÒèÏçÖÀÔN ÿ‡‹Ñ.Çàõ¾Hßù&y«&© :èE’ü^§óõÃNµš‚Mú*›i³Ro!¯Œ0;™n|¶&S´iªFfþPYø’(ác”Æ#°t+™ðÕ‹?ßÄÐ4^Æ>Ÿ/>oDm¨Õi¼O€9–ü3XÏȆ'w uÇ­€î œOv¡Wë#—}|´1Þ‚‡ªb#ÂñîtHù¢¶©¼a঒I!£$‘íì>ΉҢ’ ù¨S‰ÈRcÊa" ª±í?‚~ú»-åF¥UcÜMüOÁ¿ýpd„i@Èp!Ç‹]Éþó såâ¶„'¯uMU-»šA¢Ám8ȸÓ9!ÿHÛžÃ53,B+ºÿÙî° É ™;€Z£h¬tÖ§JLÀݹ ©»G\ɤøòx‡ÃЧl¬V‰˜ÊZìQZiwi†è«< ­¤Þü×+%-‡3ä ô‚=×ût&T’îd†¥í¢‚wé¶Ûr*…Šu5°YþÀDƒŽñ¿¥šÑŽÃB@vÈšh¸&+9†³"`D{ØÛ‘/]›oŠûÇÎEªy<Çatëëmw³…{œó‹KE»é‰†:ªï…p|¹<žUÁí½’e…0}Y8ÁÓ5ŸoB %ÿwò-ãsp—øv¤ PÌäØƒùòÁñaÕëswÍ~XqJæ³ü‡mU‹ü6þlÕÉÏ òW@©ß_aV<<ÿø¤*„µäÄÍMƒV NÐ,C]Ô#+ê/ÆÙÿ$¦Åé`TëkØaY—b·?Ž{FÌ<:R9yèb¾«Þ.9ÿ‹=·|#»Ø’ÊD§;,ž|_ ëEôô5r­£X!åÍùc`ÑÛraßµ÷(¸ŸwòégY[-­5Ý:Úç0ï^4~¼a§öµ«5§±« o ¿ôKOQÆüdÄë´Gy'Èú7ÝHØg |ö¬~Ý)g¤¸¿åq“ͯŒ©4ä&ÒSe±-ƒ~wNOmù¨z ’€€µÙqsÝœ:êJR§cü›jªÊ¬X¿„ Œ]RP*PSp´ÕíjgWòÔÒý ï®Ñý‘dØ»ÿû\9t”y^»¼ÐùÿÚÑDZ¸wó,^X€úج¡Ó«feOf3?o/ÂïAx>¿—V4ñþÿ#zTÀ2ÙXõÍ$ˆe“:hD[?cÎTë·>×¾ãäìCèHk‡àÈQQ_»°d=ú<(‰¹ñÒÉpæéÌéð¦OÀ[ØOËŒüP“mïlwû†+šÈ¬Î ?‡ÌÑ™y/FÝT)2ç¸s§DØEHáá@;\®<‰óäå °0Ä=áˆ6ìvØ÷òÍï€Æ‡p˜ý*þI#q`޽ #G}l=ò^é[⋆‹§HÐÍÞ¡ºètë— Û#½…麥ï?Ë™°1©W&&pUŸ5Ž×ýZ·8\|æ¢A€c–Ï€ÕPÖ)[S\Ëh¶âdO€Ÿ LŸEÜàFî‰ÎQŸýŠQe71ö¶êÂgNÀ æóq}@¤¨Î-wƒú®_Óœ<ô å0Žl/àLþ ³Y¥Ã+AZå4žÇ\`ÐoÌW•ÁMy*˜™hÐô.¬]T½½©D*bçßfüÀshI‹œšÆä.,¶ÉŸ=º¦ˆŒ_˜øË„É$æÏ•c’‘/¶.ß~éÌÞ9T¢kwA,sÓ ³ ž =¸†ã7Ñ,=õY]cÛ¿fü*£ÿ8ÞÓy&’€€©·?£Àò&j_5UK-;ÂCôœ7Ôt$wµ7¤Ç$]eˆé}@JÙcüÊ42Vxf¬ñŽˆƒt ,VœqU¾ß1§5–á!ˬ†¤: µà¥aËüz¾û¾Ñ"¿w ƒ”›žš ë«K^î1€ßK[pmŠfhØéaYÍBtel,ü,¨IâdßAc–äú¦qö±3MH}ó|‚­[Gb)qè,EæŸl¸¼ KäŸ`™åFr–>¿Ì爿mòMEàü註ë ÖßÍ™|¶¡‰™iç<ŒæØWW¦?“hÕZ¯p\cÆ8÷çÂÖP-$ù×ÚàAÞ\!Wó;–°À·2±' 3Tå õ¤, dlHÂZA}:ñeT9žh—ÿæ\4± ñpÉy¢ü‰¿¸µY°Ža×n´Ïã¤ú%”öXrmŽ8%½êA`Sû_±ÞŒˆ÷å,¥JŠÀ"±Ç9îd\w¶:ø'u•¸’xKRB„’ž)»CÔú´ß»AR|›#©Ós:ãøug:ãnÀ€ÌK°Å*MyGÄ7TÆ Œé²ÖJæ}HU“{©Ëßéã=©H–q§F_jL‰†q~ÕêÏ“Oí·˜èÿvøTf‰·‰ž_ßÊZ Ë"Zp‚eßn8o¸nIA„à†äÁ‘í ‘PñÿLCÃ!¶ÔI"o *û$`Gàˆo4øÑ‡`Dçà(q¢ÇÊÔ¤ùó ÇŠxAÑŸVR¦Dþ†Ä†ÉàioB@Kø¥„4ªÖd  ƒ—ƒÀAÈF™Ý£0vA !‡M{Ûo[Mž;¸xûÁwó y±ç”*iÊ‹U;@ªnÑ £jIaDðÅaLúÑÕ5¢Gx,&4½ UÞzö¤6jo{$úã½jÁr€ü_‚âœÜ¯;Oï+ô`zƒ‚Lžè½–)uõóÒ-—ŵøŽõ¹«Zˆh[ÄÙóÄ/eU݃Èýû6‚u4¬?›0ß1@­ÚëŒð%:…x\œ¦¿¿h+@ø)§¦D¿½c­»€Ž¢Í£ÉÍ áí#ùGÀ׬Åì‚°ºñl‚Õ.P›No=Hþ£;#\áÙl]/´¬¦$x{gÓ z\@¨¤/y £ü»§h1ЦÉ.:kmÍ$ܲ$_’€€ûE\ü-L ƒz®£§Òm9”R@=¾“kÕʉ1?ÅJÌŒ:pÕ¡.&²!ê/:Ù­òhúEâ ­²Ìh­( tÔ:?n5«§÷Ë a‚¦dL4AÇýïþŒ¥5 õ/ hÀSˆÍ}üw<¢ÁÒJ ‘éùïœ*UôÛC+*ÅLÆwVø:Àá±F“g ÞLsQ^D'A·EÁvã³ æ ”ðñ~k¯$ï£âÌ05]`©©ÒdçeÒÈ–{`dóðgyc50Åb›6Z['ÝNAÜÌ)Êp06% tUÉ|ÐÔ®v}¾SÝßšÜ[5GÆ]ŠºÛƒ¥½ËÁB2>Ø`j‘E¶¦!w˜ËíÅ™!˜Û¾ÙMf–ÔÕô×Ú¤-#ÈìÛ•|?¹8Q{Ð+»}6ÔÄ•àY‡\Z?V1~ïöøýÕy;} eå•• ‰ÑZ¤)÷#„ ¸­sÙÅ&dïçÌ‹†MhPCçíFÈ('ø‡|¬+P E㮫Ze/¦ áÿ–,µaÝ?£²Tv’*Uv!µ­æµ;·j¯Ê6¨æ`é*f ŒÊ±0¥XëCQf‡š¾ß4[©}’B–ï¹f*OÇ‘ IfŠoÝõ¬©ôäLóôhH·5@Ðê_ˆµ](Œô‚Ú;REÛôÿÏÕ…0aÔË>áqð¿Ëë»ë=àã0¯(!1=‘|‘ÀÒíÚq fíVóQ9Ck°)ñhÞ` »F<Åþ&+ñr߆%˜â@a¥—äa9qÑzAÇóöb"D)ôÊ—~ÂL]D¬TÌD tö¯0+’Ì’)zï„KU-Žv“gõW[ÛU+öÐÚÇ£ ‘nE*Re^Œ ’€€­ßŠ G{ŠÜû›]®œ¯ãms©Á@Õ-v„y¼A¿ÐÐ à š¢hM¥¡Â¥´o)£q3†mꦌÅú ­ü¬9d‡©ZW\4ÖY[âAäÑ£ƒ`ø- æz`¤s}+| ûÔórª9™S&fÅ«%„Å©s$'T© ¢K ?Ä}"ʾë#ÁÕà!Hw²DüC™éNƒ3g2èµ~–Åæë­AÕ£y’?añe!+g¢×-ÑQ𑵂 QB˯^€®•E:ÔŠ.# ~ûÁ²+_$ÌÁ>>Œ ¢Ã$EðofD{ÓbXü”mFU×g0kTj —W³׬#nîZ+õÄú’E­Is;IyÚ–{ÛµÐüç¸hXƒÖ̘Šr•fºK]XâtNçñ?&¬'Òè1,X•FZokr õçEm¬5—W±È¼¾øÔŒq°¼ ãÖ|°æ¸¯[—a¿ÃËï"/ÁŠ”<ϳ1:Cvz,¡ÿ?ùc–^:z~@Nü)MOÿ‡eÑîÝ üCm®TJîö«Hf/¨yf«¸;–®kÍpü2Ù;½ÈDú5V¸‡…áãÿ¦HnrÙ¨;}L ûkäX/eÇh 1æs‹^|¼òçÉ…LJPK“Ÿ ZÂn?™«:®ÔË·!ê¼ïd0a•Ûá, Æ1µ·bÌi"uŠütoÆÐýõ á,´[âå4x§ A? _áiü PvW°,N 1äÈó`$:£hèO.â;çÿÂ[UÖ¦¤ýÛ?§ê›Á&?6X–2}%÷‚Øbò§â2õQ-w;ô` DˆŸvˆò¹ÉßÓe¹}Âøbl8B£ÕDB–œr&=¥ÝÂ@k`I$CèLd:úJ®ë&Lb.¾8ºŽ*^xǨ9Rùð߽嫀Ûg §ûYÂò8ŠÓ†,ˆ±9ç4õ›DK.¯Éøi"LQ¼ ]¤^=fj¹Ìj sÔÄ‘YàºdìLE­•ð»à ŽL³ù4*Ê_¥PÅDÐÏçt•ŒŠÑ3!µ({åV ÀŒ‡ R)V`âÊ6>ܯw‹÷ò[–3 ”éë€\$î².h’€€á4xœ“ÕE})üÙ÷¡Û† ¹Ë†PažñÛ<¯8 „úbÜbùží'=ç)¡Juž¹2³*;šOc3ÉiÔ 5x*@©H—ôÀÂKÉ6¹-‘;²%2'‡ä\.ÉnTEü«FFb=²¯7!a‚†ê9\ ÚÒÄõýC¢¡C{@kíšíý‚%Ïž.÷BíH%7ÛV6@õ~yúßë<ÄÈ&ÚtC„·~•¤à’Û7Ïëÿ˜.á„aHwgÄd&ï=k­ûÖÁþò©*#nõ'ÕkGzÀ #úhnÔš2·m‹\Æ@¢P¾áã£ëïÀ¨æcÞ­¨v²ã˱_cÛù“…²=PÎÌ<¬¯öMº9•ÎÖ’ 1¾f£sÝ%k6õ)› >j¤ýUUpl/JlC}…³&Y g1[aØ6SU*«8€{wSú‚JXc%Ô>PÅ®dŠõÊ bnÇæ:ëêòN50Ùå)†¯Ñ†Ã‡;¸œ‰6×y¹ú¾Åc=}h>ÝH,Ì͂ӡÖE!¯óUsPÖC¿ÞÐ wçM~§å¿íœß9?:ó¿ç{ä¦Ï]gCÿßȳM#íÝ4æ"»9óÝÔ¦ 2[ö·o`4t¡çöTµa=õ•ïg‘j·Ý×ôÛG-…*]ŸîI—æK#.ÃËÑ8‹d­.s–ê2T½„À·‰€GµìòïåF3{$¤§ÌJÛN ì¿çÎ^ÄÁ£ÖåœgxO.òÖºþTà”]f ÊzƒÜ8ȯíeV–ýŃ]>®-ÆëñÖ¸í `¡–…‹¹'ët=—浺.…¾•ÑnbïXÍ }PaõŸSß¹fĆë@júøã“ÉÓMبu ¦ª^°+Œnfn„áÂâ”Ãtœ‘B/™Éø¤ÕFžÊƒ;êÆŠwÚ [‰H}ÿÅFUc¯–ûÆe;YžÚ‹lÖ¢±F •o%·sï ¹Âëšïë<ÀS ÓÞ™3½ìÙ4ƒ¾ŠšlòX”î¦ÍØa&Ÿ†û‰X¬Óæ.Ø CÆ¡³‘›5±'4é®ô,,þ¤WØ9c ô…^å\Ø×ÿ:…ÈV‹ƒq³7Ú'Ö§ 9§Áµ„ý\Øp§Ð[¥õÁ¦|lÊoöïz唥Æ’€€Ë( ¿7Z˜ÔñKÅó”ZNʘ¹Rö¶OeÆ=ø:D J-1­¿÷hÙGW¤Z9µà7ø°A)ž*n<þ ¯×›ïZ›žc oXNÒ3Ô†àÆW`µbzU`GŸk;)‘ÍÙ;³…jz´¥j~’me„„fÿì/0!J§õ¤W“QâÁÔ¹!eµÜŽŒå_^K×Er¨IÑWJ[|]•4µÂùs}OæS$H>üg‰¾¢u ,å³ÀNÓ½ª‰¨wk˜[êµã"órìP’ÈÕöQ¦^õ–ýBÔô%bnŸ_¨±Ôéú€‘˜8Aý‚Y?/àÆè¡ñxÅ5>odîŠ0Ƈ±"îš}”=ÈV[ȉݰ(/ßI¤_˜uâm–´ÿIÇEuv?‡¾æþü*6¶Ñ:…÷ +á lY½QQÙ—@æ´žáéPšn†ð¥Çòª‘nö–Ás- Ò”³ìšóžvúZa÷rÚ3…{‘••›“FZ[Ž Z3ŽiwR?qH ²òÏî£1[Ì.%x‚ýÈ\Õ7­“!f9Ó¶íÝÚ»2©Ðw6A&ô’gØZ´¡üŽáÛù,ð’S˜bÕûQR§þJD=D“9våŽxV™öó[Ñëé±C&Ÿ,UsK…г&F^œv\ ¸‚~1¹¦s|\KÖLÆŸ¶«ÚŽÔ;–œ¦úãáÒ#Ÿûøð 눩øU¾UL†LÞ®Á†Ü@2@ GPý´ ÈAH¢jIOçŠp„`² ê ¿Ì…Ä:)r÷ëj»H-{È+s÷:ˆ¢ºB§î©ƒ[·!⻼ñš!%™+–°Ä{\Å›µÍdŒˆáÊ9þT4Dâ'VB}è|…ȳ‡ò‰¼€¬¹ußÅëssžË3¿|Æ/tÁð;Þ+Þ­æ1_—ú­»&5Å[^È3Érª5kk4ò¸ÿµfóý 0 Jÿ:ØÂ7=têÛ©EÈ’à„²—è‘&ƒ}•b€òÄøõ$Oè-ÿjÂ//Í‹V¯Z¨ÎÈ eDOÞ,^;á*–YÕ¢cuNLáqA6 ²…¸/±8}.ˆôËRŒ+™üÞ~©û…’€€Äå…ƒžC¾´IY榵WÞ 5±“*"p<'6,†£ìŒÄoL£94zmŒ„tjm1S#·"k¥vÂŒ¹ýÊ&1)º\c?¾#ùztc`Âû_»BLös™‹Ûë›Øã–k¨Ç¼‘Ôë¤JP ú”D ËPuâdèl)`­®“ý´«¼ð1]¦*ÃKŒ”róà" ¶Á€ GýXL,0úîêÁ‰d°ÚfG!+X¥n#½—ÙäV¸­ÌÓ C((Éá³u¢áÓp[¶o\qIðê¨"U!JŒüiWjÍ› =YMãw9ï7u« /–úb»‚vÛ—€s^ýisŒnâ7šž  ¶áùæ:ñ³*Ãk´½Ñæsw› _-Eξý–Ï$È š¹ÊâLŽ7æ€ö<7Bgæ ]M—nŽ1­W¯šåšÜ‚ÞÖpw¤§¡¯CÖ\Ѽ4Ú^ÙÉÜî?”t„(l{:im …çsèRÉ´fÝÝQtŸ‚-HÖÉæ Èm¤ñh<ª¶wâZ'Ò#5ÐQÚ¹ºÞu©LàКôCnü‚©àI6ÞEæ¡kþ9éˉ=é{¶Q§L(J–~´Y9o;+º-_¾bQüŸk«÷Áv‡ 5[ûàúÍ?²ïTûÎÃ^8·È››à€òF—üÐ)n‡º_L×nm Ì ¹ãJ’1·bw8ËׂÃ2¾ÂıÈM 2š ÎØÆ¨½¹¦Ïwµ‡ÿŽÓ³YY ÙitÅ8<´Õä¬üÖ/©úëÔž ¹ý3þ&ùKB€lgÊØƒŠ K³˜zu¹°¤Ìö$ᚣ…• m ïêwr±/Îÿbù·&75Þ„!Œ±*‘‡GAÇà’€€Ö®SV'Ô¤ÕËàKq„9i”˜'ŽŒÔ2ìM$ó`ñsiگ˸R ƒñü»)‘zR£¬44uÕèBéNw R®Õ=pëŸ3&sއ…yY°â|²eNæ‰ÍF°ì]Á%…Š~éÿM>zÖ1ƒñFÌ't  ¥l\yíüùÞ%…²ÎOI¥[se`ËŽ3\ …¸§(„zŸa¼C­Ó³?Çz^ôTSV3âðÒšønÿažÓ–VV/Žã”]!ðe#C™ÍÔÍžd÷«ÖVcã³k÷?¬ä?C‘ ^¦Ä-ŸæÎ¦iˆüÕ †¤àïø1G uØóæØÇ@êŒyÿíM.L&%¾#ø E{÷M [nÂ…ô*!Ûì±õäi`åc(R»Ì©Gö•=o÷‹–Ÿ¾^Øÿr¼NÊÁpAñÊ ™D²5qp,\?5ßñž#³ïk˜z±g²'TqûmϦÈl¼³_»\¢¾ï3Q¼ÖØGš­*‡hžÆ§–ïU=•ÐÏ/{çsEºµô'䨭êܹh”_׬qýdò™V´´íD]ÌF塹„Sr:­Jfè4rˆs ´Ï·qîšZÈS÷…çe‚w¼ vÇÉæ¹,äÏQዽdUóB;+Fþ’Ìóâ‡r%ÏI0 rÉÓTÄ5’ç¨ ¼ÄÛ¶,yKàÔuiUMb]èÚo·"áÖÍŽ^°Ö†Â•™_¾•z‘˜)€€ +ž:´–ðÌËÞ˜Z8`©kÉŒT'Q£Yç¨òÓ0Z9ÏÏíºr*nžŒ·,¤tóüŽ%´ÐVŠðœßä’£%”Í%hתô†±/›ça?tÇ8#ªëªØXjËq»’u¿ñÖ × U.%ð!¨›òP ¥79ù4ºÌ\q^Ñå÷.{ËÔhF+ 6ÍGã"7V&ç";…ð•f.T Ç ~×â:'*ŽVž{˜Zz÷DÀTtNë¼]<~-;4’¸ÝM‚oÍã¥g=­Ü,Úg>‚-Ë­úžTÅÚÁy[æ6ާÕ¦/¢‰EØëî ûÒiæ /i|£M«)Wb°ÏÏÞÝÑ̽1ªtµ׵ƥÞNtÄåÕ_$ÈÇôY½B¹ ,2´è;¥â—IëD“‘F/jócĺùxCEI•qMÕÁøÌ$úÛ›ZúÈwÔ oÙOÞ–‚u’wà!‰çÎT"}9$Ú^æ-iå ½ºÕ>Vª¡Þ?Ãö ´ŒÓ1«ožL90cÀ‚w|BÐ÷äÃMØ2ÝàŒü­­¦ÔÒjÐíut£þÈ]>€Q9‡ÐØi8¯Îl7t〧±W@„D½™ŸA^¨D‡Ü€YùÂúh¥Wü¼I‰L  ü-ÙÞp\¶d«/ý®;ûŠýÑvƒ>³^ß“/óOJðdé#›ñÑ÷™hÔ4˜Í®1F:N}WÚßâÌ_ùŽ—m‚1?J‡;Z¦âØáxWcnùåYki0l#´Êù)G¨ÆZ^â:jÙ*Õ@´íâü;YZSìe`p© „¤J-Ù÷¨ôù%o˜¿b·ëÝh`;F…>¢n‘äb‚ù×Z@) »ÚÀÉçÓ p.K©ŽXr–L÷ŠÚÏý¯C×|­þݶ£â¶ï`Zmò °´‚¹ï„·É#³ä–»Qá~íç>%´ZÛ ó|UǾ5Äeð]k*ÿíÚMc©{>€Šò Ó˜@¾¹rLð;s„Ãöì$nl´§¤¾FP‹ó»%ÁS*ÅÔ-(ý0pÑR*ý-ÝD|¤/¡Ô–x¹,¶œ1¦­£N+“/?êkAAJ´ŒÊtÓ¨CVk7Ë·¨çñ­÷B¯N¾âTr`x~öÄŸLÿv4‡uß…¡Vë,wwEËUÁ(K8Å]Xx¶–Q ȧøæn©4ûñ;¹=6ÙžÞk6×ãmM6D¡ÿ?ç!zS8>–Ij@dô°Éy²¬ÙGC¤•ÃÑ(¼0s Û™"åõD{­W[GƒsTî À_Öqƒ± iaÂç7¶mïÇÚPÔÜ’zO—¼ÛZ”Å 2‡§«p›OOñ’€€½ûf¥Ý˜3¾sádr@/“Az%lêc–80Â9+M*-ËI\% t‹f¢ð:›T³Á`èc’4ÍTÉ`nwš´÷ñG²-›RªæÃ'Ä_–ì„¡ k@fäNãàÉ¥f{Ì¿ÕaÙd¢Šþ'þH`ùÖ!”†;W¼qÒ›*=šøûC¿ºÂ͓ԃEc5ª¡z¯(†¥Ûª° ë6QÇtn!’{ÏguÏj-1fúp"é'ªê,bS‹oácðl#§Þ†çà‹77™ÄuŠ©WöŸv³ñcº1­z%§ßÅùµFðiž| pC–|—“øP™: Œø0ðpHˆu?š_Ž`p/¡×‡„7Û¥f…ƒï=€%‹eÉ£M$: EúêÕ¾>hïÕ\爉á°oÓÐͱðÒ̾Q"ØÀ\Ml¦ûjéÀkôlj-kB«½ }ÿHŠ=Ú°^ ã_Œn\ ,ÞIBÆÛk0üGWÆÞðæJØgZUÇÖRWû–×4êµ»“MÑLüì Ÿ„WC&D²Ì¹J̨KRWž÷©ÙˆyJ#¥S¿¥çÜâ˜=\M»lö4œ7uxŠQ:ƒ‡ Zå"]IÜmYn²¾FÚ@%€;¤4„EÕ¹¾ºAÀà¼×¯/‰9‰çSÿR!òu¬×çOÓÆºà)€wƒÞ•ñÄ ¢?Ñ”—Sº|¹ÐœCXM Š 7íçg )¨°yƒ>&KÚY!¸è¹ð‰‰è/dwÂŽK8q‰¶î Â/0'`¥¿L%”…oûŠZÃÆtG[[ãAk{–þy?ó y[¼DI""•fÜ›…]o‡ñ Âö:wÿ­ià¿dÆš¤P\ýó„e(V°î¿ø#Dê‰\ào•5‘z»¨Á8Åeh9yºvÓ5—¼ö,šÞÑ-ÈÓ;î”u¿v…0ÐÔyÔQ怰׿1>…!ë=ë"r^@’€€¯l‹~tœ/˜‡þK@WßÁ/¼ª@æ²?Âr J§ö/®Û¨HŒoU½ß*ÛkóŽù’ØÒ7Ÿ¹Æc×iæU“^Ìï9ñÂÿ¡[=¢¼­-¾ìú¤6·qÒ#ãž' û²™3î0'šÑ/‚&œÐ!@ß±Óàiïp¦nçÐÏýÁãjÎXWŽKÈMþrç2׈¶Ñ‹¥Rnéô&ìö·^ãøø åù–Á`7x§ýý7ú˜Ÿ4“»±@'klGíð=ú3ÏÕ]¦Ë|Ö%&öÙ§ö‘„o9QIô”ÖeôOÚ:Ù4N"<Ò²æ/#p/¤ÚÃÆÑP9鮂¶±E-³óþÁX}=€éVB"¼dA9ûeG§†€/ˆU-²C-q‚?×H6U0؉㼤º3Üp<÷‰`™ìLvœš^V“;;IO‹ZEÁ€Ì®þºè4€Ÿ‡éÉ…—õª¶Ÿ}h‰Ö_‹’)C Ppwyö-í` 9n–F œœ‹ bµ·œìZÅrñK\˜×TbÆØÍ‡/@qcØ÷HXe »UéÞ@tÞ<ÌÆâ—&¨¦#W ’¯—kK3h):"=•À„Ë­hqDËÆó>'ˆ'B°?\£æD"ýùÊ7xÖæ9Ôþ„1<øW»ƒß¤$Œñûºà´';aå6Ø/–Ãñ£è)á[ía0­`kÖųZh®Bç ÊëEø1d3ä§n£ ìSÐrBMðÈýcÏâ;óÿSÓ­ D‘7"žÕȘ¦ TçT1ºò4Ó¾}t˜ôŸaæ1âäÁY±ž®b¡¼BçA'æq“ÇHß2-Ô]—m·ëMÃì„ÎÇ:üÛYÑWÊï¿úsá'QäM5óïT¾i| ðÙEÌ¿iÝõ7gG;Š…|M!„ܘlMÏ~9¬îñ¬» Q.ƒ±ñô*AЉÅ+ÅÁ ÝÄòi|ª ¤DÍ´1™*O·Ï’±N³sH­‰Îuþ CìÕF0ea2SÄîl­+˜h@f¨ðˆ~}–! '6'[ÄŽ[ÃìCœ«nú‰’”~ÑS!OÃEBÁFñ_:¡>€Lj­¬žwÁæUÉcñ{ke‘Vãµ`#¯GälG@|:¶UQ)†_Lê>Ñtψð‚„M@D¢ù·ÿíŽÙÀËžnÔdê’€€±<ëó¥@~ TÅiÍø¥«ë ¾è˜Ï¸@\OYRç€[aÌ…mWÔçk G…±N²jÉìan’“ÇÉ"7×=÷¾ø<[ö¹ù|£zßD{E™æ¹è¢iñ÷CËeHK_‘ß3*Úá¹ TUQÂE±OUÕ|n3uŽÂÝë*L/(t0 ±v’ û–ṵ̈vïªÆãÆõÊ ®,·–OUÒæ²K–Éãj‹¥´ªd¤ŸÌúéê=5ñTÌóÈï/xׇ–R¿ón)ì×À Ó•î'b±E%B=öhÂ=| ÞÝ{OÆN·;‹ Ó ô+Î3ÿ^^øD6¸Žñ›]á‘m§[þTÚJƒÛ† RZV„JÇ+?Ódq»R¤Å ‹uÍ®àdGÜSõÁ' ˆFzjJ=¤•0‹Æ bþ1ºN3ƒä²a¥6Yk·~I-³æêüò@¤=tA…Y#”lò2ì+JÛÄ¡1> l@àTê?•HpöïC!ƒ²噵]KÁpPYÛ‰8Ø&õŸÚkþ©žF½}]eOF^Ø¿ÔÚ‘ö\®åÀèf>ó¯(õĵ/Ô„ñ’ÜŽð¥’(ù+b¡·÷õ½ý´ ¦Á`Çt®•Õ² Íx)q@wÝIƒCO‰öñϧáÙÃàúºJ€J‹¡,.Ëåÿ‡Å²p̵4–!™RCÌËq¢0úÖ’A£pÞØVJ¯šu+@Ñ‘(²ÌkÉ\Jžç1fØR3å€2…¡.‹#ìl jåâ ÐØ 8“î ˜ÂÉ× '4Åucc^Pü0bÌœØ0ÙK@Ð[m—+¼n¶‰Y’u"geÙë—n@ÈR9XÉ6¢³„C¶ÒêU?OXe4‡©¼½6x°ÕÙ—qL?ÚeÙ;ÝGbÇ–YM1&m:a‚â°·†Íz˜á-ú–úÓË)z\õð…ÒHNøŠl€tyêèŸ$j3BȆÍ}®œ+QØÑæh!ä*§ÌYåË;¸Ô"z6¡²Û¤ÍXʇ]P,Ì(ÆÝ1“»TfÌ>í™_°˜Õ‹ë?¡…(œyL¡Üà0Ê7¯ÐþiF`ô¸Õ•øœLx8«Æì—>Ÿ7X¼¿q=¢`ü=_ÜB|ÝüÆ??n»Gð…ù/’€€ðÇO€p±Ö §#k-}caµÀT|ù¢Í¡n¦á:Óú>UÔ&óýè äñ#RèÂÇ»¤ÿðyAq¤ˆZxGˆgòœ€=5ÿÎŽh:X}ødîEº³ hï„PkмÉCb#ãO?ÖÑ#”ƒ ñômx_Çåþ ¹ÁžÈïÒŽý„[Pà®-yi<•¶ý?´j|Òˆ¦W^uxvDçÿ‰6‡=ÍT]g%¦¬‹í=>Ýs­ÚsîqlOÓ$]–‰7÷³¯w¯+-ñu/ *$Œ,Æ%‘\›¦¾ÈüË֮ЈѢBø‰fÅ.˜îð¼ÚkŮſI‹ ŒrÕ6’ª†6¢ì{gw¹ jµÜ>.ôìK¤N°y‹—„¹šŸ»®8c¹sY9è#›Ø¬HÈ%`¸_k€øû±Æ}ÐÄÓEêÖ’|k5:ŠÊ'¡ó [‹ÔÐ>ÓéL]Íì›àf…½ŒÙ4[=È[>QÏæ9ž¬ÐXß—¬Æ;ƒïÄJÁFs{ùwæPòx ¶g‡¥–Û¯"#5qR8FÚÙÞPvaJ¨Oàk4ÛD¶üÄ39žn†õ½ µ¦Gùœ¾öl¢¸D!.à™Ÿˆ…Å£¡uÙ™»BÒÕs¦¥Þ< FJuBúx)-ƪz6z*Ñù mhZP‰9î?ŠšSs¬¬J+;EýÂT!{žH7À©„0Æí0yWØÔ6®²2­Tƒ\ð¾÷3È@0Ä–òI­8ãÂ1ä7±5A-Ý8$&!-«\0¶ƒ .;½1Åç»hñµ¯{ÿ.G{-9Àa"H•ÝW Êj»OBEúŒoÝ{.âý„aïàþ#ý´Õ‚ç`Ðr2õéhó:ð =;Kžœƒ›°é£·ô#þÖôÂpøÆ·Í¤ ?x½LL¦wz£™#©WÖ¬é‹Xʱˆÿmªýà˜³¸©ÀàÀ²µ…Ã^wo$•J0œoM^ÝúwÌ®È" £ÎNS  ™¢3÷¸¿ÈOÁ!ß3†ÑwM䮯gr…t¢hÐp¼RâÅðëâc;H@Tš|t"wîAE85„:4¡«L)så£xšÀ ÿ{I.SiŠBt/A·ñŸêeÄw¨V…<ë쯨áfFâ³#NÈv’€€ÎÖN=ªU!]L±Ùî¤hP²øý¿óã«ê¨¶Žæå{'í¯i€{à_#o5ÎD²@­‹µHiø†-&à‘ 3À¢a<î⣃—%Â1Ê``^@üé½Ý-¿ù¸N÷G(Ä1*œýngên;®!€#ÇäÅ´Ë@†&hc9ÂB»·N=Ð¥òœ@9Tx¸{ “ŒU!‹*W?îêaÿôô#ÙªñFPÔ ¦SÚJÛÏïMlÖ$ò©t¯â¡·¹ƒG#ÏsùÅ·§ÖåÂØ¹éQ57%Äc§ëÕPIþ”ÉAZy ã0j»Á[¡¼ö(âÓCš_ÑQ(TÞN€î¿Zıð)_h/ Wæ.©‡ ¾U$ä5ÆÑÑuÌòOßÊî>/÷ÞÉûà»›øøµJÉ;ÙŒðC:+¯æ§à‹RíËþúÕÃá8¢Þy\‡\qƒ\µù°=F$E€QPÿŠi|ÃâÐkà4[ÃÃ]¿þ Ký´3Ç/¯@ÁŠ™çaµ›RâeM‹1†åSI>D‰NCQFÃ?;ZÓΙõ!j$+'¿½¡taÕ †¶Î†uö(²¨TŸ>®Dȱ(OSd)5šú¢U®ìqî` l‘kéÞ¥ô_› yÐïc‘C¹U…#‰àüÁs1-§Šë°Ø{Aí¨£mDÝ™´u‰–‡5þ 2ÆP¤šŽ’^IOfAŸö'ÒǃrvDꩦ«n¿¢¸uþÂ-9Èì4Dr’•®(wÞM¡rŸ^iЋCæ%oXs j~x¶XZÙò¡l±DÕ\øÒ7þíB‚ Ì9ÞÌ»“”ŽÃ0&7¿Nô†èêÙuÏÕ¼BWÓ+ÊÈÐFNä²Ù˜h«1pAÑ0^]#<*9…"äЂëß]:sŽÍàbßð1gÇ}÷;¦š&QÝ ÚÓˆYƒÀ÷¦u,.hIYEøžIïΙŸÄÊÿO`Yžæè8¶ä2ÎÇ{ß«N èa"âÿÌJU2Ã’-¼eÖøEß‘´ó£”pËr ¿VVüÐNˆ\Џ†R‘ÿÁԉߵBÔ âÿh¤>t80ú!^4·º¤o¡¯/B‚ßÞ„q7Q¦Ìñt ïÈ_›žccD'fÁl`%¾ t[W­’€€¬ú•!¬™"yÖ…¤},=ëí˜ášXG¸=©¦·"óÜešY@–y¦îIa;Tðö”˜ûÁê“vÓ&Œ$ íKš@âNÕ>Yzu£}sî R†kÞï^"eƒÝžÞùƸÑq&,ïºt;P”=Þå0H T V©P;Ûäõº¶ÀöÐÏÜëõÍ–*Ø@TÕf¥Lë‹âëS©!IêùKÏ×P §3æÊo4L¢Û1ðZ=6Ÿ$¡?²QÿeM²7ùÖðŠÈ¥©Å Pº±f¡ýKôieø·JOûWnv^›3pj¢ëyž™«Î°ã“ÄD„ qŽËíçØ Ô73«õŠ]òtg£è-ËÕèNHGTv¹ç?nn]ØFü®_–g´ðœ„áh­[µt†SXsWú—¡øÊ¤¾H5æ(ŒnüE£Ñ­ x%ÄöÇáø5Æ Æ>\y*"µÏ:ù¿ÎEh6zúM*¡(QÌi©'Q(ãâ›hðâi™„"‚­+8~á43G¹ q‡ÝÕ½KÔRçxDrè#È@àTOÀ€¬¥–?F ½=¯ ¶iÇ0Ûb'ðͰs “Té?Ëx©º.3$›‡M Ëúm^9uG½$\¶7]ûJ ÊeW?›Ûy[xTÛãÛ!@ŒÈ(¹ûŠè÷õÉÚ«t;O6 ø® ^¸¨BlÍi´r¥Ô_ëULgýh”?#­vP]ôt­ó­|2ûnXÀÆê¿Ð•F’Ïu½ÓO"g<0Ž9ø³à3®Hr]•í(´§ŒÖ“)z×£¯Sñ&¸±‡¯kæ!KÑËœ¤6‚oh£f p©V۲ʂJö„€ DZ./tÀ”fí÷ˆGuø–÷gé¸*Z2ü†–)›Ï«3A^ñÍH5\ .Ðû±€±<úÍ`ã›`ÄeEN(Üî4‹[9½îá5mÄ}Rj΂”çz˜§…ÓÊq,„ëÐhNð:sG$ê¥åøjyÐÇ_”xîЧIÂÌez!t+W©!¹ ûnV²·•Á_Ÿs'éwMÖJç{7ýöFÒ¼éyêŠh„RMÃ\ÉÍþ¡ÿÎæ%›é8:FÜ`HZ°ÕùÞ “ß; »r…LY*¡¨J4¿ŒrÉnàì­UxqË®×ǹ|3¼PCõ)Ò£’€€ªV×ÍõJ¤Ê\/à¿|5”½èÕ¬ݺ¶Þø Jh\ÓËLb¾ÿp-¨[笓¾È†t).çË$u”ˆy‚Mœ¦:ØèÃæw ­ÒüE5Ï…™_jœÓJuuÙÞ¨”´¶„»sѵ"ýX–½Å” Õè6°VÜÈÔŽß FæUÆÇ^Ó]ýÝyÆÓFÔŸ‘BFèBÿæºø×%뢼¿ÚÈ¢ðž´Kq ´Á_ú=ubX>³,Ê׉;6ÜËën5.[w³J‰«… Ò" éÏ|EÑ6œ¡ilàþš·‰x^´øÞy.®]qq}yêªÝê°sýÒBóáõS´¡ì—ÃÈÛ ñ%‘Í’ ÂM€ª¹jLÓд`«Rž÷‘6%÷xïù€Hèƒ)³®ä8ffÆøçæƒ$ÜØmÚâç^ž$ͯA^`ˆ3ÐMÞüVmC•kÈ›Éÿçߺٙâ“òï%» ùXÒãcÒ6´’¦œÀzøÝ#Eë ^$3¤½9‰•s‰áfö›pÚ‹g ¬„•ÇhYÄAŠ @vžMƒ6ö/Q©°=`@f»$^O×­ýú‹XŸ¥#‹÷J8œ%µ“—Š| ðdZ“ÈcÆÓ÷ÕFéáD±îva>^F‹ìñÑ Gîî2(ØgÅÿ²¬{;a1 çœy1æûë$,»h”ÅÁv]…ÒÜÄ%§€­L”d­9B8ä7&ÞÐñÙõ Uw±z¤|(ÿE9\Êð 4fÝA>AŠ6uœ§tuDe­IÛ»#YY)‚=Cú×›:‹÷ûÌ«Aö+׉Ò~®¬Žáö&‹sÀèøé³µ/VYV×@ÆÛ~£ QÁzöáÏ„±ö`†¡rþô0å”Upß#µ(qTåy¡³q ç³Ôõ/án4½j²áð}àý½ÓûP&†±ó::KóYË4ºå)câÅiÁìäÂOívùÁq£öß †Ê¶ÐpØã0Dv$š›4]]ø­Je³ éAW‹’€€»B¢ [ìæ#ò Пà2Ô¯nl$$¨1<Ä›]ãŸÚs?¾ï ÆaáKNÊE½A…é0P#ä‰F,†p7j„¿’R"}+72I+.ép?k#xòjÒM¬q\]&8† Qr¯¨ãLJ3w€kƒ–cl6½± ,ù.Fn§D4"çß±U;O†ù7Þ6ZÈ]hk¨¬lìkÚ£yÁÆó#‡^Ì*ãG± âÍbÌ0”à2Õ;°Òž#Ò21‘ÐM * 3/ÙŽ@Gs<";ÕßP鍨Á³Ó…ú/Ÿ±Fd+j€µP!µC ;¹Èm¶Ó±éÚ¥p±m)ˆMçÌ«)× …UzpàZ³\9Ú1÷{{ ¹ÎÆÏÞ¸ê¾MQ2Ð[oÌ9Šÿþs¯æêÀåü”ÎÓ C£ê¼×r;¢öÃ}UÜn/B·FØã îÙùRÃÌð’Ô1TÍ»a9b™ëІiâ™‰Ž¡šÑå•·ö¬‘ýÇI{k)çÖ]÷e@LQE}D{ .ª‹º} ±LV£zÓ‹ JZ|Z¸ìz¯+§W*5þá2|_h-€|33' ?Ñ|£\¦âß±¿:’ß#YÊÒ›&­ zÿ£/[L0]ÿ•öœöH¢ª:·§š%Uæu¡Ú'Ê‘“RrªÆvA¾å%uš?(~ü-ÖO´ž£¦ö¥$×ÛOôéÔhTMXb@H<`“y]avæ‚påŠ2Ä D ó›ßä[ŽÇFÂg䣳al/\?/o¢„=îß0F ¼ñoâî -¥öîýY»úöþ=tÎ’€€Ë”BúcŒí@e·ÿ'góØ"KJ :QT;–@ª™½/hýúr¼¯ý¯¾Í×Ík¡Û[ ´Ã¼Á ‹†r/eMð¯Î=îjã™cè§ üÒ4Y«eüHW»Ù¶ƒ•ðk„_9ÌÀ$J²“ûL=ncd¤]®yÿå£b`ã«ûÑÉh?Sˆ:ò»üoí?„“þ×h%4SŠ¥npQÄ ÐM±¢»Ã Ë_-¼ƒL‡‹|ëä”é(Ü™±˜ÿ—ÌJuæijÈl¡ã²Þn,¯³oíµþdR}Nµ£ûG~NÕ ž0°S'Ī•^ï­‡¨æÌèõ‘¸ßVKÌRë<è×"´„;c]´¥ªŸ3WJ’åo^ŠðT+Ć_ Ì«Ò$Js÷a[³'°¬ù$ÁG¼Ÿ“ý}¬¼ zkÖYý«sÑfèý”¾œ“Nóʳ’!ú´ËXÚómP°oÊ‹ –DÍ¥u¯syùÖ)ý{G¿]þðí’qÊ•’¹¸¤Rc…9Jº´K•Á ±›7 ‹|æ­VÂÏvðF&f¬X pIZ¬•*³[ÒÙÅiÅËí!ºŠÊ‹iÞt!OŸsP `¡›·¸4@^Åwµò6d‘â¥ÈZ¡;nÐÉ÷¸+éÃózï༠Ç ^ÏŒ˜à2!ì°:ýÀ©·qC•ÊΚ¾'žÉ$ÂÄßì:ÄtÕ³eO ,®xQ,‹(’ÅôV…ÌŒ‡˜^sWVDíb94#,S1ÚÂd\U±ÑJÜU{g{ê[;¼{)º>)>Ú6×ß‚6øItªüجַû8ì.6ZpäÛ£¤2h!æÓ­'Ü0xP¾Z¸¯„Oº°ÜGUÔ0·pqJØ÷¨›¶äóîCÃÚ‹Mâø?¸øEâÝWÄ;¼>±Æ](©™L™L§úÐfé4BJÒ§¸˜³6/Í‹…Ó€\Ü¿YÈ]dÓŸ’La;»AÔ—¾7Wé©¿p|UÓ¾›f& +yc2m^±õ#ìhEµ!é Ò­@R^}J¦ãШ.jjWbóüº-‹à-òsm ÑtÑà.èÝ‚ ž£Ÿá&˜tY4Õ3rÏ–þáIh™òìæ§vï ,ˆÆ8H)zfÇmV.fΓ܆™æsMóÇð¢þ7vÊj|øÁ7æ’€€Ãc÷Güû½}LWg4Ù¸õ42Ú0«ì6|Áq 6ÈqÄtéR"OAétFáÊÃÂk‰©ºi=HAS:ŒãˆWÀú8²|V±_åcÖ±ªó^UôæÆhÌÁÈÔ’SZÃa;ëgw(Û×äÂ7 ¢ÿ†Ü}!ßÇ‹!õÄ€Êá5\xì&,Ÿ$ΔԘ]kØK‹e^õ߆Ii;«ktš¥ÕZ5ó l;F·À}Mj5ÇS•‹2ÙÄf·îä@~75ˆ˜€V´»TµY~Ò{2Sð2±l€_[ÌÿÄùs ó‰k$±f¡Ã›¯ Û'- >Ï[ ûr{I]Z:þZºŸ1 z ú³«æ!¨NÑíoä¡ÒnÌ—ˆŸµÑûÜ߸º­›^è¾,ÑÞ8áîí¬ÒØaiµ/¬^wÕ˜–° Ž) Ì¹UßÃVJ¨EÒP(¼Œ æw­=‘/F뾋q¯ª:3FC†ÒÁ#|ÛÇ‹¬´ðKÅui§ŽùZ6P©¦Á9è鎻ÕDí(§…ÇW&Ä=Ä 2á"@»Þ0¹8à TXž•0ÕE–På¿3¬”߇Ôm’±;—yj†û4¦ï˜hý&ž8=ö ¡zNÜnFéxÎh9ð_ä£ ˆ¯o“D.ÝG¦Éþ qªíÅ÷½å 1¡»{ãï½ }¢­¾ã,éщÕÙI¤Ñ Áj¾ôŒTý¶©–KguNG?ú¦áïyWDD4­ÐÝ´î‚SBMÖ?ƒc éld‚8œíEé2/P@Ï—š(/C1U ž™ß‡K_÷…ÇK G¤¦¡x$qúqÉ‚«0Khyú‘ô©Ø÷óýkÊtž‡–.¢æ…‡”@ÜàÂü¦;3Œ|Æ(æ=`/ØÜ›*Ÿ‹ØcÕÀwE#Bx£Em&‰—T,ßöVs#HQ°q£ÄôRáÁÖð½rÓcckC@º3¢‘ù3×÷³âYbºÖVçc!›¶Ðþ=áÐÁ0pÿûqâû<µÎ“³åeöTÿÎnTq3ÏÝÈç,xsy¨+ â?ëØ×Æ-XéîÓM¤3΄C¼‰K&±¶·Ø mx͇vpÕ»$6IÎ¥ ¿Ü°Q B kvì.Wœ j3ã;ˆ`é|ž®KMB‡U¥T¡“ èÛÄŒÖÈ’€€Ìõ{1VhZ„'‚£«9ë=cT(½wŽœüÞ•º¶G«qpaû³0l aÃÄ1šgQ„C÷¥§ˆ žð:½@ÄãÒŽKJù,•ƊLjմú‹À°§Ý1W«DV•7Æœê¯^=lºO©U!÷5c?gùc÷œ6Ù.•k–™JL:Û£e¬'D§Ý±>ÕnvSŸ•ü&WQÉë˜ÈDSÄ(ô"vd݈syvãYü?'Jù¡–4}ȹé¨$Û˜;È ã,·ï¹8›ôRdÌd{j¢·®l²\H…-›ìXóã§øíøXÖC–@O©ò^ú -2q5zv#%ó3PUå(f÷ò׳0÷×ò ?:ú¦âRÈþ/@ÄÜnƒ Œ¹äM1Öf[È-„èÄß}ߥ5MôLXðÔÓFÿ2ÎJh"l8¦V°ª×¾;+E£`£~åxCõ€ô¸Z(ŸŽøÈ¿­~U›*@0-‰1»œð8K\®~´PG¸™O›øÆD‚UÙBa¿OÝõM­f5c@Ä=J?IgôÊš‚Ð(š˜ ECÊév¸_9øuÃüßЦ}½‹â!.qh4~¢Àˆ\[mìÑLg¨tU#îè› })(ÉÍÙEXnjD8ëc÷L¯Þáî'.çh‰]¡„ªëúhYÕ­Z÷Ó$ñýlisÆÕuŸøG*C¥`2ˆÛa•öØ Ò,A"&ÿ# DI`žÂÏ•¤úŠ"Ö®—(ÌytEB¾¯‡õêáVuåÇÿë,$ª; ào6ÒjK8ñ¤)×ó¾8yså¥tçðW‘ z,ÌRƒ!ÜQ˜¶YþÜk á2;†0Í2‡BßBâŽ\ëf}ñg;•4ë†à)#γuàÏoìÿ¿ÐÅ®nW§öÚ@é}ì:Lù‚—ûÙùµèzhW¹7t°†™ŠÄt7A—ê,UŽa¥sÒWƒ=5 ½ÉX¦ªöHÐzÅS ±°!7¶*û†ŒÆ \}Ð[ž¦®j!Э•|F&[ËÀ8H9¬JѬT³éº­¨9UµoäbE¸X„¨Ðo+èED ÁvÑr¿ÉûÔ0ïÆõYjàø 6–¦£ö¦Ñ±{¹mþ¡’A!’Kgl¥¸bç¨Å9Õ>°Xç퀉“P‘îG’€€²Æðœ Ö x'…]Vÿü‡}PoVs½¢vOæô×1Ñm«uÊÉ÷¸€šHä3šÞZ€tkÜÖÐh*Ϻ°‹ïR0±Ù,Aò€¿ 7¢¢y0ª44¯P|êÌ5ˆ<|ù ŠÓ¢æàÄ9ޤVKt îA·sÜÉôå,Ç0¿ÒJýâAÇñù¤±ä¦U†¶h_L¦Ç%½—¾ÁÛyΖÚ¿°µ9¤ëY-ºÉø(1di0Œ¦ng:¨è=vfFE9‚ö2Ú›ä1)Ìß°$0Ó·e&âja2¬5©apÕ‹r€u¥éaf¼×l˜m•C£nêˆÚ`Bùµ—¦Å/‚ѰÃ&u×¥¯×é,ÌÝF:¡oú ¶|u®¤ró•å;iØ÷Ð.ê;•¹6N†mÃÌÍžÁ´æ‡lNd’ÎsŸ²Ñ”OHê·m1bõ¦1%øÇ…;UHÁ Î¹›ö±®´¦#õ›r)¤ *¼·ó-4ØVÀHÞlô¯›nöfüqÝVó Âi×^•µy*öCÝZ@/7¿ê gš³ðò¥„ŒØ¥K@?›E&ÀËC>©ÒdÕ³ÒIh¤ˆ1UCæ¦ë®3ÞŸ®¥•BU1)@·@ á©k«§‘}ÒÇQK¯–‚üŽxÃ?&tÇ¿ÚGÖ 7†(>¨H”AÜ5N.± ›ýÆ÷‘·‡ ‡öS䯔Pz~'²±÷W¾D§$|¢Ø‚Á <üu'宸¦Õ©¾6ëä¦R¤äÁÛ_Ùå.3‚áùD<‡æÃßG–ÎÿŒ_Û"âý~',†®+A‡GÆo>ƒO;²UíW"QgÆ›V¨Â¿µÏo;ŠÇbsÚfpÃÇ SÏxtIìó“+ª~!hªöÑdÐI¥tüo‹Øþ»-»çý:\#€xš,þÚTSž.=ñW.?ˆÌÅèíhøˆ©±¹mp©/È̯íñæ1Là„é°ð[Îåß­ñŒ’¾1JýAN<½ØÍ‰T=+ЃÁU<·Ëú(úº6U%k”²™S#ÛUû*¢yÖeui!Ù|Å(±@%[ð^qU.ïõÔz JóÍí`…3Æ>š„e®2G F:7 õ«¶Š* SâÒ|ˆþ׉nΨúúáÐ R¬‘¨~P©’ñahŸ1ú2MµP´Ðyè³’€€¼l‰{VÞ‘Ù\™E GÍJç{r¯8ÒÞ!U@‘ÖLSýÝ¿[ê9³éÏ›µ˜ª ìƒ(æïÀüi±~_ ºî×]:ìÉÀÈOoÁªž:¿Z‚d{h|}ê丗g÷e ^‡anš°R4ãI"²ZI®± â+]±¬}QG>wîs_3¬<Žt–eXüœçès†Žp_‰ù5Ê,ÄèsÜ&skÅí7†¡d3áòm¦ÑÅÏmÇ4ÍÊT*Æõ%‚,» ~fyç‚àª~?$¬>»ªž¤uáE¾tÈi5]÷QLÍ«ˆ~µÌ0Ê1áì¹£‹‹ª´É*+ÈaÏâBK•¥yL+%´CJžÈJüšÚ†)ZÜÌ îÛpçÕë®ÔPÍMÙI ,Oä%ÄÔþï{Á‘÷]Q³-snG nB«Ù^¤—Êc˜ÇðÅWøÁÐbeh/I»ÁxÈÛ >›„óBÕ­…cF©6’C aïüÍCev¢.’QbÖ4Z¥B÷>±)¥…3t´ ¡xÁ‚ôôtn\«çFé(—ÿk€§)*Z¡>-â•aÛÅ¼ÞÆªìÑvÎc®ñƒ¤—{³>y¶Ån²Œ) K`j÷Gnʶ‰ºôx½s›Ñ*+=A—rÛÍìæo®@FRÚÆš‘㵬ì»™“zJ«?¶ÔÝoà˯Ö(MÆØ„Û¿T{e‘p%tyÜÛ+ó”qÐÜ¿ÑãÜ5’–ám®ÀKgߨN¬BÏ\øµ¹ ×d³ÛÔ«ä-1רkâ1T]£ÉÈÀ  *ï;´àojÏ®šßQb„_ï_›æ±áK…ëªä`%O?§û|†b'Ö”íÄO€Å„¬þ“ ÉŽé˜õ·çk¥£+x#ôWmGªÕÃ-y*2ö…¢Z:ÈcCoÔ\8Éæ#¹[AW”¸'îzÍÑz$RFO¼¡µˆ¶x_ªØG±{ॾõ€Ês ¬¦˜øàDè—jšúÿH/šèÃtíµ S°ìïWí( Ãù!thþÖRŽ.gJ æU6u9_ûé›Êü…œ†e…ôjh`®†Í¬®ø ðäbÎ…¬¢«|«Jà ê%L¨ç¾Í:~Ô…÷¸’³J#Ç}31mOìg šíãîìu,=W DSÜqþ 3U¥H™’€€æ…,[¼//ZPìÃl± uøª“$åm('ÝŒþ£ñü€¤ÎJiëô‘®—Ùù݃<È´(5³ÈDÅœÍÈoÙìWôeÃ.ÖlðX®¢Ê¹Å[ÇǪ5lÙ·V) 5/¨CM¢oÓ…?¨Ë¬GÅ\ÉÅ-Tµ:’í½7Q,ˆ³<2*^utÆêʼn€w–e‚^ÑÞÙªôE©ø"JØëΆ¥ð›s¦†¡'%TAM °f䃪ª¶Tö]ËÈÄlôgú(wËè.sR¢ŒâÒÿÄ)?Ž)—RÏ?f ‡²@fìIøÅC¿¯:bÄ×»g=oîNzZ¥ý|e1AK ?…WÕ;ID ƒY÷kZaa‘d@Íþ8’~FD\-I ĽÀ·3 ´Uöí¸åÓ,ýë’ Gëક}Jð@»ÈƒÕöÙc#Ù·g^!%6ûñuY«ß !ŠCyw,*¢ø|å«(*Ï´€YÍ#éOõ—# ÛzR>ícÞöTþª„W{õ¯ce& ¨é[ÜìùHä°XM~1 Š";P^ v^EµÈ:ûä2ú½[«¯.5ºÊ:À®¾h D»áÅÍ] _[6O%ynÿ-J‡zÌeéªØ4€Çª~«ÕGìi„Û§­é¯éY†±= Bׄqàë¶Œ´ïþ§Ž¯mH ¿3EÍÌÀùÒί„Ë|‡ãIcÊyGås ñ°u\mÖðÁ®† ­àE¦KQò\c!‡ú©ß4~l1N]çnÄHÿ zmEÜ(³ÌÅÚ©k?ŽëÅWMÄÉVÖa« ~ß ._ÇÙt–$俳nè'Ìÿ|߉xI.²FáÓ°'ì8&Þ)cøé›ÙWç ±>ò» V*¥”ƒö# e¹: ìFÏ’±þs]1{°£ÃÓPÀjx?ÿeºbi”b@1Ð"’Ñ%êÍŠ<þkËó¼ÏßÎÙ2Âý´J2ÌË!õ 0æ+]Œw(¡ý/ûO˜]^Sðõ¼1æg›-LJEѵÑZ‘·˜–©ÏøÞXذ¢í™-ãJàsóµáåéCÍÀ‰Ý¯ÕkÀêóô–>Ü4Xrh5§….m«¡ë‰q‰ ~Ü0õ§Ùi B©Î]y9µuµ†È¥Í5Ô¢Á;¥¤ñ¯ÒÉ–°S­Aå·+ªoˆ»’€€ïQ1#kUµySk3Y.<(ô`þ•È 5<>}烂ù¯ð°£‰EðžC÷/ÅÈoiQzû^Ét]Ù¼7•Fø¤/)4Nï8êŸt™*rL±£„“FDâcåÕ¿øÕ™š…›fŒˆôŒº=Íj±…"ÇØ”‚’RjÆ0fÁç•Ó¢’c¥ØaJS Gˆr <‡†9P!¯’T;žjš†Â?rçs¢™?ò¢Ü¬å¢£84Cõv”Òûñ[*?¶Û  X±":æ:­8®ÝTy"Äç»{ÑWäŒ=:%YAÀ²¤pŽOL â™Û ØÐü.#âõ˶f©‰Ë(jÿB¾b ðQHÂÇìcx²p‹6!ÿ(w>?zÊ:?uå¤ä ËF£÷Ù÷âæ+Ý…ÿRFôÿq€›Àœ}$‚=—R™óˆ×õ²•*³ª!]øí'ÂÊîãê¼oB?é—5™õXÿÒaDSáûª„53 ‡àwªÜÚ#/aÒsC}÷#TÚb-Á¡ˆKÕ…Åãª?Ä„ŰÒ $ŠØîèÌ £jѰdO÷RLýpÙM>ž=éÃGŠv$;ÎIú4¾%ÿW?„~ ¥OÏãøÿÔ;‡’!ͰS]eÍÁX4ðÛ›pm ¥77ñ·×)“ÍkqIÆp­Ý‰¨¯=úÞ¥’DPyx«Øí‚)–0$ûµ<:›1Ò¹ÿX`¿3óÈõe ÃcOT_l2PÛÉ%–™Þ‰`›1ÃÄ5–MýK¢QX|Á‰ròN¶M·RxÒ_zš Ï?áÑ…$¼Wß·‚\•T‡È+ÁûŒ×zØd›hýI”úüXgø‡æØ‘ƒŸô6²À¨éR*¯Á¹½DéLj!LÝyoÁúÊcçCÒª‹7Ôã‘Ñ}Ë] WÔLÔlÞT¹üÉéýCN𠙨1R²Áô,áV¹,:ØŒKùîÖeºÄKyœgC É6EtS–c&6:ÐKîOç–ˆlâ}¿Q§E¾;f½ÐÐÈL¹"b׌Š$¦[šöÔ×Ê øíè–-㌼e–,ôÀÛ ­ƒë)§aêÃQJ–ÅuºM†É†ß>"Y¢<˜úŠMŸ})V$¯ Á¿9Ü@ã/0ýqLœ ).ǸŠd›÷—é1œ{'y\n™”ŠשŒ‡×Òç6ì'YØšÇ7Z>Kè´’€€Ñq3™DÙB´í¤ŽñýÎEÎ;5:‡0Ž—¹Q†MçˆØ­S£Ÿl¿ûD©ªõ=t«òs?þY¦¿:=—,ÛY !™YTóÜ/§ókShÉ¥4êàiRâ¿óÉáî~aÎÄ]pXÂK ,ï9kôÔ̹¼wsì½³Ú“Qð «Â°Æ¶…ùe-Mö/!ë¤îi:¨, 4‹ÒëÍE‘d©ù7‡:l Ø6¯×…¢t¹„¸ðøz:Ëë5b‹]ËIi•VÚÌö›Iäƒq÷žl¦o}À¥&â u"ãuŠ_!ËjÿB÷Vç±qdì…Š)ªî Š€ #­³A?JÔ<+}}y*·!úDzæ]¼»‘ãˆÕŽz½UÂè2&å|5ä„÷Ï÷ü€ýû°-/ºlŽ·Á^§I7nþš®!§a£@H+U©¼l2†íÙ'Þ¸ŸÃj{¾©jzm€@Pcý`ÉͰ LUs.ä’î>ŒžÊ”ÈÕ‡cÂÍӾ曻’EþX¸gó¹uSú(GÛ-û)†cùkÈBb.Ö8çº/ýDàá|2bŽ¿ºŠ6ü‡T7¢ïRÏ<]2¥½3JE¨3AC>µ¿G™º Js‡“±“z]Cz*ØPªx©Ò蘻pÒÒÈÞü=Àpÿ O;¶…´ó¥0ìð>‘Z©¯ÐF¼¨ÎÕÂ’€€ÞfžEZŸOyH³)PÀ1ë”!=>o*A˜¶†Ô¡ËÎÃë‘mƒïb^<š(B¤0¬Õ}A™7ôª@÷Þã=l÷øhŸ× ~erNÄçÃb#Ðú ©ôD òû­àV‹lôÚdç$Rµ¢sq/×+Y<¤î^Mù ùuPÛjIœT金uªf¸x±ãÀ)Ñ ñ†m£xÕöq±¼»Ï 2:MÒRÉw°ñ˜y=7EM†A{þcÔdÒg¢”¿­|äÀ“² VK*NÄ‚£~Çê"IÄ[Báßu—.Ìì‰Á¨øÖJ¾áSm07aX^”ZnÄŠ˜øWPl8!s5*îÂNPNè ô,›0Ú€‚@À©§>QKª—ñP§ $ùSÀ`ñ'/;ƒ®í GØ+PžÒËê‘jɆe!¤‚‹Wmt<Õi›¹@á$l pf‰¡¤h,à~ª° êÎé—ÿ몈JýU Êdé½?G;Rưγ@@°¨ívÚ×Ái|¦¢ +%’¯Vt:.*ÀóÁM¦£uù›¤2†­€™TšEè_½n¸c<5î¢Ð‡õæ}ì휊$¨¡KÊÓoƒöË6걟\á˜öfËO·ªÓiÈ1ï^—º!æ^5 O‚¸jèæJÖU'=ñ®(ïá¡'ÑAz(o)›ØxÕ OkûoÙ±s±¯ìôÀ K´RõíüÆž}q§ŠrëˆrEö¥ÙÊÔÿ2*Šç¨ºOåw£¡Ç=]gÌ‹ðÇubÛ©ˆ¯¬{h²²Ìȃn Ðï×Jn* ö™d×”mOBȧ7ƒyJ";X:IFczëq¾¥5ß„Æ,ÒR³™üéí!×}Û¥Ðo®‹Ñ3W±Óo‚Kq½=þŠ+Öb„oà÷¾ÏoÐe¦Ü™_.õ{K–ÒrðX喙̨³âèáxÔ¬µ¤ª’€€±éЮ-J®±3ýÁüUÜvíœI‘A´=¾·¼dBþ»âüÏͬ žËø¾ÅTkÊ/"f‹¿—&µ©1Þ9AÞˆ :ëÆçYÖÀ÷`™JÞ§gN£ïjÏ÷w hÀßKMÕäÛã_ôÐ8Æ¿Y)š¼R˜d8åÎÅ3¬²Þö ÅÜ„…†S,Ýž[L/¯¶BxŽ¦â¬Šù°Ý¢ mZ‘±`üOñ(˜hs0ç3/¬ø¼ÆÏÃ)ƒ&¢Ü«S¶!$%$RÚÏ¿i}è˲|ƒ÷é—¦ îêè ·„„¿ ù½ãi(RXÀ1Û©Å[ÒBä:óˆ´`rð.gW„V§Þ‰î‹]muX %?ëA¾"eàÈFùÜŽ‰IÿNÎíÐ>2r ödГ܎ˆ8Øj\b…àÃ!¿¹“ÎBœ·T§Œ’]_Þ‰$A;Xá·£ »Õ´²9ÒR"éV¬§{dÆý÷ÿ¯DXÃÅPT☗Ûp¹Þí§”•ȤUDs[´n•‡—E§âíW+qnI?Q8Uú!%š—³{íUó*j+ƒÞö×8‡ku÷áëžI÷nø‹´£p€¦5sÏ£³TÛÿêßËMÇ{æÐ2ÿsÅÛ;ô,íb.Ã~Ì 1ºyk)þ¹¢FSšPõ©`G€ w :ŒµEéðj1Ö˜åìVÅ9™+ýøŸâØQú„" ^»Lº˜5~šöm„”(Y›Œ?ÔV§c[O3°~*UÖZéb;B‘Ý÷ÍÝp¸n]]±ç¼9'7=§Å&AítèÖ[ì$•µiw@7þœl„ùýÚ¶3B /ØÚáDÃð‚§yMÓEŸÌp,?æ>}õ2t2ÝÕJrXX¯MâÆŠˆ§j†íbe¼œ®ô‡Þu!õ+eK(z4-~ZE1ɃBÛº/¥ãf–AœÊãFë˜5XqBØçœAäºèƳ±9ý1ÀàÙ}Ø #ÚR™ZÀšh—BG Ø ÍÑ\eü<Ãn¡¶™þå>¡.ú©¡ðëãuÔAÒtwó„³þna!¶uøTä£E úLâð¹n´ðöÎò‘|„—‹ªd›©Nðsh–Å{1G°ÏOØJúh!“ÌH§{/ŸÎÒÑFv@äuîÖøkããê¢H؃c×i’€€ÒÆM Òé“KÙ…‹%t&êez»©Z2 › mwôY`• C5áÏʼngÚ þpŒÝ·m-[+ 5õU­bìW°S‡x.ø†‡m1÷ƒ@Ÿ‚›ÜbPÞýî}à ¦cªŽ ¦&&·3 ÍÝ(8²íQ8œâ«Y7š–ÒÓv…+M鲺¦Úú{l?ïáÒ¦^…ûOZc™Y$r2*‚Z‹+ôR=wŸ@EgBuOHġ̙­£`¸î‘ÓzÃIJ^Þs½ãuŒ³3éſಠ®IŒºÞýÚ}ˆ†çHÁær?ëW·‹‘Ù6ª¬vº9ûÐ.øRlt®É*ÕŠ/ lºuÑq¿hNRQ00²tX0™GCÝ“wþ˜„ì8¸eŸö×Ca`½òÇæ´j±Ã_‰!=J^7Ùèß\“ŸÑ¡¢o¼-‹>|)œB:bE~oV½Œ\g9#iÓ’ûÛè;)‘!4²s·i£üg×¾QˆÄ,y2iZ=ðâ–ÔÙ£où¨v–Ä·@6ÍAg*S¿¢m.+üeõ·mN%õ®™LôÒŽ¥ Žx°KÉTÉ< ©bÒª;>”Ñ©|P48@Z vž|±~Á›Ý[ rÖ´ð60±Ó[‰(5ø“F¡Ú=¾^ªO¥/›˜A¿Î-u–ã¶Ç ¸¡¹°œ‘ñPM‰ êçLƒ:Ð4ÐìWÿRþ¬ªt§*eéý)þo«03’u$ôÍÖ®z—têHTŸÒþ6~ÀBöOLšIFSô`$盵[A–›V®BO9ˆ]LèÝÈMÕäÎ~Ì?~N1ûIŽ”âº“éñ”¸ä"'rëÐ5äHþO«ùß`?ÓP•ïvÝ?JYê,´Èx•ºˆŸpv×Ë;ò0\aæƒþárDˆ®QR´dÍ¥bVÊÙ_Æ-c=£Ïd œ® £jé1hËŠú0.NÀ€zˆˆÅ‡nœ´³JXQ4ñe}ø­e…K›3œ=JpB%iËž .X´ýž™¯ÿ@)^°RÊüp€œ)­änkÂׂ¯y(‹˜/Ã|·¡”Kƒ ¸š¢:öºc#§.ߺAêQQ˜è ¬I«“/ÿÝœüËÿSçÀ¥R’¤«Ü‡H`´ía¤¬Ö%½÷]â¹GãbÞ8Nÿ\ÊÕô[g&œªÍgâøh”5Î|HK ºµ•!ŠKì וKü7ÿí¦ ¡ÓEÛ$$°°ÆOÂÔŠŽH\b„ÍW¼dÍ ù³ ‹|âä!¥z¶@ù1ߥ—0S—àG+G³SD-’ɵ‘íøBv f²~è»Ö?†E–ð@KƘtu%t_ù^7¬a$šËí”Ô/dò3ЌɴÎÝm´™YU ‡QÂf’ÁUf­f½-”xpw5mÙ:+Óë Kq~¢9Ü*ž] ÙY†W¼Žàî]‡ ®Ìöÿ×¼çÞü¸5‡:ðU†œ“•ÍŒ=±—ƒD\è0[„H‰Ã9‘Lr ]=Î&àW¹ÇøRÉæ(ò_-lËA¾†X• ÄHÚw8ò•„-]«Ž•u2CØnW°ÄÛ€n¼wzÊ®ÞÜwš7çû€dÀú¨¥‚ZH´røºé™ÙFt´å*ÙFð/^÷v˲¾ êhÛª07+ÃìsúgE úÊoÐh´oGâë9lì ö ²¿UÉëÚŸŽ±Ì9òÇÊ §gޏ1SЙx»/ ªÛ…üõp@€«äT‰,¤å4.DÃñ rIÙaÎøCpê_KáÝoûc¶ùU:ˆô+ÐŒ@—e‚_UPRL˱’€€·d`›qU%íF®¿®œ5¯Ö,\b ¢±m‘ÞÄ_“a@r3B=P5˜wÉ­RñßQŒ8Öî™Jre‚/”ˆÃòèõÛöz)ýMµw6Eç·Â„Xe8©ÁJ©­‘{Ün7nTµ®±øí°§u%j«ókvô<߯ò'Œ´Çù¹ŸJCËœ'$#T!‹µ«op>å“0-¥ÐŠªÇ€üÔ⊿ýú û*,Ç5öã +V79˜’[‰Ù˜Áó›Òz7ž°‰ ÌÒJˆ ½rÊÝ îž·Ä $Ä%íñúR5ü$r\#ñe˜6<8Š¢›U›=5̳Üq´’Ì¡ÑX:µ²í_ûÁ²±a¢Ö+A[À¦È!1H…uÉ è<£“DEŠÜÔpt&óWð.¶j^Ò/ÝsG,±Çì4²|˜, )”m|Nhð §7_=-g‚ý§J.”á =_£§©Q܇‰­}I¡šž^Ü\ X±Œ¨àO&Ìã~U*ã?Òþ¦r³ÈÇzyË·˜„Ä~K„¡µ™t º¹ç7 HÔÌ)×·íý÷«vKDÓhÄ’Öß¹ÛÙµeN ÒÖp;Ll®x>eô,ˆÀcé}œô¾»'¡udÞ2”Ðê%çel#“!5”©Š~ñÎH,Qš´¶¥«¿½ÁëKŒú$•l̼o§ átÐÏ“ñEÊ÷œÌÎÿØ#‘„û`š©i“T.‘ƒñc, P;*[¸ß;Œ3©Ë©œh˜é lì(T È’ê»ý:C4çYNL´Eb«»QX+{ëâ¤Ã«ànŒ4¯C­¸¡®í•4 ~J¡Têá®xø]¹Ç‡ô´bc¹PM—T8Té«›]AßÌ£"Ï"Ž·¶S47€&ÇÀ¾àTó<ß÷ý:×#^ÚõÉÑ ³׈æ U¿ÂyK'‹ïŠŸ4à^ªËy«:ï¹KˆTpްÿÿ[âðjV§Òz„G¥Vùü]>/ØŽît~êÂâÝ®[¡zG ¾NÕÇ~ôœ¡›Ëy¹Þ卯)›ÛxÇ çÿ´¢+·xŽZþ1`ˆžõf?äU—\¹"ø@FZxxÑÇX?ÍßÐÜÇCÃñ c¯~ð_÷ëq{[ÍÈ!cÛGZB]|ÚìŒâÁ¿ÝAŠí©_±ªFïÎá!0õ’€€ÖÚì«ógãC™€}gåÀA1L8¸O°4 Ež0U5]ÂŒ“Äð6_P+Øäýº@Ê»ÖPê‘2L/åÞ/œeËÒù:·Íƒå¼™9oÙ´>ØO·Ã8òÕPãCÖ¶¿ÍבÍЙZø«ò¾LÄ_¤³¾é¥lF¥IWù¤l|öHiÍ¡[- Ý:zÝn Âi í.ù®nQ“lä -y ÍW©©¿”AÖþ1$VcMÃÉ ªµ€Û© ¡éD¼übO”Æ’óɳFà0+ŸÈa© Ê:šŠE4äÿ1Ÿ›[>Ê/z!@`¥~$G)P*íeÊuÿ\²XIóÌE/Ð÷äÿû»tŒê²ôŒ¶_5 >v’•³ðïH*™éÓY"$Wßv(‰ˆa’U·o¸"ŸF%ioŒ=جÓLá ìãUwå0øG‰÷º˜Üô¡h^mWwB9óSà00#Ÿ ‡VN€A5”ŠZѦÁò {3l5’Xãe¬fmý3{©2àø[TúZ `¼˜=}>nÇ‚VÿÑᕨx^ˆ1ê¡B;³ìG¤x2+oôdж*pØ{/Y,ÝŒÑÀ]V̺ÑÈd?å˜e«‚,w,¶VÉâ qȰg-AAŽ<¹Woúu±ŠQŠ©² ¾æ!¾8½ñ¿€üÖ|ܾѫæ_Ó¸G¥'l¸+Špp¿DLl•Ȧcz:_;¬YýþevB–<=Œj/à¼1ýHtƤEø—ØEÈ¡¬-óhø¢’äìÆ3œªÏïŸ÷{EœmèÐ0w¿?D¶”%üžû×{] ?¶Äz5 z½ûû¼¼ñPí#Ïý 5)0l´ï³GMÂüG*àúI²'鬱WéÀ1µÒdq{ ú!ÂáÄäX¤Èȶ0%(¶ «-: $+3¾¹}5TÝd"t¿ëæ+Ä2ÉÞ"Úo’€€ÃÖeyÄ„ýh ³7ÔwŠfU3,Ù ¦·ã-Ô†zÓÆø=|ÝT-£*ó}Ó¡ë™#EMñpK¡é‚”0ÄåçˆPˆm¸¬&ä¡*aÆGQ‘dˆcÊ_ýó€ûÿo»$öØÈßáÇÑ,P7Yt‰€›Æy@u‹„´X«µIžÐ)ÛelºlŽWЏ eýœí`5ä#—Õ@r{v5¹:è'ðêìUSŠ<À¸I*©±;ëU»H ôiã3æ¤WXY>Bàd˜7=WsJ\C¡~ËRæ5­{Ð#B¯/d=À}òcRHÛ;Mƒ©Õ¨ïG&Xyè%#>=…mq§™mZÌ<$±q'™c€ýÜYÒËìÞ){ÏàØâv¨–Ñ£Y"—¿"3ëP°æšª„XÓK>k”ÚüI† |—ÈÃáð¬m‡pJÔU¼¥Ö­»çÿ B• ²kzuSEdåŒý\'öoðøUáMƒä;9€Ÿ}ÖÕ9Brf%·û1ï‘ u¤ ºV1‡FóWÀÿª ñ#5fOKvŒVÙvÓú¯CŽìëÑäš±`b€¨Ä2P’êh¼íKj§%fcÙ®!›š«Q?·u€yk²T;Ï$ŽesèòLðw¶MÓoþfX¦»Ú^váÖ‡ i€í¯;"ó†«ÅAÌËg˜LÂŒËªãY¶ÿ},I Qå!^!VNäjdªÙç¡ìÎÏô …3Ébo hqkÌì7>ÎÔØž°ü]_š 9‘ôÊLô娴~Œ¥\^ „xPÃ+RÖè¯pEÀ.›$>;è|@Bˆ7Ýþ#ࢣ½2h“ÅuV7ŠÇ1¼|1=Iží‰·àO¥X¶sæ¶ßg0 }ñ ÏÒèÙÉNêOw§\8êåui•:¦»Ÿú₲$ïàƒ‰ú/ðŽþ b:!…sp[h%«„UjãÔ+y£Ï˜Àäp‹MÖ2j¢Uc%%ƒ:ßæA@5OÅ©ú6Ö–¸¢Î ËÕ~þȺ14Ì¢î±a"é»»ôÛÕ[LA_kJAe{˜.Õý?‡ûVå.ƒæ %Æ:¿”)¹WN#Î^Xu¯]_oüˆÜ‚ƒØ!º—êÙ-\Â˾)ÞvÑÇu{( Ã[}‰’€€Ê^Øn*ûª‡tOÔ rŸNØádMÇÈ$¼µX.®YFm7ŸÜƒ~ ÕÂÅÁï OÞGüidóÕ 'R"ªvî3 {›1OÖ Õ&èÎTBq@Ó÷qË¿ã²ZÒb°?—€DEÀ¤6™É…9™7,J¹²¶Ð~ðâ®ò9>†{ÈmŽõÌäÀ*wù„»árú žR{ÉùOëå­v[&x¹%.Á>wî±tƤ_y'›¨’ õ&°Îq¯êб²Š‘*tiÃkG´Žã:•ðVB™bux“ ×¥­Þ@½zc°Ñ)‰âf%{Ò÷ŽÒ¤~k¸êÅ þE­lJ¤iLå4XÑûgܸBD²QW2PßO²Š6Ìl÷Õà’¢|¶æà-‘ny½ÚUPÔþ¥«V`ÙÇð²‰l³vãh(„s v”™ I¨Y§¤É~Íß»?­§­óêB¼pᵦrÐóo™á³K´à¤E7ÞXT|{‰?¡9VQ8MírÀº§§µ·¤A—L§¶]1 ç†ç@Âõ£ÝšÎ/aŠöè²N5ÕçY«ù=1…TÔÐ`bù—°}¿ŸÔ?6Ua#äu÷.¶z;Åa…jÆžQÂÂzþÕvænéS°3/çB¦Oe¹, ÎýuØòdæQtÅ1ÿÉ"a`“ÂÖ a¹óÌ™0MLIŠ¡¡‚`m›,£HÓAüÝ·ÌæóËÇý,‡_E-÷Ifâân ôÇiJ;åÈI^qv/`ÞŸJsô N|Æ]²Ê{ݾÔlIÂF„þ l Çùß)öNjН ºKr(LAþ>Ê>êé7dßY,n²T2”mcÏ.AåªÙfËÇ{ ¬‚#O-2gåßœ*ólßiJ5Ke œ÷DšÊIO%Å%¤ÖœNTøâa6ü203‹/èhwbžŒ’Ô.Á¬‡DY>æç¡†œ¡Ñ(ðñå¿8eâùçx1×-VkÎóŠ’€€º‹Þƒ$üX@¨Ø€#ê¿„{Jÿû›êÄò=-?Š‘à7VÊ·V4×6¶3a1ètÒüs@è^Èûf›7‡xP’fwE|HH0Ïò3Ž «v“JŽætÖ$ /=äüƒ–²¹ÕqiL"¦M Ú5m¥éè›uƒwY&ÃÂΊ¿­åqK÷y£´~!N+í5 ”tü:^»vÿHD“v^×ËæíâbëWªÏ¼ÙáÓ½1dÞÌ!åÎ+{÷™ÝÆç½JY-´¦ ¨MùÜ/nܪEÝ)ò#¡O C|™@™¨) M{žç°|2U)ÃCžPŒ“аñ e#<%9©_üih>TÞÉ­“)8GŒ¹k%}Û´Tœ6d°¯uŠÜ<;³¡WãÜ8Ë\óÎÚæ|€ðFm±fãaˆ¢£x¢’¿c—]~>Ò¿°Ìcʘ¦æj4B/ÕNvjW§¹¨"Ѻ¨Ýêì­KbÔ–VQˆÈnGcñ ÓTëå=ý—ïq (ðZD¨U}ÙT¸øÈù²rr/°;’‚Âþ¶¡¯NùAð²H¶´A¼_1uQÚ(wn^°lOÄݸc #ïfÁP}áKmTΨ%²)³ÿšS³‚x7ÉXtØK DzK"ñÛUeÙ–}R²§ÎûtØ-¦Ð–Ö ßZrHv­ æ[êÃ2ì5Ag®©žÎ‹ÅØÙÇ»E4•€P_˜'ðWK/pMb”1Æ}üW›dR‘Õ¥ÎHß%ÒG‹Ù§·KÄ_ ˜:òÝØ0œ_;2ÈK^µ¼XI?²N×ÈND=Ù»O!Ê5øë}Q˜ŸãŒÐ:Ù “[mMÅžSuXß\ž´ÞkÐ.4(DMéK:Å|V ôå˜[ÄÙÖÐb ÜÄ®½‡ÚeîÀ¤ýLòÇ[¶ûö!„à.µ ¾Äcز¶kH4¨•%ÇHæ·°/2‰p@²…¡~tÔ9I"ÜK߯©8%t^ µÿô¡$ÔLe^Ûc8X{Xœ9~ôW¶3¥s™úÜæyä>½@Š…Zzö;í;Ü.iñÂwfÆôžUsÂL£jìE =÷a"Š­ï¾³šô3 æÂ¡Êúô'åê™t´V%̤¶h©&ô4t·68°îñ›,“ Ç’€€Éù¨ŒSìCA£Ù8ÝmõJ0‚¸Ëà£åfÿŸkœëþ¦¼ºN˜½$Z)Õ>Èw ÿøL"`e%ªiÁ6}:tì O3v¾Íåt!¿ƒg¥ì´îÐR#v)RR"äÎüT¹oªe¿ÇÈ)ÄÌSó^›t…j—Yás6Þ‰ó+¼¾X0v‰Z\t8rf} ~Ê~¥Ä“!‚ßñŽwy…îÓ>ª$ßf¨S¥Z˜¿‚v3 E·1{R‘ÅÑfŽJ#6º€ nr%)ÝäÀçõ³,éi0)™¾J7êb£ ÈÖðy6(H¾r!ÛÓ2ežË¨)Ñ´ãÒž^ðï #x$aºs…NåzÃíjñÕª1™u€¹æ¡R~ÓÓînæ%û¸ŸÔZzðÊn9xØ1`ú}Aï¦u¢~'?gvå!Ò¯Ò_ïpXOt=a"ü­ÜÏ|:…¿$qf¡ZœFÃ8è©—¶ê8Ÿâ§k–)åNû=íà ÕÓÄK¦:D‹oË}N䵯 Ëêl.Ø(Ôªê,år&'r#Ð1Á'ðœ­ìW!’ É;ÕüÏ=ës-›µnËÓ\9Œ sC5aëñìU¿ûã]Ëç)ç¢é!Ýp€ÖéÑëçôE%¨&ÉZ}™»~¨žcJŸëäAKhˆ8''¬è!ð!éô‚zJ@¢ÎËDýkhƒÌ‚ÇdØÛ…¢·7È®©ty¥O³Ráží³¶þ²ÿ,…Öš…¢z¨ÕæªÛ$¯ý#9äáÿ¯Ä¾7vêhÇ¡$üÎõ.4œA·ãéÏŸ«ðÝ¥êâk‘K ’€² 3b*‰žð*Xå<Ùû+LW¬¹Jq°÷Ç>!¯Ç,DûÓ¶ðY_q¾Å4,ÊLD½MÞê}Õcb’ý%[OMÀP:@[¥™2• AfК„š=Š'ɼU6 kS„´¥z¨i÷Ì÷9ÿ$½o¯œ`L}Nü´£àôZLp­Ê?õªÅ]ìÖ¼C¶ÞlNa· ;ZÇÛêû%qéÿ‡+£T¡ë²â>eû™ÀYw—& Û(Ƶ/€_M(ó‘ËÓÙ1’€€Àö…Xàõ‰êk«ðwg”¯¯9-);[²©©vúŒ·,UÒq§ÊœEœy8É£^qD’×ïñ‘ ™c¸Ž:¹aþ¡Q¿Æ9nu’ºs&@aœý¸¸ðJÈ|’SâÈM˜¥®ÞÂÍ ×Á³üBÓÞˬÓ×ó;mÖ°£½*tÇ:$Œü#¡™Ÿ·GAÃNª.8ˆˆd”ö'6’áø4Õ³×4ÊŠ¨íª Åï†3aô–K·3i=-Z÷6x½°ì _Æ‘‚ã²XNh*üΕWµØPýÍuRɦ::$@¡âAPíü–¡i“Ìþ?rÐiè,‡}_òÝ#ßDºÝž¡Ÿ‹Jàk‚FHã#‡Ì:í¸§¦©’)ßDé c7—Eû%¿wõ×au`ügNJòŠÖ^.¤%Ä1øñ(PÄl¡Ò¶:˜áþÙÐzœPÏÛ½ÇL"ßšæ—ÛôŸC*œxåW1ÅõÍ–€Ø¥Ä7®À°-DƒKT¸¨c²§uT,¡Å0"ï;Òáñc]Kp‹”à(³/''8ÆT4ë<ÛYg;î8Ò컥ÅdVôéÄm+D6ÙL£Ú9‹õ®/{xz3:¥Ptr$ïO n#\êBv$–%4Iœ·’zjôÜËWõ·”íAz?z:.­9QL¡ÁþzD»D©òT4Ýéš¶4ˆ1ºÑ1Áï½õìI¿3Bç¿[žwnCbw!öï'ý4úÐ#^(…íJÓêêSõþõK=)%(/#(ö¯-º@“¿¶¬èÅŒïwPIÌ­âTÅåSÓ?`í“7yI=ù™û,÷¼xÄü(ƒmbæ7þÉR]oR‰\¸ŠEÒƒoVxÚè½È€M(­—íLà I÷vu ý»í`©àY~vÛ:D£Y‰îç‹ B7süô—˜!Ô“¡F…”¸V ™ú9˜ÀV.ÇQ´Æ×í†ûÖsžFµ¾®Öø´œ¶Shy}ÅìÆT–> Õ²©¤iR2ËP¦ª‹û7ÊCe2•^àõn4±í”mš]jܦî²d>ýédÊ4¸˜L@<»‚"ÌܛՉä©`0©j‹úˆ9¸OtL¢8Âp|§2c³¤>“V†·b8J\º)N¹TZóÔÇ´ȸJ€Æ‹Í18™w³í=<wšEº‰/”g÷ik’€€¾ðoÂîÖâ³q1Üp ®m ;Ô§A„Ùºí’Ü–fa)iû¶Õ(œ–N}]ERPêF2´þàöá®jÆÌõiÚÄ_ðó\^V1i.œÙöL,ÁôFËÕ³ƒrƒ40g¾-÷¢Žq˜°›ÿ JJa¹áwÖŽéêu‹4F½£YP‘ü»jqÓõöA>&áÅŒåÈ#™B¦Ý×afd,B7¦³ú”f­Ôn›ä¤Ê€däê ·Ñ`Û& Õw¡£ÂÙßn2,ÖÆ3çUE?RëÖ%À()ZkVòžk€I›Ï;ã^•þï7þ¢!“¯ñ3 öýe’¯Eï³àâÄ=;Ï«0˜V=v‡ÁÉ¡Cô,C Ÿ‚̪»÷Ó]–ùbþó4JJ ™2×4I$‹Ðë^´˜›³ÌÖ€w *L^ÙOÐé¼çÀ=› Šú×nãl»¨;½“q c— ýof7=·é ›ÒÚS<¾j "ŒEò–“óËëÏÁòWe•ê.ôAÕ†]é±ÿAW[ÍW6ÂØõ¬|éÍ)x,.X]Œx>ÿ K¬èãÁ¯Ú_ꤛ‚ÊoAE ôŸ‘ h¯N 5^ÎíôWïUð{µ×ù{¬ Š¤Ç¤#²«_#k?Øìù´d-µ›ºÌ÷åxÏq(Ëh¤¡5"í£½˜M!Ñ_ ø/‹³Á›G'BÔ&.Ͻ]K9 ú³®q‡lˆŠù~ªwd •C æ½c«S¶ca¦öOí44ÈO§8LH¬)m/xL4 `טÆê·¼yx4Ýáù %g%ùÏâf÷FðË|“[Q´I’€€øèN9Ä 2…ÙFXpYI&¬Ê•×= î™Jžmc.ÿ®+ü b‰¢(gá–¡.#>.égZ ÞO¿›#(÷œFI“™<ƒô¾è E¾œ)@ê®aòØH ºÉzÆ<‘èH˜YÐÛHx‘=­‰uòTsœÒG‘ ù4©OžÇ ÁK»È‡2_ß§ËÌ™J±"È1,L{5ƒ¤4™¸Ý*µ@”Ê—èp“ › 4<‚Ö‘­9.D \î *$8N›;‡ÿJÉ‹{ÂÎM2蘟¹ð}È.H ª}’iM+XRÆÙÅš’fŽ'óòÅ¿>i“"le“×mþ¨ës‚é‡dc¿oGÜ¡” ª1¡NÂK¹ÔWúºE&p–ßÉx?…Z´è@‚7i—Â@!ˆ_ÐJŽ¥„A£[_ ûб â£ÁÞ R“ †°Ü?öÚ" ÐP÷ä5¸-c/wzi¯-êÀ5Qbl!Œ©d™kÚkÆ1B5éÀ}%:lH?À´¯%ø7ö6cW+vGuöû‰­Q—3¢%mþ­?9vË‘w=-F28 Cyí5,Ra–µ2¹ãK‹l|¼‡[8a9Éßn|± FJã\qA´’# Ë£È'˜Õø®j·Mkv+Lv5¿vƒªÇž&&qEVµ9áXy2b0€­Ñõ=îu¥(°õE¼(e¢ˆ©ãÔÀ¹£äb×q «.O< ,tyÜ5ZÛ|¼E­{ü“©›½[|+ݱ± l!M…p¢H˜Î¯ö£~Iº$`Œƒäºä\à8' ‡ h6v{J˜øQócÖÕW­¶˜NgO–>gÁÐw¤Ãà '‘E€ßà]íLÆ\ÓDTJ¢ãž¦¾$ï2£0äzÓ¯‘íwFЬ÷#¾m¹÷ß' tIj·}Ú¼ø»Jòì.c|­•àœ‡ªl‘.±ÃåR𣨩µJŒB³Ì6‚¿çp•cOв×̵’Ó!àÆ¾à^9Ý/Væößqëq˜€K[•SV+b˜:>DT)¸#RCеR ­ÿ룔Áé–½öñn/+ß«&3zs2'T/»Ój¬¿¬±)y- ¨9c –ÎQ#éx#Ì4½Duºµ†n]>¡vûXÑ®ÃGëoÑòWÚ,¿UܘýõC´¦¹%á;9‡Â›S’€€Ø{;f›óLe²)1òUÈÊzî· d÷$L`þû_•ŠhKé©=#Ï Ý¹]ˆn=ëðPs=º ¥˜À¬MË] TÑ´2 8ÕÞ6+' >í'’É“x8¶«ÔYîŽ+1 ôí¼è_Ì¢Ž›5Ô×c®Î`­úc¶­@Pq'¬2[oÇÔ8ð—þúíúù·Ð:uË"ŸgL‰R‡4@6:Ì{m­X@XèÕ¯êuïûJ‰à!qä"ެeJcéÿcÀà—»{¹ï¡Iý;/î| ^o UòmŠ;Òf=æB[¹s½–Ž~Ï+NyzS\‰C ûâ![&}vÍ6´cý˜% ¡è®zGjÞd–­«•`%xD P²OÊ/•&ïñæ!å|³ôº·F ¢M’ú|=:ñþým…ý ‹–šßËJƒ•/–ü‘ã ÞâW‚úßýD6P‰ÈwI-˜R:c·fŸ3ƒ;Ùák¼ÒtìˆÒB™mNÅÛ*ó³ÉjæhjF×9c b,dr«H©tó˜tÔ‡x\ ÅX„M6wYf[>áëO÷dzô:MLÌÓç·2²H’KÃxu û^2~@ 3‘£¶®Ï¶ÕVÅ16<š°Éí¿X"—\‹ßàD½{teVh˜¸Y1÷¬ÎÕˆRAº{øfÛ€(~•ldrL9«ûÖHF_5LÿužatXªîädL‡â¨Íç 㱤=o#¨"'©£1&D-R&o,ób¿”(›{¼(ÖΪrÑìñ"qRù=®£¦òëaÆ6°eÛ$¯«0ó*™Œ(Áug»½ßÂYkj_³‚«.íè‹:{õy>ÄýZ|Ï7;+Ò"m;ü/ÿŠÒ’µš…†¼\SWޤ©u~Mñ8ãÄtp:»BH–"é:H´À}÷“T³•ª?^/T䇸P40 §UüŸ”]pç»» ;ÇñY}ž=ÉûîŸòÁÖX¦]wXv–ÜQiGœT3àj Q–$'Ñ×'…Øõ˜È΂&;›˜î¶¬˜ÅJ‚N•Â>uärúT¨‹´ˆnzÑ=®ovñèBzŽp ÄÕ]ÉÇ6^¨E÷xP7ÊMا Åúý³øx5´Zb’€€À|œ&u³kŽ%çï°ðè6IøùMËTÿŒY,2Ör¼ÍWû7~K?tÏ6ìÓ(!Ï+ŲE.¢½ïÖ:XN ºà±”ߎ%]J@°]aé½½+â ]„¼Ò¤6ùàìl£°; ¡„¦_\çG"鑯êðîÔ0!g ªZ'z`®7[À•ËÅ'ÕØìx£YþáµÞõ„©msX‹ö*&Ðæ_†¥J…à=eáê ¸<“¯3 ÙÑ+:(£x†ÆAϽÐ<°õ¨„‹Êóý/q:½xÂj;ó$ȼïÍ^(¹…iNí"ÞQf~ƒ´hôC¼Ë¿c^PÁàÄÛû]o-¯eGRòÂÂYO:·mù(!”ÛÄI•p øðun€ÜÇqJ-Ç„^¸Âø6ÅØ¯tc%÷¼Où ü¤]|1Š1¨;i·­¶Z´¿Åß Üáò¹S~“¿1­kbÒ±‚Voà¬ñ Ñ€ÝH1V,mXJöóY´·õö•¡¸¡ÜI07Yn`Ó4Õç†/9ùñ|>c›p ¼÷ŽŒ'%>W;cLÂ~é©Iæ}ìÆv©éÃQIöUÀ[(„d«™ÃìØëMîAÚ³ŒY|÷ÝLydCáRqžýÄc§öÞ·\¯?7×Û?QæM¯>ØMHÕ)To§´i¸2½ò膣1ß0¢xJ½ŽÍ"€†¸ºÝWÏzÐÁJªZ…ÈÖ*û½2ö¥¦ÚºƒEê>ÈV½™pqkgvÕj~š÷†ñÜl¤[égŠ~,ƒœ1¨m˜V]˜ª·‡ÎùUÜ0*ŒÅ½ŒŸ"ÏÕä@ÿ C«tð)À޶²’ov· L¾¤•ò‡!Œ %äÏ$ð†uîíü|¨ƒš“± {5øÑ¤÷á7®YÖçCÞ¥|cX#? Xæö„î•öt7·Œ‘>lÜUi‹ ðÎKc!â?’+¥{ôygÌÒÄ^ÍÛµÞ±7EÇr2·îÙx@»KêÒË &Üï§ÓSé3²ä\Œ—¨Å­ã¯d¯»ú_y†fí»plg•‘#ZÐBxÚÆl ±Ðqhu*6bÉëϨ„Ù*¦µ4ñòj d BžUÚ ƒ ÀC^ÖŽ]¿Cª‡Øa§¶PBì jzÞâÑ~wÐî†ÒÒuJ°ísà 7œ°^Ý/¨SC4ú›xR±R¦½Š×ÊCžFlXMjÌKÝ–Lkž´L#.åóˆà÷'á"[³kŦw. 9ŒAÇù(üò zßáxûñ‚l¦ÎØ>Ÿ·€ù%Ý{£µªëàhÆÃ¬C<•~"·¥^[ŠÄó"L_9è ñH$0½íY…(ÜÆ{oX’€€§±(Ü Ê¿Z¥q ~,o ©Úr}0¡ó/À ÎYx4µ÷WRÀ’Qi!ÄG–ìý½ R¼‡ªtÌ…ÜdWüÉ»Ÿ­ª—öºæ•ò3›ƒ8h® ¿ÛZ.xÕÌ…—O¼Î¯gÖ>ÁÏ4U±ñ"#ù‹{’ ÏeÕÈòÝ#†­äJ ºR©ë&Öàh4?Õ}!‘VÄY•jÒ r@,rMÏß_OÞ—»†‘ [Û0dãJ“ò„w*:9 ¦oƒûa|.ǃêlât1%Öÿ¸ÖÂ,¿B\øÕï§ÙqèCnÆ]?8) }ÔUl‡›vó_úC" L&“#69©ùœ(zõAéV?„¥S^]Ô2tôÕ9ˆþÍñfÕQç~bpguTö =›ë%øcP¦MÚŽ¼5èÁ÷xŸ±ß€r´:Dr8'³8aõÒ2›Ò:¦û¾Ä;26çøzÜUÀœ¢PéÓËjí1ÕgiìÚéžÝ²3ùôT]Ñl++ôƒÓô{Ñ)ÆŽ 5:š^q\|¡ +:?œn~Ʀ¶i .u“ÿ*Œñ=ü ³W%- Ps÷˜‚æÓÐ9šl­R©xšohÁE©çгué{“KÏÝð&Sµ’ âñ˜ñ^^ÀøvK[VYEŠØF@«OâÃóÕé$XÌÑÑb›ü‘2ŽÐJÚ½Éñ³ßQ¡ü„y}𾩈Jk¯¾ú¦Túç*zÆP+Ö9@%v´@¾Ù ©(²©ÿlÿD©VÔÛñ`ѯ=S‰q_€»úƒÀ;¥M|)Áä„©®j ¥8r@æuÄö\¹}‹\ ÿœ‘;ü`ÖS Q¯ÍS ýïPfŠ#jØû=ò9a"Gªô5Û[àóEŒ|aí9›X©oeÄ p /¿3a?WÛEô˜ÙuɹôHóGÍH; x)ÕŠ_|ˆ®Z½oü-IŽËÁŽIhª°7KS“A»¨ÂW­ÇÉæßºvBÏð׫MˆcÍPŒÿËû„‡_~—E©ÌÎÔa¶Z}\ü“sö#´—Ï(ÕŠìT£)m'Rîçຆð0iwgb=Isg6Å¡tÌE” ?ÿ"2%íú ư2å/ùªl&à éŸ×]FÕÃÉ¡VäM x ZŸŠí…ò€üÄÈ’’€€Í66‚J¹0h¸&rκú\TROLœ_QBº°ä^,¾XÒ}ˆ7VïXÁsвáÂ]zbÒ»tÕ´cÃ^TˆªšÝàç‘pXAžË=Põ"&°¿ë¯Åüäryø¬È= aHDÚ´is&EÝ>#§A4èKqo:ZÅ·†I Þæÿo‚ÂéTl#EÀ@²c7rÂ>ûçÓô,î¿yÍ ¡V;š• ïr|.¤h׉pcvk/Èä¨ïŸ|•©1a/oØZÉðíøÁuÄ{äE¤7Ÿô*÷kÝw]ôhI–Ñ÷öPÑLoK@TyµVϪý–ˆ¿ñÅÏ´x¨:Ä̧Ôž\Š9³ aíñë@{s¨ü´‘žÙåÎZá±b†v'脵½—CL·{W“×$“ĢǤ¦s³¿ø?<Ž Õ縶òªÎ£6èíy¼Ð¾ˆÙ®qþ³7®ïÑ<ˆ'FþFäÅÏ Ús}†Iì1ÚÈ;úÂð¨ÿh]$@¤ìq‹7Ý–Ê„$yµñ¯«+ãîì—µºJ¹…˜)ïÃÌ-&Qš¦¸m”Àâj÷•ä2¸’#~QÄÙç,0ºò\!³Ö+„÷ÉãÄL±}ä6ýV?MÖaž6)Ñû‘Wc\ÐsÅC6×þä ²­FÝôÁ±·qh¹Õø|Ç®qÃÿ ú6´¸™V½«½ ~ÍÜi„ôϽ¬ƒq;”±Þ* †z¡Ÿæóy‹Ä„Ž_[µÃ”¿‚ñŒOÓÊÀÜÓa;»ÔÃl\•í²£ÝçLkcUòñø·IOÐÎ-Zg¡¨ã0;7ÙÿMçÍ}þGéêŠYUýÖ£yú:‰$ïõ†Êzž=ÚÃ}‚ÝR8†<¡‰=fÞ‚g ÿ‚M‰êf¼´iÉþº©€Ç9"5¢Ï.jÙ5íÌgn©Ümzsð‘è’“w殊*éJi(6ù¢/D>°Ãœ\ŸIÊ?ßCK ȇ|¨¬cý›Ø3W-…w‘Ž6d¢YšÛ?Ò™ò¡öõÃô2R©`›Æ< a“à+ÊŸººFÝ‘'©9Ÿ¤>A‰i÷¸vTë¿#C€ÂhøëÂÇ!¦ãSÔÖ’Mz,sçèÈËáë5Õné&W‹ÒM—ÚíïvCT·¼û øÓ8Á¼òÈœ#y1,’€€ÝÇIÖ̬kæ+[Z@D$I32‘6ÞyNõð=Á/wƱÈáûª£e(«µñ‚8A‡§°^Zƒ²ùÏ»Öpôwo«šÛAE”ÉoD­{½Pîéábœ—SåÀ¯ ãÔÐíA’øQào« œ° CÁ¸"š3^îÕ-é»Jøe5ŒÄ à¶JJ“`õ„Æ,™IÞ æùú¨9D´Þ!~oG²cGa`"R³ñO·Ä7œ#‘3‹ ýÒ3§T‘'òê¼± ^òPéa[½ÚÚùL1“o-ȾãûLõ–‹Åç¾Ës5 §©lÅo=ÇåGñø¬¿qÌ•Ÿ>²yÓÚE—"ò_Ë©¶+†ªw¹-,âºV›¡áÇà˲„™›îÞP#E…ùq6Fn*éb>¦Ä„y[ê*ºA„éiep*t¤RƒŽ¼ö‚JŠÍ,ލD§/¡ øë|ŠY¦†Ð!×ÅBUì’ÅQê­Ó¾ótúy»mÓ²ïÏ ¬RÖ‘m¥‹…øU š00Ädo­¬­w¼JTXò[ÃýY¬#ŸóãlÈ}Ç‚‰¾)ì’¸hzQÕÀ×WT=W¢Þ¨~q?õ&}´"n³=ŠN]’Ý{œsý O剭k®YvžÃŽô.1y€]¦çÀîæ õx \s³óû¨ÿÿù—a÷wîï{‹SL°±ó‘m³é¦Ë‘Á…xN§ø-ñ¦×@îÞîªr²ð•^{nð¤²eâ$äkAÒãiŒSs‚ˆ±_~®±Ý6%Õm㚟²Ê7qåàÒa¸ËH_5lgGY’b„ïäšš$ýÉ0˜§tOÄmUöºf"ÉŒBJ“sãy÷د¶mtçûŒ T$°Š`ÞÏáÊŽ6Å ö/µœOèpÈßr± º(ßTBéLû;ÖÚE»uiÖrŠY–h²"®‚YðjŽ»®_ÕcNÇ•ÐF„¯ýšmZâ–µ(~mš¹éû.Ò´Bcw|E,)›¾âï7_c<Ä=6=üàLw‡ØVýY8^9}€y#7k·+ÆI÷ÝÏd×îè±_p’ÿ¬²ÝC‰c-i³m¾(#RT't·\wžœö÷óÕ¥õzö ÿW¯ÜAŸ¬s ª­ßOýùp¾ná`€û`k¨ ä-eäμÖPÄ”8&#«o\%ü‹?œ’€€àjˆvzÏÈñš*_œYW»ÂöU6Ý2µ£:¯ðžù™TEó+×W•ªóäžMŒt±>VQÂp´§‰Õzy2”zí}ï[˜D}xn‘´.lú(;ëÝ”½,¯Àåuðcö»”‡õ©U>ýçÅwêlû¢§~3ûàüܼäÜò¦…ÂëAŸ<ZÄ›%³drƒC´ô€Ã 0°èeª¿X9z»› D«3t‚O¢ÂÔÌgA1L0qGOӳ᭕ðoÑY=Ë¿ÉDá8G6ê»UûOé‹Qæt0ãû×_õqd—ðÃÁ`GÂݘq|mh¯2òS‘v¿ÃÔ[|â2ùª±ÝìÞj»ÃŸ ;TpUή´MŸýzQƒP_>ô×£T9}£ã n]q‹%äÇ#e‡Éú „`˜÷m£ Žn¹C¡GTAãX¼õH¤gš?ǺÑàf"Ü1Lþ³Ž¸¢)Ø…%:—ý>¬¤®Ï^RÇ3¾sB:Öq‘ sS'&FË>‚‘$Ä6U0nÙscÇ;k, ñò$R$SF\žÛ‚’.Y¶tìªø*5ÖR;D-ÜÃö^¯Ó˜”<_ÀêG‘B?•ÿoê çáÁùü…5@-£?‡‚#¸#þÝæÊO~}¨²ø ·ZrWàcpq?w̤2;ÏUÏ‘ýM<€áhW2¯ì|ðJol)€J©,Ç.–:˜M1:^h Œ£ÂdQmòt€iµ2PYb>Ô-BƒO-®œ(Zj§-¿%´Ì<ÿq½²!gIÑ\ƒ2}u8á†çǃÕ$tûÁ/e5Ž ÙÏF÷½!o{'êèѦCLâΆPn¾ÅW,i¢îÅ_œïòÝ,–ÚÄšßÔc,ÈñjÒJÜWÙ ¼[aNaÖ{¥¢š‹™ÀŠÕm=Û_2RS56ÄÅ«{'/Ìæß^áwe$„Ïþ÷¡I(§þØdÎýg l¯‚{ötZí*ü`IW»¼¢m…!_%èe½÷Žäº=Bþ^6ZR®¶Œ èw‘â7.®“&Ä} ÷Œ=£·£ ÷'¡vÑ^0JƒE¹H8¨ö–02m.%,@@9Z¹ûØc*\JJ!Õœ>ì4+ð…N½z±ó žu· o*ótË%¬’®"DòF&VCò{@’€€Í̃(è¿ã,.ä-› !76V¼+pʉ±Æ_ û¼"ÅŠç’¨ýL'rî#Û¥‹vÌ|«ÁÍ$e5´³ÛÕÿqD÷J ûSm*ã`óM–äÊŸÍ£"¯Ä€®•  ùLŽ!t?|té>‘­¦%ä pÕ™I˽†ùòöš ïüäm¾ŠœÉ•Þ79^gu›õ„TòßCn8/ÌëkãP?_ %ßõÈQ3û¹Á7;Õµ÷Z §o/ð@mFmÝ ÞPLY––“¼ÓÿÙúgM¤Mn–¼4ÚØ„¿!øDb¤~b2ìdàŽ‘‡#YÄpŽæL¯‰{9f*ì´ÒNÆþQhl|EN‰-“Úë\j$ýáÄ}j \bÅÌ`VÈÊÜÄ4M²T•µ¤½i˜®iP€BÃ{­æ&>NyC|£Ý†€™àGgW{·Öª†u¾ÿ|)cDj[˜/Øš¯ÑÈfr¿,—ú_NÕ,8þRâ|Z¿/F’€€¦¡NgÅúÝÊ1<§\ýÔ@—×=°ÿØ¿€`Ð"B.–JʬGó€ir¾ˆ…›–§¬¥ÖkôjLÒc‰yÔò³€Ü›¯Šj‘Ü€fÆîH4ŒÐ5cf¿Ëßò/7Ït?Àn^ÄÇ.(tc ¼ØŠuÞ?Ee+I‚‰´Ïº»a¬8ô½ù§ˆ­%£°\@K­è´Í$¾  œ¾èa§¢Î¶£H6mç¡“†îÜÄÉ¢˜ù*œUÐ^öKuS¿ Î[ ’]»Ÿ?xÑH ù %•» GT[˜Õ˜þ_é Þi†¦kvÂÜf+OŽv„cPE4ƒ‰+hƒƒòMø·Ó}«Þd.`”OT1$Ò>UvÂ"#ëäò S°ÚRî‚°Xh£Æ…ÓieõpÚâR¶j“æÀ¨’15 tÐe÷0Er·X#Y"‹UÕxù]WöñÞù¡×Xf‰Á4tÙ:È ¯ àaIð8ÆÖ«=ØêZÈØ ÓaIŒUŠɲ´tŽÚ4•dóŸ7 ñ±AªeDI®,¯³Ý³LÞ•¹l¤%ž|›mWÍshOÏåvÒ¼`Áþ«dˆå ÙæŽÜ W#:;± q¸sÑ«<I ׊/OÐAUÃæÑù½G´‰rßA¨gr·êLsÀ­'Ž%8°<Øšû>÷=ªK41‘<ŠÆ]UÝdwœË‡¾ª± ~¶ žQIi•XÉ@Ç"'¹Êú*O(h½â«ê"¨z•ìA†ó4ý4ëFOãcã:´ò]- aÞÞ­C"\.ƒÄ»[ƒqOŠ£ÇŽ2¾aq‰×ûç þàs9×íeþÐ’€€²ÿ-XœXdwWèâ¤2†¹>õ8É”7;œ1e¶L›Í¥ŠŽ—qoÐr¸™í.›cÄ7(ɲÒå²aXfÛ¥®+Ò„ßÔŽÖÌ„¯±¸¨èÒß;wI¹«â<ÎKkÁo`¡/çåoÍM…KSÍŽl¾…Xï ­Ö|¢ÎÕh–y.Ô´D0w‹yÒ {g«âþ©ÕÈiÃÆ På¤v9•ô@ÉUOY¥w'"ÎpGÄ“©µ0µz©²fìe·Fn<Ç–[Œ åk¡ÍA7,@W·Â Ô›0q#‰{ëRçâÁËÌ à[]}–ÐV›®Ž„ÈS«í¬Ÿ™+ç3ÑìÑ×ö0ô[“¦©—èý÷’ƪ•²ª|¿ž@ÞÏPuç›Å¤d 0Dðó—G ¹ˆÏ7LGºS"è^®&C#‚D¶Ý©âqwyÜ«1QÄͳì8'ñÎ'Ù¬lÿ¹®)‡ã¹^Ýz`´S°H :Œ³ÓŸc“î`šî¶6ϦՈUπˉ>=äÂÁr#u«^úŸ!äiwC–J=n•ñ­÷8]°¦š#ÂYŒ§qÈ?¿¸°Þ¦A?cèßàáÖ¿P:„¹äŒøwºê{Ð1äýɲJr·†½Å`Vˆ)´¢T2®ë—î]~³.ä»UÞ*Î1Ìf"/‡ˆ–ß#”ôc¤PçÕçò¢žÅvê`Ä'8R©·oGØÊc„Tì"´“§Ò®DÓ4`‹w“È9õ—fiÓg¾H.òîA4cËØS|.kv z?1 «Õî½Ez„ Ä a{ô0öœ1)OòˆÀíE|0¹­ÎA^Ô@HXÁ ÄtÏÓÕ¢Ò×ö¶ÕVjÁezDdTb­GVª€-„#ðåN~×J O ñ¨³· zt2±GS‡xαxÀ¿Àmùþ!3¯WÂx*ØgïèÜÀ|ç…mRFŸ<'í©‘³o”™Õ›;OzÇoê:@D‰V4Ò¿8ýc @j Ãk¢9:evj“b|*|{¹x×Ç›ngeœ˜K+Ðàø¼y]˜]ùSµÑxäîýè3¾U ªq¦.ÇüwÁE榭‰—áÓ¸ƒæYX¯Nx™v&Ò ùíe7ÚìGžª¢yF*!ü^í”U±ªÏ[çALž’€€É9–iå›™yÅ5‹áû·¨¯¡õ¨z§ r˜ØP¹Ähz*ΖìÁ&åøºðY0)]ž^›Ky¾.{ìKêjw—ØãÁBþöF¬a„ÊýBg]콪_O€5½u=ÕÃË$œN1šðºsT Ë+ÚMjK‹ÅjtÜ–ë[…M·'–ÝÉ ÷—ÙÝ Én¬KÜY:Ð Âq›œÊKB­g•,b~ïs‹Žð„ 3wj=þ÷À¡6PæE÷å’ ö»¼s¾£ sî@9t ÑÒ7O÷Y³¢®‹Áh 8÷ý¥½â.yhŽ  =ÄL ÖÅÓ(5¬¸)éª%Ž…„ï}QQn‡g1t¹ú ð«ƒô«AÍöI)zU¶~$m=Ìáž}¹4 2b`7Z÷{#Ú÷¬7·AAxgKœÎ0׆µ"Nù»Z(OÜ%_Àywâù;†“³Âyý‰dIz`1§‹uôlêy3Î'rlE¼3¦8Õ´x±KŸ$0ô+¥¿¾=­pf¬ßø×hô:Â(ÎêæNløiÀ‰éë5âtztR#gÓpº4utÛüq@c%WF‚í<æ+ä”Ƀ<“8´MRž[1䣓À—ã‘ùØ‘&òªÝ¢”ôMóŸé%iÛß0Ä'÷Â+ùœ¶_¢H“*p€Ä»Ë[òÅ%ëù*ÔÜÃÂE.rýš#Ô•Ô‹‰U)ܘ„ž,¿M[†Y¯¦W7W‰QCd‡Aô§ôÏì6ƒÛWùªêßæëlN¿üQl¾ÁЍ,º=Ôƒ~‘’ÓNü„E‰ÏÇôÖd `< ñãÏãF4—[¥_FèÚx[ÙÛÆhÚzqdÊW€R¤¿‹!Cê/ØŒ½O™¹$8þ•Àï¨WÜÄ×röÕZ 7ûòòx“¦áHh‘®L™™‰‘äpœò*Y>ñì…~ ¸Aç_F›4¸Š#ùÀçÒ¦ñ„ªINT†v¶Ž¶©Ï»Nˆ2Y‘A# —º7aŠò‡nÒõK¹ŽAý}±úççÂÁ6ã% ñ++Jõt_r¯ê{eEA žè6rt‰¹ýÈ;ÔmªÛWåàÓ®â·zKMñ’Ëà&ܽ¾uÒ9U ü3w¿M¢çx©4„”š$¯·s‰½À‘ýãå2^˜Üó÷^Éç për†?IMä§W¥Pâ›uÝ͇ûÙUP­©¼y,Yä' .¬uÞòíLWoá¯ÆÛTrg½ifƒhEF§ì9*ØŒus3¨Ï“©Ý:6ÔYx®;n¸¤‰£—mô$]Ã¥NâI$%·qn\¾?Mð:ôöâÉL7‰<þÎ]Ù‹‡ÖV–“û Ùóäm[gè ¹ér1oHŸY}êJ^ü²š¾á€5 ýX;ì[é¨ÐäPƒÓòàA(üxñ 3ìkdë—lƲ;[bÆ‹)}ïEõ07H1ŒÐ=þ-¯‚±w6fw3S)ÞÁË:zŠÞŒê5Ô>€âÑìªgÙ¨ÈqC96VKîµ×ù¯çˆ?‰\<L’€€¸‹i¼Ó¸•CÜšc®"Ÿ0ž¢ÖIñý±2 Ñ.æCþÙK1”­ƒ«ŒSæÞ¨¨ ²^÷l>ãZžie—õѺšÙù0i&RÜ!m>°0(KI*R6ø'G2)JþNy  êµÚÇ[K‹ÿKžW–°¹„¤ò6¾ÕPÄÔˆ V¥˜:šMº7òG]K‹R};tÕŒÿækÛ0ÈX&(21y½}iïqn!©W૟fM ³¶¶5]YÀMðæÚ"®3Ê52‚½µK͘ôq÷Jï«k¡’r-^ÉÈ”„nh TN°]è4»b/Ñ"®Ìû,‰ÕKøÕá×ßéþ‚ý7"Õo'E†(\ˆàyõÖǘÑ'Ò¡œ-!*ãD¦tÍ_WP ’+çÐ`,GB…¯Œä¥ëéφ a-¼¥œ |8·]‘~á­ò”WÞ/¬.Ϭ\TP± °×Ìe°ºÓ©ð¤~}^O~wý»`iUK Eáêú¢8>íVÒx»1¹®Þ\…ÿ" ÏØåš3g ½WH€ŸÐå ïÕkൺÁó!Ó¡®âÂÈøïüÞM¬eæ[MÖa‰HÊÏ_3vA?²ò?⻇ ÖÁ"f1ø/í«*™gÿ5Õ׊‘#ôÿ¹@S+ V+æ4ñIÈ-±R6Ùx!C ?ÿ\ö̽5­íÛ–©O%’9#K<Æd4§/§VO<“·xÇþ] ÝÚKI6n»Èìs #ÙMÞÙêÔŒ‰‰.†½(Һų ß)ˆp–ñp¤PµÖ!wâ÷£Ú)Ï: ‹qù|=´ÆõCˆ-··5¼—ˆC-úEl˜dýL‹dL'ÖŠl¾±>Øœ™.+ºX< 0œì3—~Lù‚N!–·ê~ë¶µ€=H½¯Jûnp`4%Y 1B•ºçwN:Âø†~iÏúýŠÿOåÆ_xY²ËNR4í í8U¯¤Πe¬uÜ ÕÍyDÛùrPšöü¹«ýoâÓ;Ê3w3»Iþ<>oŽØùó§á0Ø\­¿4åó»Yä”?5Ü]~KEãY‡ÈèÊ7@1Ç9¯ø¯ú%xs²£g yLçø p× ZœEö±~…‡¬æFTì@×_›çCâדE@ñdCý1¢'¡cÂ/†ÙPþ ȃ|Üò·a7r’€€è¿™uw‡Mß-×v aþ½Jb*VŒM‰à•ñ¸(²7ïL#G|Ñ®ˆI9 Ì3Ãx¼Oºãó&® xÀ'MYíF YÝ„Z®ÿR”ÄPçK1¼< ”c°ÿUÙԓͲ?:Lûh‘¼Á¶Úbv¨nѯfß9ŠÁã¨D«Ó†HŽæÙ²Hlü=øBpÂï<·Õ²N£ÆÆT‰*lœ¬ç´µfŒC­}çgÖ¸ØQÀ…5ÒEÚ\…í¼ÊCjÉže#WkœÑ~g º„Ù™ŠÆýnbÌ:_8œ÷ÅCãdÜt$kÚèÆÐö•VÛ ­æ|rÒ}ä¥] y-óHNHyþì¹CqÕÇû'9çúöê'” ¹öqKf%ê $šk¡‘-’Þ¶‹Ùx/½éÍ:€• ÚAXhß›¤1tÞ2=ÖÑ49d¬g‘2óˤ¼ÂAPË×9Ú?!²2Ù0³ÂiÈ*ï{@cØórÍ÷òàÈUÈÅ^é¦FÜ#‰ÿÀ>V Ô Õxæ£õ¯C`ׯ†õyS©¦fíyDÀÁå{£h½f1‰CI|´ÂÃ>i1þPÛeÃdeq„ˆ‰–¬½8•³+«-ÚõGÈJ…d±Ò}‘>­œ¤ÐÓ÷ƒÞ*é™Ê­}¦ã‚g×ßÚ:~”©–€¨Õ`GFüYüÆ+Nx$ª·ÃC R»yŒšzÔœq£Y ¶Fˆì†SÃØ4ÃáÛ¶Ñ¢Rl¸§û$O@ü/ÕCŽ-LøëËZîÿÖ?ô4ÑÔfø,ßa´Â«ö8ÂЉwí3-ÎçQy°¸¨à„vD@“KˆHéa^q/$” {©ë¸I‹Ý2Áñ˜alµªƒ®BV¸ã]Å3ܧI©_ß§sòÀs}†ŽxAÛa¨wúÀ·]‚ïÐ: ¢-n.1µ».kœM°8âÌßÜàï4s <>bQðÆ[? Rågî–(ÂúÐWꪭ­Øú¡kôÐü?ìµ#*¡é2³#|ÅL¥ž‚ÈÛQ€r“úà‡‡5‚H–±K~­n> X„(ZÁL¡7ÁÊF—Š+ dñGËe8,1×éÅö8 ÝNJ¯ô8xÒŠÖ~we>?àA#«®y/ã…„ó È<Í%ó@=IdÝ­ûifÒAÑæ!E~ÔPJÝ’uÄ0`=@å4’€€½¼†gOm¨²2\ááiHec hÞ†jLC/‰ öÙÊž†×_Ù z—øüæA© ßæ¤æ^à8º(i©‹‡æ¶¢§—ÁÑmÀ-ãL‹˜$WÿÊ—)-IK°B;¨BFÄiOðz³½û@2L|Ðwð*©ýw¦^šûPÆœ ƒhûǵÓËæqÒÓá¹ûç¹tÌ¿ñ •ô{ë ¬ uªôí*Õ[–u¹Še¿ŸÇÔ™ïU¯Håe-Ï̓)§„ X«$Ä€áAµÁ[‚V*߬¨<·E/ )ûxžkœÏkš·3y޹úщ/oú |âÿõƒTÕÝ’úò|TÞ;#—ˆ]xë(ÔëõîðàFþÓÙ‚ù˜ía7x“F˜ÊJw¤•ðìq»¿L˜5é}½&ºgcöì±ú÷ü¢f/€ïâN±Î‡ ‚ºi0Cõ½±')e26r$< Åø.•Ñ{r—-áÜ’[Øö!Nc¸wÖL6b%í^i|0ÁLÀ ë,2¿õÙú‹Ñ-“cè¶B%}ÿŸQ>gÍ“ì¾õ¾‰4lÏ¥—,þä:j)NèEfô™ÜY ¶}o7XÍŠ]HTKðèÉ=q‚‰7ÿ Þø$ëx»¸šH®»FÖYwMë¥ÔÄ‘ òMÙ:AõÌ¡[†KÒo†ÏôÁÞ ¦eù Ž+W|t®Dš•¡9°•&íèó¶Zq`çsÅQQ®0ÃáS=àÃn—u´cZÕÃ6 ®Â³·NOMà_æ…û¨}†>—ùßðÅLŽ\¬‡|ˆ±Y*#pÐû7îOì¸Èló¼·ša×ê cL]…;-ÂZ²£®Ã^•¾9%E{— c0‰¬ö„ÕkŠ GxÀ”;.ò ŸªÈ×è¢a~úþA-àVÖŠ®¿šçf+›íg¢/"ŠYª„™oIå¯ lÀ·Ìán…»cʧºÛ\0o¾åÅÙdšÄc B{שȎR ûeb’€€»F–Õ÷gŽgl…i©ß)@†8 ðr‘c¯u:ŽŸe×Y£ó\ef‹!·Ò9]Î…ëP7 ü@•¼ÆRzäõnpŸµ^½Žª&rø¼UŸöÏ‘2V ïA»úNERß{(m`âTÛ Þ9E íxŒô¦’o§ÓOJNs¿D0ý¦êš/5!HøXû+û%æ[³î› áèóɰã?¤¶CöP ‰kF=Í\-ßü üMÊÿ”ó.[ÍrdݳÄV(Z1ÉéH1ãVvTPkÖQ$¼Ë¡ê”u6<½sDZ,j/ûÈÒ¡=?r§8ºxÉѯ`Üý(^ÙpjTsõ `Œ=¢{^þl°êÑ@¯Æ?—o90ÕÄæLlâöϤAuñ}žðŠö3HÐsÝ)»4úáÎëÓbÃÎå,Ã÷égß«„™r,Hg'âLE¸ï–28˸êéÙàÛ/b —>“å%=‘@õíD’««ëhñÛí“]…‹æ#0cÌ5[/Œ€,Än~œJˆá“ VQ%ÂDaQ¸0ÔpÙí_JS§„Ñ ]9‰+ã°…µô¤ Ç9‘­êCèúÓS>T5ÍxË›"<àûå`äÇ $Ø>aÜn¬òÜx¼IczëmæLÁ- ²n™rŽ(ó¨Áð¶/øqõk]¹Š=\l(ă0yxU— 'ÇïNmy°²ŠAÉÛœågG¿Bg3›P#B/¡ò¶êMêÄÿo½¥dÆav(_DÔ _ºÝH™ãUSiúÕ`ÆMÜŠoø‚lE®:Rʤ¤!“½‹ H[-6÷…Ј^ÕÿßñÇ+‘¤hpÇLü|$†š•€¥ò˽fFo®œx`W³‰J € éÚ>ùÀFsÌ %‘¥ªºZ^D ×l¬±÷jè⨳æ`Rû{¦Œ4£r ¾ÉÔûn±DÂ9Ny(2³ž™ùa\\r ÀŽ¡ËouáJÜz\Í!Àõ ¹eÁÓŠüžÝø;:ꀕ€zYj¯µ¼1 ¹ÀÈà6Φ‰AÕ~–Æ×ž0¥a8¦Ó圥bí-`ƒú~Ù¤âÄóy_µrÙ|J¥=wüK@¥ù;þ¹,.´!oÏ7qÍ+÷ÿ›Âpp°È‡ù'ÕÖ‡\AØþm%ê±ÐX ðì.èL‰‰q£ŠËZÊû:[4•«däˆàc.䨴\nº /²c‹ME:ÝyUÖ,…`[•ÄKO‡Œ”Ï’àa ÌZHu‘«³$sh9yƯ¿ÃM¿Ð Aÿ$•=?¡ Æ %ÑM{‚;ömM"˜í×Áûñ¥&3«Pwæ8ùõE ñá•#:Íà‚­QÐ n ‹‚ j…)§{:Dì¹}p^\½¶›: W‰À;×zÏ¢ 4§¶ ¬šL ®µ¥Ÿ?Kš ³D³”Ìq¡÷üU‡j×_sÝþš¤ã§½æ ¤6IGί7ýÌ’}.ìã>’u4xu\![â»›› qçdgÇE)\Áè†7×ÐY«å11ÏÂØs8by»Žñ³Y$,bŽ(¨U]¦TÇ™ <Ѓ_Ö%Öµ³_ %a÷»…ÃŒqz«%ªbb<(š]å˜÷Šº_g_ÕÐ98¼ýŠ­¹1¡ZU«_#>X8B§gãîn–ÚRr©ïs_+ÍyUš5s¿¾Qâ,PFáÝæ3g‡JºN]0ÇQk$l>ÅUžSÔˆ=ÃAóPøÜ<þÑš§`å1-ϘÍjÜ™íijjM¨ »Uj€u‘’VËUDlNÔ±> ·eòC’€€¼‰ Þøê 'P¾xq ŒÐò.óR~‰4j2ðÇNE8¦ö 5ª½9ÃmÆzÅç[dÝR^0¨ñ]ªMj²ƒD(fg†Ð"¯XT­%äN?ªTz”‚Zûö6Á ßÚ,W`ì¿¿)·õþׇٽ½}>¦<ÅaÝX.ã,žØ“€µ~BÑ6uñŽFöi•Ò[(wúݧy†Ѻâ 4ërPe·€r5x‹tЍ·>:à2]Îr &W]©ïG8M™¡ãáÈ=×¼µæÛKÙƒ¥Õ þEf²IÕäØ\eÒæH•îOþ<ÁϾ4ÿjL»JqÁ RÁkG „ ’]R×’{Ç•¬ ðÞ%îI¢ KZbeÌÖ>{4»ëUQo0¼¥)5DÊFâÐ)ÛF;ÿËýË4¬6d¶ .Á¸˜#ä‚ûÎ;eÒ:]‘t‰¦–ŠD¸°4ý.Ÿj§\ÚÇÍA÷,–®¯…ñh×}Kd°”ÙAö¸DéÊz¨p^µ.â9èÇzûÉP «ÊŒÃÔ#›—š ô]kudÂl•I×›uøï. ð”@ÿÙ«°D1|ÁÜ…^„«…QW󋇉G@Âúøe¯Ëî Šzx³´ß%Gn–L&ª83—ê)£Ÿÿ¢õ¬ sé<Œõ†»’Iy˜D9×ÁZœª¸*PÔÌ)s—€¨¿ØŽ“ùs^íÍN"GažŸ‚ûeKÎxžä•«vXœå꜂!yKŸßϱœçÐÆ 6cFЍÿõì M~;W ¤£;v2Ÿ‘@BéJêJeò_Ò€k²c ·y,Ì ¹&X~S|9Žô. VN_ÊÖTO@+ƒ’€€¿-àF¤òŽBÞg> “öòÕsh¶öéd2¡È€dîX]#)aÐʹÝèáL˜Z?ç8Ч‚& ­ºáއž}®Zr­°–}üZ"^«ºÆI 1,4©k±ìåikšR½Jû—™›RÞö*AÏSðØ1ܙð äû{BáçªPa÷Pyè$N;¬Ätx÷³Ñ‡\4«›°vGg\)]ºt%“‡kÞén¢ÎÖ=ì…s6ÜÅ‚´CÄ APlô¸zwcYeÔ¬ðîsýÄá{ÏÈrˆÜ÷4“™Îoê´F(>™¬°÷8œ8šX¯ÍI¢ÑçQ]“²_Í .ŒS¤”J Ý"–¡m/*¼~Š"Y>ÂCKÅQ§WðIKËõvU‰R‹fõ}°xØõøJô²ëá«/½oT[c’/Ý-òG„ýì»ÓmÜl¡mÑlû˜«²‰ñB!› Är@Sõ6š†i0[AViçÁÂÿr×Ì> Á,”LÄE#ù'G¯ýøYí ­5F͈ªq­e_å@îÉ"¼ðvÈk.T¸„þ&Ñnâ,±.9dÜ-Ù[‰àÌÅb^]¤4$¤U¡ÞÞâz8 ÿh“ÄweÇ@Â/0ÊmmBˆÇív×%„]® •óçbßM‰žZÛyþƒ€¤³ÅÖn9ÏNu7¾PèfÿÊ_î,¹g’÷NÒ6ÑéõØq Åt0H 'é Ê‚©Û±Àòزö»Œ©Ã•ýªfùh%1Ç«ÃA™LIÖ-úŠô§ ø›ébQ}Ãó† Î6$CCi®IJeU‚…°Õ[ÀK°dñˆÍýÓÏ‘Ù"iÕO„W°ú•E­s:ŸÈµ—aácCÞ9qyw·÷Ÿ‹"Ÿv(‰xÓOGlÿ’Ûé›ì·ÅS‘tÜ€û13ÕLøWá9 i@ë†z’€€ÀQ[)% öQO*Bý3†Ö©±4Ⱥ2l_ŸôfúÿÅÈ×eKtKÍ^ᇗësÄd­z'd)HÉZôsëÏHpÓ`iÕÖ!³aâgèâ ÌTxY â™HýË—HxÔcJHx€T9±ÒtÜ Ac·hüåÎKJ熲ݸGs+Ù¢?é:YùìÁSqòü9€»Ü4õ¢¬© „ ‰ëÝRçMNMðx²dá§‚kb#Ênªýñù¿Ä]è¶ûPŒåQäÁÞ€°;$ ™ ÀçE®ßÀWDCÛZø®}ÀˆZļ`ƒàSÜJˆl”$Y×8ßGÂ9ý~© q~9wC~-8îXŸŒÖ¥èe=F§Ùn1ÀeŒÙ¬ÔÝc¶0.ÚWhIrÎÌäŽ,0aÇŠ?¡Ù\%Yg_Ânr,<ùØbmïùBp+\ërþÝó wdüã¶¿.Œ Ÿµò\øñÝd€äMà ‹P:õÄc•M‰àÇe «°6²‰?ß Åï]Z‹ W~ÉCëQÀ’d–Ø¿ÕߥLYXXY”%d‘îSÍÚ5²Ï }`A±Œ2C 1Y‘>ç?æ›Ûþ»µ%JJibf_/VÈGÌy)Ç%V®{\—ÿváe' ÃHD/hËDÛyÜbE;ïò2hóìŽÔ”Žå…)gï­‹ŠS£à1zºÙ:3U0ÆÌ{øbzòŠ÷™lk¹\ÂI0¦5>íïêâOøP‹÷2½7qr‹'%·¢Y‘1AÝ„4d‹¤<ªä XæÐ’@4!†ç}§H¹ë#^.Ì÷+¯DÓd@¢—£Ó?ɸdÌ×1`ø¸mrüD…&âÕ~¤€Õ\$Íú¾º<Ô ?g DªèÇãKžŽËQL$|í[Þ5ê„}±O²€ézÐȃ:Q!iöš…»öVÞæI†®ûö ’Â:Ø QŠøñâÕ¹!Í%°A<ËúºÓw ºÊ^õ»·³ÕDRëÔA¨÷­ÿ—•T¶¼™×‘~*×dÕÇn½¸÷DhÊT½¾D¦ÓaˆHäz>múЖ6¸ŽCØú7á¤O(kù뤉!ÜòèÊÔqtA̤L’q°£¾§¬öµ„ÝGŽŸ ˆàkÕ}ù¹&¨{(2Ñ~ñùÝšê¬ÃÁ•©È™¾›jÀ9–9­¸ùÒÇKîì¹.6):Ô¼j~Ä|CÚ×3w¯µˆø ~ik” F<›ùBj`òØb-5yÜD–Õ¼Èî˜{¹wJJU¦x§Ì––ôÁN)á­#—ÖFt':çÈ”[æO~å—²÷,<æVá¸ä\l°BÆþ¥=ÝaÝ’·]¡G\á1áÝ\¿&J$†jÀ¿äú"§A«PæEî×ÔW7¸«Q¨NÍêM%Ý}‹œŽªh1Âo’€€èŠ –ôï\r×z­EB©Ík»6döõ™ûZÒ2#î÷4xŽ€î4K¤X;fç—Ø±LkøiD)Bo+r°AzË&p™KÈǨõý¼à/Ÿ<ÞKD;éEOõ·>Ê ”üZƒ:R¬Ü8K¤‡]R^Y`/d¹Ó)2¥Ž2Ü ¹NGëÕG’»Üö÷#Ðô\ZæŽÐù²€Ôóÿ+ìPÿ³ÉN9EÉûr[Y½ËËäžh-¨Æåf†?ß’!¾#ÀÅÅŠ¦9±§o&;ˆÕÇÍįìO¤ì¾DÏå¡ÀÍËߢá²ÄÇjþæDçV³P8éD’½ÉÁÀù+58µÞŠâà(³8¬ä0j“BwÍÞ¦Bñ ˆ×^Ovv»áæE94•OÛbS(ƾÁ±˜YïϘ#ï1Šþ½¯N阪çÄ/FŠÏ»7›”±è„ŽDºÛ½»š0åOÁ“º3ßnKù{6l´—jNçåÔ (ô,Y-Œô (1€P *§mÌí|@»«£G/š{3¢P_ƒ/_Öî…' »zïoû z×^sRŒÉ’àŽ#I}ýƒ»ÎÇ™_ú[OnS€li§Ôâ5QŠ$4}Q4 ÷åΈÕ!š%¨ïH5e< ¼ÞÂÎly¼Y+YqÖ¼¡uŸ…Ý¥¶9Y ÊE0•[DC\ˆ5°ÏÉù‰ªÔºûƒ³ëSä öL"^[úr`E’éeðDs åÂêÒA~«‚ä—ê†K¢av(ФÝ()¸DEwßÁ‚Úׂða‹Ý¦)J×¹‚qŒÇѼ•Bó ’þü ]t¶¾U „ðå©É¢ñ®öUÿšò’¼ÌŽâµË„[ožÚ*_÷JvW»q l Þ[Ìw޵ÚÉJgñõªŽ@QúA`DžéšK*×7Û—dƨßOÿE?£Öë¿Ò7êQo›Bü³ ì$éKG¿%ÏFÓ|¯ÝQœ\8\5ö(Jeþ‹š²yžÃ'|‚4®$ÊbdÙ»t¸Þ›¿ÏÒ<8@[#Ýg³1÷""DlIFU:çK s³;‚îeŽ^4ÍÔÑoÚì­¼‘£¶}w‘V‚å‘íÌ ™Ü #8u{žb­6ê+ :2㸫xlãªDN~L¬`×4»ìoN˜Œnº‚b»¬d>Ü匒™ÍÒìxâ—±“Äw ò,|ârðèðãyÂH‹h"fZÍ·2UGD>’ ç<Æ—"©…q%á‘‹£¹çÒïÛMfv<é»kõ#ÞžbÒ?f× ²je Sm´Ã'ñŠwç±ûv<B ´.Ðý.gzq3´ék9Ì@ÛÕ…0¬Ÿ5ÉNÂ6¼MÄ÷u¹ù‚öc•ÙD:aÿaûZíZF .`‘Eƒ÷ö¦•ÃòÓ+WâÙ¤¸ÁΧÐfó›pzŸÆEšïY6óͺ-ïÁzôDÏ6–1+47®ÆÃNö» “Çð‚ Bþ{èœi/2x3ìk´ïå„T´Ž Û›Üä.xEØÃä³ó¨­óì8¸e÷šŠw¡æˆ¬÷î¿äܤôÖ¨‡0=z³o†À¢€ž‚8Ä í‘T ã(›hžŸ¬çX‘Û¢B*CE¥é¤„òtßj šïçJ €,̹m)³ñÙüÌÈx)n7¨*û‚o<ʧ[´ßaÝ[El}È¢M¯9 5§ƒýNs¦(º‡YŠ·£~êoª'“áþcÙÏåÊœm-×·%zf?Ä4Òü“Ÿ=;¾… d3Äò±Ùp”t«J).îø–Øç2hÍMTè­ë©k \¬f°ú!—Ú­tËn˜_m~LŸ¤Õ¦¶’:&•Ó3 Q]vfÈ–äÀ«Àü$…1H(“-’€€á5eawˆ,öh¯Gê™à=J-¶\tX:úb=N4Xé»â'úX¬ ©Ü0뢡b¯k?Ï>dÍeÏQé•¿aC$;¹/[ÅISiE¤ƒ8£“``ĸ›€XMd‡Y–B¿¤öónުќù[«)™­Ä¿>P‚" >™€2ŒFœÕ5@èý«™¬TÒ;–vØ/[Û¥‚(OÙjSàöôŸäñEÈ´&ŸvÃÁê˜'èb…寉+íJî‚61æŸÝ - …@W4ˆG"ŽE¹Æ?ÛØòÕ\ÂæzCBfç7gg5…g± fS@ÿËHç»2*öîÿ¡ %D=ÎR©†·µ¯0¸’ë ûúi£núŒ6@l²ø(¬FQ¸ü‹pcéŬÙ@“è32š,@YÅg¯ÏS²éɽ3#?Ñ!øËB¹Pƒ±i9ƒ?°T×¼Ý;t²æÊÚÀV*° ]‰ Ü™Ÿð{£œ5 Ï=_ÌYyùááܳÚrêGQ2ÄŠÍ[ùaý¿/_£ÈÉ9¤„Ö-4z½EÛ%$ÙÛù)íáñÉõÔ”±/x¶*Õtu~ZéÜ?aÚ«4êæL-P¨oA4Hž¥Pö‚9ÈÙõ ¤ (&p·=ôÄ(«]Ä´–‰”+-™>¨NÓn‘”vÚœCâdiw"¬ŠìP#€¾H)= GãaÃÉ>‚r¡‰X~þfSèåœâ“eu¬g LÔ¤S*RPôf!´üÖ.\`q$>^w'!¤•΂0£›ë‡2àþ¤®ªEü!íV ‰kë‹r‘]Ùï!—Œf =A7“ÚwÁ”5N÷e§ÍgìhçÞ‡îªJGÏÊÜÆÜfØ×s8Ì¿sF3•Ê<¹û©k@Sc^ˆS üEsdbï$Û˜/ÝñÈ42.ÙF=Ò«ü %5‰.\}õ&„Ÿ¸¡¿·Ó-Â"HrP[ÖþJ·‚éKêüÉCç4ÙÖîÉÒ"Ùª–,Füq7 ƒ+(Dl0T½L=¯d‚FÞ ­ìÖ]éîy^Gee…ªslšâ:%ɯæ?fZiÈÎv2Úû±)ܬÌC£E¨^O ³Gq"-¨ÖÉcjt› ;ìJÕnX@µ¥#PaT’€€¡‹_x&nÕÒ‰[uJá¤uµyµŽ©O`’½µ©¯‹ÜQ@D#ÞòM\ìnw>˜âÿÏu‰Iž^á(p2ÜnAǘœÐ„É ßµ¯‘À ÷8Öõþ¡¢ãæÞ`ŠAðúK_Ü,߸TŸùÚÅ‚+½¯«Œ>öiwUh€IF”üBM=OÎ9Ý©*¨u`MI¡}! XTV°wñ·Z¢¼ô7K/V¹9íÛÎÒFÖàAùµ/çÎxJ’JþèˆÔÝ}cÍãcqóåÈDÒ+êƒ&cœk¥²9áÒÕ¶kýŸ}'†¯)Àdh†ÕQe oÿˆzýâ“ÃHûâ¾QÌ›Ö4i„ÛžæYƦz1Ê#ýº|ÙGµYJJ &ÌóØ“C“TÂHœ¹—hZA›?ÜÆ±^ñ¦î\f›»Ç©âpêå,¸ñ“N­7°ú¹àPÐÍ÷ÛÎQCC[Í0¯;Ò½’ó©eµ. ýh—¡Þ\r„í…¡÷ÿG‰nÊÑÀ@Mn—гÇe~(ªŸöo1‡|ñ ¼qÌê /Ÿ¾jëE?¾fNXÄÓ`c®½x®ª+õmåüûË€ßA1²Øèàþ¥ˆ”göVO‡÷÷Õ±j33••²ËFxt ³ªª`ãë—y¥°‹©SïrñÑá&7Ù¥Ù1kÈwUXpHv½þxTe¸:¼ñNü'£R)yaØô•ú3ÔÛ‡©~%7ѦV¹Ý#ÀlZJGÏ ]WÙædïœñÞO&R½‚V+çõO×ò-Þ£í}Í9šªAË_søæOÝëpYòÛýÁô¡uLy—SÅ ¯Ù8¹y…3ÉL *žT˜Ä¡Ÿ¢¼/|ÄìÒÓ’Â`E/Þi“à¦ßbÚ“è×,ìET#HHT¾™Š4(ì8Åv3@g}õ"XÝé¢úRž™}ªÌàþK®ížÇ™ÒøMýÐZˆ« ƒ“cPš ÃË‚Z‡œ.§mµÔ©ZR^¿W{Pçõ¡å„_ÞL<‹@“TÏ Q–O­Zü©IøÄ¿¢ØJ¹uU$þ^³Úµšüv`%TRú™2êÑH“Ç¢´??lRöa‡]6ýPÿÐÈ0[y߯jjÙ­;¹8)ïéƒ<+z¶¹µÚjLXœ?àSj至’€€½'eúOœ«Jç1bsSPDæUBdêDúí„N‡9Ù˜CÀCHê@C[8e)ÈŸØÌÕ\“V;ö©¯r’ËK4//!>·6º¿µi­TäFz'jÀosøý‰Ÿì°2tüÄY5³–'Ïî3†!`TYË?{ ‡ðP/e®ª’çæ¹^1K5¬ŠŽ‹Túv:#Ÿ´bGQ‘…N*$_þ ü0•ÿ÷nº‡Œ-.¥b÷ï®á€™Ù >ä+êáÄ?z&FDÚ‰ë>;%ÐÏÜûb]R9šâ í‰T_Ãýê»±q„«l~Dº¾U$o4ûµoa±‹)~ëJK¥9Swõ„ŸÄK}󣄅ƒ$h€x÷õª°,ãHýQ@:tøB½£G“Šv»ÛSíDŠÒ½‰YV»)âÉ  Öè°¬%«cq½‚YÀYšùB…=9ÓOS¦îIH mæ°üh,Hì)b/ÂÁˆžÍA4®k¡¯¶;)u›ÔmðN´¹¡çï¤!_fø‰òFýbêÜP`^éÔÉ,”ëµLwF;Ù/~vXg'Û°œ§mIÉÔìÙè¹!@±"ÈLÙÎãZ/Ð åÚ70›üLIm­Ã ‹/˜ºÖu×ÃY9ÐìZ§ÓZ®jlè<öØËÉî û¥ªæ†g²Aö8vЉØznÆÔ]¿ª¤4hþÎ…³‘†G÷¸=Nvé…C—Gù‹ u˜èÍÃòÁÅ“QœÜcŽ;«GSé¯nÅ5SwyR÷ÖÞÇäÈ‘‘ñÓŽµ¢¸Êj¹ü"„:3–¯Pô"† OV1)Ñ‚¿p•ªmAüçJzÍåÀmDœµ o·¸Â¥eAèû<Í«¼Ž%2€ËÆ!éØ3éÆÒqÖ¥“„1¼ó”Hºb»->‡9ïXw¨P– tú7%þ>FÜnv+Da%Ä´"¹ÙJû"Q\ §¢Å;:¯­¹ð¶–‰¬€“âæ‹·i ת ª6¯Ÿ`ÃçNl¨£ ¨©/ Tã\”±k‹ñ¨åvh7DÊëé+ø!!ÂJnŸVÁ£SÕbps@óÆü‡EqÁIËô–M#ÿ™c9© ¡°‹‰Ý-u0…B$šf«€Î»òçü‚7Nh J6Ù‹¼ ä^Aäð7ÿ;·…ÒĆ֫K§[&ê¾s|®à’”vô/PE®*ÜJ¼Õ 5M¾"½Ûóuƒ— iɯ_NYª.hå×°öª-kB[WD´Od°ïW zÙU™,J븡 jˆ¡ôàÉPì í^ëß%òr&Ï“G|IxŠvÕ¥Ûnó]3R%àŠÄL vc9„\4ªeÂRÉf¶TÌ( ×Iö5B.À&ž­c í‘ËæŒ¦=ŽÝºDÙ)Þ_ ú'k¢O·’Çï`æ÷Í 5Ê?ßÎ2‰D6°híT’{ ÒÙIyÉ £#Ìh#à%vÕAã'ocg[sñŒR)ÈÈyî§ÞvL~Š Áf¦å÷ªåÈÆ»•æ&vHäo.] I¼­\`–×g´“~Á‚C(ŠËš„¦‡ù÷xÒ‘+¼2 E;N)!š?#1µÊ&¸×ln^EƤ!åÁÔJûÌcÅW1E´„6N¦÷‰’;t ‡£Â'`¾5Éxi „à$צaS™P¶‘ƒk2-ít2–ú÷O6ÖéÂîDÛ™ÛØHÐIš ÎQ:}¹aØl¥Š­ò¿Ž E6G¡äVd¿g=ê®¶·JãšaÛáoNê#{Ç„pé/žo+ –«Œ·‚5,mâ] }äz ú=½X‡¹´¿àdÌó”QuŸë´l8úpîeKrçýÝ%’»kîÕ&°{ ®;&+ø§)cm}œQ{o|©Çnì IÒÚ_®¸ ÍO[ € *yûÖÒyF(ÓbÏŒ„ÙZ+m¤„P'÷ßyîI’€€³Eéøz‚[ýLdtÊi Ž-ìtbËÉdÆê¾mª2®âÅG@búh‚¸ûÂÅTòr³‰§‘“œwÖtªþT¹¦fÜÊ‚pó;Jȶ¼M)Æþß ¨Ldv…Qù˜òJa1A7j4p#Ýì ] :‚uÆÌž“D™zÃ.ýGܨ'œØ‘1€k&nÅ4zO¤Á;wu4â€o:¯ë@Œ8ȶ‚ÀÞ+ Ånå;<ñ¡£éÍ|û ð‡>zÇ£±þø*ƒÅEêXÚ0ÔQ9ÆR1ÌSôAÒƒŠi˜cl„‹ÜÿFi)6Ø)ç#h ¦’=†!mb­¾ Ä„>®+²»H2‘"Ë3A³ÓàP—ÊÒep#×¹_†¡8RÚdà9gMa`í{ÚiÓm'ÉÈvQ†~™ÿ(CéØš™‘Bþµàc|š»¼ÿ&ºS>ZX è# “wC³êåd4´¡S¾…–Ó Ü‡ÙÙ}5ôà¼~©>%bü½_+Öúù¶lÆ%¯T½-<)ƒO¨ê‰I@2í·ö¹sPn,…µž®å׺æ«ê8,>¬läy /1oE>cá{woâ›U´ )ò~¨Âck=P;6nTH~^qZ›癄¥¾fgÉÜ+²ó­b P®žÕlž~èêw«ËÝÉxTÑ×3÷6ßl À¸¦Í g‘è®Ã–'(öOÐnËHx€Ž[Vþ¼ÌÃp~ö-‚Wj'U·>1«ÃükDd_ŽÉ#ð"UÉEÔ›>×ÄQgÀI\Éý(}L6eº÷έkF0^Û¾Ré4¥-±sH¥¢QØAi¬Ž{¼ W/;9ÙvßÞE•7J¢­)™ð hÍ_Í<î§ÈƬý¬l*_FG’Ç›è¸ñÕ¯´Íœp*͆l6º%`€ |£']Y|HãX€:œeç‹ÉŽŸÎ*Ñä+¿ø™¼÷]ŸPièúë—ÿR¶Ó)„R핾*Í,Æü‹§/6Xßñ•°t$iË:a“Ú»îd»¥ªwkBRgd¨°q‹»Ç­º'¢”—]0>ytªÀK4A•òÏMAJu~P¤ŸéUù•¨­'_Ï&V.Ë ý®àîR^µK,CLɤ_ýa^FÄ•³8 öá 3¬ÞG+a‹¯—<í^ÖÛ”!ÁÈú—´Ú&«€'þ?S#-tB¤Ý©úd†n”»N3ÅQ¥K'‡—5ÔäV­dHëŽ ºn~èB¼Sz.2Þì¢ò+žNö`²Òäw>¥‡öÊ÷ß_Á].5œÐ²y‰%™H’~X•%+)g>2­²ÔlÑ·‘H¹Žg…Ú˜ò{G×>z_ÓÛ²Áìtk=¢h¦Ç ñà•ŸB?úŸŸqYóûÿ[X†ìõ»`y¨,Éd³KƒÊú•@M^Ö¥Dñ:Szg  †ûžþÔ."6ò$‰(íXU<@{~%\2y/]§Z,B퀈ÇYuºäär↨7 ÿ®4ñím<Ý…ØÃlö¼%QRŸc¨uÆœ~ÞÚ¶4þ6@M®#HmÐ>­_(ö«1ΰú>©¤ÎG¡6©f•y¨VÁKÓG±Õä†q<"(àZ“yôÌMå­žÞ)¼Q$ÂÕ¨n[øÈFk"*?©.üdW¢dÿÓÈ~ëÝÛ-ÿoéÃÓüË[€\PG |Âmj-Mͦ³ö&EѺ}²Û¥µˆÝHÊðË>P©‚ZYi·y1î;ÁºóGÍ籡©Î  n~jnk,Ý|’°0yã`Æ$$s êÄâÄmg¤/zßwŽJ4Þ/ñ·zß+ÝÄm#µB­|%¡q§ä»ì4%Ú¬®Ê8ì.W šÙÆô о†Ç'¦žŠ‹ ¢º{!rç8q¸”Ž€Õw%r-„¦kÑË þº¤‡}Vá‚VéCÕeª ïÄYäNà ¶æsGœÕ¹1âÜå.®¬Ì;Òï/<²ZàßÞ êø’€€å­"Ç\rÄÛ0¶oj=IqÖI¼¬:níA÷(ý½9õ’{”4ípzŽécŠU0»› ƒ—úDÅ…1 œ{Dtp¸h—‚œmøP[‡:Koc-+˜hm×Ücš»@šýß~I¼U-«‚2\ï’W¶À /ìÝ 3¢L”~0©8ìŸ" ¡QcŸ€¹ö2¢»)5,z^0—³]AH™o(ê÷ifóŽò3Ôr5´—ÐjöŽ O#¾8,?* ##µûñ7n‡2l…á‹$ø©K-è· ‰~¼Í„mØãTí1Íb²­4Q¹&y ÂÚÈ ³Cu£q¦¼´u*¤F ;çaÛ²­˜r¤2#äÃ.áOر‚(ÕœÞØ„_¨ß¹ÐW„`CL'™RÎâ1yöaÜý6¬áç™òxt  RœƒÍUa=ÆËxŒü¹¥€Ö˜«yr_ÅêÀ;™ ªp>ǪwÓÃU/Z³»MŽ¡ÇÊ×!öŽç·Ñ@ÕªÙ ¯±X)cÏ‘³βۘÜ+¼i¢L"A¼¯Ræ”P²åR4\@iP™Ê‹¶¨ëGeÔö: èkþLDjw‘J³Ô{Ñ2œq= Ô˜¥ æN›ùê#tÍøOªã>WðL%ä=ssjöpÄ´Rð(çMâníMVÏMî ”_@Mÿ,|ŠÀ˜¾Îò˜ ¥ø"vm_¹e ù˜nmD¤D;:ì€l…f\¹XU…¢æ/ !·W¸Æ(è)hei¢ÕS,ÁC£M×âkY÷ëUsj«¾Bðý·ö¢4üÀ«¿Öª‘5u]é=[å™ë¦ÏQK<¾µ;¹ækƒ·yà îµ'S»_+âeòÉ€² îxVZÑÅ™Òö¾nÎ(¬É„±¸œŒ`N|Òpé‡!BW„»…þéD¶] 1OÒb y EG_!¾åØaíÉãbc•BŽÛº—éwL°.‘¹Ü.À',èB3 wcDšÒâ~P’›Ÿ›Ì‘ðtršk/ɘBcJhx?Í®¸¨¯ðÒF¾hÐüËìÕÃSJ›2#žÒŒ{éÁ‚Æ< ©¥…àæ¸c½±é üñÙ´¸S³â¤Â¦ó¸ÒþàÐ Éóƒ>×e }gÊFe”ÆÖo±t19£ÄÙYÒªŠÜLµÛEñ\Ü’(c¬À’€€Ð%rßpu*ZÒÀÆ„m‘ì¤ .åUA¢—f±ŒKM7pß“¡·±Ãþš»We}ƒR‚·C¸î„¥¥uMS¯šFÔÈk¢27CÉÿ«ø <WxIœM1Ì1x3ÃTÞ=¿‰Ûg3sÏT˜ÆñωTö#‚˜fL°& ƒrŸŽeˆ"#¤Â:"š£öˆHûð€2m j(ã²×`dÆ´bP{‘‹0ØÄþ‚&G+(9SÝ÷ns`ëWiÕ–½5ƒ%Ô ®-Tzº¸å¶ÓÌbsÆï£_°iô"!Ë!±3;nAÓ%“ ‹  ŠDÚQ‡kåÔŒ"ßåšãb0íøŒaùaä ›ú ¼¥Ó»XXwK@L³ßq—B~G§¯ÜZÈXŸ:ôÌ;]ÊÚ-4»]ÀÝ×;‰Ùxâ!,¿¼?ÈDbF@?'Œ6)Ƙ˜CØõœ­çMf|ð Dt ܯœ‚[['¸N}YïnÅŸNÂ3{œZ2®Ä´¦G£üjùìÄA\â1%w"O¦}ç C"ÿjcÀJ¢†#•ð!± “ÁòP–ÙÂýƒÇ™íü "ìÄw{H£<* _üP©½jßfI Ýô‹À£,~2Ü>v÷ÔIΖ/¾v.4ÁødЮOÈ7k2-5Üãv¼FXŸn 1òê*_¬œ ü1>ø.]?L*Ê0Cû[MŠh3ºë¯Ì{ˉÆ(Šu.ÆÌÛ˜—YÕ`J¬_¼4UTkRKe%â¤mØS5óš"ƒeÊ'ÏɶÂå?ªêrŠú%GÝC"þUÇ–¬­ÌÌ_ˆï±k’Mç*“l}©ÙÛ­YÑ,G?fß¼W¦¼ŒÈÕ\aÀ…'+u›´H‘åNì‡omy“’Ñ¿.B®¾Œ¾Iáƒ÷ˆÎ>Ê3S€Í*èýƒŒp¤¸{ŒŸ?ÅCW€ ÆÕǺûŽlW¢™Š´÷€øãhê°Éñùér××Q¬’™Èx£¾ÎÿC´ÙÐYaÑüg¹¤ë^Ôè]¹d¯¾~wÚì(Í›ZIºz{øvÉQþ„‡ê³;\Z™Ô.[¨© %yªòa~¨q”ˆK>>fÎ`T<‡#·ØžnØxZúíRñSúÔdÝeVÌfýM`g[¼dTÔ€†c+Ë’€€¡Ðò]^„ik¦iž§j,ÄW©Ž¼%´Û’¶O«0ÁÇw˜68ߺ‚ Ñ=ÐR€,üâ×5<¶Éç_ˆ \$0–‘VV{…µVø A¹·NHw?û]Å…Êç)Ã:ßÇ$«ñ÷M®þ%ë§Ì¤ãy iI1 zŽCË£ Ϩ:—ŸÍ;-î2 áÔH%1ƒÁ“ F:»ógc’Â,…šƒF?Õ¬NEï÷;Þ"jÇkPî"F&d@{ÔØˆœ`ö”Qxú¬5òÍfgE ÚjX÷–a¹ê­5}ý8ejeû ´ô69£W»ap>ϨKG6—7ë ö‹q|‡L†vâóÏ©Ã%ïY9HMJªˆD(#¿È!’ÿXS¿!*Û]=š  À¤â³Â]&0”A·_œ‡‘li(‡°·³whԠÈàŽRv$ª¶#‰ÔÍiŒÑ=ê/Iº£÷ÏèÚ?„xd\µÇ¬ƒ¹(Ó#ãì‚"ç1]ªr‰(ž8f9El§FE¸ÿ“Ü¡–>A| €w…ZT3áà°4í•"f¹wº;¨‡tKšsÐ- eôñ¼§åuí&a8hj7«ŠóâÐ%³²çvzèHÉC- ¹ìa¾äèzü'¯&P1n€‰}}xt…¿€GôÑ]µÌ¡Ëæ˜ùŒºŸ£N>¤…ñ_ÉûÌÔ#ôMê•v–El¦þ«5vâÊ}7Ý!yÈ»@ÆùKM!-*³º_l®ÐGQ„ÿè™gq=›ÇwºµÖ®ŒTKëÁn¾G IkD[^zI~^HßRæÝº`éHúäf–úû8µÇNâKÌȾr-½‡¶ï§8å®¶qˆW(î’€€¹Â[º¾D†¿3µ ‰’¢ã^šµñÃ)Ÿv9öã|GàT­œzŸ­L÷‘„/©$(ìçë*`IÓþY”F’·L™ù7ô÷¡|± C£Ÿ¨3H¯%Œ£šbàÅÞœ© ol{ÛwJ›.³¼³ ‚ûÔR¡Ï»)¼§UV†ëIé…œ±k!ç¥þc¾íÅ€ŸHxéÉc#ËúÈñãþá®gFÔªfÈjJ锚!z¦› C—[IC"ðFk u4s­‰{Ïäó[Z–otž‘Ýþiçs…މ䡓=2Œ:_¢È†]ÁÛѨͣª…?˜×i”¸ã’¶ð «6W"ÊsJØaãJ÷@²ÿÖ]Ÿü9þ Uœ=”•Ã{:õMyØs³-G§< ¸´`Ø"@šAgi¶YNNÁHuî=hà_/øtn-çPˆ™‡ͳœ¬J5aDu:@\“Zèv«‡ožnвcfF* ý¨|ˆ¬Ml“kÑ7~’'ƒ ‹0Äg »mgîåXÍ2ëjc#)™-wšÊ­9¦”I·ÀÙÇ õÏ[Ëðµ= ˆØ GŽˆð™¼¨á«4Þ{„ºP,ªóÚ.ùß|„ÈD=€GõmúÎ,o”³{í€aåO– K`Ãü•f-*U*伨La-Y‡Ža+éé·/–T!¦KÅ3 F@s%T?ž%H¥+Χ$d±&s¼°ž0ÒðÆgþý -{ø{}XÞ×°hªC ºG*¨øÌÏéfŒŽ¾õ£†ÆŒŠ9u•ÀMäëÙÈ2=°.dèÚ'OCÀ0\oÏ<‘90äߢ£Èº­ÍÉmD›wÚ@%yÌRKŽÅeògÝn†Hx¹'öµÃÝ=fqËßújˆJˆÈ|ÄD Ïu—>WÎ7²¨O #êíxeOzõæ:¬R+2§¾=èõǃÌOY"ã{ÛÃÌê o©)Ý€ÙáЕ€9½Šƒ I^!·ÆÙx~µ›iñ™`}9/r›#ºHÂè j~w´„áÆÝð [S¡!º¢¡ð°Æßþ€Ppë€Íú;Šª6p„öA¨­úU’>&ÉÎ\7sÅr‹Ýds gò š"`¿<ØÄB„ª®-¿·aHíÚœYOAµF jef¼ 8.kÔc°u49`L& ˆDÖ`±Nd[ªÖÛ1¯94ý¦rO$+»ôª Ø®¾YôäQiöž‹/@ D䯬¹Êƒ{õnÆôrpŠår@»“0»¨k£›èºVË2­!ªq8^°aÕ/iŠ­³žÎM­A­õÀœÒÛ¢ÁkÒdýÃk`ŠXªŠXb|z§ÝÒ m0#R©“ÛxÓ-ˆ4PªÃIšneÓîÒø>Q¾u 9Þ;áøˆ8Žºh¬Xò±Ð ˜Ô]ѾÝÅ\$…Y–xö[1/ åŽQa‡5ʱ€^å¤z´ð(PÆš–°¯ç÷ߣ²ÝªÒýµ±H(ëpHÀ9 +WZ°L{]ê§nxùpìΔÉÍõXO¿0–Sàá”hº¡EoÜh MhrC‡¿2*a?)ÄÉùÔ¹«$žCìëLÚoŽiä>˜âœ^fÊô›8°?øó½¢'º-øŒª¤ÛC-5»Øké'§¥F‡yB™o{ ó"„…ðñ„òp„·QL=;¾ÿ£+këi¤ÔÎc`8-àskZ"vÛs™Ô³èZ?¤—´ÍÞ!´Ú»|ÇaKnѾtëpDé‡á›£9ÜtÖÂËåJÓþMª³-×€ƒ§M r#zEžD’€€Óƒ«¤L`áÉí]ÿ7¨5¶`þÔ/,ˆTvÇh£¿S€½r#Ù°àøéJØaÃFGYz \bÓÿûFÖúmߊœ”ÂLp1·e*è—Å;P:ªT†¿Ë^3ÿ¢Š€ñþ>Ï!KYiÞ.!5MK]/ªúè³äU+†òwé‹iô·Cn•,:£žvý xO¤ný͵ýøKpbŒçASV)'ƒ"k‰ ¤^yœÇ=6À1Zv¾R{ #ÖRé‡ ƒ­¬½lUfS³¨üçYs$OH4lE?²¹+ßÌTbðZímC¹D8Û%rØÄ4”ûÔòÖw¯ÎgH‰·î•L‚&*ñ3ÑÙÙü‘èT³é™kðÅ¢¦Æ¥Ð·Š•5^ÇàFÐm'¡F†ã„ä2ð¹}ÎŽ§­¿EH?+¶•óÊ 3œxÂ?Aj´Ü竽ðÆà§6÷&} £Ë¯ ßÌý,%Áw8}´Is&`êó(dHÍ·¾SÑ#ª³$ –ì·O@ÿÖcý—ÅPî¾;fª²…šëßL4Ei«–"Áú‹ÅC[5µñËOƒYÏ»ßÇÝ7aïg+‹—“¡üHW°d[ŠÈÝS#[ºÄuG¸•Q^£¢¾{ß»g,A‘‰B¤ôô1­ï†{Qì#Aã¿é¥#Bº5vôKCaÎz]!·¸;ä”»¦ðР~4¡{l>…SÜ–ígIH•YHBCi’ມPE NfòmÔ=,VÞÀuö#¯øÐIªA+ƒŠ‚’«ü™+QAæmÄH ÇéC© ]¼,m€ãÕ™PAg3˜›rq²Î^€âÑR|.’€€öড়È{bÈ¢öJQ dÓg_ôÞ(’ÚsåoÒøStáòGååÈÁ½gC3lM|zdFt y^’^‘³nX¢,Ã"V¼š—F·Aøëô(}å(įÑúVuQ›Ε•T+‹†o&Þç·W×aHVȺX{rR÷a:St’PðjÅ¢S‚‹‚Æþ†·De$_Iç`ˆ v4pX³þAÿTE?A¶M—¬Ìµm° ¥0 ¦7}Œ?öÞ… t5…óTìb52£2l‰Ài‚ܲ¸Ì÷OЬ·¬•NsaŒbÓ“Ç{9ÙógÆ P…»è#Ö°Úx´AÌÛšž¥+¹IQXsÞNþÜÔsEvà„Á „Y)ª¥|ï÷†³(n¯Lï%ÚYØPöÖ·yÊbà‘Di×@@CA×ñ@ŸÈ“ÿUÃJÃ9«IéÒ.ù·ìnÞÁì—½ú…dMüE7†ÓÒ¾ÔmÏÚ&}yˆ°¯P¤ýDù|Çx{Ù€>ØÞ%$=J ù–Œè§}TQ– ½RljugúßÕÁDxXà”¤³OA‡–_)Äú¢Â#w¥Ë–_Á|a0Íøû"qï>9,;Ž`ÔëVâ횦VoEƒ…@94¤]þS!ÑJÞ00“¨!Ê5}çÈ„–JÂ>RÒ©•’#‹h´P¥Ó­ãî÷a}[‡ßqàÝâ=úÑÅn…çˆÕ’€€Ð©‘¥ÿlÉù ®|U•¨ñźH›z ^Ñ©ÉÏ Ÿ³Vé ÚÌýÏ‘ÇL|£d¸|7ôMfd#F†Öj—¶fñ;<Œà`Öóà³WöÍÏdAuR#NZ=þÔkM§ã.ŒƒvÐßX ×øŒµÀÈž "¿èXpfI郋Èʃ1yƒz} `«³zmAûúÑÊë TÎg•;Ájj芤ÀMœï{‚"Pi^«CP{Œ8Eô¢ªDMA¾ßæsZx%ô3÷&ªí–¾†{g Õ9ŠØí¥ øŒgâ3ç.µ+Ç*h@Ì@šK‡3Wàµ_I»Ó‘ö0M‡O •XÉ1º×Aµ§ 2¨iUé~-ªãíñA±Ãë¾!g…¨oÑÉÏ»ýÉ“Í!êç0¨{=& w5+ɦøÊýΕS˜_ /…*llëö²³ Óè©{–M»wEò`L1PÊn¾ºµ¹²…%WöÙ~Wÿ)º¾p­ïìÅnu!1jƒœ)Ej„£¾Í[ýΡöÕ{þû½aw$­cù’7ôÒèh vÖ‰ïÇ{ƒד‡qDfÌÝw^³GåX{ö¦”–¦i-+cZï®Oöa 9gâ-~ŒXà3÷ø€=‰oOðá– 6Fa2è½]i¡±Zñ ‡Ì@Fíõ.9³8Q Î[m‚¸“B§Ð€txäj¿!Hoô Jv>÷( Q\—ƒx4ßÀÛÄ.:?²™LueóHáy`s·P´Y$ªC‘¬N =ͤ ÚŸQmúa£ÿ˜Ð´áÐP=CNú ª>Ò½[Ê’RWcñKù´ŸNeȼY–À{ƒ+ÂéRFq{våd°ÖTaß´j Ï»ù®§B>Ùá+ÅVÈìAvZ4ùö  G`³…¼3ŒáªêZ±nNU°N2ÎÄYíþõŒå Øè/½k$´9b3T°Z«PzTAdjÃÞ¨ëdØ&_Óš” {Ê;³¢Pt÷zA7¿" ê*õ;nÁ¦$ב[ž‡sµŸíM R—Ÿ±à(·ËÇ ^[)È‚l³ {4UbƇºÄéj^¹öZ­¨F`ÙD2ÕHS2@OÔøëV…F¤' žˆhҨĿXð`ò^q/¨ÉÙ6« ”óCŽV3 N™Øžõ„7K ¹B Šö¶dÛLɬî[Å”}+êmWbˆâoó‚W|ÐT̳¯ª¬:}Y#ƒEµ~Àù·¯çv¯!¥QI ˜”Ôæ 2 ‘F¬1aSñìûyñ|q¦ÆëRêŸAÓÊ\Gåñ‘–’Æ,Ü´Èàá´pV­P?2šÀÜ/Š÷T!™"¨€=7äZPHQEiÈ`Ž£š’#œ¬Ð7 š}Ä(-iJ8ÉÿßiM¨uú™lܧÔŠ#r¥˜³!G@{Þ¸Ž:QkNEQû1½³Ò¾ëÍíq,QÜr1Z¡“Š­xsÂäßoåÌ‚lQ(ä7Ô¶í?0›P‡1â}­o58¨Ú--Yž=ç,Fž 5E_rqà’Ø¢nN*“¡hÌñ&ÐÖ,ýKã.þøT:K·?SÆIX¡Ë´/%Gž)Ñ4‚ç¾ENÿ*ŒãŒX«Uq° ú>S#/¿Á“|`¯ã\1Ä‹?‹àì!qƒù/òà¡ÒhÉ<¿fÿiî!Ñ7]öL•Z0„9i58[ÏoεN WÙG¯²z¨{ÉKQËAºîÛÚ¢ŠÌlÚJS˜®‡ÈFúS[_= P‡äâш™wXÛžµÙ ü[IoöÊÐRó¦¦;hà§x–³ø7w–"H’y3>ÃÁ?|yþ÷ïÎe ¡-ow5û“׋zCnõÊó,àJ®‹÷ÿŠQŒ¸á–<“©¡†)’jæ¸K\XËò×¹Íu¯*»Ó¥RŒû!4ŒޱÞ'÷„¥©iIÊÂOvßìQT]ÐîÝÈÂ9ÌßÌçÙ€·×ë[€|ì<§6ôÉ«F•]Åmשí@±ñßwåäÔEIV–„H¢fî’µ¤pJ&oUÀ*pÈfjȺºL¦Ažû ·kŸÔ…(»žµzùÿËðUÀ׉µo’©¯ÔWD—Œ3D—Nbß ˜”J’€€ÉÔPv­<ŒXqt‚O˜Œë•¨$[S.Ìò)YÁ&­º–·¥\°=[„ÿ0™I훾úq1ÝånÜ9õ©-O0ôÇýQ–Ÿ3ªûøu5ÄgR¨çþa …BHF¢vcÌPaÿ z_Qß± ‡Ï˜;+ˆ" ÃʕȎ±Cn]ZÉaâEQÕyb³´T«›;­ˆJ¼“ÖgŒôgÏ‚wM2k—*TºßsêçrÕ¼H¬Þ;ãåT¢´äÄÜÈ<ÓÃÏþ%-ÚSbB,s¥ƒy†˜FtØ­p¤Dè~šQ¯FYí™éXåÓåsöÃHÇyÝ&dÑÌMqV˜Î¶ïârO§ä±U2ÚÓ¿²_?ÍÝšé1%S¶¯¶àKO躎>èGd fy*­ÆõžëdKÖíá@àÔy©l”×·±¨}àõæC½F·õ{³È‘ëÆK£ïr6‰¥Å†Ci£^G,Ú3Äc‹P¬6´OEèú/•Ó\è¹ý@*‘ï$ÉØuÝî\ˆg8˜¸Pº,Ûà ìÕ”þÜSv‚6ªU*D“ª‰èP§‹á¢¤^Iíè1±VJ°*:ë­§a5(8™ŠYÍÚÃm¤¯ê¦ÄfêÔÞk¶±¥ûëõ1ûtŒë¸mùÐ~ ˆÞE_îá5胒1Þ3¦.Ö›(hiÈú¦düXÉÈÛIp¾:B·.çŠH¤œyÕ:xHÊus$¯H)œS …¼œ+ˆ±G6Ó®ùbŸ÷òžÀ"…Pk±7.: ¹ÑäÇFß™·«›[ã%€y[òyy⯠Wš©Ú7Æ4îW\KÞ7J;<»w\÷…(Áø97Ôœ yÛQÉ£a¯¼ØÞo´™F=ÑÐíÆ}‰ËIOR°TúqS·ÍË®x,¢»ëEÄ-ÙU8rj+ð©¾XwCV1ö¡K¢)ß%lò»;¦œdÂB…úVòE/à\5Ðb[‰€t‹™¬6`Œ¸†ÉmMu‚8qêÛQqu|ô²„‡![ySa ëK°sæÑÐâWJ4 Ox`ÑÛ©q®-+@Äû¼º[z‡‡.e`8Í@5Õ¢1”x‰°m€wJ€€Â„àÐëñ„Ñe^€Qm·úØÝ*T– ‰TÁÑpêHFyD· ?~¨éÔ¢fÀ’€€ºÞx=QYF×€š #ûTÊ_Ñpÿ1¡È¢ÑOÆã;Ú%Ál¢«…&ØÜ:Ø!Õÿï…2«°l€ëÁþj²˜&…ÈÃ4a#¿aW¡¢ü¢tÃÿá`”#ƒÒ@uŠÛ_”›†v“ÊÖîV~ÕK‚6VmRõgª:oNFÎÍâf‡Ÿ–§¼0ÄóKŸ˜÷sëÄQl_ÓŒgƒ€šk·×–Ä”«Jn•ô4f…l£säm œêdsF?{ iŠÞ_t©?ßß$Xü'g¤?}ŸNE¤1’y®¥T8ã5è7D°ÛÜ]éqdR(}”¼<{ó>ÄøÂ¤®r+¾¶ —j,"ïW˜¼Ýú¯‰ŸÞõs‹’±RéûÇo2ý×ÊÌëU$ŒÇt9âº5qö_æfßE#œg/zºn$ö­™ªœ:éºj6DÌþS)CûNµ²Y†2좖gˆu„ðÞu?Ln?@ ´ùgX;Å3úp¬Äõ±¯£1â=^÷uÈ¿çr–¨ØÜÚ!îz&X:vè)qÐÑä‰aÛBdNÿç a?ã\­@ë|®íÍŒ8]<€£‚W¼,ÚÆ÷6JXÓ i{™" ðåÍî˜ÿ·´,ãO T7=­yP6'lí™ZaÈ‹Á¿+¯Òøk!"H#í^øVH6ºߣƒÊ+)£õäü<4@s!N'??Ú¶[’¨CÚ<‹KKD3[™^÷y¥!}$'Ω<-Z[Ç»W€ƒ©Y#™  Rok— ,Ìs×kt¥pF,Í©Œ¢èRx;¬+:;•@ã¢Ƙ0,?/ƒâqúlÐ&ÕèÛPQÝá·½ýÒå”Áüºvr®TеáO6QOvÿYê°µÀ¬Ñd±4;Q•ê, |iy¢M?7s·™SëŸí^9_‘š/ïã©• 1Û5Ý~~TOÌõ»!UÝSTÝ'޲Ж{ƒLS-+#[Y6?›ÃÊ"s«ôeï/}’,V]ÓWŽ6L(ÄØKȶSüÊYŸý˜Ø8¤ š…]Þ¯ª®:Àk[˜¶›N† ìZ! í69w®‘*#ˆ?ùwË’€€¡:>™pßQ§êÿJ̧5”Ço‘ìÃkÅJ[·A&`§Š« öS&Ÿs䕦ɲÁ"ÍAÈI´ñÕmÒ¢QÃ6©ÁF\^7ôIJnŸLݤ9Ì•yRŠ}æø4ðÖܳm¹óÇyºxJ´x˜ì^൸3¿Ç?I¸rš_XsiQzÊQ„ã³GŬIh£ï´KĘuPMlô`vÂà\VvÚn–*Yª`&bæmM> “q2gjÆ{'äÎ-ûÓKH]W‘Å/Ëø5Aë\cë-¨æ6!)±r³õ]¾Cõx‚%zK`•r§ƒ ™ëtnÔ»€×èt>Ÿ³9·7;è§´ÔƒÔŸÁÀV¾s§qþ„6°ìî{OlÉ se Á -x­Õ¦–Ñm°{8›_èÿwÿ²¢¿h<ݘ™BÙ’4 x—ôе—†30Ðb£éNxáÍÍèîÐ3Ñ L¨IÎò[ÖÂ)qM0ö¾q pv™?ÿ’;wªl\xk‘Wƒ£ÀoFLå9•ÔcÌÐkd„@âžíž”"Ë¥Q°Ÿ_xbë[^tj4¬¤ƒü+§pð“¯c\'P¾ìnÚÙ¹ŠW+$Ú¡;DÞµ¸G †‰GýXG ’l˜›\ƒÎ .环²+e_û/ÓïºG'’ !Œ½Æ{aÐîRûœ¿ðà=wAÔÇP +­£gÈ Ó•4j[k$#§´go‰šØ ÈUÆnH†£šK¾.°šaï¨Ö8~/ ®ãîZ¿ ¬ÓH:é<“ê,\®cÃÃÙwÝ3§:_2f#`E§xØÍšëÅktÞ}ÇnÈ=zDn'ŸÅŒ·¤xYi‰A 9£ŸËyªÂ»(1Å]ˆ ˆ‘&ØXæè1!½½³JX3ÇáÌ#3{|ƒxRbø‹èÆ.Žlʰ±ÈÊöNW¦Uv/Q#{â£ÏÔ3Ñ–2ˆlÞŠ&)õÞAnˆ)¦l)Ânü,ÃoÍŠž’KÍgÏÄŸmü8v§vþ˜iÙ¹€ ߇›~9â.ékÊ€”e`[n¢´ 2)".3ƞ”±¨ðÞ“ÙÎô’óì²G @Ù’³túAÎYCœêbäÐQ¯m»ïÂÔ(w&áÔÄTÕ¨[NÕÓ&8%=„4)—ö¶Òàv*x0ÌÊ%y…Æ ÆÕ’€€7Å /–âÇÚaÕƒ'òïìY.©M£$¡Àû†ãOB™g]„z#¯ÿ;5\¨¸(Ⱥ&È#´%BÅõQ¢OÕbyíÑ@L¥Œ¡™[“]¶‹ŠR®G/}Ügáár‘}Ì€æÏlú¶µzœÔE¶X65BqùMÕ7Óí^ŒÍóÀŒÅ›Ÿ…2~>Ü ¨ü¾ìÜVþ)LäñJ»F™¨J›­r-¿\q±‰¥”žh¯M ·ÑöÀÇäÁ Èï :ì%?í@ÊeõƒqÂ5Ó(Ïžˆ²Ÿ*Í}'9z?qŸDqäˆ=ôêfž¶¦pÎÝùJp¦[ˆ˜sõ6í9Ùz´ÿo?4­ÛƒÀK¥=Û@Ýtj 2g;~ætðëRHs›tò僸ka^.[µ—¼Â,¦3¸nzМ²ÔƒZ<ôTÙ’’ÇYÅ⯣þ@ÍÒÜý޶‹c ®½²rð—g,’Ua|q&i?%•Œ³ÑìœO’tç.ù«^&ÌMT¥—n.6ÖÓÔŒÀ‹:q¦Ëâú’è€ô†˜¿ÁÛ…e(¨ØˆÊ, „«tÛÀ~D“ͻͬ¸3F¶§ –Yy0ÙÍq61½á£c: ðÀAW° …àìJ’nÁpñ¤0ߘÇò•Ðv…=®›Ïh/½ŸJÃá îF"õ,QdØ…µ?h p–@ËïòÜHÀÂÃYy5¸“Ðób{ÿÿÐÉÕÅ(a'æd>·„^³ÄyæzL‹WA12½†î ¥^o,':ÌËóÖ±e/óж;Q ®ûÞŒéñ ‰min%ïÛ»ª!JÒ½žfÇ…K+M Y–èÔ4¼-w[HÜâ­Š·ŽTÐñÑ^0?VCõ¹šœ~)o™‡XW3p[›~B!æ³ÎKúe…Ü<~”4–¢I§âeá‡ôÐ K¬=æ½’Âþ’7D\nëcP„Ý1&eTE …Ró‘ÀSgœZÖÈýe%_ø -À¤/)²¡p4¤®ÞϽ˂6–ðûÌ(„#|í‘;q7 •Å=Q ²pï@ØÁÞµ¤÷u¸»OÚA±.ž6K|ÌXÚk}Øßf/Œ5J£c7¢’½XIŒð– ÷°ˆƒÅØØ‚pˆ A€ÙPm\áf¤â×R]÷…/’€€¥Õ_§+°Í߀Ýë;<­“˜Wør³ ¼™^§íų5âc“uØ0EyÙ¼v ^!Í>‘ðÎ3mÁZ%®÷ϾôLƆîÍÁöÕòuªìÉF[ÂÏâAåg'µ¿ïo` ¢ØÏ¥!ö®¨ÌÕa*ú¿¬±xñ1:y—JIòÁ_wý˜ÙgÒ’c4$Úü;åIíë0Ç…ph,G§ÕYLç¦9ÐX ™°÷¾‹‘¯:ý=¯æUñ8" â¥aä8¨aR¥«[ŽÐíu¹BêMÖji/;ωñpsÕwÅ=â}ØÊ‚l´m53 “TQn³xš`j×tiüV*%"TòO¬AgeúÃÒûzüa3`>ÅF¡užá/S³4¶üùïX»U4®Uί/¿KµìðA.‚ºßZÚ ¯ÛœÎ aå¿Å€R  i·8J€ö¥•O›àÐk•× ´%«F ÓÒëÐÊm#6Œ $§¸3XiÛ4‹ãþ”©³Ø6u¡æàæ,JRŒ…k™Ïw˜9y¢MÞŽ˜€Ð9¤3Åzü‰¥ÀGÂÈ–æä{ 4dÿªßãâ †*[ú B[aÓ«€Q‡' sÿ‘C]=9oë§¾-×…Ÿ¥êh›=ôT»t„q7ÆðP3KL|±u£”ÉXôCðåÞÿ¹Ö(æ0»ÿTgÄ®µz˜\ Vr΃ºÛ%A>JŸFV"Ë9™Ç/5º‰¨ùo1€¨ºQ©¡—Æ–5Û·l fúÈcO´gNÙƒ´ÐùègSEï|´ î&Ìrz)I5AßšZföw•Ìf<˜èÚí:ìeBRbÆpú‘¹tnpÅIÆ<8ÐåMì4Oü^<ç0´ü_ÚL»×ÌhHÑJNñJ _šY:ú7…,ÐläŽurˆ$Àð}FôÛ¡‰>™|9C¸’€€¿:zÈ…÷{ µúèæÂm˜MSعP7; Ëktð^l*ëïÐKÃú\Zª‹`èõÁÄQni.ÞLÛ¢ÌÆ0S†ƒx ŠÔ-Ø)X8¦—ˆzi1ç¦O0ü¢ìsÇWÁjÞ_Jª‹{m÷Ú@d×°-7¿ ßUžÇ>Cž“Ûã¾îQ›¦ž78¤!ç»ÁÄ`ŒvøRæêkÜP%„µ!­žppÓ𨩔”{ÍHé{ÝOù‹ôÄÄWWâÓæK½ÐrÚ܆àÔ/¨w”‰–%™¦¹a\/®$MjâÔ“S—wRŽ€=_ä®F:שg’µãœ©<ý:Gëà4C˜ 7àæãq–wòàšðZ®u ÚB ¤j¡)ë¦qYÎñãpæä¸6JÅïÁü!°-º2á„4Ó-8¹ÄHILÆbÀ+‰nVçB.¡h”.$oIð¸'¥³-ÕïµsÿKp®¢ÃòD´oCÎ{ Ò÷uر|>ÛþÇ!3ÛB$Ža­V6 LAùéÍD^haþ{´€c †Ž1ÓrY&IÎî%¡cˆágþÑh#¼ày)¡¼Rg’14¾“þ²ó|(¾EŠÄd$R¬œ(½Wò ÷‘ Áã&*â§ApÁ4*e ƒ~€Tx=ÿHïy¨ÌŒ™Éô V#¤éÕ#á·W›I#à[.©7Ù“ÅŽJ¸wÞz,<¸âµd‹a“°eõè"T­£± ~’Ùö®ÀíÙb<%]™“…eÇï1ÅóZ”ª*Ã}¯ ¥¢i·ÏO‡ÔÚ¥€¯Ц›­ùÓƒ€Å}ÍYÉÆ Y{{ºÊÐÍÈ™èw”ð5O KKIªÉå<)ùìͳ°Á+1`yr.GbE„µúLtmϦ…È3Ã9+%¯´ Õp™µAÍœKyÃRï¼ÐÀÚ oãz–'ƒLt„â¢$½sÖÄû©üÕñ|€³/¹Ïh;©w9Ò 3ç9)­'@5H¿ÉP¡kPãüJÁȪ½u7½a^©ñk…´Û½KôÄ™Ûè1'/"ßu5_r„%¬/$Ev è¡ó£lêC¡¤Ò·¢¡ãk_¦Fú ó3³OuâKa¸Ïu {þüš6øDv—]ÈxXy$]ÙѧÁ’÷LÍÓcdS9·t¡fä]ü6 •añ¿§©bFÎ,ïC ˆ™VOL„"]6zèÚ.=aá|®†aç–ŽM‡¥Æð…ŽÙ"}Q¯€oQ\/t§]§ø$îñcôÄo6G,›KÓ^…ÁŠ41Œ4wn)"Ä(ß/¿èèú¡p›RÉ˯Ìþr94‡ûw•Gb°H\Ä„ñºÞú‹/@Õurõ¤®B›uÒƒ)e¿X…ÃW$ý¸èp@;gÞ.ŠàçšFgi…êÂtJ~ZÇÄFµ©ûzm<¨1޹m×0Âñ¬³:s–·¶Ô#Q/0,0\lhA¨@ÿ(ÁÌ ›]QÉëÂ.ä1^šYæa]òÕÀElA×vÊ2‹ — Šw÷(‰o)S£áÇ÷£¹$ƒ¿«®Cï#ùΧuâ’Ù>{ CJÌ•Ž tw[ Pù/ƒh”"¾!g÷™·ˆº5RTø00o¥ÖÒ•?­^¬×UœrFc3ª©—Úÿý&еÃÊï¦Êstüÿè„Ù·£øÝ6ì°ôW+*°þI‘Ò«@ ûÚá¤T®ça+ea󥩨´¹ÖhV·V’€€×p¿3yrã•&‚ä }ä"«²ÄÔî65{®hô‡Cßס 8š5×âÈ"º÷ŽpN¯%u¿·"§Ù”-wB: Ð7ÅèðMÕÈcĶ϶çõîµ¥ª}uSp¯—nóàz¼fm‰žÿzýmjp oN1¿ŽØWÛ-n¾4Ÿ×zla¯Ð'Ÿdž=¬ü¹aPËRjRS› cVKè·¨A ù?³“F„€Û{€Ñå¨íÇÜÕ5ëÈòÛ>0ïàç Ã>¹}ÎG‡ŽB6{ñÊ.Ì7W¢2.«ôPbÄaiÔÛ¼æ ôUž<õ‡ª»n\›h(ÅÄà-QT£~ƒþ¢C¢wŸ ÎzIe¿l$~äf-ûÔYš’fæv%aç`¤N숰*K§–ˆÁíéZh:ÍËq§aVû”zô KS&"\ê‡{ãŒ=>5-$ n?u{êwåBÁ”àwÊÏ4kìÇ0“»ˆtDÚ8RÕaCºkŠ žã/v.ÜU/pþ~…9óê˜~ý^­köüjhnÁ,i[ß¼Ð^–â`Tp¡%}L¶Ò>ØHíû+Ñ¡écv{™ÕowYDÙª1R/ÞóY_)š`ã–™•J¨ü<' 3O âXzÙ£Ú¼n/‡¹p¼nytú™òZÑ÷dL=_†|žÀˆTVÔª™H¦!ÊH±³4'+‹] «nw1‘-—¾Ç›CÓ§¿LÇDæž8Ñ$?^B¦!+©¨öŒ®™ƒ«Oæ$ó‘…7 ÕÃb³î>zÉŽ+ãý~ÃîýZ¼œÜeœ¡…0 ØÉ/‘JgYÞð ¦`iZC{§InÙeûÔ†Ï=Ûnå’ˆíY'ïàǵ¥hV^³ ¸A²0e¸8Íòòµ9ÌÀ¢À—­œ²•ï¡dK*ÒÀ65R!|y‡O}û4ï3³ÙºЫÀ¼"([àa1†Û‘J–²-¨ˆŽï¡3ÝáñSÎÞA1¹Æ àê:ˆ¢Ë¬rb.|—sì:ÂË Ò¹Y®ßHDÐ<…d <â:žÔ}Ÿôl½\»â ìå–‹à_K‚;É'‰ùN ˜ïÌÆvÙ=H/ãûºì*0Õe~Uÿ°8œâ{¢<Ç}«äaàF©˜z-La_Èãr¼ô¯oÙíMR’€€½4ýט¸3æqDÉ/¤/æ¯î‰äf,h&·ã[çtÚ­­rHb‚÷^!äÐ/)@Ó±dt¬Í#ß,ÂAyÇö‡xOºîè2ï ¨Ä)ˆˆÛBQ×4¥>mx¢`ô`"‡ŸUŠÔŇ‹A2-ÿ^ãÆm-2U¡]t_ÈlïeÜN_º»Ãž?ç©×E­/Œ/ºœ¶UÄ€ãI7]¢÷à?ˆs½dɪÑí¾:tßø¼g§R婲”äƒ0>…`ÙÉÇ:òØf¤ùO„oaæ7·+äÛnŽáW\‰ç*däžÄë"vY†ÓŒb^Ç09ýêÔ¥rRSɽ 4¬@OÌ‘çë.Ìžt3kZTÇ_ß9ÍÉÃ3uækœž„—1é/Ô¶¿Ú×{z¶N¢®ùyÆn9NËGîT„ŇÀGc_ÚòŸÆcgh†_¶›¹'ij¿ž“BD»lÐä„M¾xLKY¤\„õûÈ-–òcž[{§r,êdz°vËŠ—'Œ0JGЂU ÜçŸOåÛÿ¼Áecœ‘ c'ß½ÿ\®ô*!©Sá¹oÁZ°kÞÏÅæ^מ¥—EªRîUÉ!JÍR«]M±ÙHÀÜ /bjphÿ„_$ŸqŒ€Y4Cäˆ0Ž<å…IíS;¡ù 3”nõjÁNð½öx0;š‰KeµŸ™…œ¼¨ õ‹ðd¯ˆO˜faR…ÍçÉþJu³l\ø[dõ’á7_;ï ¶€|—~e:ßÏ舛kMÇtî ªQW|a©øy$µŒú$‡Yé¿™Û"êŸ2cgýý ¦SæUèWD{=TLE|ÊTcBP÷ÄÌ«MÉa>¤yÁ"˜Ã˜Ÿ^¨'Š…õY’ …ÞT%¹©-ëŽW51R{“2[-¥öø½íï—ÔCNǬ‹Ýajgë|6ŽÏ¼þÌkda®²›¶ö€uIGS¾°²Ï09Aì»jF?œâyüÕ¡ŒµG÷rÛ1L—ªiQ8 ]ÐÑëLŽù+&ÜŸ8y—_òã*™Ü‡Ó¯@ƒpu˜ÎoVԃ錖Gä²À V8ž—)89­šqtf– öƒî½<Øzuo¶ÿíöG{ÏsÍÜG°¼È,”(pÃUìÝY vjs»»Àå­Ýl‡Âƒêr¾{¥²®‰fm'ØÔ)’€€á:ÑÍ^ÇÜ£‡Y)žìG3Cm<ÑkÄ¢X(ðºUG ˜µè\܆éæxxæNþòhŠÕ©™ )YòBK ɞκ«øjì-Mlɸ(™1'xeäßu<šDˆâ<@@PmteÍch¹[HO5œD~ƒŒ¿Ü‚Âã|£D¢ôµÇv;³ Ý!|+œï?’‚Z|{ÀãÏ?ÈIgÔ%]|BƒJp˜’õ‹Ñ„b¥EoG.(”s¶ ªH(Ê-þ‘#²b€ŠòY’p¹ìîÛ ©ô°Gß Mi°QQ޾up~k;>¾š:¿½‡ª¼7w!;´MG;«.ûRî/¯å D[\6oSOÝ\vÆd!_ ðÀݔƂÉ ÜšB7ÚëÂ,[º z¾ÝÚÙ·x³^OŒMÿ’ò‘anÄ}ðrV&ˆIg,É’’ã9%‡r”ð§Ï1ŽÔßü3´¦ì«Õƒó‚Æò·Â ú(-oo÷ꊤûƒÝr‡7±ôß"0eëv\U"ˆF#ýå\ Š’3Vvöø¥ú¾ÖÁE XüåK¢ Ïg“¿üÏàÅLÉ D1Q—U.8…]ð\…·¼š¶ÇGt¨‡è®$ Ö hᎵ~Éêa`“Åó9|‚æ/30cmMè8s Ыx1WÞ†E¹ûmÃ/¡ZÁýyè>g´B\ U,ƒ·ê@´Ït9_¢^¡J!¢ö°Š×®2vlðnOî°µ"\$ËB`£éƒÄ€ò§¹}JòÝÏú¾´¿…kv¥¬…¤‘=t´1ÄÓ¦äÛ»$BB¤—2¸sÿ¼ÀÇtäSܘ×Îi›åS'Q«êðëfíöºw+¸Íék¡§‘ºÍ"¸}n?*†& 3%'.` “E“·ä®ˆ®±Îȉ8۽ؾŌýï©Xܰ‡®,T“rJœtĤpŒ ÷/QƒÅ«ÚðùÁ¬ËÊ'ò^’?á­$ó1,oÚ£ì­hšÒ6°‚ø+$ƒŸ7‚ýWÔ¦֔Ëüµ|YTB÷“{¦Ê@¡‘ Kz3XëÂP‘'ùZ›«%à±kúU‚ žM‰ýaU€]ÿ~b1?+h¤ˆ“(kð³¡3R6)cÂfV_q±âÅI«zÔ>ß×ê”s·äS5 ‘â=.˜ +(í5‰™› 2äÚÜy`ê:]®¦+ƒ‘|SÄÈÓž=1㕟…kú¡è?Ë¥‘²N=h”õc?µšêðtaª ÕK4¢ ,@Ь;%øEãY}ðò¬g '¦WÊuÒÅö-W¸j>« #Ø™(Œì ß nsöY½ŠÅt íÐx«—äèÞ‘JŽùᙑÅ>š6"€fw]ôõy?ØËIü˜$¡¼yÒQÚ /ÚìÓ)Yñ^Mƒ…œí…ìL™+t`ʳեêoŒm)cd”À–žÌ7úO^­”Ýk¤¡lÜ7ðĤ3ifN]¿êö©ôýÓIñìqG·Y£Qvé$0Sa@·<r¹¹š… Eo¬‰±1bs)žäùiN¡ýv³Ó$aqä@*“Ûi ×È>EXÎáì=¥/­š]öOk|ã*`yW±iѸ’>´9;s€`ŽN4/Û‡DNdu)u`P—îÏZ´þ ª“ ¶4(кó Ït!ŸA‘­Èî;ű1$’÷Žv¥~ºy×Dܲ‹½Uƒÿ¡ãùÓÊÀ%þ(p?KðL¿éï½¾²‚uËù°.v#Ô_j©®ÚþLn ïleõ…mÙ`ÿI‹܈ˆmÇž¬®NRŠ ö®¹ê’€€Ô"oíò3.HþOœ—Ä §m&ç ­95­äèVb?zü Þ˜ÕöÉ`ÆÅqÿ¡kXïóÏ"@•S~¹óžM˜=ë÷Ãò·gÆnP̺áÆÌyöv´qÈ4ë®d_s¸>‹Ñï9å&¦‘êé—Co2g„ÑÌ‹§ØÖS4WÓO5€™`3žÃin a&¹ã~$eñ©ëHûÏÜ‚‹ÛuÏ«4¬EÞiÖj9»ç«E½¥M "¡^ ª56ÇÖÏÝœkɼßãYn4LŠádçèÿW"¿¶ü(ólÝzÍÁ‹-IR7G"²ïšF©)‚¯lȫ̗H3Ýdâø¦×a¦S¾ÆEMJyð¥,n”GŒ¯Á(ÖäÏ"NäÇû•Í*$i86f:Z3ðDïa[I5?ÜO3ü‹-Šãb)…!%V>ˆˆßRÏë_6íAÀÐB'⫯Ùç~ËßÂ÷ÀmÕB„ úM÷¼ßºOxñòÍÅ_ɰWY!‡tTÔôìátÃítrr7cÅêuJ2òw,j’` }4³ÜÊ«èP §jNº¥ôe5›Q$œnعLçd˜7”6¤“m6ƒK̼“4”òN÷K¾«»‚4¹ulÞÏ»\ÿ榵 ´–ˆD“š£ª-ÃîGGvP¢û DÑ},ùû¡Ç&:ôœþÞ²Õ÷eÏWØ´Ä*J饌 žªxí·<Ü$Zuå<ó•;Oa‚ÓhX•eÙ@Y352Ù&Ò,Œú¤L"5ìøN]b››.ŒoÎO¨Ý0(2yg:XËOŠK"ÃA[2îódN§¢Gxé²ð/fàóh©×Ñ"_`a¦x æ–N+^˜¤F)Væmblc‰2åb*9t7gÑ‘E:}»ùȻʫ)È/:#@wíîV®¶ÔîÜÀ6ÒùÁ{ÛPøéËöÒ¢A¸¨ïQüÛb³Øv·38PÝ÷OÇÂ\i#«êQ§HÐ%§qÚvj/…“ù®·jÕ²£úØüu[ï ¥öÿR£â·LŽÂ8,[^×·ù“¶yQšŽÝNÿ¬ˆkG¹™eç³èúéZß«`åPÊ êØFû½¡g&˜oÎö.QÛç0¼ßÐŒ}ƒ_FÇ}¼! ‚SºÏ ¤PYß¼OŠÔÏxªøÞçuÚ^=U’€€ö؇ñ]ª«•þêTiŸñþ]ò•ÉxÀWoÚcÜÁ€M@*J•ƒ:fÑŒ‡zɎФ=úЇî3²äÈÊÀ1¸¨HGi‘GÌ‘!²s1Ž-p©ÁW³¨³Þ Ú£Þ„ÑÉ»Ög¸Ó/9’¦å“,½ÀZpÇ8•a{ಊÃ-­¯ÂëŠtW„”ÌÜs¡Ê4¿»%ÉçCnÅ%OopXN!’赎<¿*Ì-Žs¿ô˜¸Ù4vµ ûÍ¥¤õÊI(&ó\èJ~™É­€³f†P£ïŸP-Aä&—è&×~„3ôÄó+!iÐ&^aÊ †øýD¼O¸{—©´¡¡ôNõI‘ã”àÅʇž½›c/ˆ¤yªçÕó¥fa!”s$U6Ê>Ø·5™¿Ž(ïKžsÆü(ðË|[‡´*V‚õ25ïüÞz–‚9M»ó{»2Ñ\Êü;Ô07®ÔÌ W÷„£è4:}€Üv|ÕâŒØëíRk©¦VÚ4O$ÇX‡ô.FÂ)lìžÎ§½.ò2*¥_=CfîŽ"¥XqPá•‘ôñÞNÎÃÕŽøv.ö¯,ñ†‘KB9i!Dwè©‹Žµ‘òãdsØj‡Pþ¡sj—­•^õ+µDÈ•>#ú@ò‰óÎ0>Ã.·±ó£féæÂ)ÑU¥°]¸2‡¼ ™Ž5jÈlUÄÉLÎX¨G‚ ”_r3ÐY[ùÎÙíir,õÊSñ[Y9àB«þu¥rþ=–„õ\sãà7ãkzÇ¥w‰¦nƒXžƒš.xd„Œ÷fÃÏEÂy%€!œ¾Ÿ} (>)çf›à%ž¦R™8ÏÄÉ;”L±ÅûÂex§Ó[¶ie- ² ? ½rõ‡ªšúË´W9]aL±î•tô¯Û°*hÙ¬ì|g!¹WÓôÀ¹~ì ý×éjÆ­(ð\Ý­”™kŸ*]†÷ä(™Ç?eo‹ŠH$ Dcˆ/™²‘KsÂ0JºdwUj¼¿¿íM¡¢ï‰ª F!{C+ê]g‚úÏ 6|, ¶D¨Šè×’€€Ê;ˆ—Ë6KN?ôâˆAj’®¾u"SWtÛæþÛX¿yLôÏœäý_—¬RºïûÂíäÛtx=À™ø¤¯à Äܰg\þbË(Þèm)÷x“c L‹ºSêc­¯ÿI‚ å­¬¡RÂ<Ó×çSÕX ³‹ fº¢s{±•)}ÈØgë_ýQÒØFÙ€Á8ÁW‡<(÷º|j–ê¼Ä®éÈ"8ÚªkôWã«RzR_ûéü>I9yiä¡™‘júR»’á¯v÷ò´µ4+Lu¹kH1$XÀéŽ}…eX®ÞQoÒwÀŽ®€q´QÓw6àNéWQ€õZ7í¼}í¼ÙZxnV$i·•É—Ÿmù]ÚIF®¤-°zwÕF^@\=ö-·>•eŽvb¤¡LÎ`껵.¹CrÖhwã†ÚÕÌy£â' •Ù³ãa¨ÿWµœ—…&N¯í2Ò»èÝ &–FÑÆs*¦söŸ—7`yÿp}±´öÀã{º`=ßÄ»f ¶#sFä[‰/\„ívöåcª{óKÌkÀR|¦q:p¶õô¹!‹©]”}5’Cÿ¤@×A‰§-`µÁAç…oÝ\ê1·’HúÚÝv²¨f^Ž ÜÍÛ8…§Š`qÁäZ„4”ÚŸsܵµf&²½/âÑëmu`L|³¤Ι“̼{Æ@Lhè!ò*c‚Tηu¡?ÐeŸTÑ£)4l¹ÆÎÙbÖc€ÿýÈ3Ò¥þâ§µ’îéºâʃóªë$°aï#ý•湎øÌs9>«ìLùáé'fW…{0é‘èŽ}¡·œ°éösÿdtÓ·ݰíÜt¥ÛçÒ 4FrS}#—ßdf!2DÝÀJÝ9§‘sKgáÐ~-Xäxƒ»×°î— \xf;4é*ø,§’Tn*"îA±SSY†|L:‹9 »wšËÖa;fŒÄH3ƒ‡ØÏÉÄoŸkô=ŸÈîüAm¹C!›Mº4„.!ˆìÒÞ±Í%Sˆ ¯T_»ÇLq=Q’Ò³QgEüÁOPH럶q¬1_Á¸r£&áL‘é/\ÎKA“6¦ÁN[CŠ* ¡£æàh]bÖ#è€ =]-É6¿ˆ©§c¢SEQkjVä¬&Žž¥Œ:wÀ$|¢îÜg£²+U¦Æ±| ¦®‡Z¯Á’€€Ó®Ù ΈŸ4šÛ*ÿdn -[Ñ[¸}ZÀ#tË&ÔOó‰ó•É©^Û‹û¢ L=ì(NÌ@•ªß®Nº.æåëÞÖM 5þâIAãŠøx)ÃfÅuó’ñ­¿ÿŸKŒªËkTÓ`ù´¢p4üó¸V\Œô.+[Œ=:™6·Ï÷žãYYÎë'øOZÑg±}©½Øª"¾“2³©(ЏìÙô æ‘>_5An ßPÑÓ.,9É;b –Tú³õÙ6$Ey˜ÕBO„‰ŽErÎë~Ùx’n Âçîïi…“Þ7«Ýèc¥à11×0:.Ð\.S€iÛ—{¶¢ˆÎ½e¹«ØõÉ)D²¿5ÎomV G;z±J1˜¨ábWT>–á*å ŸÛ*B[@‚)®WXվͦM2ºËLøë-ùuÂÏtGÌK%ãe©*/j&YœñoM`|þJZB ƒY›‘ B_]ó a¨¼ÂêJ²>sYØÝå´ —° ø¦Åp%…îo­„•Űý¨ÐÂÌ åd ¶nÄ¡O"Eõy|©|7»î‚Þæä¤I¶~âϬ¶qráDà]¦Èºd*[íµÏþWú·êb0ìª@.Öhd¹á]ˆÙA«k1Âo,>Ë6 '«à¹Ï9®©ì>­µRl ;`-ØŽÁë-/ÜD` /çpº+ÿö›úÕ‚ÝôŸ®øõVòKE›÷çÕ›;ZXS:¾ð°rÔ™T¡ö!´¨Â€±\Ñv¹€å¡·îK² ‚Íì Ò !ÅCP«Á/©¥úb\,Y£¯?7“¿—åb_–@Õn«I}õ&çm\Ìñx%;0[… aÍ&_1¯IzÂnW0 SýÛã–Ø ÌGÉ+ ÚNuOÑtÿ„`Æ/€Ã ©g\z¿7aw=îÅ­³cž5I}[x“¡‡ˆ’]º{dØP9Lù¬ð±>ðGX]L&­± Žh/±ò3Ò¾HŦ÷/ü^m®Œ´ž÷;n°Ù½é_€F øs0€ e žð.àí¸8iœqQÍfÂë!FF’ùòŽCµtœ]‡W" ²vDB¡^“I“]¿}ÓÓÉ[¨Ht1r:¸m4¹ÚcÞˆ@¦ ókJ’€€Óº¬:Ùô*æW¤Œ@ùKCIWŸ¹š–.¸. 8{Ç~½ÌÄNUoÊsED+80 'Ë_jµŒvKJÝ P’ñR’lÔ^”…‡Œ× 2}û²u ¾hÂÁY¾(‰h^ÁÓ×1Ö-^*,U±ò_UÀÀR=ƒ€J{wOóô0o';•÷ y¬ò®qšé¸-9e²Œ7fâA€@n‰ÑOLöžcfFÌ»RB×ôl«gϘ+ •” þ‘­ûqÖãܬô_ÌÐM4ÜCeîõ®nùzáV+jŒbÄÜ‚Δ^]àÏß–¦øžd¼Ï‡¾ga&×YÒÁMpP i»VWÙ|¸ÚŠ~ YãO¢ñ´+n¿qtv üd´ÁûálÉ!¨CFÙ “ËäšIË›ý§¬Ó˜õOœ,Zük/#¹‚óô¿.âµ» Hˆ€Ëë„Æ)6sÖË8ƒk_mW†N6µ¯b@uøº¶Ç¢œQlû±œ[תè0ÆN¥¤{[™µ™í¾xÉ×.A>}¿‚n{¨š™ÊNUÙIÖ†t9´;h[.{ _Ê×MHòØ ¼ü¦§¾êÐ kC\œÐ@ÛÐòxzìuwÔǘ¸´‹o`¤¬•9b+b‡¼‡1BË8/­‚ú$¹¢ì“©MP‡Jׇ7?‚ÈÛ2!¼Gö‰ˆŸE©%~ú]ÜKÆ›[›Œ¾?0\³ž’#%Y,ɈÏ^èÿœèJ‹Á¡¬*0„j2­“|®„G€¬fÖ©“·Ë ÿßý3}mÒ QÁ( &Ïûq5^êO20Çþ“–èbJ¤½/.`þ+•]utRLë])ÿ1“Ì…@Ê(fflxí!QguLð=ŸÑ¥¹8af©®œÐ®“š«Ø;t’€€Ö'Øúè§#z^ÚþÄÔ¾’«Å?ÄÅ–rà:XŸÄ{‰ñžÕ\6n¸­ô‚%{éöÆNólšÈÉ}Ó±+a€…ÎóÝRI¢7CpÛ¹ýÝAGfº³Eüì†Ë–¼Éœk>½—ß0 ¬E™š ì#²¢}ãÓ *h=„¨ðÈÇnÚ›µò3ºaÃy#EuÚ‘ ÉBÜÊÝ/®%1¾€l°cª8ƒ7“{à¶rË7©“%n]ºB”nƒÉo~Ã{DoZ® "ÃØ23JÀ&&èã·­*¿] õØ´1Ïv!§>T´ìbˆBćFð|ÓýâV0¡(¢>Ì='CsGž‰û"`f~p ÈÊÏM—Nž€ƒ‰ÖKƒ›ærkÑQÆlç2¡Yþ€3ÞÔoxóÕ^}›À[ï7twTÎÐ "&ÃPCk¬œÊÜ¥ºúçl¦vv}Pdú‡€ßƒdømBvÃÚgGT§uÛ‡E«¬ùœ‡U ÈþYÜùB»ôˆæŸÀê?p¢Ñ<Ó4z³¤ [ÑAÄ_°ªV‰»Ò­ü„¥“A/ØûÇ1kƒM«éبãŘÑ@èõl”+jŠsµD8îJ¶ŽÙ–G2ãÂ_?Îÿ7:ÞNåÏÔÚ0f¬ãÇÔ¢» y§yl"æßßh…¶ °NÐæÑø'Ö·‚²|³"¤î^ø1!cÃþ]¹®Ó!èò„;‹‡`xŒ¶wö‚8 ‡#Üìþ¤ ÓYÍÛZkK5ØäW9ƒgäncêbbçk_'úø¥GMz,¯•VäuýÆ·½ÌÕækD°,IÓÊTªKtÙ•†ðn¥¤Ýè6U&¡[ÅU°ÖÊyŸˆ¾¼±Ô<"®+¬ÙùËÓ Me ásö³e-# œ~J’KdQoø‰:¸LÛ’óÏ9é5E–Ð8[SÕœ /îÄ,[v[ó¢o/ïEj=ãæ@P¤C¶z‘ŒƒñPzÖd{Ž<ÇEŸZ3q? 'm º€Üù-ÁþÍ%VÍ-Ì4渿÷¼ÎSÑ¡5’Mô9¼%†0yh®XŸ/g›?‡ð¹(ûdÝ_ 4Ï[úW,Dp²é[¶V›¥ªåÇf°&kë÷µ‹öÒsZ*úQ§Ù­ [¨ ø‰È¨Št–±c¿·7~’€€Äèá[âÍÝ[ ·â&‘u"XÓƒä€ìç ˆœÎÜê½ÈȨȳô.)v;Sîq_J•¿TE3D«Q· åkHí9ÛZdO ¶>}21à)‡D$ÜaÍEÊñ"•VWa%§ƒEš§®ýèyšÍ6ù§\¦‚앸"vXsÞÙ§)Ýá\¡1ÁÌ2JBh—HÕßÞ¢93S4W©ÏÕÛ=‡îmâÙ4…2!OŽw{ ùÀÝÏ/š¥»G­Ž°]/éÀ—Jð™à´ÿ^ÈÆ¼šK8CJÉZrE ЋûF€‘mu¼Ö$³ZUZñ¨ì}›–?H,±“ÌåÈWX[þì˜ùÕ—.úQ<óÇÌä„ùê¹\ã}ëojº¥}?O'~ìsºÁ­ˆÔ-€P„:)YÃêŽþ«•«1Ûðî'N…;»ÂyÞ‹—›2!Èôõi÷oa‡» ŽæƒYRšw׊ïøÿ‡ºkáy2ÇDQ÷R]®YèR{˯¯0á¦6^µC÷# ¥=riÑÆØ…ŽoÏ!ÂYåU¼×o^nãE™Åu¿,ðNýjôåj{®¯ÙÆý$,ûX‘ñÂW>xÆ<9×Ú‡±÷~$)Ê×ФÑÞˆ´z ç`ÇçìãgÊg .%ý—9úúÏÀ·ZÄÑþJ¹NÁäVÔãÑuå¶ÒƒÃ©‘‚÷`M1Q7Ï•Œ·Íµ{úb”»{w|Lc¥¢š¨Ö¶}៤÷ JT±—DÆÂ!yܶ‰Xzã(¨Û@4Xß?aà'¯Þ ðjµd~`‚È–£oÕî[ÈÙ1kR7ñü·Yò@ëMΘ,Ø=^«QhA×÷Ažaœ%8ʃ8•eͪ¯!Wëó#Éý  ^—«²}ÎzOgH"g4‡Ì?W‹®1¯Òl,xÞœi®6oHî¼TáL+_< A ¿ž,z“F–~[jàõ ø`í4¾¹)7§ØÑ½“ÚÊI s/ßÁ_·ä„žèmßl‹[°û¸­ûèÈFGÝ+Ø»[Yˆ²E”·±·-9©“Ú‚¾:‘Â-¸zWEÖ}SЊ қ΀¨íVJÅ|¦ê`ƒ´Z—4‚ø¼µáRh ¿û3™4ôá×±4ù†b:6kM–°r)’€€¹N_ƒ.>“…b`G KLGæ Z½€üÜ-"–¶ù3(«@;&£%Ý2;Jä”ïÛºÞ`j´ÈxÜÌ™dY†:ïÈ4ÔÃlÞ£DwBil œ¼N°žÞ¸LcÖjó¾’^Ý1u®=!@%Ζ[Ö‚îL$îííe)ürÎ@€÷d7lƒoX™@´¥% kCï F‹õ®1‹‘2›ÿ>l¢¦·ãä ©|®tDMƒ6û2Ç-Þ‰a½·m 2Šsri¾‚OoPб‰J¹cNßʇÈé çïr=c]éΠzœ œ¶C&G_Mö•g³§Â~,cÆ®¬hi"sl»Ê\"÷Í ëÔž.}¥Ž¤GR>Ë®Ü2Qîá$„ËT+™Ñ‹¿]q4‹©¿Þ[†ã¼§Lé‹:{“™/+úèm"Bþ /yåz?×oòWËq6|Áî`:?)ìøáªHïÆ}u.ôAëÅ»áÈúÅAöˆI_œtlåë=§2ø)ÁËl~Ègg€]”P‘àMP¸?BI·IÜþ {͆_4íGîý1½33œÂÁy9)oäú­þ™’sš†UƒÚ‘å«aVkN@PÅ ÏË£õJ^•;<…F™JÓÖŒëꢲ„F0=/tƒÀl({Í5mz†¶Å'‚ÚµbJ"?ò¾s^!ÜRRÌ”ý€û/‹ñÔÒ×–|êjÝqÔä?­X£NrïWõydN¯™$‘³ŠÀ\T \XÛD )†œì}8ÄB¹µ‹›ýVü”Gþ¶OÐ+_p’«¼–…niÙk›ºÔ`ÞX[‚@Áî£Ó¢ç>RîúJÚ^‹´Ïn ¬Vò$‡ÐÊŒAërô>Êm½'©ëÈû¤+J«GŸ•œù¤òüh¸:-ÎDhMøj„ý윒¸åzLÅKñ])E»œBŒR¼)Û£T í‰j/¨2ÞdØÚkËwç% ll‹;ÙŸóu͵y’€€Ç$FÙ©¥ŠÌ …Éa½¶h_Ì×ÉR$÷La>½µG—ÈC4@4Ôǵ+ø4ig1Ð~7š›ï¨þxQßGy­h–î§³®ì%‰È „@“ôˆ;Š—kF¡ÆEÝRSR ’8œëÐ…x¨€@L¥ß¶Cm˜N8{d‡n»({è¡üG.þIáÓƒ„âxÿ‰2çô§§cî 3<ÉÒ2÷¼7ħ´Ƅ†â­8u´ÚŸ2[Lì3z_å/J‰Í ,ð7°OÌ&cè›ÓÕiE=p&•ûü€HtÊÞ#œ9¢PózœmoP,>io©XÂ3+ &óSOl™Äb ½U]Ý@ `À ú{ ¼žå€šÉè„_?µ_Ê,ˆáMšÐãô{ÛVŸj°0Ëhiñ—«»³Áhz²Ð)$±£Î݂뢂îšò•˜Ë·$O/·Ÿ^B1–/³Eמ½œ¥/;Á¯*ű¨™ÐB7Ç™ádçµ±ãîË äs˜èR7*ž¥ÝŽ2ˆ,ŽE'òÈÒ¡uR¡?ÅGzÊ~‡GÜeíÑËç¸\†àk·pÁÚèβY1j¹õ/ä‰[Þl‰ ñ‡ÖÃP©µ 8LwК¹ »Fî©á“IoÊݨ–[ ˆ»3³á0 `Št)H®Ê]±ÑÓê'cÜíȺê¯ðR@+Š¿ì'yµ«¸¬CéìºêgT‹ ‰ ¹ÙÑÙ̳CŠÔÍV.Ô”iõ²lè¸âO–ŒG#ÕNDiüV‡2ƒ[’8_K,¯OD‹-¨÷àߨé òø¦ Û7Kûò1VŽ h g„ Bÿµð»µ*¼ ÇÖe·uœÇó—´¢~¨Ö'JÔhüö2å.’.>›(ÊKÚÍžã*¼Ì“ÊqѺSÙ6)ô®‰iù€£Gÿ?büw%ñ>·Øª?·[Úw‚”Å|_û`Ž']ÎCZ·DÂd«دYŽÆPàCŽò ¶XfH䪱ûW‚äkó}ÕñW%n–\ è2wÁ½›63‘z[ÕïÛ˜´? ‘úÓêÍÀµoöæû›©¤VKËÛ*!®ŸSëÒ ë´Œi‚.ìfÓóVôq§®æ°N:Ht3_E™]ÍÂkÛ k®V Ë—ï=@ƒ’Ç6RZ£˜3f±JÑ̯Þ!ÆxèKidN„À]Û¿<¶|Ê%Áž…Ì׃ “F‘ó|Æ~³Ôúvl”t*ZºN„OÅ!—V÷n×{?µÐ«ÍN=,1Ðliœþ÷ïô“î£t÷B…-GÁÑ/ÏiØðv{ ÀŸ…¼KÞm h^~aÃ#YÏ3t÷E´–ÓÍSãKßÕË¿#Ó˜2AM˜…6ÒDõÇÊ"é=àœ;ª0‰>tyúniH,FA –­™J¼Q eGY®Ÿsn¶ŠÅ³à~*Ã~ ú0š×›T“™%yáÍFr²Ó*> Uóœklzk™ê ï çÐuéc<’C»6+¬˜v€¢T.ÍÝÙbÄÛ¹B`û¯ ýÏäŸÆY~…¾ ë¨X￘~Ív‹Sß ÆÅkгbŸÒ›ºª°øÙeoÐB@ž˜ö1ì»Ûj$ßÁ@Ro·o<Õ,áeÙT³lÅ¡| lu¢Y¤ÀíŸ dü[¼4´ ÖÓNÔB_ŽYÄ?,€†+¸l¬bÄ8’ILä“÷âɱ–…_Ü2?Ak,™—øÝœñl¸`’ޅЩH¬-Ôšo!)¬õ¸!«q” <¡ÍÒ…ùjzøÚ³ø8+ ˆ—„ÈcÊ“* ’€€Âxt ¦fõ+6¬r£ìü\~ßÍp'<% ð‹7Ž):òµ p|ýãÓ5.³—üD¤!Ø .ŒªJ)$÷×åàû6¤]y[Ï*hbñ~Êý‡ç ˤµBŒ¿nްgÝŠ™ìU¼jFCÞ{ì³mè9=ŒÅÛfÅC5X”I QÄr¶ß@G¹¾uãh^ä"‹‰’†Î©”Fß¿Ó ó ´¤µµ|ý·ïûûîwÃ~7—á)Îk¯^s)w;U’YÊ›J´jC"”½h;–‘‘ý ±5ø_é¤ñƒT…+Õm†Z†%W;ñùíÆò¼¿éÿ×Èø8èÞ6sÆí€´аµæøî¿§ŸqÝxco “¼]{@‰6æ½TÔ?¿ºé,¨i¸FO:Ñ›7.*°Æ=I ˜žÝÿ#±¾è5ÑMÉ eÿîsùââÑ ß–öŠŽ'¦uôU ôð6ÇÀhx­y˜‘¸P+AD¦2uÇ=û…z5k&U7ÁÎËùKsn·IÃÍŽiô¬Ó¼2ž©[;>¿åŽpؼ¼´ŸïÂ¥[á'Ûô»£ó¬xñt¶ž¯°IHAõ”ÌD|»9uÇ­Ïò“…üìMp— ‰£)žÖ2_‡5¾bêÜÅž«€,ÓÛ. "ó\ò˜›7-êtõ¼©…}?ª5”ÿ)â©i…bÛ%¥.—ß"ÆNìF‹}mݱ£6~‘ék‡ª–GDꙋ­Ñ¯,ͽ5 Zˆ–g†Oj¡è+Hìy—[Qõ1ÛpÔÒ¬zK3ãvöªIFþ%§nÖàVJÈЗí¸ÚØÎàŠ@ Î;±‡u_º¤…Ë’rè<À ¢·Û£Ü˜ÀŸö7šæ=3";nXï#$#)P_'ÖX^¾½UÔõ-f¶FjÀ2<#Ó½¾ÿóãç k\ ©+OEvnpÞ ýX^”Eðϲ.Y’#gŠæ"\Ræ´lñ™ý¬:—ÌßÄ ší«].€=tàdt,<ݧr‰ì9Þi¥í$Pëýž!Æ™5¬ÁµÇqüâCÛ0e£=t‡®7¥¹½.¿çÿvUàÆdb‘ˆ­ºØâÆ£öLËlhæÿÿÚ1òÓmÁE ä3E:‘¾&ߊ˜bô”z¢’<ìt(Fh›’]õÛeµÄÜÕ`H‘Ź]\^’€€°u¡Ùì:ð 'Ö}ÃPáAúâ^q9I À~™PJØv]d[¿¶‰²ø(ù—ž³aüØ/{>žþhòçˇÍÉÓaÏeBÂR·»,ïÕk=ž¯rwñ*"Ý7«õþ qý<°×ÖxDÖÉ&•‰²Ésû^ýwH«>7}YÖƒ('¿á\×Ñ™µŒ…m&¶Ö#øÙdbMZ'{âOk¯jnméƒgR»2ëÂŽ‡¹‘«HyÇ£²#ƒc‡Û®h«‡ðE§5©ÏÕ®Q“Gyá1òœo @5¿î[jPâ!`AËÿ½‰.¢ ˉ^¿ ÞzùŒÝÝÙ.†§)2_ƒÙöLAL¡lZš1E‡†›íŸ™„'Ç SIÑeÜšìäVÜ3…øHŸ»#\ä‚ëMPœªè¼å˜GZëv¸uÀf–@º†oÛWAO\ä06§ƒ flíT*Ì {⻩=l{lÿ­BÀ’!³Tåô];üJÌ,¹I ,+R@\8”B%ÛRžÆ||d¹Ê¿w!«ŠÕ\Égq{ÚGý•(84òp!œ£ÙR9Ê7”“­Õm}P[‚ãË骭vg1>@EEÔÕ9"˦7{~îwñV3\ë0ÛEò¸Ræ‰ÇØé°ÝsÙÓp …ãC¯ôŒƒ:ùÞÑ~Qù›PÔ÷-äÁoâѹébš+ý^]Ú+út¡O¤8ëvh„Lq’óÕ†®¦N]ÄæÇs¶,Z¯ñËüX‘þF=é·-"ͯ¡J†5€øO·‡Fê²ö& Ô>_íË-©£m àx½Åã0|,x–½G¹vïºâŒÓ¾ý:qø9pKŽôÊ3vç¬ñµ('[×mÁé¹jÈhùsõrA»òß;¦e*òÇþµ“ë}ÁtHú6M‡&ýš\|Èc{qªä;$Äf¯^üŠ"Q›Í–ˆÒC~­ò‘¶*°añ‹=Ѽ`ÃÕÈjAwðˆªÞ…æ A¬½ê¼ÿÀ5iOx@óI=Áß•Üe[äe„:Šˆò{pö¥”Bcª¯ÖÛÔÉî' èÿ‚¡§ËÉõoòÆï+¬‡¨b/ѧG_•=„íLÌÙ‹:Læk¦[ª„'²kGNN¾o¾Ä±)à5cša qiÓºS÷íùi\•¸Ú!XØå$™^|E¯ ‰¡’€€ÐŸôNK²€}g^Z^(ŽX£kÖÇÂÖ8¿“`¼¯,il¿rÐ}ׂv+œ¾˜sd7qEÇœk™Ýhí¦” VXž.㛬®îÒ×ÊØßP–ËVØ6‘²w*nyû¶q9§„ëŽ7Øt5ê§^À|4¼.Wë&Oš&¤’ýdàO®<;Ð]åSZ¯Ø"Ι5µ3@3ù§:&LJ'U‰Ä»î #¼Tôv{fŸ´Ù1 Å´kþ ?Uóûvïé³±ÂqR0ÓÓ§š•í×ÖÐÚåøøLQ³}Ë7“ŒÂ£‚Ê)"y&j1{ÿª]ºíeÿIZ²Ø`.X¨ý–oè’Id¡:’¬B0w䘗ÔH³%]S|“í—À•Þ”:C6OÜk,ˆn‚L"ŒÈgùy•«8O|y À1VP®{Êîe´ôC!ËbÑx)ïFÎã«Ø«æíPÅ"”´a–;Þj$}öˆT–¼;æànÚQ,y"ísß’„O6-WObÓw¹Ï>\0ì§…žZé‡"~¨® ] ~}XçVôœ%íI™Bù¹^®úy -«þKV÷H}{Å!º`ðö×hõ ÏMÕšI¶Â÷1 rÅËê®§7!,"½ˆÚ‘§Zȹ9|qkD"H<—lg4„îέOAâ;õ‘ÔUÜi‡¼úÄ')V¥e8ò‡CbQÁÒ¿ÂTǃc^”VÁ>?oi1*¸Fk¨ê³ýŒ¢4ôw¬o.;Áe߯µŒaŸ‰»0™w…ÝÂBöÐ…{òÕ{6äÝŠ*ZÃü¾—y&žp©µÐ¯‰´Õ'hYgã ʧÂ[õ†þF)æN逃“[_¤\nó¦?”t“ ~ÄdÖeãæ.á”wAÑ„ˆÒ)ŠÂ÷üo)ó±©XFö T¬Fä¼Í_Üú £ ÐÎ1øñÄý »K öd’€€» ]œ1ç¶–DgÝ@Þý9)k0³BêÓÇ#u£"ÑuFK¶w¿Dr’ˆ‹é¼]x¢•‘ðZƒêñ™ºXˆdÌËvF†oâ”Ýß;ì\h— Äi.\[ﺕC44/´I(œ´G#LŸ#à ׸įB}5ý, VÀ—_ãù¬;!És*{ +“þKZw !ó4Ï×jŽÂ€@‚‡Í}v<¢pÐÎqèÄÄV=ŒDˆc¿[ö]kJ»×ì#ˆ7¡‹7GÖº¨ X¶Ô¦C'Æ8ÿ0:ÏeX!lm/ªv–•u£èÉ”,Q HYSE~·¨¾ÇÌÀ’¡Bó&à”W¥æB¯—‹Uå‰yT®7Šs"¿Ù•;o‚¹@)~ôµ#<캧ÌdTà¨'ŠÅ[×B>ïŽ Ç²,K¿jšþ—Üç¯=Tp,¨äæåg¼N*‹ä‚d”wÓa/ÚÆkÝÖõX“º)/ÝgåÍG÷‰t%ŽNÆšŠÏt¾ óÕÜ Nñ¿©4þ.$Wu[i̶z‘ßÀmµÅÜ0þ^Cªgìú€Ø{`ŒœŒ8»·ý-ýí‡ù%B¶Z5¢Ð‡v=#¡¤w›˜ !œu‰Àyí3>Vèü­Rì6Í£¾X”’83–õŽ\º T ×I”E1–öÜ úï¹ÙÅ(ÂCîÕHàC¡âG™+jéÖº_ˆù´‘8õ{¸¦ìiNÛÈ6[´8ùÑ(g†ø(‚bòÍ,Æuìö[܉cšõ >¾ø 5šM®µsü@˜0l=ú½Ø…šgÀͱðÞn|Ú"ÀŽ€û #¢«ê’/DØ5ºŠ 8R…ROk›ð FÙ¬ˆBŽ=ËÝSM…)ž ‰ÔFéù§À‹&Éb~Ïœ ?½ý4=pˆÐž¹âY^?ÂM>¥cê¡pßi‘Æ5nAÎê™EcJ¢W¤u;!÷Au{ž‘PÓÆ~‚øÅ ùÉ©¤® Œ–Ü€‰Q<ƒºŽ 0hE&²ÿ#_’ÂDµa…jÿ)›iþDEøáOÃ>’€€¡Ù>ïà÷6= Ú×!ÚÇöp=ß5»‚1íNšmMóYí¬Á¶ô&NÚ£n0Þé0f5šaìöÛ]_ò˜‚ל“Ø 5[²!Šá*Xë¥EYjç³È%<‡töyrÇLî*ªqù·Í0¡þëÓbuT†„v ÌdÎe$ç¾¼„)¿×]PT űõ ' xØÉ¨U»b÷6iY1I²l‹ê„ѰbgªÔs%Ù2ª5IHkûu­ç$AÉÜÈ—¦ÓÆöBÄ2Cï9ü¡±ÑŒ,‘|pÿUê›´áfC€]·-;òœÊ?ì*݇I‘ØíXî)vaX&5‘lÛΙœò€©J¾ÔZEµf‡ýÛ'uÓsÔ²O(ü©QW`s:'.ýr 72S›j}¨2ì“`dëJÜÊ´æ‹ûd‰î.‹2!þ[x8ÑäÿÑQpd*0iб5‚XÖ¨Ù3~ rÇ{°h¢eÏDxÏ5Æ.oí¦Øâ…(M%Õ-õjyŸAב>{ŒpJ¥EŸÿ@Ú±/¬WþÔÅׂ)Ú–Ì|)M:Ý|éÖoòÚz‚jök63¥ì§|e³ÿfö°oÃÒ :*Ç5n,Ù òôÙBóMíµýá¿C¼•¯:×9S¹[y¹Ì\r£‡ð¶\(©Mk·[º·À¤„í®Tð¯>ØÝ¨Ho*›Õ9ü^+°(.–Æüs}:¿[SùÂ|l…LVOvÕ¬ÑJU»D^ß©„ u.[* ý?˜ke´º|(ëæÏ!†&—Ÿâã9*Êã»8F¼ÌsÕ8h4ýº~ùzù[Õ”0À‰®å2a/ÿžbK‚YÒ5Òº¦t²&žÙ³HèK T¹û™u“ûÙ]êzƒ sp­r•#Á°¸Z6m² ®Ð<õ6J"X–¸AmAž$6_‡y”‰˜×6Õ 0m³¨Ñœ%¬ofKG6ÐE–NŽ®n ºñ‘|n·k¸5ZôY†~CùßO/n;’€€Ã2ó¸mÔÊÞ™‘âp6)m7óúGÛœe-Œ}mFù5#7¦¥ìm¨\x.tõh¹/Ê%]œnaHq=J‰Ó°G)G ÃÀ2[Þ{ëÐöÂ_ALt¶¶_Û¨›äEgø58Ãé9Rö8KàŽk@ÅÁ?6jI'ùôO„¢^…û³ZíÑUJ;láú²êÜÅ ¸ŠÅͤ&¶ó`íœh«:›°ešªF·Ij¼°,79Øï¾Pv’ 6ešÈ[±€J\¿Û¶ ”€j¬N¥¶­ZéÏ£ÕõB—Ó»ʼn®zEǯDab¿m®ÿ$«@Ge£’玂ŒÏ©Ì°œ‰^òoèθժH¾íJ$ñÉ'›ªÌ/(ðˆ÷2Úg òÀJÕ­kÃ%­9 ¢×Õõþ¡é75c`ŒÌyë¥|Ñȶ‘ùòwd)yz=:dµâÄj›00^·ðvšmV]íE£_·t —EöÒh=b <움;ÆòÞf©ïîG²Èx k2À!^´„ûÄÙZåÕFì*®S@ ùkI­d‘LØ´(¬§’òi¸ãHÁ¶f¾Çã‰*úYö¨¡©¿t¢ ´³ÉÂ^aI¹jàR+GšBÈCR£º—aG e_éÎúÃÁCJ´¢|h%½u÷Oœ-ürA‡Ì¢IJ[^ÄÁÐφ@}ÌlŽS{ÿ-tâ»#%í.)7çЧmÀEýgKcõêž7vËÞr»ä´ /5LË#b5Î:?7S’:-óÍ~A•Ÿe”Èc>æoxìØÂŸ+[n¼|5¨—gï²S*³ïþEÅòd®g;`Em‹=ûÂ>ë¸ä.6ákÒàÏ¡mÞJó«-í›Ñൡ˜WqŽôøaÆUA6ž-v–– ‚îóëhϾË:³6ìpdy¾‚ϯÁÔºb,rŒáå»ü'fë‚øà}eoe‰Ž‚S–[ÞÑÌÒ`Y»I¤ù’ë è™Âu>$ª£"©é5Õœ„CȉýÿaaŒÕ=I>3Õð®QiÕÛmIVD“ÃüŽ6êÝ,ïY[¼´z™÷¤lx=ÙÐ+ïp›ÜêKi½d[jûËÎiMú‹)†q7š¥M‡@WÇ^(†xºe½B¬²m4to“qÆöY~jHÇØ’€€×˜»:ÉôIÞ¾gfß)µš,¨ì—ÁN Ðq pA6’EAà‹/~„ëy¥Z­¯œòÀ¦xÿrtkŠSLSù%þK<ÊÎ"Ê1Ãn—æÌ+’ê…Ùašñ/:¡I§2ä3`øÈY÷Zí?úüd¶×Tâèî10…9œˆ‚ E:û|N‘{àÇlø6«â¡ð2ô?¨¬fÒ"¼ .‘üïˆò¦rh³Ôlþ×Så^pEŠŒ<-;U,ÓûHÂÙLEÜ»Ë8j¸½»ú‡_*g×ãÑ…Q§Ýž¾XX _2-”X‚¢(×^cíÙOyà 2¡ë¤Èfkâ+_ÁŸø5búÜÛ‘åÄá s2Cð*ÍÞù!ÔÃò™-š-[HÛ4éø>x•Ïi¹¤\žkXÜëéxÀ:‰]Ý=;•ÿYn‹sõêÈîÄô»¾µ¼x§çÂMÞ<æz®.Š¥èOVÏŽ×4ª­YÔ‡*PÚ•D*ßÀDV¸iZ¯Äo‚10ºþ¨9þ¤-•¾ñ£WcCêM­º–] ÈU±âK¯1]þ4{h+Ëæý Kj…4áý=á ¨Q´ãF]n¯·Ê‘í¥±_„.òW I=ŠÄìÛêl¿6"‘KçWº£‚C`Û^•£èËÖ°ÚÈøšW \Óhãôv.ÜnUØÛT˜ÉºOk9ÿÄ-؉¤›Û–{—åmè0d“æûï&ú™.<0ˆV‘y‡ÜúòÔÅz§Ò "À2ê²›ø-›WZG?é‘0€($ E©U[%¶®û8d™Ä“*ÈvXÞ›Âá$· ®äEÐu~Ÿ @+À+áÅÆѵ‘"êœÝi_g’ÙÑŠ,‡ò F½ÁøÆË©ÌE·^3S!,€žâpm ½>UÃ_AýY…ŒéÙEa–³0uWBµÝù~‹–˜“›îΆwb:®-pDU%ŽõÐDÿ:¾%äeÁ-/¹ÃÛzчaIø±en1»Û9=0ƒÆsÌn™ÕÈõŽs„¹@<™©¹»fȳ³ªË´K $€­÷[ì^}Q®«â¨PµK3¯å¬»µžÆ™ˆù8Ä3Ÿ2J¡F¾œã—‡X9ÞC« MÐ-%…ž Eå1u÷Y12Sþ s™û÷Dd^&†<Ú¯ý©·æk³A— ’€€Î°£3ãñvªeæŒVOBm;tÁ¢ZPK3_œÈ­ñïóy½SV;Ì’’œ·yuÕ|¦ä GS ‚p¥)åá^F’ Ñ¥LàW(ä[væApgBfÇrwŠ)ç‹]ƶSŽˆ[n“šæ ÐŽð:9†öGò32éÚë%Ìo1f'Ì¿Çò÷hÍêg`Xáð”„ÙqøÐáø›ÿ qíý\º‹˵[Û,ÜÝ'U{w¯ )z8knÀf¸xõE•DAhŠzS[}€I°xv׺…únàÒ†ìAð—EVZsô´ ;šfžzu“$jEÀ3'â ¶@øViIÑ~BBw„õ¦t BŒèB§è+´ÉÜ0¹ù²{[‘(-Ê^›ù2 ƒ£ÃÉ! DõÝ߉¿îÑŒWUÑGÿñ¯‘„áÌä©ù_²TbY%T1`i*41´ u©²t_:žâpc{݉‡†®û]IɃâó5Êg‹x/üëôõìêYtx«ä{e¿Í 4ã5ÕÈÔeí–*?3…b?p³|¡ JºhQ´œÁÁ›~iM“u£ë`Þµ8›-í¥ê–~GÀ@·Alõ1 —}lÆ©´çêþäD_+Ú ‚I‚I8ïØ˜"¡° 5`ž‹e'aìmÒøp ›<ªš×ŽÜ»¡×kGŸµÑà¼h!wاYØ:áÖ8üñ­þ6¢möéÕêíÊfÃ7¨’€€ÕIôÏ+œQ«KÚgY- )ù±÷ÒF0,¼y× ÀÉ«%÷°ÊJ—w‚:èDœ¡;UƒO‹5bN_\ÅRîO‰Å?0åв>™¥t§þç>W n>笜 |œÓÓûg[pÕ„¾Ùå¢e(/íQµNį"¢`/è!´w(ë´dÌ5Îã‡gÆ/ιcS}IÂÔQ‘g!‰•õˆSbQŸƒé‘ T‚1ÉÍG®ý¥Ï(Eþ‰{MÒÆ×„fh0ÞÄðb87ÈßòT³7{~`Ÿdq]lÿ‚ ‚îÃïìläfµéïë8V¨ñÞ¬M¦NäÂójÙ »Mçj¯Ê‰p£¸£ %Ââ ­ÂýK8¹BO z¼¹'ù’M,cï¸ÚBÖ*@¢É+Ôè¼»Œ¥1v• HŽ(Ô$¸Xš@Žþ“©±qŠùuEêíªGjÚaQŸ®k)f†\»rŸºsHÁãûª‚¬2ÿó$Æó\ÿú¦\(…€9F¦f:mn©Ùè}°{Äìøãœ.©,P Øµ T–²jYâœÝ/p—>g^}m)á Ñ„ NÓ9ï°©YG'Ûl@ðíÔÊ’È&`+ ¤Q–ð%›ÓOöê‡ïWëBÙãžÖ`±g~îDý ì€g%O¿Ghi O´ÂÖŒBSBÄlKdiFƒ«BAúrVJ üÔ¶‰s”ž¶ˆ(å¼·âÇpF*-!Ó䂳YʃeYãbðwW6É|AjÇôäó@uðôh¤udxÆÓÄ7ƽ®å•v|»Ü¿–œ…ùNICþ ÓÌâmj¬¤+.z“ уS®R¯¡¥ŽBYXIaˆe/E e€8̧£¢mÚ±cÍðÑÉr1>FªýŠ|eèbÂNDeq]Õ›ãz»€'m8õj4nöÊ“XXÑ2îð@"ÍÉÞ¹—)ba/ÆN3ÿ-[ ÁQ‚¢:Ýå+Ãq&\Bæÿ“R¯øÅ Â’+y2…Nü¨ñNwè³k/ë2è …ŽFÈ"¡76‰1I1:X­¢@©®ŠûÎñÜ›âlÆW1Y`ùK>`µb©úù.©ã€‹è~œ°ù3{kãZØ»ŸÏ2Ò\#ÙÃÂô0Œ9ð×Ôtó¹Þ/TeÉQr6eGTå^¦€qRb%ÁÚ`ÌAoéM…v¢˜àŠÈ0¼;}xÒ:ž6x’€€é&v¦¸á´<~ŸÜ8ëíÀÐ`à6üõ¬_«vR]Ùñšüqá·ãìªV²ÝéÛ€ŠÜÌMOt³lL•@&’ÜAŠNf—øþ¡`µ‚aüZm³ƒÊ¥9ö,›žÕ1sÿúo—–k/c);—•ÁSŒ§U§'”ëñj ®"áÍ%G¬¿Í áÛ*å¾²§ÇZœÏý¢ÄŸæx lÚoQm8ÇŒzµÐhK$(.($µD¨ý ›øõî<-óŒj÷Ùðˆ@H¯ÿŸ·_uÈOPt (¿E^ô¼ò5éñæ\Ÿ‹óDnª½ð|3Ë‹jbr­@1]?†[¢^Í×Û©!Þh:À*Kóª}OVÚâtT¹gKd*T$a2yrt©=\É'Ã.ÿ-wI±˜ ´6§$"åï1OºË`çBb¿sä+¢ ueDèùèÚDLß'æc^‚hA™Wn sXž Á¢ÚÚìþ¬×8j 7 l,Vm'‚ʉyÂ8bdåª9~pü‰½!ÉcFŒbß4ߘŒ \C±Ï×Ú¤ûˆGé$+êâøDmÏ%!3-ï+2õv’ ZºalÙ•€X»k>5±—É–ñ—à ÈfvBq^ñ‹óÛ ó‡ìt»!<ªˆ &™2®?›æ@½Û´ýŽŠqBíïŽÑG‚Ø’ßÊ5×ÁSgüo ,Ÿlý–EÔßÛ®¶x]R¡Ÿ#Ö %Þè{'ÛCRîåÆ]Ù^‡ü¨xÑš«µ–Ç4sÕðº¬Oñ5\oÑ™,_Ñ© ÅýëÕsôtQù\mÙ]¸2^±“%(Zb)"-˜gA??Õj¢JÄoñjÓA& z¹ÀԔݧn¯²X©âòÆí‚2–E)دtfï%1(Ö^Ûv³J#Á¸]¥Vã3˜ !öåAþG–.®à½qשמJŠ]ÙF Øâ9üÞOÔ;¯¶\Úæž-ú‡µ±€,°c˜ëòƉUwZ]³æ~¥ 9W™òJ0⨠Wò»‘ÄO[¬‚ ÅäPI¸lkðÈ2¶§µ×é_€êM†a‚á…2¤†¾Øiý{RŸ ú²Ç‘Óï8žéM‡]¾N<ó÷K4+Ú5]š"àaþ«W“ ½·Z²I‘Yz_ «)ê:d3‘Š>ÙNÔátª‰²´ ˜¶§hDšÉø‡WaïIA!òÄÒªuÓh}Ï彊>qð,ß~Ôò{° Fñ'{ ½Y|üsûRæû [„ȅߪ8k “ÞÇf €øÜbÇ/•q§VˆÙ  yô0ÏóoÅÃrÍîeQáI˜tî²_µ/ÄÖ¤½Þ|Z‹8çNR 'F2®é¾Zz¥ëqÃcïB L€¤iŸ(9p¡A79Úñ\8º‹[ƒ°õÀN5ßrcCtN;;Î¥ $HÜ'Ñ¡R˜#¿„]¢ê-ÙGÇš¥}kU!º˜Ñ-Ýæ´âxv%¢ÔjªÝÊÖ„Dnôö.ZOä?ø’M®CD¬å,ÿ¼m¥ÊÍ€¤æÍõãô§3hÃ2™!YïsÙ‚¥`)ÀÀ—hÓ³¾u‹îqXÐÎà Q#G–AÝž|ƒP­U@‰ñEÿs¯%‘¿Ñuòâ·ýÃPnÉþøÂ7r>˱sßœ3#xÂaÏdD$É7$Nàm¬ËñãÀ—ä§/¹z+Lƒ«Ü‡ï\ß³ÄÏ•"óñëÕ¤I}5kÃ{¡T’ã㈋úŒÙ†1ha±F²Ëätè¬Wõ©oôkÚWÒ B‰ò¿ŒŠèÂ!Û^aYŒ!Ô¼ì¾1{G‰!t¢Ò­>YO-÷¼Äñ_º4ÇìZøÂ¿ÛÁÚÐ'™Ï~Ž'ø,ªõÁäh€ „RV`g‚tR6zds_Ì’<ÛÊ¿êd×GNüó3®[b«§ Sg¼VYÍÇÇæ r³Á‰ðhÙõš[äÖFÙj •ôbæÛ´"}D<»X.«" °œ#WmTƒgT’ ÉG!„œDBóOaL™œ`„Ú;H\øUÍùø¤ôIÍê±î‘ZšÊqQ”rè[T©íMclØ`’qÎLáù†ð¿äCÝ}>ÕUîÅcŒ½mܲô4UÙ;ô­!î¥;Ï9©¸ á Ù‹“mÚ5bçžò¨¸NõíÏ[²¥ŠhWMÊëNîž u„ÌqG)\ÖÊ-ÏT2ø´‡ y²Ç_å³®½çÇ‹¾ý°Z"É„K8“_C£xÁã¼rŸrb¥»7Øs… p{çhÍômC<¤BcÛuõÜýÒÛŸiÏ€gD ïGð!hÊ’€€¬µÐ *Yô'H1;z1½ƒñ:‹…_­tqàV9¥t6Hj³am+Š„î¡†Þ¨ö‰M}öEƒýZ/~.·Ý¼e-™Å8§ÿC”äxjÇ2³[Ú}z’¬ §tÛK1˜¨ªNaÙ·ïÿ$Ñž÷ur¨“®þ?ñp¬8`® àH “”“Ȭ¥hÇc~µÕ)D‚¥Ÿ:ÿu&b›°§´Yx`Nyª¯ªjѳ¿«?ó¿ÖSžc­È˜´i®&“ßÿ‹ýAßÐéýáî],—¥´ÀWyHå¹A ㎲*pÌGµ';žˆõ[l†qJeÑäµ³Õ•*‘š,BmYu#SÏtØ4n]ŸµDÕ²XëåZ s~¬Ø=z#¯àçÚÍ‚ÏÆqs¢ÉH8cOMÛ.ïS»¬¹"ÓêÁÃ^ç¹ä#rzb¼l;þÙaÄráOn÷¡DD ë sjÓµíd¼f‰“"=¬8ì5·í#S¬¸Å¿±ËíãÉŸ"Z&7WäãÁøAˆÍþ-˜‹™E„ V6æ7ãÑIçZ–ÄPÚ3´Èú¶*zvÈÃ<‘Œòšû¯Í¼P!øü UŸÚ!ªÐ6©ï#ÅïØøÔŸ ÂRú9®ýKøÅQLrPë%åèœeŸxFå"ušnQ÷­7<8Г®ÅIãPºMÝÌgÞ†ßí^¾ s´ŽJdvVrU²ÌíàÎPu òj~y; U’Æîß$Efq›Ærwo¹šX–L)u¸Ñ…»R3zxZŒZ oâû²Ͷ[€T.O? Ä8ÉŒ‘¬· }{3JC©²õ¥ÒtÓÖñ4'ÂVÀD>:“¬ˆ€LÆlœiŒÉ g4@8í—m#¡=F§C®ívžVqK‡˜aèºkI»Ö{ÃÝÆ¨Ú &G¸õ‰¬ce݈Ù]˜&`ú4ùŒ¿û0¡ Ò&j´ÞSä5 ¼ž·”ÈB·Áñþ&*0¢Œ0æ‰^ºzR´\Ä~ÌÂH½¶Þ2~*“ßɘyÞªAÞ/1Ü" Oê·ø)ÒÞrc» ¼xéRé)Èi7ýŸ€¥@ñXÌ?V®u 1˜ÜÌ3qvóòê'É@ø‡ bóÉÏ×S8=åéû‚lL/[Ù›óåqK¦ÙÐ0>¾%dšÆjäÔÑZôx=7’€€“n8J1¥çI3XžjBõ5œ·^û¡=þE“„&ᯯý°¡F½»¤?‚ÍDµB¢<5õ»å¸«Ú˜[-M‘³³\àn/iY?ìÌ@ü*ѯ· “” >`¬²)XcHžÚÇâdpô·¼éÈ›䥼øNUftL‘“T+²ldñíùáxÓõû¹½µµ¡tMëßI‹îZœg§Ô`´Ù. ]#˜c[,)Û}W Kñk)RÃÒ6ZW5get{XåOdéG?»Ù¹hÑ>ßÞ'&8‚6Ï%tå{\×£¢5¼‡(©}rP tNiz¿¯ qáƒÏÉÁ¿Ì–¡j©¦…³±m÷.>Ð$ å­5heu?ÓðÆLÝ*üe‡f‚ ñ øˆ •Ô¶EË Wè¥ì•ùŒK'oËŠS:bÿVßuÖ˜¸¸zÎeÀÀ“/¥,Wô³n»e.E¯¯¯X¸).owWXµ°Ë!t%.kðÁÊ,¥Ë±º¦ÉmR2Q"‹¦« \ô£æÇ >‡¬Š‘W ŬïÛ¥2,q#öï\~] ¼å¸I®Ë´¬‰áŠ ôÒŸ2Ö’lbÿ°ÛFRfc}6/(ÁKÌ.Gv’¤`…! Q'¿^…ÂCÁÑ{Õ÷]]`ŠêŸ=?KÃÉ2—?6×Q»csqľRYb¥a4[½?æßµlzƒ8¿3 D»€®VúŦœØNmöl½œ‡©K“5û6ÚYå©›13$¤XûùˆÝ2«%–;ç°VÂ$âÜ·ro®û£¨á·‘ºLí`“¹'aJ€¹ùh½wÙ-=ªjœ;Bîa±Àuk6r¦ŒzÅgl“¦ÔGƒ81­ u¸k÷.¿®ÔµñX…„nˆL®¼óÒ̃+Ž“|à÷˜ }æÑ„J¹­ë®]ödÞIeСssZ²ýÕŠ¬x´DQºÖ5D“P;Ä#«8/K裻)1›Û^¡¤U‹]bujµQm0 ò.Ç Ó*¼‡™Yä/is,Õ&Í´Ö+Œu›=ðZňp•½C bÊw"M=‡Øj_?{y@/×õ ÜÑ BP=º‘¥_Zô'^Sß·%ìa(Þ~• ¢fÝ’`ßsV°S”+¡xÙ²ËÄ8ëYÏú®Ü‡­TªÝa†z’€€ÇÂLk™Ô­LF[±zèHýâYËï.yLµ­Ù|ÊË-ú k¡²‘óøöŒ1lÅ¡"‡v>ý6ò´˜ˆ;MªÖ]xÉÐ…$†fØ@O[s… ÃõSrÍ/Θ23ÍR’T¹Ixuw¥ïrÀæ?<1w3g3 ‚‚£Ö©®æÕsû„LV^Á´„9?5ß·m¯:‚ÚN|AŽ.¨gƒŠ NB¬¸™mQ†ÿ©UØV*ã«Á[¡gÒjìuYU½xiæCWLqš ŽÙ\Mg+JVf+£o,gû”*v>ô=™Ee±8+œªßý0‹ó:nDÄ»9 æÏ‘ÿ`a»HÕ­HO¡PæQ7(ú`™ tS†ûÅb—À±ˆàóEا-!1MdQwóóü³³¼˜­f8m½Ÿï†ƒ^ž‚ä‡Mø‰7È´ü³ Uõþt6´ KPü»À¤sýã&˜ý)×îq‰¶g~ ë¹ÓéÒp+0Éfäuo7uœÓv˯`u¨Y–Ö=Dj <6¢9¼h Å™æLxNX¨ËXç$ñ<- ¡ÞJKŠùí°/pÁ{€dÐôLL.¬to1Õ`ݰ^{ ò¯ci1â`æ™Cû¶Âëœæ¤lU3Op${–ÔrAè§/Í?æv¼aC:aóU~¡¿fá'q;Ä8 ¯noïé¼™¥_=l®;öɘ%ºø±bQó°.r›ïZy†íBtw¡EsUt;PòDAÙRZqM„Ì7-þŽ „0–vRø•ãC1_ÉÚN†hŠ©i™lMjzÉỆð0þèöE¤í¿taCÒ('Ÿª6óo'ƒ7û½`u597oúhoÿ–À»Ë3I\Ì¥£mÇ«€gZŒ‘žŒº°§üBÕkâÈQ²ªá°1[þÇPB)¢>ÀLU¡†²µ‚U}'íyâßvVu™«&j"õõÑW8í©îÒ••â¡Íe¡YðVÀPÿMèìûœý”d‰äZ£ù]½nù›ï6ÞþÌŽIýöWHø23/ël@êèòAk7ÓÏz&¡VÒ œ†ÒsÉãxq2 RVãã‘\|„]Ærª‡¨9§ÓZÎpSà𬭲0J‰WTFcj#žñ’€€ÞˆèNa+ÐÍÐ0ÅÁ˜5ÑC–“'œCo¹Ý5—E›Ä\ŸÁñ'.@‡õœ¹ý€’:êÖ”#»D¦Âä3G親2‘x¼„éFšÛ1ƒÞüÜÅ¿5‡èç¹Ì+é ˆæ«£Ý¦­ê-•=›Pÿ‡•£Êm{U<º<ŸYã½}©Ëª¶(mÃ6D1]o*¨4ºý,/÷jM„míãM‹Ë²ð4=uR¯v¿±Ö…F‚rY*)ªÕ€2&À¶XNcrá'i¿X#R9`æIX¾o ÆSbûYÊ?ýí¬Àé® £ï¥Å•]Z H2w7‹Ð¤â8L]îoqùŽÜ‚×µ‰¿¡×B›õEžÑÝrûÿ<°¡4¼yRKäÝF³d§ æªñ%!#©#¶w,£þØ¡ƒ¤|jg‹ÚŒœ,ï¢ t@[çò$ôE"?ÕÛ‚R¼?9£äa´2È]ë)ÌÅØ0ncC¡¨ö`9%.Ò“áD/¼û±²]“nÝíê ì§¶˜ZÈœ®ùŸÚ¸{€ï]}·Ktí'õ3”AM­«ø‘µ‡\b*C ¥!åÅqU ~ÊùÁÔú °g§û\¿à†¶tˆÍÒZã(þ­¾Óõ £µ0! ëm-ô¾ @“OÉ~F¹ÌD<úÑKö&E«^ÌFøU|ÜOrT\¶!zq[ø©US3ÝäÝÙrd9…Ö5"`ñYy æF¯Ž2ýÆK#:sKf‚…:HÌ1|@±>GÇU3æžBðaöXZ ç¯ÍgîE†"Q|¬&—¸=zaþËT²R¥2Ú㣚ï±9 .ѺX"8Ðß3ÜŸ/ظʥ„¿j‘Q;7ôˆ‘u·…ÀŠÓà¯MAôxn:ÃõÕy=Í•/t-ÂméMáXP{èCƒiÂo¢)9q¢ëÃðI½W`=y8-@ÜÆMáaìH±w‹@‰é'ÒpÞÜp œ7´Nh¨ç?ªæãÓ¯º»´¬üÛ Wº!Ë^ÔlGž,/‘Vq¤M¢C¶¥Ö¿ÝiX'êæ\ò)½'›šò•qw‚n7{¹¦;4Á;c~Çœ\² ðõðý„¿] @‹šÌË4 ©75J®V®à´Ðô›¦&¿ªëVÓ%6&N%ÖPÏs.7¢”¶Yʇâ÷ ¯7DO–dŸS]:²ŸŠœÊ4\µy=³ý4&UÀ)~¿Ãk¢%3Ko4º4G–'Ú–›•Ü'"íjˆ¦BÍ! â;­IÚ.–XzQåé¾…)DŒ2I®Š‚„WbÁíÌ||[y®Þµ³Ç]Oyi/ÂCqGüR ¥½³¡ J” C™=i´pôn’ûõ½¢aA•Ãã#cÓÆ÷-]—C€Mž=G­íI¡—ìË[…4µlâñnjá²/ ¼ŠÆÍY1Žáüä9ì·Ë\V’™öòÛ¡‡®¢µVÄ% J©ð*ÅSxÉö˜:Šï ÷rLJ˜IN#ÝÿôŸ}PŒÁùK¨7ÙQÙG¼Üh°÷âøΨÔÑÞ–ü*ÓÖJ矲ï[7 ¿5Ü¥®VÝ[/<„ä_Qmø;žÊ9l˜‡qº|Ï(Qh“é½Eœ³NwM~`‘œÜª3nƒ3—V·#œÛ™‚²Ù£z|dÔ_Ÿ<µ,"©-âV»FXgò'€0s¼C©c‰Â© 4üdK‹¼AG Æž$Yó •̇.V<àÞÍÍ@†x¤²Å¾–AւƯLJ<0Í,’ßËxÄ-€"¸‚Zj­ä@ã“øhڥʈÏ=×BÃz­P,½9kgì¢5„d²ÄqˆºOl'‰‘××á2­pys$º)ë’ÞÍ|úut¼{Søí£G_PBäK…ÔK“–v#à`’€€ÅŠšv:yWZ*”kº‡‚~öFèå»-‚nÜÈqÔç6¶½ ®ý#‡êíÐ1ˆ }ZÕE é!O*ô‡|ƺóZÁN³Í7ôþÄ?Ý <Ïï ¿ûeGœ= ‡1¡^¸Á;˜ ÀKÛÞ ËpmW…ˆPab#ÀÐó·mäϘAÃ(Џ@¦t—5JôÁÌ#ïî#qWk Z#¯, ÏI쌺À‹7T$<o„Û@Õìù?ñˆ uÌðÔ í0k×)*kv›® d³£óB¥N…˜6E=þ,1:èEhÞYö­5©=eÎVD,á[ë¦ïû­^üUäâS‹k“©5Íô:QŒ8ôí¹êªÊ6Ö×ßwëà QX÷gg…DòF¯HnWßÝ…¤˜n ,µ}A”¼*R©›ÑìðTÉÁ˹p¬ ]=†#S:ftèvGj*ŽK™^3ëúŠKÿ™[)Kr¬ ¢ýÀ%Ⱥ‹o1¤"–‹ìÊ•âEÆÉù¨S sÙ·®‡8‰…°Gí˜ãGrƒ$Œ~¬Æýò,ØŽ5VdƒèJø[¿^%9÷ ÉBôž) 7Ö[3¯ÚÑyC¶íÌ a¥)3õÆ]¿sе6ú;@y°QÉTQoë.·¹˜•ÞF»†«B0]±îtJô¢þÞŒGí¦-)cùè}½»06¤8ŸÌè(Ñ/¡b1üPŠôË/4éÓò’‡9hð #¤Cp;?à%~Õ?dP‘ Œ•u†GzJŒÇIÙc[—@ÖäOb5OTÓŸpo¹«µ‡{®ÞoC01©Àõ°âkg–+x¶ã=v³ÏÌ) P»%*†Ø‘Áßì?Ùƒ–ÒÀÜl'¡¸x¿C˶>¯‘» |§Î+:Bkp’m*q =oV­=¶b“X¡èÎ+1Qé !ptAæ©ú0„ÜÅgåþ¡\Åóò±ц؈ŽvšsÇ»µƒú‹îM÷z;2$°»Þ¨…¨=¿ûkTH=Ä&c3Oãºé¨[B#ëE¯¥äÆ+QpüÄ1.ägnaŒKF˜ôþ¿=®¨M+od«ãV¹ô“Rô‰÷lNíö6ÝJ´4B-ÞG .îÉÖ‡YÜZš3KÇU*ÃUJÚÑqjl„%\¼¡ïZY ^}Šo9lS”Çã’€€Ö.g¬[0C{¡ReÉ|ú5–—F†ÿNFÖröüäC7ÑVÖÉ¿¬C½‘æF0æõAÓ%²²»=Ô©‚>Ç16~-2DxdÍHÖ³"kÝñÐK€c~ÉÔiçc|ÛÃWAø & üí-^qº,Y³EÚ] ;Æ·ñ Id+ ,1¿ƒ¡pñ­Ðá–ï8¢©V£&WýX«Àr½Î\¹jË7jÆCMê\ÂP-gš€–ÚÖüŸ$Co‘§ ÿ¿÷Úó—¬bsUe„F>™À/$óí.ªX;Ð@£ùuŒ“¼Šôé\Òc^LxW5RçAáÂáv8¸·Í{Ôg®vo@ •RÞ-}Þ~¹0‚m^@Þ?¨À¿XÚ<ä¿óÂÖ–ÞS\¥Okô™·÷8qŒjÍúå„Ut£ M¸‹H2 ä\¥qýé²y`[1¡¶N“@’…ÎW‰µË.b†3 ÓYO¾„3\¿Aäÿ¶o:;­áDmû¤Ñ竈fð±1™=•geÓWb×ä“F6¡‰‚[”»l½ÞÉ ‚Ì¡Œê’qþ„Ô¿²†E&Fø\Y%²;[N.¾¥\Q‘oHÀØÐÞm‡^ú}KTªËt–â0Uþo=¼:fÒñS0’aù²W˜åAù3TF'*cQ£®Ï°!Ýëªs¬£¶£“ÑU!8¯]†«åðÿ÷U è98l`tTí+ßê¯N´lœRijÉwÒ¹1N[^‹j¿!ù´YfùšÆa п $.F˜ÖÌ’%õ§þ‚t(ž_Æqg†»ÂmÒ8{õè€)¦ŽœŸœ¨¤‡i,H4uE šó²‰È LØ:SèŒæ®±îI¢ôù–±!Âôˆo8ø…F’´‹†ï›tâ)¶)”FîŒâ#a9­„ÿ„ôt‹£#b ÎÙ!¯~~ú²¼@zMÛ€¦mSŒßŒÕu?Ãз hhõ‘zNsÚ‰ú4ÄEÒÌuØÈº‹o/9c ÅN¾Buˆ Ðpøs£u†LƮƚĜ£šån^‚¥¬¹±ß§ôŸt]ZË2—ÿÀÖf|‰€qÿ±2h«QS•™Ö¢¤Ÿ£ô$„(‘>äâ*’žBøl¤‚pïRíëv-2`Y¸@R6¯¡Ò¾užêÆ|ïØ9~ Oº.Â? ŒS’€€ÛvûÂÏmäÁ3€îD¬Ÿ9ŠnPV300»ªô{¼ƒ¬›kV;º´D˪¨ÔgÛ+]o#=u@û[ˆYÿ§ÜÙ~¸ z©E}0ê¾ô©Ý„¶wv¢k½m(|¿áwøXK»$žœ·ëîÝVXJ!=(D‚ãðï$dhÇÈô›¢qÁ*Ážô2#ÏrÌITà-–<¸Lö ö ÆšÝÃí¸½!3³v)HÒ,0·}äƒ%ÿp0%–½×þb:²–Ð8*$íÍÀ쬶åX’AÁ' ¶C [bÆ}Üä‡*Äâ[¥¬ßÌÖú ”Ʀ×ähçjq}°‹yT¯ .ƒøí<|Ä”8‡•-¾  Æ(ÉEm¬¬B¨(é’=ŠáÊ¡tº±Ûìéïýp°·GXJ°2M¼-ØÌI«’ii>7ÚþÞûŽ Ôß1p½BAÄÅ›“Y9 q:Ô ¤]ûdì<€t,å#wLp!hЄƒV5Lè l¸ÅÕóÕPÒäÃ68¥ï%&ﶉâ&5wЙ»½¡eñø!ë¸Y±ÚÏx¥¡ùÚÄ”L`‘ö„­¥®0oêð4ÑTemx.‰¥ ¶78x›¢×MÆEˆ & § ºHÍ‹ë— ÊöÓ@ŒGˆx}ÉÍ™0xìçæªñjƒlÙ…4XÅ 'W€¼ôUÿ¹»ioéª †e)TxzKÛ†#CDxƒÝ_ÙuÍÎRò#HÌŽ wþ èÓNWp|L½xöp·Ýf)(’§¤ng±—î®<LwŸþ¸ÎN”—¯@èê·ãŸ_¿ÏÀP/©ü´Ç=õoˆzvôaå=0·ßÙ©™õâ4W¸{¿Í1Ù»¤ŸÌŸ±‡dM-==>šÛÙC¶¤ým½¯•aWþmf}Ê"‰æ^ëmÐÊÞÛ ™ÈTR­Ž äçÍ5¦‹TàJb{_®œfß’¬ŒT~¾GQ{vžlkþ*¦aºt "Ó_T­v.3ÀüoC+ªUa#“”žK”#q¾jLDŽ͙¾£¯&£ éfá Qåå®-z¨¬àÓ¥ïâeDB`1¹Û!ú©¼Ë"åá+anÅèw3”K[s¼h5,¡¤¸kxˆ+Äð7rZäÜ«,CTi+…$JÁÌ™ï!ž™R“²{†â bôVß—(¸Ðy\ïð¸r—^çw-’Ý€q{ßðÍ xg #¹dªºçq2ˆÿáï^!Ðú0 ãVàîÄBÛKtKnÿÜxAYIkÊ×®…7øí~첈'F÷žßwx%ßC#hžpd-¯Ð sn‡nŒæð$Ú '˜¡wAºù­ñÅ;Gë¢s£wÄ÷ïneI!Aõ¶Ý÷ öxBÌPûWÔÎ]"m?T¾’Éy.–5½)ÖŸŒ„œÈåþ¿ëh=­Î­éí ,·ýá:%ú&LÑÆ@»opÓõölX;Yl׌7üµ¤J´?I©è· > ›×†}D‹ó‡¹¸‚u¿pÙÙKÌú×N±MÙËÍ âcñ©f¶;"zªÓ*Ò#ŸrÐÇ™¬‘gô´£$0«ª'd’¸È~W>ÖS`]=܆;Hé™Ñ7K,ù˺F†ì‘eB-GG…S+h¢£M_³ ½´}¼£` o? æžÐ_?ÂÙ¹P€{-këòƒWQ=+}÷29?\‡NëáiN>/w·¾0tµdx¨ý·YÒi [ n5ióCÁ9mImÒu‹ö©ue¼Sµâ=%é´Öo.qO§g飌gG(A¦j…g°dO¢á*üF«ŠEè.,Áü½lÒ#;|·’!€zÄ¢5¤v‘!£5 œk9¸ÉE[è´’¡¸P0{} ¥ ŒPk•Vhè>Žø¤k\ãï[–L?L²õDën¹ÉËä`²§Ò¯†èU–8äò~:$ü¿6÷²3gPÃæLÕ¥NáÈÄbóOÚ¼­ÁAõ~||ͤÈ|Ÿ¤, ÑÖß©7òê6ÕæìNÑúiÄåžxAe 2?C>À”†#E?!°]/‡•ûò ±»áYø†òÁ3CYOºel™]ºÏ­ˆ¸VNüýnGÚþÛm¥Ù½ÇÞIg ®¬ÎEùÒ °QˆwË —li WÆ^ÿõèy7±DPf;TíRê ‡oÞº?óå¶ØsÉ+4iPáåSa¸ËÕ{?Š‚2öƒ‚q8΄¹k\ö¶êŒ†zv+jïI¦¿º=( ÎÖƒÚŒSŽü|wÆÆÜ µ*nïð©nÝSKƒ•-k[ÓOŠ— 1ñ–Ðí,.éd…K‹/ò‘}®#ÄïH 8²þ#|ý²³¬XûNEa‘ ljÝÐùŽ¡Y}q»¬ÁtÏò£;”çÂYò|Ñ©nHõÌõ•Ô¼/ül€Ó*Ø­t_pCñµè-.t=윚Ny(‰Ö]ËNz1É”¢ƠΣ2÷ŸúÛkÖ ¥·»ƒMœüþ-Ç’DàÁõ”¿ÿߪ¯²¶Î‰ŽÐ, »Ú#íhü~è¾ßQLÜ^\ªË¡ÿ¦—È…×p_Œ­èå5ÃË Ñ­’Â^ì—…´¾l 5˜ ‘~ô™-o‰„s%¶Èl²«GüëA•PäÂqyE¸$õobEÆtZ,½Ð[ýã;UW  ² šY©þuvaûžš -ø¨]„H ŽGnƒ¨r¸Ú‹?c #F/<€þ7g0<Î5ä{çÕÜ ¸ˆ +€ç“á-’½Ê3E0/!2X£[Ú J-¾Yëö¶}ÐôADcW§üŒò¯¼àoT¶&¥ç|ç7÷o#?ÿUìý¿ØÑ®Á š¢Ò B¹›7ñÚ”9”cŸÖ»ý|ä's ¹‹[òpqR¹Q×ò‰àI¡ÁÒtÆuÍ·xL6 :%ÍÕCùµ—[¨º­Õg?.øÜJõiÅçº* fSÚi½~Wä S§ƒíf¾Ëëžs¤žËcG"„QÆð6éE\éиˆ‰Ç¶’RAØ.7¸y­÷á¾!Ý$cF#‘™áth\Dx0Y°/º#>ÁËXŸcËw‡æ¶ñ~ïK”à' •ZQv‡e”BNì ”æTúù‘iÄàVNÌÙÙÙkcÎñhdY› …s“Ì?ö%¬”u\’€€¬0 ‘¾P­Ò5d¯Ïhì¶iZqª6øNº3rN@¹ùªg`v¨ÿ¿ªp7A>ë±ÕÉâ;Ö1œúSÅzÍR'ìR)ÌbòZ ±}‰ämÄÂÏbMè¶xÒ‚¶‹é£/f³2#Ë']»É.„øµ(Ë~ˆø$í¹¸óíS ×m‹PÝäçC•# ×ù;Ëàȱý9Á˜üysF/A‘)wf®i¥¯C¿8Ÿg„q_œÑs?Ç.–’È Ô,±0Ö¯&Ç1gØÂòj‡e¤¨`"‘{õ> mG.D–~Tjk…Ë»LßÁú­k;»ç< ‡kï' <Êú1»ï&0ØT êÉÞŒkmÀœ„ð3äXð–Þ•Íÿ1;.:\”p a?±úøI=Ä_9`’̆ë Òé½;š°3jànô+›é ©3=‘Î^„Ó×§øíñ){«Yû’KšhÑ¥9–5&Dgø]·—wü‚½{rçGÎÏó1ÅžfšoÅv>Åuµ:pø§ öƽÕ¶@X‹¥Ä8®_ñhùÕ}ˆà™¤ÊYëwYÄK„¸ØKÍsøØ.©\“Iâ‘y›qìï%n»­Kö”z jˆ¬¼Ç’+Þ–Â…},y¾ú1Ø–ÃëôÌ ròd¤ò*èfÀ½žÂÉáÁÚ0Tµÿu±Ÿƒ|âG$ž± žù%Àœúà ¯?àúš)rRž3A‘Ý ŸÐºõby;€v¥ÍdC_e×vÍ~¨ŽÚÊ[Âg­S¡Ô’©Ï?^†nÅbÇâƒB u ,rƒyº‰AÖ,t/‚úÛ&ìFŸ++6GÊí±p¶)j ­ùEa¿™¶¸(í™#­À>y¥õÆep›~kj5Và¡5iÅüé2_VN6óÛ¨Èü\É”î¨;T*W)4DÊŽ¼ÐÏ®Ñ2ŒÕ‘9&IÏ=c½,äR))qŸãï×ù6 Dºž&Õ‰#ý^€\Æh»ÿya¬Mš¢óhì4Ô‘(Étóš5<ÓÈÍ&¥öàÞNôûqϪ«ÿöÛóŒCÏHIÙ‚lµÿ®jAˆÌGŽìc-“"ÀâÎÛèîÑÝZÝס\Äðl«–˵£ŽZõ_Ê«ÇÙª%Jg4Z¾Æ¯ø¿ÊYm¶‡Z‘ù:Úô$ÿ’ÞÎ?UÕ«Ü–yšf|¨;}^¼‚¡€7êÕ©hÍÑd¨Yr$Û³8ܦeÉ’ÛýÅÄ5uª¾Jõ ñšÍ„“ÂНçÐŒvÏÍšæÝ?Ùù¸í,=Ú*‘FcÀ{g¢õõÂÓßS9[´2?WiÏ£Ÿñ «×ìÉ+Î0]gF!Ĥ¥'‘¼ßŒYytíÑ«q¯¨‚˜„(0UXE@R“ÇÛ£ºt?`¶Æ¨÷|rËfó•“(M«oÃþþ<­7Bç:…Ù],¥fñ¯Ÿf¶{(F4Vʘ* Ê\läoBË ŠôA? â-À‰ˆ˜Jˆòbç>„þ’Arø¤¨/ÔŠ¦Ú‹¶Il_¸é;Êþ)Zᾯ®á 1à»CMùpV×àÉpQÞ»ßñ©­K¸]0™£ÞØþŸ’€€À·Û.µ\㮎q='£`¯:œúÿ'´ã+÷°Añbü!Š L>ÛÆÕ*9VÀçÏœúÕ¡Ra#§®³Œ0¢M “‹Í_åÒXÈí¼KŠCÓ¿EX–k5$ w*xk²¸_'¦¾à'‰¡Þx´ľpß‚¸òåQ ­¿~I^"ìbeйՕxÏ<ßæXAp0,‘Ù8?I²ÿ—^ª–ÈÁð‹§Æˆ 2ìÈá6UIì [#¸½0tϦŠAYY±¶RžÕ¦¨#Ëú„\Ýiô(É)ûì¶>òYè®ß,OŽ^¼ÞW‚&6™adwí'ZˆpCSï!gÿÛŽ”OðÝç…WB½.7Õu±ý‡Öl[q+¿ òPdiy€ÈSòùñx/yƒ·ÊWÈSZ­"í©„Þ4Ÿ&? t92Š^ºKÿšË‹#üàù¬Éy—¾RK3çäfÞ–Í¹Üæöz§q£%Ò‰dZ~Çf3HñòKi C.Š¡»tÔ1vÕ<×&oµâ ™Ú ×Ó·ÃJ7[—¡Å¤ïûuf.% ÆT• £8i!11Â"ñ¤…;T9ñˆU9~._.“ 5@í¨bÏøÆS!\­{ƒënffÔyQŠŸºäS~û£zV!“>ùnk<ˆßŽ[PbÈ9Q( xžÈ1U e>¼‹¸/¦&´éí7«Ó’§ ØÜ5"B]}Ûnq¥Só§x£…?ï9&…}R,˜ö{#ÌC 1)Í‚Z §b—üïùH íê² ž Q*R›Uƒ? K@ð-š%·H®¿\ˆ–~¼ôÖãí>‘Ó„J&ƒÓo0ëlR¾Àš՘÷¨r8ŽÊUnGø|Ãi.ÎË€Í"I ¨Zïí¹¦VÛ©Þ§b$ú=ÚSþgðŸ§Ïµ®zÙt¯”V D‚ææÖÊžs(ò”}¤Ÿ<Ý{êKiFSûòšö|.,µß{¤f®,3Ñ6S ³ìÞ¶AkÑ[HÿZ~ ÀMhë:aæ_ª…Ô;aƨoÕÁͤ¿ÌX°WðáÄ„ò:è·, Û”×qXG’€€ÝFéC1ªj›Ý"9Àxsÿ.¹(J:c¹EH—ÌÈBûð¹á0¥³¢BiXݨÒ6z>~$ßÿZŽ— vr4ÏìAèø0œpHÙ‹ˆïiLð%¿?ì^ÿËo0EezÐCüÁ~ŠêP5Òrµ®²üBɳ#CwR“³§Ó ÖOiah¢Œ‚@c÷\€öçÖ»ha7Eßš¾>’n?‘ÜÆ\W-Rb§â©Ìµ¾%?Î$ Óµæ§dÉ/ÉÐW,9QÍå\’j ¾nlLÇ¢$Òšm2ò=ú¿Þ+€Ý`þúJ|C:ˆÖ¾»sÕ:…ªØù³|­B¤ Ë?é%«bû,A”m•‰÷†œb1µL|¸Ù`jÃ#‰ÏÀÅåa_c•Œnê™äE9¢¶ÇR i,C+ØÞ“§‰=²EO;}æ`Æ0ô¿Ü*ºoï)a¸/îicxS<ì-0á¡Rþ¹ø=<¼v·«üyžœ‰ä%2áåde®6"¤n¤Q“Ey[mãq·ù!ƒˆ RiݵmôˆÇ©9÷Ü4,Í ÷t½ ÌŒHV¿ ÉÊnGÆ£ôE-­ãmMk°‚Êp²#Í–3¤îª÷ ÐÄ€SbšñØÝzŒ²$Cî9!åÊ–1Ä1$FßI!h-.7ªbsE…ðð2oAåneoRU ‰©kHz¶Šz>åó~‚î÷et%ãˈr9ƒmh}}\J€N™47Ó]K¢ˆ†ü 4³à.½\9Pñç$εz«áS¶èqºš…þ!¢àùœïU‡*÷ Á†û}Àq`,K“ç9е< ZònL{sõ¼éñÌ Î›?lóæZ/ÈZ§°o“ºÕc…É÷*oª|WU«%¿h|…»ý׬Á8aŠI‹Äúëb¡^W”&§k‘…OÙ÷ôź]N!Ãʃ U#6`uäî%ZM7ÝålÃÀ+Xž}4Žhö–|X˜»Ò«vð oy"²È5èœ ¢üÔ‚S¾2.à¦O´%Ã÷/r˜+b‡øV·*-ìè»AΛðhÒ&žNÿS£iè]€ŠÓ‚¯“f`>þŽ˜„V^§fÍ‹T÷šdÙí/Cç)’°5=j¹Cí±"O{˜D¢ÿÎY"J]ǵ?Ó­ÌìñÑ\P·=á½güleÁÖë$+Äûgœ<¦~Aî–®¢Ó±ç!‡<Ö\„nšsî×i€Ä5u\À×¼l´8Òß禭ÒhPQMmØæçš)†x€ÐõHª‰ÅÕÊ0øß7ìÇ„лö üÃjXìbÙÎæöno;6% YB¯—ÿD̬Qpwiè0=Â)f³É Ñtu¬äY8Ã|u2=oùËK hì¡Y£ßºöŒClÔ­'·ï¨Ú÷“È!ibp$ر4í¤ÕíûØåH»Ìšå-:4WÄj’cìÓ…IŠ ¸ üx36UÈ ‡tMÛºR²Åšã[âÀ¢mâN¬¶ŸFøÁ03É‚Š+CÒiæ¡¡VÕ-0%Òí% õÞxùú’g?’÷… Ùh [ZÜüœ¡Í%'±½ªÌ‡46Ô‡Ükrs38}˜äÞóù#5Ó”`¢QŸKÂb4»¶—F³z1ábçáky•¶Ìñ¨8OWrßÏs;ì®P´#%ªÅB[R–MP°k#Y¡?ðf³wI'·–]B4DKŒ˜… ü› +kߤ“áÊ ý黔ݾÝÒ—>L@kZhºœ«‘~YËmB,\zRÆ7Ià‘X)i´o·åÏ5t0àò:‡¯¯ÍFAŒ ×}ÍZ9FQ¹všY-‹’/v е›â“ÿ%ùü5ª` 3 1ì “Xj|.\±Á–ž)]èWøjÝl‡0ŽÈã.œ}_ ¾yè»í]Jž"ZíÔÔÜߊ¤ÝQr/ñÞ(Z&.‚ñžœûãHíÖwŒÆ*Z€’€€Ý®¬Í…iªÍœUH=`þZx ŸS˜,é€NÅ G 1)R…'4`+LKýH˜y²Æ¥ÑhybãtlŽ;gªîkÙ9M(±‰GïÅg‘‘¥¥xÜjñú€nˆ·8®zýÐe){e1”‚ æ@–AÇ^#p·|d9vám"…÷^eâ]uæbO$>ç)h©tõ÷œæÙÜÜ4Ì­ÖŠ&ð6”Õ€$ä;%Q§;NK…ÙR¬iùâµ2Ù˜C€TÞYWÕﻸV2qÞÁ…—kSóO_ãáúM#äjQôâö”ì.c¡æË†\(ïÇæNõúÈ’?Œ.ë¡ü`߫Շ“c¹z(CÞó² Mn)- ;µÃ¸LÄïëÊpM ÉÒ‰_"^HîëFDºqwº>ˆŽÀ.¬G-ª|WOù“p”b±·ágÍt÷jatF—}ºau]“Y˜ºÏg y ôD ¬æÄü ÔÙöHúç"K³“ (Á!æUe`jHf´‡b;TëÕ0ÏÞ­Ýp¡Y2Ó?[Biþ”Ý a}ß/rwŠb}~K\£õhÔÞÙrŸXªnlËà\è6剛éò/·´. á?>¥<íš$¾ô¹d’c›.ÖÛ·ðè8ñ’°²{lÜþ€<\q1î¾}©)ÇøgLjššM¯7R„ƒQÐ@G»7Yûp‚iͲùõíöí ËAˆiôÁk½Ò÷£üSî¶›åR-Ê®ùÅø]:17Dÿ(QývŸûÅí9-é7àúEÕ„†8à¶ÛzÐ2S¬òP£'yR/TæÓ·@ÝJÈá§¥ *Ä'{ Kí©"v,ûá³ÿˆ‡aUÙÄOù¥CÉBêŽe‘×Ù…Ý+QzñGêî^*¸NR¬ÂØl¶('ÝŸ“:¿€ÃCƒp•(T^6(²Å3ЬT¹ lþ”D<ÇdÅ oªyªY=g¡é$¨CªCÆ„>ר¼þo8¯Ébç"ªü©Yo´«L®„iÚ(Ã\lÓù<æœñ?]—žvã7Â?+y0X©¾ÙÑÈáÈoU‘ßó)bC™ÖÑ=»BΠH`¨´vz:"‡¥2Ï*Òp¯È Îioî–‹ ²?á‘‹]Ûti#¡Áȵ,<] ¼BØ"õÌ3а!®ûœ~a+Åå5î’­HsQ¬ø+-[Ìt±t¥‘¼=¢B#'_ßÅ%rO@%˜«€dc˜®ß˜äÜj \˜¾åL²hÛîA¬F=BÍ›ÞUµÚ'zŠÆuÓiXú£ ¤´2_à£uÜSOÉ~‹ÓJøë‘½ÄëÚÛû=dUÓ¡‡ñ™ –åNØ4·}L>™ëw„5«ÝóÔbÞ¦>šŽÙ;b !9lÄkð ‹§ËŸHe|F×*éOð'™µœ¡Ý|-‹Û¶ kZY‰ÇG§˜anDöèGVX«^w/‚µÿigeh½zÍÅN`Smó>FYäs,o˜IšbÞó.…ƒŒŠÌ¸½U‹LÔ9ô]‚e—ÁHú6šâ5PÎv(BS#kp7ZÅ ŸŠàÖIO¥|QiWÍnpî JKβPË›Èäµ¼œÚ2g»ç˜–Bã3#>j1ÝkÆT8QЧ ÒÇ 4vø´ÈŠž hÒ ç:`-P´Ø~°Aƒ¼zޝ,W‹ØÝÀëË)Å–‡6üX–ÜªÖ ÜRÝ%œ­mÇPFzÔ>¬½[DØ™öTЦØkmâq8Úè&ÎH%öJlë9¸uŠÔ—ª|ðT£Î*JX±—†úïtß,to~Ä2ÕÆéXÃ=@rDýádÞ&dwçav%ƒú%7R'ëv÷ZV˜\‡ã?’€€­7l¶îüœ¶Wè»zúÅø?Kº™5ã%¡DÍú†‹5…ƒã¼0Ö«½oµðOìƒíäMÞc7QÇ!Þ zzU*²SÂ5ˆkYíV‚ã.ž^/gÚxÏ0#µ p'œ‹{œ w•¥ÈºðȽ·È„ÙLÞ¸ò’’ˆˆ4­ÍÐ4 õî¨904äÍíÚjT\ÔSóçâÕ°ê²i¶u°zQæœ@]ÃÑ—=v†€Å:{—>`ÍÓxÝ‚´ÚÞBŒ¨À”¦Gbs; ÌñÃ>Ë©bs¤O>{~‚<7LÐ{ʳ$ˆYªÉó9™`‰ö]yßsÿ·]Ðëâ”^îz2q0ϵPáÛä"G.JÀ´c~' Ë\O0G‰¸Àⵋl¤œz· ¼(5²Íþ^é»»"´Î6IɬÕ<ÄQÿmDØ+k×1©Þ=é/Ê6Wz_ÜIîa dëµi'•QâÙ°à€á¨7ÖOf°Œn¿Y”‘=4§a¬¬ûÜÔ£Ôí³Í¼g3a–­]ÝÚ_+?<ÉQ:ábgEö%Zøí Å$b”‚ø­K÷ùžø.ï®$±S¥— R!²Ú'¬móÎg’Eoî*¡Õ=6Ù5Üú×f­êZöìÐR@wì¹Of5†ï÷P˜‰ ´Ë48T›PïL–t8´gz#.hѺ(ž€/>û°"Ía?“Eš5¥ÛòDó˜B†-(³Ü÷Œ¦\„Í„TïãñÙÞã~ˆËoiìãm|MƒNÑ墯£ÏóÌB6ž‚ÃxºtÞå’*cØVÀså¶ÃT‚ °›Y_ù‰Ê—O¸Æ2 ïzWd8-5ü fÁïCfCGbŸK™À ä ñ¡ëz¬66  ì{ÁÌj¢Á~4@;O! l}Ïú ³ì³¨W¿ÚGÐÝ5F®Çw+8ƒLçmÇ2Ë”^êM’Åœö°ÈÛ‰Ë@œ„Û˜ q•MÐ TxGGú!ö™¿¬¥Ûÿ¥@‘1²<Å) kø xñ»w×;½OUGèú}ø%bÄrº~ûÝaú‘.ºE7<[ðgnÚõÈT-û„£Š2£Ú‚ÌôÎ{Xñ(§.DЋ³É,’€€¾™ee*{Ýà§"â×Ö*ë~²×[æ³wòßv@"Ú¸ìÐãR Ä0ªÎ ¯õ)ž‚ÎÏ ÍÑâzÕ¤&È®;£¸Çõ÷ 8“.¹õ­àY²ñ#"Ÿ÷¼ÚÒc&òe=éF™–¬Ø»oÊ[/¶üä:ršzŽG—ñ¹ÂÀý fNõÇè…e‰áý[¤$/ºuÊ„pš—~“ÝpHVO^ RäºÿÓ§uI†;‡ŠE®7‡F›Ë’éEÃ\«Ö µ¹cÊ]U*!¥¹Â·œkœ–¤ŽèÝÀÅ$<ûBã‰\¥knÀÇHåú}CÀÀÉÉb+B÷iÄ Syá+2½ÞÏ é¨Ü¿4IYw)/‘J‰Æ~BR`u0­øèE@Mºd“²Æ`Êá"Ì«éfdS¢${mnͯ”‚Ug'ßEšC=ƒ«G¸>¬3,©Pÿ¬½2Ò¢!VlrMÝ!Hª ‘#K–½p“«ngýSn •£ÉC¨sUh_’¼JØÄ?ì/o¡-p'¸\±“Þ°b8ŸëýQœ5U–DÚ¹µ!|ÿ²ÂHGš´f‡N_bâh•ëL óAºÁ“[R$?'ìOý7j÷Î(¤¡›A¸hΜ#I~à^èÍäÿܧ e2æ`±¨Ûb+Ô¼Ç3åm«TË9‚"€Ž }Ó ÀE”>ïªás‚Ô¡E½Ê¦µÇkÏÑTEÇV.½š­,*:º] íL©wõï—%åáòTUJb§)ªšÚš—;w´`qƲæÑÅ}ºç£€ã×¹µBŸr—¯SX·”Kûµ{(ê|ª¢Þ›ãEýÒ=ÐÊÃ˪·4–Ò˜U™¬Ô êÍix<¡,(‘¤Ï*o:ŽÅÌw%D£ÖJÜçúÇ£þûª_ØÄШ µ©nؤkQOsú±¯gž¤Ðs¼¯ò=ˆ+תþºt åYgÛ‰8sAk¼gT _ŸÎ±UzB‘Í‹S’€€—ª¾ë½®Cõ vèˆßw~(× ¬|;kÀai»L®Š³h¿ú)®ß*wÑvv4§”4>Í>«®Uj­V¶õ]!Ò-\&Sw° ¯‹„¾2Ö‘‘°½¬Ùc?°_Õ«x“zB·a¾®E’ØLp¥ñx^´íØÅ q«œLHØYó:Q51?¸P½øFìAQÆÌû‚I2pêž ÝyÕÎzj6} k"}¾…ü´U‹Br½îYê —Í R9ÄÕêJéÒ£Ñû´9{ïCä$õéGŠs:'Têd™øœèó>óûƒ]Z$ýŒ§ætýä+¼‹ÛEW‡Ïá.M­¯wž4\ûlR¥™Xà% ÓøŒô'`Kï-3M ˆ”½d_ï”Jö4µÐ*¨‹¸o ê ‚ʇ'Þ¸ƒŸxá¿u îÝ#bmð`eÀΞs™Þ·<˜“þ5¢sU]¯¼nîæÝi¬"2Œë ó}yMVËògoçúT\µjØMdÁæn¦z§z-°¤àï¥/PñѵAþ=œOMÇgIϬßѸ†=·ä°Ø¯ƒH°RG÷„K‹‰ÎWg•ÃZ¹˜¹¨çñNÈÕ©ÇÙÿ¢ˆ¯g]¯ÑÈB^× ‹¤¢è©\l^ÍæjŸ8WþâÍÇÄ•|ÞèÜVAèš —fW/ÍЖ¼C±ʼXõ£ÇëŸ.ð—«ÊN+N$×µɇ5¥ÆÄ†ºXãyifœâðP¯Uûë†$…2r‰¶^šf^ØT-‹`IPy2²ј=¬W¬÷û$üBÊd^Iùöyþ»ùj3ÖJÔã ¯MÂ[ù“‹Þègså”4oŒŠFƒ†4Âã?Þ2­%Aÿɪ«ìt3âRÝy"SòR?v¡Ç©–{•f>B¿ýˆ¹¶y'š¤§GQhR.(¯‘"ÔAabø„‚àÇ÷/˜…d šsúoØ{°Qµ]7!Fõl† œ‰ø7!-2oX!ÔãÇH 5\¹6þˆ±Uæxê”Ôøê¢eçµhÏB+U—d¸ÿ®Rç1ܦ‚ËêÛºFV­ÃÛ~4Kµ¾ÛRs8G-œ¯»zýâ@:`ÐWCcqïàˆ³¥WþÁò¢òmƒÒ„1DsÁýËúßÂg2Јëòð‡nãqv`’€€›ÇÈ·S’ë =¶D½ÌÃ1Ó)æe2‹#)iáƒÝÔÌwdù‡Ý×·,V@\Ò-ë (ÌWÊÚÿ,Iû€FØ:ë=sðNÆ€d;†GËgãcï̑ҡo›-&{¦}Œ‰Do™0Ñu`Ÿèæ9À`DÜfáž®f’p‡wUT¤c¥,—qIþG|5òè åŠ]ƒïÄèFXÜ.Ès^ï\t)½f³«8>u'ü•‰#êFµ.cAqóÀ{oÏ-"YãI]¢"Z‘”|Tä…c'(‡‰zFUÐê¨-©ž«8dØ…Úâ\œÄ@ÞŽëÙó‚;%Ñ…Ó±t†2ŽÑç;’¦¿Š n @r¼ÚÆÛ „hühÔZ’“ó2R°e$œ„õo—ÈÈ5OŽd·Ð?qPgóÜxsß¡‹'ki§º},þЕ WŒÂwûw{ü¨òÚtW‘â}¥&±åK”& °p^6ý¥­¡“¨bÐæe,oÞPþ)ÉÇÂ0øÀåöƒtPzH$ ¤y £wä j(×w|—%ák•õØ3 =§öjÞõšðÁMÝS›OØqÖ,A‰l¾6§}©>o5icËûŸ:"·@{(ûŠ)O¨Ü¦ÒLHZ:[@g[Sä,œ‡!Ï ÓE(Kµ ±é'GÃãUyq©êƒ´²DEpN\’y@¨yMN]Ê­øZ¤>‘?~œ­Âª¼="rnòŒÖ§ZXk‰Á­ÅtxOpÔßœdÜܤB›RgDO.ƒÃ‘¥\©ÔëȶFqïh]óÂæ÷Ãêy_ j )ÉñÚÿsÜY¦Éú÷M£ NþÃ’&o_‘MÀaÔŽŠÑ´SÆiï/{ \€˜~” ÐvvžÉ†3©¦j¯­Qû×e¨¼cáˆ`/3À€ç~Ÿ"ädíüµj5Kç¨<5Äe¸:PuŽ%ŒaŽ´uÿczvÕ¨rÀâïßnh·¶g¶“?è_ý¯ðµ¦7€!£?%Ø6²þ.Á¿íôW=¡rú ò»•+<œ«äe‚o¥­uüÇeÆ{Òy½«J‰ÜÖÑràöãÖD@¨×Æ9}‚¸ÿ »SÜFƒ )0õ¦Ì$b4ö«Ox4 ²‹ ‹ŠIQkâÿkOò|ï)±‹‡%Ý?ùˆ¾:zœ¢W ‘\ÜË)ôÍÆ^Sée¸½¾@€ÕN€‘ÿ "jÞ0] ð[Ú±‡˜G÷cmø³ÄÔ;˜\Ðõ9-ñFÜø_Z4Ú±3Èr½« 단t„2ˈsìp_¬AøÕ=u^NcíE`K…žÈë ñš²özN“x¬ü.þ‚¹6;í’€€Õ@ŠéÁh³Èº#Žèw!b+¹täx,ösG«emšø¦6ö‡GŠÁŽ]Ñ>3,׈–K²®€™Á't¾è”süxYþ—ªÝ ü­Åù¿ÈçòOVY(ŠM 1–´í›¦›Â~4º0O,;ï˜ûió,Ù4dŽÞ F7›‘ãÚÚoî`ož…9å§›òŽþuî&o»¿ºZ?ÒÑ<æ`£ªA'pM-žQ‘Ÿ5?4î´›@°Ûd ah |`ÿRIUKG´¹yl] ‹§Õ™»åä‘oÄ•óp%‹ûc§þÅ<ûßxNâcŠ#Á-Nd§3ˆSÕ*QŠ"d²¦àúÖøùì‹Ã÷®ß±Ù‡ûôÔ+š~xÎVÝ÷ç¡t’`¼7 šôX¶ùµ®ƒk„±6l§ðÒËÕ¡/¬•rÞŒ7Â+Œª_­OyÜÁ¯"ãQóÍØ[`Ù:Sß™„†Ï2þ µoàäëµÄ==Ý”Zê…‚óf*©§ ‘ë3nÑõ!B냡¥åbË]$‹G”>2ÉñéIJ šäœ]bgãÌ䡯è¿C¡Më_ÝÜáåžJv:|ì_y¯ h—×¼.5E w¡²z‚>X,èL·0 R‹š…† ÂÁ@©ì-MlJ3´gÇQ9_ìŠÝ™'1ò{õ'JÏÒqp‚B ~9£:f’Ž9Ú>¤¶œìÿX—éÑĸ™æ:kÁFm =¶ ’áöd³ÂŸg÷º@vo¯ÍØÛNpžœülCŠÈ“RÀQ*ªàå9ÉîÌ%C°+¬õcÀ i–ü[EÃ^ 0¡hX[ÀmbƒQ(ˇûä Ò5dÂ3-Þ»þ°S×=Rƒ£¾LžgûYŒ6¨P޽•ûõÄvyªOCÏ€{þàÒq?-Æ«öz üDA…e'DŸ´)óÔ_z(¿·_è¤Â޳$ª$y8 ‹›r+…”ábšÐ-R˜Y¾ ?N?¼n7‰56„Veï¡–‘Cܰª¸ /¡üûñ¿ Œç<þ†:/j»©í•Zo6 ½|òžœš[:éƒQì­Ã$QÚ©jò°û,ý¬çŽcEl[_·;&`ž}~U}‰ØÇ×3·'ßa/ƒDê QêÿL|›KP ¢`p”­gVÿ~´Ö±h"ÓZoü›½ò“î…÷Ç}‘tàŒÙãÝà¸rÙGÅ03,åî;-Ç¿âÈ0ïNÛ•_¾&1Âwš a1›Ò» I< ù3u|ÎQáÕS¹t;ÂØ•Ah‡ eÕ ß™kŠ\­ñ ùÍuöîêÖošô¶V¯å3F®±Þ,%ÏNŒò¨sdÙš L*Ûàx¹´ =8‘.J-Èa£º’òmý;“î•ÖÅÃ|ÙDÚ¬nP ZìScÛÿŸlqÎq"°¶E5ídŠÀuq‚BœhØØíxPŸn®²† $ xpÚÐ Xó9œRë%øWyÞd\°§Ä4s‘.Óœ†BŠ7ªÞ)‡:{é9kÓýxÚÿ/pÆÓUßYH?ö“”÷í¨ä:-c5ÔM2ì-õà«’€€ºo#×2ÂÙ>ë²Ë]0 E æˆÚƒ8‡ÛîsÛ[ƒB˜“Ø¡|¿yRgGäQGR"‡í+Ú[Û¸Ùhy î9Œh ç‘þVi€†[\õÊÀySDy9·lõ±¤qWÊZöɲ x˜Cº‘z|5nÜß%¼F©0ü_bî!¯íF;ì ·nXqòÃFLŒPDŒ îÅ'ßÞw<íþHǨ‰ÂŠ¥¿§þ\_#P5ûÂÅ+È[;þÁ9¼‘ïj‰ÆH:9‰øyš§‰ÖQ‘|vWp©ÅlÖùÚ‡¦ŽßrBX7뺔ƒÔÎÍG‹¬ë›º«­\ó°ûÖ¥\f¥íOûÜi°ºèò5”{è †ðF¼’ÖûpÀ“*¡´ƒAE³Ë8ÇŸ eìr AîRãÚ}ÉM'NÃQKOáöLDð”?•1…ˆ*F¯Ôs9;¸—E[µ/ëÇ»/V†¶Z"Iõ_“'€ï­¿‚ë¾RÇ{±}|%Š­¾ù(í $PFó¦–p¢pïã5l”‹|è„/ S‚Ô¼_•vœ’}<ÀÙÊå×Ç’±ƒ¾ñQ‘]Âçþï‚Â'+‚ f${fHEíBÊÔrc¢´ªL°±_°^%e^=€ÝQ¡µîõ§ @Md(?[w}eU† OpçˆÂ™Î\Áòlº)ûúÔÊ ´¥ÙÜv6ƒk¢´·êa®—·1²Oø`’ãu¹gmÍÑ/RH[.Ò^QôÁžêëê¬ØU¬ê“Žûx;ƒ ‡pa÷ùArk’£Ö€d§»q–P<ºƒS%Ù¤5¬Qþ.¯ýMLHkèab c{ BùÄßž(䔵7­Òò6%&Tß ß>÷½£ÁFfUâ*(wíLµÃ.˜y°Òµ.¨Ò‹r-lŸäº¬¸KS™›y{¾¯÷8CŒqÑ­ $¶i¬·SšF¥NãñGbçºùCó7¬†V1ãÄ.gj+Ö‰‘À83×Ñ(¯y€£ñ¸>€5+}ßh­,1Håvß@}»µ¹9_­§ä @àüDçou±±Éõ°óg‹Ãÿªì(„ãõDú¼™î?wÀÎíõKð7ð°Ø„Â·iè†îÞ)}·ð9bz† ü©í« »†€ã‘”“,kvÙ!Ž0⟅>ië»Ý_q–©8P@ɰ=’€€›Ø=×sÙô°z‚æªI…]ÆéJnóí¤ÝéeÂmœÕaÈ2%tíx ýÑ#@5yµ³d³ÑÃÄJªRì&ïå˜ù©š<¡3.¹ÀožFH±ašâO¬íÏ?‘áõÕZ¬~™>_\¤ÚòÞÄP:ì1E¡´e)áå#¦,TKYÃY+–‘R×àR?ø’«ÿr<í¯ÏßÀ¥v2.?G1â1O Ì…6~+ŸêêÝ÷¢dò_в–ØY»™^\’^Kܳ€Ç¢yž£»E'I¡–"݉ S}L9™Áÿ52ý»ç±òosj—; ‰šqnô9£âº!71˜'Ï?8|]PêvɰWª&d¸ÄØ8ÿ€Ÿn0†'º®À'i•+¥¢A)q~kÅ1Þ•ЗF¢2Q0rV¦#Q7´Ùâ[ïEu%ËÐ#[S½ê Õ½ËsNx¢Aëf»\—ìaä2qîÓi--®[HªÆð?ÆønTÅŸ´h“g ^x¦ÊàßáÒ¶ˆ>–⢌RÛú Þgäã¬iV Øõñç\Ét2ÊãSD!“|ÏDÔ|¥EaGV–q•ê! ]“Úû¨¢ï"aɆ©¢-®ÔVkkj©¯›„^¤Ù6jØGÂHóÌãð diÉâ·:ÒåÍ£I²S4¼£'4T6›X“¿ÚmÞ—UW‹Z_ú0 Ï9¥3½|âwÕÎÁϱïgPD,¡†íy÷p©™a:“(£'wÈ!N‚Cº“ß’¦ú08£Ýƒí½îüÎ ß­"jOmÞ›ÉÖ•TÏüBöå^ýi‹Åž-µaÊ—ƒ|ªöpÎæRœî›>Aty&÷ÏÛWkXŧ^Q£'†B‘ºœáj†)rœ˜F­˜"›¯b‹^¤œªÙˆ÷µÇ4ƒoþËYE™y¨Å¥ÝF®8"Ÿü-ôœîÏàü¤ÙfòäleÑÛ&[•«Õ¡.@áö¾©·Ž8M…+’Lq­J’9”›@Yøaˆ$²2Ù}â!{~´¶kW›Ö×$–Ònú¶i•Ì}ÆP3ÁŽ>¦~ªÓaŒ,J¼›@,úu ´^ŠÂ¥ËÁŒGÀÏ·^¢a¦·[puó×: w›<«lÙ÷Ó7íϵz°ßïºçˆj^ë$Qw³R>’€€¿Ë>J*Çîº&p¹,üë/ðàWÔñÙr–ÙXm¨™oßÿcT¾¶,Žy ÔÊ^«ºé¶ß¾kо©¹òð ·F®c¯Oð Î-u2 ­Î!|Þ?¶á79!È7_@FZ³,}Ü·…Óš¥ñ´~xÁdâ~AÃÎ*‡î‡Ðu˜Ç8Ú¾`ÃuÑIÞG&!EÆJ%³ÍcÖ›§MÛ¡ªÙ›Â™AêKŽøÛr!ZÒŽáö*J°l ¨J]­ru¬<ÐïÙÚ–„åî}«¾ ŽM¯ìu­^|×+fb‰;UÙÛR?³µ7¢ýeM¹€…V^}Ñ’ ¦n »û»JÅNä!áD8ATå!û(MöË7Y’ó\ôg¬jè‚‘U!/’g«`0¼DÝô,wòÔ] Íû@+bÓÁd`^Ñ…²V…Ñ€¼¼y÷œBi +üôuÎPƒõpŸ$Af,Ä`(½$Õ§& ŽoÒ´úÞqåô`ØÒ¸&'âÁcE<'f[Ór>uÁS;KˆçÉ–u’§b)¤lǵmçÙ&®û†±iº™ ëÚ³8BÉûŽÿµ2ˆAR@ÔX˜CVDÊ]N‰^oÞê|søX³2~¦¹¯Æu ÚL ‚ú1ã¨UsooÌ‚4Ûó$³B¬yV…ÙÜ-€ÄwimƒšW³tF*Z•úXTè`Ë€›ÝºÔÏfÝ.,Rø#ïÓÅïðlž·}»1¤!³Ü«5 ì;²¨ ¿ûx 'Ž%L*£go¶˜eHrlz§©´L|<çI…Ñ›LøÚE’ÒNÜ´f0DˆÐèݹ`¹­Ô«°õ·[A+^A)µë"†Ž©qÙJÚ¼&…v‡Öît¡ô½ó,ð»3y娼%wå”!3<ñ&ð¢"  t'Ð4³¡bXЛñºÔ“ˆ˜J¬«è¶ºWp¿ðžJè88*waŒøÇT,2åç-Fõ‡òJMWON;]'×rÚ!î›n;S#ÚÄ›ÎMŒP!©#òß®d±Y“.¼lg?ïŸö‹"_á½ñë½LÛ’€€ØKÞ ¡Š^ˆØÇëxä» 0VØA;?*êx÷…âvžÔZz,5ˆ| · Á"gbãYÃE&Tf:í:éèàAGéŠÿÅ'rñ Ó|c‰†¯Åå?ÛõüÑмÿ18‚Ïv,üBõI’{Ë¢ãÄ|ÕøM„j£=è§Kk›/¥œ%Q:¼ÿCÚo¤}ÆœoM9v™Zòôú¦?’·<ÒèC/ ‚:VŽo:þÏ>&p.)Sú½ÙÎ.ªÛãjÚN3qŽMÛ^NçˆÊ G&X˜ýMFúûæaÂB­*Y£&* T†ñÓ­ÉßZ|Ý!äÀ­^6XGðJ’È®S[?¤`ûòDÏ:-@WÒúð},éáv.¤cëÄÅ!{g3+?îW¦âjrd=ÊI·pq¨Õëã&¦A("%€ìqØ ù¥¸¿ga2w–Òõ£v ÒãâÓ£ü™ÜIž&kÝvÙEJŽ(‚§Úi7Û=ס[#ýCÿ›;O²} ó8È45ùåŒÇd·N Ò›µªë”á$€×øíî­SúÛÄz¹þ|hØ.[ì~¡Ú²ø(Âç™eé`p¡ãpèÊGÕ{ü2&³€ãrØNù!µ6Íu?rK5²ùÞ…ýoZK²Œ>QEJ`ýÓŒÖL1­3êî\G`ñïéèfxõ9•xÏD>²Ã—ðGvât?­²Rˆ¿z—òmiÍ>=zkàK<¢/šªonl¨Sx™àúñg³Róú+³Æ r xÍ-2Âáf±Ø”×êò*b‚ñ0?ßõ\Ê=½T¶½´+wXÚ^.êKíš;B΀h–Q"©…¶'æÌ’pTölt«³‹S³Îs¤9bi—›Šó Ð$gß*ºÛ‹LzW2 ƘIas[FÚåHÌ ¿ø«<¯(E–]*ôÇÎÌýy,è¾Nî]#§Ll€wäÓ¦â8YPþÛ·i9lüÓÊ`f:–ƒ}¥hÔo")VºÑÍ­ /Yñ‘8©U@D”ŸúvŸPm•µuoB µÙ ê0˜´ÅÖ%½©K(Š®¶1«ÆrÛëÅ`N¶G¢¢Ôbª@ oB”Ë‹ø`kƒ‹{©³¤Rz_VĹǙI=¾{ú§u¦Jž¼ÚÒçVû¸Eá2h‘ºa+: 0Ž’€€À?º™¹šæ5Cì.•ØE—iy!BäÚ¿iÞj3@ž}Ù.[ê ÷âds~ï#ËP¶^â©![äÒÏ‘ä#íÃ\Ž\S `Ç–Áó;Ñ4¯å;ÛjñCÇH¯.ô†ó#ço$S8ŸfÿE»·„ù6Ûœk|'š¾uÄO±©︟ü/CâðTWcxÃ|–âœâÒKâ9wV°\^< øm¥ç1ȈµÓq“…ÂVó^ÚdóÈ:Iù5jÕ6d‡¢¦Õ ¯Ò•;CÈç—nRŽj6ÏmIøqèeof×dK…¿Z^<)|^°¶¹)µD(%h–병» ‡mgqÇÞ%šŒmÊ•`M(fêßHuæKš<• a e4ÌÅÌò€íוïj[-²SÝõß?Pd„@$.éÏÒcyk_ ¥&+ãsÞQYaâœ,pl—h×j†Ó°Ö©ýÒ«‰•pÐï²ï:× ’™fyºœMnå²ÖÑÒPË6 ‰ä¸×ôI€S9üO~èÐzXç%ECÕ7+2šªæ®Ë±š×_@òÂyÒþ•ªùvš®0/lmH‚骇Jcz•ÓöÄ[ÌŽ%‘è8!†ä­.~=½Cô¬-íõVC¼„»htáAŬ,àÌ„‡TÖ|ZqõÝ#tlº¶R¼RåÈTï³Ò0ÚkãY´Ó‚æ%‡©K"Õ•jnºqÎ×™ZE ¼†ÂãÉønäÔ? ¬•¿•nP*ÚKE„¦áþ±R.%ÇŠ¸9K—œÈ"Ì!_!C¢ duæ¢T/,8hF’ì~˜ã;ÏÏ~.Cµð¢j‹ÈߊKÌeƒ8”a\.e wG4اHô˜š*E[­ß1çg®!¶T–`àkœC%ð%aÁgØåíoŠœ„F°Ž8 í6ެ§M=‚ifBr cš,h+ÐÚ5ÅpÅMF1 à/µ€Å4"‡ñÁ§ÐÚ€Ú"+ñå’"ž¥’£á«ÄÜgÿÝÑöœâlà”Uó ”_vPz®¾11IÚBkiHIÂyÖÊ>µ96à»4T˜‰îò£$LÔ«Äx*{Ö„b“p Y|¾-´GûìÕV&‡æ—!ã5!JÍY T Vô™vý$¤nÇChƒ&T±³14Ô0$ˆ‰¿,’€€ïÈ1ü7<Ìæé =ÞÛa1˜Ôœór¨rf/l¹)Ű7CÞ èŒV ¸ÍÃBæ‘ð€WÇh‡ ŸÙHÏ[ Àq€¶@;”´å½XÔ_g=·jm#ÕéLqT½'ÿÊ-°Ì€˜ðÌÊP%êáœ~wžýÉÂ6§Gûôǧ„æÏ i·T¾-[ÉöT<ˆÁ¢eÙ}z”vôk­Ûg=0 fêJæ.úº$¹m•)¯,Ué6Zþ è³ Ò}ëËR:´àP‡ˆ×ñí® ‚ET@׈vÅ¥íN†ºtU(¶1NÍA“28o.h‡†¯E:gÅ«%|¦ ¦)5Ú¿ñ–‘,íXÐi@%Üu­”ÄœKÓ úë„d5ô|…k…A ‡c ÇkZ¼ O ±•EÅ凯lè>5ˆ†Àj0‹¦M³Ö"tÂ>ò gb,¶jT‰çyRâ6Ò%œ­u Ö¢pÉú ÐV€6\½WÊOôs‹‹¿mڭÛê_n&üz’Pn.sÁl¥'âM9 ü|.íj,øR—öÛs3oeÍãå6™Ê7V€m‚ä£ì=Rë ”F«.²ÏAV8P$øvkï§YDC$ ¿7c ÀäžiÊÄBÏIں⠞ÞÉ:ãÜýjÙÑóiá£`Vjéï^nX®ŸøÄÿ=X¬´Ú­çe1!AÔ¤»#’ÌÀ(taâàµF„;s «YFlê0š7L2ñAË— ªs=T°•‹¸ ¸·}=ø¨¼,%]—úî9àþö0U9¤o||ƒ¥1Ù[Œ…nŸÃ±e^5š¹‘ý¦:c+Ù·zØ”šL¼$±íÕ jÐɽrêî½>XìâX©Ø¸Eß#GEý©*c C£»ˆû‰ä×I?ÿŸ¹+ñc`¯°‘e€ÄVv$(cùwŽ*á…:Uö“GÃAqYBÔû’€€Ãyòiz?Sä}ÃÿaÙxàc¤°\üß%L©âv•èÃXÝ'$'‹xÉÿ.jéÙoi¶)jŸ!¡] ’.«D $ÜmÊ=SèÈûõx$½oõáe@ K½{çÂÂôŒ‰XN„µëE%_â€Y1~á&Å6Ч&–ñUí}Ür±Ú¬¢ÈŒƒÐ¼ð]ð¨øŽÇ‘„Rhhú´Î]\s&ùS_MÚóÕûuä“lLnY¸© Œ1Á^íÝ—UóAˆåö‚û×¥éúfK–Ø©ƒöªÚ Fˆ¿9¾E…=¬=míÔå/(˜´¿]mªI•¡yÖ=Ån€ÛÚõ²[¤$mvÒµ¤@>® ù–œ "›p½¯I?{R[B žˆÓfö±úFBy^Ç O'¤¼ë}Êå”ê3·žàË+ÉK ª·°,žSXÅŽ(ÁI`A™½«¢RïÇ…pŸY¬Eþ ~@þ,±0i[Bøqú¤4éZI§ ²Xv,Ÿ\~`7«Â­n8›rOž`ý§gî­«õY9³’$†`³ ²•q!0ë=´ñó~E©FmñsàjxQ=±ªQÐÀ+<ÆDÈ¡Ê ÀœÅô6Ö@æÞ¡ëSr£ydƒæ"‘[Ýú˜T£rêðÔÿ˜  :Î´Š½†x;Æé÷ÎYò£aÿåʇ¿-Õiª‰>ØJÇGeؾxgµtå…ïD¨åM‚}¢Ÿ]¡ìIÈ\3q o¿èÌÞ1ƒÈW‡o¼Wy·ñIƒ°^ó›_*Ž=ãÇ4Oå.oí™(ìAOÇ“/ŠvCË¥ÿÔb¹½‚3=sd³¤Íš´IÛ üW–¸ONmÃŽ‚g”|¡Ë]$·'<ët)$€köT4žEKyWëiÃfpRÀ°Nì–DœõÈ[!VXáepŸ.ݲ[Ýg:I¨ãpù­Ê^¸Ôå7ì}Oœ– ½F}€Äˆ%íÞ`=‚aËêŽ^Z©ò=²N°# /Âë[SÀ€‘jëˆóÍ4I©)ˆT¸ë€p8yÅù/E'Ù ‡( _Å@ÕiZ4gÄ9‡Êئrë3¹°¾§±Å·a"ê¯_âê#¨qw Ö@ õ—&èZK}{mÝØ£n>/<‡~š²³t„.©¼&ÒÐYÔÿ½U“¹m;qN1UÙï9}œpÔ’€€ÌÊy"Ÿ /äÍùŒ\ßF)±rÑG‚kW}ú/´8SÁ>\€Qí%×0Ù°9Ýv !ôáo~ZìW‰ð©.&/0ÐÍ®÷c¸û§7Å„sœƒl bso !½NÓ„ìI¦+¶ªíÁâ´Ç9‡1m< Gð«E£u·Ú©f†Dàû†³ê“¯°»ƒ\XÐ);Õù˜ˆ,Ϩר=®NÑ.esJœüà'¤q€iàži`"³Ó#ßi€ºêÌÿåÈ/ø” ö;r$or(.„$qÝM‘,‘cv³xs? ,ºZù\Ô.»Rr¤ËTÎì;Ö{UýŠ’ðÂün‘!“Ëiø]ŸÁH§"„—#`pѽ]æÒ>^½vòCZZ9‘v~%ŽÃºßHì8ëb–P­E0²Wy¿ py/øa»Ç\4º“<÷=&))Ç3ïŽ\‹ã‰—Y>ç Û;ù“Ê™æwaàêT‚e’€€›ø•ÕÄWz+Ž<›~63À"MýcOW¯1È! ðÁ«Éþ ýQ{WÕ±£Zèt£êÉß¹/ÚŠ׋œâ˜oJÿ&°KdßJ=þpú"h#öÅ®-ø´Z>½Ä;nï÷1ëlÙÉZÓ\<4ìEþß;j\,ÛOý¸:üî0d¹zaê¼´ðÌž,ôà_Ÿ?í¶±ò0©ò°;ò\o+1Ö¹A¿ÒÓk³¶ËÖ=ÉIÚL¥ì>èo^ðóÒLEQ°÷L¡EíMv/ßáÅ3H»;féo‘Ýz)‡3ÙõŵèNõÇ 53'geÌ¡jº3±S¼Ióª§5E“VWüR‰­™*ß.c¿ªf¹}W§™ ­‹!¤û8P³»ä”ŽtþÙ¹XôÁ,3³ a‡ÿ¼j%1h¾º°KÅšûïãrÃü›+3ù²½"Û‚^¾ÿ0xµ>úlåÿÖù`‘y55\¬Ûâl&êâš}ՊߢåÐ/²¥|Œ¢¸»¦ï%Âe5¡…ÄQ"‚àB'b¸x§qã‘‹ê›ânúV›Áå¡Ù"°Åå©®Ü\§¢¯?4YP±ÂbFDíŠßg"$„èf8n܃ÀyÓ!@YuŠJD¿¶¬ù’€€ÚÀ­ r‘•EM\¹‚ “’½7ˆGKë,‡>*ÿ¢Æ’¬@?æ=VQî÷`L·ÄN‘»{ þð™ð…S³–lƒ¶£Í{à|©äâÏJ- Æï§È ýmõyüW´34QÛŽšâÙ †¾x×ùÄß3;kh)‘Vy#2·ÃoßAøx‹¿‰=Ÿ4 Ò]ƒ'¨f»÷üé\dk ¿‹¿[Ù"$× óbÚÌ(•Äf‰ @Dš׃“Ê!½høðü¾¯:ô­Éßwìµáèöé)× ¬ç^ùnx®Ê™*)”Õ_]õ#’ð}ÀÛ™ÕJ÷åCMê_3ëDPܾ™F8ßÌ|YL|¢¿1˜bg’däô çónGK3qCT^eë{¾´ÓåSoâÖQ^É¿Ü&ШŒLբόéO»qNô#©³Ý¦¹‘4çT=é÷´;`oKøKG9#>qx¢P‹að©TFk:â/6 =Æ?˜?øƒ hZ;}CmLáÿËè/ÚÞ%Ê…æì)Wý¯T‘®,ud ʿ⧌MQxl…ˆòõ¨ª›Uξ˫ñÿ7KÁžŠøU'¥'Åo›å#ó5§4ÒÁà‡ õº'T] vÑ"¨²¥l¸P²<êÄö¿:“¥K„Ôs7Ò»‘’9gtFïÆPÜÉÞ3ƒøñ9bË¡%góšþWÊLG¯â å_¹ÀÇüé¼à:]ÄÆA<™ÁQ¸Ø¼—ˆ–  vú®²JUN·n~WàYä«ìAÆ£¨ž8™Ä †AÓÿç:9J˜Óh·jwB{(¯``(ž.]±’ÛfÐ8Ç4`Íâf­ºßUæâ¿—áÀ£»Ä;W!Ó ­m–,ÜYl©i}ÜûAA«†d0LŒ=, eð-‚üÖ’wôXœU áûpn§Ü·æDèFç¼Ò§‚Ž™p*¼D–=âš-©èþ•ÄhŽën>`cy¸¼Â7”ÐŽÒÛÀ$ @¨¹ÞB¡Gÿ˽³,ìê9OÚÌBË)õ÷†X0òÍÎSÜ­ ÞwYû)(@f‹Ð!%Õ7O2Žåá=ð ÃÚx7 ["`gvÔª¸3;ì±Z«_µ>k:¨#@ Z–Xzc?ýÜÂʹ”ô?ƒa2§û §B€"÷nZàÒr’»½Š¯4=9ú)y=õÌ ]mm ¶GVªÃ]Š:¯Ø .߈ MhÈ©º€þlúÖÀ[¦è Äæsç¯gšY^rˆ)@XX~QKÖ ) ©œ×bÕ=zDíå×|5øa#‰Hé¢ G"¬6"Xºpß@¨…•{"ÉÓ_ÀI [òÂQ9Nr[åM4O§_k@Ë[;,Cíw—ç-£-–5޹4p r=ØP ŠÓ@2G^IÂܬ>³ûì’|[°Âl„eÜÍ·¹ØÝ9¦ S*åxŸ±hpÖa¯6‰)ÐQ¯7˜>0W.ܦ’%LmÆß±ñ¤1 ¾hi$eþAùÆig³“žHx6cü›ZyþoéG‰蟷´¿Åæ4+_wÌéÐ:'uN¢˜vÏ®ÓWY_£"&+­¯n a»K87ø¨ó#PÇóRßA†‰ãrɉ2Ú¿hz<§ ÉÞûF"ªà³{ò‘BaéN#Ö ÔìÆa÷€ÆynÏëô¿õTEuS†Aï;0÷¸|Œ uY‰ˆx“ûÑ] UÂa*;ÂâIÒMo¯&r€ŸîþL©xv ž4Ï«~“SŸ(½–IÚ>Û]u€æ:ãÔcÛId-owܪÄäÓ ›ô^Z1ø€1=mh‘GFŠ zá/‚>tL#›8»ÒÊ\Î[è§ó˜Q;NÙn‰·ÛÖðé0÷ñ´¡kðG‹Bâüo€¾ˆq£50P#²¥1“ ‹V1À˜²ÁårA'j7NÁÜÞ~5;]ÿ€>yìøÀÝ ·jY}õ¹Z×G ýdgè¹/9Sä:$âyõ5¦³Ä¸T³±Ü*$ÌR7Âd;&^_™«ž;\ jö»•lV53Qô¿»†Û3ÍKT`[`L%hõ$Ô(++ Éî‘`þ=VÀU}ÞèLUPÕïh™›¤Ò눵g >\êI ”bVÉ ýY95QVø43O.’€€ÖCŸ]û<ubò(º÷kTeœL>-ª×Àöµõ¢¡Ñ««…CÑÄ~Å<ÙÝëR˜ðbǘ!ìj„J­¾í³aOx›DøÎVÓú*`œÂO±¢åŠø*âÉ¿@¥|Diùîí¶NÝ#‡Ì«ã”IO«€"~Í«:O}Æíç8š5ÔgºxIŸáôº¤ÅŠxèuhÛÕ¸ U:^G’º)úÌ2G¹v¸¥í#Q°¬ëÐý°€øMû-n°™+B.¨ñÉÐK†'‰ËaövíïžA8± ‡ÖV_í‘\»¹‹Níü<£tŒ§ó§l£{ëš¾yám*!!ׄ3Öt&ãíCB‡ÊX>úIŸÂã[¢WJËA„ÕJ*F}—בuMiЏž()&.š®:Þ†÷ÜkU¦&2K‘P„ö]ÂdZ³¬_1ú>eNN@«c ·ñ‰ò“®¯ôÉ~Šie‘6pY`Î +fÆF~Tv#óëôj#˜DÑýÓeu&³†`xuçûЙ»§¦¦eYK±¾t¡nª 3·,ë9JSmÚC.k«¢­pÁ‚¹º;¯Ôû;ÉÒ+/QÍ×n(œéªe-W±UXÿ’Çv);âÝtÏMzÐin>”—°¨Öé?GzjÂ1àââ(uÃm+æÞ;Œé5Ƈßi§öìĦãò9Ö±·”LE'èh{ëD…›Ç-ÔæZ/4W›Q_ø,)H9𺟴}·"k£gÌÒeæãã•OC“ËÝ\ÇîuäÂyAæ2L+Ç*Dÿ×Áñ]Æœ,‡æò^ÜÁ†³‰sø¹¿>=}•ÏÕœðJûV’+¼êpæÒaÔ½«YïÛíAë³ïÑ Æw^²¥Ô$n¾ò¦boX0´3Ö¥Æëg<{$Ÿ4ЯÒ#ûBb¹'ÅA÷+*nhÇøp’€€Ã&Æå„˜Ÿ¶N®€0µ$nؘÙe˜À£‘€à3€¹ÕÊbØ@Õr[¡ääÐy¡ÍÝ­ bÎÁsk˜q $WOž9‰h$ÊÔòçy|3(˜…:ªmÁÆÏ§`Åûk4Ü {ÂgºÈ]ÝÛ î×ûëOðþ—ÇnÚæø«äãHÇSuWxíÍ´|cÐu´XÉŠñ-Üãy!X$uš_Ö™dº;µ¤m}5¯ŸéN÷“HÕñê;™cäÅd ÝZVêoíøºq3šu7¨MÂðLíê\Áí86å´Ÿ_$ºvÕõXN%> Ù — :€zƒx¥€@m2¹Ëß5ˆ¥!ðãÐÚ4P‘öUs2Ð@\4Ø3^ŸãIßgZT„õˆ³b&ÜŒí îR¿Ä“4nG¨”ë ¶-a@ ÷Xº8õ,®¸9+“aRÃêš áX„»t$ƒ9ÌBWü ƒlÁ€{Vp ÕwÿdÙCZ冀ÇÓ§tø`ä¼ÜKÝQhÄk¹ïŒ@ûue4$äk7Z_ÊÉÅ¢_œêÅB³wÖ°ô=¦Ó@d{·1Ĭï—*ÓÍ<¨ÎBñÜ”wf‚*mmù1^QÝÆoߣÖrTI>ôÜ ~+ðnux’G‡ÌžW;ÍQÛLª£*7Q¶µ-ÃÎ EçØ*p'cŸiT£ÿ†ØÝRÛ¢èz¡6Ó[-_€s…ºÎ•ño°Ð°·³Ë8­p‰´nÃ~ÉyDd649PYgçm†Â0ÆtÉøæðÑ* w”:¹‚Ä€óÜr ·q,Wv¯ß4Læ[V,LÚê½# ‡ë°“x”¦Ô_wàþÇÕµSÉ$»=¶›ÌⰠዎKÔëƅ©Ë(á1X_ë4¿Ó5Ä—¸ÀÇáÍ08]’¾º×niú$ÐKŒì\p]ºcyE›î©{Êï¯ÀçÂø¦aoðÎ5î#}Â^‰_ä)¤DimµyH&î§’€€äˆ•q­µ2 €Žìö ¤º{dGq… Ì>Ⱦ¿j"§¢KQa÷Â;ÍPÆ®6l»2›Y94eÞ[îw•éñóò ögÊ|RiÎpŒEš3ЀI,e<èØ+îÓ¸,ëÁsu¬ÿdô‹t{OK= ¶hˆEªdÂt¸:aÍ[C™_v{GMJìl¹…x칸Óm ^$nP]«taQx¼”Ëþ…ì×T_6ÙNÞg¥c§4 eÐ ;æ" #Ýöêu_§ºö MŸ„tO«”`å{{('Ít°^‘š|f‚Í€&kfáeúÈÇ9ް‹´I[,Ù„¦–ÝÒŸ©ƒ¶ˆ›§¨ ì g:µ9Þ»­U,¿ e”ãM¡@Gq&=ÉIüP½KD(V±SQ¼ ãfðkI³Ù—«|Ñ‹ …û@Ÿix|¾‘%ÎÊ®Y©’Õ³ò@AÌJO“»È×"vj“+À™Ù»ÙQ‚]| Y?Ûƒf-÷wàßÍéåÃa›Cñ¾ÁðÓŽRf,Ž§Ô’Š;Ëä]#öœ ïí˜.ô=!¶*ÇÝ ®ì^ &¡©ã>d¯"˜“©ëè?ÔèF¡Õzôð;‰<È‘VG{{?î_Ü:V–,Ú¡Š~¬®£pø™ä[ÜᎢÕS6ù+­“ãd=×¹ÄHÿ"DÜùÉb›X?óæÊÐðÓŒîbÈÕ:7çÀÜJÇØÉd–5vúìÇ‚¡ø»Mà:Ü™BWXÌþñƺÈÅ’ý§ËµH‰SGĶ꼫)( ä>. •œ¥ˆeb€R Æb-V µ["àUýýQÜõAãóU µì.Þ1çmá—ð©Ë{#à¦ø¯äkœ/gØã º]w¤xjvЀ …>zgh»¥Sƒ….¼ÑØ«éyÚ –¾.`{±Å™Y¡ Èjà[îÛ$®y× ±Œò˜+q]U­ýE3Þ’«É:ÒÆ!ÊgÌ·ÐUù¥WJñ]g"ÇQ¡>˜7bh•skk§¼Mñ¥ÍÆj¥[zî¥ÖÅ•ä>cÒû9:VfŸ|º:õ —d‚8õ)øÁÊ€‹bú}Ìÿ‹xžj²a€l–´íö\ ªbÉkXÀC†"—’e­ì(#~Lw4D¸MIIÇ(DK|ôR1tW5PÝÆD0Sh/Ãß›Lv+^ÑêòP/¢Þ’€€Õ3=ôîbÔû»Öž0Ù¨Æho©,+õ¨ ,ó_(ê6ƒøý\N§0Oæ½îc*#Ð}±`Ÿë/¤ÞªºÌ'5 ¬L¹ÅƘï®ßN(Z:hŸ^N¼6{*tfšßËn/a(KR_‘K–m_4¨l‘ŒzÕÍý¥öbûËÄê{ßf¡ÓÓW5zo›Ùs†÷záF_§Þ aÏÝÅ­Ø6ñ=ÒV¿Š4 G~ÚŸDêí.8¸-6âJº‹ f£n>‘êaù„<9ù&jǪ,”_nܾ8Ñ~Æ÷ûroÊÂJn‚!ÈÿŒà%U6™áö_Ãdh?[ÒDA“ž+g 5uò¨tt×HË!ൠ^‡VÖD…RH­U‹»UHÕ„³¯‘¶ÞÊýº„Jž ÛÙHšºèAL£{ÅIœâ6…} {_fÊ躖Ln`ºoˆa­hI\õ?TÏ¥NÚîu¯5ƒ—}Žv’×ýµµBÞøW ñîoò^¢õpØçÛÍâx]:E%QÒþ*“V"Ò’¢³ZNs¶CQGÓ`…OoLÝ=µŸ—ü`ò›qÇ;{ãíq©½ÖCÍ4Có­›|4"E©•Á¬>åEQÊÍï2pò.y@´&’íÎhÄ…"æ% óŒ/3ïðªÓG_AÍ'2–áþ–gÆãlÆ+$ç…Ñ}ÏHû‹°Úäe‘<{µîC4ÖM‡?C0´¡½*Glm€}H(”•à•é‹}ƒ"e‰Ã5翼ã:ƒ5U×ÂUáÐ…o&+¶˜¯ò®É1QíÏ>ާì’#]G!žY;s•Üß*èòTÁ‡SÖ]Ö.˜(6’ñHCI¤Y·?|g’SûÊ…o&eîïGîÅ¿=]î±¾$…ZŽzÿáháMF´ÊßÊŒ´€Af›e=¯Î|›Hú§x¹ã4!¨[Í\.4SÂò¬ÓÕËÃÊ¡Až6FDˆ8Eã^Q}Sg¿Üî1r¯àå8 “a-qúfûïPÇ¡|˜›ùœhµbÞ.€o4—Õó^!»ôüdê†lć_ýwgN¤”=ç gZè aÐgñæÅ†"-"—ª`åꘛ™#C;®.oSÕ"øVXìlq¨îdú%Ý ±5-ciSTL¥<|&Áƒs`Äkvì¾Da­l•ºè»‰±£r‰' ÄpΖºïŸHñ“ö[°E_d°%ØRcÀÎM~ ž(åa"»áܰ?„sqŠ™·3£" LÕ‚´¨,öãÃÍ&ý=º#W@Š µc¸ŠöçÇeÖÒ·ûpG'ü7Ájåãx;o;¥wwªR{':weØDP Ä€PuíýáÁc“S‡èÖrD”¦îA^Ï5j‰ÆÁÂ?²ÞjÅ·ù™Ûý™À æªjýšo¸·‹Q;¿w ¿á a~ýuò¶Þ5Ϋƒ§¯ÆâDÑÛÝs°Ò¬òeW<ă4‘DÍØV-­N-Ûý©õ2y vY­K)©a¨Þ^ýš’€€½:ÀæùU ¾üD‰Ó5½hæsÿøi¾SÎ/2lÈRµ¼ÇÂ~·V -¸c‹ÌîÊŽ1ãÙ7thˆRe\ßpZ=D pÕq¶nž³‰|Ó¼nÔ{ì›l6X1„ŽQˆ ]ËÜ£äˆÌÖŽ`ƒ }\ ¼pkØ#ž"$¸X^ÔÚ÷ö Ôu2,pム¤Kx[ŇB¶¡Ë%e³¯&˜åï DJX‚IÔ#Ù9cÃÄ|‘´´ÒJ¹Òâû>¹OGØD/îÖ·ÖáõG‘,¬0ÛŒö„`¥+Ja¬& ZœÝQmíØÈiâk¹Y»5‘¬G´ç]Pàmx.e¬ =(®òîêe56¯H©!8 ÿãØ°NÃ3m4ÅhTÄô § }úß;äùi‚x& :2f"•JE&¡¾Œ¬S&’\_©ð ©õjUé‚®PJ]Xs’~ ¬ÛÓ`{;ÜÄ&»Â|á}”ñ+b×|ËoLS ëÿDcLÖ‡ää-Û…ü6Ƣï®õ-ç™.ìöN½‚R`zŸþ…تP‰FçȦ‘I¢VüŒ$tb–[—Ày MšiêÁxúóðŒÍï2–Ëá¹çoÎBÀhOŒ¦¤¿lù2M"úÕøþÅ=>X³R®Ï6Â+lMï~Kè}k$Ž½Ò ×ƒµÃé/üd'ûƒ™¬…ŸMÐBwé Nl:XcÙ[R]‚Tu9)Ù¤@¿<4‘þXWj—÷ɺè?EäÞñIű?íÛ’)£š+ô+À Â¥œ·à¢t¥ÝƒšQ¢«hpÆ×Qláb†P_´?û z{ÚäÀÑVš>ÙϽ'ÊL,ÆP¿þެ™Ó÷Eàm—v„¸ó¡¶gÁ²cºùb,©*µ,Ãð¬Çq YKéÄe„üü;„D7´®Tƒn¤[. 7 @#òÅii}ŸL䜠?ø“‘>½š ¥$Kø–æhÀ÷ ÃWØ7Ÿ^´v)õ½S@x%EeÝ„¯$ÎäãLô5E¤òDašÇe\Å õéž~º¬šb:ú`ÔÚº~h@;8E øIXôŸ~Õ„Ùè…¨5o2ÆÚ›/š¹AÚ¢ ‹M©ÍI7ÉŠ&Ô:šfiá¾Z¼u¾?ÉØg?_)I~¶ì¸fÈ’€€ÅŒ!ce[]Ýsÿt³Äƒª&„û“,¥ñ-4Úþ¥y­î­þ®É=ƒW ÓjÞÝÆ ¨®ÍQªý%HÛ Ûõ2˜¦­ÀðËÎw2d¡(‡ü0 r¯yÇ‹‹øYçÅ¡}H-FZHÛóˆŒÖîêAÈPâú½k~CÀÌO¿ ±Òic~4ÐGu5ʺ‰±8ÎDfFÏb¦ # ((̔穾/Å~¡q=d–É7_¤ß)µz °›%Ñ>¡FÄ»•z‘ä¦{ªd2\£„xïmß2.êŽÇ‡EÔÚ[Ú^’‘w›J¶‚¶ù§0‡K•-ž@ ðç@;›¬JF¾b®•µ[pVàà %J™‡µöÚ0áûWWJ*ø6QíèFâ-Q2äzépŠävvoöêŒé£û”#…ˆ^BÝR˜_½·«±ó}Zu,^ÒímEÚðòßË3¼©$C*f¥CÜÌÞGMb4\ý#QùB·u1ˆPD–y-Ÿ*ÀÕW-&3ÞŒk¶Óý‹DäUƒ¢ò;ib¥’Ób’=©Œ®g†˜qØ"5á™ÁÚV$sû=í…±¾$qõJ·V΂8#(È¢ov®+Í·ùr‚^Ùge §HÕjŠX9žÐ–IßVI²A UÒô¼é-ÏÊWEÍoà-d\v5XáÈdÝù/k5‹G•¥ ?9,’¸µÂØu –üý,?}æ bçÜ©›•V¢n\b8ÚœI䡪ç§ÿû‹â튒Qëq“ì¤uÞNؠЬÔúéòŽ{3“•4ÿNû…]Ã\#êö,õ!„ø0)Gpfò.N jƒIftF¶ˆÁû8p¯gÊónä¿dÒ˜Ÿ·ŽNöHQFˆêÆ1Ÿ¦©IÙež?ó¡|K©-z}.ëŽå03Îtžñ„<Ó·à‹ª¥Óç{Dɸ·(2„Íl•ÛYïÒ`ÙœØEæzƒ0žÂ( ’)ûÅ¥!Ä=ÐFlS ÉQõÔ~œ¯¹‚ÏÕ)'E‡|lHÍ®V‹&h(3öÕíUÒÿüÑä´šÚ—“½ü=ØöRÖÚË7$QõÁùm ø‡ûgPÏ‚* ZtŠÁZâ-ùž†§W<Ü7,3½sõ D¡èÛª— »Â®¥kº?Û® Ä ¶9ð„ÞþHi R »«yDfºrD‘®.™’€€Îløtš@ )«¨3ªØàªk¹ÿàÛ›w# §’Õí¤Ñ:.úS1¦¯‰þô*cu¢V:·-DòáX`­´njJM$¶íœXpV’@g‚¦Z˜s:£…£=n””®×Âñt2Ø—øÊÜjXÕÂ;AZÎyý¦zŒ¶)à’|ŒæÏ ?†Ÿ/¬wݰ–é“;ÆØRýeâr°ç7{ŠÉ×)7ïwϬ™< §Ç¦þºÄ=:’ôSFþľ)La‘ËÚº†}ßZçÛ¨Bp)²b¤¾â>¨îã­ÕŸ>ÔÛ¢ßr Åîºpí°Â³l½·—Þ8å6 —ÉñŸ¤Úß'[¸Ð äí'"³ñÔ{ÚÞ2(`p‹òú„ƒõöèõaŸí.Õ /Äú†ÛÙòhÑßÑ‘O“‡’Oû¾Oæ¬{ÐâØ%›5B0õWÏB»g¹¯„Âoòƒ:ieãã-ycX›R€¹ ^nÊq v¡ÚÀßáµa}e Û–¨ ³hZC1â¨{dÚô¦‹°¨R6V8¹³Å´ä{Ò$ÓBjÙŒûՔB/Y "ƒ4›j¾×ͧ^KDð.Ɉ|O±&”4"Õ]»=ˆEµïz¯ÿƒ[¹ÀŸ+§Ãx[²?³ù/*Y˜J¨<|–ì`¬AÀô´86_åçZÈÓå [¥í«ÿþ7ûДúü‹¶©åÍWG׎û:vXiCÊÐqmªC8¾ÌUùèËÞïZ”K&âR‹ùbã¼!ày^/à •8W"6Õg‚ $ÀDDA\,Jä­%JzóXçµÀ•‘L=Ͷ+I.¾Ÿ}€)’`ã%Â\k)ò^ô®hEÞX˜¯ß3eg í4\™®LýPTW¤ãéÜûFÉÈ‘ñd[Ü®ã™!ÇËCËáúpE¢Â¾°šg0Yÿ32÷×¢;Z@-e¢’0]Ê|-¯ ðÄò6þú ©C‰Á©xœªT)ÿl¦†ác¯ÅRÁLå*•ÎUgâ΋ºÐƒõIÙ±‰1sQµ‚ä,NË8cÜ ¨>HÜ>Œð„n¤ÃâÞ’ØFva˜WèG¡–IŸ3÷ŸnóR×`­ÓÒ¼0-†ÉV%¹|"EuuZ t¬‚}IVCÿ6éý3Ëwà¿©øßáƒø/'·‹’Å€¤—Û+oOÍ`nÃá’€€µÐûœíTfÛ]HÜŒ¹Hë€uÌ‹?Ìí±:Û6®_/kõ½©ç|´šQÇ{|nÊÂm½‚ œwä¡E4ø7ÓéxÁBŒ‹ø>ÛÉÞÉ mÜûدXƸÇ܇ìè=ÿ¬Mr„rt%n¢\ .oR,}@0L!›ït„Úð¹Œò<™Ë»&ù]“¹^’Rý´ÍöhW»hàý‰@•BŸ†'ìøÈïÓ(`iüŠíó[yáù}æi|ó•©@X\6<Á Â%†J„W1%:Œ‚ÄE“Ûª¾‰„£rðHS56Yúñ•,»"®P᥺jP¼æBýíöóu­¨Àt ,²‘dã LØÔ±‰1ÑÔ¸FÛ‡•µZ½~[vÃj£“‹À©¾ <óù³²©ºà,~ñÇôˆñ„Y(UE„¹Ž»õc­ƒÅ¿ºæ„f\g)´…ê ©ÐNI®˜fQ#u˜Žžo@ÁÅ Ú‚š‰£2xSü\n Ð+ôógÏA93ò„£½Z#zAr!–”L3E£€Î5n|·€e¤Ue—>´]0¤»òFŽä£Dò  ‹Ø8)eî[) _ûŸç …ü«ç~ˆ”…ïÓƒ¾s1®ê˜*+võMx™Ì®Ù·¡§!ʹµ|ˆÒ dÎûM CŒ „§vJÀ.ÑÛÃ`D*ß½Qí)W UÝÐË À㑎ð”^ŠËv–y»ÿeºAÉ˜Öæª`T$œœµ©Ï·d³60:‚úÜ»›/£+}8'@Ó'ÛŠy­Lò€y•‚‰± K›©ûV(ñ*ZË‘œ.Á%…³°ž§ÝΫB¦öþõKª„”²³5ÓËÌpþ­bÈ…¸¶ìº¥Þ¦ØqùeI°¯Àwq®jË©°8ò¥p2ð£jÆÊèö¤H!«ªƒFó:(¾Kl¯8^3êT× ]Ðl±Þ\ÿpÇZöxœL“•PëqkÑ! Só¤…0mî ¾bv jÀ¤M‹冹›ub·’„` ‘6zËͤ õ™™,ç;vJl(n*³è,^лcÐi0Ô®éW!,åLg”èzÿCtkÊnHvëc3÷ƒÚÉ.Û×#tW=¯Q¿¶ Už/‘-*•Å¡>¤­mÕCÖÔ-°­ÓÆRÀ€¿WrYw8èHo½¡’€€ .wÌŒOÊí²© ÷nþ {ˆ„÷Ð¥ÐdÀž}è¥B· .†é@G5"`j_âwQNÂÞÊΆÍ1^¬ç¦ú½å`a KGyÙ>üÅ?„l¥a2_‘Íè/D:çnÒ|-ÛO, ³ñ"ÀyÐ3#”ýËŽ ߬Zqü¡zç½ö?­P¹»É‚<¶FŠ`q,Î~Ày±ê©À¥¡Âé¸ H‡šM ŽâkÍ9øÎÅŽÌÁ©‹z"è‚ij‡üû8…_ÖsñMÅ0ìmÐKL{v»š¨-àHVGà¯pP’€5 £¹â‚Qíƒíõ;•䙋’Zî ÕÐÉŒ`'oI„”Àq<é“\*MÈ`† ¡0{LÅŠ¼›(þÀœw%Ž]³ñR±š އ¼Xn{Ÿ†ž1ܘËF>S‹€½(„•ì©/éþþzübÕ´î'õÉn‹»³RÝà…}ÜìVU³Nz¸\Œ›§VY9›½ ÷Ñ;p®õ9ôBo®‰D“@‡MxâÀ¨¾%—/ì.L}2žÖXj=h1Û0LŒ>_Î~%mzœŠ"£Ô1¨z·r ®†‚Ø5Îôw(€'fú?Ã!¼ÐžYÑ&žð2ž…K7¼n) ÐP×»"ÔE>ÂmŒv¬…+%Gߨn’€€·©Né¾ E¬wÕfqcVþ:÷(ó·ã®vªgœ>°údú%wØÛ©¡åÈ:ëŸ>/ç'¨•'Hzõù\®CijÄyèÎf8F†Eì$°îVƒ‚š«º|4¼~ï½ ãÛù®Ãˆ½ëf…žÙ*Ø?^}5×Á榪ǂÙ+ñö6ÅWë=;) s¨òÿûý<9L~J&ưŽl¸›uWoÔI1€Z5d•ƒNìßo‘l-°ìÑÝŒ-«È–ªƒp3ø*ˆ8~ðz,aÍLIg œ<& Àwc†¢% Œ‘e8f0Iò¢€š™ª¿|¼â©’cb Ó*àͰï9QÊeúq 6Í5]êyñûXv¢º—8·‘ {ܼþ«ôÓCëÖ¿. ˜¹Ù`ÌñC¹WÞ’ýÞøÓá$çtý’íC(Lã†xÿcô¤Ó =”èD(xoÁ±~Ôà‡}x[°ÒY­£—N»òç>„ L­a®Xi¬UB{Æä­Ck:¾Ü"ÄððàÙk7ó;v¿5Þ—ùOñX¾À¶ïªRp[Xl¸ü!ÜY»‰ ÈòŽUƒ@ñqmå2’ÇÙ5§ç"ëÚ'aöæ=;¯ÁÃ¥sÜÓ:ä`]ñŠuC}N2\."!U^.±‘pǜ찊dñü—„’aàÙ8®ç]³Âþ®u7 Ò„Õ =ötçÝc&­"W»§/JrL¶‚;Ê:Êê[}Sªݶª…ÄŽÊÇ ¯ÂÙ‰“¹V°‘ķÉ^úø³Ä>ZŒ¦¦g*½8;ãê†8’5®£ÊV”b8u0/‡ÆK!â–ÏEnª«ïcÿÑI°áS²P%ž¥{l2£HSf¢Øzhƒ?€‘‚/’öç6“„4Pè²’€€Ù¼­;ê-êl¶ÿÀwûp öO»€W’b`#_ëçÛargUW&|8›i +㛇ϩ²ñÖ¸<è Tö{zç6 üSí´…ñºY^;ûEQ­—#Aê5^•øS-e»?ÒÛõjÒSüohœ)‹~—t“‹TÎÁ2ƨÌç’¥Ò§Õúæ_ñ€ô×ñî™JÞçoô¥[ áñ ^Õ­H&TÓ*>QŽkð%$}óhDnN±ÈFv„YÉŒâÏ2Šö0÷à3©çÜ8S—ÖtÇêï«kþÃmÜ«Å0#¬7þîÄ)y®^2×ý|1cn‚ü±®—†ÿzå ¸O Z"­ÒbÕûê‘/²ùy+xÓŸ‹¯´émw=f+ …,Ø–|ôêàØEpóre]ö>9ÒåÅ»UÉ ½?·¤I/~yÀÑ>þ¿ÔjËÞÚÄv0köÀ&¤/¿ÚO£ù•ê»ÜiI•Žv°j~ÚP1¨$2ب(OšÍ˜’1Éé–v‰ÿ§Ô¿¤ÑÛãb‡@ÜÒ“ê?pV sá§ÆæÜȨ O,WÚ }w‘%ÊÂGŠ£3Lì¯ÅúÛ錘;ä´aÂw? S2_ÕáÐ Ê`‡åóAKÅ_I¤úN oÙ”>MÄæôQ2ò´L!öyPÖP€ý˜CÊ{pkåØÙù·é‘œ¥PXIlÍðI· ¥›fÙUJù#o^ús%„ä­áéX¹©5›byC;”Ø—#óž%XN¶/fšógeN©ôF%¡–7 W¨zÒ &CZ´iõ*ËYœ0µ6Ú!K« î!Qâ'¬ÅƒgíÛ“õžÔ Ý5BàrLíXAGRÝåYbä/¾ê¾âYv=ä³uBªs‹æKý°È={tÑiüNF=UŠ²Û¾àv§«:û¼&X‘“ibýkˆf%…)ѹ,W™Á¥2\üN Ü8ëIV—õË`ÑiHK¦z·ûU–h¢9…OùÕ=]è`ŽD˜Ðï&bóÚøä+J—Ö¶Õ¯ó_î•ý<353‹l²%ž L"X±V‰©²k`Ò䑞 Ž‰uDI™±s6€K'¢/íœþPùËdNI¥Kp/qÙŽµè¯û϶TèyQ˜š=½ÖA†Ìê#ÉïÈ›’€€Èyè|;9‡UDµØÈE1›£ „¬wvڂ帡ñÏî(“ã¨Àb‚‰Aià1cD¨¾ÁYà¢8j×/£™ óÐÿòòY­½›X¼ÝˆÞôÌÈX”˜ÀgæMVÄÓÿRrkÖ/4札ü…ÿž˜¦"-ªñÿ-…¤Ô:¯£?]‘6 B?Ÿ‚'Ðg¥=Äð!*Ú¢è?»™ ýÒõî¹(',cÎô€\¼®~Ÿ; »f™n#¿Damyr–M2Dë(xÀ ÍÜJJ•Øã3DŒ!áâk—EªAóºÖþ«ÿo ý q 7Žì2äPȶrRž·5j”jäš€Ñ ‚…ø —j]BeDAß–ßJw-ÎY?4r¯ŠË'­0ü³ z!8®tr?øWÕë¿°-¼QÚÒ`µ‚Ä­šé£%E‰´¡MÜTµë€é>Qüœ8UbåO\¡Øn[Ùé™ÑVï†>o¬/…œ÷ڲŠÂ˜”4z!ËêÄ ÁÆóºm¡fåC7ét}²)nÄW+²z©Îž¥|Ø…)‹Ïç–ëù…Ðq¢ÿó¬±~k¡ _Ÿ@J&’ «&‚wl1Äâ­xLQç¸Î€ÄAœdgO ?4Žq»¿åû%¢ªo_öG%Qv”̰T\¾‹g=·Ã·¾Ÿºw•C=ñ,4þ¨2®éèå_سêÙŸšMosÈÀÅ×oe=z×Í­B„â*æ]‡`¥žo“ß—t1yôš9& çÁ&Ù·€*r©««=ž[Ýutø±0ÄN­þ'S#¿ä°2ÂYýUð–f˜nKnK{zäpáÂsBª"NV®:É8Ð;žönÞ­L#nµ›*RÂØåñÎ]>`¦a#Hå­ Ÿ™qÕî^Þ9úW5ÝwNÞ^×’&UZ)õXd+%ß ¼DŠ„oο°1¤€2ñå¶ùzÕåWX»›ç1ӬȤb™èç*غ%Ýµß O¢¢™,AÚÀlR öjÉ4Ób;ÚaεfÌÝ=…¼¯þüe!’èhtä’€€Æy ‚¹ ¶zgÃß>/„ç`턚†]ªÞVD–æXà Uwû°œÙ` ½krH¸|)ÊCK(õ0Ž¿Ãˆj.}n"°ÿßnJwÏzß©Êé·`a{§~6Ó'9ùuÈæÁ5ó|h|b­¸º‹²’¼ POø n zÁЄŽÕüïòâÁ§í%ns¸eü߬¹š?òƒF¨3Þ`ðjùwÕwI6i CÅAÏ´og™)Ö¨#êÅe¢Ð7§”ï@iÈPñãHÀ†héh¿ß•)RUË‘ùHCë‹¶ò‘|I¼ÜFòl"x7¤±û”­>†,B“YxABa³’ €•Ñ Tƒ5áEŸ/8NÉÃ?Ī´Õ¡ò*è+Ík,G9B¤e)9]cýÃo“9•çt¤fQirx„¹JÖYê9»Dò‘Q:H¡ü¸ÝÿsµM#å·í[s<;VU-,VÍ j K² –Æ"pC€®TÈøèÁÊl1´œ‡€ ãÞ*ê^˜””$Übw,»²ŸB†í.mò0¨„™µ¶\j».ü1¯KÎ?«Ë‘ˆ¹ëÏi1u¦ŠDçH;OÒÔ¢ò:c1É »¼qý-wTfñL,uË*kµ ü1˜BŒò õ‚I% Ãú%N–8‡Ø†GÖÛ›ŒÔè¬;ሞå̪ú;È·"wÄí_aø"Ñ–œ- >ÞaE Û7Ù[²”2áN|¶ ½!U=vCpQ¯óQÓÞPßËà¦$<žÍ˜ê—œ …‡5è§:õ7‰GòÆè(• "Ã1Â.@CbdïòÓïPÃrÝ¡QRò°Û^õù³ê)ñÙ2á°ö*_1x rç‘‚“„'²egVÍES1öuÜ[Ö=Z©ER{Ç€NkAœ-ÆA·Ë}­ žŽàŸ VÀ¢».œísDWV Ÿò¹(3%“\–«x97èÖ#Aî‰ÇÅÂi‘E `&a€,µT@ËJˆðÐONò]ñ¾$ÝÝÐäNäüÂ.çÆDDЪ~_Ñ¥î´Ä‡µ2ŒiûfQ<Œ2`>ÊÈ9Â$JI£†uºdžý’Ë2ŒYÓŠlÝÐÄO½Ò†É"ºh®›Ï&Õúq9°L»~‰&—× s¯ù q/q¯„q¹… 9†©`øüÄ1d¢8yâŽÞ…œ†–‘èW§~(YS•G4öF½ Àš‚S×%ŒàD%»”1z{ÎG +à7Ói6 R²!æhýgVK0VÁ$d9¶˜ÀY• m)Duä Yl›¯Ép$Ü5 ¶É¼aõ7´ΣT«9 q—:†Ô¸X×s×…²oiˆ?. O,@¦]çÿGkÿó {ü"±Õ›¦µº¶Ï'4ëçÄUα¾k&g˜ç«z‡Äôaîò0µœkA~©/Ýçu©!1•)Ú̆!jðö*ÅÊÌV¾ ßÍF;|ãü'oDtäl n]û»ËeD•|æÎO»—ÿR‚Ùð½|‘pÄ´¾S{ë;µzôyþÆî"Ì =Þ¯¸ !ýäÉJz^ [Ú_‹ ÷\Á•%<ø›w„Wu<º˜øëe•Ó Ã`Jliº ’G¼j•GüZm=á×·íÙø[ç¡É3`Ô÷~g‡_çcÉnWzû"}Œ¨¬âXŸÛ_©øè ¯°ã¿€m½’IÚäŒù£çUñ³ÇjXúmŒZ¯µ¼ùòpwQpBˆºžV¬n’€€äÃÇVfêÕ²±¿,ß'z?B2=Ÿêù*Û¼Ž(ÎN XøÃ,‰Œ‘) ™‚×+G»X“ÿŸpܧ‰G¦­þ^ÞY 6ÛELÖ]ãžÎ8_Nƒ5'6!+ÑjþÃ;«fL­–;£ÊÀ—ði?>¼kñ‘¸…< P"x´TÙŸ' ¨ÓÂ@Q†üU N„¢«˜©«ßè¹"|öòëºÞÿiA>e»õ7©¸;`8Êý8]§wº—‚©õÖØ3Þ®VÕ<‡Í𲵟eRt{oÏ'´ˆä.íL­vaò¼™P¥ËŠcŠxeBÙŽv×Ù”—xú2¶Ô ªÓ v>¨ ?av9Œ,H, Žæ¸Wgr.)ÚuPê]æ‹5wf4w÷Ž!ÎqN¹«|Hͨ–AÖìËV c‡Œ´Â9¯€¥ÚÐ$㯄4í…*ø> È\Ÿ÷ØŒæææÆ|âµyàU 6¾X0ºº³šASâH«¶,mo4±ç¹{LPÑö‡LaÉÝo„çå Ú‰[€ô3'0_‰šðMHôq¤²T‹\!ƒóåú'Ö¯iÍI{Ù8®’ ,ø ÙyKò:} w^nÏÆeÔj">ûx[ð[Aw~êrFÙÞRÙxj­ Œ1¢G+ÞÈ£úw©'‘ÿê',~; ìý’²c¹vý“*pˉQÆB32ñ@ª~¿BÀnîMÇyÊi¿ äòws·D «PWIs½]β[´h¨Cûf°K çq±¹»<ïS¶.:•"4°tª[M> ïoo«4 o ” LgÔìÌ-Sxk~mn·ä×NÒ8tfV²€G!¥pÛbüµÂlBO’j‡ÚÖ?i¶? lj߅‚}=´2C‘ZõÒA+€á—IùyÊÖ²×ü%ÈNšH 69äÐès%f|Tu¯®¿žF>ÄöN›d,Ì/dˆy¸É¨ø„µTG8ËöHD¥Osê&¹­.—=À•H– p(¤÷Er´X퉂Êß'Âåg éšÓÕcÃþ \ä ê¹%âË9DR'†ÅïFAוé”Eg³ÑïB\Ñv‡Êþjè·åîKz9'ô{È!ì;zЖ.¤qÞËl¨Z‰’€€Èu…«O„s7ðÎt8çL ¼X ÍúéÒ®Ù›ôŽnÏkÆ>E¯“¡ú‰Ùät²¢7þ£ƒH¦ÄƒXJe%íV(á $3ƒvÿï'd‡ o¬Ï{¾¥âv-¡6ÖÎÁšÅyì‹Dx’_!dˆ$ÞÐm6'gÚ£ÿw/Ç·òbe(ÏÅ&ÛܰþÄdh xvål»RƒþÅDzIøAImÖjAÜÉ«TøN‹B†ÄVD“%tf±Àtʸ#a[÷*k™Ù¸¬ñ°ð‘Ož0º„¾LÚ¡’¢3#PNŽø1{²r¢9Qe§ˆèµ^µÉ^-ž$p£Ý@JuæUA… Ñd²Ã Ovµ ’R¨·-ÄóúÎÖUèÓˆ†Ö68t ûu°„¶È.SmÌ’ú¬goI1çWØ™4kÙHÙ÷u…‡|4LX[¸áw jJ||i”æðf°å·ú}ô?þö›¼\¿¤1°°=Õ¸ejh¬æÆŽMîl†ºu› Ì\¬vµóùSx7’»‹ú1h"ƒÌUÊÅ«kq ~+„é;QfÈ­Øì24ab,Š&ãÐMš—æ°@žRò8œ!2^t¼é®ÞŽå gòZèÑÀ¡ß}Žù>²Ú!#³ºP êÓioÔ—©–¯øó[q8û ;SP‚¶ñó •¸ì€0—nî‹vê|J{ìÕç·X|UecœnµšéÎóQö3¸Å½ŸMCZ¦Ÿ«ßœ×2®rfG¹¾6 þÀ„~·óÕý´´2ddlaRá™4žª iÓYK˜×N£#ê]Œz¾ñ= ½•.WÎ'h¿Fk€ ½ÖŒ<#R£Ó#µC~`Ó?ƒ|“  _{¯I[6Y†7iU¶u—m󏿿F†FéZÛàKä¬v‡1™^i€Ã-qˉ¤:ZñcsâMcW¾"ì3¦ÿ~WÊ;{Ë×’~Ú¤¡Ù©ˆSÌEÞ’4ÅÁ½ƒ>g+³ûŸ@-ö6L˜J'ï*ÂÕ¸§noM¨-•Ä’æˆ<ºàO—¸¹o6CÞ-ö¸Ü’!çŸ÷£Z‘Ñó¥Êb¨IGÑÐÎ׉³¯Ô“ÝîLóÊV£³ÅÅýÓœ`1|ùÊWõi±kH ü¡f¼l:c(×>ʯF¨~9óŠlz¿.Lÿi¦GÉUB‘Çr’€€È¡Y’4ìïIqè¨kõÌj‘Ûöœ(l-ÝÜeÂæŠkõRæ¡ÑŸ¡’SyòÛ†V„Ëõ™ÎªéÜ?îùY¦JŠ1´ºç£Ð^Þq”­`JÓ^FX>­ŽKÀ5ãsñù «¹)â‘ÔY…, “ÌÅ1rõËE2r ‹ÙüfГ:I ÃüÚ™­w¯:½4æÕÿP‘”i?@nnnžµ1Vf¤§M¢˜_X@ÉI‚H÷ÜœkúⓌ»žcÝÖ3Ûï»)ùÛ‹j&‡¬>˜HüÖ ©q÷1v¶N7B¼ ó¢Õ3¹Zç,¾Kö™4¹Õê5!=7wëe¾†æC“QŒM9Aa¦eÔCéO„´„‹µ“XW=}èa^ù•õCë䬦Ð×ö®¥Vs}gQd²ä9OåQá-™êåa}6ÇŒžwQòJZŸ¿zw/£‘Dn«X`eÒ„@ã7›¨Ñ ÂÀµÁSD³}DÖÕû¦eu“.ê)ÛégéÆ ¥J Ø^kPåä/1 ‡û ±ž§>ˆ¶ƒÕ´œ]©ðhħ°zíúQ|žÕåÀ d¤ÄEoYLžë$nCxH(xÜÇuœW,¿d7œø8æTq]~ {J<½æ5•BýøŠÓQl#ýLìÒKøû_o½iâj»™ ½¶X}‘{NêZJ&Z à±ú#%\®M«l0¸-éé0î ©xŸ/윉¤¤ƒÃÊIE“{Çñ6×–MS&v¤Z#@cB™]ÈÌrŬ$)þ µé©ýÝÂ3 »òÇâåÁlÅRþǰ"¾FÄÁû¯ˆ‡È“>€‡&¡wÕ5}ÿ~Û‚|DhVÚ²ªDÐÅD6ü‘å÷ÆÅÍU'å|Iþy€ÊI¤ö©×v$çê=_ƒá††_Í­Tã†8v8­h$ ÇÑrßû-¤L›ºÿù¥€*ˆhai2M H¬by[ø`­¸©™>éÆPƒiÌ)5áë‚4z‚jÃrcÅTÿäÎ/ݬÅ2&å ∳±‘?N\üÉGéjí–ÙÍŠÒ¶…Ï üìEf—®Yn¤Í`ÀF +ævüó5²H,ûweŒ ND]éñ®C¯„SYÇ1歷:ßSzµXX—æÞdÑ„=x]ö=l_-ø­Ÿë½Oå(tÓ 5 8=ÈÁÐXžÃò É Ï¬÷Ԟب€'Q3͉p’€€Õ ƒæÀ–ZoøEcà[6c1 Ñ'P×;â|ÀÌnÀª ­õGOÿ±‡0øî¯_ËÔ¨¡’ÄCøRºõݪ]Ÿ¶a Aª£áÒÞ| T}¯rxè"Tm5‰´Òmuƒâùž2UÁ™£žÈ„™?¸÷?‰µ 0n¬ŽNµ€©ÌטYbßEÃ@¦J=F»l¶»|6Ìõî»>T¢acs…¼þI¾…LjhÞ`L÷ð% zHÿ¡è¾\{XZFÕ¨÷4-”l rµ2Üó"OÏ.ó"‚^xå¢Ó-ý Nçð\²Åø·_ì´¤€a¨"Y¡Õ–±×•>ïûœÉï:_pdÉ~z~.\ñ|®Bû*&’øþ‹oFÍšÌ)6ÀzGüGSì˜Ä`ísÉ$%¨Õ£l$—]Ù»=; ÄŸÍ\W_öìÌlbØOé%ï€yåi]sÍ/ô7©ù:žêO’€€ÚÐ ‘Ajd] *ý·PX€rm. k+J\wÉK‹ô•í¯ 3f"›£!£Ú³«o|qä×Aò-ÉÁ¼Í%-Ùt$bæ*çç°RSpz–är™¦ÿ bÅ_YD èF RfSÿʆŒÉ¤é±¯Õ^ó ©ejw/ÈW²‚·²±d †< Z8âgÊ/a~‡ã6ZŸ÷¨u†Tej8¸Í?-x:k¦á‡âƒ —íØO€*ʲ÷oî;óPæ{IwÂ9l[û°]–ªRÝvNžqG¤m }¡´šÊ—VD@ȉ cr o}ÇBòaCØsë¬ òKB{/=p-¬¹3$‡§iU´/_9Љ–˜ÖAÜGåü³éVÃ,frò TeVorq :ÅCc/Ù;™GwžÖ«%–z¾kî9>dYæTáÕÁøòÔ®"ø+½–Êbe)ãÜ„qf2]høÁ8;ÆímJBs~hïºyÄÚù磊ÓhÊdî¡>À&ùÝAøyå ð[&ü‡HæXrlÓ8¡# /{Iuæ“U¯n(áX¥Ø\OJIÁ; ©JµO©Ož@X…j^õ†*Ù¦[ã»Í— a˜¹#;ÜìŸ0H¸] ¿Ÿ¾,_éúû>±xœzi<ERÚöÆBì¿ÝL —S5ŽhÒÚiOµ«O ïö¡á™øé+½JÙõÁyDß* «¶‡@ Îûã?j§(uÎæ•O)eÿ¨&ã„(>%N6Ë‘=è~¾²Óo9f«ÐÑô–Î%· Pê$Þzª#Q9œØâªçVw²ì1GM}Á5éâB+iÑ×m6` D Šßq]óX1T–SÓyÑBx©`ãáqàÎE7]!³-N¤%æ4ùñi~ĤŠuó¶X\–9Žm¾ú½ýnpgœ¿€ýÙ±µ=жÈS%žz¥gÄŠ¶J…sôûö”¦äØ{´uüò]¯ƒ¡HÏÆ ¾Œ©ÏƸiFëõL¥azm‡Ì¨†šÂÞþÝv™Õ¹ä?Q5²tÛŸþGÓøà \M/Ø“ q¾\Èþ¸vì!¥,$Ê_QÕÞê©Û wêfô‰îP’€€ž3cæ¾IðïAI ¬ô”Ã×BÃhi²×ãבHÖÚ¨æ¿ù½´tøkì‰ Ba7H#0%•¹32ùoJpôüý uùT/!üé9Aý®GÅ4ie žg¹Ä“]nŽje´•×Kð½ð¹spËÜ ,µV'{M(/h•”ä|\ S™ç^ã„l¥7Ja&ýt`êMÁíÂvNßD›8ŽÈì£cÛ[c•Û“e•kÅ¢5Š®ðŒ.”]\•p.4ûô?1ÿ|4FŒ`ŠC (Öã= Ðmžãuž®c(ØË#nnl£3£§µ±â®LhR )")ú.WéAeï©U°åE³©ypÔñ÷àRé4`–p.v*tÍ_ûj]XÏ”~ý&zs¥.‹šþŽ…‡Å4çñ >U, 7ÝwÐýÆÈxdtóaïç• Þâ•JÆF@†KÜÔ%ý3…nÃpû8ýRÚ´wŽBFs„§Æ‡™¢G(„{ó_Þ­RÎ(f[ ³ínQ=œ‰åöãµ%ª YßÖÙíbù¹`Ç ÆÖ†EôåÉ¿,Á{$,¬ÑhìKYÚµßÖÁúR0*¤m-æš½%ý¡Rλ1Ðp•1ô PL Ê ]éÈýÎç·Ë9|m…¤,…l4y‰úŒ$ðmEõkÍ÷„¨ÑLãò•L#VÞÑå_±µÝCâþU_g 8rõzW,y°|ÀûaÑ©KöÊÃaŠh¶A$%™>WŽú zül:\†]GgßV¤y’·zâ9¼fp ìŽV_þ¨oé~i/i+ËÁ±e8:>_z ·«Rpe_–p Æ$ÿ:G³«}@FÖ÷HÙ ÒýVP ¾]–i ¼":£o.q$샎t[³ÞEgyÅm™¤žëȘkñôÕ}+Z¨æ‹YþœŒPÿÄ -*U’€€¶›óJÛÕº´åXùe×cu6‚<íЙ6ýÇrG Ÿ©«Äÿ~GÇØPÀÜO©ïëXéL\×¶ÆËa«¿µƒqR7T wyT‹“Ö• ÎÿN3ŸW¬Û8™{¾YÖÐØÕ€¸ã<d|}¦¥©­1h¥„éÒ‹ÜÚíÏSe¾Mðúìc`À²e28)ø²DQF±J\<,®1Œ[¾¦‚+ ASQl¯x]gŽßb÷n=I¸O¬â>©àbuƒ^´«½žO„~U!͹yú£ÿdò4¯“½ v‡4?ä¼W«Mü$‡ehõÀ*¡®vS¤_UI{… ÷˜iµ}¹S¦~Ê‹9è½7Þ¬3ä„’qbè)ÿÑ lø½+›fdšGW~Õ®€m‡Îä¶ •ÇíxÃABb ÂMMÞÑxGPÜ«ºØÓÉx.ZŤœd,øøíZ 2Åôu·Í›¬ì­6FÁ7C˜¾à¨ÔÍ3Zc!¹š6:&o—%žâ8@#ñÝЇ^q/K]ø#OàgŽ:xðÇ'ñGÁ¼°‘§aЧõ¼"ðZCèÞܨ¸/¾ß„€«Yë«"¬fðŸ(÷âúQu]Ñ??Jtº Õýn‰ ƒo]ŸÔÃÖ&Þ¬gÓu›±€ï_;5tTyâð.ðô\,"‰†¬¤Mè ]ãA©X«%å 8ÊHŽŸ“üó* ±MŸ5,;Þu™ý DÇGd|¨?ebhmlqs¥„ŽÄü%”K6'>i"?F !–Äf‹ûRÙôXK÷8ѨeT½PµÆÐ-4M×¶i0O@Ñôë¸úæÄDÓðÚ9%éˆIéúÉvñc¹~›Á| ƒŽÎf°Œ·Ö9„îBÜíÝôBCÈ;oËå› „¿˜b2„ãý„:A¯t4Aw¶ pÂBe[F`ôyX-xÆvÈ—W?±G`t—ŸQiÛ)n” ¸™:¤X@UÒ%rÎÒpú%ìðÁ¾ìpUС—¥ÌtZ_w¶w}eöKƒy·ˆ$î³7Mâ ;T}”ÀRek‡÷¯˜Í¼ÇšßTÔãŽS x^A]›%>€O”†ñÜÓ=G÷ìå©]­ï(t¼*% Ë3w#´œf$œՂRn{QD´Tjõ¢Áú`i•¦ú(ÖCõ×Fál]3™6Z-Xe’€€ùžf~wxº ëíçaþe‘Œ æ}mCÅý ¼8§u÷í¬Aì%w3[–é3y9´)J¸|š*îû¾fÞ«k¨¯Þ¬“õ·–`s½€íÊfj×r™eàZhТyp¼?Åx€&)×Ä`p`I¡íS(ÿ¿&›¹LÓOÕìe‹Úí7x¹Æ (UÅvQ¦UÃGûÏäÙ›9ƒµ E‚9$Ÿ=Q¬xˆ®›} ÿ~×mæsõƒˆŽþ‰Ó­ÚR‰ã«µºùà×|MvÔ\äì>ù˜«§¡3à=¤xHë1À’¥yñ!£ÕTÔ´e?}èá ¢âˆÖ’.'gWb•·ÃXLK€ŒýÕCÄFþ6ÏçúÀL³$¸µ “â‚à ² ÂÿëÄ”<\Œ\‘ÍRÒ”‹%½Ì1—±EéxB†åÄ(!ý@¢ÿž©„»LŸ7šJ ¥3[]Ù“´éŒº ŠÚb,0ƒc]ô¾„Ë2­ÿÒ×j]ɇ±ÈµÂî>I¸‘vOhíû°Í–" ’nÿ‰2\ÍCçŽ×ƒ-]D𴤳3ûô—+L ‘ RÚ±œ8û¼æNìò¢R|Eþ Ë‘í³µ´Á…åAðíö>Zuʲ È·µ\¾™íޘˆ®¨<~D˜jŸx•xÓýç-Yþseî)2ô«èoTIÑg"j”J½›÷¯&˜-²A»œUÅÕ'#Ƙ,ç—+ŽG&äÁ1³Œ÷v¨"Ù¦/oêºBȸ[RypDBω0Z`žâá1Ì–ú£X)jDöw¥/9œ&9’Ѓ”6ÛIÛ®7áÂ'Õ@ûŽ01‡e 0v;÷¢ >‰6Û‰(ãC¯s´`ÎKËGC>OŽ⡦‹ßéÒÃtlâäšý‚ŽÐY½S½K~îü·Q¸¦—üéV™¬:êÊmÍ?ìã‰*{;lEð3-þVŽCAgõw1ÛÖøZ1ì%…+¥&'Wʃÿ æD_ÃEû‚&gßÀÞJM¿ÃyŒL—ÑL:Îm]ñ-VîÔ(æÏ% y±UÓãSLžû !Ȇ]¿¥‰‰­¤^æ1Eè¡0Á“Œ<¬ÞÒ8t%׿XãÓøØ0M´~Žš©ðÜÖ¡f@uÓÈØ¥ê¬éz…ÐìòßuܱíxO­Ö=ec>pý6„ÈV™ë†:¨ðU?7}Ä ¤ƒy¥‡í«+—ïè0âhp¿ùt3-öø €cût’Û¾Bˆ?X;ö×/ Íõ8Rþ¿©Ñ,¤2¼óÈ`$•¬õ¹„9®ÃÞ>­®î±—%È«øÆ 롱=¶ê'ûA(å]Ï^'ßlûôZì…ok÷¨2­ð¦VPAñâ Nƒ®¾‚ ¤¥7£*ÛÅо3ZŒN«·ð2+ÎNŒ^šqÆù¶>¼dùâ„U N=ç=º›d¼ÛWX_š»?\ê(ߣ—JX€ãÏnËÍ#MÔÅtúúùcÍ–çƒ]QAÆÂáÆuIX§*×£#ý唎%>ÉC£Jân¡*«Îáe‘]uÖSEk5àÏcÂÓ¸团š3ÑÜä\@¸Q¯¯‚n ËcÏNƒ™QR6]?ú‰`o/³œzÖÂ[r´°yʯHŽäÂz®¥úí1¨óübp°k>x¸>ƒWÌ ·m׃SÛpöÏŸ'ŠH°ÏfÝD ø5™(H2UV¶ÔÏõpT´¢9â}|ÀSVî}xJ"/‚ݤ+óØ \X€ÿ: ÷#8i×A¶¹,⚈ž#õ8wÆŒP`"ÄE^œ³âžÔ ¾N{ÁZɳ6¨ˆ¼Q…vÌ:Ö’€€û• æJ¤ªÑ¢­ÁóšµÇòæÁj„œ;‘¾ X™§Aû{õÌ‹0O¾vF]ô[Öj¢f•½ò«ÑÍ"Ó_ÀB£Ÿ©|#;ÔFWÑ1o3Â'áÆ£Sû:y„°aÈr3É…ç`ýöd볂Ú&®Ìy‡±»Õ…s€ V\ ‹Ésfp¸å5´éþÓ&)7°U¿æ…Ue˜ó«PãLpn`ÚpÌU+õ£Ñ‰þ~#ˆ‡ÖÇ>‹UËe_h29 =ìÈ!Ö $ØÐ÷'H=÷Í[ØÓSƒÜ‹‚ä3T[Öþ•à>ó7Wä rtIÑÒîCÿG‚S+õHë@#)™{1owÆ'‘É"¯ÄÒýòÚª1¿ª´ÖQ1öÒ¿·ˆwÈØ¡­Ð³h‹eůXb¯¥ñšÈüÒ[É|#4öQ+¥¿FÖ(`5n´|SkÅ“$êxÏÒ÷­‘KŒ uIÂç£ñÝM ’¼ÎTÊPÓ@¾=†Ž`¸Sïw©ÅÉrûúXåé¤ ¨ª’€€Ë(E©k“qƒ.–zë-‹œgI…,5¹Ç=íGl`S-ï 1Ÿ³<…ÿšîÎ9¦¹=mœ±å»¹krnã„ãQvŽ{×OÕ\ã Ñ–»Y¤¢LDY1Ð"QoJf!Ëf…ƒGއÝÙhúUuIlÉçšAÆn÷ŸÙ[uµ!ø+hÃÄÕv K œâÒ}ß[5Ô^þîµW¾ÞÃÒˆÌ{¾["œ=*\X&°vñ+õ!¥|Î.¿¾31,ÁD>(åtü-'‚ê"ÇÄî–®†öˆ2·²-¸ ÍïEsS<;Ü‚ Dµš¶§ÝÎÜõX¶ç×­TìªÁýÑÍñÃ22Jüv•ø¯Z³ŸÝxSÍ~ ѶÀ“éòhΓQP”7Oتs¬º4-­EwQãš d«ÒTó{úhL›»ÌɃ衲„ªRçÔÀ*ÉVS*†tŸígùávw‡Õ:éH׃0Ws¤rh ߣ’é+ÆüTcå—Tј&GOˬÇÙ–‹B9úÞgÎ^¥vÅUõsO‚ÌÔ¤r\¼·^²ÉiVÌìJW³²&ûÝ/ëhÅžª„ßÙM° fà³—D&úkË¿:ú»NçÔàc”²ÝV·VšP-˜õð“¼qÕ.€U|î ?‚xªºÆv ´Ü&ØLÞ1Ϩqo>»áþ†íë®Uò8Ü]êè^_7 àX^€lˆ”}ñ$”'¡ ŒšSk‰¦ƒž¶¼þ¿ì°Ï hö¢ŸÖa±.'ôí°¿ße€Îî3JŲÏaà '*¾ïÄþú % úœ.·!’Ô;“ÀFÏwsvnþ’?S%hã£àx~OÚɼÆwÎí{ˆqyŸ.xÛs3 ÑÅñ7µ=Žä Ä™ëYÐi^‹(ZPsU' ÎWÖäßÎè8ŸôŒ¢Puèº2߉ÊËr=‰Ñb›=ÉÕ¥\ÊÓ°Å<Å}/xaÐN\]Ì>ìehÉ™7Þt*õ:„Í©ÈZrv5_¹çÅM««L` >6°®îÇà¯Ölùgïù9¥õ-ˆ3Xs*œâ$–üNú“|„ÁÄÓ@™!ñƒ¾Ì¼2È5c?¤ÕÍ5Ïj‡Á¸q…ÏÜÒîÅ’€€èÜ8ìÇsGö„¯²nôÔ\òSmÍL~g4µ^Õ·pp¡yªÌ?ÓÙ0FàóUãÒ_Pqzf?~Ê;5ªtìdJÃ’y¦EäM‹~£ø7Âõ)=4T%º7L™tñL`BÆ›ãt³£zj`Yáy4Í HX­8ÍVfÅä[û””ëWžNánúÍ­(ÚB&–-cÖ>Š}½;?þûûJþnâ@GÔJ°!ªò6£%‘™ÇÉþ5é{Æ/¶ÇˆI›‡òqæ=h_Æ\ß‹A+ú²`ÈE¤PüJD •å£àmPö0h÷pº™>‹i™ßTД"­ƒ<å©L¬ QñLS¾ Å:PP1@'†Ä,k‡<| #¯Ñ3ºƒ©±k Ø…'Û ¯ ¹Ÿî(% œ …8“в*¼§Ü{#›Ÿ±Ö-‘ÜÄ›ÛA`lù°:È=,Aa=ŒQ•ñèM ÑP+‹M˸þ4YÚß‹Ç AH85°­Nú—ÚÝê’.`Êæ+IÙZ`œZ9ö6ÝãsØ”Êþƒãè,hÔS&U,êï¾ÒT™£¹CœU´Þe°uõÏ`ÓM\¸$Ѳ‡Y)4smO¨ÞÓ˜Xì%z‰]ãìMèj' ø/g_qõk™o³Ÿú&#|š³T²ÏŽMÐ=Ô­÷S1þµ1gÏ# gÏÏev0ìævi$õÇo{[俾‡½ìwˆ‚ß¼ý1 Ä[ƒÉs§5ÓÛ‘ ÛUùÈã‡Pˆ³ÆJ»»Y­fŸ±ñ-€l¢¹€ÜýÑ_‹§7ÙRZÛò¦jC4pP›íƒÕ:úú@ë®{–1¢F^v6̓w‰| AóŸèײ}ξ„m„’Ò¹QdÉörÆ ÓÂHWj®òÎÇÐüdŽÈ©Îò¹°*²ÿoŸY.l/[%%y˜“ò¸½M•Š<Ø Žt¦ã##ªqÊ)Ü%ê×Ã’¦Ô³Õø‡±&ÐGÏ8—xW&kqá¬$oBØ …# è ×^„ž„õ²“j¤«šð=fæùù™1ÈÀù 4ö V4΀œx›à ‘g'@+3àSØQÝî´Œøà\]ähÊô脒ѬӪ%RN¸¢e!žËâkŒ¡¼Ìnœâ‰i>믗’€€¬MãÕ~ü³–ô!¡Šå_ˆ Z”ƒ8ÊÓ›ÍÞÀЃ mAþ`–´£Ûwáïò"™ìjdàž6ÄGϧ­¶1! m-Ý%¦Ë%†Y–èïCÚpâ_$Pî|¡Ðî.ê/ÜùK›–?¦¢ó%c…\‚.o¸Ü.ù„i™›óT³ª§ &{ðŸÁÁ×Zsø3WÓòó0"eÝ(fÀü¿ Éme•Iɱ"•/b×¾anÕÈ;®¥bíp™ ©àÓ§H´:n„\&ˆu©×8#)Ö¤ïWr“q„hÛábÅ6u{]ÖЋuwû´Qœ(›“¸§º}'‰Á‹dÖe‡(Ø^Vž£KXžT>ˆcïEÍÙN™ƒh†{ÖPÓ½‰nÄ‹ÀÜÓå`¹ÉkM߀ÞFbp¤¿20ÇËU”á¬ï‚ææ@´Ž×ë…ØgÄe¦Ök³ù…öSMdÙBÓ~¿(Áœ¨Y±0R$1Ó1:½Ýè~¢«Ý<»â¸¡ü6_ÁlÏ­ Í$æ²?f 6ÝŠŒÑ\Z¤Ü~QS}‰ð‰blÀųÔDÃt6P­çê¨~îŠ `ë“ù‹zèðO{.Þ›˜óMð¼”¶Ÿ‰j&lZËz#FE6¥{ûl/ J‹bÔL¥}56 ÐY¼6{^1_d´p5Bžl]ØÛ3\t~`e?Ÿš¿ñÛà eb¿ Äe‘¾Á¦ªf‡(Å&¤.¬¢°µDΑ(K,œuR.ë!z…wÉÆLÚØ$L%ëò¾%ÿ´Jœ¹U·º3E‚H°ŒÙWG1‚A»‰–à^(xÔœè cb·£§kù–ßhöj}˜¸kóËg÷Ìýq:ÜYÊÿ!]ê rI (©y XìyöF ·è>İW0Ñ–>¿Ó½–ŸLóJŽF@Ô¹åÌÒ·T&*§XèÜX°Â± )îú–·þ¤žTâ‘ZYªþÚÝX ’©´êàÖD¶ÿ„õl%bæšÒ !ÛáòétY”•nÞ†2«ôº…Œµ/[÷£0ó˜T¹¯Š´04)ðí¿ãÑHœF`3K˜¬–Z?2jå<.%PJ*>®tL0ºSô†Dßéq i©zL+0$õŒE¬N<™šÒ¨½]IPáÂHí„ÔÁè…o¿åîæÌÈ,ý~’€€™ÔŒ)jà*iï@¡§)¼h”ßðØ5ŒËž&ª÷}ÆÛ|Y»4¥œéóJíëÙ||Šì~ Å¿Í.†–c¤0’Ñ驆2Üq‘ðO“Z?1¼Ù´3¨`\¡Ë9ÈB>xp è 5ÎDÒV¬GXgÈèl푺ãöå¬w6s[ß;"¡¿ç¤Ál#ªÈHXœ–ûi6õëÂ#ÎY ÎþüüíT”ê§~ƒÌü‚óSFF—6«¡`­V`IfoÐï¨`ïmû‰’Ãô ®]£™,—òLuE«l†Ž@lº n,ÛG×£{Ĉ¥ãS¿”|e((ÛWÓ¥Òª*s4¬cÊrJÃЙ¤’þwª6eÇ3–»¬¹E2’€»W\Ž`@@ xuzð±pxš(ËÇùR²G¦á&‹´»ö¦«š†ôÒ7ò¨±õ™/®Â(­D}c¼‚YƒSc:?'\ ¸"\‹0šÑ-9Éâæ±4=l«ONê’L¦¢X^ÀcPÊ1Ùû—°û[ë)÷sÕö¤ì3Kcá‡ÉU—=Â‘š• œT3' ‡á9ý·ù»‹RSJ©é¤1› ‘Y­‡ó¨y˜q…ÅXžç©Ù ÷t u¿®Äl%”i Ì؆’æ~úz½•0s (ç´ F Ýh™®óÑm‰Èè=¦lŒ'O½¯ëà•Dg,¤Ã³Üz‚׬åmæ@¾“=RNmFAæ´jp–ßPjKH½R"´›Ec™ Åè ’š-•eÅ÷ÓîÄjm(oÐ=F’ÇÄüL«ì {€¬Fê ñk<×7Fx ,D†¥¥€7êFÜ!Ä}-·YÔ›Å8ÆUÁý*‚ü.oà7¶C¹yÓ¾^öo­c5‹ˆ1'cœ\ÅUóq?rÞ‰Cëjòa]h„Šf/ZàìZÆÝ­Ô{B„™åÜ´ “ó1(ŸZä$ËÆ?ªöÿøPžEŒe?¡6“¿Áè¨1ru4uT*A«Ìl›æX¬ûòÿ‡þ¿Ã§_Ê“ 0¯è-ŽbÉfL«9ê ’oFú·ÍüÝ ̻Ú¨@z|ôj"ïRÓš4‘’DÅ A®Õ€™—úáú%j2â¹­Ç‚»ZÎ%L¾È˜Àüq%ºYß#Å,Øu:O‹è’€€ô :×2 þ O¼Þó‰¢#òo°¸¬1VÔؼ}Æ'•õÆO­”Ç”3MÖ!@%–sÅh½ïEÈ*ßËPÖm&×Tغ‘ó36%N©b1c~9¿#¨„õ{¨zªï‹!QuF¿~±îàH†q?M6ÝTziœp£Nò¢wÿâèÑcœdLq×@r‹\7‹F"ý?(¦Ïd4 .¤˜?b~O\{lç_´|Î „!¡ÖFb\Dç0 ¬u{bKeî…¬x÷€U«ÐdÅœJëðÌë·­OBŸÛ›ÚÅ}ÝGª<ÓÅ¡¦¢šz ¢Û3±V›îMf˜ h.`ºh_Â#ÕÅw±˜ô1çÏF¯4R7óÛ²oPn—™„?G™¹ÊþÀ÷h1ÎZÿ ý;“íq‚òÞä‘ü¿[‰™Ì±›).¡&Â{©ß ë@`A(m…l¨ï€º§mè9Té‹ @ŠÐp5ó( Ó¥6©`¼ÃÌS5«Xá™»ò‚4ø¹|ö'gOKß©Ó9…HÅÍ·ffæµjºKaÞ}iÆgÛpC…•Md1ÿ•&>dÌH8á÷/3‡ÙmÒoŸA6'ssN\ ‘üõêÐ÷äþlô0 ‹K ³ÁKG·åÙä~I?´GÞaŒ#8¢™¸0oàu´»~øGvH¹‘U _.èë”·'7®Ç¬ùA‹Òÿ²5Ñ7‚¼U,ÔzSË\Ú0}Û>êÉó%É%‘“[±›nñ°¸¯þnjšj‹V‰ù%½pÞ³'\¨lç¡,О†{š{)m>pW²bä/¼²{¬Ú —FŸ”£<Áùö”Ô,L²N »!5Zí¦xMSå>Wç~XŒCp¡P:p˜Êê¨b?þ0{fƾ­`@g›çÏ_—ªg’€€Íùé£b ÷ÖkhÜû£q"l*0pÊ/Ú Pa—-P¦ñÿsÇ{€¯Ây~$Œ%žãµ¥ÿv  K•µAÿêU­ãŠ»†¾úd Ñ\yÇñó¤ŸÍMG¯[5Ø+ÿ°Qo—«>£n[¾ôhU3”PÕÖ¨nh>E‚oTþ™+)·`CÅb¤éž­ÅbÅê{É_¨("zß"Ñ.šËÐQ“rˆôüÚ¨‚×y.¶Ó|Iãwâþ× >¡jT+-[Ý ,äÞçdå»D¾DO½à wˆä°êÍñq‚àÌÅôQy[²g ðùU'±Ý0Y: ùãISiÜ7Ÿ±AAXÃ:’­3„×–þßw?VÁaxv]"‚°Ý‰Ç;2Õί~1:ƒ~wÂC*@ÉÝô×V½Kî}+ ×Mí#Ö¤×ö,8Ÿ‡—Yæ×H +Üе½s± {7ø§Õù}Šw¼àŸÜ¼ÐÒôtLDã¤Â“´+¼?«mdú]]™YxmgTtª|;$‡ÈÿÎGºùS‘±ñk†êZ9íjŠAË /H‡!ÕRN/ÉÁ-ÑLRW#uk0´ôÄ*`&º°ôe=…[ÜDi4iÉwmY‚ßý.$¾T8džš¥x Ù¯$5–å›ÑŒ1üM:ÓÄH/ÕëJÖo±ÒEã÷„:ÊÖVú軑^ˆ¡"âøò¢´tJ²ôp~¤¦†K2¸ñ;Ñi“÷ë#­Õðäñmt²3~@ˆÕ7«•oØ‹Ü1=ò ÖLNaK—¨×ò‡BÓãÅÜ£,Ç¢GcRÌÚb䆔ïò`#¿ ñ½íà“¹ –ÑSY_Pþ* þÕëI~Y>ÈÛá¾'¬ÜÖra9Ç%¹fÛð =çUxO]óɲ7eÑ›éYò´†jÃ1ʾ×ÜAsÿ±Æ¯“µ£'¦SÃêë³Äþ{kìÝE.R‡ ¨í9 •€b† ø³Úp=tIoÝq5ìc%MAy×\’B°xí³$m ‡nXm„+Øš”ÜŒ`ó:Õ¾œ ‚w†¹I„C”ÜùÂ¥o‹© ¨»uvŸF1Ú«¸SäR½BÚþ¸ÖèSñžzˆ$‘Ÿ¢T £É艞Å#š}»xl\qøKÚ}8 È@¾vÞµJãŽi&’€€«m¢8ߨ/(ú9¤w¢n:ûI*PCºà¾ø)—ÉA» ‚£•CÙT°ã ­ûuþê4LÙC2U^Yî+7 £Ó@— οgqyH ÐÍÁ§QY’-¶=‰`úd޲óZO\Ì¢— «)×yég'J XöÎrt1UtÞv¢ƒ›fˆhë97_[}ê|nß¾š3œŽ¡çc‘r„ÀA*XÃQš¾âw?½k Â bÛܪÛÒÒ+¤ÚËx¯ñm…ÒâL¯m~×Ó a3°à,—9úõúhéhĤUŒ:/Ÿ}‰—¶ó‰yq-ÅH’óˆ£aÀCn{¬DÇuë¬=. m>R[2"þvÀ6fÖa_É¡…Bâ=§hIåÀݵÐéÎÑÃÒgŠæk§mú0™~е_·¬Z+££Œ‰r›Î¯R/´Á§°wo\7Ì9­†.,£†êÕz¤Y¢Õ’¯ ŒèƒíÔEaäÚíO82%› Ñ5†‹FÁ¹Š"Áo5ÂØ†ÝyØW‡ Ê.š¬£Òk^ô‘|4àJy£÷”÷ÔµÌ5Ñ1“…?PT¤E$YØt”‰ÉnJ®e™8ñ#‰XŽh’o—l¦ƒR]&Œªôÿþ°ÁÇŽÕEL÷¼ Æ»Qk ¹´ðöK¶6“Tíƒ`Ç2p®ˆÊ ÅèSDS\Êíã·1Õúâˆ}M5¶›èâ;i[sä?p¦Ñ¢ï+|Z¨ü’€€ÂzF©¡¯ì¾Ã:òoÂGið !D¡hw’ã·’d]WaÔ€¦?Í~Þe{Ö´|¨k I×¹Såμé/†@†O.0K{ÝÓµš]S­?{¿vCôßC ëj›Fžô àb¨ÀÉf5>ýØRqYq_Ñ®ªG’ãzñ’ÓR~(°†~Þ‚G„¤6XC#¨pXÝ=}Àp)Q·à.±ã°¤·Ãë4K…e•8·Dìƒq°ýꤡ ~~kĘù‡9}WøVZ=Ì[ ]“™m†Pª}+²/% l™lÀõX¬å9}þg£UÃÈÔZyÜ? rúyÑòÔ!¶S®<´à—VÖ³*&xP–ïaV°ÐMƒ€4 $¬ðü³Ÿÿ*i䂚NÓ/טPêëÓ¼¶KZ(M­k)o¸Õ·ÊÑIЗƒ¤›LÛZ y )â?¨šýkój– ÊàFˆ‘àÔšâïmæ¤DAix¡¤]#„ÒJý¹Ò¤ðû¸ÙÖX8f¤¹™å÷Œ‡™)›;—ûõ1Щß8øøyã°¹Þ¶>VY{t J.koNc½¿²½‹Y¸)güâÚ J¯… C—&‘çï´&(ˆtU%h™G  ÄRCÔ:\—âÙ‡B:þy18€ãö¤uþ™¦å×NÙ"Ó*p &‰DÏœÁ5zJ®, ]ÁMÐ$ïl E; 4ìðº ðŸ\ý‡FÃ"Ž~yrcÆr«¾„~±¼‹Õ¨âËÞ@b*i…Õ6ûmÑö0玸²QhV˜üG„@CyŒsfùøkäx±X0“£ä’ü…f+ÉÛ(ѧԷ(¥* [KÐÛ ÅîEdD2qˆ< ×÷ËP8¼r4ˆAz{âaò'é$ôª2øK­apÔýl ô=+¼eâ"k¢ü5>½ÈR=²<©^íOð8Õ ÊèxJ‹ R¨¶ÆÄx”ôÿ„ë1ô]óÎÕØ·„»Q+ŸH}XËPFا‘ÄšŸZ ­˜ØÿÖP®„j7¥Ë >+|¯¹»ÓæhñÇYÄày9Ê@CþU°-ÌE¨øÅS•½áYàã äºt¹UĺTÔy³S¬T·9gÊAkøy¶N»þ¥÷fWQi¢Ž« ë§¥Ú0Ü’€€ðgÞÚku)öTõ´æ„þ”˜çǵÅa‘„:`µÖŸZO¶è_éEj®Pïbö½bPûâ6ØF)Ñ#=ƒÃ!dvPU¿^>W"ôÑW-ká)¡³£]´0UÕeVKª:ÜÑ­¸æ<{xÁÏ#³ßpØwYy^óŠ–äD&˜Ìàz†÷¾‡¢FƒuWÌðhìmå–­a‡°‚œ„û7Ü*2ÈÈ¥%®´@Ò¦FÜÅ 1¢Ž$°Ð³Iãq _O'Öá±Ëí˜Ú¸¹‡ìmôˆþaÔâ¥fЦçО˜”.‹§X»}幋àù!ä«2Õ¹ëСæþͳoXpê¹—kâñí^<¡xQ/Öº¿WfC„\Ý¯à†—6} çj K¯„¶$wdë}˜a €Úz¬½kà9`XÀB’€€µõê-M”yÓoª ¢v>¿›ñ\Å[þŠk¸dIÎ:mðwáZÓ3©’=ÙxŒ8Ö¬á}sVÕ=<º­üO L¯ÖâÃ)8ŒíLær©Šì"¾Ïz×"ý;ÿn2l›|Š&cÄñ×f„9F‚DŒNÉ^¨î¥šuL>Î[ÝAðŽE*è}‘tá—‰J9u/%̸Ä~å¢^¾š[¿Là ©%Y®-¹×7©ãCðyò„žÅ­ îÊYLu‡lòv×3H[<¯_Ÿí[Dy+°OÄX£­ëóNBG)’4Ö¡àDeýÅ=!Éï^Ùâù?´æÛê¬ ÎâÜ· xímN}­¡&Ô@ïhõ´ ²ì?;^mxVYÀÈÕ†ëÜþ+wú2xÓ°VcÞ©SÔcÕ¾¬%ôãÙ¢ó”ÑÉkkP,ãô/¡§^dîÏJ˜ª–ýâîZ_áŠ+ª´Ì`fÏ!òi¿B–ùç^á' õULع!\ñ{½ba΋òqð,sšµ >%|àªßBbY)ì!G·XÀ ï<#¿VfG䊇æšohÆu‰¦ ËWS_§†ôæ=>uld†ÑÊ\®)…¤Ú©é•#§-!@:Ò'$‹Å0Xö?òbpöù⎲¢® ð¹Ó}†öªÕEݾ85« 7¤sÅÚÏÙ.à ‰&´¡£1võMnÄ´=Ú•ƒ9Þ†ÎÌm#”ÜêE§už"kÆ_Ëöp[}±Á­oXøL|Õ ž)ÜkUbQˆ‰²/™š²GkmGWÑo€l‘JƒÖÖèhëãORDb¹a’¦S¨+Ò5ÒSìDž‘ߌžJ¦½™(¤M¼ ¡£eœRSF‰30Ãå[ýîÛeÆÁÞ,>!^~um‰>ù…cÛ?/S  gn –¿N‚¡Ê9'9È08ª:Zè _L›X“ÖwhM<ðøøs¡m£2½[‹Äê5}=RE¹\’bšf$X“Q˜9+ J©¢ÝذÔý¨C ¢}|¬èS[ã7R7À9((¡–é)X?¸ø‡QàÍ!TÏV•ä£ÚûgåB›Cºƒh¡ÿ^>nƒu¨JÓ—X-½Rë9¡O8 †‚8ydæÐ—‹¨Ÿléÿ¤9íJŸb’&’€€Ö&ÁMŠ5ÉHæÀ…Kïõm'BPDÁIIa!Kˆ}˜u¬7k¢ðæ|…Tm:Á˜p~#øA ‚‹,ÞXцÎÕˆ› Ok“H¯ Ðů>èzaÌæM7àýÃxã¡…vñB'Ϭ}5ødm†¬L8—û†ê­5‹CªåÍg;«£åAtшb >C0(+–޳›1W«ZÎô#ǶŒ0CP:É’ŠSXçÏÀ3L¤/ØféÌkù¿,©÷Ê$™Ó@KüM]2Cåµ >¨¼Y´ˆ}˜Pð{C#5ã¨Ô¢ãÀ,×¾)ñ>¨£œ0Æt‚¢¥eRр͒æx¦ó8©”n¬«ì»ÚoTö-:ð’ÚV§Å׊3þ8 D†Ð¦Öõâ-øˆÓ«–(@¼|–Ó™j1à4¬ÌM@°¼ùÐÜÏ@WP~rFSAÖ¼bë•yftlßM5¡åe†•ám*ê§ë>’¯¦TX¿½ˆT ÅD½{r¿:*cs'YšÈÿ¯Òœæ0Ø?Ý“³|'£ äñ·ÈÊ%äÐAΪÙ·¤ž™wWÄ]Šð7¢Èìs6DÑÒ\O¹;=º°¸PE¬t!`KY÷Æ:U³ß»ï›ß[¶üÖ¿} TõòZVf ò˜ìÖjÚ ËÌmð ÉgÏaûð? áÖRäňM%§ÙTöÛ@yr ~]¿4U\”ýôâ7&Ôfg.:Kd” ÕPûŽÑÄ…c(6hØÈC(Niòû‰Ñê6¡³æu7뙩ŽÒt™-Iêrv`Ït¿%Þ`¹VÖ¡o8üü0Ôa‡Q)‡u(Žóã{ÿ=Z*·Ùš\š*¯¿ãÍœVa @â›06bnBf=ç·ï)J;€ïwÀviã¯aÁ˜h?ÅÊÙ \¼|Ô½×z"“ dðÐà ôºä_íMYˆ=«×:wÔ_èà\é=òºüÙ´àèÓ«4â‘o·ñó&gv!‘ŸI¾ëФ&Î Ù¥°(`üFEÞ2ñ匈A…Y3ͬQ[ŸfvµPÇ©î`OgŽÕçÈtŽ›Ôž‹C9g÷TÊ4ª2Ø0¡©x•ù»†¨n’=ø¿"Ón÷£ÁÚZ?éßJ9›<çû±ui6é6KPÆíZg•=xö=î•’Rä [£ÿxM ª [œ­’€€¦ÃH£…ß­9’¯;¾ªPú} œØ&A½3»«r⸉\ß ºïU•*¥ïèðš$ƒ†ÁÉ.ŠfŽ+áŒÙõ‘£ø*…z‹lÃ3.ò•êg8o²UâÑ6«™Î¥Dö¯ˆ¤T+¶Ë¹åÚðŠ{U#0«Ág ®±Ûth§;ßz¾lŸ(ŠÈ³Wsv²ˆ‘ÁX4ãL÷É{µ-“¢%± Ý$ÙÈL`pK¹ºüø«»ç¤n5i–c©_1SY%|$dŒåèô^.õ²ùÔ~µ÷kµ2x¡ÞËOy­Aw8±À(äbz`Eçð×_yyNj¸ñº¾K1Pû48yéÝŸŒùí•Ýw^ªìÐ ZwŠEv‡¸'ô™Œé'ä¹dŒZy7›²Ù­©¹o6[²ñQ06·…ÂÊ: f—ÚH •_Yl‚ªæYÔ9³±+¨”b¤¤,äA.åìwÈZ2m°ÂžÑ|›×AÃ×ä"€ÐwVH–àëE>q%AôÛQ÷‰®@ Y›TgËÓíw’ù@ÿÂàëê­#ñy^žšéôž×2ÏðÏ ¥›Ìæ×Ë{H!~¼1 á8 ýÄÚëx²ˆ´å'lW2§H>=DŒËTSùÅצÖ„X¨²O ÈAÌUÅ2È˶NªëïÿÓ?·§ œØ™®)Tžš!þa¶¢Ì¡sÐàHE" ê½yë•ùÃy«_R€oý’O4Ágxù45ý˜Îöâæ:ïzþê4@šTIýÑ»±â×ëNF¤}$ñ ~±[ùÌê6Ì#ŠE{*Ê€h‘”«±Ž<]óðˆ•¦‘Úh°6DZvó­€0>á·{„¿kUTñË…jöü³þsçNqùøÄ®:Ÿ»õ̶¬½ë†OÉh¸­Ý|Ÿü4T8f¾P”)t»°›£WÐ$½"“²·°&ᯱâíð3ú)_ùjUÏÑ_¥šËú‘)·ã<²€2q¹†3ö ”.|©$‘,M8ÍkM^×àÛoó¼ßiÊ\Wˆw™à`0݃œ³ýýaŸžoQ—ÌýÎ/*¤¼v?žDmàÊO;æŠP½Å-–“¡ÅÖ¬Z™Ñsnóñ_xiÆIÐ3$È8‚ý†$ÁoÍÞb°7Ÿ ÃqWq<ÎCtMpž±–æÅý~X3U¯XŠ8D”3FeRx]1ÐyÞ±‹JÂÕ+Ù¨ø®*HŽsÏ<Æ­±œ·vê°²1 ¥LSýy]ϳNî;…hSø×Ç»¶W¤‹ÇYKÉÚ>ÁnG‰™…óL$õ±hø›l}éKª.=Û¯õx÷â²HgÊ3æ_rntÒ-b›ëªW`Êà)Iˆ#g>Û:$òH²j¬ÍVE”J"_xtÚ§–ŸÝׂ9 ‘G—F´Ó‚Ü ‹Q€ƒâ¤/ïòÄ—FB·xkÌ‚øOø|B¯é0ö « øc ]I_wüi—އeu)üþ„ƒÿ•’íÍÎDL…ÈšP…«á'ðÄ_ôa{À`<¬±¤>#ü@sí[j±qêåî¹ué;üŠO‚ÆZÇs“ÜqoŒ0ý F¯•¼gò3UTG-BtX ¡g>pÜiv©I) ÌAÜkð˜S=jh½PÀªUßæJ-¹Øáf]Îä³+Á,qcÂ&Ö…úô¢ \bùóâuÉö;›2%Œ%óJ<Ž­ôÍtÃ8®ìC—ÞLFûA:ж¦ŸdO}£UÚÆ%QÐü–> ºÆüÈjP­}Ÿ¥eCíDz»cã§Ÿ*m^Øá"YÊìm3Å…S\ iV ôñSt–I…Z~™·¡uQœ~|:*bmÒž€ˇÿbtºõCßÃiñ\ՌՓn‚ÑuÎÖso!ø†ö¹¢óÏ¢)c‹Øóbüv*ˆ´Ï€Ízõâ9L41…[%­‘¯Jd-"ŒZ„Õ»S_Tþb¦BÁ›»N4#­ fØ·ìÙU¬EfFKÞ|´‚åLÿ%x¶"á!¡ G¢ë«½8u²ÿ¸$é;¾QÿiHŽ£•»XkùIi¢ÜßÔÞeð´;RA¾+ÿƉ)­­9c4Û´²ÆÖß™ù&”ò¡|îOÛ¿Ëî]î:çÆV•"ûJ&8¡¹v7.ƒYû_çÏ-0EDDx@¶¿˜>mǦ¢‰—÷=qq“„r¯¹,šÒáöwaÞÅA=¼‡Œ¡÷/Yˆ …žÕGòû’€€­ æ¹4g&ÊüúObÂEÍ“h/T¸¹êF,"»ß²G(ØÊs°x8vx>H1j(qp&Ô€U[ÆÀÐ10‚ÄÈ5½†ËiÂãJ#ÞÃ&¥1½1š¤-ò+ ¢;>ù‰lÌÿ~RƒH%y[0žˆe&•Þ¨‚ ƒvÜ=<˜ÞÏO0÷~;q„ÍX!ÉìRU‘¥r³ÑRì3ÎÉE:„ªfS™|„”ÄèÞ¢‚›C é œ%Â?:ýËy2è‹ÙSjl®³b)ƒjÄ*ÚÆÊË^ÑòÔÚ©ýt[̤ug•t½#§d´%óC2{½så oê¢@7þ­‘HNØõ…=ûövX….€¾í-2Ørâ)9¿`áÕ«ƒÃ§~qVnð ß“JÿZƒAäÖ³§àËÏ(xYßÚ1¿ÏÇápåJx„£k‘?—iÚ¦6º•º8âê]­Ò–áDº8¥Ÿ9Ëœ›v?üâ=˜z€³,V$ýynÃT·gèã¤\o $¬í(JãéA7E\xL?8¯:á¿|Jã/w>öñÌyPˆ®5κZ³-å’­˜¼½H²iÆŠ¦N:«ºÊÛ`Ç3ò”.X„È`]ÖãQYªQAw8U=,6¹(äà©þ˜¤9¯÷IÀ³Ý#¯aÁŽ¥¡‰¿æüèÿ¡×¡rµ§Fäo10È1öYGÐýÛìÙíò;¸a]ÕÍsØ_Ë´©‡“gÜ|±ÿá‹-³y.?[À’Nã)ú¬ô",°&‚ЩƒÞðüÈv£ì Ï•xÿa#CGc ¼ÏLöLí4ùá­h}e ÈaWDeuòðB§'º.=”1dùb«‡Xv‹ÏMAôQ—Õ€cÓ¾±1\É`BPÇæ„«*MÏó¹-WÙ0œ>^âÔà¶$Ýú/,cÎx4EùÏ[Úýñø2ív‹‰t'b`ËTŸï¦/í’A¤ ^¤'æÔa~ý" ìý' Ç‰lVä³X@G%Át䬬ôK½yä¥âÚ‰Cõß½ˆgZ¦kó0?›©OècÑctq^J!Ãj×ô¡¾¬e†)69°dVùë­Î:z“î :F„j9D/”c_'`|]ö [S?’’>I¬¼M<«’€€É‹Õbð âëâõ¼T ,ïj}ÓœHÁõ2ÖÞÛ8¥YŸdty¹žcá:œ/ÕQ6cû=[dÖtEXN¢˜ŠJÃÊ#Û·!teUðü•¼… ÖXjP2':³ÿϱ¸—yÁLfeiôã5eêa’#â¨ÍAö6Ô½€®"ºÍlmÚ&źr[§Û–Ðý‘ã{ÿH(rMÌš‚r{[6(4ØzEÞmñ\¢0åo  X[â°DùÛ|˪økÔ]lšVö3 ã¿ñy°‚¦¬É!~Û¯„§3ÍO÷²Åh}{ŠYeY½r³˜õím¤ì[¨b²ûv03ÆÀa‡¡)»ë­Ï1Œ0Û¯Ý0\™w5éW!Âs¥ÑÁ÷÷2)# Ñ—!¾§U{RõNmŽðS~à4²±h^à¯£¿b‰‡ø‰ªgجbòb~=} aÊba‡ýµ˜#’ë|l¢e}¨ºO—éL1¡"P÷ þ¾Çè2w-cVF¶ñ¨ FiÔI’¢sR³^Ħ ÿÌæ¬Íg¿À›MÁøÐ^:"åO…¸-±Â© #¼”iS'¸¥a.ö‚‹@v»Iûîì6Í9¼ølÒ÷åËù^ÕÁ±“«OVkÚXêÛ™ÕÀÈÏÝÎYÄÊ»}¨MýL¤¬z½ýIo{;æ·IS´P± É%|i¥Z€.ü³ë2ö4N tpZî¡Ï]ü–ÝÒZ'äÆ"ìC"n…ƒÄ¥¯H–Ì6¸Nº{Ê„ZÐnðÕä¶óª´[MÜ„!”×¢"šPxÑlq+ÒÀU›rM? Q¾þžÜ¾þÌ·ØXz/#'Ân^zêV'‚«"†T¥î+l?³ˆøT™wà¥2“|¿Ú š÷-±@T£ 5óº• ño[Çý…n-—ø¯~ ‹ôî5¦by¡YGîlmÌ¥Ò\—U‘ <écïBÉÐ’F'lûÂAóxA¨¡iT2ENT¡ÅÈ{½àpÛLw Lšj-Ôwæí£'wÚÒäƒí¯GŽ AȦš’€€Ãƒ»)mcy£¥%¼ÂQ]øÑÛMX}œ»q¡Ÿ“ø;ºEš ¾Ô„¬E}˜¨ê4ŽäàϽ4@OY8‹ýDNîý;Sî8Åç·‹soHÝ»ÍÏ¿4Dø×^1¶)ÆÑýDçc¬¸Õ“”xN÷#MkÎã~èWçÁ6JÜÆqÀ¤Z"î$cI× ´2­¹ –5ð—-Ù{ûž}€‹žU yF’7;׸4 ž£Û cW ÖhPp’±öùZ€9üרüŒš×ëî_,ó•cfΣp:W’¾‚«e¯'MÃ-·Ðµ‰TÑ'¸6øC?cˆÍMy Ú–Õ)†¿©£k¥Y‚§¬U™xÅbºØy XLCÉë¿߅KÀ3gÈS”<Ôc3 SÍE‘„±a¢£N§ÇL÷~ÐÔìÙÚÐ25Þ'W°`ïgµoöúÎßsÁ‘ɹ¼´ue7)²ÔmІɗe}?¹šºrÀê:³ÚG÷D/ó ­¼œ÷$ðÉ9q$QŦ>LP‚Ðe³ûL}Y–Æ-BdTA™ZT¼ÔœmióUàw-€"¦¬³/‘ÎM¸.¤_ l6ËŸ’a¶‘µr? G~Gïsu¢]mICCÛ6MÀW©*ðsÚ£ªê~™ ¸¦ø]Ô„~dytV¬*AÍ“ ’±Ím 8&˜±6Ï´ã£mïÃ1x5õOÌ빬c(‹¤h“.j]$Ö¡ãLÛ°¥èFŸŸFÎè5,¸¾Õ÷Û@ 4$ ¢¶¡GbI¦þÙå¹ýõøeˆ0Õ"¸ó/FCbÐ7ô,õÑ£(­è-b¥{Ë‹\‰wû#QyÔ}a'ŸX¸ô{Gƒ0:ôèCmF‚>l ÆÕžðS ;ƒKov`:^ƒòðR yo! Ƶdø(ÄòFž•$ÒÖØQ/ÿü¥ -~!hÓ‘3{b’$Xª¬m/’€€Cf$œÈH±ÙȰ/vqªoe\³a7£xü‚Ò*Ñj/.lÀ_r|éÆûFõfï9ÇŠ½Ó®JacòåÜ<ó¢1I-½«vf—‡fin£‹N»Àï²úÌX ¦SL3ØBD-tQì©M!ÜyuZPì‹~u?Iƒ ÿòÐ9÷–¼Â«*Ó´‰®²; 'ÎèøÚ¿=8ŸV#I€˜ŒwRæCJ¤n¨¬]§D°¡ævgŸ²Éà’¨,½=BèƒÔEÆVÅe§;_3Á¹å”ˆ=Q””µ#"#ù\2íC„·¹,îúÎèùÜ;úÞ ­Bøü®% Ð Ù­³B˜D)ÌÊÙ1ñ‚bTýý&*pF²Ý‹N€¤&\Ê­åÐÀ+”Ûøm0º„¨•þø¤-ó~!›Â›/búQÈ,ðBª0àÜq™gY5ÚÛŽß<*{• T1éÈTäîºóŸ$ÊÙõ/§ìƒ¥äÓ–MÀU ÿi:-D‚®8—÷A@U®”nFÒƒ U´Ò‘Ïs8að‘£$ÔñÃñWãG;Ùœ¬•3þÚwÀ¦µ±zÎi·T9—¼ï©mþE¤ÂƒÖ¡aÒ¢ŽsîÏlßËx3¼ù¾¬_§è•¾g³b(d_¶ÅX¨Ná³ hC6ž[‰H.çP›~/êÉÎ!Ýɵ3tÏl¦en… }¯ ³É½ÎqG]ÿ% C%Ø|鼈(%ÙÅgd)Æû… ]~ ®upæâêd€5¥¼‹HãDÎ4PµÂ¢.Þ’Û.H­6;‡æäpFN¶òÉ(¯º1§’Åhyâ|Û§ Šæ«"«˜{œÔ6l+ ¥`^ JLý§ÿOfî[&º‘3÷}§cÍ!?6| § hÚ”´®ÿ þ¦ÍR˜Ê ¦ï´÷z½NŠš”NûF“¶DÐ(ÌI Ñ é2µ,AÎGiÈ ¯J~žØÈ÷xø†Z‚ì¨d&«’€€ç‰K³ïyÎmû7"ü*Ã…™$ú¨;¢Ž‘,Ë @^|Ê{:„@,Æøö)$Èx;†_AÝ›Jj^Û5¿„^v ÌúPÛÄþ§¢"Â5Øå‚^0Ôÿ5¥MV—wÛ¾%‘4ÄcL¹NËljÓ™.ßÚtGçXÅ´Þ2æºÁnçcÕµL»ý ø+WrÕ‹þ¹BßVq¡ä¡À(ÝY_áôo²ƒ´þëÅÎÞÆ¥‚:·º‚í ·Á¨qG.Ðo›sÒ~ËM¸ »xÅáíäw©ª2¯AƒqaÍ›>ƒ”NlQ*ý±ßÄå$àr’z¡-°‘Î~+öÄŽ ir\£24¹““±6 S¥l3î®<à)HºÁh°µE[ÏNýèÖO¯¬^JL8±D—àjÒéêÖ¸ïr— 5 (Óè*ÄÑ…Wª+-bòj.§ëCC)Bœ‹ @ZÈ•«äpfSkù¾|aozÕÂ<¡3óN¹÷³ÆÃØ¥ïJ¦P`\1c¨8¥ðŽ<M–ú*Ÿ¡Q_ ·þ8asÍuDî岓c¬k2ô2H‹‰¢\ìîücv¤ˆ4;öŒ1«æÁðCåòYõ‚îàd¥¿Z°û¡¾£Á§Ò»Œ{ßìi'â/Úca™R’á1ÃïKmÈ8d¬Óò®¨wÅ—†Ì²Ð—ÄQ/Íš 7{~ÒíÂúØ#¡¼—_¯as••ÑîRéã2MüIÊsª2ý».Bó¼Uøn6YN~,‹’‚Ò…­At‰öæ èEèeÅaÈ¡—­—UÈèö´º÷ˆ ‹ˆøš¬hJ0WåÙÊO2Ç@N5óÜÚ¥ö¾Æ`iÇXÈϯѯ¹¬$§ÃgU« PþÜÉ›Ù,ì?ªrý]xy×>±¸l)· óµ'‹ó÷›KÒ³‹Ö«â…ºX¦i¿ùv~Žà9zëÌžjÏFcákà±FÛ¨5:,Ô—€¯Žú˜Æ\)¬Õã|·OqmsÄíw#ª¶šÂÚ´…¯ŽX]šòb±äÜŸ*™¸v‘ÝÏ]æ¼ix9ã*ÿBÎð#)þÓðäpÞâÿ…@ÿP§`6ØÕ¥ôæÊÿD…ݬp×ü IµBm2[’¨QÈn(fžóNošÃýÔ¾_¹O±ÀîåŒàÅŸ“ÝP¿J+§BÇç³ÆAá¾b«#˜@°é rL„ÌÂ’´ò(þg{›ZR®E¶çM±ÏÐëIË6žâ;îYáßà}d…ŽÊ~ßËîçD<¤ãuý¿R¾_…û™b¸ÎO/\SÑ+1ÙÑàmô:™,ouZ¿L{_Ô=_ea|ãÙ[EóÜ5!³®'\¢G¨¥±a5Ò]âKá&s¡2 †»3Øâµ*c* ]†)Çgi\bZ­8«]mbHß¶í#8²d9¡Ëí<6í¤Ýúj)îì]O‡DRÕö/IÕ´ÕB`7ç8Ü\*Óè‰Õ§þÓ3.'·m!œ”pVßl{+\Ž»ê¹ ”¨’» (O ±œ&u†ÈíÅz-©ô˜ù‡ôRÔBÄÎÒ¾ÿÜ›O’€€Ù‘„\ªòtµm?•\­ýz-4¬HîIõ/nRo¬-8Ÿ—ƒ'Bmc¢ݘèvË“ltoðú¬‚KÃ~"I>PÝ7+¸w?ìc®†òsÊÁо`LtYî=V] ôPq»…Qy)ZÕ`S(¤*™î´ŽJ¦‘Ú‰A 5úëYço‘êÁ5è Pmç1˜²Í݈Ô|CÖ-2‡ô)ÆO¸¥æÉ¬¡#™¡uEaC[>5¢ÿ ,Ü}C9^Ãþ+¬ô‰TÒœöÝ®›×'™nUüG¤,ÿ óÉßó(´r ¯ªD„Ëdå իسp~*ƒ!ÉΊåqÍÜv6ùÖA¹Edut³ïÍ~(Þ]avÏzó$$ÌŠD”ù;œ…ÊÍfFñ@‰¿¹qt”Ti[»X>@R–àï†/zŽÄ3N8QNÑrÓhòWJmÉÀ§7õÌ™}RUp½¤G{ú|“^ü:²®#kâkÙc2ˆ¬ÿ&mn+§”m" Ž¸Ç’Ïb¬’€€½twdb€eð1P–^búô¸˜ XHàfÂY?CC~|:˜+Æ]ß襧 ×®Ô?+5á8…‰ds!òð¸#‡4ˆ†Ä±Ô?ÚIëJÓµ)š,}XZõFM]RµÏkã Ýß=d˜¬]cOvaH›¨zo6«¾œñP“ÿ6 $Ðk©§ys‡Ó›- 2içš7峉°’òéA˜tlGÒÏeSȸ¼À]4€3Å9Ã`Bj‚a,o:˜áØß~þ>º-“Æ‘Öè°:¢5ßÁ]Ÿ8ƒnZ?´Çé"Y^ßœ’(–í f±rvÓÈJ=íEë¹.¢ã&½6P¼õ¿25ÑcÍ Òa?Ô~ÐâD6q^Ñ)"£¨%JCôo–j, Ê'i@¼ du~p`_j*ª`wŽJÊlîb£Ä%QBÀä3U<üG•¹PÔbÊmí#¹Rtïl1 Ó˜º¼œgÝ%ÿ%õf@Þ=œ¢ôµj­Þg }µL³œ¹¯”Ó¯¾l 6=y)ÜV”f_S5á0µŠwò^™,DVè¥Ñ0w^Ñþ"³>bX&®¿5{QYÞ5‹'ç\S¶‡Ô—AÌW~>çVaéÈ»eôjh¯…⌬ž63Ö”(L j4öêEj¶3 ˆw¨©žL[ý??h‹~ã’€€à‰ê…Úežc¼žËæyP˜‘¼ ½‹‘—³té9)ߘ²RÉõ»ÍIŒ…V1™ÑDöƒœd)á#èZÔét£bp,äCÜGGE4š‘¸zâÒÈ<;ùãõÌY ZˆÎ žV§Í@óÛœê+Ëû”¶Ie`mö6Ì-Çs)ÚUœ`B·­G‹‰‰álb̹I·Z÷—Æ"-o|3˜¢gÏx ¢éÉÀ©V×ghnÕô|×õ>︀Ýè­>C·»ëÉ&9'y»àÖÏ ©?x™¼â­È,óí)8˜6‚.J¡ÑI¼îàã ÷’o©E À‹}¥˜½œÔ‰Už–å  Ó "L‚>2χí\‚%ÐïdÌèå0•z[ƒ‰ëý Þíiõß öô¢ßoOõxW®>wœ¢m߉ÿÉ,³Ó¸a¶ͰŽÈø_η‹=âÆü˜½>–`üc¿.Ôòî´Ú}üÚò¦IwPBº‡€¨®Nsû”£tpÍòXÔl½xRaa Ìø»€@gyùìŸg5ˆ>õ‚·abÃÓb#(€å÷7íb^1 ÁôžïšÚx²zÙF«@§ïv@NåXœsô´;KÀ½ž ,fcsˆë›ÕüYÕ¾;Þ¥JšÉºi1°’©ç&ˆºWaÖ!ú%n.UI®üWŒDÖ&ãÁáÛJM€†T`ˆø iÏW\@½{ÀÒä½ÄòtXéèCr¤ª™uph ›oTÓÉFÝÝ€RöoTM)?ÉèòÕ.âÖ¯fݰÔ½z hª¢× º6se©7 ¾\Ú.Ð¥tŒ[‰HèÓ!åíXüÀéÜQͪUwE=ÄØw þ¡Å}Ó7ûv.öåœ+;²ÿtÌÚ7VžŽä•’Y(XësœBè…À©„,9<#ŒЉlƒÂ´OȰø«$KÅâ …@Ϙu5B'i8J}`íZÄ:ƒU’È-–盡ýQ(;ÆÃ`m!ÿ!`/ã}jFêjA;;l„„º–™°çc#I`õ}¸7¿ìËØgÁý]a¤‚XY¹"7™ôSšûÃuA‘Òš# ÊáÅìž‚mtL¿q ¼!ŠÚä9Ào†Ó8D›Gº1ÄüšWÞ`i`}—×S=—Ð]ã²dº$Þ+⛢q[bŽÿ:?ë|qOø[M`ÖÖ¶rËùV ÕˆÕ2 —¡ù{Ÿºkt¡^lã˜,qADRùæ !‡†J%ý½Ñ_é*÷K®á™ Ùˆ+(!M¦6.¶¡"¯¨ªmÇ”ü´8Ÿ?Õ#/ŒÚS˜,8GÉÜÜÐDmÞgºñDAF`8t! 3ñ}»ÏsWdc;Êbéb|þòcò¨íÝV8‡8Íø³—Ev¯Êt« DC5”ë^PßN1Øàz…ÑßjÆÉd\žÌÄ"Þß9:¦lÊü¦»”«D͛õËÙžþé ÀEvÅCÄ…Cø¾A%B‰À¦åÑ5Yff†ûgÞÎY3dÅuÔPŠyú>X|ð}Žk" Î?ÜTî˜wtÀ|„ fºâXs•†°Mú{°zÒ–£l†f~eVâô6˽ÈùxÙ7äv:6«jJ,7(ßHS"Ö>ù‰ìs`ì]cLØ]_¶XÔxi9îæÞè6Z-úŒN}{snmÚÙü™>Ÿ¿H˜Âv ή‹À3aã³-èn Eký~ŒN¤MËõ:óì÷ÜÛX]ûLf§…Ã-ÅFZãÞní騜O¬u|_„aÉ%qÄW{› ³ƒÍØÅWÀG£ï"­æy° ¿;%B´; b©Ê£ªCÊÞD]‘[^&;½¼1ç=m×ÌAK'.%™îFËn€ /ªÒ²G*ýbÿ7„qÁª5–e/²ÜX /^.h·;¼=CÂ,l;„à aî7x‡_N Ê5áÚÇÍ›¶ÿË=bÉ!¨„à·oQ5ï•^?i÷Š]}mvÙΉV±³9ä +yßKÁö¨¨Z›¸Äž$²à|mU& ߟm2û …¡(žua‰³qA)#¬>è9j&YIíœ圷mósº~’¦s¹o©E ¥Šû9ffãmúþQ› †(F½ìÙy’€€¹x]]½bý™Ì¥µÐkRœqEгØr ä«-¬·Nk‚F^LùX`l&‚ôi]ƒµ¬²ÔY”܉¿îwÎÑ÷ê‘⇀ _`\¹6ü±ÒJê50`ÞQW·œ;ͼe[>XQL¥Ä"§++wSìùÍòx¶ÃãÆ‹ÕÏ$Ù) >£ÑI‹,séÎàq]èehÕ_÷‰0~ÂÝ\Ç gˆ@,Gîé7¦%•\@ªSD§ ¸ÿ»½Ó!܈:¿W¯Y¯J}ö×x²‹ép@Û¦›h&Êä¥e^m¦9 3ÅH×lv‡~®Q{¬>TdxÚØË=quL=mÅ"]ݯ…NT’ê+£º(»jôê_Cˆ_“ygÌËb¾"5•æóµÿ‰B³Q'tý… =áø®ƒ­¾íÕÇ%æ%GǺ§qè |²³pa®¥7P]ƒ„þr.´a¨ôÀVêâFR!D¡$¡›¸ zÈ8q8oZõþ%Väð¤²j“^fopjn§›kú"T)s4Þ࣫ð«aº¾y\4æl!Rö!Í+Àhâ´°“Mkßw(÷³Äìm"ºÑÅPÜÐ kïiäq¿²©1aÁ×%go0R0š@ßí¦Ù5ÛÞ.]t†X«‰C”2ÔDDbZOétµÍÁêˆX³ÛIâ”Ùµ%:kÂÃ¥Ñw3þ¢_a MðÓXÑŸæÍGÙ舲Å?øào:MO€a&œ|ŠP?3d ‚ñ¶È2¢9UVùOæóŸþV³I½ŠoM®"ó´ç¡C!ø+,g8|WWYÅÀnêg»Hß Ð ÷¶ˆŸW˜ 2]‡šÖØQ[8•. ØHê±6¹I½á˜÷|ûÝÁmš‡„Ï|W˜×Rɉ-¤Ñªv†lÍ›bUe´M÷g‚6Ø$cIæ”ä0iw=ŒÏ3’€€î4H|öç%BË·7ÿæ‡;Ó(Úh ìËÖ§u7Äš¯ÊN%\/HC„qC¥ì¢OH¾:Ïqd‡r lSdUþÔ4+×Ý<]…,H·šgè)}t-Ó–zuCxü˜IµÚ®ŽçÌÁ´ïtŸÓêû¿ÍŽK° 1V*{TØü§×Ïgß­gMÏ' ̓–<ƒë˜º¼»÷§ÀV{žZÏ­!#k3“)Å<*²à‰†¹ðÏ©¥›#Ââj¢«q#7H—iBmZñ¯f¿¦ØÆ¦âñ³¢ Äö"‚ŸFÓyfï)p˜”­tÚë“7SÞÊÚR DÆÒÒ5?\˜–¯O±–¼Ír&a®¾tíœ÷6w“Jœp¼»j/©)y®ë#Wæp¨'çûrÙA*’Zï„íMó÷dºO_]’ÊØÎh£¹* –P9²I—1c?zcÄ.¬|ìä°Uø‰³ðé¤~OæË{²#Z¬ßôÿÍiq=U†Ùœ,s\†ÌætI æK¤äúËÉ*IUM;˜1XíCÐ.1>r´…éÁ-ÐK~}€hCØšv”OK7xÓÓhiœc¼yÔ?9u}!gjÃNPFŠž^YnÉ'lkýWç¼Cz¹´š¼ ßEHvëÛ`^",uéaþ|»»¬.MÙ‡ï  Ci³ &>uPS³ ™3cè ÜêèMSzÍ@hÀ[’g zÑØùMcu.츀ñ“†¦ }JpÄ´ úÅl³ä{m2 ’—qÅóz…])¯<”nº\3òEùÚæíiþ2QÏo^_FÖýËaô&ä{ïŸZ,Üœþ*81Ši¦Å¹´%^£¦ß÷=³ìBA g¹¯¤Ô£ÙÉÔ Bæä—=~`[½¶t¤MèOQ~gj¨kc®ß©r!ÙV©] ¢««1“M,À+Fø¸óÜËМ«_øž.ΖíÁˆW›**"1åOË%^áf¡n÷]Õç¹ÀB¢–\ÏŠ lvœ–NÅ$lœ·ŒÍqà ºk§•ŽM6ÁÜþL2ÙX÷‘›8Ñ¡±ÿ/=z¯>Æ4DsC#%‹ñžz""dï33JTÇänªp‰ £ØD~À6Ì ž6¬ßÁgDä×›¦~©ÿB˜-í¿'õµí¤Çã€Õ—Ä¥S¤ˆÝ •T¸Aå+H€ Î+aÀÐÂ@X13qØUÏ7[¥ÑñÖÙ0Lá`ý–ʺ˜t¡“ªç[ÍÓeäÙ®¨‘94r-7=8y §)ÈÕú¼­UTþfë‰À¢›ý¢U;nG‡ŸµdaJ]y ŒKºØõÅúb•u!þ íÍÈync4‘!ÈØgt9WÜ‘û³-h„”1Fum‘þ’‚hz5ôdÒüæFÏJz ö !þîžVªÆ.Íž3%™´ò‡Uˆ‰þ Œ0}ÏknSM–äjKit¶z9¼»ë#Et€®¯¹ðä°ðÞì_P41é®ôa<¨Ùª“Ê⽿ÓSŒ•œ£À1}«:¹†Vd|nüâ˜"M¤ó‡òé4€^<7\;Hêælº7ÚDïsXã=G›æ\$bªæ^c5oãB`À…+—ÑxŒUöãÂøy‘ ér¢¦ù …éjnQ·¸,¿ö.EÚáÝ-ÐD9¬y™VPýLö‹'§ Š*«’€€æƒ‡þ&«š\öSpÂ÷s4‡æ‡ÂcbNg%iøÝ†ý Äp! Õ ¹Ê—ªÌŒÍùx:µVÜ*äTouY …ë›ÑdUÒJAõníh§-oÿ¤ß~u‘é~ÜŽ`»câ÷éÉ1ßZ5Gr­¼ý÷Ý[ƒÓ d;è2uÀú§×=ÿm²›ù%iûÖ5âáø1ì!‘«h$›ñ<2Aq6' |†L£ïY¢÷뢣g»N2âŒ9 x‡¼@¹¶ÜTKs‚°€Ç†H|¡ëeù ‰¼šO=÷«¿ãÒdÕ,…Ò1 CIwˆzk%ç®Ìna!!ROgš­°ÃèAGi[¹][þȽ­e£M!íÃDro²‰Ì"à+ˆeìoî~ ¿4§,.6 P¡Úé=°Ž– Œ€Þ?M¬*Æ£~ϵ¶Éª|ïÎÚGRLô#v„<˜t7OX}fѧèà›—é(Ë óAKd»"¾ùo¼­³˜­©$»¤yî}Oå-m3®UækcQåUáÄjFÕ ¸™ã¡Ú ¼P“U¹/›Öf£PIõUuÔW@ÓÒ N:%A‘úwÏÁ«ÇÅ!=Ù¯À÷×GŒŽ ¤K1·Zµ/æb Š ®9‚_P)ÒÆ¡¡+.“<ÞŸ3VÞA»lQk'WCUw÷ù”\[ݸ°«~ï’€€ £/“˜ÔàQíßO2”mKQ• § ›"–hUu¡Ü¡"åù2 Ë¿}‰J‡…Ö}ŒV騧Îsº,~ØõöÄ›q$HÄ´qXÝfK R˜¿`ѦàiH8’Î7,Ä)í x#Îõ¬ú´«9f Tإ ŒKòñL8g±Yu™EÓ?ãÅ3 "=Êܘæ2E±t°E-jªs‚`x„ë$ª*1ü×§!â dãÛnÈú¸}AæL”+ñÄ’?Zå¥?õYR»¦jó„EÊooÞöp°YÑôºë !‘(kùêf]¿CC÷]ìï°Þ›b…™µ¯?k½3œòƒ06kbþÅ)D)ÖÛM|Ë%Y7G^-ò×/nþ•óÌkÉt ñÞ4[‚oÏA¦3FT˜Ô/ ð|·xà‚‡4nÇ[WÓÓÏþÐÁK;r%|Æ$GíÐã;}0¼RÞ Â­µ Iþ°ïÂöYT‹9œMÄœ~g¬ß¦ô¶ ¶>’9¡ mÌ`æsµ h ô!I­:R‘¤»úƒò¨5Ó»Ô†ï IIî¡!8M:ûáYÊÏ1P›í!F©›|%Šb‘0²œÏÊBúÏ+.=šÓü˜cv ùU'È4cœYA;îì 6l¸ë °ÃEg “$+䨴äG0_ËF·UlI`ªMã`™,™ªÚÔ±Ÿn(R5F' *¨‡Eu¿˜ DÙl‡êƒ¾18.|œóâƒAmÛr.ñܱŒ×ŽÙ[±tmæ)’´dû bþ™7(/0Çî£ËqA *.­² â9Àº‹i§Üp¡ìör12CóªŽ@õ?ÜšÝÙ0¼=ž³ñ*ÇÕ)¹Ù:æfKÇð+Ïu*qGd—Ó»$Áw”Œ ¹ùœ¥IPU!w‡I_ìA-nÆòð²tyÎy¶Z/Ì¿ê‚ð0…{³íTO®¬1ß )ý;å•inø§q«|šwz%rêq0áÙÊ`BcÒ«ˆ)Ç›ÒÅÒ@û¯ê¨:ØtþiÔãYyT°òÑ& Ôf_’nþÂ/Œž^j|.d‘‘#Ê ËÃÒ½¿pù0LuqâÈ”(g\’Ô"üûßýXøV£þ±|‰þ _EÞå‡k"/Ur>M~×xKR dà—NÇ>{nN¿3Ïqv£+mGµžÏÄÁK˜š³1°i¢V^Hð70N?ÉHÿµ$íg„$dØòwr„ö  ¿59AÜj¯f¿‹¦×VûÜBþë—çÊ%ÌÃ~¦N¦ŸËF³{æ}òv3¸¶…«µZ…õÈÙYÖò«³G3*YÖù´ÇÕʳã!GÓÚ ¾­Â]ZÏ„­ö±~Çvˆ3æûžÐyû¯àÑJÑù´QÏ}q‘Ö§ØBÛl'q)`½kjã¨<Üæ8ú”€§sÅ[mp ÈF*æéˆ_¢#Ÿßæ,]Ó@ SÖÕÀõZ\A·‚ø£2g©ôµø“kåTÉu)_”a4l™ …Y!q²‡º„"om•i©ÏA4C 6I]:£HD«pðÂèo£_÷~¤iâèÙ®+C²žš)eÅ~7 ´o…HÖŸùA+ïŒú™8¡‰¿Ü¡Š¯o?#t® G;hd‹’€€¡”œkÓ¹à}°tÇ€müG£En\Mt(½Ú+¾Iý®‹÷-0yþwE(ßýîQRE 9™TJ÷æS§4§Ë?O…DŸïTœ0ŽÄá ªÞ*\(^)¤ %d‘mîb§9XpÇáI»d”R.äbjù‚B!jþŽ]á”|ªgá¬ìÝ£9²0³)“äÖ“Ï©$±´ï÷¼ l£»=™âm»VÚ3JƒR$Øï‹ãJb%lØ(M¸þMWýÏ•ìêݨœY^ž™â¹¶œíÖ/qªt[pµ’Õ «\q`pϩ̖u{6µ.§N=f\¬ð1lY¢MyU‚m éC ò†z<.;î*€N9çÚÞr«{µ$›"üR¡Á–Àg>Z³/ªw‘Éæ"ø'ªvÏ‘¯à…’¢ÆA%ê+‡_„“KwÏÇÒÅÖÝ­ÏU}}ù>¤"Tv±ÿGW馸šÞ`¡xð]’ñ½Ú 8=«Ežò¸Ló²óÔyŽØøŒÜÿ h§vÔY ÷÷8˜crf}¡¹õÄPN½<°÷k#¾%YD-•z¨€×órby­µÙÜíÒ~–1y]å/@¤ÿê‚Aœfì6]ê_éÞr YØ¥òyÍU`¯ÉÚ'~¼§…Ü8Ôªƒú› àv0!ngZŒ‰¨ŽÚ!Ðçó- Ø+¾Îö›jÀ¯xe+ô£Ũ0ât§˜Kð3¾žÑ9„¤ )Íz=®Ÿ Œìp‰8yÐ$htÌý<$¬üKB!>^^¨ãœÂjŸëöZ½D#ENtèlL¾"Ãéf†Wï½û‘Þ†ºãØ)òVO͘ù†…(/8ºÂkm±Æ{ñ´Y»ëx‡óÉ31i<‹‹ÚÉ}ê膥Q`œš€ ×™ø4öóÅŽZ¬°x=¢½ø£I’…@ÆÎˆHãâ5 —î¼áumµ§®A,ýM{û j‘ ‰÷£hêúu¡Öq‡Lb‡e`—Ù¦ ùlÿ€¼6\=è!…H½]ÿ¿3 óÿ"»9#Œ8#W»Ò<Æklr«O ŶµÎeäec+¬‹ÂKóå4r×ÇýC¥<À¿1y­tl–û ´êü;àh”FåDïäÚÍK¦|tÙô%®—žøp2 wäo GJ&ç±”L1ËÞB>ç’®P€ÛºŒZ÷玈~±’€€®’¬ÃŽ/c!_¨EâkØÔœ@³ê/álÌ0V#!qG-Ì2œ| ¾ØNP:ýÜÓmú2%ÿBý”J&ÿ|¯WÈøÑ¹2 =rlýo¿B¶u>$hË;×bÒ·Õ#ª ›º$E’¬e xãàRÔãœßs³Œä¸lÈ|¿L-Ífƒdæ º.kŒqÝCl¢Rj›h‰àoM€­˜£2)Ìë6LJ_×É| ,Ï;u9¶+zFõûÊùÊ?2{Å¢°m÷´xïXë*šýï–goÞeiYïñUÕ›”“$ÊÔ<±™Ä™ÚÑ¡H(ËY Ú„ìÙ£¢[Ú%õØN ÀšèÊîË€Û÷~>Rï_wËÙ!âgì/ï5y<Ì ù0|âkKÓ?®7IT=òÚ5²Tcþ#:’‰ô"›1ñ‡-öœÝÑ^±{6œpx­.)¨’dí¨ÞFF#ëNe_&Z¼ê<“1Oá$SÇ3ÁéúA­·mÃ1±ÅpþÅßóq8Їþee t÷rå/ÏñÁ´Ð¬WñœÛw_¤¤ë"²zoÐñïåñ¸+—ï%ÂýâÜgìYob|K4 ÌUòbo³î÷·»¶¡ÂRü7SÜ–º¡é ’€€¤ƒdÀÊN¼{1žòKƒ¦¶ÿÉmy:žÂ´ÅÀiÐŒ¡ ¯å:t±›à¥×~RÏËÙïÃöˆm­½hO6u ]»ƒb÷áÛ 1YñϘ–’µ[gD‡žMÂCH·ùYš`¬”IRÜýä:F÷k ¶$M“(³ú1 PùóUî ÞD›i¡ ` W°·àp3 ;wÑ»ÁÒsöΔ­Ø©I²9±ûÕ‘ŸZúWÜ×Ú˜räK¸ek¼¯·ÅU°÷k†vžH_>lAÁß}[#çµéP˜¨ ¤¢ŠöÄ­…ÞÿÈ^m£m¼§¤Ü@ÍUgëÂæùrgZê¥áíB`n‹5¢yM Õ¸GÅXÎÇjxäÕÀcµš÷Ì]§^Y*skãT °$g_¿Â<µ\Š×Eä áZ¿ÂÁK$Q Þã!jw¢“!/°Ë`°qw~qyfBïÇüÉáEqØ…î6üzÄ÷(Ú ðDÅ"c4·r9VgØ kIž¨²I0Ø;Ÿó+á¸íÝaú?è7ü8VnTÙr‚ûC߇Ä|µwǦ 4D~37¸ª»}ñ"#j¯äâ¢ßB@wù±jÍÉAjm}’;){Z¸ M1?åÜp”Z|ošù=ínS¹“9^´|})*Þ»h]6K† ÂïU$ÛÓÞF¦¢ý¢yš­à‡@MÈÔi2Ú_¹œúòã0á‘¡,°è yÛGHÙœRÊ"ÌÿLáßnÉòtbJ–ï˜RÜRå*‰!-HðH]‰Ò”!ÇŠ—cnq§Ö’C d÷¶ÇÕ žs ;‚ ·/ò¾#VÖßH*÷Å“qÇ‘)Íi‘ƒé€1Â]*˜ËbøÍ¥òy¤ðˆüÑó‰EЫ13ñ7Æ—BŠÔ.΃EÀ7üFãI’€€¾±`’|‰¢“ů©ùÿ³Æóô‹—ƒ®2ÁtçD‰Èå Lä2m n'>c®Ax‘û¶ Ó¸©€§áap5ÅÖÕ—y8ë~!াi±‰®ú¸œÿ‹Èÿ4-b·Vx<íýò§k¿$‡Ápø!uàå"³r"˜`®Ãã\ÄöyYrœ÷+& ó†þQªgE’3ÇÝi#ëïw©Ž<Ï¡j|dïìIJ8MòБÂDñ¾(KjÀ•5VÑÜ;ÝŠ,~H ðùÁS.ªªí2:óélÖ“Œ¬Rš%²l˜„Y¸(¹¢häóç‘lX;f¾˜am ZôZÚJós‡ž´:YhÜš­)3‘–!£,1q¬~±ókδ†]ˆ%¥"b¾…ÃXú6uC°šŠÜÊ¥jdaÙÈ Þâ‰zò¡å‡®$×Ç¡Rœ"l×Ù×Ûû–É©#¬œD½I9ƒäQpœê]‡’¬5gíTøl"È c¦ñ*J·ïT ‹0ôè ÚÞuO÷E™Ö¢«ýL;æ°W0$L­Í;6Œš¸¿Qk„/Vªh`ã''÷.cØõv¥a5tB8à ë'½]¹Žvº œRˆŠrœoz¡T 4 ÎqÉÌ{6[”FÜ4AKëTV”‡Ù4pL2¯Güu%˜˽öîŽßÅ£!_þî=Ó‚*mûDwù„ÛݼÀÖlÊSž¾gb§wg-Â5k²œCgŽ@¤øz _x¹Á‘Ž¢HRðCt{”#‚@[§çI"_޼(5H)F¿÷S1[ïνÛ±žt”H"Á 7Òn4¥büÓ€“îφí3–¯¬÷6Üè±ø_!¢õ†êIˆ·åí‡XLyOù„f·GSL­èpF<ãa¤ä¥SecÝuçO«}ÜÀw õêîuð,[&rq]Ô_3œU`øÑdëmœ¢‰xgM¢Æ»§6q¨¼°Ú[Y(ñéscšÏˆŽ[쳤(dYA½ý„ôÕˆÄM5à$üîIu¾±¯ŠÝ èÞN:úC° +C‚ êd¯¾ÊüàÞéÛâbZÒq0ùéâ´OÌHDôOážÝ"¡nÇÜeÑxG’¤d<ó·ÔÚmKš]Á*'×ÓMÚþÜÝ•ÉÍÈi%Å&û+Ò~LùGçxÎzâ6QÁ­@:Ÿ QF¨©Þsw<\« ]芇%’u\{*-‰RS 5xÝcÖÛ£éã$"kšÓhÜ*Í){#›_QS™‚# ùaN²m$8»Ñ…-µ]1 No×½wHMÈÖN¼]ý£m<ïsISuš´&’+|ô…8Êĸ%І¬†;ÊáómPÊ8(M8UÅ9xÇÁ½eø8'G CÌèEzS§·ËÂñ$>Ô … ‰¢®›&ìzî îœE¤^r” qßC0ò†ý¤ç!^×wùg^?L°ñ”"â#ÃǨ((ݱ$,Š.™ì4ÐH#>®Ò §8Õ«Ì::;Æ·¯£åú+é6¦µîwnRݳqj;ntûø›¿Èö¬£¾Áørp7È";úi²8Õ1ÕþxO;ÍÕ–àB·w;*FjW¾±‹íá(Eðp7—yÛÈø&¤dPv´Å¥—ô¢ŽÈTÈRHdö}œ®“[7ÇC @+Þ¶ë$>O¶”™-^_vë¥Xv±L9fðö¬Juq~à á$°Äi]ÒÞAœš¢ðw·xÙòFly’yŒ¢&B åܱØ@¼’?Ê‹oѵS;:û“ŸQ/Ê„KCœ’ÍV˜žäIüôÙÛžãø1!n{3oEåAo/œ“€ÓŽß©åšÌ°F!‚ä6W¨?ù* {×tÝ#º¬û0õL|Væ™êKcH?fËt„§r{ùŸ!×¥v¿ùd¾0PB¥¢ß]6ÄúÍFçöë^‰3Lú†$_bvóY’€€–2³Ø…J®WZaoóë(´{ÒöhšÄéŸsÈü˜”ÚD³[.±:=Mg:“ÑøxÛøP+Êç·»üÕDßâÆtË+?òû*Eº&üs 4b/!ÃRDCþu¼×˜Ú={•9 b†í•ÞΦæ¹:KÙ»æßGìr®@[Vå2|EÌíÃ0ù§Ëbòáùݯð‰ø! Gû±ƒ«Š€ Ë~*¹6{A$76Zýß!ú— Å'íBF•Á]…Ò óËÆÀ¨òHËAþ¶ªä˜½‰ðr·­Nô8Õ‘‘¿H§–3 ¤æ¼Ž›Ö©~_UB§Pú)qµñ£ýß>=«·qâ÷ÀF—ãüÓS¾€½E¨åV6—rU ¶þãלþ›Š•E>y:¦¼¦Yp§<—&o€½9@]üyÒ¨>ÒPº$JKLÑõ:<—¤ ,î—9JI­å¸¡â£Õ46§C¯3"ÁÆ3§ 8«v-¶È2H_ ê_:/˜çuùGX°®TüöVÏÒ%9ƒÁ»v1ós諘oXMÑö%›±ªb«.ìx2SÔǤÉÑ>Î*B0G‚¸ÎNx¸r§UÜzîÇö®¶…jŒì;ÉBê#âÀ3îû{çàdH«14Ðe]™ÙÄ>ˆÙüÕ6TRÕ0vµõ@3î-ƨÖðc— ;X €peù¯ó’Ìkó=®Ähî©€c­…qŠØB)²©Š+¡Åð/ t½ðR¶ ôø|\bc‘Ë}|6íiÙË"è#·¸Œž_Ëâ·aõ| L³Ù+ÑëVa_¨jÂõ€Öõ‰­ù¢ï“ ˜n3ŠtäÁŒþvØppþió õ¦(V'cT‡: Lüw#Þ3hLÑgüfkÿ*ž‚˜o¾¹“[q4Q~ÂF߃ª5ãaE^uôË3x¸ïÔ'» ظcP¹r¾ÞJû&l¯ïĘ5­Î÷¢¤­¹Á¢1DáÕxC£q‹¤À¦+%Å•½›“¥}"MV±¶E޵\‰¢¡?Y¢³åâf­t\6ÖÚà°ºy~òíFk„hQ ÔMÍ™{áÍ3c¨yk–Î[ˆZ+Ï]Ús®JÊòHˆdï2ý˜þ¶)Go2»?^@ÏŒD70æîI×çFëENÈ•% -ŒNb††pÅ1‡-O7 6ÿD–Ö_£( ÇYZª{*Ò#+†=|• ¥ªw"Æ»ž|ŸT½µ£sçoê³ÿªN©øÖgzcF{Ÿ„½Èö߸ýStÃù? _ÜG&kÕ!¿Þ¼Lö àB""é´L»A|,Á%ЊGøRŒQ¤D7QÐ@Õé>¨ ¬FãÝ‹”^ËR)«‡¬"oQø Alw¥a†”›DOÝcŒi¥†§ì׋]éX–Nëþ´’€¿öÙ7\-^ŸQøRqKj±ÙÈó‹åµœc£g£Ÿ:Þåš™j6¯¦VŒ‘ÿBåP§xì%éR^†Ò4“e“Dk̳;ko­\i­ˆ¹¾MÔº´²Ø„ˆ]eRÓ3QÅMm6Bo³ õÉ«”5ÅêèOz® ‰â'ïîŰOJZëóÉX¿.òe(ú`~kiì¸%«Iƶ‘u˜óÚ¿”& ìÖ>°ðÕq×dy|°IŠzQŽÜôÕÞeZ&!‚hñíÛAù\4± da‰|03øåg]ÌC“KM‡ŽÔÜ»¯dE,Øt «_Y7®²ÆåˆgËbÄ ¤‡ãT˜ü²«q­t-59{WªrÕòYp&Ñðø—Ñd&8­‚ðáw¶óþ½í?—cdà¾Q¥Cne¶T$;H˜ü>‘G„°ÝWI V¥Ž¦ï÷þ01ãûàj ‚µ>Æ@Zy˜Ü¯mÙŠB•Y‘LcÕ†q³È–ãþpÙúªËÉʱÑhÍ¥’€€üb«,M«qwztÙ—Eã–K>|É¢0ƒ/ÙÙ:€R޽ñÍDÓXô ÔËMT4•åÀµœ¯«ó'dc裡 F÷Ä´eRú*‰íDd£í÷•ò…ÒCYà çFëíʃ¾¦—Êó³³K!õü{v…”9é8w¬‚²§$B-XéS‚Ô[î"hµy,ž—ÞGÚ@›GÕ“$°Çnq¡y?÷7þ7Íó¶¸Õ ¸V,RÁÛ¤'Æ=;%âË,û;®åGJ%Tº•”@·—¤Û>1É0€sõ9ØßQû@Ü^»ÌÎRGÁMt—M*„¿Údl±l`޳‡Kuä0b›u¬;z˜3È/$Šå™Tàð£¢Ã½É/°([Ô¥Ó'žØ ;² º#H fñ×¼.iÈæ-î+5Œ(æähëXöSf/~Â8Viïøl´A¤‡TŠº„£ä÷Î6Ï»«èϯò–ÀwÛ)Žòšá#RßP=¤¿†E; }ô)Ý!%SÖ3âÑÒÊ[4ȨôUCÛïà‘›(#Ç«ön›AV¥û×ðý‚_ÊòS,óòÔ$Wˆý–Ø%F.Þ£»Ä&Rt€*GêÂ]•ÁÒ-·ñ¢iÛl˜¬´w\«'_‰5ì÷ÉL‰7ÿLåîEÆ}EæÂŠM§›$^Á¬ ³]:PNßñ\[[ œ,G~«âÖ.æžý‰b 4ó,ï­mBé¿KE¬Ó.‡sñY°»Íôu9–DÀ„ê¹Àû27fÊ\Ò^_ÅëüÍr¡ h@§vÔòßžnZ›¹§ý¦wý¹¼ß¢Ö!]On½\€^9X5¡ w×b2•$8ÇDB³&4¯›³hpÐPç‚FÙúø±m#]D˜±ú•fPgãàd.¦èа ¯–šË66ˆ½èA«€) ­wêV2b0 u~ÙøÒ  °õ¡ /“$†Ð€†FHñ;(ù”j> O€ù ,a‹)&ÂÉ»™_8¢ÙÞ+ME7úAmR$ï}ÒOËh¡‚¨ÓÙúX~zšÏ˜·^.z’øÈ†®¼¿ˆ±²ìýÕŠ‡-+õÞhÃý/¶±ÒTñ©Ä5¹c"Ñ36tN‹×TýïÕ\/ܲß’€€±†@àÑÏïÑøñ¬æ±{®Ë…õS Q™õÝÜ P~0Rþ[kºKçRwcë_Ã.÷ÊÝ»¾k(MŽ< å~ª ‰ú7% ÑLãU¶Ò¼Ñîà½Â•aÅÝۥ꿢MJšX^>¬n\Ñ(qØÓ¸ûÃV±)>d‰KÓ91È +Ö´”øÎÈlwsÛY2õô°jVˆìÅÂ$V·PÌ@¡ý‡í?ì­¥Æ(×£ngÖJcF°Ó÷a¬v$u«ô‰›oŒlss‡ȧÆýÆWÊ…U»°¨$Š@ï2ênõî‚þåƒMdŒŒ‡ða2D£uŠ ½åeD±š~f:S‘ q£bå£Ûϸ-Nì‚JõÖÑ[Ds­¬I±P¬…qü ûÿ{™Â£&Á·í~»[º°x mk÷&sB, 4x­l†¸ß!EÖ‹ãé2Ys9ÝD]×èÆ¬9L¤”L4¾Ti7vù¶HT,Ÿy×deÊ««¸C¦Ä™úzŠ%šª˜÷NðçßP¶¸?oáve÷F †Ý\QȳvHeÄŸ…|jŸLǺ4À?1(5±¹4å E$òÏ;rÁçÍDèª/¿iO‡;•5ø÷¼9qÏŽì]‰œþ§.΂!³%z!ŒÜÐ#%Ñ8;Võô ãpòÄSRYO¬n±æç ñ’ý—my_<ׯY€¯—Åh;E3 KÃ_tYê 7ÍTl¹×—EÓ ‚Ôä–Í^ùné©Äu4Ý ¾9b샂Æ?Öâ¡}Xí.áš¡ÃÁ¼‹±¾h² N’!U~׈/S|š¢"Áš'YˆÀ%>½<ÿ@Y1•Ÿ6¤ÄHÐŽµ\Oø¢‹ÚXE@1¼[â`å*í³±óÈmœ¢“9upÞé–7Zã¢HËÓ½yÍŠÑ1—ú”=‡U•dDR“öP‹8ªàeï7o<6ÆLÎ ¼Ý N™8ÊDµHl™$ f—A nm4–áM3]bºFf¬ä§xѱµ%\ 4Õ_¡vý™ìò#uM/vQ‡ˆ[²ÚöÕôrÀ œs£ÛjäùK‚€JöþÍå’€€Ú{ÀÉñ_w6³îÌÙ&S}ÈUs¼9€1+aݘje5{xT û ú+=>§Z=R a³hù6†ÌRŒ‘YK s8ÎRSO øûŸ"œàa+߃Û*ßyÒ‰öÒ* ®sÄ–cd4ä·‹>±ƒâ-FG3+,§À7³1wlÀ5ë[QÙ'AÅ"+$¥JFPðÚDÌö»ÑŸ´#…°Ÿlœÿ}Œ$ì!Ö̳ãíê ¦]þ¬Œ†ÇXk3Jÿ Á2Y·Šã}ƒéñF„€ðˆ¯?!ŒÑ «"‹ízÆ“ÎÛ®×¹uçm¦»V›Fέ‰~Z³ö™¹,ÝY)¨ÞÈ]_‹? l°… <68ÂP÷ošÀGt’oNïÅõt·¥¹ƒé-:T¸óîX`jÚáÒŒ'/çÆoÌO}jg¯­å(“úyHüÅ,øWPØ _vòÔ÷=ˆ ‡Ä£š›@Ë¡±^ÉÖòÁ`F¹)("‡ë® g#ìû2%>!Mà†§'îœñHê«´e–9ªdi€z)HÎGG”ajZFºc nM©‹£½ÌüÌÐ?¬ÁRwÅÿnp[¾õQa†'IìºÚyû)ÓÎh-A :’À· L yjÄe;v[á2ë=ƒy.uüI[ø©‰ë'=ò³^îÛô W•?ÃÊF°ÞŒZ‘éÈ;B×¢ý µwïµøxUhWìÞp7ÿã›Yt*õÃ.ÿê&K¤]@p5Vg‘±…÷úTÓÎ!EÌÖO5GF~›®þbúöâí•Ñ·jÖÄ͓ԥߣvXÛP‡Ý³EÜ5¦ û&ê{”ðx‰x¨l”@XRàL1í–],7¤Jíøï⬮»)²^Ù²IxL ãz&ä[ùÚ!_ _c¸RRvª§ ³Ò_*€åV§‰]À/>ðK>è‘ÆwyÓl ñ„)õÓ‡F,ÜpõÓßÓþ¡‹ÈpOÞÛ9;÷’”ãlFò´9µ€˜„>õ¿ñì:³»±ÙÐÆ l–%G [bÞPÉq÷1°Y×É kµxHͪhî7ûJ4}Žg3B;Ã8ŒTÃèÓXžJ ',Rgã"Æíz=‡qŒåÕÎùn”Ë{‡ptF. ï W—] Ÿ7c‘ù›j­ý±’€€ª‰Æz¢|:†vç×vX Ÿ­—f핢ٱݳ4Ø”S޼»ëˆ ûQ™Æ1.mQæ=ÓšÀ ZIÆ‹-êµÏî?¥ÏK$ËîŽõÔÈ -ã"4?‡~U$hƒ?òbß^0S€ïô3ž43@Í=’½?Z‡Ð /ùøwØØ®ý)ϼ]æò¥œ=“D „ûåLÒïtßg=$žÒCnvá*-’ýD°Kkº^ Ð }Ê1“À|O^«UùØx4øƒŒÿæ5@}§½1Zú\k£çvd\w&½‹–$Ð@‰gX©ña© p:d|kÝ%Î…Ú/Nu«IÕ J; ò!1͇¦µBœÏƒS–ˆõŠ©]Zl& Œ+YÝò…bû¿ùè‡ê4ÚgÃÎe123–?N‹°Ã÷£‘à´6ˆrÞjµµ·hÞ8å[yÛ@ZÞ«P×ÒyB'³†ˆÈú’<ú Ôñ«ÊÏŸH³™F=,»=•©SÞÒ“²µn§yYªuz[˜y¢é÷Õ%20û3ÇyÁ)ŠÏ|xdÍ ø¯ •ÈfcòÁÑ© /Ý×ô¸çâ3Tc[zÎXBµ®Ò; #HÈ;?¾'óöj8 ‘-n‰‡¬0ãnڠï>ü‹½*¨4â”Î,þ¥²§kVæà=¶$2ÖÅæç CV¿ÿ¾Äƒ8˜Âfœ1€ì²AŸi¯‰ƒïNDâÛ¹Üà O™"L¥Êœð!-kjyÇó²ï­ŒH×b|<¶ÞÖמ›^ëÓz/³ªtÇÃÅjö‘(†7nG÷Aò¾tžZcT ¶®¡ƒƒÜ€ªÇmg11“Úƒ† «'pñ^ 7q4†ŠG€èl HÑ\'Œ$F?ïKkÇ™S9뜱ΰæ5ë.fÀo.JŠR4(ŠéNöß‘xš«.Ú¡¬èZØM¸RÈvK’ ê½@…Ñ\ík3Ó…4+;±s’ŠND2K+O@«ÿ¡¼¾÷s¾3ï [.KkS"2p®‹Ûd{ŸCA…:ê¹µÓá«—p³7¿t¾µÂÁJ˳æé»Ž^P÷)r°lpFÙ÷4¼qã‚I†HÃÀ½AÛN~d ˆŸz„69Òí…èE]”âP…[WÜz`{†Üƒš¥žf TZðbøg8ñ%Ö<ÎjÚœ™fû׿zGÑUç AÀÞ+È»ݘßFÀÁÑT¯B€D‰i±^cT&b>žµ‘mµœ:è ^qŸ$s‰TRš׸—ÈÎV¢EƒÊ‰<Šüí§ 2 ^!ñ5÷ÀÿGph6ecW;îE*Ï·ŠÒ”ÃÀu Å}™ƒ¨²¯ÕP´ÌØÚq¢GD¢µÃ1.{ë.l²7ó¾ù´F>£O_®_7rÔÇ ˜Hì*—}䎼êÉñ€ø÷~¯údÉ<©Ér moÁ zZžÛGf³eÂ/qÈü‘ëQPÜ Ã+µ‰8rüÆng•Þ acTóV¤ˆ`Ìâ*›Hÿ!¸-wŽH#ï¨M0EIN’€€Ä­Å„‹f*!þœ£ÏÅ<*“ŠÚ¢?ØfMe\áÝérlR~þÕ¥ß6¢üuªÜ‘!àv/¡KKïŒá CìéçؾÂóÐÈ]I [|*Ññ¾Q«ØduŸ©xIJjäfÃX;âÛ@yÁ¢iñybHg¯† „En¬rö–ü‹]£çv\ã‘â* =Cb¦ÕYWç „vÀËÛ‡÷;w–Ó“k ¬8œÍ*CäkWø XJäÒ—jàƒ õŠA;jø•ƒŽìmõ–˜&«]áõò>ŸmO†Í€ÇéµF¬i4ä‡2rº¶‘ý\ÈÑGÿ}ã^É]‹Ç²˜Nê¿™šñ*yŸG§¯~ùƒÃ?‚šp†¥€Áá¤×1û7Û9íÀE!£¡?H¿“SOº×²È­°ÕѺæ=ÃäÑníLKN-Š4OìÔ™ùÔ‰Ò.zGåQΗ&.;å¿„[Þì.7—Vͱ*”ÓÀtðß‘mGI *¦kM–`Øf’Lë„ 6°G¿À‡v\Ó‡^Â÷„À¢[å«…ž+—8#Cs†§f ËIÖ.bþŸ0¶Â@ôòê³0hP‚A‘ÞP·ÿÏÿ6îZ%s]Oj%?ÒD ·K³Ô%™ê†`:¤V`Õ‡[؉PÔv•r‘I:\q¡í³xÆúºƒY¬SqZ9y9…À®ò‘…J³“p.EãèŧÉkÜÄÚÔÑî]¯.N½xjã ŒF_­±ÛÔâòSÐÄy?µÑ­‹Ûõe’%·á“±ñXOd ’jp®3wh´0Ò{.˜Ýþ¾-@ÄÏ“ÉÍ03|Ï<¬}áÓÑœë^à[‰NHŠ}Ô0|û» ‡ªuŠsvÙ-¿bÿ·:ljÌ몜¸sŠªÈÌ&«º_ 5hÖrŽî—œAHç¼À–þédL+ Ïpv¤áO ðÑIä¯ô«‚âzyošùeCÙ‚^Û"¸éTk‡äÛºàÁ‚LjÖ9=£rXÛBÝG=+y³Š/lø=»sÓJ|.°þþ ø;íØ@ôºùæYé/×!GösRvº`Ãߎú:P¼QÙA?KHJ½Ÿ9«xæ´·nkà,ÿ³¶‡…H‰ñ ÛÆÉ%ºÅ_ÂJ±ñé®ÛO™h@PÙ1È[®p‘’€€ù_Sä fÜ.ôhIœ"ÿßéøQ«ã˜Ïù¢%â•HΧ/ô˜x-Và*¶1Ú0,•£Ó’^FëdCÛ„õгÚMl5`èô ›ŽvËÕ Ú„UÅF~{o#’`zØÐÕ4X>-CÉÙ[„FÇ5yZr‹’~Â<¿{ï­Š„ºÓ¾l· b›v,õ»ä«ï{h‚ÄÒ¥1çÜ͵K·‰ñ¾ ‘N:ʨtVÁÑ¡™6J¤¾UØnøIdRº»/0ŽA†œjs çÇÂÊ×sÓ><v Ù4‹ɳ üìô‡;ÿðy“‡j¶s±nÍÝîO™ì"²ª\Ð ¿'ydÄÀø'g«’ 8n3¨Öz¤-³jU ‰ÿÆîŒv0‚hû·…om©È¿þ5ù¨µjß…õÎ…za2ÁF@ë×·»ºÿ†êrñ¾…×àG[/Ã-qøâmÈž%³³r§þmº_àŸi{ŠÁs=µ0‡•ÐJ'ÁDÙù–÷…eY·“eF`p%:¢CÀºœb*¯µ¨¡YGÂÞŽ$èØƒ¾SVA¶Èl‚- _žf²·çŠu[,ÐÐŒ§Ù6HÎFÝl\®Ã+§l ¢/1ëz’\¬ŠK¬MÇ´è÷Ôˆõ]jŠZ60IðçNç:N¡¶A¯Õ¡È6lÙ´óÄ­ØàjztçO,ú™œÃ*mö¼—¸¥Ñ¹ø+ÍÑ (N=¥¦¡‘õ[?íª±X^“d8Ï·œboׯ®UlÕÝiÑ1ˆ>€c–‹Žë—I˜†×4òêÀl%1¯Î3ƒÑ".éTfN¢zUöMÄ#õüJ]ùNóðÏ’€€¤;Ô.Lëkoˆ!r¥L-Ägx¦a(sóÁ‘.Õ¡ctå©›·Ö÷Ò­;Ç&¿UãÉW[°ýÿæÕ,1„IKj à_#utùÊ\>œq¹å+ë›nî&äŸ_ùˆÕÆZµ‚ª§ìQ?tɯ¢ ÷Ê{¤vÐ"._‘Lm¿õ&9R5ý[ÇÎmþé³2®Ó5‘~Á³¼O˜Õ|ÃË"¸ƒ!ëéñ"Íj4{p?IŽB„Ô¿Õ‚ØÉdË=ŽY^Nï»”N ©.žjÄŽA|—q÷s…¦Éf«z¦÷§´¿V®Ñ1J Õþ&Ô¦-ùµÕrþò ÕÕŽwÜ­ÅïÇíKŸq†ŠP?Yñ9̲cјõ¼ÒèNì€nÄS9/i.Í„¼/Át·Q&÷ÙÑJÆrŽ¡»£@Góä¿®•TF[ª#àø¾<ÇQ¿Cƒ˜Ù°PN•¹Öá2wð ”&z¸~µâ‹ yO:"º®´÷ÜSâÒÇW¬8E[Œ»ëNwãey¥ˆô©8R:s…‹6L.&ŸZîû Í´RbïT*ú£´“J׈˜*õï‹LKVBs¼Ö•:vP° Æ€extÜ<)B0 2¡ZÂJhiÏ{‚|rF³PÔ—pweui!ÓC©ãàƒùþÃÃ$OïÇw¨Þ×'F’žÒTÀRį–óÞ®Ò˜7Jfã÷ãk·cæIÑo±ø :}ýáo»7bçò a9÷û×Sƒû€;§‰¹ãe]¤ÒÆÊf8.ß_—^¦DÐe]¶ÙpÄ‚Ó7ì*9q¿÷‘@Þ ÄÇÛX/Õ=ÕÂ<æó³“t%ºÛÄv\Åû•Ñ®Ö,¶ŠGjŽ_Ö äaVí¼íŽœÇêÝ&XÂ^­´´?mÌÕÔ›aûDÍCÞÌ[wm¦£ ]Œ Å43+5éüÇˈ¸ñÝ`ã¡ü¼( ê§ëû¢Æ‘â@ƒ´qzwJÐo[éÕE9ŸŸD¡RfóÝ£ ×YB;:rÍyݤÁ¿9.¼µfvqºª$õ £²È^ÝÍ}”p{’KrLž¥;Ÿ‚”WÜU)Ú=ä»Ö$Áu kLÅñºMù—:R*”2]o-VĹdEšŠf:°ÅÙ•–ƒ-3Õw±ˆÑZñÖÏ·:¸÷ÜòÓ×”@"OÐïk~7Pp0·ç·¶Í­T¥øŠÿm~µ{à_%Hå€!}-j3|–‘×Xyó¸1¸ƒ;’€€¼)`K­Ü¾„èÀð :ñ««À´Å猚¶ï§I`Ôg6ÿöêvi ë¿v’I:«€¶dã,sJÞå1/¡ˆŠßK’K{÷‡¦šNÜêŨXò{Žû/!¼jßcÀßFPAÙu¤‚qq2à³m¤`..q£š!œÁrþ ÖW lŽ˜9×ðUUw÷PŠMQ°ÇPJü)º¼WæìÕ_™*þ«V2”RÞ÷‚—ú!´uÜá?ÌËR>.£XÏæ5§¡%Ð)v(zBµ­Sé¹üMtìŽß¹±UG¸i>Þ·jÓã,úåâÄ->¶ºÔÕ=ÿ5þ*ÐI™EŽ!‰­Æþ,”¾5Ksî,‹-HÓ3¡…÷ Zºò7¦*c>ädÇ_é’¡k`ËBóŸ´„MD’"Ob_ŠàSò‹cbÔ–çVº|°YI£ŽZ³î„84ë¦lI4‡Çiêâ,E—³wÁîÒìHcqnç!vÆòÙ®`wcˆ2[ðWuþ¬¦Û„|’ý†ÓÑ_»‡;ÿÐrâló<™® k'•¨£âÉ¥aâòr:Z6n®c K·Ã¾ê·»vb%êYª­A-„«×+ž?^ÞœíÝT³²JÒÂ}}(Æ)žÙ|?Ð~ w >z£¦#çí×Sá ^´e0Þ Œ)è$žuÉæùƒìø9ÕϨ=™õ|iߘô¯êæjm¤, ÝqŒ3T群“ß 'T ª ì ‰3Ç'pçµ{þÐúcݯAß­ô [#l¶9<¥žA—P»hÛÉ R8=u vèÚ‰”‚—_w[$w/Ö~Úܵˆ NBOE/fÓj+6Ó·üoNV_ Â3¨àEOï?ÿÄ÷¶{Í ¢ñ—¾m.ÅBÉ!]WèëËcÞ5À9/ðÜýŒŠÀª«Äý{ñˆt£ÜØJ‡êÎÜû¨uËNýJPƺl}y«w1í•Rk{Í:›%µÑ¹ÏOXq÷å®žØÆ¯1*¸ì[ðÜ%{KÝÓ¡§‚8DMþÜa¨,쓜ßKDÇ@«xR{ b¦Ö¾D”h$öE^P¶¶?œL-F`d»3¼ÝÚ{Z6~ °Y't0±ZßþŽÇ­:¦Ñ½Dw£CñAvCKÕEêmvJyÝŸé­¿­o’€€Æ™GÿcÄ”íl:'1ùÛýÉnâæâZï®GS¦ çeð!Ü*#ðdפ§gRVŸÀœ Ôa€ãq¡W’£¥¤h½«Ã²} ¥éÙüh­éÀþy$=zæeìØÕpíýBêšõM@"`Ò%ÒÀ©>ø,$úb îéL! Ræ%w–“J:ë¹·š˜OÊæœc4 ;dÝ}»ô–ñ?œ2;ò†tqa´îР^‘Q_a;¢\QÍhèÿùé³ßÇb–ØÇ– Z¿¥¼_Œë´>×Ì Ÿ¡jÌýH<#’ØÉÙ›iflÞ«&±ó 4†d©Ü>C—µV…jÁ¯Zº ¤p(¾7Ž})V¤Rƒºz"ÛOBßb¯SË©ç(Í÷è_ §…ÕÓ ’ÛS1Æ]ÓßGÅ+zäC=¹Y9ûI¡®û“&Á€êȕɊCÝ Ù”E+túédxÚ©ÚÆàÎÖ9hÍ›âèú-ÂTr.fÒXÌ=ÝÛ œºárˆX¾Ô“Z¼ápMxâ)ÍOÕþC_˜ZjÛ©S—EE¸Mº€ñòW*™—<¯Ì°äUo·ãûßþºi½’i¹xòƨ² vTü–¤"Æê}É‚íÉìÀ3¥$´+®þ¬ôw'ô ֤ư½.à3!¢d—éwù N¡K–àîé-­˜Ï oÐ0oPa?ÉbB¼³çt¹þœÐ°ç‡K­®-fŠ%ÞxÐSÉ5²æÃÕÞ ;xI7øÀ,c­³ZÒ¸ÜæsäOÍ RHE(ú“Ô‚R=¶g14a ÚD÷Y|¿2ÁiåR×®+õÏÙÄŸ4îÖ"ß/UÎHêS¼“ûýÂÛ~%3"íßZiâ¸T¨fMÑøTOñKÝð¼qí°h¼Ü ©Ø7‚eG çõ`¶uÙ^lwHw"z9ŠT56e¿©""(ýÖIYžüŸv£"šMÑ©b‚m¬f £TÖërk¡ï¾ÂãúŽ–ŒRµ52Òrnºª·¦?XèµÉü×ÃÆ§X#¨…rCv‰nï}î/,ëÔgKÅ`ŠâÖæÈd\1Õ†RÞ™ ^¼ac.ýªòÇÙ›­»ç¯`R’)0ã°Û:‘$ëÙÈ5÷æýN @WνUë’€€¤1—ò'±¹Vzr&ÂU ux[,Žûˆ:ú6ƶŠeNr'߸Õ»[;¾M×ÕøKädáOwoïK6†µÉ’ò±¶LôË9üƒŠø*?¼|îÈâó» ɾÂú’a2”P¬g°VR}¬?Òª')‡¸sëd~¥б¤àá½»@áleð"ç´¶ Ø”a>ßÖÑ*ƒv˜ôPgõªà_ÅwPz½õfôA‘Á745PknF‡ôF¾,85Ö“):ͪ'œïÛéº÷°/PÖpúRÎ)ìÛ4RÛJ¶Y©TãÀ2mƒÃ]|-!’,wZ­’öO×o ÿgn9”ïöFÚþ%Èõ›·ÏÓ„ å°ä©áCj‹•ïi°¾Ž¾ÀhŠçtø«É¶¯³ ħn Y”4?ovØËÖ]d³ 1ºœQI…uj"Wú¾BÕª¬‡ÒÐ5C èš“ÿŒ¯BvMž4.ï™dš»TÈ´)WÞÕÌCªž¸¥?Œ(¿™ Ÿä\üɨF\T—`âš²˜ºåA¨C’&¹>è–ýÂ%ðÅøqEê…[l! ¤±]§o k9b=OS8ÀÊ+9£40• x`~Å‹˜e‰2,ù:d„=1\ VÎe^‘mÔÇ3~‡2BÚr˜lÁß`“¢‚\ieÁÐü‰œ¯Þ‚[g¨ÌÏ#€‚lîXŸUï÷ƒrxpÊ{óÍãìzH9R@÷¬HɦÌì3:«g6ºóã_óÃŽÁ~¶õ§hå­‚—µ²2/ÀÏÄÓË%é,¡g}‰ØvLlZï÷ÃûªEõL½ÚBßaòfùÉ S»V¼M¬£ò_?ö‰@fGïaâ~2‹Ùë^  ´Âo¦^È«Cn‰@VÂÀ8$Ý g½.<¤SÈþÁip‹Ê®ïóÛ^Gd²¹£^*cêÁ‚&r9m¹R°áp“´§¹»'¯­žDG.l°8¥Câ¡ ÛÊÑšÑAzXWM[ÿpì>Øé°É3‘tcoEº$ö¿È#/kÅB˜ž éÁAøàýͨs¿_h«É$!8^—·tÏJvrñhð{ô9¤æh5-´•vœúÛ°¬šÑ¼íîÇù§0kñcX=¤¬E¿½í“²ýˆäĨ$LV·ý‚åX’€€ÔöÐ@obG¦ÄœóœžûœnîG(‡WQ:V±ÙrNÛ#I-ŠlÚÀ¸q®z®ýDÇÉžíX! _”g"Hu9ÇPK$qƒE€ è+ˆˆm6Ò“½îýNoYâº`@œ½PÂ^E K°þ~%5“8Lô1bIcªÍýõÐì2Ë«ë/ž–âf]’)lÑ5†]gžOóCƒ™|½!–…¯fb–Ÿ0)ä¼~+^Rt¢ƒY±· ãØ4˜kÖŽ3;×  >׿v(ÊVEÏX×û&`¦ø/51”·ðW«íØlÑ&dÙÀ˜ÚУûÆÝXýúF ×_Ý"èF®c˜EöL:.|·_¡ HÚ¢“FÒK 4t0@Þ‡„ØM·Lñ N·¨É‘Eýí¡ysA¼• Û$û º;Às?­¦? ͆V&~A?©ÒˆºëpÛþ¾’Â~g—¸ zñíÖ#œ]wüÙªûtMt£JŸéE|¡QFe©e0‡Gt¨•\É—"¤.‚àšƒ·pÁ}ê/õ£;»î{[h[ ýéª;}d~þ‚¾; å¤mÐ)¢ɃÆçS‚V9‹I]d~íj(›RNåIsŠÕ L†“ÚIvbL™¸¶‰§plí®‰–FE…×꟩Ôd“X1òÍWÄqßdgr•àD‚HZCß&;n°m¦ÜÄ꺫–åšÁäG×Nm¶ù8ºÝO·mîµ¶.ð‰#¶¹ÁUïØi´®(䑯*¥&X¤Ù_tÒž•OgV äµ"¬[;f¯_:$dâÝCBÑPêàÃiÎê×ߢw”ÏÜìP\i±Ø"Š ¦%ÿ‘RVr§—‰@³£Òt<è–û;šÐ0ȺŒ¸•íÇ]G÷`(çL™‡AC&ë”}ÞÛ)δ;‡Ÿ•ýtúnJØðF“–9ŠÅ/cØVZ¨Î«¯½ƒ®¤”#,(Û¿¹á÷ˆkTQ M2ùEšß,…š3/™ŽGõtáW!NS#6ë•¶¥áÞoÈ>ã´9¨)p/®ê§H¨¼ ³ífà¡+Æs¶¨?I§ïbCòãž/V|z“,/éjÕа»løF,–.¹ºVnóŒ+`£(¶õ¥²Ñ¶f@C^âQ’Q’€€µ/Iõ äbæB~&ƒEñFî£ÅÊâödþg!µP£Æ2¶¿/153+à°©†˜ûôÒ:ÔåÐc>ê~ºiÒÈ.8w<ÔŒr2'/ÔµçÚZ÷&Œ|»Ò¶ë­/nÔ¶%Qõ Ä൞¶|äg—_ŽÓÆÍržú×%P“½t1Ø>n«|$?7Áì'1NØâÛö‘5w±Í“¾pÛÌÁðZƨ£ì,9#!ㄼ¦édPÀÇÂééÛ¼8¦j€ó{dtl&ŠMy˜±OY[JoÃÐ'Ô÷‡qß‹äík ÌÙC #o*«L*•†î ‡BÂ:Ž‘wjém ³‰iEq@´Âp(sÂG‰øpäåìƒ F‡TŽ Wë›hZ)'h@.Éfúù9àä÷ù¹*xqú³|9ÂCy½Ü)ŸÅÜbå$Ë€“T¢^W,ÓEþDO›‡8ëì)2ÕóØh Ó½y”MŽ0?ï ñ~¬Ïr5¥£¼›ÉkÁñô^¶DY 0/Ò¸»î]½§äŠÆë³Pd&GìÊãËÐgžA˜YE˜ã<ÓœiQ±)¦”ˆ®É„c±§ƒ È[i½½JN‰ÕI6³³ÃÎRd²·ÛKÁxÁ"øZQ™êâ^÷[ΚÔS𑾑Êi«Âw1uE&øpsxâ+íúüø°ÉâF€Í>Ae?+ZΕèñK˜t²"Y½`×lÈÄ¿Óé^Z÷Ee4z!õà¥9Á0Y¦Üå–^\þÄá®´?€óðÛâé ²f“ä%ÝB¿*¹K¸ÞÏEŠ >EØvºŒY^#û‚P]²2{^¼'lºCÂç_"ŽÍôºˆ™áÙ ±‹|)¸šÔ™gv`$JÊŠ<‰¾–ìã0œo{Ø…Ï?ú"•«¢¸žHrdõ¸»]ô¡aÏ;Ÿ}³…bì#žœ ÌH‚PÁ¿´Šœ8ÏÂÎb²x]ØÐýgÄí#®ecgG=°„¾ûØb²Ö ã…B'â@ã¼Áˆ„X'¬Ùÿÿ¾`™EÆ‚ùÀ€GaKälég|ª¼¦^Òqn¾¬§ÄZáà]““Ì^Ñ*S¯å׃Ç\>™âïÔ8ànŸ¥¼À: ŽºäWwU™(åN2a©«‰•Š2=Pe$fç ­Fà¹%îÏ;G[<’’€€Îs¡ÓÌpäÆf0y¯“ .tÜAØ~ËzGñ"ÜÑ…ÛbªÜuÛbŽòUÔÎ2f“ƒY‘Ò0$f &ý2hWôšFä³f`M¦—voqS#ö‰”ïIÈ¢xH<3镊Õqë”' .èSʼnãfïÉãëFˆÙÃo’ÊÕùyë>Ns8­góã­r÷Ê Ö௒œä~€vc œ¶j&Îvú^ Øë[fóY™EZxÒà—µž#]D±wÉX¼[œzL>wG7kÍ(}‡íŒ}5à l3ÓUëdZ»Óˆy;íjêz\è³ÿ EW¯Ê,·ÒëwØÃZ|mT aË’ýûç·„%©vúã[\âÓ#>Æ]YOr½¾ÏÍKK‘§Y,?}§GiÉö"î2ÁóÒiN6wQoï³êÿåÓä(6r¥ mu¢Þf§ŒÃ6 ÖèéUeY÷çÌõÛ¿Kh¬N½EsŽnÁ º:9 pH'ºäÐëñr’®AÇ·â{›GNEèZ봬ʡ,{êä³¶F"r9&Ñ ,H‘”ø*QÖ‰nuâ1¡­Yg›ŒÕÞQGE)ßàï‹n‹ûŸ¿”ƒ¾°§U±L^äû›C‡ña1+Ƕîp–1âefK}É*µ¾„$8š›te°aPÃáœIŸàôÂÙŒâ€?©Zƒ Ax}/›ÐT’ˆáEMBŠÿz²ÏŠÆ+ØÁzHžÖFPûð;‡P;wÏ:ëÝguܯ®ˆ‡ÄœË"‹E•‘ÀßµžÑ{sâþ7Oך£­Å.9…Pè³rwÞæ®yÒ–ßo¨Lòʼ]Bg‡|ABèŸuzxk…‘–m~í/:SÌ ›ÚI2`päFm@<ðH•-œc¿sÔ•Ç’z/8D¼HÌZc´Rº:ºÕÇaæ²ÛBiÄï Ã}ÿsŒn…’€€®i „Œh]?3£q¢MÅç 5 º (ÔÄäp1ƒ¶µvÍ%ËÙ¿©œ©ãïÉâ=f'$EW§t ,[0_I¦<’!ÄnæYŽºÐgÒTÛÕh„A°ãz?¿´µ€[Q Ûû;Ò¯®³«äq±…徨5ˆ‘`wøvø+’*æ÷¦dî:ÒKµß½]Mœ:Ýz«B1^æV!evB¼HœÒþ_ 2!Ûð}!$ö\Ä<ü!Öý›Jš&©D?  ²Á š>§õÐÌíŠÑbƪýtŽÁ/è&#ÛÀÐçÕ×6±]ƒfŸô¤7hÕäëüëòZ«Ê1ýÇ!‚à0ðÕUHŒüä:i—}“GÈ@¨5ðÇÅI=ž£-Üõu¯]ž¼0[0¾^¨·Ÿì­]HmëF·ë»2pguÏ®êç EØí÷†‹z'C{,™ØT¯ÏbéÇ­ÞE/^WnÜÖäQÁù«<é]†¼…ŠÀ%Eú)ÊÄŒbtœÅB»å„tÇÚel ås?a’þÉ·0v¢Ëa޳¤ï ¤ŽCԺǧ˲©hÈö:?­Éxó  Ðï ³ýf}Aw),{U'ì==Rúl›/ÀŸÛé@rkS_úv³# ê´`®À™à\Œ”´xU±)Éí¸â¸þÃv›Í\~rJ丣3ç-îLjLùÖàì1ÎìD¥/7 ¦Í0eX1ÏþöòB›rK½~ëSðʨre£Dæ°èÂ}õßZ÷T¹Ns¸èUK椫€÷5k€3îUîÏ\ŠÞ•¾PÝk š qO†l$®æ.ó? s‚ËšÁâ!q:òÔFjާA>õ/eÏË©ƒ…T*ÿÌãŠã-M`Ngñ´3"ñöŸ6{Æ'*·[ŽÉpzÀÌ$ýlµ3mãäoÕzvjx¨´ŒÍ¢(6­'³Ò Üýƒõ?_ gÅ_~æÑ2çà`Meàˆ_ N•s¼*nrÃî HŸC\GÃÍ)cS%]%íäM/G߃ —˜bô3Íûòx~¸¿È¾¢ñ}ígµÑ²vøö÷"Œ¥câwÆ’d#8»#ÏB×Êz’Ö]²@žI%é£×£)׿sÎ’ô/@Ĺ rjè…Õ¤N±„¿–.qÃxŒO‹PíªS[ã=»³2‡n”$h8Z8’€€Êp¨ûœMn~ú/Åi±–þu¸[üüé6Ô%åø~0| j“ðé¶®w®›hû©Oü ƒ«Œ0œ§V¾âà*–îzùÈi±]=âÜ‘\|möoú‹÷®©ŒQÍNòů$–N¹y”5ÍŒÑsã¯Ä(Ó î侇 `‹öB‡ƒÀÊ@¨œÔ‘£S‚B!žÅbá›é)y°êz:džS䊬@ƒÂÚ¬“²'Tãé©úK²>1,C¬…ÎX¸,­½PlPùÕ]Ù§QåÛlw(ˆÚIxS :qèòˆuÑ@qåºHS¸uúÆ8Öœ^wþ×d[Þèåß æ×%WoiÛÙÚê¨@Í­ D»¼˜)8·+†"ûÊ1å3"BLkKº—‡• „ðeÏÕÉ”!WèœçÆ‚ Wq¢JDXkó?89.$)¼Ïžrê¸NË6‘ID^RžhTz­W­¶àž>í56€Â‘Ž€PîÊk¢oÞ¶x(‚;Π`¿¡%}û ß}ýX»„T‰ë+ œ×:Â'·Ý¿;ôïÕå205»i„?ÎUo}ÖtùËÂX8}›‘ô?=ø¢§µK°²ÿŒ)€¶†áÄÃã Zÿ 4W–‹ m*!,9铯€-q •i¿Åf<¬±%†=Hv¦_Ü–5ê!ÍÁUŠ¿V]à.P…ÓÒ{xXegbuh÷õµ3äZ !ìÂiÚX‹äÏ|‡²Ùög/Õ .(épŒÕ…âó5‰¾ã‹œvÝì]¬ìë1E†ª”šòd“q›a,êLY”ãJÂÎ#®¬<ìY)è=X0Éd¿ÆÿæÜGüoÝY‡IÝ;×' ¥nL«øý\Â01[’CAé!ü“„TM0}ÎüÁŠ!Q5¾/<33Àüë6d3aÖs³”SµÓ£¦<ΈÍ'­ÄÚ@õhì{TxAÒ·?8îÈÚ~ãÙzÇ€•Ž>D‡—zƒÑôÖƒm5Ñ¥áר6Â0׫wx娅ÞmâѲŽÃä‡ ¡¡Kg…FßþrTH•ò‰_\Íõ:Ê­bËóT09퇆ª¼=ÝßM8£b÷Õg_.Káú¡-‚ßã|¼¸¿-»þr)ä¥Ãð쵎e͇;Ò§;2rž´PÜ‹àä=Dƒå¹r—½ßòÓZ‹'(ˆãš’€€¼ì+šÑãú"ÁÊ[ò,C«ïn*ßý-vP%È(ïÀ!\™¤¼~—¾-¼X Hê ë3ã*Ðjáþ”Çë€9e{¶Ü ׃Æ&0÷À\Ök|»‰gtI: êÊãÊ싌´kþˆ£Ep ØBZ汢Ā|Êÿá¹RÛí¬  µn]Ž–¹R–Œ”aø†ÞD†TpTªÊÇXïÊRÕœbÎOÐ]’Ä›ý»d7]Ô¿M_ã¹+¸ ýÕyp÷Ž#ÐO*@ý–E _ q4д/ÒßšÔ`GüŒ9±’ °,) íö¹êV_à3ðÞËRÚј‘)ˆ—¢° ”­{Ï#¡N$¿¶p`‡)-–:ÎÄCÖÈÑ^Ôl脼O£ø§Ë4b~1¤K)P|.¶ïby#m(Zt9ºÂ(¼DŸ4 ü›â¡0–¯™›1\u`LÛ-‘©•ª”{nŦ·£¾Ÿ­Ë…àè¡Rä°†ÅhŸÓa”®í@Å 'âLÎ-«E[y ´¶½e–TÏ(5Þýd²`·4ãYÖbÀøWLÍ0ñ¢:é7Kûc:ðn- œrU)ïŒ}¨9ÑÐ"µM3ÔbÅ"‹µ÷oèÒΫ?±­¢fSãŒg­ü¶Åݳ¥X[weܱ9÷¡)! Ý[àV£Î×>²?Ñ­V #©ß>šÚ‚L3E·Kafy¨§¿˜4 ¤Ÿ˜~?’„¯ÛÝh/ìŽþZA*–ܓ#švÕS}8÷uƒn*ª 0ƶë(6a×RÄEYWr›Wš>®ÃÄQáö—`ÈŸ~Ë;è%ÃNþ~YVÖ:ÍFb þ™Z2ìEiŽ‚ÃáD!HÑð¶ÒÙ¬Ü>¡Üd/‚ƒdÌž.k­4ò7Wa¹ ÷–Ä@;mÌirUÛ(ºž·í2lýì—­=̰–„‡¯ÏÓ_7ÝÀœéÀÒ¥˜Îq‚1­Þs§%y(£a¶ú¼ýÈéaË;âó'beáó}ö M_âJϘ ƒwB _tñû$ñt󨦃Êò%0_7X[çbç°[Ö¨”v™ç Éö?&e%o/Y ßW§ú4AN9ˆ«‰¯_iN,ÂõbŠaœÇ;õ7=Bëy.îštëMŸ¿?’€€ð_TØ’ýˆä—ïŸLGÛAû@Ïô”Sà·¤…—°¶$‡ Uÿ˜ÏÙ¹<Ç–#·ÿ0A':5‰ò®u¡ÇyT“¬G“?}ó î÷]±ƒÚ¯PŒ|J?¤aÛK¯œV¸šh6µÜ9¨:D%èŒkD~/ÄÈlx\‹Is±”cÅ{ªee¼ÚX [rßÖäl'ûöøiªRÞû‡<„½SƒË“ÐÄ-•Ä(z¹Òº‡ãR C¥ùŸ¥¹YÔ‰Rç°={Ѐ9I¡›¥˲Gb¾ƒQG†÷ÍÚx.§†þ‚œ¶&‚ÿÐ\T0j5ÎhUü/ úu ¼d¹"qˆÝ /;Eà `-j¥ ¥°ãËùÏ­´Öæ\«€ý?þI{Ì僙 ‘¨]‘g1!dŽ•=MxþìË8þ$_¨ÅZI:á¢îH« ô7Hv‹bÂÁúð‹š×¿”ì èS&g·\QˆaŸ±U[£Ð‘L}ʇÜî¨UéÊŸnû SÙÖÍM6<:¾ÒWƒü›Î^4Ó´ò{O´-@aëfzUûÊàÜ‹ö½ð0ÆF¶žêÈô˜Ç¤²±¿y;$ ‹iæˆAª‚˜°¦Ÿ`WÖ’hä;Œ,ZTµÚnÓ|DÁǦÉMmRËç¯åÕ4á”ZƸ°¥¹±PáK¨'¬ùIÁûO—û’k‚åcM óÛKŠŽè†ã{|¬—¡f8Îç(âû÷ÚjÔ’Jû‡ý\›ßÞØZ¬ j‚^& Ø´™Ã)¨ôqÿ®Åû`§z®Bþ/çÚ„Á)€™å}x ´aðÒ5#–×ïµB§»¥ ¿,4[˜4Ù»–↿°—¶aôÛ}0Îà‰P1äaÆÜ)Çà«òͲ+Ó¾Ç7óa•ˆù>àÑ ÔûæS=#Ž”ÜZ¯”öyú0ÀYþš.ªìT©ŒòNkè°Ïü¡ÊÅ“ +DšŽ³¯œpƒ@ºEsà VÛ¼Èî²Ö¬Þ‘ªEí~fø^4bPÜ÷ƃè_.:=O0È…cËW¡\5|åè>ËÞZv+i<„ô¤L!WÐÕÄxO¡•ÀQx’ª ðTÂIúa|ëÁ ‹›túî4D õ׆t7×R6¥~#bºy3…dœÌ4Í Y¶¯xIñ¯‚ŠR2[º¥9viÖ~9Ëö’€€ÂQbbâsøÌ$öý»‰§là`-¨ïÏ+r®xs'¶Ão2ÄŒE6¼#›Û׸ôëʨ´²­_h+x[½ûÈÒ¯A%ëÀì‡{ÇCŠvD†GaØïRTÊN9Y†kó¯Híà>š“¬4S™–¢át·ÌÁ൹~èºhØö¯Þ©6K“BXñÝØÅQ¨)ã9§V€Ü›´Ãù©òNáÄÁ4á¯ÔÜ&*2(‹1-[Ô@l®ù½@·½ØŠòE¢Š\K^EeA;£¨†¿ê|é7Éïm—¨ß¿ÍH-h'§ÂÕ¼P¾Õ„×V±#Óå¥ý´ˆwCWêÚQÀßåkZ`UÑC¹3£Â¨&M˵ÈÜ«µÄß_K´£¶°Y€%§ZÉg2'B{zËÔ$€såæ7ÜÂÎ`ä÷µ°8zÝYöøå+ä}[Ì¢¾ÉܨXï‘«iÇQŠÿ7ٮٟ9ù€Èn†¸Äƒq®âÚéE`I’–(ôÖ—÷_…À˜à 9™° Áº¬¨LAy™íìø}Õ¹Ý^R9h?üã¦C5áfgdLº²r‰}œv¢ùw»3=>-Z›dhÒЉS Ð¥’‚})ÿí<ÉÄôsü|\. {‘-)Åi⋊šeND³õÕܧO§…ßàDñ?›½¦-»31ú**g#‹˜9dw‘DñcµútÝ1ô'UâµÕí¯˜^dʱí]ýKÕrè»6”¾tᨭšG̬Ïx µ‘Ò|g~¾ @5.ùgÒª5uN¤Çk¸5ÝœËÃ{úEDgVß’v­ë›²Öc“—Ow.Ÿö¯ë‘MÙüs‘ÆÙ»Ô¸F1ÒchÌöµ.ÿm­îÁ×ýË5ÚÆ¡ 칦MþɢʹgKO…°Ô érÇ^Ž/¡˜Ô,Ž+ë©oï-¥’ïÝößò&9\»uˆ–’Ñ’ö£ºwÒAh5“zuÙOPA:r…²ŠÕK‡£¹ù£)†O ü}0bFS©UÄ2kB?J‰r>ó}6ë X¯ÍëÅø£zƒ®ŠnÏ¿Œâ ¥ñš;|r“BkÆÀ6á »’Aq¹chÕµúQ“²ùM!¥$•ã00äqªÈ:LDú'8 ôà}•+SbÝÇøWÆÁMTU_[̾O2ÎbkÚ*„\ÃÜY­’€€ß;Ðél„¿"Ç&‡lS/bâÄaÃ#@cHKñè]ÎOøh7ãò òI¶®T4¬ÙNz ¢ÐmçÆÁû¬FÏNÐgHªZ¹Šn9å©D+:3â E@U ³ÚŸb?¼º9¡³Oý­ö¥0‚¸©qÓú (4ÍaßEµ“1›í8H5d×µ)d Œ?i±újåñžD šv̶¬H§¥Zq¢P7½±íhE¹s~€ÌØxVór–¡¾Ø˜}ß÷é*X¬F:§,¨yÅ“kã¯a$Oó®ùó)’ü) ™Ž*{ä9즥“ÞE|ð+«ýuƒù-¥LëÜÁÇÈ)‘O6©þü¯¢’KUÿqÿµÉ¥÷ás€qV÷çЩÝ÷_¢³ätßøBÆhoÒŽû,i+·ºìÍ~{(‰“g,^Hú!؈ƒ8–{ª<Ž{›úoÅlŽh-á{¡“U&ù?k0ofÔƒNâãùí¨š9nÕ›FlzJm‰$ÐC}™‘ ?ï–ôNKÆnkÝÒ@zžªPª…‰©eÿÏè )Íê*¼z†Z}£M¾ƒt4˜YøL,Q°.ГyÃ)ÙßÛ49ŸWu`~çû¹+ÂÁå&í=¸ ë ÛŦ"p%—‹ßŒƒDÖó\èç诶•2™ÝÝâuV;Bòf"ž¾K£rc»1äˆß bprt¼;]¸=Ð;l^f‹H+òsÙR<Ù»¼ƒ ÐÔJÍÚ’‚ó‚§´\LRÈi±y\éI†óJv²×©ˆ´&—rBµ4b_•¿m–PÇg¹¥u»JŽO^3Ù~ò{7bœn@+Üß9ú†CëÂbýÚúsüÍðR§;N,`ùø¿Ñ+vce¦O\D¦Í_ƒqÿŽšþ`|rŠŽ9ü…B#';€ETZrWê’y]7öúÙr?>’€€êwD1ûãSRνz7®q=€ …*’Ϲ¯¬¶ÞÜÈÐ&å&û‰øMî§Ÿ¬)lo»¥v¾0{AGÒ©×{A3…щ¸´z®‘aòGÂïÁ£ÖBpcÒhaÎûwSËÀ¶Q7Ø1Ú!;[,<=•R€¹/>„3ùdtÉ »–Çža‡¼[‰ ½ç·\×{˜þ,F(òÚʨt?0XRuWbwÌáûiéYâ¥Ë¸ü-en‘…í©\î ìÍä¤,õTŽå"¿>Å0»!ú¸1Œ¨|ï%¸ñÔŽÆQs8¬Oér“ÂB^_~pÀmK’Ƙò<ÿ/¦6š¿›é‰9>ƒETêkˆ Û7Ñ«Îêÿ»¹e $Ê¿%hÝÖ}Ým¢ZŒ¥±ˆáD‹*’€€ÏNa:ãNÁ+øx>Á%J¢duqડv6C‹i0qÿA }ñ¦]Á‡ô47ÁŽÝòüij ¹0%Kñ«ÅÈ4€ [¬CnÈÛ°‰àï4=‰ï{ÙQø‘÷K­E,ÌO[fÍ;ÇÞNk`¹`ì‹îvî#­ “ø×/†ÎXØåQŽ¢e~nÜþ„)Uó¤…¡:M©NŒo¥ ÔwY¼ˆQŽÊj ”D}ÉsÆ—<ù©ƒÇóÙc0+?`æÅ*öež|¨Õ+Ötòm–VÙDóËÚ $k’ݯkÐgUÆ–Úÿ¡}NªÄ9¡½Œ tŸI4f­®ð"'¶}ôvý¼ÐPsnÝ\1Ðó@&×CÀ6©ÆªùìÚŒJ¼;„r°pG´èAÒ÷°|¨ófhm9Ìq®Ñ „¡ÿ?‚I’јÅkç'Á“Þð¾Ë1‚” kˆ2Ư ‰µWW¯ :6¼˜ ÚÓÞÁü”5ÉœDªs£`ÙúNÖl²†+EÛP„½µ WŠÃ~uFC¿Uj?k.ýǹS½ÑŒ[ø…ydÈz;Nø¹ª°T56CrWÎyAF†‹@=SnbÌj§20t¶ˆ,¼oaS ]ªÌ@5Æ–s„쓟ùë©/œ¤¦EIÄÿ|Õëd2Â\&y4õ٧ʇ.ËÊq̇wöÇ3ì ÍrŒx¥ìî±°G€’m¾ƒae^€ Ð8^mþQ¹éºìñ( 2^ ¢²áE–Yvã¸GL÷w`xZEc8Þ¾[Íç%¡ºw^·°†m¬q &»Š·‹‘UÜXöŽ“ˆ­¿’€€ÐKÙ¥,YáDqŽ9#«Q‚{´IÞ´”J«Çèþ ¼a ºc®ˆúY-úl¶Ú2F([Ö逌}‹ÚÙ˜Å͈øZx*ÿ¼9ÊŽ¿f²SœDM×ùD½î"—Ln”˜rïðv±Ür¸/ò,Q¾]™Õþ…ðyÀTé |MŒ4£¦BaÑÄ2îšÄ'x¥%¸°³EP6íi‰’MªKš±òs冤Ã4SÐGB~œD'˜D@kÉ&j2&èü õ~£ÇY&0cw–å4’šN@y]ðžQ»[³>¹ŽØÃ n‚N‹×o±!! ÔaHYjöMÜüöNCÊ€kH"ðÈ®® õ(ý¢ìqu*…^œbÞNlyg%ñ„q#+¼Âõ]¹ÎKHhtk"Eø/%íU„†0zÀ©J?MžY úÌÑ{qêÅmÌ@b#àÁy m·¿ðm5˜1…ÂÛ„eCfP•é‹Kׇ3û§ùdĘ@>ÿú™.„œO/ºŽïÈä(%ÚGxLÏjëO!#S€£lF“ŒÃÂ,쨭;ÒKÏΣ‡¦Ž»î’ã³€Ùâ}8.˜JþhúJó R"¡®=º…l(Ïñ™×6Aª $Ã÷(ýî1AÝÉÙâѾóËÿ{¦Ÿ´a «;¦ÂT–Q"ÇŒmBÊ$÷|ýJèjѪ¸‘€QCBáá¼5Óì¾!Ükš Zïm¾t ¨£OZ—¤GúVéxcØ«ëÎÁ=×% joƒŸ€˜%‰¡x[Ï|~ ¢_ÌØØã¢å³’„ÎQRY9ï«*8ðk_ž\4/jØã´e4ÇA°¢P½)s]5Güwæ‚9¾ qôú¨J¥lÅd¶ºTI*Zh¥ö³“1;j‹9O“º1ᡊv"ºÕ$2‡­ž,h^Bûãf©7&)ŽlÛ¯©Ÿ²Mú¦ob½Ù,rNpã\IÖ+§S¾áìX©®AdØX¾ö_/îÉ|WúrÁ8\ÒŒÞrXMÛ¥„`k³1Q“ Ü£‰yf_"F³*"Ëþð¨ :q©Vo C¬Ø6ãx“zYmNG\„ãuófÛyÕ.˽”ASnQ„Èþ9 eNZz—­Úªv†ÑûÅ7_5«quÅ—é§&•–¸Ð±^K“kÉÀT=5I;O9:¯—v>ÓüIp}ŸDŽ [^èÒ!lñ”©OøBÖÉ$Æ CžÊLÀ“ e ¤zlSnC,BŠz !Ú±Ö}M™yè|DÔ¶]g7Ÿé¤£z'í;.‰köâdŒZu·„ç‘ ¡’€€Òp¼f±¼}´‡”f™-W1°.¯ÓÙe£ê7¼àÁÛ‚KYDþßZ;Å’²»É4®Ó˜¢¨K” «ö¬!‡YÇü†¤SºËç ‰Ýœíä;²yóñ¾?d;ì{˜ºW%ì6W½‡4ñþ< ¥õÃÖ}¦H½;¦79‰§¤?…TöŽÉhŽV–+ %0&Çëèõ¥BäHãï@ÏhCÄÓÀÜ8¥Lñ ž'gÊÚžÐ*?ùFTËzÝš(”qˆ½D!ÿ[Ie’ì*d¼Ø·ÃfY×Á<_©Ÿ*gýHz·4‹Ñ›3R<ú¼W;Ðø¦>„œÛqš<¢~£ªšçYA¥7EdIã0¬†ž{DF“yéŠéÛÂ2? dmÞÙhJ?݃DJ¾òA¢¨}†${Ö[glw¡)•NÛ®‹ÜAsîèG·¢˜}PÂɽ…å¥4º&“¢ìÛöGbT™3¦ïÕL­Ñö]Ä´rʾšA€ÌV·@‡PÝ2!n=Ž%¨œñ&?:É…³Žé1ÒVkŠ<ì Ô‚¶RŸòÌÑ¡ªgrØã~µ×ÜLlùÀpŸèÛ,‘±i§éO8¹ÈºžE§IyA ·×îT.ï^.ÖnݿŽ‚5.—A…ð³|¥n(˜‰>ðÎh[_‰?2®Ty:©ËM®KNm’aÆ«ðÑæN›amú½yÞôàmô…©ö— f,õÛa¬‚JgœˆBYhJ}¿Ó ü=ã÷¥ksÕbÓé2RÎ/Z ÂÔv¸N'GDœ¥+–æófT2o˜t¦úŽ?ä6>€YzÉòêc©{E£Gvv®ú’ñŒ¿öÕ@!Eõ*&†»/ß´YÜ«ÿìàW|Zy@G2´”4Î7ìM˽/‡Ø?·¾uÍÅkñÜJñîW{»µŒô³žðRÛD?â'ÜGð¿f„.@úÊéiéß ´eïÉ·=÷ïÍ-›”Pí9Ù"4>J<¨ºÓÊ£cP/Q]ìÒ¦ÊÖ4ò°…¥a•b kUÝýþµ1ÕJ«ÂkÊWå §|L¨r0 ~;%Ð,Å#a茵]ê‹)è¬xÀ•„•.Þx>nœT€ý1)õü®Sœ†8¥±´¨X-îX¤”Ës^UÜq*9¾á ©—–æ ÷ …yÈiX'°üòÕÒ’êFÇᫎ/)óÉ’€€ðú˜aWWL÷ç(Öû~pŽ£9Am- r•ù×Ï`Ó}(ùŸúâœ!ÑÀ¦*‹åƒº"5Qò‡0b0) £*Ó$‰Æ¨ Xâ0 Id)Û‡ò¾.ݰ©pö]sªÎAmp(ɘ6<ÔðXr|Ó?çË!»jdÒÙ'ôæòu©Áü„zA(Ü–´jüŸ¾L ææ#‹6rY>y!R'{EOÞÊ¿±ëð`‡2…7©½¦ïC®Äj t²¿TI›¡`œ³Ð;³ff=šùÐZèÈF¨|ˆH÷Ø6(À$yJŸ{À0bIDêt§îB¿‹}dH–Ë'™É&ÍÍ™xÙ .p Õ°,3M1‡q°ÂØ#ÈäHG°|þ µcqP¦7!’·¡á7ƒJÑ£<‘Ñ‚¦£®«[¿œÊ¾|$Ÿÿ°lÅ/FØFLp"U«½I•¬pMˆ),Å'†Í¦®\ZŸEF[$q ºä#2Æ[ƒ˜6ðXŸPüJ¶àÅ„ÛZÐk¯'¸‘[pÑ; $«r6Óû¿ÁVùz¢8CÄ‹(Öê¬ö‘Ób\¼>×N ¥-ž¿må%T1ú±é^äA"GBt#mu¿>,á^S¨ácë~þ•`Ç€üÇŒ‘ì“÷ Œg;ûÊÄüA·d¹Íþ²j•Á,¾Ìü=–ÆZà¶»°Œ™›á8 —ŸkÅða°ÏsQoV;*ÐZéOÀ\g=®?‹õºÉíê™nª^—A‹]]6:óÜÂÚš”PG»©‹ ‹¬‚[lÄîlò?‚„Üý}p"ê<‘–.¢yƒ¨ ÖyôŽ DL—XÀ…g­ívçãçÀÒÕ°œÌbÒT·t‘ø×Äßq’óæÜ¸Õ]Z¥ÏÊüj–bß„1©˜ã)…pëÓÙV»ŠÇ()¹s1¾ËõÒwxb{“ÞÍK½Á2ï"qVµêQOœ1Ù•víþ’˜BæQ!—•ŒÔV&a{q&’ž›fÍíèüœJí$7· žV3Ѓ.4ðÒ A6Ç ØŸK;È×;Mßá®÷åm~–:ŸËËå¬9YTÀ×é>ÇFpÆ¿ô‚½/¼68)$òeüÈv„ï|4ØIÍI/k<¼çž®¨oü¯Ì×¥·¬ ˆ~N¤K¤ Üß g]’€€´3ý"ÎÙ›¶óåÜÿ¡`˜#YÛÆ¿Æ”ùýüÆ vOVšEõ‚¢y¤qŽ$cÑ6l¡¥E&‰ڀQ(äÛ”0ÔcÖ¨&¶ùIz¡ËÍY³ÕüU,öø“¥—˜XH!–q˽+†ÚyƒBk{ájJŸw¸#9³õ?dçã›Êqï;•$´¿ôäM€á´Wª˜HEPòÎiþ ƺ½IwÃØäËÃîzT9ˆñþæT12ĆÎ:epLêâkIʸÁðÜõ^°/dh)sYöÒêÓäî¤é.f\;‰>o™Á¼BÖŒKáÖÞ:æÍE=((OJ•¢5=Õ/{&.ѹ]«3ã$ÎA‰]¤ÿ¨×šGã Ø®ÄrUºˆâ/L—›S´ãU¢ ÖS5y ΫVcbš™Hy)íˆIÝ›:â‚Y²Ý)Ñ_„вÀ²~ÝêðžC£À“J‡‚ÖÞžFž„v°o±E@V%“ùŠŽ -¬X{RëÝMº÷“k‘¥+ÂBLÅ• 뢤³þÇú°píð6uø¶Ùü«,ò;Δ}m@äè6s_Y ï¾{ÆdÏ“ô.*$'U‰÷Þ.lÅ¥;gmõ¡-¦[9p­²IPƃ<+†D(ŸkÚko²Ö ܲ,zű¢ö䥞Ž=Ë3Þ䈽ÂêK¨•o´à¸4\M&\ÕjB\`#lßß göõmÿ­O®|}p»X’ËÍu$ÉžÑ/¿ÊipšMôn Èíìb%æŸÔç‚’qánP ÃÍŸÿ¾{eP©úÏvŠ/O"`œ€gÈ­ùs­Ì¼¡ó,QQYÊçŽp/^òcéÄtXÙä¢ìhu¨eëKªµB4w ¦Ø2±™¬¸ó koZýséC,`€–"Ä…PÍ Mæõ賨q+ÕÞ8‹³ÈL[ßB¤+ëñóý8€ùÝE$žkmÍ@ÿ”)ŒóÑF3ËxÂ&ù&²&çyÝ‹^÷^—H¼¢^ Üã+0’gn^ ôYËþÀKjx~”Q¡2qî`W;­LcA¢ù‚Ðè—ðâ ¶Ez¶ûÒ%—wWÓ€Wý)'¢¹3‚7¾r;ž7þkA3’€€šÌX«Íû®˜fÀ{NðÃá…êÐúÚÚýUš)©Ž'õŠßi9°»ŸL)ú’åO0ÕáJëÔWÚ¤[‰g;€«ÐÍٱ܎¸/¾j˜ƒkk©ßÖ(ŠÁ¢T3™%eçz’Ni¢,º“Í*Âq— P‡Âî<'sKîê©M ƒUœ—<‚ÿTÞ®°¹¶¨™Ü2d?D»Â¥Bj M°aUƒޛ͠뛑7 $Ðd¾3Är`L÷CJãä®ÜÇLÞ^&0åDsƒÃI°Mç—,_„r!›aÂuZ`p¨·=tPÏ2Ål‰ÊRÙU‘Jaœa4R©£@À,ø(¨VÏÂã7 )f§sNݶFõ¶0çËfa:–:uDrW gúM¤û¼òXhF‰FÔ!åÅøz eÍ oÒú,n{´i„Ó9<†„ªðÅn#Yvès7ŠŠ* “e ây §u©õ‹è½ôý›¬è@ÉoY7²°"À+Ï<\ ¡•§dã"·'{–ã=s8û4ä;ÓYæ¢Aéjóf±7´dÎÐÆ^'XˆK˜R"K;¦1û±… „wµÔIéìÍ ¹%ÊßÿôÐ /X\Ñ÷e?¤§;ä0æ|c. ´WŒ½GmåJZç²ÑM~[“"¹£LwÍÖE”;À,È:DÀZ]C ”¹•hbáyBß‘ÛX†$˜7g(dd IA` G±­2©ÁÌXlEÀôtj?d×­Ü«"Þ¹ÜÁˆŽƒ­¾_sññ‚7‰[¨ú¬÷úTøh¡îr°±‰\‘ƒñØ •.›&Qìl«j´üô0n[®h£}À…६¢~„¾¨p&ß(+Cxž«§º§žÕßàYÓŒã%9r_?6­îNO8ÙJ3LEتÆñ³m“;ÿÅÑ¥Ù…åÇÀë\­hÁ|ܤ–¿ê&°BJ²•Hâ//ÏcpQ-/‹ŽÃ„ÖaÂA¤Ð&ö©î²ƒãEËŸNŒâ–F)„V—~ðDÖ³p+ÕøØTûqÏØ°kpóÓÃU=(¶&'““Fú£žXª,cà`×uǰԯ* +ÒZX•M¶0lÁùòbgßWøÜ}„S*5ÙKuºØa¡h·Ã`Öps7Üaë$W¶•Îsư\¤V:W|Û€’€€¢9»ôÜe¹9/Ž]±Y7òl¿ Î¸Œød£Ã?3œïÖ×¼ŠLw3ë”Ái\“u{«ú¹±~Sú¹oµI¹íL¼R"J…Ê¢®€t7ÇÞÑ÷mOœ7Áäߦ¬*éÛžXœVe™¾|e±çä›ëõ‘:»_TŠé­Ý+øHcÖKÝh°ûŸXÊùŸCº4ÿZ±õão‹ÀÓÅ…†—ð«½/ ‡_mXaóê¾-uHè1èjvF8(8ÏeÍuÝ"Å@ aBÜDª’IïÁò…¨Äì0yö´ôSWÈAü ñhHž—4ž7€à®;½ãpV²µÀ1Ÿ3qïg ³/Hl7›8½)â&‡éȹ'ëì‚ ˆÔ¡¹,‚TžiÄÎ<¼5±.?×ÌZ§«¦b­‰oAÊ#ÐS¡Ip'ÚïžO­I²n¾„ Ã2[|¿9$OPþªÈ¢FîÖª­Ä;&ól¶œªø¥ã©é»RènênúýEÖŒp•âÑï%AVh¼™]«oöe…Ëo·“RX¹ö Ï먲®Meží4×­Ö‹Còߔ݉GÙ¨cÂuaéÓ`š±ß¹¹w>¥jœ ¨›l¾–Î'q´[ß<×}ˆG`+üÆ«÷NUêœOMµ)#…hïŽXaQQN$W“¤¿B­ÔO60ã{­/¡ô`¸Ê_é3ëÏ/÷§3;Ù62\§O¿ã,NÚ’jÇ(íÞ¦üRYË'ÿBŸ½WÑJ¦È2ÑMñ1‰‘R¨P7 æ ²ß" +͹¾V›j̦Œ÷¾±7ÏÑ(ï VñA²®U`gƒ-)gÄ1óµ“Ü…‡É÷:OJù³Ö佉H§¾aÒe e(d׺ o7AeÄ{Ê•'lÇͦ¤«–>&@¯Ý¿t9aKGk·JdÌâc—óXîheÈžÍF%°áˆ‚$i¥½„.˜£û¾³œÈü$¢ôö@7q¸x c4#χ[EgÆ/îO¡!ò,Sìt%}ù¾óˆŠ›ß|•a’ÖÎŒ¹¤KPM¯Öñ¨’¬áÑm‰»ÀJÄ¡Jùÿs wŸ¦Ì3¡pç!Nh ÀZ{\Ì©!IKÌÓ8+x>Ôà1Þ›®¯jü<0j  dæ±­ÎíÔÎÿn†( sî’€€ÚpŒaSïËFó‘s<‘ Nå£pKÖ>™HKy‰V=[Qöã¨:Z,£œ›·ÀHõ¡º¤%wxS¸ÜññªÝÐò©´Ý\âæ#¤Ÿ¥®¢x}+rÀ;Þšø ÉÓ5ãƒÖŽg­V^¬DçÑFù8_‹gEaÒÐãyR²•’Í”ÖƦaŒ!†ÆJÊônî…Æ0†6´Y$Ùêô´¨i+lør=]ò†" øP&Æ ¼F6%¨}#S.ñõÁ•R¡ý!ßW*wÅm/æ ˜TÑþß±ºž²›oÓŠï$ÅM')2gž…·¼i·+žºóùÁ ¢ÄÄë³ÇÍ8,¶ÿ]·šwïæ¸ŠÇ‚‰ÚÓT-‡BŒë{g¯íË0hl^^]ÃÁ¾9 Ÿéå[’›B¸f ¥²o•Kf°Š`õ(Ó=‚W…®?*>rþüQ÷ ÉB1^†'gý¦ €S7 CÜÇ|‰÷‹v]^¥æ˜‚ÈJø’¡™4äsWµ\Å|ƒsocv¾óŠôÙçY3X¤6P~‚b˜Ã̵=Òö¯á ö U¯87„3NBbõ¥ÿ$É`?Gj+„èÝôm"àýôÍwŠªèÏv‘äÈwJ '·;†ìL3ŒÌÒ;8ýuÞª%Ó¶3bŽÔP˜›Ô“_/¢—ÛP^ÃØœ· Ô§ ×Ãz¾Ínàžo”d‚ú¿½D׈œ;º?oî/IŸuà\fl´û´é‘ÔŸ;AÿÙÊ~àŠé"wßZT•È#vÒc–6ãa–a ‘È C‹nàߺ©>íe˜.é&¹ao}î›»?µIÊ’œpKZWÕŸôWªGÜÚ).1À-»\"Wi7ªÍ’CI´mr™[AÔŸ§È<Ý­ Z§F~œÉ“a‹£[Ù®yÑ®þ™Õ¾õM‘Ò¬¶‹¥/^8JŒJÓ:G¼Ös¼÷æñ2b¤Ú&•¶^ËI˜1蚟‡ª’ {æ?ºxÙ£9Âi¥ø¨ì,qT „oÞaÜJSc©1T•-§Æk)ˆzú¦ sÎgÌ<-¤Ìq“ÒÝÞQ’€€Ï•SÓô­,5.ï­ÍG`¬Å;äò ¨EvÕÇã´>—¬™D{2pè‹Õ–6˜²×uo¥.¦•AS¥GUS4ÝÊìpv´-‹–¸wÿñG¢+8µ–þY7ã™Gb3%Ã]ÊBñVAÙBã C}¿÷ã,ìŒÉþ§°DR̺ ÷9èÿ…ÍA§åÇ0~S¬¶1íûJÀ¨wë°F 8¢™¡¿ðѽþ·Ì§Šýk½AdkÕj~.lBl•|x8qI6(\$s17u¨Ã!¥šE˜wÒ™¬k£8Í7»p9ã¨í—¡ȇ5Ë¡Q‡ótšÖÂ7«,èú—Ç"„\öqìw6…Z@"àÈ_Ã.±€ÒÍ„yì$,öÒ¦µ¨¨-1†€ôæMA:’3ÁlxÊ]rë"ªB í5Ùu‰æ‰ñG_ì•lá\G\Ÿ~ä^ltÛ5Pë—Rÿe]¥•?g;Yo³*Mýªshý['}¹@Ãáµp¿évQLâÊ ˆ•»hÁÌÈ‹âÃUÈЫâ£B¯?4 gˆ§®Æ¥1ðÍyÒ,_ã¦ôx4cê^ü£Ud6<‡§'ߨW˜¡‘l},î¦ls‡?ãªÁ¡êö¬MÚ®#ˆndò¨ò¥/°c—îê4Ù‰óõŒ›!ÜiìºÒµ“Té¯Y‰÷³w$Yõ@‹ 'Žy¥  Nð(˜q¹ŽÆùàéŒR¶KŒrôzo¿7°Ïf+Jwù4v>îé:ÊU' ¶¨àÂ!ˆÕE¯÷Dh{}xñ5íÎÛ©&S mÝý û¦…ˆ=a}UNdVgØ5ú/Çn:R[ ÍeôebVç°óJÁÙØ®.†eBšñöN*ë[ö ¤Pö«2](»X_C² ¡Þ^àÖõ/Bh¶ðÙr† tLw€]Ç©a/dZ2³a¹ÄDÄ?ÃT¤œë2îÓ2%Í.ùûú…ü¤Á_â¨Uñ¬ì¯öc{Ì/R´¦ä"‹ÊqKUxi‹T|hnñ‹ü«íÞÏI|ë3 Ë©ï^äŸÜ›²šùSu†+QÜb“ ¡èw7OÑ8„Óš:Í»)@—oœ/eNf²ª”ñÅÆ`¼òJASh¢fQ•ÑÌMÈkù9jªðEôÆ´Ô¦Žzh æ:N~E[‹§4˜RqÒS6L·û”¾º_Á‘x¼’€€¥†i¹ÐFWŸ.%: ³Ð7¹ÆQ”Áí ÁM ²@BTÖul/‰[Ÿ:¡NˆIéJÌXœëqa¼ÈQ2WäùâØÓ:„ =“°D‰ãvžeÅIFk}ýž”‘N¹&Ìã®Ïs0WoÈ £¼;ÄN/”‘è„Hït1ÅoÐÝD£Šoe²¼³%Cî$ÙW@!¬/¿ŽdÉ f*;\ °j”{bâ«å±N2“áOÀ¼¡±#ãzJØË²^@–[É! åÉ=‡Á¡È›ùFÉ\Ø{*»KëbYEuv¥ŒG´{êDÒ$:cB1ÅúÊ¡¸F8ÑÏ á­ô»·åÓç¹ ý9ÚLjPvjñ«¦Þeìç –È»Œßð‡NôÑtÝqHO bÆö cëäòAÖ‡äHìD¾xm-lIó2Æòγ|Õ¨IÎó™jõÀ­_ÎDYµÃˆÎWù8º—!óeGDúÓpƒÝÿšçë³|¢Ÿ·ÖÆhYlÔ.XþÖK vSY׸á¸Ídl"ßîpFJ{ PáÖâ‘àtBQ˜R[ÙPGhäg¡13G»a¹WFm㸨’uâÎZ¶¾Ÿ_#P ¼í<”Ô§’€€Ôï-ÈÓu—ô’0ö-h2ñXŠÐ߆9PÎÔ¶™Ë5NT¶òs‡¬ê{¤ŠhY÷€yxâëG\¦”ƒq Z测‚÷Å~[8T½ þäTdáü’7B·Z`´«a9þUùdƒ0¨IËB:GܳZ¤öÏtZƒŒZU¸À•Ù Ñgë²c;ÿk7”#h!í±3º ¯ˆÌÚ™+4a†Ï˜úôª(G‰T ‚N¡q|ölj8æ¿]Ý£xi´¹k8dêYËÖP@ìöÐ쮌߰–|òÅ<ÞêÁ¦7f¢‹P_-ñ:³#V»Ñd7&[󽜺ÙhIt[¿w׌ã|?ȇ^tUL^Š>aæë¸®wõÛ(.ôеFÓåklP‘(À7;/КtÐѦi¡´cq›*œ¥ˆ™îª½dÏìë58¹‹l¨¿”›ŸáËÉ#~ú"y°6$hþGX’;‹²`œMk‚q Ç8cƒ½1ñÙt=`CO°•*åƒwVS¶3ÃB01Àx¢ƒÚl ¥ŸtŸ\*ËŠ¥eƒµZ΋}Œ× ¸tJÑñïÍ£|n‹œ;9ò͈m{0ìëb¤Xô¸ò„ÿ'b Deµù'â_×+Xs?âÊ ;SêÊŽÌ u>Ë&¯ÎN[½1­äô¹7r,R5ó!¥%í»š9]þŸ½§"‰Ç$ ÖùÂîXK·"xí^Œà¥þ~’|7%¢æ' ³]e»áOÌDVÙ†˜ªBIÛÌlp°÷¸Ì¥AyÙCVô,mÉgÒ¢ùKm@vù¼"Ëš4îÐ" ér•gõ4>Z1T¬uq¸‰è:ÔíËË·Öö$…Ö ö Ù+º¯¦kèÕ£ˆÀ¿‰¤k`%¶çÝ]ð4(Á2dzÎ:Ý@X µ¥]¤úo§È³ÓŠ™Xܬ,—ìg<œ¾­B\ÛGiÔŽ¸¹@ ”ZLV{Ü‚©º‘ÖÎÕÂ"|W鍸n32¨®ÍÒæ,;®Æ“à-.,zÌ?›£f&®£þ¯¿b°ÄrðômHPD`¦à¶ñÐ>ë¥7»õ8ˆçê’€€ÑÙ>å”ì”ÃL6›y -ÔQB©"ÜÒÚEË}ä9V.>ÁµÇ&°?ïÖlôtÇv!Å<Ü)K«µ"8õîÅ”Y>*Ž1 »s­ñ%Ý:¦Õz ÙÝqv ÿ(¬Ý±óØ}´¥rà„gûG»ŽmÐ €U°—_Cj±]%Ëù%¢ÌÖ©¹­»¡®@ØÔõmª9¡ä†i`j’•(R}/ »¬jí_7| ‡8¶ƒ,yÝ#Ïv:2?ïljù)èú®„M¶_šY’`G£ãå?f^;!Q­djê/ó_&~MNq£ÉG+V½ŒZ÷{Í\уÝÅ¥IûZOÐ PI+-€¹(ÏP-¯”ê’s«µJnœmaž[¥œ<’û¦w£ªŒî’jòŸsÿx½ß–0Pxr$YÎÜ÷$R»=< €ƒ§„¹Óˆúàà:Ø’d[t,S'&9&œp5züÏEÉUbŽšÈÀÂåKE‘ï(¨ð)2IŒ;†^tÓh3Ìýå¯ó«†ÐjÓ"VI¾aåçÞÞ#Q.ÅÚAçC4‘ŒäUrØÖðævØlèDi×k×ð›6sü«Çè›v$zÓã¤v”~’¢êçY ñä 7Œ­áê-ŒïCÖ‚ôü…VºCQð·³ËCA`ºj.%]û»0|TÝ®f¶2/MèÉqŸÛ ý}%>×í• c³º;êíýà0…7 ûo`41šÀêYa\Ú¸‰MqÂà…´Chss°~2C­´ çtÍØ ÕsÄdkƒ¸”¤ ‚¥tzWU6‰Ä[2RÏ{Å4hšoV*xl?M?Õh;ž?Ñ ä鵿9ԂǃûtöŠY§ÃH`aäêFßo7u !š™`4Ð7¢t·‘c7dSD Ô{Z9Û<Ê'*à‘µ®q÷Íx¶(“§â÷23u‚Y²[<©4:°VAˆðs¾ru4ušzò.hÅSÝÊýü/w—C ÆáÂÚH­^ìC{?+×^e•› äìÃ/¾4(@Ö›Bd¹H=GU•¸_YCû¶ƒè΂+A™SŽ×)CVü‚3{K×z¹¿ÃEüî’ÒFôRzî…î0€µ“éU—´¸SØ\€çµK£×´{ô“7ñFõ?\Zü¢3ù’€€²Ÿj"øÓí •EeŦõ[û4D+ñ¥³,Õ6p†ÂŠd§OKt!²”Ïõ§HÀÓŒa«y660°º/F¿^#Ù¸ M™UýïÊ6~ÙÌñ.ï7#`ÀpµnÌ”.ÿdÍqåÊÝ¿ïá wÍÝqÞ¾ZèhZ%óÛ%C¬H ’¡4¸ò( 7ÖLjŒÀ¶?¯ÚB¢ßþZU¬ýÞ}}”3´'«'ähÉÌ\ì¥ò‚Ê5ÏÜ”iGç®ü™kЦ5èý.ú“_€Pšò~£<¦ròzÈ­ðë2¿UÈi˨ճŒ—nk¬; Z°êØvÿ'¥?s Ï’÷ŒŸµÿåðC´ª×VÚÃá [´"Ä5‹ÂÛ8÷j@‰%Âé&s=Ф¥±xviåæ˜ª&6ï,ÿÄ¡šã›r6o /Tmž47"ÊV"ŨG´ú¤²îl4?r ¯¢À.Ìæ öoü¬A´ÃÚA‹ÕŠhfÕ×œÚ‚áæ†Øqç»@¼#ñDµ~ÌAÖî¯ô.ÐDvõ‘Ĩx›ñ[$Öú¹Güga³2yû€¤¶çU‹°Ýš"r‹z˜a¥æÀ­0Ç—uXƒÓ[²übÓ$ç·ÎvÒ¿ç0½tÈ ü3½•€´³Ú‰_YL­»E÷Çû]á|›¾’wIã¶RÉÀCÜ&Þõ6lþ¸{V>ŽþÆ´²l7Iõ©ÄÓü5o£è(¤Ÿ‘˜imçL!›û Ýr1eÔó¬êÊv `‰w‹A€F]ø«‘³9%j¶ó@€GŠOõ5^ê|õ` uÉ8“`!3ö‘†Y\7È.M –|fFÏ«c8×óW2¢qÚ¬àfŠÓm)@Q/ñ£žqklቇ£…þ)¬o©íˆÅгbÏ¥¯1‘µmêÚ‹d¢0ŽéϽ)ËüŒÒ¸†Ø%>ûF˜$†…Û…XÚõÈÉGÊÿ–ÚÑþ9Âò|+@Ý‚s>ž7‰q)ȬÐËÞžï‚<2Yªf´•nw†øš_—#ë´ÖÙ[}—¡'ÊMI;˜8ó¾ò€!#ÁmfÉÒÞ}ò8ŽŸhމ˜×ÛyV«9t'"—~ç [\ˆ0È:g×Ýñ}Ñͱr㣉ïB ·èiœ‘´ZQw{¸1…‡u *O0‰%,w’€€Ä€0JÞüë¡©çhXâVlæž´„ãÖ:.pÒTš2Ý]o¾±—›‹”Óš œr.9›Ô SzxLüCQ ™=Ê ?ò—uc´8Dîwlíª`~*Çn¨0˜à_y…ˆ8'q”¯F4<Ø÷–åU~z«¹é ¢ñ›7¢{œ‚ç@ë ~y°»Z|RÉÒfÙÔO¥¢1”4‹g“,F·b±ýФؘ {Í©Œ°Ç%ùSgçQaùQCVÒ¹’ÞÎ’}äÈâJ­²…¿_±2ðr“#µ¾ë }dK‘Ö¯ÜÖx"Öý&’f¾ïs* L Ÿ@k®üØ*Ej¯iú=W†™Xð(ȳ›’V{FoZÙ¦TÎ þ£úØMý…~Ná5l—gýƒïŒ,»A8y¢ä­¬–”ºdzËÈcDj­¾ÃH½­Hö+‚³ž†äñ !ý”ÅsIØÙ[,×g6†ô寍œÄ8ʪV ŸÄ72‚_7ŸytËM6˜åÁZËÐæ@ë‘~Q¤¢È¸Äh?Îɦáq]ÿܽܥ/TË?‹=´ }`oƒ¦ä½…V›oÎW­BnÔè|ÞÎHòò¡}K!ÔnRòäï©p<¡A«´ òkžw#ůôFG¤0¬­Z¬]ð÷¥ ñ·ìUFÅÔÈáâªÎœ’€€¦Â’d8-²\÷F±ËÃù¯v>#Ñó©èÁÓpõãþåiøßƒŸ9‚ñ¬5k9†œ"Fj’‡kïÅo¥(GÓ&a1©J3ѦK—0×Ⱦö *Š8J¸èÕ%-îx[ºáJXŽ')ÈÏyä+ò¿ˆ3ìž,ÞxÕll+à Äw,έܭ38uƒÍŒ³­ 瀾UóÞŽœ„(ÍûƒÔTanG?äE1çˆÕ3¨æœÏRo -ÌYŸOÌ7Wná“ӽةùK"½¯V2Ï™›tÀÀ2ZWu—*äslÛ°GViõ[XÛ~$u§ìÝ—£»\¬‰£/Qód€âžPl¹¿©i‰[¼ôNKp´/Ú~¦ÍPÄxzlTéYÞDŒ·7ÆÉ›&}/=!Y²QÛ^U Cqæó9# ÑýÇ:†MÛš„ó&˜²O4sv{¾¨¿ø·î:/YŨØA¾o½¾Û|B¡rú•½#¼|Ôˆ—KtO¿hÁßµùú ü×·4…{?FXy—Q‘ýã~Yš¢PÑì`„±wVry²6³Ø<~#\F& °’!³â˜¦d†»¤lüZV3œe=Ò¿¸#æœ5vuÌM<ɘ‚ŒºÿßM¿%Œ¨å9ZcîG¥:I•¶›# Á]S$ "ñìM´q¹ ÆgÓ‘Ôx*ÌñX¦ßJ¨®Ñ\(Û°Ìx™àua'¸*Í.mù‘° ôLtK¢GìÄÐÓ'é—¡/Á„ß&F-¯=ñ¿ ùJ7}¬ÊVà¹Ô ÇKã7åz+ „Ú묗ž'îɽÐ})vÊáݧ½ámÏX d˜Xgƒ ·lÅû9Èìý<2Q4çqo¸J@fËœú&,zkXš´G£ê®Ä‹ðôŒØ,šÛ‹ ìpM§ÕrWyÖâ§û(·m/Ô3«¼rd¹S[x%ÔȱD××¼Ÿñp£ÛiìÄ4}1ä[™Î«À:ͲÂ6r^%ßçhš-uÏæ\ ÙN¥tMVÐѳi¨³ ’åÀX¼è76-DK‰D¥Ôýq¡¾ýÓÕé‡w îÊ×wªpÄmûäUŒÆÍu„ë¼VT¦¾ù­¿8å¼X¨ñTÜm²Œ’>žõ.7ªêçÓë+èǨ½»á¥uÒÙ—ˆ;®…H "›hLý%Cè—ž<²@O"zZ®í’€€ÌŽÐëÍŸÒú(¶¯D¡L!ïàs³YNÛ——ì.ëÁÿÁXXò*÷h7gš<ÿ·¼KLkÀ68ì}Gëè7Ô¨šd²lÑx‡¯ÚåO¬%†=Nv” Š•8U…b™ÓÑÈNa5?3´¶-§-~Ï0Á¼Ë›}–Q{™èU ) †gçÛM×®¤‚ò„¾!f’NqÖôþÂ&.Ô:œÜV¸ý• ¼CqøCT˜­=݃‡ð.M¶;.ªV¼ÿĦ÷¥¶a >§/è•ÞN?¤=u*×LmÿžôÐÖ^È 3r#ƒ$=G¹ðú¸. ^×M@ó·EE-xB fôÅŒˆÙýݦռ§¦“Ÿ(¬M̱E±õ±;®™?HÁˆÓ…­cפ•Œe¦Kñ¾)»  ¯Ú× NaÌ¡Uç)èëvãT=©.Õo H0»™Z~÷±öqº\O¥fVlàOmÁTì2/Y¼üùÎVíûB#>€®Ù8ýÃcˆ*)¿ o‚k7’h„y)ØXô´¶ò‚®ip2'l-dÕÞ .…£¶mDg áí Ñ[Á³*€"ªtHÔ ŽŸ§„¢»]¤Öô,*}V[˜þzŠ¿O3©B™\iµ^.A°öA-5FpC_Ñ¡B̘®æê™yÃD™ç¬9~˜©·šÚ¾ ]u!l¤+6Œz Bwou•V"›ŒÁ‰]»·¹/J!ø 5©yÛ“@qx=Üøçݪ‡Ìz¬9aðöýî^ª‡×*¶£r_öw^¥E‰®bÛÊüË“-ׯ.}ØD‡.£¾»Fùñ»oˆ™pŠËüÜUô¸!¼’N╋‹°Ïv§‡©[˜ˆ'ø?8ðV)HPÕ–º…i‡Mfx'm’'è©£Ô×r7§%³FCÅlê›A†’IÀÛ‹ 4c€ƒ0™õ%K%ëC åë×ixå 98 M¯db=°[Ŧ’[¾%à…ETêl.5’€€Íê"î™â “z? 6{)Ž€ÖÒ Èý°"¸¡pÓ7_#å1ÞÑö5¢[2ËTº« qj{½q}ˆ´‘QD¢U!£ˆÙ†ò‡Š;?q©sDYg˜à¡aöj½÷\eËdƒ è]C•u°öbþÝG²¤6€† y:G)îåsvl|mS}-LÊÝnqã|­Ìh—ô‚@ êáy,yx^‡Ò½¾Õ0D[sX¤j„âÞõHÇî{®ášãû#Aë^±Ù“f¹H¬Ë ‡­O¡iA™‡¾C »˜ æ¢ž¤ËþóªŒÜBÃgÔß«½q¸ÚÄÿ»Ÿ+a¦¯…¹…ñ/À~ÄøQÞJ•ÈùìéR`÷3±“hÙR×ì°’kXÏªé øÔ²æªGrÆ%NÏe”ß@ŠÙ~ †‘†Ù8笉lÂ׿Ÿ.ð\l)Ú3?”óñ$ï­[ }8]õg¯K)Pdy úTŽv¡Ai‹9¡¡Ü¶h‹üç ïkÿ³èSе¤´¥åßåä%n&’ŽêoÖ­mEM¤¥×Ó`Bú¼q÷Éßc÷teÏ&–'›ôy*è &÷>Ä/_*ÔÒˆ[Ì$ Îàßf6Šãc¥ç’+&1¨jwg™¤Ç%t–T‹á.k Nb˜à `–åàXkúOÓûü±cë§q=fÑ46Ê$·ø«pïç[ÿÉ_ ®w7‘%¾;hÈ"|íš,§ƒ€‚Œ¸(ñÛŸH£â –òkäž6‹Ù|¨<ì ³ç¿îY)RBaj¿6 ¯<0ž–wºGs¼®9¯Á ”™ ÄfbJLé(¦ÿWÑê6ù’’ÖR‹5c¼z/ûÏ•%ü˜š?ªtSšÒØ/kz¼¾\Çb¬‘/f}¶]‚[-Î^÷wwHžÊ÷|Ï‚ÙlËâŸkî•ì'yðŒ  %qÇ¡_¬ª£†MßÄã ã]Çøñ“¶7²ãõÛ6î)/>(G >éÇŸ¢>/0IÔû+TúâÄ€ Ÿóz6£qTf ¦3•ÉPÓSTþZŽIÐþÔä­0ì8¢ìV­¬¡|ÀDþ¸5‰=±ÞQê*«øUü³Á‚E[—zÄ`ŸÉ¯å+Rîé*HMÆ€8Ï®¢ð±ú½ß+,‡?÷¸HÍâÆg~¾LÌÊqaýe§±¸¸—P9.ž :Lwq…qf`u¯¤É9Ë0¢«ƒÊ9NAßíÇv.‚à]O~›5yÎå4 ­Á¸ÜéXE¿0"ÄsIñD’žp… nŒï"œ§y¬2]¿¤EÑ~–Ì$çQ†Ñ¯(Pu´¢ŠñÚÒT¸Ð|#`mÿ ¡´°Œ4H³|öïä=)ØÓXQpòŸe¾ão Žý~ó7z"'Õ1@ Í“­)!_tÏZd ÂÏËGô7e«¿?\$$^A@a -IÊ3KûÒ3Ñ?‹gÕ-àÂ4:ïlxô‰d¿8­‘¹Þõ2D[Àd -€œ¾èŒÉ”à–ÖÛè£ê¼¬ ææµÅ&´r8å4=CâQ±j BãõgG„Bßfñ-ººÔŸäãM6FÜKRˆË7UXþdgg%= 8e©€9ë0†mßS  ¦z¨;¡T9WÀlOHubç«GÅ©áB Î0ã¿.ÓcP¦0ÖPÁg‘Ûeµ‹ ª.ví•o˜U{û†a‹çϹÞÍ@q¶úª;ÿÛ:&b–©@ò`вV@b>–øb‡­eïÔôäLŒ€ìú„—„D>àò~$5òÍ%Ë[¨Šôhó°¦qü+‡Œ<'é¬ô¾í%޹Áï_Ç0ó9.KmͲ4$áé:7,9g—¼k|À?'}ÜëÓº/bäÜHB ãǬB[-¤Õ‰ENs‹EÎÙÜ32AOa‹†U÷%–’€€Ýxlˆã\Ui4­ÒÇþš>fð†ÀÛ %\»ŠY¯p1ެË ràÉ#”RÄPH_;©Boq0˜*j°Àbb8ŠÆPž¦dÔ5¸ö8¥ Ù€ï½UÝ—Ê~بÅÊ*ë&.§C€•9—§t¦nyVtnøÄhQ‹Äã/­y Í®M×é_޲¹âxULZ¢×7O8¤½‰3'ßÙD ¸¸J 0ÅÊ€[„;z*Î!|Í¡£à¸›ÝÑÖÓXqè%BK{Fü̲}–Xø•Ç»KåÆŠ4 ¥0öi˜)!’͸CE¶Ç_FÖ|Mü•®Ò³<ÓobÞ|]²:¢ÑW?§ïÿ(,·]b;+û|¬GÈý=2:·¼¿¼ÉV·²‹Ê_ •ñº­ A¡Ô1 º"ìÑÝŸ¯c›kÈsi"oÖTÙ¾Ýs¥š šÿÞãí!é;?YOºµ`?ÄsMǼ Fäeß£í³„övÜ "n:€`®2±¹µÔM‰džpqAF¾8æb_±=ˆZ¶]½-Ù˜[:¼‹Tb;ŒÀacã£Rë÷Í«A+ó‹×½VÑ\¨öšú+ÂÅH2mu—/ÔÑJSµ_Ùu2ÖYtŸh¨BgÜÇÀ¥X©R™bPyO»4`^¬XeBºh…„®(hmq#¿ñs^H¼Ù[5Mmà§ï…+™â‹£¸#IåÁP™:¯~¯…P­+ÙƒèBñ…cï6a`Ÿ¥vŽšb18pôð­TèÝ¿65óþ¦eaÇÖw7I‡å!u“ü¯Bx.‡ÇõTpu¬-fû°È˜åÒwŠÒFÞ“])ðÏ<·¢o½×ë>ÚÚ:´s¸ ئÍéiòDÆeø¿F³Ó×  YÜnw°¬WqÙÔžÓ~ÝU4‚Râ®ßÉ´hg„å 3åÛ\>ÉDëqgÜÙ5.Z\þ­øíþ”­ è bT&1ðâDIÃø8ØãRFgÇííS›vGÔETˆxëxVžˆë9¯<ÌkG²ãâZôÖõ~Wb}êðÿâ‘×ÈÉWyFEg"ñÍø ¤¥YK+Z]=&ßß@×"Щ-ª8v[kmä+å(@òû ¬³1ˆÓÒ5˜)™‡Œ½wÔѰ´rÅIш60ý”Ц,+K–õ4ÊEç¨0â²+BÐ’€€Å×Ç`¢Ðß›K§§™½6?øFD8 3.Ï3 ý³$b$Êåø©ù†kòƒ·ëÊ`“ê!ä‚«¹ê…zÀKHù¤¯_ß3ü”ý¸c1¥ ú¿ÀÌ Šï\–ðYrÓPÙOîáñ<°yªxnÄBU5ãÃ=Deï^€Õª±}žâ„bK6‰©Ä•¶ à±Ï`‹Û!LèÈD#ÆÕЧ޷>‡¾@»¾íè@yýÉP7á$êŽ×ÅùF}L—sg9é´Z/›ÑÌP9Y¡Ÿ…Ò±²ïáÿ–4MXEî;}¯Ý 0–Õë5¥HOÍî] »-²•ɸ¯µ2QBÞ¡¾Sø~ù埿ÆÖ‚0ñ&þù;3˜ƒõ3—{oà×ÑÈDòY^žØAžî`óL)žÖ·£'÷ºíî|ê+!òN`šgÍv'JŽ_(ÿ³ÂÐûÛ²]x»˜+ Ç=Ô™$Aa’.Œ+Ƚƒ‰&WWeGÀ£èâ‹ãZÿTÃ%&ñƒAËYq÷‚£Eìã¸)½/¿=ºMîfNpO¾I€õžfúÆ ‘ÈÊM¦ôr‚s]­a zÜ+µ¶s-ØæÊÕ[â«å‹SWª¤(âÉ?úÕKÅ÷#kz!‰rÕV!MlÍÚ \ ‡t5ª™¶©­¨è‹X2ú‚U 9¹ƒEWGg¾6†ðdDj¥´¯,Ö(Ö<<yŽJ‚^…ä O¥ZóÅ0SQVú†º—‹$Ì:æÂ¦w÷9Kþýñj¢À€ò"²/÷»‚Œ¿ç-* Yf%–~—6”ݺ’€€ÃáO&6<æáúùNQ¡f÷­™£¹›„·[ˆ/Èç²6–HSý"ñK•.D¶C­¯×'0C-Ž$™È2 …Bú¨pº#(4 ò6«â½ÄÓî<Ê}[ô¹È¢J[8G¯XÒþ;»‰ßôk{ÏN;§Ï¿—f)Ü™”†Vœµ™Ž6ÑM U*ÄÙ}r›d¢-ŽÀbgjÚª,cGºÃq[ï-QšóÈg71wéf ëÍš½ÚZ¡¡—b ‡‘ éëÛ«Kò‹ÒŒ·ÑM)g?_¨½Z0¤j-[X!CG±uâ@·1°å†s èv¡ó‚'†!•"ζG|‰*¼ 21ñ¥€¢aÇ æ ŽÆ™£sÌQmçÖŠ^V3ÝíVŸ¨+@Ìh£±K;Šõ¨Â+uá;ð5>L±ï‘b ØÝÛuB´í",@¾ûd3]Ð[¯¯¡kû˜‘3?;ëdUM¶G8ß¾\'£ÒŸ¿Š’Ïëk0>F§.q ŠæA$ ²ÿ€x,“j-%Â;Ã?Ðàb¥Ì$ý¾kà0B+¯}.1§=*\ôXŽ2¤Æ § á¥-„änwèᛋþ±[gS)9¤œgÚT?œY¾ÈÞ‡ÞƒÔ  ŸÚõÓáAõ"ôåµéÚ$9²"‡µ[ï$šeóé°ÿá Ra‹s0¯1Ãgfw7[iJ€È¥s¡Þ«ðŒKÓSWÁ¹ÊgŒ¤b—zŸiè;Ž8ßÖ@ª#MênOÖåª ëìLrè{ &¢ë˜$'Ð, ßIÙorÅiµ&®f³å]iqa`‹ªQž Çð3ï1åx¶eóš®Ù%²a½:{fïBJ5®ÅlùÿàÚU«.øõÚòÔ‹ ›‹Jõ.–†ßOïÝZf†×©Rà.qé ]Ú[å`7ê"#ÜR3^«âÉ*±/½vçm]G‡&1}äÏê]L]±ú÷÷É´fMÊ߉–Ú +-ü=»áµX†7޶S噆´iZK©˜VFÍ/ø„0¦C9å8¬ƒ—ž‹¾Åþˆmû£"ÊäÄëtëŽp½ÕÇM«ØÄè²hC/†ÁÊ·0h,W‡=ïÉëìà®ùÅq†Š)=òEèõ#cî ^ùáûM{ÝÃyIthhH{‘×oW!}&Dçsgš¤©6úžíËG C+m¸+»VY—ã­;ÿ¯å;F¡G7«|«ïÀñt•V]RE•ÃöK³l—˜:K©Ï­Þ†@õ6å![öœ¢¬êÐKØ—uÅ(TY>q‚#>5ÙâY0³7©Ù§ãC§öÑ¿\%¢×Mò’€€åCÉ”•h@iÈÃ}P蔎à÷] ºjsuÌGã ÓUØ'öÜl¤¦f²‡Þ#™ÖS*¸4Ìÿ¿ð†ñɤ}“ãcÝù‚œMg¾’o\ H÷µÕ}×ÿR„*esõRÙ£„(rÇ×ΪûâÏ3ÛÑWÒg%|¼”¶Í\o5ƒÂG€ ~½*œ¹Ñƒ¹’>“çÈË!!þzf@2eD0ûÔÕØ{ûBÊz©Š˜˜~oÔÌv¾7|ž…Ù Ë÷2è7­[&c‚cí;ú<_l5¤ia»·eR¨4j,èÛG6íxñaÒ’ü²~_õg#8A.ö0ÕDyµÎÐ,ë–:ê!> ãÊÖÿw>6€4êeÖ5´^Ô>š)AŸkíïqWî½ß¯µgª3˜Ùp(¡J… ø\ÿ¾Ò—ã .¡= ± úY° ^±6¬Ì oÐB|(ÅÊÖZ²g[eò:'Ö™¦XàÖ;ÁK[ß €sÏZjˆ`øÅ¾ÊxåÍo;u-°q,XOHB´†ñÕleVן¨aïhwêÚÍßø‰•ã½oÃ’‚ÌŹ€FWWˆ‚ •bd‚ ZÉn(¥³iËfµ\êÀƒç@¶Í[%bg€ˆ_œôts,¸a÷ö†“„jCPâ¾Èyuá‡Z·Wwk]0 ùý[Çeª Q/Ûã M‡[ÉH[†Ó˜ g’€€Ü¼/ÚŒ^’%üÑH¢ÿ%DÖ•r×Ô«t_Añ¼TŒìÄ>ã¥CyÚšœ?æÎØZO¸ä ¥³òbHδsEPáZq_ÒŸ½¯‚{B-¤zµ¦Ï2äsÄ9»ItGaÇË·Z¤˜Ôý퀆7ÔD%ÎŽ˜æpw$èF@P蜃¡žšËvÖñëçX~ ÆœŸ_A69´š0-¡íð*;ÈpÙ”žà’ÍìÔF|¢ÿÚ^^´ß‡ á&§jù²zˆj̱rD›œÍÔV6nÜpËDXq¿Uû´)šV2/°P &‰ú÷z¡çTAó§kÄ «Ýs“دzýK|ÒæÊ|BXÜÒ'G.|G Ûˆ£gäu›Cå—nô¡'”§IX|Åòf'Ž7_ëaJdmRr§ótÄÞÞkªÖ8À#˜‰~€©‘\q8ðÕˆÒÓd©2u÷ -É¥*.®†Öûèn†1ø*8ÿ‡²·ÏôÅÁçëx¿{L¦Ú¯ýÌIá°ï”S÷E…¯½ŸÐI¼  –†Yè‘Ñ¥o3Hx2£Ú*(š?Ý• ²3Ûä†ÐýÞdŸ[ 5\†æó°$þûÜ[iÃ@ñâ9e §ôï[æ/è²áÏÊïêÂé×!q`f$¾Ê³œ2qZyÓQÃéÃúóöWF<¦ÚrjS{‘øÙ £ÖÓéå²r¥ÊCyêeê. áÉâGäP™§T¸ÏWžìîÄIöŒ¡ù–– ª¹«.1ÇsVƒ¾X®n¼U2"›û9emÂÚ1œŸ²Z´¬å\é(ìyN¾æ£LS|²}Jxœ[RÛ*sìKý… õ•Ž.ñœUn Fï¿‘o‰í=›ÔIX%%âøe:U»î>ÇuX¤wbÊp´\é6RÉ·ÎË úþbÄ4Øêy¢åS‰[éˆÚµ‰ÑrtË´Û¿M£5jAü Ž$°f†ÏýM Í1Ñ™qþõŠ—C»·ÖIçQŒðrbn=ø/ Ô>¥³&{ ÒÚmÕS£L±/K)¸Þ|͈f‰q…•nÂv[¹^—I¤Ksg‰ëb6qp:07M3»Gß:Ÿ‰ºL¹rmüSnéªmGWÿuº|ÒEŸóø—ÖçÝú‰½ÍLuvnC{ñZýäçkcÓ!R6ò¾ÄJ³Ú±·G`Á”(«ô±¨aD×+ùP™fè;[2Ís|)G§eàXWÓfzáhúêŒ6C&¨I}=¾SZ >4󋧨Œ€€óô3>@öÞ(¦j‘ý]ê^9ƒþ¢)ÝDZ CUÖNþ‚Ò5Î »·‚¯ä²ØÍƒrÞzp ØÍcÍsT÷ðÌ®%#’_0C!?÷BnÝ·(òö1±/2ÍwÂ5°¿äíèýó EÖÔƒÞ÷βUöíU±Óß½F¡ÏZ„)÷`Q1%Ä®ÉÔi®Mbf_ù§¢?{î´Of÷–O3E >c×d¶Ô ¾Ì«[§Ëš&ËÐ ;9ôV›Èœµc«}‡KÐp­þCrn} »‡íƒ+Ë€´Æ\ØX œ›v ò 8aà ,C¨¢G“('É„ˆ“Õ #¾üàs›wóÍ~_àÂ}Ð- vɧþ}|þ Bdþ†ÐýýÓlåã6wÀ4 ôP›€¡å2F™gåó½µÞެéRµ÷ÝÒ=ð¦j¯ŒŠÕkõ¸BhÐÝ —FÑízêWÕéSa·äªsw6ä=fyKǪ‹~f'N‘×ëD=ÕÃ@=ˆÞ‚¨1GMøõõÏ<Àúˆá۬Ͱ|ñ.nTáÓ‰ ž³k*º¬H^—Y›ñòñ8k ¬ë;Qx߸ÇJ65Íü3opÜ®Fɘ‡ûúWG1#FZ0Ü2²õ)x® }sW;&Ç€¡)<I4€Ï°•×:#©æiÆXV¹~âñ‚‘}32·eÃëÄŽ¾’™7jÞ5j¿ Ò'úí¦+dü"G¶Y} Lzq ‡«‘H8râæ’üÜAŒà&Å™2ú—_÷ ö:$v¸‚ù[žðQ6žhhhc™žÇ›Ìú&(W¹ºïh3G(òigaË™.,ô3æQjÞY†ÜWíyk¸9`à²èë‘»¿8Gð#¨(á¥\5½8Sú9º›õ“ñ ó­“ÄéÝg¢d5ßc†;±aeóì†Ð^Ö„Fa€çk^{{N£^påäŸ2oY‚î¯þ4×­mä 5ÖÍ%µÜDøR) w%ÜY Ë`?ÕµD_±žåÊkÕ £z¤Yb¿ƒ›âíÃ¥ H,*a|UÓt ›E’`íØ—oÚº¬6íp¯Ä˜5ú«­î ã.½r‡>W®ç)«>PÂ?¹’€€ï.DÃë:úOö¨-Yú—³^ss"ÙÝlŽLÌ*d.Hìì}N¿tç|FŽbæ`1¼ë¾ÜEÑ[H®«×iì©JŽÈM2ù¹€•¤š)v0g¯1ÿ ^Aøé>ÁŸq!üˆø; ;>Ö¥ò?_j¯%ÏPš7lîy}„Õ@îÓ†ØÈ}^¦%ß9â¯Ï Æ¥\÷ÐêbsHïW÷&ÐÓ×e­/ƒP¹ï$pÕqzeafw‘:œ'ŸÜo[mM^ói‘JöF™Ëù>?7E¾5ÑË?urñ7ŽàÊúAp¹Ù1òÖ“È“Î9û"H­ºñç³ûs^£w _–u²I ¡[ï颌­ „诗Ž×=ô#u=iõį2þtšÛšE(ØÊB×µþ÷ ÈÜjù-lzáÞleç-z……ïD“ù‹£}~õ©¶Öø¿Ð³ÊC€û"d9fM=;ãËén$Âåg´tÇÆÇöËŸtý?!KÕÔðwÁoQ¯W±qBrYÆ^·³#8d}µ[&èf*;E' êJëð+é›/ŠS±](Ï`YäÐyój+ö…£Ñ…Nή¶ª¶Ö…éÒIôX"[" +tIN2©P}¨úp1³R=n˜£"i‹.kØŒ#ÈÀ#ýÒ,Ný†6 ¯§GaÜ\Ûß ôl¹¬8ÙìX³ÄF_ЬV6#dümrõ8¬ä²Ë &Ù»úÂxN]ÿ'Ÿ“ç¯X+ìõS,ê¹3Ò MÂnYûµ ޼ïÇá•i͸ ðÜȆ©„'¿õ³$T¬>¯Œ®À[ñ;ëžÃ¡ÓŸ¥ψ-V(LDR…Éš^A‘r_aŠKòú„¹x€”¡•µŽBÃøÚóºÕ8?oqJM‰N"@¦Yð! ¥ómÌ€üàÆ•ãfjܵ3™fT1îŒxòHÄrLõ¨p1q;Uº‚M7Î<Üï¡}Ÿó¥,YžÝG¡ô¾Na*½¸v|†]©&xÒ´>Á&ñOJ\@ìñ˜Çðð< ~8:ð¸:ÈWNhb¿ÞÊ€ùÅàʹ-§I‘ö½c¸ÑB¦– KûÌ&<ó-§µÔdBó=ã:¥Ön°8'ÿ§ó›’°ÃŽ&–1·@8óÒ¡–ùÞäd.q qÂU·Ë]B厬5]€±š°"¼ˆáHˆITîöÝÈH7gqój‘¾ÿEÿi”Bhè/ÞÍÎ×åŒØïCix?]—|9¶ÃÄ…Þ 6£e3„Ƈ)Œ ÈúÞë¤R>ñpGÑÆÙ“zÇXË“+Ào0 ¹¬ÿ.ZÔ›Ûr¸ïAˆj ñ@ºà8WÆ^ÙÃvhÇ”Jàcâ[Ð\¾lš-¥¦g”°TiœC#wŒÉƒ\ËE¶`®Õî¢hʤ›ù\ç‚ÓÊ·ø(Ô™X‚'û+Œ¦ÿ’…cµ±†ß=ž“”òcVZÁnvµƒâÛÿq»”-•Ë ‘'~#ø0Ê!¦òà›2c’$-YK3Zdü•É»tl¥;¦‘µO t2˜"Dב> #@·ÈsÅ׿‡QÙLE™®­ è „Pè'”vØE}4ÄL·ð³ââv°Z´g$Lÿ„qw½)hžèøS`w¢£¿2sàžkëCÜϯÇe‘æ«·õÝ ‚Ê5ê+N„±ú¬tP¢©rl¥CfGåË#eü¢Ûö@w0Î*æžÛ˜‰»6|ÒXž§ÈŠ™«øŠgß}€ycàõzq’Q±í¡ÂÓÊWXHë{1ê¶d~Ñ»â£.TéXÑ™u GÕu¤avÃËá#åì©ÏøÛÃ!oZ…m½WW[V‹yv2ëÚ]j”%!9£t¤2‡‹±YqY¨½wn£g»Gw×ùHRïI±‡)šv⮥ û^¾5ücÆ€4 У,´<Ó'R[/å.Ü”l¢QЃ'MÃ|ÔÆ‚ä-Ëß—Ëñ"y °ü ½ç¶Ú¯ü‚eø7÷l ³pÕ3e¶µˆ  r‰À¥ }êYtY¶5adò…™¡ì1Ó¼°ÈÅqìç®ü,æ4;¢3N‰¢Ûm  š°PóšŒÙ’–—mh?ìÙÇ!½JobÄT¶pzÏnÑœ4³9Õ¬¶±¨_Æ$ÈßI’€€Á¤ëàƒVBT—žÀY xË¡í+®èN®ŠÛˆÇxF£µ ¹Ê#qË,oǯ6y›„—¿zÐ@ÆvLöw:càq*QÔ¤ÿ1ÕÆ!5ÈãѲ|ïÛ—ˆXå7™„+m͇]yoá˜;ç !Þ<Ç)’žúAÂöÎ~D¥’íågû½e)AB³A#ÌÚI`\˜Ã|X'¿2 ¤*« ¿w©—½}açySíÊn}È4[°Ù[Z­üS‰ªh¤ÐŽ>ë+àaJ<Íe`~þÆfÀZß\¾=?„å'nùXª?Û™.ùc oW;X+LÙ£¬AšÅÊhxyoh%qû*ïPLè^ˆ‹„å–v‘ÒpZgM ›Øò˜4>•Ô¬ež„'æÍýSöi“é-æi¸ Dï…`ÜžëÔ¦À¯HÒ"År±µµÓ§»í xÖI€¾n&ÕÀ&|{>™85í5Ðä$ÕhR!Ú´ŒD‘)>[¯lO©Wõh#A^ãìÏ|‘9í{9Ëë¥238^¡‘$B]!ÞÛG* MBé–oŸ°ýÙõšÚƒàÌcÞõÇkŸìi^Z’DwÀ¢—…ùÎÉájNØr\tûŒâ}P“ ,¥ºéÁ(ïæz³%Û3Ÿ«D¼R¢ ªïÞnuÊ‹¢¾  ;ùkQX탩Et°n%D0TƸï–üÇHݪvRtìó®íûéÒú/ßÕ É×üj)ÈL ¯räGäÛ#OÄ&êm¯U’ÑËí•TØœã@Ý¿—góqÛòáðâgà»]"ãÇó®æšT~`ß#ìE"/ÐÂC> Ÿ#Ëûb“ÎÌA툎Á–Eˆ§LTK„Áè + ¥=©ˆ|›B¸tzùäüH–_¡‹í&@õ“¦¹uˆÛ*ˆhwÙp}ÖÂwn7 Ž=HÑi}7xŒÎÆw}¨x[0¾[]°í[[ÏòД1 Áe•QZ=;hhÜþÕ TS}P‹ù°à¹ö7KxšUÙ ã¹fåæó6ƒÎ~­'™J1¼ØaD ’€€Ç Á}ä}° íÑ6 ³ £5°7p?ƒ”öØ%q´z=:ÈTcŸ6ìhžˆ:CP$Kçí6§ª 5Û\òpðgã±$Ðì`m–Õ­ÉjSTQW™w*¯±QÞŽz©)'k­X¹dxš>\X¹û_KY±27·âÌ"Ifý¶ ‘¡ÝÜßáFFìáà¥ò.œK¦-eŠÜ j'wŠ“³úÛ9à‘#ÉJ¬Ñ®Ñiþ®Èª¢}vt ãt–Kf ÂM¡™93}E“`–ù‰ ok3pÈNéÜz §sÖ½o‹‚,ç0)I&¬o®_õ@ù”òNVTñTůÉßtÂ;t!ñ‹ÎV ½ñ°È|•Þ›3NŒ’¯üµh³‹öNá[þ#¨ûFv%*Ó~:vŸë’õxn:Ý$<Í §Y*’UŸ·I¬ÚœDGÆOTÃ!òzõ‹0†}<®eÒ~Ê3ðùÐÈÙrãk™Çèá¤Xë%€M}(áå!¦òªÔ’¥l° bdYõÖñC™¨wå·Ó»ðéjLá“)˜ô@`¿ëÙãëð"  `9ïÄÓ#ÈTW(X”ž5¥KtÒÙçY#¿Zü #ñi'#5º $¦°‚{E.\0QÆpvN‘ –“åH ZõÛ3r™NE›~&uÂVžáñ?˜­ê×Ò ÷²gʒ܇j¯4ë|¾þ'Hë*‡ƒ©¦¹ÈÓ£×bϵ #û°.ÿbUdpf…Jb¤]“û(o1k¤ao¢ˆ»*Þ«Ô6K?9àÙ ìúà=[Þ X("â¸V996ŠpR<ì^–.ÏŒŒý Q4ˆŽMÇ«\†¦ÙœÅ:óƵó%x*.ÊnýÄŸ:ÏT ó NÓuäâ ÀHaÉüèö™\u=ôš ‚«¯¤R÷ÕלU5 ^Ä»- º(¯g]¼!À#2] Bn¢e‡]ÖÅÿ¤ˆ>+È´&c%hÍø æyèäªÑü…¼w-%O)©Æ32"ôm;y—Ð —2“f[W/OÀ¯…r¡ÌÊñÛF-/Žç\:®Õhã‚NOiáìr ›ŒHËÈœF¯D¦2…‡ÔlUÑÀx>-N¬NG¸þ0yÙ‚ó"+Â߉¶Ôóp¿Ë ÚNtnØ4û£‰µ¶O¶[p}A¯,ŠÝú°jðM),n’€€ÅâMé®»s´«­@=üs}k±¦'߀ᡅÿg|GÕ},ÃÏ­Q3T!þËs’-¿œ„†ìX®@è}û‘¼ï„ÊËo 3¬ÿ'†väá¼þ퇴ª¢<«åÙ;Âx¨&²ÈfciªoªGß‚ø ƒ˜—MÝY4£‚l'.#èÇ_Ã|-&sñk»j!pÑ7|÷Ík‚믳™ã>уPÆô‡(è­83ßÏ,%`R¹úu(éSeËz´k¾{{)W–,‡@ß”WmÛ_µîa 2ñ7 ¼c™;h׆¡ø%Q,½½‹Oˆ¿[dŽSÍù--‚7ÿF‚a¥Léi 5Ž‚{+]qVTãœâ¹޾w-Tþøå@ `Lª7ÙÜ'HÍ»tâˆdÑaÚÆqÆË-Q5ÃóXB¨Úm§ö™œAœóŒƒ|wQ<ó]7C(„–­L¸-°$ßõ(K€¹Ò:ÀÕqG(þÇ:òŠ„¤qhˆÑ&ô“”,‚ µ‹enö =&áV¾zƒ cp®–ƒqÇÇcìÓZâ1r-E¹J >ðVÞÐgø»²Ý¥ÝŸ p¢dnW$3Ü|D^k¶u ±š¬ÜÁmJµ¤wöbô»ÏGÊÛMíg럈ã»MÿMíý·ªMJ¦Šì_}ÓÝSg܉üçÆ|±Å}Á¾Dž×r"n¶ûÖY®GÿGá}òöYh7+!BŠ–YºJP&nÈ‚ ³§/²¥ØÚRö3¡‘„#u\õªÿ¥^Ì9©~ÌgHòÂ^p 8ë˜Àt}jÑ[—!Ì$ë·‚)kØöl(äœ* ̯bÌg}“’€€÷‚£Îô&›gè_*÷Ôˆ<%]à_=È‘ò¶ÐÀ]¯µèð7°Q‡QW4¤¹ZŒÔ¶=pÅ8]bêxHÑß Q=û¶®u%rUpŽÚû6ÑxBŽÝZ4¹ê‰Ž!ñ‰…z4ì–ónCÔê–Ï? j“ë‚’"5® Üõ6~Æ7»ƒL/`yŸTKQÔÄ Äz›ÄÄáE î 'a™¹šuùò^~äåË«›Çû´¡È‹ }cá½Ë=ÇŸ)Ë7n‰a)½9ÂpÙ1QI>{˜¹Jƒ§zßD·müBˆèù¦òòö¢× ¼‡iä‹ÕÉ'Rˆ]ZØ-¥’\ÜÙQ܃ß×9˜~¨ðSõ› Xd0„þ™ÛºøW‡“âµ pË âÔo‘Ob(çÚŲXcžcteyBêÄK Ø»×Ï÷ ȦPQ—Ç2ˆª»k‚‘ȦØfT‹!4ý«¥í¤é5þ†ß'sp¢-Á²°%#K:!±J>,ë,–· i"Ö²pPýƒ®+G B ÁÌÚ „‘7Ñ|êÿ„ÛĪؔ³‰Ët'¾͵L{æ3Uï–ãòÐ ª,í¡M(RYÙ¾Ÿáxë_b~xyF˜’tyná“ÎÏqíäÉ1ÃhÒŠßFzÁwÀô+—E ? H—ÌÅþì’_à%Z¶´…°óÃ@ÕD‹õù¥÷˜C¬n={Ô–ïèÆvÛÿ²Ú¥ä‚¸Î>s™Ïf"®0óxzÛD`dØ4g $äsÑŠ]`úš@tO[muÉFŒ=¹ÕôÛ ð£,…©QÁ9:ÝYH< £¡‚ÄWð€©./e£ÇøŽØÛ#Öž%®ÃþþýMi¾þ%Ô“¨%'ðDæ-“rÚiˆCÚPŒ‡žíp§¸u9ï.Í~Úr(µKZ§Ö°x7ð¦~Ì}úçR&fB¤u'ƒ(·èëS÷R§åÒQùãQpXC¿yõªžù hf_²à=È\`Gb­‚3&:_yÅKÔøÇTÔM,-ƒÓáy*¨s¸ ù¤Š4>©Q.u?ÎË!aC"ê·æt#ÞmÒóê#Ž~ó0¡uÏóZš%˜×7A+4Ê“77ÝWœó¬ÏÉ.±È•ÈÈkA9´ö )ªG¦{}ve»ànĵ@ðï‹ý«»Ùâ‘á’€€‘Ð<±°ŒHârCzœJ†k ”on˜JöY§$ÔÌÎâ{µ™."Ûóuß rá~¯ýðâ?äæ 4«ëC5®¢½³ñ`Eo¯ÃkV>b3=>hÒh‘0«fŠK)$ ID•Ô.qÑÑiÎ뻂1¬‘)-ãëMæ¸/ÅdPKŽÃÇÑݨÁù|jUÚ ]¥ç?§§¦œÒÖÀ)¹6Ù“/|Ö«Bñ‘d;$¤*Žak«kÀû9)–¤tkµ îÆ7ºE&A:¸”(júç‰ÞßÖÒU¤,¼wc,\£ê²š+Ô~€”퇢déÉø‚Ö´EÀd˜t ì…¶…YQ_ÔXgº+¼Còu/86(‡Ò‘iìË180[[+x;?©*[èN‘†ªo!†À+¥I#=‚‚¥§ú1ë¼›ìk‘ƒAÀ»¤XËP¾Sœ·€F$BM0˜å°UExùÇíy¬F6"LKÊ39’ÐÜ‹š &]̆mæQ­_ÜÉÆZË7Ø[©G;ÍtT¨Ô21nfôŒ (6ìiÓì™áÊ‹,ªo ïV³ºWÉjJ:Â’².Œ8èRÁÏÀ´ LHÀGÛùäâ_^;Õùý€~b¾H;4·™¬{UE³ü-kcnfÏÊè¤ñ+˜ÍtÝ\.NØí.ØQøå ¬ ±óç]°ŸWÞÆ¬î‚ Kï¿ÀYQý47ÀÀ~ ”áSÂPÊH _Pl?ö¼±ÐåGÃ’ñ%åb)|¯ÜQ“Û¸"¹t…®²;\—¦Ñ®hm’›.gµdQ0ÕáÉOªk¾,œpÉÒ:GÝžþ6²Ó“­TÕ÷Ñ"}7­œt¢½×ñá¥]–Ÿo7ô yĨr-pÕ±Ó75né.},Íæ ÑKëÌñ]LZȘöÉ!ü¾¾Î)$õãÂÒ’€€ØU¸ÛsyùìŽ+é.ê×JCTß yú†¯cÛÁ„ÌŽˆh…W«xÜínØ@}ˆ‚^I¨î€šš°” É® ¯W*ci·€Ei–Ý+Lß%Z| ’‘S¯UDÃ`Å]ô ž–ûêÔæ¬è‡¿¡!Òàè¡Eo " :”¿Ð/·˜¿ô)Z †+üm£:LñÛ/ÍÿQnôµî/‘>­VtìÂÀ3ï£;\”z|C0Cè9D‡A–´þ³ËEm9à‹<\Hƒ b„¬zœ‚~tñk;óõ'Ñ›«ñÐb'É *È£R#loÁ6K (lÏÃkt$`›¾QîcÇv¿7ª‡[ß¿0¨6 é I"…þ›W>;~'ËÝôyöö/÷7uOGC"";ceöK jŸÎ韒é²ÿQ[Ÿ©Ñ±Ý˜•2``x†³ìt†{¯ü€8ió÷(2WÕÁÇõ*Fé>JÕYÔ,Z$5OÓ\l8Êî>$$µîÆÒ78AU¦€ &ä ÑÊÇLÀ,çuÞÈzO¨»3)®ª½hÅþÏP‘>T×®Ìàغ!%¾ >|3Ú=VMc[•ƒôùDm½ï-¼P›¶/ÜEû"&qsØ‹gœdôŒ~”¡ªN,³¹¬{7x’€€áÀëþ°|‰{\dך+!ŒTQ€ˆÕ~R=ÚssÉܽóºOèý×ùyžºšs¼Þ¦L‚VêÂáFúø7’ï‚Z`ùÙW[|ÅÚÄ«Ix(Œfä¡ Yw;IyëÉNûé%;xSãɸãª÷èÈ¡­@HæÔî539¢ƒSäß±V®ÏTû¹`U>0`ÐìÇuUÊŸ-~ª9U½45iv"†rœÛ>HRð ŸäƒYÉ÷¶Gnßt/n ¼aºD0ò'õPf®€ú§L1õ‘F˜c¤ëÂ/n<2Æw@¤B9κß±ñ¶ƒ¥ÞµgvA#ŽÛö±o«Íšƒ€. ðÑ^Ç&KHRZ,JÊ{†œ¹D³ÉwñÚ_o·»;ãEùªM2³3G¢ÇÝœü3î@j ãýíòë`]«½Æ!DTžxò Œ™GZÖÄͶ~æõ÷.¸ö-ëPŸ^‚ÌÂdœC_ÀF@tŒ—Oika…GL2‹IB * ÅDÊûCO³¨Æ—L¸eØ&l–?.˼éOQtGñ…~г÷[¡›cñ,”¿ð‚û\&-6z\]ñ-ù÷¯æÄh}ûž+¾y¹f²é¦ƒ-ˆ˜O%– iäuYaŸê™AÚþ"?§Ö¦Rdo¶À$·-ðżŽÎl¹¡þ$Ò¯sòï|ùQ+aC½d"kQ?¬n¼$q2ù4ò”$HjØŽx5> ›œ˜™»¥Ò“Ó¥z<îïч†–|jù+2”yõà@)¯_McuWÖ·Þñ(ñLü’?cO ý›W–Þ1 Öó‰'úÒw×°W=ÇÚ‚³Ž yJ±N’3„<*l»K'îê^‰×eÏÒGcÇ_ë$¥p¡Ïö;@tH«ƒEÑêA™½%U^¬Y¢ë-¤~«bšßáÔÖÒO޾C”î…“èÍ•„û«RÄE–õã'IhÈ¥ê ×øñ?À»ÐG×”¿óÀñ•`©Ø¥u赦ūQºš•›÷?ùÒ¥G/Np¿šªÛú^;Çgóã*ìHUZ]ÍöËß‹´ìRÖÀ*¢j‘@‚a9)mYïÉ·úsl{ÞMveÍ-¾û’ŸÂ9¼òŸטþwn=Z€¼:ô磲U¬Ò+i±…ÀµîÝ ŸUI̶Hò¥À.nHmëÚ­5í–2:×¥½ûâ©õr$ót æg™m˦€Ÿ¯Ö £"\“³ù+H:Ô¨ .Q™ úÜ+ÓH+¨àIŒ/*-uñ§¥û½g혇‡(V8£—“Zšòû„ŒÃ Ì;H;öò¸oU9•Ð`€H3¬yÈÙ™=t1’ä'»D4áN³ÕYÖL¢ªã†±‹háö[,þ#å«–¤X3Ö&ÛÔ¯3œ”ãgÛ.¥#¾ïÉ¥ð1"ýîNaãj\ å̸fHñ0L”×UÿðH[§<„Ùfþ¡Ý ¢Ê<`CÏ{cD—"ôm)õ†‘Ö/Y,îñ|fý—E½ƒµZg¬fß Štùô#Ý“%­F¦§â_h1ÐTMËÊÂIaÄÀé w~ì†!ý¬2´’©G˜w*è8º¬ÝÆêT:åþà©7¡•K çúéz’yÔÐåHW"L²×¢„Ôµ9Ž6ÿ׈Øö#‰’òþ/%)ѱ¶Xžjw œ9|ßwDú,ÑŒ-µ†Mžö;Œ›ìÒ‰*a¢‹*º„ªœ#•%9Fh3ö—iÁäÈG,ü†h© ?€kêÇŒ þù+|}ÿ¼óǯÓÌ×MÛ^£¶éz!Ô¸H K!;Û3½qæÈ%ÓȇZ11p†­¦ás‹^ö9°k¶½OÔÅ8µ©ˆKZ ½¤†âo!–Ó³°Ìãuz8Œò6*æÀ’Á+ÂY«ÿaÒm†}CåeØ1°Hã›#Öz©ÕÞ¦òbÆuÓ{GïsË+|}¸JE–ýÆÌ$Ä?Î7#¯©z0‡7Tà@“,¯†ÍÑ­¡u.7ùñcmœw¢Eú±í k³¨0‚Œ"Ùzm±CtǯÕK·8‘=pù¬F¸6Ë(nx Í0èÎÕÌ“êoÓgI¬И¯XŽ;f~ó& =æjÉØDZÔµFР“kµ¿c¬î]/¯WnÏG²!h[Ò¾sE lw@B+4—|„I…Œ$²æ¡ä÷U—v¥ýüž‡âêá„4:´þc ._LÊžjšvSšºžôht ºÖyÜw{®º!’@}Ç™Kã$JÓ[1²°Ü,—!zÁä_¯ÊÖ ™e XÌ$‹„aTx WðšAXÂq/²m^ÿà/•€^Vp Ç‚¶Þë™Û6‘öI–P‘?nÙõ{%G)kŒR-ËÍü>ÊNÉúñA OH»UáH.póÚÛ$w7¡nœ)háEx’€€Ò±Y›2ݯ’ÐãTÐZÍI€½!Æ#•\ª¨‡hÐ$ÒùÕwdŠÄ–xh‚†.” ,ü=‚4¡ü˜_[{Í.Ÿµú(ðÿCšx]3¥ÔDaR_ñÀxÈÞýʴĺxkü©>,,ë^îPb9`¥¤C'¶=ƒÁÉ\<ñ’Qᬄ֙Oåða/î /¨f’«P€ÝÈ)\Â:þBãd*&;„Hp»î#£‹+*ÿÌHô•¦Ç»Ûå¸Ä}AJÄR¼ M;µ±|vÝj u¦«Åï†<„±Ç‘«3ø Õ"ooV×ñcñÑÆ(As øšÙö|L¤Of4fKp¢M1¥ mU·(+Æ`Th”…uÿïL”«Gäfªù:<°wEdÝÒj¡ÀÊ.a?~‚y5´ŸÄ.mÙÖƒhªW(`"¶6[gÕ ÉW„l$äñðÌÔB^eÊXìê4>[4_mk§ ¨³±2c‡…|…J‚y­ºWƒÃßæQ£&d=jž Ø64øiH'·¯%žû®A> ‹Ýñ/T–¡ñ}(Y!äÒÓ&™«GËfÕY„Ûdäë©TÇn½c*ÔDPû¤Ýþ’©t Â.q·㢔ÊqùBÝ}#÷Wv¾ÕNœèQÖðþäÜ–ùö“Þli”š}1-5qì]ï°ËRóL7ºåÌô‘½ýiÜòãOSÈ®Öñ ……Ç)ý)¥Q;£šOàÇüK˜Ðú”¨è}UÜÐB1¤ækÕ,ʵËëN€/ºVe¿ÝƲ´Ç| £¨Î¼¥¿< ûñX¿¦|fý¦÷É~y;ÈÃ>ëþjp©|wá.ÿ¬ê¨»®ø#šŒÖºl.  é—5¤/;‡¥CÍò‚jm´AOZW‰©S<~*ï…3 ø®ðS?³>*¨Þ÷ZüÙ}@ w¬¡þfT‰ó‘ WL ìXØy¶WÑ¢‡Ä…8TÙü‡ Lˆgl& ¢|ÀÙÓv`qäÁ¨|µ/dt¿nI€…ÿµ¯¨¶$ö|c,&Kª–c¼ _ÕÌfŽg¶óúWA·§eG-V’‹ìГg8CÎ.+Räm±©ð¨ƒêíXvs˧oøQ¶NFj u¬vÏ9cmT{Îλþç›nªצiÚ‘œÂÐå& ĉºiÎvõjV’€€Ä›XGµš ÙC´k8]žÀ'9Kúÿ‚ŒnÀ^>–"xü@ñØñ§&úõ†cö%nY…b†¶††_ãø°WÝ’„Ù3 `aêW‡èòt1(Š¡D^L¢ÿ Ó(ëÁ IV:¢ôÒ\ÑÌc.Ø&âÿ 1Š~Wì rEVx¥÷KmµJén ÿvѯÂCïäëZø‰)A|DñeBµ$ûeP ß®îM3Ó3»ïÁ—MP`b%IIUiPœV¯Ô`rÃ0öíC˜@£9®Šn8å0³µÕÆÐù{êjç_OçÖ0ì½8crðýðÂÕ[ÁI Cïÿ(ÐˇLï ³c\…½þW•®è³a±/¤Ò-D[8xh>ñ³Ïüƒ ÖÈ–âåq¯f®Þ¤Pwå}x@ÊI6He£GèÓÈë”]ÌòêêmÌhÇ\½´¢bijõYÈÇj.š@Ⱦg 1ÈØp‰;çØ[  wëf®—ð_UÏa§¾jo|Bu8¹¶Øîi›ªÉ'%+PÊšÙ³åFG‘RÀØâVúþg³N Žœ~ܾ=è›8ðºñ(ï´xc=ªµÒ!½\w僚YhŽ!’hÍ]2§8Æ…ö•ÍÕv‹‚‚;(O‚î-¥• l…è#¹ðCKÏ<@‰¶ª‹) qçPªD¹g¶ÞuÅ7ÂÕMŸ ]™!0^$«“,dEûº)=É£”ƒÁì—Þ¢ èÜØføÜ yÙ4&%ÿ‰Ù»YÉüeVs£ÍÖƒHDuM91ö°NˆRÖ¹˜Üõb•¼<ªÂ-cžE•íî’îyÑ{ÎpJÅÕ{ëCCÇÖ§«Û³M@O ÷ ³3£bàáó6Ýó8ìgªºÑ Èæ5ý ÃYT›k¶(vB‡ÐÍvD›ôdfåþ.–Ì€8…ÝãvÖ"s-wc¾ÎéǪÔ#nc­Mç¦û¹ñ^n«{'Ëvç´oœ<œ§‘+(ýz³ºÚÓƒª ›Š/v"ú·84íFÜêG•íH[¸<îšÞϨ«ÇzZŠ>¶T<¤‹cÆ®Ä(,äˆ.íòé„#,ž¤lTs&?GÏqŠ80l:H>\g‘”bÖ>N‰ Î£Ÿ¾®Æ~»ÍÒ³z¬@Œ¡‡’€€Í© …>æØ­IT˜“:$«Ÿ^û)-ïÖÚð»n{rÜ…–ýZnQdÓŽDÃ&[ÇL¢v¨kS¨ùlże±ö.‡ ÌË!ž!5náNø\øç¯â‡-ð›Ìƒ„Iã*ä¼u©öAÍþ¥Bùÿ)žlQ~cåG‡¢ù6 ÊÀÌ,ËÒ7Ââ{¥Ô"X¸íÍñRy¯Ð2E<üQsÂq%¸+ζ—U *‡•§íRû­ñâ¶ kµ¹Î]d¥äü‹¢kMdƒäœÕ ÞBiö7ñZ–Spšœl’õ– S-ž4+Ë ¤·åöGŠ<þ ×Η 6@J‹1¬ßvUÉ ͯº3, [¤kÍÑø<ãµæünV¢VIu í·eøÓÉÓ )ˆê.Çr½´Á|øÐ꽜ÿVÝQ¶ú\§¼Ýõ õù6]+÷ÔoÔ[€èë8EÏü҈ΊʽOùë±H¿Í’IðÄæ¦‡TiÕæçIœÏ6eñ´,‘ çZÃMV…E×…<îu ®®juú™Lrº'FÓàEÿÜÌó@ ™@×Ç– üóÓB8jy˜òEmGW¬I©6µÏP3b7@ïïå$;Á^󨌉”ÕBŽ`>ß>¶ eÔ09ƒ’y¢ø&~M53-‘ÃC:ý”e#K²ƒiÚH½ö<„´oüÿ>…Ĉ”Æûø¨q §‹vfÂÅy– &‰ZE{ÉïlWªÉ"ÿ‰›˜+d«®Îo9£3”’ÙbG-JHµ%á-°¬]Ø\¦®ä3Òè9¹ýVÒ†‡—Ï‹ #îÒü¢ Tã€âXTwÞ³´œeÕЦF¿Ö¦á£GBKÀDfw=`îÀ`½p4 {ß—]hû†T9Bf&J[j?]ê77Ë|>Gñgd6e³~ÛêYµ/èõA’’¿xggJ·(šp0¾±»ã’Ei uˆ.Š“—s‰øÔ5RlSôöÏ¥où%Ž•x1F>¯, ñô6¦²w8_XŠ æ ¬þæ?ßÅÝuó&÷ SîQ”…ÝZ‰4ï"ÄÙÅÝ|Í­/¤Ùtµ˜#à ±$ËÎeœïÚu_íëɉÓæÏïTie"QNNu›Ÿ*ËõÀ†<õòIÛj(0áã¨À¢1 Ö‡–iÄ6CÓ°ájÙÂa¬)0Œ«Ùÿ‹ÒÁxoÕ¿ž—¬”¹\/tN\•ФþÔ ÿüÇ6g»nσ%`å3ÿ{/›$ ¢¥ ˜|ióâX2ÎÀëOÏÚrO=W†ëLUQÿ®bþRÇcF­·r«…ò~ m–^Ø[”ˆ‡ûŒ•½ñcš°úËýc½®¸\¯ôR2;iªˆ·DEˆC¾]L_,œß½,¥Ì¼ïÇõ”ôe½u±mK«x6 µ‹j½ÝmBfÇtw‹‚µævÍÆzëÈ{ŒT 6Õ@3]ûâªóè†6¡s½ÖwMÊw7mU:<Ìfàc\Á””À8Zd&y·Û7øÂk¨¥ÀšL5ilïŒ+SI&T³žŽ³oG0ÕW'Aû¯êX{ÚŽý^C*à"šq>ÖHkÑÊ‘ç ~}ÞbˆWØ•uyMš€põâŒ8'Y75Š Å·º7ªFlÕg`ê ,ú–û÷RSé 쯘šÑ©¢"éæµ- -Ë럣Ì|(؈ó ÝùXˆÊÚѦÚdJQÔ›äæ 65Ï*Õq‚Ä«·©>eº0í±‡ï£ËHwx»tŽê¥T´cû| ¹ê°®ð €£ìÝF:²üµ=[ÍE&œ …&¾ªíœru¹{è1[eiw0T!бÿµ™Ê©ƒù“'NÄn·ØéRŽxÐÜTžˆ§© uÔÍeöÁë"⹂—5¾TØP†wæŠY½} öI¢£ÚÉœ“Àž Œ° Žb’€€Ñ€=EPìÂsƒ‡1ï*Ã9ùÉË^^&±5¸Ub`úJ ]lµ‡/´o!”ÈŽ3É„<è–œîØ¶z´œÎ+Þ6¸vcÖØV~šq /Qf ’¿E'n=×l-ÕqGB“cÁú –ÂCÏr¾¢Q– sºFFŸ=É÷qíuNä—M ׂ®Wÿ÷*ý M>%ýÁi¡¶,Ë#°©S¢ýÿÿÔ/¤AÝôur¼@VgÍo!+%5j@ÿ:ì}{BS=çlÞÿ×Q ÌÍ¸ÒÆ/Â[ >ÕqéüàLèfE¯p£ŠP9° å#GŒþAÊÒÛ23&L ¦,0×ô«ÕW1nbˆ-èTqÀÙvx©^IUƘH²ÌOôû ûy¬íh¥TÀ«ô)‰»ñעжÌÉä7Ò·¾º¬"ͧGR­N= ŠY±ý~‘Å+²ÍL-•å6U±íù"M;cýí['LöÑóGhÏçO*ÿÏìUêâ›V Kö)½0ïHƒ“*/Åé_lT‡–kï±eŠˆoÉXöÜÆ­H·“ྲྀJû”M!­„^?’/–R½߯^Ø’×QÂ+FPÀúX¡/£å,>îE‰$}´¹×—£Ïq«²ƒ›Pû,ÛsÇêòÁ`ÿ0ò*0ÛPðÛ­Â--i“~ÎÕ*¬bõ&X—ov é=*¨|f.n&tÉÂ}Fk†›h=T¢e‚ÐN§m¨ß;vâË£ŸŽÉIÞ_öR¾Œ¹ljÈ€ÐÅN‘RµÏˆ)ä•>çtóÈ)’€€ÁúâPHÐÄ9I(ð_Òʵ”¹uêBÌá]['ÝÝçl˜Öô®šïßmh/²«e `@§§>Híêº8~“{ë~ô\…`1h, Ñß8ó°{»ùÓhy¥!àìmϰü’IÚµòu«Hß1 7Qجºñ:hú:¿%6s÷•¦ÿêwj˜@ˆ¾ŸÃDOûû¨W­¸ÁÛÔItR ]Ay9S—SÚ¨²Œº*?‘©üdÖIvØÇ!ÃÎYÈUø.»ˆ„*À”ð+.[™Q`wHðŒBO‹‰ÂÒÔ¾„œ›ÒuF‰œðÖ‡†qbÐ’ nåHg¨)ލNEªhcJ/¢¥úðBt‹GÔvÍ£ çšfCô¬áWÛXL™õ/‹ïÃ踾±nX®U_XUøÁ¼}ö,1Íþ bŸ‚ŸÏ-RI•ïT¼ lEƒžCx}87pAûÆûç†6’®àIŸƒ¿¤ñÙÐ=b &jÿÎmÑx÷y‡#w¸‚³äv™‡²Ì/¾/Â(Éd—4µâa.Ky¨ÃÐÛƒ¹¸Ãg ÔöŸ+=®=áÓ‘•ÑR>¿üj¿ë w<Î0n(•U¥äç‘Î,(Û_—ü–y—,†ÁŸkÉ8Ì`ÚìÁ˜kYª7M)_‹I6™Õ£¦ï' ·§eRB:^8®ŒÖ”QJ–ÀLæ^“±lR‹X¥ ±P ïJã!‚!‡§-“êZI¯Ð´vè7ϰªH{k'î’°º¦íI;Zn,$†¢OÀž”Á4îÅܰ¿ÓoÈµŠ´3Ü/Þ¶[›cˆ8B+–ŠÒÌ~8FÅšŽéÇrüÙH“¿rùršæQ³I ¬fSxÛ.ãvá.àvÎñ‡$ì@žÁScu&¨UµoSõ©Œö›píû@?ž9ìž÷ã˜Õól8yè¹ø°ƒQ”ŸÄƒY‡P)dK„ÝáEŒÿ¦lG@´)mTàX’€€¹‰=ÁÖõò¢$´Kh÷‰ŠC<7ÆÈ¬¼ŠêfÚ(¼õý1dç©&håSY¥ª;~Tt¾rˆ0"qñ÷ Ê7‡/òzÓÄ´z_ÄÜP|)Wˆû¤8åõž%Þ-Z¦]†A•ø§J–5.¥’·é§Tã1·êý¡Nã,Ϋúë@Üå$M m'.ö0t”Ë"Ãq¶Ôˆˆù(ö©¾à’ ›YŒ.Ž·¦rheã7Üêõ»FW=¼xÝXlæäÒ—ÄiùCW™cß;´Ø. gjÑ•Xc¯¼Ï­¢¨ïÉóxC§@ƒqí•ó²`¬N<`g¡ÅެmÓ¦œ4ŸÊˆ•Ž µK £»™Ì›¾ô蔨¨º /œçýë·#éÂ{l®t_¼€Ãp >„¯ñ=ZE‹8={¥E|SW]T<²WÕÀµ^‘EÃÃb UAy– ÍÆ£Þž3ƒÆ<•k¸O«Õ¼æ;¼Ìk'ÒîmZ©IK.âO^ïƒ)0Kÿ.Ð<ô¹"!'5¶ +é8T…Éøe[½NÔ¾.2jõS¨ÕŠ™®Þî€>6qN£¯ÍpÅä‡b‘3³˜2JŽë0%|~UÊ)3Q­ÀÁërçÁW!tȨô‹¢ÍùŸ÷aÊ^G ™Ì ½Ë#bTé­/Ad}ìæ^Qp„õ †ˆs/äȳLçï„‹ÜwQÝ Ï§ÿ Qó~¢ýMí8Rk•0ga´“aÇW ­ ©¤)gUŸ²Ä×R<»ý¦ 9],ó¡m¹Áy÷¥> 2hÙY—gz /%JÔ–HEž $.ȲÔ\~³4º‰jw÷K n§Ü w>£ëŠÑéfnªd±žÎÌû‰94«¬þñIÐ=ŠÈj°hBÑITІË¦;ƒb$±¸`ÈÝ>ç¢HUÝf$ëßÿeòö(]Çæ¬5\ !{,#Œ^f­œZYÆú¥Ê»Á•ãKX…ìhAé~X¿F™ Ѷ€Éƒˆ -ã0t™ p‹“ój‰MÇÕ“ÁÇË_“£‚W‡)Ç1oÍ ×°‹Ôæ¹Rÿëµ4i;òz¹Üsº"6?§WH {øÏëRÍ£Çåé8 ÿhëq{C6±´ÁLL¯¦ \õ¥‡Ïý ë¥6ž­Î6‰ÃGüvÏ”ë+¬8qBS‰<~ÁïÓÝ´˜"‚û„DEkþ’€€–g–Ý/*7hA¯KK@›Ô‡NŸm4"âØÏÞ¼‚ýeèêi3Î24ï‡ A¡Ž_^õg!š×ÄÚáÖÌݼÙàçξö;Ó÷¹‰:”ÝtkЖ­)îÂÉËPOäN¿A÷Ž·¼š Z)Q“õ³ ¶4—|¸¿¤V­ž=è5¡eckyS­ƒ~Tˆ2Jº|agüᜥ}°áöd~a={™ÿ¶_`£¿Šútá¯[ú<ÆÒñ`t‰§è oP¡BBÌ:€B௪LDrÜ&­æU­yc1`YÒWÅ÷ hº¤9Á<7ÄhAˆæê²k,Àpm˰ê@·ñsøÃS·ËŒ< Ĭ/X.'ëhÏÚÂ+d(G%eðÆÇ#º¡ð2_í3š'¥ ¶ÀÉ”9ú;Oå9+‚÷K ¢þåá!îu-¯fÉm3ÝÀ ÀÊ=Û1«@ds%ª²ÑXÝÐmUÈn5¿\|¤Il1  â!*[\ú“ˆ}àë¢ÝV“øcËÐöIÃÄÌ>‹ë|¨AËjÐ&#˜™6Èúî݆=”_$…!÷î1u¬¹! ž‚ޱº–÷㕉þuT¦Ú]òã–Ѱ—µôƒÖÓ®+hß#¯ ¤Ë´Í›;N‹s!ÚU6ä9Á«‚c~3îPSÞ¹ÆÂå`Ç /iY {Ù”ßõâäZ cÛñãQ‘œìÛÑOj`—¶GJ.…$eÚgÍi¦UŸ•ˆu¤¶~BÆÈÓê9vSt˜&uH‘é÷bÖqnºÓ™›ÂR|÷“ulqLÐ8ƒL‰Ó¬Ð=7Ì&URs•‘9ÃÛµQ|owÁ·¼ÕÖô‡«_æM¡L}\l×Fk:z]CW_ýšf òæÖ!z¯ú²8ǃÃA¨Ý2ïArS4×S4wÛ?ÁEV[=÷«»ë3…Ç÷Y‹zúÉ„ùÿ IPÿ#êÇ@û`pßÿ%^’c~àLþd7K«;Q2Ê:šþ¾å (•Ú)w(±ð½¡ê»GîR¦~¿;^ó_P•YB¿ßæ«FC •ôŒƒ¸ŸÖýD p%â08b©+¥–ÔoÓ+4ò¶ûTf Ì a ‘p‰„‚‚í[§I˜æ÷Ñõ"ëÐWÎÔîÌ1×Ñ]¶õ‘vd_¾ñOýÀ2h€#Ù•1›’€€Ëb ú<²±ï„” p =è×!­ ï¿Çˇ}Nm:¯š…|YßNõSpaÛD÷ÔFž±åÁÑ^üÜ×-°—õЉgÊDí?ðúaÊL!‡§Ôçó¹úWHÀìñgD¯4‚boïaš"&®ãè×SêôïxãýûZñŠ5u÷ƒù¤En¤€ö\"%§1DíËÇÑUÚ»4AËÊG‚¢£%·Q{…[˜Z„7• a§1WÝ"öŒÙ7Á{«L{pçe¨qnëqÇ!}«HŸIO&דp¦rŸ¶Àè¦ûƒ±?âpk¸öð±¨Ùdÿõ}b ûâÃå4ï AU˜—ü€E¼û¼ÐS«š»è@ bÊ>'Ï•ˆåø,Ò;\ºruÇ~)Ú¯}—ùÁÑma‘•¥UÝ…©Hg@  ¯„’X™R^Å8‰é1áΘ@XG_­UùÀ¾˜ïÓ¹N²S)F÷y:³U¦ƒW8 ±’ù‡I´!œ5m—­+úë ˆu5楘YÛ¿’ïÞ9‹j6…k÷_ÿ¨'í½+Ÿ!{É)4÷K‰!ŒoìW{\>”Ôy÷¯3‚·‹P±ßZûâ{cÓæËö”±»äUºttW:p¨R™%—©s{—Ý@l"œ¦þt"g¤>œ»œbP´ãBLGñT¡TÛ3£ËHkÆ$¨“”\a ¡YJ•»€o²=}Æ÷{);*§†:N—u€<%ø`÷Œk`u÷~bK×í¶ÂȲ¿æ¨æX§wv1ãì-L¾¦=⡥ɰ$äê¬iüEœk^Ëž´øº?øÙí²ãx™Ò;Óg>Àó×¾æçvIãAndŒ,ŒÚ7˜Ô¿OuÕ Gµ7(ìs­¹p.tõe¥rËÅ`õÏ›Þ7 »¹þ7Í$W˜úæàÒ¨öß.Îþ†ú '2‚Îh´É¿ŠS©À‘'‹ÕÜŽ¯måfX5MÇŸñCÙ郻?À—þ¤Ú?e‚øíx*û“yQ|²Û+çše‡Râ¦ü-Û&ß»#бæ)®>i.·Xô'›„èÖF¡î¡ëk†´+êÆÑˆúMñè<&!¬w‚šžÜÇc#Wc4˜A@kwÖG{–ÕkN ô¨ku9cá õžsbëd?E"æµç¼›;ÈniÑ­ÝÊYò¡‹TM´Ž=»»Yõ©ÎÞ/]gï€?rÇ(¾Ð¿JÂX1sNZóÈž‹V ‘xÇò{\i@­Riæ–þô!y²eeþ“UúeDÉâsäÖ¾!–·¢ì!½6œÜZ}w´ù{Ì×0­Ü®ºõAÜ¿ã°gàšƒÛù°Ì|·Þ¼Sõs[äXö7£zmäQý)¯XJYßr`[ˆ)\Äh˜¬*\srÁãÆlM)7‰rfÇ|1ҽɓøý_M¤“hû‡µü‚Æ BYæÛˆa¶Âe"åÇ©ÑÈÉZ¹$ú¡•6í9÷ÞYÃG<žŽJ`÷Šø‡™)[ÿþÿºGSÜú²®Éǹ¶kcÊÁêï¤Dü3#Ïõx6Ô’&îËÄŒ[ûå§¥ ü¯âáß°€$ $Ý*‰q4U¤$ïÔãÕa"Çz¾—š;Ë9±T€²˜ç¬bÄøÖ¥ªÉêOÚøXæÈmþèö»"Z´UQs“ùtž<ã¨u­§KáüÞcõ¯îN¤Dó3R×õòp‹,}Ï‘utÖA[gaÌ cƒÎú²@ñðœ`t>êã²è¼OhVQupIÑ2ÿF}´ ¸ÿ¡{ChõÍ¥ Ð’–#â2‚ð³‡ÎµÞòêôšÞr/=R?ö¬Xlj~ÉVUéÀ$¿Wžê+A!ŠŸ ¸Xr –m€*†›Ü5>ÔØ[œ—M³¯NxÈ6b0q„ŠxdvÒ¿õE’Ëô#Šþk¶BçíŠ5Ü”ÉëÒÑ`‹­;€¸.(ªõ #mîàÑä[Yò47‹ä²QÝpü´>÷?… LõTEûÌÃF3SÔdë<#xUÖ#¿Ó¨gŠú¢š@œ×1„~Œ—z®³ÙÕRS"ا”Íx¿tW^+[…îÝN¸#uÍõÄ€] Ÿ /m†aTܾÁêѹËpt“ãO§ܵ¤¦,à$Óèp×Èç·eQSÂù`(?#>w^sxÅ|P¥HŠQèÛTwâžI˜¶c]CKm¸R ‚ÛVl‡¹Bl¹ìÒˆç*®tâ Pöä]\ì™é{²‰ŸI¼vU ­ç{›äçè/KLÇ\zuH<±w…8XÒ¬i­fäÄäždSâëÃí¨Ð588±\Ùq•'U\Oì™8kê„Ï@ùƒàaWŠ8¢ÉM=Åfе~fã¿â ¿°´×¡’…òuðp”âÞ«£‹äI"èm[~áî*}ó`á§Ö»’…ÇÍ$F7ɳñ)Ý®l‡SF“êLšÀ–ôÖÝÔªYÄOˆSSÚä©5Ù[šïdwÜÓpósÝŠá<@äAÿ°€õ/,ƒÓ8ïð}†)Ý™©Aqâæi¤»þ— mk²Ø”ΑJ‹:#LßÏnØ×j¤iÅX²ŽóI¤Û»ù펧š«E6Ô-í5b¾>±íú\’²j.SL…³!H²µÛÉ5ªö¡ QG.ˆk1eK($»ÿ ^$[¯ž¼\ο4é=> g¡ú‡¼ÍOëÓo}ÆP!{›2;JŽê ¡„l'*î;ÿëê1}/̾lÔÀE÷‘t™Dðÿš©z yì¿Êð&N©9."¨‰2[ήt¸Ïž"Ë4’€€¤`ÐÜuCÚzÔ~`)­´¶›z´sÂ3ÐáöŽk,.ûžD 7UNCEî˜ÃÈÑÃøŒ¼¸ü9-Àêgò¿Í?š]%&æ‚|$*‚ãU‰éøðb§ê5é˜ ÜÓá ·?@ò°–x…Þi¬¾xa#Å’ÐÒìÛ8rZ |Å-9 ²•Xˆ•P,¤§h8™;‘y;°lÆâóõ«žáHºk\Q/ýÁé¯öÔ ùÑßg¤y-3>1é”PåWq¡‡vv¶âO$ÛºúNFëTãœc ÒêÐŒ èËTHÀôõ ñaãE;lùåXUeÆ–ÙµMÍf| \NïÉžsì¿|³’+§s‘ÄrV×ûµL>Z»Ú€xà|.„ÀÝþc¥jd¾XŒW«É¡9?¿ —4sl}V-˜ž¿­°žÎï¶î¿Í âÙì—ù£R*S‡«·ì9ª4ÎÊG\ØÀª¤¯ãk¼Í“eú×­—XsÌÀÖlŸtîMÃtÿ™½ÍÆ‚ûÙFhÈ´—O¡K‹¢eþnS\„,ãt0İPÚõl‰3º‘^”ÎD!7VcçÕ+0ñ?@Ú ·¡«•ÇQTóŠ­á»ÉÐG^Îÿën§qæÆ¾ô0™L˜wfQ§Gâa× šÕÜ’u‘~ÿæRF~ª_nþiWÚØö䔌!O4`ç+S쵊®7 ÷¶¾D‡$ÌÅÛßx@8¨>5Ð}Ž//GX?YÍÜ ™à¥jd·ºÃñ±ÞšZ³½4wÖ~Q-þŒ¿ÀâmÇ—Š|NqÆq ’|¥¡¤©¼©ÃœPTÆCð f½ ó^ˆ«‘Â~ <Ø•n§ƒ´»Ú=žq ˆ•; {¿î¦í<Úóã\l=Àˆ=ŒNúó…S É—‘»îŽ÷ÔOXsö|´M¨çt(7t ›³:ô*hÉo†!þÍVG:dÑÑì’FÎ[nîý°”T0ƒì€_Ê9ØÈòtõw¼/þXajÇI±¼‰,‘tB¢7½TºcµùJÚ¬12Ê,âóÆ>-üjõ€ÃG®Ëˆu0=p\0_ÍÆ¤x-óÛʸz æDäºNÝÛh©R~Ì~M îXúµi'tÙ\ ¿¢3ârc¢’€€ÇÈ´P¶6`ª3Ó¶iÜ¿u°…H> qk*%¯[³Kàü皀™ Ù;EôͪŒ-EKw8Ø\_:µ¼Ž­0LÙ|ïÿiG’ð©«^1ÎÌß eç5#'-f­(,Zm*¬ ƒúrâ¾òÒ 6Å—“à¬9ÊÔÓ7[U wÂߎ+÷öYD¨7la×~º÷€æâ"Â#ÖDìÇ(iËê“™ŠlyJ´»¦dÍÀFI UÐkà\k¢þL%|_S©×3I8›Dw©av ]½~‹¤ž–ÙÇŠQâ$ûxœ}ëä_óAà›2/ðµìÌš;'€"Oï)ú»³ñ dtÞÿOn °Þi¢ª©å‘ërk7£Åó[G¤¬ œ’ÙÕ q ™@ú2¤ýžAnˆM—xÿõB®Üœø!ûâ£ú̸"Å0ͦ³Õ «O‡»Õó|añ8­>>Î_'b[Œw'^ƒ±‹Û„‰b¤ ÚSp§ _0VøÆw Äv¯“Cžæm¶½º¶_2»ÃJ ºÑ¶iQ ^·9Íêè0#‡¸åÑl*ÿÁ˜6zd0›Wd'س½Óçèù31åÕa.m ä ½#@ÇÂ5¨6e&³…ž_¹{ĹëãÔ”µžáþú ¯CÐÈ=âñ9Ïö´Æ§ÆéìxÞäÒë¿É½WR½ó=wkîÿ²þEc1þ<Û K=MØôs7‹û‚ç㜞ϹúþuªpnŒzJÑÙVñ¨`‹@™ŽéïKôC±»nƒå©“õ×ÿ´kÍ#ᣫ4š‡ ™á”–ˆŸKóÌÝ 2d÷z¼cøã| ›Y[9Ø¥ K'ÂÛP¬‘×Ô`}·8nù‘Õ`÷5„7sµë?ÏîÚÞ+ÀY‚°&…ñA;7=ZE¶à—*…àz Æ*;Ü 2½kuÂW½¾-ýÊöî°é¨_-²7îTÄ wŸDtwnÜ¥BÎÊöš"°L.dÌs^róFyœC—;å‰ŠÐÆžo÷`:!^÷ó„͘qá¥1N˜­ƒÃ[ýöD¡TŽêof¶8=÷óګͯë5ˆ§ ‡NP£ëš¿¹U°ZÝè Ö­$× i©¶]éµ ­ÀÓü´ÙT×¾»¾‰KH(¶·Þñd•f x`Ó¹ûi28¸eZ"·’€€áß´wáÓ$½sG|4`[Òì#6<0`¬g´bSÔ›SU£>´ÝO×q$… YgÁg q+ű²Há=/Ë£j(Ìù‚ˆõ§ìü$€ZßpèË‘½w¡ÈT÷WàÆ¾i®.Ö$–B¦šÞóªžsWÒ u“ÙTÊ.dn+º|Lî¤Âq¨¿LUn<8åbs‰Î·0^JÂÌå;ôŒG‹rŽšèV KxŒB…-ç| 2Ñ£Q 'RlÏ”/&ý§$[¨†ôáAèP¹‚Æ™doóþÄX寸s}°&Êî£R}ñSÎŽ¥DÉ5€ðÉ<Mí)NB0ãK©ailÅ*Ä;—Û…Ý t"$·ê¹®†–·Ù³ÓäÈ@ÇÖ[þª7¨÷ý<ÿ?ܺý(Bø¯™ä†)ÄX ¡#Hc^k—võgc— ^gÀfßX‘Q“⑯_Ñüë‡U@Ãl ÞUN2zè­¼ÌjqW(Á`ºœÒôßr¹žk Õ™éös°ASйîÑ*6x÷¬z ×:„í&«Jß(!û¤q õÚ$x,J$±?e‘(Ñú„ßçé˜óáx@ïn.DjÁcªž-¯‘=ð¡¦S¶íyŠÓÃÉL_}òÔÍ0aý{çK·ʓ<"·× D벬E!{Yùgðú?9N/ ^‘L‘§(IÔ­Ž*ÕŲô`l?A°²«4ÄawªÌTUÕÃÿ;ºŠ‘´8ƒºÎ%­/óðà.ðÐMpú¼ÒRËâÔHÂ'ÜâÀwÛîZ`s„)R ­&b^]ê ÆÍTm”ío98+i¹ˆ¥ Y„}il=çØ}Ž«»¢VŸøfEGO¸w«¼Ïý!­ÛQˆžåîhýÄÜ&je½' «ëkO bM°æ=yÚ·ü™8ÿ¬íh×¢ ;n J&¿0-që+ ¹P„Q¹A•ƒëýÄWŸÒ”–‰[šÃ$Öäö«qÈÛë÷ÙyçÜöZ÷Ý®¾è5„(ˆÉ²V1ýkü }Žó° ò¿>›¾(w¥Ç‹ÞŽ©È¥:´˜ø%Šàüü÷*¾ ¦ôñ¸ëÔx^#ƒ(Qo\&0Þ Uæ{e›¶B?¿¼4t#ÙÀBëiÚŠ‚FƒRÝã»ûJ>t9=)O ɲEÅ µŸ2ç×S’€€Øî‚]7Ë#u9ÖÞ5ÖïýêægN2tXlïüÓg˜§ÆàU‹gZ¶å$4 hÑ¥S€­9Ԧɫh„Ûܯön¾›¸»'¢ ¤~§t*oo—ªÅÒ}÷T#5¬<Ýã{<4ŠW=­}ûàèžäH‚6?Rxí÷>dtŽ‹@jQj\PX-'r‹}#°ªÇ\*Kr*zCA^o[¨¸G@Ø›µž-1¯zÖ?˜­0ßr8 'Ú½q¶I=¤o·°d%óÆ8EBZÅ} Ž¡t»£ žOò.€ ŽÆRþyå«Xÿյϊ"æì$ì< ª1[Ã^î;cÃQ íqõ ŠÞj£–Âèr×Ì šïQ.„q¾¹‡9–ººÈ³uâæÝõª1²ÐWŠ@éCŒ(—h%±‹Rfðq±—qöë\ž»ÞK=¾ý1veà¡ò,D§NRh1º’ƒmòbˆ}û²ëÐ.ÏnHd~’H]ìùRk_¦³9«–BU X&Ò"øéLDDQcɾ–RçÑ„¬lÿK)¹×®’˜7]%P‡µ]Mä¬Ê@kg·ëøB›¹‡:d G¡žÚÌOæIÙ™æÓ ˜ƒQ¯‡Ìˆ~ñÚ Èˆ¾Ç· –g¸ï’þx~#¯i˜†[b»<Œ!mâæ¹…xRŠ.VéüÜÝòWüÆ€à7ÊMiJN ºàh/=à·•†=ÔåöæŽýå”ÐéòˆnîógåÊè5,BËê|ÿlÔ˜)¦H›‡ªÄ‹ÂeZ&ºqs“§Ú­™¯»ò®îUûÕË-Cß~¶5Ä…©R½ #ò’½*¹£D²f­aqã<ð*v(äíõ× éK/Olhr1^—3EaÃìÖ³ê6ÌÂBÜx0/Äú±—aØå¯´Fš3MbÐü7Áºã"fhKÐ~P|qÅ"ö¬YÛ…c=°0OE04#NKê "ˆXœûœSÏߟ®¸xo¶¢?ô¡ û2¦º³d–!¬"r'òéCK÷ÁCž&¥,D؆VÙ1Kìi-ÝhµßÇnT;ûQ¨˜Ž¥êOh0câ{šÔTd6ÝT^49ÐøöàF¨fº(ÿ^wàqÝu¥- ¯o©Õ» µ‰ )ú®XG¢ÇáX^- ûsŽœ6"_yÍíQ¦ˆÏÝœGVÓð?Yy‡ïPTÒ¤û­‡2cý”Ðû9X›·WÐî’€€èv;(ay¾ãü,ê±Nµg~ÅÇViÇÍxÔ7¯±ÿT£¤‡®º¤Ú †É±µdøoÇ/’@Ø ë>ež3üSPSÿâÖÉ‹[žN–X~Zä’™X-Çh 96¹5¹¦Z’drý·…fR‘”äìò½kÔbà$0ˈêÄaW7zÆkžSƒÎÓ”¡[8½¿æÑ|„r2ËaB#¾ ‰WÕtEÒv;GI©û’M0P;zŸXZ†ùË'æ«d<JѧÞZIØÈþŠ;ý6S1ãjœ\ÛÜ [H%L0°ÊÆ¢÷j, üšqÈKåA„æë~ÁLMqÔpé…ôǨdøI§*õ‡ÍøÓ;µ{°ì-“XðfÖªyªá¡t™YY‹fÎìO´Ñl!á^¿¿O°v ØªÿÝìföì™f¢2–Ä2ò‹­(\µdâ„©ð†×?€(”DRFF¤kD§GÞ²{Q»9ä8p#›0 ÆH6/Ôê"“±ÌµÝt«?‚Úxï*5@8¤,?ª6©`£þß–\+€ÁIš&š®²(zÁ†Þ²Ú6\y€8ŠÏ‰yN¯¢>-ª2u¤¢{Xë@¬ô0ãùv'âsèTu½r¥‹Î¶¨¢ŽG|™´8µËw¸;ßÎvòõÙÐ.¬róg¤“óªVà‡ =Üæ¾ó€_õÓeºz]X=dòEXÓÃI‡:'Y":mk¤\£ÅÕuÄlª,ň,RÆ‘œ±k\V/ Èœ‹÷s5oë—ªåä›|r­˜“eˆöÞ‹7¯ ‚«Òð‰™õIàëyŠûl€1§Ž’à)Á¬b{¥‹\uá;h’€€Èפ³¿M£øÕ¸j~Ÿ­ ÖgŸ“†Éïë9@¹,¦+Š!–+‘°}®<®óš…¥…–/ߨ¹QÙIÂ8¥dðuô¸Ã__m£&åü¯ì há Aÿ¡~çûʽf®²ÃÄ‚ô¢}¸øÈÔàK–…0l$èKªñùdìкú÷Þ)îø¯»ÉÐs”1u×ø“©÷àèEóME¼ýÙ<ës’/±Å¯»(OtCtiú¨ /Èf~!‹²¥€===¯‡Ó±t ÒuZÞ_ìetÏ Ã2ÍyDôÃüÓñ‘p:¢ù<àDÝO„Ï3éVoíC°"ø ûp@yÕø±M®Û†›ÍÌi3ñ·šÃ~uVÇÆEÖŽÐ/í®Vô@ÚºZÕz"ŒsGžzD íÍ·×Coöòr–c¡ª‡;0½¬˜enšŠàߣ.¦¯Û.%ÿ0]ÝûHJ|“v'§Q3<+1Ô{Ÿ–’³ÂÌû;«ÇÓ_Ú¨¨‡’l úöîœ |üÇ·ü¿ÊZÁ,5#ù¨º\ìnÂ<8I|AU­ThÚåY@Â!?„†­Ìå{]¡ñº¶“LÌz£*¢ŽÛ”xsÃ*±ð³¾;ZÑ¢Üc Ç3$v6þÐe]?H’ÌŸÌ¢Á³ÙàùTÔKãõ×'s[ˆªÕld0“DÞ}|ЦIë¾~¢Ü“×÷y]Ô{/©°±§H3×ɵ§÷Çz™p¡×ãGí£…Ë•y Ô^¶k*l¡á•¿ˆ ‘±Ào´ÛÛá¯WÏ««|ÄÃÂL »Ñࣱ‰ L$’bó ?b‰`'iXœÆ+ð˜$ m:ßíKßS‚Â[¥ÚE"ï6¼¼*E\Æ&]‹+ðîdLÕ|Ôe{ŽÄÞ¯ßv"¥çænõˆ!m“ _sÈϤßm¿)B17< mŒÿ§ìcݤ™äTóè½ë·zÚ8ºÔÖ|_„P,i^RÓKmyi¥=ª2Vƒ’€€£¯«"ŽKV;÷5IZnˆ”öFÜl>Ñ>&¶ÒÚi‚oßX©u×N’¬¤– M¦80ûjH/QöMò¥pP—ñ9WœQ¼rD†£Q( fâ™agò~`s‘;NºàpÎÿ¹ÛGÜ—™Á’¹Ÿz5T –âÝq:âBëØé9º°*»¡´6‚û€;59åB¬q 5 3OÚ/Z«]$~;áVg#€ã%+A‰7*Òrä¢èµ%E5H‚÷x~ô\“B½¼ß[G„Baè†ØDzM~¹Ý´€Z¸kÑ5.êÚià]¤~~bUýÆÔ¤cKLýŠá|®(þ|—KÛqüÜ΂Xºñš¬Po¼kð<.ag¥”ÂbQP™çù½¬aôx°÷«O;„®Qqüâ|ÏöºÑRÜÄÎySda•¢¾[#¡‰@8Úzº§IÍWÌ&_­HP“,f‡°àöÔ´$…­I‹z‡¢¸ÚæBN$ãÃv¹(<$þ_³†þ)ͳÁög¶*ÛVH4Œa!%¹Øw®1­¿äíŲé©÷c–8jL¢gÏò€pÄŸSIt4Ôëªâ„@»”¶bLDý)Ø‹½/ûßb§ih©ãalÀ(]Ò‰lpæÿ8» úÅ&¬­šÎ‘Ø"„X“Ù;d€'Bæ»=ÿlNfÖ_ÈŒ#D^úÌ×°˜/I.oW†bK² åþ¡©T‘¼98çèYÛùJeH©å”vE5Z/C)àËIM´æV†:?q#ß¹=‘ì’/Óô4ϸ$,޽‘ëDa×å9ß%Áà Ìu(ïéW_ŽëϽ®Óƒ¬‡ÎŒ xûõ)u0+\½\X^Œ—í¶ rûJÔt_’ÈãÒÏWÙx¿@@‚|‘˜0ÍN"Whß•¯‡Ýø·t‡ÖÆ MâJÞ…•Wx{·H0ê9V›=+Õ–¦û&`hô×ÓW©¹.j1×ášAÀ9'ˆŸd¿p`&?­ÝA×~>ÂÏÛl¦K‰~¸aÎ;‡\ZfÖÓúà¿WUb™ÊyÎ4dÁÓ á¤|]ަÐÂËCÙ¿^¸þ&:ÙéôÄS‰³±jìµßalE½¡•‘v|†€¿éú[%*ø—L€YR(êÜŠ¼µ’€€ÝZ¯Œ"Îßú3T‹ÈT§ÝÊ˽ÓÎhd§ ÂÇ4¾¬ë†;°Òq4îÒFå(<‚ä^æX†0UÍ|x‚„7,i†ëÿN×ÎETw'nØkïg^%:¾3þ×÷ž{} •¡—ƒ«lÞùÉ–Á¥ùÍÑZG1M›§¸Â`Öu¡7ý̃tfQ(+¿EѬ½JWö’Hußj >س'x\ß’ÅfìT‰¸²žv²ÌW¥×Ìe0z:zC²§î ° ïC–鉜ñ‹ú+Úþúñ–,ľ;~8„¢3E+ø„éÚ›²ràBÁ&§ñXf L¡–*B¡Gy>êG8šMº€\Ÿ62jôžJŠø&"ï*$¤zB¸à#a³)3ßJw» ƒì<±gʲ¨)Þ6«wÚ$ßК‰i«; ‘ Ÿßî†d3œ˜E\Q¦ªc–-‹ájÑFã†I$­X%ÄéT™Æ&½Ž•ÊSN=d sC[$bP}›¼h€Ð m«/¶”a"J¶ÂHï#Þn×Î^_Cž“ü’€€Ç¦Ý›¾°˜ ¦b*O¸•$Ý•8¾®U*KÍ™6ê-2r¾OÍ™(ÿ0¼³Ä¹µsÇ륔ã_ÀM‰lÕzp¹§;˜An„[ÒëL~r¡´5\ÛbçDoÈúLõî¼Q±Eà/ϰÝ3U¥#T*ú4ÛAøþâÛè©Y¢@Û#~¬v.þn!~ÖbHüðéQ~ÙÑ ¸Û“£¬Çzåèý?ûqÍòK%ŸeRÄIñk`!n>c¦ó’u2txç+#P14[Ù^qrxOÉÙ$ á‘ñ°@ƒîµ2Q‰ë“ÿMùåe$/Æ¡¢°S¯W¡H_Ÿ8(ö‘:¿¨…Å¿ÏOùسA”YÍœê½õ;ø,ëa.Õé89?ñÏÞG÷p“p<ÚnýDI6™úƒS²y±k˜±6s‚ï9¥î\¥ÖaèEÙ>+Ÿçæú“?oÜVh–-Tši/6œíØ…D´¨x=5I²,-æC(gÄ–dŸ” ¸«Á6-Þ[׫ÒM|M2 Œ3ìn¨‰p›pÌ®’(föNãDÒŸqe7Tê€õ¦ Ű™9©îB‹×ÿEµÛ|Ês¹Cu‹ŠRªj_GJ€0IV%ª üNIÍ7Ó¸¨õ6­‹vQü¿{™·7²¶a,±Y`ìÞ©-‹åUÙø‡3µBÌæÖD%êV)4Y9põÂ?Vjyû ™5þXÄÝâ®õs: ?±"\ÅHgwÛ•}¾†wmùUû”׈>ô§€«¿ìÿùm¬ŠêÁ0  +ui¢«,Š‹ ‚iJB‰Œ\ªNàv‡®½áˆûÅ~ð`Ñ2ZØÂ“>,‡§Í§|£xd…5“(ÔÍ4nÎÔCI³ø`ºËY?þés‡È˜û­FVG|…º†ó(u±•Ó±f¹Hä3ÕÖ§ÐSÛ{ŠsÂ-£(Ü·×%‡æù´vëŠÞ±Z—²Ç3¶föâ@1¿‹*•‚#>`„¡¨¶rì¡5»sA´—)JèÉúdÚy…äÒ¥Kƒaé¿¡ ´û”®Añè%Áô>®Ìå]ÁèËF³3)üŒŒ-§(fÕ[µ :_§]¥6´>ÀV½fQÈÖ'–$ÜO9úz˜ß8,,bG:Þ¹Sáã´6K}º³Å˜c¬OTí8EŒ?|T’€€É*à‚ø‹ËÁ¦;§…&oH¬Äœµ=óÒtÛ…ˆ.\s…³û^ñí,‹ì«Ó‚ ¢:i‰3Þ¼5Õeá<SÛ­»Þ ŸÙ$,t·³+êL/h"“}/ jg<´[‡FŽZw2¼Ýçbdª¤ î3þsañ—¯¢ÆÔ"â×ÙðMF6»/"¾ÍoTüAr¢Þ‚fkwžQî#OÖeç›’LÏœ¯ý]ã%¤ã˜(6~jf£0 ?î]v)šÈJ½H¦iôhÙù{ôÂ$\‰¦iªõe»`¥+©Š¬â`Æò" Ò:(‚;t\S~;ê×)vª)[ .:øÉÿ4gø|úu UÛèL­U¶`z¬Ì:X·˜¹(æèÕk {Ÿ"¢¢éÌx€+Eé†\½Ÿ(㎸8Ýü0ÑÂﺸÛ%IˆŒ*²@GºDø>âjæy óšái¾Ó¶ü¶GwÐ9íjöÓtr– DÏñ{sLt±Ï“–Û°d&}E¨Pº¥ÛÄ3]Y"PK9nGbm±[±æ`â4ô/èžô¸ö(Wó©ŒØxî;âè9S.ïÏÑGU^Y€Àçˆ_qgÐüs…íÜò”Hi#”[ã™ ™IªÌÜhÈu2Îi€¬Sl=óQÔª·s†g©bè8 ñßø,Ó›ÄñvdãTœÒì€éc×Ç>ú€ØÞ ÇææÕ¡p+µ–mðÄžPFòqåyv›¸" ’ób!‰YönÂ#íDú?¾Ø6VéÔ>å!CaÎ@óâECìq‚ç&c¥T3>u§}¶‚ÉÎjg2—&¤\¬Ä’ñÊ0ͧJ™Ãkjx*ý¬¢~”·¾ø/oþpMA~$'2«Í½›Ž-à>êÞï‚£Œ¬÷]2ã“a±$FDž2ÑÚw}ÄyòuÊZ0í5‹Hû+qí³€>W¦HÒw`„ôœÓ9@Fn$°T›³!æ5m“UуçÿF [[*œŸÇŽ…"uLñ/B/žÕ®¼ÿMÚûáR±ÃÐ'$YÆSK™5ß»ÿ­ÕKÙŒ| D\;XižÝX+ƒ- ø–‘—ŸÊb¬~5[Ëð 5h¶”;rLŠý ’€€áÿ’8þdLË+ð`¶Z\ÚV¤Ç§T:5bàÍ¿õliä~"+'-ø™a—v·Ð´¥£jÕeî%Þ=„vL¸#¡üǘß5¡†½Ùd#Ç]çgù~ÄwȀ̂á ³ä«Og?Ÿ˜¥wϲ…:0‚é“•i{æÀ<°èŠü¢Þƒhß} ºÄ[%Ö´Ô„†w[3Ķ*ce&Ó·3˜ú²¸¨ÿÅÔì߉ùFXl¼(þåŽÈVB{&.î5tÙ–‹{Ñ”y'`eLU1/¥¬}¡”ÖÍò2Ž~CÈó4´»í² ƒ¢@’€€É‘ÔåY¢ígÕ{êãu©?T‘• m"*¨Joö}ÕÞ†ƒ¶§VùÌþ£å\f_"•ªŽöx]ÉÙ Z55¬¦º:[~Hؘà__ºëž {]AÀˆ×‰™µ™ˆWë¨VU¢1Ìí5D2V3ryÊ_<(¬U[ç¨]Íû·×ãûn;xÝ 4ÔGµxÀ=rË‘©€•¶­Wìç!£E¿žû p®gO‰©eoÿMt²†/ê—©½ƒ—3¶ê]ƒ‘>Ž'kü”ºR‘l›óZÓ+)TGÝà:K*#Ícç¾zhW™F»µ"ºèkÎ?fªµi íZã)Ô I¡b¥#áh†%F夶*"y¢–eÉ[$6îâa¿Ó¡,÷É’€€ÒàÂhb¯ãdGÿ-â{X°UwšjIwpÐ…r{²+ìJ|Ò8㲫¡Ÿg¤2æç@¨'h«ÐqÕˆ‘•gf޼A»½gR>Ó™9Þ zÖ5²"ËVæ„”rßGE•»G¤òëßüÒº àámº ›úAúÞúa4Oiþ2 ôaãfJ‡iyŠe,¤é¿0¨ÔöÁ8h,BLÜÞúŽ|w°ë£qz"qvt¿/]rÓük©öB|£à '– ‡m ^kç ‡¼¬ämx¸ãe ãHÿÔi@coæ÷"œ̽š!V˜p)þ^\Û ‡U½ZÆ 8¹ŽÉGî<*D4ºßQÊaž+‰¼$ ˵—~¥ýbæúÃzáC)À]÷¿ÑT0|KIÔÊ$~yçÌŒ’qÜõz{Âær D~pÎ9 Û6"\ÛËd ©‚ Ö˜R8‰M•~®ƒm:~u–”bI‘¯o©9€C|À U2Ã;Áæzk<îDQc«š^Ä›.»ú,þsfS:5^™Ô(@®]=¯$ÙÚ‹3°8w5ö1× æã_@_é)YÛj³Œn/eø©“YËÎä§rÁüøŠôb|ãY•ôús8àg}µ•ÿÞv‰ÿx—SÃ2~h :ÌUãùl„mS¼ ©mà(X–ªÑŒÒº`>mÏ\ÔÜà–d˜ã‹sÁ1kù1o¯jb:8ÙEï»D Ëm­]˜=ü§üßkm}‚ô’)Ü–Õ>¼½ÙÁ}¢ðŒ­Ì}og™ ŒåÞUR'¿[’ʇã)#m’Ãâl•¨h4 t`ä¢m|9ò}uÎÇkc5“ ½ùZ<4ü‘­Yµs¾°Å¾á2,ÂX|úN«â'9$ï&®eªÎÃiÌ,+¬+šìb—„W/îÌ·‰–«3ÐùßsSCù^^ñÅ)Òetµï%ˆ'¹Ë~íòou‰5‹ÆbñÞíæ®@öÎ{ÚØ=aZHÍ-òN̺6®R¥/·)ßûPCaï™CÆåfJÄÍ8±2…r"Ît@úø8_Jñm |°Èf¢®CÉ>•|êbö?ÍH4Y ¡5?ðkÀŠ1’€€­b®Å¥Nwv ãð)›2èI'‹ÊàUÍá²Òq¤ ÖHç2Ü—‰\wÙ¾À…Â'I=}êk7RãÉêoM‡¯»–úþJݧ³Ú ƒðØï¥­¨‰½«òKtÏÚ˜ #‚IÛ4drî?_6Z"YþE¥!t¢µŸn ’J«u87'ÍodÛ?Ç)ÆÖÖ{›íŒiŠY¥”¼øç½ä?ÀŒ@Áy£•`ͱz¿"t¦/§éŽdþ³(Wú¥s+¯íWïØäÜñ6W(w_Ú+¡Q‰Í@nÐáá/L˜ua˾ÂwhIì6&¼¢7ÄñJp²7‹“ŸáD "¸dC饥¿¸rl¤›­:'x—e­.]Óì¶£gi’¥Êìrf¡[B¨´çƺ¸Ì>”*¢–þŠRÖQÞJñóï9é¯@Ñûòù©k!ä ¤‚å“Ȱ|ä~Pg 'ÇŠ“õúº†Ü:§æW´8E pG×­©Ú£ÏKÌmäaSiIJç/ÙCëßøC8Q(®¤í‹•e¼äÕ±0#ÓFÇ”œÀ2JqDº ¡ÉéÊG+ÐÞè©w_Óeõúè๬”d¾Èˆ ·Ï‚z¾·‚ˆD%ﺧèzÔ`†úz»xÑ}ºk*½ó ÖN€ez~ÔRá}•Ñžs Ê´BË”˜F)ª¹à~‰µF¯×›ØŠNSMJ~•@&|~Å褛rݼHáZ¾êOÝ ‡<ŠF­k‚n”müO{p:žèã@Ì'¦®âXàXåéusª -Nî)}š2œT5 úAêE uAϾd,Í»V¸]ÔoÆqfaîIܤßȳŷò%»¿N|•£‰ôáâÙF\ç‹£Oû!çߤ¦í“¾¢D¹€‚ÄvóVóÏ…¦÷Zˆ/j? E„*gÄ*¢–uÎRÛ„M¹Ô³KÞi ô;ï_îf]ò:ÙsÇ…£Ó:K'âÅõÝÈæH´¬KKÖýC:æq|Œ¥©GBûDWÞ\yU 1âu-K#ÁÆ7BDƒW·ajN¼ÕÉx¤|Ú› E3ïþ'­ßm¬¹¶Dðs(£++uT´‹ÈƒÞ–†dLÓ†¬gûïO|’š ¶2ÀR ý˜6e·²m¹£u8j'Î]†Q´rìLe1h¢ ÀrŸY’€€öž‹ç'º½²gl>wy±×Y-=jíΗN™0M~ò„Šõ–‘¿®zŒ›LV,èã(4¯ ˆO3€þý3íqâ¹Ãd?UšAŽ/lj`äж‡·ñ«¥•ªBé‰z ÷ƒ£ÖR‹`P¶mk£–©H[³Y°Äa¿/•O3%yÄ(PGÙ,S #¬;¬•DšT”ÌõÓ‰ÝXcÕèL:/~”..þç*W²ZÑ—úH߬ä·öÐÖüqýÛ+Ñÿ"Æ^HÉ`ð‡Å^mùÕ†è&@Ú<ÑÁÆæ².¸7T¼CúþdÖ#¯9Rx´º“œåìj =>§Ð—Vw8’%;ˆÙN¤7Ð’«WK’u¶ìŽÌ¼&ÈÝwÃðn'˜Ó, Mì@œ–\»³Ò×ÇZž»-Ïø%»{qYU~K56˔ŭ'&gí÷9Á°%f«úôÈšîfÍL¥¹ŽÀh ·nŽû#ÍŠ™”ûcjäÃ[8 '`´,Ÿ(»†P²%µ½}‡‘Þ.iŽdâsz¦à·+á¶ vl[CE¤7”{ÍÜò¤DszÄMÝÐ’ƒ)¹c°¸àp%TÑwmAÁñë¯kŠPÝöNÿ¨g¼ê@À­,Zq{ÏÊ9Sˆgzs´ÜT²AÎÙKæqã0«3íúbÅnÉU+Fª3ªÍ•îSYi’ º‚H¯Ñ°mTUÉZFC’œ¸’€€Òl€øMM†h®MXo´¾a}9=äÙÉè•+ßuÖm)"Ûˆ.2³„Å5Ö*á WT+í·¿,¥>¡¨jjÁ÷Xü˜·üÏt…$Ð÷V†“+ÕH’Äo†”R¥Ñ"lÄG >³î ù|l?›Ö”Ã}M%¨PW>óŸóÐÿhÁJ-­žãD…uØ$šÓ ~ I6±k9Û‹fs× à“îÅa‡˜xè2lIŽ?LP¬ ÕÐÐ¥Q`ðR‡ C˨þø¨HkÝ»‡˜€Išh›B€1¢ÞÇ ¬DöØ>¸“ð˜ò æš”^?‰v!¼¡G *®›k9]cÚ« ƒÙ}=1܇Sg¨Ð6ºÍ r+½„òjÐ"eœÎ¼·‡Œ‹wUøW6ËI}%×ü +t¨yU¸¾åâªøg…!:6îEêy]ßxãôÎêÚïÿžržÓ HõغWŒõßT–.¾ïÝþ@¤Í¾Ôö1ðð¤7*ÎL×ñÚ‘{¡wU†ožŸ¯Q`\ƒÒ©ðÔT¦‚êòévó$;²¤¡ãƒcÈyØÚH×󌆳a%d5S0Ï£é?ó¹d>²DËpHRÂó8Ie¼i«/Ó´kæ¹vt¥â¥ê’=diéX]-²à£Á½Â°o0xx‡|lÜlfd6Nf2v^µ‡ï«4æâ!¥¿Ér›~}•QRª`öT!Fjb]½úýS¶¿C ±²¶¸ÛÕ€czÍ£AˆÔ…ÒƒRÆ×%/ŠJ$3Â1¼äƒV:‘”X+L(Ijk+‚jâˆï´02‘†r.ªÔø(¸b:o÷¾ÑᥖO¿Ò§^ ¤«÷“Hš?=àbíÙ ¡NØ®Œ÷0¥\ãIà”•òü®ëÙ)ù.L`èïÉæF9Ÿ"±E?‰ P6’ÃI„Ê£ÁÀ^Û ÿ`yÂ}Œf‚ß¹ÚbtY±®¤#^‰FG/&„ùeõ.Xc­q>U\± õÈ9¶¸ ±2|®~ẩ'[•øƒ‚ûñàç/`65¼¯$fÔß¶+Ìôþq´¼ÓEä¬uÇó¡î¤æÄgaÕ wFB/¹Ò®˜ìj\:oƒ›*7šcÉz€=©_ÿ´Ùtrh£ÓZlð?,cojukHÆQZô 7Íu+>{õz銠Ë{ã’€€ÌîîƒÁÍ-$ð™HîÔ'õ‚èÚ<ðA™Ç‹S_7Í,4ô³œ —DN©ïAÍýd³K(„F.{=ðJD!moË\èX'eŸ\ðé¼sE;Ð++wš±ß‰,I ÿÝö”f6»ž|ÒÂþ½à ²_„dé¹¼CJþR‚lv¤pœ&E‹”±™Æ‚+b‡¹*ˆá¼°Äòaòâq¯ªd3"ˆŽß;•ˆTKÁ&¤lL!(u8´µJÛÔëŸl<{ƒbˆÅõVÉÁÝõÞl¼r°1À7Šñ½sì» °@cX‡µAäýˆël5WÆfD4Õ®c•ƒ~"õ59 x‡¯ˆù_¯$ô«)±–à EÎ÷Y‹¾ùŒu½•ãYí<…‚úcÔ ”‚’ó+ hfz¨³Á¦´Óí„6 ©AÄúæ9x€'Svn‰T¢ÂŽ§ë¤ŒäöE–„{/ð2õ—·UpÚ©s@~ôä¯Ú¡ÆªÎ²ÚÌŽ&ܨ„ç;f VPlälÀl?¡àwc]ÔçÖ×~ˆÐŘ·ØoSi]áD²åC$´uKÖê[/-(‹“ÈŒ,.Zù¨¥h¨3;´DñHˆ|Ø¢©Ý!Èp]˰øª N[ÑC©ÝÖö«Ziڮדä@Щ¸0š˜õq9 ¹ ‡kÑxKl¢†•)æŠ „“sŸ²æúM!h^lŽß¾0B=TuÆáæÉJÐgáÕH.Š›IHû5-1l0ƒ&ö)ËÄtÍ©;«ÿ±Ä£-)Ój=`ÖFG~{‰ȤΆR…}ôÆÁµ¯H^ Kþ³)ôJÁ-QoÏàí«›Œ9²Vë;þ­4³ÈfaËûpÅÕÍ]–€-ªË!« £ù9—7²*sš£“IcnÙ©’€€½·UPÐO5l9¢úŸš]Q\)ÍCêÞkxOPòìÊ~G3#¡™Äy¼¤æhÊN´€&öHŸü,(t¡3Ÿ…eË."ƒœ‘êp“"lpdbùÏ@¸`5P¥€bÕÊëôè ÌüÍ\Yuß0%/å °øOB÷!à×ü\#B1Æ/v†¼4‚dJ{Þ»á„KÖ$'´ÿ¿L÷™1iŸõZÿu„-j‹C¤eî Ò‰e‘*¡ :%/Û8JÄÿtMm‰ûƒE×Yp8æÄ{ÆÁ|–€ •–ÂO]«r9¾üUUDys<­ ™ib&uÖª€5IŒ‰ß¹-ŠIÕϯɿv+/5Éø!÷½}®5C‚ÐGHE"â4žðí•[ÜÍxbÜ+œ™R)P»ßÎØ ÛcåES;ä3 ›;ãªCÇ÷OÓõ¢¹eå™.€p-çôUÌ* ¡L…QD–3;0FÀ!íjZ“j{yø79„˜)Étlî<Ñ=bühG–®n þ˜KçÿS9‚]± 3Ìñ=æ¡Ï`›Ë0h£æÈ¨øÞÃ3KÕóoþSÛM.ÕªóŠ¹ Ä¹"‘‰ïÑà|£VîÕÓÿz¤R ë¶™@ćoÍçÃh Þ%D*pÙCm 7úzw{Òýð/`5ÄwUÙòÍv^zLÕÚš*pÄSÎÍÛü°ÂFUæð*]å¬l·U ãÅddÑ2ÆY÷ÀFFú 5ͦ=ˆV (Þ)g®UäÕ¡é‘ó¼E&ØpÕg›1áw–ÀWˆÓÅ燲§ÈH³g7#àË.ŽQe,cN °Ê"Ãý9àD?YfOw´2?.w5…”RÑÕea…àjÿ‹ˆªOvõDí¸Y|¹“ñ›æ*'s UÖgf‘ÄõÛôcR$$ÿÍXœ0ƒ+ý¡5…{¶ð¢fJ,M3sÞÆîé°’ú—’ÆíSAJCK¹l©¸y#gó·a)–±'“A·Cã]uñz«uÃ+•|3š=š”J¿jÔzq¼opáhÒ蕾¢C YoéioÉyÐòFúì%¶{… ¾¹˵fmZ '¶>[¹¿¥ª~º‹”L,ÀÒŸ6Ïíw¶Aëå­’€€ÉÁ¬>D‡ùˆÈŸÙ- ˜‹…c.Ž ùºÚVB÷é …uñöKWC£•ò—äá¿ò$ó=è¯;¶q >(¬ Ñjƒž ° ¶š#°LJ )€ÀÑJQ¤"ØA&`åêàú<=´¢þ“°†á² €KîóíÞb…Uíkî^}()’®« Âõ¤è|J@œ>/nÀëó1|À¬óÓóuÕRÔœ¨Êc"P¨ÛÅlYý´æ+¡"ÿ¯ÿaL3Ëcãê:–é¡Päà-–ƒ_M·êý„›u‘"ÁêB´2о+éé­úI¥rSŠQÞmT  ˜¢(éÆüÒx\Î\9¬Zìn„.?E@S'²:·]w¾-”h¨öùЏ×B@4ªÎXy©ÂLjïG‚ËÒ«Oà![caÉW›+Þï2AâP5k|§gûýÚpZ°¦{%Øu =ÖtôÄ݇¬v¨(°z5„‚ð‡ÒM“c³=cò]D‚ªnvÑ•ˆãÙ@ú:χ¤&;†{·…'áêÉÉt §§ÁÏï}1ÀHHÿWüÿÎAçU”b >=(xtè‘Èer£´¨˜‰ŠZ?™%V-„Ɔ˜Úø’ð@äV7²Tš ƒî–(É eò°ÔSt?ÜýÔðИ†#ÝÂÈqÛÂx÷¼W]ûAî~:Y(^¡î%4ˆ+TÅ¢¡‚ñ©):$‰;)H¯æ Àj梃;þe?%û1,w„8™ƒô62"›9zÝöv“Ûwê?ºÖ?ÕÙý³Í,g%-)Òë'Q˜Q_—${¾Ø*O\ö".7ÔÛö v åeºšá–ß«Ø\•I©Ö+Û.½!À5•{€'²HRnš¡;Uh“@‡ú p{œgKcˆ­ÐÏ·óúo ÿû~ÿZ²§}IÊZ7Q‘dµ'·ø7zøü…wš‚‰˜ôÈ£±­sÀ3ž™Óãób‚éÅôÂY%[tnÆ=OðkTp$O…*ÌºŠ  Ÿ›Xt×äú°£à6Ã}†òÖ;ÌjBœâïÞ=ú—Kïå1–mUÄéÆÌ”±RTñæš–Ô0ÝUUi ¥OÑ ¢vƒWí—¬s&€ïZÖåHÛ(ð®Q`UÃÆü<;ÿuÖ®˜-{€©òŒ"¬x–’€€â2ú`P¾Šÿ2ÅZSå‰Ú  Šîã;±/¢†{J”¥»‹ †"y! —¼-¢²%s_7]îü›ýÓ.¢ã/QªXˆoÝ/k›ôÕkZMp1‹´T)žº †ð½²síá•08’/ö1Ô™ö? Ä4à§@r¿(hcÛq\wÒÞû!CmfåT”9áÄR‘¿²˜Lº5Eàpt×¹ëˆäÖ¨ȒTHÉ?6w•|j‘„¹<ä€QIíDft¬îD0¦9˼_²ŽF¢Y¸`ŽWÇm¢ú&¦ µ!՜Ȓ6g(tíîL‚«ò§†£©Ñâ  ²†xQ_¢Qw1ˆRë<3‰LW»ë'`n\'Qø¦ô´q¾3R#…ÆËªò5‡jºÊªIg6=8‡bŸ:z‰D{¥ûA*8 ‘È»üJ pO1w*@©QH…æqA±»í—’z˜}ëktä¡q¦<òáý¸EIæ_ýO¶àãȤ:`tr6îˆÈ;( ºÄÅÉßëóL£~@”ÚSg4æ˜þ…¬úÖ–ǯöE«îIŸ~æÉT} u·d&5G“7¤îUËÏ51`ºõ‡‹›6\…_ÒéOÿ.ˆnîY’©Îœ¬e¡@9¯^¿#5üú?ãcWÙž|¢¥ÖÀé N¨å„¡åY°·ÖT¢hóª0ÓüBÅ#!vèÝdˆ¤Þ0²•!Ü,Ò±,íp騴&9Ï<Ä ò Üí±ÆO‘öäÇËBq|‚{Ûšpq»Ó/™Z· ¯Ü©ùA¦nã z[Í yVŠèŸ2|ÜÔž·*ú5[Êá×{©¼]†Û(·‚|/i“‹–u6|ÛHL8\]Õ“áBo õûF›G"\«ž!•– jÐ@µË(ŸÈïŠ÷ÿ¡Ç…CJùð âTæ?+x™@µ?>þ‹íS•c›ƒG›æcÏúœ†: #È·RØã}Q±;©Ì¬ö™˜S*¶3š +ëùƒàzØç¯îg“7ê„ìÊÔ?™›àÿe(µ¾ Î3” g¶GìØŒ¶Q‡VÌDyÿÃþÍ«ÈnÁ·^i,/mF(ay±\;ß½aB#¬â ž eˆtäxë T˜ë“3ºx‚åÆÿ7µÆU5³îÕˆ”Yƒ™Ð5:°'p±ç1†ê “/áü$Õô$hcÊm^&%ïCñY=BêO1ÖK™£˜X Ò64™m÷­Âvÿ ÐD<‚daÐN‹åà{“}d yªP>ƒAHD£sù²CŸ""… „…Ý`®—,pd'÷Iñú [hWjÃÊÌ>ÔRÿÍmÜìöb>h)½ŒM÷MBÄK“ržbu.*/ªá~DÐÿ‰Å\-Oo™ØknŽ# kù‚ÃEAàSµÎÓ&3H3Ý.fdå€$‹Ÿ‰ Dˆ¬ES¼MÆ¢Vú³Ê!h~3RŒ¹5ß T54Vä;¹vÅËc}Š-M7kK#æJûÑšrÿ·æÕâºî¤úT+§YC™çÅœI(žÇY3CZ˜ºLnÈ ^ƒdtâwÕÜv<>–€ ½&©Ôbq\ãÄ06©“Ý•\Œ ;Ëk0g/GÙº>ž•žÅ K9óBŽá[ªŸëG ìf/”…Òo ò •Ý ô8„ ÛþÌ/ãÊ^ í:ûµ›æ·È”…N›Ì+å|îÈŸ?[wäqÑÓWÛ7c³QJe½øãÕ¡"°9/$­ ß<û¢dJÁŸkªïîjj𼙜F>Ï¥×£\+žðÁ.IÏÖãSÜBŽzþ¡4§ÓÊÂÙ…¼;K±ô^þœ}”ꋈ In+bàa }Lk#ÈÑÙZH·T¾ì„µ0;”÷oLÒÛîÝ–‚!K8emm¢»wãôÅçÙCËT6J[Ú€éŠï0´²¬£¨»ÞM«þ48š*Ò]Õ‚©1Ó;«7ÄŸ‚Zœ¤'Œ‡¸)f«Í/;ƒPç]8°ñ´2‡hQ-i¼dRÌ“=à~‰& Ô¨U%vwè•'Gi›õ)TÜH¢RÅÛz#2-ètlë¸g#C¡Æmã ©>Î";Ëæy‰Kh‡¡¾Ùú®‡’‘&Ù³óuhpÉ•UiÖ’ŸÎx½ó¨ê# ê3d¾™ ;QBF¦ð š'€%JîŒçŠ®ÐÜŠ­¾¡yÎ-^ÕÈš›%Î-î|IÎ ™5áÞ ðìBz8à¿›e[ „‚½I¡Å±n£­É4ŒU3û ‡ž8Þÿ‘£Ð ˆhh±6Opà¥L¦0# °%¿A-­2g]Y†ÍSؤ¥w(ææ15~êçßåC³Åy«ç^Ø!È_ÎPñ ïæV#pP8;šì(ÀÄ'øÇ†ùÝZ±JÈêHÇÖ®‚zZmd£1Ÿ8˜·þ;Eè¾Y[Àš» ø•ìàg‹PAhß‹ç'šøâõèE;Űö玠ӗ#+¯Âü¹0“ÏŸOÍôÒýHa°¿¯2¾ÜE®#–s•i«ØŸ­‚t¶œƒú©Ïdèw¾%šW 6®*^· 4'\Ø“¢¡’€€ÔPþ'–ÿú—Õ¬ë°Im¥­1‡ùz>ãÙE1¨Xi¡ ØJq2e¬ºõxYé ]L"dænÙ;žMÇ*Íì"8•sR õ\»èv…Pù€øò¾›ÿ|Êæ2û«ÈIÈÁŒ#ù‰­¬Y]@L8Èw_îè^MɯBÎÔPê.&®ôÐæRËìþÛ& Þ"ˆO@ÿÑ{Ñ;¥ìaË®DE¾j`(ŠäÄ•åä,Ó>ÊÑß}a6Úšiÿ€Wn4¡ £‘SôÞ''lð¾hÄh±&„–n\Σcª”Üunû­Ç9ÄòŒcäƒ)‰»Qò4`~¸PŒá ‘ë!<ááSÚB‚0.O‹§V¼v±À‡•‡q¾ê909¾0Ð6ŠdËsšGM÷ɺ'Sûïr­¥’Ñe— õg‹•¶ }ú~&ø˜ÖjÎ@±_è\$†wd6µìÇw¾ ì…¿wPý~¶3 ²]劋ÏéÂ,L±†ü~Õ³…›Èg²Ï-ÓZº-)4#ÆÅñAë`p³ïƒèG!?öo(ŽñÆt»"Ñ*…cMÑÛµIåWÆ/H J†%.&o¹Hø[Vfl*r9CÛòµíï¡gáìdzš¯Ðz85W:Úº`hx¿!¢lqºúR¥Ðy“Fb='võ¹hPiF¸;œT®,`†úNï¨íô‹ýãõ¿è)€+¡c­ÅNÔNI þعŒîª£¤Ci@§EY׌Wô™2ï¾Æû¿e<Ê'B?]ÆÝÜi¤Ðå.1ŸC]wÄq·UëöÑîu&²…ÐOÀÖÞQΰ|*ÂAvÁ4Å–ÖÚ¦í"8 2þDóÅ$ûC,¢:1ÝjÇäj·ñ(ñ9A†J¦û[‡S.öP4´èx†ÌÀôÙ†]ϪRLðOýÂçaõ[‘h"Õ­j×Jþ0½”+Ò!èÔ†<‡7äµß&%‰æît×7Z̨ī]YÒ‰õfŽçy3üÚ•¡|Á/ÒmnO-«ü!Òf2~5ÒêÛØýƒw°Tê˲ï³tNÿ~+A¸|¯«Ñýÿ®ïˆQ´›ÉqÚÆù¾ ůì×FúBu£«¨_ÿ;ó‰õŽä¼î.Ân‚6óuz©†‹š²¡}Ë ÊDÚ(”—,²Ëëw½ˆ+$PÀ¾ÙU“£Wø±C0‰ž Rj’€€¤Ã¹ÞœÙºŽl‘³‰ÎF—šÅâ]lQô{D‚zÒ„[/n/¼ä¦ftÇF,’¥2Â6kìŠx4Áývo9°ë± þ¬÷_L¹±Á» !Áý d¯ÀGû_6^:!%„ÙE½OÄ¿Sššk€ÇsØÙîèP5Ëø²™‡µEF@/Aæø|”°âÏñ¾e&>€=l©âŸt´É¨¦Çðð‡Ÿ$ti¬ûšë©„*í8 …^ºÝ²Š€¦ ؽÛ11Àv›Q9M›žéw[uzø@P!5"¡øQ ZY°UŠJƒ<<;ÚÉùÇÉëÒCÓËþÏ€¤™ÑM×Ï›ËÄk›åAKq}Øw*÷?>näwYú…‡LL¸ÇkWaÇ‹¹6åà ȕÀöóüh¤?ì~’Kñ™'eCc»I ÀÎ4@‘Q2¦j&ÿ&¼#b«Åp8ZÇ‚FÔÅjÁ毉 «Z~*ðe3/sRÄ!YqxuÞIIE0%œôŠfw¼}t ¹1¿ÚÈͤwÄë“‹ö­†³@×?Oܹ2àÀrQ7)ê_úþ©›²„¼ÎiÁ]Ç€˜W x:X…ˆÓŸ‚“QAŵ‡³E~¢8:_~\½Í¯ô¹Ë~É?èÇ ¬—«üžçÑÕÀž× ?Ó+œÅR (ऌÞZS ¡zè{1~Ù서Õ9ÛöyE¯¬“šˆ`¥^íÓ’¡ÂGn½ž¥H©¾gpu›§´/KÊ ðK ”¢•IZ@dF ”N®Bùñœëž±ÑëŒve€‚7³ävïéÅT‰­s‚ïWê~ã}7ÍjÅRÒ]ºaäežâ82Tr ÃUäû†¡¾Š¹Ò„ê˜Å%‡#PÂÿ¿}ˆ¼ ´Å¼´ZöHënˆáå5ÍB¤/SÑxÿyÁ¥‹¢R£%{‡çT^§©3­,•sÞ7>nYzáÊ|›¯—çãMÑå, DnsBp‘e"û¹à‚Ê”ª€ãÂÓ¨ ›S\?â,A)¸}V$å‘k¡áp¢ŽýâN¤á@h™.U ÛU‹µ +ÜoÏŒ–Ù|ˆÀ ‰ËЙ6)kQíÛßÌ¢óùÝíÊXÌ&HÕ§ýä=b^HA®ž €Z’€€Ò®“FFµšë,?¸ˆfÞÄqA1hÝ6!1‹?CœÕ]ýŠO{K¤9:y£½›–y¬Vî„̦²HDxËǵâs׳ì~òjeW’Û5œŽISD`}DwÛMŽmÆ6´@¬lÛOÆ<«µÒ–;oÈÒ¦ü`¡*Ͷe‡Ë/ÿÑܰ•ÓŠ0€ñw l‹IVe6NØ¡¦ÖÁa‹Œ¯jXi¹àë‚êÈ ÉRˆ&¿§êò,ÑàCäެKõÆ0›†`-››àšºN:Ýxo,ʹO‰ü§áàSfÛËóäé†-'â "àÒÜ­xþÈ_`†€Q¤ä´%Rôº.o÷%Ûjlø¬%$Ý ˆ¯¯'FØTåhw$ ,²ðÓ^å}Q éÖr¹òsdµ¸»Í\ãÍ æã×ÒìJÞv@Q1A`›$û‰YT•&vE áãÎÛ[Ÿæóþ>v'!šÒþu™Ÿ¤¾_ÜštÝC‡f ë»^¹¨ÈŒ=\V‡ƒ RW’Ú¿Ô±Rcelö`åÃgýFË[2Uì› Ñ÷ ‚›µÔJ8 Í%×n "o^hÿƒ4çÛÕÉeIЏ0–S™,÷Æ%Àòøô;G"IŽ7TuœyßÛIíwåEݵ=2ã‘òËGtÉ<¢7ð–ÉiÿçC·è3”ö¦+àê´NòÖYº¼`{§†TrKU•kHàØêNsõ*†DËâ)Æ/LwE¹¨æ¥¿·p â-êWg¤îg¾]S“Fj±ê´aº6áǯ¤8íŒØýÅõ˜ÎBÀqfU.ïYL¤¾?Ô°Îß3ü›ÜÞA.Ž„ÍÆS—nìpO’r§]±ÌdpÒ^.ŠW•D6³ƒoˆº,œ2J÷Að$ÿ>Yê°ì‡«ÃÈSO»«TÀt ¹úUÊq[á™ø›´æ_ ”¥H;a€*€n\¯]ÙU}äÑ­›åâb;ÿÁ@L ´4Ìeid;Ÿ·YGþ…èI¸›üs¶t ï¥>Ã٠ѪvÁÅzÓçä˜ NM,À¾?ËÖbµœ81>ô%ÇÊ¿”SÕ–gû·cýqXøÆF—Š1¥Phjo+›àWI¢_Údù?±I|¡MôgÌü1*°Š° _†»,Z4m&ðziÓF0·MÊÈ”OÆý9=Go‡Ï¨)¬õT¸‚ýT¨Ãò„úìlÚDàAÇyëñÔ‚n7‹ß\ùÊ✨@„ì–·gFГñ½º¶ªpåLÇå&ůéScO9Œõ†ýn®d¶hÒ‚Ktù.ù’# ÙÌ­U¯`:Š nÔK›EQyð5ÔZ(/>rÒ|Ïš*)®FùGèù0"yEÚ]zØcKI P†„“G«{Ô®ž]ºÕl¾E>ë½DŽWúc:M÷¾fF[ –ˆË1tÏã¥<™%3};rAþsžV ®–†…œ.ÞkÃ¥?z¸K™nd@óLŒeužk$ã 2©ÚË4]ŽeLûåÌׇê=¬êþv. kæoοD¼|¡9诸oUn“«?W®·3¸Zw“B…Hì>¾iÜ"bî…Œ—´V<›Ð*ªÛ•Úš­•ŒApw @Qß×È´IgyÕî’Y[ òÀwïù¦šÀ[v‡†Pk<ÕKõ^=÷;— áž¡Y…aĺ¹ä”D’€€˜BJTêkà?ÔýùÖÅZ‚C,Œßªu !ÊWUf0°d“³âžî/ç:=qdèF|¼»µÐxAçŠ_;kSF®›nªâŒÀ³³iqŸi¸^ksªP÷XÁ»Ó]/]Ù2uÆ ¿d´nA€ÉhLz™®ôzèàuøXž› Iî§/õ­OôœÂŽVd«K„b*Öaƒî{{Å©u=r€ª)쪊ÿÆö–q4Üí=ω” ‡Òv[oòM ŠÎ‚‡³ ¨“5ð/V 0 &½Ÿþõ(rëãDcB›ˆÀ&7敆³Üìê8‡½ÄÔa9rØsë©#©8_ /™ {™:zá"E t®’€€¾4ÝÒäüÛÿ¯°Zö9çÆ`×Tä…¡ËwÂî²r7l­O.™mW ¼ÔËfþOw£Î¿È=‰BiÀ•ŠUUméjÇSPá|óqx¸Ö³¤HÈÈKñhƪ{ƒ„6‚oc+ÌÆÜ:‡J>ÈAüÕÁ–MúÈqQ³Nô˸LÆÝ£™-^C¼*Yu…kœñ d’"òÞ\М»Æ¶µ}ã¤"1çTʇEsU;+$ Èe0D?¸‚‘·>BÇÊsKå œzÕ–°Þ<%B.F/…›í¹e5Þqàšê󧟱É`Ã_RÈ!Ö >öî 9žD|nž‘ÞIÙÆzèNÌ@—HD±ßAá$ey‘6äç8ð’…Øx*nX‚8lE#Ëì„cÔŸÃò …KÛöoã?{ócÚŒ7¶=5Žœu”Ì>ÌpÂKŸ=3?Tc¹Y ìÞ)Fðm„B#]b-èá*¬«éò;¬]¬HRX[ ¥­Ö’DÅ/,„ÌíNJ“ÁæÁSÉü•ÒJ §AþOŽ®±UTz9˘x5 &?uvP{#æ@’(©·Ü¹ãñLEɈomïBØŒ›{Ñæq7cÊyÑëßíÓ)ï¬ø7q“l!9²‡h›ÿ¿ Æ“ÎÁtÎ# "t6þJÀcL6¾U#!ÕS¯Jà h$Ø{6_Ä|KÛjÞÃÌ¡99Óò½ Ë=úÿ6Éæ~å#j{ƒ *÷~úÄ4DNˆœ5?ÀNcpOõ¹òâÀÔí%Z¸5ùlöz¶bûò:ÛSYüj*¸f%HH8È?=àän²N#k54àUo2wÌ·™JÍfaÕ$Û¬Ò¦n£Ë•8Í~ÛÏþütE×¶i,Íd‚dë;Žr‘\¹ã1޶tŸžñ®N¢3\õ" Jí¥ì¨ìô¸èÚ¸ÒYHlC”Ñ´ÄAjµÃƒeÅiô@ ë‘\:Ü’Ü í7âô. bˆu3ÜAf®öõ{ /Llóï×å‚Ä.šøð …˜Œ}s8‘Ÿñã‰}ý¾,AÊÚ‹–“Ö§mhŠÌgßhaòQy"·±,“Sµ,s]^¸fõö"û¯"ì ‘Ý)\³x‡HÐá€>T6v—É¢[ך@E;/äÉä4V”ÚüBj* …¾ØJÌÔ u㨉‘s0Ð*—ûËǬ ›FTäR‰š7„ü‚ú¯VòÝë|V½¯cu ·™V§ÒéÁÈÍö©"FRÞ ý0n*á&ýç Kýp1ØÓiðþÃðý‹[¤\9xN»™4‚“ÁDœÈÞSu£:ìßk¯ õÙ[¹­ Ú8~]d~m­€CÐ2”¸}a ãy”5²ËNp·ä’}´w˜Tâú“N_Ö°Ýp9K¶üá´PT[RmÏÙöÃÎÁ [«KcúÄy$Ðê“ð©1Õ‡†q~Ç8~'¸í@iO79:m!5C¼Wø8&ú ‹ã¬Šqf‹çÜÈâÆaf+H”ï› óÀ©#÷¦0`¯¥KjI`ö>+I¶»0 Lsܽ1ú<É©€ù‰ëdÍ=Ô064Sö/älpеº:ÿ&]¿;0æ I*à•s³^S‘›u9gŽÖ(Àm´YÚýý¹6žñ~k©ïÌR„Nã;xJ´/œ·Ssæèh,P©˜u:Øé/…ùˆE,’Ý1Ú-oƒ¦UöÞËþLï–éÍ·dU´9šJºÄ4ŠžMPk!ˆbxX¤ ¹ËpO4¥#Ú¤2Ϻô‡&•¸În[à8+µ«¯›_’ÊiºÎšd(\“Í’¬ðWZtœØ20þW몢.>1ýâùZ0¶R°¨ˆì:k´éV§öÌŸÓ­ŒD!®MQÐÎ ûsväb·uÂFªdµÃŸ‡PÉy½H&”É&˜˜D*œ€¿5iäÄB&P÷¾¯JŒ±i_›}Á¿I2¶È쉛òͶÜo=OwÜí·¸&r&ïWñqÁ݇8pêÞ¸r[ [^á5n0Úßyä:݇̀8'BöÁ°ïôá«ÖÿQ —,·  §LäÙÎT.óöù(Ow›DËÑ)M’IÆeζQV›óáKúãŽ;½‡<D€¢µ¼ã[âî 0yƒ¨>Ü´—À§eÝC3ô“9RVB=Ã견Þii…]öL¬|wÍbB'#ÿëex‘›r"ldö}zœŒ_ÒŒš—X‹X:h€ÊA¯úx£zFYŠxºk‚· ¹€—qødîv5iÅ6I•ß; Ž…b‰“Á͇eJv˜ßõÅ_ƒª» Õ²XX¼Ó<ŠA:g O«XmåtäŽé„‹¾ñP<Ó‘õ§Hk“ýÙõ»ί9ó?§¿ Óuç¶7±¸GW³ eœç¦*»WýëÚžñ² 3O4²÷^’€€ªð5ë2hUtï£=àâÌçÆ¨‘èlo\C¹Z7!Ï~¢ëk§î1¦¼ {õµw|zù<@/uë`;aÜZUŽ_¸Æ¡|TA‡H¶$r+rFÙâºÃqẈ}û•¯›·ùÀÆYô¸}š÷€h×ò§jÉ·°"_ÐE3\9ZÎÂÕ²—hÑ\Õ±-èL¸"h”0 ³¨“Ü—PÛÿÒ;¾D%õCÚn‘ÆH }ŸNKíðò<ºA«Lüä?/`!Þ/ ÙØxôž«IOõf‹Ö0‚VôüXÓªJØ) DVÿéâÐ\í,œV‰Œ3ž< 7Û–4¯†5S™1Þ×/©®×ô úÚÉŠ!Auˆµâªô"Ddêv»Î€¾nš‡þë]é³!L"¬þoU÷îþËg Q«æ‡zƒÿcÛ± +¶Ðs·ý'øÿqÞÞÔFΓw(»+óË8ôìõÚBÁMF^Uœî°Ååz«9›:R>'K;%! êÜ$ÏÝíâ ˜°ÑJR$ó¼«)‰ÀUܘy“íÚÒ·Ò2“' اfy!›–YŠðHЍ+l…ÈwaÏÈ@è¹ZòvœfUìË"õúJè¼k¹Õ žÿ:N¤ìÖ«ŸÌ½%=x='ÙÒÎg‡à4SW—Šf¡UÛ65†Ø÷‚5ÆÇ¶¼°:{Pû~U)Ví1KŒ?cfr¿‚å´|L±ÄO¶ÎºJ“³{|ögk2¸`¥U÷xæý¸R‘Gt*Šý®²O|VïG唹a$w˜—¼Ýøê?}aÞf—н˜müè ¹k ±EÈ#„†.ç ­Bx0'쵞LV)z(΃aµ?H¢›U%‚¿ ±jÌÄîiî^¿ðÈ´-Íà-N‘ëtiÑ׈d¾ñiI³ÚÝj¬ÚZ‘6R‹h€ÔŠ„ÆWvbÌŸôr€­Uó0‘ìnÙÆ7dó멇÷uJ^eœMr~bû³†§[AZãqµè<úFe¤ß…‹’€€´"°švÓâáü6ŽÐŒ4IÈ€s7o­¥%*C§Pˆ=òÈþ’»œÛŽæ~ã WW¿ÀÁ7* ,nÀè É4¹ûäÛÝJ$乂±÷Ybi*Qñ²Ø½A^J0´ˆ[+$é œ÷á K›€G¸å&[ñ¬pØTÉLí¦7T›Ò|ÅÔÑÎB¨?¯è Ÿœ5—[Ôƒ(&úøÁÞîÖ+%W´²³¾ÄÚÍ0“iÔÞׂ>N ƒdÙm5Zù)0„‡ ²¢[XÚÈ鹈‚¤é¶@óå×Û!^‰çZ§OcR¨u6›×± 0ˆ< 0*Íä¨Ìh \PG=àþ£1hi(áúÝ9y¢î‹„ZÛ‡B7‡E£…¸”Sn! ’yÜ ~-jcri:':P¯hÕ~GËb{¶C×”)­„‰ƒó ~°Éþto#‹Âª7ˆHúqkPHñ¯ÕÙ´Šài›<1’Ò£ )¨*3àfÿ$[¬¯Uá!EnúAãgÀ¹ê4VuG$* —Ç367ÿ?ÎÊîý&¦ÿ7€®¾J„9w&¡¤”°ÇßÀØtã6xÉ¥„R6ï×ì|á›`mÙ[ÄGóL¯G ¥˜¼ím%cí}xåõœ#wÎãRšïâÝDÍXèÞš9~F§lk\—v9’yåÙE‹º—Óó×¶yI¤„§(,¨‚ª)Šá>ÍœRz’öJÎïÈ‘³ôÔ/,µšZE-1šÒ”[£¸™z ̪á­6S º¡ß¾ë)‰Oæ1˜øêj£uâ5 ÌK3`¨¨ÆGEü¼|™#/9%5 iä½VúM7DÍMóSÐûÈ¡pª:1õ FŠžŠ$ÝÐGë—†Sx §¨ ùî°œF÷ó1€– f#¤S”+X ±Ç ”¡~â±è$òSÔŸ/MÛÂyO™ÙJŒ¼Žeºk05)ØIl´Mú^7ðZ2kbk~‚A¸a_…‘ÄKÙ·¨8Z°À»MÌŠŒ­¦ eÿfç«V2ÉÅ_P*½°ã)”JÆ7»ü.Ê‚tMdgÕq.+œ^BûS¨yV_‰{s…=eµá´m;’ªÌÕÕš-˜Ý!:x˜'r$ SèˆßÁ!¼—šj„$zPºÀÙ€ª•Âó4DžI§_‹‘Ó:Øp:6‹ 7í’€€ë´ï<¾…EÛw´ŒS¹·£”"óeÒCÅ©/¦¦ ‰Öñ<¹|JèØaþ“§§U;+’)c®‚'GÃÂX'†Eym–éM¤ÖÙP¹…osü•ÄñÊô©fŠÅ=Ød‚£v˶=¦¥¼Xáã`xyqŸ96?®'K$€ˆ Bä l ÍÝ9 Ó€Ì& R¾Çd-d9?Õ…›ÐËÚó¿X©’ÆW^¥K~ÐÃðšo¤¼ðe9Þj]ÜòaüáÈd”ñMÂÒÅ6k9vÔmYñ!p²oW"Õ$Š~9äKÚz3øK0Ziؑ߆èÙÄ 3Ž2Eå+× )b,nwL‹4Fk¡ÝcƒhÛ fÉÝÌÃ:‡rfó¡…(­ÑDsEBvBK»Â{’³ŠZ›Tí¥Î9%8Fb|– 7UoWê‹~?r°†H…¥ëY£aBŸ žSwñ-ºBœ¾2—6]dGŠ<ÿGìK?gA\êø ¾Ïh»Òe‚æ¸ñØ¥V{º‚ï>áçXªôzüÙ)œâKµ£ïï7Ú@£(ß?v 9Õn,Ç€‚0¬ÍÚ|^^,ðsh÷ëB]ïÊï˜j'Èà‡\ÚW ¤t7ó¬Dò$_±”V }: ¸6¯œAé+×C¨K~_P’K” 3É=ýùZ2·˜í³iÖq‹Âq`ð'^5ˆµ1²¯{·±‚Vq¯›[uáG|ÔØƒªë"DÊ«•+ÜØñ+ÐÛ%=f5I*?Î D ú<1ðÙ&kŸË)-= (Í~ÕÒàU‡©'#ü`Q,õéùe…Ž«‰«M¤Üí~Ýu#)àØÌ­§³5)Ñ„*\­çH0&øu\ ¥‡åiÊVë@!öû†aô%úý¿QùÍ$6‰hEÃ06ºe>½ã ÍsõÞŸëÎ{^˜ur@ÇMú¿°ño'uçP?@æñŸâ!¦dA´LÕTï¯Ërp}Ïç˜ÊÒä¬ó‚Œ}¤°Ì[iSÈÁ¡q@=îÅýrW·V!9;í¼?>~¯Ô}Vk5¸/wAgÞç?›z!|¶Ø[J ›ÀÙ#¿€é´ ·†ÌÅ&bFJK:4ã½Ç”s0#Ñ–p¥*öÏŸ›)A¯§NêÐý0J>sDz„’€€É~´ßèJÆãnr€<˜=ä':¾úº>ÕM!4Ñy^=*{m¬…tSvßpÐa_œ¸émöá•lÆ&ä1|y]Ðä" ,æ9^©6Á!>bàP U -²»+^ i°Kì-üWȆ= ¥µÎà;~Ê) šëâ4òÄ6{§¼ ßÚåw‰AJvï>S?ßÅ1 A¤"˪ÿRåãš¿XþËìVûR‰×åèëÞ’}tÕ¥¯¥³5eRõd½Iéë à¼Ié)ÿªp›šrôt,Ûê|/Îú#bºä(ì¿hµ¶jà{¡Æ‹1vOf•VWP»ÍPe •^«#œLíAÇû6ÐnŒû‚ƒõ¹]ô[ã­’¶UçRk1g:gþÆpŒ•í<ƒËá¼¶V±ê&@2Q¶\Ç?>¬C 1˜ž6 jÉ#»oŒC,eØ‘7WžÏÑ:Ùº}º‚“É“?ãL[´uŒQ®+2Zþ\"}…²’h’é+=”™~1‚°ï>â!¸o7x% ¾×ŒÛ©ÄíÑwÂÃêÒ}"Y‰<"\9®¬ú¼3Ë.+ô³y|™c—"J@@_ÄQýør @çíêßé Å¿hD·²‡)Ûw‹&¸Gc¾[|ïÀ?Îõ,­ØQ'/nÑõyAã·EÏâžkÇö¾øuˆºÕ·0Ýsn'ZéZNψšä£ÄÃâ(WÜ+ˆF’7úÚÝÅKŬëïkœz)oý?罊Û)š‘¢=ñ*‹/ÐKŠºÔoÒ&Ìè*RýâDwã‹f#øI(PbÍ¢FæU“.³K#¹.\àG[=Ò!ÿˆñ û…RçnW9¿fï¶oP­±zßçe2¬ÂõÖa*8Þ#$îžàw¼C%òSº×b‹'þ|óc÷ü1^q+ÅUûLvÖr3ÌÄhó»Œ'{ð¶+öå÷ζš(kH0˜¢}{n*ᔌÏ)m Ìk÷<åMw·ð’G†zbårpæ²QTýÅiz ›g=¯ÿ£íe¨ïxý(l@™âyRò/®ô{Öf_ŠÚ°ù«káŒÅÛWá•)Ôšj¢¼µˆ®­™íä` ßz%tC °Ä+£x M¶Òlb٤̣KõÛ¡›•²‘½ºý.áðïDñ›vg÷ë\Ú0_d5Q¬ó¬ÈhöÆú… ª»éBÈ5 ¥ÙƾùnZ…¹å3Óg7ué±{Åü]l®Ïͧ¾¬4O<Š~™êCFêH¯M¿Ó½Ý ÿ»íÖã2q›7Þlô» Ü‚¦»f(V*b@&¤ì™ +pe=G*¤ ¤€0GçW²·^!z ÙØ[‰§Î‹ù¤CË>ÜWݰ ãácßÇä~È™ÑöT‹‘vvÏ• ¿¡þ9\Ôû+â©þ*J~Q}ÿÄï·&áßÏ…[g§õ€’~ íßy“t{Vž •‘…„ù$®ùø±²Ö ª×„È«¶ýp®Îz¤•lŒÂ‡‡Pg€.´üMF÷ò+Tˆ¦@4·”¡~Î}ìò­ÆôçTwºmh›Ð$¿–ˆ æ¾òg | |"†ÏMA»¥ª dŽ»é^˜é௠ ,Tv$³Ýo?Ò; ¤ ŒB­˜Qû¾­09§6¹ÀŠÅ±óÍXéžþ< –@X4&eGô—’€€ª‰Ó51P¾­„tž‹Þ´ÛdÈÃÑà$ÜÝjx<Š95YªÏŽ¥åUQ)Å%ÀSµ¬Bº&wk‡[–&ÏÎ$#c¹(´‡êJ¸>0kmHx3Z-û1R@ë@žH7>!E‹½ÖañXmá%V-çš·.…Üüx‹ÞK¹Úy‚H=ahEõOB_žàöîSƒH!£¨9ö¡ ÂþqÍR¿W5•¡ºh$g«DWYpù´ûÐÿΧ+°JÚd>s@û-¾j¨]{^Ë^I Ž]•ñ\Ð<°þéòHg•PI‘È龪êY_§ƒ—;ÙŽÚRs=}È£&&&mzÕâN"(Ã+/œÊ4Ãvw†œ¦ÁíQ@›Ê‚ƒk¬ïîQ@b#D!+ìPNô·‹‘!ÈýG[#,™Ð®R-EéIVüôóÞé2äתs(]Xcçѵ#_àODÒ×EšÉuYËd³Ä®ÉVc Ô|¿?é¾¾QÅóP-{ÝnQñXéÔ0³D°Úⵂ ƒ›h½*}ãÚõÎk¤ÖÉ;޽€—I*/@•9&Äà©pÌÇÅ0ׂèÓÀ.hì§G0›%±¥V1‡Ê ¡Î«¢¬HñøIÔ±/|‚ÛPmÉ$ëDæÕªCÂÖˆ†ÏC0•çqÏ2Â-šñÖÚá™V—àç)ÎKƒ@¸ld*ÖÀ?ô#IÏßrW‰™VÈÓ|È|™gyÅØ% 0D÷lô{$‘ºØðõÇæÁžÉ̬± ÎMí¢šW8zh¹š–‡†McK*Àß]rcéÊ_- °ÖË”ôG®VéŠò€Ñ–©Õÿ=ÇffÊxåÑšw¹Q°±Ô7ÞEf Y”8ùŠuxÁ¾]}ÄqéÑà²mÎñfÖ}¯Ü‰I˜KÓÔºyú½éL‡Œ+;=‘¾XaHd@æž•¨Wì@º0Ô<ÆZ{±®¼ÍÂ&PBrù|É„øop q«m”ø×Ú! Z•E¢0¾‡Ó6] s”M$’€€â÷8£Õb­PÝ7Ç¿2&«á]?Y÷F Ð% c?Qgåg/Ë,A'¾Ý(8n7~ñº Í²/yW³ »Ü ¢ÞºÚÀ’㊟K:˜…ðÁ\ñ7t<`#M½$nªzñGwú× %_áRD³ç¦ ÊNµ0ÂMÄ;›€+¤÷»®ßz’³¦c›ŸöÒ Î4ójû],òÚ˜ë`A›å ÃÀ!,¤ƒå:ºßñÔtU@Ânÿ‹Uî¼æÎÄoÕ2=2ØRì‰+y‚u¼Ì£’ktÍQ½*øÂý¢@ Žì^°o›6¯Ø!:ûOŸ|¿ôôÕã>€©NÉù_½×èS¸3¯Ë7¤¼ñ`(ܘ|]«€‡¨ÿ§jTH¥­Úuá1JZ{·#¿uˆi^Y.³¾ÞÃ{*L»½Ó–²&–t•>ñŸ–ŒM!Ã+-øRm|2ÔÔe¹8_£”ìì{t€o+<˜ðŽ)K2ZÖ´û»äk/´$aÏ1‡¾ÔH¨)\Ø5h(YPÑxÿêÈÒ9Ò_ÍmônçûÚtÖžÉñ¼}˜(a/ÇG@ÃvÙÏsû .Õ[G©2{×chÍPnq†p°VÞ«’øC~±•ƒ=·¹«Ž|]¿“Só§šÂ#So¢¥#b‹r¦CØÐÝKѧ»sXÏ}ð/¸ž<œ‹ 6®‡°7yøœftïÌé/Evd2ã81Aæë•H115íeÓ$Ä0D-`UŠÀÚéëäuÚ-B6EÌϳËÙH[›ƒƒÆ*¾Ç´Þ0UˆR(/’x9Ó,Ô+mŒ#m E4šPo¤ÃÐÍÈùÓx¡FL0NXsXû‰<~‰h˜’€€Þyé"c2vùÑj!þ¦“¼Áwâ\cÀb£%rÉŠ:ðã …†IÁ¹÷~ÔÅ'T’â¥V¿Ý,rrÿéLTÕÓ=#"¤ë£Å;‚sñGiVw°`)‡u!èÝÞ@ðQ´ ÒåÇH´VKnÄ–GÙöÿ"ser7(êÈê`¢e±v#¿áØ$ÞE:wÎZ!âäEœ…–ÄLØœ×w°ïÄ'‹ß¶äŒ¨"½ÙwtáÁ²•XôÝ[Å÷Š °ÌmŠÁ CÞ4³c¸¡¢±º-å!ÛÍjï'zî˜?›òٟ٭•mgbGѾnKÕãõ+ê!œŽÞ~9îÿ¿0 b¨L5;™M4‹Sa»LÙµ¾¾Ô3l·EA]«Ã^ÝiÏi•ÜÀ=BŽ™e•‘¬Z_‡˜?Á¹•o³Ñ©j¡ÂqN}CÙfœ$ñ24“?»š¤N^Dëñòçºä¯jL@ÜÛô¿ƒ¡© N5i+9ä\¯ W¬ÑqˆVþÑ!««¼JÇT¹`Ÿv}.«å1ÌVµä1¤†'ÝÉ)w¶|Ѝc›AOdÌÊxçH)mƒoßÙ / YX-F/{“P3¯­ÞŽ„T2TäñRðy~sá8r¾ KaØ Ô³ÛŠ–æ<¡é’ÚQƒÿ¼"¡ß9·3ÊÁÿ(­8/ˆË¢ò‡g?%ǽRj̲/uKo ^l  ÌŸ¡ €œ¶| 3ý.ì¶HQ§Oä?Q»ÓHû·ß•±¹¨»í19»÷ˆkžlœ(½ÒÊm-¶¡µ\3;õ‹ —üæo5+#êƒC±w ÝÉdb*‹Ž“Áß=û#`*»ÿš×qø´ ÷d}”T0£uß•± ´=œÏºõáƒ*Ê×ç­zã°îjx¯í‰ÿbkê|§;[JíÚ3®UiÑwy¢®|çåì‰]+5CAÁéÄ$88r|…÷9{<%¼òȾÊÇòš_üÒåÅh*_†4FŸ)+X­ØºNœM|k—b´ø™D"½ãz„Ÿ#wÅ(]Ç’È®PÈ_'~;œ¤f†yš1Tø½¦TÒª|î^ê8WÔ¢æ ä˜/As!¿jêWFÌcñzÛ› íó]þp 8iîºæ®ää/yn”}Û–ç’€€È¢þˆ=~MˆH¿'Œ çE ZÕü £þRZ¨ʪx÷ÙJF¨%ò0)*‰úº]°é¬úšŸí²ËÖdót©gªrv7Ä©í¯ ¢–¹Ó:šo<„ðH‘”ST[ñl<úŠú@=è3#0TµÉÃ.Ýp”I’¾K$0&• Ù‘Ði‚ž¦¦t@J,ôr’ñÂg–¨¸OnI5ªDñÛTÒ¸a‡”t´à{x"cGâ}r_³9®t;”³jpíͲh¥jÂóå ¿'™úÇó.ïø}î…þÙ™;:rÓ¾Ûe>#”;Wû2nïÿ‰=`h: ÄÝK%¼nÏÆóþfÛÊ©¿öº¿ú»"DrÞ!å8ïá,5æHrmãª$Üã y¡'fï)Mʉ¢j') ˆ¾€¤ßÉg”Éi¿+÷ˆ¥S_ ‰(îFjr<”(|üZɪ®¯§cþP™Æ½ßì Rn¨~üçÏJÛI¶dmF_ð|õˆöÚ‚œñ}­N4³ž)±bvh{¾JAþ]-ÙdþP‡7ñ‹óxE am05Dò¹[;<#ÁÌÛ€Üé¢Aýìz¿Æ$ܽìŽh ðJ‰¨ã–5C+ñírŒX¢ãUÑxæ§pïˆW Ô¸9`È+p‰Å,Ûì€Ä»umÓù'Dünã kós‚¶Ÿ˜HÕ=ä¾ÚŠÍ‚‡©'¼I?ÒÒßðY9pdò¥¥mh Ißqá¼”–ñ¢C­'ô£ÓÀ§m¼. eñè*vÞ¡gªb3÷|žÿx “8>û‡Â¡žg©æ¤¨i¬ß^˰ú­vž¬50” HsIg³DKéGÚl™©YpK-JFMGÐPQv)Ž–]dÔµiHEÂz“ GÇÑØªe¤âùòu?¬"KŸç:⥙R¬iñ{ŒçNøÀ=zd@n4^1SÁ²Å ¼ˆI9‡Óõq{^>/K¦ó]èaêŠè'ãp¤¯WE¡””b9NJXÔµ'Æ8›»5Á$®É $Íg½’€€ÍœûÆb>×Läÿ}öï{æ%¸IÕáYë¶!î¢ûN…y/ŽÇ·šë¤û:ù:70hÓªòŠ:ÒÎÄ¡‚ºdOÔJÖl´ü³µÆ 6-ü*â(­uGÂ×ôÓŒ…G™ÉW^@ßkB©š&ò[ñlúFДkôþËXŸF"µ`¶<“á-ý¥Ž•$à:Ü®0•ë>•yÜß¡}Ew,%g:3ÈHp1ÇmÉB{Ô€é¾ÖWÝ+³ÊÌ6S•l ’{“V´¤h€šéùý|V)~~Áuö«$SUNXõYÄä |÷b¹Ö²m~â|ÃãI÷‚`7Êm~Ÿ~c,7ü6UÛÐDBÜZ$mcqšlÁ7=¢-Òº…ñxȈšÖ¡t6–Œõ“Ç$b§ß`=£¦'%(‰ €˜Böryåk˜ºfb/A<¸ŸÒ[§c?ß6I[!å3eEJbâar¾V=çM)ß®À¢’påãƒÌ‡úßo{(0ä¹)O7€n+hÔefœÝ+ß§",‚…»ìhjÔ~š\2j- iàÖút亭sqö­t3m½Ô'n¸úÁ24¤·Hly?ÄóÓŒ„\eÇQ0ßÞV€iSQ·Û%kˆ‰Ì4cö˜X!®@F_µ:os³C†ø~¯— ò)ê‡dàfèË×ËׂÅIŠ…H?oœB£¿á“(iÝ >„Ú>­¡òwûë²6Ú ò@"}œÄTÖ>‰°Aî«tœÁ­Æ1À°›LðÎ]ùzWä0ºÜ2àUs<ǹp™½5¥Ž¾f;1ƒPå¦~ „+‹Í‡ÂEŠe-‚U+ç‡àoæЉ—óÂo+ê©J~“Éü˜î§ÒaG i ï7ÿØ[×1f’Ÿô¼¦ºúºң¤çNä’ÔÒ]мæ +l)†Ëc’ʪÅC ßxX4K¸Ž÷úT–ýÈåóRÜúd=úP hr›et÷ v†9€Ç¯œÞªÆ)¨ eÀP~ Ÿf¾½«ÍTý®“7L%Ó.˜³®×ð'ò-^¼¶yNyk‚U0.ÑOÙϲíüÐÁMcÔou3]ˆÊfTòCCT«:>ºWÖÕ„ ªy µ£¥:à[Ûl–,6“…Ri×kÕ]ý9û ÏçÁ¾ý’€€¯Ð'š¹ñÏYo²Ø.hKa[”øK¿üb(;+ÙÿØiˆ¼éÜv;'Ĉٯøxƒ,½ü£ƒ¶'`ºÊÚ^™½&‚×›¶æ¥ì=(É%s ÞdYe{Ì¡ƒˆÈôg³§¸ÕhëŸw!¡»fä®_OÂ3IÛHý:Æp4î©ò£“){Ïx™¢@~ Ç傚N¡ÛIÚAO¨9H žœ°„rI|HAÚ Âg¬Øú+ën‡`8T‹WM’ÒmöÍ3.'s9õ'Jf0L;‰9ïÂr¾ÚùÔ-G¨Ae¯élþòÓO”Yì®}柶-*Ï1+'6ì~E¥Ëj–ðªÝ:ÝúНc•¯,$‹Zã‹»ã‘z2d-’Ú«qÞaoJcM$UêóÿÍ=^w’þšº é‚ñÌN·Ø_î¨ðà rN!‹9ú³¹ïÝ”igÒnhoc¯.¿ákÑpŠUr¦=s³‚ßøNª@ ¤­^ šÐ·]3Û|èºc\hîv?jóD¿2A¦Ÿà‚O!HoÍÛõkr)¿%zSµ§Š#‘˜q¹ÈãÍ<0/ç(bÏ© ‚6½+[LÚª/” Ècüªü–íwÇP­Ð'vÄ ºÈDéäi™g,uë§`òhwŒ£l%°gm€‘Ë‹z—­a˜iXZž¾ÐÄ21HÕ  ®…D‡×A\gK~(LaÚm„ësÐW0Ób%È#õCà¿X’€€Â/+yLÁ€¢ ôMàmkrErÔ µ“v§ðh¤à©‹&,'ë¶cÂB-óê5[e·ú•óàæ~íâ}fm2ïãÒáõ“áqÀLñc±:—Zê¯m~â)æĜŒtò |»Ùþ¨ùUOã~؇0"¹.܈®LNA‰EÄÐÃTD}š ….{ŒçÙ:NYq£Áí¸ ÷É‘fø¼9òÖI¹ƒH¶#¿÷6N©ûd©\ÕëdÐ'ù¥ž)ºeÄ‚_ TÏòÄ5”:dXêÙàËl7…<”×§ # C{Ô#Z2*·BÂæ‘Ò}'ôê1§áèõïw° «˜ ¼×~º>\<ðO# žîE‹cÚJ–EŸëé¹#[Q5T.F”QÃ)u€a2¼ä¥ú]Õ=x#¡Z‰Y}Ò‹½b–^,ÐQÂD›PNêW?U1ÂÙWôJ»Q†Ì0»Z¤Ù8ʈRM¨¤/v𛲶–o‚i»¼óŽ#fy&ý—V‹;œòfö«Žš’•U-\’€€æÅ‡ÙõÿÄt,ºÖ…%c9#P±b¡ìqªslµ ²¦#–=¿É'Q¯9 Nˆ(CJgaªˆôìÅÑÅCý|~ê~®Òk:q›ä%â<¾2Xî P’Ûì4‰Í³N›šô0¡â C@SzŸŠõžYL!·YÙh_-}¡}JH´í8É{.WŠ£u°Qæ…¦Nä–v ¦(Ñ¥èý­[¢Ç&r¤®cæ?ê5äèrNŸÕB`»4q9ø¥!ÿ\€‹Páro'&!b g‰³%“á¬Ç/´j'Üö—a›»M°ˆ²}›mI7òN© ÞÜNlñ`^OÿF %?)Ê#·­òúb,fý>*—þ ÿV³¿èBÜL§Æ×ÿÇ eä—Å¢5·ßzɶô‹6¾û^ÌŸ„†Kž|:á\‘×P"v¸}œ2jÖ#`*þ5!öáªÕÁa W…6Åæ»…ãS½•O8ô©K2gTHœHyÅoƒZ7”ɧïQA8Ô(C$›í¶(þ~Ä8ôĈ”¥žŽ1r¿V7¸ âj®ªÊú÷/²úT £q©…•ÏÅ~æIÛ¯âè$ßÂŒ†E{Xb½Ù´X…;ÙݯrÒ¢|ëˆ[ä0é† dØñ€é™9­ê .>þ *¸"ŒŽS –3x¥gðlŒjìߨöNÍCn׫Jÿ‚ ×gLJ³ÆìöÒž½¿¶Äjö’K‹Í´.Yì¶‹Øj©•¬—>Žj•™OvïK<äÑ뀟Áýäø(MëOªi!¸¶‰v«Åæ-á˜Å(#$ 1x9ÆÃýÛ Œu§Ðè_Sî^Kÿ ªoÞÿß{ .…᫈ž¯±•3ÖUŽŠÜ´@ÎþGà^à¸J¹öøx Hë•çã%æ) ìó¢ä{±–$¢ÚÒ²ßÀ¼Aø£F $õI€'ïMÝ#Y#ô'G³xŽR`àÊz}§jÀô»ëßø‡ÍÁ“xÒR’€€Ñ¢œkím'Ô»$cµvUs"ÅùõW±ŒiòrÚ3ÔÜslß!X-*3½ÿr!СVÓÁ=ÑØ h¹¡1·óÞ– ·ÍKš’Ïß”¼37¦´}úé%A±‰*5\sÞ÷ð²,¶á)œ³Q¢½>³‘OD¾ÅuÉÅ7Q , äf‘ªM$n†0­PâmÕ,ÃkÉZ¿ß ¨ÖXËÆ‡ÚePÝ!<ît+œÀw£ì›§‡öguÐ2³5%¥mˆÛQÌËçÿ<qÅ~µÚÓÖTÉ6˜N2°XêŽbºÞñƒD::3I™ –Zª]zô>©Wæ~åD%z‹Ì¯J+2õ8Ç2“V~uöÄØ¦Â|ÿY6@`·KüÂ>:U‡™OÝ93<‘Ø6øÌbCŇ5 8¦Fë†ÞŠãD±Õ®Í0Æç½Æ»{ .Ôç0ÎŒ4Yµ —éz{5ºŸù´h1föxp‹l2æ Eù .û½mPyE œ,N>ænž¡v%½Ìáå0tÝIqë“”/lس–èÉ•èŸãì8r(.ž1Ÿ–IîïÏ@p{är@ÙÐpäk“ú/ùC„16®âêGÒ¡áØÏ.ö–ñy{츮ÙÚ+vw~‹ârË&<7âé©¡rJÅ8++ÕW¦HQê‡g3ûä¥oL”¿3׿¡°8ÄÅ%EMs´¿Àçý¯òôPëè(Óô5pÂdάä2JX‡càåiúR!w‘ï‰k!qaûHfA¤h}½fÇaEM‰EE¬º¶-è5°ï“}IêÕi7Aav2€¼m/@›'¹Ø— €iÏäÓǦA¹Å=ƒÓ­ÿˆŽãó4HöÿÇKÉ 5*Ÿ"ØþIøŽT¶Amƒ©¥ç—zôä þ]¤æàÁci Žªn‘LWM¯‚mÚÞB¿‰ÏQmV3T^Ї¨ýz~Ê»çgMÑê[XøÆß僜T”_Þd“ U±Æ)a+RžÍ]¸Ø(è¾fsbƒãÝ[h™ ϼmnE`¤Tipr‘¸PWœkùÞžÕ£ø·\Ìh¡Ey(ŒK|}g¾<²Ã0 \Ü :ŽLð—Œ_™„OLIÒ)MÞ=[СjLUn׈éÌ;AŠj¯^>‰wp]òýÈ{Bz’€€ÚòSŠØ<ÚgÄKGXîô9œ®æ>nÿ*µ°çLk†ûXëùÊ/—j¹)Œî^1¹’/? Ò‡T‘¡\3¡¸ Å'ÊžhUx!a0‘Í«útŸ¿½‡0UΥѬ†·r*Å}޶~×ùãÛ(<ΉÒ7^çœG¶ŽüõNùA¥Žs¤è¹Õ›Ç “b‡Hÿ­7²÷{ìäBTKêÉì\ã|0É>‘7+]™uNÝ"Š’±' Ò\Ì]"ätï`VV—ó[¹íÕò ¶>Ý{½ì%%šÿóü¸öôt ‘{ ÛpÙ¯§@‘…€‚ÜQ”o¥þd{`âIYM‰¾ÃV f`ïØ™ <œ4Ì —3xaM}Ãc 7ò"ö–.˜$öML¾k2Í”‹S¡Ë˜Ë‘âÆ™Vw!G÷Ðâp¸ÿeÅ’–ï5¤+Ñ=ÈÜél¤ämQg©|ã'uÏNv,\ñü9]‡âUŠrÖ#<³%L“{¢dÇ'/¶™ÞaZÛMF–ídìr/µp5˜ÇwÁ2{Úpº~O²ì"‰?éÌ {6üž©¿=E)sš#Ýùª‹]Ÿ×ÁÖPK@ö\ó…W æ€@Å-ÖZqÐíçrûƒ6 Zã4´îÙ°@X4¡4Õn\öT¥Ù­«²|ú(Û `)¨qÌ,ŸEÉÿéÒÈŠ›°’M ôÒBÁR€×lí‡5åô‡“\ãÛÍOˆ‚™Ÿð4IoN(X夛*HÉï–ÐWoyÜIõ‹=V9ªåÄ{e¤ˆ«âM\Ü&hš+íúà5yF@uf,µC N)£˜—ß›H«Ò‹Gتs§)î@OÛ…ýv“ ñ76ÓpÍٶΈßfñ¸\98—O÷hÀdœ_ž×¸²AF‹glÍ…•5-¼/_΋r¢ÔÉ‚øÓ,cwt*˜°÷ö-˜{ªòœ—pWZx,N 8^‹æµ§@4ĪÍ`›´‘è¯k7U[»ú€iMÕÌÊÁ¦Ï1"ûÓª»,þ^R+êj£U0«ǧ‘At¸3ïn•25ïJÕÁÔüi³Ùìÿ¸ŒzZ3\‚[q÷dJD]Ï#èÿ§Ú7¢Fc9±ê pí³—Vn“%è¬ß+,1,4&o·÷(®yƒ¡³÷™ýRóˆV}ük=o’€€¾m[2gËR„k ÀzÈ‚H(³o}4ìɳ¼*pð°?Ap>–ª›XÜ ÕR&𕻬OÐ Ap}Æ‹{bò¼ANÊËÅ—`>œµ‡V¦$L%j5HtŒq™ž‰¥L-)¸-Ð+ŠàY·øƒƒ¼[=è ß…çEáhÖáí¥ÒEÒJŠ4µ (“XJޝU¿à˜r{­å®ô¯:6Y]ÆcÓ3P¦Õâý ÿ¥‘o­ð#€D”P܃ýú!—HäJš'qè 0±X÷eæüɪב_ºƒÓ,>%}¾iµ”:ß7ÖI¡qÊ mÑ}þK·Çk/Q°++ åóþÕËUÀ'ö»ev“™Bœ°Š§ÅS¶å>½n¡/,â£Þ#Bh>‰û;瀴Ÿä%$J s€„ƒŒÏP!d~`x4z•½ô¾32¥j<ðqdE>JÈAsÞ>ä8.9iR¸‘Ü/DÆ›zó Ë#àc³)rÛ»KBþÍYºãÙ+_ФÒÓ,x€Š ÅNõ¶•uöö§¤Ü%D¿OÿRÒŸÁ&øZˆÑ-‹Uƒ(ß¿¦ÓXÊæv­†ûaEa窚75e¾®hK`|EzBÕ›ì–uP#¾ó‡Nµë:Nï|ý&ɘ|5ÔŒk¬xÞø$bGíã¡ø&Úß'Ñãn¹£$>LŸ`^ŽNZ§gLªò#Ìn"4 ³‹v4àúC¹6¥m6^_/%‘Õ„E«£Ï¼èÙ§ÉX§×¸É)ù®kú¼e|÷f埳õÊw:Êä"Øœ \ÑÐP£ÞÕÆ SLY”ø 7Šù3å÷ÚƒyÚ†Á•bŒ¶;ÝÄL­ò[÷q Séž#@Æ]8gŒÀÇñ«W2µGV ;/n¥QS^š|¯‚å¼RXü臭”pÂFúÐ.ƒg­Q6f2ˆ“:\I —\ÒªE Ù&üÍx‚ö\¥áLe’`æ1®Ž¼'†GBà]P½-À(ïóÐ2 ªj“Ê^é!ÁÜ«±§…@êZ) c¯œýªÎäŽÎ9¶z¹ÙIªu1Ž:zZ?-’j5Hñ¤+ºãR °“ÖáÅŠ_¹,îvP8â4ñNš–‚Ô$à’ÀiÐ…ÄÁ{â°ïèØ±ÕçˆáS7j‰Wh‹@åÊ’€€¿š~ÔÈÅÀ ÁǪ>Öºu£™ ^ØÌs êyq½ôªP“k_gê›—‰.k”ß»‹²Î´Ó›ôgíl Ó¨Áú%­ÊåŽiµâ 6=QKxPä ¬—´ô’3Ôhu'RM>ÜÉdï[½±tP—Ã0|›q£ØßHÔ1.™ë$Ø¿ä&W*\$òÍ´f@wíl'Ö”÷‘}ÄõÝ”mueÃVZðÃÉG4“Ÿà?Î÷ ;(ÓùF•Äóu-4OýÞ«nýABÍhi¨épÖïâfâu5¡ œ|aµŸjí-vP¤-™õÉÀ޾4Ü…Îà9ìü?@Ñ,`“ØiïVJë%… Ô—×IÝ8èHŸOE«ú8‘º—ÿÉ?¦§÷¯üå”|.Ä… t:Ó4ÊJH)Du­Âæ bûºÜ²Ó3æŠCüHó«Žó–jüÐ8úw8Yë*yÚÄ¡ë%>«ä±£ Í%feþ^N»?ÜFâc&C§d=ÎN¸yÖnGâ %zûØ@vã7,_4*0³ É…«<ÖóL57ë¤Ãâ²’B>ˆyÍ-4Ì;cd®jsjpÎ/Ïàe’o¬kqºÍ¸ ´—6óº¦\Z|U ëHØ#¥ÐŠáN,GïSF]úë‡ùA…Íô?0ø þ“¡—>ò¢üêÿ_ÆC…9øÌð%‡¼JÞö!»ìÕ;Æ­f @J×Îßý2EªYQ¹S‰RgMÿ­˜\w2ý'Á².e_oc 8EjB¡§ýT*?;äMB7£Óf̈pôŠŠ aeMœ+Tugº-ëvK˃­[¨èä¦T­¸¼Žv´‡RNR扛e$)Å%ÚŽ°° ½‰^úp4ÓÊí[sÎÈë;&úrê$c‰“ÊB9·u­MOk†é£6tÉ:ù#‡¥…ŒBwÀ"ôcï¸Òô*BËâ×ÎÜN|½êi³gåÇáP‘¯á–¤ÐhÔWŒ:¬0QâCUIÜ>IÛ4ïãÇgÒ~Ô Wvw¬Í»ýÔæ¥¾’L¡à#ãRz•Êx¬­—%¼`Á)Ѥ@ iL°¶üÚÄFõºùä¢w¶Å€möY49ÑÈÚ½û/é;naÅy(‡ÛzŒsèýÈæ5ÌK9ææ_è FQ¾_aBÖšÊÂö‰'«ôƒÉ…Úø‹_’€€­›  ñeÇc¦ÎÏ+3_«î˜bT8µI£ ‘ŸT†¼Úÿ‰f¢×%ôCAxϾÞƒu´E3.›o/Wß&Åü»qÇ|K¼ –æ¬2'`,Ÿ€Ìmb°ôËp;ù¼Î)’s…yB¤`òj;=èó@»oû×ÏÅUñxa›ÄzöK6/7ÿ=ö ÅšìXF8Àw¹”—ì ó{±éhJUÆ#Êøé) Ƕ3ÊÓ«+ÍxÍ5(-XQO"ØþbþS¯o .‰µ®±„yF[ué&ÅœŽ8é9qÉÊtŸGMŸB”,Šàn‡š@[&R¤Ú º¯T,$Ǩw[sŒo Å¡€•1Ñꆺyh×[c4ÇRÖTðlÛI2¢k¡3¬7ï%®Vh¶©›Šg+I+Õ­.\{¤øáñW´³"x¡1Õ §@vpîË2XJkûÆ,MH¡lc„s¯w¾Æ‹¢ŒL·ÁŒ{yîÏø_@…‡Ö˜…Iê³H¡UàÉÏ%¢8«´¾.èh`Фxá¾Àxƒc 5¯=4¤ÃA}*ìƒ6rZ§Kò©nu´· ­ýk™'&;|µÄÇÛ=°ÅÈNàÃ)6øñ\®Dw*´ßtÔM(6&™(7v>‘Ì8G/ÆLuF—ù†áVn[êj±côF? õŶ—º_ ÛÒºA{¤ÒqäóêŠF¡êêIv gßh7ê÷é#yþ0DgGûrè®iÒÐðë]±¹tFPqžvica×(F&‡H²FÀÊ‘sÊž1ì bçìí¬Œÿ§Þ¹P„FN6‡¥‰B7|lmêuÑIz´ÚŸË+[Ô%P2–‡Õ¤¢ ’°„9 BLõ_Á ÊÜ~gSÒ‚í~m~fÔ)°’€€¬Ô I5ƒOòsíôütmih¤ÝRèÜXNoþ2y ]ZßÒ‚öj¬Çê×&_É)2(Fþï¤)«,ô³c«Ãµ®±Á¦¾é†GÍ»»»y°¶Õî^otÆ¡¿&;>* ÄLÆB‚-3dý–±¤°/Τ:Ïy¤V+Ãͺil~7;§Ê­ ƒ÷ä_õµBœ4ã ø¶…&ªÖ$$ýs<Å£zÖ]ûC :,âøyát¾D”5àU¹£É8Èý‡óe&jÎHì»Y½²œj¾0ØÞõ¦€§,ž@(ýRRfÑ—J«Çç ò°!zÅåOkpM3ø£5651Å™ ‹ ½ò\îN]OÓèAÝóïWH#“bXbª±RO÷L[šãBôÌkׄ㊹¹sL½$xSóš)æÅ´º4¸6⤢—_ûãåGA’Õu¬vU[ñå[(GÅ5“¼$—½¯ qi^i…2[ÀSLräÀÛSÖt "\-=ÖMýeYuÂæ Ðîä÷%»©ž‚F Q×e‡ZCzÂm$*X‡†ƒªœéð0»&u ©ª—ô7®Ñ嫤blyb°AË4RÈv®¦¯ä}åV,W;ý!ªÖu©„ÀQ呿@¾¸éJ u1â7YH>8ƒgˆýHAå(òÛ–¹Že¹ÌåáBLÅ w0Œ®JÇžz/ Ñfæ‡Cþ€hù¶ÁøÛ½,n¯œŠ¼eå2„jgŒåfW‚D}y½Éò½Õb/»½oßiüd‹á© Å#@ÄFž¨$|¡][ž)nrü@öÛû­€aˆßQÕAµ?­÷¿:ŽÏ/‹=ÕÏÕ6Mï:sã8*>5ä}|z¤&ѳë8™âæAØTK„&„РЫ-6rP|m›«¨• —Ï­Û}€[•ª9ëk<ÅTHc£ª“æÔ’¾Úž 5×Å\(‡l £ ˜’œøEBÞí ’€€¦}90ñ¨=U?ÊòaAö\²p]YÊK4&[Àû¾‡òH-©ÏÈ¡ó×ÂH¶ €ãt åêãqjµÁ`ç‰Ô³Gº7V?±*‡FeYÁb¼ö'æÿÙÃkMq¿®Zä9IÂÚÏK\xûnS›üitÞE’1ê<¡{åÕƒÑóX6–ZÖ˜PšV>ò£~Áï™EЫ«•1ƒžC“žFÃ,7&I 8?Ý€ß;RpÐÒ›ëSh×â]‚„`q8œø“A2Aü²5£çšohL :ph¡¨·^=ËÐu'xļÕ)ͽù8‹`vBë+Ý‹yî £è¡ÂÚîõPçHF/‡w0e·±$›j™â¨ÕŒÓÕ¹RŒäÊ"(¤þV0 ¿åfæ"Ù³0FzÕE䌡Ôvø"çéÌÝ]ðJ˜(׿ðOfµo+ç³<¶+ÁÃvŽdc¹Ž\¦Å(|OÊ9u©„hÞ©&$2§½åŠeR:~nx•£ h$E$­Ç¢†*’·ùožtºÏÚð"Ùg«#þu…~§œ3ˆ½ðXНÌ|‚TÍ0˜O À‘Ì"ä²^¯‚~4ß:eŒÔÚ$h|Šwã\$¤ —›9àžß¾M™}˜,¢¾íØÈ7)G€óCºç¸Ñáˆ:È ÑKûC8›Ó®ÓÅÜ0“µø(èJLÅ— ¦‹!*y/¸X¤9Fk h­|,vèȾ\g [÷ѤƒÈ$y9ì“?ð<НÜlI/ñçS—þeTªx®–HV±*í·Ùr©è ×ZŽ ##€¶м²ûn’yëXLH2ßð ‹”«ŽnM³Á‘G#iž¾«ó¿_3lÏœÑ3p¸[Ó}üµ¸¯BeT· 4ÎÔ^AF%ôÄt³yÒð•ź˜WŒ²ÃrábK¶jÝ#Mg½Œij¨]Æo𤔭\·“‡èî`f.¶Ÿ±¹>øžh•Æã| Øþ˜f¾t®õ%& û,$ e7ˆ} x A"‚½³Ú‰›÷eBí¸Yý‡ûS°Òä! 8¸=$¯e•Ëÿ!ªÎšÑSêéà©Rº8(5X_%Ñ¿9AD¤¸76àµØ³©à2”ðžòÔºÔ6mòåªSE/‰nëîkòÛá7¨Ë­¤¦}³¿ñºCo^q.sF ÅMñÉóì<:ÀÏ?•÷FT¼t±†À»®JÎy‚Þ0•mÈô«µwäL¦ÔC“qQ2kPâ‰ÑÁÚÀt»Ç×@3<,KªïèAôºîèƒ|ï­üéXéx™P6ìÈé+pi[¢\òkH!^ÎÖ€.TOy%½ƒè.ûÿTn¥~Ítwòæ±€§Pë y„ë%o¬Ï_—²f­ÒÅÏ=<‚GãÄI„ÊgÇë:ˆÁÅÝ…xH >V"ýiw¦·n‹ãösx‹×›t ÐQrNÑûŽÔuÁÔy=g &S\•»èk"¦.œHÒcÕLRé÷H_°¥WåÐE?À}7eG +ï»y­dˆæú»’ÃlØ=¥Acó‹uøòëÈ«¤.¡ä1Vm•!‹¶Ì\€Ã ÀΖÖ-ß;¸ô%Á!»y‡±ÝͲˆ‡1›Ý´½ç°}77Ž$úPÈR0³ÆË¸²ÜkZç’ü»…5^k)·¤õР}1 &W7+V<”ví›M‹ÿ¨±˜ÍhnÍɕϴlÿ÷´¿]£2û+‡õPÂå£#Õú©ä·Á¢(“hz• ï£UeVq¤¡ÛH˜l¾Îö ’€€ÏCÍSµÎK¼¤\ÏAò`i6«´ÖÌx–nñòQµ¾B‡1)• ]½ñöº-ƒÙE,ï ù‹váo}èÞtY ”ÈJkò‚þ Øì"pÀ‰(›¦W¾ÃQš„ì~4»ãƒüÜ+¨å}‚ KÇ6µ|úÒ†‚_h5¸m2r¤Ör«_“â·Ú ¨ÏAƒ2º¬±ÝvÊë &Üò~ss?Àä’åQ‹œþy!¨Qƒ¤‰ëÂS‚3†Pi¥ÜÙ‰v¯ì©˜;°;¼-údí¢+~%¸ oqR·C!iŠÈó·àË@ùMpž—Yßjt!§å?·–óyéü¢Ï~ÀF&³B*¹¼ûÓ>+’ð5ÿ˜tV’Ÿ“Ž„žøn%¾aû{!¤¦¢ “³wå‘v(„Ÿ š‰‰P¤ê쎜¦ §Õ½yµ†Èç0ÿÐÂy|÷esHXÉe!íéL„ƒâ›FIî{uü¸è4õ¸9S‘"X™©ÎÆ:vDFßÎ\A³™âdí¤a„3ÄTãX è€Bý!™þ”µ„_Ò¼˜Š®Ì‰áöo}ýšë#.Ó¶£}”®UM#aSª  ")êõ<8,h ;ubÓL›S!¤lŸ3¥­Ma‚r¤82)`µòU?4¢ G…hð®°Xxž£5l±•ä ;—áÖæ2ÃÍ1Ï^i©SFí·Â  ϯ'ùK¼j.÷ð´õG©Jèâ°µÀðÊmb6qqÂ!]†ºÉ{QêþÔÔé.—3ŠƒVC ػ2)DöœÁ­çÏÀQjPýÃðöÞ… ѧI+µ¤Ê¥‹ŽéÖ`ûÏWŒ)‘U,¯ÐØ*ÝF!Ÿ>›Â©G¾Ÿ~@©’€€¢©¥5ë’?T/´pv5äïJ¬†¡ñoOâ^p¬dŒ|Ï^霟I?ƒN¸S´®ŠF**,þ¼à±˜bã®; 4T,ÒhÏ74´…q^4¥•7¦Þ±þ•ò*µoz-½ËZÔYq: ¸ò™ìDœÝyÇ·èÔsmÆø`(| K‰OÇÂŽ3õ˜þ4¾Fƪ»>KèSßÙªk䔳[ãÅ ÕnFÎ Yò¯Nqi¤Û 4i¾6'ò(ô½Åm‹¿¯\ „ôÃD3Þ—ÜE§¤}œ½2õõ@:~y{°¡‰”á…+Éóöî~Õ2®N1¼g1â¢fÖ—éw*“®Ï*s±+µâQʦáSqxX~›n;¡„QÀV‡¾›ïøªÀf ¨Qâ[$øëà#‘Û‘ô†ÔƒúÌ>Pí콬jÄWðð½ËRɺÆjç{é f3¦7:é‡FF&»¬ØÕ.¦¦&Ÿ£=ð@jí¼–Æ".ˆÞ'Maj% Âß•»²©L^ôÝ`,ˆ°êõ܈¤ïp1Æu´OÕýãY«þ´a!F§†NdPø ã,¶‡Ê²¬Œ Á {)±Xº\˜BLÑçIÐ'õإܹ¸ÇÛ?«³ ÖñäTBÁ—³®ÉýF(ïIÝ‚¸"Ò±À«h›«£ÙWANm/݆*?΀œjÈST‘IéÖƒP–¶]? _?è­CAÒ½ ÖÐÏÚªÏ^ýväZIí YÖY˜%¸Ì¶øÃó׃t©b¾@h7i ¯>t[YrëЙð9Ôç€NÙé¸5Ì!ÿõi½Ó9èà À°=±ÄìhÑ)ÒÞžeó„CiMbà”E·ÄIXGº÷¨@«o„u&éŽdt4ÞÑ  êD`‚È.‚ã}Iºèü™ÕÀY GéÇ.T”ãð ìót¬R÷î›´|$°¹x8n^ò I ›xžoáJ§Ty‡ç]ãg‹ešJŸ[ó¹ þËzÆ Z´3Á\.ÚDg$DXí<ªÿogt¡DçáØŽÏpå¬QHl Z[íIÍçþ®yŽ„'5XT#Ž84š ²7…9QúApÚ^Zû ˆùâ"E’Îû}¡mˆƒNj5ÒâyôÉq;á‘jr|LQ|ð¾ˆñØH>Ë’€€Ú.µÃDè>¾¤Á_ $†+"œ¾„p àË)ç"Ìçò#:+wiú¨O1‡ôeð9)]wRÇG­¾àùWHP×ïŒ4Hlö~¬íÕÛ«I¤o2o¦gwáyì€nlÇ¥M9\Æ•uÁiŽÃÕ¢Žñå‹ÿ~nîȇ°k¿šèwßrcСèh]3Zðžz VŽÃèWéf*–8#|ÜWeÌn]µüX!Ë®&mlùG¿é¼»d€FŠ<šõ+Ex†ü‘M sv¥Î×Gq.ʧà"y =ï!ö¿\2žÝÑKbçÜ÷$ž6à4X¬² aè_þU;Åâ9« .~ 3ß=ï“Ý}}¬$ìý+<n—ËH‚‚ùUSI¤Ê;´¡åm$£Äk¤ýM¸cع«}u 9³²üÿdO¡ü)‰àò})±ŠNÕ×õa‘IC€˜p÷ª²ëVÀË™ÐûI$cêô½=ó*ª]õˆw$'gtóGó‹GC{©þ’-_ŒýE͹YÕ6…p‰û8«¼ÆÛ#Òã§ÍÍ¿ÿsÇqÞ¶o§d˜glËA.‡Î5[ºÂîŸî)p¯ªü{¡ ð7lƒª®™¤vaj*Ñß÷ cÖÎOˆG :6èVqÄSZ¡åhžn÷þAùÔ|¨+j‡õžÐÝÓz+.âz¶ŠB üÏVeÝ+ÁǘìEþô§áqô´m0ce*ˆB¨D=[üüœAø´4¹¼Žµ‹GOÆ{1Ì…¦cƯ·@…tÙ¹¹É¿x¥B£ÁwjEBÄñ÷§C1!~`ø.‰ ‘¡ïÛ­rŒ«81që\"„Jsän5Ži©ýbŸ-• &<´œøðF´ƒ#GR– øÕ\ä9†9 Tb´ñÊkºÎ~ÀÑ¿$ qÈööBrŒyÿ¤+áÅcÀجæ-Dû'6¬æ4µ]熰KI{ƒ©º(¡lMy«X{HÀ*‹‡ÆWÆ“±‚tù¯©es~Ó|÷×Rì Ú®r‚E5zäNë„ßlìç û9,'¡ƒû¶"}ÛZedF¸Q#bÉE-Ön´#ñøy&'óüÅÒT_Ü=p=»Ü{N§ò Ï Œ?Ò­NY •¯©¿P ©½‡–À“ò “\˳^ø¿1‹À’€€Ì<œ¢éš lÊò'Aˆd¼«ßI]Ù ß V$Õnðn ¹”#¯;lúÈ”O8ØBµÜêXÜæ•$cÙ¶´´wÜ»Îà¦O™Óh“ËKj××Z¢¶à⌱¿E¹îàºyÃ|>›âçæ¾Ã¥JµÂ¼Û££6øÿÂÃÚšêþŠޤZ$‚AŽ‹·,hN:>ÛYû^N»:=‰úZáOouté1$›†Ûü˶Òàoß0N.NSÌÀm^€]™A8ªGù]¾» cøVícС`Lº–yÞ‹ÃÿóNhè)ZžMÿƨšÍ¹BàôE=®Î`Q˜A‘ øa–[%YÆúíÚŠ½ŠnÓ¡“tX:i$Ùžœ<ñp`bÌ‘’¡V»vú*¾CÇ .V`¤‘?$j›´Ù{åÈŒgŒþ.óxøFBZâÞ>Ùý%-ªò­ÛÈ{¨¹ÝíáÀ]o³("8«$ZDd/-ØEqìÓµÐîLS·9MÉíº:牛æ(®8Œ·n‹¥+'5÷Š€|°lŒÒüñǪ#iF ©S )å%Û¸™LþX;\(jù»1î”] ¦«° µ{™ˆqy¹µJÍCë0“³Óò„Ç<µ¢œÝJy£À-cwÑ®Kqh‘žÎ1v¨fzL ‡YÔ Äšý´² yþÎ/mî²ü?1%ÜýоŒh﯊àï¬RP ,žºD¿Ä9Uád½ÿ‹ z̸uùë¶è³b¼ÕgD©zÖ¿³ïÖ®Vk/¿S¢o÷¶g?Ýr›î~:Fwüðg7€ä,ÜLâJD5¯ ݦÂ-3gúIÖ\Zùº@ŽmÍ1¼vßµ”+äë¥C’¡;Ž>Ú¨pÈI=ÀßH,µËÝ[Y² py p÷Sψn)dĞȢ“§ðŠ7œÓë4¦=®=öæíòÓfÁ™kADç\±ãñËTGȑ۬`Þp¤;w[Ø4è@7UÙúÄÍZÀŸN«Êïhç‡¿ÛÆ8/51ò*Æû.BžÌ¿ÑÚC»»~PÜÒ1ÛêG}P†,‹ºòmóbmÉŒáØì×Dä¶3˜T¸t‡ÐgÙº¬`Òï.ïjûÀ¶³©Ör›_-“‰‰Îÿî‘Çý 6‚îF¨¸w_*jQøžNÔÊ[T†ìp7¹9Çjøø’€€°(ù{ÜÌ:q5áC6¯9r{¦k=“V±xÇ–9‡=Y8¸¥³Gt¦ÈlFIèðJsŽš§è…6‹Ÿ°èË«Îa†»×‹«qw‚ Ô™©UwM¨5ØÌ„,’äzÔܪ»"ÃÙ GþnµÇQùØîÑn¡uœhô¬ {…KÊ”ªè¹fn|'` ý,?ä‘®3« UV_† t2ãíE¬´Ñ°>JS7<êÜï#QÃFëqMÖô“OʆV•=bÓkÏì(È8L<¶‰ˆ¸"À§”Iõhz¼J„`b˜«~Ùh7©wL±8ÒN³‡Év÷Õðw“XBAó¢ ÄEŒèæ\Q9-ψ†«ÎðˆŽ<­XÌëÚÿÞà NEãM_Y~õA7Æ3kúJÑŸ'†Ü=ŽàKsS m;©„z (v!Ö*"CïåÎ9¬s†–G¯MG5á{$8û@àjyÉ‘ìð&ó§Em§Å›¶X*á‘h{Ï´˜’]|’ÑDñvÎ__ì“Ë„­oMé zíBÐjƒÓ,’بìÈeÚZÊÝQ™‰ôÔê}KÜî‚l3êÆÞÑ&ìå®Q²Á6‘˜£Á¼ïæ©Ç>ºÑªžp"cN㸇Ú/¢Å¸Ð¡ë¯qØ“lsÍ[’êLH𸔉¥Å.tÀÎKMéX3TÞ[²Â×ë‘|¼­Ñ«Çô}V·Ïz)&mƒ=¡)Å]Y4’@d€nÊD{X%…U*•þÅ(Õ*-&>~ÀßtÝí¸ê¦=†¶ýC9¨Ò[ô؆=Ûßþ<•w÷‰+mtl…Ð:×Z¢ ìonܪ’š¶zŒÊ§YP<C¹sàŽžXFÍ{W½pŸôpL‹ĈœvoùI§(ÙÔ¦ÿ:ª3SÒüä}=öš˜ˆ†¹sÔRfpnЖkn]5œ–£ðú7l]Œ\ªQfy^ âI«ÚrZ–ù-Zõl&»E¿`Š—pEgÏ÷yÚF¶KOÎxÌûCrã ñ_÷Pýü `2p•ÓX ßéD—Ó†`ßLÒ=>/6 0³áS1^ú×½û  ùi¤ÝMÓ·É~îW@$3N¶ËhMþï H3ƒÍ*ÍÁ•ÁæEæL&DݹhDzâǷΑJLd¶Ràú3|T6$ÀOß½e–3ÒÏVldŒq{C­O€[Á…mÈóâ~ú䥖˜µT._Ù°ZÑ­å),`‚1³¹öfÊdwuè*4|TÎ7–¾ålaÌ@¾Wëór`r•u*f¢ÞÁÀÀƒ²f\bœü" Soá:nÒ¦òÏпÕxͽDÑâñrŒ‡»!4Þ!Û½Ö2³:j³šÐ¹âvj¿ôü\£œfÄPCéÐqñ÷-‹Ÿ¨‰îO0ý`‹DVbH}£5õ}Ò-¡¹ î@P:”ʶ¸[xç„6ý=\ +ü’ºª`®.ýTÕ&[WäÆ œZöÑI°VŒ“Ö¹ÿ*¹Y¨ð$%Î]ÏÓ†ÔÎ0'Ø\fòèq–é(›¿ÙŽŒD*ýgsë˜<¸ï^TúcõĉŒ){:ˆ@× žÿP†ÍTà„©D¤OÒ,án 0#áý~’€€ÄÜ&¼÷—кÉóþr¶(±w‰ê` ü*xLÎ,mˆ‘–Ï‹HÔþ$á:´2'Æá³¹B iʾ÷„€¢Äf™q¿j³Ê®è¤VxV6‚ÍÁNnebP²†Æõ/ïÿYeðƒP|>ÖBtnÁ¢ÉÆ*ÈÜ—]ƒqœ©ÆI‡·èÏ1¾Ç=@t(²_ãî$7|‚×:tÞ0í ½¦Ühl.[׬¢;d}ö)h¶s¤œ24Ú ™}Až'“äò„×ÀÖè¨3ÑCY|UúäÓàhz@ÙËý¥Q™'Èö´õì²`‘«õ­× xe*GÑ*ÂÑ"ÚF›út% ײ°¯‹þÀ2¹\KÆZö…éU"£=ÒoØf8U«@m™PÁlV, èážíîþéRòÄÀ¶>Gª­®ªŠÓÂíR?›ÔÊ.·Á–$Ïþ)¸ªÍ|CºZÐD‹&ˆámqêÍÌæN˜†VZý!ôs–QB–Æ•b!S™[{&˜þpÐj-†7ú-º1|cÙP>K¡çÝÆKƒô€¥­‹[Géýxèyãd•R¬ˆøÎVdPHWBf‹ <­Ü´v#çoßýÚ“ÿoRÌÁ`0Hçèè‹ÖöøD¥pè`F÷¡êGÒÓkwP9Üæ¬ÜyÇá¹°ÿ Xf-Q¦&#ïçkòl‘­šÐ/Îrè1JÒ–´º‹Î6–yg±ãçisIÉÐòs£ú"ÛÁÅÌSv®,Wš÷£ZCªÐSŽV·m_!IŒæÿ[2~´&Í*YQ?Šxo_™Í@sÕäzÎR‘ÉÇ•ßaÑ«t}øp䥯'ßC\ó”·Ñx2äF2X•.öÊiL¼:¼7ñÁ.G[“´Bø@*ñ`äê`Œ­p=.åÑ ¢máNˆ9úÉO£þ?Ò„ÙØ{µo±€Ÿ$Ê_©wœZ(zåü÷· ñËáZòë0ÉC´„…‚µÚwÓŒbPqk™½§ðo.‡¶‡‚Gº¡§“‡ïíÄwLtæÊË¡1…ò®g<¡ðBôu\—i5<ûi3ÞLÚ µXó_OÞzÓë»õ‰]f¼)”AË%t‰B¢¥3C‚OÓH $Šf½\žÎñúÐ̪VÙÝ8Ý\ÆUr{¨½À¬úpiƒTu¶LXï ⃚â©­›’€€×Ôž8ØFº‡k»,å‚!ÑÆ‚žWÂO´ÏÖ•6‚^ÛË[ä8fXÈ’³,·¶A±À:¥T ‹µSg ŠFÈ£Ú…­^:ÕƒOL·†zdᆤõ¢ùÖ«Œï£aባÜçhæoF!ý ã ·š¶áínù¥7¢bõAúãô€’9©@ù ÉþØÿê-@M0¬ÁäÁOé2ß±Qú¹ŒåºKm3Õ«ÈZ³ºG^ÿ£ ÝÏʲgqäßp*%¡iº†O·\¼êýµcAÌ"ÙÉÉ8ÖiEÕºÇÅ݉f­íWò;ýíxm vNQRÒ‚< ‡UXÇÛ>_)ýn˜NËh¿]ô’pDµL0£÷¯á¡KØuÚ½+ø¬É½ ‚5¼Ö û[ÐÖ(“NJŠ-^46= ]ì3Û&¬|Õ+‚™C$1V]H4Ç6ÏtCô¡})%À-T2›MÐ'D¼hɳNmE^+A2©ŽC܃)˜¬1wLÞ¨qèî©Ï`t³„U-õÛ÷q.ÕVO{> ´}¯]ÚUÕŽ˜žâæB1|§žùÞaÓ{$AŬV½Î1ºÕŒ/Çe""æÖAG$™=ß60Ì墂×Ýr,Äù©-o€½*Hi÷»<~í –¸ÍuS~®r("D^)ÌD•¡à!õó<1óÇG™§æ'b5CŠáw1ðƒŠßˆvÐá9 -¥ÕkøR µoròŠEÀK´ÆZÚ¹s:ÈP^—Ô RÓØÁrîÕ˜̓—øh½%Ñ(à)‚Ï–Öùºˆt¾ÌNژÒý.ëÀ,Éžío¼=Kô‰¯®sÁP½™Ô„ÑußñýlN¢Mà vÄL73ÌzÒîD=Áñ¨£$v§³dº‹l¢ÓrÄø€Ïw ð©G½oi:7Æœ”ˆ1W©»;s• +…íuÊAªß0V¤$èĦº¶^b0÷ò"~&‡³_dàgr„žÍƒõ}GÕ•^GÅþ˜ÎK6 iEPŠVO¶ùÈAª¤,¿ÇâJ—’€€±¯J‡™=¿òÿrÿz(ž•0°w^Íé<Ÿ+ih|vë5ØLŸÛ56Pà¬W@̘e¯ûÆ®¾ò˜’²}HÛ*QÓS`˜¯eéÞUïªê8ó"91·=ÐE7f£¶ÓÂkö¦$–¯Áõ‘gÝÛ ¡¤^l‘œŒ5 wM¼ dÚ yϨ¾Ú`pÊi½öðÀÁ§tîN]G§B5d´ÃVj×1º°WÍ–‚ÔÂ4‡¸~³§ˆª4Á ª×ÃwÌpé’6÷ÐQ¯Õfäf“Þ¼.¾éñ=å¶S6 ‹êBÍ7·Þ±& 8ꀉ%p8#+c®ëB²Tf÷%Ûƒ±!ºÀa¶Ç®žŸÃnã®g¸¨­r¨“û*j $ˆL̈²¨Cþ:þiOžbrmá52,q3ge[út‡&«Šn©(xsKà<’þ‰p7MŸ£Úÿ²|#…¼nP›J ÀâÒù~ ô‹¸Ûô©B·òùùŽ,¡-“d¡¨è2R±³ˆºI68˜EüE¯UAœÓµÅ<#ÃéŠÍÞïÆ× Ï ¡sÿj²™ Bµ!›·xÍ×–/¨Lø0+m*EìD4x[ÂMÇÎ*× ]šjCˆëãO0%ReUš¨*l§ªì· ö`ÅŒ±¯Ø,ΟÕÞñ32äJÿSëÅ%âà »÷S-X)‡‹ˆñrOt8I§ Á»•ˆžp§Ó‚šjz.憜ãêi¦ði:g$n%lñ.Yþü{•e~›¦H›(8qý€\ ¥òãÈ1¸ ’öÁOp-R÷ò¦X\r¡„:#o“ÄáFÈ£øãÓéq)éwõâ_tË‚y¯±õpÝÈ~&Ïó½+‚ør&YtåƒÃV ›Æ'n,1##ÓŒf" NÀ-òE÷g ´¸g© Ü&GO,HH35˜ã—x×»€Ø#À­Æ\PER*±Ü‚•êé ¢ælZ®¬³€D?‰·UïåR ¡“æåi¢…Ï63‰ÓW<GÐEN9ÂÒ[ôø9¼˜YËýùãXþY%0—õ&1“Ú¤õõ!ô~{†6¶‡ÊWKÒ阩XËä.âM®«jpÂAøªî€FrÁ›],"Ê ôdÈ:$ȺRün;9=Åë˜ 8Qpi~ Þh: 5³û’€€²uл5¿Ô­Æ .nزо¯8Äs7N®Ú– ÝÆGŸ¶{ïóæ:=·œiÅ òB2ê¯ÇbÏdŠà‹x¯²#ƈ=&Tf8Ï]ŽõÙWûÜD¼ߢOÔ$Q)îJ8ÔÿA¥]à°½™Ó¦6 ‹zSÞâÝç2ÚšMô‘ ä® ½¤t‡ ý ä—$˜üBÀo+þ¸î±Y¯ݬ×ø¾ê¨D_ ží/õuØŸšU£¬G9½t} 7Ò+¼-ÚÃò‹Þ/éI–µþ`©ª¦]JîZ„‰r×g«ÒªëýÚAÖ;Èç1ì”ÌõùV@¢¹Á u“?ïÖéŠR|le€N×®›èªÐùÖ„+ÿŒŒ®±¶y–(Çò63ÁÜËê;^WÿûKâ¬/¼!§pBèc^a¾‡úðžþÏ5³®_ýËZ ´qDôÝ 5(ú­“v¤œ“\Ù6ÕåQì»D㉷èý-¢öžš¥]—üŠg]Y ãT>×®o²'dð-¹d‰Na—»¾’ˆ³YžŽOþÿ¥®ðô¶¸u«€o›>[, ¢[1Û$ë;݈ªuŠiæì²ŒNÓŽ¨TñŒã­‰W8x+çŽÏç¶ü. JNÁK^D¡§ñ#ÌAƉŠÄ²÷F(ÐS¦¿šì­^¿êZJ|ù¾]8Øívâœý ù;Eг=‘mÆ µÌŠlsyE¡ê Ñ•/¢±^q±ïŸÈ£)ùuVÌÜ' ºÈúbž?=H ˆ§mU÷¤+ÿ/fÕAéLÚXm · eÝ1iè¾äøcÙš1á÷ÖŸEÐ8Ójðç±Lc^C®-–¥;ZÍã62}Ð'"†¬Ëí«œç –Ü˜{;|jQ=qTðÎ Ìã9ad~¿=¸<”Ó1µXôK(“}ž(4váð¹¾ZçwF?/¶t’dy°±c‡A¶¡y܆®6©%²ˆŒÏ)Ú“œ÷çÖr”äB—SÞGH¤Ê$·þóœRƒ9œŠ$böÄó»™èÈÔW±XwަE/2=±L Hzèäù`¾¯°½wåÂ·ÓæÚCxÿÍsæéw„ª¶jð¼É¨+æþ¾€Œ¦åF%ò5t¢þ‚¤"‘·¡t´bü3]îû9A¡“¼¥$_ÉÅ>–q ÆfÁªOÓöêÓÐ_*0»×rìý™‡â³Þ~è¬>ðÂï,Š«Dg ¦S’ì„”ïÃò!òé-ŧ-é_‚4*„?úÌñ›áÎb ´-çµ9õ²@+Âo¼T±“¤SY[3ELηRIOöN‡{YÌÝ–ê,‹Ì|{%á»Ü m½—B?m~^Óººä Cõyl娵þ‰ÉÀMh5r_°ˆFê“mÍðµfÿ‘‰ÎÔˆø&ŒQ§³<6îpMߪëp'‘ÏzÜ´œIË1sQJßøJúsO)±1áÏ{¶ýÀy¨à ezÖì%ÎX3[Ø.Z7ˆ_äÆAÎ}";óý’IxÚG÷~f’€€ÉàëEs%2)R[ä ~gîq€E‘„háåËjÒ_ÎøÐç>pžpõ [GŸ¼“³éQòí‰eàP¿•(B€:„)*ÀýËÈf ¿2Þ¯ þÎ'Î/²óµ¦$oÕÀÝŪÖ,WH•"K;R QNï 4­)ä¥Î’š±X­Ø:1Ì’ÏKÒ^[Œï8*Ê=Ï‹O9€“ÐäöJ»߉Ýö¾7C)6t¥ÖAº–—*/«“ìRoŽU$Û¯ìÃë $íâid¥À¨£ýJÖÊn?)¿ ¼&¨E·s.æJ•ì!ù='rU6é'òvT5Ü4Nà¼\CPz¢qðÇÇi/Oº˜‹<ÌZäÈÁLŒbÂß>õóƒÔ-­çJ´à¯ì:ŸÉ3\J‰&‹F‚¥Àpu_äfÁ“nAì Ö™j‹]ÿ×\ H+YGïŽ-°ú>,ºì˜Ã|m™³’M%2 êÛ`Š ¶j®%ß(Thc—Ÿ·+|H½éÓ“ŒÈˆ xŸFñÁñ'C°ebX[1ÓF§*œÿ5W?:Î;R±Þ‰_ CLþEIˆï þ»dzW„©*ø•ã}Uçzô¦ï%·"WÎ è[a¢· $ ÇÉü+´IfÚ·¡K~XEàÎEúõî1#Øú«ËMfâ¶|¬ih{ÎÇÊþFQI©Öçöbæ³Åfº1‰lwPUߪT¥Fá»_ôA,Ç1½‹|©‡îÔ’˜r‹üK{7ݰÝÂÕ"UcgzŠ©ò-ë×¢e©ƒÃ6-œýs‹Ôòç>iÉòÙä],‡Ý¬ '>¹‡(âþ÷JCyÝœÝÎ 3;:ÇÒ”zÑá”Û—ÔMÑÀ„ôÁ¬Ö†fbc)±DsXYÕ«q~ÃwVd0úP¢/1Ÿ¤ £ •²ÒãC'7s¶ 7ª’Wóô‰Í ã‰Ù³ü™$yxÑ.ŠPôäÕ%"(1Q–çîÔßþ OÇäƒÅ0Ñ’ëÌò>r‚ÙߊÅrõiàb½Bjt® †0íCáklUwkDla;LXßhŠkuõµ1—ûæCW¨š,Z~wÒnRx€Ôh¡ñª!Ž:` ôp^³É×Bp™“‹º,ÿ¯¹äª©®Ää;=HøëÙ‡ìïëI?±†r#Ú-lRÀ^¡«.EFÜ´´XU16˜ƒømŠ’€€°¯nÌXP…EçHcb^ `–üõ„ÓyòžZ, “ïQô\„P‰o÷ùqÝÚ^ÏßdÁ/Eš¸û¼Ža üp°}ÎñŽ”°¬·:\CD@luXfa³™”ÎÀÎçCb·€twø/ÁMǦ›|‚7÷:` ;ÍÊ#¥ ýë½*±ÜUCÄ™ˆ«ÁdDSò‹êÆ1–Aq¯ÛÈÔ"e Ü-´Ê‹";½þ´ÆíÉžòØ^{k±ì8ù“œ1÷š â¹i=Š*¬Tœo¶ Z*üšê»Å'VÙto?¸Ú¼NDƒðê_cÉÆîÚõrÉÃØ½Ïš &¨™Œ¦-ÈWbåïÆ·‚W/ÕCýPù©Ô¤g¢ôã0°Ùó>Oç}­~Ò“ÖdZVnÙÝ–ç£1á÷èóéã^ühµßÀÉÕï¼ ¯ ŸØþH ‰qóNø<*+ 3‰:÷ !B£¬h°ÒÇ{*j}%5¥=˜˜Û{æ¨ÁÈG*±` F»ºaësY}éûÝk¼,gkZýΰ™Œ uu ¸CTHt—y¢£æþkF;ô¶•î4^>²¨—|¡‹É¾A«,ˆµ8«Ã,FF5Ú»eL(9øÙ ¤/+Ä›&ÇýÈ‘-æËö§˽¡e©=п+lõª«< º†‚«Ò‚GÉάEÛÚcIr¡Sö-tùêÐQ㈴hŽsB¨ý”3 · ‡ON5Ö}‹K7“É‚¥_NgÒÇt=uÖju…|ן]Þ½nt·XÜ9Ìì—x¯øCU’û¬%„naµƒù/VãVTrç‡ØQF¤G›)%þv\sÐžØ KAxXWô’9ÄŒ°áÐVx廣±"1Ù;A¡\†$2î¦:䣅\^¿FŒ‹ª\U ´¶7t]ML9”ÉTFç4‡Ä‹ÜÞ̳“óyÊtj¯Eôë9\ iŒfªV&š·£ ·çË’€€ÀCӮ衪R+Êqw¥ X˜])£Æ‹>*÷ìKô`\ºM¹ˆqë¿(-ȪT1Gï"àðëåþd×°óK‘<#YzT”&pC§å"iJg^¦¯]0s%©ö‚xDuX&ëõ«=š5Ú#…'ŒÆÿ%; º_ˆ`Ôðßw­’CØé¶ 0½L@ؽMrò‹™cG@ê”÷ï2}·†ö(ÉéE‘ì9äʇa㣠È0’`ŽAÃõµŠ{?É ´á©BkÑ´yœWsdç¯e^‘±*õ&õ©ŒÆwy…Õ’a\}ŠžŽ fuñ`H=Ƚ¢4\®=Rôh5¥œ)~ Ð’É1—¸Û+™ÀŸ'˜äHb´wP,ýW}Ñ컦¯ªÕfJ¹ØµÆ F|%Ã=ÔoÕ$ÑÕIÉO£ ã¹ü]Æé³ºœ:3y'Œú­xª3 .3ó¢¼Ç‡{œFô%4)4$ôqŸ"§™=|j'l§ÆdZâA€\ÖÝ\ È›°½Ð!Æ$IÙZ_`Å*d{Só'âc0lè ¹óqÃú²¨?"bqxË /4ö:ãJïѼØ0ˆoŽ“ÅòO"Œ‡Ÿ¤¨Ï‡¹†ÊˆYJ6³ôXù´—îæ 3†È Ÿä|3O÷ÏOÔ‡pQ\ê-êr§ŠúÇy´*(hµ(öãá û;¦Üâ»Õ³Eòh$¦´zñݲ¢N뮥z£{^úñ.äÖ=)|‘™Lõ>ê-ø.$^df*‰u'¬Ò­)w¯ ³G¬±‡!ÌÐ1†M2Uå0›5¯á¥Lk¸³€< KÛO°B¦2÷-Ñò9oTÅÇ&w–ò¥7 š6ñçòáX¡”"¶zo¢ó\“dïÙTb6·¤ÞÖ¶zfË¡Çôc‹êo‡pötsÿ0äBÌÍÂЕ”øÆ#ΉuÚ×»TüïhË­vÉ ’¬Æz(4Œzí-—ÌË9¬% ø:Óü‹KÂí3ÄÂõŠ7ɦRGÇ-n¼UÝJQt²‚ Ž8Ìå`¿+ŽæsºUDÈ‹’€€ÓýÉ6ø’¯Áœ$ULr¼¡®tÛÐ0Ú” )˜ G~4´¥QLÞp?*„)G$ /<£_ºΚÐwÔ÷y÷[t¦&¾k²éØéçø­ šKFèê›$ŽZÄe/"«º¡HZ–ÀZÞ_xˆawpBhw÷bC)lEÄ}™V€{V;àý‘IýõÑV@¯Z<ÝBkpn»©THÊ[i,Mž‘ŒhGW²Y(ø‡­ÂñŠXƒNF#Q3W‰ú’}G6ôÈùSÁ¤WÍ·.•bcâÞÒaü<^xÃýÅÊ IÇøZ›"RhkÿªéXZ±°«Ìw@> jyŸçDmï'Æ3õ¡ï¥%T»'í0œ~tLÃmåÊ9¼.¦#BK=þ"Kñ™0‰x„«{¿=Ørǃ¿Uk‡ƒ7è°^&eKw2ŸŽ6 ZÔåd@9}˧Qƒ. O´¬…¬ÿ{2Ÿ¹8Dã»ã)¾l þ'ûÇ–u›bù©Yt¾ än™G1–]rídZê"$ž[êBÇ+ƒ¹¨÷Oq0”VÛ‡?·’Rvó—…áÝ7œÁ£¬½Ùoì h¬S2½¼=K‚¶¾’ )ÍU“/^ìwSÅ´Aòôþ˜¶à{¬µóÿZ?[ Býèm._¥Ðݰ·~â¿eò®áÚ`F-ù‰èáÈ'w“²è³‹Ö ȶ?ª=û²&G(6’¸Hz¨,*d¬«ÌÈÃýN—§N®xÇA¨ZïTcfb–!rœÕª®I”(¯ó]|îa:ž5´ú—¨Ì´,ŽPõ– ™¥[ÿn Šëƒ\®«x~%áïZÐU†,*t¶ö¡ÌmÙzMž\äJRØ0øæ¾Ëyüs “ç€cçÜ ¤–¿øo Ü6y5M%VwR_l}Bqñ Tþ\»ƒ©@¡IFÐåê»$˜2Ьæ^]”ï#¡²œˆ: ˜¡'‰Ã `O?“¸zÕ ~Óð^aŸuu]Þùµ°ÅbBÓ÷àÔ¿Kå¶Bƒ 4~•€+톺'`­K`` ž(ÿ²"KÞÈd!“Ã?yúdO B2o[v7þ2©ù=ò£s†°ŠMgž>ªPôˆJŒ5«_šqê¸i›@vt"rìV½‹æ =AÁÍÒ¯h:(@ãÆñNÙÚ6ꉻ!«¥¸Ú, ’€€¬¡ù Ìó‹oCŠf©‚©‰hÝn_w²³%%w¼%AÄÝ4¶ëà;xÆÀfá$Š‹Y+ÈMÐu½ÃhL>SÓ(·FÅûNÉÁÐþ—Ol[ôºÊrÔ±y}œhëæÑ"´¤ÎÐNUåˆÏVýŸ›6y_Æ%æFà¾^ЃëÜÂY1­ŠÌeϦŸ®ÈÞAÑjéضéxµ!≕ÃEŽñWH¶D¦è‰æ-–˜¡ 1!é¡{újïC=#qÀÌÜÍnROõ_ÐSQà,(¼×L"3=P?‚I˜ýãÆ–‡*Ê4‚ðÓô<^*·gX4ŒÄîDÞ1g£ÐhÅW®¥Žoˆùä˜Šê „áu:ípQõ7ŸÍ;ö Ü5kµƒÆ&]Þ]u½± I‡B¯(ÁF¦Gº†L®Ç…E‘ÚÚùaÕ ­þQ>°ƒjòF¤Su¥ô¸6e·>í/ñú™Aåg¾2“o³º• ჟ’¨#aï‡z'z}¬Ûù#ÒÉãI #Ïny°FÆ·›f(&Z«ÏïÝâñ£Š¶õÍö«*zäÁÖû<ØÍß0©n÷3kŸ ¾+--! é˽Ì@’»Š”š‚çnÍVc­ÞúÅŒl#¹UÙï Xž¼âÙŸ•h¶! ì¡ê,I[7.Ó‡¿mè˜ÔÍ«o#±—…ðΠ5Ð5z¼¶¯L©×qF­ß ;»8ô"êQómF¤ÆÁ¿àïFŽÀ?\°iKMû¯…IŽ¡<ïKw‰©FDs®Û0BÃî˜Áû´â"ª%ìåƒ+×R?ëºÛåé‹ú™ ®ì¶›K*¾Ì3¬¤½ö€pr½%u•~šqûo™î¡¶¦¦:k÷ÕWšôT¥ —³lî›~,Wr€aÆ¿.?œÈ’Ãó¥&$’€€¹€Ö%û…w ˆh}Itâjà)JØè }ÔÐc¿GÂxÞÍêÎQƒ¬F޾ͺ®‰YDa`Àïr·/ý 5Ž4Òë¢ ƒñuçqÙ ° ‹\5™-Ì”ÀKüî; 6¸Iø·¬·Á›?£ ÀÀjWNéƒÀ80Qy8€¹\©­f÷s­ùx­=wÞŒ=Ûª>¹[7Š6’ƇmW UD=U°¶Ô)› Q)`$4Bå/ ÉR64êÑm0¡œ˜9à ›F‘àO0èy¼0{ävœUTƒáó&µ‘ŒQZëdŠS”\ìGÔ¼{.Ø’߯G³ùj´¾ÌÅ×cK Ÿ²ŒîòE ‘¬“$åŠl‹‹Å E|£[s \Q†‰d&žJ£ °Ýè|0*ªRb |Wqòºý¨“³hŸ ÀêøË$ ´ÓBß‚jÞ]6ÍŒó(ýÉIÚNs2AŒyT瞊ŸÇeiùÛo%5€«•rî)¾ï¶ÂΔ㵬X¢ Æ¦}E€U×þuå:Äé^ؽÞ¼—k{­éÝGÏ~ƒcð!²½ƒhC`õáOUZdÝëX¤0_ ?î[ïÆ‰˜¶ZpÕ••åÇÜ\ÃÛ¾0ÅcƒG¹2‘Ù«†-)7;¡÷{eY E?0íï AñÒ´, £Û8×Xm:â1 Uå\_òYC©:tý¢Ž€ ½÷•ÌÑ——N®–_Ÿ\¢óQff+WttKµáêÖ¤šcÂ+Ù6J/ÇGw\¹V”“+«çéé›™øIÓ ‚3Ø(6 @5p\3A²µ)¢¾]’÷k€-߀ŸùUš)ưÇâFkK'õ™SúuÏ p¡àZÀfA–Û/&WÃÌùiZt‰/Bƒ =]T>#F7B¶9Öˆx;b2af³EÒ’z‡–ü©¿€Rb¶OêØÒ<Ýv½I/»5gr§Ì& ½v÷f³6κ•˜ípÕõˆPV!Ý| Åï$¶dÆúuuÝ?\þÐÙ’?_w­ÝgÛv«öeuEðõ^ôTñIæÿ^ßRýeòÒešÏî wmNÎ|²ö/_t°™Ø”HÛäõaHz#!¡µ.9†ŒõÿC³acƒ}ÑGÃÚÑ\Wd1·­ü×?“ˆJW•Òq†Œv„™øÎ˜iUO#|+r¥¿óib÷³âó²’€€Æ¬wå¥|ûG>rCŽ®^("óJ/|EZ¬ô-F9í¦$%Ò:|„[æÑ« ˜;~ñë×0Oˆ\ƒuÿkG[W^Dh,Ëêa>Ú`o@¼‡hê’•¶Óövœ §7‹0"jC<”àVz…5h*;,Wؤ™¥Ú¶"(è29žÂA»Z=7ÐiKÊUÿ¼³:#)7ç!Ú ¡¥=D|Pôô·µ-¬€juTW^YüB‹xö. ›34¾òT Yß·ªžÁ#êBȱÐ]p-Ïê…kÿL_z:æµMC;¥Ê~ìXå¹Ó“~ª>iÙ²«LÑØØ­5å ¨>²&ïJ†&sT¥=bucOÚ@)K|‡(õ¡£6“ïeVv“™nÓ£úÎþz ¶²þò<Ã\KÁQ(Ì罹 íí*8Qñå{0ŒÑÛœFöŽä‚sŽ Î†® ïÄ,£þm.&òØ{d]¦|Ž §Ë-$­ |"7†Ïî–FÛtܵ`2ˆÞðm¹»j=¸7»Ú=’yr™&q"ƒË ÒbФ±h¹xã€bò¤ùm±•F2âCV±“ü¶ï:$bƒVX-g̶©5} \t«cB6;D 5ä˻څ‘ÏùT¼® A×PwL ¿½ÐÀ¼¢M³·w>°,Â2Ë5ÉIc{(îK5—@îú‰'·½Ú5<Ø‚jŠ?ôt8ã›k¡ýuUòöW}°Í4³@_ÁY÷êÇzÖ‹Œ· 9bˆ‡ò žÙ5ÝHÔÏò·Ô^ùÞáÀ'ÞKÚÑs­#T¾çUÇpyE±ào ü2i©•”þ»rzŠv…â–mçxff„¬Í6\6ã‘)튃S©ïé5K£®!ðÏÿgø‚ô'[ñËh_æ_›ƒó¿Á§pM–HÁÍ‹`ÅNÓÈR”ÍÂÙ&‚ÿmh-;#™ÂIU\,C Zÿ³dM eTžq«^)80³l8O~×h6£¢'Hë¼aQ§ê–S´%˜–]+×볎íólkIó`„­ÆmžÒp+&Óc±ò[®ºF€Z2É¡“þrš^ž„t?úššN'ŸzÏ ER¦&ìß+ü¾÷º’€€¡¤Uq@ÖŸ$Ñü¹nQ—‹ÏUñÙ›º-ÄegŠÈ‡ŠˆB§é FÕ›Q*Èóò(¡Yœ|±ûrî5n¹C?+#ýCÜš) žPëB @(´÷ÇÀ$»¡¦ŸdÎu¥|”X~òú?ðOÛ—D•±wI "Š"p8Ó´ï³ù|MöÐbÑW‹Ð1±p 7ˆÁ%¢³øT)/.C7‘Ë|`1p ¸èQëøìö3;ÐL‘NÓíÂÐ`±ÞÝ×JÀ꺻JÑpægs’$ÕÌ÷Ú²Ñéd¾^„ué°ê>*À(Ó®^‡wGмóÛüTßRÐËKöWËU~ç6ÿÙ¼d¾ˆf¢ÌsŽT‚ǵ‘œÐÑh‚üå$öN¸oòcëU6®x§4€nÉÅ.<ßlȱWiZõÒÿú¡4–FV©SpÏGm?êOÜbì?V—ò¯¾`ÖmH=ùÕ¹?i£Tçgç0ZHUN³Òmc Vh“K#·vc¿Ì «`òÍ ×ó~Ø×ZdßBd]ð°+ÞG=í) '¡¿@i-6ñd¡8q­€¬ÜZÿ輊¡ŽêáÊŽ|úüPÎp  D´T•ßURš†QŠ9¬ÒdZ!W…®J"Z±T E‹]¢eÒ_üNÁ#9¿%ôkóØÔ³/5Ñ8Ã~ºâ£KÞÖÙ.n·ØkP»­´qššJ>ÿÃhuÀõÌó*úåY¶Èã7”Ù£îKÂþ«¥†mé_d`&@°ŠIænp9ƒœ†  Ük/`ü­ýn©M¾~«¸Äü½Ö®kYs¢}ýçSÞ-Á‚äµS;®(ÞuÅÈ=üz ’à~Æ}sRC4·ZÓçR2†ÈKžŒÕ™P£ºjž0C88+ñ­Âp3¤Á±æ¤X=á³~Á3°ÒzA.õ¶}Õ´À\ºÞ|“ˆx-’È>Ë2},†ÉûI«!¿´L™Pü7Wûñú– dÙÕÌCãɉBMVy9îÕì‹ks‹þC-R¤À‡Ãõ–-ôS¦nòì{Ø„/d±ü·ŸÙàä5cºÀr¿0¿ù%S˜/oXŽê9 jࡵ·Yy€VP"ë)F!jâ8g÷ʵ Vðô5ÃFhl-C|µSœÄÈt¤¡ˆ4l$,§¬P꽑d}Ù_’€€Æ@þõ~micöbCüe`1›r}}¼­äÈR³@Fq7¸ôŸPåð]ÿ:{V_}B)˜‹£>8vz|/¿÷:„R­€<ˆŽU]¯˜­}¨ó}!èëérixø5øKßl<:Ih ãÚ•·±lÑ3X$ÎM³†ó›Nnº\ øý¿}˜/ 8}1üø*Qaƒù,/ÖîC%K8†Îi,`mV>êQÏúeV°¼e/ù½?¯épZAr¿DKµ:ó®1™^Æ>5UKHö5{ ܼëXšÞ>%¨vζ¼­½ÊPpóÙBìñüëÆ5ôo:”Â9¢= ©µîG C>ÇnhšZ@løEôµž¼¢SЦËÔˆîI^Ìt~B/‡..,õ¬¡»Pmñ˜ZXÈOfYE|LÈW5¥{;k‘Y„Òý„`–Ø£åp£ cuÊI¬A|#y=;ZÈyŸøCmOÃÁ GrúR>–@qÙ5vÙÇL^ZE‹¾³‰uˆ¶‚û0‰²9®eDè¥ÍoùcÎ)us>¼Ì±ªû3j×ðnÍTž ÜKKäéLM߱б(5m±Â2Jk-ùÛ ’(mÍœ^§tÀ>hã¹:à b£’éódÜ05§Ê\ì^ò#N¦î5+»ðòŠF¬"Oœñ$ 2Á û[¢D>ÍÞÞÏWÚ½Ê|F‘m­ç‘Ðg²óf½šŒÝ4jQ¸Z=Qst‰­ãÁÈJÄŸ^ãµ­„RI#ó„TmAu?12y¾hÞ¬S™Ë"÷¥ÿy:^\’K JªÔ*;'„õ?Š®„ôµ•.ÕØ/å?¦'|@$&qd§6©Û©¾ChšÚ%[«¼ºvþ¶Ã¥ •×!k Õ`¸1ò\$в”qÕnL;+$P’€€Îta¦Ë=ÁE–ôG_,ÜÁûœûzÚº‘DmϯðQ!]ÙBñí&õV\Ícì]í[·óàjC?áyh´ìÊ?#b™¦ög@]­1J¿È‘…[ú.udìkîû寢óÀïó” üÍœ[`ô…i0W§\qöq4|),¼ …ÂWÔ¢ËÌœ» Ìäw.°¡1ºfy`æSð}‘ Û¥…‡þRK<ë ÄÌláïñò±°É×!V"Î:7‰«¶Ã‘õ l³‡% _†® b_åsÆä”þkAö±t‡ ™/3.©ƒ6§jüø©™½ap½ÖÇ,‘jˆAåÌ|cëry‹_{àXšJLºL5o¸1:‡¬ÎJ¾w³½Ï~Êe˜=v±°t²ÿÜëâ×>ÝÍ8 yŽÄAPCýKQ½„°ù*QÊP?rÁß<‰‚†þɼp_N¥¨jn1Onq6ûõ3o!R7{™ó%¯ÏçéE L–ºÄ³Õã˜@ À ©Ü©«f¬ÆxØü¥wpï '°Z>{Ÿ Vy7‘ñ¼ì;7J6eG:fÆÜM´}öK{í`æR5­9ªDHóœ¶ .lÅ,Ü»jgXm1¤ñ’xXä¼ :KCŸÇå+±é¾VJÀ u’€€ì•*ó%ªE€9>{ë¾gçTÀxb™§†ýSÈi¶8í@:ªhµ±Œgq/ó,“Ÿ?˜&1^C5µzV\¨Ðê`Uï ]óÚí ÔaJ•ØC–37ޏö5«*ܱÄÐ$„7R Ü…¾7Z…g’òV™bO[Lö»¹ ãK€‰-4myMÅYÐÖCª[¥ÞÍ'~HfAß‹p—¦¾™é»A\„ß:„eR =‡‹?¼0±+-ó'ìÙ2"!?Ì f£[¿Þ—5Dv:÷2ý©àg#(ž¢WšÐ G<)"Xg{¹/ubPÍÓ¹K^áûr®j(i”Ã[ Z"·£²½£×\§.gZ§û !5š%ʬ½þiÇB ¥T¾¯hÀ @€b¶EƒÆß‚Gw¥ K6µ‡dYàKSÍ¡<~ËØK•$·]xÃüÞýE>‡„æTñõ-*µˆþBRãWÎ8ÞÕ*u *G8?°‡;lœ9Q…3ÝôÃ(ᬠçƒX=žþÚPÝ6ëº>ƒàMV|!|WQõ\wãî¬Òv bL«Uö^wËÀ%|ê$^z ÃHSê§õÏ¥¹™Rqr{SòjŠà(,V~§QÇüTg^ ƘÆSúóÕ¯pƒÇRñf•åç>…}нçHŽ·zrí¤ {èýŽšÔ½…ÿ÷w¿à¾m7h Ì¹Œ¾jö%–âÞ´ðÆ>nB B»~eO-EÚüWÛï” ÞúÉÿT)·yT@mßc–Íàl>W»CýKj±lh´ºÆk¤ôá3þ6näã½ÈÑá_àfz†äîí¤,ÝΧSŒÿ'¹]‚jn6ÕYà6T—'›C^2÷ûb’äúQ>t!¸œ°®ô_¡B+ììÌH#G¬k3u}îQ°ZZˆ9êÛ×^-‹÷Ætƒ‚ ¥éRžNgŸ¾Tœ]èí§lHxïæpPB%šË…|ûS½€à”ØåE‚º÷æAËòjÆ$м4%jÊÙ`¾?æ}Ï¡z2KÏðw(’Lb?Z¾:@!^~àÆ0yŠ`RI¨Û¿ZÙWVþÛ‘)£×»˜_3«rŽ_ûÆÙ]ÀØêÈËfõLq™BéBKO,šeXHŸ+-÷$:ØeÇ¥â¸]ÀvݦCÛŽ•ùfáã——Å .hXiÕ%툯ùÙ ïÚoöAßg^Õeb^»h³ìðkžÔMÆ9ÎK]’ îä`gaïÕAy¢ø0¶Œ¥lA°Ð?rO7+ºG®pî½ó&*3è!êÚr±mÛÒtå¬òHô©$‡[ik¼pÀ¨âEíÄ:ÁDkFÑÑÿolí:á>-äÚ׊Xg$•8µœÀ­tø |©§ŠiºÚr_çê9PùnµJŸC)™Ÿ¡sÝè êÞ ¡À·*ŒÛ 4ÆÿK¡Ã>LJ$;Ó ¢„@÷Ì9j€Ò®´;ÜQÅcÍ£“gÀ­ 5–æL?D£Ìßéq±|%b¯µCŒaç|édjKÄ{<ÊÕà¯çã H8[Y¾?n5¯?üwxÍRŸF˜;åáp#ªQ.*’²*0¢fªûf^T®ß©Ãu«ö do«Ã>=ÒnÀÏ!4qÒÞ„»M¡ÏG¡@e&kÝ?l Vƒ~~«R¨fasüÚÀãÌ(-!ÕÚÜÆ#d’€€ž€á1ÎõÛÉ¥àE"<4Fm”¹Qp€ ²„L•ðyž-ô”ŒCa4›ñÂ&±i¶-#• šbºôÐÿ±aÄT»-\]ÚI÷ñ sÜøÎK¾¾"§:h=î–E_zf Xäê50ÛÈ=¨ÿ7D\yæ£q8ð£)¹YÝíÌÙì½ëCn挠{ í-:åc(©¿Ïozày³}OÍÙlõ›=¾Ó|XÙºÍ\¤çh˜äÐÉ<ë·/=á*+­û{Hz”WÄ#9À{žÐ! ý|2+@AP>E_ædFP~e“ƒQsÏíùy6õIž¿õ^)N—IGÙ ‘aE±y5¡Üýg’– "m Zom–Gænñe™tQ»y`ÛD7NŒÀØû®b”ïê± ×°†ª©’…Ö—8ÔH$ØÿžbûšnG;:JoŸšG1jZ²ùvŒŠDÿc.Äo ­Æf/¶NQ½ªz,o¥Ó¡¿G"_àœ”à݈âÂóT3Ì[°³}ïá›x««ú±xIÜÙä£`¡ŸtÕòùÛôßÛB”b]ŒvÓ<½â¹8'kÃÞÉê3¹ºx5 ñÅ \>®j-]‡’_RvšÓ\Ÿ‰m‹ö±Â³DxªªV@´aq]‹k ÄQLeß}gõǼ,M¼÷Ù²wÊoßN¾d»ÆŽI9\£— MìFÐT@dª,¸Õ$ÜàK*½v»@>s\]üå;¤9€øgi( þa‰aà(êÄl<£˜/þ뺶h©9€·ܳ0.Î5Ëû H¢J€r·þf3^ÿ*CÙWrÕ˜°úæ§L÷Q[Ôß‘k”ÌöQ6»­õòw¡\d¬ïn”>üO-­QD[ô£‡R{Xç::0Ü¥tÿ®tûg=5Óèª[S­É6ä$_0e[B Õ-V ÓeÒÆ_YE6ý6Ž’€€Á© §¿YæÕKÛ ˆ!ŽJtS1I6î]æ¤Æt_yxÉ+!sŽèˆ{™{¢­¶¬!S³j°ÐxïùþâPÂ.À|'H,e†™b *Ä$^^‡Õu¥N¤Üã/Ó,õnQÙ+zÙ€û–`¼ÜEÕúÕ¯ó ñÁ-ã’Öœ´®WpýpÚà8È0xpîÖ‘±@}ãgᡜ>ˆ˜¡)ENV-í»ù[oc*ÉyWÃßn“¦¨9¬“öu#¶V— ñç·3høãÄd ×…8‰-!ä×\ðÐô¢8DGê(GBјœÐˆµó„ág(áÜ“‰ê®Ìo%Là¡<²Í 0ÔCF²Ê9,QÄP&øßä´(7I,Ð ÚûûÜE°œrÛIªëæbŸ‘|ìbÿ<Ýy$ºâ©`×*{Vw*\L)ð8Œ`§—¯”1ñï­3WíÖÃ/& UÒ9™ásôLÁ®öm*V‰v»àåA}\×uàê4r³,Ëg¾õŸ8é¬1åãB§×Õa xÄAc•4uï8¤p„Áý¤ˆRxš3sÃŽ˜Ì¨#G’,°^Æ­wp“kQBõÎ~ü÷ºÕ'õª~ëäÿ¢½˜ÕKÐnóÂíB\[Ü9®/NÙò×Î (tÓgßÈqæüΓÊ!"#wœ^»0A“}Z¢F ‚íÿ¼ýYÊÑJûϽTƒ¼`ßÉÚòÑay ϲ~y\ÿÈ:¤¥ÞáÐxÏe8Ïf®, ᪿÝ€üˆDšÕþ wÕŸãve3 ó*Ë8Ä›xzÿ!j´Z~ïÇ;ÎY™Q¨'~¨øÔ1Ö¡qq¶î´×ø%¶>é®Ó}‚<›?–·a§ˆés@°ãºoäD¨)H_K—å(egâÀÎͽ5{XSú l+Ïi ‰ŸµÏƒ/2n‚i<£ÞaMGmQ ¦ü¸ÕÞ ½vyú_’2Ã/&ȤÏbd¡¾<ÐÑLˆ`‹…KIˇJtœ¢Ÿ«©a_ÿÏ$“F «]¥™ îX='¹É‡÷¥ˆ‹óòZ°hNÅd1ã¦23~1ŸËO‡4Yî5´ÔmλŒlT^ñW»;‹ }D—­1S-Løë™,CuNv¢ŸÐªI¾Ž.‹G¢‡'³iql˜uõ¿CÞÞ½YÊ’€€“”x–8CΔ\袙—UUÇòW<‹¸{×üäl”¡¯rmÔˆfo³Ó1¡CKù^¹Š÷N@¼M‡ªÙKؼ@ÁjäŒÙ!ùàKï!ßL¿ÆyJýM&uMÅiÜû½ˆdtlX’ÆòQðLÇ3º}XókY¹ƒýwLÐí d€"D½£3?Ó©8žQ6¿Ç‡„>Fd""i¥r$ ·¬lyw¿a åqž½,ô°ÙC£¾¨ÔÆ÷paH‰¢šV“ÕB¸’©öEHÖ|_§ßV‘‡ÜÜMËâ Äì_¸§37Ÿ.üûTÊ…!¨®|ß(öõBt?åÔ.†ÍßmÝ:ÇÏg¾F©­”"r®½áb=m0š£×µ|’Ó»ŸÜö¶!;顏ֿ_EBZ‹®MX6GwÀóëÂPÆ´Œ3èVšÇDߟ×Læ9Xäñ¡Q»“O*?’€¯ÛIcð §¶Pé°´ ô'N€Ã¥¬¸€h;©¯'æÈ}36Ee*0"¸ÜÙŠº–ë/@ס«–ië½*Õ1;3³Ó[ ŽI}®61ǦÈ«N pï/-fž(q’6–QûªÅn*›ž‹¶E¸Ñ©/š–Ê ‡Ê”M™fG\ ½¶aü†ôüÆx ¨áÚÆ9ö&ª m²„ê4^OPÀ‘½Äw=Êyãc‡›jÊ‘•`†1æ@oƒ·š` ¾¤+!E‹Ò -õ¥˜øŒãÕÅ%ÕîEì¹y½uÒJùÕ—eà$å6ì¤7„ïAæGÇLÕè³÷·yQ®Ð‡G쌞8õDfn-œâÅ¿`ÅD&ôF’ÈÖ¼h!µ!ªÄD£ÿ½ÀLîïï$$ÒS€EP42ãîVÇDéj³ÁùR`uÓ@›Œ¡«qÖàžv]ÊYï{æö½¼-ïU… Í;\,üä¢!Áfq-,²Ó~Î4ù º”;1nd_ `Õþ_íø¥CÑ,²8¸Ù=ˆ…Éõª¥¹ù ¿pfÝßãÙ)£ôûƒª.Å{‘·µ}YB"e†ña Þ~Z°É+dAŠ1Ê·ds¥ù”[V8má/‹áéË3ùê­zÀ)VzVc¥j¤aóK'%À|ÝçíÅ€x«°;#»VCÁ¯ GuË 7¬„rË$žrþˆi¿ïpI dláü’7½è§º=âùBvG6‘ˆ’€€¾ÆßŠm%@ §1’ËqWs²D'ªô„(€áÖ¶ˆÊöJFïiCíÄe‡:Yâwh¾Ö`P"ˆñàõ‡ÄPw6ÁPÏCøùºñêz"Õ Û°÷üÆÉÍèCt©rvG•’Ã!Ííó?ÓëºÆÄð"‡LfË—‘O*X”%xÞŽžð†rR¾G+Ê8DÍÚ~r]T¸ %š?àoö;sØ‹ê©Aùáïb‰y³jýª?HáæQR”F ¥w„½“ ò¯Ã?€à )§Ðò[²ÀxÏ=êö*0¦&ˆ²²R3¬@äçvJx‰mƒ„–Á|<ƒ:8Õ˜ÇwdÜYÇÜé;ý#B£ÖXçßêšÿ5·Ã² @7\I%9L7²%M#+´DdNy¯¼KÎÏ!´âqƪxq2l«É¶NÒ‚À0.~`½Vn|¯Ÿ—Ö&Dç ÇöçU1Ìù­kÊé×^ ÊçOôÎ*Vƒ5¿y¢v)Ñ (]Z.gÊÖŠ_¸p•Vé—Žk6óúe=“çy>6ßÅS/f?Ü–¥¥Eº·î$×›©Åç’bþיǞo"tÎ>Á·°¿ŒTye ý¼îå']_ÃÇû•Ÿö\ÞÄ’€€À :?1;|!;&âY5¤OA|L<ýÏŒ¿öË… N?ØT÷¾Ðžn>¥ î_ß,c‘M=ÔïËc;:%ûÛº`1F ª)uet+™ÙÒpÐîòSšìÕã,-¬Ù` %0äÎôÞ»™}çfÙêFC›Pù-´O å÷ý±†ût¥¯ßÛ“%‹/lï%÷bà‡p:å®Í¢f…âÓ…çKªúàØŽ­Z‡ZãEãn¾Æ„'{R_…´Ö'‚3lAü®wÿÐ˪º†Îoc³:ð å11á4¢|™5¿vuäÁc'ë¾µå/mÔű¶ÄT ·1¢xnlÍPfì¶¡Q¿‹$£¹ÈXÃR?»3› ƒ-N‹o·¤tÍ q¾}ቜo„ }$ñ^Ô@û¹›v#ñöô‘¬óŠ:§‰A]5 sI1ƒNbn&áHŽ9ÿ\eÉ‹©èZÞ›-9 } JHÎ|𺠙¤H‰Ìbõ¥`]X:µƒ†ØúuMÓÌaKk‹ þ#¼aùèn!i1îž;„üM:ÈóÒ’ƒ\ —/ Œ!Ñîaúº1Îbo£ßýyÚ‚­pßÒæø¿§ªkªò£sðô¾Ĉä SävÙÂ6íýc‹¥l½nú¨$váì/)5v¶s±öËT¨u wj—šŒAóì8RÅÙî¿x¥¨êæÆó‘öëq1çÝņؙ=ž º Z÷dÒ­Ò°Úú¾#ÝzUšªn¾*PpO 2%ÊFÓôͿʬܮ£<9].Sü!|±·Öç3¯.¢³¿Å’بÆâ®n˜ ….ªs‘Ù’ÝaµÃßÝ™ç=¯Â:|˜¦¦:«å+KýƒP“yí¢&˜+ŒÁû•–~ÁÉ1”øÒ­&…€K_D‘žE§À»gPUl3ï_`®™§#cñÄòUè¦ñБöDàB‘¼’€€ã-ðïè Ž"qAq¾DúÇÆs¼–Ùó`:ã~t¤e.pæ[ùê"bÈœzo*6º¨;nWZç>¯“uqÆ››ÛÏhhsD/•ËSÜh”¡ì<]F­'ý.€D7ñŸNýót©>rQ¥wäotk3´X$Ì+ÿB…oVPTmûzÿa;Ǧû42 pY!³´Ëè¡k‰èøñ"‚pòÌüÊy0e/ðüKãV@ÊôÊúÍzÃT\|” TìÙd¡ÀÛÓW8&.ØÍK÷ùÄÆœ’Cv|(A¢ï`cxÅW£E$i–\FfL–t¡~ó ÄѾ¤6prˈ1£2]zÚè‚•'}¿í€O;fµ•w@ÄÚO9f#íèÚÔi'Û‡U\œbîñ.Mùvq£Œû—&剛JÊ;³ãXäT°âOìNê‚k±ýÇÎ1 !j ôš´`ã±hØ‘·Hï=¶K»mÓ.™æêÞþNà»ùþÕYÌñQ¯p¾ÿ€æã¢VX Küf°Ô• þYâVJ§!‚ù%|'ŠjˆRÏÍçý"6å’¸=6èà‘åkxçÃêîœC0nV*”"1;e¸íü17–´òTA×<ÂÒŠè%~$É‚^Œ€è+>Ü´Ü¢@è¼±ØÓoú.|3aÀx(ã‰QyÌÍõeü5lSZ l”®Þ!ó÷^º³Q~v]—-è.ÊÎòûwÀü ”K0·ËP*•—~2ÉòuœøŸt;q^3¼(²ë$œu«fü{$4—³ó]5¿5ç20JE•](Þ{œZm¥ó+ †ª'¨z&‚ÑRsœö–%¥ìþv"Ú¶1툲€>ñe 1t,}]ÂEWZ‚@£¦ÕŽ ĬýÉ2‘T³›h¹ ±ø ˆ`xÛÊl³àêE´»`»Ìœ¿}(YX®¦¤…é:­(¨Ä2fÌâàœÜ~õ_­ÛÏ3ù&ïâÍz¢Ü)ß OžJýŒ®ù°¢óí¯ƒlîK±Òè«M÷Éã­¤Kx”™9Êr>¡4?Y‘†«uR7"T[³Õ@èŒïïX©ž6%yê š”¹¢Ð—é+ädƒ£/û Þ’¢º¿òç.ò³>¥†s¹I#P³i¾&6³»²Àÿ¡T¯ÿ,×ÛBÍñ=ø5Hšïï’€€ÚPBFìžfSFƒaEOC¼UNLÔ9kÝPs gÈ‘ý£íˆoÇ ±ðÅ£ÞÈ=¬Õ’ãì´T[©ºJGî3K[†ãtWÈlëaÜQËÍÊÆ†Kˆ%ML­Gá8º1ºqÃû=ùÕ¶¯8 ®Z¤¬x­eûY?Â%þE„>VâöP(Üÿy´bd±H/¾m¢ˆŒ¶dz4½Àþª™Ø?y6†ä\MW,“šL`QCúAN1VGŒ:ÄÎÆ°k0>kÃ?€õRÁ<|M~¢§C†øoV©p5º2]ŒŠEÈÜÀœa¯ƒ¤VòhŸøZÝÕýYØØ~ÊZñ¶Ã$&|ÿ9ØÅߌçñÙ~`¡G€ Ÿ9F0©†OCœ@`d“Tr¬%ÖÁ#`J²Êar‘ûÿxÇê¯`ãÌ÷ĨSzµòˆËr¿“ÈæÝntÓgaË&øB~`vì]Âð ž3ùfâÐÙ”)^iWm†Zmz.vÕ…ÃduÇ„°íKtN¨oŸ‹ùÂõ¯wØjQæÖ%tÁïàjת¬\A¿4ëTºfí£ülÍpÆ ±û}×ï¹€HÉVy@î凢–¹³Y÷jz9–5 !HDÐMsÂr[‰ËŽe&Ű[Nj ÇÒMÔi¾Ø™Úêߪ(7f]Ó–ùüZíï¼æê]kÚƒý½Z#p‰®4ßLULes}$ œTÐÕ[ÎæÃ»_vTU&ý­O"íÆõEñÂzÊ[”ÊÏnÏËÏÕF0ÜÐÀYˆØ«g½^vuÑ:¾ÿtæ—Û½’ówNéèàöX´¹ÐÂm}wù Ü-xÃéQgtŒ+WNaê韜[FèÙåRÐhD{]@@¤všrù^½ø¨Üî~ æP5'àñ‡(GuBèD >óv×ȸ‹÷.=7Š&â)n z³F¶zAB@eZä:$[¡÷²ç¨»x 8F.*½OŽžeò –å‹"”™=̵a“ ¢¦Z Õ‚¹[ÌvðÄ‹ €:ÛN‹ ÔR=ÿxw{žëK‰ñªÇjó¯<â‡ñ‹†Èu® ÛfîÝvÎÅ犯/×É}“ö–™§Àt“Ž*o+¸bâUçØ¸'«xOýQÄîôLUùýãÄÿæoâûv"Íì’€€¼ÇhÍès‰?¦ Xj3¼8b»ŠW?Ôb-°•-Ö¥ ¹în×b:¤R–çÖ™Ä`늷i—£‰}ƒ‰§ôi)Ë-¯]cg»"©Ï“r×`/o¼œ/ž‚Ì ¦?ß×ßßW«?õÛ”×–é׫›Ö€Þ62U kLö4þéigšy¤Œ,¥}wIÁ'UGâü׉,F3¼ù¾¥A4¨°Â7*iFêdAðÝÐxk¾9¬à´~­rûØMU`Œ$Ý ï‚‰R4>m/©:äNP*ÀçÚ…|ФR‹_+®avØŽš{“/eO=ìJ15ž´¦³Ž§J0ZN 1„{c~h@ýöŒßO{5,ÙÑ £´´¦kOª È̼ºïº¡Ío}ö¯¬ûÏÛ©”ïõYéƒô(TÃíB•€]Eg—M´ ®J§ìR¦ïÈ¢a9IÍÉiæE‡ 2ÌÔ|®/Mã;¹—^B•Kýèlð&®³Ä@³{ŽÔLµ“ö=¿ŽædY_r¨’½ÞÒF¬ƒfŠ©.S)Ñ0M¿Çº—7—zí€XKÔÛšêl-ô¶¾ßíj²Í…Á$3Ü3̼NÙ3=3Þã~Àá r2C`Ç $n BŽ{ÈìVxŸ^‘˜ä•'5qÁ¦q6‰õ1^æø~.*¹Qjã|CÌþö[@³E?ÐŽrafQA;3èlV'ÔN]ŸÚMþŒkõ5 Ç«¬$½Îþ21ÄÿZõ¥Ð|ùvïv;<Æp‚ht:Šê÷AYr«"Ñ+ÖΈ{?‘`×Õ𓊹eBHE³"irÔT?Ï´»½Ä»Å% bja06H?²<|¼wmR€³íå‡@•åÃñ#·J´°þŠe€À„›¿?G†Uo –pŽsÿûF×§íbGO<“~ÍDp·’,ö4­ÿ©‰!0½hÈD/«Ã’®U›§I#÷'rº®ì”"㥔1”Œ5ªAÊlÍ?x1³k,¢ q½FE¬´ƒ0‹Ãi–á×GÝ:À00Ó"bvuÖWì„ìª"u?™ œßw#÷QÕØ)ßGƒ iˆDí—\‚½u £øæ¬ŧ²•¢Á¬öÆuá¦=)“õSr]Ljyž§X›Ì÷*ƒ§}G)q{™’€€½©à\àEvî³@b¨é?WþeÄï•Þàz0«‡£>£àeüø‘&_¥Gûd‰*8*3’¬á¿yÓþtq¤Ñã×6hê'ÿgƒ"d{w=÷Ý´ÖË8c-Î'¿â j¾ ™Õ¿HgÀÀí×&@ j'{`[C•*Æãhè; ‰S%,í`ÄŠI€»ÔÚBújz[YäÇ^ _mäB|âp£_­\™:K[r±Ë낎{Öß$[o™c¹PHGÝ7€ ÐÇÍ´'9ö3ÜŠ#A)Dƒà ƒ7$ØŠ_{"®.% Ž÷³wðÉëçòu,öÂ’ý!P¬{º$IÊÄáÝж±!øÆSðþnVàÇ®…ÆÂ‚RtH#Ó¦s9páòõô>²%Çü†Ôß~艫 –3ýLĬ(g1’+m¨\Î7¶ˆZv*™E´ Ò‘àH+¶ÚUdàå dTæŸ8 Y 9%îí°{|ýYîïJÇg’¸ÞMÚä®(îbQ]6Fu¸/' 8`ºlN qm±ñsº?×ÛH­A´‹ñJaN w?~ž¬Ål%glN,Yp‹£[¼òjÒâ¦ßÿÀ‚8.±¨$wÑpÃ^E‚Vy(¡Ïã\Ο³ï%ˆ«5ˆù%­N;_~«¸µÀÌbñOákKÒ¤­*Óä[Á| %Ä9•­vä®…Ú™cå£ú¬/(è›ÆòS|k#YiowhÁûL$ÿ¥ŽÎÞN» Œ c9K¸æˆ)V•úÕïgߪõ§Ë‚$³êzš“ãrÔEªy´3< ý9„TvW7íñŽ“aÚ•:Î’€€ÄÞK¦Þ»µ±µzªìf¹\]|ˆã¿ÆÀüáŸ/Z‹y( ¬°³]J(Ô ÒÜã?„X¤œÆ|ÇM•wO8ö²–·p IlGˆà4ïGcÇÂ4qPJÒuStÜG¨{¦‹ŽÁ¢ú¸ kó{$y_8›÷̆Ã(¬jÂÔ$tœp"ïu'¸â_iK5Ê¢¿ÉÖKH0u²,²û³³ôKJçùü(H™!¨T1Qxž’æÅ+¶YKC(ñÛš(k‡õz2gàô_v_ç5ï×ý'r'c¦ÑWM&{±<À,e¿ñnw‘£1’·°éz]r×-ÊW™Ìï0)E–t  ³öj{é`GØwš0,ßļ€ g2ôà«Ía•R¨‰W^çßò¡1õ$t¯‡…ôxÒ_wCNœßU€—ù’¢L°/A,#Ì0gÞãÑC5–2 ‚)JHŸÎB%§¹§Å]ø½dýEƒÑÖ-–8hº`.Õu³ek\r¥â1nÊÚi×<æQ ¨ù‡RŠLî~§³cC•KöË„¯ã댪¯I•«ÂBI#ÀÏn¢“ü>cLjÛÏÀ î>h%È}eJ˜O¥úÞ„O ‰‚Pa>ô{¤„f4€.ð<—W&R9ª==}S³Í±?ݦ‹×…ÙQY áÿ?'Ð7u)ÍÂ;¦1Á3¸µà¹|T(Ù„¡ ›„Þƒ/¨+5^†¯bz£˜>nE‡®O>ð\v hš²ð=’¸•j–ª ³ ÿ© ÀMãƒ3›~Ñ„«èŒ4վг h«ùûÂsQeµI§³ï¦›4°á}GšûUrþQ×»ôèæò¢YÖµ‘åÜd३^ äÐ-˜®õ£*ozgàë`.ÿ~åCŸ3*¦ßƒsøãuÀU¶2ÓÀãD¶Ä׫ sW^©‚ðxpD°_üÔÐ@oCÕÐí•Xvh³–0Œ ¿Ñ=šZ½¹ýŸ¾â0Õ Ö+M¶Ò˜ŸFf<»œ…-Þ&<—¤07Ýþè(ñ5ÓµMs-)wöì@ÊZ¬æCÍ–®Æ¹“vjȧ%˜ß{kSØúRòW×`–”¶É>ªpÞ’«ÁzΪÊÓióÁŸ’ž«ò“Ë«·Ù¯î…5Û£]ÕÞüÔÝì.»o£JsƸ“Ûi)áãCåh? I÷ ÝDwo†¨WZ-¡¼ÒýqÜ s‰èpÄ2%ÙÆdá΢cG¹‘DÍaHÍ‚ k @F™‰eµRÒ[¤UÜv9´ ·TÞÔÓŒê ÝR£ÿ`Çî·ØiƒpÙ÷¤f< Î|ÉS)dïv!@f†¢lù¾ ì8k4Òøfž¿J¼zȦå~¨ð&þ˜c'E·¼NOÜ×ìŒS«9“~Í÷ØIXñdÑ8×é.®Xú-sa)ô+”ƒ+6ÄçD73ïL2äô¹«´!ÅÊh?F{× HÐ:G•4¨4C0{âB8eFGð ŸÍÈ\ZRþŒ¶Ò•”cR;žv›'TX#~×Ñ„ÔæÊe>0Í]¦åüܧÍ,KÀt",á}sí¼L]5 ¦N»dòˆ)úr.Nèfè÷C]I«pa=vGjSœŠÝû£Ú2B’SÙö¢m”ß.~bÔÜÎÔŠ¨YzüsýíE%ˆ¹ —ºT?N‚>þ Æ•Ùt`F|›p?}½[÷Ë L²CTtm&q‹l*:0_‹ºƒ_£[/[S ÄGüžìË’€€¥s½F„—;éТ¡ŽÃ@#AÞâ9úç/Mëƒ2.}Eƒd-@¥U2ÜHV•Ž`ZÝ&ºvØ@¥j®#Ï“øþk¿ÁåmBõg¾†ƒ=œ(éÍÂgßžLíFÿ-ŽûÖH¼Þ!ãÕ˜Krnj“Þ=ÞvÄ€Hë&G¿p;  ž›¢þמVÞÈ•ÈýEDzÜU];E•€Åáí~»„3fFÛº©õ×]0TYÞ"¢?0”G‰)utü¨þºgŒ@:ÂZ&6÷Ÿž´¡•ŸXE¶y•=súujž‚a)“¨UÚ*kIðš1„ÏÃ3‡ÒÀNn}õ!H;B{ï·ñåÒÈ\â×ø¨/‹´œ›U'ùQV• æ m2Íé¡(£˜ùRP‡j¥iÕ,JÅ/ŒÜLõxª6jü}îdjXLÃC ¡ †°ÀÆ›sô­Üª™îù†m«ˆ¢IËWJ„/mm¤Ûç¼Zmìb§…þE—4¢X¹%ü…`~ö:,×Éx¢f‚tD,¢”rŠP=¸™9E=œð´˜ª’ˆÏ‹,¤âÙpD–ò!Ñr%›Ñçô¨`Ǻãn1À¯ÚìØJ;¥.ó?Då³ô¨è”9Ø×gÇbÝQóÙ–^#‚‰§¦Õ±ÏèE[S<þWD×ì¤o¾°3ÒK®„LYÑ+~–Áª.Z¹û]¡[3†âhbѳa¹_ìÕ„Šjð'h»“‡»"ñLV߃ãŽÅyy" bk‘§{ÁëÏ«çÒÚÞüÎåø£‹xQXígõ¢,I%„êìÅσê5ø~‡ó×d ·8ö”(’”$>†Ùð!°—âC¨)Ê&Uc8ʵNñ”Phác’àÓGP¸e54›Ýe5aÌw³hjr\ŽAÀɸÇQîÄ”–aáØ‰)6U´[ÿ±ÿvŸ Ù*iÈåõpÑòrP1¡ÇA„*-ZûŒ^…ª<Ñj)¿œ£1 >Ñ›‚•ì<ô¦áÉÃCp9$uQtHwäÈŸmäã"1 -OÅŒ2a@ueï7Á.>böÓbƒ¥¤]Bnþ L}>XÅ=²æƒE¨÷vÂàéUqí:Í Á>®eKk»eécô;S©*ôo›´%8²2V÷¿À€ªHTf1}à§ ‚»ÖÌß¡fO’€€²›ÛÝpþg¶ºö±›èÓž÷Œé¯]Ò¢^â– ìª!J@D—¢+·×omÇ=Ñ·D¦\ñ¬A?ˆð:êú8Õ©îÉäÓ0“a)ÊÔ°•ëFGyŠ·x±ÖÿÓŒ_FŽ’ñå©Ý+dÂ%Ó¸ <µÄÁ—ây:€…MÖ'­¢?"ãDÒt ¨@éø¿Y iä‚ÉÛIËÒjî„Û 4uxY[9æÎNÖ%AÈUŽ…I3rR{( 6¾ÖW|¼D¯¾'Wt‚ÓÌ&žÁ¸øKµ[~Â[ð±ò]ûÌ},ȾkPxŽªê¡`ÆMß뜋»¯“»0ã9퀻"ù]8xN(. ·Íá§2fA– užÅcd€—¦[C¹@ž,òÍeÍ™bäqôÔŠ<‘Îp¥/Tâ¸QÃdÂý±(§–åN5×FªÊH®¶•Ô1þÅÆ¯µžÎ«¨êAB=tXj6ßʤW1,fýEpÚ[‘·«±B)&BÇÀ„7©9îK‰Ów†xô»íÞ W¾üû$sóÑ$ïÞt%9mØ\h ¡ºþ*¤{ú—­Oƒ$6Ç»ïîÔ¿âýrê'LÏz†’ô»p§Ïæ¹[¯Õù3ó5Zd†ôf¦“ðÃD}o51j _‚ºï½ÐúÑáÔܺÉÇ >íú}± TgîŸjõœC<9é)§ ½…ÆåÎ8r'K?—¹'_½Ô®jnÖr MÕ…§´ËלñÕĦ¼uðodHkB{r†2Â$âI´#iÉLX¾S~lQÝÄy®”â¤fus£ÜâB<Ð7£9ýîUr”º6¼á.’€€ýÕ¡5.Ê-‚”k‘‰«@²<ˆ?˜hAÊÑ*p³Fó¬ø¶­ï÷ˆ|¸ÞmÕp*…B‹Çøê%Æ\[¿‹_kæ˜.É*> ‹{⡚ÑnD‹yHfÞ;ÿqìFÛ«&†ü?'λ¿ê”ÖXWw;E’#J{O3qƒ–Ù®|×?f½;EshÞ-L2ð`±&Pbåeî~AL³eúj™Ã¢nµ˜¨*צÿ©ü+T…À&YÍÓô¶&¬¼Ï·6×½jXN4w sŽ~›14†ÿÐ%îc¯5ô0ÝäIR¸é?!¥Z(a«`;‡NR ,,ˆ˜ìD÷2ªZÎ .N¹ÕÎØÚ./‚x»7³+3U‡€Ô —,Œ˜YYæšR\§Ïÿ^ëSoȪH†³ÉU)&¦ÿ2 P†œ…|M“ƒKZèR~r‘¯Sç{Rë«Fÿÿ£›µZO)†¯]ÇÈêÙ»ÓŠ]%jfC¦ñÓõ]¨ß îG”1S¤>åÝâÀåŒia"ñâò`ì1I#qí\IBŠƒe§r ùX¤MÞ‡œuH®¿þu½ÎFÎ78†0îÊ®Y²±±åº÷Á}§MÔšI¸ðjÌ1ü2â“¢é4eÃÂÉkåR†¬YñjŒvK²3âûJQö£L‹äì¨Aµh‡´# ²Þø¬Òˆ U !-\‰— Jèä8üq¸üâãã˜WÎ>ú ´ ,un;»íÄŽW»5Ûß¾·Á.ÜÁ<¯ËM"ž :HëO˜oQD©ˆÌõ/ ¹Èÿ„1$6îáióýš^îßD^›xº¬Þ­ô/‹cØG,ê´­’j2OV3_*¯Qðrp)—*—Q!ˆGeÔ{k|áXM:g÷b#\—°BШÛÍ’€€¬T WùOõ›Rì§zP1gH„£²Ç­ÂL¼«ØDÂK¢Û.7YÒ.r»jk·•êG†(×” í!tÖŠ\ˆ@u²1<¥°&¶Ñeo¹s¸Àm| ª¸É³Ïj¶ÄEth^‹Þo SÇ¥#)Q” ¸}a¹Ž@—?4a*ÖZ6†×Æôð+ßZ"ƽRÅĨœ)<þ~ñ#g·'A•îÝuÁÖf²Ò(_? ®š²yI°T3”!+›[íC<çR›÷ža÷‰eeÀÎEïÔ{Ö^”ñ¢dŽ£;²%p«Z¯ìù›\®“ÔU¯·‰T}¦™Ÿ–Êa8¨£¥eTñþë—k~¨Ž£^ ³>Õ´½ü{}¬³.è bO4ÞÌL%ìÁËJÈRíÎe‡€i”• óå{ûx áÿlzÏ5¹¶ î@•=#33Údä¡_¼¹³î­ÕU®ÊoŒ˜yE$>Çñ£ÚʨVß³¯½ËûäÄúÃöN•î©ùZ'|wIcU̪@’€€î/쮇zŒÿEß²D9É¥„Ôë=ƒº>GþÎ++lmIiÈ#FÁ9i¤]õaü o§%è,®`,K÷º°<Ž @¨S‡@cÁSTTë:…reVÎê´H•çEÞ¬†ºã» ,C¸Ãß0'(?Þ9ç¼KO’ÿ <BVøÅ^ã0'ð’GoÅw%#~T9­p¼|*™%‘žÁ-óQžO•m&U,2 ¶°càD$(@¶ŸªfFZp©øjHÞ>¶¹&ײ>ª$v´:¤è“—!¹P}7mPC…hÛ³À@èî;G$cÍ,÷÷r³Œµþo=XâÁo /qÈõ>JEKUo\^¶¿=<ÞaÂDãéC“Îô?‰L[¢&¶vŽAIdú㫳l=¦¶ˆžU[)â{y’j¤ óH>nD蛢çš¡ºD,ÕLÞÝ ‘ü–|c72Qκ˜Þ¾™GljdBÝ⣵ðódWñMÞ¼×á­Õ$bb[nÇÎ!â‰ñ'þÔÔ[¿gSk¸DÚNdš×”‰”ŸÀ²\Ѐ9 ž'´ÙØÈ7ùÎýNS¦Æ?2 “ªqL„¸¢ 2¢*}s?«tÐ6BÀá –åণùì¬t:,ã±ÄMŠ€§ñí®íÂêSeõöª'úè_þl•Yï·mî,àB™Rf·"bjѦ0û`wõ+ã­°´ö»(|q1üEíj¼ÙñD¿þ`ªä™éØv¾ªÚÜ‚ '{/c$;4¿WÓJþˆÞƒgx#óû>ÛVŒ&‘à±èEâSŽHƒUc}ojÛð–2…á±ç¨;šY µç—ï~«’M]{â´â›•üHÜ7çŽaWˆìÂ{ýRh_K#5—‰þ|«prAÿÄFrÀ\÷Í¢•ȨÚIÓ,#‘Öì½ëX²}…y³ á;{e3aXÚ\ÕJPØ»dj? ¨Î”Âõ"4úaI¡Ä´‘jâUgDPç<ã¡eÔESåOìþ,,ƒþ «š%C–ÇÈLql,Æ[Þ~Y¶Y%Ö`ÄÃEYÆÈ ‘äºb±veu?kl9N¥à†!†O6¥7iö7‘©–ÛŽVa@L¶¹xŸøÂ2A‰7xyAñð̜ӲŠM¦u›MépLümtå°ŽAÀÚkN’€€ÂßkŒ$øü!„ù_»¹È\“<ÃºËø²¶>¹o£P¹sm]œà eíO.ÞR„q.7³Ò;¤¶›Ö#¹íN8ÜÑ3–R#Û’ n/KûNØÅ,ì²Ý­¥1ÕjyDËÐÑyáâ ÁW"¤&oÕ°ËvÌ—›a&¶à–½ÃÑòÙayÄ™µí€©gPNÕÕ VMn^ÂÛÃiJÒÍ¥'5‰ÏÕUЩ™¦ Œ«‡{÷¶|–%|Öehr°Ù¦‡_sÌû4EìÍ@± M®Õ3˜PÓÙ¦©> pä2“˧_1˜[ÌÈ_„½„HÖ(“2W7¥¡yn"QS^¼3?”+ã5ëŒ;'ÌC&ãš9¢©þ•ãnç§_¸À¤:y3É­åÊ„ ¶wŒa?^})ç+¶|Õê9©»ˆraišfޱ ÞÔMáÙ}i£|ã^²Wšeo¢Š¶†çºÊd_¤,F"yú©Ý¬?™g)@m¬îØ_WB$ß± %Ý Òë30¿¢ -—i_3‹\vàA¾X¡+PŒ\¾rê0þ©“¯ÒÎ;Èn.à-<‘!4'(âã—«ÛÂÒVÎ+Àj{3G9Óþ15Gßà=)Õ?HLœŸáLúÒ €¼Q‡$â=Òç×ú]ô‡ÉëŒe;/#j|Ôã4A : lôa™Ìi÷‚Š<'VƒŒÐš“BŽß@SsXDxbH 5Åv~„ŠJΟ‹)g“›fæà‰¹½[µjíJÔ”÷¸rÇ…Ê7žƒg7pv…Ú(V¸#àÂÂ#aq^#€ýÖ76k†ü^Ÿ ÞíBöÛÓˬK˜H]Èû¢ñ[҄ʼnݭ×B%7½€›Ç&­ËÖ½v~z¼…YfFt-à¼\CZç8%9ä†òT³øl&ñ™‚߆À“\ZÀzÞ:ãiõ"™åñRo¯Ù·4 ã‹R2Ç£êhµé¹Ïø·Áè)if[¤Wgêt¾S‘„Ý•–>ߪ鄹+Ü%nê9; f|HϨº-]ørÊC®„æø,A5K_—¥®éƒ¬ Ù!ç&v>ÉZr½ð§ [sÔv~rêbÙÑÐ4Áò;Ïû_»ŠÛOX˜´ùŠø>©¾8·yÖóÝÌ} (e…7ÊÍ¢¨L ±l¡³:Õ8 ÁªKôò-Æ8é÷U2//ÐaåÄÛÑ•ÑÄmÛò´QB|ÔsÇ®ö¡ÔÓ/³›kŠsÀéE­Éa ›8Ù¥]{–q¢œö&`ÝyÒ6–“;ž€I¢*_\¼Êüe;Œ‹ß â;:¢å\Xû—wy‘ëD8¬eƆ«ÅKMòÞT§È‘ Zdñ‘šÛºoþ‹Ô,£¥ÑÏ€9œÎªáé&h{óiGø(嫘º šÉÒ)öÕZpÒ#áËöÓÛdiïȧ³5à%ÐC;• Eç駘´fÔ"ë-%W 0U¡0מ]æ ZòU6g¿oVÁßÍiBÉK[²ò™<é•“ã…ÅQ*U;Ë£Áÿ¤GðZLQŒô€å‹ñ™Ô]»Â;DÎd/A›ð ùȼ…ûܸŽ;$®ma`/xWௗxi’—4Oéö»·`¼OákcZé–<÷çAΪ•™ö¤—Ü…}kÃ*qkŸ¬qSŸ2•b„Ô|I§$ûü/š{6‰*ÐÜT˜ãT#Žà­Ì²—Œ¿°½ÝˆëyÀNz0o¢þÚ#š„%-@x˜y¿ñ[ÍòΜZÔn"J@iH&eÖÚcÀèàÛA{êüPK•TA5ÓØ˜ûb%£©"—¾ÃÀ\G–qD¤¢40&jo1nöÉû΀ûEuíæ,¦œæÐ/ºs•=té&y-“ü'ô{ãHæj9’§JýWƒÏ±P/ º‡e 7n¯©†Áš¾MÐT£=(NáCŸ ’[ٰı’€€¯(z¿nì¦Üàëw#Ž‹Ëe²Ìíÿaª¬LS %÷“#J2öïä%›hA÷¨M²!%‰ö탗T;—¾ÄÙãvÒ7ðl8q÷¹g w–É;ñî‰ìWÉxïB÷†Ä"Ž ˜uTd§ý_Îeí?@,aA¯ÜÂ|B`E% “‹G”‰`"}‘Ÿd… Ë@Í)¦«&$ˆCtÝj‰¯î`áÎ$`-! ºû ÿæñÝ$¦o ‚T’úO•©›©#<°n=Tkdº\5‰%Îé`Œ³·æ±øŽ6û^š…ùn¾NÒÑζiÞ2ØFÓ6›Gxå´Q@ñ6ñìüý‘—N`ÎU©+#Ñg¢$`˜p\iz×7²ØÒ±­›°ìÐ&Ò‚b‹8D /¥üDz/·M–F²Ü•ÿúÛè÷™TŒm­²¼dœ*-ÕÖ'Aà HMkQØÕR¢nM"^ô†Ž¢ç4Q‡_;˜PæAÇïÙ¹œ|W˜i–”œcnb¾¹V‡:;6Já~vÛ`‘V»b j?rX<Ï«ÑzÈ Y@<òhîn,æ>g÷ Ã5‘H3ïÌ»Ë ËÑN©Ùpè‘6SDÑ„H”¨Íã=ï[vH]S\„œm-çôïM:Gxeb‰Ö8ºñT' `?:b"›L6 ˜YÍ™»åk¦3â¤9:¶ƒåÀC9‹ˆø¦Hï‘sãÎ5þoá,(Õ?8Zfô™°¥+~WËšëZœQÛã\ì9[6‡0’ã{2{kåŒxQdðÃÉJ4 H³¡c#©.kÒ6õs à1tŽIiò<:›öÙU Ix47Ñ÷Ãsö‡øAŒ\[ø ¼ØìÙ\™ é<³gù Ãî Þ8 ó-.>—}/RM”·Âþ˜K…Œ„¢:”óR”•Á”ü£ó° éD*PÒ°¤^¿¬Ì°Dñåܶ„bǃѸ¬Õ+9ws>²Y)s†6·9«¬š‹Z!ZírhÇjCbeXÕùE#¾+ŸÙ«©1ª<¾;Y%a…êv}ŸÉ) õê«ýPÿ0åh,qnk…F1ÀõÑÜ›;^èWAß_ÁVotë± ÿ1ARL¡tÌþõˆ*¸f톼¸Í{”ÑQv’”VÅ#m/C-yH73’€€ÁétØä©Çø$¡kÏ 0áäy —!c,qå W]í¸r2¢óIÞ¶6Õ„Ç*þp dÅÄŸÜôšu¦!V¦µYþ­êY\E¦dq„P;˜ ܰµÐï‹°(ÈÍ‹D®¨¤$y.óЄuÝ€Ù Šj UóéãQ mË„ _}›o­ø¿ašÞžHn®‹TL©xð½z-L$ª;Ï\Ð8À\4bNúxÓW‚o@ŠYëäœâŸw4ÃEQÞ'3*_Å–Y3‚i¸nëTÙ¿ºöî¢,XôÞ_(¢„ßê¥ Â;üÐÚk:ÌyR¾43ì³@eÇ™<÷÷þ«ì‡$nÄk_VR›òDá¨)ÎzªBÝæ3–žØ²†„Ù¾)´zªâù Hd6•]ø Â,Lê]Ð-±Á¶‹:–7!Þã\°wOiû¸HiäFøXC#$­\/œYbуÅi2á“j\-Ói¬ )D‘å—<½nöÈíO”Ayä(³Ç~ŸˆÕÔÃAe^kôÒr¥à–Ÿ±Ä1%±—Q¦šÑw –W‚4Aíý˜Ca¿Üц;Ū­v„]:.§+ø2 v^¨âºÈ ° &Z™_ñd&¹p›Cf‚̳¨ÿÕÛ^`uíA `²òÍW\öN{\t„8Ð{à$­äþUy‡©«-‡…Ó‚Î2+—µ pxsâ“> `6ZDréëäLs§~%Œ¾Ð{é„úÎt^Æ9š¶!ÿ•ý.âf>¯? H€Š¾¯=_-àN‘˜»YòçªíšTÝͺ@†Ÿ7}Uq§£07ëôw•†‡ŽÿqûcÄë,þHëØÇôÚž%ÊÏâ?K¾ÎÍÀó9b­d:ÈžÜU£ê`‹c–U©Ö¯÷¶ 1|– ¼Â\Èãa£w£ØNmÑTC«%k¼œ©ø Sû™ÎbÚ߼׌9&F»[,¬­¯Å¡^o?O˜C÷S*‘Ãðþ!i4ä~UOÊ%ÓÚF¿g^ŽÝëfJÏ€^݋Ǥ|Êš|<ÆÊûu¦ò`m-p5v)ßaáû=$c”ýÎ\*ÃßyL—yž"R{a5çw]À}FÃÄMYx-hm¤ ®óužª|ä&݇•œ)ÅÀ~Ó" ‡ã'`e˼^þš›wl>ßRÀÃêXw’€€™KNè-%}¼þ—@ŸäÐ"ÌÆA™ ¢ ™d(ÇŠÖQξIÛOe¡HÕVã»›½Dô²±ˆ.ô!*ìúÜŠ„×%Z¶äj-È™ê‘Pð7ÿ¨–ýÑ©ñïÙ6¢…9óÕB³ †ž¹YÕsÐ#­îò¹htöx*¼Èûíópzñús·$”HuuÈÎfUa¯5È`· Ýšƒnˆ ŠKëðï@“‡Lyºî–Ñ=¯3Kkü¤`H5Ã÷XÆÇ¯E.ÕleìDég›1ÄÊ'¹ÍT燯€ê*ѡ޶q¶MðËÜŽ]•!ªíZÃŒ8éV³@V(n] wJº¹ü,9j ´>¯d5K<ƒXTé+ ”¼á°F±†1éÛz³‘ðæk£@}_„^5@Öy‡îr-»’æÑåÊFQ˜-¡<¬t“2ô™D¿ò(µ5ú2lrxØèúq²Œf¶Ì¦d°›ãs…ª¦3ûÊ;‘šŽÜ“‰›Óè~óQ¨YÄŒ¨1§u¯mA~Ý­Þ–RDgàrÃk2XÆG!8ÈÅxsæ¨@FPì€Û¸e @xkI­újöÐ7âH¤:áÑEÞê¤èòsí€9¿qßçÌ¥á,E³ænÔF§©¬ÿ™Œj 7"æ1[pš'gˆ­nˆïbôà$×3ïO?‰MÖ'ô‰@–sJm±7“l©RG gì •ÑÕ¶ßxKÑîw>>ª=_ùÿ2GýÑå"§.5òÌ‘KŒc7ÈXÿW¨§ÖùM£¨ú ŸßÌíÔ'=ê!øŸUÿp1‘d¯kêÞ`CßÌ üsMX‰‡ª›$äkkžtöîR*Sº¿¢o’€€>'E9ˆhØæ–Ó—¯UôôåVQ:¿¶8_7‘,óˆ #ù’t‰G Ö-ñb{áƒ-]ö_Mòì‘~J<©™Ìþ´ìÏO¨6lG&ûuùËd- 9F(¸]·( ç÷4¬#*ÂõèÒrf`FŒ¨ñ/¸ö-[m>_Û}¢öÅþxKìA¨w0òªûð+~hîz¸š|.UfŽZ–a¹Pê„uqíz$Ô‰Ð^£q¥ëYübVO‘â¬Óy@!õvŠŒF㬧¶xƒÈ²bJh…£¨!*=&£e4êeÀcH íƒáìDOÙgÓGj..Ôël XöW pÿ«|¦¢5"•è`¬G†›ˆÕÄ×yálÂ;»äÖ)Yàt—Ú Ý•c±R> èA#N’Ú«ÀzµŸúcÌ×­pãžÅÑv«L@È]1l«ûfѱËÁ‚ä 'E¾<ªãÛ„@’E:ùþõêê= MéßV¤Þ‚^â·j©$®ªx÷¬ÁM°áàdU³>Xýè;2Ï¿0dÒ+Lt¦b%M€p景¹—d¾K{$žºÀ, åöé×\ C¸ð—®]¬µ'/œG–Y÷† jÞO@Â~S£WQÃ[”]ß>w°¤Ç5ìY\pú=¢ºjšúø¶xîº}pÒbYk”dØi£XWÒ'K ^\RZa€ÜÈH¾¾d¨–4;gA¹q›Z“¬@¡)Sðð#9`!4N#¥?ó§ž;Y†§pºu~Ûf n‡+£©¦èkûK¥ÈÄ_ÓoûìФQeá ^N,Þ—¡Ëœ‘–`—þlõFññ©϶?C E¸>P€òãÕ%¢C0z/oŒü–YÑZ!€™%Þ=´¬,‚ä{JÈýÈô5¡¸ÈÖ!¨Ç‹™eB…é¤ïŽQ–½<ÚФ-|ÿuÀ•¡(-¥Q²ÕÙ_Å6CÁ™³à;mÅùå± :×qzœLâ=yÓÛrÔŽÅhBŒ…¡ï´cäH¿B5RVïþròŠð|ã¶oÛâ&h"|Á\½Ö±6ÞJ3æÃÁ.”Õ‹…Ƚ/ü`g—Oõ樌Ò–Áâܺå(T’¿:‘/Fÿ„ºypÐ/<€X,>ÛîÏœí-×׿›o Ño5'f¥é1Ò³ ¥érº1ÛÙµ]* k^üÑ ™Â1c¯ô‡©·xK‰ÁÓ@éNƒÃ‘È·³Q‹¿2!‡ š+…í°z嬫³qhºA±çÏPUhNÐbçyÿ3ÕÕ‹è¦qϘíàDXºÜŽwÚ%á[ü±8WŸ”iô¢ˆ~µÊÏRõAme³­”ËùD,¡® ï¿cX„€AEäB\‹)þGº/])s(Kˆ«¸7â&ÐÞIeܳ÷µ@n¸{‰TC©ا<»r\Ê&®Ò6 Ó0 gæEë ŠóŸ´‹å­TÈ‹q‹æO’€€È `n×®‡ý~ëêàì ‡Ø µ¸û;ñ¶”Ax‰|\¤p¶«.ƒÚºÎ˜ÒáÅü¾›JΡÅ!Y'ñ÷{—À’vGg±•m8ËZƒ9Ù<Ü<ð«* ì#°5y›…Z½ºÒ€œWþw>Fñ©¿R}“¸Q¢›ö¬‡X%¶‰á¬±1c„Ìʲ˜`47^:†h\bBšK¼ì¦óÝä°VàtýGJC´§›ßm{Ÿ2ŽÅ W­Îjìa´Œûãþ3q´c} êUÕõšÈ£}(×O¯Dî ð1Rf‡Ì]€+Ç›£oêÞTC0;bz(rM‹Còh™(FÖ†M*yµÄy1ð¡Ó¿t_50›7ãø®#ÊV9_ÃÉhT•” õïÜ:¿×à—.¾$¸zɧtÍG1'.0yv»»bªêÙð‰ÎœX,[ÇI¥G³î}N"¤FgêÒ Q èòJYu{¯¨@Â]µÖ¢%íQLÿ$¾æò*)ëI¹ø¸Fœ?Þæ§$¥µ<½¨I‹¿¬$ØÅ{È­trÆË?:™yrú.*LOÓý ž—++Å9ÇýZj³öÏIì½õ©žË³t£‚¹Ú(—1ÞnÊ–/šx%B©ÏR“aÛ] šùÖØo©#DñÊâ*€‘2 míK…¼ðàý~3¡í½`ÿNqêûÎkˆ6ph0@tzå®?õÄwtƒ¹ìo[\è’(œw>²”ä4L0›è>zL˜| ´gÄè<¦çœè)»òͦ>Hù«ZK#RT.>š˜¸ã”Žl$ã”±…Pp &_TÏŸÖ%”½°ü;tmàÑó»d„·: ¢êY.Óé Ü–5ñìÑùëu-£@ÖÛsyŒTIUìúì;(‰¹*ð¥ø¨Il\$ĺV ëYJÕÅ3€à›}¿ïžØHhD¤çç óž¸Ä´¤a ñgèÓV°sP“N¬ Á¡Š[̶Þ‰• " rnq物J…ý’»ÆûΓËäë(µÿŽt]|£ s"Gø¹v¯ *@Î&AƒŽýÄõ Qƒ6Dâ6½Ó— ¶5a¾A3A›ŸCŽD–ÄÖøi:[£gõjд¦5¼n€¾j@jŒ ðÉá;¶ïÆqˆ3J¾ýÉ/­nØC…ï7R„çàÕc3…„w¶{syAȾ˜V`¨ÕNX±`è+²Þ9¹¶PÊø«;7m@­_vß'ý$yºœ>èrx65!MF<Á>>E\* µÛ8ƒo¦Éñ€n<¢]Êh_¨%ê¯Õ!/îVAÒ‚øgŽV9ßN )™@l è6ñÂõƃ—¤hrðçP„=wæ$a* ¿ÁŽokW¸  ƒHÐzÔ#žBUÂþ¨lvÕãü,€l­Hã·™½‡ûNƒB&mÑ0}QÑ—ÙÛI‚EÑÆ98ªå¡£ª…^3"f_V«2 É~T+¿9¥•šÚ d ó{Àľ«¢$»¡ç+Þ"Õ{ŒétõS³ñ‰9*»ª¬ ¿ˆå(*óù q˜¶yÒxæMGæy‚(¤WÓ°-ŽxØX™öÒ-’€€ÎPÕº/«Õ©2c«e$úÈE÷ˆIåçØÌW¡ãößâ1‰ÍÕÍs‚ˆÏï»CzXª’ÛhXá"û¤ëªŽÛßð߸LE » cñqð Â*ÁÆ‚s æPjÿ*Zå¸Åk*³Ú¬v]"¯³Í7…h¨ö¡¼¬Qûðf¶®ÝbY®Ð¦ƒ*|Û‚bM´yÆß1·“y]ðÍlÁ°ÞgÉÈ_©gwq Ö£5ä< ý²Kíj/Ù;LpÔ^ÜF® ÈJ_&’mšEBu’ú;ê¶ØL‰®júÑ&Ábx5·‰jž¹)2Pù'ò¤ßPš‰Rå¡à/!d¿àÉTqìÐn/¬Ù;öÅ«‚Ê@ù;ìÛQ¤9~C (å‚Íj~–«tCiÿNFì‹ê¥Î×…Ó´,¨÷‘9† ÇœGDm*Ô R$ª…pŽB·¾pïøt,c:Ùî&­Þ(€!"²çÏðøO Ð7°JÎ0"ƒ-Ô…ÓØ½DÛU,Й\ ÔK/fGÌ_˜6êߦJbó»ëûJ,±ûïÏ«v:û×µÂÚc¹”e¼-VXP{8t# ÿôöã†5P–ò±ûÕÀnç¦ ŸxÏV+Ÿ`¼*‘šò„CãåG PËMl=z*„þîbQ?!Óòbu¨à(/5yú ps ZlŠ­§ÜÏ®UÅ)á^boÔJ—ßcUTo®+BàäÄœHíÎl?—.GE^ÛIÙ.LVOõ†gaêô»ÅŽ4ÒÎn0´øa°íg #zvºŽ9óÚ^Ó=Hb`ŽŒ¶ˆ[’UÁBï¬-I PïÉ!dCéHe™2M“Ó) ب mlâhÑ_iùn™+l„ìUUÀMèíoO\¸â¶B&©å'^Åë* Ps€ÛJ29Nšõu/«–\¾Vñ?¢?.} µÄè`Ú…û¶¢(èìõÁ~ÈšIw»+{W‰ZtP ­C%¼f½ûRU$о `û@BþÿÇ]þû;ÏÖF@ÆïH³}ªÍ&MB=£mä”>?(_Ðíyr•úï“1÷ââ±~p²TÂå#Í+ 7ƽŽü œ€7Q¥?¬má‹nbò÷ÓVjC^N¢M0é!Š~RÃÄw9à†‰KVa,åëL«ç0!ðìÜ­ó’€€¼«ð  ЯRVÕ¸&kÀWì—º4­)¤ßY×^*LÈé¡yÙœ#ÑËmKÅšÃrËÍÆ{¡«@VrȦHû¡Óñú´Ô (²ì®·R :wqöâ´’³ å6#ô&MÕ‡ê͹IfY½VŽöò-Ú_ƒ"ˆ B³€ áéË‚’=k/RÊH䊜S¿QSë™­Ä9x‡J¤ùÆ D"g:GÑV,¸Ãòÿ×f8‚V+•Ìô=M”#Ç&Œ*kÖF-V‡ìöâN&£'påÕ;¢ÄFªãËúG®,ÄišÆ ÜRîfO9Á“'øÖ;Üô‹²[ûÀ%YâòÉHˆ°¼´© #=ä"ýᎹY.-â™Â°9¦Í=ÉèÖÍ VQœÈâë[}Oôfï5Hì ƒ_e+kÊÊlÁŽ‚²ÒÌnŸ9ƒÛ&ÁF[1/’½á€ùühõ+¾Ãi(⯇ô€=…«(Wâëaþ:^“UA8Jçe‹vØ=êÚW=x«\Yt`)< ®êÐD±8"•¶ÌRÚuÔìý ¾eš•|Æ,l‘ÅKÖ¶eC3:–v [Ô¶½¤ß¡q˜ÕÔg Ì.|1»Ê™oQÑðòÏšn~R{@%Y™È! Õk™LûG%i‚Ú¼6ï áp“ò—9eXJ»ÁæõSHIEC™D4þr‘AŒUÊäIœ–²ê¸†î½äl«anõø€!gèT\”åÇšxÖeKœS̈|üÔH®ÿ ù7Þß½iC$¢ê«ñÂçÙ¸†½,ORè} M¿VÉLgæàÒÅ2‘ôdb¢^žQÊNù÷›$¾‹Ñ ÞÁÕ°«<ëô&†o+^fÙÍœ¯/ûÿÞï®4 W£¯ $xÕzunemÕôÀ4@G–˜bgªtaÇ’ÂAî1å4ý£d ‘½A€ÞEÜBQ-(£;_%†º¦–,üøñÚpŠ3…pÆ ¯ #šº¹x.ºÎï"â2ÄÄŸX¨Þ ï^Ä™ÿ²—KÃ_*æ3•û2’“¼žÜK®q6D“þŠd<Âã_2F¯oÕlµòŸÇ.P›ÙQÅ%d©L Öu@>¯r•¦p8Т©æ¸ÐNÞ’PV’'x_­¦WheìØ:¢½/¡lÖª//À;—ÈíVÅ…,f²-RFNº .Ðýë[ÿÞ©yßža/…"ºÄÈ€t:Ô˜Ã?s;à)n—Àäæ/ óvëc@Zz-«™]A±6¤tŸ‰|„é& WR§RMÃØ¾9sV•+%c¨M3cOk| nÈþ-Æ8û¼Æ º—›3Û«¾=º{ÕÇ™' #L±ÖæyË¡2M¤ï,îoµ½"Õ—ò¤Ñ ÚÝj ¹ë¿4ÅÆOJ=î©aK¦5}Xo‚-…¸V\šÇ± Ę™æuQÎ"À‡Ž…yW1ÄBZŠ’ãÒ ”ú·*'E»Àn‰«e„´Ÿã,ȧʛÀºÈôÁDx0›Ö«ÏÒ,%’ÍÒï Ñ‹^Yã)ÂúÍ O‡ÍÆ\zŸhgÂ'=óÇü²£‰fpÜÅÿ8ÈØãy}@ôäü …’–ï‘üÞ¯$¸6þ¸ñÓîÊ«Ç=Aâiày3pdî‰Ð³,c?Åi/G›ç—? IœµrH¿Õéô¢ª»ÉYuîg”õn§Èž[jS\’tÉòQÕÁ[ŠÇ,Ð×öÞò½ƒ´ìÄÙuEOšyÅ?"±õ÷ŠäBäÏ•7NŸhqµ¤ìéõ%Õߘ–1}h* OR&Q¬QAõæk¹§ ™i†RNv°3Ÿ†Lyä|ÚŠÍæŒz¶ßìÏQÉ8lb¼F‡g¢(vK§ä£æLmjƒ¨§V’€€¤8+øW·xsúe :ò÷ºYðk¯.hx†g›¯Äñ&ª6™¹[ÙÞ ¼÷É0þjÖàX¼.ZD†\ø,4ó‹ãð(\é‹!Îdù/­²˜2ö>}FZzvŸ¾-0ª…Ë—2ýq‚òÍ4`šÚœ×»µg¡BÈâ‚R)½Ù ½cœàÈØ §øYýPøHIÁ¿$~|K¡z¨Ð6î^bÛ¤|ôªL+ŒKÚòÁ³£)y÷¡6ÿ{wmÇökQ¿"S>ªì¿úÚz3diѤ•>l‘Ag¶&ÚxÞ<£þ4‡cÍ´‰=5óˆ,WfݼO¥ÝźEN¾ýÖù#åf¦°ÝÇ´ŸY½ÿ–3|7+iY=Òƒþ¾4í’BjQ;džoùŠdƺò÷kqoÞÚ½X½ˆ¸¹›ìÛ3¨²¤ÇÃö{xZê¯Â‚]‚îöªï̳EcÉ0ÔÕ âs³”›ÅhÛtÕM¦júÒÚPþ(Ús.Bˆn¸¦xÜ—S{ â¶8ÈËË™&Áã {|£AŸMVmÄ_{V3›ÎXš,A¬S¯W~àµÀàYèb¹ë¯÷< Ã¥2ä¼íêëÃÙ(†)·ÓÇMCaœß¡E rbz;f6Å#`ôç(±…L…:]÷‚÷u…®~öKÙâ÷¥a.­šp¦=1m·7•ãÜù °ZOƒ„}twßlú÷)ͽ=³'^Ó—Z±¸¾“Ô‰¾»”z"uø t3ìÜ6±§HèAš€.=ÿú0ޏÌÔO$Gåqð)ª}Ž•ý¸€YìØßj±›ãÀñø“‹l‚!=¯âÈzÅ&×J²éù7Ø—n-X5ŧoqéíìž=½éd+ ÅU\ÖŒ©¿?ÙØõÝ·I>1i]hò»º :@L~H, …¿ºÍ"V›ˆw—Ö p0j&ë÷ºSùšRµ¯×C ð¥ýSÕA’âs®Á°ðsYÅ.“q.YUýf“3™-K¤ÛÅá3¸m ߀WæovZÃTÒ³Âó êÑÇ4ì'åöˆ¥Þ#Ç$1Ρ¹®$VF-v'ßôüÌÅgf“L-<ž`(DCn·V)yN ãlÿæí[´a;U•¿úщœªôÓÞÕ>R ² ¸š;’€€êÒÐèÚl©œ¿­mßá—Ú—g'[)>­.ο¹”(b‘aÎqt˹gB¯€<›®aÖvâî;²¡ûeçw#’žÂêÜÔ8Ø–¦Ö®,sn(&¸þwx6t£UVíôùëŽ3M ÈáH6x‚³•¬E|™b„Ë2‡A£@™ å–Áø‚¹·¸*Ÿî06ÛÕþ¯Pô¥ATÞ¦ËX+žÎüº,~¡Rß«I….ÉRY…9­ßßòEî~5¿v~V êþÌРËÇG¢[áJ9ÔÆj8tÈÈñ4h)cgœ¢f毤]±íŸOyãÖé¯C¤¡¤µ·ÃKbH§'†°¤ô¨É’êñB€¦9<”…47€…COÚvëî6È:]£ †[+±ðÐ.œ®È첉ϪàKbÇ·PK‡Œøišpˆˆ]óÇAѨãu_w'2N\|xH§tScW8ˆü1ù >È,W‡•Ê^¬U+uD燿­@¤®új$åõikºHQdnr+ sO̓|Îzgþ…²½»ìUÔ²=UαiòR´VÅ´'Zš3Ìή‰ ß5ÇÉŸ¥b{Ô*g3õ2tÞßû ߨô³! ˆþ6¡EŒû¥²_Lú§P§§;¾ñÞQ’w…jྴðòñõyøglÞ`#²îUE4ÆÒè1ùQ‡ØøÚ¹U5ßÐ_ï%êõOµöŽÕôß›abÕ3ÄS ê­jyD=Í0‹±æp?Û{ýyAæ·m¹5Ü:“ƒÓdÐÊ3¥`U<^&R Tžu†ä½§?\Yøƒ®+°sÁ CôãîÏÐb6Ñ!u=®:¥¸ô¾¦ô;g¿÷ÕÙE†¡ñæ9IÌô”6"iñ[%Sˆá)r1¥ j[Šª½ÀpihèX˜(§@usÐNý³ç05¿ÊŒ¼ñßn¬ÛšûÜ#^f*î¾{šëÀ…·\M5¦XɹqÜ2Üí©`ä1YÇ}è· æÙ³Ãr·Ô;˜¿m×Ãy_:V1M U}¼Ãù«W¦!î;ÀF‡.›C† a..õÅšvÓ›»76š È×Eö/oâ(¹ &9ðÙ@RºeÇåè\Glï»$œx’€€º„Ý¢Y`.ûÃÀo{ÕÞšŽ ™$á>áXÁßFÑ>…r˜&Ö·…ý}&|L—דkqÚù1b†æ¯±I>'U Æ "ëc×ÂM„÷ƒ{æœoX—æÚÀX>!<’žü‰yäf_8ª«‡´Š{ ?†|~:Q¤2jl×x BÒýÙ#‹™sê1K¯ |)¶ì{²Þ³·&*}Ì)2Õ±áÎŒ|›¨Sª÷Ü!„0á: ÛÔbgýÌm#Ö|¿âΩ1Sþè¥(3XÈÍåG¦³2ì¿|ç’›jÝãäʧƉnÅs#^As¸PYÓzë‹·½2¬ßêý ~îl+†‰i@“Ò~—|Ÿ¡j/{üŽf[¨”®Ø#€Y°Þ|ÜVÒ‹ÕA™ü  iì­ÐÅ-¹cè,wß‹±YL¶…´²gX¹4>–‘'VÐ7Í%_0«¢Úà¹Ù€UpÍJýPxâ÷xPSbHn·* ¿˜_ÃUÈDál3™)¾ó™{Ñ/Td"^rñ¦5:J'•Ïe5o¦uGÞ¬Ö¼\×^ðFøù." kÇ c&ÔI>^. çàÒDS*U!›J(ã.<ÇŽÙPiJ¢•õðGØÓ/ʰV}ã•Ìšo·p€ERü~æPéFk¡²~.™õôç‘Ñê­è­ã-m~n‡l#¿³gŸÙÚ^B¶²&¡/’µ"¾aê=à‹OXØï/xÄ‘n`‚f\ÝB<ÿ!4:€zÏ[ûoJåÏz` ‡¤mV&Êó‚šü>Ž‘þˆc€ÛÛ>˜šIoVƒÚ‘ôMð§|“7¢˜.üü=¹øJ O’5Êî F<3Õ8 ýÕç%uö%9'ˆcÚƒeâžú\$‹.>;—•€Sx„˜Ù¢jÂgè@¨WÎ#­å¡HŠQ5:2²… lçLœ0Ç‘yÜIfÎ,Í‘>ô»³MŠÛŒCíýéJm»¯žHxÄHúš¦nðéCëŸF©rY‡í†Œä;-Ÿy·Ö É|»jÐÿkŒ¿*V!ZèëáùŽôL qË \ŠœššÞ Åk—½ß`µ¦MmN~CgÑdËA9þ³›<'…Àd%ó N,ḬÙäˆGÍ% ðšoTæ#ó’Y¶Ðlðß~ÄNùÜÿ~ ³]‘I’€€·RÔòŽôe/¨á–c‡xȰ@$èólKî—öy¸>¦H3–6“͇€©4‰¡‰P½‚‹ñì©™Çy$yoÌtøÄ«“-Ò±ñÞÛ¹¼¾-#H´8rƒqþ–‚eˆM” ßü€ÄÔN·ZÏëR 1ÉߺϬÑâ.ÌBVOªsaÛƒ¤Öj‘Y÷Ƨfþ‰T ¥Nc¹€®ß@Ž[÷½¬ç 5¢"× ÑÅÂrq¶ Ï´ €UŸ'QµMMõðäÔŠXƒ8K8ë߉¾5Åüî5J|÷ÑwP²€^ƒëœ;z·ÐÇ-Çÿ eËÖÖWñ66`×/–Ù´J$åÉ/v!¹«”¾L¨Äb(øáï<åÌÌÞrt¿!âWÚZ“H¬¯\åÛ°" 9mÊ,§e’ÑàÙaŽ÷¢ééäkÏT]‰ÜŽ–‹ vK³R…Ÿ ižT™ÀÖ T²«Ã2Gý|_ûîÙV‡ÆˆFÜi Ï\=þl[$ø„l뙄uÌ¥?1\éw"ëd¥âØó"ŒW<_*ñ¬mÌœ¨¤ïð1ÌëWÓFBáªVöØD`÷ªN€ ^îÉEÁ¶”z¢;ç’×#>&6- ¤7Rh/ÿ¶zAÈV1Â=äFW’´HqžDŽê!J8€žãßqàÌ©‚öÉzºÇ›’“EVí#àhª(c÷ÖŒV]©/Z:gDÊe{TÒˆ€¤"™U;»ôóL:Ók0Ÿ¯ç¸V=9tb»ü‡¯ŠØúã‡øÔã ~ܨpÇšŸof‹cu7%2·Qbê^ìã³½€ºþ˜¤ŒÒ7/¨lò†ÐÄ~QtèlÍ”~nœo±'@¡6¨Ó‘ƒká™ö¡k¯ã ï6OZQv Ǿ`½Þº{N_*¶ÅС÷Û;þ¨~ .¾Ôüò¿•ì‚Ñ«9z`ÍZaì2#—?…À ޏÅ'Ø q<¾´Ñ çNC&•C§~M¢—ÌãQš¦<±jÏ=é[þS:’Óë„Ç” „˜‚˰v(l(ølœÙWTür$Mý÷SÒUa×M9È?2.§P)š±O3&Í6óô‘×2á=¯IÀw¥ì®£ì“(Ñ„(ÚÓš 8I‚©û5§&h—ù¬ÞÁ‡Eýä|¼¶…É&í TÈ1¬$’€€Ö:ØôŒÃÞÖþì+«¹’Ý»m–P(uÅhÿ¢©OÆzI¬c)£« :Ï¿Ÿ(¸ª¨­éÈ. ÔŒšE:6˜·±š)ŸvO§¹‡ EOžÕ†¯1¯$ôúh×þ¢¡%OèÃÁ"ð˜\ãìPa"~á$ídæë&C›‰zõ¤ UeÊi%°™Ghl`42TÈó쯛Ú4z”Ä.„E’¾ap{mºÞÜÐë…°ãȹ­¡˜?È™ÿTô}”ÔDæxësv¤·?áãÛVi|R½÷Uk4TRܳ3„ñOtuqvF1âØ’t«žÏ‹u#ÃbÒ#3é±tŸ’îí/Søi^–T‘*<¨q¬]¶3À›œ_ÙpÊj!£”†õ¦UŸÏ3¢(y‚™R« »A¼ٜ¤oz)R°qÐóAZü䨔g…ö"qÒíëAçk5}¶äš§­@>Êû½)ôH±á9J}O»R¢v•/dzÜqª1ÄåÁÓ¥!ÚtNzq„‰RUf"Ÿàe\iÎÛ‹Q`(#'´éò†Ve#­Ñ¡9¼Wįz“ù¥;žwOçÿÆ–æ{|ôÀô|Ð"à‡ÇÿK>,§üÄ?1ðM‹CœX¥°ÞY­·ÝSJÄS%(8ønÇ7‡Ü(Áÿ¤#×£ƒïL“ö:¯jÁê£1 ‹ê7 ¥ŒA/&}Õü)rþ2Å÷f¹—¥òà´|¬ÒWù›¾ Uy0¦×rºèQ]µTEÊß梭Ú_•³€b™û€MBo¹¦A;‚›–“þ_Å ÃjÚ!)n1DÉ-•=ñÈÕÌgþÔ*<~yñ%鼚ZcNêèQ5¯¨½ X *Ãè ® ëÞ‘03¯Mw7lòªÂ}ßLÎRIc1“•‘%Gnä­}6dJ«"6VúD“c+`õ^,‘àÜF´V¿\!ñˆü&ÐÍËàÆ°”£pÅB$£™ª!o§†‹â‹ÌS»(?¶5¦èq6Ms|fxù‘­©ÓÓªX”9ÇâŽB¿ü$„gŠåÍÀ ÏeîNÿÓ¼ÍøÏ²=‡ Û§Qñ†ªn–óCé¼ÀÏG´7v5âÒ° #ÄM•Àôˆ¦œèÛÅRÏ]çöV”æE²ƒ)áIÁ‚tYߦ9Þª´J(P„NwÈ9‘·9’€€·É´bUÒ½˜vhÉÙP>è´¹Ô¦žfŸB§A¡TñdBôÂáPEtLa‘t¾² ùäÉ@ÕZϺ֤vf™ïºž’Òq•Úr‘ñ¿ó Ⱦë!\Ãp‰o—’" Zfó^¡$ª&ÁÍ^ÐLà,¯Ð&B±<³.t OVÈÁÞ SGîO?dœÉ{MÜJèí¸`"`!v¢ Ä–o‘ ï Õ#qu¯Šn£rv²ÌÛÀ M]‘4Ýr9‰Z«ûƒ”&‹Ép[ƒ ñ]ÜEààT#rìð¢'¥°+ ‚Àô}K>îóv“0®ñ^éšÅÕçÒ‡Švxm`”A÷Eec'Iî²$GÉ{Ì$öÛóƒ“Ð)SȲÕ@›×éöçÖ0÷x `uq¬¸L v{R ¥ýhD Jb#¤á¦ [!þ%Z–›U¶¹¼–Í:«ïs«~Y‘S]ñ[Þ6¿£á¥mÑ\Gò7sl'úì÷¹LãÌáj¦a=w3cÎKŠË¦`Ú2 ¥÷Î 2zTãmä_®X<Þõ# ¢Ëq…3I0½GûjmÚî\Ð(?½M[(o`8N’kžSn0ÎZ]¯}=Ù¯:¨^OÀ-ü'”*F¨×½süõ™5ŠFßw-8YÞ# SðÔ“½[¬@ÿø)Ý ¯ý _¸*‡²]¾±`çÕFU/þÔÀf|+Ê·5+é%úXÞIž9òý-ø?û̇¸ââ®Hw±Ïð(y£Ëšzùúæ2ÈqªQº#ÔkyiÚ¥®Ôñ„±Rã@žRÿ×oHÔ©ÒÕQ8˜ç_•B¤g¦eÅåÔÙÂB… êÉ㇬³žà'Ú&ôeLÛl·&dî0 0ô/À'OŸ"]ÉWP­+gø˜"ÅžìNÓa¤K˶7¦ù¬È°LøìrËìN@ Ñiï¡zΑ „Ë}M}t]Xo~ië BUœòE¦‚m9M(ðœm”Ï´±æÞ»; —;=c†#. YjTó+dˆÅŒy%ÁGÍ|ÄÝ¥P¥ûúxÐlÜ`^d¸Ë8«¶x#ÆÓ†.’/q\…G6WðÚf½d¤uuÏ«Ø5“3ÿ2w¬pµ“…{gT¡¹7Ðk»Øê[-õ2§D%l+‹v¾RaÎ^f’€€¡¸l ÖY`TéS­ ttÿ…»¦læÿ„¨a_yK†?d+ú°õgÙ¿ÙâD Ù‚Z 5%ê*o¶‹zñ_àüÛÇëåû|dg5ed{mßëd–¥iÐÈaqÎs^CÓæ° ¦9Â’ãZÑàk$ü·49:¨;p¹`ë­~oβ¦Ó]dœçySýÆÂ¬Ó ÁQµ¯kGÿɶùá?«£Lh€TƼ8™‰ïb‚…몢~Î65YÒŠD­²Ý^û¥ºÇv‘JùùÈ…xÊ$k’êiÃÜ^v6¶¶[J› ƒÓÐÖå3±š¸Ñwº„«FAŠäÉWν›tù—²ó¼·»¿Ï¥B×Gü2”8B¹xÚœÒB¸8¯O¢Ö½¹HQJƒDý®¿žÐöÓ³8 O^¯kRB¹þŒZ Ñhö ¥‡b]s&ó ˜ø¶q.þÊ 4Ê`—$9Ž¢Sä‹F¶D½–<üŸO´¨Ù:®uã᎑ è‘„À Ǻ¿d)JØ”+1¼ñ[$úÂgK ÜÒ>ÖEÿbÒ%DGÞõ¦Ä‚h,†l ”Qãenèé÷ÉîT‹ÿV.+à>Ì¡k—!ìÚ†iäcW¾ŽÆgK;W=”.P¤Hsv¹š1hêIV"pFÀ¢'4 ¼ö\W¹s‡F+ ÑÒèœXà¦f®Â〤#[˜‚¤¶8áRhÏÝŒ–Mý;÷]F-Uÿº…ûia¸*¥Ê‘ÅÎÕp¡ž †è”›`.ˆrz9û“u±üUƒGâ½á2½k);ðU¯ïÛê 8¨hˆ%2ÎÁƒC-ª BÄÿfÒ‡¨ÙPµÄK§ÀÃA` I»ðT…cKà¨\#e8HþÓ>ÄpŠ ©a3ŸcqŒ¥¯EÊз9§Ü¼­š^tŒ¦Ô‘` 8´Ì‘%ý7ÞiÕU=ÉîRþƒï›ÀŽÐöJÞÌl¿ ,sóqüå—¿Ó÷æú4õÌ~PDë’GÕ^Ø'é<~Oæ.Ì}¡]\`zÊoáý\VQ·?§8Ô=ä:¥¾«$ œtÐõœ“)þïPdã£hF•AP=ž·X¼Ôú$[—†jvs|õñêÉGOÖò‹á™†e¾;œÑÐæ6é˜Í‡€Š¹w<\—çi&%|sàf9sDO¢lIà„¾’€€­ÃŽŒ ·5>@ %†DþÍG΋ÀkË¢{‚ê“â-;u©½aùß‹ú”‘Öð|Ý{ó5«$o i6ÚËãÝz¶ÔAcJð(2Hqºü‹áGcŽò=‰m•:W𙑊V¢`å7a@4“;{¥§7´ŠHáìT¼ãD1v˜ÚŠB)sXlÛ´ký…ë‹8°:‡B8÷x^#©ÎÏ×;ŒK3f=³kå«E¬Ôžøóä2²¥1UõâLÜ8-á»óžSᣨvøëèêÿLãýùmIΜ«”ë•äÖVï3FÛ½å‰[0öeŒ•ðËÀ¢¢ŽÝ`dþÚ2Dàü§"ÉËag,é×W*¹·»Ò»Ž!*nªúO Q‹´H0œÖ?T/)ð_;ûàšˆQ€ßf“U dÎx“½»*Û‘€_Œ/a,m󎘽 ðMÕ'°säótÉ€KǦ"t@W¤ÌïÔäVÈ=Ãt÷”·„ÌΜƒíº Ë&mÙNh`q³³y"Ò„ K¿<-›š°bWd0¢Sp¨ù§†¤ÏDü:/Àÿ÷¾ò6E,“ª¢×sòí®2 €u¢–p¦lÜ–W‘aÑ’¯Ï)#¥…Qm:­‡ǶãJ¹bÿâ©‹ÒÕtR^‚åº:(ã4ÏÁô‘½±ð¥Ù,¼¡ñ aÓñ©UQD\B~7(3rH^¥Y] ´îOmr"C•ÙR.ñìÉ!©H¸ìñ-ÿ†Ð]ø¢ÖâýužH£±Û!פ>$/ÒÀlâø¯|™—öHÇ3âæ$“Ë‘ö6ñCåF<³¬æœÆgJ~Ü^+½õÀûM|›ÌÔ墦ÒW®U{"Ã[¸f§u4ÉH9!)6À“ãH(±@lH™œV8xf•UN~U»®èu¢øÓ‡ü¡¦ÚB~.¥FnGg¾G3¤é™çŽÎ(7É’×|?Ôi÷Ý7Ç~ñSÙ€§D9‡])ÄE¨õÓQ‰fË÷[Œf³EpÓõJÖ³‰ÿ"qF‘Ѧa¦ÖSð†6JļøøÙlü†È»ã“…‹$·wÉ-Qm‰Cx»Zòò/¢ °Cß:rjPž¡Ë¯ºü¥œ:¹ÅêÂØ&òMaðw@×öŸ6¼FB7\©³»ÃX¸{݉ b7%~®ëw0>’€€©©¸R{[÷×è·nɃ~Ÿ•6«#øÚ;†ÒU¹]-x ®QÕúÛ[Ç}!9?=³h„ðu­7ý¤¼Y,p …ë ø Ûܹ‚{#êsÐÑáǦ€ ??ÌGÖì]tÊõôËÚÌM^í@dHzˆcÁ3܇׫Á Ú×´­al;W4‘‘ç O¼€ÎÔ ¥hjøÏ”½gÚ#l/S¢že©m JæHi’cd>£»“”Çœ‡¸¢Â·ñ²àòˆ§ãâ(²{È· ¸"=ÿ~ó ‡F徕û7Û†âeKÉ$‡Ò~+s¯ÏÃLSçGl NÝœý{ÍàðÎå‚ÍwÂÒý£k’T÷–[™" älßõbT~4€–ËñÒPÌÉJÚ'ÀpŠ}å©0²rNŒ_=-ÍŸQ˸ŽC_lwº…PØ ë0d±ty÷ú ·P–…Vø U&gġċ|{ÆK%ý xU9l§lö’ &6Qg+oí¾Éøž’ª,9&;-®^ua°‰ùû˜ß}ÏÁßêv¶D¯îMýùbsœRkòê ^BY¡Z‚„ 3éP‚Ø%w¬gØ=DÒ§TjU±ù‘ÿ– m‘V÷!¡kffcrÖ"èÅÚ[§Æºu5#c•«ž? ÐÌ9–9Ä©Y;îgÀ~Ø °mA-zÝ`¾Ÿ41¸´^ƒ_šumáxvßç^{_3[/!“Ђ¼]NÀÔïÆþrû[MñKžÜá3‘f¥!ž€³ö¢^%Rw•ñ䷓ᬌ§urÿ÷£Iì—ìQö—‚ºùô5‰q8 a·S!‘ÃÖÓh1h0öܵIº¸‡ºmUV¶zE©"¾®—É€Þ¨ûxê;mеo¤=-<™g©rö’áNÜö¤qJpDñÑ‹ØÌ/ö>x)­H"[#|jŽ™[)¹m„®¢ýÚH;Æyý¨s=mðHÔ¾ åƒ`¶¸·QYÌÿ.Ò™Zb3Ç“ï8žßfˆ’€€°.̤›KwÙô¿á¸Ô%b©=ÿÝçy;#x÷GR5ñú“(êˆ'Êh$FÌ#jk±¸À?ó£ÚØpAº. °áÙüÔVÝê"Ù¶yQ—¢8Ȩº›y\GX7¡B¤gæânD7ê©PN±¦BÂüä¥ÂrNW?ØL?„þ„„IJì&a3}(ú&[%Go\÷ÝñÌ|ûŸ û˜–´7Ë-Т”m0^ 0Y-PwŠ‹ðbV—~Žò¤I°¸ü°!f.8•K:¨P¹Õ,@^‹ïêBD#Å*@ƒIéüFTy â÷Ðøãtá¾»“6„ÍÈ—F•þ90à“M–5I)·&»˜‘ƒ¤OK9 1¸‡¾›“e¿Í†vi©”×¼½Éù´w}Ý$S ‚N®¢£ÊRò·¯j,ü'bv&&¶u„¨â(ä:MûAíbå÷Ç1óDëW_’,ÕŸYüdeøA¢f>Z›ùpÉ€ÀÖfbÂB—”ª‡¥c¶–„rÑsTûK~pɿų·³­ E{¹œÌìЋ+?c4¦­eÇIe 7 —×Í]ªÔÿÐ-œXé Þ9Ô.ÌF4Ó-–b/ga~¦ tO9²¸ E·«ºpï¨õ›Mã·•†ó7âÂDL£UHaô³ÛH⨛Vù½¸aß{Ñ€iðâ*KSd>…ó˘3‘bÏTt]VC_cÃ'wm0ˆeûÜY”W ´ÉØM¬«¿˜s³@] Xü`_Ãt<Ž«@ðÿŠG®TàJ %JH\y 䤨z5œc;Ø­Ï ˆß±ÆÂÒD*”µöÀ©zã¹ÿ•qâ°‘™gˆ„´×ÉÑ%àWÏ6މZI„91éæv·¨l„4ÂC #“M~‚T‡Œå¤_[_i“µ Ù8Z_yyôrÈœ¿Á[{®½M¤•“ëþÕ²Y6pqCïP(ˆÁq•A–éo»©| Úä1Lˆ9Ì(l¡j£A_Z­AO³ b€h«¶!ÈϾ1±•{Ubeáz²¼ãý÷²_æÄó³K?r¬íe@Z½ y SûA‹<ž ×ïÛ8l®«ƒ™\ãôy`*ÙG½Ât~qÞðrç 2Ý? Ɉ dñÝ  é¬`-2xó$£ñ¿¼5Íü ª[­*ÉŒ%¦’€€ÒÕžU§ ûûÁ º¥òA'¾ë‚Çã*`?zÛæÓ‹¼áÑÿÉÿYëe&̧nÈýÜkZ4þïï:›½¤÷‚<=ÈL˜îD²Îº½€•hmá÷å#Ü#—ø”¶)cŽäñöMãeÑÃ…)Ðëâáâ t:©¦Æeuæó¢ëºªUáo z!€º"ü»íˆ[Åpô c‘Ï”]h¶"ÏR5‰`W€Jp‰,‰o޲˜èä „l©gëÚO‰äZ³›ÚT­>rxËž¿ÑR›ÆL¯Yq c‹N NÚ9+(Í$BÂ58°'Æ‚¼ìœ˜¤ %•RÍ›êI×§`þX»c@íPxô¿ãw¨@ï)0ÇÝôCºFé½lÜ“ 'Š+ ×–? ö4:ÄÿN42ê¡KÞgwxCBIR.C6¦¿bç2SÝnì®Nó¢¿Üè h}ü×1æ„eÄ¿Ó1M‡ð‰óɃZËÏk£ãrÓÍjs ;lµ›úU1„Ž>b †Kq”:WBùšýiÛL®W^ËY ©Ü¼ùYÎ)Ge ׎‰rZyõGó#ÏV†´Ábtå¨ãÜ!î¹ñÔ=õ7Ö× Ñ,tLZç] ZÍA™‚SÝe~ÄOÁnD‰Uv`@øzæ`ÏÞÁËéê0ÜMúu—x!¥rµÿ»<ãdÇ]¯é'zûþ› -H÷”6ÿŽ,Ø>*|:ÿõz€çËD*ï`“™¸l×ÍY0q}’Ä>þ  ”Æ ùÇmylÑDQ{2ý ÂÆ“P@ù?1hVS98–Þ5#†NOc®xܬ¢žÿ©DÏ'K{a·g]ñ2_%öû]«u?º=„P»­œDRÿ »Lþ"p%“<0ˆfÉ} ìJÿMì_ÙµãpÍË} õ§â}‹ ˆ¦Î–öÈw¡-Îç8hrIˆ¤œóöKìá†÷ÿ{þjt‡3r1!ß-¦¿h4BË ºžTmÜÛøàÀÞgŸD‰€›ûȠ׫ª¬£{!LlDEÄßÃÞÂÎ:h¦DC—¶lJ’~¸“_ü2Ζ7ü}`ö|œ-[ê!p£KIi&òøº:ï™/ ¨Ð-ZeànŸú²] Úƒ¹êÂe’CbÊ õ³¤Tí,)Œ²ÿCy èCWFiî6…¯ÑŒ·Ýf–Ц Ì#*?A%X”ìÉ"Oefa—Í%¶Þ"ËêˆçÎ’À·z Q•K ìmq;c§./1Á-gºö ¤JÓúœœ²YÓ—a i0 c-GM¼€Îqí¶è†q—Ü*§zÕtKÃîs¹JàB5Â1F–U4ÃGuÅ¿e)ÆBÜ4Ñå•0zˈv!ú÷\Õ{¿µA™ ^ʼn†@Øâ5&9”ãà ljûª_ú?Þ½Ú+u˜7éÆ9Ok$Öˆ:==¿[~¥3ù~^n)aáÀs"@–0?pS2¾œ´íÉôtLÒöE¸§jÕ ÷IJt5Â\·òGlÁb›,Ôskê#v\$Ö4rƒœ&ó0hP]»Jk­’€€»4þ18ô¦gn ì+µ·¥›¤@ÿïß,x*;¸•Û. š<3@z©Œ±9‰ôè+Ó{xÖcGü†÷\—,t},ŸðËW›KàF¾VÔˆ0ÔjBMêРÚÛ3õ»¦ïä{Uæ +Óæ Û´™ ådÎÉW TT6’˜ SDp˜¼ö‹äª"ƦAÔíª= /’¥¬A ¦Ð)È_†¤;½]è\õ:p'”Ê\£‰D¿…³‹³"öUy$> _&35à!tŸ]ØÍÝÝÕzô¯õpÖ³?à[€cf…çãÏUtV¸ëþeÚF4!mÑÿ÷ŽgkJLÐw%‹³z_íH”ÿZ¾«»p‹iqÿælK•>Œþ¶º~õdL’û‰c”uôÞ—«†ž±I£êÃÙì¢Aù¼­2•$Ì8xðïL¶á—>6kꀋû8 lG çU.f¢·ñN(Ed!hŒv¤Áhû=n-ï©ãÚŽþ6¥;uö2$E„»@²Yº@DÜ,ÅßlU‰z4ÑϤÒ'a¨hÖ†šNQNTƒ,~hßÉ0ާ=zËBð‹˜G¸à¶ŠàDZ P”@Jóø™vs­]ýúûÚVãÝCÇ&x×b~Àky*}’^mfMá¡"äóÔ$’aìã“Û‰qAñâƒ1?»†UH¼6ôšÖ­»a—¦•Ò[ •#`Å­Y4>YÁÙ‡ª(!óÌD+U'Ò>ÒÉ4àÈ-¨¦º¿ 'G_ v…‰™D(&˜F–W 0ú”ó.Ž'72Ô+É”û'Êc ŸÑñ©*Jc‡=ÑVX•JØÙ}ëZ>qÆ!§ÆeÂZCö<ƒž!KúÞu5j…ýó4^؇š…V6šÕ,8ú`=̺ŸÅÃØ\;Ko›±Öé©L³lœá‡ ò§îzjáuKIÝòÿº;)rã?œ¡˜xøxìB,ý‚á62ˆ¯Ó¶Åõñ¯Ž¬ýeoÁŽ“oqÔ©›¾zª3ß룺eÚe¶”{áa¹Þ…<†’Á.˜>'âa–xBd±º´;àš½Ù|BºämN·”% AMù¸Î$J?‘àGLåŽ"sR¾ß%/=de°à{¡%9 ø¶™½«ìIÖñ5Ïçþ Ǽ’ ¡¾H Û¬¯$.†Dy ô¸¿Ä 6¡}»©¹tòÐ?ЬÍÜØ¯‰6Aùý9¼¸}I1Aj¯ýçëÙd?þûŠTœs( îÖçS{`ø2ß ©P Í›¶çEâ[=’D‰ˆÉ·’Oªï ¤n¢ÊN߇´¼\™2MÜÖ ÜòT‡z…4žŠìHu*fØð²pôªà‰#N›8œÒiŒmº{²[ˆ(ì÷«®rÌå¨QݤfVÐa3ä*WÜɵ ÔÛ̽ïW5DkF£ÎÌñ  Ìš·äü_¸‰½àaP=§S¬çV–o߯¯+c×*:À±06P-°Àò»¿VÓ_óÒ†©ì‡^Æ1!"¼Hºž ìü†±­Õ¼Ô¨¨úšhðáúÖ²FÀoœóP®­¸EÁ6?5ƒY°ÑPÑPăˆ5žZŽéw¢”•±Ö,ýÀ“ÏW ž..p‘ˆþi=÷'AÎ!ï¦.æöj–†Ìº½aæ†áÅ \}ÝÎ?~Æn©ÆŸÑR|Ã걿ý½¬Xä&Å ˜5M@öj› E¿ÉúH1=Zv])邳) ÛËï›Æ ÅÔ’qaF6etÇÆ‰Šð¶ÍK€UÅõÉ„p`|2™;?ó7aߨÌlTz}T¥ÐÀÂLÐ.ÚK!àí§÷oß:ÊÎ=©ê Y\ÓAjIœü¢ý}k±èâ6OH†˜8'­óÄ)\KEi/VF\ÔÙÙ\9Q·YØìÞf¡kç¤õ9U€_Œ˜’€€«,f: Nú¦xé:HÄM~®·ðÝ ¾ ÎàT˜Ü·£è^ç†V)"®ÅlÆùÆÜY²© Õ%_@—cÀ!úÉÏõÌ”þ«®È¥VxÞ(BCÃ×£ùCâìjSmʵ¸ÆwÙÍáÚ(­zCÒHjt¶ñ¹w_½A&kîÉvHîá7æV?m‘5X¡% 盛ÐPbcÃk£¹PC—KCC?&Ž«–C—O…Ž®y.:5rÈfÄþÙžêžá~Ûð–s÷'Äõ8\þ°«T‹4Jä¼_ßš¾?âeŸzÑmm3Þà™?°c: íPÔ&ÿÀ&e½³Šè«~êãð÷Î0\_xHVË&(;ó±•td5BÎï1÷ªI»ì#Gx7`H*¥c sÎU“»Ïµó“6É;QKÆ%Ôú쑻õRŽSm[ :­+¨€QjáFGœ±c\@ÚÑ(îÈ<£Z° r`J¨,ž/Ùí£eò^åÆuã.6ðÎØRÉËZ­©º0Ý øÀÙb ’€€­†Š‡:_±ÚrLteß?aJ¸¤È[MŽŒþVo̧8`H5ÄvɯV¾<‰ø‹ñnŸ[Åié‘—V÷ÿÃF‰Är‰=¿zòÜò6Ç»´_;‰pœ¡¤I—i0[2þw8â6ZÉ é oÎóK¯½DÚuܸdñUc†›º1x«PVO‚!tí^C•‡ç’3züð5ÂüÜÿÆRÁYN¢Ìõs^\Y œKžz〩æ+F:‘ ú9˜mm‡­t¡«íõã“…ÇȃT”$›™)¤'|Õ¸³ôË=½[¯Äít‹+”.&¹ËžYŠ1ìË}4r õyé‚Èæ8Úp7­® ‘ ±rm»É%3Þ ¡õ?T¡¿ákøb´Y¨hÑã·W©ùÚql¦©‘Ä÷½ù_S”jÞô¨¤²èÐnÕÁŽÈj²kGTü×aëÚëP@ÐÈ32x.¡ ,0² Öxóåý%¨åI}«€”?Àj$fkÝm'îk ÚT+.¡ðÌ\> Í™¥ÙaP¸+ã7ÙEÓ›< +°kú„Gò¿c1´³ Í› Q>ÎèÃ&§0"gÌp–œ’˜õ±Ùå÷Ú%´s–¾ÖÓ;¡R‚X¸ ui’ª'“ÙU¤©·=›Î´wÒvA ˆVÂ(þýâÏ%‰'EBô’+/Ê];—#oÒ9åËÌø)©é ›=kTDvâ‡áÙ:7–‚˜L+ÍÅ*Ÿ”z¢Qk¬HÚ_9'-–À¦³›W™SÉêóVa,edXs+*éæc#ט Â}©?“³Úô™ZgOÚ õÛÐÏD‹¶m[.þÇÃÛÒp®Þ?‹!'gt,j™¨q‹U:%‘¼Gh6,MŠÏw [A-Øá¤dÿkXËÐ v6ö—Ï]ÈxxeÔµòiJ™ðÇâë1¹öÌßrÄ•æîF¸Õ½ú°KêËê'±ÌÏ]õŽ3µ‰ e]­ ß5±'KewcÑÏ@Ïç°F*i)ÇštþSWÏ@ñ¬ñ<‡ÒòÊk—M¦ƒ†e¥» w×±ÓsW4΋™ú>‹¨¹s!M(ññ€'LáͼÔD=9‘çþœ6KÉ$Å´^`ÍX>§XST×Àµ6ãçæcжàÃÿØéå5GW&T1G¬I•ê]W’€€Ò Yªt®<á¤îÉT8ï¼™l8"L—F²S.³½Õ^v¤(VSß’B}ÁÚ„zòÒw8—shÜk ¿ˆ*b­Ì>yàözb`Di²2б70ýXÁø›¶ýãÓ”¡æ’©z¥;1ýýYôãÙ>%¡,%…PÄç3È#œˆ L@M=T;ËxueîŸLâ鉨Ð.,Š¿T×Ðúæ S̰–Çg€ËµoÒF½¸QB¸Îµ€Þ´ÁÛœH<ÁlœúÓ.¢®ÃkGç`ï?bJs\ÚYŠ@ñ†Ì¯[[=*”y‹'=5H»{v‚Ãñ‰ª»ù,û$/mMD9ºJ_©6aÖÍh8¨è5õþ3¿b Ú 8cåG/™¹•ë=n…|7°ûöšÌljG´yŒ¹ ¡‚’Ô<Öð©‹Ç0mäSý”ÃLâ<–Ó;QK€ÑÌ çAº{Z2Ã^ß¹luÓ;¾N¯‰Òi\UbSª„ãAgVY<»ßZþŒ†‰ÚÌÇéÔq¼Ú Þ@}&…Á'Y WÇ”Uþgäóm«ÜJ°ÒÔ7ëMŽúâ`x^0ð—y“we¦¢Á&• :'„a1b䪉IQÜFp€vmú ¥±á‡þ l:alåÑ®Ö{« …¸BºÚ—lz‹¸?2ÑØ&ç­©PÓ ‰'c¬ã§Ð¦”ﶤûLRä\ãöH•‰orB ­7i¥mÞæùˆ’¬ïnõ]iغ}­C=ÑUÓ¾ËïHSO"yøà¦cþ¨ ‹ŽÀ…“3àÿj#ÛÆd17¨øKÕÕ÷ÙÊ5 1’€€Ò„¿/zý¤Ú ðÆÿžQIÿhÍŸzL£r¬ý+¸À+ˆ5¶IÈaÐ,3èáYk°;ªAªÇ%IµïŒ»Çnk*˜¢— ºhb¶ ÁE3“þ’•¤#ól ®ÚK¿ŠÙd7|Íyˆ  `ÖR†ö÷e€ê¾´ÅRΟQ±"G(“Ù÷¸†»ÑF¸ƒc-™Wþ4Œ‚ýRßXñ[dàMßÏ8×á ü nYxÄû7Õ]b4{L ýàøúN¯ó»<ôÏ®g£¾,^ÏÈœ²èãj\CËÍié§^¸nò`ˆ÷üÓ°ãá<,Åt\J*Êì+)̶`è>/ëjF‡n½m ]PC%£œ)*RžÓ¯ª }] —R E×*±£ ¹XÁ›ã µì{†ƒÔ>ãNÚ·Åvj¼Ì.jp EM_ëÆ;ÉÞÁ‘&Î; ‘ÔÙ¨Kù`)ä¼=ž96REÿv Ý~ÐG%U³•dðRrì/øÁ÷¼·Ã1õpV¤vRbÙ†ÁkWsºÉ¤%•d`Ë$c°'åÊ?¢æîl*ØÜ9QìÄ’Ï-°®þœY 𦨭BÎÅ+ž[ótñÔ›¸ÞN7Ó–Ò?X ›Âƒ<³¤ Ç)k‰Ðý&*‚…Çý,g¸ƒï5Áòsø™ˆ ¸¸YîmÕHv…ìö½O FÝ6¶¸jz óN™h! ¶›¾Àäቅ•=e#ûïôH]ZlÚÂenØ+b¡›§©ù¥¶ù'OèAl;S%qyK„}àSkû¿®ü!öŸ‚)‚¾1äɼS÷޵ÔW#:÷{ÓÞGüÑO<ÒúÒXBòÏ`lö2B&¶è #¶™I(_\>ºH½Q‡ùõþÅN°*2n 3ÚÖ™–“¾;ªEËNä°QêsB·ŒÈM,ã„i¥ë*83æ]öûÙV‹>;÷刚à ÒžÑs3BÄÑ:Û“"ñ-Ç4öIºÃ²§­Á)§òYU×±ÝU–`Æ9Xâè’0e£Š(*±W¯Š0¶çSs6”è›:QJ ÇǺjØKÍͤǽR %]­ç³ZìV‚v¤kGë@Š«ŸýKô.¾ }Ù÷çjD É>à¡mB^Ô¼¶’Å«ž×'«~úËsì¼ËϦ’€€¿Üçï•ä01ÚW+¿ã:d(Xð«Mc†n{u–ÛòÇ#ä·N†#¶ÅÝ F›B|-,µ¹¬ú”ǤK ‚Zî/¼OP‘Àž~ëYÈ|”øl¤Ž,hÒ7ZŠgpóm!jþoÏu±ñÅÏK:¦6ûÚa 4NíÇYÛjxœŽ¸0¼’ì‚æ¼î9^ßôþ­åïZ¨ü Sý“ÈÛCÀÔà(ì"ж õ•8Ñ+ñ]/-Ip+«¿›§ ¤ >×¡Ò @ñ_ˆJ’z©w`úúIŒåm޳b.–ÒÉTH¯ †AËö¹—銡ë†n;†égCŽkÓZÀ}ƒ[,TA9Þ=0Ür%JB µÅ‚\BU&ó¾•x§‰§£øÛÍ€c"ïòÌ0EýÛ¹¿)63"­È˜ƒÇôÌ('å}m¦.¶Lêøè±O]î® ×˜×éé= &VÄK%Õt{l~@ñ]ÓÖ€t⼈|²—<ÇÇ+ÖÝàXq>+½Ú¶ld…hê U@áR…}õ¶:]Çë¦i¢ŠIØZ Ç–.ëK éô)‡‹áº4ý4Ô¹mºŒßFmt¿oc¾àA•­Ù|àñ¨ÈÍD<^(÷c0¹%34†ÈZ¦‡1¯tQ㙄zîBÝ.ò˼ü»ë<©ó8Ím"á0ÚOÖ‚ê°¥YTþ6™gVËþbNOŠD½]bòw®aúK*]C°Ëh‹ñ§äaà®qÍöÁç¼Ï®jß,ü“ .©È‹Æã_³Å Ë9Êò^uüÞsçóO #ÌñšÁÚR “fX P·U,رMB••†?ɱo(’Kæ(-ßHÛ¦Ó ãß!ÇEÿYzoļ3¸I¶RÒ·¸>ÿ.Ž&J Q3ž¼Ø/¿ê–PLO+Ξ¥É𥰨`°-ÁU*Ù”ßɸÑk›óÞœMd?20— ü@ U8âÄaÙ·p3mŽ/XÒtáV>ÁÀ…½[pá©èY; ßë‰!{T±6Y§Üv}ì»jO:-tпtBIÞ—‡XÊv&µ$(´yo?¶ÃpðƈlÕd-Ez…ÈXPÈÏÓ7e ŽÒ:¢¦¾Ø0«¨RÃÀ ©ðñ!P£•ŠÛ*eIj?F2" ™á,¾P~{ÜÊÅÿНy@~á©ó¤cH\Óàp…‹ò9 ¶*m\€¯îù}>}qì¸?fWÏ%¦ä Sÿ¿¹ä?Ȫ‹M§ ŸN³ 3lb­uáÝ34Ýd¬Ïq ½¥Õø4>zÂa‰JË·?´½/ÖËA•‡$ªÏ5òHlÖêgvÇÂ_5¡vupmí±¡âøÎí¸4^Xíî2}5‚¦È ¹Ç¯:\«7Y‚ $ØóMà<½¼¯¹‹0žbˆmªÒ¨L÷©AR»‘÷6|¶a‡ o|y\ìb5ügòÖ˜6ŽŒ%hšØÿô¿ùœ6§©?…~:K'LY_–>õÐL…8Vß)ÜõõäÔ霾ˆ‹VÎ'7ÛÞ/"Z”´“ JÆÀÃò2ëvt ûÈ™ÿŒãYgÁz›àjú Wžkf:ª¤ˆnû‘-RTJJ\^Fvø=g§]2_¦îçéå (Ûj0 î:EÐÝO|5 þâë»ãuxÝ¿=á¹ÉXä3uʪ’€€ßF!›\6ùà¶‘éxÎv‹¸½Ò4‚z~ÞemÁ$A\7yWÀâJ?‰ŸjÓfˆ¦” 8Yà÷6Ã2ã«Ù‚™µ 'éômS-&˜TWU¢`zvpÅe5C=´*¯6æcd‚Ôn¢æÌ>ÐÈ9Phö{„ŸÏÓv`f‘ÿíe´˜÷Û‰9«~"¶k jb1XÏ c[ªH”\¿ UW¥ûØü Þ„ ™Š¾€­•Ù±ª¾VDzÔ67Û‚²â¬pã3×ñ‰]snBJeÓá1ÁxˆªnÎÀ€ÀA¯à¶o:J;ˆè@µLOWÆ«q¸{œÉ–›|%EMd'Öíñb+ÈÒ˜ú¹ŠÁnòWýU¡×{êp®…Œs¶ê¡ÐpIk}óˆ›(Kz‘./÷XæG |Û›J•5èõÃfnl•ÔѽÀ(Ἀ[åÃ~o™£–õÖÕÀMùÍ*7jz¥–ïçoËåùd[i%"Å ­zæf<õ”õƯÝiîÚ7M~o¬­göA\tæÏqﳘI³yäÛÝé FUåé}MŒÿ…梨1‚Mëø»ˆç!„mµl›sh›Qàßg9ª×BOSç…y¤BfªcoI*ͼÖõRLQ¦t»M€¨Ä…evJìáL¥è´C,ièãâ¦P‚!øâ’ á5÷Üt ‚üüÆ=,#œ UZ_( ¾¾¼HûõËCÓT2˜Þ·D£ŽŠ—¯ ZÇ rÍøô(>‚"¨£Ê½òCu²±š£2¬¶ÖêE¿8HÜÌb£N“­ßöâôÁè&í´Ïk‚œ©+.uV®í*¦™Lh¤êÔu?º‚¨åkæšþ9¤›úÌ‚šHÎÙ¨ÅÙ4§ÌÕÛ6Ý`Ùi‘Õà‡÷ûŸ¨{eHM„ƒñeÞ`Ð+‹À¤‘n‚^ w¢?Ü8vÜônÍÎâñ y\õÎí£¶ë1ÉâÓ,½º(?lŸ ¥ƒìˆœ¸ŽÉt-´ûXˆžî»QØ\uå«}~¹`ÈYÍã+:Ðç¤7¢ ÍèÓrièAãÂUAƒEo~Ĺ~iŠE€#ýk %ŸÐñZ ýg3æi©ßæ7èDÞUÉ EHtÖ÷kèy®iejTAºí0§ -˜ç>—ê2×+2Aå´=túá;òNT˜‘žÍaím”S*"-Þ`Áî|ç}—.ôyJpÑX{7¤N_4?#¢"hZ› òÎ| sj‹•UöÀÓæiá@å]ˆqçØÔŠ›KµcŸ@¾Ñ:`÷~»0`ëvе`Ù,ˆ|šä¯Óo÷ü?eáözáìÜ€R`ýÀpáSdN4u‹¤;8ߢ¶5ÌOWÐT-Ù‰9RÞïÎèñòúZliHéð¸þÏ<Ä00A#8D,“nÂÑý¼ÅYD¥giDÓÎ [¸¥7”°T\µÕɦBø*1Î%ËÏM¸**Î(ÇÒvÐÙ+alÑÕ½:äÞäê5ãZ¦aެAq6ØE-°ýÞŒv ¬, cNN°Å¸4l.’K×–º¯Ý:Â;©I`l¹p7ߟ¿8¡É€3Žüi¿QŸêyÓÕxtXpX´aº"O»áA@-L[ó‚¯Öƒ³ø£…+n?Û£]àQm΢úéè°E\j!õ”³›¸_®F¯û—xn·Ù&ñÏ÷…–ƒí6 6ÃQQJNڲȳ‹2zvneûóÔøšVJÖþ†=ŒÇÀ̓;¥”‡ªkçLl—¸¦¸õ¶¼ž“+¸¶¾€63Ä:ÉÉ'ï˜æN,BŸº-ˆ@RÞÓ×eòõvÁé-`:ÃÆ’Ä:úáÃ]ï$*C!cÃÙXMHê›j¹k-›ý_òf1 ¼Ž£®|ÓY¦Ô#}>£Wð”;q“^Ü~o°d;ž+ÄÊp'íé#Ó63q³ø‰M±š*n§È+CS”@¶Ùà¿ ïJ†Êb¤á¤……äÉ“ü.XŒý¦;ÙÖãBUÝi6÷QO 2b*Ç!íEeƒ!U`;Hʶ>kCˆn‚n€Bb:_« dI,žâΟà”q/Ž'¯O‰¶Ç7ªè½—=>ìó ú® öÆÖ§fôd’€€¹:1/Äi0½ØÈh3ä±D-*rêÕ. {߬¯ÚfaMµ««æÔ6àUÄÛµŒ-ñ¦_mbÉYà\H'Tb àÏœ÷‹ü)Öµòw'Hq &Ъ… ZüL•yâ=äað(¦£ÖóûÑKÅ—lêCkôßæÕê&>ÍÛÊVYHôß‰Í '7Ès2Ñ- F¶ižV±£®¸‡6©f¤igS²{E-”‘Ôêå?õõ–qÎVÅÀ#:y'ñ³B£É³ƒ¨ÀóRë”}𺖋‚C¡LÚ–ñÔ܇&¬\/î»_Ü Q(U˜”A*µZŠò´j¾²S›OrÕ®Åxßí³äÈœ¼4¾›Öä„òˆé…ü]D ñßhí²û%Ñ70\,~[óÝì~AÇÀX_~zM8JŠÁ²€.û4ù‡êýñJD4wö4â{—Âp)¸JŒŒçºx¹­zĹҀ;}B~…èÀ%h!•ÈõÌf ã¨[ƒ#"é{\γ\Ü®¬:Hýæ 4ÊX¯ë!þzº¥-/ŸtÂ×ÑQàrDkZ‚TÌ‹~–RRNUK[ðPíÈ÷MâŽ~Ç{ ”¾PdÊQf»eäÒ+y±'ÓªaBõ2QTm£éàqÊë¯Âæ}ÖíS{ê±"æ÷íp^z·¦úòTdjöÿW^!3ܹëÍt”œ®³ä,°q¾ª¯±ÈÍ™$Ÿ9 {£XØV=MÌÁtù¹#l¾wu³ù±´,ùûO§é!uörYžö*ue³ ¿ÎÍ`ÜC½DªÞ0¯åÞ|ΛF…QÃÐ U4ó9­Ç´ö‹~WðõYýëæýùRàäËÝåÃXPÜATUy Ô›’ os i½¹(©€5%»$%Ct'«|b°öH¤üQA7Ïo<QIôïÌ2 ëá²PMÕÒÌü÷>ÒÎ,ø v1í C(Ÿr¸Ú=„ºðZða³;U¿uÔý/ÿÇ’¶P‘€„Ôn~TsïÇYKO9åÀ·¿`LÖjwi`ÛÑÑYöUs£éÓú?0$èÍ¢óê+mƒ”Æì7s“EÝ)øaP#pjÜæ°‚~4ò‘HcðÏWóo"íâG9Ÿ?K9°5·´'#b£| V€ Kh=è„—Ä’€€±.<˜‰ˆš/jçÕí“Ff™£óUãøŠp·èv@oèåÛÆ;´- ¥ÌÍ`÷ÓÁý¿eZ){ÖñHNň÷Ÿ?^³š…ÍZƒÓw6•íŒÝ¨ÂÐ GPP|¥¶¬\‚éÏÏœ¡ÅÒ³Ý+y½Ç ð_”3'öè€}ç£ÑƒØÃF[§/N;ѾÄXü/@z£U²@7MCŽ€+ŒD¼Iª\rcŸÀ&O®N *íÃ$}ü›ë$׺ŽñÊüØÊâÇ0Že¦ëäO‹ãÆ£c6@`ÙPQñ…÷hÖMeýÉÎîÁ+ëŒÃ^È?*»InÑt€¿×Œ7yBGÆ xG-NšƒcaÒü¦”‹DÉ;Fè¾ÉvŸ´äJø8ƒÃ×ýÈ_ÇþLVøôç /,ù‚Ûþ c³+ÿTð-dIì@KzM,ê(ê ,å÷ôµož™²²¶Ž¬ÀMämƒ¯>ê@E“¬”JjW7ÔWp¼azò|™w¬o÷ô…zä "-Ñé÷ÜóÆ7{²ÜÂÖM-î”o%9 eàlyЧûj„ä‘ÿ½½óŒÿáÎÆÇ‹r|{¿g!Údftè´ytÙ¼ 9ñ¥»cYv:}‚ip˜S(ŽL7÷¥Î›jÄ(¨ÌFJP,%ßUú.Z…›åe²©²#9b¥¼Ö¥Ï v£_[Qrv°1D§]k¹¸ÃÈ>‰/©ÍÞ®€Ký'/ ‡¨€ s—^,%Å,çB:&‹ýûK£l<|ÔÜ"XfÎQ™xî¾™`c%MâÞH˜s¯+µ…êjµ¤¶ñ'x¾™Â"¶ ~Æ"LæêOÅ£õƒ çy®º½•ŒŠ¶lº“I8 ¶¡ Ð ¬/ï):˜£¼ðò¾*ªDEÌ ^X-Ç¡Úõ¯_²ÃŠÝ]4¸U|#›áÅMS—êÖÿͨµu0øRòø»¯†s7P¶ˆ\ZÏ7Ž æE>Œ7  cñ¾¶oO› y“ÓÒщîõÓº+ÔHõ$úÿ`¼=¿Ú¢àwäî}ZÁšNßùÊ ŸßrNø!=Š% k r¼7s"£4Ñ5Í ­’‹a³têáÞUÄ÷9Nvåò¾¼á¹lïŽÏÇ ýp0ÜAdd9æZ“òAXoù凵RVZ0ËÜ["ÎïUU ý’€€Ñ×6 &–•nNG1E_)(ÖÕÔzºÄÆåC`ÜyÙ¿+‘OµHœŸwb-µëƒhžN¤ 3 `Ïå9‡É´¿§,=>8šœa[¶v̯µd°¯d â´"J)g1¬sH¶k6&]jâ_Šúø7$·} ®Õ[çˆÝØ¢þ!Ëlé³z?mØô9.äújÜ~¸»¯_ ßAáÞs'A6TÎ|Ôë_9À]ÔlIC #‡U&FЍéh)kY­\½û=ìyÅ€å]ý«xÑX­„ˆt± CΣ:²E_Aò_|pVôÖ‰Bw€ >>! qr?æQ·¯Œ Q¤TaºXu*{²o]}9]™(X¨Ê6ªÞ ’ä$ËÕL‰r¬°ê•ûTóDVh²PågÎû“©¯IׯÙ‚Juªó*ૃ2Gy Αiu‰O#°zén¾Zú¡"ÍÜŒª?{¤v¦-\pŽ$mÓãáð0d‚H›¯Q%"}V‡Øu3;B½¿sš)½*>ŸÎ+YIœˆc’ؘü½£^°NëÙXû2¸ÿ†§öœ ¨¬¤Q¡—ÆXQsöM=coñ}1´Ø;æ›5¶ÏÅã½qPߎJÛPê*ÀÚòßñ¹bb¢Þâ q?ÔôŽŽãr;1èðxöôöÊ u42Å9Ùìyy<ÜxnŽðióFgCÆk–Gô¶tLÔ*iQã­¯æ"Ÿ½á &«\€–ÑæúcbÐ ÝÚ!P>å-#MÝ—uv@Žr)u*vCO|Õ<ßã¢;‡oÕ‰«ê­žÿЍí’>$öƒ0­ìuæUšõôcpöïfÌèÆ’G·–ÉTêe²=ßè‡WxžÁ¦SëÏMµn%Iï+Ú\¥}­'g²•Qƒ“°Å¿[ ž£ãqKBÝ;1ÀÞ0,ùC‡odÐÖZÆhK³ÏGGØ/ôL¼ÍX±j ‚”hdŒŸS€/‡˜—ív¥69’úľ ¹'5(Xì±rù&öe ˜øÍá 3¹þ`5–쓼ÇÊçGÈìæé¤Óùª TõìÎÈf ÜÓ&Ú‰÷Ã9¥êÔi’Ã2eL³Lf™{‚‚>µ„;®O”=^¥[ÖW=yÊ.xÿ÷uü½é ˆ…ùGA8ÊÐv!’€€§Ü ó¯Û$ |2~&4n§X¢WW}Nûx|Ò×êæT`‡¹:CHäl‡LGa=ïn\€²6P®rœÛþ²,^5ül&fôl?ª”³|cÅçËyáï,íøÅÆA¾Ï~õ{Kl»íƒÙ néÖGíû;%(¼ÞûúЩÂÖâ4Ùx–s>Ë“õ]9«Û¶u¡!G7Ðé¡è»T(”™£Ö=­Q®éjæ¹±BzçÚFä[ÅZí %ÖÖýx5$,ÈŠþ~<¢u%xlöå´ÙYÍ…Û•‘µ -Ω˜bmáVCæDÂÒ}JLãÆþó0Ôܬk L/€ÝÃxfâ­ÆX1ø?‘o†#9FJ,@Ò5Mnÿpd¾#O7»‚M+¼!ò‚pšZW»ƒàbÉ%Ìõ hÊ• »€’€€Ä±ÚÝF !íJ‰:4êñ!¡ïbçD¦x®‰¦âs 4e˜i" ¶Âª@ê$„ @e¬ NãëF­`”C²ôöLxú‘£ çØ’þœözË`}ùàZ%g9»ºúu'¢øÿjõ…Ýð%¼ž¨:aálvU†L{ëÍÔ“ß1–ï{eb0pbÀ×g7ÉßÛsßhn*Š9×É’ñ—s[‰|ëè°‰åq¼—.> Õ±{-n'Ñx'àÁÍÐðÆë Üݬ Ë^kQ0ïœHO_Ø@Œj½½´¹~’Mfÿõ"¶P †€¸M7ÿ&(*Ç2±B<¦tÚjŽ“· Z¶<>Â5Ë¥;4 Ó.±Z šXèTqm@m¦Vû¬;«n¿)žÁ3žßšïk­R_ë]CI7ã,Ôˆmû{|Vû{iª˜2Wës¡ìZ˜¼hÚ/¹Î,þ>?â7ObÐðßcAŸwt¡ÉÌž»yLøîvñ¿È%ÄWwjíÎy Ü•xå¶WN¡º]Ûtº_úL"Ë8®ÑÍJ)²IðÖP–¡ƒn4£¶ÉY¹F•ëz#@'lK#Lñ$JÍóF–ÚµaîN™ãµR$ŽÏìì¾ ´þ©Šåln+¦wkM{™Õm‘x…á'Cø>9¿-l˜(Ç*Wò)q×5kð¢êTzRaývš‹ÁÒ} qiÍP50ä8·x––QXTœûކþTFÄ7„è†5o-¸äadýî­Ñ»½±ÉÓÛóyÕ’¦¶WrË5cãÇÅašLÀx¼4UW`Þª­Ì0÷“©ÈeÐɸUsEvÞDÞôB´¥ ÛO»9«°õ¨EtßÜLJ0‡L¿ÄkñâõtìñP}w÷ÕÁAîÅÎkVv2Á¥ª6oþvžXÇN2§ÊQ0ŒùC(žîÒG©gR3'çÎF%@©%õ£{PÅ#‡Z¯upÐ<3ÙÐTÙäÏ¡ÍnŒbáÒé‡2àG4Ö£ƒþ¶ M( qÝ)ÚàLeþÞíáúP$ýÜLú¨9Ü#ý Å 5Ž_ËÑ0¼³›_A=â¸ä½`X><-Ç^J’€€×EkÅÌ:K‘JÎÞ`â÷Í¨ÈøÜŸšýÛBN‰«×¼TòþLµ^áq£¯®¾ˆd­qZÕ8"^U²õü§â™/ck†i¢¿°JäôC*dåM¨Hð„á6Xk«Gdñ²÷±¥é›žNÏø:¾Ò/;ÌåsRþ¥qú“߬ÒHu+€ÕRr²D{È=¯Øk>¹G:;ž¸ZÎ$öQu*O¦ÙF…ÿzçÑaÌ~@Á4:^µÉÌ<*XF °igq¥Êä9ñü;GÝ~ŽÒªàA5’+¯¸þ•$XRß×v¯•¼a©ªçÎM1³¡BÛþ£‰s¤„8ðž2GCËy‡ ¾M6\â‚÷Œaž`VTû4‰ï”'ÌÈ[¢l&)ð™oÂÝì,‡ ÷—uº=XÕ˜Q ¢äiã‡uw’§ËxY)N±GmëšÅnŽÝæd±8E+éÄþ·ÑÍ>dpÁÒbhmÒ6‰›(ìðÞ¬ÍA#ÎßY§À;¾U›À «O¤Ý²ˆ¿}´…1–óûÁA¢>ôòÛ]ZpS…*¹'ÁˆR® w:J“,zãðãØÛ‘dÀ>‘þÄk\ k¯çôÖ¬ÛÜn´­)ûHjå”o-;™‚9cˆ¸ôó©bãÚ48xÂi–˜q¥ÑI>BìÎÌ é&ÇËSÓáφnǾðôú²g©Wr³šïîÎ[ÚÛyútpJ‰6Hã/Ò5Z¥´9A9¶äruy¢.úœB/KÌIhË£+ævbÁ¨qc$P›Møwš'’€€Â)©ÛŒ'‹¢§:8Ù2ümøÛÎ1•¹ ûÈ&O®â¹ƒìð;``³Æ»‹øÓ­«¶}vÒƒËÅ}ÃÙÆLIR¤à{8;âÏ£•µ[zô¼ãwëâZ²g£©ß¯EÑ™Œ_®²ßœ´ë{ MÒƒn ŸGÙ¬úJ¾Óe°7¾ž+þåU/nE> ´èžý‰ËëÙ¯O¶üÌ))ƒþlÜa§" y ]î>!ð88"©nÄœhG%BÇÅ=pF«ã§‹ïs oÔ Ë\DºŒ(’•'/T‘+·¸4^ë½:4$+¹©ôj:¶T!ïÆFêíÿÜU_ôóé‹´–]·ÎììéùHŽ´¤DçJÉÅx‘£õ&ˆÑæáæî'£éwú·±¤}ù3¾n]ÂÄÿ0-MyœÇ c¹íGÍ@ Àºûýcê4µSIQ­Mï ¯®#ae«qƒ0ú†®C JrÐ3hýQe¯u\Í0·Ë¾ßÆTÎ\ÒÔƒ¡±$ ¤Ü"+ G… Œ',á•q7ÖiQS¼Í§óv‰Òï}3©[¼5ÒÊM&tiÛDZ—n[¿¸‰#‹ãBrÄ·UgC•±žÏsgÀ›pÕ§¼mPDÚ—¹•Üyb3*áëIæmãDz©*¨mH“Ý…³*ñQa9Â'ÚØ±§ðÖ²6I0qúHÀP\Ù¤oAáx¸ÛHêol6£_2Ü‘q§]ätq$ÞÅÙ‰ ãÛz?ô¸”5ñª:y\îÂo´æ¶t>¥çé«+E&.=pë ¦øJÉr’€€¯§q§£ÛãN‡¥vö™£Hm/`Ì,õŸôuÆÔŒZ$‡“¢Ö¯ñ‚͇¤ÖÙ9I‡ýNìçI+£1:p¹£«Â±ÁÎf÷I’)¨H2¸XxŸóB¦Aã =ÙÁ]ƒ-/Îwo¯lµ”¬-p¸v1ýà£ÉÛ'j׌DJŸÜþš8¢„ðÔÓÑyDÂ6sŠ0m~‚ƒÖÔ Ñ¸Sý¨‰bK²slýÍ>¶Û¢‡R8¯œ;¸`ÍüÏ5(ëô¦Yâ.Ïšj1£w@pŠ™¶|@Lf=ÝáÍœ ZæýhÓýö÷é=˜ôîu4)Û„¸™®öè÷¨W¼B>4ŸçLä1@ê—‰Ú(sÃZ*<¾“vC~rX•,³³ù£;¾V Sý¤Vû ÏšÚÑýÞ‰içGÓÏ×ÕOYçU’m'A¹UÇRaÝδ™Ùài™GºÖó×nê¥ (QFÞ}6FNH¯„œ¯&ƒF~Š…kŒ„³FíàñbÓe¾D†¹ãþ -Ój¹!ëúV*îIÑdà 2ÿEÌžpÙ˜ýS¤ ­kï¬èïz”Èãž{ ˜ðkïOþÄ»H†lçb  ÷)B×oµ1ˆ–ó w6€£è[?œ Ô”–¬åDaÒrå鎈ž¡…îÜ·ìcFãö‡Üej½v°}ejn–ùàüe†¶ ?ME »8^áÊÐ,ˆÝÊ0ͳwþîª+bæmS±L*ó‚Vý¯+ÐÒqóí$ˆìσNÛØª ün圳Ée "’²“Lÿñ½Q9©ÿ8ÓFSàÂOòbÅØqñÄ‹¤]»6ÒåTÂþ7¤¶zi`ÞÎV¬{‡È¹ÄEO MÅÂCüÖ?}\¤'åÚþ¿œpßmëÖFÓܺó<~f7"8˦¦¹l: º*ËŽª§p©IYžØù¦@¢i“ˆšÒ/õ[_ŽÏÚµ~Üõ´Ç,-jFj! _K×qŒ¯®Ët±Š2Ün3›pµ«×¼·v5©Õ¶{hõùä²p!ÍÅ(z…pïû1G‰,5yõ(–Qr#•˨ù–?±ižÀ3´Yÿë}O=¿ÕÁI£hWKæËÈøH>)$ÔÓR1Áù0ß5Eïi ÿ åÏ š„óýDxxW7/ÁÏçßr&ö…[0§1LK·}²’! ’€€²'u ;i·Åìó}vùŽºp°)Ç®8G„Z¼S@*Dï"ÍK—ö¦ÀåôBà;5¨PA-‚@‘ŽËëõhÜKаhQ×ÚÄ{ 4òèõ3“b âzEËJ ß YÝ×Z¦èæ†@' õZïºag@¨4Ùk±{ÖÐs΃B*Ž»OÂá<ÝBü~¢©SÖyÊ/ßß¼¼Ï—S_\;îÒ¹œËî -­^åÓÁêw<”ç™éwÿðßö¶·®òÂæ/ ƒ‚óhÿyéå!4ù<»*þLpË‘yÏLUðè#eôdƒ4~LÈC wÕO‚Æ&£~pžÁ;¦4Üy¯Ìiƒw%æþ“P–9’µÖ­´ðŒW+K¿ÈÌ»‹Â?Ñ·aÛÈ9±Iïp9M+#ï{«©=Ç-§šÎ6g¢Sg[„@´XOJ(,)Æ$·e­aï¯;ÉΞaíýAúÇÕr“óö^ÒG‰ßON:îsýýúíí6òƼKÜ5@ý&âÅ|ÙøbÂqBð"ӬеÚÎYYÐN+ßoš O»Ôr)à<‰äAšÂ@‡vܨPÔöh§Åí”×ÓUPV´©;!:½°@lc²“  xhŠîYÝÄC"ƒTÜ×)ÏY±áC tÔ„=fàý€’h%[Ìœ(SñµÍíÙyô&°+{fØ’›í*…A¯/rã¿mE*pëúg°“ŸdÆ<ýz€tå]òÅ aÆÑ– #üXçÈç¦9ÕEXÖôÞ^¥Úk79`tQÜ)ã}‡PAe ©L¿j"aí0g ù„üӣʤž?Ê¥u{û¯u¬m ÿ‡î™õѶTÄqb!Ÿ8@¯Â‹pÃUô¯_½}ð«ï¬‡ä¬'p$ÀÈMóv+Q yIþ<×´°*fçˆK©õK'úc™Ç&ͳfׯänº¼ Ù’,l¨ƒ@»)+ýÚ¥µÇTuB'V ”€„cy¯8FÍlî^ªHfÓ#åâ-×ÛŠu´1¡öó>çŽNÏí ³R« >³ô=Aqß×x½ãÛÖíq?p [{ðKôÈfÄü”zÞ/ÿѵmé?ð}·gYÕ.S<7ƒëÕyò üc1h +w)¦Í'4Æ,El¿;TðíWHÌD=…B%†?"Ϊg5;’€€Ø¹³Ëoh•!ã.ÁlvŠ^×ÿ5½A¡Ô“j¥ê¦8dAæò[và^fß:«œÔÈȬÃèíÈNÒGC_ú«ç€Qà€ˆòæºPø©6Üf/ìë' ŽYy'$oŸŒ¨éaÏ‚ÊkqÔ“ùóP¸–­såðfä„HÓbF@qtÀn×'W<~ìÌp^íÍ»†#yÈ‚Ž.ÿ½Ÿ"¢îIK>ÌÙÿ5Ϙ«n«]××ZZR?PãºoóªÁó}iC+fÎb2†õHhñ㟤›ÑÄå!HK#²KÓÒ|?&¾>8NµÌþ­õuöOÄ׬üJjy"ñ·2U1Ü@6È€f•„™g*‰ïòÒ“F¦%ÓŠõ:åМ›‘Ëú€½é%B6â–û ÿH&/GÄ}‰™µº'm»äO…ÌtØApqå’êåÎΦL} MµÌÔü¢’ÈO1Nõ±â`üù÷<…Ú²zþ»úàÞŽ+‹ýÉd̵Ua3kèæAË%‰@Dd7M,¤øõ Pâ&©¼y³Zb&˜Ã­´ê´™í,ó=º7È`u²¿£XÅ/ýŽ˜±èÉ@ˆ:RXQiä6]_ÖŠ6Æ 8%ùËñT:Ù¨C¯6Ëm Zz^z>öG»P=lÙ ªýÐ6ÍÉ+ÔÂYbp(ÏÈ_„•ÍÇeëÞ ×}V@äªÑäH]ß¡{¯Œåvpz¯¼KÖ){ë‰É¾ˆp$‰³œ1¿@µ’€€Ëî=é»ÔØrc”q‰6åv¶ŒÍ ¿?Ôæs˜nÆ™¨™h³â«4CæñòYcw,‡Nü&yJºó,Z½ÅEÅ 6Ô¼ ³Ä®H/*eçAÕ6ÒÎ AbãrzaóƒÌ”ÃIx/Y¾WD¼Wr1Š–°LX9GF©‚m0 hCÀ7ÅÀ=HnÿJˆ¨½P^.$ðœP8ƒ–@ÿrÇ…MN*|ä¼ìþ’ÿðÝOaCžVÔf a9Ï.óÓ†EùEg¼‡>øíEÀÖö¶\qfHšÞeq¸†(УF[ÜÖÍðÚÆ$….¾@´b¢E?Â(Ø‹=½_{üûš½—¿RÜc[ÂÒ ÕMs‰‰%0J^ØpïØnÝðFgøžàJcÆÑã®é½Ü€óD ÷BU—Sw“˜A§?˜(4+‡‚ÔÊ×É÷Qª¾0kªêxñ(bœ¬D¿ÈˆËâûPa¹]n…3~›Ú1g?*áË]á¦{N•‘dÂLBÝ[€B y¤&j-àÅLŠŽ¨Û+¹ (ÂVß9¸¥d¤-¥ǙՎö4TüÇýëÅKÇ+? uœg,ßøã˜±I{r¨ªÓäDóyéP¬%Ôhòâã®o› ñøaÁÔîu±Ù=øcTYÒ .~+Uˆ¾p/Ê]_ŒHk§²—{0¼‹Oùž ‘œË‚ìèò“}µ˜Ù¨æx }”òOÙ½ï£îVŸ¬sT×:Ã{‚¶yE-ÊJÅÑ›üw/Ór±é²¯ýõѧûŒªDØxÓËNÆUAžvS¦wÒ/v|hpí¼òe~q™‚K젨߆ǻp¤÷Š"ÍÑj‡FªÎ.0²ËhøÇÜò?Å S"Úß‘ߎ;AÝ”@í5uÝi3-‰â–š(ðcÄ¥ég‘†Õz 6/wìd†æ OfÇÄtž)3ís´ ©O=„#á‹Ws dý‰X§tÃwEfUm{ÝQRn6VÌ]kƳ”1ôèLiÚVÅ!=XÚaFó /na"ßfTJy•ó^—À ¥«æ`1mÄu~ôƒØ-1p % =Ôü ~ªŸ#®úý€&Ïï fiu‰¿KF‹©8a\wì-â’€€¯ÌÈôޝËv2&&äInQØrMd„ýœ»Õ[Ó÷¬äšÃª†Î7.^^Ê4`„V)Cè –‘ýy½ON1óõw’øtÁCñrûÆímóXÐMûgÏP… ÄÂÚ/YQi…Š5óß\_[’ñ¨ 5 ÕÝìF4¥[|‚b«æòåp’þ*ÃCÖršð,tŸëG AèÜ”f!µ{£dW•uÊu"5Ø÷î<¨ê\TÔÁ|«š„9ŠÍö¾h§†|îFÓ†“›pK’WÊlH³±óÏ_È1ô‚6šÒUýø&Ù$Òz¡ }øž´ˆÌj;çöå*˜{´gK>lëm§fY0<Œÿdñö}VÔ,ð)q¿eQ’lëÉã‘‚é`Ù¦lÙˆ-™à¬Ó­™µÍõ´p¼û ~4†cël¦òƒóYùBãÞL¾sLfžŸð9.A@ÅÕ?YÒsFo?!Ù}ãM<¼ôSÐ/}MÈ>Gâx‘q›³ŸvxÄ0÷Ë öÌžõ®3QÐÂkóš ºƒŠšfÚ´[ Ybä–gT¥yáØ…R/jõÃfyw‹¾Ì0Ì~¶)ÎFdÿ”O€Ù:¶œ,ïÍ­¹SÚ9‹˜È¢:I·?n‡*cS¿™€¤mHo¡"¹óëFM|û´¹YH>jÁÕ¦îlôFN?JÞB )úöc&¨É…aíyÂ#Â@©BÙš¸j´p¶ÝЦZ;†ÅçÅãyËÉG±Arô’Ó):=0EëýW'°üt5^¨Œ%Ì.¼v=K$Ó^ u_"_I¡.YÍÿ1ÎÃqUêÊzóQ•úsGÃë±Ò¤D9Íâ­Øtìt!¯Uµ­øÑ:ûG‡ÍjËk…Ú6N¡jv³jE?„¨–?/Á“mŠÎº'p™x'¤àßRþCBo×> E6ô#$º¶˜¢M(”V°÷ce¶‚{XµM*¥óåæ_mv¢Ý·ªï¿ÿ½þ;_^ï3…_— ÈOC F \%͸ô®§ H¨‘]­ÈÎM‹/Dñ±yNXÝ›}—’f­ß“ƒŸ„†Ï*àLªÞ\ŸÖºe´8?y7pý`Cm5öÓSo}~s&,6Z´žF‹Øk¬–û…"Ú–ŒF"®¯ŽR£¶N‘Ë}û‚·FÁ’€€¿=©'X2kpmò¿}î¥Bb¸UI šÅJ‡-Î"åc±u8ž/„-ІC®7¯~ Môôt9 >ûÏ-Èbô*Ѭ’°Ô˜pìÆÔÈY(¯YÃCK×/ƒ|YÖé…Ú] )ð½Énð€­@•†klÔ‡XD¹¼Ø?´ÍHˆ$ÆèùèÐÙ3Í[m. ŒWûøºÁT;>ÈæIl‹Š«uŽ*(ð`¨ñz 2K‘4']ÛμMAE‚ò•‡ëânŸ’þS)å—¥[vÙMNFЬdôù¢à&[Œ³À[ ãü;žÆËýàmñ†ž/`:—&e`»þ­ Ä•åß™DßBŸÊ 9õËÇœ‡®¸ìTÅßxOVRaô½,%ãÏ& 麚òs¦=cùê=QÞäü[V~Š?Ÿ:Üü8HJí)…†[«@UF„&ÚÌC³Õ8 b[þXèš[Þ“¾Þ×{¼ @¢Zµñ„µÙZþ;Ž9Q)]IF@à$3…U¥6ó÷Q“²ò0hMNª†\,Ÿjq Ae¸+ϼ£Þ1KåÿÁB¿~•ÑF»:-AZf…ÁÔ\Ëûhû+>_XÃ*.,v«#ÔnraÎΉÈ‡÷ÐÂt%Á^í 0+F.ò]2L¦Õ’Á5G‰½uƒM§ÌñsÛ¿Ôqf©üïᕇ6‚ôPÅíC–Θ¶ÿ17¯«-‹Roò=6j2slÏr)m •¦ŠÊÈSœw“L*ÿ!oj ùÅÌ€íDÙûŒØFW—ä'­VÊñ +¼¿NÞB‡lÅÓ n b¯þk-B_øäŽÜÝRÃ[UôòSø²¼oÁŽ„œ«á7ÉÔP7À’úhK€‚ø­2‚¤×gQ"qï °…¢{'ÏVUàÈÃz#”MÌeVÅ ë¶Þ½5U÷mà“«ÂS´mqKÛ*-ÒŠî ºmœÅf¥£€8š03è8w'î¯ì±îpY6³òV\¦[ºÚŠÄ“rµ¸86*Ô¾èJYA^½éj4*] <à(—[­œ<ãZ+'M7VÜ4ˆ&Å•áâ;_ê¾Iºf²Ì¸Í~$p¡Ýo´j³¸häîO÷ËLÂÈâ-Ü–P!Æ1À—W-&üZY—IíÙ’€€³¯UHk°/Vßu(ø²"êééŒßʬç!ö¥Ä3‡gŸ%)c âõ:IØixd:{ ’rI¡4þK޶NªÒV§îÔþ Ÿ×ô6€é£Y×û–ÿú¦Áe•±'õýßlWÈü–þ‘m©¼‚XBàÙ^*ô6_Ø‘¾æ¢‚÷vTwÙf/:\¾^AjßÈ^WÇe;ÙZªêÝ‚Âë¼4L7b?È”exâÜãÏéùš$gCqÈ”f¶zÆ—ÛáC7+ªùåV…ê4]E=ÛVPÛ @@Ø_Àgb÷(Û”;šÕà¾8ej ¨x{BâM[»jb~ñ a¢¦ž-÷dhêfh {é‹êNÃbR:2C¿8r‘‹ÂLj„£P}ù€ªË…•óÜúÀ™‰ÇO€àú†©ž¥)#XÛîÂn­×yÍää³Âf{ þœ 1–ý,á_8¦¼ì2 c;glK[<Š.Ùà‡½¶§-m´BtAæ˜auP@º}¹H$Bvé<1Ü:}a&Éš=Ùê‚ÐÌê¿)±SQ¡MÊg\ÞYê#À‰’¹‚^“BAV7 ±}l+sÜÆÆ’ußëa¢ Dg`:±é+úÐV;Öí׆èWôÏhÖH­¢y!·õƒ›ª¡Mš,°™@ Mnm Œ»–ÝaÝ:í¯`˜»@­\çÒŒ>)·&©¢­K%Çl)r¨ÇÝ&k#¿ŠÙ’a/&6Gb?‚•^mŽÛ~ï` É\21B飼b»8x%„—+xQäиÂÇs[¬* 6žL¸.½‘a0ÞU8çY@·Îï ãÙÿÆÀµg¸,b†›{SÏì“çÏ×´WŃ'9?Û&GÌÜaNÍRIpü2+ÔàK™½ð°Þ}_–¾ékTÍ{Y5«ƒ·“i®×ƒK¢I‘8·?f9G•LÝøßý=ÀBA/eé=¶)dz\X¾lýÌ 5srŽ*(„Óï8§üÇwÍç*ˆ óÞáUÎ…>©*¾/—¸h6µL"uÿþö¥¨¿ °[õÓ~½7_Q0xUzE©~5l'e`þãúHs&è•kÞÙ‡/ã`‰_§ÎêÜ =Å+Y—¯!aåû]¬ÙÖŸ+~Ã&ƒ¢Z¡»®’tÙz«¦¥ºÞd²O¯Ë°cŽ»ì’€€Ù*ûÑ÷¨ \»K}^ºIxWYH%=)‡ìên¢ôÇ‘7®oN\ ÈÚ ZVJ†äý[¢ø_0•L2¨g'~`ï8ÙUdV €§íæJCßV-S^‚]QuöKäñÄ7á6Ê”¬!ÁƒèÍtnZ8”â¨{Mï †DOï¾ ™.t¢¥ßZ6 {Aw[³kSœd¼1Þ¼V5ï2´ý—ÈN6õ<°½ÍëXé3xZ1¶Gƒ5€dl€G ë+­ÏÑÜÌuç·+a|ù= J ˜Q1.j½pÿG'ÔBüÑí™*+oDVªZŠ|e ¾ÕÚ $Q81xñ»kÊLZÁO˘}EkE÷´®›3Öó3‰“w­ '¬Êãöò"Š6ùn&Ør ƇN6ƒ›-á"©:ÚŸ¤ÏÞ±ªMŠËÓxÙq0S(õ2ÚIë½g£UxPm“(w' «¯JªoÎx´,—pNG<)írÀg40¯<3rUÞó ŠÓ¹Ï>¼1Ä”›7¼09ãnrÖÌÁ!$°™þÒ¦ÞNŸ òNzIððˆÕEåvž3àªèX$†=2KL·é·_b½Õr8ÄÄ >ˆW~;id6&­øÕºJÿ)H d%ÙrÍI$êŽÚ˜säÝ· +Nƒó—Š ù2LÂeÒfžQ/›éî:ü!¥aâENTj€qå‚ âZ‚K‘bÿؾôx›‰ feúK$Ô©8òë¿RÂß¼¶ï¦f v*䙦[—4!Â/(OÞÔÌÁ`ï£RºÙOˆQa1š1m92ÿöÝ_Þ§äKQÂä:ßP_ ÖÇ5¥g'ÌúŽôÜŸ‹+‘ð÷,´¶œ•‘«\~ŸöÖ.n 0ƒó°(ج‰¥äÚéöÍ÷äòº`ƒltÍBÞ‰éKJo󌃪pǬ„·Ñhe#,úv”A£ .…u+@ñ’ õ¯VÕð˜Ô .;ä;‘ƒ‹NærN¢ªïzçâ#†Døëð±–|K[÷î[¤2ò€ÿ@¹PÅ ýðOöÿîÆzŠíòM]âÛ©ÐÛ™érºèíÞUÒ¨:ÁF¶2ÜJ¹îý %Äî'ŽÛiï?:‡—¾ï/è¾þ<ØÂûiÃÈ ´˜¢Ê/V Îζìg=²QBÚ BÚ'o’€€Å„ „^*lc™¢lyëfÿÄ?ð0§ãv(pÁÕ Ä…«¶íã)kV4|ËD¬CÅ꜅Ø[ê½ÂÅÃáΓJì6EÌF¿dôÑ_©wR€}Œ'²2åæþ„«Îé[c…x>¾Fbw/í><š>O{•Vë§@¯‹Kh´u~3”|õ£“ÊËùC+´ŒàòUŽlK|ÛÇlzvEhŸ’…Ow•S*ižÜû}Æ¥T@2,1|Í  VFÇÙ¶k¨gƒgu^ºs`ñž÷S­Óðö}R’å~8êû‘èÝ.¥ NѪž@’¾ÄOœ/åá´ÉhL`-B•ÛY‰ »Xõ]õtõhŒÒ’<°aš3ðvŒ¸®‘9{ùÝ br2Œµ+.*Rx·­*fÝ]‹jiéq±NUì•XîA"ÛÖ쉨pšîzÍ;ci¡×JüБt$šΑž &ïÚbÕ·ß(¦–¸¾9 *[Pm 8d‹"ŸÄ q|ÀJ{€U²ñjE{uðQ5׌}Ê3„´Æ%J^Ý(³/,°K+‡Ö+·À»*A»g†i“Äßü Å~+“©§I¶Þ(Ɉi°y¾(Ò›ÑЙ\¿xýlï<ß0ÇE©—OZ°M]?ï×(Eë~ZHãw„n|i¾éOæbå뎮ý=«~³ðþÑl°+cž´>ºJR‡ mhvX{ÒÞ. §‘ŒK‚ä?C¾%u²ÐDûÞßj}hFÄy—ßb Î›ê8LGÞv8¢°fàÙ<#¹Hþ˜ÏžÐbº­nϳa5¥VtD ßé•\@º}sA ­GTÐñÁa7?ONßáMÃלm g”–â°±\Þ Ï-#ŸÄh€;Uü;såQÎ-†fɾ޶ž”áDlÂÖƒHGÌ:n§­ÜËjf ™IPãè*Ípe„Mù]Ìõ !«6ô¼¦Á1®D$  ] ]ÄEE³¦ Ž¿¿ÚãÃ_ejÌ<èÌü¢g®´™ZtlÝHãn$­ °#»ôY©5«]‚ýê˜ú]–êC$h ¤¦NÉ Z»hW6*½8h)㮚Œ8›lb ^]¥4“ðÂÄ^¸B®É’Œ­Û›ºU™&1Ùá!ÿ<:£Ñ3‘„ŒöžJh]˜ ÚÄ3|8FÑ’È’4Y×"±_àÉŽ ;(©‘äåaÝöš‹ Qa¦B†×q?¨Àø?¦•RpJÖ÷£ñu:ükº÷Öf2óKÐÜM³wQgÊ ½æ ¤šš` èú¡Øéýo@?À8×]ÿ™3 òºpº¢É6›¿ŽðÑdC>@¶ß؈Æ!*×sžÛå/èéMò­2¦—dÏ`÷´°ÿœ n7ÜÔ”ŠB‚Cˆ¾Ž§@…XyÓÃÔ³•…ìh¡Dœ‘,óÓÒúÝÜLߘ£N*¨V|óÊ÷µ™<(=í5_w“†äÝ«õÂÌQO!q™Ò:݉ ÒuE²Ý8UíÎk/ØA÷Ü)H¶L䌪~©,µÞB¢„L§ù-Æi<éÚÁþ§< Ò×~®uþ|ÊFé–hèÇÍëâ;I·¢L`…qÎE¦`§lkYîŠ£ëøµ ÈTPÊœ¬{õ=’€€Ë")H‡&u>u÷uµ Áo“X²{¬ÇeÓKŒ_=V·véØ)Ê£ §ž‚f¸¾ô±²S×eãZÕ°&@Ï2HÐ’ýg=Ûr^Z^Âró‚p…P`4QÜÌo9…‘ TF¦/‹èUø÷a¨ró'ÌØ\÷XD™Ò>а}fCùiHmpN]3¼»W>ün€òa]ùÿ¹ÇßD’6ñî+U:fˆˆdý¬Ñß ²Ã&åT…2äëš@nQ<>£57HÛ×°ßïÙ…T'0KE˜::ªêŸÉÎí2`¼ ö-Å‘šë¤6Ù®§uÄ'F¢ïllArŒXL=Lšb(êä+ª÷ž5½Z” ;¦åˆ  @Xèÿ |ã«ÕàîÁ2æùQä¯%ã`MlèÅ+˜!p8FW8ÃÊ2öíÎ;DëôYÛñÅ7¡û|O¢…íí ÁÎ ì†^ öB²3›øõÊòqDà Çæ4È¡å÷2‡• 0’é‘´. ù Ħ9ž޲|göËRþ©÷ÁÖ¼uOâÔ±õ‰F–‹–j)”¿cÒ$«d=ÜÁ8j^+qjQ1Õ=­5q–ÄÕP dWU ̤ÿa„¾ãWV^«†3ŒÅÀî-¢<Ú¼³—Å×i5‚±þØ3ŸÍæ„WÿñõJÕÁ|¨“³¤ƒñØkNømœ‘jܱL=À:ºÞÃui(y…Â-1ì_³D_¶ÙýÏ5£aŠbÈÕà骶¢ß˜h&jðŽÑý[ï¡m*íz\†ª¬K$ERàD|BÀ£‹cN}ÈÍN j Y|$EÑÁ·ò%ëÑž»búÅÓÒåšmK«>Udû™|L²þwí ÌB°Ï–ëT,dÛáØ@2Hû`´9¹vƒ™Íñ㟃y#½›ÍU2|’Sš[v(ŒQ,Ïzñ êºÇp ³šßÙ'aêDÌþ¹6ÅP¹,B~}ì9üèU­§BN;>Øö²ì/=´ á`dÃ2÷¿·!¹À é;Ïã2w­/UÒS­§“ü­.iŽø¦o á*ÿyj^N¢  ‰ž†h’€€Þ‘è*öX7ÂQíI+ 7!Ç/ÌžÖL´†‰*#„<áÙ ¾1î“x {´ñ’tgðC£¨~7i 8Dª’î=_LeP1РЗ;LqÞ°^ *Jy-[c<éã ”X¥ÎÍÑñ+-Q©_ƒÝ®3¾^·ÏÍDWQDxÓÿlñÓÒwgÔàAÞua²ï¿?ù¥›¯ðù`­åœXúatc˜ˆf4?‘Bf/¥aêÅó“°Îršn5Ø$ggúÄ ÁZj.yYT,Z:H/uÄeݧàRÛõ cqêþïÏõ×e¹=yn¸”y[!$ÇvÎ5H¤¼EÇ0ÎQáÛŸ¾¹”ÎF˜ ƒ,§ƒq„ÌAùP/&XtbM"µ¶ös‹=ˆ1›Ó}U[”ñû£ ÎlB·3ó±»ÐÁJ>=õ aY=!ÿ¦FzÑÇjhÕ¬þh‰‹'Ÿò¥~íçÒ0/í’òî¥ôxyñ’U< ¬è]Š ©5ìaáõf‰nŠ“ƒ³ñêË·†¡3AÚ¢³eà ¤ݤ‡p( ûâºÞôs.óQŒXüã€÷ñ ï§‹CgëÙVâ7Oâ†-D·eÉΑ³äÝRêJoìo7”ßåQÕÁ cÊͱK5‰2@¨ Î5Ïd7´±KÍûi+5·èƒ§Q¡Ô>9AZhï>ós±n.,¸¾×Ù2Y,Uþ{b÷¾¹BÜFS©Œ­ôšB»CYì?7LÚ®gÞoçæ4SäÓ[µm~ÐíO h<µº:âÃhD‡g¢©Ìôû™6z½§­P.®Mâ úáZT)xm,>ÉÖ&¶ ܼæÆbÏÙêôEßÑ#Yöÿ!WÊË$½Æz4ÆÎcÛúK“þz~ Îí쉃ì€KE¿‘ͨ¾—Á;V«T}ßîÛÃ4ð©…äAÛ|¨üìøêh¨=êìžO%¥±Ahòµlu‰Ç[Vcƒ-ËŽh}·Å*~D@kûü&ƒJd’Ž(ómU889®¦1›W•ØÓU[o†\Æ2Nù,ý˜^$Â)M…üWù½æÌ -Ïe“’zlƒÍ©›Eá帋P˜‘ÆTÚÓzÀè«¶8 øî¼mQ„CýYö.ÖGûš›H¹HwyðSˆp‰ê¤eÙ]5„Rðߋ鹊‚¯$•£\/kÀD>7%)”®ž¥¾Ælö<ÎÅ{žSÎϯE1w’Ç®±xb߈j¢¨µEu®PâÇMË6X¯/‹·¦ìAIJ UF]#cŒ)þK]ùê¡Ô‡íϬXTõ1}çRáMzÅ5wÙ!£®òî¯!£B£Ij2\¤M S*‚÷_…¿y-V­‹Ú×;_ti €kú­ŒµvË».ù@*1·¨;RH2X«í&AÖ ý棯Î&RxZTO'›kdx…;9€2ô t·Ã·F·FÃ{£·ù¥­ëÁŒÒ²ØÔ~éP¹ëܤ‰ÆglôuÝ\*­•7ÅÎÎ Ÿ(UäqÌëXU÷&TPdÙ™æR|<ñ g0vié0Añ‚¹mLº©K•yLžñcÖ†ˆ¾Û¡ÇhsgS÷ä;ޤŽy@Ò–0•ƒñ’…›yTÉoè£CóaSö ™ ‚¥Óµp ÉË ‡Ž·Emªö¬AI®õ“cZ/þ‚R Aý³"²ÂØÿ½,ÖK’õ»´Á ž_&r{a¶ñOC¥ !'Ý1Ö§„ÉÇ[d¯1#'#>ä‡OR±*⎼å*V*ÁôiQkGâ–…cÊÜšãCÐtCŽIÉÇ]€‰c#FºÉñë쳨‹ùÒ~‘òènS¿Ã ÔžSG @cÔõ2ÐËÛóÏkZú$ŸÉ ÉO–íôüC¾ùÏÏc—±§`ølõ ”bNAЃ$Ûš4 Š¡VW™¼æðµ9W4·Y…!Á‰²ï19~„=l?V5¨~´w¢(cƒå äðEŽžU^VAºÜ6¬‘ Ž£ƒòò =ø°/leÛbD`]cŠ•SsŒ~¯MZ1»K±:©ɧ‡7`À9ÊÏõÚÕK•¼[$¤Ék’ ¿öê Ï¤Ý©±'°ÂtÒ}ï1bÛ\— &?é±—x’€€¨ ÿLŠ+ÀÎìÍÜmpƒI“Š]1„FQ`Ìt-g4IyaäJ¢âÚNCš¾ñ•ø7!{Üþ‘`q² ·NoU/*T/î °fbetÛ›ˆÑPç½|B]_ÒX%8ôZŠf½  —?yׇ˜K+öm½˜°3ÈqF¼%'~igKGþãáž^ Ãíœ=ƒ›JJËãJ¹qo$ÿÛ‚|­‰?›†sÅ{ea²Õ"uËR tVX@øV®£ã5VxTÉp…²PöÄ;K<4Ýö9d ð»«]–vu5Œe]!½Økeiv“áÇRZZI¹E*sÒPv(A9Ú¬,7ñESX Ïš"Zž¦hy‚é4y0{Å¥Á®îÅžcðúæéNÀ÷LZÂ[4„‡À¾\~>ö^Ò(‚à«yº6nÒºì,­¾Í)Ö}áŸâ¨ ZÞ¹4,½ášVš´Á’PÿªånåPÆ3¿ÊÝ(ÍÃ]ݧû%ËÌ!®ºÄ.g¼óÏÏ–7ß;ª’êO’„|L;¼ÂÛ¦ 7 ¢ÐÖ÷?eã;– ²4aÏiIÂÂy*ÈsÆ0tŽ!VPÈä±è¥55—¥zÀZ7äŸ RV!<¤僻¹çQƒ;Ü|܇Q‹®ü"«µ"Ó/½ ]2xäµàKt‰XÿÕ‚~f·‹©§ô2öËÙj«.F‘Õ¸\·w(š.&>ÑDGE¼€MÄŠ\VF>ŒÓÁLš³GÎÉÉõ~øyC„°¶„a¨^îBEN¶µ˜½OVšsÉÿÏfH7…¢:o’/\K°A~NKþß»Ðáå3ŠßEƒšZI ›©Êöžµrˆ4ê'Á¶µ´ì=õ'é&IUp0l~^`*à9¡jCíGí¨X—vJnü¿Ì÷’ÞYrîP Ø{aƪÞ<²y#õ—ZµP÷¡¼ @æu/\ö—öî’÷nÓ ú-ê>€â%¶fFØPJp7/Ôüm8cÓ€_kd‡¦ ŸWëxJÝÔPãié™|a•œ+¨‚¡=,Jãðæs#ìzŸ¸Pe„g!£1½¼p&0øð‚ýtðši.£<¼1n n9B>hVD(À#üCìoš S§ 5hcÓÜyä­í‡HÑn¸@#ϲï¡…¢´±3—Ì }»iɽo¿h¯Éüä9è4dŸd?Q¾Þƒê⊳8â4œè‰t÷6¿JLeþÝ÷‡ ò‰È+AÕ3^œ:+™xàÀô(èGYšöé€|Jý$Ùæ4R/hc_Ñ#/ LÑŒœ—™­Nˆ»wÃ×Ôj_ ñM>_j®ÍÊÝmÎwF¨/ßÕr.ö¢Gy(Í @á(¯Fc±»æ…iN8p=””ç´­WÌòœG¾î8P¼LÕ’¦E­JÌV—G*Y¾Ší¬Üž(>a øô]öP#»ÈÓš¢é¤¢Ç©S´ùÃ\.Ǭ¬ Œ·å¤UttJqriߘ3œ#åòê0óë O?­"ñÕ&i1cÖõö›3Ê(úŽ ‚YÔçÁÞ{žl£uDmA:¾‰™ø(Côj‘ÑN‹–ÖÕÚ=ª›Íd!¨j³=åz%¸f/€8lœ«býAqt_×®ú-¯ßž ìq„É]©Û¶‚9ÌÐŒ¶¿ÅÌ‹Yß…’€€Æ$±«ÎH N(ù!Á«lœ T]¤¼l>SIÕÆëù»æÃL1¹„.Žt™X¼þÌyd$ªÒ8­Ç[Œ ØlVËGk)•l‡OäW¹€/²þ\b3þÔ,¼î™uí­­ñÝÆžÅ"x¾«Ö0÷>½¾mþ3…SË7n=žq£3ð$ šÁ‹rå%QŽtgÄìxÓWà)„oÎÿvð.³qÊ•`˜ö¨¹2ÄŸ.\¬êo9†ÆäI ¡„™5í—Æñ¬r X9ñeRÒg€#+«pFÙ«fÉkf,xÝ!S“<ç- L Ñ]Ì|·<«e­þÝ%ö¢«$–B S ·í!’âóºr„XòbïÏã*]s“ý®q@Z«³ ¸ÓÚR'CÐSEj%C7–bãyÒ¦Cò+@†2åð:¬ Š=8],a¸iw‹C¼AI.³¬”Êè'ÉwI59 ²04/šÂ5NPd¬òŽFñІ3HÝ¡ø[fÙõ:4Š_àW¼Þã‹á´(UûRl!éçGØÏ  ¨e>$2ˆÏ†LæBî+º‰ˆh ë繺‚?À)A›)SY23Ñ|P_âÿ¥!g“BÖN ŠÕÍÂô7R8˜î¶*; ‡iá?JóÒÒb|HÛªxÙ+ÝÞÊÁ™åÌ=\~ç¤íÕ%â[ ¦óÈã»;’6ª¾âД~¿‚ÃÁÞ·¡I ¾\±„¿Ö­²] ¢‹Ë&Ó$~ ÅZ"v^¥ØÀF0î¹øŠkp»çž,Ù{„X ¹^êt`‰ ÿ…I(œ4—Gäâ¼}\†ÒÛÑ(Yç²êÍžÚ!åè¿»µ*uaF ÿÀ8„.0ðiŠ™†29$x쌨@}NÝ:nÄ ÛÞF½*RÅdäJ'S}* ¡]û{J´³û½ºÑ~˰BqÏŠñP-ßy(G à6{|ò[ ©ÝâM©ÏkÎ6Û›<3›ÜâÒQÔˆR;x’€€²Ðo ™²y µ Œ/L ¹|¼êõqárä¥@§­Ý®[­ ƒþ\ÕÝCÇ1WmÑŒy«°6Ÿ¸Í`RbuÝBØ¡€eݰ6¼-àÕ«F7s‡ÿLèû ùá~ôy}þñuð×>BìÎzKúÖ—¢ƒnÛùEsyTÁB‘ ç ]øÿq&íkõ†ñ›W»BQ³¢Ë&Œ„6>†ç]ó˜Ccý팔UêU^ýÞžÅøú¿màíÒ·+âÇzvb.mìe£8oÈ£Ò%þDZŠ_ºïsIg^}7m±g´Œf†ÁÖl§€ p˜úíœØ÷ÐõÔI9"pÜœSdɖ나ƒ¦¶”m‘™í€ô‡/êv}‚é5(«g"cK§²¤"‚vu”Òéø¹Ø·+¥zs›!)BéyÀ“"~€áüüTIÉîçãîÃI^Aü=Ü0htWXõ‚èá šéz< G¤Å*^T™:»(6(ÿJ¸äPTSpnoó*¡ÈíΙ١ŠÈ¦6Å8ß-õg-ë†&ñ67„ÇÖlxÇÞ¥Þ˜ÃWeJyÊèÎüÚWÏÑÆt¦×>¹­Ë•ñ¢7¦¸ô»ú¿6 ïNTÒÎ@_pÍù%êÔo@ u`uò VøƒJæacº9òˆÝ!÷Ù@R¯Ìvª^F§®ÈToÙí^¡€`â¬_y×£z¹ÓÏ8,j‚mÒËÂðˆ¶µvx³NùVô¢jÂ:ÔKéä¯XO櫾û2ûéLBÔ®d#x3ºîG* ÏisÐÅsõ‹5ø.ÂqxH&VÏNï0öª1†Ý‹³Òµº\ܽôÎCã”hÊê²[¼XòªY‘OwÚHk7"(ÕD l’aù^àž8‡nb³JLZ¾cò—,Ýx¦?#|…=vÍgúSW RÞ¯È-øúÀ?WÀÂÉÁcò›|à c¯mrÊâ;É™„"|ü1ca­¨ÇÂÛØ„5d˜)ç.!LØÎ„Nç[KÈÅ¡Ê8ñ2l|á}[1i<œ7Ž«ç;â¥Ë¶ö’ŸÉp#~Üäk¿EL„ :=­\|}çµ3Rxå]Üósá ÄT.6°äªUq|ÃBôsQZƒÕ5Æ3ÌŠ$nBÏjª}ŽÑ.M’€€©ÏÜÒ»ZÊ¢–>"îo÷?OÂÄÇÇ*ï™ØŽ ,?¹‚ÞlëMà˜TÓ[BÑÄàBçÈg‘Ô:Ô³¢‡ãyŽÅ}¾ªœ‚ÿãq_oÙôªŠo'¾Â®¨ùØ•€G‹±0O^%ºUà ½QìhÄDÌr¹µ>œg¼dˆ7šœ`.]öqW¸(Ë•wŸu`q¥”奵m½¨!eo`æ­(&yâjñˆÜ˜±¶-ÉãiÆÒmÑðƒúÌ™5ƒáœ2qNRÌÙ!Ì—O]RŸ09Ö®ùø½”C[žð’ƒ”ÅF ð÷è2¨üÍh ~jž+%²ß•µüQí¨*ùHGŽ]C„gâöaߥOK$~±"á͇HhT¾¯˜!Oü< 0êïÒö˜åËýÞuª¦€®¦cv5„°,µ?5 &Ý1ã‘g–¬šRî“J÷º\nßlå÷^ÙÊĵPxtð;X-ý•P ÒÑÅØQ#9&£Ëç vÞêüäKz}µqŸ8“ø®OŠ Z$Š1#1.#ÜQóá¿Ã±Ò|˳ž¡Dˆ¶¬ÿÉd¼!rMwoN;h/O=÷o+b=Ñêªú¨8DË„|gËZ¶i*㇇®>Øjôá݈ôÏZìå.êH ©tîxäM5;%"ˆ&‡g2Ò^ÖoÉŒR¦•Ç’A<@ûãSÝO¢…m®¹­keÎä6‚ÁXÅ_˜œ’‡øz:4ßT‚ãj{ö÷|ÞØ9'ñ+8ËðÖ6Æ5«RÏ$û 3÷‡MZbòˆçy¾E•Ãè“5ªOij–™ùÇØ«qì? P¤,ûœîöü ÕǤrÜ”²û²TúW Ǿڑ˜fпO‘‚C|” Ó>0zظ‚ 1ž ;V%‡©ìpÔ¡ñóXܺEÝî0îCX7`Ú®F›}Äk½jmeŸQ†`Z´Š”é…¦‘ 4}ÎÚÝb+Bƒ7ÊÏéß¹ ~g‡é_‹z’ÓPH nØ ÄøqÍû0Â'kQšÑm°g˜’€€Ò}òSP€ÊÜQKŸ×mø0íØÙxa"E”æÖU»æ6~Ùƒ3ësñ¨¶¼\—Ъ¥¼-›&˜äˆ‚S"L:*³&9†ä º&–û¡C^Ý&û 0甄»„ó‹o× Ýþî(kšwšaÿBb°éa(ñû€g/d ßQÀ ÂÝ vÀø {^Ä_×€ø¼ÁÀ¬‰«ÒûÉE)ºðÿލG^µÏ¦lVCm™0óÑø^-þ–$¤÷.ŠB»>­ ¹Õåƒá$Wó^?À¹©#B×ÔГJnÿ«1ê"ô…®'7¦ý¸Ù™±5Mbc»yî¡7(|·„6]Kiºá”˜|Aÿ®S¿*Ô$%·ÃMÑ,˜øi®‰Å€iD½}z¦Àª†ÎŒ5µÑdx»M$WfÔ]ñØ5}­¡Ö@NÄÊrñÉ {™á*VeØ>Û°3ú_»2ri»òêÓ#x4©gP‚yéæC ¢{ÉÝ_Ç£Tξ\®·«6’VЭj1÷À✠U÷Ú‘Ï­>Qç]ü£Ž³†jÆ&¹õd Œl¨}V?¯mÍìÌ/f ÑíCR+úÐ]š#€¶5ËšzêD‡h«æöVéþ奘æÒI@•NNO0úïx|Îd¼/ö ¼·Š†IšË!ÍÊ*MðžBÚ£‘À)û˜½Ä¸¡‡'îNhjøÝ$äú•ËÀÑ[àfL~¾C¢]:vzZe&”´-Ü™fo_‰Ùè¿ÄÎÕ‹ j6ùe ß„wn5N¬Qñ;ÔÙä Ã$MŽÐE/Œ;?O2Úîp!b†[©QÎwîà„é;÷†yÌYprmVÎàÂ4âÔYöVxÖ‡æ¨ÙȧIUráe0ê[òF²’÷Ž19 × i‹Ȩ"¢OëPWâR(ª“j‡¢‘ã0® ß+$g¡›÷V™)‰? DTÂPúá|D%ã/YÞYŒË–"šìI`'j^bjVȈCx–ŸxpÔp$oG!³¡­AÔ%&)«ŸÛש s"ø•’€€¹‚Á‹‘ãù%FJ çŠ~戠U³iݟ͵ÔÞÉc? gÚPçÿÿ’ŒdôŸKÙ&YrJ¾íÉcªå ó©[žðg©€mÐ~ŒTš`ñx7éO<î ÞÅVÜüŬХàṀEÒ= I 2SB‰»Õh¯EÁ0ïԬѧÉRSqXgÍØÄ ~~‘äKÎr›—äÞK¯Æ0yuÁS;p¼O¥£k~¼prm;PÁFZ6Xâ¡ð±)Óy” ¹u§ 9ü ¥Âþ ÅÍpš.¾,àìÕúIû;„l°5¬%o:E†õøëJ¶…DTõï¢3è|=ÇÙ†3Ëz»›‘Ò꺨s#×örÂCt(‚‰—ƒnn3U *õ£¿eß ÑýxÌ»ïÑ,ÄÂø©ò´A—p&0ãðÞž^ýÛ²ujÓÂT“S+ôŠªhÎ ¢ä͈çK1d&¸©@Æ–Ùk®2ösÜ zÓíI.Õ•6aœKæƒÃCV½]-“|±®—“ºò,y%^ŒÙ n0I4j†à P–èj‚NƒLÐ÷ ˆ$ÓVó^øRñ2p£qĵ.W¥`º)¿Bºs`Kh1?ÚP‹·Ëj@ÎÏ© Fú“ŠeåRóÈhôÀš¸Ë~³•ŸÁn Å* RÒꀅU:‰9Lœ§«üYlx6â“Nö“§<»=¨ؘ“Å'#ll¢Ð=°<ùÕRb=­~FÆÊýÿÃÃÃÓŸã5úÊ-£FÈLåàöê·óyÔBâ$C'¡Ðqê˜!¡y&׉ü|Yèlé¹;"7Ý{&#Õa\ÇhEȹÌwBôbœªY˜DZUÍh|cV ¹wªAqìMèÐä,ý‰Qg€LöŠ(>îE¨®s²–1€&m÷åæÔ+h5äØ9Æòd:€FãoÑ6‹írµÙuL`õØŠÒÎèm þðc…ɹ:¬Æ?›––qŽB^*û"A…ÊW°?|H7äwÛiEße¹±©€Ž!íJ=I¹PJs피w|‹àͽI¦6ù¶ä”^ ÀÀÓc§D(¦“gêýñ¥Ї¡c!Ú0·<7$ÉTÎÿŽýòT>4Î/Ò¨xaüšàÉë¤ñ 0Ë®Ý\˜þÜÖWQÿóI~€@†*œ –(øU¹ü ßâGn¿³e£’1VQ€÷üxÙ¾ñtÝu¿k®¾1v:Ï•ü½Kª‘º‡[}íÆPÙÖqþ1ÁTŠ‚‡km¦íM“·ðX¾¤êŠÍz>¬Aâ&ÔN0%Á§Ó$6u4B±! ­¾Bn„ÂÇ3$Fˆ¯ ÙÛÈÛ ¼ÛÔ1²vJµè¨²«´ÞÎË£'Á:Ö7¯Æl¾ó(Ò⯥Œ‹zšœ:ПyXsGÚV*¸Q˜8/Q{Gå f—ÜÊ]fÈ"‚çjc‹¿ _²)õc©ÆÝînA7›hG¾Ó‡5¦€ˆ¢Ó¬à† ªÌ/$Á¤|`ËGÛ9ç#ðAmKB %Zêäðiø¢áÂ+Ùë+ç Aâ†[ܳ%W0×Cß+è$ç:ÔöŸm¸’Û #J£úO‡VßC˜ŸÿXÅíõ€ Hèµ;ªWÜÙЦ¦’€€çÃí &uº/OoШ&”KíY#øýTº`2ÙÙ¾£¼¹Õê/-3–G˜bc’aè*œ§æ2g3qäÓ ¥U 8Ê ™ñê²íœÌ¾î¶4~ߌô^¥M\è›-Í”:OݲÇç,~¾më]½ §¹‘n™ ÊL©1°¹M%kU̳¢ã`Dºs#Èþ˜A¢rZ”Ïå ØK]ð,]ºHÄò´²øÍ(qVZ ®‹½ëæ¯,¿o1‰Ö´“í ËÓJã+Û:¥¦VƒZÄè;?oÔø„ 6¤xÆ­,V²×™þȹG Þw0†¬|¡-°Hï ¼é4(är° ÆÂ†4Ìï !ÿh.ÈM»¨ù1ßþæÈYi±*5†êž>jQp<õ¼4αùNš}¶\]@ÝŒäè;½-È1dDÄïîßhJI>€B¨»Ã†ZŒ×Ñ3£)ó9ÌËr{‹:–Q0ãX` U½¨Cêò'à,×.ŒR(d@£ÄcѸ‰t@Hn8•RFv§ Ö…ü-ÞZ)ø€Ö±Ö˜î“(Þ‘g¼‰‘ Ÿ`§ëV΀ðÏ€€ƒ‰-’€€Ù.…KÌþî­õ-ªZÓ¥ŒÅ'oShã_ [:¹mÐõPŒ`~ÁP˜_Ìaäã}œ•§oξ^ձƧ«DcS¡¹¬ Ø7÷–P&bãþ+Èðû€{ÙÀÍãóçyŒÃµ„G‹þŸ1ûU)¤NlIÚШµ=Üv”šŒ5ö-™$¸HY5º2—·<ˆõ\üž‡‰MÚ7]_2F±vmø#„/4s8=$©©cŽ<,åuº¿6À-6ó3¢LXþ"•Q(Kø÷gM,Œ%MR¼LŒ8Š&‡ÅF¿¾!Ãÿ›=ö5/"^Æùå5¤òY$„ó|b{«Pe0ŒäL¥ÓÇ[#û|ôqGx@ˆ€gmnäO";Ò ~–ÀxÁ† ªi¤ìéɆ]«ý+MJ*¼ÊË™± DªuPç5ªWØJÊqôÒ©Ñcr÷êãDܹÅÁ±B¤!¨ Ø8þÿ|Ƹ©ŠßV‹H3ÔWÇŽ&øzך|"#¡]«VEQ.ÑÙöp~*÷ÚÇC¿4Ó²ù¨Ð7ǦLLàõÀ´}…Vj£BÝ%®« V³GÜ},öÎí“`‡ªœï¹œÍô vòmGog71‚¬¨×F¤C o€Ë3“å6Å F|“¿[‘È¡}ï½lÚ)a˜Â»/½U”aÓYlYq2úJ9ÌÞFÆ.âÿU2íef7É1î‚Æˆ;Y7z}®«˜‚ ~+ÄÀu6˜²ª­ˆPà¯Lº†°äÄ:¥2½—"Ò‘A@n»ÁF«¹Q£íùùuÀàö|îJE=§ëCMð‘Iç˜ÎWt‰!VAç"~ˆž×œ¸}-·HÇøfYÿmÞ""ã¿C}E N׈æ¹!VBÆCyD3NŸI柋>¶~s‹#ÄØ¨Pô&ÌêñÐ]"åEâ¤[@óû©¿À7Õü߀}a·j"‚±z,_N"u>@ëÆ­–•–“bGæ½yðé"±ŽP{EU·[ Y )‹6´ÓñT>º$¹œmLJ«½ðÍAz^7>’ã4ÅX|V)ÑÒ”‹¬»¬€6tœ#qˆ#n‰LDû!Öý}7êâÌcݯŒ'Gƒt‘ƒâ”oéˆE¤ äjåĪe.R‘m—ÎÒ_:½FÜšOSE½½<ƃþ¯÷u*µœgKÛ?³Ø®r’€€ýkÜ[ÄÛ‚Úàì-Ôù4äkd…™ÙV4OT‡ýtã+xÄÑXM¤HÃhpmX}‹xò„“iâ#^*’Øì‘h”·¨t‹D6ÊËøj¡F¯Øä“ĪüÌÅObÿ»óDR5ZE6o+È¿‘™Üì>åÇÄNÝiÞ$¯ýƒbóô=ŸÞ´©>§ñ¦”•"#Åã]ǯ¼º„º?åY¿é´Ë÷õeýFô:ÍôPMw³­‡´Òrâ =x¬P†}…´ÔN™S@ Qsö¼„°5² DUGW Kü]3fÏ7$°öµY›MfæU±Íxæ¥+°¼+<Ö|¶AN ]…A(¨;b`’Î#¼š>ÅÝuXÒ/ WdëùÁ|.ßûUb†!b "÷gµ•à"p& §âà!:…½ J­ ®9O†Ì":ÐT†]Þá–×2däRŽ8²<¦ÁŸWù B[ûXYØ·é ìûâ@¶±Zi\åÓ—¨×ãx_X®Gc6nt{’+¡Z8ÔBÑí|ßÅk" ´ïޓȶÀ¡þF?…7ît¤F1ŸX¡c(ˆ4RˆË{PøOÞóû¸'!ÓVl –cÃhW£¹2Ï2xxÊ…ÿ©æˆˆ¦¿žIµ)8¤ÚªZªç$Æst²[Ãox©û“]Åpã~úAB'¸‡K¶¶eú‚qH;DùN÷Z Ooö%¢óÐÝùÛ…#.õê¨ÂÙ̧螩ìýü P?wßRÎ?¿ÃÉ‘¢ËÔ¿á<ÂAèêÁ–ŸõÇDCýòÔ³ ™Ÿ9´ÙÅ*4c^WYiO3l¶pk —*w\õ íAy)±Âï”b´§…¡ŸwÓ¬Age*òaBK›>ÔÙL"S¾pÑÜ…ô[41(‡`ž¯ÕA¢h«ëÁ¼E‘Ô ]H–ÝÍ(»ü'±€Æ™:-ç— +O˛ԥyägsµf¿tÖµ£6¶EÇ«¯•üv\àw^f€^Ž:]¯Ç-ëDÛSßïµ^:ÚŽVm+m$oçæ8oNû}íï²X¯çPBÿvæ¶Í•þf{j®Lú^3„s/—{×Y¦Å|:=É·èçëáI#È ƒ9ÄP‡UùÂÇ@’€€¬`-d/›*Š(75P«ûÝü$ U"D¯ ž€$P+WußJö¥ ¶7—Û>¿´9¹g„Š¢tÃN¼,гgFAMãLÔYHqwö}'X»û㢩|Q‰ BëŸS ½ iÉ݄Ô*WïƒøÌ–¦ycgÕvªGýÚ­q˜!;(ür¶j_°[£¯Þ-ˆðÕøŠÂZÔoQáÚ;Dçö L/r­oUè<¶¶äÞü‹ŠÌè,¼±š”ÚòN z„7 F>hy;ˆ/½"lpcCRèý½¼9î4»#˜ɮ‘:týñDÑõ3vú°ó墭 ??B¾x¬‡l–B8CãÝîÆ)B»jï­_¢ª¼Û$¤^y¶Öã¨CÑñ“ú‘ìÒWlšy…kTQç2åªË¥«Ü±=Ýc׋W9©]Õ1T'`"DKûœ|¡Æí Bä’6Þ.ÕIûÖ[F/º|Úªñ‚+mD¼‘i¤Òëø ýîѬ5Ž7Õí$Ãç9€ËH«âPkI'ƒ! –üÛEŒÛ&:ò´k°dTrãëÚޒ\,ÇÜXKe­ «ÃEO(äλܿöYÓÛUL‡°Eð‡û ‰SD}èå1EuÑÝú„±üJzÈ¸Ž©›\W½äÍÀ+³| ä@ ³[B¼Ù Ä€^Ê€Tʧ ‘×úì°úl㦎?ÌjSf;–"¶|û)ð%í-&_­½Øæ^}JbÜ€ ¯O(ïUÝ»šÔ„“ôí­÷ÙQsàS{[!6¨Øô¦X aß[+Ð×~¶´ö‚˜•ÓÁ8Ê/;Er_ÈÅ>W[&`Ø}Íö*ûtvü!~g?Èg9HË*öFpbZ_š¡ëäà„XŽSqiﻲþ òî—Ö9ŽæÃ@nJå(O\ö´’\KIð¤¦$·š¶Â¬öÊÏ`®ïs´"{׃+ÆÄwô¾ñ6('UŸ¬ÞY­a`¼j=ƒ Zb-Ó jÿ¨Â c•^ÖX—Xë¦=á¶36~<Ãÿ­Ê؈âB2ó¤¹=–ÝŽàð=­|†¿¦0îâ²¾…QʆCÐò ù®[{q¨…Œ¹:œñW[ëßš‹Íçûsë—ˆÕu vàqW¨'vA\òsôV’€€¹¼£ 2Ê&bÌ‘Kcåà,eR×®2eC»’ˆ`2U‘FDS¶@ÍÎÍú¦Öõµ¡:9¦S'D·;…wG‚•Þ RÖ.F ®mª½B2+³MÆ+—6ÚBðÆ*<^F¥³½zV×ÀýW†=ª?žw%IöØm VÉN{½$ ®ïÔ©½JŠXÙ.~¤Êd"(M£çÁf.̪AßÀÊV ÈöCžkT¦%ÔăÅrf Àäxþ’æZ¥îÞÆ°aå,4 yæµ{ÙúÈ7§¬O{µeæßùò—­þA¥êáD$¡"Y“q0ã¸Úã¥ÞÝÑÉp QÊÔ+"³%?Œj~)Œ©ë½êœñÒ® :¢y·£ðC³­oO]U›N€Q”‹€Hº¢¿0UëNGÙ‡1êàÿ·Yf7`퇫>¾z¿„WÕvViç¤Kt¨-gÆG’1v§ãº©'k/{ê.ªÇûΠDÜ+ÿ§‹o¾CÁòôH¦ú¹C„úÈ (¥ÁöñD¯M”ŽÇ¹X™,Õge!(ލ%0¿•yÖ§Äʨg=šÙ‰»f¼cÎßÊp_Eë8&X§ê€xÍõИv"…mBKàOˆ_€UØî î•JØò‹Ã¬˜šäR›ŠªdHÀz ‡š—ÃÞZë . Iq}º^X»-°`y°\ á¢}ñf! S"®›Ø‚ÃæÍà4«éxƒy8%•3[ã`9Æè°»C’(ÜZN*…Û…ÑkÑ÷Vö”mÏ7í÷e–+(¼heÀŸåx·§#ºjѺÌtãÿ¸|h–â|ŽÿHù¥Ö6t~QgMTZ ¹R+çË$cœA Y—£^è oé0¥®¢Æ]v mÞêŠä¦8ddþ™.jW¾6‘ñÛÖ3²¹÷hôK²[_Sª¹îfe2-„2[Ýq¶ ü2Cú ˜8¿EƧ7C •‰a½ãL-!Eˆmþ["é§l ìXJ\Û6ËLw>ûY$ËnSV7«Ù"§„"/ \|£tZ·z¹7æ:.ùg°p‚` £_4°3ÇpQ¶¦ae> ,/îã®á•oý  k)MêBÑIe2ºÆTø‚˜«E1&3¦ð秪xH…CqÙa@¨š#BÈT»¦“×ˆå¸Ø)£s‚r•]6M1yZ°Ø.D#ô« R]’G·­0(âŸ9z9]°AÁhé†öÑ[¯–Õ—ÌÌþ{ UÊŽ ÁŒÊJ ë”ÿ¿=攃OÜÿ&¡u7—eN0Ý Zh÷7pø±ýñ}¹é¾Ü@Ü`F„£•TRM€E„l!Ð%[æ™hx>GQ›§uw¼ˆ=h ‹7¸È¡éÞ%ÛüK"q;Q–Ç[ašÓÒäÓ[ …~g,Í÷ãøÇ 4;±$Þ±;TÂïƒP¹Bü­`SwÎWü”dGŸöƒ8 …+%¶‰ü¥€~ø$ ‰ÉjZ_xüŠGû|œHǪׂ̃ÁÛä3‹CDL˜`ö Ë51ÛaÞD1'³Ì3ÍÒV7Êb|ŘgŠq‹Ð!þP £l·G Ìœr,„ž²Ó6uƒ¯iûàÙØ#’€€èH»VÿiˆŠÎƒwEÝÒá@ÿqqƒ ç’50´L¨x.nŽÜC ž ëi©r_ÏAøNLbØ YCr¸Í±ûã‚´Vï5÷ÒƒHéC ßé]ÝG€9N'IgÍÜ\sÒl“2Qr ºÝÑ…‰G$)oÍu)«Æ€ø½Èƒ#³*‰Ê€&O¼ìßÛgE•ÞqÀþÝ s¨‘ìŒç*Ý"°#è8zÎ๓“¼ ÊÌRÄ~°Üú?Ö0 ÊXglCÖÖyzYÝÚW¾hW‰>Šq(Êx·HÚ‰’£¡¢MªªSÅ SŠ W#Ö¬ó,"ƒnƒLDZòéHçcx znD DØSÊ+6ÒÆû‰®.4´Ö|WãäR§–ñVg§¼VìÙ2Jlv¦T9*%ÄFv†î’Ì'2©g–ߤå RhWuÅ[ µš$?/j$â!á2Lv²™ßžáC‚¡Uñ˜!äh¬ñf.Üó¾K‰±O;®.CøõÖ;BâËùs‡øn FÌôéÑÑÔ°&º*þ‚±áP]É*„Í ïÄð[{ÚrÛoÖQ0sòîÛ® î뮩rTÓêÉÓRjÀÛ¹49]Z¸É’…ÃýóGHøPç]ÝÖHs“8ß"EG€-:G©~ùO7”šuc'ÓKÓâ¯×? ý®àŸ…o]o8IÌxð³êçdXÖæ?ü÷-i › ðÞ0k£ú h® ©”¿'£ñæ;Œ²@í¨×ù0À‘ëD'nþKA•e+ÿYasƘ/”Y¯Hß,öªúQÏÄÜàn”æ/ {-DJE¬5zDáÛY/ºŽãM­êgÒª+ÖÀÖl÷,ó•š½á'Ž”(ß’4DúOÜ¿œ¯tß6,cMå_ÈŒD ¥Ã¼âDXé…=830Ê!¶ 9¸‘øDn‘ȤÒèõú£ÞQUOöÍ–J¨*ódÄOS‰’5&*§fí´ÑØít<[)݃ͭÒ+Ú)uT!AÆ]£ó2ƒzýÉ@Y”C$¥'Ó+On-' Æ œ ;doºÚĥ߱0Ä™¡m9OÞØIpÌC÷Vž³‰Úe¬/¬_[ý^'ð })Å*øöžÛ…m‹†&Që)îVþëuP°ô¨ª‰&«ÔÔ¢"Q žÊEnwø´AdnÕ– Hêa6‹¬P„!Z®à’ÁÑt<ˆç²Èü}r`Š/„Ì(ºsÓnAêIKºßñH¶X[9£S"r(6÷Ë‹ßgjÚnWK7­ +‡"Ë/€¸ÆƒÇ˜ Škʪ4Ћ(³„¿ ýÍ¿“ã qö<"±îõëyQ!– ¹¯”X/¶hëË€AL’ŽØ[8rÒ%£‰”^ËZÕÂÃA¬ÙMù¥ X%’QÉ/? t&xØU÷Šê2¯¾vGÿ?ûòÀY Ìïþ΋aóÀ CÀ„w߀åG¤Ì.Z8€ÒÞv ±i¶¡\ É'ßÊ⨄{*Ü‹ z„ü!9É+†×߸þá½qoa¹j h¯°•nð\o !>OèÜå¥Óé0ªÀÛ¿Û¨Ò•÷\·Sc­˜Ìpê+UÓå'³‡ûe}·ÐZ"ý~Q=Ͻ0\n–¿ëN’½¸ ×>ã_éÌœø€° ÕõȃQ§¥¾cä —9Ýuô½–1âóHÖ{ÌR¡¤¶ÿ-ÆÖ†§‰“†Nª¾Û/>>¥Æü1Ã{¿¾Ï’€€ºœÉÝ '@. 2øBoUø;¤—²xnß°¡/¢œšŒ¤Û¯,¿ƒ¨EŠ\ˆÝzýaºLvT[ÅÖõs?û·Ù¥‹¿‡¦Ô4·£y8Á  å>W55¦i€•œ“â¸0ÄÜ«Y_ËvÒm„î`ˆöé~Sé-:­# –y¸‚Ð+µ_å"Ip…hmrI@1³ÊÉ{šG…åxVÍ¿¥·‹ÈKypVíáïúÚì+ý¾0 Ž/û%KJÐ5 VZ2`Ý:Sá»úÕ˜Ë?=a:„ËNZ%Ü@A††,c@(ΑØyRǾ'5È•xY¡kÚýÌúÍþàÃ0FTê§C·ª ·—๠Û÷"Y é'Øœyù[FÝ…î×þÇ·(«ï;hÌL¹:&½ÒÕ*ƒd*i L ÂU9Y¯ 0é1ƒn¸YóE‚'£ÓWѤŒÜO؇hÌ–+&„gáMcqû.tIá/ 697™î‘`óo5è$mDÉHÕ¬)²'‰CýÍ46àëŸ_•æDX! S#u³DÌílià4*´ü1ª{¿âòËç>Ã#{”2™¢³°å»`ÑT.}lMSûÈmdî’rÙ#’[ÎÍdgöN¥ö¯š ¹ ‡.÷_m’9üÜ¿øŽGC&úñ’ÍÑ ü«—U‘ßç7x¡ÃZ××ëL,t?ct½±uýudZÜQ}£Sjc†EÉE V­Ñ}lj8ìj.ŽÒc¼ÙØž”¼}O²3ûòJ7ößÏ%Lµ±R$î…>> 9ìbâ§>Fëtt`MËD¤jF] ?EÈš6%ðÅкã_$qÕ]5ØçÎ Óm'í­®J:ÎÞZƒ âe;W‡ô†ÖÏòm6L<€LUúm²"þÁ’—öæ¥njkçƒ" áÑrÏ3ÅDPMÄÆ–å#á''åBþÏ^;G¶ÂÞMY0UÏYW[\œ IYêòÛimÙFv4a×g¸¢s®Â­Þ¸Š\Á ¨£i<Ζf‘œ‰¥ÊXœ€þ›ÐÛÞfuw€.åfç5à‹ %ÿkq—ã{7\ˆp°³xÍj÷ì.9iÅVÄiýÁq„êÎf70[Ÿüutï1Rª:Û?éT>¥"ã"ÛW™Â Þo± ¼¥¹¼w¸™©«Å’€€²­|VJ˜Qý'[ÉzÑí©.Už®ÊùEšõ«ËF6 ®¼àÄÞ¸j¤yÇ®t°f€Æ”a˜Sàl‚°—·Œ_Êê‚ËAUXÆ«Rè~¢°>—šH*"¨ÃJÄY·fG:ú½ ³§5ˆr'ó>«¥|RZò‡wNI¨>X‹Tå%’×OANÞR(Ý^Æ&·ýI"“z‰4U~[È*%_©úƒìLÉGQ³}áîÌh]±ºÎ¹!Ò ! ÎxF'u5ä˜çí§/¡¶’·ÖêȦÌÿ(oGa…s@3»ùé*Ľû©FrYwYp±\@€µãÔã}+ áì·e›>š”Ío-Zixæþ(¸0àr‰;Ðì/ðP¬Ñ VxÏ—aÀàGr¶Mü¨c\·ñ"ðî¡ÁûG`ÞÈÅÃ_FÏœlÇ1GL`+m²ß¿ p BN¹-¥/pâ]¿­;Nªð2d\?© ]Ä(Õñ)èž4ë(ìsBäÌE( }tâëÏh§‡>q¡ÕqFÜ鯧1ÙkINs©{¼Ã"H#à²ÛK”ë,hjXqªÔFzhÒ0lKúp\Úzå†Go€Š³!Uòm^/v|Ÿáù35¢¢H‘7|‚H^<Äž³r©¯f‰·/ÛíÎ ?ñ~.büîÚ+ˆZ!Ö&%<˜Hèø,´ö eâ¤ö´“À¬IîA¶ÄÁ²c7¨ÅT°X<ª´Óÿ£bp™ùt@Û&Ò:Ò²p=T+ÍU Sô6ÌLºm¸=\ª¿ê|³‡sEÕZ$Ѫõ„ß-ø]ƒ%>Àjó¼‰)gE,s{[øÔi½=OÕ˜7$‰q¸ WùSMY%¦í^6¾Ô wã1õ´´”y‡v7ª½Q@´‡ Õç(£c‡™ò]ç6®+²‡H¹{HRLwÆy×ÕÔc¤Ê•Ö†Hýtº­×ÑsôW‡jï¶ÁÆ—,ð÷–€Ü#.´4úô*][L±úø¢_…¯—¸2^óþ"9žÎÊ@ORWÅÈïŽÙióþšgZOðÚêË_Øù^ò‘_L˜˜eOÆÊ‚ý×–y§É1.XóAizÅ™±±È¤|Ôs³Ï›õ}ßE1ÒËiÅ&BHp‹*ç[‘­{nÏ|Š‚ß2|;´8îIÔkÊ’€€Å©÷îX­µó’”Nð”‰7[m½MU¨MÖÂÜv5*ë#4½Oa”}­¨ôßtWW3p‚9û2-}ìòì4ì»3pKí¡ÜV4YJ aò¸¥Þ!ïM5®ÜáDM)N‰}‘åZ„á~‰ž+ÎÂŽN2Kü$ÓjìÌGCFP.@Ë>ߣáÎ\ÝW{àã4Qˆ¯ŽámnX8KvsÒû²ì>,QGé IÙfu^gÀÊçxÛdÞIm]¾Ôì:HÚ+s?Nå*†UÒ@y4„õî(×3ŸdCçT/A)¼ûK¥Þ´1²%°ŸñM9‘k.’›¦\”ÿLv›û ÏBp=…Û¸€".ã!o‘#R \ørêe­§FŠ'Œ¯*ˆ¤ ¡œ"ÛŸ)Grn2\ávy€E¤ìèáv*/Íæ3:DÔ´RL6UÜ0»ú,³¾ ÿ)€k c!u”'ÍHê¿õWs*8zõ—èg,ÚElyÝí=I#7ZW´y Êê™p’¯^¾ëC iÔ%|¿`€€éÚÙŸhF·TjçùÍ"®÷UQƒˆ“K|8BÆ0nšêbˆKb  Ò¸Ÿ‘5Ä>G .‡,Û‡ÎK[¯à¹÷ÖÜ3J{Š›íÿÔ7ÙbEßWxöBYëÅc¥ˆ™aéÙWÈð´P¦*ü$Ù-ÓF¾pA‚X…g~ëRٷÓ ¥ªl/9ÏK¹P 3X25,<}IF·Ä#ÏrÓ3C•‘»oµ#7®m'é‰ú“±Só­R²¦ô³ò·Ÿýª™¥¿îÆe¬­,cºážo¹òE5ÃËꥤT\,Åõôm…שÓž G~á%o™á+ì®"&‚zø»iŒÙõnÚħ6ßFW´Ç+Q¤O¡á2ñ/–KôNKR˜@BÆ÷M†¿O~,狆ʱù4~7БÖÁ´ÓšZ k‹npdˆýÌQý·,Ãè@+>pµæþ§]uÐCæBXƒû=&‰§ë)IDé?6Iæû¯”÷Šì÷Ö%¢Ó·í7£Yl; Î Ðò­Šý—|ƒ77s‚;ïxJ¥Z3…vtªUܬ%e²Â(4íêäϧyÝ` ü¨VtÙ dJ)6Œ¦¢²û ûçRo_iØEèúž}ªsÄ×÷5Zwvʳc~ ­’€€ñ»a’s¸üÎ,£jôoÿnO–M£³ùgQÍhÒX«}Œ†-gh˜Ø‘Àðk†Fh‹¦$ïÂ>þÎï3zK‰ô±ä,ä†9pÌ”3ŠåŠ[´••ñþó¥¤1ÓêyãZÚÆkâ®éªªÿ’l/9R¦GDÁI¥›Z»87B”˜9pÿѲš _[öP—Çï§bcóå`¶ /Z½µÅ}±;ò¢‡&5[*³1DR¹WÒ\êØ&Õ¯TœÔïOkÕ®tWZb¬jÌ%ßÖ¢Cìe_:½Hê’•Ê\™½¡¶EÈt›ë±l,ù¾¾Üfff]—1šu,ªbMyšøb èÁ^•–üŸçÄu-)qËüIzWùä†]g©;ÍrO mbSTµ¿£ÇS¸ÂäO—¾YaÕˆ·GÄž¡Ow˜ÍÚëÉÁ$è*E„÷]®¾õ…™”»LÖžAi¿+M)™€ ˆŒ‹„©Sp½D¾Ùn«‡úiŒ(ôáU zEš[÷éÔårè[ ¯ýr²‰ B(æÇÙà˜òrv’€€ä*R5°7GèøÄQ‚ÜiØSçB§ï}ðÁˆaÇ ÏÍ`pW…Æ ;àÅ Ižè¾ß¸6„_€ÏN«%SÏ*Á2þçÍý@þtº“Ší+ ìœ)¦À§ÌTe¶UÛÖBa³7RíÄZ’•¾×§"1Xu( p1ίÍtj®æFTÍu™p:jiµ÷Ã\“È‘>ñ QdóAþ«_œ÷ yëôs*<°ƒ4ÄÚ6¯ÂIoEÆ_vÎr¦y¡¥ØÅÞB¢ }HÓ›’1ŸQ­] dsO'6½nl›Î›PÇvˬ6>A{Ä}† ç2…Ä˼I£ã¬¶¶ÀLKËâÌä^wENªRÒ&–ÖÇgôZø–’›s?Ft¬g±qðx³ÙN0©íõÇV5x[ ø¹kÏ6 ÜÐ RðÛ~Ö#@XÖÖÛ|}–ëyu¾º2›ê§fÆdÙÚ+8YÅïøÏº'K€§ 6^ÏîÝR£3æ¹~¶M±Ví!0  $a¶õÈæHÔFÅ“ÌÆ?À1Ký°›lçtAžß[ä°!{ÿÐZMHr9ú wd–>Fã“Hèaèë-\à“4kŒR¨FíÜÎõ&0±Vˆ*6úOXOÌ``Iâàä¥ÃÈ •ˆ÷Uˆè8Fÿ½Á*üüL34ýcEt0¬³Ú×q,E¸Zû“œt¬€[–!§ù[ÄC•|d-Õh”Ñv ç´µDö mí«®q¾wןnüo‰„þµÊMÍ»_Z4#¦>``RˆüøZ­GÜm Ž"î m6N6ä&pNñ+˜Ç’%êÆ_…¤OJn‘æâOЇV‚ň¿p Ô„®7ò¨¢R{‡p,¨ ^âœB!¤›Wø‘D¡îp„oõâÙ^ø“h¥ÉÖ ðcÂ.äÕ„ôLþ<ˆÆvcÇé)R›W jדq’°‘å£Jò€úsŇé“ç7—x^ì0TÓf90hÊ‹š†Ö‡1cI™.o¦f@_]OƉ^©íh¿¦Èö p2SÊûQZNÍ祉~¸áï]Lå f¸=6 xØÜË{ÂÌ•5õþ×ÄóY%[ÆO1á–pÚH¨ÆSÛkNcÞõv¥Ìì·,Šðª¿-P­ÏÕ£¦žeœ¦”×Ü)Ìï…e‘‹Tü1/²ó’€€­_¢‰%«g÷à€F'ÈÍÂÖ>ÌÍû¨ØÌÒyÃòéæÙØ2k(GgÞ&rÉ|eÊ—¶è}2Ü¡GVøû;Ùܸr›-ïü„C‰sÎÏíB%ÜWËëAYç†!7–F¿(q­ëÒ2´Ê.Í),:½C˜¿ €’ÊÔÔ:fÒÞDyѱ+5ì ­²™ù2ûj6Cw¥ðhtñ#R`v³ÈM³>%Xoß~ã”é~4,s¤~˜Lñ^ìbvî.UÒÃøPµ=ÎØ˜azÜò!ÁÎu‹8]^¸Qÿ¤Þ×F d“7›evA§æfÐç u¦!GÑØÝIΰ_G ÔT$æ¸1EqHŠÎ«š+i è~¦^ýiqNâ©SÞñ|=zVó!cÂö/äð­Y2#ÞÌ^‘Œ¾3ùž'fÆðÇÊxp´[K/j_ÀvôßsnMe¤™ã¥Q|@ٓ΂øšô…«V~Í=v±8‚ËNüÄy‘m?Ú7Þ»ª)Öੈ\å]eøŒ"–2Ùe¡¤Nz%Së˜úûÿÅ"+B^q'!²«ì²ž÷¾{ŒÊ‹U~¨Ð$ëùšˆž©ðy>íJª8~Ã’[s¿R”%Þs™oÞvh\å¾*þ†=Ïò!ê#do†US=,óŸ´-©ž¦ö)!:XnÀ!q6¹ó{Ü*áR•éwt›Iþm_Ý2@PF¿¼¹ˆ¬¿ew ù&¬‰Ý±l‘úÝ1Îd&p®&9 }Ñt¹€¦àúÕ 6©Þ..¯§¶¥ãY^?³à€ýpJâp& ‘ÝÌ÷ñŽ• ¹X‘Ëýmë’äË´l-/mÄN{jÈÙé^$D'ëbÊàWWݞΑú¾ÈJ¶…x©â¾F¶’€€¥ß°ŽÔJcaÙ*.1,z÷nKq¼aLÈFØ2´ÑæØ !êÕÆOónG{+×êÑ¢‚ úκ®4£¢ŽF$1íŸáTFº‘ÉÐ@ÇC+À8ËÒ­%%[sœpvH:_ÖÞˆúÙq5·,X-ðXÚÂm ¯¯|k?QZ–°¯šv‰ —4wIºØBX¤úzøf/# PVÁ†f©5=8ýÞ±Ê+G8y«èÈÔ£¥(ñÕ¬(uæÛâÁ,y?ò Ûf«‰M‰7lëè½€~L^áKÛ žGásÿ)Ûi2Å= (|vÛà]ðÑãÁ?ùªFü1 ##¾Ôb7PYãÄ=›Eäe•#ÄÚMÇ¢äÞpÉ ¿ªëMCá©ûœ‚³µ b5ü|œJüG/ÎÉèk¤ó;ñýéA–ȇCN¤àTjz§@*>RIÎìö/R²é§Q=ßlzÇ…g•ÊQèÍ‚¢òi²õêê÷¶i2r¶Ÿ®ƒî%«u%·Ò¿¸ÇϪ6;F ØÈ'Áùwk9¡+iöÈ„óµÆ„+CUÕm«ñêöŒè$6ý‰¹’ìÞ ‚ZKcxfØòÉ«í¾v.„›¨Â¯Y5Í%PRÃÃWÓ–mcE="ê0ª¢ë§qAìÁ¶CÒ¼T`ÌòÂ߀OÒk,xà€œœ±QrUÁÙ Zql®ë³šèyú i‘ˆ™Eó]/–‚>ò{õíØ×pڋ篨š“ÝÌyÁ Š9´R*’Oí’]SÒÖ ÿÁçW Û“þ‹äI×v d ½Kw’€€Étˆ²! š›1wOeÌ6ë/>+ 4!(a[~§sìP6Ä™o͈„P†¶?å~$CˆdåËž|Ó,#<ß³êÍ<R#GµœṼUõaˆâpƒ ³‘E9ª'ÑOе”&´õ?xÏ¾Ž²’‘Dš?Uþa5„K½…cþñãáâÝ"ÌLËñ­±Zí@Y³³¡¾v‡ LW¥(dvÿ©Çš«¢@®ÁÕå.)Øã˜R$#&Åá,د…ñ‚‰¹Aºâ÷øIOUƒ×–— ë—Î…˜½Êl¶gÍHEC.-$¯8KF]@–Õ Ü }Ú1±%{NTMýD¢­“Ò¬ ãT×.SÖ53ÄéaM@F³çÈáàðbS˜Â7Ù’ß§+'6)—Jt‹8&b+úƒ-$5Õy1x~žzÅg\=«Ã”±,ºŒÉ v)ÚPæ®D‹‘•]%œ ¡•Eüα<)fqÀMÅÈžrš"r(Ø-' rëÉ­:Òï8°JËlÆd¶ (lÔàDiOhFXmQ@ÿ°à/^®\IO'œõ­¿-ƒ´(|;½ÌxÔÖF†Ã  b¬®õæ€K„ Ïó$¨ŸEâÑñ<\8ÝÊŒ"iÚìÀDæ˜ë;¢~)r+HkÛéš)¡KÁ²ŸÿÁë´Òï: †-w€ü¤ÑNïõ1¯Î@ÁV_œÕ.SyôjŒæîD YÉhòcô~Œá•œŠuÈ÷^³pa+¨2È2ý·o7ÄIÂw«éœ³æì¤è²þݦh!–ÓCKKÏׂ3Mî=ŽÃYxŽ"•"7*ž‘‹Kz2í1ÚÌÈçfÚ$¡QèŒñí¹" ,…<-ìº'ýZÇ(e«¯úZþ†TéÐíOöZH!7€$‹µ/ý…u…¹Ôí åødj¾ŒW—++hðkç0´¢©½Ë¨ØÑÑ4kdȾφx/¾eäi• wv†³J4‚¤ó’ÈêôcŒðP~=Ó}20 Úbõ¼„Õ8¶ÇíuúQ v Ž;èÅ«J—ùB¿ sØk|àªXÅD¤ÑZ÷ʘåËÔeànG3–B¤ì»žH•„‡9ë<};â ©ȃþ¯]úƒ´P뽃¡/‘©-Ò-jGJ=ëÑÁ kã(qÿó®”Df'‡¨’€€·—ß$1ÌÛÙ W6ð2©üèS¸ó/në?HøÚi'1˜£­6hÎQ|–1žNº'´Q áÅûìl”Uc¤‰ Hþ¢#ìÉöîÉœ[.*ÀÎú5“kŽ=Ú›Cϱ‘í+µr ¨•#÷ óEÊqò“o$*Š¢Þ›jÙÊö“‰¼=¥{!J’UÁ“µ@»Äyg®úêe!wÆq<‡©æó´© ØÜ²Æ_òŸ’ÑÂÌQsÛÄ\¡Ÿò5"r #Ĉ_qG㔄˜°ÒÆ@ …Â2—|[%P³ã¤eEF¹°ï,hà™ Aµø³P•y°S‘Ñ¥ìtAÙ®£¨˜OÄ$pÞjÃ!Q\»B@XüŒ×  (÷‹pÈ »@ 0y¶|™À ó;1üvå¼A@¬ÿxjkäô↱~ÊíÕaô•#’K²ø]˜TO.?ê‹ÁÜÉþZ„¬Êý]ÀE`þ¼òþòófsÇÛƒUŽp–kªŸ¢H¼ÞWó&˜Råo}á©ðBÏ-þ¬•¾ÁŒ) ¤ë—ðçcñü5ÎY®¦NÆ¿ êØŽF÷zNÒ•Ò}‘š4ŽÊ(o9ó8¢2ÐÝ¢ª…tAªº{„H}¥NCó0š#K¯„ñÎ=žy±bÁlµêæ’= êñaÏq º­§“¯ò|–­Ö·ÁTÿ/zm&¡¢­æ;&†\”qÿ,m§ 6åö (úôX®*Vv‹;¢ê¹­®Éz¦õ_Žik-ßÐÛ½bIŽÒ£œÚ{ôA—Ê„´r%Kõm⸴9î³D ²qÏÈ+6™¿8ÑW*¬„P(›è#ý…s YqiÁ|?×–sWÞ½¾Ü¤¹.^D™Ú}õÿ¼üß5R©ªï©P¦>îтآá„gD%ì˜Ô#ǃ¶I‰Q%W;,“5NèÙ¯.“U™™Õ†sÄ<‚0j±ï>°4xjTX3OÌu…ΠÎ=xµô›¨Ë´SŸ–MÞ©øt,4aè5HE†”ãG§ÓãQÿÃHô<ù •÷+µ² ÑHSEÑþªßuá?åP †Ê˜üÄ_š^ÆG™càó"uTdDöT³)—ñƒ_5sïóõ`G¿I}uµÜ>^¦~›CÆÔÄn’€€­IW¬'ëð°ìJ/•«QŸ_âUV8F÷”ª{!{V£PëæÈ`Öðs¡`Úð•ÔŽF lÉöWiS廋ÌŸ§„ÓgµDJ4âXNÊPòïIxä-þ'º& ý†àÁÅ9ÏB`jµ ŽQïg²Ó7›ÛN* ÂDåAô@G.ï}4éÅÇE„—#Ont¬îJü—.kýª¢ïÆ‚%)‹ûÆÐ x`Šsä² «ð–¨Û‘*ö>ÿx1¥¬ÊÆÆ­ˆÐÍý ×µ¢–i®oT5âEkšóäˆù)›Õx(›H$ ØÙÕ¤ Uî³²t!³O/ñs+NpëiÒÙ02= V*ÏŸpcäoúxæŸ%Üß5ÍÅg*O°üu›¬¼$š;. ŽcýÿØÀ,Â¸Ž­ç³Ü dêiZԤǟNæoÕ(ƒµ^,$ý©âtBgû ú­ó7C£x(ª¿ ëSÀâ„ÓÞè݉² ×E"՘ЇÙ÷ÙvPÅ1°ÂˆžiñcÙOGšS½üÎãH»\ÂÃqœIº8—òmªˆ¿¤'9E›;_o8¦š 2OÅÐ%;/Hîqë‡Jjáëò¸XáQœ]eLç{ÑC1ƒ•“o@5¡Ö”%TþêM½Û7%Ò‰æó”Û ó<ì[ºó·ŽqÀ¥Rм={úõÅ=2 »^àÿñ´zŠ]ð'ãM6èª-Zõ§A’×ý>[I<{ïpüódó>./:öl@†ÈH ÿ¯ tªWrÛAäÑrt÷nÑuª-ª–Ò÷á÷âEÜvœOtuY5À ›?ZÏmÓƒ¹JÄ)§%øt—Ãß oiÞœ¾—ÁêYr–Žƒ"^ëð šT~’K™‡v”>´„±iÑLì—¿IÁ®™¡;¿ ¤¶Õ¬2£‰fùSþr-—Î(©•R½Oˆ—3tû|g,4ô«œhïxÞ/Ó°N0Œ2rjúI›e”¥Fí|X° ÖfÇ©UÙÞ„—õq[qv=å”6”uú{chF{‘ñÊWP°w’„aúÀ8U›Œ¸¤®šÑIáP¥aíÅÊC'I{ð o‹ë§¶ël,½­CìÇS–¬Úi¢¢¡ÃJëC=?5oz’€€D¤1¦§ }RüÖñ,%… ŽÎ÷¤ˆÇVßð‘}öl˜Ÿ¯¡œvS&'—žEÐ]Tz…(n»A¶Þ(_»bY¤·Uƒ2É:çØ»ã¨2Ï:>Ž€Ÿ¿)}@ Zz‚fЫz±Õ†×?JŽvÐ9æAl@·~ûZ¿“j]MÕ¾^ tR¯Ù´Ò©Yû?+V¯'\W»…ðÚüXä㯠onøf\òC\l,DjÆ_eœµ¦¶ÔIû¨ÕZ$%úDÂãüÃ´è »æÏÔ”ú­MÒüÿ%/ n¹©¤fàä`äÀzÖDwÝyôÕ bð=ªõ;Í¢¡‰‹ú¡» w5`b»>R׾бÍÝØ3œ(¸°† OܽŠ6´¬?æ¢ó3ôçåËÁ”Wê˜Q¶ØG!zÜœž¸ò/oœs/TÒ;-0Òÿ<tKùj›‰Ä»UM¼ÜÖgã¦? ¥j‚€ŠÇ„ÿ˜(A·éÚ {Í‚³“Åûß‘k=Kh8XêJ`Ã\߇´/œ0Ía–*T>-_HC Y¾ƒáPL[S–§´hé*µ wìe¡¥÷º^i¦Zm¦Pƒ:F‘e/ñ'¸*ÅŸVh¬ÔÎúëù…sb¶Ýx½þжa6b"õ&¿Ë™¾;%?kvÛ¶ ¾iq6Ð Ö>óaÝÐÆòj\\ìv^Ð(U WL °ba²6(FÙ#*ŽèmϬë;piD1”ç·ºkÝÊC¹¨Ï«V£¶ÍM`…“&ÓÓ(Y76ÐHë lv¿kÅ1ñˆ|ÀðQ? ˜kY«™cÉžGJ“¦ŠÖX¾Û}c¯ÖÏ3ÓKkÏT¾¢kJ¿?p!÷æß@«è þš â…ë¥4ÎÁ*â51Öºßj[½ŒébA3Áï^ÙñûŒŸ„Ö¦šFݘe³g ×ÀðG1žXß_ÿÒYU»ÝùÓÅÌ ›_/ÂSb7I ÜšÕQÖ! =†]ŽË!ø]˜Ëóziþps~ƒ)Ù>;+p´í³¢P3È@²ïÕ„’'_Gõ§6ùVo:²áÜ ¯¨y‚ÑÚXOñSú¯Ø˜ìŠìË?x÷ÂPwƒ;ÄœT  ú[Ëбƒ–TèS™—_S\òJÚNÂK«’€€·Š#yP\ h—ë§²I$Ý–W8ßÀ %eù ¹.bx£H˜h·mB÷åsÓm+í¨nÞ3«Z«¦^$ºõ5ê‡'ÿôÿ yÇ—Ì£d%jR’Ù³Ë`³ ­££¹Óó`¬šiˆGݬ1z±@DFW¹> †ç¯æ¾³ý¨@M Õ°KmQµ”6Ö/ÏëÄÛ(ò÷ˆÐLåL4¥Â7KìËYÑ“ãm H((ð7Ÿ9r@è©pÉ-ú4âic¯J~Ì€[@’€¹3kC™âá¿+ÏD«Ê îoy@|h‰uÁúüé; ×Ý~ë5ŽÚ¤:4EçWÇMÿPûb#¿‚Æaà+1“3Ÿ\‹k^ô9~[ î­×~æbR÷sõé=<v²lÞÞ”xäÀ¶BG;¯ïûǪ,ŸY+ü¦ƒƒh]žàQÕo›8m–Ë;± 2gá®éµóôR ‡ì4îrŸ¨s¨9VÝÞ†,á ›º¼ï,’Ž)ð!¡R%‰]j|uŠqj& Æ=h+Á‡´5˜²Vazò§'Ð&]ŒÓ¯ý8&މh7›iJʪ¥FC[Û¿Aj]üôž„”º¥sÑ僚Ž'$ůà–1j2·Cå<ªqîR“©Æ2o4#RRåA£Ðç´r¸&ðUÃY}®W—‡¥†åéÞØ@ç ÑBl æÌˆ®š$égöwýeß™û‡›d3/ŸÓ¯Ð0ˆ‡ÂU¶È½3Hå윥¶ F»uS}8Çy® $!ˤñg—ZL­NÖ00ýdkH^é¨[.ñ+³sB?½“öë³i †{ÊÈÏH„vºct*‹ ÿÒqy³óÎÈ;§³]ÿçKª ÔdÏü£ÎÞ ˜K«^ó‰óàK3™¸³‘IÌé(VœtÒÁ ˜‚ž^òîb<“m‰óé ‡ƒ×¦lµHñ5ÆŽF’Œ¥š×[ÕU·’?ÓØÂ•ºõÏQ™ƒ²ùöSµ³ÞØ!ý'›UO‚г[XKCY”ÓÓX[ø„À¶…ߨÓ9e”™9Ðe,źKã ƒJVàÉG¿ƒ¹!Èq¯ÞÀ~\ÃAé‡vJÞü `>XÅ6ýXyöî#á¹ä®Å Ÿ=²…W‚4¦á¡ìá•ëy´A¡f²iŽxáQ’€€í¾ÆtË Þ‹¿Ã£çO”lý $=¤õÁ®æB K¤w#Ê,þàr÷BŽ'$%º•µÍá¡[ËW^§âÌ›œ¨bpŒrògÊíÀzLÓ]žê‰DÜ©IYO›‡}ü{·À>v)ð4…k})<• në~ ¢¢Îâb‹ç Ljwº2[ò]?©ñ½qÅÕÞå˜Ðɶ}œ®'Jþ¦ÕiŒt…0dñOMëìòhz•M±Fj["óV\êšþ›gÝuáÄ8ŒÚ³ü»‚{©\k`J‘µÜ(Ëí&d°™¶ÐÉL¯w^\Êý)‚£¯­SJdÉ»c žç>(MŠd…Ô$+rdF‘nn^¦ÊVwÂE´íŸ6ð/Ó˜ ´xJ‘ðGî]ÁÜ.ésÚW>q€ð¦í…Ž~±— ¨Ï_vŸzÕ±Y½”Ó`»èhUm=ࢨ ø1ô\®T“ ã,Hj+Ƽã;ßûÛ{¦ÅÿdÒ//6`E;~߸n|I™õ³ê=’å½P=ü}Z‡©bò¤^ºBug{5F®ÿ­þˆ¾Ùö^.3ž»~"Šrp«œég%Ÿ€8¹ÐwÅjVRuôH2ù;ÐYñ$J½H?6¬Ã¡y˜JGE¶k¯¿uöÐÙZs7¶¿­Þ˜Qbë{:g€ög‹˜ªÕs‹ÛÜ™²ö$šCÓ•¸LªoÃqÖc 󳻓£±9JÄ™üÉpëã!ÄÝ2„Ý¿“ú°ïK\W²ÑHìý•N‚|·zäC8%ôB;ŸiÚþ½e¢^PÓuïö—….Í´[í%/~‚}›8ið`Ä‚B¼-ì¶“Ò™ç"'¶Æ.ôHsW¥9ž36pÏ»8‹ÜäÁe  Â»ÿw)gºÎôpÎo_ƒê+còlÆÂØ2äOÈòáXJÛfå¶6óÐ*8^´«úÃdÑ•ØiYO—…CÿãeÍPX¡—ü騺u¢`Ý`®!?rf…;u^…voé2ÜD›OK nxe½¬…Aø&n?xÕjàfì³ØÓ$CŒ'˜'…Úˆ©‰¾ñ±:B”ý3Ð@½gh7üAiOÖLŒù10Ãá®Nçp ͵Ôl·õ‚*Meó¸„ =-Spo «ö’€€ÇÓ<&U³+ÃLºRð}n«ÿ«2LÝÆ.MÁrïH‰æ‘®jšçŽ^A‘g8õc=5›àOD.[´{Ô{E7+ÄIW)B<%¼JNyhñ®Â¹ñ¶ (Ò¢¡P²hòÒ®š2÷q¶1ý>Ô‡O¯ç çÍ%x_ÎÅ:€7ñŒDíÍ ­T¤Òæ’!Gú/ߌ½Ö½A{6ε³32m:í-'m_Ù3? ¶Òð ÚÇ$¨_·¶ë=_…€¯ªh]5âyVEz©ñí·²OÁ“òÓ€ÁÑJýìxD ç ȧf=ºë‰²aë•õHþáeEçÓxÉpÖQ¸{Û“ˆ•GKu¸ª§¾}®DÔVb©á…,Šxá¹v–qÆ›t°aãšH] ?>£ÑLÝ”µ0Lœª°++‘}ð±hIá_¹u‹%ê}Uóä.–’Yëâ§âë}cÕ_;5:É™‚01Ü!hòôä²5sr7q&§[Ƀ IhãÜææ„lÍL‘¼I B/棩˜NHaÝ+äžqýþ WQ{§[Ðm!ÊŸþYSùlÚertp¾ürCvÎWEâšéê}KËð¸­9-õ’š,\t»Qã4DÌãÙ{R,{Ï¡1Ńº»’€€Ò¶2Yœ«š"ÒÁÇód˜ÐieöZÝR?©Ü¶©1‘l] ?¡£—ý¶½d|änÿ«`Ÿwl_ÿgòÊGþÖ4xC†v2ìËç2“¾#а†°sÆi©N’gÖþÏ€ _õ’Z˜:KÈáTSíÿ§ìM-!¢ÒŠs!$Ô9ä–ÙÎ’¦™Û¤ Š>OÙפМ¹_4[v(½ì•Ÿÿ5õò8I„Æa©ó”ߎš#‰‡«¡ÀÖù©@çš.~~ ¶ <¼”.I½®w‹ßƒü^¤]O‹~5AÄ»×é%èM˹ð'{!¥ÖÒ}fÏ]Ÿ'¥n¿~Ê©úÛòsdÓÞ)=ÏZÂf÷)›,m#v¶x'1ÊÂ}2dHJ¶É,ßÎç/Ç0 öõÜÈLMÒ3ç[¶d‹R”ÁL±=w3Mÿ9Qq À°—­©â[ J£·R‚z!iˆ”Ë—’ygÒ2úc´3Ðiì‹ a´úøû«¤ý"óç ÜH‡¦Á&æŠá¥½›Ÿ%ƒMCz¾ ·$Î…ÜƒŠ‰¯@ÚTU î^³R»Ê.«!JIîçŽ*ôŠDàë1¢6Ø7v‰ñæGIJ@Õ<ÜåR*×±Ân†]Uv—¸+?®Æ½K¦`üÝrݽž¢N{Â.Û…“@TŒ¶f4­Ìîôž¶‡u´•n'¥5£k7ºR§VU)UW:^>2£MIN–†º Ø¤@Ów9¢®¨íáÖ'Û\TžÞ£S«ˆKíu̳ñë7õ:îáÚ¿ ´gÙpÓ=cêÆ»ÜKqncÉ¢˜ƒÿŽðqóãùð{¶¹m5å¼}ƒíñ\Ÿškβ®¡xcEmJ~¬áq?jÚ.m6µKö÷C÷¬¹,Ù†ã³ÏÏ'°cÆ•—³¶KîÛh-L®®`›%k´wH±§]§~§ò[/6 _æ8úÚãÀFVº+CýIÉR³ß«,âÍ€`à)ŒF…æÏ¸UKG“¶âV4ÕÞs“‰Tªº_Ù˜³#y;š ‘ÜpÇKÛ$ÛÖ!ã¸G,rÏŸ§qtèõ‰Ô:ÞrÇ’€€ë_.OÛ¹<•èjAN¢‹çôqÌ -ó ãv;•™î­ž€«Ð7C”£®ÏÌvt‰¡ 8*A$® Åd/ʱ5ˆPaô±|{d½)‘k_üupŸ p d‰–Ô‚I)·v‡*/Þ/A%ár}•í7W*bJ§OÒüqÎûéÁ"p©‹srÙ›V³ ×ûÝâ¤éÔJÆrœ˜ÿIüŠ@Ãç@‚«*”j½ª³”±pP0M» fµRlŒ”·™P'­@‹¨iØCíôÃZDƒ0b8çÖ÷1ákDåXOÝK).Õ ŒãC"èd«2¤™:Èw‡•4ze• Q‡¤„ïñìS¥Ì²+žFhÚw’â2-ýϙՔ‡*±úÔ Ì'ݹcAÛ”«…Q-6}'!S´­=ËZ:+ÿ"Y¤°ØÓoû©âÖ¤g䦴K˜q‹xRÑ{5¨÷ü3¡&+SÜ,„ªa2µê’LnK FFó‹ Ö·ÀÒ{s_É(G0 4›ž%“”R]›8âÜPÁGÖ~ò82ùã>,†ï7VšhôE®½ItKÙ8²ÑKO_œ†'Y¶]ªñ78Ô)åE42dÃ=ÃwgÐGY§bÉFøïÅI~–(ø™ÝéšI9UñØí5ˆi31ù',iâ>/v´Kú¢¤±Oè6Êó¦}Ž\ 6w-Û î2WØÓ_ÇŠS7Aõo‘$ÎäÔÄ®ZËüðBh Bê—«åYµ,0axé”ñ¾qÛÓ³*V5H*ç' X2I€‰ÜX-M<]½\á+¹«Ñ‚?¡BîST™†»IÈ=øoÇmå«MÕ¥Rµðhæ¬4£©ÉOãH„loX>’ƒžÈ«îoJ*c@ˆAúÔݸjO »WòLUã`kšËÀ/inß­°&‹W–ÌÝ?ð¹ñò@"Qì•l1O‘Õ´`Ѿ˜ÛyÇ Å%+ª°ãäµ®''h’VÚ[ÁÙ™ÄqÁÁ/á ]v$¹f¸G ˆ‚ˆ»+%‡¾B¼‹>¿t¤§®Í¸S-ÜuŒµKÌ«¬#ˆ6¨¦^0àö:½†:42ó»_a¿6å’ës&Óˆ=†ÌìN‚¹1BÙÅÓNsöª•v>täé³iЉ`Mš>‹³tyRûôÑ`]2!ïЖÇ’€€æzkü't‹'Й â<µM+BQÉ’Gl/‘rõ͵ç@Ÿ‰s¶L„ã,=()<52éÐñQ|<ÏÚéˆÅW¿ã|k5©xzr‰âY´õh~ŒÇðvˆìfLHRðÌßî$ ÌkT{/`4*Ô¬?}ñÊåã%Nfr´ É^nLžÈÛåîIËÂÀmpAÛ)¶0.bO"×Å›«’ÌŸ’Åj^E¹Ü,(DÞ`ÜÓ¦éæF±Ì©°g¢Ø;Aÿ­ ÎN˜À,a!N®›,LŸ'éšRô?ýnɆ&Ï)L2u|*¶Úµ*ZÐ\D]»”Š_Öƒ­–Êø\¹/pàÇ$6õ駤•­\¡´É:)ôÐ1qù÷+Ñÿ0ÈOø¶ã;sKQ/gÅ›Ug Ô¨ÎÒûY:>ìYß”÷€/,ÌÉ—ïJ’Æ”l5ÏÀÀ”%±®à3'+-X¾ùXøoè(ÄFø÷Àôg8‹bW­¬6f3v{Ú)Íû»d¢1)Eà_Ýà<&þ•Ý?-ÈA•ë¤ÜjÔÊu]É’õÍx$—œ©ÞœRã]îZ$SaCO¢OnZÙÇ{{Á°MtØ›–·mõ ][‚þ©ƒ#­§Äñ ûäŒ|«5âsptmh®…äöuîä¿!Î%t¤_)X;æ×c)9|VQx)§ÂÚD_ó>xU&òžêµºZq¯¤[µV z${G¨¤,+­È¯h3.œ4¨ qÎ(ߊÂßH¾ZäÇiºBz’ÿk¨×ÁyëÊ\ ^’Ø}Äf'´àtIÛp`mâÙb€–°9E'ý:û†`t=ï#5}Ñs RS¯M)ã·ˆõÆ¥'?®í“2 *n”’€€œBÛóAŸ8ßÚ ×x娆´4¡ ³…´ÌØ:‘Z&z%U.Þ½ð7¥Ö¼ÇÈÍì;9!êâ ~*‰ùP²d|í°Ñ}KhX^Ëéœõ @þ¾0L¢­Å²}MÜìÙ?á1 —öãü¾„¶vnY5w|sµÿˆÞV­^]bH9÷ü¹`C׈\Þ9b»&$-ŠËO$¨ ±zͦBè£þð(´<”XÀÖ?ŔԼï.½ 6”XW›!¦â)õ•âCÚZVÃ>’çlhˆ‚6†÷Öbhdáÿ U•¹h ÌÑ8:±}>g!àÙæá„µ%AZŽz+-?=$4Êx‰J–‚¾Ø5Gš$QPpåhŠsc~‘RÕüw0À&KEˆPJ‚™Ô€VæCSµÿ½4²ÔÞLÑïH\!œ(PÉ­2Ú[ÂqBÁ@iŒ‰Sä8Y×:úOD£X3t÷‰/›~#Z÷, y½+/÷Æ,¤F½ ûw1ãwJŠ)<Åþ°à)'S滋öarÝ— w 1}ÉÖKx£ƒ«eÀ1Ä\’Býq‹ba¿«ÁèMªÚê·™;—«€¶Lto™¾)t×3ë”ר§~ª Þ™M¤¶ùûÅ`žÉE—i?ƒ^ú¨ì­:ŠÈ™T›O` jÑ6e%%ÌdKS‰Ð¤“¾©\HÓ¤1î®  àá]" ™FU@"ªc¨ª7êzÁ=Þ$·«ö¼=¾‡E!áÌù§,@æ³³ê3¶R“SÈW§ÔÌ(`9…g:)EÇë5nätG1GÇeóy*}¸/BWÌiÄØE˜}˜+J6d½i¦e÷@û ¦R .ÜàÔï Ü›§c¿BË¢cïõ–~¡g}ÀƒÑIœ@‡þ®©­Oëë¦Aÿ¿øQ u3©{n ñUœ#w°Ø|mMŠôøsÁDlÚ‘({L=•9‘ÇLj`øý«Jiÿç˜Tí4É’ÀÚÂ<¶‚ã5Ÿ¡/¦hÓ°ä*¸z‚Ý;a1I”A­ '‹3¸Dœÿ/T“_-#!3‹E¤T7.ñk-ã-ïŠ*zB´OF°î»m³t™ÆçѲ_º—Lœ±òÖ¥èuv26r•ÌùöîÁ>šé­u|ŒËEüÉXØ»|­ߥšè_.&´’€€Þ+Ƚç öB^&ô„‘„£vGC'ïH^WjÛßMw-v–Õ=¦–?MñÒêâyßM*{^wÆ•Àu +v@S”sFz 8_¯ò´ã~œtú…aïµ|°7Dó£ÑiËÀ;G M—$›ú ù"Ùo[Q9ÇdVŽÜŸd1BvÒÈúf_#Y -GU¶‡>ýˆ±+,ËÕ¤þ’Æ·_ßÈ¡’ž‰]~ÛW)£vÚ2ȸ^ß÷ˆÅJ¸ÍÃëØD¸Æ>o÷3ò û;‹ _B‚ÈqFJ‘þTQ »tû8Ãì»¶NCä|…»ßg‹® ¤Ì%>¡’¸Ø¥fêHqQ —)ºJ #n ÀW”ïÌg¡‡¿-a%*³ÜßÎ<™Ÿúóg…¨]¡«€ýžE`uO¤ô¥¯Guzg™P¯jì€'ä¨Ló}BÇ¡š,Ðh£x|Ž5©Á8(FC¢¶ëç¯Ð¥è"xµ“¤OÊ(•Im5>PwÀì1‡·Q3¹ë¢˜YøýNµE<)Jf3]‰¾Uª–HLÔ ‡§|þ£q×ðçnoœK?ƨ»3@•é›úÏíl)FK ö˜È΃T6ɔ㕮…Œw¶d¡Ö6p^+ÇÖÃïbx4FwUÎÎÅ}Ô™B¥±šÚ{~bdƒ›"äI ïÈ—¯eÁ׿¿HêúJÔݦeîH~ Œ/&(‚Z˜ P76wBÛqçDf²â6ˆ$†-]ѹƒ9ŽtH¨íz$!÷៺î2ÿßÞÕ_Æ ñ»{0Þ¥q…,P–ëîF„Ï„y2p‚Øhdƒc‰­;ŒÿÀ:­­–òï>¸ˆ¦ËíÕA´fu+l<{‰°G•QO>¤+)ª —<ž•ð-:™Q‚b@ziñwÇÏÄã,áx®wH²¬>xý¯ ¹ëmªHŒ®jOå&ij6ïh®­D>P—õPÈÑU´Õ·gZKzìFZϰ«;mZËÜ@ï>É—eLUxÞ®†úYÄùG[C)Ì`r/û"ïæGñ9aýXjQt9j=Þÿ¡únúEÌA4ö€BTœC¦NT`ÑØ÷ÐKÆ&z# b™ÜüåßAHR&$Må†Gº.ŸŒ{Çî±y3 vŸ?‚|ˆÄù@0ВÞ³é¼7Á´&M‡Š_¼¢»ÃЭ’€€ÕEWAFCòˆà$R‹Þ{ñœS¤™C8¬ò)Œ”îèáÏD¨dNžn²|ðqšiÈφ²?ª™‰=2øêµ.J¢ª›‡)4fUmW/,Ñ^ÀÊ@ (a,Ÿ~|"Ê{‰mL»Í’¦•Þ  ’Ç„ÌTDk‘ZhêE-ŽzÇCØ9‹ò¬¨4ŠeêYÀÛy³ë “ù]©e!ª)@ ‡[Óµ¤0§ƒC5ßa×fàZRH‡]ÉœJŒ“…"¦:1‹}¹ù ûWͮȗÊ`Ç‹*Ä|gz­¹¡ÐãSQ7S„„T±LŒ5íݼláᛎD¶èô9\‡,T™Úš “üöôr"óÇΟ‘мràí)oK’{òg_O`Ý$n&Sfˆ:ØDå¼ý•ókÚMfîX‘/I¾þ`@Qã<<Ïù7j¬8£ràh.Úü±©\vô×2-`å‘#e€Ö(‹”E‰2°§€ë”w[÷çèD!„·^\y4‡wv´[€c"˜-«+é7K;¸À"¨œ±DX§çì™m¿Ôˆà¯Á«{d®ÑÍ"9‘E{¶RL(U§uÔ_\¯çTyÀߎW:GíãŸD'²¸@²Ž&¬ÛìòU‚uHÏâò·+sÄŽg°‡îŒ¶‡%d‘Ý*•®c-zãƒ?ÄÆ}Ï\*¶\h¹‘ô,­PH–¨— /ѲÀÓcqù/ =GÖÕB½EeÓªæ—& ^êÓxÀdš8?×^$ò ÿ:ôSºéCˆf4ƒm$n«?Oˆ§Yh¨Î wIã‡äß<8Ͳ³{ J Íq>  JÂÆ 2ËbTo´y']°˜í–û1ßg5ÁˆslÕŸG#©Ù˺TWïF°®ô<‘ÙÑüÑÿ­F#¼çi¹Ö™óÎ÷ÐTeöx¸! O¾ûÈ&ˆx÷PG R;Úºo„w×µKFméHäðÚ?Ò°ÛmkšÂQë?”¦\öÍe0˜Þ"Á¶'ÏñZ»Ôzü/ÀÆJÅSÇMkRV)7á6ܰ¡Û퇿¬¢e—˜½7! N]öÇ[úþFØŽ}Cß~³J.Vì8¨ùËJ¦@™É¯ñs®Epÿ5t§ƒ~Šø„ñeK@†ÜÐoT g1MÀÇøú¤}®ÿ_Õʇ‰›v‡òt/û¾¹‡ jxù^/°5?A)U.AånSwÇ6 i+#M‘ñ±f¥–@W ¶ì`•NK³\wÝ›d<‹ÚèÏ8~_$)¶ó´å‘õÍ·ùnÞwªUG× [ª F+Wb4¼ PîžÆQ}oM‚Î{xY\¥NF9ºýµ*½ò_6a€ˆ;º¯(LÚØ1FùrJv×4æÅGJ„Œ{Àð[´Z…ç]Ó` 醟6ëw¥¨=O…vEúÌóß«™ˆÜï`WP{c3õJt”ÓŠuT7Ú"²L¤=ž€N%Å.:0.5EŽ«Ù·ásÀñ8|ÿÊKeç‹{z![Ìä§úã˜ñ6º̈© V>Ž$6ažÖÅàÙû¿¤Ù c›&ÓÊ?VjlVT,?ín :%1—S3õÆw —ͪÊTȫ΃ÙHÈ[öVª3Íi-`Ù„ŸÄ]‹Òm,oáÙÅ^ù¢B ê'í(•‡~zû¥.•ÞŒC±}æÊ –r"àN6Çe©@iýC ”ó²ulúÔÚ1ý…T?tLHëýsÊl§þ5›ù…QÈ5¨þŠŽµDïsýõu÷fR}4ãì­cà”ƒ•‚0/‚)F‡ŠVFö/}ü÷×ÄNQg]V‰že…¯nâyµ{ª’€€Ï¸4LR5Ncp×póþâ8¦Óú5¬Êµ§!óQ¡uç^oÂGkE´-›Ùÿ‚cʼnÆWñ Ý ¥\áqä ¦RèFÇVUÆ`®)`TYNMh:Û€ÆQáÐKv^c»}DÉÖS£ÇX‘÷¬ÇÇ(×÷Þe/Žxâì·Ô8ª@\¬Í1=ÿUý«ÌXœkêJè½>ž±µŽt©MgP]eÃÎ3šé ¸kcv›\a%"Õï(µ²f™ŠðLZÆL´Ø+nÖ0WdîWE€ñ˜0[4i)¿MöâŒå²ÅÜ8Í”–ô n0¿sÚÖ_IyŠÖè@*ôv!Tæ‚»?r‰çN ~ÿõ-¤YÓa‘0ð7Èqw°ö®×EBÃo8:; ݇Xg”µ£6ER¿ÿ_J-<æaþ¶DÜÝh5~¡Wõ_F!Žjáûg îüVn?Ø$«2 0WXpD]|ûíª9þ§¨É±‘ê宸ކ©h-h¶Íg)ÝÎ á>ោ„Qtr)W¿‡bp£Mýϱ%ñô®ð-0ñÌrÍ?LàªäG4èewº Ëõa‹Ï@J4Ô“3¯´!Ä=â¥Ýó{¿ï(¢©'|ìÆÞÖ]o29ßtå5*ï^Ǭn$¦]aiÛ£¶|'õüQFÙ©öÚÉ‘HŠì%0ÿ[úŸRné—‚ˆ’IÏ«îµó”Ö>k”­Ì=^èwŽ繈žÝâàÞ³<®üNMÔáä û?¶Ï±=·)P›ßß7ÄŽòtgþî€Ö¾']ü–„SáµO¸ SjrQ˜„¶6²¾­aöåíï*íI×jA*o®YF'Ë _õ|o­ÿñºA×Bã^ŸÃÛX+´­@iá2¼–vàK&«fætãÜ®6l­èTQØVâÏS0UlN±%G^á<—ñ?ª„Oç»6zzG,Ùªëƒ\M£$Änk–O,â ±Äboý)·ŒCã—_ø-u+¬Ô{Ãöß/½·†ñ‚9¸ZuglR‰k°&›Áë[L*¬|E§˜6«´!Ôù亡Ć#@‹ë’"J±XáŒybJÒÖp=½5;眬9¾(qFµ+K"Í€nã†õwµUÄC2=cþ~BIàAdÇkFY Š»Û@L †’€€Ê.k«áeó&- C_4[×c6Zozu‚dþbYƒÿ(Ræ‚êy€(bg—† ª—)LÖ–¤‡ñU™ê¬p]Ζáíõ[å îªþ]ÊãEUöÿÎMZ@'KE Ò䀳i/jÓ–wH^æ °Qs,®€"öDÁÀGß•‰&tš±qͳZ2/…+ó™ëtmòå'ø†Ç”9Œ!Zyðgòs’{U1’ÀF:He^ž'qáïNf(Õ˜ª.ÚˆæÆË»ŽÿËÕ„[»ÕNF3žË{ R/&€Ézt†Ú…Û¢­ª{•Ù^£.tZŸ9ùF%o^Wg ¸^'ßhú¸,ámT=ôFó3ØzËSI•+â{zÓEÒ(É(>ÍÓ«-Òâ>/]ó4Œ+Ó¶V¡+Û¬/§ZA>É´õ¬­*YÏ|¨~ßh/Ò$²Ÿ†éà·|oTIðÿ–D¿ufŒLd,;ýf·ˆ™M3ŒŠv[j2X)…·¾Çú<°K ¨›ý™½<0 ôØì¹H"¹yžqwa…+Óž7¡CÅ•Õ[˜Õ &ü='Üú÷x~Ý'¿—;KÝhÇ/2º!Æ|a Ù=¿æã¡@(whÓXÓÃþ§TypoA¿¥:ïpqWœøgÊ›Xì=°g¼‚€ , ìgèyó5ŒÇ3ö(Fô­Ã; \ GÃl›·‹’âó.³Oü{2v罊$õølA-ð&´™²²2{¤Øæ3“Ævcv ‘îéñ› ©`w_+˜Àֈѻ]ìO/Mœõ‡ عìv%·¤Ú‹2Åò>I'±Ð¶Œtÿ€ÿ”ÏÔÐ}ހŢjàö•ÝË886d0·¡Œ¤æ²NqÉêrîÏKî]›jG±j¸²]åDoÐôÙº)3^»Èy$yHœŠè×S…Ÿ(>CáɲFJ?o‘A¿[&Ò‰×^Ìð¤…ëv£æyÁƒûúe©@ùƒ¸î¨rõlÏJl§7}>‹ÉdD-eGÒ¨1Ê<ÄýP«¸eBl©b¯‹ìÞ@ˆbµ«ïèåVp`˜ƒ·"J£•Ù_Vi ã®Ê¬«)–UF};'¯NÚš?«ïCS-´¤Å+º Ÿ~Ó·­Ć_È$Mrìú8Õ0ç5Ê`R6ñòŽ)…1@#´Pê/gÿW‘×¼±Æn¼ä#1v{UÜ6ôW)·Ö/'óß6ÚKa÷ñ0`ï¼PsÁÜ”²¯¸9áŠjzoÊJªŒb[d•9gÈnBö™xñœë»Û¼¼.»7³{æ:…ëEøÓfD“d–)œ¨ÉUšo ¼wuûåPR4nêKõÐ!åí,Å‘#ëFq¨ ªON(Ë‘úa’3o1gë{­Òþ˜r²™-¾X@Ïñ=1¯Ö2ûR¿ˆkÿ¯÷@³åmigy|`…v>±¤`~w»YO©†‚(“ ÙöC Ðv”1¥žNï_òu¯›v— ¹›WÕÓ›cˆDÍ@,蚇˜x"êyøÓ;|¯"ÿï)¥Gt1¥Äì.wù©k‚²’¾…½SlÍH¥Š`LN×/ ïõñ|§µÏkfF[‹Ø%ø-͘Յۑö„×”ü[y‹Jàád)ôßf“‹4‡(÷¯ìê²ËC1øìÞRÎrêŒ;9xtwÄýv¾ª¾¿6ý$‚à¡Ò×ÎÍiõtCÓ¨¶?XÙܦCb1Ã’°^>¨B{*à‚gª3ð¨„ê×MZ@G*l¼rpOŒ–Z·]v©7(v”rr?þÊœßÝÔöª#äÚOStäð&,É¿ó‰þ‚XðÊ6ùÙ{ FÕîÄ£€{9mº·ØZYÖ۲ꤤaO»E¼a@p!J3÷Ê÷"ð‰:ÿ^w¥Y¶]Ç…O•uêÓ|Â:6È­\2„6Ø9#7½Ugû¾_ù¢V$V‰NÆo¨Z7&’YÖĦ¯œhnßGUì{èœÊLöÄDT£ßižïí ŸÁ™Êc„•çB¨¸.%–< >†±6ÐçÈ%ä‹å$ dÕ-ò—ˆˆùÃnÝwÓ_¤½üc~ÊÑ•9ä8 ¡zã¡Ù÷Þ@´ T…¯ë_tX› µZ‘a¡FXCÏÊ) FϪyGÝ2ÿ÷𞸸û0¨Ë+U?æ*ZWWLÉó@”!4~*ŸñÈ+æ!6“ S&es—£]¾¹˜ Š_²ÎÇ Ñc^¹ÇÏE® ‡er׉„ŸÖ!ú$­i&ÔyÐPm”D7Mû—ñI‚v‡m¶Ëó$JŠú•Yåwý~q¸M‹·ÙÍ—Lp›S/ü|ɪeü.Öf.ñ  –‚¾¿ÓÜ×·†¤·ïƒˆˆEö,Úp¦™F²ŽE+es? ·#æ1Ufwظ,KH¿mµT.’^D°ÝvkKC¶Ö‘9KØ»ê– »œÖoú’7ßåq@cñûxâ´{÷×Nãcz²˜×†;Mú¸†Ë7ù‘jØ{6L§­Ä¸ó‘Iѯýwé5-ŽIR}Â-Áݦå¶É ÛèÉù 4óe@´!IÎ#7)ƒû^3MÀµ4Qb‹ÉÅ>Wq‰sˆ”k‰Ëw”Ï_’-Ü Êü¤!Ÿ_3|ÅI9O}‹ì6‘Ç}øÍâÙ+\õ0?>î‡TÐ_Þ£¨¡Í„+Ò•Ãîöð)vÏ©Ââû´LËG=ˆtþ]F[’qø¶š?dóa D/–Rø¦‘y4wJ°è] $a,¯ ùË ÖÚ7?øêAŽ‚Ô\–©ú•°¹¥ÅzD‚m®ØEå‹e<ïm¸÷uÆÿë-q|kò|úJ_™A×2&1^'ÀJÊåùQÞ‡£+üúÕ3µðÁl¬‡v›€(Ú`"öõìG_q‚Y.?†«ˆ…ˆ@÷¯ªdIJþ"GÂWSÂ׌Ð"mÆÕS}ÅÅ£a¾‹ƒðb…ZjMOOcí/MÏ4†ƒAàöðvÞ|5 ”Í× þázãgÚ ÞL«¼HlzQ¥r2ÊD:"_r8ᤌ6ĉè»K4O—²úÇt K¼÷˜lz;TÖ¼Îò© ýÊû¾õ¯tÄÃAoBøO¾-›¾»›C¨-¦†RsÊÖÁ•ÁÁ°ãÍùàyClꥯñQ°›;‘mvíÚ'_â³ø­ðÚÙŽÑ’€€ò­¶ŠÜNšêÑ<°µyJ^ÞáÖÐtÑ2àc,r SZhÿòg;WÀÍVBÌÖ$i*”ÿ§ÈSË Ð,¨œŒQM“7Ë€ª³QAûs&¡®j!%¯øsd{=.?™Ü_7yä‘,eÐwó±8 ihdzµçÓ/ã+ ÂRD—¾n‘Ò¼Åhn}†Ñ>Ì]šÅ%jÛÝ/]XkÈ“$ö…òœ¬¿fQ®1UKþ;öÈáTUÌÙÄÐ$^p+|²*Àg˜T¾ò(æ]êiª,Ø“£Uå¼ðn~d*î)¸ŽÊì¶ô›Ó… þã*-œxꨆ6^ûêýò]QÖ0$«Y,ㇺ $¤¼ýÚsYQ[ÈΜ¬îIroâç$Ý«£èZx̆ù€è箞‡ýõÿš‚ÆC_™ùÆs/£ ƒ'$äuonº‡@ðZDì˜ðĤ ºM×þîÐûhÇl"…‘m—ùY>¶&¦Dv±^*åÜ庽KÍ(‰q=I/ߤáóÕeL×Iâ>(Obœàg£éº™1ƒó,™Θ°…‚uˆÁôú”Ès#–ÊÍÝÞ†¯zwõˆš^A*¬Ôhy¹×¢­}ÙîÍŽÏú à£þX"L@«ï̉ ײ| æù¬`áj=« LÂÏ«]W!ÞÌÖì‚'¾Íû m¨t•%z&R @Ôìý·1Fñœätñ2üóGßÀ¶·ü'Y¾˜3HfOèXû”ùô•«:îGrõ¯H>z*½‡‡ I»gÍÇéÈIÖ>JœÌ3ßFØÝ¼ÀòÁ!MTr³^ œñ¯òNx°9SÚÈŧe|šÉwE÷zÅyñh‡äé\!U£>ÕÒW$pªàú!dz€£*Ú– ˆÜJôÃI CJ+Æã’ªB%öÁƒ$—,ËÂî›ñS'ÎÿÝ}$[.2ž¸DçÏZK:ÞÙÙ‡‰­F&)wóÂñÒ–HÒow¼Q¦<„9Ðú„lûyD«Q_‡Ó%C¶;Ä 3·žka@ÄŸgžýòJvɰÉߺÌ$Rð,ûÎÿâAÚh=h¼wÔôÀÙù( ­á|ÕO hnm˹Ÿ§Ivv¸•G{Ó¬’¦€wï­uU€ÍnÂËÄ ¹A_n4pV¯°€]ä]dŠì[¢Žºê‘Vã³z‚žÚW͈’€€ÕG *°yµ¢Îo2YÞR"CtÝ¡‰xi®NCŽŠr¬µá¿,7—ŠÏÛĤ\4Jªv‡›X=C¼ 3qpÄqÚÚ]"HûÅW‡;S©k±ïXϯívÕubfå]Û•Rû N‚t¢éÿN„Ñ}DQTÅí¥.pb&„í›LdjÄ=:¹@XŽÉ~ÐkÐ<äÎîÞmí½R˜®Ø¸¤›O7¸fø®ëÅs›”éuÑ©L¿$¨ƒú?ê%—´‰:µZ…í?` ¯º·Fê=\ØôÞÆøHÚ€-»=+¡H½ 4x.¬=ÎÂ·Õæ8º›÷òs¡º&Ö!¼5‡à7mmƒàFèÆNC-èK|´<­šà¬¶(ÅB5hAQÏJ"‡¯]ãcýŠ(+Pºõ»#*;þ£þ[2)v~۽̔D2 ·zÞ=n,ë(Ïyýø–×@£QÁ]â`GO &»l¦Ä1à °‘DòEÇl›Ç?wÁ<ŠZhâÉ—Ó7dâfï«gfØG¼÷‘k²ú¢ ©|kB쨓áóÀmÝ ž{ó˶ÊÒ²*ši?ºÒ‡Ê”¨½Ø b.f™&QŽo—2Èiì[ðÞÅ.àn .øžvëÑ|8Qü„1“R´ñ5ŘÏÊÖg\xÏá}n8]OYür€9M*Q5|;Áhû!9ηyR¦Q“]"÷É`ad9¥ù·À"àãÕíþr8†–aÖ’¸+>ÀææQZÞ18[Ŧ*Þ4c-6?êÖü”Ìc…ññc'ÄH6#gÎ ØãìÍ©¡U` ãJõcþ8ß"¡&‘åÃóØ€s;& _,ÖËüM]½’Çžë<ݨzaìD†yK—™sÊô„³•„V¹* *wKz«K.Fí½ÇEk°¢•Yѧ=Žs0ß ”Ìé1l!8üÌQZ°+ɼkû4þ[pZÒÙ¶˜<Ëí¼(þ¯ƒS-jt9 AÍ~+†KA˜õP{ð[¸ï{ñå]ph%KIHRLã6ÕÉIГ«¤Ð\«Ò„`ˆS±1•=®€%Njöö@„¦žzÔ'ÏŸq2´Ú¸U—Öèt(Vá©<,D¨oí±7Z4¿ª\¹ŽeÁU­pøÄs{`#okóæäޝ¿ŸÅAR=9’€€œ˜©zjq/:F¨­Ÿ;öbǼòJ:~Ü;ñØu¯¦©©lLè$É\åȸΠUû¯Ýޱ8ûH’ÍdÙÑAª`gÝöêìËÕ?&ÎÇp‹Á‘o¹Ðœ{TË12½ÖÒº;®P¡×¸c†’*ÚåQÅR SÍjŒJtŽY4€—/¨ÐV¤5fƒB£ñØŠOkÈÂbJ¬"‡'ÆGòµ ogªøbdŒª145<0f_ê¿Di("¯œÀÞœþ]ÃuŠ·6ðáwwÀZ=YŸ!¹$~?C!Vx Ý”Œ–·T™Ú©20©%ä™S‡Wç‹R?(‰)e¶©âÀ µ¥ÕÏÉ¥b%§Y,9›èüsèHÏ€³." kù9‰!QžýŠvdÁT¯T‰í½ôéמn&è}6ƒ´ÿœ³îHKì:;¦l>+`3ßÒãhws¹ëepçà›¦q׈8r}R ƒ§uû§wÏÈ4ìÀfnPÑ·:üršÞj& Ê”¿®Î^†@?쀾+ž±R,‰×[ k?3]eDªÕ|+µ-w»ä-û{z Çg&n\cÚü"m5CþÑÉÉ#“‡I"óË÷£JÛVÍÈö;J¾×“1ŸðÈÐÌw!°|{4œá³ÌÚz•Fâ¹µ ,D )ÞA¨Œë˜÷#1Ã÷â“Å„NÊû ðŒ´â¼«%Ï·Ž¿ 0t¤êµozŽÙ,JßG1µ‚Œòü(|Æ&úƒ“~#y(Ò¸‚žwFP>jš@Žbý“0³2Ä,ã¿R¼~®/ä7¤Ø mž§á4,^ÆÎ,Ñ/%šù–l6,¡¾rmôFWÞÇMîŽÌÂÌTvv˜œ}=,· —í´ê3¨.Ì®´ÛØc•(,ËñÄß72DâWÁ€oÄ¿ö4¤ §í‘*¤ã–Gz5> ´· ãí³R#/-KU!j²±íá¯U&èKùžaóŽ#Vße5…A¯îšN|`’аgHé-ê yÉùE2€P˃ÚJœÉ'™=·ÔÄ¡)ÛéG¹OÚfð.¢JvÖÄùq €÷´[°ÄbâBL;^q;í`ö”>“¢<ô°Õ+ _ÈNX(™Ð\½èäÂGvü_‹¾žÄÛoÛš¨ÖZŽalÎYm»¿°±„NEf¤ ·u嗵˿ž÷áÊ0ˆ”åcêêšÐ_‡ôw0M|¨MXÓukÑG%s”¶FñŽRªQÍMÞK¿üß R‘Å„bìœÐOV†ˆ9u`°EBNÆÕNµÕr.¼E}—‡ñËÅñºj»4ÖøHQº£"Lþå­+÷NæsŒ¤Åùfæ þ=¢ëÌ€a¾ÂžêÕ¨܋a{”Õ5~¿vö‘»C¤QÿP’‘žQ·Â½e}8`€èÚ +‘=XÇâùÏXçš pÂdò.ÿÆþù ½z=#Žï®ØáG™}v¹Ì>¾ûã´Ó«›þ 3þl˜w½8âuCvÄKMtZâfTI§›äò5¿$1éÃkzo.2Z—óCúa,þïºR€´ñ•N0€”ü¶j×ø¾šÐ…<Ûo ù—ò²á Ô“çíCbTË«ü¡Ud’€€Îë?lŒ5O(ÛfÚÕ¶Qe¦»­{aR­P"þóðñ‰ Q —œ¦‡^J­Ç\eYúm¸) ù tö l';èÙILZÍ’ë¯CÀµ<ÀªW;âçnQ¢ÇÇ®¦1wôtÞÛiBÉÒ­>ËÎRqp #ûFçœe–ŽŸ>ƒZ~`’[t¥Žf"‘Í–þ(çCš¬Ì/AËÖtÉ3ˆÊ+›ÖéSšôSÙÜ¿*z“u¡óÐý©”cŠÅ•x1ì-Çaþíö²}~ûÛÄ¢ƒ|×›#s:Ä×2m:óÇÀeÀyQ£c}O`dñÍ‚Yo–Ê5©ÂÓáíÖ1%u`VU;«Öp.ÑL¶ sŠ<ßßbKxòÉ­ °Hâ“Y-zÄ uì)O¥ †Åøìûýóú9àe6¸i ôˆfñìÔ¦v* ²uà(Œµ}ñ^ö3q¼bD&×}^,ÜÄXþM—餀çFE‡ëß§2{x¯ø§Ì?‚Ð#ÓŠMIŸÌ>+ßu'!LeìÛ*‚ʦKrþgB7uÄQF«Î/üßý›…|ÖYµ…X©A;k«ÃØã"ê{EÑЭíè«=ìžË¹$õú{‚cË8÷hOÊ\Kí'Ü=Û\{ÆÐ¶Ó0ͰÑïíÀj'¸Æ3¨áæ·¢vp—LÞþCð¿kí`"Ú^$ 7Ê¥|Áqa#Pº, žø/>f}î“æ™Ê” úü|(ÏjƒoöÊc%¿¨¨f¬È‡“òm¨FƒBÍCvVG¬ošp”øk&®Ø"á+­å¦F§”°¬·aÝ[×伪Y”’‰»Šù1j£ñå—ýÙÌŸ-öZé±`éœ!Ø‚]ÚLL÷ü3Å40ò&w|.µ¶\‘Q^Ë%,ô·Áž˜¯œº×!ypdMÁi£,Ìà´4ìì^„ W‘¾ûÊïF´àD÷(äšû›¦àD¼håSÊ€䢒jÈǵÐh!UÖ&ÿ oGW°NV7{5+ÌWЇçF…À'â,E²<Ë—ˆý‘NN©Ú–" q¦w¿×¾„û»0â¤mÝ4_ÄA+”(¯vÂÁ ÎÊiU·BcZzÜ[Ž~²65šôTµÊå¬6»E{RK³äOz À|*Û ™…dÐNc3Ì| q^®å,=Þ7ܘŠU×:þN-„¬N/êå”ê`\´Õ3±í¨,)(¡‚‰kø¾‹ò;/)•åp8D“U„Z¹k©Õ\?Çz@èuG<‡ÝÊÀu„%‘9z„o–/Äô/lTqlÉŽž€¢J.l ã=³z›ßâ%•Ñ—îÝ´F²9Z?6ƒý%‚¿cwy$y'‡Ø¬Œ£KðP½?C¿qî+Ùc.é39ôCß6LýgËÖ_Á‘“ÿì]Ï9S]þì™}bùÅ­ÏðGÙÊ8Çî͹÷Düöpj~V¡Oñ—v9Qr@~G¨® X£@)ÊíLó*yà”–„Õ-çê“§ÜtC¥r*LÇœR…äW)óêOÁ^½µ$ù,ÊÞ’Ù¾©ÕCÔ0˽ÛŸý…†Zçt¯v†÷”ðóïXkE6)rñÕjö§1#o='±g?ø$)Ïk•8‹zD_¦ `È؉Y@P‡Æwðîn)$O-WLØ>Šè:´\A…„ï0vµßÃA_öàúéß©ðN#¶d çzÏ÷¯Àç ëma³ñqïvãÓ! gî—=Êà¼ý}ñô‘Qˆì-`r’€€Á¸Ëä\Áeœ}ëî¼jkŽ|çv5v?D[tJÞZ‚Ü$‹yol K¦Ma“ÿ‰_IO ¬Þ$à­Ÿ @çreŸD0äÌ*Ø"QÔÖiJ)‡݆¬»m/ØÜ/*µ<%>ð¹ûZèߥ˜jýthhC#ÔüÿuG†|˜;àá>7§¨prÛHÕtå‘ß?1•þ“0Ci½/»¦ÏÜÌânói‡æRI³(#+7È® 0Ír¾åüB¿DÁ“%–@$WBò|¼i¥æ,ãr?ñ@}F‚óº ;›Á]„aŠ®tÏžÒ‚yËlâÖ81šàO·é‰À@Ÿ [±5*Gw·ËQ1q›xà(Cß¾_mšó¨òþ#­ûІø`¾k}çVSƒ&Íׯ½a 3c$YË쎧~ó¸ñL¹óñ˜.º$XnKHP¨Ãd΄¤cŒf­“zÓ0eòOADÄñÙ«ÜÖrôd±‹­¼g–kÓÇoµ¢²Œß¯#u20ûÚofë¢hxÔê)ÞÙ’ÔðºÁ7ãøûŸ/=–oƇ·Ê0š&²µúw°Þ•ÖÒùžÐÆVAõŠ’›˜Asô‘rúÞeÍ ÀàÙ\¦mCåÊQüÙ„»ÑžÄ¾Ë¢wÁùùVɵ¡”¥IÕô ³¬+¸ ãZñÎa‘<§€Î¶íÇ·ãðd߃ãi”2€1È¢^Û¿ ®Ñ¾…™ý†2:>#ÊܵX¡÷n_ÓÔ©$¤b+j©šQ xâ£(‡BôA§òî%l ÄKgÛ³ ™í¾ hçS iî×(TÔr(î^H_ƒ¹TÀ%$|´ðÑñ)¿Ú! ¬{q‚ž“«%¶õ*eÏÂVÀ‹ºIêÕÓöÏ(+o­ÜÓûþ+›æªsµkß!tDµŠ;ŠMß-›a5~¥;Þ35a,Ù±·¬‹²ÂíçÞûȲöž¾Ê¯ÿ7±áð.‚ˆ/>›þø¹-_­P¶üŽJíœ7· j“J*½QyO¯SÙIò £ÏÐó)*Ù¼—𝳖Tnj,ìZ¦XuL1ü¨Gƒ›QŠºX›“¸w°ít+¥3wœ hÿSÛ•k¼ßÊ–¯Ýâaî&y¶X³¢xzø9jlœž)ÔŒ[jù&ÄNL3ñ–‚ŠÁ‚Œ…EèéŽ ²+)’€€§ÆÁr…öÁJ>¨¥oE˜ûv08ñH´GxZŒ¹ü ‚Ä%RvÆ)¯Ïu®=JeÉç ªz(ÊwäK}¾øìe}ídêû{MB^ÐWæ­Ý”£4Åç`a§#<®z|Àžu)d%çðÙZ“÷LÅÜýÇJO$›ÜÓVíoýCUàå¼…Kkˆ‘î‚’Vôku.]uú[|›7™4S}G橼éŸ%ŸaÒnBä¼`1ÕP!²t/Æ'oÀGÈU—ñÐLz§Á¡5«Iy@¿²rŒèÁ¶öKøSm‚œ‚KDvJ åm½)xyc²&½éùVïhµ‰¯ÃÚ)§Tʬ¾d6««#r2}¯Bà-“ï“iõ’®ýj†$LmS°óbï„‹®Î!E¥í^I)Ê› ƒ1pߚ׿¢áÍňÅNÚ÷Uýǵߋ: a‹uŠcü! „@õéˆæ³ÇËèòtû:;Dá±IÒHÐ3 ùdÇŸ˜ÄÉæµ B˜É/>Ûw¾ØÚJªhИ_ª³‹q4²3°-o\àØNwÏÁÂ)A¬ß?˳¶böw£ãœ¢Á•~µX†rÁlmþ91åC‡‰êÇ™Õr«ƒé±Ñ7™þGÜn$× þÌ'%ÊHiK<ùre^Û ðàBùHû"@;LaRã&â•™•+M7%úÄV7¾òaµÛ …íM³¿kÅèFƒ±=É-KP°ù0ó![Rs–UǺ’€€Öƒï›MÖ_ÎA¼f¹ p.Ö¶>¿òW=¡¿2¿R¨x¼“ %”søŸÃ\9 ¶øhË «cc™mr.õìô1ÀçKaÁ¿äõ§Ð{ Θ–˜!G°X¬="…ã}­ÏF—ù‡Å&åô bB¤Œ¬×®CC y•ES_/å¦:R:$!'þýîã4F’$ µ‰©ó“× â@錗 G­ñ÷YUŠ_ˆ¦Ä …©‹´òÂÀþ›-å:Kw@Þ=+Ÿœ?b#(&Âê¨údN¸©&È£¿NLŽ–J &LøªûO;5±k0Ôd“TYc3@VadBçš1@òªÇ±d”…Â×Lü™WÖƒ•ÓúþÉ¿™øiçã‘4®_½PäçìÖ`ÖÙ‡w»¹/©á>®¥3쿈Øß%b¸ þòxÔ ð’Ó­&û¦DQìåüŸ ãJ7…9†’½Sg!ÒH, ®ŽÑ=!Räwx0Þ€º ¥§ÿt¤Y[þœµó"‚«þâ)Ô÷WÉl܇¥KÜП‡q?3Á`ÛOvŽ5UØ„ ™›ƒo[áEŽ’ÆjÐû˜t}èe .j—˜™È÷ò{oX.S,‚ÿ“^fb8dµê"ê{—¬¬çÝ&™+ ¥›{êáëÇjc"oùÜÖ*îÌž}=ÿB+Ð:…ÿ˜Ý-w‹ñÈ&>yœž7¼¶ê¡:­„šèlôëÎkñq½x-]JÈd‘m¿#·Ù—BíTõì&Ÿ*%Ô è2I¶@õS’=vôNœØrWËÙòÍ‘ar Ñ›ºSPè#›˜>¹ Á¸lÞÉGÝ‘|7¯ÊbiîHŠ/¿#ÖÚ~¾à6‰ˆQovØ$7´x{)¢½§? AS'>¢üð, ïâðºÔüwЗ 8Ý3aƳówÑjJÖ8̾&áË3šy(oÙ§áÀ§ÿ8â–§½kF¹>àèªaC‰A„ròš2Ô~W—\I2GÝ[„ID周¯¡#:Ëxg7|Ã/$²kì³ØÄR)€¯\¸óž€%RÒ ñ°´'†©Œ­Ftÿ€mö±²ÞLŒb͂ФÃ:d©gÈ;wÿ9<9VJÎÃÌXÖèÚ‘ŸqS­½¯YüŸÙ–ò¬X):A¨ÇÍs,ÊèÃzÍ@x¨í¡£ú;’€€ÏÛµ1§&îÔ<7+Y¯%ü§3£KÆ&¿,g~éá€U¨ç]i!»üˆLŸCo©bГw”Zì™\zÚ„()ðlÐRI¡k™VÇ÷[jkçÔF댼O7ñ¦xŸ¿ äŠÝ[ûÂÁcq¢ß;€çåR èž.ZIQç«W‘¤x ¤MÃòÛ†8ýG³ ânø˜Y¢PÏuPi+D èå²¹ÍËk‘ÝuTR\€6«Ks]×É(‚Üío Ô±×)²Î0Á®• 䌿Û&’W´3W=-2š~;dÐGTÝ>|æ ßÕzÞMK˜Œé€%FÊARÓsr³W(ò–ƒN¸u”šGȾ—`óˆ|Câíf¯S¶‚—¸×%þ>Q‚ƒUç­­#§âSm.&]Aí§ŽÒîRNüGÔ(áftü@uØMù°£‰ŠS‹+`V"HˆÈq?ϽÞR‡F*ýgS%ØJ{e›ÑÅÙœ¨óŽh mèc-”Ùvza‘×Z?ΔMÔ]$O¤(™w𥢔æÐíXŸþh¥ºˆúòK5lvI+=Kpä»SØ%q9«:ìæo}{‡NŒª2ãö=ãï~íbÿõ# GÁL§lyvZ5EÖ:ªƒ7@Læ'göuXüÅ„Ú"ð·’±%æga²)zûôŸìƒÔ²þG±Þ®åa­6þI(Åôû`ðbý(n= ŒÂçkó¡Ò$Åd§™œÈjˆÙk˜Æ¨\„‹ÊËÎÆp£–w„s“zÖ3‹e‹B+ýk ‹<÷ÂzZké„F´”P@ v{ÙÑÌŠj™øg:˜.„ åÄÀ›ž×Ù†5žÚ ?>2%RŽnÏt8(ÿó&¸´ÁÌX1ûɤõ’ùXž}zþji}ø)|³›E^µ…þh@¸ó:æ×ƒ»ÌbÒø1{ë ÑòýÏB~‚iJ&öú€ZKp~õŠ-ÀÃTIYTõBP¬ÚUïL˜&X1Þä ¤;‚žI}WªN“6Ýá=_l6ªg`‰z„G/ɇQ‚®%SÞ ÌŽ«¾• Yžª®ƒéT!& ¿ÁŸõ°,/Yì¿~RÖaq˜*"µ@Këƶ…G”ûе9‰ã¸ù û€yìÔnÝ*ð`òê˜A0`ó̧òH )Cé:’€€¿_”º”«¾P§Ê »jÞêr³– ð§W9=tÁÜ=7¬V*°Ýà$eîÌ+Í:§cß6§'C®Õj)«_)¨,è…2²}ùwÂ2S‹Ÿ8Vànoù&œï,Ö"¹‰}݆\OÉb@¹¼¶ä5ˆ^»ŽÖpîžïãŸDˆ£0ÐIlJÔË?u3g­?½U‹¤§‡àÍWYÛÎÏÖÈrâì˜g ‹h ”ð/; Üwa$8–Pw1"Ôlòô­”MbtLÔaôq¾æëž:°ÕXDX1¾Ñ±ÑàbTó¯(E“ üœ>M@¼nvYëUâCIO‡¦‰ ˜÷ÐvXA6 ¹ÜÛéÚ1‚«e"œëfYAƒœö8p´aF‰ Æ.°¥°Û…n_LU•®€°.CÍÑXþ†çxÖUðGF]½¬zãù‡‡•öÿÐÔ¾&Ï„©ºE"Â}å‚'á>µþˆ¢µ:¾˼É2g*°µØtê`š@åìù‘ØlWT‘Ø£˜ÙIŦxFõñ,¼Î%:dƒ”ŒœÌ{pvFdZ‡ëZ—oI(\‰Ÿ½fŒX9aK¤±b³PU—ž!ò’f¯¢ÍÇX÷¥3ÙÎì_³ËúšstâMk<”–ƒ²P‚«ý«:Ì2Å$4EÔ%™3wÇ`ÅñçVRï$#)Ÿ¼L3Ü'Xª×­«0@éýbFzÙ僤9òK߀pe ×ÌU­¬„¸ÚŽPÔÒO:*Õèâ䙞9'X£4> À”¾•pò*'ÒTv´*ªóvBÙ,ˆ<Œ|î »@O»¡¦ ˜nãaÚ^K–Ã!ßÿQÔ°a+}a²öË;]Û~çnZ%·H¾|Pw®“‚½ií&ïžX¨o¬ÃIüè¨í朱’s<%{Où|КÕÎ=Åc÷Æ wƒùËê-ÊÆe¬õñ‰£›P­I°þ0£f{?Ñ®Í0(d~׆Œ+¡J}]m¼–ÑÇLèF¸–ª¬‰TB%?ñüçx8›ûƒåñ ØÔaÁe àçNš`W9UGzè/¢yË@ÁT…w§-ªðÂÉKæxl § §Š&‚Y܃áÇ-0L[A 8ø¦wåË5ê7Db} ™PWª ó{¦^8Ñ7(ÀB¹© =Dr†Ì«¿e€Krþ#¹S±üÁ×ÃRóÄ&´žŒÂ}ò{$èªÂy³¥•êÿÉr¿0)Ú¸½§d)±PP–pf˜ éû\‘ÅkÔ‚;0‘Äo‹å°ÑA3ªìÃÛlçÁv‡•#‹aI_(‘a ¶Ç$Çí[sÏxš÷Ôä-„cÖiÃ$?¯v¹ »÷õ3°ÀʼǘQ'y+k‹gÌ´k–©õ5?1“§Öæbm–ôŸªëúö@h~\ÝDŒûe»âÒ¢wÀ˜VeΨ~5ÝžŽÛI…--þŸÌp.ooµ Ö¯(&g?,{'âáÚ¸:í”®ç,‰Dn°9Ç\É;Éù4ã{,Oõ¯ÕÈÓlÁÝ |¿?‡RÍm,ÚUæòßÓ&ÆX]82$]!8‰6Њ|eA¸M¡ é·ý^Y)ÆeU¬Ü[ZÙE1²³Édº¸*¡뜒»1bçb€²òÙBñ!ÿ8úOxÑòÖ‹J fÂÚ(ƒæð4“~0tì#]ˆUØØeÙ€(+’yíBZ¤¤j: J¡óXµ…8¹õæ¿ëœí22¡nwÖOvÇ¡½ðƒŠéZ…-’€€Ê±}–ÀH”ªºeh˺©ìúë~ãr 66JUEkî®ÿ<÷1xé'â1Ëy{žÓÉÃ3ôš¦ÞE2 VIm'º1¾eŠ1¦g.%§öáGn·Ö•Õ®– 5àJ è Èþ¶gö ~3ç¼F•ær‹¥t•ÁQM¬:ô±3×õ|DÜ) ܸœ[@F£Š”¾GÎûÔ|ê÷é*¤ñçåÆÑJž š·»ëþ#r?X}“ëLPÞú¢¡ hóTÛ¿3O²ßXSïø’Q;/eõ]XCOñ­4ió›È`¾sæ§V-~th¤>†?3ª£.©QX‡ˆ*% ½ º"Er&oºÄe! Zˆ.öÿknûÅ’ßkj‡nÚ ÊÀ‘ÜlÓÆÌüdÜ^²i‹Âì)“BÛBÃg£¶áFíTâù©fÅt40,ä¨Ée[êFe}#šü1ñŸ‘œböœ¬ÇöE$°Î˜ÍÀYÕi4H™ ˆßÁÀ ÔéØÍóøÏ?0;¯-®àLõ„ʼn3ŸíŠ–uy4ücAz|Ô…ósIÈ ¾ðT¹^«Uþ’ ƒQŠ <}´6Nk ¡ôdçè5#XVãlž\9Ð"£)©ãçDin4rLN[ É·^’¬'QÇîŽqÉ`ÏiUž}ÃV4ï`\‘g/|ï·jî=¤%hC®gÛ`Í—NÞ‡{BOÇÉ›ª=_aHúUq÷~u×L¡’€€¢[+GÕ/bô)Ù_ÍÏ›ûº•´`Ø:ñƒÛž¬Óßö_G2hASw{­FåëÌ·YPbóõ)ÜÉ®ªßü‘pè‹8ÖýMOÂêjtðÛ,Ìf›Ïù¸tf˜Ñ°(t‡ÔÙ±nªnÿô‘²”K5PÔ#ØrB§°Ѻ–ÀÝlE“Ð+[u¥ŸWŠi¤äJ.1Á$’âmþµU¨ÊÞfº3BÆ­µµ³ÃD…á7Ö4 EÛ?IPÏa¿LÌßœêqÂôH§µ,,Úì"°œÌœŒ¦WJ^#óÁ$ߨ™aöídPÿòÎ]$ ¢Ô£5}?´Xüö˜›¯}—?ç§0 ˇÂ9›Ä·´½m«öXceüÃn¡ƒ¯kâÂdßi¹=µ¯`WòT¬B¿ÄFÞŧãûÞŸG7ÃjîfyYÙ \QŒ (ÀPû²Ã~?²tN@5)4¬¥ò`ÏÐÛþšY¢øH”£bæ5ž`˜¥þC¨_*¤-7[€ý‰ÌÇÈf¡8ÆüzZ¾N÷Œ·¥ ­{f‰Io¡ØkIþÍr`D“ÒÁFšÆU‚é†t1'/…¹„²ô fzàâ[\ºše†®æ~¥½oAïñšáó|VSAó¨·ý"<õúîÔ“ÏÑ·­BUŦ¢¹oØëîehAÑÑP¸ÌP'í:þ–óáí}Á=9æúwÐÔ?fá,7ôÄ“[Ì®L YoÙð·˜ÛÚà÷ÍͲƒÜ|øê/|’¢öŸÖ˜ÎN;hp˜3-SÐÚqR‰;™YSzåšãÓ_/¿ÿl¦jUéô’møD»§Ýá‚àï‰ÆH/¡âÿí•ï)d•I--ŒÊ©uóÍÝ!¹”ôVl ™‹ÂKÈ«Æ äE:ÞÉpáG¹ dzaò­\µÕ—¾´ã+ÜfŸ´€º°m^Ï4" aYuÿ2^ϯ|4Ý8±dÛ.¥`['«Ñ ÞAnÕy‹HtÁx²½HH]_¡¯¦;vUN4HB–ùˆSr°Êü[K  j&ÝJPw—÷R>²g:ªI$_m¯Š™ÛF×DŽûRß;šè‰Ñ5ÿaSìI#•jk^ÌøZU½Ø;ÈP*ºJÙ«z¬@µÌÿ0A x(aì¸G‰u·<Íž55’v_S5"×!ÖoáDÄ5Ç%5¥©[¬8&aFlk_FÏhXyæ:Hˆ7pVÐþŠo¨ÛJšòë8†+^>ë©yæÆ¤ëòÖD‘áàšx½¹È_á!¥ŠÆ;D XkÇÉZ„ÓšÇc9ÅÈOÿ^ð`båi~-Ôí;P¬ÿrïo3Ðê˜UúZÜDKö»ã´ë©¿½.Øáƒ Ö$¾…~:˜ §üÝW8 4q¡rÄcR0jå—ÙÉÕ{”ñ·7 _„Ûrâˇõä!dÅw)ˆaÓGñoÍ)„ÿ©È";%à ôéVZp\l‹‰|{Іvx *“ ¾ßc•ñ8Õ·n–À¾o»Y\4ö3ÿEÌ0ó«´DµNÚ¯!Æÿ% þ…¨¤P»F˜b4§1”JgßošW¢ ÂàT%»Ø¨ßìÇ ¹îÅ­Õ…F’cæ3qtƒö¨izéÑŽdÂ{[ŒMp*$¢‹dÒ›¶³\ÁóCBòÕÖçEÿèh6€_›ü›‘ÑÊF)zDÏ ÆÊdm\gÈŸÈ!̪¬MÈ)ìŸP¶=®àw¥‹¤A&Þ¨¬EÍðäý›šI¾ƒIúüÊÏ1Ó¨ºŽêÛÓ@8ä•Ìz†äõí^™îfðFØDi –ý=*ǹ‚ýY¥p·Äu)ãkÞØ™Â¼Ö;:ó)óKœÙ¥pm2¡È-3àÌǽ‚!Ïä6ô’½|罊BËÐ"‹©jîWæ{¹‡K³Þè TeöbSÊÏ¡Ú*½‹Çõ:õN™:àNwÀeXõV.+³™«Æ˜¢‰‡5=sû{^'VŽS=çƒ4ÜÕå˔ڮ?J÷q¶oP®¤PÙÊðÁùþMÐG’cªo²‰¦7‹™ì²à\zÁDˆá¹X‘Oͧà È&5ðÍ«äëêöQoÛÒÕhÉ/ ý  &cVN—_ò—ÑÙŸCVÃ¥¬ @#‚{ÐîŠ稜áoÈ–Ê~"áS] nwU¡­_å;üáå”®Ïã‰øßœWm­ g¼ÏONfJŽD•¥-iÅZ庀•…½6ÈC×H–ñ·:s¸d“ÉÈgº?º KÑÚý¯¨¾Ð[´¨INí¥ïC;Fz.?·¾èb¤DÅ'ÖÿªˆšÅœ¢«öÌ/æYˆµ{=Çç7`’€€ž»Ñïõ8ZÇ¡šN›í+‡à•Z7lDe×õ%ÿPº|hðîÄN+ê@ÉefZ‡]¯ØûÂÇ\ă2ú.ŒM‹RáÝÔ>K2æP,楺Âp6Ñ.Ôä«’~¹cÃßúø“Ž€n»dúR!0X¨5jQÒ騶·å„þý¶'f²SŠ\7ê0Îw*3šÓ®ˆv'89Ù£–¯%Œ´5„‚­ ull½¾WŇ*G¼äÆiçBñÐÄÙ¹|³`€l¬TVºÌ£-y¤\&`Ç$vBö(`ƒÒü¼Ÿ¼´WîÑÃۺ酙Éå*㳇çÜ}ÊÃIérŸ1„ª¾Þ¡þÚ¼¯v¼€a×¾¶ˆ;: {±®±àKòë…;¿G?ªQ×VÐþµ¹’Õ9#E%à_µh“ŽΆ~ËIä±” «KÓ]'#¾’Vµ…0ns,œeŸ IÌÕ.ç[ø÷™cP`ògLÉE™‘:vHsp@óLšÈJO¬µù[VÙY§S—R†‰“+ñBÏÞ#Ò™D[bÖ­ >X¯H¬‰ªc\6s‡Î˜¼ºëG«; Ï¡Õ)¬6B}ýŸ¢ì³äBÙÛ@ó!É!Ä–¯ÿ_qp¹oƒMú“¿¯)ZÖs‡o@ÿÖ·%`/!Ö¦Á•#ºèœ§f.¥VUFÇ8÷ÙƒÕ¹ô9Õè}ã­ŸËã7«orc•s#__ôIçƒõcgù3ÿ¼-™qÏ¿O¹  j… –tܯExÚXÍg6içÛ™Îø ½e«’€€ÁšHH_[°buéx J\ÂGN+Òvhiò¥ÀgùЂë×CØÜ9šÀ¯{˜Þ6ØV[^†[«Ü;~yO.½ÒÙš—tŽñ*—5‚„¡ñ%æÝÞ6…‰£½¾R^ß1M+:!i0ÍDWø ÁÓ”¨4Ç>»€qÇø=Ñ©}hî?# î7t‰K‘8hb¡m3­¿€ßì.OG¬!Ië³°*’¯:8´š´Ýlè2JmfKn?ºA`»JâÐ3ÞÂ7S÷©r.ïÇ?·?ÑÀŸ\”DŽnÜi‰£¬Ê ¢@¤ù;vÆ¡_ˆ ´ß™—°úa}YõyØïGs?OÚåö3H®33‘Aj‡Öótü‰ÔPÔ3Õ¢þ¬aFî¸iUÆip^K},òO³‘0¤SeÃm5(ûa¥$6bë. bSï@›”“wsš?r%g¸JIûпì5åU `ë°C¢of'¿5ȃè˨™‹¿À9iÅW³ed4[µ¿ÃH"t jÊçN’ØãC|àÀœÂIØáØÈôþw6iQ×WéÀb ¹3ž™Nüpc€°Ì›‚;¯ÎOBnK ¡;¬ÎX™Ñ¦|1ix¿ÈÌJÝ ÀT]]JœÇä# ¢µôÉ›( g=Uð¶è›ç>Vé½:úê)$QÏÔA临RÞxLzâÒºýÅNêÌ ÉÄæDUÕA,:LÛ ]^ºõ‡Ý6¯xïÏ ZÕf7TpômùnRa˜ð¶"9zåYà-äˆÜè­Dˆ¤9U}¼(ªZ˜jDýü}wó˜OñÚ "h.³úu;¸Œ.£ºµïE/#Ò.—œIüqÙFuý»mãè”C#¸nÙ÷Á1‹ç—Öb››Àõìl¼yÜž›I®¾K^obÈp©³{2;TŠš³Ö%¢²ý³ôtÞ–ñ©×*$\¾¹M†1W`øÞ _˜§[.f¦VmjrªA‰:,ÚÚæ#ÚÈS÷Wg!Øf¥ ‹m·þ†«z¹wðB§ÅQÜ"¶ ÊNE£* Ëu÷2žVå;수J¶ž‹@¨ë® D)Âs!æyƒ×ºZj÷ß•ÚXa>¹ÿPçE‘s¿ûêïí^ éÓèÊu§Ï±Yq¹-Ùd(ÏÆ„²½ ¸u×]0À í[·ÉM—ëþ¯-õO):/!>«¿gLF£ó uOžò"Nš©üs|uJßd>Tzº({5qɧ²òà9¦øÎ ù°µS:Èöž‘UÓ´íi{ÎGMÙÁyfÏMærnî.{j¥H\ÙÙÏçÿm£‚>„Fí'<h÷D:·¶ˆÉ¦QÕ@°ÑNq zö¯y'íëÔâ­¬i>xª#†? ¢ÚÎ}?™h0¾4¨õsˆœ”vÔ¦™1‰¼À ×œÊ§Ç©’Üè&žyăî÷7 ¦ÐƒÏ†äv¬¬R¶ùuf«øþq^Wu3ÐÍš%Þõr.ÖmÔ& âr6{Õ¥-Ç’`¸‡9œ¸`Þu”AÕäÜë.Kt.Ö$tggÿ HzZ  Ö€løiIãõqmûØùêþìÙ‘w¶6¶ƒÒÌ2hV_ñ^Рב°RóoŠ­O"°»O¸lç";²”´ÊnÊu½sïë°ImÞ¢2%Î0ÎƧf?CC³ŒÝ¼£ šŠu±­4.E}·9>êj¢ÈÀrÖ ‹¿!ÜCÐm¡ühBsPÆÎaÕïAªÉ/ºW#Ö10W…¤= ¨5²ïýŒJ…ÙY½räÊÖARGz¨h¹Šx?بٵom‘·ëR0·Zärrɽî˜~V¨[«\ß}dH¬ÝxãKo>nI&Öü*¼öjxêkì·e b¸ÑŽîNã#6½ó91¯`ZŸymu{CÐði…ú‰ ,´øïýâéÉ‚,Ï&œ+IwPÖPó3m§KZÆBu†uÌ€¶æÊfш” ? äP¢Á¬'~4r÷g2ÎáËè‰/Ó’€€Ê¡ìQב²=Е‹çɳZ*IŒ&¼3Ý;Vå}ÕöôïÔ¸’<ßÒdŠð]l ȵÄc,/¢Ø¬ð^Õ¼6•ûZŒ•¤4u ëº6–…2,Òø!ç,—>EçÿŠÈö‰w#| pïÀŠñø¡d:*ì˜fÓ•&Äî-\¸À…·µìXž‚ Ÿ‹Žô{4~oÑT}ðúǨ°NcLì‹cnëòíWi/%¦m“4…ì–Y5(a »vùNš’þIª—•˜õMŽ#0áŸüðñ¤?Õ¥ðëb;Šnê^ÈÏ+ °ƒVÿ3¢¦F™@˜Ùj |FÇ,ñ·H(‡<5Œ\‚ñÍF$;ó1…Ì¿‚³¥s‘韺ió ÃÁ]Ì”ôà÷kksBGËW Ȱ ËÏr˵ÏNHŸmšÊ8@èdì£ ¢ÙœŠø¯|~zÄDZ¦`ƒ sÆ›Lçò¢‡õˆ‘QHGÚx¨§‡„Ë*u³w¥{D»ê¾wþz§¢~žéº@qŒ¡A’€€Ñ’Û 'MßgR†;»jX©O×g.( @ÃOöÆê,0õe$Tk%æCÒbõÛsÛ ªšàÙ²€x~M$Þ˜.Úg¦YÖ)íß4!ú·§ÃgP*Á!…_óJ¡¦ªûôî¬ìŠéˆ4ˆçË Ý<šÅ–?¶EÕbÇ=áÎn%gµ!í›Åa£Œ]ŸÌœG÷$'y³–ÃÚ@œ5±ìÝï­ƒïöLŽŠgþ»Ö,w¥®Ô`c;v?»çI”±î¥ÇÿAÕ :v¦/ô²i4tì\C˜àhÞJ\ƒf½†‘Àp,™ÅþAúâÅ¡6çý*†ÁÀ[ µ4ÍÇ„8w´J‡ïO_‰³ξÝð]2-ÂÑR,¢‡ˆ8NBv% ;kr§a Œæ`œ%Ÿ+˜$ÉROŒ´(ÚÀÇ >¦5Bæ-c›ÇÌÙŒ8X÷72Üâ0pq¶p/Phƒð|gŸ%ˆx×;³çüØL¶ '³“@ÊÓ`óFè𦻶3ÑùÖ8Na¿;æc#«¦åW$î)Ïö§½Þ¨)ñÚý…*ìSH8È´V.Ä3 ²½—ŠÛ5è–9n–‡ˆó1{2³*S*^÷Œ7ÝÖ…˜4AB-]‰Þåÿ˜Ÿ™–3`¶HiŸ*e¿me°!!ŒÏuÑÏÄÁþàÙ`&ˆ4`uN¥ú1Þ˜2ñÙ³ EÕ׈o±ä³íÍüA‘ õà(ȀȎü4­¢ )Ù ]Ä8( .€ÔÄ8yBÀ‚c•ûœ¤ÐÙœˆU€ê©”{zF^ºzˆåÊÝrÎ(Ä#….W§}LN¿^y+S¼·'¥ÁÑí oå‡2YkûÀàç­Ôw”Û˶nЇ™…ç€Þr~ŒØ‹<çìó‹È®vp+ˆk¾‰Þ²ÿ¤X%<úî$?¯¨û½º¿.ÉïGm5J~¦æ-‹‡ÂýŽlÛýÑ,P·HfØ^Ô&ä«°®ÚwN‰àÂú %É•ö…d̓î áÍh¸›ŽNÌÎí`I¸ UØ%V|s?#Ö…ÿsêj¤èåÜžj뇥,d§ÎŹ!0Þº\åsÜÛ/º+àù[æ{f2j®ö8 7Udc×c“Ý"Új|òÈêIo7@‰`ƒ&š2‡Yk¶~3ÁhÇ‘øìw~’€€ÍD/GJ7Oͨ®Ÿ†m46êÖú¿Y&ÃÝ!Kûn©˜øó0A¬nJÏ ˆt ä–­½Òcš-Ì^µ€žù*46ÿÇ&heümŸÕ†ˆdÓ'âÚ6`ÐŒÔ îÅNmÓæ•˜ó—`‡}ÝãÕ Ò öFk¡Gá©„2_·P©¬ÁéÔüWHߘ§öu`X:[KQÒgѾðZðDAÏô‰.¶ÃK3rcµªý,ˆ1Ùž±—Û eQV»y>d¶_1ü±%’ŽEêI‡â"× 9ËÔÍRÜ)k]o¥mYw}€@KC?Uy~»R¥D´ C¥T$XÔk“ `Ñc½¼}Óæ—Õp÷<-tC¤1É5éE•ßmZm,U²[iìŒwËÔšŠ+B«ç5›ÒeF¾9Áߨ& # Ö–h@‹¨šŒ 1ß¹ù vï°ž×S NPßìÀ•%Þ]‘]Àço!NcÏ|ÂK r‹/U÷l¡màÇž¨Ph.BĹõÒô>ÒçîKÃ{) µ™E¡yH¸èˆ^jÝE_/,Í‘ìƒ<Øq<(àÂØèª7ñq¦Išèöé~0§oÃ2aL2­vB“¤y'5‰ÒË% [{ðU,X.™3sfÌ‚’“¸õ.˜aš®P 7³[±…ÀJ$‡Ý®®X*H„L;4ä&³€K6Káúïàr¼-¦|´½1SŒ×™Þ:$§ðëlbÜš'û( ¢TgЩᑵé±`½¢º¬¤n[rø(ZðëÁ‹¸5¨Ê¶7yvGì”YÑŒÓ;Pèsžs£?c¨ `$Õ{ÓG#Ù²ÁyO’èöPR¡J½£%/§%b”½ÍOXæbH““K…mR¶ŒÏÃyŠxJpÎ(åýE¤Š„#ñ=(ó”5÷ƒ‚ 5¸D[ ˆ3v¼zÊ{–o„ÍO\'Ø×‰ƒíMèeiÁd}¬‘q™u(T[€ë©Yçr$ÚØîòzh–£|OK?pûœº×ú\¬Áœm–„Mqñ~bÙú8Æü4ÇÙå|ÈôÀ<µNÙݪö޳Ù”,÷ q'Æi ÐÍ’€€ÑSËø”ešÂ·¬«žs¼ð‰ùM%ý•7îÊö•‚õ  w·“¥ö¸2®š& #³ýxÖ;_‚åÈQüEËØà¿À³°ð¼+¶ëkÍŸ‹°¢“Ö0·×ú’ý…Ò¿ë²DéHÁïÉ«8ÕˆÆJÐe–ñ?ô%ÿq!B˜·“²#”1M3Bbô—ÂQÝ4ÐÊÅV’±ñ¯ý2Wø±QÁº› Z¯ŽÚ8LÊ)€%º²>,žƒÿ¶BN¹«ŽØø›ÍI‡bº C'7È|N°÷ñld£½³–¶1‹n_cpqÏžïBÿÇØŽ"‰›"î˜dÚ÷S,=Îð«ŸëÂ_yÖ÷Z–û,°@.‹)é—ƒ'×®ÞÉòHJ¼“±­_`0ÊUëÆÆWJ†¨•á¤þ=À ¬ŸDc© î*@É>5ž#c©i´Oq(ÄÖIW,ï߆c°±v•áYÙùÝgôVM¡—k–ÈX7ÝóØùnLT‹•h~iGy¨Â«¦ŸG³ªÈRO׋líôP•°tƒ|}vÖ᫳}i’RÚŽ0Äc,I€[¤66%çÇP¬º‚™Iº­´Ù†ÆhoV³¡í ²X\o9M·+Q’Á¦¿oèæ” ‰ePz¶'g`œøŠv¬@Ç ìupi5'½yÂl¡øüˆ«Î˜ Šê‚ÄË 9âD56MÁèjd,dÑB6ü‡š÷ÌAOÆ2½>.^鬿´M5xçW!)üu‡×üYF¯Î0Å·P–ÜjœY»PmKý ¹=ÜŸÔ3Òè@¬ÛÒtïªK¦ÏŸû)Ø < cfnÉÌéý]×u}–,š(Ôd³}•iÙ„óOiTBLLJÓX@E…«©[¢|úCcKÁt®~IøCÄ´jà¦ÆvÖž_®á>^&}ãF*Ýšíeu‹lÕßü„£YÁËi>aâÒ´ãP„ˆOmŽ/VÔ0ºÏÒ@w\Í?«* h·sÅ£m(=ilñŠÒ±¬e3hpeìT{Éõ†DüšüàSëæ¯íy -žC3†“Ó}YµÅ&¤{þ¨AàL~I[ž†]êÕ«‹ÂÿÓ^®ÏWaÇD&>|àÎäAR‰?]ïÁ7O¬Š"§>u5¢Ó­hGj§nGßýÆZ„yíY8:Õ• $깓yˆ%€x=c±qI!þu¹°ìgNgÐH·ãNîÖGÅÅ,§9ø+R9à¼4µ3ÓH—¦°XË'bMÐù}™ØÑ@ƒ÷y#¦êÝÌ1$—vkT¤aÝbŸ„úå”8\ªY` €ç†"¬0]Ñò ‰ ¹{ο\a/‘D¬Ÿ/ÅÀ'éí=ìSsbưxúi»B?:Pd±&u|›fsZ޶BÌŸ±ÜÑ;XØž‡=ô,}¡cÚ&±É_ÏYÐw'Ÿîë׫7ha̱3Xr(u¼ì_¶i½$Pü´ì&që©E#èË6—ƒ×§ Mö~²\^ÇÑ“›á3ylÁA%!3-–Œúãe7ú¥?™2;*h¦ò³ ÕÎþÇãÍlcè(Úß,!ñêÛOëE“A=TÌ]Ò† #×¾i&ßQ=°p4÷= 囿¿¹ TA±á÷Í _tø{]¾Mö©Õ‘è³Û!æ¶k? ¬7pŒ}šLÿq,kO÷³§ š]g±[7 µ LÃ/Êiì- ± Sê ®Å7á9—É©‰G?ÝÇE²ðtMòÞôÿ6XOM£Ó†,UäêÈåGÖÊêíÝ/‘´Û®}íàÚÿ‰ŠÃÒˆ»æ²+(h‡*çȌqâ†ò&3"…Ãb†©çà³FßÕÍ“Ó0@üß¡f*ç sŸyÍOx·kl…’žú‘%çž÷Ç|‡ÞIÄ´*[^î'qaÝv$llÔØ;ï•acÑ¢*ï(º°ÖRÑ*õ$“ÔyâMºqš­æ@TôÆãühöß›òŒÔ˜X†@¿¸¯WzÐmÌd9ǘì«Ù–0¦îµÝ[žÍO7ù…Ð:Õ_ÐVzJôª’D¦í|sšU“TV/:¿àæ©[ˆ{f”—yÛU83U v`Œô‰¡”¨%[¥ÀÉXm—N)ª3<öN4Ì$M%7× êjT‘+E£ fpÒ99(v×e·©Q@ãbœžìœ^da²5Þd±‡jñ­·¿1Ê[__¶]ÒÔ¸pG' ÐÌò™VƒéÎ!19ÿwSÎ)ø¨Ë=ð¸þ~0»÷»w;”’2bü±nè”E³O‚d𙹙)®ïä3vÇûÌ€z<Õ¹š_w+ÖI¢Z"0# n-‡­’€€Ã%±•Æð¤K<Ÿçü``-à8ä‚pÆÜjñïy# O dáw¸>­!¦`OžÛ5AIPxé+P'‚<—ðØÚs#Öö‚?ÞäýAÕ!BÄg֌˜-ÑÝâ0_1˜j™jéV '$ãý¢CÑÕmrÏšn.׬E'öòXKg9 rÞýúS¤h;Q¬Å‹ß|}åè…´!Ý}¼•S­å™»ÂAdbHìÊx&ü !s?¨ÏãyçȆÃ0g2‘ö lÈÒÿ#·uRV—lù/ãÓ®A8¿“¦° éQ°œýàV)Ài]ò!>¶öƒðkÂ*Ýèu‚Ôú‡éHP‘°êïã×TUh);Ñ8ü±1ØU?yÚZ¯pýÊ'BaU2³"ì¯Ã ORjZL|Î1‹x;!€N-é´”Ù™¦ªØ¦^òx¯ï­¦¯EA”¬SÚ½ÊÑË׎Òs®ßÇá‹k™ÇÇ´±>t´4؈kwíSMDK§{-ia²”5¾•MþÉ–ã%ö†5ãp¢ô§u|U´¼jN>Ñ@vkD“h;ƒ‡¯<_…­ïþù• Õ-¶õ…]ø’Û ‰OÈ=æ-8Lçc áU.Á¶½1ëëa7FŸgw6¶µ‘ÉßL¿â,7€‡ÙÔÓ=vÓ1x,îåÆ/÷ÞÎÝ•¹ó|I{1ëél@tÃ$GF/#†å-™»µ8óYó†òVòЍ-Jeµ€õ­çѤZ%E1,_À†'>¦”€ü<w*šÁé Ù­^üÇS6•zé—…ö÷ö;›êŽ¥†å³ù»@PRhÔÿ!¦Æ=k@þ¶Â™õ•ç*žnÿÂӄ܉Ô7,azÒmé,¬²E;9ÒIÿØþÙ†ìY{¼Ž;C»$‚ùÄQ긼PÁþA¿€˜ÅäØkä-ßWE{;Ù-mfy—"wøÉ{4ÙïKžºWl.&ÔÒ¤ˆŒæeoJ´z Ç7ç©ZV,< ‘¯±LÄFª^è}Ý¡Ééô>Yâ´çÀ^4ÂX]6xPò`˜Ê(ú{@0hn ¹ëgŽ Í9áÃbqÊ:ù¨]ÏÝ@}†DÁBø7Ýü±†eVåQ0FVäl_ FöZ¯íÚpC‘î¦üGº?ó²Šø8`³ïSN½£pº™‰ר*b)Z!aå"ú’€€ðåc•LnësMÔ,Y‡xñ %7Á—š&¶ÍÊp¤ë¿´Ñ¬…y½f£QŽÜþˆ“‹R_C˜ÆIܤÄüÇE2ùÒ³Æg8‡^§%^ú½rZ†TÒúÑFQÐÑz+ÊP êÑ+þ ÔØ”¦.úEMGf¶Û±G&ùvø]œX޲ÐNœÚ´\Wßd U£äWDJ®˜šh¸éÁ!`Øs“À•Ë:ñ^ð!+¼áüIáÕÿŸ{X ÞØí|®Ë>ŒhKƒ ¬ɋۜچüü Ú6ô¾·ðô¢ãü¨Þÿþ¯OÌNX‘–ÖŠÅ2’ ÇŽU,ýŽ£N$ºWm­®M}¢ÄÛcãí`u-ÆUâ@Rçw¦æ°ƒØÁ,Y)Ê&ÄqÖXCÈlzYcê‰ÐˆÃóÅ  ‘í=³Â²ß¡º–^Ò;ê|ìc‘Û⯆¬ê›t’gx‘4þÊ?? =~Áqw(zZØümÈŸø°(@}É/Þ7âýпs²×YL»$ƈý}ØÛ¼)b¼ˆîDâ¡jÉR¢/š+Κ¼øßÀ†½;+&N«¿á5xˆkM€G>M@”8Õ¨ÏzóuµFÊ¿å¥Û7.ô„³·´mŒ[øŒN½%‘¡ » ›Ë¡ÿZ›ó ÙÁûÊWùé­ ¸íR÷–³ÔGºšàŽ*ñC¦Y’CÌmºc&¼èêšj5CÔ²õÓÙ:±¯ýïšÆGᇼ¸’€€œ„[DD]ól]䜹»‹!€ÃÞ Qºf\µ «+ÓÜ4ä³ã¾0Ií¯4ŠrµtÔ·ËI/‘+3ás¿Ê¦Çï°×p™+¨bW¤ð«43ºh JÇoÀ¸ ižØìUWèuVx κ®çR2Œõa:|SR~ ÙŠp­ÄäS~ÁqîC›@6W«X–(£X çrÀ½Š4÷ñš7í&¼üXïZÅ^þéÕÏLŒðëþÚü+ûÅ£…ØÔ‹¨Î¶zÊÔÇwäWÛiA}xÕžø¯,¡ !«€¨Èl¶jg2´[‚çÙFè®[U,Å™å×»%ƒL·ð|&X¢;kÇîY',<åëySuJ°ù0gSkEeͬ}íë‚àhß<3 y<%*ϼª‡N ígß”éÙŽ3*_$‡vŽI!`fø¿/GàÀ­oí—¸:£«±ñ§¥-©ô,ÜOA”Å¿¬º?rMû–¶çþØõ2Cù¿¬¾?Hö§G/ƒ©t¿w–ô&SHzÒ¬™ÈZH‡ªx=$­)!”æôºPbDßöܘµøÒण8çœ^ÙgÓGhxËÈðYÕòVÐü|YaÓÜ09‡s2µtî¬ZmSÊ9êÒ^[òÑMÀ‹ek/Ö[ db¢7IÉ=säâ‘/~ó_ëž ›²:†·bÉ,^¡æÀu±|)ÆkL¬‚9­,dèÑ’'@eȦ”1%ÄUò`Òrz±N¢û"4Bpßd¸¾Ò Z±VÞèW}W­˜³Z 4Ÿ$æÃS~Ýž²#õ8fÑ9êf.]‚£µ1ýǸ/Ð5ÚãÎnDºÇT±E+¦ÙÂjœµðú¡Zg(‡Õulj²žžë„dF,¤R5«£²ÆŽ‰˜ù°fMžxkI|@æ¬ð×ûW¯\‹î²ÙZ£Ï€0ÍX“ÜW*{ðŠ×^ 8ñýàmZícð´‚ýíŽÁôãÎJpKE tJ’§Ë5R ·ÍRòÝd :=\çn-?!l‡Ðì)í$O$5µ^ÞûŒÖÙ¢~¥0í’€€÷ûøx¥#»þж&qi•Zo˜^çD.üÉ€‡ÖÀ×:AC¬ä¢÷þ+·@P/ŽäÚ¹û\íc"÷*ciÃÜ9:¯gž·óúÔßögLl½;Ú}õÐ1dK½3ö,#Z.Z?ÃNS½2±D4ZŒ˜3„ªÊhs(F'@WˆžºaÙ¦­|u11‰}$ •Éuv¨yYùUx0ó!‚\ïT'ãlÇ\쥇°ôê ™©XRPa;.‚2Sâ 8.-…²<1VØTHH˹ž$Ódwåwß3ÿ±F¯d^kàzÜm–¾Æ?«¦ÀΨÂô0KбüTÛ8$cÈ‘ôD_ŠýnÞ?Å„'ä˜jZÁç7Íp¦1á—÷ˆ•gfÆêµÛV™¢Úf‹é¾_†~l”5.]«§Î|™ŽYHÓ$f@NJm‘7¹¥ü²uÆ4òajsê¯SxxµÝ#!ég†RMÀ‚2E©°TP9„thµÆ¹P"ô˜ý€…Á»”õo-Ü<ëG}:¾Œx4¶¼™(ü:ȣʚœ>’€€«þ¬˜Hípä÷D¯&sÝyœnýU–Aæ.ÇFhXEÄ@8u6USŠ$û…‘a!^~»ìð†RDÒN&k§þ9æo<ŠkwŸÏ\öõ5o¨>¸§y`¿’[XÛ0Á¢ï1¬¡‚âTÇ'Q›ÖMMK¸º`°ƒõ¦®Í­m©‰’V#¯¼­¥iLíÔ}%è²3‰ osà0¤“¨Ëô0QÅnb£GA#H´h¡ŽÐ“J˜Ží›*Ãĺ¿è‘',Å–—4ʇbDÉwœ…0ªÓA™éÔä:8ôx­#;ÌX™×¢fQѺñ;¾¦ßÉÓå­d Ÿ¡²¦“§Ëm¼ ½†!’†WJ0ÍŸwYX%GÆ CFZo]Ås]H’GÝîå$/U¦YÊÃ1 ±mÿÚ+Dÿ ¤r‡FŠsÜ¡áâq®3×ÿÑ,ì"Ƕfï!br4@r>M½ "ÜÛ«Áðs§j'ÊëU++s×+Ž_a¶“ßúªÏ¦Ò|Â7†ž¦”Ì?¶€˜nÙuò‹:8Å´ÃümX2‹‘‘H(c •#2sƒ$?MÜ Íˆ&š=|ðsƒòt™rœùîwy‘€A‰.¹S˜ºFÁ74Ð8û¹é}axßšaZ|P}kCñÉÎ2X½*i,´Zší‰‹å•´WNñ§“ÞL ãé;R¶ÔN[[–c ¡Ðà€ Á±/Á–ã ûM­G¨˜W)R"]âl¼ü(g¢Pá°¤cm_®§ÿÀßf F±0Å›šôPÓz!¤Bï˜!³þÖFæ&sìK@åË¡À\‰CrYýäbÌ?*4a™tø*¢³˜âeÕ×`½ÕíÍFÈt/7T,¦‰sÈ)$ÉN訕ˆp&ìeEãwp9kç´5ø/6°<ŸæÄ']+BÖV£ß5DtÛÕæ´fgò×¹CûÛz‘3œ%Ù²úáÁƒU§M0ŒòÐH®³k7¢s83‰¤E4Ñ’W(¢TvU…þ®â¬6³ÞMVñr‚9¤¤a1ì¦äðFéÄ‚âãÜr÷ë{¢‚ùJ¢ÕíŽÓ5>?WÍÅPÇè2½ $:AšeÁS_8Du°0`k —~Š>u}4÷Í ë/2Ç…;‚®—FàåÅ'SõzÖ¤#‚x)’€€®‡¾.ÇœùµŒõ¦/˜PœÄo6‹\´P» «$i0ö€ÔÓa/Â4"ÑÖá)ÐóqÙmy5¿˜pk ‰¿Uä¶÷1ÈåÌ[\­ÔT>h´_ëãæUËP÷àù“FÒ×à‚×Ï~ïÁ$"æÒÄÆŠrúàKòîGDlWZgWeCÓìÇæAÈ[^_’îHmŸ¿' ‡ÁA‰yñg­Ä 𿪑¼ÍÉÙp8Fh Q|‹ ôK­tõe$6ò…˜òÍW„µ ”ÃòaYÞ A×E¼-v*¸`5.jWÄPFç{kuá™:ùS ¼g 4VÇ]Ëšè 3¡éíÇIŽòìYìXÊsÿµHÅ·Å-§7ʦ›±HMüT‹&%ñ—wÌm Yî÷€kî z7Ó-y‡¼¸(4˜•4Ìt êU²6}W£ú¡•ï‰Ù.³ø–—ºÒŸwæýX*…€µù›à›ô1IÌr‚±’ÃçPb¥»€9bNÄk0(ž$¦)>"ë²Þæ¶ ørµgª¡¿àÑ ¬Þ§ÎLÁþFü²ZžXr9OàXµZ÷¸¬ñÝ!Jfi{þ$j0ÛmEÎÑ/z2e8}%{Êõ/Hø?ú.ùö¯ÅÃ$ò%àç”Õp—^n·3…”‡AÇñ‘mà¹yd;I†VèQýèátÛî\Ô-æ½r¬**µ–Š䦠é«.gß!¥_i³Ý:]V‹jCý®KlSÊ H¯Å`´J›‚AJ²ÔÙL Å÷ ü¥í„®“¼n¾¢ÞÓÅ„¤¢7sÊrý‘î1Ò}:za>»Ä„½£ˆBáðiÕC/~Õ½ÇÁŠÕÙäñö}7×Zó›'••âÍÇbz3zÞßyj³ÅÛ_…_¼?9}IÐ0¹  ÆÙ¥U³š—f‰Ê1Ofu7Ńö¡ó¤r&¸S;z꨿­/Âÿf,,­c(À>…Ìäýº‡›Pl¤”¸·õÔªÑ2ˆ\ë¡»‡€ÆÎDËöHÜ´Ѐc´0£ŒïíV„§Ô>Æ•1IAÍ;Å ü‹ƒÖžÙ´­ ö%Ÿ Ž…’€€Ã‹ì(øÙõ‰<µÊš±ŠÎ ±Øðß±ÞôvE•FŽ˜+ø'ÛÄQ#~P¥cˆ:v ‰EË‘kuûP²™Luûè‚–†¨tרo·z^Ì™ºƒk$‹côØŠ¸KûR¸þ¢Ü®íûdG–vïª<Åó¢ß·RNM.¦Ãï'ÕPÛ7ϨÂ*\úŠê‚Tƺít™·»Ô0VpŸ!^–Ærú[Š3'äNØ-5`oT"Ì3kÿÿÊ@•CÑ®Bàžá˜|,;¢f0¶ œœ^L”R FYx¢0 £–°7ZÇÕºŒ<Å̃Ôn¨X}v;ûŽ*jFé’¼ +«Ñì|Œ«A½-0²HÁ|¹Ãž°|õ°ûgL6õRrÃ@{¼0Gu§é{ÕÍØ2Ë>¸8Î…Ãw±§:ÓɹhèŠZÜ¢1ú«§vñÊÚÆã9ûú!Ì„ü,ùu+¯éÛG€X¤‘ïþéê¹&(·Çÿå·Ð+¾ÐaÌëѵ^5“Ýì J|qIu+z<ãî®8¾õ­ÿO'É5U,26†[Y¢«…#Áâ>å¢<—†D´€Œ¡–ryOjlAgÐß¹¼<Á²—ÁËï\4–g²Ð.VŒ&ò±äé 8Açó¶D®H©_"ÿAÞ© wüçŠS>[;™|Œˆ¤+ò@Új£”¿áøS[M›aå‘ßN•z_`6éC:õãÞ~ÆÎ: (åRŸ\B9ï_ P)¿¥o3ˆéÅ&Ö° m~v´ÄŽI7°sF›–¢c ¹žzyµ /"µnä2È#¾ßrÕŠÚ:ÊA®€ ,jŽ`Ðs©¸‘kÿž ózºÁ~±’€€Ï—Ê ÈMñ’Ïbž b˽ÅÞûB‰,| Órw‹G>¦h²5 ·Ãà—]'з¢×ÚÆ]}\Ú¡¸x%ë¦e/Žþ"Xò‚4”º'ÔÇ~A6UCa, RE?39FÀñXê-mÿb2ã×—½~.šÞû`oxy>àGÝJáT aeŽ ÁÃÙ¥CËŸÂLΞ؃ÊçÏí›!<•]¨{ª¡j£ðÁˆ_ #^³°Ïé`%T'_›zöиÄþÊŒ„GÉÕ´º ‚¿}û'öYÐEhºb8Ð&‡#Œ×güÎÉj™ÑûõP2‚º§rŒÌGÞÍáîÕ°>ýNâÆ"!õ³K>ë,m/9ðÎIq¾V«h{ϨåÀ’Ú¼ñúJ3B~I 攀¿Å>O‡ìO°í(Æ,ȪöÙLTkQåÒÆš€çCŠi”ù½ª¦Ó h˜Ãf9ùz_Žã¼“‘LÌ"Ф1ê,»Fq`«ÖOúvY–wùÇ–s{¦f+Î.]BYhkG#KRµÕß¹4›T•¬©mÜJ5Ôƒ+δæn÷ôg[Hº­Ðæ¿€QïöRÝ,.é™Ô!¯¯ÛÉ“b&7¤ 7¡°¿®Ôã±K)÷rcWŒê•Õ)Më P%O±úÓnö—2ú ñóÛ09üÍ&Nåë;å2•]h˜œÇƒW]êÁÕˆeÙ–s½¨‡¸` Y(ú†y7d#ÇÈ}b‹*édqÐfg픚Ëß‚ãXp–"X·TÿÆM!XõøHnŒ#)ãöÓЬæÊãÐ!i‘Z:k¡#¢'ôˆõéøzy0¹q®ç¡ïMÒ84e™Æ¼¾²°`J·}AS„Cv†«ÀSï\=–Ü:÷põ¥`[Áӹʀ0bT­‚étjÏTÉØC=Q1È7G׉%/ 2F±ËÅ/Œ£”ê!$‡B$vùÌbq«ªóSŒ"í–o–;j4O¯t›Ñ¦D¶t$økø;L³õ%&õAÒÁlŠÃ»#S\—MK„`_½£8À¬•bï&Á¶u-ô¤JC=£«¼Ñ¦\;2+´;l¢f®o«4í[#myãÌŽÅìIÿŸTY˜É21H´}ûï…ïÿÏØ(~ð4¨ü&L"3ì£^©ˆDEºÖt›<’€€ÂöÔ h>üüãÛPÌ:¤íÀÂ]PãG=S ¡É} B¢Ìñ¦wôKq©–W; öÄ3s‹ÿIÂDÓ .92ÅÆB¥Öõî YÍ„ÄøNú’É;@¢ùUQ_Þ†Äñÿ¼—Ù~mt±awC±hüÝÓq4‘€¶´VHhŽv]uïN\×;Rê+ùù¤"¾Qœ(mÊ ¨…¸ì_p+‡yª;¼­Ý1(âgÖ1ñÒ •âV cBB}A–‰ÿÁÑV|¬ÄúG¶,Ò"%=Vžv¾гFû|m'0¬ûR;*Û'ăxhÚZ|\ɼ‡Á ±U+*÷8;”ÍåP:¿ºÀtõ þáì†~´¨];Ï£^é¡nÂ䦌ÎXÐjc(èm¼5˜®WX‘MñU»gh*¶@ÒJ“c5·!m±eˆFC£ú—fÛÅ„´×ÅŸtšHL^gן` 4e‹„€ ¶üUœý&þK¹ÃuÛëÂùOµZO°šf"©!c0x¬¯$'³˜ª Ì@r%2·¨^K†t- ÉÙ¹½5Õ!ð€L¥˜ÂÞ{)ó)9P¦F÷YkióDN ȨØÈd*;Î jÎv'+#™E~2Ö Ô é¢  ß,­jƒAêÝä 'åmxÍ«ÀM,C§ Û;&€ì%9T3ArŠŠO´´¾ûü!wä&· S…3j©_:È÷NžËW#³9¼nÊóW“G]מŠW”~B"sáÊL~}JOlxºO~ ¶¾wÀ•1¸ ñ}Žr¨×jwDˆrQLÍý2ÈÕ›Ú_Ë^'·Ú@nA@”µq¸&ò¼"fÕcSß3U2îYÈ»ö¦z_ÂvOЯÀ<€jt»vôN<‚¬\57eVQÍ&ý&Œ ÉØ§Šø!`YVÖVîE¤¨?è€ùÁmté£FÏhØVù@íñLÐeý¸ˆEBx×ÖÄ•ýºµpŒ€,Íi.º°$MSÒ³“ åOs|Nú]7õ $1G)&â˜f êÏSºý/M"þxWˆ[U³¿o<]Oq„£¸b;)±¤P­iHYq¨Y·¿mZÜ¿léUÑ>!}!M["¾ 3ÊMS–oð.x ÆúæóLbçÌp³×‘£›7rv’€€ôÝÜšBM8ö0]’—9EÛ7m<î”ÐÐG.c2^_QA½úXÁïÊŸ/ÀÂv2}3MŸˆ`­S@0úå¶ Š]Ðv»Š‘#Ì¥ëäœIpæGJJy˜)H¤p=uO†Õ4@%‚%¯.³ €~‚•U ûqkôfHœº–(ô‡7iImÅTÄ6åvĽ âÄ—;—*ï ƒºSË»Þ^AYP5TÇÀlÅxuÆZKÉã^’@Ðb/øQQ‹ ãHÝ-c]9¢ô YÏ_6Ý´C__º¥ÚÐcÁR”‹þjSÞãçLù´ÕýgiÆ»èðÖǵςPËiÌ‹³ªÁaÈÞ£¿)evszÿ…… H+Þ*‡l‹rytÖN äøëëŽþøgà!\Û§Xé$ 3÷z7p ÒkÛaûÉ”¡SldÜ_æ÷ÜõqqŽ'`raOµíhäq«.¢»ÛðpÖi»„+û´ »6ÇjHu˜!ÜÁK;tÈŸ.R>3&°…32¶ÜÔRKõ¸«°ÈT*ñиt‡C¥ðÔŒã¥(ŽI“ôPö“+it©»c°WÚÜ¢ëÔêN«v×,þ‰¿ÏÏò¶@Ldyûü¸ó¼ýIúO"[Îs«»*ÿ04uè×ø |'Ôj% >Í'Ö^Lƒ™ÒAä&!b”0öfpêóGðo$s¸<kSCPŠ@ÔKèµ$F^—Œx<Ë ûËçÅÞ×ÄÐKt¸ƒ¦ä‘Vïá1Ë[UXÕ 4mûhª*{ÀöøÄbo`úzÇΙ5 ÿçV*"í¯¬vuÇÚ Äjƒ­_{IcŒ¸}OeouSÀ,¸ÑÖžµ$ñhÆä5ëýSåt³÷²jÉŒà?Vì¶u'ÆC†È¤aÄÖÙ³4Bxçš¿²æÄ#`^˜›Ø6¯ Q Üã ü¼ø]}§¯âr¤xÂÛ¤mÌÊNÌù°‡K0EQcd`5Ø<’€€ÔlþØ'¹ìÑÞX€7\ôƒ*xáÊåTÀãrwwÂÞ¿ ¡1éÏåÑïö9¡Q ¤öãÀwpÎ2M·Ä×v¢¾/5w>“qrRÎÔ{õÂ”Š•èKázQ©\eÆ—Ä>Aˆ¡¨ÊèÏ'â4²—U;×°£yÖÌczB¡µw4žs\CÔ<¶‡˜ãàæõ·üyâ7r¾¨ÖÁÐù²÷#À&-t5x¾^žSbåÞË9>V‹Ì±Ì`ØËû=¯°ž>Óˆ“N”%mÒ|~Ÿ¤_‚;FA°"Dœ½¦"Û¹öiäÄý5"~Û 3å“çÔ¤J·±‘ŠâESör{@!²ô6žàhÔú\®f;áMÆz|úÏ%U*‡G«ë³òBšJs!ÕV4¾É€¡L‡TùG öC…Ê3·Ô‰ÚÄUÞ×ÚàqCÛ/#AK¾‚ª^V6@„ÒÿÂßäâ(¦Ó}ŸŸsç!òåÄsÍ]ɈáÖä}³qŽI—zð©×=/ÝùÇNókÔ¤ttWªV‚7ŠÅ×ÑZé™(9Ê3]¹Îce+“‰}T8²÷ú:Ý)÷ð‚Ò\Ë`„2°=¬øA„NfÀYôòSÀ‡NÑÚ+i÷¡-òdí¤E:_RÜöÚû6à˜‚qǼ ¤M´ïõA“`bøs¹Ë'|… 3$£æWéðãX¯Ã‹:¬nëXÍ}t…“xÀȶÒÓ²G±“¶œò¨0âÀÎÚ줥‰„©ÛTìå–Môk]¥s®~ÓÍhc,°TÈ­·#Š’52³w&áˆs&;Ù`¦3´ Í;¾ÇZÓù™¦›„ó“š7–NT÷Ãçòn88F+ë®É=øVEˆBõR?²2f=ƒæçYÏÚ1<6J PÁ Ó×Ò'e ^ ËÃó7²¨©ÃWiWŽQÜ‘;µâðªJêbèT€\Ü ¨z§uW(Yï¦BóÛ Îþ˼T“–©UXB_k*9Xâîø—®iÞp‚žf¸z3Cžð‰×¹ª¿˜4%º UûX”½Á£ª¨ÄVÓ¼+­š™Z¯—Ìï¡'³÷ì2$÷k³DïÓ×>¸Î’€€ÁçýŸÇlU0†§ŒÏøJ¥'”šŒ/ë`ëc‹1üdðé>Z h‡fÉÅ£ówØ}–Y*™{šÞGø¶èËŪa qù Ä4ÆÛÕk¥hXÕÚú¸ÇÅŸé§Ë@ €nÓW¨×£Óm3¤Ôò¼"ræéHO{Å”å[H(u~ FùÄ 0ÁƒŽžêseØI'¦ef >›—ÂŽ¤Þº\Q4¯îç‘2LÕ9FœeNGšª¯ü©Taòæž s¬MQx "¿áÚw°B¡ŽüÇ8úÚ]ÈkBÅhËk€R úùߦ»_æsXËRÁ±– C [:¨aóä{ÂÖEo2j3¤&È “å5ÆÌj†p™ó4(¯}d»2¯îÌ[Î`æmc¬ÍGcÂ5°?w¦¥( 8Þ^_·J·ÓGPêõã© ¥5xlª[f#u»‹KÚI³ý?¤‹ü†%U![ñv8¢ý¹ÍNﺑÉç$>BÄ2‚äÅ”°<¢XØø}P 'r6pF>¯¼Þ^CeÐíõÅù˜â&˜_ZÛÎÙhTHÓ×—ð„L(gâÁ÷äèÝ.<)”/ö#† s„ÍEYs7›Êðf”+ž.BÚâ:ks´/oÊe1p¥‡Eý_#µ”+l_â…,nÒÔ[1ÃèråamcW¡û+„<È›¤ÿ›eµ$tö‰µ3ù3£€²2Q¥ÚÈ·™iNܼêÁ˜ìzé=ÌB²PI4Ë aÏDíÜàySFîÑ vÏR Ê(@¥µ*\³"¡Aa•¡4üŒJÀ¦ éÁ‡ÅŸô-ÍEª®=¥æ‡šíŽÕfN®È ÇÖj¢_uŽN-“yA¼~±:â» 9®ÉЃ÷w[m•ž›Ó4>™ë¾G}ÞîgWú&9š­º¾I8½;‚Zl§4í-M}¹žçi2ÒmE ¹¹˜!ÑHߊ¥dÙX+Æm‘rÂY¾TŽô×%hêØvô›‘ºX"˜-z,ä‚ y›k¸“Rø¢Po™k3í]XÀ_,T (ÒJÎ~UE¤èAóQ {Z±ù°ïoÌâÝ‘K_ÔÆ<§ƒ]½'- ^zðWtÅlþµþyú.Åïø ’€€þîvP„ºfV„£ÉïŽVËRíå,Ž0ä]ßsªh€q!?™]ÍäÃ?Õ,£¢¿òø™3ŽV?ý[xχa`ˆ ÁÄRòÇ®/_äßs@ü·‹©§U‹ îaÕ˧* ¿ã Ï:Vòç8½¦¯3ÚÝŠ‹µîàÂé~>œÞ8áÁ9F{òŤG¶¶óüüáCí‚uö=ü29{1—0¬·î‹¸µ£†”€™Ðb BÈØ©B ÛžZNÃ&2êÉÅrÃú8¾jøCï [ÿ™6éjlGûxÄíиûˆõ:Ÿ2Á &9Ý'—ô{3 lg°_T77f…( ˆ"»ûÁ>>èæn÷4†£ú¨s °pip\nã¿Ïóc¯á·‚ ÏÞZäyvÆ ò–í(ì D¦5¬l p®¹Ý1M^W¹ÑÓ6aõ’cS'+r:|õ1Yé©ÞjPpü—â¿÷¼c¨ÂWðZ4~ràð7XÖoú½HvÒîM¿bd‰gº©tÉ.QßgóD]8"7-Â÷Ûyþ z›‘÷VÑ¿º"Ï2;nÇM˜VÞºÐ?Ј\(k5Æ'F¿šÚr8Ï3ø»œü]iÍLœû(:˜üajˆŠ$㪙ƒÅšµ“×#Þ8}ƒ|-UnÀdf˜•€^Ò`òŠÁ)BçL ÛÇÃàÛí=Ïû#®×µ¯EëHÖ‡CJøÜwˆs üþøâl¢Ú–ëHdã©F|¼4æsWf²ï #‹«ùÃ@BXøë^m/'îŸç ngôóy–¿8’‘سeé'Ô?7Ê‹C`’ù=ô:bÞUw‡—¤„ûG¤Èë2$Erõ“bª×yo;^T_õäo…6e¹$ÉG °k¶ªžÃŸ¸…Câmà ã6.›ß›\ƒ¼Üâ–ãO1qxÒi >Þµ}ÛådCŽÂAc¶\£ù¡×vœ“/<ê㌜wëá² ÙÒ¶¶óRê(óüIxù£|oï討lª÷j‡4Ik)ð3K¾÷.è.ø¹‡™‚ºÐJ9Ì·Vpß·?(,ló¡ÃVjuãzÞÚLq™y+4¼ï0Ân®Îê¯îûœ(ÇÅø›ÿ±–ín†å²^‰*ETÍçþQõNÆÌ¥çæþˆÝúŠøF¡ð†H‘çWÐùäZzÐvƒÌk•py²«‰}Sü€ÐpÐõpÕœªj…h îM—Ò>Ƥ.õâS“ޝÔÙSÚAÞ¶qñËØV;¯Û–Ï%’…-ÁºU3UŸ„׎u:6Êú?ÞÀ£ÙKšÿ—¿¡’¨r?}ú§¯)ªs¼ÇÌ3c°§g$´È ÄÞRwã;š´h§Èjm¶×Nsæœ&#þ¹Hå¥uÏì¶³¹vÅݘ±#JCö{QVÂÔ‘òþú³{@u}À©(¬2‹«½’€€ì@Èþº¼á9a‘Û Þ¾^Sä Žw”s€¹'\“ßÖ\m¢ÃÜ”¹°|×y.¦B ‚¶î=ÕYæ>™ÝzÆO`Y¸i*üŽ pÆh½d’$l€sÇ;Ú¶¤r³›úçW—׺iÊÍ…0Ô^òîÕ£éO¸'ÿ î½×Üx0F©"Ó~w¾ÒºüL: (PÝ;Àõ øëÉì±ÄÄÿ|#’]]؉½G-ò¹þ&Üâ’PÑ™’oA[qï"ñ!Ön*n>/OŠ÷Y|NŸ¢^¡ÿ|à—°¹ÃèÌõWý²ogÔú±õØB¬Ê¨ì˜£ èI@ý/Íø»õ‡b­ß· í±³ioöáN f'©È|Ú¾@vœžîŽ1‰.‚þÊõߘ õ$Íhốtˆ[©š—}µÑ16þW[VX˽mÁ К>;Í>RKAÔph€}Fè±avft'°^ ÆÐš`HhUØaØŠ•c/w]pXàƒõ4>PwJŽÜòÖDò‚>yK/}õäk…ÅcåýV4‰WzÌ¿¸“ÜÚ!öW¹s¬Ê©ç¿í§æ«nýWœCÝ·¤(ò}™`]Å7A¶m< DX鹑^w5H áhòÐ;^ÑæWk‰•œN[a3#å°G;aÿSù-½íŸ¥q{¡Z6dj`"bR- bAîAŒže‰qXÒò¾£¢@ûµÉ  +Öƒ¢Ð´žŽ |{™ÐÐî#Æñ (sê×ÌO6 B&¹åG_§]`Æ4'l-©ýV?;ü 8Ž9mR²C…424щ'?7[%#©=ìàÛ4C ¸ÍbåØèeÜ‚TûƼ^¥Zm¡%­,vhº{+§§&l¬Ê5øtC.þ'ÅT“ø7gˈB|©yCþ ¯ûÉÔãT=/ã>†^3aÕ#Öë´´Á²Ñ¼Û¶ò c±o„ÀÐeWê£Ð<öneHMhÜyÍ^—Y^œiÂjÿ"™¥´Õì%‰­,HAPa UÛã^b.Å Ý Ã^yÝ#/ÃÔnTÒe=î¨8æ“_‡þ\B¸,%Èr©„­Cm!\úw`O,>—N·êqÒúbOér9“6‹~õe(­WäZá^¾©^ÂD}ä|íýîÜ’€€«Þå Á­ì÷ó?± 1„¦“emY–`å[•lêÆrjŸ ÈhŸvºÅ"å±,÷D„IConyë¼á8(ÎèÖ¼þ½öèµ:òÃ`1$°äò8_ö®,¢&K^óȽÉ„†õâc퇞¯.Ùyæù2âêIQEäÖà|Ke)BeÌ>`Š-þËXÕÒ}¡X x{—ÂÝï«F»•,˜‹ÓàËV)/¬߸¸X”:Œ9þ¯úï÷ýÐîÎÂbîઇðc៹‹_ÕC9¿-ÜCݸFöwÖÌO$ÏàÞiŒìï#7 ÷sú%£cP|Ëû…Tî«ðGFÿ?òèݵûät¼_~¢>Zrkw"õk¯”~òày_Ó˜$9,Ÿ öQ°ÂQŒm¨Ù»«Á†øª©ÊLG¡7g$JDö¢&b4b¬Îûs#[¥/ØEÌ‘—1p âˆ¡x3lÄÜL9Ÿý’6&SÏÕçEÊS#Ô¸½xÂ@ñtÆn^ºë²·WAk})çÍ6ÿ`º§ÁœAtÇí«¨ž£BÖžÄVdܘqGpâ>Å$XS¾~èCn›L*Ò™îYS²ŒêRÀªÎËÀŸÇVòáOŽGçn`±’LÜBb5|6M æoq\`Ž©¾a_Æ~ݱp‡5‰åì´§ýbcGVzÌŽ ZXÿK÷¼n¿ «žK–9½È߬þpà?7Ñþý“ü̳˜ú À’·çOÙ•N~˜ìþ&9ŒŸ×öƒ<ó¯O=ƒ4l@Ôo½q{=”瓜©-O ¨fðÙG÷§ ›¯JÒ.þjUüž,x’VI3ÓÞKÖ“ÚýÑê°f=· 'Õn`A:l3¸æ/a3mlûv꬞hq6b׃iv°E¿jœ\>ã;®AšB·Òq½Ù,*?Ú°f®3Õ>’Ö¿`é‘Dì5VŸÌí÷4&f™<6 g‰º¯“¿Ê³0—TOH/ÂJ1a±ZÔÿ[Y ™ðˆª.ïRöÑç¯ÙïÇ+Ò .}1WI¨s˜Åö•9ÒäiSßöJ¨ÚN¡% R”´ÿã°£í´·ÉröP? kê¯' t–ò±þóh­ ìÔ¤;Le_[©7…n :¥8CPØìH¹ÏaÑù…ƒÙö>ô·’€€Ù°u½Å¨ ŸP;Ü1åˆöù(ÌQ&È–c†/þÂ=[S4bÄ1~|¢“Í{ˆ¦´TQ–>pàxÏ;£ØDÚø:̨_nÁ¥-óÊìàGȧÕëÞºÉÞœ%ƒNÙ$¨’Yﱓre@¿æãÀ0o’hßÁë½ÿúÕ¿Slu2œö=‹¬„"ƒJAKÏÜëmšq©‹âÞ±Âk²¢æ°˜£[8œŒm|‘1QµOöF>"­¸?Ƀ‡…¿Uî´öŸX4,àN+™Xè6 ®š| øÍ†Ð9‹]ð°ýÎíÕMÝl4”£T£Ø½"ºˆS–SÚ©0Eņ½@‚m ÆÁ÷-Û2ã p?›ÏÇêhúÖ•WÚä%†bf|6ªÖ:Õ*é NØý­êÝî#Ìùó5‡{øcŠ1ù†FvÒEÚH{#¦êµ`ó³N³T@wOpfäk—º|áÚ >fa`}è)¢3Ú›ľàÊ^Y+ô×<Ç ·''x`ã`zYq8½ì-cm{Ö'ÈŠ±aøáCKb»µFTêµ,7É«ÿÚă?9uj2Þ«*ÀÄœüª²¨ Q½—À5…ÄÈ1S9›1 AÁîã.~HjüÐÆOTHjŸõ QÓ÷§Ø¾¼¶;ÐÞøíÀ'ê„f¸g-=øíÔ²‡ÇPûrO< b$Z .®žÎÊN›åBà—÷<Ï8=Š$Ã=ÙŠ ¯+|+˜Ú„ŽYÏãœ9´-ë´…q2J™{‡’‘&-wö+‘Iˆüª#£x‚°G¢Gu¸üá#vû†J0#ï°ËÐ c xAô^<#X n1¦ÀŽQ‚ÖEgÿ"e¥ëÁÈS¹ ÑÏC¾PðÏyíèHò ÿãÕ‚RC˜íZ]R Ýà=O¬ÇNDäF«˜9Áþ(“(EŽoÛþE,ô‘õäJGÿ]ìÛ\gœCïWwšÇfxŠó.ì"¤ Ö ~³ÇX‹¶¶|#a·\Xׯgì JnNNvŠýaƒ%d_òÞ_‡ç°Pr^Nî f&½h±¤šŒË}P%*«äœ¨ŒôO)ÀseQNñPÈ>É|Î÷™åfEŒ´Êƒ(ŠÝ±b(O~'hÀù®¾°æ‘Æ’€€âöáØÕ³FÉ—Er×·µ?-ØÁúz´¤Sj|ÜiizaÞŒaÔ\ó¶hø\%7›»%W¡èJËgàñjla¾wÒ¶‹Š¾¦r9K¥ÈcßjÄ[Ymõ=2¡:ÔB°,üh{Pi« Äl–‚ãqj–ÑNTõpiUg(’^êq[û$Òÿ‹ÝÅí’ÿšé^÷r©ò§ü"z[™N…¹çmÆF/Uì5"¹‘@mqì»buzéNÍ̪ÆÊÇ'œº\_ôÜB0s»"ö#/sÇ2ZbÎDïþtϦW¥q¤ó;èç44†b=p)ŠáxˆÑæÂ®Et\Õš´»›,6!ÅùÓwZH 9eý[ßÓó•{³½xeKbÐHgœ¸ãI²ýak ,ì,žo‚Þ2(?Z…úËs½*P9¾ gøÖ]Î+¨®½áRð¾7Í·ÊÄFÌt¯º£[Ò3ý?.> Ø=ÎrVëÆˆR|JäJBVÞŸp¸Ñ`‡FÕtPAôoY *àýNùËx™ZÇ‹t gFOŽëFTàŠënƒ.@(åú ¹Ñ-ôýÕ± ÅÑ1=Z!ãµq‹–·‡©Ê¡ÁTѰޛƒC'àŠۻûÝsÄ[,~Ÿïß ú"KÀèaÿ»ûN(þò‘ÇHöÎûæ‘ßE;¬,@>”IÃÅ”wn³c{ùòÔ~ `Uû:d3Ë÷ú¿ö¯Ó¤ÁPýMììÎò]¢4¶r<Ånש±L<êâ¬fA›¡òg§þÁ¼¬7kYû[bF)Œu)@_ùs€%¹ÄΜxDXYU*'áÑã2`n8Uw9%Ml¾Àþ‹ÀG“\è/æ× è~Ò¿PÎh¨úý„¿ì¼‰ô2Åy}ÙNßûaš;’JzS¬õô7}’¹¶S∆¿ ¤Za¿üè/ ¬@„ÅÕØ©ÙÏ Ö¿Ê‡Ëˆ˜9c?Ž„ÇøÜÇf¼_E5¶í÷€sÈÐ@mKƒHÝõðÌ“ä¡´Ò D|Ixã„d?‡ y¨§¢S¢wZ0¡´$µÇ˜MãKK |mÀùF9ÝÊlùC™ßôœ­­°AÉrºfXðà÷Þñ:.â>’ô7Í/}žÚ1=¥„ÙdK•æÿT˜-¿’€€ÔjUÍÔçG |e£ïíH"@ mÀ­üÊ—Èä~>¦ùåá*ã¹|úxÝGYF#ÝUŒÅ'  ´®ÚÄï Ðj’¥ÊØšF ®µD]äüæÚ¥_ts»®eÂÌìZV4fý@Çæ¡˜dàôjl£Y·+åtmGs“î8œ‚HK¯ îT~§P’K'}]"ÈùdŽ…/¤R„ ¬Ãꚤ éÿþ4œü9§en‹ïnÏ|+V : îºfD‘² øN”؈¶{¯ŒxH/Ü"lˆÔˆµLUq7G÷¡rúÎ0¿2|×keÛé…²9›ŽGL]Rj‡†ãbn7¨Ì™ä+ø(Ź3wò‡U.nK‘mNJ"fh‡cgÍå•z÷qˆpåבrš ‰Š7»¥¤ä¶6tGuí´4un?*DW¡Ó0éhÐ m‰Ig´™ !Œ—knùRtΑ蔊Éšïãë޶hô¾ÙÌÊË~(è…ͧS0í¼.‹´3›BÝåWlº"hèOsÓäïîWJ@Œ&ÄãaÇÀbDp’bòôöù_!©k9£ušíGäÃÖÙÝÕ™ð“¨ÖVo`xL?gBÙК=âñ8î©qc¶GM.Ƕpðì’¤‡Ü(–…¶KXh@)"ì, 𕬵ŠrV4Çd¥Oö7ókŸwgRðBl[HÚV:ó,ƒ tµ*¾Ç£whìRð©ª9üõȸm”+q8ÉZÏ鮆ŸŸE¼£ôÄÐw¢nS>Ò‘ø· ¯êK@_·Ž‚¬¾Â*R?¯4ÑâWº»gžUqኢàqüÑŒU^ Ô\YâeC°‰KT¾pï9!ôƒ‰§¦ S†ñ;3'Øv£t")Lº"ÌôË •X-‘Ij©$ï[Ë!Ø ™’€€À nú§ç좘ä,Ç+{#|½ÒÉÅøwqa$ØzšQÂÆÝ–¹Q°xêçüO–E¤fk[¸¦ÆÇ„¾²åD1¶Ôüݽ¸ŒÈÊEotÊm§WÉ€5®…lÅÃÚÿJ7T½V*ã³OY76\ NK0io=þÕ½„*0axd‹–Ÿ™è€¤ø@,ñ‹õ÷fãl¼Eõ9ô2pž­t®¼AZÖ~)–üzhqNýsÎqKÈ92’‰ú;@„êבmªf¹YŸ@I‰knŒ1at„CÖä°³…Ñöëgƒx,‹{^ç喇¸²7@+OO„+cÃY„Ý,µ²jX ôB CÂ×ëe¨ð”$€ZGüá }#ïcijËÈ:-JÕ­ûŠƒh-ùË–KJÜZî¸OîÚPnID¯ütè:÷s®P낼,Gvéìø–¯îcÖ- ëLˆeÛm´Ö÷ÞòœJ³°‘}ǸŽÇ¢Gâ÷‡l>ëq“ µÛ°„÷%Ì¥{¯w]^ ‘mq¯%Øó…]}·“DÚ’'¯le9 Ð@ÅûµN’€€ÚÕ:<ù5”EÔÿ“«_ŽW3e[bÕÕwØêC®ðúDe™HÅûÂûŠ'.“3Hˆ)Á„¢M¿éÕ”‰ƒ Pö{г)Ãùïû~ ¶Á…ÖåùAhªsv:­´ÒKûBÀ¬ëç’ðQÀâ Ÿªóo΋é^<Îr¸I°?g{œ ÿ³ªÍ¹Ý‹Ó¦íUšv߀–ØàÿƒÓyôhhíåg&U,0ëiŒ çd‹¸Š´Íy&aÇ­3HùPegPú¥?“¢Ã¦ È`ÿ¥P° ËV,N¤ò}n|ŒarµóÒwÆÌNÔ®ÜðX¹@1í¡úKE³‡ïXŽ–ÒêSpË’ô߀Qêö6é=¡˜.Hâ^Ø9«ÿ£¤= š,[Ÿ¦u«È@!yã#Dœ‡ðEÁ @ØMÌè9è»G>…¢ âSImê‡>—ûÑ&Ã2;fZ׆ü;ÓôX{—Rú@­/¤¥âk5nSûÝ]ÜrÉIŸ´"Ê<é;2©ð«tOáP4‚û,ÜË T Ä¦å[MjßñH]ãéä8blõÜäý®YÔT´„nd‰qš”” X51êÜZªÉºÄÝ+ÐFÉÀ½þ¥ ¡gBFÊ€ÖëˆÂŸ¯my"–Ü<í³6Zl“@}ça³©Ù6/¨ ÀÆì3ôÎe-ïC¨Ì® …™ÍtÇd•É3ŠþfZ] ÿøÚù/1XY‹þÓG>¡’€€±õ,oï†ìNbìžÿ}'EÒè`o‘L s ‘œË”†tT9àW`TæúŒQìM _JL)²“BaNÄP‡|zòiÐá¥ÑòzxiØË¯m.†åš÷qZ7ÔË/╽äŒÝ:uˆ¦X1ÑW©ä¨¼þ¿^¡yu~Ÿq„ÞÕÝôeX øY2ëQ/…?€œvÿŽb*µãd÷6§”èæ–hr«C®‚àÕ(£‘S¡S=#KÍL…#gÁLÊ.¦ãӡК°qÅýñCDAõ 2zœ |€¦Èבn¼4g9œ×ÌÙ?'±ÊSÎìës}µ¶xn0ïz‹‰c/lÁÊ;÷é–î˜Ì¥3²JoÐ,ÞêŽv?üê8e§mZ¹ÒQ ¦BZVâÉš<Â'ÓS/{ƒÞÕÚ)¯%ó¥!”Ž ¨ñÂuñ5ð}m]ŠWs3‘]ÕŸì_ˆ†ØßPæ'†T`¬ìë_ÐçéÀ€ÎiG+îIfçJžJNH!®Òê,‹Š©snetkÊåÒ«¿Jü ?Û}lxFYJš o‘#yQ«X’¿ŠŽr©ŸëòÇgIÃâ M1mËÓF‰ƒ‹¾RÑ5"…zv¾»Enc6wR)úõJn+1åšÃ[ŒìœÔûì?‰&׃0Eü)å&¦Þ5:š¤yŒr \¤ÞWL¥«×¥„¥o5&f-~(ª•Ùæ¡(`fi*O³5›–Õ´× 0fH?\¼Jó¸ŸCž pøG׳ªf§yÄøPt•T9+Æö(¦7KÈÆ=e*w²ý!þºÇç[*ì1Lv* è¥RüNßý胉0v¹O/Ѿi÷ þ…îUMÌåÓÃ÷¾·<óÀ^¦†pE“¢M, Î-J8ÝâXþhÞ:„ÑFyEŒìà¢Q{¨K/ÊßÖ›h¬õYDx¥Rìc'ê/㘨'—ÏÖGMòG?5@uÍò\òàŸ±Æ¯Ç"R¨g‚üë¹ihzäÎ\ð¸|{TJó¯e«EKlìØ×»‚6ü·=ñ\P±§ð þALPÊãþâѠ˰ɴëp¯¸³«ˆ…®vmñÙSÐKCÔuÝ^l˜¶íû÷Ì ú,ã@U6iPiQÃðñ %Ç"Ìe¾o ¢)¼ YšÊœãø¾ðèÒž†—¤…¦’€€Ó\“†ÍQÿ‚Œ6fuRønRˆ?~ôy a^=:;Üû/)žŠß“ÂñÕ,Iyq2›Jwx"NÂ@€SîxtëšÙŸèKÝõªÉ¾Ç'øKòzå¼ü›uoç¯wˆÎ}?Ê8 O(éÓ¿ç@Ói&õ5#Qy,^¢š¯Ì3¸tÈ~rºí ÄG»5¯¡ÄAâ8ëœT|ë<ÒÛË´÷ùhr¹”%hpÜZà ƒuk%æŒ~Dtÿ1@ãô PÁO*4øÛ)¦ò©¦Äüù®œ3w±W8Š£_–P¯, }ìå«“12éZæÁñ‹‰Z&ÜCŠG˜Ÿ6Tu©<-;Ï;øüGŠÆf¼]RS¨ËÙ¢*5 eP`1Û€WȰ§ûñÞp츋Þàጩ€KR`Ó` SmÔßÏ‘Xí‚Zµ;Dé´vE®Â’Y^ù¡Ù Ó³ÍhSŒ"ÿÔ9½š¢¼ž<¤˜„þ:Þ‘Àó­ÌiY4¿(ÞÓy'mAèšjtõá.JP±u0î>i%ðŽ' ,¤œRŸ\q×.ÿi„–&¨µ ]»Ð"É µ¡Ú2ûÀYº=MÞi†¬ªÃö¢îêöŸ~ü·‘KØ€¹rê´5×_d„÷%#qÛR3tÊØ&nr¼½gÒ5MÇúïGaùüÈUlÁíį—š¥Fïk|¤&`åe7hpJîÌfC´[›fà«{ø_ô°X'ÓúùŽ·ÞÆÀ"–—ùX×\LFmá9ƒT§aºT‹ê‘ÂdöFKžG ÊÈô| €al¢.xT°¼³PÞ•+¡<]aÇþ2ßÙÇ¿wÓƒ¨ŠGžMäEòýìø.õ4PÌUAo +"¹Ê„špZ“HEèc$¸Â®°þ{£¨½Tï}ÆÙû¡UoÓ[ébäu+CÊ\ª¡¶¨tMžcVäþÄšæ¥ wr¤&ÄêÀ6¨î—MµÒü—ÑþجBê§óx)+ Mcó/Åa'\H¹a”y”ôqìN;W>ßþ_’É–(ït?—q/S67Ñ <:ý6€Š'|îqB^˜pxLZ¼ÌR’&M´yü>[IåfupÅ¢ZŒ“:ì’àq}s^$D‰ qÐk<˜mŸH tDÍ­^Nwhà%ÎjË’€€¤·Ÿ„LNåÄ£†?Rçòðâ÷žÄ"4¼V 819 ë «ÄRqj`LšsŸ sŒdÌ,»„AÎn‘O#\ŠgÝéV9®wM—ú–²µƒŸÛ´áça±Œ»ÛÀ%Ú¬Rõ“1ø_{"ŒqnxT‡ª1PL­-=­_cæËH·Þ^.ŒF ¿ÞheŽKè»Gè~ËÝŒþ#¾ub\ªpοâL±x %‘ÍZ²#' ™|Q¹åß/À`bðû²´|غTzÀaè!Õ¢ÕJ Ä&0ó¯ò…J‡,ÇŠ{(Äfâ÷\ýÜÙô±j6K¡äoäæ±1Î'Þ‡8¸ÁãYö¥Á½1I¢»ÄpÕu^šãùÞª)M…²ÐVmN,Q‡`ÖSú»bíQÿÇ÷×Àp—€üI—bSB¢ä­Ü7.4‘Ë6Ú–ö@p)œÏ=D™ŠH gpçgæÀ‹‹ù”±ÚPÇÒ’ò ¨šY:Íò%¬æ-„þ”j°S£Åuè?ÔŒãryª_Oy³JvV¶Jüù]–hb4·Ìº'ŽýßzÎÔù‡‡tzöâ¼l!¾ƒ¡QŒ(Ðóƒ–¯ßB†QÞ×i¿Àv¾\³RßLöy¼ ÍÖ\XˆëÁÿXPÒKÚF‘ñ B&Pz£4Øé½J:ÁMºhh²8 ½u~®$“új“0H?e÷Gî¯ù¬¯unÑþ—éÇa˜ÆUý{­2yH>iƒlŒ«èŸSÑóh‹ÑÊbÜÝ/ÿ°ÅÌ ¾OI|+êFY@>+|V¸åÜyÌÛäGí?¥ "ÌÄÈDe£r2€ ÎmÍ}IHÎdž­e ZY”s#Ö¿âSVéˆUv'…Çßæ8?“g`CùšŸ__kì;‚êJµröt&pÀ\mÂ+Í÷“ ¦‡‘·"è^çƒÙ‘àÁ• µÄ^tÎ~MöÃçKIû¸†Òÿ|³a.gL}”'`õÍí"9= P—¦ñl^žO[l‡J­|…,\hÕ˜&àX<2©¬þÔª¬O+H Ö9³âÄO¾e¬t{9 +pyq¾ö^±ë)ĈI3üâÓ¯½›Ø0ʈَ>û1V¿AcôŽ S¦¿Ýp¼l»±õZ’@RØl²Z»÷IQ!mØñ+Ð?›ñƒgJýjƒ†øõ:5*žÇÂ.ƒ,^犱Ü.ÁiÃ^ JÀ:7kf®ó) ØE@E{ ‹Iö&ç?¹zò¨ÓdaäH8wïåb³ÞÇ©wV£ï\÷;u;lpÆ1Ëõ‘ç¦ÁNggh*ÿ¯¥;6íq"  .1Y;tœ­FH<¥g.J§5do¸uÓù$Šþêˬ)LAã_D9 Íõr—®@ë“ýÍU…cšŽT倨˜ËûÂÝRÃ&s‹ÿgÆcTP±ÁÓ"tÕÓb=±-¼5÷·F ‡Ö»¢ËLØåë§8 `Â{ŽŒ£ù³iaŠ®“çc¹&Û÷žC¹-PÂÑ¡8ŒWÃŽˆNÎ)Fƒ9O¹$˜ó'÷»Ž(h»Äðõ?žº¹W…·˜Ècq°V/]ÊZ £¤v¸p±¾dòNô³®{|Ú‰|÷-G¬÷ô€jù³¨«…Þ¿èˆpQ™yïÖ|ý\É2«LÐt !œ¨§Gäb+Ô•ÓÓí`×Á-lîQÎ`¿Ìhs7,ósç?æEÔƒv”A0P»oݶzÎÒ>,TjpûÑPK¤ÕiD…h©š©ýøêC,(þ¡çÊDnì]:‘]n`k!ؾ€¤nšnþ•p­lýéé>¡ Ù|‹d}øÛåfXн8n;ÎMû» §TɕÊÿãf€ûÔè¤×F˱“Œ.gã™ÕéëS‘zÌú>(B;+:tÿJi­}aBR!Eî÷íœÀÚYvÛg'`Eõ}ÇÆº9œ·]’Ý‘mLåj‰·yyÞ4M;ÜÃi”öù:5ò$Ülzíâì óÔl¢2x¦vôó7=$êþ&ó®®Ôpˆ®£ÖR«¨Td4"þW)Ü€Hˆ¥ZajL/ Ò“0y֦ɊJØâÚï Ô1î“LÓ¡NØpцéNÌ’Ze lÚ)’€€Ö߯„ÚÌü0ôµ.…vÁNË Ä>%l1ÏùG\±]+Ä7q‚ûd†CŠ0Uw°]Ïϰ–3SïìããÙö/á¡Eï¼”=$îÑ“§úÖ”9 ÿ½´ãÈ0Wa•Öž|mt&´ç9õeéx‰A]–™ÑÑ5Ìæiï]‘;÷+β«H?S<6_6üaÙÞÍc‘Jú¨ºè™ï†Lt]»s#/‡k¾øæ¬þ–Çß…E™€œôbZ¸ç¶»D%¬Uj ðœr É``â)“ïÂS¼­–ð±.õdžç ƒäó]È‹ðÈ4Kª?s%ìñ¶ G„iµ˜ìŸU‹÷”ÖŽ¢.lS¶QŒ.iCÂØÆUÿ!µ5sdZêÌ›ÒÜÙ©œ ˆ—Šr·²¨N§—é°}'… ç1G?Ô~Q«†xï÷6 ò«0+QùO/$ZäI4=†Rû74)³ß wxâHw¹è×ù\:GQ¨©©g‰ ’›¼žDhŠmÛ#)B„[†HhíâYè`õú3ççKÆmåêh$áFÒ•Æ{™¦›+˜Ò+ïÕO·—<_¤¯†}ÓªÚˆ²Ô9‹9C› hí³…„1¿©s*yÒˆ!QB‡Ì#0º jN[ܘxÏNÈ„$6J 2Ï[õ¢´†W4;UµPб¹…‘§o†"Ùµ{†‡ëÚÆ"`£¯[mó»]RDÞ D—ó!ùÊÛ —­MsBOè¶‘ˆ ßÑþ¬G(D™$’‘ C“ûÑÙÂÝ”&¨“îÄÖ©#¨¤”ý³Õ¹µ2ÏböH£3H HöqÓŽ}Yµi3` ƒ²´øÞ‡2Ò7ˆ†í,jc¬W´ØÂroa#½ OÌ_2‰Å[ý‘±Wúè,‚òØ"~_$k%öÔK¼'ôn‚Hœ›œ 7”žcÀG–tºù ’ÝA¾¿ÿÒÊî£DÀ…mˆ[DËÀz‡?ÕøØ’€€¸â G*䃄`‹yÂWÖO胚t +ê7A¦eŸï£1ŒÊ±e.12é‚Å÷{eŒßâŸ$ì¹øw%µ–ópŸ]0ÛIÈÄr·ZõwžFÖ;*yxeÿÜ:oËÿ·¿Ù}³4 V²¶ÑP¾5&òfè,~ùr©.·ëZ\kñ«uTû5ͪš:-Æ ‡ð{àNM7k,•öФõ`Æâ{¥¼8»‚¤½Ì@l0,*­ˆÈ „øJ]m ¹xâ§»%ª]ÊJÞkG‡âÊFþ”`ÎM”Qµ—@€&pÃ'"]šxÙö¥Z“3è£õb{Ú¢Ô¯)Ðt±SiÒ«[Á±ð)AÒ÷Y–>n“=D•o•¥?ÄÙ6d¥j8y½ôM\Ê ÿjçŠÜÍ5`QöoNs²'Ý¢?s)Nÿ–dp’.Çîr,eÜZo/Ù)’®cí¤-=K)„ðFœYÕWºë¡z¤j’N °[˜3Ë|?ãäÏ’•å’ŸÊÒÌŒTsúð‚>C>³$Öð×®êk %”;ùë“íéhû¤”ŠÕ6ð3Ÿ¼€“m•»æý±ŒÆ“µØ-KhQ06ê -|è´ü£á*[)v©|´[þ(%Kgx8ËÙô-ÌÁlbz©g…,ËÕ§è+ì_…´¡-–ÔñhGC/Tïðý{‰‰v<…™cëúÂÃ/‰À \7£oÄ3¾ÛÞýÅÈ»æ©<ßO œÅ^7ØË‘ýã?»DðÅ LâNT*ñ\J!÷?Sw^z²3©Ifw´š*'>ßÂßôl„vaïæÛ•º¯m>„³·¥)ψ(>+]-*]‡F°K±ó1žš ÄeðΙ™ï¶ÉlϦ_`ìWFê›WkFì„§á§=éNÂdŸL…ÐuSdxnŒ.fËŒ„œ|Sû1®®Ÿ¨7ØïM 3{Îã÷I¨ £8€AàØ…ì‹/v˜ÝJ³hJÖX|ÂýäY)ØšÿÉv¥só·ÃïPÕꌳƪébsöQÒ½‡Í±½´ïà ³7¤ò°NDMÖÛ3á¥f,¶¾/ÅÍWý2„4?ÿá¬a+oÿÏ)­“D“^’¢10f‚íKR´+ê4U#ž#ÈûÍãMô(ÌZM<Ù!9ûéÇ=EtÔ8èÆ\³P¾èØ“î%sÃÀ„-’€€Àr§^D&XQ”ׯ< ãlFG°ÎÝšR_zX ùû‹[} <% gs|8Ì”ÎO˜4êñ”3­£’LP“ž±gmþeñãt˜¸ôhu›8ðe!l(þ¥ì½‹’ˆ ÑÏ„¿ÀUŽWêIˆï©RAƒºx¸¬¶Pšei1'¯Z) OWU5ûOKèÿfô­Jý"ÐÛÖv/Òýþ¢9!Ùòj÷7PàW¡RÀ2+r½Ñ¿Ö6Ü“‰"Ò Î¢xÛ‚‚*R¸j‡£É4N?¤¶ýÅ(tø¶b{êú—„½©­7%Íu• ÚÙ^–çÂ¥#‘™šsŠ`Â7¦båB€4mùœ’»¦wªž?(uì@^YÞJ”˜Ó¸Ñ$wÏôÉf«§X>y`DäT>:vrA¨¸û”BJº/a9Š$Ò®af´‹>.çV d‰w©êEšO÷­;"®¼ ÐI u½7ã MæG0„nV’£|×Lß±j[Ú…U[Ö`ç8R–ÆœP¯Ž&@M)ø:´Ù*–MH8® ½ïÞ¸†kÞÄ9yIjòÙqæFÁãDüñ`Zú¾ÔKÓ–“‚i䜪›a;  XÓþ6gp;7ò«ÆÃ‡ÚÉ3TìÆLß!ò3µ 5·‰â. ’ÕvOM4Œ—·b]ø~zLkñF"ÔxÀmÆzSOŒÎ>Húy§d,p–n5#•òTDqr¹’&$Ëœ…ÖìqIØ 5O¨!ÇP”O‚^ø V©½{äÔ°ïÿL› yÓE™ Rø^ØhxqÕ¶ÊÖ¡ƒut‚®Aâ "¸IÃÙ¼“¿bÃíoØt÷¤,QMvþj¾ÜïbXOHc- -ó­{Ð{|ÎÚ7ð¨#ŒÖ/Žr°À<ù"*½påx¯=DàþFˆ\nôŽfž'6Íʾñyi  i«oë„èqE¡ü‡Öa ü3¿qŸïx½üB¹-JvœØyT¼Ø¥3ÕïÝS!îóšvbŽ<ÁH/Úqþ€C®pìùú$˜ƒÔIPçŒà‚5¿‚, MdNžOA)¿¦½¶ÍMDmnÇa4V1{*¢ñKÒTÉ{øÂP:ÁIY‰í‚ÅE9’?¸«¼šq¶e„éØ;  Xp³Ngg‹ên]½nKýß³dºtl¡¹føÕ¯|h^÷æhJÉìLPtä¡oµnùGˆÚý|a³Q’²óÁQp£ Â}JGšŸ-TÖAH-Éî[µ­K^Ò™b°7KÔŽYئÇ~°øçü…qé¢RÓ‘ý/îXã 4–R„ú×éaœ¦CûaÀª« ÷[wo±d÷²)¯”cGÓ£›nTˆÐÎZul4Ëg¥—‰â’€€²-Å Òþ¢WüÄ pA¥j«?®¨Åv(§Øü@.Ñðý]YY€×6Ž/ð3]!ïÐ ¢ßj£VÏóýýˆû²)Woö¥›Ï‰ƒ ÿ =ú=…8mt}‰B=‘-B“ MµNŒÄ'Pk#’é#ŽWäk÷ŸR‰$Ùprèw,šQ{–œ}DßFïùøÈ)PßH#×íJ¾FTÁ½ê˜lJœaÛk@‡¨…¬Ñ?„4¿SbZ¯ïèz®Î¿EýX;^JzÒå×Мø™‘FM » õ7b°ufÿ#ÆMíÞKšc(ï_jhœƒBåN¦|;rÅc£IýX—/?oìVzœjÏC.ð††®”XùzèS4ÉDä ¯ZH+äxö‡åê$­tåvSMèòÚ øá»ŽíèKiÞ@5ÀmYgЦŠ#‚ÓßÈ`Æ*ÒK_¿c{èmGåf'«š²°K„Œ]Å=Ií>öj$rŽãçÃó½TÁÖšqb¼Vð£@e{.²¤†ºÄr‚vî¹ÌϪ«“š¿¯Ô "l¾_íªIT´YÆ×Zïâ!Ÿ™ò§íJO&o׸üRk¤¾1…š‚î •¯Û…|Ë;ƒ X^  g,qvÍB¦ð=—T«K¡òbG*U[ã­ÒÖLï0õÀûýþ®µP·aàŽ8Và2«87 TðÐ2‰in¡ˆ~éžêÀŠš6é®Å ðñWwã’çÆñw5êºqnÌ/èa„“Š@TŠ^Šu8{ÛëåÖǺ“AXbî•u=¢ë~NÐÙÕ6=f”Á¶ÅD¥zwÓ,R³¾7 ó¼ Ûó…(^ê‡Ö'Ë! » ‡HÖÒ³…o¸‡¼¶ˆ¥MC®>@ÿ†Û¤âeZN$ÌE檼O“ÌÔ¹ £kyî.‚b„ÍÉW*´wkìâÛ|wbEœÃwü2Å~zLÚ¤7¯¾Fè…¾¸\òK_ÇŠ'uQŒ²d]†üBžç2a„ó„õ Y¦v £¹#×Êâá™B‡„Tá/“Ìû &ý–°N‰V3ˆÇ{‚0ÄáÂç0´‰< Š’%R,ÓØaÌò`¿Š‹òš@°Ý·³6&®E¿bކñmyÈÚãß ƒÖýwíõÀ‡vÚt»ju,*¢kI¨#PsØ|9ÅW¯XTSuhÒ2™·¡§‹Öè‹aÜ\;©¦>ó…Àìn T#z[Èñów4¬Þõi;ó UÚ)S³=:´´—h“js4熢‰o±†~ÀOfkžœÓbz¤´wÉÈ$”9½è”Å¿¹×$2yÿr¬¨:éÂBòFUŒÔc‰ü/>e1án›Kd^Ey¶-—ƒ—£ýƒdF2çÇ!6:ñ9qöÁFR'6á-«¯U§ªötúÇÿ?&ÞX³í?0‚ K³v›5TU:Qþ8Êí}÷ ]Ù—’ŸKá¶'øN#õ˜ "ÎŒ\þ®ñë§A^úÇ`‘Pç#x€}›ÍÔ¹§¢ù©yòJ“¨íRRª†Sès$Ê ÈdŸ\·×S7FòLb'âšûC%Å•g kmѫ˖ĸºYrnœT˜ü›DÁ'‚•ˆ©â"‡ 滘”p€Dz'GÕMZÿ{Å#ÁH‰ ]¼SËð5Û¢Ù¹.ïu!ÑØ;нß@že\/’Bž{µåÊýuêŠa.6§5Ù3m¹H™]ÉÀO'›d^¨š<¬â øQSË‘Öì8#†O=­>±4"ð‰6l+á ¡BnÍ£Kp¨èQ°Ê;«$Nzl[ze™¿7a* ·É,´„áîçåK[cþ_3;¶¢ °»spYñì׋>X¥¼`Œ`GFÊIã&¬çÞ%­Y¶×äw‘ª–|캥òµÚÿÏx0èaàÒ¦‘`¶Ï€}$z„þÓ«½¿BQ#è7ã¡ 5Â+©ýÎLJö(øÔÌ7ÖFΙÉä’è—Ñ÷Ì_Ei5ø(x<ÄG†?ž|?)«FvŒýÒ׉[;›kfXd¿3lF×Óîвã]À~%5MÕ…ÚÕ9<º´'ˆ"¬ÕƒŒ WK z¨ó«TPðÒUéùƒºï-&å?2ø¯šØät½>tËHƒÔÓë$2 ùø Pù߯® «þŒ€ànŸm†™º©oo ´÷IžK(NKêÈh ø¶u+EAC>—1’X\¯*wOrÏ8LQr’€€²¤Š H!ÈfÁ­ÇúæC-Ûø®²?ý¥š¦f™ƒÂXFeSøM±ÊXNò°˜S@UFsÅ~¥„(V?ˆ²†l³Oî27‚"s0œæ<²1ºcç^=Ä"WÏoâì踿9m›?Œ‡ÒꥸçãÌ" Œ(©Éå$)fÉb'zýÀ“Žîçæ#ð#ò΢»¹üxÂvýƒâ_”qÛY=;þ?pC1¾B¼øf~*›žˆñªÇ÷ë]…jfGÒ ³ÞU,¤ iÎO î1ƦáËí@ ›*í_¾!Õ4¼ö†±•Ù'â(¨Ó1,`šÒ€Yfn*„ˆô‘7š¡Qß'Eí¼:Ñ™ÚÎÌa]}%ºÍÃÛ11\ùôšà,uD`Q韽K#™Žî~綨úØyz iŒL¡gž YQ«õ6bÁPÄ{¸Öè’Á£°IY²Ýo2–ýcäMH[jÉcMu÷œçùÏË¢$iª=ÚuN@Ñ©fð?‘—ÀKÀ00äWLÙ÷ØøK®nÖ ï 3iÓ鼟!³wtD·t*] ×ñl¶ÃU±ø•ŽíÅ„5óÊ%J«¤_ifóPpÿ3PK•—9¼0EH¢–¾¨JÕ-þ¥V©ðšQk8`ò uŽ,Ee5ϵ }B§AäSDúöuÉÞå& öOtKGž«À?C4Ë îÕ z7Œ,ÌËBœŠP.¹|'¦>ýP@ 9“Ïhx±‰nt7ü JKTtÀ³Ë㨥uÓôkf^az€©=–3¥’å,0â†%?t²Qî}•v®£ñ½OÈJä²C ΡªµJÅòæ~« ÷mí­š‘Èû¯´Pä¾M© Ý×bÞdM£¥´#¥]³kØîÒ¹ÛÐðW!£ß9üXO`;ÛDn‚7·ž.®Ù¾_Üö‘Q²õÍ“0 ÉàcäÊì•þdöòLÌy*ŸêËþÓÛ† žqgÖÝ#02°,TÍ>û4¹““òt±ÿ6ß@Xñò²¿#Wu[6üCÅÿT=S¢MŽï²ã±Ø’€€®„ÎeÕ˜Ü:g\õJØè+·êÞ ^Ÿ¬P†k“‹]×<=t‰êðÍ«wÙYWêAoÌh7YÈXæA>$)Ü~ìé†7[à´ëŠýIÃNÎzÐ2,UbÄ&>˜n@‡ÒæØïûðˆ}÷'ã›sŸ½'nU¸µ;¬ñÑ}]»ÇÔyšß)JЦ€šH꜠9“HK!.¸˜ƒƒR¬½mhSÀ¿Ç"Z… ðI6ê‘ÙßTÏ,ÞŠ-×Þây’S ÔPŽ~Ц…kš¢Ë«èÄ…éµqy;I ”y­³tLÜ5¹8Lã–Ï)e_"¹mÔ»C†åÄcMÀL̓b€ŽÈn ·æ¯ƒMÀ¥ªá'¶ÉUäËëJ¯Tƒ ·Ô{š7ñ ‡||Š]÷Ý›)H4kDPc™—ƒ3B2Eþ4ŸMOŠ–_H´×k­9äà\+{˜iﺎîëÓ†g¶º–$âF¸tÛ¾)ÝBì(ãs—¿y½4å=›»a­ƒVÑa1;AžézIÈÆ°Ìâ}§ò?? K„_É%.%ûå°°„˜ÉêÄ’%­Ø¹D?!,Êà#V›!Ø›&¼Tj±¶RP¶«Á­ªŠMÖpZ^’~ŠÈ~žE‘#IÀ»ÉRÌz䨻8J­#}.XFsÕc5ÔeNq Á ŒýÜ»$¥\ªëüž•‡†gTËñàF0Pœ—≅:ôƒ«rêîwÁC$DhüË:3ðUEbóDŸ”‰ÿÎhÙ”ÖÎY#á.ÂÍð73â6J„\þ×]ìO‘T$»ŽÈ“£GÑÓår·3Úê7įpöçÇ Ïú+\[)§OÙ_‰5“”oñÞ`ç?cLéŒgsÇ4É ´ÃoK»üÃù¥.J` û5åînƒV¢Ï7½wfµŸlu4\ºÈ‰Í‘Èbàǹg1¡d¾çã¾òId¹m‘qZ:Øü†Àêº8äžÆµ@Y¹·å›ó±˜¥=¢›†5e.…c „ž«T©û˜„r3׎HËÊ ¬ZÞµÏUjÑ·ÊiP5ãºY*wì.¬³f$üæyGä æŒ>AÊeÞ0˜óµ^±{¼g3’ÍxväønsØ_œ]NN8˜Âtµ¢<©–ž3\Ü& ÏüöjÏõ£; ‰’€€ÚCA±`µéõe¾VKê®Ic§Ì}%ÿ¾h¹.‰m\’wìÏecÃdü2l²ãò®~ò™”i s ý-y÷Z€¨àRÒ!Iê¢?îa;:|žÖqçC^w>ËÈi‹Ðøó>Oæp"‰ÿ#ð0}}‰ž+oäÙ¥¾6X™Ú) ¯¡£Aï¡fl 2º{ðæ¸9‘ƒ@‚Iõ‚ïšn¢Ò‡ŽCÍjœyäÒó’{Âʺ5gưC{‘ªN]Ûc4 ž—ŽxûTî@HÁF‡¿é°˜Åä_q%3µæÏ9áÔž ²{´]§“ñlûYr!휸hNõwc]_¦jÈ[‘•ê]T« -z{5?ñ÷ñðÆÛiey4ÔÏt΀p^Ûíi/ 9ÑÛæG¢æÁ¯R°“rC„Éïm_ÎÌN‹}¹,ú=´»Vdú;úɵý%rÊeaɰÓ}±éƒBæH¦¸ç*¯cº„Ö¢Ðè7n›ÂNhÏT_Ú Ë\`·,¬À†ÐP«Y‘XÁÒ"™w1dΊhoP¾ârÓ%çòןƒ[yo]Õ‹…K 0í×T[ ‚Ö¨á¨UD–á<0ÏÁØR#ü¯o£}Ð I%ŒìZ^gºyÇ®6øÒÉõ×~Ó7×|o‰Z°YòàA í6Æ4©Zã¹<ݺÈÁ¦åjYsurë– ÎëZŠƒ©}™-r»Oè%*œ–®µÝ&; ‹©ºž yIãh3†_B [W]$GR~À' åxà¨O*šuiZð:}cGrs¾#Šð`‰‚ÉÏ©RtæW8 ÕÍæ…ÞcXû¨I¡da¡Ù†ƒ5š7ò1ñom$„Øîª Øp#å'žàÇ  úónHÛ9cÉÐÉ×V-Z–Óü v§ù†¥Œ\ÄñÍXÏåø©F)…ùÝHßÏtÇàÔñw«?èï?ÕØÛ ¨ˆD¦‹ÑödÇ):åNzÕ¹½/fùKÄÞŠPÍ ¿t†}+ùœ–Ò4EA+ð½_ƒý–aO:íÎ%øËlè¸ÉmÕœŽ%»UÆ$RDÅ»=àìEœ¯ë œ±˜§‰uLk:¯z[–Jh€»´)œÿ¹Mã…ÑUÌLë¯=í´Ãž¶ÞiŽIQ´Ñ'B…å§8á»ôä îcÕ$¼'oQ§nÚ¸+®#—Ù\9ó‡£8çê’zoG©[· ñŠ}YmÎO}âW‰¼ÿ[°Ê Nq«àÿ¸Og—º!˜†»Ö^Y«3Õ{Ë£@þ€iÍùaNmþÛ_Zsâ‘ 7G§- %’h‹ÓIÂË)wVh§/§›¯‘à#¨õ_ìÓœ^J4"¸ ÎÆeÏ­Qß1ÈWpÊ×ÕêÐRtH$øøooUŒïÛug}˜û›qø“ù:”¡õo©Ö¥ÕáæŒQ@h+ ÊFAµ14[™G{Ó®À5‰™r§í«"/›Pš]'7e]ŒsYˆðù\¼æáIöêlkm›k61×–{TN f”‹ú x¢Þ“mMÞ©T{hÜŒ ¨Oäÿ¶þžª¼?¹Ád¾/pw8Hd"ÉI%Tˆ‚ÚU »Fôc·™æ2 0ÁŽS¡®¦µõçYÒÈ™ÑF3ªYΛrû=Yß“FâÝG*%®b?›R[š´•™i¥qm†{í¯î$M{¹êr‰ìf)WÐkLáùóhØùÆ@FI > ä'‚šKn±?ÔDß´PÇÜ…Ë«dÇ0¿m.ƒ!¾d'aäÊr±ýÓ)–å ®ëˆZ~Þ_I¾¦rvi{”ÚáBäi ÝðÈbÊé<8´pµÏ‡ÏÿOO$£+µ¬l<%¶ëOÞhü.’MÔzw¢Èƒw|D˜%îÿNÙ%Dæ+&¥UÝ9¾OŒDå|ë rr]Y ÷YkË›ÂË€eÞ°C%ÛU™š ©¤ê¶e1?ÀRŸ^„2ªä5Ø0?Ÿ„@óJku»Dˆ é» GŸªŒp… âˆ9È sr1 ‚ ¬rt™@;¥áoý6ï^AM  F‚~»N½¸ÜjS­*§˜Âuð° çR_ÆHj ¨‘Ô Äý1±}á qaMVsâ=b ÂK|t~³Ekž­5=Ý«±tâī䬠lv¥»ÿ®4݇[Ê=‡›Yë;].`{TR2pŒø,^y¤~@Þ|¼²Ão–¡n)yÂÞU¤éSHÇ¡f1‹KÓ^‡97«Ž4¦zÇ1Tpå¶ýü%e£6 3«Â“é¦×0a@$¿sL‚eÅï¯ÄüîL_"yµ6'5`¡—lŒDSÉúsÑ'¯vF›ÔÓ}¢S6¼¶€þ'¥ÁLv›„¬Èm¼9¶ ±Ð«¸HéU–ŽøC;<¶.ê¡Ó."'HÖ%‡0Y­—þ?ŠèxÜ/€ð*Ú¡dгAàh*LØvó‹Fãïn@_Ž¥|9²÷ÍÒ Ïò4²š‹H‹Xº²^û»¿ˆ[Ïãå‡õ‚àG_`H0àñ 6­ü­·x³©æ{¨®÷Œ@2QF¨ž“ì‚‚ ö¶±=ó o+»˜R ‚¹gð¥{2Ð!–ðX“á¿#*•¥Úzp=WyýŒ1¢1?*/OâÌ ·þh¶œCy;õníÿà†35ä¥Ïu D’HWÆc(_Üxû+cáïcõPx´Æ^ÿÂClÞÅïp×”ü§-Dù<)!u‹€sð-B6/t42¤Æ~”Áëûû¨ýŸ§1ÿq{—Ã2›¦<9r…-Du’ ÎÀØw"ª¤YdX†iq„ýÁF†¥&Äž…çî«ë‹îV¯ƒ“…áI³#+–²p\÷ê)´… Ý^~¦x4È‘×9*‡ä ô®/dŠ„D$fù“âBw?Õ;f›ƒJتÎ|4ÎÜbR$À ÆÓN,ðð5|ÂKŽà+¼ŠÔ;’+KQÉã‚T‰Fhì)¢ãz6Lùeh耷\rþ\•‡{6Ý;Ýg«’€€Öãû­²Ó†ˆ ›’SD†¤é8¬CoëÔ¹œ»zÅÁbp=‰-Á?. ~Jé¨áv¨?UX—êÙu÷ì ·ç'q«e²­£r„ë,îV|¿èñTOT¾,er«?´Ž¿¾”ìe»Ùº£(Pª±añœ!Vj˜í3šXð‘ ºcÂ+Ø%ÛÌ*ÿÁíV(XUµ$O ÎÍëì„䉇Û`ÔNá«íÆÙª’G±}QŸæJŸWPõ6+Lk„4}²›“ƒ¢Ã\Î(¾ wg›å$_á=W¸Ë}eá’NØoð?kÀ3›Æ°œ¡büBtSÿ!÷÷ô‹q»/ê#AóiìùÝQk$Ø©îöÏL ”ÜzïÓ&r-ê'2ÔC6³jä¼ï»½ŸU(:£Ø6ØDGV!À{#vTÖöû¨¡`ê²Õ:ßs »¥Z5 ÆÌ»ž¯7%ÁÜ9¹%[Œ¹ºöÕRQpÍl‰D4Vë^ ±~¸_מóbqùôQî ®j’€€µRô¿>®Lùƒ’_¢›÷»8e0FÚß2)üJ§«¯7;$ôw:EöÐ*²—©Æ­  ~[’¥—ý¹Ì¡1AïÀÂt}}L¿èÑ2c²wø“ t z7d,§_ƺâinAí-0Çàî~ö™o Ó.á£x˙󾕔ûË)€ó±sSUÙ5§ø‰ 3,÷6‰Žt¾üWÿ(ëWnG_@§ö˜ÞkMöצÚÚÏ&îðR'X¬Tõ”aOò÷k:߆˜á<õ»Áþºf¶dŸòpÚNä¬ùáBÜ5\:PvöÆd®0ÝCtéH!zrW¿j´75Ðw t=S¡ JÎ.”£>+<2•mô’×tOX–òZÜÊ ~Áõç)f·ÍÊ»ÀŽÌ÷ è>zã R /úíAwŠ aÁ¨öMµŠ”DQ&s ¼Ç„#¤Ô‹üØÕø¢Zušæ¡JÍ[¶„a=>Mï¬2~Ikì9ßœ–™4ófË7p¬–ˆ;Aþ#³ °íé%#OHÝ<»0èØyå 윔>{±><¸£³¼3ÈÆ¢í99Ä_›-À`+þwI”??îXöã"(¶,*sÕfú"= çcu„®ïúÞ~TÃA³áÉÄv4IQŒ4󓼕¦¯½ELhÙoµÏ q/FøÍ ÚõT2ûú|i½šð[´™¥–:'¸£íÇãÌŽ!]ÑÛU^ÈlÌwÖ”b›q€]CŠk…ö§p¹A"&Õ7¹•x_ËÒXl©-94•Lx¹WÌÌðX^Îë øá¬Ò<ˆ„Qχ»‡?m<|éÊ.ýi˜ùûT%‡›²Ð’8¨ñº¯Þ÷cÁ/jñ• uca}+¸@4@¿”¨X*ë¤Ì?qŸÛõsÛiØ`V¯ë3nyÎÕ]Ëe5º~x c&§z‘ÄHômΓ‰•º¶)z1R¹« ‰?¾mBÇ÷¹š.fïǺ혈+ñ8 )˜L æMÄi³Sª÷òÀóÔžZáøåü«InPsªï•5 7c’€€Ø.‘Ñ×Bý(qן|òÖnoSÏBn„™™8X¥èË7^ÙÕ¾~mg3$Š——VÀ¬|¡È\µ(PY!„Ë‹‘y^VÜG7è­ÖJƒ=|ƒeåŒ$ºÄ½mÐB¤í¤Îu;•{`Ê÷$YÓð[øÜ›]>×þкpÛ£öŽÁØ ›K b[e@ªÅî+¯ `’ˆZmCÆË»…nÎèåæ™p5tfP÷’È/ü¿µI®Då:fM •Ö k`E#@"i§{‡»Åc”Ã}ŒT¥$DeUÐ'1Z^IÍîÛ–³«À¨)Õt [™U¶@ÑHCv„-ÎæúfÈíÅþ¿McY[½¹AG¡ÛuqÓ¢¸Mœ^;·igý­¹¸¶•`…y`%|bZâNž ×LO6”ÓüžñÑ ›4uĮ߇Xv> 'Ø4¸è®SŠtij­e˪XSËyálù³´^nZZE¹žÄ~ÙÅ"“ùsþ–ÄANš<”AüjXÓ—îvø4v⻆Wy·ÄP—+òe›ä¨iÎrA§ñg%¾F½”W1|,¨qÉ™wÓ¯f8ú¤ÁïÛÏþ ÜÈ€ÕLdþÚá$*rJÓñV™Ê]£ßëØ£¥gªžš¥àtGêC«,jt6dOÖ×ç â‰Û¨×IgrGM r+Ä6E.Þ).8UQ ýu»8‹iÞ3÷‹ó3×î鬗R)Îï¯ÌÅ›ÄJáÈgaZ›„TÍEø‘éÙ :ÊÄ‚Þë—ò±m Ã!PÆ: l°£Èj3¿Åyô/uváQt™ÛÏÙ¼z š%íÇ—îÜzzŸù+¼ús©…IÓÚbɬG ˆ¾$©‚íX¦jƒJŸS Î1Üó7©4€ZT<ëqËpá¯è«GóÂ/”±ã(˜‘OÈõ±ÀWöSg™ÃŽRP€ÈŽœÆ;bQ§9Ÿ äæþ¬Å ±v¦×¢‘S¾·0(ÏÞá†;’€€Ú…¤Mõ¥`9íéÓ„™ClÂwzi9ói…1î=…4MèÈfÒA4—åß¡.î¥)z¶Ó’–ú``ñu–ÙÐF]iƒ…Ÿ%™ËžmúŒg²ÒK‰’ñEJ—Z€Æ˜©xžHš~¡ˆÆ æ4§É 1ù„Œ±¿»å¾$®i«¼^s‡ÿ0M§œ°e`2õþ<`3‚Ÿ*-­³Uþˆ¬=m¯¤æ@ $T¼føah#ïOl+!Q¥ÿHïÅ!ýó²ªkÈsº©Kmk¬Œ"©Á ízN§Âä)7pª eLׇœq4n@BËFðÞØ‚Ëuç ¤ÿ]e\ BÛµ^ù—©.øNâÏ nfô€P¥v¨ê׿¹[ý™Rµ– Åì¬$;\¯ÃãÅÓej›W;û¯ÍØ—‰([Њ.ôÝ!%¯nÏNõ¹›°PD¦zˆ:ŠœÆIƃÅr+¬>ׄ/G²ï7m®ÍF(ö'$tÚúz`%IT‘‚‡A4©?M0[wòÙ÷—Í“¥k¼z¾ÇG§$HÔ»Ü1BÐ3"¸’A ä¿ÒŸ–Ù¤}íìˆ7ó®µêù„ã¥Oå×?÷q^VL…²ç§!VI¶äÆÍî—“«Ëç•V|…å[ 2—7ùwÝ4Làps«RXsùÉÆN ;%‹¼¬!°¬ÄeRB;®€ÇD‹xŸhÂz#òQÇ>Ôq_wõ‰\ ÞïÊØc¡\ˆ.5]=T!™ÆÒ¹ TY×—®ÿÚ¦&ìa¿ÛUµ}¡É†_¢NÔ¬Kr&à«„ÛÈó´Î²*ÁÅc–[¯wô7ªóà(ÚÈ{I,p…jVmeòV›²"r3óxå÷Êùçk3­`Ž£¼.Wï|˜³Ë¬µSNí&ñ‡×rÌx= ?=|ü7´{\M)Æé•¤Ø¡€+íAxNö2®c~ð¨’+ʇ_1!t®&Õ¯³r]¡ÇîžÁ §ql çq)¼¥ÿ×.;Jíhíæäÿ‡8-’T3ž@ÕxÐCòVéù.êàœ6ÈM Õ=Z3S†' |–âÐÝÂþÐg,Ã9©\tR`VØaw¢ U1{†U:ð¸Ïôi$}á½°Ó·9g>ν¥1ÓN¡KŸèŸàfFÂ[ ­l,²QVôs4®/yºxN»†¡`â¨k÷ÆÀâââV#zÁàäaʾéÐSNŽ70¦þµaè‹Ü€ùêMöØf5*š9 ‰d«õßíèÛUɪ[€¦sw¨QeøÓ•Äz÷=BMŒx;) *îWÜnsPNSghåýŒO·z)(’#F7šÌ.3ôP±E€u`Î2QDóà.v±¤°°*NŠßOIkåá-¡¸Ó#1šD›CØ· á µk`¥×T¬ÇB¾–™=ŒéhßE´ÆÏã$Xh6‡ƒlìZ|ÅGÃÌo¸îgl5Rœ<‘›„'ô¡ÖoÕN1¿Gã4ã‹L.CŠ×»U…ÍþÐÁ÷Q«IY¶4›\üœÀÚ*ïY$ ¾l²Ë1ZüU6Ö†ËÑ3Ké[UOVº1…À¡k¿>5¦DiðD%ŒÔ°‘F_¤OñË®tÖÓrlǪún?ÐÉÔJ=˜`Á@Íh¨³ü®!BšM'y|¿b›LmÆÉ+õ–)´utÄ9x^kä ̃lV aìr^Ó):ןÌ'#°Ë®¬ZʰÐ/öÖ!¼¶F&¶¯e센}“Û’'Övh2ÿÑ1Þv¢Ÿë×!êö4Juø ÕÖ@ÐÞ3<áü œYYÙ/¡º‹cÿ^ˆ’þT3M3Üw‡ÍÉÅÂçbØérÉ·Ø è-ãîJr™Å ™üÕR.v-›ëÍ…-‚+Èq#lÆÔPRk‰±œ1º4ë¯dßùM¶lÝßÓð“×Y·®ç-ùX—ÆÂÓS‚=þ>&:ကØk„¯Ñk,nÔdã»ëþGKˆu’€€ºfE¨úyó|'ïj‚IC¹Ý'ýÇí„Sb6èeFðZc-+Y|YƒÚš–À©q #º¡››IÊvzÔÜçCåš:°ˆÅZA(¥¾;W𓜻eá#/Ê ³¹µ ìå°pR0¦‰'âÏ옴{Õ‘Ml´îj°j€‹='P? T'Å:ý›£Â°üù@Â_{ßJÐ%Tc`€aʹŠê¯ïBýêî¤G„ðLZÕ2PKÏlFg­¡ê¹oOŸÓï×Þ$NÀ‚eJ¡O GôbjÈ‹ËÚϲɴ#ªþmd¦  ³Ï1íÚŸCûMõöÿ­Ü0LžëÉ›þƒüG_;˜cexé42𙎅GE«DÄ·äw4o€«¨–a©tQý$…¬ cŒ'*î껺˳S3G[sˆ¡¯#ßk‡¼#»ŠA÷„WÖpïêϺ¯1¼²|ï½m¸_të¢ål©ƒŽ¸͈kAб‡'iØ©¤³£¿/ïþŒOÀ8à†_5žùÊÅ_v7cÇÊÒ~ø¯ÀƒÁÇñ¨s¯²ŽUÀ½¤¡™Ë6ÓÊHíT÷h:&÷Š™q¸—Ì?)ÉøzYãrþŒ€‡‡Í–C6€-¹6)/òƽ+"¿´V4îÂ$„ìåb¥§¥¢©ûP’0•u»pjøÔûTpU×ÿe“8€–Œ3ƒÅåÏM¸¤ÅAèUB”d’ïBÁ´°JF_%[±—ð¸w.ìëb{À°.Ll…¯úÊóÏ®ç Ài3NQËïD©cî,(ãU3Äs¦jïÛÏ58ùŒR5r %_Ê)¢;ÃÙ(D‹µx:qëµÚ]ð¶u,T„M„Ø uDhÔ7—ùiÝÝ‚ƒ;ŠÅ‰ÞJþLrµs}§eÝÙ‘Å[ÅU¤õ‘ÆOýc ´ÙE MS›sK#.ùÞñ%ÛùÎ)~Ø31®Å,ÞfÌÙ®kÀLÁ¨.li2׍Р·ðÕĬPíB2ö·_×§îKo¾½I,n•Q/,‚$À²ÐZ…öÐ.™òŠžv〼sÙú¢ÆÑîsËr«f­QSDqb·±¡ý=UY=¹+¢‡Œ;þ‘ë’€€ÇôW­VR”twï.¬*)ì’¿Ø{f@Sï%Y÷JPŒ¤4cœ)wFå(õ¦£È &àÜ:‡G`’u˜BD©ñĦ&qÚ"Î$Ñ߀¦>Ô6¾‚”…zS!©tw>›[A'k‚GÀ¡Ù÷´­¬HèÅvH,eHÉyz-O9úœÔGë]‘lưTÐc÷®ç%G!,ÈßÚ…ÔÚ³9ùè*ò ¤4+:[º2Ť%wô?^ Ý*gÝguiJH¨Vâ)€;ºî:N˜,Î(^g0õ·î§ùGëÇo¯üp¦0ùŸÑeTw)s„‹Æò—ª[ûfÚ¿ì¾YdUDfi]+Nÿ7ó:Í[ôýÓd»î~ÒýXݘf ð%çªð¢¯*/T´HTä$¦oÖ>shÌ–'ù`¿ŠMzI?ª,·¯f€˜²Šm>q –ƒÏ><qÊÚiÎFëƒôµöù!^îbüÕ•–¢GwrC›¥ð‘£`zQ…<º© +­)1|hØó2ò ´RBce]Ôå{œú÷Ô/Ô»[Ï2s¸ ‰ßu…ú¡=EvÀî]rÇ;nýûÒ#Èp7 rΈZ)“¯.Í# hË <Ò%³ÖÂà§3¥ÿÌ‚D€²­wnXp8õ»Y(SZBXT˜õ<&AÌõ’2úë ñøL»ú„ê·Ø¾aŸªäTO€ž•7sÀY›çuA}ú2úFÿ‹i”á—í¯ƒcâAG]ÏÛçPSyN ޱ¹_!K1%nšKI"ç‘–ç¼µb(¹Ý%ò.ÇG ^.©R£¼½:ü¦€mò{E_:ÝíÚ ^ôh½wðª--ÇqìÚ¶'™²’K|0à!nòœuÆôÕU ñNO4Éø9¾^w±à8ʯ|ù”ß”{£_:‚Bìýeqå|ªµ‡+vØÌÙ‰ÒúyúˆGWîãoqÌŸs²qô^`XǾCõNTäRàùçòqÚÂu9¯€~ ºíû´c&F¹ Ã38§~œÐ§ˆIº@ΑÍcý¾`ñiæ¥:a˜b-cGH:•náæµQ’· wÑb9Yøg´Ì3[u´;‡ÚÖa±wróÆJLW-ýÚ^ý,5Ò¤”â×\áhÀî˜~ ªmÒ§ÓªCt-»5¨–ªhXׯ~ãz]™Z£ürf«©¼¤ÌÓŠ´ÉíQ¡f5ø {ÔÓëÖðŽ²ºŒÉwÕ·Ñ@=vú%xùHBMfF<´öªæpÃ%èÿãývæ¾ËDîkONÎæ¾ 1ÐZÕD4yÎã/Ôݦܛb^7߆ªŠÑO*v+ÕÀäZ7ÝÙɬôÊjä!Ãã@Ô]Æ&Q6–î+í ‹.¶žR¶¶úK?ÖÄv߯Ÿ–®ñ´{ý‘ b;û›#ƒ×crþGõ% (µ_L"ÉÙJ HñGD äP{ëß¼ƒÚ;õNõä­§À¶òË+ÁŠÓÎÚÒO~'s”RQ6¹îzUup‚§ˆo|»<5Š·ûþüƒ6LÙfKeƒyÿài|FÙÿ‘œ««¾ƒ¸«øí€1 r«]× #õȯ&Ž¡`¯îb*tœälóDÌOÍž‘ÚðÉv+Æê‚$‹›g,ðû¢¶bE|Sѧ¼’¿ý}d‹Š!u¶æˆ. 2xÇ ¶[º)—ðÝo;ÙVâZØÉ ì›»§ÿ?k"£—6tâgœrŠó 9«?ÂVüôþìpcÜ·÷{‰˜Ñq c.Ÿ¨59%‰.ïˆ3•\×HнY2"³vß œI˾ÿdÛH»4`ëöC†›§Œ/£8Ìv€:Ê^N*ŸM¨¹¨‹‡8oƒï¶šìñ:Ü&úÒÖyU°ò$€pE±⯰ŠK/°é.™yçØ€u<ƒøÃ}eL’€€·Èä/ømØKBÓ^A…&÷:nr£Ük)æ‘+àh>uëÈiß7‰[þ?v‹÷f PIaa'28HÓ1¼˜e±ðé_ùóÝs{zÕ„ñQqE’kd4€5 fYèH}¤ìõÞæ—¸†Uõ¾ˆÝŠ&Þ¹ùvú&µŠ˜F¢'aì‘èÀ ’£Ïn 1DªÊûe‰:Y®DÆi‚“HDÈ:Xü“QA,£Û]ÖsPúØŽ(£ˆš ¼¤”|Ç¥°?0/+Pßõh%3*#DðˆêO²´ñPÕÿR“ÇÇ”¸žöƒ´ÿeYÓmºäc\Y€Óʸ;îPr‹§‘ ®#«-6Ô³OˆU˜³héÂô3òäK z ežCÅwvΣ1ç+yŒP]Œ‘f¶Þ—B %Dÿ6ýŒ$=¿ˆ.1ŸºåÖCëøÐ“ó·ðÐ7¶Æ±aÁ+ØÑzÄpó”<.ÞËòj¹ GP^‹¹'¦ðu8÷÷µˆQ_ØÍ®b5+÷ç÷*ié‹mç'Ö—xtbÂL[Ž•¢²}O ðè¬ÍÙÛ8Ø­¬§.)…CÎÕ!ÅvNÇMƒî5Ÿ–h ¯ˆÄ&{·?˜\Jå/càO{û¶dbø`³g8ÎÕO¯/0@n6˜‚î~ÉvªrÕL/¢J‡æŽmP%QâÔB©ž›.`é¯F@BÆö-Ô”Œ‚z.}׿­§f(¤B¬vÀŽÚæ|ª¼¶žJúô¹uxåÉA@^î½Éø®EÀçifåsÔžÀ1:çÃ"ƒUtC^Í…ÚÈý°Ìûu_2 ¸ÄyÞÈbñÅ\‹Äzçœ_¿•=G´åeÏ,/ùç‡Ø4^×j" ö$¹ ‚6”SÈz´ç…ÖRf’Ën4¡`›‡&@&Ú´"¬±Þ;0*¨<¢²u»ÿ•IÜEhŠ%L“ÜÄ—Ân§Åû@=(ùüÜ/Ãí£[r{OãȉxoC·ã™U.LÁ¨O­-4GV)oÚÁ’%Jf7FB… §m±ä#ó§”LiUïŽ Ž,·éjœmÿ5Í©'­{ñÆ\?Øõg¥àºƒ`£¸£nE¡÷@ãV(d¤„!e¯€ãh¦HÃ{Û™äkŽõþ ”Ñ•5ïâ–t_ÁiBb6€f2LÿôvZ¼“žÑÎR†ñŒíš’€€Ñ¾ìÍ ö°«Ã0âG!b T”ߥhz;QwPP¢Ã ¿…ßßv‚luôÂ}ôPpmúsy”{´xXr– ø 8¢²koÖ“ÒÔ¾·ÂŽ~QCé[-q[{|)`treò¦nlÓÞ‡šù›ûoÅ2_¯Ùèp@²©6ƒ`°Òë½³ôìß#bž8 0×èvož!f—MÑê¶/Sn·½úzsS jóÏàHÓ`½†Hಗ„r›¿Æà ”8w˜ŠÝ)°påàØr,ÓÑzÿDÉ|…"||x¹_Úß¡°Ò§Ÿžg.Ì«S •ˆøã§ˆ 4â=IÙ åþÀ„èPÕa9†õ*_X«û|°ìe:ù'ªÐ­·þFÇèž“j9ÀK°6Ç9–;¥û¬­Ý®Ì‰ß8—'––²ÊJ®ýƒl…ÃcQX¨B ù̓ÿöø;2ÜÙ£Gé‹ÄÁ™ÌÉúµÕöïpÛû|ƒÌ™ó™ü;Ä¡‘Ô(ÉŠYR¢hXûعo”ª7 ¿aŠ'P¯qTÞï¥R؉tü k9&¦òÑëÏ¥°òOâ´õ•÷^îÂ{Ñ{»åw©ÉOâϪۤÈ-Xy4…ñÎ7mEÐ:€ ¾ëʱQ!¶ÄÅã&bI“"îTš)ÔWhÛ¶Lôbù¼U”È›HÍ-Kw\å_˜7‹ûôáSþ¬ „ÙÍL}–¹Ø©½ªö§ …Îg ©Ë¤mâ 7‹’˜“HRñXcž=ÔÙcÛ”àqƒzu6™ïåÓè¿ÂdÌ4­­xª´½;ýg‹…÷âwÀ§3¿\–Q­ŽDâ.®7PœÜ¦t9«ê¯¨l *eŽœ·Ú–ÅÈ"ë݇8Í“‚¢Æ£ût=}G/ž\aÛÜ‹­¸úT.Oºô™œgNj®ŠÂpB¯ —þÀņ1.ä—ik‡Ñ¢[Þ/ œb|U¹õÛjˆ²2yCe§øÜ å‡à#y7“/ûð¬£ýÁ%¬˜z4ly,¬ù ñ² Ó;OÕÿ/(ø¼¶ú¿lÌÝѵԮt æj$ß­-„^­poæØšd y”–é‰ZŽ[…xw©›K%B' véSDO¥FcŒ¥õ* ú |Ìñ³€IX&O3 Îû9Ñmö²8 v‹9%ÇÕÅt:Èÿ5áŸúíÂå›¶$¹ƒý¢ÔJíÌviú„gÊ·èøÈÄ hñReºÆÍ©¸uƒÁ°¦ê½}A:‚;ÔȸKpó“Àj²`½^wÌÒë²'¡öÂÕk*ƒö †´¿Åà 2”Eç¿)¹Œfr0Ъ&¾üsÀkûQ¾*^gØ£TÆüÊ®ùV]r÷Ý$ƒCÐõ7‹©mS“ãŸþG¼õ"¡2’(‹á” Y¬Ž­EI» èë†>í½w*–U_‚Wºx ËÊƳ‹vqá6n€l)Ö¦ÊEÅ÷)HŠÍ1ë…˜# Ù$¬ù‡œø NçpôŠÓйO m\ȼ»ƒ‚Ò8–ƒ£bÊHæÄÚ!³L~ÌÂ.³ê }Ÿm¶£ã¨(«ªè‡Ze/—˜pÕ®#Ð-Ðç-D´’F‘{±eêgh]|÷Íœ¾+N€ç12"ÕåÄØBŽ™š¯Mq.J°ËÄ£M!éí©Áµúü]©oÀE¼L|qS«~åšÙÂ[² àª®VÝSö‘5ðˆ§¢‹Ë‘ˆ?—å—ƒ•–·Çm/Óˆ!Õ6Ôœ,¾”éÝ_ÒTb³·Çâ^RÕÒʪ\™T/WÛïSˆc>¯>ÃRÞYP ét/,ÞI»æYàò2™!¿áM;Gñ ƒ¥*˜•ñ¼©Æ‡.À/=ÖYQs@t±Ô”~Ó£eZJnÚ-¤ÕY”‹£y«öšbÄ„F¡³Ž0gÞqq¦>Ê™•`Œ/— ô(ûÈ ÀbÆëX¸ðÒ  ƒ›êÔílr2îÎùâØñ# ò®Î q >Äø¿›ë¿œÔl>™ùót9Hg'¿|¡·Ö¿ € rùoïcü@’€€ÌE‹ ØZÓé~`vË*¢ð;$¨t9)ß_— óË–”ç¾¶àl'¤¿ÙÔPÉ2¼›Ç^~¸Z¡¢SØ hŠ™ÊA¯S˜I*¨ƒº¶-á óì»iY±KÎG{¥’dpLÅêæÎ6n*t§´tÜmìEêoEÉLÎྋ ”°ûàô,NøåÅñ5åË8LdñÛ[­Ò/W¬ÍA÷%ˆÞnž Ñï[ 5‘{¸ˆÀ‰CÄ­ýWÝ °.Ò®‚5ˆ êr\Oé¯nÏK:Qsd—È«¾¾éâ…ä„\j{špVê–x4·Šýµ³¡Ãi¦2 ‹–ÿe ãã|N‹(#”]37•ùt’Ü7±rðº9³“/`únÑv¤/Có+ç]÷Ú%²ÅœS]$öàZyªUØ {c<;*ÆÔ5±Ë¾°9íëÄ+á!ÿ3ă­Ë¨ˆ‘RÖŠEáCÇi1ûÀ÷E“L¶^ºS(†•5‰iÚ[KƒÑÄ­@ÔÛ ÷ÃÏ‘D$Ó(s7Ï›T¼"þ„BºõüOË+zçYö§7åhRʬq¨Š*ÓÔÓ½¦™)³ûh5Äh,©/1&|]Wû´Тə¡y™9WI5$2LHàn CâI“š§†öª!&W›ø1ZB8H$è›hÁ ýBhOí0]¯QOVïC·ÑùhºÛI;sÙeqIC¦ —-á5’ÖNÓ~‰É4ÃÙ¾(oT1zù*HÊê¤ú;?òµ¿-D¯,%í²:§”ãÛé'PôÝ·×Òrw:“[à´¬³ÛEÖ‰˜(³0ÓbÛnÉ„$kÚÁÌOEøa ¨et7dÿu.g`XÒÑÑ«tŸ¨p§· ˆë7b1ÎÉaH2¬  ~²ÇξœMæêW[ˆ×—i†D¡qÐŒs;¤[6Õ<2cÓ&ÕPò Èd¬þyUIg6y3Z~¨ïµrb¯e* xËöµd³“ÓÚ’7/ "êŸá‚ôúà3’)ÌS)›áWµ$:ò>e’[éö7YJŒ©Žh5!ì÷ËîÔãS±4OF`Ù‘¨Xa– J×ÃCŽt­Ã¡c›z£—d”\&ïX¸Ú‘ÃìºQ€œ¤°xZh y‘²>{×ì§ܸxjí¾ ªjW•ÖC¿í Ÿ±q™”ö¨×äÅ]Ôóù’€€Ã£ï«1º\<¢÷.ÔâjŽ.‘ '2h©ÚA`¬j”Æf“>ísÌCØíG|y!ÐÃÞ%cñþÊõM† ‚ÁY|ÄB>Š?CH}`èÉbI6â«pP|ª;¯6‹o>¶sŠ®ű+‚A§{n.„Ä/bK°O«`.Wèùê´U5mUoDüã<“ñj·y™Šw/—¤lÌ|vF\6&ßíÔÉaM6Ó…ONýÏ@EAœÚÂDuŸŸ Vöïù2Øÿ yΔxM£œTyëSÝó]XÒ5…ón"µŸ÷úˆ`KÀþËÚÕÎ"—G„̪‡¡›Ð'*‡¡Ž`óϽûÈû½¨ã×XQë›…~q÷‘gƒãÂéé^™ýTh°©¡³JIlvµ™åŒme¯Õ sr.ÀH}yW&ý»¯7*ô —ƒ¸öžP\Å9W½GSMÊ™†‰ÔÞ,ýu}Ìu¿΂6ùaw½üǪú‰;ªÇ5{–šÌmkÀsÚœéJ‡ô*;9GŒ—uÖ¶LÚš «@ÉB&ÅúˆÇ`w)’û0^ ðCºtö÷ef>p|ûBé)t[ó×[ôÞéÄ>áz’¸`dA˜2¥ZžÙÃl»ÙL¿½Ÿ3k{¶¤\„páê¿l$„QïÐhަ³0æ}³/¥¿°ŒŽÎrÖÇÅ7pTñÆzPn:9j:Þë²Å ‚èoIîÿS¶ØÑV£CÒHb€Ô€Æèì37ڢʓÛä“–³ã8ʨepnÚ•2yWV¿8'%X ú­-Úž|š ³Ñ“ô®o§ E­L®¤U©ÐØGb/àIŸ0J‘jiØÈ}ø`\Õ$H„Êaxù7™SbË{7&ïåg:öX xž]CB”¨¨Þ\QóÞò'HŽ$N+º{Eúþµ ’ 1b™up8Ù¨ÌV+¡§¬º÷mj—ŠÁïÇ®<ì ›9‘ïE¬Ñ}ý5Žíîù‰/ðúWü@…3S¢îk•yÔÝÿ ¢äÒ´êЕ£Ê=shÝ¥YKõÚlÎÏ©GäŸ8°æ ”sž è M©Å4]ê;S4ZÓ„%æ“\_[ÁѼµ7êìM ‹îO4i€Å³™!qÐ Y°@QþòßW¯˜ã’€€³þ½“¨#=Ó&6¬/›á½­vâD-ø1„šs™¼OuÅø°Ý%ÿÊIàª/$äžú9sÒsðÂÉ“‹c[x”fw„\¹ú] è¬ÞøÅ¨ /åéþ¿áëÏiI™19Ø24,Lù-×EåÓD ½!¶ ŸãÖZ§×uàÕR$JýŸ%nZf›ó2¹þã.#!"ýêˆcSÅÉ2èé ƒêß:¥…ѹöïpžlQê“ÐâïöW‡i†Zyg‘V¡Y@ƒ/#Öö XbCï_mÿÂ/L$ 볋ÿ㋳ZNý ¦|ÙVM"B‰êò{¡T(޹6÷ ›N[wGW.©qçÐ…¬¯9‘©É±¡:åéOÃÒuvi#„?<ü/Êõ[- !v“‘:ì£fÅ’Kªî‹ÝÙ[ BBÐÉË„×P] Å-0ùzoÓÀÔ’š+J·Ãl–ðÁa»­×RÎT•„õäãï]Êâ[©höÖI€Éõ‰Ë×慎º‹:n$)Eé¼öb#h¬©ûjüTéñ>g¯K :§Ö·‹¯æã˜Îïú ÜfËÂèÔ×õq ÀàÚáš’%l=A-OTéÇ2ÁðôµÔs³±Üìhµg®îâD¾F¨Ì3ëK:®”i`K²9½}N W!àŠi ‚zïÀ€B¾ÝehlG•=÷þ–®›µ?Ήù¢qœÓÞ»A|]>^V“Ó|•«¸3/ù7ÖDÁpðÊuÚ,BñÂùœWìæAWàX¡¾àŠ[>&ofÝàÖÇqèe¤KºJèÇ>ÍÒ}Ió+p3º%_­é ûÚô7‰bÚ’€€¾M‚gƒ¢ ”Š(¬ôþZßt)rêÁä¼¹ƒ®¾óX¹kKzt¨w•ò2|½ùð'SGà.•Xjj‚iÉ) á®Ëp%;»NTˆ’ëÕG¹µÌË·g…ÎPèT-aûÜÚ 9î;*0˯¨‚•r´a¼&®”:Ë£’Žtxp0̰µ.6ùNð.¥)ôûa‹üç"·ÅßdòÍÍÚ.riµ§j¶KTAGņ‘¾yÑÑúY®=Gö&!Þ`Œ¯†”2T,Ò¯Gèî:pû¤ÚTzizý‰íåØS%h€žÝ´|¾€:YƽDEƒYÔÃmœLɰàð¶D¢½3 7Ç ‹f§É£µÝ ”ž«¹(¾>f1¶k)ÿõ»“×’Ê™é8#‘?Êt'Ò¶'ùù˜•?•’K´Âc ºbX EM?,G…ò@þ!VàÒO(öÕa—Õª‚9‚‹ .¬$ ÏQ*¿á÷]-òZF8…DÛ/Âl­q:‹š7ú´ æ/†ÛY󔤶$»IÑ$Qý}ÀU¶¹iJÏ.Ó‰¡Áæ3=嬖ƒë.x\Jw³ó$ ¥5†×ŽsË‘lTÈä4e×v‚×N=aV”l‰‘BòèÙ-%°3b®!BJ`ÑòTõªÆ¼\\ ) \¿PC哜ñ¾Ü‰³r¸ý6°¯×o`¼r5ÚüÛ*LWÀ|Z³Êœ}) ƒZáæ5ʦ¶)ÇÎSÞ4Š}´£G>%´‹§AÅ ÎtÖ=/J×WhLid[èáTNLÒJFâ?‰®2o½uWbOAº63M`\‡YùŽOm®1½ODÿÔ4µ%ýÃøgÊ› ƧÜÑ;Qqç}}¨p†¸ôáaĦ—‡^tÚb±ý‡y<õŽA È4j®çž$ÿp±xŒ žë“3nL§;E Uþ£dø<ÔÛÖCU ÞÏ5Ç<0ó1´‡û«quúüf­=tì3ÔÈ \†@„iƒ›‡ÿ0‹©q¯fÄ!ñš„nKä'²¢ KýZüÏ8†‡x41^AJ-ÞWÎ}½4ž¨½“Þo£jB®è`Ê|}OcC_YÅ™qHz“$­LÝ÷ò÷*˜…°£nÃK“êøgJÌAG­6Læ•©%y1ó¿)¬V`¥­”0’€€—gÔRNfšÒÌ´Åâþ1Ô©®‘>Ièó²À‰Ž‡‹ÄˆÊYÂí¶Hd#ç¢B=£ ÏÌJôå]=4b?Ñ¥éîO|K¾Ïÿ`”p0€¾^ eýH{ß;{¥+#Ò±àÄá:[?|a™fHÁ×émW’4‹´E`xé˜þ„n·Äöœ¸‚*•ÙårHø¾\p§á#öV»ž„5|åÄS!ƒl«vöýõïj®xX0MójÌÔ… ;ÄqÑiÊÀÞ>«,^¤$AB¯ÆM¼AúªëC³¤ûÀs« ÖS,±=ðR©ÁÞ†Ó˜8‰ÞP´Aa]Ñxµy ˆE~‚ ñÒ˜jk(´¶dœ©¶z/RÞtiQ¿:¥Á¶þ@:£r4 öˆ30¨ÀXªKT7æáñÔáÛŠ¿Åñ bäŽ×À¸‰R˜~ÿù;ù´`TÈ#µØãÎüçÖHn„ 2̳ẠƒÕØ”înÓÙ—–±M+F|@“¸B«öA¥wŒ¡L7 ²º™."–úW— nÅq±,e?¨ƒ ‰Ã²¸ùÈU&¸‘«”ðÆ/„Þ¿Æã'º«pƒÎe¡5P§xLp‹‘-]¼”X¨ë®„¸±³«D•`Õ–Še-õn¶­ï£h+Üdä#^Å„HZnÄ—°6Ǭ!à-Ú}ûVÄõÔa1CqM$,@¤ç+ìû{D1 :L53  o›ðƒŸ]3þ Dˆµö¢u‹Ê®Mzʯ2¸è|9F8Œî±$´m%rFX[ý\ô Örd½ ²ÍÜè…Å …W¥½á.·ÄS(¶¶³þ“b‡<=Žg7T ÛŒ¶-!e#§ Có¬Ü—ø>ŒvÓ ·W—º}%Eà!°Àè`‰“_Æç+a€G¢úÿï²Zà=²ÐÕºÖ¹D3»Œ!ú0T°„œž€®Ç̲—Llµ‘­ê|¡»¯ý¸e‚µ•Ž}[ÌhÞkV1>¹yæÊcîm¾>ëÃã=ª– ñü¥Ã˜g’€€Êï¸ÈOœ”±·¬¿5ø{~Ò¹ñänÒ*YTŸ—£ïLY¸‹Àš_wBÜÞÂc ðª-9-‚„w4L»@ØÊvÍO2ðÐ`/j»£o¿‹;§ºÈ¨^ÛÉ”…+ÑèϘtúW™š…r©Æ5Ífç‘(ïu³äÏ‹‚Ì7{( #/a*${ÉGêÓRŽ£xæ}ÉÛðæ©wÈ\ ¾ŒOš^Ó¦ |ÒÌs×™Våœìû'ìµ–N*$ëÌåŒ|ºò{ÊG›þCI¥WŸB!¦vþMSÚUõŸÁ±öðîŽMr%vâ ›Eó6{uæƒVÖ®Zï&ÃçÈQ¬ŒNXppg;˜è%šv´ÞÈÓéü pÀ™:µl¯CCÑ4¹þ²´FùÃ`â§0qM >5“px¡RÔ „göŠ>U¤.wщ tJƒ“ìö¦¶3å,äÒö²ÍZÖ$ ÉÀò;K+nòù!%‘÷å /R–- dòq©#­Û]úK•îSgªµT(ø¾Šz‡æ©d­<%ýÓȾáçØô](³T‡ÓñÿÚ΂,èsÂ}³FeWÆÀÇ›–1qßE‹å½(E>,† ÆdôïÆLæ)œª¥ñI\t®GVík GsQk¹p®äì·ùê\ç©«Ö¢u€ïe:Š6†9Ä,2µN¦f¶T,ÄKuXâ°X­ ¤ çÁŒ÷¶S/2ÆòÜxr:ò­ ÜîÜ&-™~Os°ý̓ ò­ªçTò»®þ<äPhÓÕþFµnÿÁNÁŸÙúî AÉµÈæ¼@ €x”²¥Ra0A!l¯ñfD DwÙGñæô:£§&çÄz䟔lí‹‹µÒ´ÚKâáß~Œ#{'™g=߽˦r)°F·“‡ z löü™¼ò¿˜ÝHÐ2®ÊC¸ªº“† I:úª¦[ųùkIðÞzÍi¢nEŠ}Gj¦Ù«v×ÈD„=w‹ùö2mû`Øã’ æ }•¼tô–ñ§io¹V§ý.ÿ[|Ÿ®5*¾_ãIiÄò'ªÙªdÊk êMÒ¸ù¥°]ÄÚÀÍó ¿˜ï1¶Û.Ä(0OQ•)¾}FÓÂ, ð†ˆMVó"Jvt9´dUAY€ymȬ5vÆnØF¤÷Ä6´Þ6ü’v•[8ä¼YR°ô’€€ÉtM¾YDÝqmÆØÝP^»X"쇨’׆S píb¡#ÄTEBÒ+îÛgîJtÚ#"©Ò¨Â9˜›Ìñ×dcþÆf<»î"ÓÃ9›Ê˜“#•,ÐF»"²°ëeð¨{æMûÇ×Tÿ§ HŸ=Aøµ¦yÌYú¾é§2¥2Zv ‘ò½¿æé(Œ7¥ÏÁñ=ÛˆíÔc¤°¨lÿ©êG¹ŸÖÖ8 ÿR¬Á€XIcå×<‹ÜÐ…ŒǽdK]þF:àÆ·Sçý£.@stÔ¿²¸ÞP‰Æz¦ÕØÒ,ÕO¨F¸U•’§ÃpOûfÅ€ò¶†þÑ Ci¨u|€XÆTŒ@™¿@’]>6)LF*\¹¢Ä[‹ØUš$ý$ž¥OD.lU£¿:zoeÛlaCÈûµ‰Ïtá÷G¤Íç®÷aãÏTA<Ònþõ'æ±,{‹ã1 ÊÎ…ÖФïófïžCàŒ‘Óªé@L†à»1¸íLï—æDŒ´Éˆ*1§:äü›)¿ô­w&‚ ˆ²u7ÙÁÁ) —…E&gaÎÅÓeÎà]ÿxû¹s gí4¼øÔ¹ðÔR,óÓDžm‹!3¹´ª%dýgûU܄֯·}`U ” 1ÄOvF¢ê Ò,TH(?;™þßz©íMÜí/ª~øœWRŠUU¿8£•€­O±*Ù•™1y@?ý¸Ø»3™þ¥iBœKU?î½éY„×vkŸzQ32R^{øŠm©˜XVn‚îýáÎsX‡!.›æãÜæ!ã³ Û„¬®>Å?¬ž&‡8so°áv÷W~ž$×áªö—ÙSd’ü¶ãb$2â Ãï²?³,½ÛœæÁ2~gÆ[ÑóÒ›A?ІY6uQ ªX•UÿÓŸhY㙿•ÆwµîTò»¬è"ØÏ\!ÇØL]<ûˆ$ V„‘JØó?D ÊR(9Ý,Ù“}YáÀ-dIЀ,c»»Žu‡”®{º’ÓžºTÿ1û£áN•7üëÞ‹.e¨›‰À Üz”§!aÞ~AÎ>¼þÌZÏó¯Âr÷ÅJ4•UÆVØñjòSVÞx c(NÎååú¨;m‘\£zÛŠÁ7£qöý±Ø¸Y`oº›Ix%Ÿ¾\€žxØãÅ™c¼Á:´Œe-vW‹ò’€€ÃjF –±zÇmÖ¢žè†AnÖ(7D¬àP]âAOt/˜Õq*­ëBŒMD>*E)_Ó³!¥&BÛoKÚíZûÏ,ª…:^EBŸÖoŠî7þ˰c`$¿aÀo]ýNÆ6!ÑØC¨„Òr¼_@‹ö¨,ú%øáu5a+ð#^OBÞKva(¹zW| ç°q˜±¹ú^´ž`~:’#¦ Í߀=5èÇUÿF¬9EW.Už H 2·Ó¼ÅÕ|o} »Xgóʲ¡8þeØ£«ö¹›Ÿ°v‰ LæwBÖ$ù ~Éän³Ÿæl0Ab ޱe޳™]ªÌ‚f]x$6eÂè¡â׸ŠnŠ/.LãŽÈòƒ‹,¥¦ÝƦºH´ŒµvAÍ-ä`â(ô}ÏiÐNûÙ¬?– ¬RĆᢋÄ2€…ì{0ÿJŠr¾“V`„оcûç¦ïNáPó´|–J¥ nm¾ûB»> u2ÀmÅ?PvG[ޕ󿖨X”•ªqŒþ·Í¡ìFµ¡ùf…ADqî¡®–•™<¸Dx³Ê8V¨.Ù÷À†7›Îd§dÆv¡'´/=VÝH‰ŒC'÷¾<°U]i·3aßé#¦Æíg+iañ1mp'TO8¬Hó,r+bÓÖUËM+n]$:Ïe‡ ûùÍDEÕ<û[!a8Ó‰"T1yáw?*âjŠ»µQ§þväGÔ—š¢oåÛ$ÕÊ»Éëµ[þŒ^ÂŒd¸8=¾£Hž6ü]¬^ñ<„ó"w¼{-—Ë£×ú‹ P%îÁq£>쳈’p4¯€~íÔ¼ ¿ÈBØøÇU2ò ë>ùR°þ T•S5ü)Û ¡¼a¦­ù"çn®¯Nv0òÞ›¶ÏÖáVçþÕyì¥ Î­aëí«QNÖpy¨~Bä w*‰F¯Ávšgš-³š ÂSsG†Yêsûñú)bÌߎIíj|ßjŒ4xHmèРކ®…/a…ٵʈ¥¡Š.P„ôARÝÜ¥¼„Ú‘j7~¿5ÕÑÊ9™,6ó’€€¸@ÅÖ€T÷1ç±B|©OXÁùš vKƒõ5•ĨƒÒ†»_{éœß¶Oìï͘Êé}h >ÿ—ïqjþvM³É»vVm_³P â’èûvÉã>aÊÀž?ò¬ŸUÆ8‡)ߎ‰i•÷|[ü3éîC[x1¥“m,Ø@Ÿñ°§(PxëÂÄ×± I6ƒðYOy´Vã]è)~çJE¦2¬Sõ¬+«ÅȪÎëFR—u‘î좱Y·¯W—ÔÔ†á>nÒ…^˜8ô‹m9µPç©Ëj"³´–hˆê‘d>À-÷þ©†bgÒÄâ¿”‰J Öˆ€›½'4ٷ÷-Fl+#ñZÂ|!gX `‹:èÝö1vžd.åÀxúc`àÜ™ŠP9Ìþ…°º#¨Ì23´”Yðpä‘X0®œ ‰*¿ˆU¾cß[NIÛ5³ýÐ"ÈPŸ)¼¨IW8å4hOkW·êuM „]kÏN'?šÖè2XJÉR2Þlj­ <ÓaÎAþí%‘ìÀw%9€u¾å´NÄ~~µR ,§GBy9\q1‡ 3 TN;=/> ö³òÿ¤(•ªÊ‘ÃÍŸ…¬­üoÊí“ËbF“F;UC€Îç\hscæ„©Èž @³);N¬@­ã Û»Ö“ãþ¨n|ð²<™Ù9"2ýÉ`Š&gRTHØÕÂÐ3I늉ª)rQ•F$ ÞpÖ Ða‘ó-šœ¢íD‚^[É}Ïž‰Ç>\ypºÒÊ~BZ6_Àßšqˆ½˜ ýA.°{;ÕàîE Ýá„mÚçp™‚f׌ˆ\lÎÖ‡Q§ÈÎ⥚°þ'KÚïñmrƒþ5·GËxÉÅóÌ‘,·Z€Ò53ûm W{ ±±K´Ê&(Mcwq&µ9éÊE½å^8qän f°ð¶léq€/Kõ¿V¸ˆÛüìJ›2>=±'êÃr×ÙH–ÞÖè|™²ºj:×’s!aï1xsYû"^SfY}´ÆÔXi÷v6ê¹<¤7fº^ÙãxmµíÛ[b„‹v„_„Œ}̲:J…zâ‘]y»ÿdÎH×¾>±õ˜ZS¸º)×¹B¿ÓcÃàµ]Vrºf™»Ô3›Þ‹~¶\õç'í>rì¬W( [ŸÜÞ”óyj †ùs¼í¯îf“ß§ýe•}wøxc>Ú æL>ß;îq‚…Ûœ!³ÆºZ(Qq‰ Q,†ÀÝ­V>¸*©3ÕN Þ2ß•N‡E’V îR[@'êë ôÖiª±¾áÇìCëÖx¢>¬nq]Þøü˜jTBÂÓ13]3€1Oüþþ†§þÕ NüÂÝnÀœnß#ïr¦¹‹€y¥( Ç5RUæÂdQ>T®¥aé?4É2”¨õŸ×µ-<ôÔñÊ=œu¾h=n~Æ>I%ÀaK#? ·¸¼´­ÚÞçé ßÚKKjÜ¡–$@§# &ªy„YÞ!ªwËCÏn3ÈGC®<ßY?#^Áà›ß×8Eô À\d'Å—ígJz '®yil©Z”ÖôAŽQvû$࢘*M¤Èè~ìû-²’? @3-ç«™4µò㜻áhZ;GH`B|‘%>ÌçW2§ák'fb& ¸…Ô”×r›™¿%¢xŸÐ»ú/A\öþD¦ë\W˜·K›wgÉ9óÈ&ªLDG¿MM(,¼fú WeǼýhj˜ÜØS¬x4pf"[ÄøIoÙ‘oSùÚÏþýL–¼^=<Ÿ„îP¨U†{éQÜvóá~?‘õ)ÅÍöîBò;ž $¾Å‡Åü ‘(t#UÌ Ñ¿¦Wò‡¥Ôà½æï‡nCž*nŒGíŒ^°I{ƶãT˜åxQé´ý<÷œ̾ÜQ…²»›-Ȱ¢Òý5”ž)uEøo«WqVF?®ùI6TÏžŒ> ð’wÀˆ "‰£]£¸U¥ÍGª3óIþiøÁUÖÍtR’èƒHõtÙb“"‰ï…)x*øþ(w}* {º&¥ê׌š¯uWiD6ÊEž'£yÅÖ}‰#µrÔÜ^ÞªšÇC;ª»7—þc{zZ0æq†êü•—¦ª¡1¶Æ-L4²Ñ!, áH'3E’þ€¸·PèÐT!0K~Efc—\?Ð'[»éjÕ³®cáÁhºe³ëꯩ„^’€€¾)G‹›ŸÀBâÓñÂÏ9b» â‡ à‘–ü|ÀúòâÆYØhã|´˵0^4ÛŠ± ¥Ì{Ù/m9vÓ¢lS”Ã\üÎÁQ`HþΪûÏÅ”À눗 ms¤Tð%/Õ •XÆáÉóÑ|’¾ÍÎù³–oä ­bdùÂ1«ÄU— ìofO”×9@‡ÓM…„L=)sÚ!ypU¢óM€X‚~{^uŸ"ža„mºIÿÁ˜Î¿h:a666ðíäêgHø$â‰NN Í3ÜΡÏã±;K3o•Ý$½_<°–z=R¦µ·`ˆÅ.kfRrÂØ>Á¿q‚×X ²VAƒ“ܨ¸Õ~.¶<ÀOTq&=oTrCìc›E®÷ïz¸°í«¨O^eKíj¨"oÚqøÇvÙ2“#G9!~w¯!k°,§ÓžsH‡™â›¡y_@#XI;ÌL÷{yfïqv¿ñ¹|•åúSEwx ¤re¼ 9 ÆgKHMÑMXÜœöV¸ªÎš÷zÇÐ…f ƧqRЕ¨¶–^Ëc1‘3¦xxCT?X…LdSïìš›Ng0ÕøÏN6CuB$xL8s’8 `œ·ëÀì¬ ˆT2kŒñdíÍFIZXázF'_²³ŸÐ®Ü ã(Cé¾K˜åøòŒÕŒ#ÿ ¤sÜBjÚer¦¬'  e"rJ8TNØgÊyËÎ=‘4"«ûþÃôŒßjI ]xMÓÃ<‘á¬ÚWñܽ8)kªH©}ˆ’í´Ÿi=eãüôŸ¸ePw¾¦wîBßu—‰Òß ›Q2†6Ù]=IÖNA¢Œhí±æ‚/±ç’$v€–’³Èݵé5{‡ôÃ@øë/Ú•,>1q¢Ø\ ÒOK7ýt‚qÖÍ‚:æÙý ®3 ÷Œ'~]Ú4‚"D€¦3@•ÔýÎ#2÷3‘‚ÍGG;®Ò*f5…¢qÄȂի§H1ù(Ö!_|ÁXÌÛ „¥bÊïV¶ÄgÒ5=±«$‡$[èñ‹»Žê3jüÕ[t†¨ÕpÓ £î¡”|&â*~ˆHoS»K1^°à«âÞ†ÔV«RUà õ/jå¿Tª>éøá¶º2ƒÇÄàÌüdn±os å1µ}JUý]žîÖ«,¦š=’€€­•ØLÎeYæ%½=3ÛÍ8ðÙ¥KÌesÉU+mõÜî-Ú®àCßLzü «tÙpø‡ÐB~Ç,g³dµž)Œ Tš£â¸;ÉåKHh[ãW‹Žžý!N­k‰‘Ë3öz üÝGW‚lÙ5ýº ÛÔÇNeÁÐQz9ÉíƒE¶ÚT«ï]9±˜ÊÄ›f]aD9¼¦Dåw‡Í¼Ôg‡û¼AGܨÑ}µn´ÆûK¦‹[H¸üèWYæ„án騈÷y \ÐO?Ǧºñ‰È¾TÈ·NÐ;ª–×Gì¯Ðì Æ–{ÝA¬j&šr6ü“‰5£›GGffùµõ1¸fÓKƒ<äÙ~¥ 8i³;=ðC¼ßû$$o ëRt÷Û ­ª¢ëÓ ‘ìE<ºK¦õ¢LdmZ•ŠEÃê툔ž…БQ£#¥Š(°t¼~³ýk& ç$S›ÁKc[ Ñä›\QÇUf ø”Ÿ„¶íì~,"ë"ªÙºcrfc—c¨90þ(õ8€wÀ®¾uþTUÚ›r÷1÷~Š5@¦äžÙãFøÐQäÖ,–ļm.NøÅ©ÿ¼IU)±•›Î‰¸~ ¯¬ Šë:SY³Úºx=Œ¢8vš{!6¼]ýùa–ég Ö8·ÄŠIDŸ/D õó¦^„2gâš?*Júùd.±wíƒmˆkØ“9ÒÝk¬Û¦©Ió^Ö„¯±Ÿ^Ѱh@×8æ¦v9LJåѕР¢Vó¢àjÙ? ÓÐj°B‚wŠìÈÃn»¡õôíCowÉ%ü9ܪ·hŸÀóìЂ»+ÂÞÀÇ׈£ _ ¿Ž1ŽŸv|NA“Š ¡ú\ŠYµûŸóÍ/8±ÂBYÈ„‰Á™‹Ý:±ËÂ2ã¢ßHº6óÂ]ÄXûùÖr[âÿ_\›Ù³ƒVÏ—Ãa%G;ÖËï®ÈŒPx—ÒUÒ»…$2"7ÈùƒUº£¥öM€ôÛ˰:uÙZ$*BŸíÜÕzÙ‚Íð>% ü£F}ߊäwå=ôžì¼lñ6oÏchÑG\&ö·w°ô¹RÙ-¤pŸŒÈ©óÝÀf ¬^P·ÃëÕñô±0 ~s÷7)Yµ·ë½Çƒ kB¶bî•ètÞ /¾Vá¼¶  ÇCPW{Ââ1X~åêm‰§ãIÎÑ’€€§-9W:!m`ô'ô8P5¯ {*U«p‚˜ìp$ ÄD—ÁrÖÎ÷‹èo Ö¤ÜôôȬ5_´¤âшOlÆ¿ç¾Þ‹çF…•hqþkÜÙ—Ž‚9´?r;<6üLd]Núúká²Z4…Ñ£ZÓáX‡õt¸Žþªê‰Á$…Xøô*iQ ðæîg ’㿔己Z?—A9SÓgÙ—±áE,UØ|A# ˜•è_,^Ûœ¥ìGôRžtC>OÆ£Ù(£T#Røs®+ž:‚‡< [Ó³‘—@Û %¢ßH˜Y«»©K£2 '`° ¼‡~JL4i“äÖ‰6X=ÔÇ!¡…¼ü¨ÀÒûMÆ¢$OäS&‹j¡{ö[&X ¶f Aø¬+$Ž–÷j ¾Á¬Íw§ÎºÞæ'Ùže¯¯·»9Óy‚Gö¶ „GõióD†§Å"[& X HC¬tk’s=)Âú˜^³ÁM^«J[ä°³eH Ó³‹çêéÙ¤…i6ßø3ûZr^z4‹¸‰“†Ñ_¨¡mÙò¸Zy†VzOI”Ÿ7¸Ç"öŸPðØb6͈Ñ­9²6¥ÿ ½q„Cq³üŠU•tÖý8Ë nl%«É÷q÷Åðy *^‘\£„K¶šéb¡}¬-ö ýËxRY rØxðKêfØ("bd2‹Çk~Ÿ]á±Ø®‚¼¥ãœ-ʦ¥CLyÐ˨ec×ë8NDTL=‚lE02I½Yºš<o-F¼EµèOèR1µyï.GÁ"²Ï[W^ýÐ2ço„ËBMY]Ûĵž…ÛŽRù(drÇaîí0ÃÑÌvv¸ú¬& +O(ÝJò¯<Ó¹(G€3Ú’ÀY?Í7Ë¥|ïg18J›'S»î/¯äžåe@Ë& ¿N©jÒÓ* éKQŒî\¦AŒÆ®PJz,ć'É#ÒL Ãúp«‹’¢ôIˆ­Qµi&=PO8íð/²…QÈ ³®Ì2ý~Ñ•rœRÚ”¤ƒþ{Êÿê­éÒzK±Ð²Ó1H1$wUUN®yÓøA-ƒÒtÖ/¼ÊÌV59Ú÷VÚõv³Ÿ·ËÚ²?IÑ<ïõÒVx­dYÏ’BÞdÂ_˜7ò/!;cóƒ'&ß¹ ¿ß7«5‰Æ+ŒpÝJxídÕ:BD}qßíÒBÔJóá_Z–¦äÕჽ”Š®e¦Õœ8¡Ýá €x8hÀ–Ô€¬ú¼: ÌT¸EÇ^'ÿØ×9cQòרÔô:Ý¥ù¬ ãJ¦ñLwÕ¬k[:¦ó¦X€Mc攢lË¡ŽWªßŒB±áÅs|R³©ÓŽê'Î#éSêbHŠK‚E«ñóqÏŸ=Ø¿§xEf]¢XuîâÜŸ“74¼DݱèšìfRè¶àòÍ(øaàá’Z+ÚŽ”tìz“” ¦DË&wq>Í®Ü@¹’€€­©Ú‚ÍP¼ëXÍã´•]½ÞkºÓ6ñ³Õpj“ÍR0¹ø‹ ÁŸÉRDÅ»ƒC”Âù ؉ÓðIŒÆKpV;ixåŒÈH¤íð–GLœß b‚AÂ.Žñ:€3/…S7ô´Úg_×¢ýH¤ YÜ”®&œ¶?Íû=I<±ž"£  äEÈóv ÕÊj§aî6ûZ76'&øFÁ>Ö3Ç­)ö¢¯­ø‚·´*QçŸ3õý,P*¾#Zç xûb=塸xÚµ¡ª~pÄGRVôY¼{¦!s-¤:ÇêÃ#YÅà2c|½½@kW3}†°ÐÃ+i`´œŒïQè,ñ˜¨3[¯ q¿¶}©ÜJŒPß%÷ ‚…³óM°á©–•xíöõa¢{ûìûc‚’¡¦h73H-±Þë>T8*$ûñ5)—ë×;€ “Óº¦Çu¡y9B{="wZq‡>R< >–"y:1 ¾y‹o½Eè!»ÞóŽIÊýexñI$× 2:bĬ3wˆ²×ŒŸkõǘ297äª#”{jÈ\Bìµý÷ '¡¶ £âP-¿.v…ÉnfÏJÛjìèãßF&Œ¯üÄgdÎbÍ7îb\3ŽšÃªdŒ~ýÒÌ87–¡iÌ);¾.¸— FªÉdÖg£a¬ÞïÅ5¦Á€ûåø Šã4ëêÿàXv\­´2d.›„ÿ[ÝÕBÁànÄ8R'ßtÕÊߣ‚Á•Ýîk§]ÛAÏþÉ1Qw6h@t=ÞâæÛ«ÂК@Š÷˜ÊGR£›hÝ ±ŽÜ"¼Ø>Da“gæó™qVµQ_Éß­Ö°wkçŸäºü¥Þ ôÓ ÀÉÿÁQ¸”A[ch[dˆÆLúC.|™ú»Öø¯ž2|Y¼È%É$–RÃÆÌ•ÕØ„Ó ¹9¯9K$ÿ<Q,ÂuO…ã~(:lcô¿Õ]ÒëvM5t¥H«áv¸·w$ÖFÍÄžw$ó‹œ}`JxÃàÐÙ·9+›e} ã>? ¶Q ï «ùô©ÃÏ.†ˆüZ?½X¹#P€ïàf°ˆp—;Ö†ìbãUKˆ¼Iåü¡œí->tÌG² Çm­rVXÊÿËÛŠºúá•›á±I2ÌãÎy ÝRíàDùŽ[x³2h5ýß´¡fé*CòÛ´­›ꟜWròÇKÄfáfœ[=}ÈÈ!Þ, 2 ŸUÄì¾`0(Éß<üÊÛ» Ä(:í6žErECrJóNê´Ý>@_‡‹-f$3çË6gTº."-t,)sc“÷¶£ÛÖñ“!£j¯ž¡Góòò(ÆCîô~‡¹©~L&ž9µ‚q¹‚ˆÙ¾À•ýÄógz?²Qå8¬G}žb‰P¯I‰’ ýPŒÚÒ±¾BS‡f¥‚åÓF·:è#®,{Ñ,,ƒ'[ ²íÇé_ÎßüÖùÔФaœX戕V?ôE€­$òäåÝöåfÌú§Zo“ nYÊw¡)õDËI%ÆñÃ".5+ƒŒ/ .6Ç´¢àÁô¶U£Ö*ºÒ˜&\š‹p’QéM©äò¹E7 †QÎ{Œ’rîxäÊÃC^¾lÌ^ßK Òq Uš²Â, ~Ð,Bʺ«Ó7G´Û¯Q$”Ê‘æ-£ïùͱ(Öè]h˜ï“‡Ôíáoêƒsm„–ù 1#2Gk‚ç€ñ·…/€ˆ­L¯&‰Ø¹dÙCPbÂw¯y¯z ô!"¿åqW´Çp> ž¤Â¯]‰rÿ…0š¦¯Ô¢Æ¼îý "GëþT?MôîèÄÏ}Þ[½D“Tóªä÷nÅj:©æ¯ù:z{Ô0—-7«lu.ƒÅ3šƒÙnÌ^Hn¹g%#$ Ê—¢Ö¶?· ñ²ÿàœ«#f•8„,‚ú»a"sG‘j§Š×Në-ÎEÍ5Äëm§ÓØo–1ÄЗd™6Äéï‡ý”MϽ¶â[Jaq?ûŠ>pM‰±Çê¥îB^2o}¡ÕŸÀÃÖÝÞ—¦WºÕƒ+$¬`OªÑÆÑdþÎ3øRn’€€Ð/™s/“Á"7ÒÛžOê©…åÜ%^—˜PojEä䂯âJboz.ÑÀ®ÖjQiµk£ ÊùMQ<—o`ÍÈ‚(ѱQ¾‰Ã‡,½Nž)KxHþÀLufõù:^*ác©ŸñaYá*Öð7ÚWdSŠ…Z2`@ÄwÂÔ¯ ~Pó5*ÎAèq*/Áx—¯lžØÇf츿˜¶µþ@ºnS4ð{G¦àó–)±ã‚ŸË†!wqr«‹ý¹ ä.h6A(§jþ@ÇŸs‡kÇÙEžÂa•²¯šI¹wH‹Ò1â¾£èH^žÞ-8${ˆwÉÍöcðÇ[‰yB•jÍr§üÚ?U~›ÚR,”UÄäÆºsud¤? )¹VÞ™ü‰dŠÕúë–ì Ø¿KÕ~'°Ž,ŽG:9Ê»ßef…Z¦)%„ê€3‘ ¡®iΤ=P6›Ö¼FŒŽê’kt%f’IŸ@ÇßbµÝkt°,£uÄ·ÞÚüKdn”2w ¥Á\F^öóÂÇ„UÿÓ ¦»›ÂyÕÙl5½{ç8WÒxr)ãç¶äÌ5km1Ø^kJñ7 Âà×îD-ÜЮŒwõ®–èÎæÉƒzQd&|xØc)Ó)‹¢.Pëí÷/í}šà\úÊŒ7½™ZÛÉ; ‰ì¾œ _Їs‡K%qá©åVXDé×cP)©Z4ÚC¿ÎÐÙ€éX_ŸÂ|LhE‚’ÑÕ%‘±äKسBÊR§±^–¸øy.:ÍfŠ…á´k‹/4·!ÞQU¥{í0@*R= ›÷:¶_²†vÔó. ï&„f~óFÛË]—‹áZÉFE?òþQü:u”w¤xŽ›iI ¹À'ˆ¼I†_ín d;0IÛ5ûs§®ªRÔ‰±¼Ð+qƒÔ2xAÛ(Ëñ•Û¤Êfñmö-Ëôpi r¶ À²Ø¹L½ûšž0M!xÛâ:ÕÑù•›dŠMXÏâ.‘m³FËÔÓ5 ™ÌÇ<­™o ¹ æk¨ªwøq k³™çÞ.qˆüVÓXÂUõ]Scþ¯;*KÚêÜ3Ôe;z?4O}ï^˜c…óï}J,$I„ä¨ÍhÀ„@ÇßÕKa¤„Ôƒè…¢ÍæSÇßüjnu_qÀÔ ‘¶†_}Ž‘”žuðp’€€Û,‹í–sv³!ôœ(ëlÙÌëwâr T®µ‘íL—(-¿ÝTÚµ“Î:D؋쌊Zª ivIéi1ÜñlXæ°@‡Ä¦••ÙŠ2vдRèÒ/ þLÛÝÁ»\ÍI0¹ª$ФHàžxgPâYÝ^›µÂ b¨©ÖY6;yŸûK–î D€ÄMVh* VàÀš‡å[’bÉ8t„ÿ;ËsGÇžÄfÙ5^ÞÃý«gi߉E-]v4Íxíñ£®¸isÈŸ²ØÌÚÈ®1,~»*ÞÓ}òüx#Žk€|w@¬Bš4ºáà¸v½ÕL£TÒöü‹ršjÔ«%ÁVw=ÏüɹLd,þ‡§Ôç¼ìÍV&ç’‘3êϱî ½•¹Ešf\V¢†¿Nv›»º2á$©ƒË àëFŠÉxà¹#^“ê@‹ßÁ0ˆ4 ¶ÑcP™‡ºM5ºQ‚‰$¿™ýÉc45b˜æB›ÛÕ8X+55Ç©cΡýZeu /NP¡À æ…Td;jW¯qE±ùg‚\s/[ÛÏjYòöuW Aö WXbºzN—Éi7)а-—~ë¿4»O£"•!â7­¬©n-KÀAa$€uq',Á@Z‹¢ÄAK×z.®Êî㕳iTÅ»rÅ£\óƒ+„mŠbz*ËuP] Aв¡(¦È#Ü”º¶òâ‹—Éͅȳw|á<#óîé$k–nb©#j'È=óçÓtÅ S †“…ßÁì£,ñ;Ôp3aªHËü¸5ª@©XVq&ì ¨Ñ9¥ÅÙ*1ûE„ß¹ó±•vkgýæàCójNÈ‚º~¡>iÇ· ©QËç{â"r´³`kͶ^í¤Y6ŪþmWÍßÚxX¦/~ʦ¸%ð²U`Ë­}á{÷eÿnc¾TÎùeBðû¸¦=%È ¼^;›0îCˆ ÞÈY{ºêÔ¡Eë °¯)|fU[*qŠËxk7šð0gÖÈ3½Š!^a›Ý0ªÕôPÙ%2åĕۃ)”EÕ6’³èXjÔRê"†°„€É#lÓØ›|žOÀ˜èi`µL… ?‰Í}„úëJ‘²ã¾Kym푹Lc˜ë²ðŠ$òOvÔf=gG‹«‰œ’€€ÅzÍ @r¹¶‘Ð"%»f=¾à¼œÁÄÂ[»WÕù×Àê_âV*hVòwÀì‡ t¼Q¦aPÖW®kÁ±;#ÂÂx|.û¨Î%€vã³ùP½Ãg8„Xx®Õ¸*¼æ6d£=÷Šéîº.âÃW0¹  åvY¡…$ofA» €“TšdVð+ZkPCwéžþíª«¹BtרûsÉ‚asþÝ:ëjDÑú«ê7l²û¬pٶኤkŸ1’Í ñ <ˆd§IÒœ§Áè¤SCÅkè Ïã2Qõ>ÂõÅü–®9<Ajâ2´Ïž ¯›îqú²^ yuÆ_DÚ¬sõ))¥á€ÙÊŽf¬¹÷ óŒÊ¦Š¢Qµ'u%ad÷=UŽ$’\‡Q®SîŽÔ‹\Üš9é¤ ¾[«úŽÎ|G?;Õ¶ Ÿ¼”a^ûFˆ¢["ŠšÖ‡¯¥l‹»¢zÅæ˜+34Ð|Ú¾nVÿu«6Ͻ¹§¸ŒZ”[s~ë^ý‹Z<„£†*ÓøK®wòÞodþtë«™hÑC±ÑPƒFÀK¾y$¨ÒºrÞS]Àp@©2àŽXµÃLmJþÚ[“çlªÇ{ÏÉ*'­}¾²çYÝøæb2h#(hÓ&c[ÃuM‘ß]CY{R+‰±óéËnü1†KÌéñ Ãã8 zúW0˜Ñ/Ü]]'Ç·8À}fˆäQŸ‚EJçº)z\œ“]oµtôžoMk…êbsF޶hŽÀˆjm)ŠxeaqöFKZzùÑ¿ÖÚ˜X«mÉ%ïi] íåz­†T oŽžÏ>Íê¿=TåºÀBƒŸDv¬œI}(Ç$Ì}K­³¥;›®Ui¥¨Õ'^»©Q6)LÖaûlѳ.µ¤¸ÎÏ݉ Àvfà<×G)V›smb­ãÁÕ¬UPJŸ}F4Ï,ÄÞYbÒ?8|ì|ºE‰÷'ÁÂjUí‘ôAqBoÍ=Lx~œUv̼Ž{ÕF_T‹Üºvøóä$,#_ËZÍóG”œcäµëlû®Na’€€Ò‘Ÿî,ÒÈ›ËÁÀÌÆR¯Á¢ç¬ä¼O§ÀïD›CP‘Éù†î2rÇyÑ4Œ!åh±ÖñD2û<#ä^³Ån&Ùˆ÷ o>Pß²ÃnPµUh"q{ç­•/£¹û7*mB®J$ ¿ÛEÿóÈ©(¬îK”é±}8áR-$éUâAKox‰ÇýøúÐï 9IýG# “tà¨ñæÇ)É®ðÓX–Õ¤'~ºù_ÏH9d#tÓTÃÝ}ÀT³-æÇfYMµZ Ž\k4â¢/ZÏÜ1­<³Jª‡š¼“Ãh³é Ä1Á䪧 #1ŽY¦=BòLO~9¥BCòÈ)WmQ3¨€ô¾Ü}ø{=JÍvp°©µÆùEuh‡¥ˆ[Ãpæ©$QÃWj¿zó?ÌŠ*þåp‚ð¼«.FmCÌ$•…þ1òˆ<þy§ô~Žq=ЉØG(®èÄM<Ó°VÂ;HßLóÕ–TǾ›£­“ügm´Š‹Þc‚Á›“)FS}£‰Ž0'IzîÿÒ'õˆÝÕLÅkÞvFêùæ™vîð-KÕnqß“RÜþ _}q‚=ó¯‰p—G0Û‘dܾ*>ádÓx{á¶¢Þçfy¯iœ,­—ÉÏšÚ±§¹.UÑÀ«ÄÇŒMÉ2è{1óŒ,†‘\À…þ¢a½ j§¤rXxÅqÇÏuôñ¬{}l\ô>5^û°ö&çív¿R´ôÑ\'P»º&E‡Q[Pi}‚d#ϸtvOãÓ²ÊåÓsTx Ñ‘¨çbÝŽ".—N!øæn5µñ2€³$¿<óµ›1öV½záO8‡ŠW€ø³ÝUÉÄ%E8½³KÏŸÆ5Æu€5PÛ7¦(žº+¦j½/©ZŽ®»¾iÄ™]h³Ô$ÂÎ-Ä“²"ÓÕë“06‰„¨@¡“ÁUIrCoέǰOñ=¤Å[Ì%ñîW|½'瘴úÑs~âáR¼ì€`ëT°›rW/±!~AÁlm«qÛëB-©ðo]Dâ»Åë(ÆïÕÒ¼0vgn"MWePµŽÉì]òa°¤W½ÎæÏ÷Bë‘\4½ä·×{´î¸'éÅ`t“÷èŽhLÂ\’›[ÑŒ$,ôs(NÌñ#¥˜]ˆNŒ{÷r‡ªÇ€¡RWcñ±¶µ,š‹‘»¦á— ¥–7;’€€”eL‘©ò!±-ö#† â1Èr¨=xnÔQÿZÐJ™’‰H9(µ 8×®9N‰ @¸ÇÁœp¡ËÇ™ã]g3;Ä9'XN­%†á§œW%1mp-›ÿ㵸øt/¢‹Ôý³ÿãçeŸÙeÄ2¹¦a8tÈnÖ‰Ú™_å]Žm,f©jŽ3àÐÈç£B£hš=Öô×Mjä?ðÔï[Ù}²ºØù½P© |iÕhÂÆbÁækì8¸ähp›æFÃc3 ÔÉc®ƒ0g´>#uÛ¢VDÜ~ÓšÇ`Q"p·š*Õb@΀ —}462âQ U%B«¯ÁßåhGíÙKs}U¡Ê2Î5Œ“}[¢¨£ksQ•lx‚ë”O¹ç=9Ò´—ù–n²:týú­Þ’ ×eÐøÊxbàòâ*wΜWäSŸè^%âŸBŠŠDª³H}µk»“’ö¿;÷”ÜËpˆoÄtwyüûloC M˜ëºE‡ô/GZ+IP4$ðŠƒ¾”&ÑͧêÕï†Ø‡ý—™z4õ¦f­Šqš Ž\.mÈŠ/‡Üð¬1X2Õü2;©í³g÷µtã8Çlòó†!å×ðÆØ««¢ƒP–«4þç?Ÿ ‡>(ïÈWÌÍFl%ÃÑËrv§F”±ÁèyÅù|È[) že£v»¡ ,ŽõÀ¤¤Ãf¢‰Á?º­ô RàQûê¼–M­¨8¹%„øáýå_?3WËðB*¹~VAXÆÓ·;ù“¾ãZ”ƒ™AõÿBÀm»*»—ô ¿™úsoÂë´CòÞ?¯5UD™À‰‚© ¾ì¼ßÖ–¤C(Ϩ2¼¾£q¦ ÷ð7&lE¯ßHË¢J\àÎæ:y¡TVÖ¬*™hŸŸÈšœÎ^`p\ÊaºÒlrDs¿»‡{‰_ÐÉpϸ³Üf}Mñ¥vþåÛ¿Gi²½zè*Õ±ô¼ŸÝ–¼DK œ‡×‡¸.Q}­±{ÔÅÿÓ~ºjWZ¡ïDnEœI:3 ,óèì/Ä)†k~ž¢¤"½Z³#VõIj*4N†ÂbI¢yM5äVn÷Å Ôº÷pÉûAâb8õ™rT„½däµmZÄ‘ÔÒôD ãÍ-Y—† B[œŸ CRo&Ûÿt’€€¹‚Ýëæ,6†[ï#¬ Ù’kÊCÖpªÕp Å®¶¤˜ãu×ü´8‡.–÷^Ò¹šÈvƒ  UOÓ¸Y.,œ0ï‘ãμ1¶ÇWã‡3‘B8doÉôtõ•'Êxÿ§~±xòfº Gw~f0¦ƒìbË55µ%ä—¼w;œ¦d_« Ô2¤¸Ý”jbir:19ñ­í:èï [ô45+¶šÁ=þâÁ—‹Á:-Îbµ}Ü ÆQ¶æÝÁmáQ¸ÆopŒŒ_d§siÌߪ®g^ŒIž ÑHʼnº§¥Í€Êà|t%´©ÙÅNÍŠrÐï¤áp} ¶ÿy ;Ð(ª4ÒSŠumZ«,/¾í ƒ³¥<‚…<$ úz¹¢g<‰òíÝÛ÷C“»lÖßÎÕ¾tøW<ÆÉ§ ³5"ÒÒݳ]KÛ-rU”šÙrŠš%ìöªP¨Å¡ŠoŽamÄœ'#º¦î­®nØ@ÔÝ”;»‡uC–ÂAA­ˆ´U[’]ÿ€ÕÑÑ3¨a…-OG/Q¤¡Èìb"@ñ…:A«qø aOޚꤽ—†‘GŽZ}1D ÊK¶òóØÍì)sØÚjò«Ù‘;á“m åškõ}Ûè^Ä¥_tÝM•Üäeã qëÞ¿4< !õ3¤IØ “sŠX!®¶÷ÂðÆ<‡úTödšÛâz=sgs%¬)vNpÛJõ±n×qâTiLsï…QFi0àC¢€ˆ«IPa¿BN•KVá6àpŸŠÓðÁ{§: Üö)Ÿ'Ü·™é¹‚ÞåE¹èѦ¬M'?‚èÄ”µÙÁÇ!¹1§¸«â0BZù`>yŒúuÙ?jˆíÛ€Î,@g£—¯p³iðbWÙâíM¯ÄK7΂HÛ´¦.¦¥N¬o¨Õ \ݺŸ¦Ñ!OjÉ p!Æ„·¨è_¿óBdÒOFq”ê/Øoƒy—þïî²³ÿSßèÑ|b%5I+¤¼§Ê?^.E„¯f~º?A»º>0øLM®îy˜+̳„b2c¶ŸµtàÜ¿~'õư–üªÆà%^æTZׯóçÌ.ÃÛ1”}bÙ—9Þ€1 [Vý]T”ø²¾q£ç@ µ•Ãq8àÄߟýî“„°áž~ñq®´,àM-%-íÁ’€€˜¥À)´¥Èï» qà(¼| ÉUA`?ðx’©x¤ng †AòM´AÊåë´KjŒ–k³¥‹Í­g>]«7ßUV½0Ív¼þm´÷˜…FÚ_ïŽÏ±É¶v¬ÄNi8TíÞ d #}žüÑïñ¯`°––p¤°„[):÷$QUÞóªŸe zšª øÐ›å¢¹ÝA]ÊŽÜþmÈrÿAvqïv€™ÞóÍ S%ªàОˆ‰èÊ´¤Š¦¿º{^ê¼EŠÎ×'¸ÍÞ&wáȆ÷‡ÉàÀëîæ¨Œ çìß¡ ÷Ìݺ€ZAµ¾Vö‘>Ϙ6[Ú¨¹ l!‘Ì“ßé$Ù¸¢X‰ÀëÎð£_“ú®v ¤žcÝ?Ûùdòõ|šk Ji"'ÞT‹BúÔ®BݪzÃ\Þ·hWÞx¾Ó(/*aÂà,7_ M™Él닪Y݃p)2—ž„˜ãgTéæÂ•…ÐÙÀÄ7Ã`æªz–O¦š–Q¶Z7ªKgwªìAÚȇgl.S†¨c¬=fÊ8ñÕäà1ͽÑZUÁq<á[Î$ŠOl¤æ±üªï³’ÈAö$bp'¯jö  wª‰½4ZÌJ¾5¦žÎÃ’Qæ’€€¶ƒdÛÂïgƒ3 U•¦U8¶’nÛÀ và sdJë q‹]F9© -b”ö°/“«ä@Ã>å«°8{¯¬c‹ËK)DþaX3ZGüîrxËè¾ÁW²°£ö·ÀÌb‘[ã/a-›ø_ hÑž%‰${Dl|Ppµå²·Bj·ÛÕ¢ÿ²ñןn°®¾.Ÿ ,:5¯ú(ÿ«¿ñ¦çØk»%ŸÈ»É»œÂX(oã¥löŠm÷ß»G'Ö,œ •ØæÀ¾±äfˆßwdW#DŠ5EäB'iWŽó™;HCn ³‰ÆÖU¹µ†#Ž)R˜…,íÝÊ1Ù½ú'V£ú¤AÕ’Õó]æ¶P°ç¶êR z½ÛO€—4ƒv¥Ä®È±Þ^3mpÖË»~á ½ì fk[–"jÚ2A»ïáÉ"AƲ4Oþ‹v¥±9`y‚¡)þ/óŸñïwÄ>Uù‘Ëðá|fô@׿´þ@¡hÂ’‡ ‘é\ïV@J8ùò¹Š8K1¨ïa_N³OI'Vu4ÆÂóKs´í+ñ¸–¼žØç0Š!,P®Z) Ãw©º;G7{9–m3ùßðìN÷t¦¦"c“N‚G¦$~Xî†íEÕi¾ª[-þè{Ñãm’¡[Êêr¥t“œID]3Š0qèaìj()¼y1©YiG’Ú”d?GôHl`A¬j)â‹bH€hUsxòAeP®¸H*]'٠¶†ïílZj˜°f +Ùnútæ/I-·¶Ea÷@Ë öä®õöê,æ·<à9Žâ„·™-­¢5¨Iæ`óiÁbÝ6ÎÀ‡EÀLÉû¸“ž¯eËØvídáÇÂŧ‘MÐæ2 ró.Y¸=$“ýS9wÐæ”}Kˆ©ýå~=äàÐÖ6Ò;€¼ ¦ìŒ˜êœ;¶b]ií½Ôù’’ î4 [ÍR¹»¾Åƒ¬_T»»ùÃ!ÅA«7)Ój~‰¦0·–ª¯s[À™†ƒŠYÉ IœóáÍW('J£yf÷·1!Ã)$,XϲK2ªáæ°©*¡dq7ÙŒ.ìÎ)UeÞG§&X ‡úe"W¥mßf7·Ñv™ØfÕÐ.̇¯ÐgtlC¯r!0( %þÁ8y'á¿>ÌëÈlkú _†H£ŠH¡1’€€«{NùÌíÂd ¯‘#”H}*ÖÔBÎQ–ÔÁuy~½1K&|…åÔÃ}¦G¬8:dCkuV _¤FÙT¾›…NÁœš@2ÊËd¨;išô<êïGñQk~&5ãX4ÿÓ¿ª^’_‹­Ô~r êÀÅCDä´ ;ðà24Z:"w'øC…M‚cæêW¤üψ™tÏkïljÔŸ°ƒbµÛVWj.…{³‡’®3Pó¸Þm° …_³> H«#`\Õ?ä<ôÛ‰¯0íO·j0V2\¨<çÓ8‘pÁFð¿Nžþ oNy€Ï éæ5¶ýŸ ™Ç™,añz53¼þzˆoexSé GÒŒ neó`Ò‡ôõ Þëí6‹ÚY\‡ZͰ*2myCiÌ͉$‚}¡û…A¯'²ŽB¦e@¿Ç cÿ#+fŽšÜàâIH·V[¯ruN˜Õ´6"šsOŒùþ·ÊU|p=£Œ#qyÂ.ÂN_ùά½ÑÓ#2ö·r¦ôDðqŽNͶy°C\§\êãˆà?z(ï}ݽºl©¼Ògjsš¥•ˆ†%ëH7ŠN£O÷êè’«iúzŽà2`#ßÂC¾e %Àâ|xKk^ó-oœ €Ùgú—Gß{E»š>C‹ž‡…H7ŸµØ+IÏë ,8 OjRFªã)°Ç7>Àíø´ÓÄ9ˆ]Τ¦£UåªðJ@1.¶.WkÂ"vöeÝï2¹¥íÛ‰°¨UuWœ{"‰í»¾ŽBTýòR’s×è0gyBàlô¢DýÀ¼xéjG oQ¡)1z¬ˆò?ã{ƒÝàÞ^+„³¶4rzïÝÍS8º`UÎØÜóý Q…D)íÀO•P¬Ê{ ÅF¿Ë+шönÈÇÁ¯ßÉБ-L¹Í¿À}•ŸL =ÔÚ˜J#ìSÉ>¥kDÄ@^H¦":ç®QvÚ·Ê'¹§©–T=À£§Ü;‡’€€ÞçßÁðøÍÿÝø3»-@1kBÊνs<*µ¡y–¸&§ °Ø±[üb8©&󪕟mövNó{¤F´Ãbmº(éùtºK¢f/^,øÇþù/NÔ- @œ#”ÿ‘âÕ¯yj/<(¥vuá{ˆSË FDwìÁ”pFuÇ9æô^å¹›æÜöÞ+°OÌ'úÞx¿adp”KÆU¸{-ɪåm3FÖ7Ö‚)V˜ŠUѱ‹˜8åÊ9Ò¦ ¤o‚Š¥ÊÒŽÖA-Ã%ý¤î?Å÷LV©f¿ì#޶ õõ欖01§OVm9¾Ù5:ñN<'•< ÙK;äÕ@ïéñ.ÎÿÕº¯ó<- qÕhMŸÀõÈü8¯¦N/”ÍÞŠÐóaE¡aS+yM;CŸ›Ü:TRE’uo3à³R¯0ÆÍð¡>ï”È›S»Ô“Í|­bè2F ~<±µŸtIUTÍË=9V?éËîÓ¦jѸÞx ß1ôàCç ˆý +6ÛXé±ó…UBd]³:B‡²®éŒŽrˆ†ÐzÀY1F¥†(´sY–ú®T|é±õ«üS±$pßLYÄ~òe´‘Õi4›ŽY‰°È¤Óf;JQ}"Ú£OórƒwÓXöÒ5ZžmÝ §o/²ÁõD¬¼@‹éž¶·óôÃ2û`з”ñf£"}9*» ¹òÄ FÒ²`rƒš{œW…n™Ý®ok®Æ5¯^¹,Ð/"‹|Í-éñ‡¬F™X€NÕÜFôSè)dö›Dƒû‰¸©C¿xaX¡Whkö,£Ò¶{›ò@çl<d,_Á1*„¤[èøË%ÈüèÎ1ž¨>ÇÝüÓÇJ0èþæñâ‚í3ˆ…°à{ÆTq%G!å'ò'çYôôLÕL+Ø&²sùç#·Á~ãQËFc¤Ô !!矾w؉0˜©ý|Âk”ë\9ì~÷á"¦̱CÿãÿÀð"áÜq_6rM f(K ™%?‹g#ºS¼E@W"£ Û*²1ô̈PÏ_Ê¡†0‘˜‰mEÝ1êW4c2à¨)ãê\‘Dóº@â“àÞßxüäHÞ‚ ÅLÂÕx–[ë|ψ$¤˜ƒaÚ›…M(…) ù_gqíàwú6 “•(¬¯Jm[jg2`\¨!ŒÙƒ­“l<5ùOåÐNxÁ`—zi¤ºI,¨<è÷¢Ø‚ÒJF»¡fÂÆv1¯´VK±cšFSÏÎsU?A·Ð*¬[öhÖ— ïÉQ†: G×zŠ5‰ôrÆ%©å„«?7 v-U¹£%8åˆ×´Þ|B'nQ¾„a¼U¨˜BJ9M¦^Zr¥ÔX$µ9“Hï/Mé¢iöåø(QãT‡gkƒò®lÊxPáXh€4©ÛåýÎ`•¬†óÙÅÑ¿¾ú½]N­0¼*xÇÍ¢È5‰§pÁ3ò¬Oñ9vÀ.D¶ùÊuéy8ÌÐgÆpœ9QYñàz¸qg¥… ²dHˆ´$Kï{òš¨ªN°E 1½Uö½Çà‡Ž¹Þ'íó%÷¾œì•ƾ!Žô>Î5Òy‹š—wÄí—{‹»ÎÖ[A/8óÏ©í\–„|>í½rUá †ú¼¤´D[±Õb"× º™†àìëzL-*™þÒëÿ†û2 ô/o„†33tˆûí¢=;7EƒXo9f—ç¸àËòöv±jéãȬ:ó¸þh6ÿlÀ¨sËI¯yž#@‚½áòÀ©ž5£.¹yÒêh5¼RÞÆZKÒi±ÊbšÎÄ<Êí£Ê8¼ÂÊ8_åS!af÷©I'«Åm õo·Ö¨¶Â0q#mG¥¿›{Y6ËÙ¼ %غªæÖ—„þ“E°¹dÝ#Gâï$¯^ÇÜîõÊ_ýàÁ?hÛž1È´“®iüºq;&n=-âJ#ŠýÈ5ü‹ü9-i ½ùÄØQùT‹8Yª2øi‚/Ó3ÔÛºó Ï u’ƒŸ¨·Þ¬øÇ ¼Sð *À›—»&Ü#c‚m«ï K@#Ìȧw.rzr…úÔû;€-­ÞU_5î{)Îé#0™¡vœ)”[Ñ;“WOùLâ}¯ÊG±·L'ÂxLÆÎcQo¦|œ[g““Ž¿1f;m¬KÓuÏ}¡s0L§öNõŸå†¾0„l½Unòï½·–‚±ˆ^ÎVŸü Àÿì`o†­µt&Á2B¾¡°"…Ìür‘0½ØÅ×Cò Fÿ9Ù~’ ´ù´ei/Ùî?äkÐ#E’#”¥›(§Œº<î‘Á¹é®—fÇ&À¾MñÊb…6qÓ˜‚&ú)ïTò1ØŸwÉw³NÛA^¡å“Ôϧ€ºÃ„ñ‚"ΧR9›½d @ÀÏß{=VÃyj³}KQL¶™|›´ÿnåLg½@½iÁ½Ä%ü °¾2ÝAûÞŒ×]ŽpÊýtN¨Ñ ¦Tkeûé‘$Ř3Û1Ô´ŒKß”a{4|ëÚÄP¸Ç{rŰav}¼â$ôêVïy&<˰ªh4×6åÁF¢Y´Xh†§Aü’¸Òþ°ùL5³¦é"Ù»›t¼'¤aeº’ºbxº-wÈÅNþ›ÍÚqÛø]cíýÈŠØ\·ruZ=õ$+ÂJ€Q0{;tÌç $ÑjÇÔ×fF̃J×oŽhÁqQíÉB1EÞØ>clžû]ý<Ý-¤·ùô±ÚHŸg¾Œø›æý,àƒA-ß‹³z=?þ¬á§)rkaÖÑÔ?¬O.#ߎûÒÅ_jÓý¶’¨a ßÛO,޽拨ÃvÇ2]då×)!ãTy‰õêMvb2º A¥é—Þ€"÷D…=ZÓYÿ†Ø·¹ú~â~Û=µUÈåˆ|Ó9;ÑtŽ0ÑÒ8 Ëù‘¢‰IûÌq·gÞÓxˆósÁ—nO½ä*éI›ÿ[¶Ý é§Š¤?¶Ôn¶Ï•M™|¾† Y‘™¢ë;)"ÄåÐÙÑâõ!ZyôûHf’€€úC¶#£ÉûÕ§«Ó ÏùÏ ©-s6Š,”i@§´Ï“!©e6³vÐŽŸ{j0æsÁìz._œÊWxK×^ô×xbÿ‚íK6ØÄ‰žÛkÜLÏ>{VϤGkgåUàPpU…L vw¹ýÙ'uøbççÿ¾Ó¿Ðd|Ioò&:!ߺ¡5B2ÂÝ765šÜÔWbUèÇbØñ½ªÔBø‹­¶(ôÍ~О¶o¿h–‰RÕ Ñó-¥üv/R“Q5õv7fµh«uØk ®ßÖ 2gø©DÀD)s±ûQºÇ³Ÿ6|¤Õ·öò—‚Ô:`|*yŒŸ5„ží4Q­‚â8®W’䨤Ö=¨Ÿƒ_=¦aw!zÀ¤¥èž0sÓÿ„B£Ý¥9p]ÞÔ"hG1™? 9-lÝÿËþž‚x°y¿ÑOÔWñpB€þ§ôW@mÐùNÓŒAí NÝÛo8BFøÙýË]¡ÜKš+k÷¼ §"¡Ü$Ô‚Ek^·êch¸¹pí¬‚¿0_Â;W{\ñ߉·oˆh‹>°Kˆ„{H|ôºÌ®ö˜þî“ å{ï‹ZÞµÓ·^dvo1!;F㞟ñâ)]jûíb«»Úþ2%(W‹#ȤÆYbcMœ’¥vÍÆxÕëm¯–”«¼ØL׬KÇc.¤‰G;6 Ä0¿ç[‚¥7 ‹÷Ãì€??‡jl f}«P£ïDŽ_šìK1¥/ÚìÎ|6ð-ûmË-!jnQˆ¯ÇY°bQ¹4¦‘Ì]yDìQ¤†K9Œxô8¤\Ýj6.Ž%t ã–Š± 5°h žm6›4U°"3ÄLÊØÃBdühh[Œ½El‡ü6¦Y-ó”ý—šu¹\¾ÞŽ8wìF¥ãþý¢Èæ‚Ôf߯¦ö#{w)n‚”î×äè=ÑÆqÙµV…5źèÜìD5Zx::<Î;ŒS_q¯tÎi9[½¯f’ªÆï½$Öd¼‚Gk{_ïæZ¥üM±Vrˆ” (u?ç§ìÚLpþÒ¼’xŒÕÂå°6…¸Ú7†õS­¾ø°’Hk‹˜€œ¥’€€ÊÛ/S/°ëkPâ •–©¶æ´ÙÄA0uBè3ß~7í_¬$¢”¡ªÃØpõ‹B‡1óÅvp»¬Ÿ6”$ŸÊDúä1˜QR³¼Íç2ËÙ[²ü/ÈÏZF_ïÂIq‡Ú(TÕˆÁí™…-aQfu;@ÁÙ[Ï]eH­Ræ¨Ùì›—ñZÑ‚âzvGW‚:·72,ã[Í gÊM)\Àðòè©£¥¹Çb ÛV›"ÃbB8Â,39›ØGÝ™M±“ íêýñ.2̵ÈÂÎ)cÛ%ûbû`ìM%CÏË,+D¶¢ð¦©XTJýJ?˜Õ7@®B|bsì]­ªXŸ0@¦‹¯(Ú;8SV|Ã@»¶‚È ûy+ §Í³{'ö:¼ë­Ù‹–gúØxºÄ6µÌ7yÕ’Ò¼ÚãYCµTL6~3‰ïZØ:¶>Òœ+t®q£g½éOñÖjh3ò)Ú&aÑãzô&Ñ]‚8Êj6«ˆ‡óúT›9¡| ¬ðx½eÆÇxuõ‘US›]öS»ñbg‚ ^ €nÉÊR”‰ŒÙèÙ‚5ŸlÜyžõè=–ü§Y+Ìf&È}:½?Kƒÿ´b:ú£9$™H·v0XùåIѪ›É4âÉèôÚé~Å1 ÊwŠ)êdÚ!Ù4¥}b>Lâž5‘¢D³È-Y‡waÖŽû_Bu‰¥ Dø@·Ÿ&Þ¸òÑãÍv°3Ζ&dU e±È»­>ˆ0Š¢7I [gùp•¯¥Ÿ=)ÏÙÕö.óQ ÔÊû ÷ÿC£ “³]­huÈQ·Þ옚µ8Ž;0E`Þ¤ëÄ+Ë/ÍÚÉ2.WYló`Ÿ˜{,! î½p_%É~x8—³D &pz–5èÊñ…ÏÑ+Z,ž5áL3{—Ø•%ÌìUFÔ¹ø9tT³)Š ÓÎÈKLÒ6¨Gnª÷Ãéó'ØL¥6t«d¾g(bóuVz½w%Óç2’ÌmàÃÓ’¼íP,°×Uø·¬ÛÒ?—BàW¾Œý3½âPµâ˜gá0VÖúŒõê2Jý¦“o¥ÔA(•zï=ñ’Ýâ©]Dém„0Æ,ªvM ?>¾°æIVÊšä¤åk‚ŒK4\¸[Á’ü²; ’€€´cËsyÄ1i§¾ˆXr’æŠGe;ÒŽ·ÕGcö¥(3Lêì]Ñ›¸Á_ƒËz{çï¤ñ³Å£ä-·$˧+œÿ鎯;Ôbà›ÜÍòõ0o<€±ÍXýšæµNîì©àü¢ëØ‹ðÛû›ÕZ*äp®ôÛµÌ@»cMš&7Pç羂sÇÛ’¬hF÷Ûyùf%~e[B‚F¶€ò†*pD‰Àhçþå+~=oçÕ± üb"?¢Ä¾ï—HG¾¨Ä ¹¾E—âgHVÙtmeC§ür×…Eœì¬§Uì… x¯^Ç+,ÐYMÒ7MOèWî›n¤µ†yJfëR}‡´Àþ.À$PO!±Ã~ÉÔð>ÙE „ßA!ƒº&¸ ©†×¨i#nÑåh ™²añÊ ÐªC‘ª¨‚t@Ó» æ õ“ŒÅé]"(Oäì´è­ÀÙO'!l€”J6Ðqo)vu¦ÝH¦QrÎÈÛ¹õªÀ…áf¢ aD/×¾Íůâ¾,|aÏMÄ8ÞÚ¿m û/i’‘P4ËÚΠ›ùÄ:NiÝWö…ÓP‹ÁS8c7)‡Åsò:Ô¤º(T#–| 𾑒{ý®æÖùwZ±vXÖö!KuNËDMèºLÔ–Dð,oÎmåƒnñ¬äÁ`Ž1Zwíz>þ ðFwÄç?<å|õQ÷~ [,\“dSª1 dXJ8Àœ«Ð£hÖI3¥P,oð3¥É…*<8EYâŸÛCz¼Ôb¹* 2˜E\¨D÷9@{LÞÓê=£•–Ć­êðJ¾ýžcæÏÐWhÁ/3 Ãx§Ñ“ÏTÎ6^µ÷Î8\âºëTÔ€',|7Ý×N÷òó¤vÓÆÌBœè:á`Uny\ÎÚwHbÀ5ÛnXz°pRVæŽz[$§€e‘°ÁJˆœ3uÄ\õ>Üű.Õñ㪽BfFã<—çÄ¿«ak$ΤCÎQ¨=G¼›ðKÝ w3ã–U§•’€€ÝK€˜òÏW—¶ÕuÉHmØòXl°*à*Ñô^øž¾åûœzÈês€O>üÚ:`Wô®Šól,þ‹[áÇO;ÂÅGC79/-œ(j÷^1]}ýŠÆÌŸG04pŽ€&¨CV¿Bx @òDp__8ÛgÕék›gN1×ÏXŸ×‹$P¼ vKbÄÓ#ðáóñ;OÉÃÊú¤Òx¹ËÌÉ—fF÷ݸ4"ÕÁ(Ö£Ö½š°Ý#@7cB”wG¨õ¾Â5ñLÒýÒë+µí•èÆš_›¢œÌ.rµ*‡~Wy(ãØ’º»ÛLE’³ddú죬#.Ôù×ä–®áWj·ÊSì ¼_’µ=lªM±Ý:Ówy®ƒ“²9zâÆ3ŠE[cÅÎפtªú¿â}þØLúÙy,@cÂèCnUpaòuX4AâàÓqhÚmÒK)ªÁÊ`žãœªñ°#jàÿM`RuÍñ΂K¢'‰˜þõš pìe žb’¨> %+ÞÕ)*s àúÏõ>æP ¬NR×~:u\®î@Æ"Ì¿Hpà“Ž”^PEÙ1b…ÃZ­–÷ Â…–G¤|Ï4d»é§®íJ;a&jhÜê}cÇÈæ±n†ƒˆ4pV‘Ûòpl€¤b-;¥›[¢€±v© ðO[1 k,‰Ï¹ê=›ùZ» 9µ‡ƒTôÖ TW†åÙ2ÉŒR%²#†à[·#>&C½ÑX‡üvIr¹?úï¤m†ÈŠ C‚Xòa 1è@À1¬/ª}Wœasa§Æ€¬ o-û=>2C¥=M]P©…àWEÍÏ÷Žìt†0äúV"oÈO(s ³ê8áÜÍ’_w¨èã H!Çê{׫91VrÏã)“쵋km¯¢Hþ¹ºº¼\qa]7i`J·ix8Ø’€€§Saÿá:R—³d’¾³ŸÜu™àà’iDÂ÷Ñ-ù’/ow8›6•=çš>ûݓƷÅÇÉ’4¡ß@:Sij_s°ú¼(ÑC«`,[$¸xÕ!Ÿ[?žKu_NO{‘ÙELâ/cíø$‹–Mï>}Á,ˆc¡/ÐÍFµŽëvc?º=„+sßm¬j‹ËûtQèÄL÷"«-ÎÂuö«+èu䣼·AøcšE‚=Ý%ýxΪ^câ%"ÛÔ"u‘SJæçp^x:0Ô¨Ìü]{v‰;@ŽÎÀ0y‘›Å?z‡õ«xKú :§g^O,Íÿ58Å7¿õP¯zæHÆ·9K^Q£È/|ç>kþ, Wj#oo„D(¼¡Ží0“q¾)¤$…º“½>7#Ÿ­š£¤§ƒI%ÖÖsÎI[b±[Pë¥*b©Þ(v‘]å 4 ~ꞤéÝ€,Ù_øÊ!1HÙÕüqNû$¨£ì›/lÍ™µ-V¬ã.PÐ ‘Ù}"϶Òéb$nL„³MA7ð#½a²‰¼˜¢øØ@?H<ùX“ñFå¯ÔáD¸|®Â`ˆ¿%É£¼•ds;¹†’À+AÄ—•ºnù{ô“¹ýe‡SdiMˇ•¸ ™G…YF‘•ñAÕˆ%¾mVûJ𥴟áRÓ¦œ`ZdzÏâË1 ð]ò‡I'†‹8sÕ¿ÚÞ˜÷Rf-é19Xhi >Еô%‡ˆç”[<£³^¶ý[7Å(@»÷p°¾þÕéD“°!Ñ—(cÆj¡”%×rº^ùf/É£2VË:öï0 ^ã/¢°“æ4ÈGKµ¶µC¡g7ïmVƽ~ ÷Î giµ³G]“÷`ëC5¸.Ûi|ï[7&Š MåIákSÞ,׺]Ë›Œ\P”bx=À8CM)ó %á<7kr åí- õ±+x é*äbk¯Jÿâ{hñ¸/š«tlZî/”ÿöE„FáZƒèJDµP­ì=[ÆêÀ±A\†>åô€åðüí!ÜϹ¨’½£0?ºÞ»£ WKÁÀš«ý ]ÉSmöñcÀÜä·ƒÔÇáfP+ÑJ€%FúU@sŽíÎéU,IÉ«²‰¤9^ q€ GHÄ<ëÃ̿ܪwET¡ 6‘S¦ŸM¬´„ì’€€¥uF¤Öåcê¥îœhæóÓú pœõ=nlv®-ªÈ”¹,‚¼Úv…£o¥èÖ¡»2hxV¿åGÖ[Þ=Œ®º#˜°ŠYü²vÈ^è÷h3¬Ü§ 5OûPøÄo\>1Ô.?X[ˆÛˆªô=öªCà\þ²ŠïÒU^«e!6pdÑ…½q'ôû­’ÀÝE/c­$e%RÊ<Íݘ ‡R²¢:@>ÂÏo‚1‘¹u/ìAT,²P­¦ ôRþãNçÄÏ ÇqˆV4 LLbÆ_´|úÜÓ! †K«?ÌóÛúÿ7Øú÷0m„—?Í¥RKÌÓû v*+Jî$Øõ»U4@Eã¡5á;>ïàHnÅ3¼1}2Q»¥>5ÈŠ¦’c­EÈ#íøhGK )Ýú Öÿ]b˜X©¼IÝ­ópÓu&'6ƒðÑëªåçP+ôͰiy4‹45ÿ ꂨÎîKQQÓ Ü²k?o?\Ú‰g(.³wòÕÏ?–‚>¼«·7þMšÞ—zÏÍbj\ÕgîóºØÏ–z’=½L5o[¥˜åL£Ä´UŒ‘öû†ÕǶ|Ù¹tVTúv!²Èòˆ¨£ -þù{Oôcü“œm.ÿ$“OòÇ÷e6 w/?¦ƒ£ÌµÒröÕ¢æXhF^;ñ–jF^Æœ°ùQàRÚB2{Ó4aa«>Üǘ¡Çãà&Ëó—†wo ˆ|Ñ!×PK ¿‹wƹIø Ísè(×¾£!ø ÎÈß4”ÑÏ­‹Â…Òy]§·ÜƒŸ“d§¤µ]°¥gí…•ÇA;ÉE$šh³"Ï+WÛHm­SâlˆŽ•˜øJ½[ˆgó;|‘ÃÌÁ#ÍÌã_®)&ðŸ±ÚÉûøReüÕlºÔ Cdž*}Vfuƒß¤£B|erħ†r Øj”‘zJ[‘Fm(Ü/ìrJn¸øË Ù”Oó“Ó$®¡5 ÉÂm7h0¬Rõ“.9Ì4‚ìå®÷i™`M œ(”Á¢ül^&º/lÐöôš–¨Pl/çiâ!×Ôå`µ6‰ä,’+†ÙØ’”ÍÚÔòaóQsÌÑYÊõ- T˜(TH Ù\Â-&ûßùƒŠ½(ÞïÛQתÊ2ýFȉyO‚=’€€é†ðYRÆ?’ÇÀ¶<ŠîXú¸}L.!ïº3T²ÊXÍ+»–Öò³1Wžû&ëÒÃÞƒƒ°&³ŒE%YzÑÎëƒÜÉ:cµ¸øˆÒjY¼ù+­^òÛ%l&EJ-;Ié*µi}Ç:VÇ[/™qŽDØetìt½ ÆGT½—©CÖÅÞ© Ó»m·¦§š~‚//m4sTÌñÉÇ·2xR Aw N6ß›½kà_¸6ê’9¾®6ŒNFýE¿‚jĪq¯T}‘œ},HÜ"vµ¢,PºóÞ˩ǸD‰Wññ£·Pú2½Œ£åÐzèü¿\óÀÄ2òé&®#Ý!Â6šö~öïÛô7][°%í_ú#%ªà-K"ö¨r¬pr½ëœ]ÿu׺̓ò^^âΡDe,bRž`¢‡xvÙZóPÀ‘*¥*äáfAüÜ us)&ŒÜfUþË¢hÆ'˜¾äï²Ê‡›xË%%RŽˆ‰Zí â b¨‹ñ1ÍÇ Éoí¹`Ý baaÙÌrµQŒ â*Ð&Ú%b+iÝ©Œ¯ê5 BøƒòÍ5é²´/&VÇp3ÔwÒþCù­SêuÂdñŸefáêÛ w Qç5á94¾S¯ÀÏPo×n`0sÝ$©^߯䩑aPWçÖe¯dþÔ±»Êh½c¸Ú•s:"—­£Ç,i*pFBº¡mÒ§¿ÿ’ÑÄñתÒÔ@5™×Z«͹‰—­‡ißߨ“œE;¿_ÅîÓÀMêRU,8Ð8…Y-bUcþ8ʵzÍ ;‹òôe'ìò,Ái›w‰çØMašvÓRigýýé;iê™9 tw:ô”…››1ú•ámåµB¤’€€Ò¡<êe¶·H O’°J ÂÝÈ$IRœg&CàQy9ðׂºŽBcëékÞ‘¡Wœ­‘ D†­È"#è9¡ K䫽IŸ~=¨|­åü˜}VWj»º y´îiª­í¶¨k’¹bðÝ*³¨+é0@§Œn\Æ2î™”3Ëf̆‡Z{éÍñ£¦Òû¬<¢·ÆöˆÀƒR„]x™g0ÄÙZ§¬QYHGBˆ'DÌ@|éO/ Žvî¶|ól$–*%~䉯aòAD4“UPI‚ÁøÁêlžY³‚»ñ–›v½ÂZ“¡ýÙw¸‘),.ud'ôȆKÛ)‹>íÐfÿ¯¸… «ðÐF]r>é¦rj&+6v!4UHé†ù~¿ÈSÁ&Í øïzÐÈjüËÖ1È ;’j0†53r´ÐÍCè¦Ök ŽÉœY“$:m·®ÔwôÖe1ˆÂ4)š'7=23—î™KCî”İÌÈ›zfH`=&E¤€€.o„í_ÇñT°¡S\D¿ü~ò«„Öém½^Œn2½êޏ%œ<„=E©¶V}Ýôù èâ~që¼aú­Æ-o4« IŠÑ„Á’Vý…ÒKåd!ðmÏÞyyp$‹¶w»ŽA\2\”ÇÊÀÍÁϰåö$C²’U3ÅúÒðõ)? ¤ÿ­[ô·^${cµrùλÁ¿YŸºüÖlX{ºò=‚*êÅNB‡D5ä #)FÊþd%ØóEžïXG Ü9›:ÐvUЉ,t ÚÄ"EëÞ6ƾc5¸ô ÛÊ²Ô ‚éf4$_’ù³Q‹ óýfó"êÇY›¥¡Ó# AT&"‚=xÛªµMÈ·:²¤F€v¯‰Æ ní*ú°7ÿÄçqO·³ØD„RÁ¢)ŠYJ<{ ï-LÅË||<+»_ ëÏÜIÞä–b€h3dê÷rè£|©E4œ¯jbQN$¹ý…Æ¡_ú§ÝDÚ|ê ÷“ÝúÈ3Á)*cþ— ©dA€dZ4±iœÌ(›õžµ·Oh؉ÇŸc,ªèh1`ö¼£{¢€¯€]²l¡ èmÍB@½y(áçxÊŽh<[‹zÄÔ¬mB Ç •æ ¡X<È¥on«F’€€¿~p“¸éÚ Šˆ¿ê§B’— 92ÀMZñ§L¯8ø"Kd%ïϰÁŠ÷’½©óoVçP=$Ä þR¿³½ž +-/Ö2—ާEŸ)ÿžqÌvó¨Ígs†‚hŒ<’_ß|Ó)DDš»®dðîÒŠ&Þ¼Rån?X}'eº:ö£ ¤:C€‰üƒQgýºªÀRŸö€1×kãBì¢&’=]Ãèö²3!Ë2 DT›ÿvuP^Ó¼9é#¿,.ͱ{F·ù"u·œš¯“-‹ZäR”‡I#­å†Z½I*çÞ}ç–˜4™3¦Ò5í©aÓ³Þ¨Ìqq#[ ˜``Ò¾)¯Ô1ùQjê¦6““ïšâ7ê ŒÊÞ*/áo±ú’ÃËè¨Kï¡ä*ñMD… %áš3‹åî™jÜù„ÆêËÏúù.É Ñ 3éVËõéÐËí)òYƒMàMþ΢/ ¶*ØÐõ✵Á¿U'gæøóyS.¯h.m °3üFÔéU͸ÚáV.Q ÈÂæQÛúªÊoôù‚#"®LÃÕ¸¥·äY4+ýEñ¦À}¸·\ó‘ä®A[N{‘¶CßQóÛ›ð¦ëoòHãçÿß~áYqDφáÒ Ò"Ó nôßYdôyMuÍ('ôÿO‚úO㪊ÈåײæÿbÀPK7$8Ahé~é±ÏÕj9šk˜”ç‚°þ’è¿Ò;îa¸%6bߨOPÍF šf’²*¡ \«V X"Üç1*µôGÓ(y€y†²`‘•¨6Ȩg7?h³aFi–êOÕ˜3.âߺԞåÿ+,Θã;f>yгK{ÕIz™…úÀMY1çfÒǪ̃¦Ö‰ì³ʤ†ýÁÊÌMFº_eŸü!l0¥ ÿ3O¡¬¼é­à½S|6c3HEKËìI<ãÅgw˜Ó&Ô“€Ë› …øYhGÛyœ.5Üú2=`MúQÞú/ÅE–¹ÍN&>|?Óa««bÅﳃQÁr>.,sjý¼~ñðÁlé¦{3œü[™¾I­RJpåÔÄJäú99ØÃŸNqx ·;cBÝQ×(aS;Ø×vSàµÿ’xOûÝÙ¬ª;-õî*¥Ã?³œÊx@¬Põ«’k~ ‡ËA½4Í—6&³k¤ dƒ6ΟÊœQõ’€€®Tå¤@½ï{ÖHßí[ ¹Èw(¤Ü¥ÂÂ[”tR{ž$$ãró£EµÔlÈÆ‰"œÈNÖsöE »Ò{¿“†©è Ð.ƒàÙE>:f˜S Âsk޽ÚNÎ `•9â§wV|©©#hüLÀþ¢Žèkî8FB¢»Ã«Ò;k¥ :$„íñ;*÷çÌ¢Ö§¥›OJÿ’/nÒÁui«QgEÖw³Ã¯¢!h8½¿,µ³T$}<3ð‰`[É5™H¬â­ûé†[çÈXäXkDöo‘6û ³KÍ]!^YDópÜPŒÙøD|HWQfZ¾ÞœI›as¦Z5…¾3Õ ^) ¨Wì¤%üŠcN­0^Ãß9\±)¬?!+Ô½êy«GYݹ£ÝëÎÀsŠù­ßô±,>uæ+Ø@0vu\¡€Ù~šCßÔ!-qz™†¼Å:Tv´Ã×{^=Üë^8ÓPØZºÉãBñIRÌÜÏw›lE>9°È¶ÿÕAS8t`¼Äúp|0–¤+M"Ë%/‰º "¦þ¥nZ•,÷‹QköúzBçPþt=û‘h-‘=T‹:ÜcôÕèƒ ww'󵛸?«è)›Mm7@HDn¼4$çˆ>·½p$–„Ú^ÖñF/-´B|Ñ×j^œš©.Å_û~çÕü¬ þ¢(|IzÈüó½x{öhŒ/–àʃ§VàŠ.xšðøBp*‹¦î²SGlö˜·©ZLÃͧÁ LQ¾äZFI".g¸³ƒôØöX¸ŸdðÑ©Ñ ßre8ì§Á˜"¼¬QÏ-R>$´«WÎï“øSï€Ù¨ü>h9µqºwëëãµG™j·åDŒäðˆ1oìâ¾Â+»Â¢OP˜÷í°&;Ô wp?ø:9N˜EÜvÌ0ÆñaðÚ~ÛÑsï¢8ò<%ŒéÁz§íwGÒ<’rÁóK*ß/¸SâZÞ—Í-÷àç­ÿS¡ê òÁ¢=!ï_> š^¬Žœú¡+,͵Í=)ÚŸ˜.%À©ÌᙳçÒ·Èÿ.šFä€î̘%=NÛ˜0ÃŦÊO—m§Yጪ4»~Åþ :óxŒ…8è sÅù‘tý}W•S b×ûv}/ñ2Ë~ÿáýU!âÊ—8ê‘mþÉ\ºAš6Éx»F‰(TÆ÷Iˆô>ßÂ¥òŠÉ¼ôr(‹Ø3Lu¡¿Ê´t§V­xNæËŸ?ü= gÝèõè 2—ÌÀî =¸&»µÝ½/—SÜÛ’€€¿¢}$ýw”^>•Eß0_ol/¶ðúBY ÿ¨2±m;m§Q<·@æ8…8…玣oêPóþc‘ãjNÐÛ1m&O&‹zò>'fAíV¡ ÃyèÝâ«eóÕFI¼ #OP–—Eí¼¨Ìõ&g‘<E ¤'JRæågõ ä¹ôu@Æð¡qË1¨å‘ÐU‰…÷µª©ø¡VµPÙ¦¢Î½h’Ü›’FC!õÔ4ä#Ë­™ï÷ð.V˜S3€­Ôd?Eí"Õ£¼þ8ʲÁ²-ZƯöžÓ±yc5¼—w-zƒ4‹øNÙ0Tó30“Ðâi‹¸ÃÝû:\Ùùf$)›m Å?°<³¡¢£ý›Isäp.6Ü®¹Es¬ +½`ÐX5ârgm¡ß]¿ðÈ‘AJ.S4éjÑGϘ7 íQó^f²rôS»Yµ‘~ã88‰Ìî{GÀè} JÐÎgÅTG{]ÎxI´:2ï¿–uÔ—6 XÂg`Ö± l¢MÞ9¾«ü÷WÕóO9gükñ$§fˆ»³ø÷cseçFÅ ö ˆDZ:¯R_oü€N~WYº—¤³Xý„ =¶#õÍ’ÙigRäé¦ÌqÎåˆ-¶o|c§K* U» ú€oÛ\ ÛtŒ•«2࣠ñg¸£CÄhÝþšnaÚ„MÛ öð~âq8ÃBû#7¡Š“ÿ 9©kÍ¢½T±»õAìÔýSQmPÖPöddÝ(#øŒÀ‚€ïÜdÝu™Úí'ERÖ¬2l¸yÜ&SÅ»°zɹý]§ZÅæ4ÂH]2b¦ÔãMãôá²\gÞòÕ55…‚×ìùÒOÀúù]'WÙÅA–0¯°Àe¬’.¹üØQý€ÃWš?æmNLMIòÞî̤ ÍŽ¥3¿¢'Ö1RŽŒäéè½b"*†Ÿvø‚JŠŽ*ÙA½qcÕ3й †_4z ÷HZh&´~°á ˆ†÷ÓØeíÆnïp–I“ª•Ì*š5ú¢ÃÙáà°u¶€*çŠ-ÍÎ@ÓôR‡LÍž‡ ôx Évpâs^ùtþÀp[¾s ›ë”“€? À8?Y(±ÆCã.Øíç)gÉ,®`VÖ2„®ñå&íPý‡‡X@®â¿í˜#ÚyWtþݱ¶ú¹UÓ¨;MÉ’€€Ú•©¬Y5½"J¾‚9beôÈþV~ùÖÊI¾.êDÏáƒb_ëÇ=ÃË\ô)àWz×aÄTè]«ãˆž-ÂÞ‚µv¿?lvaü‹tYzÅÒ éký‘Í¥Ï%¶ëâ„^ªu¦‡¥”`‹qXMDÿšˆÌÛ‚ŽÊÖºK(}4t–f©v*´g°ü{ÃA´²`VE5zÇÚ®,”m‡‘z5´ëÄ£`.øÚܼзOãÄ,PÄ]ÐF±ºß°÷¹¹Æu]!dKòÈó [Èô¡D4M 3ñŠ˜SnìXéRâÔv±Øä·üÕ÷ºhÉÏ ~RIÂ7/¸Öm:5ú#B÷Ûc„º ßqªY~ dån¶Vkº ÖZ¦(ˆ÷ˆÍ."í³ßOÞ…ƒûÆã¬lt>§¼ôê¢Í1—w<ôdhaºüF±Éïr·cl(!—}gM饯i _ºÁ]ìì{/õé{PˆÕm„üÿG"Èò¤Ý'Cʶv”VÓNvâ°L˜æŒN:Y ÊùÅ…d~ÀƒËRuÖyI=ÿ_iž¢÷säE,®zeŸua2Ã&Ï…+G]¿ãvdcðŽ¡O%›àržæ  n^Z'J]’-pWõÑömÛ‡ŸÓŽS½í™Ã5¾ £jd³SDe<¸}Ýú"Úö,ûU±yõ¸¸å9ÖhpîwC$ Ý2ñ‰ÁÂݧaâ¥wüÿ¬'-j"1çv¨BLì1ÊBT´yÝz•HZÖª•)õiÔá$þi=ªèÅ´gÊö‚a^SŒ,¾om¶àI'§írÜ¥F"èš~_f›ˆÝæ<ÑÀ¸4þ–Q"˜$¢Å'ö$F¥¬ÎnÓk¡j}iƒÍõÖB¯¬z}â—¦K@ßQD0G†bcÄ&Ó_Ô/-Ÿ ¶Èà»Ù¾a˜ù\ÙP•ãoãfM;LÌ:ù­)T’¿móW6³F›,|AàFTX7.Yú-Ü8´ß:}}“ "ÝszÝ1 º,²p¬‚JÛ/ê]"îS¥§×9«(VZL:2“r6n'oѤvW%—À5DÁGÁá¹Ë·ÛOA}GXäL»xl/à¿Øƒ¦3ß¹êlÄñÅù_†©õÄM½!oøU…  «ÂÖ²þZ K´Jв“ñXàà·ÑµE3-C´¥We9%[ȃL¸nEÙ`C±„ÊM“݉]‰²ÄC+Ñ%*eõqR C¼r¾õZâÙ’€€Î±†ÚOªî¦BŒ;yšWàðL<ã¸lM èò­hnÞ:·!òc– Fˆ…X–5puðyë²ÿv.šÁrƒ®ÊÂÚ•¿ø“Õ‹7„"Z: ÞÏ›NÂmÑ1{¶ƒR… ¡{¢L»æÖ– Þ÷±+±ðb&`=9ƒºìpgÜ×Nþ— \8ÁÍêÓVÛç¿(k’<&¡ýð5Í(PA_˜`g”P—Þ…-Gõ=©x§A.d1:qÍWaDÒ†”èŽ4ËMÇçü¥’¡NÉ'1‚ú}ÈÞkh8âÍÑÅXDóˆ­—-™û_€æh /“ ¢.äoøÏÇ2õ0ãêÛ§½Z¸­ÿI–ÜÖ1HOüpXÆ{{/9¬7º©Àôœ¦œ Ùù¦Ç5?b¿ØH­ŠshÇR_lj‘‚<>¬ûTÏžr†ñ³mT‚PßAxÎqNK;s@Á䙦ž‘&•Z£écT\& §€2nsæêo˜:ã64ß׎SºÚu ÿo…6È3¤Ñw̨5žñ1íÁf¹–Ô. ‚2 æ?@QΑ,HÍ^áPuØU¶,xµÅcùñ¶ƒ e Zë ·<óá)s‹ÇO§QªÀk2]Ò£E\MóïSCí@>TÔaý,«Ï¢¬fÒìo°û¾— þAïèGáê…—2ã¿dÌ`Š.‘ôº!™ïZ9ÄÛæõ u”†â1›Îf㤤£¸ô'X7¸+¾EËùA GõÆKöÜå¾ÂRü-yþHŸú¸ªÛ ¿ñJ?øä“¹'%ƒ»^¤&ÀiY´c’vŠÎè6ÊûC¥Ã›XŠÊˆi)T+ukùDP6 ¶ q¹ÍŠ Ñ óâ·ÝË4d"áoè"Å¥¼Üü#ÅgiŠ—^u–s›òßP³Ûï±j¨Zã.æM.DÿüUFjÑ竼e'nq«¡K0ÁbíÿÄË…ßÖ«ÏèTE¨Cˆ2/+)_þY¥ä¤Cé±×ZŒVò<òÄv†߉ÊEŒg ‘$‹©02ö&ù÷€BBæ†,!I[OÉ0pçަZؼ´! H'YpV|3nˆš¬˜1ÃoZÉ=mÓ•ÞÚ‹ˆÃ¹~:Lè¢ä¿ÇœlŒÚÅe’@¤&øïÂ:rmÕò«€=ºòAš[¯^—´,Ww‹–Ðc²Ìw´:t'`’€€¹¯þCNæ:&ìø„[EQmäµAIÇ­+úŸÞµÓöáÉ8BÕ§µ(˜~}nJ†z9—˜–2 •m¼vÙ°ñ½DBÁ¬qå`f%}ìsøMw­ÿ_Óòªï„Vhâ·Ë²¾/ö6Jø'‰;íQø' 9a×Ü&!d~z£!É2è¨ôäu$–T:öüÕ_kO¼ËTA ö¨ÊÁûùâÕ3ßhþA‘W^BÌs4SŸÔUÆìNr, î‡BÍW^¿ÆV_ýÄÂÀÆvôwGKƒv=š«æì!ÎŒ ëÁݵ Ú yn¦W¡›bì:q\B3– °â4(¸µ>1À}?™½ãpû ⊨öO`ók¡jâ«ôù2åjÙšRü–ùA³Ä”kƒ/û5NÏÙp´]Ñ ¨ÚÒç9ç?äÊÖ¼HNX"»lãn››‚€xF…Š îAˆ¤Ju(܉d»ô©–8ó#?m”sÂ] H]ÉDï‹æ½ÖÙë¤d­?¹Ï4$)MÕr¯pŽØw¦ñB‚¨ÐñP‚µ£+¢$æŠU0² ²jš>ãæwBØ û «¸•YE^Ù1”+C¶¼”aô#l K·«ÇŒvVj@nyÎ<åÃíhÆJI„¹¦¦©ruà}ypwd‚D¤ÐfôÜÉàünÔûѬ~ÝŒ` r.@ M÷µxÕóæ˜oߌ…:o\è:¡v.6îm¢Ò±dûä^ 0]½‚hÆãÐ …«ßZ[µÜ7Òå~Kz¯7äëy«#µ¿Ä3rûÉ TÆ.;Xb>³$qIO¡†÷/ïEÈkÔŠ 鸄gÙâÞ÷Ø­mY(9÷ùnü†TNß"5!Y0ЍÊÙ…0–Áy=ÃO"É¿Áˆ}ç"¥N†û@ a[-PdDcU·Åáá™§ÓS'óµ °Ïñ"8y,ð »ÿ%âK{~±4‰xw™$=–èÀî-Ó¨v¢ ³ÏÛj^E¸$iÊ€Ÿw¤9ý„ëA5Ø}™C¾É}@ZIGÀifàZn9áIaàû®êÕ-(jIF°ãBû@¤ŒVÖ‡’€€Áœµ{DÓ‡SsOåH]@a0œšMëL«¤-ÇQô‰m¯¼b„ëDà;€[ ùˆta~xûñ—‰î;È8ÆÖ£?ÊÏ·BLpç÷À̯«‡ø¿ï‘¨¬™ ÈÊæpéDäãÓâ¿o'þt1+y¡Š5M(|%½îvq²Ž'ÓÝÓPÏ‚²9£¤Æf³YU1×/$'òþÁl?9±Á¨@ã‚+)9@-…±a—%òz*ÿÞ(1‹ðWÆß‹[ Ý!±.‚÷§Dä<·»’)å0~;!;kɸß1í~žðУÝhàW0(n0R ®J k ùwú—Õ;P?jÒ£© ÿŒìÓÀŠ'‹•í°¿Ïî. ; ˆn”…á…®?mþXºG5yDÛœ2¹©0PÏ¢r0½Ø*× Ï„²~h¢_FGxÚK`ú÷Úšñà¸òlÂÔ€”ûß…%Ÿø`Äí‹3—ܰèÛã‹ÎÔð¤S8©0ŽA‚K»T ˆëô¦Wú½Ô³ïvÃãâ2½¿$¦PT£«¢4I–¥ØËþÖYw¸´½DÙØz·ÈD[ —ƒ‰Û÷%ìŸjgõ[ñe+½²E%Sº¡\Ð&eÁi¢Ûù,‹;„`ê`a™v3Ëu/CÉ¥àXÝÓ*ƒëÓ&¼€Ü)­ Ô—œ/&s&æ¹Bˆ.g`aðYeÁœ@mþç2¨0­¥ ç\6¯‚—Yåͺ†.4(}tæÛlHßÝUÝÖ.Iàö‚)—¡Hlþ9jÃ}úO-`:l5>pà,=÷M¹á_[Ü ¾­ô~æÎ¶±…êÿµf¦øîya~a• Çùló’\xæ»+jNˆÎ1Î8yd†š_Ðq0Uc E 'F* ¹¸ ß ÎWeC‚Ïâê| #‘ƒ×¦§PÏïUÁÇx¨T¾ù; :Žv–óY‰YGTUÿƒ³qݘ¿×-ÊG€T=m›ò(%½5cé= q}Ê¡‹ã4Žcž–ZwzÈúárÆW²Ð¾P³4ëh}z®MœÐæÿ, û(råŒ6ˆ¿ÐzÇc‹Lyð˱õEXz„Â{ŠH¨5”²YýÇß(Vöo§z¼[õ<$@O·V«| E^¨|õ®»º=p$OÔä”P$|zô9ÄòewR1–C˜A²Ib9òû¨ …ÆÖ¦ÞŸE|%ìÛÚ{¢j:ΗT–ѬeJwQ{—a©Ä(ÖP¼7¡z0ÄÚrOBBÿë:ı!BëRŒYCB£ä÷~¹;ÔÔñ†SÓÍl}ø.9C´V¶9î©ïÃÿ .,_ÒB:#%ħ*»[0rˆVˆwSdÁ~ ûÀ |œOÎ5¥¡L'4Çü!ÆŒö+ôãúù¨r'° 6»’`QYŒµ Ê(þJØa] Ë€…( m” à 6Â1êþ˜º02뢒}îAñaz¸EŽjÇßQß[Eó'á8RÉ+ïì]dy4ƒâ&V?–=T ê-¨„z‹­ jÞKõlŠ;sžorU ·µÌ´ì÷7´pbZ ¿jÿ5Ú@ȨBÖ£ø£)"êØ [üMy˜UôžhZë+¾^£Ãì$ð@âˆ+š×ºoË¥î§V§,ð‰žfÿmĶ5†¥È"øªÐܲ'TúÃø(•W(à w—]$Û)ìCdÒÓ@}F“R'$Žù T¡­ms[Lpó€¿_R#ú ïc¬ˆÁ÷ÅÙ ]µƒà@Ò­&íBÇ’¨^oD–n$‹²Fìö9Šø˜ ƒ9¡…¯q©r3+súDô°RJiçåQ¡æß †fQøhO/ 8d¿Óö×§Ãmÿä|&4ñÔÛ¿–6à"C4Ò|ì‘n²o‹fù ¸V¯>¦ÞÅS(ZîõܧçmÔ P`&½‹˜ég^ß§«š,È7§ù"æÞ‹^]’€€Ï–‡ß‰–6ñ 1²]Êï’¬ÔOôtî÷›+‘+ù`ƒ Ž(EÕôÇ©Ìîä v\Ê„àÉ)¬–²ÀÉžéìÙFì”Hw’¬Gžç¯ þøX!©ð+Sgx›=KœýÖþWe äP‡]·#ÖòóÇvèl•$zP¦èÉ1Io®ã»ì•þÈ“‚ÍŠ¢7¯Àѯ:‹O¿BÐB!Š+ÆÖšˆ‰þÐJ’¢•ïû ÆW'/úãé¡|ª1@n–¢õ".,šÏlt¹4Âv²!1u«Ä‚ônC&ÐYu>’x’_Kb,ÛÕêƒÉ¼c #ÓSL(¾ÌÝêÇNCÇ™ßÍI˜7.AEÞ~j_á®ÃÚï¾;Œ$í \`£v ±ø8bÕ·¤ÛÉþr)o[œgxFqœC#ÁT‘b•þÒL×Hé!fr}œß‡‡®„¬œ ÚL*5µð²ûzÅ®‡Y$æÞF©ÝÇj:úÂgù¢~˜Æ×§ [VîeÚ‹ÞI5bo¬MÿžrñaqMÔh ‰Ëh’tþâ ¹ü Žc$¯W3[ËXdá_j=ŸIqA,×)Vl0hmAã30bHxYÛs±±©9GÛÙò¨àbÉoï&¿öf¢ÒþÍФÆçƒùÙæ"UøÓ¸¥Š §¥\[ÓŒy¹Ùš8R„›ý*j¥ …ÞÀ%4uÒ®Vãö…¹6u¢ÇÑé|”Ìm,’³)àܨ7ùÏu ,[G’†ïN£íë§Ž¶ted…G{Š(:_Û1R†gé5¡:â E ŽY(WË*Õf[ÎZ1JúnÒýiùP¦ÿ—êbŠ{þ¾zcÖ1¾»Ht™ç€\ò, ‚4ÿ [ŒhËbFohÁº|ØÎ©¡>ŸWVJR‘"”º9âµ/ØÊèâu.ž ƒ©„›vã êuõt`v–<ЪW‹O­Mr#OK/ÎRú#¾\‚•¨µ8§0¾ÇHo¸iIqóöŠA—j`柱ð«•\56ˆ|µéV"Ô²\^\ØÍüEƒ_xÔ$IÌíÑIý+Ñp’€€¸Ê–'ÁÄP…¦Ê”B×é+!Ñè)-ñŸ›ˆÝð4ÏͰMÎ)0¨J·^¡3µ†‰Òr´®×ÌSý„ß…Îa,²š¶®Q²ßåœwîh®î÷øŒ¨%7š”ôð Aÿ ‰YO2Ô¯~ΗKƒb­5ÞÐö¸ñlðÇ)šOÆxÚžÓVjT¸ ¡Ö½O¶Ýa±ºÄÃmŒY:HOà Ö¿Éèu[)÷£ÆÍ=6¶빀.N]µW,<¾ÞIu2QŒÌ)Í`ð})挓ã®%'X=ŠmO©1–ºGþ65âßÿUS ¦ ýUœ¬Ùdz™o99ÝoÖt .lËcÒ¿‡Q挧ýåÜvÏ-€bK¨H»0ñ ʶE_ÂSQ8Öãnx | ¥õh¤jñ†ñê| @Þ>û ã<'lr¤TÒÑimvuqíY’¼®óXM.Á':å¹Õ³µ°ä@d—½#^ÅCXÆ_º]îÝCe± í‹ECVÓEãRx#‹œS8±F·sËy®º=Uáÿ‚¦©l†?ûóên¨×Bt}•‚Š[Ø­Xt¬ñí3‹Œàa•â/-l¦vÒ6/¼€X´f*ñXKËE†dÉúá»$ß6‘=ÇY¶”}aÆÇ–O9°%ýC¡îC/qõ¹N**Ä«±ß?J ¬Mj<ÖJ:å”DÕÑ#ê‰rU“OV€sÎ9IõåIï[ÕØ~•„„œ¢ªÝÑ ôôrò*F 3’hõÞ•oDDî≠¾ÎÈ#/)âΘþZ\­´%0â5‘„ ±½ŒR¡mýÑÚÏ|<1iÀ„ñ¯l¹aIüvÂ=¢ Øžís„„ Üu0l£&‹â‚Ûÿwª_·Y TU|Ó@¥»ÿçI•åóÒ«?Ù‹'dæ·¿ÔîvoI}Ü÷Šúíé—Ôüº™'¬rc‚z¢ÀEÃÊ÷d‹Únx3à+8ê:ª21ù’rK=qj“ȚFFr½?(–Íùu²9Ëó2b>¥ÿGå¿™(Ì©%aÍ›E2âÿxm°Î¦H0Î]RTèÌÏ]Vj -"äÚ ç’’“¯†Ü›/ ‚ZE14Hµ“ö±²©m½4áé3HHDxÚìÛºäkÞ=Â6Áª×îÅAâ%Ü›ßÜ-OW¶ÄZ°þƒs¤mÂÈë®ßЮá5­Aq#„húepÌ\ÓJ´ÁFûÄÞ«\hÓ"ú­÷eË^xf³ÞêD#×5õìW½±P}=ßÜÓXœƒBrÿ÷þá3Lßü¿ú 2@ÀT)pY>b{åžÆ»ûÈdÎ `ï«YÞE¡ImHåÑnRÂ’Yâ€ØÝ¨ý§˜mq¬ÃBi;—ùØ NÉG"/@Ö!Tà³'à ë¶t»«|íA~¨Í¤a#ÇmIÞ?&ÒÂhña¸ÝÉëò|:E¬Y‰Á^ë…ÿÅ«K2ßßg@v{ tTt1ÊßÎ "¡ÜÜ«†pg «^ÌuæžÃ›@—½_ì_áðBº—oÌW¢/’Ík4ùÕÀû—iU—D@w¯§ê¿2óÎ2UËedÜ/ŠÀ혿†“’[óÔ† ¸»p=ûâå¯eë³;,ón™¡l„ÃIå¤õw#¯»X£ ÍÆÈ}TÅ×ücŒ%Èâ¥á×÷z‘xŽ„z\5TM£"Rq>íxXƒÕ]ô%>F1³=Í_¨-Œ ~ýÄ.»F(kÒ)¥HðÍõÀcødKM’&LÙFr@~‚p¹wÉ ¢sÚ +„@h½}¸“Ïã> <Ç£NDX+Êå3õ®Ü }`ã|â½M†FNÖ-8 R„êÑ·Ät$2 Î…jÇ”»$,œƒŒ1ôÐ…–é¤jï.òg¿%¢º_oQ—í†ö-\ŸŒLÔC8¡î»Ìð†ïpÙ‡j ?½psçÀYš‹Éa1hÀhµ»žF/‹¦(8J V 5àØý}Cë:ßÒ*À,ñ§Â~¼ßdñõ|Ñd¶ãâ­§¡N9w:má\Éçk‡ýáö„Z O³ýþµPr,÷Ø–Cðœp¶Ôxne4…Wã’‡Úé ·mÉLYƒ·éC8~˜\ïbo Ò  ÔH ï›/ iï-:Ô3§xŒ?—HÜ6Ti (Òˆn4s<,r<—‰`¼ÀWË{§õx0nmè¹m¡’€€½ïlD5æ0#UcKà oÇà1ks*W… ÜÑ׎~dmªbe½ ~£¶f_ž±×•ç¾å´˜÷ÿQóú­@ʕμÇɼ]Û¸Ún´­ï¹Ö8ûkÈ8»t‚Œa¢á;’C¢è™ k¿Ðê¹Ñq´ì‰ÿúL-émáÍxÄ*ŠÚƒ +á~x²ìr§&5Í O*òÐ\ÞvKœÍm0ùYEÏ‹š#Ñèí™'P£¹TKj|¯Ý øôꥧ{Ðzñ¥Ž‘ÑŒO?ÛŸgºg:;³ýÚˆ‚ ó/ (íÈ¢êX^;‹À:¡çÅ †Ñ^ o¿*áZ®YlqW 5#E¨óÑÊÛÛrÓµ‹úà‰ð´Û¼Ã*ºØ‚Ãt#]ïݳS+fx9Lré˜xÀûÖé+ø©×­aIÙz¯$½³ðîS>=ãåò §ÆÕUOdB®DxqWä¿Á'С €”üú:º2×}ÅRÝcç#ƒƒ±)*Ü;4ƒojÆVCb:røax3ÏW&ðƒû–;âÈÃêɤ…yïn3§Bݪ*âLæÇo®†ufl#Ö?Üu¹ì€;»3üâ L{Ë3 >ƒ¸–IØsð±ë¦ÏÒOj·Ž™¬œ¡ª/¾Ðhæú’ã„5;ä1*^>ðòæùm7üÐ_ÑOñ$v?¡=´6‡ÓPBGé4˜<¨øŠÒûµ5†'ý"Øq -•ßwz‘½\Z—= w„D2Á¤©)ŸË¿jðÛ±ÿ_qR@§Ê³Lƒ–ö÷Å.œ¸z…ètÂ{”†Ûl—g4©ú’JS×Çï·ã_Â\Tãá+Òƒ°DŸµy‚çö$£rí~/o&PoÄ.éáBÙGMx¨Ë4¨ÂÝðáM±nÄêFÁUUPaˆYb!5ÞŸµ9RPþãÚixWF4áѺféFA¤ƒ¾öQNiœÄ©‹!in“Ë5‰Ÿ;Ó‰8v{?¥ ‚µj¨7`-(øß'²©,M{á–­k-ÁºÆÊ2K^/ÞœðGÒ¾<ŠÕÏM9 hý 5a”î2ó;Å•‰rö ¹gÊ A ˜Z|ŒÕ±í²à&ìNÕ^»Áù³ÿÄö(nâ:»|N'×–’€€÷ݸo„'Œ M3i“Ÿ¼\Žñu«Ú÷ˆÞø5[By7ôP!«‡ó$ž(³ó5ÿ÷Vyð_Ôh’Š/nùØVÑïæaê»iaïÜwñé™(+Wòý[l7_˜è”z¯*+\Ã̼ŽÕ™Bç™Wdù¶šsÜ.„a“ŒÂf‰À d%·¸"€ 4|‹OhØøp—·yáð±Óõô¼]Å(A êº½Ù@:owgÒˆÅoª¡éžûƒ¿~–ÁC)7^Ç-œñÜíß-{çël½j D8µz3¢.ùðc¢È4Wì9Wûû†xß<Í@îI8U!b,·±yx"º¤+}PZ×S_ú@/9ù@(BÊÓ&N0|b•´QÞðÁ±#‘ñ}%,«¯o¢]þ<ÿGÎ5¸±r©Æi¾ ^}Ý·®>Oð“?¡ˆ.ÿ_Ñd…c»ß„æ?!íqmkÌqû‘d±»ð;cÁ𨩏•— —*¶ QˆBÛî¥ç‹Ê äTæ[¶…¬À61D¨±ikûõ~r³ÐJ«'ξáxÝÉé²®­~<¤¢« ÂÄHÁ©`†²o8?ª©ñ ”Ï‚.–8ŽVpCiL#ßOе$ÛÛU‚[J¨™¹1È EÓi•Ñ• ‘ü÷:>_PÀÁPûó‘[Æ¢º!x8{nP•MP4Y³Ðýg4ñ€æïç³}ç|7¶ï¤ò•Åœ?8| Aó¤E”銂VÝòA\]éÞÉÖç&œ–‡ïd-§§ —.\¸‚¤Çi›+„„þ‘È&›ÈmNÿ1ÉúÖ/½“å×à{s>H©(zŽ@ï/(…Ò¯­•ÖÚ £ï{-ÃÆçñäé—š:&Ï„làúÙ˜ÜéTÿ +>,;|€î:¯³7‘Ö ŒôðM¨9ÍÔII½pW­1u!‹ ¢¦+ß%A«Z†ÅäY¥ìz­|\Ú1ðDþÓ‰€ØebGžJ“˜pÓ‹Ä[Ìô9o¸ÖæXͤ;^M>5½5‚Ÿjû‚4Ê¥²D–E“;SROz~ºÊœ+Ф^ƒ!ûà|mûì×Ë64Ö Ÿ°Ö%ýSÌpô…Ž™ÊÝ1v(~£ö4fjû"«mO@kqÿ3’€€Ÿö0Œk Ëa:¹’tØ¿½E½ØŽ[©Ü9@f>æ°¨®4ŽbÌ÷¦{>Y8“}Kì¢Â®*ìØŒ´†iÃNÈ3/aáÕÚIl"ôß‹÷’âl•ÿvᬖ֔ã†ä!R]Qø¢.hŽ©ÈsûÈÿÑäŽ]éa(WÐàDäq@E¿ÎÖëí‹Ò00 /§)K.w ˜?Îì¢aÏtT}ß´æ“26J‹bô˜LøÑWC­`un¨dÙ„¼½äj^Œ¢Úg`$"ɤ©b܆–2{ã››Àq3̾è>ø¦¿É°žS+ ÒNdŠÖ§¡ì1u_d ÌH I½Êöêy(vì/(ß—d xχóŸÜ½è>Ÿ>ÝÄIêg<•Ò‹¾èJs­ûïú4óA.gG©ÉÄÆènz}óôìU_Ë–µJ&³Y›ë¼[7¦ØÖ2B¹ª¨O¦¢‡WÚ1V·ÔÓk¶µpÍOÑ…$}d[ÞDo=yLˆ4Ôeë÷ÿ@J8Îõ쪽f%!•#ÙicÀ ¡§ì™áÍ0FDàvÞ+‹=UG;$áˆbÚ!Ó=Âws¡É…t%kå´ž$W8¢©L rª1f€ºßS¿Ú›GÕÝæXi›ß‘É“)7BËé,çG!Ñ ¬xG±:Õ¡BþBVFÜ@:2žÒÛ]¶`ÈÁÞ/ìTûPÐ#5 Çî’€€Ø5sÆ+3:ßâÕ«ÏN3!âH)¦uiç~‡½/$ýþ›¦Î™\ÇA{N>Å„NØÅr²>ØRtà Ö¬ÃxÔ„c§a{9ò,Ý¢—}9Ü%A)¾ˆ ã{r¸<; §ø¾§ùIU+çÄÂUŠ;=êíý?Pïz˜tÛ›Ãà×Xý{gªLÖ;pJ4bîí½•b)¹d2™0 ‘Ë¡^€!ûÎl, o~ŽY(€£¢­Õ9”¾_|<Ó;à/†9a&Í|š›|loި܋¾H\ùñÔõŽç¼±ŒÑÓƒúm™’yÂ<ÃHD–± N9q•Mögï15ꉫ¤*ìdEjB‡7ÞÕj“•ë)ãh)Fá(R:Mר>)Y$üæ—Y³yTtôra•^³çx‹.ˆËìAa™®9¡5¬ŒG_Ò¤Ô©‹Yîï™fÝ5ª 5S«®µ™{U›†w ?)T¥¾5(I2Äx}ž‚‚ÄÇn €_·ÔìéêsX ‰ôo‰ƒ©Íû°7Ñ4( ØHœá§øî‹UN+À´^P÷ù¥ÒÄØ-¸r)Þ^>#—å(4¦¡Ü´)Ì}>B¯VÓ”zU&^2ÄIfÊäy)‹° ¸>Ð4EWNH•vG‹±aÿR.7Nq€J¦ìÑçI©–œ|@B.5ð¼ÝWúÀøòíÀ+^ÔãɃXXxcÛlqil¨¨ª¦øL¯ˆIi G‡…Ý+bÂÍúí¥‘•6Þÿ!âÚ'ð¸à1<^Ⱥ·6úêѰ™ÍÓ¢hz2Hge\Áôpù®îI–8oÈØÈ¤C‰Wˆ'Ko·æ‰´²h¹/-jªB‚æT4ÛPüKƒyQ ·>Wœù>ñžŽwlY8”’`qüe]çÏÔ*í,_êÐ×Ã6ØŸë~3‘” 0ýj®ÙãBáÃZö¢_y(ÿ¬á.¾,Édú+ÁëĕΧ†Ì Ê æG}:‰œÞ‡ÎîÛaBf×Ú„ßüÁ¾ÕÇ»2‡UNÍèlÅjUÿ±Šß¨»Çì$¨þ)¾`öhvMtõ^ŒS‚t [ÿÆMßëûè*‰ÞÃ{$À÷ô#P>Æ~&þóÏzթɌȲZwÐþ´ÓÁÌ©zJm´–[0Ôß`Ê® .Õú ±U"ؘxß¼AüÍ<Ë?Í1M‘{37] nƒðŒ¨HpÓÂ0S<ÂÕfÉ »Ä ¥Ê–äöæPoäèúÓ/ܤû¡Uµ˜÷a=•ß²AßåÚüA•´ »› BÕ‚ƒf—åôßæü 8m©cMÓÑçÜG?†ý¥d«`g„o.k±\àxöÛ«`ñuÖ‚é_leTÇÊðÇPÇ÷’¸òLñ (®¡<šè%?íÉúò?†>L®l·!e[e«›¨Yš$Š-öºKþw^î"¡& ½²òÿg¾h5|I4·îhŠ’€€Û ²cîrÊí@¾ÉAeÕœ0}og°f SH>&âïRb# g{a=;y“l¤_ ϶­(L\Á«ëÑx¬­ö,*[Õ·Òª¥ðããè„ÖC¤³Q¼ƒžÇ«¸5Yk¾ˆòô†´©ð]k:Ðwo »FU%,¨~Ãǥ˺>ÃÜ./ŒŠÛsãïd:Üd>‹!«§¬ZÞÆ íÅE©¹3\ƒð€¤‡õí$7!)ÆØ¸7U~-n…8²ôÂñ‹@<Íʉ"‘æ~@p1L¥8âÑr¢£ë3{â[n=ˆMpMéàépïw˜•µ¬¾ˆJ!ã͸ʹÊhO7³½ñÓ¿ù¹³èòí@g…"ŠÅ1è¡)ÜëÊ¥P!¥Íf<ìëZ´Á. AœtÌž]@qUA]ºÔA|ö%;UÅy0à4¹›°Tˆªë}F™È7ýª®žQ£¢7õº¨/Û8?0b¡:âaÇÑ º³TÃÀË‘“^ºY/žÏWµrŽr{š* —B’4?…DJXH~Hk\e=€EîLΙï÷Í8ŒKËØAûÓŽw5Ww«Œ7õfj$6zÊeýu¼ S®+BbHŸÐ†g]ôÅ(SáZË=f}Óšä§Éß'l¨ÿpßP%ùrXn³ô:OkU4žuo÷Ý©Ä}Iþ¾ŒA2RkYœë·mó«¸ÜØ-ާòùüc0ØdRnJk÷Œƒqô‚§U¥½ÔáxÊÂ娾x Ô%9­ Ê‰ Ý0G#Ë´;Ê‹›—ž1z| ž¹ÒYèFWqi·¥çб1D ÝÁöuÁQ”Qpë@=dç̧Bmdµ›~ÂöjWäþÊÆ;ÍjïÆ7³Wa¤Ú7êÝ1UŠwo¦Ì_ûNAY¹ƒ?7„¿®÷m$ºCÕ±›}¸N0xœE˧.{¿BÖ’¼™dÈÌžæÕ¡ÕN‰iž±žÌ‘ñOCvhÙíBY$lZ6îjHÐÉDÎ]c®îXÆ•[ä´Ù¥ï_4¬Òw-ªºö½xžÓ˱‹yǼððÈ–ë¯c½KÓñx?&´TÞJ¥·GçL,ëü“îb/G´‹ê¨vìÂô›«~8g½åÂö}º /b›‡™L1lLŒæ·Á… «“÷£9>‰2þ;­+uÔ‰*@kBâ¿(,ã!=òÊmÃlI§ö–À3kÀþ°Ï«ÑcLƒM¢%(ÓPºe™æ¸¯ùšÿ×ü´•ÐÝòµ cöÔöÍ×?Æ:£„¤ d(׺Ã::ßVôÜtµ?"}dS˜Mƒm†Ä´ö¼ m‡:Ë*Þë÷Ô¥^ø×:ÕÚðÒ,³æ—aÚ¯ûßçæRœ1oÐK5úêa¿–÷}R¾c HÑŽ†›GJå ù«SvOòËÝëE —nò'ÇËHŠ]µIûôùÚcžEt*ò§ÿgcƒüÈeÖ¡ÕíÖ¬paÐQS\t7¶ýœüóÿ„â;ãbäÖÎÆõç¾sгXç€×XMÇÄqy\ëãv»†½õ:nTÊLæýLì~e‚þù±|’€€±-»8*–íJæUvY¤­ ló¿ž W!ëºäÑlßöš¼ïT…áïGÔň—ÜOâ3eî>8èd=wÛf®¡ºy=¹£èë_ŠÈb¶Š$ƒ‡_¢)Qfàÿ×q,»ðêÃWYP"$“+˜-¶E²2ÿD•|ÓàÀ˜Û–‘`žGô²‰×LÚ UÁY;Q…µê†Â¹˜ç+eɯÖ/>JKK[@¢¡ T‰š2xìA½uЂ0Çq½¼»I‘ÌìÕp±½{è®j‹Óa\àZNŸkÇ€7Sôh•‡4Gä©»Bº0³D³F{?È’KE¦-VÆÏ®z¤ ‹•s%BãZü4'EFEÈ6RØ!†;EëËaÁ o¨¼š]‘…÷Ò{sJvx:¹R¢µùþ!ÜÎ8ùh1ÍïÇöpI³SMâ‹{¨Áó´~h::OÐH‰“²XòÓCo³ш ÔØÑ|ÿúH;^¥à‘?´ñ/þ€&ßKÙûKE q£x‡%ÃÞƒÑË}Gb@ïáõ?6ǧ9=WP2?<à Âß±4¼•Ík ];³Èüþ§Ñ8fŠå;¼åÏ;.]q¢êb§’ ÿ±bÀ@VóÞ¶¹]ú@òÖæ‚Ià=¶ X¿V Qǘ÷R:N99)ãf×·`[úúÖLêÇnÁrtÀØãqYõæÛǤ‡“ôɼøCŽ"ò™¡“Vn)ýIš–Ã<ãI&zf¤éú¤# ÃÙe¦\2_ÍÓ_àYEIÝž'7g5Çdª¾½ýÒ°qº$¿P)~¾#ÉÂO¬³ƒÇ¤O=ƒ ñæ·¬—ÄP%•²m¸m\E<ü´$^n }ÂzUÞ@øçv>bv 2…-³ã’€€§ÏÈ+¤âØk‘ó+ïš[dYÃäJßF¶7~Y¥ƒ†H•`ž\ÂHSÚæ k;Aïúš6%ΔүÀºc • YÔ €ñV“&e"ÓnL܈wÂjlh DƇ^[m/tÜÇz`g'kIòªwm j~ºàõMm7åÜê·ÒºŠcÁ]zV gvÐÖ<ãK[éI­îfKIˆ :#@«“r0ßÃ9¾óà$`·ÿ³ÍxyŸ+c%2öW(Ä}UPÖv™‹#nHFñ¨¬@<žPe|_e'],T| X6p€é–Á­1~6ÑÈ[,Ú´òûÍÛkJ ÏúriÏÐ 5Ð 7ö×Y_ÎÚPÀééâï¼àækµˆ* âê‡Ç– œ8 †$Ÿhë›ø¸9Ël³:qès>¦ó"þR^£µá‰† œº¾W ù¤“®!"¹ãO>Š#“@®%Ûo•úür‘L@ôÖ§—ßÛ¸“Ýð•“á©ÅÈkí fÛkÄY›ñ=¤óÑHúêÀ§eá\^xBø³å´ó£¬‹Šà¥à@u3úá¢ËHF’€€ÁpùaÆ—Õ}Zþrqå8-ä¯;CsõרÈÖ ÌÑ2Õï¬Ð¯pn‰2@ñ¡ÿíþ‚Ÿ÷ŸOÆÌ†°prwXlõÏøçk1¹ „¾©jÅ~‘9É#Å¢æJúo­€W|¤žÙOaä›IÛ×uB€Þ@¥19šñÐÓ=Œ–a»ÿ]‡¼Z†ç|ú…ÈФ*[gz÷/ax5}<49ˆ_lØ!h­3)ÓÒIï†k°âû®Þ>§"âÞüƹd;\y—ÈÒ·s Ôô`,W#ÞÇ™?;÷ŽôÍ ÃÆfJÉ{†ˆ×act~úe½‘/«Q ‡~ß}¨$9|­5ÛÚÉâü>ãî0Ô LÚ ú#íßb”­o’|E’Š—Rç€öb™®­šx6 /:6ÌúƒÐŒDô“Oý(—G'wXà W!Ì›5z¼êç”ðHÁXÈ_\ØÏDÊ?}+ñcƒÑÖCá[Åž ~Qÿàºä´A}ç”×VjbçÃù›tN–ÌóÞûÕ|ÑØ{ "ýí¸­A€•Ï@ΆÀÔ×4!% »˜Ýë=}"ªŒ(¸q|Òî]GËrkޝ©D˜aý[z>ÉËùYÕé#”¥‰ŒÌV•E­F{>´ÈLº1§&‡šT!֟ןÅI:ÿJ§(;˜•p£2IÚ1™¼ÀÙ)'L ¬ÌŸ±œfº–½Ïì8~[Õ1H#´ã©è›¦Ð3Z}¾Ë)€˜OÊÿÍÝæ‰p-¯ôåàÇéÔ€d¶úü}‡ï¤cCw·‘ïlæ}’€€­åûÌàP0Ò‚¶ðW w„ Ø–ƒãà`ß(›B%´ÝqfD#AùdØ”1?§‘ªd÷ŒB7.âlåˆú®¶RüëU€ ŸÛˆÁ4z8ϼþþà7'P±xF(]%àúÄ­•Ç Pyÿš™Î`W Û‡ê”u¸b½VS厌=#³ZhÆùŸ»mŒ·2ôÉD/·¡Ëf.–ÎZ ‰ÔgÇÏ«ù>F¼Aù~(¯ûm)wgܳЇño¢ò0ï” É­•§Ä”1U5`7X»OD·U~ë­‚M¨§?Ô³ÆR’åwIØ&âíñ Öª ³MÞEöï| m¬E#·ûPâ€9Ni°"¶îcS`‹«šžF8€(¹ŒBX…VBÉϯB´u‚Ð)2³×1¶±`Ó¡ÐR¬FyÀóX4§@%Fß †L/H>2Åkžþ=x*ÿtóˆù¨Wd…Ÿ_Œ+ˆ˜pâøê´ç*“)*ÙŸé×ó-r8{ͺ8Ó= ]Îó¦Ft0]é…Y«Ùâø9)¹•ÕY~¥¯ßpÿhd 64`Â0k{Ø|óÇ]2cÊwü£k]u,î™hëvJq ñlÖI½ŠGû(jU½%'`,Lî|Ç2á©ùgÄw®Š~u‘“ß ú¬û´ùÈã=ÚŸ'“Ó nÒ`Û5˜´ägZ[ILªóœéƒ=6¸â ©k “(£÷ˆ@jmÿÏB·O¿b- Ó³›7€oµ“x[Žw¢¿æÊÒƒFéíÒÿÌYçÖ¯>7­êQp-Ý'ŠŒT˜æÿkââã«C÷iÿ›x:%lÊT{%Ë¡UÜ nÓ£Àú‡Û€p*¾ûQîŸ=œÔd`qo^Ÿæ€ì/ý®Œ±Íý-. |`Jø»–Z[ɯ$Çüx›~“1±2†ôø?Šj€ —®M53ç­œG΃Xkëõ@‹í«xD+5†òâ‡Õˆëe%‚Töp\èÉÈ è֎׺Ÿ?©ª Å&Yš«&~¤CYšÒ5éM ›’à*ò|aGU×áóß…&n#¥QŒ¿L;A¬“ê™Ù0ìQGkÕ“éú’§`½]©c‰¹[[Žp[³âÀ3oËÆÕ!õ›–EH }Ä~RŠ}ymØ<Áºž)t±‡¿”±vþí’€€©˜tP» ~)6;YÉq“¬ˆ†]ýÕÿ/Óã{kÒL”Ý3ª§"íe__v¥»ÂÔ”….p8!ÞHµ4-ô‚ö#ß?K“ ?éMÀ9ñL¸ìõ"×ݾ®Š%'®ŠëÇÊt*¥f=â$Qúë9ùÎZûë¿2P©;_e|`á…è;ÙØøqXÇ¥ x­ËÚ™lÆÕX–¾-c;¿`03w^•{d è³¾‚ÇÞòCHÅš]­>²=è œyU²ÂJà®FôJj†Í*o›á¨â¬›¯Ý %.¶ü¯ÐëBÓíúá *6[.¢nMÒ’gŸCzçe±ttº÷1è…·QlÀ-ìòMè æMz+ކ $ßgžß_ûVù‘Û jÑM5t4/0²©œ`7©3)…TʼíÌ]°óó–SÑTAÔè]Ñó‘UT3ç9öõ³Z)H™ûÊõÿÚR÷¦èUã»æn´ÕÊNªÄ%“$àÐõêy” úÇÝ„usçÌUh½jG®·8_p&Â:Û²s©‘1 բׯL-wéˆaÓ&DVݽ(&—y¨¯³ìQB‘ž­pÛ±~«ÅÆy‡ÈsP¶|¤‹«0„ æmÎŒ]aG]Ö¿š6ìƒPž-5¸i«36ÃÔw)ã–]1óhà5£›´)§&ë—ô7åÝ£ 8N׆I\¨Åð„Á@„ž†9ñbûêuIÖ:ÒÏ`´ŒûJQ˜Æ*}Éž SÜ9«ºþú§Ù 8É á·Š$aé¼[0™¤Ü¢½ò{­cÉšvQZqXFc b3Ë)N‡ŸâPqEÜšÝxPt·÷Б>* R=¤kÿû<Õë'T¥ùš€šè5ØgßJeJ:남z¦Ó"–*öDù}Ì­™ÉÇøÁ\`%ÇRµ ¾Å£kèƒ8úý ^¢º‰¤Î6(yrûRÒ¥zhõ‘Ä—ä5Š6tëÀþ³*ÍF %/‡9‹äëºÞ@S훌KÆ|ëñóÒmèL-ÞÞ}1h F²Qó/Ô†Äâ6ì Yߢ[Î\ü™µL1Úâsç‹öˆÆyÁCJVB[É!›i–È0›¶@ ‰²GOà„ƒºªÁÌ/ÃV$é’€€ª1J­æôKWàbضIüw0 »£°i÷²´&·Ôx Pwrª7 ^1ª$  9B$º[ß$/JØ1°¬1 SãZI‰­{Æö­[îWÖ`ï–õ#ÙÀÓzØMøWÇE`²È˜Ãl†Ùx ÁaÊ’;¶ç)`€Y¨*âeÄÇdI'SJŽÇ;òù)RÖ»¢Eé\Y^Æ]W¶ç0#`Ûnß*CÅ44ɺ_(¼bFI”Döäý´ÕG]f¶³ž²}?îô Pï~Šû NNÒËH Y÷ dpLH¤Ä[,cÄϲйߟ:'.›ãä˜þùú‡<˜*üÁa’>®ðªuÇXd5«?!o‘ûä$;"léʦB$žhn=›1ø;Ç/ô,ofÚ”RíIHù«ß¦]Ó(š+c¥\a;ïT[ïù&#QMQƒHŸ°-ø§8€ËD¢‰Oú8íÇWÊyÞ‹„øç$vÝPîÔÁ{q.Ås®”2r.1ì}ÕdíY^4|»úì"·¥q‡Jßzôö–‹Y2ßpH9Êôð}iaÝ$u¦I¢@àë\±¼BæVXò6°Šf.ía¶ÌcÜmám¼ÄX/™šUåþúìwlíòêj÷z9‡`BøÎ…•¾Ü„;Þ3`“3Áç}W4¶ÓÊM#f%G¿N¬Îž‰¿)àwÈî­/…nË{㥻 ôíasn3lÑ„H[øÝU>»ã.ÉŽ¶ÚU¡g¼ÑÛyN§`¥ýô8gjû]õ(?ÄÇHæ'"Yõ-í’äö÷„Eáö£j^°A ?įôÜ |Û*g7Q—tòªøz\#d†íß¶f`Wh¨ê‹Úþâ­+óN[çN)äuŽ£NÃÇÎŒ†ë)FAú9ã\ycº¹mÔJvZNë`y/ßÔÈ‘|RâXÖê½Ò·ªÂ)Ürý}i­êÒmXGßàÍó>åùUÌÞsC«°<7&n=çD…;ç‡*Ü»T®ÃH3B„ ¨PÁ ¨P8-;ºfÉÏ0x,’™4×SµˆÂŒ„ø!ÌT!¡$˜~·Ÿ®Ôð»ïñÔG˜÷’¶pîœën’€€­Õ€k½ŸùRƧþ·’©ÅR9EkB’$‹¯Ô¢b—=§VÿÂÜ’u«ÆŸ8ÿ¾)A°‹Í vèMûŽA¤W/ÎáîÉ>–²û) ´¨(“Í€ë(s6ôšq¿ SsKð<Øç¡>ˆ¡B™.‰HN9Ų~¬IŒgIÞþW Ç×ú°X†Î«ÇpŽL6øƒ(ÉF—dœ<õ÷ 6G"»ŸišBßx/˜®ÒRǼí̼ÀJªª Û…|뜑tð_jd‡‰»oˆø,Sn¶ƒ×8B Ä?P¯9«+Î#ímj ¬õȈ/aûÅÐUaëTÅ£diÌåÖsuéàí‰A];?$5û©ÝMªó7÷fQ¬½­¬_ &pÜ߸1î*tî¥{ +)ll•aCÉ ipžÇ²‡–Yú2qª#W´)™IÈÿ]O÷ì5®|…Ǩ]–¶§ wF¯œ_ÊVŒe¾—äã) Z2°­WM|Æd°öh&Þ—è±¾î§gLŒ<ú~!ö—¨L]t{§†ËBÊ\)œïá¸pìX†«>Šñ*´yJëÓY¶¦µ_ðJ‚K¨ƒÔ)ϨX6h­'O‡Ýœ/]bš‰’Ž‹¸Ôá1_LÕ ÕYj 7ÅÕós~Œwü[Ü $ÂiØaÍ8[ë“Þ$¨(æÆ¸1YQo&ÄÍø«LDž—£#$9i¶\ÖϱÃDJ„1ëš`;íp\xÚ{Ôß2ÎEš­džÁWº™#¤åO+?ÐŽuq~Ìtå *hr'ЕÏÄ.¬§ä­o 4rú€F°ÓJœ0P±–è/гø …‹~“O‘½\î šwÉSQHZf„‰$ª­êš ÔÕGL;ã6?”Ÿ¹LJ¤u ‹£¼—ä…üÑ¡ÔU°Òì—É)`œ§˜J; Årølù¸äÛùí§}‘·–dUžŽç »ží<ÿqÛš!k«yD“K•õ€*¦àTR9’€€Å f¡¸zµéàÖÐj¶:ª†J^ä€'ŸÚj*_öì8WSf¤Æts ó:¯PmµuiRwãñԧżND-Λæp?žÅ ¼`–Í=Õ¥eéûžÛ)„AÅ?¾š ‡»`ì(±ÉèŸ_Éb&û±šKgÕ8Öà=ç½zð®_ÝÚä‚SœP%‚3bTÂFãÂ(áHî'¦sªxŒâÎY­D^Šêlñ½ ¥ aY‹âL´Ó) ßãúÒéëû(ɧ~wãÇ–yù•uEƒ¥Ñ>¶¶€|TSß7½‘H“UÑ “é`_öT*¯½ž$N-ˆ ©?RÈôÀõsyË÷C5Íkí$=íHèpÊ d[J­6“_èÃãlÔ;ÜuÀh/©¼aÂîú¦WÿuiŒH“:ƒhH0pbwÇ:7ÝÇ2ïVñ=ÁüÌæìèy0~HÆ© é€(ú¥µp?n€ ¬¨ú›æéšŽÿ+B¨´üØ$#–Ô«àˆZçádTœOßR 3q˜3»Œö%Sÿfnö%AT’ÈŒ!˜“Ô6Ö—úϹˆ ç }ËÍ`E8xbG`?d¯þKÕøô›­ŽuÈä-ü”iA¥¾OÓ¢ßYúÊžç×)ŸÃB—,”á³i ·Q¤ù™ÔØËµ>íœá¡u¾g&Ê{Ü9f›[ ð ÀÙù÷˜ÔG„xÝYR™,ÙO`ÍŽ)óô"ß` }›<‹]SBv:0‚|îÐ &µ˜Ž#R«§Ä÷m (É—Þ¯¨´äpª?®Œ·qã•÷º& ©Æ3¿~èèÚ<ˆ/î‘w;º &X¥z‘Ï’äªog‡Táƒ3@ õÉáýÅÄFŽž×ÿZ2RR!\¦¾éûxcb3ÉȦ³Üå>HDÔí»©Ç*ιs=WÍT}ãÙ;¼‘HT<êY¹:q2o[e^²jà'SPNˆÀ‚‚?m35ïZ¿G+G½vÚJiïªD™õSØ}EP§ò ùaUí*'†ÙÉËs‡÷“'LÓÏZíw¥Ü?¿¤&ÂÇíw{I亭XVƒZŸÇ‹¥tPŠ@@‚+æhbë…›Óx8ýÙwÏ“_/}‹/¼_8ÏŽß5‚"“ \HyVÅ+ÅŸî~Õ#'1ø2?ž©°­˜±¯‡ÌPk:BÙîÆ› {aVìqŒ.à ’€€¢*A·yâ"kÂÅÚ©«ÿe÷N$ W®1UÃ`ÌîÓÅXF—Í?ƒNíG¬-éi‚ª,ð–O ™[+µ²ó¤½ÃCÔËÃèÿ×f¬q³W³W¯o…ÛÅ_iÞ#©/\/æüεñM“|èÜE¤å]·Iظ—eä h™­û°Çô|O…Ò—\3„ÌœsKGœ\¸«:ØqÒ¹ØXhÑPq“®¯~b´ö]W×B>@ F‰Ý ÙGeS_–\îjWΖº0Úc0ÓB:$›;2üÏ€`š‚ cÿÑÿÊ[ 2Í‚ÿÙ˜nϸ'jãDïÉ 5è“©Ùœ°ÕŒ–Iõš=©‡9—Âê´ÕóÊïÁïëÏ ™XñÀîéñ".Ö%߈åqÊÆ´[f™šÝÆ'mÐ4_ø~Vêü!v7ø©"÷x3¥e§â`Gq7ØÿÅ’ 5åËÜ%áÆrÕšf¸O÷¯3J€öý®mÖ]JNëmã[®~íù² b™Ä ©k 1LCçá-çÆøÁ“Æ¢WÍ„ ÇÈíìPê%ïW¨Ïk;ôvKày ]ÐÕ8„ùöC¯b!­Ò—¨äà¨mHÉ (¹š@÷_®ãèµAõ]Z-êЯ½5måöFw®ÈÕu)~½`\I³‹d§)Ú;DÕ]_ ½ÕT¾•æÞ'u¥,.@Ðàc­}P^ ÉTÏãçñÜ[*ÀÁuMçùZ ./°ï…wÜ*i»çi™Â*:½Údð1, ¸üásFÀ£‰G¼õ}Þ¢y:Ïþ•yåƒ|KÄ»}v¹§Á<*‡!±­-%”"$Öù¥’¯Z¾´–™¥+1 ¨-ÁÇUštpi¬—0[é1×_4 B0ƒ  ¯§·¼^«øpX›Âj~åCÑG4ø4êÔ݉JñZ$Rýù™^™Ã²‰ ·™­²k ›ÍhÖFg«»ƒ±nåAc(%QŽ1l…þç˜fykÖÉmxZó¸ð%:Û¾F@²Áê˜%a©=º˜l5Ætvõ›¸aíuÂÀW4_*TѯND™¨†b ªÛO‹|]‹èÀÓU¥B^,:ö!:ñ«RÐݶÛÃA“ê]ƒT÷Ù ¿ KްDÀ;;bã²OË’€€ÁR=ä·ò‚po:>Út…”|¯¬Nëi0o2®qþ!›“j~Ͷ"»æ³¿óaØ££Íµ6ŠÃêS`§,Ç‘¡ >C•rÒ0aGU-Ói’‰Œ ïå@*|ÓÁ KŠìlLpÏé¼”àiJ®Ö¾;ÿ }e7ËûHWäàŽà *`ò×åZuçN,4yŒ_ÈdkËÌZÿÆÞZˆ÷¿R2ßÁOY0Ä*£>;J‹6óCn!ú ¬õ2síþq=:–Í,fB˜l‚ð gR]ô1vï-­tgÝÆ]º63{-ìr± `fN÷Vþl¦JÉw]_ÇNðFó{Í—§ap 7G©jgV€%&a É1I%¥„ CÔ²B8yø¿¦pèhG.·l1Â{Úì¨eslê” \#{ !÷ÊuÁYKdUÇKŒ8×wvOMóXÚÁ¢ß8Ç´Šzص®›JÇ[ ÈÎêíF Ú°à[Þa9-ûVOŽàTìÑ™M&?n?pì/Ù<´FÔÂü>dÍÈG%†~NN?×–Î’}Ȳ¥±º ñp01æ!°ìÙü]‡ãpro4¦yqŠ÷;F߃ ÑËxƒÎÓ2¨jm<(ï–›½ly ²Ûlâo¾E¿wóyR•¡ÍëìÆo‰W¤xûå4—ÁfLeåÑbO·)gIÒ—R´FÂÂ÷"jÔ”ê÷lUª}³Æïy™¤q2õÐ^%’oA€Ö7ÝØ € üŽE ËËKK?¶9¯¸››ƒÚš)wR›Þ ^–ˆóƒ±1f¥v.w-MXYÅ.KóJQ\µ[ÁÝK×ë¾6Þßm´œf­«ç²ŸœÇ¬ŽA°k &óc¸hMŽ&dRšLæ~-i¸lZ[ òÙ·Ä. @§SWÏ,Щ ƒë{$άmæ“ÈEUºôØŠ~¬2ÝzäB©ÒÊÔ|ì¸éìžyµí8 íÑq¢Ð/5Ü®I%/˜«Lé14Ù üM…’÷W#@ L…€õ ~Ü¥ ˜Žy ÕSé–D†‘æ|7rêìõW4P§}µ}{ÃÊÊÝ5píü„¾àY—’ÑæòÆç¿ë@Üì(øíì=ËÁæ/ÈÈçÁÒ7Ð9Ì¢ò”õV`"…õ—ܬ;RËPõá¾ÃÅÂuÂW×S,°kð£e)ŠõJ¯üÝt±3%z8]›Õ›9võ!sL‹ùdeÏÉ÷{„š4"vQ™gƒâVæD”ph\Á«òQG%ŠÔm­'ÑDÉâÙ-X†S È€òX—fœ½Ú‘çkÃÞ¨ÈÁH§Ô<ø|•¿ðŠ…U´‘BEVý’­•°’~4Ôp4™—À¢^y6õ:TžÝëÝ´™VU ÚC[ îÛ„î ;þ[œy•ùeQ·ÉQêÇW²§1kÆڶ£Èß—ã?CXæêã¤ÓÜqéiÈ@Ÿ_a*ˆ]‹Ë[¹0CåíÅ¢ €XMà*Õ6³ÉîO¸Ü¢ÃÙÁë³í³N<ùKzZÍÊL:)ÍTáÕ8¶$öH%`sµò‚Í?b€éê‰)deÄ`d0,×!V)¸nxƒïÏ6Î˵ÜÐ0€‰ì°Bi "!EmkCÀÒP©ûItã3n?}UÉtèR'zÙ_G·NtÍ™ÇÝ µâ¤w½1@BÖn]Qœÿ›0üýŸûÁÞôÝ*ÿDXPvÜ·¨,¹Ã’tÏ9—ž=¼2ôÁ¦Uàþ¨y–ràðç¡Ì'00‚êt¨ÄLþÔúJ;‚U:œ&Bì9ž•¢v—9d‚­ñ]í] ÆÏtŸ‡¼>:µ³Òì’Š‹-­"©{÷ÓSdS›šÑ`Ï,Ôm ùWAÞ6O8£sÆ×ØþóÒÄÙëz¿Ô®†ƒ±HªšÄà}$vH}øqý4ä`a©5ÁÓJÍ]— …O"àÝcÅÀ¥Ê{$öŽÃwÅwÓæÔŒO@Š.d«º"œ«¥äÛðÅœàÆ›^—¿ï¬=]ûã(}EH&GËT·U½ŸY„Ká…Yc»´àkHpÁ“a–T ƒ^B·`ZAÇ÷§{^çÙì#P °YÎàIrAjéÊ×–î®a$[#¶·W„‚…äy5µQ€J¦Ÿ¹‡ó:^øÅ`/5yS<Ó±}ß×"(‡1E?šukTE`e˜z>èÚ0’€€¼³Rm²1dðôžàìÐüPh`}£|ÉÁ‹:bR7¯«“†lΓ±Œ—tsOØ$KûDUÂ#¿q]Øßr»0‰íTõ5hã’5Ì š­ù–…ÇÝý|î¼B†|ñc1]7Ð ìåL&"·Æè×U¥”tÜ¢k'{P’‹Õc à‚n s3“ …c9èpµž ñWìYÆ33àÿâiYütç©¶óÙlU׳ ~ðÂt· z4‚¾Óšài½Z«tŽ[]͈¤›±<…Cky¶ªŒþ–÷±o4—¶&hæ`†åøB‹²ŠHkï w,×Mçg8ZU• 07¤AÙ•ôæ`âx\‰‘á&£”$åÖ'üÊÀyႌªN;†tÙrà¿Fiu “•ðÇMN‚x^̃ ˜ +8€ïþ hLž;~äÏNèŒqÇ’Y)Ç™!«Üé›ÊÑÖòS>)ñgëêip¬kŠšÏJͶa!èI kFþùùâ"€û%kÐ~ø½iÕ²—õ†²²£ŸCýh)Dg×ÑcxÙG+q <S_Ƴ¥M»sŒHavq2B}íÜ®Á{/ÿéž#¬„”nrY¶€00’Ýò¥†Æ‡C¥DIwZ¼yHÈ?q·8.uRžyîcˆÎÕ a9‰N@Ë~å‘J¯õR{æBÝ–’áX ùnTö¤t*–fŸìðdÁ+P®%Kl•Ò¼§,¬þùfn©\/ÖªðÍ9¤™á5z–]üM().‚Uè–… ]ã*Û|ñV£æ=ÎÈéû¹¹T&9Mò^CXoœ‰Ê{ÅlVÒ ñ\T EÜbuX=é§“¿¸7Û -ŸÕ’¯'’ 0¨•Bz‰îÉ¥î¿ôS‘üç¦{fžP ©2PaG‰èmígåÛåú,Òû¯êåjEK§äs K Ø6ËU.¥ÇTvp?^ÚäÔ7–éà âï*ïå­º'ª xËOÀ:LÃß$ŠN%V‹.•ŽûÎúËÎJ– Þ’D[ªję⦀dÚL-ê1°ŸiùmC’Âý¬0H›ÕÚ>VáµÅèÆWãq,&T%ö‘⟱íõ^µ >1õ2ì¬Îô6Šçвp^’€€ãQ°dïÅ“!s ÿi¤Û5ó:³¢ ‚Æf$xÔ¾1ïæÏ%dä?µh•Ve´Ëê­Ð]6ÛŽv€òOâ9T ¿—‚M;9më]‡q”¿l^ßÞ›ë/%m9‚*ÖÅél‘_ä'ÔÊe!±¼ò1ô>»ÏØ¿…2WQÚÒ?˜cKå:V'ÁÚµ¤*Þ˜é™êdÄY6w„T1+ûªÅ†߬’~VĨÇþ¨î ±­¼Ø¼sAi¥®ª’÷H½Ñ êUvåYŽœ…e­6<—‹^ͳ¹Ó`é}àügш†B@âž4c`ËPMn‰»†­sæÇ9¥mdyô|-xùÏ.'¸ïÙåõˆç!}'_X Š>õÓŠ…ãŽ"øHÒšÕŽ]µŒ:•›¤ÖuÚg5¾Y°2¨®"ÐóÔ߬jýº¬ÎÄ÷_MÂñ:jX«*îŸQrmã!â(žO>Aì¶“Pß¿[ív3šrbÏO]A®!RY¹r~Nî/…ÈÉU ©µyîC‰"lÓÉ™64À†051½åÇdÛì{ß™ü)W µšáºq²±0Îb¾gdî1ÐæDcܦš5;4˜ðàmMîBÈäáÜ÷Ì}»Ìoëæ¶*»Iœ`åÀ,xìI¼»ç”?ðGh“R<œýøJX©R‚¹ÜDW;RsˆÇ€5§â„öÝ Þ¦ç²DN¨ÄJï‚Kñ ¦EŒ¸Hº%èg—ÐSP¥„sÇí›ÜµŒ&ÿ‹?˜÷q¼›ö³þ]ÉSÕ¶@=Þ¬ùnd‰ëQ„ö$4¼¨M]}]Fñ¦mI1‰zÿzTl•ˆÄ&…jóꪀÓܱæžXÍÄ™§÷?I\¦B|vâµÆ¢äÑ:Дÿh( … 21ÄUë™Ã>7T‰¡€7ª©Ø`€Í›[ÝÄgæ°þ¿Ówß ÉtgÑãŽÒ•rÿ LT-îëš<©À£º±Nüœåv§àVM}Væ$nã@™›sUŠmÊËa#5ßïÏ3 C»p¶'²Šb]v0R¨èeÎÏHäv×›`ѯJ^¢ G<°J¥W@Lú¤ÉÜχOß<ñ¢ò dÜ:/6ß‘+Fô5l‹·I„ðýºaú¯uˆºz*ñx/‘ÅÍÁVk ç'2gº.Sò ބʨ»Q.$nr%àÛ ŸÃªDåq`;ˆÆ<þ',3aß¼Þt[$´_¼–D°˜Ù`˜C$f;çuÚÕSá2”>·’ÇÈ,ñ|÷ß>I­{D}I„HxSÜ~é`>NæµBÿ?TcŠ—PÓ Æë´⸬Њ#Þñ$ÃÐ5ŸùïÐ~`KGš¤F!ùíÚ'B­#CØ®L¯Õ6 …Á:È.¶‚ªü^ÕpàkhßN÷|ã I‘r=rÕFGޝ‚ç÷_á!I-©Œ¾Žà ßQ¢3ü£¿3RÕëq¤HÐÂŽ¹Azù*ƒýfUMIÜ)ÙcO¢(TÞÝh·}ö¾@ å_ðtÛ;Ž8®¤·BW±E⦅ªÎÇÝxÆ;¨ü¯[[Wšâd‰Àœ¢A¿Qœñו‚kÐÄò|!MǶ TÝ6¶z¤þv¹ùÐQ!;ÙbÓ‰Ìv5°_ÅH§}ßj𤦪m Oϲ×ä2:;JõQüãîhÅ5£ \få OÓ)órZÁ¹¡Y4»çƒÎò·õJ–ÛŽîUøÁk+F¸ûM btõÎìÉJdkÔ2Ø„ð£OXûË:Þâäj´28®xþGn¥è’€€Ñg\áè2Páüä)øKÙ õÓ¾°ù¹Ü %g•ü¤ ²ËÀ¯½ØÍ /.qŸ!ÝÂüa) ˆâ=ÿÄ+†ÊïZÊÌÌçó /\YÚÝú&Jcu«áøž8RÇjávãiñF_ë|KefÈVA€ÒÅÀ¦³Ï\°©R¥«0’bF ›ˆu‹²·àÐÁÔ"Wrßnl¥P»gU†tæ;+Ójp”‡-xúrG–FMÕhÎFwrô¹u+ bŽpZ×ÏÌ?€?uºéæ’`ëu‰„б r~{£wm®§_}åŠê-ÙÝR(mèR[ ˜C4•¦bÏ*¥ðÑ¥8â))²˜àrˆÎ¡S¦î¢ºã&PFƒ¬‹Ñ)ÌHCí·‰N9b@/A;Š NKge?;V.ŽÿL¹B¼éWò>(ßPâQ á²õ‘7áXò¢óß×|ÿ+ô]ÓDŽ[Žß[lõJÀû-sa ª`¨U¦[ú†9D„J¾?cwÜr»¿îŠyáa¯e ¬)E_‡ÅªÇ帚ü•‘enŠ^‡ð *´ÕÒó¸\`M8‹Fÿjµ±–OWD`?©,ZDVJS)ÜÇø~ø§W™÷VóxZI?%  ÞÍ«ž3?hTŽƒ‰Â¨6 ˜ÑúŸ2 ¢*´+ieÍç›UÕEØ– Xµ4áž•ª©ôç7IÊP&$Bÿí§ÁD<‘Mt.xáb°²ìƒ¬Ž¼]MŸŽªñ«‚—Y|&Ð$p“dôÂêÎs²øÂ%¹‰t£vF›AÜ.2G‘j“AÄx;f/ßéæaâ¨ýCó¢.óËU1 Ù5ö•Stð‘´¹òA[õÐÉͺðdxú5±CiÃÆÒÞsm+7³¯ÜDú˜G'ÛPÛâ@~ ¼+î¬I¢­ô qU• .™i{Æ[š=ŸB¿š \esô̓¢Km‘JË“å¹pQ+$➀¥õ¨!ükó/cûòúlƒNãq€}-—N5íÚ"&³Ÿ÷Íï`ñý=©“«mg¡Ÿ\›çÀºçÏW´`¨µ*â>¯/c°Tå\¥Ë‡s s’a„ZˆŸPžiPPt?³¡Æø‚DÓ¬šHà Z/€§oEƒÒ? ìÔ1+1æÝÚ”Ÿƒ bÜzÊÈVwŒò¬1ÕT¢Q‚å[#• 7– Ê ×9A)l¸õR´[WÎ…¡øÝtÞ ­;L˜ñ¬£¨’¦x¨Y„½¯ˆSéî\sy¹ý(Cæ¹-¦Œ<9ýÛ`Æžtk.gÝ`p!gÚõ7¨4ZQœLuë™»W‚4$vIm-mÂ$®@#¶‘î% èÍö¬Öõâ­W²gøNÖ)‰< óÇä­ôø²êþÈÙí¨¯eÓrPDÉÀ«'?«Nš ÂÖ Ï µÖ£+¸M@3EN¸|A"¢k7LÙ˜7™å…¬rÖ² €Ýa´Úá˜àÓÊR ’€€¹?7,4R¾%¬€UEr n©Zæã¯üoµQJU4?ƒŸw~zè7;»êÈ"g!à„¢T®ék¹÷†8Z0Àm&ßwéÊ1E0HÑ%áKyu™½ù%`¡ë¹Õ|wX‹§ Ê!fÝ%`Ú5œ¥ÍO1h)Yÿœ/SÉ{ J¦nÐUÆQw ^'/“žf9Åa¼Y y-¥+6—¼S7{FmÞê t˜FìU_Øáz(úÆz*e ?Œœ0¦(~ú rëlÏh`VÌ{^†eVoëòÚh5)üó¥J”<é_’Å{p|ú[Tí§ i­–®÷vHÝ5ÞÝ’ºh+ëuõ‘ÙíGµß+6C8ÿÏ‹VÓ|M­@#c¤ãÓäƒ)„‰þ ´Šÿùy³õbÎ>ZÊڵєÆ,ÿ!ð.nl³O¯œˆðÜ¿cb‹Tñ—ÈZsíƒ{µO2ˆIæV–šŠâÂ6o~X™ÔÇH'âÛëbù•4K±VdÔ.ăšdÕê¿7ØÓëIK£ƒr•òÌý{¥3þø|Uç.i‚Ãç “q=ô·ÂÞóú8ë#¶`Ø!þÞ4S9Ð.KÅ&K—lsè DÐÏØ.rµ•ÏGÁ³ð$Hh,ÚÏt ÉÃ*©'»øÛˆÌÍôºlÕê ¢YÃOê#±ZÕÓf#dlŸ×ÁD©±*Pñûa¹·^”Ö!éëâóæ¡x]™ŽéЖÏrè›ì:®•ÀçØJ ø“)»÷\€ ÷ÓØ P a#ælT…ŒÌ&ͳì­ó5íCìÓ.¢Þ°Çν "<ŽÈ†QÏmÁÇsG¾a‘a¾dî0]žß@ 6MªƒáÉÔï®™kå*ÔN«Ýa›Ä‘öo5¬§“ŠNô%J¼­ƒ¥Ñž¶2¥yåK´™PÓjIûŠƒî;¡t/!e9™°M°äãs¶ÍA²±miØÅY:E_ÌØ¡ÛØ2š7äý»»>"×°Œ<ãÎ,Hƒd"‰ÙÝÉÑòƒ=[=ÎÀ¸×¢éÃÿ,¬'«•‡£ahÞùJ·‰,ÉÒçL [Ë×Þ Êº^&“€ˆ£”Òþe1´ m:|ï‚x»KZuøjİ^‰n×Á{ú°¿e LÚ.:Ký“¾‰ 9"Z†}°Ê]—jzg_B¶!ët.‰Ad€_–¨(b³Ábò›þþ:5nc- t7—jðïR`°îeÓ÷Rš(1®8PRÁ‹W£Ž‘¸ì½aå#)­ß²êoÿƒt«¤/ë+gØŽ?ר¡ïe,·0RýÝl_¯\ñÄÝÿÁ½ÈÕÛ*Šlcq¨%úÙz su°ôðC)ºxê[œ{Ë~Tûs¥WÛÏ(dÞ  øëd7bmVkìÿ ò $ìEùyVlnh•ÔEý¿`òH@)§E2`` ô-A—5Ý­›Á ÌfýhJ2ß á^:Ms´'é4þÙ'P·Gì)MðRã¿$²ÃÇ´õ‘:ÃGÕ ?dËOt…MSþÝ3ÆUqÇ|¦ ;Å&Dâ«ÇQ_ë6:Ç5x…@Jôû€Äm¼;v§²ñdä}3>1DB•Λœe6=íõÔ‡‘mçs×aüòÃÂ6LÇ©ü×ôúg‚ÆjÊò¿WuÝyP¦cË7º-zO÷ªä„£í¿$Þ ê‘Î’»)‹UhÔáf Ïz<¼ÿ€%Zª …üë•PîE‘s¢1KNœXÀ ™£#7,ª¾_¹Ã„FXVÅ%±Æ@‹³áë¨À»zL´nGáYM›ÑWqòu[ãQ)ÎH³’kMu·A`èµ®áæÈ®wžSúHqiØ—ºIË]äâB#&bR¦Ìt7é0–qÉ·ñJHy Ý´:ÚÃÁv_}ÏV/‰³ã¡xkyœTšH{ ¥ê½PgbWvG†^`…q§}CLŽ}aóÒu£Ê4_Û?1· ]<ƒ;³·LS–РÆù˜Ö¼Éá(è§ ÁBÏK†Ž~ m²–2úm›øsþÕâ^YÓygî¶?'rð6Cì;<2½\JvfÃ/É·œ‘\Òý1Y­Ã´YÍvÛ Çžœ[§ºÓ†C£Á «Õçl3;>µš:é ×R¹¢m/¬’€€È5Y¼É÷ŠêAúĈlÊ·¢ ˆK;• ùƒæG_ל_1<.a/BïÇ´BPœ¹Ádë˪É#£‡þ¢FOKZÓˆæŽ×­8ÚÌI„ûRš”Jšþx|W¦Ø*yt>\SIÆú¥R9–òtÍ vµ5‘u¶­sÙ`Ä( ÞÞÕn4sbA£VEÙ}#å¼ÄŽù\n-‘”ˆ£€hܤ†îéèð#@ƒÙø¸¹*תyf½¥n½ºÜOC WC¼Y¸ú¶vª¯]+á°æar —Éjœ€ÆE»Íãvûâ2èƒ_Ž$”>¥Q<#†”ªm(=MVëi ¼Þ´ؽŠåSk-&C`–ÒÖQ[ʉ>ÝLZ–(SÚ,õ´ÉQñÍ·`Ôká[” [¶7‚Tj\zWå–[#È¢míù´;%É!¼¼Ë*¿ï ŒqÐorÊÙ·µ,åbCJÈ&}“†°Œ…ýÒ Éê<œ&E2õ B…ŽôpÁ t¥lkÅYãæïõ^³cd늴y™Æ¨pY¤*3F«lc6˜.øm W4¸g&µ—x¾²ïa6jÁÜmÜÉy ðJg®‹ùV Ù¬§>èb@¿%ÎÈ ˆïtŒ{Ý—ÚgGSg)Ï3ZE„¸<4£«øsãÛ"ªìFËöÓº.Cøx|0N°âñ^õD­Ûð#06Ü@>b†ßµ0æçϰ °Ö2ÕÕÊ›.c7F‚0N&|½K0¿?’÷O¿íw õV’= …Ë“@󟜬”Üd¬ßv0Ïž@‡y§´º‚Õ$3Òüd1CƒƒÌëàïý¶WZSK8L ƒï&ÀƪÝPl>e5ÁP¥D9b3føæëO§¨ÃåÜÇ}aVÃwZäV³UÌù]›w…|¢¯³´ð5LŒ8¡Ž85 $ÿ { ŸÞùDT棻$7•˜œNUfÇ.¿®³ÇT±+îÝ™2Ë_H’Ãû»hìû½hB˜°½¶ºñ+Oi†@¯X$EËA⯥Hu¥\#o‘ç½¢;¾ðدL$S»²ýGdT\iCR¤BZ3W޼³~šb.ÝN©Ý÷Úį}Dc 0“|&ÌõR19¾ÝãU%©æB‡þÌb¼æo3(kÄÿ-Øø'G$<PƒÈæ¸W._Œ0Î+?\÷e2H­ê×8VÕxÎÔ]ÏÊû\€Kì•­pgíß„˜~RvV5ƒîÖ%o-©Ô¯‚3Îqv‰xSS ·oÁaFÄ9óìÇìY^;‹DRø±ÔJ0RMÌPã8Ð%Úf³Ì°ýôç'’€€¼DO *s墴ƒô &×ÅÖwœèF>kò/ç!ÚÝDHmµãâp†þÚÃ$æ£QU“•\@Ÿ,+‰Ã™’€]žfóïóœió#ÀIVò*ô! `¶•K-ú@òu2WI»èÕ¼Òp4±*ÖÄò硚YiÊJŒ— £tþ)P‰©¶ôR‡~ô …üï^}Û®¦ŸÓRÏãn Úo2–‰òÓ§6]±`HnšêÞð¨'±Òv7ñp*Çœ‚tÞc† Iµ^¤ã@¶Î¤_ «û-s­€™¤ìo5Ž|p["¸Á-Æò=5uÓ œ·~ ^ˆÇ `ž†‹¿CÂÏ©f~ØpÙ`M¢‚í ò ,çz–AA õ€W=µv´ïIÏaG–u ÇŽtnüÖ¡4%^££‰sûfmNä?žÀÅ>ºÓ!bw°øqqy}¸9U£N[Á+LO ¦ãA$|…#åÅø‘rˆ¬ÑÆ''‘ëçÛ{ÐÊOP¿0J Ã9iæ`ŸçRÂB«šÎ #Õ¦vS#ÖýgüÔðçàB6†Äm¹3ßÅkËZ~ÃZôStNj&¡óÕðàzׇÚg¡‡ÆàmqQø.» Š’‰l"ÀÑ&ÐWŸ8Ïœzû}‚9 æê_ÂÍÆæ×b9¡Së(Cî©™ÍôIJ­|š¢we‰Õw"aóÓˆ’,÷¬26 7ýéGÄ¥3!ÑUè¥$RÙò²rßmj Þ°„˜Gç5Ц×UT ÌN‹±†·Öߟ×}öÌF•éK.h—ÞÂüz8fLt€äÏ|2§Ì½BRtf3ªûÞ•ÉÓ5Ú¹ÛµýÅK/lÓÎj:ÜE\ZÌõz¾rÇ«-' âcšVyû³“ˆEÁÜr@eÎîæ€ñënv…8Bvó ²N»†2;Së‡þüeE7õyMÒA.j:ƒô†ÝkytÒNø’ƒ±oÓÖ3ïÎ ®¹AãfЧžT„sí­"¢×kµ°ÆrÔ9ÊSœesQ¡ª«Qv·/áÃD­”•ß)£·ñ`¢ðë¾4ap>ªº÷³:î`“-Žz^¥ž^Õ§˜8Ü­"sãÍU“BþV™ßÞA+ã¢Á¹ èÚØŽç„ùTÙ6SõÎnŸr1âá;Ö験¿ à ;¢ëP(1­E ßb*’€€¯#ºÉyª<½JÜu+ĸt ®T«:“=õ#üûEfy½¾¬§ *Yg—þsü5E  Ê|ˆ÷àozC!ΈÍ2Ìkb&©Q®`í ¯c¼’ŠD)²TÄw­y Ãëra_ý4¼Õæ™ ‹04]d…£Ú8|¾]­ X†™ 4¥A©†”T@ÉÅYÃ2I€`œZ{`‘²™ÂBZÕ¹WŠ_í7ô’„8¼¥ýRH^Sy7šž­š*ï}cZ°‘­?Г“áÙš´mw^5wÍ¿ì¢1.Eò ¿î¼ ÇDz„‹úÔÎ Ô9hÑ þ×íÅ\°Fžiï=">›ü´¥';õ¬‰>Û8<ÄôÙ­Ak'Eô´æ{ÇsèSg,$Ë@à¢a‚K¼’Æ¥Å{åWÙV÷MÜ'Ù•q ¢g'W9$P) IaTjWÑY ²SJSƒ=X‡p)ýI{§÷Çõ5‚?¬ÔˆlHì¢øj!µ>ØæìÎ Û_·›õ¶Wbéiá nÃ- —¼ücÔ…¶+If¶ê ‡f÷b0Túâi;y¡ïî-(?ÆlˆýHYn>U9^È6š Mg®µ¸@¿ë¬+Q[wDä7-V“¢4nÒ[Fîyΰ®<•¯dKôð›Çî-úÀBò\~uÛÿšøš‚–3¹…ÈÛ)o»«º ®"xí0@[¡à¢‡%[óÄù4Ð~ð-÷ôªfž:3‚nþ—v×Hh#º`…2Þë%£ØÔTºm1û"r¯<Š*$¼¼œ-h›ÏÞ%ͯ¹xeÎ퉣÷Ã}‚_¸v¡·Æ—Õ~Æ!ÀÂįËÍOÖþqšXõËŠãŽómû‰J£†_WªŒ­†õq­·…2ÒÇKÙ†ý ÿ••T×ûÇLŒ)‚ à´z9É/l% ?‡°aQÁ×hHÕÅR¿cKQÔix7™R2ÞïìáSnÊ$Šdµ[h0í´Û‘ºšºu°vÉÝ/á Cº›mDý|ˆ‰>–gÀŒjbU°ýé~7õÈvþÅÂæÀ¢]Uy;[­T·P…±X“z>»Þ|cΓ¤óÝ"¬J"dšg?ç‡W\ë>v˜N…ï‰u*±{½'UmêÊÏ ¨O]FÂpÓôßù3e¾~…~èš:ÃÎH$'­·²áçÚ’€€ »f±Y—a=1Ù%RXaŽÑïϸÝ^'÷k>û¾Þ fPïX$Mý„`xT’º4δlK Q–Lñ·Íäp~ vtð`…ßÙüvªT9²€‹HÃDw€(̦ÛY‘9‘pP%•£|†€û¡ü°I¾C”à;N¼?ìzcSr$ùåø*Oä¦Ýp¢]·!ÂöM:E¡D_m¹]P~‰ŠÁ²}Ùþe çÜ2g}ƒº¼[o7z;ÆZžt‘>ú¬1º¶wfrŽ…ý½ 6Ô^ÇEÀ¦iÐörþÅo ]ÒëQE%!«ù¸ ¾X½ß>ÃX¾çt5 AëM+ƒ!´˜è\C†°+Þãê$v‰—8-]¢ÈÔÉñ@pcξ«œ7°È%à>ØÝ«˜¸‰,„ T¦X“æ)¸ÊOèýËž$ ²¥T“ê©e'áæ:ÖøÂXª4/}ŸÇ‚ÉjµVã €ýñ`Q±³{äÛœ(…³Ü¡þëYS^o²Ú|ut#_ßÑ7'¦TÞ_l,2?=M›±¤*×hDÊ‚“¬Õ¡“ÌÞKè´–×'™ÇGÌ•-Û7öR Ø• Ñ{OmûŽºUè‡YêxÄ ½Q‚ºiŒ ¾Áê.Ò©Ø”I}W {n—´Ðr(Ñü¦%žcl>™ÓB«1Š¡J D#Ñ/•ÙMG€ìkeŠSP²Ï#¸¬r¨É·koZTst¸ŒW#ÿ“ê!³€…έy"2AlÒ\g ž¹~àugë5ksxï­[ÏjU©]^èº)SRï±v„ؼ.ÍÔ>«­üÁ¢TJüG-¸ö ÿÂò6—_Fs.UÒÖàÀG¦ç,GÕ–ÛŒÚ;x {¬ÕýQ3Á'Õa u#i´lµàT9p¿‘^2êµZcÌy@îT9÷@äM l N彆4òqðµ\¶s‰›ìš¸öƒ-ŠGë!øeüÕq›- H‚'mÜÆ’¨»ËŽÁ–$©k ¾Ù¯#ªÃ´À‰M~àLýÚîXžuz ât¸í(Äcî^zΔ$,j jéfÆ •hµï2äd/I?RUÔ8ÕãKÜñG\ŠRIÄKÿyî&†ª^€!SÈ¿ºI7,ŽÊÀØxÁà1c— ¼`ÄÏ83éó‚’€€ÊÎb +W—ílú‘?BŸ$÷FãÑÖ£\–¿/« ñ‰DÌÜM×Ò4ŸÒãª3Ü0¸É( :ŪŽGpõg>_ϳ³‘Ð ëBêi×Eg5ßó SOHqâɶ­ á—!;~4]!,Ê(ˇê t¯ú8Ð#ç&Kž(²óé‰ëé<^¹ã)G·ë¤/€­6½Zù㼆’L*^iÒhpÖ]{¹„«Ú7‡¬Å`–>+¬‡Aèý©#Ü"ÒűwÎTdظ}•=#ü šm=i¥5*qœ¹ªHÚ Ãù\¯Ú3Ñ=”7±Él#¸(Ý'1îÀ)_‡g¾æ3¡x{¡ZR¥¼ýƒŽÑ‰­Ì &;WaÓJÒšý M?{Y}à%ê&æEÐ=•1¾x‰ [L$¢,ìê¼ø·f±q–SΟ›e¦‘bãŒ«Âæ–\‹»]B>´,·½ìÈ~—{X qﻺ u ^æð>õ{â†T&Ë´³ým\Å{žÎnmIôDj–™IÁëÚ~<;§Sf{–I]¨J †’žŽÎ¨4‹Òéa•Åm%õ±¿õæo±Qdæõv…é7äÀ¥©¨ìZ©.ð»¥1 ZÍú\Þ>ÙïsŸÆœçíææ“:-hpcPй¶ºY7uO’8!Ü–ã ÂÒ Ðfæ‚"Î÷é2J’¯ ]8±Y%¼)ÌÑ–NÊÎOÁÖ‡&º´/’Q§˜„8ª‘~Â|Y•0ÂQçÞø„u’ÏŸª¦j¬ë•»7kŽgcE—4‰­¥ÎT÷‚u‘6d§EjzlIÕÆ¯ƒ4rHOÉÆ›Ù6@“º(Yp†¡Qü·¬ÎݨÊ dÆeî9SfYço’¾&œ .T6™‡µ|D“a!’ûw• sÏ㼫XKÉlׂ[ΗajqªóWTÇ|²¹5ª!/¥ÖÒFûÝÞ‡\ŽÉ…&F• ο`Â6óX7(ñ¨4ªH@1_HøæE©›Šfߢ²‡æàÍ;ªmÎó1§cwƒØ]tMû°}2ij²ˆ`áw²„“/©uõÂjTÕ"p8B–›¦~4¤íVœ’€€½ àÝ=øæ" j›˜¨ÚÌ€MP³MM?hHjÄ‚öÔ6"Á¡Ê ÁÚi•‘—¤ð„ìWm]29=¾$Gnòñoaã/zÅ?l,Ï7à••sÔ%÷2ßX«\24o `ãùª@±‘{ e‡³%™ –›>ŽÓ sÖaôl¦&Sq\sòAœFMä¬7åäå#A8­º.×£”Ì2ŠO!z½É'dü:cˆê¸(ÚÎîd„NXNøÝtz4š´y_ÅÁùTüï¯(Oö#ý4¹Æê[©èÿ]$Ó«L.€ ¼˜ý™t3A"B&EPwiÀØùï²æúñš{â7TÈ¿ðïqýÉ-¼E}Ò|¬„ð‰è·žL}bfiü©.:aØŽî ²½Ëì-5X‡¼š ‘€Áä¿”CCÒ8TæÉ…ð _˜›ÒþãHyGìs4ãíCÜø¿rª‹þéÚã>^… :ÊrÆ:˜†˜SÍüÖÔí‘–£¢–¨+¹Î„ÉLÔ醉lÒrIåŠðÉË$²I«+ ņ;Ïbö”–ÙéÇäÕ·+Þ"=¡sßcçc¥É4çŽ qŸñ9î ˜¿÷^y‰Ãqݹ!þÖqŠ10G0ÜZ›“ö©ü#x5ç„\°bV›Všéóy\ò(øÜ¥õÒN Yûû· ‡ý´y܈ù¶ºq+½ûÁ´)G†¡`¹’§cñËøÉHÈ$Y!¡ø©SÓ®(®¹i–m´ (E½O¿‚q0»ü„·!AÑŸ‡/!$ëŒÉX“$IaÍuÙ .Ô%o¬ŸÝɉ ‘&MöŸ +¹›Åzî HËÚV2âpõ\ü"Í.éª7ÕV÷¼Þ=Ç­§P°ˆàª£ÛKÛ 1ŽÃ8……°Oâ¦CG€uma˜ªÄ÷\õŒk”åyñJWâD«] ì;aܦ¼ÓðÎëÇ4ð5¬UÖÒ¨±Ømá´tÃC«>“„$ÉÃM¶D!Äé6­ ˜ ËdʀŔŸF0É`—lÌ%Á¹8Uÿß^Zð¹TjDtýJ!Û?BÅÝÒ“9ççã+|Nkñ…Mxr³3–‚`KäÕ ¦…1X§Þéz…žh"å‰P¨/r³. }bêçâ‰ÿuÉúFðžÔûü•)ó3#Qà`Ê*ôË}¸Î¨ÿçÏà ¸2Ä£ÖŒø*Îì¶m~RÏyÅqBcŠikñwÒ?ê(mGâ^ëá YÈ_>S "¤–‹ÂÔqä!Vݪ¹‘ý2¬ƒ^¿}—õ'º v¾ôFz—ÂØ‚fQê?¦·³è)ÏÖ;£n1˜.’i÷ð%¼%r·98É…1²[ÊÛt02&È*dt¼4Ó? ò…MoI@éÕ]ŽMÈŽ ½?òH覤[?X‘±]Þë&¯k³îø*œÇ#ÿ„ú!Ñîߥu‰jæØ½õqñú‹jLú¬u)|ø³K9,ËË`ƽ±Y/·øm­%fC`ê>ÈcÇz®Kå:ض´”x}§JW=·zÍrk 5!àÀINá m žBô¸#ìü¾’€€Âd@ÛÚ„9Þ óL0¬ñ ö€Ä²¦€í´a~¸(DÊpaË'¨*k—Rx·‹é‡B°³îÆímª6ùTÄ‚iˆÀ-–y©Þ0­4’hö„ó‹÷UŸ¨´<¢™ÝBùoC>ƒ¦b;GLöö¼nu©õ­¨ïm&éìÁÞæ”…@ÝŸÕq”G7¯oÞ@9Fllã¼àÑUæ™÷ÿÔ“˜ªÿÉ¥eL¥ÏÈðÀ&5»E0=ÀQójEZ4¥#vñ¬ß]ìÖ¢ßöiœ°²¨ˆà7”(Jõé˜Í¾ÌvÙóX;Ž?æ­Ò ¥ÙÃ}Žî¹=n(²7‰Ž•ˆ2"ññ£#C²Jp¼ ÄuÅc!í+0Ó¢£½ð¯¼Èí%ô›S>RÁKzÏa%8ÁÛ‹Éj½ \ÈÎ÷ð aõa —“$sqÝR~ ØU®ßÐa©R'Ó&ȦR4F¼vbhrwÈ6¯SÆÙìêΞɵ† àƒ²Ü×ÑI3öOwõ§D´¼Ìþð:óÞ"Ñ E|ì*(sÙ^˜n@ ÒBáæPXÄç'©²¶õœ`Ç''7DDk:üûÞA©ˆ"åX ‚øúM$ÈŠÒ¬é½ ¶éƒŠFÙýñüKŒ1?–§é}-ã#;¢3¡®‹ºUï"³¯>×ø¦íe{#ŽLÎaö§[Ô“hšYý¥¦ì¥õ+4…ÿµ}4§ÖQ€—ãˆ|,gÄdŽö†‰©-™Nc~Žƒ6ëy3  Põ¶†ª sp42¾ LÁžì{96‘k”纗rº5üà–Z*²KŽb“V«9œ`D>ã¼p~íÕ”‚ˆâñLÞÁÈãÛü`fÃÊ4FKÅ«®þÊ´ê;˜}^¢'Æ}ÅÜç~Ò&¨Q9%”Ñy|VáS“—˜…$z'Ù9Rþ³äœük)¥§„§ÁÐü$ü`NÞƒ~v‘T(ízy ?ÓIøëxKCàÖªª¨kÖß„A÷¤<Ö~Œ+xé ;ñLO›N4¢ÈD …‡!à¥u+?·òdÛ¦ ÉŸe<Æ·ÁÞÓ:ý2ƒ'•‹„Ës—Œ7‘k¼:5Âè-Íj'ðRMþŸkp¡)†§‘ÅréGM®ýöÿŸ_ãØÑV‹©%§wüJØrKuyÝ…›2¡a¿…¤ý)^çú´4›»Ø(+C¯;ìò’€€È÷œäù\Ä9[úæS<žê C\2[™8%AX©÷fqæ—är\ÚÎQÏ‘š™È2M(ådéæv M^‹ãݳO³oÑZηrÈïsÖé64 %jãÓ  †•tܧ_§Ä<-c@ÚïÔéGó“1v¤øbö°cÊu¢ Ó$µxvÌEk È^ýíèGzV‹ >}Å­Ï{Ùi;ú_¹–ÁÇï>—½$(»`×ÂõN–Íëê\p/”¹Î©¤ÜŒÐ2%šüVÑúvW»iqôy+CÊW?gCùÓW‰ó‰~c½ÊÙݪíÝÄLÙÜÈô¯€˜zÈÀ°\³|÷Õ3 ­5!Ò>p°;êÆJE¸ èòÉ;F³—Ó-,¨cœ8ü-+'îlåkÖ Ñ©xb]+ü·ÆEƽqÿ¿’¦{Ãqó°n)C:éˆëG,âcêƒÎ€}Æ‚zE¸Ž¸0ç*€„ š"À×!TŽÙ ŠÀžX7J¢ª1§L[ñ ZÛ—¡¥Pmø:¡ùô-²Õݧ{»¹ÿ ê†pPÐô¨¢2Œ ¦4jïqÖÑÒé#?Aè| íÐrç0Äv/´åΥ绽×hD®tëe­™z‰É¿†Ø—02à‘~^IúgŒGõªÆ§Ì­Ûáëw¿ÅØÀ–}ÉQ«Òc×)ütÑ*ôñ·§ÒËg'ð@î+D²:wÖÀ3[ éõ'/·YBé6„ ö]¶™šI¸¨F¼«j@§¦Uâø‹Ø&ê“z„uÜ3à)½‰ˆ'^b†¢PÉîÁ¡ŠqþÏà]%ö¯Ç/Õx}üܫޏ˜,t$[°›En/óGW)ýz\œËÉÆ,Ô9·»4 ‰k×à3i¨Æ.nÜâü'tœ(wÊ+Ö¾ÒÊ?æÓ5"BIyÖõ—?w±¤m[„ON®ôÊ|j[¯mjÙ5°Ö+]7þDÒ<ÿѰË:„Á“z€u늷¼Í¦÷Êv3#kå²»4½ÂARž¾uhÇ·ùè´ì棫ÏQïÍž+gL®Hø1¦a/sIQaQBŽ›ëesf2ŒäÜùžX}Fw ;T‘‚é 0¨ø[ÜÂÁ·ßÒˆ…&Y<ó´Šß7&Å:Ô¶£•oÅúhür8òý`Wíÿ”¦àº áŠv烩ñiß™®€X7§•J’€€¼Ÿ&Ê Å  ±ƒùØ%|õ”Q³:Y#œ €ÓæBVªÌ•=zÄO¾ ú——8õKŽ}Î5ŠÅ"”Æ~ítàË?bŽZbGÒøhUI¬Ð@Ì®ƒÁ};99’Uã¨Ͱ–Ýè9{c _͸ÕÄœv*lÌKv@4Ó@×à˹©GBUÊOî+F(,&Rš'„^“mL‹½ÅåïáÀrì°Æ¦ìŸ¦90¹i˜LåÆ?ê™1glÊÇ\;ÞZôj'[ëÚ~ƒåŸ–…Þ¾šéµ÷‘~À‚^ãTÇÑl€ý¦FúÃí5(ÃOOR‰æ¶i£õ÷¾Ô@‘1ìò¿‚ =± 9=†eŽ«Ò"ÐÖÜõVŠCO¶ íÕ£‰¨'o쳫Y¤ŸÛTßBÅ †¼mã«q¦÷¶o‘’mÂP²=ÛÖʈ@1=œhýuÂíéÁnlÖMKj…f`ÙŠw‹Ò)s Ypgí×z”ñ<ûfó†ÂŒv/ ·9•êþ´‡ü‡>Ÿ5ú Êìòïר#Rööµʬ­@&.Å»ÿØ2O<Ì[Ò+•‰{°#£ŒFfodX:÷?ÊëcÁ%ŠÈ9zóYða:o;„+ µÄÞË‚‚/¢éº¿…OjÔ“ÙýîãW€ÉÈÞåÀÙ†…0Ìf¸#©Ù óƾ¹Ú[OuKBO’€€ÎÊ"ôŸ˜((Yvuj{+žò¦ÒÁ¼Ÿò²DtE@y'{S{ÆøObúz(çñh ¼Ñ’®â©E®+ @£MÉÈe»’l¯ÿ>Wº&>±ÿ{§qCûU I‰e Ofrô%öËLÓ%&IC9w!™…Eˆå6ôË?·¥ðÍÄÇìZDôoç†+ì{í¼‹XFõ¶9´a[~£›Ÿ^r©´½–ž™ôµ'Fø,’¾ÌC¶¾jvŸÖüèßÁ4ÈœgUYËûåøÏ+‘0w=rcíU|à³ýŒÉËâ•‹É`p@ÃÔv¼—Þah“’ ®öIÝ䝸å+ë‰"¢¡Š~½½ª‡©JÜbé*qƒØþ;`CW8ä«`:‡ÁËAtX̺‹I$¾¹/a\h‰vG¶¾Á‡è H&Aì@œ”ŽfaTç•!U„¶¦Dx+áZ´(™µpë|ñ8j„èDA‹íàI€zÉ%{Ê"=ô£Ž¥.”v®}`õþ&Òkš¸ß”ÌäGÖ {}šŽ´1¾Úç°Ü¹ðGŒ+Y Ô‰zd­ËíÁNvBÇgàhÿí¢ éu³Ì” hœdWÕl:Öûû^ûV-"©lOH®^ð¹šáðèUkÕ´ÑYÄæV‡¶ ¬c–ô£nÐZï:Þùóûr1.=ieÎqÅpFßxûHºp„Y¢þ²(K&·Ua+ÝíÇcbU*üÒEõNp€"þµ™æÑ£XëâhKUC÷&Õ˜õýËŒ™²ôiÛE!¹ 9½.UšýMxĢà §E³EÆ1¡ ,i¥ׇؗÝIãCÝ]f½†’ã©BçUV˜v9+ßÞ1_Ð-È™€]b8HΖX¯h.äáâÐ`e>+¼_\6ËYµ¿ ‹Fº_TˆÛë§]¬¢ûh 비œ7’s‚ñ<›ˆn&[…½B‘¤<ßfø^„ ß|*‹±Êö;–Xm01mô ¬‰ZÖi=|vDIYPg¤—ƒ;¡ŠÇGzÚ8ùãmÛ`^ÄôŠ˜õ.³Ÿ‡"ÿÆ“±Wé¿Q”˜1Ø6C˜»Ô¦Ñ°¥:Q ­¸^ÿ²ï”a¸öýË9 èü&1ÀcwŠÑ‘~ qÝÛzƒ\äxDá9{]šW™öììܾ ü¤Ç’€€Ä̓TôBÂåß õO»X½³›3¨šô]Yýà¨w1]Å´˜2ÝQ:‹À¯aì¶8yé[_JüU±J¹xRBÿzåúgxÕHQ÷,–¤ È{‡åG5ºÍ—„˜?"flñeBÆ×Kj¶ï§­.NÛö(­uôkå…õïò2˜W‹Óðœš*”n=dSô>»:…ýÝ“UG±U#âb¹”Å‹Ð7Wg\±µþfie_¡ãÃ>7,œmXuŸåÑ…¡\|l‹xCS4¶6`«Hr`ŒÑk÷…ãàáîs`Ò§ àÎìØÎ% ÁÀÕ” ?^Üƫ޶ãg§ן‹5ŸdþÒªø Ž«|ªÀ丵K&ó}h…Æ´‡Ø@ûfŠóG/ t?cÅ×)Gб~…¦¬~T_Í&VStC_¶"JÌk4Š$„z®v&0exþ’Ø*­ A$šm~žó*œ|‚A[~¤8~i˜S-ìCÅ` ‹‹úè†_¸Quò1 hs ÇDtÓÍdWƒRS*Âå“Ô·ÿ=—f¼•N³tŸ¨ÉŒdÓÊÚZº²b…_ö‡íªêTñ‹+˜nnQ2æWö¶š¥¥«à§ë 6½è]®ìÃϰöIG}3J£ñ˜_q;Õ Öêz3‰$XD »Ÿ=܄Ļ~D;^<|¾*kÄ g:ý=¢ §Ë4E'îh½ ¯DWcÏv¦m#¸ù¢€‡H’§íÏJ„å‚¥A`ƒÐ§SOàP ÇéãÁ¸`¬ØlàR%üÏ%®8jfØám«AȲoFó›Ê…àx¼ ±ÜkèÆûc@Œ9Z¼Ž6‰Gðû®RÚWœ¾Yê@ð52!üÌØ¸|l0m$ɨ.2}0'…/} êUhò§Š 1·5ŠÛ-æW/³LU§Ô‘#’ˆ[ ©:EzÍR¬CVÖb"_µ¶jSˆŠ•tíÆ‹g31›Õ¥k’§ê¼€Õ.ÌÏ1*t’î01¦ùS‚+1ð.¤%ñ ±Ì““$P ªC®Øiå?ü°©gínŒN¶¦H‡¨í·ÿ×$!ïÓU3ºÁ…\Ö¯¨1#„øÛ9ÖºKÞN,µü#ùÞ¡ÎöÌ‹óJ^o§mòvýÜü¬/Od3.1í–çÕÎVñùXôÙ éÕïÞÐÁÄ”­uBØïtæG"àb[£ÆX@åÖÞ墓 ­r¥•¼ •F>¼,/jRè*o2Í [©¨&)¤í –dÑÞÿÎ;Sf'æ2ö¡&GF‚ª¨sÐÜ Š¢DÂRœŠ·)ä±}¿¬xb™Æ¸È׌@Lì/È}Žkþ¥„Iò ëjýóåGíÈ …´ä¤Ë@- ÕÏÏþÕ-_ÕÈ²Š“µ‡—,½Ð³!:{–‹®[ɸμˆƒÂ¥zsøW¡—¬£Šø9ÝôfÎ4—¾ñ‰‡€ëz¹Zî˜çµí˜ w^Ä$Øbé00‰ñ“ -A}¢BGž ùÞ›#¢þ¿4‰æ¼ k¼I;¸ÍjUáÞ°ÌŒ¥‹VÏnÝÝt\›ó¥tY¨Ã4˜ñWÆï¬ÛÎ[ïQ!tä…»V×·IwÇäðýŠoälE˜•ž™xô/ò®0µÞ£þ(Ûlt lQ úLóŸüc’€€¶„ýaÔ>³Û[“.ƒ\>‘i÷ª·£weüÑ£€¤æ¿”1±›]KGÂãøñž£qI%ÇÜ$C…8é±< ÐÓ´£Zߎ8/ ÖOY ˜u¸—é1^p#¥î¾š+ É™´Ë©X»B K4hñUÿò%\Pý[W,Œtâ¸$͹ÁÞÏ Ét,æwæpG/ŠŽ7çþ½G›h n¿¨B<Êž#¿æ7±Š‡YÌfPnEŒÆEׯA/M½;Úz–€ øõžúÔ¬Bö*eaK¼1ËÃŽc[)úQxJ 'Qd\ü=,Ï¢m‘:. ƒ]Í×5Et×P`ý"¢&èí Ìš¯•'—ÞO¾:L’…±›ÅVŸtÑÁíýÛe½éqÒ)v\„ Èè=9dç0ºñ_Z¼’^‡-ÕƒP±ˆ’Ž{³|T#ǶåF"´?c…‚ýS˜+7†{—HÀ' (ÂÅ[·“ðüdE”ù€ûÿ£7kÀãXšçlWBÁ 'ÐtÃÙB[8pà¯i"ŠU“4‡c€å;Æå¡œPòH¦ðæ¾.Ò:g0Ðt¶5—–Æ=[Š#]Ó ™Xç׌×qJy;[zžœ—Ôåf&S’e÷.ï˜ ëë 2â$ºôèL®ðêóМ–ÝógÔŒ_¾pú‡´å=Ù¡†OÑÚXeåù+9?õ÷›Þã<&|ñšPš-//J·Ž¸)óñÄù~i9ƒ‰#ÀJ¾~/ËóqöíN0÷ݪ’?çî0°?« }u3õäYY¾’ör|iPº«6Fö{ 3Ö”a|Hžä\žO 0±`€Yš€QÔ²ÂÝÍg±Õþð: ƒˆ7æãß# ޏséîÚý†a$N‘ò*QBǪ¦Ý+¬?%½Õ)/“‚ÉÅ_4'…!üåýoO<å€zŽUr9µáœé.èˆC!œm…Q+ ³Q`°’ »‡½vºìÃTà¿Âz»½sŠû›Í„6ÛJ°Ü¶†áu£%ÖÐòˆ/úr_¦L¿>.l’S‘‘w=‚W¬Òƒzf £ˆ +úøáI'vŒnÊq?\™‚/`mÉð±waÁEÊô^¨ bò› Ic¡ç¾Í„*â¼_ò«ò¡ ãrçNm'î*LðqÜVü¤=ðÜvƒ{X ‚dRiBÛ¿ 0’€€©õݨ“:aÇ.KI•ÒšÔñ; EÝ?Âo_\jÀg™ò; –?R?“*} &°´(Ê3>W¿–Á„}ò‹ØNÑ æíWì/âÅŸÄÑVÞÄnåý. w­8‹’Û>1HuWô•W³;‡\Éî!£BQãM)ãD\†OÚŠó¸Ó¸lª^ì(n±‰øÜR-‡3åL±Ï&Kiã´†̯ÞÚÞÄe˜¦êÅ'ÿþ¶àɳšÖ@²çGo¶ ”äZ–åÍôG‚÷TÓ@-QG9ú¸¬ç Ñ@Ì9ŽÒ_Ê}¹äD/e}b݃ó¿¤lÔxÆBìÎfȼMnúÞÌûŠ×6ãÓ Îä¯SÅÍz¸QäA š!ŠœN§¹DR–ò2’$cGUa>‰îœoù@Nd‚³¿7Šè÷Fš#ÐäÆÜz¦æßVˆk} |–6™EäUZ™÷=ˆc>Òú/&‚’—c𓸛^ Ö oèh…ú’ä¯ÿ*Ô·,®^¥¿]¬PÊ0Š¡~ ñ·àÎÒ4è•„0¥§çèT9Îá£BüWG£ÈlN–L†\8&;s±ì]*wørl&îÄ‹I„ˆjD?Ж2+wMDÊ»ÙaJLÚ7%. Éàƒ¦±Øv>ÐÕð^ËòP¤ÅpYSÁºÀOÄQð–ª2®ÙÁÞB’‡´,cÖŒÈ9 :Íä“Þ²¥§ËáõL›¿ œãX,ŠÖ²~]6³ì‹ÂWcݨ>×X¬ ÕóÀæS¦n˜´x£e¨;©–‚Ž-rµÁÉ®)Ý 3šC=QŽO/L Ž]Šù¶=‚òMÅ^ è’~úq9gÓ7ÃÂÌ ç<˜Ï]ˆ‰F8áÌMYð1ÒŸ­¿$_[YÜŸRÕQé#Ä.‚“º«]!ÁÑø/¨†&ŸëÔã«`³(]å:18…—²×ÿî6>oQêýJÿšt/‰Ö•Áܼ0aÚ;ÖÞà|ܹ|ש í†öÊ0˜¸UèDùêÜÀgÔ·a¡ÿà¾4r>P»þh7Að\$gÑÆÊ6À™¡Ù®³/£¿s)!·˜Sdg˜Sø9O[ nƒ.öããP’J²ßSMg–qÛÝ«ù×$N,Ÿc–õW.'ž@‘_‹Tà&÷\>CoËÁØSa¿Æ$T ÃÐë*ð’€€¸ò$ †¯›BÄ%©*ŽB5œê³øUU<·œ$–|7x%îo¯ÿÕ°S›³»^Ú‹ÀðÌâŒ÷£œß[«Ú¼»UI°ÿ9æC½Kaúý.{©‡™hL³ÙýÆI”KjØZç;ůK“ä;2à  Q3 Ý¥u$ÖÎom™°$h™Þz/ªü÷~0…±ü[Œ+v_ÕÃYì8¡“w\Džˆ\ݨCˆ²öa°@ ‰4> d0"íÐÞ|5ÃZFèwûæ>xñ:žÛà1ÿ­¯Úµ÷fRž–nOjþ›Ý9©Jäöïë‘ÈñÖ…·MÌòZP¦‡ñÉxSß•Âv}% ø9L…ÒD9©<…-GVXlz*Zɸ §‰dÂg¹T+ݰuKmÀynQ8=x2JnT¯céå77¤ª²ì´¤  *ªÙ=“J Æýº:  Fh`g«vOíØèd––æJùzÃ\CÓßÄ[h|É©JÅø–xx¬oJÿfŠC‘²¹= ý_uGBO@ÑFõx/Z0ÂSÂÓîz>S§†¡)ü0”È(D%!Ãç랯¸ Ãyž¯®Üøô·n7õ›œPãÜÌ'5Äu+… (·K};3´Ï9< ªåtaŸb¹,‚ãq._÷„”ÔEG¡¯@H“ŽÉÿ©Yñ}‹$zuÄ7Ëly„#Ÿ!þê§vnUÞ]W ÀYWãÃዬ)ædؽϨR“yn= hœ,l¦à'4Zù/€‡ i¤«ã˜M@Ðuk51äè#:¢+œgÐQŽm’€€·`ÈË9­iι ÒOSœ àfcd-ú+EDR@:̆ôVÎ”Âæ¬•(¸E;zm7QCî‰Ë)_«y'ÔÝ%«› Wwšj£î´ö`h”‚›ƒk…RSD¤’ïâ²!¬´îØÏóÓÓŠ¼ÍØÙ¯sÿUú!R—Å…þOœn®è÷¬À³¿«Ñ­ê3Öðÿ1HYåó{s×É%rq[Ö`ŠÓwžZ™e–ö7”P°£SþqD‘cžKÁ .[ö¹|V}~HÜ_st+ê“;MNéTðÆ Í•¯¤qó™¡§À—¿2d™c…^é¾vdðu,¨G®öÃ8ôÙWÏÒ×EΛ|Q5€ù`ë‘:1úëÌ~é_QŽE[¡"7“ôááÜ&Ýq‚Ð%Ø›ì9²9Ì“`w9¸hò%°4ÃR“Âòã¨xÔh¿§†f’lnžÐ·3þ+²ÍnQÎÊMo¬IóG2‰#fšÔ›üëØÏ-Þ9†ºAÄfA,Z]­"ü欪ۄ—è[hkïà~ùMç)®[ìF9ãCFJ¥àÚ#k°çú¼ á…I=\©(›ÙÕ¤(\¬Ãν$–žV›zõ™GôßêœNV)ÝIVÅtU»K|i#O)õë%Þ81åV­[ôôñįf“Jᯠh:W߈=YÔR×T†CŽ¡F¼€¨Ò)_4œs² Æ@ºšô’ò"ÜÚéºèƇ5Ì…úç9ØŠ¯”pëé÷©Á4ó¯ÀjN%'“Úý—VÏÑ6ùçN&ÿ* %ñ+âІ-*ð¼uaW½#¬³Lˆ(:ãEWXé$0QBÑñíŒÎ0}¹S€ êÝ ŒýVU¼?Ùºpµâˆú?ÃaP´/Cà cv."QMÈà56#mLUÆS™¬AbÔ’€€Û×,þ´Yä§ì'åvú€Tâ–+ÊK»#FPxd‰ް쪮6zf#fK<6²r$– 9À=Ü‘“ýd}ïÊÿ"€ñ±ñ•J£žìJÞ<ªú R€Œ[1|ŸE| •#h%g‚úùÊYM~Åùƒï–ƒßâDüˆS{¬ô¢—笞žœc;EbªñXŸ8ô#òzŒ.úkiް5afA©¥ìHªg0v´¹¹kú-úڻ·zZA£šC°xŸŸOLå¨é Wy̲Ì'‰1&^ÕÔ­…†a_©[X·Î ´x­z4 G%ú½”:”XBô×@]8.tÑâ6¯KDnÏ@Xa¬¯‡ïÅhß;KƒjDò·ÃB¶o0:ŸVAìjÿ@ªe‘æL„“0zóïâ)éküBìzà`Zmݩ׃ú¬¦{.¨xmï~«nYÒ uÇzKkXFPJÅÅêníã› Gï®/Éqm›š\Xçgƒâ£Îç%M°wîùø“€²ˆƒH~êBÐNÏ¥)¨ 1P!ö¬V¾¡®*OphL·%'Eè¡)-V¾=Âët–ž‰TWš‰ß󷬮öl1‘¦ ©W!™{´ÑÇ(rcX$$Þõ@™©Ùì&×½…_a‚´û³›\µ–Þ•Óæ¦S¿ãT ËÇ»‚n¯þÿZ!o0$P>ƒ‹77…)‡q“Ò6« t8ÅEQôúhrbŒ…vs†ÑØ8OhOõÛJšnÕ9¹ëãÏÄ{QˆÓJ'Ðq'ªhìÇx£.BÊôR{©Ó,ü¢É°¬”Ühò]L*Å‚A5%tÑAg62‹CÆV ÎVsŠ“Ð}Ý…=:œîÌÿjv½?ðü Q¿Ñã ‰žW {JN×ÖÅ—k­ãЉó†&8¤Ê2€s[¿¬–8ž.ÙûëÀÍTvag62ó¢d°-A˜ž>?£lq­Eé„v —½(Pç."@«hûLzfàü@•Ûô7m›<ÿUó‘gé ¦)ÐÌ]› ‡õà¤ÒdzæGÈq?ŠU(?ÿjܺ®ð.ë©c9àOy¹9i”³ã ;êV[k ÐûÛ'ô¯lÑeÑDþ FÊn‘"â †n–Œ4pŒW ‚ÁêŽÅWµòË ÖjIÞáá²çÀÿ[’È$’€€ª[èÍìlêWpÝmGu0ÍGì:$Çk‘Î:œÏÒ«‰PMðG^:èf%un1)Œ*pÒTW:ä°#ÂÈ[cW0Ú§¿/¸r InKa»SÔ~>Ÿ©yr»Ø65‡çT(z %LùÖßíñ$%hA°ó)æ+¨Wú6a‹o ßè¤Pï¾ñ[ )P‡Ü¨&¾Ëvôˆº…‚#ŸŠÌzrNgÅ-ê 76>(Ñ»;„°·¡~ÍhŽ˜¼ÏÛMi±X¤!«uªÛ[Îã¹"DÍ :+̨VQx›¡`›vÂE€“Ë‚ÝuL(Qq7éæª‡ëT ⹕ aþmB*0r™˜Áa¢1Ø-–fðK,3&UG ûr»Þl¾¡AMõÌR*w ”ªwþŸðç©6M‚ÈÍ×9Vqæäšöó^©ß%îý’{’$tÔêᦸșF­‡Tîf‘ZìÁS1-Ð…$GL gDRÙùD_ES$x-T$ŠMcUæE¤º¡Ž°LªÀ~ôq=9·–æØev:üMjµÝ}NïâwQY$Þ)Ö¬ÿÖ×oN=8…Ø'WS²[ºé…É5‹šcfŽDUÛ…É£žÂøs1žÿáý)Îe|µ¨<úÿUlvl3Îêþiª€38ýçcD|Õ\ÁÕµOž&#¨ºž'?g¾ú´Æ^+KÖ ÷ÉÜw_Üì€÷BùìÂ3ÉñÚšI{>¬f^ÀÿEß#…Ÿ¬hKM =ÿtÒL—kb{ÆzdKo¾ ­^‰'FÍØcÇÅnÿ˜GQ2â‡2Õ@´ÙŠß8õ#ýú«ô¼O9”ö´…Ø’ÈÀÛÄ¥˜‘æyg%†9ÔŒ…Ç-_ÏÊG«-³+s‘g&ÝFñMUC¸ÖRy¤ÓëwÅ '.@ê‹E{ýÛ/, ™'$fZØ{”ÕçŠÛj6¯Û¯‘l\ú­Ÿ‡Ü\þøµÞ[å ÜܶUué¼ù°Oà]¿/>…| ë|.¹SÎäÓ²ÃÔó"ö`Ç)]U˜üäÎ 0d<ãí-p¯×¶Ç”Ä¡©õí?í‘¥¤ˆa¿¤ÎФJy"+dõ‘1§‰N¡mU  Ã½4Q)9ªKDZ“úuª *ö ÁÖýÐVÅÓ¯]fã:±¿<ÛÖíþþõùYù½m¯ìBº! æ^Ë!Á5ݾ†µÂ'”‹m‚‚ˆsˆå[¨ïϦ̈9S7™zæÔ(@ª†k´¾½ì˜¸€@̾saqé±ðíišèE%£]'76g3V¨x*!¯„½@|kQ>“ð•…×a¶VL?!‚ÍÂ% Ô´‚>ïÞmK—Á®àâz$þ]ãý}zŸ¤pñÊ·|Ê»ï@#‡Ú&"\VøvŸUÍ[åõ{ëÎPqÐ %qÖÛâ†?‰×¯Mž¤RI"å\Ã|ŸØ¹“qÊlqfgYÓ¸ÙªW¡ÛA)\çØ&ˆy¸Œ@¦l(ÜÓFþ˜6…‰½øp5A“o$å×9·ÝS»L…k}br3q8#®þ8UM»ÈÆÚKÿûKõÇ> çM—ʵ¥@'KçSpb .År¨n7ñ[# ¾óÞåðø¶31‚˜$ŤzÍýËTpW+;£cÿ­˜Ã ½ÔY›ˆ»Ÿ[©žýžo:.¼q|­Õ48‚Ãü3Z2’’‘ÓoGòZ<# Äs ÿëÿà-ò_ì\E¸üZP dp‚ìEB>)›h_V£êÁ%|~¢:Ÿ}éZôn7œMÆP†ëÀZwè·WÀKõ»i‡½g¡ItJ]˜ ÙõxT¨…ò$KE|cUž¤¯ÄV¬Ö6Ì#=­ûnŸqæÉÁ™ hø,è@Ü”¥b!{ŠT!Vä¿fš,ã é½éŒÎÄ¢C`çFUƒ!Qw»3,#P¥‰á|í^ÂôÉ~KgfØñøþê8`X-ƒÆ{aw¡JížÏ—{ c@ÂÇ3íÐø5LÞÄ)D'ŽpÝ¥]ÀCsNt‘ë «f^'[ ¢xξ͙±ª¤ÀE·þAYå½¼:™¾²³½å®<›óÞ–¬œ!é ó1Åe¸È„ ”Y¹;žèÒæw)] âŽYOs’€€Ã'_DòÊ<”÷ 0Xµ5Èÿ}²†ê韚㭼n•ò–Û5ÅHŒÁ,l>²Ãß±,±öGþ>v`¯\5E¯Êòvž¨ÈXDZv8“re˜ÁwÖhò‚ósé’*tõRk‰Êr•|bô±¯a¯Ê!Ï$‚Ìþd¹ÉœË%K\º:–lò,DÛŠ}Ì›³B<}«„až¯>æÅ—¬Ô*yåÚ?Ó rϦÑj“x×ìôÒûCL©Xd:Sƒ²Õ~¬:-WPÕŒUÛ½o,0.âÑ[›“!/ðM2’eíØ³ö–±*-oÈŒ‘l\¼ÉÑK9¤¿Ðo'­²rNïVUt0yb¨ßyuÞxÆê3ß%Îøj*Þ¨b¤u¨e|³£TV“ž_lÕªbíéG?©"Y@\âF*P/gïäînèýëêAöØ‚ÙÄZÆÈ¾ÆH§<Ñ|V!)šIRÚ¼…Gþ§8D‚¿_½í>!›G‚&%OT¥?©R[éWÛߢ±Õ×Ë<Ïæ9j¶:E°R$£é•F,ˆô†ý•Ï©©±HHëÄ#U2.ë;ü”î¬aAèœ&ŸŸàVE1É,“• ¦õ?Ÿ§ã›=gä.Úüw3½C;ëíê%³ÂÕâH©‰âgVo2IeB @›Yý½Þ {8ÿ7ç‡ã o–å4Ö8§©ÖÇö±¹ÍOïE/$ xUOV,%æwÛº¿©ê”gާ˜ÝœÂÊ0£¯¾òÒK©-Gò—àuȵ‚4Dâš‹§çû4°OÀ8ß·´ «xÕîíj¯˜’6èË´ÆGDS“÷i™Ä¾w‚Vöuî_.y¹!Z9i ×‚Ð<ú_Žy–ÙmÆy²( ïÃ#µ#ñÓaàæª~©Ð1BPl­–l÷¯/>$š^>;/X᡹ÓR§¶Ä°7—× ‹‰ìÞBƒ†²Ôb âE+œ¤C»¤'® ŠÅrû ØÎbݵœ;‡&¡Ç¹%’FÊq³øQ×Îý»B¤0{GGzÙä‘…Î øÞù)[zÓoå5w· ÌP´Ÿ=°$uÎåøïßmivüñW/€´Ñ°þ÷ æÉƒA¯]©\JsÃ݃·›ø³H4ïÂ]Xž¼Ø¹\ž Ù?…Í·ûRpq’€€Ö߸¸íq~2,)#—¶w9Sh°ºT<Ê¡¸K‡Ü½½÷†„2íßgN …ÅQ>Úõ6ÍõSšzÝŠu]d7ðÌ4>ºt0<¢.C¦@’9ÚT,Y(ɸïËÝ^`D{p¯¶ÇêaºMc&Æ«_ºZ8Dêh|]¬8ùôœá±m\·/×’¯9Yd~éòØé›µm¾8y6Ùýý#Ó—ÙÞÝÆ14 \nÀìi ëkHÙŒà²n´?”‰ÙÄ׿í:š!vèn,ÞβÄ;Âç2Þœû„#§þµŒ@šÞy`꿞‹î¼dy—!9û/71¹¤ð…†G¶wç™»ðˆü4˜Ï?6L"­m ¸;’0%Á•†Â»›ZƒI„êhIvs¦Öqr‡äP(­>P­Ê9·ÄµjôžeÖ®d}~+˜©—D+¶àýíûgwrqвªD¥K½æœ5éy±Èq?šÅËÙd–œð­+߇àLB„#µ@xÑä¶W úˆ©ñ˜› 2ãÌ«xšzp>L߯mÉN9´V·ê ÌUÿÿvmÊœìƒëÕd¼ÉX«¼xòriM¢É¥îý£6´á>È|@ˆÑDk,@¦Ì€Ä2(ºPÂØP/<ÝZÄè@QÅïBØj »ôé`Û˦¢îVìWöðvq¼®1·÷_Dm“–'&aâ(ÖÖ«'¯pg©K†C~ÃjmÛ=Síf8ÈI‡r¡[å˜y­! ÞÝ67FB{›CùC?œøpÔÝ<±åüEù©á)þÀ¡ûÓ7 #æR>sèç#Æ"SÓ’€€Â£YÙ›Û_£Že2‰úhº„Þý«ÿ›ÏLâ*š7 ò9ÆËU×åë˹18P8ÆòVïQ»‰k¨âɘN ·K\·𠜽0ÞA]¶Ô¯Ê|ukÀ~KîÛÄÄÃ0°á«C­#”âé’«ÒwzºBù%È~0h°äeõ©±È3,TÔè!qâx!’ºô7-#ËædŽJ™À{Ù$íÑ|€Ù>ýͬ(‰'R<@ÒЩ¬6>™N«íµõÑ6e??+Âv#ÈoWžÞ€xc?/úO½æè^Ø…¨"Í& Í­:W…"dÛzdÞÓØcœÏ8¦«LœL\ø‘(v7ÅR&æÉ{—_÷6ÒÉy©´@PY®ïº’º³‚Ýhìßâõ‡Ï*¤=Té°ä*Ï<)Žc‰bW„ß·M‘µýȼÛhpÆkù’êðã¿,} ™l«Ÿ °½½Í'!í‘4† Ó†”žJCË~Û k[‘D $[åºîƒ™”é„·®@2~Mù’טžž~ÀñS’€€ý§Oõ¾–›-?t^êãÑçÐ"2µù:ú¹H:›cÉ,·ìðþêàTƒÀ!\I”+·âíH¶ q³³xîX‹c–®Üö½êÍ.$ûq0ºï¬?¯“‚ïm††ÆÀ•v'O‚åiR´\sÛõÞJ©H#yÓ(³`Sž—œÛ­¨'”oÔ €{§VðEUº ¥Ò9¦ÛÏ0²Šh%' yÈÈÔdÇ âuö§E«Š,‰ æ÷p’âQ=WÇóóÐ7Z€,¤o=Ój Ê9ðëÅ*®ç4|“Š”¦z¾eIÇ5í/4Ÿx€^úwÙ$kXÞ ‹“†™‰cªu¾x­ÒT«ì½ic-Jç¡ üÉ«¡ûBcF‡j¾K°jì ö€L&§¶QÉÆ¦Q*À²è À$BNÀ¶»Ç<­C]q¾—™´—8ÏjîSÊjŠ­oäW›‡l}|ïu}ƢɄŸ9dš¤X¶*®ƒ­³Á);ñ™èðòÓéDm\_7+«¹lp^ªæ¤ ¦££Õ¿Ãqܲ«²Ê% ûˆæGÃÎe˃^Iû_¶K6á&òÖÍ%ÔoÉßf:Ój#³WÕ×p…ÔÔkŸ&"UÆNöMfª ï—nÊ!—¦êîèwñeóX®<7ë¡•£ïò üLKõ"äBëÿ¾¿þˆZ‰Ïøúû„I žE5_Ù”?O-²4ZXÂìíEOÀ— 5¤Ê̬Ha¾IíWؘᇳTj†àWGH‘g– {0Ÿ'ʺ{i¿R?Ź4i™ˆnp+ûÛû¹ApúTР œ¹KÆó /xÖó|–ê±×)ùÆ'ýèf ¡ªÖºsjžÌÚz3 ßã“êóö%R¨Þu¤þŠtëÌA- _w/®È~wbñ×δÞç?€]Ã.^+C”¯GöûIL·Vð»]ï¬<3ê÷г”ÓRŠû?Å’)\ãù‰0{ÚÖQ ) é 8qa§ñt²4À¤ñ Ï6el¶„ G~g Ž7¤Ÿ,¼cŠOè Vê³jw1öá´‘ïËËëwGajO⦺,ÐyµÁŸ$渂£}ln¼¥ ?.ö µR«1 ¿Ë%gQèß’I×®ò¬‰ÀÚ.ÿµŽ½Z§[F‹ù/¢Ì[ШYæÆpéøl“ ìùT*’€€ÛixÄ~­/;#ÃQŠß·(úC•¹{¼æA†œ³T›rÛ+÷ ¾§Æî¶íLï˜'»þ~Ñ£û˜$éMg‹Ôã´.á`?SïK@m”/½ñžY«˜Yû.Ž1˜yûZ Ü:?Ú›˜£³¾2ŒwéäçíQü?b37î—>×%H¹Ÿñgbb]ÐDÓ!gä[t¦G>©Æ£jm®ÐD+G÷'d=—ç—Ë#øqBü‡·¸íàV¢S1#@”€’çp®ÚXR®Åçé2GK¿pȺ˴¼}×ÊN@™ªezTœÞà.O<7á–Ãvßæ¸Ø&t½[I ‰ É̟щ3!ø Éþ¿°ð$„kîº>P²ö“7ÖÖjˆÆ*ØŠ¡¢4Oƒ™jn2-/™–ÆÂÌ:„wÂÎí5GȧÛqòÖšæ à&Ög4-IËØ*J©Åõ³asøÙävÇ¿ê:Üï‚*ÌBÅ*ÜÏ´ž_Å™Y¬±«¹2|ppþÁyRÔ›ÏTœ:ÕèÍÚ2ü–)NžŽk’‚2ÅZKo»+!»¤³ŠNŽkXÆ|+f^^LºT8ð†}5O1œË3;ý’<‚[£3_Ê^]î[-ðÄq­¸7Ääç„ü7Ôýyù˜âõëür|¡7cD74zqí$P‚¬ÝŸ±¼º)3–0lSƒrôL“z*؆yDعÔïÉ Ú¦8ò†  ²£,]Ï´aÁÒí¡rw0h» q¯|¬üÍæpÌþQŒ…½d“À¥äê‚53UÝðXñ¤+'ÅŽŽÖoà"*þ”—× š’Ý;ìÛ¶£ªŒ…é“êJ¶„ü´Í G“®á¦ðCަª'Ô<¥ãŸ³{¢­%Ï&teƒeIŸak®V–mŽÅõ±ª¯YyýGÓ~k\cX9ççsÑaoZƒmPÄàJÏ1𑉳øäOc@¦'þÒVhxŽz•ûÔ VñKßÛðªE%Ç-,ö„®k¼’ËD׳=ZF]ˆýÖ]^\†¶àwƒPrÞ…R µÊ'(2\c샿3Õ¶¦ëzw[O¼C¶Ö?N—›zÞ$+\8;ÔÉ2“XËý‰Lð‹ü/£¾¥ Ó8aõ–’€€ºj "jcgéJ¨hÈú9‚HlG+“Ø `2!$BI€5~öØÉ*W6'Þ1 À5âóE¼öì­/N¢‚†ôN­<â×MæZ¤Ã ˜=›Âj‹Ôå|èbQˆº±ÁâwIO.A…ÿQ^Žÿ%Ž™$ ~;aè½)„ÕyÔ'µF¦]1Ö#7‚a‘†éÄÄ5”‹¼ë”Ž£ôò®l­Êy̪º1ñÑ ¹_A‘Ò2S¨¼'ÙÚÞ:‰h… ÞÅSvT^­zN"? ô¼¼ùñœÄ$K™û,žƒü°¦>Þm¾WWU¨¯gï 8‰C戓n@ÖRy!FßžóÜ’IÍCJ«éÚ‚)€vœ6}ðoô+ÑìŠCi|sìç4¾ÂôÆ_$ûN'ÞN]‚{+ÉìJ8ˆz$ÏûúNµ$€(‚ú¯µX3zóÓ-B4ùM’s;œýNVôO²¢Áœš­¨©ž›‘Í0P} îhxý‹•⪫9Ý[ˆM@ë•™ã#À¬¥û|Ýy™ÕÂ*¦b ^& Ž6Wö†Â"É|Õ7›ÃÎl€î¬‰àe\IJvp$$†I™—\iÞúz@ ùMJ¾—ÛaX8dbRaÑØÿ´@@ UÀ¦âï–ñ_W›N–žl™øjÕüÛÉm øI&U.¿ÿGx̽ånPÏ!kô?_+VFààP·]º$á.¬y'"¹ ´²4ôAe;(ÈÀK˜uò{‹ž%ðNÝ'™ ¬dYˆ3dßÊââ2‘Pæ  yÔÍC¨Kˆ™b¼n‘7Í!|¨y‘~àDø4ãou ¤p&/¶÷ŠÞH¾SŒQ+¦©ËZùra‡ÇvS4Ì0oâg¢Ñ)sn:r¬Qäc÷cÏak†\áZÓwxˆx§) £Íà3g+“•êÿ­ÃzxS=«:—] ÇvGƒ‚†%å 㥬6,+}V>Ýî*•¸0×å¯,˜aQÏcÕ“ ˆ”ÐN•ûØT¢úkÜ`ýR-é² ô½ä²!1JÒE‘LsÒ‚,–}ÇžNŒô?±£óþ"hÓ+ü¶4æ6¡â;É~¾ÒûÃ</¤‘­¨ƒ± Ìnt(K‹ñÙá%€›Ž±©F§Ó{½ÙnùÉ _x+Ýe 4Ý-ÔžØâÝÚ‡#÷Ö@?EÜØ¸cÉ|Oõ°Pñ˧8÷ÀžlLŠõÃ)^[ò´& ™HÜ;oA3#„ RšêIÚ!özÏ¥·Q9ˆò;uÀΦËa%~ƒ×¦§â”¿Ôj5¾ÇaFõp;bÏ ÖœÃÅÈa2{þÙÅ;ÖWôÚ›)Ôš”ieŽdí{ 4†Èr4I¸(Oü–†=ÕÒÙú¹Å(|þ-ˆ%ßæ£]òAù?ò—’˜”ÒÑ÷Yª¶‘ùKôßÕüâPpèŸ÷¬¾ì{!Ì Æ*XäoÝ2ùI #vçždÄŸ²ùJŒ![¢èAÞ¬íW¹EpøkÐŒŸ—›nò€A²—[‰ ?¢¬lü~K|zñÉBùp0žX0¥¦ÚíÆ,±jåÂh%Nl±ÆfA‚üD¤’€€Ä;‘NÊÔ'êÓ|Ù*«¾™ªØ 7Ä®¶åÈÃô‰éÔÔòÕi…52’NÔÔù/Mé™»Â|W¦²¿w‹KEì7Gû¿$–ÖÂ3N-UÒmêÍ;´bbÉròõ TŽ¡Äq?þ…ÊIƒm ¥2(¬íŒšúT'vçÌD<‘ÃÉ“U9²*ë.9nt«þ¿¹c뇢¹®Ø†Ú S¨Ž9®P¼;ž+:yh߬ÃD( £†ÂƒÀ¾ª&‰˜poˆ“¢¡²¨S®f lÁ7ö–b9Ú-BÅ´ÐB2·d»'Ó‡ÄÓç5úÆ }ÂÙ®)iï? ¸h“”ЗAyv éþÀV©]Žº”9)‹ ®ŒîéÝ.‚}û$Yxäâô'«ÍÈ^ÿg'ÂHÌd´4o1~cô†U3Ô¸{Y´Õ”ç‹ôÚ‹®Ÿ±ªTþÂþü[o+{"X2ˆ7¿cY8€“úɘ[±ßl5¦s…gW޶‘z\dZØ'ÙDÆÊ.€uAË[b}«o£»Üè« 9pLœã¹14ž'¢/oøœU9­Añõ¦L«ï¼Ý"¾6åÆFRYêÔ7GÄÔNΖï‡Ñ÷‹§/H:àÖ7¶—{÷'%iɧÙMÛq íž°™ÞN6~‚«‘(PñÍAðÌÔ.ÿØð1>¶á+4ÃquË_›ŸuÖÓøi¤¾ºMd„ž{sËaÒ¡ÁÂùó¶[þ=¼=”"½?`¯k€J7Ãý¿ò÷Ö…S¼Øeq] ÞÀøÌ ò—}H?¸ ¨ãŒß }|~Eßy aÿnW A˜Ž£#‚^a3'ÝОŽúïumt(ì-Nß$lÏåI¯{é§êO1 oãd€·§ü0­Ÿuó]TÎÝS ަw4k\ÏŸ‰` Á*6CAù¢ÆpåÝv†ô¾¬kðÐë‹Ê¦RÙÈhÿFƒ_«|œ¼:õ1#µ&=UÖ¹d²,hf|%ó¤Æ 1ÜV'µÂƒx»[!lpˆ²â!SCvLU%öíu üJ:‹÷¼~+¡ 7H(mD Î= {fìðØk1ÊÖDiùžÓ°1¼™J.…X.ÿ„‹XÛ­²Èà-c•¥MSΑÆ'yQ´¿™†Ï}8 Ôs¿-q\ƒ~™G¼’€€Ú1XíôÿY‚†`œ{)ri4‡b´W ~'F¾Â¢»=½m“ü§÷¶ÚsgÀÑÅ€‘œ¨ DŽ’CÓî¾è5 Ž44Ïå5¿lf‘¼»‹ŠäôæD2Žùý¨€Ðý¡±S¬¸[K+ óM›ÆÁPÖ8AdÇè×¥Þ§± áí"·ÑÉcŽH#’ŽGؾŽ÷¯ÔËe£œºKWh(¢ú5Ô(_s#£ÐñÚØ›gg0+àÂ"­Ü¦;!ªÔ»¢Zyå$ qé• i¨œxŒ£$îõÞG}80¹¯æg¤œùûÁDÜ»^, ±db+8÷”zP>˜z ( a댑Ta1aô«þ€kâŒÚxýw#Um²}qOo±t¹ŒÎô—]Ö8ª*®Iêžl*¶@Cõ&¡p[7cÓ“'”[D³x++gήÁ)”V§-Ÿým´²út\6Ëá#›FÅÑo|ªIxƒL~g;¡CŠÕ|bnmå ž ¯ikqD°IÓóù&úɃ9Ö;tdÏ{/.ÌkØ¿ÉI0Ð--aÁo&æÇ#ÄŒ!ø^±5¾§²Í¯×sÂðèŽuJ’æxðL FUúèD†’€€¨ßãYnta¬õÜßwZ Æ*À^f&¼¡oäMê7>„œŒÊµquªƒAÇDè9½iɽãÄdYUt–÷a¬ÓWo¦Ï,ø”o4Oz„ò€6A¤ÿN^¾eP:}î=Ö ø x_%Ù&ZýŒÈFº—šù:¸ó¨Tƒ9 ꊜx¤ÓôÇláï½ÉÊx7Ÿ¬¸S’‡,Ú­í}ÆÐlénòÃþõ¾ÿ;2nfIÃZßñ;¶!é2˜ß|wî*ÇÏrV9©';¥uàï_š®<§mÖÊ s¹9·ÙŸN$ca6ú'ÙF+ÂòV‹9ð°-æX’´Ò£q±©µY=­W³ÿ;¾ªùÃ!¦Ëó3«Æ§¼Ø1Š?Ð# ~·â{‘¤Ôh"ÝFŠd¾»¢gݳÎIZz¾7È•@Jr@§¶b!0Ç Æ8+‘×W bµæ‹Ÿ?*•"8¢ãºp|8ñß3¢¬£‡˜ÖƒÅ Åï7#Ÿ½°`zJÍeKé°}Å ãË›ì3tÂöÉ|8 VÄ º¡‰·Ëÿq_{ýñ>ƒl¸wt³øÍ¶²‘¢S uw* Šüt¥ €h \,ÛÄŸOéNGÆ›Õ ]h‚”kZñ±U½9Ø錡öKrݰÌYãÔ“ïåDäÔ5¤î-o¿â>T©Ô%Ñ0|öröÚ4ãC £¸|õ>(ªfa{'Í™€ÃF‰)b\àòñ‰´ÑÎu.M°iUÇO€ÅuQ¡ÃŒï X&êƒ|MbùŒÞøáí×*Ê«¡bëž/yOë9:AÁ†V‡Tí6¡Õˆ ›3á#|o0RÂÜã9ËÈ1bžN„æä b"U¶wÿf©9唜êS<¹žwõò>÷êZ‹xýÃQi]XŒ$¢ý»J8j¬ÉO bé«[¬ïaA¯¤¿ŽG¦õh”‚þ-=8$ø¾Æ³#øŽG[~ìÉJ»Cš¾LЮ_Rmk_þ­*l&ãjGÍà6Tà£WP<÷ ’›b¬¯²kk˜¨R×òÚ#Õîn¢í|±u¥é„äÚÉ(«P¹p°©f¬õ¶‚’€€Ò  d•óÌgp£š+hí(¸of¿0†_Y£í……> ÅŠš³QŸKu8ì›—RУ¹0zË*]+R/¥ï>ªoKzÍ ¢çtû¬¬ŸW3éÁÆnHkÌY¢p²¤n÷u÷ùO‹¤¢wºç€ÅÆèNÏÛ¶Òªï5þ_½IJ<‹ S~‚ˆÄùrÏ„¢@ò®¯³°®µjMdõ˜Oíï­úQ¶±&¤ƒJ~)ŒÝ×WºTޙŲ߾à8š×mQzÔÛÏhlºò¹–l?OŒ!‚%Ó§sÎ.NÜeA©C[N¢_…í ­ Aâ*sÊAŸQoX 矮Øé—RóÝ:¦Í\.ÔTSñsÂW¡…š¬!›«"ç–êN¡²fÞo¡Òƒ•Ga ð!®•#±ÏQÐÒåÉÈhDÑ7$4^Á«„ÈöεA/ýÿ/%²¸Ì½ØÕþ3ËQóÝ{ZˆÔñxÿ›.Dd…×18†âºB €ÅÕ…pr|ƒå¦£=øcÏŸÍÐ믆ôŽö/3û[/6~ÑöK\ìÎ5Åí®î|¤ÖdIG£r¢3÷–ç¿™ð}/•î1ñN…«à‹F/Ûtän‡Ãé;æ¸NqÕZf =:œïA8ã¹ì‹:àÅÊ…w‰60+(îwD3<–©½1SƘmµöæp&qÛaû©9®x˽§€@‚Åp‹‰¶ÍB@tç=Æß.o¼Ç-. ±t9ùPÓĺoz£gëŽJsåsoÑýñ6e>³¤P騦¢·:ÂÉïyÙüËûé¸Ãj×Àôÿ¶¤/nÁTR;ö¨µ7(¯®O\ÓùdCÙÇa«š¢9ø®3 Lf§bvÄx;ÈbÕîkªºþÍœz©KÊ’toFqâf¥lÉ/D. ónº –²&õC×ðbÔN"P8™æ-ý™Çñ”•?!¦fe©SrÔiÔ€Ñër´Õ,ƒËpËÞÊ_Á}51ØŠ¤Ñ³ZZHã™OyWŸÑ1AÔ àè¹Aœ'ÞrÝŠ×ïªyÍô1 •}®Îñ«£É3)¨r¶,c*¨cÐÍ"·¬Ü¯Ñs͆K`Ǧ vcŠùbÚrh,’êO’xbTu ¹®æDò`$ÜP°eåxUû‹Ê »oJè8( ÁJ€’€€Ï™e/K„•Ø«Rk˶0)wø!&Ìãç‹ Â0o×,@¢U:ÀçÿlÙ œ9§-uÈ.<m ØúbàBgÆ{»µ¿^ã]¢¼v8Qª)~Ë,š‹l«f÷î <ëQF‹\ÇX£˜Ï c:áß½¢œv‰~Ü?Ž›Ïªl”cý—`æµÛ—ˆiõAPd BkIñ““R×!”÷ž nëØ·±|kë5fµF¬%X‡#^«X*LCÑ[ OEêˆPï UúÓDGHÁŠy·„M¤Èò¡Pˆ:æw»ŸôšCëå4 ´ŠñŠwÕœäK-ê¿Z;ÏY`éÜ1‰º˜Y™Í PgÆöBo“X,J]›€— C ïÒR€‡eG¦)C™“=}9(A:±þòðÛ®m÷{?æez8—Á³þ â„áÈßìÄÙþsâ°tŠÂçá6$!?î‹}¦.FËŽô&#ó¤1‡š˜y;†¸²é`ø"IpåŠ)m`["¥@[‹ R%8S“Ø_ °^ ŸƒŸÂš2ŸoM"-Ð^.Ãéǽ(P„üÝ'w¢¥ŒÛŠù=‹‡êº'ig^û¹YÕß°l6Û’ðÉè<è¾¹Bi@~C³ÚŽ™è4òó •¹4¢Žºaê›ysB“]be‘§ÂÚäÍ@¶ýñ_ûv±÷ñ“Ó ”˲ö ‡6Ùg±³Q,Qƒ¸±iPí1 õôÏ»éM4¢g·UúŸ»[Ä´UÑÄ>…ϯrº˃‰¿H¾1‡ÿ‘í…Iâò¯F]‘%á žö¾¹«ó}ÿÙâv¯nnÝöƒV]q |Ù{Vtý*h º= T~›R1«OÙ¨Ý8HT!v×aqüü&æòØŠÂX':åºì- dýY±p¿b³r¡!`½ï“š¼î\b¬'%u;ƒey¡ë|«÷µ?²©Ïj×Ù´Úì,<@°…ßˆÐøÆ[—&£„PŠWæ<ø¦°pž8Jg7£o; B‰XîãvÓD‘ÐaÔ8°Ðwø\`[Vo׬.qæç}ÃŒßæ¡÷NȾmÓ¡…Hƒ‡î€o¾P–@LÜür¿Tn£¤’€€Ïõ]ë”å.çŸ×ì–â9û”ᜱñ<)0é[D/T)¬G¡=3ÕnÕÀ®œßõ¬tcv¤¿'œc…-~Õ/П0]ŸŠë©Rö}¢5Š ³´b„á»pxXy–{&šÎŸ¨GSíôd°ߎaÎCñyë?‘GDÊb.¦õØ}'«̱?·æO½òº-¹fá© Ÿíby¯>½,tÞéCOL›miÔsÇÕωÌiapŽŸ¨¹å'Š7¬0¡ƒ%À4Ö–å,XRiü¤l¦p–颔á<°Y}YÌ9܆™Q'$Ë¥ŸÜ³ӗñì‚#ks˜ÿäÛMÓ vjt>œ ¢&=G˜~>çå*..¥¦R…„º}*ýQ â bÕˆÆÛN0Î5„“̤-RyÁ±Œ‘•ëò¼sÌ?:;à —ÂÇÁŸ%¨õ„ræ Å'b«üè|¬y~½z…ô¨|ƒ×º®£ÐCûqÀr(±S4¿9ù tZ» ëè¼ [óBÇbmËŸÔ*‡—CÛÕ‹LTœxqNàüz³ûª*Âëf'ôÖkAÌ^†B‘­u탬ŒkäÑ }wUè /ßþɱÇû–ÕùÆÚH£Ïf JLVžq[ÒYÒ¸çL×XÃ-£b‚Ð:ïq ¢ê·ýëû âÌï }}.ŸÌÉGÚÎ ‡Òò·ñPwdÜ?.lªäƒ'±Ü‹CF/}¨«­¤é°,Ü%ŸyðÔQø$Nèm£V›³õ7t‡Àt_Oî'Ãõ»ÏàËb+1¢#""†÷¡'ÕI "+úT‘E[ßä« ~IOÆùô|=á™/ßZÒ‰‘­Ê0w¬bŽþëÀ!d®WÔÁb)n±²XŒnõĶo—&1¡F©8L¬WØò4¶>ô”áIR¥Û«M{ùÇ”?=)ƒ¿xä“·¦ï5äû]&TºŠG4¯5GR”?ˆ4ꊉBÝê[Y„ãAòzÂÉCOµm±%VÆýøeÁš!}“ý8?±&î[ƒ¢7pöV6"‘²ßCÏKúôá‘6ÛÒNY×Á›°¨Z:õ($ýzKÃ’ÞÍ›ßÐÔW=ëã"ÛB’m¤¸®‡ÒÆ&“¦áË*“jò7{”f<‚m¹@aÝAÝ´ú’€€Ÿ1×áEÚå³z=Þ ƒoq>óÛ¯#ìP[‰iÍgÛ̘‡'k¨Ô›Š×{ððÞ¨û`ÔÛL9‰|œ‚ò«<\4œÎ[ ,7ÁÑæ TrèBÛrŽ>–P',²Ÿ¬“®B°$œÌ¦AœæáÀ‡=£ì¸ÅE9xNjíNO_CÌá&Ï‚ 5ÞÉ^ÓÐ̘£Eü…¥ïrÔæ¿®09Ýx­d+‚¬`œ·Ä†Osp„ˆ˜tx3©í7뚢»ÝÖó}œ€8¸°*£µ{ŒêÆÖrë]è@–]Q%¡ØÆIÄ ¢šbXöO—´ü£ºÃqWåÒµ=…2%P¼šÜ§%ÉYTP×ãà@}k ù”g_ÎM ¯ßo¶¤‘`_¿˜›ÈÞ\LÃRN)@$éZ‹‡1œ‰Ì~µ¯œ¶6ŒÞ©³x9¬íÜlÂAŽªtìa%Èk°›Iª³C›F–‚ÒÓ¼OÏ>Ó£WÞòÆ–-p20Ò÷èQ^°·O±Ìä¹NN9àsÍgh½‹T5aÒŒÄôÑ™·¨Ôá«ûàý>pb˜Š}ÆÂ1ÍŸ½é̃L"“=º¢“( ‚UÙ’´Ãažãý:ËñaÁ|JAéô¢ðhîiK•áÞaiò5Š{†7œ'þ}kG¹Ù4ä×Xeóº¹Hšæ`¡£”™ÌÎX¹™v¶/Ýïfú |J:ÂØ£ŸK޵$…™ë8BþéŒ`ŒyTÚ™ÚQ¥¾Qø”zJu§(±/óm“íi?.rÞÞXg]I†„ÒÂò¯NÆw¤™;¡§ZV¿ÐrìQ#XØ8’%‰½é */¿ ›„ñwR{]ÆüÍ)ns¤^˜ †þ3ª E±ôXÅáÖ¢áͨ)¹ÙP<•(žð’PÓÖljš6H¥3ÈÓ€.È_'ÔÛ|œ}Ðzƒâ‡VÍ cÑ\âþ‘P¦ÊÚfeö}Ž©c(§ûÓ<‡©´O‹ï\ç?ê±Ý*‰ã 'õý²IýbšÛxºŠ &)³èáóï)¢þ*õ« 1\ªŸh’d“„L5,^OÆ:[âEš„–QÅ)Nv] êвÄ. ÈÞkïž×òªs/“˜Êä>I]?••¤°÷ÉóÎK8’€€²Ç¬T«ÿ'piÅ‚Çâãbþp‰HÍUŸ|Ù?ö¶ôè<´› 5²ùûhìgÜ{ža¢U> Eú¤J:Ïös(Š VºG­ì•xÅ´‘§]NÈѰC©~QM•àDų§+¶’Ī[Ó0RN1ÿÕµÚ$`­;û»}w_S²B«s–Ñ3/;æ)]V„Y••ž|*†–z®À¡LÂì°ôB!&HX"M+¡W¶3:‰†,ú{ÆÏpÖ­§ßôÌœ©ùLºg ôh  ôȈüÏÖ3|WWRM䉛~­¸#_Ìwo,Ì~.þ™O¸v],\šÛðÞ´]loô`¯é6dÅŒ.ˆþ…AݓՀOµåPõ…ºèÓzˆ¢ñù55È繕…šUÛ×G Œ®šK|*ˆªü>òϼ7ö>k*t/ˆ¾-ä{eš19l¬?‘ZŠY,5|zUõº¥Õ<$D­èS:†–|‡f/÷™m;^sãü•* ˜RE\ÅåOÓ¼8ÌTÈ`.ºÂ–JA.Ù˜ëY½ñ\½áG¹ïÿŽ|ïÐ/¹ã"i¾“¥å¸§È ‘ôÔUÌ#V²Ê«bÇ_fª^ VÅ o¹Ý)¿ZŽ"Žö&ŠÈë·ñ=ÿ83 Zì¢ù¶#EBF;iÀ§¯ªÜ5ïå~C–´ÿgwùŸt‡<ê9­òþiA­ RÕ¡Ï¥š“&kü‚¹Ëqõ31Ei¡2[zµCе4 º0 ãGÅOzëIh4;龃 ¾É´=g^â .ëT…­~o}Ùmî}"ŒO£sVÏ#!“iÔXÛZ}Çå×s¥8t’:98·Ñî¦FBlÕ¢©m,CÚŸÿº–ûŸ¤·ºk’ÌèŇÍ,! Lë>믒€€Åšì\‹÷œ -¿9¯YM¯€Eg|¦j ?·u›}9œUýp<@ŸOÝÜë&§`‹=¹óÆÕ±2%¹}@`š^ Àû䌅ºß)å”%Û­H7΂Z õ´(žq&ÍD#I€ãuö¼äÄ6«å‰X0ßI3-^¯O^¬Íp%"Þ6Üv [èébOéku¹ÉèÒ]^y‡ÁëX4tÁq´JE•©åh(ð64‹1ÚMœÅV• †¾Ž/2Ž"§’_mSÉ ÿ}Ò4®Õê£~U[ˆW¨]ëþìheŽu @Xt“üÜc97$nw%dZ3`!š3|(‡ ÊQÃe`š^yjXñ6G*ù'—ùèÇd¢n .—@Ș×ë·3ÖhÏ\ é'Ê»¼&3mOnÌùZÀ™ó\÷Ý=X2™ñ‚­Ûbi *Üš.„¯ÝKfP7n8òAr!슻$³!Îit˜6ÒÁv%FPîfvƒ€qùØ'-ÆúÖ;?†¦rF ÍrÐ æIíîšÂ®Zç}qyUýBIg\BNé@X:  hE¿iÉ^²³¥Ë„²Äî6R„«S¼­ÎŒ2Vë" µÑuèáNaúäˆ!²•{yþ‘2@íã6ï…ÔÙçç«êQN¾ÿÉXý†D½j©ć½Dj¾ÛÃÁÁì©›I†}˜Åš§“a»ui«*{$;`aë´ºt‚3lCÓ!i;ßsãn˜ÑæžaÁê²âµ¿úlrqPTÕYyÛíV’ã4Xέþ.x7§å­&Eáç¾~’úÏÚ+eM1PápYÏTÕ$tsC }´™/­!öküjŠ:ó‹Õ›Ãë ™8‘wÞ|R}äTظÍuRø&`†> ¤¹ Ô[VÆa0xι`…ÁJ:ã+Þ®âsŠ%ô í‡ ÂÀB…ôpÛÞïªwaúýKG¸Áº•ÝÄ—³Üi<-¡¬{+®£Âß·E@ho’°2ÃRpt¿o’&lÇzÙž TªÜÕ©CÎÉd^‘™ ™ $ù̪‚S;Yý‰&ƒiÃÛà­˜Ù‰›`Gxrco¢ƒ¦¬üù# I¼±Ê"Ê>Î+8áÐ’r¦‡ªõ ‰Œ›ƒÚ!Ü5¾;̵õßésoo Ö’„ÈÁ‘8rü.ú£q©Wú0Öh:t8q¾hXážñ«Ð1eÀØåÞ*æÊÍóqõ×Ìr!5Tº¥Êø!^ä)KPzâÛÔ[úO¬¦V˜“ŸŠ:Ù.ÔÝ.[s$8¯'üÝ¿:4P°8æóüÐÅ5ƒÍÅa†Ãs+2öu}tæôù8‹#mÿÄÙxÅ H?Ìóé*I·a0gø¼¼  ڥ׉‘9ØÁlɵzŒ[l©þ‘ó|Щ‡—)Î/ÂûÖ;iØeðÐ’V"å±_lé(^ª(üäðCxAc‡v†EX,B¸à‹Ï[QÒÕ%’€€‘l’§½¡xƒ¶ÆI’.ÎT+1Ém4ÍÑ .h¡¯ss¡Ý[é_ãà…U÷C™»®¥ü½\úÂÎq{ÖT­™ñ½4/‹'køï5ˆªpå©7œî]•@M¤Ç±¶jп/z;3Ê€9è“´S9§ïÌ8hHήN–Lñ°­1V:ˆÆ|ç¹æTâ«È@R(EŸ¦bÙÍJ'}ÎÁ¾Ê²—T‹œëH áiÔ  k‡*|„3{Hlj¹w’WJtÓ{H¾QvdíÂwóØV{èÁ(åX)MBö'ܚϗ´?ñØ­‡["¹xyÓX—RªT·Éje©ÛA@I|Ü¡à1ÉÂÜüÒCç$¿•¯´Ž–ø6ó“5»=1g5ŒÖ> ¯³"½]3ãUu2 m£{z{c;Ъ–öí¢*©¼ÒãÍ©•34 ì™®qMÃ8"Z2Š~DâýÄw0-œqA›iÏ:EâY³nh6ÆñYÉúÚ,jcÄŒ£ orÚ%][f_/}ÉÈ´jË%ÐBÒ¥tW-¥˜Nnýú¸rÛ53Û8ÒŒñÆóî?|”JxBb úØ( å·N¨úŒö…PPxV¦c;ÄYwóé¨VzšueYÆ®X«¶³;Lãjm»ä2Óš¥º kw&½^Í;=§7î^ƒ_“Ž}e\YIÀ«(V¿7³èq¥öâ߃dáŸí•ö¹Ê€ÓdYH­Ô†¯ë![’#T.ÙÒ‘ßã[-_ã"ÕÓÓbÎn»ÿ\yÎç*–HkÞ"b:›‘óÄxörEÓ¢ßë\>2ŽvøÁ»g¿B®z\!\Š/¡÷•\ÀªÛÎŒ> ¦†-Òsª[&yÕ¹‹â•fµøbñïZ{üŠe…ôy¸zk›ßÊîêBCôGµãWò"÷›FO{á 3•»{4ù€€`€"Y°CŒßj‹>„ðš/À„´]jêÏ™“îå´<üÏ"¿}€Ì´sïÿ±Ç‘S{¿¾Y5笪=AŸ·?]S?àcšWÞ˜ù±W–˜Þ æñ¬§5óÖž¤ÝWƒ¸î piCétéüüZªü™swx@ÍSV“o±”™'âןËù ¤KUy6¯—Ä|Ũì’ÿéH4ÑíÌ÷A N mæÎ#X—Ù1λʎCXþxøìátH|šXŸ òB‹ 2D&)õÆ3›#_µ´¢{EêÁ ߢW#`,ÍÙ¹äiÝq(GÔžM;—m7¸6›”Š=hd’÷h˜‹Eïå5lk E—$ÇÉp{`--³)óB'M*ÎÄ8‹Ø³ny¢›Ž½à ®É7¦ßr›`³y©qÐ$q”ZÚM’€€¼˜ÿvl—ÚàÜ ð@ƒÎîj©kˆ€¼‚^Õ1¬ÒrzpJ6E®R~ÀDõQ7½K ef6Jà)ÙXmÍQ”p/fÁ/¥¹z˜‘ÿ¥gøvÀ”Ö”h›âc²Žl!²¾a‰cǦ·³{¯Ép¡g«*ìW×[Ý7*öf¯øødåŒ^£b¢ÈÐÚ88ÌòÆZ÷ò2¤ïÅÑß^‘æ½grL¥ ÌAÝÔ%·ÔÚ ¡) eïI$‚Üæþ¯‹5xC®›)tZB&ײó¼Ù «‡> [ ”Riûcye³·XŒX÷`çÝI `“úFèøåxÝ3{O­R·«š-bGXÁÒBæé#°Ú’9õML5ÿ‡”ê©ÿnÝyõ[ƒ±YÞaÎý;¤OWà`MâPRŽk èa-ÆöZ4CK¥†ç#¤(Ö§¯€²6'40¬ÖæS€%ê@ÖÔoóý=æµuàÌb‘!^°«¦=ù ¦ÔÉeórCNÕ4\®žsãß õº,° Ê2|Š“ µ‚nNðú $œ‚ŸUÅ~X5G•¬xE¥ÝÜ»Ó}7¿ÁñEÜë ¼’xQÈóOEÞ¿cîìÀ¸é ‰b <‘ Ýúûƒ z‘3Of ¥Ö×ò O›V°¦ñØÜ… °Aâj÷5îÉW”¯÷¿·bÀ‘Ø”A—))¢ Fèva ã^|ù˜¸‰€‘ôÙ;Ÿ쇎ˆ-wSc“\&gOÓIi'h»K¹~åè„Ä¢YµÛÏQ¢ûžD¤Œý‚ŒŽk˜fôñÉ%^¿ÄOOÐ ‹Í£;s&ŽÑÕ2mºâòõ/rT(ÿé 1‡w|Š#ÐÊX•ìøM%Ÿ¬bURš:Â{p#”ÿŒÖµ7|bN&Ç2¯‹™Ç•!Î5CbÙˆîÙ§Ù\é/ø4@Ï&×\DôÊ~6üØ„NÑŠì®,Épüп›^ï¼Î¾êÐu½ÑÿÅžDMG“}¨· ã´lÁ'–•*TC&ÿî€QÐW1ÝX£A‰Eoùgõp¸Zc~˜QS`K¤â0î»F‹º ðNÐmœs“¶=vxVöŸ§ØU>ñÉ®M´"ŠúçwüÔ7Ç“°*#ˆ¬`,ä»’ÏåšmËÛ¯$ÈyrAþƳ’€€KÞÕÄölÈ´+ùRÀnœJÜâmh$›–ûGø.ª#ä,à ´Û™Éhlj*ýdß`@±þë…f¥skYšeùݦ1Èù¤)¸Z/h0`/ L©åÖ°bScVW}Ø~î6ÞÃÛ“ßI,3ör<€!z|ÓŸÂòšþ-œŠxƒó_á\y ŽldÛ®šNÑñp×@_ºøîó ä8³ö| ľbºh6‡€&WÊðß À³KWèSPü³¾Ì7G4ä¶?z2ñ»hòÑì¤;Z±ºÔòÎ+[SÏ]³c)‘D ?ž ?2ce†D !iÈÍÞ6Ì&Cß·Bi½Gì±^Å(Ê›ÓvyŒ¢À—=Dôˆ)j ³`Æ´G¢N©±_²dÌý+‹Ü¹¸|Ní^±ŠÙ¸Í£¹­[SY €+o}\› åGhoU‘¶®Ú?&/ô O¶Ó£]Éïõ½Ö¤·&ºÊkôS¨Æ³ûÔQ‡™áA‚"¤æ±« bê7÷#ù$˜ áê֬˻xlØÕGµ44'ˆ]Àß¶ÍŽžrŶ…¹½TBp·ZÚy©g†Ïö¢ìïžõp}Ð_ Q]€ªn *–[N¨ÐèÒw3t 1û«š?kºPBÍŠÀ ‰ùfHÂ@$²]A›Ü¯i.ÁÅ"Å„ªs­T~&Žjxƒ¦h1Þí‹ùÿÏ:ˆvÚ±½ô”ËãåðÙa/D»¿«ŠŒÐGøorÀfÃü1v'Aºô©+dZ3 ‰Æ¤€£÷ oSnË([ü4†'íÿ³é8yNÜÏ®+"›õú·‚%sÁ«»u]‘5ˆjó’x³I£O†(صeˆ¿}AÉñFZ&†s_­,³}9 ŒVLâS†æßIªNz,Õï,¾Ï³ñÄ›æÍ1ù3;†¯„w+²ÖØOøº¾ó!qH@»}‰ =-Ã)´ xÖ<Áœo p¨£@e™¦âÈŠ{Ô’•ÅòƸñC¸«ìvÚÌ|Šhp>)Æñ(!6Ì&BíA¢œ.ƒÁòZÜ4…Ý®® #>%;›bʽÜp7;!Íy ňGü˜÷ÍŸî³îÑô*?Ü¢¥´e?žñ0c* yZ“ls±§ØQ2ÜgñŠ.2„g¡Üþû /²PÕ†ð¹ÓK%6y7]eXÝò”ìö=«]ç"®¸S•V>¨s8„®º|•ü³ÝG¹~{…çè6²aÞ ßÐb„•y’€€³ÃÇŠøÉö·P|eDvF¸#¡·ÎÌ3läù„îE“8—.@^Ëû£e0ܰ:vò05f÷]€]EæB„"^8ä,†›C!]PRP[P¾¡–>´ ðI£b·æÝ¦%Õ> ÷_ 1¾¼¯;N óäÃ,•±cÊæ$j¨3¨ œp!«]ûI‹9Z; À Ôì 7›vùÙ»¼ÏŸÀ”÷MÃÕ¼caîpzý’kd}ñä_žëƒÅÞ>¼Ë_Þ·ž¯€z+ƒÁ(úÑ*8³0‹Ø?mÓ j×–m \ÛaO]K»v{O å+hRkÙãF­Ü¦ß©Ñóz€öc*%â§ðÒ&/µ¢ŽìA ÔÛU,{`Çöö…1Ð'ýН¼•zsÙšºÖVöÙÒûï´fÆÄxê­C¨®-:Bù= í×é ŽëÅX@4üÝNߪö~$ 4—¯Þ»‹úƒTàç-A®ïŠ°Ò§Úí­’€€Ö!‘6¿™Ì*ƒù :®dÿJmÌ‚å¼ue‘Ѻ=þ!Jê»KŸ¨ŠÀWåœs¯Cþb¾ô Y#;ßôJ 5#Æ,i+´o?é¹(¥¿ ̹`ùKIä´ “j)ýPH—n§ èÕ6ÂV\¡Æ^íÉÕc':Ç@Í6QcèÖÌ#ŠnòHdy÷-Ã'ÝÖ,/í<©Æè±ŽÅ.‹ô%¸# ñ(öa8•î["çoJ*HglËô˜àÎÉ»Gs¤ÁŠwôþ}Œ‚¦v†ä¢þ'…Œ™®Ž`ãCÇ<@qå1ĸ„¹íM ¥¡Z£Ád§ý8Úª@˜'ðfsím{LÁ»@XË'ðzEð$ðêéäÑxƒ ýeg~…¡¶ÁŸ;bõ–ìëVbkæ=K›)œ<6ê§cªÌ5öP µÇ _çh¢ïFB+ã›+V]^À/†kµ áfhÚÙð‹Á ù8–­òðËl^8´÷ÂBlÝÁô!Éûy±qD.0ÔXñS&ë5"ÇVx(!õ£»ûÁ¡ú0s§à×<˜þ z61`àsZ(›Ás§­{‘ʈý’©¸ é<‰ö †Vœ Ô3 -„ÞÃ-¦zÒú ·ß=Ë¢~„V· Ñ¡š F@9Xgq5e TAîJÍz“W!³I™êežÔ‡\oò"S×XU&`øq¤7@óIoGÑÈ ?Kßv’‡Ø K0àFú7e ëÌ´—W–ƒ Òl–ÃOS?‚ÂCï±Ïð¹ßÙÌè% öT- /ô*ï÷eÓG×›ŽrµbP[!\`üÊx\n²Ù`ÌÂÝWHµâ4ÞVøÖ’€€Í‘€w{Vp\ýbÝOÖŠ@ç"^аKŒ_÷Õ[ fœú/¥Âd#`B醶ÄlLÔ?n8Å»!¼,Rru ~´EåÁ†døN·……XKýº•šž¸Ïâî›Å›ý-p L Šä`EɵðH¬8ãƒ3·S4‹ ˜IÁÛ0ÒjÌŸÖcº¥ÜŒ@Lc±Ø|]€º~[¯ßÛ,E"×|³¡ÆRW’ÄA¿Ô2ƒÄm›Ò ¶&VóX¼à÷ÖŸÙØ¦[%¦Ä¼…ccm§Îaø¦â§ì† #Æ+à(ÏuBU½Ìë-´2DàÒ,¨}îÄÉS¦Z±M<Á¿ua/$sAǾ•Œµ¶SA\qAŽP‚)xN«“x§™ÕÝ3çÕÇd^(¡Ž3¡ÍðIYb¸Ùþ†a¡-ÛF €ìïò:Q@6?™ÂWJÓõržID€’Ï…1x»ƒjÞ©ÿœ²ä•Õk3}¡š?K+©“lŽ6Ô­PÞÖo×)ø†%·÷K¨{šk’rVêdf°8¸lš÷W5J«Xþ`—^]9ú8,UßÓ¬þNO2œ,fÕ¡IÏ »ØABþæ‰&DŸ®5pþðv7 /Ôf.¹ÔE±¾§íä‚DHYï˜y^oN î¼À¬±Ôj››­„ž 9èkCùw½lŠ­<äoIQ[0|Û"l¿zú yNbÝàн7úQ¨åæ¯ëVá_ ´ò:ÎÚ”ÅZjü°N›7eÁoKG¤„c|º(¸×lPžàÉfÞ†?6eòm9+u|© ¬üR\ËÈàiüÉ@¢µ~•Ê¢#G„D‘ò Òòýc‘PÚ Žvsº*v“Î(m¸Væ nÀi?³Lvl‹Y0ËÄÝÌÅç\ß|úe©çR&j{cÚÊá9 wéo¾ÄÉ>ŠÊг‘ƒh±äŸ1¡\šÛ®œ®mÃñ‹ºuÒŒqFE½€¬eÌ-q°3túó ᥃eÀÓT<«7¥¥ ¤‰F'Aܶú‘t•Åߣ( `ë×üƒèPövß&ú^»I^qŸUosÔa¼<|  ([,ìÆÈæ–³%’‹Å‘f¿ <'‰B¡~(éöTì}þ«jŒº[ôK¥ã=Fñ³›œ€$‹êül Î…²ýƒÈd’€€Ðš®~Ñf»jâA þ1Lƒ¾ÝPUlá5‚éø,ßt¢ð~EN€°Q`¾â˜÷Ö‡ ¥‹tr(X08,çѬ@]DÂ&<˜!‰‘¿Æ¥v\˜é¦ècž6ê{PäýWÜÆ”¸s¨Ï“ÅšèºÈÁÊe-ÎʯoÔäÀÜ令óûµî~1eùRŠ7´´3QΉÔãh\¶s¯»fJ1 ßêFq'±Sx¾ÚIátP¨¸içH;2Ì]ßìªg€Ê½³`Ï+Rƒ¨¿8µûȱ€7ÌG÷FçïB™pÌ%.'>3ÑŒ« õ=Ý7[œ…•FÉ…u&ÝÜOó“8Y­nàžo—/ä¹ã ¢ù!b\Vuî¸^€…wÌ.2 x˜²WÏÜÕÈ“w@ñ6ôÕ–îÿŽ7ú2”/³ArD |k¹5t– ˜͆ÙGð‚ý|Ñ Çq†ùz,Q‰þon¶qžÁ,óÞ¡å„´ôwЍO‚ó**ÚBÉÈÄe¯ô³*ÐXÀtA²,ÄjÅゆÈ`®ä ÇÅËâÞæb§^³,Öâ-<Êö°¿Ê¯ÿ––D;Ä=ÌôZ:ç*º“Û›EOëJpß(9´ÿ âëW™½ãs¥54&«Ú]37°ŒKVxƒð#*Àþyúƶû¿çø†ÕƒV2~Eª´”ߌ24ϵ=##÷ˆÚöÚ_˜˜tþŠéÛ¹êžå¨œï%¯¶cü§hQšíÎh¹Cçøb¦?A¹æ³/Žó s¦0úQŸRH“A÷ïãb3ïPƒ`ç­GÐ@Uq—3¡ó¡Ü¦«ÞM1ĤU¸RGÕˆäT¬@Sïc`Cö3˜\\#â¼øn¢…”‡ö‹ÎlO*Á3Q¬5°žKô—”gËÅaâ* ¨³Õu§7 M(qæ­Ö‘.iG¥§Ž¶Z¶%DZÃ2²Þ h$s UC³XT´z²i'0àØ ÊôgV¹¼SKzIH ßü`uJrý´ê•©¬›¢ÄÍžnL¿ËdüÞx­—̹LÛ–ûðHx·w”FÅy-ì3m0{6®<«BÑðt4FE¦;p4(ï W’lí°XýøbJòŠ[˜e3‰|¥srWÐÆ"{1YõÜ¿$iGƒÁ•ãÌH1ú—P^õ¿w’€€Á‰Ÿ=ÚsÕaVÞÄE ý(¯@ƒ£™ŽŠHÆ‚89¾A”‡Ù9¥SMEbêj’h놗ÊwÅz”<ÿ7‹»™Õ‹[¨[ÕR÷ÛÔ8šb<¹Ödµ €áF»!tÞ3¦|…áuŸ”4-¬@\\J©÷L‡”Õ·ßhg(@ËYã3֬Р/¼îKº;Fá”=eŒŽž ²{Þsn47 î ZJ¦ðž«uÞ±˜¾§çÀ›V†K›AVsÿ]&h¬-¸-ÆY+S/\õY§‰õ·E|~tI'ajìoûm½n ‡­hƒ— غ[Pmb?„‚ŒÐFáçIÓoQKP}>@ê.¸ù=Òç÷âd²ÛÆíAÿv÷RjT³Åd9~ê4 =À">é ?zr ­ªAN}2r5ô;Ùwïò‚SžtlÝ)‰³”!“mí_¸ç0ºl>p¼ÃjÏÐfˆÑRV*°°y‰*L:ƒ¼¹){aõ·6>g²hÑç8È2#®dº¶§œebh|H仦b’g¤czEÖña*(»…˜o¯àdwœíI;É={žÒ2*5Ín f¢'SΔQBïÎè“Hí¯"Ѽ_¨¢aÙZ%&ò‚ri3ž/ ôà7÷% ]¬5LB&*T»’úb·ÿÕ¿sä;à6º0Ù ø0þ·„ËIŠj[ -ï Nø3Ù/"eO~8½ÁPhã‡xyÙ‚k~·y^†·§]†oN^P%ôlܬ“õrÄÞÚÉãNúØÍ ´EÈjÕœX*yRºøŸŒ°& …?š.Ü´ü4.#O§«€„™f´F`'øÜ\R†nKàm5ýÆyÜíÕ›)G m¹x9f!hÛÁ‰ãL¿JÞÜ>vT‘¶i’ˆ¨Ây̹NôƒfíÂ+d„!kkÅÍ:qit”æŒË¯ô™áBžÒû«‡Øúøþ_rÿr»g+%@ã6ÛU)‹4yd…èí™´±(͘Ê~Ú=Ͻ“4|iH7fXüÍá9pžËÚlصL,è«.%9YÞîw ¿Zj‘ . ¢˜èKÅ/lçl :EgX¿Î}7]®x)Ûé:ÂÃߟrE@Kª-„C’€€ÉO/0„*—Òöî# ud-„Ùý&LÚ¢œå]ŸØ^ÛTkî3ª^ëõè-g ‡a£Ì°6|5ˆ\N°Õšòc¦sÝÑSU8 ÚmÀclưɼù`²äç¥qOlQS½£ŸÜSÖ„I¹öÅKcÒïG‹S èàb R²‚NpR Q[53y û‡ùWùÿöIämC2IË$p¾v]­ÎBâ~äÃØm¼~'ÛÊvdÂ-¶ÍgBt/ÍÂíÉè×cÓb¿²óWEòzxà¹9íØÀ÷¥™iuöMž1¹ÅƒWjù˜xæö>ùؾ» ÔÀc#®Kf¥-}I®Ú@õ¦^ eY7±TÃíó2˪`¥dž9ºA4« ¸=Hbþ!H=‡H+É­ò“<5\M:òÈTJ{¸¥„Ä"®²éNñÕ¨„,¡Ž%!·Èr ž9„;÷†N¶S¡ìŽœD=¼=Ę8xPÖý¢‚¬1 0ÈÀ’=ËÛ1l#ÖÛߟÃYÖŽ{k{#Ôö¾$³·ígךì#Ô^¬^Áøsοá%ÖÈú Ôäo†Øv8©½ÕXWV£`-uƒ£Ž…ÿŸœWØüÃæùWåç¸ó DN»"Hi„‘µ“ZœœE‡¢PX%”¼!ï—U•Æø´ú”‚Hy±úšà”Ošñ¨F aÄ.LÁLAÁ©NqcPs‹h÷šq ¶H…Ð~êÉ,Ç.wðÛë÷£ƒEùE.' NÄ(˜?‘ûÁ?ͨ+Æý¶¾%KûŸ&ê­ŽàCírJº”¥ŸŽT Ñ­!,»GšŸëY?^L%ˆáŠiͤ¡‰“;iÕ—ß/«í4ÓÊM܃{qGP±QLEÌhöü¨‚ˆµñŒzL÷L°Ë‘Hkºø1ÐB‘ûùÊÙœ°Ï;¨âòýA!BœÙžŠ!„–Åaßã;k³€°?iÝ„’Çûm?Ùª@¤uh ~øÙŽ:7cbtÒ±­{Ùü'íS8ÕÕŽã£H(Å8î·`DÆ$ÇÁ:½ô¹wÿCCẽÀ'>õg*¢%Â͆õeÆJÞßXn²,[zäkqE !ƒinç÷F½z§y&9ˆp9c¤Ú/0ƒI(Ië;DÎ{Pî:ˆê:ºº(˜‡gë³H’€€¹ÚÒÊÊä\íÏbÊ(8ÄpÅb‰ŽŸböÒņ˜}:spoÓþ¢—Ô—Å©ì2§ÑóN¸ÈÛ¤¹…Ý›C”—™Œ<î#t³µ<¯(6@C÷5GÈNÙ9ðpЗ*rcP{[} de.«Øvÿýû¨‘ô7Õ³"Ä?g=é<…ÎxÛ §|Žw\“‹ž’²¯jÃzý¿>+ ÇLŸ‡ÃJ'¡Ä ÇJú¼‚Ùgæà´ÎâÐO˜…d+ÐAT×ñJû±,åMšqÇ3:))Ť&âŽÝÏUï!¬ 2ð¹UZ¡ kœ³þ¥Ù$,ÖfªV“ÖÛ~È·÷?øpÞè\ÓóíSÉHHw vJ3†eóQµc*í¾’Ÿ4·§1A™9ÕÑ|懆sðÄŽl&ÑãZ,(ÑlüÚ>Ü—ÿ1Š)?3_“é´^8>i,¸NyŽïö²1‡‚XÎož{—NC¨¹Ð?,C^.^Gí!¾A}÷#cÚÛˆº~ ã¸o!˜6äIBzF©œè¶âÙ¸ :lž«Çð~ž)Œ”Ä’ ¯u¼‡Ó; –¯Ø®È²N|;œ)8¾Kãé…1ÜAO2#ÂsÌL€¼ŽòƒwhÜ4~ ͧçA˜:Èõöp/'*¤¬IQÊ ¹æ4ÈèòÊ ,"Áºhßt™Q¼ÜO½;±h%Þ‰µ\fCgÕ„~X/½Î[)zÎßQ§‡Ï5?Å ùôQÄôº$ÏË. nÖAðЃÈ]pQ¢•ßòÝ¢\o߯hÔÔ²j÷Ã$ïðs˜J&f‹öq‹ïÏšaéŽÅ›Ú)…%ÿ » 9½¾Q0Ÿä*Å}í”qŸ%]›?ö‹[…¨þ#oÐʤN‰õÇÓ²™¶y«E½–èùºÒþ*=VÕCD®?Éãä5W’_òN!3·@ý»Ìú=MMm¤Å´£ÿmm_uÜJ'våz¿·`/øÇÂÞôÐÓ$hyéÀ´øLпÍÝ$XÏûœCR¼—ÛJh7Ã4€Ã,ûv’€€·Ðxԟߦ0«‘*ôÞU­Üf”«ü19¦„V÷,Á`¡ŽºD€þ ŸfÔÌbù³ý–­s´0GÞ>,«ª¯¬kfô™¸ÀêÌ!Ô¾õ=K*XeÞQr ©þ™g…(çÆ!{/ζ0ÿ°— „2¸PŒxfŸÛyuXH†»"ôˆ@Åh3‹(¿°MçH&€M­=¬‘þ‚m×¾|åd¬®ýß-DG¼îbš¢¥Ú·Žy}œ=sàÀÉ¡¥`T 1ú¶íM+‘Ó9…ï~Fk1]˜ÂýÜÐ?Éf'žO\xÏ ¹êlc£C½™œÉoýü“ö=ȯ‚“×¶Rvƒ4¼?9KÁòoÈŲG}8j˲¿·|Uä1s" í6×ї†e2»IµRßÍ¨ÓÆn6 Ù†& g`rΑxÅ&@úÐûÝWÒ2JMƒÝø„ñ{LeTÁ¦#`¾ ÂÌj6 ±ËTbiŒ;î 7ΘšWçòù4la9F.T¨@Y¾ ³1ÙàQûN<´L2^ÅÂuy+¹ ˆ»I¾OÚIé­e‘┘ÊqÐXqòH%ŽW0ªƒÄ¿Ç¨ɠF TÓc2mÿK8VÏá20ܪÊXñào= þŽDÇñ‰?uróu4óg\JL²?=›™»£‚eï܆5ñü†‹@ Rkà‚ÖÛûïñ rg×$û¯R=Œ™ŸÚáwDÍÝEhV£•–TÏC®kÃt㵋e¥&sž¶ãÌT¡T‡>s Þå?Ž+j$i?7»ÑÄ ;æ\?°þ|PÔÅ%èzÇÆsã8X…ãý—>2Ð9ùÔwäÉE%ñ‡£ÆdþpL'6=ÀzèýÙ¹€z@ð‚{R$Æê8ÏØd°Øfê­ð—H7Õ8¯¿H(ÅäšÂŒ<í9-ln‚)‡þë²¾ý$°®w¡•"ã2ƒØ¼iØÞWGLLÌ9)—Ñ2»…ê—ŸÖ?BAÂèÕJqùï®ây §‚õ€ÐÀZ·]·€¬ cóìÓùÅ'¦5æúÖËŠjܨŒ3ò?×AÎË,ÃT´4-zÅg!BéPde°æn/®2ená7Ží‘:ãŠz˧Š>LÄ œH«ÓIt¶ü¡A@IÕ (O ޱâ?u¬Øm›ƒ¸LLôôÚ1\½æúéÂ,¬ ¹ßù”Þ„­oµˆ~IêÒŠ’ô¦A/”ÆÉ(­û\t«ÒV!TQgnšõUY·S¶¼ÁÛCˆ˜Ê.†Qí[¨À@q/ÄYÞöaÌý¡]C’à]lÍ6ìOH™²¿Iï‘u°§Dòë_‡„¼Ó³T̆É “ªPÒ‚r¯Wëïš…óxàIV³¸%ÙU8˜Úx´¿¢p…[«ˆÀíØéiÆàQâ@ØÏy*Å%̱aç,n˜º.’/ð™´Ü£–©–—è­©l’€€ÀÏdzÇ,çÖÏ«wÁ€t@‚+R¡Ûy±‹nɃñ!Ê‘^Ó¸T `®wžK’=ƒœ·’(¥¦¤ t'Bó³qyö N¾ÿ@wÜ¡6~\t9éƒ+\L—|ª¹sÀ-#£Ïm|dIKÿÓûÒã6ðË\ÓÆ]¥®¹GioX\Uã„iF§;VT/OÔéÓõTS]Ùt²8’­çœj!ÑØ¹ hˆ5Î+óØnŒ âåjU–_ŸË[l¸‰3ÉS­p…­á×ä ü/‹uÖ² Ùoq[DC˨Kýì-ùÑr¦Åú¯ëù8[71eŒ]·ÒÉ„·¡ï~ a¤â $fÀÀ/Ô€*¿Á³š>i¸¨ƒRwk·ßHåqÕá–!Ødþ‘ §îrï,¶õž×ª Ù'A-xú«+ ‚ÑÓ[q®g<™B*y]¤-”÷"¿èÚó[ xa˜üó@`¥FÈ e{k”8ß9çh‡JÒvŠVº¢È²7'4É›KÓ­Ÿ%ì&š3 ó¡oTý£¶û‹´a•Y}ÞzVÀoRW¬•Þ¬\¯Õp*§¤€|OD/Õ¸/;]¹þOE_п;Ö­9á;=‹V>ˆr‰KË ÿÏ_?^Z†æ„Ÿ€WEñá•…ªZŒv’Åò?ëµ…n¾7©$±£äO‰Ê• ­c«A-•ö€6âëMÕ°µ×àU"mÁ”zkb…IË•ËÇ7 ƒmhE̪Ñ»1÷+KÐ'å4{‡}¡Æ&zö‡lBÛ2¡ [ºfF>_×ý·çêu‡Õ(·ÚÏ jAE|ôˆöÍ7hh©‚^@¼éâ¢)êH¼ ?QH¦Ã¡ù)½º"vð}ÎÔ4E+--dо%`×hÖU]ÊT½±A™‡räs|å«bÕüZ·k¨±ö`Fhé"\< ™L&zBЉd"„¬J×`ùPçÄDÊ‘ÆEØ8-Çó– {ûþÿ  ÿvt9ÈDú}ü¾íÛue&›ÈaÏ—V{G\,„„þ8Vˆnõ¢G“qÃÕ$ÍÇ(úý›j<gvmŸS–€§˜–q'úЋ`Üê®ÕÂNÏ#ãòkó*þiñ\€ÞqÅ5˜V\±4©|4†Ç˜»2½Ã·ÅzŸ4ÛW€µ;bÃǃ¡3åˆÊÍHåŠD9!¨B¨Qz¹.ÇŠ?¢šåÑç3¨Ðz¨˜0éŸWÃ6zMpOÊø[cÏ£‰Ì¯‚¿×RÇòΤÙaQž |ÿvõELÖÛÖÙüÉ€çd·›*[G•xt£x®»²µS/ô'ÉiÒïS“C«Ð¢$Å3fžÆ7|å°Q"8UCxá=MÆÁ Q~©š¯„>^]üäR©!‰»«Ù#U/›3‘ùô³=ª¨²U¨ç_?5¡ Æ1‚F•‘vÿ¥Uüà•cƒ3¼JÃÏÃcMdÇÕ’¸–ÎóP±¶Ïûùù+tÓ6’Œ®ÿ“@‚ÀAõå0M÷‡ÎwÑ£AQc@Z±˜Æ,%’€€Ì’óR>0ìÈÚZx»†ì˜ü'`¬í¡ªôºûÆì6î 3;¿PIQ”2F¯öRJA73­oJ3cÓ ÖþÀÇG™ÜÆKºV,H+,ÖdC80 ÔÁ4= á«ßGéÕ¼¹¸‹Ñoœé Ó¸s+`ATsîô+·•UM”bB=›g»:“ª>[(6ÿ4†¯¸>Á„o ÁŸ‚âXc°w~¦eH²—²dÝ¿gÿ†Ì®+K³»hmŽ·û(=ñ9ÛŒR|ͱðBƒ#Tää“Sä¿Ïì& ÙD6”’HÞÁÁ¶÷]!/ñ´B¹Ä¾÷¹ø*82÷­’€€Àyw ˜½yû³„]´ð÷7”$·B××¾‹@[ñ§×+è 6F{Vó5— ø¼kF·|ó§ÓòáÁSÞ 9GHÇ÷êµÖ"\N”4z  èãDŠÁÍÎ;û6Ü”ô~¡C(µX/ | õ»´Õsëç~ÀÃZ["mK–Ê뫨¨8¾¿…¸á‹Wk~Õ np¢ï•B ¬ÿ¬Ã‰­Ÿ•s¶PdvûqÓ6‡"¿´©‹Wù<óCÅ<§WOœáÄÿØ…¨\ó!=]v6ωsÈK<sy&Mw“>>žDs0 ÃÆˆ|vù(erìÊ ô•,'߇Ë9ƒ£ÅÌsÒ嘒tÑ]«X““퀿Á¼òÔ)Á¯w7¢o8É®8 ‡w¯Ô-S,šEá^|Üå b(:Éo¶ÄÝýA0‚gݽ•.£Ño0½ ´û죽Ðç wªôÿ§ §{b= #±9Vvb …EQDR3=Q¹Kµvi'óLŠ®Éw[@§bÊ­vÌvPa{‹ì\æxOªˆ9ùÛ_B”Rù¡ƒdùoi"Ã=~ðÁ0±Ì¾ΗÖ^Ke9Ãp,T?2ƒC¹pæ7 ò*Ž©5e˜ƒ^†áGSÛã­²Õñ?dôÑIâm>7¸];Ài‰Þõ‘Uöyô#`݃~ Lƒ¬Ff!Ÿs=I"tU¥£¬æ ü©½„>˜L߃T¿áqw+ñýèaÔ—§V[ÊÇ:[æCº–ÑH °5=Gá™êóž%zpí%Lw´;1MGÒBDÏ<,Ën6a¿k¬réveÒ+<ÿÄ[~?Ýãç àíéOË“+¼±hoîç¡æ5Ëš¼Ü­Ð4×ýͬ‘üG~T -ƒšƒô‹Ci ”hu+Ö6ë®ÁÝçfBÕQþà‰+$‹µÈ0“‚œT =ö•1D<—”¹­+*ªGp,!Ùž±ÃÕrɶuÌhÙcÆ•š£Š–•\¹ÁCÚ[im³s m96~,¨È?aÝ¿%Ùïÿ¹8†3š¤oÅNP ÉŒ&/ Ím[P<­ÿs5^ñÞLVQqóZçí]C 2±?oÛsÜî{7àÍø"ÊþàJqpØXX©GWDZ·Ä]:Ù/u’«ÜrNêòÿ+Z¼Û’€€¾ß_©iž9rñTÓ%(áTp~ð~qâyœúð±:£Ü[´¢§èÙ•‹5J¿)#©s~_q÷Ÿ˜Óøs}›’€ØMXþ[kC YâÎN¾$§`¢­6X=ûïöC:6]>š|³oBgáå(¶î˜‰vrC/ð2ðC³ðŠ6Nþ!ãh²œjj‘ž‹Öç×b×1ÔJ ÔбóµV£ë:·&òLƒæùíµP_…ñ®Ò >­ŠnW <=´îóЂÞTH… AÈßžxór¬$8?B¦tʖư{eïØ‡ÕFqD§Ÿm"½Š^ñàkI1¿û£%ŽÐ Ÿ–ÁGä¶_$þZ:–HŸL¦¯1èˆiÞ˜çpä‘Ó$ò/æ95¶I¬VçÍϹÝêƒP“+-Í×øŠ> '?)³g¦†‚&“\^ÞÝ?ȸ9à¥_0æ:x©ŽÓV6:÷Þ6 îÊš?:_l-P¾õ’ƒ‰~zc'B)ðQcÊw ÕҤÕÙÍä i½1X;b/l…QedÞ ©[9€ zªì"Á?Å›2Ü!#¥„ KÓÛ0*M:¸W56î‘#e·ªž»JŽÍû;œõÒ ÛVÄ_ÞÐôåú‚ÿI¥Ö nƒC4ŠŸþ ÞŸÆ”dO~ôyJ§7E¡ß#ºÉ)Ò¢”|¤ßÉ4 |Ä/l‘ÿHk­&ÿ¾wm¯«3OnÐéD­À2NˆékÝf¿ºpÜᳪ³ÛF”]Q×ÑÄØ^äÍ÷¿éSÇ„#ߨÃOØna£×¬ Ø÷²çìÏ`†Wm.§XÊЋ·ÒoïD¿j6ðj õ×<0ÇCÚû0ÖÙ@[ŨBØ2ÀW 9ûCæÈ›ß']‚®ÅܳÔ(¹ß=V댮³-^ Z|ëМ¢9)2݆#;½ ‹ S˜/W ×BþÆÛb°/N±ë(ް€ÆžeÊ ñïÒ ÉzÔ ðìäRu²oÜÒ7¡N5j'×âßÖ]Ä!@C8ª½$düëFóû´–Ù · ÝÎô`hùmilÔ(GuKÆÅ²Bœ‡}\—>½¼©%øZRñI®xò÷^~Á0SGªsûRã¯l”vi*Þó;Ø_¾©E›Ç+{Çë6“cšŠw—šl†"ôiƒ–ÓU]Ô€€Ð䣹*ù=i–dÃÚÁ~1þéÜ&ç&¶ût¢ci2¦ø÷FN™£7\­óîgó6ø‘,›½Ú[ä…¼®Ä\ÞÞÈ“ºŸ'F¼ëjÿ».úÝUmJ½¾¢"ºÚÓsÙˆóÐqÓbßÕ¬©¼ã¸àÔÿ¹XäTÕ1©zˆÊšÿãrqz<Îø÷* Û:Ì–k®à]ÞŸå%Wè.€/aÕM”Þ—dÇgy\ÇõL~I…'­Õ¶J¥\ðN޹—#{½wz`j ­Š¨Ü–J¹S©Â7C}Žä—9NuX?ðã\¡šŠŠåjâ/¨Ó¨KÚĽN8LŸžÕÒ«_Ü”õ>ô€o_ÀŠb³‘€úb’ôç ³ªëë+ Œ¾ï¿ï;kÀxÍ ½,F0\ÌP?!‰¡}Õ0õ(  ˜Ô˜§R"¤çG­*g´ø,Ô퉹”$ÜÂ2 ô>¦K"•;Š^ sÇ­»–õ³ÝTå|¯‘ zN]ˆØüoø5hÚ·‚ó½œù|‡Ì'Îã]®`z#Ô9VØðÛ\ò"MùcF(ųª.™û72úTÍô}Þ^ìbÀ` ³´Mi^m6u€ŒÜÒ¡ÂgÂ÷ŠV)?8Ç™I+2FO«Ú}z;¿åÚ6ðÉûÁbåöïôh -‘þKb5ú)ý‰Ü\áK˜'7YÜ+4?¶SŠ }Álj¦ŽRîÄÓVðÆŸüïÑH.©ßB6•IÅ·JjoþÄÝ)skø“è$¬¦VÀWËlV•¢o `ÜvP¤|‚»äëœÝY£ !O)ó訉d’€€«¥gÕKÖU‚ç Ú õ Xõ(y¤ïßø•r šÓÄ ”½¤ &$2˜—ý·ÖœT4¥^¨žèËi<$%jš^¼-÷`O ¤\1êè4FŽ5îl!ÒÌ”Io}оù~©áu©yuže›W'Ø8w/ov2­µÊÉ áLHÐV潕¾nžðþ(F¬œ;B2ÉLºžé` ÀT¢â—THªîæÄï[áóêÎ}áàNäÅ%Ÿ:.…³‰Q9x‰g2 Uü‹A $ïÿ~¤­w&¯…Ê& %$ª´|ºüË݉þ†:*'øÏdÔ5LDA‹J½Ds¹ë¹kh8Ks´y¬vY¢gÑcÎË’‡ŽÆ˜3s%¶IÃwÆ ™z¬.`z‡&.Ɖ ú} bT“Pû’BJž0Nj½ÊwûRäø÷>zéÃÄ•»²aCaÐ8V—¹¦ß£€áCßó/Fúîºnb»j…pôHÒd#pþÖRò·/ʾÉnέ‡1]¤[¤+BH±ÂÝe\„0 x5l·•IÉêV¥#š–ÔRû5&ÿK@Ï«»ðï"‚qSæÆU~SË#‚Mô'‡L#¿”ì ÏCmêÐöø ÆÞô‚³ŒQŒ%|¯F¦$Q¦$úEb¤BñºÚ3»€*Ÿ!Òà‹SÓzëE˜TµO¿€¦‚®t‡£ßhÕql…–‹qi)T拵M]©xV¦È嵯…si¦Øõ ÀûwP‹|Øü,8{™’,MSÙñ™áF ‰qs ‘€ßZp;l”Ð'X¸vï(]›ù«y´O4iZ¥&‚;Áu–ŽžÆSœi«Ð`wÛ/$•ŽÄ²k³ pöº®)_‹°!©BM×ä™÷‰9E2Ñw gbóÚ@­ôúNÍÆ¥¯*d”–¤—G dgÿA܆ZË›eNç2;¦w 0în«tõa ñ¿bÔù:z½ìs¶Oœ{At¨Ä<›¤zý+Vµ–Ë}ŒæY-«Pàoµñ[¨0@:0 p|Ê,úä¡‹ùÇA±^íZkTá9öƒ€Ì6Á@0žà ä÷™í]ÂWG{œûµÄjœ–¶Ë?ª|¾3x¼÷ ö‰4æ¤vA›z‘¾Ûê Í6Îe+'Ûeã÷ró#Ò Ä’€€Êqb®âyú“¥%m%ع5o 4 ðÏ‚šÀBoxqþ›‡gß/îùeåmÃ}3ÊY¶L‰Â«ñçzöÿñ³£ï¨.;6f!C‡6Ó]eÄ ò¨MŽeF›O¯~Çf6_ÿm9™Sˆ H³2‰QÀÚWçpk­®fHl·‚ò{ç§’{šIç Ñ̨];aÀˆ›™íî™@EÙÙ@dé1ûëÉsÅž/MÝÊ7H»æÝyÉctúŽ<œtOóÒÓby²¬ ºÁ¬Ã §ìuË›ªìñ5²ÙKËÌ.í²g¨µÅQb Ðxëè‚r¸x®§XòÎpähüé’I‡S1ðÛ¯bHä]E^¾a²à>²ûÌšKåÒèU ¢×Α}3ó uÎõí¿6¥ígRªãu<³Hâæ¿Á)Önib˜àW næYæ#õx`¸…›ª’?ß$aâ% mmÀ|M:ýf[…]•sŠAL›´vLã¢îd¾ÎåÌ_#‰uZÆY_j–]Íh>%d¿`æhÔ½á VÊ„-&—›r ¼:sM-¾«Ä„UÖ¸â_ *K/—ïƒJzIä5™Ùò¤7}¹Â4j°t šÞ6Úhv þñúÜ*+êT°WjÎF휺ž ×`XðÚß!]<…Ÿ±å¨¸`¾"¾é©~Ô–ì!è*'SËà4SžsgÏïN­‡ÙØ*8Q´TTºZƒÉ_Ó¡xbÔm;—áqÿ W!nid¤@ <©k¬r5[‹%áþš²‰\ìSªƒpØFÉ';ç…„úBG¬5L%,ŒFw6š}É}ÊŽì:¿J7ÛáN2Ô ¡¥ÂVü¨èåŒNHaD,¢ºì ¢rg‡aýcXˆ.¯ÆË3Ð76À=j Σþ‡HÞ)­ãÈ~fÍyʾq]žÂ‹Á2?­Æ ˆÞ0ë¸!ÓvE­°ölaMÏʎć4©‰á&Ÿ—GÅLúO1q3$“kt[ÌG.ü¦¨ÜÓúÕ§#¿42OWNÊ8×C¶½»3z¡4]~1+Gƒp‹©æ‡³gjN={ltþZyù›a¥(SÌñ°Ö¸µ`x2|lèE „r.ŸëîHt|¢h1£ön‡vW‡ïCº´aΚƒb`¿%烻ÞÒWNYûã’ø $È#}/Æ`†èé(=‰× £ˆùm—{ò.×N‰Œý/ÔKß]µøìôí’€€Þ#È®í¹–à‰L¸D°»ÄhQ³Ä¢ÈŸØ8ž’v°¹|þ<Ÿ‡h/¿üQ!× N#I§¬Gkhð/Œg1'êŒæXbçCVÇ2<"÷T¹]1†g~{Óf$­(ª¨o \›Òi­èÙ½°;,ÉÅõ‚2ªž&rhmz@rZÆ=‡n]æ½0¡&}w$ìEì9õu•Àɯ'<$q×I¨4 (/Ìð™\jsXG÷¿ÎEà »..Uù4¨µN6??0!ž\ËžÞ€çßÐ6oggسéǽÁã‰1¢ÍÄþÖÜaM‰íŠ5m$º¹²Y{úfeg·fÖdàö´P\€ðóƒ ŸƒR’L1øs ç*P5­˜4ƒVø2ã¤ùéCZð5rjü2ã™:T´°_„ ¹N9oRñ ûòd^ÑÍûÜGÒˆ2_wZߊ¶Øé…Â<|õ*ž § ®„aÖ}P•ò*yœfâ%%®—Ñx%ð´ð3L¯‹&CU”NÝ*·<˳õ÷ää^$É2’Ó²¨òãxþ{ãcC¢O14"*BHRb•ËCº°7µÙ—‰0vÞ_‡ùú«.ú8p`ÔC7úQ HH3æ¶íϦ¨Ò2c¾ÒdšXA…ÄhœÏ¯ÿÁ nì·zöÍOˆ%ò‹ñ– vh ÅÎ'‡ +U•eß *92úKˆã6œÞ·a)`i~l8\lxìw\(Bоiúmk:Êæ¶±ÃïRC‰/û2å²"Q+Äüº£SRà V>Hѵ™ñ 6!Òšÿo*hÿ6& kV˜Y”}ÞØh¿1^k†t›–ùß×:z¤Ô`í5c†šîõ2ë.H>Ä’€€Öјù´EiEž±àÓÔ—QÕPÍ’ƒJ¬GŠÎhy›6(4õ;kš™2¼¢tZ… ei{£ûg, ‡Al?õv0V2`Ý[$6 Ô7€K?Z²lÇþ|&³éuˆÃ˜Ö{˹”ÚºDò ­¥RؑԳid['0ýNû3Í× l9Ž=Þ íœ$N–•JF~ىܚ\صtv¡™‹ã¹•QgÝ#Ù­©ä …Ç?»nÛÅò»xÅ1ÈœàŽF¨Ì•ýë¿éŠÄZ«ªÞö¸ámÈx²;“[RZ;rx-£'ª·ÿè™莇ÁU¯({·ì¾ÈcZ’7½ßÚ´ ô-†€=Q4>Ì“ üÃòÔE¨ã£Áû 6èbq2MuR8iZO‚!ö˜H(©ÎZzÛZ·ßã8æ#ž¸;aÞÊXu…‘”óý…V>—09|†°ØÕ¦šÄ,Ùóàˆ_¯­¾è<£µšš éÓEÒ²Z;~¦kç&¦§Ô »‘ w>èée…—_‘ñ.dõwœÁÛèƒÌ‚³á«g>N:ZÈ3øë'œý÷åÂ%®+4Ú¥ÝHòuåã&±êü* ÷{ÂÉ–òvíW|gû<ÞúRbk÷p}¤ Iô‘9p}`ñòñ›BØ"lœè m¯ÑÐü]œs=H@µ¸pg”‡îãsÀ×}µ={/KaØb nøÿ¾}6ì-§\%ªªñCÉãÐåÜáwµkç5{þf2ÿÕ{›¸«´uÁ듳œZ²/ U[½ ɽ‘&E¾ëzçH¼‘Kqòì°B?mÂðÛ4®¹›ãø×»Í,Íà±Ó!a‚0¹Hϰ’€€Í¤`a$¾£Ÿ¹»L/ËœŽéóH¦¼›Ýj÷G—ˆ¿\)챿±EHáÚ³rxp®¦ÈW'0ž§ÖßÈÓùΗ7zš 9(ò+žR€i©áWÔ†åo¹OFÆ7·.„,â, ‰«.%[5‚V• A<œK…Î6&pµÿq´ã:fz¹?²OAÅu†˜jgûuÇФÐ)›;êv?p1j[4trcÔ±š=U i¬0òEµ=,ÛUøû™±w‹±r´Ù˜” okŽÏ¾Í‡˜£e)ÉÝç\N°þÑ9q¤ruQïÙĉí¼ÔwÇîÖr¾þØ’‰¨íïf¬0¢%< $´I@õR"wÉI^RDQÏ·€‰&ñß‹=úthÑÀ¡íšìæ[~ô$pÀ:+6Á>j eÂÙ\¹]aMÑZjC’²¨ÚûwG‘kbeÊrÇL>y$Þ bøÇIZUgZïÆ`-afqG„/å•:Ð4-º†-¸µÊ·e=y4± ¯T^Kyofà)Pà[èN æ>/Ov°zϹ^«Ò(?ª‹/¿±‰:¿ X0F0šíXÝ0æ•ãvöœGþU8‰«}ÊOÜ-ˆæÈwJ’‡m>§d1Böð¤ÙISMÃÃcMB9–Í6U¾¤%~(G0‰Áìb·é£VuD‡jK7ùm,ȸ¨5‘È÷äõKoŸ®Ñ“Š$‚»Is Äðh5s©ÞWHYî{OuPxíð«ZrTÑ6ÄyçìäçÒÇÌ'â†;S’]ÃQwMî iq”‰$j‘6ø4Å&û™M#ö™Í稂¿‹Ý÷Ñ@V èåö«saÅòö˜Áš±ïÙ˱™·ëI¿´’ç^ a°Jˆñ._Æg,¿"/±Ý4'qÆT<ž Æ幉„ÞiÝ*OQÈ_aéd·ÍÙ¦ræäcÝÑA®ãÒÊ®::\³sW>Úçƒhf!`’;™a-`ÆR2•‡”‡Íu8 ž Mu÷ap…KÒ¤·w‚± Óá¨þ'½CnF¸‰.ÄÕ”·mÑÈ º™ "Ôlˆ~`ù¶•ßà+èÜ…†•Â4¿rZ´òœAKcȇ$Šj¢ÐN÷CÎCfk^iH¯´á[-¿¼P® URêH1î)bè÷Xý;pU,àß]ɲ›V™[†õ]³½]l zã‰Äš/dš!´â¬êÌÒŠZu@ Ù穇ŽÒó‚꺑ť#Ý E7ޏÞuóD­Äꕱæ‚dгåUƒ8ƒYèŒæ€ÈvP¸›Wˆk¸Kñ®öhzKþ¯ †’•Ê@±ñbÛµne¾ŸÑa£u8ë®u'EOÍîöž¨§i\˜ W·ÈM/*³@$Èrõbܶ…ïèSîNJs­> ”_{Zf…5e y‚ËçÓ9DÒ¦¥Ç_ü¸Ú=øœd@mÔbÉ; þ¥AÔîáÁhh,Ù°ÝÛùüN mñž’¿–Ç z¿q—Þ®_wg®è{¾¡¤7r¥ ¸É˜ôŒ:p†Þד͚¨â_ˆÙii~í+Ó½^Mèó_&wê†{×$ê,å«ãx_oÇ=—Û¢W²DÐ+Χ[9fK`ü©«Çfûh¶M­HNH3)ß“âVUâq”«$Uy½ûÒˆ/ ÝÇ]4fA¨Ã „L‰GÞf8w“’Z½cÀ@J tuGuöÄýûZþx ›,]<#q9…ëDdôUGÜØO…w`4$¥ðÕx¾¿v"›ÜAägµ`mCjˆJà΂_Ð| Ôv!·N@38/¬Ïª:øIE/̓ɉQºVjÌP’ò0£¼§±r1_Ck;ølSÞÌãÌ”–6ȇàÚåùÝ^$îxÄûSwlõ b_/£¥°ëŠÃÑã‚‚Ðù÷¹7ÈmCêÔB)!uß™À`©d{щ8"¹Ï´¬ñ5{áXÔûÚ!¯Cˆ½•y =5¬»>%GŽG°ÉoCONŠÒŠ0¨°€« yÒE­‡ÿë}l9O¾™FWñTͺØþšsÀ-y1Ëq» ÒÛ×eî¬Ì$Bù°/õièûðr“»i`boXr:Ù»¤k<§s/{W(Äf[y¡%·u CÒN)â4 Ç๢bdë¶fÛò/_Îé9bKöpDØI™'íÅÚýØjçÎ ä6šfË nY|T/N˜ qãð½bë|åàP•þñ7¥ÌÙ«mASÞÌJïå\ÿÏÌ}ø’€€á ˜É·J¹»Ì¯ÓŸg ³Rë®Àb4ç»õʾ¯Ä qPɦàì h¬—¶ù‘=§÷b‘’.~˜ælÕ‡”Ý/v§ƒ)c«=bFö=uáÇKºöY¼Ã^9ýÐ[%ç[9dž×÷ÌXˆ€(ŸéGlþ¸óð¬Â‹-—‚…&lwºå¥M9Z”tîñX‰èQãlYl¸x¥•«œº²—•Ôüü=Pâ¾ :3LO­J*Ðëß}w#xÜEèÚî¾jäQ@|~d©ÉÔe¡ÉMÕ®ph©Aøs”ÚÒ¦CñªJa›Yq1d9êli>ŒîéÂÏþƒ¹ —øÛã3íñ¤t\t´ÄwÂ.±¶Iâÿ„à¶3öƒy{v¶{OùÁ³+3’µ¹F—S‚Û q0Ÿ{XÂW\,KÇ¢&0‚Œ÷Qº ‹Ì°¬×J Ͳ†ˆï†3 ÚÑtœÒ™Ùb·5oTÑÕTÌw¼ÐÕðX ÕÍV&ù"ì0«R5–¦ôf¶ "Àâý­Ó)¡o _•íáZ†f«{i1ƒñ¹©X£=äaôKwáaî ‘»7Mmœä;„PiÃ=„ÆñZ;u¡¦’ÙyÉgÞ;„~_}ïŒy¶Ê ¨çÁ¨(µíÞÉ’?Ep±»)ïàÆÑÓb|5ó|3[=§>… D3v¦§ÝÃŒÎx÷ý>)ùÍŒ`ô[Íä½?{M˜tÞÙ ª2dî¢Õ˜ I´`ê ½³­VŒÕBé5ÍBáwÍÍ$©K\#ó*t;š»7±3Ñ îO8ú-d¸¹½o¤ÿ¡ÓÁ“ݺñÕ²¦" ‹ÏÝS`¢Fì–þ\&¦ú‘žîE~ ÿÆ©ˆˆ]õ„åq%_ݽÙêÕ!ì;þܼי Àެ HMüa¢W©Ëß•EÂ^>¬çO{C¥ûÂÑ9(†úÙ©*Ò͆Æ`OKO“7 Í0og¶ @)ÆKyå%Ôdà”2š¯ŽB„êNÿ>ho]‡€]¸e%šz€‰u7ãÖÿÍ7nDã¢Ì¸Ï™—ý^´†r=("¤ñ¼)7l¸wþãµ]ŸÁQÍiFè'0ª¥EÌÕ.9‘•F O‹©™|é§¾ *zSMòâáÝH*›9UéƒaX+;›qLÎg¡tããÞ[6 ’€€g‡´”dÊvÆèúr!_긬Lvªq%è^>_\¼4  ÄÃèôxBaš©¦Õ^ð¶UªJ¸äEƒ‹pìz_0ý®è¥«")ZɰºŸ|²U‚þ€-íû.Gb«°:=$ÍDêÖJA4o޶[ØÊ]nÅÖ#»îp`Š ¾·€»"OB^cžJ³I1‡{ÞkG%&ˆÉ–VEnçžÝÉï ”lw!ú˜Å6cõeÕFò† Bów|†IM‘×ð.jò½H³\ú—Z¹æC4ß]ˆOkä×(œ„‡¨Ôľ-¨ª vlÿ#ùŽYØÉ)Ý4§ÄHÒSáëpHÍ—bp à”«ÂdX2°†g˜X Òš«Æâ±û†Â’ŒC‰f,çþvêcK¬r½FRª¡U£Góƒþù‘Õæ…ÜãñÇ* l( äïFp€¬€a;e£æŽ½áSQæÁ¤bVÞŠ°AU¤…=îÃQq½Sž¡Oií/²’Ê ‚¨Ó^Ôr€Ç‹æÉ_Ðù>œÚ€BÌ)^¦‚~n£Fdäp·â d2ÃjùÀ®ÏáÒCº2àrS¥qÃúD¥*¥8%n»Û((ø•@ˆ³ÅLâ ¿S|Ô‚>±¿×„–å±3  ¡ñA”%í òϦG@Û‘à½îíHªqÕB*7ØYÙê G¨”sΨƒØ‚Þ”RJO¾‡fx“>Å6¡Å-Øô¦“ànŠEl²W0tO[¼‚Æ¢_9qŒ8Ä´¯²×¥>m.È?K3`´ÄÀúB‘ɬi_›jßE¯šyÎ7]¤£p_›Î0)ÂeCƒ¡IXØ·ëE‡m¡çÞœ^Êr«õkýÌ»›ErŒM#“~¨õ4ì½GG;Fëbþ˜IÍc3~è…ŸÀXË¥ç)՜в¹‡0Ç€‹òDï…ˆá•Ñ Çåd&Ó³N— –yPF°…¤’9º¨3M¹„®ãþB¥e˜<²l vˆ÷à'e÷ ìƒQu-Dz V2¢³)âFtË©Cjh‚ÛÿWJz×?»·îÊZ¾©ºìP+“ÁóTÛw á*¿¿÷wkæ3öhõjS:ö^…Î…r·p£òXÅ&Tq?ëêëƒ!Í›¥ÈvYžêˆ·q8Éáoxt’€€•y²Î’@? ÔéÃÚ¦¿¸Ù´Aª¢Õ™‰ÆlT¸‚ìƒ(%ëçA—Ñ ‚_O¶û-J\< evä,Ó5ü¹Up€È®|[~Èè†OHµ«ûÐ=ê!¨¢á¤,í(½´ˆ·_ž{ݹÆšBŒ%:Z:{1âíº uÙtÊA¦xg€SLÂ%Öj*ó»ì¢s<Ÿ-æW™Ç s5þÜq$Aþ@mÇ!?'†@Œ%®ºn;TôP?ócAÅ€ÕWyyï=Emáõ W´šfGËܾËôÙÍ›'u™]DÔøöèIp§‚b^¹/÷u*îåI~h»öÆ›Î}MvF+˜I£r‚EWäDLav6@eésEoòµñE›WvJ‹4–u²D'G%þ;Þ ÈI’È$’UÁAÕ'LÕ¦Œí.'ãsxhõž–LÍk\Yà»g©VÓâ,NÞ4„ó€Sßדi·àú=¢7« È“’À¶nd]jtIï&2ÞW*Ω\Ár_ËV$w¹õ“»9wº§¥^Eï[™9¯ÌË aasï£LÈ5þ3J´Ñû{ÍœÔL89ª'eÎPë?ÙHƒßb£;ëçbbš û .hã|  C•^ýàÜJ…E¡®“¶€$Q&…k½@ÇBÛÚ{Ó¥Ì-c8nr Ž×ju}ÑõOj(K;[ôQyvÔj(%ÎtÏ*û›WŸð¸CÈp¯Y“âÌ[2k—`ÀÎJñN3ú2ú¾}ÜôÍxïˇ0ã?ÑmiŒáINõ‡¯+¨sÕÌ}ÒIsÙª;\ŸXÛàS€?­YG„‰ŸU†Ÿc7WꆪZ5½Âc¨üÞh¹‡l+Ð"Y‡”¼]‡žz²ö;Õ•b/ÙBKbÊÓè‚ØˆOë•ñ©¤dO -þ²o¾ &rü‰|œLÒN^MX…ï'yçö€† 9Ž;´nœ¡3*ÍÊþæÒ,Ýî/q]ööˈ™¦sË^«¸›î׌¦47­uHqÁéSÇ;íÚ4(ì½Ó3¼­òØÁݺï þ¿Ó r´‹‘à‘±<™.+Y©%¶ÓkhÅétsæñ9Ýõæß;5˜¦;oÔºÑo²¬¬ƒ? ×ßÖ×-¡ëmP£¼‰ãòò[ª$´ƒ7÷…š« ßÝAuá~úòªõÔš´#eÆQûEøuUîÊiBK7Ø,8²tÆHj ¹éEÁ>—îjgÊzب/¾„£?[]\ðû¾ByõŠ»´–ÛŽ&&²9À'š ~G¶ìùŽInãN2Cõfæ@-Ë'ŒzjÀ…³¾Ì̱~;Óy„®ÊUù8ƒ¼ã¼SG³dôFE³rA>øSñU¥r?-’ᔦä î „—GAaC…Ê:Z9~6ÆŸ7D£MAÅE@áŒNvO4F/¸I´•Xúõ*BÓ´½^‰àQ`R×Þ]"äIƒ­ÄãtùõÔBçÔªV!å‡ÄØ¡ðˆ$xET7ÒáxÏ^4³qgLúG’€€´ƒi·’¨€Ð—¯ùïÜ0ëÙœ2L¤á6ýñÁÃ<…þŸýÛ^­*I–«RT×L&{s ‡Ææ9 [HhÿJ¬É‹¹˜†Çþ-¯$ýÞLYtÓíËÁ”Ä2OU›¨Eä«Ç´§]kû@bà8ÎF"#/õDÙLtÓø¶!2PzÖiAà®þiÁygGUaûÞg|‡åÕ3YÍœ«1>j èÉ%-~¹ƒwŠ ýÛó– |H™M¸#—Z÷º€Z÷ñÐøQ7'q=ÎpÁÐSBl{CÌ–Yñ!ñ-²ßµØþ™Éˆþª¢”M†Ã7ñæª-Ÿ›ô|"ô¸a vŸÙ‘ª/{.Û|D¾Ù+ÙZÕâN )Œ·‡·Ÿæ pdKq 5~Œ¦c°ðýàÛUh÷T`˜»Jî(’ÖT[æåË‹Xë©ñÔÊBÊrgýÛ8‰ò^sZÉ^A¾£‘šˆŠ0g—283ö F‡ÙÇkè~/®Êrxîñ#ör®p@¦+¡=l»Ü- ŸpÖ»JH`ûaX©±ÎÕÜX*f?ádòà>Û·T"ÂÁC5~qž¤ ¡±q±Ÿ«‰ýý7‚ÑÀlóÕÏpv;6ó Í62ÕjøÏlT‡¹DDðsNBe~wðTU+ÿRˆdÐV|IîDx¥™=$¸ ß¶¡“D–b¡ä±ës#‡[¯üéwfðɦ I@5UîÁ½"¾ç7–z=©Úè[äj1îêÖ]àGèů*'ÔoÊQ~Úuò²wÔœA(o¶^Λwé“@J§Ãp¢lQ”ƒ=ë ou‚w« zæÖr3kuû D¿Èëª^t”ö.ÕÙÊ«Ïð1iBK‡–ˆ*DìKŸ&3lJ0Ä :ÃäZ¯Ûi òz’EÌ:˜‹Ð\VŒZ/åC¦¶žjQ¨LIåkÏv»XÃ,'U¼]’¨xnsOÉÕ=}¸ƒâ駸Ô÷"{íöNRòV\vIãP,¬MÆ5äγ¢.Xˆ‚Ü­¹ÉÉšÚýº²'Äa¿‹ß;ò¼½Å¿qÍz0±ç9-5ô9×o P$_“ŽW¤:›a®Q÷’äq[óÆÅ–!fÎ[ÚvÇÄwÉIHýƒÃ¡¾5 ‚ŠzÅÝŠ¡z–µÉy t¨U¦+k¤Ùý‚㙸ÃùœAq†Åë|'ëC’€€»Žy´ÿ‘6&Nu>M/J¨%·×Qg)ó#‡iCm@ U‰wnŰ—aÝk¤ž–Ä6Î9Ó„±ŠhËMý]ÒGˆ:,wådž(wW;Ž)$—Ѿk ©›1Qúê³ÍêjŽëí:{QµuoÑØû×›1 „¾nY=2I“+§ç9÷ýêj=!š‚ó óaHw´[Jnkiœ9Û_KêÔU@Q0;Øq¡½ÕùjïÊrõÂnpò*Ñ@-ZH7ë“c¹“´hY¡’{±ìšŠÛ%57㵋;…zZMû…¦1B…²Èöþâ]§.3ˆSpßqfpE½Ÿ] i4p×è*MÆT3=Ïß)ïÍ=£À×Z–@V>ªÅUD²Ib`8Žï ¯œ³%pûs½ƒÓÜ]ÜÃÀäAuJRr´»6ò[¹‚Þ>\(Pz•¾¹+aG ñ=Cc=E¢EÙøù½ó€ìôÖèUGi>7:¿Ë×*»ˆוJ{u%\ðkÍ€xZp"k†;Sòƒ.æ{çY ÒÆ }–é5ðöËP"ãzu&”^Ói7:é˜gÈÒ -O_xF~¿ÿJKe?À_…®¬?¨1Û¿j|yô>³JÚßМ͙{Q lבþ… t×Jndz|1œ…ù*u¨R9g€»„gÀ¤ZXŒÜŠð ä³b`®¬6.ˆß~”^áàã?*š¼~3=©ü±Æl–ýÂ]D°X+íb í ³Xãl“tå½ò”0‚¹.s¸Ý•vqBÌ,³4Žâ„N\}0ˈ—¾´¨™k€~w5F† ´.Î]ÖR¦I`-ÀÆ7O'«¶mEºf7yM<ŠÓQ«^fenº»aWW^½)²ÝDÊ„óu!¨’Âõp¨7&2uC|„åöúë´Ö ŸªVó3༌À"óÄûÍÎAêyy£JuV<qœžÓŠ{¥VD›\ù*L²Û鬇3¶ ã¨{‹Ñ<ÇÄú«ÿ z1ù“7LæYKïÔó•¯@õ@µõ¥ µHå*Q&–Þï› ýÃïø¸C=Ã'P9-:Âðº…Û/0ztúm(aJþ>'ìŒhaãkÄõ¡z‰!´ç?~rüvˆ‘ô:[Ó‡õt*ú)üT>Q­ïšäÅ‹ïƒÍ’€€±ÜsÏìa-CMÃ^4ÌYÒ ªï6kÁØj§²àâ)ôǘàhˆR†2C¿h™O‚6ÍèÇÈp3ãÚ Š¬ †Šö®­úÎiuèæ*ÎðKYIâ¶TJÌC6Œ¿Òž“¬÷ð¡çê ”gÜ`Õz(à±È¼±ŸŸc‹¶ÂC±‘\¥ÌOÍ×å™­Œ­·÷òðY¾Xi|ßú!û¾„/|É Ô–lž-šT©hàmâï¶Ks]prÑ'°Þ\%f]–b±q^4 yPäÓ= ÀVõ$|ulÄÏé¾M»*d–ëzëž”{Wö­ôÀD^ªÕ ¥7ílûˆC=?v’†§ª Š›)8Ñ@¤h´¬AèaîR1¿:¡ø êo$þ"dÿa ¡ør¼è¨"§HûäÀ0J x‘µ­w¡N'çª"gªaûÂÆÙà÷d9XPO‚ŠÀ¨ZU£ `Q|kCï® ˜Ý34zÊ«‘mym‹_è_¼ ª*{]ëq‹áh+è'B/¯,âÁlu@Ø‹fSqU{†s¤NG<úÕ„œêåïÉ@=‰¾;¥fÅ‘wû'ºÆt6çÖÈŸ~Z˜/ ¾5Ë-JuÁ*1|f9ä{¦)«´øÓ%rZl¡8v`ò™ÀÍKH§Ž« ô°ˆšÉëkfiqXAòÈCÜö@HtüJÐdÓ]-§Æ«E(S›èLÌ*¿ŽO¸Q=­öHöx3nOA‹¡MåÎOy¥YZTàU›nSAª_g„Ý^­J­‘±<›­ïºÉž*“†^&ZïÚ+!r/G C 1üHا«ˆ– j©ò_0#ÞŠ!’¸dý$‰ ôP‘f4 Ôã&þXÛÜGöl@ÝE{ Ê〬1I+ÚÞÙELÙ¹[E•µ "Uà¬î:ö¥¿–÷ö]ûàÙjõ†Ú¸àÌ‘Œ Â%g/¢Wªh6×bu¾ ›Üø2Z— ¨t=X¾+æÏ8»µ¢—ž©Ø×#g’€€á›ÖL,Bœ«ÕáŒð1ßWM©S•ùíÚHŠ|ߋ긕‹éLÐXÒy¼‰ïÖÚ‰¶éÙy Ëò— EçýëR <îº}5¬Mõ¢´éÿ᡽Ž'˜áŽÙý)=±êŸBIS—\IةͱQ¬÷9í·LšôÌ^=@ïsðäqöXÉãÌ4Lp¢RBìÂS®àO ¥o JÇ<±ü™{Â-°Ú²J׋a“A¹0îaÖ8jYö¤ªÜ«¢4vNæL³,LbÁÿ1·Þ¢v#ÒU¬¹ð Ïàé­^ý㘻¹×‘ö¬ÐÏWŽÊÈý•¬KµoÖV²‚zÝ¡^u@ƒZÏvW@—Aâ¯Po¼“ͬn\hf»%tûôÍA}£À´²æ©E^“}Š>r¢ñð-¶îëpsó¼Êüf ç7DJ`dþ—lÓ¤Êë ¿ŸþDD `ö©˜˜Ôû—ý8@ÅEKƒ7ºuÙÝoå"l‹´I 5`X¨©¦$EÌ®ÿ2lã/å^k}×™ò£253œN«¼ð'Õ§ŽuíèÈMëyÎV×’›Ú9m¨~¹Âê¦ûVÐSâ—Ôþöuç9ðñ½Özü|ÉzÛ¼ç©[1Ô’€€Øªag€rŠt½Ò4w,Œõš…+§øi2®ê5[LT‚ü𶣤sQ’`/}‹ïUxìò‚‘ç%¤ïj¬+Ñü>3®mÙ CÎ8sà¥Jç>äM“gºF)ÚÔ'ëd=‚§ÿe=wmˆÚóÚû,uL \ ½è@˜/|cf£øƒ¼è=WTJÎàû=“¯..îžÈµ•¨Ëá×VA„Ì›©üc³É¼‹ÒCº¯Ù٫昔žôãî¤h÷¬L¶sÃ+Øt8®‚ìÑe?)º½ë omm'5š ¦œÊyCijœYÚaj”ÒXos—%-— ¿EжM!45=S8ùEK”œõ>é5´€aW£ÐÖÅ4éÌëf~GÒ{ýäãS¯¼µ©ñ­”¸µu~cüwÕ4Œ™¢žäÞ“âÎêÿˆD¯št¦ý¾ˆp¶6 ’« ÔñÕCEKÅVÏñbôVmqúÕÊ™y@¤¿°GWŠeÈ{W¹é»7¾‘© pjÜ©…PŽã˜›¦Å°:ê‡²ì —(ËÆ¹G¨„oO¡„öüÀüϳ1OP>ž®/÷¼æêÑ65Ù—â̆«!W’¶Žy í—|ÉØÖ’i‹Êé‰z'eòçç¦ô¾=YŸÜÏ òƒôšg ,›'#Ôa&5yÿ><1„U×å¨K„©]<­oå/wн!àD¡^ØÚ\ 7>õR‰°èù¥ ?6ØS‰§Æ7g茬Bñ(°%ôHQn¸h *k[‰GäÅ´sn‚ƽï踤®¦ªP1¬»ÍT”YÒÚ,v¯<›z9;ýÛ  âmÙN{ÂÃõ”ä Øºôîu¢»~ ƒ= ÂÔ?wôÞÖ¯S˜6¨úï|ao‘Á“¢E?Y€® újÓ8ÀröÈäÌüÁ$ðªÍ·Q„atÚ =™²ç/ƒ¸µæÕ¸‡ðLß9o'Ï”5ŽÛûhŠ–%(®‹ñãܘu­²_¤²©C؉òÐ]cëéÊjòiÄ«)¦½§öüztQœÌX+™Å:ÁmË‹’B–ça.aWðd@0lÌâ·ã.6Ýdr…g>÷³'£’䙪=µ~®ÆQ½GÍ~ð“¢ÍΟb6»ÇIÀòÔpxüŽçÀÿ½é­¡&HKøúÀ_sû}m$ð¾’€€¯n} àH½Ñ¯(;?Së×i. CH#Ô'’ÕeÏ^–®&"š{eRE5äX¹â»É~‘oiúuµƒ,NÏ Ê{(‘÷XaL놓õEë³™jJn8²öG?äÕÈ9Žv3ŽÍ• ”ÐÑŸµÄeˤY௠jkÚ0J€mMOiœè-9VYg1xŠ \,Žmªq2¶»#?ÁïîÕvhÝ·Ã à4ëœWú¾Çýëžd.ûÚB@…,ìq4 ÝË>µå-}BÍlè9¡kGU—OÊr txk²)Ò!mÆÖœ/鬜#&3@£u Qãé°™àG±iF‘ðl-¯á C[³±ClÏ4•‚OE£Qõ‚7ž‡» d^‹ºUˆ¥“à[Uåd£*I!Wߨ"ú \Lš¹ê«‡lî&3i£LЉ@0üC~tà”™’öX© R¯ªüž `7fØîy!l0¼Š.¹ôÀ½·h8¿]'Qúl( ËÕ}0ð±AÔKÁEE~ŸËžr™6ð¹BO§”s>† DP¨J¾zF[â›Jç¿Ãà,”‹ÚH”µ0ÜbŽ6Œ xõ½©÷Ðܧ¸^d^ŽP`—_§-œëìBÞ¦`x ­=b lƒ0Iæ·üï¦y€À:­1uþ{¿£¹ãòlVäW†#2¢MªUé‹`©Ü€ŽðlÄ¥¡_Ò?ðÉkå‹ÀGÈVfΤî‚!°²ï©u^¼Qz*+@ÚMÒ螤?êã‘  ×ÞB T x·WÍÀt²’‡Ø‹WÈ“ˆaHe8T’Ns?çgqc§P.Õ—Þwö€ Zù`ÅKú5€ñåo_ozcL0î1ÉÏ¡fßÅx âŸŠ—¾ K<›Jq òs»Tk-q_ &î®Ñi%"þhi69 åïæDœ–D€zl/“+ó±„je ®.Ðw” b›òêJ¶d`qŒ3]ž ÍtdHû¬XÒm>ªÕôKT»e[})îWùΆoRCsšç9Àº"r²'HUóÆ ,ŸD)­ÖœDÙ„e¶}û5úñ¦iTœF¯ÌŸ&‘—ŽŒšÎì@˜cTcF@;™\G8•¡ÆnM4/Ú®®£¦öó‚ÂäX²Âç§wù^èÏà©n@÷\1pOé˜áÝë÷Ÿk¯ó³”@&|ì^T´%÷áÁ¼ÈvHáFN¡µÇpø¯‹=A@!Ù\ljÉÏÚYßcRKw4 ›õ6M” %õ@âºt—væ{î{1¬]cz3ùǧsIñãIÐYM¿ 7NeÇ­ö³n|7‹AÚï\¡+±Jÿv.;nP899;R†mdIxkGzoÖµmIÓn58ö¼G–0êìñdѽ4ä,bÈèÆšvT€°jŽˆÍÜ^eÏ®ÅÏ Å‘ÿoÜh¼ÌRpSlîêÓ—X÷äU=C60o|b(:3û5žL)…\î;b§7!fªèÔôôEŒâ\ wv4,XÓd .<ÈÜaóâİ|^ 0Ô¹±ÓÔ,rjÂåéQàÒ[W¼^­ÆÜôI[ûdë°…ÞèÆèνcs°BæK† lÜ¡^¸{4¼\…fãíÁ˜‹»ŽË26¨|2˜µ×ñUÓ\â'ú‰ØÂ™R/QH¿•^ä&ìÖžTô;û®†C?|Ý)ã¬å]¥V±¶µ„.»¯zQÆlçS»[q[3{Ãæp^Š2ܪ‰ôºòz^…¢.CUšÖIÆ\2 f¼©ÐK˜ß-+oͽÉñ’ïÌ0E žÕÆô!táÒ©›÷ ƒOƒ”EóúEïƒsƒÙA‚*t Ö =>B;¯­¸Ô¬iôg£ìÏ[Ó¹$êÉ”D8CýÀ”Tp,ÇD)fÕ%†í™"LjÓôMßňA4†’€€Ä õ¼±á¢ÓŠˆ+,Õ)ò\îa|, Ï Q?¬ Õ:¹|DG—˜®}ÌYö‘Öxs]¾=åÓáÑ ¨+A€%ìàã© ¦»»èC™>‘Œ’¤×‰J¬q.ÚýØ¢p%…žÇjAª¤ ©c ¨rëçÁªa¹ðãmiÁ7€z6«JÿMb·n|aïÒFxdŽBóQ³ +øÊ,fìoµ¼!ÔMÙ ZVã´qk_K´FކP íþ¦âÛ€¯ž)qw2‹ô8>R@mµ“$Â.#¤‡]<9{OB«IÈv0#r!½k—¿È+ƒé.éÉ|ÿ»õ9gÞÁÐz!Š.Ô)1À­BCU›÷VØ{ÌÃmÜ WT’!kß îhô, \ ŠÙ!ºÎ:°I¡’fÖ~Mx¨fFœÜCs6æ‰|0²y ‚{Ä…ÍeNX–/G®:ìòï.%fK÷¨Ëm¢Ç뮑)ººÍpRI¦öBk¨¦;Z¨ÞŸ£ûú23Š[Ú,ÙÔ±ä× ¬h5;à½["í)®­ù´¦`çQ2àSÌÊ–0¥Ï§s,²p®¿wnû”2œäHûf%7ÆêQ‘›¿ÝLò¬LµfѶ-ãÇwº½ûÄ×5ªìߘê+Y‚KÛ±CÆ,2RÊ*È™ý…Â<ƒ’”8¨’vã·³²¢À7 ”ÆÐÇ0ïdÌAåà H’¢¢E–×*°ºQ™6#\vŸý^Ja¾YâÎõµð£ïùÓþ‘Ðòp%ó ¸ ’€€ÍR#ÏŒE+X§šœš«ÏJðð\^ËäŸM;öƒè SÊY(cmÌZšùz´ÊgÒ¯þ ˆQ£ù&ÏV zщ3âŒQYhlÃsžZçBžhbäl¦IŸy—”Ìè¸Õið{Á‚ ôœ?±Ô”° ¼35`)'Ä GîbDB8…Àq¦2Á§úìL£s…¤´v‚ÿótŠÆò¿Îد°=òC«<ÒæE#Èjks¢I…@w€ÄÑ«—ÈÐ ü¿«¨XêÅoBƒïôÒõf\£ž-5K‘ËÒR'ïÇÉÀD³¸à>±`¤®T -Q ^» ª÷gÿ4-¬‚ÒE³éÆÜP=¹é7ì‰A~Ü Ìqbãî\žmtE )Áþ…  7.9œ¼¶̇ÕQ¹vQt¯‚´Ø–Á¡ùç¿·oÖ|YÆÕ۪쨢á7”^>4Yd ½7S¶¾ö{@ZäŽ!å¼ÍjWj%eYìÌž‰™ö²Ã=ZðP ÃÍ¡=l®ÅÌUô„”t9ŠÍ‡¡Ú#c}?[îä~$E¤Tž¶ö° Ô\…ž®Ãé#côÍ*#}mòO¢ £‰Õñ‰xh‰À ×&þ‰™_»•*æk9ë c—¾Rû›Yóß—gWVáúiÆ¢ª> ܧ*wQ¤mùx# e`TGâÓž*S:` kàŽåcD_¤M4øãº!2»:’€€²>ik©ŠÌsOùb€x˜äyˆX©ÍÝ`›-7“Ð76àTÛWp똚­ƒX‡)Qê¯úéÒõáŸLµIsÀª2ºAÔN«þ0(¦qþY²oqº¹*M  VFlê³'òûW¡`ÇTkf]­ "^KЂ/¬0 ý9(u¨ßUz¿ˆ“›ÛHN2ƒW*›mÉ݈_ÎßèQµ§{»E;ä3xŸõifuÀFˆtÅkóèRH^kåwq]Úíé\Qéâ¤mJ÷ð#QoBóàÿ÷âÞDÅ-Ök5 6 Ü·¬]ì‚j„€¹uVÖä»}MtRÇÇ›ñq™&Ö¥Å5îý™™ Ž¯äKw‚!$yÉ •œÝ¿ð€á.a1€=Y¿ãÐVе^Œ™²Y§1;íhä -R–® ÕN†Ï8$yu ÆòChЦZT¤¿–Î<6GÑ[DâÙD³„f2“ M%´(wûƒT¦%”¥Ä-Bаêâ­X±V¦\;OÇþLJž^Æ MD˪~¹¸‘ú·²£,/]~„òÝZu?%(Ÿ;×÷Wbäéa»RÕ0汌Y1<¼* w€«}•à»™ÀÕ3™kK{cÖ½Àãðø=¶.ÝÓû12Rj²ç葵ÎûÐö}7qÿ§«!D1~Çâ 0‚hŸ9øÙ1ßž9×2ù ¦YT¯£y§·Å^a“Í”NÄy+{_C~^¤‹›Mç¹ ˜:ÚÉ?ª¼Ž&Ä’€€½ ûÏî*C4Ý™ µt¡•;*ìް⤭€™‘ÿ˜¢Ê¨~bÞªo‘Óñöã"%pyäÝ_Qqw­O‚êˆãsªÃJLX*à§>»[b§9ÎÃCîwŠgŽ>âk–}õ/ÑÑ4GîQÇw0WÃFQE˜1Íìç\KaäÁMõj>,ñ(Þý˜'ÕJHt;ö†äò«T̺䃯n‘X\Xö×[Q@ù€Ä¼õv…vÉ£š/}ÅW­ ß"¶Ïôm¿Ï}äTÊêõ”òÃåÚ’âhrih91Þ"öç>ã?Ó)Íÿ[6Y,篃"’hû ¹ÈÔg½Éô&Žêž'îxjÞ¡GXДCª]îKýú5!*óårM.A@Ìcä–{ÿ:ŒÅ|H‚÷!ù5¼­ ðâ‘{–ÐÀ¡è e‹Ã0‚è&Ù`ÍåÃ!üÓ%·Þ¢JÎ,ÿ2Ä¢žÒæ:^–9tÂÈDïMþñ%ö2Ô÷)ÇÕ´è o€˜É|ÂëFݳxÚÛÀSKý÷±fÏ“Àz\5rr™ÀÁ¿¶F®šUûxÂ×o‚ cr··ÿÝÜywžbO®çÓ¶ÒÒE‰#@ТÛ¨<Å¡c.‹wÆ–¦f-AU˵RBÃÝz¢*{D± F+ùö?XÌ:á©™ò7§äüÜšÿ{ͦ:ùŸÀdx}/ÀÉ'g«Üý|5EŽØzYß?ܶèaÅêßJ±`ka³ô¡PkÛxŠC–‹c W ˜ò `=K7£Hó“{€`Œ)ÈWÌ7ʘÆ4& mç">H“Öˆö%ïQж-wïLúÝ3ùÄ|KžnÏý¾ë©—(]eBÈm4Ó'‹:ÕÇf,¬¸>€îù°î:ì<³ØYÔÖø5ŸB^¢±ïPI‰Ï ë>IÎQUAXãÉ\Y“°ªóf¡o¤öƒ8+6uu± fЯ}¼Èsúfäºp86/ÄÅ€@~Þ´2ó÷ÚÌ<Å5aOPv¸àà‹Eh>%B{—¨æü(ÃBÙwÅ0­†2"œúÓ†·*/ °g|X°¡Þý ÙÆ‡Ý™À¸_gÅNÏD@6²&¡ã`Ù`Q¬‘:Íé[霌ghƒlfc ȶ®ê˜~ë5RArçÞËYgûS‡€FŒ²·nBt„'8Ø‚ˆWkÊXaxòW>ʬvSÑŠ"3 m?P¶XÒ*=óÞd‹òY4a9 Fu¨’å~øér»Óè“Ç™Z猯ü(PEÐH‰ d·Û­q€QÌUò$ºØÈY@îfö`ƒ€üyôÄýæú^[¹,ùÕºÕæŽdP„áä4úï›ËYˆ¡Jø…@sÿ"rÙsœßžôÈÄ‘Vl +ÒÐyÌm*º¢rû8’ zeYð¥0ãÕH€|ì¢8,€’Qï€Å: Š|asÎ=¬#Ò+D:]FºÇG‰H£ý­š¨•%Ïæî àùžmE™ìbÝr‘{;ã®èKÃüP%Ƶ'õ½Œw"KÁ†¹­FR‹0Hò&€TÑß4’MV¿ÉÝB…‚ÁK†#ÁæŸÞ@ À…ÑË^逯H5(ˆ&Ë0/î…Àcf_^„°§Ø6P¢‡c3$ß%l¹5N¦—r}S)ú ʆA‰ûåü j³'ôZ*AåcÚâmPþ:‰ÚÞ[ìÝê7\๧š—ÊÀ-ÒæäÉ$5$UÍmœÕá ‘¾5¥ ˆ@·ú³Q|œÙVg¨/­—1ºÖD¨#‘†Æ/pYà#ÐËAÞÿÃÙ6ÃÿMY Ê µL‚ž*ñ¹KlïÑ?½Y=÷*ß:ÚfRU°jd?•NX)–¸_—£NÅòh?w–Æi \©ú&“KŒ?=ÝîKF îgÈRC»v «è(q—ñ'¢ä–L[AÆ“¢·¢} /ÓJ‰´ŒýV„í-0hŠ:þ‹ ›µÌA!èÖ5úPMŠà’€€ßŠZOO(I•½0žÓϨºaþ«(„£8v§XwŒÍVïF«„éî Lº³l÷¼U ‘AN4ÀzRšQäYÕqüã x>WŽENô¢Eù8ìÿ1!æ¿A¤‘èk¢HO=G­"9T›à)M¹v(<ÇÉÔÑþ2ç>›}ë>×AoÛºæqU±¨ÍvÞS÷Þzèq™›Ÿ;mê‘qˆ+¤œ\Gʉ¾eΡ¼õpOEžïk=û:ëáñêžµ.Tówš»ýx*aV¿P“ûä;Å`&ÜFí«ò󙤭­ [h?"ÔG€QUFêˆ ìlZR >E&Pºæ.ÔúFRÿÇ5v±—²ìúó¢„p¹ö¹O‰nŠ•¤ ^ï‚ÁŸÌµž\[úô`ÙB…D¨T*yå„ag~€@ß1jYý^ÑÜ©[oºš± ÛR$âN1ÕSÐÊ=Š©‡eÜ‹÷Êy§&ŸÈsbðºø9Ešp¼ÚÌ$©€EP3gc\·•ÓÝM!vòUçØ"ªÚDŸ9¢—§…OÞ†ê^ÔC¸YsôX„øšþWn5Ú 34”ŒúgÎj÷Ho’Öcgë?n¡`ô|ÞWb PÀJš‘³× ˜”ØÉ2ûWðÓ¶âJIX¢„ èá´‘Š¿Ñ­Ð ’TŠóu@œJûûÑyÁÂt—Úäî‰!*‰öܱNÞ*• á5rx’̤¡Ö‚߇SƒÙšÚEÊû©sK:(…®ÀõcëWÊ 9àé‘r¤þ—„÷X>»c¬²ŠÁ¯ª¸WTŽìŸëƒƒzéH•ÉÄÇñºbŽÏ—'ëó¹˜Â/ÒC)vWë¦;ÂKÖ)âˆg“=?Q³^ï¯Là등bq£f8$8Ì)ßP.ú®t"ˆÔÚ¿h€k£þÕ0„ëhç[ôÆed0“,)ÙAo"yÁÓ®„ÂWFæE¼7ðp½DÅ{fLÿ­Ç׺{:Éò¸ƒxÞ‰·‡bg1T!qÝò¼’¹WAo lÆíÔfƒyºÈqIB¾ªÕD¾‘¿CKk §–=CéÛÜ à¿kö¤zRÃ×cÅ}Ž( \‹öÎHOº(˜Ã~`˜+÷¾ô5J›Í¨×³·vɹ Ãö¦ø#üו¡`ƒ\î˜É›ÇD3^h°X’€€ÂaìeírÿcèhNH€c¾™Î#å#Ìk§)û%4m§èp0cƦ¡4˜µ_š1´ï1á*ӻпâÚírÍo6¼`KÒóÓC‘®²×‰'–c‹:Ú¢vYÎËȳ|î\(xk/÷Láí/ s}Á"r4èǹ{‰hë=%žÂ‘x¯kº¡ ñL å0ÝÆ‹í]ÈÞŒ±Fí|!Õ¼¾ó¦Ÿú9^¸ fL¿$d'b‰i²z[,yíä4›žÝB=´¸ ÔG!]*rG(Û†`p%"«€Îtcr.YšÕ¿c^NÃÓ€ïzމ (û|°Wœú$qœ  Z‚H“©ÑÙÆî;±ê:Êç–ãì¡S Ga©5ã"çpã}¬&ïn>c;{—útbÖ­[ !Ùͬ"õP coê:›Ù´ÅßZ¾ªÀÑÖ@ó¯¼6ÑfT{Ë5C}Ë‚]ƒ»íOÜ3;è8!Þ‡,„#¹Ð_ Ä/²-ø) èz#\j©|H:Š’.ˆšïÛh¤|Lyþ±“™H¦#ê$ûö; ƒEb»€÷0Hv¢Óf,Æd€7PÕþ~;Ö;cÊÚŸ!ËY§üíÝŠgù”Ø„LŠoWPxK­Ö&ÿ8 &±ßƒßÉ·*•Ûn~wì^Ò.ĵö2Ä/Ð;­¶ü:°\ ЍµxóÛߌ¸µ -Z-GE¦·ª8kÔx.KYKaTXË&@¥í^ò­45m´ÝðbŽõröác[Ö<V+M³NT¹è73S§-I5M~׿qVî%ql£ˆ"ÃÕEßø;ø—¯!§ä‘#Ê5bvý¿µRÇWò…°ŒaIÝ´$e,E¨WýfeSâû¨ëÄkÅFnô*ö-¾uCx•òäçWs{½ÇxÎXè\¥v3nWVsŒê˨–x¡ôlW2T½Þß “0I>ù ôr¶B0ð•M´±N€“xyóÐ<hÏMXè‰a™ØyQ{¬5üj%†qÚÎü¶Ì”P²Q7´˜’Óš_ZN´çû=}'‘q6•á°•Ô$ý£ &õùáîY>4‚Q‚l1µjŒñ%Õ¥BHâsôN¾´7[ rÐF´v/JÕŒ[~ɉ\g45çÕ½ÌLÐKƒ¾v3q’€€´^B½lt…«ÈgvÙ 8 ‚“L9˘¼˜k¹[c ¾ˆëkÞ¹cz¤+ô ò¢&ë5m­QV•ZÔïÉÁìë—6 §Ø&à Ùcw‘BLc`¾^ÛJð•m†C7ÂÅŠFÓFÌ÷¢œu `«<“¥xö’v¥1dÙÔ0æ™ ÇS¶Êª©¯±& Né»´ÅåÄ¢m׿ Û<ÂX„ªë9!È>?"þh¶ÝoúøÆ3¬{,2nÞž †ŒCýiïKµËÒ¼Þl‡AyÍk4ô<ƒ¢§ïa#о'.Œ¦ÛëßC‘Ë Û]åvذAÍ=ÿƒ2dKL°™'ycÀÁn¨çkÜdÃy]Àþ;ÁAšvw=j‰¨€t—Ìx[ÒÕ?k—ˆ:’†þ3ƒñ’lr5¬ùç°¹CÉ=v0»·øÖ­å†¾“ÂC5înCQEåý+ 7<£ýrßb›3wµ 6H^§«tÇÖŒÀæ^™I¤¦Ê¶Çóœêsêàƒ À¼¾EuñÜg.¡ fÞ¨O¸¡°²…x~ ñH;¯´@qÁƒ¸þ‡šÕ‹@6²ê SµZª¢“ô%,ÉÛ¤‰rBØ é/GgÈßpÕŽÖ”0 'ª2çõnIóà åHõØ3¡åy“ù¼DM£¨˜*d‰ª/B™2ÅLRÿ£K¡…T× ¯ÇQù÷ÏDoÛ'X’ó!˜Ö8ÕfÕ‡þVQÍTSÈW³+®à(²:CWÕ¶ç÷rüˆ¬4¬V‡Nj¾Û¦b¡òÎû¤À…ˆIÚýÞêا³H.áÉ7dhã4ôaíU³Ôù0ÐÍxã ±çi:ž›¬Áèk 1Ußáɤ"›ÒÕTSº IÉK§^Ÿìo¿ÓŠÔ2gýr#x¾'ßV€pƒª»—iڠߨßÕ3ø‚Æ §ƒ·Åç1öL41— z¬\hä„å6ŒÐ¹e œAïfgÔ§’ªï(2#)&Í–dÌ•Ð!òQÔ4ÞOoŸùSÕC`)ñkÃCi1;¢eØ,ÕªÏu@ ãÿ„ãÛp»ê–˜a f€ÆW—{–V ó©Lûz†ñiCm:Kž_–äf ¹ñ{Y^FƒÓsN¾„ _z2@’€€°Öº^I00øm­»ÏÃMGÂZËhƒi³»Ñ‚`?Qõ#Èaå@]Ò×—¨sqñ »û׋ËcïÂÝô’–*£¢ÛéúOÇ„C€©¥Õk“^®åé än`àIÙFÇ3õ˜Ýñ‰ˆa‘ ×-w‰uJ YÚ?87«áŽ.ͳs­ÑïË3M€Zо0úÜ¿áñ„©JªŠûìõ[æ_[kæDîi¸OµùÁã;t7Ý‹îKy¼XD‰ übÈŒi@©$oýx†)Šå[³fy|®Fy»‘z/Ž}™QPà‰ÊÛc6äð™;ÒˆÕ?‡ úòéEåLcl¸·I!±L¬óòæq´è×Åáˆñ.«á¢j3ý©ð²› ºó#7OAŸˆ–à”œãÙN(^Λ³´»\4žj#Óqçõ+Ýô}Y+Šç¯¾001¢É)ÔÜ0.%$nSÏÞoÉ€V,ÐÜJ8z©ˆhál  2'ò´ ÙX3ÿ€É’J‰ÌîÜD›ÌÏ1;Öðñº5fŒšE‰äPñÜÃ7rŠº±4#jN?h†zq?.ßâô(~‘:ùÄ‘*Më‹bc±r4Ýs*¶MÍ(^±xœ+—iŒ ¬yÍS¥kÿ8Ë}æ8Š!4Šž³‚?è/TëÜÚžtÀÁÕ• Y [›ž¥šÊÜ=gý‹.9¨C6I†À£Î[Ý5€Ìà„ÍG·ŸYÖ!ˋܣ Á2ç­´0ÿ~ʽe”yÖ5_“…0èˆn7çâ7²VI ‰øý¾öx34:T²r¸b› ¬?‰[qÊÂé÷Ò6z;% PôÄÊRŒ;€ùÔ†Pà_¨”­)ð)t˜Á–ªì0}•Ž6×»J3½Ô´ø¿ø·K·œî˹Ýí]̽®!2…4$ ‘÷¸{†eó¡ô´¯kW½1‚t¿³ËÏl é:ÓÌfd8K–~u|_ÜjD"EíOþÙÔ¼óô'ƒ…˜Žýüñwšë;ˆÀŒ_ í½•ƒ¡Êº@£ߤkëË/°ž Oâ…`=bÑ•!µ<0m!ôäùÀòùT™°û%‚’« þƒ\8BŒ;9nSÌÿ²(“à ±S¥yðšv ‰8¤åóVÝ Ï>jmÍÓ ÑèoÕ†H5¶þ|›”›ßP"úü’€€Íw5¥æñW¤j‘r/6ýé>›ù ¦2 ç£éï5 •)óÕ·»u°€k'ÿ~UIõ{­Ikþóx·:üC•‘Á–Ž`éW©»]…_çéV«±a©¾ÝñdATà O¦ZtYfdòÂÁŽ{!µðo8W˜^h»®µ4ऺÿ™ùjRZ¡KØhOåGHd™ú<óÄê«¿Ž¡Æ ”EÝ&Zÿþûã$ôÑxG‡"Á-+£³j5¢']»÷t.Û2:\ίÄé!ß®q;åeÏ?&²@j¢=<L&-µ¬&¬Éô¿–IÍøãæûìó%»³ZLz(íK(À^¯Ý©2¾"_×ZÿÛ®fŒËOÄ/¬Ùs¾óÕ½Û}iÁrîFsòSQê`õn@ y²ã¹ÓÀ9$|ñ©F`'‘JczXócNvhöM©¯ž;úMÑ—3ÕS!²Nó³_ˆæžQwJŸë ·ã®øB“íz^˜—Þ눘0‹HrD<[usdDâ‚Wµ dµqíRÙxM8°¬™j¦ˆëJLjÑFõ—Ñ£ `4ñ›‚/U3ZÂö1ýi/…t£Õ=6b0m¹¸®Aè·…Tê7æ²à…çÓò.£!8Ôh‡¶Ð‚µì6ÀP’é]spE¸?[ޏ5zܤ©²`°îðl¢ôV੎¶«ÉãuzU¤œNvpPF\Ù³,JZÀ EÕ÷ñ¢­V©ÏvúCp†µf¶¶À³Õ$L´hC#F—WÎfý’B¶6PfíZ[iÞ¶)ö£ï°E‰ûº ß5‹¡xÝÓ"õWv÷Æ^‡ÕÜv"&’ߣ9öŒ·\etO¥•¸H´–¢…:uեлáÀwøX&Þ¸T80KúÞì§ñ\ï…KµËåêñ”œ€ =Ç×óÖ ÅDÏŸÑaå'¯ï ßB¼À nÓiùK= R¥R[&(àçWÙÍ‹|ŽôCš”Š²:CMüùÚŠ=- % eíoÀÊ›-Vpt±¡Hp—¯œÂ‹7‰ ÕˆÞ“^PáèÙ«^kŸ‹ 3ÇÞßèÄ ¾^Í—Ø-`bÿ†ÞpÏ«÷4nöë1ƒiЧÌÕˆÆoè0—l’€€õ:ˆ#.µï"‹ ÷[SŠýV3€{Ïãš'šSê©puN;î¨á$oUqÇ~_¯º,ßÍ¢G9µR}gN«Yáo“ú‘¦¯æªã±1«.N'EÈé°ï$¯ó6t2ôÅ½à žøGǹ 1äz¾TÝ]Ò«Ý×juñ¢¦;$ãÆ–¿£sÇOwå¿È€|Ç:'Qt÷'Å¢\…2mN½½þ;áÇ*‚½áž«gêKC´§N¦³Œ6^Pó™{´ŽŸ¢æ'WÕ±Ç0Œ2vpî!`®8Ø”Ž™%™”ÒX9û,rD=Ý“ø`?oŒRªŸÌþW:–ÔaÎ!`µ~Yåo= |”^ǧ\B®ãØÈpjßg¬7årâðÿE.”@3oüýÖûT‡ƒ$ç'óß½»ÈÒG?õçfؤ ²!0 `zñ99)à F„4ö©HI±~óí`&@ÀlŒ™Îî‰ íŒI„!æ»U„L—{€äT³B”OËÌ:è ø¼[@ÛDî£{,zð²g<Û²PdJcù/÷Eæ[‚&kjÇüæwlkhÍ{©gÐ1ðéQ%bº£Õ¶W(¡§ É]Ö=ËhŒék½à©‘ûOž%ÓÐ]Á W?sNv  qFf¨KÍR9Hùç›Ëþ“é½èÄ2Ó6­!õƒv’ÊzDŠßœnKf±’Å£ö.›ñ¤N…`wQµ_‰¤0Í*ˆ3z¢5¯ï'´Ø ù^E`S±0a¿À¯ajo-R2½”ÿ^ ™Õ0s‰¹ñ>óêú§-Ù‹rêØI¦ÅD<öòŽÊPUçæwöš «s½Ñ4K4ä¥gÇ\äk»ÙÙïó7˜h,æ9nX’gUÈÑ¢†Ï\1kªò‰*½#:úb†ÿ¡º¯&ÏR™Tb¯¶mJòí0gl‚Úgóú»O ‡m(™\Câ“G€Ž˜‰Ô›?¶«‡è ÛsÔ˜ ;Aþ¦uXsFTKÓ·'ŸX)ó÷ ¶EÕEfö ™sˆ”âkg¹Lßf`Ä!ƒzªÁãÍ–÷0ñ]°Ö^:˜83„á²£²rl×·g¾0|îøJŽÔ·CÛBCwаLù„¥Œsc×USu–Çü}ZÞÇ¢MtÝ’¤ÏÙJEëz®ääÖ’€€ÃD+Afìܾ"3Ç~ÜR‹>ÓS~ðëdÔÌj»lÅ“qzë×Ãx ¥Ý¦äw¸™{I£ªWÖ67Š×:ü¡`AÀ|Am›þ£9nBçç³^Ð]Ĥáýý´Mø'¬±…äT°±Œ;ØìËÏ]}þW¼ÖÛz_¢×ÒhÑDsñÂ* ¯F("N¥ Λ“·•µÌ„§d|9ÈðÉUGÇñK’Å´ýýe¼gj/õœ.h±²«ƒt$¢8;ã:ý6H­Ñ­i]Ç*~Ã%¼ë¡ £Îȑв Ãuk¾fÞ·Öe7$þËSš·–Ià!gœápQ í’¨;@ßv”ý¡× ÿ:½BîYTÆÛ IkºñD&ó¬f5‹rU‘’ö îìœí"7”±Ê· )¹ã™€»:Õ¸‰98Ž8‚—ùTõÛ¾ k‘sžð[R»„ÃÏƒÒÆÌæã\Ì73 rµ¡¦{câ-н³%}Ä—/Æ¥±fm‘%õÈÿÖÍÉ~M¡㇠T&èÊ€ÔÿôF/ðÃÚä%[^Š¢¬ñkƒÙón0MÄâ„—‡úC™ÊRp"eÝãý:ªq¤Ð£¥ú50­œ¨|Ÿøî¨!)³}ùÄÐQ†z¤¾ÿÚ#8Óu}.@2Ï éÓ{”¿¬þKHv2Cü—8“íB@숟x õG4ð h¸Ó8êõ íº­4UKPÃÌúñÿ è}·¤áØX$'$:´ÛÛ¡øïÀ!„#…Çhuª(fbÞiÖ('ýC~ì}kæV÷ oI i[êUD˜óÞþ#ÒHW°im+A*‚ÇtQ÷¶Uùûu§q@ö6A– íž KÇ× \hìò)ÂqZC¸í" :p|˜'êûÝ~1¥B#Ð&™Ïý©‘±åì˜ß¾YMìŸ3¯ «[oè å þIÍâïÆÇÒvÖ?˜²2¡nÂt´ ‹Ä%'¨p^‡Ü(änòâ*S}…îYÕ 9ôj5½‚á‰NïÍÅ)N3®y$7²u$R)Z"¸jù—kÔ¦6 ý'Â&È/’òáËñ(&ð8HÙÕñ=¹X£VÒfáý ¸k®î<°gd œŠ­:h£8·;óà÷Uá{Å r¥&€¿‹HáØDsˆt=~”+“,m©é.ì[2èIéÛ&m-·Ý>ˆÁ­ÿcÉ_ƒgìk$º7¢´eí»‹¾g©M(ç*VÔ»í°$MPz½¹‘ÖÆVÃ,vFM¬@IPò½ÝTÈÿÛ[L%Š/ÕuwÎã×ÄèÈ×sSšZ_*è†r˜fܵi“lµÑþÿ½÷|¿Ì-¸Åfùqÿ<¿L´3fHP§S ”‡÷Љ‹Ê0 $“õÅ4@¼“aVÓ)1>kòûzJD7ÔoO*o„ V·7¹rÜ þ»¡7jµoɨGC »TÅDæ…b jp™îïQ`çHnÜkq9ý0ýœ¡Y*¬"TÇØí”3OU~Ó ÐW{\cH„Ø4þ¿]eœ^&Ò­çÝ—u½ÜαœJÉÏ Lº»ï$аh¸¦‡)œÏÈL•‡¸lh™Ç%Ž'2Â^g=ïþ°F“Rd$‰ñ,‰X9¬ÕisÌÖ0ظQð§™´¡ÀV¦×XÄ^„$7zX&=Ç›n¯m\£4(øù¶”¼ØŠêŒXt¦Q‡À ÄnºLy¼”æÖ ¹bǺ”,POpþ‰CÑ:žVí¤ò …0³·a‘÷]¯®»ˆKçzãóÂÇß@–|+4RržÒŒ¼³‚ÀàE©–ggü;¸¯þ‚3žäà;Ù¦j$=ž°éé$ª·Å2Oÿc˜–$ÚSh}èV?_©_W4˜ÏÕCSX ý.“~iÛ­ñCÎŒî4ŠÛ²µè¨ ~TEeNú;R’J¸¦w3€TØZHé?·!G|ä3®lš¼ŸÑ]UÔ-զ͢7¿ÓBv~„pâ·ûï«R:å«›ý7ÓøCÌàoÜ pë h ™Ÿ[ï%e&8Ì2ÎìZï¢^6Ídi7‚é’J²ûccÁå¢ü0¬ Å×!—á^U€¤"ïMê¤Á¹÷M5~c–}/µP^«Ñð•l“å·Ò^P2X^[d[*#~D4d\¬aTRcتdß,Øxaöýènó-ªïóÏ_1gJ0Ü£Qaôm’óI7¼ë6@õ‘ŠÀÒfzåK’€€ÕP4Që0–(îv`C‚üZÙ^e›$á‰dY!®?™® :pŽZ[G©…vËÞ­ýÌgã7 {NÆDø4\ó‹¡ò°¤¢cQäWóTP®'—]çÿ”fnß„| ~U99^ çä 4ÝxÔº& Ÿ^·_q×Ñ0x~ü9«Z‰½…Ϻâ!’2'¿¨žøº ù=„ÚDrÏÏhZ]ؼlêL[þNI8šÔÎWc‘=º¼Â ¢ ·§rÖ–Ú9BìiÔÙtçì€(ú+Ö4¸¤S¢Â6îãjõÐ7Àœ5Æž&u‹ÚÜWë%ûWÆð¹ÎU î’{Ó!3T×ôÊÌ©¬øJ4ËÞœpfË+‡¨8½÷¶7 -Â@ð€ õHË8’ŸË-¯+dvT³Ãä /QHÒqÝ‚€&¡Œù¼ÚÕPšþº¤ßË(zcZª‚Ž!Íbž´8zæäØxqÇ/…ž“®ëÖ¢š{vªðœ`Ô…^Ìi?>C>Ç£}Ô‘|"Ñ5Và)îzÇ\œmzUÄÈü@4Š\¹Æá¬)2ç¾P™XÆû2t ÆŸ˜&¼tkŸäßÜï+⯒®ãã U•mÿµ’Éf}£”Ä’"ÅiÐ`Å]È (¨ÂZ~ÑÍ$i»v"m?Up­ÃNE’€€éä Æm~¸oÅ fhW·ô–H% }+,¿ªvÜ 5ðâHdÈ ßnèo=3ån·al)¤oa¨Á¥r4âIwdì[ÆÐÇÀð9죆—b'è­2 Ælù׃d!äªÑHÌ Ë¾dh—^ó›~Ez¹2ûFƒ½Æ­TÒåI·Ç½,aðì.!î‡ë±Öà¹|³×‘ÆY[“åJKZK=© ÿaè8>†Ú8ü0âÃEö¿º!¡ÕÌ%ѶˉۣÀPÇ ¿¡ð/{4ÄÀ&¶\“ã¼|¡Y¤1Y¸GSÆgYyòJ3¹~72Så@»@ àóT¬&˜ž·A;éÑ6Ïá N…“€Nÿë Ã›û·^ˆ}õ¨åœû¶q)ûk2~ÝZ[¤|ID}üòÄ»!Š3U„Á'õ²µSa7'–@§€=e-?é:*•…0Z€íE ÛS>,$”r„g±dÃaìøb5[Í‚ `CÊL#Å–Ü­X"¯Ç>š7~ìÌ ¢DZºZu‰PIþßžûÄöó:|1ÜöÍ%ç«vœÂ ’ßXãakfh’ýÚ¤º±wyùÏ¿Ž¶õyÌ+löæåÛI B†!XHƒ$¥“«úf©9æ`¸È]ªÒ_ãŸå¼qÿê|³ã/|B*_g!»‰ö4 é(èÓ3i=¡Ø‡)Žº˜º,ÍðÃ*U½^è(Ç–aäìòÓhãþ܃­eèf¿áÜ`º*(¯û‘*JÚaÇ•Í<½ug4<úÓq©F{åº{"ì¬ËÎk \EJ¨Á # öÔÊ¢6#¢üÃyð¡¿ò~rΞÞ}ÐÙ{0ió2—/Ò¨åóyû-ÉèSɬÞáÕ̰ɱgWWPö<¯‡Ã·¹‰×•%Xù”Ðý*³WµÒ%õ PMÐ@ÝqB+'LW,¤­G²ßÿ×€Š{EòÁ!ôþ‹gŸSÏ" ƒV1æ3uFŒó‚ÀÆÑ,¿[îå“Åe²Ë04ñ'ö7€=,ÖØ‚8ßÛLñžKõŠÜÅqÞF™U„­Ÿ W†Ü•¼Ïã ¬xSü¥+[ x9ºü¥°Ù–ø[Ù‡ŒÌ¨gzïf"å襃 *@ãG,I¬Ø5g¶Û•†ØC#½z³ŸGä§„üà$§„5·i'‰l>:Í®¬ÙQÕ’€€Á¤nÏö[”×(KFøæÝ«õ±7m³•{@7Ku±Kº`“v¢ìÙl¾(»Ò¬@ óâ4¤ò# >½ß²‘ ¾’’ÉB©:²Àñhnå놟 ˆ¨OA*—žr½_Rq‹#_KØÎ7ÌÄ($x'YPÊ®»ÔÆe—m1]òÎuxšòð2}Vi+^5"’OõvËùƒìRW?¥ñÐÚO\—:¾±*;Ìþ©w*‚š´¯ž»&˜.ΜÕQ‚ðþq·òg°EŒÛ¥¥o¼ d£ ­x£ÕÈí5kø2àtJn;;üüú9ɳÑpyø¤ˆ™ƒSšÙ!UPç têXd Ü=8"*W˜ðâBK#¼^óý2ubª_O¡õšrjÇ-6 1çÔ.1϶[’A è ÊjFó)¥åóœZ¬7Æú'BÙÌŒTôù°_mD²/S‘Š„v“ø±ŸøœÔï=wÛ×NíIjÐ5Ãl™€>ê­µnY,5̓ƒ”³ÄzÎÓHb¡~øÛ|v]yS¿"ydìÌ}lOPÙP0MG3‰ñÐ'¨ÙjUv”Q€¹1‡òíð9>¬ 1žãù$aÎwµSN}WDðt9ÃíØ×M6÷¦.:)žÙÇÎ 1ó·2Ð.òúÒetêk¶œJÙúÄ%°•êñmÂ`>ÿ¨8œn yéʧ8›w,yÖжér®³=2?¾ÛÊÑý–È3Õ¬º;œkú>ŸÄö‰#Ò™ ^¦QµŠW“åîNæQÜÞ w>§»FŽqØc™ÐÔxœñÚ4}d-üÑí[ƒd±ê] †º¥¾üÐgů›üʸ8;­5.c<"°-*GŠYܼ9ãg,§B—‹c?~]ú/åyd³D¯cP•“­†˜G,¾ä5שO„&´Qx[9âå=7È Q”KB?6üK|0¿¾]¥¬ö©À©»¾/c¦ ­%ÉÛç`nPÓ½iÿ¿¼BÀSÎÓ#2òúéý·™¬C”.髸§ò· ­”˜ø’¼ãú x½"+K]_Gä™Ï :ؘB+ÕÄ‚½¶7ž3‰Ÿѵ¼Ÿi ÕfLÈ@Šð¯·«kal°ò—X¼øUQy¢=]UÀfeBZ™¨ d‡ÛpˆÜ¨ecìàõ ß>’€€ÐC”,ªé1\‰i'¥âÆ¥Òˆtrl~Âáê|v Ú9Cšmˆ¸Ä«1¨‚]}6.þ…°‰ê"¿¿†ˆ”ŸMÒ¯ÄhFªw\ ƒýzÌæbr“ªÎssˆó*¶Ãú•S-ÞŽQýxLëÔähþŒ¸@Shú\Tt\ÚwJê]­ÿ‚Ç~eѵó²,ކEœ)Òú)Ù t¿D¾ ÉTÚRâáÆEj…7j‡«izÓÕ`åC8| 1~kåÏìY"©âš+ce%V7ܪUs™JÄxÚËhÀÔö’ÿ»KÕÒ©´ª5[ç÷f4'§Y …~- •äö€k [ýÚ5&+ñi¼ÓwèK·'~”_t‹Ýѯum Û¿}J1dJ‡Úf:?²Èâå™Â [×0L‡Ø9ÿ?²öÛpŠ9Tú8iXã6å'D²_ÃÃ~ŽšªÝ+Ñ´ÒºãôÍ6&ktg¤·¿âEµÖ¶^Ä ¶28rúü*3ì©kÑÏðÁôÁ “sxweçOžƒÄÿ7$2ßAdàç#ý›(ÁèŽ"Dœßl¢µ„í—ö~a÷¤ý¢§DPLdfи ˆŠío¹­ÖUw âùíÜšè¾-þÒÿAØùÒ¶ ‘g: ’NZ÷ ôM.l™ odD8ÞÚú颓Tôdgî:!‚¿¾è°•0ã"“ðS¥9Hx:’9¯¯:qç£î/ŽöÑÇ1­T[ryðg,@J USHÏ ŠºB:¤hB¦®¥¯\ô‹v G‚Va^62¬šú}°ã¼cÑ;6H/§…—§‹õÚvw¶%çð:¥&@N—ä3CvsõVˆ|é€Õ…ÔiÈ·;БDæË¾‚º%—ßC©/ßñ™€ a»}«=LZDa%10º6@ý‘2= 9Èd@þ”IÖ/ë®®[³GÂå8Ä–kÁ‹0ƒÊîd—½æ¥Ü%çOö¨i}‚–^އä€c‹(+ÌòhIEv@bëUÄ_xkÅp/7_Ñ=ór±¾ó®ŸÁ£§²?ª¼ì)¥krž á ãPúëÖ1¤²@c˜µ6Àê4hq¤Ë+£Iš-¢‹¿µ»v_IšâáK1·L†GBfûd€mA¯ ?b÷zÞŠ)r2».’€€Â7ì¡ÆÎkµRá=¶Yõ‚·Ó‹O VuË;ÚIæ1x†üv¶2ÞW.„‹Ý“Uò>TG±ÖÎ¥š†4bëõ•‹Ú'ƒ·b¤Sñ™ž~è6zd넨n¥"ëvåƒÑë[„…†Î̇í;‚¿ó.„Zÿ“5厗Ó7•ÁûÛ‡,œ©Â™õåû/¯(€Âï¼çkÅY_ZYüm᎗â£ó¥ÆÎ*ÓFD1›êŒÔÄÃQhÇlQÞbý4~n5‡¢° @¯^2G;ʨ¡þ2h§aÉ d3QžsÑߘ´pDù{~.F€LTSê;ãhÆmnÚÿaÖ!+Z¯‡dpÀz„U?­Ëø2âcÇaë#iÍv—ºèþ2Lù^G R†ÉHbξc,u§hଊö¤·øä¯ÊÕ™O?{¢A·Öl¤Që=ÿL0¨à~Ï–˜(úâ…Ø‡4ahýUŽ ÕÄòA£¦S”c§Ì5ŒJà!ëõÅ(æZ¼Ìcp¿5ûý–ÖÎŽzÛÕjŽöÝG U‘´°ø`+969¡6ñ^'µ„õlgS‰Òlk\¡y‰f{öBËì†Ô Ì8[N6wp^,þzm,ˆ%c«zvªŽWŒVXïoÂF>‡¨(¨ªç› è]r¸-§ªÙÐùñ`Áôd5£Cä?E²YQ sd\O}”ÝÀÎÿ" X}ù$¤˜a¢ÂÒ-üã‰Á”UÒK´^ª!øy?2¾š‚ÁQl Îé7aj1e±ñ~!!¾½Å DÀë·Ð¢AR™Éí_ò·0å°/ Âsh— ‡ñª˜±½QtHUê7˯ø[d;:ï0RC‰ Óv qM¨~ÞjW)¥‘wW§YP\Kªjï±7AޤcbƒÕ´ÄáÅiT)'Sý¤JÀŽpLÙ¡}™³šI"âJNÕç^•öÖTX&’Hß 9~°Ü†±ëE²88ðTLw‡696 µ}´ ¸¨úö­ºaõ¶‡H¯˜DÚo•Z]öžg2@½øÅ“¤6I¶¥ Ã¨âeú/ŠYT„[€c7««$O6鮟ýÉ\;†É"A[ÒÕ`Õsåi©Í­3Ýß7µŒ|+T¶ GA0YìyXï„CLÞYÕ P© µA"¬ †lÊþ’€€½ªª_“ææÚúÄ_^ƒÀÌ jôÿ$¥cXŸØ×<ºdGý®JWe®€KÔç§ñè(ˆKâNχªSÂ…:C9]Al›³šÄx»¸ËWG[Ç…-<¦ …ŽüÂJSÒBþס»÷‽P ëe×!ŠÞb”Uä)Ìo{á™§ð Œ+´š0´Yð$[£Ñcû®Ô£Xu_²ÏÄK YÌ{ º7|»{¡¡Ø?Rs3¾*ÚÔ.È®Ž»Òz_[¥ @r$sµap¡ß¨5¬¿ëV!ô$~1#þ&z/kPqޝõ6Å@ðÎ ×7&Ò+ÁðÊ‘>ã 9j‘óèç±€£‘n†éâv¥ÐúIT%Q5æËò_ÄnÓ%Q -Pó~“¢w¨}öSà8Q¸ðâYº¥í°TQaÈâð% éÅÙ:ö}“‰©œHøÊÖ$AºÑ‚ÃE¢lNx㯈ɪqùÜvH&µ$õžØiƒ–»…2TðÙ3¨kª6‰$Gr)tOòoƒºè8*=*ÂzÉœãϼ®cM;¤À<Ö±s0ÉÚº {=ë|¸';\z}C`bmº¹¨Å¾0ëhËè¾€Û¿8}4û×+ýÙ¨ÜÄŸEèˆàÚÕt…­Œ›ŒÄýH›ØHGJH Ê’‰ðTxžÏlëý§HY‘¬‡Ô%@aÞUq®Nj¨Š>k[•oA6p×á÷Ë5”—à–2¤U_Î#ËÛ×FCÆ)}/½’hùæÂLzM6ÕVLÊÚÇù¹Âú\)Ê6’ ŸñÖÒ¹SUçæ3I"y4\)±q—“<É¡S¥k8+‰ "aëÇiÔKn”ã_ÅÚ¦àÓ¥©â{ +ÌSBr àˆ$ŸW›˜rIÓT 4mÞöÅ„Ëvÿùƒ Ò­^Îu 2zq[1î¼'7«?»Y2¥;ðÙ¨¨Æ¥=ȇ”䑦ÔCpÛ¤»‡šx]Ÿ:¥ÅÇÔè !-ç?‚1œ,CÅÞyð@÷‹§GTvÎMR‡ð„¦šaRIF|V¹—cÄ„²EêÒZåbÕ?àçÀ˜‘+2}TРð¡„¶ê× òÃøS]tÏÉt’íöwpâ/xޘ龜Y…žf½ÙýE$À#0ƒl˜£KTÓhþ›¥ä‹›©I1f¾1ËÝ!¸X°-§?Döar—}B/6a=Žç`ð‰ 2èè*ÐÀÿìR’×¢pÚ“îJÕ]c3œ&¾áå籊p'8Þ?0æ]zh=+(œSÏS•‘pë1SÇbõx9ãkÚhý¯²ò1@¦šK¥tWÈÀt,RX¸ /(¿ê¹Œi­‰•«”,{>Ðü©¸Åâ!‡äc,¡ÒkŸ ‚ë´Ç# ª&.JµîAƒYVÔ:ØåýÚM4I"‘_÷ 5SÓG;‹üuC9I’~ÄÒ1nÒW]D‹R»¼=ÙÖ{ÁÕÉóðJb[WÂÁð (––Ätöȯ<’¦*f©d´;š£"µ3¯Å§¨¥YõtÑÊæ€,i!k±LâV°ëHÞsK>úž±—ÿ¥ý„-üwH‚*f¹WÿêgŽ ¹ÔÚ› <;ªoóš³s8ƒ`<ÉKœaù? ÂF— çùiû‚yµEN (¯hO7^F,–”©ô€ f«c”b’×ÞÙ‚l…‰zB÷ms/iãÒ°¦Àœò6¼öFö<»'·x.;tÙÖrkÒDñMAï~—1é—!•"f{÷A7­ŠÙ © [7@uƒuÄ rl%«iñj‡6w—A‡ŽÄys]2Qp1*U¾1ÔU@Ù›…î´ÛÎe%sŒì«ê±ô¹ì‡‰ÊÿÆõðõµ.03ؤP<\íäƒõ2‚ŸéZÀÕÔdá ŸTZZÂ'ñÿžõùEYªÄä¡™#’µU†0ˆ:L xPÇ—\RsMköï Ô Ð#!‡døNÖç1g#°VÁá!"§{OüŒ ÆV—pJW$|ÿz¥+½‹&P.%²S:—Ì|¯ëQþ‘`?–Yàuõ¯l@@‰¿ÿ&µäÁ‰1¶‘ܶ)qs±‹éÒ¨¥s#ÍËe侤ù'åAáãw<¤«‡šq á’€€Ó¶ÞW– гFyö¨K|³LnžgêÕ.áíCåͯ€¿÷À!Ÿvm¬g±žŒì2v¼æ7‚òG7¢õ!Ч²¦CóßÚ†ub£fsêyNß¶'$¯2Fžã ZȃŠ)õÛ^4Œ#ìݼå8*õhÅ{Wiê!™d6F+Qùƒ7ZKŸ5ød îŠSÁXI(^&|~”H_wj«_ñ&WÔƒ÷t\dQ+Òqâ)ªßÚ+…ä‡N>&Ü#«9c!Þ/¦¯Ûã#pðÚEm0:.à€¶ÄïJýXnQáwî -Óñ—¸ˆa5¶jé_âƒ+7Ý9ñéA̽-ä¿ü»9Ú±RxœXÛõ4‰ø>ƒ\ŽÑ‚Œö8ÊqšÅˆõ2‚±'rU©`]:*¨v-ŽÅ鸗è¯ÏEÙËÅéÄ£'7÷P´§Ö'‰3eÅ0–¦@d{âwXц¶V:+Z“!9MpØ{ƒöŒ®§v³,\ïpH±Oò!Y[–‡ÌÆ#»Ú{}½s¾¥;ìÌ ??Öû(6—o  8Z4¦*(Fÿ³¶fMä˜jn,ïnFñ»HG7íoÝÃØo9Þé(óó«æ/J“@ à ¬¤VUõ©tpJ:ÂÌ0Ÿ ŠÅ8çûQ¹„†Íð|°x­UMÏ#|ÞÐ5Ÿ”ÇígÉUÊØH~zÖ3Å™1YŸèæC¾Ò`•Õ[V®V6#­úÅûëŒRÅCù U¯rm¸€!6ùÒH ^[æm¤õ»l(^ØÀ_NÅ–´ Kí†b wòæ–¼`‚áÞçרOZûŽ÷ÏPUÁ\ó„(Àá0Dj÷,Œ <¡$ ·Ž«éß,À?XÔ€€‰ŽJÍŽfãš®äœ ²ç ù5DA°˜ &âyíH«áè-x*/.ÞP¹¸™ÃÄš…•ÁʼЫ–Ì.ZŽ•$¼‚¥{Ð^ÑüÿSêÞ!ð›Ue”phù˜.Þ¬…ö¶ÒÕ’Ðl¼› o¦ &ÆU,™" #þª©Ž—ޱCnÓݧ{Rˆ=ÝŽF/Kw5–²ýŠoÈ`0®©>êI½ÉZñT¸ô‘ˆÆ…ÞÌÙ-Õ…+µ>œ=þ„áØ£…Ö9¤‹Rc$@%´Rõ™1x–c…5’€€ÊðµÊ\¾9Rp«£Å”§|´ÃK™ñŽõ=&— ‚uu¯¯.8²ˆ О’¸ó+sGÆI¬CJ6B«kXGYÓÆ2î9öçùh\ô¼A¥p„–Ÿ¹ù¦Å¡cûY£û )£íŸhkW C¥D†èfáUk‰ªÔÓ+ÁØx¶Ü”¨v]~ü˜hþßfO|Ûc¹ûÅ ö–X¹Â¼ÞtãØÝŠxo~ðâò%¼òl€|oU9h@ä²ÂÁÐC½£®?ýdd™Í¾qÎHó)&1sX"í…6¼®¬ Èó£’­45«Â­Â•æØÁYU,”}kôm²ÓWØ;k“ËßÒÛ߯z«GØËÙªU4‹ø{Quæjv‹99¦>¯›o3þ¾5‘ÎfÁ˜”w'hl379.ù$6<¢ 5÷‘1• Iµ$"Al“ ƒ¯.‘Ñvñ*kÏ{,»Ã{8¸ÅmÛ M ¾™´x÷•ÑÚy‰Ø §_ ‹ûþev$;Ы:Ã-_#/W®ŠÁD·‰´;W´¬peÞƒ! æoÛX8PònÇ|“Ú ÆgÅ}w êyü !âe‹³hŸe°p ^\‚ÑŒûÃÞÏ|ä> ê>á¸>Û0׃Yüµþµø´Ú9oT,Zêä¥æÞ²òíeѧJ'YôsªJ¥jZµ0·»WóÈ£÷V.½Ÿ˜ºÉ,܆#$¡&Ò¶S¾©ü+î¸x̸*ú„§P¦ä±¢ko ¶±oiùüD=±š ÜàHßûkdkœš!Tñ‘WÍÏ—u©a2>ó{’¨É¨pa%*ÀiçPõj„ÃÀvMÔ‡ó^ íèúhl¶6¶ØÙÊþDÚ0½á†ÐtxNàKꔊ{³žáÑ'iìÎM·,Ëü«_Gá)r«Ù{üÛ©nBJ<„aœÄ|¿ªÓœe7ìrÕÌó©£t-›&]ÅO„¼JØ{­™©²ÈßÒüùÎmuJ_hŠÕ&#êhÅ´-ÁÖ7Äs»£¯u8ÆÃ …;ÁŸäñ>¢PLM+"z7G+áÏ™>…­…WhvÜÖ+ŸKPk !\Ç€­µ"Jh7”“¿vÂÞ*ÚŒµŸë÷:B„P°vÃ}Â6¿ù?…JNî§WxàG¬“pPêÖž…Z TÞ’€€«¿‘­»¶F9ŒÍ~íU:Ç(Üž¬®Œÿ§Q$½Ø‘zÌYÊtº‹º«*:¥%Zu®»4E‰.HFÖ< ¢›d$¥ênÍØE‰ãœE>=è… ¹À»ÌC€)ü¨&¡›n—<Õ<Áë-ÙÂQJÒLÃëkÔw×"#ªÉ„ÏÄ–ø 1ì¤-¤AJ(ë{C¤•/™Â{<é  àz.IiõÂÿ?NÉc _¹Ê‘ƒ«JLùjRn¬ÿ—˜:;Cx¥³vžF£L%Òû.¦:Ä ¡ÈG£/p@âE‰½ ÌÝuûuŒL]âCXêg¾¬™QœÓx‰@„W@ß>ŒÑPú…f!6™i2Ç8aŠ`xÂwuÜ¡±îXôÓƒúV`Ôæ¥V«3&_Ë€’¦¨•n–,AM»ç¶‡ã,ÜRÌ·4¨œAÃR7ËÝŠUŽé©&ÖJS V7»"ãú¼g·ëëF¥KQÖÙþ– ÔÝöf[ ´Qo­]ÃlÄÉäIB¿0fý 8R0%.hBŒvv—¬ Ð,$K“ÏYéèôûå•b,Jº“6Ï"Š4ÙÙûÒÛi?Ào¸œ´<Ñ+$ôjÔ¥œ/Tb’Ä6,¸là_ !žõÐéfRøHèhmh»)Ñ8²§J§ß»×Ê÷;VÈàr Øš‡Ôå¸Òá0¤ÏØñ3XKPJmuà m‘¶»;¤”;Õ^Fz”µù3’û ”iQ«j-í0Åa·i·3|_¼Óì6®šp¶¨ÖñÿíUo1ž?-k… Ñ•Ü ƒýéx.})ÜùE°¸þ³¨'9¶ý8ñœDéVòKibmÍÑ$<ª4Î… M¯®|Et)×#SXùúŠ/í¢s+ÐI±K䯙geG),N­2×sOàš©Ï¿0bn#©¿¤¡Ï“¢fnê}¶ÐüQ™I"¾Ï%ر·ˆ‡÷a©ß@C–\ï˜{ÚÙoºb/–?5¶3ùñô4¢q•þ6åL@­Àˆv¼çóúlÖ±#iÎçÃ…ÜúÈ:4m —º :RqL¢ˆ…è¿Ê5‰B³ ~ñ TQ䌇¡ À£ä¥ŸX›ìöÑ% “öL¢o¬¯O8®sòʺ æìÊ£i™8ª'ªÀŸmo ¹§º¾ÆŸ5þ°’€€Â›ƒWt“ó…4é`Ö‚s5¢“ù´Âu  Yê•‘ÒË™™c+(»Xœ¢¡-H1D¥¡•îhhòñm2íîã¶ÞWÓëÄfñ‚Ïê>žl`|ý»ºÅ­=vš©%Gà¹a!¯ANwº¬EæäÚ†s„ý Ç! ;u]ÌÏ_8ãA‰ºaÇAñD+éþ»Y wjEúçO–¤Y®øI©ÚÐZo¦iÉ ¯=;g62ƒËÍqìYÛN óe—ôúðdm¢É&~תJÈLda2â˜ø1!°Jv‘4XGW%æ½k“ìo§ÒÞÅ´Qi¼…ŒÑ7./”À2ñû¥¥X‡!@]EV³½}h¾zÕkcio²6ÍÃkÞj)ÄäJñ rZÆ'-XÛqöåvT©üË<r.{­”T«¥õÂE2ûfÿÇ–e£ˆËsá"€bËc ¹oðì°ÜcËeIÃüþ5©S;hò6a¼=>©ö|{©Wƒ±º¹t‰‡n¨Ú9‰×­Ûg4ù}t¶æ,×~‰æe|BÃóJÔàKöÑŒ}¦•~Fèácì½§ó‹KÞÑÆ»›z£{VC@¥ÌÁ pP'ÿq?.p×RŤcvÕ:•wã|~A±I½¸/©ø*Y®v,Î6ðƒƨ+®wmjà ¢° œ]s º'Ö †”Ý;ݽªxL€ g®®0‚ͦ’šà28Çk'^oeë[€¶*AK0‹=WvÝša)Ùº¿mqþh³¤Z§rZ߬4Ðä.7G[Éû3r:[i«}§Åjõh;®,+åK´zî^ZýðôãLŸÕˆþÂ]›4²‰!XˆT÷m¿õc5'†œæª%âÜ+¨ŠDHP¬¹l¬ÐM?h3CÔx’€€³™ÀëÈ69ƒ©C0äÂrO-Ú’¤Kæ³ð0òà ã¯b£Ó  8áF@Ò½j™Ç}# 9d\ÊÂÇ:Ü?c6¾Ù=ÎQ§ìÓn%‰MÇÐP¬57Æ‹2^РaOm^uLEÔÃøOw`ÓY‚[-i1S4ØËîͱºTs.Àžün5É». S#ñA2Or<iõ¬Êçï;%ß/ÞÑÈÍÍ‹nÏAÂÎÞ‚vçÈÉÁÇŽ»C®âm Êk¤$öFˆ³øú£À=LP±\jèÔ$›Ý§™¦ÿ¥îeO ¬®'· \#-ñóί»áþu¿ £c 5>Lµ,n46·%*ôè[HZÐE©D¼2|½zÜó_:*°õjN@«)¢þ±… ç yTÍ4ÜêÇõ¹t´` ±2£öò>–pÛSá¿T£ÿ ÎFßsÒþšÿ>W2¯K”Zÿñ–­¢œý„–mÔdY~NåÂ+ØíøÑ§ »/W}=»ŒU"¹ÍŠÔ}(vº¾N¨+Èþº9¡B6æ>AJi´¾¬$û2™ÐJ©ÌT Á¾ƒ3/q zýe*Âë(+ÙÏcþއ–<†¦hšÀð0"Ø=KaNàç2È$í}ÚÌìpþÙMÉø"A+X9Í~6ÁÈzŽàf³b.Á CFGfãÄhÇS¾>˜i4ÃRE‰Èó.Í™•¬þv¡o7+ΟBB»¶£ýe'¾k—‘1À-Ü=—^ÊôÍ·Êå§¢âˆå‰Hw0“1h¼>Ôòñ º‰hÒÀ^$¸Q¾ÜŒ”Ϻ¯¼3ÂUâO¾¤&°SÌ䌻?`[ÝA›Â”“?5"j?ñ;N”ÿés«æG–´ÚθæÓŽbµ7±¾7¿’d@EËL&üÉ‚ôΗääÍ¥ùã“w™bá÷¨êÄ 9ç¿nn-hòÕĹ6eöö¨éšš½™1=òf!7^qjÅåTG°íñ‚»ßh[žðÚM磳cYcê#”&‡uUtY-YçlæŽòåLØnsƒ: ÓÎr"¢$G`™k±r‰r†ØðKò®î°³“Íj~qhûB4cŸ 'ð.ô}—4›•¡ðÍè/d t°þÄ ƒ ¨ H¦º…h¿w1bç‹…ÒÓõ°Ý¬_ÓY¯˜§svYj4±ìr’é®`(~9 #°ÊçÐll <欲e ÂVeŒþ ˜£°’ÿšo¯7ªí¯Y¬ÑUþå;Ø·ûAŸ(E¥UÇ£ÙgÀ:)p91€Àß&Öíäš.2mGNE Ö•öÕÝdᲃ\tÄ N…¥‡ž”>’¢<ñ+½8·1$Ȩ‘ØJù¶lÖ8YÄÂ7žMjl®à¤þ¢º¥SÛ½À€vÍGâ¸yï„DŽ„APU2Ù¶Á’Þ¡üáÒßlµSþÇÆ‡`¦ù—íV¾b%iOhvÜþÿÊËe;6—L‹Šan¹BU0|Ú༜Æ!¨)Ü–k4lB¬ VF½‰CYÄ1sÖsùLA- «VͯÝÖCT˜r3QùfFÌg9[Êë¹pÛ†®Ë”È£ô_¯ñâŠy:!ÂŒ\"§§0%Z;¹nriqySªž\.°u”Ùç£Q‘ã«¥ÚËcÙ]+ϼ]–b̾ó.8÷œÍ ¯Å åÉ«MÀkïî;۸ᶣ7÷èöñXÒ³LÖÙ€)y×Fa2Ü\ ŒCéÆòÅ…Œ¢¦úª²æ²uK‡ E%ÎÒaW²:2Á£!扩í«å'-³´³tNµ# ¸¥TŒY£dà ÓÜúzj‹G£â"Û ?cø¶÷Rùˆ©ˆ¢´·}È -[Ajpù ¯ŸÂÍ÷Œýaˆ‘`ó \¬8 uýH¼5úøÞCÞ±*/X×:~ऒ€€Ð¬–nJ¹˜ñ½’sÖqT0gèìn m!sÚÂ[àØt«Š%É@–Žø&¤“¦=ÊÍl–ðÎZM.ó$¼­ÐmøL߉?˜ê³Î´oè’OGÀƒ b;šnÿŒ2:içv#œyæãX:A‡°ÂÿyJz€Å?ƒ¬ó²Ø`*; šÐÂè³…œõâgå½ÜáJB¤cl0j$—æ6¨¾ÊÕKR³\Ü{ĉý;KV’Ã-uôðŒ|¸o+¬íÓ¦ø½ ü§|:¹—0½Ê:Ž6O?‘ÂÉ3КMþ‘Ýx!¼ï³wHE™,¹HAˆ¾“*h×ç oˆ•¨÷_Ýl©È)G1bU<å;º¸ÊU[;‹\y+Ö†¹àµ§[;N˼Ëò È@D,$5,»6\+^¢¯‡62 k`ë„»FžªÂ?QÊq¹¿%ëà=^,Úñs¹ýÅ?‰’Ë%ݼ;]OÔ¸eÚ}MÝUwä\un ð,0± ûºÓ¬ž¥úé6þ†æÓO‚oJ3³†d¹Ù©póâk”Ö‡†a@Eœ\:Å­}»15î%¤rJÉ¡š¸ÅQÏ²Êø> ì£Øx’‰;©À@Hf7£?í-Ý=$ì"¸óLè@tgp·Î8„²å´+b&݈´!ÒX®ðMjœpú²…vv ½ÌÄáÖ£"%F³%½„\àca‡ÒõyCoöª™eëLTޑЀ ˜$8ņ\O´W6øX¥¢j™AÇꌱyWz90mtzâ gM²E*Î9fÿ”…sp­[¤€Q>É…U¼cÐóÜêœ`mn&›=lh €ö1qË×g§ ˜<{„„øecᮞ̜6P—Øâûê¼z\ S+§ _Ã’QµÕß.*R©ú@çØÏ»F€¶È eçj»j|Ó㯆¦6ËÊõ_$år¨k }öÆ<ÍeÇ2¿„~{cÅDÿ_.üÚxÐ\‡2@5¡„¬3y±^"­Ù­Ý£ÀB„ëª黺 ~„¡ ÷J»­`uê¨MThi‡Ð)ws~ÖÍß U Rˆb¹üìõ{› Péû5/Ûzr'ªü,#⑦-P €Ä\Ñoîkç¢[’#Øè`Õ:‘W7è­t*ÀÍ=r4>>ÈÀ1Q܆AT Yë×ÚÙÑë†çcÕ°]߯P,DÉ¡sñ¥zHES¯ Í Nï1¨sbžäÇ­4÷¿/0 1f®T,~Šlq¾ÙúÙDIW.!±kWO„%’€€¨¶å^!]ÖF›å×ÔÃèWò Ép¿D\SØd™×‹5¬™žÃðP᪠oZ&W‹©•O_F¡GPëÈ­ƒ ü 4ô€í“¬ZîÜÝê8³ôžñªaÒè)*E¸JáŠßìX¢Èˆl`/®×ˆ”Åí*Ciíþº À/G²Jƒ½‡‹ ‚“.j±A5~#~8y&I³G(TÒQ#j•‚‰ú²JJÛ)ݹgšv{ê¥ûËÒ—^èðTâ±>C÷ Qì~€³# «åBí‰%ò­ÀÀäü8-j´dÓN' Ø4X’ñŽÜÜæµÂÞ·Åæ­(G5éÝñ«R8Q:§§;egg6=+Ýf•Íbmrx°i9†u®Øvú;&±4ÅÀ Ú¶jfná"Röó ú‡»BæDŸ›Ý·TŠTv€*?ëÖï+j"aæ`¤X”lªà´Ê|l~n&¾ýMNÔ¥¸PH˜Mq¹H©a÷ë‘Ë_Bóœgg¹‹éÛ3ˆ“@('bj0DÒûÏ¥Ûµ5 @W¤r1ùd O4cÏFõN˜a6L~†—q¯AL¸ÌÈÑÍÛgc/{´[H‰ã߇‡°Â= \ÊIÜçë§Çõ$¶ý¡H.HiS‘2˜XÁGáèW´;àš‰WÅMH¥ýU×P­’nçyñ8Èf1&ÁÐWÏc}k>Õ4¯«ÇÝ|r0‡{Áº±b ÄüŽšÇ+„ÝÇw«ô%¨ðSqΔü"ÄN­F•¸ßغ¦ÎC÷Y_N\úÛ „ê£!sö)TÅ1&œ3¡"Ô™Þk¹ÐäçéŸÇº²>©ýDÔú, 9Œ±( …;ú8kÏOO³Ð°I‡ÝXvwošzý+¶ ¦õ?â ]uY^—# B.s >#\™Ìwq”Éj+cÉ]îJb,m<7?*D‘ow-…‰€aSˆìÔiÓõvÆ¥^¦kuáY9ØC¾L•]Õ¡Å/q Ï–í.ñ†Wäø§›‡ƒý1LÉJ >A}!Í-Üoˆœ/Bƒ[p¦0sÐr žfrØHñÿ=ñD#Ê$^¦Þü’:]¶ýHöéC%f­ N]NW>¿FqG°£–Ôg°n‚áT<.É T¡‰x~ê—É>Ë”@ÃÅLâÔ‡0×—SÁ‡M4®³EkϦ4Pâ'Á}M8„ÝÆž&àïµÂÿjŸ ~E׋TÿŸ³ƒ{ÿOc{4h…Q€Š²þ\1DøÆf3÷h¯ñ%Y®IS€Ú/$ƒ;ø|~4 ñ|-/ÝȆ–Z¥@ösÂDUÍbs„#Ozf d«#Ç—ÒZ3±ÌÜ Šw:’DD åS¦l±Öæ0[[z~{:³ƒÒZBºÅÐìN9"ˆ VkQ±MÍLÝ®úÒ÷§d€$˜,¦DíQIK[’€€¿`æ¢kŸHÁ·¯NÓÇj]ͨ §²Ï¨.ÄkÓ|¦LXÞtü×yù`%eÜN7{5˜»dHLˆ™ò—iÔ?¡ô0—•™„’;1fÉcÝŽ©€|£Ž4Bnù\„6¾;­˜Ÿ•Yhg(ÂÂg»õ‰•]ò-OFkí?÷ÃTgýEí6egï[/A(5¤’uÏï"Æ'ª¥x ÚØm…r‡{?ÒB¼‘ÚÒXÕ ·ÓG©Õ}Ûénª&M!uZÒt¸&õÃÂ¥­L¬ùɈ˜¡ôÅoYcH¸Lì?®›§¯iãü@©!ƒ ìþòc1¡ûÞÜÃ=dÛŒâDk;ï_H;{ç£$6[ Þÿ?Oý_L¼Íò»ýº±ß õðÚÑxÚò²„øuµšµÃÑva .°P™‘»¯PqãV©rê›Í¢ K"•\ñå9uÄ4­ {g;Ü¥‰=–à¶*d±¿Ì·ñ³„„œû%ézÅÈL”nŒÚ¹É9ôu¹è‘ÿôùö~²Oéœû¶194<²ÒΨSä¼2O»è#•»%Émœ»5‰÷¬ôõÜ_öøÈÊŒøón ödglDU¹•¼&‚(…üÑŒZ;LJxðbTBsuq¯“Ûp²Ñ8”iQ²ˆ™òmgLÏ],|펡ðjA±—k ˜DjÉ/¶héòñU-M¨'€w†7ëÑ)§ˆ޼åxú½AÀdÜ ¼¼Q™™ä¢/x+Òʇ âýKM¤È\Kš"|ë…¼}Z&æ†|Û+DvcÉ%¯{Û•íÛ!­ zÖÇæú£âw½¹HÒ ý:Jó±ËÈßqå7<ç]9'¶îS’+ªA,ä;ë;f-k¨29M~çx¬dßJªvlå/;»™ó·º™6еç½kÂobØÞÏAf‚è\2zTëÛ¬Á"ÔúŽ®Ùg 9PóAuZ7–ƒv½3XLñ2m…â8!ÙSì7((ŽC0g’:×_&¨O UÞš“Àî¢(òn¦±ô1rh|§îµJДŸËóž 5‘Øg4Kbmvw dñÞx>#ß‚yk™¥dÆð;ˆÏ+}V…) °xÿÎ]r‚' íÞ ¼ÿèó"¹.äL€?:xh}Ë\YÈq„!Ò’€€Í«²ÃÅVÁYP+)(¨gÝ(`ï˜XÙÀâÀQì£+X€–j&í-͊ПƾÙ: %Aò®!vø¨’¢2D¤LÜzTŽëÉ?ô:¼F3÷]ª»xÁ¦Õ€äZîØRêCº79„Ö†æ¨ïa"]çn×cð‰P†ÄÕô¯/Ù˜åÍ·“LÅmr¨þ/šƒóîXÞñç^M{Æ”wã[›É7‘SÞۖÏ7ŸZxbÌ0]¦Pf¿¨×Så÷_9Azü„cÎèƒrt,é÷æ†-`Nšœƒm-{K¿Vàž—®…ÁK;bîX§u¤tß;@bð”e [Nc8íóeì ¯/<¯"ûU#Î6K8oÛ‚©W?'Éi¿a¤ÿÚ«ˆlŸFè}gbÌÿZBÇsé Ù?¢¨Dˆådt’éÞ1IèMVFhÚ*ÈÕ‹²¾/öµK']†¼U´óï#f$E)ªE ÛxM>ƾÂ%ÁT+£2_îú<œhÒˆG0ÙFNó ›¢ÒQ»zÚ./¼õ•D\Åç®r+Ö 0 „i€ñžÍ Á«KÛÁm-Pƒòn’Ë?ðê}çиÌo-âc4Ù­EÏ"u·ã»ÇOä!Ê›¬Ø÷´BÄ¡S«œ +wH{™ø_…+öÂ9–®»t|V'1ë‡4 âÜ­3maÎ3–ÚZÁwß¶ˆè›42IlÔ¶Ö“Ó•§sñŒkV¿Ïð•÷¿Åå‰|‹øˆeÕ3Ì3ÍÓÿóS2)rîÏVhÊ*$\±µH÷xùDcÄNE̪2)tM½-À⣠yN„¸µ2ÄTôVöåÑì—#NG½TSߌ! ºäÏ•.Á ^š]8X9.’Ylô€,g‹°©–NFC5—fÞCáOc<ÜË5Ì6oà7jœ]ù#’.ÇáÌvóoCyüî@ï¼÷;¶íÖŠ[‘IaÈ º­‰QGI”à±õF8_óû‘‘­ØÔ3P—OµÛa=(Ä<©ÿ“ϤìqWЏÒA‘Fðlò(‰‹šA“®4<žÞ˜äÊÛ 'b¸4ùožyùðÁ2Ò8ƒ±ˆ+û;§¦ªñPnÍ$ßLˆr™r–Ä*­Åñ4óAfi-6™ %Œ¦ð¦è„°°w'PäÞÉ“‚zÓ¶´-LîÊQ4(¦Ý’€€é9Ÿqí%w%@»à3vI?W¶™u¿œBLGËR, ‰€ yy‘EÁW@§ë± ÚSZ‰xÃüÓëÚ÷¦½ô¤þÿ¿hÁj2xFÂîƒ!tÂ=iÅIº—µG é[™~Ãó[±…ª<Ë[c+ÑuØ@RàIÏ„rÐ¥u®BŒ¢˜Œ>Ø€íBapo½ïÐbLX¡|[lÛEld›%z'M¢¤´£1ðMWø¡kr,`r »Ü!XœÍ º•J/;C±I;¼+Í$ÿž¢·6šäœD ‘Þ7.$ãø4v/èŒTP2¡²à•I©¾Öá©®¼ZÜ:ÉaéþÉ*Öq¢x6­÷¤oÒo©«ïó*˜I¾g˜÷ ²·=¼ÅƺŸ„"@èøSZ¥ÞÛZñ¹DF,ѳ*ÅÛ Ö¦p'pÀÀõ·¦j"9®šõÔB3§ ‘ÊèùüΨ’µû];Àw¾¦9êûy‚Ì6–|þ£z»àÌã›1Äþl?âŠħØFìf‚,€£ÖrŸèó¿3ï(°+;΋$á¦CFì>cX&Mè/ZfÁPXž$ ›ú¾Î_RªQ,)8LJ#—â…€i/(ý•¾ë2ÎÀ¦9OÁª$R9ž´|tg™¢€NSvgå=îQõÙÑ÷G«ŒbZΞœøNùghM1€„~lààŽ}ÃÂIÚD‘tQP,BîPO”•{]I~JÒÚÊÒ³VÄ“¸ÇÚÂNéTÑ×O€4w!‘K÷óºwQ¯þ ï$•môBØŒ)«¤‹ípFüSL¯~wÙ£_Dv ms¯Ññr‚ šÐDÎáRÉI^±š‚Þ9¢/ªé¼©Ö\ß­çÜ«VdzÉÏ|Ö[õVQÚOAÀ ßDúׇ UQcZ'Š¿X†õóîQgôo|¹ÿŠ¿vÿ˜×‘åy5„T\–RPÞê=TZÍðR„¿îVj´}RNxßÕ•ïæ±,ÃhS>ƸÀÞ†Ì;ƒÕE,^|[Ž}Ò€^)É–ãY š¤[«èRW·jD ;,Q±±|5Ü)sá`ˆº»7çâÒ»§"1;¹ ºó¥g^ì§!þÞ…ô²ú6î:Ôà•z(ñ­ýàY9‹¼ ü=Âöë­£ci;¨©’€€½mò’jlâ J9O¼ÉÂÜ=bŽ«AÕd¡+ió`òh«âDa7°?¦ßuU9é/ã¼èôêÇߤui!Ê3Ñ…Sd%%‚[[î@À|ü"hjÒ¹”Ž•øBãJôézdA¦åJ(Ɖ6k½ëM~ÎÅÉ Sø@ µ¼b€ÏÜØFgÄçìË„J’ŠtñÁÕ=™oº¿TAMeœdï.wrùô[Ás[fï'ef ñSì§ìkšûˆÅTg$eè·Žeo{yÿÅ•{;¼oJporÀÈ—X")!\Qqd[QÂv]ë2òVMDË… Fg]Ú›Á…zbù"ï3²Ï[cÐ ˜¬æ×sò'ПÔ: î×ß8òô™ kéÔ&=Ñ’à ùÛX[øýx̃”éRÀ<¦qǩĈ ñ¶KX2ÑË”ž÷ƯòœêµÀpX U|œÒ>6œóu¶±¿’¢÷ÚmÔ¼[=¿ý+µR §*U?P“#Ëe,àñ¢§„Mú_h·ÓôÎd()$ì%í*[üQ›ÔXtŸ.q¥ÀÍ3ÝyÔ!ƒTZˆ±u­ö]ucnÉ¿P§_Z¶ÓC¾ ëmpkÖ§u® Öxbûsg51·fóî`£72ÚµmUJñK;®4¿¶eçõž'µ§¯Ô6eGñ2»q(DBhmã­åÆJg¥s÷îF´“¡‹èh.×§+´½¤#<çlYýØï¦—zþtT+#ÄTõ"øx H@ÉW–þ·ûÏÌÞ5}D’WÑÇB `A¿‡ùÄË“ôŽl>þvÚq`¶N2-û„g°$æ¹$>àØYäH{-g'Ȝݴ™&ó€°Î:´>á’-ž}ƒmºòº9º|Ê«íùôÖ?*‚¾ÃÔq± k‚¹5˜Õ3þã0âŒûÂŒ¨NÂ0‡Í#Sß¼¶¾æâŒ–ÄÃ1y‘@Ý îkÂOÈèÌtþý0[!:]¡s…çíˆS2VÒtÛ8ß×?èJäÁ£ñïñ3t-iÍëÚ$B/nÛ°Ôà–,d›µx`ð*"™Æ1ÞЛj_lÿ¶M>•ÿKÓʚʗsKYgˆ­yÿìÑG4}lXƒ9£p­u¼åTAhXØ~;›å ­Nlðýû=BŸ‡ú¿Ï|‘måUh¯å’€€ÕÂÙÊŒøþÌÞ‚Q ²Y¨{0CúË·$¡H«ˆê ‡`CtpÅÅgSùˆÜ‘ž‹øZ>~ %̇•Ú%˜r…]󉳇ü«"QÝoUÎ^Y©Gǽp4S‹W•Õä6e_]ñç…Ý»O4ÿû;÷õÙ*,&h'ïPA¶÷èø¦¼·&¨¯ñw?¯°ç](G‡ÓT¹oY`Àþ!\¹vïÝ=,ª~¡¢ŸžÖS£ ™ Sñ£cÑÖ ¯úx |Ó¶Dáœ7"Ì é¿FLÀéª 4Aä%äâLwo›j¤®!e ‡'Fò&i×!·jÿ#vÀ$Ô¶LS40vз²Åp¼2•²ïmtrNµ.2†ÞJ÷7g}n鑨) ‘i53ð¨¾ïŠ-Žm—Ñ8Æéd_'ø å÷ã]!ùBpÖxšLh&þQB_#¡CF4ÚýÜmªW±mðW$ì?lulø¢ŸÙ:‰R5fvÉwTrTȆ2 À >°“@+Ài~û‘HÄ~Ý}è°ÍùÌÜè©ÇK¦â_žö“ƒ^HWÔ‰Ö·}Z’û.»gïÍ•œü}cÄmyäR$&qNTùíwE—–Îv¼‘"E|7´ ,T»>ôq¨¹ÑXž•¯DJ¨'óC4U ô63ÍÍ¡gÞ%mYókù’þ™žÝÁ’+eïý­Ê ~6ßãE±ÿ::kÃ6c¬:´ÓüO³(“»~qD¾Gʪ—A…žÈ †{­c(ãÓ} —nÀ’j˜/¬ æ_mÑ©§äÕ‰+ÝÝsÑ%8ÜG`’Óл†õ[ð&h(©21©žÉá¼.Ù_nlþαÙjÐ=Ý!¨æñÇÿQC¶®ç«m1}—Lcy4ó /kÒ,èBþ$½B |•,Ü•ê{}ÔêpÛ!‰ ýÙîCä!ú”ï†L-qRÝwø¼4Ûäªë’üäÁ.ç½ÏÜD«Áq™ä`r\D¢(¹äEáT¥Á’€€Â70,ñ¼nxÌH2 ¾>µù²6*ÇGõ†>)¹ŠŠJÚ(pÚ³`ÂÁ%ô…«ŽÓV`µ¡ö#@bïä¦á?æy©¼|Ç„àâÛéfÅ¥Ž}UÆÇýúiû ÿuØXªn_W2£Åg‚tv›ü:q#ÈÇL­.Î!—³•Sjºèÿe½`“wòÚ‘ìGÁ¸ŠØÀñ;ÙMüõ¯8÷p Š Ó/X¾äÜÊÉ 1KáKP‘db¢ hµ‘ªgCZKî1¬¤Ì²UŽ[‰4Â.êîëÂT>_ô`š7õLDËn䃇3÷sµ¡¡ôÆÎñ{ETÓ’µÉ,öÜÕœ’¸ØCÏ«ßã½\gPCxJ.¼Ú9ÿ‘"Pb=u®¶ýhÑúkÅ JPÏ’³ž¶[­q"WÁ ©‡ï±òÖƒÖ; çh9PŽÓqHÓëwx‚jIíÅÛýL“Px#ƒúQÕSpÒп¡ìå,dÜCQù×RÿRíHÈ .“©#åÊe œr ­Í2‚ò•%¾[å­e[…ªŽ§ž¡6º¹9ð¬{5ø EsÌÇýVß³Uë'î^+aËâ’¤×gC½½pËe%Æü.aeÚ1Ibð·ÈmGn›>¶ sÀÉÈnmúaEé‹nçor}´ôíd²žúN¤s)Oò¯íE®‰äJ–&Â{Cþ€aÒeE—BïàRääWjå[§éÏf¦¬6>ª*Ë€ ø±u|ÞÂ"›e¾9WèÊäù ÊZ]ˆãGM{úǯœJn÷Y…eýõHz$¬Ù¬cã´Ç Lïu‰&;^ àÉýR®ñy¼'£Ò¡§ãÑ‹N52)!Ö/ð®Ã Ò\ûßþT«ËËM¤í›ˆOb5ptp瓊BnˆT[²¼Ô‘ÓiTa{Žø>ó‰ Ç€<œÌ.É ’âX“l%±˜ÉVà†ÔÆÙk<·»èææ”xäy Óßç”ñn%«éøêKö>öòÈ öcc®épÝaŽ·È„È-Ïlwkª;Æqû=œ£žP˜›€nÁûhéÎŒë ÌÖàÚL’íK¨ÄN-€8·, aoɾ h™­QíÍlITS¶œåX¥Ó|pÄU™ä¾ƒf’L‹H¸ç£Òô„Å„Å~S;^Þ¨˜ å‹ÿ9’€€ÙËÑRMï9 é•| –cgeÕãdˆª‹#"ÄÜ Ì‹â‹(E;.š´ƒ‡xŸÓ»ªùÅæê·Ï&îTŠ»JG,!¦H&\4Zú¹vÁ–\w[IArSµ€òXz½ÑlÓ¢4ñ$\…vÚuWŸ?d]ÿŠÖŒü½în6Í¢pVˆ=νwAÕ˜ ¨¬–ã„kë5æs€Ÿg+÷¨;’Ê’€€¯˜9À0”@ÇÇE©_î8rL)‡EÚ»l"Ø©k¼Šê*eÔíGsƒZËfо xÅÈéLiÂ\,yeÔeàæ …Ñœ36±#ˆŒºþˆÉàkÆ)f À(æaÛâë©Äø­k ßln…›$þnÓz?Q³ã']ñH±eiUg;ãCŽ=é…aÈ/¯¢¿íx‚d„¢AÚ¦ÿpàMÀ¬è9!˜µ:Ö°_ÑN2ùÚä@¦Ò¡Ýï†Æ~ßO°Ì Ãßoèþ±§#6ì‚0;Ó à ÄrÀt9õÝ®a˜;üüÆ/?Ž«È®çž¾‡qKÞQ&Ú'ö\yÎq.@¨ùL•^y·j} ¸¹‡ÔY#މ®ö¾úfô.&¢ox†O}—ÖÉ*–©—7QÒpñÁy‰:}Øczu¾“H¡’ eÚ¸Ð:jh(Iã)Õ.- 1C°5£ü~ ƒV³½B³â í8&;ñ×£,?\q2¿%¢Þåz½jÜärÚ â‘§jOEBFkU>Äìu'Ô¥o)í«Üþ•ÅÊœ€™"žmvý¿Û2$«Ä гõ¸Á,Ê€õ;Ê| æH"?çY>œ€W¼¼Ïv¥{m ÚL½ƒ¤g.ѳà_õ½ ë„Lv[–­^ú"Ø%"£Õ¥ÓªT´ÄyÏÜ*ÖWöv5_ÇãŽÕiË@¼2àöÙÁꙉù‹Máè33}ù0¾Õø%â:r•C®ƒçG-ñîÊÉÿ!ð-žÀrmº R æ5¶ñ8ÒÅ7Ø%’*¼$é4l œÈòÎ3‚Zè•´œ8êã.UwÇXŽ ÅÿÛãÒg‰f¸V–ƒ W@Ë^#¼“¨yÙ¿ï(Ôaß¿EyÜzðun o3È$lèRuïJ'Ž4\Œ¾mÅß7‰ü!PÞ¯ºð_9h¤ø2JˆåJ(ñoÚv½>!/ù”Iç@î©¢BÄ¢,°ò«Š"Ø€Èa¯:ösmá;™îF|Ê™d›¾/½gFræïÓ¾„oÂÿI Ë‹yçsu†0;„ôy(ÖŽÜhiÙîó”sÉæ0Õ+³‚Åf¹Ú \bY¹5ï»úöeÙ+âóÝÿÑzañCßlüx˳¬Y ‘dÛÒOÛkñP_O~‹¢h¹AO á²&ô±ÓëÅIt”»Ên’€€ÑÖ7dãþðR,.$¤¼b…Ï@Êñ勳ÆR{Qì¹FnÓE<ÀHû¿sÆäy©B4ÛËsͺR’–§B¯ÆýøÝ…9ªdMj=ê¤Â”ËñÜvâÙÕó!û¶Õ.ßíCž¤wâìT„>é2y§ýqµñ¼™`KS²Í]~‚ƒdJ¨îý¾þJp½ÌË‹c÷:tTÂ]fóm(„f ìþo‹¾nú€‰xÕÅa™‡<5îQÁ9 `Å“¹Ýøc{X›ÂJËžb½•)Ív·`1­ó>Ž ¯h'ÛóÊhtØù '3Os¤µpK1”—W&tuý§‰¶ •³0ý/É2rüò¨(n-åñ&6\¤$ŠÝàB9¿—›ßŒßê†IðLÄVª!=ä¸Ó¯ðLê™É¹õ/¢·£† *v¯Ÿæm}»È'ZÊf˜•JJÝÑÚ'æ>½9ÅáêF5VÊQ‡¦å3ûhu!ÜáÆQÑØÍÖÑb¥÷ð1K¤ÝøMª¯æ™?˜DŽö Çø+¿?„Z³£VÇx)£>UîxµzÎX#Ü8õ+vv²}‹ôpBM/X†ÇC9‰©yª‰{Úcq낌çö„íx®Ç·Àƒvü*1½B ¢À«ÇùayAvrmu¥ÐYRa¥"²EË”꛽!ð#¨â¥”c¿S¤ïl’AÕúŠ¥"o æ#—^„•üe œ6äê™·_j £E®ØuŽt£Å9h/["m0ȯë’Ãéû[oòÃ#‡L'öf‹Ûà’t=?s‰WI¥¼¬6ôQ¿AÄ‚ÃéY`ÿ¤[ˆð{ŒšøŸ•ß²©Ó×é(ï@¥ÁÆíŒýÖòÑÄ#—v[æºW¤p¹—I¹¿ö˜ÆeBç)‚*­=µÏù®Ê_e¯¾³Dÿð3Ÿ¸xoà ҹ bXð"µÉ[é„_ôHñÓž´l¤îGc]¶„Œó«Ž÷Å}"˜W‡ÉJ=‡åá0`+º'Á®®'f9ñ}'DŽSŽWÎR¥8Ò# )}#ºk±Ýƒ IaY‡„šöhÝÆßRKh¤Å]rXIbuÀøZ£ ³ÒÓŸïO·èUY{ß#—ò/Y¼9Æ8——¼˜nÞÔE.¡¤ÅQ#ç% 船{w!3<êN;.>jÀ=Åàæë’€€º sÇúùî3©ög¥ šuøH¢œÂMû À-¿[“û²_¿Ìf+&¤"Y$»óS[U×DœI30‚ †qðLé¦Þ`@‘Ì1f*i0Ú|0 x¡‹…8®V… ®ÅÛî·L¾Áà.š= Ï1WÞu®ÓßšZœúÇá7â?ƒý€_#ôŽ…ÏД{ú#¨Ò‰b—QB¼å¯A G2Íu«RuØÈ’…³§‹ŽÿC¾)PpF*÷ÓÑ:Ÿ&=rôP¼âšòo¦þªjêýÖ5hÆô¢õ7Ij»<êäÞíÝýØz•zŒnskSŒ»eÐÝúþIûO#—¾ |mî™Á;¾aÓ &­W×B!!Ó¬­CQœØµ½SoÌ ‹lö«€—bàÕ &ïrŽ¡|¤ÁÛ ´lfqäns¨'Q‰‘;{3 [M:bºP¸&’¼ì¢®Ž¤H/ËââÔãüÍ·¤_äà– 8!BþaÝ75ç»ÇÏàǦ™&¹wÂd {[`ôǘšùß9ÈX>d”'[‹k´"Ã0ì“ÞU«¨-Ý*ãBP+_oÖ¼­ÇäU  €-ÛÆíÜ@µaá”Ë[ŽaßÀ |¼wÀúBa¤³8q©>ñÈüV傯oP‡z(*ûçã)@lI ,÷¤F~ã3âóý§Yçî]G±–ž‘âûLvš˜bÝàÔ6Ä~@¤:t»ó¤«·|ôä ìG@=ÿñ“Hy£F(å¸Uä^>û N½_šP„ªŠw„¥>›a(´?—Y‚Õüû8´ÔI‘4ׯÉǯyòìö¬Ae¡0w ^ ”utuâJ¨9Y»S¿„ª(Ã6|ðÑÑÓ< Hw{¹24™ÙûR)Óº‹a35sœ~$™Û.’%$Ë߃ ÊnñBR&ë‡ <ÐÒFXíôNC2‹¹Ã1 kÒbd¼Ó¦nmœô¥ùúP¤([B‹ Q¶ý“äÀÅ ²Ö‹@/ÖTÜyqP}Êé#"ðqc(c—h| ÆÞ[«šZ˜Q1œòÁ¦€Ʊð5ö–Áºnž&mÒ+ÎB6ñ62Ž=sÎ1 9X6rEQ7â'oWœgêUËu2ÁKݑރŒ„«&%†üÏK42D%Ç?ªÕ³ù<ñ-1>C¥¹•ަb›}–ù—ÂÏé(³/¬+’€€§Æx²l#vó¦Úô®Ø§Ü&™…è‚ ’bcÖרCŸ¶íV# þÌI5úpÍŒô¾óDö´|A’RäXÍë;Æ)ÞÅPÐ4ºçÕ©wÖnpË%žG¹“ùRÜìGƒ`·Þÿ´c+[ 3…N3\;«ÖZHª‰q½  SèåpÁ†Ða ¦9»C ›02àš†H8NшE1\âKATŽÚGbàpÕ[/¸±ú·û1Tk”on²c%Z{s5„ï–®è]e÷.ÈÜÖ”õgó³òcÝ:õ u4sh?g_’ ÀÐÏ-«^7ákJÆ.dœ4L~°ïËIÌ=“{¬•Ù8[-vÃóæŸ'+Te‰Ù¹ëÇ+IÏ`)»¤]  rÀ¢ºa5)SÝÐI:¦ÚZœÊÎhwüZº÷\¼ûˆMf)m럽1]ÔùGñ³õä.Þ*mΈ”a”Ÿ08ò«åP;(¥äªܢѩþ¿|þ|2º®Ã:®A8ŠÙÿí±xnW(%É„ºÃ7ÒŒŒÏ;ËDÊ:ž9î€Ú«C˜­Q| âêR4·.qÅ:MT‰ï|X3|kZ?´J¡ÍÕj2!x·ÃåâW˜©rŠñan:jõ«Wè$*àƒÍº|?'5“½—u)¢±À¾Áòˆ ;g‹àR‹‘»¨·YûKFϰ_6 ¯ˆãdËØÑ9Ö‰¾ UØ\íµ—"VñH˜Éqü°›ö½û&»’ÎÝ×mšó”ø«™t_…ú±³,xHe›ÉAe¢$hôsnò[|w.:Úã@“h™*]&wÙµ=HNŽÛ$«ótݧƒþÕ‘!žTc?–Ly;×Öù'ˆÓ‰R]šœsµ:Üã”@ú]D7oµSЮ®Ý§.þ“}*è,¾3~ú  å„iI?½|Oç &¸y=#¤=30$ØW ‹Èî7}?@’€€Á @ϤÈ҃஠FÝ6K&ºONùTòÿ­°o¸é,cbuZGŠ,ÖTjÀbq…§':ÂH2eòÏŽã|lÕ¥ËSŽðþ–Ù\gÜ ½­¬NÆ ¾Wñ^@•s ™Ú â’&Ó«Ü`äVÜ,¢~wasû­5ÍŠk;Ÿà-<&‡Ê©¯ØhjSBy»Ù(®—äteDà&˜à5yÉÛl6Vä ÕABPé4öIÙ>#=/û'Ôó(±îbóŒ´<ô*!ƒúµ‡]0ÖYŽÇ×ygu™q¦RSõR[v¥ëøé]-)l§qÛ@v€…ZX«`jůûÁï…Ç”Xô‹h¢} ç´I< GXT›Œ!Ä÷¶JAQí¯¹ô bW1èK4¨"¦ˆ‰® ÐNXT³tX1;»?:|LüÑ´oLèNº=K Sê¹ì¾Ü  ƒëü¯;z^Ðq˜'€ðRJ€~{µygU«ùÓàÞŒ¾,!^KøGÕžâƒ™ÚÆ´ÆR×HA³ì†m×gaÝÓ†u ¸kÏ‹¡Ó$\Gò‰ òÃÙ&?ô³2•< 0v£&’ËÞœ¶QŒ¬(4 Ù%áôºª«Ë,ü¨!SA0ȶõ­ ¿h±S¼Ò¥èuˆ¶ yqÇaæ³YòÏm©æþ¾w¨Ö¯pK¿ò¹Ú*µm,G_›³u0EnMã½/k{s82¶>€Ýyxà&†é R j?¼7þA“S.æL¤NÌc’®A´< üIóeCV€õ¶ZªI‹e 8Îbœ/®VßÇùuboXH èè%Õ[”“íf"¶Õ]Õ4¨YÞ=0Ë}ì€F׃] y/¤«–m­o:ýN/H½V·´j¾Ù1µßóGô'¥*%±JѬîŠ)ü©……“2vîbn˜Í®+™a{OÞmøyhG‘8œ=ù*Ì*¯÷Ò€UÉ5¨˜¬TŒyIz„¸Ûÿ`ð‰fÖ7uS/„™þ½9[v²™‡=ž©ÄùÝÖMë¼wt*(f–H¡¦‡žEã_µ·ñð9é¿Ę7™{F’÷AƒCbÅA¯€µÜêz{- /Mûç‚;Í¥æé.¶|;ÓÕá ˆ“ XR}šâu¶_’€€Î`ÑÍ×îÂ2Á’zŒ,Òã—ü[íœ<” NîΩÀ:Ǿäb\”°ÆpÀCª ýÞÍΪ}ÐÍ‹ˆ÷«{öüI â´Éaßü’›²¡‘ÉõÌmj2s‰y8Xì‚S¦°É†ÁP ˜ùz1ÌÔüÂ=7ð©R´Äå~¢è­é_¾améØQ^A8©›r g«„ËTÍðïŒÔ^ ¯õWQ ÁÍ’pþC–yULj°+?/d0láÂïe.iöïòF•ðη2ë'Áæ0‘Y#œöecå?J¨ZI“ì1û/½ð}ÅœàeƒGñ¦cøæ ç Š4ŽB¦½HtÛYi¦Ë¼£'±ÕM»Ùz³ð?¹Ï¢ ö?Îóðªs¤«ªãr}Ô:LJ´Ã%Ûk_SPì5Ôx!²w­J6fã×ÇlÛŠ‹¸ÁïX!Mg9óþ“s; V´œ¹ö¶=×Á!|gê€è%—+_š>ä"ÂÔ_<™Í¬jåF Ð6V`j0y7í{X#ï ^‘U8Ž—'ˆˆD• Þ‚ŒÍj„˜Â/>tzi½°ˆØ%˜ˆ ¨¡\fØgÖvƒ3‡œI*¥ ²Ãšhªº¼.©zü1è1$‹$c‡šš¶éc%o/m&$6vð,ëbK÷½ìG~”0Õé­o;4p:Ó"a.j¼C‘÷µãÅŽ¦ëËmuJÛ P[±žˆÆ†Ë]q“?S˜5íõ¼Éæ°&õü¢ûY = HDîÁ<`²ã¥Ç–·…š¯½ò|=/âÈ‚v²ãd„ïÕ"\~Ú¹+8fžC‰aÝY޽c~D6Tp9rë²õ«¥yÜ{Ͱ=Ñ|SäÖ¢Fk;¦¬°ÒþTGÇ—:5þÄ™á"ö¥Žm”ð¯¡N² zbÎÕ#ÞðöBVƒ<“„µÈ¦DÏ}â‡aàŽÜ3—PÙÖ<©mJ¦qåÅ[€¡¦Ðð˜Déw?ìQÿ~›+ÍY WY³J|Úm3Ži¨©©¥¿œ&"^Ê%ª÷Ö FÉ ÓéÈŠÂãBÛ/x÷Å8­ðLÏOƒpÉé o7¦ Þi’ÿï–/*rΪŸMgõ¸¡‹Ïiù\ÄŸÕ’€€µˆ¨".oÐ;>—ÒN™>Jí! uÀ̤lÎÐ벫7émÍ¡@€|îþª• +üaøÅ«GcÖs`¼[Ú\¯2)Ðao—qÍWÔ¨:1ÃN°yŸŠXÓxÍ ¥yäÚIëC¥KVfQ¨äj”°©8è÷u¸b­Žq«)ü¾@c–Å}œ÷Änʲüm/ÚÄ*Nlœ„ä¡åÀ‹Á¦µo»!Ö„$¸ïtÐLª’¶^„ 5Àô­ÚO±ìa.\§>Þ´oÐÚŽpVjG…÷ìn°#»ôרÇyP"ɵ#¥jžvIÝù*ÁÁL‘ý«ÿ·ð³àû Œ–‹1V…ã²gûüàù™CÝHV¹8P‡ø0"G­²›Bùšv"Þ‚·  C I[ƒëËÛ“Ý„¬Œ4Ç߯$êS\޵’ ­'¼NŽvlÏ^»`èש֗Þð„ë®?FšsS NùïòÍ10Ö} ¬‹æM*=jÞ°pORO¬Ÿ{òº®òRÇæЖä4„õ”8EMp“žŒçòS1Q΀Êá§® Â1²"ëÿ…§Jm6óÎýXM™]®pI^Œ ønOOKïwˆÓ|pïæØ¼½‹jz6z9Û`eª12[—M&ùùm±ž2wî*îáㄘ‹ë úg©+6l€‰Iœ—ã­¦‹‡lz¯pàQAl7ZÎT†ÏqKNT ý“y]Ÿ@›œ¨×\º2ë6ub´~Ð(rF«2”†@ºó°Çóù‘]À›¨·®þûÄ›¤ xƒ‰«¶Fv‹fÓ ø«ûi‘¿}‚Pz0ÕÌBa3ã @¥:¨³q`µþñS[úÀÂî£Âœ«Î鼿€É/óá¶ë/¿F)Wÿ|Û®°.ͪ–´Ku׋GLŠò« `,öÀO1£±ç­M7þlfZ2Üy$­`Äç`÷xJ}Cw2…'dÝv>x$Ò#w(„“ΈÅ2`„nC/ꘄãîƒé8+›røgÈoó…ø^&#¨!œ:·QŸÄ­“B¡²°&ÜøàÑÉ…Œ¡®ÜGKûæôùSÌFê÷›,Ñýã~mê„õ‰,AÇ\³C7Ô}Ù 3™a•ôò–³M;dzß^›Lû ò«’KØbÉI2’€€Þ3awO¥äéósYÑ;B`;Ay\Ò¸z8›Jªþ†l ä@•r¢¤ªvLº¸·_4ÛMgè”+X‡aT`kf‰Þ3ñµÀò*¼i—Á1^¿'Ãj¬{†q{í{ÚqOÍÁ"æø¹$£ô¶—KßÍp+E¢‚»ÀÞåÁ‘¹“jýd‚oÙò’Œ¢ØÛjò9+Ì;ß&Õ0wy•È à@K}£ŒÊef«·1ot\Í4¸®}G[¥óòá²I]"—o}óõÝi ˜Î[ïŸ$Á°oo ²)Ù¼tö{gKµâa0â$Érkw|™AJï|E–¹õ‰Qh=´{‚ò% †Žk‹,F\²Ã‹4|DÅÿ]Fت€ßBÊVRÏ Q]&@>±¹FóZ¢Mšûç5^ǽ Ñú» r·ô·ÿ¦£zã[^G]0—‘X«Ð„T&šoÏ™IºÉj][>áªÛˆ*X´–úº%&š)e†UÅ?qÓÞÍ–W`;á*ࢹ-ÙNj{Ý>ÐqjÆ2vÐŽçŦc˜ÝIÑÁKaFãdš–Z^¦¡5] ƒL=×°•wFsñà¶®Þ£/…‰ZìàH¶¦Ä1+a·fÆI¡ ßÕ4N„‰SR¢Œù/¯³ñÃvÂ$öûvóõyâmQê ,ÛWËü(@ª‰;"Zœ0%Û}ý«W°s0É$†áQo €Ć1R'À#~H'šÏ޹Õêº3ÔÄ ÖâñZ(*ÙC¾¢ >’DAîzú©ÉXt™n8,•Äñ^ #~ç̧‘`JÂ'W…÷çº  Ú±bν“òË|4rÓÍ8Á"q––õ»ÉØÊ¢ˆn 8­B#§ÓÙ¾–‡÷G`mRîÙ½ý]+ÎpóѤñpßèŒëv,_ó¸‹ß)ÖÈ]ŸƒÑç嬬7…öX­ÛBÐ]Jɸ8̬;¡¼|ÿ#IíS ³P£†}âùâ-é–j‘Ã0)zû8×tx®Ë1²Q«^9^‚#Ó¾#0ûæGÕ¼ƒ>[è?]6u„Xðñ~,ÁpàÄEÐJ"ÞÐÿ…~‘ýd³:ÓpæR@až$ÄIÄ4Ñ<îk•笼(‡ ‘tô^kB¿Çà²Ã]M 8’€€¿ˆäį¢Á$÷e¬).ÊÖ!„¯Òù@\×§÷÷XÈÏÅyë"„A0¶™æµ™ÉEÀÓF.D¼ÂõÆV}ŠÀÏp«Ñê}€kƒÙÅ4!›Ýe¦ñâ…¥¿C¿ùX"jìnæ'ZÞ^ë2˜©å?¥ôáUœ|ͳ;d…*dkuðÝcW”†(Oû=ÙTÚPË+ÿPGÑ¢4q”ºg÷ò?“¾eìü±ê`LðD·™¾ùÕñ&Z/¿ÚzKï@Z貘L™ð§Æ:Ì’³`yߊ²UTj`èuC~'çwgcÌÏÔé)»fÒ(‘¨·N wø-˼"–ôïðtôj²üO8¨J‘fåD@ðwðjÏ¡1'+‡øÐ|5Å!£Ðª6[…Q5 &ˆ¥ãæ'Þ/+Ïez?· #½pŠe±®Ë|ôØ÷/ ´º’ª{ 9 >SÇ ‘$Ù±ÜKdù™j©Žp˜—7¸IÙrã­ì§Êô¡ùdøß>;¬5Š&l°V·N*¥]ª/½Û×€ìX7@ù7TXºÄj¯€s‚¹+7…ë©çÊb7¢Ì4rÕìpÜÔ*(œ›ŠƒLÀüh7RQ?ðVùäôt>ÁÆíÍPáOy~D­e2ºíüÀ~À•T9ƒ#'†r”s•¶¿á] ²³úK­ð7êžrbJ ˜ˆñ½!E0ⱡx„ÂEÅýJ¦b>9ß’m?så1Ærñ0ÙsGÚá!#Çúç~Ô…­­=‰#“' °Gkj¤+°åñ½'‘œÞмˆNð°]†µËIXõ­„;j +ç€÷)ó‘*GµÚá«a2þ»‹ÿ›Ì1‘CËöÏO­¾Z¢eÞÕ¢s 'QÏÖ±U6\¦„FE'= À’B•ÎÈw«`¯¨§hÛgÍ!¯8Ûm€uèbEŸ £w°1¨ÎÿoÄyNVÝç[>48üü½Ä˜PÏ«¼’BNƒO—¼¤ ¶5%»)uAó]µù<_}ŠÇ‹_#›kÊ€)6ÞØj,ãK6tÛ¯Bu“%gÄÜÙZoü¤†º¿FÁG>aÄle½‰T$Tf„­R!„ƒ§D5V7È.¼W¦þ€MqË2û!a;]ÞÂæÕíAnéÃ{Œ1¦È2’!ó£6¶4†Î!>àùÌ’€€½«Ë|5/% z.’aÁÕÇ„ ¹§¤¼[· ?g“lëÓÑh4UióšŸÿÕG“Õ“[­hðžpk+e…â7Tâ½pl4~Œšc§€r‚µ©¤B!¶•ïÄ‘!xÓ0uñU•ZÞš÷å¹K§þSQíÆÁý­aÏæ†5ür`OiÔy^Ó5ÇÚº—R€d(ÏfäŒf‘=Ñû _EÎ40a‹:£rÛF3J•*—¥r¡ú7=QoçÄðVö_ÁjXï7¾UrDxœfxh%ÐÉ-ùK&Ά|ùj&•**0C<Ïn'¥sjvƒ-ÈÃÃÊ?&C2µ¼i'ù; €å9?ŠEb; ý>ðýÑZokwOÀ:N=1µj1$…Ú% ¥;šXz:®4e¶YºåÅ>§-¢Wg–è½nq ´/Jl/˜¾,_^€œ‚)Ax0î¢gÊÈ^õu§ßU06—¦ÛÇ bV¬ðý|<ÛÍû¼}X÷Í*´žBoYl#Ìv´pÇxþ±9Òå÷òð±phdÓ~7.gz´œÉ9Û f½;Òuól÷×/_@¾³·ëGeêÿrJ¿ÂwÿÚ,sA1ß±S+½A,ÄáVŠ#ÐDê§kXâr8QÙ/ªÀ™ÝOk UX§½S³´ô2Ròöé¶ÀÛÔ9ÄÓ ÊšŒ5g{…çî8ûUxg£¬˜«ŠÂ.B")­á’d¥óÙ_i²þÁuÈúžË?7ÔTÄþ»#RFù ·´[α =^]­†¡`¢)ú·FÂD¹y®ðÊò¹š-‡‰´œ~x=u¢êA/Ûg ½ ÃÄ™'~ŒO±YUôᢈF£Ê…ú$û ™3PÝÁY_=©øk ŸÖ¾«øÅ^sn>ðèr#©{à’•¦ MÎu½*Jo[½N/˜ŒãÏ8Ô‡·‡qTÝÌ” $ÛŸR%nÈ¥žBàcÓ#éÐ2ÏÃ6Ñ«Ûê”W¬c-Æ®œ4{åþÊ¿«Fš˜£Ë@ÝßQužæïÌ€Ö&«‡±]‘×ßÊ Ì¨™í’¦}@cL‘sdR𶀂M³–³OÐß–§Fé!ÕNÇf4ˆRljßý€û£û;«>˜•¬Î.A…¦ž/JQ¤§–Ó«zTÓeIÏFÐì´]Ç/€’€€ÐÁß¶öŠ víÄpºƒf:j­ߟ‚ÿêhAÄS}çÚ¯=$»^U4_@«4[Ç-hªNÊ?€ç-Tä|©èÞã缡JõIZ¿&+n9ÿôo÷EŘN_¸¾¤ §ÜŠ• ·}›Z05Æž÷û«7QŽ×v~¯¨y½ËvÛÓå“­è×Ýqß“IÿÑ_\ÃXGl9¦® ôƒö†wälPf£Wà-¦¶U8ÞxÄ5ýzD³øçsÌ+JDüÈDÛØHùúÂn×]©[|õtwÀ1Ú¼]:jáGåþÖó)v; !ýТ\…(-@V×ZlMe Ôª_4aŽÀ¤##"à•!I²ÍOfõbÈD‹°1»Š›nÓW‘|¨ëƳ¶å`Ès—¯x¼SUÒ ³©àƒ¦šÿã-«&=V§»÷…­ 0Mé]Iúõh¯ÐM¬/7Pímà ԣƩ¢ƒ?Õ*Í×>KòÕ¶¿‘¦«Ë“Y>öfKü{2ïææÿÓ|B}œÓFëíЗoƒÅPk"(“˜PLN{›mWÕÔäCÉ·†‚jäJXîŸ(NÍ“j «b÷=µæ'}¢’„bÃ%9ò]öÚAKAj¡žÅzÈö&dΊŠçu?~ÿ NÐ?cãPÖ6Ûú`eÏ)æóÈŒúoðÞ–åèB]‹Ã~>ªDÕ‰`6Q ‡;ÄhÎn±\t©$åû"[Œº$A,ÿF&j57âôâÈ!ÑMßED®2°ûáš›0¦æáèzÐÝI{ׯÇ×rïvÕÌ$Kµ’M(™ïJ*Þg–Orœ·WpJÙ‚þÕr,nàÝäëu!cuÑïcmp_Ÿ_²"Í&g€–in«çj~WÝRT7£Ïˆ',GT‡¬/eƒ½ýéPçÄTe9¢e€·(6&0¿¨Âço0T•zì] íy( ø¢½ GF @‰fâËAÌU|oÛ‡åÇ[{|N=U·nË¢§Ç%i!  …‘J^3ÂáRRd›G3nI6>KýS3Pa_Lu)”15¸ËÏ·OŒþ©”Ï+WÒ•ÕzÖHˆOºn#p„#;VÌ`g²ÒäïF)`Pöàû©ôïHâm3 ‘šuNòò¿f§›A|Ð-wÛÌîÏOöà^’€€¥-´ùŽòDD­‚õ_èvéA‚NŒ™Äk™²ÞÇyÑ[4+ì“§µ{cÅ“âoŒCh@Ôo,ÏzÈaÙzE ‘á’Èô‰—}Õ{Οœ5R‰5v¦4¼¸CA ¨ ›ùØ©íÔj•±VÓaø±oÑ+l¬gÈ"®.6Óþ" T#zÛz™aД‰^ö±ø·ô;²QwÅÎ ®0¿®•ï‹Ö!àÚ›zzª$æó<DsWlò6o:žäR|õv§ü10pÖïÙ_AÞ^bíµ¸Œkɾbç¯ßelÅÇNâøeRÜ×ç¨Ö–*[Qˆ’„#dÔçûèhsR^€ŸßãjŸºïÈ>Ò¬ù³OÈÓý êî–ØÐ3FlЉ„¤xX;MqY0ùc2*þP>}¦#TÈgï'I"ùnÕc¡ â)Nm JðSÃ74zœ܈¿§ˆR¯ˆy—ߨX¢’òã 0ÝüÏÝnø$³ß ¸›± :“Úˆ rT,S¸‡74RôÃ%Ù@N|™7—ZKÝt§Õw“øôõ3\ÉÕxŸ¡:T¿-qù$¶¦6_Y–h]kpŠïƒ› ±™+l@9euN1Ì¡ã &N›‚ÁjÕÏÌ‚=eÙf}¦—=_ vŠÅ»µLœå *» “×[Ý/k6\ºZ1Xç}*d/’¢[lZ3þŠ8%)dìJØÂ ÅÏ”=®“E o¶ 4aTç`ñðìdßJÐçDg›‰6dØ(qzÃu#”Þʇ¼óº¶- 9[3ô•Ë~R—ÚÑ}óY"àæ4&sÀµç(ñsœcõ½¶2ƒ60p—5‘{QøÚG6ö7xt宿kþ¼Æ¿«%ï~&UO-?©Ÿ!¶¬jŽ-áçS4ñ2p6£1A]^9æº3 Ânê¥ÌÍ[G/Êêá¶÷‚´eÕ&(Ø£x· íìxÒýk+Ý‘*OѱDØÌ%©ØÇfŒªœG?2±;go·põ‰ÜÇ!‹‡zpG¨`H8ð£mƒ8–é}ä4¹PêVÁȦ.ÕÝ:¥ 7, CX̬âê¾ 9y×9¯²•A„íËlf,i³ÂµÊG$Ÿ6v[)°CÇ»•­=´ÂÊeȨ%¶…våø¹)ß0;¥oõúES¤Ë½:¬ ÐI8¼b§DcHïb¢”¨¦U±C˜;×lŒÜêVéÀñWÑ&4Wà)ìõ‘Œ‰5˜%Ór‘•»w¼€ÝFÿ9˶å lFË%æWñQ‘,Ø&{Þ ¡”ýæ4­*kô¿& k0©p&iã ÿGáЊð”wfƒålhÊìlãSÂVù€é"ÂkSDμ#m‘1÷†ÀÓ²ží„·•å_e‡NJvŒb6 N}ÜW¤%*W:¤P‰‚KŸâ=º®Dû*³~+½±Á„£c™™¥9NÌdEÎIÿá‚ß´Øx‰ºÑ œ²^v70ûÕ\;g J¤$ÃøÌ6tpNô`HOw+Ü~bg3§¥†Ôܧ¬DZ(áÏC3E^Ÿ˜¨Œþõ©“¹¥4Ètƶ-¼^pÚS{7±sÀn½ˆ|F–46BÂHk°€f®åhIoªÔPü…–®ÌþÊ5ˆÁâ!_Ï‘l¡»FiÂRG¥ðˆŽ&Ø(pX]•¬Õ=¿ã3öe¼>„t|ì»k[»@À×'GvÍ{‚î§³°m×NCôÏ/Y±ƒ¥Ø1:z#4¹Òý/Ñ$ÝꕬۨæRø„²GûÁ^¬*}[$çV^M«Êó¶5%ÑÀRj¿ÞIÅ=„ÄOÈ8|l!iWôti,' šØÆ~ér=¬ï‡³ÿ“³r}ã£tq›¯™Z’‹[‚wî§XÅT©•ˆ*§¹ä]ÆËÎ í$1ñba¢5&a¥]‷†»F8ËKú7M›EM€úYXÃ4Ôþã¢×þ⎪æEʉb4y:#Þ \Q’+ÿÿ¾ÿÒ˹+óþ/r€zv)©‚^/ÖY”¿z©€^Ìžd(ÅñÆ_P­iØ®_\ã„l. Ô±:CŠ[¸O­á¾‡þ²ZíJ´ý¾ ½‘~«ÐäGJøßƒp¬¾åÀÌ;„:×鱦ç>»ýEŒ<ª3’€€Ä¿v[j¢ŽbÃè#÷ µÄ¸aÅtÉ«ÄÄ?—/âryìzw+”‹.T™ReÏû¦x…Ë,9™Ö[QŸ]liÊ?xsv\BéÏ}¼‹PÛó<¾¥C¾ÐD·Ó¤\q09‰¶ºašf–柘– °¶¹ÊøÀH$#'—oúÌ2ê&åÀȬÒì·i¸R´õ%µDjC*¨£MíøùSieÎQ{h«åºâÎèpò1^=g%}=–È~ôÜýkkÌéÝ•üµiµñ{µx’ãm5ü„fÜ×ù?dÅJo‹ùæ£ÐƉ0AŒ,ZMïXÌÞgÎt‹ ¢×Q¡@N„Q­P±¶‘š3 ­ö•Ð7ÜídÇ”ûit'EXØ}î©…”·Ù¤,•¹P&l32á¤Þq䵕_róš9L–+lö£Qf¸ôMÜ«€<Æ…i%%v߬¤Í!4ìåúû8¼k›šèÃhÉGóŽm‡o*t£Ò³…x8…2OH®iÙfË7OÈ®Š,4/ Bõ–ö”3s'/lÓÙ=ÀŠUiÁCÞcçQkl(IB¸j Yó±Û¨’Üí¶Ÿ°uÚ|(èr%‘Ä7ú»ØFê.Þ$ŠLj/Jn ºž²ª(î@øDû»0tNJÐRÊß$^I*Ï0wÄÁQì˜=œXÏ.IÆÚ®­XÛ?Ì¿œoƒ À"`´˲Èÿë¶N£ßÅ lEÓV︂Ãä—2HUö¡çžƒøïo.ʇX[ÄTäÇž]ßž5¥Ü04ô¨\ ñÚmk¾•M¹ÖTž›™n#6Y ½kbïÙ}ØswœÏ¡þ‚Àå_Õ[°O!yûP»9\¦]å\§‹Ùoe o%Ä3Éï½mÓÇ€ÚxÝ¿Öáò«ßÚy"w6¼â½«h»ê?D59)KÙnM#à®"qõ"¢ ™›Y[t¨ê''$‡Qc“' ) 2½7{ 9Äeɧöz³ºÒO¤Àf7rÎÜÙiÐ[ð—(ÿJÖÈ]—Ãì žâÂr·VN¡¢ÆM?ù¨öÿ"œžH´éö_“ñÐe3µE“\„"Ôœ3 |orœç²Ú먊YµÑÙ—22ñ.y}2?CÊ|GÎ>N³ ÿï×O†â±%™_™­d•ŸÐ½QW>{‹S ãœ.á–”¬Ÿ»¾Š’€€›èû,b€˜ŒŒâñ/¡ÅdØ· 6þõõÓm Þj·Q¼ƒŽb!íís±/¶ybѿֳ4‰@zàˆÁxñ€µ7Qƒjª î‚IÕÁ ª¤ËðÓ”w/)?\ð„¥*?²Ô‰`ä:Á“˜èÒ¬r¤øzáÀ ò“· ©ïØ\›ÍTöI ™nL¨­´/±» ýýuÄÕ±9Q<ÇZýyÿâ/Ã¥¤†º,ùk^Ç7\òD2ÖËôô çy˜à‹M…•ls}yå±1µ›uÃí²ºA<yç¥h!ù^è2sÞ{ô3Y}†˜¼§ÇÎÍÁp¨õ‹ïÖFvãðÝר18ù ž>„ÄÑrq˜\3øhì‘>Ó‡¶Ü„µ1¡X8Ëà£Ë \‰XäZ ṓ•õà„›Šäã$.{4Ê; Uje ÌüñYÖç:2ÎÙPFr0w¦\}ׯÞ>D]Ê 7ã<ù ›óûýU^káRÑ>çñàÉCZƒôiÄKj1cu õ7U²&¨ÏÇ9—0)<œ¿’\gƹÊèw¹1:š+ohA> ³„Pöïï²eã ûg‡tyM µË“Î¥#ŠÇTjÉV\7ÀÏSo–˜‰® ,žOKnö¸Ï+ÊÎ/зìŽ\ÂûÈCG¤5½ðá`p7us®[K6½ßT§S|/ú ×òö )ÙSl@ß>£žVŒ¾£ï(/ð©  6ÁŸ®ùƒ*i'Ë”> zÁÓO!àjˆ¼24t'>Rú“ÃOH±Æ‰uìYºù’©Wc¶ŠÊ– !=ħžSö“ŠßFÉbé@>·¬Áò¯.{{€½JÆ©ù%èÑ(gFsS»ük@D¿_ÿ;T4¬Ó`øÆÚñ¥»`®€­ cÅ`Œ#ÐÈþ2´ó6úQ'ݾûGÎ~¦é ÇÑòuÐc@aníƒ ÷N¾+P\-Ù%Ng½æj-ñ—B)ð¥J è›bÙù¬iˆn‚Óž óï+:Cž¬ÕæÌÔæél!Àë}x…ÂôG%>ôñfQiƒX´1|Dûù|Zå=¦å¸s]01¬x[çÉC],6lı~J¬‚ÃàÆO œqƒ´‰æÚ³÷ÆÅý•1G©’€€ÎʯÝóêÛ¥ûêÀ\RmBÊÅI÷ž÷)ŸsL6B [¾lª(wi°Jée_»±‚Ìž¾ƒMS‡[{]µ\mB'Ê,–:v”&™ª± ¶‡wG<‘%ñá=FÈÌðö^ï}@’ è^6jëÑngÝ’ëT‹MfP©r*Ê3Þk¯ƒ¾ä"«µ‘¡ åØ@Æ_o‰¤3Ë·H'}‰òëS[˜ÄÑ2%BÔ±ÈçPŽ hýù,\¸‘Єö÷'FœKèˆ|¾$ä.&ËÓƒì[±Ø¥ß‚•­0½ÖŽ·[Ïú–c,!´y ÓºÔësÕâ_«{Þ#˺ VÂkÌ¿?ôz=ƒƒ¨ÄŸ¶;Æ?l¿Î5£v¯ u›A;SC¡¶¯²±ÑÑóÑ‘3õÃÉFÀ[˜Õ*zZH(ÔÿùÏfZfˆ_†K1$à×z‘³KÏQR.ü îTS ˜SÄD¡GrèîŽÐ?ªQR!‰ÅYw”… j«›íFƒú‰ A«'dPèj"uè´´oæEMÅÒž¦CTJ׹á׸Ñø噄–„³ý÷+vÁ¿ >›÷\¶+2–n1” bÊ4˼ª<Ÿî >4áã ³&+B}Όٛ\-m)9ËWÌÿ™84P¢KpCrÈ!>ÉÉîNÔ-[!øË´êñ 9Aòâ.ëÓÞص*÷`'}ÓõšÍUK°Õ¥mÒͤ˧hŠžÄ˜ò9~6äªBµO¸§Oþ’þŒ¯ËW!žâTˆQY4j#)çË °,m²ÐutÔÞüé,™ŸÝ{J4 `Ì„cÙ;wšÁ(ð¥µþe£˜ö•¼n[)d/ûÙõšÊ—-)õzñúSP•|-nx²0hçãI2ÛT¡WŸuœmØtq¡äÊl0CCÌN‡ºªš´´à™=Œüc*mºã~À½Üx‰Ðd÷‰G¼K™Ô9äÇVÅリŽw’ÏSoõUß¶ˆ6¯fk2+ÓÁªaHwEÑ”ÁŸÁ‡v\3¡sl§Ò°Ç„O•õΟ¹ˆ”>& ÃÊaëý>°Ü"H„¦€¸•®ÕJrìŠ)9-"œ‡Û=ók:›Æh–ü+Ö™‰äEÏ]uퟃçœH)àÇí`«Êý¿!‘‚kPFç;Ò-÷)†ƒHâ Yÿ ì¤ â-U3ªjÜÛ’€€¢ƒæs±æ$Õ“Å?úÀDÒÕ‚ÙdYÐúàÞðøÎøˆ×¥ºmÍŤê>™ÄK"æ ¸ÁÍCT¸år*î-ÉæÛ&›œ¤N…uƵXó쬄M¨ʾ¶#<å‘ÇD`Rhð}“ÊÅæ7&±ÿ÷4w¸/Bƒ—‰ÃwpMI8ÊìYAÓf¿&!†óàÛû .ö0êyœŸRàØ l¼.Mß”Öô˜±»æ¢ÝMvûT=&q>DÔ\©IiñŽŽ‹p‹ø¦‡]±‚:ã{CP àÏ»V˜ÎWƒÚÓ(l}ƒ³½–„`£–_ yØé˜‹¬ÍGëòõ7¸ž‘å¦ K¶_SeUùÆ*·À¿ÈÃi£Ï!·39¯êœTÙQ÷q߯ À‹À!Glu´Öó Å»wÌ‘#nÍäˆØy¸g ’I|‡zÔ0ÇgøCÞŠÃò½õaÖMÓ#/ /¡Öä{ÕÜÈ«j•PMFÀÉüž¢§¾’U†$7ß´ [?©MÑŒI$LÇŽ-‚C‹TÄ–sê׿ì€%ð4Ås[xb‚€lÂèYßã^ÍØws Å¢¯¸ö?ýãü‹!G–Ø-‰FïÀßÀ6‰í4â9ð˜®@¦Àµ ~¶ /ã s8SÓ; Ø(N¿qh¦‘×só·6£IFŽeÞ?Å“I¡-’sgÿ(¸Xbp‹©#Î9¢~ÀC›û¶Û[ü"YžßB·¨N—‘PغBO8+2ÉÐ¥›1)îvÁ)L_¢{ó§ï¡¢×å-ÏàNåÕ ïzbs¡<¡Bе˜¼(š›n*ð‚phµNM£jÀÁ†¹Ð:}3W#Ñ[e#äùã\‡Çg*ˆÑ…±ÿk$º4N³NmÜ} ±(oŠÜ x´<ƒ ž*ŽZ@(Ç“mÌ­gˆoA¡½ÙŽ6¤æ'ží{úŽÓÃþWT&” ­ÐuF€Ô‚•‹~[õ#^ Ž<ðôã|¬ì}Ñ®é•fÇhDß°8­ìdh4Š )Ûyž©RI·_®{'+¡œwbšã:p킃RW¹¡†=q Ì!/UöhuÁPÐ.vX Àø=òºz´Â)‡HÙæ©m‹‡Y×v_4*J®@ü³³”N{Mò¾Óûý˜[õNnùQf´é1¬’€€·à¢A³ªFÎ ã=fÔˆMB¿‚åMó轨â†âÿd:3Ñʦ%’dW“‘ýœß \Õo© “I98î»ö(’i1RïPñÈs«8¥ø4ô²É zKª s¨ ^{ñ¸øõáÿæCeN¾OKu0#Ä ` µOÜ/-Ñé­FZcÀ …3ÑŒqCÑ-)r€¯òÿî í¥sªþz¶ˆ>R°1W˜[iâg쪳˜ôÔU†\BðíK#=_LšœD^PÕôí"´îq‰UþDeÜ9oWY]Ï!Ý›nIÒG–ݶ Ò³~À‡€›LÛfXÀÙå4@µRÔ]Oü bPÙNP¯žŠ¶ý0"¦§ 8>¥âߎ1†;Å;¦™0WËÛØ–wÈ^N„´ó2IÄ!åÞÅEùãr‡­K6s»Ît…sT$¬}HÖÒåsÝ´ÆLrž1ÿ©NyªTqÓÊÐÿ@ýjÊ«ˆ3žÌâEâ’¶NiæpZó¡v¦^Ñ=_bð%|è¨a²Ð7Ù?Š%÷R¥½Üf;æ°"7)ºµ©>„Åìehp{<±Cs‰ —= ñUêCÓ\°@N[»y-cÖ£î¸áœÒ“îÐ'¦¤’ÅC)Rl„®Àüeо-ô„„™ô;ŽýG~3øK+Èxzчð®¯àaÍ¿W·Ý¡Ø`8‰Þn)¸ÕÑË0¶Ø’Õº?iÐéTRׄnƒTc ïõ¦À?.Û(ëûà îq±÷ Ïp¦Q $L¯(¾Àl{Â55¦Aãµ¹lZ¼ŽUºÅý\Æ@Oo¿'×Có|_ö) jNÌæ¹øü9š­(kQ•’Q†$éËÝ’ÝY•íÕ½c°¨Óoúmj°·ØY¾üÿ»Íšd‘¿¾o’•†‰e³>Jš§ž•å…À]Ë•ÄÄzÊc5R¤ÉýŸº&É $;ÐK(•¸)µâ à\žiÐóÛÖ»%ßÝD¦y8Ù_±Ç%Ž­d!Oã ‡Š;2 ¼ý›–ºË–O©R>.&(gb9›\"@„pÍìoqoLŸw×ÐRá/E ü|„|º©>%[J_;n’€€·°¿gÎIÒUŸþ×05ÊÊÐ ƒ&ÉX›wRç¼à»ûgóÃ1ƒ*Aàƒ<·S»V¾EŽ?‹Cõ’KXG;îF•O”üxwR rZõR-ëEnæçþ¨ü ûCœ4ZÛ´Hö†æ+!MÕ÷]ý®Nµ{Èä¹kÄ¿ߣþ5zÌš¶ùcÒRJÔ’ðYL@†UÜTd_&=ûmA‰‚CJc¤,xï]Ö³Ù…Kc×0¡̶1Cžœv†-KãX¥[Nõô˜'¾ŒÄÄHç R•>áûiWù`s¼Z¢PÛú{”â>æ0W,ëüITfj•¾1J°õ,ŸKi¸£PÏ^–±МÀC¿]ÀE™=§qæðfÇ›ý¾š'÷› àMn{DŸ† <™ÇÌŽÕ»5$¤“.Z¹=†I©Rþ™cw¶j¹Rlº 6|÷Þ4Ü=X½³ûÌÔëZ@×niÍ@fºZ¬Ô‰'§Ë88‡…i<Ê–Vu)Ù„¡È‡#m«Ã·ß´Q_Ãg' Õ^¼ªRÿf/^ÊùA‡?Ý?EнæÍ‹r~k*æíŠýÄ {ͯû¯ßxM3ÂÞ4 ä\¿‘ Sø€î)Lj“Z‚DÍÝbe‚;ÂBl"špge°['Mð[ëÍæ²6Þ¿—úö£' ®uÃßçÉÍ EY‰²¯*î;Qº¼}W ¬6³t@*“yªk3ÉšKå)–Ò¹ƒ0½ì0@®ocíдN«ïË *)ÇÅ)“¡`R0‚Ñû$EiÕºì¸O“úJJ8áöB5hèEhkJÇÇòãÇl:ÚUQAˆpÌœI»º»=sªò<ÓÐ=) ÒßV¦Ubwɱ7þoî\=5²÷oDzï´"ìAhl /ÛÊ—°âÐö÷à6y *g ±á ,¯ ²‚§x,Ún ÔH5õwßÙþ }4ÐÜžÚú[¢¶Ý×ÇÛ“J@WÉà œ£w2tbÓ«ªÁÜNç>‚BÆ.Òb}%]çì[»º6rKµ{P( „,w†M[7Õ› ušëÆfêîÞï‡Ås-4b‡O”Fƒ¶êõl¡Ê“’EóŠoöBziªˆìl/®ê´ããÊùXàÂ<¹¶žÉ”q’€€®²ÈÀ@>>qôÀºŽ6…~ H ¿¨47Ó1’ì»KãÁ…É4b=§£Ø‘š 1ÇØ\¨ ùŠåà s£Žý KB¦_SÒÔë¹²MÀ ¡ÄC?(§ÂéxÎþó0¼ÝZõ†¦÷ŦْڄgùÛMàpW.”Km"z‹}beL1øC†ŸÉ6ÝÊ ÃŠK2T‰÷»<Ç—[âA–Í3 Ò‹Yü¤ñÖ«Çz{{2¢}—[&CÍ Ù>» ͧi6Òp­«²›Wæ·uz¡ZôŸ>‹G/ØÔ39 “§úˆ/¥T)Þ¢‰Û0¡äU@InÈ…õ“u‚b³”ôcÛJ kÿDþã´u n?‚«Þ‹kö§F4ó &t„·pP‹¶ßíM><¶»<:#f°÷«•[6áòM Läo%°ûvÿËð'D1îCN" j¸˜oŠøÎ£n¦Å Óï „Æœ–¦€í€¦œù‚ Þ[5>"Z0`—ìúÊa5e¾ÆO|:ª$>9øÛ÷ƒkg‘~‹î Š}Ñ,·Ì&Rë?à±?;PS68Ç¢²ã ±ç:䤛aà4°0«5a`Âl¶%£ãåýÄbåUköoÈÁPæSybJ³]gö¡¡Ž†Êè)9Úz8š|ô(•ÝÁ!hÖˆ¤:»v~VÙÜØ…]meÁK ´€³›§Ñ äÈ-òšºštaqDÆ' ‡ù8*Ý©UO¤dà =„#󺈎hP¨EM%š;±ZY Ü’ÙAu»mu‘®7ûS‚5ª‡[—@ò„@y¸µ9C¹ÉUrý£%ƒçª®Œ>"Tú—@Í™ÊÁ*UÅô­Y=4€yÕç•MÝ‘Dˆ†ç 1š=åª|×êaƒé´ÇGÙ¿)gÙfŠ2H0]ý_`_=XZÓé7p¢À÷³^\®*º£§t[Ù}Ýy.®6à‰[ºµ0v‰º“%)XQEHy«j…™…âÌwCVÏ«W¨âI04t ])¶^ÑD~QE”LyJ”‹•²²¬‰álXu×ñìe¹3QäLPÖÎÖàp±ø‚kkä ‡"ôË€;f©:¸ö:¢‚’+šà‹NPaŒÉsþdhuŠ—D|^’+ú1#ê†ÉË);ùsÇ‡Ö ÏÃÙ{Ç‘®’€€¯E`L…|‡1p×zêÇæOõ”*ã[= `¾ÇÍd 9…zI ý‡|Ç5°z•"%EÝö”ñ¼/ ˆ=vxSHìõ)Ö`7©?åCÎi‰èŸ=M½}¼z.Ä‚ù@c' ŽjååÍwþÄ_è4?Gçî·”¤$4ÝeD_åðY. ¨€!\cbRb…ªÞß§Ÿ<ó½k¦„òúªeЦ^*ÃykñQl´*n'"îzBYðÅË+MŸo ÃŒÃ<ôˆ{ý] ò;|¦¢FDEÍpíW•æ¬Â»<-µº¹\WóWPÖ:ùÏ܆G1…Þ…¹u)ŠIµúæ{*ÖgÛ€xÙ$À+´Jo%•ƒå— G”5G€LJ&¯ê˜c¿Ç¯öíLîVNôeûPx«–Qe6\¹NiHÖÅEﺕ ¼DøêÈ®4r>Mþ…ð'µ-ë‡l€µX»’€€ÖÁoR{B¶ Üá4‚œ:o (¸!‘‡ß øájeæ¢ÐïD±ÚþœŸÙÇJº’ó—Ôzc^ÜÝë‹«gA (bƒ_·–lꨣÛiö·ÀMŸjÒ7Ph’úõmª+öøEOTd³žI²¸¯h«Ø™ç®VFŒ%ÕôBä‘߉ª Nô4òz2 ]ù¹:×Z€ãjÄZ°£Ä¾xzwâ “Ä_ß-UÉÉt‹ê¼Uöð‹–zït׈»`}Ô| óÜ•Leå:ɬÛéíø*0‹‡J vR±œ1O-0µù™×q!ç&Ê}³F""ÿ¿oÇ8à¿RdŸN!„£üÔ§¥ÑÚ^‡&Õ¹”ÊuÌÚE±è}Ö…² lân_üyû€}}Õ ýL~¦òš°.Cç&a!ø&q†xG³H-`¶ýš>d}e¶'ìP ¯»Ë{¸lÄé¾älj“¤ÉŒdx/ øN¤øóm VN½ÆÌ¬qYf¥|#C²8ï]t:7š|[g·œé q“IÜT’ÐW>œv?F×þ“Ühã’ÞE0ðeé—õŸÆ²¢ÉB´!ˆVaDÐÅÂì9w·Ó~A3EXÎc` 9(¼¡9 ?iSš+ÿ%qûª1ï( ’+ÍÉz«#¾¨ÈÞ¢9 ¿ÂQ2Ã:(õiS$Ðõx´ºWŠ!¸lD«4G`áF¢~­“g69~ý±y÷%ó¶KžŽ %X"ÌÆ,å‚Ú{Rˆ¾÷VÕ•»Ôùíãjh‡Þå.€Ê¶§)Z…ˆ, ‹™Ü¤YDÏÚty¾  N¼¸, ¾gþ"o‘Í–Fêò³&¿û„¡³ïK.©cd®­Ä9+ ¸Í~Ù%‘ x‹wŽÿÑör ¬Þ_ºfJSó1ôŠÄ·¿ça×v«üLjX1©ÎMÈ»Ê)ƒbM—n~` ê%Я ;7,’÷/w1½û¬7ÌÜÝ–‹R6·ø‚J\ xÌSýåÇb¬»•‘G¢Ê«!œU#ÛJ~"´èÝbÉÄYgómvv×F8î^¤Sý J¡äþ A<$ÿH¤öô†²Ýe”°Òú_·‡â7(¸:Â3º Oh[™€ÞMŠÝ × †þ?–’€€×f‘véã[°‘n¹L˜úA¨·ÎD¾ }Û¾iA³±Ê:S,'{ãGf !±kžjs¢¶øÄ@ø6+FõO ^Óì[ô¼…šL߉­€*'‹<«AIÎîð­¬i«è)Û]û%pýÕ´VªP¾àe¿¦¹è'5ˆü"ˆnráÔ×ø!àôœû˜ï!.}àäÓµ½–}³»÷2hîpè?§ž“}’kV¸e¶ÆÑ½Š·â¯K³{.˜áâåî.ó)=CfN­B;nûDOu<~Í`ía(·(ÞuŸ*'Spõ0(UÕ‘øÍ¸äÁø¹ÉQ·ØkÌ}–€êÔ[pWTîa !ß/þjôú6ÎH=y’¤ìJbî“|5(×}”çím ¤‘µ1WJ!…l-ã¹üˆ}8’Á †÷ÏS›øW¶Y.†¼šÙ› s©;"yÖ*¥„z2ï‰bŽ}ÍYiVØ)´ ¥Ð²ƒz…H”M¨]Í4BñöX•™¯8!Û2,aUsòŠî[þA†q¢¿ríVÑÈ€ï5|ùPø¢´ÚÕye¦\ž -L{¸¤ºx}Í„¼Æ/é ŒÍÚå”À4ÕØ—Þz‰yˆäJ Ä-1lç“ìzë  Ó|ýÈY½çßòâ{ɰüÙj#u2[Y¨Ñ6d·U¾òÁ=¨—Ú¬,ÞåŸ k$ÈVåW/§1ˆ›Ú5©°|Ї¡(’q¤Dxþ‡ºíå«àJhÙþ±ôìï8FÙ$y‚XîøO¹²Ãß»<¾Ó{ÁOC¼DÂñø±ƒl×6]P·ã(S?S Þ»r¹µëgƒR›¦,ÿ+,ö‚ÞøDÒ[œ¦j%i\®pâbÆ<¿n4Û„ÚÏ#ËùÉ÷ñ«'M:ÉŠU{FJ4@i2㣔Z“½§öÞ(FCqXmÀ€÷F\†ëýwžmê!O‚0¡ÉKþÿ¿B›"ÉG/›?mÖ†I „FTsÉ:¿ª;×Û«CôL""ª‘ÇSâ@Wf”A%…8(Þ-f%¾Ê‹3cîp×y Ô^ø²£°µÞïÆÊ8»by×ð¯MÔ˜¦ïïcÔ`z¸4'sJú›¬èè[ŒOBZ˜oÎëÊÒÿÈÂ’€€¸pzÐÑ´MGdÞ‚+f<¬PT`þLz–Ñl,Çg@Ô|JL—hž0ì¥1<§ÐMÑhúä¢!/á)Y K!袠á¸P¶ûØ}yöðvÓ<ûíÅÌù‡Ø;ÕÚx”]¸B±«öÂî½PàT`µNš‰q–!d±žXIyp’‹+nýêž?‰Â)7>àãÆð™f±)â`->˜FBf¿.ë¦Ðâ±Ö:©&_Ð`õ8ã¹m·þ«óz¢Ò–Ô¾*R†ãyFPC ¿«§œ^sÛýv½¨u™EçäI‘·…F¥¡šÜ½Šmï83è{´WQ¡º°´÷Ü1¾ ³’°P}Ø4œ?ëµ5^(˜é=µã¬…Iño®n•„M‹ZpÏ‚f„œoµu xüxÚ†ì*˜W%æË5ÃXË¡CtBŸh /cþT§›žàŸ†Â„„„x%H„µáS5°$)NªS|AˆÝß‹ˆ zWz›rD¢(U¾¹P§Ù#’´zEð²éS$ÎRþ»Õ ‘zS–¾…å‚“Šî­ï›=ã}i{f]tIO%£¢HɬP&ŠÔÍÄ[4©P¸]`~çŠMç‚=ŠÙ—K~~êÔ±<‡4lù’–ô„(èkˆÀ9óhý8^ñ¶Â8B´[°Ëƒ˜é2Ï ª‹øj<vÂ8 ùˆ4ë›8ßÓÇfQíÁ2ºø5Cö­j'Jšu€¦ŒSäJ×{Ø}%ví0F½‚¿p,<ªE@UH¹¯öÑ¥.ªÒ"ëæ¬™ûß‚Oå¡€¹-ÓÈș8<P-d;zÄ“`0…ÍTÂPg• ‚4? cÊÑ?4}ääePiíl—]+_f-U{6ÇÿîÕЉß×vàq^'à,ß¼J)Ê —ú£ šr(OÍlÆO?Pmñ›7#xåúGî3v Í‘f™i¿Kv}K!ˆzÄeùõ##bò¡Õàž¯ MÓ*ï©èßeŠsº‚xYð;RÚ*ŽŒ¿-€ŠTð6˜EÈö޹6_[œÑ‚JñÛ»µòmz hB [†ƒ’€€ÖÁ éGRsf®(¹0 JþÌj½\/ŒÍoÒv'a ¶¤ÞcÍ:õðÏH±`Õ‚ l†¬}Þöi»à– p’*ÑixX ûŽYáÉ(V"1|‹<‘ùk|ÍÙž8œŸõÈtŠàÔ];wµ¿È¬nBÅÑj‹cU"?©Ï “$a)³¢\Šal·`êöeC`†ž+IŸђ"“˜Yq¬°0Ýy¡Ù¾óðø ŽC·gåš›°U7µlÅíâÿž_lAiÛUá0øo?ÄEü“ “æäDfÄò¬êù¼ ‘ÂÄ ›Ù‰hG–ŽÔc70Ÿ’Ï#<åý‡`h=®¢ 8VÝkÕV±‡4 õ/³`PÑŒïUÝô’ôÌØMÚ=:àÄZ>%¢HëÞ¼ÖX]ùàax9ÄPµÿž¡ªm/2p²¡"À•Ì7MV£èèí%;Èì>mÆ1M–ír„_( è§ÝòÕ±˜¸+ƒ‰¶wb,†œôsʬe®vÌñ…øØÚÊ'ThœwÐyfëb°xÌzÍHŠø<¥æ“°RßèÛSóúVp.GKŠ5”ÚÈügX-eêÜ/¥ŽªÅÖV ´”søÞÖªãýe›<{ A6䦙ª˜1€8´‹^­VÛÿ%ß[ª*ˆEð·wÚxCg$ >E÷:SÊ4áA¢W42À·°í{´Îºc®·9j¶§=6|yžÌÏ%;«iÁM#Õm 첡 lš »ƒÝ’æÜm`àåöÛh×°€KÐÍI§Ì…ÃÈq ‘¼]BÏÀ_W<žql ÖzÔ_×x¥nmÂbU?]¡žÐý:qzýõ‚ÝŠqÖä‡Ó 9­´ßäû øâ¢!}ÂA™?\8ôIÎâp-otý·‡äs.o I¹vÕÈøKÌA8M5“ìBãÛ)Í£†ä!>YHü‘±°wU2•ÔäkN•º±‡–8 -l¼òUô÷t: ÏßùŽ:e «Í4Ãgí9£Œ¹z'sÑK|†b°î/ðnÌãÿx†_K ùx·JbìŸØDöŸH:£›`°Aoõ4—B 5¢‰(3—fÁ(3 §¦Ž/mع£ü†ýçÇ-0Qàbé´6¦’€€¸$T @#a飞Ôß6/ÏŽQq¦ìxÌ~FsYìB½8vš=Ã3y\&î塚žø@RUñŒ"ÌQ»P˜Ã;å Iž¯ÉŸÁu¡aÖ{JøIÅaþënnÃ…lp³ñíeà{€²KPà 5x”™:üuÒ*‰‘¼(‹PÕ„²;ÐÈ5ä´›P£NMeÙsÒ@¼@*Ë È$Ęš6l ã_áѸ#í•I,ήñ«ã›kßá8=I]ÀÛÎ'ã)‚™Þ›¶ƒtÛÌnÐ=áŠ1÷óD%¢‚|¥Íµø¸EôqÏz’ÓÈ!"+³Æ‰R…6éXRÝ™Tµ¹Y)b}P0Q˜ rH­AÈ›Ï"‹+~â*7ËïMóXƒ’5™psmåEi>Þü¸4¥¾÷ U£ õ«·k§‚&ýû=yCŒJ¯T:2ߤb7(Àf ¼}fÍpiíXFA­‚“‡lÈnÌwøü.yÆ<ëÒž&­cÄO÷`™Þu “8=§#ìÄ%³˜ò±Ï¼â…, pk¨¿‹(·…;¹‚Ǫ|XzJ¹¥dP¡Kœ¡v¿^ø,Ö™Ô•a¨‚|¶Rëî.ù=¡~jà¿s÷Æp¯‹µèS:þªí“!ªû„4¿÷ô2 N?&xÍhT‹Ý§ïÕïœtüÑû,ú'ÃnYJŒEÈdˆÖ s®è/tŠòf]Þ.{eïf¸´Æß/Ï·S+ÀáAì4_/DZ-Ÿf`F#Ú²™¥)ù+®îN^øÒ'ð|ŸŸsè`—%ô )Î5:§ßÚäCe뾬rñ/„7ϿƗ¢î‘ÅLX‹Ä/m¶ r°ÅAÝ“ˆct®§O´÷ }èL•ˆÄ“u˜ëú¡ìcõåÂ&”k,pÌ”]êÌ.k?D¥\˜ò ó TàQyP‚Òþ4k‰éM²Úþ2õ­Ê,LŒ8Âc¹f5­¯©ë›ôI)W лòf‰óÏÿ½Ë1þ‡EÁ‡½qûAÙ<“/4f0u€Ð°vA—Yè,CN˜­=«˜º¦D¹t>'B Wîž=þ(Â7Q±·EEަÊei±vʾE™âçÛúoS"§wÎ!´L(_ú—Òš†bG[Z4nF³õ ª+ýÚ%©©5åÅ”-=6߆_màϪˆ’€€¬o)l–’êÖÜÓy¯gt-^_”PfÿR/x:úfdć5MÕH4nMÆ®J',Kö§N`BFNØÓy+™óKå¢Ùü€ÆcË¥mò:g<r ut¾ãÆðÀ 1å¥_eäês^[ñ¥IÑ$¢xà€«¾ý_‹wñ %?ƒý~ë4 äû×”%€“ùÆÆp<ÀîP+'S Ã|÷þªôŒy²9%|W­#Ub$x–}º5låÈ1¸=G÷̘0¸ 0}¿Iƒ‰<j÷BVßÿoBj¨u¸£¤£ºÿ‘Ïé…«?Ü*Ë—Ÿ\ódà‹$ù&5l£½¸ì.UP á%H.ŽŸH÷î_koü>¸sõ%ØÞTÉ1¯äGm†N\ML¦piZ¢>H6Ä>S­Ug¾Mèèr]ò¶Ž}Ò‰‰‡ÇNr9½€‘æãÒµA«úšŸ(ùKŒŸÿçóÖÔpðÕ߆ÃwÓPrFlqhÇO¯gÕ¡+Qß1§ud3XNyý4A¶›íåsÙï>­ˆTŽ|çÔYé‚ÜšMÝ}…Š­9•7In iGî§kþ"§ÂëCõß¡}{ÀY¼üz,ò2žÁÉ™—5õŠØh@E™®ýÕ﯌sd"QňQP‡Ã¿OÀ~º—çJ¾ Aá:YgºQ©v)BÊW}=zËEÿV ë;Õ8I¥„1¶¡ÞÁ€ ¿/$YÊu‰FUóê´…CXß­¸+y~²ìâÁ‘-Õ;8>d"É_‚˜ÅÌϽV4q öˆ)ìQêÖš_)£jjFzØñÌxÊ;¿´ Æ‚³Žý]—…’Zk1Ãþ„0"¢Eže u¯áRØ£&~šÉbÊû®¤!jñ áûðÕ‘ÔI㎷4…Ž%:ß)ˆ Ícx±¨ä¸ó(Ff uLOdè[8~"ž|zØ•µ±;<vaª®Ú¡þjEÝgšpëÔºNÛFMƒöuôŸ}mx}Vë3? ÊV£É]oÉ£ý²Õú‡E!Œ^°¹®^ñX )¾“!N ¦—³a¤ Ýé)ˆ|¶rd«Ð/hËGU4¿Iîhîo-DãÀ5fo¶¨^Çï> ¨³¿ñ¯1Lˆ†ýWì(µð'[j‚"V’œ²=ÄPr£’€€ê Bæ·˜€A–,€U3Ò¯Ãa[µÕÜZ$ÜÎ"IúµÖ{g“Y­ecôEvº(Uóü¤¿P‡í‚ ö{ÞºS."SðÃZMOD€H»f>íã€ò¥†}^¸÷7ˆqþ…æSZmn³ %=­Y†¦êçܺMTÀ¯Y3½ Úu¤´_Ð#9ÅNŽÕüî`?ª¦š©É>—Ÿˆ ‚|@çóy¤’Câ_¥2²Ûh=áo7 kkH£(¹"ÚRdkØîlßÛ€OÉ¢1”PŸž¡‰¥Žü¿Áð¢-Š®xé,E»' ©©O@Kâ“,øÖkJäê y4JNW$á½×¨c= RﮞÛÖýИVÌeœ§­®”4=1k²ZêZqq^QœíbÂ; cçùŸWè 6õe›w›q °É_mFP—2 Tö‹’b¡ÇôñWêÅÉ pÒIÿʽq~±2ЂÀ£žN[qö3YW–%¹˜P½ôœÐØî®[R°³;†™L»„è^90rü&!^6 ¬#ó>^åE…¸O^רcÕÒ‘H«®LÃ|ûWÊ0]Š. êÎOOÑÂï’ /O7Û0N“É7{)lÓëĶ*ò _s—ãç6âÕÞüOöfª(q/p 3ø’5þÎeÇÂC=Ϋ”ì‚ÄÂ+ ï =e˜›j±I/ 6ÎQFµ‘<·VR¾I¼£™¾Ió ËãCö59‘Ö’¯àÎ6—rJ½Íôém¤Ø:)æ‘Öü‹?–œß–ö^Þ—TÿÔ7‡7Nè#ÌõscwÀN( Z[(`Cë"õ3‰”˜¤’„TÚ‚ðs`½.;ŸKèÎ9§=´¶WJÉ4ÄêúW½‰þÚFÛtÕyfÌmƒèky%x.<4ÎÀüç5à§¡µ…úU`£(>$S9÷¸¤º9ãYǸ£ÁIgdç„‹•Y„¦BoŒãuµEß»ö ì4íªqàò]EièHkëŽÈUu¼Φv3âßd$Íåù¤ìúƺֻ¬D ôcYÕ¾öÀ£{R4e~lúÄÑœPíbB‹é Ëveâ7§ihCD¾ÚŠçö¦c®ÝÄ’@¦™²963m\úkß­9=z3ØÐµR¬x; ­¬¬6×?ŠEô”)VŠ’€€Îþ–¤Ï$/£È£ î±súß=²°I•]²fÞq4̤bóYGK§+$nªÑkm'ÁjùÍ,Ë© ¬ÕDt7s™â¬Š†Œ‚r¡çsÄið~Fª6ãZ€¹?¡¯X¢Êe™.€Sü ¡s«dqË“ œ8Ç•Ýpðí„å¼™–Iª‹ªB·Q–+ç}P*êÇ‚ŽT5•â R:ðº:ÁJÓIâÔªkÌõª;æ¿Ê¸ÕøçÃDCß™ANƒ”÷;BwsÂËÞ®Wrõÿj(t”ÁÛ¼$¦l÷IbÌ=Î[ÏšA›xŒüv<{Ð=B([²0 Ol§Žæ<2èg“È5¨ý{Þ Ú‘»£úÎÖQ¡<,H2ƒÈF” ý—üôr˜1…²gKu9çùùÐÅ_J-Ï Î›÷køkfÔÊÞ¢Žy»ì?—ŠªŒ¼`ò7? Ÿ6"²o<Ö³ƒ8Yy;êðØÔǺßôKÇUŸÑçqŽ6Ͷ Q~úA`¦u­çŸÔ†Ö3F¹Ñ¸ØœgßÏ@vs´HxÍjb^¹š@!w 7E3¶‚KwÔfgÙCqšÖ%2{MåkW 6\LÆô† NWwÖÌÛš*ePþ¼å]Ž®º3·ÿc—T¶_uŽv;ŸÍMYôãùO> äo/7ÁgæFõü™ÿÝëdé"ˆ×~ýá¡Ë`¢´¼0Z“_¤$ ïîf+I²Ù.c¹Q„ñVÝíŠ8°ô÷Š-ån ¦_ü´¨±ŒgÜÅ/ÉDE×7eʳ”n9óü-5T–2Îðþô•[Œ~GÊû=@*o™«ÙNÐHònGòãŸÏÚoªR%'Q”ú>ì‘Hrèò™‘aßBÕ«Ü\—G•‰o¼è¿ q()šçã§!ýÓzbCe2…ûw$›dúN*†ÿ–ÉwÒ–ÿ ¼FÔ†Ô¶90/Äg±Y2¼ñwP+šÂªüÞ“?nõ(3.4äæÒºng†9"nB½½HvQÁ'Ñq÷ä{ À¼Ç]ýˆgjÉ™¬3ißúGiA-(ƒ‘™¶×â¤d¬ÂÃéyGˆÞ&…J<ð)ÕùTRpîñãœüœ+!STÿtbµù=,ÓFÕ®úÿU¨$¡™Çâ·[‘]ÛŽ„Âs6x'­BX€ÜK9­Ò’€€ü¼iWˆ‡…z ŠrŸý:I~ç_ÃÎp;pöè´¦o Äcá]šÑ›¸‚¬š Åϳ#4š¼ÔXwKÅIôOd9Ê”Ÿ·@Ï È'sQV¹üíg§û° W“ƒX¢Àëcq‰I¶r¯Dµ»ªßðº÷VàÖ‹î¸ZT’EÊÍóÝ‚ø)?çé`”K5|àÊ> îú¨ ÷¶ôç}ˆ]Z‰h7æA妽›ô´² q†}(¯þÿ«<ísKTY¼LeÛ;ªÞ=¨™ìÂÇÏZ=R”ʶyì½é ÞN'°”äÝ·áœlÍ®4ˆ÷Õ»“’_¾ÌÌäŠG4âì3ý¤Ÿ ~è$ì61Júëç¢!]Ø{È^lÞÉãÄœpôHê#˜LX›d±ÊÈ9=èœdÞr@ohæ­Áýé‹e_±?+²(Dcï;¤2 ç™Ãc´g MÓ¶zÞÓøˆã_fWñHW‚Ý55þýŽÜOÚØ©5ê• òvæ(“¢Zð`úžx!KU_€†'ë½Ó²xi%-͈‡Â0ÕWÁA¢…—¼¶õ˜8=(’‡g˜•#>äê{I¼)ŠF⯵d© ö×éKö|•ál 6'RÖÿ Ñ™‘bÕäL’;M˜ÖÿmèÍ,ÿ‘í8%æ/NÝÁþǧàæòÚÊ–ë0¨¤>8®-‚0=z7n$ùYŠ àZ3¸<â<\¨+ð"y ¦ûÙõå¹5{lÒ=É2€MÉ Ä|c|þç"GFx_O™à«AFS±^?–N%0Û »öäÜ'¦?F°"TxÉH ¸§Ã´“ÎlüžèÀ]b¡ýò?ÿ§J¼|ë—VWþo“Î |£¤DÙ¾3®öãÅýÌc2ðºitÄŸè— %8ʶ²ÓùTí]Ä'N+kKy‹Ifÿ8W×w)kÒ-ä´Dç–~Ë/Øã—S††¶'Ó“; ­^$ýY M¥Šbýì¶jÆ!É[¿G±€V~_«ç!­=zëQXH‘CJ³ãÊÖäAªY-M"‰º]*ðØíM[b’ÏõÎÁÛžÚ>Ï0‹Í@,Sb“ªÇyÖY7CƒJ5²åt0’¶øÿžÔY(3ÑbšÂw…õðȺyèNVæ¹×LN§ü2Ùƒ‹í‰…ym ŽìœÏp’€€ØØŽ@@+ÎRÝ…TOY(\ÿi$ÙKŒ³"qb Óûz>‹ú3óM˜ŒÁgë”±HÁ36yÃè}Û£Z%>†ºóZçæ/£gØŸ81géj!H ˆeÛdCwŽƒI¯ÂßÍ6ÊI†ëu&ÞøÀê „Ù]/«÷Œ–k@—`‹LkWÆÉ ÎAÞƒç6 ¯jä½±KF×7à“ë*ßÌÿÌmòÓ­²wY Žcâ~êÿ}µœwb xVÒúXmðóô‰üß?üâÜù"RÃÈI«•Å¿1ñ÷Eü^„þÎ$(’£?ÀGèCö®i÷e¶š82.5°ÆR/z¢ë!Z)ëQ25ÆùªÏØÒ651ýƒ…sÒäì`DœŽ~8µ-úÖu©¾Õ¡Œ^€÷ nXáºÁ[/‰Íù z+vÈMªÞó~Hîh‘p$–Ð 0“‹î?B˜'ëó:ªæ~˰òˆ!Ç·g m×@"þkL ɽ¸îy÷ c»ŒŠÕº34ƒrÛŸìÌ éné7O ¸¬ I'/ti <\ü»Ì TjéÅã-m¸‹ìoBk³Üq QµUávÖs'E}¿¨(åÚA¶-ǰBþüË¡FãõîïãÂA–‚Ë¡X–gF…Ç›órÄ¢ç¶ñ&ç9> ¬ë] æÃéºåùãÂSop^ãpkbY"a0gMÃ+u<Õo¿_ô¿:z£ã+[êÊRèGã-Œ†sÉòÐ_Ý€e•0ð|Pç/+\6ÛÊb; 49€ 7þTÃ("•{ϯCÐc5ð˜|”üÃÕòH/"ê0›ÚoZ*ôwËåvrA+Æe:ШØzŬ¹x—6‚!¡qÿõ~wá©}b¨Èڃ̠|Èîý_l¨•Ú¯°”Š÷qã …¡¦$—# P3gÙ`¶êôܺdŸÜ5‹†ô±£+} CQ()<±âÖ^ÆX2[¡‚Ú‰ÿF†„£‚‹µt¼Íe ò¢›4›[;Ã9ÔVzh¶J0ßý ,Ô÷šV4Í—“%{¤Z‚eаém9.ÉÁ<^rÑn›ÉÊ‘»~4_a²nðê´ë¢C^ë{d,f¶¬É3í wÜ-õ‘θ7‰—[U˜¹\ù´“à`mdGÿZÍÔ˜aÝ%`{ǫΛæžêyÿFè×p?=ùV:$çÌü'€ÎÖk¹)K€Ú0I¥ZhWåîêcŒRáe¨:_Ú ‘ÎeÎÈß½˜¬1•©8†Í ’O‰|¼{¸ä¾Ò£@‘› ÓGWYÙ ÔÀ+À–dwéAe'–^Ö"ίËwó‡N(CcàÇÆ¶v•FÕ ÍB°}ówEˆ6|;‰ÌÈý¥A+HúŠà‰¥¿öÇá¾”c¼ðv%w6gñé# §aß¡Q7ùii[U’+솉넆f:pß–s¯aÒ{$¿4+3§h+£“© Ò¢/´à­ùk7)„ø—i—,Mª&pMÕ¯ý‘Ǹñô€4‡_¡–í«r¿*ųt’¨jÝÏ€Þ{j=£CÁ¥æð˜[ëÛ‘…7éHžZ9ïñe¶^n1°–~DÂã ¾S Ð!_{—ÍÂ@0âÑË;µûºL7s~¹ê/î%šµ*" rÁn8±·ðt`‘û™ÓûQO®ªÎ ›–uÎFBÉç}qÿrx:xîeŒ|ÂqÒä;P{· b§îM .Gs_÷ÒŽÜíªn½•ã­–ŸÓù%ö\„š…>™}Ï• w°øy/Â¥îPùn'â–:Táçíè%HªŒzFyZ¡r̃Sø8š-I¢y (]¹À (‹éÖC…3+ø2X lkß;HïÁ~?À kú¢Fƒ-)уzÑ ŠMöþXyÖò¥Ò&gLùÊLZ:Òe-þ¦µø¥ÒqÄú2°RYœº“"Ṵ̂’€€¤öÁŒRPon'@“ïåg~ š0Ú}5¬áÿ»Èï™Û:†ÞQß à‹ÆÜ~•VÖë¾–Í=ml°Ü}fÖ»^Y¶¶ƒÛ ñV¬XÞ«ˆôP1{X«­•Áú§VוcñåK}Ú[å#5ÙªžÉ>bk }IšH¹z=UpN¤=Ò‡€ÑrÔ}|5ô™QÝJõtÐ^{¦qÑ1#l›zù2褂ú÷a\”ãÍŒª¨Ñ,­“7šóÛY}\¥iV­ïã¦ÈÔ2Zœ´Mûú›Æ¹²äSá¹±OÕšòJó]QÃçãÞ-7é‰Oûû;§§îÅjZ¤xiÄMšÃë‘%ùgš}Yª­©+ÄZcç`5<£³Á/¯tÃ`Û02ùü ‚—+ª¢ú& èÜRÿ©!ÐêOD«”¢tªí×AÏBÃjÏ*×F®>s«Ç[‰%~ÈÄoœ÷Ÿ[üjB3¹¨¸†;™äJøw\5¬¾Œ@°„`˜«XJNÓ]­»l9ÛhN¨HÏ©*ËÞRšÙ”€"369ÌJŽþ“y— @‹ŠÃó¡+‹ø ìž_Ôé„×´!½¨Èš°º»ÂjæÝœÒ(O<;Bâ;D\lß±ÌÀ=™y­ýý£Ëj$à³°sTkI%ÚÅÉ7ÿÁ8‚Z÷×U46„.V2'Y£|šBTËPÀ±Ïü›3ý;“’.É8•½§#ƒ¦óIøü¯ÎíÒý×m÷ܹÛÌT6êJ5¤7aº:8âwd³V] q6_7LÿÕ %ýÎZ< ϵÒZæ™ËÜu$¡ °ÝË—¨ó¾5ús¿ü|EÄW{÷WiJ*0‘Ù¶íΓêEíCa]«ˆU‘á­Ot“ÝyŽÉz-  a #…¬—ó—Y‚º¤à‚Ñ=®Üò5ÈPQo”J#NÌ8Ãp Ž5Ùš6^{›Ä殇[ Çòw>ãx>Ã>[¨À9”><üƒåô«@¹ŒjNTÝž€ËXNª"”¬¡ÏbLCVÌYv½Ó&úˆÊІBÛ%žƒý•DÄñöuf¡OhFsÕ͉L`3Qe+ÆǹúY9ƒÃ¾$÷HaeBî8]鼇7 “×ü†&RT!N y™ý™Ü³®Q®'8Àæ·Kå`ÓaW½¢%xvq2:µÈ„u]e«ÛÂÂNGÇ÷ÁHÂÆKùÆ<èyàådL9̉zû#Êcœa¬sþJ†Z>ž …\h¥¢zœÍ0 Ú1ÛÚîWbÙ’ƒH,—W&òÇå ±…”‡oóÍðöp9¤ˆA±…Ö†nZ/ܘÖ<ÚŽžñX^³ 7îl©ÂLA†5?z’€€¶¨Ô¢N[Å•ø¾ÿº¸2·‘ª‰Œ }šo‚=˜º-÷ZTâ–ü8ÙË^݈/W°\ì·ÛU™Žƒ¾öãª'ž[OðIŸQp›$h›F¬V\%C6‚Déoiˆà¸=ÅMheOÄ)n^‡@^íù+×4¨ÅÛãÛßžJs~+;85å¾1ôÒ’ Rü›žïn[eªçg”Ì»Á¢ ㋆٠s.$Êâ÷·ò†b¦ªšåYƒ9¢Þ^ËÈ[!ªA p½ X¸R&òMŸQº†.s"gSNÚÅ+ïUz,\Sü =¼û pì•·yâxúûå³Ä&Þ¼8xó¯ LwݪÎÇ"B7ñ÷\t“Xu+0¦c£ÿ€<8oýd¿¯…E…G”’¥Fõ°þ-M²¥æÉ½ü㾜û™~‰ ÅY;S6+ªãÞA¸г^‹µGŠcYR.ÆŒàÙV¹ç¨ó§mÞãujc>nûmIŽÐµ‡)þ •¢—ã. ¶™ ±lÖ= ²9«×úDlžïÏ-jÔZ3k~àêàl|Û}Quj«B¿}†ÎöoBJø´Ö6w%ƒ ”ùah•Fë |ta›­si8¶H/ÉǾÝ}Ú Ô”¤«TzJýÖ[Q£7Dk€RÞLN¢ÒloéÛÝn¸œWünóxk±r0AþÕ#x=ÜUd¥b_!Lß­hðÀ¶uõ€9V¨Žá&1.ÿ°Û’Œyž²-ݵåqfjAœ<âü,X ã7´ý켩] úRS(†öG÷ô:´: ‡•htEúõýº]émÛb´O•ù‚ý^ŸoÓ,ÙLÛé˜ã¥¹Þ_?Ÿ<öf1µþtCVUE"êѨÊÿie¸1÷¤0|’ífôlSw^bs¼5ï0¨È5MÄ;A.úŽŸ„xŽ:6 ¸o.%ɧVÿÑ!ô?Ê4X¡:;³Ã$ko¤†Ë’–e°–³Òm¤R뙈çg/x>-‰|÷Ý3ßH2| Q³'V™…àÁ[è ZaEc`îR§D;LŠ® )ŽºjŒiPüŠý»ÙHcá'‡:ÃÂÊž·\hQhŒÌz!¨ÙœN^nÌ$ºÃv>ÃSSPƒó_Ô’*hŽ‚±«¬- Kâd8–ã~’€€¶§d‹‡®è̸Š1í‰S…w?SÆØSø‚¹n][­,?vQrØò§ó=哽Y8ÃOD.ãÎk¬GôQìÌÛ; Z‘; ‚òÑø!Q¿H9 °°a þ%Lþ.†TË3!”wÐZ¿\ß}‡/ÿïÔú—.¡Es†tòêDÎ\AÇOwû¹øÊ#iuýJ›÷Ú½Ùé{cãúe¡B䙯¬€8V9—9”Ö½]Ì“z;÷A·~fÆp$,‰.î C{%t.g`/ƒovDìgûЄï`.´…íuì0yÑ(â ‚—º!I§+e|ê}böÛá¿°á…YN^gÞŸÀÕt£~yÉ)L»Fµ§÷}eÅE¼ ÁhÄ K–„ª˜¶m£7ÐÎØ¤}§5« ǬiøR­Ÿ\oAÈL\.\ñE•¦> bÔª–Pþ@Ï8+Z· \+Ž…õd±t0™¾›k:üô-{ÊpbóêhŽuù]Œ.¥–*“9´ì“fÖ¥[P½jÕ§H¯V4Ë{:*èJÊ{÷pMCZ_ÿBøZ­ ì-ûüŸ. mt1Öd¬ã[?DÂEbd”0ç?«²2IáxŸû#Ji%4[ãÕ’ˆDEšl1ZVfÕXÇ™žÉ3ÏÔ·II„ˆWS/[@2ûd­Ú1tÞO›˜­\éYÜõ;ú¬8˜«ö;I˜äÄ–žM‡Õ–+4åAÖA1Þ¹#%i9#ÞF5À¦tíͲ¨‹¾êGÙÑ6šwaó¢Âñ¶×h’¡ãÜ/RZ'b@Ð2Bäú†’ßÝ+—\<–´¨ù“›;qZ¤» ;ÖM~¯ ÕÙ¿—¦4Fã8[_…ÌZ'ë‚˜Óøa†wLñFABÞ–èÏ]±o¤^½Aõ›ýq@Àô²ŸÇLÌ>qg¥l¢„}3h&dvt„­ô­hR8,«fÃ0áå9_½?Ô=WäÐI€F#Ï$Ç®‹2°×ì&‘IG?¤zÎÐ?ö¶Tßvž(CÀf+`F~ÇesÀuoë¤ý×^\ãµx0$°’À®Àc>BÓ¿íÝ3ü°Í鿼L’?hRXÆÜó…SáΘø¥ÀçÕû3NVùœ¿iCÿ}þ][òÅ “еUÏMñ&WÏÅi¦q¤w†’€€ÓÜõ¯¦E;¤ Zá—„í—q¼<Ôé» ý#ô»1»¥|SLbUŸb/Loy¨`$kõÞÕD–Ř“ømˆw`[c©§z²ANmkzÅjâãä%ÏÇl ¨]¹˜í¯M„ÃW?\—½ÆI˜M,ô { í#Ž˜D©_i${Hæ¨3¤W\róüʷמìˆ%aÚò)æÒÞ ™é¾c 7Lî¼8š½+æ…F’î{Ò;Ë*.5p¢=…×'‹°¯0îarxø€Êà`”ƒÊÌÐßm¸G¦EnS,±ã¼ªzÐöP·y²nGÆ.s¢C¡›@:ËPè‘ÏL›gŠó0|ªµ (xÑøÞ‡›a{ˆ=þ"Œ€Ó¯d:Û[ÂÉÔ¿§X?­”Ð:ÌÞ’¢ƒÐú™† ;üìò“S¿Vc3E¾beÆ€ õý˜ ¡Ùí³Íy?>ë§H>ºÓª-sÂå9]^™niBPšÊ$Rq|v§ò½ðT.;%๑Øxz77ä3ü ‡vdK5AæyþQ’zýÐמ+§r2*”õMŸw`ÿ¤Ê×þBÉ,ßd‘CšÜ w÷ǔޖŸÞ[´è=°†¢1ËÅä,µÛšš`bùŽÏã´WÁJikÈxµ~¼Îï¨q H÷U©ðù\7UÄÕ€ø2»[…’1 ª§ÁþÉ—õ¼ aCÒsLV¿?Þ‚øJ¦9kTùà\%X âì͈¯1]E…€=Œt‹Ôù@È~ÝÐ?6obk&]?h¯•J ñׄ Ž77ŸX¢Þj³·ÃRP±ñµÉÒΑ® žÉB@7}\ª!â´À2ðFv°¾È~²è«~üIŒï rÄI´Èù5Še‡þ3scá‹á.Úòtv8¹¨–dþ=  C †˜™pBNE²Ûl=æ}²™à¸¦ÖÀ ñEA’€€Æ›Y´&Fð—'¯¤ý°øŒ‹ëÀUútØ£OohòFSÁ­½mäÌ‘*"Îa†jú¼ÆhGñ–ø*ÇX†eDHWõ†—3ÿdžÙëôoJ¸ÈÞb®:ž-›‡ƒ‹¡ NÏN/®ÏÔ—M*ŠÒ·‹òÒGÁ`“«˜Ôö†ÑüXúû]ÄéÐk¼wÏ9ÜÈ?+Æ•?Â×Eä"ŒŠ¿@ R¯ù“âi^]ÛY‰hã ’n˜X¶î¦ü.E(%YdÏ Û!xÅÏ>]©(œáÙO-¢Üµ›L€nØ»hòÓ5 nÈžçªã—>kÿáÂâ„. Jþ³¤ƒ-û 9%¿½-óÅKªöÍܨ¢‘jKÜ}w~åþQoîúgêÂÔdXò$Ò¹|ÚcyÍ 2† v7Žàf9Y⦸Y7¬]8£?«ú*]ñëñØaNað¯…??Ó Í8õ¶^‹]Ì¢ÀƒO“ðþàÌ• eìWibé\™§Vï¾.UúÈ#Ügÿ¬¼Z÷—™P¹E!1ËÒ&¤•ÃjIÿp‡™š•+r$º pM½IüX}ßÉrÚ%­ªf/ÀûðÆ2„þqaCyý˜—D¯}k¸L 0;ƒv¿e¬¢²arB¡ Fý‰ØzYVNCv¾»ëŠëµzˆ6“'éÏ%D³,‘ç,ðîÐÞ*å ÀµÿåLA4a35’¹„câpC^˜¦èŸy‚ï’ß\ñÁs^éÅ`Z‹ö‡¥#ŒŽʈ&sÅ©€ÅN<øb„€úÏD/D U¸[V€ç¸AõDÝõ„£ê{VehEiU’8|À¬˜¦ðl†çÎqÛï‚Y±ÙÕІօ:LL­œ½¤/SK¤BY«t´úaTR¬çîläÿbQ!>L²Jö{‡‚D¤ÊpmöqúÇJŒ3;5•õ>ûmûß}Õ×pqzଵu8‰£;ÔY¾@í1©2ÿÊ2‹ûþ0’š$»^“[+¬äq HË L/üÂw®ØÌß™œ—Ò{8£Üu›Ý"Íï ðº”Î[÷9(ò¤5ŸzlêìÔóæÍ«0’€€Å‚VlûŸ=y?Å矺»p@¤@4½j®"ЇbbÒ0³‡Æ|.0Çe;0] ÁKúNÉŸË+3™p+ƒ–†Ó„ýàDÓfáÇàÑ*;ºÊ6ð’CtÙDdÅáêoWJã²ûÞ©U²ØZÓ –u?8xîW„s¢¬ð€ç÷oB-“*yòe¬y€7nB§*jñ9§ôšØ„ËýÆb‘™Ñ uÍæÖµ”óU ؇ïË™rj›þKr~ú‹}cê.4·^£©œ,pvОä[ˆÈŸUÉ–|ï Å"èZÂo*¶Ø%«±Ü"oÔPjŽÆ¿^š£MQ¸ÿüpÍ´æÞ¸¨*÷8”A'`2ür™òM%Ü’Dç"à‹¼Ã×6öøêGp W´wqjsm]*æ8qîˆõ›Sý¹ôtÚ—¹31ÁÞiìu‰’®^l#ä_J`9o3 H«Ôç…åó¸9ª°=†ÀkÝ’mD¡ŒxohŽf^šÈˆ µp›C»;àez~is]GJžŒÂݼ)8h|`«¡6ZWOÙÅûÏòÄŸÚj üÿj’®5ɶn€*-°æð[:× þÂ}Ùpeµ¿® M®[ÿ½µ%?¼ÁORì‹« À=9+r6û5(Ý¥¶™‡¡ž_Ž_¢ø#>Oƒªáò³¦µÝÁ3ºWvºÍÏE?¦Ùõ^Âé/èWú_ï³aoÌØÙÝŸn©S,ô'•³¶¸Ó¬ï¡4¦ÐÒaÔîvÕU›CbÎ?Ù¾6|¹Î®öÌ*mŸ€Ö›þ*š3Ý•ü†‡Ñ´l„$¥Å%ØõÀ}+`Sû–q$GÐTÆSìäæ*›¹K!a)n ýB£,ÔŸæ’Îì97¬‚ ¸ªÄQ©#H~@îß96$§M6ŸÈ¹o!„4öþJº le ÞÂàçÛ1븺•”Ô#Hà¼_Ö™•-ƒ,õ«yË·@Ò÷ ƒr݃`záÂ|%¯Ñ"‚.á,ú©¶c „n}6Ë}» ÙC@à à=‹aÆ$ðÇJQØÈ$] ù¾8éa/qÉÔ£·Œ)Ýçq*HYÖ¢¹Èh˜8•ýcRÿ/?g‡ ô÷Õ3“~^w]žx oM6W ›V>Ìß)™^Px¸gÎòµjì$Ï =i˜;Wµ9¾š©Oó꺠ˆ•u‘@æì÷%œÑöðר¿Ê±ûY@rŒápy;W™*WǪNG;—ς̌lÖØ,Os÷-ç7GêCÐK©a”õ$àÓ ½ßmK9M¯‘s0àg¦N‡š WQ¯"¡—¯Võ LøJ«Aª;öJ8Íp´bÛ’€€¦pA…•Ô:fƒ¶¯¼Ú6ò#–Ü_˜¸;?zæåš÷û¶ ¨ïªÐà0±¦uŠ„™×‰É·rc™ŒÊQ$.´“Ë÷8²¯Š‡“æJ÷AW¿qûç» H¬Ú%"žþrÙÜð]©æØ>ôvÿZIB(ãR–ÆÛw4þtL°ªvA xºö5œm‘†ŒKñU–=S6ã²3ÙªJ‘Ѫ˜,|{!wžøµ$òËëëÝJ?8×®=Ít¬XTR'7g‘è¶hA†Ó ˜î|¡RÄ9\PEw u† õˆˆÈÅ~;D e‹€Ù|ém%ûË?Fá®A9Ÿ}h16ØåbÝDðõŠÑý&É IQKtœ#YÓÉo¼¨q{³}øÛs!†"@þIª9j…Ú3«ÕÖâxú­òOãfý•£Iv±tYL«øÞ%„¤N߈Ҟ(]TC*–EB<}4J»’*ŠÃd·Co+~™RVb ;¢^qlÁÅà÷?J)»]Šr\Zƒ[ãmŸ°zG}†l³t!”ßœ1YÎ&ëë‚wçe ×ç¹íéí^5v‡–ÀätÁòëíKÍ5XÙ#­ã;bNjb¨l¤.ÅŽü½)²WV76þ} +¾à¹Feù´ªÐinÀÂ8G¡R×â|òRÕ:x¡3yöZ´ŸCã-˜[>ê¡äqéõ*I2檵W'(CñTÌÄ6oG.oö 5ìØF.Ëšnm®Ì¡{Öp³‰6wŽë>ª¯ÞÍYfþÑÅ¢àœsC¸°>J#޼ñ»Ý(/-æÞ0 ¯'jéãacVº„üUwo>—7ÃNɲ̵[Ïü)l Z˜Ü$ÁòrŸ² tBüd‘®=Ú4VGº=ð~°ˆÏ ’€€² \Rÿù•íúQJQù“Ý~Z ¿ndí|]ÃbdlÝÂØ"¹ÃÊÙÍû­ÜÄqßÅøÑÈ oH §½\¨·ó2•?‹áO9@í©îÁû-uÔ7b r¡×6I‰âuaÆ&ÙÝäUjm„§+î°èr0{eQc»Ðb0í”&Y&ÒÐs?ìÁ :—g?é·Þ–º(·œî:ÏöX°48©)Káñ«þNMÚŠ•Î*¢:¬ö<èR¸`uòw>(ó+*§8Ü‹We¼V§;Âuˆõ½Ë½‘‹s\R«ÖWÔå²T|³³Ì¼†ãÚ(vÖ‡Ýs ³…z,ü°±½BÍ­øþê ¿¸Q3É’ΩX_ˆ­s4HßÕB¦&[·3 ÉѧI:Û›ÊFé3Ò=¦ n8:æ¦Pì^¦`;€ûká¹N„ ȳDÀɘ҆OÐwm>“i×Mó¸ýAeZ-ˆê‰»©´÷þAØ)PàœU³xÛ#€€®(¾}óS9›7x]Bdt—B‘ãZ^ ! ›™§A‡®uº+8 NÏcþ`É‚½¨8… UwÏë~¤úÒyÿ½x7O:;ÂkŒyФÓ]ù³ ¹~׃;§S­âJ÷»_lx©Ó¨•𹩀Ük¸Aãt/ÌSâ®´XŠ=›ÚKN!ƒ aä±±p7¿›f€Ž-‘pX14íwøS8‘k'£LççLZ²ªàÚ Ï3°±¢Rܨo;ÁJ=ã«·x²Qö³÷Tô}&J>(%ÔÑ“çæÚô­¦*ƒp"œ'$’嘆 ÍB亽V¿ãÈeõ…*sßth¤Þ8”µÃyÂã'Ø%OV±ÚÙK¨Ìxæµø™ª$娏J[cjã¤sçÏŒ7.2ÐpÌÿÅŸ˜(€êØ3à(Àº³Ð+;0’0~GP_Íazû‡ û ¸ýâ=|ˆ3ÔGýXTáç¿ ÌX®Ê Ž1}&1ɺýσv×Vp5V£¹Ó„¡ ™×Ú„Ûÿ_«g ñäÊguó×8dL/.¿E•Π&ÁùRéü›l¿®Ø›ˆ—û3¾DDè«gÖND݈­„}‡ŸZ/‘J{?Èÿó©2C¹÷É€/ÃD²Ÿ§ðìs’#¡~Ì{àFZøÅ’€€šÊr½aêý‚‚îªãâ²úOò—Ì¢Nð©²Þó….žM£Æ67ùLYD5åå_tÇxÒÀ¬7#M›7HõÇ¢ò¸¬‘+wN«”}'‚éóÓ—-x®©l¶-½DñÑ'¢°Ué6ßÌhÿFÑúÀìhlŠ5þ3Sø'[d›|“ÆXãDXËŽ—Û¯Þ&^.;Žn†ÅÛÆÛ+ÚOÐy•äE›Ä.ç{ÉÅúlõÎŒ‹jÞT+ öœ@ðr j¿rò™2Ϊ\eJ람ºTSݯ%!ÕÞyHhÔ¯!céÎUZ%$C¡i×Å~»V2ü8qÌŽTý’%953I¶ð~Ê ¼PÉXzнˆ¢15ðÌ4`Æ, ¯CM‡Œ~¿6H3¯ï\§—"n8GŽ7CK¢žªS;Fv¹ß“UTÙ<’NÌt­ôa˜þIÆ(Ëè7Œ ¶çD ß³07¢ÞÔLŽDp+¨i.fwj鋺axÎÛ¯½Çʺ¸¶üøÐN:NnxíZº¬þLðZz²>«ÕŠL:üÊàT6ŒæokÁ¿IëÈGžõCK-&›XXÎU%[E’ì«=¼üHæ¼]¿À®1kx©»Á)è 6ˆ-ñqíÚP‰¨˜³é\;¡›(ʃ-ç¬qçËÿxÅAø©&¶¨H' £ãDxž¹Mœª?'{4÷pžkhÁ ÃD4[“§æ> ½°’}•áRõqÿ‡‚=K†;oj«n{ÍÒzŽ {ðZ”2¶o¤nmdòÌm×ÅBTzI;=aÑ €)æ\IRl¬Í+‚{zåäzQñŸuï³UûÈoÉCu&Ôª’€€Ø˜fcÆ‘`½ãâŒ9£¾ÖK31m:æ„ìß­œŸÉ ·Z}=«“´ïZu«^¯§ljù©›§õKxUãK:\cÊ®ž¸gf´¨X*Ä[…Ë®YÑþo Ø—ï\•«°¢LXXuæ? Å¢ÈÛŸ·f¡ûñQ_ú_·xƒ PÚfd·º¦‡ÜçV«£Éç%ýÄòû")u;o>D)° {ÆöãD« Òó>·±ÿ> ë¶ÿ(‡À0 £e¥*ÞŽº–\E=©ŽÃ°ÆïÈcѶõg ‡y£ƒŸïìfÛê¹ü×ÍÓÁ 6kõô1Úu#-«‘GÐ/ŽÕ]uËT]C¹ÕP÷ÛÎñ‡Œn³$Ïm”.Œ[nèR¢ !K_ÿÕ¨*ü]99(gË„å™UŒÑçÉ™˜¿êæ×óe”ÍK»èˆÜ4¯WmûO‰N§W ŽIÍöIä»ç›àIéc‚WA§^s'dÝñWøñÒÍQZM@òiÙû±Z¾RZr*¬[.ÖÐÎZð³>Ýó~©2cèiã—M„b©—¨‚Ljë=®ÄÎö*ñQšÓ¼Ûž}ÿLkãsâ|« ÒEJ$ Øá7)¤FT @g‚ÝŽûßXý9"¾”8ë.@ûhûò ’÷ Ý{ªï–nØ3:‰ök;É{Øvþ—Sò“yY›XÀ©¤‹Ä¾‹¿r‡4ºíKßÈ댨3>™ h$/£"Ì•ÙÚÇ\ñÍ$ÏÌãXÏ'D0‡âÄŠïn5̬»ôi 7.Üo• ˆ\ éÚÕ±¿åœô3²`­{UŠÈæÎCÛß ²`k«áMI¾„³¡£ŒzXFŠO‰Ã¡BÍ3ËR©Nï'teW¤Xþº,N/|g ‡Ü¿dr{ª4ÀßW]È%‰*àÙ4ð°ýšëéIª_hû£þþ(·ÀÉf=‡g/IÂ¥¶—,ð\¹B vdò¦ïJDµJCýEÿOÊQ*5žóëyôÕ×Of¶úæ¼ _=-µìN[{àÀ>¨’ȃq®æ<Œuì7ÞÁÑf’l:™6Ó‘ý!!ˆÙ…­«tZ\sö]Áx 7›³oâÔR™–)l]9ä¥ Xô2h©¡äÀ NF¹ÿý'6Óà†÷Ë@ã˜ö¦, !'Ñ„†’€€Ä#Ÿè s¢“C»°e;rñ?ªVFRõnªò 'ŒÀÞ€ý (TÞCÔ&d•ç :1ßnž5x@8z›Î`Ñ%`E‚×q¤dH¦<·k&Úâ—W„ã͸“Bi O¶Ðu|@^x4ä}è„ÄqvÙthE14¢$^åØÖ)\ ˜ zþ„_{{ ’%ùºä(E¿[êxjaéi@ûsûFô4”tûq…^¥IšÙĘŠÜi¬Nmï>Ð’-­‚™Jv¬›Î„åÓÖ(>€Îœ›É鏿ÊÞ;ÖäYC°1ù‹13¹­P¬Ñ£JR¡šniF/{=½}açR” Ã7Ù@\Àp5”óƒ÷2‚A²*§ŒƒÔ'U¢ ±¸°À¾`eÙª´¸Œ†Ý–’GƒÇ4Áž“‡@ç°Ð@¥îl’%tDm½ƒK.Â] ’-A2ïj Ù Þ–² QÈÈŽÈ9<¹Àë5·’£EÌظšÙ*àyð›W3Ñd5ï¦ÄŽÂœÓuƒøôÉ…W•ä3å}€ÌlÕY®]:!¸Ÿ4q¯_Þ[\YÛo±kÔ*/5ØW*Òºåâ¢rAÒÀ qQUÄq$QŸ0ç°Ž8¬Xœ¦áÃÅn÷öz6=+r¯jÍn÷5®×;;¡ÒÊúä/mómì<*÷à1à)2Ht^jjO!– Å­;¬O|A˜(ù¡±òIއ“Va³­Ü. œ^K$ÑÈ_á¶<ÓµÆ~!‡Iq±ßåªLIõõåLé î Õ˜¤$=L–Ä}ds9%Pãl¨ˆ)pÈ𚊂—`Ñ©?O)TAwÛ±ƒyþדßöØ ¸C¹Rî äŸT;vÕXu$PêVÞ䳌]¶"—<÷xeK\¯:¦qoÂ"·ˆNºHVZ,÷KŠD3û*†¹سNœ;¦q¶7æpbÜ àÝÛ…ƒ†Õ ä>p†á9º3‹ŒG¸¼†°"Jlþmä+€´þc¢>zmÈÅЪ M5+“kg9&.è­ëÍßN$-T0‘*Q@ÖoqžŽ Þ8Yßœæù ðsÖ5V®u­! +;k!Ñ(<'Øš4=OªÔ–8×k–¦Ê¬Â'mDâTkB-ÂàW¼ " Pyì†Õ…32»]¬šŒ†,ä¼Ü…’€€Å¤¤3:û„Ð2UµWD©i‰ #(¿}ï㌑žt£6‡õm¯˜Æïð¦EÊ“ %aPk]×Ö1XLBô˜±5Ye]yòygî•ö@˜vL:¡«´Pû…ž^mþcVtz\üïËZ®ù©:øÍ_e©N{iÇ Ç•ÿzŽðàÎWɉªìèÐÂ7U½—ý­ú‡¿5±;¢»Ó)ÚzocÍ6.UÎo•|W¶a½À=hPÈ/K0-kG3’*|–ÅÓÈ* øÒúUEõKp’ÔêùŽÍ=º-)‘nð¤Úbî£.Þl²7É"BÒ4¨˜Sb#ëWå>mšÆû¯B™$ËâûÍÍAæÛÇyöäxg\mDÑÅÞ “gC5€^;ý€„ ßŇu©ƒpÕ&o—jÔ?á¶ÁgͲÛq¿áS6Éù~_«Ðë2ù#r»náPuiÅcª¬ò¿àUoô¾®GÌô  ­7¦ÿ‚`.ˆ›:~djµ1´6–““ôKβ¦–©%ù3±/7üFû ]»ŒˆƒÙhX‚_!÷8 {ýí ƒß÷¨µáÕ[à}cÚ¡çHñíçµÌ¡ù’yø5&…w˜rÆö¤H,0B[¼c ?úýÄ›9¶ È Y‹"]Åé „Ž’([<2JrÞ ~n$çóýµ(\cÍ8Ýœ­æ=ßR1àä3^“­†¸ÛsÙcÍr æz§?°ë!màŸ"“ot!SÝg$ôÎòê5àAà©YË Q±– GZÊ(mô ŒN>V—E„6I>U^m®d¬d'ΘêË”¸€²55"²jUäl¯1ÇJõ7/æXÿ|Йàp@熙íîŸR¯‡ÿõÈ×Õɾ·4lÆt?kWï•Då±­^f+›´äp—Øaä/O}晪¦ñŸ˜že,IÚÕ¦®áퟭì2ùTÊ糧8±™ëêÀš|ùµéòìT ›µñA$Š'A|‘Z§{ íŒ†’÷.XXV3-Fºè²ÆØVƒ¿Î0JÜ”IÝMtèB3Šå Ã)«€ftÝØç§ÔF šIšÂÊv¾\Pôþ|‡L.þôÊw/F€¶)t?ýh޳3z¬|&u¯ ªš•ŽbKªc1ÚjØò½p‚É™·•©’€€Ï±“‡BÛ«ÿûiNÒÏYà¨.o3 a|^‰¤¡Qò„»:¿ “aL_(iöc0{ßÛ$Ð*œg”pº°·oâ‰'ÍÕäǯøëê,žƒ¶yò"a¬*Óž úÉGÕ8ë¦Ù?C&¹Uiï»~0JÉ•L+7ù‚wÜ@Ç’'ÐAï™ÿ ›¾Œ› æ“soeH¼Faú¨Nð;Cö‹"E×J™}¬I1ÉÍ7PHF(¯–F†wßÃQé`tôTÖ&¾ä9+€ÒPįD£ÈìðÔò 9ŠLI¢Xzî Ãz[ #ǯ?ÉÐ}r‡sNÿœ!ÑÊœôé3T=o®JH™âTo~or #Oºå];Þ1\Y>gÞjNº{«øt=ÇÞè«U˜ÂzW{¯äî¿æÔ5›)ü¾åü¬Ü¥«[C«‡2T¹;¯ûÔ™KļÛ Sy©}ô½)r·ã"´KÜV;hÅ$|hîUr!Ñ… ƒþ˜ß|(Ï¿ “Æ“á0»„ñ/k´fl/C d¯é¡Ù £’ó¾¸ËôâêNþa¢5±õ=Í=˜ ju®§¡Ä§oâ8Kõ(ÀÓ í"ãU}&¾›$T·52-Ty=ÎjDÒ²º£¶+[Ãzz^#UzaN74a¼8WxÆÕǤ~2ÁëËB :`ƒUÒH·S{ ñÎ'ºÙæL§U…eØy-í²e@ÒÞ#bšÈL¬Dµt"‘Øå{Ó“ FmIdÀŠû÷Ö¢õ*¤Ð¬÷_CáÜ?òô- àw¸oKBý8Fµº½( ÁI2U‡ñýz'—øù jƒl›îôñmá}Ý.«  oéEpޤ™[ãÀ8I×üÔÐJUÖ A‚t²«¢’fW<üìg|vã.¾Â@ÒžO~í;¡++Úvçó‚·FûåxÒÏyå¡®Ä#¯îœwÐ_rû"“2*†â€¢ÈU}ªhœQ1fI@ó¬$†‘¥…¨Vš`2X„]é„]þqÎ¥Êvbóùíd‘‰ë  Ž ‚A¹qu,ñEÙ4ÎÅsŠŸÃ1e»À¯>½\Hí'­þê1„EÆR! óÝj* †L®øjÙçɦÂ\ÅçÉy] O§DU5êS—å¾ÝgT±ö!8U4öiÊ9ûÍ’W’€€Óâì›eê:Sè0òNä[måþØÔOôþ’n¦*0²'^n&C&”õBÄæ=×î²bãòB…†ö­­1Ú®­Âð¢^kRµPT1êËtø”DT5ZLŠdéôÃS½äNz,n‰ÀFdØ= |ºF™¹>Ô1û%ƒïм[ D±µ]Nµo3 _O» Æ;ýKÔög#ë‰Há &ý>R|‡´Mt¸Ç‰ÝGnÓÚ1ñ¯îöy’º6gttУÒËy@ж9¯LÍAxâëÊѨҦÛðKÌ^0ôGŠ}WJ¥Å7²Ì]´œdöì*‚ú› ôfÌyK½æsFOÚÞ™UӸȪE`'92+>%œzÀ$Æè‡\ë;βü4å4‰t•–ŽbLà Fœ@Q„?NEé[±À y¦f˜M‘3ÑËŠLjÕ‡ˆµ‹ßbˆûG…Þ—§ÍJÅÇ8râ›i wO•£¡ÿlŒn€ùµøÛÌÿI5~³ªT³eµB_^<‚ÓÓ54¶{.¢h7W:‹B²žž#;u|32Ñ¢½jè<ð”NÓÃ+ð-Áu9ã}e×û€šd&6/ø.;í: ‘Ðq“!*Ò/u/Ó-^"·7ÞMg=êQI¾ˆõÞvcìÂí|~)îˆy÷­šROjx‹©‰à<«UÏuÌÙ>Âz\Ì ¤ê-(M×`° Êʺ¦„…»‡h¤„5·˜!´DEå¨:ä-Í­q·‹;¨Øv‚àñþk˜§²Ž;rEº¿,æÃDg^“Ln7l $»j3KN¨~ÙÕ¦è@­oÃãfîW@ô –•ßSÅ}Õø+ÊC‡œXŒØA‰õ…þèÈ¥ZuºÕÕˆÔåìC C¾ÈNa`¿‘`i=I7ñêì:À5”Š”óŽÕ '¨€¦L´3Âm¨Nߨõ0š³ž½(Eä›BÍõ?ºÅà½I$"Hjàé´I s³ðð7¬%#;[µ,±bß)jàîÉ6•ì)_ÅÔ³ƒØí§ÙµƒžN'A° lM›ž›Õâ.!4‰m/»÷-‚Zo%åSLzÄOW.:Iþî.딣SÒ^.š(SEÖ‰•lëÄ…]€-ç„ã Jƒga}®ö’€€éä+ÉëÓ½>|(ã Iª×yä&ó3á‘›VËë©ÝPîçÊÁ¹:…Ýÿò³ü1]%‰\ÿø¯,mz±C"ÝOF+(l‘5#›†{9$¥CI¤]‡eiêØÔÙÅ¡‹;̋޹ñ%-´¼I£ô€ã}[Êx†ØBOCŸ‰–ë’Ýÿ0ƒB±¶HªkŠ6â£%bvÔŒväÃë— û§¸¡ZìK¦î{H5fŠX›'aܲ© H;q|Œ±qòìHÓBë1–Ç›‚1~0Ý@%ae•À2 Ñ0é sqCxrFò®e†U¢a„àÒÀƒ7l Lð·q[¸^@‡I$‹‡2Äa‡ø;7רÞ`SªÎ[§»‚%ïloXjÖQEvÕ;vž ȶÁ\ÌàL¦Í]òjõèºgF«¼€)¸?ëp‡ä™)â(kéyIþ¶3¤9T£í½B°ÝÈ‹g0¸ŒÁÞìß3$DHèÐqõûëtÒ…8?æ~¥›oi^)¢†j߈m­«sÿà‡£Ã$}æfZ<ˆ"b0W¥¼s £jгuvaÿ"=`>h55¼ZoGñºˆåwúp€úîbÕû-y#þEnÀ†äå†+>®”vºh$r†T{Á»É¤LŽJ¸º“»ºúO _¯žri&y£Î€vµ7ÙµqòÅaӖٟخSÁlšPRŠ«ÉsÝ‘§/Gà†íGC•Ô<ÝÌÈ/÷?ü®˜m΄%ÿø?îñ [",àúZ¸Æb¸iÆ´”(\eMðŒ•kP?»„dï{î^¤]¿à~ÀëÖl¨gCk\V!+Ey2¡gú¾8ã#Y[Ú©µ*U–wÀ“QÔ* «i‹òªKó.ÍwkÆÌX`h²>3| b2„CîþÞ6‚IlŠ%®è¾p®aÐËÚæÒ4IѳŒU`:¸Êe6’¾ºWúyp1ä!5é ‰F@V çÇòÇOŠ8È"lŽûÙOó¹PFa*åq‰ƒ€ÜªT’€€¼Öe¶Éò+G{rAMgœ/ÝyÀ+œ[®o›}%&/9DQWg¦¤1Ê,bi"­žÖ¤x O ³I%ëµ­qØÂ³^A±/’ü xS”L+øm™«Lð“Ùž!»^»‰V¿ÏM´!É(Us”E,†‘ŒÖR'ZAš¨aóî{”B¦‘Öî[…äý}‚¬~+ù’$‰rÈÆnÕéo¥åžÉ0XBÍŽ=Þr¾õ4¦Ø=øY¦›ô{4ùd–¢{b#N1:¥÷Ý´Åí$¦DóU< bB^õË7ÜX˜µÎ·Yšž;˜T 8%úK)Ô9´+Êôbó*¦rå.qÕøª(­ÔdGz>æ¢p'­Áo$T–nlïüÞ2—»ðîPœ 彆½£{Év˜äß1<- WDc%‰X:q\…ˆÈ¤u¸°–¶??=O(Ãa{îÎMª“~Fgfƒ€ ?§ i†Õ?X–×R©ƒÁÆÜI~*šÁ¢äÁ¸u4$ÀoT»¼&¿çp'ÔÃODP™"¸¹gšî¯×õžêÀD›†,õ[c|­¶ Ÿã×5bví®F©hå&Nþœý91Ö²E¹¤" H£8*Î;éçÜÒÂEG*@VÜ6\4„¨ÇÊ Žø§Îã!ýFÅŠ ¹ž'Â0 *)á zзÔsXã&?Ô¿µÌ.¹wȱÁ‰ŒƒUÚ_/yM Þ¸Órs<¥$ nu<Þ‚íeAã!JÏÚµ]Õ¦°vöIò¾¹UŠ Þ Ü¥ëݲmx bÑùª‹fÍ\wÅñk•YÖ7|óÚ”ÝÝà¼4¯‘ë? ÖÑÚò$^Áï3rì]2¹>ôê] è´Ó›5£ºñ%JJÔápñe‡&yÇ¡®þ/äšWa ©£ýOÉÇ ~k‹Ó0R["S}K‚Àô7I7ePîdR~ß> ª´éæ¥f+úìž`£ŸV{Ëih`‘¶Æó¢@ÜP0¶º¯ýÏ“° ¾ñÀ6GçÙ&üò<ý}ƒ=YkC~V±¥qmÙÉõâhKŽžÞZ ƒuRô2o¬AèúÝɘ‹rÇ̪•Ž%㛇ùlÙåçöCöíW*§{n8r 2s Nc¤¼ÒÓdÏpJÀ­ +TlÑæÚµæwrÖ¦ÖD¡ð”[RM q*f’€€°RýëK+4+fݨù)7øšç1Ò¡!ù÷1¨ÒŽ]?rÌvóÚ¥@¨`_,‚0ƒÔ.sç|™ç½€Ì4td‰û¯"¡ré;âùs“¸Œ3D¯øS™ Z—y2’+¹wjÏ6Ñ|‚[É?Üæ~@³â§{PJ–ÅÕûô«#dϵÚDl]\=ÆFìýµdÓÌA'R±A¾áqH¯ÝgìÈvV³—TRÁ*ȳhô‰êî9F¹ÞŽÕe:º,ýâ*¹’í»’ @`$:šêÛ5r§IÒ©ðºŒTæ×'®™í\aÉÙ 8=:5›+ÁÍ|.9 ïF›°¢}„mi&dÀj¶ë$±xÊ}Ê|Fd5þA(üTÙ-ö¿‰kbow¼êÊçˆÌŒ¸nhö}êØÒÙdå}›_‚{ýÆä~c™ŠµI\C¶#¹§-9µCåÖ¿ùF’ìoÚ­ʳ $œs‰_é·¡pþ³:vÈ~J2b5ˆ/š'õImZ7{(4÷Zh/úz[ÿÁ-gDÊ·$ ¢ L†N}{SùV €m oÛ·ñIH'1ˆ&ØWº"GS™Ä«Aò?Y7]‚{œÈÍD],˜žs#ÇúùòÅoÜ“ìI†—ѹê×µ j¥ÊQ¸ùñߨWÊ×ÖƒœÒ‘˜,ý±DlÍ*g ©^†-ΆS³ÐB"¦'n§(ŽÒ2vÓ6Ê|¼î?_f…ªßTÜÙ~¼ !t €Ë³7â2!zN£˜ld â—!BXÉnÜ¡Z_Óoµf®ºz½õ>[†BÚÔ†„WÜÔTÅ»ðïbý›!Ç ?ØK\E%WÒ¡/ y¼“Q¨êyFÙþym6ü§±-#¨eùkƲqKÙ…—å{ü&Š;œ^DB)„à o L ¼¹iÖ¹û*ðe%lR9 ÞÎÈÎY¿a$I݃ H™äýfSQ/þˆq9Ó=Ï·g-¶·Äµ _â3,Vµª\0ÈTšµþï{ã›âHKPâAºˆ• ‹ 2”'0 ˆ;OvÄå˵>¬æÚ’!8²™/ö¼i§Ý~w@К Ž¡=“ÇÈ”iRÉ7’â3êÆ„0L!*—_!à”©hôzŒ×¼¯HÕãL1iûW¬=¸¹™…J]ájvhZ>äŸá´×’€€ÈgXyœž_º.X!t#œÙéÒ Ð:5ðg”tà“‡ °÷gº*BäÁÙ’ÇE¶?{áeŒ”‡|a²–‡ðZ¦ Ã_aAq4ƒQâr ´ÎÌ*)úwù1QUù4ûû,^1év9ƒ‘ØïÂQ‰«Œ »ñ—dÂFúX¾eÁË=¶®p‘N“´ÿöL§¿ùœN7Ë):Þ9ö"8ó¼'*cÐÝÕ3¼âcÛe ‚+-Á:;©·½·¾+±uLñûéà’ɺ82K1Þ? ÛYÉ OÏ»:U0‘ùx5¡5Òiìµ%ëg%ß4„ÆLÈúÄ\7 Í¢gKó¶åHf#ÉS$Š$bS 8kè÷¸µ,H^Rä  Ær&Ioï®"i ks·7HXåˆwhï“Ûl>|0,0ù­¾B›,:*¦Up²€ÙëQpìé[ƒ%Q—G£RŸbR¿r³ªâÚ¦U±!}õ^2Ô}âý+“¯Bm}ki ’LÞC"n›04ÿ… Úü§ïòIèd²é-–ž1áøæø’Õ ä~L•M÷|N>A‚#°ÁI•°ƒÍ~³6 ÍÙö´HÈ1l.ÊŠï:+¨ØªÎ|Îæë¦3Õ§ü¯MhKÉ øô Ä{­_kKäwøÓOLèAõPV,ž/ ­ü¹ï5ÖdH¿ÑN¤®ÿŸÓ y½…J¯_ÓÛõ®åÇø¨Ø8²Àˆ¡Ë ÿñ¾sõA‡)eeÏ4¬¿3 p]w|AÚ/“™Š©lEÊPZºëÛ3;©¡^t'@¯5iÍ>õð”sØ5ò¤B½ÆíodîJTó6¶B5÷Ñ"/€ eôá걎 =?½ í´“:™÷Å"¡—¦Yînp^)ac½ñV¯ÅMòÈ‚-4²–4c\Ãݳ‰ söŒŒuýÒ&ká›íÿðw­¬çùE­2·-xy(ÄH ßƺtù/Kdœ±ã ¥tùß1¶“xóâRÒ{Á™+ '=WA.±’¨T¹Žr‡áJ_˜f:šç÷l^¥ŒdrôÎH`=x׋´“É’–… :õÚ93¿xåËâ¥fwÊo?²SÒ[qùÅß\>"¶$ªý«Öc¢%¬ïUöì„D@sê|³,_ÄÎvކÙwûÆ–Ö?s~’¯»’€€Á,®%Ëù·êѸ•Ésÿý_F-4û%µsÙì=†u ³7I>Ž@Q—¸;Ê—4)íÃ$½ŒËymï õ¼3§ vý7kÉ„ W F Oܿ֓ĢΞ£Ÿíš;¬œ;gèò—‰r5Zÿ<6ìÑYaÔ ÇH·âFdéÓhpª–Cö[Æö£44ÁG€Œ}°´‘&ÃcÎùë2°2Úw†ïa!í‹îè–e¯¼ö 8ʯM›<± ÛFƒ¥v­FG’bm.Õ2ùij©KÓ8#%i²ï¶ÝŠ«VÞø ñð¯eo¿lV¾p³C’®ß‡ -@+lꫳ®ÆÛ9tÒ†-sCtSƒ¿¯³.¿¤NÁ Á¸k­Žšäµ&¡üÇëzØ3Œ-jä\‘àT Vr³Î©X›¸³Î"Ñõó>»Ln(±ß݃oø©=Õg¿Åvå=AªœU9òýõ¡D“ßMÚ²ƒOJ$ š@ãä }ëH>‡\éc+Ò¶èß{¼ 9I'DÂŒzòœ´/¨bi‘HpÅ«[ðxëc¸g ñÁ"«’q‡&¡q-Z¿\$Ñø-S@1 ØÜ‚W…19&CŽkù'± fT‡2-­±E¸C(_åûn³Qº4¹?:1àJíÇoqïÝá‚«Èä‰ ÓÔBõ–ÞĽò)m¤/—BEŪ¹Í†¤Á€eë­ú\(\™O£”2‹­\Lé“b‰𢋣$g½i&¾8ÏÂi¶ÜT×Y˜^ý›Û¹È裫8`zúÊ IÍa¦2§üÙŠ{ û†ÉÜ{˜¸‡t‹ö°Ð¸6ä}÷b-’5éo…$kíÀ:MWµx|¨Eî›6”çß.ò¹²í`r¸¸¬Ó›€³˜é&¬,™Œç(þ³Êá²Uó~‘=’…Žúûáú¼p_ôF‡Ý—Mõ?¦üÌ€¶iîÑÄh|ÕÜ’€€¯~(2öÛQMš‘›Áƒ¡B7ž‹Ë˜áp%|ñF\­nΖ/7Á* Âs6‹^S[,6OŸþÔ2E/gZù–Á@¶¨Â¦mêZ,ô@µqü0¨ñè"lÉ=Ù’“;µƒ?KƒI[wJ3užùÙ{àd4I¨¨èô‰Áó#D^Ô¬m¤©~«ØÔÕ'Ç­iŠªÇ Œ ΈûÝe" #˜2¤ÔË6ŽV‚òAsçr0¿DP嬗ƒ1óÊcî•×#•fú‘5d\¡í4CQ =ä™S¡°ÌûÛUŽÖQ\ÅWµHŠTíK¶!–uPÓƒe •á'-Dþê±*¦GǕ«æ´Â¯ï¦¢Wí#uÀ‚eÏ©o(³-»ÀóÙ–Ÿl˜”µÚþ #6…¼EÖÉéxk£‘#%í¹òh¿yP˜*Êê|H©‘æü’œ¢ U”ˆô}×;7¹Pm˜e·ç8çÃ<Ù7òƒ18áìQ2à8PZ$4%øÿ.Fî÷::gñ<´Ø/‰,3ª4fF’­!Ù;>H@s¸-ÛJ½¬ûY›n/…í¤ÔXmtˆÈ1µ ôE­55F•‹,+2zÔÉÓ¾&àÈê¥ñùO ŸÿÊàÎΊB×}æ'Q=ÆQ:¥Ž{7+Gv¡×¡BãjHºì¥N}?í\B•%†v¦š x$¾¹]êLB‘†&'5áoLªÇ©¸wü/ÂÑÅ •Qj²¨ ‚·(¦Z1BŒËî_[%±qp(‚¦þW€IASkÇ:6³ä$S=Å¿³Ã®òƒD`ÃìK­›‚ã]¬ð%µÐY2Ë® òiÚå‹ðúónXtÇߪ»oÎÂò@èuZ­>LƵþkëÿ%áCb´¶²f³µº¼\­ß‹ïy‹çyCÌηñ†iÌárqÒ#Í"è¸g½9ª™½T*­ËJ/‚»)¥ ûiÅɨÂ87à>6+öý1á…L¾µBtñWé5yüOݿĎ™Þ{K{Ñ?á+¸H·¶ÜðÌý¨¶ráÌMqÏ’³ÆÉCäÕâwÚ]À‰Á &aÞËڳʸÍ;…׃÷²ý tŃ…•ç@¡/¶õ°ì zžG+“ö.¸qÄà—ìÝòÆf!’€€¸“TÆè£u–4Ô(M&Ûtðš8/ ç I(*OßþÀ÷V†'û¬6A¤J+ ,7âíw}NxÄHüb¹Ò„ëª{‘w&ð-Õ„j‰%Õy€°ÊÈA¼Ý 7oª†áÎã¡rxÚ³Æ7[JÞ6 ÙÜÇ5;žÚ“×?Ú£’ƒC]¥Hñ‡+ å,˜×âyU8RçPØýˆ®Šõ:)˜×\àØ™mˆ¦[ 4ò6Ç_´X0§Á$ªñ›:ðxe@7ÔƒÊéÅxqÁ·G•þ«ÌvQ˜–®sh%;-Ùÿ‚¨bõ˜ ßç{Ã)¸áþ.͉ #tPÙ¹ç!ûl½óÙxê6FýËùl ]jÐkóÿVÍpé’gæ:µÛ'{«ËÐBÛfq&¦ñ(…ÿ|†ŒYF3)ç(¾³Í¯òM ®Êåß/äÕtôkˆ—ì€eÇmèhì† Içÿµ±îzöØþÝ‹_¦«¹³³¨-û²·7š6z®j1W/âŽÑFúàR(~Tz%\©a‡•Ц¼ÀŸ^§ ü ï”útÄ·Bã[þ4¬m>˜]ùBð‘Oñ‡×é[§Rß…¤ß[Fâ'1Èq⇫¹É2~¼¦ØrS 3§ò®û (5çëÛpR &•nÿ¹š;ÎWTuDR„GaÆë¥±jˆmj %Ûhö†¶{ódeußÂTÔíÛh!×pe€ýè\vW}ÄÓyò”ø[ï`É:É;I6å®ßɽùêØÊÒGŽ#xÈ)máEA±V'§ÅÂFÅÆæïé`í¶7‡oô ÍÈV·Ä°$šs Èéºd‰ià‹±çÌÿÏß8õF}ÞÐI^–wV;: ¼ÇSWwVÁšÚöÏëÑ R*Õ†r*µoi”êþñmb,A”È€äöêu-í¯ö¨Ð¯§ZZ¾‹ÐG? L(‘%@+ç7‚³óâ[fŸWÇõËgD;$­N Õ¨ëó ÷êûòvh±I?¸÷­›ÑFÂLþ+Ór›Á‘zÒ#Àá,ï¸ÉÐQG ÆÇ…ˆD¥⢋Õ38â»3f´ ÍF-eöy˜¢cª Ͷœ>… µµPˆY\U»“àu{9’JLJ˜'©,'·™à–µ¤æºÛÝÐ’€€Ýô7+‡o‡°âï<˜Šö´Öa¶d= Ì}¡´"_øHX ò9w±[ß—`®w9¡ê;TÂm]ēɥºEòG¤š}þþþNL3W=v}êAWÄÍ÷"D¦HY ¤VE×m3Î`ÿ6Ò ÷5æz´ŽÝ7)ßJ"ÐÕ/GÃ^;<ª: Bñ?r)@Ñ—Pàƒ›æðLa‰îSCj¾ ´æ{øöé8²|Ø;44ùk°ÛÚ†#˜Q_×ûœ,®³ñ§Ü@¡«Lu :}M”aP '4„å²Vrk!ß]6´ÜO×¾áQ›lf[v ­O¤˜ÃçÛ’Ujªq|y/„ Oè·Ù*ŽÍn/W¿º*™º®œ ¨eMÔZ ß ÿ¡qŽ4²U<.Z >½ýh“&¦hèñ´_ yt¯î^Ï,h*ùÚÚe’`OKn}6¸™qLÙ–"ï5üF†~¤ šÎÏ£d•!o!.‹$ÅÞ˜Qgç=Ø­û~¿[•LWêù&B‰ÃFÖÅù;ÿ&”|OõšÚû"a]Ⱦ†þüÆÛm2.¬À"‘ƒt)üI0_lU>+¬‘¯=Ô=K‘'¾Ò†;Äçî ¤w„°¶¸zà°ºøsûs¸Zï|c§´›:i8;nÛàz{‡|CA(ãªô”8{ŒÌÌ¥æþ©ü9º çÁ¼£ÉäK²ÜyÀ@Øžu›½<¸¯Å „,Ø;ÿ·ŽÖ*åEøÚÆ;&ë÷üý ™F—!9¥ü~b_œí²¦ó©ÅØAKF`|b“îý' Eh6ƒ"£e×0/a9̯ZªB™ºK„°ª ô=ýýîÌ™¢9àúé=èz6\‘,ë|±¹3æ÷4u PWeÎ;²ï—‘-Üÿ’O®Ì¢¨n‹‘«ª~È—fðxhÞÿ$þ¾ë¶šØ J>Ç"i~{:Ò>è“Èøù»jÖÖbóŸ>Š;Øâ§:ë]LeÕ;iÝó–z²oŽ‚«ˆxÇ-]Öø@t©)kÊkÛ{†$­|Îtô¬ÆY MÓc ™ ŒÌï¢úT{º*Ù#Ã[79âá}QÊ4ñšpAÀ.»B(MhŠÚtd:fMHoÚ½›ƒ_kE†Bû¬ÿËï ŸÇÕEê÷þó_bQ°x=ÝÑð ïøàçd’€€èXHÇŽÜßöFu´~š#ê?§~ñjÚCŒÂ¶³¥§7Ç\‡í÷S‰ÜEŒ°LoTyñƒÖUó}zŒ§Ø·r÷ž’KtZíÖûlÅž?s=‘È9¦ 6î1°_pÒVÎάQèî{Û¢.È áq§UJ`|'áüÀuá÷ý`Æ]wFòH=<€•p*΀̉äùÊ@öEUEcpz99@Te$#’ÛIsª±Áã*"gÏ¢!«òX—b®̎׸ W&`7b?8maåoÞ4ìþ…„¦¸ž{ ^þÂ…ý/É SåMÏOË%b³Édê!.Ë8î-y5–®TÞ‰;ÕÜs0lñ={·SÝz—žWüÙ(©†Žœôðþ Gf3b&Ž$–t^‰˜@Ű³Àpý:ÿ‹C€¯²» vÜbuŠI1#_6žÀš0%£?H¥~++`©-ªa)†Géø4vîÐÇÞ¦VÂôÀéY;`È TŽ «ÕIÚ¸%ukÈsf6T£Ÿ‰iøŸÖIqQŸGeú‰IHÁNW{=ÄÃ/1ü«³ä½ aWæí Œ±›;.;õ ÕÛNd±É¶Ï›:_£k/zD¸ 7a¿W0@NÏ÷>ª‘®ÿN1`üDZA‹9JÕ}@êksÿ‘éÊ-:¬èIIä©Ú2•ɳ]zŒvqç½­va~_Ò´žÆ‘»e>X˜Ýp¥·yn`kz•¨ÓØëžÁ¸3,ÔO Mÿ½ Nmç#ÏE/€¿E¡Åp”.9@yÛÁ‘q ZÇi橨þV§N!ˆÐ».ÌÙ®÷è¼0V§…5rÓBôžDæÀg«Ì û«O² P›ì|Ô*ò,ê5Z;®ãcÆ3™´‚ tÔõ–²{Ц»"?Û8¾à?ftuÈöºܟ˷uêߥ¼tí…ùóËÎD÷úËÛYPÊ*å?e”3ÇH¹Àý· ”ždéxÃÚ 3·ÂU„å Ûy#¼”u @zI+ÅjËääævPõùjÍ€ûö¿™” {—É£~3“æ´Pßk#ÛùØwß½Ö#í±«:œ©Ò˜ÛMÙêš´ôÚˆ«òEQ~YµŒÈú! S]u‹#5T™a ’½ñ¬nA°f?î¸G’€€ÏbêþIÂyË n}BúZ:¿?þ€øë•úËÍnjðÓèÛÓ2ШPøü( Á´ñ¯©v3}ÐÖûo¹<ïLï5—¦/S¹3Ýq×Rª¢Çvä#½P$1p¨Âd,H£)í²8} |NuåÅíîçÄ.?¹þ³ÆŽò’™€µ•–äÃJ¼®tÓŒ\„~È{ÁøþœÜ…+äyæY„ýƒ¯ÅWïäü!Âòѵ%ˆŽï=¶K*%Ï5ÀÖfüѸFÙød½…kóf×­þCIbÄx¹å_u‹ü3ÅåÑD„V‚69§ÞŸŽÒýñÜÅ 68ð ²gG¬³vÝ[¨*j/H8ÜKšõK±âš—‰A¨Ý­ÜÞ›{ŠÒ/"÷kÆO™A.¶ºEÂIÞ!ú>ƒúî©r`z#Y)þ覜1wí³ˆû3)bbÜÅ&& Åâµ[g—캎T«/ä/V%?Ë]<’-½¸ jå ¶”œt(fèC§ˆðÝcG8Bè5B¯‘g$ÅUÁ§¿Šo,Ù‡Œ˜ ¹r0ûà*zrA=«Y﮿iºVql³g„[§»a[‡kÌùËMV“›ƒ!–ü¾y: EÖï¡vå¥Í›×÷¡Ú€£uÒCë¹îôõd!:ÐÕj#íHìþ•ö‘_ðºmnjD XKÅêÉ4ЬÛ:kD@t7©ù:ð&%‰é8ÞØW.b „žWÂÆ,o!·ÔÍ'øsÈ'GE§öÂþÍ›©w’·^5 æÇlZŽÌ1âåYP‹P­¿È !Üã4GÑÕžq^8-À‚òÜj‹Š\Ÿ§ÏÙÑ‚rP„ÛIIáúâïá‚ô;Ü9»¡ QÖ²%“[âÇ‚TÆbÆç  ×k©=D™©¡*ÙÒQîlhÝŒ_ü)9J3ÞÀC(x|l\{\'z÷JŽ ø*øš@g.3µQ:mÍÈ¿ð|Ö€Ùe7öc_=ŸrÕ ?þRQ?3$„Ð -õƒÅã» Ñk)ËaT‹?µ@ ZÔÔoÙÝä½Ã ÐWY ß/I³î=’‰üýµàáˆGTC–ïhswì粆µ Ũ ÷âŸËœ9Ùhù¯ažA¥|ˆlrùÄø$2ÊÜcÿîñmÔ÷ “!ÕQ;NÕ•cƒ’€€×õá>î¢q:•Y‚tI¢ èógᕵùiõQðõ©;ÿ_O1¡jëŽf—H~$.GDìèt³ –`ª½É~·6¯™¬œ„ÈLjjŽœ#HÎ×!Q¶Oò¾Î‘{‰OŠéyßÿ-œ^¾õ ²øp¼ó0êϧw|Öö~—Xp²öVÇÌ1lÛÕºB®,yÂòènZTû¨ZãÅ—¼±¬¬½¼ëÏg‚Ãgö>½Ý@±ëAÝX7•£­d°kÐå@j“á`¦ HÝ1ê½Fæ“­ÀŠ)øžAîWÿå1n‹˜é‚§ý>"ÇÂùùþ²>€>§<êqæl¾©´/ 3ÒÂú¨û.vp¯|_.ÖOõ¼ŸWdUƒ Ï’€ðóuJ>ßù/ù]×[m [Š_w\[)­;³t-I·²ƒ:òÒ{Qé 2üB–Сڡ1¬-ÌzòÜwõ›†<õ™áĶÀžHáÓ:œºv"9†s’ëËŽÒ” ÆUÛFŒþ†h¾ã3ëÎMàcõý˜¢;„aŒÉ SÑË™”C†`ν~¶C£Ó¥Q£ÉèA¾ÔUÞ(txh20_4ƒ&Å£¨Rà§#ñ¨EÞ)N¡,èªp2½ù`ç© *ÓCM;ýÖ­ÙÓi½÷V¥”™.ñćÒ)‰·DÍ›1óöe·T§ò¶(èÞ“Oâþ½ï{©BòÿB¼jd~ùdÃù‰±MŽI”"¡XÉEryºñWñµ&Åßs<§Ñ<šÀÄAR9v‡ ”ˆ{E -ň’ ŽïÚù¬á;tã*Ûãò£ÕRŠ­J‡w%wÒárQý›êÜ‚NÍãâÆ®S®Úî÷ÈÜYÿ}ÄyDqÐß'øLÿŽŒå¹` Ie‚8ƒ§ZEô§ªæÑç‰5 xø ‹é[ïìv½Þ©-`h$Î|à:B&Ö˜þ5lbL¸^iÚ£bFíx2Քų\¿Y;Ô›1•ÊiÈ;Âà½.€üœŠ™Nq‰#¯!“¢óKReBDרtM6r¨ÿÀm’´Zþcyä_e€ˆ¶F1´?½]ÑOöµ82Ío9Ýõµ«’™6ÂÞJApZ\Œ^¢u1ó¥8w6áÞGŠI÷Y–ç|—•8<ÿK€óÿÊ6ýNØ+|åñâU—Ö&Èi:ÍÒæ’€€Ó¢zñXD#y5/(Ís¸Û欙¸¦2üƺ¨jÃ#:…T_ªtrøp¢½=¼ìoIÔܾ³£€Qq!û·dök—÷yW;¬ÃŒ¶’n¸s‚b,ý&= °Ã;”²K9{ê®p].Ô {Ûa÷‰¹÷ô"IàñR»qr/¿Mèå•Í[hpkbð÷Þ%Ó`8…u_Âá>ÂH»è?ãñÎGö=]¢ ,ðŒÙ9ã)[˜=Ò³Q†²fLb@ e…ÍÒô _­6 “Ž:7;Óì£Ìì–µü«F+N€tþ¾¬–¤¹®Gš×MC  ¡½C3Ç™ªÇˆÒ™Xï›âÖúB|z§È“>¾I‡R“‰…QmŸjçô»„G¡O¸È8Ïy.§dOoƒ¢*õ~J¯rèÑ„¬±æTÇŸ‘;ðñÏ6%«ñyJÖêÏSgÏìSóˆÞpù+žiFù“À©ü÷¸âCsamxVƒXÓQcziW‚èËÛ^ãì¨VaÝD=U#RùA5,‡M¤7K8N.*|Åk|0ƒêÁåGž¢N óKÔÊòPA²/0 ë r+T¹|á‰ü>Ž»7ñ8û>ղͥ!”ø½ñç[#!(ǬܜF¾ñA¾Åâ/ñ¥²ˆ£Ÿ]N·žâf{tŽñýBâw3– ͧ(””åoÅx‚æ"צØŒu™öbN˜d ¿î]ôý·½Çö]R•åØýO\ ÿ‚õ€}áÖ ëüwMÆ#Rœö׿ŠîÌ‚úì>Õsö*öHí†(Õ5˜B¸`öŠ(’Q:$MW¬ƒS8§uÊŠÉU'Žº˜ÕìZ󣶸ÂÈ×4,oªZâ¯þ+!QçÓè*Z¹° «õ:ãpnA¾ˆ%äýôÎÊG*ª—Há¨ÜY¿i ÉCübKˆÔ_ñ£¢$:W¤üØÀ¾+Éœ B#¶5¦Ó"8A\D÷…¥ˆÊæB“€PGþ¹Ö¸’T-×¼Åyn¨½h§Aá8>n¯•KG!uëf|‰4â\'MyNÚôÀ0]âOz‰—îuû2ýrwÅ®ùÕ´…x¼b n~övõˆÝª|Lp”öd‰2^Ü‹½Wâ15U^ÿÒî8†¯õ›žƒÜþ½ÞN4mïÿ²·—Â[NÒ’€€©à¶ŸÝ`[Ë„tFYï'pyzù{¯EÙeiõß·"ÿ"å»ÜGóyŒéWdゎèГ ÿôèÀ€BX²dýD¿åè®(Õ@ê\Ú#8Še" Ý¦BF¬ºddOL|ªU'«8£AÊêùm•š>SÒÞÜ"Bn94”À¤îø—Ñ·\á EJQþj¹² ú5swù& Ò‰« ;AAœ+™[aL˜„iÚÕµXr…ÓÁ@l›Øù?óWl¬$ذëSݦO!Yã‰ãC¶4Ã2ÀTË¢ø\„¥CLV¦«L>*XLTÖ-n`õµ¿4V7"æ™ÓB™F]ýUJkÕ¼©¤H.³¬ Ò6½¹_"\×fIe·ó8²Áj£|%;®¤à¬uR“Ï>pQµnutØU1tv@ëßñGa©-îåpäF˜_§Õ^Á¸±ÕòPôÜŒd±Ùd+åÖmK8Ò†ðQª3ÆìAB»_Nü¾ÑË–SÄãÁ™xÍ$Ü„@'-<äÕDӫʘJè»v¦œ—z´ã]ëç]x¼¿‘Od.4>êZ ûÜn¥Ý÷THÃr¯ e°†#Xƒ¯ýß{[4Y2Ãkñg²Bèë˜Æh‰µ1ô\ß$#Ö@ÆÏ·œá¡öBf[(]Þå½\ƒ ¥ƒÍᬕþmÓÜ7«ÒÁoN ³Æ¢$¼4µh%»Cìà×EGrŽ@®Ïš¿f)}[alz7ÏQƒ(Lbå[ylÞäû:G”ŒæŠ~ÓþQä8C¬‚;|ÂP,76[.I`ƒ÷´k°yÊ” ¨uô¢èäÞ;ÐvÊ––øU¬,Ê-À´­OY  ˜ƒÚ*¼í$ÞzÎFºPžÄHCëtsËN‘”«UÀı"Y?…x¡’iýÆŸ{£<§*C”$§Xh5úÖ W‹cL_Ú.´póŸ#>Ó÷/¼Ö’‚r˜zƒVC0d”Æ*YU¾ÒQ‘ñrÔ ¥wjéôÅg̘ك|yk¾q¦*)ý¥-é­®š7”zùSÛ˜ .cM{`Ã+…ø¤wÑ¾ÜæZÐ}F¡˜ûƒX»á@öÓ pªWÕ1? 4!pçåkÉ8á9ˆ•€õ Á,A•Ol/âh6ÕWž62ûQO^KˆUħkkºáçnY?m)Ʀ #Øà’€€ÍÖvc‘Æãùø;lüb˜jUGÅ\¥ð§ ïÇ;;û"Îfxu‰›6íg¸3òÎuãø`µ5)_"…ýdÝùã}E~ïƒ6’Å•mDÉÀzcèR6OÜ Q“ðg-]Oê6žš¸º yMò¥rÓÕ{Ùñ,\`Õòm¨_ŒdsxDí̳ñ|Å„œë¯”[q~œx£±–]Ìr0%eZù†Êã9D룿Ò’'¡\²ª/™4:@Ú}hË÷ªöW…* 1›¨¯žzåá%ßÓý¡nV”@Ž›u²Ñ¯it®j`hÒlß–í)P—,ªÂºcM_ 7Ÿh|ÔÜ¿ÀqÍ~E•=œâ=ö]›ëÙ–b&æpäÎ ¨î¬ S-Üp¾¸k;…«Ñ]ÝÐ ”%}W¨¥õ4^•¸²{ôûxü¿b(Æ:­6:? r²û¿ø­¾Äá¶ÎjŽY¤)§Ïèºî÷¯’è•袹;ÇXšÿX¤m'ÃWTNvêöRÌæË¿W6Œõª5¡<6]ý)(Cq¶!²÷b–öŸÛ ±^Ç`UZf0ëwî"Ÿ·ËÀ²›âh qà ÍvT£¯@Ô£Hr*¶“!ÛX{õÝ­m=ÍsA@'8¯©Ø•Ñ«zŸJ¬|Çþ”’×_äŸ"øøá8Èu™oûcÞÎù§ä¸¬=Ä‘©ÍP‚F®µ€¤Œ¶í÷×:¸ÜÏÆ¹Ò{y(í¤Ä7ÒöS—V/Ö:&l¤9Á Y¸ÔZ"'©ý¦ªõŠû«ÊLv¡ÿ#çβ¹ ¥‰Ú‡kÀ!݃µ=+53‚b¾(âÎó}´ÎûñøòC•¼H†€îø—«ÂƒØ5´.pJ¡£ìýåÚÖ±îJ¼áÅ—YUh´Ub®µuÆ£S4|Üjª´¦ˆe@z”‚y²mB†jZ‹Õ$Ás¬ ô¬d”t–­ô”ºþý¡^òR$©°ŠÚ 5IË ø‡‡ø tÀƒ ‚­ôVá›È (ÊVñ8`ò;…lþñÏÑ´„dÄö¯$aãœY5º0565uK7C³Z°Jî'û4W Ÿ»­8xEm¯Ùð%Ô‘Ðá1ª£…(³åneiГÜ\ž,§§âì¡wwr6È‚A÷Ž€Í»ð8ôÏþ¯’€€×q­IÆ‘zèZ€<55òt ˜ôšÎÜÆ;v@²ìú$,È6?”udzP*P› ô¥!»·¨£<—/àAúæ¢%¸Eq‚uÕW_´vlt%/­—×ßP]³ìe^3Qbøâ=ø‘ @{ÎRë˜ÔÕ­{ži;€åð¸ø„pÍ—JàìçAów ¼CI:B›µ¨±Ü§X¹f˜~Ùs0Ÿä!Køã:ÛŠ={dÈgæôþ.`}ƒîô’¦l(@†ôMÒ)"”ýnÖ`&)6N^Â2#>2op«V±Qð‹üѽ@YH¨v,p·R§gÔ¦¿‚\aT„“FSãªÒØÛ¼ùOXp‡Ð°bì´ÈmžçSn¯°FiÛÏ.8ܵv”¬ë ¨%#ݧ|œ²]oöðµ.K¼@½;¦ Xpt¶Â2b}LjAîù2 «L¯”OáHö%æJ÷#Q¿‚79žÇïG°œÔ³U*Zºüûþ1–]âk4‘6¥­‘¶Ñ¿YW;FösÆ+ÊÄ‘m¥ÿØMkÀ6¯…Pei²õWuþûúí©yc“ðÕ9æò,Œ«u35з gHt%th "kÍÆqÑÃöÔ¶Ñö+¤{a›wl{Ѧ’I¨aä Ÿ»íÓ»þ°Ÿ¢´(ü•÷¨á8¸¨ÒäP;ˆO¹œO™ÁhOí¢~Ôq5:žínf3>¾‰‹k¥-P3|UGË ôòO`ѪžbÎÓǶ'ÒXçÔ£¥Ï·nžµzïSú™• Ãu#ì Îb㻉,ªÔµ?î3+av¥d=¡u‹ÁªW“ØÃH'ÞM„æÌa¢¸77uˆZ<ì4äŽ6¥…ã2ØAÇAXSKJôÒƒmíf‹)T¡5°âgj¸¡qÊbæ~£¯“ø`œªÀ×#ãÔkMÿ9µù>Á%‘ÙÄî ]t¶·ñTÎäu é4¢ýѳû2R)9ÁÁ,FÛ¥0Ä7Ïù—:ªé•J%ˆã¼Ëü˜;C56„5+8÷œb¬Lë>iO{AüÞiù¡á ÇR\Ð’üïGoü¢›X—> 1ëð…Œ§Õ9ÿEU—Ÿ@š*ˆUTw„³{·¼êÆW§ŠD ¾|ž»B7}ØÞ)KŠ ^’€€¾‘Þë|½—û&_ø0öæïÞUv>îÊOŒæŸDçaÄo 6¾kAz㜃JH §™ý†(Á†\¡H¹‚ØÅÚmbîÁ¦w=FƒÏºÙÏw)OUÑ^ø7å⢿]²=ÒëEÿ®“ ^H«¥Ù)61¡>,tî²ÕvýÛ@ª"“$;œÜ ‰ƒmÁÊ_GÙ‚;ÐVg rÿ³Ü©ß/Yt¿¦HzþáiOä¤þjl –%§¯"ßûò》¬ NGŒç8/qø”.Œ™Å0Œ~æ—éhÖ²`‰¥Ieô‚Û¶zœïm=ÔBæž6²p…ðæ0Ù"áÛc¸ÏÛjšÅU6îygzãdG´ÎD6^Ç!!djZ& ´ñÉÁàå6°*ÕÄ)¦;9L¾z¶H™Ñe6m̈ G«'!g{ÛÛbï†éfdõ»›„dǬ¢h âoDûi±€íKhÍ™<Ï4²Úp{CBi–~Ké!¤’€€Ð£;µ4èãî™f³øúd»FÑ~Ú¯Ì/W…¤âNëH4¡Ó»’P–ÏãAªÍŽ‚ÜÏ_… r÷³_D*ÝæÂêÄzR”]=ëÐà|ó·ƒQPœŒ…\IYÀæjIåD˜w-“ìÏ"ZMg=o®‡²Ä£UÞãW(t¨Ëõáz(ñ{<ÐñüÂÄ!"›á;ÃzÿxÎøŽ%ÙZŸ·öy¨¸¸nŸLʧ¬) TT;;çn˜Qè)Á³Ow’$S¤Ÿãéásô­R¸JØ«d6©áü-&ü¸Hb’šNÜU# Ô4«d¤Ê¤dÓ )¯²ŸÿY9Bûeu¼ $ev„Üí ¾P.°ÓNCQÄQ“Áuë^$é|›ôn $¶Ò¿ÈÙv©[c nÒ'8^ý‘{î®uÃàAÊä§ #^oñsMsŠ^Ã*ó™ßŽÂ&W¢Ðii2Õ|À§™îÍÏ™’t¡Ð»tÂê(\6EBý—IT¿! ‘9.;?C?§&½©’ú÷¯ö{ ò[¨ÂÞæ‰Tu™ñ=\§¦j$Å-˜-ÌPéOì8žG™è§mÑöƓӠÆéÕC¥x&ÁÞBE¥Ö ò “©oÊl”ã6óks*ôƒ‡º¨ã%eÐ,?v»WSÜ üü;EDǦ¿¼f›‡Ü}ÕkSþTóíŸ! whlƱըMÒoæ\{ï– Y:É´!àɨõö7£ÒõÌa’[tUí÷EãûôÔŽjêóÑ{@€„šÿˆFäwCGô;®WŠ@GÛk™èW |ñ«šWyÆ™æÐ•Rw{¤Q[;«[¯&‡p94ÂXÚ¬O×'ij}ÿ™OX´P¯…æÀÏo–øz Óý8cë] ‰ø¸¸¹ „unÇ=ú°{çáÞ7‹74*ÝrO(K]„C/!ÂcáÔŸ°‰¬É¤HƒFˆ*ƒ¥(…¦6s¨ÙGKÊŸÖ„“ƒÿuNñø÷ßñð÷êÆÈqT*¶ e`CT£oàάԫe×ÙVy½È×Aå\Òƒ–¯*-‰Y(ü;(0w ÅxJïÞ#"k0,WtØÑ*}ðQæ«sG‹S_Ózx¥!E’€€¨náC›6ZyiŸÏçÐ^ÝX]OÞÍšÝpஈ>hn” ?ATåç ¨_Yï,Ù¢ñàKÉ0^“úƒUMzomÙ£j¯3‡"€G’×è¶Ì:±{ÒÐ%`¸}ñŠ ¨Ô~‰9¦xŸ:Ȇ'¡˜d?šð‚Þˆ ¿Hä× ª—z@ƒåY?@„åÂÞ™M‚*NÔñ‡±,Ò('nª Ûà%8É«B2z-0E¢#b{ÏØñ}”Ø´ój8‘¾Áþ+Ê™U”ÛüÐ\'EU«âB%œã rŸQŒä–ù\É“3 SMÒ@eZÏÓ, ¶—gJˆïÅ¿õ z0ã~o/è½ô*Gpûºž MpðµX½eÂÇÙvÍV8çMìŽ?wÔæ›è®te+´î‹lèEúÓ£z%Ô€K“ ÷_‰¢(Ñ4ˆSwI_ôÍšäñ2Ú+b¹â¹I¥ùjŸæ¿¡Ï,µÎÞðéÁó˜R‡ÑF*ÇnÞi-mGWå„a°™ƒ¯”3‡¤ŽÃ¬ öú!r¯¬a«Öfö³|mÐkQBZ»Û¸ó›{Õ"À@®â°ò¹Ñâ‘·[Øeõ EbmsK‡æ]é°NAX,EDjGõ¿£ùµ;‰¦M„×Ú$³X¢“©)ß»ô“á$Á`-V‰5ÊN9إŷHÎøj™ÊFåÞ .…j¦ƒ€¹oÄîÀµù/£Ô%{J0ÌHÉïƒJ4goí¤ cý‚3²žØŠÃC•/&ÝD“Ý›Õj»N”Cs7+±`B(º¡?a¦‰Ñì0æ%6^|PR¿¼ ÆµnÛ“ Ðîñ:Ë)åï —ìǼÿA%‘­ 13›éz¦¹a.3Ïúé\£q¸Ô|£8sž_ƒÏ s9æ|v·6^*Ëü,XØÕž”z°58€í€T´g!à:f~!žq –RJ&ÓîÔ³_7ÞùMªvª^P+-²ôb»¹;ö¾»š<á{à»Ö’a²ä~YäÚ¶P´Y À‚^…ÙühÞ\4´§±³Õ`ó}uøxªl–Æ|I,uO÷„À›7¶õV—$¦ËPŠ´±èJ¿tß:§½=àBRpÖÉÈU+ c0‹±Ú#‰Ê´ÙGSP.¶mšÌéÓþ4“ŒLÔï`)«’€€±–‡^¬Ò0ÕñiñuŒz„86Ãje5í˜vH•^{cîÌ—(7êB:x)ÚT}üfïA+5Îô¼þ ê/¢W¶tp©Ó6W1_TwÛŸwçü4ÑNsâC:þÁ“ðE›1&Ø:<&±L6Ï‘˜AAªû·ð3ji#JG5ÉèR‘%T\õÙ8r‘vÖŽõ`ÜàZÛ E ̶7îæ&¨Ýª¿­Ñ*³ÞÈ`)‘õ):+µÚÛ:¬áÿíÐ(uŽ;6?ªÜ7ú™C@àè ®-ˆýyYs~pg‹a²X(îT<Ÿ² Bg7Í;‰y4@  hº60¨ò·=Ow'§ß©FÔù~q©`;^jašžåf ‰ç†]çÿç)ôGxË/v~Gõhš«½n‰g~ãeÍSxë{zÓÈ` "'ŠH©.?)ycÒy@Åx–%[ß•YêÌHj·q“Í×V1mЖÎýÑB^ˆ<ýÜ{®W¸{¸ ¡u·ÐùBR iÉÀƒ¸Cx[ŽT(Ö‡}ÑÈcÞò)ˆ0#¥$Î’øóš›)&tR<ñû¸èŹ|à㙪7c‡©H`äBmÛ1dÜ~p^ Ö¬âÆäΊ4 ¢T¦ä›D§ºÇèÞ^‘õ`=„q°D±xo‰×5×ï¹i<@"š@öêÄáÊ2 çn+ÀÿbtS‹Ôýùý;§K<¾³€6±kb«´¥È#™D·›A%ø‹@бηN<žæ$†U¼þÀúÒ„ 3,ÏAWöãc1PÄ5W•;úgV´ÛæígÁÕ|ÆI)ç%ÿí¿#þ+ƒZ’“#Ò‰a2#’¹B+òÜáà½Í`ñùúcú¾Ú¬°¬³øB$È@O‰ˆÞ0óa+$bÿô]÷‡Ëk}¹v”À&Ë-•6ß\ÇO÷‚ $4OêÛºæ$úp,Á2adº6'â+lO˜zá1U÷s«»nÄÀC¨Yl‹‚UY¶Dº…ϱ«¡•ò£“äœÊ„1–C°Õe‹¤9Ziêy;ëöÝyëG /!Óã;…¿WqèHÏëhÅøà¬¿;eÁªŠB#ÄË3?Êóp›ÚfŒÖØFÌqC_–4S¶ H”X ¹yÍtŸ™áûäXžy™ö4ÚyU焃ʉ•nîvC¿Å˳)‚HùÀ™€Z Ì:Z†‹]úîæmäŸq ÏÈH];y•" ?n©CË…U„×r’‹Y„…fhš>«/9½¸“Ÿ Ž©IIÊ`å‹{Ê·(«á:À€éV,ÁìÒ+ŒŸ—íܽî·ö{À© -à+KEƒ–Iùd_WÃûýC¿#Æu¡€ ­¤×:«“âZ5n‚PTš<®*1+n™£?Ü‘ëYc8š­àég"«uu Û‘Ù7HÁÇ32Ù[Œ–2\J9Éû¥…¾4…_š4oV¶tmµêpL+  ¡Îy"ø—fã+— î/ó\9°½¢l[ ”°‰Œ„¹Òd‘g’Õuá]c;Ú¤55ÿÛëQ2(’€€çFhü¬=$ýâë©Õ{PíC/G‡ZuGsöijឨ“EúÏ—,nUZðç¨|iQÍx&¨UDüàU•Äæ£°³ÍM!Íë$Á6±w…àrÿƧÒbÑ|)sûK·³M¾Lõ¬ítGÞÅ_¼äKet¬ÅXᕺÅ/þ›Bë Eó~ë=âS8­Ï· b?eð«ŒòîCº˜Ž bJL”&©#ŒóäõÔúc¶ì}W«5ôföÿ, îÝ–0SANs=¦s ‘»ËÓZÍ4¸C%Q®ú+¿(¬á[YÏàIp©8Y9bû).’Y`ðí Øã¾x„4Žl…’xmƒþiBõÑä‡^1 ËÎïÀ· Ð|Õ]«ƒDÅú! À'•Ò{Ž WŸ#Í<þXh‚×ÈñÿlÝìàS9ãzÝ ™\0ÄÕóXó¥½W,´ÙPC l?Ž/šeeÆØïÓ:†âIöïÚ2r=8$MÐâÐ÷Âþ{|&Iãj‚eá~^¶–Ñ{wXKg ïÇô}à™Ü‡Ü2ŸœF§0êÁWI©‚Ô,ÝM)YÂü¹.Ÿ\eˆ¥'+虑ql6°ãÿ·l’€€ÔÎÓtD#|Ÿ¤ ©¶¤¦œ>#íaָ¶Ûížœ²¿ êK¾õä±½X­å´õ{f°Ê‰Æ_ žïCÀóᛜU"sy|_ß÷ƒéû¨Š:ªÄ𤨠mC¾Âà èT?Å‘¶ÎPŽöÿ¹¯ú¬ä™IÃPQízÆøj)¥$)P>~±Òö‘;ü%ö•ƒíÊ0e!‡V‚æ‡>2¾n¾mo°È‚š wˆtêHèI ÐÂ0ø›>åcFàóÌZÈ7í¿;·€‚ËPd0ó˜gyû< Æílø¸ˆi4OcOÂ"]¿ vmºiqŽÄH'œZÓ£ãÆ_•¿_c]•ˆöù¨ÂÜs‚«mÏQ…À'ê9…î·ÝÙ>$5>‹ ȸÊxª° !p™9Ø"¼4`›ñ v±`ðÐ!&Ád¼6Ú!ãñŠk‹uV)âF765¾¬žÎÆ!\ˆ9w>„ï4‰> jmŠPCJ\ µ×m¾Æ¢PôÈÀ»´R} )I?&Èz<#ù½z»:´ÙåU’y˜zZ%õýI¤íÔÓȼžuL†ºµ¾"–Ì|n3–þ0ó€Ÿhw‘^¡4p=÷Üä7) pßßÔ_j\k?j3zDTõ4 ?2°LèGƒ¸ZTO"&iÀJ° †)bÁþÈú9÷ ÖI‚½\q(ßǵÜ+\‰åî^U¸„\ô¯ ?+Ñò²±ÁÖy&*`Ÿ0ß»FjÍd°•»špê‘Ò©YUÒiN¹!¤ =ífc +ð‚{ƒ ó|or›ÌÕ!ããH 4J¨èZ‹¬™§´Áú ðHÉœ$ éÀ…Ò $EÕÓ^ ×Få¾ÀÈ7Ñn÷irL̨ÃQùÔo†r­‘IÙ϶&¸•ºÏAÖ3œ {/èŸÉuãˆÈw´ “Bo4ɉRf=!nå­^ ‚AÒ)ŽlÛºxJ€³>¹^>eó–ãhéÌþÉ Fs¢dœ¡érÐ „»ˆ=“h³°§YS'ªTÜ¥à-b³·)z¤‡‚ð¥\ǨÏm´zZ«\s/öt`|ðºXg²×ÒêÆ_Þ~2ñ…g”Ù G–aŒÜ_%åíäÆ]NB|™c˜½”=M…’—6Ôý‘Cª×h´\Þª’9³|£«$ú+˜jY'ìÚM¿.^’€€Ê¡¶hç_çýKìÁß-qÄêç Ïü% ÞŽÁñ'Bwq[¼Š?;ú&ºZYv%g`ìþ›q@s‡ÄNLE,6Iž(G³†*é„AgpÙeUƒÇS¸´¼ FŠõ^¯ibÎà‚˜ß¯<¬¯(®Î` P ñ½s&Æòe¼u.­æÈ„Q\ ´"˜Ü…#¬˜ÙZAŒ£Àɱ'äMô¾1[b£Wb¬@>tèá;0!pˆÂþ+ø~£d»¨]gŸ”6BJ‰ô óôÂñÁ|!<Œ $ëGÖ»´ÔÀOµjí®+iõü'4\‚9Dˆ}X)TeÔ5Þϸ´ö¼áíñ7X³Ï’€ZÿŸè q.šÁ"½e1RQ¾.а¨!£ÄðÓxÜZp>?„/ Ãý¤]geZwÖä ÃÝô!! †O8EÇ¢mµ°Ð·8Ìd(Xæ–ûè¹á¢§3-‰A—Õ9´V €{≥¹±Â `§;媖"¯Ïì£_í­®$b&µ:«Äd~HÕú@q¸´0rÄö 0Ê Û¼rmYl™à `PQQ´Þ ·ªsZ_v~$@¼§‚TßT] ôÒ-‡{Ÿ3¹IòÉžÑíP`ÒÜjñ_Èbi1‘d×ÊÑs[ˆsL^VÚÛ\ZhP‚‡gGâØ{à\!è‘r¤úZoìö^€ˆ)ÓdªD!rŠ©?1 %+n@1‡âŸ#Ânö"8=‡à•ËçáF”ÍΚ¦Âi;-TÿöîÃ¥‘ᙲuúÀ>7y‡’Tûç©Ûü“š*†MÌy.‰¦±ôë[~c+§ Äq2S“¬Þ&Øeß ž»ÌßIçúZ¾ÕR#…¥)ÊÎ"IÈx·Ênù膡l图zÕN¹ˆV!Ÿm2ü>5.Ž Ò íEXi÷U¢ÍcÏ}R¤Ÿ{qŠHOMˆ ÎKE4¼¥QzìxÕEùNÂæ,FTMÈåig|í ™ÿ#¬“¥ùœw¬ÀšÒðVéLyc>#{‡_Ýñ¶AÛôùé9ÜW[ ÀŵYe&ʰ¹Ðü.Žkê>9`˜a&Ÿw“ä˜dºêëeuCϤƒ±—þ»a;åöea| Ðõ ctÓÄ9ðD†Üp8<êÅ÷ l”RUFgˉ—+ç3©`¿2´¹Eœ”Ð2^6D’€€¾ÄÊ¢¸Ìí„kwl”ãÀ”˺E÷¬ÉïƒÓ¨cðÊ„i󔟩FPrô†Gkï†R=ÅÈ2ÌÙšFN U„þã6º&x¼‚ÔÇ0€Ñ¢ö·Å›÷¿ê²¿ª`·Òír³¥¨›ÅöûI4wñ2fMõ‚s¯çÈEŠ/r}ikÜpÔä‰USÞ0ŽÏÓcH.&%ºÆ†@è`Õ´›L.MÁ™;uïØx)ÒNJ;Æ*FÝGÁáé#ÏL„îÖkÕ‹›©8Þbëp»òB¸¯ÉÆ0².'´çôáȃ¤û'´b€QIù\ âP7ƒoò»Wì–ñ0Mag« €ƒP¿ZDI*,›a}is~Q˜l“™ÏÈ­Ôͼ\Œns%°lÊ(ìÙÍh´„yñbÊoDT÷¯gi´\Ùj¨ñâÜ©åi™©†™è“WbÎV±‰‹¥ú)>ØGw&õ£œˆ,Ó2AšBªUZ¡lhô†‚ÔÓ H󕨵"3öçÆk¿lÍ_\cè9wco¶eùò'Àß¿áJEV„Í|=£D,rXØ›4`=·¹®£›³34Šs®ó¾ç!µ£‹ù”ýÑûƒ4·‰¬ÒÆÃOxJNmœíÖ‰‚, dó.?;îÑPÅTL2sÞÞœèb`¾A×6Ý¡ÚzJ¯B-ìfKåí|±á9Ü u"¶a˜e똒<À‡?sLoo=œd;[äéÈÓ‹"åYÃÓ`yºÉqiì?F¿úèÅGgOŠwMÄ|ÁìÐJ¥‘£ñ)7¤òÎtømsÀxұ̣%„þÏÒ*­½e2ŽO˜ ß$€ðÿ”‡@ÇC‰“E°:W!gZÍ`Ú×SŒR\L+vzƒËq­Úhô´«ØÈØÏÖ¯¶.¶ë;V£a"œÃשhµk¡thž °4MÜ’€€ÞzÏŠ)®sRør½¡ 8Æèc›#&êÝT…dìbÁA^!˹ÃÔ®þ)1©Ã0ÈNìOÑœ˜Œ r„¤4È7“Ö>º&tÀ3Æ•ñÈ ¾o0ŒêCTßþZî´+Êi½t„°)Ê&é×"l‘ÊÓÓØE’ÈBÚÈ šÆ¯fØ'ûæ«Y°{r\c9rœé—ТLÏ߯BŒ]òõåù%Ѭãq©í~pt§H‚Œ{µê¿W¯?N³Ÿ|B¹Ÿ\C挋eñµ„ç¹Äê^/þÄö¤[È®’;§Ç¦S[³ÐY1Ù¦êqŸ_cL¦ÃrŒá¾‹á%#—E¯îT}Ýf0ï%q0÷çz+ü ×q :^µ<ÿU¸ ˆ§™úf K¨ultbš7ÁB§°Çqÿµå™þöƒye!õ²½Šg¾È¥¦;®_o-eéÀk‚íǧÓÄK\U…ñ5 솛ÂD_±ŠýFÔ~¥3‡•ëô³EÀ ÛÕ9€«‡ŠÏÚUZ%QEµ¼Ò¯±0õž&:ûÕ²·¤Ç£»ÎJá’—Ñ/ÌL‚ÛüÆÖ^Lž )¶– ]8yæ÷ˆlYO.><o|ip?g¡·†JµÑ £ä_·o¹Õȶ‰(GYê“-²Ú"‘•ꂹ>}C80?½êx8_¬#•¶œ|…XI …}`Yþ=j,0vï6„¨¹Ù\-ÛŒnî Qu·D{°ïDº)™êšÙïÈ]rRB[A¶ðsÙBÂûKM#ÒÿãW ‹q_"*Íã©ft—@fD&úb§ÍTo±o÷5Kà#ð‹¶[aŠ¡Ü2 °K‘9^Ûœwø^ áËî½þŽ:þ™ºš~ÙÞÉ:dA&)ÚËÔ§·ò/fÚJÚTô¿*H}˜5T9Gýk®)6 Œ(ã‡ÚX2àB÷\ánžÁ~÷õ¡ôMñ—(JZ^0¢n£w ÌÈå’€€¬‚IBç…w:ÿNq sÄ»kŒžÇýîyp‡õüM¥˜?ƒÐK ]Û4ýÕ ¸„7€‰¶úŽۆÜùç¥{Ãr¶;Q­/åƒ0Æ{Âj66Ý÷ûŸ^Ù c4FÜö¥¢(&è>(¥ÜçOœÉÉcŸ2|oV$œcxæ‡Ðð“°[/u2Óø¤åþ`›DÀ²(§Ï×ÃZå0¶jú=ªMú@¿¦+߉ cXN€)Dð EåzÈ ìÏ&¹9h¢Ë+¶”z™¤T`\^â¢Â>âë"]}càï:“Ò³Òºøð2x° AújªxOö ¿úð¯%¢IŒ©†$n)óÚÿ"²ÓBYÆß¹­ÙÔGyHŒ7›âÕÐ)…‡a“ZQ÷7#3¡§ÂBRw´Wï¡&;cÈp¨ÿZ½¯C¿N˜ig ¾sqÌ~vÀ6·„àPº44sŠ:}ŇjÌ£sZ%ŸM1=;´0zWûFŒ¹ yv·‘rÕS/Œ‚ Ðt÷¡$'>à§',¯>*¨Ôdåç-•P4ƒZ7vóÚ×͵\5žP¾b]Œ@´ËyFo`ÜPê] ŠY&Ç@ÖwnR°:´. BŸ«)˜ÙKø)5í@Rú. B©å7|²/èÛ•ªc3ŒÝ ˜¶iú>jûˆÃÛƒßТÕâ’]nç·¨ûªòaáØ‚—.Ó@u|Íiq©(¬zIJríÿ¤áXÂÊ˼ÎAÆŽ±¥`SwP•èx@z³ ’ºÛL„ü>Sw5V©X:Í2“²'¦pºr¾˜Á̦¨èþØC’²ù(¨²¢nÎ_7A˜’\#ÅPèx,r¥¾7?ÒíÈ÷¬ laÀ BÈéH°“oñÊ¿¨ 5+`#œü®éÒ}ÿ9sÊ2æ}žµ~cÁ>Ÿ–òÄ ô…Ød†ýÑþq¢»ä›wüé2y'UOÞô!>Ù}± ÿ‰ÊÈÅ-á}7Hç$¿3'ìZä í‹~°lFWx"+{•ýØ3@X:}¯dP‚!õ?â]ÀT8š‡·Èö-WúT;þ=sÞÁ(õZŒc<áζWx…7B‡‚¿c+ݤýʽtEÚKy×RÅ^÷0âÍi YšÅq”]ŸYiÏÖl\ÁÏB<ФÑ2¢”DuE’€€¬yÝ»q[u8Äfù»`räÙæì˜Wdýž¾]qWzdiˆlÀ}ñLwòTS\ÊA¶­Mk¬ó¿‘û†óÞ@&“<ÙnÂ5ÔŸ•r’–pKÅØ¨~‡žÿµ‰LUæFF¿ò\§,:š²¿¾=4‡²®ýl=ýq׸,lrNqߊ„é˜ßóÙ½<£E¼˜‚g3לn™ *IššqìÚŒösP¨Ag,è\Ãg‘ëÍi‹&6e-BO”ü8ý3ñš(Åu2Ù&ðq\ÛÅ{ÈÏD-Hóé}gÕO$È]¬Ëã?éR`í5¶6ÎaÐc}>fÀÍ"Ãi^¿Â¹<‹Œ6°Ÿœ,ÅïÿºêqEôâ*ßR~ß·ÛÃʾ= %ö»9GOtpÖÎañV®N;æý‰(×lvËû€»ŒòD 9'_¸ÔÈ_©ÈL&¯ø»n?\nSÃ*†N:Q~-,À^;ówkK¦ù…s­An×h%›«ñA®e¿é«‹½sgæ\å´s_šÃìœÍ½AÊ hј¼9ð¼±üÓD½$áMêäáÇÎV2„oNİÛ š‡J[ ‚nêh hvxäÅ †NÒ„?%¸ƒe%v#ï‰kÀv6m3–1Ë(«÷h ¿eö<ÛÌú8ƒ°gÏ÷(CêàhþìÆØÿ®ÚÊÞ>1¨)Ë|«uæšøãÿÄp«”LÞdëèE¼EÂCI„ѱ+qæN¡ÿÑbéÛMù[Ñól¾âÐÂŒ°š„Ëà¢õE~Ê6Ùì)³°Žlƒd wHÄ®v#Åšy)øÓ»kjÍŸé{XZ#LMY¯LY„uÿQmŠïÏ’êö2T€¬A’ÄÑLA'¬ {ɼ³»ÅfÅ£±ß&Ô+]*Bk®tUÞ78sX~,©ç—‡²K©”kÿ¢£¼NµÝ‹ye6mhñ{ÀÐþ§9»®>ev}3Ûí!ÑïH”üQôïq•ZåaR¸b³Í’€€ÏÛý0(õ Ól¡’„Í]'t~ÀÌøTj"è+5ûÕtzue`“Û ÑX¤¼ùŸ!ž7@öªÀÇÅ”×í>“öï ò+4˜§§Ðxø˜æHÔ%,¶§Ä1YøY›ŠŽp©RØm2îìÚ h¯‚<Ò•„£ybKº¼Ø:^÷ãákÿ¹528×V”Zîó‘0ÆÇwØi f·>n}ðÉ"ú&<û#¸Ð&øÅsb56¹õu½½wÄ^YAB®òø`ÁÂd63DÝ*E>N`U;¯ïèŒa†HTOzR–FX†¦µ±—‡%V¶FAë¹iCv8ŸÞ“‰–ë"T É©ß_²®fç­…-‘Iˆµî ¥÷8û$Zž4@ôXÌA°ÙUÕ:Y²”¢¼QãC,|ƒ æueǹ^ˆè>6±4ÉàV?¼AÍP5¡¤56ê ×F]Ù«XÈ<=]Á·ªpšŽ›u7/šù7€d~ÚMà~>Þ%_E™ZãÊ|>2V`{æËÇôƒ†Œ£›“°‰¥Æ.±ö¿aЇ»mGÙi£ÌiÿÁ‘ Ðt±?„^îdguCK# DçÅõœø’ލâWÃ)­¢™ü|)Óèš`´¿€¹Î«Ÿ@÷0ÌSŽñ€´ÐiFaÁüϵJK÷ék¦FÌ”SoÀ±ðk0@¡‹q’ó!lûSX³wMÕ»s&–} éõ,Ñôo ×…»ÆNrcP?ëž;D•4£0¦ÿ*îqÙØmTn¬Àçï(pÿ¬Á¥SòÑä·TsŒÉ|¿;Ô2D•ø|€î½I ™ u£’_E‹~ˆ¢†°[!½Ûk…„\»Ü|Ops™èGO Ç¡Μ0Œ3̲ôý–ó[²Óˆ¾±nBÈQÀ >&òz}Z°§˜·ò®«?½g+˜„µ/M¾F4-€|Þ‚Üžü'M— ›÷ahÃW;[?q)LkÚ`6Ý ï”7öÇt{”O'-c¾Ü_‹Cá>PÇ-íLáÐsÙ5Ä/§ÑÚÆ£)ÿNnúHêfsg%‡p?¡3Óðát¥.‚³?uÖ1º„Ùýâ­V®ÝÈÅ©ÌÔœL (rËAßkOе*=Uú$žðÔÚä, _‰VÈyÝ ×B>Ú/}¶d4…a9ƒme;_dŒó’€€Æ ˆ˜lXúHF±óŠÕÕk‘]Üð$‹káÁs/Æë¤"þ,%ïì"À†xâ*yU‹ÞñæFJZî£/,¸ª—CeÚ Æ~RJï YsrLG£XDÚk¨!û99™Œo[b?Î+Cƒ üÞV4š c䓆FImþ˜‘¯™¢d/œ¤JÞ ˜vyÃã<_.ùBÞz8aû-'ʱ8åu EŽŽj¤vÞ/F¬?! ü`¡xÒÀël>ÔÔ…ìvGï*%›üšhå|ö §^À§’Oá-s°6¶ÞëtÖ¯ý°Ì¥¿Jfü)P®!BÐñ„{rÏçÎgl“¥¶^– ʽ㔼ÚC©4{uR‹0€1zgˆ!×J´êû]7‡Y‰pylýáØÃš·êÂãMì«,ä÷ôŸÐÏJ ;tÖóæþH7Û?Ò¬psÜcÈ"̼5­‚îìÐPÕùY$"9–“÷ÜLgîñƒB4KÅûÜ'ÜG¯ê|düñÝЉù×3äÀ 5S§Æ«½œúÝ«záì?WØü¿g /þB}üùLÿ‹‰¯»¡NäÈú÷§è‚æ¬Ë…^:6çp^æMv}p fÚ8‡ùÖ±KLÓØ;‹ËÆU;PqÐ!._Gòû jÞ¤F,$¬æKP"Ö#ÐßòßQè<'/¢}ÃÙå#ÏóŸ}D·Û¡UÚ(/ï› j<…m6z¿€'´÷Ø9¤ÂDá` äZªÖòu¹‹Ã¨ê¾ ARóÙiþi³Œuã†ç‹Ïà שª½t߯Ò÷t,V1U[çMh->Ì4?c/Met<Ô¯ w‰(íÚaézc¥!l‚ Ì™1oAÜ2Ò\™wÈ`U/±û…² ž$ÿWrð´Šf7:.–½úR·¡Á¼R7Ã; }Ý• væ|Lò¦´éWÈ3‡D‰ÖšÞE±†´´½°Ï,èHçnÑÙaX†ÿS£!zÃjéÀ¼¥’€€²ò†}~œGU8¡¶ýG0EàW”h|ÀÞ<=† Õl 1-È®ew½CE\B2äc§ËuIõšþ×R ˜3VöϬ›"lôNÃã@‹Þ4›ºË|ß7†»œÂAò8+½bËuÇÆú;)¹¡LŽ[‘`WŽSgv ãÊ«ï 'Ô¸¦˜“åkk mR>¶¨)#Ûéøï­Áè ûü4<-ÌŽo w1”ƒ¸6iÙ[®'`o~€^ó€Þ«U7ÀœeTzÂ~%l…Lðܜĵ$ÿ|‡þ¡å¨Þ»<æÅ¯Èxš®Ê‡Sx¦½Ý¬‰SWyH1 e8d jþI‚–:^3jæEŠ/„Ó™¬Û9mÁs[#þðEúÏ×ÜxÃ…tª1bp.gq'½îD®#i^6µä­»C/F½qÐÂÀ½´9äì«öŒ° ¾"·LD1íeò0Çd²E¿¬ «…÷{k¶Rа%åj—‹ßΥ̲¾(O9«¹Ž%wØV¸¿“÷FbØ?¬ÉH wý L'Æý·Ž?8#kÎ'mö¡î5Ž˜UU·•”è|(k^ÒÂ0¾ã´‚É[ÞLÁEÇÈ$iÅ_Œê=Ôãå b6sø£hÉ›`ƒï ãkžû !­ëßS®éC¸iÛµ¼s¥ç…X&×ÈbèÛ²•JpÔ”T’V™!†¼Ù•¡X<ÖŠ)u´Y3ˆnГPÿa‚ƒéÁ¤qVdWX[n;"A [¾þŒ£ïGøÁwl~Ó;FT¾í›&ÓrÁ+ÎËŒ²¼‚¨¥b,k;­;ƒþç¤%êÚÛ‰å0]Uº[˜ ¶ìþõå&£L¡iGÎáÏt–Yt4~ù®ý(\z9õ°½,ah7¾þîF™qRä4!dÒÃeŽúl”+Òfm/ÔåVÑiw#­`ºm™z©’€€×}idÊ2ùª íks°qmúpg®tï5 T Â9ª7s¿þ^®Á˜Áḙ'{×Ä2BÊÀábpbÀ5¶D==×WÞÞ„‰ò3O¿y“Œ–£Ávœî¬e~Š,o¿÷ðkyŽÐ5ÖZ˜ãAÆTÄí­ x°eÇÕ½Mãíôœ¡°E2äz â!ÞàëÂÐÑ‚¶_*ÌÒ¼ÿr&=½µŸ*œÿ˜;%§l{|¹hn+ùäžÏž¢õ) ö»´‡ºË>*ijõù™’U ƒÖ2ܼ Šó…F5,hIL=KYéôæÀ¢Ry††ÔéaeBR&§ cç2¸50Ö–!¬ ¬8¾¸ºHÐBl¡@¨ïZ¹JËI„ gL¶¯Eý§ ÄlßU —ŽH +öÔT•5Ê?jý°Œv«˜±¯‰d⪙&ÊX“˜G§ý±®?Åj5ËÍÓ# !¤ú­þˆçç£pw Ùo ß/£·j9²ÃH:}h¸ÆÖŒÞ•r†¿gå‰âSN9y¶ga$J Q[ Bx™eÚ9æ‡ØdªÜ@!Ìn°÷‡&SZ»:;½Ü5nk\G°_kVámõc‚¡ ž6y$­'éa9 ɪ¸éŸ°¾iæfŸ£€Qà·`€¯>TH-ùš5ŸnæD¾à2æ4¹é¶ï#¾-Û‡¶¸x µhP *M͈"š$ÿi\bT!aN-!õ˜"„{´« ‡Ÿ¬ Ž·wxcikë°J'm­7q1™†M<ük@þ„ŽÜÇÀ,ˆìRÛ ¸±LîúHøÌkq‡íwï¯?[rø+ÝsD¶ê¥ºž° ¾Ðþa©÷©´rúàN¼/´O>—Å&^ ×Ý/“z°D¿~ÍÚËOœÙø×?[Võ€Øùó^¸Ñ©KH· `Æíäß³Eñ·ß d Ý–-.”ï-â‚ Ã*½0ö$Mù'Vð16ÜÎ4N'¬9Õ Ö_Á#ª±u“h­4öPIB689oá2i/Ê©4:š…fcþAЬ ¼€Ò§H~ºï=x4ULb­IH’Ay›^$:]íš@žz£YpýíIpC÷ú}Ûy1YáôQbêþ=–‡­#^ñOhYÇMÉ÷(î¶›þGÝœK\Ö‰¿îö’€€¸±e á èJž5±tƒç}‹›tª·“¾Î`-ް—KcSW"€57Ø|{§’÷IùÎ@¤¼èvNÞë5$š ”v±Ã;_ê5º¦·Šug+Kâï-I0õ$Ë2ƒî ÒPÕí`Ãát‚Ù?XÀWeú†Øc¢FÀ‘Íí’*}L:J\jM%ám&Åɲõ ‚~ÚMß•VÕ„! ·ñÕ½DË•FÀ}h,)TŽoœ \L1æ´glbƒüŸ@“ç… Ä¸7`j[—"%6¢÷yZ‹YzeÖ‘Ô ûÿdÖ%TÍkwB-üKHш'lÓ-þ[ +é‚%gÛÐŒ”eyèýßK8ôïПƒ‚È›¾º¬Õ Kªtª?¤à5Hþ *|ÓUÙ`¼Ë¯ Á‡žä@ÄØÓ1¦T95t9¨ôeeÑ'Y"¨©¢šª^Óø¨S0DOå•Ân‰ÓMhæï@Õz'ŽŠ^'9—Œæ]Ý]›aÉ6`6¨_æLD¹îêôäšožï†7{³ƒ¨¿M8äçhKrã·t/„eÇé”z-ÞŽ ¡ååÝð“ÎZÊ£`#D÷ ”U­eÅÊõL¹úœ¿ }jÂjeîýº¦Â)”ÜHq5¼rÃDhÓÒ¨£°j3Ȧœrj2ÏKa¸¬ÏGí {úï`YöÉ&ÏJ/»ôŒ–Ić%’ÑCõl•Û³Ò0dfj0Röés&êÑÈWl7¹ÌGŒ¥ÏŠšôLPhxŠôa…:v“f"!„¹cðõ­iÒb¡0¨Þ²À› ¥ÝMÄÉEáe׆©áU’áÖÏÔÖdÌãe«¦³)Jº–2C-•¯ô¢(~gÓrú¯ðh⌽•ÚLböÖ‹>8¿ø­¿ŽÐ8}¸Ð¯ŠÄãêüd¨Õ¼5%?-LOúk0Ýóx·‹¶H?CÁyn¬‘&ØgNô¸k AŸj@ûÎ^Çf7¬4§&9{)’€€˜òïà ^¯çC‡†gó‹æY—Fª*ÑðÁ§_Í9Þo~0œÊâ—¢8¡t«|]Üz8S [l7˜%œÍjAÇïã¯ñÛÑÅ<—ê/8A±0èFá]Û„²ÿbêç}—‘¼ôJ¾½&Kæ½rŠÓG dŒÛ—w~SoÄ194é^|0MTy.ç­äÅ «$»ÍÖôiJáã ´SNÎ+Œô²0æ=Un5BÙ«N¤t/`,<‰ÙðN±þ£5Ú"ƒ@Bûbù«k•÷0BXÌÍ>Ü3(8Åuº.!{"©üz%<êì|²1¡ûDRc(¿h2*'FžDVK7Xè–ø·Ù„'Õ×ýx8{rRÎÿ2°àª{®ÁëT£ílµWÄZܤ©K£y®½ä•Y¢ÏUæ³”o¤0@@Ò8A]ó\àXöx´»ï’,vgíè4eÙÈPÌ Ñúÿ¥⎬g˜áX¼èfî·.2Û2žh[gæòå…«z“‚]¼L#J%‹ðÚô±ãõ$>*…«>²¹Ã[(Hsj%› £9Ø“„û‘¸ï®OŸÑK¨DW…O‘Q©ÝÑŸÿ´•œ ÍHÃÞ?÷WêúN×OÃwZËÜêE‰´6—äƒhcéfr“XIéú¦õ%jeâIøi™L?f²âÞVìdfåÿ£›¢éV JÆÍÞ 5y`ƒÂ´«­³Ždâ¥L‰–Õ¯ý`ú'2ªÂÉ=¶sIúìÆõlßex‘‡°ŸMFö’è0kV•ãREJ³wÑ à:Ëõàö-CØ¢¸—*”¤¡?´*ƒ·Ë³*Ò;,Nžõ†ušMkûøRTc¤‘}ûͤoç„óê¼¶à»þÚO rHЄ==À½Û¼¼Th!›”Ì„šŒšÕZ¸ç‡ °ˆgñ‰ÔþtÚdç‘õ ùgij/g™’€€¶!'”)[>–7TE¢DžF#kØXI»ßžb~x¬×u;¬ýïå\ô$ Ž‘’ž^β¡¥ùä‘”[/ãL$6À†dKÉïHõÚŽÊD¨5 ƒ1¨p¡ÐÁ|b_Bg5° šj$Ú'Œ‰÷ª®e«Ò†“C'XsBÇ:0y*wá&´ÌåÎÔr‡ÚxÍö« Ç3AÕ•ŸA-Ĺ‘fá ê)+!‚úD™­y­a"oiTQ™ îødÿK)軃š²kkŠ´Sß¹]Àßµî#7èr:æòå_Ÿµ½Úºa4‰Ý6'\¸¸¥ø'å ‘.gèB·Zòge†dï®§Èjs¼,{_XhJ¢ “ÉTu¸ì²±j 8`Ù3ƒ³Q[ßz‚ Åžj›¥…(&=ô„P³5­yœ­QÔJèiA]KåÝA ϸÀ<ð•ù2>Ç;Tœ¸¦~ÌáñÏ,c`|¶˜:w)ñ=ŽÔÚVÓ¾ô‘¿öKUDþØp£Ÿìj‘x®£@a«uÞ`ºÿ“RhŽ,Í»Ò ¸¶oÚ- –®{ÏJô€YrÕÀFÊËGÄ+Ë‘žYË.b#å[7%ÊåeP ŸþÄW:—7ôãnWy‹¹~ã¤?säA×÷ЦFм¬…Z]xÇ¡äϘ)†¼r©U[\¥!aR<úg¥<ìeÅX³Vxà©‹Ç–®¯dù)÷ðÑa:j#Ýügšl_àrB1ÈPêNÊ”ãêÛäêŸòˆC¨¢Ž{Ì ÃXUÑÚú³¹ü·ÛQ,Ôù]Ó—çäÚ¥×ãå‡ð]µüÌùO¿rGç’—š­“Ç‹r˜B8T…g¥‰øÔ½°MHlHrœù³Îö­´°Aæé×)lÔ³ªüÜÚ¿Á^ZvpúÈjcN ˜¯Øšë á4þú˜º*Qç%Ñ+ÁÌ(K*ÖÁ¯w°@¹úKÄe£Ýûl,-úá T›¨ó3³‘oGMÈ—¬ê Ô¾ÍeH‡)dMSGI†ZŸhçŠÇ¿»zdž9¢´ù b[æà}ð)û¥T‡édúßäNÉrB†›%îûQ¢Fëwn‚ôvʫݮ©TÛâÖAvµ•±SMq±´<¨h ac&ÊA‹’€€´yš’× êaNÍlÑY¼ÓÔí@2ÄNa1ÁŠ5j‡f^gÃ=Ðx?Ú;ü²¤¢ä(ù\žiørthæoœ+‹8:?­#<ªYä—`;ž›"Ì_0tæ";ç$l=ŠFåü I{g+ <úœ»`”¸ÿ]ªCÂÇ”Øö¦¥ ‰9ˆKð%zpU’°ß ö³«"káB•×ÙLp>½ݼÚÏa,ÕèN–”õ-cO(”{DJ¸÷ ÝÔbðç$÷ÉýšŸôÀ(óÊÇ“GFïÙ_,~NžõÈ©ûÉój’Y·<ãñ"fÓhÖ’¡e¾*ŒÎYAúV°˜;ÑöÌáOîïI…~‚Þ!8Þ]ƒ=.-êTËu!W6TO—o•ѰWDCmâÓ…¸Ù—){utñaºtù€"K£·õg¼Ž<ºBÛcý\%·º·iÍb²Tø´Ã¤LØ”C0õØè4GH]f$?—Î3j#“´qvе`;™WoÑǹ ÊAógcK¥>í°ão{4a.×ö5úë ÿv³{xÛ#l4 /A?„!ˆ÷¯í’(Øõ§e±±µÉvG‘"í¿^—¡g>‚&ÿf夃G›d)Þæ) ív†dÃî±Ðe! šÀü±b¶ÿ®™ñì¬àÆHæ=ÏvÓû›¯:.ȳ^EŸ"‡$çý;…YUwª…¹f,—°ø‹Ító²°`¤ú››ð0‚ÅgD4g›¥æ­[ïÖö›IÈÖS‘;¾°ÓÖÜãÏãÒÔÀ=®o…rðáèf‹ÏF¡OIj<7²ì5((Ô¯ƒ\Ê¢”y¿¨xp8Q°Æñj(z.æÍe˜Ã(H‡ Ç‹hë¢þàÓ·óHdKôsYæiM{ÊïpÂÚ€í;›æÆ4«2Om™lñ:ª_=9Ý…}úösäªÁ§,ÖÐC ù¬4ÊÞ…8× °ef̲Ä~åDObaÛÃÊ}v’Î|Œ×PÍ@œ“öÖÎ`WyšT`¼êjˆÀD‚1uw6ТԵQ¾ÞašŽDçOæð#lÎ÷§_­„pÑn•}ælÐQ^]ÉÄ×Uã²KmŸ!PqëÞ1/·£«]¸š#K Wbùô´°ó×+r•’€€ãÕZ‰OQwïòÓ5D2s†ØäE^ug%‚{´±©^R ~ù¡1}÷‘E¨ïM©(Œ°æBYР‚=Á‡ ½Yuhîö“æÀ« ' ”óÔ®Lr¶ õöÒ™¿ÃIx„€wH!Jt¿¶êpfùùa²>3ì¦ê|) •£ð½Ãƒ$¯U›w®Þ™=³5²‚uøqÙ¸¸ØƒQ"NµÊ®²’³ÜÍÜ—ù âÇ:‡3!!²¯¶ä\Œ®6Fk7²E<<8_]ÔïP–È`ñΘ[ ÃïP{‚¡ç[AÌPÿyM¨Ë_Ò)þeie`æý¢vÁ쮩XìwÏ•×í”;f·<2Ç%;Åq‘Ëá|ZLp¿‡l²âЮ”WϘ²ò3•ã‘üØUÈá¼TbßÝâÄ4òÔ8ƒ ½—Æ[dƘx5) hÛ›wΘø¿°P”†EN=a, h¡lYc 9X|î i˜Ý“)‘qxޝúŠI^ÿ¿˜óñ”U¯§›`ð›Í£+W€ZðÖð²WJu@&^°{s«B#ZÑå‚Qçleô½Ãg£~ý†–)‰ŒCÛ›7 βÉ`—ýB¸x-4`ä!üü·w¼ߨ.P¥šÉÊu8ä}Úm•},w hTÝùÍ@!ØöZçAòP«À»ñ‚#E°Ø ÊÙ Øp‘;7ȕЀKËe€k™¬«¡©§9ŸCÝÍCœÆÜ«|ù}ºÞ­g2Hî¨IˆÈ0XÞ4t‹„,ßaX¯4¯VšÑ™C(f/(ª "loŠ$,Õ¹®Û! èZ×b‚bëÉ„æèÐé“ qð³OZxÎÑMhc—Œw•)HšóÉ›Vxâ"$¹»vþ1À^Mk ŒqµÍ©œ›¸Öcë|î/&L§oõÃX¸b\ý*0ý3<Í umÙjv 5廾Ë.ÁXƒÌ"™]L ˜¿¿÷U,[a!€>øüÒ„òûuÕ ߘHî’%ùSëÈ}Ìlܺ˜åäý–L)ÚžÒeÄ<³Õu²p}2¼Q®TX¶Ìk|®¿/¨n·»ã1$H•7\‘T¨œÁŠ%G‡h.ÂøÑB”øä‡EÝ{·8 Ái‘DÂC:&3†ÚÚNK‰†Ø+š©EòÂj#ÒÏ{ˆãâ›ßïzá$ÖSZ¯zt)󘽤“@F3·žÏIÏãTÑÌ PïêøKò·‹61fF¶Ô©;–lñ´ÔÊ Í«»nÉÒ;6Õ1as^7€´˜¹ú]Y ~!"áµbû÷ìé FL" .òÌë5X ·Ã™püC{´Ž#æ4„{èºêÝbfÝÁZzuâæ ´g7Ÿ‡“kÐ{>HôÍÞj=d¾³Taò - 7úN¦­È–´-–•x …™zÚŽ¿Ê†^¬kùÈ`4fÏÀ«Ÿ`DÇ&¬ºÓ`5ˆw½;Ž yÄ06üØ]â * ÷XÐNC–á…?3Ũ 6ò½¯uÔU¶×rhÐ{ð*îíÈ”tˆù DËšV´<@ü¯øŸž0 ¹Îì 7¬Ð Eµ¬8>Ò¹+ÿmJ¿¤¬R¢¸Sa£z?D¢øÇ=úÜx¢ŠÜ‡ý|µ¡%ib ègÎÀ"‘à#Úin S à™ãÍâJ+ôbœº/´ùÙ×c§Ü¬!cãõËÎw»:P;1Hgu«¨V›J´3ã¯<-|õS~ Ux×®î¼ÊŠïô¦ €‡õc˜¹Û¬ƒÕšì>“Mè¶+VT‡oÕ@j@LžqB9ÿF_‚ UhaÜs±^†*ªçGqzÿ±DAÚ®Kà9?1›ÉìÑ} ª‰Lì7ë¸ù{¾2·žwª ˜“Ü„Ï}÷—«}NêëtWVHtNòï¡äÓßÖ_3ؾªY•çço{SÏ:x†qkfÔ’1çŽ oJ¼Í–ïäÆP¨»$@NÓ):œYÊç¿F†i£¦™ØÆ*æneKšix8#¡z=ãsVÖj€Å›À.{˜xü;p¥€ÈF*×ä<û@jñLaؽÈï*V7FóÀî¼æ¦…½»ÔXïÂ{©€]ÆÎœ‹ ÀFžaBÞâ’€€²O5B¾ì‘@ðÑÙƒbîGž.'“fuK ÜjŸr*™5£¨åÔÁ…ÀÚ«lTö3*ÆÊït¡Äý)rCBÎ ¥ó‚âs„JÏÑËû-áó9Á'÷6¯(oýïy). TZß?¿¨å‹ì)ã&69 \œÒüŒ9iÃ9#-äéOœ¥g²YèÎÎÒªjU°Ø^6ÒZÃ9kÄ¡e}ߪjr«ž7hç¬Q×Ðã|ÿŸ+CÎß¼4Ýñ~ânï¾Rmt?~7«…´Îcƒx¨{¡ÔE^1ÓÈ„n‡ÉeÉDó“PØŒ=ºªCÙuvýðð,S±X˜¾Wf"'vX€·%w=þ/¶ìÆ=¤·uê}ÅV´¤s)”@ t ˜|Ñj2H˜9ü±nº/ëÇ>¯ò^$u©²ðvGÈÑN(L´¨òÑŒ[FatÌ:À켑!LذBEZ6MAngj`ÊM%HXp`utšÕ3óú†¾ÕG2Úñ¬œºµË‚Á«­9¸«ÐNÍ÷òæx„ºy”ºO–RAyػҕ“d€Ç£é£TXhst 6”’¾¾Vц5 ?¸Cd"×SwBpaQ’ŠŒ¢"©´%¨ѽp¬‹L‘ˆgköy/‹’*j(d';@º¾g©ã© ‘$¿ô¨3¼‘æêøÈ}jí»H²GÞ pÁƒLv~«Ú¢Ïºª\‚–áJpß>p§NŒ}yH²‘h€Ë·išVùÄì ¬€uÒ'ÑO* ÌK±˜ÎY8—AÎún}”Ý“U8$Ùl¬O.š`_öV•ñã±Ûãñϧ¸÷×cùõ×bpƒnÅ®$Z±ßßì‡Aä˜sPù³Iʰï*?èJ¬>ÑÙ=h Å%ÜOq‡ù4×™K­?ú"ªË„¸¿’ÈÑÑðÉ0Ž'Bý3S«¬:–h‹ìWÃK ŒÃ´h,D>‘ÅMʧVÔ>WdYLš]²È ʸ e„ŽÈö–wäoÐófSDõÁ•Iq_HÉxiÚ(ÊA$%g•Q^Ž@u 9ÎuÛa–œ%7‚mœúmz. œoå™tð½‹æp!`+u·¥åÍ[æÐevj†7†»_ hºÿV¸ŸÚìúãÚ*ËIÏÊ‹P$—'¨å¼—¹ :šEüýìó_3 È# @8m’€€´jép)sLE£«FÇ¡'Å‹†ã“”ìâVÚnüÿ¹âÃKuüŬ±Zã`åAOš]-kI O3ök\ýxöÐ8ï†^¨M·°¹;ÙU­"÷ˆšÈ•–Ïndbç6øÑÖ£… n¾Ï3¯ ³9.=´Æ`@RÖªë!¸¥å-lïa鯖Iÿdl©¶²# Ô˜–ÌA? Y'ðu îà–WR]üï~(¦ÝF¹Ü^~ R6z¼¥Jj®\Wë—‰¸" Š–ÚI—ÄK³K~3=ý"W ¬8;åâÅÈá\jŒ÷ã­LÄÌÉi½s‡PÅ+xGgƒ¤ 4 nêj…Õæ÷ž#Ê×Bì·ä/¹ Øxv&ìz½#¿“ËC}æ>vä…âøåQ[µÁè¨Õ‹H=EÙvîÖöâ‹ÚHIS oÙ¨Õ­¼u±é¥8ÂÊqÏÙ%ðGž,åÑÓ•àZñào_ ègá515åoâ|ë6É âqÌ"‰Nò(Àà¾í¦¶ÉÞá´zi7QÌ ™;»žŒåþÜŽ/ÐÂo Í.’ü;õèB,O­«¯ ©‹Adòµ` ÷ÇÁ€ÁüÕqpMŸiÅ­7ÓÿC ÂQyQZ3Bx³ '˜|3£iéÛ3Ķ~î­Ðó6À†ç7ò%§I™D«×ù#UD¼Gø<xå[Ü|i-†0&G MNyâƒÔ^Ú„3ØÚɇÏ"©ežWŠ~ µàêìäJÒVÚêÙCõ'Kks…uÙ$im#«Ù¶Æx¾1 7òwUP‹P²ÄéûAH4±ÁÞ‰!jç%lŽ_'o«8cîë{dà˜ÏËyY®«ÿ^¤-µ ¥R‘ ‰Û¢­ÎžŽ ¯(ʺ8 ý¾ÎÉúˆDÎ6€´AÞT¹›r0Ïùß7¤÷üxi†cuí{’€€¿ýTw´¼wœ4DU¬ l{[¹V‡5{)¥•(´¶Kfæ^* ¿nÀT& NùÏJ›”¨5Þân¯î\|O”j*$é@ò΄Í!F Ÿr‡”eÍØZõËQPÈŽ™å:(ÚbE|1B–Þa!XšÝ¹Ã`=[f¼áíÅŠ ŠúÌ~ ÁRŽ\U×zÅUþÝ€ìt¦ÜkÇIæOð‰l}ïAð"h†íÌkû mŒk-PGk›eZ/¹ázúbõ€ØcûáÕ×ôC—‹KõÒ:NÞmi‹Èè°ß,€e¤’ª1>Ìòs±–šc¸‚DâèõÀüôêØ~©Õ«¿—~gª#Â?i”¯ða¸”ÁäMpüíBïë+‰t>M£…„iÝ{ðÿ‚þ@¹ûçTŸC1ˆ~ª” DCh*ΡجaTÈdì¾bÅÊôÝÐz@È«¬‰è”®pàÖ±ŽÌ™¡«}‰zŸ¤†fT[_˜¦}†Çø_OgÓ¦ÝzŽAOÿ¸÷1šeSõJ)ËŒê÷¨,KE¾7€ÿN»•›WT(µß\.fÝouk\Q]"ªßïð³í Æc¦&2+ß’€€ ÊE¾1?©—;jlÇ)•-»D'§ä®GùÍaE]>įÜqçáÎáY:¼õÀÅëXYÃ&FšÑæÉE´ámZ‘UØQ"ãæ_E¨§^‚ÎÇËf¿(¿âÛ°¯°ú¢Éä1õ1ÕZ'™²¶š5u¸&6¿gŸ€UM<¥ð›®Æ*â3Ë^X6¼ØÈ¤°•¿wÐ_õüõï¿êuU~³j*bœßÅ `r¶RrñDû®Pû&,DœF©¨¡V“«#µzÈø‹!„¢ýiéç¥d’*[·¦Jï™0¢ðB{ì]CL™•j2Ò64Àå1& ¨“‰ô1À±6™KE%÷kjvLX ,ÆrÔ‡£¾6ùoZf1S;] z÷kíä–„]“±mìc¤Ç![°Àæ13R'Ñô—}|7;B.\ªíøÉòcû¡wj®ÑO™N%‘а1ÌŸÖé‘`nÎ[U09Äôâ눈J/Oá¨Þp¥¥d÷ÏIýEm’ÀTÜ…ÚÃÍvkÈpy©ÇœÈwˆ–É-é`8‚Í¿õ}-Yè£@la®ŒåZ&€‹¹GÊ#²¢L<íVŠª\ŒWä ˆÒ7²§å"`ûKôíg(ÅaSï^áï®Ë×^Ú-cíh‰ç¹C'ùÇÌÝUE¡«4™›=n÷(RZ”·g%Ÿ@l¯÷ŠùN2ùc¶îÂáû7XOÔsb÷P~B1@Hà×&3:¶Knz@‡˜™V0êéaŸ8NôÌyì A>ºx±Ž~üYߨµ'•·*±&ŠäرˆadDk’_Û”Öo:„,ÇÛž{Èì×äjŒKÖåQ¾*R˜)®™3{É 1ücÎ)ëæu˜w¬ÎÉ7qu³õj8[ûº~¤µe<`Jø,œ¤­Øc¸ƒÉ¼Å¯Àø@Ñ}5 s%\TÈÓ’Û>OCyC  Ž|5=÷¹À'­éôQQŒ~¥L¸ËŸ]Ì·É«‡wŽBªAC±kÓãà@¹à’{ˆjtÀ©P på^:Û6³_š.¿³rdÎÅ9zYî91…™âUBçé€C6‰s¼ÔŠ›Yåׂý/ oððˆA¦üÔh1"}-78úRh¢§R9ê ÜMèLjÎïÈ>Ë’€€ËßYµÐFÍúˆè=ΚÞv‹%X¹­üSà‰Ì®ƒ¡°«È®pi.GĶ®ýŠ”ÃxnýÄïík€…@D«JF«ôÄ^àÇ)×’^["í{VüñŸ”:äÃès¡^øÍ/krïb<ƒüšßýH Åa×@¿µbç \ʪ’™¾ ù9‡˜<¬}† S¹Ö>}QvÁ´T¦³F×7̓̈́(Ê'¤mÛŽÕüŒîùŠ$óZ!9‹Xa‰¯—ÚKa$-áâ² õp‘S,§Ça:`°]ܨ€UyiL‹ÔÀ9Û﨨ÿ’œ]9Hßfç'‚‡2ȾçÄe8 '¤[§%Fÿ–ÅÊv¹úíO#xBὄì¸Õ¯;ž´Ká-Õ/×l¢õWn?×no½æ õalàׂP\`!ÎÆ§î ÷ê'öŠ ô¬2V‡$رUIŸÎªŸ²äg]ÚÙ"™z–˜?èšiGÝ®—mdEQ¶M ãÍߨX¾«7TA¥7WªLT›)à:»p_蹜¥TONê‚#}3ªèMA¨$½ÜP^–[šö=êÏjåÝ=(–yÙòc9æšs„ã}à55!糞’…?” iè?g·+J½&–!ù'O:ÄsêœSµ7LŒózŠÇF:B­NÅÅ}ƃp슞_x–»¶Ú¿àg¬ˆˆ­à‹ xNªù¡©› /âÀ’€€¢²[_öƒéÚ ¾¦‹¬bÔÛ1Mu9v®à«“RÕù…GDÆDÏJÓeŸ¼©NÆ&³ELR«¨5ì8ò nsÈËP²ÂN›)¤Ö2Sêr߯¬j¦ð’4+ö¢7ƒ<45ÕÌüµy%§fœx¤\nße¹·653\yĪΠËÍ)°4ýtF\‚ÇN/•VÿÅõ¼”ý9»Ã©ëÎZ­Èöqù#9uò¹¾Û|†Q±zÍ&¿n:¶œ-j¼XI'e§øV|V¼4V£¶j ‚B+8Ý…Ò”07ú£Û"´2=KMÛK•:®vŸ19XܳQá ‹¿.½áÊå —-åCiæuDû ]ÌÁuýJÈ­ÁðÕG?a6òa>ÊJ³úÿ'U_QŒ»ìÈU $û"0ƒŸ¥À`1ýJݶ£ü 7¹l $„¼ݪ®‘ÂqÕL0ÕqV™ûí=OyÅq›õu¬†#¬ÀΨãJ(&ñqh¨cM.ÕVˆÑ…>ÃQWñÈdCÌ`} O øØ1±_ƒ ,C[̸ÑÅ *ZÝÝðo;fLc`vì¿S´×Áã—©¶·V92çh¢ [yÇ™µ@Œ…Bë–Ü£ÏIäÜÝGÖ4a"KN }€|À¹à7,ÃKÞúÈ‚)•3L‚»¹cûÅ;™ëÌÑÀ‰ÌO¶ÔÙY®õ"lkÒêqhÎï„ÓÕ$×y6'ÅšÜE BÂóS•/&÷Q›K|—ÌØ\ ò™/&̳AGôÚܺèÈ4Ö¾¹*qÅ1ökè'=½µï^Fê£OñŽÑh`1]®ž uBÿqÙÙ×ýÃäÌ& ™ÆÔÏËÜ$‚pòàû‹ª˜±#(…ñk­œk´ç@5óZæ9Ÿ»Çn÷›•7ç(9‹*:¨.4U¯*:¦É/ “÷[)fç*ûÕЪ%µ!½ÿDzy²•Í+è³/î“o&o—Zí’†”ÔfkxV,8x÷RÆÌ—EýLñSѼ×1­e†¢žhñ’€€Áÿ}þ äqôä·¼…êv“¾3íá~ÉŸ§0X[¿±+[@Yûö_/«“ d…×bzI»x´ +ÖçÉ…™ºjë•™ àêXðMï°4—’ñ™Ñôïÿ3Nnš"<í‹nÔÔð}vœÁ‡ iD ±¯š+q÷„hãû‚ÿ¾¬CœÕ⛣®þc’hé¬oëÏgOuP_¶{pÐÀåÉù®!áý–Œ‡f>ÖŒýNÞA÷Õc`d§+MòÚyŸ¦?ÏUB…)\Yúµ5zÍç˜ÝÅU'oÄ ~ø‡Øã~sÛ’Ýo=-—eêZ©Á! ÒàØž¦[?A€Y_»5Ž!®KÝ “/î‘´Œk˜oã¿L &z·WT­ýüt*ñƒîª¹Q€5nÆTÅ>» Úß³œOœyʽ¢â}L ÁÓ_00ÉQ5É}Æ£¹Ö’\$£Sz‹l€ ©4ö̪ µá.bk3ˆK¾òžYa3ü.MVœÕà]nóu!©žyT‡Þ®eŒfýFwꕯ&RÔÀKµ÷稱×ß €+ ·¯žÌ`R©¯f~žòäJ¬‰ßÞÀ#°Â\QU~.c*¾ xcä•Eî3€]Q•}O—C¦if\ddKõtr òP.u-_§ä¿-ªݺŒ{?U4ªê'ü/_¡ùt €F”#öEnˆ6½ éÊÓì®;# YÁŒÿFRíø$_e8¯’_î…Çpd€PZøµ§ëVL“þ-çý5 £xPZ‡ºðGÛ_ÅÆ0 L‘Y©̸†?pá&.Ì5œ`uHâþ½M¢·FwødáÒ‡$CÄž€)ÇÎ5g™]KW"v=½p´Ùã¦p¬›É¹'ïb’³ê×ÿTEÈA=´i°VÚFè½/±ÊãÙ—éë<õééÅYÁÅñ£XV¢lçϲ¤ÓOi~/¨ÌØe2)¯YýrÁ&0ÆIFòªS­®¦{ Š¬Yì>©ƒ}9?ƒ‡iüêGcãŸugè­„tx¿!´ZËXñg(@—àŒ}ÿB›À…Ñ2ëôÙ@5Ò)§ú.¾+toT˜{äÏØ¤X3kpÜŸ3¤ýüNˆø›·4{b艗Ár‰/uHAœ¨t¦¦ÜOƒ±ˆ›o±é†ƒxòß’€€µ.4Mǃê-³2R–™S2UñoÙñºŸ¯‡„ßp°iµ§[lž7ß *äÆDéaç õyAÃrÏÈ+QB+WZîýP‘çr„ݽnhï!+;Çñ=ß–ÈNW"Fë*†]O¡·ic–•×§šÝ(G`pñ gœYW¹‚¼gùøÎ ZHöqɾ’N9Ï^‚³)À¯®{C'ŸQ€›¼.JkŸVÖ­*p7±c®-ÙþYX¦þQ é¯èlŽnìGva>}”7…¹¼ì±% µALN F›41eÚ7žOõÏÒmnpö_2ÿHAŸXž G¼L+Á8å Äêô{ÂLf'ùÄ‹ùW>Êâ&v)èÞ7CžS§/¡°Ì7Þ)©Ô¯•†¡ù4øoú")=ˆ ÝãŠéÔX®]—ý¬‚ù¬ˆÒ¸ŠiÌ&è±õ]ù¨ƒ˜pÙ{[mtÔü«ª!ô 9gÒ¤¼ñÂq¡ 2·®\Î(n™o(uí’€€Â]³w„Jé¶{§Ñ‚§ìfñ|â4DŽ“SMRb»¿ÌÐ44¤³6’§èþ¨U‡å³‚oÀ‘53l6@8 Ù("L —0ùɯ /ñ<¼ÌÃdHð3š]øÁÇO—ÓboH€íÅ95¯U5®þ/tj™ßö†:þÁQ!µþ… q¡ßM¯«/×ñ5|›­¤ÚŸ˜,pô ÒŠÓ«u”Pe©QÚ¨ èv‡ë±9Ô)X2îYkÕ~>x3–IvÜîh{tõ@–N¨T 3d™Ò2\F<“Œb™žÃD‹sW«óÜì²ÛÄ}Ï~¹±¯ïªæ‘¾ôj@)…ͼ'ŸDà7̦H m’Ù/ìD þ²ÓŒ’9×Þ#J¶{Þq#\Šv¸Ö1·Ï^³qCØFl PÃGÊçrA5"ù¦Æ`ÖùíÔú'˜Ç5`~Âᓱ–ÝBÏ+ì 0j›}ÿTîgµ*y{d!;sz¤)hKD–w¤àùÜpÉü{‰s6sá'`~Mw?÷¸'-Âö%*Æ(“sØìæïþ&AÂ|œ¥¶-Ÿ-·ˆ%ç€o;ª\ŽG¾£¨–ÅõÖdÎfñlzÝåˆëoÏ2ñˆ„ÓQBÌ©ø#3»Ü7°39^[;âÏRÈ=¹mïœ(ŠéŒòý°7yõ;ñâ6Œ Š¡”ÂzAàiÖߣWr@çHÁLª˜ážÑØT™Mvh˜°SÈ+¨­©±ÀéIÍb–wD> .Ëøºã©áoU^ªâ-èob'ö:ïX?ƒ«SÚ¡Ülü J´žÀŒ©e­ƒ;±-Eö W-³†ÌOÓÃ?[(œ×»výÛõÑ´ ÂÅ4u2ÕƒøZš>mgЃ²$PõMw TÄ‚Œ7‘IªœÆµ p8†B¿vNM^':mA°¡©]ÉšüîxÕ×Â}›ÅÉjq_)h‡Ï o„ž múØ QøXnîè•-ç/£>Ú±Ž=ý®7M`‹<̹/i½˜äG[\`»úó·ž…µ•'0¹‘& ÖXf<-Íö»1/«°3½asþ½”zÁ—.{:ªÐ9¿‰ãÚ™C Y ¾¶Ãùq<Æÿ̤%Û»™ß=š™ìxÍ]önÅ8Æm$ë6—ãQRœ;!6µ(\eÓ}gzÏ’€€ÚþÅ$O¾Â@‡zXÝÙªZx^÷0+UøôT¹Ü&ŒÇñíÅ ÈX\fÜ,ú,Oû!ˆ7ÇHÕ¤RrS+†Ð·Ù.´{K+¶½dÔ¿ŽažüÈS¦'® v¨jËzb„Ç’ÛìßZªNôæ\ð¥øHÉ+\¤RÆW×kµ<7_7èØþºH=$g¬ÍꔌHü§RøÎ<Ûu¡ãJ[u‚ÖòÉ£•_Æ c)»^> sòv÷.aäÞ2ô-.žØ|Xë±Îlj_·jìQ‡ÀŽØ÷Ð9wÓ¥þ,o¦m¨~Uá4ÇgX1ÎåHôªÞ5Y¼ùüðÀ¿Ÿó¶®A·Ít²*ùˆ ÜùVJßË4„¶¿7ñ‡jDà Kâ ˆ åztàXGÑ/ôvÝpñÒGJù g¨Îø:Þlqÿy´FZàN&û㮊p„À À+×KHÊ\wÒžiŠä’•¹^­¬¤þvb²<û¥9BŽ}Ø‹¹g70ü÷Ýõ‚)´›ÅÀk•ÏtÛXÑÀ»RâþÑ×Ú^“‹¥ë¡æ#u|Žëb#ˆˆ†øÛÑJàø€æ?Pß°hÕm“üuà ®ÍžÿÆpn˜†WÉ¿ò|ƒ #Ô•æwÆÉ¼-! óì ÕÞcú!»Ì#S‰o­qÉí~Æ£ÿ>Ѱ­o«l+i‰F!]-€@|ÝÄÒ5ñð;‚mEY~‚Øâ±Å½)&[s^=¶ ¬C΢'áý»ØRí·§#l3'ò,)ë`1£.g\35=>ž±%tÎ\`Õµs¢ö¾ÅåÖ¿]‘‘Y-/ÿe¤ct»áK³§¨zµ|eß›ºl'øŽÈµ.CÃLíU52c—œ‚b5ê­»™LÇà¼æk¾Ã®–ÕfÉ¢¹˜wHœÝ¼X¯Žvi»Oÿgî†Â“Íý¨Bñ~ú~BX›|Šùò¾P…ðE³X£}h;|¡~ÄàN¦øÏ¾‘`øº2îÙÜùc8=uP§òhyç~ú Š™—¶·Ñ52ÓOag²b—7ç˜õB”bôFÛ9­Üñ¢85¾âŒÞP5Ú¡}¬~:íÄ›«c>]aŒÐD|~ŒD^97à#]†š›â‚•âô0w²Ù«Öã{ë’€€£†E?„læ½ÂF vzýð~ÌŸ¿5ÍŠ%÷´Wt\@ÌÁ»r£ÁMCFóÊõäädãf¾ìeÄ•KÃããÿо$ŸÆØ jt,ɦñ{Ô±Qn®iˆ0gh](°”!o䣨Ìâc]nµÑêú®Šâ¦ŽXE¸Ñ¸&ºU5”Ó~ì”Ï’ep§«®zˆÎô&¬>]+ ƒÀï‡5FÔÝøÀ…;C¸qϯ`[éaÏŽæÒªê/¨RKöM„˜Gæ¼ÇJ5™ô\'ÎZ_FoÍ[áíè³<&õS2“ùCylÒÑh ›6ÞV´à@Ó tz„ãLq(õlÏŒ ‚·©ÓT“Ç[ÿ>V¨¯Fj8{vÂYSÍAdçªY5 E¹+Wü8›ZîìtI[Ùm®2B®Tüò=¼_ã³RMÇ¥ÓZKW²Ša–ìü|\Rši hÑ·Œ¹Ð›X¥™%NÖÅÝ«ñ*œ`§e)E zû]—Zb «>©Š”<ƒ+»ð3[qj5czû dr0nèÛæ_ ©‰¬qº€ 0ü^ºD#Jˆ#"òlJe£œ\H‰gÅŒCO`h+Ûª`±¸ìUïí*]ßC™ñ!ÙèÐ’eŠTÞ¨¤ßœr& Ñd+ƒ:낑ЕÕ+åIjÀ¯Êÿß­÷duW]´¿nšŒQ2Žbir©Wj4øa»NÝŒz½23C÷K#{/[Š´”'~w8*š„V+a‚{V_7†‡Å ‘û;Ûq»ˆâJFò–g_Óøê†“³7R’ƒHÓ€Ë\"Ë2bgÕȲ9óXDwÛ Óvšcá3B¾eúZÔûÖsp´k*¸)õ ›}óý¦ŽçÜ(»›É>vth‰c,?—Z øFº‚ØUr‹‘«ÇiŸKÚ\ŸÖ³Ív¥ 91ø9¦‡hi¿™«ÓDLß8G«‡¥äÔ…îÆÍo¬½®È¸TàìÜ-­äg%9t ¶}ú° å«:®#« m2ÊÉkvVÞá-êìGäŠÒ ÇÄ X“B„cK ˜¤ÝuÚ£$ù¡mÝǺô8þp"’ÚçBýN‹¿¡Ž·”¸‚h;óË(²OU¹ %Š®“ÿ Æ„%Ó ¶ýˆ)w®rÚ¹°a’€€Éb˜Æ€}ep’»¨68ŠººèÔ$qœ9.;Ë4øƒëF¬¦kêVãLÎ/bÕãØY`—–jcëÈlïódúÞòȘ+ÚRòѰL\P9n#•žDh[pkªµò°‹ŠužÝ•mškÐ · £ãOK*G«Ô!y×ázæÃµhƒnrRÀ¢"ÖãjLkò‹yƒC1<ôy G:D“!ˆú Ûn!#K)'ànU¡ª^^cô®÷fS(3׮µ“ xÊ_P~6+^¬…b æ&ŒyÞé 9bé8ŒXty°×  BànÍÐwn3öç9ÿÇtbqOþA¹ÚÕ®ÞAgÝWLjMæ7Õ'ÛÊÞfŽ´ñÏÔŠÍC½ct“ض#õÓawÑÕeÕà¥ýcñÌÚn)ãÌ,I €|›²ÈAË ‰Ïøê ³2 ‚*!ñ’˜j•Bã#uaïž0á]ZU„ðæDׄQWqÖJ޲># p޻Β„‘Ûx~uKK¦°Üݾ-ˆÞP$»•1ÚͲsNiÐM”ã=<* –¡‰1·³ðW\ÌT¦²èiÿJ@ˆGÚ¡5LÌ\49¸RF#<ì÷ÉmMø¨Ä>K„`2sÑ 6Š[Äð{°Y,yä}p¯ .k àjÔû›h>x'ùG±ÊëÚLÍæ µºùG‰h=¼Þñf<™IÜzEð @±7reÆú$¯wh·`G Ry¢¹çõ×÷씢ԓèÖ îQ"\æÍÍ –ÜÚùDZšó G"p@ê€AËUò̪mõ³¯€†O·t4}᡹ T‹ÏÉ8(<úÒ[ž‚[¤- A VÏîã³Ðý·ßmó€#€eŠ›ô1´œÚÇ„ÒÌTÙ`Ï`•{À‚U×WØ_AÉ‘a(¸Øéb r/9ú¤ƒF˜¤ó#ã“*ƒž»¿Šá…~ÁÃ*¡’U¼+sÕ^ƒ îwnÞ`Éò»)À'Ör¾©ÈèR¥ñ*š-üT㔣{ÓŸ½Ù<Ù¦gýèÒ´3bžàœDzBÞ«s¥TÐÃîñÉ+Ðã}Vÿ‡_ÉàpJ‘1xp‡É~Q¯¾ Úù[иa·~ݯ°üiBõ£¾æúÊà^1ÐÕ*›blE9XŒ C”±b’€€ìZåy*}^£ñ±~ «cZw¹ Íòhô‹Ö#Bè>„z*;ƒ µÆ»är¨ÍD­ûªÆœƒ\eªgV£Ÿ]Ú"z€"Štù;ü)PŽl¶'üŠ ¿Ñ¼(Ö´ûZ)ËvwnCž¬Žüë57ö;n˜ÊóÏRicª$D}¢…­”%@xž†'ô>'ÈÎÃØàX»¶Þ9 ô÷èx‡æ™ pûAг'övK ÚtV×Ѹž¶ ,$b@^ÌÁ'hš§†aZ_ÚÝ8Ô:Nˆ¥Oí(ÖO륎Ît½6Ž´e‘ØB?×bÞaæC ó$Våöÿ*ÌÛdÎzÑB)ÑŠÊ6È݃š]‹ÐÊYÙ“8\ʧÄú)ù2žÙÆÑ$hÝ%{8Äí¨¡—¯šgxíAÓjާü”ÁIž&’í| ³²ãYŸ B¥Œè/…Ÿ9C?-‘Öj+Ô„òlFuî€J¢ñ~©ÛryŒ?-‰rùEë3ÈW=,Ϧ™UGX±øE7@r·]–Ê<ªRn6ŠGpTÏäÂ>ÎóYq É}ùØ—Ë›k:pNX/îÍ܉†ª¡Pù†_0ÀX^KbŒ5¬=r~íZÞŽ=ЂÂ\Ð)˜Ebùõá\rŽ p~Þš š]a˜ö'¼~ŒÅoª®*í‚S*’[Pf2´¸1u‰Z_ÁèÊo;hÇÚóž ´¹(šAÁסǪálzù÷ATR÷dsiÑ;jL9ÎÇ‚y¼½ ‘>ÞÊã w€:Ëi•ÎÛt×mVJØGóCÈ)^ ¬ªÕW!w W‚ÃÞmº/™i/÷wñXÌ«Fa£m^㸱a—µÝØùÄ,ñ³)nV´ÿF`-(¹¾¢¶ÃŒJ”Z’9 ¯V“OÙ’€€ÀØâ/ hYkTbÖ² šx@˜…Èj9†É÷Í&«´³2Ho:J"¨‘òXó·ý:jÓÐ=ÔQV'× R‘[ÖóY¨ÃË8dèžÛ6@A:j~ œYí4—³Ð¤øŸNœ·»ÿMµlMøBö¯>?ôîëÕ,‘â¦áÉRA `ÁõLÕCØ„§5†‹¢» X»’’îñ\ÏÎö.‚#“Ó*?N{#³ZºY4€¯Æ®XŒu.¡_iåÒ,‰à$ö¢lÈìô‘Ïã§…OÉêšíÕ„fueâwTÁÝDÌ“ÂPýÁ[†d0MZ#/NȬ‹¹pÙöxa79«Eôÿ?h.z ŠæP •H}|5:í–k ÷£§ƒ¡  ÜÙã”ÛȦXmÍH^¸2 ^6ˆ·¸g§´1keDÓa?TȆB-.9ûŒ;ê¯|Ÿ¼òçvüç᳋¨’úºqz?#ŸÒH$³F}ÛÖ.øW½É*{ûðÿÞüF¾X‹H¸[4Å»Èý¸tËì(ÞsaU{Œô÷îAiÄïÞó&-ƒªD’HÞ-"Zù©¼xót:’qK)…ž+¬AîKÀ’"n¢*]Öú]¢ºÑ*`öÅ„Uü[†‹­U+“Ù|bIö ÅMÂ/bÁê·£¡õ{¤ˆ%^ñ3ír³ÚMÔèìûYé&?Gü%VèMWH“>騠äGÐEx"sÊ Ë`žiB)²¦³?ÇŽED™„Ð­ŠžñHœ£ËI„Ö>„r•`2CèŠÖ·„VǬ,TíA¢Ž:M§¿Þ3Š~ȬQG£sÿ¬>Õûò«ÏêÇ)¬6‚W: šâŽ“0Õ“dåóÿxÙ4ÅPV£Ë.T. ›nÂ´× ·”¸mXEC÷æCC(’Å.~uYiM¤}÷uñAÍw]ú|Þ¨‹>6|ÙUDž¡â(fÊÁR%s\ÁÍãq wÖ[¨f’¢À¦FÍÓý 0ôýw+2ɨ<€bR®ôP§bÝ=íîÜ´ç¦]튉 †!OÆX+&pl$@ØÍW°·übß>œÚÏÕ³‡ÇTÿWD®qÉ™£ øQÕúËx€ô:p‰¿•³j× ßÿÑÑ(o ÆÑ2A8ŒnùdŠÒçªNQ™yuoéÊÅ’€€äê¡ÍÔ/ˆCNU¿¼å€§ï´4’Dµ÷”K,Yq.&­ ̸˜å¦#û7¦9q¬ÇxÛMÄÜ9ØpG&ïÌÌÑ~ô^¾.æà‹iµP³ã1š>¾D¬9ïÞòŒ…– Ã~q‘ý)M•ŒKr‡‚:ì?*X©K(PÁÌW;ˆÕßÛNw®&BÒ³Ü9×ÚÚÙì4̳ã6BÛ¨ˆÂ8$‡;ÄÀNèÏò?o´)».ÝMÕ¥2/\Ó8"‡™zF¾øl*k\Z•ÇF2ëÓ}Ë—Fš~{•(ú?)†Šè¥ëqÇ÷¨ JÀ*w=±¯3 ”£ó2új÷‘ÈQÙñFû•ÀÝý ñQ7cüjñŠÅÅjû:"[Ý’œ}«ïù^Ûí´z ôºÍQôakï&_~Â)é–iÿ¨Ñ‚4ê`[äåŠ Á¶Û²Ðè!ƒï2žÒµùáÂ"ú!äÛF ™;f*³(K&ò9 ‚¶ÌK¨b‹ê«ÿ×Õª’(q¶zÿ'\ž((·{°}X.ÚŒ…êóкÿô‰/ À˜3Ÿg`Õ6î÷ýèü"–]Þɬ$R i"ª¾:òû¢s‘¤A`ªº‘ú’-Lø.´¸U&V^·£ïÈâÀ¹óÔ×\. |Á‚Uøöÿ¨·<~ö¬8mWn䔕׿*É0ë#¥°M0®¹utñ@)¤Œè*užÓWØ{‡0xƒzê>guf:?uñpÃYòVL4U"nØ1Ý€žS¡{{÷,kn|/'Óð0Äb9ŒÚì”C9>^Aa1)a–¯3|‹f ýëcp,ÒÊZ™Âñü€qÿ›ø(o³¬¿SÉE˜ƒ@’öVÓfw96bg¤ñ-±J)!V=;d Ä †Ñ×M—%—×GnJîT=é\—”=Àø} ñ7Û~9WæL¤’ÏÌF]O k¨¼4 îú<4g¯…}ºÖïbµæœ!Pj.´¯žßÓ>¨,~¶ ¤TV¼±ÍÒÁ1ì[‚å‘^-þS’ÆI£†’ P|¢Bï㥅—‘Ĥ^-®\ºæ óºà=?Ð @«•¼ëɉUÓʲɺªæéÅÙe‹¥¿Þ7Túê­ûç9ÓÅÆìíûµš’€€¥dÒêßµ… ë­¦ÜGrRxI_$ÉÁržN¦’÷÷HÐÏ‘#ìw•ÌÖï#‰ Äp…ì¹}>æ^¾´h¾»Rç€Ü$0mÙŒ!zþvoÊ$߯ •{‰ ¥ÈŽ®FÑ/SΨiIûi¹ã’¢ÞÑõ—ŒêYáÔà,Óä¾My†g]Äú²Fo*\›B²7KßI;“â&‚w)ýÆ:+½VCo öpRt Zš¦‡kL– ÊAÕ€hn19´þ/¡×}ÊÖEïǺt:'^6ó;¶›£E’hfd!œ½¤Ë˜G2Pµfl¸ß½$ãQ¯ßh§À¡ô ž–¬™¨°O`ýY¡´[Kmyž1H-Íû6 |bhá9º¹.ó#Å3€=ÎH–¤°:³T#B‚ô}( }Õ¸pÿ¹¼äwÁ)‡[âÌ©ÚVû©³=Rw‹¼R&ÄUlÄ3ÿ¼F™dõîÿO m÷Ÿ'Ϭ8,?“áhTr)EÓ£ ã;íÖ½Qß/±¯6*ü¼ ò8.Ú5gÑLPZêÄÒW]€Q·™pŸ<˜à2ô÷Ö’äÔpVNT ÿ‰LðäÂß䍨i?ùìa)€³kú<ѹÒk=rµ†ŒQ™ægzuhGÛ Ø‰ŽV'~$°þ¶b!™Å,M`þt]3lF7Âh¡âñÃlÛ²¸IñY1s®-%׈.‚ÅAeÁjÆ8x¢›ƒm#€0é›é\jH­À슦‹ÃŠÝЦyJg ¯Iÿ3—ä1—)Ê8É8›SR;Z-`~såë¯å8 É0o„Ó¶ì(­übt½ð'”­±dD÷jÖÑÒFŸ8Çש’u$ ZÎ,âY Ç ²ÿwà;žÓ7¦h®RÛ)ȾTYß¯Ï ¡n½{æÍV÷øSïê›üüdGx” Xë ™¹Á¢ÉgÚþ­|éÌN!uù‘zw•ïÞúx&ÊÝ㨠û¶Ë6°FüùM奈«àeSfó¶xŪ-–>““<Ÿ½“foº«SÑT~ƒ¿˜lS´ÅQÿúN‰êÅ4À‡üst³ö42'X‡d£%‹\å(BÅ4í\–sa¢;;vz?ÝWöo•:DÓÜi»¸Ñ)§Ê„éÑÞ¦J¯Ånï¤_Óù^¸¶‡Ï%©»Š“ rµk¡…l8òþ¯p‹©)¹•Iébø´o*CÑŸ?™Ös"O§)È7úÄm±­^.|OéÒ ,‡ÜòX¾ÑÙ4uOJ×3lÝ;iôÀɦM¤ §"½Æ5‘Ï Ê0 5¬€ßaNÖØÁö0 Ì>ýY÷Jª”¹ék—Äù{¸})ugϯðáåK|)ô8NØZž(e @.½b")mT£{Û§€ôæÏË.B¬.ÿ”?Zeœ– œÅ¢¼]”4F¶2Þ¡ù–}æ]µ“éçµ]$Æó™KUÀ²í‰xn}Å»áàgw(%e²†Ðç'=Y\°éã‘—ø6Ù16òõ©*TFëaÐg%6ÙiJ›´’PŽ*ðÀûüMæzø²ÑH`ˆMµèj‚åtOMíµÒrKÏ;öÅý¥•¨äúYB IFä=‘::/—Êy†ñ’nXzñYi¯VqÊ0”öîuÿ-ƒ5•ŠŠ6Æ4õ§x$0À‘;°}ŒsÁ)µoy¡ožï0%â-~8ôà‘‘}(žë .æ$cÂþwS#äZ꿺ÕyûW©jN&ÿtÞÉ•üÉÜ—¾PjƒÙ«Çx3g+Hñ1dv5ꢂ½³1¼Ñ¡ò<¼§&"Ê}æ³)am.nšl(¼.G3ÙÃ1åM²hÀðt4ç¶ ÊêFò)ºÛƒ2Ü ˜Î8D°wœÝÖr=Ÿ¨´ƒFÈ»G²ƒA¢\>m gå;•¬æ¦˜D“Î3-ä",)–Qz.þNÎCGÿ_~ZÔEË׈OÓWZhPZAçš–j„»Ï½ÔˆR„%Ÿ®áy¶µ¯M2¡tY™è÷æ«@L¦÷Q!ÑÞ¶öù1æb&Õ'ôûÞ3GÑýèöâ‡=ðq]0g§C7O¸µ¬°.rÃÚÝ7ùéçU点ÕÝ•ËtJG“Å\è}PƒyöMš^.ã§MôìU3©ÜÛÈvÁ• ÂIKt]éiéMÍ׿ôM–úŒ,gŒ{Ü&>ü€éŒöÇ”§ªj>L†9pZ„äÝäeQ5m~0çµ=Dˆ¿®ëâ)6Á›8ÿÿB¼±¢ì½l7ƒäS CÅ 4Xs d`VfÓ=‹ÃF##0î}Ï–$ßêw’6–@×¥¤/õ€1YÈE0/W¥Œ>b×Íu¦]ï7‰ccÉçŠçº—V¬ä™òSýµ|îêfÑÖ·Þ/Ÿ”Ńӑ6 gï8Â÷qËUàÚ§T1|îˆ,.o{ÕÆxÛx¼@µ5" ÎsðúÄ (ÏD—f̤b‰ßõ5z@Ÿ‰ó2 ”ß^<ƒâUeHW³Ü*¬¡V¢‘ËßCÏ2LqH(k‡°^wB?àp¦ŽtÏ´ª×÷Þ7 ú΋Ù_ÄÃR³KšZøZn{´ ¬È±J‘ ¶!ºÇ7‚5‘(±²ŠyRC?Ñ€Åj”|²?À™=Ñ«8î½+?× +½]¦ah‰t¯ÆÄË÷ ‘×1õRÕ¢abÅB«?îÈ œn¼Ñ€®3Ä„6öÄ4¾m‚JòüN±GyÒ Íòº j8znº¢S|&á·’¹EñCÑ–Žp>¶ • á Cf’gyYù5ÿ@ƒ X`ÿv2€œ?â“=®7&, Ô5™“€’ú´ÍcÓ"ÒN=G_adr¿„ ‰×$F8åç°låÙúÃÌ;xYîÖa[‘ý^%ø„ÑßÙ“„.˜¬ØÉË5fÁ8 tøFìYL@NKúËäÍÃÚûž¾=PacE] OP°³}]ü0,å€xTÚùs!Pz¼XXò@*?•’€€Áà–HsQiÞp­ãü×¾Ç/Õ‹Šëøˆ¨õHüò+ë²xCØ#ðBàüͽZn°MË+³?)ìž¹þ%&ÕÞ³ßx9¿„×o4i |n]Çt@o QU|$ÍÔ¾yJkZtôÎZ²3õó$ Èç`;#ÐGj<¬S)›Òûö\Œ^B5üÀl%áýû&0‹Ÿ™"æn"B™¦^¼ßñ÷–7ø”ªÂ¯ªBWk¸ËI,Vky?£3ŸŠg—Vܾg›D¤ú©ž'-\wÑ´Çû4URt,„òe™UF¤4^ß§¦žJ¿øS®L¨‡º<ŠÍ:Ï¿Ž‡QOp[[BžŠÇú>Õ´Òå\¥Ø#3ÄÍÙñ1Tr3sÃ̃B«dhh˜{hHZ ¹8»*©‡:6.w¡ø%‹Öÿï 1ÅHçò”?… vC ÷;˜lç(p¥' ¬®ØzøïÕ0ü»:‡7éOO5bN6Õx4ÜUU_ùÕèÄÍ%õg,X|ŠœúÕ÷õÏ>c=tDEäL_Ï_èªÅã¼H€û=SœÐ§zÄ4ø‡×z_|Ñ´ÑËâ½&=ÿÅ(‚¿}TÒÎeAð[ò2Qàp7â:àu/šOÐ#Ý»”~ž¯8¬w\TCÑ}ó¤ÙЉºêQZbhqñhÕáø(Ðê‘™zØiuíAvFP‡ ¸f*1ªY~­qìŽáíý1"Ð1½Ì]®ØR­µéIÛ³Ú‹ÁUšéèó,GtÖÏØ‡üª5Và„šÚ¶À.ž:c,Ŷz]g.“ ¦nPs[0sPKAÂ]O\ìþtEüÜ¡¿H[Zp.€=fb±È¸‹ú Òiÿ(°ý\§õ¨Šÿ¨n Øõã4£ÞÐ<ÜÚ™!ð< I—9Ú»¯[·Yo¼üNœlˆ­*OZ ȧ‹Bmú™Ö]ú1ЙU8¶)¨È²œW«û÷m»e“–‚·?ˆÔE Ø.á£Âm=šV¡— žÿhHIŠ”ÑšX>€ÛDXÿ¬Ë—lØ«gŽ©O}Õ¥a¹!Ûè—T‹ÀšŠÍ`c½+’¿!ya80f¼ó¦’]9›OÑÖ&¬ɆlÿtAµÇÏ Ûm–ý„ нXŒR(ÖöÔ Löók–©¿Ø!â&Ï­»? Âá4*’€€»}/ÎV¾¬ÿ@…7Å›Þf†òP¤P/àÆ´e:qÈëy€pž‰¯åÎ9ó¼‚I™xáÜY=®X­=*ÔÔ¼"ª‘Tp1ƒëÛÓ²-’ú}™ %ý²E7£:Ž8Ê ­’¹ÄU/ÄxÑÇí› }òX›Ä UÁ ÁÍ#•€µ Õu‰F& ÏoÉDRغÅ;cbp3Ë[A'2 |pd5 ©aÕf}#©YqÂ?¾¯2ѧÖߊg8wT˜Å Û,¹Ó¿`OË ’«°CËRuòNlL¢Pz$fˆÝ³-ëkb 88ú"eú8ð&t½òù‡OÑÃy‡ž¨Tn[Irúo39"k´T ¡ÚêË\C8ð…ü3!¸!­@¯‰Dô~rÁ“C¶öùôœ~©Jžb‚TÓò³;…8MuÜwœUeöG$Aû–i`ØÙhà ªŸÎ¦ÚÞžò4LˆNé>¦,Øu¨<(JRã×ÚRNs7ÇÕ÷„å4*…q6^®2Qkëü =I‘—Êp´ŒÞqT­“fýËYŠP\6=´/óc!tÿàl?ï1¶Ï˜sF,´éØ,å{‰³…DU´ìbÕ¡¨6ô;Q1åfC¦p¼;×n!§¹s,U¼ÄØïjnŽJJð‰€£Ã‘`»ÝÜ“mΧ +nnš×LñôcP’6ðE{ß…t‹¸¸–qøˆC÷•ËkLÿ³ ˆžãŸAXó^†Þ£ÐS{Œu–*½1ôYÜ,e‚­OTjj`£3ʘ&ü€ç<² œýM ØŠžûLMÊýô¿ò'¢ªÜ3qÊ´ØV ¿ä6~ÀÙ¶§4%5÷ÐÊäæÒ*Œ €ŒƒH™÷„‘d3$êb’ZŒÞëBè²aÂö'¯Ôè;ܤ{,§“§¼©Ä±€z¥<þÔæx“ÂØrxÙiÓü¿·Ï<ÕÙÝé5õ„vÙÍ•º¹ä¿¼ãflx”.¢qô9Äà ݕ͞꙾w‚¹ £;ý}Êþ“éÜÖ<óÑiµ]œE].lªùá ðˆò ™®ÏG¸9ºE¶´}F#UB¬áIøfFàÇJ"3WΘî.¨Ðó£oUh¸±Ѥ¹RýÞÀ„_ÿL=Kh¿HàÕhLÿ½ëÒWŽãÀ¿à  Må™u`“ºVÀƒ”·Ü~@…r³¡ÏX(©\µYš•j 6ÒèÉ‚3ÄìýdùÄG#æâã1ª¬$úƒ7D=Þ¼mXïåÑ„T>F©à oEP˜vôIraS‡•C2 k„•, ê&iÖL 1tÀ×Î/ßÙqÇëD,ge‹È£/éIl56Ì™xþ²Š®óÄÿ©3Æ*åÅ çÿÐ@¹^ùÛ7Ržn=¤j‡ƒy½Å¯%š‡ÚÖ®L»~Øc©(5ûM{0¥s/¥æ¿U*ŠæìÛNÝ|QnžP§†*Ší$Ž›»-¸¤©ßB×÷TÎlŠ¿Œ—ùÛ  íÖçX¦Ü¿i¢.oUµH´úËØ¡G¥¿éý°-ä$‰ã†!ŸȶSö¾&{ –%¦Ñì„'`){‰®C "€^£]u$  Ò;Ȇ¶É«ŠÝÔîvy ѹÒ?À†¶kI´äî… ÔÙÆg‹S_ÿ´ŒòPk ÷KRž¸_¯bASØÑU¿gÎ]Ûy'Z5á v~)žj”i`û…SVÓaÊæõ{6Ø œÐ‡Ÿ|ÇÔ®!¬Ö7WÓuå”h 2ؤúf8¥2PŸQ_ƒè‰]eâD§¿Wq®˜ä)^.ÔY+,xUè²×Yê¿ô^}U«Ÿ,sÝ}éÔ2¶8ßÔâI\ÿx O6B™ìŠœÀ§ÈÊуf’ÊvøxÙàìdkÏ~D@ˆì¾ú®– Š–1Ñ‚‚>†YóœŽéÔhÈ ^Ùh»¤’%ZáÏ»:@5Zè_pÀzêœ"ÝSŽuÔsÛCïw4h$S„ÞF± áj×¾»Ƙ°×4›ÒsqÒ·4NÀHŬ Ìí1þñs)‹B©Ò_ãEc’ˆå´Á£6'”4|›ué~ž‡[’U˜Ÿˆøym¯’Í T%Ýý”·f.½ñ‡11»HUsöÆ'lÔÂvëB{T/;/î¡u±0ªøêPüá2GPX¿ˆÕ]¢ÛmqiÕ ~y°h ’$Óáú˜’ b·Òy„Õg[WáéàYwÊ7Éû"D˜‡†èä€%&êãB‚&zGüj×Z!9ô7 wJ"ÌåÑ`Àêø  +0¬Åi»°ÐãÝ3¸RWJÀ0þˆwÌ·n!ûÿ)rÔ N£‚‡Û«ð·oИt*5p-Lé߯Øy¯Up.8 íÏ0 o­ÌD§Ã±àÊ4_ë—û):êSRùÑI>òúêôÑn¿j=w¶ð;½‡[Ó†NîÙgÕNì‡4©qµøµx‹ÕåB–w_8‘7Û^øºÉ68á=5‰ßÑŒÙ~ÄNÿÆPSYMa¾¹DIjÞ‰úž&$w&+ªE®y{ ÇuÈê›ècÉ/¥nsÞ #—ó)¾³ÍŽ$$Ëlº“›_ ¶}öI[®q®1zÞ§}:t¹OùìwŠÀå^熙*oÉȲ`‚=Ù¯“Cœn%;¹jþlUðí×ÿNÆFFTúw¡OÍÖ‡ò){å¾( ™5!'Cf¹Ô§Fµyß ˜ž¶6ÔŒÔ`ºí¹*nN‘T´æ*–©ò©˜ÁN å ¡ÁÌl%ônh2عb½-Éi}4ü§LY”¡±&6cÌ'1å¯ü(_‰€a&eûñ3 ‹±^›ª.%ùÞz !¢ŒÇkÞé9 •lÑ*}ØÃò¨ýô,+(m¨(#¡;pÙ´ƒ¡rþ˜òµô´Büÿè §Ðʲ’”AôvôÜOUÝŒTšËh†÷záe7ؽið”šýþëñedöÿˆ)`Ó ñÒž=Óí·³¶‰Ü[ÝWoÞêøYxÛEó3'µŽ' iò?ÿRé WƒVxÔ´Ñêi}ü$úõ¶õI¸ÏŠß©©Ÿ·6ä7Ygbã”æëäÆfÖ¦·E éÎÅ›íã#óëò¶ð«Ü•Lð5peË\Št%­:òn@4ëxÙÞ•MºzäOO¢ ñÆF¸/ŸüŸ†:æZŸÒµi÷(Þ6¯ôê¶Bò˜šœïqÓÓŠYÚÙ5͉}ÀŸÁ…‹µZJKk¥HÇï^ýñ°†4 t›)I¬ÃÓ*31‡U›1¡hRÿÓ’‡ÐR°C¥©ª;IU`%žÍšŸ®2ý¹2¹’€€¢V HT¼ò"É…Ðo9²Ž‘Á< ƒàOažú¢Ø7÷8ÛëýïÞôäÔó:øºÐÏÙ i¿¸'€€ž&=A•Ý×\[¶¶Õ‘Ncÿµôž<ÕËWþâÅçèKLw'Bÿ¥G©AQÁüfn|‹md^„Júã—À%ô<èÊîÕM>ù:¬Éä*;æÕ©Ö¬¸ñÚÑqäÊ!ù !fŒO¶KÞ¨¿ê$ÀG+õº|u=îµó>½|¿›Žb’Z´j±+ûç?2RV¬Ó“|äLî}èfßt·V¡ËˆíWkCä¨ÑçéPˆÚÜ)ø°ÙK|Èòc„‚ÈXzâ;ÖÄ(uKãÍ£ ¯9üŸ€}£šY˜kêv×=Þ‘þãù©Ì^.8b0·Î. ¹±ñmúœ+ÔÝv±y»†yñ¤Òs§Pì‹H´Äߧ₊ ç!UÝæöSÍ„A³bbÑäõ}(Uî“ðhMÿÌ –z¥?ÝZ$3¾ÊªŽ-²{ŸK$†@4eÉ5•¢‰‘ËÁß­p}…$«ÇlÀ^ºpÕUÞ’4îåþ©ÄZëì¡Û,5·¿] £ŸÀpÖòÀ£Pa•úL'èÿ&Ïp½•Å&¸a¼ÌyQ¡5àüȧ [ RÅS_ \HÇi_F Ñ1›Ø_óS6è–€ú®4ÃÓe¬%jàP ­geWºÂ =[푺ȱ¿K|giuWÕ'Ù.´"â™p½ƒÇÀ>\AX°@vÍ0±cêÑ-b‚u³M •4=_¦º }Œn¤òŸû}6P·R{é(}b«¯5.öÖóðPJk°t¸óG¡åŸCKÄï+þÓ¤@>Ð^DH?7Cƒ™°ØË•}„ ö‰gÃ6×I/ßiÞ_u7:£*–R^aº.eQ5ª9Ÿv»ÆMgÑÿ[¦_Þ3€ÈzòÎrì­Z: ß_ ýã6ºBÕ§+i8Ÿ›§ÒWE-©¸üX/[Ø·.qq>px{ý•H «ÀRÇù¸d[D jÃ;ÕVY[ )ڌϓ"[˜ÐÝXc9 üôÆÛðô’ó™ XV´gv ànE,-ûvvlÏ[êG”>Ϻƒlq¡“×£ ÑisŸðæý&XYõæ-ˆK‹[œQþä e žS­Ùâ˜àvOâ<‚uz÷»!…b’€€¹^sð¤k÷˜¶”Ÿ/x Xm¶­÷¥›ÌFËMRyÎ6hQ¿æ&Ë· B0ë h¾ÎÈÚ$äTô(ðÐQ ÛÓ¯žó!YÙeâ–Äk¬.ÄðO Á‹JI­OÝdL_zO‹1Á|²’\2³nü¦—’9`zÂwχðMÀô·3Is,~…c†(Á;š†¼-x½mxãßÿ)€ñŠ}®žzæuŠRÙlâ?ÆÊ5 (EvAFZõú“ýJ²9ëØÝ= ³¥×6ýpJ"9£{;î ΟÛD–Kþ—þî‰TL¬~i&‰ynl¬ðYH%è¾á‹,nÜ’ÂÏÌWåàƒ”!‡fOÐzRë+Y]Å%é4òêa›Õ¸E0l <®(ÍoV¦à²±uLø6/~x²Ë¯»¢}‚^‰¡€³˜øÿÍÖ…ù:ýý¶UI],R-ˆþ&•·é”&»‹y‡ûi¯Ø’ÂCQö7ÿ‡²©Êî å¹>R¤&ãí²A%ÈðšÖs¨ö@ãfõ:ïãUha‚þ› éw¯õε( šµT¬¢(5ØÛ1Û6ÎG—ù"¥ 0€¸ÊŒEm¼Úï`Tú¾¹”Çç·“]ë×9´ô“½7 ÔE‰ôq<ÍÑqÂÿ*èÔ[§l[Èxfß«æÈFwM~ÞrVòÀO7F€WÉÀÌŠĸ?Šcùì=hÓÝô¢ý€>v˜H·ø)dzý™9üÌ ÷wÄu\ÛVG2«ï „iÍ{cJÄ51w;/ƒ"8åêœSúÓœqP XæAÌ-•/àrøZбîYV›¤t ‚ZŠç™ë濆T» LVQ¥³—k1ÚæêdÉ–¼ZQPp=ás'Eþ5ÃvÇä¶¥³ˆèÙ‡Ÿ©ÁJÿ‘¶ŒrjÒ±¹O²¢ßBNg°¬Sí Òq. ?$‚§™ô ÖU÷s”c9ÂmL„£Æ‰"®üÕ ¹è¦³Ž_à•4žYüŒ¬O¼Ä>¶Ã|³`…píC>Ááÿ+r)V-HÒ"j)J š¦¿*Ëm(IÁWª¥¦½—)«‡áðέOÊc jRÿ[:,A™Ç—}œÓW¨õ3 > ÍŽ†¡š³Rx–ˆ4e!bÆåMÅp‘â²°, =¡“,©è!°9‘¿.ÃÌòvæN[êþù–ô‘OþûZßU„°ß!©+ã RcX~„RBMé3˜;ûœŠU³ÛˆËÑÂÀ!R¤ƒõo.×B1éöÿ ¥ÆÛûGÑ~qÓúCó }êÀ9Žžñ™A¦1ÂßZÉ>”ÓÓ41¤i”••ØíÒï|dæç.ã/mÔ¢3Û)I›aA®úÄMprÄë˜,FZEÐ4‘Ùßð–k³î>ž>A{[Ì—ZÙH¶N/³6¯íõ}ŽßнKµ®hc‰’}l„/ëÌAdXäüæov†Á¨Ëiª™ž¸ˆÜ&ûôNù•'ôŸ’!ØÙZ¢(• €}ûK²Æ2gïÚÈ‘¶yˆwŽ‚u¤í€À±ð?¦6Œ(—?¢%!ɨ‹e’€€®ïéNúªˆªKéjøòUÓr$…<Ïçº4{Öô°¾’¡ \@ÙI°ÿ­ŽfîÑø“ æ‡ÖûRü‹òðÇr³§Ê‡Â,UÚ(ŸNM »íPÐú‹W¡È×g¾í-T|•v;o†FÈHmÛçêP5Óú¼ ^é®BýÝîØÖHD.3Ö'†Ž¸!Ú‘ób—ÌЉÊnwÜ â/W@?‘jïL Eü_(lþýì‘|rfm‚[±ƒ"°W?½ 1éaÈðÚ;ÆÕÑ%'¡SënsµÔÉM 5³ÉI~ï·={¿v’„7„=zg¸ß©°_ZZHÉ–aãŒ=×V ‚Pèì7í²o“ÝÂdñl‘äK­ ûçýhš’€€ã í²óu1!iü˜ÑÎIÎIÂñ^Áaß~µðùϘ¸Ü£ÉßRÙÜߟ|– E¥Ïøh¤Ü-þ ¨q\‡Œ‘}厼”d;Õ9V|°ñy‹%4XçíÝfܬµU9dP\²odŠÄAž‘&.H='Ž›B.éöÕB›êÅrhhEh”2eäÈ“ù‚¤`7§]¼ãvÒt‰M§´ˆ_YÓìÜ€¾SMÎv¨€ØS2p+`ÄÔ9í–0þAâ7M'ßÚ¤©õ8Â’³Ô³ºIRA¥Úþ†é±"QÜ´úÊBÌ÷SÄ¥úóÉ}$j~'ó.ø .0ö)u/#_ã‘-+vÛ͸)OÀ+Â…hÚE¡T¦’¡zÀ4«Ð'˜AB(””’ JÑõ#*v7Mxþ¬øòæøY%Â!éÍ¥n;v³K¡C8#»Ã;%Py†òR]PžzÕ€—ïC—Ë8Ös,áÀ\sºžå¸RÊÓû2¾}dÄY ±cêˆç®ª+Ç %öš¼ý;Ëu\ÆŸ¯DƒÚ,©€yüœ‡˜ÂÃOß9Á«û"9y ~|sÓpwÇ×üCy·QLöï‘Ü/ „Eõ8S§¬¿•÷¥¤„®ôë±fWÉ=ì,ÁøÝURf ìZzÓ(uDì%f9&:ŒÂþšÀì¨7™ ÿȱii_ ü¯èa)ÈÏE¡Q<Ç×tò?ˆÓf-i臑Ñ/—˜ÍÚ|Íy@®MorÕª(–µi·Ì] 'Îì75“edÊýM¡þ6žùÑ4滨}…Ô{ÙÎ .)ž6ÁnÚ—ï©ì74¿Ð™–¹–65'Ç`èøBeãR ÖWyfk#l£K¶b8 XMþÊU Iå³H JTRoð=ò Ç h&å ŽuÅÒUžz>ŠFÌ™9gfÙäÌ÷í"/háÍ&’€€Ô#&.|S×’ö¨ô§OÂÁÞžœº½‡b¾¨á¬°îز‡ed+Hâ>rºqà·fÄt7Òög 8ý`3A²t㺜ƒÙ"Ì=Šy 08ánòWRƒ¨iqI×£4³ú á_|aq¥rÇÎ#£ÌoÄÌ2®Éõ2ªp—’óåH¦F^¸#ég.Þ”­¦ÍÛÌBB£8æ‚ )Õ½Üü­{Ø¥bî/¢ëøò±ô3.¥ÐÝDùßtý,ùëx°ç?§ôc{ºW‚«åqâí…âdÀËàåJrüëè»[.ÌØå¥Åï#ÿÆö—2%tëO:ªY ÓyFD^<’~ä™ëV˜.I´zÖ ¶e6z§@ËÇØÔÙ‚_íç¯æ—\è)q)}0+T84ðõ€=côè°Äv¯Ò•©Ö,/—Å×msJžéÚÁ*h »ê¢VÔŒ«„3_]wsC GÀ/wÞ,㽎Úä8€Lk[ê¡mF "¦zŒ¼x²‰J» á¥ûé0ÐàJ&Ýzó!j2 £A~\T.AÛvÅ_zœNG™½Æ3 d®TÙ…õC¨²–¥}Ó7þídÌxÅÚïH›M`ªþ„YÂ_á/[Nœ¾r“6õI7]åQ ðÈF/ñ’Ô»f¸6`7Êÿa™¶}ꬲM&Âo¬Q¨úb8…pšÍFààl@_¿¸® ]ßuV¬UåÔ&b—üéaëYÞJž\H¬IUÄK…ƒ4`X« ¶í¨óÃuS_-yCd˜‰wc-VÊ›ñhÛ¬ä’Iœ`™kþÊ 1w5á‹j'Kð"H湆—ÑëÓ‡‘d_a*Öø~Õª”fŒN5OèIÖ ù]X$ézDH/M%q¼×}]ýAN¤6K‚‰Äx/NHøË‡cæ0ÊÈÝŸþô!íTYÂJC;š³¾ Hk:`‹ÒU·XiçÛòJlé·¢Ù&ú8ö(ÃhM2yµ$Ú‘ŠÒy¶ÄT ßíª¢&DFxá./=þ?ÁS*ëp“¥¸—WÞe'„5^Šê{%‰fŠë¿$t”@RšÅóR%él·´>®ù2H/âä^Iè…x+G @v¿QQ˜RhŸ{ËQ0ÞQ‡Ÿ‡¹’€€§sŒ%£/š‡­.Ý–³( ìq÷¡¸ˆ˜¦¦ísÞÿŒžaÆùÍsLâ Œ‹“`?ÓM¤›>ò?ú¢³~zd*S×FÛ³ —š{?m®>œþ¨“ù´ï îè^©ÿœ9Ò[jk³ÍÊ:sí8ÆcàùÚß¶=¤M^£®ÆéàRZ1Ò_o‰'(] †Ò7]"¢?Š+Io«U°•4`å–³ i¾-låöò ‚¸ñšuøJ‚Plf$P¥²+ _*» £ ËôCTmQÉ¥ EäZ­_MÓ¢¬õµ‰mŸ |U؃C\Å@²Ç ]†‘džعF`Ú©¦‘Öˆ×!Ž0BÐÃãço~»O?&êMºä–g-†5'?PycH?Òß`¾‡Œ™C“nß=ý,…X†e6ÁZ—eS”:†«ØÈ¶Ç¼Ž³Ü°Í2· ®7ã<Ò캀ú„MÑØ®4±}Dà ÓÀƒÛ4ôruØÐ3ØÇÉŒp’%?non[ÕtÒZA>³å™'`ŸÔä”úeal¬ryM;.m>e$šö«YX=…Å®I{‘ÿ·h­j¹$Y9àJ9ãÒkïµÇ?ÄoBôôöÌ\ÛÓ#½iAñ8–È5xw‚2ƒA;uŠbü˜CTÖV€Ìü^ÖñÐYY°eŸ5 Ô*íÛ7ÄBûÀB+ÍHöÊcö/N¶%&*‡ýÄ¡³¼“gg‰ˆŒTó3ûœö¹JTlÖœ`VŸzuóÎÙóšcLÏPëÝÏÅðh@¦Ê+ÈéM¥iêC ~oC/EptWt¨šÜ.PÐ÷{øjýÖš“¨j;dSÊÊ1Í¿­góµˆ!zˆQÚ»Ie£"˦1mÕüÉåà©3f|vHÿƹÖbıL´n]ø¡;&¢cþ/oƒ,Z®ŒªÙO›¦"P~xŽƒdß™|¯ï¿„0TCl÷ÙZà§Ê´4ÔŸZ!ž.Ì{-¥”~þä Ÿ±9‡œû¯ÈV^êWÌF^¼HË>ˆ»Žaû–åeÓ[×ÑG¿XsÙ¢,¡w±ˆ‡Òû¤ÿD·ÅøüJ,Ðà=_É<¹Le” 6îYìi…=ñ¬h›ó¢¾‡÷5|f!Æ6\ÊN`1æ† Å69Uü»i°˜ªc•K8r9±’€€Çä~OÄ®û:OLëÊL% •nï=H²™Z`±–% W?ßó\±Ý^ ¥ÿPŸ…ôT½æÃ¥—šC·çd¡ýö >æì {w¦(õX¥C䀸 Ù`)Tlþ€}´…Kº„ê°QÂꨚàÇôµç¨¶‘l–(‚þωo-öžEõwžÝìþhü¨ì¶V*ôxFDxKÿ¢›÷‹=„£Iäõ…a›‘#“æC”€VÐDmMkÔcm.ìý|‹B‡0›púv`d·ôi±Qûa‡Ÿ Ñ'µAå—þþÝ]–S±ÓÊŒϪëÀ”\ 0{0œÃs,Ø&ЗEÁú±Î¤­#’±£]vX£Êˆ–ð‰-ˆñ;ŠüXüKï\!{}cÆO`ÐëÑý%é7ºX›Í͉ŠÜÁn¯6¶ ´®}«Œ¿„W(Æb5Üøˆ“Lû¸ój ˜âû‘áž¼l%[J¡R¢åTZyŽœ]½jÖå›(btÊ?¤.K§Šm‡¸‰¸V}¥ÞAà°ÑCªhìí-[”™ @Å'k¤ÂôÐŽP¶¯Cº:6èÃeðNƒùN"Îpª# ÕJg ›ï–a-V#úÄʲ³6í>q„"÷±Už±ˆúÕÚ´r7'ϲêó,:=þƒaQñ.ç³Ê0âÉçÌ’€€à#·*š½FÑ8ìr_˱E½‘^ TŠ´vEÙú?ó¼½tÙJ±6 }Ç1`­Ô3tª¾i{]¯[ŽaN[¬BÄž¢-è½ÃcEXá[áö‚¸¥ÎC¶"BÐݶ‹ø¬o Eã`Þ}•qæšRZ.½ëÌYzh Vâ¹àïón­›³¾ò°™t› =ÓÖ‚÷Ùü¢Ï —m>"¤|túöïS aK£ÿ®÷µr¿]åùЈ›ã&+ËçTîaÄñôt €¢¨Ï: äÈ ¢« ‰úfâ"󤾟êûñ/žRÓ…bÒ|çç•»ïB.-Vƒž1ܧ6Ê|ÌÍõÖ,‰“‹µÁµ[3ÝA`í’(ˆwEy„€7}úhôC„4žJ÷ªI8­:ÂftmÆa…·¼ñ˜äã ®7ÿˆj¾†2ïCJ™’BC'¬ ”.¶’m7,;l)‚›ÉOÂ]a8$ððqÂb»¤çp!¦һ”N+SÍRrg #nùÞÚô$ÌÖ/¨í?™…“m ¦ä ‰Þ$rÑUÛh‚;Gïq‡ŒÅ3éD?ýx ¸<¡Ò/ñÆÈ§†¤ÎõŒSñ 8²€á¹¦‰ó`§›èijå­ä¡ÇY#Ýiã<]~ioÕÈ-:5ïßp§ähû¤âÇýÂ¥óÈžæS-†d7\ßÉŸzør#¿1±+$”Zn<ŒÌÔgñŽ„‰&Ýì- Ù-ô$çŽoc*`*, ´â]j›¢Ù Aå Ïýn½†£K{›%MGí^Ã?)qÑÜDó¿Çh‹ªJeê Óémƒã;ù…O6:Aç÷Hó¸6+À=#ë_%²ÿP²&Ýê2AB°óªT¢³¼‹ŸjÒK¿µu+˜—²Sc…àòÖjXÝ)Å­}ç´²ï Ì»k¸íܺytè©cÙ¥ S¢œÖ, ‰ëjY¾áþk°ªŸ4ínjoêI„‚¸iN~ç†þšèêrÀ¤T6=20éA»N¯>—©úFךµ Uk)D†ˆ ؤ YÞ*W@A¦£t,A[(®uî. ¦ Þâ£ÝDÜíÓ¢T#`”"?m˾3ˆÚ‡˜ÎÔ|-žËÌ™ƒ‹¯˜Nñ#’UІŽF$ ül÷¶üy»Ý¦ÙéòYPý1Kž¸5z%À¡'˜U2‹¯k’€€°àGÑÂAOïzM“ÿû€HHÏë&T·íÇg÷; mO?=›³e´t÷:…7 «n*××.>€Gì2‡NÍyê^Õú›E2†ëc·3¿TÆPŸpÛ²éÑòr,tâ£Nl¶¨xt!h²¡^ôâgd?n+Óõ%´r ù?jý<†`éU®íò»Pu²™ÕÂ#ï¹ÒÙ½&wA_Îi¿‡ÔK±Ôø»gƒ£vƒNü[Ó´4܈¶šGsoÄQ\/ÐóÐö-×pW>וIHb[äÏ+Œ&AíÎGWyLNÀر¹Ã;ú°Šp2³æÐô*êyæ.¿_ú· ïjÉH™gK»UL•jTo¨wCßr5·U¢)-­Ó|)‡uŸ]óµ+tŒDGVïFvöCl±Økšè÷äÅ1qèìÕ¨¶hIç =®ußF™ÔÀgÓµX¯5Œ4±Ù{>Q^ Û/ñ*.˜oœ'p]vË^žöDß6y¾®žIk¥‡ &©v:"óE}OHxa^Z#’€€ÊÊyïb­H‡÷œ Å&B3úg Jì¬+ØËÀràP~ зðMÊ*–„Þ¨m³¾ºÏéü`­¤HìNÎì͵cê À‹78-BºùpG­„†ªKð5Åz\ÍÐý꣰øO"u¯àór¿x‹ÃK+ìAzuyózé†Xi$ͳ#S9tŒ§Í„––ª!|±-¦ÚkÝ)C& ø@ÆëçA§j;Þt«Î í ¨À¿a З Å\j)r¹Y˜U½¢ÓØTÉÏy»Øú£ÝïåV»#çíœ^AÖÿGLÿf8ÀÅÚ“ÄcóK½·×0ÅË(õàLì§éÂß‹S¡UÔ*R̰%°ák€ô­I eI`â#Ûn¹ R]3­sþ1Þ›äQdNÿ2Šá‹mì*·È?¦HßR†’'kÁY¨ rG]²Ûá¿«œàÍ Óî”Ü™ªÝ[-õ2”²Òͪš ²LE¤:¢}² û¸ë“=Ap0kPÀÔ÷y„³­_Þgø±üWøH^/rÇ$ûùtóÉÙ÷ŨuìÁlÅÅmüŽÐvTz–JUÕ¬‘ÄM4’Î1•­*ítÀ̸Z M–žK)Îñâ QñnHN%Å‘ƒBÎdÀ5~tôÏ’†0¢°±ñ¯VfÔWÁód¦CÕ#â ˆ¬±óÇö.çP Ÿ ´že½o©°Ø±åYÑ8z~Ž=S•‹øçwcf±Ñþb x_%¢ÇšmöS¶½HµùºÛØË÷ȨúY…A)ò\ÔÅ»R‚:]÷ Ú¦yØ×‡8hªœË†™ŠiZèìáQtQü—é)2•±Ý·:toÔíE`mÜg=“«/©Â9¹HïÖ«Qí — òÓQïÓ,ÊèYNŠ8ì™ËÅðsÖØ1ÍÓe[ð&_Çüƒhw:â"X@]µR æÇ™’qpôõ‘à—c°Š§Š[´Ò&¹`ˆzÈ}®”?“CÿË?Zü0 À8–í—ñÀŒ±@˜ùl¥PHgù§†ôˆ·X²… xGÒªþQMÖxÎ(?þoØyÃîqæÁcaö†æ?ávwù®Èã½j¬ 3"ÚNš­Ú†¾0‹ê—¤ÖÙï„õoø¹‹œ,›“ѽàò°Ù™HoOls^÷}~æÖÄo+ ˜Qû@1J½¬’€€Ïà9®”¾ð»nÄ# º`>jëåÇ@¥ãÏÜG H«ñJT«V¡"ùÕ”bªïº§ª«7j†'EÓˆKláoíÀZt9UaLXzY(ÆïŠÍ:‰ó¿"GC.Y½zÚ"ÀêBÁªVÈøMä¼j–6÷'CóåõÊÄG¼-Ýr¶Ü,+gœ±·ù¿ñº®¨_ªñ9k;št6ÿoN(|C Ô7p®‘(–>Ö‡Øüùm`A玕a+`a"Ã鉓‹¡®råÇ ègþ,se #˜úPvÆ›a¿dü|’H«e,-T]êru–f ¸À’ð¬§ö׸áAá‹"©ÏÜxº,–²í,gÒéŠyÕ-#êÅÛéÌéb*·òòƒÖ„J° ŠP©@¤3KôfæD‹Ë’°%Ñ”}äRe¨û< 'T¼«[°›ž®LfüŠpÙéîM ¼8;¶ d®ÁUü‹R 5ÎtOJ!ÐC§ù¦÷q1›–D5ùŸÀ¿áæÔ¹Ó UTh‰f3Úv§EÂýsDÛŸCÖ…ÎvÆÝ;™)dȳ=™k+iÃo¥Ì£»R–´Ò³Í«´«úK§òáû? ¢þ‚IQ®džÑ ‘ Z¡™«“30’›©!–"6ä¤Z0ä¿ÊM³”"¢|5OUÃÒxXU¥ˆ`ÏKn\Ô§á oYйÝÐä„ã‰ÙÛžPN2´ zI%dºU‹×ôeåÚîe˜Çõš/U…û†$Ii÷*½³Ð•e¨‹{é<ÀáøIU΄ôAÜ¿~ùžøgºÊ"$¸JÖ}HýУê'HñA€c‡·$ðWgGÀ|kò0!ÏË©î\Ûú}°Ã³‘e§?³Àéºâ":Y”K(oÎYÑr*Y•Ô, kÌÑšÄÃn±Î!žôVg¼K}ÓþÌë7ñðf@öõf•f‰;µBù¦˜WÖp^аê­é¦XÇŽNÍæŠ ooó ±çúŽÍ—=' t¶\ÐN:¾f©7"Uj`Þô…˜ZÑ¡S6Ô°>—<¡MXŽ>s;t¿›ùÔ_Ó‡$Z*—%3·Qâïc›ãqñkJW§ã_iÉ¢9–›_µ>X—2ú**½Ó«ŠV~ú=”}AVŠXc 9£ —ä‘ÿ4,!&¿šÉxܽ“\ Ü!ÃÁNòÙ Á ’ÿ¶ðÊ 5›ÌTW<õ(Ž\Ï²Æ qC7V4ÆK†r"¸„s[ZÈ6¸Ô1Ùï ÆxSi3pJ‚Ò¦|}ÈÈs©Óª™mMÂ1ÇåƒÅ"*Ù…6W12j“ Ž÷’€€¬Rø™ò‚ P E3è™äŸ0ù41UhV>Û´dß_[¼(a–¬‚«ò®ÕïäDðXøzÞ=MSéWËYÏ<° •g¡Û^ïŠÐÜô›Vm«ßk+ïcØLØå 3¡KöýA˜ƒÞv;Åð”ÓÊÚHª£u!œ‹Wt°Bù&cѲZn^vãV…ÃÊ" Hs°>W5I€ïøŽ•9v™¨öC@ŒÍÂ…Üq¾6:Pký½p¡žûDR@­B1òÞæ´Ë"Œq²úʧD²hÌ?‹¾cë…ÍÁDH¹yú]b)€ˆˆãûw ªœ“ØþÎ;QÔ®bNšÖRÅ“‘ {‘Oü\•Í–)Q^‚–Xòx­y2k[Éð7ca’ß‘­Ã}…pÂÄoÚc]4mÄK`ÄX;·çPÍ ¿}~€ùh”Zó¯ž`.x/=|IßKÃãøë<ÙFb·Ón­v½Z©Xùfm¼xm@ÈÌ7µŒ¢ú½7sq‰0ë~°…Z>“¥ý *P™ûO7o~ßç’EÑu¨F! ô}nÜñ G€CÎ4ˆ÷”d¦×¡HkxƒhGenïQîNãébB¾.9ô6×+´ øl%+ƒç¢Ü‚·Q«§PºD…ü^WPME7Ê–z€´]²T#f 4>s›Näí \Q•±äapq6‰Üç9?èrÏû"Mìô{.øgèð„däV™0z§¢ŸÆ]©µ¤E$䘎ñ73uÌ;wt@F>¬àÍü°Æ”ÚldQ˜ÿA«Ý–«ô>û¥½ÊHWàò¬eßk(öî¿[00ª/Þ¢ …¤Ø1‹ åÉûs× DŽhÒQ dzäÉÿ¤›ª—Lƒ¢‘žy²+Áv¹Ü²´] Ùäh†T XiM~é¼+hÈ2÷l;‰ÜÏ3îÕôp‹F[ W¤b, ¨{1md0…©®¡ë–ÙøÿøohL[òN•yØÞhèÞ· $rjb81R»fiMcLmú O×£vIŠž¸IÈ6F™™7}¤Í\_RG? *x4ÿ§FbÿH³¬‘\‡è¾žpä膑²Un¶Vq4M‘[JQ­ñ*ï™ün™WÓd…uù¾öouyÎCê3eë»ÁÌÕ©}Xb|ùgíÌ䃌ú)ö¡ÝïÿàõnH…æN‰žCé+üe’€€ÓdèR“O[ƒS¸¹®ˆ›Ow¬ÉXÞŒŒÊ¶Ë^þa>ÀØ©8Êgߦ߼ˮ‚̃œ‹TìóŠwKnòl‰Ú*Ìá¤æ!9ÂÏ1Þ{[±Ú‘¢D½Ce;3ï*^¾”4v0×›>ÏzyÉ.‰oòΤ£}¢'( ùeJåÏÁT!Èp¹èä Föiôp‡|¡žtBu};F½‹ÎAJËTž@KÉ{„HN;Ð'#꿦è$°î„ òáÔÑ÷[RÓðè=ôaÉ”Qu6üÛé3c™äˆ²êÓÑÊÀa¼nÕÆ DÅaœØ·M‚$ògHŽEëÈÕ žhÙÝfh*ÑWLË6(G[s²†eR¬_ú~Î[ã1«Yoî]`ר«™m6šsê±Ä=d]ÿÚmúv`£WWH€ŠÀâÙØ¼¸úÅØ@ºQ!%‡¬£,î%L®e\dv‰‚d«l2$üÚ~qæ†UµŒRRÄ…<ÌÅ!NlæÈ¯sY©©üÉv(1n_kCc>¯- 7ÃiJ§'¥É/¦’£YógÂ=iÕzwN÷{¿ *½v3Æœ_#B„Ѹ驶ZòÈãéÀUHÃH@qüXp©±#–¥H Ô¾±)öô* )BVýþ¡•ý!®Ò“n+ÎÚã5£§=ÍY›AX?]Hk£ðPŠÜk®ŽÏ:ê:ÖSh˱Ç¿Áì⎟Àëùíüê'Gê¹µ^±röÁŽáŠp*~QµîÓ±‚±ÍÔÉLŒŠ£¡Å¾FIÚ ‰;æíà™]zÞî®­ÍȶKÖíÔ‡ÒV‘ÈcÌq#Ss¡ñx€b@ž º3Dñ•Jt²ƒŽùZY ¯.ƧOÝß%ý9Uh¾‚ô—™nk½úu@ ’ûÌKŒònO ÄŽÿûï«i·ì^(Æ.™›N&š+)ÖÆï…Õ²µc¼¤€Mlx{T¸b«š(k$˜ÈIÞS3ÜyZ#é¶<¦vioÕ·ˆ±: 'Àøù¤»ŽÞ½UKYfX%jÁ~öÝâ4Ká`T×­•ˆ ºZü8(x B¬¯öEDç]Ô2­PM›–jŒ-03ôÄ¿BÅžeæë 4/“k¸QÅË+\úbuOgè’€€¬‡¡ ¨Ác¦ üÕˆÊá÷sÙÄð2)ÉÃø‹Â:“×Ó€˜µ.(H3…Ý„ßê’g<Ñ;ï(6<Òtmb?hE=æOŒ˜á®Rï‡_kÛŸØwa‡V'Å™€ú¾·àñòƒÝ:â"sª\m![ ëv­M»e¼ªÙä;C¬?5źˆW•)Fìæ'A¬ñ=-IôæJÌh~‡M/ÞÚPËJ¯`Ù Â1S¹w¢6À] eV§WK³£òüÑŸÌx^ÏÖ€ˆà9ðîÒ–(•H[)¯@ÞRYü7øÖFd\r­Íÿ/Tæ>õ’Þl[{zB³z<᤮·«5°©™üýJÚ0ÝÇ^* A’>[o‰Äy‹ôTa›[IKˆ3„×1T/ÿ¶Ë21Ï`ñe’åï§‹ÓcYm—D NCC‹È25¦V)Ý)ŠvC·gi4×|C=–ÿêt…ëÇ…kh§7S‘9bq…þ¶8+¾0OŠPñÌÒ§&6̰¹dL!Å)=[Ð1sË×/I<õõ(ÀhLÉ|âþVPaxJb&ƒ^ǃäCuI~3èØ=Ÿ¹- ÚÁ]xs…í%¸öËûYÈÝ,Hù” ñé§}&‹[[‹¡QùF&´õuK—HÚY­lyõ…Á^¾¥á @ášÉ™Ø2 Ä~†vÐ+àWÒµ³Yø‰•[ÌÅ|à]Žaü[؃ŠTZþƒh×|ýUÈ›2˜T}g‰;ï/INÖqÈž:Šß˜N[ãkq=»7IÄÀ"h$ 2ïCbFr:ëâ°2fØÜZÔ )ÇßzAEæõ ìšÙÛ øMÕ: ¬'/ï€n‰Y–±a¥‰OÄC.äà¯k©­&5ÅM+5Šy{¯9ë¾ûSº4(DôÁ¾¢‹AR¯ÚûÛ‰#Ï*»Ð¥K»í僽šÍê€Û¾Ú£AnÄÓFWиƒ˜Ór×|ª“‹š™嫉ÝÛ”lsTÇ=“¾/» #rìá,’BOG<ãµß63²®iö^†y@vub]ïá²êÓåþ8ÎÕüv ð….jr«øã‹ÜÛˆýOzá:ÞMýÈF}¿[óiˆ}`øM·%µOg ðf‘ÙïˆUõBè6² ¿>œ6ÖôG;IÅ™ìëø[àÒYn[9Àp¦iõò¯ýâå³ë)cöÅå€sŸ}Ї‰`ißAØÒšVFƒÈm©?[žoγ>²ˆqÏ2ß_KŽùÀÝý Áž#t„X›TÞ~ž™Àظ£ÊY“¶6A£ºv7ÙC7ºÝ>È…„ËXe¥&“iKCûëkO4GÏ w3#@½Ò´C¾/šMÕÚ**‚<ˆ:é.šç‘8ŽªJlY™‚rkqp7 :i³a"[ îOA9Áø)¥„s…A•&ªû\34dV3tûÆLÐ'[ä)%ŠÀiû€<'² j” ÛÚ¯‹`)—ÉÚ„@ Ë@ƒùœk«{}?ÒЧu8£ð±²,Úyôv°…µ¹èéOQ.5ÐrÂõ˜KÇ•íQôö!\¸_ýÒDß ÕÊôÕÛZÚaÐ’€€ÄŽJjYúO>%´AïIÏ?De†H‘“Z-x;cÑ’FWõL5òÊ΄씂”‘°rè\æ|Ô·qø´»–î&“óÍ@s–z¦„HÛþ^ßøÍòÝ‚WwT¼f;j-}Ok ‰×¹®®Õz)'_`EeOgN‚ÍÊpö2ô^ ²†„¢ýE]ËôZÌ+R«æ&ÿò‰q4­TC 7âŽïÊÑ`ëÂ|ýÃz¹5‚7˜Ÿfhˆ$ø¥\¦}èÖÐŒðÀNå&;áš™ŠzMȰp%P³&^6IWµiKík¯•B'§QÅݤa€OE¿S8p0—^~ß ïÏçôÏȵ¶báyHìæîÊ@ñB&<ŠÞå"%[ªëCp×Ó¬Öƒð£q¸ ÊòlLÁ HÞY&¨gÊCU¢ÒEý¤Ô̶[Ý©¡HÞ¥ìú‚¿ó_#„!õgê”ÆÚ)í}„ž1È…E¢2\ªd& å½8ø’½ÆxÐKÐÓ*Ôò˜¶ñ;€#œ\ÛÍâ6Ëlû~!|토l ™sÂêk2QÞo¡Ú°¸dÞ}ÅÅà-uC¶I‘üÄÂE@‡´o¸?;~_¥D3$t$\jà¯÷»î‘Øoÿ’€€Þ³°’‰XžzÎê I¹±#ÄzGp©EvhÕ½im<õCà Çú †Ò:ÑòŸ¢¯\[¦í:B"ËÂóÊGn>––D÷Ûàã+Y t~ø•ÌÐ9Ú²-nî5éÝä-JulÊŽðàw—é!–hV×:´Ï…ÂМâvòæ!€BC=9æ«dà nc¥ˆ©¯93Öi›V¨¤ÑÍóŸz“ÀÓѪ®áùZº]€C…Bxìó`´ï ‘þ»îË£Às¹õ6yÂÁ¶ã´Á9 p…åÁuš0ì‡/¼×NºÞ4Û֯ꒀ€ÈµH§¼ ƪÉýA·|î/–úNŪ‰=úäµîRPìŠñEáDp«e³Ä=Ó7‘KV|á~}чÏ{ßäœåŸxÜ®²óŸÕ€ç@G4´Y`£u ÏWÁLÅrénÜõ'‰y1bt|“ïsd Õû&Æ™ŸèÇ«©Y¿UDlÙ¦7OéPoØ×åÄ’ ì©K=InãUh´ª¢äÿÖi$Ù3Öc M´(°±‘)‘Ò¦2›Ìgï'CÈÒÜRyHÈçK,Mçã–)t¦Šrî©5)˜.µEvR¿vDØJÏŠºub‚‘T¥þ&~¾,hm»}ˆj¾Ndi™)1_jЫO5éÿ(ñ¥~ÚQè>úe¥MI$Kk!½Â³2ÏÎÙËÏí:2妙Ök+Sˆ`|àQˆæ‰ß•z0ƒ¶ž¦&‘HÁ_>õ 7¨#$w)ՉˢÿøÅKØh'ÆȇüIjFô¥­\häèý,HGQ/oóÒ›ÿ`Ø¡Ci;à05œß|a‚阹]Wbl"µrD‘¯^?ÿ‹Æc•â×tÕš˜êüà¸àŽ'YDÔÕ.é<4Ò3ŒOè`³cbR…¦øÝs•29P q`Aóyœºˆ.‘aoóÙQšØ+©½}í ‡ÖZÚ-'Ê^F9~ÊÝ[È;uFáýò¸©6?^”ì4ÒONÊ­=ŠxyosØ3Ë”G¸qÇ ¶]’SÎì’5[»TŒ4¡•ý…ÇЈnâÉ`*Žÿ ¼2gd›p;ûòà«€<7mõxàˆX D^‘ÎçÜ,‡†Îé=ˆ/gÝâ¤Ó}¤Ýª"¼c‰/AW÷‰ÊTp(\c›XÁÿÏžÁƒþ˽^ÃvLjÄL‡øü{hž»ƒJ9Ot¼æ79àƒ¸rzšøÄZ" ”_Üõ@^rüeøãLМqwô2U{Æ`qæbßtjQk Ä8%ã–xS‹•X—^єﭧÛÕ%3OѯÅCM$ë«“æ7C„¶wÿXµ²ÁO·øxZ8Ô--ÜnYDøD¬}úeâ2Dpå•QÈæÇÜŽYhË2š­Žëo¨Ô‹â9ˆnøÞ$C¬éô>+êµ¦Ä © "¿Å›[0}ÚÑq‹½öv€1FËtÝÈÏ÷_)ÉÔ¥,IO¡O’€€Ê¢…$ Ò±Ra@§°Í.gÒ¿C"` 0’_â·Ww^âÓÇ#*>!fÊs€]`MâZO&Nµ±™JRß¶:B·$ÄömÜM\€Í{Š4· S·„{Ù†>¹Áí¶ÍàÚu4’N¦Gfé'åD| iM˜iÎa¥N=òôs‚—éÕ±<ç~7âa,¢ÏäíÚ`¾I½SÝ~NîW~À<6Ø&Äv°<»?NƒË›'½œÃYÊYá¤Þ–3wßy¶³Cáévkò?TÓ…ynƒÓúi1B‰³ 36~,èh§;"?áÝÆexÀóž©vÌPcsíiÓôœ¤ò¿f¬`ËÝþ/°H«ËÌxõÿj,2û¦–úŸü­–L&ë0º£_ÖAÜöµ‘Ë0ß{\GÏ@í ‹ÿµaý]š£¤å)YH…_ª¨ÿû9‘÷g”*¼ÓN– ƒ‰Ø©$DP&W;¿ºìFƒÂÅ‘,p"WÆÃï$É!«ôÛ¾€†w'vS,ßwóÂm%Ù³ Þ·¶:bÈ .' 26V)¾‹ž ȳ‚Û5mcÚ2xeCl m÷2zu/Æð*a¶0ŸëâÃKÔ£š›^‹b T­5Ækuž±äŠÔÕR5N¤2#H¹]^ñbз¥—#U Ä¥Iýèû}‰%ï¥?i„íÕÔÏmÊU¾«çï0¥y/ÍZ4òû {e]Á`Sùu'ü`®öK,–üAZ£g}f#ÜNçø„iЃKP)ξ˜+zu2½P(Ý3´Y]ÛÅ€À7Oüî"mž4@¸­+·{ý&è]"8'ô<Ÿ”e’Þü tö€cËe1½~ÍáÈï;å¿L3¿L)§¨B ª‹ôˆ2cX*È$\A“if ‹+Ý€r ÁˆÊµ§äŠêV‘)Æ’p8/¸?“ÉJÄVLðâ†e•.3ÔΣ°d¸áÝÜ^Š$ÝÔB@a¢Õ”ÙÛèîáý òø67Su4A›Ë™Žä ’€€Þ¹„Yšw w%*Îp”u_0bè>$ÇvöÄG²ª D@„;ä÷^…n… +ÚI]O섪‰¯I ÌAñ‘a؇à)Ø» n_¬ñÁ£ õPå¶z@râ‡è²ãÒ‚O…Fu/-bDŽÓ™³¦‰x›Þ¦“öÕ ¦‡ý(¶Ñ«ÚÆýÈk‡âŽ Ñ jF·RÅ×dŸÍ1˜£øQ¯Lžvi:Óõl¦lN²®6˜Úü- 'ñÃT^O¦²kDb¢‹CÞÓ1%y³£ÿ¼÷>–€+ÑT}_91LgòÌÿ÷ã¬y6*ÉÞ]‹‡]cj°x-×÷À74nh³á ¦Åbá‘ ¼Þ7…yuéø¶ú»áGH©Bƒ»}k<`À­ì²CÌzb³¢êxìmߪBA„…VIb¹À#”§n-ù%|ÆAÕ$yÏÐ&ÿ‰”é]HiVuU©}4q·¹ÿ4Œu]—D8Çà5èu‚S ,Æ\÷( ýÏ­AŸI啱[c+¦Ã+'–ѼÒþe8þx„êÖ&]kš°P½FýÒ‡à"¥ä‡ ð;Ú Ò–Ÿ£ëSWCsºßËl˜¯J» ó¦oÇë*êÎÓ:´6>šûNÖÃÊc¤Ÿ^Ù®Þ$ª›ÄC¶~»:»Ú}§4Aô„ð“ŽòìÙv°÷#ƒô|ÿ9·R G…ûæ•f£=[zdõå·X©ÅV]M̲ôzÐåÍXÚËõ *DO¢¯áý1Jw¶un¥¤UÔlK¦±ÉžŠë ë³q Xý}¶ÕZÚ|V§.Ó;(dàoBÔÙíL¿‹×´”"›£¡Ì¦ï?‘Ò§½mÄqBTøž‰žcóÁ)Bd~2Éh\Ûi{šBÒ®‹ƒà©CÓËŠv/Ï9&Éi'á,ô¤ž?ÿlƒc±¦Xžº,LŠ.íN¢µ÷’€€ÁZ»Z Cí0(Š7¿5ö2j©;÷«æÎíšÇ~9ÖóØpV¢l!¿ày|÷þ”ÿןhë¶!xŸ7Þ&6-ί+©NàïÙ³Eãû÷­¶?¸!¨‘Žˆ¾ƒf_}íËœ»:ÆbKFrÆò´¯×ê;R]qx'É h½~(Eö¿ ÈVI›šðp_v y}C m¨ªPXÕóý?Õ7œ/ío¯[Ž>‹q{ûd'$”š¦`LªÓÌRp» ²ò¼_„ÐgA^Ó­= ‚¤o21§*Žt¿°wYÏ$茠èvw­F '÷ŒàVY£á5Ó Óñš3 9ˆUˆÆû¶Ks¬¶äÇ“E·Rø÷R çFªpn* ™ì/Ã*äRDìÓ>b;d¡“ éºâ™6ô£ÑI¯-ìå­#ý“ÚÕ$¾$d˜ø# Ê}'ó¯—˜Þ4û=É-èö_½(~„ÀXªû´5\ð²{È$‹å"E’€€½gµòÃFöÕÍq˜¢Ú!QžŒ­½·Þe=œ—͉ÿÕt„B_몵NDü2DùºË«±B1â#½#«sß&c&+ ,ZÕ±nûTƒà­oB/~M‘¶È0þì:ò I.æ{úÃÀ¬Ê> !ÛE7¶T2©Ø0Û÷ ó>ïöº QÞPT 3øä³r”WjÆ™b¾ÚDs„\r=¤/ˆˆ¢†áeûûÞè1ø¬÷0ß“n6Ôšówd‘Jê ž^$OT-ÑátŽ›¸—F2š*¼§x]¹€“ÞBgs¸œ²púl/Ø!l!ÿ¿.ÔJoÓG+ÙÁã~ßÑXçUù`Rl JZ×{´¿1ÜáιÌ{ÉÉ,ï¥TöO¸SP`§õ¹N¼.(?snõ6Xõ€J^þmÕ0PŒ²ºáÈôWþ8 6%¼MyäoóLšàÎrñ ŒÊýÆ7t ]ÁœÙ¼¶*gX”eZÌñ ‘S»~D€+xròÒÄ¢H kT=aèß…^¦oâ$JHœHTÜäœÃ¥à©P_Dîñ^[¥:iñ1#ÿ@\¸—=ª°¯’ç‡ø:Ó%* )êü5ïšïFˆ®IìÀ¥4nôIû ÛÄ©¼ öÇ.|¬k7— Öš½íHÎkw±¦°·'É Sìù¡êä¼WÒt¹¹oÇ^ÎVBb ÜT‡-¦ÈãuŸÝøß”6Ø‹¡`òt•ÒQ3«Í¯¨·EôvFÛ¡u«îè#Ô2¯‡ƒª‹'帗:¹·'Ê2H2¿•†ïËIÿâ;ñXhepòœØÌX"üþym óFÜñ®T„âIÁ ŒwûlÔe0Ú‡]ìy0©ˆEn­ª¾0­£ZD‹Î‚¼gnXˆƒcÚ=bÎæ·lÉdÎ)îû±È—‚ïG<0*·¡7¤6+Ê¡hÒ#Z|ØÝè»îÞìZÐèßKeQýW÷ çÄÂõÆIŘë©va™Ò:|‹¦¤í#•E0(­¢ ÄpÔ¶£ Ì›ÆmâÔîÕL4š£x—žte÷Ÿ_ËWé­{Qà=ÃØ¯Ç!Œ—•ãÁÚѵòÚ}*\SgΫéÛ®þ͙ǵYÀx‹R"ác–¾Ï§Å¶à—è׬éòü­öý[¥’€€Ïçà²tah?sU±:ÂÜ {‚n5ДÔξO½äˆØ'ÉÈ}Ãs·‡.ayìtSÓr?¥.½“zÓ@á‰fž}·djgAö#Î.ž”µMœ¼w‰ô×r ˆA82¼–ªs½ž²M.1dOÇ®•¬î¬$½jCér Ñ›`¢Úôº†@L^ /3àÄRW‰²å~ÜTåY‚«Ü¥MÔÞÔÙ &Áþ*üß-GÂŒúx“Ͳø j\Ér‡†®'#4Šp]®Zê—qŽùC˨ÉW# á–lÑé"&EIWþ Uù×þjŸ§_ÛøÍÐó'YŸS7jic¢¼x]áF.·+ †€hR‘.Ú÷\Cí®7†)¥î<ìèºì~Ü€zVÁ±'ö)=Ç@Wh¨õ3DAG\€ð]7ÖÌÊB ,nÍ•™ ôÂ<¶€cgÇŸ{xø°ñ5VI»¬U,76>-°¨WÃ?$âDzœ!Ežç¯nzûY õO8_…ß· I|rÔ Øžpô KB_ÈCÞ®n>t€$cGVݬ·@+a-ŽŸH<Æ"YŸßTÐ{Í=öæ¡SáíœäO?i8ñbݽ±îÂ1n…ïaæFà®S›EU2jhvr‰‚õœ9ØçSíº#ð¨–$ozdéZCÍŽg!é©ÈÝ] ¡º²%‘Tò@fü¦}<;ÕÕ½aѾù€´ÊdÌD””ønn¥M­‰$ÌÍPW¯éeÃ/G@è2B£mßcÀ»/Ô»`l²´ÃÕÇàÕ e `I.æt}(Dz–øö¯{‚•ÂÍvÀ«®Íàf’Ö}ãv†vœïnj0jûg˜Ð3#zò5ȼJ¾#‚å` ¸"¥¹~¾`“:èá„ô½: F×™?p 7¬Œ¼âµËD)¬Âüx¨f"¼})?U22Â^q;ÙŒusÛÅ «˜±å 1)SÃ;‰ÏÑÐm\ø~­TcÍÃõیա=¦aqÔyðFBR!õ‰(ö¬ÆPÚ3.ï™` ™º>gO¢ªÊ‹Na‘x\VßÓÇ8Ãr/ìõúù³I<?],ÓN§îu#­Ù¶ÉEHBŸˆïB<_n­BkžU’ÑWÕ>+­ 7>¾;|>-'„W—JÛ¢ðAt‚X È!MJR’€€Ã«‰eoîó–R\ÞþòUÁ{ ×ýts½ëOô9sÿ\zÅ(r‡N.û³•?zb>}zm“°Ÿå[”ˆcYÉüMÉ{6¨ ªì‰Ž¤˜FhÌ|$]Fs"ÈOz_¾/éð7šzQƇªÄýqô QpäObC^Š‚¢O´àU R8vüõËKÞVy†,aªûSô¥ÿìB8òËákT·ßóÞuÉhi­h¯¡¹n¢= Ç‘œ‚­½ûR¼Ê+ã¾B3Q¦Á o{iZšÙF¸¯¤žs™¨“¡Œaõ?1lÆò¢å°÷k°œ …¢ÏV€†¦k("Ée;`U6Åã9çöbØÂvì¨Ôn@qÌw_ü´sÄqp³Ò[;‘¦¬Fr d©ïP Q‚wÔkF­G 9¸ ‹ j?Ë Ô2âÙåxƒÚ'ÊUéñv#áÛÖÐB]F‡4d—ñǃ¶Vô[+C*™”rµ.²NŽLê-´ªgå }ñža'þøêªÉ´dËã-µÄ›ÿå˜v®œ3כסF’wyþÿ…#ló ä-õÊÖ•©W¨nò~ìûû;£¹i·ùBT®EŸ) Q'yÄà2J޵*óÅêV]kCFŸ—³ø~ž_žåêå=™?Tg*ûׯO›7^s#ð–tmh1B¸&;ÝÎ žÑvЦ”ƬíQ-È,X B©È´„Ÿ¶Ê•¶7”-ïñFýîqÓ/Iõ"´»wl1í@Zê©–ª[W°ˆ²ÍY¿uʆû>«I$|F.‹ÛÕÂu“*¢ZðÛ©?4Ï9zoðCЕ„·Ì;‘Aò%tÔëxÎ¥Üè´ÛIBï ¸#KqïzÉú{ ^ƒ1¾:”å¿LêJ!»ËOš çñÓa×l"뮇g•îÎ$f#H g¶ójš»n }E•5­ÃM(4ŠÖšV†2£oNrYÈ ¬3fó[d+ÖÆZ¦/ä½—.ËÀ%€ÂÙÊgj»N~œÛæFï¹õf9N¼-ëfLÊZGÛ¥‚ù8ae½˜½tÌ ÎÆ«Q®Á_¨ýûBEÀÇ™³ä% ÙhY;˨ò\üTJÀù®è¸×´»7O±æyhVñ˜_z’€€Ç‡zˆœT‹ê40U%&vÁr±#Ȧ é'¡ãý%‡‘܃r’ê €ø—vcO!p<ÇóëôIªùœ@ã—,4¦TºVïO¼Q©óŽî–Â"Ð3½JZ~+¾}ød$H^W ;ôeNô€‹ç1àtè !¯zmÊ4þiïZ²‹ÈÍx0Š©”*‰lÊ®ª[OÌ·Ÿg1úè5 E<"v\fôP‡‡;Æœ¨vyç Ur¹¥¡ÿ+˜Â ?UBMíÓò‡:ì¾³0c+œÔÆ`*ç¤Êê•'íÁÆQ{Pí¦Eäh¶®0c\ÌÄùoXwƒÝ£”v¹ÏJ•Æ<Ò’ß>kŽÉöï’XS¤Œö~ª§üû {/)ññ&°¶¶€ìAéh¹ØÊ{o± ?SBdBÍ=>H*ûl¹”³Öœw¬1ÉR â˯]½&Rð¨)$)‘ÈÀÄ%„×`:>…PΑ… ÖŠÒ%¾p䦧²—$Ô¡¹Áª 0ž]äÓ–õŒ¶“¹ýZzɾ-›<½5gœÀlþ_íZÏÞÿ;›ù8NwÔóKÄþâØO Ÿ€g—7/MuK+ ¸ª¢ U?œÔm›BÁ…µžN±¸èYÇËp[ÅË*뫬ǒ@‰JÃòD“ôIž*YŠîó1^•“GÉ[’ÃÎüºô†Ñ"^8ÌSEQe{L7ÜÖZ?^F¬„.»Eôä;Å«É^«`åÑì뚇ߧ÷àïù2ûðÓ4h&ÐîÙÿÐÙ"Jk˜wùc›ãvTÛá‹"¶m¼ù ©Ç'vÚ]b›èæCÆP• øä‰û?,æò•]d,ò¸a¹õ¯Ð#µGš¸zÿ¥ˆæiz‚ÒHÜ…ȸkp¯:Û)½Å©¡B왑ùÏe¸¬¶’ºÝw_©0˜Sª‡†{€bt6õÀ÷‘ȵµîH2#ÁMí¶øJ’€€¤o½b¹ Þþ»FQOÕ;0 \gíÉa1õ ~4¾> áFd?MѦc+ÙX2Ÿ#‹ F+x]‹2;¿4/ó§%²*äch§sœ¨œp.ùѸ×ÔdýÞ+ï ‡iýøÐrs²6‘ÆÆ…|)ÐÙ®ÌËlB‚¥=qgó£ÔyRh-:íP0¯ÃžmÿîЏ.ï@Ò³“¢^Î…âÙ0Ü5¡ø®T/Øs•]+X°õhÃ$-^¨þQÄ»^Nn:ƒœ”ËÔM>–“µ@³+pR©ÊW 4E7YæÝºë2 èÍ|¬ŠŽÒúšÂ‰¡þ˜áôÂx we1:RjÈ;FâÁ:¹!㛡fñدiØkÙÐ8Rç“—‚ÆÐ=ÓØ–ÄØÀÒ/UTy‹/6f`Ë<”LSX œwõ·ó ãJ˜«i²ÐL¥m=‹g²;ñëÙùß=ÔãŽ=JäÿCVÞΖ`%NºÄþ0-|ä_ø“`@,-õ,v®Æð,8ÕçnÎ.Ôâ× ÛªDƒJìT>꼪² *To°™)–1h§¶yþ©••dg¾·wž.-¾IEÙæ;üIcáÔÍr[ЀÚ$Pxr80?~\H+¶¨·!=" '-)jÍ߃lyv"Õy/é/óãv˜#ÚŽ'¹ÏÞÁ–¿Ì0ÌÓìÏ«óØ{þT‹Û ‘À”Zí ´S¬—:¶ð gÂXQ2èˆÒ/ŒtL¤Ô Yúª7aÙ˜Ä<ŠÃ­k¦ìZÄ!z>S:itÿ±8h);…p¶?fýËæ}'xaêfs614î¨âëY ŒûxѹׇNÆ—¼ºØ{f¢¿ÓÄ캶Œ‡Vá|•éãEöGOsàóùîf(m¢þìÔ—¯u„÷k4Ïw¬2;j>àˆž¸UúZBÎ[À’€€½¬îcì º"T·ÉP³uÄÅk“ÜÐn×k–ƒÐÓç?\ºéà ½.B‹Š ×,€¬Ø…1ÒQ9åùÀÈEÃ)Àôj1gþw*Ú:ÞûIÄbhg*0 ö¹dpjÇáÔd€ŒËPY²îЛ·%,~—0•ÙuI©Ï»¼¿û툧˯KËÑHÄ„JмEçìërôÁÐøÍ\ìûâ²}"ÖÎòKJ»BÁ-ãx&C"h¾žš‹‹v4ñÍñŽßž`ÊHmK­jS’Z5[†‘ eædŒ@s¡ïœ_„}TgÑuÉŽ™ õ.• Óµê§ ì¸pÄäĶ2OÉ…x¸hðëÛüYÀ„%JHY ݪ} É^[E˜ÀZÑg ¦(VcÀÅR(4PÆNñ)„Ô+×€…*úSPËÖ.ļӷ΄üë!²°ÝBÌ猯ç«ÜçèånñPœÕòíç¨;ÅSÇÎÑá„YGï~Ëo¾¢‰)ÀÒY _”ÒúÒ0FÑ4*V/@mêd5Ušé¬U0 Vû¦æ“0”Ua¦IŸ-ŽfKŒû³[T($ìUÅ:šÕ¨=p…Åß‹ˆ?õDhÚ|pA+A´ÄlÙ9݈% 3ãVâ-© ¤Î'ògINz+¼ë¯«g¨šìž®NÁòBô&µóV³,9=î¹ÑH2j6JZž[€Ð¾Œlk§@AÄQ7A}‰K»žé¨¹Éæ —®òMOŠëóœ‡Ö’í…÷¡¨/š~.1¥PrÊÑRÝÇÑÆæft,&;b Ò[+Hxm< ceçh¯?lQ.ðr¬Î#íÃ{ÉÞã®$FÕk9O¾ý!ƒ¯}ø/#$=»³!.Îí×y—2w§xrùṎ=Ý^xÐ2¶E ¦é .9rôdí YÈ^$Uýì• ·RTùÞy%ÉO(8-r7–©~\Cñû3&—4ÆeÏ6î£8ÔÌô–?B”Y9’ °¼Ú‰9$qÎS¬œx»é‚ÝŸXJ7On{*™%’üÃMhêNÌÝ |¦f*è“UḀ¸éRàGwLDÈ£"ÖTçÆ U€ÊÆ[粫•gO íµ¾’€€Ô0IÈì“Ù½êYS”«ùÇItÈ9Ù´é;ny‡¨ ×Àư@ëTj¢Xñ' Ùˆð.±[©fJ<"f>ÃÄ”• æF1S°º½ÃÑðÔô—>ø²ËÿîŒç†§‡d”¦Õ>oê5Û¹2Ìaáj_HŽœP÷©@EÃâä· pqÅ *KŸ£3¯¯œiDÛ±ßíw;®Žé,îÿüDTó½WŸITôȾD!S0áℌɱSÆô&¦þvO®6½*z­ôñ(-:^ǹ ¿ò¡|`–ÿ33î•¶ˆ †vi»sôÎ{&;¡Œ‚ïpšz@vtjyý±|šÌAФ"ŠNÎO РLR°Ž0quãáþäP/ÐPï˜õ1ÕS ™®ŒªÇ©šý¨l¾ý¸ . Ÿ £CL*Ÿ¯P# ¢\ÜõáãO-R è³î… ŒFÎ$Â0øB˜åèÀ…){{kÖSäKGÅ…åЖ}_ …CÉË Bþ^tù~ ¸MÆ]ÖAú`gô˜ž±Âi[ {`Ëö' Šâ Å; ¿$aÍ#Pà]~œ0­Òó<ž*Z»u´Í?|¸­×jÍ«S!Â( ?¯Q|xÇLìg¶BqeH.ëTù„Å7wïÊÚÁ÷fà9È[¬>ïÆ?ÚàcE©MG 1÷&ã?³ ’ÚcÒ"¡à?s«Ò†Ì+«ä%ŽLcºX´ —úÓfÖ±µ<¹‰ ßêÄ«ká¨ò[ ¾Ñ¦5’‘vdÖz)„ôyŽ1¾FÖ£‘Aoó|±T–‚„ î~æv•¶Nw|‹mÌãÿ;µÔÒ¼wð.\Uˆ,Å·ÛÈ÷ŽJa×7¨dÎ’ä6x,ð9U*3*³¨ì´áÍ]7Ýàs,¶­ä~ñÎ%'bD@”ƒ"u|×c%º$q²Eé÷|*$ˆ’Ž+d2Mê²½¼1ÏCð‚ùCA)ùL½„Ì;P|¢S>ãΧZ`;ò)ÚÚø™gR¦ùü)>¸BãOlŽî4Í'áºp'Xú‹ìÇ4ävp@z>80²c*1ÐAª˜i}½2Eñ‚¢D² çqÛàuhrÁlhSÊâ¯yè¯]•6öŒ}ŒÙ„Yô?|åg;•X1Ö•ÀõDiÒ%Q“ ;#&›ì‘݈•IJ-7’€€ÈØ¿ô¾{îyÛïV*6üÖV)ÃTBŠÚª¼4—Å€)9yá㙟ªÈ–¨-_1úócÙænTL59<ù¤' v°v}]^xRËVüf§¯EͶ6ïl¨§>‡9ŽìSv! ¼”»›Ñó/1ê EuÙ½éõ¡D_¯o^eŸx²gU¦uLé)Àº•¥wFÙ{Ù2°rnï3ÑžË44Ï’X™G áúS¸'hK‰pÜ_¨å_Óíïíôç8~øÇ=åPÑ7¢¹“lbôV¤nùLÖÛ°Îbñ»¾ 7a,“«Vˆ~OÁ¡î¥Ðpz?þuÍ›NbN1•™Ê§^+Ú€3>VAë<Ò Õ-µØÏ¡‡Ê‘\•,D2 ÆÇTiqH C'sÉ>jð^§÷˜æË-%ÑN¾²ÀôQrîçv™,ÕZH°k4el~ÜwͤaW—ˆ +‘·c*Ûh™µ#/Çï™°“e˜LŽºÇgSÊI¢LB ã¨f¹(v\Ô¾8ª…øúdä ç°÷EöSa£¨Dw·4Vûóaž@{ö·pTK°?£"œü kGBrÞc$Yíús†YKqi,hltØöÁiMÌã˜jo¸3üD’e¹ ‚…„I|·—YATØL ¶»\CÅǦúc¬Ÿ¾œ”Äe «o~³·3æ—8ÕÀü)ÿ,B¡j ¦²&‹ˆØU5ôªô†ý}ëA81&§vÍ­È[óÍœ …}¤ÇfÔ”¥ZOøa†¼Ûæ ¸ä÷(‚á¦zž ®éo$šO`H~Ú$&Ì'obYê\9¼!‘o§ÍXáf¯ö "oYßàÌO—R,U²!>o¢þ6ÿ"->˜úèPìfE¥¶I.Nsã/Á..[$e½—À/çâRÈ/g¨/—0@E4øŒq̶Ö*“ƒôˆ—Lµ|ó¢î>µ'Ò;Ùå«4÷´ˆ>oÌü ÍÔhÙpT‹®X-_S•Âeá¸õ×=:Š_Êß/X<Û{Óá.ùçͲ¥]ÿˆJ*ð‹UÿF6,²Ìû%ó/áQPN^jËÉJqlˆà”twÍœP±éš o—‘È ¼ãDW¯câq.Ê<5°¥™ÞÛþ7õê›E¹EM’€è¡K5i— ‘°pV’€€µÏ‰n×çÝñã ?š¦È|l'ÙªÏSa@¥î‚C,dg;»œ×L¶Ìç½ä²ç”[þ奂6¡!Ú{¾¿s±æÏj"kì1²yEgú…KC^õá;.á’æ¿Qvs¸ÍÈz#úʼnå8“ÇœÌo¿‡•?Ç}Sæ!§ù‰ÐeÂŒ^ÞÕÍf§îô‘`²¤%ABç™mÙÌ÷j1x†G|x¾™ÿ-¢b}Zÿ¸ÑÊl«‰+sWŽ˜™r›ˆ±¶ó$%¿ótÊ¥˜úþØT½þixÏì?:¤¨š³ÍþaÌ‘l ;îRÅLDÀ»Ý¨ˆ_¨¯Lëðw·ÀçhD?¾|Ú”ýüŽž¯ªø}Oßîa褄½©õM§¬àí¯¥-c),(¢“öŸ»“XÇg[8Lò<¹]Î"tØØ§d˜|v ¡ &›¿ÇÐgå!°•e£šŽ÷ÍE=ki_0ÄÚP›I½ÐÎÕd ¤ÓmÀZ2-DŸaOEñŠ/›<Œõ²ñgcKd­vüÆ[«!YÄ›Å2£ò¬°Ð“s».j{àÂ5éaí*ËÐ66wB1Õ{ šx½ÎŒÜ?¢qqäÇ¡Çeº­ ¤ë˜íƒãê>$ÇøK>·œXüné:‰æ›1Á·AîÝ×5%V»rpfiî6ñßL7¤ÅdÚa /!çàÛ×°-,†GN5¡^2Ïg7ßîßxÛ‰‰ýtâ ˆ÷Y¹@á“T `{ø‘iËñü¶;@×é~~¹È¿f˜8r·þÓ!2LŒˆ•“”êÑ2¦Òå)l–±L'Pܦ\cÝ,/VÈÚ~åÚvr~áoÓq¹`FÁ"J½~xߘLYåù½J{FƒùøçÆ/WÑŸÔ%3NÓÓQ…0c.†Ê_™/ãVˆ=à\Š˜\+¶_‰-VWÙ-Ðx˜[z@/ 7ËM¥Š_ûkmÞâ#§„§;Ó–Öàß—Ydá µ‘“ZbŽOTÄó½MÎXT”¦÷2”=ª,ÌÓÆØ78×ÈjŒ¿épêŠÓHxÏ ”Ç&-úôr”Ö©•4ͽëÁû¦ë‰Œm2X±R×Ï€írã!°.Pi&1+Ä|Ò`]ýÓyHÝÎÅk½ûQö==w§º+ÄøÀúF Ô¾hÇ;ds[>½†vò+$ïý­ÔcKÉ—•â²aŒÜapïóÉSBU*J¬I¨Ø3¥š¾ã¥v‹+Zxx¿û— r²ØíŽÕÇXé†é~š‹Ä×8€§×~÷´†ÁÒžl™AbQ–‘šŒ¸¨I„Å_Ø mˆd`¹â¦Pc¢Å‡Há0i( %ºs f?5¸?&µâõå]·:=rÿKñ×CHø›N  ßJ…‚«|œ  ¸v|ĺü€¾*Œf–ãÖòÑ_Ñ) \1»8ã0•óI[¿ðš²ÍjÝz”F2´énQ3ÙxkºÖ@¬]5ý Ú&L†½¥V(K'ÛH>nïäGäþ›æÆj‰À/ŽáË0FQvžk‰Â×SÂ(~A1~Ð¥Ÿç«G©àÆ’àâ(D#çH½-=L-x<£p¦m/K·üé· 6a’€€ÆŒÖ=Àm·å»ÑÞ+nÅãv¥·jáÍ}ñØ`eïC”d ”‡«2êÑCÃ&ˆçÆÔaä|‡þ1~Fç0öýy×jnûæ3UÁA<å`ÏH^˜‚_œ$4$h=O¿‚¸‹c>€…ç^7e«ºRʰ›|÷O©¾õ$ŒtØô¼F€w­ÇàM樂ý¹·2ÅßÁSì3yDè"ºÏ*†žýÕ¼ïe\ËÑÅt¿ÏRŽŒNããJœa«{\²*.ùo Dz$ú°´© hÿÊ]GtMÄxxÚJ"á5ø+{dVËg9õB}EâÛ8'x¨§ÚbùŸÈ} "8¯Ž£ßVêŽa^³/+ø"´D¼l忎 Y ·1R*¯ô®.ÓŠÖ³kzïŸwàÄoªÕVîÇàÔ…¬@&®hå,2‡Á¦þX²#1Ùb ¸)ÍSUZ iù´Œ´âDDŸ½ŠåÇønðŽæÊµ®½Œ¸õR8‰Þ^à[eH-2Ž¥Q+ÂÜÜ!n¨j9ÃÉÖ†¤áúÇåÖ@¡S"J© m_3E×­uz GÎEß:®ÿ ÎÃSŸf:ýsõE±vªIð)%·±8(anŽôîn,¢4ýôlã¶L›ÍU[uaèÝÏ‚Ž{¿Eå‹Ç)Ÿ×½„ÁDîå¿)­2Öòô¥Îÿö0üÙCU±µxeŠèà=èð4'+€GÄ®áz¯]sÕ­Ë'ž‰¢¯]>žI°î´mß’dJiÄ};*ÛR¥EvC‹»Sš§2ræ™OBSBXÝÃsoãÒº}>®v$("ðš| <Ü&Hh‡kÝ=Ÿ/y·Ãà÷°ãržŸÂÇZ îA†è'¶z‰óuy]f¬ÜáÒòrùuÂ]€~IšX{4¨ü)Ï3X•óÌÖôêzM£ ¿Uåub“Éeºòµ 5°XÐqÄsK[(B^I·}QƒrÍºŽª½wý}…Õ’ü§Ø·Íu¶žÂõ äÚ?ÙiÅ%l,†BÙW@È-GW@„ÿétèï(H凯täôp*›ñ`E¹üáT}k8lör ®Ì –ö a7Ôè‹Õ`B?öÍ5RÀ OßôrPˆ2 5½?Ø·‡ñê|¯ÚèLœ~/›¨’Þ„cdöa¥ˆ’€€¯‘G%IxÙÜÑÿôÐ]™–M¿üÌÂ[Ú8µ @Ö™(Sc“‘hÊ_¢Ñ9pFàr½Î&ö˜[³³hùØ×-©qïWŽ.ĨùkG¸œ´Ç¥ ­ôVV°#ú‰Ññ•ÙÍ(›$"0ѬžÑ¸D.­²qÔ¶óÕ7~QXe„IîwÐï`DlÛ½Âjù©zZ&nXYÎËQäQ‘ªAýE憥K¶HnÕSÌdÿ„-óšwþ‘ä5„òÔ)¹ÿª…í¸Öý$óŸ!Ü»ÖejÈÀÞ P¾'B}5ü ÉKp+ÀvðöDÍPmÀîÁç߯úÄã¦XcS·B›9VŒ¦¯1ü î«O¬J[£€ôÄwŽm/0 SÖÚàtg[¢?)é|èÆ™©U&Œ½FZ¬@°$VÑD¯4Ô—A]›4±©UÊ©0Ø‚­{fx;¯Í§¤¶a1B`–ÃBU…‡,ö†YTÇÀ† Õ„ð-€]WKPª€)¸oâ¾²Þ̪ŽIÓ_±AÑùÎéÖ•t3°é/gü9”åqœ(¤²i5²I¯_ÈDňe8  GÅ’$æ>"D2EL˜¬r<Sw´^ŽØ±‹J©¦Ù¨$+ 8>{‡Á {òW˜k=I„Š8¹6Wj)Й™ÕKæÌ™qJ˜Uõ5ê&³ypf¬óS'n |5€T[ô§•ÿ¼š$X.å…ó [$Ni‰²!M?Rº‚Lìþ¢sUcfcÝþ“톉ûÔ³Cùù$×/S–Âð·{`žÀ¢‹je’š ÅÌt½ J¼Ä¤ö´äŒåˆ{ Z“:ÿqÆkÒ·¦1Va\CkéR´V—ôØÐàá‘ëdXÀ n‚ ‹:‰‹ãÀO.8Âhºõæýœ°å‚ÚpÂê•H²Œèv`¦uD—,v2w¨Ë)*Ц§JÇ«ÂD-FdèyëääRA²tt<º|‚¦“c|YéÚÚ˜_Þ™f_c†²ì‰:V‹šQËsÆýÝûS =n'dê"³$° >ÙÀ¹6Œ˜ðO—@üÇŠÛ1Ä[Í`ɨ«üçhaB8•rî:ϲª¿—}Þ䃑Q.ø!ˆÆÒ^~-EZ6Ý÷ý—¯Zö­PäªOëéŒ&†§}¢ˆCæéuZÙœ“ò] ,sø!HËQ½ó³öKë)»klI7d ¶×=!-äÍý|—ñSxÓ†¶6N+~Ù<ÅÛêӽŠ”Ô qòÓtÀnFÚ ‰y¹É^Î9[_há°'¼÷EwèC'C»Áí8'ž{¾K­þtšâƒ1@È¡2#ˆ„7¬>G]ö!bŠðÈ>b$ÂÕ"Q …þðÃy;;hæxHe$ý9¦²ëEñ”&¤ ‡8¿‚Æ%þÛ$ x£ÙP÷°Àž£ ¾W±ñswh#?‰?ó¤ê?RZj[wi"9 ZÞ{"ü̃º7ó(J¨®%2ÍŽmïôIõ`^ɇ¾¨ÁGI*E<›ô1/ÖroÆé·:îòt$ ~)~;sáÕ9ΨL˜‡|\ñ@tQx†"‡A¦â"M`FôR©³žXCm’¿‡¹—è½çÊBÍ.î+tŽªŠÍi,F·5‚¤·P‰a„Ð[ï+*‚Cçà4õÁŠÃzM¬Ë héRnû ‰ª*5ÓªÛÒw ¹_!âÐoåÖÝ27[wÏnòð,Xç&ˆ‚,Éàê%^«— %Ïrº9ÁNèwYü¸ÜZH—“qƪ!Ø+D!WëþçÁAášüþvâAò† Ë·­~Ìûx_¯ºÿïãmLÿî}¯Ä+2ƒÕ'(½ÞüÛiK¤Þ.k5óWÅa€hÓ4kX9 Õ51¦(ýÂwžGmaç>êßôÐRÀRär‚éf-þ¦­¹ë¾ûþQ§o_hg†WR41Å|Ä{ÔÌ¢X™š“«²ˆ'H)1â·‹¾’€€ºä¹´¥<¶»œÚE›§2tCyòóPÛ²ÐÁ¨[dؼ7$»j‡19äÀüÀ!òyð<¦aþÒ-C5Í í*»ÅøÝ²!qËfí BÕF¯àõQ%yD,š÷³äàôÜzOPäËjÛÅdž&®Jí:ö•ÌÏÅPZ¸u°*_¶:Ärµ8…á”ö@@ÚNÒ€(ó­Ðýcë¯2ÐëGéÕŠ½Û³úK{¥ÆjæÃΒ˿㠄»¨y¥F p-¾¨aH¸Y»eßm«òìõÿ»ÕFC:‹¶ÅÎòvÓ¥/®F • `Û£º½%ôÊî6ã ýT¼º1÷&ü«º_J¬J*2®ÃöDìˆ0F&nÁîgãCp)½–K•BˆÎ ž™ÀµeöG cßZ1r#}ød¯æDåÁ Œá¤õ]å‚kˆmŒékÓZ6á\m?¼8‹mqöð]r¹5‚8êy&´T.zEÄ‹ô0ñzó°SgA)‚|uÜ‹Yì¦Ò5_u=ÙæŠ%ÂÌuþ—Eéy¸©Êħ:4™`‡_¯VŽXȽ¿Xü)E†V™€_46üÏ0’ ÿµhEÜ% íño¹5z©WÿíR=Š 6 Eõwé.±‚°©ót.·lN³Z¬qZ«aCÏ«“|K–9ÉÿxÈHõ©Òã~‰Å)½ºúQ( ~Þ’€€áž¯#ñ}9ÿl‰&× 7fâuà€ÉW½Iñ¹Eçk Nƒ¦<›Ð5üéT¸“V’=ãw¥º{Pù&ª}Õ'×n©8 .ƒú»xÖønß¼¨¬î¶äP”‹m=´ hi$¨'/C)ÇèÓ•3oæ$_“VéûeÅì ìÜ Uš·Á}/*œõ~´^hA Å[Øðg(d/pкTª‚ïaó¤;ÉÒ?öür©Û~„6R–ŽªV$É ›„½Yæ‹á“Ve”ñƒ." ŒÆfTT j «¤9‰m»ÑŸ 7Þ¨wEH€ï¶™%ù¡r€É éiÒ®Á_æšùI™V´¤öÚkß\²ò„ج6ŠÐRûwd‡(ƽØ:ãG·×o©H¢>ý]Ìèn¸æî·œÌÆï êOŽùp]°®/´D*Û 9mhÐjãHB¢?Å’·OsзaɦÿúdªAIx)G˜ê°½Ö­9§³ƒ[ÛPÀÖ—^ÔÒ0…‡|C3¸“å1ÅÝlÌf¬h廩ÊôŒßYc)`ôÏ›'³R‡ï,/–ö ß)™å‚Ð’­6@AöMŸh 4L„ÿŵ£‹å{*èO{oÂV‹…ü³é›Ì¡âbˆ‡hˆ°v?Û)ö.Ö乨j*EšàU+ÞÒØ’’à¨:ËeÀ¡Oúùä¼ý*ZÞè«°UëÝa"(±»ÙEmÉ@Úù'Ö‚ªxS¸Ð°r³>é>Û?‹ ¹³¾Y~ëUׂ2k^¼ w ! }ª§R-Äó4eÊ'wö‘3}/…G÷çt@ÃÇ’ö!8-¹œËi°w±}ò}Ä:®ƒ’ï¢qµùØp±}‘1¥ëŸIà åUl1ß·B,fO¤§˜ u1Ð&ÛÛŠ$|¤ñ®p£wTæáŠùŸÕ#Ñîgµå°e’€€¯‰^KÛÂÞ´RF€LŠc~Œ¹@š8Ì5uS|­‘à@A¤éãè–FªÎ.A™Àâ 䪅8eê$¯ò6»CùEý ÈE⹘™#W{á›1!ÿ¼c¿ìÓ=œwÅ9²g°£óð‡KñYÛLh!®}Yw ,vz2ç”Ò{ã{®›lò&™<“+pµŠÇâ¸T¢Ç`ôfÙGÌÖ¿Åü‹\œ1וÒGürn¢)u­ ¬Ç HNï+Ç>Û3´Èþ1;YÇêÎ ¹^\þ¡_81Ðm‹Ø[Ô¶›…ÆÎ¼QØ©»H X!Ìúú`›¿ØVç&‰Nʵô¼‡‘ùa{Dü5ýïÄ¿e¿ÞTDûñ“‚ùÞ‰ô~˜±>ñ‰tå7³9§»œ£>j¢Œbf/>PïF ¬½ÑƵ¢ùÜ.Ô½µI"X˜êõ -54°¢¸nèfTŸÜòÐ’VZTèü~@µ‚ð”„Åaê—lŸ–~ÞØ2®¹ï@ºÍÄÍ-í™Ì=‰ bØž&ÉX¿UœŸ%úcvé[B›šÄ%/L¦‹úî¿rN²t—KÉ@/B§«©Ox¹9{‘f¬è°Ê6´3¶ Ý"“yÁÄÃY #·¨Ø”wp«sd¶îë*ƒi;PKtø³SsF_=™ŸæÊ2§,zÛã½Þ=9æÿ£›VT^ª·)éOÊÍXÕÑù ×âQFZœ_^ !®³¥ˆ>"WèØ]­M)üéþwåFU¬Ýu"±Wà '·Ý³wNK¯‘©“‰ŸÊ¤ÑÝ~ˆ?EÓœ´SW$ÎG›€v…ÐÄ÷·Âö/zßÒ9ù³Í™‡ý:K(gµ2¯Â‰êꌘ«¿®'ùéèÏÕÓˆW@ª{E)QKb?7féo Š–)éM3 Z4wï¨C6Æìì}Û¨ö?üý3÷ùÎMѧ`½:©kmœe¼F"l1·Üsï2ÄZ˜ìÿtT aŒóOÕ½¤qq£Ø~æ õ5•iÁKŽˆMh™©‘ènt°´"¿ùî61,ú·{⧈ó„²3íz|®ƒ—å—Çú´Q¡nÒd»ü¤ î_þÛ÷c Ãx¨Ú8µç ’§j1’Ï›«é+Êz—Öx·>ž½®#Z¸þ¥üé‡Ó.rµÒH€ªúú"aDˆqÑ’€€§À¦ó>*ì1K­}ù•P-b…Êr Díñ¢qò…üµZ¦¯ìl *$¼ÆÿRñ[WCâZíU‚p¢ßÚ¸WýÒÈ艄çÂÑ[&ë„’‹XŒmh ¾/Q7ój5”p¬žÁ‘K..­ v Ç øØABèH©”½G× õ„?«¿ÝFSôõß¹ùn>¾F®¸>‰ø©î¿_EÏ—WÉVLL«7H°å½˜.ó,°Öô+!æÜXÃñuÉ—CþÜéÖíú2ýòôåÒÞI;|}ሾþZ‡—)Üóó#SëñH’Ùz’»¤ðÛÕº…f± Á½ÌÂ¥ a&F±bòÆÉ‹WšÀ/¼îÖKîÃ@±š“Òmͭܤœ³ÌRh¡»ê?X¦˜Ž°KRl™>÷ý’¢dź·l ”¶Sõ±h@8”ìfâ:!]çò :¯ü7öy¾8aÔ:(æ†~Š/ zà†KØd7BvÕ•‚ÜÆ-jE"ðDK@ ù—]š\5ð;°]8uº÷«ô šs½Â¡ªüñAÁ¦µ¦Ýð³îdÑ·CÞ>(lᩌ@iT&VáÞRy44ßG2•w”Õþ#´Smã)V7xZvg¸D1äpSFÑ`ËsÑË*Õx^‡¼ šÁšÑ|5Àr(Nc.\zµÒûá Tøwó„c1ÁÒÍ,ÞM–rQF›Z§Û|¹Ü¥¥{¬éV:±»[BPg€¼T’B] R%(%_ »gôXöÖî*~ ç>¿Ó9Ví)Õ…‘ß$Œ0l4{.,0£Ž¹=">f°çåâÒ²«”¡iè9kaX=áqG°kµá ¥Þ³âÌR–¾É…xêR’€€ÖŒµ¥_Jq/íCµ¿•4f7•݃VõPÞžÁ;—¾ÜEá”Ëç'hm*¡„ÝÚ§5i_ƒ‚©c~ }¶çOo—hÕfÊgõ¿‰G®9[}HªÚKÎ4GG*Q1Ç'ÇA§ésâX¤jK‘XÎÂìB—‹÷$2ÐN‘ J¢G‚FZñÒžúE³d…&‹þÐK+4’Ÿ´‚¡)øø!¦Îç[æRïãíä¤z(·£.¡¹¤ç¨±oŠœ›ýšvœr áðî#j¦.7v„T/—dhƒ¦NþÕæ©óÞ 0n§sZ” pñ"J<5'KÎThAzàSìËð·‚T·lD ¨£0ôáQ· þL1ë}1YXÝlÐN«)‰÷Œëã_À~Ò Ý9ÑìÔ>  g*Æ`í›-S¸0-ë*v2S']Ƴ¬Cõzž[Øy}ÄÛ‡I5ì9kEâ–PÙP¤.6XßxH¸VoV|‘¥±]Ð5÷Y©Š=…$ž´‘—y¢—Bn{±ô‡r¸Ã³¥³šN1D Ï!*x)ÎKN9U-& ;¸¢s3òC;J8³)“ ùÉ,HX’ ÙÙû]Ó±Ô „Ýý»ñÊ\_rE1ò°øk¹Ö®œF¤ˆþ†¾ÿ+bR¶Ù¬À¹á†%’8åÝm2 £¥ ±ÖKê®YÈÄsÍÓbmÑ ôcÂaá—„â)?Øø6✷¾ý°ø0ŽžÉå¶•C©Ž»š5n…›ù[:§¯–jX~¹Î´N‘0ìù’±ï+*(Ÿ&‚³¿Ë_U»æJqAC \D7@þÿ@BRo@aùM!š™"ç)y;ê Iòdãén6»œ5˜žB'ªRG©àyƒ‹p’fR‡­zù2>pÊ(µ:ïÿ¬vn9ß[g³È=R_,F&s7×ÎÞôz‹<ŽV…hí‹v÷ïꬵIBàðö޶”>NCþ‰q…*sžbTÂMígíÖPgÑKm?š‡;Fj8‹èõJ(%÷k5*9ðšúöù-fz£‘hýÚ}:©5¥ï7 .KÕ€7E3°0öLב+Ë×·–@€\‚LT\9?Î y>Þ]}Œpš”Œ@ºdPò¾˜ºDË0µñ‘ëèÛÞD±‰À\$n¯†ü§¥æ!â’€€úýØñ!ÅŠÞg78¹$§òí¨™(¡–ð7ÕŽTÝe|—óÞ" ˜6‘àN&ML<ôkÆE˜<CÅ& £M9YµÌVÂ@ŸÐ¬ §Lb†híBâP|è9л‚–·=¥±sâó c‹C°¥8ÉE`n DßOý²QžÂ@«N¸‚S“;¼?Ö~Áš7Ž-àâ„ÔÒ R·y/Í×ÃÉ¢‰dÍòÚõ›“kÆ¡#¾`ßç¼ÆÎ|x>½3CÏF(ƒ»3‰|3ÃV&k/õ¡LóaÉ/‡ª¬’ù-þ§pN‹ma•#®SÞm†§gëYéžÉO±ê|­z7[¶PÈ$úÔ˜ ‹¢ó­P,ºÔÐýAEìˆð°Øq %ò†’OÛ‹‚É­ÛðŽSÓÐÅ»‚öÖǶPÓuð×4AñCßö×£÷Ž®ÆbBŒZ>p‡£¼cÝ'èT<‘A— =6èó€‡Kß $†íã½w«¢Ãk¸åÜo¢OfT—káÏäôÂÑ5BÿÊ¿§ì[Êíã„ò¸íéqR(û!Ýoãfç -çŒìE‰*U–WuÐ÷æu±Õ„.Ê:IêB:LŸiµêª·{–BNÓ.¬…~`ㄵIê™0¯íÚƒbÒ¤¨XßFJS¥×\[Þåÿî;­u±ù¢ºø#òT²-õ>?ÍÄiRÕ.BæØ0C8Fî᛼ò]‹ÿ!ÎV}„-mŽë\j„öþÏ œ{pÌ-5Uëa’-»íA%\'IùÅ-i+zTHBgaƒ¯CãDP6³)q RZF8Ë›cöD(…ÍúX]ʱ@ÿÐ@Øî 8~îm| .éh±)® „ŸIMJÑW Ì€L'éWƒÄ)?i€rΞ^QÿË ‚š Çã·u²h~†¤$ä‚7O+Q8o;'†Âx¦©JO‚¦dëW´ñ“ÀX¬ûcˆ¼9ÆQPÏî×åÇÀcq4R¿.žš±‚YÌì}õýo8ÞPc8²ËÝa!\ /)t“ÿµÄipYc‚7_1›¿*¨fˆ°Rûvœsˆw¹ö7™Õ(ØÖZv®~ÚÐëNó_SÄO‡ö8 ñÚÁªUì×ÇzÐ$dŠBÿÛ\²ô!ïš?Èø$C’€€½ì ì>=ß<Ÿf îÕ ²‚—uXÙXÇÉ÷Ù }jÀ5*B˵qi¯,c„þñ涸Sž¢«n ÐÄa²Ú/ºMë^S'ÀÚg?3]ßê@ûØÅõ%K¨¶…˜ÝÈRíAèΨRÉj*H0쨛äI¢-gÕ$HâÚP³œ4Æ~(“¦7:­P0´(o¸©”•°iÇë¥àD¶¨ó±{í ÷ÓËv§—cË6*Ý?uë¿Ío~Ej †¯öœ–3•Káwá›IÛfNqµi¢{XÆ…º´Á£Ò?Féú V¤UIä`€ª² (Q¨¥‡FÃF_³/* è¡ì¿æ¨ôæßÔªÒåû2=$,æ½ ±³j¡²ÖíÝò¦Â>^á¦Z‡ ûÈJd¥øYÞM7±¶ÄôÌŽhðwˆúßm¤Ë¿i?ÓÁ—¯aw‰O¥ïr(N…'®U%I§ky84b'¹IÒIÔ sÆ»ßñŒ_!},^l„bP¹}ú3±b8ìÕ,䚺ñ¾ó¼®¥Ø`¤* ÄPÆ!(ß@eúíD0˜ÍÂÍs(a?9+*$ ü\O;j,ÖætÖ„èœ}ÑðnŸ(¸ûtî5eš•#ƒ®ªÚ²6úaðäŒpXÚ©^A—qcÙ€¤Ù6ËÖ…Éì)ÈÆƒ¥_ üok»<&0/4S®Ë§–¨cì)àVè2Ýèˆû¬õ¾‚NìÀhfÛ¥àŠë{æpÆˆÌæ/ËNn/ù} Õ!ˆüÒŽ±©Þò'w²ÛÿعǭPz†…ÃZ§KIÓƒt4h¯ÚYÔÑÞ¦ßM̨5ÅÍŠH7cß½ËçTå“ íiiI¬Ò¼)òÓ¹7å’ª;ôE¨^¬t¾f‹ ‡^-¯pwÛÉPEiZ}`¿7šòRÕ5~ _t¦»ŠÒV¢NŒC£ùëO_Í¢éú}™æs›¢FèˆÍœ¢JƒgG­ôÓÿƒd­Ý–0„ÈcÑÂhé,|‡¬°”—ZsP½p KX€/yõúšhv°w#ºe.d7 ÜÆ’´M¥pçÅe#MÞQCÄùIu¤‹¸ç%à}•}ÊY—Ä‚¾Å&&*ÁþðPK剙¨¿iŸ$›1Ÿ— ²—r½dÒõÐIw°§Hx¶N’€€ÄGÔXùu(«B en˨ö0}‡p"„BÈ.-!vFÊ Gâ¬.˜f^EÖQ£dKT%“ñ W¥Ü®à·©Ì¾rá´Ë'HþWÿ“pa»jP¶ ‚*äôbk˜÷Üè]O&ðlT8‹3‰ ‘¶†1]´2}ÿ7]È—jÆMŽNmЗ9ᱸ;8êbøàH Çw3&“'ˆ1]>Ð8wÍ‚´†ù×ñ±Ã‘HŠÒŸ,)‚Ù^+aceëg‡>P7¿qœÉQò®éRæ:nÛƒqk%f»é†î %1î©@ïÉŸÉ•xùb”3è&θT±ðŸ ®‰¬’Ÿ±#=½¢:`¦cÞ§Œì{™¬ºÓþ`AÂÓZÀg+ÒBÐ^Õ ož=–FúéžòbbmšêÿÅÿ‘­EsaæO—Óad¯Áìá;x<©ž\¡;âž)ɹW½vú»Ïê Tp‹¿ý^ò0¢Q Ò2ª:‰¥ F÷_¢ùOÜŠ‰¢O`¢J¯‰¶‘$¦ùóbN@víø¡×J+2#1‰zýÃoA9Ÿd…,'Sõå\ZIû¶ôˆÙ éÄ¥Y[ˆMý ýQgqtIS^Ô©ÐJo =_kTQ;’í»ƒÒÁjøOþgR9ÒŒÙeAŠh‹•œVy=N}¹f« eOPGKå¨Ú}RHÉÓl ŸÅƒ#$àþ x”zâ¿Äèº5Œ´­Y]ò¹Â~cmßùp-}ib@¯s¡Ž?³¼6’œpkÿ‘cr@@Ñ)í›c3>wF„0ú6ËùÑØ!Í`+@‡Îç 虹òËœýˇˆ",L¥…IýGeX‡jXær¸GœÙN* «°! ö¦tté¶lÆØÍýí\ºµn8á¶VÒ¡®T¨wÅ^Z TžÔ¹óá°_zÿW“K£òs\ûfö®³…óg÷òÊ/XÅ“ "DïÜ!eˆ6ô–ÑL-I‰´3OS-ñQÕï«Ó&ñæÂq¬€¦- \Îã‚’€€¿QkìÖ¶²â†è£OY•¿Ç¬›yÑì“"eÉ¿ˆÕÉ›²ª9g '• û¬™_]nl¸ ®òuÕW”‘Éà̬®þ.>écûÉ«¤>i˜l·YÒ)½è®¢ƒTÄ­*â½<ç²êþsÊÞ=~°fc Šdú—,V ·qØ ZBG~áÉ^»ã yšeÓÜÞ‡ N¼)_àUV—õÛ¹·äRã9‹îri‡<(»xÌ\œP°’¿–PúøüçŽÐù°·ÿÚዹû‡ÄênñŸ¦eÕ€oZ#/5¬¬€qöÐÓ¿˜®²@®à«ÔhTTò•ÙŠ+Ô,ˆEA¢“%)˜ Òv+i ³: ý¿W“›øŽYÞD ®¶Þy¶ÄlkφE¹ÖþAÁ»™‘‹e©Ö3‚Ÿ¨.5ªn1C >&ò ÓV¸v®®~°ïÝFVàuÊ›7Ë…vìwd‡-©Šß¬¢îm€Âë8ŒÚ?k|Œ· ê;0u÷LæS׉jŽßsêäŒf~¦î€óŸ-ë©Öà›&HÏ"¥øóUã‹qâ3¿w\ýt `käwÅIyÓYm’R˜g½TLƒe¡=.œuSû<Œ$‘Ó -c^m•øF¹³ ³ ] yÑ._H^€•šÇ„äŸBmlø.7tGÈȺ2öçÅõïÊáøŽŽí* *‚]T4äk&°FIžû,Ã"ñmpíÿ?jwãvÚŒ=‘A3ݺà3/dåƒiÏÍÜ@’H E$£ Æx©É~ñ‘Þ«/ÎóæÞì5ñNê9m½³ì+Ñ“læ­ÙCôEÃøL¢ØF¬×Ôþ­ëÄÒI-È…Ìÿn»Å µ'Úes/Û­£×±{n£j~–Zå„¥la·çâeS¼ ʰÏÍ#V͌Ҕ¸ùš7™¶RdýSºjÎ7˜H¦‘¾U4ϓʾ„ºU^¬a‰çAÆ–ª‘¾[€Œ²*ª“!¦ÚÖv1½Ú‘áýç†nb0³¾©ë< M÷¦¡(´7È[‚kYj,„=™üýD±¼ùdޝ^†ê_^œº5™ch¡ù_Ä»F<O?~›`SäɤÑÝB@‡¢î§ø’)]à(Ðp%¦ç\»ñ1`¯]w&­‘=f¹6i ò¯||Rg¹ÑÉ7Ï+R¡ÎHC"×5ËO˰£º #»™ö'Ñî ‹j±Œ¤SyÇò̩¨›¯Ýw¥ŸV‰Åö³Ž5½üY‡Ùa« à^·®ÆªL†€‹Â9 LÀé2òO¨¸Š]Å–Pœ©B™¸í¢>¨ðò–.oBZ\^Úßøp”ö¨º¦›ó~DòþçÆKŸÛ‹_ÝJV‹=ª`Ïv¤4™ d ¬{=•ë EõƒÁ@’x1‰ ÃÜ~XuëM£Â =°RÝÓ•0E$¨n2Ö/6¸b"$}‰5œ9Ù÷´y¼ ˆ±~ç1 Ûýò4Øë—«óýµŽ8gŸ›§áÀVÜúG ŸÒ”{ÑÅ™“Ò"JHèPᢚ)E¦ë™!Þ#¤Œ˜šB•r‚æ[7Å)iuZ# k';yæÙA<†Ÿ8±ö®  ÊùSÈó×#úljP“±Ô—Ê#,(T Q[¢ôÖ IOË!±*Šwxµ¾"õW—ɼH¢1ÒG7\žXÛĸ«½jë2z2]þzsc"PŒÜÁ±¾Î_8O»YsT„ÓÑtOg›ïøUQRüù²Š‚Þ8Œ` éŸ5e÷d°–Ñ„L¦œXËQlˈC³bn¶cN[»[o³0ê1'ÌwäÚ¢qjŸÛ4StNcQS5ÚJ\ò©L˜ÝßlÀù’Má)Z?îÙ¤ðFÀÛƒ>ž_³Æ—ßiÑæŒâHl¿[gA®‘t~ðýŸ¼FŒ{»8@¹é4g$(·Çlf*‘ËÍS¿K29§úッ IfÖ6¥Ž#`7S–VCsÿ—\t°)æz¨~î¼Eb ¾o‘v'¹‚ßÑf‡ù8zB܃ðÃpÅ$/‚„FýöoÈN«/1°|8 JtÈ6B" èãˆÒúþ5qv††¯0žñˆ…}$0ç_ Fà⣄¹'‚*pÐèHv¯pÜÆA–.à¯lŒZqÖ¤T¡2YP_ÛN²Z”º·">vÑ’€€®í»«ØŠ”ê üŽ#³ƒQ¯Ñ:¿¸_jŸ=¢ù×ç±(Ï:†Ýö×Mz]™ÙÍÌ .ÙwÝVh+– bj\¼ÐŒø— © |Æšåg@Ëu¤Àš…)£»ÑñzŸ©‚0w¬‡À]ìÀ„ôÄèÝ)uìë‰M1ÛÆ£gn4ާþ¼?5d)܆Âüvùîí¨žiÎæ8ZïóÌ@, U„‘öŸàë–Q‡û ¾¡<}óEË;ÕXHÎ ·²ÛÔ$•ãYöî5:öhsÙŽQk x¯t …(%;ý®b›¿ nü É­wV.Äe¿e-UB(äëÞÅïÉþ{WGD¿ þÍ¡ ´ªYJÅ%ïâìAÓŠ+xEAY·5XR’‡:ÜY9)ÇÉ}pB«…úÓ¨#×ÈŠŒŒvšÒY>n÷#Òú” JªxÁ™‚þ½Òr÷ô†æ²gl؈ujò- ‡]°·=7ZU‰¨–ÄÁ·5õ,ˆÕ¢,N?p×oÉCZƒ»ÎµÉô¯«¬5ïcλ­†ÖIXª­CÏ7¦­m™Ep¿×¡E‘¨LA7æYöŸïô2#OÜ´ì¦Ãð }tƒ´Í”ˆ<ˆ‹…àœÐVäŒSÃñ£äHY¾2ÔZ04އ®":ÀÙÑÒ(šT#^d9+·‡ßÐS%k…Rûç¯qÚ´ e„jÄŒÁt"ðo…jEךhªÂÞéó© ®É^Vb,9ç&|×bãEÀ£/Äl‘=µùbЉÁ+^¤8–g%RéwzÅ·x0~¯xíæKâ}¼S¢à³*²ëøS–ÙXæŠ@xU„žaA Èÿ«^£Ì°[qj̓,)3“é̉]¥jy3©óph®5²„EÖ––ü>µÇíZq $U¦Ó Òä@î¸7k'fÛ@‡Þ˾õ…5-„Ä1µÏ˜jˆ}A%MZ™¿Ã«yNœIµ÷ŠS8d\YÒP2”­õ§Ñ”´ïÅW(œÁxÎøè%@®økdÝò£w3u Ú¡ƒ¯Ä;´Tη,i˜m•oXôíDÄ6Sº•lÒÂaÀt¨ª¨ÚWéi¨”l!-Í-Jr!‰6·Å2ªÜâŽOô2’æã·1õ¼1ºÔpxƒ Õï*A ^éÐÖ0.tîíÑ\N6zÒ““úôn.è—†yè0c(‡³ú’€€ ôz¼iƒpåþ_Ä™-€ßb½§R—Ê€ŠË“޶'ĺêkÈ`•âãl¯¶‰ oåÓ”B]­Å4®à»7@•å1Ë÷}˜ó΂žc íÊV×ñãóJsHþ_PN>‚•}SCÓké(*Œ}Ä ¥,݆ÇUÀrÚ>‡-™7É9ñ/šO,Çië—”`<ÊÜÎGÄÝP(üñÄ·ì¢!N€”ϱ¦ œRy•>ˆr5 `üK×Mv€ÕÎÈ€è­V±.hoìþSà+ót¸8 Æ8Z•Aæ,‰»†¶îã3f w$.Zs|TÕ³­S_„º"ˆ!¨.œì™ãë!ÏÛÂó&«xfÇ'[¥¶)ÀôOœ>R Þp ‰¦+TúÄÐîkn-[`Ü7 $?5 ¯ ±4qÁ†"ÙÿÄ%!¶ÃNÞ0_¿t–N9oF‹^âºK÷öÒÓ9å0WÕªÙnÍέÛbã?³ÕNŒ¦»$ùÁ5WÒc[½”L!àâ#,9’àL| ‡©Ê)â3U]³×ÖõWÉ]Á™ºûÞÅ3çqt¾xZ°CMèºï ƒjÞ‹‡™Ò¦Oå«–¬Ýç®–êÞøXW7 Gp!˧Ÿj†æ4s^B±5g¾b‚ÓëÖá%¹«ûøh óWë¹Ô±­ÝŒÊyBD?óš¶‚òUËeºÏQ䋤A“üé–njwwq¹|Îfã.ç<êOŽy¦kWiÆŒk¥ˆÿu„]ô€—x)S /¨ñ ü3\äw‚f*gÉ8MÂ{¦X1bg’pNM‡Ëd ÄåÛôo§²ö + €çýÒÛ¾/Ñ&zZÓÕØŒ©#gKWUX̶â°?“R›ÜŒn=ÀÒ[Ó%iËõµYºâ6êV˜YÃ"fA›d…“‰Ó6[†¯*é[ïŽæ¯;”:i¾õâÿRÛ16üȽ³ÌÕ©á"è%”ÙÔ{NYŒ±>äsþÊm].Î äü‘ƒ”{ÜÇà߇«{\>Ò`¿W£W0ƒW5^®«al"W)ú’Î‹Ë ¢ƒ8ºÕ¹Ï5BE³ÙÐØ^™ÌÐM9iÎÖ“ú0ó™í­b”XÛPy¢ìÊ’€€ÈCªšÚd‡ˆ¹¥²Cª¸®“dØ 5ÜûˆEªª¯éCÓ] *T½}9"5ر·ýÏþ¯Îd¸ÛßÇ}m„­è út§8ÊŒ¥jzçã`@,d}$&ÿP^݃5/²SšâLù9‰ï ;køp?òœêškü.ªØZÚV¨ãÀ\Ãè>R«¦„¸L•àøÿºÌ2Œ ÜÆoF¿o¦özºkYêV0zÔž¼4œÉ}Àà9ƒdoC]´† È˶2²ŠºIZíÍøJ% ²ã0å½ZÈ ±Dܱ KçÇ öN=G€0ˆ{–õkïU¨h-‘Š‚d²š òs……-s³Ë¢ûW’‘† à1ea¸œŒTù†yìXRGN‹§‘âŒ}\¼“÷út`öïtÃè,’ø¹Tƒ'{˜Jra žà9bù©ÌÏMZ.刃›žA=OÒFlqÚbz`¡é›Ð¼"ØÃ'Êk"àšQP=óiï7ËÍ“öR‘lü,õZˆ® Ù7¥¡ðìM;Cp(Ð:”VêF)¤œ;.ù›¡?„Ÿ"ÑæFƒ;NŽÞfMYû¿!È-ηŒ#’˜‹_¿©e¿ LùÿT=A÷xé3¸¾ƒspMæðƒZâ/¶ð>ôu,ÿÒÚ*¢.9g2Þ1ãñÌdžéåù>åßP‚F¡÷ºÇµ=`ã4»˜p)ÀÔÉ/•oÉyvr¼I°`Ž%ôÙžk7‰ÛQÞ=Í;sá +lÈå}òª~ÑÙ±˜òᣦ¡´ç®¬¨QÓ† Ýmvr  ?>ú{ò"`_œàTKR¹·ŒÒÒyà¦ýxwÕÚò€{6Å-¤Ùô?ÿtºè± Ü+Ø;ËÇK´»psêî£+Ô×éå€X€Au’!.ƒÆ¾þ .¸Î™(PPò)BˆìP*Ø•Š×³ýƒyÚ‹š#A¢<Çü0ž¸V~Ò2¯Ý¯"|rI.2õ.ÒR‘Îõ(mÉš`WO¨9Cùƒ½ƒ˜’ü³ÑÁ†'E$ÅkN÷ «ö•fâ;0ÂŒ:$ná$Û‚æó¾±WÑ~‡°ìâiœ „ é8&úß$q&-àúÞ­gý@göð‚e‹‹j,êÐ.—™ÚU=9ºlÁ $ (¬"·v,ÜM’€€Íˆ >â_ˆNJ® b^;1·Ñ0!{p¦½Ú8 ’{”8_ˆ¡‹" =ÍŒ‹þl!že2š—ÀÌñ[EF¹ÂMâ‰ÀÖ£y¥ØdiÜ,½™­hÃ'¦¹ï|d~ž©Ž !ÚøÌMùFìnêw ¾êåÔfÎK’—nZC¿eôÁYMJ™ÿƒÍÌšãÓ¿22ã6h0O¥ÙLFÁ«N09G>pýßèn­@?8'mõ¯%@ôp91kCý È/&óñrS—åwåŒ!›CDfäz;c…½³ Ëûtm¸è'¤"@ÝI4?1žjL+ÑKÌš— ©Á|ß@d ³Ú‹|MïÐ!nh«>¤¸ãäÐ&InÒ§§vHö%5øŠkÓwƒ6aÞæ'Ÿ·…;µFâÉÿY”âJkm”¹8õE“9Åoäùd þÕåt:èæÿ‘›ü×ã[¼ÿõY`ðßȨ⥸#YBøÿeôÇOK63ÕšñÄñ^oA¨v„(æ ©ÉÓíÄø”QYy ß¶ÞÔ˜~Œ~t<5D7œNC·‡•\²ø]ggžQnÅï€ÏãB@û ÅPY “…r9í£ÝÜ3uXÂìPF*®£ñGx}|ØQ#¼èͬ˜ë,ÑBˆuiþ´åþ0wþŸêÿ˜a2ç•|›ÕtKïéþ<Ü;#”ëÒ£Íj¸<Ëþ¿Buu(WßÂÑzjÀa”™VÖÝðlÕÍHê²™®¸SµX¶Ô¨¸(’$ˆRf^äèi!§F¥fHóÅÚ¾IÍ[Êöú!€X¿\õoHÆ?È‹µ²hʸyÏÍÛ©‰ ï"â8tìþK!­àÒáqÝCV 9÷E7€Tæ‹òž(f`™÷ä ýÈÆæ¤D²c?Z­È /D°ÑöA¢^iœu/´eøÒo;‡%ß6Öýš`Ư±K—¿W‹.!å#ËŽ\"/–^­¢½ÆQ‰ÛÞ“ÊÓ×@t0Ë\Mž¦†Ô5äš"µÑ{—¸EÿÕá¡þœ4HÛ$^(©\ ¦”Nos‹ ¾Ý¬ âATNûËQ=à? ¾R—N*ŠBt²ç”Tw8`6Ø­ìùmÆÊ¨‡Ï4,¹†jsÆ…Å5ÉJŒ‚µ3g 00o€‘ê èr·Þ*Ré#ttÁ(¼³ŽLŒdïÛ Ü kx  hcÍ%!º†ˆ:¢°ùïv(øƒÞ먔Êqz3)‡3Žœ%‹r×$Há}ó]ê{þÕ¹!äÑNË+~þ­iŸVx•„4ü¦Åœ)Ä i*ÆÎÖ—Ø”‰ ¡[žº†ml½+Cm.ïçfÿÓṲ̈g£>ÐéwàS%Mzâß?Ý!Áï<Ó]ŽîâDñÁíòËÆD˜ÕÚí|‚ퟳÌÀè*¸ïMÖFðC7èé§a ŽV÷aJ ‹±¬Ê€e‰ÙÊ{3 >×Ãt ù]° ¡’ëÃÏà÷ίgèÛ{U%HÞ¦D?‘¼*lÀùÓg›‹H˜©iŽr Ÿúj\RâˆEɇ˜RÇÅsíhõBAíBðÿa;Ž –œ©cµ­ûªªonÂÆj#Ò"„|1Õ}{–â -lm¢[&»PÖ¶ F5Ý=YÚÖ­JÖÏXß&ñY&9 !ŒX8N\ß#TÚr)˜zU,ØÃÁŒF¯ÙíAýõ„Wæ=1ó}5YYà6[¿+ã}ÀO¿rC#¯Ç9ݸ×lrzù3ëáí(C6$]$a 4)/»B¥‰ÅDƒXqÝ\B–´I!´šôšé*Â#8÷ñ›( Þÿ¯Øã0 "/PÕšŒðÛF€nQS cŠöOÌB{"æj¶´•5q‡ÀÕ’ªj¢Üp%,~\˜§œt:RjÅ’€€÷©¼€˜XCê^Ì{Gã(àvÂP¨„X1a(¼´yE!×më÷tb½õë˜cXÂì%:ü¼†EÐ0Ù…¤R3¥]*CåÓ«ƒë´ ’(óyöº8 íâ.Ì­DêÄ»™|ŸóünÔ›¬š$ýÌux†!ÈU‰Cv:‚+#ÿ²'-™ŠG郀̓°¯·¤Í™’¾|-wDÓ²yÅ ¨ÆüN¹ˆÉÀ¿Õc¬ízÐÞ¥„äö,༲õU_dz ù¶Wm“•ô{…"±Å'rlq¤««à€—#§‡ÐœÏœ5~÷Õæ…nà‹ïF×´'¥2A}¥*n‘}š¯B¬ ߨÌUÀâB¡1ÌÜÈat¢#q•Ô(+*‚ÿÒ¯îæu%¨°Cª\qCá"k¹ùéÁu†/ÎûyÃâjãÝîB5‚5\Ý›²|ø6(áÎj^žbÖGÇ÷Àí;ÿ¨>˜ (Güâ¿ ×ç><;£ýÃo†ËsO}²ˆÒ< ’mÛjÖçbÿµû• Ö µ=khgÙdä±ÁV…Í›¯"å´ò»Ì×-¯ˆ~UhŒ—´V¾R#' C,` ¥”¶,Ëî…‘¸ße5áé—ƒcRdcWkŽœ‘á §¥Q7(<ß\x}ý]:Õ!º‰Ðòõ ‡D¾ 5Šd=èp{ªþ®ÒWús`g¹ÀÆþ—µ@â^+ïzoÉÊH£s³Ž—'j=Á¨qšà*6ƒÀ::o‘wV}›B0¸·—úHsÒ´M„„ÿs/ùë ’€€È\ð1uMÌm-x=Ã}dkõJ–<©îL9ˆtª6Mòå4êQÞ´••²œÓS« &ÁZOÊx¡” -í§8𡱫zé=¥æ†AË(X´±¬rd}í|;ÝÒ¼¸×hs¢’µy:Qín×ô&Þˆ]óvÌ´wÞn‚!CJͪÒanønû­6ÿ8M1ç™w°ƒ,¾®‡6Š Î°¥ËBÏ+TÁ¾’ bÏåZÆ'IÀ˜s|ë:=¿Õ6p¥¹‚b/³sÌÂ0Á±äVÌ\Ý8•êVÄdÂiTY9KÌ[ÙÀ‡ÕˆËè'cHFëî äI¶M«ÒŸUV›±öÒ#‘%ÔUïy['4¼<ã¯O^¤Ww\Ë¢ÿ–yÜb Lv'Ƚ½ùÏÑ rèׄڮx¤‚3=%ºúGÝTWé–¦_ž«ŽÂì‚4̤ÝàDñ½tíˆ+—×}€E³â©™s1ˆãÂÓnê¦O¨w'Œ)U”šã²6Çœ ûX½~%6÷‡'©/R˜VO%ªÔ–u<{u’úNb0ï°¦í.TÕbTÒ(Há¹ô(-X$VùìÖ¡˜®òdHg?ìvs&ž! aâ¢ÆÛEÉ#²PíM\ìÐ ¯ ×y>nã(…æ%' {БÝ2ÞC$ÆÁ·ÙF& „L×Hu3 úqo!QøÿiüÅÀL²rxš é2éQ¥¶œ)TP9Hó²T&OÞ“ùl $ÎfìûÔ\UŒñè [6µ+ϼÇåy_¹ ÂÝtuÎ*]¨¼Dm+¹C©+$¯„¤#hõ¬ÚyöCÒ¢0[ýÂaXÎ7Mn×K·å=âb±dCÍÿd¨MBÆ€P‘ÏyF¾!{K7¯.CQêqbÔA ºî”5°¢nð¯]h3¨ÑÊ‚8Â*E¢T ïÁLLbZçD£Ý¤Hlô‚ ª°(^AySeESžŠØ±JƒŠSÇ ­ËͶ ½`á)íä"DÂY¨|xš8ßøå›O‘™;þL˜#Né„’€€¨¢Ë#Ç?‡ÆÁ!1Ds[Ó» ²ûPòN–jYôßv俲µ¬€Ú­ z9‚š•#°[JŒVø8hš‘ßj®!Ñ÷kõ¨»¤‰ë»šµ„%•¼)ð9(àHDÃ`z³k *žÉØbÏPwYÿAžÕZ._¸\ù[ÓÒWÔµ ?ÍYô; ¨†½^…»ldN5—Uêœê΂‘2ÀTÕ3ßõ»8j’žºÏ«ÿÛ±¯B?U­ØÙ}«U¹9y"À×á}Îõ%›Þõ³_ÍÇ¿±S0qÕZ÷vÉÎ27[‰Í %¶X¤EDGhHèª^–'g½ÇAÒÌ´üaÄ™eõ™!ÿ4*c±êuÄåS¦(¤µNñ¤.wް¶ÿlžÆ¥d#Û‚gV êñ¼åk*?g-ÔAC8Çl"¾â+֩ŠK›èa„À×ü¸ €»ÂGd›S²gXØÍ£¢ !TÅñËÜ_ï¾ó»¥¹ß1Ao%;—©×*–I&ÝjgÞ¯óÜiÑ9•ËÖ"^ÒOæ¢N z‚tlïÕA£TÙ%oš»Z ï”Nƒ—v»åœè¬,žÃî”<•[£¥•üXw^8¤Í@c x†v³QéÃËVñiæ8šÙOo_Qqzò}‰Ó}–k<ÉÿI®¶½‘8þÝ|möæ"P‹‡£B£¢ƒFáwÁÜïþ˜WÓ/H•ŒnD:¡Î>_”°X‰ø’I™È4òösšïåB„š ‘&áí ýë›k!QÃ@(Ûµ?nˆ“îù›n-¶ ¦7}}o~îá^ðÝ/Ù­}ŠJ$¤Ú®Ø nd”daˆ‡gw%’¿ë°ípüöÈIü"÷Ê¿ÃeòÆŸØ· Ý7ðj ú•«¨¥ÿÞQ«MöîÈ ÈŸ}ZKx Ü˱6óÁÿué|:ý‚ „EƒÌ?Zn^“nô‡½þÕKS"5óYG;ál–òpMMÂm¥;¤ xè2±$&§ý2a¿¿ßh a'=s—®} o:r¡hÿ—”ð¸Á‹d$#¸-I4L¡sGBˆxî‘WE8t ·ÖŸÆS÷\¶DñQ±y ›ë@v ÷Pm"«½fP·*rߣU~Ÿ(= ê}ëãX:Itµ ,rxljnº^röJžžÐ?2AhX¹…uÊ%ç(v®j6YÖ®Z&}¢šÄd€¦ v’€€¶ðÙÓO "Ó èú‚8,¦þH1YºîÀœî Î|óèÈ"]4à™Õ @'¯¢DŒcöÜÜfSŠC¢ pC)VåôïNm¿ò­gúÿQ+¼‰,,Å wŸÚòñó<þ‘m„µÀ/!†®ó [”·™Ä‰P‰˜õ™ï|®ZgéòxçÎ^¢õÜdÏ8¡ñ÷9ä´õ Ù„Íëâ…4^^R?ØêËÖ–Êa)èBþÅßöåþsVðéo“»Öìª6½\ܪš8V2Z¢zMúUáÝ@F`t¬Ã‡Jhñä ·Uã±²|Äßú–Uäö{9¹:yìË*³í‡¢àLJÌ`É'µ€f wIË7“(¨‹•¡R´³RisPÆ܃3°) êÆjw¸ç²àÍ`K¹(ŸŒì¼ä^÷—Þxb7©Öô(ó¤7ið(Ò/ãÐçYÎ)òIoÀ´NïV‰ö0‚kEçòËÓH|y[MðÛð¨ÞY·~Âz«Ò@òŒV›ÆdPóú;É™&‰À”|µ‚H?­“¶Áƒo™qƒWÀ›ó0¨Dü&åÂÓ×qöàÔ{.—YÔ×\E"Úey’èpÛ“\‡^ÖkS‚³Ö~\°ZTä êê0IÞy÷õ S߆ÐbúN$µ®ýRçn‚©’´²L;ÏK»L™Ú$£¶¢½7ä õótá¸hy¶y¤¼·‹Gлž>hÇaXÌ<ãçŽÁ3ªÆCƒ7è;ð¼ñ¬Rÿ9í‹§wá0‚ó04² dBY(õ7(ˆš±²£¨˜¿öI™›[À®. _Ô`ܵA U.qœfLs?þœéEÖ°JÇ87&."3¾~ʽXÈU=íЪBvºŽ3 ˆí³/Ã6‰¯ÓäˆQ"øŸ˜PM¸(¶¯Ÿío߯Qœ®*—®;:ÌÜ zúmìݼzƒbvTÎUÕôØXnÔ—8µ`×Óh ü# =1ßÛØàÕR&ÆÀ3êK@çWµ›eÝÖc<ê]<%_gIŠÁ:¤ûö6œ:XÇŽ’®DB °¶.JóC†«ò¦ñ†.Z2\ì´d&a{ªšäöÎ$³²7µ–K7WìÄ„¬Çбp‰v/ÿý‚šäæ›X‡WeO4.ª  bŒM¥%´ Zçö¼™H*Óý’€€À Ñ©iß·”Gµº7`‚¥ø¶Š4¸N ÅE‰’ïùÜ“-¬ Œ%£¤Ð–qäûþòûš®_Á2âíÃ’ë^²8ƒ TÿõAAQÿT²Y;²ù¡N_Ä’Ì5È}U6â h1J*Ž…L‹iUw+ 7ò…¹B tò=v`“aoüJ«Ñ´MËÏÄFGè;Œ»©J"Ή&g˜Æ ñL¾º@Å"²¸3 Ù©+±It* DLAz&pN SÇöó„þöY†¾SCüô‹äØãìï¤c‘n?;pV‘èíõØ Þ‡p·š²èƒl%V’«p}y»ôµcÕðÍ\A¿GòQ…!2þá¦0†J¥5º?’úë¦ø~Q#‚j^‰ºUÔÔô¸îùç·“hÑÈ–×!MûbʆTúÑ•¸FÌÎÎ=³“¿ë6+H”(Ñ˽ÒÌnVûªŽÞVº:]Jô€ç&2 §einuvC†s…%ÀÛY+ób Ë\Ë|0jhOeù±‡ %Øõ]·#ŸkÃtÖàíÅ@, ®©B~y±Å EnÄ+Q‡¨ž'"ÜÀžñ÷3Öĵ“Çò³¨fŽ}è7Zg„¢ýî9ðëae5´ÓÊ?ñ9¤öK-jß”¯]:îNÓÿ\áùÔîc{Ø. ¥éweV» :òÃsáo§Tõ5[ß—A™Ý{¬\<è«çùá¿ ì“(ÕhP%b—^”:O?‰RO«\Ø ôÁhó*9ĵŒ8ÆM7 ·Í# šp ÈËWñ =áP®Åè_†{q}Ę˜+UùÄÈ T,ô6k ¢EeÂ]Œ 6gë˼ŒŽ ×cÁÎÅãP ›¥³¸ü¾ÓB”2R5}uÒO»0Gºri‹Pneº0<¥×^F}Ôo²l%&Ejé@gªìµž!°aw¸0 ü¾ ¸âzÚFþ>Ä CdâÓÈŸÊsÕâFÿóÚªïÊ2Zµh‡%Ôð‡ûôi¦–}¿‘ïÔ£y%ü•íð£{C§…éÇÊûñßKÓÐ/ßëhžØÒ!.´EK® Ä_×…÷¡óg/Zƒàü/ñ¾WÖ¦þsïe´Ë>'Án~bˆÚeôÔ ñ37’&©QK‹Ñ’€€¼&–"‰ŽûC¹üÃqeaQ ¹YWâ’ë?’iÖzªK{®.PËúHý¬qçR+õUCoÅcM5°ƒ0¥ÚMBÆuæ¬ “ Vá’aãиV˜µ¾˜aV©†O”èñkíà*¦³ŠEøÔVôš4åDJd+Û¯¼g1õŠúòj‡*ó;ÙD)Ÿ‡FÁO‹vßÅÖ`¦òŒþ©q罨íÉŸ°*È]G¶Ó¦i&^íÈò{^»U´²£:Jí9!@vŽ|N3×­ Cûbǽô­®9¥BÏ2ŒŒÊ6ªæçØf¬£–û¹Ò÷P€9†~#™è¦TfšªR>’ Š‹ÇêLÚÙU$âigƒ&Þ8˜0í;~GQ­Í“o¨˜Y¸… ½ÈHtDS +·„z&ç9ÍŠNø—U¯Ü^!Ò¸ÀÒxU»ü©&Bbr$SÕ‡{;õ ú:Uqêøp;O aYT¬Ö³¼;û i¶vÄpó eíÊu•eUUï.ÂËl} ‚R Ü^dH anSòò'†Œ’Ô±9„]Œ×S"Qò£GšË›9Ðfá`¶‰ü⮪€W‘fÒ²üX"kºÍ]+8R-AêÝW夬DI#›ü£ÀÑûÚŒ’€€ß™÷ª¿$à y2àÏL±í "kãZ)cPçƒáBãž–mU‘üŒ€4~«Ì! ¼‚‹¤sV_‚"ž k´Iëê«wÇîŠFú"-Jh †’ü#ý@‘]€Ìç;®púÞrï2ï…·VŒÒñ¼‚€ õeaX° m*Bp óܦ'sPº{98ÿE‚[d[ù(¾œá„‰kÖi9C*ÉŒ‚ÒÆ5úJåèW%ò–ÓàȪü‚˜?°„^bÊ06rù¤Ýçr¡Œ TUÅŸÚ;¶íh¯çSm Ž(oO2TæQ Ý#mxh°+ä»,©6öŒC.}§»`eyÛþq?¹€•­Äºn±®7Þë!ãª6¢•*\uQZÚ:–¾xãË 'm[ñ§dH¥ `ms“<× tY1b,Vvâû+8lg˜2 ]ŒaÁîðÔ_„itäF›Oà ÓÄcOD :$,»Jð"ÕêÃŒù~¡Ð᪂œù>Lz¸EÍé¼™)o'LϨ»ýóËß &PÀ“g(Ñ#?ªÖY’¿BMUåŸÓ6©“™è òN”# ðAîö# žœÿ÷×ÈÜa6èCšø’…¢ ŒÕ˜ï°‹x¨Ê®r(ŒœOaíÅ9‰ö RæzÏÁÇúRýY¿56]ŒIÉ#e‰°yF Aƒ˜Áã¶eî:¬‘‡õs“A5ŸÄµð9Þ1˜ío—{–,>…ð©{eÏθõ~ÜŸÿ-.e%î¤@õÖÅ+ˆ¤¦i}Ul;AZÁT»ö´=‚ÊŠ*"Ðè¡q Dºo•—J„06@M%sä«B S”­Æ7æ“ph³6mÀíêþÏâ‡k¬šu»Ïçê?-U£¡eç†R´6Eo“ã‚¶Õ“_kW"rBÅOY,w6¹ù17¾ ‹MšMO.Ÿ8 ~óž|‚“ ƒ^FDà™ŸŽÎžµš1Œ;Ó§\?bu•=áù§XùŸQ¤»h¨ÓÃ$pf8o(oú¼6 úížD›gp ¸öÕvšág¢ö6cK»|µo¿ï»;‹~j<·bÒ‘‰‚ïŽjj îÏz0Ùt|ÄÙ£”4“‚\IÙ|¸'¯ ßуÑ×G ”ã¢fZžÓUóöC’€€¶ïÀ‹]qYâ)‹¼Ÿáw_ˆ¿!AòF:ä·/t½àß6qíPNqP>ýâ3Ùdžnòê0 A­=š¢qf< 0 &*lP,!³SAm—vNù0ñÈ Œïzë(‚& ´A½}F<Ä*”´Œe ð(ƒÇa²£G‘ª|þa „C©X¤±ù*”ôý¯ PUˆÖ Ã[°XÔ[D K¯'»‰•Nó÷;`µOM!·q ÆsRÛF>÷\Q d!w¸MNR8f&kÅÝ ÷¸ER©Þµ’ÕÙ$mèRÏwË’¹3UHìû¦„Vwx €lº‹>H©¥üsÊn^Ô_„Ó%íŠÂdØ{b§§YÇm* ­¹-/ÿð–báíÍ AõQ~ú^(é‰b¤g%Ì餈AD}óÄû£ñŽvãK©3Áƒl‘š Üm¾!Ç?<Â&Qò_ca¢’úزF˜S8Ë8 Íûª:TzRéËæ†er¿ýi3¦XoylX—ö†>Ý 2œÉ‘\c'jøÙœk{^T!&ê¨ýÜ–sXQµ”ÓÆª£¶ŒÎÀ¢xÆä1¾jÿû’jS% ¨L×ÏK¸¢0ðœœÝqª×2=¬'lƒŒc¡ŠúXìÅgt¹}JV†¾py€cûœ¤4EÙÏR¿Ì/wG”q®*'‘¶tµŠ^–…n‰šSŸt#›Ç}VÒo§†Îœ¾fÙomà$ïÄìP ¢ ˆŸVãT¤èÕk9éüpi7ZË•CdB‘õµ[um®ÜtëùCtÌÅš¯ÖRԣ榦 TÓyn]$½JÊF9/×Sâ6vq?βðñr¶ŒÄ°ß `ÁT£¥CT Öh €ËµºIÿ$YE§G¡ú|~èBöØF¥úºÁd``Ä‹,ÉwböþW¼!í¤ÕÛÛ¶´ ºÆ½–l(@9OÈ»èo Sßöé6‹°isË©lÖ”Þçº+ñ‡Ïeª•BP!&fxègúsa#.£€‰±#¶iaùÎ=ÓK öüI!_ãeb2Krž­*LS¬¨§ÊÒ4–ü›†ŽzƵE‘Hko ‘9Üá>O?¯- 55[Ø`XZuŒõ4‡Ÿ—=½eO¼díõ]E~×­ad@šÍÂßÂu[Åm–’€€åæÈÀ"ñ̲¬Ç´ãX(©â‘%¬ bp§“JÍ©%•@Y X ª4v­8¸@G?Žm³ã*ãr4%0Á0ªåx•€`ŠRtzYÓ™2n¤4±pežF*U¤GZ6m¿s14²«þ?3o'7:*c.zX—••kÕ aU‰aVãjM°TSàH[”G,¯R¼ÿ÷9´_†=Í^ë6ÕŠÒ·~<€Hö þªB ‚G·k,êï Â6¤K‡ç~?4Reò méÎÝQ¬çª‘zbb·³þçÖ’Ä=ÿMëÒIÃ!–3·¡ž—h ÌR¿ŒúäY@Ðç?ƒ~Pø¸WnË”–vüJÓ>4‚5 pZFx‘XPˆ)\M`ÓžU”vDÔþÃÜ£—šI¶ñ>ÕÉî‡È¼×§ƒs1@6daúãj„eJKÝú¢“˜–O&—)fc—¼\áÕÏÍ‘,†óp,§9 ·¾jyuÅ¢„÷_çÌ2†³Ë'7"•ª1¡IàÀv*ö¨‘i&¿D„ΖOªÞëe¾‰d—ˆåNžy~Ž]h°‘´^OHë‰}e »×xî€KÂÖÿÑ ¬‹ NÙþjž>\üM¢ˆz`÷ô£4žkEoIn¾þòƒgnVÇÈ/\éoÊx4è³kñôëˆ×LÃN0Q3ôH5Ö¬£P9[rw×x‡åý¶yôÞŽbw½§úU0aÃÄU…a}úáÎ+¹UîL©MCK¿Ú]î.6áµB^‰ÏèÒV7X¸Zè(!ó­T:ÓˆÒüê&àèÜ ¾®Ò€w$ÅS^UÕ¬Äc’ƒú²ÅAÙŸðMPݽ…7í36y!;­ß4+–ÎÓ€JC¯ûÛ6 !ï´¦ªøf7MüR螯t57Xdõ?4wœß…+n¶ ‚º[q©(€8fÀŠ®Q\Ñ3Sp„kb¿”~ÆÑûË+kiÆmõâ !ÐvB…þ&Ã,^þ´²Ôšë;RS¹ç¤îI†v4Aî]…ŽŽY‰¹u TIøY:EéÌœ Æ“§z˜9öñZ^öÑ[‡Qâ ”1X€îu†(’ˆv˜Ù²T@(`PbÀ4ñ#R}4±„CÖAî××þS,e-%דb{oñeŸäœKòžŽXò¾6R®d4’€€ÕÎU 6Pèù¾iØ}ÞÓ±§KÛÈÀ|ŒRKódšä1í—Z7œùtîånÂUj~þè…ú›\[· Xb”dÂ4L,a3qkÐ:}Ÿ—QšgAŒ8²I\È5°ÇØ1¤oä7ZÎÝAOСa(‹g^ 28$‚ÔêºÕTÐsÓ?}öÐT¯°2R•ûΙْ½±-Õ˜‹ò®GŸ÷­ª¹O&' tP¦£Èc›(K›Ô´ƒZVì>=ÑCÔ‚¹ß‚é‚”47Ì®+ÌÔD‹ÜÙiÏ[‡´–_E÷ôQÖ´žÝ zÍËtÒäžÃK`^¼$Ì1#]I’þ_ÖàrЙÕm0·¸Ī¥¬ƒ‡¡ñq}_-Zdé³îEnìtƒñÀÀ%AÊän}Uî¹é33ÑÃæ| ѵà|Îý;m£»BK²áxË~±ps“R££™r ܉”'×ÃÙÁÌDxgGÓ‡r¤€Ç˜Oà ÊŠª;„?Az3-‰ÄÜpaÇ<´.Rd‹zÀXYŒEU"Ÿ„jÇ1PZòÏ­g·›DûÆ´¡WDUÜ΀CHæ•´þÇ|ªsøâ·9¼߯ÝÌp„–çdªá2~ êH±Ó+“ü‘-4z™„eÜñég+}èíÞ¸¶ X-€ øŒ¤/à]÷Q$®Œât—+^ŸA˜Ž£ Ÿ\ê¿h¹7û–‚>×Ó2…ʽÝ$2tÚ©RÇðBÊ$[£NÎ ”Ãé G[Îo!„ )8åxxnh„lmN;yeò¹@z„š(þ¨öÃ0[–&™lÜYz(©›…PTH½2üÌ~ý"5T™"¬å†äípýóí æ$ÞG‡¹\[¾Ï\·Ö¯œÏ¥Sé2yy=“µ ·/`á¹(yãCpð‹fø³co»þ4# ÕRµØÔœ‰ µ%_}t¤l¯°”Læ¾Stà>ß[xG`aêTêfá ÀE[EÞ´‚rž¶F vš«oÞýK‚W®¼n!yèµ÷½"øräúe—«‰Þ_‚XµåW¬‹üô?W2tùþg¢‹kŒÏC:z\oV4£ºßð<š>„´LÁŒÀ «]0Ø·Ä×è¤ æ€j‡Ëpé ÃÈVlêMËÄßܯ´À.8|©ã%·U‹ÉвA%J$¯2Í|ÆÍähã[÷)É^âv­Y~¹0aˆïãv‘~ê¬X?—ÂXÌÞYW‰Z„Ù²t´D*šß6*ìsói7²€£O¾<’°ÙÈNα̻J•©ýIòJÜY“¾ÑVߺ’÷W®:Ñýœã!Æ“ø,Á¨ö$þ4˜¯‡Ë<Ž¿•¤ÌþäPVdŒ»0O >pÛÝ)=ƒRÕç3Ÿ]ÑbÜ‹K¼Y àŒŠørÍy˜¨·T„s¬œV‘AÿÛÏøħ7p¡5q©àL` m\3»ù"þ>Ñ}ââ¨I„új¯¾D._v@)²`wŸZ‰F6<±’€€½phc+W‚cg†`,tr ™  …ñ,q•VM2Aú©?òØ9¼T,Çß•„®É gî žôÀr|×vïtúËã„ù×ÜWîòÀ8^4ú¨Î P܃hÖ«¯OQo–½_õþ§· ‹Ù[»Q(»a@.¿èIüá°glÕ¯¶÷ë>Éà/K5K¿£ð Kñk™òÔñ¿Q6‘Ê”" ´ömQ'°ïÊ›E›’EÔ þ%oр̔:G Ü¾HÄÙUò_=’ êñt 埳L˜×dÂô)@Ž´¡S÷å Y-…çÇ„;Ó}›ÓždB)$ÛÍãýOeë×(,+êNÍì5 m­Ë«%Þ…OÂÃÁQY*©i !)¦ç*àü ßQá'#tw{·-žá¾nÔæ6¨êóÞÛ Wàs|RÝ–Ñæx5¶IÄ‚ÚÇ4‚oŠGl ±¦„Qï§©Dšt-Ê+«\¼ý.µ~«H’a^÷çp”f“ë"¹Ãe>ó_èØš?ÄRnMæÿERȤ´&~…›ÄM„â0¨oX3«š¹zj©‡ %þ»’Õ+à7pš{ÇmµáÈÇkbÑU†! Ø1ÊöÝÌÑøå> ô¡¸ÏsÌuMø­½¦ÏÓÞèäÀÊ…ë±#ánEÛ³qH˜q±ôÀ*“Ú›r‚fMtµ‡ÚL¤'‚1ô`9^š”ÌJE‘ö4|‘ÃÛѰT¿Oìû`â|‰œ¾ÕñÝzk¬‚ø7=ûøA覰8KtXø3ä  ÒoÆ>8ºå²À)ê¶èQ¦¢9üNÁzÕ©5ØêP§s½Fª'œ/iÆ«4·jxÕ¼¶Ä™Æõ€{ZåñKX¨°½ûÏ·.ðPDÛùlZº%®íÁj–]ÓÞF8 m|…Ù¯çHç”÷pBD9c@Åi§WGc¿*IOš½ÅPë—‘ß-4ÇÁÇ`k^Œ¨îÞKöe#-Ù@Ê [‚çà0Yå¥,w‡Ìµ½Pâ~ï¾Òqlåü8±dÝÃK0Ï@»é}aº>fSŠË¬.Í' Ë—ò_©o”¶«è ͧ…S&×cr›9˜iõ*¹‚¢ìw¿¡¯ÕÛ\›Â’€€áÌ‹õ7:+à@62• “È ^e‹c¡.V?`;ÞV×Åv?™âEuÁý¼õ$.òãaRòãkʧ…fpøC·³p¿[Ͳ€Î˜¿ÂÿDíOزç 4û8T^D¢ÖžÃã ë!G´EqRZcPñ¥âऄ f³ì ^— !”qù \¯}Óf¥c=:Éꈧ2i<)\eFèâÍz!Ò‘ôBèœ)ó]Ê}דü“XˆJÖzˆ/â—yY ÓÊ&Öl}¤Š% F€á•=õ/®ºG–Îër–@K®öŠˆ¶}ЮŸzJCƒŸ0.9)‘­‹»oÔŸ_w»S<Ý‹¤ãö‡Ã&;3{º»£{S}#m颟cñø ]fLtnËPœùðhóeõ±#Ýí!>W©´_Z´³øÖmSäg7¶ 'ÜÜT=€­^š… /°óFð/“â´@Û7¼yü®ŸÛJøänNå®’€€Ô0LM¶ï£,ü¥Ã}|+ªÜÈ—ñ_-àu K2ü¨8ŒR”’ÑáÛÒìÇ;,ÖÈ"ÎS¹çU‡® ûüƒ ùºäSe)\³ú7w.«Ðñ¼j²Ü9yÿ Øwøq¶- X5}v‡÷é6P–YCI@ç&°æàëd«ÿW±|· dü-ŸA΄²åƒƒØ»|K³{A…ÜcsM£×Ñ…=ÆKZ4⬌6òÌ#ôÄx$ÆïÕ‚Ù,>DÇp26¯‚m\D¤p°ÞJ]žä¼8v”~ÖÏú­ðŽÚ®9§©¨˜” ^4ûîêKþhŽ€4[”þ·­ptÃd1õtÁ¡”ÝG¶§ˆ\Nà®+×EJ˜ªo ÍOqihæg-»‡=9Â.¢g=çëÎåʼn‹çCˆòò¢LïK:‹6k¯b/q!¾|€éòé§¥ú#©b6µ8Í4ÔåðWêÅ=™! Ðsë/ÓmëZsŒ6+‚ÇiæÝ±ßJ[FHÚ=¾Z]ÌÁùG ñfÉ0,§7¢Lÿ–Å‘†ÈêÔ;K@éÂfŠpñ¿ŒV1c6SRš¼?'ð3ûÖ$js_ñ !ê ©È”JsÄ©-æöÉâw–ª}ííxUXj«6õPZ±‹ÿaï{?î5Š QÓÖKÝK«H+‚ñéL/³¿y\€èNöaÇÍ>á 2…Mñ´ìí±RŽè¬)ëœ 4Ýf/:ÛÕX´z£1`ª°¥* ï’€€×Bâô6¢ž|Å4@KE IŸIßëã%Û;¦3…ÔúЧì7ÅzÇØµÖ5>‡hõ8΄Ótÿ†ñBÛ˜qÝÙøµÑx㉡€ë¿ÒS…™¾»Œ|FhØÍãüI3ÓôÎÕ8bäÿ‰u±±Â½Ì­TlÌu£~°àrô8À_²ÿýý2+x@דP:µä(öþÇR‰À=µt¥ üæíW?$ËÓgÖŠ`¦©¹$þ†öóá³GÒBvѼf~7س(»ýÿ#K %îxâ®y¹bbpháߦ[ªA’ªqôŽÒQÇè~W\Àrù²ëÛœm "÷:ÖêÖd£¸ÈÝ­Õ/®û0”’Ø{äòõO^xô°R[»¹·»IJa"…Òn6àe¥Þž”)§Ÿy¸Ï@éÌêܱÿŘ¿Xñò  £åµž¤½›•ßW4X¶0fΚ°´ñúJŠ«Ò%Íó+z,ûš#á•G¾©8¬x25éGý .wÚÌ>u<ΆU,/^6ñqæPWQ_ æ®é]¦ZÅÕXû\@ñíÔÆÏ§N‹òóiÜâ•öö˜e;†éúâ Kg£\‹„•`]2úîúœÐ~=4æZ¨¿ÇÝ"•°S×~ Md ZBÊ=2Á瀡¸^60±iVî!¹F¸‰Äh ‰ñ îá2žÍ¿i!7Ÿ€šV˘Võôè/ãÔou­§Â4„ßõ*Õ{=¿1Ûðî5)Ò2ubœGÿ†Cw;–¬ÀG *¹½Nê’g 6öìL¢< *êºv° ËœXü³ä樱„‰ …k$—i•ëÇKy¨üãÀŒÕ†vZFÅæ°Z·Ü”–ýŒ?^Qv0æ ×ÏŽ©ÈK) 礬Y°bhwBƒîÔúóg¦HB–‹µÃãü¦_YKÜ·sœgh`ÿšÚ©sþ³¼¹W#BúÓµ H±|%¬= €ã}ö,ý"3-g¼ö0 "Ð2@’w^l\nÏ$tñz g‚8+m¡bPN¥3¨Âþ*ÊÐ=÷B³ç0.ä‘r™7V­¤¼¥@#A8EBEÒ.jFŸe>Â¥ð(­ fÒ´ 4œ Bݹýƒëö¸ Æ”rbªqÕáS¯ú™0WVnI^èvD€ –§¯k¼þÚÐ?ÞnW 03¹\3ôHÕ¥#’€€ÉŽ28Îa¬^ÛŒäÉgŸ°Ay '±&0U`pŽ—ŸXÎ:íFøË *` æC€1Hìý* Kš'9JÇÐÊÎôíØ†ADÿ Cì¿6Ó›8«1ñ ¨CëÚ`‹ëªzQFSØ·ÚôЧ°“wùt/ôÃy3ÑGVvÂFåöì*þZìs‹ÚÀG‹ux;`ß¹Œ–dÈ>òÉDÉÌhMœrf§ô ŽM†ˆËjÉp"ò/Šc!¢z³¡ÑÚ3H!W-3uùQ{GžH⡞pþ³q²É-Cv”]d&÷u¿Kˆ"^h(ty'üp¾är(¼v.Œ¢PkÅùùbÔBbð¢ÎÏãÞŠØôñN$èTÏEöRS“mÔ°õlœ6 Ý¢±úúRßÓû·l„QÞÂŽýL:Õ@#"Jƒ~&ìØ!‡çá%¯|Õ?Ú}Ñ#œT#²eëú’€€®o¹Ðj}ˆ § x1å)ûþÞÃ)½(uhúCÙ½ãAxиМ/Ë¡Ülñ7[Ê}/äêÌ_¿- ¤ï:©Œô‹mÓ=›Þ»Á‰^½\hû´Yñ#®NHt"‡ËåÿÆ£»“ßÛ/|ZB6ÕA6Qsçõù^¿”Ð9f¢£r÷îÝw—·X†•àªñŠqØ^–Ð|¦†RúœŠx3w$î±.# çÓªüñš¯|a3ÆF*šN†y·d‚1íÖúø V>Ÿ¸-!nŽX/Çr>essÕºNЏ[Ì–Xó7~‡Í}ß똇R‡¤Î'ݙնåYÚj‘Sƒöþ†[bc7ý8‰ËÌueáäÏÈ;jŠÜöØWÅ_<²$[Û 3ÝjÔ8CuÕJ<êJ™àè§–[ËùOáŽÐ"d ¨ÈˆÉ€1pe¬DBÇsàQœSÞß‚º§þhOyÖo{ׯ™ÛŒR>ÇË Ä’¤Nk¼Êw„ß¹Íײ°èXsæKžI´«1i‰E>†˜xõ\ îY,Ú|FkiŒ›†²¼3ŽÌ*Òókq|ú˜Š·ìÅWØÓ/¹peEäo€H}ˆž!—DbQŽí4oÊôwI ,±É¦žmEÆPýù¥7z xRþn•7L"9 î™oúÊ ݇Ä,$+:KÕÓù"QSanhüEb5ÊBëœnƒüþíIÆûƒ$nU&BŽÌ‘Ò3]4n~‰}̼86‘òn‡ Ô«®åŠ›šk4‡¹ôûÂ0}T.ÐÅ;UÛ5Dˆî5þߢ–œŠ2x ïÇ|˜ãRMÎçL‰Dk¼P}4>¦W´ÅÑ™ÚóôNÅÜÀ`šl•ãŸÁV.ê˜qµÕÝ¿[:FJfek ‹tSªv$I˜¦Fw®m€€âi·Ã-e¦Œª~b?]°w¿j_ýßÓù³&`â;Ô”YÏ!ñ%àÅÄxwékJ.[A¼Ê¥ËHFþñ½wÛÅ ¶Æ‰* ª8^Ÿc“è³€K{p µ¢GÐ\«÷ü¼œ+‹$‡Ñb9·­/s|•ñ’ø™ôZLŸÇÔ¡Y/MFº±$3÷×E*Šî3aöù‘w±WÕc9~%~â ƒÐWW݇,°ÖÕ˜À½¹p,ª™ À›Ÿ—±‰>lÅïìin·¶6Qƒ'Sí¾f¸›^ééêóÄÒ”\}Üj'Ú*œj¤%h“æ fb>\¢ŠrÚæ¾5r )JT‹#hÜ«B£²BC²¤4º¿ðÄý­3<ïžÆFp…‡Ø”¬Œßî‘Þegý°~àúöni °9½Þ•¼ æ—TëÁ…ÒÉdÎ45¬–ÐTÇ‹ÏÛpŒ“£“àÚ½ýœ{ûÜ˨õ`äY,|²¹½çW:ú Î/ã-e»oýÎð|ºp {ÃdTÆZ“ÉûþZø™òæ 5‰·.ã—"ûÈyöö‚óÏžkp[l¦{iÍñUÌ6 Õ÷žg±Ç£_c¿XÜÉŠ¯Étý÷AãÖeîB[u©Âûhr^u<€™·ZÁ'h„Á&© *8+£ºvË)@é¦hOS;ž ­™8Œ²ÂImb×’ÕAßGìtÆyI!ª õÛ-ÆQM ‘$—v\zÐc}Øw1¤8{ýú¼¾ô6,{OT§«Vzä=dË/þˆ`H\’€€š?y”ã3©"p5øå/n±*¿‘xM9 ^ßÁ *ci|²yZs®.Ù7ùè §K×m Ä5'‘‘CÐ.P¯É ”Ï´,TRÚø†.rpÚú#¤ã‘%û/—>‚ã– üSñâår©[ù ò39æ1äÀîᙩóÅãP¡6\¹ú®˜ý²Èe_³3Ô`¨Éázú¹Ì‘~ÿN˜,†«­†Ù!k#c¶1J§ l3¤ÀÎg‘8)Û¤ˆâ,gw'ÓäÃÖ {ñ[¢¿»ÌêÜêfRb·àë)£v¡Ó2E(¥*ZÐ £ 5+ì-Bû;™Ï¯L9D Ïæº-çÃv+Ìs±Ú’›Ä¯ƒqÊ"H¨ä»¸z®—¤!îXO0Ð!·8Ñ“º»’Öñ×§±6s?,ÃEüžŽ´#Ì?×Sžn†öS4«RþÄKâÔZ‰ GÈkÞ(VëÝž04H/r§ü¦ ¦Åk•@—¿ð[‚Bã„M‰Y©›”WEMÞüý.O[â8+Í¡=KzË‚LϼpSä äŠé“Ðî}):ÛŽ"ÁÍÎK«3ÕÞ„8‘ö•”`ß`ý[¢O–x7MÜÅ–rËÂ&ÙúY⯔"h˜kW0³“j~¨j-f•î'º–G µk'ü}¿œG•ðFþ›è/LKŠQÛš8‘!¾yéqg³&#Ùãçû\/Í!,™¦ÐþLpGfnÅ #f‰º›ø‘´BÒ ÿÄNŠc|ðu¸tv…E28¦æ8–dœÃ¾@%n‰lù¨BîÜM^#\÷*ÊçóÙ¨Á†Ç½:=]ìÁµŒX::È5p5î¥|»-ú‚Ks¿…noƒ KÛZ±aöìI^|Ø…"¦ù4];"DÌPóä{$-^4–Îs“JÞvî@[9¾œÓ9!C™C½G›h(ù–(Í÷n¥ð46Zâ—Ž7 ""«D³#ñÉ~³OÝ‚E‰¶¥!›ÉÂc¦þ|Úèxi½ôô/Áì5¡!²öL}¯Ä"Íc›¡Æ ¯>{£ýÒö‰9ÂÄ¡y5¨*yÆëÕ˜¢0 ´eÕëõÿå_==_ººˆ|U;}¤´åEBµÈ¬ÎÛCnF_ÅÌõU¬B "}ùßÕC×qŪ˜u%…pøŽI4'ƒ_C×7àyÔ4l¾šŠc4•þJôœ³R^Báê¯àÀ+ÿÏð4 O’*éì*œÃ -ÙF³å§€Ed+æ4Dpç¼?{E•âh4-ì€CÈ­”™æ+eÛè”]ºdÆoœr]=ª•Zv`ÈHo-?ÉæÌÛÓOÏ ^Œ<â•| FôxÃé…ð7—7ñEÊðŒX\¼òÓÊ|½Ïd’€€³·8í¹4—pÿ¹èÜ1Ç`)¬csÌ—”úÓöž®Êªë!@ÁXÎØ:G5]# д=o¾xAÑ,ßr»ìø%T¢ÌX 4A ¦ïÄúÌw½&³Œ01Ìm/·ÂRÿtŽþRFvâC¸~þ»Iz°/çAbàz YqWU”¹æBÊægU{á¸ËS‰–yx›ï"úaëVŠ:~J«¿@ë-àpÌö¨dl[ã[bÙ=ò?›á¯ëÿzü Ķa—Vb°Éê ¾?FØè}œluṄÃúÇ­Ïû:±–J[ÑX– …eý3ÉxU5CÁq;µ€¦&ÇŠÄc+s! ¸ë(j#D+0ñŸ :À…çBaÝlØ«AB‚þ$¡%Á¨ÿŒžoØùô“8GÙ*1áRž“qðDR‰¨“ÓBPK p¥@,qx.á•p$\÷Z©9ÁÒ xÞÐÝÄ‹õÚ 6¬rp?K.½ÏB!Ç#gz£+yD]3BPÑ£±°÷5WµQlÑ¡3ï­DɆÙ2*æg|2E+é=·wèªF ŸÆJ}¬y#µµÉ[G{š:vïË žNË.Ùͬ‚üs˜x¶‹£ôª©ŽÆámH–ªˆ’€¬*½²=V‹>&Õbk („’¸ Œè™¢… ëÑž;¾)¡®Lô›úA"ã²B¢BâË[U]üš×Öq&Xd£¹"ý*°TVÆ‘Ð(9`X¿›¾•& UgOã°wÛ22›뚢ë –#dàòÈU«Æù¶ ‚Iê´}Þr\àÛ@L›,”üõcxl‘¯ÁŸûBÁ&yÙgÃì£v™.ÒùŠ>fybÅ⩪ruì}ê¼21.ûÏ)CŠšéå‚öF&jÏàÈÆ„>Ê=ÆÄ¡;ú Ÿwi‰LŽÂ˜xþl ¢Vàù¦;–lQ¹¼ÀRD1eXÇ#tyK“QÊj¼Ä·×|0jý¸ÉÚ=¥AêÀ®Ä¯\—a?Ä_ˆëv¾23ó÷÷\`GaVX´ ˆ‚”ð“Äú¡"ÏpŒnΔŸ™ˆàÞï‡)^FçŒ`s†ÂZ>·}½1ö 5vJ8èö®õæz¥sûzïIÅ¥˜ÝßwaáºDÿ‡AÚ°‘¦G AjGa°=ºkO¦-l决<@ò<’€€Ø©e8&ÝýTæÂ"#q{IKþ&Vø Jãäøm‹ñãÑæ‰/I¸aeúͶŒê$°™·vêÓßp•läº; p{ôýZë Sþ¸V |Æg1NÞý8n m¡»iw{’D5U®£µLp×iײÇÝõÓ÷÷žêƒßÜ îE?HC(ïØáÔnõû"H_ У^ƒd(¸U Ô$UPç©ä†»Añàï}ÒF«Ž¨­¿õ. çé–Ÿ½tMc >;»€øN8ÔÛ¾wssíb|h±{zà ƒfUÄ2•n82ˆ/¯¸‘ÝTs”MãKAS îÞh± =þÇ-C‹1JVÆ»KÉÓqè"À.ðv[<¾üŽÕðâ Ò¸Øöqämfo8m¦(’ÏŽIµÎa; Ž.Æ Ü«ûF£ÄÙJ­õ.¢pAÆæ¶¯‹ÐÞùf¯Ž¶%ýÝ׃ðM[áŠÍF8ÛA•MÆÀáôÕ"Â/>Žàr²¾õôS&¢S)¶\DU—‚MÇ`*ÑÓŠû'ôÜÎ:*åtñÑ©ç輘©Ð“þ}é=Ý“s!YET½ãE»õ]9vÝaµ5ŠUÌsÙs&*—¤ªhTâtÜKGš °~ó—ÿ0[ ÇG·œ6LLª]Œz –SAÍ[çÁí‰V®g/ýŽ^uHÒŽØú‡b§õðQëƒûßXd%`DuÀ“X™ésµæñ¦k%ãD¿á-Ô¿œåèE© Ié³f²ݱgmØê›-Oå Ä;c¸xÈÜ~d¥nò¸àa$YÑZA%"Iœÿò_áÜŠ‘ðÁŸßÕ³aé€ÿp*G®#§x’ÃDù€¹D#0+û<ÊÁ†1ÓÐÏæ ÄÓì¯ß¢±¹0gR ®ÌÖ,û϶É`êú Q_e–‡UF&}ëßží¶Ê3‹3o£6]/Á¯c΀ÑrØýˆZDnƃÙLÑ>À0 ‹YUWHôQŠkž§¶5ì‰0­Sêm© SL§ùAðËt;Ýì²\Ÿ6¹«P1+ÔÊÅÒ½–ޤô ?ù:¼;B¡ÐÆj|R’+ïäYWwKLܦZDýäɧ½{™Í{šÊ|߆½bð:ïÉ®H·mY[fR‹bìf[tqÊ ³ ’€€±ÿ’/þ .~ÄcimÙ3úL.ú† q›G åÎ zʵ'ÎÜcLš!DÈÁW¬öp‹íð°~\ìº'ðìèîæ:¥X/-Úr•µü¼Ï¸›X,•Mt½ýˆ¹îìÈ ëÄÇÒÜ`òA‘žýF(Rúã]tÞÝš˜‹$NcÎZPÔ½]á•|dÌXsÔvõ›¶F–÷J¡X=m=ÜC äùÍòS«ž‹HŽú) tÜI€Å±ÕÍBQ7çN.óAð¼ò&† %½=–l°,1oIŠEž~ÁÎâíF‹®Â& Ÿá©]豬sïœæ¼`ò[2Äpgp`XÀxÁ4¼~'¹Z<ÈBÖì#˜=ÛbNÎq>ÑΠSEQt5Æui4©$ xàÓÏ48ë°íƒdª½uRXÿ§yõ¼ h^Í0üÿ ûAÜÅ‚í¡ð¯* µýôÜ„q“PkõL³®öÌ™šð¸‚ÅXá°ôj-ÑÍbLh8.DΞë+WY³ä A 9¿þ•°ë^É8=Ì+k~á3ã"GZ˜]ÑÍܨDi2‡X°JßÙk_žX ^çkœfÜ:f Yо.Іä’=?x¿¬¦<ç‚ü$2…:ýÓdøjŒXFìÄcá71l sƒ¸XvlÄ ÷0 qá7³Æg"¨»úòúÕõ„¯¬jçn±TV# ù«®r½êË›òr">q3`¸y—+ŸÅXúR¾í‹<'Žçý–QGÀó~rôÓ«ø“‡ò.‹7Ê™ÏTÿœE.× gi:TeÎ…«ùˆK ÿ‹ö°Þ!Ý«w/êM OKÊS®Ô?ö”Í_‚»©O ”¨æÒÛŽWtÎjŽ<¨ª\Í®Q8gZé°¹P;KÏÄ6¡§Yݧ–WeF¼ž•”Âð±t\Åhíê§«G·¬“Þ%~xf}ª…†Ð• A8À«V›9å¾ÕGŒÑ$s§<úüùÎëÙËá1axmîŸhÂ~‚Gì÷s¯–êð²PµζD¸Wç­p¸Mú·SS+á§?³UÓÄþ {ð®ÉÔÇ^1C÷Ü´—¾}꽟€*ŸÞÙ+2Öò-Èg-j²im¥V1sí$A¼‰x‘%²È wË?\u!|èåÅ?Þ±¨’€€´dJÌà[]ö®nèÒïhá‰n»#Ëð߃÷й\®|¼±šŒ¢6™î¸åÝ‹Z…bŸxôŠ„º(.Ùf“LIloLInä¬hOâh­úøaN ‘J¼•Ö¦ñœYÉÜÜs÷PÉ@Ci‰ƒĶÔàŽV»+¥PAݲ ¾àž¹Ö)ßl(wÄ×t­D(W/ëÇùõ½ç´ nÕŸÉ~L6Ýi8;wá“ÏŠk9äì®Ì½)ü«ÉþàÒ¥2ñE>¤ ‚G¶êK#™œ2ÀMu}óÏQ³Š•n'ñ‡KJ*D.c­ôFºµ@j÷1ҸႺ۞0ã®í0ÈqÜÂ&“.Ó¤¶eÏttñ2œòÛ\cK¾kÕ]Ë“9Gï"÷Ñ×V³ª¤Ùˉˆ¡,Ì­5!BX¯Ú©[ý5¡$ËkÊ%uŸ/"iÒ\Þê¿ï©H°üɉã|Ð¥4G]‘`ì:šz_C‡o5Vyߺ£gz5 Ôˆcv |}ñW>v4(Òºö¿r!ºafŽD1_É1DAôi6\ÞÝIó?1ù¬¸¥OØcÖ…„¹#”0”-&cÕÁ¥T‹7¿'o7‰3º;3_1ÿ±¨Ã ½Íä¸6qáΩÀÆÌ$†™f È ,¨Ÿ5;f Kèå˜~S• ÔÑü¦Q›%nÚÚÒã¥cR;» õ–´¶Úa9›rÝr4šµL.÷¿n}…Hºhe’oÄéñSÐ÷·0ah²rsZ3ŠžTü!åT•¯äÏiÕ/~È^w¶ùSÔ}&Ó÷¦ø fõƒÌ| ÞÈU³}E[ÆIUã¹Ï×4†µ«A/;¡/UÖVâóóa[@OEµï†?¼ÃKÍxØâ¯€KÚº.öCèÈ›@E,\ûF ñ5AzŠžj&Îbv˜tp¾p²¸ôùì:ˆWމ òeÔŠQ}º¹Œ! á7ºÃã«ûÔ.ß‚ãà\9½.e¸W'¤>X̄䞑Ü(Z=Õa¢˜gù4ë¸o}¿ ö†øeC?ªøÝ=mföW`Hƒ)y¶KC±‚è"O„±Î¤ÐoÛ÷´ºá芖o¦?ßJÍÚ"'B17ÝïQå)ÁxЋ P‘K €}@8$sccD^/6ãê `»ÏŒ:²’€€ÅŠ»y=·Ü+·L6§^u8ÅÑ.D»zmh¨|«Ík`–óœTÝ6aõK¿?=B‹åqÁ ä՛؈~ xÀìµ4Ý8_î\. ºýåêcz-´J*Dž"º8üYí2ß1 ALqÒÃˆŽ²vÁ‰©®¶²Í¶à+h©¡~ Qdžœ ;>&˜òLèÔ¬2nR™àÁrv†ß¶KÓ C$--ãUrs­˜XÅ=.¦ŠºÉîÕK—0v §³Q£#ÖD˜gQ×LŽíÎÞJow?Áªß‹™ëàÿò1«•v3ö›«µ©sJŸÂ¾X þ½2x½û莧‹?á\‹aÓ2«ÌñÖlÐBÓQá$¢™TÖ šd½]% bç®ð'ùêoéF»†g&wo¾7T”zø¾¬5@Fž›«"%ïê —bHHÄŒä õpêÌf¿ßÏIð–Ù7Ý6^b&k˜òˬW÷¼ó£œù¸í?¾Ë¶u¹ˆv¨$y`-zX;@î ¾ÓkXº9üR®´¼Òù€áíØ'JRÊDX}Ób¸.ƒ‰““ -àR¥Ã2„A½s"÷—ÓŠIpQÇÑ1Å1?¤,^d%q逴Q7Ô8ÂŽ'ïUG÷ïYJù’"~FÆ|r· ­™[&º[V?ä¦ìÊ«ñóèf«/5³qveÆR—ó}Gô†ÈƒoÕ9Œ*ayÀür†Ý7a³†*$§ <›»}ãÁ¦d¢@c=å´³7åÌÝjl-èbäUvEúÀSÿ ¹XŽ ž€ßcTcyÕ'SzñYÍjL”—]ùQ²Á¿ãê.²ÙRÃDŽoÝ+?ÖR5‰„À >*hUÖR†À½öaàCë¢E9v“Zë9ŸË> Â|‹¬½_SÁbÆqZ“´]º"%JÝÖ NöT?uQw¼AB!D(\¼{uðzEо‰ƒ†ÐsEÍû?b}ÑõE×c®¯"iÆÏ™z'×”Yæ臯V¬„Ÿ#Û¹åÆ ˆàtŠ£ïgBÖqtÎe}%`ÅaPª ¼Ù¦-åãqf Ì ,´e°R¨ï­+¶oÎ^Í3Ñ×±òÇÃú€È˜'Ýl Ï”Îhýb!Á³wÑÌõƒÞ_ Iýè@å€O5´`„·…d!’ýTïªÌÀõû’€€é Æÿ*» þù$!]‘xr«̦,Ì<—-š‰¸˜%–FVl™’£tî™*ƒ8/ª lZ@çl¤´MVº.Þšþï2YBóÀ±I#¯ú?á`V[‹4YôkÔ†¼Ñ¦Síê w`¥˜Ëw¼Æ¨Ÿ€È‚ºŒ©›%34ÑaŒ….)ø±HÆ*Ë #ñªÙŠðA¾K wjí_é¸`Šƒ»‰ëÅ®úbH?9 ðÿ À޵Õ áLïºù׳`Ÿ”9«e+´JUB=Õ.CÆ[òUãÇ™N…ǬÚ|þ5Y>N×B:¬Ð«ko¶MΧ š¡ä¦xiYûߊÀ&‡U»•™Ïÿòµ¹k¯âSöâ#@l+ÙªbÀ²§%•HV»²üÏÄó[ãLè÷¥T(ÖŸu3ºÞF%Ê–ž¨õÌ׈f,üMˆ­ ØÜ ¨l[¼œ…ìÜ@óÙ¥íúy¢$pý Õ[ò<”%åZþ Wê jœ<.ät&0ú=Ú?ìc”u²C¸¼7oE"Ipv:N¦^SêoGÙa_$®_¸ÊÏWCxF@6öªW¡î‘97¨C;?üå v"•iÝ@þc%‚½¿8Ѱ‡îhMÝç¥ÙþU‚'ã> ÒçúRU0EeuÑ‹€šrb)¤hè&@ú?èk´Ì’êÀ·XN¥}b‚ŒR’ú÷¿ø·CáGm*³î×[§8óQŸ=’päHn՜鑃7Òl‰Ð )è«ZàŽ7F= ’D<廙/˜õi©‚é„½î ’€€üAûÛ×9nÔQ^%&ïß3zçøBZ£ãªÖGs²û÷¯ät¦•ÈiÞ)òj~s ‚üèPžôiâ1¨+:ðÓ€­¸ÌŽ–$<ülÚ _»í2¨ÞÒ` AŸbã–ëØY”ˆ¢²Ö3Õö$Lêã¼IÛY¦5Óa„‹.ůÅ~ÚÇ@‰¥3ÍEÓdfËÅ>Àv¢l½7„Ði'•QM”€F&¦Ä ‘Òi*üP-éæäî&·ã–Ñ ¬ Øó[gôÁµÞë£eœ¬Ñ4^¢ô œJ¤OíÝψbúf¥ký€>´’;ñ€t–ýpÑ\k¸Èµzù Nfn=fž?h°&ó¨á¢ ¬ ¤wÞ£&ÇwVîgAmX;£%¯uCˆ0A¥> µg—¶Î8§bÂ(°l-GØ<'±wpím è]„èC…5^Ž• ê¨ Çßñ;$ˆ‹!4“©vÏÈ´s&¿™ÆÀ¾h7£.$[Žlï‹”âošxÑf•i"“&cídÈ[Ïb´£]ùJØÑþªýš0Rw$D:é˜üiŒGK}O -?Þ"º±Î-ô98RëC_OfåŠTÿá¤o9$Ó«®Ø‚á¾5Ö'm\qEÁ{ Nv“Ъ"†ìÁhËV»ÿ¹þB‰tÇŽmÌo|j¼ÀþŸ-b^o|9VÀÕ†¸Ž ½¬?ò´‚>óÖ2B=©‚zÆCcCù——–}}ô_ÑqÃÖÖÖÅ·à_½êÉâ[ûÍ´[•Æ{y™ ^¡KgªSLøIW–Ù-C›‡×þxùÔ™»Ñ9›ãü‡ €!ïŠ*îÈ7²æ€gUbf²g}Ôx—õjùç ‹£Ù÷î¦ûØÂ»íê¥Äލ¢†* ¤éTè+žéŠI ûßJ–¿×¥[Ÿ'r–ãÓî·ðŸ¼LŸttXë%£“Z¿çÝ­WôÁšOÇkªAˆ¾!ëüsÄ=—1뛓“ö;š\–8Obx¶€í§F4†.E\Swk_¢¿JÏtÜËdȪ|yRZt îÿ fC‚}ƒ „ØÄÕR J¤z;ïÞÜŒâ%C#SY’ž¬Ž|·Öx ÑüÑÂÆÎ-ñaÜðÃGS”šbzé‡3?¦Ï°îÊvÃQ’€€—Ý(½÷{ H냞’”ÔÍd£; ̈N ÝÚC–6{A•Om_÷šüe‡¨t?ˆµR ìÇ0Àißj;h‘ж`.ýßeóUOl™©KõÉÔ³“4¨–s9M#5gŠ™rJW†)š¥rú<[š1U¶âŠÆø§L´$!2OÎDžôè¸ÕaºÔµ®Ý3ÈÌž´[$–‰)öpÿî <ÅE>=¦”òÐözµ…‡Õ­'zÄ}m#/VÝbJÄt¨¶ô•ü€¤…o¾]ò#rKš¥WÏ •‘ýØBõ“ÚxÜ»o³kœ#KÖ¶bâê¿T¸F +­ÂP-AÐòe\¥„ïÓoJ(½‹m³±ØæŽwˆ P¥­Ò3?†¾-¨™Ò‹ ²¤)q´ýEHV5¬Íí×ßHÌ0ôSfm&æmyð‹·¡Þ‰lûKhjj¨Vª^L`¼wò^dIøy¿Çª>]ò)³øžIÍb"™IEÂÈåÞoßÖoºe9iÁ˜i×VМ)âqŸ` m7°U8Ëhíød` o‘/›RvXH$F[òû Òä§²Ïî„¶«>î?ö¡Ñ­ƒ¹Cø”kÞȵêAYÕ‡·ü=úßë«(!z2¶ËMy7eæøò@rƒ§Þ´hY¸WTÖµ£ìÙtÈYjáõÙIž¥7=µË¥FZÀ‡RÊüñ‚# ‚>õ8}Nìq=î+êg‡$x©þ]QscÉSy•CŠ·– 9KÏáO9:;i»†¹ªÀ™íHœªE† êŠ@Ùw‘ùg£gÌt^MY²èº›‘*L‚aáÐË£j9ÿq¨*\Ô…C ôvný@Ÿ»ÍÛhÆñk J„_SLáÐëÉV¬¨l„2½vY.e …¿2rP§w#¦D,ã Š´ƒ8Še„ÔÑæÅíl)¨Ôísé ï#²¦&=£zᥟ¢]—RéKnˆT¿¬¥|k¨(áfíWÑ×Àekç¾ù¤Ä”ðeËÆøhüUš¥²dPgë‹Ië]iÍåí>I§½ÿ3ã¬S‰ñÞÊöRâãên¬ÐN‘p–ԑˆʽÅ$Œ%$s•¤_¸µ#P]IÿÒ\mæ¯óèk‡ˆ/x&( îùn\*’€€­!Èל÷‘†«³^{ÕiÌõ‡{;äÁú–×m²<(y& ˳B¬v‡ÈaЀì,Ý`È<ô÷Yy™;—hV(K°½D-]Ž›9Áͱf·'O'B]LkvÖ3jÍü˜†N32²ÎðÍZoü e0œÝ2Í¡´Y!Þ-†öp¹_DI5¦pv’|¬JDX¡ÈX`þ~˜(NFøY+²vVó¢4X¦Ec“ ›‰ä•–8·yž-ˆLöŽt*&)gÃÚ! ÏÿAŒ-çò¼û´ô´ßÃܶàžo§8²•\¼¦íM‘*H?Aý­ð(½Ï4 •à)B‰.(c‰M+$}P(©9ÑžÕÖX#«ïÔ®ê Ä䢓…†ÜAvgàtþMc ĽßïatHBö;k>EL¶|ìÍ’V n/'ý5»Íw„tý4ÓÒ>éEÈežJŸGckxk6V³"D‹®Q—Ö‰ÊN—7Õ…DGK–WÍŸÕ*äÆ-à ˜o%ãâš+¯‚ú5â(ï*’ß1‘ÁÃôø›'âç›qh8ƒ(‘ õ7’%;ß1ÎÂ,äˆ µ-…à¨èξ4mþmׄqPˆ"ù@ 59«çœÈd!!fÈPn¿(Çc×ÅÄÓÙÚ6e¶Ogz ¸neåã©ænI±^+ïA¨ ‚íåyphÁÞÎ:C<– s¢¥fõÎPo8/ð2kNªP\Ó6óÒý4Duü†üç‚û/[ÔV×ç¥Xz´Ó¼³å¸R‰ÂÚeÙY›Õ4ï =ŒÚ=*©SÝNj?À,KyP¡‘|)Ã<‰«ÌmAGOqΕO>µXF›Á"&˜8~þ÷>›1Ë«Ò*99ÃM©9ö<Ö´“±£WÌïÀr¯ƒN†ÇÒØØ *“ñ7-õE=MÅɲ½Y¯Ü³¸æÛÙÆë¢Ö|êB/2í9P&+}é‡óeÅÞþ‹° b|¦bwÛºmQnÃ*ø$5Ð £Õ§æÇãiÛØÓmLÈÀóNÜkTè@Ddž´ ¹`\LUU–DÐß:y6¨üÏhýZØ£µ®ºÍ­” Ì·¢h¦þ8þCˆVµ ù',Cɳ§‡x0CO‹.)æ¿,ê¿'.âpA/XÄQXÍM”;V È§Ãøw˜¸XÈ 5‘:­fH)hBoR/u‰‡«²méŒâT:]û9±PpÇ\$`QÇl'kM >’I¡…¡pLSvÑ™ðÛAÞ³cÕ¨ÖV òeæS>&Ó0ø’€€Ñ­Æâ_t iÒ+MéF?Mᗔ갭éD‘Ï:ñÝÌPö¦áî`h³Ö ¤>¹©½ï=åç5^ìÅl$š©×±8QŒ7Y+¹JÂtM5³º íVYáP‹¼ª ëçjØ1³åœ§{5aªeDˆÎöÝy„ÀÜ*m§¥nMb™Â°ã1ñ!–6™Ò©Þ•MÒd–•rü†íbî0y¾àÑ€¦>¶k O°¶1N[lWo‹”€Îj>˜‡rŠŠ<º¬ DÉÎ'’‰},ĘˆÞ2Dc"Ò›”‹§ßÛØÊ.ìàèQÄöÝÏ•—*Oرw¨.*„Ã"Åf¬)Ðfô®½c p…{-û§Åi­¸J$ËÁGÿsÚótW¿Ê™n!éà+¦CBXܪ“7V‘¾d`ù{#æELŠ"½^Â;‰ï¢+CAäÙ08êž{5´xm37ÑLó)ï±£Dîäv—M §ÇŒÎ…Læä„ë-YÈ<Ëg“ˆIAÙ€v†—H©9î™uQ>ÐYÊS¯.°¯•rÔ¹…!ck¹îwVÀÚ/ñš?ÑÀñØ™ÆNc½Deþ{ͧÐÉ–3Ÿ\x¦ä•0ÌÍ!ítà>TžfVŽÜHûõ=[GjQpk#-‡çû®mBÓz;vS®ET«£~!Ådx¼›tæ…ä¹j)µBÌM½BqT 9EKBÏçòÞ4Ÿh¿Ñ¤VU?eÝxÓ-ÕP_¤”f£û9J ª.¹oBk(ãñkApä/òí0 7/Éi⠔¶z=åºE›‹ý]Ñ«›« Óm\¹àÜŽ^&;«1ǨAý)“M§nűޱ¤ú¤¶œÞí€òÉ×ÉÊWPáJòxgäùc¶oç·aAÅéÖ â Ù»ýÛi<-3&„%®#uõa„ì oÝÕiõ|:-h`8ÐDÅ„ ¼ÙC¿|ƒæ‰Óh5M#àÍ0±»D”w*ï ? À¶·½×³ôCþ¿®o0K˜xxhdý9’¥£ìséXó]/`úYv×’€€î&!*Èx´máð‰ToTïÒá&¥)HoÓ¢i˜C6Žº}®:¾¡œÒ„g^~Å£¿ Á—d\ÍFÃHÎ]î@Ö)s]Q§?î R½F.Öó‡â€¿ˆ9ÌðXÐh`µÒÅ»'òÙÈóõå-†1‹ðš äÕ" ê-_ AlEqNC ‡7…¶Á×§áPM¾ð שp( ?pW‰ÇíÂJ%ÇŠUï:¡GŽƒt“o>Î +‰‚äÏ¿×@™m‘ pÒQ³0²Ï°i™óð¿‚ —_ù_ÛbeÝpN÷å%y¯Ë«Ê7g±*F;¨%ÇÍ:@϶5ãω§ æU›8IuœõzµHÏ<µÐ)ãw¹Š#Gö–Ï´{tïCÍ¡»y÷4CáÝr$–+â¦ÆÍÀ…­>ÅS³qÿDÒ®G…f\¤7•)ÈâõO¦žìL®´MÇlÉTVF2_ùœZü>ydaé~î¼ Æl¬[‘ÊŒð³¢÷ldcô³y•å÷žÙç÷°þéâzëM£cƒ~)_»«qP‡ÄÕȽ©¾X\T¯ Š®v<0Í÷JØ;¿ 3ÒUsn²u–”Ùäþ؇±*±æäU Œ’ Ëš™úÏ"{×_Ù>ß Í‹ŠPl2äC8Y^ÆÙü†ÝlÏÙ÷kÊ á{Z™‹`ظfŠé¿´Â!s_%×Uw™Þ#/68kÉIãÖD@ )ù7`‘›êlšÌN‰/Þnsz‚¶:C‚bú#âø §JU~þUø°›ÙšÇÞé—pygõmTKÞþô˜+¥çÆÝ¶“÷Wá. µçD@³¦ãÈ[öh }&C>æMÜä=iJºYþ¨»º§´«š"<åÂäûæFQ5‡Æ7:ÁI_Ÿa~qS•»ä?5C«7o*‘ &Qû’»YòÒî˜\! m©Ó„ëñcÎ☹"-S ‰E1ɸfýYˆ—¤ýùK¥Öéb˜ŽáIBÙQp}2å¥[¤;ÂÏJÿâ<›Àù>lŽ¡:'ñï®ãôã6†ïa»ºLéo…Ÿ@h\oöX™+-sãöò‰\;EåNãè5®‡¬’h-FÖ¹èË"ª÷QúÙ 6Ï᯼(ûh¬¾·|€iY»ô"øíó Ã6±)mðkí)½>Z*’€€áiôÇm‘Ú>¹ROí$ƒúƒxQnKm¨WžÂ>°êVÖã0\’îÐ[²eÏiAR§¯€û©òcÕa¯(];ÇOJ9Ë&8MSö4^œÐ¼‰Ä6{ZYÛ’ôVA·rd¡~’U~ŠKcôG¾³n\_{‘.Œá¥‘Fˆ ñ‚¹Û2ë“¥ä‡ñ1õèßИþñ¿åëàÿ`ÍsƒÊÞððà7‡°P÷JFê©VîíR½þîy·ä¹ƒ~î¥HÙÚoD§A?-«½Œ[Ó;Ù¸°Ö‘#[Y¬QèÐîÍFY# ìHoä‡êŸùiÌ9§ËF—_QÒp«Èûk(Êd±%¤Y<Æð«¥ ”S<7_¯».òm@2rFYHzÃê7\^ì<Ò؉ªb,œjƒ¡˜wÝÚ,žÒ4à ɫKqI®™/þTU–/˜Ñý›\é<ÿŠÁO$ uö† Q^³rby5ñ6ú3ÐåP3c• ÏnS¥8Û'"nPÞÇM¹ØówÛ·÷4çGú9XDa s§=Ÿ’ÄE·<‹ ~ø¸ƒ]%‚Õ¹ÕÁ6bºš*³9ìSC! ‰¥9»÷׿¼êÐøWZ² áBˆ$9(E—– ÀI¹•Cç&·”-q±@A0û#€gþ-Ö/RØÖãYx£:¿%uûÃ’¬3‘Š¥ 7íð°Bį}kš}iµ©f*!BXKUõ>ÊMÈf’èG_Œ3óŤï×Ñpð^»Ó©Î/'(y¶ 2[·ÈêÕé•G ÛS"&õMRÙeáår/t¯€èz}³œÌSõ8º;8¸;³ôÅ)®öÞª{—ÝA„ ÷¸5¹b:aØxõ¯¨À”³ ÕØ©2Ò‹!B0O쿦4[`TrW‡’m!bú¥ž‘¬‘ã <ñ'}ìÝìV€’=Biœî€ (¤Š3ÃÓqíVxòïð ¿=÷É™ò þµ˜8µgB ô‡‡Íå¢#GŽSàq1%ƾM’Qþ?5q‡€F1_yUê¡pO—ñÃÐØÄ½øKûù“í¦m É7O6;ÆUÊ*)ØË‡6‡mA“Ûâ(¦áchûuÜ$Í"•뺺ꦃõ4” uèÚŠÇüoi¼˜‹Nä G_éì kpùmèÐ#|p,Ðò=Ê~P+i,n¿%rãÂ÷Ž!ß÷¶Í9ÂC;ׇ ¬Åø¬9EÇŠX@ '*lKÁ8«€qk|߬¥h*òRÓÞ6³W}„gP†å—ëŸh“{)_•{·DÐ’œ ²PI'4¸æ&4 €óq2ŽíWœtÙS0QÆ~)yCÛ… wíüê#—A=ÝU¤qv^1vQ®TkõD/"‰réÑ©¡lÌ¥èÕ®Ž*|hlîäU¤¢ÍõÉRƒ_~ê÷sï~Vô óÜÏé\2’Z9Šáƒ•±ÏçYÀËjâ¨ÞàÎv¶ÿ¸ŸŽ'WdzÂàaMùëïË1ïÛûid^ë"Á¼+×@q]ç禮#AÓDDKÄMž…\¦8çFÓ•€ŠŠˆþ¯1å}…µ7"åÖn˜ç§÷Ú Ô6ÓOݱüt¬[S°û›QZÈs’cÐÅI)F°r£Mói²q»j¿ÖدK¼ÀUaÄÚ¬Œ ‚ ÉØ¬GK¤¡‘nOÉ}õ¨HB1gN‹—é:ÉúBnØ›eçH•œ‚‚dMø1u’ÂvõÅû£81–3ò{}ÓÌ\Õ-¬ø7ä×üî£Æ°ú1õªÌôÇÜ’Nú„BZVF¶Ç£k¡o·ÀƒÌ¦oi7ç:’€€ß/rÀá†ÚO °ç·j½tÉ¡q£.‡ À¢>e®¡äÆû+ÊÐöz¼OPbè¦Þ¾1Gc[ ÁXÊËä·M1s“õX…G_>ÞÈ<²Ð§™|™)åÙƒ;*+çi€èºŽr Þ?¶3ÒêB!<Ö÷fRèCå˜%ÍB«;ëÏí©õÊ1ü¼[ôÄT÷LŸ%" tÅ$9[\ø ÎQýu„S‘ÖÁr ,™•ìÈ b€ézeK^L¬)*Ï—ý>$éS‹\âæÃ­áÙ?¯íuÉ~²D•´²¶òÈÞ±Ï.äêå¬Å~9o „Ý$¼ dÀÉ'¿Ñ}tˇÈ87/)z”„ 7“gv…ÃêÄœšÓ9rÅßkêjÙ®>¤ìˆMY—ìW:ÿg¡±Õì£R‘Ï:KÂñ½Kv-Ã-ÛÀ5;% òÖ;³Šz÷î—ÃËÛßývÞ[…¨=²D vbHc¦¦3¥îXeŸº·eáíG"h¹!‡qƒ5 Eó< Ñ£–%©ÀÖ'ѲvHyšS¼*jacp`óñ:¸c©—çs§¥+ bÚ`:Ñ€¬°¡l/NyÑKù¾€%cØ$V Ÿ!Ïq:©ª]Z%xBÄ|(r8øC3w㉧½Ô ¦Êa.ÀNÉ…;ÃH×. œ‰ ]Zâ,ïrAòàÛC¾²5RÿÚ¶7±ÿ.ZŸý‹çØA€‚êc®‰Ó‚ô€Dx0÷sê‰î ïçÉ&ñð,¦Ž*~ú6ìÝRºæ>`VÊŒ~Ík˜‚ÌëùÜ:5ôvžÙ¸=iH·ð‡ƒ¿b!Ø­F¥¿êΖ'C¯’K8C)ê-¿ …Ëáë>9Ê\}ï'¡Ò/ 6ïw#HM» óyšºs–—B'&"×4®S;ÏJH#¿À†@›î†’ÎÈ%Dä°”`#3W¤â †ÝÉ–Ï T »®W9«`ŒuwÕ­ïqr«@èU—ª/©²ç@:%Ųñ‹òzîžÎ7ˆtð“k'Ç¢’¦fªMj½šQ*±èãÄFŒK´Hë× OÃ6¦ëp+ŠÕUÊâä±`–wÀu“X~`u5‘ä$R-ü+ÿÞ ”~›ÌáÉžx_§ögˆ²—iuÕWäK?cÔ3ck ƒÞ[ìßOGÎÉ«¸Á-‰Èðº-ˆÌ(eõƪ¥_`’€€Äß®N«¹9ª;(^¤¼$×d«9¡ yÃ" ;ÁÙ˜û[Ÿß€C•õË¢ ¾“‰)zµô^€ã ò&YÙ „Âj—¦ÿRï^%ãÉÞhšgþ÷øÊ/ù@häãS¼g=ù÷kq{ÛãÏØÐå£Fµ¯=Š9SþÞlבt§µ°m^x½ó%&ü) ðûpPY¦víŠ6!óc¥âßip» {ܺÿ<-#ãVq‚f›LÞÄ#¶` s÷ ¹dsŒáT¼)Ò‡:5“ØÁpÊvñ܆ŒL©nfîß»§‹‡GZ½GòFVuÂe&ÍÝßá¬ØÝ7c )ƒà3Z¡‡°Ö,ùq§š6õÑ·V6ƒ¬ w®Ÿ«Jé;Nûãô}ˆ'¢fÞÈ‹ÅëÌm÷ŒE&p:©.’a׸îNË¥@bBd›%¼3R…RtrWW÷ÁZ >c^U\ISÀðmÛágœ ÛU}~adIh÷¤.¥=WlŽš+aDdÌ9yWñ_³@VÔÊÕâÿÂwfÄJ»IÓ™Ð}Ö@¹†þ¨ÎJÓz »´}q9æŒL|¼HHˆëI¸§-2&U´ÀZ+¡#7uæ¹RŠª_=só(Hþ¢Ú–7Ù=‘aÕŠ™^mô²G‹äê97kZÜÆo™íÎoèbg£ý.½¹ñ3";ÿßOõ›í€vþ›nE¿ qxèóÉòî¹pˆ ávÁHè }ì¹­%áh+>ƒÉó!^½k‡„DMx‚ç*-q0Ýjuát,PCФ_½Äé¯h^H‰ˆ‰õt–ÊÈ„ã¨R+¼ Â¥îx‰!ómcXx\";‚SU…=ÐôA‹]˜Pàp®,gýa+‡²Rᵇ¯÷ÈÇz4a=E×bóe°n ©‹ñsÆY,ë©òZq…:»ãuóßÑ <·@Þel€vhnéi.°¶ 4÷9€€0_eUv]×yÛf‰vsØ®=EÅ–[8ÇÏ>OM—JäpU–Õ¿³¬FèuÁG³)ì2ˆ”¸L&$ul#é`Wi=Zåq‡Z¾{CÏyx䎔lx¿êøßÙ9ˆ³&o+뜅Ÿò-í*ÛÇ_ò!lfF©Èé26TÑÊõp¬¨Å7}ñ,®Ø—Ý£.ÃFÒñB[/¼ ¡² ¶‹0’€€®j]s+MBZ6YðÄL7ÇÂûÄâÇ“—¼9¸;ðw¦¡fΫàô­Y†ñ¦¿Í-½}"NÙ)™5ÇíMzò鼯ßéñO''h“Ü‚dl¶7u‚ ˰'ÄŠ‹‹K—–¤†Ø}$ž`© “à'¢+2ÏŸÿà–Lµkt3ŒV ý€êvù>’ùuA¨áéˆPëÄš:“éÒ•'_mQìüg¦>Ћ+m’ãŽC>ÚÓr#éc'åuê{®›ç¹Óö7‚=û>tt¾A¿ÅëyÜ‘NÒ¿q5éÑ î<ç| ç϶)Л>VwÀð[$()ÏaéQÞ@BÍCmgÓ.Y}â¥ÛGG XA©‘bŒ —·f¯ fÓX?qsDT0»Ãú÷Ád ôNÓxObn; lØ>Ã}çìt@T·)3ù4Ò‚0rJu?yc£t‡ÃkÍÿÑS”‘d¿¬z{þÛ0s¨çœCÒCÚÄã^S½£R1%SžYv·+6ÄÔ¯åì\é ¸i@"ÏÿᡤPõ*ZȆ=FŒ_¶ã:û£Î;Œ%.ÉD nKPzz>’!\R•2¢yN·úˆMöÊY=éí<<91$ªT³®í=g¥«ls_\eìÂìò¯ì€PJ"JÄLnÓ¥ŽÀ8Jß"üw Þø,ÈìmüŠkú2ÊIê€ö.̼ìÁµõh<ã?µ–€#REóJÉ d½½x#¶4“ðµUO8lìÿq°F¾¹á4³‰Ø.¹/¸faUÌ4ÏZ•]¡ÊÀÔi ¾32 ‘^¦MsµMæp`Ð'«Îß±ïK K'ëÿÉz%vÍuY±ü!+<‡U$é,ƒ®¸1R‚TšV"|3@ P>NoÎcÙ|ƒJ­‡¬’MVªl@„[õ.Ô@xMð§Èkz¨Ã,E88yG&Øc*t2ªó×Ñù/±êVÍâé ”’ß•vR7^øÒ*dV]9n܃PR3¶Ý¨D]Bµ\RIIç<#§B]†7†SJ_÷ÍHþÀž“Î ˜Ü’ßSþOâó¥qÉB°•ÈI²÷‰ƒËA-_P[<–í3Љ:{Q‚ Ã{ÓÈúÛ* ë̉½5v™ÅÌê`/:µäën8“ +µÄ‰39l:žv晴€€Ñô)¶-€;ja0j®áo¢s¹ªxLf à¡ËßÍîâZú3?‰_ñfÛÓØÆ©‚’­‚×DdÄ=8OèÞÔ 0›=7½£÷u´€ðµ‹Ô6§»òy´èŽŽýæ<¼åÀZíMU=ßî¤6p&Žx©ÍÎ*Ä{‰’ížw³ö¦æ˜w·k=«4“XTlŠÕέ.Ių¹Îíïtnº8ë+¿Œ ?ª80‡ñ„§ '•_˜'ݼBÓB|`ÿ Á–žêYÜãò€ò­^~T†ƒÎx4a«ì$œW}BiA œí…¬À‚ÊÄ„ð3-JÿsÖ .ZI$~lù=2·'?5ݨÊCnQ‡!é˜ÉyVƒ³Wûp}JçÌ~æ6`Í%.úÁÍ®È%]eaÞ%y7Á˨ÎK¸½‚œ榽Tˆ©¬Nµ°±z ¸]¬¾ã¯§o²C•3eí@Íšx†ÄÅNÄÁ\_eÖ3#üÿÐ;ÁC¶²@àÄJ$Uy‚ñÀ¹“ÏŸÎû¯eY7òQ.3³Ux†¼üVý•ñƃôþ9î_8ªÀÆX¤úªvóÌCi©OÃf™ò¦ØÏ¼ ;ƒÐ¼á…é̱ަé˰ ­}®ÐÚ¦~ iiïH7óXÁÚýàCðZhÞ@œ ã<' Î)1ï'lüÎú÷Á7$;v–”;ç,b+–;›¼ãÛÏ«_R2÷¡å€Ž~ÑûûµšHlw '¥€”§•=À.Ê‘¤œöyÚ‹v´óq;¹Öug§Ê Ïrýs^Xɹ"É7Í`ì mì—ýÚ(u†ù©Ã¯¶é½û ˆD"µ3éÈì…ÕàÜ…B"Aö¤ Á«‚<Ó/aÃôÓ;™“«õ ‹§·†Í\ê)æD›ˆ9ñÚDMáµ`zú$+­šŒ÷Wà設âÃ`VVÖÔªe•3ºK‚F㦃‡_†¸F$L>QÄýÝ0E7¹ëRKÿò½ö,––Y§ð½$µô&Ïÿ{ÖwÉè+¥"³Îz®·Žoô“éku#ï‰W€|Q'O…pÛ›rnt°WÆö¡š3W|·Ñ™Ç~Ì…C‚ds ®yu¼j킵¦€t+·Ç êø.óGè»(þkŠ›Ò)GG`Ñ zê`Úô³î½×ãøvI¸©ðÀøF8õÃÃÀÏÞ í’€€µÌ\wJµ=Ä ]Ui![$šªT˜!š5LUÃ㵞¼#€Áž]ŸÉòxcF´Ðó°è6¥ºHûGÝër‚ïýïQJ™¢«È~™QÇ|`$Çs ä|΃Jö &pwÎ~¿ó²Cžâ^}Ž#aâQÆ‰Ž”ý0£ÿ_ӈ𿠰)4ëï_*û‘¾vVùñ”öÃ/ûO1‚ˆ¬z2þ?¿÷¬LâÆ9÷ò§a>[ѰÖlb, åaUqânç`±Ifñh¹œ˜@yÈÖ ô6¤" ƒ6á^‚¼R>’ã›Ìñc+8— [¢ø 4óqeÁËÚ%?ÚGßU—ÿ´­¢)ÆGZ§÷UĽ>©8ªbÁS6– Í9³r†üÝ[ÿj™tÀÚ ß‹êØVGzY±Ô8F~yjÞA¡Í8ägëÂÛ)š<óaÍ|M$>Y¾@¼ß/?ú7ó5k.º/âÎrŒ:ó˜4ÃâôT”BÒDŒ("Ø뛊ª[ ^åïñ  mimÉÅUà-“Ï1ªûhØ;Á ¹#ÇÙ> 3löŒf4F©MqG H¼zïÃjˆ¿Y߬s*ò„Þû(Ç®R½è€*±@Ä·&Ìç€!X>fG™á53V8T÷uuå9†-èTEÔêÕ& ¦G¶½ýáìeÍqf}v0È3nÅÄ,KºÀ•%«’Ì›Šæå%\ÐAn Ñßs¿cÓÕ‹ ™ïÊ‘,Ã}ú@ˆož¨eíðîì÷ÅÅ#zž_À]ç¿`FÖÐ*S¹‡œÔqGc@âÌ„@üÒyú¹¥zv«Ûý–ûÅëZt¬Ç 5äÄ߈û³9r÷Ü…ƒ£´…Ï-bÊ^¼Ù½šq–w{=ô.á´jáy¤B•µ hûûŒõ ™ ­µKÌA"AíæQa~í5„ns-ž$ ÞN®É?ÛB» w ÉþøS]M)i¥Ò-é™3C+~®e”¤ ëÛ¥‘+•Ë¿¹SþÝ^ îó¯àwk ’-m  ‹ßc.k¶ÈÚl¯mÆšÖ3Z”š#{6³~Þ|u–Xªk ÚÏ䊗ÛK;ûøC>!Üʽt¿/¸{¥ð15…®„TÁÆK¨RîuÈ8eõ—­ðµ\§,Ûél?F:­žéŽº’€€áñ¾TPA4†(ù´\°y?ìCªñä‚áI³“0UY0 ¦=îi1Cþ¿ÌáêTúx޲øcWÇ¢<Ö†Ç)–ÞF¢2¢ZÒªÌ>–¯\ê¥ œwßôÇßY&;Ÿ\4Y¿Ì 8³˜QqúÀ}Óëmœ$ÖÔç8=AVôç·dì(¹Ù]ˆ'm|íg1|5ºî±}BËÙéÉ6Ýãÿ|’@×ïÃè9LÕ)~`/d°0ºâÙÞ“sÅt¡A¹£ÒUú3‚êéÄBqü CO4•3Ü^víÏ·>Š-t |!~^8dx†½;¸pN|[GvGÜœ–Q¦ 戳deˆœ$IAwGÔ’ÕNf“’Î×ð€Æ‘Ô¨þµ½L±"¡·6ʧ±XdPX˜TEÀRz1î€|Æô‰?Ðɳ6 £êŒ|NˆÖ^ÁZ:ž‡uŒjc¦¨?žpFÔ|Ï,à1Ä#-_ªÑÇi÷›ò„¾y@Ý¢ˆ½í’À¯&ŽÛÕ´XpÍt€„åd †¡1Úp²" ô ©æó`Ï‹µÁCˆþ.N|”ß(¥8ÿþßeŸî¤;æ¾&tžZ›Óu þü<¦ä”P»†$ö¬˜a°Á=h„:.ÖLý*›UtCÙÖß*rçé™Ùý¦Ëc·&Ê ¼–òÓÃCÉÈDeŸÎ5Ý‚Œ‡Õ¿rdÉ<È]xõsG²"åÑS®x|5ñ®À~4ƒÒ€E¼ôÎaþóí†GÈ€8ýU3»Êɤ‰òÑyhÀñ˜<>´™}ÉŒk¯JÆÁpA´Úüx›üpÙ˜ÊÀüÜDä¨q¸uÆŒèºZŸù2xÒ›§œ PýݼŒT"È}>Ù²s¾~õÁ²úL@íö,±R³l€.qែIRuË0Jª5Ï]$ªˆL,Ýž3¶03h{Q ‚ÞI“fskPŲ¨Tuïw™þüYqèñ´ü9Eätâ"¿K:éWuÊ83±’€€¨Ümÿ–ÿyÅÀu;ÇÑÓÆ=æûrýyp¡óT+³i§€L%M3[)*uªE|eöItèŠH3!ù <¶¡¾" eê.2Ù9 w@xöE‘6=†½Çp»7™i¿@DŸîÈ:ßèëMJd¢ 2؈Âô°Î»²2x‚guéÐ%‘pÔ½YŽÒÛÕ´é£ìyÈ_G†hgª ™d%î_P‡Ú¨òŠ@ ®’SP£Ç ?à£î£à¿/gƒ¶»˜ÎyáM¦OÌl])Á}ˆi36³Òg,̱)˜«ERgßstµ-(L[€Bt½òЋŸ>—1¯B>ù¹Ðn…»µY*ÂJÊ#ÀS>¥‘làW­\˜ýàü|Æb¦"VË[¼{*êOÉ«HÙT/³±XXïZûÆŽs6Î{Èönô0x¶#£j´¾4û@j¹ÆDßÔ8Ÿ‚Ãi>e_µ_ê£J$ »hÔƒ»m­Œ(™jzÛ§Òä Ùm– õWbReOµÐ ̇ÆäöÒÃÝ¢Ü[t‘‹^ÔøJuàˆu~8wÇÉÂfd'šCP1ÄÛÛZÌúÝýDkX‡3ý,™·ì‹ 3çó¹®gDÿ>Û•Ï%Š#ïr¾WáCgNuÁ}ìUD#Cãíqø¯šo‰§CÞ)¡ÛYÈãr&ï4YØ+e[3‹pyßv3>ùO¹Yb’*ê]ÅJj2ùSü‹op„ˆÀã3 @Ȭø0ϋܬ»+àí¡Þ·Í%”èÖ¿ˆbÕgÙT¬kúÝhB£éÍË1>eÐ>Â?Lš3q‘›Nƒ`Êtëû™w°…½C”‚†bÐXxölëØ û7_¹ŸæŽtTñÌp–Ôcø•mKŒÉ: xEoî%þ¶Ø΄’ÙªùglÅîá&—H˜ç[€†~‘öæ†ç¯»¥‡G»’“g_ÍK°Ä.“BI M¡iQ럟Q$»c¼»!°D–mš.R*ƒQe¢Ü¤?æf  :Þ¯!{IN ¿àÝ ÄIJ¨.˦Ùi–Ö Éÿ&è‡`Fr‰ßùÐÏø©'nÄ‹rÁ¶µ?!*mÅøÒK‚!³ÞðàÁPX†¹8œráɧ†Òã_¨#Za\}"Ä þˆz0€ë¨w2K™õ?zÃbb÷…¾’€€¹M+ÄÀ>DÉŽ4냀£g†wëÐÆ¬/'Iê׃;ð®cÁ‡ò¥…çûyX÷vû•é’“Š2„°ýÁÀjØýè`›Î‘žMèH±*£½ï¿šõ—§Ü©kZÿä´|Ëyùú«çÂ÷_˜eƒ cRJf¦ÕÁù‹ »ÎÙÓZîUÃÐ}.÷¡dî)›;Òî·­b)>Qá-“ˆsKA!±øÒ#Ź]ùW™·¹d€æ”¨ ’½ÁðHoÍ;¹W‡ä:í¢?~fJR~¤Ily‰­“ÀŸã«kªfe†æœ¥x‡¢í]¢í5ŽgË’´"[œAÏ C˜÷¨~®$ìÖK½2f1obœl2p-ÜÎYPFBÅqà™ï-é!‡À£âã÷ék²wÆÌJŒÁ8s÷Ú®‡xÏ_û¬"CŒ5VˆZI®b&«{m÷•™!Ù6 ‡ÙU¹#ÂXÍ%^²]![Wƒ‚qÉGÞµŸAÿ7cr¦ÿM„ýsfu]‡(z4‚\¾Èan¹9’ÐX*(Œ é`.Þ\Í£V×UPÃ>Ó «_‘hÖÇ—'¢Ä}C¥sG›ú2¬Ü²/aú p1k[e’£¿ü ¹É€ôó ë3F’ îJõ¬}_újêæ=$1…~’¿" ª[ÿ…ò“VBOüI,&¢fàÐÔ'²Ë‘©ÙØ öØT“nlR?!ÙS õ{Ïm4çñ,½Hy$ÄX6¦ËQQÓhkýÿîƒï~㘦àvH‚_·Ü®îÈÑbÓõý!¤ÒcR˜Í5œÌá[Üyhûò×cRjöññ\o<òP»ÃÃ&Û@n.ÉÂR ¥£Åÿ­S¹ðjò¶v4ü‰;gñ"}±Ôâ·æ¥–º‘ñOÞt¢¤€]›(BY޵6î+ëOî‡ÐÞM0ÄQ¦À¦Ûbf.(,Â1vd9Èð¢/ ŠÕÄ-÷ÆR™]•³Óî ErÝ.ÌZàSF&w2dèÒM%žmØ’ÕëåíOŒ®Ø"'ä4K=æ]M Z<)¹R"ò #nKWtÉÏ©q;_:1óJ*¤õìÑÁiá‚a.å)ù'Ȧ)朶õ 8rzuOÚŽÜ^W“+Šv=su;Ë'/v&iN~Sà•T€’€€Í—TU%7Bu¸7>¸hQëU3djnŒI¶Â~Q‘»ÒyDbCádpÙi˜ ó¢ ¿xÌŽ›LÓZ(à‡äYò´ëZÞri±öÐwc1ÇÃNÖ~jË®¥X‡4qRÖ€¤Ýâ$‘Á6ø/pãM© °Ù禿 ,‚½[sÌìu;·š*b”‘Rß¶uröiäÖWÙšãåY6²!(¦!›S y¯ùä}ÿÔÖ· …-àa"Ýpt‚ãaÕð·­åMôzéQN_»GˆEÎ1€O4P<[§XrgñžÒ‚¶7͆A%©¿„8Ÿ¨èbô2ÎM0 ãâ¶Ÿ²Ò¸ê0$¥2ÿúY…Ï ü)üP9âé`$¨$0c&c¯téÎzkÏûðe)$ÐØÚ y¥âÝ7æcú±dšÉº…ŠAŸÆjæ×c{R µˆÃŸŒ‘vÆ"æD3Ȫ½‡«_—Vû;Üe6óÁ™Ñòp˜Ó¢÷A%wÂ^d¼!|òT„ßÁ¾”€ÄC3©S¢^ΘùÆõ°\på¾ K k2ÐÊ„ ’P©±M¾¾óÛm¾q'MþéÂTîPá”Q6Ü5Ùaï/>þÄ’Ú•Žj# Q\8:Ñ ‰«æ6•«ß/!Å~G`rŸ‚0mƒÚE8[1~Ãq¯æ¼÷œÙJ†—FãZ}9(yñNÂÙ‹ .ëÓnâÿ!@½˜¥5¨•‚ õÒWD×…z Ô0ŸŽ²@ÎèÊÃòAæ™EcOoô®É\€4qõ˜WªfÖìË\wÒ<+¡ÍÛ­ÑolyÊW9…•W“²]´í5¬¶Àd6Qt²ä¯òÂÕ}ä‚L¬¿æIÚÛð§ ]Ṙ©ŸPî„Ú98Ä7—#Îà&*Yýдe•|K6o£–SòÍ Oõ£Ì2»ß?u6ü2<æÖJŽâTêÒ'Lº?€ìµ¸SY¿SÛS qÐØ£ óΚÅÛjPñšJNñA,?q‚ŠUà|]ºë-ªr’_ÓB±ág2}i>ip!þš$/ŠÚ„âL‘ÑŒñdÃÕT¸ÝòŽ3g >«Ú6 ¶Ÿ!6ŽÑ£ž™/wîÄÖ@ :e¦µa³vÙÝVÖhÖG–Î ŽšBPáçI½Nƒ¹ø3x»×;K‡ ÙEÑÛÍã×ôÁ.päÊä–’€€½bH6îuøeñ«LÿÊ“zëD<ÉLiû€»w™ëôÉbG—Äg™àì‚ B°04»4tââ*®Â|çéPÁ˜œ÷©¢Úo9¿¾x¶hëÞ*¡$ º“@.‰Ä "„` Hû5‰»?|âŠëÁloÙ¬ámÄÑ‹v8ˆ³%í¦ÕsjsÎóüéRR«v,îI5¥®Fp¦µ@g’‘ÎF1¦¢ªõÇ_, þR‚dþ´t<Ä›“Uç€È~¶T'mÑw*‹õy&£„×ÍVæG}ò™*?2ð÷±lÓmä¹]Ϋ*~üdbFܽɌ¨§s‚úÛŒb\*›”Æ ž¦]¢$åó#Õp‰q¼‚õ‚6ãó ªãP$9¸­l'i†>0öû w`0“•AŒ*@Ú.#ì$op|ô£w}W€.%NˆÐsA&ÎX ”T)MZgåKáâI²’ü^d>šŒAñ1A]S–0QÛ?š!©±m=7_“ °fÀDG3,9êïþýõÝ陎b·.fkj}b<Ë`ÐùbNz¥ÑP¢WõO 4àõ"x(äÕRù†V—ãÐýJø³”‚-|^xtt®Nm_«l‰Sa¼‰-nÕ½w™a÷Ýßr,:,)^þ­‚ŽZª—ëÞ×gù”µÐ«6Ë&‡$<¹°î6sdœ`aUvôáN ³?£6V Š1æÏ„ ,µ5…5CfsO‚¦”G…Ù#B3lzˆóèòºë‡RÙÃÊ´o[¬ÿpÇ1vÉïºþæšæ;6!™¸-ˆIŸLx´z4Õ×Ù^ ’ A¿ÖIFÂAc7±Qš!D‚ìÏ|èЗò¦¢&‰`U¾V¤Í:<+ì"é;,+É@u?ïϦÓ7â!T¶ð  Üž€&ý™" ¿eU"x¿òꜨ$¿•ØêYí¾¶¥e(d¡,ŶWµ;vºÊoûò¼×}™ÁІNCDpð|ûð¶ÿ“«“j,£ô …ô¨¹ÀÖ Lvp uÎ,?Ë,^¼áþ4vˆ‚(rŽ9t”뽕%L*(µ9Òâ«Ä8D›b†);*¦ÐºÒªS 0T…4MÉDwS€™T},þ{9§+¿ÃšÁƪÙ/JÈR}ôäº$j Ed)Ñ*U%’€€±@?ØdJìÈó~U5ÄuÁÍLw¨õÂ=5FNnxµ£g—A<€öÀ[?‡Se^ü­§Ù9¥¤D–ô·ˆIVÜw£Š6í±Ó3Z Ñ¢¶°Ÿ"V»Âl—ÅBjCx+ e½ªžñYó¿#FP‡¯@OMÎ'«!òa/ÅCZi}ãAñ†Vqnµ÷{¯[ùBBĖºXßÁíA‹‡aFÿýË=,°—Ö{«}¨[ Ö ðO)e.Ç„ û‰GN(>\«Ž6#e&qç±à€­ÿäлT¢1„ŠÎrÔ†Hs]ä6øïÿehiYÛgؾÒ<³Sð‘ꇊÊ­ËÙùê6ÖóéÿluöÖ8M®Õɶ֌þX}Ø~fü´±›ØÑqª¹ñÅçrÔOëOáï˜8üq,â+ô/R~‡]b—¹˜ïØ|`_­)²,íÒn0Fiy/é"®3Óª;Eâ1Ú=$L¾¡:fFɃ¸ÊÏ3`ðzEO&‰@0`šôïú­É ¤ƒDxÿi£n @e-i½É¾,;Õà !u½mà°æ+£4úÛ¥ûRü¿Ÿ(ü SzA¡]ë— 3€3Mõk$¥[MmP]$XÆmÙ"¸(›ª¬<ûÿ”cJ¶Û€Äót_ñäÀR_³Ý¥Ø™‡Ú)6¦ÏR9u­­[ƒpržE>; œy¡v¡Šž‡6ÏÄÄ’ow.ñ~x8ýߺ]z5º˜ÃŶròƒÕnAe}£À›[FÉãôI8»øj•Œ¤ªäd>¡D`¨„ðçuÆ^ Z'Ì¢¡RÜ.RB)Ô*y,ši¼.=¢$œa˨?HRî é&šG«ª‹$KçZÂíCûpSy­Ž‰O}†¶+.K#õ%,S]–(Ÿ‘1‹äjÑ@Þ.ô_WeÛ²±öZ8ÿJ͵\™Ætt§ káÌ›´Â/á8¿pËÞâ)Ã*|œlà÷P…æ=ß÷`Î2ªvÌåþD'öÛ ÎÅ}=Å|‘‹¢Yù¥Ù…TÇj—D†Gïõ¥™Ý.ßH†˜§%f„bò-wnº¹=Å_l?À­ b’€€¹‘–H‹l|8é¹a‰çÁj¢$ãÿÔ÷¶Õ.å8':±öJœÊ:ŒÝ¶¬HG&¿RÌ=X‡`j‡œsØè\mùtÝìÙ_¥©¡³:oèF’¸&5øÖŸÅ1,¤èL³ŒÇÖolÇ#‚‚XtÅnGlèŒt“• b`’1zjúêµÞÍ¢µö©¯ßfBË«*‚b°~–~>5lN_Qºž<ÅIGµ²ÖÎÁÃTD¤Á.“óNªÄ¾!ƒ<Ð0€Ne.e¼±®êˆK=‡aå`·Lûö©þQ9þgU3¡±:cA㽸q>?…újg ]%ÔŸ¡_¬0í¼I¬[„óB•v$´W±Ì€^œþZ¡]þ{¡ˆ 1–¬#MÀŽ,£¦ÖßGóD,åÂ7lgÓ|ü9h,£{ÕûݹÆõ"ú¥Å¯ÔÄä-r¥"*¢u†ØH?j8L&–z3t‚ß-} :å£å·p`¬šÞv!Aš¡#þl]\ÃH¿-²¤·—öjøÀÝkû©ÚïãèÐEà¿ò°ö"û‚4cR·ÈØ3@‡˜|›æ<È3;*®°¹ìËaË—]ÀõÎR±Ò“ŸSS ŦKŒ>â'±îÒ®« ½8)Q<Œ«{×LÎDh^Ÿ€ò:ƒ}®äð Mt +áé7õ|²;:j f6°æñ{àÍ{Oþ?ìô噲y/Uz±¿%¬ªw€Ã³Xøa’ â~N/áAêµB¦Hz 8ß<Ï£¾<ÑPÿk /ÅééMÖÇ ¢[jWïCÐÆÅ”ÇWØ­¨Vvb~ùÆÔ‚£šÐ7õ:¿/j«û Ëøëøìõ ¡yãùBe3.™£éÅl@ @%vDoÍ8€içïëROÂrµ›¿Úü겨¡|5¸~ÝvÈÚ‘pqãëö%æê)Jê›ýŒ,J»–[sc{¸!X ­j0·`ámTy&eBfœ­pw²0"-ïþ[Vl¤à½«ÅÂÔò’J¸§ GõMò>þîf=Jæë/†Òõ™ÜUzæ©!øÇ`OÖòÀÚ’R¨·,îBêùÿ¹ûA,¶4PAϦYùÑêÇA¯ýßýÆ"sl…±2ƒ ¶ºŒ,¾Õ¿Ó–Òµ?•R-ãŽ2å9!Ùô"èq’À„v F¾N§Î\øt9ûûXKe‹ô¢#FböËS`䯄TI^s°ã2¦P;Ì"éPJÎ:Ïz m*±ÖGô9²ºodýÊ+ÃÕ>ÆN^‘g…¬€ï?#¦­i¶`.$Yºÿ(íùÛÎÌtÝ-×ñ(; Ìîp]B>²Ê(æh²\XcÕòt¸7D…Vï•€Û̱Ô$[€òÆ‚î_´>nÉ‘”éQæÉÕó[t§4¹sSUkg P𘩱ò¢©Óã n-?X‡“ÎÚÿ“²$¿â¾ÐÅÜby·­¼’uvOãÆOÀbé#Z„àoÉž,CÔÏ_‘ˆ°‹0·AФܸÜîró9‹vÛìlæAKTˆÓ‚#Õ¹u;®†qí–†’€€í‚ÀqDš¦ÍšéÈgáÏ•N.²°©µ =0•ËæûÇ®¥gÞÒ*ä”tr}þ‘)xxJÛ‚T5)œPÈš‘÷ˆ¯ „JÜ?IžñGýx/qÙãµPéDÌ8»Žw°{×ñ2uú+ÿO5}Þ)º|¼[ôXjñQ2 Ò¬rùêb þ9„ûïdG›Ð©¾¦ ì¼Ü#”7Œ_WOÓ)¿"nWt÷›îޠ†LüÔd”’¢‡†@Q '"º¢V™¤ú*úé8ø,¬íõ¸ÍÅùÃížÎ¹#rˆu^ØH$Ãÿ—–,;xÂØ†×jÒž†VRsJJÚÏ­ä´Õv\Ïî9X¸OÚžâæ¦s¤ÔØþ⺅‹÷ 4otÂ0$RL»K§æé,‹ ŠdÚ›Ó¹s¨iæø›T%eøRç­& úÇ Œ/kÝxB¼På,ž¡Â<^n&߯‰¸´.p‰é:•éÓà/KJúóÒÏ«õ2ç–Ñàã+ÔÖGpsωèÀž‰õ&¥cŸ_“lrÌg1˜1ÓȤݩ¨Œý/ ÕüÂy†h›&×´]…†Ä' Û_·x»‰ÕÚŠvø38wDänûZêdñ_š9›d¯b06ÕÒºê[Oo¸[WÔfæiÈ4µùxŸrÏYNÓ§ [ÉcõÒÁ9b<T3*œMj­ H6Ü?sŽñP^}Ưx…^}øHhâúüÇ3SÙ‡øp ñ¹\ê@e&™N*@žF&ÃlníÊ›ÇË­/?1ø~¯~Áà·D$fY]îÛ~)B®Èc2 &2®îß!>¤\ƒ›ßbU&Ä` ·Ù4Ÿ®Aʬ_¥‘³"‡¨ŠŽh§:ì9ˆ‰ôÀdà[ð÷ªþxdz1E„÷Ð⌿DJÃìÅ¢j1=&mÛÂî°džð(4J(Â(ÕCz2ªJ9@ѽé8<åÔœ’€€ØÙÊ~%¸¡,Í·çó].ÊÀ6jÇ^«º%ƒÉHôÀÄV˜U¡ Úb&eüês+å’‹ÒÚj“MÁޏ“'Ÿ G;s™0‡°¼C9ðàCÁT±¸dŠò%#Ï’Æ.1m'uÏàÒS#gþ˜=Ƙìbâ.¥âÖQò‚u].gªnÆïCa,¸ÇÌmÁb€B‘Ýï¥Ü¦(I¤x s ¤{]ÞGÛª¡øGöËi0Özù:rí€Ú¥ê1V~ó{Àûú·0¥3i !–0Ó` 2¤Æ—w®¿ B jHã¨Ù¼¼Häæ½@À¸~ã <ÞEܨõŒù ™]FÄbÉKÀŠRg£|zp;ÙNœ‚]ÉÕVˆ%¡2p‹ôØ]üHÀ—P&oPe—jÕ³*áKó»Åy°©{8ÕvšWZ„16d#±ˆ¶÷ÄgÞ]Œ)X ×NQ.t´®êä¿¥³kÄ_܇¨]ÊL¤—º0ª‡SF¬Z3çº3íR˜mø3š p2‘UhôKÕÖ‹ðï¡=¯>Ïøoa|\„¤ûãŒÄSÉQ DÌ‚(Ýà@í`½¾…à½ñc`Ñt›ò™ü/`‡çÏêQ C“´æz{¼•Áe^[C€,EmäBCßQõèIž×Õ¡}ö<Ôƒ” ©˜Sy¤a[8Sƒ-ŒÝV2=ŸiÞó0ù«û‚€Ê|Ÿ¯éBÇTj(dmnÝaÓöôð°”ñhÚw%uøã¼Û@8©•`xnG|5d@‚±±]Û~H…º¶™ˆ‹§RLVWuœOã°4ƒ1ôhåõz³áÀx‡4I]ULàîEÛæ‘x”Óy¡“ÄÛ9®N›Ñ×ð1 íº›LpQsQHÔiÜ]”Øk¥ßCaÕv×-Rìl¿¥[ÔãÛ’þÊ© ±fÿš& jBm:)~NÍcLøìÄLòð®=Mñë ÝS̹ü“·Ãyg»3¥µNðöXG–ãÿTÎ6ÀÉL6\Ðý NÛ¨…/©Ri÷‚K,ƒ"%×GE9™ýD×A‰¼˜3^±ËɼÁ£ðþ¦¯jÙ½!›ê±jèEþÅû\ u}Sk Ü:kQ7ì}|ÐRGëK3ÝJa€Å®¢’€€èEÞ -ú ¼*ŽJ<í…ß³ 2)à`ŒŸ>Jre5KoT´ø!s¥Q2ãUb$É›hÖS<Üã»Ç+¢@m*9Þåæ_f.Ddîšœ]k-PFçÁl²X’ë¼0¡ R>øãˆëº$Nx×÷øë´J7ÕndÓ»š]3t˜ù%ò­Èä—C tyu±ZÉ1ƒ>9ª¤éžVtwàÎõb­O±¿æ6ú3aJVRRÿúwÒyеÿ… ¥©0{þªbªÄø¢©!on)´H¦ÊŸWyŸÚ,ÚˆŒÙ/|`ÑV:xˆÂ}:C¡¤}.H“4-õÀ0*gTô³ Å´VÀß_â|ºm¶V½tî…[ƒÒ/z›EÔž}ʬÈæ’ÇB?ÇI5i[5#¦à¾4í{\>ZüQ0ÈXDR´òä»ó©Mج­õ„„”q=ŸÜ©IEÔôou+óp*cè‚ÑþFŠÂKpÖ‡ñO1-[©×Íé™tz”‹—¬ÝYK$4« g”O¶%ÆZóýÖÞÁ%‚&[GG£2µa/r Ð’T8éôßI–Ä8Ò(7Öë+¬“™UòZ X‚çPr5&‚« Fp0âŠÛ›ÂpÁ8Këxõcdò¡ûçöëöC¢± ÖYˆ/®æ 6SQáéL" œ xL§xxM§%‰h¾Ü2Ü06óŽ^B‘KMj*ÛˆZ…qÀ¸|a]'¹rcÉ“P…ØVͨ(@|®ÕÅ «æ-,©ü"(2Ào1QuƒNò€õùý@-6ªÿÀwZL[œþ«fWlhœ}JÈâܲéªC·-ýÜ,"çæŒ.ŒºS<‰o`Ú•¡@ LÃ6>xúkÁuá¹ù“ФC'΀=Vɶ/ï±ö:«ïgdEÈ! ‡{Ð51€^©³\à SÖ™vk A ¾È¯i´:,~œXVvå/ip´sz`QZ.Â4n¼Æ'ý1KÜTj;Ó«þVXÏÛ®å¯g Ž’€€ÎC-à@ß ­™‘³1­µë¯Ê†2Å<ðùi+ÂØ@ÔWûsû$ír2õ¬85S»‘NøU hÕgâÏhÞË]R¡¨ÕcdŸ¯[-þc¿)ËÅ=/ÙaL¯.+Œ€% Ÿí¶ã!°PÄrÆý7‰±ê¼N Vî¢AeUã¶vüÓÐ?Bƒí #Ι%o¬~“€³fû0´9¦3vë«vÀZwÙlƒˆÅñå s±ÌªzJwÁ–!*z„íOÃךÔJÞOÝÝKâ^vH±kËAai–£²(¾P.!}Á%|7íÖëxnF;h³íአôH½\w¥¹W:“=F%#2øQÞËSeeužQç×í/§_j‰žîroU—ò?gz½Y…Å£¾’–,BÚ|;·ÌÄ èŸ/wå&Ð…CI#÷R#Ÿ¬zõ\*ctð{¢s±Ø6\ЮC›€ÛÛ·ÑM N1Ð5.±¦hF±Ÿ ÖñÒ„²ºTD ã4»g1…PØç´{ù‚|À}ÐëÐ*nž{U§TרS98¡|¿cu;‘té|R¥öcÎ>ùà@Šº lBËïÅÀFOE†sݲPÁõí…ú´þ RQðˆv…¹¦¥.¦©ÊêÌR?õ „ÏIÁ¸°²i;g ¡þ®¥ŒSND1Œ©KÝe·emíT!b‚´—e…‚õ§0a^©è¨Õ€•eãh3Ž÷^tù[Ÿ‚øåLºÌNòÞRC¹C LÙ½·?Šñ‰²ØâHßãÉÄZ@ú~܇0}?žD£ÔˆôBZÒÖt-ÁjŽg Êo¯ó¸R:ì±ÏTe“jûÁ;Ù ìÐU1™ÌYº€¾)étåýâ#Ñæ²¸éç[·?xÄÜ^=*ør7²‡þÓ›N”õ®’gÎÁeÝSèà+ëž!•êjm@”LÌ)ÉfY–ú‘m.òíLyÐðI' ? ißn>]¬-¯—‹Ç.Òn$ÔÊkÅ÷ÒĪÊõ|Fu»D›ŸÈ…«;ÜRî5wÓq8Ë×íqdÆ€9<&Ö mº¿ pfö¹¼IÈ¢YJ=ßâ£oÅnÔš[´(µ¸ê‚“gál…wg.¾‰OO_CÝ;Ö½ÿKA8V\Ù†ßqàkQSvì±âZ(E’€€âí+Cðœd·v‰ Ç”ÉyâˆHÂj[àüÊ èÁ}¹fŒ½wšëF·…Òî_˜&É&iß–¿«euü QjÌÍêxbžŽa ´tÌú†ù<ÍÓ`Jz¸pFärhzµrÌïÓÀ÷«ÿcíVKÕ€Iß䓬ÿq$Ó…šuxÒÿ€‰c¹E+¹}[£Eì±D`Ìô‡î¸Îq½‡p 6¿‚‚¦´ ou>T)=‡H û:ЖNä|b?Ô½“Û‰ëc{Ïu¢†:á@ÍWr¯NIöDz}Þ $ÄòA2bqðhù3q,&Î_¶<·z6o Ñù^Dü»ºîŽ€Õ+ÎtçŒîÃ,p¾ÇˆÐ+ú+dÂXøH°s%ç’úà èípŸàìÄW+Í“ÕÛÈÊW#°t±ÚégRí_à}a¶†Ú³+úÿc¤ëÐ4ÑóñÐ{× ÷ò:`¿ü˜ßv‚®á™*ßíØˆ›Ó”#ÀèTa ÖvkåD]—UÜv>él IVTÞðÌø‡ûGér£þ˜=æÙý’ÁS~¤gt•ªë@­BØÅˆ×B[þê&» ´K)óÇÅã$œC8ÌÙu˜Ì,ï/¶w„×Êóƺxm‡€5{ûÓ1PMqo•Á±Ü†~¼"bžÖýÅ4Èv¥þÖ¼ê¯xû`–µ¬ Sa ì4VêíUí†ö¼ì*“8Z¥Tð ÕÞHeÊèžû[çICønDh¶[bwÀÝH§ù IR|LÃZ°Ñ¸)î( —&¥µuIÊ$JÅçIgÆnt¯°¿DùT¨Zsãòó”€&Çj)¥ã –O~„ؤ‡G K»¼·K‘¥³z™@Sp@:£<#sæÛQ/Go­Gð*"Hò¥bãY‘s³LSOR12uVµÞ)÷·wË"ýɆ’Ž4DÉâ±\çEáÜ~$z´±z=*ƒJ£…õŽßGïÿ"­%P¬¹É_>öoy0›ƒqIX·ùcN~h]-‰RÒñÁ#Þ¾“µ8ò²Õ¿¾ÈÙ ÝÜ,vÈ/úlJÓîÂwÖLH=î¤.c¼s/ TÐyüÔé¡n[Ù& $áåÖ°€! º hãÈZYb À,/dDºù>Ï%·xìÈèAÈ1ÐHœ‚Ñ¥.D’€€–UÎÆÀFÁöüX©:ƒØÑW7͇Ë|«Ä~mÛ’Ƚđ¬ßûë‹ÑÒD5³a”ÃãVy~úY¨Qšª Çȶýd’{@n©€˜8iäë–#—+KœÊ%Q™jxÏ 9Ö\ô ˆ;¥`R z>•’¸óB‘¿j‘°ûÊ/ßQÙxÙ ' ~¸Àƒj‡A¡§¡ž\ŒƒqXVO¸ªèn#ç¢ 3I±:um‰tÊ‚BP ƒØ QE5ï]Áa´°önàpµ’cåå{§)ªòD^‰ Y6¹å€V¢ÔÂ$¡KY2d§ösБ*ðU9MÈQÛ5Ü–‚b/ ú_®ŒŽŒºëz|+g¿Øð#jhibq‡«RPÞ¬ÞnQ%€úë’gq}Aø0œ0Uîlâåçöe¿ÛOÝIÃÜB9Ù¡®äQ¼ãóŒÇ]œ_ë•,ç.5jp9ä!l°U&‘»ž{AÈ¨Ô À¾\æHx Ô™Hs é zÛ$.A›9?4éãÆó0ý…¨z\™Ò0£åïÄM?wE¥Z ÷™š(æÌôV)D,Eýšé·l’€€«û¨A5#gÛ¸ør§XK# L³ð–ßUl;ù~™¤â y Û[N‚š´ÙâA/]ˆGN({}£ýbç.9ÍvaÅŽ8Ϧ®ËyÕÃv ØŽO´#­ˆ¼ýÖgüÎ"Có¢ž ÎtËó*#HÑÐÔ$Eáï5jÀ{<ìäâƒ!—ÆÉäâˆâïN]!’éxA2¨1µ‡:Î åêü`’YE&£"´Y~CFQHIVÂêú½žXºŠyâž#V¤wšdÂ;7ž¸¾Í_µ! @O{DŠÐ0Ùœ–¿Kºù€…®~Tcìv˜»Ãþ÷9BÖÞª{0#q‡ª£»& 8û\»TQ‹DÓTÔJ¿ˆåwüþBIwPðû5O|ÒÌZç‚ýZ¾ÆW( ³à¡YBNrW MzÄYÍ.qצ—«÷Ësƒ– òÍÜT?SvŒHD Бê?z¯Üà+k¤”çOèi—æ‹t5¥¹WuBýWq„oCk+glû¡Ó›Cãap bë‘N\Ñé,-MˆÅÅÉÕ„CBôöÐ[ô¢ïnD`¶éňS#VŒei¼Z`²X‚1[yü cà‘©Ég©Ø¢óyª«ŸjnËèS2Q9“Íã'kÎÁÐ6âÍx‚ö|±&Ý;âr=zN¹ëKÍ0€³ÐW<&ÙQ(­ÛvHôô ÙjA©HåµY޳T.´\®}AI±|í.ÉòÀÁ’ólÕN·ß*$Xn%š³;¥%0°—ìd4Yòú@¬õ¬¸‚¹kÏÝÍEë =7+<®xÎ1.ð‘ÂË}A“±–7_ÏØ}ÝÄ›LIÏ‚}>gÙ‰aÜK¡3$P›¦ÀÌXb¨¨¤ëreí{šŠ¦2ØBð4ÞôPÄÈe.]“d 8¯xW1Aš*++q¡HÀ ¦gœ™ÈÀ£Z +nLM¤Õh\6PM[`2þ‹š}¹r¬Ëc{̬ú]ÔP€Þp2N­Aíô'Ùÿ"ÓGð’€€¹ ñ¦Îô¯VÞº ;rÖjØ6Ÿ±·x°’V g>•ô-{ì€û¸'•D“2ã‡óú FS¤º‹Pä¹F¾3ÊD7.óÈÎì&ðõ3ªÀPFáä?ª_)ç !±Ü_D¯ÜÏçL3´¸8(ÆŽõ–ÕøíLþ, Ã1™NVñ&@R„ì@sl®®g" ¬‚-\²‹2*d ´9éxËéx]ÁÉøa¨+°Fcool‰-äz¶NiSbר1ȨžCyŽƒ/cnÄxR­ôÚÀ½ÜŽ¿þ"qáHü‰tê~^m*–Á`Të€íô¾ï»ƒ‡¡˜bò\)Ïc@kDì1‡ãQµLsx¢­+° Ký."½<Ùå×´Aþ\·ŽºÞ“0É4½eÄ þÚk=5'{ã6®s˽ÅVA8«»ºY[>–É^ĬEÙûv}ÐÇ'@²ó&³¨a:Ù‰½½ @*Ñ¥}˜mÃÔ÷¯{û½1ßw³mC7ì—ŒKØÏ*5n Ø;#w@ì¬ÈkRöÕ£_å‹Ù»y²€?7M9cQˆ~`á‰2Åþ£¡jÏ…‡ ©‰É¡¥ˆ_¦&&o?)^JÆÁ Þµ,”³R‘kù𤴷€nc£¾Iz­ûªaî3p*yLhn¿é‹^OÛ¼z³Òb\${cؽwªWH*ý\êئτ,ÂÉ"ü&(½¡|ŸR)µèŽ[ŠŸ6ù& ø°”å²í†º˯Ë="•9…æå¥È‘‰$1Õï&DûÀŒØ¾„ÎóC,çò¥sÓÁ+Íñ æ(´\­ïA.ËSªAÊÖѺö&*PVñLÂ'øÖ¦¸A*¸túüò+Óë0‰Ë-"¶ct4õA'|ÍÏÄÝêc<º²ðà¡sÕgT½÷î˜Õ®¢Þàsq?0°][cÑœü“±dK[‹Ú¼Ø¹²"Ø’m‹So2%iL±Râl½¾zn=MRÞZ@¿§ìke™#þæQ@«ÄóÕœï¬âð›m*T†c­B¹(àFD+Å:Êù1Ùsõbý¦À¡†·:ÉV¢\/~r­[2mn¶®;­#eÓ~‡€ÓT=B„$Ù„Z_üÖ¤ó!«ÉL™ÊÚÛK€wÛЊ,!Û= dÚÕÔg•’€€ªþ \ëÞ§ËõÂè °¬á¤ZZ m‘*Øz,á-¾nÏgJ&¤=ˆCOøÂë+>¤¢xÚðêr°ñE,D¶!ÚIžl™¯|Ù± °Ë HÖ·û‹=™Ú9qUû \dÖóîçÔ±­Ýù/­HÛ«%:¤ Ò½?÷̈£Ó¬ns{oƒåpfi“¾û­q¼êOd {žÁI7@²?k§]×Gþ ¸LŒd5ïô”á€S=€7»he{D"=Ù¸Ètgñ×mB#ÞPÚ¬V³3êä k—ØF†TÓ.¸cðjèô­:Ÿäoø¹"ò°¥ÞûHAܯÍ r#…G/÷¹â÷v¢‘݉€B1?µ‡—ÞBdvžsÿÍîßN}:þŸ>ìŒlÔå‚ NQ 0Æ Éüdpü¤ITâdH[Ûg8×Õ†Ùg<¯.ÉiDñnýßÜô!ÿ'©®jXèL/=FX¸À º·ÇH.ŠÝ(¼çßÅÅz£6*<ˉ{é ,À(]nfõì}qýȽ7ßé¢"ÖÌÛÉÒÝZfZÆ,Ãñ‘¹¹j{¦TÕç×Å}o–Ú?šG: _)d*'ÖDÍîØú¡~´5S—„\£e«¿ÇŽŽÕ=­å&ÚuÔgÅeT!¿Šl,Çr“’ × ¹ßçQMW‹=¿eHÏT.¿Ëqõö\OêåG§ÙÄ}ooÛ¼¬'¥¾0)«x s¦=á±wk¹Õ8›wc»¥y*ÛºÂÑÊžpDÇ^ëÀ˜Ÿ)é@•¯ ‰Y· LwLŒîA°2€WQÙ;iñÕ0t3úr ‹[ËzÕýºý†ÙË™¿›;Úª´MùéØŸdã£ð–íñoånsÜ¿b1Iа¶KÓèÜÅœÖö$=ÚÿÓäcõ°(ñ>æã«?í>g™ªœ:±–*†É;¿Z ‹^–þOÁ2˜ý…þŠÊ%y ù Ô¸ðЍ?–ôjAóø9Íœd$KòÉΨë{Ö?·[Àf¯•eŽa7Ä;.ø¤M&è»»9«+Ï\“kdߊýJt'(1;gzùؤ  ‰ç¹îŸÚe—yVX/ÈsáDù­d|(I™öØ¥þ§$ƒÉ YU– ”úÂt1ßÔ‡SO:HFþË’€€®µ1‡îìÀúi¾š¾¯FÌ ÆgûzŸ>§ð ÈE ›Þöø0HÛSâ+ÐÕuNƒïB®³¿vRžo*ráY¿Õ~Çœ6Æ›ÙÝTm÷bÁAý—Œç]8º5¼¾Ö'>æÒ‰0Ü6q¾QÎ<"‹:QǼ)_Ó¿2Ò8(Êm.£ó+ȳán¼~#rðFæ&z\ÀŒàи¥&×ßï4™ãÇ®7ò1×àùäJáiÇt¹Ží°½&¸YDî$i2wÑÅýØ•†vMx°šW®½Ïî–ðŒÃ@¤È&Ì\EøšD;Æ'F§o†×ìl[='Ä£.a·b~jNÛ3)B”ø´êéÈÜùÉ.W Ä›½£ÒðÕ¾›‚ðKóÃE`½æN@“œ+#MØThƒjlÓ§¬ÐÐd0n“†ñ«†ýe8ô¥¥Hœë&â?skbs®`ç´;¼#›€ØÑ€ð ïÁÞß˧}qÇÊò5{9ðÓR`¸Ù’‚Q•"j¼õ‘‰$K5©,N˜"õ˜EFôÔÿb¿ ;6øt2¼éZŠËøülY{sMlD½õ8cS>¶#”ùx º~Ú@5Óµ»»ØSY•êå`œ@Åü‡Vʳ4ât%—‚ÿ^“Žþ£p Fá ~AßèÕ|Ððø¢·ƒËwhh‰ðSÀYÁ£ãΚpðìOË·Ö–<^úWÝHùbÕâ’˜”çX‡õÎÚÏr[bð9¸,U9˜À¹qäímîØ€S=ðH·wÎÐÄ!ãÓ É~óÓÜ—r2ïvRíP”gú°Î7‰Áhl—;r*,IרjRFp}— ýS6:Â6øø)ÐòÃaNVÏ(ïžñ5îš#•u¡ÿD·~EbêoœE?ixX‡Þ{ËkösšnÏo†’˜uIÖ$—ÑßÎbkÀ ‡5³ ¯œZ.‹ƒ?÷$\¥°»ÎŒ ¯¯)jÔx À¢”†(Co·^ (ô˜¤5”±WágXÿ¼$»î-•HÉ1ï KŸ÷^Ë’…"ÿ˜²&½Èõ¢ ¨šÖÍú×ø]Ò³-’ö+«Ä”Žö´ÕEõ ‰ðX^40¯#Y,= Ó¯Š;9ÁÇc-m§\1“Ùø­X,Ìì²çyµÕGí[^´Šã`&=hDoO[A§ »Aœ•Ê>e±ÿ‹BYÅ%j¦•Fc Ч‚f=ˆŸfÛü/¹Xúj™çûí ¦cðœ.2:jÙ2!u×Ôåg ù9äý˜ý÷QÑ~>€cjª·Ó) ÐÜ!{±•_†”[!.e6ÆÏãÊçÊ"½È¦]q’€°PJ¤—@M;u¨æëˆ†Fžo)qG²­ Ô¡þSݵ2ëˆê¥ä½%Þ'»PyN¯ÐB š¥ñaøç  Â•go?cHïUzÙfaw¸²,Çí˜:bøšT²‘î9¹¹Qí·1ijúaád9Kíä·¨2€i“ý¡<‰³E¬BòèuýŸ\}R Ê®NŠÒžgi¢Ðmm¤Mæž–Ø-ÝûMauðã³,ÌÓ 7?@`àjcS‚P ‰0e4R’+É·Zé§ôhe2iØLFúX¼ˆÔ>js„:@¢–€½x®§T kµþ þ”Lèð¢¼X&cø‰ŒŽ´cZQàâI‡H£õðÝüù Œ÷A72¾\Ê,p;p|à ƒ,´E¼G[0@ãœ} ZN˜†¿[m¦e¯«ñŽMâ3;‘’€€éU®¾6‚ZÇNÜNˆ«²ÿô9-ìWhüY `…biñêÿ_ØÅÂ^ÒrüMíßÝ3`ÆL‡‹Y£€>‚;1EYVªÂ{C5É&ò`ˆ'=’Ù|̤¦9Y«oAlækgh–O“تÞú5#¶l£øÄ9.¼0õº½xûlCª{ÔÜ´ÀKÕóŠ œÂÃ1=eÜ„äÓ±9¤ÅÜ—ç£oûÁ‘Ć3¾Ãõ‰Œ“Û äìË1ÍŸ…:Þ¼+_:¯²Ü‹R=£å¿)Ð<ߩІëWÎh»À1L`3± D?Úo4paM÷Yâ_Mê;îÌ‹l&–#_4×ÒR?ÖÀÒ7y `ªÓLpÛ ¾Ï6íè­Ö$Þ†âš:Š3¼3ÈšU§à¡SåfòCMžj,´-wIàT ’AlŒ}× Lüz.#NÊžç²Þ“¥;ßX ¤t:‡]daú™§!È, væô_ª(Eƒ…²úOúNMýWð8Œÿ=[ëæÛ[J G¹â÷…T­¿IƒgÊ£ˆøí›dBQ˜XHD¤ ŠÓ¸@b¢f8ÇŠ;VSôle*ƒú£@¥–\‡¯5Öïéj¨{õc˜%¸rý/Z§…k’ï_Oë43Žïú|Y¨A÷M^" B)éþ1Q(ÉôÎ&Ö“§YwjHψ¹RüŠŠ÷êRS% m;ËK>ÄÛ¥Ò´xÔ&𯷓 †-Š`˜ž²`?®#=ŒÉð®¶ì¿—)ôÏ_©å‚mFŸÐÁKÖ š*!–œGHåþ/­' Õaáœ;cCëwåí·´¢˜¹ ôKZ«ñèÄv-àѸiƒ¡$åþl ËãtbÖŒÛ[åÊo¯:g6]”•a ]ïüböƒëÈ)¹z¡—“ Çáâj;ƒ|m­y£,µª.9ä÷RÝØÞpŽF£è”OaoL“{@VêTSu©Þ‘¡œŠÈÙ+pÓy «¼iK$]"çû,I£;£à¥qcU¸µ 2^®Çf1^@­…6Zþ`«,“nÍ­<€±žæˆÌÚ“¯:Êô%/8–ñ° #ÁïZ/ɳLÞððóNü9êf«=|1ƒ‘®‰¨¸™é(DÙü©ºþÊÏC‚õy™Åóªw¡t€W¦"…T×\Ô£€| †« ìâ‹·@Û˜= L ¼øRhr–©yÑ ªUÃúmáf+Ø1Ò–n¼‚0«áÀì£6}ì“È©<¤+N”OC™P~ “­pý%ðÚ£‰‚¹§:it*ïÍYÅFä½°¬Gúõ^#ÿF Äl27@Ì‹‡0@n¢hnžYg|M0(à2Ã}ÑX¢Ó—ì×°õ ‡ˆå Û™i|2›Dêݦ֓-ȰºNÛèiPWôë‚(¶2³íaò\'8L—XEضTéS+%€†½Q˜f“lJ%Lñ=œ‡\æƒÎ¥i["ýÚÎÐ^+g[£cQ’@sûP—³ú{‚~‚þ 4³²$À#SšµÈšlÖ†äÉ´`#èY3ÂÝ—gOEß^}Õ§M d¼L{­P=ॠnæùÀ­çÒäpûÇÍÐÅ èeP"ÍûØäÛÈ꺯9þÝØÜ¸òÌ~ÕL©huÑs2jËu« ·Ô‰‘؆ÁÕõ³¶jk(“»(ѽpÝô[£œÃÝ^¶}K«»GøÈ(È_çê“J íÓ¦Iü[7¸TÛ‹*)S¬ÛTo;pE–’€€®á…AZÔn‘õ½“‹ôäa›Ô:{Áú\1c{f¶˜%)JSPyX<\&(^’ëqçsy…+} Ã×ÈŽZÝò.h£õ¿‘`ïfÿ”ý$«Oõÿ=ñLï2U\]òÇ®ÜÃYñáFT_e”_öR¸ÄAÍki8`³‰bÍÇp2Eë—Œ4yg æIXžyaQ~ž'p.ˆeŒß¿AŒ4ë¹Wíæà5 ðÄýŸ:E}œt]ޱrMVƒBde3ï6¦d1C6Me+ÄUê²KŒayð¦[5¢@Òâ²08€Á»Ía…kM6øq·””gt„%t+W$u¹Ó›ðƒF[…!ÁæÖL·ÕãÄ;lÃë ïëÿÌo$RÝ/ÇÖ¯Ø,õ qÈþô}–—`ŒìqØZ>¬ÌùÑ‘î§gqädßÚ-Ø’ܹ @€ð¡þ‘–%ŸuHð R Ÿ'‘6ö‘)Δ × 2e¹Ø÷¿½Î³%–VÁ’=°™x!_‡‹b3ˆÅ·AnRðÃÍÃhܳ/ÞeÛÉîÅÙ—X\æFt›Ù¨Á-±M£a—D{Ð\•~½@úî°»A5€ÑÌîæH8DøÁjñ6湊õ ¿DgúÚïÉu¶“µ‰Cs+ÎQ>Zi§×óÆæ ªíÑ;pÀ¯ß¼â¯Dˆ›„AÈâ %ÖHKu!kçeï·P]%ˆ°"l‹iúQiÒÚ¨ÒÍͺå~ùÜÁ<Û$c"Ĭýö›€¼¿­$HÀ 8ÐÐ}:Èd²’Öûú¾äî§V‹Y— ’°EjÈÍûï’3õ ˆB%a.4ðkÏOç7”ºIB͆ms®ðMB ÿlÔr€‚¤q Õ­«¯’†:}ÎN‰8ª:bŽ ÌØì‚Dœ'0D5þÓ¡¤² 4ðôÈô[zoááþ—7ûQ²M- äë»Ì“Ý™«Î±,4߬H[öÆ2µ®Ýšàå<× )í™O)¢‘!ø_Âüù4”CÁÕÔJ`Ò#²àpƒ>/tà“ÅRzkQÇFÝ­pÖ#3ùsýc|µ ÎqQ4<½y‘‚ §>Åd˜ìF¿ÐçÚ‹M']³’&áðgÌ­àdKL +nŸZ°ª#30„ëz)µô= &qf³˜’€€Í”¶ìÀólÈK0:3ŒÙ%¨VO¥vòEŽÏ»×&m•Ç µ…µT²´±©Âél#ôcc±ð†rK¥~Ôf*DÛ[ŽL*3¿F1«ÐòZéÒ׉®NÊÅ€¾jSüv­±´åLãWPÀ^#ß:D«/Û¨º#HŒHn–ßüz{Ê4%°㑼6š,‚ $¯žH a)õLɘu¨ ‡–  £ç#é4Ç–,`GFÝOùC<² @ZÈû8´|e¤PÝ–Í/6"'O¡ nŒô/³(ÙA‚ŒNpÐóvÿ¿R8ºb¸âB‹MR*º KG9Y-2ÕLoÌ)Æ5 ÏìIB[cŠßùJº+@æ*ƒ©p·”€'_÷"iá_Ÿšúh<ÿMi—ó²âÉ1Ï¥ºo”e2º$ÁhÞ:ͺHlë­iʹ•¹Ï O›N®Ú­ ³x‰¹3Çš¶ú»_2JŒ®ƒ×Í`úøÅ‰Äsé&m)¥°*ŸªÉµÞáEƪ65×ÂÔļFÆ€ÒbÍuã‘ͬó"vÛ|‹®+7O«Åðr’šü§Vª‡Lù7º09Ñ÷5¸Ì´,_¨(ŠEä½Ù÷®¾Î2âEPsª²Ð¦?IŽÝµ6šK.Ñ»~Ôêqùõ¥¾µ–ô?§ñ*<§~®pþž%³JtÏü-ž¢w¦k¸Ýþû©-µ½qÔØÒ“ØåÂY[ø®fklfÁnþ³QÃE»ft §¥‚Î:ŽÜÌ!°·¿ù›æ³ã3¥iŽREr³­7Ö×e“öÜ3Mú·ÿM1ÒŒ…Çû†GŸn8¦v"Êq Ü@³•×"Óhøty‚Åü{¦_gŒÏqm4Þƒž7 ÕÙ,çä!‡ì¶gâ9óž‘QU.p㚘õ+ç]:¾ý`Ÿ`óI34ªÅ÷,Ò“ä„íºvÍôäK™Ùõ)Tôp-Òa#‰ìŠ KÆÝŸ~âà~êÜc@©(¾JõV]W"5g™x'¿£—­iÕ§)qœ£Ì¯v„CRÖP8M ͧƫµÔk„8£éÎß WXïN‰¨)‘Y$ãá°Œª=S=rm.jz)Ñ.Ø!†öðF²çKéOºû†¼B ; Ï6É»¯~ù’€€ù,ôÜ'Ÿsb>7¸s­ "ÛÇ–'ÕKUá¤ËŒÄ›”©T].Ñ}ûÊÏT@-‹®ƒ=¯¬v³ßÄ@츕Èà£Ù©…¹úÛb¨®Š‹Xm5Ïy=òȽ(ݾ|`PÓòQ 8lùÀ"Ÿáyºyy¼_Nžsû‰ÎÔC=åýYE±ö3€­Aá¯ÍÖs>„S‘tÕìÃÛr#z‡ŒëÛRÝNqâHègj­° 4Ù™E†^Ñ)EvQÉ$¹„''> ÂXts+iCýÕ:€’o(>»Š‹Rö¯Â@"N¡8È‚Ïï÷.Tí®f¯ø•úôƒDÝIªø¾4œ™7vÔBÀ„£šy0{ƒŒ€˜7;ÙY%p`ˆ4/t[?±á†™L·ŠÑ|L)NÓw©3ÆŸvº“w]±ª½'aøŽõ›¤'ÐŒdh§šß]­Å”ɽ9‚RwdD¾“ÝÙ¿6 _×’p3 ñ27DJ^Î ÒÂ) ÀËŒZ³­=åhê©fð¡j%g Gæ8¨+äø’sp3á‰U± y€Ýw7«;®qAkwàðÙ+Šà}‘ñý¼"³t°µš5œmz½€Õ¯´½›šŒW£Õ3i•Ć1ôšèN’;\Ö4 nM®íøäF\O€ò°ÁüîçZÓ¡±õ˜ÔªÝ”·ÃwÂVÞÌ\D¤#¨á"ÁÅ{RœF U ~ûCàÙl;DªAÛù0‚…¿‰Aî€Y£ÃáÚ..‘ ¥j¨™š¥nÝJ(*KvO•V~À¼Û–@rR¬+8ÐÊ¢W—&ïæ2–Ý€>ëËá¡uáœ[^é›;¯ü1ƒ\±adªº´øqSÑíÉçÅuéº#<£ü ±ÿéO-G‹²³ûµ´ŽÅêeø›"ñ ¦çÌᥖԈ"ná“Æ8*ÄzYG©ÿ9doªÉiM¥!vV¨Òn¦è¸ ÝŸ4a1Õcî)M¾J*˜nñ•+*ànÙ’Gm †ïeØöyAM[€öÅ·áñíûbûÞý? 5õ¡ìÁ£@²x<‡ȯüD=íÜÑÏÑŽ”¦¼µÜ`ÞŽ9MéY»G%¿Èow(3§žâ6$¸‰I÷>’Ùq,µ û$rÏ?ÁÀBï…ë Ål”ïj¿ÏZê*WÞ®c‹™’€€£¨#G«ñ5‘NX.c†S%‚“ŸQ‹ãSwp>ÉviƒÍd ?NH¢ØY6ò‰·ßØáúW¦³¥ÁþÃ)âž3ß‚Ç)¬¢D|—²÷µ~J~EP¬gƒEâb|>'‡×çFŠø´‡ÿœ~=24ySw o?•a‡aæ_z—öEòTaQÅVV¡3ì¬ìu¦u‰Lõ&ýLØkšiè"ðDÌÄ'žŽø»JÞÜœYÚ¾Zw´Fò wùS&”ÐJÜKƒ2~Ó=ޤåJ¸ ®â(C3;ÍüÚ£¶öRð[ˆBkä@X)Î#©•P8ìαë@\ø=æÃ 9ûØ´?lZ+¸L3F‰½¹&¯TÅA}¨u;ÐØ HmAvŸ.¸…Ó?ij¤ò"ê߃óeÇ2]Ý|ІޘxË+pLmF’eð4Ås†â–3AN¾/ùÞ‚®LIÔnˆt‰›®½ƒ:,2µùäLA™—%!ªýñJ@êDo­¬Þ¿ìÁu,r ©Û4ÝµŽ••ëp`bÛ.M5d÷D¯VêÐv¯±‹iÅûgÅ FÀ"Z¹ Ðš­v†zÞ¸u‚H~n=d˜Y±Î¹¯8(mD¯—9Gµ_&k«JxÑÃGr­ò׿Ú;€…ŠT4á ãUýà?²j4!8×ϸéEÒÏd¼Ae¤%û‚ÀX%µÖÊUrdý-ø|Ò÷Q´ùÑqœþâñ %á,cÿÁ·V€úB  ÷)‹}êjµ=QÌu ×¸íßcŽs± ÄþõkµÜBÉË!™w4ÛzySòäU‰Æ½^æóm$TÒAæ´YÒr4ß•â5Ê<´.º0&| å´éì+ÞÒà¢[ç{ŸcÊUÜb Aa„€ŸÆæKàþM5EÙµ{è¦Bê8—˜‚(Çý×! —>ÞÔ5L_.¬KöÔ£>cÀ \.aÒFÙrRó•,mÒë­F7õKœ›ºÞX¹ ìªt‰kÙ‚÷¯ùæUö¥7øª¬7¥=j‡«›RüŠxL¥~è»/Ÿüòîþ âË{¿H~2ñ´õ ç¹ÂþCúêj.h“×lpð"œ¼Yv D[÷ ð>αp?ÅR¡‡¬#nÞ'PóBµä’€€¹—[»å'ÀJÊ«ñ+¯Ô®8RU /%H .ŽTÞ´â~v»~¨}µCÇ Ç^C”ëe-ÿJ/$ruù^Ku¬=ÍAƒWœu˜§RZ.h–‹­ëÑí¨ÊzNvNï·ÕA²ïýàÙ ôX¯¹ʪùY;f)Ü:QëÎF=ŠqD°#gÐa.ò}ÉL>+Ƈöd²ê Sè6ÕL_ùA²î%ŸŒÇªR39µ·4]ƒÅþêç¼ñ¡I*À$=Γü“?XLÕûÒ}{Nݰïî‹wD—»B"‡iÖÇl¸¿(?&")~7rÄ€r¬>F,>^(BDBÚíj‹F[¥$µ"ÄÑ깤ÊÉ+(æ…ý êÛû«‹6{ÿ×f2» =ˆ‚ì*.åTFÜ‹íjÕÅ3rIýšdLîÁ|œm¸ö01b+ÐÆû¨3V§‘]@Içë<#z­§>ë àL8¹ljŒMãÚ ø1“)T£…Y{s•Æmݯ/5ôí] øíÃñož‡»ié -Èmj òûcq2:B'ò-|”©ïÇ>NBhlXŸœ# AR"`!ÍZ¥>F¾:4þKÔ%°N%„‰GJ< þvõ>09=^ V‹xì£eKh¶3Έµ a;½,òŒ„ÓýÑŠ%ÅzaA YïÒ¡í†ñ˜ð¢sÏ3Sì.O9”?j[M±gÁÃ1RÅ…­u¡‹ñØxV ˆfW›Ü]G ÃÍÑåæ;¯Ë2šYº¼h¤y?b{[’чÐyIÕÍŸ’›4DW”Üœ 2á ZÜ8û®S#}=Pwž 0)©[¥Àš˜\sÝI0ìØ¿Æ;2Ú§ÅÅ¥v¥ÖýN£ðõ®*8÷ R)µ«,ÐÑ÷©Ÿ=?剶Dœë½•´­ÙÙü é$«@¦ú«!oëo;Ó»7åQÛ¶P™©Ê;q®:­˜d†a6=P.~6Jêµ¾¬{ÐX”&ó\ÍÂ-M†ðfÁ[ýepXÝûwWiÒà`ÏéšúÌö¸Â3«Â%#¹âÆõcQlÌSxtƦڤ¦{ÅÞãíäXFÏ&'‹¹t¯Vå¶Ù8ЦP¡ÝõÀL²Tx±ô ¿ó‡±ddµës)ˆI( Z=èÙëŽ1§ÅK'+ ø­Ð[AnM7"°…]¬’€€áà(ÿæKæ.ï,’>GqþÙ`ùªÒïp·ïBŠ´¨¿¹xiÅQ(1ÕeM§5´'ËÏ¥ŽÏ|i0Àÿ¹£†Ð2· ÿÆ+æ5é Ÿ ˜vå@£¬jê2z@ÁÑ&@·²Î֡Ⱦ»<º2û6æKb AW8žûNumàSÁíɳJä,m8èð(õ¥öcN?œ•YCqƒÐѨkX´­±Ú‹p¹Y;=Qdω¬ve*b‡[ ±naÜ[€ÀNoûl¿lç ©²íâ¾9;01– â$2ù& Fæê!œ6 >z×ÕëWMñÐÉûªOÊŒz´Zå3ƒ:Ùä¤éO:óÝ5,M'dˆg~˜ítCžÑèvô ÒŽ”ã(µûåië õ,~H¥Ëõ;×x(ðõåó,oÿ_Å–_OÕ8'¿ý–šÚ»¾IÏ^hEùK à{Ršï\ ‰JnÍ#ïP‰w”ɯ½š]TM£yh*9Ðï‡ïwÓ0ùåMžàqnq|v¬©ÆÄkòŠ[ð•øCÆJåƒ> ¾ºåå£ð¾#^¸n,¿'ýª9\dY9.ˆ=r@Ò:ËsY•FÚ=ô6¦f¾ï½iHïâUI@ý)3zÐ<Ï_ÃHW%k”=ÈÙßñjÆ‹wDT ÿðÿcvÉtÂγ…ñÿ9Lç2¼7=¾)Ûtzhî´qSÌÏ;õÞU9*Ø?BH'˜]5çhã5Þk\,ˆ óZË×ÊëQµc]ëÀ RBÎ!ËÈãàÒ†i? ’°ÎeYq9›³™¹g¤±¦ØëjnËsñ´ÄÎîÍç‚íÎÝÊWó=â›rð°ö©É9âãµ9õZ`=nÃ{`8Q³T"Ë$Š Ÿíƒdç‰Óò/5;ï€3Ý6.áϸ~µÓˆróuŸz=¹ `ìÒÆ—‚µsÑÈŸ†´I8·&à‡6jÊ íJøØP{‚òZ†™ÕtÐðÓäóµ{N„Ý uËOçàj9/2ßs"óÅ1^F-) ’pW¬¬6cÌ蔪O ¢ÞE°øÃ.ÏÒriUá=š{¿ÕF<ïœË]ƒýA̳ҚÀµ@ë¼ôÒï†W>zè‰Q¨ä8îò_é…  T‡¼ž®3L×´>÷€«º­_Mj>6ns"ú—ݽÏa"BiÇ’€€ª¬iãþYKáÇt:Ž)F¹¥Pu–g~\ŠÞ>‘ =3ïwØi€$‹,–x쎭A\+0Q‚‡eÓO%åœJ"Ušî–µõö ÕÛV>ðÎcs"Ôa*ìfT ñ†[…¢9ñ˜r´+ŸÕj>Ÿ•¾Âî½èvSòªAe ä“I´+åýð6¤ò)ݳj»;t|”‡i† šøxÿ™Š'ÄBÌZ´§ÚÓCGZý>Ꞩ髗&Ê"ËѽCË0x`ŽÌ„†`z‹ T܊ĺ{~Ó%áÆÈém9òz/íÑžt¼c1^ÿ둽 ÞÙ_Øìþ'™?¶I9DÎÎoêô'à'çÏq Äs)ª&n&%ñêuàIžH£ §À]6N.–XëUîsŒãä&9wôP]OD‘½ëºom›Tt“$E=F¦¶”ÖD·W™Þ°ÜVË53F ßk“îY† c§ïé¿Eº„© šõJf8g]§JœØ§ühù¼‹0¢(Ö¡}Î}‹yqõü6T= ŸÏäaYÑ™x¤€´ß_ñ6žõw,µÞ#« ™”© ¨*îr‘LOâeª¨ €c‚RŸ9« /™6Ìjó ‰%Æ^⎶ƒ°r,IÅ×TMQê?·•è y²’´½–‰ÜIÒŽí¡7!¾‡$¡}zþ³ çgY>VÃEÍÓº±AùEH‚"‰®®õn®!_šáË›˜ÐˆÊMØa¯ÉÓªíXr,&¶ó"9ýCotc¨fÉÈwI÷9E˜‘èåÔ÷¬Pôù¸¹8d-­¹v·¥‘YžÂÂ× úsûêú൅¿ÆW†¾}´S¢2´¤ŒÖâ³ÿ7j%É>™VêÈÎ팲c¬ogTŽîIMp:mÜ} Õ`¦[°ºcðKÿRGK£kgTÈÌ-Ò,ëÑùœ\xÅ@ŽžL,¯PµèǸɆ*è¬Û‘°1°ù·(‘£µÏ­U8õcCá.óÎÒÖR™Ûï³4…ðtψ–ðDåÚÍÐQ0òG84ÂJŰÏ´4´î*î9¿õu•G0|µ°š÷ʲ2󽮈T¹Íçr¤Ô_F7wŽD%ülê:˜ˆÛúnì>žc¬pgËtÀ¡]ö!°£â‰_”¢Žb$ýøøÀjeI/§Y[¬X@zaÑñ’€€¥lÚÏsQgi¸â=r/½›¶p€ñWG÷ŠáÒ©W±LÚAÙTOÔ«²…‰6¥½ Ýý}[n‡® Ítà¢(á™N+âõù\8æ:L+L‚*ÆÓZ–0æêÂø@ÕS]ýf[2^ýÝ×LÖ›¸êÅÊ$r†Éë°œ<]1‰1¬*žÚÜ|¥ä8 ‹zÓÞM]OÂê(àâìL$Òôøå)=±†ÜBýÜòn¸£¨ÒüjØV˜)ê`ßãåh“ÄŒ,zщ±ñD.~‰¥SPƒ@]˜Çïmª¤Zv›Y[pÇ×¼Z»²«HªG)qÊï?X«1yÍãÀÊÔv@Šb:3K.ª©4 qX‰yìä§ÝUCæõŽÊmt&®E¹ ¼ý×Þej;Ð ®ðþª¦µD«]ípÙ'=ÜìÙÕÃÚ`WL ž(€ž{1ì& Ïe£+¯xÈœ¯Sãjñx£zÈ´¤c ÒªYeì‚©…ŒõްgüŠÏMM†ÇÒs—>Ú¢uùj‡º7äcƒ+zS°’~À ÙmEË´0Kf:\ ¨ÁµØé±ìúßO©z9*u-l÷7ßÐÍñÈŠC±SGn¢t0Ì•QìšGú´÷g ~Òê¤ AÈP:j·JÂE×<>0!^ˆ7w¢ìFÔéÅÑšq_ IŸ­k •Cb“g‘ßÇä9js´i°϶°3[rñ76Rá7Miá±ÑŸR¡âÓ/®cVå2¾¾IœJfŠDe–/…Ì~pö‰‘ÆÚ+_õøôéÕyî{0·zÔ_?yrKµí‰hÕ㵿—µe±fbó¶ ª©EÆæè$4XÖ;Í,)¤<þm´?œ¦ß=•†jLÎÒöOE2×ø6½$É9L·ÚÚ"rAü„my_~³óÐ.ÊýOD ¨þ2 eL;âuœ–² £×¬ÔãdÙ…‰‘¨M®v¤W~¡·rc¨`b ·hö0×·L O®¦³¢½È•$ö8s[“a'£ØÊ'(ÜÔóG½¿ýE67_VÙ¼“ÝQk°bÁ¤'Ÿë”É(}¤_îëX_Cçf%~¸8ã¨ù4ÂfÙBîVVÍú>qrݾNÇ-Ì•e3!À¥Õ«¸ú“*jËYîÒóÛÇíÚúì 'ï1’€€ÄV¡Çkür¯ÐØrHdfØÐvèO¬Ôl™CMüT}“UÔúM”h#±Ï´¢§¼#íþis&o =íS/ås (fª\†`‚rþÝŽ#ö­L-çùÉFÑ(VË|D´$R–s~Dc†»HÃp¢ÙfÕÖba¡ÎÆm°oNÇŠô¶ÝV°³S¢ÜJXM7û1Hç0n;ÙŽÈ»‘ u`ö“¨ò ‡w4³ÏÄÿñѳ‹öúâb§€úóšw“]•æ¶©@qöýÕ§á.FÅ@în6lÑëÁMTœ…Æ6wÿ¶;Èåå³ME* +:ƒsç,BÏ—~&­àwÁtº{Õ+)ô”ù Jìcj-—¡XÏâ÷ 3ƒ!À7›¾÷[NXÌÐ6Í£Ý`¤ÓmŽ,$™½ E¿F§_Fþêýg’XAšw–ûm+¾é¯»ì`i÷H\MÂ-Ã{ÔMe ^Âg'¦-¿jW¬¦Ö‡fÕ€û\”fËfV£èMÔö?1_ƒ†AŒŒþÉC;8 qØrtÊúþ!Œéq ¨Îv‚¿+V¹¶ÈÕŠö<¶nV9›ÉÙî%?BF*@­¼¾¸¡x¼œ0ÿ-œ‹øXFL@*µQQe| `íÏyÏÂQËÜmÿ—ºyt¥Ä£Ò±E=AE?˜méY rzþÑ7ð~8l*ÏÈ~ÃàV*§¡˜ãëðkÉ;µUi§ðͼ²m‰}+]a0o´™µ¦e¼4ë'X Y–ö`—¾¸…ÏÑŸ´ýKÞ-äB,‡¯ç‘‹ƒÆ§K~Þê*†tV¬hz˜q@¿°Èr±kjȵÐr‚,8f¾@x]Ž–- 9ËÐÿŽ ~ß ;ÛTM »®æ¿\JŽvê8“ù|ÖÃè'TÔßò”Žp†‘Ì,ûç1…˜4¡¡:ë]("nuÃ]ûk ;ÒP[)ŽLêk¨íϯUyƒ;/ûêU%LØ ‰zpëéâ»\™iÌÒ®<(h¢¿ÄŒng.!5ßäzí#†4;´ï“ª#‚z<›’hGôÎ<¡oì¡¥-òÐi˜þ±Ò-¢¢dzõœÃS㡜iú$ë½-X6^¿?š/kÕ¡Z=u¤ùm@¡Ø25c¶ÇýM}>udxÄ.õ W掩Ÿ“ ¯*©ïí=Y’€€¿tO²ÜžwÖD–  D"F'xö{¶„ÐT:µpËR%àœå@#-8±[ÍëÍÀõc¥˜;·u³éÞ B züùF?úƒúw]ÝH3S÷ù9M÷ðÎGa#l¢ª•Öˆ®À?2N÷?’±uýÃÞ­u¸NVP”U~ /Œ7s˜fÝz29UÄ”Vò_üØ·²$?ã|Y¥@9dÖô«CŠ*°¢U*«ŸvðHpå›yRâ6î¾aÙ§zAßþÎ »6ÇHduv,7"8ÚPxì)-'ýKL½Kðæ*ˆß áÜŒË^ÑP.Çt°t'¹ š)Wt/;S“€keREô rhãø±Ó(¦@ØÅ:NQxuòo;+”ê¿kÂÒô9 UcÆR´Úý¨Õ/5ɲ=âñøƒ U]þf\ÝôÂÕåŸÓ¹¸Ýdl‹ Œ˜Ù«8PØ5"¦¶;˜ìÏF—!\|ìýqàl×|ɶœ£òév¯ñó}Oø=À ‰¸ìqo9å#í³Ù™'ªfÞƒúІï»YÛ€É*Â*ܵ11F*¤–Ùl3÷­äÝöØÌgI㣻2ñE6uó©rH$ƒ¦ÓW+çs KÊbó0NÕ-aF'ã—Ã^‚E–eƒÚcó|YrO/ o& …BõïÍvz¢yBÂÑ&ÚUÇg©Â —§Ü`Ïhy,ü‡±û“þÎM¯¶äO—^½—°ÅI¸mu<ÿ2¤"FŸ–fJŽdQf(öÕG{ÅFÙwŒŽuYß,>"vR¬+½Š¤©]—»zVg¾ò†‘-q¦.˜‚šAÉnr=h3S“ìà\|ªÜƒ%|Ú%O=È‚ÌÅ9%Ô ¾8ùÝ K’€€½ˆEÌ¿0o2—Eæ1©O-Ó*´ï¬KøZ‡Œ<ë‹¢mÏ…„Œ‚4¯ò|ÂiKûÁM€z§Ù×ocóN*ü€—ý! L´âE#•Ö÷!P“SÅ+÷œy8=HˆíICÖzJˆö§6$òv°äO¬¦d’‘¦Ø»aJ1¯´¡'‡Ñ¸®þõà,i&ÙÓNöcW (hT%<¬óYW9 ©ÚHÕ£,ó¾T‹m ¿W1%¯Wyõò ì²AΣxe']õ¬ŸRDAóy¾…Я+BRn‡|¼¶z6FKvyNè"öOx×›UATÅOpÉ3EÖcrÇ`R‹17zŸþÉܧÞmuseä™]gUj¤3³Î£PºM}Ô†Úvü¨9 ÄþP·4†Ržu,ÇyHîêµüð;?b™W¸Ö|ëSaþïõç‘0§oÆT˜5.¿&›8þq\äìK ‘wÞ˜ê‡T…ôPÈI¥¤á· 4XSg÷³n5ô+mȬR•TŠœ‘Ñýˆ•šÅA¶à¾Øh²O19½).÷6 [«Ò—ØžÃs"¨*”â[A YΚLˆÚ—)ªMLÅÙIý˜.¨<äŠÝ)J:÷qÀîDì‰Ià——>íW¯D‚ÑÚ°:{]~*†KQÎðšHÖåp[0—W*×¢ÃE-µÿžþ8_¯³Qˆ–Íy$<ªÎRŒH½º0VP4”U4QÞÞF|_³8ž\«  ÅD»® Q„ e/“œðêÜðYÆcª»*R~¢8Œè‚ÆÉ$œ–íØÚ”÷ýôz#â:œ#‹ÒPrŽâÅ‘BAÅÉ©Q«fo õWÞo–…%GC,éûZh®œaif-¦°•X¯ÀX5Ih™_Dn!Äù&P;©„†¼…¶{>Âl`圸Ó7õ#T;Üz>KÚžrÛ’pÝÖ¯7Šc‡ÖD9 Ûášz)pz÷Œƒ>ÿÿq~?M„qÅ­;Qºxåi† |$ˆÃ—ÃÍðªdÂ0@ãÙ4HXð©ûÖñ’ ‡ ×öŒ…ˆºÝQÿËoE:ïì°<¼í:=ÎP&žTj… ‘'IxýJm…aiüöÚP»H^¬³!MߟE=•ÆY61Ú&†=óµ˜ë>’€€Åçïû"G† 4¬¯@M ÆØí €Á75GÛ–­Ñq½œƒI‹(“ؼ܅/*èŠîßøž¹1"—?{ ·ŠÉ¶öjøJk€ÿN5ÅNMc+ð%òöó`ÃÆOõüN)¶‚¬¾;?á§J3ÚzoƒqF”ìW©«úf§x¯]QûÆÛ厧yW"Šs&XQœ¢Ñ&†þ`•‰¤¡jQ®}Èk“¸çõ(ΛÀ±HGF¢GɳŸ§#R?µo»að^ƒb#~;C Ð:ž<¥ß’k—fà'Šæ¿f7Ùv¡¨ü¾ hb·ëñÁ¥ ðÏÊ+’ø°‹×8D°C78 “÷÷GJëO•»¹Êÿ ‹§Ž…^P&ÄœôßµÖ(ì¥ÏgCÆ—> ûÃÓX¡dÚòÄÉ&þ­ ,üAøè–¾>QŽÉÿΉ{ >^Óñ øc•d"‹Wý6Á’昦{F9eÓeÝW®ëÆ^½0ò æ1ÀqŠY/*^Ìù;A¤àüº,—®ÒÅòs’ ¹mþÌK¥oOIbãGtÄ22I4´ì©‰uã K ©ò¼Š…(ç.9yF° ‡„2°€yÿ½ª§¥\ §ÕçÕW „*’Ÿ•zìÍSI,Ú±èùÔ"ûDÕ}Ý+]&¡åÜ b]²d‰ßˆY…è\vH³ˆœk»´bu%wÃÚ‰¼˜0öð–xD€n¢EF ïOÛ¤ÿà>²£Fão±a{9’¤±ði‹Pí”XÉû‰â>yè?éÿˆÍúŸ"é6V걄ü<ÌzJÁyR Åà@õf+ž{¹ky’€€Ê²ë¬ûâYÔ+_íuµ÷©\2IR³óÁzküö™nþSƒX´¹Euó/º„ç smyi×é1Vo~9袙TSâò^CÁûtÇÅïVz÷4‰ðöË —®‘›5­}«æ]KR¥R]QüŒ/ö@Î࣭ Dzø›î¹%ӢЅ‹ßý!‹m•¨´‰F“ %ÎÜ`ØÑÆú¼CI7©R˜#@•~“áÆwX¬i÷ò†ò¿H–Té³ñ”ËÎs5~ú…åãjH³¬í­îâ&£KF÷ª>¯Å´[NìÇí8(©l‹3ïl˜±tõ*×]g:˜¼« ÝZ'¸oC;ñÚDrÓ‡¦Æÿš¨€¹ÄÆ05Î)~‚}G·ŠôRác¾8îÏ[ÒÞ\RÊçÅ‘ ¬Ætôòá4I“×`4Üä³Ï€KHix6ÀqØýÚºÏî ãXÖ*Š©M¶TIѰ/,_´‘P«{*or)KeáºÑnÄZÏ*±ôœ{DtßèÓZÆøò¿[‘Wª hEÇñaùÑC\xD&÷ÈhVL¯Ÿ$ï§Æý"OÍÐWþá¹îNqʃ;;Šâ%½Ce*c…æ|Ïç4û¶ ·ª*&¿"}Çdë[²—A‘·/`=?Èáè$¶j•øxˆõìw·!g^º_­÷mËQ‡±鉓›æe m‹°}oÏó¢#ö.û4Ò"gfc¿ÌӜ˷ Ò%åÉ–ôººê»~a¥àµ²í{Æ’^˜˜²7ËyúÿÿýĦ¦ 3cZ siU|Á)Z.Y߈”ì…K§»"i tï;_$iõÛpLÈlûjPˆçƒ™8`÷ç\XíÂïžs$îíˆÆÇÈsËR†uX‘”OéCÊ _¢PŠ>°Ýìá'G¥¾V9êjzO”dµœÇHáDüÝÎo®j ‹›êÿwc½†~$!˜d5´[q@lË¡b¦*Öqñ¶5±_Þ—ZcQ¿È¡2Dÿ/†uœ„¡YNóŒrŠI#a†×;oJÃÃLåÖ7üÉ™I, ÿ¯j~Ÿ¥m$M\£pßn€Çz„ÄØ%ÀIh)vëÝuµ9ä’t³b#g÷åúö½q´dÿÐ’´wKwiµê >®pSš½=eòYBçˆ ÂŠîÍrk–Z_!‘çâ»'GTICK H/ÓDÒ°ÏR BxjÞ SB_’/Ƴ}6ÓZ´Kó¤Ò=‰ò;Þ‰é5ïÝ}ªvÉy n/â7ëâÏ"C³¨¤§pãòª<ž"§C’ê“GD’œ!YÃá®EÈÓz’€€ÖB•.i!è]¡fF+[r5Œ…°òR'}ìËÏ0‘XÏÃÊ’Q’’|[wÄ£î¶-å•bÈô%(§ æ¯øÍRZàŒ$§Àçbrk¬”÷Òõ JHç‰oZÀ¡GÄ“cgr†šhE=brG`QN´5½H©Ä'ú{ªqƒ£›á?ðªke=ß µXèŸ6fÂT¬ŸT€,~îœÏg:¥uƒôþ„Ó„æã8Ÿ/vðó©ìï­Ú™£‚»Ç|wa6ž')¦5¸°ï“B±Ã?QÀBówƒp4ã(3aÜ„JÀ °Å¤•©Ð5sÏŽÍ~«vTZJ±ÙQnQ€á„6X[˜2õ”Ó¶Ž¢«Ó~¦("³¡5œ¤ÓÃø€À-ÅŸ‰¢qà8uÞMFJ1å"çÌñ«Þ¹Ú#´b«ÉÁeug†Ñž }^›hæÓ•ŽÚÔ)Xµ6Ãc_ MþÛ/¹ÏÞ¦•“é8LQtÜAo3™”È^ÕA¨…R·†±o@¡D»Nù"Ë `¾GäÕ¥ý‹à<ŽûEϯ56¡.4¸4çâL{®Hòæ‰Þ¤±ÇÖ ý {R& æ·à¾Á§7.s$Ë›:ó‰Ic ŠÿQ½â*À Õ4šÈs Ä¶sTú²úîT½J‡Ì®‚ ÀQétš•usA믇+Ð=H”…ƒ½ó¤¹Å!?÷ n/¶k:#ú)o‚ñµ§Ò/øç`] ŒmY;…›ÁY-*™¤«1zA_üŽ9x2ÿЏ—`áîçä凃ï“O‰CšzB<$ëäÿ¯~jJÆÍ‰™çÁ—“§Óh÷‡õèâGJ©.èÑèºK+7ÊQ¬¤âmùÕïŽÂsn²Ún±ŽËùÙ§s#·òFÓ}X ­Xdšêób‹uâÖIý™:Yí¨]-ƒP/zµ2ËÅ*ˆ0p©aÚò|>]Wó-¼pÐÚ‘ ™%õ«ƒÑ_Æ@£Ž«8­ü³ÒÒå‹je29Gœ¹kõ¢ÍSªýà3îóÿQ(Ïò•ë¯V lГ^‰o×Ô.Á€Ýcº±lˆCµ–ïî4cÑd›C­<y©šæú6‹õ$5?ºT¾KÁZzí5Vå—”ÇQX6a<¬±$Ïut|ð6rïòÉ/*»ÂMÏë}%Óð´¡âwb>.´?i¬’€€Íp éøêS£[B]Ü$P>´´Cßuãk9|&˜F»©3½o2µQà\húz¬;M»™cëzEt6‹à¶e{x^pR³ªôEjÞzX2º(LmLfRX“i!Q÷ëE+ß÷ÙJÑ—²ò 0xèÝk{ ÈúC^:KûE<´o†dsíÒ•0¼1ºC¯ 3ÿ>tøçlJ«Ñ}]NZŒû'Ÿ äEàEN¨ž~ ÔRW¤[@±Ñ[ÏèLPu{M`AknjõƧ|e†Ù>õñ=Û]ò»Ù'å‘õ‰ã{]Í!;Ü™yÉPW@¤–Ü ïŸŒè¶¼ò¥ JXÉ3שö²xûÖp«Ñ0í#+ƒ”ë‰qYØ6dIYåž®±£Œ Ðdwè~ÚÓ–V‚s§è?bs‘5’UqôEyú­”Qx{íëq:i·(õN¶ª%M4É¡<ך½c¾KŒ¶qÎU‘ŸgÙF¨$\¥´ägׯikÿ—BHÄmñ\›†˜JPy_ôæÃ‡Q"ÙtÅÑ"†a> qÿ'Ea–*ŒÄtáÎgCØâ¼ÅÂZx>ncÑD¹Hè_Ä™õE¼7¡‹0õŸ]vÀ¶"‚¨wÞŒîÏP:](××÷¿Ð3þäݰYu,´½@TIˆÿu,«„ìtٹ禬iÛ0ÄÈ55Š…®G%6ÁP°/ä³MüúY‘E@Ϩ·SiôÉꛬ‡‹®Ä÷öŽåeE°Pb]f¬¿Ã‡»S ñLQ\ ˜âDåãeÏÓêÜyÈߤ õŸTFªF&ó©uvBÊ÷m^`¢Êʼnr¬ÉSã¨âìr˜VÝ‚FýeÛûõùXmY\&¼â±ð‹éž2xÁZ¿Ì@ bbŒÇå¸ÐHi+9¸ŠÎ î%Ž–OZMßã¤í® ›PœOíÎIµ‰š‰í×ü¢2õØÍ5à8¿<4÷8áé+.ÛåVé™"7rŒ“µ…½')ý1Óª¶µ!çÍKHñPd§3¼‰×Z”Eü°¶½âw´ÅArWòñ·+Ø]×WÙwð*/$« ¹ydŸé<-ä¼ÑÓ!MåÃ944Éã¥õyWØç?è¿ë숲n“evÞ(°{«@î‹h?§wû [¶vÓvÎo*Øi˜‰î’€€ÙÀ$®jR‹RQô;@o£Z#w«–F' 8®2„ê«,âÂÎhsÒ“þ½G­=¤ÂøN¥ìɺž¹§x…;‹yâõ×Êp|¨Å…]éï'*Qׇ7 v¾J6È;uÖU–ï##¿S¾M ¬ø×ÏHÊåvig#¨b‚C£;_µ‚®âc'Wn4È aD¨’°Ðcn žE¿£‰Pëm9»©l¶}ƒ =¯Rsôzέˆ—k_ÎF,™~]ÊQM×§¸@›°â9e.Èà)÷Q^®L{t¸\A9ù–6Ì] UF}X?[¨IÜ«[ M™&SB8õÉöêc§}•ÏI=£W4%MFqºG°™ÊÚ?Ÿ~gÑî6ÉÈf^¢Spî¬Ó‘xJ„šyØUaŽ|j2Gpj§„µŸž)ÂÔªèy`î¯J!’R÷Ùôöóa¼1z{_-áoÓÿýP×nQ •/ôÇ@ü:6B¬K¾‚ãÅçèƒïlº–šœÂ`NÝF ãK’Û{eæ û¶ VUÌW*k|xèU.BàžF~©'ßȪ˜ úöÙåé>ð"ÍKr6ðhAKºSˆh2U 0öðͶåÇŽcú…µ¶è›û¹œ­xÜÍQ ¯ƒÝôJ‚¼Ó8Ë<þžn|$GÒ,ô ¿zÄÆPC[Ÿ&Q‘ÆÐ$æIØ ØwCÍ©NkЙ¢í€ã«\ fáT‰mÏ~c ­v£´O®>G"ëÁÀR°ø ì[Ë)GpF€$Ø÷6@Àüâ)Ë*dÑóÀ µ,ZæÛˆ~9€.㮕:ùºkbê¯{Ù“× ô M#;]~#!¡ñ”ñµJªÜ9,ÎöØÇþx¬/:`T‡ÌÐzà¸i“ ÷*EhѧM8aä ¥é$(ÜeÓeÿGªÆè$Ó·9ÕâD|©p»ÇÿäÛO¡g•e×-ó-Z³›:f¦;Xö¡¥Àkv9¦U®mmŒo1k.¬Iá©3 †¿È¶!t绀ÔL 73›†YÕÇ„(ÌÓýÝzÃg›‚ÍÙÙùGýàx)L®mׯË@Ø’€€Ð$=øÌ=Y¦´«BâýL¯Ûõš‚í†|_.IÌëïvÝ„l8 (§øZ½ t:®:I@Ó\|$áäK¯…ñv»æœVìw";™Žü‰í_Þˆ‰K^–h ÔVÃD «>øKBah aëAÆL$ï å÷i¹þÿ4ïm¶%û×úâkû˜6¾‘ÜYêÁ š(€ÉL šñú0)Â"™2¤©C;óÇñ^Ðf0™’SÀ”®½Ö˜ìåýnwÒ²C™”Ƹy!öe6¤T'@v‘ÿ4Øøôy²ÃÃëª&Ÿ%Ð'Ȱ,×]  KßêNòf°¿Æâ­ä¤÷<ŠÜŸ %ù§ì ˆŠ¶~̇iâô€K—ÌAj€`è« GºïòχÀÈñå§©jK#«ÄpùQzçƒÂfÕŠädt±C±uz®c¿;Ÿ?2.wq,Ý"è‚ÇQQõ{ø·Ñ|ëó§ ¯gay%PÙ(˜àžŠÐ ÓF»G…'“ïOÑÝ}¸Æ`¦8)E=qý•ãß‹ôK$Ð`£îBј«3ðblfõWcØ)KLœŽ¿™ð-ÑÀé,ÊÌL8ûdY_«œe™\$ß5 ¼u\ˆð:•xÃMFž6¹µºÌ»Í"6 %ñ}±l…öõùl•¾lçD¬ê”l„±e‡¹Ô©ú»(1ÜDêJeܨ¹jQÏ„¢¿ßàË s?ÏHĆ#  hRåþ*½$$|‰’í¤3t¦øMåÈB½qL ÊÐ×ßæZ!ÜTÀ¯Ú›Ý,-3Èî|pŸp4æèì48qŒRs:ŠUÁÇnE õ…ǶQ Syª}Ôƒøº Œ0ìgWÚp‘c²Ý5é® wÑlÀu$Œûz/Q(–ްÝqÙ4d#›tˆ8ˆuŠ÷§ ­š,‘tû'Rlô1oPúxà­¦ia‹r†™#%'F·õª ÆÑÚ¨qâôøØØ¦ NA lQ>D‡‹²KšTðì%!j6ÒR„‰?é€}‡V1àž,«âW–ì³Ly¬,„æƒÑÈÏ× †œgÌFã3:`2?óè7÷£‰z®ãÝ»®R`µqH­ÂÐE_¤º*_Î᪈zò@à:Û¯ªÒÜ9• (N9Î…ûwGþ¶øƒþ);k“8~’€€·”†¹O†¨Wýªàš‰ŽÌlÉ¥Xe0¯V»+Fco!'‹iBzû@k- S2ÉTW$ètˆ9¨³4Ky:Õß;¢g Ha³°jaNëv}j8¿ÑÄð”'×c*Ê?òÔ_ã÷m·ijå'*YÚQé‡}Å­Ìg¸0­y¥gU 61–ù‰i"»FßsGsW\üÇ“9¸N²ûÃÄpzF[‡0B"áÕH©ÇíFc? mg~47Eö±wákmWª»YÁúÕp¬×ÏÎvk%¸>ïYÆñîüI>Ÿ§É´‡î5 §„¢¦ÖWšÝ"µ€o*˜l‚e6°É1„ÑÒˆÚ_–®™†ŸßQ¼ðSxçb1Üÿ 9 CÜ䀨3´ý—ªMñ—0dFTl,L(r²äU–a >}ߔЅÖK~\öÞÉQB›x*+eÛp/D5íëºEÀÏ–ˆàÛÓ ² o¤j>Wj¶,çCŸji÷ê«ZFcB£Œ\ìê»ÉõUå@µ½`ÓŸ­ðÌ„M‡—¤Ø3»Ëš€¦{£&©ks9ÆwúÜÖîQø8sìI?4ÒLÉØÀi&–—H"òíàB¸gûƒ/'yÖ@…ˆžÁêhé¤ßüTÚ¡‡½Áœâ̼_®2 åáèæ¤‹2’`0òý¿;]?½2ª–]ÛqªTùº6”wOÚûq~DeU–&dK.$èøäõÌXƒeç4ô3M9‘¥/”˜ÊQ4èÔº³[ \‰V)Œ²O16Õ’w=Ú-_~-åºÚ¦âÇga/Æÿ»Åo@EÉÉ öõ-(y ˆ£ßéžw½N%©›Íü»ÌZ+uŸ;¡ Åcì ßSÓyܲ?ÄÎÕ’Ù=ïx´(×Uû*G©Ýkwßáþœ‹#1è<|-7ìÀì%Q ޵A¸Ìì©Q9ì=p¡ÁöLTÇøÒgÇÃBQç»ZÀ Þù„V±S(‡ŠèS—!ؽ(@ÎV±eœÒX‹uõ±†Ô˜ –hp<_õU³ðÌEâ¹ë78NbRª}·­­øê®eH ñ^4 X…#OŽKÖÍ2ÈW’7,CMÄòŽv OXj®2ñÄfÙÈz¬¨¨fämó–;M¹«°NÃCŸ`¬ u’€€–¶&ewRY¨ñua÷šÁcqÊ¢ð‹_lÙ‡úõ`ú“3ÀÑ|C ÓV`Ü÷eÈŠ·®\ˆ—·<Úü/Ý¥±1¬®8¹†;LÉs¬È0¿Òø®\Õ%þ*н¼-xðcA~ŽhÊ—ÑϳöiŒ¢ÉS»¹ˆB/ôñ:Ì~Y`ƒdå ÃbÜËœÉp?µ]J¯Ë•%Öq ½Ê ¿ûÃ~c½®þÝÄ^w2¿ 4¹©›—ñºBQãÚf¦|0?vÏÔ»½ú…ä§Ï.J„§p½¦Kyq*ƒ°ÂX¿àÐþ N¼¡r_9¬÷8úfˆâ2K+ÌW‰®üý;Љã§(¿uO¸îº7^[DªA•Ö«9³«,u€D_w/$Z)Yìª×ß<÷rÓ_&ã®ß<ëç‘MS®¯¹‚¿ÿÞ»½¬ìþ}#tÏG394Ú;=¿-õOt x¨^§ä48…;|®%¿ØèËb«#ÄY9³©"É€Þ<¾ÖmKàãÅÙcP"üúÎ#C,Rΰ5LÈžx}uð€ÌèQ `v‰«Æ¸-EN;: •iIF û…ßWa)þ낎…öQïM ÑŸu0ïÐ5XÍPÕ6„üâ8W58»oú¼z­›¼¶ïNË—µáL†”q'¡)ÆJƒ·vr¨šv犕¿xmH7éáb¶ãX0¿ƒ¨h`zK”…=Qú¾ï›a ì^ zšýO±(R~PÕ‚­å_¼xÒwT3mô-ö³&Ò°:aR §0^„LÝNÊÒD ÞÖמˆ2†pmõxMf ¹§Â“B$Ûë”sK.C‰®³üðŒÃežDF®IIÝûÿ­¼‹V¨ÉéûƒNNà Kú[xÐ9¬§„¹xÅ¿w…Ïè¥Ô4ŠDÔˆ{dàÄ^[m:¾Çïb`sçhmž[ù,ºÊ_O‘HèÝá…žÊVÍàl1½tfñ‘N »‘b=[¶$GØ úºü•.ÂÛÅkÜæƒû,”Õ´…f÷Ê'å[WUé¢×5Ëó“«ð¸á{ÉÿöGu‡¥Ã©B²Œê%ÝäEÊÅË’=öÁ`J‘Ûçºê¯ÙªÎšôaކt{ïqªUî{ÖÌ‹°dž²³u]â˜Q„D¢çÕè’€€¥û3$I*!B¾NT¹>â > ÏP{D°^å %ù".”*‹~º¢¸ã;±L-žt€|–ƒ)Do—úÉM ä5¼S£[«Ö µ¡7•…é4_Šã;­Õõ»vRwë#__¦ötÇ Bq‘{:œõz­¤Ã¬èŽEˆš2 ÉˆÐ?ÛZõV b¡xÜ ¼*[xœäpÝo»©+bôh VÛèú¼¨}þ"27³J.a_ÀûFŤ«µ ßÞ±|÷àÌ4­¼ý¤¤Í (h¶¼þ‡ïÍiãÌܦw†:žéÑA]œÏ«sqÊA@ƒÆÃ\áä,È›¬$q˜‚f%á\¡aÜ'"3U_£Æl³ð)øšBnÿ³²~ €õS·W/_Ô %±Á@¦BŠÊÀ¶¶H!–¹*FúçõV/ô>¼p÷½¸.”!’á´‰ih2´ßQ‘ê5%?8„Aoi?ÓE“übêEÁתޟ6ßh¹C| Î>ù2ð8ª“A—QeâÏHäÉßçdŽÀIq9§Ú›È‹dÆnwÉcO¤Õ-".8[¬Ã­É\ò]’Ÿ_ÀG@ç"é&Ž .΃Ä=PˆÑ()+÷ÀŠCú¸†òò‡¦1ô4šh†¥Á»"pŠÔ¿m­³f¨£ƒÀ£äaÒÁ&Ž®b~¤4Š»jÕ×oÇpx‚‘ìžØˆ3ŽÎÑ fÜË—{0b!dhá’ª:s<*¦mKg\e‰Ë÷OÒS§%SÞ:hÄÞÄKh†ÖŸVþ ÷?Â1,«¦×±XÖ¹·N•%F×TÖ‡ññŸÇKÅÏô,£¾Ï,®*É[O´ôËy`Ófݪ͈C¼*šwމ(fR%'œÐ®8 =šŽ½GK6h{_¾È?¹@ÂÿGÄŸƒWé°Õ $@òƒÛúI ëz ë/`×ôïÓ§<ý¢ü=¯Ô뎫Ömb˜søã‰·’4ÀSMTÐ¥®e¡ %æ<ú¥OVÛR \ÔuAïܥĜW6ÒÀ4GŠ^J䤫‹qCìçÙµ›Ð`Pí©c²yd#3|cþâà§qÎdeQ2‹?µìÄÝv"_>¡[òëàl!¿ËÆË$¼K€Öe:ñ"ˆ¨»Ä€.-_ßq«”ÆÛ³š’€€ã9Á5ËÙ0—‚¨½OÜâ…GŠ Ðt˜Û×[ôg¶ßä+'|+ˆŸ«F5›sÖ~zÐå³ãf{T³ƒdº@y²h55ÜPCéòóŸ’÷Ý|`ºwÙÿ¶?Ž>"áåf>8}ãõ’[Œ[Ÿú¸!ï2WÒñi%ªi2jÁ·Û±¼ÌfRd„9ŠOtrY " .©¥žq.çÏY(Èâju!•¡`ífƒ+~6· 3+Š`pÊcßí‰øT5ýᑤ3‡8G—ºy`)Ž×@BHI»KtÝû”½ƒuYý°²²özý^&ñg0_u]ôú®D={ŠÓÆÚ!$¥Fž5©š»Áò‚È+Á7•ÕzOÌêØ©|œX<¿CuyФÅÀ¶@F¨›2ÅUU !‚»V‰,:òÕo©Óé«)•ÎwP’¤%¹à4yô•ó ñlKÔÃtv¶ÁÂiDìf¸,Í-Îßs+‘”Ÿ{ ÎÙõ»Q*Kú.l¨‡*OÅԬߚŽm÷–íC2¯ ¢º¥ŽË8Ï1®yw½š{ÇÚ,¬Ú)ýýà”ª3mâ¨nœ[ï%Pè°“®-Þq1·î¯Ð‘BºZŽÂ.“4Uݦ÷ íµ]\¦oHÄ"~ô GÀà€ÜgÒþ?µ“±Ö¡v׿gÈCK!„œEx©„×õg_e>sbÄ™ûŽº»B—*ü\zW v\"T »®Z`ö[Õ÷.ªYŒ¾V‘~Á»ßÎŒµS1Sˆ,†B0*ßÓ¡ZöèÞ4rÅçõ¬JB3S…ÿ¯I•™„{‡¤tØ;3ì*Œ$ýâç3}l"‘¤ÿ*§ür­^ƒT?îÍ›€nšxÙðömX¼ŒÕ_t7´PWË=Žû—͈=9?‡À‘ùö„¯o&k=O`3Äg3$é8ÚJî`’€€ÃC„®iíæ®sp^5ÜÒeˬÁ0Käl© #µ17À-z\ßäJÕxênó1`Y³šyç›s.¦»’ylÑ(iú ¿øóž}Z{7±µ\úÜV½ –ö§ó•ïuüV¤)±¡N z"dã­_›¹@AOÂÕÙIÊü†)(EÂ'9=fûÉã²Æ½f5òâ¹;ªó®|¢¸Û&| ·+#u&—Ñ4~ÏJÙÀ†LÉ;!IÆÖ °)€Ò"×j Īɚ´Š]5‹Þ¾LHGð2-. ï@u ÐŒ8mNúÚµé¿ð»ÑÂ%ÒUÈùÛ¦š]:ÇÝ9Ì4:²åZŒÇ:!ÆÌCºü”+^´×g­Ž[2EÏlØ5 ±è«Ë‡Ø›@íwÙ-åð0tò#±Ód‘#ÒÖ¯ò£Ãþ?‡,¨víÁ159Ã%ì`ø,1lvHfgÝ’’”rî쪦{íoÏÓ¿Eb&Ä¡L4õæ)þÒAúgç¤8ÿ0J|ÊUfŒˆbù NåhÔMË0Þ‹u’2g±!(:¥.,™lÿ¯+¥fî™Æ ŽÏ’)²àíÑT¡c"›çF† 3©† ¤õ¸à£…µ4J2ÒòÓ¸¢O.±!×o2û§W$¹kswç¥qÅ;YýùÚzû1Ó»òó"=<­è ½¶i~¶Èk1û!BôÀñb~€1Àë•[<¨„g«çZ¾:6®ùròfBA¿ÒÊãÙ"¥A©iÏ'VaBŸû%ˆ…c™E«—±<ÅÐý‡‡ß²îç5õú‰Nè”Øæ*V`²ê››î)mü6ß|š%5Öÿ*†=[+è9ÍØyùžˆPÄ]û4?¡ÄÒõÓ²±isj ³y €­&™bí9fŒLÄsï ð¹¯Í/ȧƒ7¸lwÄŒYè03ŽîÎó´ýä¡ë.š(£B¥4ZmT…§ÃzGÊK-{€´é#R¥Ð!¼ô”ú½»ßÉ„v3½‹¹?ÞÕêÑÂ…ôH¥BÛ$˜¼Z×X]»P»7_kˇ™xš––*ûá—XügÓß¶TŽKA¶J\V½A¬em¥™N>ÈOâ« ï9ÃEÍ Yô*[rÄê^2†#ц¶ÚŒÎs"ª×Þ/Ú4kf’ ¶™L’€€¼% ro+ÇúO]óIFÃoµ] £iñ4nDt/†ƒî”¼iÙÐ)Q°Ÿ”üSß8âò÷<Ï(_–oÕ%å¡›×Aƒ^Y¤Ì#d4'­Ÿ ¯mš<‰6ÔDÌëï: ðÛ $«Q§1rmìßop%jüè{ùX…¼ð·|͆n¿×Øš>GLÿxyA¨| 18É'°Ì¹à§‘Z$‡M¬õæ1Mª`&µ(k´–»bÊyG~©‚bre܉¯ÄQ¥5 x­H”ðaþ §Ï1òMÌt P<_ËʰtNꆵ+3>âÊæ›ÕÝ•S2Ö‚íùwü–XŸU%’2Ëü%…þòœNýXò° ñã qu˜ÖÃÜÈAá#ARõgbÍÏ ¿hqÛð’}TY 5£Õ§Ð'«ö6Wð üÓ5NÀ[©=ÉDm;dZîÆòêôѯéØ@ï;d!(ågŸáв"©?d31é·7ݼã»L‚ U~(h ¦;É1Fs]zt¿ô‰çòrd7”¬ h‰&¤Ãl3æºnWÊ}˜"™¿~_eKáxö 6èÁûÝ4³±öcE5{cÂdÃè¼ÒÓ«Ú}áShJ>18ëp~Ì®Èã-dŠ­maá¢ÒU#WÓ„õÌ·ôËÛÀ$“UAÐu¶.i»þ—aü/xSƒ:0¤„=ã^VÇ‹ûÊðv» ±4>É‘càX ‹×¶PVÞ£÷Èv}RSi¤ôåÈßÏÂÙúiÊÚ_xÍ·MÔˆ)\»œí¬Œ‘žf `D\Ýc*ÐNÞIÕv§Š«!Â,*Äâð›>¸±¸Âwv•¥£¹Ì3”1ê» Oj,®¦!ð]#µŠiF.quç™v"ü$:F=ªB¬ûRº¿&ô¸ ÂlZdŒ™É¯~E܈îTýFÁFZóHD çOhÄ\êõ^‘TÉi+PcښψÀO^ˆë’4Ñ)ýPÓ•]-¢¾Í¢†Q¥'^Ðlý^¢CÖBjê6$>ì2Š4}æ(–f:õOO­ Å‹3ýã¶Ó‰9R/¥MÁÄÒ ¨G*@Cµ£{Y]YìÊ}õo–æHE]O<&pðT—•-¹5Šäw³G4wl·Í§ 2æõØÍ…ާ’€€ È%Ae/Ê /Ž»’c–ñ­¼Â“ôÑj‹H[qGû~AÇ\7”«±’p0ŽÂØG³w³yN¥ØÔxp´³}²0B¡ÀAªˆ¯înêF¾r]IÐ÷#ks’÷€y2瓜¢½cè¹àq2Üøj#E^ðI)²¦p+â®%]½¸`—7ØÄqþ¢ÍÁ}Þ¿¬Ì¸s¶‰Öý ™¯oIÞ/¢nµúfÀ/µ!{…üç¶…qd|oŸs$vì@ÿ'eI-1tGæúfæ©tèNˆŒ‚ªØm3~ZãØ.i*\`dª¥©ª<Ó£–V=ÒFÙ1ÅQqHþ81'3LÏÒˆ|ÑåònÌë)º,-ÖZv’$³ÿæž›$ˆyÊTRÌbx(¼<©ÜoÓŠ"n™–üJïœÕ¥)oJÄ ]{W4çô¥ñ…Ÿ2¼þšæV`RWë¶e2*®Å8Ñé…å—/:á}Á_÷¦¬ñj¢«É"fwRäæ“XÑ, 2€dÍ]l 7Ìaƒ8©&(’)§üTëàlÖßÙ7½yÂɲYr‡âæQý—ƒHë.È¥P©Ž ™UúPúÔ?~tÂ’÷PÛè6ŸÞ¾^ïóBiƒä“ÌîO4íüê#IË4›ÜŽÕ £éå|ÞZÔvT¬9|8¾k‹B01L+µPdxcðDC]Búô€ÝÀ2$j§c!‘’€€Ôw^EŽI!Z\KÃ6üŒÑ– t®zWÕ£ˆÕ¸Ò ÆÓºNK.b¦`‡ä0]‰EGæ°,_¿b“ûØçé‹· ´íEQ}…Æó¸EäÒM®‰Ôƒ,Fà'’ã½ÔW&RÁØ4a/ðƒÓX^%öŸãŸ­ì50‚/~-¨gßí7|gË´È·?î¢úûÝ0&Êš7¦7ö®•‰f£pxÿ®$CÖ±ˆ³Óx:l9€ý®dÚÚ!ôK ÕiÛÕÊhµÃ%àÒ"²A ‡p÷Tì©îjìYp¶.ìgH( XÛ ¦²-/+¼µ[AÔ œƒG#uº½  +žX“o#]ŽLéµf÷l(Z“1xËéñïATUð䱪.`ô0Ó>h—##˜b—†?Ðþì€J½ÜVñ6’÷kqÐÿAÂ`4:N:Á²«­rM .¸õïÝ©3ŽØSFÇÊ3„”eì…Q«ë:’ž5Ó¸Ðë‚)÷áœ[è˜ì€c\Búu•0= œ!±ï/áMÜêbj¨9ÒûqÈ08>Þå•âA"YDŠg»Þp½sø'cÒ"l ‚ë'Àeäë@¦#„eï¡«^9¹Ñ]Ÿ©Puy5L†/ÿ·C I˜À*Õn×z<›l?µôòÞkó•³¼"˜Hmµ©Ú‹(Ô…ñð7Mcñt¿j8ŽùÖ´³×÷åÔïêTF·»%‚C¼A§‚½çºd‘‰r‡UBYÜñq§¨õ‰ï¤ E )]ªÆsú€=k1"ÏKB+Ó`œúñq5]fg3hA¾ƒp>*l7E-ÅÙ&Ô¹m°Ekâ{™ÜJý¥õ6yG˜„,²9Â_µ–ÂíЪ«›uÏbž/ׄƒÑqŽŽ8ª×mΛTÏ­;nÌŠñ­€@†,"–±Ó,þ•$ótíåyœáæKvÐ o!HEùqœÉl›ëB[¨›]Õe®Ï =IØ*§^0+UÛíC·ÝÑ—ïç«€îcÝ_(ù™=ÕÄýf"óœ kë¼J„ô…}–YXðzäÂtI߇!aF¥èTiG¬Yø`´h—Ë#ÿûQ`ݵ¿´ù`û§p@ ÞaW\Ð#vàáTk»µVÆSXø 5›ÂÖõ"OêßflýI“Éû¶F“aiŸAéS†ÎZ Íï*l’¨ÛR[ï;ópŸ p¾ Å™šÈê1“ºK ˆÚ‹ã\Ó[«½î#š¦ù<ÂøF¦÷£HËw6=bÞ£ÿUÀ8@/þ¡ !,G¸i†çˆ3µa‚µÛùÄ¥0~ `ò ÚÑb=&Æ»Ÿ¹NÈõ”YȺ¼ˆi“¢Ü­Ì÷i(¤ŠI¥3,Xà¢"P#Ÿ€X[¢ÊÒIÕ̱|N¸ىLJ¿-P²’ÌÞ ;êÁ <ÕÈê…ÛúO"a¤5ãÄœQ‚Ê4i¡:4»×ȯ{gFgGž¯q{µ^ë‡a„1ü ¶ºùªgµL5¾+°ôC“?Uà¼4×;™.;ÓáË9ýHBR® i Ú–\í±»R¥ZǦC[u³|¾ ¸T ¤ÌÄ@ˆª pÞ‰Ð\[ÔA@ŒëîZ¨LQÅ»a ÍmrZÓý,C N½ôï2¢»N½ÓÍ3Vh(á;\(¡àTþ‹xqtˆÃhš•cûÖÒm›}aJ‰¹›àø>X°á×fŒµ@þ¢²ÎQÞx;2všÞøxè²±Ç9ë#›†ˆ‰ñÊ‚º: n=î‡W7­Æ|j².©Mµ—Ò¤zD ú¹UØITi(›nS[UJ:¹Þå&6ì÷ŽðXü³þEoªðâöÍŠ§ª\§Ÿo)V¥’€€œ°ü­Ãë¡ax׌?x!Ÿ«Ör<”ûðH’ÿÔAÑÝ;…C²[‚ÆëÙB×ÒQ…`TɵEw“¼óàÉSòØÔÝ©›ïãM!â5øâ†‰ÆS3úlÝè%5̲‹õ04ù/á×CÔ]ôhFºXî2òX¤[¤ç·çpß½J7ý¢6v¾Ž¤µÇM=|Á[5Î PB‡y~>§œD6°É8Lc̆ž(‘êgÛ2q'-åj«ë)oa³TpvßÕû¦‰~Ìå*¦˜æG@?ð@½Óœìu|Ä6vî2¤”ÌQS3 Ÿªr?ÙèÖV%÷Ä𿬨VR“¸HWf»TŠðƒW…/0=ÑX_ƒä$$ÁP=[¿W£g"ÚY­]àԻز‘GƒCÌ8PôÉ÷gÌä¬ô•Ë[¢óöy~ŸIHÈ6§)$—l6´›•…r±Óó¢y Ní„/„QÞ•?ÎAØS""\YÍ¢ˆÙƒÖõuÖîêa±øÙØÓÍ}þ¨Þy\?8¾«O³Ú==s»¿ûß­à … xaFÄXNÏg€>Qp¾“ -ÿL½\;®v@ÆÄ/;ƒz{+æXÞoÇrhÓÆÉºàŠ ¸*eÜÌ~û†ÈÕ:Ëå¨8б¿ü{-ÈÁ‘£9$`i{Ìï.XÔ…©‡Hb`3UEÃùâTñ¸xð¦Ú«¸Hf`Ä~» 3ÔïZAªCƒE†ɲ/p£.ûÏp ¥†y-’ P÷@e Uk¢^“íÖ&ä ,F¿)…@ãÜ7PŸõ• ñ¯Š²ß*-ÇÎåpS_’æ®Óql²„ÒLž‘ ðçrYïMµ˜ta\hñ“Xú\™I€ÀÉW›¿³=€QV$úªwŒM×;7®¡wIÉxªàu:ˆ„ñ´2aµx¼ ïèAÛ'©…ëß§©<Ú+Rµ• ðkfc™‹hIÛ%¡ ´דª€'VÆ«~ç MŠª*;,·wÆ¿õ¬X͹1WèÀñ×’ ÿ"ù& ¹ñ·”tuåšS±ojAÍæEÚçÆÏ«î$_¾R3¡[{À£»i·f½Ü“.`Â1CÔiMÁxfí$’γá“@6» ›Ž…êýÖŠQXn,wZáÏBC’€€ÄíH" *H¤ fBEuaË‘ßÉ;‰EÜQè-u±’É®t·ÐÕÑÝ¢š*§Â¼¹<AtÊŒ§È°y\ÿ«*çECßÖ­™+_ÿP_M4w2ênd-\ÀJ®q¸6¿¤¾Xey^àS=líX^ IŸS¢ ’ª1½°ì$&Ô2¤(»²FÐV»cöóæï™¼I3/žì»ÌoìÿyÊBܪ1[-8ñ«~ÒzE¬okòJcë한ØÑJ„GZ62 l/$5˜¬`k î«RƒS˜uîIõ}M³zÄ£µšõŸKFê_ ѬdhHG÷Ÿ¢Õ Rèt>W¿x쇾̢°ÿÔ‹GÃWÓˆq!¦*Çb¶ÌO=­É0kJûC?}A….ù4m~òTã™GovÓÔ‰• _sŽŸ! ?`‹`7YZ5T1ò iËq¬Þó‰É©êq?R ~ÏînSå8Ùl†<®°isŠ?éivæÕh¿se°<À›Xù®›L£ òåw \…3 É(Á“ÈFõ驉ÅHªkºÛŸ¾ÆÖv™‚u gf)ÜR·÷-SK0…Öªòÿ§û(2íî/âè7ÆJÉp'Íe,ˆÔâÎEÊÓ§FÊõúö¢øÂGb›[|‹ð]£iÊ äÖ˜áYÂ"ÔÚƒ‡¶añÈÙÓ:΃QYþ}Ä!ãzçÔ',sŒˆêº~ÙdÊèrü‹À¡"[a¢:Ö øbŽ&²f aì¦ Òl<¹³2ÑÕ§^)‚W¦KK8Á£.ò+ ®t þ2@1J³‡Î$ËÌj'F’ElõE‰ê ©ÿVüCéôÐ<™6ÐwÐDÂ+Gð<†¢Ø5š1™ ÞÞw[«¡×émd>$í–Í6ãàˆ#›8„2U9/ÌGoGðjÑ%kCáãYè“ðî¦mÆò b%–„5ÓµÚ+3y·AѾlÅîzÐ-hgO› UO™Á¾XvKöܨ°!¶‡„?0.\x|37©‚æIiôÒ6-í80‚µÜ}Vy§,:ón5dþlS?î={£!'ç:¢~ éTQw†¯kd u;„ÂSIÓ†ÍWB”0:™^7çÕ½çÐ °­ÓŽs¦zç t£…ØB|J¨mN±á‚2\aP¤ð±`/b4ü”ŽaŠfåtÓ÷’€€ÙfzlìyÜ?"Ã#vþÀò ÒHW5¦”áö°—•2k<ªWcž9Q=zÎÃv„!ÁÊX±†ÝR(L#sÔCß2jêÀ 6é¡moêš·Ûs­w}@ ¦9™ýøe €ttwc$r3¶g»>3á2Íš ú"{ ±B}¶?zq£ä¥¨§Áº°ŸDÏÐWGâ7RÐL·&›Š UóeÇ ²¬ƒ1dNE©”7ÙCŸ»w:ç„PU%ª¬oó“Úªúi‡(’RùÊ&E57†‚/)cÚFã7îúÜàîKbs] ûŸ.mî´lƒUç:<«TãwÛ2a—€aÀ[.QÂNâª#ØÈ Jz]ŸRÆ€Ä-®7×>´dèhNż +ýéÎôû⢜ûgõȲMý¶Ò[èâî•ýo.ûÁöÄôlQUÜÅF“ü<$míäÕòPs`ëèQÙ¡/®éAP³šàÏ5rÇ·f>p¬êvÆa°v-Ý7êžCµH«ø~ÇÑÓ5\ä7`ïz ‘ô?§[’eŸ<\H Kmtj"9í0.%OÀ:O¯:å<~Añ?×Se1]~Q!6}\cÕ  @­çW‡O,/? MÔ›Ze;îa.döLÑÕÏÝú“ä+4hÕ\û“QB)ŸþH•^P³|Ö‰S…ÔN·…8ߣB¦š&XxNéPb3£h ó¢Ê]î70,¤¹ü—Œ±y½8ò­Øá ¾'ƒY‘ƒ- ØaGQaMhr"ˆ,옭ÖÔ†¤Ó±ÞÙÛËWj“áöö™C ¯(’ ªÜSžŽØ9–ÙçáPó¯ÕëåXfQC“°ì1îs„ñqyUì× Íäö ¦’û2ØÈGÛ e2ÑÌ]®Å›hèÂ[˜ˆøã³¤ÞRƒ¥!_}™ÐÆŒœÒ=,ÃCY¶MKJù‚<ƒ V´¡°Í¬´½©ÍE«Y+Êî°àÊ—åÜ÷Œ‰ñÝ€ÿ]'¯¨l›%4†ßw&¨ýRÁ8-Ã(¼¾[øCÐ<Ñ#Lþkò„[°g~ë±Ì‚·Ì=¡5 †!_V|˜½DÌhþªÕ°-‚7Ï}y¹¾Hq£Àwö-8,Û’€€µlPe-­ðÃÝm:c)Q‘@Á0k[4ryžjvïÿã©`λI;òŸüu·”%»káÔ› }@½·6]æ|7íQ¸àŸµsrI«õŠ_ò¥5w¹ö…iiRÜšµ¯¦_CjVnP#*_%-ä)ÊMÍ)šaަÞèͶÙßC N@ºyxË ÷ç$³µ°@×Ú­^Ѹ;œRtVŠû@°à” u¦ßêYc—¤xe_èrßs ¹ /…ãîïy`cþ‘ <Ù•tRÎŒðŒÁâYVÝWN#"¦raÈ´+8'Ne')böˆ®ð@ ã-œ]«æ'$ê9`Ë~ðÞbˆœöš~Hu5—'…ÅÍ=›ÑŒ¾!Š9x/—öm{úèWYÊç9ÊÀùNÒ÷øÌ{’ zšƒ°ï{æ/[ˆøq††½®Y‹À„Ô]ÔXý››Zõ9ÆÚs= ´*QÕ–ßEh§êv±iîG6r®­H0Òø/¬¥1e·!Œ‡O`MMÃÑ4D|}¡È;Ö ¿Ü»“J£¢3?r+•øY+!*±2é †GØGͬ]ˆŠÚmÖÃ%6œ?Ý|âÑÌMà;nÊíñ| `øƒ?½+\ ïZ¶#§oùÙèÍ-dyo þÔ´@JAãTÌ3gBš,·F,¬D) `Ĉ’€€½PÞ\”±ëK¦8¾V ùÆù9ò(í’-x Â#ƒ3K;ÌÎ"ßœ¾’Ãê¦óLÉ/ï ëƒUã_Æ;€‰;GAÖ$ŠÛõÐÿgÈÞÅÁü<aذqáÚÆ³§e*ì?¸bé¯pÍ|ºó¯ýIåïQCq¿;Oð{¹^\ɤ4bÔþB­ìI•(o>ìÌ‹ùTJ?mjê×êóm8³jO°ÊCß…-¹¤‡?#¬Už[l½NÿÆhã³+|6áW¤:}¤E]^2þù¥x³z tÓT¿w—XèQo®{¹î1„‚Þµ+#[`s툷0èN§cN)L@WK#ƒ_ß»hÑÊ ;½ÇFláÆw¦*÷b›'“ܵä=‚<ÛSX•ä+SöùžŠŽ¯©øUÆr&ø¼z3jùB†­×ËÜÒ@¿8±Wk_ê•X;ëEW¥…¥îÃ‹Ž’Ð¦ÂYd{7EÒLžÒÊÑCÝf$¿‘-nW @è%‰70¡ 5MNuBg@Ÿ1©ÿ<¾˜©AbÏ97 {ŸÎ¹êx—{ãÀë]£úŒ• „ }5&€ÃúãŸ|-åØo}(NÌN9!âP·ŒXI¥Ë:ºvõ  ñÐÏ|:ÑíMYô€¥¸d“Û^:D^sxØÏ^`n†¬áð v3c­P·«úº=ŪYºÃ?É Ø‰ÅâÅë¦ôù³¿;ÔÒh×s*Z“Ó?š3ú´¸Ö Ö¸¶q£””ƒnC«—¤õ¯únI²FŠÒ$.Hïu˸™ñV`Œl Õ—H³5ÝLÙ—='ÖXdr…š  TËú亙ÉçaC¶¯òŒæš´R|úC|þ²›ÝŒÐ½Û}sM~¨¦¶|–3òÆ@\gïÔqû œØL’г§(ú%@8çnp]ù.¶Æ«Û *ç Ô !¯À3¶{3ïÒÛ£÷E)Òš°´,Ç€©jSÅm“ùyQÖŠHƒ/Ë#7òQ=ÎoWøØ"6óÆŸzÁþpð~•ƒk™–lbczô)â@7Ñš9¿3^_Ÿ0øöëšM‹@k‹àEN J¾*,Õ›Bjrÿé {÷ñ&A‡šø y{ÓH!4Ž"‹xSÓOOWæ§ø­Ç­KJ—-Íé^ùòûï‡SSŠsŒ÷ƒ\É$Ï}.’€€×ÿ9?Æ´+Ý;H1<6?šx]Ýv‰Z«£Ínáô†EžÇÒ£•º’‡3$C»XqÎd8@µ|×Üs¾ŠÊ_%©8Ȩʯ{ñ5žJ…h\}>Ð㙞²rƒÇò.ö¨~¼p˜ á'²´>™Ìpöf^Pn'lR ý4J-ýÔ˜ý,qoxë5WGÀ½MÒ¾Aü¶ùа“–Œ›Êh`ÈþOhü{¨ÚG<@/JÝÈD_dŠþi¨÷dbšƒUûƒ¶lÁ£&r‡\¶U£“·D츜ÂqßñäS:––ƒhk‘W×Cý}—ÈmË.«hÁ#ä¥ÑìyÅ÷Èe­º¹êC7KG5XT¬hä}6•3À;ó®¢Ì aqÇ–¹.:á¬Ÿâ‹ÆÞ¢·“Â_.ÇÖ&»Œ¼y©=tÜP¯:c«W˜Á™Áñr´'H²Ê¡Â;zac*ìÅ•Û[ëèã%2°ÓÊÛfºxw5 ”´µ¥=»r˧îÑ«É5h>¡$Q^o™8m»sÁ)ê!ìY™‚y;<7NW¤íóDv­ðUø¹­ fé?ëj5Óyåp}\ÝŸò”d»’Š$•¼r9…'è€ µ î9\í•ó.¾Uyª|<Õß][swœ^…Fk½¨am’‰Ùìú¸abq@¯ß¢„¿%ëy¦a®¤'9Ý!^_\…=of{fîxÓ÷û|Ú˜,©«kÍÿ¥Õ>ѕƊ•š¥,9z‡šüs­C7š9ÕŽûˆ(tœK[®RÅ3呂±”M izb‰I£&SÊŽø÷&Û2ך²R¶šKßCòÓ®{éU_Cí]à@"ÀògÇ$J¦2LÅU¹ãV¹æ°ß:1¨ÑþÛB¦3™<Ì6®æ‡÷”<O¿k˜?ÔÓ¼ß)@¿è‘"ÃÑÞÓù×9m&λ<}Å´…ªäŽ ã$ñªþîüþ¢¿,šù/è" ž·Ž¼Üwûß_DžmºrÔ !ë¹£Ï8ÎðÏtéèù;hg’: o?%»è:aâRö¾6|¤çÄü&k¶ìwÅŠLlçi0)ûf­CåšþâCA¸É€W|.¡8ªcÿ$ª<œœáŽ”PÐi±½jÍ×ß: Cï¾.G••ć°b÷`àqÈEÈ’€€ÎZ‡jÕ¶vGY¬Iù$í åtÌé|?q5Yž õ1 º{Ü;þó÷>R¤Ë[Á䪫ȋ™È©¶Ñ%Þõ«W65H(¸j$ŠŸîj'’LÔxÕ„Jÿ]£§‚úBðö}I]_Ë´Ñb z6¶§Wà§‹IxßnupÅÏËøÔhÕ©áú¡íÈØ¯)õ¥G}±—ïâ×÷i‚—¿þ« bì@Ö+ÀZáÿE¦¨xÈëOß’É\ž…’*H,ê$< dœ³²†—@ÍC§Ü¤/$ŒGƒ®qÖ¼V…¥¥s2D·n)XzE†”2HGS óæÚëóDZ!™›º%ñpVlÔà4 Ð7ËZÏî˜sq(ñ½`RÀ†±Út#9{Ká}f½ Ȩ̈>Ugµ3Q®V¯Äl)]ž””wsÝ¥cÞåÑš£:jÉæö»W¹fZwçåªRÒãé|°‹Éi7’‘w6v ßVšpÿîÅÚ]²È©c»£f1 ö,Ï^–•/³ÕÀÞ8P^)PÙ‹þÂáB—÷ŒVIãnâÁ¯½J¦¡J´ÅŽÓyËV œä{ “Ä,nÞâ¶n"M(íL˜Ãz¨ Ë@ìoyæ…/)ñ±£ƒ™Ûª —Öe—Ðá?1·¿Dô£ ÖGü!èbÈ£ùÿ ôŸÙÅO¦ÑpJ»‚‚{š‡ïÚ;ÎÛâ FÁ ¢ÒÚ9 }i`çÓã7B"e–ùê_+V{ú‘S£ÆÖ4å¬ò!Âð¤Ýš$vÉe/Ákyü3, {@yåÏ?N¨2>mvÙŽ*w5¶(6Ê—Njݳ–yÜq›'fKÓËrMtôÂù=×Òå‹?Œ˜}˜&7¢¡yÊWXïm-ºUðŒßÁŠOö…^÷‚ó~ÍÜ:±ìbcEqyMÊÉæêðmI?”Uoo’$8èÚÌ€¡Â·'ÏòÀ&æ ÿûhÇTöl­0•s:ýÝ¢Mâóe:ZVŒ¯ð+ ÷Òï¾ii°Ô –h˜Ä»1ÙÁ hϘᘡ¼ÑLJ›>â{(‰5=ǘ &Ï:¬÷nËjäþ}ùµÞ(ÿ{õ•›<¢U ‘w^c-«Fue¶É¾ ž©/^€nUÖ‚—•íjõØZ¡_éno‘ĺúΡ{rg’€€Ééùc½°{=ß+5>Ê©UâmßK1ÿèêLô hW߀iˆD‹_žõˆ‡c>RäÚß{ö2w“?“N ±!_*³` p„xR¡9(Õbu:ëøÚ¢0R&®:¸ò™8¢‘)UY*°¯äÚýÒ¹pž¬œoß»Ìi篓”Š  v틵1vþ¯K}'ãùêÍŽÏ«U÷Š ĵ¡Ãtstÿ2~$ñæ4sÉ£~mò3Õ^[g¢ñRqIçÌëÐB¿ŸDîÚüü%Éä<[?a&Tl¨þ•ÔÕY²’ZClo¨…s::®òRy¢Z5µoͨÂp²N}S©ÊwÀ?8ü»ªÌmvÓè¥/v‹#íñ¸LB«fÂü>½cq×0ÿ»’©.i{¥3V¿kSÚý–Ÿ„²06µÔUUíœ/ªym(aV5Š>M­ñ%„n:Go‘ƒt!‰|9ª¦Ô|¼÷;}|äލ+vP{Q‡º$;¶†ý`Pdöa›,ñtpÖVØ¢?«ç ¦¡žg¾¿&‚ b3pÏ4̤5W¿ÿÊä.¼6õî ‰ 3ý¥^Z+Hu:ü5ú–»yÁ¢‚‡¢ÒSF<"D.ÒŸ’]"XW…±À™Vd¢Hš)`-íü†ùî©°IÏÔaâý ®BAŸP:‰«$*9Ÿr_À÷s'Ö–MŒýÀnw1Òà•Í‚ÔX¼`[tJCÉy{ïŽÄŸH…÷ëœ$#öˆ¤×‹ð¼‰{}eƒázØþ|Á¼Ì”Nl…ÚVlŸ²¶o)F¤ÜýŒlÞ?q©OZ*IØ”qÖצ—ÀeÖNÚr¨á5¨ôŸÀÚG aÆÖZµ<À£ï˜ï¦jBã¶S/z´þàVƒº(°gÍŸlôI~c>œÚ—JÊ+c¼Ö¦æÐÙtÇE…ˆ|ã¹ÊE(•¸À7ít#ïނŇSVÑÌ °(©Eq™–©…tª÷éô¹e±x¨„Š,‡¦-£¶ã~"á?:¦yզחðÎÝO˜€õ£u€ÏYÆb%’C£k\ Xk±†×ŒÉèwù!D#³ö 03æVLløÞîáZeÚ—VÊÍ ÍÓî@djŽ~ÃW­¾éÆ~üqq5‹¤4X‹Rœ@¶cÁÃÄ—A?t’€€Óê4ñfÜÂà#›ñ8©ƒ2¢¼°¨¯`ûNiZeŠSãôÝS{ïCWº*da"áíZMjƒ5äC ”cb‹øüXs§v‚4TY Š?¶Åê‚|ù9ó´Ã’ £ºYè­¬|щRÀ—‡©Ìaжª$èªo{ÞRòû~™ÛLjƕЉäs ÷õ†9l)ùWÏ2þù³×E¢Kn¡Ò[Ý ŠÛ *bZ5ùtßï€GµKôÁN¯kßB‘-b¼Â ðáûÏKò… VÅü¦W~BÖÿHšdÚû‘þKš¯ SaL§¿…ãÝœï×xð„®©ÐMÔ¤²P¨Ä¸ízã§ É[4vWk?Ó ùžª`¿ÊzKÈ[ “ünljÌÅ /=G|Óñ]ÒÍ6çù äY_þ@ù”Liëf¾œoÜ”«aèÛ^*jáC‚V2"ÓWCu†ÃË—€ùB½/+¿Ž+ÚìÏüµ+*Zå3oo>‡]+ków-T ˜‘¼[ÌÅŽFnàéFuƒ èzMs¼&ˆi:XzœØÓÞ)±uÄúpâ/lî†å-ˆÒ{@"^·xdNbÓgÌáøNžÉ¨Í ÜE%¶=„$ ¢aa¸êýÂ|Í(33ÈIÞCö©¡ô@Àb>qÑEÿ¡&&‡ÀU¶Ú‘§RXn:­njh øÑhÔ2òúÀð^<wµù‚1ø-¨™1•üñqK¶•&p ,TÞõºÔP‰z/ßµe‰ƒ—¸zヌ"(&÷ïo¢½ºÞ}TUIÿñy_#_o|au0ûò7Gé¡ CPãjO+ºhº¿dä—âw|(޼5ÀÓ錫"&-¤â4Íâf͵¶ÿ‡˜óJݺ1ÆèÓ†,Y{á®e’€€Çö·Š/: ¡›m\ºï'©wâ“’8‘-ªéZ\wéˆEêÖÉŽ ?“ óãåÝ‚œ‡ãKåG2%b‡ØYœ¸Þ˜RÝóœÿXpcÇ墛:Éß 3ÕÕ—;ÒI|Ž>WönNïÏéØSêlÉ‚Ÿ_v wHOOqY-®y76Â%¨tBÊ­]H91sDA_øØ >á°'˜B3é¬r “G#Pᣗ<~,ÑñÐðhEY‰nêjíÆ ¦úÇK,rö…zx’Y³8xgz·1ÄXÂÕNÆ4aÚýñ!‹¾ vº“’ùm;âÜv4¼•†$2¿ù ŸkM ¾4hiMì±zø›2gCˆ”—²÷üQMòÊ<“2·7Ç(Èc±ÚZÕ#V´4œv­hì¯W¡/O1¹ÇêGuj¹vËÓèVGðâòžüÕøoøÔ&­òÉr‰0ú»K‹TrŽ›7‰ô˜8pÀ ­ï)#‘øy½çÝõ Ès? LX'àÃ\C˜äˆ@Wh¨ÎSøÓÏ’,€€gÖÈXQ0ôíáU€¬Ûç覈ӰòaÃñ/eÁ$û®½M¾z›ýŒxC(ƒ!Úka=ïéB3t¹×gç,9qü÷OOtMÔ;¤Ö*㌷øZ íçã¯4ej§¡yú+ŸW'Ö…8–tº[._Jü‡­pÎÙxø§[Vƒöù¯Ò œ0\¢_f8|HcÄú篋\&nΫQ^Ë)f)„!ùÛê³îÑà©"ë2Tw‚|€T à# uÃmðžøhc‚ül_ž9H·µów3‡àÔø «áËzÀå­Zobl*èX,Ë „žÞMx˜N¨Ú m¬6Ðä¦84$s’ã%àûÕlMv J~Y²EîìG—ÇE¯ ùÅbmäÁ°,²çëð [PŸï»}ãÆí· )DTd#¥öË<ôù (ÔƒX„G‹ŸúX8˜Ó÷ÅòÕã†|-J°Q9"¾–’ñOëÕÙ­çœ!"Ú®¬qjù‹~=‡=í½XÔž€ã¼IÅó†ýCÅÐÊÉæJ³Y™KUR¿6pþÂuŠè§:<ŒI9£éáo’êŽË®ÃßD‹ù;Ô½)yŠÐ@™Ð(4ëN'’€€É0ÿÙ}–ÑKûñÑåTL­ÐtTþ>;ݘ(BÔµ;!æÊr(ð$Ð7[äwSl##ç‡Ýe”43ï4ùå{€Rr‰È¾U¢P@ŸÐ >¿Íèâ!ZB9Ÿ«µ¹3% ^yezØhX0nÐjÌt9¨œq®ù¬¬«éRƘê6‰Ü±æ®j×ï­îá·æO¸×`~G9¬÷íCY®i1ßyh^ŽÁù®²O‡nußá™Å±Ô2ö“<à$_&ë*´}¿¯Qpèæ ›9«\"ZWÓá›g'}Qö›Â…‘ðj~©Œöz“rôƒÓóšw>É©`½gy‹B[y1Õ9£áá ª…(Šå!à`Òy É´8^ùj‘aîA«@ÇÙˆåiÛžÎnÁ Þ*¤è«q"@j¸õoðHjhìµÒXËD¬cX»éG˜·¨¸Ró)ÄÈܕт&ÓåBhµØÕØ2 ‰0ï]B¤Að.ÛȲmñÏFüƒãšbè¢&òŒ({Òq£Â爹þS•b‰wzXuË‘¤ˆGLÓôVÜ7aŒ}I»½3ê[}+tËqÿ´(µ‡ä :Š?­5‚eqðûKôc…ûƒë=zPÆÿ•„©â÷(ß?•µhù/ Ȱá‡>²ù¨Öô8Ú‘ìL†èû fðmÑÿ©s¨¾w#£ð]þs1–'NR-„÷lÿcÊ.ssF"×_ë2Kï²¥ 'Ö« š¿çX…ü²¤µ¢½´¦ %˜U¢Z¯áÐʹæ·Q¸nêŠPº-Hm¹|ÑËQ[c°'ßiWœü9ðãÛ¾±Ù÷%ɦ¥³fr:ZÔ9¹c êV6RòyÅ×øÆ&g¾PqêòÏ’A"S>£iGµbèôaî«d•£FWb$ÝÞ»ôÀ·ü€Z4ì›]ŠáªÚÆ•õsP“*ݺâ«BþÚö>ìë°p¸´•Ï–:ÓdjG.Äê»·šô S‡Î:nAT™~FuM `þbV<ÿÏj–Àÿübµ†¥|I“*97ÉHJÇÊ_n¡–YQ¢2 9Åsd¥›xJa“H¢ 1óQ-—y»>eÆÍŠ•˜G ¢à¨)].P£—¹§‹˜Ñi6ÌZƒ-!Žr.ˆ²Íº=!«{{gq’€€¯ … çÄ}žÚº¬E«ÕW„vù’ÿ0\”…°Â#e‰AÆ/!Cá:ñHØ{ÀÀg ¬òûvš,apòK«Y³2”‚½]ñÂ{–ÆíOÍcFRa~é§¼wÈ~xeªª°”>Ÿ{sul '&¶žQÈn,8eÐqøÇÓ §ýñGA×ÈŽï»Éý˜¦ŽGDá\ïƒb¿Ä¤©‘=h —›qs×@þñ¢Z'EEư<¤¤³ÔÚ¤FóÚž5<™Ñ¾å]õ[·ÞéSÍ["I­É­×ÉÑ%ØVWâ“®E_þäÐ@û ÖH2)?§@× ï LR’®æ2#þ¥ ™`SnûÌöÔ5É~ç?…Èn~5o)•ç‰=hn–êN†XD¿¹>€ “W˜+} özN0”ÔŒÐ:èeUÝôK\^;,ÎÏyÖ^õ´÷­¬Â›t×–â”OPHÜ£R K–βh¹†œ iê[̾””Ï5;óÞ˜† ²jØVXš¢CÑ|鯖ºIŽ·Q‹ü{A³ç~P{X/BºˆO´4PÓw›à< ×A×8wòsM'%‘ ¦(»§Œ›÷ï=šòÔ¡ñÞÝ÷yž¸Ã(òPõl/ðØf—È‘ ”^¬‡ V—ñ)~l×Iñ›g§Î´{€P—@ÙŽ¾ Œ‰EFšñzSfÛЇ¸Dc“öÇíAê—”Âc?K·Š†L~«„©«±S¼7*'~ßx¿j>vZ&S˜JOÊÄ#~·Ñcò-6bÌš—D!¦]¡\ÕlÛÓ¦–YÎñTä‚· F—ÏE´a§gŠêÉ©b©B/¥¼bÒ¹,îc%•ì”ØLtÓùåfåÁƬçºÔ=õxÈgêuâõ–½—¢ëI‘IFáà1>&ëŠÔDº‡ï½Z†ÂÒÐñ¬¼Ü+4‹m¦ŽÖT¶íì4 Ö!Àvøüã H¾™J8~‹ÞÀ7¹Qí‡ùMœeµ¼ùÏ$š§ýé3É!XäÙ‰´Ýw„GsD~ÍÅPN÷ÖU5³…&@E’€€Ï— R7©ñLÚšdÌK»Ô¥#X[«e£7Ïc°{ü7)YÙ1Ÿ¯8!xk=nÇâ+Ðñ‡ø¬¦£5íE洸ɽP0¹.N=âÈ`_#Shápíñ/+âû𔏿æ±i¨¢˜QWÝL-ÿ6Ç/˜” Q5|ÖÓ¼“w¥p‰: êZÐ6»»î.Ëlí\JÃu²,0ÓѾ[õÇqÁC¦¼Š·w)²Ë'O3AhTmGsØKêsây1ŸAl¶bU¥NÕH2F~¡6žn¢e·Z=y¸¢ùZ©} ç™á!Ýž23±»'lbóö5ÐÓF„68ò©}ne"ˆ û¿ ›ï¥ÛlÉÙ÷@%xJI]£«4ü•L™”Él»ÿ `"}Â&[ãý[µnÒZµ‹»º:%Fÿ®-x€à¼g»1JFæ1±t¹ ›»KU>è›tàÿv©»†à…æN*ƒÚ‹E7ú¿øêäÉÏÊò­thwÿ¯,ÒU„p°Ä¯èúÞ_(3*MGÏ5*dÚÚ€œ‹Èª‡y-.d@ÍGMO“_³\¾Ä zt‘×(‡3¡È£÷ ¯#;Ø ÐÎ8–Áx¤Ü³Ý^ÛØÿcQ:ŤÒsÁ5Λèñ¾pËhûfïF»Næé•wÿeõ@ž}“þ¶ë˜AæÞŶw=Ü»ò’€€Ø’8¼¸§:²KR|.¿‚÷Š÷¾ŒçÅy|½õ¨×¨>… VÍG_e"§´Ëíxj©üÖ–¨½ï¾Ë–°7O’Ú%Ó‹€½û…ûô™XÛ¶ðq¼qšäe½F!€¿\3Y‚|ºÜ+G¦Ì%ð¶ Wø¹—ÓS¸ã ˜´Äà¥êF>d'žê·šø#–¡ƒ^‡^<€LFÛ´k¡ͧMõ¼ˆ¨µ·<©o…¼~E&‚H!jnùæSÞ2˜rn .u °Z=û石›NÙ@¦›·Kìú¿øƒK\sÜÊ4O Æ”ÅA¿w’ Qêyëg瞃Ôï‚h` ­ŽÚß6ÆZ ÝpP $ þò•IVéÒdä^hp›ºñJÈø¿ Äþâ'÷(/<ƒdbèªj¾t:MН0AoÒë 5.lJ!ŽoRŠz~œS<Œæ&ºÃ¥®O…‰E„¸;‚@h.pjðÁý\ò3]Û+¤N?‹¤Lëa31! e:"ŽÞ¯C^¼®(]˜·\§¡ tâöLì‘— "?„Ž‚­ñçð:ÐPl¦¦[äÇës H@1ˆ‰„'ê“ÙÑB¯{ÿ`%ïﻘêï'{–z.ÏAJ²Ê‹¯‘É9ùhE£?ú}‘ àg^î9ÿÚÓ?ˆãÁaO¹Ÿéf¶®­ÑC!ƒî Ä\Z|“ ®J3ƒ|­÷FA‚ç[Ô9™m=ñ”ð>S1å¸õˆgÄꦽ×PÚ ôMƒ™¨÷ r¦ï¢³ÄîHp~hW»µMjЈ.²,£müÁ]7ÔåM§Ã†*},Ÿ!È!""™7 ]RÕÛ;30‹kfüŠå*²KRÁäåúÿ8j‚ŒøSØèox`ƶ.±äë­•1Óš¹ƒðî„fm‡£p¨GUY-ZaÞÁ¨Sÿšw//Š‹y±TG{‰6ÝÁ=¼hâÜ^Æràã-ðR5#³y«É‘P,¸­¨’€€¿²ëÕ¬}Ó}øw]ÂmI,j‘ÉÈm#ôÜ\â4)Ûl¢¸_¿N»çW8P-ä¡ú¤$ŸÕm|$ä‰fºo[ù‰EEBE½•BM±‚·÷™7©ÀFgYt§_ÞB–ç<©SZ*U³«j{ªƒÑç&æ(¹A‰Ø#ß °$g»ÛÑ ‹#X5ú³n)¥…½q·Ié‰[¯ðr>äUõæ‹ @q1ÉOωÇ$UìÔ6„¤as:ämCÛ‡«ª`úætÛ ¸Ã2­” n½[Œõ?0 PœOéÈåufFÌz^WÔŒ;AxLŽ 54wÈ@Ô£yD[î…loè5RÁèúô‰+ÿï׺Y×¼Ô¿`ª: Ôr;6$èéQò¢{IÀšËahöô‡·]ùýQ™´ž ÑÈ´†]w߈cø¥íóp™÷¦Fu7ÔV—œK†Þvj‰°¢·nš[¾ÆôÔBûx×Ñ7¨ ¾Ãp]Ÿ˜Î[ËËAîqç"]¡ÿ©Vu†m&qy «µNÚÙY ‰ÞT»ãaµO @?ç홯€}ÛÌ1ê6½¬hÒ„˜Å6 ÒRœæoSšªéF¥‚ˆê1æer»” l–­]øº|Ÿ"µÖþÆÕoðŠoµ©ß0t… ¾}_ÖÐç~GÍÏ“æ|ÈL˜¦=§DÐe¾r­*¿‚Ï›Ðø?F²)±}Böcx]l é[¢NóÃäHž¾láÒ_;*pWòï„Óˆk¬c£¤¤¯–7L+ÏÌ–†}ë†O*±ù؆~å{OåëÆ%fbDD'Y†€±0¡F‚UØTÍÉd ¹Žû‚Sœÿ(ÊÉÔ„]ÍŸiX€‘A[ô´†tI‰ö*öiëxdµ¶]Š@K~dÓÐjÈr;> ffjÿ{ÞAëµ7ñÕf‡¦äJC24!t-‰³µÁ\3ºC§xÒO8(kNÉoà”ÿ+Ìà•o"–ÈÔL©B¯ôé®ò§¨’€€ÚŸ³_ÛÑç{B&8˜WéáøÀ EÕLåj@õ‡ªгaû>!rŒw.†5¿±Æn ÒSدÝåÕôÖÀÉíƒ_kÞ0"ÍJT›'F’Æ‚¦¬4þ— "Wõ¦–ôùoóÖˆ`^këÏ>Z—(u#RÛÞ«âš.C“¥=ýFßÈéQmÖj2dLnÑa1‘¿É10–%+Gîâx—É—ÓäØYï£OÒdSì,˜—°ßÀàØ½ÉÁ,l>];guüÎz;l FH"‘|¿•LZ®{¼bIí\«Ž—Wü«±%24¹AR.Dtý½‰Qzu=”B4؆6jýið}M{¹9æL B=U-cʺ_HÁ1Ê„ó˜d›‡¬øR»šuÃ6ÎØyË-ü)G°'—ógñV¬8‘ù¹éÎD,‡qGþ· YÁqæ¥ëÈ$ãh‰º‘`1J÷ˆ?Dm5º·×Ì V¤mq&!ÜÜ®zïÄû¼S3 ò0%â‡/`à,~#”ÌØ²ÝïCb‚õX^ª4é'n"|r])óy¿Oí+?jç÷kÆûbîæ©CÓª 3^Òœòí¯ìÆeÆúìUS6L.ÕDÕ¾ rMNÕœâÿ®8ˆm+ùnÚL{~‡U IôÉÆ¾Xþ ƒAÕÈ\w›4­AK4~_éC0r7ö®Ëx¼(@0Ç©ð®ÜЦ(œ§¹:ÓiÃC×f„2ñ¹Yw_dz_ p E$ ÀÀUôôízŠ\ab`õ÷‘ð°RÏ4¯±Ít"E¹1é[¿c]öq÷®LYÇÓ$%<_ YÍa|pm£@²f*Â絚^ÁQ ~‹ïAx5-µù‹Óhb…ÚÄhríú!Äü¦jxS\ŽÇ.ZéBË^ä÷R$#(ÅÛ÷"5PŸ‘R¾!.®yž|9êq ›÷kdü*ËÛPÎÛÓÞÈÝ›ºÛÜqgûG&Í–óg,úm?‚í¹ ¿¿Û;x²|Âg‘ÁhžXƒ*u^y„ÊL/"+Ò\[¢ì³Ìc K^µöTJƒ|0ßY+³¤§ÙŒw3£gvÝ ZpØb`&Àsª»Ä'Ø7Ó} @œ˜²¥ßow”ÑJCžÒHÍ=ïU¸ ï²E“д^üy¢_„àF™fzeý¿õ”J—v´Ë¿§\.²”0Ý®õ2¢‡×þk§!<†ZÉ$–ì™L©ø£Ÿz˜#!DfD”0*H¥$Ooó| Ö}ÚHµ‘£Y:>ÜÎt‚©h€„ÍÀkÔk™´¿§îSΉѽ/É2¡È TÕÖÑþC‰&pHÕ¹@Á qM¯ãµu) :+^^‘6ỪXË0±ê 0Ëeâ–U׉]åé0!‰ .Û6Êy2×$—Ÿ®ZF½¾9ågjœ–>bFu깆þÚd˜+aÖI‰¶7¨)3€r³Üê›Ëû5†Âšq1í­™>iÓ)—?–Ji‹‹C´¶í‚ Ããk„ [Bi¡+Ì[Dð™©qM?2 DÎýïÍX&hvÓ$çŠE~?NZ™Ï ‡sר=ÝuØrýë¹té…Sôä’¨ïR§g™ÖøZ¨3¹p »àM4Ì8Ð#2€ û­I&ôA"äÌ’yìþiJ¨3_?ûpÆ’€€ì.®ô^E i‹>CY¨ô`┉ؕmÏÔÃ¥nile÷þaRó´gã0Ú´/€ásn♥¨æØ«Žñ)ƒ-?«±á2Žg’òRß)´ïaÕÉØüªìüÚuKL…|â“ßÿáålÇ0i ÛçëHဿT@–Ë3›\„oùOΆ-ô÷5Ç Db‹x(C[ç?Ly~#|»M{q? ¹wWG kŇÒQTš^£Ÿ¤¥2hÕïF:¦á^ ¢o¶[ëp£¤^RBTÆ§ŠØÒ×з2ÎÆ=+ž r=.ld"d*Ýìn`#®f@àŒíJcÃTï+Ÿ“Âñw§Ë¡©²³<§a¹GÆlÉðWÏN@À:0nh1cJR‡ï>³–Y;Û‡M dd.iÌrßZÄý˜ÒÉëŸãøB—•«>kþE–x&U̱Yg>xªÎOº6í#õ;&Cvó?*ôË-õet=®t¼—!…ZûîxÕ&<çöPBûða|©0v‚„W€¿á&˜‘f†g0‡Ø¦}áã[ín¨MÙ)”çW,îêÖþ‰ý”uá[Ì}˜Ÿ4{ÑÅøÜ ˜¸Ä¿1Øã O7ÂóµT.p_BFC)—8ÀÍÖ£h_Ãè1±'ki ¶§P©^ÀÊ' 8èÞ nÞª‹L!÷öÁhñÐcƒÇ&èÐã”a—Û]A•,XAÖ ¥)uà‰Ì8ÄÕ«ÄÐêR7Û‘ÐOÍ`À®÷éŠ8ô=TÚ8‰”iaŠN å}8÷ÔñhŠWv`ͼòE¯ ÐêabX€¦ÄÜ)(/f“§`'jád黯dfßuíÔ$1téóÖ.Ž2ûª¼ŸÑÈ/9Èc©Ì{Ìö~¢ÓvW…±'EÆeêO…9N: EíµæÇL69Ål³¸=nF| N-Œ¸ÜtÚ'>i¬E“(“·Ä–¡1rê­üìR˜>™í’ÓØ`‚¬Ö¸M ‰Õ/ežÜr¼iš^#q;Žv„úË×›ž¦9ñ&ÉoûIo–PÆäÃilKõÜ× ÀP³´H¡n]P7‚±ü¾EÔßú€·Ü+‰è·Pѹ&ôpzHÝ9±ÏUF„C‹(©?’åΕðñÌ7Ý­7žÑ«& 3ö(ƒ8÷£&÷‚ÔvKz¾L!ï’€€ÄÊ•TÉÐS"?é¸-§Lñ D}ÇÎÒõž²­#wM½¹¥*†Ý<öþunkÙ~FÂ(ò²kß=jBVIXö¥B¦tC6¥áµpuãàw”o?GØÿ¸î(b>Ф:+säo§~-±!_ú”Ô=çðnãau!ÿ¹„•éøl®Ó[ â‹k.Âøu0¶e‚ÄÆ~á;yši’0ú¬B1ËCÅÆjÁàûwáÑ æ´Jæ-Hƒ±mLhˆýꈼVyËa¼ðÍÒ¢Uƒ^£å‚f«»+böò亲꾠}ôwe:ûLsp:ÍúòM¾oùs¾)ÀWêt‹IÆ+ÉU”¬¢bôjWBÞ¹&^êëÏÉ7"øÖ(“Ô­p¤ÉãU˜7‹âÆSéeg4Ò2u´¢šô~lýMgý«%„¦· !®íª€¸x¬Ø+qÉW.´Ó4ן£[½ÙÝ®ÿèîÛ FWÇa.ûQ¹ÌÍJâÑóáñsM©æH×s…Ž» y–§þÛÈt¦ÿ§Í>ã‘°ùLܧ.ü—ÚàÁ­~Ú´@Q‹’à(¶šzÝ)?nÊå!­üž7çÊ`ùUÖêûι,z³,ˆñò}b€l oxu3Öåò pÏ’<î: qk#ƒÉ<™ jΫ‰Ë’ \¾œèW|T¼MÚÅæ£GFÒåÀYŒ«æöëûÆkò-uqMF#Ìl›(Úü¸·3ü¤™ò•Ÿ¢'ÎdŒº>j¼{‚Äç i)|ɤÁøþ»þðøü‹3ìwÀ=O=ÙO£Kr=_¶5ü0{ùVBf At×Ð-óK1ÍâL4óªÀð`{ì…™–PÒ¹" ,˜IXàkšûó»óe7ûgkdÜ"š[Ç-C´d²Ázù_ ºà²!óƒ‰%ÐØÉ¦‚ˆMw"Ú\í¯E¢fbe´›EД¤ËšŠúU-ui’ÐßäæâŸmJµ‡Þ“uFž:|èiçüg2Øx²Ñéã'ÏV’€€Î–ÇÖZ·qzb“£ÿ¥ûŠïðèCÁ¾ >4=)˜ú>Õ>±bß’qŒ l`ûó£¥¾F*€!è]v¢DŠ¿@1/nÙý1}é†>N÷¿>—è[Â<Î »¼ä“4*ÑjÒÉ$lÐynøÊ·¢b¸Ç;Ƨý×7æžîg®Ë;$¨Ò uêá‹iAZʤåѹǣ9O„œÜ4r™´1¹[pq mG´þ8þx»´ þ»š×+¬Åˆ4•!2à'Ólª»$Ù$( qÇ$ –@ýîiaiƒü©ß1¾Ìa”³üñOÛmm+·í sùÞllÒïC ¦‰&DÝ̳¦øVœÈ”¢Ø*mþ5mAD‘#4K\–7=ÏÉéS¡I·G¹R3±\OºÞpak®tm@‰ì ë<¡"Y]ÌSíü ÁQoù2!Þ|”$ÔEVnIÄn³¬çŒwk³´ï 8ë£Ï³åö|7Påº&ð¦ÎD3¢\">’]ºŽËWsi Ouî-•/Ƨ2`„ÖÒDô'„x+koÇ:)[[ëaœñòè×óà,Æ£:mõyúòz'‹É#ZTÐ"b]Î"CÎd¬ &-é#yÉ,lï[Öì±gŸû¶!5ön3ij2ºµù¶âJöò2¶fAfç¢mè’€€·=üK¨3iÒ"m±—{z‡ÁÌC(Œjg[f2Æ$)dMø¥Z–G%ú^òU %>"F¿{áå¼½*$å9¤öIA~JöjŠ«íYnvúõJîa¾Ë2 ô.ÜLšë˜ÒÔp´Œœ›øY/@ðò?}nk d㟥jé÷¾„WÖåÍÍ–}žÚ^»òã¥ÿ(ý|TSÞrkï%ŸÆí÷¨H*]aéþѵA[ ¼nQ™ÕÁÛn¢ìøúó7w_F™ÝxùcŽð•PËíÉ,Sö£¦Q­®HÒ_ Éì Ç­F6‘¤´kï]oÎ4•ñ¡.ž¹(A}by-¥œe})-›u»ÝAå^Ø‹„g³0ïË[ ¢gyƇlÅâsìª- WJ9éArØëP%q$§ëhCýÔàßß‘½I=h—”´4–VTÏSIŒ+ahíœ"²ßHS´>gR=/=}PCëZÃ¥AŒFEcEÚª×^y †'Ö1qÈ’>{yµ¸•éZQÔyüTÐÓ—2ûe0íóœröŒ´4§XUEYË$eÕpÅ—0T`õãÛy|ƒ)Î( ÷õ­žÜ1wEÞD 0ÞäúW[þJÅW&wrÍóÂP’âÊձ兤Ë÷µÃl§†¶h5ÝÏH‹æ¾g}jW!ñéd‰ÊÆ/‡YOÃÌz.sBf]™,ºsñ?$ °Gu ¥PàÉÕ äPÅe ~ͺ¼±ñTC±B ‡Õ?Õ0‘û=sõ·=¼GS¹É6{Åx)8ž‚"—Üîxqú›‰ˆ.b z,3OlTª0J˜k³¤ºÿû‰ŒÑ9pè¦!}Ç…Œ^†kEP,N‚þh´£Ìƒü l"ZLlÓ¼}M}öü ' ¶/ÒZ¹1Ë¿/ʳíõ3)ûZx”aué’Ö? *ûB–ÓE úP¸à‘'‡ÍkTøâWA˜üÒP£¥uíȸ$É_iÞ{™|ìâéŽX³žõµul>d4È–†ÕiÖ8­ú /ùÿî Z­ÀH^zã} ë&^{4¿aÙhB‘‰$žšé­¡"o Ðn§Y…²0óéKJÒ×Q5‹ŸnÏ›c¸Dý‹jí{&ƒ]5µáE„¥"нÌU~E-Cë꤬oÌÚ~#Èï9á …z,í gbØBÉZœéœt¡}D€,VNˆOú£ ›6ñCÈ«MS)å>µj"Œè§€r'ÖKj¤lêˆmU¬Wuªçº“)oë fÊÌóVâÞ»Ñû’ÙÖ_›Ñáaå÷ÜÊ{VuŸ„ACµ.Zëƒe»o‹;ßœ?.ùŽšª[nÜÕ.ž®·×iI@È>G¤ÝÌѽþL¾¼ µk³¿Lù×+}HÜÒ_ñThÉü,¦Ü–E¥Nl_ˆæ¬E³âÓPbm[DÉÉb†¸±YÙ¹BOñ1†FäËÉyd62’€€ØŒE¿JÍÔ?"þ5if·DŽlM¬•"SÂý_ØI·È&#g/¥»<¶òåbч=ýÄnš„õÄ ˜jæÇAû`›ÿ’$1/«“Øk7ü©’¸SL;Ëi«)Í|_òúU„I¦î‚û¯žÈnÊÖÕí.Áý=(´¸•”Ô¸¢ôûZk‹Û`5“³ûT ØÞýn½t:ûϵ:|{tG‚€ñHÞ;¬7cät?Öî¹HæSÐj³üh;‰óÅ™Úðš1ïC²–=3'ˆÙ™óÈAeǵZš™üNaNåȬT¨ªÃÈè…ç…êfý<ÈâãÓE°¿fð‹Ø~ã`ãtßcÙ0¦"éŠ<‚¶û° @Ë 1»‹E/3Ô6‹½ }¡— ™T“´ð?/þ?½\Õ"JçnN½9$è“?û¥}ÞYÛñ4Œ8X“\"_Á¨Ë²·šóÕ×Й!·æ,=»%pKMÌJƒüÎ1•³1@X§ˆA”àêÎVQ G0Ã<„‡×™Q.¯W"¶²ì0â(°Kgg@Ô>dÜä8R?+–Çž;¨ü})ªµŸµÜ©t*{G¿zˆ§Oq21.œÍF^\„ÿWCz»ÁÙ‘ˆäúr*ìÁä:þÃΓ=pE\‘‡h+SÖ}éïjŒ©rõðeΣ~Õ–b‹+QìŲiyeLØM¤ôSL…åh6ËA¥ø¬OÀÙQFö?¹¹$z»×\6{¾`ç&Ü °<—Êa3¡¶GJjp&šÅÛ2lPÕ,ø.RòŒk\H,€†ö5¼¡¢!*‰Î=é½2ˆ•"2Ww¡dœoâhäI8y!^lt5ñê"ažOc¹»Î4pî’À«6NumvDöÿDê a[` 51Yu,Mä>_ƒ^ Ð<°‹b>JjÉÄhV±ìüå/k\0»Å¡Šyߨ¼ð{-B4l[æqçpae%ûXÒ‘¼Ôgc”¾$ðÍQ»…Î)7¬ö-`pßéV¡}©ëøÏ€î²2ÁŒ$à¯Ì8c õ` »¤è"áz)I¯ÉÒ(ÚràRùöÍ–>þK ¯-?Úï´¿×úŒœÈ¥*×/ й=Ú b~å@éT7cË’ðy™f7ëdÉó)QžgóÕ¯LÓ3ùR}Â~·“&ŽTn-v±VƒO8!UîÃõð€d •’€€›ÏCM]cÀ8pò$º‡ŒF•å¸O~ùН%Öð *TÁßç»ÃÂmùd Í/ñ§çÓÌÏäGDÞšòZ˜;b¬çðä—X°sÐãï˜ÿÒxrKxsZFœâVÿ8µ¹ßdy¨9fC¬dá;߸9RWçPêF‘2PÝ—GÁ_scS9d¸[4JoI(㸫sÑÝXКiË‹—tçXÚ!áÄψpCUceãvaäM>ýšå=I½¹¬ïÝjøÀ ;·¾ÃÎNpôÓÖºKþÒ•3»ÈÈ$tÓ-¬6¦ÐAücÕWSZ]п¦ód†G*M^Ò?;Ýöèûõä+Y¡Óýe·ë(¤¡º1ºwiÙLœa¿7¿ö”˜-Ãöm)î‘`üìÓàÑ~yiN=wüý9’`— aÈ,˜XÞ¬‰ÎÇ“Tû½ÃPþâꨃëv6Ö0Ÿ# ž'w/CV»07ªòhÎ8²‡UºßmGê(É;ím}Ÿ$pÏà)üRæüÏ!ú$z'zÀA ´ø €Äàž²pH«øô5Ç2y®R‹SHÆÐn¢šÎ+‹\¡cˆ'SÖ~ë3¶ìð^é{á OâmÉþÂ\Pžî{Øà)ÂHÐ¬È OîɯbY¶ªÄðlËæÓ½rþŸÁÀaÙYàK¦qpž¿S/L¥„œ²üv…¹]ØŸÄpÍf#_.JpJÄXHÁÍ1’€€Â¾<á-¬»ÎU `q dÈ| å[‡25xïEd"'Ê'Yx©—UÅž/0ŸI‚`ìX¥£ç¿Ê×Þ”Ùe9Ä9otDïÊØB˜É›=̓Mr×_ªx„¶}'P°jX'.’€€ÁÙßXÙ‘:Q׉<Æê²˜¢&çèÚ=mj´üg)ÄUˆ/©?0@¨^hù¸ÔíØ{DÃ>qÇë8.†´òOÑGª¦OI4ìÇ„¶î)¡"XgVš+VB8’•ª 0€˜%å ‡±IFî†ß7›X4.@À÷¯cA_ŸZOæXþ»ÑŠyÄ»Ã>GæË{‰nNЬ¡;¼À#f XÒÎGuQu iÒÓ.†Œ†f Ó8Î"Å6-´›K .Ît8ö‚¥íbn§žÞáw”öO=ñ@AûIÖ¨€J dOŠ÷¶ÄĨ+/\ Ô&bÈrKo&ücçãíù|÷#g_Õ³Œ%Ùë?•Gy s2\ÌÞÎæ(›¥£ÑßUqÀÞ19›sG®z&ÝV¬†nûà‚æ õ²õÈBËyœ¶N7î¹è+¹l`¼ CÞ >8Rê*lÞ‹ÌÿôH蜘N75^q Ì‚CÀ{ð?ŠÞVS0§W"ôGžž1ôq«Àt˶§ˆ4Ýk¥Ø–âF¼o¥¥*Û™$Ptu{G–bŠÈ=ŸœàŸœÞ+n3©Ü7Þ3”}øPÏZ¢ñ…d¥´T¿g‰ÍMT d!:,©èVÏ^'ÊIÄÝU!xuŸøëô‰¤%”84óm$:^g3vD›²;‘"iZ]HAÇMó¢‚hÛý8X¯ØnÉW(žt•й $s‘[ú-û£ËÙÓ矖¯fò›y!ýÇÙ½³ˆÇ3Þþƒ˜¡Ÿ–­"×שž‡p—“P»ŸMUÙ©pæ¤'Y8œ——™nu:Ÿ5W~DÂqóµ/g!({¿ÇçlXˆýÈÔ<œEL9«²,Ñôí«@â„ò9ï=ÿv¸ìÓ¾¶‡±åd÷å”xÝÉ÷ ¥TU ÚÚ°çÜ:{cžê¬–Ã#æÎNó‹¨>yø¶@3m¶5×ÁœC…C°˜MT]t们3)<ð2LCÜW¶¾‡ðÌ8q¢UtÀEÞá«ú»œh½ÞÞèF/ÃZ}Eaû]©â])ßÔøPÒ)Éå©°À í°Kˆ?ÎFš’€€¼È>)xkõ»)E’.Õ!ù&Àk«fN³š?Õ’+ŠAÛ°Ý )IJãøÇQï`”RUþ~Ù".¦¾ùõÛÁvp[Åô‰˜[~‘‡mÜ6Å'Æ,yÞ·õIx *Ö)&ôG]…ÌT$8~ÑåÉ 2?{Yžï³ê«©@-}Í]¢˜§Õí.9tëñK ‚ bÞŽ¥¾SÇÁ 9»y«(/é£-±•rc›ÿ©…zñ£€kqx´Þït65êÑÑéÙçÜ^mÝ_/ÙS² Qµ7Äšf˼ÏφóF¹—ñ’1}²—÷qçPj# ·ˆ&̈¥´_+VCOò.ÍÔ¹ù`&?F‹¹-:ª}íf‹¸ïR}uêÓñ§˜âW;›žŸw)ùìÆ'Š ÀÑ÷0ÓÑÌXŸˆ2cÑïïÍ—³©×V›~èá°±ÖtNpËåG³Ü ?•.NããrY™Éí¦ëX Iöug’'÷ ïŽƒ–±‚¼Š“[&ø¥ëBïÈÚ;JzÉά„¢Tƒœ§½¿}•$ewçEâê»Ã„ø+ó‰ó:¥ÁÍÝr­•œAQo¶g6cÌ€œ+™jÕÅ0Ü´˜›í­t³In`˜’Ÿï˜ïþSO½BFå|èÀ™:dW!Žâ% yk‰‹#ÁùRns Ãkæ¼>—†¢Á–ÑQ%÷ ßäO£0¤P¤Xè§|áÙ.ÏžÅ:AîÒô{§!xN:¯2»’ñ¬ Â3Äÿ†‡¬K83¸Øîx ãxZºaûé9µ¼Ž[= 7hÓgß«É)D5錒¿î‰6t+n5OÅí{? Ÿx«/ÁÖ„…¤©¼o Øîå/â ‡ ¾F/Û‘A$ÒùY:PöÁ±Ô˜º¼8År¨·ÐçÚýáôÅ&?Àé +ÿóýŒ¹A¶ß½¯ù`ÞQvѱHd>&˜Ï†ÖÃók|uâ?À[ñ”¶óU0öÀ!|ïÛþÕ•r˜<ÝUòÖjü¨ûó 8±\ËTƒ¥a¶Ý.-ÍB]rfÎ3¸v”V³'O­M0·á6™ÂiF8Í¿V¥ÛV!ÒÊ”ãò‹Ÿ(\bBNá:á§It:z€NÈEd¾÷NÒdGŒÞáN”ɶWÊ΋­¸½!Lø°7@ Å‹Ø2cA–s1ªË§Æ£I•”°><¢¦õž]+[ õÞNƒÕc£;"{ë´Ü³³À5OòÈÚÞ­¡¶Lˆ«WXࠥƸ³aGÇÍ‚~;éý|Ì€>ÒÜ®^'À°kûz:  Ã¥“ƒûã’}†mq ét´­cñÚ&%H¤í{4öçvÔ#¡›Š®(ÊRbðâ…SÈšèßKâ©/A™BJÜÓÆ-îrno¼Lë£8îö w?R«§¨Ò£ÉšYlùçJ8j"P¿:Í Ÿ$þئ£œ¢s{ „§Åæ1Ðy¡]vä°Õ,îÆÓÕš—ÓÌXFVtÉMÅØŒµ‚"êÇ© L†ìL½æNpM$¢*Ȥ®šçÞke>ÄÁ¡2¡ôJgSZboAÛ…Ev¥‚ h<Òª>Æ…ÑWæÛÆëw•U¤6Á´Kà²E‰µŒ;*ˆ¨SÍ2í–ÏŒ,÷Œß㩬’™ì“ .iÆÌ_Œ›\ŸÍl `cä‰ñS¡zÑű ý´¹böÝ8ç!Çz !éô€’Ui}Â#[žUŸõtE¹ ”²–1¼ó‰ü§j 6[Ö]ÙeÏ¡Ìõ?"‘É á|@=LëI¡aöDg_I"ò2ØÎÆ€e ÃŒ0.¶•ûfaÊâ#V,ZÌ\ñã$¦»"TÓ]' Qz^ò³D ulùTg› ‚E?]o¹*×ß=ï×D¢ÇÆ$QÉin^¯bSG4’€€´Û.cÀÝun{a0ízaÆ)ë»@ƒä[ÇqæÔiÒ®±ÖUº qÈøLJÌדɛ͘N¾Á‹êšáz¢¤©µõí´(>áˆú)í¹¹X·9Í\××S¯Š’"c¤6ò¦qúoÓË©ƒR[3f{Tw;ÆG9š aŸ§àTÁG«Ê^ÐøÅˆ'J¶Š ²dj„–ÛkxÄúbl›k²ñ™†jQñ’` H4¯¯„Ò™V‰sú¸£úŸ§.,ûvžr­¾k„3SU÷É"åù´™œ¯W·:Òý4åçŒ6Ú»½Æàž<&‹X .ÀDŽŽ]5î›’liTÛ〓8L2Lße«i-5Q="(0]Š cÅq겋ÇÐrÏqÄÒÀ:”O?Ž » “oî@¿ðOIRJ1‡ÈØzYìïê]î¥yTØBéÏrsÿJÛÿN\bÀw„O³êX™–êœãn—òrÏÞ)¬Ãbàsq0œkð:+y—U»“àõÇg1Ìýœaöù™¹ùz‡½§"wŸ‰€ÍÕj“䪯ÞuÙí£MÑÃ.Þë7^Ô‚¿RiI»”®1ýc· ßÐûSÀ:€UV'wÅÍZ çßáhÔÙ¯¤‘ûrEôcÊE ú·ãË|=LæÇìÍ<¤•(܇b™tšD…®ÌO##8GLèB©°ŠV‡ªÿì°„µêTž§½ìÜZ|ÁRLðÕI„ßt!L~ú,üúýLê¤sÊö¢ …õJÙã\ ÆË;¤o… èû±±¨i¾øºh¯dò*ûe5Ñò6uA+󎦯dM«â úæcÏwt³þlUÅ’m/ÿ<5i®_wML A Ë©y5‰:cê൦‹G¤Í%©È¼Q…E-Ëx´ÁËÒÝ1½° :À“vŒ[)C¤ƒáeìƒr»µ—¢W…R"Sy®•ÀªZn‰ƒ²Ðz©yÈï§)VF´T!àŠM¨‹ýÏà£ÔÝæÖÐìȨbøôǃ»ÍLOd|CýKmÚÒ*˜ÛTnQRÓþ?X¢Œ7À­ b8'Å•Š*¢6ZFåÍÐþ×™/ÌzƒOfìõp9ûè­W9o1ÇQxh¯n­eND¬VŸÔqãÂÿ{J27F’€€ÚÎ<ÛÏY¬ÐC"½Dê‚nWÜÑu÷Íý¾¨Ôˆ&Týæ¾àUXŒÄ;¢*L玧<ÿ9mJÓ 0f1húLJQÆÓZ£çh>!ìùÿ=ÂdðÚÝÅï3l; æ6àæ÷%çÞ2ß±©"Æ¢V€IÊj'c-H¾_®"¼ÖRnüÎ/{+¾B¹Ätz(ò(¯é#TëÊSS$lò÷èë&¡õƦÛß¿.Øœ±¶<´ÓkõúMâM-®¦Í˜s°šŠý>ÆÏP ›o»/F3Ÿ±ª quµlðÞaïýSi‰•ÈÒfáü˜W×ÜÄüï»9õû@Ì{£†hXkñÔëf*‚-Û&œŠí[\ðü'hÀo/ø–[€Q¦0Òý\ ö‹p‹h›8Ó·'=Z:ˆbØ:²Œ#ÃeÏ„>—½uʱ¿[žH_“_¿‘UB^åâ=ÜÞÏ´#íË £6/ÔÛ8'±*+!úm´áÛvL*Rç1åǺɬ÷¸ ؇ÅýÄ¿3tmóM¡æ„Tvðy9±M`Ót6ë k+Æíéw ÂÏÞnBkÒ{¸Ïå:PJ»ÁŸJ˜‡Q‹³á$¾+o²Šœ†Rl$ üÇ2IŸ¤Éªà¦ÿ%Ü#ѳV]¤ô¯¥½úg`½º#SE„þÀ]è*ŽïܵÇÔÎ^•NaxÍm]NÚÏÃU¥ÅÓ#^}€ÝŸã]–ìŸÑMª›W)Sø\uÕ#vIO-[í¨ƒ¸ÐÑ›‹vÕ›jÍúB$ðïlÜú?ÒK[m$éKÑK‘… ²3»,A…’†s ‡[Êq.isÿ¹±yg•I\<“êWp„·$†¦m¿ñzDÞtA‡Vxëv<Ð ²¿Ø4}­Àüªˆ Ž’ÙR늧ë a#C&«Ÿ¦“œÅË— ’‚VÕt™ôšíÊé$<Ð5–®: :lcF%åÒÁ£Æ8ó ÝHÜ6w¶J`¦E¸ÔóI]l°SôiIµ*‡L¸R_ûlŸWßËÍq48ÍÓ²ÈmFxû•ž>sôB‡å;¦Õ OŸþYà}[j2×eaÆ$ó"ò7ïÈNçÅÐø½6ÝÉì‘cè‚`¸ÿŪlðvÊ7:(ù÷Ô¹ï$ÈÍÃÔP(í€/º ^cÉ{Â骒€€Ë¾Ÿÿu¬ ^‘ÐÔ¶@J®,àÅ¡‹£(P( )"[}Ä+i?I[ý¤TQ´8äÕN*p*s‡§½Šáæ(è—¤ƒÍuU’ÜôR]Í—ãJÀcÕTœí“àÂ7ñ­{”#<¶î,^C;ÈSp†!ì'ň,6bДÒ£`ðÞÛqgz‹îÐ`{TEÊÁªLâ"%¿›Ð¿IGcI™uY&˜&Qócg´‹çðÝ׉ߣ  ¸¡š~aizMño?ì0»DÂŽ™«$æc–L]G¹è€øÝw޼6>*ù¢¦î¡£‡Ëge3HÌÛŸˆœ†ººn𔩠)NŽ¥ åv6ÌŽk—†$HÓ¡6ð°imDäË8vKÝHg3ácLÛ~k6˪ðj64”C)¸\ßÈûþÁ¬GŽg1+éT÷ñ‡/ú iìo“ý±ÇÛéÞ÷(2Bµ©"HªÛ¥bÕ\qvrãëóu`Þ¬Sf`ÜZÆ—[ì&×÷Ép­Ô‘ðuôG“ÏØ´” )S²O³ñ™Ÿ%gˆb¿ú#‡¥ bãeìa7|2Ë ÿÌb-W¤¦' b^ÂŽ¸­’ž×êÆê‘vA5<ëøfž‘´­Tª0®ƒÈ[l'o&’hSŒ=£—ËoŠ€ªôY?kªnA0Xú.aPCR&ã\u_™×CÌœýtÆÃìjé‚esð§’ÏOc½ðw&ëCÜ®@pÍÅ ¬_ƒµ\×.SΧ÷î¾rœ ÛÕ—H_câÈß 4OÖs¿FsWÄoe5º8ÔzKü Þþ”F—‰‘uëáiGFéPÒWÀ”T`þ«Hß’¬¤&n—NZ‰ðìÍ_©rI’€€©æÅ.–&Rž±FÖBÈÑnA?”vWЄôï^9Ê™a"‚é5câSÛÄ~"Nlñ·#æ¿ÁŸ­¸©»ŸVEø@W[m —°öÙÕVsI–Ú‰;ý|9 `þ8˜ sù4…ÄØËØŸÉô°T:¯Ý¥ÖN[Šu˜7lÍ]ž7ÑnqO¿\—Ý=rnïªkËb*Y8‰þ-ü‰ÐŒa~è;¾{ Èèžç€mÔQö2ñz½Äµ?¶Áƒ2£ЉxiÞ0y÷J ˜J9D–ñm¸ï`Pbqv¡…¤÷iÔÛ×}ò^$óý¾†!Ne:Y);ÀÅ ´PðÔÅ ÎfÖÜ\Ò\i2Å]0ìB×Y[ßL@›C\ñiýå;™¦Üf8¹ÌÄs†!iæTùn´a„®|.Qg%éЦ+Uë„‘»ãN‰$óô_éÉèºÒ!îY ûç “þ‘>ys^! €a€ïPäkeÍVãrŠbHžŒYÅ"Ÿ·¸G‘P,²º¤‡âÁÂÓ5·³*~•¨ŠÎXž¥¼¥†ùN¦zVdëúÎÉ•û/kâžo©ï[Ôͨñ[P&63ÚñÃpæWs,švȨs%1ݽÓ9HlTܽPtÆÿ^ëÙpèöxÚ€ð$…«’Ú3*øtƒ8Sٜ͊ëÜ.\I¶:{ñ®•«Yˆ˜%ÒÿÈu5n7Ã/mPŠL"ö³­a:Û‡†Ñüˆí‚hòâ{e#boÿÖû)úX/Þ~œäò"ðPiÀÌ6—‹­ÚTáß‹5Ce•1R/Gf·twÖ‰ÿLj‰‚RõºNOÇß`?:÷£Ü^Ý|¡„ÜØ9›è£õ0ÎÀ±ª¯¯ ®÷Ÿ†1°eð;¯Ÿ²)° OG#]9Ì@ø«qôÒ5uÓ¼ƪPŠkØÏº _¤’”1‚ÃîUñœ£Ô•èmŽòHüã¥ìhÁ.8 %Œ**[Ò­sLªŽùœ˜ûÔGÞš«#ïÔ[öè肦´³v]„â‡øÔ|ÜÜ6Î5“e0BB¶™œGPÿM“[ÄùîæYˆ­ õø)pÙü2óžÙòç3».^uDCµt²ÒcW/³«óæ`”A’ÈZfž’En7¨2R¶˜#!—ÔÑ&sÂ-èµÁúOŸj° wÌ@·íßy‘’€€¸y‹†xàŸö3Žô"~Sš“¥4 ¾‡L¤QºQ)-ŽË^ÈH‡RÉxéÉò%Ïpˆ6OÌý«}ÈÆªšÒöõÃïØÒoQÕ}˜DÜhÐÁ>@cò½UþÕŒ ªÌVF”¬"Wê9°7ÃÄ„ˆÜâ¼äÊQ’g­Çè¸?g˜ì¡ÕBŽDÉ›¯¸Êæ8}(Þ¶³b­$2y-KºÝÏhõÉúélk&Œû$\XêIdå.W ¯²˜úw Wi_×fºÌHÓþõEK<-ÿ½jd O0’ªRÝ€ªÏ•léxbçS8yrLT1qhŸQÝ»P?X ¬' ’Ñ%ÕË+2w°TrîÝ ¢½O®’­QïÆá­?Å ª'ø“-RRÖ ·"Ï>5­„>•ˆ J–X4êÃt›¶{£…Jí²’ð1g—ìcж)ö>|ÁCð³ÓQóÖë¤QÊÛé*wR–ñeɽӾ s°ÅÛdzoÚØDŒ€“tÏ*÷Ñm÷LØ&-#ÉShÖ—. ­ª½òk‰sI z¯%E1Á¹8h0ÞÁÁòÃÌ›8«Û{F­£³kwÐþ`£ -BŒ’Oçš¶"úÄiÖ›rªôì6 ¶Àšsâ”ë˜wÅÒiW¹PÜ?„\Új÷ìIŠQ”\¨Y^Áä6élÞ‹”ãþJ²ž…pxS¶ÿu§9ùøMu¤üL¦JQqB‘b™mh2ôŸ5äSU›Eó(ÊŸaL´Š{žºæIc¦]YÃOb%Ê—$mlS‹¿QZ8Ü.ÀÔ)ïU4?(ýT3õÌ=‘þe!µºPILÁ³ŸROf°ËÎïU8ðþKùsœ©JJ828;gœ®FU™#.2Wp+í–üô€‹ÜÚvR¨ñ*/H€¶d>{wVyB¶$®’wÐfâÍꟑñœëÈxÉò%ÚÚ ’šÁ²¾ëZ½uØ.Èu´K1O}(¦¹Ø£ÿ:ø&ö©ž°ëMßósòØ]’•l¯d"ÇÉ]‘‹Pé†gŒ'…0]fíÍJ è~ÕË`Ѷ½£›’ïpRr8¶ت ù ¼qgþé_ÛǸÒ+.´¾ožÆ5®ÿyQuÛ“Z|›ó½Ú6¡å_ 1pz} ¼Î¥hø×L¯_yªW¶ZKyœkþïÈ ½Ÿ2#„’€€¶‚k>¹;ÎULjd™KhøŸ{1ªPαPwºBo ­»4%h½»‚ÒãZZ‡jäínóç% µm*\iÍÙ’Ï…k(íCŽÛçÚª–¸~Ž 6?å)÷Rœ©¿ %9@¸dù›ÃYÁä­a )@Ï>H?ÖÝïtÅÏ#|ò·£«S“´bAHBàƒ6‡Æø1Õ98ì¤:‚åh,ÅÏF]·âcxÃ%TÏ(¯)Úì„~êáÌX½§'Ûcº9œI,_X ÚövTÀ;¡þ'ATFŠË;*”ô`7ž ÛÈ÷p@'‘{œìª‘Išxÿ“WŒfîSÀÉïZˆö3è\[¶¿ 7¸™ÄhD}^$ ÓLŽ""¾5õˆ'Õž-ûÓ%¬pìÎ% Obp^H·Ÿ©Îêú!³$ 'UUœSë‚è‰FwgÎë5Ûv,Á„5J‡Î]¡¿Fx éû˜øC¾cˆð†É‡ˆ¯ÈìͰEÝ£çÉ.Ígø‡«o•í‚R4‚r;Mâ-.Ÿ*\Øü«Ç>öÚA‘¤Í±N½*]5åñ|nL†F 6Ae aÃÎL,ë÷9Øã¿/jCʳÁÔB>£kÀ<²Ñ¼|­Ÿ q ÎTqÞë+‚­Û«LJÀGQ01ã³Å‘æXz²_”λ‚'…È‚¡çnׯ’¡€ذò˜ÕÀX3›¦Ù´Wü&¬0÷Þ2竾Õw#ÎÝZtñ85XGž7Á~·çßÍð`?¯à”RJç‚V½ æ>НA²Õ²2ʨöq±~'£ÔF’s+ÅäJçÙ±ÛÚ5ŒTÍ…süJßôšCʦ¾är˜1ô^;âZ™¬÷ŸXˆ‹:¤]²8RN\ǵ´¬r±­$Ürìÿ° ;c•$©ÖÆñÆû¦ ø)Ó"Š›N^(±¤O—žJðJ¸Z1•>AÛ5@8mÌ>›èF¹U)ºª‘ÉWâ$"ßcß–“  {¼qF¸žž4‡Á€#¦ÄUü ªÂÖ5¾1ßj>@yó5¿/ý P[¼Wšò¿\3=ÊqÇ i7¢ûª¸Rç’â`%ÉŸ Ò0¯­XF™-%­Wf-*,—uâúS®IïÍæôŠ’€€Ï8­¦¯/î1Ïeû1±í68_c"Ê Ò@•àÈ¿]MÔš Z–qjµ§I‹æ§W‰Í»&‡%©m”ôÐuÏ ê»O_N1Çú¶”äG¦ÛõY„±¹ô¨°®H¡\Q¡f•Ø[(m¥¦­PÞ ìq¾€}¾~ªḞíá—ë­Ý3,HlÃ9ê´ÏЖºÚ+Þô+PØ%O”‰Èª˜Nª²áêöÕ¯º#£Ÿ'wqÝñ܆&øå VŸ ½äçË^Û¶ÐÂü¡Ù/g{¸¶¶f»ƒÌ™=µzbßè”5!ÀÉÕ„6qAÑã`x˜ÐdøÈ/â¿(ŽBf"¡Á/š`‚ôþ'㥘k%¼ß.÷a×W‰=Ç™4øGù¾Šã‚xR/‹Ö¯Ž§\Ѧp»" yUæîBoý†ÞþTúž*BäÊK õë@‘Dmôd’1:…¯¾½o1jÄœT%i²ë·âÖKV:îB ê—”xßM1Zаìù> r³-÷éÜhRÛÃEAŽº-ìö8²ƒJ®Cð…-Föº¢’Ò[Om’€€œ/:nˆ<匱ÐjsʃøïÔ‘Üë LÊRoÚΛêjͰ&ì––™u´Gìé&ePï<\ÓèÔ ¨Ö=çeõ^ž “«×9¦óä©ßD"´ŒuoõIåBšO-?r´L'B|–Ÿ#œ?kãDwú³1ØBsUµâdúö®bï‹'ý=è%gƒóÚ”Õœm~rvØç¥!Î+[›vb‹jݾ°iQe°x‘é&„S)*A§¤×ÅGáÈ]9#®™‚½…=FÊ9|]õ»Š¯h |S#›U¡j;°(%îZvú:í;¨)ÀEqã ±õÇ#F¼æ"ŒëĸâSõŸ:«Ú¦‹+AÜ.Bù0«&E·^óhsÜ’ |ÒSã-öÖuflfÐ SÊñrœ,âÀw”bsw ({V0&Ô6J­”÷|1[aòUrn¬ Ê'ô°µÕNA½]ôר;"rÃÚ¤U3¥´I¨d9^W$pˆ5Eõu·”ÛAÈâÚÅç„ y_Ÿß)†£³9°1¬Ï×Èø§ª Kºˆˆ Â7Y€’£7„×ÄÅõáè/O0ZiBÙª!ïYïé®{œG¾æó7î´ŸX³9ð–;cÀË9«rþÐÆª§%M˜¼Pz€.++ì œžPåFG6¯„ð~¦EDE|wžCÊÑà.Â9­ÂFM¬U­?<–íßщõ%ž_¡òPï…¢°U7¹ 7bäîàe&ùðL’/%>¯½RŽË¹\5ÙvÓ¹1ˆÇJtGË Â™r™Ø(Õ¿ p™æØ26C>‚·®¼„0÷œrËäI'ö¿˜frP蜇Q¼¯ÅßVbm™(²'ù÷íq)0vœbž«ïfl5¦¦Ñ³ï¨&§·îRs¦ZÊÌtžÁ6?çÄtôþ{û)6ï^çÕÐw¶ñhœ³šÁVß¡øk;/(@®ÌÛ9bqp±§õ<;c aç`@ý„”z+ßøQ%á´Š3Ô‚å>ÝÀô;·ÃZt©ìeëàë/lôêTÀJ·~³W2ÂÇ–p›tlwÛ1\»ççÿ"”…¼¤ñ ¾SR˜ƒ6¶Û¡ìà3‘Eà—$(V ünoï† æ/ë‰ÊI6‘w·Ž{®~K"Íùm¸ž­Ÿ ¨¨óÍ-z Ge?|lËz$’€€Þ\®‡Ø…S?ºí޶7p>BIs  1àÖ{:îîâS‚‘ÿ¾ Øq¦|à_¤Á cQÿ‘Þ|ÁÓ¿C®f±!šl4ÓyÉo™šöÇ:Xª´ñªaãÓjÒÇÇ™ ¸+X!\:m$þ»Êà*F7¹Ê¥îhâìiÅ‘¹Ñ5õ2ý]áÃ;ÇÃñ8!‰¤*··']Ž ¾Â¬‹nRntíþ(RGˆ4’0ñ1¬5ç´œTò`!aÉj‹ÂU]¦9?1Îâ³è€®0êꀋf¯Áž^ße‘±Ïçµ:qMrÚF<Ã= a )ö™õ1q¦¡&aí«Þ¼G.%Ú|W_àèâAð(ú©Pz<×61¿h÷i«û“¾–¼qV÷{ÛlÍÃ{êIÊÚ#7šk-Èe`q®A®"ë!£ÚI´3bAÎ^t /})}‘WôéQ^ZuPT_aX?tí9Ø¥®©BŒ¦yqC›düÞŸÌúì'\Kn8Ì~rÄkŽstc–»Eßöæß#Bt‘+‘®HÄj뜼\50m•šÂ'ÎùJuétXû¬áã<:öˆ4?‚¡½ÊÁ¦Ú>ŽCC4L±õ÷Ë©!Øÿé¢5W¢Q ’Èy„åó‘zR)pCׄ¤eçýæÖ©Óx¸S\0•ùȶñœYÞú¢ö&ñݪø wöcvûˆ¶Lá¶ßž¤ŠÂEQ_ý)ÄX®»-¨M šhœéE¡$ÂîSžÕ¬²ŸÆ‹©BYQL^ÐÌ-´f¶3p#ËÔ —êz;'Ôš$qÆ/ DÀË€k™bY …‚L9^­ˆ¼ã¬þ¨78]ãÕãåEsªjÆñƒmºŒ¡VŽ£ ؈ÂZ. ÛFÙJïiœ¿Í=MͽTÇátW¿i תöÍZaîÚuÖü€Ç§|·ïq0 •„ðR~NëŸDIPì'º1¯Š„Ïê«´²¦ˆ–ь׫[èÍ–‡\ˆYÙõͽr‚Šdíer}Oý蚉<ÂFA¬‘Œä¹OMh2®³I¹zÂìâ’@r!¯„†Ú¢Úa Ò¥˜ö³¾aæÒ_Îˤ@4:©¢$%¿¥ù\®j bÖE‹®`†¶¥#›—Ší¬¯9(Ïk&¾šm®JÊ(³NvîŠÞ–-$Ÿ9wËWɪD°}’([0鎒€€Â27CÀ´‘Ùàö¶u k pàœFö”‚ {¯sñˆévYÛñƒí®`U}6? ¢i6’?Ï5"A½þµ1ê}¯¿AyI«kvTá€>rG± ¦¤U/ !4ùýûuÞ„_ØÚ‹m<ð9°ˆ_W2â̱„W\4..ÄQX˜a´ÊVy­„5d¹…Ç-ÜC®Ì[> yyNÈÒ:j°Vk‡sÒ.Eþ{ï(é¥úªÓœÆÑzΆ¥ç¦ w$q§™Ú²æ™˜Zc<]*,<þ>d’8uÑÜöþ¯Nªû–5@lµiËÇ1ø50|¶¼ˆotåvÜ+a±m~í¾Š×mîZ©cƆ'Š?G†é‘Ê–“ Œìy<áêïnW,å?È „›bñÓ²´è•+Á˜ñ ¬e.²A^Þ `a+¹uÃ’ ÷Eà¨7ðL­ÌJ5+#Éù5’¦$ÐC#Á¤¬=‡A~Ë¿YÁÁEF¼ub’“‘†\¨àŠv¹ûüYØ¥ )\d‰¨zº“ ý=DÝÌ$ ¹³¡©'ªRQ‰1GêŽÓ›ÙËT'Ž ‹ÀpÊ×6äR+X…‚ì”ÉÛƒ LîSú‡ï²ð(†‚÷‹áÆgKïØ\ ðÛGÚÖ¢Zª,30£ 2`´,ÅÇÇœŠÄ¶j;ÿ[Ùù´;ÇÃ];WÞ*ªªo‡":2}qrØfCgPUõ•òÛhQ&‰XE"—h'4³5¨!‹O_'N¤sK f:+…4èI­nŸæyV×S²'?ü4[=·šn°F …Ü,’Ó ^DЇîe/‹gýHJjþgeÇ{—¾˜*WÚá®Ýp>vLƒF?•µ»„p¹8Ùþ2WCPžØ¾£vï°¨‡2&Ã¥šC(âv._Fø‰û)PYËUf¾>•52ߊÄô7Ü:¼Ø8˜IM\­2r Å瓌…àÍ„VÌÔü36 :¸Ýr›\-ÓØËÄb{FìáKi´“ãÑ6YÛ‰áu=[èïÛ\i@êõ|Ö¹(tƒÔlã‡dX7®SÅW`*P=ªëNGë—m§8gÓR¶eZæé׎·Ò®BØô€¤W“]»oÔÆO¸R~„œ\Š Î‚œíCoJ±¾½á´ÑªÜ‘¢)Æõ ÅåcÉ^^M¶’€€ÓGJäûk¬Ó©)Œu¹ÂÀiks »BLú°–t6¥ÅiÇEUþb÷¥Á[S²é¡@Î<êB¤;rÓj e½âS-<=å`Žôº®×jC€ÜeöÇþ!µ–j“ÙoÖ¢ZKÄC«Eô¯Îþ+Fš²ï#}]àoãgܳ'³ùy­°}Û˜gh!nŸr³"=ˆ{†þpOT?m‡dQEØT»©]=RÒ¿üc$šòñ»L¢ŒÕqa]ÔÐmGäÅ!?ůå ##˻ϫąâ] A¢L®‹þÈÜwMù"Z]íU…bO¤y~`A°´óÿàæëûÅÛ[¨àF¡ß%'9Çô<6_%Rž90;™X r²q’ÓñÔbséȱ #Hlà E¬Nä_Ƶ&z-"îÿÉì»ÅÛp)ù¢2ªT°“Š`ËÒm)¬ ²â¦.y•¨Rý u¯'DïOOõ¤Ax}<ôꊿ!¿Á:R/³QBõ›. lô¯° ˜«P§uu0Œ\ )OHìÿë(ºogMƒ82ÿÐNͬÞ7cx?¼u¨’=ÓGpCŽÃî°EÝÜ0…w?Í-uÑ|s Pkþ›‰WõLù8xã‰Mïl2éµèÜ>òšÞ½æ„MÞÕO¥“Ü× )ðÌ[õÔÄʪ—ºµóƒ>ªùüblç;W1þ.ÂvÝËÙ5—/å·ƒ܃S£ËúªKÚ²$J¼6¤Z÷Œéîz‹Õs¶.ÎP–We»ßK’„)¿­{À¯I\ s‚ÒLÄà“ŠµnƒE#–6=¡LC©i¶+ã¹ðß!jv2”h®¾sª–2¸…çþsãÖI·ªÝQãCŠ,ËÈZKWEø®XRÐÕxïFþhk¹°SP%*I_Ó–{ vÕç|¦ò˜ëç]ÿ¶@×w©žÕµ{UAn”Å=ø„L2|«/ ß “Àˆ¨E ‘ͬ¸tÄÄW?ã—’€€¬Ñê+_ŤbQ"-ØÛüt°í2>K¯ß²ú¦PÊP_¥>3D3Ñm.V©E3þ‹lâèÄMФĵ-ijCœ/"=0CÁX*ßnƒ¦‡›„µóçeR{wX’+zJ;üIÙb¼,2, òB#­Å¨pÑOz u¼kÄö%®ÉJ¬ÑVsŽ¢?í¯Å,Aîí]m¸Eß~KÒ Åi´Mä'ôvýžø’‚€–Ÿñµcø#Z½±EÌ•jÂæÔ·—¤§ ·É%¹ÿßöœL§lã½n1‚ÅGI°fÕ¿Á!1×ã'ÐÉO÷ÉÙÊš±¸Ç[&¹o8ò«Q]wO_!#êǰ¨,S¦¬{$÷Ǫž(“sM!~~t1è}½~þÓ[?}x‰,fèýyÆ>Šku„Xz¿5œª„ghL£Ô×l77¶æÐH>—"Ýjóð OÃS9~ÒDIèþÀêÜÚ=Ô¬–FÛ‘ F§é ÊÛ3¼[ûÓÈ”ÜøµjVîôú-ôejlv›ô•7˜Ì#°ÅYe¦K³ÁZà4¼š 8\¬yй5ÅÆvs º)ö†rî°}X¡?.oÎÚØh§N@teyß;ýîß §ÿŠàªõ.;¯y†úd}àDrËï“ÛcÖ(úæˆ$vƒÖÕ/ä„Áµ<(ô'%â™)s‘J¢æÆ7¢(É´Ë&_¯mü­í¡ešÙ*½Ó´~ešÙ’²!ù,©£— coTÀ#Åyž®—È]q¥V¿Ñ£Ú÷­ãY]¦dÅŒà¯'ʬ/T¥ðB‚‚üeKúÀ8JN·ÉŒd"ž•Ï…¼Õ©qIèc•:}N Ôw»‰½ž`çÌ®Ž¢Ñæ‰ œanÁ]i¿97B—óþcFÖcæmåÊDJŸ.±èðjŽ2¨ëÓÊ®¶fÚÂÏzC‡Í s[óþò°ÿ@÷FØKCšªÌü#À/Y𯬌rçlxÿIå•cE?/íÀKKpÀD™Jä¨åü„ÏNÀS%ÜBÕáuÝ4×à+±«¢‹Ë$£Ù㣂(·ªZœÈ ;'$†jêì9IG¼ZåmLïó»P,¾`Ý}¢ËrPI>å2®½çó¬ædÆÀþm tQòJ #:³¶·­MTI{m~f{UW¢ÚëE¹È ¢Ëñ1P2ÖyÒ@šÜSï"iˆ«š!iV ݺœ“PS ÷=ûegƒéê}fš»cY7»-d¢7s½îC†ËÉäÝțt€n~ Tíè†ã}J³wð*9}@’e[ÿÒM’±DY×Ûq å niÝÚåéCâªóA¶[š«ñr–XðWäçü‘[\6"lÖêõZFÄÖïj0czÇlü\;ÈÉÖ¨Û[ÑJ ðÁE(ó3,B Èp)Înǵ³cèILp°ï4Ì<…ðø¢¥ä&øÌy_Ðâ¨ÇúRß?HßÖd'´G§ÄóÙQ®\ØJoT¯{à±UgõòñÓPá: .ù¥³Rð:#7…ZÖöM8uhœ\ýnè¾ù7igôÐ%‘êÁ~¼£`ƒÊYûb“¡9aÜ[˜Á õª¯É›y:î¢ßtŒàücPŸ‹ò× 9ºÉ Êî7åH&hc£Úð¹ïW1—!Wã–Zù´à”n a¢uaǾ™JÝ WÃJú#ÂuЉËX™C™l`dÝbdä¼’øæE) L…/v˜€…ö~ö>·p4èú›Ϙ÷Ç~€dFC‰¹3µÉ]_C‰4·†‡†§7õ£ÛY§"¸‡¾¤ ,Ô—[8¼FìQVµ##ÆL^qô£$¨ˆ=ˆê»ËRv¦TGÒ?4—¶œœÃØù¤õéÞqõ²þØý~J†`âR¦i=Xz÷Éý\-[  ¹mŠØ»[v`¡—·w=ÑZÎf^¨œ›l’§¯Mie]ßfîŸÍ¹5Æ×å£éƾøÞ½• < §C"¯u2õýÁtñµ¯Ñhn¾È>õmm$?ð(»¡KH•H/SÁ:ÍL@á•î)4JÉö­ôê´U@âªÉ‡«Í(ã^ãžT¿¶7+“ijXHÄ3Ÿ™yšt­nþqµÿ´O‚œ?%Ý}'„§D›ËÆ· ²Iþ‚d}€“¿¤JJrz Î…{+¼.f1"’€€·þxà]à•I]s^à ‰a±}œMÔ?ýzK ¨@k·^Ñ«Fb lúv§L:yè Òþó`uìÊÚYüCnõø†Õ_Þ |æJ‘¦=]»ëÍAò¼1u¿vqaâ Hw ?¦ÿ`Ñ´`æo¼ ÙûU!Ë®êTx†ÞiË!G‘àgMÇ­vªMVÛµZQ]äÈøºÂ䥆Ù@ﯾŠÜFiN²á+§"ÚF&ñ*pf;ƒc‹îϵ0Áz2ŠKŒK×àJã‰âhñá‰go©rv?·`Ã=uêã¹|Ý+jºkÖª[ìÆV²Ø7 ÐߪO ¡)8¹Ðz1I8U__är¦{.Ba2›¹YJ Ä—›a"{" þ°ŸH ?TØÙô˜¤fûJ»7ƒþ >Ÿy¶’ m–ÆþÁYvÿ)Úüo‚+}aq-LŠô¤É¦', ªæa™FîÜbfºiì0©¼4t£åŰÕ7›t}ò_Åó8Œìˆƒ… tö­žÕå×P»ù‹™s :w?QˆÉ­ËØ‚pøFâáÞx¯Î ·§ÚpŸ‰ƒ†vå5´Hoš@é½m]’«»ÝŒŸs;d¡Nù°B J° ž®3Er„43üeµšjíJ¶ç”­é’€€¬QUœá0V”{´²´Ú+a`J±v4ð–âZÂ>\3½I—×ÅK#| 6à?<ʵéxɽWpÛ--©ðôÆŠ¡3)¦ÀáöÃ1øú×ËǺQÊêv5%jÖœ7c°¨d Ú«j®Ô} ’!ø‡?îƒÌŒL'•b}Š$![y?(fÉÖŒ’ÛÞ~*y½ù*C4æiö½Ñ–ÛŠkÔ4ê¥v„DÂÈ•Á^M[bé€J*ø`Mm!ž…Ù:Ô¡%‘ô?ÁqÅx‰–!ã¨\Q‰&Ú9‰sǵCÑ·iar/9óe ³vT‰uËø[«rÒ -Ê”˜Ääª95Mô"ت8¿âˆiºrK/AueÎ0" E‰‡ÀtÚ̵Å¿F5UNTÓR!\¤^lŒ@g$ë•lÃs4Ø7,CàKÁŠ“q`JÐnd`#¤ÔNX+¤o®þ¦ÜW> (ê“TÌø¨gëèQ;rÌÅ(Ü´ñYŠ‹pr͵@©n‹öžÆÒU¨ n#§eô}é6€´‘Tµ˜ûvΈä[);ál/J°Ã->-žÌ¯a×"瘲¬òÌÛšA4 #Çñ¬Û¾Šžr â&@HÝG)¡BT‡÷VþQž“ˆLì’ ,F|'HªzÇãü/åe  “ýIíAõ÷[ ¡4@KšÔc!cF¨\™®¥EÎõ|”_o!!z6YG«·­»ͨ;\€‰Ìm ep=R$HäëUEµªY…Ò¶ÓïwqÉ­*zè³Ëííe•ÖwèV´iŒ°ÆBdºháœf\…Þ°˜ç¥üˆuªUHóÀM¢²ÚÅ•úŒäÝ'InÏ;#Î:î}Œ.²ÖíÚ†umQ©_È'¯¾~ˆ?¥æP ½†öïÓÀ‡OϘÚtñjÐn‹RÈê:Øž–‡ ‰e¡ï ð“«8Ƥ˜ ´ª‘‘œ^ R.ôؤõRT’c=OH!–L¯öl`Nv¿À ñÃX®­Ï×e± PbA˯ž4ËÃòâån»G 8'0_1&ýQçõ|xžji,¹œAkÃ;Õãa&¼}J® -do3"s‰*Ϻ &n.ـɬÕxBʼ>’­lUdJÙD•L*K÷v+¿V1©Š6€Ädè~¥r=®û&éÑë=seÄ7Âz-)wr ½ˆfœÝûsÓRáŸXk©vTB~Oñ¯ÍI˜yFº$¨éfÖPnŸÿ;÷^µj÷V°vdŽa f™½A-þO’ð?¤Êçêºvk gغl†È –…­ÞŸ”. “bFúâ!Ë)MW×Û•ÂÅÉ |Á÷åNsçÞÜJˆ•bÙ\áÜO÷w9šq4§õwÃ'÷bóšàŒN¿ýГ¸ëû~„kÁü n1j®$} MÕá[ø¡µ|kX ´}Ù#/ „nrµ¼ªòF[©°‹Q¬~?û• pZèáà ‹´ÓƒPa.Ñš¦"9„ŸÞΓ÷"ÌTٽɷØ/»õåu!·†Î;¡¤CýÔÄÿ¯ÿ¨êßõbU‰à17z뼄äçž::©c)~@8ÉEg¹{Ûm˜³Ð¼´ɶ·}ls á'¹œÌFéÒ3Øå–o{˸¦9„ Wb3;ªe=.d.Ç̈́Ȱåñ‚’€€¦QÍæç[“¢Ú0\†jGÁCË帋t(?§Ž—²®çȬ‰ìu¸0¨‘ ‹¢µ@Jíå¸Á¹° {ó¥ßŒtðW„0‰s°xd¸Ù9ˆLFêCûó„pÈmxŒ ™`ÖOÌÕ˜\­C‘¹ ì v¶Èzþ°œ¡¤Ã«Íüñ¡QF-×8H,k ÞrA\êø¡0ÒÔ“.JÍÀ/`½ž¹RÌìì–²Xü·!y~xs¸Ÿ4¨{2Óí-É›-<¿Eð ³Ézl}MIÊ­N=q#‘-K6pvw„àÚÇï­l”94ì·ÜÃf‡AÎÎÊÞŒ%t ÑãXAï¦÷ÉO£ü^"!/m‹_wé†ün¤‹è(Ȱ‘_ÜiêTkrŽdØÅÿ {Õ%Ðyû7ýyQ¨XT ãY©mÓž_lÛ4¢¬—=]|75îÁx5?…¦>_*F½ Ö D3í°É`Ìùo½FäS9uzxÄljdßMݸrξڀïL[ì•õM/éŽ_ƒkSD#Ul - v{Ð`QÝ•2¥ŽÐà 'ÁÚ‹õ‰ ;ð?¥²ÊoQÓÓ¦¯æ?>'JKz‰„Š»u°°Š]UÕh8‰½)é+äŠüc.DtµÁ{E* ÐÁT%«&2ªkœ˜±n‰–u -$îaø@°ô°±uÆk*r k¹¤ÑÂÕª3Hɪýøo©D™ z’ɵ»á£¯ÂÒ‹kZ," Ïñ3Qb9h”ú²Ý ïCßÎöÕ2›Úv$(&†ˆÛÃ‹áɰYrD‡Ì)ˆõÞq90niWU²Äжl‘n³«| ÒPm¤–#oN#D}¼xiƒ³Ö\»… ?t+2Ó-íX N='Dß ÕĦ"ƒq!s¸!:Æ@ÛÛÙÛ]º„8Û¯ W6[ßÌQ~Ì¢uØÉ‚Ÿ‚5ž¿¹å=È«¹£8õT—•äû?ªg™#éÞ]ËOe6JêH×pª>WE8×Q K|úé¤Ëyø¿•vIòóB“‹lVÿ[ž÷¢+úNÄtÍ^Ù&ø¸v’€€Ã:2¤N_oì( ¬rAÐJí•“ØO«ÖAj¼dp®.Ð ZÀ=hÉèŒ8T}s[Ï­ÝÉÙ§Þ¹œ–j}SÐ;‚~fÞ=b'eF¤áI&@2 HQF!×hÜþ¬{¹lX±(3¸F:{4±¹:L²ZÛP(¦=ûoM¨ËRìÉýjrz3¯˜1ñ£‰¾z¦ïùˆµj Ú6׈õ¸@-ÍôËd@.#°ûHÃÖ»í˯——8Ü+ÒmrŸ<%…lrGAºÝ ÿâöxßôØwHÜÀñàùÊ}ŸyU´ C¶¯Çk7ûWy|²îÀÌåaOÖ±jM—6CšOÉŠìÀ¤·Í<§ú‘÷0VÅ.t„kÏ‹Fx@Æî ©âœwØ#Äaë‰hœ·G¼¶oÈÚeCpX¹ª©”&gr¤îˆ¸U+%„Ýf³•%ZÊoHCU ÞÒúh1Ú ‚ÒÇdëŽåÔ›ôaY_·B)p›çr¼†£¤ë§Šç Ï/=—ü"n–N6®ÓDz+Á °ô}‹û3öàqÄrmE´õï“ Á+§{nk{*Š ˆýó‡kÏÌ†Ìøc1V&èÌy–Ô‚„æS-žF­Ø8ÜTÁB›„œ%… »2Àävx¯X›+`Ý¢•ueïÊIp0¿O•˜vóÖýß¹u‘—Oª}̺€FLcíƒÙõ·­Ùæ&-–¬,F¨°›¯ÂV`ÃÉK!˜­'ßp³“k°cr|N¡»#­ãÁH¨]0ƒÍfË‹¼Q·àGÅí‘ö]ýHÄ…ú53= xH¾&ůДj9Ç‹Ðl¡i*Bâ°™w¹Çæÿr¿éÚÍl|Ò»‘t¡ï¯½ãíĦ¤=±œ !sñ{òƒýüFO‡x+¾ < ñ>”Ó î."Ò’ƒ9•!æC±:1ÿÚ«{°R]rcG+mXúâ’|E¥­'(^†`uÍòQWp5˜[þZ¤' ˜Å^€G*CÌj—soM!«®Ér+б^–E2ûïêòp¹¥r’”ƒÀê'óX4Ó.âáaAè ÉV5Ô0„éÃþêÔ˜Ú€š&¼$ä•êzˆ”wÂ\²+3Õê•Ïå²ÈÊXûuZòü¿‰/N­4½ÿmË¡ÛÞñÍ£™•àûI+›NÚÖhX™Ž®íGÈRŽ &yݤD#’_¬cyÙGu@÷ÒBô²¥h»r ÆT¹H|—›(ÃÒL(F©×™íz$pÌëÖî`h&÷cWÚ6²#Éì3bÂÏۛ˱մª3¯­mÚ1êÎkÜà]ýÇ×}Û B¹¦[»½u&5Ä[ б…x×5 þZ©=‘xh ¿d X^ÑKÖ~ß'{¶§R Hðœç…6ýË×m–¹è¸¨Þ;aŒ/§›¥LTÓ°>'¦SÞäJÍ…¿7jžèÇP dj›ÇטÖ*øõêy´×SõJ‰CèÒúU‹|{p¥ÑDø$ aLù›^¿ž„ Åò+òìLU» V+)¤|ÓuQalsT߉Žá2„€"÷v5n›¥rW$ šóš‹«ù“†Áú·¯q×­@ƒ¢Z ùhE»~D}YmÚ¢ ¼58Þõ­îâíÎÂ@(¥ç,MhË÷q‹ý›V+¼ú{칇ÍϘ¥/)®¥m7S5®Öia-ÇAØ| $éõ~k§h×,†ôs="’#Å/M'²Wan)Ì*oZÒÔûÐl:Z×r¹3cüÛªÛl‘8ùŽsr#óçãŽMŽz/¢pÞn€ Ò½µkó'‡1'Ò)G„sbÏ›g®‡uýímù…Û¯‘_µåM!º068½@A;w¹Pì ªÑ·anÓ¤%*ûwe×b‚,]DÊ?ÌîdZƒ˜Â@æ‘e­f`¤Ÿ±ájxÍi˜½Ã'ò?Ë,­·Ä1øò taUöÉálÕ¼! ‡¨ª¦qµØ5š0õ’úPçÂÓø&jžy‹•-¨ðq5ž³|õbëöÅÙ2lC:ï‡ÃéWGýò¿òš @Eš# í,Øô{ÀÁ¯h,½½ÑzX11ÄdÈÛÂNŒ@ïw!}ê³|±_õ+6x «K$^ã( úߨ×ååÏôù”XÕ8×=Der“‰š¶K$ÔÄ"n¬Áʯß+ÓÙkJÊ$xÿ±!K>êîI‡ñ¨šÞ/NzÜŠu¥æ˜½$ °8$>  ³ê3+Zy…«ÀT|PƒSƒ²÷”Æž5BkŒs9^œóu’€€¹åÄï£<šãÄF‹TÊÆ/Úž—Œè[˜¼ë«ó@¯£5Õ{¢Vv H0þw¿QIÍLü+( ã‘ SÊI£ð¯ Éš:£ã"ä)âÈn¨Hh!t ¿äʣ㣘^és²¤# ¦`Ø*‘!VMoŒ[°ú&„ñØÉ\¹Hð,,ãGpSYÄö*Ú‘ž66Åê^•5µµÅ˜EQد£>Ê[]qGÓ —ý@ÔEÆ,‹Ü7½‰xªCXÝ•ÊqÆœ]Éן?òpì³–‹ —¯OŠøÍ\ÆÌ¼í»AÓÿIŸ¹·íýÿ³v8H–‹ÕרAïž…‡P¸MIƒgÆoªú¯KtÕµ¥§_/ä¡uóCû ñ.T·Ûø«êàÙÚޝš'-MZºÏûpÁÛµŸ0IMtã×ÎØ !C4f0 iX…7xð}ó4"¹K7×§y_¨2BòЙL.–F¥>jÜÓã 7QI}ÇÊ8´{laêÛ©Ù7__àx¡¯ÖSËš-5ÃÙg×l"‹/Üï BÙ10v]&šOd«ck>ç€í÷¤Ûcå់ִŽ¡…JÑsß$ÀûzK·!ñžùšÛ©sáÿâbM*á$«bíúï‚­9£–ùiqÚ±ÖêZ±çèz;ÈE"а’©/Xð ˜çw ‡ X˜ ¤‰û–[ó3zò V¾K­žEšO÷€°I6Ý?H§µwÙ£°]w¯àÆ1t8Ë™3y×ë`4/Ê/¹+¦“²:ýE7'ÌŒ@æ(Œ0(´waqf-Ær(JTl¨«¨Yj Í5§´Ò~ü]Ó\u¢ZcÀ@\/°Y¤k–Ž3·–{ÚnBü;ø»ùþN¤“_/Êœ•-Éðƒìeè•rÔvb|O×bňx´‹x÷!çËÎs‘ùVÆÅÓQѾõ0!´gHá3ª~êü¡ÆÅY HÚ&–¬(eŸµkC |‘œNõ(êz{Ð.ÍsK6Aë $i™[åP€¡f’ÉP$†¯tsÁÚ@ \Ìç»´˜M®(Aöû@ñ´.²ŸÚ뢖4趯³â‰•@g2Í›Q ÿÊEÝ^–ž?f'¯‡pÊ %B¡²ë¹2x%_}Ï¢0çÝÇÙKI"Ãe’€€Û(÷ÇÒ ×h;ÝVi Ïôý¼ RìIN¾¡ß=+®úÑrœ¿ ¦¶!ÞEã&¼Ü]q,üñ¿2¥~œ“¿+ÃG§%ö¿~ÑšÉÃ%kNzâœL‰tí£,O†¾Éã|nF›hJŽjh´  tñIÊëδ¦õM¸SL½·È®,¼gb÷†ÎO Lý™G4 ±É'â¡’…iÂÿ™ºGüvç{/öp;ùÄ1z‰_y#è[×pV¬à$•YÈfÈ:Ežñ’5{©%eç©áüâ‰ÿžÕùƒ®&ãê¿–ö}$ÏîšNË![¯ï —·>EL¦÷êÈÈsŒŽÁ-‰ ó=HFªquã?¢f€íÅßN$‡•Ç¢\\L}Â/]ÊUÉ”ÿÒ—)h–ÿ$žGk»Z͇¾*þ  Ø[P…» éË{ùÓµÁ¬Pø¯Ò[4âÃ>Vl!¤Ý?'îþàí»ÏôÑÎûFÌ‘'>>-€)OÍ^ØÄ,åoqÃÅêWAŠ_l°½V&•`è8:œ oºéïxÒxaJ [/Z{<›*I…]\(;e¼Vð[–Ç 3-/"ÿ·1½Ó\ƒ)}Ë‚MÏõ®¾‰^#ÄuEOJŽí¥&ÝøA óJS`1"¤Èï˜ÖÍÒEmïñ"¶xi”)µ.uµïµnyf˜UŒÖJWsÍ­íA‘* 4Ü–0EôÒ•á¤q§‹àVØÜ·Óê¹E5Wuü<„c$~ íÂJôËCRÀQs°^•â@žixv|vZÖ&ìÞíJÆ®µ8QF†„Õ¶¯ ÔmmWoFÃ.¶"èボÄ<ÃiEåûèeê5¯"ñ~+§’·uñìÎ/Ź+~¾S$¹°yׂˆfy‚ß…¼ÄZÕ™†×"û]sH!ßbxO ýJžov¿•)“Ú^*Ñ›~о~Úñ ·Óð±ømá­Bç xÅî£ùHÇ2ŒŸ­N ˜ö³ •› öE]~´U5 kµ÷°ig–±ÝÞ˜!Iµa› ë¹QÓ5Nq,5C&cœË튿ºÅBfÉ”¾e Š:X·7Ç#Yq=Íç+Ó2QD¹Ùõ¹):FB¬Oàa¤‘yóð³F×ÜkNád1|vŸ2٪ʆ7Iâ›Ô²~ÿ}/’€€·Ãù¾‚Ÿ£.¡…ĉ!;fÇNÿ[¹wÅÉœH…žÏN(ƒ¦»áÂï“»ÿí?ÛüðàXIÅZüþv!ðœØîBLì‰ÛÅgÝv/ïŠÈ |¼é»Zß^Óæa§Èðd/›¸ð½znâÃröÝ|×”Û€T¯PfWäÿ­Ù"¼dµŠÄ ª-bDAïL:›«øÿd³@ €n\G\gyeÖª‹u7jzû_⯬mÄä!ÁëTò<¦óIá<À`HÇÇÞ3Ò‰ŒcóÙX Ñ{G,UqU]TÒð[?Ám¯¼gvÓ3k3~±óPàùاúÅ”³å£q–NMŸRsiðl¡kŠ5o;èÊDÒP¿D%B=tr´¶¼¤øs¼ÑÆD»Ë/ÐDg¯"W§çÎKOû@~óŶ5m4Nû’¶=Ó³Ñê2I>çoÔP†SR›DXëvãýˆ€æ¶¡øRPSi‰—ôYÃ'ÈŽ{ÒàÔ„•õ킯hÐ’¶í'ê/ãçµ^ ô~xëF®»à?s¤æž)rµÒò|CµHlBŒS»=¡ë ‹ç+‡¥:´ºË÷]©Äö•jv/Œ ÇþTãº{×Úò$TÇ1ò°Ý}#æ Rµ—Ã8‡ŒKå‰å±CtØ‹ºÙ¼4õÔ!œã'ì+xsÓð™R`câÆC¹.Ð>î+Ç*ÍÆ¢¹®9û›c/£íOáTÔÅù$ÆÁ\æÏU.jéý×hÿaYeÞ ·N†x}ûZ?þÖu`ÿ}í¾p+Œü­‚JÄιÌÐQEÕŠ0í½À¬Ð¦B2dáÓ›³2ãQÃÍN‰{¬5Õæ+ý¨QîksÆ{,y‹óœÓš"º€ËžÞLDž¬WG) ’N8Àåóæ¨u«™XtÐ5àÍ?Añº«Å nÏ,kDÒ|3ÎU‹¸äå³1›xN—îÛ~ÌZô-Á÷„Šä;¹x›8ySç5oøÒˆÕÉGE;©PòÞXµ2„>ÈÊ» ÿ ÒNôÝ‹;$1ÃÖ`ê ¦l ˜Ú%&kX_ù †ªþß•á Ä xióMáXÇ4Á$ÕV›ÁJÕIìÅ95&+#ô\†ò›ÅÐMÙÑ7q“/"QÄÔ¿’€€§m𢱆 ÷_mR,Äcã^ñÅ7®sovË.Rd¥…4<^: ›' 8PÚ8ÝïÔL4¡eò(½&lé½e+BŒ±ù0dÿ‹ó’ }¥Üß9?ž·2¿?5ÙEé[„ ó lml=ëï)7<‡¸É47rÊ4Ö¡0|K,Nè¤çùˊСûoÞ óe8ýx¤OÑÄJ‹Ûžî—ºÚM"Ùà&z6ô/4š%¥'‹kW\EÁl{〮KŒ5Y$Va7Ëk]ý6!­îRFÖös“Tv_ÃIA`§b`!— b‡9LåiÙBÕí!‡ý”rÔ—D2¦K§æ™OR@î­e¡NN=¬§LkêQn7ŒÒý»F#4|8£V`ª*þ˜I*ÜàËyÙ{ld Hˆ ë¥ÌÀ±ÞžTž‹¸*Ã^`¾Ç" ®¿TŽJZmì×/ƒkÐ.N¯¢“v}å ØÁû_x§WrC ¦Á%@#©Óqhõá@ïOÔGÄ%ö‚™Ôž u‘]†fŠ(1RJ`ÏKÀåñÅÂJÛ@yÀVpçÚp'fwÖ´²¢£¹Béߦ^ví—TþÈÎ(f« £¯€ KöM˜+þïÜfŒùìåÖ Ü”E®%/:2bø†«äšžcŸ×ê5UÚ$ÜAðF UëLÒSФ»åØÂI´Û† MU“†xºß,~?õ ]ª|kËàØ½‚C!×eªzéöIÄ’€€§ K“=Gµ¬S%ó¬_)ž"¨iÖuÖ-Ó{äVå Ü(ÜÈhÉ ”å¸ÚŒáÔ‚ßô§~ë„;r©ÁP*‹‹ÈÅüBS(ˆƒ†É“ jT›~犂Árd„„V]-fåzªÿ„ù;½Y!‰•|df—Q–j§KL¯öüF\ œ¾g2êÈ`®ŠÊ³½2&k~„¸ûÃÆÓowqGý„T‰—Du“xv†¯%­l¤óÐü²umªñ Š3#LÓxþƒR å4b;fÂîϽõÜ-Ä„¼ÛÞ·â‡ÒÖâ Ðf'¤eZ©Ž»s¥xr˜{„·æ¼$½ „öDhV ËS‚_äih—âà± (Õ†÷ÞÒÝ—íŽÀbÔ…6Øð ÌszÉ­ö‹Ò_=µ¦ä:<ΧDµ BæþKð-Û"GAjÚi Æ 'Ë “ ÑLæ¹·ÌIÎyr%Q…Ý4@n$äÂáê¿[ðFö ¾­Ì{4”Åwjb 3Z1¢B“.±øóaã~¶’K½‹ú‰ÕË~ƒwƒÿäiû}«¼Á 3O}"YÉíºhw¹c ªâWXéhæ@6úÙ ÆB}Æj¥€96¦žIžN¹ËÀ ¬Qù>eˆ[š7Ðoè‰í»ê©8'ŠTùÕÒЀ™~ËËeø×\õ% ¾Jb«y|‘¸?Èkdéí£Ë{‘{'ýe‘õG-¨¡A6¼:H´ökaÝ]¥Ò{‹Ú^ŸñûŠÔ›\NÆ”§OJÒº˜WÁ#K¤ ç È&„˜Û€DG>r økˆ+/° ÊØ8¹°÷)û iõh œåÀvÿ¯‡ï Ò¨9Sk© J¯õ te CE5œ¼žØÜ©ZŠIû¸NuÒ›Ö9¨èøaLÇ®d¶η~;€ãØ´`Ðäû>ydJæïeüðQž¹ë›" 7Š” [kð3‚0‹÷yb.>rÒß w^ ¬sÙ¼^ûžk=ºäÎ7·sË+n[æV ùÿ’€€Ðå’ŠjG ¿"Ëu á@™’µ­‘ÏÆë ºe ÞÐwHd)°hÚ§è[$îûš§ÆtðU&zæŠÛ®º×o»cÅhz0Žšÿ’®Ôb/ôm¹>C¼óýVOÆ`fºIgg­¨*FÇ_V Œð©X?áÀŸ— å"9ä81:V» ª-Ìn¶‹³@«3ÕæcÅ"¼ñŽ?Š-®SQG¨—öB}´Þ›øB[ñ‡f̼ò”H²Ä´ºN…øèÚ×¾fH—ô7 ƒ(4ɦpH@Mŧ`UÁ;¢‚ºþÈÃ@„0c¿„øpýy¢èHëbÝèÓfü¬TŠ<éê1sj½JCBËÝÛ¿€”¸ßÖº}1ålµÖ˜äYÇSk‰ˆøÕY¼Šä\xÑ¥vêtòÒ„R¾µùyöÒRȃ ò$˜ÒÃŽ¨s#›b•   Ðö. Âý1©Çÿ>Ra5n@Þ¹Þ„‘›[†ƒm¤®I‰ÓF‡¦ÿßbë+6Dú'Y.xÆ6”zÃ$Ó^©wu~å;hÓTÙƒÿî®~•¿;ï,–<>°öŸ¸Ò7é/ÕÔœ9™FØÑáæÒè›q¤àû’€€ºLbkŠkˆxïîTÓš.áÕ‰ÀQ•óÐ:²/¯@NèYÇj]å¬ÇxysìÒ}Ãõ—-Ö à´"45F×=}ÝÄ)&ª’4(‹G¢'œHj.Öuy(ÊO.=—•Ïja—m½Ò¼8E,Ï@¦Ý<&íØ"¢–3Er0µšP§”¯NåÁ“#åÉv9»˜¹”NFJ€ÝklÑ…դ𡌘]i”ic–²u9¯Y#)š¯È¹Ä ŠñšZ²®¬·T¹%ag¬¢dc„.ói9–®™?bÅ…7[µp_y!9†#ó°‡m/ÈW;“ßù(s›0…ötýÉ©ËÕdÕL' œssQ04¦¹ÝP{ýÞòÝ ­G‚ • Ä”cÖ¡Úïîâw:Šê«Î¿HúxH”=þÜ€‚v>Ѷf1p'ç“—@øŸzðW½Â„q/ÑŠõ94xî'èrbo»kòÐL+¡ÍDk±³{Õ .ˆž”»nòƒF†°7yñƒì¦4j½j½njæ<® Ã{@ÉA [¼î VÄÐ<¶L£çs©_,‘ñËksÚ|×q@ï‰j(+eé/¶vHe÷Ñ…‹¸?f{wÞ¬³YhDbHÓ~ç' ÇSÔ.© û$ˆ"8,ù\! 2cõAèP¨Q¼÷À£AkvƒŠ•ê)*qæe–0Íš§Ú[O¼¡Ò¢0²Í9ùÈW 3\ôºx½>Õdõe-S¨Ø×Ù EõJn¯XKyÏ m^]ž8›ÂáLh‹È§¯Þ³HJ-Œí^YçÊ_>üEø‹‰O€}|C¡`1sv ÍJ´ã ¸óåHE ¤(öÕf`ç’v½VäRº½¢ æwŸ Ðá|(^¤h®°â|i'&-ÑSTý:É»PÍ3ýy¸H³Dòu½õÇeζ¢pX¹ä”+#ë”±þ¬øN$`䨇…é¢U¾öÝq2꺯@ÛŽòÁtSÏB±§ßm¼éZöå ˜V—}°ÞO,Ðè´¡²ó/X!Ù»ÈyKÏù@N>TÚ-ô1úó´‘7Õ>uìSL"­“CSËñúÃ/ö‡ß²‘ŸøãêJ~öD‡j¹Z#Pðè̻^ªµà .ѶØ·ÇBñzsÔÉ`’H£?’€€¬£½ú`Û]Ö37øÝJ_Ðzq"_Ú²-®u‡SÑ9Ÿ†Ëþá|<·Ú¶¯ÂÖwŠ£U œÅ´‚«x&ªÇ¹Ùs…þÜ:Vô8€Ú42¤´2HeLÝ·Z¶+°ªÏì¨HF§nSÄ\R†Eó>´6^ù@H“ÃÐjY0„ÞŠ°s?ïuòႊÅÈDB¹ø w`)Ôôd6~R÷L˜³!†‡1þX*2UŠD>CCæZ¯vp$|æ-¦sм6ÍïúªüIz*§jêÕŠ—./ü·.ñnê†8ñJröAíª±ÆiíŠXU¶nÝz—üšM˨Œ ¹l)ŽfõU%I+#DP%³)ÒëþûÓ칇”žíºžërÔEíÖÙŽÂt°%Ÿž\œ½šu•ßg†÷ø´rk`ÉZ“r‚î[¼t†=ì ™%9Ü(*‰ØîI7 k®kðµRQ¶Ëû["3ìAƒ`à<0Xÿbøü*OÍáL[áí])y÷8j2i®å@àÑf›Jîù²}Õ\Þ=I }µx{Mvµi¤½ª ¬èþ‰ä.Ív®î€¸òðöà”Z%së³dããáTÈý»â ƒÍÑ+¿pè `Ð|Xo®?ZbäÆN5ñÌò÷Z´ió?û|4¬‚~üP±Iöä¤àšð™Ôh¦=}yrm™ÚJzÕÈ﯆ö~™= ìÂÚ†É&$büY¢j†üáá'k¬±3`¡^{HN%¼±\­™«·ëN¿Æç)ê¶ô@(ê#¥ >9¶ˆkYƒôÌ™ýäÞ9XÚþ¾É(ùŸ‹ú?¬¼%t¤¹‚S0¾øàSÓâ(ôÆHYлöþ%<"uö:¤ÕóÉ*Oð’˜ðŽKõvÇ)Þ«çil'SÜ[·rê;1¬Klåÿýâ—ú¾«*œ ¶ (ÒÂûNÜŸ¾—ƒÀƸTJž¢?C<蔢7} ²=€ÒŒX(³¦×ˆ{Þ´\B,]'m5Ѿ7.(D“§í#“BBn°æ'éÿ4ò3S‰¯½©# Ï{¿).ÜÙT˜&3¥–'E‘¶gx€6õ>ýÅ–‘Ã$?XôoååŽê\º@M6Ÿ /¸O-ðeÚ>±¤!­Þ,íÈB E„åhuÇV×uDÂINÀ°‚þky ô Ü!ãRºœNÆð’€€¯kºcæ£x,èÉ;Z#ýСý/î½ü|©0¶¢0 t9ÞŠB¶[öªO _Žy{„¥ÁÓºx»nÞ].U nk0€Råå/ÕØé)z°}¶ç½èr ·,)† vp6<¾¯]¤› uÇü=o´B yZÊ;39;¿.–èA ÂcäG›§xζ—!$S×Ϩb6Ý|`‹îèCL³¤;D.ãd x°8u K–ËK¬†ø»Úé˜ý%éf V6˸ vx§K¤ŽÓ14?è â`Å3šÍÞê7‡¨í«š‘OÆæôL˜8È-7 f”ÖrDÃõ© oŠs.¨˜öÜ‚úÂóªÂå*­³ê¶~:!2/¦HaùC‘wfþÛ¬“h‚êÅ”ë¦ÆÊÔ¬à<w6pô.ø.ûoh†_bq“æo¾Å>yôEûXà®SüµÌ,T®¢y㤌z 7Îpat wzÝ’Ðêñùia»·ÄgþVÎTDWAÛúôó‘6T¿_&² g”˜»Ï›Á -öÐæ7ùA6uEFQ¯¯áXcùH9Þ7®µ«™žEçßø¿¥’M‰ÿwAi12|þ®í;"å·“†•©_¬òÆ¥|µP´O"ûñùݽ—ÉÇ„ð½v‡''²dN ¯ï\dñ<ÄR?ž«’S[–Ö •Êz† €Q#» «Ã@ƒ£¸EüK ²·Å¸~œbFþ|"52ز X;ÙÂtùc.¤~™_1añî$žŒÕ§—mßqCc°ï{“ ä_à€Ï1 þiø¾yv¡^Ž_Zƒ*Aщ\ï’,È!n‰Ö‡ÈXÊVks“õ6†@uÈiçlƒ=Wo·à~°ZÖ(˜ÉçˆÈ}®‚X¯õŒ†9qD;¿oäÉT^’Ôt%öîÄn{'ëQ¯+R#LÞÿVsÅ=Ì[½Ûlvf6À5_3®â¸ðm¿eã…Yã##Ídy«e…ŠV®%t¬~G‘e›ÄT‡tX$Ç×¥5Z’€€æ –pJ„JiÃpRï¥ÐO´»6¾z5nÉ(;íC7Œ³žŠ.–@0ƒjS‰𜡷ãK’¢ÑºéˆÝûñFM?à˜õF`¢«-ˆ.Ÿ±•·¢¿~¢þý(}uQ•ª/^ÝÀN;G5¿: ×Õ¶NŸtbf¾€ÅC 3ˆƒå\îƒþž‘T èž¹"AyÙ¹~위WÓ£ó~h’b{µm5ÉÔÊÍØm®ÍG®—.¬ ¹üóÇ·4è+¶–³x9·Ø¥¬[EXÝ‘9vž…ÖÁ>EѸÁ‡ý—:Iíóë|Ú>ÛÆ|ºwíƒXII/éç:ñ’€€ÖºIq*n^ð¬‰FÚƒÍõMßsÙ|µŽHøá¿n\¬±ŽpÙó>úA`´·üVâBä>ød§š¸È .QŸho³a·,zµË˜17ÊE±BIV>ò¡»¿Û Îüb8R QÎ(HBî°JÑ¢|ùm‚¿^„ ‰åÔˆlFÚ“Ôi±­ÏA\§¨ñÿæáyã"Œ­â´œiÞ¶¡L¥,b¼8ïsã´–P·c¯$§«¾”xØ.ˆYe5iÁÄ{§½W·‘ÂxôúýB†aC«ïkQ˜üÛ0ET_µ¸;¾2ÔÖ_×”2+ºÂ¾­n¶Èˆ–éâ©w]Fd¼ÅØçb'$W·HQX8‚@n·×–©CžÞ•+n?ú¤µµ×¤õ<Óª»GµŽM?lœ¶ùݨ'Ž €0­Ìó0Ejó¡æü ôíÍ`™4ïEI!ÖÍK~²ì“‰W€ìaZS£s9¼“UÝÛ~EæmÄãÊÇ8t@i_—»Î°¸,ŠuhÓo¢ö¼òò"SBd`#9¡—F'âð;â¥ÖT  QÂ11,94(‘qËu›vŸ§‡°/ÿ^³“GX}f¼;D XÐ!ÌÀgr|Ýà'ûSd|€Œ‡ ¬ŽÙÔnnWº]¢ˆöô8ýè[S%ÄM:øK#½vgs"2êK^joQfNxr’Ò¼žC´SÂéZÒùôt˜EÉâ?À& ™ÉÛMo·‰-ÿ­¥öú3ÖŸ,²iæ7ÉUŽù™.eþJÔÄ«*¸ÔÓ¼Ö“rö0‘!RƒD,¿öå/“½a:Pzãi …5àZßgl âÁÁ’žéL4éðªG¾ï)Ö9®‰œmzî Ù°aœ5Ô Z›ˆÑ¶£‡p(Á*â‘§!,àŸáQ­°Ð)^ú_¡J³¸ºÂGÄöÄøˆ»Iv'ƒèûÂj•*ìAR'·¸ÓÆg늑ªÊ¦r¡6º%{Ó*µwÙ•…-À++’oWyЍb/ owêwh}õ§vŠ[a„ŒÍ"ÐɲϚ¨ýži8”­×µÔ‚Þ?d`ÛÛl¶±àjE€¨d!q­ïY¶Ë&¤JnkŠŒÓDAÏåCYü©³ÍsœÕª@&`"¦0ºÓ?rŸ9€’€€¯ëb§a6cí³\¯¤V‘àêûjªŒûný·Ë2dä‡Â)H ù!71úNÞE_ÃóÙÀØ:T˜Ø¿Õo«ÆœnòÖe¾!… Ù‚wq?àY:; ži7Öãïu²¼Ó|Ìö‡‹ª´½øß+òÂ6™ÞˆÍ‚ÈÙtϾZ5Í< €èMxX…ä¾Bb± EÅÌ*ï¬vB“>+D·¯ÓÆ1zh"²! ®šÄ •d ÕÙ&™»QôG JÅÕÓí¯©B¨z º®½¹-óQWޏi®°ÐD³c0n„WPñh‰fžŠ/õÎ:éxóãH«ïÝr¤¶^Ü,•g^:°5GÚÖxŽÁgˆSRŲ;‚Ö¼j¹„Œ$´ =Äì›ì£/Gª€}¡üÌ1Ôì忾@kKèú}™”\«è@.vEDºHP‡Ý2ÅLrDÔhEP“ê±52º¢²òõ´EvGÉêä65àfeA/‡Ó3ý!íi6äˆ5X9‘¶9KÇÏ#Ûí[ …K”œ¹sæÒYº˜öÜztY@"¶MТžà;ÂGí­õ³àÃóE]#sØÓ´õÀlÕ[oE K'ýêçIÇÛcP*²ÕoºÌ€Úmç\n¸RˆÙ®«N> -lá Yø‰f†_£Çì5F²U8ô[ÊÝh.;73Úýœò%éljÜc'äcµg!ÛšmÁN *ýF1`ÚgoЪ;é–ÈñÍ#®5%¦ãøùÎõD¡,µ›ˆ}ó†^ ξ3HòȪôHHýÕá×{!7溜› mïj¢r7 \ß|°ùœ½H¡:ÍÊN¿!êo«p5®uƒëÕ.@o2á£0†Z='Õ‘Éàd¡óÝS3vžGY¡øßfwÐ’2ðxè/¼ Ê@òd?ù=¬Œ ÉÐiîNº|Z†Eš ¨ ÂÞxôìKiúGö˜vÁªª ¹UÖfl×üösÔ—/‹ž~œ;imбÏA:ÝÌ‘òÊ )¸A+Åuòi7©C¥¯î7ç`ö—G¡}_+ÓgÎÞëjêø„hA€Hozp¾#J¶ù“ÑK#Â)äµ9ôàeBÊ,‹jQ¾ªãá”j%H›º ÷VpÎ÷¤pîöŸè344ñZƒö¨O­SLÈ±È ÚÅÒ<¦ß9A…-ð‘Áe/ÙYT¤”ÌðAh\ƒ*EaË ’~f;ÑÐóF¸s: ë¤FÎpÅ“!Ï>Ð’®ïÞnùF÷x÷x rÈB«—£fvÉ€ƒ7¸¶P…åËsj;عr¨SXÿJMðÒ§pÊz|ªðá• &CðœÝà¥s:pÆÑTÆXŒ‰+áˆWpG¯ïsBs`I‘ÃùBnBãMòëÀ’2}ñ‰ ·À€ÌÀ•Çl]qçîçb@‘91l€‹;«æ“.£Ynƹ“œÊ„s)@ƒÊt)O“ÔÜ+Ë~Sþj)ôeµ[ Z´±w“â²³ì[’‰mwê’€€Ä¿ÛñUb¹Ó5XJ˜Qqx‚ÝLD«ÓìñdÖ##` {bAs¯Ä/nŒUì5Àé—zÁü³Þc›/UIOB2§(Z®×ÿÁ "³ƒÛ7ÓÙ¾ï8]ì6h’¼@Ž¿™WÔ¯¡"OŠø¤Á3Á/HÜklÈZ\Ö¬­W©RúÙgbpØÝaòg.‹:Ð͵Žú´Pfœ¢ð=ÖÂÝ7ú ž oK/ôƒ˜ÂÊb4¾Qš¨v%ƒ ž+‡PØ­(¹ð£R$±‰› ”Ïy+ zqõÜF”‰Ê‚÷öÝ ûcxÙªÝtëlj#gi Žßõ~¨UnCH!€*ãu[ê]‡xy « B%7±ïöÓþO¦Q‹e!„ÝSÝíX‹°–žÑ¢ .±´ÃQÝá¾Þ:Ä“ÀyG¿D’¤þÞ^aMʨãÒ†:GNÿSEn>w˜M}Ô…2+d௴Yn#°‰ußRËšeéö |#[!™BÆ ›ªTš$0d=‘ˆâ>¥µ_ü$Ã~Õ›µ¬ÃÅ8k>À» H ]@E{Ìê1Ëq–¯o£ù?Vžâh%Üî|!è(?"½êE6]hØÑá‹u—%…~êý›-÷.dÅÀ¢?“"5mtΦÔKnV PrZº_Óê°ë50 ÍcrŸV–³Þ±9ä-aä/¹²ó’ ‹wêmªJ„õpsú–ŽÈ‹¤ úíO¿‡Òïcæ`ß•ôR;‹ò4— îÕ7ÏFÔ¹Yùiå{Z$ï_¼®€¹Mß/âé´þ â!˜Pî!.!Êrº!iž¸KoÚãõö Â%uƒK;Ý’Jœ«1;e¼}6¦Úú)ô:zP&Ž[æÃoWãm8ršckÒÈ%uö‚¸(~i8¥º36¸¥×šN!zýʵEŽ “íó=èz1#Nô»ñˆGÇB쉘53æB`‡øüw1Q‘bjU‘öãé#ˆÈ3Ñ“vG8žeTûþò@rÛI¦ØA-Uýdpꟃp¿äuY’žm‰…bÞþDS’{ù½*Bhµ=iA#A|Uö»¸äÀêž³†uC!qÔE5 ®Àú+ÞƒçÞÿbïè.,uèJ'N¾ô Bšÿ+öNä@𠂃l#½Çbï¢è±½~:P% ¾[!‚´• õXJ]ôl𼤧õò9Lz…Ò’€€ñðjì“<"ÊD™iÑwšaEFÚ`oîÞKÀ"*– õ³‰‘ÔŒ[(]™Ùs§Ñe–ë¥ã-a¡­É]иNÊMƒ9_ì%sí›c÷£ éÈôFÁý‡òCô-úx̆•nÕôrÈWs«ê­gç’¯Àf{›x!òÚKçU¤µ`–Ç3nj$¾|Ï7ä”'#ÝúEJtohƒè}g§ò!ç;ÐÑúˆÿ|лï4º,ò¹C0«'àÐÞ'ƒÐ?æ“fÙµj÷›OÑžF§gÖIí]ô·% µº{\äðÒkQ‘Zω¶iïKƒ@Çí@Î!29¼wâoxâ;ÖÑ?‰Óò–.ùóõ’u¨ÆÙf½ôÊj+Uħ;Ôâgvfʪ-|‹LvÒä,â—#ï²7÷mÐÙïl/Qs‹º¼BÀ»Q ]0Ñ>·‰5Þ± dyW;ÝÐ : L™Æk,â^s  <³zÎ#²‹úKZI'j%¡S^€ÄR)Cà +¡¼ÙJâVð`aÁ £¨ò"ÈCò@ ±D"Éö ¿Í²¡¼¢hN& í£µôX‰Â«ó²ÛVP­ÄŸ1Õ –_-¦Þ‰ƒ/“¼Øž†#ì’€€ÃE*kÝù<4q[q/üD¤©´uðP†·‘Ê+ÒAºÀh»H£º²ýÎѰI<ƒTë7×Nªg¸¨„¶"ÉΩ(žõ~«¡› Ï%i[ý­Jùÿ¢‹¦¡ÇŸœ Dã?`ž[(È_Ýòv Ñû¿·4E@rìõ`í"ŒÄ4H㡈"!žú²ãÐÀÆú›q‡2é0„¨i ?&pEÜÈ’ô-^¬# 4$AFÀÿ] ßç±ã6Í_È[eNS’gø“ª+!É w¶Ýµ(–—BºÂÕðgz2ÛYµúžk÷ÙOLÏw˜Ûr¾}^µ~ DyÚñd(]'±ŽÆQS>ƒº >Asq Mübò4§wÒŒÝ(ïûS^CCÍ‘pÙ·èš=Ý*(©Cè8uóúYöP߃²ËÓŒ6À–»Í†¼Z^ÇN^Žh¥·º»‡²¼ˆ0`^ÈìÈŸ7}¾J6qÃç‹;¿ý—oFõÈÌz"Êãh’Ï\ïZÊPB2s EퟰG6uþ=^ìë#î¢at‚Þ/¨Ì ’Þc’SJÀbRštw®žCö×:Ceö±NzKUˆ¯ÊD‡K]ÄƒÜø“²’Q<·oÙïû]1*iVÀíKä&å A©1°Ó£û¦%»×\Dd¸ñÆo€h§·‡ÃìÇ!•ÞáG÷-mú‰î7y“؃§ìVsœBײÒi¿@dxO÷ñ…!}ì&"TC@œâo}°#üEU"›ð:Èqûõ&ÈÍëŸç¼²ÛvSI圳&I¥/MKTŸ|»l‹†YHVCÃrR, Æ¥y5¤ç¿9{¥ôL[´5jÑoRërz(7ì^¨xÀv>Õ¦»¥ ñKÝhf(üÁ •"†€öSÛ,uã[+TÚ,xë+ÇC€G·Ç«Xá÷<Úð8ªûOb´tPðFeqXép=¥}k*7€{_ì²QÆx޵ÕéÄ_P,¦c̵˜×}Š‹ùIvÆÒ§Õxt ¡ÙV4ÅÁ汄(\ép ç¯<ÆÁ'Ö]b–Ö’* Œt„YÒZ̳dÿñƒøþ›Ž9–-\ÉŸÔ`}{fŠ-˜¢Âþ”Ê}åPn º‰þäãUw9™Ð—.|ɶ>ú(5~â0’€€±æ: ©2¾VÎöû²&‡u§4hK/9|øCqøzTÙÓK5ƒÍlˆÌ 4Sþ§Uíu†È# ´'ŸÐðêjÒ+1ëEÉo£«H ê!ç4.9¶ÍuÞâw¯‹2]š»Ò‹N‹yêùµöÉ«E5æ Udž ½÷‚ŽÜ=$l\cÖœJ…ÂÄœ~Ûî¿ÐÑï/Æ?9â}Aí ™Ìï>A~ð±<Ñ’Uõ$à>ô#͸Q!)¯½ßû™Ãïˆqy|u`þÝÛk¯éûØoëxì$Í=«†=žÈqç4Š ›{Ò¢vQ>$;Ã4~‚¹<%taO‰ŠLq¡É[y 3FxqÔJ©Vjžœ‡_³ÅÝ~öž›û©«ÀW(Õ]¦ñùUdã{`äf$CD.Š££–Éø†£•º|qŒÂáÉ ˆ©U@J­·~fÖ¡µÇ®G¡&V€¿j¯•88î"'OTv}à'´å—­š{nGZ›;ˆ—RSª2êCë4%Çð¤ÍÅ&¢'Æè*ÎâÎ1Ÿ3»¹ø›Ü®+)`˜6Jƒã&ÃI7JtÐGݹïV9¢ãå„Uûg(øbî ÛD/\$ØÁÿ=k{~&åâ›D]ï…†/›ÛÊñ´þ\¸0À¿øï"Ù»3t›¿Ñ×aI/Ä„/\WÜJÖ½ªÝeé;FžI²hÛÚ²ó$H ÀÌK,$9Ý’ÅqÓ†¶IS'Þ~Ÿ‹u‘~Që§‚ó÷s_XÂ}²ï2ŸE×Ifn[N$³)™utÞº´ll•ÈúÞDN’²ØlÙÙ’Òânñ:´ mSJj0)¡Î½zÃÑÓsWøÕˆ|/ÿb5i½åÖ’r>“gÈÉݪʰfä÷²?À¨ ã>¶ 4>°=·¼ÙJu × Í!2ç0q°9e‰RÀó¶°÷ÛøqÕ´®å›¢Éÿ;øwÛ'ðø;D‹§—ZßÈ7õ„YÃåü Y}‘€1~æt럹))g¶r´ÉÃÿýaÀjrƒ¹§5mí:ÐôY׆ÖÌÌ }5€ß¹"Õ KÛ,ö>¿Ýðyо¯‘rlõzº ìÏCJŽÈ“ÓØGÓW½CAN½t§IŒ+ëÒSÄŽWOlðEùõþL‰è÷‘GìËSùÜàäâê#§‘B’€€Å+'Ƹ-àè3Ëamþ 4óPÙ÷HÞT ÆÕ«mhŒØZæ:nõº‹ðxØ,›~kX¢¾†1B§§rÓFë*ñW¾²m* ìÈB¢íª©†~´ë™Ô¥b`Œ<Œj™Ú²²zÒeo0Š{øý7W¡Lw©Êí zÏÛ‹¯Ò`-Š“lܦ?;}U5¼ ÒòÊ6gkÚN}µ”ªŠ*¼rtÏÇng_ñúi`Qª¢vWÞS¦ƒìf²J\ñ¢•=Ô2¯·ceÐáâbX•U›Wú/Ñÿ1 ‡¡ÿØU±ŒÎîbÓ>¿ËZéC[à…þ6¤²4$—ø©j²ã>$ƒÍxÆdç]¼µ²~B¹Û!ìl2,¼Þ_F«C=S!¡7EÕµÙ-ü@%÷;Ä2Øj#%PEÑ:¡’ÂY†Õí9Ú™ð]¹2*ê`u½Ba,êT7t¦3 ÿŒÇÉ>äD)‘â¶Óêñ w¶¥, ºY]%”tÄ <|¸HÒð÷ÙíK-3Wn·¼(Ô´5b>pjBõx;QG[­ßûÖ ÿjŒßÌÔ²(ëz>Ø&¼Ë|ÏÒèt¤ÕÛcØ„€âΰ¢ÁY`@X6ÊPÚ«5VNPբLJ7í3æüŸ“xÈ{cVñ|“k'.¼.¿2FpªVš¢ÑåA°Î) Gtæ##Î\!so:Ç#²˜"J³æ€£Ą̃=“‰Àhwç{ec‡u†+‚\áÀäÃtÀY99*ÎGD9ºYaÐBƒÙªÎ9˜™ìc—à r Ëôôd4cæŒ5ƒÿ®ÚVð¢6û}Z+áÍVÛï°5ùI/®çËÜ+7œ I´sùP‡¥Ù€•<¾-9ý_é’Z:!ôsÙ`¡/êÒ:A¦]™Ë#¤[ _DO,Ðß¾«øÇˆ¢^ˆ€k"@àVÇýˆîî»Jö =Ù@›@*žMÓÆ9Ñ…/mªR *jiØÒ›ë¢ ‡Áó´q¤#îCV¹ZáQ`§$I-º‚Í¿Ï¬æšØ•}Yå­Ä‘ò Ó5;&¸¢™ —¦¶Ñ\è¨'ÖÀ¸z²æà§»[»$MÓ®kÐ6´©+õ`§(ëÓËQ}ZŒ)”úwÀ%€Ä?*QhìpPªr«Œ…ÛË ýFÙî}¡>ÿLûgpþ_PÓB-’€€½*¬ˆL ½àNØRôÍÛ»D Ãv§T»P÷,P§ô´Ùìòúˆññj‘§±d²üý8аŒlºBþûú\8ÑT(ƒÑ¦há šýƒVmÙÞDpÀòúìÈÍÆ¨ÞH¿¥úEÔA$®‡ JfO×`áX¬µ Îã xÈ7ø ¦ AC〪]×<›ˆaåú‚¯ªÌMÊG&ŸDT:<tf÷O<7L²ºÈ=©+Ñ­‚ø4vÉ/ 0ñ®Mp }I™Û uŽÙrö…Ô  JW½=š ‡2õÜ<ÕUÒ<+Ó¿ªÃùªe’Ì\n_B;g¦M&C W¤ k;V9Ê&³ÉØ1 Âñ(ÔaªÇm’ÏNfUî2õ¥>’’w.gˆ£ø·¼žÄ¢¨á‚e¼ P‘_.¦ô©mÁ ¯ÚªmÌùœ1™í|éÃÊ…“M¯vpvº WÁÖ¶pV–íÄ;~ô~úŽ9Ó÷ǼWJ{‡9;.má1aóÊø¼H¯­ì/!åÊd*O~F@ÇåV_¨Õ'\õR4'¹Ñ߈ÂDçÞ¥(ý,{½Òª¬´i 9HÚUµ*_JŒ·ŽõI4 ÒòjûJŸk‰ýO”2²‘Âûr,4”âå$úåBŸsݨãQQÂï„âv ±ìIâøÎ¨÷§øŠ[áh¦µ¤²Ñ2ÎYs‚•h&%v뼂¶k!¥WÝ(š3O¼‹¸`ׯ¨®>ÙhKvÖ‚_—=ìrë´h´£ÿ”é; pOÈæ€PÉ©¤áˆW$ÅèWŸ/‘:Ý _ ¼ccÍ*ƆQñN 4ñiDóÌà”˜;¥÷á8Èw —¾ß£ `êÿí"]éÓãì/jm0’(?mƒJØGDº‰)x˜:%õá}›ƒï²]å4}]jZºIdË]¬d¸7‹œÓ`r Û¢¤ûœ\°|dbÈLyßÈ SÈKÛððˆ Æ*­¬Ñ%΀ZcøÍœHD@4 KÊ^{³Ëâ°d,Ĉ¤…ØŽÛ»Ödõ†U­ÃbÙ†u††Å©áww|^ÖrH=çˆÞ<†äÖu ã—“ “á5D¦fµü†\§î>Ä œÑ-4¤@©Q«úÝ™[4 ì pÌðAr¨ÇØ)~¿¤s&¼ÞFž4‘’€€ÅäÝç5¶¿t¸xŸÆÇX³wß$èœ+ÆÇÚiBé³c * fl0Þ{ X¢žÐÇSÊŒ2õ³¨µb±à,s «ŒÌ )MŽoù…¢1g"Í+ÑW÷doŽlp¿*rb :=]Î Úá~›ÍÃ#ÁÅI²ø2è{[ƨ¼Ýä¨.éü®=Ëxõ#&«ƒÇ³WÕpæü‘·š:(ÔÙÜc:¥[v*TŽ}‘!ÌÁìê¾oà—yÄwE)y>ü+eåD+eæõ›kw”Sê“6߯aÍÀM:ëˆÀB]Öì 6¢å¦ÌŠž@fíÞN«¿Ò…7Qï(ŽÓ c 6£³ûnm.R&Ž“±»Ä»IîxƾÄÞÛáîxï Ò*_s³é¬f泪ҹ %^úœÜD¡üÇÚe±j5WRv4Þšák_ÃûŠzœëEÓleoVX‚Óüíyã¿d½×.qJÛ™Ãñ Ñþ²¡GeZaÑ÷Í)™GMù~ßvˆx´ÌÕ±PÀŒ÷‹†‹‘ŽêѵËRï;OÝ=;g´qR³ì¬s÷)X>YÏšãáòøTÑô„J‰Bˆ29~Ií¹Ô£œljéD1L|qbbÄ*c«n”Éëåõ…>Οà£UCP±ˆl0<=ïâØÙA‘摽V憗ÇAø,™OžÞ.'ÞëEéúTŸ/íPa¯%-ÿ€1©7p–6¯÷ìåùu5Šß¤ùÏÒÔÕ¨‘õ1D±›w7=ûÄÏxéR*XŸ-oÁ»Ø$®%#Þöød­!Å~™h<$ ROŒAfjƒÓùö=.®ÍÈÛÉ•Ýì«Ôuvÿ•¼9À Ì!–ŒÝéRE:o¼pLÖ¨»%§¥õ\Ó{( @Rž*Í¡QÔ×dzåìc¿-·í dìhZì<›iÄg=~î‹!9p$æúÙÔ¦2R‚<§Õn4¶S%ön¤ýõ`-L+’ïxR=Oº˜øPRÀÌÅw‹ZÎÎæÿÊÖ€>ŠÂ(LE´—•lááö;;‰¹_öˆ³Ç¡éÊn=ÝÙ§µGxUòc—©"}7pl“ün°Ý¬»8þØ´ÄÚÐÖByÖÞ`Ø©L‚qÒ§&U°õ cI¬|óž›Õ±fÌv¨ª Öiå+¼ïkP7㩉bäÕø+±‰_Y¹­ÈÒýò’€€Ê5¡}FŽøFÓ5P·Ù?ƒ´ýìBÌêÔÉk]fx£–†iÆh£)ó (ŽÊË2SÚ7™ Â]w+‚ÁrŽNÛF˜k¥,h'P.ñR5PDzDì;ß×9¢(‰¾ôaGXp~+áµæŽÝBÖ º°\›7^¡Î•YPÕš ‡'§5êköö¼$)As{¨„EþëL‰ æî¸Äb¼þºR.0îÄ-O&mÅúËj8¶ØÝ¶ÝrïͰzL0÷ Û䜡 Ü&e¯×Í…%ä’´$™K2ìF9åÁœKmDšVl©P‰ÿ­¬Ky ÍW7ê`ÿŒ™Ä=áØá± ¯v$¼Î&#“wÿÍ|ü ‚WzeÁw(ø–Ñþ@e|ãzc7°B§ #Ó¾ F-ö‡"3‚ÐÇ[ŒìÕ]è @rMÒ|SDÚÙ* Í´i3-S û0!‘œ’_3¡à~xr—Xüp§–ô†”€—&ƒUéjo †QÙ#LŽk €Ä;ôaöN˜2´ðÈÚ=m`O{U]·U´M—™l¤ZÏÆ}7=)¢Z“rª‹”BjAŠF]•N õŠ-ZÿØú'ë. tŽº±Xï¸Ð<.Îqp8½(¢“äÆÃ/iQLq–»ªÍä#F´·ó¤ëáÐë£ó=µ8.C-ÍÊŠ•ª_ZÑ% 3­ò”x©h¢«»ÍcƒŸö ,¬°'Pô©¥   ‡¾bùIÆrÆ>ñaWv»l¡l@ûa¯åÚ›ßÍë¹ÊáòsÃz6ÿÌÑ’=3Û›ÒKÐ>Œq.ôV@² mcK\÷âçµ,Á¿ë #Z‘2Š!ÞÄPÑŒ“EÎ ëmr™?¶ŠGÖÐYVà®À !'ÎL fâB"b=~ÊzÌû·²ÁC÷áÝHr7i*˜0ÿÒY/8[=ö¼–3©[@,W*îÇá F€c‡Á&4•èhòJ{}Qÿ=ØÇ‘.Él=sòo]æ*xÞE¡+ÐáÁºJàx¼Š.SîéU‡\XÃçIŒà‡¢7¼{„óçpÀMgë6l?jñØZ°Ae†QÛ~¦Êg¾4°D”MM“Ãö1¥£¬¡¸¤—àî„Tï)ó€øA©Ú¹Ch”;¨½#Š´Èœ¤Tµ¯ûH,wS^`Ÿ@[Jöå?.£3û“$Èétݰ©ðbíö‡ÌŸœ½®Á†ìÇÔ¼˜õr)\3ULÔhŠ‹}ýñ™eKhr$€­#¤y˜m‘ 3-›d «j_2xßÌx Æó$\¾’X áØ=â¾ïn¸ RÕ«ù†1?«Ÿ=Ýi«€|)«ÍøÃbxZaJ C>‡hw°çž ™Ò~Žêœ`£Ë¡åP°áaJÛª=îántóç/5ÐÐy—9Oçv!ßùýš©´Ö‘¿Aï´GNƒ>ÿ“‚Ò‚¯Ç˜‚j1žý$óœ8ykíS†pð©tð<ñCɇ[ˆ6ÓºDª’äGãOa°H_ÈÛøã@g¾–*|€ÞÞNµtO£f†O…_R|`<¶¹ƒoä…Y¹$S®Ç^¢¿è~øI–ýu\d‡˜ [l`”TDéÐ9Óƒ©ûðª{ÝÄ!®’E4’·”ϰE•CFŸUqÚô&2Žô8°l¨õ<'M†½ÒÛÞïê9•ì âçÌbßÏÚÀE ŽßÄ:ñ–ö&·ož Ñ¡0^ðn#E‚ÑëÙ{¨ÔI¢½«fI/Ñ~•«;Ô&R¸™ZD˜‘5šöwiâ×(µÇÈ—7à®”“cå~Éã¯$ª§…ÙîV¸ïñP›‘vzïiÙ7åæEEûÃ7—¥œz·¿ác6ºmªÛ‰Ëíò„xÿ+{3 ‡°_QÆÖ—¾»˜ÉÐÅñÞ¿ËKZˆ¡èWUÔ~$zR£8©[Hÿé­ÄF:Ñéãpˆû‰F‹Çï`P‚£jFþªÊ¨}ƒº´V  žä#j-7¨ŽWú:+=j6žÅfH#J™+Å7of´…3îÀ¼D÷R¼ów¸ÄÈîof°#Nlþû™Ž»k¿“6ד)þk÷CqœàÄÁ nùUÃPÔžLf}„îòŠ;““ÂÆÅu³_£U"B”¾.|8Ä‹1¾Y9Â(ÛD&(?ÌÊ’÷7;ÃÙSÅ1–¥?˜°…ÂÜoƒ!e¡{AALC]Ä×’=ZžÚ†’€€® /wD†_öé ªZ\ÃŽ/‹ÞrÞ§C\Þd\ ºÊ*Ì}”Љð½v@ð›ÏUñì…Û¸/W…úU“oÂ;¯4‹üĺ$¢ûÛI¿è^ªLÞÀL©è•,¦I:»"6~‰¡ø+â{>óLÂ…9âYÀ(BbÒI– ¯S¨ø7×%šÇYÁgƒôÆ<³<½¥Xûª?‘ïùé—$Šŧ Ý-Xòð+žfdŸ‚ýFqØ(ûKå[š¥ÚˊΦ‡Äå’>>Zoôd:“dã×¾jóÐpà£B¶È~Ìå”_‰Ò=iÕû Œw‘6M2®MÖðÒ׸ô·ûÛ‹ ^X ãýÚcLŸM®õéN»ÕØK9ð>IÀk Lu.Ö–«Oh ÐVÈ‚¶v‰á}R@\ÞÕóFIÈè·ÉŠ®óc‚Pûæç´O×±l Te ÿü€ÐÎÝ”o‚TÃ&mG—æUÏÍO”sͤŠWÕ©×ÚtÑr€øb(i¹ÚL)³\µÛ7hhð¿b€£iPÌÅù„¥MÁ=¢¥´Ú£RZÍ¥%¸„ï*²!Ãö€~êW¦šÐ<—>_3ÒDu ·®ê ±ÐIœ8éÿV'‡EXŠó&?JÈrCÄæµÚY Å÷eN­›7Y(‹¬ùÀŽ¿Ü`©rœ©(Ò Úæ Ü÷kVÌ4€™Ê/†Ävóòíše¶/‡s[Lx-퇗 °X$I‘’Ê–ÑB`Ãñh3x î²+(Ëm°,?°œÂÙ †œ•ÄdD97°»E!ŒQà´û».ä¹,_‚½! 0†BÊ® —MÔ5(ÖÕ0‘9Òê¦ ßýÕu"hX÷wÃtO<®Ä‘}xì±5Äú¸>ë ¬É§,Œ„›Ë‚w¶<|AÍ…!&çíðá Xzñza']²QOŽY²¶9'ä2±’ôÍïCM ²·Réoµ“ÿÃÌ혒| Ç‚~ ¸ûê• ËUJÿlØð8uϰŽpŠFUŠ­’€€Ôfï‡Pz¬ íTÂU‡p½p{Òí/m,öùvÇÈØýò÷Ÿ&x;ÂeÒµ{T%…›ÅN7¬Ë¿ ë÷ý¿¥f6VÊdԚʊ/ñ»sqŽkià!“J²–Ž3„ÖFÁÞÑñx@âôå ËVªÅ ,"Ý<´ú(… â7Rö§;£X#—J>” Ä—Ð?!¦‹ZôÐN“Ã4*è…ö/°Çy»Jø£ªttkdêŒB—8-VÀFð¤c8o*rÇ<7P0¼ùL=»%5ЊÖu‡¸0âš¹Íܨi\J‡cC€^•rÀ0ç&ê#qÀe›I€§-®L81¾r±@$`Àób ¹¦TE“Á%\A ’}wbòëñ ’M¯YýK–&™)ZÌ~ ¨¢ä±ÏdQFf0Èå„!*,ÕªMÞäá²y|À øÚ}®B‡w²oL Ob‡t˜ÌÁ¢`@)»½L-ý‰ašŒ4zô¸ûج>Ñ®Íønz°êK98•Cõe6N÷lFþ^ ¸;øx2L6VïdË#ŒªC n‡’wBiÕÝo@’FÞ nBbw„qÖIB?ôíp¯ùÿ.²®eÆ:Aã{Ý$qôQ?>\pé´lhŰOƒÄ›ñÍ«£"¸-j½ð _8 UL¹y¶méþ6ÞÑ ÁÓò–Öe|¼¶|—ݱÞf€o‡ªâÕÇ·QëÚ¢Ì1® &7ý_—УÍ׿¢|,ÓºÁzq–`¯^}S¢3ßµÔá_Çÿº®ÛÕ”ÆUê×¾²êˆÝËPÙƒêÚA ¥€ fǯ–”AÛâq»Ö“\’c4ã|´(„HÊMN+É/±MJ(ðøëÖ¢kfí9¬mzUŒµ);¿PÍq.QXŒÄ D_‘Ù>*Åpöú» Í1öù}!”&¼†Ñ%ÓŒèøÿ?øÜò]û·ˆØ…w-‘@߯ýfEË}ì)P*rîE ´%i•ó~3€RÆ"†â•hëõ2köÖf¾ñ×þû\™Xj ?¯$“G xÎõÚ >ó(lgþKm´%N»Î-„ÕÒú7mVFîVbƒ+ÉÎÙÅÊkļ6ì¤ñI½‚ìŽÖÌ}±QN„@! ?]Š*¯ï#›${f8é.uH”’€€ð’Šº^ aPWÝ¿<™Õ%•kžð¨`$ÍÔžìÄ)Þ”puC9¾Èò0þՈРªÈ»ŸÑYl˜h’õN‹/Ý æµ@ï†~½Uü~Ü´y\¯‡m€üwr¦tЮ >ßiB"»ýY7š<ÜŸ€á—!R'\Å-_mæá¶˜¾ç`ÄÉš£MÔêŽÀÐPòGæ~ª<¯ÅFq cœµ`Ô#ôDK%¾…ˆ%%Ì+¯¬ãöÝy›N ¼{™…lÜï<Ÿ2Ã'yª­)Y#RvÎÅ‚/Æ Qõ!«^LgmÒ³˜¼¡ÞÝ”Cô|—ȧÙçÔ&Èsåí Œf{ñu› :¼äÔ…?t1†c-¶´fr‡#ެ˜™4¥èà·Át –ðs•½‚pñ9·s2w<~u¢)%R†ærÜÝ,lùžþ¨J?I³+ÿÒÄñ·§ Âôû àý÷L×­áuÛ§SwkS}âÙ~„÷§6¾V™µ~”ñåúcjŒXú °݈»r>Ü|ØQ1Ù- ·TŠ–@ÑÏ*xš3…gáÒ ´xÿÞ”¤Û©âWøLÀSà,9»Öx6Æó50GàôŠÝá`žûM]KL¯þ¤âjB^ŽºâäIñxµ$?oÙz4Ò|ðµ¬ÿ§ëuÞÀ4—åëCZ$êF4íÝýVdç^n½kRxî|RÎÔDRµzðíexøg@"8è=9-7Èø/KfySÊUz ë£…NO8;­è×øO¶mìnºÔ›ó Üb´ÛŒ„Ç3’5ÂjXeµÙ$~ö Fl$Ý­èî#õSÔÿ# ‡ÂE¹Œk¥iò×HUóÍ *½Ã’îÒ"©¤ó=B A0 Ü~~@ªÂÛóDàx4úL¢{~cÌjEOp\ž@BlŸlà›‹bŒ½;Ê1H"*á¾×pûé ÈŠ¨5sAøyi!}[þRçd”é(bÿ"2)B¢Ø(‡.a^ß2wëiC”`\±-Më¥ÀJõ´®—›s†9¸°l ŠÏ8µt2Af ¹fé8ÝíÊ Ýr3w÷²i:c™Þù|´ÕT´üQ¢ÀB]Düjµ ‰Žv¸©ªL3±âmÓ:!Y×ô1+ù6@ ýAJzL)Mz@AÈÊÛØÜ‡¢˜‡•‹_€ƒÞqpa’€€»e;ýQ¡‰èL&Œ a^5CXÖ ²]‰K'Ü’ã'õ± Ò¦ô;§rÛ5«?áKÜ:[Ü'´tr,N®> ÖÙ6öèFSõ‚ÑÛ9ç 1M!å€{($½]1ïKnŠ¶Î›"ì£v¿yEí´í…bN %ï[w7ÑÖ'énÓØÝìfw¢¨^ô3¨-øE6ßšÛV10ÊUæqÖÉ@S×Ð XAÃ0ey:‰qA(† U¸¢ëèéæ{°Ï…±ž¦6×NÊvsÖ§ÕUéš¹Ãøl¯†éÃ(:£ó%8bÖ kÆ%€ãݼàRFÀÔ4¯AexÓIAIÎZ õ§ªŸØk@Ï$û\ëÐZ¦h ùÙÝo–é)SÂ;ç!T—¢_y›¬Œà2®[…Â@ÙÑD¾SZ y™÷?qíb½ÿ鯌l_4¯)±àŸÊCœ©lã_ºâ¢…?Ö Èbœ¤}ø å UýË¡¨ÙBñãäKB ×aÕÍ Õ™Oåê7GÒ’èØ:«Nº(ÀÁÇÞ8W>Xö!KîSõÌÿ9PÍM©„´‚O—À È•]µ†ERWIvDÐÚ3û×.²9é•Üò#Šâ!“:À´>×n´Îc.Gx<%£ˆÊCûz8!ûª'g¶4à*×üÉM2ÜÖû…•媯Hì€:‡œEìãÖ¶”pú[ìå¬òˆm•4B8&Jî5 º”“î¥;‰ñÖ^@PŽ à^ŽªJž,7Ïcc“ÍÔ“Ï€hòœÖ°i<`Þ$·u»„ÿX±ëD0Pg$ê£}éïóØvQ+[ùçLÿ–„íÐáÇ ⨒·¿½ƒ\%ÃÜ=9ãSì §˜©ª=¢4•Úbuš¬*⢂fƒB ›1¾£ =TݪˆÁ_Ùþë¶ø²É’ƒ"Ì@y Ñ.p‚-$WQª„B‚®Ñ†í |ZMº%|AJq6Ä.ñÏœÅ$ßF‹k ÙÜV+IûèsRݱU°dæhr¦ü2®¯ÛÇœ;°ƒ¥}cSN;:G¹'“oÕØ‘Ã*ôGø:`­Ë⨈$²y&¾H3à…@ð!D·‹(® ¶œIˆš]^bê;;ä" …ŒÃKü¾Y_+j NEÜY-äÎ@E¢Ð;/ðwû’€€±íøÍî7 Á(é¶p·FiïŠÆPdAXk-„ÒãJKÎÐ0µ@õ=Kòò?¿ozK㺲Ë@bUú“4ÄÇþrÃÌÈÝ íàû LZÙ ›ntãêþ%¾6àhÙ”9zì^,[àEKEùްe”ûöÖ§éÙ˜ÆÓ×3s1ðf¦ùt-%t˜óZæ‘°8‰òæÕÀ@™4oËBØó”pÅXžMl릎zq‹ŸVŸè›z×®öÔ­×)û‹}yÖîOªl$1"⬗y¯=,`›~è™òË ¨„æúþÄq¿(d&a¾a*5ÞRÖëgq:,˜»½À;¾rÀ|¸€ÛÞüqc@ÆÕ¿¬Í²4ó:縟:„CÌÜ1h> 8×Ó•n‹Jm' æâ¯[$âjƒºªT¾ò)ZÒ¯æ]ï~âUþÞü_ªt¯ýH©X’€€É¢Að¶€x•‰;Ô è˜ÿÚ ð§f]–§#é qUeæ;Ml£¹ä™ ÷ËvÍ›B] G‚ÖbÿH6ÛHr»®l«k: ž™kÚÕ èäåØo~¹ý4ÙþYAÅo_¸¹t08¯~ïåpbYâKýçS'—hþn=˜¾_f·:,VfV»‚{}%ÑŠ¡…eJóww”¼aeÎɦJ5úkb9YQ„d‘ W•7lÏM¤ÔìRÉ\ Ýx^Ò6n5‰ø¥B ³ ‘Å}ïª>(Ðñs†Ã]ëè€cëbЄÑôihÖfkô÷?BI{œú¹P9§"/X /§÷$rB÷ ˆßº#ˆîQÕd¯Ÿ£ãâöæµQ`š'­: ä²CÉ—88ˆÿKÃçôœ$}5yfÏúÿ¥2Ë,YÞv(êÍÍÊEÈySµ¾Ê@â ¤§¬Œ¸­ZË]â§54ЬÈ?¤¡ùp<¦ä.ìDz"Í$*jÀoü ýbµlÁf)uˆ–·þ×(’Ѫ’°ã@º¬m f¿Q²äô´¡à×—"Ø_œêçÔ–KÆRB?*×2—.ä)ÖPZc.±O[x¤AÏy³"RËÕ-©I¼h)7‰[âº_o€áî8Áj±šõI¼§Ã«ýŠÆ(=»·›Ÿ° \í.„Ù¿‘ ÏÁåYŒ%yG™¸Èq^§ná*†’×É*¿¡pî§zÞøb+¾ÊÑZò‘e PgšŒ0:¸ z¯jÌ»r­¬ë>ÿ¤UäõÙPD]>«ƒ•ïi”݉54”u1ŽãÄ,.í¡.PœÂ¼÷ â°«–Óôç*ef\p¢qaÉžD!áF[§ªu‚¡–/„‡à!“£!ßÊLXÐOŸ(ÆEÚG†ÂNt ê¶ ·8Á¹”$ çôÂØIÛ÷kg1ÉÒSÕcv†ƒžÃó5£ÒžýÝ´KÍR{ek@oë÷µãøg×¥FÝ—«Q*j¢òBAZß‹6ìyªe~¿'ß8àÁB¬á-Ÿ[éy¢ÐlÂ|bW&3éÓÞOÛ÷q‰2¿tH QéÝúx‘}èÏÇC-!‘Hÿ¯pöžä«îxßôÞ“ø[j~¶ý`½îòh?xºÂRý ËЀêG¼›?<mCZ²&T:}Dq)Ç»éÔ;BMzŠ|? nP½3ÇœJž9GñCB(ü80ªÄß^ûœüî‹>hifã/FŸJ$DП»:¥qúÚ·ZÎݳKH!  nô‰yÉÉ“ÿÓöJðÝ(¥ª²®$Ï+Û:í¯ Ö­/ô*Μ†„µ€x(±t*ý~ûÈMˆä•Y9/tnöÌ⊚Ðì+ÚA†NP}Ó„òó¿ï¦f&³¯þ cs 8ñûd Â+½­­8‡ð;eÕ¡Úiáˆí7—ˆN#–` oâa’æj˜ÿÇQÍÅêÃN› 4ᬋílűH2+hmnóü9·y „Æ<‹Ã#À/ o8nE N`{øH¶eL9– ¯¥Ç,^¡ýðZ÷Îåm¸„ޤ§!·<¾ï›£€F:2±“•ÝïàbH×#H¾—„VÇPaAŽ n¥…Ä/_vöñ [\E­éFQå’ÁÊSz”š˜´ ¡‹Pè,¡R&³ÿí’€€ý‚îX=\׳°kuv?Ë»U&³øãéèë¨çjtï"±-ÌËé=R —°Y¸›!vè—°“‘¦ÌZº8!ÿœ5…˽¬ÃïÖš¬Öðyk×ëeÇñ‚So¤´-¯ ã_V?Çï¼Î£üµa8†HzvKýeW×¥pé#PÕ‹“qÐ-±/°‡Ø½C+:qM[lÝþCuqbZü*dÜ”õ/3‘gçBEåO_QËüÅwßV<[ãâôü#^Ä&ÅÆÁî'¡(áPN½ÛçÕyH0Ûˆ”–¡g8’ÐX ñ£8¸æ…+@˜®Ø„­@ŸW>ǬE1´åf‘'úo ÃLè©ñú9ÝÌCM\&šn:Jñ«påKL¶v®C|W¿%{U­,㥹©£¬Ž¼ãFÍÐ$“¡VÕɲER060œ/c+BwDö8v}(3—Fòv^¯—ñŠy—ž¡ !ß´Qÿº$ÒÎ7ž2&· w8äpa¶¶Ò£œ4%é5z£ª˜þzIN÷ÚÜÁ¹¸WóÃC³É캙û6|²÷¼Y¼¸Æ*¼£F¹ bʸ¬BæËÂyº7É_[ãKïB°q3W;*P”Ó-´Ð:úþû&ò¸Ó*¾Ê(jγêô1ö;ÝGCÉJý¡ÿ(àcá’ÊšŸŒ—û8=J\ùDáÖ–z$¡c*H¯Z,?M2Bü¦ùex¦LTûÄèü×¾?BÞÿ%V d5œ(¢Š$’ü³Žå` Ï7=¨À& †´'êK$g-r¡bG¼8[¬JUÈf‚¶_/€ÔÁîÙd†FB¡¨÷“ÃÑ!ýÖѰC½Öà]sšÈFGØjõçê²H(A=–š‰´Fµß_ˆ¬™£¢hCÖ ‘e¡T`ÚÂm!üjZÓVá)LŸ¨CcºÁERÏVS‡R¼ÞìïºÔïÕ¯¿U<çs#5;>AÁ-äœRŠò_vŒŒ.FÎ’¦™tåÀ¦Û˜E" ‡çÕ4HÔ{„2ªÄ0îi¨rȰD> ¡È¨nÔÇÿ.mÍ•ÁW±Ý®>/(¼¶^ ]+—¢Ðˆ') µg+À©GŽ!¡Å/¡ç=u,GNtŽÏ̽ò—Ox¡1e¢e¢pÝvd•fu [ËÃKÅDÆ“<½¬z’€€Ám:¶™*$'45+#ÆDååŵ˜V(ŠÇO溮èN øšD¶ ?±áØ–ñ4w¸|3à‹Cv㘬¦}D9IÓ+}&éºn¥óÞ€#ÒMjú¸CðýIÙ­ _YÑš ž@Mì@R€¼ ,W¬þæL-ýÇw¥ªò-v65òÛדѨiÛž³¥ÃÕðY´íÒU|öYcöúظ³®6(Vpæâx¹ö¿ tzº,S…¦Œ_ÂBT °×?dÔI\8.¶‘x wG0&iŽˆ¨–p‚UœƒdÅÐ]"R¡¿?Ðq1î¹$3õ¹üw-ËêÌc ™FöÖ+]üA‘»4“Ý{­ï—­)Fõ$A¯vƒïƒwpn*û;œ‡ÛÈ lb›G[@HÎ1ë6•Ý?Ë£þÚxƒ}gQ€yKv£ £C‹¤v“:³«>]"‘¥0Yª’—‹ ÔJäPÔë“f²´ûµ“Ù8v@jû¸ƒ¶$fñ.š[ÛZLüKra€¸`M»ÅGGΧˆˆ!CÂI Vg2^i: ½'ðö­ÏFøeÍÙÀŒ5ÜU7¢)nÔjAêEå´ h©nBåìî½îÈíó)sGƒZNøXéµâóíÈ“Û:Jé›aAúò‚ž£oWöŠº òNK2I›>àw÷ß±Ð?ìÕû}м];~4|Óå…†c¥‡·;¤ƒé§W/ 3Ã>¦»h„ø,Žcë­â/0!¡ Ç^>‰4·éÈT?òL¾(Œ%w©hÙD*Xø9³¥H¬ž;Z^(ÒµѵO++÷¶?î,éÁäy¦¾åÈØÜdLÁxÝ–ÛüWØVxs}?­Þ1·üW4ãYæ­ßwÑ6ÑÓBF˜ÊúûŠÒ6#ÑØðzÚ‹¦ åÙèÙv`)b„1B…žöºkWqpæ­­e(UEøDÇ2©©ß¾!»¨Lñ Ï2Ê`KØtFK(œ”è’,+äbxÜ9KF~?ðqºŸÕ¼)h‰Gg—ƼsÐù-·'‡Ü_¸sê…ýßl‰:AO+i4©3 —îM»É¾Î;‘òm„0&Iù$Vu ßséh[¸OœÕkprVƒÞ‘¥4•µõñ>¼µ¬ E£þ€*­»÷Qø(É¢!»™O*Öps–’€€ÝYŽ>m÷ë1,1WˆÒÙ'uñ–OlD•0Ži&ÕÄß³k †u§/ßuþLÕ\“Ñ¢€’¯Ý\ r«[å8á=ñE=äFUŒÌ¨/d¯IîÝ"R’H‚ŽŽä*#=Ë0€ýºŸ°zíärG9¦—iníŽi$G49êHSH¦þ`ƒ¤Gµ½Ø'Ÿý7Æâ”o¾iíÇ‘§eVà0¸Á.w…¯Š°öQ @y¦ñLE™„’½»l~'¬ïg%\Œ{×?µ%¹WÿŠrõ£93Ó­I5 bÈq\÷4˜-‰Ô˜b&$+`o|ÓÙ‹^f´„Úž½·8ýHo\ÙÞ&ŸWÅ&jú ¤Â¤—9›€~æSQÇ‘oc¦_{ä…<l"ìwJ~“«’l¯z{ÏíŸ,¡ËÍæ‘Xï…½ÍîT ØÜ‚j%—ˆy,¦}[öųOr*å8ˆ6­­léî@`Ý„8:AÈÛc¶‚L«RGUwI$ YÅ—‚8N>)¾êy"ñ”æ¡*JÆlþÈ<ÎlQÓI˜"õLК ‰Õ‰È³ÉÑ¢Wš¸h_#(žÙ,þ`D] ±bæ&^xÚ$œ$‘ÙÛ*Ï;Ñ â”Œ5µé/ áuÜÎ…è-*à)“¿õè kZpÛ»½Ãö²þë˜Â¨Mx…!öƒÎ”U†IMa‰!VÉÞ]É›qûÿ×>.›Uqœ|çèCC‹Áí÷,BÓmͤªhíÖ£ž]Æi['èü©<< Òß²Ûñ0¦Ø3Ñ@¶WŸ/š±l"†GÎ3exáù=§¿¶) Åîñ;"ÃϜɌ´`"ŽyR5øaåÝÞìáø s¿ìt£‚ qsb &64 ’ÌF¥œªÎñ‰àRÒöêùÅ/ e\Ï„ªØèÌѰ•6ÿ™ò1öO#!9úMͰ^ц‘]m–=Ûd;¿{›y¯U­þ „­[Q¿.^E°s†~×Rlµ.5ñž™ÖÄWr"ä ·ÈxÈg‹j†X@îM¼ØI£K7S°¥©=È+3T>d™ÌƒŸ^Ó¬B¼£Wù¯–?ß x!tÌʸŠ>C¥Ž(PùÝY[º5¨E&:·%&ºÙä×f 1V{¯9¾¾˜Fo+Ù¤Ÿ5øwr(l”¨2‰9aþ(©íPN€Tb^ûŒÊIÛë±£c>&<­Ÿ÷(ÂàÈÉÆíh®X DWäÎxSs¢P4&€­Ùßô†ìAÙì)ªžU ôA¤úU„~xŽë=ôÛ Ùm7ï¬)Öx…ˆ«Fºœ $>få0;ãÞåÛ¾óK¤çœxÝÆŸÛØïúá—ºÈC’uÕ°Uñ£Ò”Tàÿ²e—ì¨ä[;Á ’&Ä °ûË.á:eîÒ#ÇO)XgЪ0Ìïôë%øîá›}…ÚñÉRÓÃL™½2ÌkêņTfz4“‚Èû÷ž+ 2æ@¢¼fùAYõ”ÕÿT¹àÙ.‰ÀþøR•Z;rKuzÞÅ› 6–­yàLkĎ׵ÚmC@ƒLhrp,»Y¸sçì“i1AüÖ¢—§‰)Z‘´¯=2Ð-¹0fTÂa¬õ “õóȆ‰Ó,Bª; Õ2Ò|/$‡<œâe  kð>8(ƒðyï³W›Ã#8x¥x‚KäªìˆÏxŸ#­Q8{¦¨ÑÖH{ë6BÝ ðÊÞ§Ðý5¡&[h±Ôjµ®ç„ùÇ™­=Ê ˜Ø®\þ¡lXÖÇwÛ×'-j¦;Ÿ$ДðäM~MZ”g°1Ôwn§øOâ<õA‰má2ùbs#2Ú…™¡(ùL ð}ª(Q.“ê‡ò ϰ,8鈒¬éÁ;çÚ7¶¶çƒÄªT¯¹ÊÿcaÖ„Ä)6edö¾+ËAôV,3è+ï¦ô•`?ÏII $.´ºÐ¶¶T«þ²ÑD||¡1ì(Þ©tJ¦’s"p-C?›g%ªÕ‡ 7¿æþZaŒa k‡ØÀï²TL›n~ŽXÄÕ˜Gul‘Z^ÀRÑÖÒÚ268…T½õ¿Ñ8*ônH\ÿ–¿ç7R”‡Š4§4N>n+¯ºrŸMéØ=‰ý 3R{u6A‘®» ï;¤p¶mïÜôB™ó‹ZÞ±Þb2£·õ1=æbškx-²gÇ?ÍÚýòUv“[Ð)…Q®TâGv¹7.ÊXÄÕ>± …uÔ’€€»ñ?ê¿Y¢æŠÔÏŽt5Õ.„§ßïaÞ- ñé2º0êœnêy€JQŒY/—úlÿÒ?M Æj¼ÈõÕW (“€:5ºëiaý€~Ƣͧqà˜tóf«]ör³pÕÎ#Άí$/Ê¥êÏ@…ÜL+Q´÷:ۮঔj³gTÜ _žž÷6Öº/}wŸ“c~"ÜÁ§{†¤6 ±ÑéoÿXZEû‹Ì̬¹’Šû¨Ü)>Ìú³z·´ÿ¯3¤·º±=Dº9m0|b‰~íÙóÁ¬tT†éÿ9d‡yvÒû„æëA—`±ÌD®h©d¯âfmá–¿*4³òWW L§\Úœ;ˆxf?Ô¯WÇÔû¾¹ÆïdY°˜äØT`èŽXÁ—˜*Bàr‡`š>ýe#7LCŒ_ÚÚ,™P]=¡},} Q™3"ËÕýöÚñCÝ×6Ø{Š0\9ƒ<£ Á®V#Òº$êh©”ÔL×ÖwµCÉÝL,ˆÀAJ|!]nÌ’2[0ø”{E’Ëö3=£aQ€ G‚ÛóÐE,ñ±_p¨.‹zìw{9(”îÎh["<›¼FT}¯E/ [:ÂÇQ¤“‰ÿ¤µ–ž­ß÷¥ÍI±®ë§CØã*‚Ó2t:΢™ÆJ#eŸáÑçÓÑ£-½E˜Dœ¹RÑ“ø,^LÄvøt9aþÜhÐ%è°d}æêÝ{:Y¯2‘¬—­öƒ¸OÇiˆššAÿÁMFž“Å?~Œ¿ÜB½¦E”“uUÌOã¾o.°ž¸·E"Ï=<ë±ïíì¯4'…}X±Ü6n«' ÒãA¶K1΂و}¸{2©…I‘Oä8>ºú©P®#÷¿AcÔ¸â‹Ûø3ên­ !,FÌ—äJ%-lmd|nñfºhYB‚ 6ÿ¾†#< ³Z²hœÛy )/ û®Ì8µ=åééLðgYÌœì¹QV Tåý>€Rc¬Eãs¶•ÑNŸcTAQá„Yt•/k¼þ®ÎÜŽ¦±ïú]¨7<ÞrÓÿ«å¢ªŸF§¾›?Îr 1ǯù&Ïå£ÖÎuRÿH@ ß‘ v)±õPpÈ÷•h”ŠÉs÷F¢lµsiK«Êrë3?ƒ=î¡8QáÁç³î+r2`È(2ÊVº‹’€€Ó*ª•.üo”ª× }çh;ÑοÅï{cÕáÁåg°Á”‹âÿOän âX÷«VØ|ßõeßÀÏNÞG—e@0O~ò¥à®iŠÆºYÛÈEËÑH!£8©–Ip‹ï÷As2àÁ7øJiˉÉw2f›P &ÿ-V©gI Ï9•5?¿‚d2)·¼šÏDÜÄ€»êÀ»„:йû4<{[Õ®›||t4™‰GÕíÛ8CÉ# Ü<‚áSzxOÇR߈Vçu7Fñðƒ°Â»ÕNšayµ=‹‡¦Ò@žT÷Šœ‹ /bmörh÷;Ç© žß Öèá¡/Òx\¹næm:qGn‰4TxY|—Dâ]XK4_¯vu¢¯ÿ›Riˆµ#w”^úc«ËïN0óàŒ®aÐY“@¨[g *À4ÀÁ.¨Ý±S×ͦF®¾vßqLpZ”+%÷ðžyå€Rõ@‡_dXöù 5M¾0+Z(œŸrB`oF(~pPhaZ:¸†»¬¼Ó”9zàÓÂ5÷<¸¶Jq‰øЧuÿ1jT¹¹c¿Ù[»E±ûˆU [ tXÀS+\šë홚eΪ~–åÎÖsRþÊ‹¹×L:J“<-S‡ê­+ñsëKÖD1Úïã*ú¾AêK aYk‡ÐÐÅøègH¨8Oß?pz­ ‰<´ùÏæ/б…Ê: Ÿ2 y~øÄ×1I_œql¢C}­C†û€/¹~‹úé;¡‰ÔÛP¹ès†ìL‚Á ,¢ŸrÚG¹Ÿ÷8ŒZm–#Ž¡gk¨°£Š±–‘²Ö#õ滸íGˆG¨VØ=´¶Ó¢÷•…8¾§Ó”©æï%‹ôãÈá›d ~ÝœK.C0yHJže@$lu g^"|9$ÓŠ!ÔÐߥ<¢ÕlÉú· k`ÁŽL•qçîàþ­NBjå"ñ_°ˆbv,CFkøð@¿_5hb µQó*ør[/N\{ØÄß׿8©qX%”'wmH^›0ó"ùOp%Šß“ßH)G"•ÄëP´m‚ß{J’Œ¼…Ïî™åŠ_«­.êhž„žÖñ©»â™rj餑œ4÷¹ `ÿÔM' -£‰$÷†‘úÁ’€€ºõ8bµ‹åáÿ«òfƒÌp"Yן—†¾Ì’Ò380Ø6SÒù#e²&qêF‰Ã-IÂèíFSi;ç{¨L»HU`×Ú²_š®¾)§”ñ bÙéVM^µ·_¨û/9+Næ 6Ô´’—HXb¹w5“šï&Ñ ]"ýeó“ ßz9[°€Çò祊OS•.úÉ÷,×Ð&nܤ‡VÍç^QUðæºQe°>‡gocªž Lr üv«Íä—&é¿£}÷¹Ê·0Ðk)`­«W‚‹òxåˆùNYnÊ¡Øî¢YãÝ»i9¼ÏÍ58`[Ì´RÒä èÈ0Ë@‰½0Ó ý¼8Y[MºÍ(¼ð[NR-lŠ'åÜ@?ä&Y­/öMþݼï¼M$EÿmFÝ‹0¯Ôéÿ7·§ Á|6&Ä˯ XZQ8¦Ý7F£6÷›é_­`1V”0~k97ˆ¬\Ç»NŒk‹[¿PrÚ_žs÷ÑánÑÒ*e± …ïÛ͵µ"‘À„ r”sô³—ÈàgC»«ªóå#5ª,@´y­ìî þÉÿÍ·¦M;*¨f#N®Eø7q2ø'ÝbØ®1Ä!Þ5e}Dz{sD1¨äßÌacšO1Ñ~d6Ï^ Ä?6•’ÔM æÌzð-|–¯óQTª„ÆeÞ/ÍR'+3Lºà‘æ9xÀ½æùª”ñziîŠ_ìuè  )NHóÚ‘`ñw‘ÏäÇÞ;·û›‰×„”H0ý6~¿£ÁU rØ»^,?É#lÞQ3I[7<Ç=‹y¶¦‰Å‚^ÝïI€X?4?±}„ïOn51I¾M¡Û¦É‡g‡×hïmßéÇtíܽ_ ®d%mUk÷ÆíRCWÅ}\8lÞ ¶AQÉ$þøðßÓJ–ŇÔmòœŒK–¦ì@ÓmÅZ¨²áxÇ? Y {´‰Ö5;B7å½´À³NÀ#¿öî¶'(|Àì´Ú†¹µ I¤vùÄ6PÀ (,l­k6_U:Äí¯ãþ§Ü–¾öüˆx±ÖÍ^"fŒÎ¾µ@®]Ÿ(¯¥¿œZÿ»§=MÁ%q‰ß¥uWP~î»Õð·›Çâ=|mÀQetÅ<ïÒäðÕ‰äeeK“DœŸXéGJ+Œ¸ ïw‹Æ°àf²Ó¢lÚ5q’€€Ü¨ºCºvý¨>G–1mý°áå,Ï.S Â7ýe*4xaåm~ô#ù Lj‘I°[V[^šáëãÝb¥10 „óåÄYTµ.—%*rHWâÿ„FÖ E’ÔV0©Mõt˜Ãx »1<×ð'ÙÙÊÕ­$PÈî3çByæ©{Q-izP¼Zí§šNŒá&½Tg-ý …1³„»oø|\#eñôFäö˜ìÇ„WÇUÿºPÙ$ÿ?´9¼àkß"¿ýð8âTÂÇtåÕÿ?ð©Uåî’yàϯ8Y‹Hé{É;;ÕCT<éîŸpùöv½U‚§Ü¥9§Eí$‘&&isnR½´‡Èó³ͨÙf Ösðs8›Õ™¹qB¨b•òa‹¥/’Wl.åý ­ôÊÎ<¾)mÔÌ.ëh=2€ïˆ,¨uß$=Ê0“Ä×µoÉÜbPŸÞI[C^ÛÜ‚•—Gw}2¨-å!}’%Ò9á>kbô¯£cÆ×\ .(d÷—ª50[-ß)¨¡Éògu~‘v²QŽXÅ®mkìæT×’eÉE/v «€/€ˆRÀB7@*oâ±ãû¦J꯿lÕ¥ü޽ Ðñ÷ÐE°c2)áZ:µä½~]ÒYÅõˆg/ïN…Œm®îDðz®«$;3‰óMѾ–®¿à®ã6– â( õüB/a®0}§n>Ù”H’kÛÒ;3Àü~Tøm\$´¯A¶ÓÀ.œÝ„[¡zš©¤\¥©ÎQ]ÌÓx.¡xÖâ—-·Á«ôärÚÊS!™6^¹žºáDÓºéÔJïej*ÒÊqÁuž£uó!èFáÛúÿpªÆipÏáf$£E¹_ëÊ’½ZAÓVö1à`nz‘šª%^O+I&t=ò5ã )v•_ ½¸ 9³Âª½Ù¼žwE~Îö¨l}:㥥ÜF°y¾a`=Œ¦„ËfJ¹æÜ šh%šÚà„{—i|¶ê·’mѱ9]Öºí©×˜ÀlÚfŠŠ:èr˜rH§(ô]{÷fyDÞÈ A"°Å°ÍO0Oª¬¬ËÊ Au°Þ¯ ýQƒ?Ða¾)•mÃV¤Qi5¨ÎŠÑÉBÍÌ\ã@nç%ùÃÕ©ugê'ì«gÅzr€zODñZÐ?’€€ÄK§0²¢ËÔÇš²nT]³ˆcf+o5µ`dÜVß<ÓãhóáÄá%N&\ÀàH‡-/<Äéïp78 ±½ÙTGœÚ÷è¶ÿBg\V"æ÷5Ï–jf®Q“}Åa®o>à}˜Bü g5°ú»'ÂÓõ¡GÓ°L§i{øoÎ1ˆˆÈK Ç‘PR:RÍ[èkøùšù £fŠ${úM1±òl-)™ˆW—w Á/¢ðÇÐÛEéIÝ¡òŽY€@1=¥»/>”åoÛ+ÑÂLµ·•D²Å Ò<­%59–ïÁ[Ð7’9Ô'1~  &Lr…¨ä™õƒõ_¾Ñů˗»S¼¹ÉÀ¨Þ¢ÇëP´+Èi< aåø“•ÎÿM1H¦ºݽŠ}É’Ò¼ …™¨ÎÜ%Ö4’ŒŸéuE8Ü¡™Ïõ-ü\ 9uð‘t5céûÞl‘’ߪÑmpå1#Ž&è:Üx'1öd#•°‹¬¢Ó›o»%êÆ'IÔ°5gv€Æ4×’˜þêa»¶@M€â®ÚKÌÇë:e¶d½h H†š&M”R²6Y°Úž´ âm¬­OÖþ„®ïY*¨¾³Ì~,N]$µä÷«NGAËÅ•ÕÚ¯8z‡Ž¤»8¤¾ í•ÞP1I3½qňWlè'k ^›ƒÎžëšíÈv$¿³©µÌuócªàÏØùj’€€¸Ã[¬sóvù®ëîr’hõ3ºº‚³VY‚–rY%”“èê;h:¡÷B¸ÝØœ<ŸoºfOêgøµ–•Ö¯N¦“žÝgü]+6Ücâ‚ ã½i•ä_Ly,·Þ\¸ª§ “yb†ìÊ':Ó­’ÖÚ»àqCYT¥­6ñ=%Âmú§Íg–¿ÞS0|òÓ¾xpVˆfhßÒ{n ìöÆ.Œ Œ¡5±Í2zo‡ÑJ8Db”î61ø›Fo¡#©Þ†C0žBEÈG¦0*®>¦žÓnœGÛ¼·´ë¯ðBFi›%˜¼È`_Cª&ÎÇ—jB#twa¾óïÅN¶ëŸ- 9³Ó<\"꛳ ·æú4µ5£Á‰$–kZ­à=Ý^­¹Ûöýä[$éo_òÌ£H9ÙU<Ũb[¤1WÒ˜íç§ ç\¨Ü©_ÈË èªÃÁpÈÊý„5DŠþ=ÑÞYþh ÿ½µ§„ãÝ_P®–þð²ÕïZRÊw°ä$¼¸KËN€‘T>åƒì¡9«éý³7d ÛàpWµÓvgžÂK+ö<é[¾ûŠLÛ‹<¥GjË‘/–ÿ?½8|^½ÃWû¿™ÞiZ™Þ{8˜Ó@TMo×ýÏ{ðß4pÆ-šƒEãÝá™Õ æ»Õª*‚[ïz¡ó˜G… {œ-XQD ¿…=rŸHñâ¸r¶'ü @µÍô*•x½TžQph€ÚÖ ëO&Ïúö'a™û‚ñ hÀ« ³(\—<¹Ñ.æ!c ןJ %¾j‰,$UGR°Ø ývíÈ/\bÃJJNû‰0t*[´'U"ž]É)kl³8[ùüJ•º3²%x:‰X\³Ê±%60øÌk÷깪¾º|EÊx{…X ¼÷oÕ‹¡«ôaœ7ç6n#‰g’˜ð‰Çzc•¨ÅìªMÖ|ùŒ†0DÙÜ¥¬È-°‹®Çˆ{ÄDe—ån ÎëºÜü \]’€€Ç$½áÓ Ml™aHI¨º ƒCú­2¤ºD`Âÿ&̭ꉀZV{Ü„ÐÈ_Nmž=ŸÊtW˜-°0<lyI÷:£ú¿†T[>ù¼„g8òpqU?r})AëÒEšX÷=Ý¢„–S_õèE‰¤+ä2‚¸ê êY‰ýLRÃÍÿkOÅzK¦Tp›‘ÿt {ŽNÓ R­D4ö1Aã7³·ÎÖµ\µ0ñh‘Ï,ãcTš¢~FØ —CìS&Í =Õ.´8¾ñbÃßü¹¯7/NÛÔ€!myûU\ýE.¥$˜( wïpLÈ¥Z ô,”„ ¾ãÑ=Ì{‡VËD0\=—ó?]ö®+&Ù$x¦·tSLºÆ|‹)çL|$‚Ák 9Zs4Prƒ+9ôøŸ^½’"n&„I°¼1ºmðA”˜fö¯)£ß›¤®§þöWwã# rÕöž^œoÀv6r8Û¬+D¢­ÁU@®á’ݱX¡1 Q FíwsMlõ%œ”ù´;‘Þ×Ò š:Ü^¡Êù8EfW¿ï%‰>Þš~-V•Áñ+R# Ñ¢"9:\í<~:±ï§‚3ºÞx×í0ðêÌjn†c †{3ëdf¥e‡ÕYÚˆ9¿²{t+Ê5Ú0ÖÚ*67ÞfÅ:ÑDAè!×dE¨p]$™÷!hf—(E´—0»ûæj»ÃYëŒÖYËLQñ^ôæ+  U²ôNdÞ#&‚È Ví#ïp“«¯^׉ò^è߈¡&ƒM:ÏúàC8<}É^c“¥ÇP\ ³¬'cÚ¾4—.ÎäÕáõÇ’yÜ¢­CkÜÐr¸¼ oÛžQ)O(µèQ/ éÉ•X D㻕/éüg<ã—CÐ×mœhëÒëž,9÷¬œÅùðøŽ/ÓæòJqMY"·gm)Nš+™W<¾ãÍù ØBhI>&ÆÂc$,£‘ÍâAƒ¦]tÚ Ýž·ÝøÏˆÖÆk¬Å`y–eDŠ`Ý­¡×CÄ5Œ÷Ø.€ Ù$~æóÝÔDXì³ÛO†Oq8ãcûmȬ¹V4Ï`籩„‰šg–ú A J? %yÙG?¦¹âÎi¸æ† X q?Ò\£Sè7„ƒÕ®˜Ælß…vÜ€Ïb÷ú4‹7§˜JXÈ‹«i’€€ÝÈ"É•·c7—#Føkå/p²Øæöl>_”Žy_I£¡wƒp¶a‘Æo­§U‰p‹®ÅÎv¯/h¯­uœ¨ 'Ш ï»Û^X€£l+fúÅI ÷§š'ŸFJͽsÐóÂÚjwæ1Àö”Ë’j_¶‰îC©ÚúF2ü¡zJ–ªØ3¡|q½0vG%ʘA×Ilê;ê}DPÅÞ¤4E%³m=Dö8{ªè§Ž-ü=©|×ýPrD£Å„u\°d/Æ(S2XÊ•0â;Wy{A¬½2n`ÆØ¡Óú9ÛLÛùñ\?47Î'¹WÎËúÖª”3Ô!bÐðwœù|-2\‹#s]Ñ)½H40¶Î¯ëÇ#ªË6Y—ƒf  OÌgÒdjo²Û€¶g'òñ覈šå K&a¢³åV¼’£: ¹¼€@¸¥q]òËlšrØ™­Â)q :•,rÒ^\Ï‹½ßK°Øí3ºù.ó¿ZôVÝ«@Á|<¦ õx4¨DÅØ©,ÅlõY]=/¢«[Pô)0²íGÄ_Omؾö³r™±¿«’º.Dm¾M"Ín]êMæ©å·X¼ó´…SÜØÚ2Ãé1°x‹¬ ìñ ©…Çh×fµx5€’­¿àéé´S¡™gŒé]Ó`¢ÖY~A_6"·°Ëâ̪vÎŽ@>·\W=ÔNdÓ[1ZfËcLrAÕæú¶`=Ê• ô¶yjÏò©´<†Šð’16hNËÅ[œ_}““ÓDĉ?ÄxØä’5 KO¿ƒ K¤¯ZwPÝ@oÍiª5tuŠ‚ÖÚ?Q-++¼ÝvÌl Ceò °!æ£ïOÑN,>[Ïܱ(Z•´ã’ i¹Ö´AŠ#•ów1°Ó®%9*’€€½âJ÷ðšÁbÒ¿^›æIÍ!kcðŠÆƒ=Ô ?4PsÛ¹£ê¥šNgãR?%(E³#ɉQcéïÿH²LÃbèþw*÷|o”o\<8/è ]„yè¢éRìáÌ»Dí×[ß?}P÷ —Ohñ —C”PAô:ÈgHH¸ß5Á0°zÁ²Ï êšèœ ÊòÆ+ÃÄ’DÏÌCd“+¼f’o¯š‹r¥íZ>Y–ÎØMÒÐd¾B±ÒràO0Ä“E¥É}Cz8оwþ…¸’yæ8¨Ý»"ŽöšÃf]Ö&†Én¤”Ç_Ñyù‡ Iý¢É »èüaÑáll…Ço£ÑÿqÁ*.Ë¢.¥¯_y„YL“‚A®ŽŠÙÅi둵Èêì‡o^IôÕ~RðƒI­öªÍ`žˆÛû¿?è·Oa–“5 KóÕnl9í^Û¿Ý„ê š޾Ù~K)¥u·ÐhnÀ˜ìÿ—R8ïÈÿ4ýÍ)LT̰ãËQ¹•vAT‰Õ‰èÃØÓ<'?ã¨ù›¶Ö@°Æ kÌU®…qÌZŒÀÇbMV¬“/ i’€€¦%ýœýÁ¹²¾|²ÿyYãj©w«¿7%w.ÂjŒ„‚ù𤵾VýP‰ˆò±2)•¦šH³¬õ”A¹,‰úÉ­…«Q¹(c­ÆÍJõÒåŸ ˆÃÜð¸ÿ¼¤æËxäs"·fŒJ* = Jh^±è™è82jfå*ñ²‰w6¡™Úü/MŸ©SSeMV÷](jÙ¹\4€¾îòo6i‡›¤þór…$®GÁ)âYc4i™iéÄïëwôJ¬KVN,zWY]Ø|žLÎcDF%I#\Ú×î°—u††5J“'_[˜Í“ë Eç‰~ÐT«CqEåy£#ŸÉQmpJΆ¢©£U¸:H# åÿ}Pºt3<„ò†~ÿ½?]ô­é_e=çbA’GjzÕ-¤É>%Eyæ9ɘ]høc+дÖw ‰³™i(¡x’Nî#o i¥ îSVëm‰KЉûØÀ²5æ‘¥um…ü µ-뻆Vã-&۳芮î}ÞÕÿïÏXQÉó:ÝØ¢¡ÇúJ®%†Š—á^öVÞë·ÔsòBñ16¢„B,yâh|×>`Už¨Ê_ž¯}gdßµ1.'Vûpèû2oÇÃtYŠä\Ú!R‰q¨Z“ͧhÓA$f ÔÊÖÖØ%{?úû­Œ0¼à ~ˆiÂC”s§Ö·WÇŸZ•]\ú.ªp8ÅLS?m ÒîË‚AO¯y¡Í™¾1Tcý/jf/œýÏ 0áQèœJ¤@ñ¿ˆ¹7(ÃL@;Ðw2XÞâÿˆXÙ±kÑL¯‹lµÒÔ*³¡ÇâŒÂé‚ÿ_@ê:Ýú8~á8šÑ[Œ¿O8=@ÈŠ_ ùú½å}’›{5+=i)Ÿªg3sÀÞ±º[0@/±½•ìúh7ÛÖ£X|à4X4åoÖ'ß0›-!,Ž®¿X QÐHã t.,ô¢3T2ÿ®ô‘Åô@>&³“aùÐ3‡ŒVæx§ÖâZEBà ^$bF¨­¹Åùà<òÈìÀÓÙWBuÖßTÄ*yJ*ÁUrÓ¯}§MûJ•„9ÇFÔ5:’vÝ%†^€Œ ÃÓ™óÔÒ‰~îG1¡úˆäX5n{ZÃÜζߡýnrX9Ÿ¸°4ÿýÝ^î:8×I]j'9Ú¦8mÙ?¾ù'ËY÷´<ã]?ÕŠ}EÊ,KBý¢ó¿?®ì6Bâcq)>‘Kp`øú—©žsße±ß$Ï¿p lÜ@%‡Õ{åxïùªçJCFr‘ vˆJˆŽ† ÞÞ˜,¼îÜH}sŸ€ýÆÎ/ ]FY.¯lÇ´ô¹1$$¾4}; ’þÎ)²„~å‹9y“úê]ÄçRà;sãx}Klå²IÒ„Qr ¡œæeªX¢It©¢¸ÓÏ£ðçÙêõÝG¯Œ`` ÜeüÛ­uÐ;Á6Ôãûä‘&(.¹/!*ÞÍhÆÏg>$F¿KEÊŠ7ÌÿòJ–r‰]QžN‰cEÅ—n´]~HºK=Oà„!›Á–Ä©„Ê„?_.ɇ40° ˆÎŒK„_X'’í³·‹´Ž­ÁÒš¤t'X2¢éñî„f0JBŸo|'$ç uB؈ÌÏ(»óìUæôÛ‡œ†Ò%í80ƒÇ\¦,î:ºæÆÙE“¦³¼Â`ùPq”Â0ÖcE¢yW˜ -žòIDµ=ð0­€Ï¸¼2Y=zfÎ €ô A F÷õ”Â’{ŸŽa˜›GÓÛUêèP +1neþÚF°‹Óø.¯°ÖWÌËà‚²Ñ—®æ±¬ï%v ã-BÍV+¥¥gC'L–éh`àM>@^«”x{¬‡ª\n3ùºÛ ®!ôº>>_«¿H!z4ë}bÉÝa…è ÊÂûÔì ]yÔž7Šy—®“ß`D7Õ.¨2§uT® ÆnüHŠ(ƒ}CüÛ±AÃkœi’¨Ú~°sXßxêÜ·ˆŒ¹™ø ©ûkõ?§(‹;¼³}ˆ¯WÞqP“]WK@i«rL)zcCr¢Þ'ûê8`p#}“&ÙDÙ@¢Öx-ëÑÂm{Ic’€€¯(‚T®³PJåV‰ç!c7±h˜öÏwþ®£cA•éüÿdè4CV\ç*¼ÅÎ9”é÷?ÙÈsΖØiˆfOÚô7úˆØ~I÷Gœ8©«v‡}‰LrnÕ 6Ö8›ÅÚ\“YUô1ÍÄiݸý±'(Ów”Ò×ÛoÎøÉ^fœãÎ3IZοÏ¿kÙÔc1+l/¬Wñ¢Æ›ovºÒö£°T3!i¢DÂmA™üm²Iy]˜­Dž²+= éÂNz%¢)¤ÌÁ\[óÅoc«>Vˆ (üiðpÞ4±q¼dþ¤$=«È9º:F©—W–_oÁú¼#ÁíÀýŒ³'0hꀄ–¢$dnÂß™ÐÀˆSW¦´ºÞ•÷†,žœ[Y5>ë<€ŸF—TÄ¡Ìé ƒ…Rm•4kG´æÍCbŒí§ÃBÏõœk5(t•ÿ—"ù YXý®Þû ÇV`œT7“… ûtÝ䢩ªþ»Q© «~ÝK0™ø‰eqñ³T+³ÎæIø)û{ÝAb5”Ú€,i¯{QJ¹¢[%v–œø¿Û韛íˆ'/å¥I%Lã(ÆVäš|x_½ƒœ‡% Eã*Ýœ67 ¹"QN¾”9nÜŠŠ ’BÒû•ÿ«'@h§ˆJ¹¼ª¯ÀgÔâöÉ}àÝ’"kZ8°ÌåÊ»nÆKGªø:†/”’“,ž¨Afý |>Y"ú­?šç)) -VkŸ ߘ!§"©~§;xŽHÃáÜL‰ÇªdJÒpqÞB•@eÌU;,DÞ*›g/ yµà›ð¦TßlÒøÜ[ÑÊm¹õlßÇi Ÿ«^–jïSб/1EQjrE•Ë@ÿcĶ»ÓHeÁгüg$LÕTŒ@ý(œ  šÖW€Ãðh[dÈm P‰ÑR%({¤DEºéö,9mÏаdU¥Z“ _:ΔC#ë˜I_@;`]QÃwë¹vèï\yàÓŒ[ô…Bî®(i3¬åëâAP{KgÇnå½jÔûŽ©Ýl#ZéÏ…ÀÄÁ ͵þN²ŒP)„?°ûßqä*ryíšI𭍥 ‹¾ ΀¯±nàÐô:Ú` ^r[~ò.GðNr Ë&æL“ÃzÝ>~¨©LGpj¬iNeŸÖ¿"t§åP×£˜~T²£SÞžÄÃ]ŸpBî£ -<æ¿Í$ò羚‘ã?¤EÉ £é@ ñ)cÍc CtXT¸]p+¹um‘G¼œ *|ªì€"/º´ÚóÃëJðGd‹Yjm,p˜wW…O¡Åôþ]gÁÅ„¯ iêóáû„ÊkË,YÒ¼L{«Çöª4:“»˜uôš/²VÃâ6Þ"‰‹²¸MDT©ÛwC‘íÄó8”&K Ÿ~Xìë™ M§¶Iâ¿ ÉåfAL…`haz]ð¾ùÐÛ]§UÊ—4<Øâd "h0’xXÒ ¿¨Ó¾š-÷_“o žM÷ 1GÝÊ-åÒLAÅÞœ°âêµ;gÈíï¶”I[$lÖ{Ÿ)À+0A P‡“¾OЋ{GÙŠSÝ}]¼Šà‚ÚÛÚ¦Vô÷°–7yýIå…Ó£î§ k`_€Ò|}ÆNü-Ff"—¶d9T¢Ëy=ß׬xJÅ£¥<åö7õ– „´ñuf~ÀŸ@1á”ê$žõ°½€øÛ&‹)sƒé³ÖŸ\ð9oZp)¦±IYO0Rü™FÏEy˜ÊŵþyÁ³þ’€€«ŽçóÒÜõç^x«‘€Cê˜4Ç°ŽªD[" ”CôÑßcc8PˆºÏeüœðÚŒ¡±O²¦³üd“\ìÉ÷'—Íàå& ‘§È9ÿe·¨I\R¾œW N”oþ ¿Z2Ù>±£j0$¡ã+èLî»|cøB' ´ð!‰ M†sw> —uD±ðjÛ™R‡"g´ý€ÊÅLÞº³å:©Jÿ,®5½aavUÜ~aÙO»žæ_LcÌê¢T€ ¥ØE”„m©íÚæLd`tåâ{/É.ú„J³‡”F¯?Ö«JZ¯ŒærÉÑÍ>-x¥ô ëú3f”íG\ö ÕÁ¨¢÷ËȤêÝ Û[45½Ú– ÇßYÆi÷µÞSà‘ &&{Ê X32ñ1¸†Ï­¥ ¥“,*½ë£I(Ÿ0FòRE÷¦O³у‚«!6xñ1\Ćäayô2½½G&·œ˜FÜñrà(è´|iUÉ¢³‰Œ«ÖMJy$“ÂÌxŠ”}`ëÅß’Ö%:Ê:ê“P|²¤ðÀ›,dx0¨˜{«`:ÚMSײ¢O!á¶µùó0¯”²qÝ:€¨aÔZÿ󳶇¥XÅþ*½îH410jªÅY€.æB¸—ëIWø{ž©NkÝXEÚˆ…[€#Æá ÉdfÆcºš}—ƒì%*ˆ7‰Íõ©ZlÉ?j”¼·úã fØ~ã„Ï ƒ°²RÇÙ¯†v}@0îgþi1¸’¦ˆð>«’2¬’í½/ÂÉÀ4œ…†P>L=N=LJšL‰Vò}˜ósɘ í8XV *Óµ† `™£Èø¢lÏsõß8” %}A@@þoò¾Ñ"eÆ‹XF­˜Bý÷ÞâÀé¢i|9gFÕ Õé2ø,PuÏß1ë-í¡ Éø¦Ñs‹ãˆ­Ï¿‰þN f_ÒíÈsT Bò\ŸR•–hæwý¢¼ŽðäSxµÉjV˜Ê‰¸ùsõ; «Q‡­­•‡IÅ%£@ŸNìa­ä('§_–¤0diذå¿/¤Òû¨}Yèb¸õ=„Ä¥eD4Q’*±³ÔLkÒô8¼¡ úwONúÆü¯Ó¼JÎhÚíêóBïPk£ÛZêà1L O>ëïÞU4 )pM_ ÿÒÚ~ Ãù~е·d8}ÿ³ 3°ÞÉáà6^o‹é2ãõZrõë¶8ùçŽÑÙV÷ý‘ ¨6¹Ð§"ÒÇßs’ûÖ, |ÒtŸœ¥¶û- FAVËBRi¿­bÃç]KrÙw™èC¦žš\½¦$G4*+/&jš/äÞUú’õ¨î!-­ýŠÜz“¨;ÞÊ Ã¤ŽC·.€±L`2”sñæKíUjíÇÀEWÄÅ:q˜‹y>ªòéTãߦ½=pÄÚà¾R^‚NcýÕõ»ÇèDÔ{,YRНú¯f²Oôã)â!,”9œÀÌ7'äòÇòß±£ì¸:®IKs!ÅH óÀÇþ;ÕhÐýœI“±œ÷=ˆÀ°ñJô_,XhVÔÓ^ l,¶œôB/¡†‡LµÎ³f?ÔC§  ö:¥ `Zb6',qÍ(´ŠÈl¢>¿s LÐ_÷oÇ%lG ]üÛÎ=rúñj Áél YÍ.J„2šåRþH¤CMãÖ©¥+é.òé.èþè6>õä`Žì¦~ÄZË12Ü~ö¡eDów,.ÀÑOá³'ï‹›âƒì½¿(b즛trÚè&cº$šìõ§í[Þ kšg#J:p¼ —íþŒa‡[Y¥…ä aÔØ3íÄ¢\5#_]½wH~‰5Æg"¡‹4¨9 ­÷ÆLfö˜ˆ? Æ’€€ßnAÖ@§ æpêø¾Ãj¦ò=’y4W¼¿?Òà{Ï®½$¦}°6“¯Ÿa¯vÚÂ:Çr¶¬Ý=*õµËl‘"A Ý·I Á)äÃý‹>:PûYñV@Õ2  °Š©f*ÁD2=SYÛ‰0jÛbîpá˜kR¼Ú2Y /Öú˜H†oGÜU {“Ç»¯˜ÇáhOc9)`%ˆ^œe¿è®.Æwc®Ë3Ï1™æYÖ9*ø¯4ÏbUATýaÖï‰$Ží€ÜÖPÀTôˆµëÿ Ük¸(`œ§%ëÚd¡êtTû¹940ПÏìRÞÕ—Ïâ>C~Ôå*aÝ,`S ¢A `^ÓÏÙµ• -wšUUéª"d šTùk4}½lOÇa•å3TÌ™TõiØÊ{gš¼ŒÒÔpëÜÝrߨ›~ÏRb¾`8`êËÍЗ+ z*cT¨hÄÚXÁÌ“dÍäâ4³KªS­£…ÇO%UÔ‡¨vc\ik4k­Úä½¶-29A³‹ ퟸ ›WÕ— x1ñÿ?Râ¼íçïJ˜dþ¦M­÷%ÙjÌw¹KýxBcl)xƒ"Ъ ÷‰ò´`) ¸n„èÌâœÝþ]Z2rg0K¦û\M hXH´á Nöš64?vÓ¨‡¬U‚¹Ê©R!ñüXt¶Þp¾ú°UK¿ÉäÖòÇö1BQhs´ƒùd±³ç®¬ž£á´÷Ä{=1òk»)Es˜ õy`®Z€Åc{|¢4•Cî}j6Šž›$XŠ¢äõ‘ÿœv‰ëÚ¶˜.gþú;Œ/æ(¥„Ï«“4¿ ’~!–aì^ÑDr|Œ¡7~°i}@`?(.úu¤ÃE†q¸mÕ{òï’ù¶†(s(èDg3 _äŠâMeÑs¬|¸÷ö‹o#¼»5®PIeS¡ñç’ýÞM3éù÷ò‡‚e`[ °)X|6!#ÑÍÍíÒ=Æ®l(¿€`×fçÐpG#Œ8Ajvéþ™làOyhﬔ¤í‰ª¡º—ˆZÅF7„òœ¯R‡îÊ Úð%cå{UF± 8›¾ üYËÞj+R§kouGB}jïp.FÔåk~6 Ô‘ ¼Ù<¦Ò¿°¿±{àÅsá¡Ù„``ÿXíþþ,í’€€ùWJجÝGÖØríç[³Ö òµµÊÔKè*ù‚Á˜öïG²—êàÉÊ`ê Ž^ŠX¦¤N!éÅCX*" AüŸç|\¾Jù}9¤µ^Wë î¤ÏÎŽñžûj©qAíËÕ6E»z7OGÃ9û¾þvÄÅ’ö·¸ô¶oÌwÃU0dËi°šºŸÉ‰@kç;À¢mÈÖ_=³2ý¶Z›ÏPõJ„¿^6rFBŠ” °´ £ò‘sGn‰ˆó©[‚²NI£ÍXÆ;TÞçé-¾›™°[†öŽ( •×õÆÔcšd‚¢!;i+¯© IM5¡ÇŸö¶ þ¬>®”g3 DSyeL9¼ fZš÷F¤QVø qu>¨aK“Õt1eúK/ÁRc¯1"Sõd6XfªËæL”þxµ¯È,¦Œ·â$DñXh·|:rÎ4 ʈkáÊ¥P [b[í|Á2ÝNs#K/ûO¡zÿ ¢ß€T*\î´w2öj]tÉ嚈ž}Ë]‡ûÛo;A=Å\N˜¨ª½ßvíϔɿ®uݨf,úW ƒVÞ…§øó‡t)×iÛOE`–ly ¯½|:ÎÄ_þÎgæªp«?±\‹yµ¬ÈssØþ`Û¹P”„ù~Wšªr°Õ„%Nö%àÌW⌠q´K ùÿ€\UK[eøâ»ìø®¡AE»ìUX4hŠDãeJ‡Gs†Z™ãÙbš‰W¾NžðrYumšVÉ«Öí©ë­]™«æGµ¡;¥£ô:Áî5YœW5“dzÛÌk*PìT¥I»Gç|XÜéÔ9žªšZEAtäŽ>5Å»EÙh 9ýF1î•ùÓÚª¢ó#zé|)É¿XA½Ò(ËQ—ÉvɤBÉΤy5 ´4\Ûp|Má« ¡î:®"‚%Ÿ15pê_y+-ñ‚‹Ø;oN†µ¨ºÐ]yLÓ/ÛžÄÔ#Êf`#:tË|Ù›@ˆŸ+>ýÂK„w*éÔ¬Uþ³*¼ÑBÑìg=—Ô%Öb4ÓÖš¶Xøï«ù×T½¤àëêï$Ö}MƒÁ¨Hx4þ<±*T¡÷Ù¿v•Í":,§ŸX–€Ž2oÃn°—ÆîrŒ—sXãÔo(d¿ý vƒ*®4XÚ+/£FU ä(í]…$¯7ñ  E’€€Ò –6åŒ]ó½è×#Shú)%?o!ƈ{É>lÞwù3(™8eÉíWÑñxÙ÷"‚.ò˜))2‰MY[Ñ.%J2;ŽO¶d\Ø}_pm‡ØÏ `ìAí'BÞØR^¥RÕ{*µÝ9É m²eÿFJÚöËsÑäô$ý –Ó²%!ïñ¼O.C±h>)ߟRÄ—ÎZZoñÍÞ@pü#¹…Ó!¹›ÙK·3^”Òóã±Q˜ÍÞv›ëT»€"‡J|À8pæGzo9z9ÿ‡ØÁC£$†øÒ¤÷äÓV&tW¡„t€¾k¼È¸“—׿—ŸºH®ì$7ØX"w7ù}¢ÍcæaûY½òN-‡¨¡X.WDè~‚WJ¾47)ÈËh(ÿQÅœAað¦3gÔº6>ÏcŒ¾[¦éR)`ï?…DÛ\"A*£ü³É ý‡!n—rÔ™Óþ}²w½ÎãþÊAœ¬8N!Îî 4:4]QkœuŠ]žó[â\N¹o5vßr#Ró°dÚb𬴒$Ä¢9|½9š.È6ÕKü\±ä{/ÏW‹µRbLÛÿ#¨™·@×P­¤ë¸Wh++-Œ‚ï£B³¥G 4~PJ•µ¯×á[×.̇pž"u™©î¾/˜-;÷4cb¦îͶY«ý"ÝQÐ×NÑ_êÐq¹²t#íI¬P[~™£ðjuP` x©~Ém‘2Ê]™Ý'H>™G¤×y˜@ó¹áÚ"ůYQUl;S&Ç{HîS§»JÃ0×7¡§,¬ .Ö˜óâê{zš;éB”t“ZHWë•!–þú§AEo(Ñd;H4«Á]êÁµ©óàÒ¬®GëÂÛù¼[~=a™"7$)Ɖ:•’Â=LY+´ò‹TÜÌßšÅS¾©+¸eDÉâŒã~™*žp%Óhªü‡†8žLþ‡cËÙÈ•J|«{5'~ïµ h<(,ûå>㋼[ÊHÙ#Éz8¬9`€†®Òò†j?­ž™ä}…JZeŽŒ(ˆƒ3Ô•ŠBMW1¼¾-ÓE3VynKB“%   )–Ë’€€ž´¢üßýfop´çÀIJþjn! `4ä< Å'^¥-ŸÔ]‰WAÅš!Ö§Þ¡Ðã˜_é9U³Ý[Œ7O:i<Äih~®º ðê¼rÁ áTŽÅ;Ž{-udER`Lò¦ç¤¥Êpí×Ð.™ÄÓÞz쉗Úú´ÎµÉ]IS¿Z4Iyí®™Ò¾÷þš)  LÞ£43Â`h–*6ËWµ¬7„úb>âŠî¦ñ‚£²ô Ú¤>L$u6—…X÷°šugâOáï JeàGèÇNÉÔõžIz´t¸ = ;ŠÑqÔ0Ÿ²6Eæá ÆÑ˺8êÍõØq3WWcÀù¥42·"¸á6òñºÉ8áÉ<’)ʰ˜ »kÁF`žþcb6—'F“*(°»¶ž !¥Ðì¾H $œ¬®´꣊Béìaä«‚ÏÏþÊwSiX#¦ÚiËq“ã-äH¹ §ÅœïyJKÞÚpÑH±Þo˜j*L¢9ÊÊ)’né4‹;6醱­P˜¯Ì«³…6GÛÕ xXlë C“ä#t×ÿyšmÚ¹´™jºÊ Ü¹$õ¯˜xÊ?UrÚË÷#~üèU­/É× }¤HÃëø)/óï§æø¯ÍÐÊ[–RiðQì4¬òͼl”¤ä»ÝßLáÌNË»Cq8‹]íû73§kÏ/+6¦ëlAÍ1Ø7ÁW=Þ«*­!jàßñÜú’°]›œ¸` ×PRŽøÛå4Áê˜òÅS<‘æJ­†´BM¾Œw¼¾$À'”ʬlV†ã¨~ò¦eÁ†ÅÉFñýÔ¨fUvaäÖ³±%ÆÛyÎûoÊlå+6WêO´CŽG7ýjàœ„L·ƒ‹~¿îóD#ø1ÁlK%BSžý~²4ÿPЬOïŽB0t†«Å‘>•Áù%ç6+(,«P×ÁšRï‘®…êêÉú¦rñƵ« >»‘P‘Á·‹Ô=Eü‚Ÿ~ŽÏà‚UH­ÒEVðCî!ª3x»Ÿö‰¶<9\õŽ3h#r·5~*ä³€Ž ðwGMR:è—÷^4›ãÈy¶†¶]ÒEV'÷â(Õ'E‘ql^5ý×⫘²¤ Ó«ùGÚz_–/F”¬ÉGÍ=‹xËò9 5ÿ~Ý¿W` ›ío‚^ñš¡Ù’€€Àf,]™³ÎÚÏâ—”W-Àó7—;ƒ[¿ôSøôx‹ŠÓä•f`«xꌈ_¥¡¨“ÜŠš—I¾ვ橶Ђ›ö2€0FjÌ¥ô/ðÃoã­ "Ì¿0Å¿D‰äÞ‡´å´Ñÿw¶Ÿùk|âQ0Õ”Žu™°ãøŸ†z-«Ÿigk(‘VYÆ\Ú¬èIÓÇñ™CH\‰œVku¿¾kn³ ‡\ØêÄ"šK×JÛšÂíxŒÅïuR;.¿ñʧ'T}´éÙè Ãm‘hàsT°Z胸¦"Í2l[9센‰{)‚( G,Ã]ó"ä´üëTeôÞŒ…ø‹ÕÑ÷ÁÑFÞŽ™ä¾M€ÈÌG4LXí—Üàƒ³íu؆]IÛ°w1;qh‘èÅÎg­iíÖÌ/Ðâs] -°Š:sR¾úü°ËâÍò›ó(k®ó0šÒ »—ûíÒ凱’¢ÏŸŒÊ³€"³w"Ò¸B%å€/8‚¯ß?€”&cÏBù4ÚÜì5›<\.û%Ï僰zƒÚú3ÝÆÔ°¶1Ë¡ ­åòÅ~áä‡ yÒwVÞñJ;É.`ŠÈ¤Ç›Ó>.ë ÊzL&ï5sÓéZÌ ™ÛŽžÀü.(í– N­îŒay=À™Ú¦xÖplØçEZª5â ?®YRCÒ VúibùÒ݆=×T …¬ìeŸx¿tt<+x'Ý]ÙÑu2 bå'l²‚?R0ÑÉÃ_ÕÁe‚à †¼Ç»ª «èÐÂ~[k¯²M)}IÒ5õl™³2d†á°yò_ææ2ÃeêüâÞœ˜ÅŒT­ßwpgžÒ«æNJv6‹a5Ïh¼Õ1y‘ž<Á¤¸ëy˜¼÷Ãá±L?g#;Í£c\<#¹E€Áù¡ã•€goJ«*1.0ëà ìˆ=çLèö{óó¢A½(œõ©§r‹KI xÙ¸=°‡Ü†oèÎyµ»Y+‡·2Ú¥#ìÏÞY×Yed033}Ñ”}ÈžQf¬èúæçDBÊ wÏEåÑõõ›0ãkM™Où’€€Â$é’@® ŸÑN¦³˜ I¤KcÙs¾ yžò*VMåÓ­rÉ]Pzp)ëÔLd[Fas› Ÿ'UžR¥ò¢¸ü{XÜ\eîNpÕ•‡ˆIÔâGÑð5—QóXvNÙ¤¥aô®€TqÔv}N8 H˜.¨Û”˜{¡ù¹o©Ÿ)MLûOac¯©‹×ÃGþAñôîT»Ž8®éQ '(@[n_9Í¡ô{:íTC•6+¡ÚÞá®þà0Óé7ø eŽOBžùqÃYnLøeãbc”M;Ç8Î×Nʽz|Å¿vUĹ¥X%³`WLo(Ä×Í­› 0剔~rÄÐm6°åøl˜¶>š%¹{„оbñÏz“Di[XiENPë®O‚'Ö4`œÒØÿHm_X°uEÃxⵂڋÞ"ÜN9*£Àmþ³s(1P÷ÉK%~– *8 i63ÎÙ­%Pú4kª“r/oÇâû"ÇíÉç3Œèú^¨P׿ß<ØÇÒ+C]¼1ëWBO¥åšbý³KcNó„×,´Cm8»8f±æ†SfÙèêÏU¶¡cúŒjsòÓí–’ç™i –?ÌæIuì&D\B•}O†„²T[C,;gy6F‘ñ{ v@GaVç€pøtj{ ‰ÇÍÑ¢!-Ò~f#œåì®Ø)~ŸCPYàazX’€€¢hÅ'ÌÊ5´eýSu™ÆyP°klq§àoö0zJj:Óp®É€0žÐ¬ á°é©Qý`Ñ+ã*2óƒÝG[Q [ìŽOVf½fê[%ÿRõÄñë|ñä4p¼®:ý² ÿ´r@¬–Ì ŸÐÉ4}‡¹æõ°"ਕ(/ûØØp¶q†”2H‘‘ÜZ×—ûÅꀋÓO4„úÇOQŽÇähSôIþ[åô[ubœî~Â‹æ ²èâð²ÝÒi˜&F}.l ¥žçÖOç”aÀ3ï·ÃNѯò-m€ÑUJÿúñûÊÃL+—>Y¿õ‰à¬©æ½˜=€ðÊiÎ'TÕ‚‘3,J¿æß *„Þ+·Dã(ý7'èU œwožÑ‡„‘?:Þ/P¾Lg#'8« Ê}û06ÉT5wW>ϱÑ' ¥Dm2äå>ÖMƒ,ÒTÐ͘¤fm*y§¶÷Ãþ¬ª“íß&úнnDÒ2( y£1õ8ð˜ÕC…w§6´Íû,3 ‚‡ÈC÷b#Â:«Eðo:¥G&Õ¯OC‘•¯,ÉîçÈôPÁq6EæÀI¾z阨 ùçq`¤§5¶ Þ߇22hH0Ò¬;9<‡ªmSŸ[zv?D>Ji›»ÕÁMzFé.;JçUjFsP:é\VèÁÍ3éšu¤jã«J«ßVtx˜Î-Úmûûÿé:hmô&õß«»ÉÅVÄZûµ‰œ¼´¬ÃbŒæn6A6Ó©.°5ùCîí]­0¢•—UçK²‚ƒçGÍ÷¦V²bõXIH‘Ñåeýi'ÿ޵ö¿ÎˆCþYÒ‰ } FñÄ.…”Û}¶µÄŒŽIǰ)*Õ˜V8=꨺ÅCìe>¡ÁŽÇ,ë=lå£þÃÄòÅv5 RÉ«š\(Ú¼ã©þ¦7±ü×–›Ãkhp¨W^Ö^Œ›?b-úèâ¨Í\ «•~þùJßÚ°Ó«ç»43Œ½d‚BÒÂ×+ #T•±£×¶›÷ÎÖ9J+.5½Óª‡)à\5õœR£ 0¿±TÉ„î±AÎq–µËÞXIdT’€€Åï¹c6õ`RsÈ„˜%søþ¼é.Ù0u?„jLäÖuù;  …y=Û ^ìli†œÔŽ\×Ô\?åuÁæLûȸ®âÀU~Ïkb÷Ÿ•³€ø–oäSØåZ¦<†áð…D¿KÒËÏ\3MHxV[FA™¬æ€²g‚'¹ ·æÉ»ÛÍ`Ü”*p}W%O–‘êsG:ÞõÅÿe<(bØÛ1Ò’‘³ ¢ü瘝ÑBäV3â@#˜ìƽt.¡xŠ#ioÿüpô÷ÌÂn½"ïᡉ@H:&øÏ¿_µ« Žt‘UÃÏãÚâ¿åô¾eMI‹ë­'!n§!V1!OVù þõ]±îx<Àøqó6úuY¡}x£—Ö/Jlr¡/&#NÑ,Òö9=Tél_%&[.zŸ`êÇ/Bjt¯È(á±Ø'C$.ûiV:[^k@¡Ú}T;!ÌûXR|RD¦÷˜ÝöšáÛZ¨’?~åüuÛQ #ã+€¯Âžœ×¢X&V ’*N8ÀÝS…WÓ[8Ð3ö‹Ráù±¶Œfè{÷žÛ!“]qBJþW!e\c3PB¸/ScpöL´PDZ«@†×0¯3|xawßå¯Kà ¥ŽVVR›…x…3+í🂊Bm=…@ÏcôäÊ‰çÆ­ØwBµ1¹6 aš¸¼k=eaUH†mþÆRèÔûð%û™¶éEv–OñwlŸP_oýl>ÇÜuÉHfô]‡º=š|þàøÐ™˜æÛ•ô·›Ÿ-¦ö¶îÝYùdÛTY& †õŽ”W  + ålâËaÞË£ÜÉåú ®R°·X)Úž÷)iX4Y™YŒºI”TŒÎVÚ žƒµç÷‰~¿&“0-LÙžyÉÉÁåzdÔ©ëC<ˆ‘×aU±¯¿Vë ø(ϹYÀhɽJ¯età *ð¯K£ì?É#Éðɶö5G6†;³Ø@ î oe4YîLóK…ÅTÓì=(‚ƒáè*¿&íà@”šN\‹¯z…é÷EŒ§è.òÒ&vÅCŒ1,;ü}††Ëç¼è©ÿÉÛ’F]àZt>Ä×…©åÛqƒ §þv-ÏM$•><½îæÄ>_¬ša ”¨ùGG‘ˆ6 Ö­“"§Ê¾Äé°Ç|dB¹ž¦M–9œ’€€¨"( ,Ò>«¹¯Ù*ò8œ5Žlù!>ªâB!kyîªÇ!ÓÃHqBîˆ-ŠÞ ˆèŽc:ÀÈ'S?ÈOlxco@)v-®Ùó”þrÊûn—|ʈ;úk‡×ÍqP…ýÁ è»äe˜gï¶ÏXÈó³¶©mQâ±pƬ«Ç"øÑÕ?'#~ŠîÈ¿¯ØçØÚ¡¦í6S鈿o¥Ý³Ùž²}þKçŽþÙtQt^üb¬˜©[êä´›skE[XÙ ÜüY­vë8|(îméDúÈÏg—A&euAý34¬dÐj$·pèÐb«¥4“8 ¾ÙUÉÌ5p>¨³ ¼Ñ¹›…âÊt¯fÔ˜8M‘µÔÚY`¶’rNVTig˜ûNwçÓwŠ¡HíïKÇßNÔüÓ—¢2 eÇ24}BË0Ö”„èTHä|Ãp¶þµ%&t‰GŽk«½þW)]L²HÓuéÝàÊ-ŠÀ‹žxÝEßš_»¹«À × 0jWxý}ïP'3á« ïÕ0†f<™ Ç—°[2Î=g)µ‚<ÄßN–,U~%, ;­Í0ù²ÿ(­ÒÉr€€?\`Mš­ÍgD¿%L–u ?°Pº\ÞÔ6Þ· };»>Ž0ËaÞ\1nyõ6ôÿss`gÚvÄkoýâ”Á¯³™¦—ˆ¯ŽoÑ[©|¾6ø>»ýü»¥\ÈÓw·˜ÃÛ¸iò=€ÐwV´håRìï9ø;H× W6ŒÁý·+N£Z<÷—îåõŽ}ÚE ]À2\O!€é§Òwõh’€€§¶G9äÁsÇ'y¸‘¿NÓÊ£¦¨x¾ÊÓŒÀp¥*íhÑ#ÑÿÐ'ÄNÏRªsR«¿ˆÂ­èAž ÇKëI¦wBRS¯$Š–4ÞµÛ½y„ª£3”ñè;Vh*³ÄP?Þ‰FT¡_.£Yø›§Zk0T&£¯”ÛÔ¾4Ngf%Rñ^åvÊê–‡bK|åŠÜù~ÖøÈ›Ë ®Õ_óÂhrÅ×#ŠLë:2$¿T¹(Ç>¶Á¼ÔøKœ1ît•ÿ.¡ß—Ceø%‚jöò­ßß-ñhCŒã¢g*ñÜ]¡DŽÞÎÒüÁI@%•ŸSÄ\±PÞ[ûE’ºDÒûÊMk¿.U8y²[â‹Ð,Åü47ÁáúÂpòFs à`K½¡œ2µ"ïÝ`’(Þ“ë#\µF¦û#Ê4bб”yÇ¥…Öþ7[ƨÿªU›ðÃJøUùJ*ÌÀgÉŽs)Mj§ÙŸ"C«¢Q¡`>+çÒ”ÁõpB¾Ý#œäÙÓ€Ù'Vê> ëÝUÎ6&fG÷ù±Â´?é¤8˜Á±¥xw%v<ÒæÛ¸ç^ru@$ÅÂQFYÈ/Yeì“Ê+ý8N‰jrœ~ îÝ8\+…áàËs /B¯5·[ v½ã7 V®~"X•ÛŽ9…œ•Ú’¦÷¬ïÛgê[k52{SÃnù"1ÙKñB%îôA\RÖ9Ï@¯6˜{"¿e’‡Ñrÿïù=ÖЭÍôç¡&ïÄO¦G(zÐ Ñt?n¹ED„…¤°Ê•ÎϺºÝ‹ÇR¹GV”¶SCÔ_°Ï35g@Ôf…wê[¬+`—sÁÑ´‘…<¿Ý<ÀÓÑ-÷Å–;Šs!|Ã̤6Š)p¦¤€Lh8@<™ó†#ÁUa¿oûšáxË+—†½.BKÏ+€OrS*Em«Ž “rÑ×w|¶aÖ3úU~­ö1™‚™D9S³—ׂd%¢Ÿ6D ~zfþ=/k=çÖó™ìßÒÒÑbHä²*pÝwyXø¯Âõ‚GÑ“\hÇÀ &LZ˜âsà Ëß©adê]SS1rM/s)…Ë‹…¯/óøž²ß^Oÿ}öÄaGi–;ü\ÌAgÞ—ðÁ4ÿÂgµ2Ü¥|tý1¢Öóæ±s\Pm÷iÏÕZ ç×—$/÷ù&’X ™~qÎ¨è› Ì’€€ãÆpæÎ -ðõÂdØ š±±r\vW‹ˆŠqaRFØñ?«Ø™xÿc£´\‚|“–•äÇLÚg²+ÇpG}ãá²$Ív„½ûeËÀkOΔm'sJ¤Óý,MÎìt@BEÅÞæÞ²i_N{rÑöx1÷„i§%Á: ¾¶*})²³?©Èßg’‰}ÁÕ1¬)1+N=Ø×þfÈIn”öÞjô"5tŽ3§2ö™R»Ë ù6ú€×ayÊù»$vîÆÓ4>ˆCð­¾X¼µÝS7sÌ¡¹39ÓRèVÅ!=c¦¿ƒªe\w ÷Úë!ÂÚ±®cqTæ H­ôq¶ñ¤c”pšäûZEG¨ñ sI¸{ûü}Ë@æOdýc ¶{¤cð"Ú1P/ ܼ¦ ¥ÿ=D'>w;Ã%@r©ôÀr‡œÜbÿìpµ6v ó£ì|Ú´Ö*Ö‡Ú2Qª?›ß}ý±à`|f`Œ)ßhìPÀºþ:€7ÖvÓŒEݲŽTˆôUsMÝ"ôÑÂÒX+õhKjo—%Ž(h æ^³ß­¿¥QõPO€¶ó¯6÷Nú“Öq›MæìNË;y3HŽKÚï&\E*â2øž¯-Ô뮘$}»t—Zê-–³æOŠÓUMÒtôà¼êSÖfBøjÑ÷˜NU ù¦¹2`Ø@“å"c¤Ê…¨ßæ4õGWWR©§´•/7æÕš÷ˆÿ3Îf5!ÅóãMYÂ*ô¶.@¤_;÷ù’¥nå­îÇVæê(r¸ÄêÎÁÅÏ §šäJˆçÕæ±É#LRÇ©ôwÝ7ÃÅ}‰•>þC LÁˆ .<Ýc±FZ©¬É‡¦>°dƒz4!jóBZlãj[ÉBQ«ºA $bÿRÙ›ä¹Ó¼JäŹƒ’€€èo`½k³±/sªËÑÖõ«.·ØaL߸Eø“· wrª`ßQ/²—±Fšúò½o²™5æì’ÒÒØCp‹L£€Ü ø†€ÊP=t¾Wã¥jÚ”¶Õ!]^ Õú¶g@áÕÜkþXâ-ú'ûzP©¡lS´Ú=¸ eÉlŸ ¡O/n?©I¢`ßE'é½­‚èù*9,Pêz¿—âƵº:“~ù‘ÅšVUð‘%†û¤ uobFCzEÊÒRçS…Ê%"\ð1+`ÞtÜ,g>{·½+Lú v4ÿ‰ {®Ø±Z›”}HÍ©»&1NY ÆÐWýÈzÚ±õÍãâžZK€±Ò-üfpiW6¯]jèô`Ÿ<¾­)afUFk&±Õ„—ôÐê’Â,! !4Å >aÜíY™®BƒiïÝ ‘€j¨‚ÕÅìú`úD6;%vaöVADþö3¿ÚÅ“@êó":½}/D‚N–8°Å60~ ®eÍÅŽT|žu»×^ðÊ ãõÍ ŒÂ(÷ArnŠ+:JÇåÈÐ)—f^µHç?÷0›¹.2à‘úFi+Éÿ"Û«ºVttˆÃåLÉ?õBœ‰SU—®/«€<†‰\°?ÈRºúg¤ÑŠQœ7ìà$¹u’5ÓL7àö]6³_¹ ^$"&©Úv—û7OÇH,€•¹mr€&{ÎS8ƒÕ AÉ·Æa­`SqhÐ埾Át²I¡¸¾”;”žÙ¶Ðª4}%ó^þ ï3ÀªJ±"M­ Ú_xÄ Ëð‰ß¹ ÈâÛù†‡~K¥ú¯pp¯È‚€¡¹ñ†²(¤ã (#$õkÝäMoí8¤qÓh]·ó ¨¿YC Nf¦ùRK㟾ÓÐÖ{o„&¦Q˜?>óÂN#`õ@ Y¡lî; ±àVN)–7iÔÏ:?fc¦f°™ôÜ€‹ï»Hvàž‡,z.naò’ã¡ÚeŒ§Ä¬¢ä…ÿ©]=äﮫ´G‚ÿ'Ž_îV(­†G–Ï8í®—~MÉí4…ØÎæÿÛ¥ñ»]¹c;¿x*µz“ÉŠ«èõP‰°àt¤qõð¢.Ë©’iÓÉ9¯÷ãÌPa ™á´±éJqAp‚ D €’€€·BèÀ6!/í…4Ê;Í5ç«|(Àÿ¡y‚<ïô}µWÍï ú Ø:,F¼€>¼â‰P>ÞxÅŽO Üu{S€å úFÝÿÑÁjæM\‹Æ,Sè7¯>㎩BK讈¤Ðqì®,×ssëüÃuý.õtZ6uüÇU”fj¥0ÊßÎ!ÖžìøBidÆœ‚¥¹U` ¯¬ÁÏŽ“è‡EÇY·ÆÁW [L æ21S4D^mú< §i+ÔF½Œ·í$î,ñ:!§÷‡Çz´ªŽî–zΠ ¶y‚̾S›Ð ‰±Ý’öhÙS7MBx›Ì¿V‘†]¯PÉ 7Ñ.$ã-§c•gÎÝò|Za—›'/ÇRU Œí9N“¢¹Ý·±Òt5ê¼¾ï:`lWƒU]Ó—·K]µ’ ù‹ÏÝ7AÄWq¾’$oÅ:YÂ}Œ#VÙ¥2Êm¡)Ef½6š]Ÿ¥tŸWÙVñ¾p&¯ ÙKí=é„èJ‡žZ„º’€€Üô5 Ïñ‹5 ÀªUÿMbîÊ8#TÁ›Î7RiÕЊ֋$G¿úøš0†— ë —ädF?mJÑÏÈFK­"¶k Ñ4ƒèÔ¤PŒ‡¨kÀ5‘ªþšSº`fN0?Эÿ/†Þ‹:-1{ö\²³°XEPd<€Â‹:öºÇyFL¶ä¥Žá—­>DÄ)¼^T{éâ ãÆòàH"„~>ëuXœgì"âÚõßæt ó—@2nŃ¿è–CÛ#]é±ÉlŽe(èÌÀ•H5]‰m»·µÎ+CD±¡¸Bû:hz7^„h”裊H¼ªèr¬/$f(½*ýuŵՙ™Ö$`–ö£?¬ù¦`j$Fgn¡_Q]©FÂopO Äy›êÿÒ¶QÎÛ IÓãHËVýÎ]Qïp¬‘=ë2ßÚŽr~}BYËArým}Ö ÀÅKEHi[jš£øì¼æ…ê´¯Þür‚ŒÛŒ´›ågÝS‹n¦ÏAGcÏ5Ó|Rh/fнhñ"5Ô¹S­´bl û'¹î·[Æp¾'\41+”Sû1~_züÛÇÄ–9VÉZ¡ÛN¬.U©†ü°®™‹ËflÖLÝ"5F&z¤ /Ýiè$È⸠·î¼n#ˆMjάç%fB$þâ5æ<"¹¿K²Y—‚„:›Tþ­"úNYÉ@†qÎÒwp¯5ZÇ ¯Ôr<^lÈàMªÕDìh™±bª’¡_>}2"@ð“h“ZÐr—–ôóÎ"ƒùµËx{ ‘oÊ.î™v”6]2—É»Fª;^=Ë$Z,(Þõâl†õ¡LŠw®ãÒY@Þ°ÖØ ÓÞÞ$¼@a›‹±³ü6G?iâ/ð6”¶¥š3°h|_—Üù¶iAo’€€·ÖÑ«2l‰sŽ›ó€öÂò¯‘(â3@¹|"VÇC¾]ì‰è`š°Edøÿò±]{—£é_^Sæ8òØò¸Éb=„áþHJ|[†Lö@?ášÐ#󺳉XÌ=`;FF¹µõ þ(Û«w¦¤§SµhÃ-Á¹³eõMǶÌ+~`p«n¡=À¿cùöÒ1 $•<K{ܾc‰ŒáôjËÃè<â]Ÿâ½á9õüÛ GK{Ün*Ô81ïÍNg7^œnßZ–å]ó“‚hk$Ò«ˆa»ðÿoèlÊQŠx>ð%Э•ŽÕ7I$gy¤c;øíë8¾ñ'DÓÔí*¾×*G!â½Áœ×cÝlŸÍ^-+RÆ™I5žï˜ž¾ ·0Ë;«©!>}ƒÔ=%”ÉmÀ¹Ó¸:u•¸ ™ ÃWó5§:žê—ú3}Ð#A³‚+ F7ÞÇ–ÃAoPk¦\þ'Qcwó Ûr-Ζt:Ьyâx®£eOÆ礪ïõ»tæBÉͽ,®tgéö8–®à¨z ÊâèÆRþɇ´”„±éPêk³iŒ–7ãîÌu}æ·kΡ‚uÎü”|ôÊF;®³p»»Ñ·‹ú˜qïÀÉ4¦ ¥’¸Â"LËIí2ôÃ2û¡j¡1 T3ãÈ>éÇé:óºÒñ[É(–TQD`’ü÷£š¨GTD7£–›[“‡|®ÆLûfÚÐkÃI£Ñµ%"ÓÁí°8˜/:vùf2©©Ùš•îG€ °’Ëõqš/ßñ6 -XïCê7µé™r¨ÿÇÔ€ídèÆi ßçŸh^Á·a*˜nË¥=F–Í ò‹? ñÜl¬0v0Gï‘ûÂÊb æ™lä§wwænMÉœ–Ô<]Zñ%\œå(r’s²82ÅD½¡ƒxÙÏñÙlò•AÞ6£]›Dq ›¦/4éIÓ QQ]øð‡Z¹ûXYê!²šn½bhåyîðœÐ±eŒe'0Á¼“ŽgëJ‡_¯ úà<9a®¯tA“H$ÅÞAÑ=v²“Ý~e3Â@>½?ïôwsÍŽþ³–¼éËÀ²"‚õª)w&"~7Cñ4.áSB\c(ù—,èGäpšÍ欖ֳÕù%bÞÊv’€€¢G_%DS H¹¡ìÔ˜&P‰.ñÈ«’óЀªJl¡spyNÓÚ|…z _ËÄÙŸX¶ìztêWÐÇÚ­þÂíxûÈ™Pz†*#ž!Êô3Ô"3¿Qx€;¢®àè¤ñ%¼èþ°Ä µ hl9.n,þîé7µ¬#­ù™¬}Såmà–¦(ÏÚeR`”S>ŠG7Û`•Ó¯û'Çœ/8F¾Z‹©ÀÓ×£ZMC?Îäý›‹‰ì çÝ|¼ÞsÇïöE*¤R"`ÊÆÔNbþ\›%ß@õ¤9‰[Q1 Œ³úM R€Xf_sÅpXPW`r'—ÉI³ã aÿÑÞ½Øââ6¦Sšßäþºµ¶ 0á³›A…^YÍ+¢E7ØìÿÀÝŒ %D×·ÑÆz ØëV«¯n©{;Î>‚"Û°j¯iX6Ò Ô6˜¸ÜpM5€ß¥Ífšý#f3”²vœÍn¸>¸ƒ¯ðµ} 6Ñ>kÈÃlè1Vù•aÝkN|ˆ(mc À†Ï´n‘ó>‹'#+{ÇÔ…‘*%lÓ<÷“níðluGj—ÎÚË\i³ï7–RÓŽ •ÞG@RÌÏWóI¹à [²ÖÝy ϽىB•u{*iæíÂUà’>ÚégÿV†+qbÄÙkK:l ‘Ð3kÚ¡Ðm#§µw…ßûgj‚c¡ ë¥ñb ÐvCɹÛ{›Ée¨ UóÎMbÕj\ÀfJ|Ý!«žÇ¬þ;¸ð°®ôOæÊ»°rZ¤Kƒ¦¯ÏBw}q„øy­Èx4ÉÛ»ÈlìæàXØÅ!ü×1´–ÃñHšÚ§ Ì¿ÍJÖFâ°aǶá¢ùŠÙÂæ©Ça$x@%V¨êÃEºEÝ®Ðf X§q'¦^П (¾Œ«ÔÅ[Ü=à45ÝB»SR.M¢þ9owLèð vö¹Ÿˆž‚ìë£ ÑA—ôȦ5)Ù™Ç #·úsË3ÝW êñHÃÏ(^Ö}°@i0o= ÇÌ ç 2‘(Šågœšã3%•ñ@´±Õúé í{dêÝ·ÉŸóH¢Ï ªý™›ŒÖaé»Ì‹o”q!ýñûWóÿð aXù)̪‘3dèta„æÐ*S¡€=èú/>àýqÂyÕêõ_AFÚªáaéI `g÷¸¸òú›’€€žõ³27w›‹£³”o£4""p¿¥wdYç=Ôê’ÄwÜ.ˆ(/îQ:i§õÌLü÷A#üeÉ +æL¢(‘díü²ÄœåÔl0ÔÒúÓ¨xáÁ*ÊGj¸ ªÙ‹Ì\qœ¾t€¾fÍ3Nrf¤®SÐÅk ô9áÞš¬¸é}½êÞ¢GG¼°4î[dIî[˜CöÇIî%ò—Ì^·<™;ˆCÃMÚ*]aG©i=D©2èw¦‰ÕŸ€F•y @Y8¥ÕðÔcA÷/ÕÌÐ!f”­‰\µØÏ0Þ [6‹f gÄ}¦9žÓJß;‚Ë´üŒbs*!ª à=ètšUï¾ÔU©+ø•ÙjÜRÄœZ“¥°dfÿ´½ŒåÅôb¨—R°ùì(“ ÒœN‡S”2ȨøÄ@A ’¬$.±ð[w kö ©"Óúßà›Äæ0QUÿÔ‡OÂí(EñXÊÆŒ:Õú¢Ä¤š6ó„—§«Ò¦i¼%žJƒ. 8ž$KÁwc‰ V’»µ(Y?廑¿¹e‹ hsS‹4ïÝs…ßWýD2<).¹×mðÊ$_™k}Hýºx=IúûÔ”.óG·9c'$-šG$¾ÑÝtz163ÄÝ ±ýgV{²²KŸÿN,ŒúËš: ¥;7AË]¨à®)R#®ðx«òÖ©?å^2À»¿õ‡‰P»vœU>Èݤ¡KK{×ÇŠßRAúµà#}Aü3R¾¼ø÷ÈZ®y$ÙžE–ÑDYÓ«¿±0‰aaE%RÎÒß-¦ÖY¿ŸŠ1÷„ÝêÃÉ»n˜ŠÁ¶@(þYÐmÈØ4u³*7Nv hú+Má/»Ï³¬]’Bi»x8†¯5`,Püç<ñ=L2ÛA@©>¦Ÿ•Íóˆ?töFŠC¯Þù”δý†EÔÍíU|èd0—…\æx¯_E³gvf£ÌHîÇ› y@+rdýÌ ´(ÏÊ, ]|!uMëç5æ3/òí%Ìd¡ÜtÚ?ypz k¯[.š'ˆiLï´ñ†ò ë°*lJóÜm¦û×ïè›ÍRÞÝë©p3Ž=]šö™¶áïY´8¹«ÔÖ¿1~ÈÍÖG¾ÐpSB}7âC‘]¤92 IÃL(FYf‚4%Ù’€€Å¡ÉÏbá®÷àciZÊóPG­•Ç´ ÿ•›LNU0· ñTjÈl$Äû"ÖÌ‚õ†öe+3õ‚ˆÎ•÷¸ÜMéȳRQ{¥_Vp '®4èháü©sÚ·„® ½3<Þç·½›ñmR1 uO4¨Éu©R4bt‡5fȯ·§HÅeóydøhßOòþ®¤Ýo« RzNI~¨„nÔdj‰(kœÿ¤K<Ã4º9Eºp¶òF}êöÀt°¶Û:—$Ób`³aY2µcOêU) €ÎƒÙ›Eã%8L©¾`8^à §\È2‰ lr¨Ù5×ûÔ„r'¡X"Ö¾qE†ÂlaJRƒ¡„qR«±hOSô´Ïí+hÏ^úŠEšn Ñü•òŒÆÿKÈå¼¼B»\hñCí(L“"Yrâq.—!¾žqÌ=cJì©ÄËi8oÈNá…Ír6ö…æ´HÕÛŒ'ç¬ÝIýÄïn_?¬zr²¾yVqÙ°yÕãУÛÙëüÚÑv’¤,Aá L)V̉´&»s3mÇ­yYð¾«Óˆf’ÝïdÙC…MÉszÖ?‘c?1ïÜ^@’º+…‘â¢MHÑá3íØF×q𮤄)‡ ܘÐðºèK÷Ãòå.Æ2B—ú®÷~e[Ϙ³¹¬ÑÈÈËøc/|×à\àx‚جe¼Ä3,i\-Š2š¾E³]ÙýUYe«P7Nœ~ú]É*7Ù®æwÁ4¡¨­Óñß<ã¬GOãw_W-æöŽ… Ú±»:ûçƒ_èQñ(Â#+&ªTú‘Ç@‚椺7*%M4,4\ñ…fä–ÉëesþïÿNÁ²ˆèb'c:ÔÖí ·o*ëº{Î4_ñˆÃŽ0¤¯1WÂýýKÁP«Gš5hw:”òû/Po^ Ê;<ÞÓ™¢Þ»T.ú¼T¶©’ËÝМ ‡°5ú†œf,œIä¿ %œ þ9¤î3;ÊMuHRéB‡ü´q†¦ö+!ao:d{ :ã·³ÓËr!ýQvËÌ—´uƒ ašlu|ªbÚÂ^b’")5ÊãÀ/ëÅ6íÿݦÍà6’€€¿i«ìëŽ%í1PÅ|š×*êep®î»†€Û›*ev=j¶°¥-¯OumÇ‹¯bxæÓÔÛEé¹”kªàUUoK{S-©YÜÔü‡Ì˜¾¹÷ÛÇù®Z§í#†|/¹G¢ÄÖµ—IZÛëF j¥î,%C—Xz 99’¥k=}ÅÙ?]øßͽļ:óTFC.Ê…ò}oÉà _Ã\Gõ˜Óã;UˆÓ8¿­Í¹3H2Àªé˜~t&ìGçÃ.-Á6¡~eTD¿ý|ò7Ä;,STq~¦Ž9‘ácîÚ¤2ð¢wû®õ~4.¡Ó“õ‹x{†<‘¥n$áÿÁ5,¾À•x¡"O%ü/éh&¸^øÙþÞ®1A—÷dgD{n2[àb-º_Gš¿Òd9Ûú+àN©E§è€ò˜gŽ{{ ¹E)%çÚ“k ÀÍïÌC1 Ãùˆ`䈮Ž‹DšZ úIõRNxñzü*uÚbsÃ1+þJæ þaýâ¢ÿ1"A"´ñ¥'XGx°`ª¦å[*F¢R¹gàhL¨*á‰U™$WÂãoB¸œMwxn fäËâs«€ÒñåôCaÒJ“egØÜª àT˜ é[ Q|N²}N;üÑñý 25N£Ü=€/ް=gvµÅgêfëöCoHï à ò”åùŒ¦¢ïå*°~ÑÍRå”ѳ,гLj©ÓŠ’ʆ„5C 9~sQ5¨ “* N6Û<¡©8観µ)+ñ«ádÕY¿+¿Íù4F‡H% ŸÐI-kŠOÜþÄÁ]6Úo`D©ÀÅô¶/ä6+CÁö©ÛŽ´r[Ú±FvšÅ••öÝáF¹0™µh¢géþöÝã‹€ŠîP¬guÈ‚ ÿLâdþQ ùƃEÊ¥áK »†#¡TF‰+æ ÝȘV§9éLà¦yû~:7éTUsÚyMH¬•”QÅ\w=nu­FE6Eœ:ÔÁüD楉 1)†%ªd–\Ù5ÀwuÅ53]O”Á ®^T®‰Œ¿t°|pÁ ž‘ÒU}¤ÿ[¤{K{Ëm†w¿VÞ"ÛÆÌ?G4ÔÓ²UШyD:B¤Æ” rÙ”s—¥÷Ý€4ðÑR™%}Ñ6ît§ï‡"n½buP!‹‹ó,xq0Z° ¸ÝÀÂ@ݶ’€€¬î 1ÁUݾ¼d¦/šß¨'Á•ö©†³7? ˜„_mŠŒAÁ»-ä¸ÁÚÙ\H >w¥‡¦Nµ¬94!-Ö­‘ŽO²´ÎõkÏT¹@žåÝ›Í ° ö¿P¾çþ2 ÃýV;Th:÷•¤þ™S›šœ þFQ¹×==ý}-qKº²ír&‰òhó8'¢K¡tŸÆçœ/±¢,Ÿsf‹GôXéOÍVÅ—ÿ3`¶MKU¯ZÙ脼VX^ÍÇœ—>ª Ú"£WšrCin¿aU¢›ÿs“I7Ýö^ÖÅí¥Ežìk”§î‘õŒ;Cþ0Éo÷§ûWÅéÍ„í I!ÈÕjo@ô´íA<ã|œæG’Ö¸hWw"–†úý&Õ8qÝÑ ‚ÒÚòhQü™z†$u¾li ÙúKç`vìb~]ÑìÐühæM÷Íê‘QFøÄñÀd“-’h,(оä ý™ôªr=ZŸ¬ªVÂXÆŽoH¥³g:8ÿä`£L\EÈl²€,Æ[ ÑMœö5de¬õ×`*LÇ9Ò;1î_ŒõCçT ‰´ÚsL-¬ÒþFÓ^ÈÔ#lS?0OüAøœ1­Ü~'Œy3{%B9€£35<Åv_뚆t} @ž³­@qÏ™qüQãʱ¶S šZÑ<$œÕ«‰\+O"J9,zw“G÷>Èì¶a[ ë)^7YÓÛ›ÙÇ݉$=Ƙo²=ã'L++ëB—âLÐlI¨ M?m—¬ß§:ëþ¼˜‚N'¹D)ˆ~L['ƒßYý`}6FfB '¤•qˆîH¥—[1ÂX& t>¿Ü¥.gêÉYL¹±‚¬ÕÑV¬õîíç1´É ¸²>sL ·W€žæiÒ]ùäðïh #oÀêQWBCJ©JqÛè¬<•ìõ[!´§äWx×tûAš¬êò9û[Ɉÿ¡¢5«®Þî»w™¿ëø™ð%¥(5ÙU5ñüg—Ké†0-^¨©«Ë‰Â H¨¯¦`´œá+çÿŽêÍÀ$%8‹æâÁY6аRêºe+°Ö¨<ÌuµÅÎH†Z½²Wô .·¶ÀÿæÙLé¯ýöÐCBæ»d¢ÿîÉ+™6±¯Ô„kñLŸw¥Œ°&=’’€€Ò%÷¨ßeK¹iIý£~µsJOž9žÃ­¢ÔõÛÈÉò, #ÑÆ ˆ‹¬ÙMÏ;ñÿ[Èè«ø‘ÊO âa’ÄÔ¢\ n­nôk™-8¨Þ4HrC«{—Û;÷Ÿ9eƒ*qÎþ3çpÄ$¦½$äàTÛWáÁ¿^ÿ L V4ióà—nl5"{õ1%êœÑRU}FÂÚã`Ù\˜Û€¾¼—÷!|†î•Õeæ•꓃ÏÈ×,:õ›ÆG¡2úb¥ŸAÆú_<:õ­±—ÝÛlåâÊËã·= '?pÓ]Û²Íð*ôRk—_©Áu7#Ò­o3˜Bž(0¾Õ˜u,ù/A¼÷™«*eš q®ŠqS£w~Ù‡”uØ#5 Bı{5|•eðŸ|A1I—fvAè݉ȪQ©øýоïñÙŸ=вk}9òUgӼϺp/éø:úZt¹ej2óÅt¯_s/GäMí2®ÑÎOÑž·J;»©–Ž|è*µyºð<à÷­ù~Ou^Ÿ™Œnè‘Ð ›n¼ò±(øÉ„Z¼)*ù$¶ä#ùØv8‰4¾ñìPÜÿ3é=ÇRƒº¢xïÿŬZ™ä h4§'4(HœQÔªpH~oÈéD¥Í;õý´€iè܆'9ø„oë‰þöáÁ)Šûâ!†øE š8Ô‚]+I¤ž¦{YÎÖý¿ïÑð‡Òêë?/B3£­_läÈÑy`[å»iÙN/‚@DöÊ%#ãJv•@ìóö°WǨÅbˆd4YÝÜ–N£ÿQj“mÑqþkmÿ3Q¾þЙ/fX°pG’€€Äð õ–KZk¨¶³Ùƒ5©ð«ü&ºÍwóau)ë›ðYÊÉõCn2¢åUæ> [±û}«Ö¼-õ?Pªµ=ÊóhZ¬¶vÆzKBüT7\ë!¬šËl«~#ýÈâ(5âvrŒy²Lžp´‡’–o/™¡Uvï•Ôì$§Ož‰ mFCáÍõP€J€¯ GV†k>oØÎÿzÈ×WÏŠD£„n)ßoï»ñ÷„‘˜ÃÅU³¸MN4x§Ü²NfR·m Š$È·\ÉÕép>)S;ÇÞquul/a”{CçTÇ$FºSRØ›Dó ÎØê)S¥¢;cóc‡÷}¼.°¯*ÈÚsÙ}åî¬ý Ê]ðÜCoáÆï½Ì¢ŠueB¹+ÜÉëzçK˜}rŸéΨ¥m\C® kÒ£ bpé1UëPGW êÚ@27ÝÈô´Ý€ê¡F[\]òÈNkÎÚp^yHŠÁµùšH¦5:âT{Wôäz/™Ö¤7ÚßÝL«d‘Š>C=W6žñw|áèÿprI2!WxŠˆå«’àlA0øëÞ—Åvþ%†«OV怅81ÔÈOýòÀ ²í›þsb¦¡¯ÆÒñäý ªÕføwf«†r3­Ä°:ÄzFãUyÆ®Åu²l® êC$š†rà?¾ÓåCVoûJG,~íÏö%”+¶û‚í‡óí ÞQð3â˜|e8Eï‚Æ©VA¢X…ª§ªS­-¬V`7H’;ØŽ’ÚùT ¤ƒæ¨×5S ß‘“è&Š3úFóœ<Žlêóh5làƒÐC†ã¶åo->+踘EÖ8J5LsêͲœúÍ?¬\¥Øf6-ÆÛÑ#qÝè}[*;ߪ %):ÐF âE6¡ ãW^ótB~H1-¸º+ä–UŒ/¹ü^þæëg1ÈAÑ8'Ö$/káÎÓ¼œØ’N¦—>ß„ ƒã­%ŽLßvÓûâÄñáCjøt7¨ü°ðP¾äyð‰1mÜÖÃõl\JOݧ3Jªõ¶½^-J?Ø®£c³(D8K%¹4 yD¶_îs*ª²Ì-Çï?/ë¿ê6=‡ â‹&·q^tEɓҮ UÙVš{‹šíùpWkKj<‘0Ü09!l°ùœ÷Yvo*œ›ŽIn2&ñUÎý~išXÄoŸó#ª3~rÓ˜´<êqŒ~;RýáõÔ}œäœ„—½xþ?ª”[Àáŵ°ýµþÔÍÀüõÒKÌ*†œˆ¼!?7üy‹³Ç2nñȉŒ ¼¼ÖäÌ{׆k×yjÉ8ÉÒ'’iÇ~ÞB}X}±bŸ,´`*B²]§N9ÉŽ÷ám‚RÌP<­+€—-‚¨O“”à“fé¼"°°®,=¥ÁY@àÙlÔ÷oÓO5:¨SßãP…ÛÞðVÒ5š»TÂÊG½A} #D¼òý;¸lˇlfÞP´£e˦%ŒZ —su@:@ýˆtùW¹ÿ ó‰6œåloÅcÇÔ¯’ A*¡9¨¬€n`ƒ0Þÿ†—ø`o¶¬úÁ5¡3CmfÄyt«h;¡'/ȯê–2JA*ÅÃÕ»¼!Áž`‚ÞŠ~H¥V³xù°°ŒD>}z¶_õ©ÑHd_ ¾©ÄÂw yÖ"ü7¶'†:wó’pó+í»”â¥ýÖ…–&KCj» ÕXƒ¤èʲ¡‡8qgÇáVS„Û÷訟ûbxÑd9•loÇÂÖˆ\¦ã†â#Õ,k„ßgçv,J¢®8FÙ|¡c*ÿ§SÞ»Q—y~zø,Ö^D÷Ê‘Šv¬ðK}SÒ¬ºé£Ú)M¼m‰ã†ùüÄ-¨r¢-x8â t™˜'/ôÃÆ¡ÇÁ0‹öæBe¦ÝñB^©¸NP€ Z³_{4ƒ£Ï(ÚÄáuPùç`LÔÜ(±ÐB¦œUþþàä¥ÇÝ ¯Ôgz¬}|Ý . AÐ(Û{Ú´›s[‰%ÆH}òÇ%ìÇFø<ÿxF“7èq¯l›oœøtÉUg&T7­2YÏ›m‚ PµÇL;BçYޯܲŠk–¡ë"Ðí*¯1Á·éÊËäíÉ´T#jÞµ¶q¬ú¼Lô¢¸9ôOE£ƒ\"™â ¨®"ìb‚w³fÂJ“hq‹±ÈùäÉò Îàz›<}îÜ ³òf‚×Û«ºó€’€€§ïÖŒ ÿ§Ö}Ò…2Ͷ‰‚C’g?7v,#Uˆva0ª½¸ÕœÅö(Æ«JÅ®ªMLÌDåÌA™bB¡àâq^ &3¬7®¿*rè—¨gÏp^)e˜o9|K¿Ô´‘`–¡ì„ì)*Îáâþ¼¢¯C alÐŨʧ²F5á×®~©!õ¼ˆÖûjG;™+Û‰x^ó é½k©täIîÙ¾€‡"SÆä0ÊÌë j Öß{”>{‚1"ï€L^eLï L(pHšYu®~˜Z3F€‡_§±u)GžN„-÷5+¥\4 Ö[¿‚¼I.ŠZ›û" ’d*‹žõ½“ß+‚&÷k˜íø .Ǧ·$.:Ó¿ýøÔˆËµ—|»GÛ‚gdߋֲ^sæ&_’ƒÃþ…9‚æÕPþ9]dÜ«KÞLÙ£—QgcŽnõvoÜñïaù¬µˆúÊÚqZ(4ðÿQÊ®¨3bã#$b©ð6o4xvb£€»ÿ£IÑnºˆuž_8š&Ò~´û”¡×ÇN±ÎâÞÎððrGãOA¶–‰46ÒþuinÍ{ºŸ®Ä)´U©×)}%!ªðHü‡.úµŽm^¸@f\2cU*MëÄ;2Zk¬ýËiž¬êŽˆÏ„=õ2ÏÂ$ÊöëúžâT‘¾S\ä¢n|?б}Dïk*Ž‹x‹PWWÇ=•YÔËjõ¾ªðgCEš€¼†Àú?e¢ %ÇD)tOú4?r ãQ6BøÁÓ80ù éä.< Æ-ñÚ„IÛ€h Œ0ôË,+ø+JB÷ ®v£·2›öÿ¯3[wnŸ”ÚaÉÝÓ*è[Z^eþÜ(8Ÿ\îR¼õ>¡~{#Må)’íó;[BCȱ輄/¹ûû›8 <Ô o:ÞIÉ¡ÅþGî–úeùÌD‚Çk ut®ˆ¬V§í5;4&€[I'À$æ¶ÄÖ Þ€´\†t2õiþ€gsù×€µEénV[PÀQRC䥨³"D2˜5Fƒ’ØöUx#—’€€¶²5s‚cå³qi’÷Q^.ÿ£§ ±7´Õi( ŽÄÔ| °3)‡Ž¹ü¸*«f;¯Ü†«á^L,·ÇHågrÜí·¹ë²>Œ³õU·€0Ù"mçøk-t«ðôrÓïƒúºïµ´Ã‰õÍ©“£¡(ïwÌ•M~ãÊOµ.ô…;UU¨$O%ŽÏdyð¾šåêf7|@ø€R¤nž·W§@;ÙÚsÙmæoþ Y×)†|‘›Þ2%'z¨±Q^ÚÆpp)!,éòü×`±5uÇ A*‹T:3c蚢Ž!\4 ·©pM¼“‹“þˆ€‡[ Js ì…zýÈódÄfƒæÝ|æÃ£ù  9dJ¨¸hþÓ ?Áö£_o=µ¬#§@rEßq7VQnþ¿ G ¶Þòº‚ÈOÆìšÎ 0en‚oлþ‡ÔV`pYàýc¾:ÿ'ê[°d’Kϱ˜Ïè5”ްVÍ@÷®U"} ±b¬³—.…—¨dìS}=uqOåæï^ÄU!Q_g?Iîï+u²O i= îfÀB0_D¿Ã»k1æÊÀ‰Õ7Dû-,4ÏzÝPÀAâÒ+Ù þ"sÏ4œ¨ïÔï7Á}¹GŸí¢þ‡µx`pS=1j“omè†4©ì4àe‰­°é ¨~õŒûèã]MÂâD+¹·Å–7÷$˜EÚ—ÉÀ™Y ½¸b+~ ‚ÔÛm‰‚±¯•û"ö¦öÑË&ÙënÔº”Zø4²O›ÍÍ‚q¸J³õÑkJ¡ë¦3¯å8m¬]Øi ßC—•q*lÁYí;—DGÒ+xˆ‚V ÆkëÌ‹J°d´cÏÏóZ:9^ºÓ¯Ù(}=ç60Ö1'Í»5ƒoôb".q«‹;ðxtµ“`P^ªŒKÚ„P¬`o½© 36ª¦¬bÏ:TÃÁa#­ZïåyH˜cÅ4]òq£5—X–xg½©õÄ󢌫CÎky"‘:AË:1/ÙúõÉ­Ç ?.5AåÚ|fi kݶÔç.eæÔ¼•?éÙDŠñSN~ãqr³ƒ8Èq û­Ð>5½Îæ(>•s‡½h£G3G¡Š½Vdˆ1'•“ÿ­‡Á®î0YAcßÝ;íÂÍ8tEf=v¼Ì’€€´s{NÇðÕóÍ`âF»µ5aoªŒ•†Œ.À‚Èn@Í¢ìçkfph¤ç&¿Åë¼gc ~ºtþcÄÞ×dèDx )sëJNbIö¯r0µ ¼Ä‰¬èLrñR,k&…ÁÈ~:TÈÍ™KqÄž|®y@+ýŸýȶ\£ ´&r{_vûÀ³j¥ª}‰Ÿ§e‘щøz<»šø£uyŒ.hH¥‡r®ñnEa¶ÕÐÜMCsù±¶k œ"bò¨M%¹‘‡áaòT$B±µe\N¾„âÒh[±ÒçŠ ÓjõrcXA;3ƒÏVXXîjdºCâ"M;¡ Ÿ™æE£Pc­¥ÄU:•|ªÔS`èé\ÃB*z©·|÷kï1q¨œZÿ¬–ÎËÏEkl©¬ÐÄ“: N³ZcÊØSWtùø –2Ü´æ?çæ›|`™Ð+‰0˜ ¢<¯NÌò¹bÑ”\ÍÙªu@Ÿ ìà Æì®Ì!Ò¿7±q؇ ™[0ÈfŽË § oÙ–~Êø7&Óµ–i"8gá§~“ÛÔišHr Ì.“çpýшp¡—=¡öħ°ï²£ gµ‚rßs *óÎEsI¦úHˆd–ƒYvs‹Eß²N“ÅSÖÅ/÷rï*º/h—ê‚ ) g£HÛÙ©9CŽutY:#Å`°5öNXà&³lDナҔ>Çàõ…aUÞÝsøÑIHÔ­ÖT4xR€BHF}f¥–ÐË>¿Ì"ÚV¬7,ÿrwÞ2‰bPêÊ÷„h…üÀùdO Ń“ŽßšÊåXjk©ÓŸ!Äýp5s(1 ×|miÓ0Ä|t[<£TbÉŽŠÜt;ô·¬iõÝ,Â.„2€!»õÍ»ž ·Y³¾}µ¼5GÞ·Íõë"KvÐÊô¥ ÒÒçyk„¨Ø£-èɺ¶›±x3în)&Íô¼bs´Üêää3Fï“P–0$ŒÌkÚ›À¿Ø–Q𠯤Œ>OÓºÚä6èÉ4Üÿl*W£êŠIŽ?÷YØ¢>UÁРÓð™ÊY~*Ásš~ë+Zê|7œ`˜±° köæ¾2’’p&CEf׈úD$ûé±/žƒ…(£Ê›p„§}Tþk7kU‹›™F’€€ž¼üôÔ4ò¹{6ùA{ÓÖA¤_Úð¤ðõghZÞªš5Þê’™„'ÃãRÐ@6¢¯EŒÑÇI)Ñ*Û'o±ðõÖV³Cø¢Zúд79RNк]ë¯2!èɬ,ü-Áæ@cjªÁ9̑ҫ.ª+qzô v¡«‡AÅZ*Ý“®ä}'5¼ks}¸»…åÀŽjú}࿜¼X1ÔuFF,”Â’›D€õ07…@ #¨û ízZ‡²µŒLã›e/ÛñÄ×…TàÎjE+U£Þs¹ÍGx´Ä€|+U-V£±¡Í6£Í÷/" P)Êp±Åç†æí‘æ!æo¡g´Ê3ÉùsË7éxݶI”$„*ç¼8TÚ_ðß_¥2g\ÔpB³Ù¬uSðÙ¡'ºŽ‹œ®Ê³}Û‘NqR¥ñ´}‚Ý5¼hMÿx ÛMgw Vòv2ޏûAÝØš›1k A ­}­Œ,°¯“ÑwMç>H´–(øôÌq+ùG5çÙpúcÞ—bæ ýãÐ[~§ m·®×ö˜>ôˆ…î‡ø.÷UÚÊãcyç×|MàÀV1ó`úK®ã~ÖFŽBŠ˜ä–^„öy4D¢pú¬I¾0b¬‡ª˜´r âW»€.A6£sñšvÌïƒnGèúÐIbŠAeÝéè…H¡pº«€jZk"ê_&@ÒdP¨pà„Uö>wíØ¼WõzʶtØšokIÌ7‡ó $õÉdy-u `M”%¦ ýþ?S cPkµx~pÍÇŒ³údn˜¦ÛÙ”@8 ¢Í-Ò˜ýÍÝcòºüÐ:ê[M!Ã륓0¾ÞK(”_«À§ëETìjÿ›°Z¿ÐUË•+Éé˜$Q”*bOÅ3æ(—×L˜ôœÐ†ÍøZŸù_jê™'ÓZû²\Ò0yàoŽ’¦-Q÷j¬Éà ¹EÙk?fË» Mã4ÚDKcñå‚ãnKÊ ‹)-Œ#î¯Hˆ &…þL†ÐEGÊ”r¡:²¸;¦sgUŽ|"þµ*°ý¥ØÑé€Ç>–CàHз§/–„ÃU××_Û îŒ œ,[í 31A¶’8•ÉÐp+~¯‹ ™FÞÔmAAä5'º« håMÃP/‰ß~5æ@!0¯£Øådâ“’€€¡èzŲg¿]W¡ì+µrÀH-»Ê·4#ÑPÏÃlð‚ZïAV˜BïÅà\Í”VGA&¶Mïzz¯Þõ zT=¿(úƒ¹-ÎÑfh-ïÙ'õ¤CQú{íý ÷úå‰ÛZ+ ƒTwF¤§Èš™MŽÔF®¨1É]|!gE¡Ð›]sQnV¦/8æ<½ñŠsî ½8Ô”9äåÿ¤»(4Dná=»$žd~O ?.¦€¾Ê9ˆA4`Vžÿݸkýð >ÕÓÈû¾êk^Ãç?/þ{ ,Øm¼<®9²QÎáÁ¤IÛ9à­æ†QpC;ÔÁÇ®/Ú¯ÔxƒÁ¹DÆé2~‚4%Û3÷êž´`…y®ªmyší ¯ÿJ?F”yTBžmÒáÂ,¦Ý[òZ¿‹ûUR´ú ‘¬d¥šâc\¹ÞÌ‹gkØ‘Gs9Ü-VþR:Ã〛÷c‰Oö¨ÑØo–Ǩ{ÀÏüvÛj„Ÿm¦Ôdµ¾úÆþx›!¢²Ç•ù'ÿS…Eµµ`ó+AB1%çk›ÒÄœö÷… p_»øÏcä` 6DZ3¿6â@÷EÐg ¤2tüSÜ€v_¦ {EãÜÁÒ/´Ç9#°W9O¼^¢­•›®ä ‰ÃŠr¢´¨d½ŸùÚ;'—Ôðéú¿‡·¬ï¾DÎh>v>•˜1ÊeþE÷G|˜àîåÚ‡”G¨8w¼ÕÅJ·²МN:>‰n»ú+iÍ“côÊŒN;l%)—RÖþ=8”ƪöG4Ä|¥fƒ,·¢2²I¹O»·Ç0 fð£ZL‹¾Ù§î©`KôXÌY€ÞüÒ½sÆ<ÃQšÞ³áòø#_O":€hyQÏuNŽÊHC¡ü)¦Ùn´Ø¨¨(¬·Zõ ¡¼iTDId"?µëäÜSóÊÊQQN«í‡Cø€%®ó¥(#}Â(6~ºò#^Ê…ç ²$<•-([%ü7z^2eq¢åC‘2×›S³åñl9Ɉ­§‡ìßC‹†“;4´6Í­?ý€õðaõ"°m'š1B¸ö:Eˆm”2wÖ{…»žåÊÄæ€ÎdÌl+å×`égQÔ<_qñòS}=k:Â+×∋÷j^³`kÊdÈœ>W,2„Až‡“às{™cžEÙÃK²Ö …öót¹OҤ’€€¹¿Îí‰ØÏCÝÝ*†[Ó•·)ÿ ÈV)ÑP\Ô#á›nqoY¨Hµ©`‚å*Ê_Øoù½Ûã&¤_d”éÈÈ¿AWÂ< ù\X¸Lþ d¢ä{y€IYqä3¸êVSTÝHt06Ëv€pu7§ÕGHNH-ò©û z`ÃãÅ5yè=Ú3›`?&6zâ6Ì–[ª”倰C.n/À{°û³ œºý¼Öz<¯‚µF_Cý¹¢ƒ°!TÞÂæ›¸D¢œñxÛ»`±¬rôMs"DÒjÑmc†ýtÕl©@{›Â»`-¸Ô«¤WAÑãj?sº-¥+„°Ù ó%k{æ?ˆO]î$¨”{‹,ù4^ïgˆJ?]ˆ°-À«—Ì(`åèm3gã—œy¾"D¤$Æ}˳~^¼Ãš\ ÌIõp÷oÖrî0a·sÀ³Á¬ù¶üÖPèžÜjƒgmÆunL"›üÑe¤ª®l ç̙Ü[dŬŒ–lçÍGØ:Dú0ý¹€{yò#Ó˜BÌÄI½; Ñ‹5àÿ@®„7_Ñ[aÑ VKò+îáÇPB…0´KÐ;ê¢<´ùkÍÒ=L¢erÁwÃý¥Fi)/!!]ÞØ'± l…Äâ»+‚Ur¾1_’ùméX½ö «º¢cFÌuKü«Ÿp§íÉ™ŠÓ¯nc’­ñÚ±FßJܧéq’uY»ÆÚ†'AìKTã¾ËóµyJ…ŽœZÁÂaË´}é ù{Ú«`él¯Öq)JKl$` 9²/«[ç( 3‰<œÊ‹t” äe“Ð7n’uöÇCˆbiøê‚®ä’€€¹“ÿBiè´„½¤"…™¯47ÇKÃõ’ƒ 5üÐNëÆ©¹"$$7“¨qW…O¸H(ƒVéݨ½i\@p²¥§½ÍOF×õBDà‚‘î:lní¯Ý{·­eGª‡1ŒÄóL5ƒPÔ=NÚ žG{SDzÓÎmäkaÇq LN '”ÿ§¡¡×C•Ù{Î0 CŒê< ™ eQp¿öµµ´ë‹3”„ñº_ýtt.*¬4Ÿ”!jïCŽãªzi²EÞXzÅc/Lä-Èînm¼ÕÖM39Òš ¿­¯]')M¢6o¸NÖ<&¢ÿ•%–hc_ÆÙm¡’¿â=¤«e?Ì7þ–'z)LÇ<$²qe9%¾¾Cï^"iêìf†ÎÖÑÝ5™À´/%`4VHR Œé€‘ ß2u”Æ>œuI QO›xí¾a×I§­v–·¼ó¯hjÇÝB{ƒBÁ'5OQ×¼•‚v>&Ä€‚1)®-·–§ì+à¡ÜÄJ§±.3βI#Þëõ,§›ô¿Î>=ÆÿËDZ}h)¦ÍqGü”µÙ-‡ÅPW™Õ>¨(¯¬y­v\A%à ßD»÷‘z÷9ï½D˜øç·õgqåxÜŽ‘èÍ‚vþ®ukPFëùÒOg=¶© AíBeÍñ GÕD‰†æ?ëÜú)¼B4TokX(Ñø­£\/¡‹DÊá¹!>yö~‘…Ÿ ÁÎo}#ª þYо¬Ä£Ž®®Â”d|à„!œr¶+ŒÆˆM¡êùœay*×4]ø^ÚpOÇm©¡wÌ"ƒí…yY’yˇ û\=â%È<Ž™«:ÚÎ-‰ú¦]ú`±‚ а•ÛÒÌÀ”÷‡íCE©¾WuLÁ•hè„ñp‘ÅÆ>Àî(Ò S깋`mê‰îš¾ HõƒFéCEëÄÌþÍÎú†še´î ¹qr‚”VÃ÷hb±VˆE$® ½‚¸M³ÌG×ÅÔ/Ãyޏ&at¡µ¡©ÊÅ7#ý­uì¼tX%ËkÉÀ¬ï—x³CAA&éì ½>… ëÄX‰ß( CY0X¸•ÀpÓ‚oãò>ÉY#ѽP!)ë’€€¯TP’Âd¯>š¨ô7(BMYï$SŒWá¥*†¸? í MØÑeöl¬ úªîÀ¾·ÝÿdÙŽUŸ¨‡ñÏ ¬q[ÑÒÒ‡Q_ã@^ÈžEIòyf4üø±o毈ú{;jSÌÕŠŸQ Yªkt&äƒØG,ó3Wy¶êp#æ0U…>¶ Fؼ.âkš pÖiõtþ¤Ÿ-`Ï™Þ)Û•¹ÙªŽ½ô•.÷Yë~r‚ lvDDn°$XâÙj˜ç ´ÐS&®[xxÁé©PïbºàÈ•ÍLa·Ö¶è½üD3ÀXÕóûjsµS…·8$FAdÍk—ç†1àCCnûà¦]©ÍÅý÷—‹×¯Ëµ[?|ÎãWØ+­æé®òÚðz*z&Éæß"wŠº¤Y´KŸ*“ØËÖA’iZ;ÓT¹Ù¥çÈ ½Â]¾Sy{ñ±ÇTÑÇ2 ‰vËö¥Píë4U‹u¼7˜Sî^RŽÂ{pi!^\Èwh;ÆG ÚÃñ8˜U:‚ ‰Ž*ó๢bó8‘áÉsOe7ÖH¤veօܳp>Áívçž4íU½_ÖPZ ^=q‰!Õºœ61镨ì7*I¨ž×K7õaÕóGý@Ä#voÖL¶c#…ƒø¿‚àkiü¶2r?;ö'^gP͘¸¶’fÌAÝ<}¡,³îø™SR° S ô¯d~k«U„;™ie«é€Œp¢m8ˆì¸’C™…“šé©®s• g!=.ˆJè±ÛŒ´/ßˆšØ±§‹O0]høù¿ryZáXeª‹‰:d“‡©*}‹Ç~Þ‰Çx•š-ýÙÌ`Ý‡à æF PaÊá(ÑøÕŸuwW¨ NzE‚ØÌ·}'ÎO¬åpV¦½ˆc)Ð ÒuùäJÞoI«¨ö} ¡s•)SöL?°²K³Æ‹$=aS§¤`ó0Ù»<¬„¬蛓׺r³Ê›çù…÷•²BÐ`êŸ:Z=†Nاro,Û¶tþK@*±Œ èÿB´`8¸ÊœáÉåÄÆDÈG±þH»Z4 à.^ƒ†ñj®s­Dç,ÊÛ„EÍŽÂÿÜ‹ª€å´é–ÊåØäÝ÷ö[Zƒ£àÃgKÉúö];Ê8îåWV_aåƒûF&„„JÚïKº¹¹ì)ïß°ïzâaq¸µ’€€¸ÝzzC#Ø·¾2®eFLλvÔÝà€µ²E§0Ϭû“YAÒߥó4ÙÑ Ç€ `&„HÑjBœ²FU±ÐziÝŸüËj&¿eù«« :Ím¢7'^³ù]áSµë„5:õ°64 QÊÅ6p,·â[wzaȶ=¹Öb:²…w“熗AŽ[#÷ÖzÞØ/WŽª ¶å¾fçsHùÝZ]†"”"5ÇÓ¬—Ör}{‰"¢ïSl%˜`\øå:`a²ð¡à›¢ŽoÈ(\B†P» &ŒéE^‡Î2į Í< Kñ‘ Ø;ÐáeÔ„=7[žîã§òºA厲§·ñ†FC÷>AÄH#q†-“Jwš’0ëJCÑãAÙcŽª Xšô¶8ú%%ôöýÉÓ<›Î‹eyŸ½½x;éCƒ_¡aR%„¨¸ÒŽžg*ÄŸ>Á’ÐJ8­qšçHwæur¾ïŒÕÂüaaÏaÁ–²‘·s ¢úfä)ønÛˆ–~Ñ“µš تçþ¯AqsÆ=€¬¥R%¨.;ÚíéÁÖšŠ¡ÆÆcr| )v,BP®W®>óôJ?‡ÃÝ'ÕS‡’€€Á 4é’5ÑÒ‚L>Õ¥4A@öõÍ 5×fTÛ…¨ÝŸ¤ {‰¾°)¥¾çE:[ŸKß:ýv›b•â*ªôó{Q'[p3LÊ"ˆ^½òPœ@Ÿ 3¦YË÷Ô¤ôô8Y7j5MÀ–ötÉ“}TDVZUZÛ–ìê‹ï#ESÃüëÙ¡c¾ÖÃÖlB6XƒVAÄ•ÜQù žSØæºT2–qÇ–°´0Y½ÀQœÄeÌ)'±zÄîIÿh˜ôÍŽÛÆ 7ß{Æ%Y·%¦†ðÏýtcÚ<à—PŸD| WÎõ©ÇÒ‹¬ê>öXoÛŒòˆR’Åý(h$e=`*&!)ÎÀãÎKe!àåjðbv €SˆàvˆoÃ;†k'Œ„»~&J}¼ªˆ=-€('` QõÕÖÐ}4jÛîzwH²6]þËsFúbAÿ‹ò¹ä°ÐGf¯I¾÷øðÊ¿QY€ŠhüÎ Ù#>„–H ?„&„eÀtî]úYu½aÜá„aÄLÑNS(Ö옢ÎnÀ@3sœì@‚ËEÌ—ifÒ(A] ñ˜]Ø~)¶ìn?ØL¬ÆœKå˜ÍÒùÛD˜k ÓÛqibúYÈ>uÁaßI­2xÒ”U´Sø€:ÛÚd(/ŽÔ¥ëtí!¿åk@QÅÖ§ôŽ[:ò3IA¬çÐñЂ„*lØji÷xµ¹!­'Ž0·'Iˆá•…øÂ&7PÌ_ Ij¾-¯¸-=(’œcè/¢ÌÝÀ¹MJ^ôñÜ¡Ô/­QˆÓKõçû7#dò—Ë"ƒ>$&FÛ •,vý |Ĩ÷%#ŽV*¿|+R¼å”­rèNÒ!p‡+öXíLäÌÀS…â¬>ÝŽ3,qË֖̚Ŧ¹ ¥OùSwÒlÚ4ZÎ0ÆU­©—é@Ä(QÄ~ˆÅä]Ï‹Ì)[/úk8’€€ü(¼ƒ-ï”ô4 Ž“š\\:¶¦z¡bÀ{YŒíÛ¯8ZòRÑÎÙ«¬~@&l‘lîxˆ;"•ÖÛ^éX|PšÊ»´MXçu:ôé‘íEHXvÓC+áIUÂïd®†~ñoÜ›ðí磟ÎÚGNìŠÑª|©ÑØ[* iº»ùCý¾+5ÐÐoý*{BYåt&"ûmþüЬËG égHœX@!Ùt¨eeŠY¬9$ÒËF{u×aQÓª—n׎A£dâ8¶Fù«0ŠýÜrre4»ã˜ÒLæ3Wî®éÃæGJurµËƒ%zÞÈ䊫ék©-`Eê+<åHÿ\Ý—»±[´«Õºn ¾eû!wÀšMö©ÛÜǨ SF»¾’Ñ—;/Ê¡<"ÑUÇ|FoÏ•D¤òEêDÍÝߘ8Gåþܱ˜*]µßh.:õÁ±Vç™î’ìéžëš¿8¶ÏžeþòW±fïWÖQøo«S[Ú}VUÏåµÇ¼F¨dÚ†ÊöÛ*¦páÊ»ce;›>¿n_ ´E˜«N.ˆ¶Çc\ä–Ù6ÁùqAÊ Ò…%Q¬»½ßQsŒeùcÇWO+sˆÓT³÷÷çcX{S1ºiã_k;(÷9#˜žö@†.È×u-ÉWI݆žÀ`ü$ƒÕþdé2«ÆœD¸Õ‘!ÄVïôb¿ v¹4îú:S8Cܳ´®8è*z¾JèJ\È…9|®'ÿr©KŠé°5çe±)¥A£æ¼õZ;§¹¼Bü{={`¶q<Ç~`ˆ¢ 3<ÈhIºâ®¯•XâÉkR$‡`ö2 [ ‰ýÀ6µ ·î­0FlÅÑpRU;ý]ëZ±O§²]I(u É!ò¶™ö)E~øvPMg…ßp‰%±N8LM.BLäUñçà`«läÖø6†=ãÒFg%(BóÄ›·Þ“YU­Â&"ÈÈ_Xýâ\Pä$©5Å»úNòµ‚¥®Fë"á2Ä£{ÍPmïi¦ÛN…¼‡{«ž?hD’å#´le¶ÊnWÅ9¿œÖÍAMÕþÁƱ™Nj¬ùÓ!còüép §&m¼A×냴CØ…KSð㫜 TT½žU®»éKz4R‰¡– k@fæ/oûÔ(ìÙàeäÈK’€€È®¥´YºžN·{ÄÆæ×ï³z”ߢ:6Î¥Èp®ÑÄ£P¸Âÿø‚ñ w’ÄZj…hqÇÆ06„;E°¾ÉK"G°v…•—üu„Ȳ¼>{Zqïý¡.„¸ê7Ôø¯¢zÛ>Æ}05£›Å#»d}$UàÁ5—SpQ»ÍGþÃnõMÀCw½!ñì—{’U Þ—Ï#Ò¦Ž\=¯“ä72ªxÒyŒ0B¡ê¬"¦ŽŒ¯¾¾¶”Ÿ†·½ 4¼y¸ê8©KŠX‘ùQŸç;†ú¾O\K}µöÇ‚ç\?Þ~¨ÍWâ‡ÍAèÀßãÊB°³ž7¯LÔa½§dÈ|¼‚„€X„Ì\3³ KlwSïÒÖÓa”_nÕÙPØE|%bÞHnëézÈI› "•}æW—oé/Qæ&>5Û?Aq´_Ҩа¼#  ØšA±[QÈÕ=Ài†Ýj²EÁç “:È>õ- ë¡®¡[Ym¶ ”ʃB# ê«fO/‰ÏÁŽ)[5z‰¸Jè®F¡hy’{õV™t~rÉò)¤L–ZeǪ  }yz¼lS'Ç’µùÆïÇ©½ì‘Iªpˆãð—ðk@oè WÅÉDŽ*Ŭ 3¥I÷ (O®)¶^w;=@æ&ÕýÏÏdQ)›Á̶2 xêàRõ3sÐ /yÿØœ®È»µJ‘è€ö<=×?ú(æÁÏê6 Âzñ¡á½äºzÆ7^3•9÷„óàÉ8Á}ݪ`FŸ€ìyŠf#amƒ`ÍÛgßÈzÉÅÇ®pZ?ÚNY ë c4ÜÑ"3ñPë¦Êý>`×`MDyã6ÝɤeNSÉ9PŠmú[yµ-RÏœ+ºœÙx­ùßPub¼Qzñ›S•3CEGßÿ;¡*2ªFrb‹^¿ãù½Ùç®M\€Í÷»zxÎÏ¥°6òÆÍ !Ð7Ç¡6íâ .ÖsA¬X|é£-Ì/ê8*Xƒ,»²dãâÌþü•=4Zƒ—$Zõìùý8£1’ ¿êMf&ꩤ«À™V%¶dQx-sUJzй”ngŸûŸE„ñ 'ÓmÐ0¹=b¿F½$×^TD¶ÕZòõ5ÛÓÞqö¤=%S'™¸lAXÆÔÊ.nOçðdÀVa\•ku4 ÈDP°ÒÞ=¹¢¯fTüG[±õïçn3Æ‹6çëS9K`>A¶Ãbc/Þ«j-Òôƒ&°¦¼ÁhSm•¤Ïk6šZ mqß ›Õ§ß¾Ï–º‘;êñ=§žç„‘ÃAZ2³{Âw)~‰¹Ý±ý»EmBjœefä k˃m;qÅÝæ˜GÛ“ez]Œü9-D½@sÂ{D Óö¾ÊŽ ‹©¡âTøâ¼ë[Ñ»íD Z”í§‡“†| ì<¿Œ’K~Û@~±ÂæÚ†(ãnª(ð™ãÁóùL Y>M‹ßFzüʾvV®œ ÈçÑücäìPùê9óM¯{AD}¼–h&ÍS¦’€€Ögµ×r ›4L ?#K&@l³‘Õ—ËJ‰*yR÷'{Ëb‘‘NÈɲ£±%æ ;˜’hP/´çÃ}Sw&h™0HŒõ`{ÓHt'J=•Ñl±,VL¬.!b_X^çúÅ|¸¶ÙAVI©#jíÍwl_¡à“.…3æË_ÛúíÐkm“~.—Üëãý$+q ¡‰ëKêŒÁz| áSQ~³·¬'+Oû‡…Ž‘ Ÿßc »¥Dµ½l_}Ù4ñX|;æì¶:ž6+è÷ß<ÖWö¨…‰‚ÇöƺÑUôÏŒÞl† .ylÿ5°…¥C U€¶k:çé,oäÿ ÉZe›ªpBשC›ÿ~»°HœØf¥ˆêw°¯=?ØnšnðÁ]UrÜÚ^‘¼ÒLhØpÉ®L\ iÎxS=œ ÕL'R†ÕŸŽPhWpÛhÕ>F¼)Ú¯´r«\Ý?xwØŒ—óÐ2ªQ'Ÿ©ÛŒÙk³2oDÈþ„9}eŽ,_«ïáí@¿¡Ÿ®îéê90Ñ<ÓMæGš}ó>±¸¨µè¬4‚ö&ÈÈd[¯i„òDu fâ· MJ¥4¿î>’t¬ùAŒâ~m^\ÐnZÈW{QÃ3]IØö–$Èûê<Ì®zSñÌ;h¥!_/Œåyºû)…íÒc”®÷Ü!SDô¨øÚ[¢i¯µœùÌ)Z\¥Ÿ%αEF>âM§m]ö8.ÑÅ®å’R¯]hóÚ÷•†´nC^ï!¥RñP¸$”Qm¹{Ã? îŸ+ð…-·¯7iAÑL½ÿeÑôI÷¥²î&›Š¸pêM4JKç–5î¨~¹PšÈžŒ “̰Bæcñ.Ý—}‡Ò— …ûe`Ìóúp}±ÿfV¹oK»y}/TâöE\oÖY“õzÖ‘;êd•&nü½œyËTAz¬[®+“bz-ë½¼~S–ÝÒŠçð–S}RZ“ÄûÆߘÏÎÞÏÞAçœêÅQœMŠy„J†sP?f2%0þÝöT¹°ö~Ü3½3ä1þn8E~A¾ÒQ<ð¢o³´i”glÉŽ;ï@ÍÅž¥<‚•J4mËT[Í ŒÆü^V[ ·eæáDø®ãf4Ñe_õäÇ~D´¦€XD4’€€ÃŽøùGtf¼Šöv×Å<¡oãÛ¡ÒuƸ mÌø6; •û¾pK´a¾T±é]Ù´ëZn×4£F‹A,¢쟛5ÂÖ}Áëx¥i[*lÈ ÷ÞÄèŽè²ÅûvqtùÊ5í'š@hCKÑ] ÍsȪv·IiÏ4Œ7]3qÕ¢Vf§*³é(ê¶ýèÕG¤Ê6^ƒÏÎh>Ë\¸ÖCÿ"Ž{¥PóÑÅmôÌH…zn5jsbUe9f6 ý(‘ +:ÝS„ÄúšðëU¯Õn’ÕÚç·¦›U¬õœ6ŠöáËP‚¹Z!Ž÷¤á9t;)'yà*«$ó.xËÁÖJäóuDòŽ3`¹ ŒÂăJ®R£Oÿä\j`V$ª¤Å4¾gorEjzw‡rë¸2Q‡Åä†8‰^”-”µüÊÅñ·AZŒøÆ_OŒ‹#1.þwÒRbú¯3?)-‘{–!•t¢Œýþy†-7Šáw 硞[§fÕ.ŸÑcÕŽ‡ˆgèÏEμöø!!êû M$Y´¹rdøÄØ<*Zä‡8\H3K²|åÍʨÜܧ\LeD}¾Ð š=®&çlìC5 Q/ìcö—Aü™Lz¬X|KücÖ@;7¨èæøB>¤/Ù­ê'_˜o±eð}¯XÞBê²ÄœŒ;yáZ™‘MäOq•ƒ€›Ž`ûüµæ³ì¸KÃ,“,7J}8‡û(´ÔPZ™ã¾?øbðËÎÓ<¹×¸ÍØâÂpjJfç¹AžxªÍ3ŠŒ–àÞ¬/´ævà´ˆoMdÍ:\dúBÍwé4 þ¿[8çÝÜc¥o­ÏœgäŠKÒ±­†÷Û†Ú31¡UOß)s3mÑCAôu7)Ϲ@qM×Ošs˜Ó&~ø5ZƒJV¨+ø6™y©lÇ8ÀϬÊÂÃÝÎ ^ý¼ý0¼4§ÚE“¦ Ž ò!2Ð3¸–\OAúP÷ mÁµhG`ïð;eDo@é¹Î4û7’«´H—ÿS ~…¶“Ûb€n½*æÖpP#z -#¾ý#‰â’¦:gåµÜÑ·T  v½Ëµ—SV«’CÖI9S‡²T}›—'CÞî±?2Üi®Ð4t®ïÍUêÛuâ1«sÿà±²ÍäÇ­}º4§?ÖåryÈ4’€€Êo­2¥Œ‡uèf鉸4q¹Ë–‹ÿt1îh `í p¤ò?€Ú9Þ9¬‹18ØMÇ̘e©Ôëo‹zsòàJ VÛ®R˜»æ±pËòŽWã›®`.Mû¼àš¦šj§É\-J|Š’Pø2± @Y#Æ7ó}ÇMŲo¦J)ÌNéÁœÖ‡ ó=¸xÓá©wųèòš»9ŸÐãÁü›¡=IÀ?AûvJƒr"R¬Ô’„ ”ÒA±8ÿÃóêgá½?Vyç¬ÑÞBw9ÙY¦D#”HHh³yäª)Ç|kB ó=¾ŒÊ£‰oöw²]¬ÁBo¨³÷ Ñ*wkJÚàU¢sEwUùCoÁt]|þîi¬QòÌÎ`ä¶Ñ¶cv’á®”ÐÃé‰~ΉԺ ¨¨¾28½gCĬºqøKæ¾Òè|“hšÜ2}‘Ÿ°=ÿ˜?â÷UÔ©Nå|ŠžN¤sJQkßÚ¨ølД–8Ñ»J­1<ªCј/i_üŠëÃ)ªy >22ê]ÒÏ×Ñ´tŒ¾loo¸Y޳”ÓÜy¸úÛ¡ã˜kÓÍ+Ãû•3ªI¾{æÍ{Æ'lKòä‘=ryÒ:,™d¹:Á?b:’ú,!ÓÖÑÏ´C.F3o¹21@[ðnðMÔ‹“î¹üæ4Âü~@ÈF'ȰeÕƒfÅ»:”U|ÆnJŸ3x¤ëbf²Ñƒ(T¸JíáƒÁ!®€§ƒb~I¡»«JŸ; ˜´9‹ð°í›GïVEÇ…PQ‡>Ýç¼æ{èº#èõ!!Š ¢mÖòa¯„x¸ð À 9:î!œÁqäºl½Ê/Ø®D€Rmzo·Ð~1 ØHJ>O†7Ùwúú›7± ‹5KE}ʽXjßÜ¿vp:©z\±ß÷ H5€ø¡ sØŠÄ63Ápû¾È?c¶¼s}2[± ©±_/‘"pŠoÔÈkƒïÅm©Š¶§Á«™¦?–“iVP;Ç}lÎçS5ˆ­¿ÓqnåK‹ÍH:{ŠÅCàòÓ3O›0ô5ŠâŸ‹ˆ_° sìùH‚òÊ _SË„¤I Ü]õ“O=8Ò휰Ë/á«~¢c6Yƒ3Ù<÷žF‡pÁÆB…7€éЮt¿¹*oõ_亜 kØEù’€€ÂªÅ‰¶{‡Î!Ý«ËèJÚ\Ñ)n6Ï @ŠŒè&j” F¨ çÞÞŽ¼Þ¿‚ý'!Ç‚¶luâÌWü]'Ö‹=Eö¢^¬pÂÃ9b'>\P~óaìdAEžwYû®³âæ~φõŒ©â7CîˆõÑÓdžÜ`vãC iMß›16lId‡o²=¦¤è¼¨¾Ãõ¨‹ÈŒøýš¦­çiă®ËÙ®åÃñ4ôþxŸšêŸÖ5|r  ÕÓlO!°w5)?¸˜žâAáÚ/ê&œâ©KœPùjÙÿ¼‰m¦áØÝ^’rqƒ:”‹VMª±‚z6}KšYoWšgÝŸºÒ…IýU2"k¶†A°6~=bIìIö‘‚,4¥ÆC©ZàÐWÖ ’Uq46„ #4oóæ#H"‡ž}〉5½Ø§hƒšÕƒ2 Ú;ßòmßk28(‹ Bö®)µ%ƒÝIÀ4Ž«q&eôÙüû-9ªHz‹Q4¿{¹çS½˜ýµ7E@ÁÉTîW¡OU`±êÝ\»j y„÷[ànÆÊUˆ"†œõˆÖA5MŒžüîìP$þNºäñSK¾evë¤dÆ•>\»Œ®8‹ç¹"+!ß~3åׂÈpXÐëÁœ•¦ËÀUk1QÝ»æ¤Íå»8ø$v*•Hñ]j_ˆ½†–#ÁàEs% Å7N§€Æ|cÛû–’SÅsР1œ¥Qé¸hÐ(Ò¡_`© ûo^FøYŠö}bðÎY ËHüѰ:ÿŸ”=©tÏ% 7ê8¬ßŽG>~PÆ‚l‘‰‹ÀcØr-M@UùÖµ´YçíÃY.œ&åRœo É¥žmAe,"îGsY…DS¼}²þ…0'€p*”¸o¼fܸ•¾àH»+3aʼn0-€Oà·‘ˆg—²^òb¬5ªNCóÀ ã ©¦!yM«¶ gÚ#3­•Uö »]3Ÿj¾X~ª—Pè©\æ¼ë*pë@f¶áâÇð´åDäçs‡"b½Î›QŸ`SãÞ¡6Pò4˜·¬[¬É=…„ƒy mj<ü¿FÔ Öñe „_†çH4ÿhïþe-Ws’~s™(éLËѱ¼`kŸ¾›drªÊèC¯¸‘hÚ|̬Y.¸1Ç$Ìß«ra—‰ Mäû·ìbÚ_{{=úcØM’|À™™U„¬!«ÞÑvèy,I—H-å5«°ÑÐùûvèÒÕ™“‹ yŠ Q†ø’GŒ…Òc䔸à[¨_’€€ÇZ{¨Üe€eÇ^ÛQùýåóÞ°º áªä[.šTÌ](3Va`/+ܴȶð:rÉÆš=òv%®ö&u¬‘?fØôá ´L ö$/œʦe‹ùå΢}êá2KÜ?ñÃÁ£Ã{$ ±ÚPgã9¬¶,wþÌ_åf|eÐêƒÚïåwÎLQd…$è$ @ïRn½‡ÏßêB±£Ú=0-?ÄÖ"âzØævA,•PD‰~­ ‡·Èó.»±âä¡ùÖM½º|Ï-cc'X#]Çý¹äšÿ轑6 ‘vºÓ¦HªŽbCfÈl·}çl¿èX¾éD›¯‹ ôˆ1)`Dàa¤íPö€"¼¯”gKù¥3›¾Æ‹ÌV šTÉ‹/µ=éòÿ'ëŸê .WþÁlºŠ\÷(ÊUd¾Šª»XÁèós½$Ôü`ä.ïÖÌõi€‚TKm5VA”JØ·°\øû»þÅñì]äÛ,„¿",òma±ÖSÒEIÛ Z^/°ŒñýZK ‚ „B&Þ{-V{ ¯ü;S DÒíc²j«ÐBQPS& 4Dj` ·¢r3ÔÔDp2êâfk87ùI"<½ΕÈG“»ÄãâÀšs-¹·_J¾WÉ‚ÄM4¶øA‰Ù2pŒïÛ Ð¦O¸F}ònöéõ˜i(¼± %Gk>gÚ#3.7•CµCÈy›áÅÊäÅòFNN¿KËãÿîGÍѦ¢1…%ewQá‹]ÍŽ–^ZTg%qÑXöt4·eû¯ºâ2°-UøáêzšXoéô"|q)ÒoФ ICø¢£†i0øÊKïl“º7Ò‚]»)¼î/ɲץ"#»¦¦q4à®Ñ.,¬+ÿ¡¥}«pJ<Þ°Á)!v ½É½ƒ&|xàiu²yS6/oId¼íý´˜ôJî8SÏ£f4”ói› ‰êm¼ý­Tå¡X-–~Ö¤÷7! †±þílÎ;Mtž[즇¢˜µTö‡Ûnqw58Ö+Ÿ—áË„¥ÏŒDÙÐÏ" \)ò·Eó(ùWµŸ'ÏFtùm;«fÞc_]ÿöñÀTE*ø‡†äk¦CqFÐèlè5¢Ì<²äïEitwÏÏŽ”ò™H«>º36ؤ<¿”J°#.ø÷2:’€€­òˆ· § ,Ý2K!ê{e¿ÙùˆMµ*±²ßå‹Je¸¢šeÄC »\¡8Y”@íIªÎ&ÜP-Ë yϱ‚br9Ž*â“TŸËVš©º¬Â˜mvœ{>‡¬€b Ž’¬öÚ0É =æu®$v¬‹Æ‚ƒÛ±hûûƒA³ôiË39ÜšÉð`ÏÅNžÄMÁ­ýQ&åÁÙ„3/Œ#U:pФ/³ú;MX„ö òšÅøÐÆN¥¢yC¾ªÍTË))G'Ocq­Yèf;DAÓ|Á«îæ\$md™‘&sEg8ì"¶³åsù!Ýjp˜¹œÝž€¸® °R"íyx}*µËæä¢É|q£`Ê­‡4bdS½:‰vØ@mžo©dîüóÆ>W!fo{˜ÿ]®ÚÏG„„û)<Ú7[×´0Óù5L?ó‚¬à "©kô>ðªJÔp!k×:~ڇ̪c˜®/ÒI(Œ–£S:$A;³™4—üãÏÿ±²{à ëgìc­d5àè» †áÜü S­Ú7ìŽ {hlc W﫾{]Y`l™ÿ”ÙŒ5d^AßrŸ$äcù,:îš` ¤ýå.yz`¿Èíg,6Ž×bUìN¢é±uŽÈ¢¶Ÿ¤rJxÉ£*JãÊ7^ŸWÎ*štÑ »<@["MÖÝã?<Ó&(4]c¦ð2€•ÑÒq‹‹^W‡Œ{1ª;ÞrŒMS¾EË-eøM]Ã¥;ÞÛe½b´ôç{U¬ÎëqÁ¦“©½!šôqæ¨UR+8sKqðö3‚Nás––EP˜·,ñZ„FLJn™/jZ9øO¯²Z8Âëy¡ï^Dú(/¦ßÁL“ÜÛ'Ö”$ËSäõ졑Ͷû\YWej¨~Æd0%Úµæïö6-3Â5'&fãA­Æ¡ó”T HÊ>mN/"DòÖç§c¢•tºÔéžBßäL2“<æ²½ß$_©µ²ŸW«jNÚu9XȘ!çsGÔÑ#HXŠ0ƒL¾ÿ3_âÍ#fî†0?ª–0î¬X¸§»ÎêFM» AÙ€ ¸­Ü·– ðùvúVÄ9ù167Zë¡ç6ÿš½&±K¢Ìå‘–Ñ¢A QÛa¨Ç¢—£pR'…òS·ºªëqÂãiK¾)qš¨hŽŽZ_(ó5gUªb;Ñ„EQÈÌ?arhlVpuhj‘á@ƒh‹M\Ô¿Æ]1!Øów==v„†Ú…‚ðJ3.½¢FXëx¡«1&O˜¸"UõǨQD÷›‡æ,¹­ÐEMÏ‚óÿr¹;±nPÂ(BêMóL}'dÙmü¤“#jUbpíMOi`gkÑ(gop>0S¿¥´ÙÈëJhÿeKœÈzµZú …O@=%²ÂûîhÖÑ^yQ')0¿ùÚ Aª7?"î`^Abp'^²sZDùÔ«ä,¨Œ½óp«ënKÅ WC0Óô…TŒË£ÉZ÷1s­/jÜsp|øÃñŠ:‡ Îú-¹Èô!/¶1üb3W0ö¦ëÕ+“Üu Û^P¹û°Ž`5ýnj»ÖÖ}ARŸ¿H* ½7| >d§2ßB ]€˜¢‰gâîØÍ(×(Lœaž‚Íç « eâ¥ÒË‚Ø ûHeê‰á²œÈ ›MÌa¶¬®’AøaÞ=>Õñ¡9ïd;­,ŠeŸ§ø¤¢íMÙ|%uÛ[£*SΚ‘éy åWßL¶±µãòók·ÛI’ÉŸtR`û´Ä¥SéŒêÆØ»×J¤Hš(UÒASIèMþ¨£Ñº1«»%Œ²¶2è |³ým+®¢4ì6ìïX÷ˆï‹ÜWOjƒ’s±Ž0n\úÈ–Œ’,X`|!tŠÜ]«²/øÛ<7ã€þ‘žB­*Ê*¹V‘A¬íU˜øÖ8%€Xž¿V÷ÝÞõÕ%ϾòÍý±òÎNí` û+>ì(0…;ïÉkäñí´Yx瘙ÆÍU#4£3Æ„¨Ðš¸Ö¦LBü˜èæ¸éµ¸| ÑÒ÷Pë±²½ÄZVŸÝyXd8ï½â½sÑy’€€Ør,ç@‰¦$Êšë3KC™uZ“- pÚw9>Íý+\¢ê']cœÚÆàŽÆ;V"_+2téí ý“ö·Œ!PJ09:†ù>|Ul¿MM "³£Ó¡…‹ÃÎíÅ:~2jG.ýÝÇ|l_³USYê7WØ´Ë Xf±öø.¶!ì~>œ¹™‰^Àª†üÛ× í7î¾E«£€8Ȉäµ~RòúB.ÞŽ5ê*8~”ÚÍ5’WdÞ8ÐË;ž3( -<´mùAÍ>ST/]‰ÑâÇ¢ÈØ£YžFßúTÍýˆâjo˜!´ ?´õ …l/ tEà $JÉS:5(ï$ál‘¯(`~>ƒÐë§Á—À)™äݪ-©ßôÅÚbI®£Û çd„‡Ñ~¡$[0UYLž°cÇ·ã0Ñ‹$D(lÊM[§äfe¢ÒK &ËNYg\À,çÖ*ô‡Ü/Û\´Ä¿:‚Íb…´å¯g½W12ü,6M§î!ƒ'~,F"Eš¤4¼ŠlÕ¡%÷1¯ÑÈ3éžýþ%ý†çõ¾Áf@«± +Öý²ŽÏYhxzíîÕ@hĦû”v¼jë¨o¸ `tYôš)ò7ú=®¹| „´Œ&r~™"×ð–$dVg/8Oc™ýÒ›!ð5ß9Û…à?Bâ¼ ì=ÞÿÈÆ8våΨÇ>Ò¶q»#•ôþ°b iƒyVДƒG“<.d­æŒ· ÏÛT÷7ŠF^¹pü"©zæëœÉ´gAç“eÍu Ã’°ÅÕ’ãÐ…éür˜lóø~4óNo8:ÖÌõíØ°+P©TF¥\pFIêŒv^ë_U-Á–ÐP,„i2!'âÇ_ÊÉFl€g./-Û&ØiHU€Ýh‚,©: ÷½:C(qÇN Dë„+èƧæ€Ô•vИm¢HSŠV‡G]/LÚ/Öû«ÒËËKœ¾HþãulÞ]Æú¹äzcÃ’AvÙr£Œ«ú1°Ym ÙÊà}Ô^¿1kèÈÉï §h™P޶•è)“دQo=–š‹Æ„Så)&s·ª,1JwEðÛGw1ŸÙ6£ÔœÜ@:¶¹ó´j¥rføûÍoË^5q7ë9ïHÂ4žíœ‚T7=ÓÎ ™ ’€€ÊÓ4-컣OwÂò(•HµÌ¬¯}©ÏxïÄÞ6j®‰z߯ܲ¦Øöüé°p†+·J|¨;c\ú0<̧Ÿ€ý ¾³—õB^«yxjf[ Ú’TŠr5iŠ$ùáÞ }SêËà;|Œ±¨¼ðö ­LcÅ%Ne¯>EÙÓúLë,i©P %Ô>(~wg«± BBŽ®‰œ‘ä‡ÅÀ¨)}Þg#]mmË+s¨ù@]"ÀxGœ^Óy"+ärî[ס7ª6íâ§N»É W=^`õÜ#ü†vß _˜ÌÂ"°ÒW%q-Å zªúàV¯2ÒKü§a¥”Eœ*(ùWþþ;ÄÖâ¾^K[Q(+/ qE*dx³º„Dobá„ò*ôÚЮäC„Ô.AÈŒdæ_~H¶AÀºhWBYÏ)"/2Ü\Rÿh" Z—¿Õ{·ÕÇÜéÔo¢x]‚´+ÓQº½Ï;™Oo׉tÖ xÂ_ñäÐî¶“@_ Q»/Aç?ú;rÆU¹*€Ö9Oœö†„ùõ"mÀ9ð9˾Bé‹—ÒøÕÐcÌcÞ,¼ÁÖÙo/Œ¬>upºw­cxçžK ÷+ðÿ­e ]À•ÞÐf^ËgÊ73­ÝŠ.Ón ²ÝUÖ/îhlï´¯€ŠNÒmúÎ@é7ƒÄNœãÇ뇞å¡Ñš6PçÄ!JÛ‹œ-v]¤ð¿þîfÞ°@Ú)àÌÀßVw‡x¨°X¶J¡ÿæh"ÝfÞܲõ i‡B¦¨çŸ ‹†HìüÒ+¥WVn`ü•̼ŹT‰·“INI‘X#¥´±zéØuÍKÕjr°u¤„3VI0?ÜsìŸø¯ >Ø´®÷BYëÏ$U¯»pºtžÿB𨤢,MsqwÁÖö,°˜rT-˜¡é¥‹§¿ ˆ¶P˜±DôÚcQöfê¼μäd6p¹ú¾M`,q`õ» s»)#BfصJäu6µ.d˜ðƒþ΄sPXÇJ¡ŽäBÀU"„¼ogj Ô€É!ý¦˜‚ü… 2‰ÎOºÁ ‹×†4!5îjä¹z•#ôN‰ê‹É¿y-ÇT8­Ñè!ñfûgVûŽÄ½hŸ&v¼S¢ô ¶s…z/äp‡ÿ„É`l:°^R!€)¯ —ÍLW^RÅTà’€€îæ#ô›ù_ÿ—". Öáèš X›OûŸ3†T£+ÊÍ•ÌpNS×î’íñk])X2Íð¯ÓgÕÞå"hÞÚó£hƒÚ4]ËCX5ÔÈÓl²²³ÆàðófLµ¬[Ï©.Í_ë¶Nž·ó6›·ª²)ë2qÆèO¯HΜoŽs9:»;¯¼ÏDµói ’˜è«¾8^-4ÑÁªVWŠ,›ôkvAX¦Ñ 7>å>0f§®•£ÏˆÿºÝü¾¼mŠìLR{á¿i¾zäZS4,Gí³N¢PÂÓ¢å/Æê²áï"ñwB—_¨ fìö…w9äÈÉË[œ™þ˜7=¤äÑ04ò<= ¿¢‰_ÿ}*ÞÞú¼b¿{y¯~Tøü;¦£ðùÞw|¥ŽóadÆIÕ-$ø¯ÝHö} Ø™8«¤aí†@|t|”¹¢™ì óVÛæ\Áº^‚?ö¢ë”Ñnèõß …Y³J Cõa)^Œv‰èÞÛ—Ä™É|ƒïTOXW–ÕDFAXÃM(ßìVÎ¥VÊˬ­Î‘nš€½àN±]מ#k»ÅÑ4 Öô+­óü*X,Ot­BðüÍ}Á$¾ טc2Oë&2.^¨3 ¼x)*k«m”I¬M¨¢*ŽÌ­ªgùøú`i1Åe:B¼w3Ï –05ª6‹!EóÑr¿wÇj,¥½Ç¿?j‡ï`{¶Ù‡I@±¬À"ˆ Ê" ìÔÂ`mÈ RÍFŘ‚×Œ>‰áíªÃîÖ(ËMÃÞ>'6UõX£fI^¤c-7!N³%s_;+ôÒÿ´T¦A—Qž 0Ú.ü»vùñ}Ñððð5“@'¦ sƒ ]Ê´«Iv¥Ü„›€ý—x7³­u]Ó¿¥9aŽFšÈDhK•ÈÚÉBb«šXÁ(—‰PÙžr×D—Áõ#&ùöE&!Š´G¸ v+/„wÞ–™ð0q!Øðåže7œ{ì´73{Œ®ÄMS㛈8©A$\]b )P’€€½lÀâ ‰ÅJ‹W*è¸c¦SË2U*RZκ` Mvgò.zfÀš(d@_ozàÏÁ­î®¬e¬µ‡ñc¹/ŠìµÝbRB[y2øŸ•ûOVŠp1¥Ëክ?e̺·(ÖŽE iÏ7Á=ïʥśïq/nõ3•PÑ©õ_—s¡Öü´…d¡¸D0ÿÅÓ“Ï>Ș¨¢!ƒÞ±!ºzUtòz@C@¡Ð_—9- ™ç¶¨h¶§ ª ݾpágð¯&( ¯p¢wÉ o:‚`6ЬŒ3\&W»sd_µ´ ²Õ;û*È@.cÖûÁ½™Õj·I;-¾Ð4F‚”n+ýù}hpø| Òc—â§*’烲Q€‹x’ŽJ8þŸ2 h¢Dº2›@p„Pø˜!U>ðõ¾j¤¢yânÁûèfi„*!‰eÉó¡OÙF¶ñ§¾¥G›¯HŽ‚þ®ú©cú_ÿÁ£ÿ.ÅfyH"ád0ÒGº.÷†4_~s•3^µµä³¸Sä=ÁfK!3¹#AdûWçžèò±œœÜÈEçWñÑFÂo§a‘tÛ'*WŸ@I«³}ÉÚdXÑOÊû-Ð[·&{\ËŽ£¼L»ÞCdÁ0(Ý·Úi÷–çôN­"Œ›3vpF.3¾pÉ ñŽFd<[u¦„³`c†M‰î„d”Ëõ‰èº "æê#ºÙ|Á Aj¹†»ÿ©êl;¼ZG¯ÕÍÚÙWnþÔä•rc»%™?ßøêÆ ¬,,G*¯PboØt¿¨‚ ãx®­Ï4üyˆ2ú&Áß§÷Ck$Wƒ/Sߊ;HY/@ï†S¥?Ï…ìwÌ¥ËOƒ“Ûxw†ÚȇXtøJLÚÍÖõ8Y#)ì#S¾îI]idEB‡±.ÂÙ©?Ðm±a”âj )HÒòu÷­Ý&Qn4ä0Z~ðq“rùáAuéèÑ“éºÏðzª]&ÅAJ%”×£þ^ƒ•ï ÌÀ… a…á yçY•dž>–Áo±u¨Ša¹Qq´wÒ,H]jH»ÕcÃK Z7Ê"òðøßLU ­ÎÁ¾Õñ»ÒBl± (…’rG]{¶¨v®¯²+Ò*{ÌP5oGê²Ö,™Ç&]ˆ fÐ~w+ç¾qó^JýYWÕ¦ï¯ñÍ2ÂÀè>/¹¢öpÒ’€€­…0Åh‰ "ÚùS÷AB@üo êäÔÄDQ¾Ÿ°’ʾVŸÞ,œ[ läèxœ é(ôùæÔy/=mwŒ[Ûþ•¥×#b*ô$J’pp\Ï ƒá ~I˜úUï^osöOŸ6ör—â¡­‰\Q¿û|âÅO~`ðÈÖâºøŠ†Ÿ©[‡U:z½¶53Ó /Å߉[Bs.†Éi—,Ö³ï¦ã.Æà K¤ä§óÕ ø»œê÷»)ŒÙzUF›YFÀVw_‰}pá88!sÝëº%}ý©lšÿ*]dC¤-Ÿ+Ùòéüÿ±Ž»ìçÏåáø6È…6•ÐT˜yöØ è‰5]¾¢³æW¬¶Ñzr³J*ðƒÍÀ¹Ù\§¢ÿü{ ^ƒ:q×@»ñ>ïºáÓt¯$p ËR<³øeÊžš5ÖXÖPl§‘”< -$4Ò/pˆË‰¤TÝÖÎBKƒA.P4‡XÊ>£rH£;¯Çã‚‹®BÚ(WS›ÃÉS›ÿ+¡Ÿüàq'R±*è_ùfdñh™ a굎·ÒÔlìp#L9ðÖ@Ú N¾²DRIæÙ.œÊ¨žK:JŒ x-í«ÝÏŸŸqû¾–Zjû«:–*Ǫu^gùý»Kø!´¿ÃÏde J¨„J~éö±drTÛ=]Ú¾“‹Å’déwOÅ»S‘2nôN`·‹Ó„­‘þÈ( à(§ÕegéâÏ¥X”tì0É5cß‚kIåv#èíEH-TS õ‚·Õ™D†MÙËx7îFQp»ã`î rÉ›ú$z*éÀ$ÒXÛ©QÈnJBó\ƒŠˆ²ó298*|“r&É“|*¿Ò†Ý°Ãíò=ï6‘©¡Öv#d*úJ¿[Kº#c5T.6!"”Q4ËÀ²76¸ýî=¶"1ç®–|·@]PîâJ&ËF÷ðòáL™Ür5líÙú–Úxš€Î‘‚èì[êäˆëË𞬠Ͷ=1>$U{’×ÞÜ>¨½ªy†ÜwõL«ÎU r£bÝóLš¬sÿ½Ã«Ù>¥!¾„äéïö bÕ¶¥0˵xì¼¢œFêϰpÁvŠŒ†D‹–£Pÿ3†~f@…%òï—Dj}†œ"“µwòñtâ1O W¼ØÔ$žmÔ•œ‰é²’·U%¨V“úy°â’W戧©3†ó=‘~ Ô(ŸÍu>­²TûI¡E5±§P1.ë&SDâÿ#&Ç<Á^ž€oBm¶_‰Ä8ƒo³¤× –Ñ´mGg¦R?E€äjÌm#ºÍñÅSÃÝdü“Åàpø e€Z[ÈŽ{|<ÿËG®5–W,*’ËáRߞä*”W/<Šp”ýÂm…/¡T{ñõ²cÿÜ@r~YÙ °Âè}‘¥´ÏÃm­ ½êaE¹µJî=o"Qòuȼ93Cω*RO¡¦8K4¯A7lÌ×(8ŠK”Îîa׋µŠÚ@Í ýIän»çt: û«4xúôÈ9" äYÅúáÐn´½µ>V­R@gÿq?—xù:ì[ðdä¤òJž-ݘyCÙ“â€LõWÆ`beÒ€³ñ ¦Ž¸îÆq’ÜM$³›N0e$Ê{o7`ÖüÃ6Þæêƒ@s‘ÐÌ50Óú’€€ÊfʦºöP†HRvY¾ÅºvüwŸÍM žH6YðXmù¼lªï§»üƒ œ–ôâbqPnØM`çÒû‚ô>úi6­µžê üškè½'±>Ÿ/O@æPáÖaT#G,©‡6zþœWe–üMxL÷Ã[Q[V2¨ê€tD\KÊ 2kƒY]»ÂÁ”ZÔU>\óüDo$´ËGôA–͈nxµ¡ü”×ýXËad±”q]ç7•3‡E‚1ïeRõŲý,(œÄQÇüð}lœØW;>ÔXæòÎ2à;o F"t!rªE}ÅÞ„Èí (ÕÊðž87M % ÷ãíÅ[o:ì×Jö¬¼8鲯íq^š]A—­ýð§Ôç½t¨@˜G³3m‹™ÅÕÛÄK2û’Tq°PËêÄÓ[â£îÜV#ï˜w[B|oßaw½–Ê\>e]”½vû0q5‰o¬xäè)m¿CÝF9±O+a9ÐHuôá¥ëîö—œ îÖ°€è2×ËÞesʹ“b͘©£–F6ql<“³¾fŠpyB2Ψ‡˜üÍÖ”UmëßðÝ<2õƒ4ïƒõ˜©>D¸’LQØ225¶O\çÖl=·íœªÈUg]׃…ºçƒNBCÙØ«‡O˜½‚Ît©ôƒ©- ´àÆIuÿ‹a¢ÜÜèEÿ¼T’B©bCló;t)F.ÅO‘톟Žã_ÁM((õ:›Ì–!“$p¬`d¦kz³5æŒqO½í#Ä “yÄS„ú­$±ÄXoÊzáÉ|#}g'ñæ³èÂà5yÙVE.›ßg!ÐDH¾³?µC^Ê:ÇÓè·s&gáy̘ÙÃQ^·9µ½Ü™jÊÉa{×\ªêG|Þ9£C¬2!–¥¿UsO“‘pË]žb…9¯¹71Ô¾h¬²GŒÕžþ§=&q3Øt «ˆ qY4äMcd1'Xãî|Ò‚“Ë‹W2üúü{ò"ÃÅͺÁ³Bè…·.†¬T~c›áb)fëªÝ[7Åzð wÀ÷a̹T6ÍVL!—„õóÞ{ ëÁ®€DÏG{”Âúö‹•±  G.÷Hã¸ø)*Â'®6 ßwf0% àŒDnüÁùD37c±ÿBÀSžÊ9„–ˆ²:qG”‰=°ËŽ(Þ>’€€©ÍU?_6†„|J2Ž7ýÿùý/Ä-E44ÖØÀ¨Ó–bwß9B“¾8O=UW¡ŒÜsÍäxa‹ÄÒö˜ÙWL–Ñ1T^GCªfâLaýGÎX¢O¾…ã²ô…N…Y<µ¿Êºt~gTø°ã{°‹d€?6ïó#L¶´õ?ÿ¨0áL²#“ëêà³€‚3èN}­ÞÑPÔ½l”"®ßÀ掞 3]£ŒÎ5Õ×µÂßdXab¿5ZüžÑš²0ÑåóQÄ®þº_~=R¯º:jÉŧu¥c¸\_!p(ÔGОqñ^ڧ鯴+œv QàZÄ®„ŒÒ,?²#k]óÒ9”ÔÐU±€†&Ø.\ákêÍ)gl¶„Ù_žX™/×~¢6;š?o©’=¢æ2õe¦ ìÚaE¤ÎcÉ©r… K¾±ýd~à}ÒGlü†~§g6À–Ŷ`ü=¤Øç^ñ»%g¶áèáVUÓ!ÍÐ…<£N‚nýE²— °ËÖÑ…e|餆 ÓNóM¸\á=ªÂûdzÊÛóÕ8Qƒü×W®“‹G¨­^c&ÓbÃÎX¾×¡¥f‡?yŠ üÞcÅ}ʧo¨f­ü¡UðdÔ—ŠLð` ]Xÿg´×VÆå¬‚F¢‘ë¤Ï­ûËAÔ·nãXG‰c«L%Bµ.«Ú^””ÅÍ(u¶#!º¦Æÿß™òJZŽ$G?ÊÎ>ˆê¹ôä':ŸÎ›/«mø¦„êëW§&[«2ëǦ'ßàŸñª~¿´x—wß—Í2.¡Ç+Vú>óé©¶õ`¸z­“ÿÜ´³4Z´HâSõ©Ý©‹©[¯8üáò bÖ3p½ž¯æœí?X2…œÕ÷IõP}jd8zŠJ™[ÜzHXMxÑ*¿ct¢J½¾܃vMÙ¡«Û*ß.§N ¤üŽVsî9´y¬˜šú ÆÀøG/c1ÕþÿoCù­<ÿÚÖþ£feà­¹A+s’×ëŸ \ŒýÉÅuÂóÃsbn©j%ùá%ŠNùù<7·?€LËA„c¦ZªížÔòl.ò‹Ž·g’€€ì_áÿÏ3¼sšT´ƈu˜/¢Ó‚êš/„ñ÷úª¨ªlƒÃÂLec$Ââq 4 žЈ2z¼?ÉÜmìzM@Hcø†˜w›^Ê|±ò*¾K~¡ »<lX=à†V<J7üÒ£wœ×Ê÷µBäó—90¶C<·hj '2Gß?X¢Æ•4Õíù(6 w¢.ô[ƒŽ\h(ÐÎ)Ù> ¦œÚhý‚}bÂn P^&*±¥&¦Ó²”Š4Y-?l}E™ÐÛå«”ÓMâ¥zx£éP°<+OœõLDÈ446Z0JLÿÔÛÙÊód›`k*Ý /»ã[ƒriQç!zióX–õ¾çœ-YÕ-M^­4¸›òJâTAÂîy:-ñäã¼0-:þ¾6s¼è¤KS`ɾ¸¼pI hÞD–ÎtÚ}6@è¶æ1 XmdÅVõ¬‰úWÅæ\;¢æ³â]…Á2M®þ=0ñȦ4Ú9TiÙHa£•j¥‘ñ™fOUQVv0ÿêF”1美'ñ;¤øG´‰ÂIߺøÀH×Ô†z™‰'ÓKalotè!øÓ ID0âkSݳI†ß½vw‹/qânüß?ZÇØ.9€‡–P´ýÈdÁ¯Fl$ ýõA´ËúñNFÐÔð“ -h¼µxŸ5¥áÐ —@ çúb®j<ŽÇĺ1T•L­¨:XÆbT˜1¥ÓŠºô&é°­A½»–~G1ä…ÿ†“…ˆÝXFlÂcÔÍ0ák»EëÔÇ çÚŸ¢‰®ÕÎÏsF<Ô§ÖHÚ¢îE£0QFp»(H:*U¢PËyO°Ò,óá´f$¢ê÷Z‡? M0ð•øËëþïCä!9Uç! ‘BR¥n ÷ô–á*¯V„±Uö0çCrK(,“Ç.Ù¡ôNýðû‘˜=Ó=¬L"q 1Ü[Gu i±@ôt/ÞÞvï¨GG µæÙä¹hξ\ú< Ìô[•`§ ô` |ù"ĺô¦IHìxà ŒŸSÒ˜’BfàÅù…Oï~Hxr¤zî;µ3µŽÿµG)|}­„·TOærÚ–© ašúrOP€Ê–ËwD†B×s ÇUäu)«Z<{&’€€¼ÊFqÃGÔßÞÛ%«oÏd"\/Œ;UÅÂU_³Å}¹ÐUÁbFoîF¶Th׎ów¯Ý\¯õ#œ"žÃ*.ØžÊj o¸î¼ÜÐ:d3ªŒ?¡PŠÔh<ú‘Ü™ì*?]xÔñè¯#ŠÙ3äIý@ ΟõO$Ï•ÇGÛZ"žìéF¢Øtx˜$$†ÙVÇæ(£ ’g30²<H]Œ$«X'ï…AvðD£¨ OݬÚ\Y[¹é:¢ú6%¬'X<=ß×xμ¯.Š=¬”t笗¨âÜv3¦RPh­”ç66Mû~1œ¤)q71_*Wf 9ü€GÂäüþHÌðÂA¿@AªYQ\ÄŽ¦Áa€éCR¿¬Nôì¯dS&ûwÀ‚ßT˜eëQD‘yX¢=Éq&üƼäåœÏ•ïÿ[m‡ætågŠÕàŠ,Rï? ãÿ“àÆ¡Ûenxú ®Ò¨‡±·à =$\6|>ZŠYÜ£«…-(«êÄ¥:Ú„Z3•IÆàuÙP¹VšâñQÙi*•ûîãWÈýª‚gEˆwäìö9œyŽYª©è)?¶3ô[²7*É )6/ÖÀ€:ÿÂnŒp0ÇBCÄ;Ür7¾ºxƒoï´AEZ¢å ž€ù¼D~—Z‡õšD—ð™cá¼ÁOä-T, »Ùø?Q.oư*w™õ䜯ú¤ ÖÐXaC{¥!w±y7[bæî ”àx¸6TgPwwWz4oésF‘âMºq™ /qÜ_fïÕµ45¾!C-@’ahÞµÌNßÎ4¬ˆ¾®—aYg5€‡1±yEÈ*PÂÝ{™%|½»ý²,çó(Rl#þüúkþŒN]P{æK@Ū¨—‹r¬W£>I¦…½ëÓiËD®a¦çŠrZp¡•Ë$é^,v¨¢„Z8û×™f`#²i©%mÑÈ«îk1ˆ¸û#÷gíR¶ÿ—¤U¤¥ªú|D*5¼f%ÈÅÚÎa3kk ùXú÷9zE6<}ÚZ‘»‘"µÁr@ŸÅäq(  õ¿|9Ž”Oúжi$ÊÏä©Ì(»(x§#f(|ñ{rp#ˆ“ƒ%õ°B%;t“¥ÎïÛó’0†|Ÿ N”T ÷]ˆ§¢ (4ò/óngª'ÓêvÑÉ]C’€€Ð´ÿFr¡ÃûÎ èðó´å0£GÒQg‚& :m(¶ÿ”ó¥â/ÙÅ{b“£nøXoú§Ù?Vƒ¸#“™åĦ y`Š1ùôC‘â‚Íù»œƒðùTâbÉCº‚ÉõCé]7Æ[ý&ƒBk;™dhüý… ÷Âá•*¶²×ΚÎ4ùòéH±"¹Ë|Ô]'“9ÍðÃy))Ç˪©¸T6« m!©#Bžm#u´ýù4¢‚Þœ´÷׋ èâ_·ª˜0øÀ„TNDr¢b)ÁX”É8;¯×ÌR]Æþ–£GU¯sØGÐMÑßï=tÍ(©Øbª2áb2ËHß­Ó Â’jŽRWÁ8Ì%j“à6AÖä}sŸGÅ_h;¦5!8t¯Pª2]“>¯£-Vþdu­ ÔÃõF[²cª?7–‘™k<þKGïvUŸ3‡_޵{ΊK"—xÿ»¼][!^Ly+0‡%†êO4ËÓý{}°v ÕÕMQGÓxd‘Ì(Êaý5 ÇøFh1?* èl齪ƒw_u4;:êj/z’!=ÀáÃÞKÁ~OT0låÍü¥iߺ. >˪GÈçO[ßpÕ–¹ w9"ü¬@ØL|!Fû"›IñühùÒ9ÐȾyÊB•:sÞ9ÙÑGI;ò˄ܲbÙç%0ow7¦”žíUÛ†UÇ#áhbšÓ4áóXÍÄmk7°nLÖzŸSÙ„ÿ§%µc&;·œlÌéRÕÏ1>‡ê9Âp›0Rä»#…>ç”ÀHœvŠ–}~ã[àÍšÕìà<Þ³DàCs53îVE±äŽË" 2p¹œhiû§(`¡“È8Ò ¤Ôì5"éô}Q!yOpÑŒ:—c±ÿø~*’é þÝHÂ&cñ$÷^û/n°m•0”:åשdî¢áVÌ$ké’€€¿‹µ‰8gevÊ_W2ØçêwG΀b°Kz—¤„wÆÊRp¤njIdg€Pb^¦ fÞî‡UÒXÄðFÖwÁ ï+h{¤Áb^;µ_ÔÓµ÷!0F@¶„*’“‹1+WVµÂ|wËS³óGzY^ˆØë¬ïyžs†Y[ ®¾š¶¦7nY†°AÅu×ë^iw!¥¸Àô ù™fýž$ E¡ ÊX~Τ&™ Ëê"莤ßñ|d³X!ŠõÔlGtœÞtéGoË!zU3€Ú»ˆF¸®L‡Â–—f»Á̸ri”w¤ê‰ÕÜ4,ˆ.§¡v¾À¤ûúYsÂTc-` M}iˆÁ6¶Ôö2Z_¢cÙê«Á0B˜’g¯‘A›–]ë¯IP)~ÊC{‚ÝÈxN:ÃíqI[Ë󬑸ŒÖÃ)äŽAx *á<èT›NPèOÑ—•ÉC0òj¯}“¯{»á/£#õ@¹•FAÁ–µ°1Ñû gª¸…‹lg|‚íà â5\Ë^MJé° äé{[•¡Ä6í¼–2 Ie¢B*uйy[Èö)¹Z?™F“èùç(¹VX7Ë€°#feL(öVö~æ?d“œFþ±"ÔŒ#µY‡ò·{7[VÛè|3ÇŠŽ&’Oæ¼aAÒ;Á̰0z£óëV´˜2ëcK½¢À“DðpÀbÆÝ ÷œVÿÔ~óÙâž»+KÞT:·ÂõÛY\ùƒ <mÛSá-Œ+QíDª‚ ´Ù‹L×|À'c-DŒj3!€™íBcÙ²ÇA ´3ÔÝI[³7õû\€"ÕÇò_Ìnžª$ÉS”œ7羺տð.b hÂ<䃶· vë\…º~n±÷ÚÈï~€ÃÄ»>þtí9¶žÃY‚&sÅDÉÖè¼ €ûó_ùÌ1ÿÁ&ôbí:þ ÔyéÚ\ô“ŠÖ¿]±k‹h ¯ ·.[Þf‘JÌqp†°èZoÚšÙº¥!N·ŒKAˆ s&óÛxs=ÖèB9K} nbô¨6 CÌZüö;7ÿ)OÐN®s»ÆŠÃ; ¢ÏaZ¥ ÿmB[¬Ü,¥cׯ¼®²z®s°ºŒq¡‰;m/Ί v'kLÜB»dH…øÚ\ku¢hËœmrë`,Š›™6ÍÂ’€€é ꤲKè šÝöcA—Moq*8ÙO×7¾A>wðâ%ÀQÖæêZsµ9‹½ _íY›øw/¹ïžqì9FMH$bA·ÔÄ0=X¬Û!ð3ŽÇoß'á<†Xù ;Y zÂae»6ÃsÝ%‚ì‚þ}ê å³ñÍËëë^yßÜÕ¢°OʓҧCa2¬ØfkÚ:D ‘!¬–"@0óãåÂß­e´aIÊ|qœÂÙº%¼*›,@¡&È6\©÷{ ÊÏÁR-Á^*Z°íMQ°c&´µzô%›ε4‘qj¨µ´¼xÇKÓpÃî…ÐpÈÃ7o¡¶;›UºŠõ+Á[/kc4,)†®nV>êô@õÿM>TÌ?ÆTÑÍϯ½©ÑJ„cŸq%@áò‰š ˆí²&%DX %¥æ›«É»'›3G$ÕBM¨ëaÃÁß±wŸ6˜«ˆ 2߸…éŸ+7êð| QE)(ÄO4OgÓŒœÀÊ_ó˜ž~g­™¶¿A_z¥! ÙŸà<}Ù\È%ò¡O5Kl@èâÙ Öƒ„ä<¸[þ¤T1PDí ýðNâY‡ƒZ_›Î–ïÌðÊR‰h´¾BwÚmzmGÁL5`„¨vƒ6C¼ÆL­‡8žîö$¸ÞYL;ù.^}ýlÚéëCiù_Ç©v€hEÆçUý6jŽ•ï›@§Œë‹<~hz2H`p8G™$wÓ:42Év÷''‡wü–R2Ýpn;-´Å›¾£æøŠ,ËäC§”ß`^ œgnt·r„¸Í~‹_À;d»Uú|Ÿ4}†xi–ïÐ>ORr™"uVãÆ·‚ÏÌ,é£Öä¤6`r93Ouõ¬ý¬—·9÷ƘÑöÖ»Ç$Ä 38ÖþQ4Flú;nÊõ£ìÌÒ¤DDÙ2Ù¨-öyJ}Öq±…}nž~³ÏÛíPsÙ=V¯PÅÃë•Î]zŠ%7W©nôœáBFä?” ðç>NÓŠõž"t"qÞ¯4ÓÁ$âo¶÷Vù¿)ößðèV•ÙCjy讹êju…È™{Všcy_èU×¥§]4´MÀÉé3¹8~µR›•ö1ÆìÄÛ¥Pjaƒ³¯kXä\B°£#Œ²Á¿H™û×cÅ3­$¸ÎE˜­“¥ÏhªO2ë´)v›‰õŠù*'Z¢€†4ËX`‡ü’ )þ”µé"¹(_¦G!ÖrôzßX f»G–În7£í¯_ÐçPZ-£<ÈÍj'D Þxcu˜£ÿ§ÛèÎqa6–²\ƒÛôóç3hPR§„y ¢ šØ«‹Í°Ðéœ{¡õ\f·¡oø •C{°ñ¯,&.0e³2» îÓpŸçŒÈ%.Wßnâý»—â0/ÈéPèg(ðºZEì ìYpš8بùŽ=(>P ¨´WÅ)§ éP’®Ã¶Eã¿;JFÁ¼z¤mý!E [¥²Ú™)øøŒyLûºß霿rÜ9µbd5a…£aáEgìªK\¡,‚ýß~ †Z¦§[âY§É\—’Kþ4~Méjô-‚_ä•Õ>pøôiÚ£AöJ4~Óª²\€)Ålô}©kþv¢f¬Çµ}]rkÔ=Öûx•BåÐh‘^j_ cz”Î`²l%¬ùwXmÕFn“ýú±µ„òq—kjbº¼huÔþøêqª«¥ÎP(‡ Y v¸À¬‘,9#§Yä»zFXúæ5ï Æ±Bä÷Ö$Mö#¢a«ãi2bA¤ûá‚À2Á‰èYpÿdJA¼ïÙ-‚ßþ}q@ŠGüÄ ¶Rì,F¯íŠ1˜.KÌ1¥„æ$•ñFG.`ܼ?UnHÝl‡i]6•:Ç)bDt%í͈âFÒ¬æiÌ ¹,“xq“K0´ÊÇWeQè>>3Y7ºæö¶ÀxIQóQÒF0â&ÙçûÐki¸“‡¹E‹8»è¾ÅÞ³Z/Û—z<áýçéf‘ƒQ:[ÃpµÖ´ì££÷œù÷jŽhû1²˜R̓fqÕ‚>ö—´A}eÖ™žO¯qž¯ä^ÀŠã ~bžÎÔuÕ7@ýBð•Ÿ&цÍá{XK#è| $ò‚¬¬“‚SÉÓñõ?ºÎ#nÄ”Ü%x›iîL'©ó²Ñß\„ì#ògIB{½£[rLÊ]0áµý³=¿¥_¼§=†?&mhÁ2‹£=p+†*$RŠØ’€€»_&úé÷^ÙTðn©Øºqæó³2»aèh·Ó_oÙQ:qÖ/Aa‡ª®ÏÖ/¸ø¿…é£2“~ye£úÊ"V§ºeLωœ™'N©,"0 ¨ÖuvŽFã4±"Ƹ§3Òß9-©J10“f SˆzÕy@ï€thìÞ9pÑÁó»ý•º88Í™{×ICŠÅ¡§ƒ~EeHBÇ@À¢,Bžq ŸüÛ°ÿ?¼!V Éàö§ûr[H6ü-Ažôy'ÒÞó®Rj¦ÍÎêXÖ²¹’œófǤDBM›½sÑÍ«ô“ìÐkWoE[büî­ƒY­ ¯Þ‹)9Y¼Èc7é«è.êu’Ûð¹LÒœ€.£O·]T” I’œe˜C¥H–í?få÷̇ ‚öÒWxñ¤éÂ%‘Œ°äýÍf* b¹YWÇC,É’|­£x==‡þEûýʆ¹¿1 .wW~×ú é9(3ÐÀ±o=zs"ž}Û;"€ÉŸún×ù0Ýy7Ž K»Ãí²ßët*9S_k«_STßVP±ÿRCpÕsïJ«Ùå70O…9aÒ."bi¢Á'¢¤XǾÚx$ÅR%…opøsàd3ƒ–èBÁ¶c·Ý´SZÿBá”19L2Æö­JòQl ßà•»±÷¯D!L¡êüKÔ4yHCJzqòªõíÄúmQï‡{¥É9C‡bl6_=L¥øGliKAxû®ç’›8lÄÎCðÂW2!PÍA"gsÂÖc=›¯È @ŠX2¤b©Dú„3&:Ò³Å$º¾xü!ËLNt%ESªE¤Þü~«ÎÏÁ©†FðíMN z.¶EÁ̘·yô!§Yžè’­»› ŠÛëuÞh.[ÙœÖ){azL׆õó èÌ^ôüG®ûÏ–U&û…N🿼hs†“´*ve‡Ù ÷êâߣLô2žT[»¸`YÔ DÄe°¥¸!\‰¾åïSW§9˜ß ù–(Æ.«ûw3 )Ô=Õ÷œ£>fù‹`1œŽÆÅ$¹6HL¨Ç2¼eWå½M3åØ¼Ø¼Ýå¨B©%‹ç þ­Œ<3"[>šžéÂDÖIg*ð-Õëkt„>8”!¦VbEø~èH v–‚÷÷¼gh _rNÀ¯’€€»„cD$ºpÎQ|5¹G¶…Hg ÜÕ‚6î ‹\“°ø±ÎXäS:< ¨áäL{NaXÝXÔK"õ¨¦V-}` Ë¢7fáÞ9¦¬u1Giå ’*Y?à´‡’òMòУaÞݶÃx2)ˆ _%€/1 ˜›gK(g°&tÁs.·§ÉÜœw±ÛäÓ£,Ÿ»½bhß9áoÞÜ.Ó«iùI÷ð'€énNrTøkÙ»Šƒ!]ký¿ø½xÿXà3I’·¶Ÿ{…/síоšÚ36²Y¥¿ãVi0áò´¾ºÏh;K8Ñ|âiÅwêH¨$¦pk675¶Œ0Dn¨p1‘s÷Y ë-Ùay©EòäÔ<¥¢_sµ£ ½Ë@>îœw³÷ukC¤Î“×uFò4ݸL8M†Ì7Qƒ +\qUé§ûV» ìÝq÷ŒçxŽ:-Ïë®TNxìéñ0Ä‹CÒª;`—C=Ü€©¬J™^½^e ¼ðå‰ö ÿú'—1¢ÃdQ8¹¶ƒªÂfäŠÄý~ït@2“«!›µîp½ž;~ ¹±C#½-Û5ëÃØ{ þÀI•³Ù,a<RÙÛ7:O2Ïg~°ç…F˜UÐÔ6XK´2äƒK¤ ‚ïi2ln_A;VI>VâqñSDÅžúŸ†e%MôÇUª½ÓñœßÊž |ýTá·5v´xt8w´tÀç×*µgš>é€å5A˜Éc‰xãSÔ僿ƒ§#8s’€€µñEHÈìƒÐgìâ°[ƒ\–‹Lì%wþÓtªOEø>SYV›m”®¼#õF…ñ‘W¨,Ÿlß.<ôgŽy‰WŸqÒºØ2]¯—zM#|Š ­/Þ2÷Ä›k!KGÝËA™™øÈh/v••ŠWe@beB·£_’<)9¾ªä ®³Ô´ ºáË‹áh(ćЬ:Æp@o¢õëCGáTâÛ]¦2ÀxJìç?Œú褆‹¤0•¼x[“8WVÂ.äûö ßΫ.ú6Ò°Ù6V«Sý‰˜˜T$’ RÃÎêÝÌ%p_…À2ÚY‚é…yÒ£lcoô¯ CŽq•S,,Ç´kÿa;¬ð"5)¸ Fy¸nøœ[ì&ÍEÒ¸Ww¦Ôµ|ÆÓe,—çìV˜Š…0’©.÷6È…DT_dP꾋€št»;Ò@oñFLõ³vèI”Qbç(J׎æíT][ãÚÈä ç|EpÁƒx…¯?)ŠmÊ–=ê@ÆJ@~àqÝÌH?BcÂŦ³‰éµ E?¥|ß,fhÛToíKM~6}§Y?íGyx¸ñ9¤©‚5Ó|E,Ãögr¤4j6I 0©{³,·‡ ÷…AþêsQß·o-ÎâC!¿ù°á³8~-[5^5ʰ†,Â?/’ºŒá~i¦À\®‚‚·ãî¿óå‚ÀÎ)OsÿlúÉ5£ éW0r÷äÏÂ&n¡“Wº…`¼0IkÂl¤W9J@Å7  H&+ʼn³ Ë“·Y'ÿüeêXžJ´ý‰Ó-³2—·8¿UÏ/]ákï‡ãfóX–ª‹ J…IýͳØë€1»b9%LžÂP)»‘­ÑfØE[¡a‘ ÿphlmêoñr¹"ͦ[®¤yp¾´S\1gA½’l׸fxïSÄx²µû­ÛÛœü›ªˆs÷ø8gÙ–&†kÓ¦f^uUšÌ½šüÛ@ŒHù’€€Î>‚#*—iÛš3­óû“Ȭ NÒ8£‘ TH= %£÷EB^¢(9ƒ|…ëdìÊšÅhâtÁ&Mè”}¶jB0>%>.¡ûƒ”6µ½|sCæóüÒ•´BkUÚLKw5§ØwCdˆK  è5êpá¼jV(rÍÕ“(á9iö dy ¥)GÑL½8&(ñ¡õú×>÷ÞÓªõiMc9úTbÕIÖ‘³¶1F‹#Ÿ€mû0Ë:4nþÑöÌx.íöåGîÌ.ÑÉ„Ëcybæƒîöf ºè„´ÂcAÛ¬¸©¶5Nq“—A”dWÃ@Kü»ö‡ÁD«ü°Ê~ –1Új|í¬÷Í>Qº®iá£Pf´V¥jÇh‹Ð‡ö7S£¶E!º,7AÅoî”±¥$dÜéßYwäBÀ*Ò´IJ8lC,ÜÁ†!/jE—â·îS‰“€ã»6ýÄ…*¯ \q¸ù‘a,¿UÇÀ;Ëûsm¾üãì!ï§[6ÛÚ<ún† ‰¸ØÒÑ÷uÛ$õ±-~,f¦¥åÀ›ì€-èÝÔÓœAYÔ;øÑ”’›i³/ÿ?TTÑß–¡(^-4ÒG]oØ"Ø´†|}Þî!*òáK Û0<3×B¹[]PB«W¸²Ó‡Oý& Éóo!í°@;S9ÂØÍHƒá‹™X×°»©Ú(+¡ì(#sî²;ƒå¸ÁnøŸgGÉHºtV¦‘Ó|•o9‚Š‚²Ê±Ù=ß{¾éݳÈF& ®5à·wO]QÎkÖa¥˜”ò\¢™˜_nN,ƒtH8%áÐkØõiCÇJ-ŽF,º­ &sĨ*Êê½´ó(<ÿ_WêÛuØóÿèºT°µGp½’(j@µÃW<²šOoz8÷µÂ$ju+lœTûÍ=ù¸øhw\ð´E¦ÊvÞbÄú< ûÇä ¬Õ¶» 2étècYOÏž—³¨7­ !#láª-ò±¢LЋ|莻ù¨U!Eƒ Ù滋y¨K¡]h‡Ñ󢚈¹ÊÎhØÁþ ÐàHà¯4BBót—i9(æ›@ç0ÿÆð_+û(;Çdi_' ˜8EÇbË0%fú'D©ˆ¬ÄëÓedœR¯,®šn{ºä•6š’€€ÒäòÜï^²eè0ï2©Ný¿$»¼¯2p³M‹²Lf­AË0”Uf3?]®h^ bEßÙ”÷Ê$:øØB•?’oß_{²€á5|hÌ=ÿ3ÜÒâQNžýï@<ÖÌ&p 1ubýª®&Œ/Žàë:Œ#\™oYgž¯’ÿu‚[Œa:e™Ò ËÇÅ%æÒÝ ¢~ãÛ•ªs:6 –éš~9)EB˜&/eyS!ƒdÓ’&Â`È62¾tOÑë*ç—Ìž²¡±m—·ׇl.qÇM%óâŽFƒ{Á†6ãç´ÌcØ[|¡­âixºþ 4‹Í†?á\º_ ¦"—÷vۣ—í¦~",õPGéX‘£7ÈÁôp¬±T;‰ÞJ?õ z3ÿý7ôf {TÞ(0 y}ÃÛ¶y°[}Ë´, Œ.½QÓ±Dá qD{á™ñ«-Ý£êG{ªA1b™û)hÚ áWé3.ñqœÃ(ÑA¹Ùéï ãíÍ d¥ü—Þ^~R Õ4!â©Ï2¡ôºÕkúS˜RýÑ)ãKp(X'@‚àô± ú½4ÂË\ìDµ×X›þµù,q]°$]u,jsìâ7 1o_¡ŒÄÖaèÚ!! g8át¦tTÿÄUØðÉÜGeùø—»hÉm@_:ȘCÉñ®/!´J*Ùñ¶ °¹…„%gÆ=êɤ¬O8® Þxšâ__^B@ÏçwG™À·íìù9ÕhmYÀø—{•ÚY–¸w‘ø§œòWoIn$ØÖS11 )ÿçjl¼1ô>«ÄùAR^h%ã×û1Œ|줬T­`uëç饾„Þ³5]*ˆ«ÉÚ²»¶°±ÌÝÌlHíáÞ¿LFÛ÷L˜›ôÈ‚ÍïȶàŽ_õE°.UhÀȨPXÝ@Ìö Êó˜á ýªÐÁj=«˜¶cÐÏ 0Ý•Îßs.(µ\£‰¶U³ºÏ$k¬2èï‰é¯Ðy?1Üùåû¦8·´ó«ÊÕã·ˆ³&¿#‹ã™Ìܼ¦ä‚¿ìò\åT›‘w¦*É¢”I~JæHÔÐ×¢úÀ†ª¾H“\Í7å̔؃r´Õ‚‹RЇJ]«5åsÞ¹2·<ÀÑå(N/¶{àG¢îXz”ˆÎa‹Ñ’€€ÆÏà!”¹C­¯›ˆ²—?UwX¹Å𶌽4®ˆy õ?ÅÝòÎáÀ óð²’,SÑu+ ` ÷ċؠ))5…ý1]ªlb5çîZBÙ' ‰ðóÝ¡,­QDœ(D ªŠXLÜ‘Rès³—Al>-Ýè3‡Ÿ ~6Ì\ Y BHiü”5›6e pGá={×Ò=â7XRÆwÄ B3BzRãŒÙLÚ´©BæŽp™¸”ÝN29xôúÇ ÉÛ ÷ÎüéqEÖÒSºÄÏìæS€Zq8Àð©nt™œÚà Qü'¾ÇmÛ~ϧ^€ ¸•ÕW¬6/„…É®}‹.²WÅ’\O$†U.çO7rzìÍ2ØÅÄ.Kÿ.:¯žbß>’„&f°^t„«½ÕÀD„ÌvefÞ^“ Ê_N 5U|ä‘Ê@GI{5Œ«Ÿ?×+²cš'®~&(V#çNÈ `»r×Ìd&4/¶-^¸“zé§hÏ.ÿŒwó>šHÉ•*/~ÿ>³lÒ¢XŒfi±×>_ÛPá1Üxã+;Ù7{¼^WË­¢°‰L}¢~¦Å·2íKzÍÙy¼S _‹WƒoÁ*”¥/¢òæúÊûµÜÌ1,QN6£ÒHga¨fí _DHÁø,+Ào¢mÄˉNô;qýMA±„ÂŒÍDqL˜Ê°)tÖÞŒ5¶ø_Ö¾[uRnˆGr!XBM® 3°T@מ"Mþß=Ì®·Ò«ª¤NF[8‚¼ÃƲCï[nPÕÓIu©è£D‹, Óß¼zò†øSPÀ¿AÙØ^æ”EÍ&§tÎ8¶ Dˆ)=Ï¢Bv±gkTòŠL›Ùû£¡½nNÏ`êVÑÏh¹’£xf¹D5"N 0µŒÐži×j— Ô7 ¯qÀÊ÷ŒP˜gOVE®äþY÷FýM¤Èw¥¼[ð;¹’5ÜÒï4¨¦\ìççóT=Ak™…œ¤+k@€Wv¿ 7ÝØÔÃ"©q-”àäG c‹í¬ -©CqÁç¡('®Ü’ =o/cÄŒfºê8”‚"ªæ²_3‚§Äñ!kƒ§t“Õ;έ=­†¾°Ìöüšn~)’ ŸsM'ýúo<ù‡ AXy?:ñ«’€€ÀMºú_#Ê_Eµ¥Gõ©Ffo$mFx6H ' Ñc Tú¦–_Fìê‚ÀC3Ö.™7ÜïºÌ§3N ¨^Ú"愱/lŹo´Í\—ö ‘zúÚùªOûAU¦Àª(˜/lÑ»eâ@_§öÝJRsò§ß*lÚ_ ÷¡ÇxÞ5YM…èñ ºíúS RKž{yw ÝÓ³Ø_2]…ZíîžDc‹qøÒþ+¡'EN¶íØI¸ßJ!;Žž|øbËAÔÞ%”NYFž–Žœjk—k.* T̬ª¢ …¬3⽕ bÅÖdû®Û’½¥µ¢] _ÐEdb‘åï"oÌ`y¿ƒô`3¯ÏÇZ˜8—¢¦± »è™¹³¿HUO­`÷ø= TÌAqÐÀfœzæ*I‰Œ§~kÐÞ+õõ’‡0fÖÈÅë+³SFÉ5SE¿ßàõvÛ™±£Œ ýíÁÁ Lñ󘂜&Ö4´Kð´ùêc»7ZNÓ*VÑ꟪~>•t…Rº/ûûÕ[Ûv_¬ 4üb¯ÿŽqóúêLxø,Ë@?×X }ïï"ê“kýX¸"ã8¿Û C±_¼¹®7¶ž|ú¨tŠ–ÊIÒ¦Sh.Ë‘%÷†3B³£a•vB[NßNÆ€+z÷ïæ>T,ù»ª†Ù´Øš¦Ð£ÖmÔhŒ0•T>G-sð“…L78•2B†th³jíÌ)JüˆŽ+“Kÿäðö¼ŒD>±/9‡€¸«.Ì6†·l*µÕ±õC¢—à™[#…KÕg±ž"½¼”ËÛ‹ñϳäGDø;¦1ʸÕþ­Î(Ëå§M6;Mƒ5"ê àK°ç²mhW%¥¯Þƒ ûq§MœŽ-ºê$R¼ŽŽÍ5X&ËYÁަ±•ëßSÚŠf„†º’((mü“=ˆ^ ÷)ãgèÒ»$ÒLxÌ”ïȽËÐEW¦™èë]ºÆ'!Nþ!»s!­çÇýN‚¿wcnÐÎÝ\LíF¡$l9>“"/{BBÈ]L§GÞF#$,‡bÛN{A4Œ‰üÈš,{‡Á‰!Zl+Hüs½cb_¿¶»Rw ž‘èpoW±–¹`U Žåçv)ÔÊL½Ê¬Ü½¨–>€Ûvþòp¸ËVÓåžê]ÏSôjZC¶ÝÃÏlð½á'$ ÝínVigm&¡–ggëŠ6…"*p›C9Æ¢Tå­ÇñÑdIÇÆ ÔÂbÄW²&Že4èݬ.¹âì‹rȬ±6@ʼn})Í.Q^æT$ vaKà¦ó´š³ÞçÅ%y}661¢oʦ…„Âê<†i…ˆOçà‘‰©ûTÚ —Ñú‚øÇÓ(ÏâuUµîŽå@¿¶A”->%–o[ÜmÞI$ߦXj¯;‡ÜA­G«çYÐÔ K3ð¡É<®©x&¼>Laõ”mXÇ¥çrð_ª×‹5Å'äLoë¤XÙ[”¬Ž™}ÙPn¦®¡Õ78í·jŸçÊAüÎiÜ9aÏ0R«QSŸ!‡ÖÌÝ“W¤…X5:tta@Œ¹b‚~ÛEöKóús½˜¬–:L¶`¡g:^ƒ1™Fªléœ Íº+f±2°JÛÊÆJ@9ü¸sóÜ}çÃ4âŸ{v›j„ÿÿjÉ·¥/îX!w×™¼t k,':fv‰U=¼ev·uÕúÝß(²ò+î’"”$ˆH>±’¡– ºô¿'½S<·‚FÒéËÙUšiwá³$rØ<ªRÌÉl„ÉšMu‹ÜäèšÐ*µBCçÍOwQx†ñˆâIO Cé§rçòbXÌŠ:ëu}'Ø+2exI-fÕ²‚<«XÕ^ˆ £Þ‡^´5q}ç¯Wžúg[Ö¨NsSîlÖ’:nž~3\Ùn½ÇÛÀp‡§1È% Š'ˆSúvp[K WEóàC…MøÝí¢ ÏA×*ÞâY7Ë0îÌUˆ@€Äsû¹úçXÌA O{ÍÚÈ„X7}óêÍE{Øà(9ûzcßõ¬Â…tü ½®Zõyõx¬ùqE‘iB8Guõ' PËOµf¨ÄÄïBQš´Ÿ(ÝEÛA¼Î*SøígéŸk8Œ6þÁfß©4¼(P†ëU³"Ú¬Þ§…õt€ïkâä~8ÝPpk[4ñF*ŒÒÿÒá¾bö¡*!#/0XÛãFô×€ˆ Iÿ'ß|%IlS\M‡/^†>v½ª%@éF§F±÷Ñ?yAÐÄ÷SAV!û® ¾/Ç›ô…;è0‰3¤úøiiý†… k2^KU(3'÷ÝÐfF<Àâæi‚v“S«|ŒËHèÃ¥VÁô™<+ãºÂÕj_,ž>Y‰à7 Δ|N¦¶„ÒT]û›Ì$I×aK·o ÿ«B°% ö-çæí9]ÙÚ´«v8ý¯¢ خֹ®Üµø ‘±ž?íñ„ǧ:,½Â …5¸N—.f!wË•\Ðj€ $J®ÑõûÀÚãÇ Câh¸°ä}ºD#¤ì½-ÆäÏõv3íZ0Ja’‘g}šÇ|Ô”œn‹‹,öžµ Õ,QA¶)ñŸÈ•ïxW5.‰¹?4¢.z2=¢0;‘òêzIõ>pŸ¯)ÕR:¾è6:-:’€€ãbWª'šò_ˆ¦þÃx2‰ÍÒü±Ñ„ñÙ¨OsäŒæÈ1ßb<}¨Ã Ù>. òŸ)rËvæYâœMø¢\_ªä»Æ[e<è{ÓöJ*¥ß›V>ehaõýh “¡ø¦—éIK1”’®lPX˜ã¯+à'•Ft‡é4‘Û Õ^ÝÆú:˜ÉšRO¥OIëKT;!=L#ÀàÅu¥[YæNð¬r¿ý# ªyä%êiP_õ¨îþdªØÜœG¤; ø1køº=€¿: ±ª"PÇék©3-ÐÛÕ2[ƒAνY¢xp|]›‚¸vžBy³Él¾ì¨þ5 ƒÎãœQ›“ê`Öñ!n. Â#î—îäð«(79 šHÆs­™8" üýf°9µ÷$È´á÷;þ¶šöp×XõÌèôSêÓüžÇ¶©ØT™#{¶~¯é¢þv˜#ì#üµ÷:F+¾o`Rœ¨â{˜vø„dÓÕ¶¶÷¶'¥YS$Xq;˜~ÿÚò»Ðjýzw®ÕÞLüÕˆÄÚÜÌqH1Š¿Rž3/ÿÜFò2Q'Ó×úWXo<³[„d;(gº×‹XìPFùÏœb{Cx%ÌåË?G?3R‚ÐÓ`©NÆPÙõP?#ÞÛ*¶zûU£Öb“‰ì ]!×Ïraó4°—ÂJÇØ©£ÅÂåþÿL ìå0ìÛÞm€-ˆFÇ L+®Vƒ¿ZÔÎèuêO#gñÂh“¬îán¦Éë_˜{Û)(ð¾Z«à Ì($„²øÍý3´ß®=“6áO0·É°‡dªbó%ŽF«áš"èœê‹|Ðý„:ªå¡ïX@—·Q#g\L°û_ ’«xýï<üìX·œƒ"V·‘[õJhvÌ)ubÝ`9Câ…S¶D Tàv«;Žì>?Îģă1²wû ÷üUû yYåšÑÕ %¾èQU•þ¦Ì, üCEÝÒ÷ÄöL1o×½Œð¡Q2ð Dk豺[AT¸1A~ BÏû‘ƒ4Cl-/Á9áÿ;£ˆ=uéÕCIäå¸}+évE,ñ¼áM]ÆrG…DÄר XÏÙÍC³ó…Æ¿Œ|l>zœ¶Üíáyé|²vÞÚál‚6 ]"*¾‘mâº+í4Æç¾[ªcÇ’€€Ä®È­(ˆ²p‚ò¶E¿˜ ˆØJrœ™‘ø¢@'Ùâpá#Å´oEˆEÚÚýørLæ4¢£p7×çr ¡¹Øº\ ¬¯Ê½/Èõ'±`0DFmjž¯ŠP£ƒÿçºÆpX\ž°£6ØG 1¡M5ݬfâܨ'¬úÙQ^¶÷¤ üô»o=”œO¢öZôÿV~GEaЉ5‡œy“ä¸ 5¿è|Zb™®[ùâ¹…weRØ‘krÀ \ÚMxFžŠŒ§óÎaQn¤«D½’ wsñMcº`ßÛ{vl»Üh‹Û‚;É“ˆ:¨¼È8ÕPB6s^=žæ«ò“ŸJ€Ý׎¥ŒK°¸7¼“ÔŸo[5ù¼Œ›c;ö› „b€Ã¥Â_ªH“)œê,/ëØÄSWŸ½á}Pq£à&Ž™*¹öå£ %ÈŒ‘=<=P®OON~AVs‘bkáSA¼_Ýx~û5ìù¢wÝËS? ²ÃÆ;!£}jÐýO„ Í˜ IÝt¼(öÌ”Ê4²$?f мô›½¾4p~½ž)8§V*ô•Ä!ØDj¦<{?"u4+´Ýñr^Z>²e5ðìúˆ³×DtN­¶9}Á€­+„`Û£î[¹²²RE³¤7¾Þ%¸žLNo©=ô²()袊ÜùõGÙ '",'Æ™¡@¾÷??íhÑ£±²N"µ°P×8,«iÙçÿ–´gµÒϰ|løÝìº">ÇÙirÔî¦ ŠŠ‹¾±æ"âÜ©v¬?öÁ€84ƒQ†=)á¾MÖ}ÔJè´a¾&=’ÎZüÏ‚aÐáO§’–aùÌ?MàB>ñ••„ÿK¶iêvË]]š·ãæÁØq³_¢¾Ï¸XvƒVhñ/vçhŠòTê5ê“0½…;?¸¼Š ™½ØÂ¾âJ%þï+?Ä$)y–ŠZ·sÖ«ÆÈ© ëÕÎ}«Ñ–ÉÐ*½Ü<àUf“~¦ 3ÙÜJÛ#ë_ñ2hâÉv‡µƒlçB—* )9ŽU'‚&BÙÜ V»îu§Z ‚¸¨|;h°E ¶Ür•^ã>¸  Çå¡®ª9dlñ”)¼mŸÍÁ¿}²8e~›©;;ØžFqþÄf'Q%D’€€¬òtÞ¥CÍ¡ÞhÁúãÔJtæüépéž/ü½_ ºüŠb´¢„±ÃžmÉNÅÛå¾¾UˆÝ·‘ô¼æÅjûÆáB_#?X²\LÉgÅ)ü›Œ¸â"[äW|Ñk¶¤_whv׈È$*„ŽÎµôxÕDH7¸ŠÃ&°ø­–l~å÷7†Ü(y4±´ø$'§pÿ1ië 4õ[¢óÎ €|$Z—kB Ü²š¶a´¤áy?ŸŒR–Ô©Óç+ÄBj]M-¿¥‰Çæ.¢Ñ*ã¿~‹îñ,±ÁyÇ@k±*ßK®°›€ìH4åŽ*W3˜EŠó ÷ö²#v~öþ-”ªçÍÊXl ^‰»ÔÓ­B@&!À5‰ÙØ8àaœ`O]I?}²ê#>/BqÇÌÿ»®Û ±dÏ¿`ùôd#mê<, +PÖ¶~vÀ}Ncjá3{U-¾#c-´0àuØË[P]ø€`m–G=ûX'ïl+ûÅΕßS,þ£¹½¡mhÖÑÞ¡ÙÄ D_ÕLOÁI[”®@áÞ;åúkõe"m¤Âä>áÇ[ƒ¿x€ …Äá ÑkŸ‡FG4ç'—óØí½BÉ´Â/í *¶FÂÇãÃç ôŽRDŽÙµ½ ym¦<ÆkdÌÛÑ‹Þ2X-À¯C'±ð+”Ó¶XRMèÎ+³ók‡ ÆÄ:õ9+Jlëåƒ?ž¦°2³)±îŠA3¬þ»lÎhX Å5ÔÚÌ7 Äy¡H™ÿZOâ¥ÊØæw²1Œ;rÝÆwos¼W¬º‘AmŸ¥ˆX>«òÐpjÌÛ—†N¨ÿ¶ËÆ.o©‰ëý€5îÐdìÒ®¤~ôÀ¶& ÛÃñßó §–xáÇE3‰ïâÝ 8ŽþXuŸÐcX—Ð/‹—d­¡`ŒÑ¨feß|Cƒs¿óWýA´šB¤&Ó'p8â@ÐåcŠ`‚4éÿk„‹ dÑa©‹pKµž] ö8ÛØÑôÕ°³©î0vÙ\áø”äáM+$&Ó|ˆ1í•Ë%öFP,±iØ.ª‰ÞÎX‡CrTkæ•þ¶ã/ ZúFŸ–!Ç¡°ëF^·ÝS!N6™šèš£š [4T¥tåëEÎEQXR•¤ }Ô´övÀ¥ý„\ECŒr¼Ú „í§rìÞ…/EÇ’€€¥Ö˜ÅÏ)dì¦[Uœ¦4ÖF¾ßH׫JspÑÚ*3'©°VmJ1û4Ó•¤ì¾hvÜ+Ë5O… /{‘+›ELÝ8í+&˨o4Ëi+"ê>u›çn/ŒÅ‹©­¿f0ÁʇôQ:üè**øØ–·:.£µlŽT«Dá`ÞÄÜö?Ú…óÝQiÜ8ÒMä?Ùu¡Sv¸åéxVjÞ@.ßðRóC”<<mÊûbÞ•ËÊ軸1…n±ß?Q‡5(µf1\YL!äÈ(þƺJ^%‘ûºTªGcŽÜòe™¬žðº/ u@«>EþÕ-SŸË9`IÐ!å]g8ø©þˆ`Ñ,0ñ<ŠäØc”¹k5!Ò “? ƒÅ®EןÙå†×2²!KžU¿ .¦ ËlÄ¿!£X<,3¼ú$"IßæY'A]we§¨dΗBL´:òbÏYàåÔãþu40lFð¿¨Û/-ëûÜ¢Ã÷‘‚Ú˜Wº½¼ªÑî§­),åó‡râböšN«¹qP/8»pëw³ÃצÝáæoD´  Ï|Ì>DU♕&º±UÂÞôé¤TEYdfß§s¤X™!fÝ=€„Ķ!N€fÌ5aFæká°²±ºïàÂpS£b å6ÔG£˜E®=ž¸ãtйÐOt[TcQÙ )ëÛÆ²H|™jÇ5ÎñÈ^ijŸt³íˆ¢ad­ö„.ñåªõˆ‹ÜÏ‹®[Çj«ä®ÑE FΡÞµ2Ç9 QL¼ö-C Û!^}&6’qÌåå{S’ ·»ªK'÷,‹O .fÈè¢dê>ÏV'ËÍÚ/¤b{²©ØD¤­×¨±¹ÛÊTJUª@*F4åÈ}Q¦T3éÞCBV\¨+ì\ šÿŽNýr=†õNñ 3ÿg’Ô-#ˆR¾œIDFœ8«whøíg©±Ð× (oÀö´u«_Á„ñ`úŽ@Êàd£Ù×›Râ@ûjD~ÛMó*w*Ìß`Y#”¹”s†ÙöØÖz¯™5¨}‹}©" [Ž—(ÆóÅ×&çãóÐ1Æ!^#xZ?âoß·y…tù(þ0§€ªŒ cèyI ª£yþ" bÍà_%rö[¤ó¼/©èŽØ4P4Fîܹ0kì’€€¾˜0{j²¡«á’Úµ¿ð¢fm$>ÇžÖJËòýÒv¡ä¸>ìÓÑP$ı¬nð'j¡1~&ý9Þ…â9ZfOåÖ ¦ã´G²ý!γD¿¦>Cðûýõ1Zþ•J¾ègcÒÚ…ÒA Öok »¹Óx)ºMÝJ°H2þàöïhšgÍXáN·ÿlüÍf7²ï Mò©&ï›Ý¼›¹Zåþ;” )Ê'<¸ ûºPçáJbI6«n ñâIc8»±_Ëü¥·U85´Wý•'üz '–œ—Ž©<)ÝïÇG“2š²Àí½®ÊžñÏK¶ÚœÉæë4P½ÿ©êéÒs¬%ìÈáå°Ê-y o°ÃókòiJ¸4ÓËί-Ð7<½Óúû·ËåÝUÏ'+:˜q鸼ÿäB‹º+ÒœßçÍNþù—I” õ+ü6I᪽]_Á‘’ÑÌ¢í»Ÿí>WšWÀÓ±y5ÀzÄ«éç —$9Õ—€ˆVO¹—Ï£zI›+Ê…_ÐØM‚”(0ŽšÌÒÓÒ¼r¢¦m'û¶­9ï §%©°Î=µÝWr}:ßÌ Â^ qäÚ¾1‹0]-¾©-­Á¹Š‘.ÜÞ%ôÄz­ÝË¥¤}îü…Á—_>õaøi²ÌºêpîÍ-…tgâŇL6Ñ#rR;¨V_d 3—iùj•SÄO»Ã¬elA‡€¹Yøsü_«SÌ¢ò¡ZøìÁL^Êm§þÄQà„|À̆-ižêï, ëãö|ߦ¡ŸG¼‰eÛü¾Ï.¬­ƒÒu€]¨é—»Ó‘7"#Ak'g/‡Ì;õÃVÅç{¶ »DaÓµMþÙ‚R…žˆ;;¼:i…üŠ÷xÓ,“]œÿ9Ñ /HÙr)C|•€Ã’HR¦ÌÍ•¥Uï·*ˆßæD™Ðx:€-QkÒC„üÐ$þƒlWuÕ‰A`cÛ ¡N¦TŽV]ë—Ç{ Xó¢¾½·AcÆ Ôi²H¶ER?4^¹~ìC±Å[‘í‚ë µ°>S¶»fìÛ@žŒûx™ð¥“{~üލ‹MjA¾}iY‚5:Pø¨` ä‹% ÀGðÆÍ”8kÜnÂoÒ|ÈqcC’€€µ}ëÓ&q ¯Ö<èÙx‡216J©•á¯/Ïüý Ä/­º)r#ɰfïæàïǤžª2U¤Ä­9Ò;ëƒÃìŒø_Ò>}õeP{ÄÔ¦¾ž¶›ÈÀ:&Ù?QxÃ.1 ØyôC5I…âm6ôèÇàG!8ðÝiObEØ0u‰y‡ŽJPm¯§˜Ò´)ÔªÄUd>­°JÕNã*6)B•3IÔ¦UßÊPtFs¡¾ïik[ɼÆ>¬üþ±Œã¶zÒ Ö‚íðU¨•…¼"SZfOÕ‡´úŠç² ßÁÍËù›g ÌE_|<ê@²¾òHB-Èœ˜´µÞSÙLçp:¾,¬Ažq÷ ©¦ndl”?,zبk#§ëæ"NÇ¥¼üWyâ_ìxߦá¨ýÃ^å•¶ò@¿¢o6 š,Ö¯ Ãy”ô¤½|O¾ŒF`z’³pTƘAëyc¯æÇæV«5Šã8ÒàwÍnÙæ/â:«ã/í/’yy†:¥ ™q-, ß0…h,tj4wãÀåƒÄ?Í:צ£? 0º»Ý->ðµ|Y XƒDëe?uübÊ·Ñ'æ7”s6µv|)Óêè£ß9á8+&>»eƒãÅP&1ßlÞ¬ÿY>œÞRxeÍ;¶ßƒ’çÏ˸âÂ#µCÄ‘c·˜CøC=È×UB›wÉF¤¯Mü"/µ +xëj®mÙÀ±$Ï«÷tîXÓÝVÅ› °Œ0×E΄sd GÐðåmÖl”+•Æâ‡ñD¥d|WÝàåJ+ÑŽU»Å%BÂk¬!b„ ì£ÔEçj½û”ÊÕhÅ/‡ë5 $U„,/-ªY-s œl0“gáOÏ_Ñõ99T´—Ä) Ô#CzþA£ç›¢!…7»ÚŠËŠþ”z–lì?íþ‘ nM³“ݲ2«øÜ¿<&îàò{Ï•R]^’€€Êç Áˆ‡­NúyÏT‘ MaÖ¾€¾†™³î“pjåÕß¹‚KG ÑÕåf,œF&7PIŠæMŽéäÏÜç%1Ó«{:öµ%ZÌc@a{דÏâŸÿðäÃŽH!)®«Üv±Jcmóß-ôPyc$`É#ì/;‡aí µ<žIz檥H½”!°·,ãä]çäízÿizÀËGÔL—C_û-~¡¾ŒIC?2NüQLß'ñy³‡$‘?ÞŒ‡£âÿÕ„Ë©‘C«ùUóÎÿzÈ,P3XåUõÄ£&‰kóoÞÌ|@dëFlÅiÛë*¤nwÛ §rÔÕµ,Ð`‹ É¢šÊ Œåe¦ÀŽî®zþƒIä°¯)ÓMi¥|o6ïµ*dÓª)—™ì6à…7$‹]ÉPºø¸½h«]ýùäM¶y­@“˜dv6M Еyo6‚àg-e’Pæ60L†pÐŒ’Cý{ÙÝÉÀ­è(°nJyꉡ³vV€jÖ¢—»ã>ëÕÏ ßM‚ÕúÐbݤÏisÇD¯ ãÜ~V¦ç݃3!UùÛÖM<.lE‡7Ðya`×¶X™½6j¡à(¥a#û?Ú2Ð}ÈD.©L0Þ\ltq ±Qþêsª”ǚ𤳺®kmŸ*â-Øvöôا0%ÂØŸ 0à#ßWÒªY?qœaÔñ;¬P[H £¥^'ÄšÜPÖЉr]þà *ÿ`öŠ+µ~âz§œšîÎ19ûR‘现šBf–à¶Uæ&Ÿ@ɬpöˆXðdbg=ci‡} Iû—µ?úц‡l¾±/‚‚B¼©Òã,×tGîš$`¯£ðöb+5ìã8µ2"ÑôvOÿÓ0báv+†@€šàa"ù‹sz*êŽÎû“oc¸Ô×?ù0­s×l|ÉEwùÒ3l/Œ’«;–hO7$H2f Hì–Õ¡Ê+w3ÈÕú(ï§®ºµåޱÿ;NMªˆ7–,•Œvïð"hí\HQÌR®ØDc>H¸_y:ÞÙÈ¥&%ÍŸÞ¨~ÿêp㣻àzk8u“I¿üh@®YÎ'ĆZ(‹ÒÅÔ†hUÚ ñ—“0+™Ì9ô¾ºN6©ð`a=Û­öWü±óËú¼K*SÕï:.ÕñÜ/¹m¯ë4‡äh:ìó¸/[ÅV©«wÍ~cËjS\¯ïc¢ Vr ©íÏRŒ·‘63±ïsA;o .+9RYs—£­N bŸnÌÿ,±#°´6W`ó–Û^£·—ÇÕj‘Ñ…ÆE'ÂÄ9c|Ï#×g—b‰ijrk*7¶¦XðËô¬ Måä£H|Ž\žÕìÏ~BSx…§º©Ï4và·Ú §½ãÇY™¿S·WCtÍ%±MLü…§ )¹¾ H•Ëæúz„ý¦„òŠî¼pE±4ÃÚˆÄHgó]HÖD"åÉ2Dˆx撱ƺ«z°CË ~¾Qž»QN½¬spß™ÕDnW&yûo§þi`|(çI7PêG¥H">‘;ÑA¦ß¸öˆýa×RŽÂñrI‡ˆrÏ螪 žFe^ѯѫ* L±)ï÷l\k¿ßµc˜¾`»Ô€Ã‰ñ#Ž‹5‰£Û6¬F Þ’€€¾7RбžÃ„0ù4”ƒ§Å‹Aë¬[þsÆÕWÛJ{ª¥²òsô_GÛÆrŽø|ˆÀlLç¦{UÀbb¾>_œìœc¡hÙ»‡øæ¹_½¹©Uçû©:Ã7}tZ¸[_‰n´–¨S‚F>À]ÒùôüZºªÝ*'WàÉeÉCÔ†­ØƒâÚ&^b¹1ÍÎÈ8MöžÅ=Ô#ÇE6´îó)SSƒËüƒA0Aÿ^)öeF\­2âmIŽ{Š#ôl3þ1??×6'fæ<#V»–D²GÄQtQ:;8ÐG- e¡+W¿¶IHb<è¦é÷$å±W:ÚâV/ì “pZz_± ƒæ^)5¢á'º¯Ue˨Cs"¼uˆ³T šÈTvÓÙgKH'a+éê†VË Ñ-)§Ä´“JšêáHpº}½ù@µS@òlÿ4ô‘µé„ŽƒB…ÕZèÂöv>Ü“pÆyNô‰Q÷„q’ï(}¿¤ðžs©¢G,`B^Ñq\®jGO{ƒtìõjéñýìÑÛÞâx›L@¬K AìCÿã7b–瓲 ugUœ˜"T<Ñ®ÁÞír¬·Fã +eJÝ©7GLZÇ6†ˆIØ#$Ts”¯íÞ6ù€p'p§ú`²ÜÔžm{cÌiZ-û|cÍ$Î/w-ã…é;éâ›Àô¾÷sßdðn>1•n?굪¾Š J•Y '}ÝMÑ¥ mjèúY™ŽHžÊs¥ŽõHù¤dcH#I²´æÜ9$,ùàPdÛ¶dšyìN›æ%¿ËF£ß:ôf·ùez'­_<÷:ë¶{r#4ßu‹\ÞßÖ ýŒ÷oï7Œ£ Áw¾>™™ŽÖ¢ÌXÃ1LÉ^¾¦&øÚ/WÇï!x}¸j{¢ÜŠo[ íP·æoØ}݆jûCÝÎ!Òóh+sâ z-? ²¢ÙÉ“J'þÜÙå°çk¾Ó߈éùÆÑÀètØ‘÷ë2'ÂB'û݀õ1Zü'å9µæ„¯b‡¡Î° ^˜‡ru­-¼ ”‡ @øðÛ_{å?5=¡ÂxëUëAxÒ†¸ÐuPE›»t°ÅŠÐlâ;d™I#Â2§Ü3¾ÊÿŽÒA9;Þ&M6õ(ÆAms.ˆõñÛ‡8­VîÐЩr’€€äº&G9Í<à%²»GÏ*×Lý/˜ÚdÀ½qVS‚ei¢!z\zÄÔ÷5?]]£Ð cÝj<åÓžBÅ0é'ÎÏÀÅØÊ´åä.jÕD»ÍýŒ‘ÕqjÏŒã™T+Ê&*茣<'ó|Â,ÿL»¦yW5sc‘ë‚옟÷¼x¿Ï¶¥nİ$êв¹H_ÖÔ•Ã`Sá¨ØG|^ßèHXÞ)&¾H°Á‡pG´‡+ßsÚ0W®Nu¸ÞT ¬ê/à5+QÏØI¤þð¼º%äÔ«=Æ "?̬QZ¨‡FcÄÂ[=LÐ!•ÆpIÍ^ÅƤö°mÚ]2B‰Ò%úÀ’*T N8lÁÂI–“g#£RM@/—mTð¡u{@ÚT¶zOÃðË[•ÐJŸ$ö=&¿µM. "Vá¨Ô3›™/sá’IRðœÃ¶Ÿ9Úúkþ1ìkšï¨~òDפÐ÷ø“©Õ5›Ú½Ÿ:­=ÿúnDRV#‰­˜€¿ÞÁ›–ÁKKf:T4›п‚~ùúîæ‚þLÝŒÈXˆˆv+9>([´rÐí@:Iâ¶^uMh Î1_.õ”†m;yôØøédæ9h»ÒÉJÜ«:3`iÕJPÆ×k.Å<{뎼¸AÍbi¸·ˆ ôìª[Zì×ðî0²Áȇõ¹ÂÒ…Dñoœ™vçáY„ab]šo†R¨¥}n‹– »c3å…cž›ºÇz=cÞéàøO[i ¤-ò c…dÿ÷¶Æ) W…[á"ñú.UÚøÉ ›¶|à0ѽO{Ô¸õ3Ý¢wTï²!ÚÄÜc×>*˜Z 2­û{’€€Ô`t_v¾¡?á[dF±æàÒ'©ôÆ2þgû2°ÇÀAó6ëÇNær¹né MT’Wš‘ÜÓ[¶ÖMñ3!KvƵàÖ¶;±ÿ$é°‹î×ýÔ[RÿÖ2­×9>Xøš!~…§‰Ðä›’Õ¸YH¬ŠÇÝŽ øý¯… ÞcúëbõšcSå)¾k—3$‡ð|“(×lgJáÃF¢Ïb„ÀGü]GòÞSã˜c…§Y0ba*î­3ØüÆé2\e ]:—1/}«Þ›•´ЉÌîàÆ]–#•o‰õÉ£U!Û&a=’69h*Ü‹åÿXÃ)Q…5oÁzuŽK@ƒ+äÆ˜i¢¹òÝÒ|“S3Ͻ$m‹ ê~ƒäSV.8Öh!ýkµ’W^|¼XÑ+UgËh‡˜+©ŒIaò³MŸó†OåíP…`“k™”˜ÇÆQÌ2š >Ž€M³¯îCo«]ÏÏîh9Rô¬4nÚ¾Ö¦Â!Úüxìn‰nŒ!ÞÛ‰Uªë[>3¤Ø‚ug¬;¨‰ÌÒ3›9aJªÈvVÅë!^„SšqOhô.{.0¡u£¼Ôd’KgÛúÎPŸŠÔB­;-¬†LxÑ‹ÛÔÿÝŽ¸©ù•ŽîÛíj tI«‚hí|Ö±÷ŒY†6\M—MI+ S¨ hEdÛ½ë*Ô¤Ot-{lÎ}N¶. àjŸ5VÏI ®åœ.{1sHÚOKOR> v:Ý ìk¬QÚ ¾¹ÁšñZ¥È¨eÒïÄe>Gù¤?ƒ~+?ò¿Û÷åWš(ÛÜP”xÂŒ&#tíÉóÉ5ƒº§Û ±ñ¢ñ ödXœ¡SgÓe{ã«L’–—Ì9Yà½UBŠ‹$/Z€éÅÊHL ž³ÓÙ¼#Ú›‹é¦Æw? RIB1·&ø­§Þã”ÕÏb ŸfYJ\ó “/Ô¢Äò6Žý\j_L) lÞ=æk­ù>‹KãjÎ]šŽGÑ¡­wÁ …Ró*ø«ré½…QEAçW0ñ+L{ç:uÿ»ã™¦^l]G€)ú¾Õny}Ñ]}å"ë*1dz<×ðìÝv¢Žu;µT!s«e*7} w‰Ñ;i÷ÖªÐϬBYìœæ Aœ‰Ç4ª ùq’`G²>À,ãdþ”ºO(*¤’€€àqë1BñÑ(Rÿ€‰¬­ž·™œÙ JÊVºÏWcN¨kLFã<Ôf³›¹*N^ƒŸÝ3Äæ¸Ð3Þ`I6/-tÛšK1¼4nþñ|åNšÑ(uE™'y—)Ý½Âæ<æ:ipèŽÎ:È‘mCCâz8-‘4&–¼RâYPùAÖst‘6Á‰(þ C¯‚`3²Å“¶zÙ¤Ò6†ÂÝx”‡š®Â¤h ÒÂôzŠÖeTµmX µ-º]AÄ‹N Ì7™3M,àô;Õ±Z‘Ø yŸ·c¨»š=q¤>­Bðøç½\VäÐ ÿ_DÊMG hõ€6õtÙ‚Š—æ[†V ¡à¸ì Ÿc¦ç„ Ëåõ®Zm‡¬nNà†í³T¿RöXt;JêFà¦1êÊ¿‘nÎÖHõ#Ü¿Gæ+âÔ¬œÜ…Gí5]½ ;ÑȪí „úú+©|P êC°!L¼@½­¿×*CZ9B§7$b¬æ5SEOF)¨_¥‰¶Ù6Þÿ‡«î²f‰ùC(žæóºr>ª^ïSZˆßû:É\Ý!ô¬*|`ÆLjlMnó6hVç±Ñq$㯇¯žk´mÖ<è&ˆb 0Cü½?çM2ÂK$ð7V­ÞÞɬŸ¶Yûi# ÷¡ìG[QÇ¢ú‘÷‹y¶h”o‡óBÓªÞ¬mã`‘ÿsÖ+G‘“E‡zø^—RrÜ1Eâà¦MÙ+,Ã(û\©bíû½¦«®%_ú%¡½j @õ´îÿôÒ$?¤˜ç ÆØ (¯°¿açEA¡Ãë.Æ=U•Ïax,ÞÆYý2­†x¾Ö‡™èŽGx´K@­¬Ÿq¾Ô´#.po_²mBœ¢„È þn)WìnÓ G ¬šuÜ[„1OE~˜$‚¾^ø)R‚«‘‚>¤ý–Èâ³Tß$¡¬§1Ç\{h«$×ö- "PðÝÝõ [$T=Jk0]ÜÖÿ…-FãÑ[ýX/¹jþ@อE‰S:¦gâß¿ èÏýË4E®«E‰¤vZTyéÊ‹ØóÕÅ# Ù²¹¨:Ž>oh›âèÑwÂâõ[}ÞèX9ć-Õ^Õ'\ÔÿÓ:ßca½"¯âÅÚâ i¦ ü?”o™äz(—p³†¿'{¨ùîÂeÉØ°’€€—±—Ð¥±jîÍõ)VϿ׶cêz—M[(–fmÜ)Í«ìpz?³S«I‹ë: We0*íd:7)š±&î–‡4€G0,õ”GÞ¼m\˜@q9² =œSF^øºÁ«õtº™\fPÂ\Ê<\Ñà§µ¾.ùž7¥+ˆ†½Ä´Û0ã½_9ÁØæwƒGSòÜÚìÑÌW¡ú›r6€Òªäm}Áдô9*KÈšof}×'âÅ`ÐÈû•ïŒZó5N–2·3™ÇŒžuÃq<ô¹1å¬6'¾ÍS‡~—:šxaG4û­¥bN¼T”ƒ€ß]Ìi²v6‹°<±Lÿþ'° ÿbY<\7~#b”Š‚¸¥4TrH¤™«+óQ/#Æ÷~çÐ¥&¯³u_äCy7ÖÁšŽt¦×¬ðЈ‰NäjH$x4 kcÙk÷Ó¹¨–û•e%Ÿ>¹«ÌoAV¦^HëãH»ýΕƒ[‚G×G$â∑7ë,NômPxEÉT+±kß0üW‘®»8µî…°’ùãutñÁaŸÀ°éVZÀÃgÓŸ{Ê2:b~ÿê}ô:Îi~QÀȹ!•Hôª¿k™öœ˜«G¾>]DÆGV›±¶›i„ :ÿO>#µó…êrã'B“§ý¹‘l¡ÈÜU_÷ш†¾À«®-¤€ÖaÛÎ3ÿÕ¯¸éT{¤LÝÂ)(mæXøï_Ä笳—×mxMú.£{E¿b‚‘Ž/v{JAñø)Ä'ÅÙðÎøôÍÀƒ©RåË-K’‚ÛÔÔQy§@ö€¥ÁÓ ¥¿ë-Ÿ$å£p8uþ‡ÁV°O²Ž{Û_È¥yp73óÕWÁVNgšo`Ên^©ë#Óuë 3-'kÿ•LÝ•— Þßáš¹gõxÐIlIr§‹=ÍQ¢žnÍàÁ© >Z¬ý‹¯‰^{͹1‰§Ò*ãë]¦·„ƒ^ù¸7”Ivq»Uåoð˜¸Ñ¾@ZY2‚t¼3Es‰L(E>*uʤHèݳ ÿƒœ.h%0q‡ ßÓRæÊaÕ ×$#º3^–[P·D\y:#ítÂgTþZŠPÓ?wÝoöxåçf¸zýZ»(2ëv-»iF’Bäv›Ÿ·Í\:Ä_xÑöéí¤&C˜Ë’€€Û”QûO2åÃî+/ˆ8²¦Z)Û•œÝ ãž]£¨~sá —üó îD]ÔýÿUÌVK''2ãNuqþ!ž•œóÅÔgöÂ3¥3J%ðØ0Z:tµ‡Gƒ7PÏ^ýFª‡÷R äðÙ«œÍ¶ZÊ3âoRo„h¢éHÑ™Üþè´3¢ë0cu°¦*â"ˆ1+†Ø !@Óô‡²=”?*Œ~\ZPR2áíÒ_‡ÇÝu¡by n’Ül±î"8×¹h¼îivL(%IÖEå¬sg>±éñ?i[æÕ–Äýu*ÒÉüå½çÎÎùÉ?7Qy×`S=áüF°?Vx©† I,b#O˜­AƒC éh†N)?cUêp\  8ê-ûEš9VÜÎ… yœS‹›× ;H]%£t¡yÀÍ=S0éä¢+@h`9#‘Å—«|®…+ïAø ™J VWn æö–ŠÍ4cadÝû&öøg~?­{•ûØ”ôµíÛ•+Â^íÄݬ5…ä92Y‹ó¤¢ùãj´]épòòƒŽ:¤Ú]#áñéÓ€Úq]MΩîÍ-ùQ´¯û«ó[õ a}­°—N©ŸÊãOD”mä9÷q‹E3y˜YsÜC^X–çªh˜#ɺÃK·½È{È ¡\óÐjèt{¿»±OûQqœ¦qt&}’í„w@ñÊ|^-;ÿÌ‚H®~dE~Qìµ4I© ËÖÙÈ'iä`ìˆcË;ÍU…¡ÜÃSŠkÂVJøTÎÄØŒy‚Ç‘‡n lüò›þZP•måËr:*/¼ø8áúäÂrðݵ#‡ÛV[¥Ñƒú'ß«KTPÝ 4æ ‚ï?„Kž”³úŠeEh/fÌvÁÎÜUâí:p!i|†{—/”<Ÿ‚ã·ˆ¢ O³(äÚ•ù#Q §Vtœl›rÄÚ'†(‹§+s³÷j•hÍé)ÄiÝg!½Z©ŽâS€Í. U—©Š‹‹S™ÌïŒ/öA"½ùú2ÎnÌvs;ë^S2¥õ]Æú«UÉå„5-æÁWRö\ Z2]Â7z+RCâIˆÈ“’­ÂQ;Y½éi;¥KýæšÊÆì;SG•Ñi†pŸû£Ãp)Hüg%’øŸØgÖñüÿ "L«Œ’€€Å%$drM‰ï¦Á@)ÛK=XÔ/«)9%nsÒõh–T¾e÷ö±RFý g ‹¸¼S…ÙÖI‚´rr„(ç½IÃâ£/Ÿ‘¹Qyhû¾â=ÛmÏOÌ+ó¾ñº—h|š3na!Ì@–GzVÞáÖñ§pºZ¿[ 9mÇ^Ç”¸ƒ<´7Óö½'x´|úý›‹¨¡ê2¡YÅ!V½Õ-+®Šý“,¯ßŠVº#w×&ÿ†r3C-²0UèÚkä€TöùZÿç'®oE§ç'°’‹b¯ßfðíûÂFZP£EÈ=>™ãì‚¢;•6+š±ˆv¿üÏ TIyY°ŸÝ…6~ÖôšÆÍ§b›®.iÞ!h ”šD% ³wa î0M‚Ï“(ˆZàzì¦Å›¥ Ðê²¾äçå}ÝÓô÷Ÿá Va³=iʽ?¹É=L1—ÔLDÚì‰Á•q@Æ.ÔNÒú=Cq¸)ûYܳ/7HZ«cÚU§ÿÚ° ןç?¨7Â]ùd´Aì¤:ou‡÷‘·…Þ݈ˆ#þîK×ëm7«ËOn`+·|F&3VñVØ&ƒ¥$¢Cˆš‹U÷E5Û!ÁÞä¾¶ß(ü‡3ò®2ý¿ïXûE&®\ÁNãS9µGêÿ‡kº¥^ÏóT³G3ó }L—,yû’¤óQt5J­ñ4Jj‡ëe—8_3ǺP±-Ì´·ë/qúx±ð6^P´£Ý/(£v1è%lw.\³.imï Oz}‘Ý5b‚´¥ à¿Êˆf8ôÞܼX’ffYʤŸËM£H0™õA%Þj›ûlaêFJw;%3§ÈKç:Ï™îÏ~ÐÃUÆÍIw?¬:_ÿWbçéÒz_ûG©oÙPö*r‚ Äßû·Õ8NÂÔÛ4µ;Yæà¤œ[ÒÐ9>f˜dG\;$‹yf³‹R·Êï_xsg§•Ó‹>™‡Ÿ_Á‘ÃsQÞôp—O'o‹ÖÒàmº%¥ÛçqS¸Ö·ñ‡ÏwÇIìXžT@é°[¹ÝÅ Ö©,úθ/‚Ç?;K+bz-i²mùÏï;Û‘óÎ⓪Û©KT#S"gݬ æMM¡Rìw76ÄÉãdz ˜.ФøUòšW2ÈÜ‘.ÚÌÝßFi2@ÝbÅÏŒÇáÝã’€€¾mƒ™MBì µØÜМá³íLyÝÜÌ|ª4Þg¨j:yºG§0HÄrô¡Ýts5ÞÔÎw ×Hœ(JPnñ_ê ÿS˜ƒ¨Ïè!Q÷Ñ„J7LÀ\&‰b¨!·´\]/<; Äâ¸ô­[¹½É9«¨Ì¿Àáw…ô±¬¹>#iü’Ï| d=3̼£A%ÌW¹ïƒ¥X¼ÞÚ¯ ¼~@œn+ûôù³æ}uOyâ;Ó`ñ3Ê]`”§š«³k"¿9&3{GO—¹3$c›¾H `û´ëê*k~&sœÕ6Û€9wÀén–ŽM1³Í CœP¨3±Õ‰ôÛèxž*£aç/ ænÙ"ó\8£lLæP æ±ÍÛü5Í¿×Å,º•”Š VÉ1Ñ:eHØUs¯èƒó¡KÓ=èì³ÌÌî˜$@?¢=÷­Ê€X©âêmtÓ›ó½É¨Î,e^ô\}ëI]«¨ä í¡}%#ЉSê3숮Jž_@-ñÒ2¬ Ê/z‹ÍÏ+Ú²ÅÊïßèJAÝJ,“¹l¥ª78•¼i(¤ÊSyS:ÃÙ¹ÀŽîól*}÷Sqº­dùÈ*¶„È‹L)DšbLá03nVdê”0Œ0ë/’?Þ@úìð•lèáô×C·e´mÏö¯_?³oÆið(ÛBÊ2+{ܳ»-[|2•܈µn ;ëêþ áëÇêðtµG·%‰ôÞ®^N¿ -š…„#»¯Û²Kõjð‡±ZFC¾›È8ò2à ]l–‘'w–" ×þYÂtÀ‰ŽÇ×ñÇÙ~0 ç3ª#!âkÖÆ\½c{/u¾>*ÊVö:i#uÁåáCØ€Öü'÷©Õæ•Õ.|ÎhüÆ¢#ÜÛ'àk-Y Mpu‘¡»81¤z…%Çí|ŸÒB¹w> þUùhÎì¹ÒÝÅ#’m¯‡ü»þ¢Å=e2Ke¤&î\ÓÅšsðG7T\£côïôéØ5ÜÖ˜:7lšåÒu¿3ØÞkGô·VŽâ{8ü¿v…ÑÊT»«³-6¥ÙuÊÕÛ’¬±1 ƒññÝi)Ü]rû:`ÀvŠhšËqM¸¢$ÔŽêt§@s?ã›÷Ç’sÔäï¨I%|v’€€³w /!ñ¹r†ÿþ“P•—ö²1$3®ºÀ‹Ï²Iä‚=Cz‚Þ¹|{á°øQ>÷Æ£ûq|E¸®o¸ÿ-šUèÍ2 YNi>€d¤U|\&ëP¾ ]ÄOG$·h!ZM}7ª€ž >d²ˆ7¢X-fV™÷¹é%uxè[œszHºrwÙ&öAùãÖpŒ0­uu…ŒÔ‚nI [9ë÷5Ñc 1WõzQ4sV½‚÷ÿ‚JÆ6~"{«ŠÓ·K¬ýÑC94 ]í…G1šZœGŽ©ÊbwSÜ¿±Ê9CºäN¹Â¥’F UðFÏOÙݳŽÕŸ¾H°‡©‰û¾üµ¦ü6á†æ™]`+ »}Á¨³œSjvöÏ7¨¢°ÝYC˜‹™¡\ñúP:îón9‹¤Æª«†ó´·ÞÏ™œ) £ÙÒCþœ=¿:RQk—¶³ÙNÖÈ/~khÛ( ˆ þwýl3 eäÂTÀñöÓ_TY=>S’À¸+}â¤å­ñæ>…`ª%A^w½£×ã+¥DbhUÓäiÁ;òú‚†E*YøDÈ Q"ûÑ#åóe=× :*ú¬t:§;@5yåðoŸc™oª0¤'õŒd4å€Í—-¤Õw6¨z»ýDj| »ÉO…çB.•òˆ¨|íÅøPÐ*Öÿ…kð¯#èÈRÓ7­Ç¤ôÝnµ¨Ašm¡ˆ¦ªßnB%ÀjqV€ ·Á1s{PÊ®tƒ#^—êF3 Ѫ*€€ O¶*„—Î%o^ò• ³3ÿ]¸ôx Çš¯Va>P$û”¯Œ;t8XTˆÞÛg£QPÉÁ8Ôª±,äÅ^¯ùÙï@…põ‘K»!$ ÿ”~O§1`i‹{Íïq7LF_iZõãTñ‘}x™Üš]M" £n„­Ñ?<Šè}òû9õû±öö !07Ÿ80ÔõÌÂueó1-èô]…Ò9Yÿ×Ý&¿™3õø£ Atáçƒà½LužhÏ¿˜b`¼?v ®˜û2q…ŸW£™òÏ~VçààÑoHv¸ú2s™ÑUž|ÇÆ¢ÎŽžÓyÑôÏÚ49A{Ò—áuôÒ†hŽÄ9Š`YÀ"‰s·BGàEΚmw½Spæe’ÞQK+ol”QŒ ;y€ÆÁäØa- ³êM»Êð0"`9quo(œ1Sut fûhV•=!²v_}²i·f®SÃŽ·÷ÂÑéœ1‹FñuJæ>˜$ùë.¬‚øëœ‡ÛÈÍÍîz1bTÙ" % EÇî›ù¹¸ì㨥z‘{U8Sÿ‡9§A÷úX°¹ap[ØÝHz¼’_ÇT=—‰i—Ë?©c)ʽ‰LŒmÛ¬ÊëH¢©9T¸ kz8†¬"yY¨(“—çUb êøÔ݉5>f~Ëoš~=òÖ€½9Ž ¬ Ÿmc‹µ±Ý€ú˰ȩm×7a°ã›ÆÌ~2KÕC”:gl,²4»Þ„„Xò#i“kŠÊnû2\Œ©Â—t´“ `„à(î䪈r5”ê s¯_ª·+o5Å)Ad^n»zòf{䵇 ÿšY‘÷JÛ@;ÈéøB´ìë!ªÏet±P¼Võ›ea÷Ü”ûÄ/Pº•&´á€;àÀ9Sð›%ò^›HcRÑL…æ?„ÀHå“6= Ÿ&qXíó¨rköÇ=>Ã~õ?jÂÀ%D*žt&ޡ¡; ±,›…,ny/‡Ì)cæ#šaêr‡JN"Â{×/8øßÊ ¹{ПÃîfê&(ª«.NÚ㦢½Ö¦¾WxV¸ˆÎð/´¯i;–>?·iE3Z* \ S”ßv•TýžÆ‹~øq4Ùtì,‚™SzxËa·®/ŠçÍ™è^Ýwä T ©r~™@7ˆPhYeìñ“‚ƪ–²h EßÁ>¥‡¿Ç#NäÑü{|V Ð1YIJ@÷Øh³>äßc˜ò4-8šœs¨tì$¶Ïó,s×ð|1YwD\¹g.YÄÔ),b{_r|ï¾éÁÿŠ#–J\'ÂÀ2®8» »Ê%ónÓ•Ÿ†(G¼–õí*^8‘¸4qKñW´‘åÄÁðú8]êÐ ¾xC2N!zÑ¿¶›m¸½£åê&f‡YÄ_â(E2Ü0XmÁü¨jã•?g¯‹e_£Î’tçõ±„lC·ÿÒÔv 81 UV­Â óÖFj5}ü=d¼vœÅ•Ûç“^´#%5¥ûà+þ2š&E ×b™¹øŽC‹åtÞóí›5h1îƒÑ–4,. Î4=µH²tÜ#‹¢°þT®â^ØéÁHÍëÔÁT•¤NÚBç†KÔWyZùó*‰Îº‚f—|ƒ›¬)‡]TD-ŒZ §r&m9Ä™.™3æ &ÑÁе2ïc~Ï<‘!;ú¹J5(úËè€ßU±"¾W­­›v,î1Àk÷ÂÓv„šYYÏ$û`eӥРӀyQ ½ïëw"84¨Ÿ8_6WÈíA•o ŸL—,c®é.<˜«tÄzé¿×®ÑIj˜)  ÍÓ<™é`Œ=>B‰* <0ÊÊtY©ÀL`#Ъ#s8q¸-VõÕJLb@™yû=1Þhj:çÒêv¬­Îq5ý ’€€ÃÈç«Pû¨­{!Âñla¶!ÞÎF³‘Ÿýš ”®ÓR¨:LÅš}IaœÖÜ"É~5Û¯ÓÔÜ™r朎nr XZgn¹§î‡¯P,ðXü+¢¾JÙWëd™jÑ6_˜›oKNqM!áïèI<°üÔÞäí5ÌuýÔ‹[Ob|“œÝ´:Mÿx™JñW6K€í—ÞE‘®Ó§bôÙY 7#»æSÓFEB^à· sö…¤"nê)PÜ~×÷OaÛJÕ¿šïÍk– ê0Á'J~‹.ü1ªé&âX ­é΄ޱEî.? w_‰”ØÅØ Ià[·xž›a†ü¾ªà¯ê¤¬ÑëÓ yÇÍvîÑj6 ÿ(„ Šçulð6—6X#O{Î0˜´ß_.7ä6ç¢ê¥„˜Ö½†fCr›ýüëÁÜÐîh<ó>\0zhBÊGÛØ§çB°¥ýµ'Áw%¡ D>!',òWK¶;æä¥¾Öᡱ¹!,åÆìUDÊq@ EŽ´þ;tAÙ¯bó¸Qi ƒÌÔ«ÄLeñ±­ýX".œJPû(Š…ù›Ô&àíä¥üÛÏ×óig—ÉdEƒ—a©ZÞOÊàSFãútTúÐ ~êˆÁ«qÇ“.ËÁç¢&±œìBh¶ý‡â}‡m• Œå*p5¸¯úí´»2\$$(ôêè·¢sn¨÷&_â®T«€9Áþï‰!'L Å´ÜEÿ Ï”þÈül%ƒtÃ,Ýý»Ó€¢Y1¹±µsÜKí`*¿£øóü¯Åâñ­îÐå@Ú¬`@Ñâ§#¯'õ®ó;Çp¼{~£²'OϰU†Å m¤œ»­¢t]6DyÎ…Õœì+-·aýÜ>MÕñ *PðÜÎlZž×-eöÀ™œ˜N“R¿š¾C±ãä3¸;ý£÷¿í·ÑdãHÝžò8>Ûß ˜&oñ|ýS,î’€€¤¤ïFeã Æ,%ñ?Ce&D<àù² I½\(Mt6 rG?©ò‰Ôïö›ÿÑÚ9$}7J Îì{·Ä¸Ñ[±T™+˜…÷­2 „ ø/z-8²G§&½þ7Î[ëyð†c®&FeÛ¼ÜS°zcë&ÀGÝÁΆÝà£P6(l¨F̶šà ü‡Ww8´³ÎoÔµ±Î¦ü7~PaHxS›¼Í@ÿ›äÜ=üHºŠÊrn)h êo~i¬ÃOÌsYe/¢‡—¤Qtn"Íé_P~Ú¨® áÿ¬¶YæVøf{ÿO‡”qÚªµËüG^MÉÖÛV²›Þÿø€fp .Û„ú­[2œI+ÿ•zØOPe x;­‰EÈÂý‰ã*Ƶ c b„XUö¦B¹ë†R6„z©HyÝÄ~%éðRB~{²±W.1‡“°ÃN e fÉ@ØÓÂãКäü˜\E. £¹ð°ˆïÒêäÔš5Õäî‡=—øüYÓ›3ˆaðuKdÓ¥c«Gk‚mô9 q$zµc?cÄ£·46Þ±S`àiT½û¥ð+áI9®ùƒüjÑý‡ˆVÏa@zz6Þî¤ù¤¸ ½f2³?ufý!A²ˆ2¤å™UÒ [‚¤©«B”5qóJ´ãcZË“2ûšÖ­£°U¡ÿæ[ƒ&·àtqDöAÇxÁ×éê&>ã¨g9“ÈAãëBö­CˆÛÞg§ ^:ó½¢§s]"žÒêgPÝﻜ}E³š°Ï°VN’à۽䓎çáRÓR”²¬Ãµo5S=3{/)iáÀñŠ9ÛCt×9¬çU¥áÿ 9ì• ñg¤ädfÄØ=ÕÃÀE'¶³¡Ã7¼Kf­FxïâÆ®MÁx ù0aª•¯Dh#D¼tÉA7::Ãü·§@•ôR¾a´:óï+OXÇÑprv&ä+„¯˜y="«ž¨VHXÒ×d¦¸·c4öRi{ŸsW:'öp8%ß' @¾   âðë"tT¥É]%ÿ{IWKJ®Z^6š÷ŽAj=½úFæC¬Å ^Ë{Ž«"%dt3MíˆMòˆp¦(^ïw饦Ò»\ÜSé÷yK´QäÑ·„Oõ Ëéû™‰4¬E¥z®âÆ©bQ”ÕM9ž@¨;…ˆð.jïš } RZ²&¸=LÞ‘¢¯õKñuÓ}’€€¯9s3fp’ZBŽwýŸ t±*/ýO>(D GAÐ{#2u»î³¡×ò”/Ý—AaÎ… ¨©3 )M‡‡X-¶,ŠýУÝËòX¦á .‡¸Ø‘¿-þ ü‘‰ 墠QðHÂÂÉò—zV1õ¹…Dq9ü<¢ø0 ¹ÌÎòa—Ð…ÐËÅ‚k_f‘žg©6ìA“q}É$›è4óa ó•ï¹Èù†М “{.ÚÎtø$ÂŸÕ 2P¨·…êA¥ÅíØâñ´ãŽ!XöL”(€8¯¼ŽXµ5À°ß7®B׳nºkñý™èÿÏ0œ+V6¬˜|œ˜Ëç›Ô§÷Ÿ¶m Òm«§á¼ò3—ôKÐVô·„È>¡ ×Fk Ý8Æv6ȶ'Ù#ðÕA×{¸â`Ç4ƒ$¾àû ¼bªü@nB»úYkÍ7}^‰ °;-ß}*M¥è-ļ¼½÷º?é²ãZÅ" Õ!édý_?æ…Èu •lnà²ÝVZ×âëŽN‡û…K”P® üiAk¿²o¤R¬@àÏ£&Hº)y¾¬NøÓàØ1ˆ''µË›‹Mo$‘Ó ð•<ë1.«r¾.w×t“ £`5-£Q°$ÊÈo§OX,FñAõê;¹ñå0‰£ÿMß݇Ò;óêÁ³Q·n¾¦¾Ÿ‹ÕŽ4W L–íàðj:†¡¥ã€ÎÜZ­Ô*ìꨩѷ½L•¡Ôì—ÇgèWnIérQXD¶öž@âÂpÏ=ÌÏFC‹Æ¹IpWäϸø5)wÄQLÎv°’rH¿Õ•Ö¥ªkɶcøh®ômŸAjÃvÉ`§èÝö¥á/wï cÏoyûÃ{ç ÚvOf®ÜgÍÁù>kcc=âè/(ï@@›§’où#_Ñ3@aŒµ‘ºæ$þÑX-·)W¢áŸ ÍÆÁ(ÈïhÖ.»Ÿš‡¾kZ¶¢+v,ˆ‰¢0Øê²Ì¨9'ûN/n $”‡å)Ô!)’ظt&®® žGé[¾D+D~r‚ÂW|*n7’faŒ>±N¥5ceæ&rÒ‚^€Eqc’ã‹Jsi ¥õTpË£^ªÏ¿  NºŸ–¾~pbµÆêï*Ç@Ûè­Èž5c¸ÎÒ«ÿïá ù’ø’€€ÃN‚§ÇqãfNU% £ð*“/ÄÙ“<Üvád€öûšGóf|ÄÊû5‡Àк>¯5 ŸLÉØ'Ÿ…LKÙsöæüxI>Ff*Yí^y p»Ó¥·ÿü_v`Ζ‚Ñx~qç›w¾—Ê…àÆ¸ék\¨¹o‡¼Û›¿U€ü!YŸõ<ÿ†b€cõD›¾AçÕ*ü°gkåH(•aú¹"¬=¼qCB4õÞ“w´bW„‚wѵ ¤>â݈,kžB ¿r¸(+ôRУñ àÁI‘-7 ù|à®)rÊgã c»‘̪B±ðïÌ àu™iÔ‰¸LÀàïP%=îÈ» ˆùòÄÂRILí´,z à+ÖÑ´Üã„LH'´gZn›õ3ÈòRí-éYÏ¥ž,q z7”:o¢ð¬ÄÇcôÞäYŠZPà-£P¬®±KÞ<ÕÀË‚Xdìº>@¦ªd½ Î`vSöþj£YË×ârÑJ7UW±:®yDhJ-*68ø¦¢""Á‡UKÒ{œÙñÒ¨+c*) &Q5_¼¥¡C]2üø˜ ”¾Æ¿JÙWìësxYdň—5iO§#™ìy@Ì4“ÀÝÑcÜZ-VNrhÁïsƒ'Á„\€›Úyö‚L3S®âå¸'€:¡óÒ£$G,Òº¼¬úyZ+[[ëu?…¨ê"ÛãcA!î)œÈ¥Õ~·Ùô·á›”§ø–pƯ0¿õ;j©°ô§ÓhG_ˆÙóh¿‘âNFrl¹<Ì﯊XbÞi¨÷ˆçNH<«$PîSPß|Ü«æZ¡õZ* àb¶2¶f1‰Øëm„÷™úð³` ¨P!×ÍÈ9ä½ÿÇŸÐæ fÃ#Â4ŒqÔ¶ÌU t.°£ˆ<7Xêeôã5‚»ˆoÕ–¨Þ3E¨;MsôißÝ?|wkŒ-{ß=Um•h¬z†|¼ü‰¢˜ï¹Úhæû#%„fç™Ôɉ(&1× ¢GÓYâªj²±+ÀèqPë­5ÆÅ†ÁM5ÿƒÙB§HK’€€ªèO Çê–«±¢hÇwºŸû³®'”’A_6eeÐ×)ÄxW);É_šAÍ3ODºƒ‹ûµÞÒ§¥Ñþø1“çƒÙpÝ+™ê¿Ð6TäÑŠýsc}‚‹/ƒº©ì–Òt·Î±¼÷¬gdPŽÉûŽdÑÆ|‚ÀV©¥Àn¼>~×Î\L>'²H•ðlÛû\FJ0HljæÙëp—B'¹%#x1Iµ³^ûcY¡HÎÈD­CÍŸHÜoÆéÖLÚa¼ôFm J‚³¤ªïNÂÐÖ9}ñ…4û#¥C ¬Ì9'ÒÑ”úè.âh©—*æ~˜$.ƒ­— êWQÈzßL1m´ÌCï·³·l``-þq2d»—báQ,R¾ÅGÂO²MÍ„rV1CCxVËúFs¶Uë¸(ˆ‹áA¨/ùÞß’Â'n%hÎM®á?÷¡Š¾rh¡ÔÛ¡î>ò̇áËmno`ýÔ¶ÆÞ“u9³Þfjø‹`†¤Ð*üJôw2´gþŠìļ•û¶¬.† /ñ×èGÞ`š£]16»ÕÈ/ ³pø.õëùt¤¶ºrT–õ̱‘€\Ž3o.™"éâ‘bVž 1Þ½—D¨+æžZ –̺F«Üm¨,/Ñn`|iÙgìà¬y¹Ç¹zñ^FHê[hÄs4ÑQMã C+ÌÌ•1Ri°œ í€ª8´w«•ÝóDé²ï8-ýKå]‡"¨Í™v@ز¥!,±©JèÈn6Ü£/‹]â+EϯÒì06I B…{T0ò¸Zƒ¤c:FÞXAµSŸWÒ=Ë_BÒEz¿¹M9òÇ[é)±µÆú$ M¶™è0ûEÓÀ²J«r޲èé/Bkb^2‚tF¬…IJ`ŠLJ©úEüÅn*'ä®ÍíKU/ï™øà÷ÖtÜäÀ"õýRËT9ô#ÓEÈ àÒÕ´S-´RÑo‹Zß—&¶íbUsÿç.ÝëËL-„¦íjÿPo\0ÛCÏîåE3SÑ~9…18y øç±÷‘µãy.]³1ÿ$–ßâÏ]eø¬__p"`A‡á>çôh§Uõ:"Pç›îÒz_`¢'FØÒ¸èH€ÎÒ|˜•¹]R ¾šû¢ôšnÊ…óÓ.Áðáˆîí…ªÝ3‰Ôé ÆXƒb®’€€ßÒ%$›^Ðr¤¬à-êòNä#%ud.‘­ö¾ç婼üû”ˆB᾿/÷$©Ó8C™uVÉhƒ’™¸þÙ‰Ýõ` 'º®^^R£½¶Àb¢ËŠ1à©Ç™ƒù¥«b’NTˆÔYˆùbÆr Îï:'QÂý£å9 õN]¹ÈQ7ö¦1Zóì#= sz³dCYÐR²/°'•êg8›þÕ'ŠuºöBX,{˜a剷'Ä#™Ä¥áL8PÑA˜Ù±˜GFܼ™ÏŒõ„©³?¢*T_|ù²N/aX¤-±øê‰žïLê XxfÓÿFÜçaÿˆÆˆu{ÌÇÊ:49Aþ°¹ÖpC=z1—£ìŸõß± =z`›’ßÙx¨c!-Í/LFÃãivÞ03Õþ;é¸Uôrq‰ÜK,¨×QM].`–D¼Í½p¸s0æ8-Þ-¸ÝÏºŽª§{ÕŽ·k Ú°i^ÈsIà»d×qÕ6½˜ö£@ãt,Ä”­.o ?5ñ—–7oVkŽZZ(–eUA÷> l7,”e¼HdHŠ~‹™2Y-üÚ·ò`“@&³þÅõVÄ^½üßl"ïçtíú±Ýz®ŒÅb ›2l‰ogs·/ÎmR@}ˆ#1û)P`þgè‡?¡ Œ§ó'³ã±üAÍq€‚WktW F }QîLÜ#=Q£8výšóœzX¼•H–€¸­M €Èl,¾Qb™‰“†ŒBtØ.…µÌØH‰lJXÒÿQ¯¨6o`(È#XŽàYØ,†™ŸNõHµ:Œ:‘—"ô“K@“"{Imúh`RÙã$Sòdþ·Öôóöúç·Úö ¯µAÀ_uQj܃3¡±ï àÄÇ•0ˆKf¬¤-½BÛÑ5ÀÔ„n&6ù ªéÑ+ùõ‹­ž¶G&ƒ•^p/Ÿyç¼==eMtPµ½çˆKÚEygþkgIo°ø¯›â¹ N ×F´º€èý‹Cèî’„^œ´sP5òÈ-Úò»ð=°ûθWÓ»ÔÙ÷¾Ì¬nÀ˜‡œÎ!ˆmò9$Y&‡¿ûPqNÒú{^?‰rÌz §™ÐÔÁÀRá\Užm$݇™4Þ¸{›ª¼Eš7X(˜ *A.|;˜7¿Â€@Ú×Ô8nj†R>4’€€¿Ò Þ2míW(1c ä4Ó˜ªŒy¹‘Ò ½OÛ’Kù~ÊÊlé‚úçðï m™ÃÓ¶]W¾ë–Ê<:—àtû@õ2¢ïØôü®tÂÌ.ð ÿ²¯;¾$k®fâmŠœô¾µÅ Ó䦲¢‹Ìš¡Î·z˜¥`WÂŽ8­Ø Y>}yVu×ÿ»ŒÆ&ô=vCš7{>;½Öù‚h Ð¥Ú½8ÐfwˆÉò% ê}[6pÑ}åÀçË<“áGcG‚˜ìh ¿ß/B¬¦& U†È'›ºgBgW‡9õ„½z(ZªO 3ÉKÛ6+g9‘ñ1Òê™ua­"µ¨ÃÆ¿Ìe»3‚ÔRó·ßAbª˜Èå#!ÛjÐêO )bá0nç1ñª\^œý³1gaöÙ\àÒBL(ú6½zôט}â´çøu´æ… ºð†Êc’…U‚Sº3™·iW~³-æ%ÇðŸ")4wn ÀÃà±ßúì©ÍÎæZ]£^÷”û j ‚{’ hÙ[±ÿÕß Ýœì;eÏJªhMjÀ&sÑÂIIl|šØ¦í‘ª¶Ÿ×fO€±_¿ª›œÅÙžo0/ZjÝ¢’oÁG!»?úÓ­ò ¡”#qêê(TyŸ>r³“(8Û D°í!¼ÿ¼ïcœ{òêÂ÷3«¦²²e..Z™î¾<ýC@8zò´Ñ:Ã:QÄ€ï£K çmÚ@5äÑYô,{u’â\ºxÐÿm[+ ´(%êxÓ]¥7Cq¾e±ïÐh”Ø& S)~¹„ò¹¿K”ôT˜°® ½kÇ„t$5#n J»UÏXÒÙäÙ òµjfç9ÌîC3“%Xxº ¢ŒY7 /ÔvË;D‡æ÷WQpf^%à廑çðwŒ®¨À'›DQ£eXV!ª{qRsù>{\SW|t¿b ±ò"*¼{øÿJ~Ñ2î{åÓ[„(v!þ¤ Ã.ôÔòµ*š5ÏDç$ìy1’s³Å°RÔ=ÃÜÒ³Ny\ayf’’‚B—™_ aZ;ÓÄÐ[Ã>‰*ŸÚa½JÞÃòµ÷þäNPÁlSÑwãÖ:µx¿‹stݱQž#ÐUbôìžþyð<°J“pn^ÖʼÝr &çú”I’åÏÁûv{$H‚c’€€Îýû «Vi#żé*©èÝP=‘ä F]Ø ´ ¿˜è‹JìªÆÞ(R;o‘Åýoå,â{®¼€Íw÷ªç4/™!É(.fÙ>ÚÌþ ² ¸uá0*sD§ÂX Óñ¯í†7ÚZ?½º‡ÃÐ-¸¿Ïœ^ £d>^Cú/¥Áäœ^¸1îJœü*zú‹·@Ê帙êSðOy gÅ*¿²J)%9¥ÃÄu£4·z-N>Ëàó#*GèêlÎ˨ÊQ‘¯q‘pN‹u–ï$‡é7šŸÛ),, ·c;QÁe†6?§s©œ‹ÖÏÛð¨n R/M½›nkIË,¥*ÂŽ JÒO@tÅb°·=[ÃéqñÔÛþì’mÓÆ²Àõ—Aå%!{QƒMÖ‰·MB¹ËÚæ+Ðà 5çá§ý¤ÓX"ºjˆ2n ÎÎaƒ.Ò8}´ÓNó¥1<'¸¼Ü$Ž›ó A„Ù1šÚ½”·ñ“yOî'øŠˆ¶þ«¡$Írp‘ƒy‰úÄ>J׋ÓÚ‡ÚšÀÉ=Ä¢ŸiR1ò=#~î–WÎ3¢º»•*4-myyV/I/ÈXxúUóm…"Oæ(hm[°S_Y‹ŠÌÁO‘¢ u$ÔÍWÑt^peî03& ]è-éLõ^€B¨ÂËJá§õ|ŸÍø¼$|x¥í 9TZü…p½›]°ß1J¡[)ýjÂ¥EEßÌ´™•š˜z:½EÇÀ›ã\DÇŠ9qòévƒŒ©îÌ cïœÿ/|8*tíPG>¡Z® ’ƒM?^éä«q¾/nÏñ ˆóÿΉäµ_0wœI)­A&xA Ó5Õ ·[ðpýB,ÊxüpBÿTJŸ/ú¨lûøMÞžÔéH?QH7>2îþä)þeþ›œª_K¶Ç ˜©Ü—Kc»S•2Ù7ܶ۳›|ɽlƹž~^³_h*ô¥2°„gf1õì9×4ÐíŠ^÷ŒèFE`·ºî¡ åÉÿ3 iÏåyl³Ð³b©ÉšéÇÝQhýVX¦×u¦m!¿w™•:C'a¶;\GÅAȽOx‰Mz»Âó̽ß?àÆa£ÜzÎéÔ89¡ §»Söœá$®cgë) ŒÑyo:ögú-Y(™ÄyX¸¨íYJÃÉ’€€ Y#U!ZLþ>©Ç85Ã9‘œ¬‰¾YsnT<½å«CY|>§í+Y p(ŸH¦?_é}OoUFˆ-×é 8ßåàŠÓ>ð/ê˜þq¼ífåi ¡A4K·NUȤ{$"½ûÉ—@EÏš^m×±ÌIÞûúSXvÃ7¾´ÎûküB%†ÁÉ^`@£Þº¬­q˧IG‹®º83‘IÞ=qÈ—6}2eÒš·ñò80jš²‡×M¼ýÛ–¬ø¡Põƒ JÕÄ@UOêp¯ÙŸzLrÿ¼ÝH<1ñL³–±|o¤pW¼Ì$åΜ^I~øí)º–CˆR^L¶X‰Ž”`ùë»Ðe‰­Œžsá(x@,‘¬Ù#Ͷp›ð ؘšuôÕ§û_"êÈ0ÄÞbnw¹ŒËð„Qt¢Ô7U®dzr‚?®©êÏaû÷ÿ/þ˜dôÒb®ŒäO(GB¥{ˆ9RF$&Ÿ¥5Â-a/ý¢PXOAö°Së¥4a¾Þq/ßôÕ×x$HôÒµÛÒr¶î4ûvjÍ8ïÄ8¤­ ãäî¦3X®Ô`,ëTZ(ÑÆöy‡µîbç±\FUì‚®ïîÅçIå5Wˆ™NÉg§kÌél¬¼ÄÅóo•ð Cä)ÝP{‘!ý} ©ãw/"é¯ÓKêzçT2†òzÁÓÞ‚Ëh-¨DŠøU»ù¯xO`‰=ãEðDâ°¡u²e—W£ A{p}“N0Ð+|n>Sè‘û fÿ¶\cZ0_AóÒ´ùû”ÕÖxëÖIÜë6•ûñ‹2L…š %7A73y?A”ôocœE§)¢òsÐMРKž$,ŠÛ‘Á¿`Q-)™ØI°NÁ¿§á$©Už˜jŸ †mò®ë‘+ã³¹/œö2g틯Ï#¡ä¹&¼¦Àö÷ûtÁ‰>Àª& žS6M“rgP¹òM.îï>äúÕÀeÅÀ¢·I8xç@#D•=òãÏÈ<‹¥5•4ým$“y&„ùÓ„›!´ 9O›Üá¦oyqXt1hÄËIÏÁ9Åü÷Ü>$cBt&oˆk¿(_æ¾É¯H49÷Y]»RaA‹¯íu™‘Óë®WÏ¡¾=)Ûžµ°`”+¶ˆx本å3DŒy0“/­•d»†UÛŠØk›kLþ†TÎe’€€Ò*›‰ÐòÑôí¢ñDêÄÇŸD³8u¦"³Fû‚T *í(/~]q^æÓäyüˆI¦·‹ÐØhLkó9†Þ¾*¨(%¤‡cÊÉLU|ŽËô¢iÕpoé.³ÃîÙôû©¤ZÆ_61«*!³âÕªaw~…ìgIÿeXé-£î|¹¶.Ès1´Õ+*Øü4}ÊZSc 8=‘¬‰ªÚÃËE*VÅ¿kŧ÷<crxˆ6Fgf\@ÿ÷Ÿ*4VŠøb c™ÑRa9:“¦ÌÆUEˆ÷ÈÖÒhs ŠÕÓW‡<Ì>ÃoôtIiôg ´rjTÝG´¢Îû¶bðGÂ{§Íhx]E÷•à3XÊ„»¢s™Ø¡Oõ!иžÁ'Jrº¬f6°¾Óñ ©Z;x¹æîxÏö"F ‘_B|,šØëøŒG2ÂÕÄ7ÍõSJC¯ Öú‹ñ…Ù×>Dæ‚4òÈT;s±×˜Ðyý- d‘ø ÚĨGT#ÝÆ¢f±ƒNÔ»Øóanwj,]n«±Ù"*Hª6Øû®yÛ÷¡ƒ~)|÷ôi®-Ìôá(•J7e» MÃÄ&”ãp¢TÙ[Š¿¡Ó÷èaŠ”á@š4_D–Ì•0€¯b(¡ûºëkÖ·ãR’<&TõšZt3©¨{«á,ùï5ØIvžÀI¸€²Â§¬:£ ¹¯Z¸ÓãPeä.“ŽÖ“ö (ì«™Sšsÿ#Yð…èÛî’ êöþ¥ˆÍ%p/%:LK>P÷ÁÞ‘ÇßÌ[ùÔi/·ñÍNúP½ÊýRÒ8ÍR+<"¬%²­á Åv -_¹Èÿê §m¥]ùàêæ*:³”°ô „ u ¤ü¿nùß>½/ù>(y¥ðŸ^k#Nã¶Ó¨ò:å¦[CH…=,ò¹ùí ½PmHêòΡK=ÝUYmr÷5¸ˆ×®sY]QŒïYåÈÈ/,kûh‚}<ßȳñ»¼îœÞöÕõ 4B‚?V½›<«ûðV& vgj\MXlðP‚ÚÎHèÝø¸´õ#Á¸cçÉkâ´xo@èE<Ë‘3¹BÕlºnÖØù,{Á Z‰‘PÿÑ4ù¾¬660 :Ýjäßõ>¥d”ëBòCƵY=*÷æ#‰ÇS¸=ºU†™iDóA}ý¨Í·7·’€€Å€|ŸßNj´À3ê4yŠ…·T³Áñ¡ç"ˆðX£ïŒxáæÊ*dËWÕÓWYõåMG÷&:ËD2†g‘@̓ôj”sø…¨1–Ö`˜Œ„¼„@µ}G.(&ݰ`6ï6,­ÿu ‚xõøþø\iÕŒU¬éó3ú»ÁkšK„û'’0Ð=ä`^ûÒ¡µÆìÓg“Ò©Ví‚KWõXõ>“¨­z¢f]’¥A€¡7"î\¤Dá¼\ÀMƒX8“m%tå| S| {¸²b¤pXög¤<Û‚<(y\y |S‚opE°™#Ì$r™ã©›Ì¸É ¨@ýåœÇB˜èžà ”ðVÂBé´< û˰h+X°r'‘'´iÿÀtϦv>e\…BŠwÄ Õ“¸åtº)ßêhàH“HÐ:%1`êð ;ÏÃñ§ÕÉ{MæôAãâ2¦ƒ¦ï˃ö“". ü+WgC$öÓæÏ‚ëðÚW×ÞÅ7 58H9çµ¼Iß2ÒÕŸ3H'[°ïÇ"¬†UV›ì Û‘Øz^'õ5Ѥš¹)©í%<~³Îiº°‰Ò^(h-Ù >™ÔvwçîÅ~FmÎåÂ;¶²y¾ôúVyM©µù´0ø£áÒÝj˜<3¦ýS3Éä ½HûÀçý$µþï×ýþ㘩KçÛFám^Áœ‰£ZŒWVƒî7§Ëc¢8ä±]„ØNlÄ<4‘Y¿åýwzê¾°¼{e¨Áíb \ˆš7 PZî$êÃD¶ò}óó¿\mŒŽ1ýzd¿õM¥ê¤n²”¢Ârí „Ö2 à²z|³Ç-%âÐÌ®Øp•Å} Y*ËGEÂVíù|Ž– ¢ ,Ý»âW©ntcq;E:™àÒ:Vú8@ ÉLBuÆxÖÄáêÙrö¬z£ê·Q™ÉMEW½µÍ_Âü\µª–•¤ ýApÁ§¯2oŠé)?9‘_ƒçñ‡GŒìAx—zýö)®ZjÆ ÍJÔýué|¼j;,;n ]Ž#ýt¶z“ÈÁ¶r‡_ ÑÚÆ7†d*tD{„²<™ßOP‹”‹ÜÉsËv}èyMÝD¤{UUœ£eöç>V@|h2‚þ¬‚ ’€€¡ÈÅn£´×˜uhà",1S'BˉY‰PÿÐÎóûŸ\£¹@KÃДÄÇÔ3ëÕ“Ñ¢‹Ö-W|ó8ûKœxâŠËþûùqbî¿TÐdøµ”}&·Øô\%á'ÐòiAÏ{Ÿñ¿{FPŠ¢yI °%2’x%¾å¹ùÍÚBÓg6,€ DP_œ 5êDúéŠðÃÞÓ\0t± âóè³V5`èÓhfK€P$/€ÁÓGÉC¶Á ±ü=\ÉÇùk¯¹E7й‰l‘åW)GHirɃUå Pè¢AçnI¢"ÃR1aõ¯a—>@ÞÀzÌlZÄë?PÙM9aö]cØœ›1tʗˇ<í Ý4o=Õ|º®§|7ä¨\_˜ý&æ£ÎJ7/‚¨|ßßß)X¨Å—¹¸:='V…žk®‘TšèŽj(Ìd›æ©gÅ3F¥¹h±—¯pDjúv墔r1g*qÞ’€€À_~~*œqR!q7‡~’•±IûX(o8Q%µD~4ÆK|~['t\}I ÿC_§5ÄÑ 6ÛfIè™oÁÀ›ºÚ†7ÒC£`>ü2Ód•¥ Ò=Sç0§­8ºaè¤8¾q„©”FuÁI×ÏW–á¡åøiòò~ñMw™[™^ù#]Ÿ…¨”Õœc]˜&±G}r;À´áNÜá¸7Þ&tpÑ ,h=äüÄ^£‘ýr L%¡Ìo0óêì2°î4zù34_yæn{­—Cû¹ÄoºNôõGH?oPø~ЀˆÌœƒêƒ.ÜÓ”aƒWî,v¼‡íuÉéÜxÑýI“ÏVë’è\^@­lq7dxSWG® ÊSbdSW¨ôtïÖôà}'ZÆi,K¢Ž…nãòÈõ9€Òþ„f_«É aèŽòSóƒJG-vF;9[y-}1ç!PÑßa˵±í2ðòu‚¹h6j~D¨°­j7¬ ¤[sIüö„ØÍskŽã}ñ€‡Æ|¤5ÐàÙReKŒÜPîä݃„k6ÈzÜà³+xp#ÔQbq%M-!ëq*÷P+æÆ]¥ÃiÓÕ’œ½ö™gUƒß^»›¹³yÆÛiŽËøE/BXæßôÞ/“ HXäsiƒ G$$³Úˆ-Šk*®pŸ•ÖWñQ2úþ@>ª~âGý'34höÞ²6JŽŠ]“×1uV;%÷›2‚?bÅ!íÝ_—¸½¸$ïlô ΟÖgï!>ñì Æø"bímfgVPþJõ&SŒÆÛœÉEõë>zúîô¬éܯ{÷ûÖLÏœ¸Ç]œã uÅ Ê ßøïè‘ßãžL I"³¨áÎË`¶ÐØhf QT3šâzTïrÇkêâ§Çpý!Ù˼¹žeÏÑ64Du+ç´±X®v’€€ÏÑ8Z^mÏþž$ÿHØMªàK†­T’ˆÒ¸VÞ5ÛèyTÍCW­U¨ŽP*ÇÜ3#ÃaÖEÞ¡£únÙ'¤§(Ô«lÈ.j^_7 Y<Ù¸,"nOVåNoóÒ¥,;Pý¼ç„ø›=yÀuµÎø÷ñˆ¡v®Å h„X5Ë:iʱˆžÁˆ +‘ÿ(­8šxîóN—fݽ0‰Õˆ}¯^d‰Fµß¤äþñˆU)•/Ts¤¦‚°­Ã$§æÙ|y¶cY<¡ƒ»¸¢`vìåðs'‰xjjá }t¸wŒ“hbª¶×ÇÜ“ý(vt ÒH²LämYÛ–( ˜•ì¤×taÉdr´7v²6šä~Ùäê‡oç–D-¶Uòfá܈NO†©ËÇI1‹â_çÔdóY'ÚÛ²ÖÇCŠ«T/Ç Ébaô/{ø­.ƒmc %%ÍžÅwn_ýÅ~}åÇvÊ—•À²(¶ „Œ¿î}\¸Mc"BiC, ž/zÕ’¬ÂÆù•.þv¤+ÓxBCÑþ•~Û猗'îq¯ø]<îÄ 1=¹&2݆wO¶OÆ Òð¤O©^˜Ͻ¢Åi†z¢Øncm¡ilÂÏ$óô¡”^S¾ý9ƒ;ÐiY“þ€ipðÉ¥VŽFng<&it\¨WfnÌe#gsÂSäð¼ýÍÞåBúþ‘4Þ ¹Tí.,ýKßC],?õÉwëŠ<‰¢@F†,#(D2!xL<‘ð}˜/Ú+n÷t—«h>3È:U߯@äps./3çÙÛ®9cr~êРî„:¹W™E,4øy~kf",t¢`N:¿xaÆÂ#euob굚銄œ‘Åu’ê™#DݳÀ!¿¾M‹g¯ŠéË]îñ±ØJaV„e0 <¢›A9%7°l©/ðkõ?áKB‡Œnñ5Øá5á'a>Û¸‹¾E—š‹n1FÒÔµ?N¬Í0âKL,€¶8QпǨK^µ²cØÖÍ9åê/EñVãi®3Q’€€œÛN¼ç?[ÛÜ&J´wÚ·m°¦Õ àpE‚M™@Ó™‡”×}ÍYªKJ¼Ïö …Ý2®<ËJú7¨íÉDêi‚âM·ð°fÜÔ·»îÇÄò³¥Ñ|¹“Ù¦5Ä«‰oPÚ'Š,ÿ£ùÏ1_ÇÚ–ª¾‹¡qQ‰Üâî&úš3ùgÆHó¿Õ͵ ?»ú™'ÚpS'Ìé @¨É|“åQuªsGRä%„g‹÷¾1¹Ð]VW2¹‡Hèk55îßdÕ³)µÆ+V¸ÓpB±ÔËÆÙÜ¿û•bý¼ ÕÓ¿nf<Ö"ÕÞQÒµ‰ ²åQ&yI¹àÞ• vú<Õç>—¢´#J£W/\âbéÒîוîÙÎãí ŒV²c€ ¿ù8è•z.=h%‘\ö·´Ç`#!‡Ù†cª@S ¬Oªë$UŒÙmªËÅV7ÜçE”›WÔ]Ÿ,À‰FÎã°ó°… æ¤Q{ÏGJlʇ&Ú™„„-úýÿ îM¦J&™ìÈ“¢Û¼ëÞX—GÝL„òðp&u³vàx qþîL$•6³í<é̪Ïf9™·Ûø©æBÂzêhZW]}qÖx‰vÎY™í’<"fZT·©8닼D•Ÿ¼±‘ÑCkåc¢„/ÝãY ãUI’#X™¥ÉË:JYÃ7~sÅ@­-øBu®æŽ®¹›% Û bĨkc=’Óµ0ˆÛTm»³§N•Ç%ôRP0Jkâ{tä„ÁÀ† å®ûËììmlX¬c5œã¶,ef‡Ö;šÕ/õÒ’K‘‹æ2E›»e]uבt¢ßðdU›nW™mÅ–x!ï϶M€O›ëÝËÛ–ÊÊ£ÌÕDÙ€˜=#ÀM&Õò¶µ‹Ü†ê+¯—.–ÛH“T`qL¦pÐJÆü¼5Ä„ÎÇ ¹¸³]p$’1Š,¶Z]‚–lþW×§@ÍŸƒÑ}¼þî3I¸ÙþæÚL+Õ»—–³êõÁõ´#sá«wäüûc¼ûUi}î®)M|‹jsZ£Øs5úˆdÓÖ7 ³ L¼g#×9T])$otðMd³n‚©¤×¸Ï×0Cy óö²/÷¥ë5÷À¯éÊ•(*%¨ÌëšH¦~8Šd7zQ„–ƒ“«Z&û& _é$„v;ø#¯„’€€¿yQ%¸×,¯™vÍÿ‘¡ß ±oµ¼sÔ§zЋ}ôØðÅJ%_ŒÇz†c¡pã™Y5‹u‘„ˆlXÜÀó(vÍ–ð|«Á†šb]éL”CæÍ¡1»LYInÂ.ôèJd!]2¥µhâ¡3nšÍlÝNÒØB‰L伦ön –%.%þ"úá5U{®’6;6TOA²íXd !اTMx߉¹° B(VPj¿¢_j¬%&]þv9ß6ÝÏ]´ÝU÷÷T£–é…—|ø X€˜Ud:—«hŒ³¥îH u £Â•1cYùFŽ;Åe Õ-Ê›VáÓ]Á¢{8ËÿÕì,{g¨£Ad,·3g*¶O‡ J_Xš{øsú !צËümóƒbg˜òr†te°”Nõdÿ›WöB]÷í^ƒÓC4¾‘ƒþ»cÀiª|ZÁ!oÿ&50˜^«k–õÇHÖ*/#6[ªmvÖÞîºTwn¥ZÄ\X[_x0\l|–ÿ[ص_ÌRnï[?¾¢>±?9mæ|P ÚÙ›“ºB['[ߪߎ¯ë6‹6Þ¸JŸZýDáhfjȨ¶Ð,êÈÔðÐ…·¦…’'E’žÁëC´ã§‘pšîÛ ‚}ü.Ïø¬d0‰"@‡0hQ"`HóuàîP©QíÛ+3èÖ(£*H÷hu+ôïpŽØÜ'’ó<õ64ï/~ä5Üà^âDEs‚ãb)<.^)€|Ó?·ò×*èhî/ሠôÇÇ9«Ýäݺ "“ Ø"9áŒguÚô¸„ó¹öpNuµõlFˆÕÌ$p¾Þ“9Îw‹ôø„fKCø³¤âm¶5=Å—YÝI,<ÖwáT ¹àŽDå<³Êºƒ“8¨X¨jz¬h¥·‡™‰3®@•RXl™ÓF1QO—TŸ¿Ø¯@f~BQò`ûf`”†™Ì¢V›QŒØ‘AŽè)º¶:hµäømù±äS“ðéÀœË[˜€ªÒ’¿3ì·¹ªÁlÉòæ•óΞ®J“Ž.ð×UÄ/-Ðg<ÃiýQqFN6£[I¼ª8eHÑä%°†Øþ§×Xœúí`¤â>Ýw5J“‰såKÐ+#Ó!6»õT?_ †‘˜”æÖªÁkj†’€€àLò‘ I^©)f«?:òqô‘–£Ä/3Ùµ‡êE½<}î~¹@ÞüV†cÕ0Ž3Ð^¥04¯Û£&IHÙBäù¬ª BÇ÷I(9 4œ["ÜLY?=œƒy wWJ„ aáoÜö2wÕØ£¬?ÛýøñŒ‰©™ž–Ð`̾sØÕÈÍî«ÜŒô¸•ð™ ¬"`t»ˆ³€â0Í~Ä´“ÝíH™kDã¹ÉBg˜Ø«#êe“‹†\ E~q”Š"ÅÌèàq}%Ô”Ì0uÉ%«ÙzƒO>xšk7b ¤²ÀÂsB.F„ël-ÙI“áQßq•â=åFÐY´ÁrÆ+ÎrÏ¡(ù¸ù‚LQM gØëœ"Ùóý®Pa^8·dGÞ Ù¶ì§ù@?ÓµqKb £þ7Zö«<"åSûB4wþÝ÷ÂxÜ1:²g¬¯ŒˆˆUå•1ë/-¾ìŸÊ?`§¥ˆ>2†åÐÂk™/³ü:=§Xy€ò8 _&9 \(ûÒ% Q‡Á9H1g<=M®VsÄõI®óžŽLÊ ¦H €Ea‹™Ù@¡,¾"íW^”ÌA^BÏ*án:? þ=ÒD„õ­­Ê®q4Fe$wêΦ–³,ÅèÌ:=̯&îøH5n‡÷Îî›ã§pf–¡udQú4š¬xÇÎ=Z%ÐDGõfÿ>Û>®yÕn5ÆŒg*Øùg+}UŠàë ñ0"jFè~™“̬ʢ#ZPpèN¶t-H´ö1ê‘R¶áPÂÔd&ül6ÓNoÚ;‹b:õ®RÞ‹ñ Ì•ÒL"{ïb–Oe™ò[ùH$éCóƒ܃ÜÇ{ö3zwmNÎæàå_ ¸1ý±),IBF¾ß {H¹ƒñ’€€÷ÉþG­Ô¢³™×³êœÕ[ˆG‡?ô[u?/ ©¾0ªi¿(°õÐ@rÌW”ìæâ/¡0)·Ê_ÕÏqbwxL¦JÕЂÈ8[ xÊþêëܪËv /Éhx”c+ ›R®ÑÈËsï ô»ÄQ³†N·êA¢Ïв›ì}ºËíúЇk*Ý/4Iâ3¦It[Wùè÷d÷Ÿg0©‹*Í}ãñ7óÚbê2Tð/ZÀCüHSfÑRn'7r½ôo’ì¾òã¥ò™gIà4¯w.ck_(ëý)Ý€/¢–é>±Ï·¼Z:NÂ@¡çάz@™?¹­û7f«U|ÈSÃî¤òR2­K—©bš’&•ϘnÆç7¾ä·O1I¾6ŒZ#ÆòÕ›UgÇYÂUví§+!'„*ÿÍÓ¿ X˜/5¯‰‡”ô\âúMí´ÍÁ¸òktç®"¶d°lB¬/ä ®íQˆŽ]4œ¿c¡89*ûà 3ýô×âèân+GnýCÈ}âSð±N‰© á Hù¯¢n‘¬Ú~ŒàËè0jxh!׃«Ï ’€€×þÐöÛAŠD¤ÁNS=;…ò_7›þö>"ƒì«÷N,QJÐc}@ùq¯Ún§wÄÉ­ ðÜOÏ$¡J6ÓŸu™þNººÚmsàfäMMùÖ¹y¤pÈ畞:Ò$6Sþù`AÖ÷¹çŽ „Šœ“»U¢}‘AäîAàξ¿ùý+‘à@¸‡Ú)b„:7ðÔg„¡ýæúe™²öËÍÞ5¨¦Háí¢µ”, y¨Ž‘Ô±mEEy×¥$é»õ2¢ôè -‹XOæI9ͧzl[i%±s=†¼[h߯7 ô_ë^”ĸÆQ7RBbÔMg§&¨œˆâ% 4†lŽ ^r~tŸ®®ä¼ÒB~ë,7|xŽì¾lö©²5Hî@!©Óº¨ gþëŠ_õˆîw+ºØ9$òç&wuåKºM ªPT·š¾ý<»x€HY™Õ¢x³Ó4Yû TbÀ#r2Ê"ø˜†î!Òçq›è|ÁÂzZN“–¨ƒon£È¦¬†Ù†4¥£êÆ'˜•dÓ¨Q&ƒ=ã[Cv÷îÓÀ³† ]bn TxTB¯;sêŸí­«ÿ—«_¦¼JÔûly \®Z+½¬º±¶BQÄÅfV"´Ð^‹‘r5!8F'¿tRúyko%^«ô,×[1ýÀÁìõE€A¯Îˆ5hÛüC¿cJ޵sÐÊ^†-MïÅf$5ä·µ™…C}5ÒŠg“àcu’!)â¬L¬WÄ~¤ã_ÐIýq”Ýÿq†ž†+ z"E›PÓBU޽ß½ä¦úœç‹‘Z9—9Õ®ùÖ€­D^®<¤èY]„NãâoV+à˜9ÇË‹lîÉ+c9½Olïø)*,¼t”b©tÙ£–Ž©r6ŒÙ˜È'@[?±!èÂXxû:GšøŸããažWƒ¡‡›ß§ãÈNÇó= ¼Xô.øeSè+D '4<9õ’®\€RrÀ|²»¸3®`ÕHÒµ› ~ŸdfF¶ƒ'¶”w”Ï‘¥Oº$ï¤K®Î§Ø4Ïz˜\—4WDSOœb¤Ì^Õß\²xDq‘>j­¬ówsâ<šº\£•&¿þòVYãâ2ËXNðÌò@‚r)GJ"åhUH ¡»ƒ~ªë ’7šè'œ’€€¯&чzƒJùÙPqô`ºµ Ø÷3Œãº3¦„‡xªˆârnX%‹M;-º7B„l3Ç Ôú¿šŒb{î*fXN^ú Šgïú{l·ì`ò–F¥’;âÿ»¨&éñáÇuÒfIm×>‰É*“6€î©ÀèØúF|äi4mnr\ôyÁèmYÏé7íGò5œèDæf!Ñ»´'æq&;×â‘ÀtÒ× Öt>®§fݺƒûkUrC/•K¾Ç ä#ã"ò ‹Ø‡‘¡,^½¿óˆeç~XùØ£1ŠžœLG0û ³,õX›@ùŸ38é÷ĨeY§÷–+Íqû‡Ð%Пªn+Q&®·ÒŒÌÔP& cõ?¶aÝ… ÖÁNñN—ŠÝcö}Ësw x¹t­ÛgzžbôUFµAöe1@Uv¯k P ³(VÎ]¨îœ* ‹å–èRÏAD<²àTi—µ³2”P-Z‘å.5­ŽÿØ_²{;¤˜ë xƱ‹Ã‹•Ó~œT]$år­S ž4ifnêí øÙ›ø¯F%rìs–J0§t«—©–é¢Ã’P‹Â:RȺ­Ï5tzróÃZWÀÒ"™kÖj¢¬`ˆ½ýfšàî»88Å9†þ‚½îÛ*ñjFÓòO(±5ÉÛ›{å1îMb‘÷uç.ùêܲÇöç}»êE%ä/5Wï/×`øYŒáEÊØa(¤º•Af‹ƒüˆ üø Œ`ÛÕݤü3\‰€^ïGLE¢þ‹-õS]_0A\ ¶OÉÓb¥ƒ¾(ÙaÒÔYÜÀ¯GAHôaÒ>¬›Ã¢Õ̜РÌï¶w¡Ì̘?àMƒzb’ÓØLij·;OBf‰'pÝ| d°‰u¾¯â@A6Ó¦|áÖ‰ƒ|Lܯˆ‘÷TÇžt,ê ›øw3ÌÕ;¾XÊ?ò÷¿Àˆ s TyAKMýÄ jsPÏPÞ‚6K¦Õƒ*uŽ7ÒŒš••u}(ྠ&þw3 ŸðñÙDZÍå/ž–ýedM­çˆãØéëÁ¨Á(?ì¿giEè ÂóWítß/?ÇÂF)g³FAm½ÔºÐO£Á2äœõºªb‰€B,ÕJ.|}çvº'ÏÕïaŸg;袦Gl ¨R’€€ÍϾÁñL¬À¸R )¨Ö¤Ù¶‚•"2·]Æ×©€_T&r~ÛóÉùASY8UQ‹1(ö_'‚ß¶g§¼‚bL‘°ÒðDüLœ »fÐôG{}=èjP°ì9yywõút[ròåºÇåÓ¯½× ]§ºâ¢X¦ð™}mÿü±"ÀÕÉ4·¾¥‡ð”Œ¯Æ]½ õ¬Þ¬RL²ê`¶O/ªŽ—43Ð÷'HÒhg×pFåkVþ›Ý^Òæôy"'­ÆÐº L5ÁJÕ×4x:ú_ªËÓÛÌñc.‘Md†DC¢D>³Ô›U*Y)˜(e«S+N¤%E@1V6mÿjºh—is‹¡òàÌÜ%¨’c-j£Ú!âÇ%Æqm2ÿãýçýÛn¬œñž’ ^YfmV ß#iå¾dK™÷}uÛ®!œâãÙ²Îí ǺÏ@%€ ÌxpŸ…J)¬+›­º%pÌÏáµM$aÙþ¥Ë–©)çËͨ¦ûaYǽU/ã¢FЪqhú|äÃ[#ª3¾æTãIªB’ê´ìÃñRµ$n®ÀÎ>gQ«¾Y!9ÃîX1)Ô #Ûž8Q¼£Î–êº>*Oøº£`¡Cògg<÷a(ôDQƒã¹Ÿ¢ ^ûÉøŒ‹rkç`l“$Dµ¦"˜‹÷ù›Äï•ëâ’îáãÜÆfìÀö¦Îr<\¶ºšÌÇS{gÿE°<Ë+£ótQ—ïÒӥɨ‡Á &t&ikŒ‡@¼~°Õå œc:õìÄ‡ÂÆÍè@ù__ Q]Dø¹Xm[Ú«·¥=è¥؇õ4ÛÐ)ŒŠ¿BHå»;Ò}Óàâq°)Õ¸ã"n >&º’ØtZ Ȱٻg؆¼=o«!tà‘Ú%¸^´aî®o¶„‘_ç©ÛÊÌ~I½ÒÓŒ£.j`1Kn–5é;ˆ9›[;ÛnN™RŸLyì zJ@„ïþº|€]ë‰*@*tAž‘I+üÛ‹å~zO—îØÖ3pøƒºÉQ"!䄺§±ÆÆáàùM.JÎå ’rí"‚/ð»#¦‹çãzvF ‚ƒ¹m’oöù ;óa+B}¸k9< zï¼ß/ti´_[p=W»’“_¿¸ÎØvAmæÏ$ÎCK“)>ú€Ï«fASð™!’€€È³'š‰¦(¥9GÁvùn¢7V~ëažY ¡/5Œë¼W˜Ž9ëudCµýGî¨ï±ÚgåÒ¢­aÉnX\õ¾Û¼KiŒlƤÏíšãKaæ×ä”܈µ6M»eÛ‚¡Žj‚ÄwâåKHô5·t$ªÅV4âÏž}Ò&ëŠ?wS­R"Xú±{L²Ú=¿ø§þã…ž‰ˆ™&VS”ÜN™äƒ‰ˆTáv ‘*$heÞ”çvº$Lü|u»n{“˜èž!VO×PEÏ4˜²ÝûšÓ.ýXjéK.M…P¨ãÎ\cj†ëK =Â^:‘ꯖ¼ðÌôh9ù¹Lay™Ï¶¶Ó[™ÿd²KìçÈ€ž ¦òçH¾O·|–U) ñ~Õ±_I‚#ßÏ8”N[ŽÑX¿,öçJý쯰ՆŽÞ¼§ïP¦½¶å'îù̃yÕoäÔBAßo×÷(PÍ›rìŸSk›"ä÷ìU)6f4e쵤bæª.'Ša{e—wH÷Á‡´›ADÜv÷g*“ãú¥ÛS¹«š­Jið2ݦA0"מ]û¡ãVI·+á_èÞþNßé\Ÿ…5oôž²ÿôH&âßSBôüÙÎÖn 6^•”ôöj(wW^0xH£Ë¦>½rõ#Þe¥ùä¦Ô6K´çÍAµcç+Ëãßñ¡¨ûs@‡››žªâ²/Þ¦XVsz˜Òs›¿·VîE,*ºóª½À^Ó—kÅ©s$¥’é/Éõ«\:˜‘TC!õs5MYÝöÑ›Yžùj3*ãÎcT2zE‘‡Z´HHeÑ—Iã>æÌŸÍ;âQb²‰P1äTœ13çd¦†‘êÇÊy›èæ±fu °IÊNJ#W5h޵úï b‰Õ8ÓJpÁý9/”ÖM£MDõÞ&úÁL\ÿW»dJùR<"—I¬Øq'ôð4¾‡"ÓúµEèGÅøFÔsc´ö9z÷±_s@E‹Ì`‘¦h2©å¯Òam0’I•̨d,‚G2142Ü j¤¤Ÿb!¯¬àmgOÁÞ†‘^3"”zéݲfØ27:èpáÿxYÁž'íJ>¾®ŒúQ™‚}²«’€€¿-–f¤¾àºÖé+ƒ“Þá✽õufèuÿzëBê‹ bIò„oÎÅŽJÔ‚€ÍGÓ sÝ£MR¥™ÝàN¢´Ët?qÈ©³¤ÅŽþ´ê¨ {VÃì×*¹šc^ìŠ?ÖdìŸçºzáíªÛ >ÚlÀÅ•¼2²>¹†PòºN—vٌӊõ@öÞ‹<œ¨÷›¨ômFÚóSR³Ÿþšß¾ce™—r÷\+œF]@:A¡¹°¬Í[†˜LA ôhI¬ÐN“ÉØJÍC|ÔüP¨q݈-\.#úC‰Cz¦×¬/®få<˜” 'sŽ{.ÝZ¨™ðÑãA™aßÕ‹Ø•/c\ ØzºK…Ù‘4ª•P'§£Œ¦Žôí°T5瞎œ…þ®b± c(ÿWit& L½ÀQJRŸE¦m`,qz4Äú]ªTSãeõ·G-/ð×ÝÍÍmìÉAcþñ‡õÑì‹5â”ñyäp®¸+ËزUß¶J¤}Zuhµ:PÕ ¿kŠÇé­&y3*)ÝãXé]!¦¾‚¥M†.Vÿ“+ê™ Û%q— RÃêM1ÿ` ×Ë9ŒL o7Vcп„óž£e'¢=\3rh„Ÿ®HBV?¸¦q2qØÉþULÄï­€/¢øçÆÜ-¨÷ûÅ~¯Žû¼ÎèfI«m΢՚¯}A ̓ÇF•OŸægîÌ«! žì1Ò°ÐÍI8€uA‚5§gš˜ä€kò¢[ˆ¦ÏP ²l¶Ñ2Æ=¸21Yu¡Æ+ý·HÄÎ/B‚ïÅÐì®}AìÔ LOS1V›²b”Bu[z+1Ÿ³|Tý?îŸÞú2[ SfÙðëH ¶Êá‡xcÿV=ë*ßPÌÉôX WÒÑ'Ú½‘õ6-†›°Û³šØ%¶]š»"%°Rº(’€€ÆÅiּ䭊x6â”"­ìªÚ˜A ñœnÌ_Þ´ØrUiÇôDŽåzóVPBí2Œb<¶á&µžÈE?œÈ,£z#±†€½¤C‰æ/~ñ ®*10·à¬…‰¯5ï³aãÝ*b”K³³ò0ŠÈ9¦—üep0ñ•qËPÁKدf¯ßH7ã’4žÎ ÜEŸ@@°{yîð1zš¼ÈX9ÏyÞ³Ÿ¾mœ“[÷òš¹- LUÚµNÁÁ¶Æv¾hS|2Ѫöë_ú¿ù f*ýh…_d1¥‡e,«0 ,uðm‹ƒ>—80údo¦Z‘ÛouìBßg×Z,´¤b0#µ1TlßpÁ„ŽFÂUu/¸õ˜Ò#¡¶sUò^#Ìg)iʈŒÐÿõN«[¼ÿ¾î¥|'$NY=ôed%Lÿx†ðŒJˆ÷ÊT­{`£úáÏYq°xZBÀ2)Ù3¨E3Zu£F«k ºëDO×Ì }½2'GŠjÀ½õ˜Ã»O'¦ü_ ’»øWŸ@/êìÑÇb ôKbW„‰ç9+ƒâ2‰Ü>§ÑY”œ9ªn Ç·,LhNÊO®¡ýׄÍýpa-¥¨}üá ~ª†$ý’±Yꮪv2³¨UÿM:s3ƫċô ‰*K`T: Áp½.g6o/Òp¶M+Ì~ò‰¤×ã¯ç€Àʧ£{ÎN/Éø1±©þ˜ÊQu™ZÄ,ä´¾MÔ¨ Dtb˨«‚X’2bð³iau¼°ÙÛÑŠ‚–†L0@ª¶j •Õ/ž¨rß6˜•kDûÈBNó]·*ú¬lWbvA’€€±ð€€·~>ö®ÙbXÜÇçš,ŽæQ€©Ü x8Vé»TqÄRà!½R–íŸjw¶w;ñrp[Âý3rÕ5Û»9,DÆ\¸¬y?¸q–™®øÕêí¡vcúù£~Iø'3 pæ~F?t{{5“Ä{üRmu§CÝnÈŸÕ¶ÄàìKï0¹“¨¬ )ƒûªµ©”Ƀ©Õ ãƒ÷~6—Û’dÛÐDS·ùÍYŒ.µœÛº@ ,F~r ´ç„Þ¤AÄÚÕßpþÙÖ×U³éN“n›†èS°Â{¤PþâÀ÷i­píÇ¡þ4S~µDé¶y´š T*hV¢ÇKƒSÆåÖÿºðÑÆÝášeô‡ï݆‰Ú«%$"Ô¥-»"…Žê I|Nsõùø á^÷YRBû_õ)í.0ø´œªXƒ#ŽqxAª×8𮫻“Šy# ˜šoÑÏ&„5™­òX.ñïm„â,1 Gù ¢bvFU¹ZO ûûÐGÎkÐzÇÄNÕ7èð¥¼e–O Î<ð.8AXºTQNŠÞif‚ž3×€}Óòií‹ÿ7ìd£3™¿&­1Au*^ƒ¼=f¬+ýu¾Ê6{a¸~ãÉ‹ù ޲Þé#ξïMŠýæ„:”ÄÛJÏÑé‘Y ç •‘Y¾§n±ZL Å\q9ÐëdÑ/é¿ÊÝsçoäÔhÖºç î'ŸVwH.$¡ÓbÛ¥”ÄY’G·è%ÙYšÑM[x}Tïl(ø-à«‚ç'7DÊ•„›^ÇýR©5_4ä¾A¦ó4zÑúeL¡ýQ`>Ñ6Ù ÃpŽ˜î·ûåôÍôÁúYÚÃÿðTŠÒ–¯t@¾Ä¶r@Ù„E'ÙÌ·q°ß¿_¦JòÙׂÎëd?ŒÜÆÕŒº™‘Ï€ <±nÔí>&šŽHFw¥Šöæ>ðÏàfLV&ÃÝ%ÊÚÛKUpŠåãºo5Âx= ¦ß+ÌæªÀ¶vËY§ñÚ>ÚÁŠ>¬{ð'”¬“ðîHufþi ö÷Tò߇ ï¹Ä¯ªâÕ›¥¯Ýa0è±Uê0pû|‡5èà™ŽdêD6ÄÈõA|ž ”óhérA"4q.R¤O5£žöøù¨êIÍBÐï1Z<âU¢vXQ’€€·áë¤<qÍYZx©lšÄîä{áO–ȼ¾¡Df<‡ ?ë½Ä¸Õ÷;Ù(œÝÒ‹r¿A3c7b?ØãÍÆ»Áj –ºÃ÷^’¶o†¹:“„;”‘8=€òC]Ó8‹ˆXì×úŽFµî"€|þ½ƒç ƒ¶š­ßÚø0 õfä®âG9@0ëÛ¯þo²së»/#RGtuÖA¯*ûLçð¯¢#Y@Ï‚ˆøsÄØ&t?©èÀ¿Dz6©ˆ.BÑt¨²AÆÝ ùv°]úI®ñ­Ç µÒæ]š3ÜÖæÔO©Hß\-ÌaË`NÇ*%ÁÝ «ÀDÒô­ܧlBN¡tRâ‚æûªb± ‡h!9é ð”}ÖEç“çàweˆîv,G0·E¿~_)7Ç›óC×íºkîüÈuE”)ðóôYò}ˆˆdKøè õÓ:=Ò[ÅžJŸ™Vaä i˜[ŸVµ–*O¿OhTŒ4O†]«b…ÅZäNÔšŠv(»4{¶½ÚN5H” À‚Î ¾+*Õ¼-,Ë>Ϥ¨qž8^Ÿ²îFÿZWÕ{ü£&|y€îÙ×ɧྃ SHÝùL†8zï¡‘6Ý^2¬˜„ÃÚ¥ÀkíªF“×É¥D1\ùùÕFJ/yS6.fTبñçAH¦^ëM{‡g7þ#—ƒX˜õUóÈëñº·ÂvüÐÞɹÛDëÒºÔUß¿¹×Þ·#=„ï.I!3]£G¡j— Û‘³»’Ž;ÆsËcÐß0ÎbÐY;HÄØ}‡úÀþ‰ÌÔ©”/]2Ivdn ÝfÖ{ôh‚mꈦÚ*U ŠgËùwÇžTß°,F,ÚÈÙüÄ ï¶…ç€¥Kk4ðkÚ·b ¤;âS>\žã¿C/»ÓRMõzKš©õ¤¡©Á$úóK.´o]¯W'``B WhÂÒ9¬]ánÒ@ã1ø¬3:tE~·rŸFq5ÅŠ ÜØxˆP…g$hË\3tÏÆ4Z²àB›É¾xJ5wÖ^„øHßš[¥µ˜¯_KBÄÓ§èýF¢–•_åá2XjHj1ùÁñT`a#aDhŠèž0‹ÏoqX‹ˆÒošœò'ÚxYi aÝ2<œd1ÊŒ»’©Y¼Ø³¦JFõ›r¯óz§’€€ÒÒÜ}™[¾uj(ÒfKözn4E§A÷DØL%=NÒ]‰"¡L—EM0u®!íýIá„Hzf<näÙôHC27GŠ#cý½ÍL9šåçÒŒ¼>_RÔ.ïg‚u±nÉïÑþy ÈÜjÚCÍ!fk|õqµNØC¡²Á/ÛT G%7äT ô„˜|Î$ók¨WÖÛ ;¤°HÚdAÔ “;ÃÁÛ07Ç9'°µþËQºoˆ ERDy•±–¶ÚÕSx­‰ÔÒÅ3ˆ¦ž7N‹k8º^í‘ÅNfÀÅT3Wú2â«ÁTçÁ¬Êd1Ì»ÌÙüËAp{Õ&5ôÛªmå⇯Ùä3í3‘«Y%`N²—=†’Àõ`Qø45Dѳ™ÆZÎëŠvô‚4GÙb/·s°à¶(÷=a¨ÕÁ«ýzi`÷#žüÁÎbñ_ yâxÔ^·çÆI[_%W{`R³¤ì.WÚºmÐwÑ ê-H“u(€XZm™# Éß*†%±l§“pgù·v]Žæ ˆŒ+±Œ>þ‰5 ‰vSþIþ;fÙ©÷ÝžÚs’Ó¡²¤<¤ª›RvuŒÞYtu¼LïZöÁ8·kÉgg ¡Óíf*²óÞÒý`iùv Ò]Š)¸ïö1E Ž+¥=±ÿ…TƒfE‚.\â‚ëåZ8+BµFÿ.BEøhc¼2I%ë«Aí“°ê˜ïF>®qõé»*ûÑVºÎÏàùMŒ±Åñé›òJ¢”ÌôP+úŸ˜¼Íó<úŸž#ݵny4Vû„ª}•$ à.©öÆR÷v†ÃÒ†ÒQŸø.´—¯³AÒõé^ƒmn6ê•>êâoq³XxŠHÖÉAÖ:™;íV÷,1êç\lñ™«ŽØ’¾Ù UBí[x¯mu'á"k}™³6øé¡C\Ø^,À:?·‡Ôî\‡/s½[᣼À¶½Q6õPŸ|ñß»áY…/¬1`‡ó2¹Ñ°Ž2!f"|=iÚZ€ln{ìG%Ø™A_ÿÑ Ú¡EפŽçÖ«ÚQ¹ KUBCÞºê5š:D(ÿ>ü‚}Rk) >€üIX†º$Wâ”Ð'›&{g©N.M¢ãÒʸº‚V›¢Jj×1ÈÂIØžPç›öýXûïï]Å0Ó…ù:ÝÅ6Ökäû’€€é9˜º¼ÌA¶Ó:9v¦›áÆR±øÎIÐÔP„t—¨5Ÿ“ÑG’úÖ·à'Žä?`?ôÅ•GÔ¸ {–&ÌâJ¢2<»¯¾ùG e`2î‹ë£è舸ðñü“äl(v&Ò¾ÏG…ë^HÒâ}hŒO¾bY‚žÖü¤ [´‹ÓÎòùi ØòP³#`éÙm-ÝÏ esB C(EàÖ.’Ä­³…™ð`_—锕$IGG¥ø8ý*'_r‘nÀèdž³²Ÿ'Eª‡oMÂÀ`ϧ‹~Ð&ðž±³ñý•—•kd)” `ïãÆÞE?;VcDª Öþ¨YEZR¸N©k(·Ý[û'5a9Èüy:tÝô…ïI€ý¿Û!TìóƒSòˆ ~ôôºÌ½:Èö°XºôöÆr‰®Ëºîýfdª¼)R3éa–’ó~¬£M —ž^’ ÙŸ¶€ ³Ž±j.f™.r»ê¡h–x‰Ýíüì%Hß'œ")õÏÅàršÂ+JCKÑ4ùÉX>†ØÎVGV*OMwýkŸ£43lñÿ­±Íâ¿@x¨HßÔ–§(AÓbô¦®íúè6øó²EpðAkö`„Â"Ùù‡§»þíÃMh0ü"ñQü$kKVQëÌUœ•×K"·wóDÙþ0·N…E››× ›¸zêükúÞ$˜î¨1~XKó©âü2„éÅk ‡n³OÉœÖ7áå++ª¤©»°P%@•d˜Ý´È–ÜEÍ1Q ùA§„Ãâ‹ó¨¬û)ºÎE¼Ñ¶â”X…Èßö§ÉcW* )ƒ~鮤°µœr £ö*}€@¦#ƒ–CÇÞ"·Îà\Ò5`‹¶¿/Ñ*¦òåŸ*Nš­.ƒ ò´î”m³½<(Йçû(3Mœr?I$oÙç›ñ3Y›¼7)êp ñÖ³NÉdoÊŸM¸ìkÔ¡ÿ$oŒÐmÖ€\÷Ã\RpE¢#ˆéÙ¬ì;¨çj.t"? 3™7xÕ’àØˆM$Gk{a"äy bÁF¿Ï’Ïñø§¼ôØT0 ²5M‰åa^½a2îb½ß×îžkùé[+ûÇ -"ç¤ÏÊfT–;"%ÖV›»ÞŸV•SªOh%_Vëtc¨’Wתt—' ·LkkxO§ÝšÑ±²µÑÞlÍ„"p¥÷Y¢ò‡ëíFáA¥O_4Ï¢,“žò Þù»WƒŸñ”iÅZŒžk„á]<{×/h·1Ø º`:¹J[UŽ#žvb÷guÕ*Á©,ª¡}—„6ã¯$NÙ±\|_îÐ)¯Í\(Á˜6q<™`é¹mm É”åJŠÎ)b·Z‰…Sk–Í’¹ÀÊ+Æ£†ëœ;å„1ß5 ¢Æùê„ñ* Þˆð3U[.ï bo9¬œaxç0M.«`Œ0àiY“ˆlT)‘#y>²%ò,Þ`’ôd›&xC ÓŽ­ñHo©-+Bu”ÊQY@;)ZimqsXá/4 çÕncb0w¾£BÖ+¾léÛN<âåøÕ=RÄb§7”ò¯{úšVøÜ¶¬³ÂÙÌ+=˜£qÕŸ¦~bѯÅD»s«íª%¡)¿Áù‚3|1Ù6h¨E’iCoáiçt0`¾5™cÃfå65KH/ÖYII&oŸ‘6$DÔËoºÅŒÆh…ZÉ&{ä7W=Âæ>ˆ†ŠÇ›g¡DãšÄÿµšÿË]g5+XôÐâ1Í7ÔüX?~6³ºaÜäEÀªá(J}ŒBŒÑ^ó î{¸±¢z› †À¹ç*J‡÷ÔT”Mš@×¶\Cà¹Ï?Àâ ~l)WÅ>Ðц·[—øjútÊð‹Ôh¬uÞU µXjGAxÖi•A¬ùx˜¯.6Z(Œ¯*ó{D‹âØ';¡«}w´ôörFQO@.„Ú—.¶*ëø'*z” àéƒ?{%÷r R½(GU°(k׸}Í]Ú½tâÆ:S/•^%Ä b˜°ÆIK¿–÷¸7û@:{¢ðÑÄrpmJ´¼¬¦*rÍ6ÈÀ„àòàR¸lÁ)ÙÚൈðI®½…cJNn‹î¹Æ\)R‘’€€Ç·Å+F+ûfPà ñ€}2ÐÚD~ñr“}çÕ î–TäFòîÔ>ŽÄBP7{‰x Ó‘¾¾²þɽۣ†Óbëã”mZšzík9”—p¿V‰dp_=H­e—  @ „ ”ú6RÛSÕ=2ø‘i8q„#^É”ÿØ×í¼¼8'Õµ•ÿC¨;b ú&®JéÙæH”LJ}ú™(R_V‚Ϲ‚;a\»Xå32ظP±Üÿv3ør:|]=h÷¨,K»>¼xtq•ð/ë`á{ÎfÛ¦_Õµf™Àì¬-™”¿Á ?;ˆÀè65¥ ,È­ï|õàðèPÏÓ"1d~ñpÄÑl á4Pkz ¼jG‘GV£±P†äOXØè$Vj»ÿfc7œ {MüËúɪöÉ?Ó9ºšB„˜éá°ÜD‰Þ4°Ù.2¢H•VFüT }ÿͦ¯F¸ÒIMdAY§®#Ea#ŸÖ[±pC?v¬ø£Uï-aMo“÷éÅg VÏe¯ë8_{ ›5éÈêœÚ^ŠìO)s ©­,kµŸ%³Þ@œ=Y5Ï%°ÂE®lTAa/áÇ^è*vE`µ-„ýë>Q›Ý“òëZ`íþúbFÜîºv’m$XÅŠ¢â®ž”z?î3ýqp»õv2öª*û´ Nà™!¸¬(}zZÄhúPç‘NB:'_‡¥L±Ž§<ð/ˆ9$úI*[Ã{áÃ’Œ!•p«–²5fZE 8tÌ(UÚ˜£›=¬Ïú5NÌI=;OâjŽ*Ò=;P®Ú¾XNç¹¹ÝÀtc ú]ÞíRVÁ¤=q¨+ýH9™ÓšÅ°¸Ç4ƒt ÖБºˆÜ_ètp\ µšÌ‘ùŸ+X ¬Yx^·ëÐhWDÛÃðñ,¬P$VLûJËðŒ‘(²Ù2´ï/!D!¤NwŸÃÙq’€€Ñ0Í·AL/WWoj—Û`5„z<ìý¬$KWo«§¤ÃzV{Š0ku§]ámÌï&›‡Ç¡šÙ6z”QŠM ô;*XÙ±o # š/áPÿN3ß’lëgL ©éP¾²oª³–*=ZÛ¤þ¬Iå€*¢¹N°Þú¡òOɬ"_PE‚ DÖnéÇ'-è"Ñ+½ ±àþº(w»ìåzÕ:švÅ0¨É±µP²K—’L‹áÓAºê±,â_Ò ©%TZ ÂL~y9%‹f‡k<\ÈÞ·jgB&¦!«(žì¢ªîÛžETÏS%t5ìóqÙÄì9Õ{ºtOSD¼WÒs}M÷„N ß/ÎÌ|±¿’t¾Öõ… 822' Ô#œí]ðŒ±PÙT?òêK­ps½U)7á…Y Øv ,ö°Óänˆ4žâj°ÙŒøih¦±¤²(|åEé{–ÂM¡ˆ–Ò!Þ‡u#Ó^Be¶ˆÑuß±N/`eâmmëµå/7B›ê/Ì.wTþc*#ت–•(T†á- É §o0éÒҽ송'ûôÑö–šàútŽO†]=²{ë*ÒB‚é¸lÐ%:Ÿ {É:9ö ÁÈa Q×kFº…GÕ¶Â"º‚¤·²‡ºjå³sŒv¥ÕFÚöMÇ%VLvÒÚÎA!T,ѦoPŸ>Ú4Oˆ3ó¶^Y¡‰õÑÎwŒ‹ l„áVxRc*oFº<d°*ÆÜ¶øŽqtå©›?yŽ7ËÔ •^ƒ›€¥àDé­ù¿2+z$JÙ•YM*ðiÉüº¶¿ÏºÖ5‰y䫸?îLŒÞx‚窯Û?Ê2‹¦™…¯=Ѷ‚Œ- ­ÍÌÍŸA§¿KTX†b÷½¡ívW-Ð'¡3”î·oÇÎa¹¯·c*6E_Q™œú,…”ƒi>ý&–ÔDûxŒ°)) …»µ`àí«ÈÿàµJT9´,åáUþÔNðcÿÚåö¶Hc–ýT¥˜€$ë-’€€­FŠæŽÜˆ×ú¼Úë1[9ª[ƒÓ©K }ÃÊ8ƒ5zDyðÌk½LUNàofçø~/ñLXšGí.xÝ¡PµœÎ*í¯Ád³6‹Ta£\?~ò¬t ˜º¢B5£»ÓKŠk¶Ï³ïVG¼ìtB{2ŽbŽ £]jÕ)&ÍhÌúÜš ðë$oyøÅ cQ Á xËKñlÌ; HÁÁòM)ÁëðüÒ šKÕ‚qÜè5|éfdø’–‹íì—°ÂmáY{ýBA‡Úƒpý«lÙ–îQÔJjîPßú%†P†ˆÏíÊi'L3.n—^AúÙf˜í [œ÷derlœ;Ïú`”·•nc ‡¢h1še g>€Ë u)þP!›ž¨&5§xíÅŽwЩwøÔHÇ!ø')wÞÐàÇc‰á M$²ƒ±H¾›Î<(Ñ80XÊ®FH"%ë›—“Rè¡£>þ`®¡ø~£^-àG®Ožß󩟉Š!áW,‹OƒÀ¿Í¥cF‰F£öSrŒB.7¤?õÙçV/sß/B²öÿƒ"-oï×£m×´£V«$áeF´?»8k¾«wÊxp^®‘y#M!ò‚ÿ ¨ \bw\x22”_[ò†6Õ ¦ÙjÞÞ‹1ÐåŠÍʸ˜n%ý† tU-eoÃÒŸÀK.¶ÓÈPÕ«Hãõ±œ’Š'åñ}L‘Ò£W„zyΤ$ -W„r7•9ܽ,J "Â,ŠÆ~~ìÅ·*©]LgˆèÇSY˜%OÑp_z2HÎç¬’Ý òìÙ2W=Àf:ÿq¨CÇS7E'©MštÎÜ y|§`îÞ×Bˆää±nüUh]/Bº©TP ç65Wbã¨âfs™=¼E`ë=×”é#犥Ìÿµ¶‘7’pjñ)î ñm¯Öˆ'ÇöÕæwyêZ5gÚZݹ§êrÞ?xIw{Û[†€fÝEQ¨þçF‘˜ƒø‚m“â¼(©wz®L‡KP/|6lÍÂ*ßÞŠî-³m—à­¿òQ*áÝq/WàšœtóÙÔñ \!X]X»µ€ë)ÏTàŽtÊ{Sà‚/†#’B{3Ëœ}¿ 3®3:$íÍþk ©ªÏÜê^sWóhZÈ‚»n$ü-‰’K’€€Ë`ß­›‚ŒUW1ï}9Ð6Ãô¢ZNÔc®Y Ò©mÝç~ݲ¡"KÊøò4Ô°ÕÄXy oCéD7í²J4¹–xd¿{îà%ëxEvÚ|­(³IV¤«  ‘=`Wn†½N£ Tí ž9§t5|ûWdHõ'P–mŸJéè‡øw/‡Küé¾!yáâå9?Ý™;ð#œ$W­ «¼qsÒ7yâ¬ÑÛ½<£ü­‘¸}ßj²eŽÞ#ìã°…`ßÐeæw=˜3®ÛšÌÞ¥b½OúÉØšx‚+Ü’Iü>×·3X)(?0Òf{Dà‰ˆÐÄÛrwš ~ÛÔÈ:J «[àÛœ™h’(öïȵd ¢Ø-±£ŒNú-ŽKºµ·:ÁÖO·–³ìÎç­SëdÄ)¿a¹m^Ĩ ¦CMf‹Ô¸RL©ÝªŸÆ_xB°îG^À‚õ^*2“ÅåÉ0Úqcªî~zd™uþÅh=zu¿y`Ã*Œê®œ]ÉÒÄßrüñ±4:íÍlB 1’ µ_9]¸ô;BHž–ßÈyâJé=7Êp‰sÄY<ï“¶9»5C³ð_åtÚU çmÀ‚½£Ø ȈFZ(ñ1Kjòä“qhd2´ˆ:ÒMܬì%`udµ që­ïõõ Þé°rTG´ñWeñ–Fø¶M‚æ¼TiÁ}æn n~JËßd“{ÔöƒÍ|•ûÀÔ‘lövhJ鎒·y¯?noìÛ69Öšf£°¹§\ay÷p—4Ç ÄÒ0ÜM~×aâö3ö·Þó¼¬WJ íW…åýÆ®BïÏÚØcµØøñͼ¸ùI^̬ø¦†+Ä,=“]/G¤ÓÐùшÒ²`ÇÎÈî ù%+þ<«ÎëØ3Cš¯XdMdéå‹QÓS)ú²z­ CêA’D„!ÂS]ŒVè4}©êê(™AÏBPº}4¹µ{äµõ‡ý ÛHâÕ+§Ç1 35áW ­CHÍeS¼Úz €LG°¸2讎Oms•Iö@‰ ¢òcõxá3†ÚÈú.OÎåádK½:Ucø»|ç‹_Ô_Ђ'ÅÏ!7Î… ú÷SÕÇgÒ,†±xèÖÏ^¹léÅ-˜Pð˜¦BŒyŠ,•s/I¯’€€¯ä¤²ªÌd#•X©¡¤Úho´'eÑ/ý¶ÜO©¿nGø´ŽªcåÓÍr-ÓaR|[®æL¬Kù™®N½)N¿˜9¹ R¸†¿°[$é¦+hW“þ%Kø½T<-x¨pµQ× cÂCÈKé)MÔ viªpc.Éò/ý€h‘}„ŽV¶pW²Úheºu’$%µ½¶é^zL‹ú@$¯Z©¬(;v•)[°Ž£ü™Ë—;l%âó¡²{pz |¿r%Er¦.ìCY.\7'Àýª¡ãæ®·v»WÄT)ÎŽ ñͧ£‡¼))p¡%³x/ÿIêŠðož›–ÿÏg™ÍÂnÊÙZMÁ^¡ü÷HõÑs±@[,Œ„>H×TÛ†Ö„(QÛ3˜ÝÏù.â>q›±$d†Q{ñGŒ«k$òh<¹o¡=)Iî ÍÄUú ç'ÏhS¹6¨à‚zi™B€gËÀ½ÈïÓi/Pµ§ÅdÝ5éýljS™\Å_U"E´`FZ¡Ùó—X$jV»„üíâÀ˜Ž-¢“]ƒ?óV[@³7 ïY€9•vÁÊÓ&ȯʥh%; ÈÄ\ –h˜Od=$9¿yf‡ýš÷K‘ZµˆÄœB<Ã/˜Tµ†Œ!ÿH(eß^ÏYqÙͰ­Ä"?|Næþ4m¯.Z§–Î;1BJpÌŸ¤ä§XÍœC9äØsVQ°ÛA:rÖ÷và/µÌÅÙ´í.‰‘yj£ofv)„—nÄܺVP2Å¡â6Sãj*2ÜÈ?yðë¬ÙÕdJC½Q ¯J‘F ½´Ý·AËA‹|ñß`g±Âïc;ª—;Ÿ/ÏÃ[°^êÞ±B‹ò»Éõ ~^>&vIFºq¨Ûì2¶_k~ÍZó¥K]+7%vÍ)¨—¾„æúm´ó±7ŸŽ³HŠŽ|ª›‘WŒˆE¨l!1ÂJ¢ÎïÒ« Õ±ýÀGÔóôPoy´ÎI4¥ßUø º8G®¯®KˆîEÝÌ—õÏ9üÕ\ÐçpŽþ›L<£ˆ„øø¨|…ŽØÚN$Ï‹BÒÔR½ÕµÛ§à…€`ÎC¸l0ØŽ Ƽ¿RFJÞ÷ )—”ô—Õêš’J髯Îé‘[’¿Þshdü¿¤Š0{æ­QŠ€KL0=ì/„7eMg’€€¶Ú\Ä|™ê%¸~›9cìA ‡¸{BÊÒ¨Ó{ßb&Fl‰Í}'xÖš‚ï ﳪϯ¹´âžb²è<ÜÁÃjªÈ{°×`øŸ©Üã‰üÆ«À³FF]¬qÞµ`Óÿ¡#l»@Ôà+󛸚YZ^É4)cWkW¬¹#Üø–¨•m™ÖÞ†;Hžv›Äð®ÿÔËy>õpé¿JwÍÎÜ6Ü öåþ(¯‰åc†8EVåjœ1«·Æ{énŠ2*ïÜ&š˜á‡aIG’#¡{)2"Û‡ö‚Ä# ;8\F=$Ÿ\vxáUwN¤lå ˆ SYŸ¸˜&ò(ÌR7÷. ŠD¹2`º/ÔÜìÃ5ÞýôÁWrh³ÂÒ­c%Âõ0ÑcMm±+ÁâÒê+>QÀ98F„j˜òmÔ5¢9¼¬ˤ³eÜNv70GB~÷Öv.»¸†7´ü:¬G±ä‡ßB.ÌŽ( ¤ ²[‚gËœ=!}[‚ªîÝkÅ#‰Y¿#.ÊÇ™”DŠü«ÍHç‚ìç–·èsÅJËKÙKn èv2—ˆ q³AH:¹®ºôä2d„ ¸¸™÷SË.§ûÓÔ äríÂ@"]=‘üÔhržW«Zr¥¸{#õ13=䊈شê[†eTgŒÆ8 {Bö)ë¤XCú3>RšÔ]î¬ZÚ Ÿ›Ö¶ÒSpý4æü¾Ëê:‰l®D°6’€€²Ãcê3¯ÍºÐ2z R¡ìkEîñ“3ÅRkR3n0è@Qú@#;À¦®¾Hƒ©àÚîyßÌÂ=·@}?¼ùÝÑî'²òò;âi,Ò]‡‚Ô79üQí⧉ËTÑ‘ŸþG&h9e< ¥`®ª£‚0¥q¯DAØží°¦«Êï-ò­p&^K—›‰¤‰`DÍg؆ qêvß\†¦ ÉýÝ +{M‚ÐÅ5LmãÚ€ª:GÐ:3lzoÔ/f2Ȉ ¢©“¬SQ§ß”5>3zê@XD_±'v ýošÕü»­=´ì.[yFÚ A9LÑcõÓÄ@Ûϲo}gA2Þý|b'J‘ø•œ¶1 ~+´=)fr‹6ËK¤Jñö×W|CÍX,8ÎøEMÄ‚o'yá¨z¿-øNö%/$ûÛÑ»ðªlmà< gçú´»c%£z…>²B¼Ç;‘¾R:>ªƒÿ1îì°ýkD´–›ét®+ƒ\óâ;þ¹Î·C’«ßÏK|Ja¸‚Dœ8_snœdWLÊoÍjƒÐü‚ì0úF T–HDjý­JÃcÌjééw¨¡ô.èÌ´MPÏ Œ.бzöŠAæ2±KÓCgò" ‰Ks:þëh¦úµÏìBÏt’¤‡J‹Bmž8r=ÁÊÜ!ç(FFKÛ—0_ ¹én~úÙkIh’N˜Òˆåø[M‰þƒÄe¿„ð³ÞÑíE p¼@}`GÇRSö"Uú.kIÕ3_Èaå@ü3V‚as®WZ{¤oâuq*ZBð¾+i̽¿ôs!ÁÃ@9ï DoÁOVE£˜>­¼2Åùž(‹NH²{žˆ2b{ðeÙ™ò.ü~€ÅTŸgvG¼ƒhpÔ¬äi3`üE3e¢_ÇÏó~O‘jìÂÇ®‡Nà³n»ûÆùQ­æˆÎBÇ ¯Jñ' òó~¨ m^ø¹A½ØF¯<ûpM0Û¯†=ÍðÜœ°¿&¬‰/L’Øf5b tþr¬øÃøxr iž PÇ32Õ± ïR]4;‚x_3iái¤UÍ™sh>QëE©?çÖm f¿P®¢:ðДo~UR^Z±@U¥ ±6¦= =Ëüœa9D“´@œ)yl7Ýc-ñ¸lÊ.oÚ7Œ’€€«W#tæˆÙüõ\kÆà¼Ðf/8×J޾IRÞZí?òø«ÜnÙXpA\|Þ,ãiB÷B†n;=ýz¥Î”ÌÇFlfiàÝY7›xéÈü«8éÐñL²6Š å»i0…Þm…xã$ÌŸqÄ”‘é­ñ² i[ ܰlø´Âý|ôóv>2ä—´ §7 áô<ÚÅŸ:.*âŠOÛò&ˆæ‰Ò Ú¥{SÂríäóÊÐlå?z6 j‚Y 2Åúû´6}é$YWÌ^¶º;µPü-¡#£+3¾QOñ¾/2ÊóŸÐ*s‘ Éxì*øˆr‚j „j ß6Ïù3`)à{ Uv™YO”,ŠÁy´Ét0ÞƒåµÙ FyÒªg*ú$ê]ñà û½q”y¶r~[¿—G¯GÿúÖzÛ MsY ‰LŒ3Ë']^ÞÿC€X<Ü“wi‡rŽ‹šfÐ\6³qÊŸ‰6a+Úÿ¸ú=þŒÖ;»¢0ì(d[„t›{Õ²–u …¤ïÜUØ%«|ìÌ!Ú#ƒ Go<"‰;PQSãJÔÏÜËvŒNcùãt Ñ?s©IÅRp¬uÚÊÞÿ‘äªÕÛ°,ߨÜÊß7ídÔQ‘²ë=½g¦›t éǽò¿Yÿ¦ÏçÒéh» ¨³~x¸Ã$¢ç.º]·jimñáŠo\³âzoÐJws⩦òú/#žzÐIÙ¡c“=ÓP†\|úf;àJð!…oOxà Ä‹ûœUL¢q c¿Ïjaª»ƒúk+Û¬®‰ªÅÈ–2Øû·otçwšîÊv~aЦçÆ¼àï²þ‹XˆŽœspys.—IGqÂzÙ#¬‹ª¢:T+¯ó;=ô‘¢!ÍÌŒòBrËMPY뿞®dt;jÕöa4êo-¿#“L4¸ÑHoIlG§¯»áåüïÐz3Wœù‚w<òÃyö«uù˜O‘ÎwË?wˆÊܘ+ž¥ÃJ $¤ 2?ä‘ü¨ñ 9´Ÿh%¨«¶ÿÀ+åÄK”»¿·{9×=ÛŽ´Ü«LEh`ùíç eGKº†Aç6Bx)ÕeûÕïžt9ÖàÉçc>MŒ„¯B–ÔhÆLp9ÞºÂþT ‰Ä³Œu±¢6òÍd“e3¿Š ùoé&ú – RÙ£¹¾2é‘cÐÀ’R—ö’€€Ç{‚vtÞ§µùRðE™úÖ¬Û±™¯)PÆIS)Ûf¡D%ç€0õ£–«qŠä®_%Gƒ>…Ÿé¨¾ÿvA/à&ŠšRþ½È'FR€—ð®Ú`ý¶Þfs6Õ  B:¾´r# œW_͘'Bå¨lÃÃät‹Þטº”K Èh?j¿û·[½5/Uëݳß:Êé¶ýi®ô8®®|DɯŸS£FZ)·½$â{ã~µ¢O¥»pãxcà­ÛËf$‘ƭ׌pñÏ/ozÚ›9³KRZÙ¤™MIx¿?ŽŸäJ© ÷û–+ÉÚ¸-»T"=ߊ¸ê‚ ÝYÑßì5½ü±—P£4¸áP}B߸S†K@臛Kfíñ‹ZÉç#ƒ)ÓŸËP¸ÿÚÊLs Ê¢‡»ª(Æ“u(E3÷iM"ðx¥[øã‹¿óÛ¹ÎÛÇ1$©Á¢Ýa¾Ó;haOjà ¹k«œJøpŒó,!`$,õ¾$5¨†Íû)å~ë˜vÛæ<a¼€X Ü:c§Ëâc”YNéõ«ÃÖ ×)ÑЪck60‘’MÝJ—M÷½ÅW·„"]Ìcº* 7•TQWr†®Æ;‰7|"pŠDúMhvcZT³£ÓQÐõ¸Ò,1L1»'ž’ÑóûÊÅ*çßé%ýt™ˆi~#,ªÌ‰×,CX½£*-–ûÎv•"Ž4o ŸŠž‰v$¹·¸¬ø¹-c#þŠ¥ßom­Þ1Þä¡–\„•y`åžd>Ò‡{ÒZòþ~ÞƒäÕñp­k Þéîb‚¡Jk†ÔÖ>Šö©îŠºóÑN¢drÕ÷šT~ PÑ40™¬Æï?«(.ˆ@<’€€£àÐãøHªW¾«a,ÿ¹ßؘWÕ÷¦ØÈTþ\ µâÕu*Àâ™úiïïdŸ‚¤wóã )ª¥=)Üo¤4Æ«¾Ñ ‡\’¾y¯ÈHq¤ˆrPØÝE¥Ð/¶-”Wú _+TÛ^¡# ð¾²Án•ã7ññ’ߥlª=Ö\¦ÈÈ5!WZÆ~XËOÍâ»9 Dp¿èEv›ñ„Ä|S|DêÐ1=»Nc|!”Ee9{£Û<õ1:Œ–ˆ ôÜ4 çX?.ÛëÃ#]UÿÀoÓÞ„µT.*©éþ8å¯]_I–ßé ÿŸµaë`AмãA0ç "b’ÆE '¶1«³Á`¶±*ó„ê¥2ü7éô¼Å}íâ‘+¢3eS?YBuJ8íÕêð×óë§<½ £e *ÙÚùÔ”ƒ©‰êâx’ûlM6Œœ¶&ÏL"ÂjoòvDÚoââ*<2\ºðeVçûÃÆæ-¼åƒ@ ¸«rªe&ãGgâñϰç| HNБµÍl&ÙydröÓ/ݽ€sƒg0vÿy×b{Vôr]¹ü¿æ¡‘Ü8p–ŒÅdÁI6!W©Yk‘kØF¾d½Ú‹»2ž>]ÜØM¾J§_DÍlx0U‹“¶Y-çE«W´Ð—Ð t‡®#2¤¬¬dbnmhÿAj¸5ÄÀFJßË5»³ñoX¢ô¬ÖyNɺnEÔÀšY±3ð™²6sI‚á6 ét=õÃW‘-úƒ0¹õ Òõ¾’«Á6jpD•qÎjyMžû2¼B§ú6+Õ‚™ŠšŒ–á´DAC'k´ lÓ¦}YÏr6¾=̺ ØØy\ÿÿ½xÛ•u=s6ö_rÇY¨¤fºÛ4Ü¡˜mó±ô„Ãøfù"ƒŒ³Çç䯮‹³>yOqž•0›ãÃx熰G;æ… [«ÿ‰êWkF‘f×—±w•UáÓb[ÐàM†ïúþ­Pw¨‰T´ Å kˆ¹¦ø„Ð'jì‘Üî…]ÂWˆêÄ ú’€€­úý•X¨¢‰ñ¡Íl(KMžé†níqï·“¬×Øò]*x¶u–8ž*Ýõ/%àRÒüj¾F¼LÓ`Ïü…v ¼È;QwlÁPüÙÌŒäÜ3ÜqUp»¸ óy)$0Aê…¬¢ šðËò±Æï/ªé”íPµ3aVC0'xÎy'Ú7wew8±•?è¹€.‹O2…¥ €2j9èÕÂâGè‹úƒJw‰V¦³*l¡•n¡nÙ±@Ä<¥mýª±UŸüNWÍ'DWÝ×ýŠBfû{Üàô)Ì’Ê“ý+oB´~.róܫ˼ÄxôšæÙ¨ÝA†<нe ­|6Yš1VÐGBx·C±ŠÄ5DåÇŸ41ZPv¥üOB™ºå?‰¹âKVý¹Èhæ*'…ÀC€}¶‚µÍêÊrÙ7UðÄEg¡ 38›ž`:h™?fÁvðù i¯?1Û¦;¹˜×áÌ|ÜÊÓ#!,Ë­‚³KÄB»æÊIÞ¾oóÕ0Ç ^Lˆ½‚»D¼”˜ÒWÏK s wëÈ{£ÆÆšõ~þ,0Ú‚ÐàcØ|EShz’ıͷBp.í£&ôëè@-Mb$¬+ãaôÛ EŠÍäP¯6UA />–ž•îíR[l*`˜Þ÷±º!×ïˆSGŒÀ©¦™çZƒ^?ž„Nþ>Ce•*&ôk…g¦Œ¼â ÈÜD€=h ø^Ê›5hì,Òcån1¼p>§j8¼&fÕ8¾Ln7šØe¤ïÅN.Ó+‚IH|bñ^€`»X'Ȳ֚š ŠÀµ$`éÏ£¡¾ 6ÿ(1—´^;‰à ÉÀƒËá6½5LZ”H‘L !f÷X†ëêy™†.‚6/®["ÛKÛåÚ|쨿¨ Ô³ñ•Q ò2èêhàwIn²Z ~¹²=IDÌó–S4{ŸåN»™Àž¼½b<¦¹†­rºö ¡ÈH·‹|RÕL(í}nmƒt7€ÍE|‘õàÁ½Ìà ¯§O¡¬ÀðMä+}aòËKÐê; ý ä¿âýðÉh£Ñdöš2x.Ò2B犤,)iääËwzc‘ônÝú”kõ¸Jüą̂×Q-‰Ì2vTËÓ+¡Ie|„«ãFû„¼£x-ÑEÓœd*“cBžÓÀ’€€Úñ‚¸ü% äqÉbØG:õÛ %jëu¤2®¼üé;–°¦‰}Ř9æÕ“«é£Y¼ŠvÌå5¾¹ Nbøüm ÉÂü ’´õ$‹Ëá§ßvȈ•ÊwGÖeÍS‡¦P!Ÿ „9u9ºO8ÎôÌ^‰ÔÐøÓ ÒLº‰d]·l|rýÒ€]²Ýʆ£·²·<§9£cXÏß(Åà[`7!Ûû{iã·„M9`ÊæTŠi?,“øð|±V1Ïp˜ÝÕùüE˰€”ÁT®sx8­·ó¢.r…Æ”,R8çíwè")ºR.¿X>@¢ gË#îÈê<eñöË*Û“µÇóÌ ÞoÊ&ÔU¯6ê•#œúg0Brqê]†{Åtdu©… í‘o|Œ• 4š|/"Ÿ°¾„û»^À¿È­Ø/Òy —5À÷Q’Èì§òªêŠg%KÞ;¶äX6ôÿµø®oÚÿ€§“‡ôUÔÀ7ü@K¬rS·-:hžt^žh»éB5q‡R°ÊQàK¿¶ìßnåÿPyúkjƒªü‹àÅãÿèÉÇŽUÄïí"¯ð^& Ó,†žõhZmŠDL`iÒ’€€¿åä©[ÓDËÈ/iÈ9¿ä•õÞ¼Š*|µv6Ux¬==?i·RFͺÌsmYŠ.Ï ŠÄçμQaSP Îè8ûg‚ý•Ù«²i"ñOi¼Òãç´ú¯ÝÿU\¡S9m#mù®Ð¬Gfr÷‹ÅHÏ)š$onª^™ F¨^\†ÿüb1V2èëY›wœmüè œ[sõuQÎ"qÔݥ̠º'×—0Þ>DOÿD޳õ'$Æ4 ‹_ö>ÿÅVÓåó™€/ë$¨­-º.Ï$̪xO¸º\(k³`Ï.ŠíÌ wܹ9(oôaYNªœ‰7 K:ñפŸý±[쉿TË|–#Õa?×@S?:(‘¨¬È–•|Œ¶(è?òî¶nN'v¨×¥yÝþë=#y=+Wهº ~É8-C:¹0l ­/Å~)Žߣ;N€I8X#¹ÌÂã”râùqÄq€\_žËíùã×Ô*³&>P†BXAùyóÑPÃy59PþЋ¦2Iïu¾©±I†Y=Ӣ󃚲ÐüYJRÃ@gÎlFËfà&Üà'Xráç ¾“;KãíÍF³gf£²ŠÔ‹ÙGR ÆËºÊ#]ÇBõ5Ô x\CKVfêvö½AÕ‡Ú­V[ yö3Û0iG3 z)BÈãWÊœ¥Þòó†ò›¹º;øêÏÂY*:'¹ì”1kê<Ê^íd|a nÝœŠÄ¯áÔžwöè“ÞåýÅì¡p„ô‹|W¹ÚížÑ¨ ©>ï7ÿøA×@ì‘êòHЕ,wzD1å³oM ÍÌXUYŒoUAÃ7 „ׇâJ8MØP*Â0ê<úv<Š2êϵi¨NÁ>·hh?¨0™Žúk«ââÕ0ÿ;ÝÕ˜Š€BmµŠù—pĹ¿ˆóªíë¸ç§¦·2h¾Gè¦êÒ0Iš¶ëL¥§5 ^¸¢Iûb5´ _–ƒ³™ Íã'tñN"¬ÝÞ™ ”xQÈ>šÂÐB È·ín}O.õxíêé[Lf=®¤ë5ÓÄq]¾¾ƒòHœÙ“6Â+gå¹ ç’€€– øOvÃc+§š NO‡?8yfͣшÑ:•á5R=1PÃk!5 ±š h¿ÙC›kó½Üë«Þæ1£¬vÐDÁ›ëãT¼Žec>‘Vqܤ°%ö¡ãnß×½aŽHuÅv=&7uÎëo&0™¼dÆÄìØRJØ:§9 £ô­4ïVž(;Ñ-'‘ru\#NB?Ê~ëBx3|!ߣcêx§ƒ1‹çÄ8¹D‡ë‘¹ÊQCƒMRz§<¸/·l'm3<Áøz+zá×qòƒôÀQýuÜjyù¼v7ϰ“!3d·ËóºÞbrx¢$I¶,вp>š‹4U564°Wk¥u£¹ƒLýu˜ Y  cgΞ€ :O…)ßÊÇ"hý[¬ô³©âímØ&£yaúý N˜Äš\Ô¸dþ·Ê[¬ç÷g²òñ‚ø2ç }3HFž†ù7÷½QÉ­Ql~ŠoÓÚQ`ˆ©•æuq¿ÅÚEÈm¹­|ÙçíL€„”…ÎÚNòn¥GVÔZÕug~IÄ6¢.ûÖg“™%––˜ÖóÃ0´Yàá!jUIí|Øܘdu¥‹œ3±£¡lq袕LÇ C,D­[ïý•%ã)”!ŸrtÖÃÏ·¼kÈÉ;Ji9 d›«˜*ER'Aì ¢=v°ê>ò;v6š>çÇ2ª…à•gµQ1¡ô›® Ê#°š>bµ€!‘ŘQükêÈnR;ôÅyørÈýÔϯÑ#>y ›ëÀ©e>†ŠfUB«¥ÿ·=äeÀéóP,‰Ý»æñ÷ðôf3õ§¢ßl;~?M&_ò}¡ð~Ôœ¬ø§Á”ÉSùf±žHCùêwáêç5¶LEW I;d,㹸R¸&›ˆ˜”Ÿ>¬Nû¸yá0mhùâ1ƒÂ+yÊÂNƤQ[õ‘_IDQ¬”ܬüœ bi4p_ßü¿ÐYÎñÿN¸¤o} 1m3ø,„uÍŽ_¬VŒÖådnYƒ©–âC4…C2ZçºaäÖÚúf±úCSIA +¿1^ö^E°#DuLéì]‰J.&|f k[ÍÌ/¹@n ü[ŠqÏC4¯ ÚÞÃ8ç7mr¯lâ¼>œh$2ú«ÈÄ¿ÑÅÖÞ˜°ˆÃ”/ÍK^q “L·7å °Gº˜4^’€€¬ŠËÞô ‡ºÝæ¶ÆÅi­Ö6tM7Òw[1|SÇé"eà´ÊóÀF0ÆzóJãM³;[Flñ­M¿sÿ£„XäaŒ!wj¢™Ù Ë*TŸ¹NDÀ ‚U1gÎ*BÆ\U09J _¥¶ :Ø9ÊkÒºYdz:‡‰­•¯ x½x\*+ój•y+À«(oÚgÀ[%½wà Zá;¢¥V –f ¾èŒï ®a?y+å2“NǨ¾VRÜüÐ<õÀ‰÷´e=†Hs¤ ;B˜—»$íwEQ*Ìhm#,D 6kÙSBçÑ.4/ˆ=ߤ\J…ωäxEà›¹øRQ AîP»ø Âka°ã" ª\ô2$õþ‡’ç /ÙÚíþîY8Ÿd|ac7=H²Ç®^ˆð½•»Í"1þyòOرŠ5aöEƒ«žöãææHÂÀ£oWÄnýÊ©zè0„禈Y½è'…1Ï.¶èÞGñfv;jEëkhE=våw@äJp2nù5§±jÙñ@W2O‹5ÑdŠ.TÙ|}l0Gý@4‰Sˆ#1Q¯l—þê½v(‹¾Gܼ—_íòŽF3Î_3X½ueyµ’5Ïnð¸VqĈœ%[ŒÄ~¾GU§¦C3ô¥Y>ÿi( MÏ£ÄÜÄ}ÊÅ;×~GŽF=&¼Ð.`å¢Å¾ÿ>f&~3fVÒ)œèÌ_¥”DIùèïDblk ¹\©'¶¯Æ ¿øp¡ç±–˜y(v‹¼Û(üpBï•êß¡}(p‰{©¬êƒß‰Ðôy¹OígpWúHDŒa=gVÛ­‚ÆsÌù¬GƒV‹›œ]ÉF. ¢¼ NÿTP®ë;Aqóå½g°æ›Þµy¹ï°¡"çu<‹á÷?-Íœx]þ 1bp¥¡j~Ñ1`ð6,+–Ð!,[X/8.ïÉëW¸çï̯,ÛÆ([ŒÞùSÜ‘œ»³ÝÔÛÍл莺¼ÎÏ+hcè'ï7ÉŽ©§©¿á¹³ˆö¥.Û/¹ú’Ö”Ö¢"#Ýo ¼Ø÷J'®XZ?ög¬ÎX¢•~´'Go ¤.¢N“à¸i‰•_¿¹86[™ÒeôË?(âSb*¢›sž, £eQø9+?~ãŽh´ ¨^9$aÇ’€€Ü•Åó—³[»‡hµûMèžë1]ïk—àF_dIÆqËg÷X!µÎ© ¡Ëê|â~u'žøµ„éßh_ÿ"_ŒVhd©}ƒ“ÅËãd?ÄZ 5Zaé>K pßK‚Ø 8Þ~¶{1$A/#-c… ¥Ne›g¬eïµék’D¦Ãšv0©¾ ©o0/ÖƒÖ9 )Tž.Áó2¯`õ*¬À%MéÝÓ…‰j]~ßMö"´ÅìõŽŠh± cþÞ‹~ e¶¨Œ.Åvñ²“P`KâU!eŽŠ3qz’RúsqzZ}\UX¾Ò_RðQ®ï wbÕtñ™¨žÈÕÒ{ñwØlþ_¯ Ó˜Çý€C¢ües –‰f)IIh_ÑØêÉ“xÒ3¾ÈÒÉ™ö~Ãìt²dÊX½¦b!'šI€µŽqãàž–üôñ?òesdòjÓë×.Ï ;ÓVu9ív¸ÂjŒ]‹G@÷RûùÀ[Ó ¾“¦.ìÄ´4·ö ·÷f3,|(sýU„Ã1ÙÕÔа—¢§ÁŸV¾L°æ/"Þ¶‘Qc±‡è«^ßyƒ]L?Þï™wúؽk-réQ µ‘À}Ý<‡°mæ ¯ë{&õ?!%ËÒ:Ɉ´6ü8á€mî£`b!ÕäÕe3xP¬–qz5Qô´”ÛR~eõ59)ï¸ûaL>þîd®¿3ê50ŽvÕAÅx6ÅÀ)cƒÜs6„úí9c@DéÖ àü-®Ã·®ÃI`Y6ìœKREŸnF³Ô-Pû£˜œ5”±1Õyð"?¥ô¡án¨]Ã@ jN¯RI@MYp]ôàÿæÄ0ß•å|ÿ€¥èùÌgC,¡Ç‡Þ(úž(W¨*Õ®0Á‚$®ó52r¤5ÖŸÄ#ב5)|ƌ⚅xQ±&’ ïNÀ^’¶®4¶ÐMòù€Êïã˜{›ù€;´˜,xõU-Þ*†E1[8@÷³Ë# £r±h0lÀo)ÑQ‘R½÷G ®Ž>ºì©ÏÝ5tLAœq>@eGTZöEï2°Ô¡ç˜oWŸâhŠ•ÉÏšÑr,g¸ïZÅdR2£ìªpmø^åá•\y`:1Þ¹½¦ŠÄsœ¬ÀXì§iù¬¥”‰É^Óû¿+P†ø 4PòwÙBõ~ ¾¶õ§Þ¨©H Ú›nï£ §'Ûv,5È-Ø…Æ/H½é\I3à©ÜN‹Ø6¬ª>R•¨¢1’$LÍ’€€º.áŸbmq×M ÑpzTïMx6 ƒhìÄËpÔ¦ òûµHÎS º•Æðn¿-”ùF2¯’…˜A›ZíK"ÆÉ{cãÓÅø¬ÛšE|CRƒƒŽíÖX3rû ôO[#7d$ˆHc¸p0›)Ò³Éoä‹ÓLJDùL•(Ñ~ÃKÅ´~g¤à¯ÄW 7 ^ÔLÀèlŒdÓ»O k•T'å\Sb'z*CBqÏ•çˬ<–'ôýHP5Î<ÐÄ ó”O³o¥AŃ3²S|»Úô{U†x¥»í6ôãV|ª‡¿gwR#5P DLq’§ l;ÿÖö©ópìÃ=ðu„â¦nqhÿg4芆;ŒƒÍ ù³Žuá¼5ù h•ÿ Ä$Édì×u‡RfÚf‹bA.oéÿczÅÒK1„X>ûX)dW/ЫcˆçUüpOßÐXZ/ÑC 7È* z²›}ê{@„º=¡j\‚$´þæú†¯£ŸsËL§)g6øGÊßOY hàDéT ³èóŸEß²<ñþä»b"°f±Ù»-Ɉà5ˆ¾ˆí재?vöÀÜLÈzJ¨ò–ɾZe{2j‘TNà€ïO£¶œàZÞTùÏsîûRwX˜g\.mÒD°¥ÙâKô²ÉLÉìãÿE±¦ÉØâ h]‡¾8ŒÜМwJKM/³à8a§Í¦ÓÐ9>¿v´Øn’ë¼<’™&΂Òí´Íi<=ÔҎ״.Ô­ù8f©Ý iŠœˆæ!ã¼û9¢é-ûél¯ Ð):Cg]{ †GñƒR‡ ýR¾JöÊ[Z_Ä%¹É2ãïïY¡\úU ŸA¯žŸU=á¾lÖD¹ bòy×®°†jØr#Øàµ*(mŽ(kØ[3­§²ö¯¼[@èКŽ'Ñí9ÖA~ëšÃŽÍ|µoaË¡Á€ÔæÄRxVKø…\{Ý×ß[´ßQÌ÷m'õë©ú0T›u¤[ž †üÛ3jS¸qÑ Õ¢ƒýIa‚zj@-‰8`â6Œ'@ˈ#½äœƒ~êÝÄ\wóÎ+\²¾zÉÔ­¦e¥á+Í/y ÷ãùþ¥:y#ìR«ƆNgI˜¶oÇCþÏWjèå×ÁOæXŠ-›Aè`IšrÏË¿‰ç¹’€€¿{ ÓT0ßc%WÅû/U>Ô¥y ¨õ·œf ‘õ^•1¡sNÆL‘ÀŠ2.¶¢M&ÐÍÛ4V—e£:­r¤ÎŒýqYÒh{o‘#)n2Ðo ÈÒ[‚õxŒŠø¿,Ã.–<•Ðõ×aõ´qk H½v„è/„HWYV} Ú?…[l_Ü‚Ë?Ó‘¡;ÑMÔws#”Jìó’rb@Ïló2tÁ`£ Ø?KÝJ‡Öí=øG±zIÔb¨§ õp§ˆzÜ—Y°Æø€ ß ¨÷æPFyÓí¼˜Ç&§Òm¼KO©øöM—£6FÞÕ\"u˜5 Ç6ÈGÞ-³B‘®±W‹kÚá.½T@G²÷,œÁò£‰ÌÍ%î&)cdÓ? Ím Ûž¨ñ{,×M˜G&áHêiSüÙ¢z ²Ê\_<áà Eó`&“u2‚›{˜[¦Q" ‚~G:Ž!é¥*·=‘26Ÿ»º‹ÆHYTŽ<òó „JìGϱ€ßßËbu‘ÒÔ²ík¡SYÀ€Äa Š;YN¸Sáäp†oGa¶$Ôì=û»‹‚”°ÏèEëÎ?m´$á°ŒÃÍî¹¹Ù]«í*Õ ï]úG®›Þ¢ýN;fl0Ï•Ái¬X|`§r ëTb2+Cmn‘Ûg‚ŠÆ,u¦õýÇ;á)Ê[[Í]—”õ_\J21ì²Á¾N†æ™Ï Ê è„§JÂ=*GU™«$ÑpAÑwv£Ónò´B6N]™¢@‚û ÝÇ&ГçTAZ±b†v¸Y NÅz¬9>Ú±¨« Ç©*[X¸jÄIo3M‹:åEóÕÚâ!ŸšÀs±Ìd^Îúþ4Îb®V┣@L +à,¨Ã¥¡UùÐÐa¢Æ¦”Ž÷Ÿç¦G[lF£’€€Æ‹¶®„jßHxéÛœ.wÝ¥[Í ¶>HS·VÚ77Ûo¼¨9`/Ƶ™yž”Á O´gÔÞ—ñÛÉÃ3t`ø-–rèE‰¤ýÄf FÄPB•.øˆíñ M=y]HG¾]ÖüÌ#G4íÁ|Fç]ÝÁ¸ƒY öiRGüåuñ¹dBHÑ„{ú#M"Ç#Às ÒêV¯ðúÇšº§Çº†c]‹öx8®Òž>_ÈTÕÞ7°mÛHšgó"º[󋻆a Û³·ûŸ 0ìÉ» žœ^‚O¤³VRM[0 ­6ûu©½U¸p7sÿ¤y /qß@æ.èc<ïÀ¡ðo÷¿0•ްó–(D1¡ ãlf° Ï‹ßËèw|ÏPF·ÓR ¤1G‹>hä2·Ugh­uù{ɰPŸ£ƨ»˜ö2Ý¿½-yq­Ül÷Ü3¹¢ p±øË‹4[7#¤M/Ý„÷ÖG󕚬Yq±þFH.bxÑcÓ´o«bp’Ê‘KU »/ÖÇ‚DX4=ø?…à{‡á]Í}žGjøÕÞ&‰Ø…@¢> ÛRÇL¾÷¤¬x‹ ·ë ’#{t¾àÏåÇDS¬+/ *·) ÉÏÅÇ}5Æu¶: rjÒêu£¹]oárxMlŠ%A§nä²èî!ÎksòÛ“i0¿®ÿ»$êNÐõÅÂãõóŽvEd ÒKgýZq‡î4&¹‹Â»“ >¹ã… Ç‚CKF‡ð”1Á¬+¨ªºYC»JŸ&N/1н3Æ4Bì,'SdK¤èºõHoŒW®¹.B÷Ær_1’€€¸«èÑ;¡IHíÏk'Ñ•n*¢û¶™ÉäM&£:嬕ù“u™¦…¿SÜÞm²#ÃÊ…ÑÅUÁàO€œa$ œ' ,Ì~]½C^ëåqºg ÌÃé\‹ÞžÏ3øÑkK ÁèBA >bª©§+j›ŠÏÈO½63Pp€e4Ð GÓ ±’kÆxŠ×ÄþñRÂêk¡YØà¢lˆcâñ,£éÜ2HàÊø^ÀK؇qâ™*’æœuŠ˜ÍßéÌùýÃãwàPˆƒDÈ]TõpÒÃ:xÆ¥Ä&Ázã»\t‰xãsŒZ–VcE\«ÏšröË.ƒ·K—ãßT{+-c¦Sy¨€–û‹‘Ã:n(Üõ )Ô÷òÑ=É K£‚û~Žt’Æ–-óÁ÷Ñ^„òj¿€˜¤€ð±s# ¸ºWm)çDF9šö§+B‡·’4s<êQ¬>s=Š¢–¼qßž‡ý\Y. •ŠuMàL¸ã÷»7xßÔ2A²78^ Ã;m÷o:~Ê $&pµÃð€å‘vÈ”¦‰FÂàÐ÷¹3-ù÷6¼Ó!oê[Òc±lvõŒÆ2ÓS«XN‚¥Njç-±¡õ$úWïJÔÈ0¡X¨Å¡+óúÆÃ^B>©$Z½ÅckcáVª³¡§CÔ´t}M…t÷ aïïZ °ùäºïfà¶V²TžšÞH#0íïÄP"½U·a#Œ M[/!¸+¼be«1D‚ÊôQ›nÁ%—ÓªÜýBD—&”ѵOá~{”a7-¼"ÝÚ¬Y»ËN=ÚÖˆÞÁX¸BjɱÉNöëβAµËM¿ßõü¼àS®†ÿT·Å NܤÁ;±c<¿ÅãHŸÍæ‹jPåj¼­(®~G¿GÅã¹þ‡ûÑŽaY‘t>á~Í¿FÎýº‡lËö#òÇ£,ñCÒ†n´–îerŽ\)X·´Ÿ%¿ë¿ –W³€p¢3çC;oÄ·éºèÙê;#ÿÌñù~ì'’D]C3OùÐþ8ýˆ4L~ JIñnH¬Ô¤·F锆/ „œöñ‚6²— ›Þö7ïH~Sy~[7‰¬ÿì(Žï¥éîâé±ðݽJ,jáf}´F‹dâÍ8Ë÷0àc}•t˜ñ‚Ó—ÂÔö×æË¹I¡|‚1<°Ãìz»¼’€€É‚ŸÆÒÖï|ì?ö'-32ÓÀ°uÖàFÙ;>˜pm䌛-è<-ð öv…;ª&y³à¤wHnþn™¸E´[k¢Ûí·Çù–%p#âöÄ ktøjdŽ*Y°K™ë¹sŽÒ3‰±²»ÙжÕ³n˜þ{ãXÜÿ*h¯wAßž×…+—ª×<™9Û]ÖÛzd'ÆRèr£0Þƒ´Øk <ã¹£ Ú¼ Gº®z»¾$ rQsûRU¼B ÚÆ»Þ--,=Ø_Š|ç_wžaX›ùÙ¸b ÚÒíŽïR·‡Q?SHšgÕ}e@ÿS"~ÓÈnÐRîy³¸#pLóH눂™ÕÂR­´Nì\o«#ë{(”V/ÓçôkBÀ›FïA¹Ï?'…J¯†ÑÉõ_ðb !¶;mÈQ‘Ótâà±i|§ñË>5oÆÐ8ô×g?H]{úﲬN“¼ßÙ,aŒ±obÄú§‡¥î]Ñæ{Ì|61Õèjƒ¸Vé—ßø_“?¸Ç±Á5I5«ãúZǺŠžÕ}©ÜFü!£'üì[ûz€»Œ†Ç‘Y-fe}g¥Êië»$H¡ètT¬…Ô¬šFÒÛm„nHƒ0S¦Ë–ÏvõÅÐ犘ç&ÅÅ@Öpwè¹¾¢W쾎â;+ÜsiæºÑ2 I­Œ'œ­Îâ7hp±þ—@¼i0IåÊäÁxcZékÁœµ ÞgèÞâå׫óáwJÔXÓÏl¥„øÆXgºÔì¦5 âW9åòì’ÒÒÉòHrâ¶ð¹ QÞÏVÚÒ3™Dëh—)µ° oÞ´¡øÈãìc¸ ÌEß”‚p&i#O4¶}³'‰kà•å+âÓH\qlTBœ™‚<­#k×g*ùš/§d¤8z¡47â P2§¶åÒíîXùø>2æ5™"ÏO?„ÿ7§j) <ž•î'¿eÃkëóG¨‘ŠüÄ6¯G’ŠOšô`½õ\L*ÎO •qTœêÒͼêXÌô¿f Š™«“,ŸaÔY/óaÂ.C­ç݉;«ZµB°¯âô £Ó‘ÐP-A÷G¬1ny=bMiœÊ1<¢µm2·d§c·@ÆQÇŸ°jJlõ¼89?/_åÃkÖå—÷•ìs CÖù¶Hçv’€€¢êÜ,7ã¸ÈÍHçxQˆWdÜÉ4±ïKÝ“Ð5Ièä” ­ÓOí›Óì Ö üöËä¸=gË{ Ä;ð t]ðÁÄrÈC[•e@PÕ'>»<ð ¾füm² Íl º®ªj{+Á¤’øØ°ëŽ…¬4t™4PB‹2••]ý\i÷y\a´Õ'ט6=¥ýž¥öœ—ÜïÇõµq×w_›ðâ®Iš(àííM|¬í™œzuSk`$Ž×l>=vñE¾dï¨`&ž|éÿh–{óìØmIãNZó`D¨?½£² –~ Ê1"Ër9üwërÀ-M~¼2Ù¢yèR%—3°×£»v7„w:¬rI¯ÒˆN(ôÄGÐh:šeº²R'Pô2!1k¸¨ ƒ3ëÑ•}Ó/QHPí“¡°ã'LËÐ6%„^ ¨ òùÀ؉·B pÈ«1®‡«2¡9QgrC ¥¥õ{w1SÚàH¢ÜZífX*§zTØ …“—ÜsäK€}Úxæe5«Äéûtcz\¼ì«]ô´ µtvãþÝrOK E)ºF"6ÌàSã‡îCf&4I’p¬Ÿâ%ü›„ƒS^U…T,’0B§–¸RLußXaÝú´)p††ð.ȶX¨M€ ¤±ÏŠÑiúVÉH¼mI‹÷/éØ#J K6¦ùW$&FZdñÒRödë¬!úúëc‰Ú›ïèI˜® ˆ± :Õ´Î)|•ÔDä“¿à¹Á^<¬v3rðS7}ðéÁõ¬ !ŒÜåj´0Ú>œaWT-KP?—UEë{™ÓÚxo9Nü62bÊ¥YáÃ:CYÖ¯ÀöÓ³•ž-‡£=Ô÷ÃôÈíû7mÖF[/àÖ) >×7”üsÛ;—H¾ÄH$#ÒòIß)Úd½ÆŠzPµ¾ §a‡8ÍBMVõñ-¬†A¶.¶öPÀÙdÄ)v÷ûÒ_¾^¢±œµ R[÷ŽÏ6þŽØ}̼=bÙN ‘ÓbY™À‹)†Õ´œûß%”û«û‡þZÏÛÚò€µqY ð;`ótt'~Ø)Âh©l…ËÏKÏ„Ãã1¤âªÅñþPD#‹ã#¶‰ÝÅ‹P.À4m¦èßd¢²1u‘âàÚ¾7Œ%Á– GÓ®„б h§‡Bñ™'à‚˜í³ä3*œe<’€€êÀéL–‘o»l©ìsÐ O<ñ9äèéÄ·¬ÖªÛjI 3ÊœY9í¨,u†)61>n‚†'ôÒ…ÄÕu ú,Âi¤k°ðÝcúà6ߪ,­÷JÆzQË~E}¶•tGÇcSJ@—š“Y)oPþÁ•z—b<ÖŒ¡¨6ÞЄªá¤tÀbŒÚA…Éžv;—ª /q4ôCÑ ÛÍð_éÀ ÖPýkÞ/Ó黸†SY§JóƒŽøƒV?pY‘Åt8|ÇsIåï îXßmÂ!”úÿxƈêñÕºOsX†©>Åq5)¹ß ¾FÚë-·ë–´§V.SSV YÍÆpÙAd&\T‘°¶Yš0z€.Fúyê¦p¿©õð3qNƒ‘H­‘ŠÍG_Ê2ôz‰»'y4ýÇl×üe±†…±ÿ"ù—⟅¢FÉe†2½*N\í/: ouÜ j ¤óùCpX£|ÅÚý f<ü!óÙ–YgçÝIÛ—àR1?׬*óp9Sô~ºÌ³^-cË+›„:2 ™Epÿë,Ùð+Å8 dîlÇÉYÆe:X,Iýr$|åª#”ïÈ|~Íë ÿÄpá;C¹ ™×Å÷,}bÞyýˆûê%÷UÙ´"¬ gJð=¥Svö¤Ù¼¶…È“JÞœr>AR´¿›÷"_×ÿ³Uduú +¹Êå y£;×!14‹S§Í3u` MŠ e¦m4ˆ‚‰®r nÕͰÀ`³º§©˜! S4ÚÚͪYËd>HhÒz]z§áçËøG ±×sò{É–óÞ”̼”VÜ}ŽÌ§õáq4¯Ò·Éï/œßd)>›Ô"7ëH5áÚ®©á G  ‹´ö¿(HÝw¥àh|šž;a¢MJœ¥ÕƒDæFy;ÑHZiûÊûµ»ˆ¥oe²ÕóËá­5ØîYZq¥<¨4Ó#·egÊr ÉÙôX#pRAdlk8Ö”ÞzFÀÔƒ3µšŠ÷‘õ ­„¾ëA„GýODL 5?«/»AŠ<|׿Éj‘_‘Å\Òg™%Cš´Å÷(éîís§Ûm‚LA(üú (\è×òn»0óÄ$ztA1À™ü¨7¤[oÍ‘îv¬‹Šˆ3riQMlFÓ7sã?ŠíúÌ©ñуƓIFÍ`¯Ù÷ËuZX_‰5Šû’€€ÌÛ‘ÇÇ¡ÆÀÖP°•^ºÎžèrMçE©Žì‡ÍëGOÝ"íyNÄ^Š ®K‹Óz¯âöû¸©HµCÙ±~¯~ù8W§ü²F‰¹­”wÊvu¼¥n°žôß$åV#ÝtÑ™ÁgÒ™±gµèyÊä@–ç÷=²^æí&l3XaÑg ç`™QÆ·óoR–Þ,cS/é2·êÖ¨ùg¬­ØL7#Éæ¢‘w.ÙËz1½¥ÅÑG d –0Éx9… üÚÑׇ؄θåXpSÏWÇs¡¯85`^ˆÙAƸ¶6÷_DÒÚP>2¬¼®,±óT8GAªŸ(Ë€*b-s´ÔV-÷®pãæÞüþúp”2ÏÀ¦„ΦíŽ(ÝZu>I›\p&»}„sU™ú»eÁÏ?ih|Ž•¥FI“Ü•aÙw•;úZ 9çòâ¶Ö’NwËÙÚÊ=Lø%˜$Nß4Ô?<&ñÎÿ@[p^`Bç 1JWZC2ãÇÞ â^⿌æàOÃ"ÞÐŽrƒ?Žc/pÿ \H•‡ªKëªw”ß%“ónV_Š…¾ŸHDã³ÈÀŽ.ÏÝH}YlPô Sìt×”ÜÏ:¼·¨ËÖ3û7a êAM’}8øBÄ1–ØÙršoÎìt‡De¤1èÌ£Óõ†çd·,Ëv`Ï¿Ê\l! ùjIe„ø¬ÔÔôpLµ£¦QûæIâr¯p1½»nÆž~ÜrÑÐÕ¨½?åÐcï.H=<޼:ªŸ+SÜ/5 DÖÝÂ=§éÊïc7XÝÒqYh~èʪ°?¹cA›.p HUZ®9ö 9¤åQÃIs%ôƒIàØr¥ÒD!mÿ,î´°³c\ î CƆ­yÂR‘Â)œz]!è*…²pɰî×—d$«´]MyÁסÊÑ‚–>;s3’TE;ÄyºPLy ¾TM¯ú Î&›³F¸/Bß<uÅR²ëbÃ~¢'ÍŸC@F´?ìu!CHŸÞø¦é?ÙøO®Pã@â¯v¼¢Ýâjfé6G¥t݉;;·ÂÙZ´×£,}IâÞ^F3uŸÜ ð8?góûô—çÛ;–®ÚOã³— …Í1¸&ÖíTjîågîbÀ*{ß°¹ü±pDWÈΨÅÐìtçM“®¢èéØpŠxHëf:þýü;žŠ+£A­£Î<=×”Ù¥Á¦@‹¥$÷9¯Vé)¢dÜèËû›+Û#¬—3Bçòl1Í$‚^‚•òŠ )Šåö7\1t"){ä0ùÏò»%»/"–”FøcÞ5OÍ6«&ƒ¯ž:3è×JŽCì=Mn7¡U¶ÅÔ>´{BSK$œ‚NÉæ/àœ÷ ZÇ´f^s˜-‡>JvªÎAsG†w~ø´I–yúWb#2²LÎWf˜à/!ŒÔƒÓˆšeb+Ÿ¡ÀcÙ^Gfïg4X%SÁ‡§6I*Äéˆþ§¨¾ vb¤ÂÝká$zÎY ê ä& Ù€Š^¡Ð¹o7EËŸ…$ä¨fÞï5æÌ¥úop©«V`áÌ 7:ù’“íØLb¬F·¢Œ¤N­¦­-Æ `˜önDþÊäÒ”‰A3˜ðÅW‘%ž¶ìë<38k³Z³ÉÓ•Â[©P0ÒÓ9 4ááÐôQ‰ÞC†Ìk•H‹Žµã#úÛë²’LÝܜՌõBA¨M½.ùÂaLü?0@@q´YKöA¼hðsL¥áúÊ»!&æñQ+/ú2ÀžpD”UÕk©­®‰ü¤šÁ<óü!Á` ÙCqMQ7Q™½ºœ©@îáÚTª¤È\õØc¨¢;Xà ð­TYΓî¢5KêIuÓ½\M>.æZ·_¨³ÀsöóCUwŽÀŽ¡ÆaÝ'[ƒÞ"©Ö°DY«\U&ôï¼Y¡âôìrO÷‡ñàæ|¦ {JþoV,›Zs Ú¸ˆN)Çtx§È·,ÊG “‚ŒT!þÑuÒ·󿤲]d ±®Ù6¯] ÓÚÖ ]|OÍÎM…}§TˆT –ÝÝ0€£ˆÌ¿ä‡Ý0öd–‚÷É¿XÅ2ý3ÉÎS—«gMù›Àð·{ß!¼“^mû**ÖõKË“=)3·ºƒöÊyø;þÞ$@”Aç 12"œìˆo‡ØàN[›w¸ºÆ4ºnM„ß-ù›³ŠI܇NûV'ù=­ªç1eÀ­Ý¬7÷~(·!bU@äz¶í'8ñª·É10ô ÞËÕÕYIe„Ù]óWt¡ÎêIƒyüŸiú–ðÂE=‘5hªK¾ÙRÙ´/"¹ š•¶28yœ^ÛjÁ6Ò¶TõW­& ?!ã‘ZÜoÆ,Ô5´Y„OÍbæa,„«ºÁh\6ª¢ÕÊqOΧv¢>üIePÇ6‡ŽE ïlD®© lQ…ªñðŸë]î‘"­å4±F25|ê—²ëìÏï‹ Rkê@l¦À#@ÿ‰vûÞGøÜÿ¶†¹ÑýC‰UÈÔ¹ôF›™UÔrLgØâ×r¥gŠìÜ G@¥šíB—`‹Š¥§j‘¬d×2Ÿ•ÚµR]vç¼q•‹Âyßõl[enü0\ºŒ#Äm`¹ØÖ; -ñÆ8MpD Vªf„Þ b´³‰ÊaÑéxÔˆÚ]þ¼Ï‡˜J|gÔsJJŽcY^U…Hµ‚M¢W37{èÜ †ï4¿BÆÃ,MÀuiÁ:ê3ç¿qW²#çÂÞäovÚol Ô¸Uó%éTOªÒ&ÿR–mšô0¤ªæ%†-1j’€€ÛÆ+ 0æRȃFÙŽÇöLÖžã¢ôÖ½U»aÃÿOÉ 0ŒDÏÿoã±À%'ðê›^éϧtÊêYD)ã;°…TÓeŸ:¨eÓ˜¸(Ô|šk¡¡7ÏJjäv\}ƒ5:DúbÌx^ýÔÀ›c\ØYÄó­6ýæ¬zР«–3?çìðúÐÒŠáÐÉ ‘49ŸûkØj¿ïP9N†Ñ›>.¨¼OUj·QæX„‰ï2­Î™UF'QQ͵œ=šï1o…Ôk¹óšf¬$ ?Òšh#8!ËâÊ‘gö þ݃ÑMsÁ··—9tþ•½WHÿ`ð6%ï÷¶gL™™öòÚÌæ*üì¸>NåéH¹ÙþgJ•O6OË0öHîÐð°»8™ÞóñÞ%Ë-gBNoØÇË쥀ߗ+ñ*Žÿ 3ÍÛJ¸m¬ˆxã“%öH_‡rŽåAj®¦î¸îo­ÔbSü­>åÓ6ËÅÿxù³Reç+_]UÛ Ù?úž×â[¢¼rNô»¬“ÊŠgqŸª5&œHÙ­·ÊÒ®òÞYT'dºÃ3òåEa|¡ÂÀÇ0Ú8¥°ò5F+÷Pt1‰€H"Ä›CžcbC¸NdÀ9•që½UI¬eÜCÅÌ‹îˆúÞô()ÇŸ}ð µö\/xЧl7€ÄÑuÎÃÒI;›OmJ†È©+Mbr]fêpî7¸˜Þ…z§|·±±ÊM*sÙ;è=$vmtN ‘]zmª¶N«KAxŠ…TDö)É#×@“^œúŸÐÄ/¾)+¹Ç\Š ìÚGû7ŸgS¦æÔsï}EÈù6·UêŠ3S¥ú’‹ÚלËB"H^x'ôk‘ u~$ÁQ¼x²ÚfQ˜‘wIºMLîød§ÎÁ[G=ÊipKø${lô¬¡~’Œä´J²W{8âñqÿ˵¤'„ն݉;ÖC²«Ä6£\j õTvþå;—&jJ¬ðƒ¿:r“²a˜ÃîsŽÛTŒIŽ)@?XöJÂ,#€äq-¶>}i¯Û§O¡bçžî‹?mpÃcWAÑîPâˆs— åck:> ùΖiZô°ã'`zÏ…&âß(ÿ£jä 8ïž¶Ü|¹×¹Eज़¼çÉ ’€€ïþ ¾.Ç­ø˜µ4±ò^ÈHÝ5<µ4™ùõŠ*W tãGl‘ ‹„ÖpPŒÛ!²ÂxRßµYƒ8iôL—ÿÝTŽc@˜5©rÝuðNêЄn½ÿB.¤œˆ&¬ïxÚ}ÿdžÓ}Ö¸Cž‰©übÁÁuRsaÜ™æ’=€ñg3–Bà\‡±• 3wA¶&ø8:# —Âîdk[Ï@+壕2ˆ [è¶ûS(-xãרމO¯zÅY dÊ|âù»ÌÆÞ.ÁjSâ©„´« él2Ú‡ø®2?ï°<”v…{j ìnsB(Z§™’üBñH ²ù’ô¶-•u4ÂÏó”än£B˜e»Šsw¼-À-¸EÖ%PGéBóL©™ÜG¤¦+(¡%ðlƒp{7(]ã’ai~ ênº²5p5áõïéöør`¤•Úû„áËO×M„ˆüIâVE³nFÆæ_„&Å·ªYÙñÑa®ÈPßJû—]é]…$Žy¥±Jèþb`΂uJZxƒÑ…&«¹Îë¾ÛòÊ ÉD-Š'@¯P¦áaù‡½eæ‡ïÏ}¹cØ s¾®?PB4#ÁN[$ª j?%²Ê&…> DQO5d•/‘ñÅPØÓöxF Hpö¢¬ÜÁ–Æd]lð D?7ý2xq»r§?_ÍÛ²ôîJ)ßyˆn½ŒÑ•RP÷6ʘó̸m:õ çë¾RÀ‰øaË <«X¨nxò¦£b‚41_§Î8—ƉH‘¦6íáð÷§CÄ…üdÖ¯P›Ñð_0ü{JÃÛ—b&£;‰¸ßñ#VÑÌèµ­»ò¦,öØoðý‡ø*É>VüSš±m;})m «hÀ¹ÖEõ3ŸÜXóüüÿÄ'd‡mCü>³  !EÐc´ËÒëß‹#QOzu/né°ô‹.ÍÒÆõÏw»Þ[Ž ƒDø—ŠŸNµ¼ŽõpIëyÏ— 1ê^-ŸôÖþz:¹ÏÙvy ÆÝ-@Ó[ˆÎ«G;É~—FøÄnªÀ­Ùô¶ôô Ì¥ ·nÛ¢O;åvJbþ¦æ9|P®=+Ý_[gjׇ¶D¤ˆð¦¶ímõ ôžØàNÔÎôÝ®Á¯D_¯}â‰ßUn.Éo˜½6y~B‘z‰´€g’€€¬´ˆÁ w~ïãêÜé: ¨ëj³ƒØ”qm·±¬QB^3+½t£Ì£˜Hk_1QœKlŠ”Ž[V4ýxâ€ÐT5Ø>F“ü©í®vœ¾¬›óÀ–Œyf£®wŸçóh6Nm-&z>“>aîZ¿–û©û:É<øª@no ‰¥šiŢѲÚp GþÇD7pñEŒ¿Vç¹0©ü¦@ã…–ÇâȬìˆá~^Îd²Y9}«­`>G·ß[!1²¯éÿ³rØ1A.D`“ÃMdè‹ÎìÝmT>쯭`Ñ/°&s_ Ÿ¢Ã–Ò'{*ÙLKÇÑYë ÿ|s™¦É  4&G«9…!ÜŽ‡æ¡“Ö[3Ƹ [D­î7{#¢ã 5 Ù]™D]€¼ñÝo*föJL³@ 7lJQ+Ñ禫 ñÊzœ¬¤Cx]èÉ€ø¾²îMõú½‹QªoöÙxR'{¬Îôa°šƒšuØ)sd4Ê£ á½ˆÔ, C€¨¹©€' H8Öˆ¬-£oÎb"Û„ÎïPƒ^¦Ð–ƒŒÖ0@`âËF$³ëM¡U va÷÷X ½ #ètaY®*È…ðŽy‰T“fQ}‹ý»ÖÂà-9¼­ÞQ¨ŽµVÚ2ªwÆ q¦JÝAñÖÞ•™‘Ù•-ß«JÚlÖzcbaSÈ}p‰V¸pˆTáÛÀOÏvâr\!£Ä–Å=69YÓmY®bºO %¸`—»éu]ù ßqÒ&†PÕþx¨¿Ýwp奦 ¯MvÙ¯x®=¯Ð5ËHÙ=:vÃQ­ÒWñifnŸâ¤³imç.ÜêHQÎ#ÞþÚ+](›é®ÚÜ•bfx§uùN3œ±§FëU/LñBhH@»µo«¾¶„Lúlk—‰çŒ@=®1Ðöä°_‚–Qê3¼t耦6n±…"ç´¨k“Î$–˜^s+ ÐR4%_l²¢ü!(±—)Ïé\” Pù`sɦšw"*©œï3=ÜØ©¡õÀ$´5fsbœ!:²]h¯3Û7pµTÚZÎtàÀSq?"7#Šˆ:R©|Ë»‚èïÿåaÍ [œâµËŸ/ó¿kCŠ‘;ÐÀ=ýDç2!$ZSdõžG¥1§Uƒöý qkÔj % ÞY’€€Ð¦ˆ8FNÈ–{ÊÉRw§ÎRc1o,äQÕŽŸKó?ú>ââ;©ÍÜÆ)Ô{ÂÛtƒ¼›Â^%è€[gE‹ä–ú6kbç‚ì,½MÛá7üŽÓŒ†ïÌlðhø m§—“ëÎGçhÈ®ƒú@­:¥£Ü‚3Û‚{6±0‘ùÍß³âYõ1kº…a2{iW€Ô™-Ô9¥r&ö"¾ÙSW t­ï?"´i J϶8 ò ¿È£Ñ ïþX½nØû P–PÖU®Ûm¨Ô#ˆúþXÈg¤ „‚,^ºìưQ,Ê>*Ø#­¾v¨©´oCLœãdÜS›…Nˆˆ±­ BÚ![ çզ뉿Œ¬ƒõ„ª_罊¾—D)‹šË¹ÃD[ ê ©ŸEß ¤îùäã Ä¿äZ'¯k0z:ˆë¦þÿ=ÂÚ_xZåØJÃÄpã´s!gǺ÷‹ex³òÉM+±²–5Ĥ­…€Âc=Â=:#ßÅkðìµJyÂ4÷¤ (çP0ë‡s˜©yêZóÖš=YÊ‹Ë.“›([ãõd£·7]l5¶+¼HwævMEAGW|M’"q-ÊÏóø#¢x¯b³-â%yxY‘s通ÛلÀql N¹ÚÌÀ!)–æ–çmÂùéeÌC¦6t¹( »ÿÊtzÁÊ ˆ DÖ¥kúƒ]m<°érüŠò÷™p2yç6š0p¢Þ(#|œ¢ŠVMtrH‰5¡§òŽ"p…ú‰–ñ›´Êè4Æo®’ÓºUkyU²Ü}Ûª'™€;çR—{{}k>øüã¶àSE¢ QÒ]üpYêwcn]¼ò¾äOþ—žÈ¥£IÖˆ’€€°.ú3ÄŠñÉ—¾÷´—S<öÇÏö韠”æ'H™’²;€q¬æÑ›HKï´ª”™Ú'Ž×èù Y¬êþ‚\#¶§ÀkþàMpã…fu3!KD#yªÐpȃ‡a9"e ÕÄɇÅ+ÓóÃhi`ó ?P|Û†w‡“EeÒžÄñ22¥™¶ê—hâþ¼²…‚ið™MÁ‘HZ%“ä…÷¯sÞ¿½ uÆ7DËlŒxÇê|û,ñÿ|7-ú^rÁ\¯Øœ²2ù˜Ç¢ °Roâ·`‘ÖËTçøùòÃ5Q²—SóNAfsšëåÑ(SWæbd¹:Vøqfõ¦Ñ]l¼¾©L˜YÉ _:’‡OÈ?nºïñ’1ËÒ.VìÀ½t¾ý€v÷Uõ{÷¢d˜Ö£‹î™†­þß×ðæj¾§—8cU‘—Ó]òïXvyéåúÞBS\ÃpÝä¡ ¡WC—N"ý¡Ýx)ù/2ÐSUÐÑ:ïCÏÈ€‡0~ØSÙ¼N  Ÿ@èË*3W`b^q†6Á Z—žGAn©=:BÜ<§DFx“ÆÇç»M5Ò÷4_Üõi®¶Û®EâYÄÍ…Nµ;)9Ùcãµ]©³€æ#Rp0x¸½/ ÏXCqÆp»BãkNz¯,‚R›rn(²Áy"½…–Égµî»P;x ¿XÛF©†™óãj{&ß'%mà:Êuñ!EíF5G&¨Y0;pK¤™S‚”„m±Ao8¦.ðtŒ–P&áû+>£K¥èÐ>œ 6ä-CÄMÀch¢Î[¬TH29.Ó»ªì%«/EÉùjŸòºFt}©ƒdÊJW®0¤=,ü¾%æwzN#,2øïðl{sÛ좂™ŠD”j4š‹xz?ÒJÙðx…ìxÂíùÇu¯Ä“€nv:j¿­*/&ÒQáBãߦÐ^gV= Åñ ƒìhª˜§Å[Li‚¬A¥}xRˆlDƒF²G]ȵæNbìÈ̼™Í2¢¥¨ôþð™NÒ¹0Ò‚GH“IxfètÎÓPÀ4Òñä¨Å",¨n€25ïbF½ÂƒR«™ÿSXÖ¨§ÞÃn#‹¸Áñ…û5½:´œtƒ»(å¬e0Q6 Ò’f_§×+¥Êy—½™x=ʃiñ øþ€„ÃÑöv¢¶_G–mƒ¼ 'ÜeÉd í°És€„'`Åöiô˜¼üaÉï2»±Šp†) ö›ôÄÜzzª£ìzÕûLÛotP„@HIèm¿qô+öÃÿµ¢1ih‰•,½ð4ã#L¢Üï/óM[>bŽ7l“¡ô´°3’€€Á•K©€£qËÃ2¶ýoP5 ËXZí¨É×Vw°è§Ã ƒ×¶ƒ ®,‰äez¦¼,’ÛWGAúãÛIné¼Ñ+ÆpÂ\K­Ù\vÀéùòw¿ý k{ûf×åNÛð ñ76ns‡ä6Ó@¨¦0 ê&Òòöõd¹äªÿKúua¨ýúÕ·D*XVS£œë€SI[! ØÒ×a±>ª Íí)Á«Nüt#'=¤€ û¨Ø ®ýâEX ÅÇOg&զЉ¤³—å/U'§Ê›‚Ò<1’Ä…ñ;/q)[®wÍã-7/Õh´ÄÙÿðoûV§å¨DÀaÞvâAÓ¼$¹ãûU”R쎩órM…Añ©„Ÿ³*\Ni'½ÊÊ<õ¬ÙóûòK—8" òÿ‘4ØBÓöËÞ?¬½ÀóôÉ* _˜ˆÛŒ¾ñõÈgŽžÁ¶(†ªN=hp±Àœg™g|÷“^%>&x³¶CÅU y¨cÿ³p¦B¹ËÜ$;<}1Å ºãåw°´+q×_&vôöW\ÓJE{;*u 9µ /è\Cô›ú(HøLcû|^™dUµ…½ÜeÀ¶.%äÛMb3|ÆÑÌäsk8kÄëÿ>â*qAF–Þ0ãÜ—x^Þ ¶˜­ÔòXȹ®¼/§¬’?ÐîñùJ4 ™=N}0®à”Ѭ-ÞšüMè` éø¢Û¡nFÖ’Ë£{Œ¿[ç‚=U Ðè„yT^6A¦8ÐQgq]y´ôù‚fmÒï–/ÉPˆlæ|IoÆaª•DÀP³8œUêZm„Zº¾]rrMÊoÅWT°Ëi­ìm` v}ºIõ½µP¯yL¢ZÑŽ”6ýdù”’}¥~ön¨ápÎ,Zç=ÿm­6*3òe˜xè#ße>z%…œ;M©H,%Eìñp 6„¨:I=m÷/òí¿}k¦ñŠUàÌ ž ßG¾y_KÞ°ÿîv­0P·oø[­8-„Hj+ÁŒŠíÙ‘ŸsäÜC„€…¤S•ÝÄ39¸ÔO%H KÆíÌl "–×5TÕ˦Î"þõ—äìºÓtŸÖ©xõ,àV£/!iBJ j€ cžs’€€¯õíKÓëV‘ºÒli£\äÛ! `-ê‡ç³êÔô 3Qàaë•‚Ú¾^7¹°}áî{.ÝØ& ø÷É•U.û°ÙÄô·K6¯–x]ìÊËÆ&”·V$²‡ñé2¿m .÷ ¿ã‹Mñç¶JQçËè=þÿã ÂÃ_ö`÷kóÒ¸É.±:½?k¨_ý¿Ð/¢”€;SŒSñ@Éâ[¢‹E’­ý-=XQ+h(+$§ˆZû*ù®'S±ƒ¦®œÂGëäŽðßE¾ò›¤ØÄmWtyN>(Þj$´¤¾_*ĪÐ6rö A•L‘¤ä¤ÙÙw'‡¶Wû;Éê4XÜB6cûÍ`0: ¾˜ø¢U¶ÃѸTI âÎÊ™:GyàØœæe5O~q­O#R3‘Œ®Ùú½Y ²ëágTìKQíFMÞÏ ·ìÉ£PËÊ  ƒc3@¯ŽíI£[˜^‰:$gøtÂnº`.¤Y‚´¯‚3’ ˆŒP3F·&±‚+ZºråŽ1–3ô6ã¸Üv>×Ãú°Ý›"µ¿{;o_3@“Ö—W¬ù»· þ¨²5A“  mL¼?«2:wtñÔ´gyØŠ OÎ7òy£ýúQ•ñxš.ía7˜,ÝÛ7ôñïÞ4:ºVÏyáoMÚ¸#‚‘2Ú)’€€»o ƒUªV§@%8‚©Äøü/ó i½„ä7{BÛÊz¿ÿ΂‰QÈ W…[•²P°éßT¤éA¹t©:S 𽎃þÃÜ||S4V@5Ð29Ê öóË4öSìØÚôny1C˜™I_²^M Ò…÷gçoÖÊ^9:H¢J¨Y¶OÆT)ŒÐè?S¤$G HÙ¸Þ¢×l>b4˺¡U”/<üý\z5 aÈ—J;c¯È”g$·ä|Å!€é"G|ž¶nmÓê«­|¸ä—fëyÒ~²làãäëÎRø°ÃÌýüº"m²“gŠh12V~~؇W ÙwD”Q­J»h©Í<E©ÎÿPnÉ3ÏC¨û5ؘŸÃÉ1ÆW@q®Õ„ûÀ›†F†Š`CelIl_eÃ4§ÎÊèØ8ÓýÛ ¹—Mâp~{訠ûC ƒôšuõ­Òb®àu¼&71ávß”¦D ÃŽB f?ªs!†ë\¨Ð1ÐétüaÙM Qãä‘Ç›·ç¾y£”üaeÆžß$ã/p³¾Áü6Ûó6û¤‰`Àf‹˜ä7f±.²‡ö4þebZЬTmÊGÊ7!w6Ìs ‡úeR¼ÄaLùY3‚váª}ë ÿQ³,"òUÖ¬(õFJôF²O8Ó7#Ðјö XÙû |=hR£ŸO}EâÈ1¼Cîûý¼çBˆ>ÔcÅJ˜#À 8(T@Ž#,²ÈQǪ%õ£3^ ÌE09žM‹Œ ½vxåÊIÃÏYÖÎeï,³µÙ¾qgÑ3ØÚxtZÝŒ›UÂ|"ùŸ{tÔ{DòýíÔB«¢lmÓý5Ý“[šÏËw+ªáX!pKnï’üåDæ@¹¯RÏ»œrk•+O×'œ˜Çug¾§£wjv6åÈ]޳­Ïàü³™#/}ûÆLáêM&¸K}¬®àHea6Åë™1q< VhAä#È—=ý T8 .EmÐ& ·Šýº.Ú1|þMÈöæKøß˵OK ƒr ¾û_” žˆð’€€KUx)Oqæô|Oî tÀèÉ„ÉÙÝ­# ʤx±FÜ–å%ýL̬ÏÂú¡G±+– Ð<8s‘è¾§¸^Cõ“’xd*—’ù²4ðÎɦ/ßt&ž\¡ýÃÇæ±£ÎPL÷0ég°)îeý»ò€еíaV!úB3£Öxà¢L w›D›X2„Ü&:õž<ÐÅϳNJw¬}òÞvÏ‘TÕ’¥y×à¿ôŸÙ§æ]öCEJÅÍpç÷)¤gÜ÷ÀË…åÛ\/kŒdSϰ"”:kˆ®5Ê æ4'«SQ¼;þ8*U%|Éi–Kö wmÁ<âαÐXâ —Ÿ7âh÷,rË^*7ßÛý⇬šM¨®,s„¤w>(/gnø+‚$/c|*~E¥?ù^)è¸$iY Ù5•¸>Ò £Föì>^M¦úC c>òü!2–Àñ+|iÅu§á¤7üàé`&‰¾ÇL3³k"® &xïb'Ôÿ'ѨÏ%i† ¤/¾Ú)çŒ uÃæûLy^³ZscS“€ÇKÓÇe‡I>åŸÀ1Èý O|”9 ƒŠÂK|Æž«vPÔrÌ,6ëqN&1P*ÿLß×~ÞvÜý8œï~ê2qäuÄ)ÑVŸ/ØÇ1¬E©ð ù65xÄù…Øá¶ãv(…~g‘ü€áJŒ“I5œRQ>¿É8¢›– "rû§õƒbRÀï¥*Kì®ìÖùv¨±áE“õ’iöMg¿zà…‡ÈàWD³‘m)»< õt‰Ä0‹åš+ï$©£ýf–×X«ÿöeßݦsš·ùQÞ© ©íèvCÏ¥‰`pÎ-‹Ç!-Û7uóªge: L€3˜ä¨CÙŠÊù–Uh?Ù?½f‘}Ùòa@ŠÇgD¨8\ù™Fî/ÍÔŒJcoä$P>´YTÕš/»^ >qDÄî±QÓ°‘9w1ïÿþ:áúï‘0Õbð¾&œJ­¶¹Kã°>sŽøÑÛ\þR^TÃèòl™¶fvíó'øøìøO4p…Í4´„À$®ÉvŽ‘5 HÁ™D“x—ò=¡]ñ+HÂ)“ÜaÁ4WŸ’eð£öì¹cT7Öii¶<ȉ/TáÀ‘#`cZÉßËå#iMy€‘¼()‹wkš?´]“ %HÝ'€ÂÕô¸•ê]‡Ñöù¯ù?× y*"5w\®Ãµ†ãâå%u(·ÖBï ­™IƒTø‘„Œ i0K9[f® øµ´£> *7„¼;c-Ô…íü?FÖ/þ éå+äÈAp€{®ã¹Ò{EÚºjÈAN¼XSÓFÚty½l{>–„ÿլ阨ãPh·ò¶+há=¬6Ns<H´ÞÞ’}ó‚Ü“üœÝ{ð5Ñ’BïAá@öõÔÄ®¾^ÛPˆ:甞´ëØ©ËôÔH/Ÿ ‡Í 1•’Xåê\ÌáF$e´'xÔÙ’`°ý;:»†;ù¼ \ñÑ™öª›X³4”VÊfw0B¬ÜmJ°¤º­®¬‰î*Åysž<•çá,ÂÙ—_q2}Ó¼†ÁD¿>ýîË\ ~þXr1šZ´;ä&BWé)¤ú;Ë`ÝÙeJ¢“ÉV¨šÈm¿ˆ¼î÷J—×Û_øÚE74$Fçä ·Ú~|¯ÌRþ¬9ôSÓo¢Ø‹åHR¼pš¹úÛûBñŸç %~œÛ;…òæW^r|–”eN½$8È µPpÂr|Ë×+¦ÓíW@tܛؗÝW;íÀ¨OPÛQ"81Ž¥cr0PH™Ž­ßñ6 ‹\ãׄ+;™!Ÿëõ¯Uúý[5D¸ƒ.2ÉÙ¶¹–Ò^h7ù„²F3#ŽÊªžÅ½ŠàÈ" ‰8’€€Âh÷Qîd!»žMâ†l’}%ßF€Û@m»xH$lÖv8aÝsAKa1aèÎ_×hýÒ>J‰WøÜ£ÕõÞ¥%åòsP«„ÒH ‘Ù ÝZQFî^zž´xýy€8E»‹©U¹ó¢0蛜眢¿Ž°¦C{v,ÆÄ÷îYøÏ!d+ž ‰ÏÉl=hûÌf§7dÿµšBÒ»õÊ•nÂÜxôEŽBwj¤Žî"˜ˆæÁV­j–gÉm”xq†`z y¬ëä™o“2ðïúÄ\]QBÒ¡qÀ-ܦˆÉ½×mí¸µ&BÔ” Ä6ˆmÆžñ›¢Âh÷ýú?}6=ŒælüÛCG˜eÉ µš ï#3ö)æòqƒßÁ{¤beq©LÖ•ØámŒì q¿-22#‹BÇóD\|RÏÇKàšÇU|6sü(“_﬚X„)À1àøƒCéíûņêµIYêcr—î®@ÇßgçÞÓþÔû»,IKÀ¼ ãäÜî–ã9ߟýðø?ÎVpÓÑw¡öžY䟦~ ñˆ›¾V`Ðvͬ#ÍŠ:Dy›Ëšbšw…yËmŒI…«yá Ô—l™RÊ’vïkÔ‰‰À¾±.£•j÷úÃ*eŠÖÑ£ÌÇù¦?2ðèœ-aj³Ñ6ºÊûWÄ‘)ï!/·G•üÔJäG»Y¶¼R_ |÷«lÉC-ˆ»PUóÜÛ²ˆ,1DŒ™0‰Å· S2†9Ô®âûƒå¿·†KIÜ"¬µõ›xW3žz܃IÌõK?øN=uÍæ ¨3Çû‹§N–üˆÜ,íÎ>ðæR?²œÔ7Ðsâdé ㋉7=8) ºïb™m<ãÛ5¢íãï§Ê]± 3QÉ)ï ÖÐÖM턬ijàú¬§° È]U €2,©54Úi1¨ÏÚáäjzŒ„Ç;3zÊfZÐ×0¶Êø0-8kFßö¨^TóA´….­ïf¤ßg¶Ç›ü 7ËÏq9ÙzN³ç´«µÂd­>9y¯q#ç‹€X¹ -8ÎÇl‹úIõÁöª…kK«¨¡Õn…­wT"¹èADÊšH £w ¥+³å  ÇÒ­“·ðä˜ñ‘óµ„ÛaÔòz¶[ºæd V³?’€€ÃÑdr,VAuÆ=žÓͱr¶À#ûÎucšï*xçÿ–@lwAÉ”&×>NL€ZÄÜž?9€¶g¬œçô1vkBzØ·ÄpÛßÙ• Š#|¯¤$ŽW£6”&:Kù¸ìC¢RãÙ ç¥fÏ,•ÈÃf»ÓmnªÜ›gz°-9AðíþÊß͸•Ìøcdcá`p¯j·:" Å‚A0û3ÝFXÑËzjøy#â«(sã”ÝËófnŒùë;aXøt™Q6@¼!GsǰÇäl 7­¢üÕA¹í°]­-„›2œí%ÿ)’g3¥DŒÝ øE‹jždké.­Ÿ.rú¬ ­ËÛÕÐP“ÓUO®jÈ¥aR£sÈyÿö¶oÝò¨n³ ü®*¨OàôÙC«5ªYÖyñàïÁ÷2™B0“Çв]ÇéG ;g=p Ž÷|³«C„­`UGOߺwuLòŒ]_HöÉWª‘¡$éÑ AðY»äºØ¼u5wFõ¸·Š*ª$ˆaÉC(ãÔµ’Ù£ü jr·´d’¡W!Å&ú7úýê5h†\úèÈ»¤ÖäÂlÍJ˜±x0&qìbSØøi‰0)ÏåéL÷F03±Ë Ö´^‰ÿæ÷>Us«Æj„.uVa[ª\P„Ííæ¯â&.½£üÛ© Ew ÄFqDÞ­¹Y¡#E'{vãji?¤üDkH~â¼yÈF¥t&tÐL€tÀÃr#Še£¥fp&yOý‡b?I“û=¶}Û{‘6@D¾¬Ë1­ÔCwtD6Ñwß™˜äÌ /á`‹­×Dˆ’³GÜïn¾< ¿P:²Ó@û¬ZÓçEB6½ÓŸ¦²e%õ r <ªbÌÉ÷•¦l@í(´´Z îüT„²¥Ä¸>溟C ëšÏ|ëlH¾jÌN¦²Í¥ýª î­“u=ÀŸÇ›á×5úD#Qüȸ»Z?²Æé±ÒSæM ŸO7kªõùzš¿NFÛ¥| ™jó»ZV;ŸsÚŒš…»ªèþ–‹ZXùÁ”*-·æy`iƒA)ššúyÐøµïm^ß9OäØŸ:ý7à]¦Ë ÇãüƒSÛQÿ˜FkV±ÁÈÚø¤ƒFã)F…“¦Ñ`›ZjKºì×)ñSýÔoÎçšJýÈ,CÍ’×GaXÅšùw€M̓mnâœy.4S»GËNOXÒÃóNqÂVÁ8«¼”H@¶×Ìó5SŸÉår±ìÍ›t»(Þ‹,!- ~¼{•š¾tܧ[u[?«Ô>E¢†š”Æ&3l¤ IZA{Bf®²Âþ:£zÌwõ»,Ï‹¶ì"šf¦l‚ï¹ “PrtÒ<¶¾¤{3SJ¶½”r¼„‘¡žu¥ë˜º³ƒ1]éð…%È$LOx䢮Yƒ|!® 6VËŠÍ*ºÅ(ºc¿ñ* ¡èø‘‚ý½*¶Jâ¥Ïû(åMÞ_úJŠª¸DuMa·â7 iÙ#= ?bŸ¸ÒÍ×Óà¬;"•:>†{ïØ]AÛg/áÕøš]1¹^FéjÞþávÛe½s€iTS+vkSBÌ ‹ýû×?ão©f—[{2ê®[a<™Óñí·d#~Gw Ì.6›älª5‹â3ý½IÑ7úµyeõG÷ÁROÌÈ%ÖaUÜ­±p8‡Žê6'+„»d9z{`YÝüñD“õßÑïtµgËNÅ&5]8bçI\»îãÚLxÍ•4_nìøe¬õèë3©ª2X4ó`jQ¸æIţƫWxÃLùS•Ö:$'é &lÔQà8YG=z—Jñë#@ûÁp'õÖÈÓZ(ܹqÕq8¨/ì!›µ5Š‚$º ̘ÁNY?}MúxEÐÆ£ß U³d8¤Orc™#æ„«­~«ÕÉá ÐÔ‡ú<'çJŸÙ|K©O¼ŠLÒ%˺ åÃå{2=ÕTCÓÐ šÓ‡ðb„°–Àņpý§-ó8‹ªÐ°_'ûxÐÿ3‹/±=þ4v#Y/ß#cBå-Vè!wòòe~.~\ŽH4{NlªzlDÙV~ЋÌÛŽáQ*ÌxdÈïÀ„œÌa ¬/´ýpÌf’€€í¬‘»IdiW—ɰTÄ]c4òHû· \,PO d$±XÍxHÉu»HÙB'Ï,> ºÙq»ëª eÓ«>ŠÝ´ÆpãËâú»:È¥"^nmú÷é,¶FmF §áF#©qCÒ•#;ÛÂ_Ê×m]V``>쨋ËtZAµg£/Óè9ò¿ÙʈK_”Q¹é¯ Úñ]ˆ…?~W7Àt',ã¨6}‚Ú-»F|ÿs€šOœ eê-IgÙœw/‰hçæÍòމwì·†‘}ÕÑ'ø/êp†ÓKw:Щúq⿘!©3MŠTßw"ø1þ’w~—4ÓÎ_Qå;£šlyÞ°òQ©Ýµ€ö¾C±ó&î/(IûìÀå$Y¡¸Êz5©kÙ°ÀÝ:>MàÊdežžOCÁYxO¨‡Åæ¬Xî÷¤¢.®[—Zò+ª¤N­ 9þèhX¶¿ÔŸ’Lô,12T3Øøˆ¤ðu 4.¹½Çæ÷ Øã‹üÐü|¡(ökîPhnhJ>ÄRú‡•²Øñ„AòªJí®¹ßw6$ ôeŒÏµ âËêÑˀŗ¤1 óI®ú8Z­Eƒ¨õïX€Ü¾¿É u/j<›dWð¨ëüž§j©F-€@1µÇØ_Ô~4—†3*a¯i^NœI ™Áá¤w™•ä§Ðªò"#—"šP¶?Ûž(:•jÎÍÍEªuS Wœ(ôoü`Ïhi‰9¯ P/aÖ°3 ºÁ+Zc dx‡*‚Õ‘@º¯m«ï»=3$“ó}ÈÎ#ViÐ =B¿šÞ“K¶ðm%Ž?˜“=ÖìÒŽ*ÿ½š½C®Å½“úw[÷ ø^ê±+ÑÞéBÏkˆ!MkæÂv–ÞL’€€ÚÚh“ìH]ð¸V‘Ÿá/n¿ãˆÔáoŽø©ºæ· ¡nÕÞ÷pK¥Gi-P2«SµÔBO2¥»T—ô’ƒ^‹ sÓAƒÜ ð%"©>œŒu¨©G½ÏL½<ó7º´u \ÑR"õ?±nä?&é|öŠ.d8¤ÞÙÆîÒïv5¯@×àôˆ˜¬Ò¦tŠ‘°!sˆè@Œî¢LlQmL_kŸFjõhÎ."™±‹¢d ï›…2ÁG®°oÄâ»Æ~rG„€vt§3”ÊÂ7cÄ·²‚w³“uèYßìXRôŸNwÉ¿‡ªé›=Q¢nÝd%¸¥'D²IBØ@yó)ºùE .«OÃv"op)ìGÌfT8Ò5‰œ½Ÿøf{JÞ*ðBdm ,Âê`Ùn – Ÿ¹øÒ3šª~3…UÛ:•u¯i3Ì_e­’‘è3nõëB´.VñuFŸ'ƒ š–¤åÛè( Ð`žƒµúVZŸÓ ˜KCdJ´*‹yºÍ?1—W¬þ¿à˜¬DÎTŒ_n“Oq »€‹°Wc劬̳ äÇVÀó28ùû'£x“hAA„2q‰C+4(@UD}’ÛÊê]vjÄ€´Ñyæ¥À·ä‚_DoœÓÇ —Œe¹´7{µ˜'¢»Íã Mx‹ŠÎØÌ|‚š¹ñtýnÕ[mVæéÖ4^R€™š’.©žõñåb¶›´[O…_0V¥K™Ø+kÂÍ©³›>û;`6Ù–ÛY7¹ýP‡awô£‘J§âpGä »ê{p6åmý*vñZv¡Ùk§úJ ·¸Õ¦y¸=ø]Ç„@l¾Ê{ù‡èägí<»á|+ßÛ±Ô‹a É„äöDHAxÒ(û x·Ð|[t`<+ch#ä Ža#ÞoŒÖ a,*—¯#Áj¥Mð¾ÜÈ´4ŠéI´ ÖZRÕèU½¹Q¡!oUòÆÛÙБÑ4Í–®ÊÓÌ.ŠØì à“jÃo§ ‡ç5ÍCP~`ñ¤}(YzƒMà?Œ®˜â ¥l0Õ÷a)+»;—† /ˆŸ¾˜XZ©{‰h¾l¢?‘€nL÷¼ú’þ“6Ǽ ~ÿÕŽp)iUE¦hnjK=äU³F†³†_ùpv.eóéŸt§BÂ’I!™“i°*…pñ’€€¯¾"Ó:€ÃbOÒ»á¶Ôˆä7i¡~ágnwG~›âp…í{Dë•üCò„IÃœí¥ŠN=[6ÓH çp+œßOž±7 [[íoTSù)î› aìã_?èDÞ@0[w¡ÈQ#<·%ç·¾ÙD_¬äÞöèóœÁ}éM$ºÈC»°í¿w›;ê:;±l‚táØ\ôÂA/À?Z¿(ÁÁ:P@ D¥B>ÉÝ•1GnɆ¹åÜÌ:Èû÷ð+iþ™ÃtÐ=’‡«o„'ʳ) Ô+ `^&¬Íܪû0–“e3¢¨=âø)ÍÛC†õ!¦wâpGÝ^LIíR‡<¿ù¾92ÌÚ†Åsžk´N@^±;ÚüeçàÝ 3¤mÊŠXºÚÕ\_òèkÈE¾iË$bïÎ\¢…£ß·LQ‘ÉHýŸ£„ëH ± ÊA|nˆÄù®äÃøF]'zßT1ôxàWD¾ŠßÆ8ž#™ãsúùJ~ð!ß;Ôz.´Y&Üæ[Œ¼‘Í“K6ýnf¼“h3ÿ=KçÍROß¶-˻١D˜Á­– º‹9Zf欗6áW4„8fÖoÃq“¾&JéC‰Î¢É»ÈÈÍÍÞ–™ôôÅ`ήiÕ@öÚâÚîýºŽ1£Ð*ŠýlNùíýðbp5Ù4 ¬Ð î¿àÃ0ãØðÀÅЙ„Õ§´š°]ˆ%®¡„×ÛØ¦¥!i…¾TùZÝðã¢a¾Ë"fª¸Ê§ÃϨlÈm†Ó™²M§øVì”éìä{Èöள&›rtUU$€ÙY9Ì€¯J¹ŒèŒõ]’€€ Æ¾hàoºþn!J¸½ØŒ…=g¹\ ¢xˆXbh¼ yš‹ôË ¬´þjú®þ‚$£ZkM7¥ë‹±w"¤xgìÇÌÏ=òÉhÀãS¢å­¥ÿd!Â;{.náiÏûÒ!K°ªÑä¸iå!zêq†y¶Ë8³D¨)~°a/Èsê™›#Lî}Œ®Œš¦F’¾8Àˆ7ô2°ÎÛ¶ x>j×C—³î¿£æIÞøÕg©Z%×¹”ä C›¬B•Ýù(WxàÑŽwyüYìSR x _&Yë{>Ojz'pð… úo}êóÓÄø©mafå5Å|ÜÇU} z$_2®½Ø¿oc®È%\+Àžy{Dº²ØY©|`î¿z`EâÅåP@@‘ŒØùÚãC>'—¶ŒXzŸß ”¶…­Ì8HˆU„<=6¼›½1&¬Th‹¼vé¥àìØºI¶2±M§#ÈÆ%¤ôwÖð‹X¢` «vIìxš‹?¤×£?ÀNÂ¥œ)¢ù·ýòí5”…ôàк ô~м _+S¸XiÛ&}foÔçÎÅïwB’Ö=5Â?©Yœ"ŠtŒà&-&ö³ÚMæåñº‰!\ [Ú›ð¥]ÿXð"Çi&*˜c42õèl©' ñÏ>éÌà Jöku‚¯Y¦¿"KVæ”Ì(̵ÈKKÐ ®-[­—®²˜|dÑ=Ë>ž¼Kî1Ð.®ò•ÛXÝ”GŠpô;P弿¾ ý¬1æO"üy©wQUj[–±èw§ ¤dëI×9ë‘ ïéó@âaPW“0tb&œ ËY²oÉF9€Äæ0µ·@RwíO‰&Ùmr§šÄŸc6ƒ8iq\APÁ^ÅkòŒ-—TnO¥“Úå\u¼oâÄTq‘1œ®´Ì>V¾y¯µŒ¿d õq.!î‡wôh¿NÄù9 òüLÌÇèxçVI9WæZO¸/I´#=±i)Ǽ3WwéçŸÉå*4‚ܼ·ÃÿhÔ¸’¨ÐtˆWÓÁˆrœþ6Âh >P<Ÿá³²Ü"ìç|ržÄ>ÚÕõ£líá&•1‹z¨w¦¦¸8ypüZ¯ú ¥ÊÙZï¿_A¬èx*ƱOœæo@ÿ"œfýè’€€±i‹Ÿ»EÆNå)^ªÎ¦nïHZäZ¿êöÍü•ÊeMt^Þ}£ ¦Êì´N‡JѺöܦG&24šW´Ê»F‰S1Cï.H¯ºö“Æš`ÄŽ‹çF™"ÿÀ©ObµNï€D©å¢°~¨.lŸá1V Åž’£äÔ9”·KG£¼ƒqJ”‡Ýjvý'¬Æ"[(}°yÄ}4Š× Hp¼Xń𠆡ûœ-b"æþ£ æxE9%OræöÍfbmZÓÌçQæÄf,ZÍ︲)¶Y•dùä¿lÑp9èÙ˜ÁÇ»ÙbÍÙì¸Bå µ™¤ØzbÉ&-¶?e½qS–ÃàšðiiÚö vA@x{||­ÖPÚþ.S^óøQb ïKê{·VÐçïÜ? 2½¥^rG–JóCÆéƒ–æBE€;‡~¨ž9¥ œI… º$ÿêÂçNÓ >Ø«ÚPò®êŽM#ž¾|ñÉE{ÃiP>ÒZuN!”[s¹Óg\’}¨Ø²8œV5ÿÊø~Þ]ß2‚\&2¥è/:Jýk!HOѪø+‹Ö°Ô °‘½9ŒH^OXH¿ åE—x¥fH‡í»ÈŸ.Ú!1ÙÛU1IF»`ã2cì9ì¬qvŸN~²qïêOEZ`®4YâŠÈy¨¬µAã¸9ÿ V/K#¹gFd ãÞqÉmïÓà“4䤇zøïæb_WhH±V¿)°CtµºÝ(`޲äá[ÊÃIgðwþ >­1Xi!ÎË4²PS˜…ü­ÉÐÕ E1\¹ØŸlmÖ›\ä¸þqò¿—‡ê>áûîÿíIÐcáÇqìSÙ¥×ç´G/þr×çü1 ä0:¶ÚQîiÓ› *GË,5¬’¦4Ç%Ìóp66äù1«ùTžP{/älMn¨2z¡_‘¯f~W" EÏôõQ½³Åààš—[³ƒ±xwšãäÝRÇ Xଢ£*z«íý N|±Ïïå/þÝ_[sÏ#Þí5›Ö¥ ÿ Õa Û‹·Õ{Fn5­f3§ÄiŸ$©éysDi!Ψ}ø—*­Äê:HÒ0tVµ>B7Î*sÉnm¨âùsejó2û¨J¹ÌŸÚôOwòÝ¡>âû•²q¬kÜåZYb¾ s²¸¸rôf…¸¦öÆŒu’€€¹ê¯–°È2‹,n_ÓL v£ŠI)N¼nÇõ,±§@Ÿ òÔЯíõy‡/ÞDl+·>Ú` Ë›° ÊçeààuŸÊöXFl2Ūþ¾q`Ò}špÆÀ}”ÞœD^@Ÿ¤·¤LÐúßuf$­ºxºS>fuÙw9G-™óJyO‹m[ü†©zð+ð7¦íÆz[HéÓz®úìŽÅŸîȈP.:„GÑ©ÃðÖ«EÆ Ï–?1Ò¥gðž•ÏÅ£1Ž›e»cŒÛ+ßÁ%Îe˯€W¤„BX2»[–¦riXE~§w§IŠÏÈQŒ–¦d3}+¿žç‘À Mg¯´GQ^NÑZ7ʹ/!¯ár}ØvV>âßn%TYçÇy[#ÏjWBˆø Ü.ÅZy­{žt$§FˆA{‚NÚîæÔšžšt“ªw‚üL%ì‡õClj Z¨|æÚÑJÌ™x9oÙñ¯$Ç âÝ2&‰—k/"§€ä"ÜRv]¦MÈ‹ð¢FEê»m“k ¹Nz>O5Ãð$Mp YÊÛ&A%£+F—æ¼›¿xM@œë5_ª¯˜çØ S•.T‹f7WĸBæÉ£ þÉàw™ ¯ç«Ûb^(Vé£20‰÷År§f»­÷Ò‘XkÛ‹‘'òQg»æKÏõj39w¦}è"sO8 )†RÜæ|6.}&Ü“ŸR³,,"‘ýFù[û®P¨IydcŸñÝ0ðÃváÝÂW¬¼™q›Ÿ0]"úx±Óžùª‰†4º2¬Ã…¤öž$‘ÿÛjß Ø7Û‘0*ËàsÀ .^)—ìèKâpE'ú+Î)<{1Æ8þâÅ>Åçxð²K÷8âV}Ó‰Hp‹±œÞ òòã##|±šj ùv\ø?<`¤=xN§¤?âŠx¶ÜÅ||>]_™š>†ïŸa‹½Øj~dëÂK†¡'ÛÒ¥‡.Út€~¿J“±v>“‹¨¸Ò‚öÛ©ì•&œøô´ôø¿ÞJ_†-¨j”ßÝÃ2úUê³&I¯j†nQ³I '’Y Ögš^uÁŸ¢x6£=«Z™ÖÅÝ&û!€ Vö ­#Ðñ‰uŸi½ú ÞŒ,O sê[í¢ áû&ªš9—”T’€€ä÷ór0ÔJ4HDµƒ¸†àfÕ½¤279Âp~š‰:ùvÑ×ÛßnHmˆÍcíÀÓÛ%í^@60pŒ+Fˆõν÷æâ¿‰n¼ÕÄ=¥/eoÏ*˜½,@i"ltP^½k*œ|{ßÐg4k±Üï5|¦y¯Æ_΂LæsÞ©ªz‹-uL{¡A6ý‚”ÔG:hº?9_ °Ù`hQæî/µhaÄK6ˆ•§}­ ª¾Üì‰=ým”KÝIìÜãõÂcºÈªR’t©œNuhà Æ|“…¶Ÿž¯òUz²Œu¸nÛë“' ÆfÀ§n£å©!`;© ÿ5w“~és·ËÓk¹+?ÝEYQ†ó/Ѐտ›&¶£¨ÐOzÔ³l4Ïa/r1\—ò!5"øx‡oSÀö%¹€ïj™#É!8±u´Éä…-SæËþÚ£x{/›{&Iúx4É1b÷s'ÓwãÞnËØMA“õö$£+ü„õÛokꦔ¯^/ó¶(÷»BlŒ¿ëby"î[¾ž™®ÅHÕˆEÄ6Í!Òôù¦H¸—à3| ^¶T Qf¬l;ß/´´Þiâobi/ûÍ´Öº’zz«Ö¨*9¡jˆ®ÍH òf†¢h/ž‡z²ï¨b7ƒ_³%ÓGNçÝý […ä–ÜÍx€F#_‡Ó.XlK]4Ö…üÝ,¨3ó« 7©¶ÿü²ŠYÛZJÊ«Þ%'q ÀàÃ}QÔMÛÑÁc÷Òf. qè?Dc^Ù¬BÝM‘é^Ñm%­¥¹ZÑÏf¨àÐwÆMá©o­!×Óž€p÷,âiI½_ç¤fZ•ÔC^½®ï‹¨a—,»Í² oíP]nE]WåBW¶R°–CYëáóå[>È¿h•íÓ”%‚°ž;Nœ!DÏÏ#!9U§æ£Æ;0^\]“àì7‚ŸØøšé=* * ѽ…lØ·†Ý¿èSgÎPgæÊÕ/‚´ò Éb÷Ý6ý‚Áƒzµäyi-¹AgÞaÇ-T`à‘Ú(_‡¬LÈ0tI{6}O*ë¦Â¾ Ÿ]‡¼BÆÊH3+F–ñM¤¥–ѡ•HÑuâ Ô—L+§ÇZèö.:fŠ{+í%€¾ËæÿíêPD¾’ÉVíøiï™’€€½Êm«B?:O(´qc–Ÿ #òVØn•¨“Vü<Œ¸ ¹LøÃŒÂØÓ¡6¯M½ Ë•Ù0£y>P|¹qɨ¦Çò—ט€ÚŒTCþ÷}"mD þ”{5JÄÖE(ÏKæ™o—SimÀõ¬ZóŠÒ›—×ûXµ%‚^IïœÙEAÒ-ÇYkßÃuvÊÚllQ⦊ök­)_17’æ`]™%¿H}ÞúÁ‘3ä­ñFønXPØO\.°‘ž<®F³i;æ%;4oÅP…ÑZí\ Š{*–¾ÕCÈ’»ÓÅRØâ »t'(¼ìà”i—²é ^F°§ýúáUĸFhšé |œÛÕ.Tè`þ]DµoÙ €õ˜¬=u…žþ÷¤—© Ø@D²Ôüò§Sh„— DXÀÇï¯v«®áÄú1„ZY•×&šÁ±½ôóš¡ü_NÛº½áŠÀƒO´#vFÔ4Qá1©‡<_i-Qò¤9‹WôúMäÆqˆôäJÀÎ;S\x!(?•Æ¡•×yofÙ=(MªjY…ÓS‘Æë9[jOý¾ìövÙM¿ÞÕ”Ä`ŸÒ¾À*€Öú0¾ŸtDârÝI–ïP´†è:²ùƒ‹»M+_ËeýÈ þ¢4z²>u¨„ëšD¨Zz‚6.ïuº45}Ç¿åÿ(SârÎÇÍ×iš_¬îë-DX'hÈÜ2…ýû(ýÖÍᅵÎF…,5)噉ºoÇ™³\âJ8v#ì„'ᲦU‰FÀ¢Oe‚\»*çmé]Pžºº.û«b3nð¨¥v¥.#t†Ñ,X“–Èz”–J°&8âå ãÓÖ:”»Öäa?Ž¿D þ¡”!St ”“OÉ ûÈÞ¤M~×hEwæ·7Ùm¹ }áK¡¸š0/Õ2pcK¦ø*^æÖ”‘3ŠºÈÛ=ela»o¹U+Aç¥wŒQa“LHÄJÞœˆ ŽCº=ú號ɳø¡Eª³YÕÞ©âj@£ó˜ôÑ5ÁÁÂÁqg_èsRÓeGu›á5³›ûm45T+švöb*…‘ÆßHmÊDØŠÜÞêHo£ðíÒ}Q»õ±ÔZÉKê[Œ@ÄãÅ6@[kS£ÿ¾D'y@éÿLÌ~ú=£:4i àþlㆱí¯Úé’€€¸™U¾zµà´õ´ñÆÐrú%àÖ†mÐýý+rF.%\'%±N˜§„´g´çó:üܹJiU£½J!kVú°2ŠÜA¾/žëpVþµ°×yÕoÙOÇ»¾pvCP°>§-ª&çVÞàF‰g¢¬ôdðÃy 4½ƒr;`m¼v—m'•€N¨…#Ò0U$©)xSâ­Cœ¢VüÈ=za/=¯õ›q˜/ØÂ6Q…åV‹Há§ÀÛÅd5x±nŒG¡<£n1 ÿ~´„ƒ]%D -“¼\îgAXó¯QïO+o}mÔÅýŸ_÷KÑ ²÷ HÅï§UÅ×z 3_ ,õ€½÷(’±üG/Ü„¦%‹SÇLaò9‘«'º}è°Ï3¥ÌÍ´ñvaÉ—Z¿¡ñfáòJï_ô') ºMýûò>ôáë_üº²iÙ4¿-eéÆ¿Õ vìÇÆÄœ.sMiÞôÚºlµîå_ÜNíí¢âšàü…ºÂ#{õœÝ'g¤Ìu-àdŒU%3 ´r9ó‹3ö]s³¡Ä¥üfØôŽÌ ¥Ô~/¿×_žÞX´;_¹[ˆ¹ú½º°oʺäîCQÑF[T5E6E?x’TbfW¤¯Î Ñ Õ À6¥Ä”ÉG𦒯P¦ôXUA˜ñÚá‹÷ä2XÄ€qÙéþ·‰ü#Õ[xR *kE&¬°h?AØÿÝO£›[ýÝx\Š“Coì?šØ™öÞ´ÊKæò0O,£›æQ¡í¦éþp ªŽDòm(Á(×ü/ÔÝ;¦ê\wE‚x»$¡‘9}qw‹_¨Ù[ã/·Î$9z˜¯n›9ʶé&cq„hKÀúV¨íÿµ.Žžm#…/éËÏE+²ü»ÁÀŸæÿЧ·ï`»4èØ­ïÒ\“† «Í“ãe¸Rã%ÞÜï ÿÇVòP”Ö-Wß#Zv·{…B¨ƒÜY-&Dõãñ¿WÊØCŸ³kU’_]®ÚQÏ1:W$š@À W¤Žé?3NvÀuY­ïõ¥Ágç8q¯rÛäðj¡AÙð(f"A¥×/æâÒš"J¹>F[Q{ÛÑ\¤ˆSƒ¿É¤LµÈépÏrG„N­ßÁ2]Úq¡äØ$:PoÑÍL‘]¢£ùËý^êPð™fÁ>ŒA5>UÀØó†tʡ઒€€Ò-L^Á‡” ¨ÅžæHã&¸H=‰ðóå"ÿ÷—;*»Ì’&„¦ãÉIø\Í*TaS…ÎÒì¹…æ=‚±âRýÎ~–ä.çY‡xëa´~¤ iȪ‘^0Á½6¤ý5„@´sh‚ÆpkJv'¼ñ~&àkP¢´ºJ‰ijà 2Müу'XþƒM†gèzi|—ª©é &¬‡⪠& ÓÖì}âv»—_0ö³S‡jC7‡- ñ' ä‹ñ‘ãÔÁ_“é@g¬3½, =h¼ŒtºòÚòžŠ#žLA%z—ên ç„>ÕJ1NG”Ê·Në(fQ¡ù…¥ !üãêÊ ¤Ò] )U©TïÁŽ.¦Ä ’80IÍ·:ã…XYÝs½3¢Ñü³H§‡Îop1 ä4úÉD‹¼ïgPs:úE(²bWüŒùmð ØKÿÌ5+Û÷"X¨V ÷‰[ïÝ‚î¢Ø–ãÕ2ÚÌ˨=‚µÔ’žðÿ;¹%^ãÒ!©Èù:Xs ùU%8·&5¥üï<Ý#(íƒ µdI ›'E8þ7×þ£4«~;íoΰ)€¢OŸX@I;;‚>”».×»Ay´¥†ºVýæ”ÚÐV¯à„S,dá7ERguKN÷U·fŽ©qíùèAÞ£fØé°‘ÔjsHU:Ö)Ü}ÌK34€‡Éá)ZX½(Ð\í¥™ƒöâ“TÌã)Šná (¦§à0Ãìec@ º„RTʼÖàWÔ6ãHÆ<^ÒKz­ºœØ°’ÁÜ»-–Ûç&’ö_4ð^‹_°«äâ²ö$t3Eç!fÎÐ Ø ç©–œèúíù²iB޾öÆ´ ÊÍqÐöÎèa sJ اKŸ¯Ç½ŸÊ¬×ð¦ÀNØ~ÖÑó£þålRTbñ=ä"´c¥Hú±À[AEÙ eìÐ I]UôMƧJWrèOh'ÇS“S€eÆ„ÈÔyH~–»‰jƒ?Å¿–q¡Í±K‡úê*õ÷¹Ñy-WØ}7è[ÙÚ —}q6âZ±¬‚4˲²ñdìêg ,¯š#:Õ¸b}Û½áv˳¿§€N„;–ÊÇr|KÀCÛöœj$ñÇhíÁ±Éáøu£ÒÉÊ‚£ñy£¶±ÖìМ¿ü ¿e2äÑ@&¤ 'Î’€€¢eèËý´ÂïH¶·ÛÏÊó/g¡¼VIÏÑÜîÆ’)è­Îj—Ã,È¿Ìuƒh‰Þkªyf\à·UuØÁÜd–Q8èN”Æ^lópñ ¿`<’}?-ôÞ€ê‰E‚íP¾>y919è$Qk±Ð°×‰7]Þ õÓY¼Òå+´‰¸µ ÑØ°ÅK¼ŸÛ\ºæ¬Jì4ߥrõÜ®ÂÛò¶Ä•0ý¾suõOÖZ;)""‘$zTžçšÆ·ÁZv 4m„p|ø;"+—èqF¹0…ä‘éšc™©Ÿ÷ذ*c£©[,h¨@;6yAÜ¿_û³|òm³ÃE(¿°¡¿”Id”fbe»e's ÐvæÇQªšaæ{Èup¢6c(Șž¥‚›5K5ÄcHµ¹s%NjõE:*&Ø!ø¶Ä¹Ô2óK V•XÌ¡áQ$vüZ•Š”~Õ?-{~›—:‘uÞCeZ¤Ïí] ±H6èÝ%EØÓVC7ë´m2„Êqê;Új¢;?ø-þÛˆŒŒÐlõèAÄàt¥U#,£°_/` uˆ¡œ½pÛzEÉÅ#ßeµ¶½¹‹WÐ<'‘ æú2˜ ŠªZZT'ÚˈE»¶ºöÕ´‹dAY$‚1œÉüY“Cî9k:4ˆ‡ck!™µûãb}‘X×>Ðêb±ñÌh„¼‚¢+í!=›3u8ËìôAP5°Ý©ìVàsÁºCïÖ Ì|óó¯M~  ²Ô©º: ýæÿ™J«úÕú]‰çã¼ß|ì_j2wO>U%ͺ×A£vÃõˆDœpLÐYXÊ:êþq˜ÐOðË\‚Eƒ´G¯›•ËbùâÜa¹Ãq½î¢ÛHöS¸æ>˜Z4ϧZÒ9Ù{LÄ_¦­ÆFâ†-0Ää–Žo µRËÙh)¶¥ñïOþ3kryÏGò&g‚£˜LÎz¶wö^ýè2M™|þ¤‹nT.ÆÓ>jvß2¡2²l)GŒ›íŸ´çAÞ^‹Y(ñ-&«9€;™Uþ©[Õý* Yƒ®ÅE»•ƈ’@sU™ß:OeEîKaïd‡® c&o-÷@Ÿ ·U 4}xøG–íÿ;ÀçÃ;¨˜Ž@\@Ù¥k–‰}Ÿ$ðÖKŽ+ÀÊõjߨ¬VHGt ÝOCh:3]Úc’€€Ð¼©-@7t êÑÜrð„h}ݱÊÚ¯ø$©«ÏdN´á¨©ñ¶ûŒª¶æ•Ñ”£á9›Å ëv q°ŽHò "‚baüs;€‰®ÞÝÛñÀgóþRÚ…ždÆp·•W*ËnžxT_¯ÄHæ®kȼˆ>Ž´-υߥ"µh ó \NC5óp&ÞsªÀ1HnÌyGÆÐØéáN‘`ïT(¿êhÌœ °ŽÙ¸fáÄó•Ä£¢$Ñ Ùag]ZU'”ª¿Q }¿£…KÜå±íu±o;îºJæ!E'â|°Šªg"ïò¯|:)0ø%|ý‰”MµÜV…6ñ7sC2ƒu!Y”̆ჱƒöi„Îîi Ï6ÉûÝôæ³ ]»_Ø6Æ=ãx2d«žM—ÅdfùöÜé1]%‹g…ô3ü9­˜¥M 9Ð)…1%ˆ¼‡qHÆ‘&â¼ÓÔ(ò×%€UçÔúpøé"q„ìl`6ߪãGýäÈxNó:gÙ]ØÉ$S¨$’¦±qpmÿ²#ÚýJÀ.ÌiÒ÷Nq‘7`ów{ˆò¬¡àOé>‹™•óÝ~½»Øø ÇA˜C¡ê1…Ì}w†͖œX3 ÙG¼µHJz5¶‘jæ€Ï`ƒ4C3ñåÚî¹Ü_´Ìoþ9®£póxMˆÂøšÆ1±Y8Ø ë{É]I‡Q¤ìƉAV–Õ=ñeF)0/Dt_Vþ7Ø’€€Ã,vt—Ü5ÈÅÞ‚Ø5!éGüy¥þþ´”,¡²ZHLM`0¹ZçÕ¨Ö°2ɨp¼8ÓØð…Ö("”Ç1DbHcê꣸— ÎÈDµ8Ï|H–§"úöuú˜e=ÊFò|ãÃÜ1ÀpÙ욃GTR¼¤6XQ·Ô‘›œòËøÃ±¥¼°>€âP h¿º÷MPQå9íÁŽ’ÕƒìÄ=Æ%hZÄ0To+µô PJˆ”ŸvBQü$â`åð!m¸›Õ $•cAÿÖn"ž€óQ+\½Žêß çãÚ¤Q0 pRGXŠ& ?Òò€I(›ÏñtV»·@4k tÕ”T (ê£Èž#&4èh­.8ÉÝõÀXkÛÌùS O²pkè­¤Áÿ¤aðAŽ}ÒÏv˜‘Ÿ!“è›SDšÝ±Ñ.‘¯ŒA’;»Ë® ïnÏ¿,u!z;øïfø{}S-œŒ ŒøÌ3»1B?ãÖcqƒYƒ¢QÔq‰-ùiï+½7éøô<ΧVVñ+±;:´Îh¹+¢t«ò~ÕGÔ!äáW"zÀHÙÀQ./Y÷G"Éøïôg*4©Ý±¯àä½!nMiRŒ]DðÀ -¨µ@êÒR × IuÄVÒŸ.z¿+U†nË»²5¬;å' éTdÌS°ù}Ñü.±Ÿ¼pfûÔ~qQ˼Ş—Ÿ”MøXèÝ¡(]{@[Ö•O•èÚâ24à®@¤Ã}¯ë| zFâ׎ðWü ˜¨Íùd¢ŸÌcSù {è<=¢D­r4ÿä ì£5/QÕdná,Æ~©fÈ6^3MhP̳ÖXZþÜQ€ço-Æ`=:B:¿Ûf"G óº5ÕN‹HhD+Tkœû+óòêb´±hóU-œaú6ÞÿîLRÖ[¼ª©ŠÑü½¯1FÄb$ì{¸çR¡”Q1d}¶Öp¸GïÝÜgì ; KMt¶»È¶8ßje5ØTmaŽXK¢‰H ÝH"ãjå½6-t3²X¸ŠÕµx@a:0?©?ì3‡ŠËC‚t¾Ãõn£jQœ-5s‹l8‹AޏQ-we¾î¼ÍC8 ÈÈ„‹|e¬ä {ª¨™°8Ѳ¶Nüã€àl+'81¾)û|-º\ÌDžúrù ’€€É‹ð  TvD×ao'Æž}±òDƒoVБuHïu»ù¹\k£Ìáó'.‚ÙÈÉ;ˆÄ5; xJ· —C=¯ÉTÀ•ž8ª˜Ïí£ò ss¥|ŠðÆ] †êuaRá#Ó"™Û ,RÞ ¼ Ž‘¬¤ðVÃGÜCA¿eo]€2gTô¶·në.àj;b~K]î± Éü±ƒ±šÔCoîž\0=&ôðŽ´û§ÎZsø[:ç²×æeÄ^ WxÒ{z=è¾”bôôMo RPÈDYž<öÔÐ!“ç…ŒS>óŸ­èú¹³ ÷ó³:Ûˆ¢:Æ"OêŠÃ:ÀÒ¥µ|/›2'+ª J36©ZŠ;9•2–Ò³¶kÔB˜­™•ùnühQe Äšð$‰Ÿ†i<K•&ù·P™btØ?V'ÎD¥J€ZÒh÷ßqàE)œ!zþrÉtûÌøWñl¼6½C8‹Ð°žUzªH°~–¾ Gj5jƒ)žpÛW@L¤ÓÀimŒ¸i~¦çš´÷`‹Þ^1\õ?øƒJ ¬˜ ÄÌðHÈz´ÎK‡ÝW_דNñn[îš1¢¤×gÈay©)@Ìn’h+OMLüi,ÿHðñQM §YÙ‹”k."í«}Ev÷ÅØ8 Ynm…‚ièNR=ˆî3üœ?ÓPuê0¢Œn ËÂéåîoËêP¿›÷HVä¡›mñ·íüyɯÃVƪ6¢­¢Ö7Á¬^Û˜ `šÆ´õ¶õ^@T8bW!Û*ò€ìB:½fq§©‡ðzV½ÏX<±ê`±´cQw\ÜØ;è‰Ï,žh‘ÓÞ»J\H®g;Qm–1ÜA¹à*Y’%ʪ`¼¯€³§«§ o¬GÇB’E†ýäOç}u¢ònšéœ¢÷vUOö¤¯©ž…ˆÇÔV«\);LfPS!-•€ã€ ¸oý_}…³Òì>AW˜y÷:%þ¸’eªLnF§'•ãƒþ˜iƒb¹Áìo±ˆHÃ3P•²,hÑA š~¬®4?8ë8Ó'Ÿ~ +Iòr} _ì›…­G’˜pzVH«f^i>óñ¶¶0òãÇ¡ÖF¾‚`®Ì–?IRTA=ìèöæM¦lszµ!4ê/Ìw!C"e¾å »¸’€€ÐLJÓ-DPÝ•:åDkQK#üÜå©—ÿ-pnzÙÃ_±ûŸÒˆš‘’‹É}éŸ úÉ™¡‹YQ^¾AÚôþúÙNºUå­^Fç3ÙüX ÛæAúÿõ/i²˜4>+¤DG7K ú§‚£v5Ô”BûÒ†z»º¢Rðù>D•:©.NóY«hÍ4"ø$ÀdòÈ;Ä ç6ÑÌ';]#+u‘ÛŽÛŽÅñV»( ëÇVÁ›±Úêïfö†™Šíªb)_ÏÊ Uå¹öëᑈ®Ã  QãæFÙm ÁÒy¾ìÒ¹Òg$Ì=ó¦Ÿè)x.[3¶f¥ ͘…ôü” ö­ŸÃîNBêyx»Yy¦¾¤žn^1“?–%À?eIêV׈Ÿæ•Ä¢vÖNGåÊ[lW ÕøB=qÆKL™!0–‹·¢ÂÌÜ€ë4±ÊO’i¢ì[ìˆñž„ë>,鑬‰ç/•?¤îñj=ñ¶bWv³F÷ºH!ɦ4Lƒ VU²€A—O?d–ËÔ°„Ÿ«BAõý׸¨$’¿ê™-®Ðj- çFWŠO*ÑϨ‡ÇdëñP}\d7ËB:” ,îÆ™ƒü…·x¨d!u$wG¸¹Œo—ô*PîÝÌcWD?ý áa`b ó 8²JºÉ…‘Œü²lUˤ҈ÏMÖžˆ+mó> ?aŸóò¥oú˘ë¿W´t³Ë_„Õ b½,ªMc@P‚2À¨ ÞáÈ a?{.ŒÁ›q.'¶ÿ½•x² fV,èK‹Ä=DøkS“W#÷+ŸT1y9Ê4ö× ffÑÐ;þcî èÔ^;Y²Óxæ­ÉïöÝZ$שpˆ1âô½1¹wÿ®ú!£|8ï 0›µ¥¨LsÑDtË÷©Ö‹x ÐÔó^ŠK¬ÊWC9kK¸}ø“Ç*RTs0 \cTÙQ&yvGˆÂ’€€®ÙY¨ª“ö'‡Ä1T=u£:bÃ¥(ƒz øÑ}ã *gdS3ó‰}Ô„ä©'0ÿt¼ÏäÇШÐC?úu°röX!8Æ$-½;‘Řê@•–ÉĺòÏÁÀzˆ²‰Ü˜ÎkpÉjSómØË™}úd£ŽD´Ã#“ö˜ì?¬8Üp7S´Nst»‡» ‹pÄpWø*6ÿÁÂîõ}{‰ÛG:k?´Ššq«r%ï‰[YÈÕ‚È•µ\«ß*œæH‡ïMϼÉϼ¯Ð¦§´]6äbõÚ?‡l{/òḨ 9A®It#O¨_2‚ê6NAM®åfGDØßÁ:É£åèà1Çl9ЇWa-ÃÁÊ‘8¹Ó 6-lÿ0Q*¦k"dÒ`­¿Özmè•´~°E`m‚‡Èþ·X¹ygʹqèy`ïWF.úÍ£$¥“‹Á’€€Ö?i81Èv«ˆš²%iÐ&Îä³ß6õj»ÿ‡^;à=T~z?f½Å"¶\4Ñî8bð¬”I³ Uÿ‹×[‡¨²)šY¡¡é#\ñn;:6C"ª©CŸO/z¢Š]gsB>”i"¿-c¦¢¹134¤÷{¿ùããÜAÔÕ÷†™9P'1‹qÌ>ƒ(0à3ÀR—*Ýçx$ŠÝ”+2u 8—ãÅp pîð[]ô0K‰€àËø>?Þ_ÒS(OÝçÚ0ŸõûÀ´g•äYïôYƦÔ¬”Pöù¯p[Ĺ>ñÿX ”éÙÜì ‡ÿ0®Âw•p6Ѥ J •»‰óFŒŽ™êwJcÏË ¥g»ð– G¨: ÝÝ£“@S›ôÛ³ê{ǯ˜ˆí*¦/R®þëÜ0±Ìj5+Úª?…óM~%ñœ`r5òiTµY‰öÙ𚔞¥QD=µv4Néî”o““}€âBŠÉið‡’JNNæÛ Þè(©éìÀÁë}2›~/ 7”À~¢ïõï=£&n’JNŒô]W5 ¸–rt˜…ï‡D²}Öô;ô8`é/æMÙ1O˜ŒÃTá…êÚò%¡þ윴Ž?òïè9º·¡5¯D` W12r* öœ»4Ñã#/ÎO¯Z£IhŠó:µ{>X°Ò½ufM·ý|ñ¤ã!¹‚;‚NˆüHï#™7òøvœ7µ¼!4i×:µ,K´¢XKm: 5ÎoÑ“t;EªcÐÍoô»ªÌØóàþ¯`÷on¤¿ßá{`TxÌú\K‡E&›z¿‚póh=Þë(!ì"KCmÖFÈâ°ÏŠØ ã’€€ÖÒòKÉøVŸPS«)lã•øCÀw×qbüuøäËpnCÞyêc¾IÀø‚·=ä¢=>"l1«Ýj½MQ ÜY›œÀYuŽCQ¨þ¬R±ŒaÌÈù¡^it¶%‹ãaK¾ž0Uu±VA³ jo ‚Â,´ ^i;¶O§íÆŒpÚæ“sPþúåDm;0áâ[άÙÇ# "°+>f‰Äëö¡Æ¹¤Ž‰-¦;mS¦)ºèKüŽ,¼‰P©é¼Y«º¢S~°.ºç£®¤¤ð<[ÒƒóFRÃü¤âØÉcÚÕ„à“ž½/zQÍ=2ÍÄ`Å´ºKVaˆŠRm´në¬Ó²,|1ƒ:æ¥ÏÄ+ÈØmœÎ|Μ¾ Díày-57)öóò2âS fµ?ô㇧ְECIO:ÇÍE~Šlcö­½O‹”ótløH¦â*ÓèŸÛrâ-Øß|¤´ÏRÔ›ÖøÆ= êþëJò½ë 'ÚZ¿´ØÌ›BаýrV4K¼xÄÆ%0J¿˜†`}ö„U¬usîžô?±Õ’ñØ¡ý9JfÜt RžÙœF˜¾sïÔI KA ÿ„öaË}.CÝ€•\† úÊ줪k²U›iŠì!Ÿ•‰poÐÓÔhˆy#þ²2^W&&Øîù ¬Ö÷¿¼-®„ý„}{Ïî–szaÉžH‡å¾E‘W@sUï,S²i•‰Sç ÅbÀÐBxš‡JˆMß0>óÄæîï÷YÖ*€çÎBq¨O2c£0ít„“S)G²æ]äzìÿÏèö`ixœúwÅ£„ßgÔN…Üw‚˜è¬oZÈû$9pUàk²³ÖNfŸLÙ„ñÇšÉnV6Í3^™8:m«§˜„sŽ´lÏ¢}âÍAJð›ª'ý´¤Ê½•Ý[?’€€¹Ü€|m±°ò jøÆÐ“çz|:öæÅ?ó×J•¸²G;Ÿ[#˜î3c—sµfM&šSfTã=kÞyæ{32‰îçî׸GüÊs§Øãúø8S€ØÁïqÓQz¸~÷r¨û¡™?5§ŒÛÑ9•Æíj8©ñæ·Ýîñ|>ÆŸ,ñE4Ï=z 7áZ”0Œ¡Ì‘D6{çcÑb5]ÝÒåjÇF׈ Á¿äã^Š.ö8ÍŒ.m9³H½ë±SòÆ:Ôw®‡pvséV‰MJ:¡Ù+¹ú"¤\ÿB¥ñ†U³[ð_¾”«=ËAór¬[mÕÏ“G‰¦¹·Ì[³„;.eçi ‹½¯õ­yO}æ«êÊðO5¥N!ëPÖâJƒ (?h/ì'Ã:Š!*ÌŠLº› I7u _f9è*ÚÐà®ì/ôqКògÄk Ü4áv®äöÑþÁ£K™¸+ƒú9 ·œ‹|±Îa%“ÖÇ%Go÷”<ÄKC. ý)l¥ïßúÅÌ‹žâqiAœÜ]ŽcI±Áq¯Ðs„†r®-q1CŽíTŠÓ-¾*ìÏE§°äö0@bK(úðoØ(Pô÷Iß²qeÉp^¼èò¢Ühû’lÔ–˜ù¯ê×嬃ðb…`…QmkM¹Z°‚æàD 4ÑF\„çpFT`%Kü·TÈHù "XåTHƒ*-™Æ>”‚÷¹ÜÁûQ&z>}qq£òLSÍ}{÷jÅ‘½2‹nÁ݇k›ë0~vÓš|O3ºydÚø6£…Ôus;~+%³Ûp2¸ÛÜFÌcѲ³Õ±œåb§]áÍåX¸½Ž<Ø6yõAc+²nîìnWÔuÊ5ñçIa²q#}k?f àìÎ’§¬ãX´mk²è½õfGR—޶Ò]Ë!1î¾jtƒ>Ýúu=´-ß2¦/ah0˜¾°XGØ}%™Pwõ$I¸Ñ%scJ}zøx/§þët!¤? µ%¹7¼u3åÂíº¯šC"«A‰v+jíC¥NÔçéG5nr0zïÏTàÇq½^ÒnÐ’CãSjàÐÓ‚BÔôLÅÐOÇ¥¹2– Úéµbˆñþ˜ ³!Œ›ûq‚~v°ë&œ¾l'//„U8J‘ZX¥š!`Ó‡’ÇÓ®`:6özŽ7òûñ§õ§ ÚÎhçvVu” ¸ß¼³vÉuÌÌ a½œ ë•Ç< VÜŸ· 5eÓ3Š|–ô†èÆtìøpÈÌ“e™ÁIio7 «2êðÕÁ|/mƒ®ôå¨njçUKÏÚ•É}•S¶Þºù““4Bˆ—SƋоŠùõë”P4¯ƒw¹šeõn]yp·0Ýt¥%QñåÇhßj® \ttqùŸÝ~vIÌ}f®Ÿxæ-Z×o Ù LzL”ºayZ þõ'ªS¨ˆ;«ãn ýmJ¯(²)æVNÉT›"ÐU}AzA©!ü‰üI÷?4¿JÔy[$ÇE„æ²­–ÎWà††CNLÄL7Ö|zY1´+ëÄ#µö76u‹bëG×€–OЦoåÀ™) ªØ*߉¡ÛºM€Þïr¿¼G…&²&m½öæ?ÓZ\ÐFô‡h¹íÖDÉDJôŠïÂ48ôïoBr"øÂDJ“AµŠ'•²;»³Ö>iN`ñ¨äëgˆ²óëzîfEK†Ü,„-¶µ#ÌBM(ßµ–Ïl€šH9J«\.œ"?¥Ô0¼D¹C)xX‘Cƒôž‡Ä< -)$q£Zµ#™Q‚µ•[N:Nƒ¡é~<æ w‰÷³‹,*¦Ó%2cþ "œè¸I–NfWSŽïCƒŸªò|bsèo““@’€€Èä=§Ñ w‹(YÁ±Ç±‡È© š¢|D"¸E‚úþw½/ƒ"k«¨†yd9,¿Š<{êÅ>•Û›Ì1B DͳvÛÜ£3䯴H!b<´˜J•ÚÊ´k]’&Ÿ¶ÓD.ÞÅ]¿¥]VZùµÎüã.;6Ì¢ÝÑʈ‡asŸoc8R÷FÀïAÿ§‰ñpì‡éQ‚µé!ðÁîØÒ6S£×º’‚8ØBÏÕЙñö!ßDÙ‘ìŽy=…ýøiÉÅ¡ƒ Omn÷ìÏ»>ÊUBÞ„Ö±Õ'ÄlgÕK®üÊóÎô@5ì¬4`0ä”+T‹Á=LaîþÄ£G¤ð’ËÒÀ‹Dûñgƒ|Å'‘¾M@Žò³åÒ£(‘¯KåRCúèfOÊ…@oà‹_¶M\`®‚;C¥ÍÒ‚ùEˇ]üjgÇ5&é.…cõxŸVâSœÖ³`Tœ2jÝ$Ø^$ÎA탫i1SÚÐüƒµ |¶R‚Òå{"ƒ]7Ý«=)§<Å2½r2Ÿ0äáR®\8âgiu›Ž¹eX8V,*|ᓞ?ß„O4QoNÉØD*@_àD_¿2¶qù ¦MÚÃTUÕÅ™:–-§»wï¹@Zðãaa ê’A6:ÁMv; îÛxùha]ÄZëÞ±T=$U!ýR¥¯4´Q_$Aà¦× “´Û‡è]Ú“:¢a„È6™æ‘ZÅØ¨ü¨}l5 )êkƒ{D”‹ƒ(¤]î'P6ëvZô.Öwj Z—©zøwò1zF¨'— _šºàMKJIÔ8¨(“øî–tù¯(8ô¿újU‚Éʯ,ØÜÑj6ЪQ“!òu)¯ûáÎÁ9,A •zFfÑkó­l³ÏˆáDˆ6R<ð±yp·_ëÆ&æ~X¢Z)®R> iú‡ƒr¾rãìŒ,̓†sQòq§¥ß_WnsԔ‘Í(9§¤"ö¦jÔPÛý»«Ëý9Ú* Ñ#f;6ÙQ𤄱½ª°ÔKíBñÈß4š½Žs’lÉûƒÜÜy5phÖÁ¹~EÖén3tKÑlgˆæ©wR[΋HªëÙißeûÖ£µ*?FΨcê•Ç(֓⼄•auF‰HMºìŸ¡ï”Þ xùw`Û(YI8^1æþò’€€Áhtˆüx ŠØŸ{À·¾”päºR‘:ΔÈ|Åù~²ßŠ&jIU]„5¶ 9a¬'ö‡å÷ŠCjD²ëK‹ò:ðv€¬Ú(/À—‰ÿGÃ`A)¦à9bÝVmPöwhqt5øÖà P~/wiÜ›îâúF’ûª«[ïV¥äe*ìØŠòbíɧE:$Ç™6~eÉÉ {TÒ…EÑf>Ï?;zª³•+¨ÉipŸO ßAU–dE7u»ûÍÖÚæY+à° ˆQ…n.‚qòÀKà # aáãÍ´ù†IÁgÔ:©Úì^AûÓgf« Ye³6…{P/Ñ’¡pM Õ¶]~%Ó6¿ž„i>BßÊKІ¡¿èf9§rRZ¡Oæ(ºnÒ~ÒiçøÇ—^Dc›¬l¢ÿå<ÜÔEJ&ÌûeîP:¯äæëèÙš±nÑu+õÿn^WAÒO.•Íu1š"Y¾’èÖ1=²KpW‰s-?¥X7TtÄø¡Ç6 ågÔ3Z•)_°äøi·¨o‡j¥R´Áྲྀ/%Zù@"owÛJ £t­m9flrH-ÛIz ²ë¤C~¾µÜŸPò¤°†È|ų/°¤·Â¨{‹,î…Ìì¢PŸ“J 85¾¿Ç¨0¿²)A8¦ùè¯Ù+ÎÌ`¿aÿ.4="G n±ÜN|¬Æ47ùŸÉµ–=XìaƒÏRH¡á÷@í„æíú ƒN¬M1/Ÿ Œ/\=ÞéªÞª~Ù!¥×T ˆæÑÛÎ)ûÿ7Át!‘‰ñ;º]”Ávð—¾É"‘j ÞÖ甬+ÔÉ&5;¹ò‰¡Ä€ )X†Ú å{¼b?‹öeË㹎êèLÖ¬t¯9$›‘o›éÂ|ÆaÓtrü¸}8£?º¤¶-fn“´"›‘—«é‡ü6¨½:fv» ²æ’ø@òßå0mƒˆ³»¼Ò¨™^tÐöà÷5€ëÔóh¯ €¨B€™3b.äUºpvè@ÏÍ:©³¦ÙG”TÅ÷«”^qcÄñÄ;l¸¡«Q›¹kØŒzeÆ»H¯‹ä\-#:šœyÏzaÚh{¡¸a‰¨öql†|ô(·b’Û6²óa ÚtìÞÞwFùÙöѹÿð§uØÍzs.uäÖ’€€øÿ:¿ ]y€àÍ ?Tô\Èðî%ü"Fèi6u"¡cíLëz'®ºÌÚ±–*IÏ.ê½Ý!¥U×b¡´tØ™äÎ F€õcœÃÑ p\ˆáªÑñ£ jG–g£šÚ¯Q|4€öYä)e¶4\‹JŒ8aÒÙ¨PXÞ« = ºËœ³¦¼U}¸µ˜­ô °—"ÉaeÏc+c…³¿äûáÌYû9€Ïbˆ 8¥3†É|ˆ~jºè«œ¦à6åÐJ$¢‚9}TVÖøŸ6GfO1Wé&b$ns‘[DŠU[’µðĸ¯ „¦·¥ßÿ®ÊÜ'! i¿a·çŽA_·nÄ,ûÄZß6ëã‰RðmZ§Zz/…Ω{«˜^ÊùÏ™UQ±‰|†¦å8O£×®·ÎYØÐüJû¯&´iš(äusr+0~˜?jZ@ J+ÌÎ4*!Íì¾D9\ª{ +¾S"Ñk’Þ=¨ý†ËÛæ›r<¸ƒ"°ê? ÷ÓN9È—ó¤¦)^Þ:+CX;ÂÎËgvØ0%í™({}«ÛÙÌ¡Ø$æ¾@Ë=Âr´& Q{W„Ô™«€ qÔm‚Ãâ°c9Õ`†1ØÌxs®<ÏOƒ×.f»kÂÁþɗЖ0  ý:|_g:p4õ¡µ§JU¨@-·àb%WÑaygËþ©ÿ8?[Á8ˆÌ±ërb±w»csÛû¡pÝ{â{6Ô¢q´ŠüX÷¡H}¼sK^‰1”àï"†ªÚžI±¤îé8ä—7.à@/bìâþæü±„îó«~Ë[hðU†nü®²·ô™î” t¨)Uè'8/´îK‘o¤6ÚA%F/ù•«À)5p?+©¾Û âDÌð|Ù+2+tà)ËS¾ ç·ì÷¨Y†“ æèÒ*ܘÔÏã"¸ÞÃßå¢EØíG[‚es —9Frry{~«Ì´¸Ø¬—¥Ò?çï9m^:°#ì<âNŠjcàšë³†¯ AŠÊÌõºQˆ´YÒ]ýzŠK„.h ’ɳÇ?##Ð([J “§fX‚¡Ÿ†æ¾Mç†Ìk2gg­ïË8ò|«7!ß%Ñ—jâ‰Nw »!†zépŸÃîÞq3Nl@tßñŽi)—{×;Ï!Æð·Pñìë*êÝÎÖÉ%ŠØâ‹¤D’€€ïy5 |ž×Šî÷”If_ƒl¥“ÎDœ P†v¼ƒWî®L^åƒyÃÌR>ÏŸL‹D¢¨À™ß:DZÒj‡«K43z%¬·{–q1\¶~g"Æž¡nŠhPõÁ´žè0ò^)…ü­ºØ*Ó»œ ú»¬)F¸*Ä/Wò´ÉL­‹K;2M-hÛ¹ÔWöõrñGç.ûNµµ;¿’@ ˧à{ctࣱwƒ¨ÒpÇŠ¾-Nû]ð3#®Ðp÷kÛмÐü«¢NöŒ4fî :£0þ˜úš|µ>Ø ?W.[A%‡‹g½(‰ÅOû»´é~4PptN­¢Þë[=ákäC7èÆt‚„<÷[rÉÚ}–ûopÀV”4g‰P•¨"­ÜÛkM[ùö­h¶ÖWDˆ!ã<9ßì9fÏÌD\xåç2U<~/RMÞH''®:6<¼Ü‰Ërø€M¼-Ù_Xr7ÑÎ*hÝæCi*õ#B^ƒÛRgEUˆRfÛ¯áî„üiÝôj2;ò¼wç(v‚uªsÂb8Ó<Á‚’WßÍU×Ö! –©5Æÿ_DÛŸ,”Œÿe¿ T½S À•J˜ïwbZÅ0Üêû˜·qç÷y†’1¯ç7‘B ]M`líȬrx])í C÷cøc©yAù•Ò] —«ùi SZì^"¶P{EÞµO)µì>Žñ,ó‡3ÄsŽåÄj’§tl¢Phì1Fv}±GÉž‚3ÙÊißÄÒ.ªóÆNÿÒ‡0Õùïr§•߬üwðAÔuì½É®ìÏ´¶g%š‰Ïˆ•v_4ÞNÎsf?üÀg™õ Úî —&;°yÎû,LjàOë¿äÐöv¥˜zÜÒ¯(9ÏíÞV§›ÀïÆ##®5/£Õ?ü÷01<úü’f³aŸ—)ƒOITgÝÕë ©Ò]Àšüø šæì¶@¦IVp[5¿,ôg÷ºƒüxïmZoUEÏ’²&ª®&¤;Aæ¹ÿ_ÄCg×ÿ1fPNû½“Îí´Ñ%É›êG©09f$Ê’±¸PœGra®%›o´Û’Ë‘ Æ…AÓœþ*Î5]ÕÕ”0?¢-ÇÇ$JòWm±fʨDM%zj¹z‡ŽöÑŠ ÈùêûÅU‡]•ê¡*’€€°iJƒb¾lEѺÜoP§¥õ¯=‡|C…7Rüµë¾ö÷s9*gš‡†×0z󯕇9d‰ØMv-OdME8ÕÆ.) G _Àê[Ù¦„N …ç Ær×-­@qyŒº˜zõW’ò¸ž!0fÑYa½uŸ_/m>™àéock”%¡NAyRhœ¹­íM;¤G.:Áaž^†U‘ÑßÒ«7ÎLþQ&Ð¥ñªì‹þ>u‰æWc °8‰üÆ—I.(•™ƒ ,ÿ§±®72i9>Ù¿X >ÏhÅFö«*÷%.=1fÔ º'QúÜ®(úL-£?R ‰@ ÿ¶ê.]à Bù_‡²}K”`‡Ã/;•ýøÄêCHi‹åMTº!2,-Y(»{ãæxP ûMHØyÊ¡«°âèüG¢Üå¸ÿ© "/d¹ãoýV $ÊÄììóÔym"€xÎßJ3 »‘ƒÕøµ\Úù—µvÞ §ÌN'KÐk½Ö(¯ÔÜ$î·¦°n`‘ú?€£ù Võ{ŽZÇjÛ¼X•ÉCÐB„c•°ºÀ¸‹eÍ9h~â¼u/oêÀW±}, "°Ä¾%K¤!¼µrxæò>%Ä‚ô§­ܽ`ûUSjK{£œ'æã“’ Aè¥Ñó~†¿žuÓ­*@ÕìØÀá‘Ù ùÑfa¥QV ÔÓÒM¹[¬&$l¹&$b¸a›Çám•ÔRóµï—E9–ësfP.” Îë¥â³ðЛ!ò³Â™ÄÑ~×CéúÉ4øITEÅ”ä@÷:;›T‡=(rKSÉ›YŠæˆhî¥ÒؽWëùºVéσå˜DWS(GŹ¢/¯<ýGQ%Ïð“Z°Åè3&SžÊÏí¢Ï&ƒšü”íKḼ-S¤½so{):êƒlɪòRQ|4 ˆútX2©ª>: Þ—Úr4,HÎ8@2”«µ„I=eäÊ6)}•eúºsĥ؋—ÎèUœ¬Fw † ñ áá8<íñ~¥»ÆýGp‡H\8Fö±A•ŸY4A8Á†pîA[ÁCß÷††‹ ’»Û­}ä÷¤<ð\ÑßBqÿ\e™³¨í7°ô]Y~‰êú£…gŽ1Hüà g+qž‰”="j:º[Äê2mJUê®’€€›"+Q¡iávÎ5¾½Ã=EÕ¨¢@âñdÉûø³äPËÕ‘QNÙq'^ÃÄ“ƒñµ¥Ž²XÅ©Dîæ­(7²²€ïæßGÒ5Õ0áÎ–Š‰àº&ÝJ½ó‰ÖÜZ×騶¢qGr“Üò¶ž*ÒB,E_«ÌW¤lž¯{¾¢éQÂ0yâ_±O2 ÏØîº&âÖÁ"$|Ú讇 Obýˆºü¸18õi¾Òÿý <^EíÊO>PôI¬¥±öOFÐ|¸ìãb«™ÈõAݬ7FŽèzI"«Z¬¤¢SyÄ´¿2›bäQ40V/iËL"pöêÉóA{uP!åÜ (—ÓŸ)tm“%Ö Ï£8 sÞØvH¢›GÀôé¿Í‚qRöQ`AGZ1lþd7sÎ*áÙÛIÅßãŒ*ƒ¥•õ ¿˜‚%~ççšEŠ(w‡&áö¯,„Fsl0ëEÝZ ÑuÑßdÁ8aDøây©µæk 5uŒVm‹pA§’s¼õšlèÛáþ8ï%å©UR\–êÓƒSžlÅ(ç”{ÿŸZÆÕ¦vYþúxÌ‚dëªx |“í2¦úh:-Ý!áéý¨™D<1!­1˜ÁGá8þ‚²²ìž½Ö"¢‡]‘м\òdnÈÈY²Çã6°X1b/Õ°U‚ìIï¸W4ØV‘J›Š·/|Îh3¨„=3Ø9ÌDÖ½ [qN Ý:ß$°·` MO:™×‹gðøÁ2“'9áÕoÚÿbÙ»J •G­ò2{Äú’ûÃZ—•„¨K<0’–ä–lᘠXháø£ÍŸ8zãÆ®»ìÀ*Ìÿe»ƒ4Ûè–Ñ…˜QÜ­b‚8Ä ¡iÅ\Èð™,DÎ;ø/aØx†t{ŸºgìKç‰ââðWÍ)ñ|Í%Iž$›ÌLA(TÊU"T4+äX-¶ÒݼJË͇ûo?k.`Žó ãv‘÷ ìø=¾ÊÕönd·GÇ©X@yBЛ7½å J§OIÈO=@žëµƒ %dNJÞäõ~sÃ~¢Õxïqí["/mNÇ}‰ÄD©Ro/h{ç…½„ç)'‹¤ñï=Vä¿>’Árç£Éàœù®ÍÁ¶lºDÛý;tYÇ"¾ýþ‰ÚsØ ŽÑ£ŒùLC’€€êÆÆV{—ϼ0±ÓÌ=ÙÛI`õQŽMûÍ„~Qö;ÿàäw¾Î^¥Ò=ýlZÐì!UúÖ¿hĈ{F„ØßB©¹o´?kE-]‹Æ ŒT'Pâz/bßa˜Û4-Š,«ÿÂáEÌ›ÈÚŒs§a‰Ç°X…$í~=n b¼ç`‹bÀ«•[ü0Žô#þkâq%÷´Fè‚&”Úô¿V}vó†¤1×cöYf0A~9ÚÄŸIoêùt%lá@e‡€æä3e*»çü5¨ã9z L£rXáÿÛL w/ÞO¸À&™C[Úç·²©¹£ &Ê2™C{û8çØAªLž€ˆu/¹ ¨¾—ò“fº6¨ñ(fF² ó`œü¤{H£¿ª•–ÚB_[‡`#Ó—Èj;êµWcþq‘N=ÊrU¬úén­œwQŒ1³ ´(Gݪ8ªUvÔJÓ­ rCàkÁH„¥î¯]rÂÄâg _…†Æ0 9ª€a­¯%ªU#x£«˜XQôâøâCáÜ›p] Ï1Q*¼ZÈÄ•½\Õ;îýî#!aÍMÝd¤Í?_X0U~­IÐ Ð#Mõl鞊ÆgRÐE™ºû¢°ñcÉô,Ý #ËÈ(p0Fús8HÀRƒpbNL& Å]÷¦ å>b\ƒ1ÄÙÁeu3¡oþæ;Ó€ª-,î”ÓéŒá½‘ŸoÏ\qChà÷üÒjÀ×ae»« ý=ïI•£ú—“’ë Õš¸~ «RÅ;Ü…i®Lˆô¾À¿9×^¿º˜u5[’†Ä\‰É66f3Å£2ðƒò±šRY³íê¯oçGêŠ2‚2ðòJõï+¢B|vè«U6GNÑø" Òr´LMN!ÞÖ»š›×uÔu ¼/aPbÇ3Øßø8Cn·3µax³=ÌÌÛlKÀ:™gœok7uâ¼¾o7˜ Ù´ýçÓ×r§¦é´DP½1Çë§[¼Âí˜¿Ž¾þ§Ç4ˆ;´kTf"«b‡‚åÑ?>ô^„½ÖòaëˆM,}M™ími.ìdFoóªþ,ŸBiô¶Ð­{Í"ËaU¸26óÑ7õÈçæåLô[hÅèñKçrÇzÿ]áî ô{võ9õ—ðWLž-Üw…v’€€£z‰R I.`mIîF Ã)û|$]Yg}aº`B2r_béù‡xWF¤„ \&­¦[ðÛ²]n!ÅqÌ'y2‹ÎÄJr€©t‰Ù”qp"•mÌž¡&/Ÿú\?‚㌉tâ€Î´¯."/Q’jY6¤˜+|T.¤ñXŒ=¼ôxâE‚¯Õ¨}(úŠ jªÆS“õE!£!X°@ü0á1q;ZúÄj‘*YMcsM[¨§zïMº~”ÃPúµ5BZõªÀ-•£_YÖµ¾jÅ7½òQë-oÜ3‰›ž[ìƒÇé7ÀÓ_<²jU?Ê®N§«ÐЍ†Èi#[i©_Ñ}}Þ5›™Îr T”HØ'ÛæQÊ E¨©ŠF`Y>ê6‘#Ë/ÌЂÕSÉݨ*R›«qyþ=PáUšsWj–N×6=Ü1›ÈÛ%¼*}/n‹fcÊjGß.úwk^}= c"-T›ÌQ)Mø=;[«ÎÇ“º“³†)_÷—BûÊ‚´íqð”{;ÆêãØÂïæn˜5 Oγ˜ýiÁ‘Ø{ÎÚn“ðt€ ŒwEòõðm~ž!B;¦‚SqŽ5ò$WP [b؈´0 ª¨»l'b,+9MTuè»Õ`^¤9¾[ÏŸ ÓI\…öK•§Ý8ASçk–¼ghsû‹¥WSÀ[a\˜)Òßô»ËñE‡vþ…;ζåEßj 2­xH nõ¿w²îØ:]£3‚kžŽå¸Ë&hr‘bÎÝϳtÝ|ÿ18aO!h0$£cìŸ_ä6Õ Ý—Ä"?Tt)€ô—ü~dN£qŽOZ¨!¸×Ü”ŽÜgm!K‰Ø:ïFˆ’¹ç]¾t®ž}yÏÝãÚ<Ï9R!•~mD¾Ëªï~ò’íkÇ0”Gæ„ó“¨jN°@®q`CnÇ8ƒ­q Côó$(—W &Û‰Œ¨·85³<6ò·£51 NÑ|Ï?«!£øIÃñÞ†^ÿ=o·m#Eê9»fä…ïc /±Àx3öûBŽ(i´'9VÐ÷ wŸîY?‹ÄÃq×.H{>Žá}uض졣£Å\“ÞWtÛf.j/Ák0N7”Llã#»$ÐËçÅTQ»’€€œC=TR_ UW3Ú¦¢ŠSÖ¾Pd×öNwDtЇ_ªÙi-ôJ6 smðyð’µ1Ð8Xõh£õÇçA¡‚ŒŸÏøs"lòRÅ‘˜¯%ËÜåcU¦,@›o¾ª@V®ÕËF7ƒÎïÙ•²¯v úÉ„¬Œ”}z ÆšíœLý©’2S}áÐ0?”s5ïg4²ß–»-°=h¸ ”_Ïz]ôÆ%*ûCKáqÄ!ø¾8_eÏ¡ÇöÑ겚v•Š4öiCÂÿÑ‚r[åEÚ®F´#Jr°ì”J.ÚÓÄË]`ÐóÇ8¥²;’ß·ê  õþ‰S  ôÉ‹c‹ïÃ7˜bKåÄ\¬ÌîåUö0ÂŽ²Œ¤ë)›÷*T/ؼcÀÒÉ$ùŸÇE¸¦Ê‰APùcÕ<+iüQ°HœÖ§)Vº­Ñ jx"ލ|E„™¾ç4ŽÌ¿¯¾•FLù ÓJ'³ñ°/b©â­ol¶cYO ûÖæ½ž~l«FÆ®H&uYywÆO-T‰óÈg­ìNÕ5ScÂ.iÔ<¤É6?,@°^ôõ¼ætðÌòŒÁ¡Ã¿µÌÐ~kΧº¿®¯«á’Þ bˆÀeùþûƒ’€€¬Æ£³¨ ÂêDÛæàdp\ø¯{¬‚>O~›Åh˜ ‹EãéºÏãº÷qwjp ¦!ÛÄ8E2yxÃôß;FžÛEUèšÝr·5ÜïøU„;ÇA@ ÄåY&ÞGªáÄÝkU– ÄlŽ~3у{žnÃþ–Ù2¨¶"]Åk-‘ë:ˆ¿Ê¤f“× Ž×OÑ£"iÂRððŠüçuð¹ö£V™|%hž£?>óÁäV|¥òO„´F°3h¶f”¨èÒAÍÿrz±îPÀWtRÚÝwúÏdkÕü’òH Ôýá Ÿe“s?ဠ/2ȧªCs“ŒÉzlr6?Åf»‰zÎ ™³Éܾ¹¶¨fö…¶é—Î1óþ”²¨E¸Ä"Ž®ƒo–áïSóg&ðO˜Bú€5ÙKÖ¨ÎG>ÎŒEžSe1%wèÈí¨Ž²[@}^îøí|j¢ýnæu¼–‘r[¬3Ñôqÿƒ—8j~o ŽW%eÒ{VH@Sóêe¾²§ck$0;ü‡àV€Œ:Òê3–+×/*)IÖ å8«Ž!»!Š,‘'D”¬¼.B§Îӌء¼ÖéUö›Ó7‘æ5¤Àü*Ûæ«Õ. ¡ú2aaPÉ&ÁIró´Kºë—¤RÈÁ¤‹˜xs €³ÛRøæêl½3×°)ìB ÓûB®¥è Â)F9ˆD™qp¿†ÕÆy-Ai¤íÞ“l³W-;`\ràš;¬X2•‹g­8xx,èD²B¥À?€åõé•€rOªòQ¾µ5ÒÓŒ³ ûó¹GêNŽÊ!œwx £Þ½-™aŒ”L›¢=žÕI€¼ 5 q'­œß¼b\=Æ„Œzè$Øx@)ÈÐ]ôq Dˆc{'zþ¼RŸ Y ÄuˆJˆO³0ZŽP `×(±…äÙìBÅCÃa_Ó&Ú·Zå, edIa€ã[ÔèxÉ’{$9˜lzŸ Š,a"Yj4w‡ÛâqFàû-´U¹_….ú:Tå­ý¤+P8±æ^çÔájç rªßpß<ˆ0‹9r;z[eX†øXæÔ0ò:¨×NÚã9à’€€Ë@Zé’4àÃ"råÄ2X…JÍÿ8K¼gÐÛ:LXu¡G/ ÉA§kàÒ-štÎ,úv[é]rA2l‘ýÁ†ôùˆô`Wüèvܯ4ãKÙ¸» fÕ°.…šÑ˜ëB\hAJˆXˆ­F¯"HTRêà =mmÐb©¦Í#8Rú”ÐTÄ%ñ± œòÓ¢4ú̪‘Ø•%![º7¹É1Æw8Öí#eÄÜ×—¯Ê.N©¢&/³“¹_B·élòKßwt•Ê$ré¡Z#kúK(ý[a]{0¦î“®Ýhaö¡%-'&²qIóÿnýLŠºÔ@­0s´—(-팸¼Ó¾Ã^i9 ‡Eq@"vµ¬f·°½Ì/"Ÿ|íc¿ž+ä–+œ ;| Þ£ëY“þ¬ñË Úë<;ô¸Î`(ˆãy° ËjNgÚ5·»*)|׊¿©XÈNÒÎz „¥Ë¼.äO¿äÁYt=º­D=ºµÚ¸({Ô%à Ljò@a×nÕ¬ò߈Ï|~ûtq™òÜ÷§³-ï*õÒ(Â%Ë"eQpªÑJ8û(5È"uË,I]²Â®ììšÄÅÇ¡³ê^Æ\&øÍ˜Ø@•¿ 9áßà­Ï“Å”?©¼9ÏiˆiSzR÷ 0™'ûÐóÆ„{à¯_¬¸±üWºTª¼ÀÎ+N½¦×³ÉYÍÉïFÏ¿aä•-lìÛó§= Ϧtqé§0¤PQ¡êɯŸx·âô›†_@3u'Cß¡Èïó~Þ!5XŠ¿‡ ÌæµPNI¤TE-~쟽Ãyk*Wn‚^¥‘›èd6(ëT¯GînLÚÝ#£½Î2{šžœJ€—šüýØ6E1°0q #Ù)²QGÀ]=d´"1^ÎV1ôkñ ¯òᕸéÜÚhöþWB‹!ÌÖ§¤ú¥=ÒO2ŠóQðèLƒuŸkQÎeñmt@sÛðÄt]ÄcO<À¨' Ë–Ew¯Ð‹»ƒ{Åkž£Ïó¤2øSô!Ö¹÷ÇD ÛE #DXPëó€B¨b_nu5èD»QscïØÌë™?(ËìóngæÔ¹Ï¼^ÖåÍ…oë¾Ö²ðx ØÖîö™‚÷nOõd˧†}#·þ¸h¬å$8qmj‘·Öé_œê‚ΛhXÿ¥_ÔrHe ºÀÏ’€€ÅPÑé¥Mà 2ØùxYÃXÚ§qN.Mß‘¡.I§žê¥ÑsœšæÕ|Uz VÜšd*º¢ÌÃ`í?EÖ^}&Úÿ9ÊžíS£ºê'¢¶>º&Dƒ9†)öj®:ß%–¬§‘Ñßp$th¨y~ M@¦š¢¥iæX[…+à›€¥]¶ãU@–…n"ë“ÉAÛFsBahÕ¹ºùXòZW¯WƒŠg,w•¦ýÀ¹nÝ@>£À¿ã(˦—[aæï¡ËÄ&*<å©{Ìÿ+¬êj¨š.¿çìáƒü^ëz@r;'ÚKºR¥š>dØ-9dÜðð{÷Ý3í˜çÇÙFÝ Ï¤ß^Ú{8Q–_ýñôIñ½“'ßPÞ³Ûü¸4âSS®´9²î¿-ðÚ¬Kx4wº­õöÙƒüòÂ@‚áÌ·¡M9+~Ê2÷T —'™kéyK'ï»<9h‰4s³ÌFx§œNÁÆ’”Kh¼]>¾/Î.ziú·î_敯¹&æTÞ·b/./pNà’Þ-NópëÍÃZbÏ€f]Ñ}Ì!"6døÏÒPàŸ8³E¹Sü'džá)+‡N|¨ñTPH“Ío÷dtТs:SLä¦>Bxµl#^:A‡æ€â”WÃ7Šihdä³è-ƨ—@tæƒüW§48î«Ä-l×P‚‡\|HÌ¡ç÷õÙÊú ,nZBQEè¸yÙu§2(­Ð‡'Ú’y¹Äµnìbzß üˆ ”õ³DA²â‹K"L}ˆÇéãG÷ÅþŒYÈ0>Q7=Ì®ÜCUÞb¢{ìçÙôH O4 oûì/A‡xú$\žŽtI5ªü\BšIÞÈ Á‚BëEºPÇ€Äa`œÒ0ž(½8](šÓ6ÐÛ½±ÛܪÚÝMAs+¦%? /øM&&‹‘êÉWOm_kÈÖe¼§äºQN»&¯Œ+ï”B@шâ-ÿt‡ù?Ž;¨:‡0Z]á}ÿ:ŒsŒ>c»ø°!«é3æÅæzÿ~·œ¼%îŸCï¡MP jf£ù¢‚`ó‡IÑ+Ýn¬?“ü^&ªõ¤ªhM£)æR\PÑK ›—ؘ¶zoí’Ö"T`œÆuãS¬½2…V´ÅÉ‘ˆ§%­’€€Ù!´ßü:ô ÕBéÎ7qNýk/‰¢5h]fHPsúmÌìp®¸ÚŸ×¨%@1ÍC±m/í‚p†åçfnÌhؠ׊Ûj0…”9þ‚M˜ŽV[ÞF|1ëìЩ`’òyÅG2“Q Æ|Â|ØìjåmæÀ{s$œ¤05‰îàØ¯ÐôCB4_¤uVÀ‚ém>&2 àO8ÕÛ ƒû½u^Ž#«öŽl“ûïe&?gL¾ÖéÈd¶¿Z?ý:êß»£ƒ€È^@f¬³rhan´ðÇJš¶hóF{³"Îþx¹×ê|d]*A¦à­ú~x‰àjUGd;÷öʪã­7^³û‰%±'¾ÓÒ!Ì>Düv]äæ"ë\Ìq²XØÓ0øÉå0ðAëì$eÌçÕ•ÞÅÀÚÐe6JÌXüWGÅ>Ø”òŒ!³´¥ÛwfÝ!Y¤;¬³Í;õš;D쳌‚,/jžªµô” بìÇj~ÿT–ý3e ªÕ ¦"±®³í_Œ¥Åß™Zq¤œ™ZyjCÌ£1ÂZblmz´,/|æK09®t,ä€lÐ'_*–§%4tüPýrû~£b¾LË;c᪺rTœ€Z¶€,´ÜñHš™Þã·óß74Tò¥×ÍP7í˜Á‚ ýE6‚ÜEØ)f÷Ë÷ùUGè¦g7§©&Á! yzñ§®ùŠìõ8~¾eöÙÞ1=‚VÄ7{+FßOjšbîÚ!éåfðÿ~ý–_ùg˜U"è)ð|T\Á´¦c–ìÝr„jN$ÞnàGµ‘ $ï'#)åŦ{zéóf_Ñþ®_ŠKÒæâftò  ‘£ëhN<”Ÿõt®9‹ Áoy€èZý„,[â*Qr1 Gs„Oo· ”¼7:Ž1CãtY ãíÀ…O]qDΚê°ÿ‚GÚç× ½‰iýý*ÊnŸÄmÒe_O^:]¦ƒ4Ý’_+è$[Q(üè۵±*ޏ˜Ùèðjh´î|n †~{©@à’{ß7¼Ps€Ïƒ&2¤H׊›&‚ fÙ€QOW]–b™W›Â~ï=¼p€A©i+ö””)‹aLpÔ¾ãê}ekt¨á›ÆŒñv}Â×Ó…Þ•É5%ê Í#|m…ÞB£²C£OS’€€Õ¨#Ú©IÓAáLu|) ïc §¶þÈŒ\.$†i8½œÂ©d• QJ¹"741ïí»¶˜wÒd-|ª_Ù{ÕÖýÕ¸ƒÑ 1è¹ 4gHlÃ…¬*}ÿ HìÆâçÑwÞ©~évaDý½–cQ€ò¤`ºÔ‹—¯ÊG¿@ú|@h¹G”¶ÇÂSºÿi6,5›«á`Óæ#àŸzà6À@ËžH‰z;F‹ F¹‹Dæ¡ìúh^ÖzôûÑãzÃ_ÿ·Â•fíô÷º<Þæi-J±¤m3²CóaIEgã~Ýp¬Ó®äMœDø)8»»´{vZõ½NújãAÔ¥ÌΑ 8Ôì4³Ø“‚²m À=&çu¶†UýQáIqBp R5ÓeCa±{eÝ\5t¡‹(Ÿ’¼”¼yq"d!;pZøçuC× ¸ —ËÃL‘<÷«ÏÑŸNÉÐXÒ0ž=Ø2Í<£* ô«MÏ&(òóèØ¶Êæt}4®Š vâæè~Ë×Ú(¼LÞpK9–D²›Ü-ª«óg_R¯DÜç}ºîÞ?[Ùø2|7Œ‹v OH« ÜþR¡õÒYèL?ÃéÅb£G›‹ÎHèpª_¿î±³ÔêISNL’ñÄïÁÒ8¡¬M:‡‹´cåýcéæ)ÆURÃÐà] õ)ü´ÿ“©IÝ"\ 8~ÆçiçµRÓÞ‰¥”ÑyÇhÙÛ»qål.q$ìYSO˜/sçÜ„>î»É‚FBû¸[.µH¸ÓœYáŽÿC¥…‡"GØoíÄT•šà Íô­ å‚/ë)iªÄO G×Ûw(;“u€±Q2o*•Û9R€êà÷••쯞e@™ÐÿÉÈXÚÍ…×ÞDD¤”³WòFºcôÅkO»—ÚÕQNv¯°‚C̸Ѿ ‡ª»ÛâoÛ+Y•ѼȲ'É÷¦½\àW»F=ùê81ìü,lðCÝ-dû}–Û»—œ½’Ù\K§¹…„ «%¢æx8€ƒåת E¾Ýïà* t·–VÿVVÕ8Ö˜¡n³x6Û8ìÜÝ(é$é<R~Õ“ !˜iŒN¼|[*Îpbb\pâŒ]§^ +hú´! ÕdõaÆ…¡}Ï\À\wÛÞh’€€Â"”L!¬A$v:ÒÌÜ.)–Éä’6*¥ßJ¸lYžL”ª–ɹ”*-ö%aoÑ·uß;S€Ó"¡íò‡‚]|¸|ËòðËDò3ÓT†L1áL{ñ'Ù·Ñ¥)ߴο+¹¸q °5^„®MlãB.³‰¢áü«ì³Ò:6V=›ÇRG’¸öC„î°Å+«1=Sé¨fë®°ìN46Æ>̺,­\È[¤õƒF@‡†+½ÿµ<¥~I¦B\ Ë5æáH[îæ$¨]^õ­ØT™ÏXåܼjwÛñn›âoø¿d£MÖ÷Ä'ÿ{ôbùÃ+°ü= gëw$×?q¦²õܤ/Kphï’Ç¡)?~Ä£.¡žüÝ^Ä`9›'÷€xÛßá¡øœ!Nm½™‚¯×îØdAƒîùº:\Žeœ«¶þx7õã÷°ƒ`ˆ´k‡xKªpTDô³^¦£8¾³ìmE^±( Á@ãÀ¾ämÎ(€ }ã\özs¿ÆuQ(/·Ý›8õ¨ì<@JŽ¡S„–À#ÇùY6G·YFhj 6dhðŸÒ«·†<$JÌ&‹"6!:@z;–Ó5t¥=ºë;™¿¶76ÕìÜ䚆RI7€r¢f! ”cÁ¡UÎξtB©nð¬¹:-\¼xyá¶cßÅÙî,-Þ*bPZæeKÇâ3ßãÈânM¾¤å/ö‚<ÏÓºéÉ€åD½¦Æ.¢Ä%¹?'ƒm®Üåp<<¸"¿ù]饅QÙä°ƒVG}Çhe3œÉ° ³WwD—(} xx»ŒPO¾3Ü}ÙAÍ ï+p%ú4= •5ᢿӺg‚UÑ ýh¹9T´ÝoÄ>¿Ð‘[9òS6!0¤xÆõ¡wAºùóZõï¥ùå?]c§½Š6¿0ÛtUõE¾Ž<æ[zB´­ëh¹‡WZæÔQé/hWC¨Ž,F}ºÖ6 Nëºæ4ê/·J˪¾ÜB/`ŠInñ»˜Îú„ZeÅ ìöu@†ãÏC`clúþMÍ/Ö®ª\¾ä~Â+HñÿÍÙŠÍ‹CüÉ<2Ó‡ŠâJ©iT m¸;G)„|™›_g|}û"vûYtfŸ²ƒ½ÇÎreD‚ϸ/ªs­' f^¨%G ¦ *¡c}ˆ±>C’€€¯ýh)‰ˆ·ìDõíj¶^›r»¦TÛY…Ì ¹s¼úÏÝE²é˜„æ[âXoœr[>Ü}.uWìf ¤: ÄX±ô¡$3ïÛ˜B¾òíº¶¹áÃI8õª÷¦ÔÃТ•Õ’¨ÔŠ*³”¦œ˜ûáHN ÛNª€P¼×?ÉÇð ¿‚Y•Ö)ë{3YcT;9ª÷µÆîô~‡»/‚+~ ’æ=M’H†J° Ì æRÑÁõÝ(€|$g‡H8v°ÄhTotîÄ|Œ,G¬è“á’ÁúüùªÃWš(M„ÝÁŒ¡ôY/ˆÚ,°ªHRdVÙ膃>þ;t‚µ­9~æòMS Àa¸²ë¹Ûß{-ªÚ¡n¹¸Ô–P@%ižigÞ!º¨õJêrƒ6nwM7¾ùG ýCòÌ­±³Ó=å;¾£óRzµ €ÂZxàOº-:àb‹1´å´Àl½óA µ8ßc¼šO mf*BѬšžWœ\½|æ-.oíg¬†÷üh8µ„Çì-C’¬M„@’¹ zßÄm‚ñØÈF}B,÷tšÝQÌf¬CûºÇK݈`jæ¤3csoFvÖ]¡qa¹h0ˆ‰Ó>G©â2ufû­Œµõªð)ëǯ[kÕ4q*‡á¾ ¡ÿ& ¹OåOž¼S !©ÕSxÇBK¤¬'`OõX:’„‘:{æƒáJç½PÅ)bHn‚Âlt+$eÉó~B’ˆÆR˜þ-Ý.¿W`MúåoŽz”TeŒÖ] J%Àùß’Æ…'U›6mÈ!S³ÒÆË•ø7D-òÓËzû ÙÉl°õs¦É7{¹±”ÃÍÓ1î_€þCX>T©ˆÿɲM¼¶±Ú´Àšv7´8NN—¼1 长Ö)ÜO^k\33œ°ßÓÀ_oÏÕ¿—HZe „}üÞÂäG)LßþìP™÷Ô:ªMþ¶„ò)ø¿9׊úÎe¼‘pwå`â„èÉ+¾fîʺªCì‰õU˜+åZ¬¯zŽvŽsm¿1“6Mÿ}}¢i9ü†ÇŒ?ƒÃK°1F¶ijšz„JyûPû/lã˹…ž×„wÜ“ñ,šJÖÞÝrÁu»€²Û+ë!ÖºÌ[Ÿ—)æjYÆÜƒ©óæõÁN^½9ûb Å†­’€€Á%8xúŸk'²óOž"»§ççßì¢ÑìdG±-x ÓJÉù±Nè‹¢PÊgù€¶±H›{¯HJ Ù6~Ý]z«*ˆ‹x|-µ­æÀᔕ¼=#ki›•¯Ï‰~ªf «0ÿ.ǃûP! hc”ÆÑ_…1c©.2ëai¥³lŽ!¸4j86³ß ÙJ<4”)9¿‡ØÓV)‚©¥#¤;ënªÏ^p¿²F/këÀ£1[4ÔJRcõ D-@Ö¸_yGöÐà¡‘Eñû+í™ßgÅiþƺè¸4/Ùº¶šgÍý ž„L¦„ÊÛ£r©BFüj½vä©Ïí1y¡H?¥òEñÝîú û¸_˜b£LÍÀ®F¹ûanûxÝ4"zš‡ùˆüö&]¶% Õøö‹‹5O¾Iè¨)ùÐn^FÖ;E†%dpÎó¿Ö²!Wåñ”Öt£3%5ª¸tÊNÒ,¶âå£ã#Ú ª1'Ž7ÃÚHgyÇŽ½ûBX6ؽÆÞ~Ay­×9ëÖS”Fâ5që6™jJ ²\ŸÊNŸ—\K, Lož¢JF§ýñ…½*†X!-·1°¢Kõµ¦c§˜9DQ†•£AýdøXJ«âšOs¹´Êÿ›ú‹ëìß8™\e8 p,ðâ¹$çä3p(Œ“ûÌz³õBÄmk¤¶y- Ž˜§N,‰…Pz Ðî³DÊe`ó” Þh*ãý) å µqƒÏCU Ôð+«Í`ZÕK„ ñßE¨2‹ÿ3´(úüá©M)âøCìw$¾÷ áŒ6eUEõ—¸¶{‹•´Ç¼nŒ|q`‚æÂ: é± ‡Äšjj4©G X[/¼se«P{¸È,nϨ¤:2‹¦g/«p=†* ÃT\Z. R=Ôª Ðé~j_xM*"THrLÎb0ó=­_ ݲ†-W(?O,?­bF£¼êîîúGW¾¥Án—ꃽ‰²Í\–·ÔCrŒ_®OÔ&óy;Ó±t`ˆ6LPþRÖvvÆ´ÂókŒ¡ÿ1—vìö èÀ>à<ƒlÉÚmYáÂÏÍ}R~à‡Û .ð–-‹6_qn´Á\Ëa$ $’g¡ÇA%0Èn 'Z[Û-–—h¤ÎʘE€]^ÅgI¿°pCÉÕèiz°’€€ø"@/ìyÑ ÄVKnÔÍeÄpùH‡•@Eõß7u[ð×ÐÑïD§±7·cµk¾0Ò•ÊÿK;"*»J(ÿg¡«Ü8P†“ü—mWV6â?ŠïJ<ó!áÙps|ïdH¢û^„ä_„J<‰€zD´“Ìh˜%\i^‘Ʋ]†¥Îè]Ëô¸ $L8wð¯æudWcǸItº[>ëQ”¤I79»Íí­o]¶7‚s"ݨTdÀ»Sˆj|B-üqsì¨Ëã¿|â³VvTÚG³ ¿â)Â;‘‰e}ÃüÖòwc9Ø#KÿŠÒ»œ8+³6NOþÏj-kç&#%ÐnöÅ;@c6Ÿ!­Àµúð–Ó÷xx–©ÿMN^…å2”0'ðÛv©/YWEŒ×DYfoVA¤MbVŽd™Òðä”È–ccͪ>|¸7´@'\]ûÈ ½9”‹mÇ^_l¨ØdXãsÃNK‘<ÍV#–¿õ ªøCq7NØõ„OÈ<–b¶WFTµØÕ!Ü×y,Ú‡Mü+/Ö;Æ Ž'…]jg¢¾ ÛOmÂÑÄà·rŠ v¾ êB=7§Œö+S¼2 µt§Å^Q§ #oâÕx/»Û–¶Ür7˜Ññ2 ,Ç«¨Ò#2,ý»y’€€§˜Fuc‘é-“ÄHúÕAwY¼¼P.…yÓ›‰Ô í2™ ǺÛK”¯ïvõ˜ë§ëOΙW¤—‡{z®·jÔyú7#†‹v¡sÔ ”P…ÎLòZöâ©™!] »S'…?)¿/ ‰‡Ö’C)ا9ç ¥å‡ìƒÓ¢@hy|ãQ«%ìé㕪€ó£RWÝähùyœD–Šn@¿\›Ó­³Hfvøzf²ÙþXsštL2ëŽ!tì7EçX­½ïÚì)EAiŽm–á(sqè|™×Þ ‚ó,æx½&Qfk…WÒ€oãcÔ?VV®SÀ”ì_U$Þ Œ’ïŒw²:ú¾?!ìq†•FŽ<l¼iÇ~(,œ¤ «®Í”›J+ð +£èX^Ï¡õy´ñA°´ËY[Uq’YuÙÛû†r;”¦"Gâéu˜› –„`_ÒÐ_ŠIÕp¡ œUd¿z΂@vg˜=çIrÓ㔿l/“H ZpÍiÑÐâ 6 ¿1©* R²9ICœnw§ ³’×§:¶%/‡dêÉìöÜô¿sj•ŸÙÜ.ϲ²¸íÔªu/XöQÿ$6Ì+'˜Ra”²pº ¿†ú@Ê+¬BGõÕ* jÉ@8œ8 –«ôw ЫêפÔþ 6ÑÞ†î`=ޏ©àêÁýæ}[EwÂ)+ƒƒNáa=ÇÕöʲLûu’ËêLÈ:VŠvçØ6Ë?²¨Ôpô‰/£àÚÑ?:„5@†Z^72ÉÚlvvçÈŒC;/¼Šóh 99ß<•“ï !±Ò»qìÜÚF]»mgumUÄ·À„yÂGï‘*F® Ázùˆˆ¡›ô"i*Ʋk7wì Æ!»O¿lºóAVà·Žª×+ô0`þäEïÕè…ЛDh•iwÊ¿€ñF¼Ó6aªkˆà6æþî$žz ¤½úôðCø³XšŒî(„ä`{¦Aßð’€€ëC"Ík¶åzw²}·¤ýÄë3Ø£ô> 6­› ßD˜l¹~ot‡Þ'™8©kAN¤öà¿ñîãôùÄÝT]t(±õ3œ !éú·¤Šó¨…VVs:È¥S+â ~ïö…rZûИYg-¨\Oˆ­<¦WpH‘xsÿzšî!œ gò6¾“ÿ®Â`;vÄÞe$c@"Ãp%€2~BŠ–Šy¿\fÂÉçŒ{ ŒÙLÅ =‹=ò £øí<› —ùñúã>ñÀõx÷Jæ^¶ÿ²à±]ƒDy3᾿ ºÊgõ>#v›'-=ç¨Úó'«ý¦üŸFÜbA>I)ðK šÓí@#×õæœå®–L ÑÜë‚ÒÖ"jPLMyÇl*_0ߟyâkìœýENa±ÇaâF—ÜèRF•E›Mí¾Çnüäò´:Ëzˆ0C¾É˜‘Ë&¦ÃF,ÀÔìJRÉA³é$Ùý¿—·Ö:ÜèXÒ¥Ip}*{sSéì  ä\ò.fy/ø¶÷ß)ÈŸ EðÕ"ág>oŽ1¿ôˆòàaÇz>ï M·=T§Ñ6ðv "e­#Îô –6ñÌN!ø{³±ûæ§ðl Ý=è]ó:/®p®2@y;täÒ¥È'AKX5¯Áò€š¬h ™ˆƒ m‚Iÿ[º_‡ŸÚÙ>†¹ýnˆe…D¤l®”ˆkùuu„3Ê­©ÒÒè5ô] ˆFáñÖDi¶2cþ1ö?ý[CÒÿŸí4yÏÉý4`j%ÀH’Š|*þs5½{ûÆqdå›aƒŽ%nWÒ"&\#\öŒøäÊEâ¿·ÁS[Är}q7Ÿõˆ°”]Õí5·ñ,ÏøPé¯À…ÿ£§ 3GˆgnÁ (¶ü 8j VQßùÊõ”¯’î£Âfvév8Ç›ïzˆ7,r9èªÀz‡¿õ! ‚µ£¶úšðqI/…ÍŸ‚b…’ ‡#bñN=®8t„qʸ <~µÆK¢L¿< Þ=­ ½ÜÑm4C ¢øCçÎé–fìÚ?ÂæùÖ3©ëE^VÿDÍÊ(±Ä,ÐrÃ1<Ç/£æ­ï.Éô 8º0$'S}YزÁЈÓVª¥{œƯ´z¸ï×óËÍ[¿ñô»É6ð˜©Å6x*Ò牞»¶€é´iâɬMY’€€Óû~„fÈ>QU¿[ã ƒM^ªÃ91wUØÀ|êÅúÀÌê³.iî¸Æ_-ϧžAÿjæ•0EJÑIÌ7 ‘ƒ;g¾õ_²‘£ ‰c¦ñ¹‚­Ý(äªÍ*¤-F€òÉÓ§ñ» èòKœÖ5¹ÔP£ÜfŽúĉ šµ1Ñ-n0¡ÍK1—†t…b…,Ój†™jÖš* Yˆzå‡ÛÔ›àǾù.¬ìÄ«§™è ÖDܯ:ûÏræJ¦n–pÃD¢ŽÎDérÔ3„ñ?Æ }sVA@â™0ü‹ÞBÞnà@ZÿÄ•:ÈØX„ D_ "±*˜?o? ÙÜ¢kŒc•8ÙÁ䈴¿J§†­nÞ”¹»`Ã[ÛDÍàO@Ü\Yü•ËsåE3ÕN ïÁ'ÒªæBS[•»qÚœ>x6Æ (˜ñäðÈ·bíù›E5*’'ÞÞÀVgC‚Ã_®éJ%`ɳ— Þ]˯ܛ{Bþ]šOýŽñ¯xˆ”ƒõ‰3µúµ½õ\Ën§gPø[zPêßÁÊ3ðš®±ø+?¾:Ïe+ô<Œ=ó¦.‰ÍméF&Âdiºý¦ò2E1’Ø7L,úo;†"w “òf‡½ËÁ[j¶eô¦Ö kÿÇ•—[­õ¸9¬gkÉúºï}†ûKïqë¦h›d×>»± °«Ð%l‘vwYº%}È1†S2@=Æ|6èðÍ¡U€‰Li3=Qøž©ØRά’¡ëhElFU$¿Q]“`Þ,‡ «†9GÏÏ.„w>Hø'#¶8ד»U+¦{¡ÆÓ×#…˜…v€p™†qåíþæÎ!Xð5rqùm Óö¥Ï劜/Ûb`T!‚tD´æ¾ŠýqN(mÒwbn‘xËÐÕ¡—üIã®x¦Òçóðœ“\ë5 \±C!ÃVÙ#Ò¨LEsè2U‘:Îúé} „éÑSy¯„ˆÔ}}ã“è]Oº"žzI ÷0=lª|óµ°ç•Z‡„ÉbC©üÕºqœéÁj6pwÕ€½ìZÑ@ÍŸž‘f]#4.ÏO.! O·à0$ôMH<õjÜeðg{"ir«¬÷•#8ÇëMŸ³8Yá&ºè¡0tp'Â(Ç´}\ùxK¾Šó’€€Ø®cÕ.réž"ÖhH‹’üWRÇÑ,pQ&Æa~Ÿ„˜3«]s6GC®Ø6úAL§Úæ’•vîÂ5öiÎø£,D[I«5K )ˆôT–›5ŒŠ õO³m7øª±+Až¸þÏ÷»£9¦—D'B-–;ÈÚv]X¶GP[]pÛΧ‘4Õp¨%êß«h_ùA­TÓᵌ98åò/5xv"6.èå§ü[«#FâbK&ÂtWås_Q•q쥕;s%ÝùX»©‘vbZº/ù…à ŸºkÀ þ«ª˜˜ØœõCh}„»ùÐ$Æ"w ¿Ø7¬‘.iõWÒÍ|X̺™–Áq‰5#Å—Æ¿ˆhN ®âÞSþ„¾*ù°§W]YÖ̃Šß¼¨¶u® ‘,OպδÖ†ÀùÚkríbg=°‘²ˆh$úmÓÎRHãÓéPþÂÉšhÊÌRº¯¬B$ÏÊ•i €Ñ³>ñ®4¬Àj¶Á0xVáyîÔ%NLZI¨Õ³±íWIüc)ã#ôO–º.ñ+r\OîÔ¬*£È[}þ²¹•nZlº’¾¹–3nÁÑlŽ×ÞÈ Œ*†Î¼«:@R]Þüj¦qA3 ØØ•¦½½Xšg¨2¿6’( ©%Å©J ÙE?…]bÆ6VÑ™øEa‚R"ï.Éj”]PöŠ"îl1‡ (ŒòD¬¼//XQœL+émŠURx;ÕZŒKá¸ò÷‚ÙC¥4ÀûUÎPÌïÈAî»N*/Ú>jqöË›áòD*#èï©8DÖzA>Ÿ—„äz÷ûìzŠ>ÿc çÅ J\Tv9Zç »Ã8GÊ+ ‹ÔêÄ-€îLÌEhÄ5ug$’5äLä¾·nR+‰Ÿ~Ä:É`Ûkþl^ÖÒŒßÔG‹µw¯°U…V‰ÍÉ­KïèÀØnÚ±ø‡!ë ÌÛÐ i~.;Ý(7¯³ì­½ ‚µ~w\9ìc¦kúm9FUÚÿƒÈ$”"ž[æZ°šµ” t|…d\›q4€L÷©o}_»·pObs¬˜pThT£+å¾:«ÓT¶cêÐ{Úö¡7Ç‚ícÅ€ã -)ð`ç¡*y¹h¿|–µ0UÈÛ)Aì˶3I²cÛÖH ­>pþÁ‰¤>'‚·ò:lr³Áàs‡=Cøßâ•C|g‘.tÚjÁR-ï9õÛô^Á¨œ¯•ŒHúz¼ªWÀˆ'‡<î ¿c*Ì÷Háf#n‚òH³îDñ«þן0¤ÿ´;’] =ØŠ%P\!ZJw,ôS!Dõ ˆÜ,ÐBµ(Ü ÃšÖÞ½®’¹õn ¢r~q·ã©û,ZpŽü‡^ↂ‡¡×âÓ•xËh{\DÚ³å©Õ2ºÍT“§âÆûÓGç$TÔÓ2wAM:ò¤Rg´ƒq¤2âxþ+£R - 3]&zí•y¥Kçæ\Ÿ›­Â}E`;’"qvEs©ù¨ßÅÚ¿^™üûü\)ïþ;œ‹¥H0ÃĦh‹Šðħ+Ù®»-ÜžÐô-ž]Q ‹áQ^•<öëf߸³hª}˜×mR¨T}ÔÜÊàÿ¸§|Ìݬ«¤Z`ò¯CÏ4L¨¸—õn½Q2‰Ö1ÈíÔpÌB‡Öð7QR-QhÑô_Še¨î¤!Ú*x’€€Èͼ7¤óafû?‰Ieë©D7Üb)—= †ý‹Õpž¾^î "¨¡:c¦¼žyql×”¸DT ×Öõ Ý|Ž&ñø£ÚøªPó0·.ºáå”ðíoè¦î:·û1õPz½u–fn3è1sÈ-"QÁÓÅÿ!£]Ñò’ÃY™þË„x[sKß-†Ì0Ž»žd7üÂàø.‡:‰þx\y x ¸#:3ýØ#”ßN % 1™1zôØœ“©ðc¤Å“dy£UÀ:£Ð-[O{ÉMY‘ÐLƒÓ’Iv]J@)ûîW0#,&ÉžnóÀ¦(sÜôHÛê¡¡óúyË™Gß¶g;HWD ŠBÔf^ÌsgîõÒïÃU„¤KAskœÐÚãîýTœÑ¨ÃЍ 1"ºÅ„[$”„“µ¢Œ/pg›Æx^„B0 üŸˆFUœ^iJ ¢=)! “˜À iÿ-FCP×PºŽc¬9ÏêzæÊ*çr/ P‰ m%2ãDî”hîõ÷\û¨§{ù>Åâ)DÒPݳØs´vÜŠ£,ns6‹µïÞæÌg ®÷c°QO¿«é1˜7.æóJ†Ó]£õ[÷|Õ_n 4íåR¸K-|JáI»¿…N‘B_sR¾.B#J(¦Ì±Æ¬lÔö:X¯‹­ ÿ]Ï‹}çåº~•ú®aªª^ÎEŠåúRqÿç,I¯ð½ ?5r?±¢¦mÀ·`QÜdO^!ñ©XœgšŸ ¾TŒéˆ ‹Ýè×Z2¬Óxzâ"…’ØNÚŠÈ]—Ú˜y‘ÇæÐÜøü»µÔ¾x™Š´µÒÛ…ð"J^Z@v²ìéB`a¹Çݬ¬Ú¶’ëÜ®M˜0••¡’áÝrÚãÑ\,½V-¬â‡Œy“ ”ÀQÑfôFLˆA¨Km“ÓlÒáÀ$Äÿ‘ÜÊ" :9öRo’@AeŸµ$”hú~ª!'û°L±b…ÕìuY|“7ã+¨R6†+œÖ<]Íì²õOŸc¯Û`°):;^ Êõ9EÒøU±Rßÿpæy*Ûx‰5l­½¹šaªz{Äç>åRäÀ!À´ÌȺ©V÷G —ŸÉO *Îè´6:þݽEÛ3õùȤ¢gâÈŒò˜nÀ3ãâ[“Ñò{QajãF¿Ñ9ìÕ›Y ®?‚Ü{fü’€€º0¸îD;9Ï6$ãWo: §BŸ+âo+58V÷¼éÊqQ}‘åïo(Å—íƒ ÅP¢¢Çñ{k<¨_§ÇËÕxÑ—ž÷l^ìÔ„7}›´/—l óí¢ÇFÅß u‡ÀåRʯæÔM]I„Ü0w\þ!>±¼)•yì£ù›æ9&eÞ>¼$jüwœô­›ˆNæƒK|©y!Èr¡÷:D6ÍTa»žØ¿„>VþÑÝ=)\¥ÚwÝZ8x·9c—%9|)Ó&ô4öAÁ]¼ K  K»÷WüÎQ¶£ŸrÑÄ€ßåÝ´602€‘‘w³׆§t´KìOŽ JÈùWžÅE"ŽÝÃú‡p7áU}qp4ÆaÌꢴçã:'ÔDçA´ƒìôEŒw§ Z"?6ºý7N§½°ÉºHÊÉS¸yöÝV”qŒ­-î׋Ø[«Q>7•&ùØŒ']íàoOv1ήôGÏæý›PXïWžayþShl/{4û‚åje؆ù»jßXaÛ…™D"¼uÌšBñØõòÅ;ëœðøªÙ;c&Å6¹ódE³Ñä.ZýQHަ ƾ;œa9?Ûd ت‘!Oc?K®ÿ®~Ôg,I*ÔR&ÓÂ~n¿DÁ~ꄤ•5M¥ð­ÐȽU B6{Go Cª+%ŠD.%e’ñˆ+ØžZJ¸5¹„yÒs– añFÔ%˜ãü-Aíê/øDpä"­Ú´²n«mTìnÇÿBj)4i[Toê2 M±"5nívÔë§Z#dŒä)ó¬ú–sæEYPyžeÆ ˜Ã 4ܱœÒµ_$‚B;<ÆÚeF&ÐSô"õNÌePõ oÿ°MxÁHkŸ_é«;¸„ŸPÅy¨ÎŠ7 :õD­P„'ñš0hôÉþЀxÌÅ’¿ÆJÃJ/‘ŒÞ‚ê'ùÒ?¢¼ºš%…£7r­ÑÂÄ):k‹DïÄAɂۊËüýv‡ášßœæO’Ï †^1oZ…ú`• v®Ìýi<ìXptu°fk³éÉŸ½¢Uª¶:…Üéí u0| nánÎ#ï?ÓM›Ì>†‘©Q¹ûRƒâš!!I›«ò4öÖëÁóäúÀöV±ÏíT¥%¨J¤XRtˆ¤’’€€´üBö¾àâ@ij·£Œðî7f1ÕYYAæ?î@À;û +â«YŠ#™}“I‚ºN&üäOfÂ$ø%Iéãø­Ú—shPêj–Æõ0³cóÅNà^H]vÁk²lôBˆŽ{²¼8Àôb» CZÚë.lñ¹gùL5p‚i¯ý$Ñ\_'Œ¬æ õ6ÔóuSØ6æ@ÉÚ‹U–>3¹›È.´© ÌÇÄ„ÏÍ®!j¸aA& "ÂYDIWýç?¶G–%š^®Z‘Õ}ɦ=8ÕQ{è•!Ç–h6‚¸Ó‹BŠ:¢åÙTwc;ÛçÑb ÓIB‘—ÓûHÚ`4™}#½11¯›1ÈÖ§Íò+ï¿/ÉžZ§>c^|¥‹·¨{‰•öêC:;ÒÚÉ™µÌâZºŠ<ðØ?§ÈsH:º#ûodÉ?.ZIýÑÁ ZPWbÎY™fÂí2‰ù¯÷/´0J˜àCJÄûò™4‡ Âvì8Èx’ÞK±*u•WV#<а+fÒÐïìIL½ïm”D;bë‹äØØØrPÊÊ$‚ùŸeg·oreòI 39ãä*; Ni=Dkþ%Ví!È@­Y°q_âB‘¸E>>ž-?ÆG‘ÎïG;Ä™9$—2&i{dI$ 9þä ¢s†)ÝúGÏfÕùÕ ÆÒLƵbk3Ž‚½`õ¿¿¸›B¨¸¤ªjm9ÿ#xW 3©×:JܺéÁ8$a{êYÀ–:×@Ÿ´tÕ ˜l'ÞX,¥ÄŽºŸ‡•Ú×Oì¤,¸æY {u×[¢>ÎɰH6ç½AÄ«åǃœ¨3йÏËÆúøu¡È‚W²3““bª’3–OM‘ñ7áwH«±ä]ÇšK ¶²ólµ0Hêoe%Ì‘¯$æ‘Dé.wŽ%Oú­üú!EÓ •-Ž)ªVX`;ÃÂQ›‘i§óÁûé¾ìÂdÌüí¸&ß6BÓßòôÝ#Â?'†ÛÉŽ¡„1ÖYb €r»®ÇÆÔ‘aÇŠ¿%—£Ëh²ž@e1`ÒT™f ˆ¯ˆÊ(´,È¥ H$s%Rq[’ @ûÁÙ6]8¿9í‡gµ\äj6ë+?ƒÕd:U9CCQœ3Pne*ñæ¾çõµ§WT¡Ñnî/sá’€€ÚS¿þh¼l!aˆHþâr àþ8—–›CJ~ 2ŒÞãT[@ ÆÙPn "m† ÏšÈS”ÙVt‡€Åãå7ñòJqˆºVx𧓯–°Í91Æ½ŠŒFã~NöBEJ·°ìs—˜¿ÉhÛ@ J˜iíuD;Ù{–ÖÉçláÄTŸ1uߦEJRU“sž±»7 ‚µ½PÏ!=:ìnºw€Ý‰cm<–òêãeã¯úí`ô™ŽM]ç’ÓCU%“apPæáz Æ¢…J2ª¬eww¼/e»( #²m‣R`Ø4dñÉRþæov=ù˜`’Æ_Á©Oc’lÓÈyó ­C¤=Om‡Øñg¢lnib’}‚„ÎùqÛm í…$O0+X'Ýr<±iOñ èÂÛ¦]¯ƒDüñ>‹’€€û¹ä’ºCã5¢I3‚ÿ½³jrè È‘PjL"Œ¹5Ÿrs€EY ;ÕsÖ¥­žLj£†Ô’ÀÁo7|ÇXþè `Sèésº—­¼Ôj/mXüÞ‹Çy¼ýŒ#r%± ì¾PS€Šãå"=©~`E‰s3 äbÛ}ê#£‹À¹WôïÉgÛ§ DF[ÆbMf€›Ã½ UBc«ðº.B~áx‡Ôˆî1U»Éð¾’×ß¶ã­Ôe¹e);?ÊïDÓ3î‚CܱÌDîÿ¶&_ Õ&–1Ñ¥Pì÷=ðËT'=d`[ƒhÉϦAnÝYÊ,Ñ庵 ßjµ4fÇKø±;ô­¼‹4«Æ^«ï­ëæ-4*$Öb®ËŸƒÊ³‡tãVÄðkˆ%õŸXÓwRÚ’/=•Å:õv2¶Mxﱬ=îÚÔª¤Ü™Êf‚×A–ëJå ÄüÌ›¿!^ŸZk^.æ bENš„!Ž»dVRŒD)Þ´ƒ?NõHà˜ÏäàÒQ ðs‰öÅ 6õ¼Ž ÎxPÔR¹§‘¸}imë‚÷‰9¡¸~z,n7 ÙýÀ#M0?H¿Ã¹3QPB¨ŽÎÓ`¢é½H£äÊå¯:PîâÀÂçMm°ÜRÙ|®B®à ¼r¯¿ËluAþš|ÕâaW¦¸y5ý>:ó0'"êœÙ9 ÞÚØ<îöôKóŒYQ÷Ç÷ÈSf\ÃðØI§g¡hyÐAá_P­`™A»9CqðÓ>šbUýšE8jW?Ù¹DêæhúR±‡·X~Gøîw/b¿)D¦A[üVÁ šO=ÊX]VÓ€+T‰Õ3ðíØ™•Q¸ü€…ÎÛ¤jÒmãEUØ•¡ $}îwòVÐÛ ¸˜Ÿí_NÌö¤þpCb±¨‡tö½áµðÚœp· DO;áHtJy¶8Ò«®˜Ô³éÕ¾{1üêšÐ+¯Ebú‹®®GPÌ~Oœ#Ý«¬}5…iðÚHHv^>29c«5’ˆÏéOÇÌNZA\„Cq—_y©‡­b=Q]|=ØmÁ9Œxi¢[å¯SGü¬òa.2CäÐ îõÔoض|˜é ’€€»ýZ…Ðh°£R04;|Š@d2ñúT •Z6ø¯ÌqÍë7xKù%à÷ ¡-¬.àš1ˆ®Ûð½ktçÁ¸ŽÃ˜¸¾š³‰y¾½ë™\¦Î~ñ¬ZŸhŸ¶ÒœRç èƒCZº2“ÃeþT.¼Š»›=ÊZÖ×Ìe¡-Î@D,Ì$Á$ú¶ 1HÆÊ˜ò†ùx%S­ÿ}ütðIl0| ž@¨”e4GoZAq8™ʆs*£²¾(¯ÌƒÖ¹c3óßà¢Í¢ßÅx•äÅÕky®‹ç‹ñ‰¯ó“,6¦ÿ 0ÜdÓ }¾¿2o`KåQåÌ @Ã'²V=—N•`»s`¥Cñéé1±M¡xa+ÏYÖŸÅÂdEñ‡.‚OÕC«ïKz¾7„ÚæZë~~ =†JShÅ>àOwÃÑíÌz-º-I6À[‹ðõG5uø`‚Џµ(÷g…ö<´L%ÐñšH‚4o}Úx)¯×NÆòSÎ^v|pŠVÒö޶¾µO”©—^ë šÔ- …Ž*õŸ:¦÷ÞK(@ ~X$`äÓÅå¹.‰kä½®¤øž"´§ÖŽº'8¢L˜Û¹DêDûº€]¯ÚÕá³»J]øZ‚.0FîCq\Lni°9vºó¤S†…_KAì—iHì•ðÐìXiÝLhÒTL`«*­8+XeqmsÚÀþ>ã¶«äÊ!À늒Io<º ¨õ„iAsØZ˜Ÿ,ÞôžÉ.=¿’²Ózâz2{Þ­ýÏ'ñÐÓàük,L–koȉœ²†ð7ØD9¬ nˆ£Z–¸õHg:EriáËiE-pl”òŽîQ?ì}À*xÒh‡x¼ ëÝg×€ËA AˆÏ±&‘ý“ÖñßÎ2%'Ó„^¯c¶á²ÍãÃÑøMÁäÄaÌS^»Ô¤/¨J•¤¸ƒqK])‹Fcd;È…süèˆ;#ÙÉa$¸‚Øâ³¦¡A“Eb£Æw£ ÕÈ©@^ͽ;Í38ïýÝ8®²Þe.rÇù/ó˜ÝxÝlÙ©lfæS <œ šºz-»'$,ʼ®aO0Àý(m¶ÆsLE˜ƒbÃUl$Ä3Bíè ²g´ä'¸ø‰°+fýS(°K¬Ñ¥#²£& ÂÚ,?¸ºqd’€€¢ä+»*&1Ö%ÖêÅaT=hãÌ”ª~rSYAøP#°UK4µ…p¢eaúBÚ¡÷/øo“O£”UË )ä16¼L·Æžöq|è²ôSåÇÈ[« Y [ \2Q”.ûïõHक£À手a”ó'dd@…g,Žyi±¨gêg Ò)oižrUƒ ¤[¯¹)Å£ø ;7…4³ú |¡•çÆNѬŽÂ¤]/¤xì*’GµÊ¢ðê>Î «úâm EžR¬çnx)ï¥xÜÂSE艜¢ÚÓË+‚V—µ( Ͱ³Wa-,Ât¦Ná¾1ü 3:¹ èåf›×‰Ý¶ŸÁ6ùK†Khß83§J_eMX"Ëþ“1½ÑJН@ó`ïͺQ—Þx§âušÛd¼)Ë€‚«Ì:øBäÕ”²œõý Öã«—Z&­ž*Ètƒ!HY VŒ0eŸgXÃB6ÛöÄu¿ðrÑýzx\Ip}y|¥ÀvW®M©Ôoœê/ÿÄ_ÏëNÎÅFdº‹«úÞÆ&»(øËLËúH)ëìöÿX’Â_gEæ{}2UKq@rkfjÝ}å{zôo¾P6éË8–é!~ðzd"@)-:¯sàRˆš­©è»®š¡î\ 8"ûҶ~‘Ò×#9‘yË6üŽÈû™ÉÁ ´Å&¼ç¨o:ÆTû)¹rÛ¾"úûÒ[™¾L¹Ž^@¿u‘pÊŽ*Á¯$DDÑÓU´%„u"X.,É{‡q;Y/çWíØ¤ƒ*ÇZ¿c÷€Ù츢 ^$eáÅû?ªM Î  €ØÇŒn<àºUÇŠæ9¬±£‘ÁÞ“@†/Ü™ûŒÛã +M¡ 5õVŸÌ!½êC…·`Pç>½øx±q#kÊÇ‚ùm-ž¡Ö¤©‰¯uLÅ­*‰{°—: ì²~‚æC¾ßJæ!†r‰w‹Dýlºøhßb’€€¬zá÷Îehš AÒP¶àn¹ªýJªZZ2ÇÚ™lcNÄ[R” ðßB€ #3\„Ñå ¢KÊIÙ̾,T¤çE&°Þ™ìO¼jÛçe¾¶Ö«ÎØÄ*¹íÖQí" ´ÊK4ÓÁa.›÷âô<Ð@áó‹Ÿx%¾/ê!Ñø‘+ózÛ&®<"=ì$a«ÉÒ –N7:("A²›h.}Õ÷p•}ƒù÷yÕ—Öü1í¢Õ‡¯ä¼ŸrÃs–P|K–?¢yúøJ -Eœ»ck€O¡ /ân¦öàÂ>¬9Šõ¼îØR)›³ðÔÅÉô¡LlŽÚ9Ñ­Ëqü-ðþ Áç›ÈM‰Ýàþ̇Ù(XÖ®¯Î!3 »'ÄÂ9—™P²þùSKª”}“M´°pZ¬œÛ­Jèr¼=¿h­ùf§Ç•,ÞíÎbM¨©Z½0#fM˸Xp 'ÁRàFÒ5enB£ˆåKåŽãÂïM=´:Töàw¢È…è° ¹êÈù;„+x† ·Q“ _!âõDæü×x.ìÁÀ¤äP^ÞòaŸÌÙ9ÊÀ5®ò2†ÓlÈD7Äa†Tæ|¡dcì oby„ûïà'OÒ?íhˆIY “ óéóåcÞ~eXއŔoÙ!’€€®³ÛžBìC4A1ÁïÕ[wt†Ù‘~ºBŠ:IlqŒ´`0{ìfºÃÚ „r¬÷\a“QSõHŽ5Érµ?í>€îqý=;‚ 6Ý<ñYQ\ðx‰<}êR¾œçÁ H;±ÆMM½¼]Nû?f·ª› °çØ1iý17DE‹éæ±›;!wëÊq‰c^«è±ûÃîÐ>9 Gh±«ê]£¥{a<¬åVÎ,âuvã`Ʋ|Ѫ ˆ»á—NõߕĮeH`þßÍæñš‚Dü,¿ÐåŠ{Œ4îW‹©ÅiYEÚ”em"s¯k~ð;A{þýl¶ëÆPAàúõ'O\Ô {•‚¹êÂMc*˦.}ÌÚú÷{G·®¨r„Г®ê.ãçgN;½rÍyK‡D¬h=ÎôÁ®Ût&1ÙæöÛÒ2o¨ 'r·ŽÑ1àåTÁ†è­#¶×Ênùt•Ç.îà(Fw%¬&ùBÐ>Úsê¢÷õ¶aìכÞê³â$*ÿ •‰”Ò Âvƒ!{Û³fæ™bÙi"Hfì˜ô_ªà‘c´vFÓ´y¾.OLh­Á3.0‚—º…[P.6fQà /7´FÁA2–°ÊéŠÖz8?T}±&rB±ï‡™(dA¶úm:™M’E~ Ñ93ãW=óŽÞ&]ì«JÑçêm„ÉÌ<ñ²$³¨ŽÎKÀR.ÌíÉÐlµç×u§÷ ÃÏì¿ ÄwL¡:^ÉÒtTÔEÕ¢«âLñ•6ž`ž%õ˜Ùº¸É"ú–V~´ÚEìÝ×Õ}=yˆ& Þ½ éä}—DçL¼SÂÎS”È>ÛIMÏ~ôĹßJâäjµÛµä¥ÿ3/«øÛ˜¿ &Ê!¬ð«úLg¨Ì°âÞ"-,ô‡üaAÂDgÀ¦ò’¾ÐßÍ€ ¯L…ãi¥‡Ô6ª‘*A={§”àÐjø' éèI—²wµ>w,:ÛËcE¯lŸ“‰â'÷Ê箈£º1i«dIÙUÿåב@’š*!yk ƒð¶T#Ý"øÕ¯±Û$êùË´ãî?ò¹ª™ù®e«-ÔÄ ææ_ökW¾®EUS8â{]­¥‰e>B SDM_þ|»ÈN[2y Ùò_8_8„Í+"•D´;ãé¼ :¹ Ыðô¡aø’€€¿joBXÞ•0cޱ ²Ùé]M{KÒPY½p­È‘ÿоvO¿áW”ü;ë6œÂ³»b¶Û¾_"·8Z/Òÿ+¨$Qçð!í¦ÔúbñÆ)`Ôà„2¦?dð·ËÔ+A”?ô2šHjúNýF÷ ûâïy“"ý*ו*HŠ*Œ¤:ôôäЃ ‹è“åê¸ýD ½¿aüiÆ‹ÝX@s×— ëѵ!$’‰rM¿¢‹P3‰Rþd#” Ј1Ђ)ˆ‚ŒÅÆSÃŒñ± «;W k]&…9ÜXá\ÐS2Óæ®jG‰ü‹ ~<É*)–Æ<»¥MzÊÜ”Á¥|¶¿ÄìÐZÀ]QbpJP¥ð‰›ßY7á4H£û„>p¹?8ÏjL*™žsù½¾ÿ(F*‰ÔI\¡ŒÊ…ÂàíD›¨3²B†[᪨õ´ ëyÒ«`ÆÜC,k=i¾r ÚŠ©æï˜aο.çµ)É\éDj¼»Ñ¿ùÞhü—ØÑ^áÙ?‹Ò;)¸“ž„»ýy‡- 5(AXåªôÀFVa6©…s¼%Í [¡?L­ª ›¢¿8*%SÏ+rÏÛõ=Adròá›‡ìæŠÅ_™øu j(Ø®æÒñâgÞ–@VâÝô©lb–pQŒ¾¸'áEB¹Šoݳ°U^Â*{Õ@×Ö—-’œÛCû Sã­h>4‘o0åó;wGz\ãÃ¥9¼£ïÂ]USu!å*"?Äæ"÷†ßhͨµÇ„ŒôÇgžxþ¨d:~ÏmÅñ€¿jÀ1A„«23¥ÒU¢rë{¸â^‡„ÎköiD“Otk싎F6;Lžh)zÁ>ÏßÐï,©þ*<ħØYéÙ˜é$O*¼,§Ðô?ÿÊL©kñ+è`5Æëî º“’nÚÕþÇ ó Á*åå³j¬¦ðçÀš|’‚›Bù [Õ籋–›³)…/¸ãòGbªhpý¦b zR¨Mÿ×|9.`I´¾ Ñ¡Š4 Èâü|áZÚᣓ ¸,³™+V½dŠ8,ã'η¥¿’€€Ñ½Uç ÒrN„¬ü÷¤Žøs±I)T™ qRVÛu6óজò¤RŽð‰»[½ú|ärœ½Ó.ùpë(\C‹µ°118d!쩃@]&BÇ¥67JàêhÈ]ÖAù¯9…R,wé½EgEZeÃç‡y4Úl»®û§ºmù{½”® p[^]þ¦¬§ÁäbÀ,4®A“ÖQ`ÉÜ‘"ÕWæ:×éªÖHÔÂM<µeÒtÚV"†å+”@BèðdœŒýiЮ‚ÁˆøxGž‰îTðòÊ1¯þÈüáX˜ô9éý«žÂ»¡;]Td'™Mçc´ û=Ê`ìØ[A=翚ëÄTáíP™SJ嵘Ÿ«hÎ:iD•íQ<ü(°Ù3¢ŒFº^±œP˨?M~Ϧœ‰7™qäYçÈñ^#† iié® 9;#¿µ6=æ‚c§â ¦ª„®5:A28wL³î ›×U0âr :Œ8Þ¨Wü ê þRõ‘(>ÎÅêó×vçÀ`âušmGþ¢®ò¿95!»‰²õðÏ.Ö[Cò™úؽŸ{Y%?âÉ“¡™¦f°ìPô¬,ÛMCCoKJùŸ,êʱ¤¤Þ ¾/ýP…·-Œ¼ª%fe†SUˆŸùIè¡ÇÝ¥)v:s ‰+«Î›IíU깊OJâqÊRñtÔ°Âç]‚1âË$1¦iýÛ¯ŽÑLLœ=yflæx«(²Ì:#3 ‰/JÍì¹ïEŠjÏÈ1}wHHS{þ,'”ȼCŒAýñ.‘:€¥1xòú¨ …´Ñbƒ„ö%5&8Jàë¾Î)ÎÓÜà]sä–èÃ9cDh hžb?·í_[ _[hºÇ©eGpCU’°|ws[¦T¶“•¥Ìâ3D€îÏŒ¸•·:à__@:¥oòš(kb€žŒ(«ûÝ 8ù=i2ñ]±°«€ÒÚ07Ftâi‰¹Äwï”Å7Ök”j§–_çÐ/½¸ï` h¢Ø§ÓšA1[?LeP׬ÿbŠB‰)J÷¢$ÃLA^%ÊËl¹€«FɃ%ÁågT´ô£Â27ëñ'7‹#åÇ .ô¨Ä²Î^=]üSqá\Ò³¿©Ó ëE(€×ŸòpSjZáOÈ¿*øPg‰‡8Ðâ~*ˆÿD© »aF²ôcJ«rB8cƒCÀn!ff¶OAêHîDyw!@µÀX+,AÎPÆç¼ÞgßmSPûsÄÜÁÈKùÓæìÖ*›kÿP<öj2ƒ½9Ò…h%€¯«Ý#µù/G­É"’•Ũ+2³˜á@”€Ñ³xª!àé°·*”EýssÓ7PPêuhrÜm“‰·P7–avÉliçºþaÊ>·ÏȱDj64͉â­4Á®Ck©œoèó%žc9éÐÅN·©_¡3V=_ƒ$í™kRÂo²(èj|Ì&©y½L-—¾ß:.‹I÷L’œ?‹@Ý[tG»p©4 %áOÓõO3i‚ذò\>ÆÚÚxÃð}CnfºÓáôÝ©Æÿ¸4òË Ê7r^cßtV^Ǽ­ú[­¨è é|;Ž‹$ìoV¶‰ëd@ó»mi“ÇQäFÊ”~æ‹×±‘+‹×å§N¹+\ŸNïs²§ís\n.q¸«{lÊÑ« V™“µÄm×Y†{²Ãèè.ãKãÍ)ß7VPt Þ÷¥|ËŸKdEÖ—]P÷ØKä—Ü…‚â²jlNâ5£ÉÈ¥©Êjó3nsëáU>jÊ×4=ß¾š §å—’û˨˜†Jë>†r"Ýcö«Ÿ´ðGâΈÊ:{¯‡×ê¿z¾þ ä“äô&7ˆÙØñã¿N¦’ßÀ9Á-ªDD éxå4F¼²_ϽšEþ˜¹Þ°P(z±ðí¡š§=¨C€ ùMÝa'\³¹ÊßXK°…Á*ÁŠ‘`ŒMpFdÙ4þò|D+ìõùäq€‘R&=O®a±Ë»­.â¸t ÉÙw&Ì!ÚÏ«»®!» 0ažìc“r„’€€áNw/£œ–|Nt,~xË<(q”UcŒÑ$Í4ßëŠ^)ÜGÃ‰Ó ºdQE±ÆÞ¡9.à)–d~qúÉsÉÕþìhùi. Ÿñ»E¦ ¦¨§:u®Ü Hõ‹8Œ¤ës»÷€SyyØ !-ŽœyY„»¶`þÌ©˜ÿ*W“@ùÕJýªAEûíÖÓ¿ÄT¨> Ø›B,<{?!â鹉<æVÌòו€be:†áó62ì/4oóc@b:uU·€U Ã4áì’ËÍ9dC<­@”™ƒvœâÔç±Â4t2]Úæ•¯Wm?Åo«HáMå»Q»Y>¾‚ ý-üa¯ä¼:3C9­!Øb?óŒËR¥î¸l¨‘\ð°Ö88ÑZÕr_Ÿó„­ö:”v/Å‚X¹YÑ#„†dsÞËâ î“pËâø•® ÝT„8»;…ÿÃKÂñ)¥~hG‰H4'™.Åÿ‡pëÿ?‰Â›[ ‰aŪœ37¦ª†Î"Ê)W–ü`{ÈúÏkU‰â.#|Å£³Ó8”æêg´­÷Y~ä«÷þÔ °Aîë/ê°“Ù¤KE¦ÓÂ8‰1gjç7 ¢¥Ô$KtÜ@7úË©Í_æ·ëV³?ô‚„±H‘x¿ý÷JõØ|‚ŸuŒ|êGùÉùHdñË*²íñý>ú¿/w-¦Fy¢•ß²§Â¸.R½Rp#àr>}ŠRо•Ðp÷°£0à©ëJ[ëÇŽ²Ø¸öyšñ`öòÛllÂ=l’X©z¼¤Gi˜íXûNœß%ùxÇWSªúŠpÄú~ 4gûòƪÃÀ<)ç`­^¶¢7î$˜ì}XNŽb ÂñI|bA«I$#áÇ86·.Ž<YVaWÎ"òtFw³öN6­Lg ÖU‰uÁÞ•jPÛ¬P v©N)uá&cÎ8T`0Wh‰c–û ,!fÄvÆb¦u"ã¤È‚ÏdR#XoŸàˆg¹qäR48!4Õé/‚ôÐð<––UÎ<Ä0˜ vêã¡rfª¤Q²?©3‚AŸQvSÁ‚Ãm¯èatãðõ*Æ>héwÅÅêê¬9ò*±ÖpÓÂ×2Õ ã"×)Ÿ<‰â g¸!o˜ìºüJºÊæÍòÔ„`2i7#]±áâ‹'‡>’€€â m:fS"öº²@ëv^KT ªéNÅó‚æÝ£‰³¶©öm0ÎÖ¿Öb·3&Vˆhj, cÎædûØä÷Î.äöˆÒ8?å÷L·ßÍþåEÄ-äž«¾²Q´‘©ª¼”‘lëQõJò{0ùÑk£“«7\²Ž ÁqMmmÓ!ÈMÏ…ÜDóY8¬Ê–BñãbÇš Ýô]‹c¾@3ÇÁá¸þ¨{w_pÌŒµ¾àÝ:Á¹ïcþŽy’3(2ÌÐ AZgøÙÁ§Á¹§ÑŽkÛVüµûŒ‚ßã#À–É YVB]faö3ã/O«úþeéDƨ$õÛHÂhÊÓ £cuF>ùÀ!¯Q€+ሞ]ÅœZtbTŒï8èKäð>‹J,[&p2qIáþñ b¸7 ûr¬„æÆ²S.B ÿû¹TzÄ5d¬v{ã@›”Z\‹²¼Ü»/[^ìôÕ~[€¦)<Ô®m¾XãF†/€LÕêj‘9ø`\°c[*¬4a’;è]³¤Uµ·õ2ÒcâœóÍa¥ƒ$Ò¥ êØ…d’]­<ú›”õTh§¢ŽAù¥·ƒªÈ—F{`=Þì1±¯oÜ)ÜÊP–=…âˆVиW¬dÔÃXM¹Æ`ª?œíŠX¤0T„ä¬0ÈÙÁ÷ ¡éÊDÅø?sþsI_›µÜ: ”¯j7°²Þ¯Ú€„dÏÛÉjÜBC{¼T– 3ù[µ+n\nvŠM„^Y,G°Gª/ç=èZŪó´U ņ¤F¤ ޤ¦©IÍÔk`Œ¹aºîÆ+ìÏÝšÂ"I[rbrÁ£Öð°ZÙÍuq÷sÍè]”7åT’Zˆäo,牓Ñ6ÈÙ«Üšs\¦³ôRŸ¥(X£ í`yC^µ\5äDdG[ó·÷à ‘Ôª_˜Šùz3‰%ÿ•¼Ù‰]ŽWî`Û0®è¨YÔÕw‰Ö ÖzÂ4@Ä[?W´¤½pikþ§Xœó,Ö“z+¥’€€êÝ&öX1ØtÖûñ¯0D]­¾sþ—Öµ¢³Ì೺ê¾ßI¸OÕ¬ÔŸ€Õ·Aí0·:P9vô®h²Ná¢zã ºM„¦*µü“Þc‹ïÉ]š£<OÀ¯ï1IJ-–žÍ øÛÎû¥º³©#Þ‰¯•p4;®#Ï‘<ßG4(º¸8<õ f(@3ÈtOl á\&™t ·¡:cT½’®![ŽžÞ®§ð(Uùx•SC6Í•‘hC•.}"}˜œê åMAœe¯˜ß N™|…M¨VTaÂ÷è5D³X^|~nGí:7yC§FÓÎ'Žc–­;§ŸÀ]L]cxØ÷÷4 Æ…²üTI€êAÛýYšEê¶GEÁ?“öÅòVoÁóövzÌâLM°èa.ä­¨ž‡Y½¯ññ‰¯Æ{]Þù³l¯XéÔL Ó÷Ømvòrøæ’!¥‡wC ·<Ä£²G0UÕ÷ן©)ÉäŸ?%kÁûÖ>%sx¶»‡âqKç!ë„ùzp.22Ó¹ ¥ê*5§ð÷ø°'q¹Í—ràŽ’ÂŸÎâ\ŸÙëw‘äyÿÌ•½ÌÏèɵš  dxø¹Í¤úû>;b<(Ž=“‘y&5rH²?ã;ÌÓÒ†ÙÒ3$ ýò˜+c–Ú¦¨¢òÿŸóùt–9G‰AXŽÇ)¤µ2þqG,>%Ò€ž¯CSêè³Zø6t—h[p‘3ž"©—´Цa‘¼DÙÓNÏtÅw )açÉ×på¿*-ÂÆÏ&æËuÈƒÞØÐ, \qhs£™‘Çó)©áujÖDöé eÔMç:à)ˆ¡ÚãœsÔ˜Þ½¹Æ°ÇhšôÓÓÜ>?Ä6î…áK0=9ó]¼£$\t~IybÅ’úÊ‚Ÿ.Q˜jòÛþƒ°û–+hgBÀ¶}w¯~4ÕÚ}Ò@ãÕåu‰”  jÖuû*\æŽl-†Å9’€€Á^‹Õ—´gÒ‹t‡E¸§¼m\-ßýok¥j?‡Û!n…®þvžÇ€°r æ>ÀKçOÇ1/—.òqOù‹ÇÿoÖÁæà€S+…ùl[ŒÙm±íYµ¸E‘6!ܵK#|DÎAªßgð\•¤A£ˆo±Á­£‡4jÁ:žBÒ™… êe妢{¸¦´ŸÂôÍ×Ê0±hsÑùÆ–¡ot" ¯Å²C}wë',Ñ·]›Ö›qÄe¤¯ΊQwqAP”´ÍÐ)~ýõ©uo†ÅØ>÷hϸʈD]Ëv9ØG,3‚vsŒ³ÌªØù…›}ÿ5t”ÀûžQ>T±Ú»ÃYAáÁé:è¼ç“öÕÆ§’ÁL¶ž1׌Óÿ  æQ±9wÊÏH¦˜(öôÅmÖ ñ—‡A!ñK”î¤È=#zÕòq–¡˜¢M˲ÞZR¨+ñJ¼­ïÝ'ã6ú5gá^h†îp’™¤œŠ=YM°æ¿ ß%  Rÿ´gÎvðä&É›Ke£n¬%·­Â÷ÂJýVß®KS,’`Ítw…oßt¤e8°ÿBú¯{!ò$ îÁø!qÝÑŠ†^ôHó´e—¼=Þ¨Ù®µW"±#¥X¯½¡t£¿5‰¢H¾ÖùM>ÚÁóÅý˜=x¥Æ<=7ôM8™$§r­28nãfRTvâ; ?÷_¤§WŒ÷Cí«ÎbÁÙ¼Oˆù¡ÄÒLÒ²‡^)c\ËðJÿcÝk~KÕiÇÅZðÉZŽž°ØÞØ “3æFµ¼W5wô¦MÖÝ^šÑË~Ùòo3Û;y{Q3jˆ'ËÇ'ŸŽ:j ¢R’ƒJã>×ç&Ňxã,ò3y!ºqhP—7øðF‹Kº¹5ŸnÃ}Æ3÷¾–Ìn0²×¤y©VÏ)EòöMÈÖ‰1[¸!)xcˆœn°¯ƒ.®Î_œ9°HfóŽw‘"7ÀÎcÃWX_Rvys€¥ÞÙ”òáQÙÈ~x{ªO¾b]ÛêJ|Rb:Í|"¹×©ˆÖr#²Ï*EšóL±å¿²Ñµû‚œ´Ü‰§ àŒÜQDVÁ"z¢HV©(éÊžaÝ踉‹ ò9ñ*Ѝ9dÊ.:Šm$žÁü£ƒ Gü“/S‹<·5ªâ?&ý$sw¾!wæÉSìLE ÷Õ™‘=Æë¥ËŒæç~õ?åíb¿øóÊKrÅþuaY+|ÞÁÄ•ç‚øÇ# BÔlŒhõµT›Z~Ž úBóàù™÷Ê"’ )팑«îku¬~£&Wešf&›Î ­ Bq¹œu_¿ ×X]YŠF"í÷7eOŒ3)¾~+£¸0‚«¡»ÎÈw(K%C{ux[šUSWqò0'ÛõòôRn¾Ñ®5JvÅ´ j‹é‘±ÞøS<ùf“7]©f4ÖUGÞ—éix' Š9Jòm=ÌÿGÜT>C+L‹IE}Ô+‰sÀæŒ!ÿ´HÉV•&)嫉ð÷e³ŒâäÊ^uàëÕ]¢=V”¥ûÉ(èôÈ=-Ï<ò~ÒIåloèæÀéöÅû dùÚêÚ'—URÅœå ýfõxÇÖÈškÓS¼IÇ4¥È±èƒ;+ß}à¢Ø+h —½XÚÃæqIùÄ|y†%ÿwÇrObô£&bò/œ ücŸWˆP2óÄœ‰%žâg]iÐI=t-&@oažý}SÚ .ï¡ÏãhWF0fŒ : CõtÍñ§×ÐþvÉ[d$ϓъž¶í>’€€ãÛP=FY’¥Èª¸"Òá8k¶W…YÌëM=è÷q@!µk™í4ý©%ë·Fë°4ùË ZÞ÷÷×E†hu4ÖûÄËÎh¢ïw)Y;¥Ä.×ÙMF¥oš?‰&ÎcJÕT¿lÞöF‚ì@N– #  êŒ|½1OY7›nxÐeO¹\ôóÑu»ë2[²"PŸ€eÄËÑŸ¤®ûÜ)©”ËÖ"c¨LaJ—‰ ¨!’‘˜àZ¸'|>àåx4¶j€ˆ15H…p½Ä¥OFw© §¥{…eZ—ÙZ†N'áéÑhpö|©Í£{l¥ji g˃³“¼“ÍýÉÙ™šÉQ[À£ÿÌË£’ Q©T Ñ"OùWIáê'çËæªÏÅåÇ}ˆ9 Ìíâñ/ˆÝ ðP²4â/ÏÚÔîÑ×;Ê«ŸÒïd¹l,B°˜9|á(>~Q´àÊÁ»ÿƒž,è@xeœÎ~+pÐHúÆ7£É ¥¨bÀqÀ>ÊO9ñó@’Å:‹!òx©¿p%1¸I6U)ÿ®]:EÐv9ᨒ;ûÏ í¦Ó³YF­~ïeå‰ÉU~ntß‹[àr¬êÖ:kfÞÌ“L40¾)Í&9Vêca–šì;`—{ˆ–BKÕ™ÿâ:ÄÕˆiý{¸t¸‡’¨½á c%â^¡ó›\½ê2•¬.ŠŒn&œ³GpŤ¾æì·Mõ–6„8#4®¯ŸŒ¸ƒÐ‡jxüY¢#Ä+Çùá uw÷Àÿ–1Y×D—˜ô÷qú+lÌ ;ž,*æ„©œÕ7+®–ÃýD³×g®á.qŸ÷¥Ò´H) rtЖdd“ïö”òB²ˆ§•:ÿg>ñ:ö©Ê®¬Œ;ëOUÈprðZoç ÖNiµ’_;hÇé¥ö%UˆÏŽŒ†î´|È özPÀÃ6rb”"ˆ"Å=‹ÜŒäç.‘™ÊËuéòî鮹 7 <%¬åÚýŽvÖ™Z Ë³¶yôŒÔ2±"0±H[\(‘ödEJ.Ó™s9èé7VÿŒ—ø²˜¶Æ ô!Èè;24–`¨žÊ2*Ü„¾î=¶2‚˜ú"Þäf:ä2M玠#e»ZLt~‹øûLù8Ô/ÄNïe+© ú\oÅíy€­N ÊÖ÷æáâÊ^˜^¨Ð¬lF9 Oˆ’€€·Owùy^=ÿþætE"TcÚ|ãÙ~% Aµ°ÖSÇΊškeî4MÚ“"MâÓà Ü,#ÊþÇ•‚ ô75g¬”¶ßaÓh #Les× eFèªc+›ŽÃ#ßJFõRz£Oßâ´6ù5›EÑ~"ˆènýYïƒe…6Ÿ¿c§ò–-m&ˆ·Š j ¡¹ƒó°dYìÕUiAú©’m%LÈ»üîEyÒ(nÕÃÒà®ü9 jŒK­('~a…7—›ábŠŠ,niñŠhÌ’?Ø’IÐjœäN Þà¦Zê&O«ãy¦Êd9˽º|‰ðµ€  Ÿ=4Ë_-§«ë¡v¶¿¦÷"Í›'#$–ƒ1ϪúYû`+ÅÏæÒ »*ĤQþ§1ëåL‰'fšÍîúÙTf}¨í4Xá.YÞ›3¨Î›9û´‘'Jàä&Ë,3poÅÕ/>I£šÜô¨®\8§Ü³ú ,¡Ä!?~´Ö&MüƒU7 ¡· ÍA €ž1!¶D”}åxÇ­°›²<~g®«Ö¤³ß`G­.וè{9š7'RÎmc‹©±ýç+û©Äêa‚êüÛùñf~¤÷ñêt-<*êÆm¯cOýzóR•ù«¨nÐÜ‹—g"q”Bœ>±ñó³Ý cè3™,>Q§'–qXæXÈrb ã¾,€*£•YúW·¤ø‚†­p'#¢j°Öó4§û8OÅy"n¨$a™1àò†ç‚¸]†\¬Qª‘ nº;ÒÂGnk‰ˆßÎ$‰Ë2è¶«Ô é‰à‚”ðÿE8(íöú®¯!ÀU…t*IeÇz²æ¤U{íæÞHM¿“NÆ“­ID^ë2—IW¬PÐòU“÷÷¡êüö—úJ²³¬ùÀ¬ƒ;LO4Ö¯¦X?P×gÁM{¥{Hó9Üª`¢ Œll4ÞùoyøDôýpö¡¢äYBÿB Û Fà i6>µcö>·½±äéÑhÝ ÛmHߟR1|C"[#Þ)Rb¹ÍhíR.&ýo2Ÿk àjF{$’¿@! GíLH$å3a™;âUÌ®“& ÁᛩVJ¸>¾”'ÄÒoé*ˆ.á·¦´…‚]m°®š÷Ÿm|½øÞº×ñœ“w•f’€€íÎt¼Škò:ns¡ÝÞª¿bæwo«Iúíuš¤PF¾T¢I[DƒÕ}G“P”¨È “¤)R=ÂÄÂU‹Â„Xi8vÀytûœ]<ËhÙp¾ƒzSà! u ŽOÜF?@øÓèMžÓ”ÌÈ­YÒspJ–¡Áîã„ð7v³a6ï>,OQtËF0òW~ËÏiªã±bÌQ°»M¦½É”K šk8/w¤€Ø”?•á‹¥¬FŒ&[iŸ{b÷nF¹ÖCêüóa A3+Ö¦éxg¶Zëí©­_ÅÖF]rù“Ä´Îè7k"Ǩ$x¹F3 '‡ñ‚CùïüÅ››FGBº<²¯òl4'Üݼ1ônoãÑólªõU›ÑóûôqÊ5b‘»=\‡YA à–£BkÑ¡ºµSÑ;],xsyh72r6*„·‘o| 8ý ÇþwÙtÇÌC«e+ÿ¦+ 1sžý½e•38мðºLÈ…]é¸" eÑ…&MÎ;â GU#ç¡3eɬÁ…†s”U×÷®µßõ¾Ë`ßloZ} ½šÓÄ^ÛÛ‡p,;b¿V(Ù­ã!±2á¡ìõþo™´5¦›‘J×¥®š  ™er¸n­¨ë Y(’!jPðã{n_=íû­ÄÜJ)¹æ¹˜ÔíäŸu¯éKû ÎJ|î³GV­aº Çzð­,-®}ÜñDS™^`ù¾K þ.˸vû+ÇàS Âìcß|…½xA« e•"ÌuË´D¥u’!bÖ7ž ”XÆØãž»\”z?$pfYópLªTñcÝÜñã¶gKÏE MÚÊy^úÔ¨hF¶ŽLg=_•ò sò9ÓbÓÒsö(ž¢-úˆSã6ö{ éT<ÄùÀ•lRPË(”îã¥öÂèçLWs™rCÛÂ"–n=ÏË™¦•ÓY¨F#5¼C¼6¹´8Q:ýñ‹ÖýqP W`8€]…ÍåS/™ [ñ«`ÊIY‰I_×c¤ö‡½wýÚ®l'©„ùÇðñp훹ä$7¾ +ö58æ/?S:L˜ôG!£.ü ÑuȤ@ðW›®"+ƒ‡_±ïDÏN©ð är`Ceü• ¬š‚Xs ’€€õ÷ÊY!69Bëxò&*0Öõkôá“h½ñ#hp"Ì]Ð+lå™<–üH[M V'×--[Ó¸}øÏ³0m²óa Ž¡ÛÍ¿ØÅ†¾úÅÄ‘Î`DÅ9p÷|¬ôô›îrH½ÏÕp“êWω6PçP®’j¡ë69bInJÞq‘#¤W0ív ÆÅÎ IQ–/cŦEÅiV»7ÍGÂ$ÝÈ8y£ÍkC’,o6×™/ûÈŠIí»´ŽºzE^ Ƥ(Gi;võž~NFy íÄGáЮaTvÈXÅg` žÌ'Ä_ o)°t¹˜Q ݘãø0¹3@4ªÉ7µê#M%`v{h®¥»ñøÝT•-ø×V%¼ŠF™«ìÎÑ…Tv»½pˆ( ¢­Yµñ~¸C­ñtë;ŸÆ ¡w¥žý³×6G­Ý«x$›í|õìöc†gÐ ×¹ÁÜ/{eÂZG‡Aó1£ 66;ú­ä÷žÄZ·cð¦ªÇW”¿–÷f%Ù~BÝ–¥#˜ð©(šÃÛÆV9XaŽÀ© õÂÊuj•4¦:ópóØ%©<‡ýçÚH…}~ÊÀ’â¢G¥è|´¯É•0Erx#|å×2ºI0IÖÒðqk—*w•Ùü€F5Ì²ŠˆyÊ-žldJ¿_WbYÿÃ…»:J¼òû§8Ìêo‰*†´_qhúâ\wŠ(@»¡®Ëdz³ˆº¦”W4I¬ì^v ÷A^Nº¨ÄcBûUª‹ˆè’¤l.d·çK-ª¯ã3ÀiÉšÊF(³ßwIÁV“˜fdÙÂd{@em{A%.a àxö1ôOþº-! çôEÒ¦_[fÿ™;3!+ep›”ð3ÀoôSp÷¤C â™wu·©ùßžNî@j|xÞ‹2¼„aHí—›Çy~Úϱ~zƒ¾×•ïô+pÑnéí¨ÐÓé—‘ðRæÑ×øJðá6Q+Ïr¥º§9Ìù°ûT±0¶ÄY†wÂ@ѤöhCahº©h‰é¢"9‘€l‚T0˜Û,ã+#¾;4ê÷Nb·‘¬ƒ ~ó÷–ÕÛµ6RCxžè‹„¿Fæ'¾ý+ƒÓ¬:ÑO33[˜ÆFô¯°;V‚k“Œ`¸ÈYüå¼þLI·Ÿ½IcäAÜY{·ÿî37Õ’€€¾Ø(‡•Á i6@¯Xb~ðì4Îýê‹a¸þ é Ú=ÆìmA]˜.±ÛrJ½(w€Jg|w4.ðöÉD2~ù4G3‰uk”‹'×ÿ™N~­};×SxÃà ÈÑÐØy^¢&}lLÝ KôŽÈ¹À*—ÁÍÓD™jÏ‹c Ï–ž÷*ˆtÐ*ø=ôê·1 $ž  ÐÂ&NÎ0Ã/Y˜ÌõðÙÙ~=“2Ü$¦Çf-»Ó±g¨|&%µ HTaczËÿ3\É©k¼•Ó‚XˆcÎFH7{‰Í~À¦ IvªÞÙÀþ;P׸úš¦ÿk‡ Ÿâ>l½;$‚JíÈóWu?!Àaƒ9 SÏEÇóGô2ºèŽaÕꌠŒ ÏF¸o|)û0Ô*§xâžäëgÎKuØø·a Ŧ=„.´‚ä~Ä¥™à߈`&jÙŠ‘àRù,´…‡,_¤Gõ©Ç&‰ý²yTÍ\}0bö뾴Ͷ¢!¿ª=àV^T ™Yæm1)²²¿Û¬€gezxxj¤ú_k½OŒ¬¨-ôÿ•*GQnlÊíIÿ]n¬ÔZ[â’•”àAÌmfþCõmT Bñêòº-îõ±Ìn£7‰¢ 7ú|3½Ãcé)E— •Ý4ü„ÕþIˆº%Y/(.:b(+‰þížÝ©îJó"ªþïyÐF>û¤`Ñ9€mã½¢OÅLgŠ%$Ë[I-¬ˆ¢ªú‡ÐX>ÓscÕ˜wšÒHF0¿iµÆb@à\ß¿]ø°ùB4Í€ƒá“yïµõ©4ÖOmä»Y(Už„xwŒo’ó±C½2&Õºqg¤ˆÄO^w#Lùiìç͘'IºDÁ+Rc½ûWÚÉž}@9`¿]\hæ§C5}]NFy ‡r ðGè¶pl/@U²Ã¯bÄ v/ù¢¹¸lÞ0ЈwÓßdÁ!°¯‰Àku$ª…ß×£˜6 þ„Mä (26Ÿ÷âp¦Fó¾ˆölÇ:‹ CÀæ}û0ºGÒðN¨cdª”;ÖeÅ«üd’œ·ÈQ¸=ÉD ñ´JlÆçÄÛüT‘Ó+¢]|Äòh¯¼kðN6 °›Aæ†×z(€7#V#ÎWfö ‡2_öù2ÌH&i'nâ $Z“{yÝz.JIîÖ’€€Áq:˜Ã^T.Vƒ-.‘ê¹>Œê‹;òw'ÞKÉ“ç£ÝÍT„Z€éB(çtTÄ´é—ù÷Ba'¾ƒü>óÐ]6!Ö7È!mûÊÚ—¬:”Jr ˜Ã}ewZD^à·‹^ˈÖ8#¤ï,O| *_c€™ßsE4óïp3‰ß|J»gðÄ”}e‹Ð—ŒúžwÎðMl'÷öÇÑÄPí©8ªï>bg]ñ/‡}·¸R¾Ú+EánÕMƒ±ØÜx¸ÁÒußoaˈr_yÛ4É ‡ ’V/§Ôî@G¥u;8õè#Qû Þ«] ?VJœkª¶u$™PRKÿ}OëjêûqŽ‘g„RQDW´í=Ø”I\Áqamh½7k±ÀØ—wÇÍþ‘µÒyÌWûúXÜuÝ©_•é¦+`s“vön¯˜?cyñÔÆ;@ùŒ³qÄ¿¤ö…mÙ¥2 ïºfKLjž{dŠÊãÎÏUÜ(›Â4’ÙÙ‘ùÀ‚Ãh\ÉfBÖ_•ù5I'…»S¸ÁFZ™· Ò±¼[`êºüÑli¾6ã»v¶©O^ 6ŽË€êKR<š¿•ýR-âHÊŠx[T ºFº$ ÓÖ$)ˆåÖ¹—¬çQ:6“Q;ÇÉ!ëÚYÝèçÐûiŽô(À†äw¹èðÈ/{Ä›¦aP¹» ŸÖy™d½“tÆZHóÆb¸Q—ñt)ï¢#¢úò¿“ ý–ù£,xšE®ÛÀ¦MCpÄ«l–a$:³Ñ÷pg4n·[ßIOVÔK>º@{v1¯avº=NL4 :ÿKLð°£æ.bÕYÁƒ®ó)òFǵàD˜W׿¶kÙÛËxßÛuÚÁ=RŒ"˜‡šÆ 8-ÏÚ“‰#³ï)ö2ئ4^¡w²5ºl XnΞjäJœìɯamrŽôý—Iv÷*>;ä6ŒÕ9^–nˆœu(k9¹+\ˆ‹#ñ7Üæšq0rCšÝìáž¡/šë€ŽLø Ì]wÖ2©¦8KGÐ9uš±®…Ò ÅJ dl0±fsg.¾è}"ßëU¢4¹R,@Ö¯zD(É£#&‡’€€º)¦MàìÖ@ˆç]®¤/ }3±”[Z&ÎBdâÇô½Ê,5€ÕC,SÓÇ*èçû?ƒ™.óT ÈÜö‰Ÿ‡]lg>Öíeÿ8RFdOƒA ã&Îå8xµ]›v®A™3 —rܨØV…’–lãÖBÎ"¯&KŸ{1ùLè2ý»Õêl«§G½`<ÖçeÎÈüÀ’ƒ„¾Bʰ@Äù{£¸‘E?÷y­’Ô_³Ü¤ý¿®g±ÏIeK2í‡:ƒ/~l†%4Ÿ×gñ|VŠßj{$sãCºYÅÉ%˜L)b\Ð ®6›OŽGè…Ï[nȯÝ%·bþó›>¨jG vÔùHäC?3–|ïŠÃ4Le]ÿõë}4:ÛÄÃn²Ò †ˆ©Ð<&-È«;§ÑßSU|¢TíoȇWQû„âZ¶jxC[Û æåãÛý~Ãjy»a†ì¨!'ñƒ]¢‡<µèe©cµ†›lgc˜MEaVטôn£ ta²¯ÅîìÇYÄS`qž¿ÐAd×jC³ kÐ^Ã[ˆ@Ó!σêÍ®­zZçøš oäsH£í®‚ÝA± n ’ºDí#ÄiÀ̳³¬qÊKÁ!!#i„82‰ì@€£+™¾‡q;¢•}ÅFïÔm¡-ûØO5†/ªIó ö¦…†‹ ]„Ñ¥V8 KBÖµh"úÓXvFrê@>&c2Ô“k0Z²3#à±UšÍäÐicr #ãè£@3ËKöP„öÏ a%‰„Éuº(п9Ø:v<õêk,}ÌwJQéfÄ{ô¯é—eìg¨ÆXú(å´ãÄÆ}É’AR™±€ì\ƒÚõÄ®ÔbÊq}̲Ÿe´¼’ÉñĆ¢#Æ™›D‚0“ô;§˜Ýâ€Ø=#m‘üX´f½»MX³ÿk0Êø®r#p bÎJ[9íàãÓYèÆ¿WSþ';/ªíć|Å6äåkÚr l ŸÔƒDJ"‚Ó_;é3éVHÇöR«&‡Ç}>¥Xç$Š„ˆ„QÚ®Žö’°S6íp1/¾³¾÷”íò+>”’¥9m¾‘¡$1› ´C!æ랟…‰È/%%E<®´dhì!ÇÕ7Û)3‹¾0Ø8Gˆ±ž.‹ë¤H7ot’v ”F•ÛDB#ÆfD’€€¿ÙÅ­VçvÓ÷Jê¤AwR5b´p8öež§2ýÅ9é µo›Úmâf¬|ÃÙ±Âø-¦)jH§\—à˜éJWÒ:ÎΛÃùõðÐÃl9í÷æ)ñcGºIhf¤ •^ \fƒ×~£½ÚK ×núâR{vvóSSö4Xº[9Oûåj|ÒæAé„l0OÔé-ÉK–.”%>*iiž?BÙ/hTR}Ñê'1n“ß·ŸØ?"­ª'ÛÊìÅmFèdx 4'ËÒ†±·(˜¬ÍôTIk{Dî„á %ŽÈ´p„9?äiC/`Ñ»¤+´"þo¿SïU(–m…acPIŠþ€sF€G¥‘Ä—VdÿßéSwSNIίРͺ±%eÚ288šÂÈ«áƒrO´nqw5#ŸF™´òÉß….Ý€(ýì~0¬:üMf®ýȺVyÈ×-'Kd,’,j!›hÊÆ9.wZ0~ó<Úö–nÀ¢wÊãšž—•>Öi1lX™ÉµIÕãæÈÂ; e7«qýù·`ñVÇWôÅ­ŸôlÞÞ ´Kln"RˆlXG›”%FAj ÜN÷¬€O ‘¤I…ß'o6hO ¤pó} –äÕuë±.pŸY$#‹R¦‰êwµ‘’¾d±“㨅B[Ù;3f¡ÒAXeP㓥؞ðâkšÛ«ùC¹w}n¹?o·³A0Å]ÜCOè{­+ò[šª1bÀr7à}·'˜6àͧ—?Pï‚€{ÕuïÎñOÏPVùþáÈAÔy{Ò ñá÷a§¶A„f»…oÑx%{w $’1¤ÀQsëíëæwÁ_¼ÀàéØS‰]~ÓXôñ°¿ŒyPäcÄ𕦮Eƒ¾¼™Õ­í&Tů½œ+-£y`×@á›è¾›>3}ü£$æÖ)’~‰…Þ°¬‚Åjµ3'ÅÞƒ·ÎN!÷gáNEçèSŽä"ؼ§ @l2”׿1îKY,·wãD$KëœQÒ›–µRÊJ·F=z8îHË^®Llž³U49ëtï>¡/œˆ#ø†dÊ¢G·ê±ny®@ ÓK¬PÍŒŸ¿ŠB?j $+ƒzÞ€ s!nU]o¯œâ™Á³½œ. ’€€ë0½¤ Íâ"ób—¬ 5 ÈÉ/hÔìÈàNŒÞOT¶Î(ô³ƒ£,*"}>ÕãE‹íI¯v¹Fž²©‹%ÎV?dMú  ššWÓ…¤S¤‹Ùšl]„\¢Î‹•í©Á-±‡œ3øÎŽQ^Wkš{¤È¿î_œ™aÖ?óä$m|ŠéÒ¤2?ÒQ‡òZ„¹ƒ“¡ûa½<Ãpoç4<15ÊÈÿ‘Y¬­ÛDbÞesl¡*Ž ðIBÂAð}¡TF<Ž:7n"ô‹€w´]¬%!‡C.ƒ•ù`—Ôà´û%ª‹:Z³þdé– ŠM.1òÀü\1ïXú¿6¹ƒhÈ„M› Ù{Èdž™õÕ×P+ˆÚa†R àívLèi A[äóy‹?ï7c±ï…tÛÛ‚“gShÿÉÉé/1g.©Câ&!ùL²¶b*¨èDL N‚ÞþÍŸG¨ JóÔÿà„-ë´¹HêÞù$žªI^ÞûG ®½LýO«  –Ë~äì‘J„;Mɧ¨ûßß«Þâ”ÁìW­,?w“ƒ ço}¤°Aî~^Ï 1b‹v… )ÍăôbEEòˆzD#.Y}àF>+}ö„fNz”#Àü1>G ByʨŠãõ *kZçÉL€Zv&~¥;£z•ù6]·zõEåoäŽy5û:qãÒe-ðAMÅ:ÝCÜÙê襡=M7Ë)Бš­W®“ƒ^Áá´s3 ¹Ãð77L#~jcLg`öV!öm  ƒÔOýq<Ì©±áü·ÑñK\Ï£õ4ITtj$ãÌ2×?\iþž"ñ¯å2šÓŽçx6[‘|öðÈü—XèWYòiä7¾öÔÍ[€*³˜r«œò«<8¾¬Í³zˆYd¨+e»—+@WëâÇC¨½Þîä^aÚ´ã…Þh͹T˜.F Œª¬(ÍÖòáO¥ðø!&ÜIz?¾\8¡Ùã^ýJAÙú"Áp¢:W &Ï¿^§Kß©ËÛ‡©1 Úߤ"×]ðçFtê0©v:åBsÑøßÚ˜U± ÿÉC±|sŽ„@KéêPGL¤ìÊ;Òg[¾_"Mú¹uzùÕž°I_¯èj¾Nüž¬MЃðp¿óа&¼Y”MêZ—’€€Ô;ÓvéÊqš(™‚Zo#¡)ÝÄ ™²*yòïŽýȃؒqÚ“¤ÍC/= 3©,Wç§Û\`–á”æûÙ®AÖŒÄ9G ®#ŠépƒB ;oî_´ÑOuÓø¦Ç]^$Yb€"º¿D<Ÿ϶Fƒ«s…ÓÊÏÿ[¡ÎÂs°U$•SÂ_MQK½î:ÏbØù½r'Îi5ââÈìyÄ6á­ìlG]ïqˆÌ1çz%G*°1^9{’qŸIöϧÅ+“€TË Ûºû >w€[MqK§C°¿Jœ/ýnt޹*Ø-K gb_YÛ`ÅïãäoÅ^5Ø(vçKtn‚ˆd%O.àß?u¢ÌÞ”(0ƒæ¾¦gè¢w‰ ðKÒn%RÅËAñ†‹°é"Xw¢0áe÷!¼OÉ⋳ð"j_ëý•¢=•³CŒìHm@/‹”–ÑÄjª¡%ÀÂà ÷-h~^ðñuÒê5Å¡ü•¥¹¬°{2{¡á»dE”F÷ës±K©ºÊ˜œ E_ÅFÔ±xU°kîûH5Èhò¦j£Ã¢/ jÜä9-§¦!yŠèˆ¸õ#n#ŠbÜûóNVh(_ùÛ|> ùœÓ·˜–v5ÒXÎ*¢çË:CÞ’ŠlN¹öfÿ¿QýWuîÌ)(Æ5LÛ¿g eŠÖÌ:j¸¿€€ùb¥»ÖJÇÀNã¸R$…¬„õ³[Çç:é)q%²}*Û' _Å2S££¼vÍì&ÛÚ„qt:ÛƒKpoÏ=($ò…g•ºõËÒ•t5ÖUq9€,92-Wz¼®Ð†Sq—‚ÌØäPÙÞ68<@È 681òoOKéË곇G]J³›6ÅXˆŽŸz8CÐPµ0 T‹‚b…cD-Eìaè”N2_w[åFáÚèðív’¸M;<ð™Ô5Ô‡ÔE‘ðuF?¹èhF¬Q‚ ’á½é¯ú›ºƒTš“áU¢5k•µÐ;î\"Ð ‰ q—Òô¹CæU¾M‡®xf»¸•ñ„7 .ÿ‚ÚîuRK§¬†¨óÇ l9Dç–›WUµŸŸ&ª÷¢6úÙ¨Æ|­qö¢î¦?uP\é ŽKøá—jpXÓÚUaý«´ÊßGJÛzýçŽ%fxÏÍÙ[ ¬…ŽÇOn]ä2´x‹óbz7>œ‡ûðIu’ ¡Ö­Î¯†e,i,ô#Ô„eeªƒ¹·.‡ó 2̱ߌëðwLy9G¼^r÷6K£ph¢šÕ[ŒΉ5 ÐÏZlÕÉBUöo-jùz ÕC ‡UÉÃ}¨od.’|@û~If%›zoZ°ÁaE“„lÚ˜ Ô¡Û‚>ýô¼`ñ´—ÏpúÌAs5éˆRk\qn$ eí´èÞuÛØ ù¤ÍÌ×Çâ$í<³SaÑP Í©Š”Y–<$,æ7´…öL"„»÷úî7Â?>~˜/ è_»NPÄß]_hZ{±FHuöÿ¹ÇÞüwt>¿²³Aá¹FSwi,tÓ)ž{kb(ê>n7a˜ër×OÒ°x$oõÐþ} àŒÔ.Îb°apýóÓPx!Ûù7»žÁU‘‘ç\tŸªwXìÌ[BЪUœ«&Oe¸LáÕEÒAÝÁuH 6®¹Üy:ø»îL’.\+Åñ_ (»×èñ|:ŠŒ•%J‚Ίžûg2N÷Ï¥øAIGV%Ô0s? ¶+Kö_—'ž°ê¯™¥H 6:o€}˜ÊñÉ 3¼À @µÂ8Ùª7&àçx¡ïÌj^‘,µª„¡×´U:˜3U²@B¤r|¶GMd¼É\WÓŒëI¦õcŠÅèœà‡lÛå‰utm^ê¯v‹sàŠj¸,ÓÙu«!ÂüŒ7#ƒ5ù’€€È8vGº—<\‡˜1F¿í"û ªì Êêýë~vç;ª âxFtŸÁ[ºU8úJ!ôýœömÌ[ÂÈn«Ó¤oR§)òœÊì:9jc»õð –ïóTkpÒg«ã±O N¾Ùe"ù¹Tßæ^uL²}cUÝG¢sü,U˜OšZYPŒ$¬f;Ô´;m'ë»E uɇÉt#nº©e –Ž©ÜÀŽD(Ò— ßð ¹×¬G;©=âã”ñVõ+íg",Í…þT0G_™âÔhV¿qö‰—¸ ž£èø*,Vh0ÝÒ×û“‡”ÌF¨N»ÇºðÀz-ò™#!WCñ×¥<û¯"”Ë;y!Æ]ü^pJ&Ü&YIaEÏcT¶R%ÃwWµ†×q%2c”ºâx§noE+Œƒú}¢!÷ÁÃ"3 œ)ŽLϰ%)„­\œ}åŒw´¹2-]Ãq ‡ÿwíºÂÙ·}1fuo±0e¯9†éuDÔà;¾­¤)ªhõ$ô݇J%ßÁ²öQº®AÏ~ Lâþoðk<)ï½":oY íÑÝ)X––J€’­(ÂKàäòîizß$,T€s\UDUL·>¢Ú ìM@½½aäsÎÿ˜DI!€À„“q¢sçQº¬êÝ!ÿŸ’È^éñð`fSnÛ¿Í>9Ù>1ʨ'œÆwâã0ë‡ówrh½A¾M®}Ô8Õ=6»Î™ãa)î‡n_ÚZº©"V±áç«}j¤$iš« .øË.zž¼âfNºèP UÎS1q¯ÄÂRm q0ùzžö™s)_“=í8‡ÜúÂÿ}CÂUÓÛcªQá7v÷€ˆãŸ@ç•ÐþÑaÜËeÞLæ…?kŠ_¥ ê¡/’¦‘z˜Uôáå¸0¹DþþÓÁ5aT³ƒ<ÄäÑ·€0‰Ø ‹_\¯JO?7Ï?š9Èò U%¿ú%`AëË,¢³î.elÍë¶êL)”A*^¤|kŸeí_·Á+þ§Ò±!]ú04¢;SÍÖ…ùf–D4UØæãÌšÞë‘Eö››»È/´â`¯Xþåë¸fÛwÿê[ÞõÉüe©´ï-=týÖÅè'þ=q+«ÎBOéÜ ÙÝÓ‰4ÿ¸…×'ÀÐ,sÿ—{ŹsAH‚ƒ¸ $’€€Ò™³§bùàâK!ç2·i3¸]Í&UmŽÎXD캈¼+¤Å±àLøáËñxT8…Å“MØS˾VlnÚúÍ&Û8æû**§¹Ÿ®›ÒZYrF1„ܽ6Nªq“?óeW Öqtoú›_>Ná?©†nM®T§ûÑ `D!°fc^ÜlV‰g^‚6Æ{Ævý½K·ì•Û>Œ}*Ø«QÎËÃÒÄ÷MQNfŠß!v)ËÕŶ$­Þ¯dBJ±ªÐÒ =+È- š:¶zâjQ&JÃ'õðòúÞ#Ð^¨ZÅX©ý>>iEµ|N̺ºÛo…Œ®áû&mT㢉Vãz‚ ÁwúUVù…SäÅDj›?÷êig*¿çްj!Ç2=jÏ!ÿ±ÂˆUYGGþ =yèrk|ÝV´õ-`©+ŸtÜ2i5a ïó#£ÀÅ÷jõU„„9v$Ú-7M†ÙµM9C-N £| ãP;Å«ôâYl?ì»cOhŠ'k4ÉßO¾ŠŸ‡HÞâÖ2‰M¹¢R­jL5t:é7LËhÕ(¾$]‘xbî½­…lêù[^A{B9²ÑÎyW™ír±ß§âNŽ&1œ¯l¾:f›üä.|ˆcÏN}ŸîEž–:kþë"çÁþcÕcr÷©@›Œ0 /EÜR&ÃcæyÀ„ºƒ\¢çÖ’‰ã¡ÙŽŒôë¨ÿå…æ–_6—¤ˆã]Ì1ÏQ´œáy%°AŒy$XS¤97(È}¡¶WO\Ã$Ü™¬~ÑÇ7ëõ—ͪüK#IHŒ²W a÷!ÓZO$œ2änE"»H…ÕèO¸³ÇºÇUöçê"ÅúbüpQ@4{A[SŠƒ1VѪº-$#WxøîÖƒŒ&À6ÇA$ŽÏFë¸Å×<³ÆvB/¼ßq1y†l2›F3F‘@Ž.ÙPl¶à 5¼[\#:…€õ(©¥åó+ J­Ì籎£¬í[Ø÷Y&M~¯«X4Ð… óòtwÛ¦¬ˆ½6ŒûZífH1ÿ §ø4œûëñ-¯4†à˜xÁ°ø‘òÓM-HUbžOXzmK:•TêT’€€ÆjÒæìóÙ*œÀì* ôkÓý“ã*Üš“…š~êÉW ÙzBÈ!HÿÖ™Cßîq7‹^þ‚®Þ¹¤Ž¶ŽÛÈõ;­’ÿuOÂÜjW„`SÚ¸Y¼cd#…PÙ}Ö(‰ŠÜ28Z‹ÁÛÉöHW1WG$PQЈßA›Õ¨ú¾®²ø­eò¥¢âiý‘¿Îª¸H@íXhÌÞ+ÕÃ#¯Çè£?CØ@sVò>N·'1" ?"¿>:8áÕ~®™TuGeÉNŽñd:“ÎjtÊ/‹“$¸±?jíÞÊþå¬!“‚ã‚mǯ.°½L#ëfúêåMÿ/ÙöL»=`˳‘ìK%–Ñ…ˆŽØ£±ß,¢ß!®O+>t>H@=,¯Ht­’Ã"}õ"v쟉6‘nšúSÖÏʇ×CÝc„£e$0¦Îö e ÉuöI[œãùŸh~m&þÏGJGX Žñk{8ˆ¯L*Þ¨©ð§äÛæ\%/°4¥SýWd˜pvIJ״R9¯ ÿIŠðô“¬ ‡fcí³Y£ âO|JT)$^r[R¦ž •ÑB†¬¡¼Ûð"/Ÿ61î0à®"?ä#ô‰gX3xÿ¹®”ÛTFQy+’BŒOF8+m‡…È…ýLÀÌ•éÓŸ`׳}¢)ü¦pðÛ ã¥Í…•¾®sÒßÚ™¢%öG. ìgµDOuÙjÒŠÄÒÆ–bÿò3a¿ ï‡6åì|À.A¨RNëx—yC<:<Z=.i´üv›«Þ|9…2˜‰µ³x]Ä7e*zqVÖã–m e™Ëúi~x`õ©‰)ZlwÍ-‹`Mº×/Üá€ÖJð§ŠWÒƒÓ~6}­:"A ÌÀÑðæj7‚! fpE> Yx£¿q>#޹\øŒÊ’€€¦áÓLÖ%š¾@^üÜ‘ã—)þÒѧ$ù^FJÏEEP™ÁÓÑ¿PÈ4UÆx+Ǧ€HI¢QÏkð£YD¡SÔ{€ƒQ÷IEÖ.AACås¶ÔÈbí0IÇ$D7ÿ3Š.ùžZý“ü$áDΤ ‰3šœÎúTW­pÕÁ~§ˆ9ÄìáT¡1:Âf>žÐÉÀ “â°$ËuÓ­bò‘tm1ý @2ñŸùQW2žÏ°Ó¬3K-ÛãÔØ-à}ÕQ䲸f+žsBÛŸªáÓÛÏŠÚÜn=Hk(x‹EœOBú–{L/Ÿ]8¡‚uK‘göF'X=‚wU•¬ ÖHàço9%,Ó­A¢)÷c¨= HWÍÀcØÌÏIðÓðZ“%ÄyFÿc5i>ʾõ9höÓs{€¯oþy­ôî¡åÐÈK³‘ oî&f¼"ÔC”Ú5ê¸]r¬Þ.QwdÜ©)‰wÚÏ +,öI f¼yµÀÉ¥%.WÄâ¦ÔˆvǽÕ" $*˜Hâ« k庵ýÖ×£w½*¡ÛÞ]*T¨ FìOÌ5>DJ¤Š‚0GrË ÷-uû9(pƒ‡…Þ-,ñU†(Ìi6 °°³¶š£8Ú;}ï“Óº¿°Õçqê˜6˜» Ä u)*õ¶G¤@w‡0¾{Ã7î“%Û²z=eÎÕöKlYØ”ï'ÂpÈãtiôãQ~6I‰®¬WÍܼ÷ÕLÇÐE=ƒÐálÜ ùWÝâÉb8òU€¯+Ñн“£ÕY¥k0Ì7Ñ.É?-}åïÏ¢œ½5fŸS…­g>IÄÞ¬GØ9Ö»§rK€_ ˜/Qè<êzN\ÐÅ­Ð6L5ÚÝÎŒªìÚö¼?¾ÔM·+äß Œ ,¼'yÍ­%Õ ýíéY-Î3«è3¾â®§~ýøÞIvDÜš\gƪñóŠë£©O¤ç éðøm¬Mô0¥`ˆîWz?ßi ~ÛXû§fˆ‚JÁ¯O®Çy©§ŠháöÜt>aîvz RÀ”Do:SN¤‚­NØÔ"Ç4‘cÕ?÷ÇÛÜâ~âSìÃi‡˜­7ž@Õf±å~?rŒ/Ý äæêÆ Ö …jj4#¿pu…c:޼‘¯ö.Ö–  3Ô8ë\²˜˜ÄHWWH^¨]ÐÓw¬@Ð UAµ)ôE{{ Ç'k1±¨ÈÍÀuø»²g;F 7ÉüPúÔpL >09J’]^9U«¡dO à¸†oÙNù>”p yèÿÒÊ4ž$¯õ„˜¯Qó0MXH‚%¶«jɶyŒYT`»:þ.‘e”f®,pF¶]J W@,‰ *BÞ«/3¸X=.ê ÒÖÂÕ¬@ö·7ú#æÒ"Ø'©q­ ?¥8ì©¶)ˆgU%[,Ø´,ä[>ù¸kr,ËSš'â2Å¢G:@­¨‰IÕ«âüLÿ¾†2¨Ñ‹ÏõEáåêÖƒNìW°ÁªXŸf4âuÕÅ(D*tYû®—Äj+úA#Wb3ÅC2¹‰v!ÂCÊ ´¦’†Jü¬üÄäxþôý‘¬L"çºÙÃeð‹ì#ôÎÛ¨=Ppìfû7ø¼®a| ^yÅõò:Ú ä/Š—Ý¦CÏ#¼W¢nÍÎ '-±iz‹²X[í·bqóÎú jÈ õær•¥eƒñ&®øSþOú•Ã`P³›™vT:$…Ñû2\M$B„mâéSräšdP¬m“wÛ õÁ© Õ>ú‚am«q6ua*xÖq|W_*ø ŒµØÁ›…ëµð˜LlÁ ±z5ýŒ%E‰ï¾ªòÈ´~JŽÒ†_Ýè®þ6H%Yð¬çß`•QŽhC4êWP7ä?E6³”¢›dþý÷±À¨¸Â™âiþ£þDê`M:Ò8“ºVNŸ.¹G„Å瘣1·°µÇÙ¹†QŽß¸“]ì%gPIŒþ7·N‚ü°–’€€×IüëÊöMcD r¹gÔù1ƒÓ‡&ºŽÜ01æû÷§ÂÑëf"Å¡ DDðÏèñMØ`²%äâH@ÜêÜX#QÄÇQׂ˜’±¸[©%L<*Ai1Žéºî)Ü'~ñªÜg@ ‹¤­€ÇÊa¯ˆGÏ_¦õÐÒÇ,ÙÂÉ·äÉý¸Š‰£^iö&F£ ÌtˆZ0¡3ÓƒÔ@f‰sÞà¤E8묕.‘2ÿÀ×Ánia‹ ñ¾»zŽ×â²ò2¿À]ÚæmFÙ ¦Â‰kžn'¼Ž‡dYÝêÿVn«å°ö:1µ» ®êãGÒ]>—¼jSf²Ö·ªƒ;Ås`µi}CW;z JÿP&a~<”ÝîsX¸]QdW8r ´ •{áôÕýãË»Lë]õ¯ ‰Ý ¼ì®>@‹ ÈU(¨¿Â¸ ÿýGÛA0›€ÆëÙ^ñ½Œ”ÞÊ—Ÿ„¨ŒF‘|ï/ÖŒ”´Åô·gPŸ,½ÅÁŒ J+^þó fž¿nü¬ò o<šå1ý¦d÷Š&K Ÿ‚ôò‡MédìRóµ)¥`ÉÙr¨ñššQ2€Ý[(½|§üþG– ñÐZ)õª±òÉãÇßRþçSÒ&¶(êëÚ×.lD³xS«0²ourüMy”»Ä™MÈܱ>Ùðygm§bþ0aÿ†îOÌ?rlS²î˜6³9-q¿GRk¬„K/Že‰þƒ¾nª·µD<°³U\s4¤Ã•ÚéØôaþÞ҆єÛG$žH‰ú}¶0,ÎËwcp™-±iÆÁK~û>ÕÉñƒÞÎç£ïTÊ·D#t¥&G2[.pÆDò†gñ×°²S° Éß±ÊC°¯y¢»–íJjw¤+QþQü›Î¥5%=ª”Ë oé'¾-,mu€…¾]^»ý~x]ŸÞ‘,€m¬7•òJöèx7ólohpêQ+ô©ì ^IœÊò$ú:%üôˆxRfcfœMm;‚µgÐ"ZI™,‘e*!_ç‡äN–qD3eëzÉ:òó»D* ö$’€€Ð]&£®f-*þd3gRÉG´§i‚l£ÚÁ'C… éÙ<=LÁ>™Ý_íC‚zÝCZÃ#œmïÍiénù©‹oqP6®¹]k’(¥ÜŠu‘vع ÿ]4[žõp”§dlTmÜ੊qCÐ**ósvNÔÞMþÙZBìëoCC3ˆÂ |œÄ)»Ç¬šÆŽ†Ó6u-ÒÅd+Ù©VìÎõú´ÌÒ( 7ÀÀ2ên(#ôYœZÝ*>®›Rw΂¨~‘Pƒ}% $L –Ê z&:­ø!=t–"Eá±úäû/PZïÃïuR#ÁƒmŽºÚ±EÔ.ûH÷À ½ñ™™’Y‡•Ù`±…KÎôAA™~[ÕÅ"Å´x½¡Œúõ ÈðyBœ•%bKœøvï¶—Ÿœt6d°¨…4çKí«,¤½ŒÂÅçm¶ïûÊñ¬»zgá²Iž¥VDgjlÂŽ Ž(­yñ¦ÂøŽ¼ ‘3hÝ6^ê»”£ØIlÏÙÏjÈ–zDüRe7€ù:.„ˆÐ:0fŸXm¬áƒsgWR¯LÅ|ÕÚÔ_$]á¥cÛïÅM^ 4jÇf²9ê F…U€‘†Ê!ÿn‡£Î»3Ík³AK?%#¢‡¾kŒVBþ±U<3÷æòoñ¬µ9aé0£ Àó­EeVÒМÌMG—•Im»1~ø|0)ݵª¸z§7ö)=g/„ ƒfaC» „ÔþE[Ä'¼¼–ìì–\)ãr_‰âEÎÜÈ/ú—.Ïæ¹>‡¥§òëJY™œÀ<{lÐðÔ(°Ö/{CÉüse‹\Þ;æã¯‰UÏg便ò`ïÚBݰžûën1Fg.Ø6e«¿ÔÅ¿?"Æ’¦ã*?H Nj™¤$¹n|[H=E• .êÔlÒuCLK¾Õ38(¢¢¯¬ o`†ÊŽÑ(²Ò¶0Ã?Ã<ÔŠ|"ÉV:ä»Á§%ÍAÖ Ä|‰w+Iœ)ÍQŲ}Äȉw­ ÿ…sÀÄÇÀ¤òvß^-;K*Qѧz6ødÞ0DnR܃èDcs;õ×tÌb,^,ËŠ-7uþ\V2ü•éÉŽóÕ€â‡Ò¾Òa»ê.Rg²ÞyÔ-âO›Ò|>…2þó+â$c+ï!t¦nºî½Zã—Ä*L’€€æ¥½ç¤“¾#8{åT†•ˆVŒ€“³ÛqnÁò¦Ünñó&¦?Ýzצ‹ùe¶Å±Ÿùr]¦¥j0è=T3žŸ¬É=d`¼¤4Õ@•C£ü¿‚4Œ+f‰¬KóÅ܈äZÜÆh&^†EÜ–ƒðd®:?6ð"ì•yBà£Ã‡{`Á$ìUK«8Œ»öHø1g¯q»ÃæSýô'¿íĆ:áC* ~”FýeÕGm·«9ÌZJ•߆˅ÂÊ‘R•4lJrè‚?1zfFÃk|b<íê—ŠˆCºøSÿ¶Dû~d ^ÓE §¼`xÇh3óÏÞ@òg¼¥(€ ÄE &¹Lëÿ ³?½ùnñòïR¨]Ç6 ËÌͰÀ èíO­_pÁt¢’_ŠJ7I•ƒjÙiE½b°ÃÞ4¯kaÝ ÐtØ-cêwŠS²â­+,ÖDH» ¨ð§•°Ýë@dQ™¯¤\7”˜µhuJ9‘a–-!5짃2Æi³þ™\è™{a=ö±_ºWkÔ~ÓÈ$½:%ä¾î:YâªWÄí¾¿êMbX³çš5œzå=Fš7Ó%ÃAäö^?h(& ß-Ò>Ú g„tÎz.NÜÄ']Cg źÔüð(ˆ¥Å,[¦ù†”¥$)1a޾UÌõQ= ÝްÔ9›rHÃÉ¢2¿·ÆAj7¤ »Rއ÷U`hr iÙà®!¡Óã f ì*‹ÎJ† Ú¦ãÇÌÆ*žlÌÅ;Xt³‰&¿žNT#eT;ôÔã^qY×:Úx—,ûép K9bùòì0¾—_ÿ:î¯RÌÈ ùY£@«:`NÃe+‚ŠkGyÝ_xU|žhÙoyÕ¨³¬ß:-D¡‹BJ›û5âwJ?ÞÔ²ÄöHhš²v“7ú2` ýè)_ïÇp-»ð³ D\s–°›äàdš·“ÒSñÆ¿Ã_#(¹o?( ] Ùæö÷g¶B«Sä™Uµ‹ù$6ï©0«éð/Wi!Ì<\tÚc§š0Æ8{êq“×}2 <õ(ËÏRú×èZÛTB33K–ñíI²jGp¸!Ö$fÀnF—ˆèÆ›X}Ã< Ï«L.Jj›”v*’€€£ /½‰ÛÎc_ì»ô£lºíA†'YjÍʦÏÖB¶%»VAXR32¥ ä0A›Þ𿞆»ŠßØ›;ëÉG–ÁºîÛXuxàç×ð"~@¯-°}¢w2¥2™šH0%ÑÄ2Àîæ?ä&dA…npk€ŒÁW_oÌsÄÔíà¾7à཰qécó-øY  íJ¼€Âã¬mÝ zâÊBŠtœê×áš´â[-ççïõÍ·Ò¶^[Óán_°à×ÏÓ¤Ã3” ðÔ)¤W‘{%KCߤz4(éèâóì‰æWë¾*ßÿNakuÇš»Õ½“ ë©{uÇ©/qÍtÙíÿà ÏÚ9÷Ãs·H’©áxGsK±{ ÓÙ‰äþ ÷âŒ?[X&fvóoRò6NNä d¹^sHžj"ž€5¸*›CTÿ‘“À*ìw_yåR>ì³Ï#£=Ì÷S¶;ã ²èr”øgí×o„ê•Ô$æîþÖf*¤S?1E8QXm] ]çÈÄÇa¾”Ú¦ƽO @™â°ö¯ù€‹9ÿñÊE`°jij¡É›ºvëÑu‚NGW/[ôo‚Ñ/UúRÒàL‰Ý~Näÿ²µ)ƒ¨%fvèEËË£²u™2…S¹ANã¿[pkÍ3G)1õÈÚÏP•­ßëAŸ·øŒ—D ïŒN±´7ù%¹ÔQ‡ØrnŽ˜ ¤‰Ócæßv]±ø¾›.%6 Qˆ_6ªC'í">aò–^s0Æ™.ÿöWñœ¢´¤¾oÝeOCuùH|£$Àó¯Ý‰Bëu³ÊWï“51•pu3ÖŸ¾eέÜÄmø¨ttŽy§ÇÖÅ7[¾YÆ XcàEVQ¡Ï6 Øë¨=[æA.‚¶R†g`O§m6l1NµéÅE‰çÙöÝòhŠèû‚%7¢xµJŸoÙña›/¿Q¹@š޶({ŠS¦”øDÆ’€€êFH`þÍtl7Ì­Û€±íE¬£ö—p*’¨a*BÏHßÚyýZ¹§ñI&Ñ–þreü»¾v¡€ ô&™[Èܯ̻üT$jœ¿PS$ §àþ„ðí rω˜Á‘X¢ÿ3û¿yƒ’«v ýðÁíS?Úü¦&BrœÇ¬û!WÅ]ÓãÝ[sî)|¾ÓÒ[ÿÃÆcèã¹­gý²€ÿðØÞÊ2fö¶Rˆß Ö›öœJîUï,ÍÊ>ô;W biG2_«ßX/>ŒIêLø–´ ¯&_×N= -ÈWçð³iQwzk‚'×p/<»Æe&®áh=”q(²Ýi ü<ËÜ%'£òýß0I³"ô<ÆÜË΢Û~#š6 /Œ¿¼ Â2<ÉŒvƒZzIn¥dù8¨XÚ!/ýå]™‚ƒ¥ÒžHÚ´q\ÿeÜÍG½mG$¥8* ˜ä¹H¥ÑМtC ,øÂí¼¨{X$¬û€Æƒ2¦ÒV‡ ÊеO†Æí<ÏD8ï<6¶½=^ #¶ÌU6Šè²îñÙYº?bTìv*GäT„k%UÉ׋6¬g¿×jª ñÌhVm?5·X†â¸iªø=èŸs¢w)–6YšÌÝ1:¿]ž}–:Næ?L—Fu}âJ•¢¯ä aN!çJYþµDrYzŸŠ¢½?ÿ#ÚX‰JŒöi°ùsÒÑ»vjözG}\ËŠNxe¸Å]½Æê÷j•ž?íyuí)øü ”/ Mð¾y†×n"†ðÿ#ÏF÷ˆ3pΘÕ×·>ýa1¦6mŒætûĤ%’thqë£r cÁ¢gË´ëv{ž.mç9@zmˆöNØqŸ)–òó¶t ¦ûé°®ÇkúGëWwâÆÉÆ…”jx|TŽ="W'!±V æÆW^M‘M{W |àÚv”äD¶cJ3ûg#_×÷<Λ‹Ôø¿—‚³dp¶ ŽE¥¶ü$ñQÕòZ–oÒjZ>ÚË ÌØŠ÷wSÔ$u„ßœx+Õ £¾‹ùGû* ú ö)}Òl¾æ¦ô" Ã-Šu]Sp×üa&³iI2 Ž3²k°×'ÛzXBgÝ r5)ƒ € W¯ö³ù¼¡Ë±DIç ‘a¡´m¶•Ôöüwµ “M¿›—Æ—6î?B±³Úb’€€éÏu6nŸ» ª ±.úD Ýg´_ê=• İÁÓ 2 ®´z<ä Ÿù±ô;Ç×íDzÍÈkSè=Å×bébÌ^YX(@HV¶`\2PäS·Ý¯Öú£¥,eتMUǤŽK±x¹¾4ðE5[l]¢ m¤MÂižü0? H2„tïåëgaaÇY n= 26>k&+× L´#Õs"ÒT†?„ÊI•ÆZR¡Mã›ë+-ö ¸ë#%:í(PaÌá€øk-=r7Üiž®Z*°¶ÊNºâñVΙ6£HÁøAËoÞ¹»t‰”‹–#¬t;gž“Ùg<0縴<­JÉËZý°±U´¸kö«ŸIvôNì|[‘™3D­ö$CÚ’¯"þÕŽÑ9{ßÜT¦gC“U58E—ðÓù°¥ñ5¡P„-nèE “ŽX.U #„jªÅ"©xïŒéÕö¿«QãÍîóQͨ˜ 8ÞËM)œ…ïvÝ © :ö‚³á ð(ØÕ]Ú*øŠ·ö?óíÊ+J‚“jº@cnâ–jàŽááY˜5ÒNnÓ®x‰Ýp2@‘VÂØ–sWu°êl¶¼ØOžÓÖ“ö ú¦ÔŽ:PxºÚý4£/¶ýÞu²ê½öw†ñÀ|ùŠÙó6„Þ}‡Xø>¤ÞÅóá»6Å ÀÄþ´ß#ÎÁtùã³ìƒE¨K*´q¥Æ‹ÆR×L$Õ mã´ê \^a:-Tp ¿€ïŽ - ·cÜR µ¾¿3&~›ur™–3 ëaÍ©vŒDO? ó@SLÄËÜÍâÑ®±ÞœßötG̦çÐåZ”úNa?)2å¬O¿&h|"çÄ_ ’šiš'/!¤Üg½Òôn}á¨|¸ÜM‚Ÿ-, )?ú°1˜§°ž šG¤LŽWÈòTû ³ð8*HD~¥… Íü½ÝÓ(²1¨ÅŸxG-hÿ½±Ôßu»¤¸Dô°·1m _°R°&y;žþq›ïþìSÊ–Ž/ò)Q^ªZ’XK¨?âàÚ]l°›¤-eú»A“\š²£cIÂðýPK— ópFò°ÀIó©®ø9µ®ÜZÁ.·Žgp̯¶a‡K û˜3SÄ ’€€²Á·?½Æ§Û"ÿ¸YÊcŒÌ©} nMÁCG½É#2L3E¥ÿív+!U›¹W Õï*ÛØ¹:~UÊj±^§Ê㱸éÂâ>t#Ô_<¦»ÙÅ—½-ç{»ß®„ækEfaKÛI]1¯lþª/mêǫ̃БŸ|st°c£/;‡ ´;‹Ç³RÁcvµº"›?AÓžF4(ñW¡}$ê⎯9€³tprдg2ö?Ù(¦w½³q"[~BWS*ž=ŠÕ‹/Z¾síO–å®óÁ[3MâÒJþL™zm¥+âÄ;¤ui "#¨O$rçù5üÝÈ'r≅Såùõ‰®ÅËÒ¶6¢=MXg—·[Ã>»šÉÄUAOo‹î¿Ûì> ðX­¤ç€{È61õ¿=$È´DGá͈b¤7(<îOÒ˜Ö­[éú º¶§S°¢Œ©ªz<¾Kõûè©ÔPèTx¿7”ǽIýGË’POÛòÈÁG:±ÑâÇR™mºÕ0åž  ö÷¥Ñ[¢ñ*¦ø4ÂF|wRÌ@gÜ0¦¡#sùŒ)µsºö#€´d}è6¨ó™à¡æÃÂUŽ*ÁÈÞõ‰ <]¡$ dÔoí¯b9m.x ùF–Ô I«H‡SM ‘ªÆW}ÀrÃö«UfbZAHÀD³u꣫‚³©èƒ[«:—©Ð¨ÚOR °—7H•$¿KöÄ¥Œ×QÿÛª2n'Øý,cX_ÔlÐë5_A2'®| “݃Ú[O¶ã)B ™°x-"ü‰–䯑 ó ¬’ÄþeО!¬ëu|n‘ŽÉ}h8g7pýÒ™}u§:¬@b²pùV.y¿ÄÐ@9ù{c~^eÊ‚*Ÿ%‰€ec¼EF@Þu\ùAO*±â_¦{¿3ªÛíã†Òï{ôŽÕ­+Üõw3ßîªÙ1ŠMãjgÀ’¸3Ó˜žT$Ïi¡ú Ó,cjÕ£9¾)í¶L1ªô]øÒ¬¹zûëÉ?ô‰ÐŒåìýb½«ÈÐyÕöF÷É}ûäwóË w&„"cHÊ«NxìFUzŽWë>Î$d HÚ?oôU~÷°³šM'…àuHö¨_<ñÒÙ|ÙÒ<ˆ&³½H®”(O}x–Óe…Þí[ª„¡ãŠI—¤˜íuwu bêfËý{­Ç’€€¾g”úe ¬î 3¬Ó9'þƒûRjkpê²c*²„@HÞÃ-†‘þûÁPjŠy¶Í‡aÒ«ñ³}¾9óp¼¢µõÖ€Ô3Þ•e]Ÿ7ħÎÑ×Úk³"]v7Ô@- Ä=‰?‰LU¢kd¡e¤E—‚jßDðk"Ñ…™lîH§-š¹):²×xàì7!Þ3ÃKNÁVãÖhƒž"矚µÆÎÌê¡{³àú:1ò‰I#­;"¶Œ"PÎôý¯ÎêÝî7(í”vâ€óÝ‚b èõìÀÖ„G$ÂÖ–¿I³P"—‘) bA \%Àru4Øcìo'±†<ÇÞâÈèV<&Èåù ÷·áÎÌlçðPð>É9é{©íqpÎ AþÂ0ÉR‰j7—Ó ZsvŸW³öÀAZj8åµÓwé*ù³Ll%r÷{ézÈöV/1ûbÉ->qª®ß²»‡ƒH{‹t¡ß Ç†IX>°¼ÂÚMf€å˜Û?‹êÅ–Û‡‰í!¿<˜zAÒ7؈òb­˜Ã.Ù3ŠîfgLÊ(H< 4#»£êMxl{]ºá½³83Úylwþ^ÌÙNFÓè¼Y1ºõ«|ÛgÍ™]1ü?¬+dK0„ÑlÍ+äËÒî¦zÏTàoH ßà¡¦Ž° Z±@ZGüè½v=k§Å‹RhW¾7ÆðR8U:B²¶dvPÂ=º¥N‹¡-õé®G-k=´V° ©®fì&؈)ËÅ.^ÐUÁǹ I’kÓ×3%øÚ, Šz½ã›ê­Ni^G·¸?½¨Ý9JÜðaµ½?Z?;Ù¸Þ’¥û^™h7ϱ93ÿ/Ïnqd1Dxï?µ5´+]¼ÜßUaˈ‰gÒŽçäçúq?L§6%ŸN |ÊlÛÍ+YñÄ>ä M›é¶Œ:wK¨mC§èËør%a¸ ãbБ#;T÷Šiù-ÇØ³5ÕD€[z-W ij©ÝM‡„íc³Ê3ŠV,CÖ2…Ì Æ°›…Þi ¬ÍÂÑ\áq“Ì… ÝÜó»;¬î(Òë‰SÁ %÷žj…Ø2âòâX¼åPîñ7ÛC&6k•A%ˆ@ôÝ_8LMez×èô…Ÿ=9LÑ®K8GW»P6Ø|Ì’€€—žý³.Þu.Ž×Ø’v.)Xà´½êÝÌ!šûu'Â}ÚK-ÔÎ<-I;m$Ôß ¡V>¾ÈŒ›ý X‹½]йOP$‚iä¤î²g–K£,nÎð)â0ÂÚûYg>(ÐñŒ Å\ú-QV˜Â+n1÷ Ïœ¿*€:Òsw>𾶉ÈN*ì¾j·Ëfke˜Ðñ„4¹0ŒY‰MAb«ìǺ}eƒN°.]‚²F§œÞ¡ö„æ„ù`-Ûoõƒ„W÷E'?ÂÕ=˜]Œ–UãTr¯”òˆõß_uýX v²‰1\µµÔ!5L¬³Æ¹/­+Åö@}®d†òfëƒsiSt«Ã¾iÔÔË8?õÝ"všÂ ߦäqææí_;㓬–±9Ï¿EÊ^¿$& [;)Œ‚ìKk.óÍaÿ*dÎÃéZÁ60=ËŠÝOQ–žWú /P¨GMÇìÜ"ŠP`4ä©=ƒéE(· Ÿš[rN#6±¿ö ÕyO¶T¤Ì¡­kÝrNùÇžº€ÌµÝ^{®Õ3˜_mjO–K]0ˆ¶Îý% ð]y²¶RÂ;ÖŠ÷ár8¨Ýuù¤(å³|_E¢ÁNÿ³”€¼57~žéJ­;)Ð3K.f‹çDøõí>0Þ‚xp%ÍMÛ¥yÈÏ8!üà/‚Ž.3ðýý܃¾%J@=ã÷¥B Œ|!àëùúÂ,õMwz¢=ˆÅMüøÝé·à§¦ôs~¹YZËÏ7ÉòÍ©‹ðC–ÉG¡æ¾ej›2ƒlAg} Ž«Ž2ì®wV; g àé…Fö·ˆpÕÁJë/Pí['¹}¶`à‡ÏÐRð¸Ñ†¿›p‚UœH$²ƒLÕ¸ýGç(Nv”ߥj:Õ¦ú™ƒ/½?• ¼М…£^Ò# dŒ!ÚÔÊÒZ%ÅöǃóÀË6¥wT’à>ØÜ ìRE³/FIæ¦OºM ÊOÛG¤_m…^·*1-¥ { h¯üŠ3Ñ4*óS“îA"ȵ~¼d™@i©Ç‰Ù#p:»¢ŽÔµÙàÛ¯·á\á ù§(,oÝõD>tއ,o‰ |YuCÐ+C]³2 «%ŽøOí§1‰nY#¸&¨~Ꜽ¦ HQ¿ž¹×yðíçêHŸcÕÔg˜U’€€Ô ²·>ÀøU^ü88èIèr|uwc6PaýAòÛ:øJNFÐ^ 0¬ŽÔ7§ ø¸¢ZS©™>ıg @¿ž½I•v1a»Æ²Pfe,Ó] ÝùÍÊ}½+òs.~¤,ý]E –)_ßz JWuŽŸ®Ùhù&_«âçÚ”Ý @-ÈdýçÛÛÈ1²CS‚±š¼§Ñî2+ÐXv‹}9­O°]ä5pf2póT·{Ô3gõÿFM}bK´-p ·Ï&×|¼êÆÞjäÖ@8‡¶HÞ]C’;—¯:i‘PQÛC…*'ÏL;}ŒLU@q¥ZÀ½Ú®¦P<6~0ŸÀŒ"Q~CuÁp nÝÃv™þ‹CFìjE§å¬m¡ã¥Ñ _Я¢¥÷<é“_€XŸäUð ȧ­ðH€‘õ¹¦Ö(c›ÝelŽDZ§_èù4@Üô“Ö´ Rk¨e ¦‹{5ªGM5×༠ÏÒ‘'Õx_/Éx՟̃!"G1ûûŸéÃz!x¨`6Ÿûv¯‰b"€7>¾ê,ùx·}D|Î`ç»î“VA†àŸêmIÒôGšw=QXăΜrÿè•5Gg¼'ÅÃút¼zÇišñ’Øåª¦>¬Çhó 7éúrW«y±ÃÐX óË×7–[ËM£ UUGa{Ɖ¹Ù0×PS(Á xP?5A¬J7-¸æ‰vâÃ#;ÂøûS9ʲ˜4€øÿ·Ð±Ž¯po€K i9”^€ Bë§J"n~bÛL€©;ðyw«ÜKÉZr]Þ˜¼43Ù—|~òWê  ï‘ðù‚ó¡\S|~rÒ t¦qEÌ“‰ 53oŒæYUØØ©[Z’´(V¬v|ƒ›õ´¹»¬^`CÌ(Æruóˆ¿{û¸òTÁ"~ÙfÔÚc<+‡bµQ MMÁ}wЛˆRÜy€ÂjGÏBxÓµöÊÁ`^׃ªÇøT$’x?Nm’èï^°ÏÖ76³¸¹ÁY?²ì]ro¶Ïwž83z¥Û¹ó»·b›èqˆNÜt¶,^£@ÏakO?™,ãÏÚô,‹Ú+  ‹³·KbpÐõ‚VzƒÞììÑ‚ GWÏOîí”)åZ­‰Kýr8?9EQý´?’€€îØÜ»n6=P¹YæÊyá7™ ~N?8è––;YWz¨w§»©õª¥®N€êo•o¥PK»ŸPìC¶ûTW`+=19•9ªBã¹Ê×XìÙF.—Ï}_*-)h&ÿÕ‚•ºöʵrýüÚï_l:DXR¬>I.œÛ÷RêÏN«$dô)-ÍGDŒ#꘸ùyîÆ83ôà¼"A¨‹pU«R ÷a í z|µŽÒµ~aù÷¸R¹"À@PUwó?¸ÅVcÇJ›Xîg4þ£½l8° t¸þÀÇh=ݸ·& ”ø3¾J޽Qç9E¬ð^Üœýj&ZÅmE¿ž®´¿WC ù·«›0݈A£ÕÏŽç,/Xˆ§†µ}P‘ÌF(}Py® f§Þ$'K w³‘7_¯&¥jƒ/~ #€¸ËIà/ýw©‚ó|™…õœ$û‘ÓQ{ ßîñ´6†Àñ=·úöÿd5½ü{ÏÑlƒ?ަW?›e˜~¸}þÄT’}[UþßI¢;ï…B¯iµFa¥IK{‚3óebR믡KVµ`0¡(˜|.×âYý±Pg ½8¾<™z\6ˆƨ›ªß±°×,v®˜àí¸\ETXŸ;›ýïSÅ.w.•œï¾ËYC 1m ŠÏpnÈí]‚µPlŸ}«š¦§£ðÎp§ŒÏ#÷ £€lÐegË¿® f¼ã¿ü-ÄìmwâÙ%¡”„FUÔ×ò=aÏQ’€€Úã%|qëw)Ó ð&šÊ÷|+* B?`«ù™ °êc)âM’ï†i1é* s´©oè¶RèŒfßB˜¥vµjF§„þ”AoÞÙAÿ?,´ßy畎Sx; ëùt¤ÁÇÊ}¦êo¬-³±¶ €ÊbоoZÇ‹Á‰Äí‚PïOZ9>È$H»þÃ5NÔå/*)OClb5DŠ˜l·* ó]žm±èÄãÛÀ÷Z=É®úÙðFXÌQTè—ææá*D¶Æ•så®·Úùà o‡è?ô@} ™Ås8'xç¯Þ'‰{t*'˜“ƒÓÁ=°)nsḛEmë»!}rÎ92+̆z§k_ æ˜-¹IÂhs™¹ý›€Ú]yWÿRý.r"Dþ\šŒß‰èÊ„©ÙŽüŸÃq¥†Q ÕåZ9é@¾&Y^ÁIoUþÐÆK ˆè)2r£†dCãÅ@ªØ¤í"7øœ´½;%Ô3³óz(Æø*®XB#(Ý¡ ‡po—UõÀé“¶G—xó8\N”.Êi÷*–Éßâdà^£Ê‡én&Õ¿Oµþ/y›Û‡;ÇëSA]ó„„bù›‹c~}μûl4HÓýÕKC˜àŒ&éÊ:d\n4%öëàe…‰áåWÒ\ ïuGõž†yÖo{ÿà›¿øªÎ¬ŒäD{4¤¸Ñ&{ƒè;[¢Ÿýîó-ßœ"ëß/‚9œŸÅ_Ì=cíë6!;jÃÞB®Ù42R=bUÁŽÁÞžÍéL˜UEÓ¶DÃsÙ“‘ºC jÉÂd:àà®ú$MÙˆc Ï=Tcê¾;sN¢~ªaÏÕdžyßR¬/qÿ gämTÁ'G¨¢B©öeu´ ÌmÄ—Fë$ëÈ–“¢}MüÓjå8ælê[„Ÿr+[(ÁÖ‰F¤ËØ„iù˜‰má@oªtË1Pp*m6þï4¬¹vÇJŠozïKwŸïªW—v*>©±ô6’ûE8¼Òå|„)> }"5Áq]‹†ÿJ°+N¹eo–Lïpc¿¼\éP ºÙ;éÍ£…d°Õ?OÓdÐ8oåíþkµ>=5ºŠ(Ö9TÕéÑwSu¶SÒ<¾Ÿ¤•Ÿº'Kô™ÒE€y 6i•’€€ë6ƳcyàuC]yó žN“my“…sx9ÚTØÏ¢¢Ý¡3C¯eÜáï¶û·§]kӔϰ÷¯C3·FïxU¾d­¯ÛìÞñΙD°RPèæ <¡wit³Ñô'Ð/ÆB‹ú ¶¿jý×,ÙúÌžÏÇ¡§f府oÊõÍ÷ ìZ8äŒé½ØN î§ïùˆN¨ —¡Z0æÂ&}çêv$¯ƒÇg˜¦ðЫÃl4$mª;¸J—Þ ×žGàõLð ìC$íkD«P$^Š/ÍÉ7F ™¾D!Óyu–DÆvHÿv ¡ôàÎ_BÙ›Ã[…ýst…g`Ž„^ŽïÊ6%ßáÌ3BJòoRKNü‚kÀK‹î ë¥à>ÖÉ^óU%aºŽô¢ŒìÛÕ⎈å-Œ¥*ÜÞÑFæ–üü%÷è½æC‹ÍŠp^f$‘d3çÿhâÍg©Þk¿üt¢ù3£ßueí…éÛC9­þi!+6byl÷)qÜß|9¯,|´z˜!Þ›W‰Hl¨º5ã´3êg%c,.á7 fº¡Ó+ļR‘íBW|ékBvg*,Ó8¯œ®—pÉK‚´F[—U„®Ï…Rˆ!ø‰ã’úäæêœSGÀVXÃÿÉdì¢ –†X!× HF#†÷¦¨û´ƒK€œæBi“VzAþ•åšAhÁn•wz@q8ÁìëËFû˜Óy>ÿqPâ7V¥õ$îÍÐ1Ôž¯åMøHz ¡Óisç‹ÿð;%ê–ÊLPb¢9Éç›ø:× 6<%©Tý+[¡8ë¢Q¬û¦©%ƒ_+4/!­5ÿQ ÕȾgï::4!r ´ÿ,ÇÍ¢'ž¯9Tôò<¼†pÛÜ´À7å•=cY ¨©ºµ”û–ñ»ìsp@· wOe™ÿïϾæö¼z`·(Þ¢ªJÃ;),E O"³=Óÿ. ±cMk‘™ËóQwU‘l˜¥€(¶v覌° ¯Ìƒ©Š¨kß‹¡Y6ˆô8û¾xeʨ¼:‘èNÇ¢7ò˜K$þñoÌ_PôÖ‘4Ã9¢òm|\ýórˆ´ßó®\'ކqÖÖÀU¬RýÕE”µôÞ èe$bî‚Oä‰êFÃÂC߯×Nçgü_Q`*ÇÕL òbþŽ2í$wÅ_’€€§”,–'cy§˜ÚÊš)ˆ Zòj´ ¶»§ZëÏΈ.ˆÜTüŒ»ùàà5…Üçá¦Ò?Ê^ŒgZ·'‚ŠNV —ˆ”¢—Oͤݵ*QË y£†ÝôÛŒ ó…LVÇgÐÂD(ûïñ —k…,_g–r-Éݦ틮°ºÄû»|¶öý6V_×Ì1üqikÙ ”ñª¢‘©]<É&ûÝM4ÍÌ«^%ð’2¦Ð_êD8âÎ#©ª€O‚$c¥½Öºå½ìNn0ߎ8iÔZêm®6PãlHéþãb"QÇÿ,×cJÆQU!”ñ€Äa 8a0ˆcºJŸ‡ÊÕó ÿ*7¥ð/œÑa+šWd ʲ;Hš¡"¿"6öQËPè+L [µrB]ƶŸÄŸòÛø[\雫È>ç²û/‹‹Ï»¦*½k±pßùT> š Æ7Jiâ w ªœ”èHÐãEEzI‘UÞ¤÷’Py°I$>ŽmÞ)ÿ×§-yjFic~Õ+¿öý•S©P×rU4¢“RE—æPfÿn@! R×%ËS4XIÙÒ PØ!}McqžfW#ü–ãÜ~t ¶|+z['ôÒ„¡£ký¼Âƒ`=Y°ÚºzÕ9ø{`Šv4жýÚ¿rãE/‰(CmÿÖžŒùË7@ã¤Jn\Dt‡ ¬Œh˜©Yß ]q¼ÞÄ{:åd™àR' fs*ÄB­þ–,UÊjíw!¿Ò]hûÊ€Ðÿö®»šY›‹A*•¾¥øƒlu†ô¢ˆ¯$W¡-®Êi.{Îñ¬hÞÍ1‡};jݤéOîwß¹Y†Â`¶P°>)“kÞŠØåbêb8Çr—a?k¶tÍcy¢>xV¦üúsK<Šo|õnçßìt"íàQ*F-–s6B}{‹—j5Ÿæ,Íd nj¯fëL=Â,à¶*«Ä!Ç©ˆl`°#ÝŠÓ‹¾§AHe{lßÀW’jâTµŠæ˜I þ’ØîËÆ3«[¶È¬I ‡JÃhø=ç(¸¿êÎÄÅ*-Ü.‚£ŽÃP éÍ™½Ñ SÕ€TEÞXlC-ùò@/ /ú'7ƒº£Üqû–ÞÙóŸyÅßÌž‰Û…¸ÉtÞ;1‡4šºÁžûã# Wü„øêÀ]+æg®à_qŸjv̶h@C€‡’dïb•Jëåuâ/¿òm(! ÉŸgÇðaýÖ×q‹R3õ¬Áç*•«éÑ*òE} ©‡Š~`š`‹Â 9 ÁYe»3’€€ÄÌè•©ÔPÚ\ÝRðš‡+CËŠ‘Ȧ.q”w 7ŽìÞ/öôDMŸ–:C/žÁâ ôqD MÏ?v3ÁÃëp±™™¤¬'–†ÈèüåWzÔ¨e¥à<`T!°ä?Ê”íÇðú`0„ÉßJxòÖ¥W>•5°×T^L0k3ä: gSõXVº&9–0^6]3 -á°L>X¥p±Ü‘æ…Ì cŒÉ5ÎŒ¸ºÙ|Å3­¢:§<¨°¤Ôaùø›>è6’Ÿ¡qE´í±ÿuȘ–jA<8²#`•Ö­ÌÇ%%{b]`¯œ¾?LfŸ"sÉÓ'ŸwYekÔ$å'Ë!+³¾‰þÀôøþcx!HÙìƒ{KÅXV˜ü±ÛC¬ÁÍB¯ënd /ºk¸-P& š1¼zåÏ=4e6)hî-Lý/úl¯E¼Ð…‰nظ1yó…ßu]|˜m*îyKø\f†´¦;i Ø-·áq w¢‘"ti3ãPñyBmÛ~¬õœfy:SË3lžr:ýf–,ïÚ€HAñcÁÍ.A¹Jtt°¼4—’„  öª¡<Ì“»àC%ÚOñ{sÂõb]þîúÔcHÈÕÊÂ~k ?ߨÞÃUÊç#…ŽÒ×´Ñ™äáˆã“¨(a`«FÅÙáÌBœÍUødYRë·i·R  VÏå DֲĹ.!bAû‡!·-ÐË›n1‡?΄ ù¡¿Öå€u0RÈ4Ÿ3S uéì{¨ŸÝÚö¬bê»$׳ùêžÊ Ÿ¿/á^×õ´?3‚a:ÚT8@ÜÀžàs>m“•àÇr½‡1G.v°Ò:·ÊÔ7gã'“Õ…=\¥1ñ`BºÊí¢B¡î̦Aí[€”9?Þ6>—‹³WM¹$£çK,ÚŽ’ ú ‘5ŧ–½R&Þc=˜]ë0z&è\®¼ªçFsìöÕZôiE…9 ºSÚ|LWœV«éõ™ ¤C 84±÷$72ÎoÊbë&e­µ͘»7÷” ´D¤€/wšõ‚wðÍ 'x%‡À·< nSa|þëv‰Eÿ'^Æ6‚Êm —’ÃÔF{t8$„úúÊ›ý÷¥â/bê¢ñ‰3 ­æÛ}b;•TωVðÈVn–£îôóñ¢«í™py\áˆFÉ’€€½œÿÚƒÐ:6„¦þ,H  [Žhíl`µ%R ©ãrS"øo{1;e±~Y£9RG5W—¯g‡ÒâÛwÎd×aÑÙíg“×3:•üo~å}8Âø¬Ö·`à*ÂDN¶Í”X>9Íð=Â{ ‘ÓFj ~§÷®7h6áô –6G}Ï^f§¾]Ò¸,í ›~¯õÑ’ZJ²ÍVåæßfüÕÐáb¹daòz§ &`Â>Ÿ¤P \ÅVh¹}):*š´v’`DM5ç©§ÿïÕòQľ™dÖÊ享ÓG£*E®ܨ –x^ÜÔ5—!‹&Cx% Ð@;(”&Ñ pàÛ¦½#x ŽÔ ‡~ õSsqNµêͲ‹QÒf‚@˜‰ˆøIlj$(MƒðÛÓjËJ {!6sÒ1ãî-•¦[:þ=¶ŒÁ& וŒ”¼@èGu7Ñtœôê Fün¾0l×Üyhëx¨êKÊlå~L?.ÅÈæÉsrƒ&{=“Ïë±û“%@îHÖlþ%‚E-A¼ÈT%ÿþª†'‘¿±~þ¾ˆËðÜ—þq¶=XJäèý’Ûÿ½äû@8iž%ëõ£/)Od]‘ á’ei ÿî\/-A•ÙÚÂ)U.Ud²"nJ“Ê+ºÒn5ݬîRƾEÍAÞ0Yð_j®Ê¿§·J è ‡r¦q ,¶‰¤´üdû%÷ É¡Ê \4Îýoî1V]am¢œO=òñ+Èz‰‘»Îë=ËED¯’¬fhP”9¿,žÂc辪¤.Bc…7Ò`M‚°ëØÅ îÑÕ¡~€«¼:õRì¼;Úwy'³%ªÐØùwc‘Âÿ\Ô˜Ñâ¸{Йyò<«ÚÂ䇱G_Ö³>Û©C>DåU5g&$ý´`zHxMÆTe{_VÍ<šh)À–æ¾e•´=Žç3)qûˆåƒ½öt³•rGí5wÝ"ƒ»ø¤Dü×È8Kóu&QÁëñlVäkêQ4Aa£lùË÷ ¾`®?$Ž¿ Ë€–ÌN“³iYˆ‹jÞ×yöM}+ɬ$ 6Ò‡BŸM DÙT%¯ØŸ§Ðé!/p ‚f‹eåƒA÷¢WÎá¨ÆÙø›Ï±1¸“jÌôpz3$ë…Õ³Q td±­g/c}ÁX¿ŒRg¼þ÷I6’€€Â}¾Y$º†«ÅVØ"ÙíÕ¢îhë×w ÓØ¸ä½1’D×§ÆÅ_OEÍûÄÙ‡aúú¸Ç*›o…ÚØ…ÖÑWbÈÂÖF&w­kâõ¥¶)Ð7@×Ç#H³+9l®ïh€VË‹à}óØåcCˆ&ôˆ9Fr“Dð•tÙ/;¾ÃÎÞê"³ÏT…É}r‹în5¹A__*1³ >cÛmà‰|´rsû…ÈíK0Œ3©b×ÈèÏ·³KTÏÔʚ܆Qª>áàÍ¿òpŠÆcó=Ÿì©|7Ú¡aœw%3Ù(¡°çe×Þú, îE~ý–.ÉŒc †«°Ñå¿wÛVÓs,oBžÍºõöÖû;°50›c}y¡«AIñ<[¦-U€ï(2Õ" ïÿža¯½VÝ×|´Ó¬‰R+ò®˜>¼,e%2 ClÖ·5waøUU’­â3Ýh¤­!J›Ùi[Y\ˆgÎbàò°^‚ó]{ÐøÎψ&¶|aÛ¯O9p$)Ã"u{7¢y8fš¡Ì¸¼ƒŠ–®cÑ1sŽtªs1ît›æ1¡°ØÍí~y‚z}ž…6”ÂóúË¥îcàInÞ®6d¸r¤Ñi"Áµhç€=ÚX²ƒY;4%—q‹«P8Òuçª'ÍëjmÓ“áü·þJ­Å}LÎ1Ñ* t¾¨äæÍׯJÈd~h¾¤ ­ÞŠ7I(·jßzµÑ26ÖuôÃ7¶Cð?>b7¢e!È'©…•Ž}À0J8ÃhϦ¨´ câggEuy!$©©÷wp·N°Bß<•Côfa!£0DDtdŒØÛÌ¿WH*'‘ß)gôììÝÞ$ít϶-ŸöÌ… RÇ+¾4÷ç|zöqÎs3Ñ($£aoÉL,4ÃAñ¬}d Äk­B©ŠPÞÀè3æÝÔ{ˆ¬e·`Ýw4uÇ7Íý[ª}¬b ºŽ2›ï([s<à³%Ê.×Úùå%,.›>Xw¯~¤áeƒ Zwš @–ž£0-`z8ÌíÁÌ 9¦ñ51™M.’€€´Sþpè¬ ú M}ýdBþF wœkù%TP›ô:ò÷«¤Ñ)?cz߀¶“\æ¢æ2B,FÀšÑöåØè¯Nu¹2]cJëuwÇFžè&gú*yÒk‚kܸE¯JbÍ(“…¹´ œajàmhºa•ŒV¿ÜÁËñf·3=Y›Ú \í3U³îÌ C 76èà–'z|ÃÍÿÉ›š³$E!tFÞ¡˜Þø²xØ…?]FœEŠJ6A ‡0'CºpÖÉKÕŰ·£JL¨ .›ñÚxetÁßJE6bKQÊøܹÓ iŠ{?µïÕ/ ÓF–v…¹©=é9³UGÖŠ.Œ]Hšk8"ÖˆäoÜ Á ê¶ÁåNR5’hÐ ;¤PÐn:Bœ€…ÖÒƒÊ{•´•zLœð¨¾•Ƭ«_l¶Ó‡Î®Çž%ôMx´µå2 0ÒåIžfi±k²Qe÷˜nÛl÷ Ý‚ñ·¢žKõÅ—»âÉç–3‹<¼€Ÿ0ûq µŒ y gTÉç×¼½R–*‡~a@“2}УÜrÙ/‹^n`º|¤½œ›ËÝÔÅìÃî‹>¨§‡9cÏ´ŠE=³‰?9z?q—¯!?–¢¬g7-𢻃LðœÂTçxŽœ¿MšŽ0Nà/ÀnQÚ]»f6ç馲$Oì…öhÌ«Õ$õ¹½Ì­7dä¦`o)¶íÚ.W31“1{×ã:fÑÙädC~LËìL÷¹•³™ð O†ŸúÏ—ñMŒä?.ã_|«Æ=íüÊïÖë•Ä'ðøž@÷Á‹±â!öQ#b@uhë3²!}ÝU04À™<}µ®õü¦Êàïÿt;½mé#ÚÌAzkRk†@ã/dºQ^£t…5\ Œì©`ÇÁ÷¢1ša4Ü‹ÇÃÇÌݼa–KÚ—¯iéˆÑ2qïFû¿n•rî`†©.Ê”põ.o'òåò~éŠ<·0+ï 6oûô޳ç¢{¹ì“Væ—ß…\á€RxY‹Þë! 'š«ÿ¸U&íS.D°Wöã )ˆ‚ä ùMAÓ¹1åðçjhRÒ Ï.gNn׈ùï‡ Ì©pQ_à6kšCÕ:*$¾èÑkErnÅJDZ¸‘—OÅf1Â÷x,ÆhÒ!ÿÅq6ø°®Ž3£•)™“ÙúëÙs—“å*`IQßï®§’7›È“{ùõ€× øòóã÷ÃLƒÙeöSý>I_­%_ÐÕ/“Ä™í]‡hû—ÑK-kùŽnÁ­Ô ëè o và·Ó6-33÷­œü+˜²«þE¬Ÿæd¨„q”a‡£ÓiÉÒXÒß3/©È+ /£E1™ÉÃ:ý*界8^ø8Ï7àeSþ¡ÂlÙ0;9eµÖ<ÜuÊ×ÖàŒbÂbÒ$ªO‘‰÷ÐX;Á†üût®ø ÖЗlÝõÖ™Pw#k-V5;ÜÅrãX–õñú/ò^¥´Ówñ˱¹!zƒ«Ä·MT è%ßÛ7!Oý¿nO>yRÖáÑãgãÌÞqlͦÛ GI%A!o½#åñÈS$vxr1“¬ˆ‚jÀ ¸íîsIž½¬!¼?Œ»\«bç( | Q ×¶c3+þ±2&š0¨ÆÅ‹cD÷ɬ-¹Îq9ÅFá+dÔ6–œYh­”ÚJ†Š bÃÞw&Ñ“‰ü’€€–¡SºúËÆØ”;óùK’˜9Qº ÒH Kí«¤lSíAžz$w…1‘/:›¨DSæAï¬S{Çìí‚— #…†zþ® •[D–¶Lj2|ü¶(:@Ñb´£ê‰Ð[3ŠØ3zß[-´ä—D¹÷EO­ï|°n7°W÷ÕÈŒÕÍ©@ÞÔB“W:ä?9ò>øé±:|åÄ#$Þ’ÜàV*æ¤ j¶d-sìƒý” 5-ècM4›u);+ùVsŸåIzÕ ©Jo¶ Îôå`k/£ÜW«ï`övËAa–ò¶êA4:nŠ› JYëwxùF¼ç"õû§¬É@¶+ n(Êâ",Zùò Τ7ûbê<±<~^¡6K÷¹Â$§øt2ŠO^T¦þOdÌí6#Êl¿ö^(ºsi}‡•R …Å”†ž¥Á³X¬çë|mvçf$ÞDç2ÜS†I’fgúQŒõPS²N° i[Æ¢5¬@ůO~­'CÛÖ;NÏׯÜâ .RÌW§®âŒîZ‘‰_ @× ßʽü{MâV½\»ÆŸ­øŠñcÙÞæÖi‡Ùò^¹y¨ômžï Í‹ÉäR›RvÂ蕘ÀsHñ÷_:Æ7VRXžS8˃1þz‚MÄä/Ál²ªÑÙW‘+“Ôè™pð©ú­Qì8°-l«Ìònª+¿ê‹NÙbÍðS¹›eùÛYIí0òïµ&½áSô‚Y'_Jhů{ýV6 )äÉÐ9qd'xõoP1-¢¶µ×{Nœ,RWÒåÅׄÉú¶ CW2~NÖÎ÷õÏ{‚„€ˆî'Šdz˜!˜Å¿ªYXtô ØÇØk¨yêµïÛvú .&´ãK@s½ŽÑÈÀ"‹×~¼è7¼_8xN_IoYRظϟ`^ÓªøÐ0zV¿•9;±‘Q#Õröi& œ“ü´öl‹¤±Šæýn#˜ØNNQiPË5Y²gˆ¤’€€ÁQÑŽà¡Už$ ÈÖ_E™RO¸¶¼cNÔ­³*¹åä±ù…F’6O~µªÖc×ã%xh kñýßÓ×§f›3Ø< {+YBL¥r,HC2xf¹ã¯9¿ži×Õõ‡å2rZú‘š¢H¼jIEƱii©m ϸ{$ÓâzÇÈô£iA˜#É”`Tb' ¿åjkûÐú™_ƒTîÀ#è+c;à0Å,“¯RY¦/ä„P<õK¢_G¤——’#.èpu¸Q3ÇSÀ} Cøyk²kƒ”5¶2d>=!çóZy}˜šü)›µãFU ü²X”1SŒÿ¬¬?@=væk‹2›©¡ d‹LUfg'ƒ p1ûK\ÈÖkÊÜQ_L5›¹„»ö˜ÐPOlsP¡÷¾û®fßô¡)·0òP@?~ÎS',õùNfýßáâÆè£¬]Gô5Ò‰%`YÕù×Xá·³—Ú†ÃÔ-„p÷iðOˆù¹‡[¹ðE³Áמ È}‚Àdk‘ôKóîà™y;W£õÁIá ¬•×%$òŸ •BvØ@èzúhetÍè1òPèî”á•.g—9‰Štk5‘ÅŠø¼ªÓƤV}%„Ð=К¹2 Ž˜UwJ¦d~p®çµD<¸šŸMX65tgn¸Hr]6’÷“×D1Ƹîi²Ü ÙAæ¢ö&‘ûD`˜:’½Ôª´ù5'V¸|ˆu-„ €Jêмì:fWÓÙaZ$Ë탋'}Á ù)mæÕÅf³^¯#¥e§ÒƆyXa;‚GHÙT–…¿ú£+ˆukÌõ7cVW~: štå¹âë÷ék` Êéÿ±ß0¬ßG€e™ãleøá ·œ«æð›Ii¤SPáê#ǽͩ«>˜ÿ Xœ !èuàÇ5fFÐ}vžj§èË™±JÒvùÊþ?ÒÅ9t#¤^_Éž¾GÈÑAož…×NdkWz¸q(jâ3&ó°ñû®}llø‰gOô±~^³…ˆyBn2Í×ÛŽ £ããóž{&PL÷ëÕâI‘ù#e\êQNèîØó¾w‚7óaÔ `ÂB‰£ •›+²ü¦šLl9Nêï”J)$3 ©z°ÏÙÂN>Z§ƒ9üÜIõÈÅ b®‚›Fê&·½|¤#¼D…²ª$Â:±áAE[+–1»cþÄÆ›3 #fµä}_®ìÜÒÔM¤é©LPîfOòp\w;ÆfàQÆÏއKÀ'ÓZÖf6öžq¬ÞŸ„=+2°î둸ap0²Ž?1³]a” Çï'ùA!ÏC66ÝI˜JÖ8gùR¤!4ÈYŸ9qÚ ¦Tm$‰¡¬]&ÜóŽé­ ,Ï–­ç& º/£=\³ä®K²A²¨zÝÄiÛLû‡PfÞ‘ ›6:$9’€€˜ë]¤Ü©Ø‚Ÿ‰ÑøÜK,ªX½½Q“iºªìÎWç~ ¿Ê@9¾è¸@>Oø}ª a¾Cmi›È2â8n¡Yó|’ébV%úÏc ½óÑt2×[}4AÍUìšXº’j‘Äõtë¸5Ó¸Yµªù[ƒ…çw9mÅå›@G¾æ/OÀW*¸A÷Þg |NaüHúnÂÆ+½7ãVÛЗ6"ždâ> «¼å"àõ5J«û(ÃÚÖÝÈaît=‚[_mâTd‘=²xÁï`¼s®´dõð⮼° ð9"¤oØqQxžæ»¥ë¿3)U8ÞyõÜ @Xe„Vÿפ›ƒ~‘š6¬áŒ’‚'Èâcb„^¥–³JÚ¤%îëÕÉOÎ*J£A'`Ls»J«ñY@sŒÿt~´8N5]Õ·ƒ¹6Ä7¸bÈèÍ“ØI‚ìŸÞé dö•Ð _¡KÀjf¥ÕÛ7`~omè´ŒÃQŽ9ÊÐêGéõ‰…È ÷‘œæÏÜò0˜‚ CÅt_¼~y{Å”ŸÑôs¦go*zåsÉûNŸßÉöK"Úá·V¨NÅ G”px˜Ç¹Ê}|ÈøÊàŒö­"ƒ$ªÉ“¹†+^ŒV~O*ASÅ“´©Z†}(ÓݲT ´>ðãò·“ >}@Lè ÍèÎ=B\›C{Ñ-Rà=YѪ§/+T¾ÆoA^9•ÕÌsëÀn%˜v,A˜È³EFÕâï!3ý{¿Åîr5é9*è-ßÁTfæ›ùÍ×à{æ™@B%d(icÌjµžÜIŠ|¿PvÂfÐU>Á²rlÖózæù^ßfNUÁ³réˆß Ú‚ßÀòß±ÏE&zµ€¾½e“M5Z!ÎÝH¦&Bë m´ÃK\³öÙ²)yÛ; cÛob§9ñiÕèÇ#ÙïFƒª¼î¥ÏdFh=< >ÕI¤Ò™1Âfí¡4ÝÊLZ$2«jéâ–<н„Ùv]ç{ø-žŸðÑuy.v êºyÇ£Æðu¨ïT= ©m4¨*ȹ´$ì0t3;ÊC`Øaª#l•Bqœ̆;Yú;š’€€Å˜xt¨Úâ²%Ó<†颩Ȋ͢PœàX­©<' ÑÊ‚¾áVŠÞQS%9á¤Àœª·¹tüp¦p)ÚP€CˆXXüÅ(Š÷`‹amÓ@™¯Íêó6ó¼cET·l§ 1m~ÅZ½é*™z°”ÀaÄç»~¡›yJû6WÜ|æ„·’Ê^Êš³»j·5"[ƒË°%R<Útƒû³ks8eÖ mq 0 =ý9ŸPG+L¿\0¢J‹ìÙv|‚úö©pÍX{ÎîiÒeqKzéÞ›f®Ô;ÿ””óN¿¿8I` G~ð¼ÐÆ++–.šµ¾#ÒµÁí‘bŽ·D{-§hNŽlïÍ(ðš ÊÆ7æùqç-=šG£cñ°qfïVVK¶2¤Ý0JÚgÁ,Ôiý½??¯r9JɤJ‹ØÚ輡–ìdz,ð¢ÉëÍTûû©üÒîG"ã ç›–aÙÔÿBŒ^NPg-åÒ>˜ õªƒR~p‰‘µE!›Ö¿ß` ;`r÷áÝW¯,'w‚ Ey:nB2%~dñq=¿Ћ!—àv¿ÇZÁ{ šT^ú(.EÙçò‘jÁ ¤Š[Mü†ŽZs—AbeY÷*ˆsÀïäL#¿¶|µ¢ö¾9¡®ôÊ¹ÅøW—9Û«€úw?\B%wÁepô©x8?½Áú0æI×Ëñ8 v.,õu¦WLãY#u|b½¬öë°ú§kL–›2¸‘IÖ¸H)ý½PÏ D1ÇbçR½é¯0Û h»Pºt9ނʶ` ï_†à'‰X#}磲êtÐ:î¹–,Ö—¤jÿ–;§±¼Áº |¾JS{æ­©ÒBê ­¥œèÅh8kòVSšhCÆ”üPI$Õ>f`–A’€€°­ÂkA:6‚êîZÈq‘Ÿœåšu¯VáÌ©leÛwzÝ".×#=ßzãæ¹bpU¡ýÌ;a´úæ kR+œhÜ„/-KÞ’ff↮¾»ÛퟺZtÿˆ:Üš6Zš[_w?úm\³}ð‹µ‡ôÆ&?¦¢Û b“œÅ*Èð²+»ÔqÃõo¿IÏè:“t5ƒhåß²wS…6Ìju:_’AZï-ß@9“îÝçÓbG\eÈçµµ.6f ôÂ]Ìí]Š*GWÁxSË^¾tÉ»à§ÂºÂØg’k77—¿äwmŸÙî`îò\×A7›$Båi¢å¿¼ íLmå\ôŽÚ5Pÿs#ë|évEE`œÉç<¶ÀªeíˆÃ™iºÝ œƒüÓnK¤üÁ½ óUŒe >t ùíÔh^¢s½={ô9gÂ2*±£. ¦?¡T²&Kó—N-B6¢eïc¦­è4ý ñø©½®Ò£l}ijUqÀ_¿E £:›ÂÛc;‡­Š0©EnŽO}9)0±ÐtÄñ³²Æ)˜›q8¼ØÑÉeÄ^ÕȾx¿¬#Û¯À<êá?‘ñq'Úe©zU¨(Òá¹íwÒüýÃm1ÙGa‚ʶËÀ½ˆ„¼Ç®çñ‘Â]¦D·ÝÔÆ¢åKRáÜ¥Œm†KbÀ} )ÀÕ¼[VôE?%3H¦®œïξݷˆµµÚ/k¢u©1^[nÊϺõ#LS°Û#ÌçRü×NÿjÙHäðò'ˆ×~¬SißKx›Ý8nB˜ël_Ñ¿’iöÉznß×J„›Ä‚²º®Nu|ÏçÔ‘åÐ¥àJ¦@vh°$Ç"ô(J§P¹>u§èѳ{Å‘Ñ(Œ¢*ë±³J¢©¸Ž³Ñ>õÅÈø¾Þ÷ÖºQoñh¾ß–Ò,’i¹“ïÖi/tìD HfÁEFœˆµ&¬'¢ŒíÁˆr½ë: €½BßfÄ—‹ ܘ)ò ­ &ïÅãqÃG²Xÿ¦œG)ƒIÅ€¬ÿØPá«q¸Ñ; zABÚ 4ùC§ÀSK ˜ë‹\1ÎP1_ðp|à3 ´ ù7Qm1ªn×)£È·¥ô°ÍÙ?0Æ,¹úú+ •Æ¥¦^0Hks(i ƒ¦=¤Õ^-èóFç@ßÿFjí [ k‰ð7NKµ¸AtªÝA²¼Ï8žL_ÎêJíµ”È$óT‘ݲ³ó­KyÜ^ñ·v©¿`—paLƸN©þ. ëÄ&ÛI /I =àH¦S G0ϸ¿¢Dû^ßµ…Ù)Yw&uÑ,{è—óP…“uÐ[Œ€Q\B©Üf:ÑS—~éAŽßÝš4Ú]€hDÐèä¸ôÓiñõÍN-.Y=t©YÈîxjùöºÁRr®«<:/ T[²³1¼)»¢Ò&§Ÿ’jeÝ5hÞŸk^e€ç;±¡B Óêc¡K(êŠÿß/>ü\{5—qkïT2:#ÚÇcÜoÕQ*­Då µÃ—Á¤ì²aB.4*ÿ€šÖ®Ö>ܬ >A¾•¨<§èUT@aÄì€ id~…Žjö€Ê#`žI ̰'ÛÁ²Y˜‘õ´^Ùdv A2ëTôé tæìg®@šdºNCWh,ñna}æõ7 <Õ¿éÄó7⧈³n*¦L€FZB<=¯)4¾ì<Öl¢¿< è*{LhÇׄeøÃšÄ N?£/¾NG·€*vŸk¨4.Æ$xѪ½8®¬‰›‡ãf3èä©ÂïHžGFóæálËíƒÎsn 1x&ÂÇ[¢Bí¥“ÉƒùaÙýžo¤Gþ’€€¾œâ¬ÃŒÑŠzý©œ P¡¤ãåðþx,XJ.È~p¶ð؆}):•:ÍŸ“S‡g–‚t@DE ¦Ù–0[& •Dóê‚þkDµ{ÛD““ýÛAx(±=:&x`Ô35(>“þT¢^#ÇVöŽÿ¸º'、½Jv%Ò#Aê©ÞHí¢}£Ü1\)áþ:•µÑ ÎBD°~Ý–<» §œ9 ’ñ<tŠ>þ^à÷AŽß NÇußœ~Ä¿ "‰ŒåunrJL_Ε›h+KT2ÒÚè¨w?çí3xl.¨˜+øDk–UÁÓ¿ XζSã¶ [kÎõÏJ a!²Nžþ'Œöüê ®H€¸åÏô‹¿6ƒ¸[/ÆžÎSìÍ`Y3IzÝã)ßµªÅV6¨ÝO¬ÒJ¬ÎØ–³y'õ§kžŒ§-óø‘AÐþö~cMwBñ\ª¯:Âé±þ̯г3û§ÊÛP[V„UÎÏ‹hÖ>Ôµ˜åÎ)­‚jîÅ3›µÒ¨¨ @=÷JöÊ(×¼–w’ê»#HÂÀJ=§[3:qÜü›T)ú°$é TÑÃÄ1è=x’víJÂ(´+·ëØ ª #¹ S±àÍNÅÆ—ƒ±Õø(Ž-k—(5JuÕ»ÛŸ±ÂñóÖ»Yç…€ðoœ¢”ç¯KžºÜ µõ•«âBÈ-vQ]‚ /ç0Â?ǧ9$*Š=¡>Oy;ˆ­Z”¥›¦~d‰ '2³8Ò“×@w¼•NNíè­ìÅsû#ÚÑÁuÄh¼1LÔù}ÔŸÏŒdLä,\ ]QÜÔFî°B¡ ŸøbY€¼L³~ø°ª ÷ò¬_@‚|°8ÅZÉRxd“kw.mŸ pžf-8"\¹* r„&›mnÛí?Êåv)o‹ò÷Žà]÷:Ü£-wGpõ—LÎM8 —ÎT”w;ƒ]ìvÈA¶2˃ ¢yå‹"¸$"Ïvª®FYÖ¯Ó”K=O'ÕX†!ñÆÜ¼«?y‹ö¬¼Ø”$‚µ²KD¤d×Zr½¬~Î}{Ñ~ EÓaê貟ËnôÛFF\ZgèT<¹é”‰Ø~ÚUž ôF’Ýby*;!ű@ï­:á 0Ãyá6“¶áôüT€=ˆÚ6ͦqáéÅ œ ÂÀní ò£Òe íèL×]”'„Vu:Ù?!I°•Wõ.h%ø/y9»Aõ=F,Ô/e¨ê0&-O)™„WÈÊËöÓ"²‡BlŠ!¨¥çc’ÛÑ‹VzûýÒ.3z3XEøwP7ï-l>1Ho“ÆpLñüZb» OÑ×ט¢˜½ÍGW[<¿­L¥á0†»}Ÿm¢mbW ›ÏBb´‚FLÿO¶•Õv’ 8«õiþX|£¤èaºøyæ­ Á΂rè&ãèŒÎ=,u\.û|Ö¥×ó;ñâè›OTùǺe`‘s«^mhTç.?O 9|û’€€Ãë³ãêc2Û–A­¯Ê€9ýó‘p5ã¹ÓøI¹™àí@(ùwU–|–'ð×XÜ[߃©m¿n Tï{Ãúù ýˆI$ó8:¦á|•Z\[ò¨ œíþ(ùÓÍ¡+-Y¾ßië:¹´…G»›Ñ†#o˜Äþû „fîÝ;ïf¹ìG¤.ã¥%@,R‘Ýâ e&Þ=ipÅu0^áWrY  gѶÖ£Oç˜ï¼€ À^îYl$mYÛžfbŠcLbÐScTöô†eÚ%»×Ô¯ š-ÎƒŠ—Š2µ0Ðá|õ ÉNΪÐwâon¡‹öß0Œ;Ô¬ë)‘[ñNA‘Ãâ@‡•x§Ã]NöÏ+°+€O DéÛö“&Q ùÌþAx¨™¤i3ÙÚjùL}“$™ÍÍÑzŸ܆g/ˆ3ƒ.SØŸëwxnÚ mÈñ©û†ÑDÚ‘ïðM’âxú뾟Ÿ@A9­ ù©2âk°‚aVGØ”†Çæ×­RçX0MœŒ ý(WZL‰¹ƒÍ踷b³ fòK±»4°¸Cöqn¢„—ø!µÂ™= ^ ßD߃{×yX•ns´™5~âd®ïVÁÐÅ’’¬€{î"³I2°ÎÏ^ðýÕWŠ~™".Uvï2©ð®TºüV GfvÎkn*”1÷b+¹[À¸¼è_57æ‹pù­ÃúÇkIV†ä* ç‘fÒÊ!©VåëŠü"5ÍĹuÕ@ËU é;"¦-ÕðpR-°Œ²uÓnîîÜòèí¹ä³}ÃoËÕÖÿ}ijcÖ´Ì‹ÇEJózñ»ÞßáÆÃôX—Î_›…ñô £j÷k—îvªŽ^{éÍÆ°uÖÑ`C…˜Êú¸«AhkÔMsÓ,¢Ê‰¾—™U„¶ «Æ×¤˜SpþÑ"Öøt½ƒÐáúÞuÛ¡¤1`Û¾â/]ÄŒËóÝ#jôsä 3•þ¨FB›7:`§náBH_<8%êêï¿ eaIZ6úÙòI$1 ¶\I,0Ú­þ!·a(yùÆübêa2ø aÙ®’ö§/Qï9ö—à7©,kö¾Šñ³Ú2ÿ·?'i»,‰lo<(È•E%fæ³ÿ2ÖûOÖü, %ªk²Œ=)?ƒÖö‰q¼!€^àÚ^x’€€Çóãäêf4¬_{N¡_,corôX[3¢¼ƒÛÍ ñ Õ³,ñÒØ8?3DR!™âE.æJ”7ìfLºO[uüHÉÈd…E™BM&S •Ÿ/[Ë|4ßÖÄì™ ߉ÐCÓ|#6ƒ]ç3N¾D  4Ä?{mûDi<¥Ž—9D[xá¸àû»’æ‘F™{å©¶SõäRqc;¸{.fQЇ¨ AÞmœÙ©p[çOÁgá’{²É«³è€aΈ#uÔû UFÈ„2E•îý0ræbåŸ-Üz+Žã³$o‘zÆòÐùN$ŠÁF^Að*(¢PblUÞXÄŠYîD©8ËÀ< ÌX¬z¿ZÜt®ùnX4“4xŸÃ>zìÔÄè×ê9¸7߮ޟj›wó¡@Et­’+ÙœDÛÅO6º‚¡è¦W\‹ty;šÉ·uÚ9š£ƒó¶oÖúÈÚ|¶hý }÷Ï‚Ã&v2üæ3þ^H9È[†®Óž€Rs/Y3ßšœ®#ÀX&/Í‘_Ö©ÉR¤~5™:XÁ(WJ›‡Ò÷e-&×njԸšC«ß°.uØX™ÏÛfñÃ$þ;ðöWU ÇíbØ?«avP(£Ž·ª•£ºÊÚñ¤øKôuþ×kí*·ÝJ×ý-ÞÌhµFÏJ%ù< ŸSCvõ^ (É;éÛ»>31ké×^.°ó”;J@ì!¤rµ¶›Kà(feÿgpòWÅfçGý°²ÑÀÉ7„UÉ®Õõ3.¯ˆ2ÚÞ‰Ýþ4néÖo„††«Ü?û©½|œ‹õS‡(«|¤ŽÆ xÕ˜èdS«¬]Þ!ÐÆÉSJÄ©ä»ÏE‘fst”nÆsMLÇ–f@ÿ (‡zVwÍç›”’€€¸¾kîºßN ûI©$ºN×É ¦Záw0º5\ÓÜQ…°>eéïNïän¾6Ȭ)QòZm,ŠM£æ;Ås½IP§õÌÉ‚÷8HQ OÐ<¤RÏlˆ>”àÜw¦ßåŠÇ&UbÓÜtš9ÀíQ;* ÇÙ°°L :#§Ç9 \@l"Gøö{@ö©ššL9H4Va°&¨Ä+t˜qxìû%šÎý¢IÈm`{+hÓŽb\ðß_Up܆¬…jŒ ì‡7Ãk¡\ø8 X&Ëæ™gžri?²ñ,äXÉðî)Í÷CJ;Õ°L˜PÀ'¢ìƒZ Žb¨t9É7XkÈê°`IàŸ"™Êz+X‰$»tyʉº®ÈÚ¿ Ï[ލõc—UìÔ [ö*ÍéðoC&NZòÌÑåøVxyÀ²fúøÒõ©G¢¶VÌ'Bø€F>Ò´íã rºØqÚ}†¹ÎÓ÷‹šO6¸™·RÝm·Mè{DœvµZtÓš&'Z‘×òúÓQlŒ hTå9€: 4Ppã‡&åƒòËãŧ]h\ÁŽÿ CÑ=B¶%†½ïùÀPù ¦'²æ1ßûÌ8Îfù1E&“ ©ˆdæÔå¬Q ³Ó™#¸>ëzöEÖ‚ßU§;ã>e _íÃR_&ÒØ»½Éû–qÀÄ2ÁYyÀã4Ô!ðpLj”7’˜èT-äÇY`åŸ\ºM¥Dw«¶i©ýò?ži¯l†VðÚõæ”°iÅXê=Ö¹±£¹ùõk6 ¤°ýï {_gØêO´)1üŸ8ð:­» èÿ aì´äRä˸d7#KÑw§¢¨ŸÛ¦Kb¤¤(Â4Û !¬ÀŒÍ;ˆÓ½O¸±.¾,*¡iÝ“…(/­`3ã ÞŒ1ö\£¶OE˜MR›é[$¿OM:údƒAéÈëùÓ¹õ)í´¨R”@v0"¯¥íž!ºüÐhMRq\wìȤꔂ}µ%¶´›³˜2aí7ðM365-±ÒóV›‚B¿¾OŽh0·Ë‘PÎ] ¸hŽb ³žê“lØSHË*ÈŸ™QíÉ/n·W)ŠñìÄ R*ŽßÄ8{fû­¢H9IZÔ4µm€°J],³ÀOm,icÄ sÏzßD@1•¨³´*G0\p¡‰bañ¹Dð³k“˜³‚µíóCÑ”+±p£¡QR½å*{\Âá¶\fú"R Hu 1¸é=÷2p!µæT¾KÝ"Žò%îð[ïÇ dwü5ŤXT\Ò_‚™÷7¦ýóõ*B¦¹zñÍeöSΦto `(cå³A´lmW9¼.'õ÷)“]/<#1ŠÎ :àê| ó?:”ð¿€eHAGZFåÎxXpE­iÎ Ìfe@L§`G«? Ë›M«ã´ápC˜‡¹ø’Þ^ò½8~Çô캈Ì.®x: ®Ô7—umxaÎ çíLS×DöåÉ­ti„‡ùi¶HK¬)˜“­[ <$?ÙóàÂÿŸ±“`㚤9I†|¶n¹RÂá%Bú<µ{?6Ý,†ÔOê“ۆ—’€€¶ÅX_W1wbµ¿×·µ^sÁgJ¤%Wcà¦{/ADS†é í¬¦Ú„A×ÌÚ‘BëwKÀ.`t`„dm ¹ÃyKÑ\‚èÆnÈx£ËwxJä6ìêy*°|lXAµ¶èÄ\É‘o8±²ˆqs~uZ§õ͉UÀ9µ¦¶,d–S$¯—@;·³yê­3èÁ~•µ±€ç¸êá.’,%ÒM»¯†“˜+L†Q3Òc{¦vì×{Õ÷N…C0,Ø©ƒÄÊX”»9Œ6hç¬LCކÚo‹œKu‡šÂß·ë¸b£ ¡ÉéÍÜ# ±¨®[ªiÿáÛ)ä³¥¼þiìyÝ&;LjÃL»/T\úr)ò¨ûžÑºÂ¡P‘„–-&Jî ¹©áæRJ¿Yçç@íoÓë5ºÞÁ¨7QuHî}ŽŽÃà1ÿÞŠ»ƒ…½l´:á„ýÓÍý˜ùŠÿÊ2üt´ Ü™“ýÖ«`ÆPßìÔÿBzG%$õÒ É7{w÷ΟtœÖ7Á£8ô#œ:E|ßí¨’‰GÅgO¦ ØêíÞ¼ÈÀ〻õñ¾ÁD§mk3Ëvyº£\Œgqe¼ZÌ#è’æw~wReªü‹‰­…1g™U«oDxèÀ¿) ³<#öÖ¢ ŠøŠÞ“~‰X¡­%™8ýÃÛÞ–7ÜP‚üš0I²B[6—õœú¦Wo‹ êsqzaSF?(Øà)¼ÁÔÕÛr?¹qŽ:LÍîÕy‰ŸEþC‡sè«ý~:‹jb6¥«ëÖzXs´6iÔKë’Vü®ïÎÀ¶ç£¾iŸèn¶ë¡;Óf˜; Ò³!X×ÓÍ(ØàNü]2®Å–åÂð8Ë,lðE’ØwÅw"í¥z‘|Ö¾5,2fHú®™ôð!ædþÒ¥e„§þL uõ÷[?º³è„ñ«¤ê·%>ÐåOÞKÀ¯×áüØ!rwHKìÑw•Ž”-SJKå/·ÑkIƒB£hk}ÏÔtEäxÚ5°bŸ¾xò.ß™iÊA¬$ú.®H3šx·›£oj& ”+U뇥҉á¡ý0›#´c˜:»èP/ %PÕžP6Å©0óްaÙáÏ6„Á4<Œ]GT~äña©åÕ¿1"×»ŽðWF»ñGÆ™u¹Ï99’€€é!F’YÿŸ¹½D‰òaԮΦ Huá )k´Ú…G¸g6ÿ7—ˆ=ù9ªóuV=¤çÏÓoòÀ>žµ£ÿTs‘ãô¸²OËÄš!ã—ÂPrî}WP Hm‘ƒò Ë?˜ž ]»¹4n#-©ŒKܸÜF«›@mÄÕ ˜ˆ%H”Ia½@NêåæGÜöˆcïÔŠÐ]LeYɳŸ­N6â$ QSŒ’"w[ܶ$‡ûæ™'6æ›ò²óå\ßûèYµ¦®«¤ù™ ÖmüF¶“Ò²á01ÙI»ÀD(¾MÃÁíµ¤”ýMí-óôpÂpi>;5’¶€Jß-BÉ$q$_øzÀš,½¡û¬x€aGí§_Ü€á?Ò’†á/Ñž¹‡P0hòpJ&ª7äX,’d 9vïAŽd4Ò“;â‹^› Kù¬²Œ¡§SN|Uêñ³ôšÃ‹]¨8¿-+·›h¯êÔ¼‚syĬˆükµS@¶ïœNT•Y6"í40k¦xlò_ö‚Ú•¿4lûÂ0Á™ÿ»Õrd½øþdÚ]n>9ÖR/íÐÀž/xXH…ˆ­ 8e•Bm>wÕ¨ú)ܘe@´€·u óøâf0H³H ]ïº xhí¹("×k3è@àT„ú1ùÅç.Oq2{¶O>JVìUö†÷òŠŽˆ'C& ç“·ÊlÇG3µæ„ˆo?ݶú[Î,^wÝ$ü^¤õâ@Šð+¹l™e=zï•ïÂÙ‹;I™%ev©ü›;P¶íGZÞ’€€Ìã-•åk¹¶\_¦'вë5žHþ¹)"¼}ù˜szS‘^“f(î[:Ú §†Bü>ׯ¤‘'pƒµai™·‡“‡'ÏÆò_Šj…l[§¸"ŽST…×ñw‰¿v|7þŒ(©j L ;ÁåýZ‡9ì6}Ðë@ùÖ²ª}'ñ¾ÊéÀùᯌñ=­<ìó`:ÏœiªÆAï¤o‹FøöýÈâ2« kÇŸRÑM¬ÜÛSGì|¡¶í¸-_øÕ.ížFÓ¶#í½3g:ŠÔ€b¸qû"Ü«[@9Í ía›îJæjd<`²ˆë6òôTáè¯uô?– '€qEaÄLP¦ OA3ê°lIb¼G( ›´.’w»¨„@¯Sf;"~ÛYˆ•ÿT&@ /e5ïP3`ýÄM±GÕøÈ¯mùŒ©L‰&E±ÏÑÐÛ‰᫱#”>õ Pãïô4Ü;å‘3òjK£zŸV‡<¢XDôKØÍ§¥OÑEc†f»?Ÿy1šØÎcy ²” SÓHȧÙ/ ˆKÄ(ÆÌÞr1:ÍÆR«aÙÓQ¢4ªx,£&‚S4U‘ªW­CäžþZ˜A›ÝL&tPÈß6ýK‹ú›PˆLUèx6*ØcÖ b)’3EæüÝW¾E™ιhÜpÔ—;wþTõ]‰„*fý#±Ñ¯RÜ_~oÝVÝ3Îó͸"ž§/òèk:‘Â?ô ›ì”£õ¿ѦKZ©¥ +*·‘od?oò¶ö¹¸’€€´Cë¼ó4¡ç§Öå°ÁF*õ””Û«òEUbÔ°òBE©l&ÙåÚ)LÏ<4܃2aJÄ…ù©’&×µ‚·­µzòczßbn%FÚ©<¡ŠËUÙY@€—> ü?'ù‘ÖHMO]=ãû?sôñdlÈ3×únž+úqê?nµ*/Eƒ×C ¸è‹ðæ©Ð«É§·¬ô”uorj¤²PŽÿÞ^é\fÒiï÷­i{\ì2%»èæ,Ϧ Í‚<¨ß_‡$«68["¹àkèê-EÞå§3;ô©²âÆ-p…ðMï³+eþmŒƒM8[½îŠýl!xåÊŠ‚†§]2€™³põ×±NÀsüBy›vSŠ-.ô‹aÊÏôŽ œÎ){ß½ÜlxÇ=¨‚ÚPô¹~2è¦f]K{ç§,‚xé– d¤‹™‡¤%þ,]H©ß>ò2#š·æ8qg5®6¾Õ膕æwøÏíÑQ¢;|—ç±ìlyBÊþ'¦è˜+ ›Jìx0¹TrS;Áooâ5áW† ²‡d̬.Î!‡bfÿ‹Ý°›ßIK6fÏ$‹÷Ÿ|ÕÆ\’$æ÷† {1Óõ 4Œ§‘±[@UuÃO h•ö—²õØŠühË:bE˜ÁQ)þD«bkLÝ©ìS)ÐøcÒçŽ3úßjŒPÔÑߘ›QŠõ®ÄN ÅØYòѹCÑ¡ó¸hçi± hx\_?æ±KÝ[=9ì÷K³—Ð0Wp'Î LÉü]ÃÃó×£!^¶XÌþÖŽh Ö¯yÛSrçÃ# T¦ xÀŒ7'uûQå@ìš *!¼¦ÿž†I® @€¶£ÞªÄeüft±[ áƒ\v¹s8¯¦„}’^—bøºßRphˆgmIe•ùU6%ÖJıIe<÷´Šð©F¡5Ö²~žÚé{­‡ùg©˜‘ž¼ =0XÌ¢î$ÕMp¹h»S B´ÿm;ì"úd†zù‰µEá«VèôZ[¾² *“xÇKbÌÞŒe=‰Âr(Ù|öN]¾7pUoÐMƒ­l2Ôßç`æÂ‡ä\<5¯õ‘ }^’€€§ETe+†Kœ»…±'ÿP@p¾°)jaKüjº² \™)¼T'£skT.)|ÃÔWomŸÌ†yÝM‡ QJö楃ÚZç^vy44½Æ y<©3ëLÙ`4&ÿÀ‰ ¹7ÇeDcÉËPóHõAù )6.îW¹YŸ £ŸSsGTËdl¸~>{c‹ús0±s¬Hí ëd—¬”òöÀJ ÿ2ã `nƒ–_ŦÿË,Ñ_+2(7Š”R7ºQݶG­‹U6Ÿ‘5x‚¥ê¾÷T ÷ ÊÐ(õ“haÙ€´u™$œ_kÏ6ñ,/ð<Í UÒòóAʼn/0°Aôu ƒ‚!zÝÉ¡ÿ~7r©«“‘ iþ8ÒŠ&eàÿI£ ¦ð ¯X÷§„é`œI²÷!ûAŽ4½­+a©rÇUqQ&ö\æ÷AxÓ]¸È¿bV D~%n¾éŠª¸¼ÔÝ0ëw R&œï@G„!A7ÉÌÒR6÷7^–÷™Ž,ï~Ýoô÷×c¼Š øÈ–`šª›»øŸ#ÂVûÿOþ5òAÜOãžäFz*MiÔOa]çË5bIzAÍ”mL5û8ý½Øš@i4l×OxUS?¥\kz-¦{çå ÉýÝMéÙéW5Nÿ©÷ ãIe„öJ wŠìúµe~ƒýJÛ€!jïØSØÚ³ì(»/?Ú^cÓˆK×¾¶]g…ñÇú´„Ò¿r»º@¬n‚OdÕ:wï¨ñÐL8(Ûî×½HX[X³ïH&/¨|´E¢¥#Ù͇Pþw1~U½çÅÄ‚ÁN^3-±¯ãˆ‹›ð,3 }±WÙü‘±iRè<|óúÝ,o­öÞ·uBñ qÄ´‰ØTYc/ÿ¹:FÞîŠ.Bä¯t.´’v04G·¹¼´ˆÎBÂ-Ír5yî’—ÛL¥T2âv\´ƒÍ÷ZuØMgšh¿¿ÅEŽÌª”¥•*ãiÒ‹ºA¿¢ÁÀ®`"¦ ,…ù®C¸Ÿ§ÜÀ½ä¦ŽIƒÝÆ&ó7ž2?ÖG¸ªŒH)L&\³»OÖ¦^@C&«þ^´ßê^VQ'z*ÉQÜZ¶ Q5ƒ¬2(›9&÷áfþ"wÇ£ø©ª%µÕ¨¼üæ,qRo’€€ÃKu´hŠ_¶ÁûéG" ‚à;m°\íjŠæ Xo–vD-N“<#q~Ø@df ûÉbÇ­ð,O´µÃøÚ9†ÇÜŽƒÂZã6Èb¢j\‰àQÎsV6äüžÝ ë)yªÓ6-¬¼„»‰Âß9ÒòÂÇÂ{GÀV:¢mŸAÔh€J—U@o#ùÉ‘9›äÐОջ-•ãò¬èwÍé[ú ;‚\tèüü ‚ÃàSÏx08 ÖÀ×&aV4šÇ…ZÚ¦ZÁüÛ.»6ùÂUµ¦å?e2¯ŠXE\¦*×Õ–@DaˆD£E¦Å&‡ûÉÝQÆß$L…^®ÝOw2x?5í¾¦)aËηiÕî ’ý/Ž×í?§Í׌ÐV>½L)Gtx“‚£Þ¶œÜâ¨Õ¦(õ]ÝHã­‚b¡«îŽiLS)¯Zºå¦†*&û›I/âótâQeÚQ…­‹ý»*^™A=/ oÂä×û’{@+ëÏBÈ™EÉõP]u‰LJLI€L&pªð iãeŽ1ò˜¥p°F¦¾àŒ™KÅ#C9®½Ü“>é¶ðÑq\JkNý®¶={€ï&¿,ÂLz£9´œ÷…?›ÞàI¨ úTÒàîõZ%läGÏñ‚ôVMtÖp‹6¶a“¶I`úI@ÊQ ¥£¯‘ü×,xˆÝEƒ!2Cx›Pf™a"²-ZyG&ŒqRŠ*»òLðÛ 5“lÏ´°[’œg÷+ˆ¤ŒGL?÷Â~AR”øœe¨‹ p%ÂáTªqWaŠËýfK¸bX¿N¦[ßdŽÞ’ãòa¨8sLÖ%8ºòÀ¨“‚0o.žói‘~­‹O0\6œ-ŽÃÔQð–/÷àYMq/Ú!ðÍL­×Ã’€€Ó»óš9Ðv…¢†µ¸â¸ØiƒBTåI(ï¶ Ž/“lx¿¼+Ë­î­2+‡3àd¦æØx0ãP„pöIí§#,e‘°Æì– ä¡–tL„PsþÕP:ñðgYbÀj P*ÖÒ€@ò  ¬î †wÕëS÷‡Þ–[Q”¡Ÿ‹þ(Й´¿ÈÒÏa©Ù¦ÙfO6Û¨·Œk(•h63¾Üýv¿Ë‡ŠÕ¡Ô8 ]ÇÄÚ<¶¾SÕYö˼¾eåǃ#2˜Ba9‰œÄsd¾:ßzÿá´ººG‰8\©õáÆ!Ï ªFÖ¤Þ}EÎ¥DnʘáÉÇî .ÍUE7ÅŠÔò÷ÔÌi jÔÔæx¬?C䬤®¦åtõ$î®kîâ¡ñüBӇ쌬tߤòÑ÷”{h,åÒ ;(½ð cCg6¸›¸L¢Û‚¼¨Þ_²7™¯óyQÁ/¢7â÷JQ÷áÚþÞ”BŸ^=˜‹æ¬Á¼ Ý5Ë®ÿh!O\…ÛrþÖà赿¯t,PiÙûeî&·¡•í:õu¶³Š-SÂ%FD#rÜ…rèU¡ÍŠ€;ªþñBRWˆjÝÐiPÀýåä´ÌD}‘ì ÈüÈÖ0£”Ô£–?Fö÷C.jøÕOªPÄ~;ÓnNRĺTŒ‹líéjA2;Ï£u¦÷%1ÚÛ¸Ëw’£³.ý|ÃR{dR¥Îv¤ÜŽÀ‰?°KÄéô0½¬NU"¶|a5zÛËIß²#m/è¯ëþO}8‰µ·-•<RXH‘îS—o¢¥èœ†ìô§ Šlú>3IßÚÀ½ü3ß$›6eÅÞúW-sè8¨ìMã’T?ÐçÀÙ[­á¦Û0oÌúxf8púÃNŒŠÿÆûÑ¥·¹¦eßd•‰ ›+|ß”ˆO#f83à0ÔÆÐ¬…O³çºV/d¯ŽÎiÞ‹«#Òâ‰ÿ¥¹^¨v›’_þÅu…ԼʩE4ѶG³Ó™{ã²"¿!Ø[²õò_Êù”ê—‹üÉ3ÍBláXÂ`/xÏT¿:ò‰'Ædj0LÒfe)ûuj”AÂU-Ïá˜{vkÂ3†ße ßž`[(£ûß7#óÕ‚/}Ï–âá–>[›dÁô@CIá—žü¦Œ«†ŒeêÛÅE Ea‡B½’€€ßìšùt…§ûì}°òl05ã3ëîÿ 0?ù ¬ñ)ŸÜ´ W1Õ=Œ”òP (¯X¾RÖ›…í—ÞÙ÷E¹”<`ÿQ97­‘M <8‹)º1z j;­Ë•‰eê°aî‚åÔn[µÂÔ/t™=|kƒf”ɰ|·ÚÔŒÉÕŽÒÍü”"“íyo¸»}§ìe.¼²•¯”;€êð¹ÅûJâàû?÷ÆRµê žMÙ‹BÚc²•Xo äVÿNVÑû,ªŠÑ³X5ϓ۠žÅeè)5¿ŒoGuበ2Þƒ•JÍ·*8ž³Íê·ì8[œÓ5j]—ºjç#JN9;˜H}ßqJv䯩“Âr³ ÁCù¶Ô—{([¸iÓAJ‚ìÀ³Á)Xß—™çZI.´¸EÏzŸ‡ ëI|{ƒø¨•ÿe™-ÒÿnHúKS4€ŽÅô>R1ÿvدôr™¿ðƒ>xi+¢’-a•ã<ð k=Ui[9J¸UV8 –¹ý`­5';[çL¿±lÓãªeMs)O%Äò¡þå-Ú§û ‹ÿ¦¦ €LznÝðvxÕ¡K:¤ü±—ˆòÓOªìÂŽ>&®RºìLÚ&n6˜ÅðŒYÝ•¹ÿ"ˆZº.à”w®¥¢vº¶ÊUÇ ¬Øx¥è±¹öÒB˜“ô’'¹µj¶€QÉêžwŒe=–m†“rÖ¬NC“^Ì´õÔª>:í+,àDx¨oªÚÁÒ›ÎVü~üë67a_Ø*†¬LîáÙÂ2Ë Y#Šñíãk Üü ΑàA‘Ö#øèZA¦u«l&%Ÿ!…á6™/âÊ«çè?ÁqàÞ ¬c„ñ£[y~Gœ†»/2{Àå")ߜµ&ÐDe’nÅ Z¹JU:¡þ2táÔ‰ÜÃÒ¶ªO7Øg 1Šz®Òrືm+¡š8k5`ÍïÙ*QMÎÿœRÑ¢_ØûÚI¶â÷-Ü9¿o()Pº×£ePÛìÓ¯§eƒßÐzø¹­PnÉ;þÚ:nC]=ÂõÚkr@(s ö›¯×?Á¯Ù_)õOwÈò½SÃòºó$ø0÷#l1gæ%á!æÿ\I8ƒÉÂôáÍ&)6“¼I·ô.ìÔ³³`ÍOOo›U1ÝοìòäbÎJm’€€Ìˆ{\ˆáè¿íA£\ §ê­AbÊQØ[¨¡zÞõ>1î4d!nÍèBsðò ëƒOW PþBf6öñ%•QÂh¡'à>H£a®çÿ‡ÛÂ¥ñ@ÿ9Ÿñ½ÄÃ[βg‚2©;É6"ÊRzLÂüûðˆdu7Pª@Ôê×ÏóÄs`4kEÍÈÏ>ŸœåZfŸÂwâex÷N|2AϽ;]poÐi»t¤ Ô³³¡)”Õ /=@GweÊ)U¯Dû»ÙBo¯[rí2ë ÿ<Ý3Ùæ E!üä 3Œš¶TO5øÒj†Øm»/©ãýÜ?Ô,o­"8´r~s¤˜AÄ«ãOÊ1Gm¾=ÕÃK¥ýu»¶¬Vj/¡û õ^ŒÍ^0ÝvA«îÆ`ÊH n<Íq.¦‘€2q U݆e]šQ€iH–îûâÊïCWˆ„L˜_Ú£(;û¼[[^|俾’ÔÊåe'qrA”ÝW- ÜFgþ[î$ý­Š"‘éÅ'Ç}8<¬<ùŠü#k’^›§¶–¤GU Êœ[äÜŠ™_?" ÷™;;n©˜FÁh–7W8óí›áfIõË&›ß~0æiAB>¡«Õþü? Ÿ<þ^ÆðLIÞQÀŽÈj½ÏXwißÜvVõÙø@¾$çÛ®DO'*ßq†O'Ë´)ÁY*`V¤—y{xã|Ç|š‘bM™S UBfù˜Q[8ärÖÚÌvÚŽköúŸ”9h\¼M¦3·˜êb׎ñ^yð;¤Ë½¸4Îj âê˜è÷‰¶fjºßЀ úuz;J5Fy²J³Òêw{Âr-ô±mN»žµƒ½ši 3SÊ.{ÎiÞE–±ÅúÌ^DOeòÂÔ$N´«Üõ5i¯…œCÞ¹º­K.— N -‡fÁ2fÂÏšàió®þBoc¶9-Q®˜¸Z’°ŒA¼ú“‘Mú*#(ÕlŒë9åpšÔ¬Ç/‡µè¬1P’m°ñº`þxIRÜrãB©tºjÑñMŸ& QL oÀ#B‘Ã’˜ ®’$à 2!óÕý6ïÃêÐaÿ+pöÍä¥tvÅà·G\å(ÿÓ¾zÑL>öXZœ×e„jÄPf±¹²P?ê¨ ¹‘’€€È*#W:À€6…ÚrâQ°t!z@ƒ|åÖŠæbpö¦8ÈŠˆ|:£­ý®ö lÝ.óøl›¶ B‚¾Îç›Ûdániá?é€Å?Í ½ablž4ɨ§tó¸1 º^ÈlÞØaV4 6ÝÉ×ùOØÅñœvàïiF)µ—!_‰UŸGÍó jXš„‘#œ²Mj»¦5}²%ÿ+ÕtwÍïº]úxòo¦¹ìwßÄüŠ ^ؘýVTìPš6 +jæµ0µ1 ýÜF*6+±G§¥áJ^!hzªã’î12 ÛÜ5ŒåËĈ)²èš Éaž•sø: dùΧ¼÷îÎŽº e°¥îwÍ¿SÙ|"Éz6C ˆj* Ý•¢¡„G#XD8Wv’4cSJ¥!´¿»+v®é¥üãÓ÷W‚ˆ‚hvsWy'ÓMNèϦ¯2ó'ÝD?9·‰Êç¨YG„Ð'œDÝñl§tC?w .™©ô ª1³Šì >Î#ýÿB!­øz£øÔrG·ÏL|µxéUU­E»£øÇðǽkU¾Äš¾•ì#¤DÄ&]Á›ÍîÝam aÛ:(…ÀÄ€EL¸“–yÄY©µxýÊ[ÝЕ -=´­Y}´Ab»w¤Ãáàq°"jšzÑq`ɸÂcEɾÕˆ¹¶ò(äµ3”G<`Š&Ç"SFùjŹÏËK¢Hac\4¯ pNAîEüÒŒ`ê©'ÈñOĽڟ³š/†ì³G’D$qZ„è¦Çù‘: ¢qº‰þ”«&ŽBëÑ—"‹«BŸVÙæ‚ö´ÜÌ’+$W§A‡ð!î@çýGŽÉû¨okÝ8‘Bf„*‰6é¦,¤ômÍEÃxÁ;ñKÉP‡.­'kÇÀ{…‚ÍüÖrf^e¶u´=îùH©uÓ™¼T|Ó¬çB]Þ’)ôª¯>-!ÈlÌÔµÑwŸߘ ÐûªtŠÉ ³s+¦ÁhDÖüÂúû»j³’€€æ~§‡'ãÙ4*B¹ô‘š Ú‰à‘Îï™<©ôUˆûÝO”Ï,’yC„“$LúAÉž0ÃNS tBMŒˆcþ8å˜1›€»ñÜø…@$£nffØ­Än;ðîjP²¶)Ê׉ÿ†Ã ç§ià %ááX%*F6«y&€ÔÅÐ=þ¸Ú`&ϊ¡-òÈçšR؈ÍÁ?åd\i¨Yõœ´«Ü$ýQ¸Ñ*@(%&Mtßæ<xú’{ËáÚE6Ò'L¤Š XW*©-ä`‹{5„ðÜqûíÄí°Îä¸ñœú®ƒWÛªÐ)3wîù˜läá‰oÂÆ‡î1Øñ­*†¶áÈeV~HÌB{fÛ8‹W„e·$¦0Á††uœF×E†éa,FØtmˆaÝC ×–tôÄZ(¹FÁÆ9Í}¬ŒÊðêδ`^]¸¸b€¸+BùlîÍÛº¯G=,Ç•Y'ÿäãÞR8ÀÜËæ‹ž*¹¯§û†eaP›Z ErSÀס9H¿ŸêD*Õq),j¸>wµäIr &9 ROH̀Ѷàf± ¸ž&yËE|HÎ…dÀÐÿ)†¦ û€„Ö‹„òÑ9 ÁãôË6ÒHJQŒíj‚-éw/F쀪(QË >uË™¿‹~½S†,8ëZBo£<Òïöà‚ÓÍ ÕÈ\4ë@¤û w<0˜àà~R-ʽ’Àq8»†Ò3L¾<øŒ;Ч!g±}Ü$ÜñúTÏ“{Û0”¢{P Í|S&½>‡û74x™{ H=4Ñ"|«gµ•fp¬´øÖ Ttd™ÿõ ŒD%Ï€ šŽ¢Êh`šžbò " ƒ]áÞG²a²Mr'žš¨”Ù!DûE{5¥BË&ƒ¦¹ÇLeíÃ7«‚Þ@Þ¦²Ç¾i¨‰òA³íŒ_ÑÏE~ÒÛÏÃN{šÐOÈ6pIžŒÂ†¶ëäÒŒ¯byL~_„e€éÿrã_ä0P5g¿…õK®Ãèi@ÕzE¡8PL¬¡ô`äëxÚŽ^¿wºœ>‹$Ú@Ù9JûñÜWéɈOQK„çLnÛ^;j÷ܳâÒ/í¤ÇÞ´CôK:uH É/TDÉÑWUšIʅ׬³;ß½¦ó¹l‹äWäˆ{£½ Þå`ɲA3=ñQžÖ»ÿÂc¬]Å}úu`„ÕLOQ뫞D åݰ0˜°¨ý°å1ÝØÎE ûR õçÎ¥) 1%ËÐBäûl*ÕúùŸý±W ßæëN²c+VNAîµá„¿]¡ÖÆü³Ìøƒ©©ˆÂ¬vÔ«#ÂÌ]=?üSÀ௿µ<Ñ\ãÄÀžŒ¨ÿéCÖª›u©muèSõÍ㨃¸OìÈ£Ïäq1XÍ©·CÚü6ç,ùWˆ±ÂŠÞEW¸<‰-R Žº¬Ø}GsÏ-¡¸o~÷ýŒqá´@/ÖóÒÔÚ·‡©2åÛj ‹£÷“’¬~²){Žÿâó˪÷d˜"âÀ¾qÍ°?Ú”m&ÌÏ]Ô n’€€¾·LîùcwÎ$&ñ© ~ÿ‰° 3§Ÿ¿†ÔP·°H‡=aÞHi–UIïsK0*+Á¶§O…áÑ[8L®\ƒ—P)Ùe…Ö0o%•wWK*{°OÀ¥N(ü VÿÈÄ/Œç¬2S“v¸¹¿†(œfœ—±TŽÌo߯chïâ‰`î»úR 0P€["~žn`Mœ~>Œð¢†ààÐ~F?¦p-Ñ.0b¤ü…cn4Tä_iý´BNAf0L'f$D‡È-hË„·Ë~­"8í®™Khø…>ä]/ qW²æai*Ÿ¨Æw§4Ù6Ñ |ñÇ¿ˆäã+¤ð #m¸‘«€ÿ †îqÕ4¦™âà£YÚÔܬ*Œç__©ìüù¦ÝmÚꦊ,>¿ˆT+`öXê¾·ÚJ¨0Œ»¦¯7Ø3Õ}s» $Uz›TŒØ Ÿí¼øÊ”Uƒä#ð3zà K#P¨8S‘¤M.W6 âúC?K¶÷’€€ÊH)¯gÐnÝš¯›ÁG~´y7g£n'o³—´!O¥‡Ÿ{õæJ³oï§s¬ÓË»ãtš¢¿¤îÜ•¿“ž‚Y€þû™PzËG÷ÿïó”rÑJ®aÇRbÝåê–3WÄM– %&HãÁ ©xÀ·ùÜ]¶® sð¸WUvú"t¤F}Д©9ƒWV¹ö$¨sxóoE¡ n¨©®hˆ§güH㞪•”AÉÇnÌ‚,/èB¦èÍôbâ ¡V=$` i»r¿§hñ_b¼UÁ´àɶPYÝŒ^â¸EôìYu¥žDI™¸§éKŒÛ^]á3¯~Çåéh<ë0gî–áž}=kÄ&Çå OÏe]˜àu/Âê#þEÏFL†k¯´^[îʦüg‘q´d¥_× ów3M0_ôàn©ÚÙ#ipWÊ„!ÀŠ6£6"Ç¿iˆŸÌåê.‡úQà¥Ê¸ª*¡8ïzN¬[¹]|õ¬G®زme$¥¿åèlÔa-IµÁÖ:èVNÇJ®Ãe üO6‡û3¯Ýô±\9ª[MVá[ß-tÔ\ òâW×4`€ñ¢ò¥„QM²»³L·½»8D¬@4BõÖ¥Æ{_œRitöí¼ZøHäQÍt\þ­‚U‹¥îÆr,P‡ÏÈ,µ÷.+·_—ÕñÇXä}àðrâ¦Ë"½5^òMvËŸ¤tË@ m(‡Ei4,Lœ—•ÕX¶aå<Á¼æгý"ÁÅýö*L] „ªB}õè%ÔØ¨AvÐT ¡6èbŸé¨dÉ7é† búíè>C­©B[10ÕØßÈÉacf¿ï_¸µxñ9`ù´*¿EÂJ;,˜’%+´Ž.UfúÂO«æz6eôÄ6 ¤úfÛ;Æw¤´aN·ÊñövCL¢­î` ÅØ¿-ËÌÜŽŠw±Â&¡¾L|ñŸ·ÄYj×WÚÅîÞ…N‹2Ø\$¸–¿ @´ô‚ƒÛ©Fß±çÖq©YŸ»¼{$‹íè"e”£O¥xMk\d)¥Ä5ì>AJ±Â OÀŠq¿ºËYÑXÐ.®îÓn4óZ‚+Ó;9Ä6%èNQ7öNúß@p\Š7Y)y¥î+`2¼_\¥”ɲ&S›IÁÎÌ­¼×“’€€Ã#Þœâak!TïSÔ(°ï=µšY.Ú!AuЄÆ8zÀV\5¶‘¬§œœbüvVü±R>°n§wÌcï <(ZñÝiÚi[¸Ü%²†Žl))E>¤DˆÝOœ7YRN 6éÞXËBµ{ßdza&Ñ[$8Ø À܈ïi²¿Åð¹#39ˆš^5Au" ùUþûñÌìuž&šLýÒ=°ÏÔ‡Ús ´ƒ= "XôØÄÊdͰ<ž©³Š&P£ð|ñån^y¸ŒYËâk‹uhBù´!ü/ÌóÑm\{oþŸ´8V°¶/{V !±no/1öÝ]‹å@O ! +n¹œýW䟶šGÍÜþJ6´5F—ÍvH´¤)ŸôÏÊráÅëæ%´¾;¸6B$?yXÖåDe=9WeãÇè²zoOŽÃÓÀÛâl^¬X„Ée_Güx$yºV€FлºÔc$tXÁÛcÒ;±îÇë¢eãµN²X­{®MI³ïøÈѧyi_Òy­–»A#¢*ºêÃû᪠֔L(^v7ç—ï—z­K‚²…áEPÏ›;a)„§R˜žÒ:Ò†te_ šÄôè–ŸOõ\ŠÁå]Ùˆa¦]Àí¹7~„ÉŒ“CäŠv§÷ð3Ð÷À ÐðŽÌnïq61¦“^@a°‰[°[þ}àgÔ 0¾(QÈ2µWÓ½D½¯hf)m®Ñ ŠFúìáa»à‹3/Õ@i)˜B"‚dß>¶Ò¨}ÁF$X"PòCܹõ#í3„åšP3ü‹™âÂ7U‚â½øÚn}Ïù[êWãÐò€Ñ%TПÿ,ðÿf™ÁrNPY^dtº¼¤Ÿ-Dý•"‚ñ9«s›Øn…t!êÝ/ðŠW©ya7k]dUÞQ¢Ç:êùÖ·Úã§yCq~ÉœbSNÆS•Õ¼} ºÙúazÏl}kðm‡*„ú%B"Sû=”!Ãs¯{n3¥Ãï¸ÇIéAžj Cú4¤×…Ê-ÚBñd5¤9ä9‘Öj;¸ ©Ê>bX]à ­Ú\mùV=ñáJOl®-Ƨøn)Lb㼉µ*r¬:,ºã–{>kÏ™x¥žjctþàØðrÉP so»J;-'€ æN#Sµ¥v¶u·‰1GBk/ï.4p´Á0ä6¤)(ƒhÝ­^âÕ¼<—ŒáPg TC»F§Ý•=¯‡½„'ÇRŒåÀìgY%›mê£Ñ2½ÞvY`yt’ìxÈ/v.Û³&3¾»OLX†`=ä¹Q¸Èæ¹ZNTŒ!çHéö»;M`ÇŠü6þ5 (áI!»$H!A¶LY¡Áý¬è³¾:X”(¨Ü8ÜÕ!>I‘yÑðÔ–Ý)Ùm÷ƒ‰tôBO¦ Ày–g ­!ì½(CLò’il6¢Ê×€„h1Õx¯“ßü4­gínªÿùø\HaêýœEMc. ®»Î[¡>q'ÞqÑ–{្]4í à"¾GTyGÕS~%—“P_æe;I†E&³(,0ƒIᥤvbåœÕ‚ ø‰<ÑËK'#º5©…1þ‰J½mígžéZUuRðáq̱Àˆ7ubj«øŒ±s‰ÌéæÉ‹TUÏ¿…5Ñ[ xsÙœ-Þ¦õ û~–OQÆwàV¡3 ìY%´Ë€@]ã™Ã6©2¨L§¡1ìŸ>¯ ÂLŽÔŒ¦5²Ypj×u…ŒTîeö½ɘ(óë‡T_ûM¨× :Ϭ §/^Ì ˜rq æ1ŽR#¹ŸD*†BªØô%çLü¢óÈà»]eòˆ“c¤·“XÇä'-~êV+ûnY 4–?Ú"š“¸w49§©½˜‹ÏJ¸ÁáÌ1/þ…£9z«VĽL'´ÅYbôD)sôÿ|S] i'õ÷¥Yz5ÊCKÙ…ÇJj9%ƒù ¸÷g½¨Îl"!ʼÿ¯X/á@/$K‘ l I41¹#rðO_,:+X^ðJ›¾š§_Ç…€nóo–‘«ËÛN •,‡ðDº(<ä … ¨´œ×Œò:@Ÿ¯‘ÿã~yé¥?¤jPßù–²ÛÎ ´©eY³Ô+Š¢ÅZP¿I =ŸëžçþEjõXñ(¹ü€• ­ C&—|cÒV¬¯ñakbG+˜E™Ùl¨€¥ñ@¼Å4T„~3Ȭ¯‘Áz{¹&X-¬œ\pÓDj+v/ø©ÃÔ¬of@Û])/ɱ.R¨.,öŒÄµ¢øUzF¡3z|…=­ttýÝ£„(1Ùi´Î«Ô¼YîM‚(Vk¾ˆLwù{7ç–‘öñqtnu&ÅÊì)ÒÖ0½ÿ'A±Ú °(e_wûtŽN–.zd-Tö&R10Þôõ¡O㣄˜â(ìÙ Qx|.BɳÈÃí+¤æaA¨ö¹û´«Äº’^ËtfYƒ¯NoßYˆ)ó»ýG•Ñ»ªÞ¿‘Wñ(ßUj'™ñn“>Ü}›{ÒÈûŽù`Hî+fo"±©c‰§’€€Êeç$òÛhú—ÓToð>N÷äŠÝýéÒ0ºŽ‚H|¦YÁbÚÑQwÐilP³¢uïtå~AE ꎼÍT-D€GÆ~l§@‡¬&E¥O†z}Ç\©½ `—Ž EÓvõØ0öH°>æ¶”A*»jü mÖˆQò£ï tùv¼ c÷CŒC‘A^ ÙßaëÐÏFüY¤ D±IìØe“ye¯5Èk/{ÁÝÿP“YLRÏ”>Þ^Ñóåùˆ@^û<¥i…÷@c}¬»þ[Á 0™cXÁ»n!gU>Kët7¸ uÊÊÒ‘É[»šI4Cyn±'.jpG%#ù~d$˜e› ìûb_wW©£Y…6ÄÓÀ¬ê=H^CÐwÂ7û¼àÀJ× ‰n¸÷ï@%<ªéõà:ù>d‚=Í‹2pŠVu ,<;»Ž)‘ö³Ô6µÈy1é¨çûYº.Ž£Ì÷RMº£¶!pmóÌLÓ¦g½dz8¹'IÊo;P’°ÐþÚ7q´ù}?„°Î”ºÎ—Õ¹¾W…4ªÄmMÇAžênQgó·óƒ8¨uÖ">^ (ô<œ· xªô1æbÜåõ ] q2ÖÆy &êÌÏ*S§¡C=\RÄ(ðN³z;|rŽhŽ!ô"Sê‰í2˜Yæ™m¶;€¡éÕèdg˜š7ÞQ'‚ÍÝ=6Ŧ6xZÿ·k@ηxÔÆ‘Y-Ñ=ÖÃ`_°‰îiïô“ ËJåþ9 `ì$æÎ8©ü3^H&Žy¦UÏPXH0… w_Ÿw°EíO´p:‘àNBåÈQÔRóÃËì\†¦éÚq urÆ<T†¬S<%ôÕÚa4<&Þ§¹éÔ%üxõÍåF$Q°l(ðxÊc p8öVP–;”Áò1IÈ@ý×y!q;¤èÍ$<ºo²‡5Sçƒö4O„`‘4é0Á“áf®QÚÀ|Æ„ dð„võª:«¥{@uÆI[p«ˆoåƒh^ŽêùíUC‹B ÒoU*9¾Mç¾—µ(˜—Šå“l§ak‰NHX~„~©Í¡ªàyÌé&O0^8E_z)ÙQî{­­\Q øÃϹ~£·žŽP¼wÕÚ}¦£j·[5w±]ý«æÕ­†4ü{9ß±.·~¡$U°Zë`8dݺÍvæ Ã` ¸CÄ^dþ4GÙÞƒ¡Ð8ôA~XDóEEŽ‹v¹X2‘[öEýø-‡j϶Ùð¹!+¾ÅªtêAo‚õ–jÀr¾éªs;Ú»ÏõÜ{-#É¢]…JmÊ#¬Š(@~~€_úg¾LwKD7¸ŠI‹_úW›OŽè÷“Õ‰òó„÷ËêûLF¸¹/÷+ѽ§f§)žw„íR²,˜"Rçp,T ®[Ó1ÏçæN¾Ä`|ØçáÈqÿÃO Q=½ 6·“h1‹¨%qB\£ DÉÆ {óâTw¡Ï•á«ÕO<™ êª~|$v†C“Øs™`³C"ÂÑ9ø¤}zlÐHvÚ©×UÑåHkh¹èÅr˜u½(äYNrf(n[&Ræ[?ž©mô¾úV "f™)ï^Ü’áTv3Ê-àˆr^}•݆Ùht½CLŠÖÄ hvTƒòç tÕ3}º`]ÓqB k7ç¾o7_Îý¤‹ÓZ©­¯¼Wÿ¹¸¥åE%Èìâj1˜íÂrJÌ”5Á„×ë8Љ0š¹‡kþ×hŸ-ˆÃµ‰p¯ÏÓ%ã>æ‹{óñbŒ§G¤+P†ã:Ž °Fy 6¥Òçñò‹üÂËF½Ï˜å¥àœ·NRòË|ÎîÜ€D,&l}ª2h‰k©äÈ8{˜c#_ ÇI†’Kèñv½çpëHj#¨{Ô³K¯—®þ¤ïå©?üg¹JñAx®ærŽWúÓv掫ó†¬ü…ž£:„ç}(ãXGàüòký9¥-â…{¬*bíbƒ/È!Á ·/¦äëÆ¼3Ÿz[0| ¹%]BáÄhAÆœŸó«¨é–¹^‡½ g!€«cýü=lÌ©kÒÄ-¨ÊrÎïë:Ϙ1”Ç£Œ«Ž£,•%<}•ӕ‹%ôý¼Ð¤ˆ¤ŠJJOùAeâ´·ZÀo5‚þN9´XYÏQÆXòmOb×h©Cê\2’÷GÆ.ta- žå±YÇì6ÄJJãÎÅsÈi2ܾ¬@G«íhÇ‹Âeèå_:5>^ȶ g, ¢Á"i¼º(/–hmäJØ6!Àùt®"¿ÉÿrýE[Ëír§µ¶ S3ÞÑ A-Aù.椉ƒdrE‡…w÷Ñö]a×(‰7•þHW]Üä5±çjˆFŒ5Ì­ÜàÔp†Úv»¶M’ÕTj&Øo¥øõkÀ ‹fd¾ Ž7fô«|e¡Láþ>Ë+¨ ˆ,—­šöᶈ K†jš,ýûÊBôÚè_À§7ZƒO3mÁ}#ÖÏ拃äÂBp®¦ ×0PÃî!(õíQR\¤%‡s= ¬¨Ý цhîööÃÕ…áÜg‘q!²¸žŠ|-FåP¯d…aÒ†j(eS»äŒüo›ÛÈ ’ú‘–òn„uìúZåŽs³fóˆMRxVW®²+æ$1'õK!¦ÍÐŒöJUJ5˜œj)Ógô„Û;dÀeÝôÚŸÊé)ߣ#‘ /|q¬¥ßŠéŒ'9«œFÄßI/_V“ó¬Ó—ý%BŠ ¦!ŽˆuÒóŠ%ÅŠ²ó²©‰‹~¢uÞaõ¡ÔÃ(MI)ÌÕ’!O $½ÔçaFámû;亷Ëçam¤’€€¤¤…y%ŠtnÍ9@FŸBxóh†“íê\<>Ù3ĥЂq",°ÂרP0Œ¿†GÔÅ’ÄTW·ëÂ÷ÀÂÞ¤7t÷Cn,ïÉGÍAfYÖ©!ƶ*óˆ~ Oûí€'š¼€ùêɦæÑpÂÀÙQžU/å“á?Η{RYð†PVÞý³J0 nÒì˜þÚ_õž²×۔졇ÏIóJÊ2'ã…4ÑØÌDŽ1mߎí†@9B.É -ù„ÀÉIE«¢wœ@|¦ ø|èð©ÿÏ)Çå1]ðžVYt}rDˆ,©þG`5¨ƒT= -‹ ™´àu8ýÐÍb6®ÜáÁ®íDuîÚiõ›ãÿ<×…!B0nÊõ­×-0×ßÙ¨ÿôƒ,ȯᵤMÌÍáH¢ô£Êy¶†ù0ò²·ú)\ùf• éš ¶WgÄÓº@}+ƒŸ…ö\&CäÆJ3%Îy™»«BÉY" (¯¾äQGBòÇ]Þ—É­`ÈwÇÀÃõs7"9¥ÒUHéR†è›¾õ—‰Av%œ¥­¹Ïn:S™ùì5aø\·1wáÑ5Ζ=‹·%€¥¦…ID­Ý›Ò‰Šû6>9}7·v㉌ne¤1!*péüûëA$D:×bÙ¨õÃ¥ð¤Ö³P‘àlSHåÉs­@ȳ&âñµt‚)‡Áê–²V³² )¸(ó]ó0FRßR5^މ̶§ÚéÃ÷1cÈÏ¿­[“ ¿YªÒ¿-ë×ΜÛþ÷ ÏÀh¸¨–{RÏãh&-Õ;eJ ½–t6uø¤çeå¼²}B8õYTc+Î>HáºßvT.2ÕX˜þ{LáüðŸ—óå¹8º¥¬ík褆4mR… BJÝ‘niÝŽÒxÞÏ„PXœÒC—ì7 ïøµ#ÈéüÚ4z)-¶U ˜ œßÚÌó¾E—JÂ4‰#‹ÆÆµžæÂÛÆ´³, d=ð|ªÕ© ÉLÆèÝo˜Ø2²ã)0^ô•z¹Xná‹{¡rÕFyKz /K5îªÏ²œ=ß+Meê¨1Eì’€€èeøŽôóO_¥zLJÜÜÔ5§»µ&ìßnQ¡ãiOz9š2Çz(¤Ð·.â,ûk,§)7àÁv•Q~ÈÔêOñI>g£†9ÂU˜ä&ûúÇS¨Zß#gÖsŠè×BÈÒ+]s×-÷ó0•4¤î ëIL ¥É}7 š:mj2`[Á2ND=øø{u±`³\ˆ*ÆjÈ'ÊËÃꃓA´s¯€'"0Ñ|ÆŽÖ̀׉m ÞÆ•#–;õÍþïõ'·omB†c*XePæÆl6Ù£sº•®ÐÓÚ|@Ì–¬2íš­¢Ã¡1ŠÖ9¨W- –[Ás9¹Á‚nš³Üù1ÛšwOu1U åhV”„¨×Zékñ^Z¬Æyºz¡$ºáqíQŸj¨Ù—ûó×?Ÿ5[Ê š”i:بñ-ò‰FñBÄ#LŸ„9qó™`Ž‘Ë]4Ò÷mž¼¯Mn0ülš¡ mýÂ…v<ø}-ZQ®y’кâëËc|•°ÓàoÆ¿ÛÍáø%|¶IôÛöO²Ï ¾¥˜ñpò¼còIØ¡ÔÄr±ûóU‹Xe‘°QÜ:%¯Ô} ð’ÀÈü·)-ðVGjµ鲋¬ßKb&2BƬ^\K©0è~E¬ÎcÔ©Yqã혋-¸¶û!ôÿ¾ß_Ï‚‚gU í ,øé¹°ä0B/Ïÿd­ôñ)EEÑžÃtá¹Ò/m©O é%úžbîÔ¼NBÐåiuÿ ï7qý „×ݳ!Gß.•LW3O 60§‘ÊòK<£~'­êŽéqüÞ¦´Cd§@R s‘6_Ãòçç¨bòÕa†á‘ÔzÃe2øi*žj.ªµX'eYϸy‡—ô¦’őƔ:ߤ[¿OÛOž”gèr¹fl`ónÜ;?oaà¦{&™SzM‡¤"„=ÛæG(¤/ª—©ùn}§?šÁˆÞ£†¸§÷ñèp,¿É©½öí‚d˜xÏ™­˜Å+ë-/ó^¹ôòü ‹+N3&‹üL¾Ô¯gÎ&£%û&Î×;ÎøåePT‹S¢(k`±nãê)Kf,ÁòÀ!ÚÑ_YKyÏ–$nj§aDn€Vÿ}בµyÑY—ÄèdÞ¸;ÏÐáßFŠž{d·Á—lqxl+¸Æ¯$óVsZ„ý~Da¶?fï )tî1œÉãÆTÉo¦=ß•sÍ,+×j€{Äò^‹b°…©Úža¼°i§ÉwŠÂs ›”Uîùž àÓPq/’p]ó.e콎¾§-ú~0'TÇÊÐüÞ"nA` µ¿4†9},ª,Ì Ô ¯š¹ î—‡Œ˜€¥I‘çMÚ0¹ED“VÊpÕkÃMØÕ÷Ôî±ÐC@_7<÷7œú³†NÈgtÉM¡GÙØiŒ_U4`ŠO <5§c?È.h}§z,ÓÙ º¢Û\U›m£‰¦ ä4BÖ,ïÝU¶®ÕÁt¯²Ésmþg—ç½Ë„èK›1ײ“! Šnßß8}sÃQ#=|cù ¢|ƒÝ·f™öºc"úÁ»zó˜Cר@>§àC _ð0¦a«D4 »f~,±Í”Âëj è·H‹oÚƒô 캢Fúüß6'xm†$ AÞ…-ÚÌ¥—yÖïÃc.­ª0{“i××厶þŒÔíËò2u-g¬Š©¶»dµl½`#@ÏÈ¥­³`ȇ<µœÐ¡íPå>­qù\m%¼Ïy#‡¸TÐÀ+W\Á–í¼³{¼°jGÁ¿mfº’ö 1Û ÂÆKå ß"å›0(|»×>Ÿ§ó–àK†Ù™XEþQ³"0T‰ \{Œ\UÙh´Ó€1bHÿhÜã’€€ÕŒ) ‡ÎBPÿ–† icÕŽö9Z‘>™b7óN·ÝUUïë4öâfnòn†Ã‘!6TV±{/¨9‚•ñ™wð«pæ1Urj!5µþE‘Ú7PscñPS82)J(AšÀÆ&½é¿T~§˜WO­/Ö•ž²š) žXðÈY÷¥g!•éϱÁÙeçFôJ(Š_3P©qm:”EºotÅÿ›·›Å[•qt»tp˜œ¹ 8S˜yõæPIð!B¾rõ+¼…l^ gsÌ5¼í‘p oYU m‚úDŒÄ±Î Z<‰ìðinahp'mî÷@NR[zÙ(ZÿL>‰ïâY´µžöHÀ…ËÇßè G„̹ë²þ¡ô„š®–R0*ÊS7KkƒÈBÉ”e³¡°½óÖ­ìLîM¸ƒ†gcÏ„¿ ã)I‰-s“±fk— YJõˆbWÚ‰…¤™ŽwT(ù(›6r/¯ûRì¥ BÊéd@·@ë—:ŒÌ ½m qéü-BðéûXvZ’€€¡b¶¶ñ:~în²z~1«Ë°C‚C‘“¥ Ç^z›WÛØó‹CTqÉbà +Ó´2kkuìà Ÿý²µb¶8“8vC JV™Ÿž Sé‘­­ê¥3ëÚŒaªñ@ "3W¸sG>Ð0ÿh n#‡Yl’rŸ;x*vC)¼µaóWFLk2¯`Ÿ ²‹¡LÐÎÛ½8Ÿ@Ê»I‘©ªY(¨äk$ÓXiÏ““«É<Æ®°7¦O$½;н’ܹxŸ.Âúä÷¿N½izfFTñ3Ça‚n. ý½ç T7€kSÏwé;‚TÜ JŒlËcf¡Tzs2ÀDö¨mtÞ|ž@¬ÄB6‹bUlY4,âÔf-±cIÜï å‚°jM³:¥í›B¹J©8ß!.…Pgö¨œîu“K\Š Ò‹rÄpQJPßÚ²4ãöGý-d;ê€2GΆÃgjÓíRÂþg(5UŠU+¤Fµ$¹‘ȶ«%ß[[‡úÝÑÕ>„lg\UêG4Û“²NÀŒxz]iÙ:䨚W’§Y]Û¦*rS1FÐ9]TÁˆ–RnÜpäy_›K6(ÍÊ.¼ áÅÂÏÅ3ËKZpà_¥«·ê8ƒ”6.È$2WL,P1èö”¿“ÌDñ('ì59Ñ AZ„ì`ÑQˆì™˜×¾ß/›Es/= @SÏÏ¿7õ ûî÷öþI Žúi² X\ÊQÖÿN5lÚ.aceyaÖ]WnD‘Î}9Û¼6àxôµ5ýup‹ñ0®l¸×û× àû2t©q Ɔþ'>ùðÛ—©0pÇÅ2ñÏp7_»öCtà*Ô€+fþ«w@7I@i>¤ËfR•Ó÷·4q0´• ɹXSÀs·áÞçjÈ·85ª& yo6~aápûLôc¤ZN€M"NTu§>À©> È{liÚé5#O"gx=G"ël Ðcöæ¥F½îDv0¢õ$£ æQ÷ï¡wCx´G8QÔ1¹ÀK_½øh*r“Ÿ@±¡ú¹Z•NwnÚ½Ö {CâÞ~¶úÐO²‹13'"Ü ÖGÅRóšÙ§ ck!Ÿ_@ÙÜ@|Ê}˜œ/ÁC`°Æ™ô±tòͺ؜Xù‹j:´‡ð  …Ž„” ÜÚ’€€Í]"~çgÉH“SüúÉá“Îè^õÞ¼2¯pŠ7¡*±V2ùVãëPÉEëáO¹pÔ^-` ðGæùh `é‹ïI7mÜ8ïh¯‰Y¢DçFàOŠdmo4yÿ2ê±z„LF¾0Ïlë‘¡e2¨*ˆ|"l‰,Å+òoëãËmçóH‡Fh€ciÎÚYjxbûk´Ód’ë5xŽÉ÷S¢`  ˆ+¹QÐÞC5‘¸ó‘±lpýuÊ,×þ€a9 }“JɉR<·™b¤ìÕ¦8m„µ–PW¼¨²ö STèBÍptŒññ·ú¿Øwüð2³]<MàB’R+iáôµl¥ÙŠŒN*TÆ+E¢v9s.òxÙc5U*öt“ÔóÝ– ´%Âc,Zä”Ê?ÔKQÿ·0?zXSv/j*Ÿd²?ÃÉ”l6Ó¦HòÀë>¾>w–}Vëk/ç¹Ñ…ØM[|Kž>àät·Ž~³VM~mÄbtsƒVÏé‹j9ÝýÄù±’€€¹Ì)_µ7TkœëÉ8»ÇpŠ4Ðb  ‘ΫºÌ(¹t¶ú ¬µn.#†ÔMØv'6%Älr›RYÙwÌÒ+2qX©®wKs“ÆGîX„2$õ} Ùìöͬ¸Æ QÄa£~¾O=,ë’ï(#¨S#®œÆü ²ûÍ€Ë;–W4X§žzô߆Y¨NˆˆuåHÝ%3C&H†)ãþŒZs`]AÂ]f×b|ôÊ«UÄœ‚Žv\Òÿ‘ûÛÐÎ,ìÚ ò¤Ç†‡påÏ?˜5ÝGº+ŸRG/ÎР߇c ‰rEÿA…ŠÇf—´êhˆ<ß2÷´ZêäÛƒdð2%v“Œ^Û;¤¦®©=û]k±ßä¥_ÇÑ5º^{ž¸ùÑA3é…꽺:pí…mý(ê¸:ðÜØ5Ô t¦Úà µÑAmL%ªæu8.O7bÅÛÜÀ —£:Nù0[xâÇY×r+-'aÔá&ž»žsû‚<ŒW¨h·ˆËð½h)%\"‘a,Ÿ¡Às¹PC&F}Sá² €2ëš½‘Ì>:VŸWvv<ûnÔf¼$LˆM-¶Û”oÿ¥Ñ“»†~³•–ÍNñqt±kBe¯²Tñ§Ì”É–;.3ü‹%¾÷·öw„º, ß¼.^µ9½y³¡Øàa¤^ ÛѲE´×¥NÜc}îðJá~tmFðF| ñv5òóÆ¥ˆ2}ékƒaAcúÍ2ýšDr–,ÕQP<æH_Ö+I]•ăÖ{uêrlñ¾Þ%õLǪ½‰¾uF¶añ^·ÞY¶Â Áá <«…ø8®~ÔÙàs6.dnH@0?Ø`íóKpWÌÿ,!iqÜÀá1I÷ Iªã®ª_͆d"0ue)sÌJ)h÷Õ…ªÓoÑ‹ÈËNdÚ´7nãîPÖ–»Ž/lÍe¥‹¨P³5b2kNµ¶ÜÑÿyvgš f§Þ„~ª Ô=7ë‡%ýÄpòP¢¹R¹e¾¼¢ÝuIU>¨í9{pdjÕMwСů)87;êÎ\2bÇBV«oÄãËf䓘%‰“]:|³b)æÛZ–bCfŠÅ¹ÚÒ §©1dsë3wšÚžüþu±ó…Çó©Ën1§‘ŽŠ­¤i/½ùÝã/ÍJ}àÎF=á’€€ÐMdvwË!\› Ì“0 žà¶àËï«è³‹hÈQ…øBG †|t|ôøð‘êb6üK'ÆTl¹ñó³í-·©«;ò…sN“©Ç ‚ÉÞ?úP§IVI}â†Ú ø.ïèçà#ØY^ËÓ·ýýÄ©/d–tؽØ(UÎÄ”ÀÕ­DÐ÷6Ol‘$OƵ{ìã–õïÁ°ºë Ÿ™†Ôs„Ô$Ø® Âq[Ë:ü#ŸŠel<®m^~ƒŒ‡'±Þƺ#ö–eÜ›ûÖ é‰Mº¼°/:IH þàK_ j½¶&¤LqZB衇jí9Â÷ñK&Y fkÎÿ{ï4?òí½I~ýù ª\yå`7ÌŽ·Šýþ1¶­†ZQR•´Ï¿“~9¨°¦Ã߆IFR“ ]¬ ¹&m½Ü˜Hó„×?â´ÐiàÓ¦¥C“€¶åéןß`æX¨t°Û˜'È%ÿJ0ó¿æß±‘SŠš ú¤IZºàé_ªº]=S“"ˆˆ)H×,”‚‹6‚iÛ)kÿ»ô5ú×…/­#H£Y+¸ä| CÈÐ ‰RwÜ3&öã”Px‘ªÒÜÅ®•Ïþ§…ö«šsÁ±8G\ÍSEÙÓ@á±rÙä;ÇE<ˆ/fJ“ßï@J=EaAû·±êîòÑàåï€6ó*c5ÓŒu†è~"0Ë“»ÆI”Ï‘ô%hŽ+üQ–¦âËÅ‘ËI¼ý6—‰B`ÛÂ:²«ÿ9ÜA~ˆ/æ®ö }ŽÞÖüÜúáRx{Xêav²·/&…¥“””_à.RU[Nu·°3òYyd&\mñEÓØœrrªñXsåPÉ¿ÎDVŽ2ÞbâóQ»c§ç/úÇßBXüQì«X“gþrØL]ŽÓ©ûB uK¢}GŠ1_®åÞìí¾Ó/ò–¯mµú# 5÷‚Wlެ“ój‘)§`rmIÊ¥ýXúTZŠ%5Ú²ù¸–© sðË.P*ŽƒŸ¬üZ"¨ç$|`5øN ì“£wíÝæ[õIŽOrÚzŠ\A[ÒÜý¦Öâë(f’%«°> ‚ÿ¯¡0öü$dAPþìûrõù™s_²†QùýŸv!áa@C{éAgÝÎ{Í6{bÃt¡“µ†ãÇ™ìz$ƒ@Aº’€€°ÃÅÉðp.%2[ünÁšzÁ×ÊõC6ãDKnš¥ÅÙ´úC&lñê÷ñ\{ì†wgXÒbØ&± 5ÔZ|yõÔý÷ >Ъ §&ß Êw&jn6Û •u#<âC…ÚGrìáFRÇ •ˆ{[ì½ϘÁ gÎÏb¸ÃÔ.¥hdûÇÏB%®Ä^½”«n¦–eVŠé$í+Z*ÈŠä=ß±kÊW ª IâÈ ”~WlZ×—/ëcÙ‹ÜtÉR§ÃÕ”Q(½IÎŒüF~l6v'Î<+€ÌqN7ü²Ž*¦ãÍ! ʘãÒËw[ÅìÙû×1˜Cçh``°ööõ1‚ygìbÑ|ÅHXþî ÉÏF”RXAÑS½T³­|*Z¤çk„3ï+]ÁüˆÃªŒÌÌ«sä;JNV•ÓlùYÀ@hR6dÏÀ†‘"·¨]i™ÿáôèÌg–ç‰*ªhWLÂérßÖWêÄÁø³K=äþ×Äéð7'úHbL¦4k@öañÚwÞ…K˃¥8ÊùïŒã/|G=½púw‰7¼ 8*´? Ç{HýÈSý÷B½ŠñÊ~$܉ùM ¼÷~û>áöfJ sYÂÀüÁ¥ªºÊ%û„ÿäç´fÞp‹E7lUšËÀѵx¼…0:KÔ‹»aèÓ[}™Z¾ç0@è²t ïìÜ?Jaäºý·BÎ~Ç(*ŠýœÛ%λLɇ†k¬0/øÀçàì+Ý,"yafBFÿ_>\ÀâÝóSԄɨ귫ýeÒeúÛ¶F'_!(úo¤:¸‹ 3˜ÙT)º„ÒCû¯Â[ìÁò{Xj_éÊsâ,_¬ŒàOíd4ž7¶—ŸUgýK™e¬—¨Ût>E™¼&üFÁ‹{ÿ¤Nºle[éê×åw û¤pùê›9èÐÏŽúlZ/„þtK"âÆ5OÞg îEa–³Qçd²ª ]‘Z©ZË«YØãh·)´¶Å’¯©×òs“F±ìÐበQ#”‡ÀÚ‡Ì=×¤š¨ ’âè¥mŸdìCaQ¨XRf5–çäwýÎ\ãwß±Ÿ­Vœ÷+†!·•|ý”3 ] Ô Üsv{lq7¤5;Dß÷„‰‡©ê{¤bu;%> `Íi/rÞçÇn·(þ ’€€»îÁí²÷{¢»Ô"zrðý~ž‘³eòjwd!Q/‘?nõ:ÄðV‡‹jV Õ¤BÁ¾VEk[ïRn=Lå[­aðFáu4Éú¬ö¹kÄ;Éfä(JeãüN„=Òßòd‡˜DÔo!&Ò( #j¾Sr6PàÖtTöÄÃJå{©€ï&v‘heŽyø;]§ÏDcž6Ì5/° EH~ä   A7SrXÊÕúálT.ïièG9?yP>i?ßPù›Ã˪üøxvsâ¹hì«‹§½çœØÀL©=e-‹ÕÆœödC„ɨ¦~Ä£ÌNÌP+ RŠÚ‚¶üË_Î×ë\Þ“¡J~H ­€¼^`1¾ÎòÝÌ#´KGú¦:r1g¦“x/÷»mÐYgG™c…˜„çä‹¶äÕ È]kó¢™@ãñÞÚ¾U¦ÏŠ¢| äv¹C¤ç2÷ûŸ gú ¾†!Aߌc%ÁDMˆz]WQ  X]È¢ùè>¿ÑíK<[GÝ#ø 6ŒE?è]dÜ™Á¹’(.––^Ƙá+Á&³Ø"&%ÙÞLc)l'vÏU Ã0?s3 ÖxJ°JñÛ+ï½¶?eCº#Æàºy‰ª¹½ª/BŠÍ™z·mº÷l\7­A¦½Øö­7 Ÿ¹}8 J™ã§ì&q‹áïgþ<·›Úñì DîϹ õbºwÚYßò¼¬P­Ì­Á+xíªü]¼×]à;ÈSU':È/à-ÛX¥ßÔu¬²Âpš”DçSM/Ó«{Q,Þœäÿòèå5C_eYQ8@3ïä†ÕÑúôû€;v=ÓT¼³68[\¿ËÖš?¦EIá—¤ðp~½;½9½3îÐo¢|&µ6:Ñ×ÚG~[|¯Ð7Ç`:Ò©íäzÁ ø1=[‡c€=ÞÈC§˜ÄÏWzŒÉÎ|ëf%“Lßá;DÖ=ŽÁ‹Ã6S¿Krì9ɾjJ쇉s¼ÃG96¶Oø³/À_Èg†Í­˜à´ øÉ˜Pw¿ôÏr ño}S#Ãs{w`Á|!蟌D¿‰ë¤•u…r;\¾5Ƴ¾h‹Ôásâ÷2ý¥Û ½³st!ÊuIskx‡\S­ O æîQ/e‡€¯P‰Â`VëÔ’€€¦ë¿G­û&Í`àn·±®á®O£9ƒ¨îѵ²÷Já‚æí_¾²vPÐIXÓÉÿ 5Ì ð/ã}.~µ¶7ÃÄÍoYa£ëÀ§ÐiY w†B+†b!®püiöÀfLè%’kÊoaé'Ö¥,•Í}¿‹ìÖI) xëòñ³†÷nÔ.vðoÉHs6Áa92a%ŒfäS>Yëýu9é9ëZKó+N®á{®Ý28âE=;“§ºÓsÈR0½òªÛGû¥€…ÿȶ6I]»Öø‚Œñ!#;y»³íˆ“dñ¸[¼qªÚŠ>ìX‚É 3Öÿ2 Žo)Åg”ûG…N‹TðV€Iˆ/Dh°µ˜åd@ª¾ úó„ìI²ÊœEhl€mA«õyù%Ò¿ <:?W²ÐW³‡Ô+Üò2ÿxE«¦ŽW;0O*©N¤w;6¿ÃZì9†Úª\ضþ<Ð ‡±¾SHˆóñaK”ÈUÉ øÜ´R#×_ÀÆFFja‡5˜¦¥¼$/;,YH¯Ìk©Œ!Ýɯg3TÊ- p+ËA¡dxÿ`ªrö)¯žmä™~G¼å‰q‹©´ìFÒà²Å‚j|eFY2k‰BF“–w„ l"ëJ>vŽç+Þ[±´#íNåò}Sh‡uäÕ‰³ZR^ íu¿Ü˜p=8Z>`Ö¨’o¶Mj6G¦¤¹Ò;Þç\þ씕N‰Õ°dÉõ¸° c’þìe˜ñ¹’¹Jô»ðh0ÕÒÇÿ4Þýñ+r >r$Žž ™"º÷—Óã›[ kMÔØ¢5¡GâL”[²ÙÕG Å+²áIÇjÉ œ™eHÕ€SjªYá`›*«mq€ä‚{k0Œ‚k+M2ÖËër°tv^ØÓQ¢SïhpñPuI“böL FJ‡rù`‘ô o3‹,{µaÏÏ­I#Y±Ü Ê+‚z×g·Y+&YJ6âu%ä´G: @BO‰’Iæ¯k½â{ÿÌ7; ŽFó|diÀ Ú$gšZٻ࡙L~sð,² ù:Ÿ2ë~¦Ô.8’ ²Ö¬‘tý8vÞK±Á ¬è‡áÕ´àpB£ Ðò¹«ÿñ°›ØÕô½–»Cæ`f6n†)Ü\€çø°iotVh˜Li, èþ±<ÓY¯D/£ Å®n­xˆ»¹“"p B:•òÏhO–Æ-á¿Û¢nÉšHC+´Ä´n†è­Ÿ}hê‚uȽ"[‘+­gÆ|wÕ£m †H9æÌÒ ¸ÒJçPoÃ^CZ¹½­Ù9ïiˆß4ª ÷×ϼoi Dí½Cc™Í˜­>Ö0 5¡»i‰WF{/˜ŸéKvŽ9ß"´²!7ÆÄÿ`ÍT?öò|Ñ¢h·jr^T#BXn½Tù°ÁÀ03tQ©û©IÝ‚Ÿ§Â]$S ÉŒ£óí¥v lcmúþHEª±xf÷”<&¬›±ƒð‘Lubþ¨š#Õ`ËÈÐSPS°<³=Fzgð>éÙ¾ùÊJ°¢ÂI—_¦vâ{2Ã=ºœ0ñEØ|`[Xò!*Ëv ¹ô&ŒÛrÐ-m’€€Ì¤lB+Ír%S°°…¯ì®t}nêU?5¿ÞÞÍÓ5ÜäÝÎ7 cAbM~8ј‡²?ŽœÈ&w¬ÜÍmH£q.êä)Œ$PlysE_waÎ&üõhFLÐàû°f&K(¯hÅ<‘ ã€LCÆZ'‹é4I™&ÂÄÀò=«»A#×eÖã…‰, T>þÜ€œÛQRp^©[k$6†3¦Þñêðœ~@k›G`QýÎ(„¬k¼ˆB@øK´H¦ÑI=‹;ì2ÒQbI%]œrr¨–2ú0R…ÐÔûÂ锦-A=^¹±rÃv5kà=ºšøÇ3°1-Âyw¹ëy w œaŠFàlÏn›÷±õZD¬Ý{£8×ø°Ä#)TÛSíŸR¶ùŠ–°SnNE!ÅV 74Šîݵ<Ý®ö}•¦Sœ¤Kä¬!I/'‹pôùª£(vâc¾T_xº±œ'~VÁZÞ¸÷Öò]‘#FÀCçÊ ¸5ó³ ËÎ8&!üªtÊ”¶…ôýFžg9¿·_ǹu¿Bê7SÕʼ£q&1§3õæ.ä.¡"!Ÿe:‰Ë.ê]²ßDÓò}Rƒ¬Ä“˜7÷N1[®|ÞÛ¦AâSXbûü¬GÏJ6ORñX¶1‰ ÅAm,Ó­X{Qp‰ƒW§Ñ5‚ákôJ_åîç=ÌOQ x­4zA£gc4NX!·l’Y•…ðP!ã|*S!3> ‘Î~°‘ÀäC+ÆÛ%³Íyà óJäÇo¾—¿A/YyNbf5(±ýœ<ÐPinUe|.àœƒÃ¦ªkðñ½VU<|ˆò¿ÅÂî*è¯!áú^©ßdØ[F|©‹Ú\2IˆýñJCcH´{=&Z'Ä/Npø€~Gíç0®TªÉ[£P0¥þ©Lò• d3+V¦Å“ÖŽÕÍŽØU‘¸/:Ì3Áaö“Q¼‰äE®°Ñâ1¦ZòtÙ'4 ðÆ}Çé8 ÷suÛ4—bô 9*ŽÙNð*Zè£ÒåÌ 0q‰4+£‚» y{‰m¦( “A;0/ ¢ÄE[5E\JÁÙ>$ÝrŠŸg´Ëk-"ÕØ@ÖI ‹ýÎõ¤ ‚Šm«‰grÛ/DÖ,éOÜÀl(&¾xêÜÄy(rûe¯fñ¹ÛÂ’€€°5?2ƒvðh5 ðжL$8ÔlÞÕ\ã築 ¢T¨´$€Ï‡ ‹¾Än*¾P¾L첞 3:ÀŸòhkLLJÀ`âWwZø-7Mºô(€U±çlìkC2aö{ý¢ öVvñ ÇhËlLj`«(v•t¥:ë×Mˆî&6 4í ¤BDu¤ýÞ“Ìwˆú…!Ü,y@ê*ðb'˜z-7Ë¢àÕõgqzÊ£Ä9—ú9UlïeƒDo––Èé©“¥A%¼AµÁ²ºŽ j¢VX90 îÔ©^XG1)}öaû¤ýõÁÈþ †V†· Ë&K"úŒöô Y4»L´Ïñ¦?šL«&Wã@ï&iêäK˜ZÏ ýÃUúšÛÆiÌ5w”‡D<ÑÛñõJ-&©yÄÔY]:¢{|LÅ8ÑtŒjqâlà÷š©GABë2<#¦Q)ª! T:"SÝìOn+Ž cWïóGѳvzË7•Ð_cÙ>jíÕ\GnA9=Æb ‰ÿž‡µÊdÛu5·Šìæ}:Ö{™š:våÊŸMGû`ë7hG¸Oë½:&-Ü]< ýÓ‹ÍDyöy¡0+F$/r?<£ym*q5ÔCÈÔƒ¯’X8ºžA.ÍË™"|î*èÁâ*ý–¥ „—€QEÊÕm2­Hé.k·5GsKÊX‰Nú³†|Ä1gØn@Sþ¥ äÔp?oT+ç’Dp`ù3è’€€à(ÛCk#Ž“bÛA§`ýbÇâf êÿ¨Æ€ß'u“ óºÏ¸Dnt×ò°èüÀ«˜Adúë” ÜìÙhOjÊïÔ™|9º›xü«?yÕÞ56 ƒ­$©D]H=Œ.(S?Ç wŸXðaªNvë¦[E¬¾e¶ø¨EHVŸxf˜pÙ0عÙê4sÃ’2@D`ÒX`ÏèÝvœ ÷±‘™Õ9H— ÊoRÑðWs+¼Òó¾d; ü¹ÛýûO»lOA&óÆ®û¾in&á[ÒkÜ·X¬Ç,mkwFÉ3fäw^ó È‘¤$ágy2‘)ƒÂ€IÄn IÒbCivuƒä|Ìntª 4·…s¾Ð ‚Í­ŠÈ!48H½»1Êb ¼†úˆX0 @hU ¼QWé¸EìGâÌ¿e®˜ ÈUµJP$+FÁ/ŒHñ\ü€ÇHå~߯Å]~ô$t¥€ëÉÍð6?ºß¶àƒ-€HÙÆr6Q>ú5ËœPRéEv]Æèz—Šÿ¿¡ü´§ˆ eNÅNˆ¯¾]"˜oäÚ9ËúÕlˆSGRvgÖÌj¼ïΞè?~‚Ô»F¦WFùéu<çÊ/eQZ¢i×Ëš…ñ¤ùÔy*‚ùÍAˆÖ¦æÕÓ°£peÎ¥#—)ô³1 ÅQÓÚ ¡Ä ”K=þÆ‹L²—*ݘÿèÐ#Ø›KVxD÷Y-.WDÐ]«ë~oö1ýPÐüD£Ø‰%§™·ï\IOY+îƒ4ƾ»ü¸?¤!ÇÄ¥3+Scneó8‡D»²L«ÞÑHÍ®I y¨È`ñì»]÷†ö³êi ´G£û„ P‡in×vI²¡¶…³³!ò0jÅí¨QÍM¥]Ï™Á²&³hOµi¼Ö#¤§EÛx–šÒ&c½âJgY,å.Áˆýöm(&™4'v"êâ%¡q='âB*<¦–vŸ)æ=[pé4¸GÚýg69ãü #l§–Ø^Rå@䊟ʻãóÍ;~30þóTñŽgUôzç^?R”2IçYµi†:7VàÒà¼7úS«K’©ØO®oªmwŠ[ëÝ_oärýqv"=‡Ï±)  \Ýï@¡s#.ëuñ5^Š ÛÓ_œ{”ÆØçq“Ȧ’€€Ê+ÎÛytv´q!àªÏ/-õ?|v»Uæƒ,Áõæß‡>dZº±³q[ÙÁ§Ãvîlüh^ì`ûRtWˆ…þ°å’Zzï0hLÍcæÄ'VQžD á7·Ú¹óŠæü¬B#ý(hôB-*îãDRÄ{S¾pBìÝe郙(„¶hÌüJhÐT1¾¶fqBœ©Ø½Ä%?¿2ãµf;…°“–?³,/§!'Ùûò&‘ÃDδ0¤áî±(‡«Æ€É4š~(+*3•ƒ™£©q„ÁY“p0Ó©#ܬŠTÁ5€!Ÿ¡Aƒð‚mŽWè’ìuÊB÷ «[…søŽ¯Š:çó®Ý8ó dœK†H‡™zÈ:RûNÌO<xuk-”ÏÈ v¦­7“_)À¯&€ê¼÷s‹ýènkŽ{—) ‘HŒÌÏrVZ©Å‚¯Šk«¬˜/ÁN"äGA`’£5·‰©U]Ökm‹¡ˆ[î¬!|4‹+'^Nˆ¶ÿ78z:½AO×ߨ{γ ¥È6aÙ4,,¯Æ˜°oqyÕʶ ±¬ªÄ]±ïˆm#_ã’£¿ïŠ-8“†È…Ø…¹«Zë.Irl}Á#óàò1õrNÚßì|Ó64”5å›Ç•dTˆÔE(XÎðZéÆ\¨¢™kSqê3Œ¿\Í1kSTämÏs"–è')¼Â8޲Mˆ1muï¸[@Þ ¼nkîz\„¯¹o–(\NÒg·“¼Šn ¬,'ô¼Eø¡¯ÇͦXåVé[GDøsKÄ x!ârü2¤¸ñŠ¢¹é~«ÃÒK;‹..äZ1ÿ#ÓÓÞ³0¿Üý)¦Ö8%tj¬ÆÌÊ…À»/= ÿfñîcea®ŽÓñšhAZð õ Mÿ8ŒîûèäE䤿t­õèÅ΋›5`=Z_¢rèÕ6»&MàuÞ¼a¼¿ Ü•ÓJVW›dεfàÌ_ÖÓl«!NT¹OÞåÝT¶B‹"8êÂ$²#F-õà ÿ†B>ov2HcÁ»S>~dKžøÂ5è=ÞPydµ:P¼¸È‹ŸÄ÷CQc8UfRá.—À¸ÿBÚÑ.|õn©¥Üh¶_pÎ÷öJÄ¥Ÿ›ªý´w™"NBm7™(2Ð3¡g[ñÚ7'¯º'¹û`@s©É’7’€€çOåË98Ba{ÖÐâ¹²‚Z‹È¿7ã€ë)žhð釣#û^Ë|»fÖ™ê}Þ÷ÞÏ9þýã¨Èj¨ ˆpœûùs³¹âYõšÔýÁŸÁå/MÄ!Ý!_³”ÐbÛc(='cšTÍxe7!éßXÃt²4º ó¥©X÷:ZÕS­’9!ß:þ6$÷7¬Ûé÷djQ?‚øœÈ{šÔ ¦ì×–‚¸>hâë¹ÂæÏ™{mc¹ÇN$<éè È™Ï7(õ6Œt†ÈgÛO˜axÏά åÝ5ýBoÜÀãcómcwFv°lsž7wòñ ¦Ç _ÉQDõ¿'¨©‘¨Õ`a»›ÆõöÇt\Ç\Äx¹xê|"§s¤=ìó#„òÅp0zª^·éæáÃi7ԼŠQƒÒ VÓ¯çnQîò Ùß™hÐàc[rswø|æÑk±},Ýj§nÇ;è5w%¬û?àßÏ4¥4äp¼+-‘Añé……uPíˆÂBÌ’Y¦³Ž¡ÂHЖ¢×¤E«¶ú?š˜µ'ô{t¸êGìM6DÊ4Eÿ†Hó⨪3Aw$é/Ž´ÃŒ±ÏÏ×0NT×aì[м¨Ž6¶õ„(Öè®ëÙËuWà4[ååJë” 3ÿñ­$[¢2-èñAÕΗ,ÁûC»þŒì0‡ÔävÄxð'ïK®?-žß˜ÉJþú»îÁ+3Uj¹¯’E¤®Hû=8âW²7 þFP*îˆç£ ‡ãI\Ú&e`BÑ+¯¶ƒÆ3`k¤'Šºì œÿ<íÚ뢙}=uÀ”ñ ú—?`¢þ[É~§mºÃ¤²­ël"b¤ž¹UO‡E}pÈIÕtZú1eÉ{äéµç}ÇcŽ"¨ÝU¯´0»9Ê™ÈùˆÞøè)Úº±õ–àÎo˜ü`ÑaIl#aqf¶l&ñBÑÚÀrí_ƒ–©Ãq¤Žïû1~Žïk.ÌÕb&·¡ ÿ;±­@…©tÎQ»ÉÃàÊIPº»jx»É!š“[20j-žBU=ÚS-†­=«’¼ƒgøËx08xÝúqÕ-À²A£ñ‹dX±VíõmOà—° È&ŸNJtcW¯µæŒ}0u®‹×žäF*—X4Ø~oÿ°°ßÒƒh²—"üño‹ïµ-³_’€€«äÊŽG—ù=RODéüJl6"n°ÎÚØâ«Hꯠj^Šº­yýUe²£ÌÍt´Ê2ýôL8àÂÃÌ‘–ª±…%gºL‘b,üì*| _Ã_®ø®)°jjÞ$†‡rÏ?Óü›xÇlÌ;«ç%O! ɭ㻵 nÀW˜ä݈Ç)¥HF›êœ°ß«ONǽ™É;²FôŸó€D€Xï†óAâ•:µ nï9 ‘;†Ê{©Èê++9H}æÙ :ü&e—W}æ"TnÁÞ`Q~ˆª d <íaiž·ÞöÙPé¯/G$À*(TI*וÜHj-¹Â^³ƒ! é2B´m©(B|ñOlâkÌ»5¯Öúó¤ÿŽ”6’?_²ìægbÍ«×К`㨸¾;^Ÿ½'túÝçi§¸%Ù£éxÉÆ½¸R´È “ㇹÐjŽ˜ô~V)èD®´Rë7ðxø•J½Äµß ºþAzq¼©¸p?ï”ÙisöAæ#¢pSÖÏh+3L£ “Ò“×ïhmÅǺ±¢ Dî.iF~¼{Ëç’<¬=ôÚ´aŸo¯ÔPÕÖ|޵¡A!¥ÝÊæ8x(£ Ï÷Ù-Ï1÷÷Þ[H©ùŠb{zb!ÑN¡ÁBdà«–‡´rw}¦o—ÏM<âÒ‰£­Öe«}=;þ·I%Ð{h. —µ¥“ܸ ÷E6HˆWŠù°ú5+y,Y¦4|dÇNNY.AOùÃ32À÷o’–_Hу-€ÅGS—¨ ÃÎõcú«xˆ‘5MŸVâ2îÝI!XpuE>Ú=Tff —„§Lĸg°,*+þ庡ž’À!ÿ¼± l]r¢Å×·àŠ²7çÊû*…ÃüÝÆIÁç<á6Ï’€€µ?ËDС<|Ì- å Ù;@þËͦ*–4­È*/ضàÿ˜ž•hîÛÏíHðÒ7ƒïjH +èÚí(g]#¨lúvƒG½ãa`‡qYd)æeÎÖÌäˆþZù}“Di¯Ÿmƒãµº˜ÙÖBÇ#ÀŒ=š©‰>g$\a¤_tf2G+xñï£s½%…k÷-]Äd†kZƒ…ÿ1;¹‡¼ñçÉ÷¥ýeZ(B¡&ž¾FÕt0ûšý÷†·ú)S›Sú¨FŸoàôsYTÈé{ø7¢‹™‚Õ}–/ÀUaæ>@±HAd·þ>v,Äj´”M¡X†ˆÌЛ¿;†KWFÏdíç6aaÜZ“êBf»F™k2 ªV,ïÄìk뎑dáÜât‰ˆåJU™á‹‘<;¶:1ä{ö}möÿ\|HŽŠË“¢$ϬÜVËÓª¾@¯Á2¤wŠªÅ57¬'¸°Œ30¢ÌF¢léÓsDõõdÑ$Ç{… +êÚ¾†ÍyLF.òbà÷zh[öÜë3éüÂ`<½IW a=ò‚ºåç½_>ZE”:y˜rÇÚz"Mö;µl¬¯.gI®ˆ[pc*íjW²TÔê.¦A©½W9ã¾Þ¡§dÑjI¹õB\W΃BÁì’…ëþÆtFêŽî°ÑtñÊ”9ÿS¹×œÖ°^KSŠq\ÉðŠÏ Ü-ÔØY: ¡Ý^gM¸Õ|¾p.÷ÂôíÂ*º1"ħ3ë}©þž(œQ*‘ßH‚O2±üŸØ.·—dùßÞU’Ù´láÎe=_•…n²XiîìI¢”ÉÄ"5R@tòF¿c͆WôÔNÆœp =ÑVƒÓí¥Ï Ä/dÞ©¬ zÁ㲨£±Íü¡&ÒG‰¢M%žGf¡b‹øð¿De±Î+sbUÇ4¿6<™Ümäo°i˜ù›Œ--Ô¢ñ³)“ûCàGŸKç글Œ3eÁ;ˆpàC.„‹êNºbãUB¡*âXE‹¸ßÇNSÅ pKÉŠ›®@Ñóœ@VU5Û¹-ÄÞÜÝ­ ‰UíÄ1²¸a¬4s¡utÄ1É1 “reû¯†}’¸èÅ ?¢C4ArÙ”æó!LP®·ˆFõàV—Ò’ åPË|&£áj´O •’€€Às}(å?o3K¼©Ûgܦñ`ÓB“ÅO³ƒqùbPƒ·<žëú¶z±¯<|aÂÝ(‹»ü]¥÷4oNû]GZÖÑF<¦UÞ¢TòMÖVJh´†‹ÈöjvZÜ ò`»aÁ¦Žî]åæ;ŒˆÊ•­`¨"W×úËÔ ‰s4Dq—ýTÁ³-Å m°Œåà‰×öЃ(°d„ŸÁÙÖž;>^÷e»Ø9ÎNWüg1›~ 1¶ìÙj1;i£ƒË ЬxäcÌù §–ˆ£QywíÎMï=ˆ‡Ps­ûÞsÕ4—?í–;^Z,gÔZwyw`9pÇåbÄMãzâÿ|#ß4R5Z< 7L‡äW€%L§D|!ñŠÕ.ÐŽ—Kbxí­[r â½åáƒAÂKÔÄÐõBÑÍEgé 32cÞ?BM? ^ì|ŽNO¶’fíÞ9ÃY\h*ümŽèýIéImboÕ…î-ÑR×&)«a¿®„5äS$åØ‹ÏÆJñ½m„rÙ*G/dyuf‰ë–ˆçâj4ûw käÊÉ3[œÛÌo‚¼ùxGòý“ÇYΉ£à¦vסbËbÙ>÷aqÚèßà&‰Çʪ,ªWÐ% $¨-®ÛWkrT·;Sê:äAùu{!P:¦N&À¬¦-|±d@b‚“ª *ªâ'xËôŒ•3ÒvW†#q"žm1—áo(H9«ó×Ëööd\`dïAPŸdÍ‹Ytb‰C-K@ôÕ›2ÙucS/žÛKØ¢ šÞ²i/Î÷\]›%á.O™Zbj.B‡¹€K¿ž”±}PÊüxLœ €|(éej˜ÒB{bìì¶D>h@c?RÐÀXG„µ87ÃP!SÊÙnKýhïÇptØÞ`tôü^Áê+Ç2ËfqV÷ˆ…”ár^Q·’UŠ!F]€¦­&K?ÕÉ28×À*-ߣøñ½(ý ÄnÉÔp^!û;Á¤@ò‹–Øu– q42О)“#Jð_S±Ì7ïþæ’€€«ènµÞ¿¯w ƒ+# jzéµòµF^ÞñLO<áº÷î´•4~¢¯ %óÔ<Ö'l¦çžÐùH‘ ÖNþpþ}®öß¶±¢XäÖ´Aœ®Åÿ!Âo ]Œ\#[‹í‹èí*ßš‹û1MJ.{Ï÷N'Š)ª7ÔQþØ9o-!Æ$]–šé~3aÞ¢.öÓY¼? H–õ¤9§¢—&Þ S#† ¡ìû9FX`ð¬4³’Øö·qQ¯pßR·|‡ÄZ᣸AþñJIA-œpüÿIâŸB¤5´ÿ¤wâ–ž|&¢ñ_D¨]n„ºUžŽo5³ÖµƒÝ öÎ=b+´®Ñcÿ-R<(]轈ï+ÔŒPpž÷ãl#Ê\F¹d'ÃÖλb–Ù)i@–b>§íH2€$ëqÕ;óÃEcÛH2«Çz·cÀ MLêˆå  MR1?%ir5oãM‘úÎåÓïÅ©[ó—MKñÑXÿ4OT rcÜÜŠ*Móu66ü·ªZíÿÝ¡˜ŒÄ‹9¶üŠO¢g,ÊÖ” ئ·]<„Y׫=²ñ-LbïQúÉW1&dS0f1œd§ÜêÅåðj³ô}ÚGø\ĵŒ) ®½£«» ŠCÔ Š:pÙÇ (”1¹Â‰y].ïÒyó…g]ñÏf|ªæp'Ì`–ÛéßÜ Þ;¡³P*™ yx%"ùÓ(²ö$¬Y>ÐÿS8.ü,ŽÙo¥nðbÄë¥;Ö~f+·{›ŸX¬±Æ~¶ÅÄnTÌPo•M«{½8ùÎè‘ááŒ-Áµ÷…P"+_¢*Ædn].œ°ßqi™LwLiq–ÝÁ³ŽˆM¦‹½vÉAPˆ}3÷Ý ÂDuþÕ- jqûšÜÄV -Ûägþ^H{¶ÒܳP7 X{¶¶–!Í}Ïg38¤ nè™ÏEˆžÅ,ÉÜ ¯™f7(Öm‹FÉgç'3— $ö3è³&E–GÔ¨@³qr;ŽÛÊ@L² åLAÖåjXXþ¸£%Wgáƒ`¹|}y‚åßï•'Þ¦ -,Œ$)Þ¢”kËs.9ªùi\ôØÝ[fÈ¥éë!+Ô`°žˆ²¥ÀU3\³Úb:@¯—/”±OÑBVÿÿW¡=j‘*ž>8µ—RÄÔ0#_ЍÃhÿõË: Ë<íÉÊõö*‚Hèí!äÐúsÊe=™¨AßIÔ'ndܹW­©'ê-L*ð 0Ñ+p¤ZFRnM•¹{ùÕ=ÉåD5ãþ/À‡`%™<@#ö{ƒG#»Ú´yïqÄ+ϪW’´œtÞ–~°A¸b¦ØÑÓTXŽÝ,å}B³‚!êêW¬\Ú(´Xj(‘§„¸[5•¤šS°Â]Ș9ÛüV4ΗéSÁ#2°êJr¬æ“p,H–5ýCüL?^ì¨[¤¢•ƒãÇ‘­æÈJŸfH{l×¾Ö‘åÃÃyß…Cþ&0À~ýã.gE‘þ,×£këB{€NL Båc/ ÎTD/ÇnEgàøž\ì´6]ùâ¡1r¶M ü.¾p7Õ|ˆ¨ U$CÓAðIôq?:Ž µ¾>j×±\ð¨ÿO´Å‹kïÂ1Á|XÎsèXN;ÚoÖõ;~<’€€ _BÚº™ÏÄÚc­‘Ê\RÀ CÔT,a¥)îXö¾>ÐF°­0‹÷»ZÁ† ‚¾—˜lœµFÞTºýNë)ÿtx¼õ„âL·  WÿG6fÊÕ٭ƒÍãµµ¶®ûf“”´eWƒ„Ô8äÁÎúòŽ-@%d?©b¨O³ñ*¡ÊSÛøÏ 9ßA¥5§hƒM©®èºêû‹U! @ÿð^rc+Ó7?œlʸR)†óÞìc:ˆo¾_1ÛMÙ+I^½i¿LAÅFìó»a ¥QykË@½4Í´_óaá×Zd[G¼¶d>~W¶>²hðápÖ¢Ëì“K]îrÓýü»´É]u£ øt8©ìé5j©ØÈšr¶˜×;Œ)È.Sá£Å¾¡¾»Pà#òº_†$߯Ö,KA¹æäá¥ÔèRmŒ­0%ö¸VÇ¡ú£ £eu¾ÝÂÍ·ë?|Ÿ‡¬y”âôŸÑ˜hÂ_­gÚ¢üŒÈEÿðtÛË'‚°;zêÜ’ ÀãqMÒÅP¨ yÚ`W5ƒ‡À –8«NN Ûå1Héš”,©€;æC ޤî(è“ùRË7f RŸ&d{׈IlƱV³ròßXS9eÛ Éwº!’±R)¤•Â]ê/.ŠÕ¢ñÜO¸*e’^³ïMý™»j‡ D°“íΑ¹RÕG®VÔЄ±ª6—]OÛι_“žGmÖ­¾·U7ŠZPrƒ† QC¬)þ¾Iáî–±0aÀ LdMJ¥«l!"$µ¥8"9Û›üHkìx/7p‘ HPLººq&ÒÛYÀ,feÛ£ok,Ƶ==2ó¦ög·'~E¡}wJˆ¿Ñ\\ræp`̬ùÒ "ëTo„ü*Xñ¤ñSQÌÒ OÝEwUyµçÞ¢Âô÷jù»¯ë31d£§Ï=Æl¡X º³mFí\†È<þ)e'·Åñ 4-Ï× dv †Ë3vÔåžGûŽЉ¼ˆ)Œ‡ÈzúùÛÙDg²öRƒZ|ºvNv‡žkï|…ª|B*’;(¬a;©ûÎÄ(ÏÆÇÚÐQ>É'|Ô&bwmN]~I;àÚñІ„jÓÜ_‹Ì®KÛÓ¢9ã(nJã¤iIÁØQ»G{† a=‹‚’€€ÌgóÐcèV#Í!Œ“ ”O~œtç¡aÇViî3£ã3]¸!Ôˆö%U9fª!Pߪ?Ñ\»ª”“¦³ª ^÷Œ“³ÆŸ ºzc€pÈ”‘&e&Ý€•‡D{íš_<š©1¢®”ñèGUqè\…™œywç`$¶*7³Jc6G-dñ+ÈɺkŒŠÞ·ñ?;7iIâî®æ”Ô(¿”ô@µ*%MÆ_hBEøf΃’©ñåñþ ¼±[ÉëÚÎFsD‰ä&Ù£Mª¿¥½3T:¥õ?ÍlF¬QfÀ›ÏOy]×…)*„c…Ùɹdw|å[&fÒçu#-»w˜aM€ï¿™q!ç+Û>‘I¦}°¡äÚ›ª>Œt$ü *Ý,`{rµ“ÎÕ6Ed×åpµÈ–“]ü¹‹ÈÑAêËs‹6Òlìlè%9`¾ñ}=‚¾õGšGŽOÜ–}ŸâÃ$GoP[©ô›LêÆ¤£œ´³ò&Ñ©rx-ý½ß"çêSS»Z:>FPÊg„ôªÜ=í×Ü£ØÐg—¨Ä0ÊEÐÜ’ü†ÌK ÿÈ1ûšª¬‹öp›ªÔϰ£ä–s.Xмlꦞ›ê/S犇¹Öÿ†,¿z ÿ=¢=wO!Ò4°Û¡ÿÆ CœÐ1 lFÎHe)îºîZ2 OB®«p¥XËèO½É©PN P 5ÍDÃ`Tò,.b(çgmÛÚÄž`xjñª—ÉË£‚(ºÇù zÚ˜-í¥Z×µ##FÓ‘‹öàºÌµÝ“ÞÌÖó´`«Ž IÑýWN nÿF§èõ:yêä<ü¶öÒY8(Û2#LÔû;œ2F/5]ï§"ÆWYlÎ œ öÆúð”ÕoªÙ– ”ÖQü¥Éö UmÜ}˜æ”Ið¥¨I`ËuÇãb0zޤz·ª%<=,”J˜›¨ÑËUv/@)¶UUðc:X”¦‚³ü8¤hºÙíá~7¶æ^^›f·Kód¡¦)íFgš×l¤ ícYX7?ðÀ€x%§XØýÕ.[“÷%.|78ä^n¼…x’|C×;š%Vâ:° JÒÛÔ ÇY£íþuÜ-CÔA‘9™l£&¹,k‚]¥øÈ<¦ zX]uäHæ[ ìjl‘ÖÛ’€€µÛØólºá³þFw¹ÉðXë(ŒßQKNm{‹cZ4<ì8Q…À‚Ô+ÉÏ}‚ÜŸeuÕ+ª eÇ?-ÐhœQo¥¶óÑõùxä0„28þ€¥ÊþPo¡+¯1@ZTwÊ[uqRJˆCºÂ¦ÕÃ(Bšxà;üM½¾c¾Ä‹©Ï\~ >5¶býÆ$YlñÔÀñ<ŠlÚ …•šœÎá4…llíû4…½/3õá•…Ë®%¦ºJ𣒹2Ÿ¿n÷ ´¢èÄ­ÓˆájཕҸSƒYe5éÜb¥ ‡ê¾´½D½vÚÖÇÀ3?wñfù¬ÆCbÅlðõ¤"4"1#XSaòô“|û©´ËIÄÏ—ÊFèFvœ„©‰ ­b‹-â–«à"Óúœ k©#õ†Þ[(aÖö­/TÒ6¯¸¸±PM>[¯îÖ_|”%.̈]ý§»×—h#ðº¥k;KÒT´Ä”„[™ÉÜk¯7 ócôE ì…*À±­Z‰ÿB™GŒ ¥7ɱ`Çé; ÷ ¥³—{e À…º ¯ˆºŸl<=;m•¥ [k!Ñ!é©Ãmõéšërœ—÷«|Ú¹¦æöÐKör’teÍ¿;<U¡s *&¬¥©r’H0RÀ '¿ˆ÷r5Zë$H¬ô•ž(fÎÕCY(áð<ÏÞçF(á/-,kˆyœÈµ NÁ*ÀK®å~X4ÃdžÉûA\I¬2÷ÏõšhËÜK@¡]ü„\ÈÆ”ü‹‹#;ó›(ÃiâáͰÏ`¨—îý“ŽG¢ZéiœX¦bݼï :ÇžÚÆh½øïÁí8±kBwÄ–Td²Ý½ÁɧµL³‘ §U˜DMy(\,co°¯j³Â emÞÆÞ:t“'ic@7£Ðû9‚þØ’»¹Ø3p|Läžü¯LaæSC>ž+¶Ú„pìÌ _ºÐËÛŠ*^ú+I<ÀëÙZÆ ‹:~ñ¯kS#š¤†)|O¸ý‹ Û°ðÖVÂQ‘Ê!ÎAI$8¯,Óì”Xç¦LJ6 - ¨5¶õ¢(îYd.èþÖ×™x¬öuFéçõ\·Ç ºljpÖUÇiX‚ÜóQ8FÁ8RSò°½Ú0^Þ·Ø«µªbÁú(*ù£Y ÿÜ /¡Î«Øl[ª“ŠòùªŠ’€€Â¸—êÍÍŸÚPaç¿ÏÕg‡Àz^ê /ÒýÁí÷±cô[û»|–ƒÿÏ|µùÝ“¡N?°x…™±=¯8.Ñ[¤ÊzÆ¡UÎZ{€n!5é)O…¸ÁI­êöe àœ,б{ŠÀ¯ÃÚɵ‘2QÌÀ‹ìGd'žœu} fuiû …7@PQ%†2¢’¹$Ü˺ESÝçpÕ§÷mbc´ÐM¼þ´ä ž{k‹¹Çÿ<²4²í1*Œ£E‡•~+bf"å÷eâN9q^ÔBåôkÂA„Tô'Ⱦ̹JC“­ãÅÃØž””*ó¢GâNåª-nÉ¥AÐ!­Ð8be.,¶C½zË7¦ü/žÔŠØÁübŽ%Ë2âðP@ÓÄ=|\Ñô“a3M²o%ÆèÏ,•ðv)yÁ¶.³ ágï-ùØÃÁO Oo„;Ï_²ÆÔ 8ò{çCj_;g³ª:€‰ÆGÕÆÈ굦F69pãðz†ÃÂGª†!gH«pO^‹‰ö]Ž«çÞ:î>Œpí70¬Ï†b~Ay­ˆó×z×k^"å¯Ü#&7¶\Û’ …»ñºD¢_ÔopØ pfõ¾Ôjë5²Å=‚~¸ú,w€õÀøÛç¿ä„²„¥#xf4®5DÓZߨvë«ì­¨ ¹ÇV5}%™æ–º! iˆL‚Júꕆ5ƨliÊKŸ„[Rñ·µÖóA¬ÿ‚ÆâçÑй<}6Í€ö!•‘åõx“KÂ[Twºž—øíÁ³\G`»ÉsðTóŒG|ª>6?5© ¹ÝùñíÿCÓý$^…[¿2¶“+KQN²à§ù¢èÈXWã³'gÖ<û¬XË:”/ù6§ÎÅ,4@T|Ãu¼‹\Ç¥vTœD7ãq±dOµ›ƒ¼X7 *“Ó-ð‰Jœñö² ®ÑÁòXÊ5œMC_ç÷(n´û5‹mÁ”änQcV8$(gú4>ëÃQoÓ° úÖßò›bõIÏbë-P§ j·÷ÙsdàòE]èòcYÚªdýD·2»MïWïƒoÇ s=&sâ€ÊñÜýHN|>aò3Þ¶ÃyŠàC†nç2—ÏbáÞJ s é¾¶+ÿ#¯…:Ü£Pú>eNïZkSøF†<kªjVÅ'a…V6܃“_X$ðy~DeÈâñ¥y!‰Ñoß÷P$-¸³6Þòh‹Ì¢î%îJ¸…—Eí«´ðG½Fj åÉ‘4Ÿ÷ÿad;u 0½ìL3ŠBo[ú’JгêfØÚu˜ÄœºÅ@!>ž/¬‡ Â} K‚‡Uð7¤ÒÉ2q”€y}:J‹X¦µƒÏÃ÷6Am‘W8ug\YD’êÀÒE5_¥hÞ°c elì×v`JxÄNÊÑ.¿“áÙ”ñ‡éy”¬gÀŸ_gVºªZ¥:&à-¦¬<½!}϶;03•ªoH ¿`Š–#ˆ«èÈ9eì9HôӉɸ¡?÷W¶f®>Táküã­ØãÖÅQ׿°¶•i1ôÈ wîâÎù8ýMœ˜K¢÷/Ýãʳ‘¢ÿZ娥/ÁNŠjˆ}Ñ "qq/®ÇL‡ÕüB˜ú3D;8C,M†·nY9N»­íuÅo6%lå/¶îâœC¨ Ÿ“1ë U¤·¬ÙÔ43ظ :5ÁÅ+R TÊcnxqìÛžºî!£X,š®ò¬«ébzp[®C N’ÖtÃÑ0é "maºä%³khM „çáœìš$s†È'ÂG'ñ͌ýÆ*^_é½u Ðû¦Wú²ÌÛd] \ò½³W~hÆWÿ9U¨“öŠqŠ,‡ß¦q:£œYZ`“kýa“rèdIµÕÜòµNFÉçzéZ|RbLÜ׈"¯4:>•ݬ:FKjZ‰•BI'íT„·é'þÇq9d4M†•IW^µ,LQ†ÄÞ¹]v½Ð`ÐÄIÆi˜þÁÔxtƒÊ)ÑdF+=‰-…§a¦WÕR`"¶ÒqOåi¨¨öÙU™’€€¿CB“š gŠã¯°]70ϲÖ2„-ˆÕ#£‰ÄÁªº‹RAxŠE¬B¶¢/€Â΢ö‚úÖ¹P¹?Æò<Û­E› f]Î ¡¼¿‘ºÔì"{’^fïX å[ú¥h„“õ£ °>zg=b“@™ß5¿PÝ Ïå£ÐÓйÇÉÊ÷ïÆa‹Ö[¶dcKŽØÐ½›Á(¾ÁÇ(›•ÁÆ›å¼Âÿƒùعù":X¡fFðv3t_W£ÌñB’€€ËÁĉ-JwHb‘/%¼ ‹ÐÖ˲—¹S %HªzÚmºQ¤ ‰©—{÷*öŽœ'#gI"”KVUΧ³±RÓÕ!×u‘(š4Vg`¬ÜÇÙàg¬Ç|¤~¾Dý?¼A®7 ;‰½zLòà%¨ÓIb~÷ùLv‹íc| ž 4)ÓÆ2ŽëBÄê!ž‡P„ FöoVF»–Ú[Ò…TØuoÁ+ˆMÒ9¹ó#{ŸNUÊáÆŽÇ#oCP*ÉSpÈd…² d±‡îgÀN<Óíüü…,8ß;‹Ö¢¸ù÷‹‚ékp°½Ðý4ÑSx£¬™¿-I&OÄ;ôÇRßÐ3°0ÖÆN¢¥MÛ!1`\*âÕQK»¿4r2ã¯ÈÊ~`sA}sIèÊìÆ  ô‚â¶'eš‡Æ·Öq4hÞ…ôþn¯ ´„pÊÃÇ(›¼6HBÑÍw±êç‡o‹Gq±ê׺™¤“”Aƒ|ï žvfˆ“”*k">t¹BQoOUç.òaÁ ¢±ªûaÄþC[tÐý1>tµÞš %YJUH eB|ú‹,ï?>+ZXüzˆÐCXBk|íÖ«ÒI¼¬á¬ÈöºÅ*‘5¤Ö’௠d…§ž…—S’*#ºD©Qcð×/3LŽQI+¢ª!þõl/@ÁüÅoä6±úQØÓ8[‰Àuȵ\²ÏŒ/îø×*†„meZsÒ&àôm€öÄmhŠÊ"ô°O¡ùÊsUå­|Xȱøp]Pº<3îäÄ%E|lùóö¯TX"“læ2îΤ®½1i\ eT_p3Üt­u3ómÇÌ–Ï]é3”°Á|üô<™„/踪ʿ¼)Á.¼¤Ø/+ü„ñ EvÛ¿'WÓ.? böo¾×S±:†À—.|ªgá˜Å·7à M;^u¹¹UBø 5ë_¡Œ¨[ÐÝž“ÝØ‚åŸÅ*ó6lÖ†‰×ä>+HÂìÙ¶L•¿Åí‚æ¶¾Î])¨jhŒ½î²!ýîSSå„TjLüm‘-Ðàó©‰Ë[˜–>¼·ÿ˜Tÿ.y9`y·¨ñ±ãÙVÃC>ôøÁ±ì‹‹ÊT‚DÑû'¬kìA¯äo’xóM ­ùoúùÀÙìÙ‰t½ ®4kAvßbõÈ5©q ¤=&¹Žƒ»¬õº8¤ 2CóâÚÖd¯”Éâ‹Ò;je 4&¢¢GžÈ÷ ‰Mÿˆ8/Tæa¨Ù.5-ðR8øCÛ€—ê>§|m4Ê]û M™jù!‘®„Gb‡ŒÑJ³¿ñ±›“)‹|á–0œp娚^bA“´­ÞL?vëÓ2®ŸƒQí²oéfžÜȦþwm$º Ü˜Ò±çßh e¯À(ÿ {#úŽ(\‰ ›[Æ.M^Q½Ž‹ZŒ¿Kÿ bp÷èÂb77WA¥ ‹òcHJßxçÓühS‚àBôXÝ€ó(^Sˆu=¢|{æu¢½ƒâ¤³Ø|à¥n9¸ÜÝzlD”]†nèIi y$‚íª\<Ï÷Š t eItæ L⩈ú‘èö÷[³ÓaT_ÐzøõÔwc*g¶ÎãXÝxø»“½´© l#Å çàÃ|8²H‹àâ¢ïz=Cljd¼¹Z}•wœ…iñ ïO‰ k üŒH7ºÁxu¬8–ÃuŽBegÛÀ&œõ4&·ÏËjƒ „Têwì.õÓ Š zFcšÞ}K gPçùáûèËq*zûÊ­1¶ó³OkWDÓ ð&¬¤¨¢5œ'¾Š€›áá¯×w=RoœèëP7¬‚ÉíÉ~•TöÛÏ|C±m¯Ž¨ã¨È½ÔK,º— WÈ’€€«ÝЦ°ÐÆzRôåLÖ²ä$:qÑs™݃¿æ%±›hÄõ3¯§¿lô¬ Ü³ká]VR‘’õûUÇÇ6‡©å˜.!ðJפµ¯ W[G˜Oá92j«?`ÉÔ¹šÐr^D ©áùŒŽVù|å;CL@7Y1ïXÈ–®nГîÙÍãb¯íé/ðL&ùx ž (¢oyxíôÚ@IŸRW O‰( TŠDö˜"Ú´ƒ4èZ·0È6v=0ª¡%r¥-`ýè~ÇßXUf·˜~pZò„KƒÜ)ËJÄôy°ò2#ϔԯ„bj±öú#ŸØØ"Kq[ž] =0~ìQÕI§”ó«}?°Ú­4yâîIÓkAUÁwƒˆiû¨P÷}npBéø(Ÿ|ËŽôòø\̘e!nvH3RAÒ< ^ÚEÑm’_b=÷/è;FN¢^‚/WØ¿xËåÖïç.ÐÛÈ&ˆ»8чn|?rhYýÙ&`Ûà[Nc…¼û!‚±£›´(`þ|0”ž—¾Ky™(!¥_—/oÏ_êÈÀ8ÓÄUѽt0ñVÓ®VêtŸôûœ´Î€^ì¼Qš ѲõÕN 9òËÉì [sZ:õí¥sxíÝ™f}—¸‘>hG¡âƒ\ý]ßô¡ÁÏ(¿Î–ë¸2ÅZ[y,äÎzcWJ‹ Yã¨óÒ¼„ƒ',Š„¾°ç-GS’®Hâ„®'ôý‰DWHDlÜc¥èÅ£æì¤äÄšadÃËwŠÉõœÆ†—e÷°:AÎe›(¨­£ö lûSv³Œ©üdÄtßþÍÌ[ÃÞ>Œ=ïr;]tÆîLƒ¦Mf›ã-ѨP!ŽØXß]9oÓ•0<MrÚüLŸ&ú=¦TÕÍXu;7j\ ›3ütë&õ,ù¶ï=oçhg\;ì ?$ÏúÑà.L ±ïl ܲ²w×yøTÑ’Þ^€Œcyò}™—*˜oîs׸‹¯Öc-°Šk÷™î^² =Êq;Ýí^UO¡ïǧØòÎ-jQ“Ø)¦âÿÑ}ÇcÐ'(Õ_ô”7L+²ªÉ•\OÔÓ 9Dgj,@TºKœóÑÚÏøSÀSî…k+‰‰>fz”¼G‰Ì!zCø» i:ÕÍÎÚ:4]Ÿ’€€à^æxöT–jêÞBÓzM É°uyj°²ÍŒ5ϳYê`ÇipêPÚ"œu>Ž<ÆB𞜕Àæ€~V†®öòfž®à·fkœ4¸‘¯o{s„ûÐâ=¸1u1ÞveÝ}õ*Û‹áºÀGâ} üÛÚ"šü‹W‰¨ëx¼N¹²Â̶›¤£g‚‡)o­¸'DeÌÚŽOŸ'§fSkà¿NŸ‹×[e\÷âpÙòíŠ"´–ˆhyaú°Èx²=¦ù¬ÖÄ_ÄüNäŸj™Yæ£d0·Ô ¹‘¼}iÍ“§(R)À^27ÿZŠ þ˜©#®yöDªèq.×!‡dæ¬Ñ¨câPBÛË9a uÍ“Òm2WïgºBß‚ë*ß“fY*@èh!üÎÑc¼‡îÔ÷?Œ¼+cüÝÍÓ4•?œÆ…,-ÜukR¿ÖknܸçCÎrt^S²}ïXpâŸUëZÌþ!¿Ó°MÅMîW!v»Cs×­aûô„†ƒÚÆ’¬kKŒ³WÊh¹lÛu[B"{&ÁÔªA½’)•v€¸+ÚÏäÍ Y?ŽDþA©À\6ŠêLIôŒf¿cJôu:“ O¥Ê[)$£ééQì  Û3‹TüÀŸr°Q‘ò½ˆ=TÜC“1ùÍs;µâÄñ¨fšæ n%ýDq­Jùé©&‘¤p‡d¨¢8ÃßT^’Ü‚Ôâ…û£ý/PßÝŽµÉ£˜•Kéö3¿5Kñ4÷¦òºÏ²‰v,ƒoF~<ÆÖ°’5O Cw±átìíÿ}ói-ãœÜ똌w¼\i Or$.‘QåïíTÑÞxf@}z¬Çnr|¿‘OVyQæ"…ÞcMÛÒp/²×1Ë^&ªQ¿ ¢ÈÖÞJCPœ'œ‹—6jµ…o#²9“ ËDª¾J–¯A‰š§ÄèÈù= P;´îÖÿªÚˆøÏÛ"ÇTzã’c>ür6ÛÿiBNhXôÑ:o’öæ* È„!9쀛þ8²/C”šåmHzÌ:âwf†LöQÚOiºå"¥Š÷Ƀ­ºˆÚÆ.Ž-°Ù ˜Ð VìñF ‡]p‚FPñýrdfÂmO…~§N_èºÎ2÷,3uÝ¿ô$§Ë)X:@è†Z1¢Î“TJ mRY:Ð’€€Åpf§®.”ÕH^P‰²léiÅ}½¸£´Š=â–îža1*ˆu£õÌeuYÈ¥ZrŒ7X* ª’v6„aAêÇiåT{ÜG6„`ŒÄß¡YŽDOÖPës^N‰®¡f»,ߟüü¶Šƒ^vçN?Êa ñåi]H™3Ø wÛØëi! \ú¸ÖúßÀšáÑ %ü—º4 :[¬xK14„Ñ}M¹­ã„©ýel3š­˜j~̧F™¤zèEœ©Ãk»tPE)—»>9²F÷Kqa4”}íÀ,÷T=WF.Všóú œhÄ„BÀ—4W샊Ì?ëMgGÌAaeC-û%=ÅŸ×Y¥K…ø` Ã`ücñ4"£Ø”* ø·ñ+‘à†ß#*ëIî(l²– ²ÆÀÐ’ü¾"Øi’§›ß*d¦X€³PŠbBj§£m„£xV,›Ó»k©¤#”‘ôµx†&žT+q&D¦”ûÇ,¿RHmxØ«»%Åä†ùÔy£LÕÅÄ‘3É"pøÚ°»µþï± ÊEVø~Ètí¨8.607V•_«fíF³Š‡Îö8ß $¯oõ¤L_ØŒ bßâÒD¤ÎãgF¬ ~èã (bLt¿ÎŒ’è• mj½õ˜BÛ@€}¢ZJÇ~ ©S 'q˜ºj -q;”á”×Ú»òNkV¢H‹ex gû³ádlœŸŸ£‚ê[E®ðÿ#Öâg¨‹-…[qdw0ª;7”Æ·—P*8ÀÝìI˜ Ô_y(}ÎkÂQÎ=–*tô|=É6h8QÄíIÁÍŒécdöy7Bßî22\oܒø"U­Ï=Œ­Jl~¾îTÛ¡¯X]óž ªØ1W#'1•WZþ;¢ì%ÁaŒÞ;ïKDM£ð”„ß ìŃð6 Y ‹egiB¥r¨0Ù)”N=3ÉD/˜HšÐÍžÑ<‹­DC@’€€Áög¿ÃŠ&Q­•^òÚE9uµ”-×Öy˜üZ7¶šOj¨mì£ÄbÊò¶®6˜c±.p0éÈŸ~î¡^9zlŒ/@¢ªLê{‹‹ à,Tk><÷&a‚ÕÁk©xûwÁ~E C†‡É©O¾¨s ]»¿‰ĬT`ÃDBÓ6âª-ÛöKÜî…œÅR§@Àå¿sJ¿úËØæF2^e‰Y‘¶\r9 ëdûªy.?¬”ô™KÿÍ~5ƒF…¹×mÚð¬$ýŽvµõ±€å)—ƒ¯ôZÏ~=bï¦"g»ŒÆwŒy8 ;ÅTÕÎæi±ð?UþéaNûþÿŸ­ù 0N*r]™/Õq¬zåœ2PV1ƒÀª7—Ë‚Ëõú&ü3äƒ^mÅp=Ê×Xˆ€ÁÜ…ÎF#qõ jWb{m&Ô:$Q²)«tÝ|Ï$ƒDò)ÜH$š’Ý>’"jqy¯rú¹Ô€£Í™¹=!ôzÎLl¶–Û‹¤¶žšµñ3€÷Êß9ªWïHcÌܬïü:.ÌŒ1ÕFYg.ŒÃ64»µ‰.QljFÑ#§êU>ªfsO“õ¡âx†&ÚJcjéËç ó’ c†KWÚº,}û’''3&-Õƒ µ\{?qMeMQÈZ· _ãÅ!=ˆû;Žz锼5Eßq‹#9 ùg`pêL³7ÏÕÅpï¾J›+YH‹¹ µEŒ{dðç«aŸ:?P#¦À)èû£©k°ªìz~£ï:4-vg^ñÝiaQj.b¨½äQê.Æî&_ŸAõ·URu%SÚ¢5½¿N`éÎSç¥ÅWÓß[™§ÊÙ-â? zs¯®Ùéï–^â™&ð"{ÈÓ|(# Ý%ÄÓjŒT‹`Çå’€€ôßîªÅ>èÂ:¦F‡ Ï·Ñ:¯RZp™Y:PA™ðˆöR‘Yöaº¨…Òœ™=Yw–’kt•™ ïD£ö©W#çóIs("øÍLšE6“&’Ë.Ê%è±Sð/‡M’2á›ÝÔA«øÂ‡@¶«€£è«C9"·åï_RË…ïPºÍ½Í÷¡Ùª™<Ôë³sÊ|põt/LÉVê/™ Á9ß“¡—ïdA¹ÝŇ5´?ù¾AÊœãÞT=ù:ž[¶Z#õª;ý9Öÿ/6…œxÊ ûC‰Ê6 ›}á†<Ù‡Ÿ‰/$„Q…¿ueóÄúÔ•(~žÆA«.aBõªï²µµ`þâ·®EvÇSØ+…ï`Í…^¯©ÀûèÌTó Ý\ Ù^æŠ%5%YôáøÝ oÁpôD.î l•NS‹ž0ïÂu'V8P–ÈlX7 c Seúʧ²ûÖH ±5±J6ìRwcÒN ˆsÏ·ôH·e x¬r%úöp‹æ2Ðpó}X}ÄSÑÌA;ôó GÎÈrŽâ~âîÝÃ)Y½¶CA‰=^€wÝ=hö$µÚg컡¹Ð'p¾v¬Õ°À\,xk™~²JIZ±%&[ÃÔý ãÄ ÞTš®æñ-›å=¤o¤Ï˜Œµ8Oü&®xµd=(@•¾ä­Ã[¯`åVJŸÏ àæ”/³¼e§B7NÌiZ™¼yõj¶TF‹ûÚNi"„®Õ$n,ÉÙÀèí½;â!2£…¯D]œ —ÿôhVá‹•÷ ÆÂµß8ÕÄ™’³wìâÏBäËumd‘•£Ií†8qοøœq ïž1Ë\2ôbWÀíb“pYb¹ò”qØf€lN~…œ F1?´# Óë" “ÙžmÅœ©Uô-)†J¥ÿÄœ§ ;Ÿ¹1ÈôB² !xèÝ—(·eÙ9wrf.:DT!e­>—x Fxëž’ö“™–dÏðAÔ½:Þ7«š-ÁP‡[‹‹"¾úGËÉ&žþI9öìóp]“R'8äú‰ÅnœÆA ¼ÑRÈ–c‘¬tÃf9Þ:¶öž$‘ÎaÀóumŽH«[”²J7‡d•W:Ê ‘: £æ@”ϸ€½˜#”Z,Óü ÑSòT^F8!téᎃ‰’€€«huNu˜¿Šm,‰„åóšk™V¡ÕöëÌœXÓÍ»îiú'ê×Îó©Tcmã*½†ì†Z0Ѱrß"©uñÞëÃ|ù0ún{@@n"œiÝ7µùx`‚@“R"›Ä; Ás51ÔÄ£6ÂFkæŒñù=³íÞÊeÙA•W[ω™(ëͼ–fÜZWÒ˜¶8u]I’ºqà\`àÉŸN¥[òGj_öò‡UêYÁF'—ýQ3†aœïÚ‚Ä™ÑLÅaèw!ÃxÐïÜa<6\v²t)Á“à»°¯U*´!’Rcâsñ$5N©ÒÈá[«þ•;[ôÁ¼ŠWÂÔK¨Òü7¹ö¸¯Ÿ~ÄQ\4“â@Æž½È;°'Ç}cAÅ-ˆV‹X¡:©>û¹¡WŽÉ&lp8±Oƹ=¸¹èñwaôqØ=jܾ*4‰F¨R4^صRÔd#¤œh¾¿“d÷ÆCG4N¯€ m OkÈ¿…îl‰ †UÔ )9XÇ¥§«•²}6adâÄ*[_Í—þš=Wu‹¸3C0ª…@¯íÎè׫ZH|zڞʼÙ˜gÌe]{±²²Ø»oIYî$ze{°ÆÝ°ÌEW’0`?è–—s²%­ÉV­~Òß'`_JGÔò:0—þôU0JYC”Õš¥¿‹«­È(cpôY‹ÛâÚ©º=ƒ²óŽ•ÔÅŒhQÕ•åîvÿùøš¡•Òœ|Éð¾ûÒÆ²Î>Ê : ½²Aã*Î"¹iUjsÊ´']­% ©P‹kóz«åt?â)ø„ ÄÑàzԭ篈æRˆ¾Š#Æñ½U<îÝ2~ƒV~]âƒÿ%—¢ê0ÿ’€€½#šð¯Ê®}I§€ª÷UÕ(d½Ó+D2L™ðž/*Â…í]»üäcЗÚçxÆ!dvÅT¼!¼yôE%OššñÏ.¸ îÓˆà?~sí™jgXÀÞödÎ Rú ƒ8èŽÁUâ1@‰ÒäÔ)úÉXç³ËÔ³DN±ýßüó உel¢×P}q°ïwûªÌÓê8½¸À­ëgE´«Î3¶LÄ“Dëg÷<ØèÌq÷F'd<¹ÅGÐêľÞ©’nEÿ±mFïd&f¦¨áÄÜ´êÓîƒÐ £ÀÕ[ýýR&M6MF僠Ábøê ¢QjMè¸Â:°ÌozÆýTl bT13ËØ0µh<"ãuƒL¶fú"-ݬ.Šö–¶ Äň Z—& º@ -… çÓ¥Æù?ŒÃó/‹µáìM0Pve]t¤év>rÛ·œêjbÐË<‚Þ Ä bÛ@ÙeU-%½èÕg¤Þ”JkßJ®yAy®‘é…[˜–Z¤»ªIQéI-ºŠfЊ崇Šù +#¶a©Ê+.£·–ëÍ}⤭õ°î9o´¡²ùc·ÞÆ^bV¬Üuû6­«†{ÅhД“’€€ì|0ñ1FÓ&Gµ19h= @’æN­ÊéôÒ_^ź|ÚvñÅŸýÅr;¨b“ð_µà ˆÚE*GÖØí)bçÞøqá8l1à̦Â×Ë„[cZdpMrïÞŒB0µÖ Ö-±TYÁt@Èñ0 n<µí)¼»–Úu>Pêäš¶ygC¬RS¶UA&ãO¾³êÀÁ5 •ls= ®™Ö5Öe>PÿMÄŠsµÍP»Zµ!’m=–dìlAA¬¾üè¶r©#½MààýC0…À‰j Jî¬éA˜Ó‰Amåw¨‘ ©ØG×¼gˆ1I™³«{a!–Û‡þš€tÄó»›kÛ.™‹)È)ЊÝ!w‹Žå §¥€tè,™µø®i× ÝðvνےÞ}…™CCú'¥3IP¾k.½mÿo¾¿~Õˆ"AòÊJ .ПRšj9ªó•íâËÚ¬õ‡Û~Gp7¸’ò€çÖÈ‹ƒ‹HK…ba{‡=Èó»¨ð£ò|”ó Þ˳ Šÿ¾•šˆ•¤¼±_ íö8Û!³ KÏãne–HÒSöi¡>{ð©°TºyëZFeŒ±OÙ¢.^"t^Z\h£LqF~ú)hc;j¦ÊÁ¡õfö1×À͆„ég°6[ÿõB{Òãgq­Î¤1ûÕ á„Z6‰6X g‰ƒ>Ü&kÜÜJ3§“žå7§]îà¿þvëÆLà,Ô>?DPùùÑþ¥Kƒ9ÛJ½ÂYà Íf«j)ZËA…NÝv±h(ðœ¥n¨Ý×4ÁÕÛØ.ËÞ¤+˜|5¥{y”C›ì†I×QÚùÀ$F–‚N®Ù·ÔÀ$ó„â× ò!”ÛŽõ —.û‰JÙ æÔ‡]ªhϪ/õ_cäÌÈF] ^Ùò.DÉä Ñ^›ðÐtïEÕ3u¯ïÀŸöÓ8úZ8´$CïR[¯AAÙÅò ’°l{åx/ñew{³£»l‹ç²D!VCS#ó:ðB{ê?M*ð=¤%a8 rÞûL µ¦ X_/ùì«Ó3%Ç+ñ=Œ_¹õUi²ÆeB4þ%Qzmó×òño7»Zfذ_{r:ñmU*K˜æ4uÀמO¨†Ùëc’4Žz¢¼‘wÈb$[G¨?šÅ ³Ú•é’€€¿Fçù¶ …ÿîûO…Õ6,4aK¶œ`QƒœT˵ˆ)u±Ù ‹…3KÃ*»$*I€"Áœ»ÅdqÍyN÷+óh\?¼äŽi§Pí¾Ôõgé½gQ¨TÝØÎÊÿ4;‡å—°ÓtTð ©S|–j®X¡·B½Gý :5•¨ö õ>K²íIú#ûÒ ܾù ÝU'̳ۛÑÞËÄQûñwÿÎ:IÕó«?RéÆŸªëò¨˜ÏV$ŠÚ#"DL÷ö½íñ¬ó¼@w¾ë¨‚ìY¹xˆ ›RÚ@!bHzÿiÅnƒÓ³»[iþš@”0<SqÞ]hüškãg¿ጯ욉î±3ˆDA¹o`1õÄß‹ò7ߢÜ#òïPþvKåËZ«€åþø –Œ¨éTd_"ì—^Ùaà´,_ıMzkóè-‘ÉK(n1‰³J´TPõ²?_ß;¸S+[#iuà¦ÆÊ¼'”RwÉíiƒ¶Þn×í(Ù©JÕjÍÈvºËâ9NØÓ›·;Ç È/$ÈONHHó~X@ï/-,¼V~‹þÚ½9}Ý:–skQégȆÖ÷ošÝ”¸w‰’,,8Zê¸E}7¬Ïœ?YŒÝ«q’4¯×\ØÐµ X—Ý–£+ /Ê9áZoáëTV©õ¢±‰²Ÿ! Ó5!3㢻*Šé:£Ñt$Ḛ̈+óeTJ’ ˜=k.¿u"kr?U0o(1›(uÕ³‘m󉸒µ9$½Y!lLb=»! òÞÍKpÙOƒ@'¿Ñaf) ©/2'=“Ò;gE耛àxîãHj_Øî¦K Dæ¥XŸG@Y΄ n³Sõ“—*c’€€Ý©r÷GãI?*ðlX_[¾¦ksÛ ®œõë"hdGšÐ*ßr'N.Ž;ö¿ãÆÒ€‰SêDò…Ý‚ÌT-No\¼ò³~¿Ñ3BqB,´÷Œ1–èÉóÛBý£Êf_Úênßs5ÿÐ9ô¾˜t¯Õ5úÃ."ÖAk'غù{¤w`XÄÜùx®29˜g€xLx‹ÏU><®æ–|¥ô!hI5ÉCz5¨•¹_ÔE€êëÀ7Î4¯“G”%Œ†égœ¼½Ÿv2¥¹0; ]àž;ì ä? îB‘ÁÖeæñ¯žeWCníÜ”4aû]ñ”æÖhôü»[Û#0®¹rdbú š`KL“ØcP ŽÍVõXø×–!¨?Z{yƒÖ0-ýô2¡ •ü|¤ÄcËEüª?ÁC•‹ÈLNhÝÎl`'«x¥b7éÛµêþO³ê˜AC÷»Ú°ýqTžej«Â4mã¼_ñYw®„paÐÕO¼A͞ѯÞSâ/¦‰P\àÁU½Yž‹„à$ßÃJÁÙ,¯‚ \e°Ö0‚BoH¹ÑÞ¦Ò¶k¸Hj@.Ì¡]XÞœ‹Œk6@ªégw ]?|DÁT¥í¬¿ÂQÃÑ®‚ß`GM~gÈC~Z®TU=muߌLÑúOK{r^˜±¯ûÄܱý:Ó1ŸA–Ôev—qÏ¿`tàìÜ_ÛS9vFSy Êÿ¿Z<ªtˆÓâ³»$IÜÎ0«¬‚APºžvk ñÆ&¤H/ðçë$Då `o<•ñVfœ›tún-Ã̬ÎÁ±«÷\.z˜Ž?1kÝ"«=ßVµôó÷¹¿~Av{1à¹O~¬üúD±ÈŠgŸ'òM\P¼TôÆ÷q¾~IU»ë45Ä'쮉æ¢ëY|¢4Ï­°%˜è9éàR½‹¼vBwYrLÓÙÆ´maÄ0DÓßHhݳ$^§¼C½U¬F\øü>RÁÆx„™²‡1A4cO#«ôÕ[î3ªÁI0À—ºzµ]ª?)ùþ©4dšÎ ìŒ ”:ð±è˜Súƒ§ŸæÌ¹tpÔ€ _Ò/.Ü$ê9 @;± KÍ~©<ÿž½H„d`zÐ/³a›Å”\MÇÉZÁ¢ÂF€Cv ð%¦{SÉq0뙬)oZ_üÀD Bø Ÿ¹ØDÇ’€€Ì€Àšu£eÕÍõëëð„æ ýé#ðèþž /å¨;H£ÀÐ*™Q¦…žÒ¸ó1#î¨xSÅá;.¢’a¬Á»Ÿ¢–à“È:·?6/xÈC—¾ÞcÍs‚µ×é¡’…ï‡ bÀ¿*í{ MId<4XË=­Ã;Þ©S•¯Åïtï,ÿÞçKŒˆp’ñµÁ塟öö-± X#¦ÓUþ»Ë´§Õfà֏ޗ‹˜B™—î€#2<÷û=•ð茙úŒuMOeâ°,ñ_„yÙ—3Oäz̉ícFÿõ6Úöß •°•ÞŠ%,û¤*þ#Ê ÿDðC-²8 Lä®í<äè¤á;uzÃCÐE*ÑÞ_‡ÇEðý€"[Äv¦Õ4);Tâ±ê}ÙKú]Û"·nt;Ash„oÑ! ïsb2A=Բ⪦€_¹Žlq«sœRïJL"ôœoøDhþ(òæì£|%AÉrVçc­Gùv¹7N[c°w³<é»{Ùp“B˜y_Zj–±ƒPë•¡oÛ-¿³™Šº•/Xoöúûüµ­"FAXÖÜ~>n¾aØÚÛ/rPãÉ;({ÖÆ5­M^@]p†0>,ÞÖN‹g˺Aâím_v™áÔNLMù ¹|aëjb³p; ÆŸ°†ÞpCÓìÐ*ó†nv)%£­¥ÌÁ_ga—WÊ™«O´B’<‹Ý ¶“Ï,–Ü É Ú6ÀKî#àK@QBv>ÞiK¯9àŽî&ª4f?aª¼dZGކ˜-JÈ^ÁÃ1E×—¡%dŠ‘K¤ý|cDO?¼n߈êZ)7D!¾“§Ýmˆ¸sãP’Æ.ŸÛB÷ÿKaGâÛ„]oWO½›}àÈOT0˜wwù øc ÇÝP¼qœ%X2ñ<^ꈲÇ1ðR4Êù¥$£-á£ð‡’µrþžÓ4€™kÎpû°Í·¬{[aÈÈâ­%çA3Ì"€Ê;†2´Ál^¬ÀSývËK쯹pSê]ž³vÆìiÖ…À|×?ì”k,_ V‚j«Ó,D•Ì‹•É¥k3ä%Ö—O¢‚V,Aê­ÌJb~X”2&fè¤ÝbÔ«#X~æ8QPÛ N.LiÚGhþy^hÆ¿_õ¦2¨Âb9ôMê†-V9$ ´âg=–$ “Nä’€€½Ëo,Ü(KöëÄÛîå{‚SÕ¶ Ê“Tw½  ù!fËrh½ÀgûZKš~Á_Ì“PEÄéçeFWÕ|¯°…åÆš¢Ò¾ÉÉký€Õû;RÉ@d4;7žsA“ɹ ¤“T(ÂípÝ€2ÍÜ€¨Âܯµ¹ú3;!ÅÒ$ºAÅ­ÄeSi` ‹“Ò{¨’2aCKJ½0ÝŸÐÖB]W¤^|÷}V.ónÚØú1¢…ëP Ç^U)ðZ·0¢É›‹ø¯û #`Àêeš‚fdz—Žæ&Ð*Ý”@X–?ähjh'IIP^ 椟"/ý~øÒã V糌ëååZ¹áÃò­"$nôh\ᡟè%«ÖôV½ªÕŸØ3âEÉ!Çä²k« ®þ«ùi{úÒÔø’Õc^.Â#òj”ð*Œ&*&¤pU1Š‡Þ›  #Há#OØÐ3÷ºyîS-}6fÚ%8+­üÔENög¤²ŒÕqŽg«n—ÇÝëŽ\F(±‚¼ âNÏ"ðÄxc³ŸZÑ…XÀPÔ¬›ßóóæ3ï(|ùŠeÖÁG*q(D)ku§³ŒV¸·ŽŸÉTž¤YÕ‡kðìÚ›-ɤ+\ø8û³qùœ¡þo8Ö—f®Üpx …›¬Iô•¨Á_xR4Œ´ê|R"wÚë7ÁéCM@€sHD ô‡»Uë8‚Ó—ÿÛ*áƒaí虽\ƒà‹™'o3¾gj@ƒXQNñ3¨‘è‰ÿÜù‘-¢-®#¤J?⪇[üÿ8×TáàÃq õ°ÐêŽÙ9Kí6Ö¢Ù¾zÇœHÜ¢”ß$ϧ0Ã=—}jP¯7ÎG•Æ°ÊÆÌ÷#ŽÇ 3Z¸ 4j«ò»nøLûÑóÊÈJ°|ÇÆïæóƒ,rÍÆqtz>¿•ƒuÍ6®*.pH ’š©;™BTPÛ^§¦];¯ßü©¦§Aï²Ë‚ä Ôï¯O?<·¹ãÑIËJ{/Õnƒ•ãYfÞüœw9¢¸w3=u¸5±ßÑäÆm%ý/CÁØ[‘ØPœ€æŠæ9z ©¸AÜlÁߥÖjm¤‚óv¥ÒDa¸qÙa–Íá°ßµYK©4 ( ã­W#T„î6ÅüØùõÅßëýy˜¶•ÕS#ßY sLÒ’€€´O²ŸyÍ«¸Ü9 }¬wØ…sc §7̓ô/VÐBÓ:ý½ºNe)Ñ•›úµ…æÛ…ØŸÉŠÔ úüsIî'Af‚›²L²fÌò÷ØQÐ)OŸ³pÊ,ÖZI%ü!.ùÎL«ìã€>/óÖÓ³ÒУrD³V40¾‘WVfkéÕéqb.ç¼G øÖqù‰‹†Ïù¶UØê?¡µ,Bþøàl6ùÌ!ožŒHezËYC1QÖï˜JJËk<ç0PñÚ".²9±¦yÌHe 5¦Ã<¯1œë3doó[²[2‡TAˆÚ)Pdš= õòZÇ›0Šÿ6-;mþrøwO¿o¼„‡YR¡ZÀ1ØÝ^“ *aT6 Õvªª ÝdzWUPÖJà2¨‰Ö"bS#Œ­‡óѨÉï@âp3žqÚÒYe ɆJº)æsãMã%àYªÒ ëdÏÁkL€ðV¡ áü§,×íòàäm~‡¾¥sX1Û/# ;XE¬ˆndŽ,|CW™cÀ:UÔÙ¦ œé¸ôî´˜TLk ÷ eÊã5zÀ…+$!\Bd/™þgg*ˆw=Ø7eaí¡QÙyùD憔[ãt¼Žå.ͨŠé¹o¨xÜN]üÇÔ¢‘>Ö·äÃî×É'D ` þ¡m+ÆM‹ÖÑÔP”°ü:Z奪íl'ý˜" n—S1ß›f”EØ« S~äã²â(ž‰¥àºEMÁúG 3*cù´RÕÅ’UsÕ‡èÈy’öiÖ=½fœpw„^)ãìO'é„ú;gü¬•eªî¸Š\úF¥ªÌnÆ{aŸô´dÜ…€=ñåýìy· x…²¶°ßÊ.2’€€ª0ÕÌ#írmF×eÃW2M*[‡ ©î±RGа Yºä¾JwÎ]é‚¡¹wI¬qB%Ò¶víTòŸZkµ³'ê’;Á~ÜqË`ß<„†ø¤âæI"ïpzJ ÓO:´r&Õ±£º„ßG‹¨)œúT÷¦âàåØÛ°F@ƒð³ë_Œ}ZÍ( âëmÔ’ Öñ‚—ÌÛXÑV†?‡¨HûdÃË.á^ŒÅt$;´~©i~ d*Ħ>N$/{¶-öå*Íàe‰ýcY94óZž)Õçµ nóÈNuEÏäþæiÅÙ徨²VBŽj(—¦‹”@ÝeþÍàOª3¤W”¤ø2qw7u”üJ ¡ÕŽ[»°a鸀v»~a†í6QŠãâ©®³%׆½Ä›#ò†,Êgï¹³²v¾‰CÈ‚‡ œ¸ÇéI#¶NëÌ#‚ä?éþ3%#íӹĎâó/ë5€5ã—CZ­ ¼Q>ˆ¡þ/êhÕ aÆ /’àPÖ§ {Øê‚ô«¹êøü‘‰m_Wêbšæ"O÷h&,© *€×P¬ \ ý⼉|±2jÄ æ¡Æú…+†>]O;þõG»í8Ô »%ç(æ§Ÿ\’ùCä?©5ÅÚàÆ¸|Dd–†^ZÀÃ¥UöÖ*yuÀ@°e‹Ò$²!SÇfÅ|£+—Âq`È™\s1·:¸¡'´ yâ331ÃUøaZ‹Æ@TPulÄü†Ùkl7H8£!UOjŒ$t¢xBs¾©w–sÿ¨ã·D¤ª­ÿ.ìÉ9ï½”JH⇘Ͷ5ÈJýɺÂÖ'¯®>=:õá³ÓpPÿCq!Œ<‚ *Œh«¿í3˜.)™‹ÃWÖm#Ÿ´˜ñLå–:"“bi£ìûĦ±ùÿG|y3#)lÖ¶\ 5ZÚybEÙN»!óV`#¤)azŽ èÚèèêÈ®¬P°º·Šù}  ÒÔG€ %hÌN楠A¸‚Ÿ¢ù vúæýô–òÀŒfØ*u›j—)mBÚ#Ý@ïŸ: šÀß*%Àh¦‹8WŠÉb X e Æ]à[»uô“\ó"ã0;ÝÅ…¯‘,ý,;ŸCÏà®cÌJþ™0¹6Ôš¿L^9Æñ ¨×¼æðÈ{êÆ3-Ã÷HUÙò$^åôØ÷=&g€Ü¤ë§bc4ºê¥ýõ# uŽvRvô‡°¢r]TüÖqL×_( ˆ>TÉ v¶7“ ¢E¤Æpp0q‚D…bGÐSç¶RËFŠf¤èˆDKÜ? ÐzŒ;ñ—·=ƒÍ<ãî·<¹ïþtcTwè€ ÐsµãlviIVàvéìkk„[ÖáíZ°g¶ã¦²o’¿|G‘}Ð$&ŸEÙjØez:~˜Õµêôk+´½¸šä¹.Ênéð€ÞAi²EØ•ŽÃä{°ZOd(Þ»„ƒ, ˜ÛqVÙK=3C‡æ|^Q˜ÞE~5 ³=.z½í¿9Ånæø…‘éFVŒ)#kagÙæºaL,k×%ظos›ÅK¥ŽQv*Ûi±³ÞV!èàKÙÁk@Vš-=%“’Í/D¹€¡2a¾Ôè`tŸxs TééAÙ™T|HÖ¶§ì‚„+»K­¬ìæB®qóeÊíºÂ€œßb \_²‹{"4t†X¡ÀË8¦YÏ_§M–'²a¤¶m¯Ææ;„¦¬Q,w'Ö†¡ö@®P…YÜ'P‹˜±j²ýÿ—y¦TwCÜ,‘`ÄÂè›kßé2žßÜ®M¢sI™µ»£ÁõòOœÚm~ýêm]׿¥9žûþ^²…”È «t‡N'ßu^'>­p ¯Nm<‡Üz² ¥·µâP¥—r˜b“ˆž1@øÇÔEÁ/ô¯þOH“—} º#=æ†pêÅ¿Õ{Ùî3ò;\/p•%ÊüQ=,’´m!-œ$0çÈdF%éoX@š3=-oï+…`žwÒ¹ 9’w–G\7øRw’€€Øý ?:@ÎCÂë‰WZtbÕ(°—j!AÄíMÀg\¸ö—“óÇÔôÌÈ™ftlù‘:„‰ý-Y##As.©VjŠbiC­ñœÌð¿¾pÀ··N›?LþT -qXk¾prÎáYãz5m~&( ßç#ê§Ï°cŸš+îEa¦^«ñ‡÷>JÞfžáR‹¶w+±iÅ“–ü'gïê%x^Óššaéëí6°„ò$ÖNœ•È.É»Ãê¬ëQ{Ë«=u+´¹¥cÂi2—#7hõ1¹«AR2[³~¹+ø}Ÿ”7¯kŽmR˜kSúiô(BÁŒo²,ÉÁqÇ6^¶>Áøý3ôæjIˆã‡‹ a ±åŽQŒ¹jTà`VN†Z›†Bh›¾Œ¿ÌŸÉ£&'–›>ßük‰.Ùêxm‡IƒÏÍf'HÓ GêEˆ‰Æ“mо_ø¬×Ü.0ޏäbJ¹<ð\*%@­fQØ5{$vÃ~‡“Øõ©RqÑå@+Éþþ@ Çk¥/™µP™!âñ5ªÓ( Ù¯¹pUÝs&•œ¥A[SÃ9ݳŽpá,¤)¾º@ABq©eë‰î@˜(gÜfáœ>Jlºò¤áoçG`E´µ7ÔŸ:¥)lÀ¢!EÛ¦#ÆßÐ8†ž~‚Àøn©$£’lcëÆOwìS–üÀ%¾¡8÷xb»+ñ;œ*¯uíö¼¨¥h¯{O¶ïÏdé’€€¬¼Ñ¢_ˋڦ¿É»ê"ÿ¸†Rk`Ý}ŒMˆÙ÷†‰½fí(²×Èzs%­ÜlŒ ÷#2®`áåz#ˆòŒ• ÚºÈTµeÐõý´lõ!˜›-À[ %E}ïwP@^^Ê«x6¢l³oTŸgòèúÉÏqY‡-žvÜ 2Á•†Ö»'e£xclO÷Ú>pi±ò]ŠÁ'‰„ ÄÙÿ*D‘“U¸ýºÙ…Aói°ÔÒ*“9ÀûÒÞôÅ÷OÄI ÚeN¸‡QšÉ¶cÔÕÿ(ZÈ(VnP©ØVJðØ"}•j>¶+šé«À{ñR~ ´]qîfu<lc9I4TRϱ¦Wªãª`‚g½0ÕšŒàMŽ£Èu׈Åq|Û…²ïµ«ÔÍŒ.LÞxþ¸æÒÀ¹hL½` ä ¶”PV\‰p°èBBß"yrEßLjGá`(¥ éÔoÆn®“ò6µwüR;`ŹsX„Ïáq°½ãöÊõ4ñó_Î ŸÃˆkW¨­ñ…¢ªÄ iòX±Þ4›ƒò«oÑ.r,íÞ—\vò~«'Än“øÄðüü?ù%k#ެá¢y>dÇ.I8+jÌ›148î¦GWHŽ 3þ³…k4¯5£hÏB©Mc—–61H&c+œ¥ Å£.­¹¹ÙÁÔªCïÿ§qÙ/7‡˜žÿÞ$}sT._©¦3ïãhÜóÔ|@*²ËŸqU‡:ÿš5FdåFx9åQà–š©,keÿ0™èêû©:Y ;æsÐåAŸb˜M&…Ÿ8¨¿í *$ºÒ&kø°ÇÉÀ\PßñZa¤•î fÏ]˜™åÏú'¾šgäËœ :ªÇW1 ±ÈØ®…LzãhÜ´1ÿxå‰)p”{ŸhŸ—Í‚)Ã`¬ÍH"Ç"ͦ%«¼óO¼Rº‚–8bÍ?¹OóãU@HeÐíJÀ+™ œ])Iñ€ùá ZŹJÑb wägL­Œ=+Ábòš¦Ø-6î’ð!bš2jÁ–ÌîDp¬{êZ‚„8Á¬C¥~gÌw„P(Pn%y+ÀñÙÆ'øùS ó “DÖJý£U?ÖÊ‘HÇŠgÜ:üMîOhˆèÂåßÓ'£¨3w-“eœ¸W¹WÖ»Wåâ éÛ±÷g_áõâ’€€Ó÷ýÄ×7S¹†Æ#–0Íl…J$ü¯úL#ëéC»¯²w[t%ÉÏ…‚@Ò$èZ^z¹øGaÁ6§e'äãN>ÜÑV{@mŠÀºÉºÄÃLÛ·dqËÈdýïfõüN–A@w`OЉO@G²ÑMìA´b`Ô›Ácü#çü­»M–ÀRÛ8¯»ƒØ$ð—k&ýZ‹ÔüÝdQÁ׆Ú68ý_1†6:Ю)*ù_9}Iï”Y¶c 2.nvªê¼<…üƒ°“É|¿³öÚ8Ï(©DÆÍ »è×–ø^^ù/„åDw®¡äðìöÒ:;Ð/ x.Lí$Ì•Ú*¯aQùèsOÏsÈ&Lýßž®Ý)¯Ñ¡R£˜ J•Î_Œú—3[wT])žˆ‘\Ínå‹°ßð‘Ò‰âTþùæ™:øË=bqRÃä໳Aå2q6aͽ_rüYRlFmÝ+šôB{ƒQÊ¡„9˜*’Ø]d|DÁ·E¡¬¸èÆh Tª>Æ]a&¶àÅ Ëùd¼%̚ˬ´ªø$ªìÁ u)­…‘uÂL¹ÞlD§ÌßÖ'=vå¾Rö öÖŽ›´ú´ïìFVÔº¶ÖÏáG•ÿ‹Ø-¬Ÿrm  YHr‰¬y“ÅWD·N\œ/¬ûæ'â‡Ð#ZO(Z½vÖítéíæ<”„W¡ Î !>¬·¡…¥ÿ9å°»0blf·wö¢ÁªNE¹%Ay*»‰xJ+Ó„Õ@SÁº$Þdåª/G€ß}#6Z+9£ u"gßßwú1ôÅ’6ê©9sjLifòãŸä4 Å$…Pþºqšƒ÷µ'®º>ÿCÿ##¨F)¾ £˜K6k(vS‰®¹ÝØðÒyg† <îH¾N/=h"üõt>,› éfÚݺOþ ù³ÂÁy˜xPs—]^û¥€·­4¿y#·€e«ˆ'ûÂV3^ ô;¾æôìëï‚C<ˆÙdQ“$™ˆ€YÂM¶ºeÓ„uûEÔ¤–¶]ܰ7÷Rתú¯˜´ð±ÇüÇ–Tå|‰EšZõÜS"þ¿5É½Õ .8×ô’€€Ê­b`j˜5£ÀBÌ1·F<0¡âå“pæk¹æØˆÄ¬w\Ãâ7îïJžsÎþgÕ^}o_Ïü»*ÉŠéO1æ²ÞvcCÏqºdir]”(‚¨€P÷i•Ûwi+sUÐçK»ÒRÕå¹ãã2¹‡GÍÁ{~ó¹Õbqò‡„í±ÿ?¸¼×— `¼ë³Å:³Æ׆ƒR Ú7[sK—‚ÔPæ„›s?@ #Xr# BZ }èì:£©JEb‹—œ¹»}uYúüŽ?Z[¸ÉqN—¢¥é[âàŽÓRV-¢yムþlÒL«÷Ãô#Ü5™V±q}ü¹ÀÖŽ±§‰ºBæÿ2ŠL³;×¢KÔC ƒª¡sœ¸J–,ƒ€)ôø:€íòšŠãŽ|$â”å^,.Ž)hýY×çÐ_Í©z ‹ÂBÙp+·‘ì>åQ¬ D-Ó)h"„ûA¡ÏA2øŽó6A ÀûÏ*Yÿ»¨þ)h~ º¹¤ÞªÑL# œ(”%VOÑë›7ØÅ&Kî¸~åø9nÊ_"à[…Ï5SÇûOúKéa<+ÈðJx¶Ø·RY0œ×ˆáxyÂù' ½Ï$G̈ÇÙ¢|»f”ÿF6O«}9bHr ;ú‹?»ËÛ'zb ¼tîë Ivå¿€XgòÖvï‡ÌÖÖ—áÚ(òñ¤Õ‘ß™1€üâ ôËt¥À}(îvj#·¶Hב—è#¿„ç’Èêy;]ê¶ú †¸#@÷ÙsJlF%@£²æR•1åîIÑýö‰Ç<‹Mê–ýéà4ûñNwC \Ì›G´ •Rsü¬J }}+u•Z4‰ÚBbКWJªþœJáGü57Ùü*KÂé‚Ù›BõV(¢¿½°àW†Rß åÈDÞ,þeǪ˩ÀÖs'w†^YöË3?J b˜ò‰=¡ïA'„P»E¯ •ž¼à… ÚŽÉÒ/°v›ñ:á¸×äŽx;Oÿ%ej…—ǹT]«Þ$4|ôCà4žs¯©{øÒ¬ÈÃß•c$&sä“']Ç®­ºí”ð¶¸Ý-RZ˜Ö~e!ÞìUò€[ÉpS¿`žX™¶f¿‹´ÏÏm‹æ¶¯ùbçÏÛz¼ªŽÚ-“»ó±¾pBhݳ‡À‹Î ˆ¥Â}?Šëxë›jÂsf ß³ús ÄÚe˜;L¥é§ W|ÝŒ™6:Î^A˜Ù൴ïV±à÷&pÖªÌ.†žXÂZ²¹‹ÊUxèXsi[4_=„˜öh°¾r**Á/h¤ä#ž§íÁÖb›e³w)c8Ü=~°Ïè5h ù1«¥Ž¹^'ÀÀ §<ÐXVrèW }63ñ_áfPÐ÷øüèôûK8Û] íÈç q28`s»„=œ–¦@Þr)ÑñÏ%‚â•ZBôXóª#m6Tù§ˆànŽE¬Ú–ÑÃÈëº&`L‰ë7Tuæ8ÛŽðørèÇ,ÒlM5 Ô<éÿ_£éëÍt1½”«W|·VÐéĹî;ròÅÃ.@… Io9¦\ ƒ?«‰ê™vøõ*]þÓ¦7¹)K[S> éÉàžtù‘ça§PÔ=Iʽ^ÿ«Kó%¶œ‚Ç»UhÙX˜V¬qâE®„i®¾[!ä×,^°O w’½@Oq™+P—†êæNeúI/\ ®ʘ­K‰ãÉäJp3;Á%.»¨:ò{ ˜aº3¥=&k7«!•,>Ë{y“©wd¿üL°üø~„]½^É&žlët9¿“ƒAÐ[Oîp2A/9æÚöáŒÞv ®\\‘gŸöô’€€¿Fìð¾‘ã{Ç*¢FR·­Â£¦*ŽœY³]§gCh»Ëu¡‡“©£Ù¾ä&_ù’Ü6‘æ¾9røž½û“:L÷óR{C(Vz¡…o’ëèä,õíš´7xö”Xr¦ð†F&¶„ñ?«gqÀ“íµ!î¬Þk`ÊŽûuÄ qDdù@j¢xiÊ×R•ÐO±€ÙD}Ô 0"Œy…–izÛ†²Ó[Vj»Þ”‡/e˜|UEW,ÙBÇoß8²¼R‡GoûÍ7÷Àug7¶X$¨'®.lrMúŒ„5Ûc‡ìÂZMP@?¸âʬ }/=Ÿ&( œØø‡K±ênØeÝžôÍÞ™DØHT¨3ƒ/ l{'A¡¼ŒGÙ°¯×¦ÂŒÊ³(/«X¨5G“8{užÚ•H,ªgPgxC~y>öe@&ŒÊÌž®Úé)ë¿¶Ôi=5 Ò‡Þ?Ëi®Ó›Ù“¾Å?ì×rÿ¸  àŽRGÍ¥¾)xJsZr)€[±¤~0ÖKèÞ×E1ö¿Ëß.æMÚæÓwþK›@­<þ(ºòšÍPè\f,]lãÀ ¼’ŠØ®µ[ .]ãÒ:ëÂí*þ‚€Ï äxæ›Ô4J‘…5{Ÿ¿B¾\gæÄ/¥òÆ¥„òµ^lÓJg¿”:àF`„‡¸PËTãü”‡ôKKà[î_ƒqcJS+è\GÍ€‘¤‚}tuö©ú0&>¹/;×¥F*ÚjóQ¬ÉBË͉œËnëÞ„nÜ¢Óÿ?ç¥Zºvæ6ïL´BÛ.¼ŸªHÅyŸvb‚™$.0È¡¿Xà$G¢²†ªâ3GUÄVn Z•§ŒQ¾§Ú@ Ù4QîªGÕ u *%aŒ>?,׺T»ÈèÉß“ÉLö‡‹/w6Ûòþ.ëýâ Ió2OÏU/‘dòÔ €%ó’°ÑYÖÔ¸ëb©¼•ñ»€Þj|@„}²R‰½'¤wÎ(þ6:¶é;{ÿ²Ödκ÷ÛKµªí^`¿Â’YΊäR ¢³Åw,Ù(¿¬\ȼ§Î›X>Q4À}€ž7€Vk"ÝÏMp6SªMbä_sû ­Zÿ/;HSF£äuËAÌmûFCþÁ2q³Ùz:2V*·d Šå]G”?aªk Vûžwuhj7û"œß’€€²(e…â£9œwZ•#ÓÞ’]$üÀ>Žª‹ð¦Ü™ï˜jÜ8¸ˆk'6GÜÑ1Ÿz]å-ÓóIÛªB”%Y`e±=_^Vx®½ûä>‡"xá>X/6 ÑÍ× QÔ½‚(VÄå;Û~å UXÅ4^Þœa.  ÝïKvó…öxΑ‘6,–ƒ-à ×ÅØ)цžˆÏ‘áîUò¨jOðXÞH—ñÖgé–ºIà›xQ„ë` Pu¸}”Íã5ü @ýÓÆ}ß” =¹•CÁÇ9¨M²aT›$00/À#?‹wô|Ù28û¼U›È\¯Éy_ÙüôÕéucš^_ûÚ÷Ú@† lÅ\73F¦m=Ø(cŸI÷¾(}°#l—ø%gÃ(Ûé£hR›wò º¡´î¢¡Ÿ,|Ð4ÌÙ-èé#áµ#ЍëqÚìEžçÍä @çÌœ­ÐzÉí_áVI‡¦è2-5“m 876.@Wº¹'aþT¼ÎAþ©ô’LJGàD¢YdÒõÔ¾7}$,,{wœàÛÍY ßÔ×­h"ù Ѹ²@#þz7¨HG?#¸WöžK ûî9œªœl„d!GGäb³¯$¹×|6»U!«ÜZZû„‹œpv ߦϼ{z•9À-oðåYƤáØ2!¥ëˆgbX£ßœ3ëP¬E^3oµsûÇ2,êÎ!Âs†\ƒ%ë³#=÷äKö×~È_Þ•0ä´ý˜Å“2sOj-W}¢JRÖsEÚVŠê·6U¼Tq"讓:ÊjsÄè]Pà "jΨt¡áË€³¥*)ÌEI›Î1ÒõoÄÕÈ ŠÖ†³>„íõ6£´”uÅçeù©¬ÃÊI8K “ìh5¶+õD¹ƒbªØ6b'!ÂŽMŽ©¦+Ü.‡Z÷=÷­å¹Ó˜'¿ p‰!C@t­ÊÄ%73ô¸´n ™äYO.” JrNïqpðµùL ïL'%£öÁ2§t(jÚLÐ)ýÀÝΙÃÿ'•t/´ òüˆnñbñAŠóDG£€`Ç0Ö!€Ñpçh= éNµÔË IÚÛ«¨½…Š‹¦º% mpνe ÌÔDœ"ìGç¶=øÖNNäæü²Å€ÛÄöä–%ζÝ“ãNû±“Cx¹?’€€ào[Õ µ`øôM”˜hÄÐí¬] l¾Ë{eN©ŒÇž@Gs¬ÂB¨\Óg²ÕÑr¡5~ÊçhàT,…,ÅF Sê¬}|=¦>FƒHÝÆHH³«G“^á^9Ò¿öæ%…uó},©6ôÊjãÄàŸN}Í=¬“S¦²ŸÎy\jx¤îŠûëB¥ škYOò~ŠZäéaéÙsOÅy†Ð@ô¸ýq©`ÈpŽÎÊ,];¢¤T¼xXeÓ_ï1SËŠaSÊqÏ!GúëiÈòÕk펉qXËöÿzy†ÇÇi‡¶¼ ´-„­0R¾¿ÐŠ xVßä¼ÒèZ¾ #¿ý6~Üܶbf°RøóW·ë l[ŽØvëÏhptc·R–\Ô -[ÜÓOr‚™¨bKÇX[/4‰úfB)aO7sŠ·|LGJ™ÓXdcˆÕ,3õ-œ²#I4šáöõå€(rô}§°*‘ †{1µ<иE›äJÀ.e}¶§ Ú1óÈè`e€wìiõd%†P#kùÙJ®twÒ˜ÝÔÒ¤ðI‘ÒéçtÞfÑ‚£ú£•ø+¹Ñ3Ÿ6>y]‰P`:Uè8fëwÒQ6PõYåîîó¶;û–d⡚`Q¬ú07­}“h¥; ¬5ŠŸ Hð¹´- L7"ÒŒ¨t2Þså¯|À8$ŠÛ”Ö»!³(!N‹®Ú 0UÉþ_ˆ¯YÂVü‘ÅŸ7ë \3Ø´M{ÉŸÒl}e®¨ÄV“ÏÞFÃsE±9)òŽ ˆ«:)L£T®blÄ7UÌ÷Ý>’Tê'û{·1t§ZßwC_¿t€HCŽ^gÁu´ïŒ'[ÍqëÇ8š'*^vS=øŠÂ˜°5ÕJND3'LÏaˆ¥<´¡#¹ôû©ÑM‘ó«ŠvÆ5n è¼Ä{W“·§ ë¬[Äâ³)BÈ"xúxñý‚^È‹–tö ÝQ¡±ÆâÔ‰1ÉF5 ðC—"`_ž}Ín6Á4&Ï¥®G±ƒô•멌i”‡žd™My°æ]ª–‡€ÊIÅáXjçLb¢A\o;é%ò†ŽÃZL^ÒÁœ”R¥ p4Ï!6÷#Lë—à-7É_AúçÙ²r7ÞDB0fÎZºG´3—°§œÜëÒŠàò‹ª¯‹†ViÒ³ŸBdù¾¤nÁaÝê|ydܶF䚊‰º´€4´¹•!æš.^V§dó\Q¥×$Ý)#?Cßo9²/^…ÙVRé9Qp®IÜ=uo V»èò§70EÑ+Á¡±×ga¾”C= ª',òíÔ¤\.$û±G‰÷ÒõhÃñ­“§sÓO›ÑœlzsÌŒ*çÂ.QiSÁ‰æ5‡õû+[;àÝxÞäŽÿ« xBð±ÄtÂŽ'°xŽªVÒÄ–b{<ìYJ$å,Û¾dŸͶ*ºˆÊÚôªÍÌ“46#ï`Wu{Ç·Ô‡ñi/Å–Z³/TÐQÙóMš¦¿¾çĈ­Ë©ngÝcºRîi*ÅӘ䮅9MüfТ úPÿUE•ÍPS‰."ûLº=ÌÉGÞ¿‘»Yz÷‹+-€R•:ÅâþQ@hƒü¾.üû>¡Z ¥ˆQÎÔf$‰›$VkÛ[ÃŽ˜2~¿ÝÀß—*Ý€%')9©²’€€ÞïZåêÇ[øÑÇ%at/û‚eÈïöpœGŽvØt®øÍãgɇX}å¹øŒÎ˜¹øç4W{#:¶92±î-&wVs ¬èµG Í^à²Ë¯J:ThW‚K2𞧘ŽÏg¨)¢¬{uM÷»g°¡âÍ9÷Ã÷”àT^Cå«fw—LÜ÷9Å_ìQhI×8UQâ ì×/ æ|NšKQ kHÊTÆšyKb(Æ ¶N&3ÝCã(¤Å^úî¿ÄŸà%@éßI‹ >꬘)Âî_ç¢cÉäÛ}ÁÇ—bÎSm’w•¼ÑaðwDÝ8;BXQ×f¿4a1Áu£­CüŸ¬½ŽäÆx‰“ŽùN(°EžV yÊŽ/ v„üÕY¤ËSgs¤ÅOšáFßoèOByäüª(’Ùö„LtϚѵø`ä¹_oûÙÛ0v9ÒÄ(óv.U^ýh>öÏg\ʰË<Þï–òÈJðt[$²””Sõ˼‡T¨{Yÿ(ñ‚Là(ñðÞÊ8‡^ó%­ ‡j$,™þSO˜Èü8 Â, "R—?Sídv þ/ª'QÄž…î7qi©i·ãßóN:  ÝŸ‰ÔìV]OÍÇë upT<Д’"gUÛV©P5]Ð`L)r`_¾íS œ‹º˜Wó©ußg'vDá~„‰EÅ™à/ eoý·Ž£“Þa…íÿ@T¹ $nÇØš\½£üTš§¡{V€-ÄÛ#9C-bê`gšh7TyÓ7ÕžÛÅ%Ó>A"”ÒíÁŒ™‘±<ýª·|îX5²Áä¬ ênÑgÇA]oÒšâôó†ã] v»èz玛0¼£6à¡àWÛ›‰ý&oÃÀéV×DˬLÐ1ÕP,[üõ ßn»³·ô]k­8Q´"ÇÞâð—‰{Tù^/§OÀgK,ÛûCí²èñ!‡þ ˆÜwçt÷vëK´ö¬üðÉç¸ê\mÒ«¶²tÝ6v>…¸/qÛ5¨ö’Éâ´‡3¸È÷«Ÿ$Êè)JíV2BÌ8 “¼’@npÓp½¥˜ÞÕÕ¹zÙúöÊ“R*$‘Oõ‘×tÐñ¶=‚G•¿8“„ÕE ‘ç®W”‹ò ”õ"Øu òÃo‹r«9«¸…tãÆ8yfa‡¹ÊF+}«³Î•?%Õ¸GLA&MÇõ]àédñxìçü<Í ö°×øçÓë¿øõiEèÅ;\Â+0a"„†ØOÿ¾ ÀznÎ_Kü ²a 7=³™LO¼‚ýí ê^¦ávCG°¨¶ vÙOi{„=DtøHj!«D¦” ãÂg)ËyS ÓÂëˆ|áÎü±·GäãX´"a¸ë•¢ž!G…ùÍy’#+±´Ÿ§Üc¦[äbŽ¡.´eÄi…\E*Ö£§Åð¹GõйãdFJû µ3Œ'AGűªƒÖ}[›QLs[³@­ÆüZ)ï 0ŠtðÂ_’e_îãoö¼Î ¼H’€€×+ˆ/”ì©­êKf-D:5ÞÃß»=¢Y8€ö v6XÞ°áN³ú“Æ—SÒ-\*4åUêÄ ØíÁFn®´àÃLþõÚÂbòD¬GÞlGý[¯æ^»Øa]øîÿ¤N‚WÅ;N ,c‹Üºi‡ÙËÁ­&p·‡{#vÛõY„ùÛò,ü·8•:eyÈœß(Ü(u÷›Ò¹æúÔH?öþvÂL}Äù`µnäZÝÉ÷âLI÷(ض»Ü·ô–õU•ç–Þê]nk|‰-j~1#\Y“ g4X•( ƒd飒â¸*f&êÇå#Ü’Î{t‡ä´{WÀÑŽ ž¶½ûB™9Ú?`ê#ÿQTþ¯6'ÑДú÷:É©ª±Uzî ò:EêSøiìËÛo/*¡ ñÀbâqO¾‡rKlëCa$¥]S.“_Rl¨µÒ{Ô_‹ÂtÂxñ-ÌèŠÅbyíôég&ÊÇ¡Ðj÷䤖èýIJP"Ð*o{¡AB°÷&_Jw<0bqt.áhoK¿al£/0&_v›ÊbÆ­Å’.u òãòâ#Úv*'p³à 걘÷'_*MS¸zøÅˆUú"ŠjÝMm¯ÓÕ-5µá¹’S¿Ô\)Ú…SeÆ`Ú"|Ò´Süý^×¢"÷3Ãø#1BlsÁ­‡#±?~ëÔç¶€„ î)ˆ î¬9V•»8a´Ç…`<™„*G Ÿ§q! Eí–ź·Ç´¬ZlÌ[üÛSÁ_Q(þ{§kç«gs(¦/š¬?ÿ8.ÓZç€_Ü=Ï6¿9¦~cq‰USãÂOâl蚈ž‰[¬{ï'¬OŠ7ã¡—W^˜f?öwnH[¬b™¬Ÿüt"€9œ­1Ô8þ/ÍMÞR”D84¤h•a¶å^G¡³ŽY5mž+’€€ÞV‘(pdrM•z–(ƒú»]`hŒóï_±¸Âäÿ [ݲê>a̤S„û«XQ:R_™ä»ðè]Gç¨Þæjsöß•ø¹y®"-¥ˆ/ÖƒÚØ‡Ç·ì˜ 7X‘ñ¨ÜÁýë¦y9MsB8ÆëXe©üû"où8I• ª÷yB—D{ÛL(€#ØÂŸ€¥¿0Ÿ½ ¦”î¥rëê§Å莛ÍO=ªŒï•åÑ}¢1+Œ¦å͆COyéP¹EaÞSµS®ŽŠ]!áÅ=}Öž/ÂWóðí'I)zêyh¸ìH Ã%Wh%ÿçÞ4£t¸!IêMõÅáG¯¤‚;",/6†Ð®é7AO0-æ]Ãû§Ç|o’Õ„”˜»¿¶n1å2Õ…]§-Â^*U`_Þì;piú~(•øl›Ñƒû¨8eà}ÔÊÀJ9(pç] çiw‰ë§âH<ŒõrQ\°S (3}ÒQ^\,“= êEi»¥‰¬6ˆJlKÛAj€ÌaqEÄlȇ>ÙiÝ‹gË\~vË+Ðõ~f@uŽÕÁ Ó l°pטǡü±l}:&b²cÆ4«‹ÿ4I½·¡å©EGM[϶ϨG.ËQ—ô¥`yCCç2gôÿÐ’uM÷åŸU…9ùöS³/ÿçî”;è.ÛØJ–ruîç†SçÐîÎÊœ`%EíÏcä„D;êã>*Ù[:Kd÷Br°êÌã'‡¸mµ8[T~'úÅÕjЧþC„@Ä6õ£hVgiOVß•0éÂ")s<!)O£©×ìY#>¦É}ódçÄqâbö‹e„ŽÓÀé‡$k®ŽBÌÈäŒÏî?úåìv”²dØÁÓŠóöü^÷&h…ºW³Œ‹%ƒF’3ReSåb©_Ú%Aˆ ò<%èyÕ´Í[9¢¸­Q³›P@óüöØ ¡›™¹²ëü¥/y]ê#™ðÉ5!¾e¶è«Â¨«¸ÓÓ‰µ©=7&úØZ9@÷h´«Ñ%ÕBüO¸Î AÛnc©º»ÃûN–pÚj~F‡óãê\¾€Î?(»lÙcëS]wH}Ý,¿•v,B”91x/_}á,°Mt¸£‚¾ÈlÞÂùŠ6î1áI΂åÚPöâ+™â½Ù…Çá“(I <¸XÑ8 ’€€Ô¸©¶j©•¼ô®Œfh簲͒³à{.%b s®Œ(ìñ^ž¥}Ø w®IÒ¿A†÷üвâxuÏ}Vt•:œ—'VÆ}íùƒÍ«U)  N,¹Ê{N½?Û0u%)0­’Më£ÒdHŒÑ ‰Ö]ÿmöÀ9ì„/Ï¥à*›¼¹C«/yV„Y†¤”( 색ðtÅ´aÁå{4IŠý,È‘æ«3_¼÷Ïîd>xé%ñ«/ݤðŸ }t¿{Y\bV´+&iå ;ìï @«ðpyèPˆ$TH®|PbÜM³6“|ŽnC?•všèïA±u[÷î©a÷\¨×"` ®há†*K#/¡Ê?÷K—}béOf°˜]0w¿÷é TGüГ‚8·Â’ö.CŒ^ÝÂnßò˱+Ä@@{[P:±WO£ïé- É:Ä2®&åuIš:Tc¿c[ƒs°a Æ¿ÔFŸ±›JîL¹u Û¸pX2æ8¥>ñ¿JuLôt${|1…jJê¢Ë•ƒT£‘É+ãùó߉´PBÿ—õB„b0g[©™Ìé+êä‘6aW2a¼}!¨ÀÛœ­ýòõ¸‚ RœZ^·Ó|)’Ã…çœ6Gqò­Û6¤…ò¯ ñêlâXKÏ#hŽê 9dWÞÔw™ïè|7Ù˜Œ!“ÅÆ:C5» ÛºÔçRF ÍsÈÕm´PVþŸ½ö¢Ç°¤ÔÍóu¾•È÷ ±p2C}~ðF¸oQCÅ™¤‡~A6~]²žïkò£& `o™´á”¨iËUçòÙîô%Ú$\Õ³?‡[,j„¢£ÃØFVa|âýX›!-_¯H_½C Œ914I9òyÆ4SS­nz”X´Ì¤Ý ŠÚpo¼ž¡Ñkg°ÉYVƒ¤iǨûÑ”X~ˆ°Î)¬‘‚Gf¿Oýp›Ï`é{ü¿Rm°˜´ùœææZ|>¯Ô¨P‹êÁù†ð{?â$fú+*a]LåmB†½e†u~a@ ÿÌC󹱫À ÙpŽÑ§ÇÈ'þ$DŸ(ž õ6‹â¹FÆÜ Èö‚G^€e¢Hañ€r¶±FCßùÎÂÊú„ëðŽ-,É8÷ãs°Ï†¯÷BËž¾i’ã<ëk&å;[—z´]b"w8ÙGYNÇ’€€É¸^Å`Ô½‰Rh÷CÔ=ØvTе¦!~Šs£ÙylÅõ¹¦+{ùÂŒgÁˆ2¸ÎB‰bGH-@ò?¼&‘ÝæVT^oÔGÐÆ©'tmY I€|+Å¿g yšäu¶Ï ›£ùf?œëýõÍÏÝ©mC¸Þ°U¦ì–*Ì^/X"¬Îþw âTcR‡Ï‘ÛÄ»õPÓðj¿~Ç|5lV6ŠÀFc¦P*–{:ä»p<óÍLH^JÒ€!]¦:ú³ll¡ˆNp•ãÿ¼ìtoW‹+ZqLŒ¢O”þŸÈÙ'®)°bßrU`×uC doUvÆÄ÷§q„‹ÚªÝ,ÒÎ>ÝjêZì½ÎáÏ’ãIRÖ%11¥‡êóù«™9»çŸ8O¸Ç(wLHyÔª•Áa i.h3 ’ÈXt¤d’¿/G?ä ¹©ni·›ùŠÒ·<~!JÝc鈣É~¢jYk-m–µ8kÊ9¯Î@´#>A’ b{Õr ,"æ——¿\Â$¦¦º±ò ñø 7gZ•|Ë„DS:3£µÅ·ß³÷ÚÎhøì’àJ¾xô0­â`|´äÝ’”ñý´«“³#¯ô‰æ¥ÁŠSP3¦ ò°Ç<Š|ÑÎ"cöçÚÏ”/éç•mM®ý42ºëv6™„3ëexëW¬Òá…*ýd{$wM.Ÿ{É#Þv𯿲¤ld²•@z·8j¯u @í²p'ÞˆšŽÐ ¨•’ :„”4†Á+oŠíLCÝcþçÅì"\ø×pp¹ëS53þþéF§f=䃱ò4^kçÓËŽJ™JŠ¡Û¬õÞGÄ|À À>¿·î7r²T]f ¶÷GøÚfݘE²Ø›CM‹N,¬k„ýû-ìß0áI@Ôõ¸y“ã­Â½Ñf€£îžÔ¤h}x›WnÚ”<ærÞ‹_ác)Àe̱»ç•л‡Ñ¨hð’ýL9@æs)7·ið:%KÖx&½Õ ÍC£J"²¤¨\,—±má>) ¨t©RÎ92e¨ýÉX•(v³`¶©®ÒãºÚ)¥;Bó1¸CYžF®|€J2äöcžŠN·˜kèœt¸¥ùlvÕæöŠ"µ¦ã7»ZNεBÙÈvI›J5~i`ï?\ƒêÍ‹ðKĸØuŸB%‹U’€€µ5 :èH ª {ˆž`äÊÕ7-L¬‡cùº? ð}Bô>%3·™:{û͵aû_Uï%i¥´  5רàÝçðúë™gI°I¢KèŒ/ˆóG0}+jpÆÅ)Ú“„ æ¼­ñ6̈цýXÃÐSQ8t˜Pq Ôs³UûsFYHš1Ðá5Þn fGÛ$Ps Å.i£e',V±~¶Ë„Hƒá7Æ{ùÆ÷……3²³’»€—û°¿r+«„¦NVgû·Öm¤1‡mcʬ£fY^ñúêòtê›øÓg|«õ±Äs=W®kþ锇IÀ;·Œ¢w ²<9†Þ0NB¼F³+ L¥ëÕ+ð¤ÿ[©»F¡]‚Ÿòõ®Ï–¨Øw¿WñÛ>Ÿ$ÛBÄÖ /¶SÎK¿)ªü+ g<ê  $V3žx@ ê!ôë6©Nß¿–K4ß9ð[ Âùƒ‘Ç+¨þÅò„i”–È—‡ô> "’¦&vJð´¦Ó-‰HD¯³wí†ÈSÆIÕëÊÁî] ·0y˜ö"ÓúšÃ=F~Khéû—>÷MÔô{Ó–vê1%|ƒŒP´íùÉè ë쥣w”yîéÀÈÇÅ$ 䢈±Q 1㆞Ҋ¼™ÚȾjš„«º#lÅ2àÓŒ më¾R‡ö½*\5šÃ|Á@=‡Ý‰ÌÚ)$þïEl˦ÏF-¿Ša®â¡! ¯*ι^;E«Œœ‡îç:˜'ÄL𠬉lúvx_öÉ“ ]š÷´w´Ôe¡òèï~àgÓµ9ÐØÉËã-™òÌ·HÈ<,5"ÃÔË䃂Қ—B1‰¥õpÀpý~ åð>ñ,(ª-/Ø…øS¿ ¤N;&Í…QYdLõMꟸ—ja1`g$/¨Ä ÂInp:èòÄú5i œ[!ÜÇis%Øý#+º¬ÑH¬w\»[G)ÊGj²§ZJcˆ'þ´é¯lÉ;¹íïúœ!@‹:ÇŸ>3þ›ñÛ%×ùBj,qÄÍyU&®29(v×·q·hfúÕ¨E,º- ¬œf¨LTÍÖ5VÒý»˜`…,_Çbˆ-ӀĞڄ5îE³x¾O›&K*óKÊVÇ’€€É†R©É×T °`Ú3³GzÍÇòïÀŠ„|_™î^DLÛuB+eq·«†ª¼‘ÞÈŸ¤LoÏ~ˆ­Ñ”´v×å6–EU<}=~ñtKó§)^¯ïü$Ïñ³bsË;½©F˜´$LH1Èï _ ¯¸h¬qQuDUI¸êªYDªe’Æ™8«ú²äÄÕÕ‰‰Ô‘Üñ仿í?~RqLO1ƪX@œ·Uí4¸8QqJÒ´ºŠ‰U R$êóІ%e‰©ª²9\co콿‘`å4¢õ™Åçú¦°6í—*ÚMè‡nǞ䉬J·•ux€ ZWΰ“™Õ{­­l=–ótÜV\œpœhx€«I颾¤Ý—Ï£2»ñ¬_è¾  œÓv^½êÁ¶ßð³rš!™ÁºN&¿cb},5=µ"êÿ8 xDbâ¸uÇÿ-ô©Êǵ­ ¹JH;­6YnØ ‘ßîXÔK,:œ¬·ÁÍî¬Ã;:l3ã\:ûiÔªˆò%¥ñZm7-”ÌÛê¼óÜ_È]¨±pí{€°“Í5y’M¥-®)&¯€Åu=sŠ¿Ý®¹~ZXWËá—Kn"9ÈjåEŒ»§¯–Á2ó¦´‹Eò ’Nâè´»g>'ùû„71Ÿ1ø÷©¼½c‰7¡yHîÑ= 1Ê…¡à.›~ À}Ì¡…!}ž¸È5Ùç†á®á¢ [ÈTŽ?›)fúÜ)dy*Û®Qîn€X#ÌúÕ2ú*ÿ?õ1å./å•w6Œ ÚJ¤žZѵëmú—ö(-¨ç|æ5’€€ÌŠ‘°âò¾ñy ïãþÖüBèÇü°™'¶ôlètÉoNÐ:µÃžý¿°CmÏð®¿æBtÂÇsœÜë¯ÎÆ1‰mÇ.G0¥mJ¾ˆŠòOsU½•L ¢è|¡|‰B17<|SzÖJ®··=ïvmäËþƒ@t 6é^Ì%½É©2úøÎ7 ­!¶MÿÅý~L·üe%wLª¹Ø¹æ«ŠŒ…Géäp?j‘Úî/ú©¬é’„ÔüZ½è R©X5©7l¥¼º <ù^&k|Ç4žÒ‹Én {Ö8Hå°g~\¥´•1ÓüÈ&»—ÜêN åóëñmoÃsz(§“²iº,ȉZ8ë{ËXS…aGüh=LO•6ZÌ>«DZ -sðXÞ•lä„´¨à{°ó#a ö.RMûûÁåpÌ¡.øÜ}—$ì_ÐÉ¿ô°­ˆ0¼·³ofOyÐçZ'ýºÚ/>,¨Û„ ÷ã«ÿ'™µò–€ìx8²yžF˜Ñîç¢Û´v\ïí uÓ‘úþf[:ù`ÇÐAEÒ¾tùÃÛæÜÅL8.?I¦Mª“¼?ÏøgÕq|ò°ì¾IÝ“b¢ßqÍ[nÝ. šýXöŽÆQÆ;Ã-4ñ¸+p|Gþ¹@Î{é˜n<–ª-ùf¯È©¼¸Ó[¾õ#ò<•¶m'„€Í;>úd‰&ØäÇ=™ñóÃÈ}d´}Ô o9|sm*Y¦“™ý :"Å ö]¤Pþ˜ÙAÞ–Ö¾OQ/;쉫÷h·y,2Æom[²eâHü7à}ÄРï=2»ór¦IiÝÒ0‘ü•oyÞ!ùŽU%Ëð:‹fR~ÜÉ€bÐÊOu ¹{Î]å‚vB½a äÐ@8Î I½” ú™o#jǨ¥N‘0ã^CÆ ¦µ²[Žjˆ:î“R©J @{ð'± „øõ#‰³ÄR“<»¨€UJôFåçm»›E\øR€Éœ„-žˆ FR&>êBN²8'I»‹ /’hN³©[| Wö8˜¹Í¾óZpPcÉÎY]T¢z¤aHb"¾|p ß8«’PU€ßùZ·?rˆ§DV¯¾“c<(ãy½c·Øþmt¬œ­é2û—ØÔ²n“v’€€ÇÔë c:vÄ ‘÷bù+­?ÞÁ€˜ó¬]ºÃ +°—ËI;[¯{kßÝŸ¯æJîÀ¿wޱᜬ³•MýBwÌ—@-4n.‹Ìù§=V ká|7tׇ&Ɉ.Q~Ö‚ÒþcÀTŒÈ p"KZ¨V’J×%sªaGnÀÏWoè´%·®l›äEß°{ß ³e¿Ëß>À_èoØÒ„¥.5;ocšR£WO/òJèm|7£ì=X+ßiÝ®Z˜…”´ËÌ%Ih‘R%/*ºæé˜;òŽ¤Ê˜5.[ÂàH‚ $S³æ—m±c™€ÒêwQ·¤x,™ïgÒÅí"ˬm{Ü›§!ô ZüRxP(i·úW˜‰ÛÀƒšíÛ1îX”>Ü…`­<¾³öĘÔÜ›˜•,ö:*/ º >VšhÿÚ Ýe=²bAº>‹Æ•aP\PxBDsJ<\P1ºE›\“K|Ø€Ù%†y‚ªwšú!ªMºÆv%î÷Àæ$àXíyl(ËSùØ,¸2ßI!~€åÓ’«ºˆ”Œ´;(W¶ÁíQR(óѤƒLÕ/"ü9M»,Ÿsy $ã ˆ`-[*iüŒ0ù#Ó ì+‰Û…é}Ý6Ο<‰c'p60ÞU,y3*R\ûUnYŠ’ž#7¡-€º%¯éðëpãâúXi»£ßP¡rÙ€g õXÐ^|í\Sé’¸IÝMç½òKÀ–®/¶d£ñ WâaŠ gþ‚•‚Ò^IJ*­eú²™1æÞÕù ÐËû "¥§‹Œê„>©—ÐO€†£ÜR·…y§£{Yõ¨ÝLt—µµÔWlÈæz—¢6?HY˜ˆsåð'Ø’qPc^[‚¦O#/ˆÐ))\#þ @Ú¥¹hå·€*]`&4é¦[v³Ð&:¶d.ãV¢‚¬Þßpža<äô•¨¸¨MUóu´Å0•Už `,ÏÒä®+ssÃý´–kIÂrYªÏÒ©“®\‰ƒþö–{èÑh¶ÎèÏ#3O7Ž8axSwâ^þÁ­NàAÝðX!ì¢ ½=dñ›e î7–ÈÒÖDNöCÂЧÂt#=Q+å•4†½f=fÍ ²ÞtÙ6¤H€‚!Ñä—¢ÃN(<–=/H‹õ?’€€·#p{ÚîF#Œm”|°ì€Ü‘SPã;³›aÞï´µÀ@Á”å†-¿${Ë»C†Üwƒ7ã‹ôžº•þdLXàX>ÓowEÑ”ñê‡Ü(F–é v^ zÏ7çð-Æ@µß¼¤9 Dî±ÅactgcZî­öRC^œ®6ú Ùí"iyéÌñ‘ÛÄÑvZñïX‡hP·~¢}tFŽ5Òùð)ªÅEl Éi¡ý½¨Y$¹3êzdÍ×-rô¥7‡[&Òr@%¹Åhú½`k1õ¿ßÛÕ÷ž¸dGNí%fÌõÃýÉ ôr=k0Cog¹Ö¡…W2…7~żü ž)¹µ¥-¥q©Tœ Ô¢îšn!cåõwONX‘ ýÙ+ !ážq)…iäms{¬…X”žN[+Ò9$ @$ÿ¤pöó×b0Ñ-®°¦rý /q^1g~K?9†‚ÒPíË%òd+ –þÝ :Nr¤QÌÜ—ÙG(tg ít†§E`*¢=Cwò:¿ZÉ_Îm³*Ä_ô¶‚¯mÍô:#ýœÇ|òΌʋ UTD=y|qDУêzmøÛ [qã?ßcä2sKÎé³­žúOçÙ)Ra·ÊÖ³ýá@ôÁ <ÓJ$q:b¬=¸N·hû‹²^„ˆžÃvœ¦Ò &g“ئ>ØÓÕ¿n=¿@Òx د¡|5r¦åÎÍ´²Ê‹g¤r@¥lL-Xúãʉàáúš›Ñ'+ œ´ÉTjbÆ#‡´Ï×þgzqÅË¢šX`"¯4~zï°ô![*Nð,7»d—¥vòÕ ¾ï ÙÊX°hЀ§œy\¡|>FM̽Q'¹Ö ÓH¶ ]ÕO-N³¼üÊ+òEŠU.(é~ŽrÏ7=ý¯?öÅ©UcKRpªA‚Tw6+’;ì èÌRéâæ>¿¾d±ca–°–°‚-vÚ<©^DÉ Úê”HÞcK¼{=ƒ\´UÚæB‚ИR?H¿V¾7PŻɕ4ä¬p‹ ü‚€ÞÐT—È›7ßpŒ¤V«´Qñ¨Îˆed#á^ œÑµ † Æ † +·ê|¹’€€Ð ¶ a%hÁ¬é÷í»‹7/À^µu¢Å/ö"\MTµ=R§ yŒ³Ë^ûb4Å¥»¤ƒ+ÝÜXw£VH+îÔTsaÄEjç’GpÛx¾J>{Ÿµ/—{±…ÇoåŽW€d÷ôP~Ü>¡ŠŠÚµ—r‹m†Þ=œ0x'Ð@/¯€x”&Êâ@÷(/L_a‘£ZÈÐç´#çÓ8ïMø†¿xÙçµZE ÷w¡!ˆØª­’Ê÷ɈüüI\š?_,‹±´lò Éú—3%W­Ø)K*¨1QÍíÏJ#„$b®øÊ¶äfüN®Ä„T6á ~Ñ/jgüBMP,yìz`"ÂÊ×¢âÜõ\јÿÖ€ön1úƒnÒ¹uÓÞ ¸^X•[>÷ _(a¨#Ö‘Ý:VHq…FïFý-Q òi²õt¦ß„buá«åºéõ»ÚÛN€‡‰Ý¶ä r2‰–¯ôáÅFœÞBÌ_Øu`ÃÏⱈ B¨²u|'Tj ¥ç C9Oš€ê'™ÓõÔèìå 0´Ü1X«ßø Z„Ð!× &°ZÿS‹Ÿ‰úÕègÈÒD&û>š¦W1,âXUUjJ{N§–·ÒEެ;Æ#Iù(ArVЏc™A- “GrÍŒN#®ºSI¹.çQ.«þI½fõ÷ä1ÅÞï,™'€LÔàꤷk«¶ËBµ #F>»iAùñ'l˯Ú{Ô´Ré+RÁ^¥·ÂãÁè‹D].T5(ÀðXíÆ§:†ã1î8â>Èeo3ŒNœŠ¦r¥±ï5R`„a¯¸kªç Ó,S½yã0u¼Cèþvq+‚óµ·ÖïŠÊë¡ìzcaÁ?«b‡g¶Æš® ·Ïcó(\!ö¾pQ‘°jd“=Üt)O¬FÒ3¨/—z© 3jIJ³¤y„u¡¯ôðä˜ô%À´y²^²°:Þh8f9N½»²Ô¯MõD×ý Së1(EcÉR-¹`™˜¦óe×Ô¡‘°¨‰å?¢cX7i=yêH?»ÑµŸVkÒ£žsTVœ¶ Ýv±E²D¸h%ðéÞµQ¡–ž!ì“ YoU´ÇóÁx+PîÈÑŒ(Ù  pI…Õô©YuÖ y°ž HUžÄõä—œ‰1 ƒ/gç±uè*¹Ù˜fg•8Û¼’€€¥û›f­¹£2 Ñc¬yMÈ¿B8ÄJ+YÈ!9ã3mÃcBXóFò³ž.¦3o‰Ò¥ãüŠ‚;?ù°v€dÊ}ÔM­›ÏêÏg(=;.1œzû‹²«i¼‘¿‡FXbø )”Ie[fвŽ]­NªRÕØ—_ÔttÀèoÕ9¦ÎY!íÌõÈ_}l#˜Â +güjtÒ"W(2%x ðkWÝFÑbب åaçZ¼çžù»€Òæóª³*q;ßnË|€œ)À-·Jš‚½K¼IWø^àT ÝtN_¤L %m±‚C-õj$Ánhs# ³¸¹Ü Du¸ŸŸ÷ö¯,fQ¾Ím’Æ£–ž€°£Ý££àLÄKgb•}Í¥Aס3‡Ø¥¹Å‹F(è ¤ÁÏŠPѶš/3Ý3õÆàI˜›ð&ÃÈž O1îœ.½j/H²G€“±MÌæ:;¹ArÂtñr…S?*”ñ×ÐvNÄ!ÃQ9|¿T¼¦"Ö¨rÒ#"¦’€€°Å7~¢¦Þ è"–HÏÄWòBS ¯Cpà¶‚â„ ï´>:d”h›é:ŠŒ¯$ŒÖˆ®½ê¥˜-„É Ûð!HOrU¯(¬ó­’ÍT/_ŠdÝæµ¾‹Iƒ[Z>gG<¸Y´Vmó,ï ÷‰A¯éa¤§Úî³ââ&­õCÇ0v úëž`==å­2ñ»³HdŸGbÊe²‘tøNßëJBm/„|a:áØÑxãÄub_z \䌹Ün¹]ù”Ѫ_Bê+ÛÒxL2wçcçö~D&#¡]ËLx#°ÿ7™9âU¿Ñ×+Vvn‡’ë`5ýÅ?c…¡/Ú+<ß÷M+|]X³Dó¢TÞ#ÝŠ·j7ǰ~NãŸLÉYçƒMD—Á4ᄵ |Ê¢)¯úÂAÊ|ã98:ÆÑÛn³ÖÁY¿•nŒ-‘RÏÙÝP÷’FBÑ0GÁ’{s“¼^l9óK*[W|gßC¢’Æöêg­‚†¥â>.4\g]ƒz•l®îUhÕJû€žÄž¼ëç-`ƒÙ†gÂ!5ÜÃáGý6¯uîö šÌK9ŽÅ‚‘FL¸LÇkÚ¶k)Ï* a%¯øçåäyðÁj}{2XÜrÇ[S<£©õàMm„¬¼])y 8å†(»_ëjÑ|Òn”=©£Ètu t ºÓÄO‘˜mŠ•ð@øë`FÖ¥®§7™ËD»jëíXÊ¢-ûJ:ÁêʆÀ÷ 8 8«Ùa¤£t “èÈè˜KŸ…”Â|Îáõº›5§Ùp…»¢?N,Zؾm›æ+”ë›\(†B“ecÌ'…tÙ²ežü\¸UW-ª×¢ö è1”BÌœ¼äžÇod=ew„åÍ'Q'`¹þ“ ¿¡ƒÛ-òh\”cøû]Ñ%ÐÏú$®ç1"¯Ÿ|Vå.O~ò|+mÔj‡¡é¼¦îƼÔÿ™ÇGO{é2“‚ǶwìFB‹j“›Ô@ÌZÑë‘­ A.á »ë¢´Iq&üGåïd8 ·å€Bjî¥2 ^䬋“óQï°A£¸ÀUúhés;®Fªæ—K͈ýÒFêù¹'ÇîH‹Dq»ƒû;žŸÁ±‚·0†`O!~Y\cLÍ£æÎLRPÄÔÏ`¬%,ÒØÍG†-U…Ù,¥ÊŸ˜MÕ. “ÔF473]¤¥HØ =és2‘'ª„B3E¿ xt§'gÞåyŠyèîI$µ uß8ñÑQë'¤½’€€Ó¨õ§(hî=ÒͲY2Ö(¤ô¦ì–Fÿ¸ÇC¤OW˜ÆÊŪ íæ½O˜fB¹Q´*%êšÛ†P¯/Jšíwûöi}Ïa$›®hݪóDíòa$»@ö§ô=àõ ÐHœF­€Ø"?¿¬Å»ms³#"WÐk® a‘âC@²¢±€ üQÉ>vŽa'wQ²´«´j’Zaã€~C|ÐI–úþÈt_Ð+ æ²ëGÿ«¥¼5Qœ›ÝþÎ.£·Ý|ݹL¯'þ,XÈ\;Aº÷›’üy«0õžƒCðµOoPzФõ èË&ÚkÛ=Ê.Ò)•4⼓ AŠY3ŽÜo@€OLÁÏ»t)°X`x!^Q32Š><]œ¾ó<߬æ§ÓÊbJ{’¸\ˆ°KŠ@$¥™h†âùT»‰•‰ éômS7Ø +ÇœËS‰êá€!¸µk­8`hw± ·Ã$[^(•¬SjAs\ŸÈ.nD´x5dÆ’ä#øJ |³uŸÝÙ`Π~ 1JÛ–ë6Ð&åßÀy;5¶b¥8)kÚÒkΘ:wÝ^›ÝÁføôþIµ~p<5i¾Ë%¢¢Ý3ko < Ù.§ZµHˆ“tXÜœ'ÀÃÉãáÒxV2ê,62WGô©9Y4ø[–l¹žÃh__¾-ÔrñÞkµ¡ÕY4a@ÇÉdw 'q°Ô|Yûª(»=%ꌢ›q¬ð|'»›Ät+(Ö~ v³ô»ÙRÀ´UKâ$#ñ]ðàª_üÿÙçYý˜…®þÄ?âÿË•àe¶MIZùl$5vÞpËÝ‚©z”ʾéÉá+‹CBÇÝͮЇE[Þ5RtñËÑLqAÒƒt¯ŸÊVdªÇã‘8¬k€ýZ6þÊÐWRhEÁýå(¬­žÀRœ÷ý0êU`[ô¶×†ƒ\Ã;Æ:R¹ˆ=:bQ¨éôá@³•IŸïtù¹!| |ãT@Ì…ª4D3”Ÿ¢NIüŠ’¥!‘|Ð->×óH1’06‰ê!ÞæÚ]ó Æöµ¾â²g?¸ç¿Ì‹Aûòø¬è«ØãtroÿÆ=j{ÓËë®êwshü]"•Üžÿl²¥Õ ßc§¥7 !.–hŸ¾f>lÐ…x’€€§©ÃVØ2Œn·<ØÖ;‹–¢i‰ëŸÑd~ ÌQ——kúÊòÃ2¡Ã«¤TüWhW·¿ð¥sj«fð4yÆ4Ôbñ‘´ßˆdl`9ær›ÎÞÖ‡CóB¸Ð]?ûÏ~ºÕüÙjÌÓ”ò¸{IÍâxîí¯<8ÿÅâý!§Ûÿ²ø˜÷6Sƒ1›˜¥Ô”„|a–×'Añ¨zÅ´üñœÊÕ» ÐmØ¿éîÙ ÔË|ÂY'.JÕ^%eÁ3¿€±‰«Àä.9ì&݉1*Œ±ÉÔsüU(ÔXLt&pF<ß !~·úº£5JeÑþ‰3ïµÊê»I{ áWýpßwÙÛtã ÅÊKú¢ÚÕÀ ણ,¥‡ô¯gÈ;®(2bÅcõqìÖÒŸãcËÉEr©(ß°‹ä#¹ÃŽ1{&*«ÿ4ï±%T:~­J\ÿ±èL±®ÄÏ)ÿ>ç¯@æE/l‹˜Ð”*øCLk“M©·¿+.fÁÚáCêDõo€+Ǧ#ø%Æ ð’dN÷9ucÂv–ýµ9²×­»¢‹³\ÝO±üß `sëÖRD¾%nqqâ ³Ùû8î8h.|úB¨ÔÕS‚Ê tjÚ\i¨nÀ¡¢Žócm±†ûþËÝ}:.›0H_Œîƒ¢Ä|ß:ÒJöûæt¬æ!Ô¬Ö¸]Å…×%Îu@óëB{ÓãýdHÂÏqY"ì©+z>å•,èîiKÓ>Š-ÛtX‹A2­âò`B¯åîàŸ’~Py"yÀ?d#Y}n;no_û 6b°‰‰Kƒ;3… p4· Ø<«´œµ¸c¢úéwD€¦Û¸†IÆø†²uÅüKÉ*>jU+ò’¡Déå½·ÔÍ¥ë2¨ë±{Hzô&ËO‹šÅrö©›¾—“$G©¸Hά{ô3ÙqR¿kuˆn yŠT•¾5Î%³˜®WÖjëF€®¤¼ˆÂÁÊ]  %ðù33§’ôffòÒ²è£jTAžìHþåQ7‘ÕqÏ¿:[kO­HVÿÌèr!Õ:;Ã’ä3 ¹d©~A?”­È—¸ìÉÉ´™É ¹¶JKo{‚»Ô[²à®Oˆ|í¸ˆõ­Ó2kþæx+žD=6…aÕ²¾ÊÙjj]$´ŽáÜM¸-ð¶go9SNÖ“$u±2K°Ö ûmÅa_’€€›{ñÕÂ’èÔ3¬`Ù‡6ø‡iti)3RóѨ¶¸\Iº£|¬i¹TøPçóÚGûQ!™)ùóÿ|I’lÜ÷šeˆÅ§5(¡˜X Œ›² kÉ-°×HU,‹ë4Û¶ÖšÊMc- ‘ôYñ!ç´ˆM)û ˜¿~²}X(6hI0• 8< @èוñtê¾gŠÇ©Ú‡¬X6™Bà¢Âž²±ÍÒ•§1ÒºÇ çL÷˜¯ª—âϧûÿ‘„éOü8ì&}¸x9 ŒÖs‰6IüÞ¢ÂS¢ýì‹ÌÜÚ¯Û­€ìë{°ûÏŸYÀøDÿXEòYâ‰:ÕýçtÝ !áñ<µÌ£‘yÉÇWF¨ˆF-ÿY'v6&UTUgöòª–D”=ô’:—BuYøåžìÉÏ>ÞpÕ7öa·FºsùFH@õb9-ûÃ…7_eh ·úKAF*ÌÙÓ{0´´ ÄÿÉ&€X–‡§:ìg‚/ƒm:¿ÂTƒSvIÑu¸ÚR7÷LÝ~zî?¡\z;&"Nµ‹ËXJ´5o;š¯žÇç/Uã|’/~`a¾ŸÉ2Ž`é/ÈÞ»E”‘©wÁ0¬N Ú6ì+Þ¯x[MÜWŽy{Ñ4Þ×?»7Õ(sù¨p~#³•‚p_lÄJßÜéJ¨â;±^áOOÙÍñ?B©þ¯¤Ù¹;ÖîÙj?¾&¥9µåÙ‹ò—=äÕŸO.­[Ÿ5ÑkÒŸävm…Ð’çéž÷8<Ъ!SG²¨AR=C$L…ªð=x³Eè™ Ð#¹ž&}â‘°VZÐÉõ±'¨NÊnÔ2l¹ê`7»iwÁF²3µ„݉_µ­hÚh.ý²-žjíevô89£ßÜ^]×ÅÕ#/§Ñ¿¸sAv&‹ÛÁ»íP+ÿ\´†¢K~Œ6.žYH7÷ꌭ³õ"‡ñziVÍÃüÐc¤ëÄZsœûÂ…©åÍ+û¤p :Ì Ì­©»K~€Zu×çÕ¦ÏÓ‡ú93.¤ K3mòÿÏ*Ð|¶ùR«ðŽûKYDöµ‹WFV8â¤hĕߑE“ƒ Žkh Ó0M‚Q Á7ëˆÞ'6¶£a¥k‰ÁŒ¯Ð!,&_ƒ“™M½ B.ÛüØöjç’€€³¼ÿ§évÏ£§Ë²Ëÿ hæA¿q÷‡ -'¢öò7|‰ƒ -çѲlž¦I‚´&v•™f7¤âðmï!0ž$P¼þó³ù3ùb>ºP¥Èà=ï÷t÷Ûs"1…_?®¾‹DÀ–¸å@ x“Í8“¿¤øs Ÿ®-nK‡S}wJ&ã8¦NhHvóûßüäi´¨õóyÒŒ‰ÅEˆ›¼éÃmPóCòdÜ_Ù‡ÂÍ @ïrMë¢;ñ/ÃÞ×îqÜÒ÷؉,È ¡)˜ï¬'>¦$cÚl.q2²zõPբܸ&*12Z4‰‚pjNK „ò-[ï/nBÜ@AJ:½ˆ,Gn#Iò·Š±júy±Å”ÊŠ‰Ç5˜ùÂÝ!ùÁ…Ë{6ç/×¼Êvâ“ DÆ/0z™°¿¢ð0‹¤wÜtÓFÞåf‚¥X|éM©êòš¤¬ðÙµî=5$t¦Ìe#Ð\ÀÀ³p-Xjºwp#M®îþè5ùðâOçݲ¿.•ªqyé‹ÜCT<œDùÀåÌçðq’€€¥ ™tD3¦oËB`Ãâc#ZËù6ž@­ÐbF^1é¿;KÓ™>>_%o<ó>1˜â.wÍ"ÖãÝÚhÔŠ$Y¡”d·•âœù’µ|Ý-–õÄæ|P“ÓúÂ%Ì…E&•-(ê›R C’dÊÒŸ’h—¨ W®C:ß|åŸR㤅8ĉ*«Md¬|Iz_K‘g'Æœ_Ë÷mðHçäÍëõÔ•ðq¹»]ûREÖ…û?MóyãNí2„`PFê<Çv~¾1’U‚§XE± Åò…Ë'دp‹ÇGÒ$Íjü=Œ#œ¼à2D)ôf”H,Ù¸“‹;„ɇÇñÝåö° =Ò%ëÞõ5¶¸ .•½ªé—ÓäI¹y Ûo#!—eÎôNÄœ,]®Ÿæ<›–ØÅŸ-‰ôô@„j/"¡è»L»ç2—sOˆ–øA:^‰áM”¢ FCSfll¯P±²?ôÝVÌMeÌø4õª€7ÙZ–k¯˜¸LŸÉ¥*u;'[=²µØxWh²¡™"ò—vœŽaú(ÃÙ£ËßN=^¿Â¨i§âÀh«“MoÂ5ÿYhÃ_É΃$E(¾ŒÌdßdàÛ¶e\+L·ª¬uKƒy¬í#Çá„qP‹WÏÐæû#ÉUT_VˆŒdãÝc¿œAÌ €ŸÉž.Áa?/0ÂnèÖå ÖDžƒ;ñ)ØŸo. "Ä®Ó×ÏÞEøé r !IËÐÓºØåï3<39xÂvÑ&ìdD‘O-WgNPaÊΰfxœœuX8îpyÙ‰UÔmaTJƒkµb ë9¥RÅKà  \%¹_ð¹E‡L0'Í@YtŒ´¹¾‹5æ|ùÅ/‹£•›ÃÈi~¨êübÒzò¥mÃcά¢µKørT) ×|!HcúÀ0¢k7 $@Ø£è a>šrÔ<õ¢ ]Ë‹õ¤Ý{Æ"t^uÖ?5~•à_ ˜Wü!#¤+pûy"ËÅŸ„i"lÕ°z¾¸õ¤ß¨ý^(lÓ%|*9a&læ©”­œ<åj®#ó~ ‡û¸~Îé*ÖŸ ð¿…äU‰±>,+º)Åñi id\oŸ<`î}§SøEçÒÕ‡¬Nn¬¾®¹óßøÊX²À7$íæ» Úrn äXŒ\ÉÐT©÷ˆCYcǶ€8‡ ÀÍ9Îz°Q7—’€€ß!I‚¡S¸bC.võÃMÝuÒÔ3ˆ¿ãòûL¶XEÒÿsFÚdØ«þ®7ñ>ÈÎy^}‹ÑÕ±¨ƒSJï; ¼³Ç’÷ÚÌ}˰ß×—¢w’±;¼±R'uóe’:wøå¿¶æopTˆ¤•ïùä¼'KßkõmEîÏ8_\ü{U øúnÊ9"ß„ßZyé­²Mµ+xö‡¼Áú]2QÉîÌxOö)mla4ÜæVOÉ2( ¡:VHóoV…R m§ˆo€xB«tôð]fHl dmkŒüâ—zˆ½5ŠÅ„†êß LgDH¬ÌÇG¸+ï£>ž %YI¤üãaÇ[íǔ㛙<5ðN ‹]. óÏÄ€ÛQö$³ç„QdÖ^‰xìÛ&µvˆkd´O æí‰ ÀÂC@1Ù‰?m›NMßö'j8½!²mÌyPG‘ÚUîò×3iÚëÔ[e0sA I3øD;IÞè}¸µΘ0»ëý­ï Ä•Ý)†u£eÔÅ,Žrcß²w¯–;ïC`ÔPÛWøp¨ ˆÝ‰1/ôd·¸U*9<é\© x‚5ÉFów ÛПyT±QÃDá ”ÕLÎ{ñkÛ¡EWl}ÔTûjä.idñg?ðäÖ´¸kù{4«Áö:‹%U—Ggg¼»ý–ô´èî*}Ã^'×ò¢ªƒ)ŠÖ| )‚¶4Ÿ~l\>"èd>‰[Õå€~ŸÕ»¹Æad(ösžù¬î{Ç‘/ËHô¡‹ëw¾—bZ}ðU»/ÛG­¢‹ïÚ+oš'& XðÞ]"š¢;ö`«çüM ~µÕk0³÷÷Å›³bOÍ ùlnMˆg³½[^Q!E(—BqÌJ<(”Û}pΔø1”½§YLúàxæ'6zÈoÉ–+Z Rz`t³Ïq…ººù€Þ…÷ú„õ¾¸Ñ ×÷j>Í HÑ}4í ûjù×iÉ´¹]éYcy¡dBbÕVH3/&ÑåðJ¨þI¡ëG ¡ÂˆEÍZâèØ6iO]Æ6ñŸÛu\ÃáÙ%ôÓžGµ›žTGV²×4OåAO¾µ«º®WËmÐWqÀdžZÆíê]or=‚l@­vPÈ"}Á;D;Þzª• ¤Î’€€Ä••Gè`‚qNà ±ÄýóHM'¸ßr˜åR<8Ñm`6Ïù–3ü°[~J®^“Þ®ÿFX­°°P!µqsŸCñªZ™,±wÂöŸ¡2KL««+¶¡DÔ~£lP³zƘ†!o± '"_÷"h±ß6`>²›ìØRÿ­t…౪w"%¦œËOAxO›±½’´ŒF¡d+~@l¶%UbäN/,’h}#º7›'í,¹Pö9OÈUt‹ÐÌ‹´aÜZ+ÇîÜJ`8ewî1(§QcLðÂõÚâÁƒÊ‘w¬'&-·ë¿¶­‚fú@¿Â}Ò&ÓèÛ[Hª Äc_¼S¸nêw>¹`¸5Ÿºà {AÁ垺[\:yÝPœåü8R÷ͤOŽ(ŒŒSO¡b¸0DM ›æn«<ÝYTâ¼zaI<ÐÙ$¤tÄÖ´&×ÍdŽ ƒ/j\ fLx Œ5gDacv‹IÉ¡.mÄÐûK-6HJðS¢Û_Q³|õ„Âû7,ü¶@Ûp¥ÇY _NÆ¿½ÐšäÇPÄÖc27£C­³ëÃ×q#ä·èZ262ƒ€ \H›5Ô­+ƒso1¶žú4½‰£ý]IÞ¤Yfú >ÓTFâý–"©´^j ҷn×&ðÚqó¸r· {Ôùà÷~-´ƒB`]Úklt‰“Bg]Ðn­$_|Óf•bD“Iøo…Î$)'RÓïâs#]ÈL3¬º²ž$•+½ºõ&ÿñ¶Àlɤl4Ä£RbeI„·3ý(`î'Í“(ð\/ ¦ç_tZ=tƒÖÚE Ÿá‘ƒÎ|ŽÐÙ“œjQ3g‹¿g{KŒi[IÝñ®º¸Aʈ½¶~«‰¾46ßì‹Ö5š ƒÈï¸éz.՟ˉ$b½+Ù/–ZwMù°;Jxý1ÏC.ÌIFË PíyµóÓ èD;çO˜ •`œà…¥ÖàÌ\ÿŒŸIH^×t¼feø×+5ÎØlè!Öð.õê[Ǥ>÷b@a€Ïõô&vÛÂQ>Íê÷¿Ãÿ^³ð稣3~¾E“Ì$V©ëˆ>]¹CìË‘à,]‡îƒ‡f€6¶ÃM£ÓïnŤ…Ç4?áÈ1h;×v½9žÇH‰Tüì0WXÛæ ’€€šŒŠáÕî×¹†BqÉcú†˜1ê’we(päs'»Tr,BXØùÝðd3@1œ]@?/qÌ„Þðgß^X1g™? }ÍbWH‚tÔ£D*ÏI¤ÃJ¤Z¶¢ ü1·’Ѩ+èðs~FH!ᬸ高jëSlÒªÐI›5ôñÏŽ9{ëúUÀÓì¨ä6°ùbÜU²€ë3¼tÑËëMæÍp Ñ¿]’ 2:ø´ÇñyÆÍ!†jtë¿ç† )³xÒë‰o{mÒ¹ùk„u‘ÅZ€;ö$‹üsÔúðÂȌω÷mÀ¹ëÇÇ0"sRåÜ ©r\kŠN0›;„ýáU FhÌL½èéhx“Mà7iuà>bn~úç´¹4kq·’–îrTÛ­ñs·ñNP 6ÀvfÙ®PÛæçfaŒ‡#©ÛÀñ³ã,U/aÁŒøD­·Ÿs$-ø³ãØP¨¢jUâÑ=¢Ç ad·ðâñÚÆ}¡G¤ ÞüÏ§éæ 1PÊBŒk0$XIûÂäî+œ‰¾7è=` ë;XWw }=wY±g{éc2¬Þ%OÕ™j,zÍ-’îÚUƒ‚ñgŒùº+hçvo¡3ÌÁý58+n<‡ñ´IšåêvL}0–úð*1Êjuè°®$ïåX¢oÝF>áu §ò\ÌØÑŽ¼Ú¢TdÚWöâO&=ÿ’=€Ôd”‘.îµ'áŽN\Gv¡Y84z†×qö['w†~àj<¥ìs¦ñä]ÿ‹köW«-šs—«!‘Sí•KiƒÒ§ãÖÄê|ÑÃÖc®mš‰u¡î­ªO$ûÏþîØµ, ?þ¸JU:¸MYù´lß¾ –‰KJÏŠ5GÅÝ„JÃShª69è 0”¾©vм&Þuôq(PªØŒ%iA ¹‘¡”¿þ*p˜5„F•[»€(½ûesÙ­ÉÐ-¥¾˜ïª[²reŠvydÚpñ°Á Îñ Úúó…Ô´3Iÿó7ÝPTãê4ƒc‰lÝù¹W­ Ñ{ŒKLJß±°užàÄf»07Ît!Ú+U¶%J?Ž }F}' “v£X¶%š»Ú\5ë> DNã͵Ú\Ù‚:2Íš,B’€€¸ïU GE”稌kŸr›§ëï†0#ò¼< gôn~Š i×ð¼ q·µÑ·lHO…˜j·Ñ„¹wä ñ¥J¿–eæ=7Öá CJö!ˆ`Yg Øó:f­®‡–&øãªˆK©?—©Ô@ˆjï‚‹Æ„ «€u‰$vdWmÏÜXt«QÓ\Æè5+4ÏONísÆAù‹aG tQ™8"Pî1Ó_ÖúwA©Þ#£ pÒ,‡1, ëvXG‡óNkS»[±©çXg¨xW9'’oµ6Ê í®3~gù6AþIzŽõB0^©ÞË=sU'±¨]^`K!…†w<úI¬ðNã.a´fÅÿEé““ÖIòð±æFv•Ræÿaä)iÒ3SãN°7´á2œX~L ;_‚ÀFŠùÔ pz}9]#5½6ÞOÙCmUÿž¸Ea -L~0 gFmÐ'¼þpp®f1 žRAùk¨qßldeLÁ»ƒ!¥Í |£²êÇT…ïd‡ìÀo¥xÕ ÄÃ@hÚñ9Ý8)ËÈ­»PvsaýFEá©Li2m‘»`0^ij0;ö§'ã¹pF/c'+²ìµ¼ËeÎê’.† ¢•±ååÇÅ¥všPÿ«¥{‹P Þ¿þÞ.U#|I+*ÞO+€yØš²}ÐÝ‚Óï[&þF3EdÅÝ”:Æ·A¼FVãYÊ+«Òù«2ß0 ²Euº8Fz¥÷V$Ç+© m0þ“’ïc;ò5E·çñ85HÉ/€3©Öy9`Il~î=5·„Œ–ôàÚC/HFgfäø ºlˆººsø¾ÄÑ#ˆ]çG;ް A6³Xá]?R"|e ’ÒÎyT:„^^·“ÖbŒ «]0a"ZÐÝ+œÉ¡3êQ‹CýÍüƒRfwÇû7Ͻñ†;n†üÁ­%nkæâr”°¶ÙdÓ1¶([› è”çW>¯©/—#³ABz D-z£[”·^3øš¹Ó#`%'ÓBQ\<Ø[±G -$ikÓRK¼GbÞúmb cÎ7niñ¦hç ê±”ššvt°f·é/‘íˆ-A¶7Fn ¬ ùUlÞÑLv¡7Û¤P.„ƒû^Û¾iõˆ- ÆJçÂý®06þi™Xn}4¹(Æ/Rß ]QHì§áH‡ =û¾ç‘ôªJ!Mú(ý×°%x wbªÿ+èka'ý´Çß–¾ïJN7Åxß1®úÜÁ"u •0®hÏÁ³›Ù"*`2¤¬p:Ö…ê¢. j½ª_ÔÿoöéÆõXÐRÀF¹ˆY¶ýàÝ“µ`w„vZxPa{$I;¡}Ðëà€õ]úKe™î„iX9\ú½=þ$5puÍ‘+ oÍ™‘¡0ÔIy~?§²B¨5¯æ8HÅUáû7d×ð3çîãÿÐßrÑÏrKŒ³©äêè+¼S ¶8Œ»íõY=Òsb“«)æ5œHjã,2C4“Û¢÷7;›MGìríFšÒ'½|#4[&;TÚ ?~«œ‚é·Ñ=ŠO›ƒß—2{6¹j®ãÐú§¦¬“¿ì·]HCªßPýp’€€ù©ÉŠÏ„ûO3t»O×DÁcãTᜑJ%˜¼ëíP pJÐÒˆ_«Ùn6íuz‡Î6Ê#šcúPÀÕßDý†Ž¦žýâsGÿä¥| H¨“ùŒö•îéø2…N…i¼n6ËªÄø^Ýö‘»¸äúUs(Ò1Ï÷pã°äÝô‡ÎO0 *Ê)œÉß6HX„ç€À;¼~ .(¥ËfPØR0f˜cbEÊ»só•„sܵ¿º;½(œü'òÅÜò«Ëf¨:øl(HA—áŸi2pJ|ÇTýÓ…£? ugtYÅY—–ZeùœEË9î&Šá_aå±âÿñ5] IQç¹Ñ5cñ²©BÅËÂofw jÃ~ún{ßÿÕí ¦G6ÌÇqÓMøøÚ¦ƒ5ŠÓ‹tªü©¤åŸ’²ûîxÊt˜«Kx¸ÅÏ#?ÄÃzÂÁêÙOÊ÷¨L—³kÄ"‚òÆC$ œ8_eH+þcà\°ÉO†HT)9_2çŽõÀ¦B‘®üµ8Ã÷X`˜€ËN·•³=6‡‚Å—Æù¦>%3ùg[̇Cû] T)È‚Ãíg¿~;:Þ¶Wj¼Ü™¥?b –e>R©v/öüŽw@ý 5#Õsjä¼7’€€Ñé ”L2Jëv}Ê`•Ix~d—ã~µüª»¨ZÚ·1”n†\ƒTŠ-#˜Zvj¨K±jŸLüÚ©yN{WÔkžmEˆÿF:„™±^äBwð“3î: :iæÚ[¢­ÞßI] ±œŽ£o+¿Kò·ŸZæ'žÁZ.ÿùeî¶Ü¾­‹¤Ôz©±©þÐj0¢~„³Û))¿¿E|lÕ}Fÿ6é(¶ÂzC¬÷=âxÚNZLdŸ¬‡ ºbè­ydDÄä¶ç˜øwc²!$ (°pªyÈ B±–â„oqŸ“Q3ñocì`ï8»öM·Ó–ãñðÝ(n!›‡Ž-‹ð–Ò€!‹RP°›Ô‚ôé“l×kÝ0`é‚“Ÿ¿)çûiXVø¾ûfŽîö¨áÁ ²Å kŸ%ÛZR‘Æ{ÜʶØö+ôý[¸˜ ŠI‹; 8éð@ò׸ ½¼A[]Z| ~œàöG“D†x]⚔٧¨k“ž²¶HV0­ª‘ׇâ¼ÞõæªÒñb)ÜÙ"WÅ)eYÃáè«LÎ@L·müw$\½$ňyŸò]]¡¬uSNYY8fàKæ×.M½•LJÜÀ$JpNÙÙ j<¶½Ò1D¹à£[{‡m­~}Ó ŸU)ŒÛ]gUôT³Aûw$7-Û`±ôá!g%q³¶Üø Œ•BÒ‹VÃVoIÝÑ¢¤ñ;?·ªóÉ%­M.þ$_hð«ÃêÉž^ÒÐ2“;î_R:ÒÚ>oo9]Xà"Ëòí¹‹k³úÙ5q¸Òøâ¢£XzÁÁ°~”'!Q ^}DʽղìHÓúqFb&ÃØÄ\‘z.Åù¾û\ÛøQ÷¨ŽPp°È”H–±lÞ~áÉü}¼c{ª2W /¹PWbN­NMžúv‡M! ¾‡‹ðqX$ë7Ö0ÒçÂH¨>âÚå¢eº†Táõ,X#H™<ŽÝþ?ñKÇ%½NÚ cä6¡æ÷e¿R^¡DðÒ½|:[™Í%›æ€~ÞÚá¾zdˆGRkS¦¹ýTUmMvzíW:›G\`_ñhnM1Ao÷YæêÑ·ˆÞ9'µ ì¬UŒ»úè.sl·vÚÖOâT°â,ªÄcšÍ"šY½ùƒ,[4ˆò}£7°¼Jµuv’€€òQŸVr̰Z¼¼ó`cÜ·Qº *Kaû{ñ‘þ&m«M˜b¼¾S”f¨ëN(0U†H³L«{óqT'§ï8%6¡z%âå¦4“MX"¬HºDŒè01r7LšëUâw€ª¹v“}J*ÊZÐüòm›ßckz‚4íÇÀu:côÃ;ö¢„„*µÇç ò€Õ|T8‚,?õ…úeµVEHŽàÐ1 ¡) À®I¨]M>tÓ¤ ”ÑgZ|–\jÓ b®¬"[Y+€oñ¦&Ÿ.» »+Uý€ê—~“wù/•1”—qg²}G¿tÑ…ûM-„û·{\Röù )¿ú­NÎzÜ@<øòê9 ¼³Q\u¯<@ú±$Êîÿœ‘5My%wÜ@gÕ1:¾D3C_1=µgRüØ<|l EANÓXº…MH‹L’›Ò/zùS’ÚÖ'å.#”/œ¨0^ž¹}.R”9ªhT¤O”rᙼdŽºn±Èü!† ly×Ó ++¸ Á¨{ksÊŠoÈW?`0±b¤wñQý<~fÇÒ›åþÜ4õÍoå\T¡á…ãöìo,»—-ÅÃÐó&;S’€€ØOÚ¶–ŽDšÆÐ•õÚÕ8W“ÜgÀj¥kž6üø5C²;ßæÎ²›ôVšÏƒH°TFP¿»ƒª¬ûϱ ·|ENwTzÒË&z¹1®×¸îù ̤’Ù #—¶ÏµðNv”€§N×> ¾t¨CuÉx‘û8«õ²ßI&BŠè¸˜ç6,¸Û’R§² ¯P$N42Ù‘žC2[áÂZs•éÏwЂ>@ñ¿'&; Óª¹uîbÎ82cC,[qß@h|f•ó!¼ÁÏä UœÃ¬kºÛo9w”r›ˆ7! Ýì¤Uí×µqáž3μ[A†A†j6*Ö¯B®ñÁ3ƒ…é¯PEµ”‚šrúŸ‹D¬Š—ò’)н ©û‰ùe2¬èm™O( ,“Õ£ùÍ¢˜Jo\AéžQ¨âûÊÁÈünˆ{VL|0üËJ½û}þÍ‹\ŠM°HFþHÏâ™ÅBÚjÑ”iÿébCn®{ô³Æ[”£%7®µÂÀl¿¤\§Hû¢ìŒÊ›ø2rÅ(zØu®³+Ó.l9ýY8V÷pÍY~¤Ô»d08›ÖTk6(ýúµ¸ÑlyZ–Ù~<*¸ÐŸ„ÌYN’ÔÖ×Gb=Û5câ<Û/1” ± “@ø¡…Æh€‚:\}$×’ò .¦v!ûߌ¿°%a‚¿Ìœh ·|¢OK'“ç|+­Éyš÷o…·¥“¡ˆH»d[Ó“¢"ÜVHËí6K´Ìv=ÙN†‘¼‚$TxºN¸,ºâúccA;¶·queä\á—>ƽúº—tö¸6ر6'‡Bå —7D“œ!ÛÄÕŒ N¸¢c;ÉÞÎÙ‰.¤x“¯ZצR–}¯¸Dî Ïdáò2ƒcf]M³tº>‰s„`‰ý|¢6æ¾¢<|jÙò„ŒQáÞ¶åëFâ«Ô˜15á‹*(/ghdO+VAÛ|Ø6p¢WŒDm¡Há£uÚxÙüëDÏî< ¢uög:ÀOÜÿ]ÿǾ‹"Ž>‚©Š *Ï`êb6ál-÷âþÔ¯ÑU¨\» Jkž\!û}uŠ:°Zñ%TõyÒ*ç(8_ +éDßà@ÑÚ^8a; ë]JYFÙ¸ÊÊ\*?'îA­½d°³’)ÀÉÞiÈ­Ð4éS¢’€€ä;ÃmÃÚcªpÒï)±è¦õ`ŽÖþéŒT[ŸGU$q<;öo+þþmŠzEçA…-Øw»†¨†k\0iZ"S|8…›9\Î*ûzDIš¦É‘Œ«¿N+ås™SdØTOXbcxrJ¬vï ƒ÷swËéO•_v‰›ŠæÉ xᨪù¨&§Í) ›wŸøfŠÔ,ÒuŠºP#†!êÅl¬é˜FlG¨ÖÇÂÎ`;N@þåBž- duû4c{¨‰'¾)—NãS¿=|×Ã_˜¼ÜN¨_§µå߃%÷å \9XâÈ–çå+ÒÁ\¯Õ2ž„ߣÌÎÑ_“‹kÔLÚ !€æ ­1Qx¶hÿÈÙì0ûiY…;]¥!„Þà’¦é”¤¢£a™ìå¡&NÂá´ó¡þ–ªäà·½*g–¢‘Ñ…\ E÷ ÆÒÕA{§éŠ %…(¿fk˜Í}ÖeJEê5å3‚* F¬ 6 YJW*ŽYC¸ÇM›À%R©JµÒ™6•{"9ümã}HS¨Ç+ÝDÝÓúL#r`"îLí.ÖÃãæÒÒªOUb§s-Û¯üÓÄ@ïß¼˜{Ûãò…‹<#(`£W„Ö±“¡(‰ Û sx^Hýª}…ÉÈ.–'áªðaöÑ0é/$2Úý¤¹9âšBù†¿’S 3ãËR~à Ÿðð˜GŒç„ŒÛ.‹M7}¥è4°ËG"Ö›KÀpF…‡¨Ç‡`¸çq£¬O{ƒ$®?c¾Ÿ #xs„´´S¢“dÙÜžgÉí{ȯ€‘Ø«))Os™5-ì¸ÉŒ­×LÔ¦VÇKL×ÌIü¹„:€mo|9Ç >IÏ ¡ ¼A6×»u?§k¿Õ5‰u²Þ\fÏMy½¾ à$ ¹6Ž` !¼~¬Ø¬4±ÁË%Å…4ÍÑHÓ˜°vi›4#DTD˜\8©mš?’±ÍÉÍ€Ê8^Iâäç®Uey‹Þ£{`T^<;!ÙR'Òø~CÛ*ä8SÇ‹Ôjêö„Žþl‚äC#s-G'ÁS’ùzdÇÌ3\Á²´=ÿkFÊ´óp­G/1OüË,ýÜ( ~\}Ÿ±Æ~^2`R¨†l†`£ê±Eƒq*Í w8ÜyÄu’€€§ ÈÅÐ#k®Ø$Ù¿O+ª)—µ=ƒ)ÙûXÒ¢w;œOI°`Œk \_ØïÛ|ÿØéÙYŠú. ×9Z؉´9ŒÔ·Œê 7ïAàÞ‰•l l$ž?¤÷ âH½Þ%fd¸†âµ’àlk%"èÁ…G‘³@Lq6»L¾ùp©_¿£ŽÇ,x+_6ðÌÕ,ý•«€¹‚´2–çN/p3ͼ‚`ÉTÔ ~„ €kþ©-É ÜæÅÌèö'5PÑmÖí@µ²Y…ìI ÿrà±Q‚R›]¹”*¶óBËhÉóÈSà9Ö‚ÿ¤û <\ðRY)ëÈž0{*ƒ¹"¨a—¥¥É`,(ÏÖU¶xÄ{2Ðjb$´r¢Ý%0ÂwÏâ'\ “‘72 h¡:mšÃŒ±VáLöœDá“ËKÜ"4œ‡èÇÎàœÓÈ Š5Î1èK‹¥`Ën¦3PœáÑ@fɈøWÒ*¼°!ø í$p§Ï3Nw)?8fÝ|:&7¸ðƒ4TÝ1T ü‹·vÑ-¥ØU¢¹–¢ßÃÃܘf¼h×:¾Š“ÄKýKG_Þß›j34'½½5Är÷F01þ[Ø…|İMTÍÎUôšYÍÀ˜’Uë¹xßb,h»ëÂX€2Í®QÞ,÷–…á/³ªØÓŸ\å½Ù%º«ñQ`Zf…og‡$dâRÀüaµÖ•<˜?)È¡ŠŸ(rÿÂÜôxâý UõN(õf©Ú5,wf­õ2>£nÏ!§eªÖÕL-˜ÎÍè"k%™€â¢ÔÞÆ·Û5l½‰ nÔµÜà®$5þM Éžmk >‰GóÅ ÐP¥H(áœ6CÖohÇ!2dUAHYmÕ»%êDõkÿʓǽ8ëÆrNθ¢¸ÝPÝnž §—­ª½6ÆÁˆ•tó Ÿ`ôªš>ùâT¿ï»y¬„G^𧢦¤NÄ‘¦ÑA¯Y'ý¨8y.ÜzWê1=kl!®4,ÍO_½”íê(÷¥%8N96ºæÉçÕ}¶()ça”ãÈ„—-‡>Žæf f Ù®¡_ܰ;¦4g\AºªÏ£ ¢Ì%äK3OË`¶ éå ´Òð`DØ„€Î£vVÏN Î…kR´þ±‰’ž¹LŒ׬Fik ¯(ƒ»T:ö³é—Ä.ÀÏúS þ>CïUf#€_,©Nµ}IBÞ`“‹®EVaÑV–í'ù4SÄ^ËaçK¬|p`'TŽÀãídä’€€Â™Ø/®ò uhà!å—FýŒÑ [ªƒ øæ³—~ÏOÿ'ƒ cÍ}"I!3 ¤ÆíÍnÞ¥TQãú)wy6ͯd©È–š‰ kä9YØêZB7Z³–q箪RJøwOH‰²Ç©¢Ã¤Œu* TÛ{å˃9mým9¹Ôâ8ü‘MÆ¿ÖSü;ï}pØ·ËÐ@°2Œë{QçePÏXðZŒ®\ýŒîÿÃ5È:£Áí0„ì“+ªjí7ø&îhÈ)nËívÑ[.W©øßäW¨úš8 ·^>í_ hÎ]Ò Ìê½…“1‡®žþJ?™ä"‹+ëÆShk-Tn©BÝòÜÁÈïk„òiÙÐÚS‚j ì¼vü¾µDH÷ÜlÿÚ×Ä7Ãsì„ñQ†µÃò¢¿ ®<â8:K„Û¤Fц™²Z›á ?û;÷V bEEmY,éØÁI ¢,±‡†\xvÚ ·h…€ϦªkEpëù¥yvÅ6ŽÙ:Ë·E¨E«5«¼‰ž¾k8ˆxñ’uÒoûüµ5$W¥tZb'\75˜B&_mØRI”œ„n%‚¾¥QbNyVóÁLñÓÅ!,Ñ Ð=ßB2bäàL•Ä»?(gT´WgV!=÷öGûKP47²µ<lNtN¾2À8ë$©F]Ž0MG¼œ ÂÔ¶ƒ“Èò)_«ûû)Ѻbîg„u*C ‘+ã_¿ÛëíÑÑ4/\3÷4ª ‚ÉàH—²‹é›³$^êÉ)éÊf2Gd¶*ßÀJpXä‘4nºá ÙÐ3ÆPí½ŽbyY.Ûf˜@y/ÞjZaÍ^¸?ÉWÅV-†´ˆ'ó ‹ÒÛ’€€áÉÚá”·•þ¯`“Óè‰õö;o#ü…Ç3ån6¥2ÁÉTX´ìOäPú”^–d2‹ÁT4Ñ)¤»"Ö÷ž˜,â¹0S9»áœ#u[cP¹ººî¬Ü“tf„M<³½ŠÙ©ÕLá8hóÐéD4½BßÅ­Ë‘!\µ:oáEA»úâ˜7à=føÓô…:©„퀤?| ½2ÄDÙ›t莻hÃ!ã×þqB1[Û¹Ìuþ ¡¾èÐ)ñhÇÆ®×Ü\oa/°r`¥9‚Fã_¡Z¾ù—*¡ÒToÈ’ßÌ*`Çà}É Õ†Vf§ÍÔEÊ«„À ßÑ'¾FЦ²w‡ ýÝšÚ%¥ L½;0´Üº|ð¦yù}ÂQ¦)'½lß'Õ3“ùw%´0»–å–ÖÝ<^Íl´ï¢÷ë„Â?ûëÕ´÷[LÓк(ÿGzuõ d"$è‹|‹„ØÂy¿ˆÇ PGŸª4øÄÛåÕ L[àî’`rŸIè6«ß¸);ö2Úà\@~Ú8OÂÒ~§MIáÝd¡~Ú€GšWÔм3bŒÞžŠÏG ÌèP'@JÓ caN$ÐTKñå8bâ— £°î /ÿ"Œ¯mÿB9LÿìÌlgÐÔL;„Àƒ¡üiµg ð‰äã5"°,n"Â8ÎÀo-¬$.’‚ÝõwVwéölW øÉS*TªÄ (Hç @Ç•Y÷´xøyÈA ±EPOMÒI.¤ íXE“ãj©fþ>…0’|§›¾ÏÝ Ò^K¨Z<# æ]Й•Ÿ"ÈÀ?^Jªý¢Praï_ÖBÒØÌB8ÊdDº(ŽÑ![k©‚¢ ×êp¿H´`›û ÝäSõB2$JÝ/° í€IdéÃØUç µ˜ÍH2‰.,Ó?ñ& | Í℉¸€®«ÇíilRqhÿ7ó|„±ïf[+FÜ‚ó&ëoB ó6}©6Þ𣠮|“³U?¼(ëAÒ$›u~» hj¦¨œã\O6|Èû(isM .7µ_Æõ%’.ƒèr¹§1~AÒöQç_½ƒÀJUŠÚÂHõ²=rîXެÃ8à•ćm5õŸ2¶äPdÂ⋵¥vd1¼WÚè?ÔöWå²Î×8Ufò§©Jö÷¸‹îÔû†£DŠ~®G­€®¸Ú"ÁÕ’€€­dBá{fYŸºµJ–JG 5Ôµ8ƒ°)¾ ¡i#¡ÂË/Ä.g±wxžî ÖZ>ÖO•’;*Ž‚éþl)Ss ½à·bóºïí¬ìé6à b7Ë-Ý_,Ÿ™]¹2ŒG ¡á#ôj£–äÁò t(yö ®@.ÂÄçòœ@ÁQÿî×(¹|n£IÚ¦ÏìÿËWû’X§â£".éŽG9TEp&%â÷SÇoÈýT¸öÚ;ä_¡X]``™=\æQchol‰2ï2ÜTéF™@ú}SÑBÜši‘ê ¥q-dñçnæ/X§—§ç8t4Þ–c7R2zû¢‰éf€ÄÕ*ûãÛ6¾,éÔG íXÎ!uv—\9‘^TåêQúÖPÊó«S¸Ìò,•ø'Ž á®T²[ù¿ò;"¯ÙžÛÖóù6}ª€ÈXû)) à`ÛU÷³¶EôkРëQQ/z~ZYѾ jzÓ°’÷`U„ |ŠâŸf/Z;æàJq¡'(h<Ã_W*ÊÿånÉ{è²çH #\ͦuľìx‡yÏ›Tœ«ÐŒ]#‰A,m‹ÑØB;((PåN®(ÛçSŠ(HËþE{Áe‘$\Ÿlˆœt¸žAÊë+Å+lå_uƒ ®–3\·o£oÚ$0k¹mÁ M_|æg¡Œ¡ÖÐ÷èÂwwƒÍŒ{”qˆÖÖKqš§âþ÷¶•y<ÊÙ^@Ô \PŒ1iÚTÌÙÜÈ„ÛP>]õ1³Êa9Úäâv|˳CbKgŸ–ÈÔ dqî«Ô³‰É¶0#%ï{Ã"z…iò¬ ÎAê§¶djØ|t@ÂùþÀ4Ø>\¶΢3mqºô9Ó©/„ìȶoÒô| ªN7Uè¬&$ŒFˆwùÝ_ˆ´©Û籚˓Ù=>i%ÓÂÉAÕ­ìÙ áʱˆîÄՎ׈UM—sG:ÙÒ®à””W­µT}*ÒYµÅ&ÚªÆÿÈ9 Bf„ëV^ûk I`§›lDK8ü¾uUû'Ó?šb#béHsÿ^}`Ì1?"ùKÚ~+Ht¼Úãä³@‘\->„g˜Æ©œ½ÇQsK}‹™pÙÀHºìžpS†«ÝOõÁ`ö.—wÈÈU×üò´þ|ñYv<¿n¼í.‰‹¾Blå³’€€àô|5ö¨Â e3Ý%×·)fL`;ÀsÒ±›2ùƒ,$Q‘„çòOxýrY¡dG~D;ÓHí¿ô¢9YLƒ6vR”†,ëCÕ;ârœ¶ê9ÿä'ÏåÛø·“j! [÷Ÿ¿M,U?ŠñR!6ÝlÉšÀ·%ÂïSôÖÀó$ÞHTñ#}áö9zxÛasÖzŠÎ1»;}È®`7ÌNá¨oü·Ê>Ì7g;[3©fkeÅÕŠ„l^Åá¡Zæ” WˇÉ;oÎ ’Ï®­6Öîv¾u‘Ås X`H‹;à `Œp” 6âST…¼ATË"ì1iî÷Ïúw Ñy_"Ãx!´‡¡Ý%‰[«g¾ç)¤÷dÕØLãE%®<W+6ùÚ3*]\¦#¡‡ŽÉ¿ß‡ÿ6R˜ÆrÕЄŒÓþå‚‘-zö.vã+ÒµdŒ†ÓÉäa·Ôº2d2çk‹òç*©ÃühD÷¨Šö3tl‘*ýŽÞŠ¿?™ÜVäw5H@¸´.…æ'»¥íÑòçƒ8@Çõ]q•øÔ]•Þ½”åE-¯ƒBž40LnÑX], ¡/R9N©^GqØë ør%\C…ëZâ² {ÊdÈY)Å–žz¸(d›h[ S´¹™ì_룦=ÀÞ?‹:|¡ø‘ taV=]??Ë<áëÔJRø ¡ ©<##qî¾ ƒ%HV?m]˜=“¹…sñ–§‘%Ëœ›Èi3ÍÀ ÝÒèrë/ üÎ'w©[Î;ª*Ÿi‡vSëOáiŽÔ5†ÿ“Þq4¿Ò޵m ÁtøÂÇÞþ³úÝR;ÜPç®­RŠŒYýU23Lcu‰•¤WY |X¶e›ŸÃ(ËšÇa&¨ß+¾L¼aÂ;7*;‡âIKè’åUBY~)Ër˜èlÃoÇxæ Ç9ò~.bP3¥ùUêT(Œ£WãO€ôRÍžZ¿ nù- @Ä!aÞ(Ä¡¬T4šR¤»¬>H0Su‰ôœiE‰#£w36†>º9—R©ÐyìÙ¥ª˜\ÃMú zS'<âa Ë-›†Þ¡ç±ð’Ê06'úÔjN >‚¥·w1å¹6ÕeH‰= áò¦Gî=o‰=/û¹ŒGGp"õŒ]±ñ¯à½UÊÐh5sÍ€”ü hþ|ͦŸkÎúßný¥Þ»†y™û£I¶ðÖ†ü±óo…²¦Å¼6TMm¦ΫûͶ10·Ùr¸y­N!¾6ôö) ÐfŸôcäÄÀ O‡HÆâèω©ðÓëó½Sa݇ø)=[õK eSÔÀà×?Wð—½ÑáðÁ,#–ô‡¢õËVByvS¾œí‘Ï"‰a£Å\ÓÿÔéà³'à Ò”ƒk˜ç]ÔQvßÙ=Ì îWıϧÚ× [¢ÕôLÌÂû*Oêèwßâ>#¿Ÿ6ÌþJ|bçj<ÔœÍOÓei¨°ý¢:ùzàS~ðþ8Þä@8ƒðR#FB±“ØÒÕÒ]šÂ?p5oH×U §j´K&^Š­tÇ­×më#i.¤œÈLN…B”õ M •*aBŠI«Ø N÷l¯óÂ,˜qͽ–¸ÞNA?²Üfʼnif=-ÇèG}›j§…cÕ£jy1‡8V~tž2ص·A|e«:méìêLÁ&eÁÑ…ñLø††·Ž€“w¶ª¶Sa{¡¢ »3|í5…z•Œ#ìSÓò¥A^ÄšF'ærÒkIFGÊgàS@ŠæqÖ¹òÌ™E*ÉBÙ]þv‡AaûÊtUÎI´w/¾Vß)w¦icžN ‘m]@€ó±ðÞ¢þ‰=XäÕM°ìt¾¢˜f-¡ìT'£'3S¾ëÎÃÐÒ‡¤Jo-^)õ!èMiD6 î2²Sœãvîk7€úºG’€€è 'ú«UÍ4’Aˆ7…ËàÌgè(¦.$¯9Žý³-Ò`Šæ¾ƒ>ª ~ÌœçÞ&ßLZß«N‰u=UÑ@€òPI™±jçÖU#?JäT3ÊÕ<øc-žDM¨=¿¼“WG}SGoê)Éeœ¢Vtié¨à2¹RFúOxÓzXÕô,”ÜŠðn!…K/ÝjÉµí¨£Í’u#4ï!£Ig§S¤h‹"·½§Zã;‚^åR¼äݾͤ0UÿUWq•KµÊ × È%ã,·(û›$0µþFuTª{;!}ãrP½±­mÊI[Ûí¿ÃyÙ$Ó#h1Õ.Ä1\5D1Jíš3Ñ/òa`$»:fe⨓Þ_ÞÙà¿’^M„ë­V5C³YÕß ïãЇ¾£a¯~Æ0Ô´µÔ?Ww¾Ç@6w=–<Ê• úê@VÔqà4cÝb‘›tgž—t¨Ë^d°Å<·Ù§çk]n‰(·Ç®º“‹j=s #K†Îù(‚éb…#qfƒæ=v %z¥’äë|g¨¯SxuñšŠ›d†B _~ñøÿ€×ÉX‘ícù㉿ähæ_Tô= X麎­\)ÀÀx4Ö·Q(Uüʤ8ˆ7Ëf™ž»ˆâ h"Ä‹.zqÿemß#&>9dð“ù Nrœ`:KŸ8³oº.á¾<»#NGc(˳»½gæÔOþE —×P 2ô3Á‚ Ô¯£'êêŽT= l€®/ôÐBÄ‘ÂDeÖµ«øu4êyIÇQ÷Ž‚ ^©HÎhúòÁÿ?B¿O.[ñÐÏi\=ÇÔà©q¬´VöO¤Æz’º©ÒÞ–uìœ3PÊœ›_öÏÕÈ8M{qRjÌRþçKý\I㸓³=J¨]ë Øì߯s¸²Èʵ¦ÎÝ[;:@Ê•ÆüTgÞé#ÃQ;Ÿ ›ã¾þ§s.¾½wî“û1Ïg >ÞyÑz¬è£Ñ‚Цhæýjù±‰š.Òðµ6Î÷Jdžàû¹[ìvå4+vd«8g¸7](µ’ùæOJ>dOQ‚V$ï¸Êoì<Âtƒé¬ì^r“yÛãjuÙŽu’ðÒSt;£¯hKòûoûm+öëÞ ì}Y{åb-?‡™ó­¢;©š*—£¢ýQá´Dô …)Õ›Bo–% gfÓmêfžÝqêÈ9Ùá|F7=I Ã9ùS¡ò­Å·ÜáTé€Ü{ÏÔ#«˜|g¥þÿó„”hã´a/»ÐM]‘=Ì‘c†S†Ì8ÿø1Œžmø6y£Å,yÍŠa c½A15¥PÁÏ'ä =‹ÞÔÛóœ´Ý©×‘¯ºT¢qÌB† /‘¢ÁWØ8¾o—ta¼C>(ÔIDùÙW=ã‚…j õ›‡–?8ßÉœ\,¶‰÷¥%¦³r90Ÿ‹Oa[–O¹ˆÖ·öOê‡â…e'´ò ­â1çb2bTy_È ¤uÎy>݉R«`<«­jÕé£@ÞqdO–)A Ù £$É™ƒsBá}êNRCìøvéXs’€€À˜Ãü¢û¥ ×–¯ø~ácÿ8ZOUõhUhêºK€„ÿIð¡€ã>W¸Ü*‡Ñ9ü*»§p)íg¨ón*Ezé •²pMÔâ½°&>ñ|6AÇtf­Üðc\¥ºWtØ1ÌØDáIß×´ô|!íc¯ÿ_IÍšmI¶î[Q®˜Ki(_ ó•†3ò.ë¸_á1sÔ¼ÊNé=þ ­m0¹‘—Cþö²ÉŽ+'"»gûhG'G?ß7yHγv¨mÊ Z|´‡ùk""©ËÅ ÍÒWå~¢…BÜ<Ô™=9Zño_CYªw3}騇Íä·U«ëH‹1uì_ ìó™µÞúc±&ôÓ(]ŠZ-XÐz^‡}Žõd½ŒDË>dÕÀRK+ÁõâòNÜ‘$¨åÜŠ[où¶_!vŠi§;9­¼kÎs¥&Ö äj»G1¡T¤âîÅœnò¾ýØöÊ÷í—ŠÏ”›eYÙÙ†P@Æ;”—öwƒBVÚ{zD¨é¶­æ¼¨rõäiG émm» í³4ž±à3‘hÃ*MÐ¥j±›tÂ2–„^Å)©:ȼj%á";n&OX bŽLÃV¸€.½·B®nÎ5¥x~À2ÃYÍ£[ß(/ìͪƒˆnßî5x*c—$ëvƒ™ç;àgnørÎÿ¶F ™1qù¹½È—¤dD1÷ã™WLÏ‚œÆNaÒÖ‡âºÝ Áš^jŽjÉë¢Yø^7jáIœ±z·8{÷èr2¤-E9°=C–BÏ¥³ qP'x1¼]¡wÒL’'upr¬’ó\Yݵ4‰mºV-""{œ0Ž&‹Û¶ØP-q׬¶Sš!zXì4NëÛã0­J„:ùÊËBÏÈd_gŸi¤Ðàëkxeo¾•›É¹gÀd*‰tÌQMwqèö›Ñ÷ˆC¬Ù·„ 1MðJPÀdšàµ`ÝXæ.U¾,­¾6 ÊIpvæcl!´êÞ£6¸*èYDŸÙßã¾ FñX>TfF½¦nî­XÔÄLå¸ÓB‹ÀªÜÏ€ÖÈˆáæ¾È8ßú¤½?â‚ðœžï¥Àý¿"¨:S¾Ò&úì¤t¿<‘nŸ€’v† &Ñ}Æcà¢þ_VR‡ì[“w%šˆ+KôüÇÕØèÛ+Yžklž\pV’€€­ó6þ¶„—ép*…Zbwi..%T™41Š?!„ & ÆVkö|µEûœ©Eü9­tè¦+"8^ïÁ=+`Ñ—ñÕ⵿ه¾ÛúÀ/žâÆ)!ì*<3™6™òÖ…$ƒyÇ´Ìùç²OF¨SÓ5ãñÉCöμ÷¨)Ŭ@òO˜ß>V³{ý ÷8¿²æmQ8±k­ÔƨíÃÂ/¾ù~žgQÕ¯¡¼R;‡‘ãm„I¹º·e hO¬ c"í­ ?Ð5/ß-e„ ñÜänàaÆü#>£§q=ü“ë9üʪìˆ{ô"ÜÅÀ—(qÑÂ'é‹  Ü0äoº‹Ç‹œIkâùÚ»±» =!½ïS\ ¬:˜mKäfÚ™˜Œ-н"{2#wz´WsßK>ù6WïÛôíOÕ=ìVõ¦œây3öÝ×6N8é‹ס¥hêö¿ÀUÐ0[Ê_Ü8EòºE¥L£gébñp  [s̓£<—‡H3G(ÔÇttfýoè þ>+䙉? ˆÀ ³N¢×böô‘£ºŸú i8œ”kZFAð³e‡ .Ü„ÿS¼bP@þÁŒJëq›Á9½EY¶)Z!U>ê®Ðò¤l·_#°KÛ· h7/Dçñüâä:ç¡ã¸Áá \œ0áìØBTmÐ…‡úKõB‹£­Ê/›–ÒøZføÉ£:%h˜§]7aJæ?‡¶ä”Þ J¯Iq‹uZʶ+ÞWqâþc`hþDjôœ1(ÏpuÚZ¦¡l›€oâøûmHt+ƒ9¢ž0;Ž ûð0¨äU°j _îãgÑ&cyµñ§}úƒ7^]}Zkƒ¡—û4rñ±×G Ò'MWšÏ8q±SQ¤¼Õ/ÅàŽ‰¿)bF¯÷Ùè6”êó:!î;Øüv±yVòƒ+wä’c}£ö4F„$ÏI·é}yª°¨» ‚ÑRJYØIÁ1€cÞRßq§@ ÈTÛwÚב¯¢5ð·Ê\¼ì%_ÿ 8ÍhKú Ô£+:5ºf%Ð9 ‹œ/¹j©àkƒL`éðsT;ìs†v¡mÆ 7˜ ñ–»üÔäêø2Ë $&²Q7õ!²‘ð&Ê'Í´ô™ÌÊOÂIXAq¶fy œxæ’€€ÃÜ{¿YÕcàªlUÄ;›¦ÖP'bƒUFð|^¾ "̧Y5t_°þÄe }Çç⺚lüKu™ ¯L {+@1ó¡´µ„ 1q§g|ÚP†¼¸'ø.ä‰'‡,ÃD¡ZRyù.ùê>Ò¦”ƒÿY¤ŸèPíÓo,¤¿MTKé">¦¤@õC69ÌâYã†>ü²"³QöŽE‰üVUDp2±—Ÿ²/Ïg(NÒ»² Åþb·ï«… `YB™ðÝŸ+ý>óÆß¾sß)’£i÷Êû9ÇÑ#ÈÒ <"v§ògLøÕp$fiF(¨ÝµÚ–§)„ÆÍ€´c'ªþÕÔÃà üÊCRûí=Eφ~* ÑßdgÍ…zŒš"yœ=Ü ³ù¹ÆhCr]&@/±þ#íkæÐ hõ©H§ƒ §Q;!sŸ9#ªÜLû/O\X! ¨öÄón#«Á6Jä_ÌöSÄ£ÊóCAp·'fžÒº»8„P®7Ý•w´róÂ~RT*‘õ.lð%Rp‹Õ0õíZ‘[ÄCä´ûUÙ£#z¿%´š. ‹¦kÓ˜ø²±"x¹œ¨Í Rþç«i·3ÿW÷&Kpk†Oþ(Hbn“_­WÕävgoJKq"W`Ð"¯bf‚3ݽ¼ùì5]M^5³ìœxé•èêßZ&œî ô]Å„í?2éÐð-G´Ü2kÝé¢~Ág)*z¦q6z£ÛÇ}u<}oY)´Eùfa\)…ø4D¾–Ó³ï4dàè9z“v¯’È~Ë‘rQŠurÍù9*B¾&Ûs_ô®²èÎU|û ÔEE/×D{Ë"Í“ Ñf° Ze‘xÎ^ Áàª%dÏô6@?ÌqÏysÒª p˜÷J¹Ò<³Oe['sòL»’WÞŠ¬™@›1ä ê…Ï>èü†b4°±¯ëÅ´ zÚ Zdfî'ˆ ¤ë-Ù¤û#/óY²z7,õ¶äG8Ä•POòá óܦá÷?€z2ŽæPŽQÎ{™X—¯¿°‘,¦ŠÞÿ†á¦O%áÓh¸eÀù &hsÔ¤SQ²ªÁc2¯ŠS›|IÉë»ó‡½F†â¿HìR€Ò èÓmË«€UÕÞ& Mã‚­ÿñ†ÿ@#Å|«b…Öt`ª•™m‰NKuòÏäãI17µAÅbö²­…{}ƒóÔ\_¹ ¤†S÷Ui‰ùçTH‰Ávý[ê)„M൓ Þ€kJ¡¬–ò™…–­Ÿù!ýCÍ3\û NX¢ &çe ÝVE-†ÿèÕÀáê X®Rð.ŸÌ"瀦ª«ÞêÒ0•ñb ^%ÝÑüܵ¼MßïÔáX´ƒÛ½MÌÿ!±)ù*à©dسlè;QƒDV¤üô¯:=㢢SR’Š1’ ,ÉþÒ5CG?8 ŒÞ©ÕK`jí>˜&ê˜ø€t-÷A§ÊÜž¸Hedz½õÆ_­§!B¶…º©¨á§©˜Èƒ)üDF ìã™UT„“åÂ4ßéò.( TäòV¿R²Ý·ÅˆBÄR–jЖߕKB`ì©ÎÒ©ŒL´^™‡é›Áyâmø2¯lïdY2Íâ`Èóì›#ô–‰Ç*éÅ€ìÊ#æ»"ðBÔüØð³®…à0&´è§æTzB¼íà+öEbãÝÜft‘¢Íz×h­Ñþ ÁðLú¯è&|ùÕ…¶©Êò«y<¢•à ‘‹\¥.ÝUl'Œ‡~4Ö4xo…ƒØ¶“áÑÍP‹ê1ý/†MÓG¬g-n+òGìh¿Ýc3›ù²*‹ ¸âñ·A`·†áò{%¿ Ð~ôÖ˜Qã„ú‹Ô×{?’€€Ü·òðO8å“öö‡‡ê­ë°ÀêŸËW¢:¿Ç%¾Žõ—4¹ëõäË)Âøn£ÓR=Ž?­ €ªõÀèAï(¢Ý—ä£=£"'ÑE-Ihƒ§MS< îO†£‹tjfküÆÙ»Y°“•+Æ­] «¯ú"[®»ÙSg5¡Ô…{~giz/S¡rëÌú%iEÑ6MDÑÈ-v€B§óRÃä}L©Æ=¤\j#Ä‚&õðSdá)JIÙ{VKô¤í?¾Îxhì`F^ǃÿš°ü¦yh΃–Ñi¶B‹³•ÂëÓíûò6Õí.æÄp—w:T r¾ËÐ,¯ñaÁ7ëºüs;ÂH]‚°³ÀP4ÇÇ9¬Øqs+èë/w&A÷Ô—eÙàN¹•"Q£¼G!e„t¨¨ñ‘È(O»&êÊÑØàJ›F숗ûIc=“í0ˆßËoÿî‹x" žö“K$$¢¤L»Uœ…°]1LJ'×Jä)ãœ5Q,oG:º.ŠË°âP§|úɪS¸}8ç\ êàUý\¦þ"dÂË€¥Bµ¹tøÐq°üH Z¸^ˆê£Y.Wu;Ï>˜E>ÝÙœOnä\φd¬2Qü<§œ‹ ÏYFË£ ¿¤“dI¥‰]>J'ERJ•B ¡ÏYï£á‹¿Z®"3c= ®™}co¤ÓÿE euúQÄãT¡ø­ýž±db©„V" ÛúÌ6ëéÐ1¸Ã êÆ.˜:mP>ì° Èê»{­DØ‹¦.—·ÿ,od$éjé*ßÝ òF ’j»´¡eè!ʇ…GWEJ-à²d;#ñôŒ9ëÉas4X[bK$KˆÁ™“Ÿ–0>Ĭj¡¶Ç{ï¼R‰ WŠ2«Âíb½äñ{±Ã¬”½TÈTXeÆOWSå’Ö_5{´ ’+'7Æ–JõbÎz˜ëŽù¹ª±ž|‚…ù²cVS…Bþò{dæl}â`ÓIŽÃð¥ˆ|c=` WpxšÙ@ÿ*Í«x‰]Q?÷úŒá™²€(Ľ P2Ø¥ª‘2‹îM°ëô· ÃMðR’ú? ½!t |=‹+êEks¶öÇx®šÄ%‘3ྔ\L/Z· r“8î°nC 1â®WšÆOùWHVØåm“\A°J¨’€€Ýgw?¶XNáç)ƶ!²›šçŠ‘ö\˜…®RT¥ ýšûM ofOšeò;¶¨¿QêOÓ/;çܹNvAÛ ±üÜYš:ăü¿8äÃM/ó¢•&MœR9 …1 LsÃJ–ØŒk®òµíÝ:ж+]Ñ ¸D a•ÚÕ’…m ÜA@/zlŠŸŸ^R‰üñSE4qÁy÷ï!¿Fû|2Z¶©à# †ý,"K¨à i·í”VD'æ×bÄ C½¶qøN tô”_è†,l“]9ŠH`¤ïë{€î•Ç©`¡q±ÓS´ÇêÖ³ƒ±nþ`ïÏâzþIRNoŸK˜OÉ*IC[D*ƒ€íLK˜ºnT»©îÜRŽ‹@sTpä(·,UÈ~CkK¢ EÚÈí#£;G CAŸiIÌÆ|#ªö¹“^†%CY½ûJßâ‰Ô¢ùÅlA,kíˤ©”¥¯•.}žuQr^ÃÁWþÆ|tûŠÚM_ÿÚ3ãKÒÁ+Ì@¡{ЩЮV¿Î÷³&bRѸoÿ{Ô*ZóúFc äÐo{º†.è:<ç Ì®Æ@P Û.ÐͧS‡>&CêÔ(¨O;º¨Æ'úÝ#„¿!B3’`ÐCY¸ †,¯ÓßåÞ±ßÞ`Ö;cgÂpþÙça£ŸÁôQÞƒ5£´*‘Õ™4ŸŸUµ`YÁâÅL´øPȈ yAåyR±¬þH¦‹So`ó^¼ø wÒô&¨¯€ðI)±cõ]hIšásµÔ(:縨šDl™ô—e0O=ù2ðµŠè/¦h‡ÞΩԸ¤(DŸØ,ïlßçý#÷+ö̠̈́1)ÓÕXšÐK_ê'Ëè,ôÞ¤ T–ÔFÕY~˜ÚfoTø¢©xrÞvÊf) q¨±¹«9€n;ÛÄK\õeqÀ4%’X$ºÉ¨¡@|®“Æð;æð[y[Ëù{t˜vY¶žÄ‹Â²GX´ޏ:«Ü…œ@‡ð’€€ªíÙdÌ990ò“³D°ýgµe×\"€½Q)íAÖ;òŒNGf@]- ĶԿš Ô.8F^]D>åŽPôæF3c+/ðU›¸j³7 <ÅÛÚÍÓÛbкC“>œ˜IbÜÎÛ§? G«Ðëx‰+ùL´ô7šJg\/hèï$À €Ûç¬FÍXÔzÉ~õsÁŠÓŨC¹ 7R\òL”´SQˆ`^¯e¹1û5U¦wë@–ܤ¿r ÔíÿAw¥´âÁ°‘#¢I~NÍ! ÷ðïYŽ˜s€'å' ":Æî$ê•n%$¥º€‰‹µY5ßbf~êk¤l'K?‘'e®QÛôp‰(û(ËœJcà1£%ŽøÑìxLKN-%äYÐÎðtIØÇ•®’ï¨>c£ùƒXÓÙ’+IVw³W¾†ÒïÄ¥Fó¦ªLî1Ö“uq™V ‹DGçPöæŒÃi·þ®®kðÊY Ûí+'yW®]~ÚEm5ÄóΩ‰3ÝDϹLgtçœ(½¶d ß(Ú±ÿáïŽmħ".ýd*qž»`wGÏ¿#CFl{¶§¦k¶¼KPĸR»ÜÌ€- |‚¶jºA†¬ô¡\¡ß87ÜýWµ„dÉÙ¾^Ä+וdÿÕê:!øÎEßSZCÇøîúq+›-¥Õé¿sLÿepÕ™#½“·g’aƒ‰DÙ¹RoÁJTv)œŸTçBÙf¶mv[¥̪M*µÅ†ŸÕõ— Ê|û{ª/Ä‚mÌ®7‰[rvYNʼ>÷í/–Ms'rG'ŽXw?Á!‹Ô!}ŸÃïý ±¬zLÆKvar5ýNJºRõŽ=FÎеlçô®Dåm‚矅WöL’o‹QW Ÿj®äÃp EyÚ9ÌyW// ãPóç¹-4r8ãß‘è÷AH€ø,ÚIOCL…NF4½' ¯Æ6æ€87 k~Õ‘¸ |He_oW©¨Ç\\½Pä¬ÁõÀ¬È ‰ˆŒ™³ÍÁ Ld$‰×™µÉÒ˜Ód"ñ¬»×„1 פ{Ù’áºÖÒ¢Ö³–Øvó§Ýq'“·ð†j/ú¹ ek•¯‡Ü¯¶Ê”‰5¬ïþ-YÄ}â5òßpÙcª¡v’€€Ä“X87ÍÎ’ÁJ^ 0óÔïü5Ü5ÐÉR+j‡,uœÎgqS.uÍ´ àm ‘#8§³‰}ÅU_Ô­|${ì» ”ŸàS*‚ •—ˆ^ŒË35dïešLùÓ)Ƈµ#”†=‰Ø?eA<©^‰GS©<Ù$T¼Ã|Œ÷ã`Ý•ˆORQÔüC§òþiüÄñ—KOêë¶~¼ikG'¸í°I[ÈdjΣ– ®s“…0±^‹Ñïj†c“†ŽáWåÛÞZ.ÔƒwUâ¡ãˆ#`œ´¤eåW­ ÑSö-.ªd•‘±."<ÙsgŒuM]ˆ-¥èÝ”:6pÁ€hVö7eÃ%R]¼öGòåF9 x†Ü¬ßÒÖq4¾aÏÿ™‡3“ØbÕŠb‰çý3rÕðžÆ{9IT­>q1=™Þ݃sAð¹¢€?$ãü#U¶×÷´[™³Œ[vÝÕr jˆ5;ªÈ5ÃÍäв‡¢%wFˆ‰ÐÄ'=Xʧ¡‘qí‘/líD¶!ËLÕfÞ,:•1%Ý’N©;)¬cxà¥-ÐIª\:ƀ݃èÂeY°Æ=—ËMذ(C|AùGÃ;$¸M¹ãœsW;kšù*åÑ5ìQ Ï~¸õ>µq

    þ'ˆÓvG JXÀØ$a ­›"ÝÕ¹˜ö-PxX|íÜW} R~’4GX!·5Xmͪ7_‰yŒ6ç´€Z‰Wí F˜þd´Yð tDh<×6nU> 2ÜPÁªîSþ±Ã¨¯Á+ ¯‘"%¨Œî?$ÞŒiðœ‘ñ¯oZ6–L̰níVûí™í0Q˜ô4÷âÇÍG¶¬ øÑäÐ*5ÍÐå¶„x\í¤qpGâúPUmÚI›Z„nMfHàÉ~1,fž0SÀ£b’€€»œ²Â Ëøk©tgV­(¾)ÿÄ‚ÕL,¶ï¯µkmÅu,D©=vìðÍ©ämìé÷H+›û¨zýš7ªý©šyæ¶á6@Úb Æaþ{+ªéûntÂoÁc%iœ µáa/ÒÅÔš{õ‘Þ±ÄJZÓkËsþzM)9ÃÀÃ+«Hÿ¬\|{-ßS{»õ.Î Ÿ>Í„`Å”…A²ÓbmF_ÑÛ?.Ò?ÆÙê&æ¾´]¾Öÿ€‘”@ _[ïµbéÈyÄ,àØ»‹ž77p©éÚf”¬åG‰ßé>z„áHü¿¼ñ9¡AvtŒ²ê£r­»"ÿ cèì K¨—ê‰dšÐ’Ç‹,"ë8ÐTï¨R‡áÏÒ9ħeýÆx Õv÷Ú X ‘ƒ »7‰Œ{ŸÁäù!!_QLmŽ€Ëü†´½*)"ÙI5gÊ ÷'Ç^Rÿ|ŽHaÿ ½ÝeÞÎÖàõF°¯lèªL}øÒÆ%ÑÝF~‘l{R€`Á9a¬{0ËæË˜ÿmöZõpTQM»IŽS`yЩQNVʆù—¡¹åÖ†$T¡JTPœ \Ô8=†cÁü¹aÁ“D]Q7~Rp5‡—$¨)OèjK#†yðKe#´©t,,ýÇ2H¤ùƒgÞ¸dQÜ©9[’£A¥qß[æ½rì„»Ì,ïnšÚêò±QR…éM°OoC‰Ma„ÁÖógñb§T!ÈX’‘êl™=2Yu€·3//…?(ʪõv®ŠtƒÃ<‹=áùrã3IŒÆþ8Ÿƒ'®Ø(æˆU ¿ !ŠàI– ®S4%¬{“Ù¨¥ …˜&­»IÒW5z/=FÈbJp¡÷ “™š (’øãðIÿÿé ¿ÈêžQÃòDýB±=ƒÝ̶ø¶á|e´_:ëEdhv£ñH()a ÅñbzªÙ;€—#©´Á<Ç뙆|ð1 ª`‡ Änñ<†n9tá ©5Øæ9Ž¿—™¢„šÖÎÈ€ç÷eîiû@hüÀëQwÏ Zå7¾³.Ci— 6K®ø]®ÿfVë4¨…úÃ>f:OÔý$6<r÷}°¯˜cpÑo€Ûh*¿pâLØ ¸{BŒå_áF¾zjÜFTÚüZV?/}½GÒˆ1¨ ^Èõ:ñð'ì$‹xÑÃ!òÃüÓhwkŒ¹éB„~Âòƒœçº¼Õ³HЪ!iËâêÎs†êY^î7Ó×6#{æZ%¹õƒ7Qaõy›½W“í1¦wéF+‹Ü)пãA»¯ÒVÓ™Qî½ú”=&PC>½Xsc`LAþÈ»jóÓ¡d…‘’»fuǧ1¡¼ŒU`W,ϰTŸîòëæ?´¶»Bdµ*ÎB±?&˜…áDU"Çbé ¿ì­ÆÞÛ)wÂ7µv †÷ðRŒšŸ¼Å)×Ï»ð9à3FPaèBÈÙG&çJ¬Ì3l+w.ßT½%^èÐÍMÔ_ê¼±&òWë^y¾œÎ&´˜"sŒë‘‚ð&è»zü¥3íºdu8ÜϧÌPKÎHõâhQçrCÔà-Ö1nxìö(©oÆ®fXš#쬾ıò‘Y»“1ºÛŠ–A`ýšÚm”Þ ¢²âQH|ÄEH¨82€¢­:Sƒ‡ùYø°¿úCsKlŠ=R: Gáï€6"$¸Ê{PÆ• tO½O߉¤Ñ!µp)NÅŽß ÷ɬ˜âî¦H¢«û-ý‚O!Ú©U$õÍâ0äú+;{g4·UЕãò×>BHkªÌW³ÔÑÒ‡íc²øÿ>Àû9÷< ³êRÁÓÿLYÞB þ]æbj¤%)+äÚéÔt.mÖËñÔ-KÊÀêÓiqN°é‰+ kãþ¡GbÙ"àÄŒµZwÊ«Éâ–@aÈKîò^­3SN ¿70¡w¶ ¢?ò¤ÓIY|¾3Ë Ä ø»–äÜ0dXàç‡t;v32 y©bD³î„Wç,`­—‚X‰AÌ·aj£­>î4*†{ßUmEî¢vl£ßäIi§<æÓ÷QõN·H=X æÒf|Õ†…Èc—@4‰Ç «e™U­Ã.¿4Q3øPëЧ¯7 š._´*©^f\„ÿJK-Ãg~À¼ð,+ ÁB8CN¼`äò˜oøƒ·ÚðÑUÑmÄ'ÎÃ{ÚlŸ2aÕø¼W0}¡]Øc‘OëÎ[X#Ù2®¦ˆ× ègnunet-0.9.3/contrib/report.sh0000755000175000017500000001111711675367622013276 00000000000000#!/bin/sh TEST=`type type|grep not` if test -n "$TEST"; then WHICH=which else WHICH=type fi echo "Please submit the following information with your bug report: " echo "--------------------------------------------------------------" OS=`uname -s 2>/dev/null` echo "OS : $OS" REL=`uname -r 2>/dev/null` echo "OS RELEASE : $REL" HW=`uname -m 2>/dev/null` echo "HARDWARE : $HW" TEST=`$WHICH gcc 2>/dev/null` if test -n "$TEST"; then VERS=`gcc --version 2>/dev/null | head -n 1` echo "gcc : $VERS" else echo "gcc : Not Found"; fi TEST=`$WHICH gmake 2>/dev/null` if test -n "$TEST" ; then gmake --version 2>/dev/null |\ awk -F, '{print $1}' |\ awk '/GNU Make/{print "GNU gmake :",$NF}' else TEST=`make --version 2>/dev/null` if test -n "$TEST"; then make --version 2>/dev/null |\ awk -F, '{print $1}' |\ awk '/GNU Make/{print "make :",$NF}' else echo "make : Not Found" fi fi TEST=`$WHICH autoconf 2>/dev/null` if test -n "$TEST"; then autoconf --version |\ head -n 1 |\ awk '{\ if (length($4) == 0) {\ print "autoconf : "$3\ } else {\ print "autoconf : "$4\ }}' else echo "autoconf : Not Found" fi TEST=`$WHICH automake 2>/dev/null` if test -n "$TEST"; then automake --version 2>/dev/null |\ head -n 1 |\ awk '{print "automake : "$4}' else echo "automake : Not Found" fi TEST=`$WHICH libtool 2>/dev/null` if test -n "$TEST"; then libtool --version 2>/dev/null |\ head -n 1 |\ awk '{print "libtool : "$4}' else echo "libtool : Not Found" fi TEST=`$WHICH extract 2>/dev/null` if test -n "$TEST"; then extract -v 2>/dev/null |\ head -n 1 |\ awk '{print "libextractor : "$2}' else echo "libextractor : Not Found" fi if test -x gnunetd; then gnunetd -v | sed -e "s/v//" 2>/dev/null |\ awk '{print "GNUnet 0.8 : "$2 (may conflict!)}' else echo "GNUnet 0.8 : Not Found (good)" fi TEST=`$WHICH gnunet-arm 2>/dev/null` if test -n "$TEST"; then gnunet-arm -v | sed -e "s/v//" 2>/dev/null |\ awk '{print "GNUnet 0.9 : "$2}' else echo "GNUnet 0.9 : Not Found" fi TEST=`$WHICH libgcrypt-config 2> /dev/null` if test -n "$TEST"; then libgcrypt-config --version 2> /dev/null | \ awk '{print "libgcrypt : "$1}' else echo "libgcrypt : Not Found" fi TEST=`$WHICH mysql_config 2> /dev/null` if test -n "$TEST"; then mysql_config --version 2> /dev/null | \ awk '{print "mysql : "$1}' else echo "mysql : Not Found" fi TEST=`$WHICH pkg-config 2> /dev/null` if test -n "$TEST"; then pkg-config --version 2> /dev/null | \ awk '{print "pkg-config : "$1}' else echo "pkg-config : Not Found" fi TEST=`$WHICH pkg-config 2> /dev/null` if test -n "$TEST"; then pkg-config --modversion glib-2.0 2> /dev/null | \ awk '{print "glib2 : "$1}' else echo "glib2 : Not Found" fi TEST=`$WHICH pkg-config 2> /dev/null` if test -n "$TEST"; then pkg-config --modversion gtk+-2.0 2> /dev/null | \ awk '{print "gtk2+ : "$1}' else echo "gtk2+ : Not Found" fi TEST=`$WHICH dpkg 2> /dev/null` if test -n "$TEST"; then LINES=`dpkg -s libgmp3-dev | grep Version | wc -l` if test "$LINES" = "1" then VERSION=`dpkg -s libgmp3-dev | grep Version | awk '{print $2}'` echo "GMP : libgmp3-dev-$VERSION.deb" else echo "GMP : dpkg: libgmp3-dev not installed" fi else TEST=`$WHICH rpm 2> /dev/null` if test -n "$TEST"; then rpm -q gmp | sed -e "s/gmp-//" 2> /dev/null | \ awk '{print "GMP : "$1.rpm}' else echo "GMP : Test not available" fi fi TEST=`$WHICH gettext 2> /dev/null` if test -n "$TEST"; then gettext --version | head -n1 2> /dev/null | \ awk '{print "GNU gettext : "$4}' else echo "GNU gettext : Not found" fi TEST=`$WHICH curl-config 2> /dev/null` if test -n "$TEST"; then curl-config --version | head -n1 2> /dev/null | \ awk '{print "libcurl : "$2}' else echo "libcurl : Not found" fi TEST=`which qmake 2> /dev/null` if test -x "$TEST"; then qmake --version | tail -n 1 | awk '{print "Qt : "$4}' else echo "Qt : Not found" fi echo -n "MHD : " TMPFILE=`mktemp /tmp/mhd-version-testXXXXXX` cat - >$TMPFILE.c < #include int main() { fprintf (stdout, "%X\n", MHD_VERSION); return 0; } EOF gcc -o $TMPFILE $TMPFILE.c 2> /dev/null && $TMPFILE || echo "Not found" rm -f $TMPFILE $TMPFILE.bin echo "--------------------------------------------------------------" gnunet-0.9.3/contrib/Makefile.am0000644000175000017500000000272111763406434013452 00000000000000INCLUDES = -I$(top_srcdir)/src/include -I$(top_builddir)/src/include noinst_PROGRAMS = \ timeout_watchdog if !MINGW timeout_watchdog_SOURCES = \ timeout_watchdog.c else timeout_watchdog_SOURCES = \ timeout_watchdog_w32.c endif noinst_SCRIPTS = \ gnunet_pyexpect.py \ gnunet_janitor.py bin_SCRIPTS = \ gnunet-gns-import.sh dist_pkgdata_DATA = \ gnunet-logo-color.png \ testing_hostkeys.dat EXTRA_DIST = \ coverage.sh \ hostlist.cgi \ hostlist.php \ report.sh \ gnunet_pyexpect.py.in \ gnunet_janitor.py.in \ gnunet-gns-import.sh do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' %.py: %.py.in Makefile $(do_subst) < $< > $@ chmod +x $@ # init_gnunet_redhat \ # init_gnunet_ubuntu \ # visualize_stats.sh \ # gnmessage.sh \ # junkinsert.sh \ # junklookup.sh \ # namespacehelper.sh check_PROGRAMS = \ test_gnunet_prefix test_gnunet_prefix_SOURCES = \ test_gnunet_prefix.c test_gnunet_prefix_LDADD = \ $(GCLIBADD) $(WINLIB) \ $(LTLIBICONV) \ -lltdl -lunistring $(XLIB) pkghellodir= $(pkgdatadir)/hellos install-data-local: $(mkinstalldirs) $(DESTDIR)$(pkghellodir) @$(NORMAL_INSTALL) for hello in $(srcdir)/hellos/*; do \ if test -f $$hello; then \ $(INSTALL_DATA) $$hello $(DESTDIR)$(pkghellodir)/ ; \ fi \ done dist-hook: if test -d $(srcdir)/hellos; then \ mkdir -p $(distdir)/hellos; \ for hello in $(srcdir)/hellos/*; do \ if test -f $$hello; then \ cp -p $$hello $(distdir)/hellos; \ fi \ done \ fi gnunet-0.9.3/contrib/gnunet_janitor.py.in0000644000175000017500000000520211760502552015413 00000000000000#!@PYTHON@ # This file is part of GNUnet. # (C) 2011 Christian Grothoff (and other contributing authors) # # GNUnet is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2, or (at your # option) any later version. # # GNUnet is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNUnet; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # Finds any gnunet processes still running in the system and kills them # # gnunet janitor can be used by invoking `make' like this: # TESTS_ENVIRONMENT='${top_srcdir}/contrib/gnunet_janitor.py &&' make check from __future__ import print_function import os import re import subprocess import sys import shutil import time import signal if os.name == 'nt': from win32com.client import GetObject WMI = GetObject('winmgmts:') killsignal = signal.SIGTERM # any valid value will result in TerminateProcess() else: killsignal = signal.SIGKILL def get_process_list (): result = [] if os.name == 'nt': processes = WMI.InstancesOf('Win32_Process') for p in processes: result.append ((p.Properties_('ProcessId').Value, re.sub (r'(.+)\.exe', r'\1', p.Properties_('Name').Value))) else: pids = [pid for pid in os.listdir('/proc') if pid.isdigit ()] for pid in pids: with open (os.path.join ('/proc', pid, 'cmdline'), 'rb') as p: cmdline = p.read ().split ('\x00') if len (cmdline) > 0: result.append ((pid, cmdline[0])) return result def main (): procs = get_process_list () gnunet_procs = [] for p in procs: if re.match (r'gnunet-.+', p[1]): gnunet_procs.append (p) for p in gnunet_procs: if re.match (r'gnunet-service-arm', p[1]): print ("killing arm process {0:5} {1}".format (p[0], p[1])) try: os.kill (int (p[0]), killsignal) except OSError as e: print ("failed: {0}".format (e)) pass for p in gnunet_procs: if not re.match (r'gnunet-service-arm', p[1]): print ("killing non-arm process {0:5} {1}".format (p[0], p[1])) try: os.kill (int (p[0]), killsignal) except OSError as e: print ("failed: {0}".format (e)) pass if __name__ == '__main__': sys.exit (main ()) gnunet-0.9.3/contrib/hostlist.php0000644000175000017500000000161411260753602013772 00000000000000= 4.3.0 // Author: "Krasko Oleksandr" <0m3r.mail@gmail.com> // Minor improvements by Christian Grothoff header("Content-Type: application/octet-stream\r\n\r\n"); $extmas = array(); $pv=$_GET['p']; if (isset($pv)) { for ($ii=0;$ii<64;$ii++) if (0 != ($pv & (1 << $ii))) $extmas[] = $ii; } else { $extmas = array('2','3','4','5','6','8','12','17','23','25'); } $path = '/var/lib/gnunet/data/hosts/'; // adjust as necessary $dir = opendir($path); if (! $dir) die("Cannot open directory $path.\n"); $mas = array(); while ($fname = readdir($dir)) { $fn = $path . '/' . $fname; if (is_file($fn)) { $dpo = strpos($fname, '.') + 1; $len = strlen($fname); if (in_array(substr($fname, $dpo - $len), $extmas)) $mas[] = $fn; } } shuffle($mas); // randomize order foreach ($mas as $val) echo file_get_contents($val); ?> gnunet-0.9.3/contrib/gnunet-logo-color.png0000644000175000017500000001530311260753602015470 00000000000000‰PNG  IHDRIK<»ª×sBIT|dˆtEXtSoftwarewww.inkscape.org›î<UIDATxœÍœy\UåÖÇ¿ ˆIÀ&IQ Ò4Q1§½VZjjJÞR¯¦™Ú½·2›l0¯ šo£co™•e·;˜–³”©ék9¦¦¦Љà„Ê( ÀzÿX<6zðZÞõùðùè~Î~γ×^ÃoýÖóQUþDD"y@0ø^UO]ÜU™ø]ìˆHO`+„_ƒE䲋º0GäbZ’ˆÔ¦7c€Ö€›€ÑÀZçzŠª–\œU^DK‘ÛmÎúK, X $'%@_G¡GTõwýZ8¾4B±1ÀDà:Ï'™À| =ü{¯ùw³$I‘ÅÀ\`ÐXìTÕUݧª³1Eîæ3E¤µˆýË~w‘"²³„@à=`‹ªPÕ²sÍ¡ªÙªú Ð8,>‘f"rÉo¸|à7R’ˆD‰È3"²˜ lºïbÊÉ<Ÿ@¬ªUõ1 P | |$"·‹H øgÈS’ˆ„ŠÈY†äDà  30 ß”#UŠª¦«ê ì?V‹Èó"R_D.À#ñ…ÿIö:ÿŽßÍ:@H5æê…ÀXà²jÜô’lÌz{á80ç?ù;/œ$"M?b™g!ð5òÔljEä* +݈ÊK†À2à`—¯®)"Ä;kë ÔÀàÄLGÎÇÍ«c5 ±˜²H¦]ë€+ÿó°ÂÁÀaà H¾…¹f+àL\zV´t½ÈV/aÙòŸçªÆ—NÃÀ݇@[ <Å_0dýG æ2cðÀIFÊ–cîXã<ÃBP«¶¾Þ_ÀݘônŠUõ¤¯7‹È%"2HÞþ,SÕU-ô¾G #5À\æSàß"Ò^DBª±n+Ŭòï@] LDü}ÀWÓÍÆ\¢w‡à 4ÞÁðÍ àLá—ãTqAÜcW`îx øè„û¸þºÀÌõš‡0ËôÉ}UÒÍX±™\Üî(j°›¢€«çí@:szbñ«Ê…MIŸ‰Æaq1ÅùwCªˆ1@Œ‡‚€``ð*s!•4ÒyÐ<®Ýá(êAà2,Ý>¬rÞö˜y7ÂÇøå‹’<>Œ¹þ,(/ÃbÎ8Шç(óeÇ¢ƒë÷bõ >=¿JZ<Ô÷ºÞÈÁuùBŸt,®NáêãwÜ€Á‰,àQ| Ò𬠾{5v,­BAÎ=5ãX=gÁìë"Ž®tß…•“sŽ Åùa,‹mÄâß ð«Æ\~Žîò…qS„cñC€Zçš×—ìvWr/® jÏbœP¢óP¾É.Xu߸Ø‚¥ç$çÚ×Àý"áË|jÅòåÀx,YaîæV¦|…•L—žk^_jœ>Îb‹TµÈkìJþ³¨ODdÁرc'†„„Üœ——PR|àÀ¦NúÔ¡C‡^ÁÊ—±˜böa|Ñe@ºªv‘ÁÎÃv‘W€]Æ kÜ Aƒ#""b‚ƒƒ/IOOߟššúÂôéÓ¿‘XÌ?Æh•fXFÞ× Æ Å(àJÙ§.¤\ÎZ–88"KÛ[Tõ ×øD  ˜¦ª;D¤s§Næ$%%ªªßªU«hÑ¢ÙÙÙÔ®]›ãÇIvv6ÇŽË+((Ø>iÒ¤^À!U-‘1Ž’¦ªê.€:ÇßYXX˜““sªV­Z¡aaa\}õÕœ:uŠÝ»wÓ¤I6mÚ´áwÞ¹ »_b`µ7†ÅžPÕí.Ï÷%ððªî¯Jçr·Û±ôyËXÞÒ™ÓŸqãÆMûìãå –¥¤¤LÈÍÍH«V­ÈÈÈ ,,ì ¸ ª'DäSç¥î‰ŸãûEd–Å÷aîw†T¸‡c°=yÞògŒØÏQÕS¡¡¡™™™üãÿàСC;v,CßÇTu>ð`ûöíß¿í¶Û¦¤¤ðöÛo³wï^6mÚDZZ{öìáÛo¿eþüùÜzë­ <˜~ýúHnn.‹-ò«[·îcÏ=÷Ü#"r3÷»%%%sâããµ^½zlß¾   ÂÂÂÜ‚IXAYE—åeG‰uÝÆ+Y’Üþ‚q>•¬HDî°¬v @‹ŠŠ¤nݺԮ]›ÌÌÌ —dŒ1âò:„lذ™3gHDD”””PPP@=(-- &&†½{÷N:uؼy3'N”N¬S§ÎÑýû÷¿ ,xâ‰'Z…„„øýío#,,ŒÐÐPrssS½ŸIUÓDd-Vùïwþ<Ç÷‰È\ ¯3¶÷ŒgöN2"ò"V”þ°ÍSINšÜŒUÑ Ë3дiÓNFGG_’’’Bjj*-[¶ÔÏ>ûìîåË—/6lØÛAAAó²²$%%…f͚ѪU+ Àºuë¨[·.111lÛ¶Y³fQTTDpp0ùË_˜>}:×\s ‹-âàÁƒ´mÛ¶ìàÁƒÿ,((XÛµk×wæÌ™ã·víZz÷îM¯^½èÞ½{ˬ¬¬ ./?ãà“€õÞ±GDb°XÖÓ{ÜÏëƒQX!;÷XÔ#¯¾Ã\€’’’¥¥¥œ:uŠÕ«W“-ݺu›÷ù矗´k×îñ+VHXX ,`úôé :”W^y…;ôôtbbbÈËËã‡~à‰'ž 44”¶mÛ²iÓ&âãã cÆŒtïÞüü|¿èèè¾¥¥¥_{í5¿Í›7Ó¯_?bccùþûïËŽ=ªnÝUý +EÆŠoïñ}X¶î‹•Z§õâiI"ò1p +.·«j©Ç˜?ïßÀØÄÝåcÏ<óÌðŽ;NÈÍÍeÙ²e’––Æ]wÝÅìÙ³éܹ3#FŒ ¯}ùå—,]º”˜˜xà’““)--eàÀ¬ZµŠ›o¾™€€ú÷ïϽ÷ÞKXX·ß~;S¦L! € 6PTTD‹-ˆÇßß_‡ ¶1###xÏ A;°f'ððµªæx—[S/ÌšŠÀÃ’D¤p'VðT#cŒÞF<¬àõ×_Ÿ¸qãÆcáááôêÕ‹›nº !<<œÞ½{óøãW(¨´´”èèh:vìÈÓO?Í‚  bß¾}lß¾ððpŽ9@\\;vì¨ø®¤¤$²²²HHH k×®ròäɲµk׎ÊÈÈ âܶGOu¼Q¶—5E•_÷t·‰Xä†i<5‡¸·€,·bpôèÑ;322JjÔ¨A`` ={ö$>>žÈÈHüüN¿¿?×\s QQQøùù±bÅ >ÿüs>̉'hÚ´)þþF=GEEñÆoœqíÚµ‰‹‹£AƒZPPp²¨¨(mݺu _~ùåqªº#û†áâRŽ|€±]=á!å™.¦BÑŽ»Ý‡u.ZàÅc|ÒwÀë1V©uÜì¸òÊ+ÛM™2å—?þX—,Y¢ ,Ðýû÷«·üøãZVV¦ªª?ýô“N›6M—,Y¢?üðßËÊÊÒ1cÆèرcõÔ©S× µGÇõœÁ7aeÍaÌejVÁ;µÁ ÷6¸0¦Àt¬®‹-G!€ĹÜð¶ ¤á2^¾éêqÚõ¡‡jóä“O~8räÈœJRÕ÷Þ{O÷ìÙSézqqq¥k³fÍÒ¹sçê£>šVPPPqý³Ï>+¨ã²¦G0ú¥1U€Xrš^Å3Ç`ÞÔp4–‡fW‹ˆg,ŠÆ||–:³]ŠåÖŽÙÆ÷‰HyêL}ã7Š0¦²B/^LBB 66öŒ‰9xð 9994hа4gÎæÍ›—|âĉ›"##c/½ôRÿ† J\\ÜÝ»wû‹È^¬'X.~ÀµX l½ˆd{/#ãžÂDd'à½ýg3>2#Ë/ǰ‘·_…ÎÆ-êÖ"¾£`›bàRºvíš0|øð«Ê?TZZÊŒ3§sçÎìÞ½»ÒDÉÉɤ§§ÏÊ•+iÙ²%Íš5ãúë¯'!!áÎŒŒŒ¢Å‹¯ËÌÌ<\‰±¦Í±—äMúcì¦?îz 3–€¹hž×ø•W ÖuHÁXº8¬îù7+[bïñàg¬…Ô¨Y³æe}ôÑ&UÕmÛ¶é§Ÿ~Z6tèÐÝãÆûÙÍýÊeܸqúî»ïêôéÓ577WgÍš¥“'O>#½ð ïÉÄŠðD—uýKõ·bÞà½æ8°¸t™×X'¬Ž»¨UîƒåVp^,æ|1~±Uøw[gÑmÀI“&MüñÇõÍ7ßÌ7n\zƒ Þzê©/¼³bÅ ÍÍÍUUÕ´´4-..Ö)S¦è¨Q£´¨¨H‹‹‹5??¿âó~øábŒÄŸä¬;Èk-ë0¸¶Šõöq £ p¹×X0Vÿ™òv»ÇàÓXeß„ÊãrG³‘U|ñ cÅ9òÎ>}úÜÓ»w襤¤×±ši÷„ väååU² ­[·jZZšnݺµâZJJŠ._¾¼âÿÙÙÙ:~üømÚ´™‰¸-pÉ^X0sÃJ[Ë:ì(Ê-hã4?ä­$ÁHôI@=—›[c`òï·ç¡ÈCƨX|Ÿ>}>¨_¿~00?88xÚäÉ“‹*iIU—.]ªÉÉÉnCúÅ_hÏž=uРAÏa›ÞU¬1Êñˆ»ºU¼Ì¹XE‘x5u<â@Tùõ ”¦ö©¾Wt‹Ã)á1¾ãŒaml¼Æ/`í¥:5ŠŸŸß‘5j„-..îš¿bÅŠJœöm·ÝÆÎ;½/н{wfÏžM``à,ëìv^ˆ·ŒÇ¬ Û{p†ˆÈ­Ž"fûõÌâÝã½Þq殘ß臥¾  cµ° ÝX©ªÞ}8ÁÊ–À?UõpRRR¢ŸŸ_ÝY³fÍ‘ÑþþþÝ>ùä“ÁÁÁ$%%'öîÝKrr2×]wùùù„„„°mÛ6rss)((Е+W_³fÍ«À|UMõúîËåÝ ü¢ª•x0‡.™ ÌSÕ^c÷cáä1¼w»˜£`þŒKüÁÊ“Å@Ã*̹?¶{¤qùµ¤¤¤™zé–$&&æŒ5ª2WÕÒÒR]ºt©®_¿^9¢ªŸî½÷Þãñíò½b­íf¸W½0Лˆ{U± ö•’S%fÒ±œÑˆŒ*wùÌdo¬âìÇ,,øÇˆH8@``àá믿¾'FU<‘––¶lÍš5‘;wî<ƒÓ9yò$ÙÙÙ´iÓ€_ý•… ’ššJDDÄà9ŒRîàrBà>çåä©Wqî0ã±X”«ªÞ˜¨֪߈W³ \)UYÓ6Œ¡¼ÊeüYÌl]wÿ‹ÌõU•ààà›5j”Yg#à’5j$téÒ%SU+,¦°°P·nݪƒÖN:éwÞ©]ºtÉéÚµëû‘‘‘M±Â´œûá$,iÇ Èå.ë¹ø?ÌŠÜ2Þ:ÌÍâ]ŸÇí¢‡ynÆD;‹jƒ{¦ë‰±€M0z0::z\‡^Â#£Ìœ9sçÊ•+uÊ”)g·[¶lÑ &èܹsõŽ;îx¯T?a•@¹«5ÇÝÕ–Ïà‚›°-D;0H榋³up¿Ä`{; ¢{Z_¦cš°hÞ²ÎQP3gñc233? ?Ú®]»¾‰‰‰õÖ¬YóÜæÍ›¦¦¦’‘‘QqsBBEEEQ§Npõ"ÇÔi.`ñ©»£¬˜+y»Z}Ì‚¾Ã‹rä ßå©W"òü³YÓ}Ø~Å&.c}0ä[iÌ?†µoÆb«‚¿[o½õæ–-[V`˜\÷ä“On6lØï¾ûNU \¾øâ‹:dÈùçX_7¬Ùp# Ý\m,¶"Êۯũ‚V9—%µš5]Ž%|…YK­ò]."Ò£`J0Fs5†[–¬^½ú–õëׇ•·n®½öÚyyy_þòË/oeeeirr2ß|󦧧Ϛ6mZ7¯yCD¤¯ˆÌ‘Ÿ±$¡X~—÷â¤3ØyŽ£NRò”Þ:/ö¶VO9«’Ô°Â*¬Ú®é5Vü€Å :DDÚb |ÌYx¬’î,-++ë|,‘Ž;vìàý÷ßU\\¼1333÷äÉ“úÍ7ßœúøãÿè1gùSô_±ºë5 ý'bÛ`[t›ÀxÖ Èw^ž[@ß‚eE×Bø|”4Û>ç¶ }§£¨ñX÷ù̆×W¥’°Žk LûcnU b §Ï Á¬=×±¦ wÇù¢yµ{Ã">)Èež+08Ž‚‰ò«¤$¬œX¹ü_±®m¥låÃ÷Þæ(ê5NóJ>%™êœw;Šçy˜ë¤c}©j‰ªUÕ¡X@í¼'"×{Ÿ=“ç±à¿ «#g?«QÅÕ•ÕØI¥'°x¬>þ`LuN=OÆx›æXå€Ä«· ¼¹êÛYÿõ"Ò;Fú/ÌËÕ[µ0×Jöi5ÎÏŠH4;oÁ(ëœy–añÌg©öAeg§EÖ hŽ™CgWboþßÎb|:°,"¯bu5V¶ÜèÜ?SŽÛ¾M·y®pæyK[°Š` Æçô‰ñ"_^&pa~«³ªpLiobñ#xkÏœóHV‘a=ý·1áëq®ö#pãÁþ„½¸Ú˜UV;vžW஦Òå|€Uî뱬xöBÒúR,‹ž«N ÁâË/Xæ‡Äz¾¼”‹®$¯‡ Åh“CX¿«QU à8ÉËêöaûÄËá@äj1Uýýæ?袪'Tu»çt¥ØÏ“UKDäùëæ¼ˆ!úyªú³ªÑÊ[/ˆün? ä<Ä q÷ŠÈ-Ul>?CDäR™ŠÑ&+0ëY ìг0ŠJ~÷_âRÕ•[†ýÆÉ].Ôp…8›ëwbø^lwË6U=¬ŽïýÖraÆGqÜâYÙ=ôÓν ‘@l;tìðóFì¤Ó9… -EIå¢F¤cn$V<ƒe¨c™±?F³fü^–ã-õ×+!Ò ãÑÅ‚ûõ§ôf=¿yÜ9›üW( *vãoÀ(á±®kšþü ç’ ¢¬hйÙ΋å^ÞòÿBƒµäÉk-IEND®B`‚gnunet-0.9.3/contrib/gnunet_pyexpect.py.in0000644000175000017500000000543111760502552015612 00000000000000#!@PYTHON@ # This file is part of GNUnet. # (C) 2010 Christian Grothoff (and other contributing authors) # # GNUnet is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2, or (at your # option) any later version. # # GNUnet is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNUnet; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # Testcase for gnunet-peerinfo from __future__ import print_function import os import re import subprocess import sys import shutil import time class pexpect (object): def __init__ (self): super (pexpect, self).__init__ () def spawn (self, stdin, arglist, *pargs, **kwargs): env = kwargs.pop ('env', None) if env is None: env = os.environ.copy () # This messes up some testcases, disable log redirection env.pop ('GNUNET_FORCE_LOGFILE', None) self.proc = subprocess.Popen (arglist, *pargs, env=env, **kwargs) if self.proc is None: print ("Failed to spawn a process {0}".format (arglist)) sys.exit (1) if stdin is not None: self.stdo, self.stde = self.proc.communicate (stdin) else: self.stdo, self.stde = self.proc.communicate () return self.proc def expect (self, s, r, flags=0): stream = self.stdo if s == 'stdout' else self.stde if isinstance (r, str): if r == "EOF": if len (stream) == 0: return True else: print ("Failed to find `{1}' in {0}, which is `{2}' ({3})".format (s, r, stream, len (stream))) sys.exit (2) raise ValueError ("Argument `r' should be an instance of re.RegexObject or a special string, but is `{0}'".format (r)) m = r.search (stream, flags) if not m: print ("Failed to find `{1}' in {0}, which is is `{2}'".format (s, r.pattern, stream)) sys.exit (2) stream = stream[m.end ():] if s == 'stdout': self.stdo = stream else: self.stde = stream return m def read (self, s, size=-1): stream = self.stdo if s == 'stdout' else self.stde result = "" if size < 0: result = stream new_stream = "" else: result = stream[0:size] new_stream = stream[size:] if s == 'stdout': self.stdo = new_stream else: self.stde = new_stream return result gnunet-0.9.3/contrib/hellos/0000755000175000017500000000000011763406747012771 500000000000000gnunet-0.9.3/contrib/hellos/LJR80000644000175000017500000000047011727710230013335 000000000000008¢ºC#²†¢ßnNöÑë”æ ó¥È„5©yìÎ6®í“ ^“Ö²2½»G°üß.È@/ð @Û¾C¹;Ä·ŸV¼æ](ú’úN†‡Kb«·ªã9³óDÎ{™ †5ûñ]uU7¯íå‹è]NðËaf–VéÑÙŽ=Á>—{¼e”»¡8wDÕ¹³>ŒÇr¤¹3Ù`"\…R¼6€§ût%\enr»¶Ç!¬¤íÃêájä.Œ9è=Fÿç“Ekµ÷iZOiXiÀ©â˜|2ÓÚÅÔôpÇ`$ÐŒ€,/@X“l‚Xl@Q»1q¬=i˜kwæ‘ßXg‰˜¹ŸudpÿÿÿÿÿÿÿÿÁ®›$&tcpÿÿÿÿÿÿÿÿÁ®›$&gnunet-0.9.3/contrib/hellos/F1GT0000644000175000017500000000047011727710230013317 000000000000008ÓU#æiJ_b™ñ–Œ…Рb4Ã×y'Q€ Ëú—¤ªN öÐöUœ‘ãw“ÿËZ`õ?éP*à0kí À˜ÈÜÄT ¥koä ׫¯ä¡ü!.䫜¨+,8N•ZíFõ?‰wt?/ø 1á$‘×Àa5sæR 4‘©BoËÅR̉¾ÜjåíL½GWúp,)AÄÙÔiÉÓ{X«ÁÎα'…H70{#oΘ"•ß™„{ÆæºTa„ä-½ý¡·±0Ë“Rê¡ÅC¸ŽPòÈó;7¨Šs’ϵ×Õ^%¸w”€¦Ñ ¡‘ ¶lÐÓGeGrÍ}%wäudpÿÿÿÿÿÿÿÿ‚%Á&tcpÿÿÿÿÿÿÿÿ‚%Á&gnunet-0.9.3/contrib/hellos/R69Q0000644000175000017500000000044411727710230013320 00000000000000$ŸN;bå`™{5£’Ÿ(b²?5,[¶EòÀc¢‚•Ðm8‹;ËuSp\ê"­õ@[ Ф°d9‡Üï,¸Sá ,Jg2ÌŠe•~xÚ-]è¯TN õãyy|g艑,ôYH+6»!a•“â·Gs^;àÞ¢îP¥%ý:s£g4|#1@žòúÎ÷^† £iäj?iÑß¼¯ŽtIË“™c&'ûœ±Þ“ji€â!„šŠùƒúRºȶ®ÁÊÞaÞŽh¢J^„Õì®ØíÃTɘÑ!v]¹¤Äfg>櫚²¯:O%I• P`Y—…ží{¶Fÿ¡z¬ÛC ýE¡wtcpÿÿÿÿÿÿÿÿ˲…&gnunet-0.9.3/contrib/hellos/KUPL0000644000175000017500000000047011727710230013371 000000000000008óDWR™«JóÓæxÂÜw@ÞÏb1•ñ±SV*¥òºã^œsØN5ß~ï0ÒÛÐ}u%4ç€f.®ÓêcÆ?Dû¤­ÖÔl´åþn¿€½³æTqÏôPó¶DR*n4J::«Ž=Ò\ÏzÅG¾ôöh–¹ÂÞ†$XPÜÊH«š–oª—ÊÐlUÂ1òV®¾ óbÑoEltR€!B4íNc€;2V ~N#Ç“@_vâeÜð._hã>ÐÖÌj5oˆ‹ZŒ€¨ÄC„”Á«TY9¯ŸrõõB”¥ãS íEØ )ø.'"·/ðz@û¤ °Až —ìâƒøä§Î÷ 1ÿudpÿÿÿÿÿÿÿÿ†Å/&tcpÿÿÿÿÿÿÿÿ†Å/&gnunet-0.9.3/contrib/hellos/8B4T0000644000175000017500000000044411727710230013300 00000000000000$ágàO.,Vñ¯Ô >~Ešk?À/ö†Š__ ‹ 3Ê ¾œÄM™w7o˜lãòšÃ~)p3š¦¹i&þ7ÿÐïü=‡T{+“· Îøc{ 7S ªÞ¿ÿS0Mi:¸m”/Fôýýdcþ v#¬sPbØN mÍåŸÙŽ~âÃ7­ aªHBн…kˆ÷N|Ú€AÌÚΚ`£sÚ¼p“*äÏÎuÈÖ,0áoš%ò™ÍŽ·2ß\ëŸÝ׋Øéø°‡ÍH o B³£¥h•Žª)²ºÆ½5Ä~5ê^©¼\•¨{L@rˆ~o¶½ÛwgÃ’;|Ó€Y†:`ÝtcpÿÿÿÿÿÿÿÿÕ¹ãUÀûgnunet-0.9.3/contrib/hellos/94CH0000644000175000017500000000044411727710230013266 00000000000000$ÁÈA•îc¶_UºÌ}KôTì¾"Ï€@à²ñqo†õŽeN]ÇÆ)FIý±*,MõU9Êêw8[“(%^¶íS@½õ¢uö @½§¾gZö[/õD¬¼T¦pNðõ&‘‹á¢Ün†Ä‹í8ƒ¸¬6öeÃ.}½W$GŽÑƒË¥ªÜÕTø÷K÷Ö˜l-ÿ“¯ G ³ØÅÞZ†ò!¾KÅYñg£‹)“ ,å”»Ò³é¸f-–¡¾ØvYŒ2뉋áý“…³­YÆ\oXF V9µU@ L…´ý¤^´—«L6d¦ñ£yïAE×ROQŸdfŽÖÝEtcpÿÿÿÿÿÿÿÿS©+š&gnunet-0.9.3/contrib/hellos/02UK0000644000175000017500000000047011727710230013277 000000000000008½!âÕgÈLg|5jæsþ%K\¾_о§¶ŒìzW·~Dáw ¬;9°¶û9ÎvüË1‹Ú&æŸðvç ÄÏÍäM}±m³›$ÝJ2ן'.³©póÖÅ^A5+8ÿŠu0­t¬êfŽNâ‚‚Ç(å–|†žüàI󺸴rOAû7É(öQ àtðfVÞ´ØÍ®QÁ£šÑhw8®•°F¥È*ð@ÂùUDï¿"Y»íQ·OÚ, 0fúZaÖŸæa7nÂZæ­1l8Ô(b4€ã2«q ·×±BcìÉ,ÔiÆ;k³—©y^ßDyý=Ç’Ñ‚®îáDfÕ=Œ*빿mí:í&䑸¸Sudpÿÿÿÿÿÿÿÿ¼(ªe&tcpÿÿÿÿÿÿÿÿ¼(ªe&gnunet-0.9.3/contrib/hellos/1G1M0000644000175000017500000000047011727710230013263 000000000000008–®J½/L‡MÆ(Æp[¡éjšf‚±¨Þ‡î´: —Ç*œI Úìñª 1s6ºŒÛ´C¨mÓž—^Mm³2o`¹ÈÅP˜ŒÝ ´©±çyT›C_˜.#¤QoÏä2 Š=k Ä |>íM,fü•Ëëb¼Ák&VØ8¿õ]oÞã›Ð+òÊüîïØ^.©è,ɦÝÒ~µÒuÛmÎ’øý©›…|¼;ȱˆýzåϯ„G,Ú ó¥älÙ†û+ I²8œ î ó?Jlƒù{1bn.‘7efÌÇg–Åõ2GÜ+E»‰:òùñ~Šß“çbêTr¹ýÆL¨x–Eudpÿÿÿÿÿÿÿÿ„ü˜Á&tcpÿÿÿÿÿÿÿÿ„ü˜Á&gnunet-0.9.3/contrib/hellos/ATF40000644000175000017500000000047011727710230013314 000000000000008Ã&V·q’”U8wEvj“Ï @²1 1"äa+1 %Ωn_ÚCdª4(g` 2ïôÔ7ð6‹îäjã¯l7d]ZØ÷b¤˜Œkö?KO¤¿ð'ddæ5tƒ¼ú-…{?µÄñi áô ×ûú\so,åaâ.Ì'^§ØCB/FK«FÚ‡¯=~dÚR–@ÃîÔ©,ùONË.Õ`™=!ç¬úgSC:žµÕ%«°´u–µÒ{«;si>qr%5±E§îDý¡´Ú„)[Z›wo! ˉ^ýê"óAƒCYS¿ÿ´c©¦Xç£b«~„¯³SãBŠ.5êøZA§À udpÿÿÿÿÿÿÿÿƒŸ#&tcpÿÿÿÿÿÿÿÿƒŸ#&gnunet-0.9.3/contrib/hellos/RL7P0000644000175000017500000000047011727710230013342 000000000000008ì!‚9~v ÂP_,N—E]Ê4éC§ÄÞ{½¤ß¯¸¢î ñãÍ*Z³¬ÈãDÇxéW/k^®ž¢ø«ç ìÃ"N¨V½Ôµ)ÄÀ°ZÇäáßßuQ&ãæ)gîÚçÁºE r¥êº‹âs—ê¿]Á¿¥BØ écÿ)«Tg¼Ÿ-Ð÷<‰ÚêVSXþŒ|Œ¤ýi#ù.-ºo¹Q¢ÁLwêç€]kt*Àà`EƺæéMl;ÿޠ=¸Ð ëâÌví ºýWù„S7¯‰È%Äþ=”¤mlVV=¹{%P¢Õ”g¡‘—ük_5þ@ø‰qŽ`U‘P ³f#øè`udpÿÿÿÿÿÿÿÿƒŸJC&tcpÿÿÿÿÿÿÿÿƒŸJC&gnunet-0.9.3/contrib/hellos/7RAV0000644000175000017500000000044411727710230013336 00000000000000$ñÓ¼0œzŸJ‚CPº¬ÏÛÞq Èó["”ü[ñ$¬êÓ!aôÀv–Ûu*šÀ"jݧ`Û–/3dèäS"ÙùÆÀïùûƒÒñËMh6kÁíÚ‘‘Û©I• ‰x4-þ¡ÛWQÇþM¤ºbiLvųUÂ4îL¿¸3.lަµŒj‚*…¹ðŒ¬î‹½#|à YÝ•Å|×Ññ­Ü#t_èçÎéÕ­ º¶ÄSÓG´¥sḦȓÄlÿ$w)|';| ¹Æs‚YäÎ}L08—uqÆ8Wt0°|FNª‘Cµ$]²¿÷VpÔ»¹APÒ‚VZ 8'¨·tcpÿÿÿÿÿÿÿÿmK²]&gnunet-0.9.3/contrib/hellos/KD9V0000644000175000017500000000044411727710230013334 00000000000000$ç*é4O õÃ%¦“O¸lïHoø9‚€Ëu‡hÎ)Œõ…óý¡Zqî¦9¡ä 3+R^`í’´#2»kƒp«Ô¡+BÖ>RòGÒð0+ªšìIÑžÁm¥²¦kÿ£8ÿÞ*y•õö—XÕÐsš£«ËíEk÷ÔúÜcx9”ëu8b&e¶ÚpûØ«¥ãö´¶WŠ ¯ð|%w(øœÅµ%\¾ W Ó" º0g¯„Êà¢-²(€ïlûN}㽚H]aÆ~adàQ&aí¶‹ž¶,l— |f:6/zjÖì)¸ùëwLÄ u)” L¾S×or8ÝL g&Mtcpÿÿÿÿÿÿÿÿ[Ð"&gnunet-0.9.3/contrib/hostlist.cgi0000644000175000017500000000037711260753602013752 00000000000000#!/bin/sh # This is a CGI script to generate the host list on-demand. # by Michael Wensley, with minor improvements by Christian Grothoff echo -ne "Content-Type: application/octet-stream\r\n\r\n" cat /var/lib/gnunet/data/hosts/*.{2,3,4,5,6,8,12,17,23,25} gnunet-0.9.3/contrib/timeout_watchdog_w32.c0000644000175000017500000001173111761753146015627 00000000000000/* This file is part of GNUnet (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file contrib/timeout_watchdog_w32.c * @brief small tool starting a child process, waiting that it terminates or killing it after a given timeout period * @author LRN */ #include #include #include int main (int argc, char *argv[]) { int i; DWORD wait_result; wchar_t *commandline; wchar_t **wargv; wchar_t *arg; unsigned int cmdlen; wchar_t *idx; STARTUPINFOW start; PROCESS_INFORMATION proc; wchar_t wpath[MAX_PATH + 1]; wchar_t *pathbuf; DWORD pathbuf_len, alloc_len; wchar_t *ptr; wchar_t *non_const_filename; wchar_t *wcmd; int wargc; int timeout = 0; HANDLE job; if (argc < 3) { printf ("arg 1: timeout in sec., arg 2: executable, arg arguments\n"); exit (1); } timeout = atoi (argv[1]); if (timeout == 0) timeout = 600; commandline = GetCommandLineW (); if (commandline == NULL) { printf ("Failed to get commandline: %lu\n", GetLastError ()); exit (2); } wargv = CommandLineToArgvW (commandline, &wargc); if (wargv == NULL || wargc <= 1) { printf ("Failed to get parse commandline: %lu\n", GetLastError ()); exit (3); } job = CreateJobObject (NULL, NULL); if (job == NULL) { printf ("Failed to create a job: %lu\n", GetLastError ()); exit (4); } pathbuf_len = GetEnvironmentVariableW (L"PATH", (wchar_t *) &pathbuf, 0); alloc_len = pathbuf_len + 1; pathbuf = malloc (alloc_len * sizeof (wchar_t)); ptr = pathbuf; alloc_len = GetEnvironmentVariableW (L"PATH", ptr, pathbuf_len); cmdlen = wcslen (wargv[2]); if (cmdlen < 5 || wcscmp (&wargv[2][cmdlen - 4], L".exe") != 0) { non_const_filename = malloc (sizeof (wchar_t) * (cmdlen + 5)); _snwprintf (non_const_filename, cmdlen + 5, L"%s.exe", wargv[2]); } else { non_const_filename = wcsdup (wargv[2]); } /* Check that this is the full path. If it isn't, search. */ if (non_const_filename[1] == L':') _snwprintf (wpath, sizeof (wpath) / sizeof (wchar_t), L"%s", non_const_filename); else if (!SearchPathW (pathbuf, non_const_filename, NULL, sizeof (wpath) / sizeof (wchar_t), wpath, NULL)) { printf ("Failed to get find executable: %lu\n", GetLastError ()); exit (5); } free (pathbuf); free (non_const_filename); cmdlen = wcslen (wpath) + 4; i = 3; while (NULL != (arg = wargv[i++])) cmdlen += wcslen (arg) + 4; wcmd = idx = malloc (sizeof (wchar_t) * (cmdlen + 1)); i = 2; while (NULL != (arg = wargv[i++])) { /* This is to escape trailing slash */ wchar_t arg_lastchar = arg[wcslen (arg) - 1]; if (idx == wcmd) idx += swprintf (idx, L"\"%s%s\" ", wpath, arg_lastchar == L'\\' ? L"\\" : L""); else { if (wcschr (arg, L' ') != NULL) idx += swprintf (idx, L"\"%s%s\"%s", arg, arg_lastchar == L'\\' ? L"\\" : L"", i == wargc ? L"" : L" "); else idx += swprintf (idx, L"%s%s%s", arg, arg_lastchar == L'\\' ? L"\\" : L"", i == wargc ? L"" : L" "); } } LocalFree (wargv); memset (&start, 0, sizeof (start)); start.cb = sizeof (start); if (!CreateProcessW (wpath, wcmd, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &start, &proc)) { wprintf (L"Failed to get spawn process `%s' with arguments `%s': %lu\n", wpath, wcmd, GetLastError ()); exit (6); } AssignProcessToJobObject (job, proc.hProcess); ResumeThread (proc.hThread); CloseHandle (proc.hThread); free (wcmd); wait_result = WaitForSingleObject (proc.hProcess, timeout * 1000); if (wait_result == WAIT_OBJECT_0) { DWORD status; wait_result = GetExitCodeProcess (proc.hProcess, &status); CloseHandle (proc.hProcess); if (wait_result != 0) { printf ("Test process exited with result %lu\n", status); TerminateJobObject (job, status); exit (status); } printf ("Test process exited (failed to obtain exit status)\n"); TerminateJobObject (job, 0); exit (0); } printf ("Child processes were killed after timeout of %u seconds\n", timeout); TerminateJobObject (job, 1); CloseHandle (proc.hProcess); exit (1); } /* end of timeout_watchdog_w32.c */ gnunet-0.9.3/contrib/gnunet-gns-import.sh0000755000175000017500000000030211763406414015341 00000000000000#!/bin/sh # This shell-script will import some GNS authorities into your GNS # namestore. gnunet-namestore -a -e never -n fcfs -p -t PKEY -V 72QC35CO20UJN1E91KPJFNT9TG4CLKAPB4VK9S3Q758S9MLBRKOG gnunet-0.9.3/contrib/test_gnunet_prefix.c0000644000175000017500000000367011760502550015473 00000000000000/* This file is part of GNUnet (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * @file contrib/test_gnunet_prefix.c * @brief test if environment variable GNUNET_PREFIX is set so that * we have a chance to run tests * @author Christian Grothoff */ #include "platform.h" int main (int argc, char **argv) { const char *basename; const char *dirname; basename = getenv ("GNUNET_PREFIX"); if (NULL == basename) { fprintf (stderr, _("Environment variable GNUNET_PREFIX not set\n")); fprintf (stderr, _("Testcases will not work!\n")); return 1; } dirname = DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR "config.d"; { char tmp[strlen (basename) + strlen (dirname) + 1]; sprintf (tmp, "%s%s", basename, dirname); if (0 != access (tmp, R_OK)) { fprintf (stderr, _("Failed to access `%s': %s\n"), tmp, STRERROR (errno)); fprintf (stderr, _("Check that you did run `make install' and that GNUNET_PREFIX='%s' is the correct prefix.\n"), basename); fprintf (stderr, _("Testcases will not work!\n")); return 2; } } return 0; } gnunet-0.9.3/contrib/timeout_watchdog.c0000644000175000017500000000526711760502550015131 00000000000000/* This file is part of GNUnet (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file contrib/timeout_watchdog.c * @brief small tool starting a child process, waiting that it terminates or killing it after a given timeout period * @author Matthias Wachs */ #include #include #include #include #include #include static pid_t child; static void sigchld_handler (int val) { int status = 0; int ret = 0; waitpid (child, &status, 0); if (WIFEXITED (status) != 0) { ret = WEXITSTATUS (status); printf ("Test process exited with result %u\n", ret); } if (WIFSIGNALED (status) != 0) { ret = WTERMSIG (status); printf ("Test process was signaled %u\n", ret); } exit (ret); } static void sigint_handler (int val) { kill (0, val); exit (val); } int main (int argc, char *argv[]) { int timeout = 0; pid_t gpid = 0; if (argc < 3) { printf ("arg 1: timeout in sec., arg 2: executable, arg arguments\n"); exit (1); } timeout = atoi (argv[1]); if (timeout == 0) timeout = 600; /* with getpgid() it does not compile, but getpgrp is the BSD version and working */ gpid = getpgrp (); signal (SIGCHLD, sigchld_handler); signal (SIGABRT, sigint_handler); signal (SIGFPE, sigint_handler); signal (SIGILL, sigint_handler); signal (SIGINT, sigint_handler); signal (SIGSEGV, sigint_handler); signal (SIGTERM, sigint_handler); child = fork (); if (child == 0) { /* int setpgrp(pid_t pid, pid_t pgid); is not working on this machine */ //setpgrp (0, pid_t gpid); if (-1 != gpid) setpgid (0, gpid); execvp (argv[2], &argv[2]); exit (1); } if (child > 0) { sleep (timeout); printf ("Child processes were killed after timeout of %u seconds\n", timeout); kill (0, SIGTERM); exit (1); } exit (1); } /* end of timeout_watchdog.c */ gnunet-0.9.3/contrib/coverage.sh0000755000175000017500000000053511273031413013534 00000000000000#!/bin/sh # make sure configure was run with coverage enabled... lcov --directory . --zerocounters make check rm `find * -name "test_*.gc??"` for n in `find * -name "*.gc??" | grep libs` do cd `dirname $n` mv `basename $n` .. cd - done lcov --directory . --capture --output-file app.info mkdir -p doc/coverage genhtml -o doc/coverage app.info gnunet-0.9.3/contrib/Makefile.in0000644000175000017500000005747311763406515013501 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ noinst_PROGRAMS = timeout_watchdog$(EXEEXT) check_PROGRAMS = test_gnunet_prefix$(EXEEXT) subdir = contrib DIST_COMMON = $(dist_pkgdata_DATA) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = PROGRAMS = $(noinst_PROGRAMS) am_test_gnunet_prefix_OBJECTS = test_gnunet_prefix.$(OBJEXT) test_gnunet_prefix_OBJECTS = $(am_test_gnunet_prefix_OBJECTS) am__DEPENDENCIES_1 = test_gnunet_prefix_DEPENDENCIES = $(am__DEPENDENCIES_1) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent am__timeout_watchdog_SOURCES_DIST = timeout_watchdog.c \ timeout_watchdog_w32.c @MINGW_FALSE@am_timeout_watchdog_OBJECTS = timeout_watchdog.$(OBJEXT) @MINGW_TRUE@am_timeout_watchdog_OBJECTS = \ @MINGW_TRUE@ timeout_watchdog_w32.$(OBJEXT) timeout_watchdog_OBJECTS = $(am_timeout_watchdog_OBJECTS) timeout_watchdog_LDADD = $(LDADD) am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgdatadir)" SCRIPTS = $(bin_SCRIPTS) $(noinst_SCRIPTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(test_gnunet_prefix_SOURCES) $(timeout_watchdog_SOURCES) DIST_SOURCES = $(test_gnunet_prefix_SOURCES) \ $(am__timeout_watchdog_SOURCES_DIST) DATA = $(dist_pkgdata_DATA) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include -I$(top_builddir)/src/include @MINGW_FALSE@timeout_watchdog_SOURCES = \ @MINGW_FALSE@ timeout_watchdog.c @MINGW_TRUE@timeout_watchdog_SOURCES = \ @MINGW_TRUE@ timeout_watchdog_w32.c noinst_SCRIPTS = \ gnunet_pyexpect.py \ gnunet_janitor.py bin_SCRIPTS = \ gnunet-gns-import.sh dist_pkgdata_DATA = \ gnunet-logo-color.png \ testing_hostkeys.dat EXTRA_DIST = \ coverage.sh \ hostlist.cgi \ hostlist.php \ report.sh \ gnunet_pyexpect.py.in \ gnunet_janitor.py.in \ gnunet-gns-import.sh do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' test_gnunet_prefix_SOURCES = \ test_gnunet_prefix.c test_gnunet_prefix_LDADD = \ $(GCLIBADD) $(WINLIB) \ $(LTLIBICONV) \ -lltdl -lunistring $(XLIB) pkghellodir = $(pkgdatadir)/hellos all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu contrib/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu contrib/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list test_gnunet_prefix$(EXEEXT): $(test_gnunet_prefix_OBJECTS) $(test_gnunet_prefix_DEPENDENCIES) @rm -f test_gnunet_prefix$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gnunet_prefix_OBJECTS) $(test_gnunet_prefix_LDADD) $(LIBS) timeout_watchdog$(EXEEXT): $(timeout_watchdog_OBJECTS) $(timeout_watchdog_DEPENDENCIES) @rm -f timeout_watchdog$(EXEEXT) $(AM_V_CCLD)$(LINK) $(timeout_watchdog_OBJECTS) $(timeout_watchdog_LDADD) $(LIBS) install-binSCRIPTS: $(bin_SCRIPTS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gnunet_prefix.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timeout_watchdog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timeout_watchdog_w32.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_pkgdataDATA: $(dist_pkgdata_DATA) @$(NORMAL_INSTALL) test -z "$(pkgdatadir)" || $(MKDIR_P) "$(DESTDIR)$(pkgdatadir)" @list='$(dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgdatadir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgdatadir)" || exit $$?; \ done uninstall-dist_pkgdataDATA: @$(NORMAL_UNINSTALL) @list='$(dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgdatadir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgdatadir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-hook check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) check: check-am all-am: Makefile $(PROGRAMS) $(SCRIPTS) $(DATA) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgdatadir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ clean-noinstPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-data-local install-dist_pkgdataDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binSCRIPTS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binSCRIPTS uninstall-dist_pkgdataDATA .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean \ clean-checkPROGRAMS clean-generic clean-libtool \ clean-noinstPROGRAMS ctags dist-hook distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-binSCRIPTS install-data \ install-data-am install-data-local install-dist_pkgdataDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ uninstall-am uninstall-binSCRIPTS uninstall-dist_pkgdataDATA %.py: %.py.in Makefile $(do_subst) < $< > $@ chmod +x $@ install-data-local: $(mkinstalldirs) $(DESTDIR)$(pkghellodir) @$(NORMAL_INSTALL) for hello in $(srcdir)/hellos/*; do \ if test -f $$hello; then \ $(INSTALL_DATA) $$hello $(DESTDIR)$(pkghellodir)/ ; \ fi \ done dist-hook: if test -d $(srcdir)/hellos; then \ mkdir -p $(distdir)/hellos; \ for hello in $(srcdir)/hellos/*; do \ if test -f $$hello; then \ cp -p $$hello $(distdir)/hellos; \ fi \ done \ fi # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/NEWS0000644000175000017500000000001711260753602010443 00000000000000See ChangeLog. gnunet-0.9.3/install-sh0000755000175000017500000003253711762217210011761 00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2009-04-28.21; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then trap '(exit $?); exit' 1 2 13 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names starting with `-'. case $src in -*) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # Protect names starting with `-'. case $dst in -*) dst=./$dst;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; -*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test -z "$d" && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: gnunet-0.9.3/ltmain.sh0000755000175000017500000073337711762217203011614 00000000000000# Generated from ltmain.m4sh. # ltmain.sh (GNU libtool) 2.2.6b # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007 2008 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, # or obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Usage: $progname [OPTION]... [MODE-ARG]... # # Provide generalized library-building support services. # # --config show all configuration variables # --debug enable verbose shell tracing # -n, --dry-run display commands without modifying any files # --features display basic configuration information and exit # --mode=MODE use operation mode MODE # --preserve-dup-deps don't remove duplicate dependency libraries # --quiet, --silent don't print informational messages # --tag=TAG use configuration variables from tag TAG # -v, --verbose print informational messages (default) # --version print version information # -h, --help print short or long help message # # MODE must be one of the following: # # clean remove files from the build directory # compile compile a source file into a libtool object # execute automatically set library path, then run a program # finish complete the installation of libtool libraries # install install libraries or executables # link create a library or an executable # uninstall remove libraries from an installed directory # # MODE-ARGS vary depending on the MODE. # Try `$progname --help --mode=MODE' for a more detailed description of MODE. # # When reporting a bug, please describe a test case to reproduce it and # include the following information: # # host-triplet: $host # shell: $SHELL # compiler: $LTCC # compiler flags: $LTCFLAGS # linker: $LD (gnu? $with_gnu_ld) # $progname: (GNU libtool) 2.2.6b Debian-2.2.6b-2 # automake: $automake_version # autoconf: $autoconf_version # # Report bugs to . PROGRAM=ltmain.sh PACKAGE=libtool VERSION="2.2.6b Debian-2.2.6b-2" TIMESTAMP="" package_revision=1.3017 # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # NLS nuisances: We save the old values to restore during execute mode. # Only set LANG and LC_ALL to C if already set. # These must not be set unconditionally because not all systems understand # e.g. LANG=C (notably SCO). lt_user_locale= lt_safe_locale= for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${$lt_var+set}\" = set; then save_$lt_var=\$$lt_var $lt_var=C export $lt_var lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" fi" done $lt_unset CDPATH : ${CP="cp -f"} : ${ECHO="echo"} : ${EGREP="/bin/grep -E"} : ${FGREP="/bin/grep -F"} : ${GREP="/bin/grep"} : ${LN_S="ln -s"} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SED="/bin/sed"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} : ${Xsed="$SED -e 1s/^X//"} # Global variables: EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. exit_status=$EXIT_SUCCESS # Make sure IFS has a sensible default lt_nl=' ' IFS=" $lt_nl" dirname="s,/[^/]*$,," basename="s,^.*/,," # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` } # Generated shell functions inserted here. # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath="$0" # The name of this program: # In the unlikely event $progname began with a '-', it would play havoc with # func_echo (imagine progname=-n), so we prepend ./ in that case: func_dirname_and_basename "$progpath" progname=$func_basename_result case $progname in -*) progname=./$progname ;; esac # Make sure we have an absolute path for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=$func_dirname_result progdir=`cd "$progdir" && pwd` progpath="$progdir/$progname" ;; *) save_IFS="$IFS" IFS=: for progdir in $PATH; do IFS="$save_IFS" test -x "$progdir/$progname" && break done IFS="$save_IFS" test -n "$progdir" || progdir=`pwd` progpath="$progdir/$progname" ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed="${SED}"' -e 1s/^X//' sed_quote_subst='s/\([`"$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Re-`\' parameter expansions in output of double_quote_subst that were # `\'-ed in input to the same. If an odd number of `\' preceded a '$' # in input to double_quote_subst, that '$' was protected from expansion. # Since each input `\' is now two `\'s, look for any number of runs of # four `\'s followed by two `\'s and then a '$'. `\' that '$'. bs='\\' bs2='\\\\' bs4='\\\\\\\\' dollar='\$' sed_double_backslash="\ s/$bs4/&\\ /g s/^$bs2$dollar/$bs&/ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g s/\n//g" # Standard options: opt_dry_run=false opt_help=false opt_quiet=false opt_verbose=false opt_warning=: # func_echo arg... # Echo program name prefixed message, along with the current mode # name if it has been set yet. func_echo () { $ECHO "$progname${mode+: }$mode: $*" } # func_verbose arg... # Echo program name prefixed message in verbose mode only. func_verbose () { $opt_verbose && func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_error arg... # Echo program name prefixed message to standard error. func_error () { $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2 } # func_warning arg... # Echo program name prefixed warning message to standard error. func_warning () { $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2 # bash bug again: : } # func_fatal_error arg... # Echo program name prefixed message to standard error, and exit. func_fatal_error () { func_error ${1+"$@"} exit $EXIT_FAILURE } # func_fatal_help arg... # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { func_error ${1+"$@"} func_fatal_error "$help" } help="Try \`$progname --help' for more information." ## default # func_grep expression filename # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $GREP "$1" "$2" >/dev/null 2>&1 } # func_mkdir_p directory-path # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { my_directory_path="$1" my_dir_list= if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then # Protect directory names starting with `-' case $my_directory_path in -*) my_directory_path="./$my_directory_path" ;; esac # While some portion of DIR does not yet exist... while test ! -d "$my_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. my_dir_list="$my_directory_path:$my_dir_list" # If the last portion added has no slash in it, the list is done case $my_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop my_directory_path=`$ECHO "X$my_directory_path" | $Xsed -e "$dirname"` done my_dir_list=`$ECHO "X$my_dir_list" | $Xsed -e 's,:*$,,'` save_mkdir_p_IFS="$IFS"; IFS=':' for my_dir in $my_dir_list; do IFS="$save_mkdir_p_IFS" # mkdir can fail with a `File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$my_dir" 2>/dev/null || : done IFS="$save_mkdir_p_IFS" # Bail out if we (or some other process) failed to create a directory. test -d "$my_directory_path" || \ func_fatal_error "Failed to create \`$1'" fi } # func_mktempdir [string] # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, STRING is the basename for that directory. func_mktempdir () { my_template="${TMPDIR-/tmp}/${1-$progname}" if test "$opt_dry_run" = ":"; then # Return a directory name, but don't create it in dry-run mode my_tmpdir="${my_template}-$$" else # If mktemp works, use that first and foremost my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` if test ! -d "$my_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race my_tmpdir="${my_template}-${RANDOM-0}$$" save_mktempdir_umask=`umask` umask 0077 $MKDIR "$my_tmpdir" umask $save_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$my_tmpdir" || \ func_fatal_error "cannot create temporary directory \`$my_tmpdir'" fi $ECHO "X$my_tmpdir" | $Xsed } # func_quote_for_eval arg # Aesthetically quote ARG to be evaled later. # This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT # is double-quoted, suitable for a subsequent eval, whereas # FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters # which are still active within double quotes backslashified. func_quote_for_eval () { case $1 in *[\\\`\"\$]*) func_quote_for_eval_unquoted_result=`$ECHO "X$1" | $Xsed -e "$sed_quote_subst"` ;; *) func_quote_for_eval_unquoted_result="$1" ;; esac case $func_quote_for_eval_unquoted_result in # Double-quote args containing shell metacharacters to delay # word splitting, command substitution and and variable # expansion for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" ;; *) func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" esac } # func_quote_for_expand arg # Aesthetically quote ARG to be evaled later; same as above, # but do not quote variable references. func_quote_for_expand () { case $1 in *[\\\`\"]*) my_arg=`$ECHO "X$1" | $Xsed \ -e "$double_quote_subst" -e "$sed_double_backslash"` ;; *) my_arg="$1" ;; esac case $my_arg in # Double-quote args containing shell metacharacters to delay # word splitting and command substitution for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") my_arg="\"$my_arg\"" ;; esac func_quote_for_expand_result="$my_arg" } # func_show_eval cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$my_cmd" my_status=$? if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_show_eval_locale cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$lt_user_locale $my_cmd" my_status=$? eval "$lt_safe_locale" if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_version # Echo version message to standard output and exit. func_version () { $SED -n '/^# '$PROGRAM' (GNU /,/# warranty; / { s/^# // s/^# *$// s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ p }' < "$progpath" exit $? } # func_usage # Echo short help message to standard output and exit. func_usage () { $SED -n '/^# Usage:/,/# -h/ { s/^# // s/^# *$// s/\$progname/'$progname'/ p }' < "$progpath" $ECHO $ECHO "run \`$progname --help | more' for full usage" exit $? } # func_help # Echo long help message to standard output and exit. func_help () { $SED -n '/^# Usage:/,/# Report bugs to/ { s/^# // s/^# *$// s*\$progname*'$progname'* s*\$host*'"$host"'* s*\$SHELL*'"$SHELL"'* s*\$LTCC*'"$LTCC"'* s*\$LTCFLAGS*'"$LTCFLAGS"'* s*\$LD*'"$LD"'* s/\$with_gnu_ld/'"$with_gnu_ld"'/ s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/ s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/ p }' < "$progpath" exit $? } # func_missing_arg argname # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { func_error "missing argument for $1" exit_cmd=exit } exit_cmd=: # Check that we have a working $ECHO. if test "X$1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X$1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then # Yippee, $ECHO works! : else # Restart under the correct shell, and then maybe $ECHO will work. exec $SHELL "$progpath" --no-reexec ${1+"$@"} fi if test "X$1" = X--fallback-echo; then # used as fallback echo shift cat </dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # Parse options once, thoroughly. This comes as soon as possible in # the script to make things like `libtool --version' happen quickly. { # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; esac # Parse non-mode specific arguments: while test "$#" -gt 0; do opt="$1" shift case $opt in --config) func_config ;; --debug) preserve_args="$preserve_args $opt" func_echo "enabling shell trace mode" opt_debug='set -x' $opt_debug ;; -dlopen) test "$#" -eq 0 && func_missing_arg "$opt" && break execute_dlfiles="$execute_dlfiles $1" shift ;; --dry-run | -n) opt_dry_run=: ;; --features) func_features ;; --finish) mode="finish" ;; --mode) test "$#" -eq 0 && func_missing_arg "$opt" && break case $1 in # Valid mode arguments: clean) ;; compile) ;; execute) ;; finish) ;; install) ;; link) ;; relink) ;; uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $opt" exit_cmd=exit break ;; esac mode="$1" shift ;; --preserve-dup-deps) opt_duplicate_deps=: ;; --quiet|--silent) preserve_args="$preserve_args $opt" opt_silent=: ;; --verbose| -v) preserve_args="$preserve_args $opt" opt_silent=false ;; --tag) test "$#" -eq 0 && func_missing_arg "$opt" && break preserve_args="$preserve_args $opt $1" func_enable_tag "$1" # tagname is set here shift ;; # Separate optargs to long options: -dlopen=*|--mode=*|--tag=*) func_opt_split "$opt" set dummy "$func_opt_split_opt" "$func_opt_split_arg" ${1+"$@"} shift ;; -\?|-h) func_usage ;; --help) opt_help=: ;; --version) func_version ;; -*) func_fatal_help "unrecognized option \`$opt'" ;; *) nonopt="$opt" break ;; esac done case $host in *cygwin* | *mingw* | *pw32* | *cegcc*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_duplicate_deps ;; esac # Having warned about all mis-specified options, bail out if # anything was wrong. $exit_cmd $EXIT_FAILURE } # func_check_version_match # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } ## ----------- ## ## Main. ## ## ----------- ## $opt_help || { # Sanity checks first: func_check_version_match if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then func_fatal_configuration "not configured to build any kind of library" fi test -z "$mode" && func_fatal_error "error: you must specify a MODE." # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$execute_dlfiles" && test "$mode" != execute; then func_error "unrecognized option \`-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help="$help" help="Try \`$progname --help --mode=$mode' for more information." } # func_lalib_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null \ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_unsafe_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if `file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case "$lalib_p_line" in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test "$lalib_p" = yes } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { func_lalib_p "$1" } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_ltwrapper_scriptname_result="" if func_ltwrapper_executable_p "$1"; then func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" fi } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $opt_debug save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$save_ifs eval cmd=\"$cmd\" func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # `FILE.' does not work on cygwin managed mounts. func_source () { $opt_debug case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $opt_debug if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_quote_for_eval "$arg" CC_quoted="$CC_quoted $func_quote_for_eval_result" done case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_quote_for_eval "$arg" CC_quoted="$CC_quoted $func_quote_for_eval_result" done case "$@ " in " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with \`--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=${1} if test "$build_libtool_libs" = yes; then write_lobj=\'${2}\' else write_lobj=none fi if test "$build_old_libs" = yes; then write_oldobj=\'${3}\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T <?"'"'"' &()|`$[]' \ && func_warning "libobj name \`$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname="$func_basename_result" xdir="$func_dirname_result" lobj=${xdir}$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test "$build_old_libs" = yes; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then output_obj=`$ECHO "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} lockfile="$output_obj.lock" else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test "$need_locks" = yes; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test "$need_locks" = warn; then if test -f "$lockfile"; then $ECHO "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi removelist="$removelist $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist removelist="$removelist $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 if test -n "$fix_srcfile_path"; then eval srcfile=\"$fix_srcfile_path\" fi func_quote_for_eval "$srcfile" qsrcfile=$func_quote_for_eval_result # Only build a PIC object if we are building libtool libraries. if test "$build_libtool_libs" = yes; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test "$pic_mode" != no; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir command="$command -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test "$suppress_opt" = yes; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test "$build_old_libs" = yes; then if test "$pic_mode" != yes; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test "$compiler_c_o" = yes; then command="$command -o $obj" fi # Suppress compiler output if we already did a PIC compilation. command="$command$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test "$need_locks" != no; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test "$mode" = compile && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $ECHO \ "Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to building PIC objects only -prefer-non-pic try to building non-PIC objects only -shared do not build a \`.o' file suitable for static linking -static only build a \`.o' file suitable for static linking COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix \`.c' with the library object suffix, \`.lo'." ;; execute) $ECHO \ "Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to \`-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $ECHO \ "Usage: $progname [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the \`--dry-run' option if you just want to see what would be executed." ;; install) $ECHO \ "Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the \`install' or \`cp' program. The following components of INSTALL-COMMAND are treated specially: -inst-prefix PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE Use a list of object files found in FILE to specify objects -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface All other options (arguments beginning with \`-') are ignored. Every other argument is treated as a filename. Files ending in \`.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only library objects (\`.lo' files) may be specified, and \`-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created using \`ar' and \`ranlib', or on Windows using \`lib'. If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $ECHO \ "Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) func_fatal_help "invalid operation mode \`$mode'" ;; esac $ECHO $ECHO "Try \`$progname --help' for more information about other modes." exit $? } # Now that we've collected a possible --mode arg, show help if necessary $opt_help && func_mode_help # func_mode_execute arg... func_mode_execute () { $opt_debug # The first argument is the command name. cmd="$nonopt" test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $execute_dlfiles; do test -f "$file" \ || func_fatal_help "\`$file' is not a file" dir= case $file in *.la) # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "\`$file' was not linked with \`-export-dynamic'" continue fi func_dirname "$file" "" "." dir="$func_dirname_result" if test -f "$dir/$objdir/$dlname"; then dir="$dir/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir="$func_dirname_result" ;; *) func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir="$absdir" # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic="$magic" # Check if any of the arguments is a wrapper script. args= for file do case $file in -*) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file="$progdir/$program" elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file="$progdir/$program" fi ;; esac # Quote arguments (to preserve shell metacharacters). func_quote_for_eval "$file" args="$args $func_quote_for_eval_result" done if test "X$opt_dry_run" = Xfalse; then if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd="\$cmd$args" else # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" $ECHO "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS fi } test "$mode" = execute && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $opt_debug libdirs="$nonopt" admincmds= if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for dir do libdirs="$libdirs $dir" done for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || admincmds="$admincmds $cmds" fi done fi # Exit here if they wanted silent mode. $opt_silent && exit $EXIT_SUCCESS $ECHO "X----------------------------------------------------------------------" | $Xsed $ECHO "Libraries have been installed in:" for libdir in $libdirs; do $ECHO " $libdir" done $ECHO $ECHO "If you ever happen to want to link against installed libraries" $ECHO "in a given directory, LIBDIR, you must either use libtool, and" $ECHO "specify the full pathname of the library, or use the \`-LLIBDIR'" $ECHO "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then $ECHO " - add LIBDIR to the \`$shlibpath_var' environment variable" $ECHO " during execution" fi if test -n "$runpath_var"; then $ECHO " - add LIBDIR to the \`$runpath_var' environment variable" $ECHO " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $ECHO " - use the \`$flag' linker flag" fi if test -n "$admincmds"; then $ECHO " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then $ECHO " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" fi $ECHO $ECHO "See any operating system documentation about shared libraries for" case $host in solaris2.[6789]|solaris2.1[0-9]) $ECHO "more information, such as the ld(1), crle(1) and ld.so(8) manual" $ECHO "pages." ;; *) $ECHO "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac $ECHO "X----------------------------------------------------------------------" | $Xsed exit $EXIT_SUCCESS } test "$mode" = finish && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $opt_debug # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || # Allow the use of GNU shtool's install command. $ECHO "X$nonopt" | $GREP shtool >/dev/null; then # Aesthetically quote it. func_quote_for_eval "$nonopt" install_prog="$func_quote_for_eval_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_for_eval "$arg" install_prog="$install_prog$func_quote_for_eval_result" # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=no stripme= for arg do if test -n "$dest"; then files="$files $dest" dest=$arg continue fi case $arg in -d) isdir=yes ;; -f) case " $install_prog " in *[\\\ /]cp\ *) ;; *) prev=$arg ;; esac ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_for_eval "$arg" install_prog="$install_prog $func_quote_for_eval_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the \`$prev' option requires an argument" if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=yes if test "$isdir" = yes; then destdir="$dest" destname= else func_dirname_and_basename "$dest" "" "." destdir="$func_dirname_result" destname="$func_basename_result" # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "\`$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "\`$destdir' must be an absolute directory name" ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. staticlibs="$staticlibs $file" ;; *.la) # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) current_libdirs="$current_libdirs $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) future_libdirs="$future_libdirs $libdir" ;; esac fi func_dirname "$file" "/" "" dir="$func_dirname_result" dir="$dir$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "X$destdir" | $Xsed -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%%"` fi func_warning "relinking \`$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname="$1" shift srcname="$realname" test -n "$relink_command" && srcname="$realname"T # Install the shared library and build the symlinks. func_show_eval "$install_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme="$stripme" case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme="" ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try `ln -sf' first, because the `ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib="$destdir/$realname" func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name="$func_basename_result" instname="$dir/$name"i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest="$destfile" destfile= ;; *) func_fatal_help "cannot copy a libtool object to \`$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test "$build_old_libs" = yes; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext="" case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=".exe" fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script \`$wrapper'" finalize=yes for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile="$libdir/"`$ECHO "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test if test -n "$libdir" && test ! -f "$libfile"; then func_warning "\`$lib' has not been installed in \`$libdir'" finalize=no fi done relink_command= func_source "$wrapper" outputname= if test "$fast_install" = no && test -n "$relink_command"; then $opt_dry_run || { if test "$finalize" = yes; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file="$func_basename_result" outputname="$tmpdir/$file" # Replace the output file specification. relink_command=`$ECHO "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` $opt_silent || { func_quote_for_expand "$relink_command" eval "func_echo $func_quote_for_expand_result" } if eval "$relink_command"; then : else func_error "error: relink \`$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file="$outputname" else func_warning "cannot relink \`$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name="$func_basename_result" # Set up the ranlib parameters. oldlib="$destdir/$name" func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run \`$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test "$mode" = install && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $opt_debug my_outputname="$1" my_originator="$2" my_pic_p="${3-no}" my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms="${my_outputname}S.c" else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist="$output_objdir/${my_outputname}.nm" func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; then func_verbose "generating symbol list for \`$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` for progfile in $progfiles; do func_verbose "extracting global C symbols from \`$progfile'" $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols="$output_objdir/$outputname.exp" $opt_dry_run || { $RM $export_symbols eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from \`$dlprefile'" func_basename "$dlprefile" name="$func_basename_result" $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'" } done $opt_dry_run || { # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if $GREP -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else $GREP -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else $ECHO '/* NONE */' >> "$output_objdir/$my_dlsyms" fi $ECHO >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; " case $host in *cygwin* | *mingw* | *cegcc* ) $ECHO >> "$output_objdir/$my_dlsyms" "\ /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */" lt_dlsym_const= ;; *osf5*) echo >> "$output_objdir/$my_dlsyms" "\ /* This system does not cope well with relocations in const data */" lt_dlsym_const= ;; *) lt_dlsym_const=const ;; esac $ECHO >> "$output_objdir/$my_dlsyms" "\ extern $lt_dlsym_const lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[]; $lt_dlsym_const lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = {\ { \"$my_originator\", (void *) 0 }," case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac $ECHO >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) if test "X$my_pic_p" != Xno; then pic_flag_for_symtable=" $pic_flag" fi ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) symtab_cflags="$symtab_cflags $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' # Transform the symbol file into the correct name. symfileobj="$output_objdir/${my_outputname}S.$objext" case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for \`$my_dlsyms'" ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$ECHO "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` fi } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. func_win32_libid () { $opt_debug win32_libid_type="unknown" win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then win32_nmres=`eval $NM -f posix -A $1 | $SED -n -e ' 1,100{ / I /{ s,.*,import, p q } }'` case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_extract_an_archive dir oldlib func_extract_an_archive () { $opt_debug f_ex_an_ar_dir="$1"; shift f_ex_an_ar_oldlib="$1" func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" 'exit $?' if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $opt_debug my_gentop="$1"; shift my_oldlibs=${1+"$@"} my_oldobjs="" my_xlib="" my_xabs="" my_xdir="" for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib="$func_basename_result" my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir="$my_gentop/$my_xlib_u" func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` darwin_base_archive=`basename "$darwin_archive"` darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches ; do func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" func_extract_an_archive "`pwd`" "${darwin_base_archive}" cd "$darwin_curdir" $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` done func_extract_archives_result="$my_oldobjs" } # func_emit_wrapper_part1 [arg=no] # # Emit the first part of a libtool wrapper script on stdout. # For more information, see the description associated with # func_emit_wrapper(), below. func_emit_wrapper_part1 () { func_emit_wrapper_part1_arg1=no if test -n "$1" ; then func_emit_wrapper_part1_arg1=$1 fi $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed='${SED} -e 1s/^X//' sed_quote_subst='$sed_quote_subst' # Be Bourne compatible if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then ECHO=\"$qecho\" file=\"\$0\" # Make sure echo works. if test \"X\$1\" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test \"X\`{ \$ECHO '\t'; } 2>/dev/null\`\" = 'X\t'; then # Yippee, \$ECHO works! : else # Restart under the correct shell, and then maybe \$ECHO will work. exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} fi fi\ " $ECHO "\ # Find the directory that this script lives in. thisdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$ECHO \"X\$file\" | \$Xsed -e 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` done " } # end: func_emit_wrapper_part1 # func_emit_wrapper_part2 [arg=no] # # Emit the second part of a libtool wrapper script on stdout. # For more information, see the description associated with # func_emit_wrapper(), below. func_emit_wrapper_part2 () { func_emit_wrapper_part2_arg1=no if test -n "$1" ; then func_emit_wrapper_part2_arg1=$1 fi $ECHO "\ # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_part2_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"X\$thisdir\" | \$Xsed -e 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test "$fast_install" = yes; then $ECHO "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $MKDIR \"\$progdir\" else $RM \"\$progdir/\$file\" fi" $ECHO "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else $ECHO \"\$relink_command_output\" >&2 $RM \"\$progdir/\$file\" exit 1 fi fi $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $RM \"\$progdir/\$program\"; $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } $RM \"\$progdir/\$file\" fi" else $ECHO "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$ECHO \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` export $shlibpath_var " fi # fixup the dll searchpath if we need to. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 fi else # The program doesn't exist. \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 $ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } # end: func_emit_wrapper_part2 # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory in which it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=no if test -n "$1" ; then func_emit_wrapper_arg1=$1 fi # split this up so that func_emit_cwrapperexe_src # can call each part independently. func_emit_wrapper_part1 "${func_emit_wrapper_arg1}" func_emit_wrapper_part2 "${func_emit_wrapper_arg1}" } # func_to_host_path arg # # Convert paths to host format when used with build tools. # Intended for use with "native" mingw (where libtool itself # is running under the msys shell), or in the following cross- # build environments: # $build $host # mingw (msys) mingw [e.g. native] # cygwin mingw # *nix + wine mingw # where wine is equipped with the `winepath' executable. # In the native mingw case, the (msys) shell automatically # converts paths for any non-msys applications it launches, # but that facility isn't available from inside the cwrapper. # Similar accommodations are necessary for $host mingw and # $build cygwin. Calling this function does no harm for other # $host/$build combinations not listed above. # # ARG is the path (on $build) that should be converted to # the proper representation for $host. The result is stored # in $func_to_host_path_result. func_to_host_path () { func_to_host_path_result="$1" if test -n "$1" ; then case $host in *mingw* ) lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' case $build in *mingw* ) # actually, msys # awkward: cmd appends spaces to result lt_sed_strip_trailing_spaces="s/[ ]*\$//" func_to_host_path_tmp1=`( cmd //c echo "$1" |\ $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ $SED -e "$lt_sed_naive_backslashify"` ;; *cygwin* ) func_to_host_path_tmp1=`cygpath -w "$1"` func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ $SED -e "$lt_sed_naive_backslashify"` ;; * ) # Unfortunately, winepath does not exit with a non-zero # error code, so we are forced to check the contents of # stdout. On the other hand, if the command is not # found, the shell will set an exit code of 127 and print # *an error message* to stdout. So we must check for both # error code of zero AND non-empty stdout, which explains # the odd construction: func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null` if test "$?" -eq 0 && test -n "${func_to_host_path_tmp1}"; then func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ $SED -e "$lt_sed_naive_backslashify"` else # Allow warning below. func_to_host_path_result="" fi ;; esac if test -z "$func_to_host_path_result" ; then func_error "Could not determine host path corresponding to" func_error " '$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_path_result="$1" fi ;; esac fi } # end: func_to_host_path # func_to_host_pathlist arg # # Convert pathlists to host format when used with build tools. # See func_to_host_path(), above. This function supports the # following $build/$host combinations (but does no harm for # combinations not listed here): # $build $host # mingw (msys) mingw [e.g. native] # cygwin mingw # *nix + wine mingw # # Path separators are also converted from $build format to # $host format. If ARG begins or ends with a path separator # character, it is preserved (but converted to $host format) # on output. # # ARG is a pathlist (on $build) that should be converted to # the proper representation on $host. The result is stored # in $func_to_host_pathlist_result. func_to_host_pathlist () { func_to_host_pathlist_result="$1" if test -n "$1" ; then case $host in *mingw* ) lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_to_host_pathlist_tmp2="$1" # Once set for this call, this variable should not be # reassigned. It is used in tha fallback case. func_to_host_pathlist_tmp1=`echo "$func_to_host_pathlist_tmp2" |\ $SED -e 's|^:*||' -e 's|:*$||'` case $build in *mingw* ) # Actually, msys. # Awkward: cmd appends spaces to result. lt_sed_strip_trailing_spaces="s/[ ]*\$//" func_to_host_pathlist_tmp2=`( cmd //c echo "$func_to_host_pathlist_tmp1" |\ $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ $SED -e "$lt_sed_naive_backslashify"` ;; *cygwin* ) func_to_host_pathlist_tmp2=`cygpath -w -p "$func_to_host_pathlist_tmp1"` func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ $SED -e "$lt_sed_naive_backslashify"` ;; * ) # unfortunately, winepath doesn't convert pathlists func_to_host_pathlist_result="" func_to_host_pathlist_oldIFS=$IFS IFS=: for func_to_host_pathlist_f in $func_to_host_pathlist_tmp1 ; do IFS=$func_to_host_pathlist_oldIFS if test -n "$func_to_host_pathlist_f" ; then func_to_host_path "$func_to_host_pathlist_f" if test -n "$func_to_host_path_result" ; then if test -z "$func_to_host_pathlist_result" ; then func_to_host_pathlist_result="$func_to_host_path_result" else func_to_host_pathlist_result="$func_to_host_pathlist_result;$func_to_host_path_result" fi fi fi IFS=: done IFS=$func_to_host_pathlist_oldIFS ;; esac if test -z "$func_to_host_pathlist_result" ; then func_error "Could not determine the host path(s) corresponding to" func_error " '$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This may break if $1 contains DOS-style drive # specifications. The fix is not to complicate the expression # below, but for the user to provide a working wine installation # with winepath so that path translation in the cross-to-mingw # case works properly. lt_replace_pathsep_nix_to_dos="s|:|;|g" func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp1" |\ $SED -e "$lt_replace_pathsep_nix_to_dos"` fi # Now, add the leading and trailing path separators back case "$1" in :* ) func_to_host_pathlist_result=";$func_to_host_pathlist_result" ;; esac case "$1" in *: ) func_to_host_pathlist_result="$func_to_host_pathlist_result;" ;; esac ;; esac fi } # end: func_to_host_pathlist # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include # define setmode _setmode #else # include # include # ifdef __CYGWIN__ # include # define HAVE_SETENV # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif # endif #endif #include #include #include #include #include #include #include #include #if defined(PATH_MAX) # define LT_PATHMAX PATH_MAX #elif defined(MAXPATHLEN) # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif #ifdef _MSC_VER # define S_IXUSR _S_IEXEC # define stat _stat # ifndef _INTPTR_T_DEFINED # define intptr_t int # endif #endif #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ defined (__OS2__) # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifdef __CYGWIN__ # define FOPEN_WB "wb" #endif #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free ((void *) stale); stale = 0; } \ } while (0) #undef LTWRAPPER_DEBUGPRINTF #if defined DEBUGWRAPPER # define LTWRAPPER_DEBUGPRINTF(args) ltwrapper_debugprintf args static void ltwrapper_debugprintf (const char *fmt, ...) { va_list args; va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } #else # define LTWRAPPER_DEBUGPRINTF(args) #endif const char *program_name = NULL; void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_fatal (const char *message, ...); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_opt_process_env_set (const char *arg); void lt_opt_process_env_prepend (const char *arg); void lt_opt_process_env_append (const char *arg); int lt_split_name_value (const char *arg, char** name, char** value); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); static const char *script_text_part1 = EOF func_emit_wrapper_part1 yes | $SED -e 's/\([\\"]\)/\\\1/g' \ -e 's/^/ "/' -e 's/$/\\n"/' echo ";" cat <"))); for (i = 0; i < newargc; i++) { LTWRAPPER_DEBUGPRINTF (("(main) newargz[%d] : %s\n", i, (newargz[i] ? newargz[i] : ""))); } EOF case $host_os in mingw*) cat <<"EOF" /* execv doesn't actually work on mingw as expected on unix */ rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz); if (rval == -1) { /* failed to start process */ LTWRAPPER_DEBUGPRINTF (("(main) failed to launch target \"%s\": errno = %d\n", lt_argv_zero, errno)); return 127; } return rval; EOF ;; *) cat <<"EOF" execv (lt_argv_zero, newargz); return rval; /* =127, but avoids unused variable warning */ EOF ;; esac cat <<"EOF" } void * xmalloc (size_t num) { void *p = (void *) malloc (num); if (!p) lt_fatal ("Memory exhausted"); return p; } char * xstrdup (const char *string) { return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL; } const char * base_name (const char *name) { const char *base; #if defined (HAVE_DOS_BASED_FILE_SYSTEM) /* Skip over the disk name in MSDOS pathnames. */ if (isalpha ((unsigned char) name[0]) && name[1] == ':') name += 2; #endif for (base = name; *name; name++) if (IS_DIR_SEPARATOR (*name)) base = name + 1; return base; } int check_executable (const char *path) { struct stat st; LTWRAPPER_DEBUGPRINTF (("(check_executable) : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!")); if ((!path) || (!*path)) return 0; if ((stat (path, &st) >= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; LTWRAPPER_DEBUGPRINTF (("(make_executable) : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!")); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; int tmp_len; char *concat_name; LTWRAPPER_DEBUGPRINTF (("(find_executable) : %s\n", wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!")); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined (HAVE_DOS_BASED_FILE_SYSTEM) if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined (HAVE_DOS_BASED_FILE_SYSTEM) } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = q - p; p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal ("getcwd failed"); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal ("getcwd failed"); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { LTWRAPPER_DEBUGPRINTF (("checking path component for symlinks: %s\n", tmp_pathspec)); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { char *errstr = strerror (errno); lt_fatal ("Error accessing file %s (%s)", tmp_pathspec, errstr); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal ("Could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (strcmp (str, pat) == 0) *str = '\0'; } return str; } static void lt_error_core (int exit_status, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s: %s: ", program_name, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, "FATAL", message, ap); va_end (ap); } void lt_setenv (const char *name, const char *value) { LTWRAPPER_DEBUGPRINTF (("(lt_setenv) setting '%s' to '%s'\n", (name ? name : ""), (value ? value : ""))); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else int len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { int orig_value_len = strlen (orig_value); int add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } int lt_split_name_value (const char *arg, char** name, char** value) { const char *p; int len; if (!arg || !*arg) return 1; p = strchr (arg, (int)'='); if (!p) return 1; *value = xstrdup (++p); len = strlen (arg) - strlen (*value); *name = XMALLOC (char, len); strncpy (*name, arg, len-1); (*name)[len - 1] = '\0'; return 0; } void lt_opt_process_env_set (const char *arg) { char *name = NULL; char *value = NULL; if (lt_split_name_value (arg, &name, &value) != 0) { XFREE (name); XFREE (value); lt_fatal ("bad argument for %s: '%s'", env_set_opt, arg); } lt_setenv (name, value); XFREE (name); XFREE (value); } void lt_opt_process_env_prepend (const char *arg) { char *name = NULL; char *value = NULL; char *new_value = NULL; if (lt_split_name_value (arg, &name, &value) != 0) { XFREE (name); XFREE (value); lt_fatal ("bad argument for %s: '%s'", env_prepend_opt, arg); } new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); XFREE (name); XFREE (value); } void lt_opt_process_env_append (const char *arg) { char *name = NULL; char *value = NULL; char *new_value = NULL; if (lt_split_name_value (arg, &name, &value) != 0) { XFREE (name); XFREE (value); lt_fatal ("bad argument for %s: '%s'", env_append_opt, arg); } new_value = lt_extend_str (getenv (name), value, 1); lt_setenv (name, new_value); XFREE (new_value); XFREE (name); XFREE (value); } void lt_update_exe_path (const char *name, const char *value) { LTWRAPPER_DEBUGPRINTF (("(lt_update_exe_path) modifying '%s' by prepending '%s'\n", (name ? name : ""), (value ? value : ""))); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ int len = strlen (new_value); while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[len-1] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { LTWRAPPER_DEBUGPRINTF (("(lt_update_lib_path) modifying '%s' by prepending '%s'\n", (name ? name : ""), (value ? value : ""))); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF } # end: func_emit_cwrapperexe_src # func_mode_link arg... func_mode_link () { $opt_debug case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # which system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll which has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args=$nonopt base_compile="$nonopt $@" compile_command=$nonopt finalize_command=$nonopt compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=no prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module="${wl}-single_module" func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg="$1" shift func_quote_for_eval "$arg" qarg=$func_quote_for_eval_unquoted_result func_append libtool_args " $func_quote_for_eval_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=yes fi case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test "$dlself" = no; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test "$prev" = dlfiles; then dlfiles="$dlfiles $arg" else dlprefiles="$dlprefiles $arg" fi prev= continue ;; esac ;; expsyms) export_symbols="$arg" test -f "$arg" \ || func_fatal_error "symbol file \`$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex="$arg" prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) deplibs="$deplibs $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir="$arg" prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # moreargs="$moreargs $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then dlfiles="$dlfiles $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. dlprefiles="$dlprefiles $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file \`$arg' does not exist" fi arg=$save_arg prev= continue ;; precious_regex) precious_files_regex="$arg" prev= continue ;; release) release="-$arg" prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test "$prev" = rpath; then case "$rpath " in *" $arg "*) ;; *) rpath="$rpath $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) xrpath="$xrpath $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds="$arg" prev= continue ;; weak) weak_libs="$weak_libs $arg" prev= continue ;; xcclinker) linker_flags="$linker_flags $qarg" compiler_flags="$compiler_flags $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) compiler_flags="$compiler_flags $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) linker_flags="$linker_flags $qarg" compiler_flags="$compiler_flags $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg="$arg" case $arg in -all-static) if test -n "$link_static_flag"; then # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "\`-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test "X$arg" = "X-export-symbols"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname '-L' '' "$arg" dir=$func_stripname_result if test -z "$dir"; then if test "$#" -gt 0; then func_fatal_error "require no space between \`-L' and \`$1'" else func_fatal_error "need path for \`-L' option" fi fi # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of \`$dir'" dir="$absdir" ;; esac case "$deplibs " in *" -L$dir "*) ;; *) deplibs="$deplibs -L$dir" lib_search_path="$lib_search_path $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "X$dir" | $Xsed -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) dllsearchpath="$dllsearchpath:$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) dllsearchpath="$dllsearchpath:$testbindir";; esac ;; esac continue ;; -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test "X$arg" = "X-lc" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework deplibs="$deplibs System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test "X$arg" = "X-lc" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test "X$arg" = "X-lc" && continue ;; esac elif test "X$arg" = "X-lc_r"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi deplibs="$deplibs $arg" continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot) compiler_flags="$compiler_flags $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) compiler_flags="$compiler_flags $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;; esac continue ;; -multi_module) single_module="${wl}-multi_module" continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "\`-no-install' is ignored for $host" func_warning "assuming \`-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) xrpath="$xrpath $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" arg="$arg $wl$func_quote_for_eval_result" compiler_flags="$compiler_flags $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" arg="$arg $wl$func_quote_for_eval_result" compiler_flags="$compiler_flags $wl$func_quote_for_eval_result" linker_flags="$linker_flags $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; # -64, -mips[0-9] enable 64-bit mode on the SGI compiler # -r[0-9][0-9]* specifies the processor on the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler # +DA*, +DD* enable 64-bit mode on the HP compiler # -q* pass through compiler args for the IBM compiler # -m*, -t[45]*, -txscale* pass through architecture-specific # compiler args for GCC # -F/path gives path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC # @file GCC response files -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" func_append compile_command " $arg" func_append finalize_command " $arg" compiler_flags="$compiler_flags $arg" continue ;; # Some other compiler flag. -* | +*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; *.$objext) # A standard object. objs="$objs $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then dlfiles="$dlfiles $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. dlprefiles="$dlprefiles $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. deplibs="$deplibs $arg" old_deplibs="$old_deplibs $arg" continue ;; *.la) # A libtool-controlled library. if test "$prev" = dlfiles; then # This library was specified with -dlopen. dlfiles="$dlfiles $arg" prev= elif test "$prev" = dlprefiles; then # The library was specified with -dlpreopen. dlprefiles="$dlprefiles $arg" prev= else deplibs="$deplibs $arg" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the \`$prevarg' option requires an argument" if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname="$func_basename_result" libobjs_save="$libobjs" if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" func_dirname "$output" "/" "" output_objdir="$func_dirname_result$objdir" # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if $opt_duplicate_deps ; then case "$libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi libs="$libs $deplib" done if test "$linkmode" = lib; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; esac pre_post_deps="$pre_post_deps $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=no newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test "$linkmode,$pass" = "lib,link"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs="$tmp_deplibs" fi if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan"; then libs="$deplibs" deplibs= fi if test "$linkmode" = prog; then case $pass in dlopen) libs="$dlfiles" ;; dlpreopen) libs="$dlprefiles" ;; link) libs="$deplibs %DEPLIBS%" test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" ;; esac fi if test "$linkmode,$pass" = "lib,dlpreopen"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= case $lib in *.la) func_source "$lib" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do deplib_base=`$ECHO "X$deplib" | $Xsed -e "$basename"` case " $weak_libs " in *" $deplib_base "*) ;; *) deplibs="$deplibs $deplib" ;; esac done done libs="$dlprefiles" fi if test "$pass" = dlopen; then # Collect dlpreopened libraries save_deplibs="$deplibs" deplibs= fi for deplib in $libs; do lib= found=no case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else compiler_flags="$compiler_flags $deplib" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; esac fi fi continue ;; -l*) if test "$linkmode" != lib && test "$linkmode" != prog; then func_warning "\`-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test "$linkmode" = lib; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib="$searchdir/lib${name}${search_ext}" if test -f "$lib"; then if test "$search_ext" = ".la"; then found=yes else found=no fi break 2 fi done done if test "$found" != yes; then # deplib doesn't seem to be a libtool library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue else # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll="$l" done if test "X$ll" = "X$old_library" ; then # only static version available found=no func_dirname "$lib" "" "." ladir="$func_dirname_result" lib=$ladir/$old_library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi fi ;; # -l *.ltframework) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test "$pass" = conv && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" newlib_search_path="$newlib_search_path $func_stripname_result" ;; prog) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi if test "$pass" = scan; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" newlib_search_path="$newlib_search_path $func_stripname_result" ;; *) func_warning "\`-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test "$pass" = link; then func_stripname '-R' '' "$deplib" dir=$func_stripname_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) xrpath="$xrpath $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) lib="$deplib" ;; *.$libext) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=no case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"X$deplib\"" 2>/dev/null | $Xsed -e 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=yes fi ;; pass_all) valid_a_lib=yes ;; esac if test "$valid_a_lib" != yes; then $ECHO $ECHO "*** Warning: Trying to link with static lib archive $deplib." $ECHO "*** I have the capability to make that library automatically link in when" $ECHO "*** you link to this library. But I can only do this if you have a" $ECHO "*** shared version of the library, which you do not appear to have" $ECHO "*** because the file extensions .$libext of this argument makes me believe" $ECHO "*** that it is just a static archive that I should not use here." else $ECHO $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" fi ;; esac continue ;; prog) if test "$pass" != link; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test "$pass" = conv; then deplibs="$deplib $deplibs" elif test "$linkmode" = prog; then if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlopen support or we're linking statically, # we need to preload. newdlprefiles="$newdlprefiles $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else newdlfiles="$newdlfiles $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=yes continue ;; esac # case $deplib if test "$found" = yes || test -f "$lib"; then : else func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" fi # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "\`$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir="$func_dirname_result" dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "X$inherited_linker_flags" | $Xsed -e 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO "X $dependency_libs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan" || { test "$linkmode" != prog && test "$linkmode" != lib; }; then test -n "$dlopen" && dlfiles="$dlfiles $dlopen" test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" fi if test "$pass" = conv; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # It is a libtool convenience library, so add in its objects. convenience="$convenience $ladir/$objdir/$old_library" old_convenience="$old_convenience $ladir/$objdir/$old_library" tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_duplicate_deps ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done elif test "$linkmode" != prog && test "$linkmode" != lib; then func_fatal_error "\`$lib' is not a convenience library" fi continue fi # $pass = conv # Get the name of the library we link against. linklib= for l in $old_library $library_names; do linklib="$l" done if test -z "$linklib"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # This library was specified with -dlopen. if test "$pass" = dlopen; then if test -z "$libdir"; then func_fatal_error "cannot -dlopen a convenience library: \`$lib'" fi if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. dlprefiles="$dlprefiles $lib $dependency_libs" else newdlfiles="$newdlfiles $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then func_warning "cannot determine absolute directory name of \`$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir="$ladir" fi ;; esac func_basename "$lib" laname="$func_basename_result" # Find the relevant object directory and library name. if test "X$installed" = Xyes; then if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library \`$lib' was moved." dir="$ladir" absdir="$abs_ladir" libdir="$abs_ladir" else dir="$libdir" absdir="$libdir" fi test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir="$ladir" absdir="$abs_ladir" # Remove this search path later notinst_path="$notinst_path $abs_ladir" else dir="$ladir/$objdir" absdir="$abs_ladir/$objdir" # Remove this search path later notinst_path="$notinst_path $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test "$pass" = dlpreopen; then if test -z "$libdir" && test "$linkmode" = prog; then func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" fi # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then newdlprefiles="$newdlprefiles $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then newdlprefiles="$newdlprefiles $dir/$dlname" else newdlprefiles="$newdlprefiles $dir/$linklib" fi fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test "$linkmode" = lib; then deplibs="$dir/$old_library $deplibs" elif test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test "$linkmode" = prog && test "$pass" != link; then newlib_search_path="$newlib_search_path $ladir" deplibs="$lib $deplibs" linkalldeplibs=no if test "$link_all_deplibs" != no || test -z "$library_names" || test "$build_libtool_libs" = no; then linkalldeplibs=yes fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" newlib_search_path="$newlib_search_path $func_stripname_result" ;; esac # Need to link against all dependency_libs? if test "$linkalldeplibs" = yes; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_duplicate_deps ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done # for deplib continue fi # $linkmode = prog... if test "$linkmode,$pass" = "prog,link"; then if test -n "$library_names" && { { test "$prefer_static_libs" = no || test "$prefer_static_libs,$installed" = "built,yes"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then # Make sure the rpath contains only unique directories. case "$temp_rpath:" in *"$absdir:"*) ;; *) temp_rpath="$temp_rpath$absdir:" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) compile_rpath="$compile_rpath $absdir" esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" esac ;; esac fi # $linkmode,$pass = prog,link... if test "$alldeplibs" = yes && { test "$deplibs_check_method" = pass_all || { test "$build_libtool_libs" = yes && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test "$use_static_libs" = built && test "$installed" = yes; then use_static_libs=no fi if test -n "$library_names" && { test "$use_static_libs" = no || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc*) # No point in relinking DLLs because paths are not encoded notinst_deplibs="$notinst_deplibs $lib" need_relink=no ;; *) if test "$installed" = no; then notinst_deplibs="$notinst_deplibs $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule="" for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule="$dlpremoduletest" break fi done if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then $ECHO if test "$linkmode" = prog; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test "$linkmode" = lib && test "$hardcode_into_libs" = yes; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) compile_rpath="$compile_rpath $absdir" esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname="$1" shift libname=`eval "\\$ECHO \"$libname_spec\""` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname="$dlname" elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw* | *cegcc*) func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; esac eval soname=\"$soname_spec\" else soname="$realname" fi # Make a new name for the extract_expsyms_cmds to use soroot="$soname" func_basename "$soroot" soname="$func_basename_result" func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from \`$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for \`$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test "$linkmode" = prog || test "$mode" != relink; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test "$hardcode_direct" = no; then add="$dir/$linklib" case $host in *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; *-*-sysv4*uw2*) add_dir="-L$dir" ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir="-L$dir" ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we can not # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null ; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library" ; then $ECHO $ECHO "*** And there doesn't seem to be a static archive available" $ECHO "*** The link will probably fail, sorry" else add="$dir/$old_library" fi elif test -n "$old_library"; then add="$dir/$old_library" fi fi esac elif test "$hardcode_minus_L" = no; then case $host in *-*-sunos*) add_shlibpath="$dir" ;; esac add_dir="-L$dir" add="-l$name" elif test "$hardcode_shlibpath_var" = no; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$dir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$dir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) add_dir="$add_dir -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; esac fi if test "$linkmode" = prog; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test "$hardcode_direct" != yes && test "$hardcode_minus_L" != yes && test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; esac fi fi fi if test "$linkmode" = prog || test "$mode" = relink; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$libdir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$libdir" add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; esac add="-l$name" elif test "$hardcode_automatic" = yes; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then add="$inst_prefix_dir$libdir/$linklib" else add="$libdir/$linklib" fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir="-L$libdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) add_dir="$add_dir -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" fi if test "$linkmode" = prog; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test "$linkmode" = prog; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test "$hardcode_direct" != unsupported; then test -n "$old_library" && linklib="$old_library" compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test "$build_libtool_libs" = yes; then # Not a shared library if test "$deplibs_check_method" != pass_all; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. $ECHO $ECHO "*** Warning: This system can not link to static lib archive $lib." $ECHO "*** I have the capability to make that library automatically link in when" $ECHO "*** you link to this library. But I can only do this if you have a" $ECHO "*** shared version of the library, which you do not appear to have." if test "$module" = yes; then $ECHO "*** But as you try to build a module library, libtool will still create " $ECHO "*** a static module, that should work as long as the dlopening application" $ECHO "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then $ECHO $ECHO "*** However, this would only work if libtool was able to extract symbol" $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" $ECHO "*** not find such a program. So, this module is probably useless." $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test "$linkmode" = lib; then if test -n "$dependency_libs" && { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes || test "$link_static" = yes; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) xrpath="$xrpath $temp_xrpath";; esac;; *) temp_deplibs="$temp_deplibs $libdir";; esac done dependency_libs="$temp_deplibs" fi newlib_search_path="$newlib_search_path $absdir" # Link against this library test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" if $opt_duplicate_deps ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done if test "$link_all_deplibs" != no; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do path= case $deplib in -L*) path="$deplib" ;; *.la) func_dirname "$deplib" "" "." dir="$func_dirname_result" # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of \`$dir'" absdir="$dir" fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names" ; then for tmp in $deplibrary_names ; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl" ; then depdepl="$absdir/$objdir/$depdepl" darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}" path= fi fi ;; *) path="-L$absdir/$objdir" ;; esac else eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "\`$deplib' seems to be moved" path="-L$absdir" fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test "$pass" = link; then if test "$linkmode" = "prog"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs="$newdependency_libs" if test "$pass" = dlpreopen; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test "$pass" != dlopen; then if test "$pass" != conv; then # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) lib_search_path="$lib_search_path $dir" ;; esac done newlib_search_path= fi if test "$linkmode,$pass" != "prog,link"; then vars="deplibs" else vars="compile_deplibs finalize_deplibs" fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) tmp_libs="$tmp_libs $deplib" ;; esac ;; *) tmp_libs="$tmp_libs $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs ; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i="" ;; esac if test -n "$i" ; then tmp_libs="$tmp_libs $i" fi done dependency_libs=$tmp_libs done # for pass if test "$linkmode" = prog; then dlfiles="$newdlfiles" fi if test "$linkmode" = prog || test "$linkmode" = lib; then dlprefiles="$newdlprefiles" fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "\`-R' is ignored for archives" test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "\`-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "\`-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" objs="$objs$old_deplibs" ;; lib) # Make sure we only generate libraries of the form `libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test "$module" = no && \ func_fatal_help "libtool library \`$output' must begin with \`lib'" if test "$need_lib_prefix" != no; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test "$deplibs_check_method" != pass_all; then func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" else $ECHO $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" libobjs="$libobjs $objs" fi fi test "$dlself" != no && \ func_warning "\`-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test "$#" -gt 1 && \ func_warning "ignoring multiple \`-rpath's for a libtool library" install_libdir="$1" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; then # Building a libtool convenience library. # Some compilers have problems with a `.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "\`-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs="$IFS"; IFS=':' set dummy $vinfo 0 0 0 shift IFS="$save_ifs" test -n "$7" && \ func_fatal_help "too many parameters to \`-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major="$1" number_minor="$2" number_revision="$3" # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # which has an extra 1 added just for fun # case $version_type in darwin|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_revision" ;; freebsd-aout|freebsd-elf|sunos) current="$number_major" revision="$number_minor" age="0" ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_minor" lt_irix_increment=no ;; *) func_fatal_configuration "$modename: unknown library version type \`$version_type'" ;; esac ;; no) current="$1" revision="$2" age="$3" ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT \`$current' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION \`$revision' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE \`$age' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE \`$age' is greater than the current interface number \`$current'" func_fatal_error "\`$vinfo' is not valid version information" fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current" ;; irix | nonstopux) if test "X$lt_irix_increment" = "Xno"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring="$verstring_prefix$major.$revision" # Add in all the interfaces that we are compatible with. loop=$revision while test "$loop" -ne 0; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring_prefix$major.$iface:$verstring" done # Before this point, $major must not contain `.'. major=.$major versuffix="$major.$revision" ;; linux) func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=".$current.$age.$revision" verstring="$current.$age.$revision" # Add in all the interfaces that we are compatible with. loop=$age while test "$loop" -ne 0; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring:${iface}.0" done # Make executables depend on our current version. verstring="$verstring:${current}.0" ;; qnx) major=".$current" versuffix=".$current" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 filesystems. func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; *) func_fatal_configuration "unknown library version type \`$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring="0.0" ;; esac if test "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then func_warning "undefined symbols not allowed in $host shared libraries" build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi fi func_generate_dlsyms "$libname" "$libname" "yes" libobjs="$libobjs $symfileobj" test "X$libobjs" = "X " && libobjs= if test "$mode" != relink; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) if test "X$precious_files_regex" != "X"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi removelist="$removelist $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then oldlibs="$oldlibs $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "X$lib_search_path " | $Xsed -e "s% $path % %g"` # deplibs=`$ECHO "X$deplibs " | $Xsed -e "s% -L$path % %g"` # dependency_libs=`$ECHO "X$dependency_libs " | $Xsed -e "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do temp_xrpath="$temp_xrpath -R$libdir" case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" ;; esac done if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles="$dlfiles" dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) dlfiles="$dlfiles $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles="$dlprefiles" dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) dlprefiles="$dlprefiles $lib" ;; esac done if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework deplibs="$deplibs System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test "$build_libtool_need_lc" = "yes"; then deplibs="$deplibs -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release="" versuffix="" major="" newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | $GREP " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib="$potent_lib" while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; *) potlib=`$ECHO "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then newdeplibs="$newdeplibs $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes $ECHO $ECHO "*** Warning: linker path does not have real file for library $a_deplib." $ECHO "*** I have the capability to make that library automatically link in when" $ECHO "*** you link to this library. But I can only do this if you have a" $ECHO "*** shared version of the library, which you do not appear to have" $ECHO "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. newdeplibs="$newdeplibs $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $a_deplib "*) newdeplibs="$newdeplibs $a_deplib" a_deplib="" ;; esac fi if test -n "$a_deplib" ; then libname=`eval "\\$ECHO \"$libname_spec\""` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib="$potent_lib" # see symlink-check above in file_magic test if eval "\$ECHO \"X$potent_lib\"" 2>/dev/null | $Xsed -e 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then newdeplibs="$newdeplibs $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes $ECHO $ECHO "*** Warning: linker path does not have real file for library $a_deplib." $ECHO "*** I have the capability to make that library automatically link in when" $ECHO "*** you link to this library. But I can only do this if you have a" $ECHO "*** shared version of the library, which you do not appear to have" $ECHO "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. newdeplibs="$newdeplibs $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" tmp_deplibs=`$ECHO "X $deplibs" | $Xsed \ -e 's/ -lc$//' -e 's/ -[LR][^ ]*//g'` if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then for i in $predeps $postdeps ; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO "X $tmp_deplibs" | $Xsed -e "s,$i,,"` done fi if $ECHO "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' | $GREP . >/dev/null; then $ECHO if test "X$deplibs_check_method" = "Xnone"; then $ECHO "*** Warning: inter-library dependencies are not supported in this platform." else $ECHO "*** Warning: inter-library dependencies are not known to be supported." fi $ECHO "*** All declared inter-library dependencies are being dropped." droppeddeps=yes fi ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's/ -lc / System.ltframework /'` ;; esac if test "$droppeddeps" = yes; then if test "$module" = yes; then $ECHO $ECHO "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" $ECHO "*** a static module, that should work as long as the dlopening" $ECHO "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then $ECHO $ECHO "*** However, this would only work if libtool was able to extract symbol" $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" $ECHO "*** not find such a program. So, this module is probably useless." $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else $ECHO "*** The inter-library dependencies that have been dropped here will be" $ECHO "*** automatically added whenever a program is linked with this library" $ECHO "*** or is declared to -dlopen it." if test "$allow_undefined" = no; then $ECHO $ECHO "*** Since this library must not contain undefined symbols," $ECHO "*** because either the platform does not support them or" $ECHO "*** it was explicitly requested with -no-undefined," $ECHO "*** libtool will only create a static version of it." if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO "X $deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) new_libs="$new_libs -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$new_libs $deplib" ;; esac ;; *) new_libs="$new_libs $deplib" ;; esac done deplibs="$new_libs" # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then if test "$hardcode_into_libs" = yes; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath="$finalize_rpath" test "$mode" != relink && rpath="$compile_rpath$rpath" for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" dep_rpath="$dep_rpath $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) perm_rpath="$perm_rpath $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" if test -n "$hardcode_libdir_flag_spec_ld"; then eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" else eval dep_rpath=\"$hardcode_libdir_flag_spec\" fi fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do rpath="$rpath$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath="$finalize_shlibpath" test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname="$1" shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname="$realname" fi if test -z "$dlname"; then dlname=$soname fi lib="$output_objdir/$realname" linknames= for link do linknames="$linknames $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols="$output_objdir/$libname.uexp" delfiles="$delfiles $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile if test "x`$SED 1q $export_symbols`" != xEXPORTS; then # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols="$export_symbols" export_symbols= always_export_symbols=yes fi fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" func_len " $cmd" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then func_show_eval "$cmd" 'exit $?' skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS="$save_ifs" if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' fi if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) tmp_deplibs="$tmp_deplibs $test_deplib" ;; esac done deplibs="$tmp_deplibs" if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test "$compiler_needs_object" = yes && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_extract_archives $gentop $convenience libobjs="$libobjs $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" linker_flags="$linker_flags $flag" fi # Make a backup of the uninstalled library when relinking if test "$mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test "X$skipped_export" != "X:" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output output_la=`$ECHO "X$output" | $Xsed -e "$basename"` # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then output=${output_objdir}/${output_la}.lnkscript func_verbose "creating GNU ld script: $output" $ECHO 'INPUT (' > $output for obj in $save_libobjs do $ECHO "$obj" >> $output done $ECHO ')' >> $output delfiles="$delfiles $output" elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then output=${output_objdir}/${output_la}.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test "$compiler_needs_object" = yes; then firstobj="$1 " shift fi for obj do $ECHO "$obj" >> $output done delfiles="$delfiles $output" output=$firstobj\"$file_list_spec$output\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-${k}.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test "X$objlist" = X || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test "$k" -eq 1 ; then # The first file doesn't have a previous command to add. eval concat_cmds=\"$reload_cmds $objlist $last_robj\" else # All subsequent reloadable object files will link in # the last one created. eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-${k}.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-${k}.$objext objlist=$obj func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" if test -n "$last_robj"; then eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" fi delfiles="$delfiles $output" else output= fi if ${skipped_export-false}; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi fi test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs="$IFS"; IFS='~' for cmd in $concat_cmds; do IFS="$save_ifs" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi if ${skipped_export-false}; then if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi fi libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_extract_archives $gentop $dlprefiles libobjs="$libobjs $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" # Restore the uninstalled library and exit if test "$mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' fi done # If -module or -export-dynamic was specified, set the dlname. if test "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "\`-R' is ignored for objects" test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for objects" test -n "$release" && \ func_warning "\`-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object \`$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj="$output" ;; esac # Delete the old objects. $opt_dry_run || $RM $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # reload_cmds runs $LD directly, so let us get rid of # -Wl from whole_archive_flag_spec and hope we can get by with # turning comma into space.. wl= if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" reload_conv_objs=$reload_objs\ `$ECHO "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'` else gentop="$output_objdir/${obj}x" generated="$generated $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # Create the old-style object. reload_objs="$objs$old_deplibs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test output="$obj" func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi if test "$build_libtool_libs" != yes; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS fi if test -n "$pic_flag" || test "$pic_mode" != default; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output="$libobj" func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for programs" test -n "$release" && \ func_warning "\`-release' is ignored for programs" test "$preload" = yes \ && test "$dlopen_support" = unknown \ && test "$dlopen_self" = unknown \ && test "$dlopen_self_static" = unknown && \ func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test "$tagname" = CXX ; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) compile_command="$compile_command ${wl}-bind_at_load" finalize_command="$finalize_command ${wl}-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) new_libs="$new_libs -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$new_libs $deplib" ;; esac ;; *) new_libs="$new_libs $deplib" ;; esac done compile_deplibs="$new_libs" compile_command="$compile_command $compile_deplibs" finalize_command="$finalize_command $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" rpath="$rpath $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) perm_rpath="$perm_rpath $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) dllsearchpath="$dllsearchpath:$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) dllsearchpath="$dllsearchpath:$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath="$rpath" rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" rpath="$rpath $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath="$rpath" if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. compile_command=`$ECHO "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` finalize_command=`$ECHO "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" "no" # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=yes case $host in *cygwin* | *mingw* ) if test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; *cegcc) # Disable wrappers for cegcc, we are cross compiling anyway. wrappers_required=no ;; *) if test "$need_relink" = no || test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; esac if test "$wrappers_required" = no; then # Replace the output file specification. compile_command=`$ECHO "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' # Delete the generated files. if test -f "$output_objdir/${outputname}S.${objext}"; then func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' fi exit $exit_status fi if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do rpath="$rpath$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do rpath="$rpath$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test "$no_install" = yes; then # We don't need to create a wrapper script. link_command="$compile_var$compile_command$compile_rpath" # Replace the output file specification. link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' exit $EXIT_SUCCESS fi if test "$hardcode_action" = relink; then # Fast installation is not supported link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" func_warning "this platform does not like uninstalled shared libraries" func_warning "\`$output' will be relinked during installation" else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$ECHO "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # Replace the output file specification. link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' # Now create the wrapper script. func_verbose "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` fi # Quote $ECHO for shipping. if test "X$ECHO" = "X$SHELL $progpath --fallback-echo"; then case $progpath in [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; esac qecho=`$ECHO "X$qecho" | $Xsed -e "$sed_quote_subst"` else qecho=`$ECHO "X$ECHO" | $Xsed -e "$sed_quote_subst"` fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource="$output_path/$objdir/lt-$output_name.c" cwrapper="$output_path/$output_name.exe" $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host" ; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save $symfileobj" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$old_deplibs $non_pic_objects" if test "$preload" = yes && test -f "$symfileobj"; then oldobjs="$oldobjs $symfileobj" fi fi addlibs="$old_convenience" fi if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_extract_archives $gentop $addlibs oldobjs="$oldobjs $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_extract_archives $gentop $dlprefiles oldobjs="$oldobjs $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else $ECHO "copying selected object files to avoid basename conflicts..." gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase="$func_basename_result" case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" oldobjs="$oldobjs $gentop/$newobj" ;; *) oldobjs="$oldobjs $obj" ;; esac done fi eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj" ; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test "X$oldobjs" = "X" ; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test "$build_old_libs" = yes && old_library="$libname.$libext" func_verbose "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` if test "$hardcode_automatic" = yes ; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test "$installed" = yes; then if test -z "$install_libdir"; then break fi output="$output_objdir/$outputname"i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) func_basename "$deplib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" newdependency_libs="$newdependency_libs $libdir/$name" ;; *) newdependency_libs="$newdependency_libs $deplib" ;; esac done dependency_libs="$newdependency_libs" newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" newdlfiles="$newdlfiles $libdir/$name" ;; *) newdlfiles="$newdlfiles $lib" ;; esac done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" newdlprefiles="$newdlprefiles $libdir/$name" ;; esac done dlprefiles="$newdlprefiles" else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac newdlfiles="$newdlfiles $abs" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac newdlprefiles="$newdlprefiles $abs" done dlprefiles="$newdlprefiles" fi $RM $output # place dlname in correct position for cygwin tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Linker flags that can not go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test "$installed" = no && test "$need_relink" = yes; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } { test "$mode" = link || test "$mode" = relink; } && func_mode_link ${1+"$@"} # func_mode_uninstall arg... func_mode_uninstall () { $opt_debug RM="$nonopt" files= rmforce= exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" for arg do case $arg in -f) RM="$RM $arg"; rmforce=yes ;; -*) RM="$RM $arg" ;; *) files="$files $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= origobjdir="$objdir" for file in $files; do func_dirname "$file" "" "." dir="$func_dirname_result" if test "X$dir" = X.; then objdir="$origobjdir" else objdir="$dir/$origobjdir" fi func_basename "$file" name="$func_basename_result" test "$mode" = uninstall && objdir="$dir" # Remember objdir for removal later, being careful to avoid duplicates if test "$mode" = clean; then case " $rmdirs " in *" $objdir "*) ;; *) rmdirs="$rmdirs $objdir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if { test -L "$file"; } >/dev/null 2>&1 || { test -h "$file"; } >/dev/null 2>&1 || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif test "$rmforce" = yes; then continue fi rmfiles="$file" case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do rmfiles="$rmfiles $objdir/$n" done test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" case "$mode" in clean) case " $library_names " in # " " in the beginning catches empty $dlname *" $dlname "*) ;; *) rmfiles="$rmfiles $objdir/$dlname" ;; esac test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test "$pic_object" != none; then rmfiles="$rmfiles $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test "$non_pic_object" != none; then rmfiles="$rmfiles $dir/$non_pic_object" fi fi ;; *) if test "$mode" = clean ; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe rmfiles="$rmfiles $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result rmfiles="$rmfiles $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" if test "$fast_install" = yes && test -n "$relink_command"; then rmfiles="$rmfiles $objdir/lt-$name" fi if test "X$noexename" != "X$name" ; then rmfiles="$rmfiles $objdir/lt-${noexename}.c" fi fi fi ;; esac func_show_eval "$RM $rmfiles" 'exit_status=1' done objdir="$origobjdir" # Try to remove the ${objdir}s in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } { test "$mode" = uninstall || test "$mode" = clean; } && func_mode_uninstall ${1+"$@"} test -z "$mode" && { help="$generic_help" func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode \`$mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # in which we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: # vi:sw=2 gnunet-0.9.3/config.sub0000755000175000017500000010316711762217210011736 00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 # Free Software Foundation, Inc. timestamp='2009-11-20' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted GNU ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nios | nios2 \ | ns16k | ns32k \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | ubicom32 \ | v850 | v850e \ | we32k \ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | picochip) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze) basic_machine=microblaze-xilinx ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; tile*) basic_machine=tile-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: gnunet-0.9.3/gnunet_config.h.in0000644000175000017500000005060611762217207013363 00000000000000/* gnunet_config.h.in. Generated from configure.ac by autoheader. */ #define _GNU_SOURCE 1 /* Define to 1 if the `closedir' function returns void instead of `int'. */ #undef CLOSEDIR_VOID /* This is a Cygwin system */ #undef CYGWIN /* This is an Apple Darwin system */ #undef DARWIN /* Define to 1 if translation of program messages to the user's native language is requested. */ #undef ENABLE_NLS /* enable workarounds used on Windows (only useful for test cases) */ #undef ENABLE_WINDOWS_WORKAROUNDS /* Build a Mac OS X Framework */ #undef FRAMEWORK_BUILD /* This is a FreeBSD system */ #undef FREEBSD /* Define to cull all logging calls */ #undef GNUNET_CULL_LOGGING /* This should be the default choice for the name of the first network interface */ #undef GNUNET_DEFAULT_INTERFACE /* 1 if extra logging is enabled, 2 for very verbose extra logging, 0 otherwise */ #undef GNUNET_EXTRA_LOGGING /* Define to 1 if you have the `argz_add' function. */ #undef HAVE_ARGZ_ADD /* Define to 1 if you have the `argz_append' function. */ #undef HAVE_ARGZ_APPEND /* Define to 1 if you have the `argz_count' function. */ #undef HAVE_ARGZ_COUNT /* Define to 1 if you have the `argz_create_sep' function. */ #undef HAVE_ARGZ_CREATE_SEP /* Define to 1 if you have the header file. */ #undef HAVE_ARGZ_H /* Define to 1 if you have the `argz_insert' function. */ #undef HAVE_ARGZ_INSERT /* Define to 1 if you have the `argz_next' function. */ #undef HAVE_ARGZ_NEXT /* Define to 1 if you have the `argz_stringify' function. */ #undef HAVE_ARGZ_STRINGIFY /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H /* Define to 1 if you have the `atoll' function. */ #undef HAVE_ATOLL /* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the CoreFoundation framework. */ #undef HAVE_CFLOCALECOPYCURRENT /* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in the CoreFoundation framework. */ #undef HAVE_CFPREFERENCESCOPYAPPVALUE /* Define to 1 if your system has a working `chown' function. */ #undef HAVE_CHOWN /* Define to 1 if you have the `clock_gettime' function. */ #undef HAVE_CLOCK_GETTIME /* Define to 1 if you have the `closedir' function. */ #undef HAVE_CLOSEDIR /* Define to 1 if you have the header file. */ #undef HAVE_CTYPE_H /* Define if the GNU dcgettext() function is already present or preinstalled. */ #undef HAVE_DCGETTEXT /* Define to 1 if you have the declaration of `cygwin_conv_path', and to 0 if you don't. */ #undef HAVE_DECL_CYGWIN_CONV_PATH /* Define to 1 if you have the declaration of `gcry_mpi_lshift', and to 0 if you don't. */ #undef HAVE_DECL_GCRY_MPI_LSHIFT /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_DIRENT_H /* Define if you have the GNU dld library. */ #undef HAVE_DLD /* Define to 1 if you have the header file. */ #undef HAVE_DLD_H /* Define to 1 if you have the `dlerror' function. */ #undef HAVE_DLERROR /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have the header file. */ #undef HAVE_DL_H /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ #undef HAVE_DOPRNT /* Define to 1 if you have the `dup2' function. */ #undef HAVE_DUP2 /* Define if you have the _dyld_func_lookup function. */ #undef HAVE_DYLD /* Define to 1 if you have the header file. */ #undef HAVE_ENDIAN_H /* Define to 1 if you have the header file. */ #undef HAVE_ERRNO_H /* Define to 1 if the system has the type `error_t'. */ #undef HAVE_ERROR_T /* Define to 1 if you have the header file. */ #undef HAVE_EXTRACTOR_H /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the `fdatasync' function. */ #undef HAVE_FDATASYNC /* Define to 1 if you have the `floor' function. */ #undef HAVE_FLOOR /* Define to 1 if you have the `fork' function. */ #undef HAVE_FORK /* Define to 1 if you have the `freeifaddrs' function. */ #undef HAVE_FREEIFADDRS /* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ #undef HAVE_FSEEKO /* Define to 1 if you have the `ftruncate' function. */ #undef HAVE_FTRUNCATE /* Define this if getaddrinfo() is available */ #undef HAVE_GETADDRINFO /* Define to 1 if you have the `getcwd' function. */ #undef HAVE_GETCWD /* Define this if gethostbyaddr() is available */ #undef HAVE_GETHOSTBYADDR /* Define this if gethostbyname() is available */ #undef HAVE_GETHOSTBYNAME /* Define to 1 if you have the `gethostbyname2' function. */ #undef HAVE_GETHOSTBYNAME2 /* Define this if gethostname() is available */ #undef HAVE_GETHOSTNAME /* Define to 1 if you have the `getifaddrs' function. */ #undef HAVE_GETIFADDRS /* getloadavg supported */ #undef HAVE_GETLOADAVG /* Define this if getnameinfo() is available */ #undef HAVE_GETNAMEINFO /* Define to 1 if you have the `getpeereid' function. */ #undef HAVE_GETPEEREID /* Define to 1 if you have the `getpeerucred' function. */ #undef HAVE_GETPEERUCRED /* Define to 1 if you have the `getrusage' function. */ #undef HAVE_GETRUSAGE /* Define if the GNU gettext() function is already present or preinstalled. */ #undef HAVE_GETTEXT /* Define to 1 if you have the `gettimeofday' function. */ #undef HAVE_GETTIMEOFDAY /* Define to 1 if you have the header file. */ #undef HAVE_GLPK_H /* Define to 1 if `presolve' is a member of `glp_iocp'. */ #undef HAVE_GLP_IOCP_PRESOLVE /* Define to 1 if you have the `gmtime' function. */ #undef HAVE_GMTIME /* Define to 1 if you have the `gmtime_r' function. */ #undef HAVE_GMTIME_R /* Define if you have the iconv() function. */ #undef HAVE_ICONV /* Define to 1 if you have the header file. */ #undef HAVE_IFADDRS_H /* Define this if inet_ntoa() is available */ #undef HAVE_INET_NTOA /* Define to 1 if you have the `initgroups' function. */ #undef HAVE_INITGROUPS /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_KSTAT_H /* Define to 1 if you have the header file. */ #undef HAVE_KVM_H /* Define to 1 if you have the header file. */ #undef HAVE_LANGINFO_H /* Define to 1 if you have a functional curl library. */ #undef HAVE_LIBCURL /* Define if you have the libdl library or equivalent. */ #undef HAVE_LIBDL /* Define if libdlloader will be built on this platform */ #undef HAVE_LIBDLLOADER /* Have GLPK */ #undef HAVE_LIBGLPK /* Define to 1 if you have the `intl' library (-lintl). */ #undef HAVE_LIBINTL /* Define to 1 if you have the header file. */ #undef HAVE_LIBINTL_H /* Define to 1 if you have the `kstat' library (-lkstat). */ #undef HAVE_LIBKSTAT /* Define to 1 if you have the `kvm' library (-lkvm). */ #undef HAVE_LIBKVM /* Define to 1 if you have the `m' library (-lm). */ #undef HAVE_LIBM /* Define to 1 if you have the `resolv' library (-lresolv). */ #undef HAVE_LIBRESOLV /* Define to 1 if you have the `rt' library (-lrt). */ #undef HAVE_LIBRT /* Define to 1 if you have the `socket' library (-lsocket). */ #undef HAVE_LIBSOCKET /* Define if you have the unistring library. */ #undef HAVE_LIBUNISTRING /* Define to 1 if you have the `z' library (-lz). */ #undef HAVE_LIBZ /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H /* Define to 1 if you have the header file. */ #undef HAVE_LOCALE_H /* Define to 1 if you have the `localtime_r' function. */ #undef HAVE_LOCALTIME_R /* Define this if a modern libltdl is already installed */ #undef HAVE_LTDL /* Define to 1 if you have the header file. */ #undef HAVE_MACH_MACH_H /* Define to 1 if you have the header file. */ #undef HAVE_MACH_O_DYLD_H /* Define to 1 if you have the header file. */ #undef HAVE_MATH_H /* Define to 1 if you have the `memmove' function. */ #undef HAVE_MEMMOVE /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `memset' function. */ #undef HAVE_MEMSET /* We have libmicrohttpd */ #undef HAVE_MHD /* Define to 1 if you have the header file. */ #undef HAVE_MICROHTTPD_H /* Define to 1 if you have the `mkdir' function. */ #undef HAVE_MKDIR /* Define to 1 if you have the `mkfifo' function. */ #undef HAVE_MKFIFO /* Define to 1 if you have the `mktime' function. */ #undef HAVE_MKTIME /* Define to 1 if you have the `mmap' function. */ #undef HAVE_MMAP /* Define to 1 if you have the `mremap' function. */ #undef HAVE_MREMAP /* Define to 1 if you have the header file. */ #undef HAVE_MYSQL_MYSQL_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_SYSTM_H /* Define to 1 if you have the `nl_langinfo' function. */ #undef HAVE_NL_LANGINFO /* Define to 1 if you have the header file. */ #undef HAVE_NSS_H /* Define to 1 if the system has the type `off_t'. */ #undef HAVE_OFF_T /* Define to 1 if you have the `opendir' function. */ #undef HAVE_OPENDIR /* Define to 1 if you have the header file. */ #undef HAVE_POSTGRESQL_LIBPQ_FE_H /* Define if libtool can extract symbol lists from object files. */ #undef HAVE_PRELOADED_SYMBOLS /* Define to 1 if you have the `putenv' function. */ #undef HAVE_PUTENV /* Define to 1 if you have the `rand' function. */ #undef HAVE_RAND /* Define to 1 if you have the `readdir' function. */ #undef HAVE_READDIR /* Define to 1 if you have the `realpath' function. */ #undef HAVE_REALPATH /* Define to 1 if you have the `rmdir' function. */ #undef HAVE_RMDIR /* Define to 1 if you have the `sbrk' function. */ #undef HAVE_SBRK /* Define this if select() is available */ #undef HAVE_SELECT /* Define to 1 if you have the `setlocale' function. */ #undef HAVE_SETLOCALE /* Define to 1 if you have the `setresuid' function. */ #undef HAVE_SETRESUID /* Define to 1 if you have the `setrlimit' function. */ #undef HAVE_SETRLIMIT /* Define if you have the shl_load function. */ #undef HAVE_SHL_LOAD /* Define to 1 if you have the header file. */ #undef HAVE_SIGNAL_H /* Define to 1 if the system has the type `sigset_t'. */ #undef HAVE_SIGSET_T /* Define to 1 if the system has the type `size_t'. */ #undef HAVE_SIZE_T /* Do we have sockaddr_in.sin_len? */ #undef HAVE_SOCKADDR_IN_SIN_LEN /* Define this if socket() is available */ #undef HAVE_SOCKET /* Define to 1 if you have the header file. */ #undef HAVE_SOCKLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_SQLITE3_H /* Define to 1 if you have the `stat64' function. */ #undef HAVE_STAT64 /* Define to 1 if `stat' has the bug that it succeeds when given the zero-length file name argument. */ #undef HAVE_STAT_EMPTY_STRING_BUG /* Define to 1 if you have the header file. */ #undef HAVE_STDARG_H /* Define to 1 if stdbool.h conforms to C99. */ #undef HAVE_STDBOOL_H /* Define to 1 if you have the header file. */ #undef HAVE_STDDEF_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDIO_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strcasecmp' function. */ #undef HAVE_STRCASECMP /* Define to 1 if you have the `strchr' function. */ #undef HAVE_STRCHR /* Define to 1 if you have the `strdup' function. */ #undef HAVE_STRDUP /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR /* Define to 1 if you have the `strftime' function. */ #undef HAVE_STRFTIME /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strlcat' function. */ #undef HAVE_STRLCAT /* Define to 1 if you have the `strlcpy' function. */ #undef HAVE_STRLCPY /* Define to 1 if you have the `strncasecmp' function. */ #undef HAVE_STRNCASECMP /* Define to 1 if you have the `strndup' function. */ #undef HAVE_STRNDUP /* Define to 1 if you have the `strrchr' function. */ #undef HAVE_STRRCHR /* Define to 1 if you have the `strstr' function. */ #undef HAVE_STRSTR /* Define to 1 if you have the `strtol' function. */ #undef HAVE_STRTOL /* Define to 1 if you have the `sysconf' function. */ #undef HAVE_SYSCONF /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_DIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_DL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_ENDIAN_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_FILE_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MMAN_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MOUNT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MSG_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_RESOURCE_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SELECT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STATVFS_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SYSINFO_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIMEB_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_VFS_H /* Define to 1 if you have that is POSIX.1 compatible. */ #undef HAVE_SYS_WAIT_H /* Define to 1 if you have the header file. */ #undef HAVE_TERMINOS_H /* Define to 1 if you have the header file. */ #undef HAVE_UCRED_H /* We can access-64 bit values that are only 32-bit aligned */ #undef HAVE_UNALIGNED_64_ACCESS /* Define to 1 if you have the `uname' function. */ #undef HAVE_UNAME /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the `vfork' function. */ #undef HAVE_VFORK /* Define to 1 if you have the header file. */ #undef HAVE_VFORK_H /* Define to 1 if you have the `vprintf' function. */ #undef HAVE_VPRINTF /* This value is set to 1 to indicate that the system argz facility works */ #undef HAVE_WORKING_ARGZ /* Define to 1 if `fork' works. */ #undef HAVE_WORKING_FORK /* Define to 1 if `vfork' works. */ #undef HAVE_WORKING_VFORK /* Define to 1 if the system has the type `_Bool'. */ #undef HAVE__BOOL /* Define as const if the declaration of iconv() needs const. */ #undef ICONV_CONST /* Defined if libcurl supports AsynchDNS */ #undef LIBCURL_FEATURE_ASYNCHDNS /* Defined if libcurl supports IDN */ #undef LIBCURL_FEATURE_IDN /* Defined if libcurl supports IPv6 */ #undef LIBCURL_FEATURE_IPV6 /* Defined if libcurl supports KRB4 */ #undef LIBCURL_FEATURE_KRB4 /* Defined if libcurl supports libz */ #undef LIBCURL_FEATURE_LIBZ /* Defined if libcurl supports NTLM */ #undef LIBCURL_FEATURE_NTLM /* Defined if libcurl supports SSL */ #undef LIBCURL_FEATURE_SSL /* Defined if libcurl supports SSPI */ #undef LIBCURL_FEATURE_SSPI /* Defined if libcurl supports DICT */ #undef LIBCURL_PROTOCOL_DICT /* Defined if libcurl supports FILE */ #undef LIBCURL_PROTOCOL_FILE /* Defined if libcurl supports FTP */ #undef LIBCURL_PROTOCOL_FTP /* Defined if libcurl supports FTPS */ #undef LIBCURL_PROTOCOL_FTPS /* Defined if libcurl supports HTTP */ #undef LIBCURL_PROTOCOL_HTTP /* Defined if libcurl supports HTTPS */ #undef LIBCURL_PROTOCOL_HTTPS /* Defined if libcurl supports IMAP */ #undef LIBCURL_PROTOCOL_IMAP /* Defined if libcurl supports LDAP */ #undef LIBCURL_PROTOCOL_LDAP /* Defined if libcurl supports POP3 */ #undef LIBCURL_PROTOCOL_POP3 /* Defined if libcurl supports RTSP */ #undef LIBCURL_PROTOCOL_RTSP /* Defined if libcurl supports SMTP */ #undef LIBCURL_PROTOCOL_SMTP /* Defined if libcurl supports TELNET */ #undef LIBCURL_PROTOCOL_TELNET /* Defined if libcurl supports TFTP */ #undef LIBCURL_PROTOCOL_TFTP /* This is a Linux system */ #undef LINUX /* Define to 1 if `lstat' dereferences a symlink specified with a trailing slash. */ #undef LSTAT_FOLLOWS_SLASHED_SYMLINK /* Define if the OS needs help to load dependent libraries for dlopen(). */ #undef LTDL_DLOPEN_DEPLIBS /* Define to the system default library search path. */ #undef LT_DLSEARCH_PATH /* The archive extension */ #undef LT_LIBEXT /* Define to the extension used for runtime loadable modules, say, ".so". */ #undef LT_MODULE_EXT /* Define to the name of the environment variable that determines the run-time module search path. */ #undef LT_MODULE_PATH_VAR /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* This is a MinGW system */ #undef MINGW /* Define if dlsym() requires a leading underscore in symbol names. */ #undef NEED_USCORE /* This is a NetBSD system */ #undef NETBSD /* Define to 1 if your C compiler doesn't accept -c and -o together. */ #undef NO_MINUS_C_MINUS_O /* This is an OpenBSD system */ #undef OPENBSD /* Some strange OS */ #undef OTHEROS /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define as the return type of signal handlers (`int' or `void'). */ #undef RETSIGTYPE /* Define to the type of arg 1 for `select'. */ #undef SELECT_TYPE_ARG1 /* Define to the type of args 2, 3 and 4 for `select'. */ #undef SELECT_TYPE_ARG234 /* Define to the type of arg 5 for `select'. */ #undef SELECT_TYPE_ARG5 /* This is a Solaris system */ #undef SOLARIS /* This is a BSD system */ #undef SOMEBSD /* Define to 1 if the `S_IS*' macros in do not work properly. */ #undef STAT_MACROS_BROKEN /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define to 1 if you can safely include both and . */ #undef TIME_WITH_SYS_TIME /* Define to 1 if your declares `struct tm'. */ #undef TM_IN_SYS_TIME /* Version number of package */ #undef VERSION /* This is a Windows system */ #undef WINDOWS /* Define to 1 if the X Window System is missing or not being used. */ #undef X_DISPLAY_MISSING /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS /* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ #undef _LARGEFILE_SOURCE /* Define for large files, on AIX-style hosts. */ #undef _LARGE_FILES /* Need with solaris or errno doesnt work */ #undef _REENTRANT /* This is a Windows system */ #undef _WIN32 /* Define so that glibc/gnulib argp.h does not typedef error_t. */ #undef __error_t_defined /* Define curl_free() as free() if our version of curl lacks curl_free. */ #undef curl_free /* Define to a type to use for `error_t' if it is not otherwise available. */ #undef error_t /* Define to `int' if doesn't define. */ #undef gid_t /* Define to `int' if does not define. */ #undef mode_t /* Define to `long int' if does not define. */ #undef off_t /* Define to `int' if does not define. */ #undef pid_t /* Define to `unsigned int' if does not define. */ #undef size_t /* Define to `int' if doesn't define. */ #undef uid_t /* Define as `fork' if `vfork' does not work. */ #undef vfork gnunet-0.9.3/aclocal.m40000644000175000017500000013240111762217205011610 00000000000000# generated automatically by aclocal 1.11.1 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.67],, [m4_warning([this file was generated for autoconf 2.67. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically `autoreconf'.])]) # Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.11' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.11.1], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.11.1])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to # `$srcdir', `$srcdir/..', or `$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is `.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 9 # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ(2.52)dnl ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 10 # There are a few dirty hacks below to avoid letting `AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "GCJ", or "OBJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl ifelse([$1], CC, [depcc="$CC" am_compiler_list=], [$1], CXX, [depcc="$CXX" am_compiler_list=], [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], UPC, [depcc="$UPC" am_compiler_list=], [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE(dependency-tracking, [ --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. #serial 5 # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Autoconf 2.62 quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each `.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2008, 2009 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 16 # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.62])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) AM_MISSING_PROG(AUTOCONF, autoconf) AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) AM_MISSING_PROG(AUTOHEADER, autoheader) AM_MISSING_PROG(MAKEINFO, makeinfo) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AM_PROG_MKDIR_P])dnl # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES(CC)], [define([AC_PROG_CC], defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES(CXX)], [define([AC_PROG_CXX], defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES(OBJC)], [define([AC_PROG_OBJC], defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl ]) _AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl dnl The `parallel-tests' driver may need to know about EXEEXT, so add the dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl ]) dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST(install_sh)]) # Copyright (C) 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 4 # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from `make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 6 # AM_PROG_CC_C_O # -------------- # Like AC_PROG_CC_C_O, but changed for automake. AC_DEFUN([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC_C_O])dnl AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl # FIXME: we rely on the cache variable name because # there is no other way. set dummy $CC am_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']` eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o if test "$am_t" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi dnl Make sure AC_PROG_CC is never called again, or it will override our dnl setting of CC. m4_define([AC_PROG_CC], [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])]) ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 6 # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it supports --run. # If it does, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= AC_MSG_WARN([`missing' script is too old or missing]) fi ]) # Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_MKDIR_P # --------------- # Check for `mkdir -p'. AC_DEFUN([AM_PROG_MKDIR_P], [AC_PREREQ([2.60])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, dnl while keeping a definition of mkdir_p for backward compatibility. dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of dnl Makefile.ins that do not define MKDIR_P, so we do our own dnl adjustment using top_builddir (which is defined more often than dnl MKDIR_P). AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl case $mkdir_p in [[\\/$]]* | ?:[[\\/]]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 4 # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # ------------------------------ # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), 1)]) # _AM_SET_OPTIONS(OPTIONS) # ---------------------------------- # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PATH_PYTHON([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # --------------------------------------------------------------------------- # Adds support for distributing Python modules and packages. To # install modules, copy them to $(pythondir), using the python_PYTHON # automake variable. To install a package with the same name as the # automake package, install to $(pkgpythondir), or use the # pkgpython_PYTHON automake variable. # # The variables $(pyexecdir) and $(pkgpyexecdir) are provided as # locations to install python extension modules (shared libraries). # Another macro is required to find the appropriate flags to compile # extension modules. # # If your package is configured with a different prefix to python, # users will have to add the install directory to the PYTHONPATH # environment variable, or create a .pth file (see the python # documentation for details). # # If the MINIMUM-VERSION argument is passed, AM_PATH_PYTHON will # cause an error if the version of python installed on the system # doesn't meet the requirement. MINIMUM-VERSION should consist of # numbers and dots only. AC_DEFUN([AM_PATH_PYTHON], [ dnl Find a Python interpreter. Python versions prior to 2.0 are not dnl supported. (2.0 was released on October 16, 2000). m4_define_default([_AM_PYTHON_INTERPRETER_LIST], [python python2 python3 python3.0 python2.5 python2.4 python2.3 python2.2 dnl python2.1 python2.0]) m4_if([$1],[],[ dnl No version check is needed. # Find any Python interpreter. if test -z "$PYTHON"; then AC_PATH_PROGS([PYTHON], _AM_PYTHON_INTERPRETER_LIST, :) fi am_display_PYTHON=python ], [ dnl A version check is needed. if test -n "$PYTHON"; then # If the user set $PYTHON, use it and don't search something else. AC_MSG_CHECKING([whether $PYTHON version >= $1]) AM_PYTHON_CHECK_VERSION([$PYTHON], [$1], [AC_MSG_RESULT(yes)], [AC_MSG_ERROR(too old)]) am_display_PYTHON=$PYTHON else # Otherwise, try each interpreter until we find one that satisfies # VERSION. AC_CACHE_CHECK([for a Python interpreter with version >= $1], [am_cv_pathless_PYTHON],[ for am_cv_pathless_PYTHON in _AM_PYTHON_INTERPRETER_LIST none; do test "$am_cv_pathless_PYTHON" = none && break AM_PYTHON_CHECK_VERSION([$am_cv_pathless_PYTHON], [$1], [break]) done]) # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON. if test "$am_cv_pathless_PYTHON" = none; then PYTHON=: else AC_PATH_PROG([PYTHON], [$am_cv_pathless_PYTHON]) fi am_display_PYTHON=$am_cv_pathless_PYTHON fi ]) if test "$PYTHON" = :; then dnl Run any user-specified action, or abort. m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])]) else dnl Query Python for its version number. Getting [:3] seems to be dnl the best way to do this; it's what "site.py" does in the standard dnl library. AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version], [am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[[:3]])"`]) AC_SUBST([PYTHON_VERSION], [$am_cv_python_version]) dnl Use the values of $prefix and $exec_prefix for the corresponding dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made dnl distinct variables so they can be overridden if need be. However, dnl general consensus is that you shouldn't need this ability. AC_SUBST([PYTHON_PREFIX], ['${prefix}']) AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}']) dnl At times (like when building shared libraries) you may want dnl to know which OS platform Python thinks this is. AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform], [am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`]) AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform]) dnl Set up 4 directories: dnl pythondir -- where to install python scripts. This is the dnl site-packages directory, not the python standard library dnl directory like in previous automake betas. This behavior dnl is more consistent with lispdir.m4 for example. dnl Query distutils for this directory. distutils does not exist in dnl Python 1.5, so we fall back to the hardcoded directory if it dnl doesn't work. AC_CACHE_CHECK([for $am_display_PYTHON script directory], [am_cv_python_pythondir], [if test "x$prefix" = xNONE then am_py_prefix=$ac_default_prefix else am_py_prefix=$prefix fi am_cv_python_pythondir=`$PYTHON -c "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_python_lib(0,0,prefix='$am_py_prefix'))" 2>/dev/null || echo "$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages"` case $am_cv_python_pythondir in $am_py_prefix*) am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'` am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"` ;; *) case $am_py_prefix in /usr|/System*) ;; *) am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages ;; esac ;; esac ]) AC_SUBST([pythondir], [$am_cv_python_pythondir]) dnl pkgpythondir -- $PACKAGE directory under pythondir. Was dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is dnl more consistent with the rest of automake. AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE]) dnl pyexecdir -- directory for installing python extension modules dnl (shared libraries) dnl Query distutils for this directory. distutils does not exist in dnl Python 1.5, so we fall back to the hardcoded directory if it dnl doesn't work. AC_CACHE_CHECK([for $am_display_PYTHON extension module directory], [am_cv_python_pyexecdir], [if test "x$exec_prefix" = xNONE then am_py_exec_prefix=$am_py_prefix else am_py_exec_prefix=$exec_prefix fi am_cv_python_pyexecdir=`$PYTHON -c "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_python_lib(1,0,prefix='$am_py_exec_prefix'))" 2>/dev/null || echo "$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages"` case $am_cv_python_pyexecdir in $am_py_exec_prefix*) am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'` am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"` ;; *) case $am_py_exec_prefix in /usr|/System*) ;; *) am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages ;; esac ;; esac ]) AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir]) dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE) AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE]) dnl Run any user-specified action. $2 fi ]) # AM_PYTHON_CHECK_VERSION(PROG, VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) # --------------------------------------------------------------------------- # Run ACTION-IF-TRUE if the Python interpreter PROG has version >= VERSION. # Run ACTION-IF-FALSE otherwise. # This test uses sys.hexversion instead of the string equivalent (first # word of sys.version), in order to cope with versions such as 2.2c1. # This supports Python 2.0 or higher. (2.0 was released on October 16, 2000). AC_DEFUN([AM_PYTHON_CHECK_VERSION], [prog="import sys # split strings by '.' and convert to numeric. Append some zeros # because we need at least 4 digits for the hex conversion. # map returns an iterator in Python 3.0 and a list in 2.x minver = list(map(int, '$2'.split('.'))) + [[0, 0, 0]] minverhex = 0 # xrange is not present in Python 3.0 and range returns an iterator for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]] sys.exit(sys.hexversion < minverhex)" AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])]) # Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 5 # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Just in case sleep 1 echo timestamp > conftest.file # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; esac # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi rm -f conftest.file if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT(yes)]) # Copyright (C) 2009 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # (`yes' being less verbose, `no' or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [ --enable-silent-rules less verbose build output (undo: `make V=1') --disable-silent-rules verbose build output (undo: `make V=0')]) case $enable_silent_rules in yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor `install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in `make install-strip', and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be `maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006, 2008 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of `v7', `ustar', or `pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. AM_MISSING_PROG([AMTAR], [tar]) m4_if([$1], [v7], [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], [m4_case([$1], [ustar],, [pax],, [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' _am_tools=${am_cv_prog_tar_$1-$_am_tools} # Do not fold the above two line into one, because Tru64 sh and # Solaris sh will not grok spaces in the rhs of `-'. for _am_tool in $_am_tools do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([m4/absolute-header.m4]) m4_include([m4/align.m4]) m4_include([m4/argz.m4]) m4_include([m4/gettext.m4]) m4_include([m4/iconv.m4]) m4_include([m4/lib-ld.m4]) m4_include([m4/lib-link.m4]) m4_include([m4/lib-prefix.m4]) m4_include([m4/libcurl.m4]) m4_include([m4/libgcrypt.m4]) m4_include([m4/libtool.m4]) m4_include([m4/libunistring.m4]) m4_include([m4/ltdl.m4]) m4_include([m4/ltoptions.m4]) m4_include([m4/ltsugar.m4]) m4_include([m4/ltversion.m4]) m4_include([m4/lt~obsolete.m4]) m4_include([m4/nls.m4]) m4_include([m4/po.m4]) m4_include([m4/progtest.m4]) m4_include([acinclude.m4]) gnunet-0.9.3/gnunet_config.h0000644000175000017500000005330011763406505012752 00000000000000/* gnunet_config.h. Generated from gnunet_config.h.in by configure. */ /* gnunet_config.h.in. Generated from configure.ac by autoheader. */ #define _GNU_SOURCE 1 /* Define to 1 if the `closedir' function returns void instead of `int'. */ /* #undef CLOSEDIR_VOID */ /* This is a Cygwin system */ /* #undef CYGWIN */ /* This is an Apple Darwin system */ /* #undef DARWIN */ /* Define to 1 if translation of program messages to the user's native language is requested. */ #define ENABLE_NLS 1 /* enable workarounds used on Windows (only useful for test cases) */ #define ENABLE_WINDOWS_WORKAROUNDS 0 /* Build a Mac OS X Framework */ /* #undef FRAMEWORK_BUILD */ /* This is a FreeBSD system */ /* #undef FREEBSD */ /* Define to cull all logging calls */ /* #undef GNUNET_CULL_LOGGING */ /* This should be the default choice for the name of the first network interface */ #define GNUNET_DEFAULT_INTERFACE "eth0" /* 1 if extra logging is enabled, 2 for very verbose extra logging, 0 otherwise */ #define GNUNET_EXTRA_LOGGING GNUNET_NO /* Define to 1 if you have the `argz_add' function. */ #define HAVE_ARGZ_ADD 1 /* Define to 1 if you have the `argz_append' function. */ #define HAVE_ARGZ_APPEND 1 /* Define to 1 if you have the `argz_count' function. */ #define HAVE_ARGZ_COUNT 1 /* Define to 1 if you have the `argz_create_sep' function. */ #define HAVE_ARGZ_CREATE_SEP 1 /* Define to 1 if you have the header file. */ #define HAVE_ARGZ_H 1 /* Define to 1 if you have the `argz_insert' function. */ #define HAVE_ARGZ_INSERT 1 /* Define to 1 if you have the `argz_next' function. */ #define HAVE_ARGZ_NEXT 1 /* Define to 1 if you have the `argz_stringify' function. */ #define HAVE_ARGZ_STRINGIFY 1 /* Define to 1 if you have the header file. */ #define HAVE_ARPA_INET_H 1 /* Define to 1 if you have the `atoll' function. */ #define HAVE_ATOLL 1 /* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the CoreFoundation framework. */ /* #undef HAVE_CFLOCALECOPYCURRENT */ /* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in the CoreFoundation framework. */ /* #undef HAVE_CFPREFERENCESCOPYAPPVALUE */ /* Define to 1 if your system has a working `chown' function. */ #define HAVE_CHOWN 1 /* Define to 1 if you have the `clock_gettime' function. */ /* #undef HAVE_CLOCK_GETTIME */ /* Define to 1 if you have the `closedir' function. */ #define HAVE_CLOSEDIR 1 /* Define to 1 if you have the header file. */ #define HAVE_CTYPE_H 1 /* Define if the GNU dcgettext() function is already present or preinstalled. */ #define HAVE_DCGETTEXT 1 /* Define to 1 if you have the declaration of `cygwin_conv_path', and to 0 if you don't. */ /* #undef HAVE_DECL_CYGWIN_CONV_PATH */ /* Define to 1 if you have the declaration of `gcry_mpi_lshift', and to 0 if you don't. */ #define HAVE_DECL_GCRY_MPI_LSHIFT 1 /* Define to 1 if you have the header file, and it defines `DIR'. */ #define HAVE_DIRENT_H 1 /* Define if you have the GNU dld library. */ /* #undef HAVE_DLD */ /* Define to 1 if you have the header file. */ /* #undef HAVE_DLD_H */ /* Define to 1 if you have the `dlerror' function. */ #define HAVE_DLERROR 1 /* Define to 1 if you have the header file. */ #define HAVE_DLFCN_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_DL_H */ /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ /* #undef HAVE_DOPRNT */ /* Define to 1 if you have the `dup2' function. */ #define HAVE_DUP2 1 /* Define if you have the _dyld_func_lookup function. */ /* #undef HAVE_DYLD */ /* Define to 1 if you have the header file. */ #define HAVE_ENDIAN_H 1 /* Define to 1 if you have the header file. */ #define HAVE_ERRNO_H 1 /* Define to 1 if the system has the type `error_t'. */ #define HAVE_ERROR_T 1 /* Define to 1 if you have the header file. */ #define HAVE_EXTRACTOR_H 1 /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if you have the `fdatasync' function. */ #define HAVE_FDATASYNC 1 /* Define to 1 if you have the `floor' function. */ /* #undef HAVE_FLOOR */ /* Define to 1 if you have the `fork' function. */ /* #undef HAVE_FORK */ /* Define to 1 if you have the `freeifaddrs' function. */ #define HAVE_FREEIFADDRS 1 /* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ #define HAVE_FSEEKO 1 /* Define to 1 if you have the `ftruncate' function. */ #define HAVE_FTRUNCATE 1 /* Define this if getaddrinfo() is available */ #define HAVE_GETADDRINFO 1 /* Define to 1 if you have the `getcwd' function. */ #define HAVE_GETCWD 1 /* Define this if gethostbyaddr() is available */ #define HAVE_GETHOSTBYADDR 1 /* Define this if gethostbyname() is available */ #define HAVE_GETHOSTBYNAME 1 /* Define to 1 if you have the `gethostbyname2' function. */ #define HAVE_GETHOSTBYNAME2 1 /* Define this if gethostname() is available */ #define HAVE_GETHOSTNAME 1 /* Define to 1 if you have the `getifaddrs' function. */ #define HAVE_GETIFADDRS 1 /* getloadavg supported */ #define HAVE_GETLOADAVG 1 /* Define this if getnameinfo() is available */ #define HAVE_GETNAMEINFO 1 /* Define to 1 if you have the `getpeereid' function. */ /* #undef HAVE_GETPEEREID */ /* Define to 1 if you have the `getpeerucred' function. */ /* #undef HAVE_GETPEERUCRED */ /* Define to 1 if you have the `getrusage' function. */ #define HAVE_GETRUSAGE 1 /* Define if the GNU gettext() function is already present or preinstalled. */ #define HAVE_GETTEXT 1 /* Define to 1 if you have the `gettimeofday' function. */ #define HAVE_GETTIMEOFDAY 1 /* Define to 1 if you have the header file. */ #define HAVE_GLPK_H 1 /* Define to 1 if `presolve' is a member of `glp_iocp'. */ #define HAVE_GLP_IOCP_PRESOLVE 1 /* Define to 1 if you have the `gmtime' function. */ #define HAVE_GMTIME 1 /* Define to 1 if you have the `gmtime_r' function. */ #define HAVE_GMTIME_R 1 /* Define if you have the iconv() function. */ #define HAVE_ICONV 1 /* Define to 1 if you have the header file. */ #define HAVE_IFADDRS_H 1 /* Define this if inet_ntoa() is available */ #define HAVE_INET_NTOA 1 /* Define to 1 if you have the `initgroups' function. */ #define HAVE_INITGROUPS 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_KSTAT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_KVM_H */ /* Define to 1 if you have the header file. */ #define HAVE_LANGINFO_H 1 /* Define to 1 if you have a functional curl library. */ #define HAVE_LIBCURL 1 /* Define if you have the libdl library or equivalent. */ #define HAVE_LIBDL 1 /* Define if libdlloader will be built on this platform */ #define HAVE_LIBDLLOADER 1 /* Have GLPK */ #define HAVE_LIBGLPK 1 /* Define to 1 if you have the `intl' library (-lintl). */ /* #undef HAVE_LIBINTL */ /* Define to 1 if you have the header file. */ #define HAVE_LIBINTL_H 1 /* Define to 1 if you have the `kstat' library (-lkstat). */ /* #undef HAVE_LIBKSTAT */ /* Define to 1 if you have the `kvm' library (-lkvm). */ /* #undef HAVE_LIBKVM */ /* Define to 1 if you have the `m' library (-lm). */ /* #undef HAVE_LIBM */ /* Define to 1 if you have the `resolv' library (-lresolv). */ /* #undef HAVE_LIBRESOLV */ /* Define to 1 if you have the `rt' library (-lrt). */ /* #undef HAVE_LIBRT */ /* Define to 1 if you have the `socket' library (-lsocket). */ /* #undef HAVE_LIBSOCKET */ /* Define if you have the unistring library. */ #define HAVE_LIBUNISTRING 1 /* Define to 1 if you have the `z' library (-lz). */ #define HAVE_LIBZ 1 /* Define to 1 if you have the header file. */ #define HAVE_LIMITS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_LOCALE_H 1 /* Define to 1 if you have the `localtime_r' function. */ #define HAVE_LOCALTIME_R 1 /* Define this if a modern libltdl is already installed */ #define HAVE_LTDL 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_MACH_MACH_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_MACH_O_DYLD_H */ /* Define to 1 if you have the header file. */ #define HAVE_MATH_H 1 /* Define to 1 if you have the `memmove' function. */ /* #undef HAVE_MEMMOVE */ /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the `memset' function. */ /* #undef HAVE_MEMSET */ /* We have libmicrohttpd */ #define HAVE_MHD 1 /* Define to 1 if you have the header file. */ #define HAVE_MICROHTTPD_H 1 /* Define to 1 if you have the `mkdir' function. */ #define HAVE_MKDIR 1 /* Define to 1 if you have the `mkfifo' function. */ #define HAVE_MKFIFO 1 /* Define to 1 if you have the `mktime' function. */ #define HAVE_MKTIME 1 /* Define to 1 if you have the `mmap' function. */ #define HAVE_MMAP 1 /* Define to 1 if you have the `mremap' function. */ #define HAVE_MREMAP 1 /* Define to 1 if you have the header file. */ #define HAVE_MYSQL_MYSQL_H 1 /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_NDIR_H */ /* Define to 1 if you have the header file. */ #define HAVE_NETDB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NETINET_IN_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NETINET_IN_SYSTM_H 1 /* Define to 1 if you have the `nl_langinfo' function. */ #define HAVE_NL_LANGINFO 1 /* Define to 1 if you have the header file. */ #define HAVE_NSS_H 1 /* Define to 1 if the system has the type `off_t'. */ #define HAVE_OFF_T 1 /* Define to 1 if you have the `opendir' function. */ #define HAVE_OPENDIR 1 /* Define to 1 if you have the header file. */ #define HAVE_POSTGRESQL_LIBPQ_FE_H 1 /* Define if libtool can extract symbol lists from object files. */ #define HAVE_PRELOADED_SYMBOLS 1 /* Define to 1 if you have the `putenv' function. */ #define HAVE_PUTENV 1 /* Define to 1 if you have the `rand' function. */ #define HAVE_RAND 1 /* Define to 1 if you have the `readdir' function. */ #define HAVE_READDIR 1 /* Define to 1 if you have the `realpath' function. */ #define HAVE_REALPATH 1 /* Define to 1 if you have the `rmdir' function. */ #define HAVE_RMDIR 1 /* Define to 1 if you have the `sbrk' function. */ #define HAVE_SBRK 1 /* Define this if select() is available */ #define HAVE_SELECT 1 /* Define to 1 if you have the `setlocale' function. */ #define HAVE_SETLOCALE 1 /* Define to 1 if you have the `setresuid' function. */ #define HAVE_SETRESUID 1 /* Define to 1 if you have the `setrlimit' function. */ #define HAVE_SETRLIMIT 1 /* Define if you have the shl_load function. */ /* #undef HAVE_SHL_LOAD */ /* Define to 1 if you have the header file. */ #define HAVE_SIGNAL_H 1 /* Define to 1 if the system has the type `sigset_t'. */ #define HAVE_SIGSET_T 1 /* Define to 1 if the system has the type `size_t'. */ #define HAVE_SIZE_T 1 /* Do we have sockaddr_in.sin_len? */ /* #undef HAVE_SOCKADDR_IN_SIN_LEN */ /* Define this if socket() is available */ #define HAVE_SOCKET 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SOCKLIB_H */ /* Define to 1 if you have the header file. */ #define HAVE_SQLITE3_H 1 /* Define to 1 if you have the `stat64' function. */ #define HAVE_STAT64 1 /* Define to 1 if `stat' has the bug that it succeeds when given the zero-length file name argument. */ /* #undef HAVE_STAT_EMPTY_STRING_BUG */ /* Define to 1 if you have the header file. */ #define HAVE_STDARG_H 1 /* Define to 1 if stdbool.h conforms to C99. */ /* #undef HAVE_STDBOOL_H */ /* Define to 1 if you have the header file. */ #define HAVE_STDDEF_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the `strcasecmp' function. */ /* #undef HAVE_STRCASECMP */ /* Define to 1 if you have the `strchr' function. */ /* #undef HAVE_STRCHR */ /* Define to 1 if you have the `strdup' function. */ /* #undef HAVE_STRDUP */ /* Define to 1 if you have the `strerror' function. */ #define HAVE_STRERROR 1 /* Define to 1 if you have the `strftime' function. */ /* #undef HAVE_STRFTIME */ /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the `strlcat' function. */ /* #undef HAVE_STRLCAT */ /* Define to 1 if you have the `strlcpy' function. */ /* #undef HAVE_STRLCPY */ /* Define to 1 if you have the `strncasecmp' function. */ /* #undef HAVE_STRNCASECMP */ /* Define to 1 if you have the `strndup' function. */ /* #undef HAVE_STRNDUP */ /* Define to 1 if you have the `strrchr' function. */ /* #undef HAVE_STRRCHR */ /* Define to 1 if you have the `strstr' function. */ /* #undef HAVE_STRSTR */ /* Define to 1 if you have the `strtol' function. */ #define HAVE_STRTOL 1 /* Define to 1 if you have the `sysconf' function. */ #define HAVE_SYSCONF 1 /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_SYS_DIR_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_DL_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_ENDIAN_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_FILE_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_IOCTL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_MMAN_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_MOUNT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_MSG_H 1 /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_SYS_NDIR_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_PARAM_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_RESOURCE_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SELECT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SOCKET_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STATVFS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SYSINFO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIMEB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_VFS_H 1 /* Define to 1 if you have that is POSIX.1 compatible. */ #define HAVE_SYS_WAIT_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_TERMINOS_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_UCRED_H */ /* We can access-64 bit values that are only 32-bit aligned */ #define HAVE_UNALIGNED_64_ACCESS 0 /* Define to 1 if you have the `uname' function. */ #define HAVE_UNAME 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if you have the `vfork' function. */ #define HAVE_VFORK 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_VFORK_H */ /* Define to 1 if you have the `vprintf' function. */ /* #undef HAVE_VPRINTF */ /* This value is set to 1 to indicate that the system argz facility works */ #define HAVE_WORKING_ARGZ 1 /* Define to 1 if `fork' works. */ /* #undef HAVE_WORKING_FORK */ /* Define to 1 if `vfork' works. */ #define HAVE_WORKING_VFORK 1 /* Define to 1 if the system has the type `_Bool'. */ #define HAVE__BOOL 1 /* Define as const if the declaration of iconv() needs const. */ #define ICONV_CONST /* Defined if libcurl supports AsynchDNS */ /* #undef LIBCURL_FEATURE_ASYNCHDNS */ /* Defined if libcurl supports IDN */ #define LIBCURL_FEATURE_IDN 1 /* Defined if libcurl supports IPv6 */ #define LIBCURL_FEATURE_IPV6 1 /* Defined if libcurl supports KRB4 */ /* #undef LIBCURL_FEATURE_KRB4 */ /* Defined if libcurl supports libz */ #define LIBCURL_FEATURE_LIBZ 1 /* Defined if libcurl supports NTLM */ #define LIBCURL_FEATURE_NTLM 1 /* Defined if libcurl supports SSL */ #define LIBCURL_FEATURE_SSL 1 /* Defined if libcurl supports SSPI */ /* #undef LIBCURL_FEATURE_SSPI */ /* Defined if libcurl supports DICT */ #define LIBCURL_PROTOCOL_DICT 1 /* Defined if libcurl supports FILE */ #define LIBCURL_PROTOCOL_FILE 1 /* Defined if libcurl supports FTP */ #define LIBCURL_PROTOCOL_FTP 1 /* Defined if libcurl supports FTPS */ #define LIBCURL_PROTOCOL_FTPS 1 /* Defined if libcurl supports HTTP */ #define LIBCURL_PROTOCOL_HTTP 1 /* Defined if libcurl supports HTTPS */ #define LIBCURL_PROTOCOL_HTTPS 1 /* Defined if libcurl supports IMAP */ #define LIBCURL_PROTOCOL_IMAP 1 /* Defined if libcurl supports LDAP */ #define LIBCURL_PROTOCOL_LDAP 1 /* Defined if libcurl supports POP3 */ #define LIBCURL_PROTOCOL_POP3 1 /* Defined if libcurl supports RTSP */ #define LIBCURL_PROTOCOL_RTSP 1 /* Defined if libcurl supports SMTP */ #define LIBCURL_PROTOCOL_SMTP 1 /* Defined if libcurl supports TELNET */ #define LIBCURL_PROTOCOL_TELNET 1 /* Defined if libcurl supports TFTP */ #define LIBCURL_PROTOCOL_TFTP 1 /* This is a Linux system */ #define LINUX 1 /* Define to 1 if `lstat' dereferences a symlink specified with a trailing slash. */ #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 /* Define if the OS needs help to load dependent libraries for dlopen(). */ /* #undef LTDL_DLOPEN_DEPLIBS */ /* Define to the system default library search path. */ #define LT_DLSEARCH_PATH "/lib:/usr/lib:/usr/local/lib:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu" /* The archive extension */ #define LT_LIBEXT "a" /* Define to the extension used for runtime loadable modules, say, ".so". */ #define LT_MODULE_EXT ".so" /* Define to the name of the environment variable that determines the run-time module search path. */ #define LT_MODULE_PATH_VAR "LD_LIBRARY_PATH" /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #define LT_OBJDIR ".libs/" /* This is a MinGW system */ /* #undef MINGW */ /* Define if dlsym() requires a leading underscore in symbol names. */ /* #undef NEED_USCORE */ /* This is a NetBSD system */ /* #undef NETBSD */ /* Define to 1 if your C compiler doesn't accept -c and -o together. */ /* #undef NO_MINUS_C_MINUS_O */ /* This is an OpenBSD system */ /* #undef OPENBSD */ /* Some strange OS */ /* #undef OTHEROS */ /* Name of package */ #define PACKAGE "gnunet" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "bug-gnunet@gnu.org" /* Define to the full name of this package. */ #define PACKAGE_NAME "gnunet" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "gnunet 0.9.3" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "gnunet" /* Define to the home page for this package. */ #define PACKAGE_URL "" /* Define to the version of this package. */ #define PACKAGE_VERSION "0.9.3" /* Define as the return type of signal handlers (`int' or `void'). */ #define RETSIGTYPE void /* Define to the type of arg 1 for `select'. */ #define SELECT_TYPE_ARG1 int /* Define to the type of args 2, 3 and 4 for `select'. */ #define SELECT_TYPE_ARG234 (fd_set *) /* Define to the type of arg 5 for `select'. */ #define SELECT_TYPE_ARG5 (struct timeval *) /* This is a Solaris system */ /* #undef SOLARIS */ /* This is a BSD system */ /* #undef SOMEBSD */ /* Define to 1 if the `S_IS*' macros in do not work properly. */ /* #undef STAT_MACROS_BROKEN */ /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define to 1 if you can safely include both and . */ #define TIME_WITH_SYS_TIME 1 /* Define to 1 if your declares `struct tm'. */ /* #undef TM_IN_SYS_TIME */ /* Version number of package */ #define VERSION "0.9.3" /* This is a Windows system */ /* #undef WINDOWS */ /* Define to 1 if the X Window System is missing or not being used. */ /* #undef X_DISPLAY_MISSING */ /* Number of bits in a file offset, on hosts where this is settable. */ /* #undef _FILE_OFFSET_BITS */ /* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ /* #undef _LARGEFILE_SOURCE */ /* Define for large files, on AIX-style hosts. */ /* #undef _LARGE_FILES */ /* Need with solaris or errno doesnt work */ /* #undef _REENTRANT */ /* This is a Windows system */ /* #undef _WIN32 */ /* Define so that glibc/gnulib argp.h does not typedef error_t. */ /* #undef __error_t_defined */ /* Define curl_free() as free() if our version of curl lacks curl_free. */ /* #undef curl_free */ /* Define to a type to use for `error_t' if it is not otherwise available. */ /* #undef error_t */ /* Define to `int' if doesn't define. */ /* #undef gid_t */ /* Define to `int' if does not define. */ /* #undef mode_t */ /* Define to `long int' if does not define. */ /* #undef off_t */ /* Define to `int' if does not define. */ /* #undef pid_t */ /* Define to `unsigned int' if does not define. */ /* #undef size_t */ /* Define to `int' if doesn't define. */ /* #undef uid_t */ /* Define as `fork' if `vfork' does not work. */ /* #undef vfork */ gnunet-0.9.3/missing0000755000175000017500000002623311762217210011350 00000000000000#! /bin/sh # Common stub for a few missing GNU programs while installing. scriptversion=2009-04-28.21; # UTC # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, # 2008, 2009 Free Software Foundation, Inc. # Originally by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi run=: sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' sed_minuso='s/.* -o \([^ ]*\).*/\1/p' # In the cases where this matters, `missing' is being run in the # srcdir already. if test -f configure.ac; then configure_ac=configure.ac else configure_ac=configure.in fi msg="missing on your system" case $1 in --run) # Try to run requested program, and just exit if it succeeds. run= shift "$@" && exit 0 # Exit code 63 means version mismatch. This often happens # when the user try to use an ancient version of a tool on # a file that requires a minimum version. In this case we # we should proceed has if the program had been absent, or # if --run hadn't been passed. if test $? = 63; then run=: msg="probably too old" fi ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit --run try to run the given command, and emulate it if it fails Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' autom4te touch the output file, or create a stub one automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c help2man touch the output file lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file tar try tar, gnutar, gtar, then tar without non-portable flags yacc create \`y.tab.[ch]', if possible, from existing .[ch] Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and \`g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; esac # normalize program name to check for. program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` # Now exit if we have it, but it failed. Also exit now if we # don't have it and --version was passed (most likely to detect # the program). This is about non-GNU programs, so use $1 not # $program. case $1 in lex*|yacc*) # Not GNU programs, they don't have --version. ;; tar*) if test -n "$run"; then echo 1>&2 "ERROR: \`tar' requires --run" exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then exit 1 fi ;; *) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then # Could not run --version or --help. This is probably someone # running `$TOOL --version' or `$TOOL --help' to check whether # $TOOL exists and not knowing $TOOL uses missing. exit 1 fi ;; esac # If it does not exist, or fails to run (possibly an outdated version), # try to emulate it. case $program in aclocal*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acconfig.h' or \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` test -z "$files" && files="config.h" touch_files= for f in $files; do case $f in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; autom4te*) echo 1>&2 "\ WARNING: \`$1' is needed, but is $msg. You might have modified some files without having the proper tools for further handling them. You can get \`$1' as part of \`Autoconf' from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo "#! /bin/sh" echo "# Created by GNU Automake missing as a replacement of" echo "# $ $@" echo "exit 0" chmod +x $file exit 1 fi ;; bison*|yacc*) echo 1>&2 "\ WARNING: \`$1' $msg. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if test $# -ne 1; then eval LASTARG="\${$#}" case $LASTARG in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.h fi ;; esac fi if test ! -f y.tab.h; then echo >y.tab.h fi if test ! -f y.tab.c; then echo 'main() { return 0; }' >y.tab.c fi ;; lex*|flex*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if test $# -ne 1; then eval LASTARG="\${$#}" case $LASTARG in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if test ! -f lex.yy.c; then echo 'main() { return 0; }' >lex.yy.c fi ;; help2man*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a dependency of a manual page. You may need the \`Help2man' package in order for those modifications to take effect. You can get \`Help2man' from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo ".ab help2man is required to generate this page" exit $? fi ;; makeinfo*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." # The file to touch is that specified with -o ... file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -z "$file"; then # ... or it is the one specified with @setfilename ... infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n ' /^@setfilename/{ s/.* \([^ ]*\) *$/\1/ p q }' $infile` # ... or it is derived from the source name (dir/f.texi becomes f.info) test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info fi # If the file does not exist, the user really needs makeinfo; # let's fail without touching anything. test -f $file || exit 1 touch $file ;; tar*) shift # We have already tried tar in the generic part. # Look for gnutar/gtar before invocation to avoid ugly error # messages. if (gnutar --version > /dev/null 2>&1); then gnutar "$@" && exit 0 fi if (gtar --version > /dev/null 2>&1); then gtar "$@" && exit 0 fi firstarg="$1" if shift; then case $firstarg in *o*) firstarg=`echo "$firstarg" | sed s/o//` tar "$firstarg" "$@" && exit 0 ;; esac case $firstarg in *h*) firstarg=`echo "$firstarg" | sed s/h//` tar "$firstarg" "$@" && exit 0 ;; esac fi echo 1>&2 "\ WARNING: I can't seem to be able to run \`tar' with the given arguments. You may want to install GNU tar or Free paxutils, or check the command line arguments." exit 1 ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and is $msg. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequisites for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: gnunet-0.9.3/depcomp0000755000175000017500000004426711762217213011340 00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2009-04-28.21; # UTC # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009 Free # Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try \`$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by `PROGRAMS ARGS'. object Object file output by `PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputing dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u="sed s,\\\\\\\\,/,g" depmode=msvisualcpp fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ## The second -e expression handles DOS-style file names with drive letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the `deleted header file' problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. tr ' ' ' ' < "$tmpdepfile" | ## Some versions of gcc put a space before the `:'. On the theory ## that the space means something, we add a space to the output as ## well. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like `#:fec' to the end of the # dependency line. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ tr ' ' ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts `$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then # Each line is of the form `foo.o: dependent.h'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" # That's a tab and a space in the []. sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; icc) # Intel's C compiler understands `-MD -MF file'. However on # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c # ICC 7.0 will fill foo.d with something like # foo.o: sub/foo.c # foo.o: sub/foo.h # which is wrong. We want: # sub/foo.o: sub/foo.c # sub/foo.o: sub/foo.h # sub/foo.c: # sub/foo.h: # ICC 7.1 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using \ : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" # Add `dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in `foo.d' instead, so we check for that too. # Subdirectories are respected. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then # With Tru64 cc, shared objects can also be used to make a # static library. This mechanism is used in libtool 1.4 series to # handle both shared and static libraries in a single compilation. # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. # # With libtool 1.5 this exception was removed, and libtool now # generates 2 separate objects for the 2 libraries. These two # compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 tmpdepfile2=$dir$base.o.d # libtool 1.5 tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.o.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d tmpdepfile4=$dir$base.d "$@" -MD fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" # That's a tab and a space in the []. sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove `-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for `:' # in the target name. This is to cope with DOS-style filenames: # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. "$@" $dashmflag | sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" tr ' ' ' ' < "$tmpdepfile" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" sed '1,2d' "$tmpdepfile" | tr ' ' ' ' | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove `-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" echo " " >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: gnunet-0.9.3/m4/0000755000175000017500000000000011763406747010363 500000000000000gnunet-0.9.3/m4/intl.m40000644000175000017500000002333011317762540011503 00000000000000# intl.m4 serial 3 (gettext-0.16) dnl Copyright (C) 1995-2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1995-2000. dnl Bruno Haible , 2000-2006. AC_PREREQ(2.52) dnl Checks for all prerequisites of the intl subdirectory, dnl except for INTL_LIBTOOL_SUFFIX_PREFIX (and possibly LIBTOOL), INTLOBJS, dnl USE_INCLUDED_LIBINTL, BUILD_INCLUDED_LIBINTL. AC_DEFUN([AM_INTL_SUBDIR], [ AC_REQUIRE([AC_PROG_INSTALL])dnl AC_REQUIRE([AM_PROG_MKDIR_P])dnl defined by automake AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([gt_GLIBC2])dnl AC_REQUIRE([AC_PROG_RANLIB])dnl AC_REQUIRE([gl_VISIBILITY])dnl AC_REQUIRE([gt_INTL_SUBDIR_CORE])dnl AC_REQUIRE([AC_TYPE_LONG_LONG_INT])dnl AC_REQUIRE([gt_TYPE_LONGDOUBLE])dnl AC_REQUIRE([gt_TYPE_WCHAR_T])dnl AC_REQUIRE([gt_TYPE_WINT_T])dnl AC_REQUIRE([gl_AC_HEADER_INTTYPES_H]) AC_REQUIRE([gt_TYPE_INTMAX_T]) AC_REQUIRE([gt_PRINTF_POSIX]) AC_REQUIRE([gl_GLIBC21])dnl AC_REQUIRE([gl_XSIZE])dnl AC_REQUIRE([gt_INTL_MACOSX])dnl AC_CHECK_TYPE([ptrdiff_t], , [AC_DEFINE([ptrdiff_t], [long], [Define as the type of the result of subtracting two pointers, if the system doesn't define it.]) ]) AC_CHECK_HEADERS([stddef.h stdlib.h string.h]) AC_CHECK_FUNCS([asprintf fwprintf putenv setenv setlocale snprintf wcslen]) dnl Use the _snprintf function only if it is declared (because on NetBSD it dnl is defined as a weak alias of snprintf; we prefer to use the latter). gt_CHECK_DECL(_snprintf, [#include ]) gt_CHECK_DECL(_snwprintf, [#include ]) dnl Use the *_unlocked functions only if they are declared. dnl (because some of them were defined without being declared in Solaris dnl 2.5.1 but were removed in Solaris 2.6, whereas we want binaries built dnl on Solaris 2.5.1 to run on Solaris 2.6). dnl Don't use AC_CHECK_DECLS because it isn't supported in autoconf-2.13. gt_CHECK_DECL(getc_unlocked, [#include ]) case $gt_cv_func_printf_posix in *yes) HAVE_POSIX_PRINTF=1 ;; *) HAVE_POSIX_PRINTF=0 ;; esac AC_SUBST([HAVE_POSIX_PRINTF]) if test "$ac_cv_func_asprintf" = yes; then HAVE_ASPRINTF=1 else HAVE_ASPRINTF=0 fi AC_SUBST([HAVE_ASPRINTF]) if test "$ac_cv_func_snprintf" = yes; then HAVE_SNPRINTF=1 else HAVE_SNPRINTF=0 fi AC_SUBST([HAVE_SNPRINTF]) if test "$ac_cv_func_wprintf" = yes; then HAVE_WPRINTF=1 else HAVE_WPRINTF=0 fi AC_SUBST([HAVE_WPRINTF]) AM_LANGINFO_CODESET gt_LC_MESSAGES dnl Compilation on mingw and Cygwin needs special Makefile rules, because dnl 1. when we install a shared library, we must arrange to export dnl auxiliary pointer variables for every exported variable, dnl 2. when we install a shared library and a static library simultaneously, dnl the include file specifies __declspec(dllimport) and therefore we dnl must arrange to define the auxiliary pointer variables for the dnl exported variables _also_ in the static library. if test "$enable_shared" = yes; then case "$host_os" in cygwin*) is_woe32dll=yes ;; *) is_woe32dll=no ;; esac else is_woe32dll=no fi WOE32DLL=$is_woe32dll AC_SUBST([WOE32DLL]) dnl Rename some macros and functions used for locking. AH_BOTTOM([ #define __libc_lock_t gl_lock_t #define __libc_lock_define gl_lock_define #define __libc_lock_define_initialized gl_lock_define_initialized #define __libc_lock_init gl_lock_init #define __libc_lock_lock gl_lock_lock #define __libc_lock_unlock gl_lock_unlock #define __libc_lock_recursive_t gl_recursive_lock_t #define __libc_lock_define_recursive gl_recursive_lock_define #define __libc_lock_define_initialized_recursive gl_recursive_lock_define_initialized #define __libc_lock_init_recursive gl_recursive_lock_init #define __libc_lock_lock_recursive gl_recursive_lock_lock #define __libc_lock_unlock_recursive gl_recursive_lock_unlock #define glthread_in_use libintl_thread_in_use #define glthread_lock_init libintl_lock_init #define glthread_lock_lock libintl_lock_lock #define glthread_lock_unlock libintl_lock_unlock #define glthread_lock_destroy libintl_lock_destroy #define glthread_rwlock_init libintl_rwlock_init #define glthread_rwlock_rdlock libintl_rwlock_rdlock #define glthread_rwlock_wrlock libintl_rwlock_wrlock #define glthread_rwlock_unlock libintl_rwlock_unlock #define glthread_rwlock_destroy libintl_rwlock_destroy #define glthread_recursive_lock_init libintl_recursive_lock_init #define glthread_recursive_lock_lock libintl_recursive_lock_lock #define glthread_recursive_lock_unlock libintl_recursive_lock_unlock #define glthread_recursive_lock_destroy libintl_recursive_lock_destroy #define glthread_once libintl_once #define glthread_once_call libintl_once_call #define glthread_once_singlethreaded libintl_once_singlethreaded ]) ]) dnl Checks for the core files of the intl subdirectory: dnl dcigettext.c dnl eval-plural.h dnl explodename.c dnl finddomain.c dnl gettextP.h dnl gmo.h dnl hash-string.h hash-string.c dnl l10nflist.c dnl libgnuintl.h.in (except the *printf stuff) dnl loadinfo.h dnl loadmsgcat.c dnl localealias.c dnl log.c dnl plural-exp.h plural-exp.c dnl plural.y dnl Used by libglocale. AC_DEFUN([gt_INTL_SUBDIR_CORE], [ AC_REQUIRE([AC_C_INLINE])dnl AC_REQUIRE([AC_TYPE_SIZE_T])dnl AC_REQUIRE([gl_AC_HEADER_STDINT_H]) AC_REQUIRE([AC_FUNC_ALLOCA])dnl AC_REQUIRE([AC_FUNC_MMAP])dnl AC_REQUIRE([gt_INTDIV0])dnl AC_REQUIRE([gl_AC_TYPE_UINTMAX_T])dnl AC_REQUIRE([gt_INTTYPES_PRI])dnl AC_REQUIRE([gl_LOCK])dnl AC_TRY_LINK( [int foo (int a) { a = __builtin_expect (a, 10); return a == 10 ? 0 : 1; }], [], [AC_DEFINE([HAVE_BUILTIN_EXPECT], 1, [Define to 1 if the compiler understands __builtin_expect.])]) AC_CHECK_HEADERS([argz.h inttypes.h limits.h unistd.h sys/param.h]) AC_CHECK_FUNCS([getcwd getegid geteuid getgid getuid mempcpy munmap \ stpcpy strcasecmp strdup strtoul tsearch argz_count argz_stringify \ argz_next __fsetlocking]) dnl Use the *_unlocked functions only if they are declared. dnl (because some of them were defined without being declared in Solaris dnl 2.5.1 but were removed in Solaris 2.6, whereas we want binaries built dnl on Solaris 2.5.1 to run on Solaris 2.6). dnl Don't use AC_CHECK_DECLS because it isn't supported in autoconf-2.13. gt_CHECK_DECL(feof_unlocked, [#include ]) gt_CHECK_DECL(fgets_unlocked, [#include ]) AM_ICONV dnl glibc >= 2.4 has a NL_LOCALE_NAME macro when _GNU_SOURCE is defined, dnl and a _NL_LOCALE_NAME macro always. AC_CACHE_CHECK([for NL_LOCALE_NAME macro], gt_cv_nl_locale_name, [AC_TRY_LINK([#include #include ], [char* cs = nl_langinfo(_NL_LOCALE_NAME(LC_MESSAGES));], gt_cv_nl_locale_name=yes, gt_cv_nl_locale_name=no) ]) if test $gt_cv_nl_locale_name = yes; then AC_DEFINE(HAVE_NL_LOCALE_NAME, 1, [Define if you have and it defines the NL_LOCALE_NAME macro if _GNU_SOURCE is defined.]) fi dnl intl/plural.c is generated from intl/plural.y. It requires bison, dnl because plural.y uses bison specific features. It requires at least dnl bison-1.26 because earlier versions generate a plural.c that doesn't dnl compile. dnl bison is only needed for the maintainer (who touches plural.y). But in dnl order to avoid separate Makefiles or --enable-maintainer-mode, we put dnl the rule in general Makefile. Now, some people carelessly touch the dnl files or have a broken "make" program, hence the plural.c rule will dnl sometimes fire. To avoid an error, defines BISON to ":" if it is not dnl present or too old. AC_CHECK_PROGS([INTLBISON], [bison]) if test -z "$INTLBISON"; then ac_verc_fail=yes else dnl Found it, now check the version. AC_MSG_CHECKING([version of bison]) changequote(<<,>>)dnl ac_prog_version=`$INTLBISON --version 2>&1 | sed -n 's/^.*GNU Bison.* \([0-9]*\.[0-9.]*\).*$/\1/p'` case $ac_prog_version in '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;; 1.2[6-9]* | 1.[3-9][0-9]* | [2-9].*) changequote([,])dnl ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;; *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;; esac AC_MSG_RESULT([$ac_prog_version]) fi if test $ac_verc_fail = yes; then INTLBISON=: fi ]) dnl gt_CHECK_DECL(FUNC, INCLUDES) dnl Check whether a function is declared. AC_DEFUN([gt_CHECK_DECL], [ AC_CACHE_CHECK([whether $1 is declared], ac_cv_have_decl_$1, [AC_TRY_COMPILE([$2], [ #ifndef $1 char *p = (char *) $1; #endif ], ac_cv_have_decl_$1=yes, ac_cv_have_decl_$1=no)]) if test $ac_cv_have_decl_$1 = yes; then gt_value=1 else gt_value=0 fi AC_DEFINE_UNQUOTED([HAVE_DECL_]translit($1, [a-z], [A-Z]), [$gt_value], [Define to 1 if you have the declaration of `$1', and to 0 if you don't.]) ]) gnunet-0.9.3/m4/inttypes.m40000644000175000017500000000171711317762615012424 00000000000000# inttypes.m4 serial 1 (gettext-0.11.4) dnl Copyright (C) 1997-2002 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl From Paul Eggert. # Define HAVE_INTTYPES_H if exists and doesn't clash with # . AC_DEFUN([gt_HEADER_INTTYPES_H], [ AC_CACHE_CHECK([for inttypes.h], gt_cv_header_inttypes_h, [ AC_TRY_COMPILE( [#include #include ], [], gt_cv_header_inttypes_h=yes, gt_cv_header_inttypes_h=no) ]) if test $gt_cv_header_inttypes_h = yes; then AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H, 1, [Define if exists and doesn't clash with .]) fi ]) gnunet-0.9.3/m4/libunistring.m40000644000175000017500000001431411700045442013237 00000000000000# libunistring.m4 serial 11 dnl Copyright (C) 2009-2012 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl gl_LIBUNISTRING dnl Searches for an installed libunistring. dnl If found, it sets and AC_SUBSTs HAVE_LIBUNISTRING=yes and the LIBUNISTRING dnl and LTLIBUNISTRING variables, sets the LIBUNISTRING_VERSION variable, and dnl augments the CPPFLAGS variable, and #defines HAVE_LIBUNISTRING to 1. dnl Otherwise, it sets and AC_SUBSTs HAVE_LIBUNISTRING=no and LIBUNISTRING and dnl LTLIBUNISTRING to empty. dnl Define gl_LIBUNISTRING using AC_DEFUN_ONCE for Autoconf >= 2.64, in order dnl to avoid warnings like dnl "warning: AC_REQUIRE: `gl_LIBUNISTRING' was expanded before it was required". dnl This is tricky because of the way 'aclocal' is implemented: dnl - It requires defining an auxiliary macro whose name ends in AC_DEFUN. dnl Otherwise aclocal's initial scan pass would miss the macro definition. dnl - It requires a line break inside the AC_DEFUN_ONCE and AC_DEFUN expansions. dnl Otherwise aclocal would emit many "Use of uninitialized value $1" dnl warnings. m4_define([gl_libunistring_AC_DEFUN], m4_version_prereq([2.64], [[AC_DEFUN_ONCE( [$1], [$2])]], [m4_ifdef([gl_00GNULIB], [[AC_DEFUN_ONCE( [$1], [$2])]], [[AC_DEFUN( [$1], [$2])]])])) gl_libunistring_AC_DEFUN([gl_LIBUNISTRING], [ AC_BEFORE([$0], [gl_LIBUNISTRING_MODULE]) AC_BEFORE([$0], [gl_LIBUNISTRING_LIBHEADER]) AC_BEFORE([$0], [gl_LIBUNISTRING_LIB_PREPARE]) m4_ifdef([gl_LIBUNISTRING_OPTIONAL], [ AC_MSG_CHECKING([whether included libunistring is requested]) AC_ARG_WITH([included-libunistring], [ --with-included-libunistring use the libunistring parts included here], [gl_libunistring_force_included=$withval], [gl_libunistring_force_included=no]) AC_MSG_RESULT([$gl_libunistring_force_included]) gl_libunistring_use_included="$gl_libunistring_force_included" if test "$gl_libunistring_use_included" = yes; then dnl Assume that libunistring is not installed until some other macro dnl explicitly invokes gl_LIBUNISTRING_CORE. if test -z "$HAVE_LIBUNISTRING"; then HAVE_LIBUNISTRING=no fi LIBUNISTRING= LTLIBUNISTRING= else gl_LIBUNISTRING_CORE if test $HAVE_LIBUNISTRING = no; then gl_libunistring_use_included=yes LIBUNISTRING= LTLIBUNISTRING= fi fi ], [gl_LIBUNISTRING_CORE]) ]) AC_DEFUN([gl_LIBUNISTRING_CORE], [ AC_REQUIRE([AM_ICONV]) if test -n "$LIBICONV"; then dnl First, try to link without -liconv. libunistring often depends on dnl libiconv, but we don't know (and often don't need to know) where dnl libiconv is installed. AC_LIB_HAVE_LINKFLAGS([unistring], [], [#include ], [u8_strconv_from_locale((char*)0);], [no, trying again together with libiconv]) if test "$ac_cv_libunistring" != yes; then dnl Second try, with -liconv. dnl We have to erase the cached result of the first AC_LIB_HAVE_LINKFLAGS dnl invocation, otherwise the second one will not be run. unset ac_cv_libunistring glus_save_LIBS="$LIBS" LIBS="$LIBS $LIBICONV" AC_LIB_HAVE_LINKFLAGS([unistring], [], [#include ], [u8_strconv_from_locale((char*)0);], [no, consider installing GNU libunistring]) if test -n "$LIBUNISTRING"; then LIBUNISTRING="$LIBUNISTRING $LIBICONV" LTLIBUNISTRING="$LTLIBUNISTRING $LTLIBICONV" fi LIBS="$glus_save_LIBS" fi else AC_LIB_HAVE_LINKFLAGS([unistring], [], [#include ], [u8_strconv_from_locale((char*)0);], [no, consider installing GNU libunistring]) fi if test $HAVE_LIBUNISTRING = yes; then dnl Determine the installed version. AC_CACHE_CHECK([for libunistring version], [gl_cv_libunistring_version], [AC_COMPUTE_INT([gl_libunistring_hexversion], [_LIBUNISTRING_VERSION], [#include ]) dnl Versions <= 0.9.3 had a hexversion of 0x0009. dnl Use other tests to distinguish them. if test $gl_libunistring_hexversion = 9; then dnl Version 0.9.2 introduced the header . AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#include ]], [[]])], [gl_cv_libunistring_version092=true], [gl_cv_libunistring_version092=false]) if $gl_cv_libunistring_version092; then dnl Version 0.9.3 changed a comment in . gl_ABSOLUTE_HEADER_ONE([unistr.h]) if test -n "$gl_cv_absolute_unistr_h" \ && grep 'Copy no more than N units of SRC to DEST. Return a pointer' $gl_cv_absolute_unistr_h > /dev/null; then dnl Detected version 0.9.3. gl_libunistring_hexversion=2307 else dnl Detected version 0.9.2. gl_libunistring_hexversion=2306 fi else dnl Version 0.9.1 introduced the type casing_suffix_context_t. AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include casing_suffix_context_t ct;]], [[]])], [gl_cv_libunistring_version091=true], [gl_cv_libunistring_version091=false]) if $gl_cv_libunistring_version091; then dnl Detected version 0.9.1. gl_libunistring_hexversion=2305 else dnl Detected version 0.9. gl_libunistring_hexversion=2304 fi fi fi dnl Transform into the usual major.minor.subminor notation. gl_libunistring_major=`expr $gl_libunistring_hexversion / 65536` gl_libunistring_minor=`expr $gl_libunistring_hexversion / 256 % 256` gl_libunistring_subminor=`expr $gl_libunistring_hexversion % 256` gl_cv_libunistring_version="$gl_libunistring_major.$gl_libunistring_minor.$gl_libunistring_subminor" ]) LIBUNISTRING_VERSION="$gl_cv_libunistring_version" fi ]) gnunet-0.9.3/m4/isc-posix.m40000644000175000017500000000213311317762615012454 00000000000000# isc-posix.m4 serial 2 (gettext-0.11.2) dnl Copyright (C) 1995-2002 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. # This file is not needed with autoconf-2.53 and newer. Remove it in 2005. # This test replaces the one in autoconf. # Currently this macro should have the same name as the autoconf macro # because gettext's gettext.m4 (distributed in the automake package) # still uses it. Otherwise, the use in gettext.m4 makes autoheader # give these diagnostics: # configure.in:556: AC_TRY_COMPILE was called before AC_ISC_POSIX # configure.in:556: AC_TRY_RUN was called before AC_ISC_POSIX undefine([AC_ISC_POSIX]) AC_DEFUN([AC_ISC_POSIX], [ dnl This test replaces the obsolescent AC_ISC_POSIX kludge. AC_CHECK_LIB(cposix, strerror, [LIBS="$LIBS -lcposix"]) ] ) gnunet-0.9.3/m4/intdiv0.m40000644000175000017500000000334011317762540012111 00000000000000# intdiv0.m4 serial 1 (gettext-0.11.3) dnl Copyright (C) 2002 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_DEFUN([gt_INTDIV0], [ AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_CACHE_CHECK([whether integer division by zero raises SIGFPE], gt_cv_int_divbyzero_sigfpe, [ AC_TRY_RUN([ #include #include static void #ifdef __cplusplus sigfpe_handler (int sig) #else sigfpe_handler (sig) int sig; #endif { /* Exit with code 0 if SIGFPE, with code 1 if any other signal. */ exit (sig != SIGFPE); } int x = 1; int y = 0; int z; int nan; int main () { signal (SIGFPE, sigfpe_handler); /* IRIX and AIX (when "xlc -qcheck" is used) yield signal SIGTRAP. */ #if (defined (__sgi) || defined (_AIX)) && defined (SIGTRAP) signal (SIGTRAP, sigfpe_handler); #endif /* Linux/SPARC yields signal SIGILL. */ #if defined (__sparc__) && defined (__linux__) signal (SIGILL, sigfpe_handler); #endif z = x / y; nan = y / y; exit (1); } ], gt_cv_int_divbyzero_sigfpe=yes, gt_cv_int_divbyzero_sigfpe=no, [ # Guess based on the CPU. case "$host_cpu" in alpha* | i[34567]86 | m68k | s390*) gt_cv_int_divbyzero_sigfpe="guessing yes";; *) gt_cv_int_divbyzero_sigfpe="guessing no";; esac ]) ]) case "$gt_cv_int_divbyzero_sigfpe" in *yes) value=1;; *) value=0;; esac AC_DEFINE_UNQUOTED(INTDIV0_RAISES_SIGFPE, $value, [Define if integer division by zero raises signal SIGFPE.]) ]) gnunet-0.9.3/m4/ltsugar.m40000644000175000017500000001042411762217203012211 00000000000000# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59 which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) gnunet-0.9.3/m4/Makefile.am0000644000175000017500000000106411700046337012322 00000000000000EXTRA_DIST = glibc2.m4 intl.m4 intldir.m4 lock.m4 visibility.m4 \ absolute-header.m4 \ libunistring.m4 \ codeset.m4 \ freetype2.m4\ gettext.m4\ glib-2.0.m4\ glibc21.m4\ glib-gettext.m4\ gnulib-cache.m4\ gtk-2.0.m4\ iconv.m4\ intdiv0.m4\ intmax.m4\ inttypes_h.m4\ inttypes.m4\ inttypes-pri.m4\ isc-posix.m4\ lcmessage.m4\ libgcrypt.m4\ lib-ld.m4\ lib-link.m4\ lib-prefix.m4\ libxml2.m4\ longdouble.m4\ longlong.m4\ nls.m4\ pkg.m4\ po.m4\ printf-posix.m4\ progtest.m4\ signed.m4\ size_max.m4\ stdint_h.m4\ uintmax_t.m4\ ulonglong.m4\ wchar_t.m4\ wint_t.m4\ xsize.m4 gnunet-0.9.3/m4/gtk-2.0.m40000644000175000017500000001655411317762615011634 00000000000000# Configure paths for GTK+ # Owen Taylor 1997-2001 dnl AM_PATH_GTK_2_0([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]]) dnl Test for GTK+, and define GTK_CFLAGS and GTK_LIBS, if gthread is specified in MODULES, dnl pass to pkg-config dnl AC_DEFUN([AM_PATH_GTK_2_0], [dnl dnl Get the cflags and libraries from pkg-config dnl AC_ARG_ENABLE(gtktest, [ --disable-gtktest do not try to compile and run a test GTK+ program], , enable_gtktest=yes) pkg_config_args=gtk+-2.0 for module in . $4 do case "$module" in gthread) pkg_config_args="$pkg_config_args gthread-2.0" ;; esac done no_gtk="" AC_PATH_PROG(PKG_CONFIG, pkg-config, no) if test x$PKG_CONFIG != xno ; then if pkg-config --atleast-pkgconfig-version 0.7 ; then : else echo "*** pkg-config too old; version 0.7 or better required." no_gtk=yes PKG_CONFIG=no fi else no_gtk=yes fi min_gtk_version=ifelse([$1], ,2.0.0,$1) AC_MSG_CHECKING(for GTK+ - version >= $min_gtk_version) if test x$PKG_CONFIG != xno ; then ## don't try to run the test against uninstalled libtool libs if $PKG_CONFIG --uninstalled $pkg_config_args; then echo "Will use uninstalled version of GTK+ found in PKG_CONFIG_PATH" enable_gtktest=no fi if $PKG_CONFIG --atleast-version $min_gtk_version $pkg_config_args; then : else no_gtk=yes fi fi if test x"$no_gtk" = x ; then GTK_CFLAGS=`$PKG_CONFIG $pkg_config_args --cflags` GTK_LIBS=`$PKG_CONFIG $pkg_config_args --libs` gtk_config_major_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` gtk_config_minor_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` gtk_config_micro_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` if test "x$enable_gtktest" = "xyes" ; then ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$GTK_LIBS $LIBS" dnl dnl Now check if the installed GTK+ is sufficiently new. (Also sanity dnl checks the results of pkg-config to some extent) dnl rm -f conf.gtktest AC_TRY_RUN([ #include #include #include int main () { int major, minor, micro; char *tmp_version; system ("touch conf.gtktest"); /* HP/UX 9 (%@#!) writes to sscanf strings */ tmp_version = g_strdup("$min_gtk_version"); if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { printf("%s, bad version string\n", "$min_gtk_version"); exit(1); } if ((gtk_major_version != $gtk_config_major_version) || (gtk_minor_version != $gtk_config_minor_version) || (gtk_micro_version != $gtk_config_micro_version)) { printf("\n*** 'pkg-config --modversion gtk+-2.0' returned %d.%d.%d, but GTK+ (%d.%d.%d)\n", $gtk_config_major_version, $gtk_config_minor_version, $gtk_config_micro_version, gtk_major_version, gtk_minor_version, gtk_micro_version); printf ("*** was found! If pkg-config was correct, then it is best\n"); printf ("*** to remove the old version of GTK+. You may also be able to fix the error\n"); printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); printf("*** required on your system.\n"); printf("*** If pkg-config was wrong, set the environment variable PKG_CONFIG_PATH\n"); printf("*** to point to the correct configuration files\n"); } else if ((gtk_major_version != GTK_MAJOR_VERSION) || (gtk_minor_version != GTK_MINOR_VERSION) || (gtk_micro_version != GTK_MICRO_VERSION)) { printf("*** GTK+ header files (version %d.%d.%d) do not match\n", GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION); printf("*** library (version %d.%d.%d)\n", gtk_major_version, gtk_minor_version, gtk_micro_version); } else { if ((gtk_major_version > major) || ((gtk_major_version == major) && (gtk_minor_version > minor)) || ((gtk_major_version == major) && (gtk_minor_version == minor) && (gtk_micro_version >= micro))) { return 0; } else { printf("\n*** An old version of GTK+ (%d.%d.%d) was found.\n", gtk_major_version, gtk_minor_version, gtk_micro_version); printf("*** You need a version of GTK+ newer than %d.%d.%d. The latest version of\n", major, minor, micro); printf("*** GTK+ is always available from ftp://ftp.gtk.org.\n"); printf("***\n"); printf("*** If you have already installed a sufficiently new version, this error\n"); printf("*** probably means that the wrong copy of the pkg-config shell script is\n"); printf("*** being found. The easiest way to fix this is to remove the old version\n"); printf("*** of GTK+, but you can also set the PKG_CONFIG environment to point to the\n"); printf("*** correct copy of pkg-config. (In this case, you will have to\n"); printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); printf("*** so that the correct libraries are found at run-time))\n"); } } return 1; } ],, no_gtk=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi if test "x$no_gtk" = x ; then AC_MSG_RESULT(yes (version $gtk_config_major_version.$gtk_config_minor_version.$gtk_config_micro_version)) ifelse([$2], , :, [$2]) else AC_MSG_RESULT(no) if test "$PKG_CONFIG" = "no" ; then echo "*** A new enough version of pkg-config was not found." echo "*** See http://pkgconfig.sourceforge.net" else if test -f conf.gtktest ; then : else echo "*** Could not run GTK+ test program, checking why..." ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$LIBS $GTK_LIBS" AC_TRY_LINK([ #include #include ], [ return ((gtk_major_version) || (gtk_minor_version) || (gtk_micro_version)); ], [ echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding GTK+ or finding the wrong" echo "*** version of GTK+. If it is not finding GTK+, you'll need to set your" echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" echo "*** to the installed location Also, make sure you have run ldconfig if that" echo "*** is required on your system" echo "***" echo "*** If you have an old version installed, it is best to remove it, although" echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" ], [ echo "*** The test program failed to compile or link. See the file config.log for the" echo "*** exact error that occured. This usually means GTK+ is incorrectly installed."]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi GTK_CFLAGS="" GTK_LIBS="" ifelse([$3], , :, [$3]) fi AC_SUBST(GTK_CFLAGS) AC_SUBST(GTK_LIBS) rm -f conf.gtktest ]) gnunet-0.9.3/m4/libxml2.m40000644000175000017500000001731011317762615012112 00000000000000# Configure paths for LIBXML2 # Mike Hommey 2004-06-19 # use CPPFLAGS instead of CFLAGS # Toshio Kuratomi 2001-04-21 # Adapted from: # Configure paths for GLIB # Owen Taylor 97-11-3 dnl AM_PATH_XML2([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) dnl Test for XML, and define XML_CPPFLAGS and XML_LIBS dnl AC_DEFUN([AM_PATH_XML2],[ AC_ARG_WITH(xml-prefix, [ --with-xml-prefix=PFX Prefix where libxml is installed (optional)], xml_config_prefix="$withval", xml_config_prefix="") AC_ARG_WITH(xml-exec-prefix, [ --with-xml-exec-prefix=PFX Exec prefix where libxml is installed (optional)], xml_config_exec_prefix="$withval", xml_config_exec_prefix="") AC_ARG_ENABLE(xmltest, [ --disable-xmltest Do not try to compile and run a test LIBXML program],, enable_xmltest=yes) if test x$xml_config_exec_prefix != x ; then xml_config_args="$xml_config_args" if test x${XML2_CONFIG+set} != xset ; then XML2_CONFIG=$xml_config_exec_prefix/bin/xml2-config fi fi if test x$xml_config_prefix != x ; then xml_config_args="$xml_config_args --prefix=$xml_config_prefix" if test x${XML2_CONFIG+set} != xset ; then XML2_CONFIG=$xml_config_prefix/bin/xml2-config fi fi AC_PATH_PROG(XML2_CONFIG, xml2-config, no) min_xml_version=ifelse([$1], ,2.0.0,[$1]) AC_MSG_CHECKING(for libxml - version >= $min_xml_version) no_xml="" if test "$XML2_CONFIG" = "no" ; then no_xml=yes else XML_CPPFLAGS=`$XML2_CONFIG $xml_config_args --cflags` XML_LIBS=`$XML2_CONFIG $xml_config_args --libs` xml_config_major_version=`$XML2_CONFIG $xml_config_args --version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` xml_config_minor_version=`$XML2_CONFIG $xml_config_args --version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` xml_config_micro_version=`$XML2_CONFIG $xml_config_args --version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` if test "x$enable_xmltest" = "xyes" ; then ac_save_CPPFLAGS="$CPPFLAGS" ac_save_LIBS="$LIBS" CPPFLAGS="$CPPFLAGS $XML_CPPFLAGS" LIBS="$XML_LIBS $LIBS" dnl dnl Now check if the installed libxml is sufficiently new. dnl (Also sanity checks the results of xml2-config to some extent) dnl rm -f conf.xmltest AC_TRY_RUN([ #include #include #include #include int main() { int xml_major_version, xml_minor_version, xml_micro_version; int major, minor, micro; char *tmp_version; system("touch conf.xmltest"); /* Capture xml2-config output via autoconf/configure variables */ /* HP/UX 9 (%@#!) writes to sscanf strings */ tmp_version = (char *)strdup("$min_xml_version"); if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { printf("%s, bad version string from xml2-config\n", "$min_xml_version"); exit(1); } free(tmp_version); /* Capture the version information from the header files */ tmp_version = (char *)strdup(LIBXML_DOTTED_VERSION); if (sscanf(tmp_version, "%d.%d.%d", &xml_major_version, &xml_minor_version, &xml_micro_version) != 3) { printf("%s, bad version string from libxml includes\n", "LIBXML_DOTTED_VERSION"); exit(1); } free(tmp_version); /* Compare xml2-config output to the libxml headers */ if ((xml_major_version != $xml_config_major_version) || (xml_minor_version != $xml_config_minor_version) || (xml_micro_version != $xml_config_micro_version)) { printf("*** libxml header files (version %d.%d.%d) do not match\n", xml_major_version, xml_minor_version, xml_micro_version); printf("*** xml2-config (version %d.%d.%d)\n", $xml_config_major_version, $xml_config_minor_version, $xml_config_micro_version); return 1; } /* Compare the headers to the library to make sure we match */ /* Less than ideal -- doesn't provide us with return value feedback, * only exits if there's a serious mismatch between header and library. */ LIBXML_TEST_VERSION; /* Test that the library is greater than our minimum version */ if ((xml_major_version > major) || ((xml_major_version == major) && (xml_minor_version > minor)) || ((xml_major_version == major) && (xml_minor_version == minor) && (xml_micro_version >= micro))) { return 0; } else { printf("\n*** An old version of libxml (%d.%d.%d) was found.\n", xml_major_version, xml_minor_version, xml_micro_version); printf("*** You need a version of libxml newer than %d.%d.%d. The latest version of\n", major, minor, micro); printf("*** libxml is always available from ftp://ftp.xmlsoft.org.\n"); printf("***\n"); printf("*** If you have already installed a sufficiently new version, this error\n"); printf("*** probably means that the wrong copy of the xml2-config shell script is\n"); printf("*** being found. The easiest way to fix this is to remove the old version\n"); printf("*** of LIBXML, but you can also set the XML2_CONFIG environment to point to the\n"); printf("*** correct copy of xml2-config. (In this case, you will have to\n"); printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); printf("*** so that the correct libraries are found at run-time))\n"); } return 1; } ],, no_xml=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) CPPFLAGS="$ac_save_CPPFLAGS" LIBS="$ac_save_LIBS" fi fi if test "x$no_xml" = x ; then AC_MSG_RESULT(yes (version $xml_config_major_version.$xml_config_minor_version.$xml_config_micro_version)) ifelse([$2], , :, [$2]) else AC_MSG_RESULT(no) if test "$XML2_CONFIG" = "no" ; then echo "*** The xml2-config script installed by LIBXML could not be found" echo "*** If libxml was installed in PREFIX, make sure PREFIX/bin is in" echo "*** your path, or set the XML2_CONFIG environment variable to the" echo "*** full path to xml2-config." else if test -f conf.xmltest ; then : else echo "*** Could not run libxml test program, checking why..." CPPFLAGS="$CPPFLAGS $XML_CPPFLAGS" LIBS="$LIBS $XML_LIBS" AC_TRY_LINK([ #include #include ], [ LIBXML_TEST_VERSION; return 0;], [ echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding LIBXML or finding the wrong" echo "*** version of LIBXML. If it is not finding LIBXML, you'll need to set your" echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" echo "*** to the installed location Also, make sure you have run ldconfig if that" echo "*** is required on your system" echo "***" echo "*** If you have an old version installed, it is best to remove it, although" echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" ], [ echo "*** The test program failed to compile or link. See the file config.log for the" echo "*** exact error that occured. This usually means LIBXML was incorrectly installed" echo "*** or that you have moved LIBXML since it was installed. In the latter case, you" echo "*** may want to edit the xml2-config script: $XML2_CONFIG" ]) CPPFLAGS="$ac_save_CPPFLAGS" LIBS="$ac_save_LIBS" fi fi XML_CPPFLAGS="" XML_LIBS="" ifelse([$3], , :, [$3]) fi AC_SUBST(XML_CPPFLAGS) AC_SUBST(XML_LIBS) rm -f conf.xmltest ]) gnunet-0.9.3/m4/wchar_t.m40000644000175000017500000000132611651542055012163 00000000000000# wchar_t.m4 serial 1 (gettext-0.12) dnl Copyright (C) 2002-2003 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl Test whether has the 'wchar_t' type. dnl Prerequisite: AC_PROG_CC AC_DEFUN([gt_TYPE_WCHAR_T], [ AC_CACHE_CHECK([for wchar_t], gt_cv_c_wchar_t, [AC_TRY_COMPILE([#include wchar_t foo = (wchar_t)'\0';], , gt_cv_c_wchar_t=yes, gt_cv_c_wchar_t=no)]) if test $gt_cv_c_wchar_t = yes; then AC_DEFINE(HAVE_WCHAR_T, 1, [Define if you have the 'wchar_t' type.]) fi ]) gnunet-0.9.3/m4/po.m40000644000175000017500000004336711317762540011167 00000000000000# po.m4 serial 13 (gettext-0.15) dnl Copyright (C) 1995-2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1995-2000. dnl Bruno Haible , 2000-2003. AC_PREREQ(2.50) dnl Checks for all prerequisites of the po subdirectory. AC_DEFUN([AM_PO_SUBDIRS], [ AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl AC_REQUIRE([AM_PROG_MKDIR_P])dnl defined by automake AC_REQUIRE([AM_NLS])dnl dnl Perform the following tests also if --disable-nls has been given, dnl because they are needed for "make dist" to work. dnl Search for GNU msgfmt in the PATH. dnl The first test excludes Solaris msgfmt and early GNU msgfmt versions. dnl The second test excludes FreeBSD msgfmt. AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, [$ac_dir/$ac_word --statistics /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 && (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], :) AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) dnl Test whether it is GNU msgfmt >= 0.15. changequote(,)dnl case `$MSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) MSGFMT_015=: ;; *) MSGFMT_015=$MSGFMT ;; esac changequote([,])dnl AC_SUBST([MSGFMT_015]) changequote(,)dnl case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) GMSGFMT_015=: ;; *) GMSGFMT_015=$GMSGFMT ;; esac changequote([,])dnl AC_SUBST([GMSGFMT_015]) dnl Search for GNU xgettext 0.12 or newer in the PATH. dnl The first test excludes Solaris xgettext and early GNU xgettext versions. dnl The second test excludes FreeBSD xgettext. AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, [$ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 && (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], :) dnl Remove leftover from FreeBSD xgettext call. rm -f messages.po dnl Test whether it is GNU xgettext >= 0.15. changequote(,)dnl case `$XGETTEXT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) XGETTEXT_015=: ;; *) XGETTEXT_015=$XGETTEXT ;; esac changequote([,])dnl AC_SUBST([XGETTEXT_015]) dnl Search for GNU msgmerge 0.11 or newer in the PATH. AM_PATH_PROG_WITH_TEST(MSGMERGE, msgmerge, [$ac_dir/$ac_word --update -q /dev/null /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1], :) dnl Installation directories. dnl Autoconf >= 2.60 defines localedir. For older versions of autoconf, we dnl have to define it here, so that it can be used in po/Makefile. test -n "$localedir" || localedir='${datadir}/locale' AC_SUBST([localedir]) AC_CONFIG_COMMANDS([po-directories], [[ for ac_file in $CONFIG_FILES; do # Support "outfile[:infile[:infile...]]" case "$ac_file" in *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; esac # PO directories have a Makefile.in generated from Makefile.in.in. case "$ac_file" in */Makefile.in) # Adjust a relative srcdir. ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` # In autoconf-2.13 it is called $ac_given_srcdir. # In autoconf-2.50 it is called $srcdir. test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" case "$ac_given_srcdir" in .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; /*) top_srcdir="$ac_given_srcdir" ;; *) top_srcdir="$ac_dots$ac_given_srcdir" ;; esac # Treat a directory as a PO directory if and only if it has a # POTFILES.in file. This allows packages to have multiple PO # directories under different names or in different locations. if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then rm -f "$ac_dir/POTFILES" test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" POMAKEFILEDEPS="POTFILES.in" # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend # on $ac_dir but don't depend on user-specified configuration # parameters. if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then # The LINGUAS file contains the set of available languages. if test -n "$OBSOLETE_ALL_LINGUAS"; then test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" fi ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` # Hide the ALL_LINGUAS assigment from automake < 1.5. eval 'ALL_LINGUAS''=$ALL_LINGUAS_' POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" else # The set of available languages was given in configure.in. # Hide the ALL_LINGUAS assigment from automake < 1.5. eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS' fi # Compute POFILES # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) # Compute UPDATEPOFILES # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) # Compute DUMMYPOFILES # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) # Compute GMOFILES # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) case "$ac_given_srcdir" in .) srcdirpre= ;; *) srcdirpre='$(srcdir)/' ;; esac POFILES= UPDATEPOFILES= DUMMYPOFILES= GMOFILES= for lang in $ALL_LINGUAS; do POFILES="$POFILES $srcdirpre$lang.po" UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" DUMMYPOFILES="$DUMMYPOFILES $lang.nop" GMOFILES="$GMOFILES $srcdirpre$lang.gmo" done # CATALOGS depends on both $ac_dir and the user's LINGUAS # environment variable. INST_LINGUAS= if test -n "$ALL_LINGUAS"; then for presentlang in $ALL_LINGUAS; do useit=no if test "%UNSET%" != "$LINGUAS"; then desiredlanguages="$LINGUAS" else desiredlanguages="$ALL_LINGUAS" fi for desiredlang in $desiredlanguages; do # Use the presentlang catalog if desiredlang is # a. equal to presentlang, or # b. a variant of presentlang (because in this case, # presentlang can be used as a fallback for messages # which are not translated in the desiredlang catalog). case "$desiredlang" in "$presentlang"*) useit=yes;; esac done if test $useit = yes; then INST_LINGUAS="$INST_LINGUAS $presentlang" fi done fi CATALOGS= if test -n "$INST_LINGUAS"; then for lang in $INST_LINGUAS; do CATALOGS="$CATALOGS $lang.gmo" done fi test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do if test -f "$f"; then case "$f" in *.orig | *.bak | *~) ;; *) cat "$f" >> "$ac_dir/Makefile" ;; esac fi done fi ;; esac done]], [# Capture the value of obsolete ALL_LINGUAS because we need it to compute # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it # from automake < 1.5. eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"' # Capture the value of LINGUAS because we need it to compute CATALOGS. LINGUAS="${LINGUAS-%UNSET%}" ]) ]) dnl Postprocesses a Makefile in a directory containing PO files. AC_DEFUN([AM_POSTPROCESS_PO_MAKEFILE], [ # When this code is run, in config.status, two variables have already been # set: # - OBSOLETE_ALL_LINGUAS is the value of LINGUAS set in configure.in, # - LINGUAS is the value of the environment variable LINGUAS at configure # time. changequote(,)dnl # Adjust a relative srcdir. ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` # In autoconf-2.13 it is called $ac_given_srcdir. # In autoconf-2.50 it is called $srcdir. test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" case "$ac_given_srcdir" in .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; /*) top_srcdir="$ac_given_srcdir" ;; *) top_srcdir="$ac_dots$ac_given_srcdir" ;; esac # Find a way to echo strings without interpreting backslash. if test "X`(echo '\t') 2>/dev/null`" = 'X\t'; then gt_echo='echo' else if test "X`(printf '%s\n' '\t') 2>/dev/null`" = 'X\t'; then gt_echo='printf %s\n' else echo_func () { cat < "$ac_file.tmp" if grep -l '@TCLCATALOGS@' "$ac_file" > /dev/null; then # Add dependencies that cannot be formulated as a simple suffix rule. for lang in $ALL_LINGUAS; do frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` cat >> "$ac_file.tmp" < /dev/null; then # Add dependencies that cannot be formulated as a simple suffix rule. for lang in $ALL_LINGUAS; do frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'` cat >> "$ac_file.tmp" <> "$ac_file.tmp" <, 1995-2000. dnl Bruno Haible , 2000-2006. dnl Macro to add for using GNU gettext. dnl Usage: AM_GNU_GETTEXT([INTLSYMBOL], [NEEDSYMBOL], [INTLDIR]). dnl INTLSYMBOL can be one of 'external', 'no-libtool', 'use-libtool'. The dnl default (if it is not specified or empty) is 'no-libtool'. dnl INTLSYMBOL should be 'external' for packages with no intl directory, dnl and 'no-libtool' or 'use-libtool' for packages with an intl directory. dnl If INTLSYMBOL is 'use-libtool', then a libtool library dnl $(top_builddir)/intl/libintl.la will be created (shared and/or static, dnl depending on --{enable,disable}-{shared,static} and on the presence of dnl AM-DISABLE-SHARED). If INTLSYMBOL is 'no-libtool', a static library dnl $(top_builddir)/intl/libintl.a will be created. dnl If NEEDSYMBOL is specified and is 'need-ngettext', then GNU gettext dnl implementations (in libc or libintl) without the ngettext() function dnl will be ignored. If NEEDSYMBOL is specified and is dnl 'need-formatstring-macros', then GNU gettext implementations that don't dnl support the ISO C 99 formatstring macros will be ignored. dnl INTLDIR is used to find the intl libraries. If empty, dnl the value `$(top_builddir)/intl/' is used. dnl dnl The result of the configuration is one of three cases: dnl 1) GNU gettext, as included in the intl subdirectory, will be compiled dnl and used. dnl Catalog format: GNU --> install in $(datadir) dnl Catalog extension: .mo after installation, .gmo in source tree dnl 2) GNU gettext has been found in the system's C library. dnl Catalog format: GNU --> install in $(datadir) dnl Catalog extension: .mo after installation, .gmo in source tree dnl 3) No internationalization, always use English msgid. dnl Catalog format: none dnl Catalog extension: none dnl If INTLSYMBOL is 'external', only cases 2 and 3 can occur. dnl The use of .gmo is historical (it was needed to avoid overwriting the dnl GNU format catalogs when building on a platform with an X/Open gettext), dnl but we keep it in order not to force irrelevant filename changes on the dnl maintainers. dnl AC_DEFUN([AM_GNU_GETTEXT], [ dnl Argument checking. ifelse([$1], [], , [ifelse([$1], [external], , [ifelse([$1], [no-libtool], , [ifelse([$1], [use-libtool], , [errprint([ERROR: invalid first argument to AM_GNU_GETTEXT ])])])])]) ifelse([$2], [], , [ifelse([$2], [need-ngettext], , [ifelse([$2], [need-formatstring-macros], , [errprint([ERROR: invalid second argument to AM_GNU_GETTEXT ])])])]) define([gt_included_intl], ifelse([$1], [external], ifdef([AM_GNU_GETTEXT_][INTL_SUBDIR], [yes], [no]), [yes])) define([gt_libtool_suffix_prefix], ifelse([$1], [use-libtool], [l], [])) gt_NEEDS_INIT AM_GNU_GETTEXT_NEED([$2]) AC_REQUIRE([AM_PO_SUBDIRS])dnl ifelse(gt_included_intl, yes, [ AC_REQUIRE([AM_INTL_SUBDIR])dnl ]) dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) dnl Sometimes libintl requires libiconv, so first search for libiconv. dnl Ideally we would do this search only after the dnl if test "$USE_NLS" = "yes"; then dnl if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then dnl tests. But if configure.in invokes AM_ICONV after AM_GNU_GETTEXT dnl the configure script would need to contain the same shell code dnl again, outside any 'if'. There are two solutions: dnl - Invoke AM_ICONV_LINKFLAGS_BODY here, outside any 'if'. dnl - Control the expansions in more detail using AC_PROVIDE_IFELSE. dnl Since AC_PROVIDE_IFELSE is only in autoconf >= 2.52 and not dnl documented, we avoid it. ifelse(gt_included_intl, yes, , [ AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) ]) dnl Sometimes, on MacOS X, libintl requires linking with CoreFoundation. gt_INTL_MACOSX dnl Set USE_NLS. AC_REQUIRE([AM_NLS]) ifelse(gt_included_intl, yes, [ BUILD_INCLUDED_LIBINTL=no USE_INCLUDED_LIBINTL=no ]) LIBINTL= LTLIBINTL= POSUB= dnl Add a version number to the cache macros. case " $gt_needs " in *" need-formatstring-macros "*) gt_api_version=3 ;; *" need-ngettext "*) gt_api_version=2 ;; *) gt_api_version=1 ;; esac gt_func_gnugettext_libc="gt_cv_func_gnugettext${gt_api_version}_libc" gt_func_gnugettext_libintl="gt_cv_func_gnugettext${gt_api_version}_libintl" dnl If we use NLS figure out what method if test "$USE_NLS" = "yes"; then gt_use_preinstalled_gnugettext=no ifelse(gt_included_intl, yes, [ AC_MSG_CHECKING([whether included gettext is requested]) AC_ARG_WITH(included-gettext, [ --with-included-gettext use the GNU gettext library included here], nls_cv_force_use_gnu_gettext=$withval, nls_cv_force_use_gnu_gettext=no) AC_MSG_RESULT($nls_cv_force_use_gnu_gettext) nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" if test "$nls_cv_force_use_gnu_gettext" != "yes"; then ]) dnl User does not insist on using GNU NLS library. Figure out what dnl to use. If GNU gettext is available we use this. Else we have dnl to fall back to GNU NLS library. if test $gt_api_version -ge 3; then gt_revision_test_code=' #ifndef __GNU_GETTEXT_SUPPORTED_REVISION #define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) #endif changequote(,)dnl typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; changequote([,])dnl ' else gt_revision_test_code= fi if test $gt_api_version -ge 2; then gt_expression_test_code=' + * ngettext ("", "", 0)' else gt_expression_test_code= fi AC_CACHE_CHECK([for GNU gettext in libc], [$gt_func_gnugettext_libc], [AC_TRY_LINK([#include $gt_revision_test_code extern int _nl_msg_cat_cntr; extern int *_nl_domain_bindings;], [bindtextdomain ("", ""); return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_domain_bindings], [eval "$gt_func_gnugettext_libc=yes"], [eval "$gt_func_gnugettext_libc=no"])]) if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then dnl Sometimes libintl requires libiconv, so first search for libiconv. ifelse(gt_included_intl, yes, , [ AM_ICONV_LINK ]) dnl Search for libintl and define LIBINTL, LTLIBINTL and INCINTL dnl accordingly. Don't use AC_LIB_LINKFLAGS_BODY([intl],[iconv]) dnl because that would add "-liconv" to LIBINTL and LTLIBINTL dnl even if libiconv doesn't exist. AC_LIB_LINKFLAGS_BODY([intl]) AC_CACHE_CHECK([for GNU gettext in libintl], [$gt_func_gnugettext_libintl], [gt_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $INCINTL" gt_save_LIBS="$LIBS" LIBS="$LIBS $LIBINTL" dnl Now see whether libintl exists and does not depend on libiconv. AC_TRY_LINK([#include $gt_revision_test_code extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias (const char *);], [bindtextdomain ("", ""); return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("")], [eval "$gt_func_gnugettext_libintl=yes"], [eval "$gt_func_gnugettext_libintl=no"]) dnl Now see whether libintl exists and depends on libiconv. if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" != yes; } && test -n "$LIBICONV"; then LIBS="$LIBS $LIBICONV" AC_TRY_LINK([#include $gt_revision_test_code extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias (const char *);], [bindtextdomain ("", ""); return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("")], [LIBINTL="$LIBINTL $LIBICONV" LTLIBINTL="$LTLIBINTL $LTLIBICONV" eval "$gt_func_gnugettext_libintl=yes" ]) fi CPPFLAGS="$gt_save_CPPFLAGS" LIBS="$gt_save_LIBS"]) fi dnl If an already present or preinstalled GNU gettext() is found, dnl use it. But if this macro is used in GNU gettext, and GNU dnl gettext is already preinstalled in libintl, we update this dnl libintl. (Cf. the install rule in intl/Makefile.in.) if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" = "yes"; } \ || { { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; } \ && test "$PACKAGE" != gettext-runtime \ && test "$PACKAGE" != gettext-tools; }; then gt_use_preinstalled_gnugettext=yes else dnl Reset the values set by searching for libintl. LIBINTL= LTLIBINTL= INCINTL= fi ifelse(gt_included_intl, yes, [ if test "$gt_use_preinstalled_gnugettext" != "yes"; then dnl GNU gettext is not found in the C library. dnl Fall back on included GNU gettext library. nls_cv_use_gnu_gettext=yes fi fi if test "$nls_cv_use_gnu_gettext" = "yes"; then dnl Mark actions used to generate GNU NLS library. BUILD_INCLUDED_LIBINTL=yes USE_INCLUDED_LIBINTL=yes LIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LIBICONV $LIBTHREAD" LTLIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LTLIBICONV $LTLIBTHREAD" LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'` fi CATOBJEXT= if test "$gt_use_preinstalled_gnugettext" = "yes" \ || test "$nls_cv_use_gnu_gettext" = "yes"; then dnl Mark actions to use GNU gettext tools. CATOBJEXT=.gmo fi ]) if test -n "$INTL_MACOSX_LIBS"; then if test "$gt_use_preinstalled_gnugettext" = "yes" \ || test "$nls_cv_use_gnu_gettext" = "yes"; then dnl Some extra flags are needed during linking. LIBINTL="$LIBINTL $INTL_MACOSX_LIBS" LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS" fi fi if test "$gt_use_preinstalled_gnugettext" = "yes" \ || test "$nls_cv_use_gnu_gettext" = "yes"; then AC_DEFINE(ENABLE_NLS, 1, [Define to 1 if translation of program messages to the user's native language is requested.]) else USE_NLS=no fi fi AC_MSG_CHECKING([whether to use NLS]) AC_MSG_RESULT([$USE_NLS]) if test "$USE_NLS" = "yes"; then AC_MSG_CHECKING([where the gettext function comes from]) if test "$gt_use_preinstalled_gnugettext" = "yes"; then if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then gt_source="external libintl" else gt_source="libc" fi else gt_source="included intl directory" fi AC_MSG_RESULT([$gt_source]) fi if test "$USE_NLS" = "yes"; then if test "$gt_use_preinstalled_gnugettext" = "yes"; then if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then AC_MSG_CHECKING([how to link with libintl]) AC_MSG_RESULT([$LIBINTL]) AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCINTL]) fi dnl For backward compatibility. Some packages may be using this. AC_DEFINE(HAVE_GETTEXT, 1, [Define if the GNU gettext() function is already present or preinstalled.]) AC_DEFINE(HAVE_DCGETTEXT, 1, [Define if the GNU dcgettext() function is already present or preinstalled.]) fi dnl We need to process the po/ directory. POSUB=po fi ifelse(gt_included_intl, yes, [ dnl If this is used in GNU gettext we have to set BUILD_INCLUDED_LIBINTL dnl to 'yes' because some of the testsuite requires it. if test "$PACKAGE" = gettext-runtime || test "$PACKAGE" = gettext-tools; then BUILD_INCLUDED_LIBINTL=yes fi dnl Make all variables we use known to autoconf. AC_SUBST(BUILD_INCLUDED_LIBINTL) AC_SUBST(USE_INCLUDED_LIBINTL) AC_SUBST(CATOBJEXT) dnl For backward compatibility. Some configure.ins may be using this. nls_cv_header_intl= nls_cv_header_libgt= dnl For backward compatibility. Some Makefiles may be using this. DATADIRNAME=share AC_SUBST(DATADIRNAME) dnl For backward compatibility. Some Makefiles may be using this. INSTOBJEXT=.mo AC_SUBST(INSTOBJEXT) dnl For backward compatibility. Some Makefiles may be using this. GENCAT=gencat AC_SUBST(GENCAT) dnl For backward compatibility. Some Makefiles may be using this. INTLOBJS= if test "$USE_INCLUDED_LIBINTL" = yes; then INTLOBJS="\$(GETTOBJS)" fi AC_SUBST(INTLOBJS) dnl Enable libtool support if the surrounding package wishes it. INTL_LIBTOOL_SUFFIX_PREFIX=gt_libtool_suffix_prefix AC_SUBST(INTL_LIBTOOL_SUFFIX_PREFIX) ]) dnl For backward compatibility. Some Makefiles may be using this. INTLLIBS="$LIBINTL" AC_SUBST(INTLLIBS) dnl Make all documented variables known to autoconf. AC_SUBST(LIBINTL) AC_SUBST(LTLIBINTL) AC_SUBST(POSUB) ]) dnl Checks for special options needed on MacOS X. dnl Defines INTL_MACOSX_LIBS. AC_DEFUN([gt_INTL_MACOSX], [ dnl Check for API introduced in MacOS X 10.2. AC_CACHE_CHECK([for CFPreferencesCopyAppValue], gt_cv_func_CFPreferencesCopyAppValue, [gt_save_LIBS="$LIBS" LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" AC_TRY_LINK([#include ], [CFPreferencesCopyAppValue(NULL, NULL)], [gt_cv_func_CFPreferencesCopyAppValue=yes], [gt_cv_func_CFPreferencesCopyAppValue=no]) LIBS="$gt_save_LIBS"]) if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then AC_DEFINE([HAVE_CFPREFERENCESCOPYAPPVALUE], 1, [Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in the CoreFoundation framework.]) fi dnl Check for API introduced in MacOS X 10.3. AC_CACHE_CHECK([for CFLocaleCopyCurrent], gt_cv_func_CFLocaleCopyCurrent, [gt_save_LIBS="$LIBS" LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" AC_TRY_LINK([#include ], [CFLocaleCopyCurrent();], [gt_cv_func_CFLocaleCopyCurrent=yes], [gt_cv_func_CFLocaleCopyCurrent=no]) LIBS="$gt_save_LIBS"]) if test $gt_cv_func_CFLocaleCopyCurrent = yes; then AC_DEFINE([HAVE_CFLOCALECOPYCURRENT], 1, [Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the CoreFoundation framework.]) fi INTL_MACOSX_LIBS= if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation" fi AC_SUBST([INTL_MACOSX_LIBS]) ]) dnl gt_NEEDS_INIT ensures that the gt_needs variable is initialized. m4_define([gt_NEEDS_INIT], [ m4_divert_text([DEFAULTS], [gt_needs=]) m4_define([gt_NEEDS_INIT], []) ]) dnl Usage: AM_GNU_GETTEXT_NEED([NEEDSYMBOL]) AC_DEFUN([AM_GNU_GETTEXT_NEED], [ m4_divert_text([INIT_PREPARE], [gt_needs="$gt_needs $1"]) ]) dnl Usage: AM_GNU_GETTEXT_VERSION([gettext-version]) AC_DEFUN([AM_GNU_GETTEXT_VERSION], []) gnunet-0.9.3/m4/longlong.m40000644000175000017500000000327411317762540012361 00000000000000# longlong.m4 serial 8 dnl Copyright (C) 1999-2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Paul Eggert. # Define HAVE_LONG_LONG_INT if 'long long int' works. # This fixes a bug in Autoconf 2.60, but can be removed once we # assume 2.61 everywhere. # Note: If the type 'long long int' exists but is only 32 bits large # (as on some very old compilers), AC_TYPE_LONG_LONG_INT will not be # defined. In this case you can treat 'long long int' like 'long int'. AC_DEFUN([AC_TYPE_LONG_LONG_INT], [ AC_CACHE_CHECK([for long long int], [ac_cv_type_long_long_int], [AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[long long int ll = 9223372036854775807ll; long long int nll = -9223372036854775807LL; typedef int a[((-9223372036854775807LL < 0 && 0 < 9223372036854775807ll) ? 1 : -1)]; int i = 63;]], [[long long int llmax = 9223372036854775807ll; return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i) | (llmax / ll) | (llmax % ll));]])], [ac_cv_type_long_long_int=yes], [ac_cv_type_long_long_int=no])]) if test $ac_cv_type_long_long_int = yes; then AC_DEFINE([HAVE_LONG_LONG_INT], 1, [Define to 1 if the system has the type `long long int'.]) fi ]) # This macro is obsolescent and should go away soon. AC_DEFUN([gl_AC_TYPE_LONG_LONG], [ AC_REQUIRE([AC_TYPE_LONG_LONG_INT]) ac_cv_type_long_long=$ac_cv_type_long_long_int if test $ac_cv_type_long_long = yes; then AC_DEFINE(HAVE_LONG_LONG, 1, [Define if you have the 'long long' type.]) fi ]) gnunet-0.9.3/m4/argz.m40000644000175000017500000000506711762217203011502 00000000000000# Portability macros for glibc argz. -*- Autoconf -*- # # Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc. # Written by Gary V. Vaughan # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 5 argz.m4 AC_DEFUN([gl_FUNC_ARGZ], [gl_PREREQ_ARGZ AC_CHECK_HEADERS([argz.h], [], [], [AC_INCLUDES_DEFAULT]) AC_CHECK_TYPES([error_t], [], [AC_DEFINE([error_t], [int], [Define to a type to use for `error_t' if it is not otherwise available.]) AC_DEFINE([__error_t_defined], [1], [Define so that glibc/gnulib argp.h does not typedef error_t.])], [#if defined(HAVE_ARGZ_H) # include #endif]) ARGZ_H= AC_CHECK_FUNCS([argz_add argz_append argz_count argz_create_sep argz_insert \ argz_next argz_stringify], [], [ARGZ_H=argz.h; AC_LIBOBJ([argz])]) dnl if have system argz functions, allow forced use of dnl libltdl-supplied implementation (and default to do so dnl on "known bad" systems). Could use a runtime check, but dnl (a) detecting malloc issues is notoriously unreliable dnl (b) only known system that declares argz functions, dnl provides them, yet they are broken, is cygwin dnl releases prior to 16-Mar-2007 (1.5.24 and earlier) dnl So, it's more straightforward simply to special case dnl this for known bad systems. AS_IF([test -z "$ARGZ_H"], [AC_CACHE_CHECK( [if argz actually works], [lt_cv_sys_argz_works], [[case $host_os in #( *cygwin*) lt_cv_sys_argz_works=no if test "$cross_compiling" != no; then lt_cv_sys_argz_works="guessing no" else lt_sed_extract_leading_digits='s/^\([0-9\.]*\).*/\1/' save_IFS=$IFS IFS=-. set x `uname -r | sed -e "$lt_sed_extract_leading_digits"` IFS=$save_IFS lt_os_major=${2-0} lt_os_minor=${3-0} lt_os_micro=${4-0} if test "$lt_os_major" -gt 1 \ || { test "$lt_os_major" -eq 1 \ && { test "$lt_os_minor" -gt 5 \ || { test "$lt_os_minor" -eq 5 \ && test "$lt_os_micro" -gt 24; }; }; }; then lt_cv_sys_argz_works=yes fi fi ;; #( *) lt_cv_sys_argz_works=yes ;; esac]]) AS_IF([test $lt_cv_sys_argz_works = yes], [AC_DEFINE([HAVE_WORKING_ARGZ], 1, [This value is set to 1 to indicate that the system argz facility works])], [ARGZ_H=argz.h AC_LIBOBJ([argz])])]) AC_SUBST([ARGZ_H]) ]) # Prerequisites of lib/argz.c. AC_DEFUN([gl_PREREQ_ARGZ], [:]) gnunet-0.9.3/m4/libgcrypt.m40000644000175000017500000001011611317762615012535 00000000000000dnl Autoconf macros for libgcrypt dnl Copyright (C) 2002, 2004 Free Software Foundation, Inc. dnl dnl This file is free software; as a special exception the author gives dnl unlimited permission to copy and/or distribute it, with or without dnl modifications, as long as this notice is preserved. dnl dnl This file is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. dnl AM_PATH_LIBGCRYPT([MINIMUM-VERSION, dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]]) dnl Test for libgcrypt and define LIBGCRYPT_CFLAGS and LIBGCRYPT_LIBS. dnl MINIMUN-VERSION is a string with the version number optionalliy prefixed dnl with the API version to also check the API compatibility. Example: dnl a MINIMUN-VERSION of 1:1.2.5 won't pass the test unless the installed dnl version of libgcrypt is at least 1.2.5 *and* the API number is 1. Using dnl this features allows to prevent build against newer versions of libgcrypt dnl with a changed API. dnl AC_DEFUN([AM_PATH_LIBGCRYPT], [ AC_ARG_WITH(libgcrypt-prefix, AC_HELP_STRING([--with-libgcrypt-prefix=PFX], [prefix where LIBGCRYPT is installed (optional)]), libgcrypt_config_prefix="$withval", libgcrypt_config_prefix="") if test x$libgcrypt_config_prefix != x ; then if test x${LIBGCRYPT_CONFIG+set} != xset ; then LIBGCRYPT_CONFIG=$libgcrypt_config_prefix/bin/libgcrypt-config fi fi AC_PATH_PROG(LIBGCRYPT_CONFIG, libgcrypt-config, no) tmp=ifelse([$1], ,1:1.2.0,$1) if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then req_libgcrypt_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'` min_libgcrypt_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'` else req_libgcrypt_api=0 min_libgcrypt_version="$tmp" fi AC_MSG_CHECKING(for LIBGCRYPT - version >= $min_libgcrypt_version) ok=no if test "$LIBGCRYPT_CONFIG" != "no" ; then req_major=`echo $min_libgcrypt_version | \ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'` req_minor=`echo $min_libgcrypt_version | \ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'` req_micro=`echo $min_libgcrypt_version | \ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'` libgcrypt_config_version=`$LIBGCRYPT_CONFIG --version` major=`echo $libgcrypt_config_version | \ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'` minor=`echo $libgcrypt_config_version | \ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'` micro=`echo $libgcrypt_config_version | \ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/'` if test "$major" -gt "$req_major"; then ok=yes else if test "$major" -eq "$req_major"; then if test "$minor" -gt "$req_minor"; then ok=yes else if test "$minor" -eq "$req_minor"; then if test "$micro" -ge "$req_micro"; then ok=yes fi fi fi fi fi fi if test $ok = yes; then AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) fi if test $ok = yes; then # If we have a recent libgcrypt, we should also check that the # API is compatible if test "$req_libgcrypt_api" -gt 0 ; then tmp=`$LIBGCRYPT_CONFIG --api-version 2>/dev/null || echo 0` if test "$tmp" -gt 0 ; then AC_MSG_CHECKING([LIBGCRYPT API version]) if test "$req_libgcrypt_api" -eq "$tmp" ; then AC_MSG_RESULT(okay) else ok=no AC_MSG_RESULT([does not match (want=$req_libgcrypt_api got=$tmp)]) fi fi fi fi if test $ok = yes; then LIBGCRYPT_CFLAGS=`$LIBGCRYPT_CONFIG --cflags` LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG --libs` ifelse([$2], , :, [$2]) else LIBGCRYPT_CFLAGS="" LIBGCRYPT_LIBS="" ifelse([$3], , :, [$3]) fi AC_SUBST(LIBGCRYPT_CFLAGS) AC_SUBST(LIBGCRYPT_LIBS) ]) gnunet-0.9.3/m4/glib-2.0.m40000644000175000017500000001776211317762615011766 00000000000000# Configure paths for GLIB # Owen Taylor 1997-2001 dnl AM_PATH_GLIB_2_0([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]]) dnl Test for GLIB, and define GLIB_CFLAGS and GLIB_LIBS, if gmodule, gobject or dnl gthread is specified in MODULES, pass to pkg-config dnl AC_DEFUN([AM_PATH_GLIB_2_0], [dnl dnl Get the cflags and libraries from pkg-config dnl AC_ARG_ENABLE(glibtest, [ --disable-glibtest do not try to compile and run a test GLIB program], , enable_glibtest=yes) pkg_config_args=glib-2.0 for module in . $4 do case "$module" in gmodule) pkg_config_args="$pkg_config_args gmodule-2.0" ;; gobject) pkg_config_args="$pkg_config_args gobject-2.0" ;; gthread) pkg_config_args="$pkg_config_args gthread-2.0" ;; esac done AC_PATH_PROG(PKG_CONFIG, pkg-config, no) no_glib="" if test x$PKG_CONFIG != xno ; then if $PKG_CONFIG --atleast-pkgconfig-version 0.7 ; then : else echo *** pkg-config too old; version 0.7 or better required. no_glib=yes PKG_CONFIG=no fi else no_glib=yes fi min_glib_version=ifelse([$1], ,2.0.0,$1) AC_MSG_CHECKING(for GLIB - version >= $min_glib_version) if test x$PKG_CONFIG != xno ; then ## don't try to run the test against uninstalled libtool libs if $PKG_CONFIG --uninstalled $pkg_config_args; then echo "Will use uninstalled version of GLib found in PKG_CONFIG_PATH" enable_glibtest=no fi if $PKG_CONFIG --atleast-version $min_glib_version $pkg_config_args; then : else no_glib=yes fi fi if test x"$no_glib" = x ; then GLIB_GENMARSHAL=`$PKG_CONFIG --variable=glib_genmarshal glib-2.0` GOBJECT_QUERY=`$PKG_CONFIG --variable=gobject_query glib-2.0` GLIB_MKENUMS=`$PKG_CONFIG --variable=glib_mkenums glib-2.0` GLIB_CFLAGS=`$PKG_CONFIG --cflags $pkg_config_args` GLIB_LIBS=`$PKG_CONFIG --libs $pkg_config_args` glib_config_major_version=`$PKG_CONFIG --modversion glib-2.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` glib_config_minor_version=`$PKG_CONFIG --modversion glib-2.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` glib_config_micro_version=`$PKG_CONFIG --modversion glib-2.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` if test "x$enable_glibtest" = "xyes" ; then ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GLIB_CFLAGS" LIBS="$GLIB_LIBS $LIBS" dnl dnl Now check if the installed GLIB is sufficiently new. (Also sanity dnl checks the results of pkg-config to some extent) dnl rm -f conf.glibtest AC_TRY_RUN([ #include #include #include int main () { int major, minor, micro; char *tmp_version; system ("touch conf.glibtest"); /* HP/UX 9 (%@#!) writes to sscanf strings */ tmp_version = g_strdup("$min_glib_version"); if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { printf("%s, bad version string\n", "$min_glib_version"); exit(1); } if ((glib_major_version != $glib_config_major_version) || (glib_minor_version != $glib_config_minor_version) || (glib_micro_version != $glib_config_micro_version)) { printf("\n*** 'pkg-config --modversion glib-2.0' returned %d.%d.%d, but GLIB (%d.%d.%d)\n", $glib_config_major_version, $glib_config_minor_version, $glib_config_micro_version, glib_major_version, glib_minor_version, glib_micro_version); printf ("*** was found! If pkg-config was correct, then it is best\n"); printf ("*** to remove the old version of GLib. You may also be able to fix the error\n"); printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); printf("*** required on your system.\n"); printf("*** If pkg-config was wrong, set the environment variable PKG_CONFIG_PATH\n"); printf("*** to point to the correct configuration files\n"); } else if ((glib_major_version != GLIB_MAJOR_VERSION) || (glib_minor_version != GLIB_MINOR_VERSION) || (glib_micro_version != GLIB_MICRO_VERSION)) { printf("*** GLIB header files (version %d.%d.%d) do not match\n", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION); printf("*** library (version %d.%d.%d)\n", glib_major_version, glib_minor_version, glib_micro_version); } else { if ((glib_major_version > major) || ((glib_major_version == major) && (glib_minor_version > minor)) || ((glib_major_version == major) && (glib_minor_version == minor) && (glib_micro_version >= micro))) { return 0; } else { printf("\n*** An old version of GLIB (%d.%d.%d) was found.\n", glib_major_version, glib_minor_version, glib_micro_version); printf("*** You need a version of GLIB newer than %d.%d.%d. The latest version of\n", major, minor, micro); printf("*** GLIB is always available from ftp://ftp.gtk.org.\n"); printf("***\n"); printf("*** If you have already installed a sufficiently new version, this error\n"); printf("*** probably means that the wrong copy of the pkg-config shell script is\n"); printf("*** being found. The easiest way to fix this is to remove the old version\n"); printf("*** of GLIB, but you can also set the PKG_CONFIG environment to point to the\n"); printf("*** correct copy of pkg-config. (In this case, you will have to\n"); printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); printf("*** so that the correct libraries are found at run-time))\n"); } } return 1; } ],, no_glib=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi if test "x$no_glib" = x ; then AC_MSG_RESULT(yes (version $glib_config_major_version.$glib_config_minor_version.$glib_config_micro_version)) ifelse([$2], , :, [$2]) else AC_MSG_RESULT(no) if test "$PKG_CONFIG" = "no" ; then echo "*** A new enough version of pkg-config was not found." echo "*** See http://www.freedesktop.org/software/pkgconfig/" else if test -f conf.glibtest ; then : else echo "*** Could not run GLIB test program, checking why..." ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GLIB_CFLAGS" LIBS="$LIBS $GLIB_LIBS" AC_TRY_LINK([ #include #include ], [ return ((glib_major_version) || (glib_minor_version) || (glib_micro_version)); ], [ echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding GLIB or finding the wrong" echo "*** version of GLIB. If it is not finding GLIB, you'll need to set your" echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" echo "*** to the installed location Also, make sure you have run ldconfig if that" echo "*** is required on your system" echo "***" echo "*** If you have an old version installed, it is best to remove it, although" echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" ], [ echo "*** The test program failed to compile or link. See the file config.log for the" echo "*** exact error that occured. This usually means GLIB is incorrectly installed."]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi GLIB_CFLAGS="" GLIB_LIBS="" GLIB_GENMARSHAL="" GOBJECT_QUERY="" GLIB_MKENUMS="" ifelse([$3], , :, [$3]) fi AC_SUBST(GLIB_CFLAGS) AC_SUBST(GLIB_LIBS) AC_SUBST(GLIB_GENMARSHAL) AC_SUBST(GOBJECT_QUERY) AC_SUBST(GLIB_MKENUMS) rm -f conf.glibtest ]) gnunet-0.9.3/m4/lib-prefix.m40000644000175000017500000001503611317762540012602 00000000000000# lib-prefix.m4 serial 5 (gettext-0.15) dnl Copyright (C) 2001-2005 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't dnl require excessive bracketing. ifdef([AC_HELP_STRING], [AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], [AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed dnl to access previously installed libraries. The basic assumption is that dnl a user will want packages to use other packages he previously installed dnl with the same --prefix option. dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate dnl libraries, but is otherwise very convenient. AC_DEFUN([AC_LIB_PREFIX], [ AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) dnl By default, look in $includedir and $libdir. use_additional=yes AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) AC_LIB_ARG_WITH([lib-prefix], [ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib --without-lib-prefix don't search for libraries in includedir and libdir], [ if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" fi fi ]) if test $use_additional = yes; then dnl Potentially add $additional_includedir to $CPPFLAGS. dnl But don't add it dnl 1. if it's the standard /usr/include, dnl 2. if it's already present in $CPPFLAGS, dnl 3. if it's /usr/local/include and we are using GCC on Linux, dnl 4. if it doesn't exist as a directory. if test "X$additional_includedir" != "X/usr/include"; then haveit= for x in $CPPFLAGS; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then if test -d "$additional_includedir"; then dnl Really add $additional_includedir to $CPPFLAGS. CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" fi fi fi fi dnl Potentially add $additional_libdir to $LDFLAGS. dnl But don't add it dnl 1. if it's the standard /usr/lib, dnl 2. if it's already present in $LDFLAGS, dnl 3. if it's /usr/local/lib and we are using GCC on Linux, dnl 4. if it doesn't exist as a directory. if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then haveit= for x in $LDFLAGS; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then if test -n "$GCC"; then case $host_os in linux*) haveit=yes;; esac fi fi if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LDFLAGS. LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" fi fi fi fi fi ]) dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, dnl acl_final_exec_prefix, containing the values to which $prefix and dnl $exec_prefix will expand at the end of the configure script. AC_DEFUN([AC_LIB_PREPARE_PREFIX], [ dnl Unfortunately, prefix and exec_prefix get only finally determined dnl at the end of configure. if test "X$prefix" = "XNONE"; then acl_final_prefix="$ac_default_prefix" else acl_final_prefix="$prefix" fi if test "X$exec_prefix" = "XNONE"; then acl_final_exec_prefix='${prefix}' else acl_final_exec_prefix="$exec_prefix" fi acl_save_prefix="$prefix" prefix="$acl_final_prefix" eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" prefix="$acl_save_prefix" ]) dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the dnl variables prefix and exec_prefix bound to the values they will have dnl at the end of the configure script. AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], [ acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" $1 exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" ]) dnl AC_LIB_PREPARE_MULTILIB creates a variable acl_libdirstem, containing dnl the basename of the libdir, either "lib" or "lib64". AC_DEFUN([AC_LIB_PREPARE_MULTILIB], [ dnl There is no formal standard regarding lib and lib64. The current dnl practice is that on a system supporting 32-bit and 64-bit instruction dnl sets or ABIs, 64-bit libraries go under $prefix/lib64 and 32-bit dnl libraries go under $prefix/lib. We determine the compiler's default dnl mode by looking at the compiler's library search path. If at least dnl of its elements ends in /lib64 or points to a directory whose absolute dnl pathname ends in /lib64, we assume a 64-bit ABI. Otherwise we use the dnl default, namely "lib". acl_libdirstem=lib searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` if test -n "$searchpath"; then acl_save_IFS="${IFS= }"; IFS=":" for searchdir in $searchpath; do if test -d "$searchdir"; then case "$searchdir" in */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; *) searchdir=`cd "$searchdir" && pwd` case "$searchdir" in */lib64 ) acl_libdirstem=lib64 ;; esac ;; esac fi done IFS="$acl_save_IFS" fi ]) gnunet-0.9.3/m4/inttypes-pri.m40000644000175000017500000000215211317762540013203 00000000000000# inttypes-pri.m4 serial 4 (gettext-0.16) dnl Copyright (C) 1997-2002, 2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_PREREQ(2.52) # Define PRI_MACROS_BROKEN if exists and defines the PRI* # macros to non-string values. This is the case on AIX 4.3.3. AC_DEFUN([gt_INTTYPES_PRI], [ AC_CHECK_HEADERS([inttypes.h]) if test $ac_cv_header_inttypes_h = yes; then AC_CACHE_CHECK([whether the inttypes.h PRIxNN macros are broken], gt_cv_inttypes_pri_broken, [ AC_TRY_COMPILE([#include #ifdef PRId32 char *p = PRId32; #endif ], [], gt_cv_inttypes_pri_broken=no, gt_cv_inttypes_pri_broken=yes) ]) fi if test "$gt_cv_inttypes_pri_broken" = yes; then AC_DEFINE_UNQUOTED(PRI_MACROS_BROKEN, 1, [Define if exists and defines unusable PRI* macros.]) PRI_MACROS_BROKEN=1 else PRI_MACROS_BROKEN=0 fi AC_SUBST([PRI_MACROS_BROKEN]) ]) gnunet-0.9.3/m4/ltdl.m40000644000175000017500000006377611762217203011511 00000000000000# ltdl.m4 - Configure ltdl for the target system. -*-Autoconf-*- # # Copyright (C) 1999-2006, 2007, 2008 Free Software Foundation, Inc. # Written by Thomas Tanner, 1999 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 17 LTDL_INIT # LT_CONFIG_LTDL_DIR(DIRECTORY, [LTDL-MODE]) # ------------------------------------------ # DIRECTORY contains the libltdl sources. It is okay to call this # function multiple times, as long as the same DIRECTORY is always given. AC_DEFUN([LT_CONFIG_LTDL_DIR], [AC_BEFORE([$0], [LTDL_INIT]) _$0($*) ])# LT_CONFIG_LTDL_DIR # We break this out into a separate macro, so that we can call it safely # internally without being caught accidentally by the sed scan in libtoolize. m4_defun([_LT_CONFIG_LTDL_DIR], [dnl remove trailing slashes m4_pushdef([_ARG_DIR], m4_bpatsubst([$1], [/*$])) m4_case(_LTDL_DIR, [], [dnl only set lt_ltdl_dir if _ARG_DIR is not simply `.' m4_if(_ARG_DIR, [.], [], [m4_define([_LTDL_DIR], _ARG_DIR) _LT_SHELL_INIT([lt_ltdl_dir=']_ARG_DIR['])])], [m4_if(_ARG_DIR, _LTDL_DIR, [], [m4_fatal([multiple libltdl directories: `]_LTDL_DIR[', `]_ARG_DIR['])])]) m4_popdef([_ARG_DIR]) ])# _LT_CONFIG_LTDL_DIR # Initialise: m4_define([_LTDL_DIR], []) # _LT_BUILD_PREFIX # ---------------- # If Autoconf is new enough, expand to `${top_build_prefix}', otherwise # to `${top_builddir}/'. m4_define([_LT_BUILD_PREFIX], [m4_ifdef([AC_AUTOCONF_VERSION], [m4_if(m4_version_compare(m4_defn([AC_AUTOCONF_VERSION]), [2.62]), [-1], [m4_ifdef([_AC_HAVE_TOP_BUILD_PREFIX], [${top_build_prefix}], [${top_builddir}/])], [${top_build_prefix}])], [${top_builddir}/])[]dnl ]) # LTDL_CONVENIENCE # ---------------- # sets LIBLTDL to the link flags for the libltdl convenience library and # LTDLINCL to the include flags for the libltdl header and adds # --enable-ltdl-convenience to the configure arguments. Note that # AC_CONFIG_SUBDIRS is not called here. LIBLTDL will be prefixed with # '${top_build_prefix}' if available, otherwise with '${top_builddir}/', # and LTDLINCL will be prefixed with '${top_srcdir}/' (note the single # quotes!). If your package is not flat and you're not using automake, # define top_build_prefix, top_builddir, and top_srcdir appropriately # in your Makefiles. AC_DEFUN([LTDL_CONVENIENCE], [AC_BEFORE([$0], [LTDL_INIT])dnl dnl Although the argument is deprecated and no longer documented, dnl LTDL_CONVENIENCE used to take a DIRECTORY orgument, if we have one dnl here make sure it is the same as any other declaration of libltdl's dnl location! This also ensures lt_ltdl_dir is set when configure.ac is dnl not yet using an explicit LT_CONFIG_LTDL_DIR. m4_ifval([$1], [_LT_CONFIG_LTDL_DIR([$1])])dnl _$0() ])# LTDL_CONVENIENCE # AC_LIBLTDL_CONVENIENCE accepted a directory argument in older libtools, # now we have LT_CONFIG_LTDL_DIR: AU_DEFUN([AC_LIBLTDL_CONVENIENCE], [_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) _LTDL_CONVENIENCE]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBLTDL_CONVENIENCE], []) # _LTDL_CONVENIENCE # ----------------- # Code shared by LTDL_CONVENIENCE and LTDL_INIT([convenience]). m4_defun([_LTDL_CONVENIENCE], [case $enable_ltdl_convenience in no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; "") enable_ltdl_convenience=yes ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; esac LIBLTDL='_LT_BUILD_PREFIX'"${lt_ltdl_dir+$lt_ltdl_dir/}libltdlc.la" LTDLDEPS=$LIBLTDL LTDLINCL='-I${top_srcdir}'"${lt_ltdl_dir+/$lt_ltdl_dir}" AC_SUBST([LIBLTDL]) AC_SUBST([LTDLDEPS]) AC_SUBST([LTDLINCL]) # For backwards non-gettext consistent compatibility... INCLTDL="$LTDLINCL" AC_SUBST([INCLTDL]) ])# _LTDL_CONVENIENCE # LTDL_INSTALLABLE # ---------------- # sets LIBLTDL to the link flags for the libltdl installable library # and LTDLINCL to the include flags for the libltdl header and adds # --enable-ltdl-install to the configure arguments. Note that # AC_CONFIG_SUBDIRS is not called from here. If an installed libltdl # is not found, LIBLTDL will be prefixed with '${top_build_prefix}' if # available, otherwise with '${top_builddir}/', and LTDLINCL will be # prefixed with '${top_srcdir}/' (note the single quotes!). If your # package is not flat and you're not using automake, define top_build_prefix, # top_builddir, and top_srcdir appropriately in your Makefiles. # In the future, this macro may have to be called after LT_INIT. AC_DEFUN([LTDL_INSTALLABLE], [AC_BEFORE([$0], [LTDL_INIT])dnl dnl Although the argument is deprecated and no longer documented, dnl LTDL_INSTALLABLE used to take a DIRECTORY orgument, if we have one dnl here make sure it is the same as any other declaration of libltdl's dnl location! This also ensures lt_ltdl_dir is set when configure.ac is dnl not yet using an explicit LT_CONFIG_LTDL_DIR. m4_ifval([$1], [_LT_CONFIG_LTDL_DIR([$1])])dnl _$0() ])# LTDL_INSTALLABLE # AC_LIBLTDL_INSTALLABLE accepted a directory argument in older libtools, # now we have LT_CONFIG_LTDL_DIR: AU_DEFUN([AC_LIBLTDL_INSTALLABLE], [_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) _LTDL_INSTALLABLE]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBLTDL_INSTALLABLE], []) # _LTDL_INSTALLABLE # ----------------- # Code shared by LTDL_INSTALLABLE and LTDL_INIT([installable]). m4_defun([_LTDL_INSTALLABLE], [if test -f $prefix/lib/libltdl.la; then lt_save_LDFLAGS="$LDFLAGS" LDFLAGS="-L$prefix/lib $LDFLAGS" AC_CHECK_LIB([ltdl], [lt_dlinit], [lt_lib_ltdl=yes]) LDFLAGS="$lt_save_LDFLAGS" if test x"${lt_lib_ltdl-no}" = xyes; then if test x"$enable_ltdl_install" != xyes; then # Don't overwrite $prefix/lib/libltdl.la without --enable-ltdl-install AC_MSG_WARN([not overwriting libltdl at $prefix, force with `--enable-ltdl-install']) enable_ltdl_install=no fi elif test x"$enable_ltdl_install" = xno; then AC_MSG_WARN([libltdl not installed, but installation disabled]) fi fi # If configure.ac declared an installable ltdl, and the user didn't override # with --disable-ltdl-install, we will install the shipped libltdl. case $enable_ltdl_install in no) ac_configure_args="$ac_configure_args --enable-ltdl-install=no" LIBLTDL="-lltdl" LTDLDEPS= LTDLINCL= ;; *) enable_ltdl_install=yes ac_configure_args="$ac_configure_args --enable-ltdl-install" LIBLTDL='_LT_BUILD_PREFIX'"${lt_ltdl_dir+$lt_ltdl_dir/}libltdl.la" LTDLDEPS=$LIBLTDL LTDLINCL='-I${top_srcdir}'"${lt_ltdl_dir+/$lt_ltdl_dir}" ;; esac AC_SUBST([LIBLTDL]) AC_SUBST([LTDLDEPS]) AC_SUBST([LTDLINCL]) # For backwards non-gettext consistent compatibility... INCLTDL="$LTDLINCL" AC_SUBST([INCLTDL]) ])# LTDL_INSTALLABLE # _LTDL_MODE_DISPATCH # ------------------- m4_define([_LTDL_MODE_DISPATCH], [dnl If _LTDL_DIR is `.', then we are configuring libltdl itself: m4_if(_LTDL_DIR, [], [], dnl if _LTDL_MODE was not set already, the default value is `subproject': [m4_case(m4_default(_LTDL_MODE, [subproject]), [subproject], [AC_CONFIG_SUBDIRS(_LTDL_DIR) _LT_SHELL_INIT([lt_dlopen_dir="$lt_ltdl_dir"])], [nonrecursive], [_LT_SHELL_INIT([lt_dlopen_dir="$lt_ltdl_dir"; lt_libobj_prefix="$lt_ltdl_dir/"])], [recursive], [], [m4_fatal([unknown libltdl mode: ]_LTDL_MODE)])])dnl dnl Be careful not to expand twice: m4_define([$0], []) ])# _LTDL_MODE_DISPATCH # _LT_LIBOBJ(MODULE_NAME) # ----------------------- # Like AC_LIBOBJ, except that MODULE_NAME goes into _LT_LIBOBJS instead # of into LIBOBJS. AC_DEFUN([_LT_LIBOBJ], [ m4_pattern_allow([^_LT_LIBOBJS$]) _LT_LIBOBJS="$_LT_LIBOBJS $1.$ac_objext" ])# _LT_LIBOBJS # LTDL_INIT([OPTIONS]) # -------------------- # Clients of libltdl can use this macro to allow the installer to # choose between a shipped copy of the ltdl sources or a preinstalled # version of the library. If the shipped ltdl sources are not in a # subdirectory named libltdl, the directory name must be given by # LT_CONFIG_LTDL_DIR. AC_DEFUN([LTDL_INIT], [dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) dnl We need to keep our own list of libobjs separate from our parent project, dnl and the easiest way to do that is redefine the AC_LIBOBJs macro while dnl we look for our own LIBOBJs. m4_pushdef([AC_LIBOBJ], m4_defn([_LT_LIBOBJ])) m4_pushdef([AC_LIBSOURCES]) dnl If not otherwise defined, default to the 1.5.x compatible subproject mode: m4_if(_LTDL_MODE, [], [m4_define([_LTDL_MODE], m4_default([$2], [subproject])) m4_if([-1], [m4_bregexp(_LTDL_MODE, [\(subproject\|\(non\)?recursive\)])], [m4_fatal([unknown libltdl mode: ]_LTDL_MODE)])]) AC_ARG_WITH([included_ltdl], [AS_HELP_STRING([--with-included-ltdl], [use the GNU ltdl sources included here])]) if test "x$with_included_ltdl" != xyes; then # We are not being forced to use the included libltdl sources, so # decide whether there is a useful installed version we can use. AC_CHECK_HEADER([ltdl.h], [AC_CHECK_DECL([lt_dlinterface_register], [AC_CHECK_LIB([ltdl], [lt_dladvise_preload], [with_included_ltdl=no], [with_included_ltdl=yes])], [with_included_ltdl=yes], [AC_INCLUDES_DEFAULT #include ])], [with_included_ltdl=yes], [AC_INCLUDES_DEFAULT] ) fi dnl If neither LT_CONFIG_LTDL_DIR, LTDL_CONVENIENCE nor LTDL_INSTALLABLE dnl was called yet, then for old times' sake, we assume libltdl is in an dnl eponymous directory: AC_PROVIDE_IFELSE([LT_CONFIG_LTDL_DIR], [], [_LT_CONFIG_LTDL_DIR([libltdl])]) AC_ARG_WITH([ltdl_include], [AS_HELP_STRING([--with-ltdl-include=DIR], [use the ltdl headers installed in DIR])]) if test -n "$with_ltdl_include"; then if test -f "$with_ltdl_include/ltdl.h"; then : else AC_MSG_ERROR([invalid ltdl include directory: `$with_ltdl_include']) fi else with_ltdl_include=no fi AC_ARG_WITH([ltdl_lib], [AS_HELP_STRING([--with-ltdl-lib=DIR], [use the libltdl.la installed in DIR])]) if test -n "$with_ltdl_lib"; then if test -f "$with_ltdl_lib/libltdl.la"; then : else AC_MSG_ERROR([invalid ltdl library directory: `$with_ltdl_lib']) fi else with_ltdl_lib=no fi case ,$with_included_ltdl,$with_ltdl_include,$with_ltdl_lib, in ,yes,no,no,) m4_case(m4_default(_LTDL_TYPE, [convenience]), [convenience], [_LTDL_CONVENIENCE], [installable], [_LTDL_INSTALLABLE], [m4_fatal([unknown libltdl build type: ]_LTDL_TYPE)]) ;; ,no,no,no,) # If the included ltdl is not to be used, then use the # preinstalled libltdl we found. AC_DEFINE([HAVE_LTDL], [1], [Define this if a modern libltdl is already installed]) LIBLTDL=-lltdl LTDLDEPS= LTDLINCL= ;; ,no*,no,*) AC_MSG_ERROR([`--with-ltdl-include' and `--with-ltdl-lib' options must be used together]) ;; *) with_included_ltdl=no LIBLTDL="-L$with_ltdl_lib -lltdl" LTDLDEPS= LTDLINCL="-I$with_ltdl_include" ;; esac INCLTDL="$LTDLINCL" # Report our decision... AC_MSG_CHECKING([where to find libltdl headers]) AC_MSG_RESULT([$LTDLINCL]) AC_MSG_CHECKING([where to find libltdl library]) AC_MSG_RESULT([$LIBLTDL]) _LTDL_SETUP dnl restore autoconf definition. m4_popdef([AC_LIBOBJ]) m4_popdef([AC_LIBSOURCES]) AC_CONFIG_COMMANDS_PRE([ _ltdl_libobjs= _ltdl_ltlibobjs= if test -n "$_LT_LIBOBJS"; then # Remove the extension. _lt_sed_drop_objext='s/\.o$//;s/\.obj$//' for i in `for i in $_LT_LIBOBJS; do echo "$i"; done | sed "$_lt_sed_drop_objext" | sort -u`; do _ltdl_libobjs="$_ltdl_libobjs $lt_libobj_prefix$i.$ac_objext" _ltdl_ltlibobjs="$_ltdl_ltlibobjs $lt_libobj_prefix$i.lo" done fi AC_SUBST([ltdl_LIBOBJS], [$_ltdl_libobjs]) AC_SUBST([ltdl_LTLIBOBJS], [$_ltdl_ltlibobjs]) ]) # Only expand once: m4_define([LTDL_INIT]) ])# LTDL_INIT # Old names: AU_DEFUN([AC_LIB_LTDL], [LTDL_INIT($@)]) AU_DEFUN([AC_WITH_LTDL], [LTDL_INIT($@)]) AU_DEFUN([LT_WITH_LTDL], [LTDL_INIT($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIB_LTDL], []) dnl AC_DEFUN([AC_WITH_LTDL], []) dnl AC_DEFUN([LT_WITH_LTDL], []) # _LTDL_SETUP # ----------- # Perform all the checks necessary for compilation of the ltdl objects # -- including compiler checks and header checks. This is a public # interface mainly for the benefit of libltdl's own configure.ac, most # other users should call LTDL_INIT instead. AC_DEFUN([_LTDL_SETUP], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_SYS_MODULE_EXT])dnl AC_REQUIRE([LT_SYS_MODULE_PATH])dnl AC_REQUIRE([LT_SYS_DLSEARCH_PATH])dnl AC_REQUIRE([LT_LIB_DLLOAD])dnl AC_REQUIRE([LT_SYS_SYMBOL_USCORE])dnl AC_REQUIRE([LT_FUNC_DLSYM_USCORE])dnl AC_REQUIRE([LT_SYS_DLOPEN_DEPLIBS])dnl AC_REQUIRE([gl_FUNC_ARGZ])dnl m4_require([_LT_CHECK_OBJDIR])dnl m4_require([_LT_HEADER_DLFCN])dnl m4_require([_LT_CHECK_DLPREOPEN])dnl m4_require([_LT_DECL_SED])dnl dnl Don't require this, or it will be expanded earlier than the code dnl that sets the variables it relies on: _LT_ENABLE_INSTALL dnl _LTDL_MODE specific code must be called at least once: _LTDL_MODE_DISPATCH # In order that ltdl.c can compile, find out the first AC_CONFIG_HEADERS # the user used. This is so that ltdl.h can pick up the parent projects # config.h file, The first file in AC_CONFIG_HEADERS must contain the # definitions required by ltdl.c. # FIXME: Remove use of undocumented AC_LIST_HEADERS (2.59 compatibility). AC_CONFIG_COMMANDS_PRE([dnl m4_pattern_allow([^LT_CONFIG_H$])dnl m4_ifset([AH_HEADER], [LT_CONFIG_H=AH_HEADER], [m4_ifset([AC_LIST_HEADERS], [LT_CONFIG_H=`echo "AC_LIST_HEADERS" | $SED 's,^[[ ]]*,,;s,[[ :]].*$,,'`], [])])]) AC_SUBST([LT_CONFIG_H]) AC_CHECK_HEADERS([unistd.h dl.h sys/dl.h dld.h mach-o/dyld.h dirent.h], [], [], [AC_INCLUDES_DEFAULT]) AC_CHECK_FUNCS([closedir opendir readdir], [], [AC_LIBOBJ([lt__dirent])]) AC_CHECK_FUNCS([strlcat strlcpy], [], [AC_LIBOBJ([lt__strl])]) AC_DEFINE_UNQUOTED([LT_LIBEXT],["$libext"],[The archive extension]) name=ltdl LTDLOPEN=`eval "\\$ECHO \"$libname_spec\""` AC_SUBST([LTDLOPEN]) ])# _LTDL_SETUP # _LT_ENABLE_INSTALL # ------------------ m4_define([_LT_ENABLE_INSTALL], [AC_ARG_ENABLE([ltdl-install], [AS_HELP_STRING([--enable-ltdl-install], [install libltdl])]) case ,${enable_ltdl_install},${enable_ltdl_convenience} in *yes*) ;; *) enable_ltdl_convenience=yes ;; esac m4_ifdef([AM_CONDITIONAL], [AM_CONDITIONAL(INSTALL_LTDL, test x"${enable_ltdl_install-no}" != xno) AM_CONDITIONAL(CONVENIENCE_LTDL, test x"${enable_ltdl_convenience-no}" != xno)]) ])# _LT_ENABLE_INSTALL # LT_SYS_DLOPEN_DEPLIBS # --------------------- AC_DEFUN([LT_SYS_DLOPEN_DEPLIBS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_CACHE_CHECK([whether deplibs are loaded by dlopen], [lt_cv_sys_dlopen_deplibs], [# PORTME does your system automatically load deplibs for dlopen? # or its logical equivalent (e.g. shl_load for HP-UX < 11) # For now, we just catch OSes we know something about -- in the # future, we'll try test this programmatically. lt_cv_sys_dlopen_deplibs=unknown case $host_os in aix3*|aix4.1.*|aix4.2.*) # Unknown whether this is true for these versions of AIX, but # we want this `case' here to explicitly catch those versions. lt_cv_sys_dlopen_deplibs=unknown ;; aix[[4-9]]*) lt_cv_sys_dlopen_deplibs=yes ;; amigaos*) case $host_cpu in powerpc) lt_cv_sys_dlopen_deplibs=no ;; esac ;; darwin*) # Assuming the user has installed a libdl from somewhere, this is true # If you are looking for one http://www.opendarwin.org/projects/dlcompat lt_cv_sys_dlopen_deplibs=yes ;; freebsd* | dragonfly*) lt_cv_sys_dlopen_deplibs=yes ;; gnu* | linux* | k*bsd*-gnu | kopensolaris*-gnu) # GNU and its variants, using gnu ld.so (Glibc) lt_cv_sys_dlopen_deplibs=yes ;; hpux10*|hpux11*) lt_cv_sys_dlopen_deplibs=yes ;; interix*) lt_cv_sys_dlopen_deplibs=yes ;; irix[[12345]]*|irix6.[[01]]*) # Catch all versions of IRIX before 6.2, and indicate that we don't # know how it worked for any of those versions. lt_cv_sys_dlopen_deplibs=unknown ;; irix*) # The case above catches anything before 6.2, and it's known that # at 6.2 and later dlopen does load deplibs. lt_cv_sys_dlopen_deplibs=yes ;; netbsd* | netbsdelf*-gnu) lt_cv_sys_dlopen_deplibs=yes ;; openbsd*) lt_cv_sys_dlopen_deplibs=yes ;; osf[[1234]]*) # dlopen did load deplibs (at least at 4.x), but until the 5.x series, # it did *not* use an RPATH in a shared library to find objects the # library depends on, so we explicitly say `no'. lt_cv_sys_dlopen_deplibs=no ;; osf5.0|osf5.0a|osf5.1) # dlopen *does* load deplibs and with the right loader patch applied # it even uses RPATH in a shared library to search for shared objects # that the library depends on, but there's no easy way to know if that # patch is installed. Since this is the case, all we can really # say is unknown -- it depends on the patch being installed. If # it is, this changes to `yes'. Without it, it would be `no'. lt_cv_sys_dlopen_deplibs=unknown ;; osf*) # the two cases above should catch all versions of osf <= 5.1. Read # the comments above for what we know about them. # At > 5.1, deplibs are loaded *and* any RPATH in a shared library # is used to find them so we can finally say `yes'. lt_cv_sys_dlopen_deplibs=yes ;; qnx*) lt_cv_sys_dlopen_deplibs=yes ;; solaris*) lt_cv_sys_dlopen_deplibs=yes ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) libltdl_cv_sys_dlopen_deplibs=yes ;; esac ]) if test "$lt_cv_sys_dlopen_deplibs" != yes; then AC_DEFINE([LTDL_DLOPEN_DEPLIBS], [1], [Define if the OS needs help to load dependent libraries for dlopen().]) fi ])# LT_SYS_DLOPEN_DEPLIBS # Old name: AU_ALIAS([AC_LTDL_SYS_DLOPEN_DEPLIBS], [LT_SYS_DLOPEN_DEPLIBS]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LTDL_SYS_DLOPEN_DEPLIBS], []) # LT_SYS_MODULE_EXT # ----------------- AC_DEFUN([LT_SYS_MODULE_EXT], [m4_require([_LT_SYS_DYNAMIC_LINKER])dnl AC_CACHE_CHECK([which extension is used for runtime loadable modules], [libltdl_cv_shlibext], [ module=yes eval libltdl_cv_shlibext=$shrext_cmds ]) if test -n "$libltdl_cv_shlibext"; then m4_pattern_allow([LT_MODULE_EXT])dnl AC_DEFINE_UNQUOTED([LT_MODULE_EXT], ["$libltdl_cv_shlibext"], [Define to the extension used for runtime loadable modules, say, ".so".]) fi ])# LT_SYS_MODULE_EXT # Old name: AU_ALIAS([AC_LTDL_SHLIBEXT], [LT_SYS_MODULE_EXT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LTDL_SHLIBEXT], []) # LT_SYS_MODULE_PATH # ------------------ AC_DEFUN([LT_SYS_MODULE_PATH], [m4_require([_LT_SYS_DYNAMIC_LINKER])dnl AC_CACHE_CHECK([which variable specifies run-time module search path], [lt_cv_module_path_var], [lt_cv_module_path_var="$shlibpath_var"]) if test -n "$lt_cv_module_path_var"; then m4_pattern_allow([LT_MODULE_PATH_VAR])dnl AC_DEFINE_UNQUOTED([LT_MODULE_PATH_VAR], ["$lt_cv_module_path_var"], [Define to the name of the environment variable that determines the run-time module search path.]) fi ])# LT_SYS_MODULE_PATH # Old name: AU_ALIAS([AC_LTDL_SHLIBPATH], [LT_SYS_MODULE_PATH]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LTDL_SHLIBPATH], []) # LT_SYS_DLSEARCH_PATH # -------------------- AC_DEFUN([LT_SYS_DLSEARCH_PATH], [m4_require([_LT_SYS_DYNAMIC_LINKER])dnl AC_CACHE_CHECK([for the default library search path], [lt_cv_sys_dlsearch_path], [lt_cv_sys_dlsearch_path="$sys_lib_dlsearch_path_spec"]) if test -n "$lt_cv_sys_dlsearch_path"; then sys_dlsearch_path= for dir in $lt_cv_sys_dlsearch_path; do if test -z "$sys_dlsearch_path"; then sys_dlsearch_path="$dir" else sys_dlsearch_path="$sys_dlsearch_path$PATH_SEPARATOR$dir" fi done m4_pattern_allow([LT_DLSEARCH_PATH])dnl AC_DEFINE_UNQUOTED([LT_DLSEARCH_PATH], ["$sys_dlsearch_path"], [Define to the system default library search path.]) fi ])# LT_SYS_DLSEARCH_PATH # Old name: AU_ALIAS([AC_LTDL_SYSSEARCHPATH], [LT_SYS_DLSEARCH_PATH]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LTDL_SYSSEARCHPATH], []) # _LT_CHECK_DLPREOPEN # ------------------- m4_defun([_LT_CHECK_DLPREOPEN], [m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl AC_CACHE_CHECK([whether libtool supports -dlopen/-dlpreopen], [libltdl_cv_preloaded_symbols], [if test -n "$lt_cv_sys_global_symbol_pipe"; then libltdl_cv_preloaded_symbols=yes else libltdl_cv_preloaded_symbols=no fi ]) if test x"$libltdl_cv_preloaded_symbols" = xyes; then AC_DEFINE([HAVE_PRELOADED_SYMBOLS], [1], [Define if libtool can extract symbol lists from object files.]) fi ])# _LT_CHECK_DLPREOPEN # LT_LIB_DLLOAD # ------------- AC_DEFUN([LT_LIB_DLLOAD], [m4_pattern_allow([^LT_DLLOADERS$]) LT_DLLOADERS= AC_SUBST([LT_DLLOADERS]) AC_LANG_PUSH([C]) LIBADD_DLOPEN= AC_SEARCH_LIBS([dlopen], [dl], [AC_DEFINE([HAVE_LIBDL], [1], [Define if you have the libdl library or equivalent.]) if test "$ac_cv_search_dlopen" != "none required" ; then LIBADD_DLOPEN="-ldl" fi libltdl_cv_lib_dl_dlopen="yes" LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"], [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#if HAVE_DLFCN_H # include #endif ]], [[dlopen(0, 0);]])], [AC_DEFINE([HAVE_LIBDL], [1], [Define if you have the libdl library or equivalent.]) libltdl_cv_func_dlopen="yes" LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"], [AC_CHECK_LIB([svld], [dlopen], [AC_DEFINE([HAVE_LIBDL], [1], [Define if you have the libdl library or equivalent.]) LIBADD_DLOPEN="-lsvld" libltdl_cv_func_dlopen="yes" LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"])])]) if test x"$libltdl_cv_func_dlopen" = xyes || test x"$libltdl_cv_lib_dl_dlopen" = xyes then lt_save_LIBS="$LIBS" LIBS="$LIBS $LIBADD_DLOPEN" AC_CHECK_FUNCS([dlerror]) LIBS="$lt_save_LIBS" fi AC_SUBST([LIBADD_DLOPEN]) LIBADD_SHL_LOAD= AC_CHECK_FUNC([shl_load], [AC_DEFINE([HAVE_SHL_LOAD], [1], [Define if you have the shl_load function.]) LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la"], [AC_CHECK_LIB([dld], [shl_load], [AC_DEFINE([HAVE_SHL_LOAD], [1], [Define if you have the shl_load function.]) LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la" LIBADD_SHL_LOAD="-ldld"])]) AC_SUBST([LIBADD_SHL_LOAD]) case $host_os in darwin[[1567]].*) # We only want this for pre-Mac OS X 10.4. AC_CHECK_FUNC([_dyld_func_lookup], [AC_DEFINE([HAVE_DYLD], [1], [Define if you have the _dyld_func_lookup function.]) LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dyld.la"]) ;; beos*) LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}load_add_on.la" ;; cygwin* | mingw* | os2* | pw32*) AC_CHECK_DECLS([cygwin_conv_path], [], [], [[#include ]]) LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}loadlibrary.la" ;; esac AC_CHECK_LIB([dld], [dld_link], [AC_DEFINE([HAVE_DLD], [1], [Define if you have the GNU dld library.]) LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dld_link.la"]) AC_SUBST([LIBADD_DLD_LINK]) m4_pattern_allow([^LT_DLPREOPEN$]) LT_DLPREOPEN= if test -n "$LT_DLLOADERS" then for lt_loader in $LT_DLLOADERS; do LT_DLPREOPEN="$LT_DLPREOPEN-dlpreopen $lt_loader " done AC_DEFINE([HAVE_LIBDLLOADER], [1], [Define if libdlloader will be built on this platform]) fi AC_SUBST([LT_DLPREOPEN]) dnl This isn't used anymore, but set it for backwards compatibility LIBADD_DL="$LIBADD_DLOPEN $LIBADD_SHL_LOAD" AC_SUBST([LIBADD_DL]) AC_LANG_POP ])# LT_LIB_DLLOAD # Old name: AU_ALIAS([AC_LTDL_DLLIB], [LT_LIB_DLLOAD]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LTDL_DLLIB], []) # LT_SYS_SYMBOL_USCORE # -------------------- # does the compiler prefix global symbols with an underscore? AC_DEFUN([LT_SYS_SYMBOL_USCORE], [m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl AC_CACHE_CHECK([for _ prefix in compiled symbols], [lt_cv_sys_symbol_underscore], [lt_cv_sys_symbol_underscore=no cat > conftest.$ac_ext <<_LT_EOF void nm_test_func(){} int main(){nm_test_func;return 0;} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. ac_nlist=conftest.nm if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $ac_nlist) && test -s "$ac_nlist"; then # See whether the symbols have a leading underscore. if grep '^. _nm_test_func' "$ac_nlist" >/dev/null; then lt_cv_sys_symbol_underscore=yes else if grep '^. nm_test_func ' "$ac_nlist" >/dev/null; then : else echo "configure: cannot find nm_test_func in $ac_nlist" >&AS_MESSAGE_LOG_FD fi fi else echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "configure: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.c >&AS_MESSAGE_LOG_FD fi rm -rf conftest* ]) sys_symbol_underscore=$lt_cv_sys_symbol_underscore AC_SUBST([sys_symbol_underscore]) ])# LT_SYS_SYMBOL_USCORE # Old name: AU_ALIAS([AC_LTDL_SYMBOL_USCORE], [LT_SYS_SYMBOL_USCORE]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LTDL_SYMBOL_USCORE], []) # LT_FUNC_DLSYM_USCORE # -------------------- AC_DEFUN([LT_FUNC_DLSYM_USCORE], [AC_REQUIRE([LT_SYS_SYMBOL_USCORE])dnl if test x"$lt_cv_sys_symbol_underscore" = xyes; then if test x"$libltdl_cv_func_dlopen" = xyes || test x"$libltdl_cv_lib_dl_dlopen" = xyes ; then AC_CACHE_CHECK([whether we have to add an underscore for dlsym], [libltdl_cv_need_uscore], [libltdl_cv_need_uscore=unknown save_LIBS="$LIBS" LIBS="$LIBS $LIBADD_DLOPEN" _LT_TRY_DLOPEN_SELF( [libltdl_cv_need_uscore=no], [libltdl_cv_need_uscore=yes], [], [libltdl_cv_need_uscore=cross]) LIBS="$save_LIBS" ]) fi fi if test x"$libltdl_cv_need_uscore" = xyes; then AC_DEFINE([NEED_USCORE], [1], [Define if dlsym() requires a leading underscore in symbol names.]) fi ])# LT_FUNC_DLSYM_USCORE # Old name: AU_ALIAS([AC_LTDL_DLSYM_USCORE], [LT_FUNC_DLSYM_USCORE]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LTDL_DLSYM_USCORE], []) gnunet-0.9.3/m4/signed.m40000644000175000017500000000140111317762615012004 00000000000000# signed.m4 serial 1 (gettext-0.10.40) dnl Copyright (C) 2001-2002 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl From Bruno Haible. AC_DEFUN([bh_C_SIGNED], [ AC_CACHE_CHECK([for signed], bh_cv_c_signed, [AC_TRY_COMPILE(, [signed char x;], bh_cv_c_signed=yes, bh_cv_c_signed=no)]) if test $bh_cv_c_signed = no; then AC_DEFINE(signed, , [Define to empty if the C compiler doesn't support this keyword.]) fi ]) gnunet-0.9.3/m4/codeset.m40000644000175000017500000000136611317762540012170 00000000000000# codeset.m4 serial 2 (gettext-0.16) dnl Copyright (C) 2000-2002, 2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_DEFUN([AM_LANGINFO_CODESET], [ AC_CACHE_CHECK([for nl_langinfo and CODESET], am_cv_langinfo_codeset, [AC_TRY_LINK([#include ], [char* cs = nl_langinfo(CODESET); return !cs;], am_cv_langinfo_codeset=yes, am_cv_langinfo_codeset=no) ]) if test $am_cv_langinfo_codeset = yes; then AC_DEFINE(HAVE_LANGINFO_CODESET, 1, [Define if you have and nl_langinfo(CODESET).]) fi ]) gnunet-0.9.3/m4/lock.m40000644000175000017500000002770511317762540011477 00000000000000# lock.m4 serial 6 (gettext-0.16) dnl Copyright (C) 2005-2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl Tests for a multithreading library to be used. dnl Defines at most one of the macros USE_POSIX_THREADS, USE_SOLARIS_THREADS, dnl USE_PTH_THREADS, USE_WIN32_THREADS dnl Sets the variables LIBTHREAD and LTLIBTHREAD to the linker options for use dnl in a Makefile (LIBTHREAD for use without libtool, LTLIBTHREAD for use with dnl libtool). dnl Sets the variables LIBMULTITHREAD and LTLIBMULTITHREAD similarly, for dnl programs that really need multithread functionality. The difference dnl between LIBTHREAD and LIBMULTITHREAD is that on platforms supporting weak dnl symbols, typically LIBTHREAD="" whereas LIBMULTITHREAD="-lpthread". dnl Adds to CPPFLAGS the flag -D_REENTRANT or -D_THREAD_SAFE if needed for dnl multithread-safe programs. AC_DEFUN([gl_LOCK_EARLY], [ AC_REQUIRE([gl_LOCK_EARLY_BODY]) ]) dnl The guts of gl_LOCK_EARLY. Needs to be expanded only once. AC_DEFUN([gl_LOCK_EARLY_BODY], [ dnl Ordering constraints: This macro modifies CPPFLAGS in a way that dnl influences the result of the autoconf tests that test for *_unlocked dnl declarations, on AIX 5 at least. Therefore it must come early. AC_BEFORE([$0], [gl_FUNC_GLIBC_UNLOCKED_IO])dnl AC_BEFORE([$0], [gl_ARGP])dnl AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([AC_GNU_SOURCE]) dnl needed for pthread_rwlock_t on glibc systems dnl Check for multithreading. AC_ARG_ENABLE(threads, AC_HELP_STRING([--enable-threads={posix|solaris|pth|win32}], [specify multithreading API]) AC_HELP_STRING([--disable-threads], [build without multithread safety]), [gl_use_threads=$enableval], [case "$host_os" in dnl Disable multithreading by default on OSF/1, because it interferes dnl with fork()/exec(): When msgexec is linked with -lpthread, its child dnl process gets an endless segmentation fault inside execvp(). osf*) gl_use_threads=no ;; *) gl_use_threads=yes ;; esac ]) if test "$gl_use_threads" = yes || test "$gl_use_threads" = posix; then # For using : case "$host_os" in osf*) # On OSF/1, the compiler needs the flag -D_REENTRANT so that it # groks . cc also understands the flag -pthread, but # we don't use it because 1. gcc-2.95 doesn't understand -pthread, # 2. putting a flag into CPPFLAGS that has an effect on the linker # causes the AC_TRY_LINK test below to succeed unexpectedly, # leading to wrong values of LIBTHREAD and LTLIBTHREAD. CPPFLAGS="$CPPFLAGS -D_REENTRANT" ;; esac # Some systems optimize for single-threaded programs by default, and # need special flags to disable these optimizations. For example, the # definition of 'errno' in . case "$host_os" in aix* | freebsd*) CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE" ;; solaris*) CPPFLAGS="$CPPFLAGS -D_REENTRANT" ;; esac fi ]) dnl The guts of gl_LOCK. Needs to be expanded only once. AC_DEFUN([gl_LOCK_BODY], [ AC_REQUIRE([gl_LOCK_EARLY_BODY]) gl_threads_api=none LIBTHREAD= LTLIBTHREAD= LIBMULTITHREAD= LTLIBMULTITHREAD= if test "$gl_use_threads" != no; then dnl Check whether the compiler and linker support weak declarations. AC_MSG_CHECKING([whether imported symbols can be declared weak]) gl_have_weak=no AC_TRY_LINK([extern void xyzzy (); #pragma weak xyzzy], [xyzzy();], [gl_have_weak=yes]) AC_MSG_RESULT([$gl_have_weak]) if test "$gl_use_threads" = yes || test "$gl_use_threads" = posix; then # On OSF/1, the compiler needs the flag -pthread or -D_REENTRANT so that # it groks . It's added above, in gl_LOCK_EARLY_BODY. AC_CHECK_HEADER(pthread.h, gl_have_pthread_h=yes, gl_have_pthread_h=no) if test "$gl_have_pthread_h" = yes; then # Other possible tests: # -lpthreads (FSU threads, PCthreads) # -lgthreads gl_have_pthread= # Test whether both pthread_mutex_lock and pthread_mutexattr_init exist # in libc. IRIX 6.5 has the first one in both libc and libpthread, but # the second one only in libpthread, and lock.c needs it. AC_TRY_LINK([#include ], [pthread_mutex_lock((pthread_mutex_t*)0); pthread_mutexattr_init((pthread_mutexattr_t*)0);], [gl_have_pthread=yes]) # Test for libpthread by looking for pthread_kill. (Not pthread_self, # since it is defined as a macro on OSF/1.) if test -n "$gl_have_pthread"; then # The program links fine without libpthread. But it may actually # need to link with libpthread in order to create multiple threads. AC_CHECK_LIB(pthread, pthread_kill, [LIBMULTITHREAD=-lpthread LTLIBMULTITHREAD=-lpthread # On Solaris and HP-UX, most pthread functions exist also in libc. # Therefore pthread_in_use() needs to actually try to create a # thread: pthread_create from libc will fail, whereas # pthread_create will actually create a thread. case "$host_os" in solaris* | hpux*) AC_DEFINE([PTHREAD_IN_USE_DETECTION_HARD], 1, [Define if the pthread_in_use() detection is hard.]) esac ]) else # Some library is needed. Try libpthread and libc_r. AC_CHECK_LIB(pthread, pthread_kill, [gl_have_pthread=yes LIBTHREAD=-lpthread LTLIBTHREAD=-lpthread LIBMULTITHREAD=-lpthread LTLIBMULTITHREAD=-lpthread]) if test -z "$gl_have_pthread"; then # For FreeBSD 4. AC_CHECK_LIB(c_r, pthread_kill, [gl_have_pthread=yes LIBTHREAD=-lc_r LTLIBTHREAD=-lc_r LIBMULTITHREAD=-lc_r LTLIBMULTITHREAD=-lc_r]) fi fi if test -n "$gl_have_pthread"; then gl_threads_api=posix AC_DEFINE([USE_POSIX_THREADS], 1, [Define if the POSIX multithreading library can be used.]) if test -n "$LIBMULTITHREAD" || test -n "$LTLIBMULTITHREAD"; then if test $gl_have_weak = yes; then AC_DEFINE([USE_POSIX_THREADS_WEAK], 1, [Define if references to the POSIX multithreading library should be made weak.]) LIBTHREAD= LTLIBTHREAD= fi fi # OSF/1 4.0 and MacOS X 10.1 lack the pthread_rwlock_t type and the # pthread_rwlock_* functions. AC_CHECK_TYPE([pthread_rwlock_t], [AC_DEFINE([HAVE_PTHREAD_RWLOCK], 1, [Define if the POSIX multithreading library has read/write locks.])], [], [#include ]) # glibc defines PTHREAD_MUTEX_RECURSIVE as enum, not as a macro. AC_TRY_COMPILE([#include ], [#if __FreeBSD__ == 4 error "No, in FreeBSD 4.0 recursive mutexes actually don't work." #else int x = (int)PTHREAD_MUTEX_RECURSIVE; return !x; #endif], [AC_DEFINE([HAVE_PTHREAD_MUTEX_RECURSIVE], 1, [Define if the defines PTHREAD_MUTEX_RECURSIVE.])]) fi fi fi if test -z "$gl_have_pthread"; then if test "$gl_use_threads" = yes || test "$gl_use_threads" = solaris; then gl_have_solaristhread= gl_save_LIBS="$LIBS" LIBS="$LIBS -lthread" AC_TRY_LINK([#include #include ], [thr_self();], [gl_have_solaristhread=yes]) LIBS="$gl_save_LIBS" if test -n "$gl_have_solaristhread"; then gl_threads_api=solaris LIBTHREAD=-lthread LTLIBTHREAD=-lthread LIBMULTITHREAD="$LIBTHREAD" LTLIBMULTITHREAD="$LTLIBTHREAD" AC_DEFINE([USE_SOLARIS_THREADS], 1, [Define if the old Solaris multithreading library can be used.]) if test $gl_have_weak = yes; then AC_DEFINE([USE_SOLARIS_THREADS_WEAK], 1, [Define if references to the old Solaris multithreading library should be made weak.]) LIBTHREAD= LTLIBTHREAD= fi fi fi fi if test "$gl_use_threads" = pth; then gl_save_CPPFLAGS="$CPPFLAGS" AC_LIB_LINKFLAGS(pth) gl_have_pth= gl_save_LIBS="$LIBS" LIBS="$LIBS -lpth" AC_TRY_LINK([#include ], [pth_self();], gl_have_pth=yes) LIBS="$gl_save_LIBS" if test -n "$gl_have_pth"; then gl_threads_api=pth LIBTHREAD="$LIBPTH" LTLIBTHREAD="$LTLIBPTH" LIBMULTITHREAD="$LIBTHREAD" LTLIBMULTITHREAD="$LTLIBTHREAD" AC_DEFINE([USE_PTH_THREADS], 1, [Define if the GNU Pth multithreading library can be used.]) if test -n "$LIBMULTITHREAD" || test -n "$LTLIBMULTITHREAD"; then if test $gl_have_weak = yes; then AC_DEFINE([USE_PTH_THREADS_WEAK], 1, [Define if references to the GNU Pth multithreading library should be made weak.]) LIBTHREAD= LTLIBTHREAD= fi fi else CPPFLAGS="$gl_save_CPPFLAGS" fi fi if test -z "$gl_have_pthread"; then if test "$gl_use_threads" = yes || test "$gl_use_threads" = win32; then if { case "$host_os" in mingw*) true;; *) false;; esac }; then gl_threads_api=win32 AC_DEFINE([USE_WIN32_THREADS], 1, [Define if the Win32 multithreading API can be used.]) fi fi fi fi AC_MSG_CHECKING([for multithread API to use]) AC_MSG_RESULT([$gl_threads_api]) AC_SUBST(LIBTHREAD) AC_SUBST(LTLIBTHREAD) AC_SUBST(LIBMULTITHREAD) AC_SUBST(LTLIBMULTITHREAD) ]) AC_DEFUN([gl_LOCK], [ AC_REQUIRE([gl_LOCK_EARLY]) AC_REQUIRE([gl_LOCK_BODY]) gl_PREREQ_LOCK ]) # Prerequisites of lib/lock.c. AC_DEFUN([gl_PREREQ_LOCK], [ AC_REQUIRE([AC_C_INLINE]) ]) dnl Survey of platforms: dnl dnl Platform Available Compiler Supports test-lock dnl flavours option weak result dnl --------------- --------- --------- -------- --------- dnl Linux 2.4/glibc posix -lpthread Y OK dnl dnl GNU Hurd/glibc posix dnl dnl FreeBSD 5.3 posix -lc_r Y dnl posix -lkse ? Y dnl posix -lpthread ? Y dnl posix -lthr Y dnl dnl FreeBSD 5.2 posix -lc_r Y dnl posix -lkse Y dnl posix -lthr Y dnl dnl FreeBSD 4.0,4.10 posix -lc_r Y OK dnl dnl NetBSD 1.6 -- dnl dnl OpenBSD 3.4 posix -lpthread Y OK dnl dnl MacOS X 10.[123] posix -lpthread Y OK dnl dnl Solaris 7,8,9 posix -lpthread Y Sol 7,8: 0.0; Sol 9: OK dnl solaris -lthread Y Sol 7,8: 0.0; Sol 9: OK dnl dnl HP-UX 11 posix -lpthread N (cc) OK dnl Y (gcc) dnl dnl IRIX 6.5 posix -lpthread Y 0.5 dnl dnl AIX 4.3,5.1 posix -lpthread N AIX 4: 0.5; AIX 5: OK dnl dnl OSF/1 4.0,5.1 posix -pthread (cc) N OK dnl -lpthread (gcc) Y dnl dnl Cygwin posix -lpthread Y OK dnl dnl Any of the above pth -lpth 0.0 dnl dnl Mingw win32 N OK dnl dnl BeOS 5 -- dnl dnl The test-lock result shows what happens if in test-lock.c EXPLICIT_YIELD is dnl turned off: dnl OK if all three tests terminate OK, dnl 0.5 if the first test terminates OK but the second one loops endlessly, dnl 0.0 if the first test already loops endlessly. gnunet-0.9.3/m4/uintmax_t.m40000644000175000017500000000207611317762540012551 00000000000000# uintmax_t.m4 serial 9 dnl Copyright (C) 1997-2004 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Paul Eggert. AC_PREREQ(2.13) # Define uintmax_t to 'unsigned long' or 'unsigned long long' # if it is not already defined in or . AC_DEFUN([gl_AC_TYPE_UINTMAX_T], [ AC_REQUIRE([gl_AC_HEADER_INTTYPES_H]) AC_REQUIRE([gl_AC_HEADER_STDINT_H]) if test $gl_cv_header_inttypes_h = no && test $gl_cv_header_stdint_h = no; then AC_REQUIRE([gl_AC_TYPE_UNSIGNED_LONG_LONG]) test $ac_cv_type_unsigned_long_long = yes \ && ac_type='unsigned long long' \ || ac_type='unsigned long' AC_DEFINE_UNQUOTED(uintmax_t, $ac_type, [Define to unsigned long or unsigned long long if and don't define.]) else AC_DEFINE(HAVE_UINTMAX_T, 1, [Define if you have the 'uintmax_t' type in or .]) fi ]) gnunet-0.9.3/m4/xsize.m40000644000175000017500000000064511317762540011703 00000000000000# xsize.m4 serial 3 dnl Copyright (C) 2003-2004 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. AC_DEFUN([gl_XSIZE], [ dnl Prerequisites of lib/xsize.h. AC_REQUIRE([gl_SIZE_MAX]) AC_REQUIRE([AC_C_INLINE]) AC_CHECK_HEADERS(stdint.h) ]) gnunet-0.9.3/m4/visibility.m40000644000175000017500000000413011317762540012721 00000000000000# visibility.m4 serial 1 (gettext-0.15) dnl Copyright (C) 2005 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl Tests whether the compiler supports the command-line option dnl -fvisibility=hidden and the function and variable attributes dnl __attribute__((__visibility__("hidden"))) and dnl __attribute__((__visibility__("default"))). dnl Does *not* test for __visibility__("protected") - which has tricky dnl semantics (see the 'vismain' test in glibc) and does not exist e.g. on dnl MacOS X. dnl Does *not* test for __visibility__("internal") - which has processor dnl dependent semantics. dnl Does *not* test for #pragma GCC visibility push(hidden) - which is dnl "really only recommended for legacy code". dnl Set the variable CFLAG_VISIBILITY. dnl Defines and sets the variable HAVE_VISIBILITY. AC_DEFUN([gl_VISIBILITY], [ AC_REQUIRE([AC_PROG_CC]) CFLAG_VISIBILITY= HAVE_VISIBILITY=0 if test -n "$GCC"; then AC_MSG_CHECKING([for simple visibility declarations]) AC_CACHE_VAL(gl_cv_cc_visibility, [ gl_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fvisibility=hidden" AC_TRY_COMPILE( [extern __attribute__((__visibility__("hidden"))) int hiddenvar; extern __attribute__((__visibility__("default"))) int exportedvar; extern __attribute__((__visibility__("hidden"))) int hiddenfunc (void); extern __attribute__((__visibility__("default"))) int exportedfunc (void);], [], gl_cv_cc_visibility=yes, gl_cv_cc_visibility=no) CFLAGS="$gl_save_CFLAGS"]) AC_MSG_RESULT([$gl_cv_cc_visibility]) if test $gl_cv_cc_visibility = yes; then CFLAG_VISIBILITY="-fvisibility=hidden" HAVE_VISIBILITY=1 fi fi AC_SUBST([CFLAG_VISIBILITY]) AC_SUBST([HAVE_VISIBILITY]) AC_DEFINE_UNQUOTED([HAVE_VISIBILITY], [$HAVE_VISIBILITY], [Define to 1 or 0, depending whether the compiler supports simple visibility declarations.]) ]) gnunet-0.9.3/m4/libtool.m40000644000175000017500000077464711762217203012224 00000000000000# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008 Free Software Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. m4_define([_LT_COPYING], [dnl # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008 Free Software Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ]) # serial 56 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_CC_BASENAME(CC) # ------------------- # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. m4_defun([_LT_CC_BASENAME], [for cc_temp in $1""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl _LT_PROG_ECHO_BACKSLASH case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from `configure', and `config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # `config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain="$ac_aux_dir/ltmain.sh" ])# _LT_PROG_LTMAIN ## ------------------------------------- ## ## Accumulate code for creating libtool. ## ## ------------------------------------- ## # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the `libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) ## ------------------------ ## ## FIXME: Eliminate VARNAME ## ## ------------------------ ## # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to `config.status' so that its # declaration there will have the same value as in `configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "X$][$1" | $Xsed -e "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "X$" | $Xsed -e "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags="_LT_TAGS"dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the `libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into `config.status', and then the shell code to quote escape them in # for loops in `config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Fix-up fallback echo if it was mangled by the above quoting rules. case \$lt_ECHO in *'\\\[$]0 --fallback-echo"')dnl " lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\[$]0 --fallback-echo"\[$]/\[$]0 --fallback-echo"/'\` ;; esac _LT_OUTPUT_LIBTOOL_INIT ]) # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) cat >"$CONFIG_LT" <<_LTEOF #! $SHELL # Generated by $as_me. # Run this file to recreate a libtool stub with the current configuration. lt_cl_silent=false SHELL=\${CONFIG_SHELL-$SHELL} _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ \`$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2008 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test $[#] != 0 do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try \`$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try \`$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. if test "$no_create" != yes; then lt_cl_success=: test "$silent" = yes && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) fi ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # _LT_COPYING _LT_LIBTOOL_TAGS # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) _LT_PROG_XSI_SHELLFNS sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS="$save_LDFLAGS" ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[[012]]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES # -------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(whole_archive_flag_spec, $1)='' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=echo _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" m4_if([$1], [CXX], [ if test "$lt_cv_apple_cc_single_mod" != "yes"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX # ----------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl AC_LINK_IFELSE(AC_LANG_PROGRAM,[ lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/ p } }' aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [ifdef([AC_DIVERSION_NOTICE], [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], [AC_DIVERT_PUSH(NOTICE)]) $1 AC_DIVERT_POP ])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Add some code to the start of the generated configure script which # will find an echo command which doesn't interpret backslashes. m4_defun([_LT_PROG_ECHO_BACKSLASH], [_LT_SHELL_INIT([ # Check that we are running under the correct shell. SHELL=${CONFIG_SHELL-/bin/sh} case X$lt_ECHO in X*--fallback-echo) # Remove one level of quotation (which was required for Make). ECHO=`echo "$lt_ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` ;; esac ECHO=${lt_ECHO-echo} if test "X[$]1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X[$]1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then # Yippee, $ECHO works! : else # Restart under the correct shell. exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} fi if test "X[$]1" = X--fallback-echo; then # used as fallback echo shift cat <<_LT_EOF [$]* _LT_EOF exit 0 fi # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test -z "$lt_ECHO"; then if test "X${echo_test_string+set}" != Xset; then # find a string as large as possible, as long as the shell can cope with it for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... if { echo_test_string=`eval $cmd`; } 2>/dev/null && { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null then break fi done fi if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then : else # The Solaris, AIX, and Digital Unix default echo programs unquote # backslashes. This makes it impossible to quote backslashes using # echo "$something" | sed 's/\\/\\\\/g' # # So, first we look for a working echo in the user's PATH. lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for dir in $PATH /usr/ucb; do IFS="$lt_save_ifs" if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then ECHO="$dir/echo" break fi done IFS="$lt_save_ifs" if test "X$ECHO" = Xecho; then # We didn't find a better echo, so look for alternatives. if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # This shell has a builtin print -r that does the trick. ECHO='print -r' elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && test "X$CONFIG_SHELL" != X/bin/ksh; then # If we have ksh, try running configure again with it. ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} export ORIGINAL_CONFIG_SHELL CONFIG_SHELL=/bin/ksh export CONFIG_SHELL exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} else # Try using printf. ECHO='printf %s\n' if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # Cool, printf works : elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL export CONFIG_SHELL SHELL="$CONFIG_SHELL" export SHELL ECHO="$CONFIG_SHELL [$]0 --fallback-echo" elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then ECHO="$CONFIG_SHELL [$]0 --fallback-echo" else # maybe with a smaller string... prev=: for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null then break fi prev="$cmd" done if test "$prev" != 'sed 50q "[$]0"'; then echo_test_string=`eval $prev` export echo_test_string exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} else # Oops. We lost completely, so just stick with echo. ECHO=echo fi fi fi fi fi fi # Copy echo and quote the copy suitably for passing to libtool from # the Makefile, instead of quoting the original, which is used later. lt_ECHO=$ECHO if test "X$lt_ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then lt_ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" fi AC_SUBST(lt_ECHO) ]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that does not interpret backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '[#]line __oline__ "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; sparc*-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) LD="${LD-ld} -m elf64_sparc" ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" ])# _LT_ENABLE_LOCK # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [AC_CHECK_TOOL(AR, ar, false) test -z "$AR" && AR=ar test -z "$AR_FLAGS" && AR_FLAGS=cru _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1]) AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" fi _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test x"[$]$2" = xyes; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" ]) if test x"[$]$2" = xyes; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ = "XX$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n $lt_cv_sys_max_cmd_len ; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "$cross_compiling" = yes; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line __oline__ "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen="shl_load"], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen="dlopen"], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) ]) ]) ]) ]) ]) ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links="nottested" if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test "$hard_links" = no; then AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", [Define to the sub-directory in which libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then # We can hardcode non-existent directories. if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` else lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[[4-9]]*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[123]]*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; interix[[3-9]]*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[[89]] | openbsd2.[[89]].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([], [sys_lib_dlsearch_path_spec], [2], [Run-time system search path for libraries]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program which can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$1; then lt_cv_path_MAGIC_CMD="$ac_dir/$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac]) MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program which can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be Linux ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method == "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi]) if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :) AC_SUBST([DUMPBIN]) if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:__oline__: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:__oline__: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:__oline__: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM="-lm") ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test "$GCC" = yes; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ const struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_save_LIBS="$LIBS" lt_save_CFLAGS="$CFLAGS" LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS="$lt_save_LIBS" CFLAGS="$lt_save_CFLAGS" else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= AC_MSG_CHECKING([for $compiler option to produce PIC]) m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64 which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC*) # IBM XL 8.0 on PPC _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test "$GCC" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; pgcc* | pgf77* | pgf90* | pgf95*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl*) # IBM XL C 8.0/Fortran 10.1 on PPC _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Sun\ F*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" ;; cygwin* | mingw* | cegcc*) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' ;; linux* | k*bsd*-gnu) _LT_TAGVAR(link_all_deplibs, $1)=no ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; linux* | k*bsd*-gnu) _LT_TAGVAR(link_all_deplibs, $1)=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes if test "$with_gnu_ld" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.9.1, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to modify your PATH *** so that a non-GNU linker is found, and then restart. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag= tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; xl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi _LT_TAGVAR(link_all_deplibs, $1)=no else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; freebsd1*) _LT_TAGVAR(ld_shlibs, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; hpux10*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" AC_LINK_IFELSE(int foo(void) {}, _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' ) LDFLAGS="$save_LDFLAGS" else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' else case $host_os in openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' ;; esac fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_MSG_CHECKING([whether -lc should be explicitly linked in]) $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then _LT_TAGVAR(archive_cmds_need_lc, $1)=no else _LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* AC_MSG_RESULT([$_LT_TAGVAR(archive_cmds_need_lc, $1)]) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1], [[If ld is used when linking, flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting ${shlibpath_var} if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [fix_srcfile_path], [1], [Fix the shell variable $srcfile for the compiler]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC="$CC" AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report which library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC="$lt_save_CC" ])# _LT_LANG_C_CONFIG # _LT_PROG_CXX # ------------ # Since AC_PROG_CXX is broken, in that it returns g++ if there is no c++ # compiler, we have our own version here. m4_defun([_LT_PROG_CXX], [ pushdef([AC_MSG_ERROR], [_lt_caught_CXX_error=yes]) AC_PROG_CXX if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi popdef([AC_MSG_ERROR]) ])# _LT_PROG_CXX dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([_LT_PROG_CXX], []) # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [AC_REQUIRE([_LT_PROG_CXX])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_caught_CXX_error" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GXX" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared # libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd[[12]]*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; gnu*) ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; *) if test "$GXX" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]]* | *pgcpp\ [[1-5]]*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; *) # Version 6 will use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; xl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='echo' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd2*) # C++ shared libraries are fairly broken _LT_TAGVAR(ld_shlibs, $1)=no ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd=echo else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='echo' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(GCC, $1)="$GXX" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test "$_lt_caught_CXX_error" != yes AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ]) dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case $p in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" || test $p = "-R"; then prev=$p continue else prev= fi if test "$pre_test_object_deps_done" = no; then case $p in -L* | -R*) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)="${prev}${p}" else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" fi fi ;; *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)="$p" else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)="$p" else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_PROG_F77 # ------------ # Since AC_PROG_F77 is broken, in that it returns the empty string # if there is no fortran compiler, we have our own version here. m4_defun([_LT_PROG_F77], [ pushdef([AC_MSG_ERROR], [_lt_disable_F77=yes]) AC_PROG_F77 if test -z "$F77" || test "X$F77" = "Xno"; then _lt_disable_F77=yes fi popdef([AC_MSG_ERROR]) ])# _LT_PROG_F77 dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([_LT_PROG_F77], []) # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_REQUIRE([_LT_PROG_F77])dnl AC_LANG_PUSH(Fortran 77) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_F77" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC CC=${F77-"f77"} compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$G77" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC="$lt_save_CC" fi # test "$_lt_disable_F77" != yes AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_PROG_FC # ----------- # Since AC_PROG_FC is broken, in that it returns the empty string # if there is no fortran compiler, we have our own version here. m4_defun([_LT_PROG_FC], [ pushdef([AC_MSG_ERROR], [_lt_disable_FC=yes]) AC_PROG_FC if test -z "$FC" || test "X$FC" = "Xno"; then _lt_disable_FC=yes fi popdef([AC_MSG_ERROR]) ])# _LT_PROG_FC dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([_LT_PROG_FC], []) # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_REQUIRE([_LT_PROG_FC])dnl AC_LANG_PUSH(Fortran) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_FC" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC CC=${FC-"f95"} compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC="$lt_save_CC" fi # test "$_lt_disable_FC" != yes AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC="$lt_save_CC" ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code="$lt_simple_compile_test_code" # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC GCC= CC=${RC-"windres"} compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC="$lt_save_CC" ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [AC_MSG_CHECKING([whether the shell understands some XSI constructs]) # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes AC_MSG_RESULT([$xsi_shell]) _LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) AC_MSG_CHECKING([whether the shell understands "+="]) lt_shell_append=no ( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes AC_MSG_RESULT([$lt_shell_append]) _LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PROG_XSI_SHELLFNS # --------------------- # Bourne and XSI compatible variants of some useful shell functions. m4_defun([_LT_PROG_XSI_SHELLFNS], [case $xsi_shell in yes) cat << \_LT_EOF >> "$cfgfile" # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac } # func_basename file func_basename () { func_basename_result="${1##*/}" } # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac func_basename_result="${1##*/}" } # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). func_stripname () { # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary parameter first. func_stripname_result=${3} func_stripname_result=${func_stripname_result#"${1}"} func_stripname_result=${func_stripname_result%"${2}"} } # func_opt_split func_opt_split () { func_opt_split_opt=${1%%=*} func_opt_split_arg=${1#*=} } # func_lo2o object func_lo2o () { case ${1} in *.lo) func_lo2o_result=${1%.lo}.${objext} ;; *) func_lo2o_result=${1} ;; esac } # func_xform libobj-or-source func_xform () { func_xform_result=${1%.*}.lo } # func_arith arithmetic-term... func_arith () { func_arith_result=$(( $[*] )) } # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=${#1} } _LT_EOF ;; *) # Bourne compatible functions. cat << \_LT_EOF >> "$cfgfile" # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi } # func_basename file func_basename () { func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` } dnl func_dirname_and_basename dnl A portable version of this function is already defined in general.m4sh dnl so there is no need for it here. # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # func_strip_suffix prefix name func_stripname () { case ${2} in .*) func_stripname_result=`$ECHO "X${3}" \ | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "X${3}" \ | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; esac } # sed scripts: my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q' my_sed_long_arg='1s/^-[[^=]]*=//' # func_opt_split func_opt_split () { func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` } # func_lo2o object func_lo2o () { func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` } # func_xform libobj-or-source func_xform () { func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[[^.]]*$/.lo/'` } # func_arith arithmetic-term... func_arith () { func_arith_result=`expr "$[@]"` } # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len` } _LT_EOF esac case $lt_shell_append in yes) cat << \_LT_EOF >> "$cfgfile" # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "$[1]+=\$[2]" } _LT_EOF ;; *) cat << \_LT_EOF >> "$cfgfile" # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "$[1]=\$$[1]\$[2]" } _LT_EOF ;; esac ]) gnunet-0.9.3/m4/wint_t.m40000644000175000017500000000130411317762540012036 00000000000000# wint_t.m4 serial 1 (gettext-0.12) dnl Copyright (C) 2003 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl Test whether has the 'wint_t' type. dnl Prerequisite: AC_PROG_CC AC_DEFUN([gt_TYPE_WINT_T], [ AC_CACHE_CHECK([for wint_t], gt_cv_c_wint_t, [AC_TRY_COMPILE([#include wint_t foo = (wchar_t)'\0';], , gt_cv_c_wint_t=yes, gt_cv_c_wint_t=no)]) if test $gt_cv_c_wint_t = yes; then AC_DEFINE(HAVE_WINT_T, 1, [Define if you have the 'wint_t' type.]) fi ]) gnunet-0.9.3/m4/gnulib-cache.m40000644000175000017500000000240411530550037013046 00000000000000# Copyright (C) 2002-2011 Free Software Foundation, Inc. # # This file is free software, distributed under the terms of the GNU # General Public License. As a special exception to the GNU General # Public License, this file may be distributed as part of a program # that contains a configuration script generated by Autoconf, under # the same distribution terms as the rest of that program. # # Generated by gnulib-tool. # # This file represents the specification of how gnulib-tool is used. # It acts as a cache: It is written and read by gnulib-tool. # In projects that use version control, this file is meant to be put under # version control, like the configure.ac and various Makefile.am files. # Specification in the form of a command-line invocation: # gnulib-tool --import --dir=/home/nils/workspace/gnunet --lib=libgnu --source-base=src/util/libgnu --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=. --libtool --macro-prefix=gl strtok_r # Specification in the form of a few gnulib-tool.m4 macro invocations: gl_LOCAL_DIR([]) gl_MODULES([ strtok_r ]) gl_AVOID([]) gl_SOURCE_BASE([src/util/libgnu]) gl_M4_BASE([m4]) gl_PO_BASE([]) gl_DOC_BASE([doc]) gl_TESTS_BASE([tests]) gl_LIB([libgnu]) gl_MAKEFILE_NAME([]) gl_LIBTOOL gl_MACRO_PREFIX([gl]) gl_PO_DOMAIN([]) gnunet-0.9.3/m4/size_max.m40000644000175000017500000000461011317762540012354 00000000000000# size_max.m4 serial 5 dnl Copyright (C) 2003, 2005-2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_DEFUN([gl_SIZE_MAX], [ AC_CHECK_HEADERS(stdint.h) dnl First test whether the system already has SIZE_MAX. AC_MSG_CHECKING([for SIZE_MAX]) AC_CACHE_VAL([gl_cv_size_max], [ gl_cv_size_max= AC_EGREP_CPP([Found it], [ #include #if HAVE_STDINT_H #include #endif #ifdef SIZE_MAX Found it #endif ], gl_cv_size_max=yes) if test -z "$gl_cv_size_max"; then dnl Define it ourselves. Here we assume that the type 'size_t' is not wider dnl than the type 'unsigned long'. Try hard to find a definition that can dnl be used in a preprocessor #if, i.e. doesn't contain a cast. _AC_COMPUTE_INT([sizeof (size_t) * CHAR_BIT - 1], size_t_bits_minus_1, [#include #include ], size_t_bits_minus_1=) _AC_COMPUTE_INT([sizeof (size_t) <= sizeof (unsigned int)], fits_in_uint, [#include ], fits_in_uint=) if test -n "$size_t_bits_minus_1" && test -n "$fits_in_uint"; then if test $fits_in_uint = 1; then dnl Even though SIZE_MAX fits in an unsigned int, it must be of type dnl 'unsigned long' if the type 'size_t' is the same as 'unsigned long'. AC_TRY_COMPILE([#include extern size_t foo; extern unsigned long foo; ], [], fits_in_uint=0) fi dnl We cannot use 'expr' to simplify this expression, because 'expr' dnl works only with 'long' integers in the host environment, while we dnl might be cross-compiling from a 32-bit platform to a 64-bit platform. if test $fits_in_uint = 1; then gl_cv_size_max="(((1U << $size_t_bits_minus_1) - 1) * 2 + 1)" else gl_cv_size_max="(((1UL << $size_t_bits_minus_1) - 1) * 2 + 1)" fi else dnl Shouldn't happen, but who knows... gl_cv_size_max='((size_t)~(size_t)0)' fi fi ]) AC_MSG_RESULT([$gl_cv_size_max]) if test "$gl_cv_size_max" != yes; then AC_DEFINE_UNQUOTED([SIZE_MAX], [$gl_cv_size_max], [Define as the maximum value of type 'size_t', if the system doesn't define it.]) fi ]) gnunet-0.9.3/m4/glibc2.m40000644000175000017500000000135411317762540011701 00000000000000# glibc2.m4 serial 1 dnl Copyright (C) 2000-2002, 2004 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. # Test for the GNU C Library, version 2.0 or newer. # From Bruno Haible. AC_DEFUN([gt_GLIBC2], [ AC_CACHE_CHECK(whether we are using the GNU C Library 2 or newer, ac_cv_gnu_library_2, [AC_EGREP_CPP([Lucky GNU user], [ #include #ifdef __GNU_LIBRARY__ #if (__GLIBC__ >= 2) Lucky GNU user #endif #endif ], ac_cv_gnu_library_2=yes, ac_cv_gnu_library_2=no) ] ) AC_SUBST(GLIBC2) GLIBC2="$ac_cv_gnu_library_2" ] ) gnunet-0.9.3/m4/intldir.m40000644000175000017500000000161611317762540012205 00000000000000# intldir.m4 serial 1 (gettext-0.16) dnl Copyright (C) 2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. AC_PREREQ(2.52) dnl Tells the AM_GNU_GETTEXT macro to consider an intl/ directory. AC_DEFUN([AM_GNU_GETTEXT_INTL_SUBDIR], []) gnunet-0.9.3/m4/align.m40000644000175000017500000000246711634323401011626 00000000000000# align.m4 dnl Copyright (C) 2008 Christian Grothoff dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. # Define HAVE_UNALIGNED_64_ACCESS if reading a 64-bit value at a 32-bit aligned offset works # Note that the program intentionally causes a SIGBUS (so you may # see some message along those lines on the console). AC_DEFUN([AC_UNALIGNED_64_ACCESS], [AC_CACHE_CHECK([whether unaligned 64-bit access works], ac_cv_unaligned_64_access, [ AC_RUN_IFELSE(AC_LANG_PROGRAM([[struct S { int a,b,c;};]], [[struct S s = {0,0,0}; long long * p = (long long *) &s.b; void *bp = malloc (50); long long x = *p; long long *be = (long long*) &bp[1]; long long y = *be; return (int) x*y;]]), ac_cv_unaligned_64_access=yes, ac_cv_unaligned_64_access=no, ac_cv_unaligned_64_access=no) ]) case "$ac_cv_unaligned_64_access" in *yes) value=1;; *) value=0;; esac AC_DEFINE_UNQUOTED([HAVE_UNALIGNED_64_ACCESS], $value, [We can access-64 bit values that are only 32-bit aligned]) ]) gnunet-0.9.3/m4/glib-gettext.m40000644000175000017500000002724711317762615013152 00000000000000# Copyright (C) 1995-2002 Free Software Foundation, Inc. # Copyright (C) 2001-2003 Red Hat, Inc. # # This file is free software, distributed under the terms of the GNU # General Public License. As a special exception to the GNU General # Public License, this file may be distributed as part of a program # that contains a configuration script generated by Autoconf, under # the same distribution terms as the rest of that program. # # This file can be copied and used freely without restrictions. It can # be used in projects which are not available under the GNU Public License # but which still want to provide support for the GNU gettext functionality. # # Macro to add for using GNU gettext. # Ulrich Drepper , 1995, 1996 # # Modified to never use included libintl. # Owen Taylor , 12/15/1998 # # Major rework to remove unused code # Owen Taylor , 12/11/2002 # # Added better handling of ALL_LINGUAS from GNU gettext version # written by Bruno Haible, Owen Taylor 5/30/3002 # # We need this here as well, since someone might use autoconf-2.5x # to configure GLib then an older version to configure a package # using AM_GLIB_GNU_GETTEXT AC_PREREQ(2.53) dnl dnl We go to great lengths to make sure that aclocal won't dnl try to pull in the installed version of these macros dnl when running aclocal in the glib directory. dnl m4_copy([AC_DEFUN],[glib_DEFUN]) m4_copy([AC_REQUIRE],[glib_REQUIRE]) dnl dnl At the end, if we're not within glib, we'll define the public dnl definitions in terms of our private definitions. dnl # GLIB_LC_MESSAGES #-------------------- glib_DEFUN([GLIB_LC_MESSAGES], [AC_CHECK_HEADERS([locale.h]) if test $ac_cv_header_locale_h = yes; then AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES, [AC_TRY_LINK([#include ], [return LC_MESSAGES], am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)]) if test $am_cv_val_LC_MESSAGES = yes; then AC_DEFINE(HAVE_LC_MESSAGES, 1, [Define if your file defines LC_MESSAGES.]) fi fi]) # GLIB_PATH_PROG_WITH_TEST #---------------------------- dnl GLIB_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) glib_DEFUN([GLIB_PATH_PROG_WITH_TEST], [# Extract the first word of "$2", so it can be a program name with args. set dummy $2; ac_word=[$]2 AC_MSG_CHECKING([for $ac_word]) AC_CACHE_VAL(ac_cv_path_$1, [case "[$]$1" in /*) ac_cv_path_$1="[$]$1" # Let the user override the test with a path. ;; *) IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" for ac_dir in ifelse([$5], , $PATH, [$5]); do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then if [$3]; then ac_cv_path_$1="$ac_dir/$ac_word" break fi fi done IFS="$ac_save_ifs" dnl If no 4th arg is given, leave the cache variable unset, dnl so AC_PATH_PROGS will keep looking. ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" ])dnl ;; esac])dnl $1="$ac_cv_path_$1" if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then AC_MSG_RESULT([$]$1) else AC_MSG_RESULT(no) fi AC_SUBST($1)dnl ]) # GLIB_WITH_NLS #----------------- glib_DEFUN([GLIB_WITH_NLS], dnl NLS is obligatory [USE_NLS=yes AC_SUBST(USE_NLS) gt_cv_have_gettext=no CATOBJEXT=NONE XGETTEXT=: INTLLIBS= AC_CHECK_HEADER(libintl.h, [gt_cv_func_dgettext_libintl="no" libintl_extra_libs="" # # First check in libc # AC_CACHE_CHECK([for dgettext in libc], gt_cv_func_dgettext_libc, [AC_TRY_LINK([ #include ], [return (int) dgettext ("","")], gt_cv_func_dgettext_libc=yes, gt_cv_func_dgettext_libc=no) ]) if test "$gt_cv_func_dgettext_libc" = "yes" ; then AC_CHECK_FUNCS(bind_textdomain_codeset) fi # # If we don't have everything we want, check in libintl # if test "$gt_cv_func_dgettext_libc" != "yes" \ || test "$ac_cv_func_bind_textdomain_codeset" != "yes" ; then AC_CHECK_LIB(intl, bindtextdomain, [AC_CHECK_LIB(intl, dgettext, gt_cv_func_dgettext_libintl=yes)]) if test "$gt_cv_func_dgettext_libintl" != "yes" ; then AC_MSG_CHECKING([if -liconv is needed to use gettext]) AC_MSG_RESULT([]) AC_CHECK_LIB(intl, dcgettext, [gt_cv_func_dgettext_libintl=yes libintl_extra_libs=-liconv], :,-liconv) fi # # If we found libintl, then check in it for bind_textdomain_codeset(); # we'll prefer libc if neither have bind_textdomain_codeset(), # and both have dgettext # if test "$gt_cv_func_dgettext_libintl" = "yes" ; then glib_save_LIBS="$LIBS" LIBS="$LIBS -lintl $libintl_extra_libs" unset ac_cv_func_bind_textdomain_codeset AC_CHECK_FUNCS(bind_textdomain_codeset) LIBS="$glib_save_LIBS" if test "$ac_cv_func_bind_textdomain_codeset" = "yes" ; then gt_cv_func_dgettext_libc=no else if test "$gt_cv_func_dgettext_libc" = "yes"; then gt_cv_func_dgettext_libintl=no fi fi fi fi if test "$gt_cv_func_dgettext_libc" = "yes" \ || test "$gt_cv_func_dgettext_libintl" = "yes"; then gt_cv_have_gettext=yes fi if test "$gt_cv_func_dgettext_libintl" = "yes"; then INTLLIBS="-lintl $libintl_extra_libs" fi if test "$gt_cv_have_gettext" = "yes"; then AC_DEFINE(HAVE_GETTEXT,1, [Define if the GNU gettext() function is already present or preinstalled.]) GLIB_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], no)dnl if test "$MSGFMT" != "no"; then glib_save_LIBS="$LIBS" LIBS="$LIBS $INTLLIBS" AC_CHECK_FUNCS(dcgettext) AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) GLIB_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) AC_TRY_LINK(, [extern int _nl_msg_cat_cntr; return _nl_msg_cat_cntr], [CATOBJEXT=.gmo DATADIRNAME=share], [case $host in *-*-solaris*) dnl On Solaris, if bind_textdomain_codeset is in libc, dnl GNU format message catalog is always supported, dnl since both are added to the libc all together. dnl Hence, we'd like to go with DATADIRNAME=share and dnl and CATOBJEXT=.gmo in this case. AC_CHECK_FUNC(bind_textdomain_codeset, [CATOBJEXT=.gmo DATADIRNAME=share], [CATOBJEXT=.mo DATADIRNAME=lib]) ;; *) CATOBJEXT=.mo DATADIRNAME=lib ;; esac]) LIBS="$glib_save_LIBS" INSTOBJEXT=.mo else gt_cv_have_gettext=no fi fi ]) if test "$gt_cv_have_gettext" = "yes" ; then AC_DEFINE(ENABLE_NLS, 1, [always defined to indicate that i18n is enabled]) fi dnl Test whether we really found GNU xgettext. if test "$XGETTEXT" != ":"; then dnl If it is not GNU xgettext we define it as : so that the dnl Makefiles still can work. if $XGETTEXT --omit-header /dev/null 2> /dev/null; then : ; else AC_MSG_RESULT( [found xgettext program is not GNU xgettext; ignore it]) XGETTEXT=":" fi fi # We need to process the po/ directory. POSUB=po AC_OUTPUT_COMMANDS( [case "$CONFIG_FILES" in *po/Makefile.in*) sed -e "/POTFILES =/r po/POTFILES" po/Makefile.in > po/Makefile esac]) dnl These rules are solely for the distribution goal. While doing this dnl we only have to keep exactly one list of the available catalogs dnl in configure.in. for lang in $ALL_LINGUAS; do GMOFILES="$GMOFILES $lang.gmo" POFILES="$POFILES $lang.po" done dnl Make all variables we use known to autoconf. AC_SUBST(CATALOGS) AC_SUBST(CATOBJEXT) AC_SUBST(DATADIRNAME) AC_SUBST(GMOFILES) AC_SUBST(INSTOBJEXT) AC_SUBST(INTLLIBS) AC_SUBST(PO_IN_DATADIR_TRUE) AC_SUBST(PO_IN_DATADIR_FALSE) AC_SUBST(POFILES) AC_SUBST(POSUB) ]) # AM_GLIB_GNU_GETTEXT # ------------------- # Do checks necessary for use of gettext. If a suitable implementation # of gettext is found in either in libintl or in the C library, # it will set INTLLIBS to the libraries needed for use of gettext # and AC_DEFINE() HAVE_GETTEXT and ENABLE_NLS. (The shell variable # gt_cv_have_gettext will be set to "yes".) It will also call AC_SUBST() # on various variables needed by the Makefile.in.in installed by # glib-gettextize. dnl glib_DEFUN([GLIB_GNU_GETTEXT], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_HEADER_STDC])dnl GLIB_LC_MESSAGES GLIB_WITH_NLS if test "$gt_cv_have_gettext" = "yes"; then if test "x$ALL_LINGUAS" = "x"; then LINGUAS= else AC_MSG_CHECKING(for catalogs to be installed) NEW_LINGUAS= for presentlang in $ALL_LINGUAS; do useit=no if test "%UNSET%" != "${LINGUAS-%UNSET%}"; then desiredlanguages="$LINGUAS" else desiredlanguages="$ALL_LINGUAS" fi for desiredlang in $desiredlanguages; do # Use the presentlang catalog if desiredlang is # a. equal to presentlang, or # b. a variant of presentlang (because in this case, # presentlang can be used as a fallback for messages # which are not translated in the desiredlang catalog). case "$desiredlang" in "$presentlang"*) useit=yes;; esac done if test $useit = yes; then NEW_LINGUAS="$NEW_LINGUAS $presentlang" fi done LINGUAS=$NEW_LINGUAS AC_MSG_RESULT($LINGUAS) fi dnl Construct list of names of catalog files to be constructed. if test -n "$LINGUAS"; then for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done fi fi dnl If the AC_CONFIG_AUX_DIR macro for autoconf is used we possibly dnl find the mkinstalldirs script in another subdir but ($top_srcdir). dnl Try to locate is. MKINSTALLDIRS= if test -n "$ac_aux_dir"; then MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs" fi if test -z "$MKINSTALLDIRS"; then MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs" fi AC_SUBST(MKINSTALLDIRS) dnl Generate list of files to be processed by xgettext which will dnl be included in po/Makefile. test -d po || mkdir po if test "x$srcdir" != "x."; then if test "x`echo $srcdir | sed 's@/.*@@'`" = "x"; then posrcprefix="$srcdir/" else posrcprefix="../$srcdir/" fi else posrcprefix="../" fi rm -f po/POTFILES sed -e "/^#/d" -e "/^\$/d" -e "s,.*, $posrcprefix& \\\\," -e "\$s/\(.*\) \\\\/\1/" \ < $srcdir/po/POTFILES.in > po/POTFILES ]) # AM_GLIB_DEFINE_LOCALEDIR(VARIABLE) # ------------------------------- # Define VARIABLE to the location where catalog files will # be installed by po/Makefile. glib_DEFUN([GLIB_DEFINE_LOCALEDIR], [glib_REQUIRE([GLIB_GNU_GETTEXT])dnl glib_save_prefix="$prefix" glib_save_exec_prefix="$exec_prefix" test "x$prefix" = xNONE && prefix=$ac_default_prefix test "x$exec_prefix" = xNONE && exec_prefix=$prefix if test "x$CATOBJEXT" = "x.mo" ; then localedir=`eval echo "${libdir}/locale"` else localedir=`eval echo "${datadir}/locale"` fi prefix="$glib_save_prefix" exec_prefix="$glib_save_exec_prefix" AC_DEFINE_UNQUOTED($1, "$localedir", [Define the location where the catalogs will be installed]) ]) dnl dnl Now the definitions that aclocal will find dnl ifdef(glib_configure_in,[],[ AC_DEFUN([AM_GLIB_GNU_GETTEXT],[GLIB_GNU_GETTEXT($@)]) AC_DEFUN([AM_GLIB_DEFINE_LOCALEDIR],[GLIB_DEFINE_LOCALEDIR($@)]) ])dnl gnunet-0.9.3/m4/glibc21.m40000644000175000017500000000144511317762540011763 00000000000000# glibc21.m4 serial 3 dnl Copyright (C) 2000-2002, 2004 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. # Test for the GNU C Library, version 2.1 or newer. # From Bruno Haible. AC_DEFUN([gl_GLIBC21], [ AC_CACHE_CHECK(whether we are using the GNU C Library 2.1 or newer, ac_cv_gnu_library_2_1, [AC_EGREP_CPP([Lucky GNU user], [ #include #ifdef __GNU_LIBRARY__ #if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || (__GLIBC__ > 2) Lucky GNU user #endif #endif ], ac_cv_gnu_library_2_1=yes, ac_cv_gnu_library_2_1=no) ] ) AC_SUBST(GLIBC21) GLIBC21="$ac_cv_gnu_library_2_1" ] ) gnunet-0.9.3/m4/pkg.m40000644000175000017500000000375311317762615011330 00000000000000 dnl PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not) dnl defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page dnl also defines GSTUFF_PKG_ERRORS on error AC_DEFUN([PKG_CHECK_MODULES], [ succeeded=no if test -z "$PKG_CONFIG"; then AC_PATH_PROG(PKG_CONFIG, pkg-config, no) fi if test "$PKG_CONFIG" = "no" ; then echo "*** The pkg-config script could not be found. Make sure it is" echo "*** in your path, or set the PKG_CONFIG environment variable" echo "*** to the full path to pkg-config." echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." else PKG_CONFIG_MIN_VERSION=0.9.0 if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then AC_MSG_CHECKING(for $2) if $PKG_CONFIG --exists "$2" ; then AC_MSG_RESULT(yes) succeeded=yes AC_MSG_CHECKING($1_CFLAGS) $1_CFLAGS=`$PKG_CONFIG --cflags "$2"` AC_MSG_RESULT($$1_CFLAGS) AC_MSG_CHECKING($1_LIBS) $1_LIBS=`$PKG_CONFIG --libs "$2"` AC_MSG_RESULT($$1_LIBS) else $1_CFLAGS="" $1_LIBS="" ## If we have a custom action on failure, don't print errors, but ## do set a variable so people can do so. $1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` ifelse([$4], ,echo $$1_PKG_ERRORS,) fi AC_SUBST($1_CFLAGS) AC_SUBST($1_LIBS) else echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer." echo "*** See http://www.freedesktop.org/software/pkgconfig" fi fi if test $succeeded = yes; then ifelse([$3], , :, [$3]) else ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4]) fi ]) gnunet-0.9.3/m4/freetype2.m40000644000175000017500000001304511317762615012447 00000000000000# Configure paths for FreeType2 # Marcelo Magallon 2001-10-26, based on gtk.m4 by Owen Taylor # # serial 2 # AC_CHECK_FT2([MINIMUM-VERSION [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) # Test for FreeType 2, and define FT2_CFLAGS and FT2_LIBS. # MINIMUM-VERSION is what libtool reports; the default is `7.0.1' (this is # FreeType 2.0.4). # AC_DEFUN([AC_CHECK_FT2], [# Get the cflags and libraries from the freetype-config script # AC_ARG_WITH([ft-prefix], dnl don't quote AS_HELP_STRING! AS_HELP_STRING([--with-ft-prefix=PREFIX], [Prefix where FreeType is installed (optional)]), [ft_config_prefix="$withval"], [ft_config_prefix=""]) AC_ARG_WITH([ft-exec-prefix], dnl don't quote AS_HELP_STRING! AS_HELP_STRING([--with-ft-exec-prefix=PREFIX], [Exec prefix where FreeType is installed (optional)]), [ft_config_exec_prefix="$withval"], [ft_config_exec_prefix=""]) AC_ARG_ENABLE([freetypetest], dnl don't quote AS_HELP_STRING! AS_HELP_STRING([--disable-freetypetest], [Do not try to compile and run a test FreeType program]), [], [enable_fttest=yes]) if test x$ft_config_exec_prefix != x ; then ft_config_args="$ft_config_args --exec-prefix=$ft_config_exec_prefix" if test x${FT2_CONFIG+set} != xset ; then FT2_CONFIG=$ft_config_exec_prefix/bin/freetype-config fi fi if test x$ft_config_prefix != x ; then ft_config_args="$ft_config_args --prefix=$ft_config_prefix" if test x${FT2_CONFIG+set} != xset ; then FT2_CONFIG=$ft_config_prefix/bin/freetype-config fi fi AC_PATH_PROG([FT2_CONFIG], [freetype-config], [no]) min_ft_version=m4_if([$1], [], [7.0.1], [$1]) AC_MSG_CHECKING([for FreeType -- version >= $min_ft_version]) no_ft="" if test "$FT2_CONFIG" = "no" ; then no_ft=yes else FT2_CFLAGS=`$FT2_CONFIG $ft_config_args --cflags` FT2_LIBS=`$FT2_CONFIG $ft_config_args --libs` ft_config_major_version=`$FT2_CONFIG $ft_config_args --version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` ft_config_minor_version=`$FT2_CONFIG $ft_config_args --version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` ft_config_micro_version=`$FT2_CONFIG $ft_config_args --version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` ft_min_major_version=`echo $min_ft_version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` ft_min_minor_version=`echo $min_ft_version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` ft_min_micro_version=`echo $min_ft_version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` if test x$enable_fttest = xyes ; then ft_config_is_lt="" if test $ft_config_major_version -lt $ft_min_major_version ; then ft_config_is_lt=yes else if test $ft_config_major_version -eq $ft_min_major_version ; then if test $ft_config_minor_version -lt $ft_min_minor_version ; then ft_config_is_lt=yes else if test $ft_config_minor_version -eq $ft_min_minor_version ; then if test $ft_config_micro_version -lt $ft_min_micro_version ; then ft_config_is_lt=yes fi fi fi fi fi if test x$ft_config_is_lt = xyes ; then no_ft=yes else ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $FT2_CFLAGS" LIBS="$FT2_LIBS $LIBS" # # Sanity checks for the results of freetype-config to some extent. # AC_RUN_IFELSE([ AC_LANG_SOURCE([[ #include #include FT_FREETYPE_H #include #include int main() { FT_Library library; FT_Error error; error = FT_Init_FreeType(&library); if (error) return 1; else { FT_Done_FreeType(library); return 0; } } ]]) ], [], [no_ft=yes], [echo $ECHO_N "cross compiling; assuming OK... $ECHO_C"]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi # test $ft_config_version -lt $ft_min_version fi # test x$enable_fttest = xyes fi # test "$FT2_CONFIG" = "no" if test x$no_ft = x ; then AC_MSG_RESULT([yes]) m4_if([$2], [], [:], [$2]) else AC_MSG_RESULT([no]) if test "$FT2_CONFIG" = "no" ; then AC_MSG_WARN([ The freetype-config script installed by FreeType 2 could not be found. If FreeType 2 was installed in PREFIX, make sure PREFIX/bin is in your path, or set the FT2_CONFIG environment variable to the full path to freetype-config. ]) else if test x$ft_config_is_lt = xyes ; then AC_MSG_WARN([ Your installed version of the FreeType 2 library is too old. If you have different versions of FreeType 2, make sure that correct values for --with-ft-prefix or --with-ft-exec-prefix are used, or set the FT2_CONFIG environment variable to the full path to freetype-config. ]) else AC_MSG_WARN([ The FreeType test program failed to run. If your system uses shared libraries and they are installed outside the normal system library path, make sure the variable LD_LIBRARY_PATH (or whatever is appropiate for your system) is correctly set. ]) fi fi FT2_CFLAGS="" FT2_LIBS="" m4_if([$3], [], [:], [$3]) fi AC_SUBST([FT2_CFLAGS]) AC_SUBST([FT2_LIBS])]) # end of freetype2.m4 gnunet-0.9.3/m4/libcurl.m40000644000175000017500000002365411574463017012204 00000000000000# LIBCURL_CHECK_CONFIG ([DEFAULT-ACTION], [MINIMUM-VERSION], # [ACTION-IF-YES], [ACTION-IF-NO]) # ---------------------------------------------------------- # David Shaw May-09-2006 # # Checks for libcurl. DEFAULT-ACTION is the string yes or no to # specify whether to default to --with-libcurl or --without-libcurl. # If not supplied, DEFAULT-ACTION is yes. MINIMUM-VERSION is the # minimum version of libcurl to accept. Pass the version as a regular # version number like 7.10.1. If not supplied, any version is # accepted. ACTION-IF-YES is a list of shell commands to run if # libcurl was successfully found and passed the various tests. # ACTION-IF-NO is a list of shell commands that are run otherwise. # Note that using --without-libcurl does run ACTION-IF-NO. # # This macro #defines HAVE_LIBCURL if a working libcurl setup is # found, and sets @LIBCURL@ and @LIBCURL_CPPFLAGS@ to the necessary # values. Other useful defines are LIBCURL_FEATURE_xxx where xxx are # the various features supported by libcurl, and LIBCURL_PROTOCOL_yyy # where yyy are the various protocols supported by libcurl. Both xxx # and yyy are capitalized. See the list of AH_TEMPLATEs at the top of # the macro for the complete list of possible defines. Shell # variables $libcurl_feature_xxx and $libcurl_protocol_yyy are also # defined to 'yes' for those features and protocols that were found. # Note that xxx and yyy keep the same capitalization as in the # curl-config list (e.g. it's "HTTP" and not "http"). # # Users may override the detected values by doing something like: # LIBCURL="-lcurl" LIBCURL_CPPFLAGS="-I/usr/myinclude" ./configure # # For the sake of sanity, this macro assumes that any libcurl that is # found is after version 7.7.2, the first version that included the # curl-config script. Note that it is very important for people # packaging binary versions of libcurl to include this script! # Without curl-config, we can only guess what protocols are available, # or use curl_version_info to figure it out at runtime. AC_DEFUN([LIBCURL_CHECK_CONFIG], [ AH_TEMPLATE([LIBCURL_FEATURE_SSL],[Defined if libcurl supports SSL]) AH_TEMPLATE([LIBCURL_FEATURE_KRB4],[Defined if libcurl supports KRB4]) AH_TEMPLATE([LIBCURL_FEATURE_IPV6],[Defined if libcurl supports IPv6]) AH_TEMPLATE([LIBCURL_FEATURE_LIBZ],[Defined if libcurl supports libz]) AH_TEMPLATE([LIBCURL_FEATURE_ASYNCHDNS],[Defined if libcurl supports AsynchDNS]) AH_TEMPLATE([LIBCURL_FEATURE_IDN],[Defined if libcurl supports IDN]) AH_TEMPLATE([LIBCURL_FEATURE_SSPI],[Defined if libcurl supports SSPI]) AH_TEMPLATE([LIBCURL_FEATURE_NTLM],[Defined if libcurl supports NTLM]) AH_TEMPLATE([LIBCURL_PROTOCOL_HTTP],[Defined if libcurl supports HTTP]) AH_TEMPLATE([LIBCURL_PROTOCOL_HTTPS],[Defined if libcurl supports HTTPS]) AH_TEMPLATE([LIBCURL_PROTOCOL_FTP],[Defined if libcurl supports FTP]) AH_TEMPLATE([LIBCURL_PROTOCOL_FTPS],[Defined if libcurl supports FTPS]) AH_TEMPLATE([LIBCURL_PROTOCOL_FILE],[Defined if libcurl supports FILE]) AH_TEMPLATE([LIBCURL_PROTOCOL_TELNET],[Defined if libcurl supports TELNET]) AH_TEMPLATE([LIBCURL_PROTOCOL_LDAP],[Defined if libcurl supports LDAP]) AH_TEMPLATE([LIBCURL_PROTOCOL_DICT],[Defined if libcurl supports DICT]) AH_TEMPLATE([LIBCURL_PROTOCOL_TFTP],[Defined if libcurl supports TFTP]) AH_TEMPLATE([LIBCURL_PROTOCOL_RTSP],[Defined if libcurl supports RTSP]) AH_TEMPLATE([LIBCURL_PROTOCOL_POP3],[Defined if libcurl supports POP3]) AH_TEMPLATE([LIBCURL_PROTOCOL_IMAP],[Defined if libcurl supports IMAP]) AH_TEMPLATE([LIBCURL_PROTOCOL_SMTP],[Defined if libcurl supports SMTP]) AC_ARG_WITH(libcurl, AC_HELP_STRING([--with-libcurl=PREFIX],[look for the curl library in PREFIX/lib and headers in PREFIX/include]), [_libcurl_with=$withval],[_libcurl_with=ifelse([$1],,[yes],[$1])]) if test "$_libcurl_with" != "no" ; then AC_PROG_AWK _libcurl_version_parse="eval $AWK '{split(\$NF,A,\".\"); X=256*256*A[[1]]+256*A[[2]]+A[[3]]; print X;}'" _libcurl_try_link=yes if test -d "$_libcurl_with" ; then LIBCURL_CPPFLAGS="-I$withval/include" _libcurl_ldflags="-L$withval/lib" AC_PATH_PROG([_libcurl_config],[curl-config],[], ["$withval/bin"]) else AC_PATH_PROG([_libcurl_config],[curl-config],[],[$PATH]) fi if test x$_libcurl_config != "x" ; then AC_CACHE_CHECK([for the version of libcurl], [libcurl_cv_lib_curl_version], [libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $[]2}'`]) _libcurl_version=`echo $libcurl_cv_lib_curl_version | $_libcurl_version_parse` _libcurl_wanted=`echo ifelse([$2],,[0],[$2]) | $_libcurl_version_parse` if test $_libcurl_wanted -gt 0 ; then AC_CACHE_CHECK([for libcurl >= version $2], [libcurl_cv_lib_version_ok], [ if test $_libcurl_version -ge $_libcurl_wanted ; then libcurl_cv_lib_version_ok=yes else libcurl_cv_lib_version_ok=no fi ]) fi if test $_libcurl_wanted -eq 0 || test x$libcurl_cv_lib_version_ok = xyes ; then if test x"$LIBCURL_CPPFLAGS" = "x" ; then LIBCURL_CPPFLAGS=`$_libcurl_config --cflags` fi if test x"$LIBCURL" = "x" ; then LIBCURL=`$_libcurl_config --libs` # This is so silly, but Apple actually has a bug in their # curl-config script. Fixed in Tiger, but there are still # lots of Panther installs around. case "${host}" in powerpc-apple-darwin7*) LIBCURL=`echo $LIBCURL | sed -e 's|-arch i386||g'` ;; esac fi # All curl-config scripts support --feature _libcurl_features=`$_libcurl_config --feature` # Is it modern enough to have --protocols? (7.12.4) if test $_libcurl_version -ge 461828 ; then _libcurl_protocols=`$_libcurl_config --protocols` fi else _libcurl_try_link=no fi unset _libcurl_wanted fi if test $_libcurl_try_link = yes ; then # we didn't find curl-config, so let's see if the user-supplied # link line (or failing that, "-lcurl") is enough. LIBCURL=${LIBCURL-"$_libcurl_ldflags -lcurl"} AC_CACHE_CHECK([whether libcurl is usable], [libcurl_cv_lib_curl_usable], [ _libcurl_save_cppflags=$CPPFLAGS CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS" _libcurl_save_libs=$LIBS LIBS="$LIBCURL $LIBS" AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ],[ /* Try and use a few common options to force a failure if we are missing symbols or can't link. */ int x; curl_easy_setopt(NULL,CURLOPT_URL,NULL); x=CURL_ERROR_SIZE; x=CURLOPT_WRITEFUNCTION; x=CURLOPT_FILE; x=CURLOPT_ERRORBUFFER; x=CURLOPT_STDERR; x=CURLOPT_VERBOSE; ])],libcurl_cv_lib_curl_usable=yes,libcurl_cv_lib_curl_usable=no) CPPFLAGS=$_libcurl_save_cppflags LIBS=$_libcurl_save_libs unset _libcurl_save_cppflags unset _libcurl_save_libs ]) if test $libcurl_cv_lib_curl_usable = yes ; then # Does curl_free() exist in this version of libcurl? # If not, fake it with free() _libcurl_save_cppflags=$CPPFLAGS CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS" _libcurl_save_libs=$LIBS LIBS="$LIBS $LIBCURL" AC_CHECK_FUNC(curl_free,, AC_DEFINE(curl_free,free, [Define curl_free() as free() if our version of curl lacks curl_free.])) CPPFLAGS=$_libcurl_save_cppflags LIBS=$_libcurl_save_libs unset _libcurl_save_cppflags unset _libcurl_save_libs AC_DEFINE(HAVE_LIBCURL,1, [Define to 1 if you have a functional curl library.]) AC_SUBST(LIBCURL_CPPFLAGS) AC_SUBST(LIBCURL) for _libcurl_feature in $_libcurl_features ; do AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_feature_$_libcurl_feature),[1]) eval AS_TR_SH(libcurl_feature_$_libcurl_feature)=yes done if test "x$_libcurl_protocols" = "x" ; then # We don't have --protocols, so just assume that all # protocols are available _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP" if test x$libcurl_feature_SSL = xyes ; then _libcurl_protocols="$_libcurl_protocols HTTPS" # FTPS wasn't standards-compliant until version # 7.11.0 (0x070b00 == 461568) if test $_libcurl_version -ge 461568; then _libcurl_protocols="$_libcurl_protocols FTPS" fi fi # RTSP, IMAP, POP3 and SMTP were added in # 7.20.0 (0x071400 == 463872) if test $_libcurl_version -ge 463872; then _libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP" fi fi for _libcurl_protocol in $_libcurl_protocols ; do AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_protocol_$_libcurl_protocol),[1]) eval AS_TR_SH(libcurl_protocol_$_libcurl_protocol)=yes done else unset LIBCURL unset LIBCURL_CPPFLAGS fi fi unset _libcurl_try_link unset _libcurl_version_parse unset _libcurl_config unset _libcurl_feature unset _libcurl_features unset _libcurl_protocol unset _libcurl_protocols unset _libcurl_version unset _libcurl_ldflags fi if test x$_libcurl_with = xno || test x$libcurl_cv_lib_curl_usable != xyes ; then # This is the IF-NO path ifelse([$4],,:,[$4]) else # This is the IF-YES path ifelse([$3],,:,[$3]) fi unset _libcurl_with ])dnl gnunet-0.9.3/m4/nls.m40000644000175000017500000000226611317762540011336 00000000000000# nls.m4 serial 3 (gettext-0.15) dnl Copyright (C) 1995-2003, 2005-2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1995-2000. dnl Bruno Haible , 2000-2003. AC_PREREQ(2.50) AC_DEFUN([AM_NLS], [ AC_MSG_CHECKING([whether NLS is requested]) dnl Default is enabled NLS AC_ARG_ENABLE(nls, [ --disable-nls do not use Native Language Support], USE_NLS=$enableval, USE_NLS=yes) AC_MSG_RESULT($USE_NLS) AC_SUBST(USE_NLS) ]) gnunet-0.9.3/m4/longdouble.m40000644000175000017500000000227711317762540012676 00000000000000# longdouble.m4 serial 2 (gettext-0.15) dnl Copyright (C) 2002-2003, 2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl Test whether the compiler supports the 'long double' type. dnl Prerequisite: AC_PROG_CC dnl This file is only needed in autoconf <= 2.59. Newer versions of autoconf dnl have a macro AC_TYPE_LONG_DOUBLE with identical semantics. AC_DEFUN([gt_TYPE_LONGDOUBLE], [ AC_CACHE_CHECK([for long double], gt_cv_c_long_double, [if test "$GCC" = yes; then gt_cv_c_long_double=yes else AC_TRY_COMPILE([ /* The Stardent Vistra knows sizeof(long double), but does not support it. */ long double foo = 0.0; /* On Ultrix 4.3 cc, long double is 4 and double is 8. */ int array [2*(sizeof(long double) >= sizeof(double)) - 1]; ], , gt_cv_c_long_double=yes, gt_cv_c_long_double=no) fi]) if test $gt_cv_c_long_double = yes; then AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have the 'long double' type.]) fi ]) gnunet-0.9.3/m4/progtest.m40000644000175000017500000000555011317762540012410 00000000000000# progtest.m4 serial 4 (gettext-0.14.2) dnl Copyright (C) 1996-2003, 2005 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1996. AC_PREREQ(2.50) # Search path for a program which passes the given test. dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) AC_DEFUN([AM_PATH_PROG_WITH_TEST], [ # Prepare PATH_SEPARATOR. # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi # Find out how to test for executable files. Don't use a zero-byte file, # as systems may use methods other than mode bits to determine executability. cat >conf$$.file <<_ASEOF #! /bin/sh exit 0 _ASEOF chmod +x conf$$.file if test -x conf$$.file >/dev/null 2>&1; then ac_executable_p="test -x" else ac_executable_p="test -f" fi rm -f conf$$.file # Extract the first word of "$2", so it can be a program name with args. set dummy $2; ac_word=[$]2 AC_MSG_CHECKING([for $ac_word]) AC_CACHE_VAL(ac_cv_path_$1, [case "[$]$1" in [[\\/]]* | ?:[[\\/]]*) ac_cv_path_$1="[$]$1" # Let the user override the test with a path. ;; *) ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in ifelse([$5], , $PATH, [$5]); do IFS="$ac_save_IFS" test -z "$ac_dir" && ac_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then echo "$as_me: trying $ac_dir/$ac_word..." >&AS_MESSAGE_LOG_FD if [$3]; then ac_cv_path_$1="$ac_dir/$ac_word$ac_exec_ext" break 2 fi fi done done IFS="$ac_save_IFS" dnl If no 4th arg is given, leave the cache variable unset, dnl so AC_PATH_PROGS will keep looking. ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" ])dnl ;; esac])dnl $1="$ac_cv_path_$1" if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then AC_MSG_RESULT([$]$1) else AC_MSG_RESULT(no) fi AC_SUBST($1)dnl ]) gnunet-0.9.3/m4/ulonglong.m40000644000175000017500000000353211317762540012543 00000000000000# ulonglong.m4 serial 6 dnl Copyright (C) 1999-2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Paul Eggert. # Define HAVE_UNSIGNED_LONG_LONG_INT if 'unsigned long long int' works. # This fixes a bug in Autoconf 2.60, but can be removed once we # assume 2.61 everywhere. # Note: If the type 'unsigned long long int' exists but is only 32 bits # large (as on some very old compilers), AC_TYPE_UNSIGNED_LONG_LONG_INT # will not be defined. In this case you can treat 'unsigned long long int' # like 'unsigned long int'. AC_DEFUN([AC_TYPE_UNSIGNED_LONG_LONG_INT], [ AC_CACHE_CHECK([for unsigned long long int], [ac_cv_type_unsigned_long_long_int], [AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[unsigned long long int ull = 18446744073709551615ULL; typedef int a[(18446744073709551615ULL <= (unsigned long long int) -1 ? 1 : -1)]; int i = 63;]], [[unsigned long long int ullmax = 18446744073709551615ull; return (ull << 63 | ull >> 63 | ull << i | ull >> i | ullmax / ull | ullmax % ull);]])], [ac_cv_type_unsigned_long_long_int=yes], [ac_cv_type_unsigned_long_long_int=no])]) if test $ac_cv_type_unsigned_long_long_int = yes; then AC_DEFINE([HAVE_UNSIGNED_LONG_LONG_INT], 1, [Define to 1 if the system has the type `unsigned long long int'.]) fi ]) # This macro is obsolescent and should go away soon. AC_DEFUN([gl_AC_TYPE_UNSIGNED_LONG_LONG], [ AC_REQUIRE([AC_TYPE_UNSIGNED_LONG_LONG_INT]) ac_cv_type_unsigned_long_long=$ac_cv_type_unsigned_long_long_int if test $ac_cv_type_unsigned_long_long = yes; then AC_DEFINE(HAVE_UNSIGNED_LONG_LONG, 1, [Define if you have the 'unsigned long long' type.]) fi ]) gnunet-0.9.3/m4/ltoptions.m40000644000175000017500000002724211762217203012571 00000000000000# Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option `$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl `shared' nor `disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) ]) ])# _LT_SET_OPTIONS ## --------------------------------- ## ## Macros to handle LT_INIT options. ## ## --------------------------------- ## # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [0], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the `shared' and # `disable-shared' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the `static' and # `disable-static' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the `fast-install' # and `disable-fast-install' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the `pic-only' and `no-pic' # LT_INIT options. # MODE is either `yes' or `no'. If omitted, it defaults to `both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [pic_mode="$withval"], [pic_mode=default]) test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) ## ----------------- ## ## LTDL_INIT Options ## ## ----------------- ## m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) gnunet-0.9.3/m4/lib-ld.m40000644000175000017500000000653111317762540011704 00000000000000# lib-ld.m4 serial 3 (gettext-0.13) dnl Copyright (C) 1996-2003 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl Subroutines of libtool.m4, dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision dnl with libtool.m4. dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no. AC_DEFUN([AC_LIB_PROG_LD_GNU], [AC_CACHE_CHECK([if the linker ($LD) is GNU ld], acl_cv_prog_gnu_ld, [# I'd rather use --version here, but apparently some GNU ld's only accept -v. case `$LD -v 2>&1 conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by GCC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]* | [A-Za-z]:[\\/]*)] [re_direlt='/[^/][^/]*/\.\./'] # Canonicalize the path of ld ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(acl_cv_path_LD, [if test -z "$LD"; then IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then acl_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in *GNU* | *'with BFD'*) test "$with_gnu_ld" != no && break ;; *) test "$with_gnu_ld" != yes && break ;; esac fi done IFS="$ac_save_ifs" else acl_cv_path_LD="$LD" # Let the user override the test with a path. fi]) LD="$acl_cv_path_LD" if test -n "$LD"; then AC_MSG_RESULT($LD) else AC_MSG_RESULT(no) fi test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) AC_LIB_PROG_LD_GNU ]) gnunet-0.9.3/m4/stdint_h.m40000644000175000017500000000161411317762540012352 00000000000000# stdint_h.m4 serial 6 dnl Copyright (C) 1997-2004, 2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Paul Eggert. # Define HAVE_STDINT_H_WITH_UINTMAX if exists, # doesn't clash with , and declares uintmax_t. AC_DEFUN([gl_AC_HEADER_STDINT_H], [ AC_CACHE_CHECK([for stdint.h], gl_cv_header_stdint_h, [AC_TRY_COMPILE( [#include #include ], [uintmax_t i = (uintmax_t) -1; return !i;], gl_cv_header_stdint_h=yes, gl_cv_header_stdint_h=no)]) if test $gl_cv_header_stdint_h = yes; then AC_DEFINE_UNQUOTED(HAVE_STDINT_H_WITH_UINTMAX, 1, [Define if exists, doesn't clash with , and declares uintmax_t. ]) fi ]) gnunet-0.9.3/m4/ltversion.m40000644000175000017500000000127711762217203012563 00000000000000# ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # Generated from ltversion.in. # serial 3017 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.2.6b]) m4_define([LT_PACKAGE_REVISION], [1.3017]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.2.6b' macro_revision='1.3017' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) gnunet-0.9.3/m4/printf-posix.m40000644000175000017500000000266111317762540013203 00000000000000# printf-posix.m4 serial 2 (gettext-0.13.1) dnl Copyright (C) 2003 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl Test whether the printf() function supports POSIX/XSI format strings with dnl positions. AC_DEFUN([gt_PRINTF_POSIX], [ AC_REQUIRE([AC_PROG_CC]) AC_CACHE_CHECK([whether printf() supports POSIX/XSI format strings], gt_cv_func_printf_posix, [ AC_TRY_RUN([ #include #include /* The string "%2$d %1$d", with dollar characters protected from the shell's dollar expansion (possibly an autoconf bug). */ static char format[] = { '%', '2', '$', 'd', ' ', '%', '1', '$', 'd', '\0' }; static char buf[100]; int main () { sprintf (buf, format, 33, 55); return (strcmp (buf, "55 33") != 0); }], gt_cv_func_printf_posix=yes, gt_cv_func_printf_posix=no, [ AC_EGREP_CPP(notposix, [ #if defined __NetBSD__ || defined _MSC_VER || defined __MINGW32__ || defined __CYGWIN__ notposix #endif ], gt_cv_func_printf_posix="guessing no", gt_cv_func_printf_posix="guessing yes") ]) ]) case $gt_cv_func_printf_posix in *yes) AC_DEFINE(HAVE_POSIX_PRINTF, 1, [Define if your printf() function supports format strings with positions.]) ;; esac ]) gnunet-0.9.3/m4/intmax.m40000644000175000017500000000201111317762540012026 00000000000000# intmax.m4 serial 3 (gettext-0.16) dnl Copyright (C) 2002-2005 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl Test whether the system has the 'intmax_t' type, but don't attempt to dnl find a replacement if it is lacking. AC_DEFUN([gt_TYPE_INTMAX_T], [ AC_REQUIRE([gl_AC_HEADER_INTTYPES_H]) AC_REQUIRE([gl_AC_HEADER_STDINT_H]) AC_CACHE_CHECK(for intmax_t, gt_cv_c_intmax_t, [AC_TRY_COMPILE([ #include #include #if HAVE_STDINT_H_WITH_UINTMAX #include #endif #if HAVE_INTTYPES_H_WITH_UINTMAX #include #endif ], [intmax_t x = -1; return !x;], gt_cv_c_intmax_t=yes, gt_cv_c_intmax_t=no)]) if test $gt_cv_c_intmax_t = yes; then AC_DEFINE(HAVE_INTMAX_T, 1, [Define if you have the 'intmax_t' type in or .]) fi ]) gnunet-0.9.3/m4/ChangeLog0000644000175000017500000000523411266675557012066 000000000000002007-02-08 gettextize * gettext.m4: Upgrade to gettext-0.16.1. * iconv.m4: Upgrade to gettext-0.16.1. * lib-ld.m4: Upgrade to gettext-0.16.1. * lib-link.m4: Upgrade to gettext-0.16.1. * lib-prefix.m4: Upgrade to gettext-0.16.1. * nls.m4: Upgrade to gettext-0.16.1. * po.m4: Upgrade to gettext-0.16.1. * progtest.m4: Upgrade to gettext-0.16.1. * codeset.m4: Upgrade to gettext-0.16.1. * glibc2.m4: New file, from gettext-0.16.1. * glibc21.m4: Upgrade to gettext-0.16.1. * intdiv0.m4: Upgrade to gettext-0.16.1. * intl.m4: New file, from gettext-0.16.1. * intldir.m4: New file, from gettext-0.16.1. * intmax.m4: Upgrade to gettext-0.16.1. * inttypes_h.m4: Upgrade to gettext-0.16.1. * inttypes-pri.m4: Upgrade to gettext-0.16.1. * lcmessage.m4: Upgrade to gettext-0.16.1. * lock.m4: New file, from gettext-0.16.1. * longdouble.m4: Upgrade to gettext-0.16.1. * longlong.m4: Upgrade to gettext-0.16.1. * printf-posix.m4: Upgrade to gettext-0.16.1. * size_max.m4: Upgrade to gettext-0.16.1. * stdint_h.m4: Upgrade to gettext-0.16.1. * uintmax_t.m4: Upgrade to gettext-0.16.1. * ulonglong.m4: Upgrade to gettext-0.16.1. * visibility.m4: New file, from gettext-0.16.1. * wchar_t.m4: Upgrade to gettext-0.16.1. * wint_t.m4: Upgrade to gettext-0.16.1. * xsize.m4: Upgrade to gettext-0.16.1. * Makefile.am (EXTRA_DIST): Add the new files. 2004-08-21 gettextize * codeset.m4: New file, from gettext-0.14. * gettext.m4: New file, from gettext-0.14. * glibc21.m4: New file, from gettext-0.14. * iconv.m4: New file, from gettext-0.14. * intdiv0.m4: New file, from gettext-0.14. * intmax.m4: New file, from gettext-0.14. * inttypes.m4: New file, from gettext-0.14. * inttypes_h.m4: New file, from gettext-0.14. * inttypes-pri.m4: New file, from gettext-0.14. * isc-posix.m4: New file, from gettext-0.14. * lcmessage.m4: New file, from gettext-0.14. * lib-ld.m4: New file, from gettext-0.14. * lib-link.m4: New file, from gettext-0.14. * lib-prefix.m4: New file, from gettext-0.14. * longdouble.m4: New file, from gettext-0.14. * longlong.m4: New file, from gettext-0.14. * nls.m4: New file, from gettext-0.14. * po.m4: New file, from gettext-0.14. * printf-posix.m4: New file, from gettext-0.14. * progtest.m4: New file, from gettext-0.14. * signed.m4: New file, from gettext-0.14. * size_max.m4: New file, from gettext-0.14. * stdint_h.m4: New file, from gettext-0.14. * uintmax_t.m4: New file, from gettext-0.14. * ulonglong.m4: New file, from gettext-0.14. * wchar_t.m4: New file, from gettext-0.14. * wint_t.m4: New file, from gettext-0.14. * xsize.m4: New file, from gettext-0.14. * Makefile.am: New file. gnunet-0.9.3/m4/Makefile.in0000644000175000017500000003204211762217210012331 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = m4 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ SOURCES = DIST_SOURCES = DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = glibc2.m4 intl.m4 intldir.m4 lock.m4 visibility.m4 \ absolute-header.m4 \ libunistring.m4 \ codeset.m4 \ freetype2.m4\ gettext.m4\ glib-2.0.m4\ glibc21.m4\ glib-gettext.m4\ gnulib-cache.m4\ gtk-2.0.m4\ iconv.m4\ intdiv0.m4\ intmax.m4\ inttypes_h.m4\ inttypes.m4\ inttypes-pri.m4\ isc-posix.m4\ lcmessage.m4\ libgcrypt.m4\ lib-ld.m4\ lib-link.m4\ lib-prefix.m4\ libxml2.m4\ longdouble.m4\ longlong.m4\ nls.m4\ pkg.m4\ po.m4\ printf-posix.m4\ progtest.m4\ signed.m4\ size_max.m4\ stdint_h.m4\ uintmax_t.m4\ ulonglong.m4\ wchar_t.m4\ wint_t.m4\ xsize.m4 all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu m4/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu m4/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags: TAGS TAGS: ctags: CTAGS CTAGS: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ distclean distclean-generic distclean-libtool distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/m4/absolute-header.m40000644000175000017500000000641111700046142013567 00000000000000# absolute-header.m4 serial 12 dnl Copyright (C) 2006-2010 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Derek Price. # gl_ABSOLUTE_HEADER(HEADER1 HEADER2 ...) # --------------------------------------- # Find the absolute name of a header file, testing first if the header exists. # If the header were sys/inttypes.h, this macro would define # ABSOLUTE_SYS_INTTYPES_H to the `""' quoted absolute name of sys/inttypes.h # in config.h # (e.g. `#define ABSOLUTE_SYS_INTTYPES_H "///usr/include/sys/inttypes.h"'). # The three "///" are to pacify Sun C 5.8, which otherwise would say # "warning: #include of /usr/include/... may be non-portable". # Use `""', not `<>', so that the /// cannot be confused with a C99 comment. # Note: This macro assumes that the header file is not empty after # preprocessing, i.e. it does not only define preprocessor macros but also # provides some type/enum definitions or function/variable declarations. AC_DEFUN([gl_ABSOLUTE_HEADER], [AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_PREPROC_REQUIRE()dnl m4_foreach_w([gl_HEADER_NAME], [$1], [AS_VAR_PUSHDEF([gl_absolute_header], [gl_cv_absolute_]m4_defn([gl_HEADER_NAME]))dnl AC_CACHE_CHECK([absolute name of <]m4_defn([gl_HEADER_NAME])[>], m4_defn([gl_absolute_header]), [AS_VAR_PUSHDEF([ac_header_exists], [ac_cv_header_]m4_defn([gl_HEADER_NAME]))dnl AC_CHECK_HEADERS_ONCE(m4_defn([gl_HEADER_NAME]))dnl if test AS_VAR_GET(ac_header_exists) = yes; then gl_ABSOLUTE_HEADER_ONE(m4_defn([gl_HEADER_NAME])) fi AS_VAR_POPDEF([ac_header_exists])dnl ])dnl AC_DEFINE_UNQUOTED(AS_TR_CPP([ABSOLUTE_]m4_defn([gl_HEADER_NAME])), ["AS_VAR_GET(gl_absolute_header)"], [Define this to an absolute name of <]m4_defn([gl_HEADER_NAME])[>.]) AS_VAR_POPDEF([gl_absolute_header])dnl ])dnl ])# gl_ABSOLUTE_HEADER # gl_ABSOLUTE_HEADER_ONE(HEADER) # ------------------------------ # Like gl_ABSOLUTE_HEADER, except that: # - it assumes that the header exists, # - it uses the current CPPFLAGS, # - it does not cache the result, # - it is silent. AC_DEFUN([gl_ABSOLUTE_HEADER_ONE], [ AC_LANG_CONFTEST([AC_LANG_SOURCE([[#include <]]m4_dquote([$1])[[>]])]) dnl AIX "xlc -E" and "cc -E" omit #line directives for header files dnl that contain only a #include of other header files and no dnl non-comment tokens of their own. This leads to a failure to dnl detect the absolute name of , , dnl and others. The workaround is to force preservation of comments dnl through option -C. This ensures all necessary #line directives dnl are present. GCC supports option -C as well. case "$host_os" in aix*) gl_absname_cpp="$ac_cpp -C" ;; *) gl_absname_cpp="$ac_cpp" ;; esac dnl eval is necessary to expand gl_absname_cpp. dnl Ultrix and Pyramid sh refuse to redirect output of eval, dnl so use subshell. AS_VAR_SET([gl_cv_absolute_]AS_TR_SH([[$1]]), [`(eval "$gl_absname_cpp conftest.$ac_ext") 2>&AS_MESSAGE_LOG_FD | sed -n '\#/$1#{ s#.*"\(.*/$1\)".*#\1# s#^/[^/]#//&# p q }'`]) ]) gnunet-0.9.3/m4/lib-link.m40000644000175000017500000006424411317762540012247 00000000000000# lib-link.m4 serial 9 (gettext-0.16) dnl Copyright (C) 2001-2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_PREREQ(2.50) dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and dnl the libraries corresponding to explicit and implicit dependencies. dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and dnl augments the CPPFLAGS variable. AC_DEFUN([AC_LIB_LINKFLAGS], [ AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) define([Name],[translit([$1],[./-], [___])]) define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [ AC_LIB_LINKFLAGS_BODY([$1], [$2]) ac_cv_lib[]Name[]_libs="$LIB[]NAME" ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME" ac_cv_lib[]Name[]_cppflags="$INC[]NAME" ]) LIB[]NAME="$ac_cv_lib[]Name[]_libs" LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs" INC[]NAME="$ac_cv_lib[]Name[]_cppflags" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) AC_SUBST([LIB]NAME) AC_SUBST([LTLIB]NAME) dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the dnl results of this search when this library appears as a dependency. HAVE_LIB[]NAME=yes undefine([Name]) undefine([NAME]) ]) dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode) dnl searches for libname and the libraries corresponding to explicit and dnl implicit dependencies, together with the specified include files and dnl the ability to compile and link the specified testcode. If found, it dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty. AC_DEFUN([AC_LIB_HAVE_LINKFLAGS], [ AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) define([Name],[translit([$1],[./-], [___])]) define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME dnl accordingly. AC_LIB_LINKFLAGS_BODY([$1], [$2]) dnl Add $INC[]NAME to CPPFLAGS before performing the following checks, dnl because if the user has installed lib[]Name and not disabled its use dnl via --without-lib[]Name-prefix, he wants to use it. ac_save_CPPFLAGS="$CPPFLAGS" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [ ac_save_LIBS="$LIBS" LIBS="$LIBS $LIB[]NAME" AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no]) LIBS="$ac_save_LIBS" ]) if test "$ac_cv_lib[]Name" = yes; then HAVE_LIB[]NAME=yes AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.]) AC_MSG_CHECKING([how to link with lib[]$1]) AC_MSG_RESULT([$LIB[]NAME]) else HAVE_LIB[]NAME=no dnl If $LIB[]NAME didn't lead to a usable library, we don't need dnl $INC[]NAME either. CPPFLAGS="$ac_save_CPPFLAGS" LIB[]NAME= LTLIB[]NAME= fi AC_SUBST([HAVE_LIB]NAME) AC_SUBST([LIB]NAME) AC_SUBST([LTLIB]NAME) undefine([Name]) undefine([NAME]) ]) dnl Determine the platform dependent parameters needed to use rpath: dnl libext, shlibext, hardcode_libdir_flag_spec, hardcode_libdir_separator, dnl hardcode_direct, hardcode_minus_L. AC_DEFUN([AC_LIB_RPATH], [ dnl Tell automake >= 1.10 to complain if config.rpath is missing. m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])]) AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [ CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh . ./conftest.sh rm -f ./conftest.sh acl_cv_rpath=done ]) wl="$acl_cv_wl" libext="$acl_cv_libext" shlibext="$acl_cv_shlibext" hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" hardcode_direct="$acl_cv_hardcode_direct" hardcode_minus_L="$acl_cv_hardcode_minus_L" dnl Determine whether the user wants rpath handling at all. AC_ARG_ENABLE(rpath, [ --disable-rpath do not hardcode runtime library paths], :, enable_rpath=yes) ]) dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and dnl the libraries corresponding to explicit and implicit dependencies. dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. AC_DEFUN([AC_LIB_LINKFLAGS_BODY], [ AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) dnl By default, look in $includedir and $libdir. use_additional=yes AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) AC_LIB_ARG_WITH([lib$1-prefix], [ --with-lib$1-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib --without-lib$1-prefix don't search for lib$1 in includedir and libdir], [ if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" fi fi ]) dnl Search the library and its dependencies in $additional_libdir and dnl $LDFLAGS. Using breadth-first-seach. LIB[]NAME= LTLIB[]NAME= INC[]NAME= rpathdirs= ltrpathdirs= names_already_handled= names_next_round='$1 $2' while test -n "$names_next_round"; do names_this_round="$names_next_round" names_next_round= for name in $names_this_round; do already_handled= for n in $names_already_handled; do if test "$n" = "$name"; then already_handled=yes break fi done if test -z "$already_handled"; then names_already_handled="$names_already_handled $name" dnl See if it was already located by an earlier AC_LIB_LINKFLAGS dnl or AC_LIB_HAVE_LINKFLAGS call. uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` eval value=\"\$HAVE_LIB$uppername\" if test -n "$value"; then if test "$value" = yes; then eval value=\"\$LIB$uppername\" test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" eval value=\"\$LTLIB$uppername\" test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" else dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined dnl that this library doesn't exist. So just drop it. : fi else dnl Search the library lib$name in $additional_libdir and $LDFLAGS dnl and the already constructed $LIBNAME/$LTLIBNAME. found_dir= found_la= found_so= found_a= if test $use_additional = yes; then if test -n "$shlibext" \ && { test -f "$additional_libdir/lib$name.$shlibext" \ || { test "$shlibext" = dll \ && test -f "$additional_libdir/lib$name.dll.a"; }; }; then found_dir="$additional_libdir" if test -f "$additional_libdir/lib$name.$shlibext"; then found_so="$additional_libdir/lib$name.$shlibext" else found_so="$additional_libdir/lib$name.dll.a" fi if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi else if test -f "$additional_libdir/lib$name.$libext"; then found_dir="$additional_libdir" found_a="$additional_libdir/lib$name.$libext" if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi fi fi fi if test "X$found_dir" = "X"; then for x in $LDFLAGS $LTLIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) case "$x" in -L*) dir=`echo "X$x" | sed -e 's/^X-L//'` if test -n "$shlibext" \ && { test -f "$dir/lib$name.$shlibext" \ || { test "$shlibext" = dll \ && test -f "$dir/lib$name.dll.a"; }; }; then found_dir="$dir" if test -f "$dir/lib$name.$shlibext"; then found_so="$dir/lib$name.$shlibext" else found_so="$dir/lib$name.dll.a" fi if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi else if test -f "$dir/lib$name.$libext"; then found_dir="$dir" found_a="$dir/lib$name.$libext" if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi fi fi ;; esac if test "X$found_dir" != "X"; then break fi done fi if test "X$found_dir" != "X"; then dnl Found the library. LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" if test "X$found_so" != "X"; then dnl Linking with a shared library. We attempt to hardcode its dnl directory into the executable's runpath, unless it's the dnl standard /usr/lib. if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then dnl No hardcoding is needed. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else dnl Use an explicit option to hardcode DIR into the resulting dnl binary. dnl Potentially add DIR to ltrpathdirs. dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. haveit= for x in $ltrpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $found_dir" fi dnl The hardcoding into $LIBNAME is system dependent. if test "$hardcode_direct" = yes; then dnl Using DIR/libNAME.so during linking hardcodes DIR into the dnl resulting binary. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then dnl Use an explicit option to hardcode DIR into the resulting dnl binary. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" dnl Potentially add DIR to rpathdirs. dnl The rpathdirs will be appended to $LIBNAME at the end. haveit= for x in $rpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $found_dir" fi else dnl Rely on "-L$found_dir". dnl But don't add it if it's already contained in the LDFLAGS dnl or the already constructed $LIBNAME haveit= for x in $LDFLAGS $LIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" fi if test "$hardcode_minus_L" != no; then dnl FIXME: Not sure whether we should use dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" dnl here. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else dnl We cannot use $hardcode_runpath_var and LD_RUN_PATH dnl here, because this doesn't fit in flags passed to the dnl compiler. So give up. No hardcoding. This affects only dnl very old systems. dnl FIXME: Not sure whether we should use dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" dnl here. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" fi fi fi fi else if test "X$found_a" != "X"; then dnl Linking with a static library. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" else dnl We shouldn't come here, but anyway it's good to have a dnl fallback. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" fi fi dnl Assume the include files are nearby. additional_includedir= case "$found_dir" in */$acl_libdirstem | */$acl_libdirstem/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` additional_includedir="$basedir/include" ;; esac if test "X$additional_includedir" != "X"; then dnl Potentially add $additional_includedir to $INCNAME. dnl But don't add it dnl 1. if it's the standard /usr/include, dnl 2. if it's /usr/local/include and we are using GCC on Linux, dnl 3. if it's already present in $CPPFLAGS or the already dnl constructed $INCNAME, dnl 4. if it doesn't exist as a directory. if test "X$additional_includedir" != "X/usr/include"; then haveit= if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then for x in $CPPFLAGS $INC[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_includedir"; then dnl Really add $additional_includedir to $INCNAME. INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" fi fi fi fi fi dnl Look for dependencies. if test -n "$found_la"; then dnl Read the .la file. It defines the variables dnl dlname, library_names, old_library, dependency_libs, current, dnl age, revision, installed, dlopen, dlpreopen, libdir. save_libdir="$libdir" case "$found_la" in */* | *\\*) . "$found_la" ;; *) . "./$found_la" ;; esac libdir="$save_libdir" dnl We use only dependency_libs. for dep in $dependency_libs; do case "$dep" in -L*) additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. dnl But don't add it dnl 1. if it's the standard /usr/lib, dnl 2. if it's /usr/local/lib and we are using GCC on Linux, dnl 3. if it's already present in $LDFLAGS or the already dnl constructed $LIBNAME, dnl 4. if it doesn't exist as a directory. if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then haveit= if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then haveit= for x in $LDFLAGS $LIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LIBNAME. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" fi fi haveit= for x in $LDFLAGS $LTLIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LTLIBNAME. LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" fi fi fi fi ;; -R*) dir=`echo "X$dep" | sed -e 's/^X-R//'` if test "$enable_rpath" != no; then dnl Potentially add DIR to rpathdirs. dnl The rpathdirs will be appended to $LIBNAME at the end. haveit= for x in $rpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $dir" fi dnl Potentially add DIR to ltrpathdirs. dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. haveit= for x in $ltrpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $dir" fi fi ;; -l*) dnl Handle this in the next round. names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` ;; *.la) dnl Handle this in the next round. Throw away the .la's dnl directory; it is already contained in a preceding -L dnl option. names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` ;; *) dnl Most likely an immediate library name. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" ;; esac done fi else dnl Didn't find the library; assume it is in the system directories dnl known to the linker and runtime loader. (All the system dnl directories known to the linker should also be known to the dnl runtime loader, otherwise the system is severely misconfigured.) LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" fi fi fi done done if test "X$rpathdirs" != "X"; then if test -n "$hardcode_libdir_separator"; then dnl Weird platform: only the last -rpath option counts, the user must dnl pass all path elements in one option. We can arrange that for a dnl single library, but not when more than one $LIBNAMEs are used. alldirs= for found_dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" done dnl Note: hardcode_libdir_flag_spec uses $libdir and $wl. acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" else dnl The -rpath options are cumulative. for found_dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$found_dir" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" done fi fi if test "X$ltrpathdirs" != "X"; then dnl When using libtool, the option that works for both libraries and dnl executables is -R. The -R options are cumulative. for found_dir in $ltrpathdirs; do LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" done fi ]) dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, dnl unless already present in VAR. dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes dnl contains two or three consecutive elements that belong together. AC_DEFUN([AC_LIB_APPENDTOVAR], [ for element in [$2]; do haveit= for x in $[$1]; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X$element"; then haveit=yes break fi done if test -z "$haveit"; then [$1]="${[$1]}${[$1]:+ }$element" fi done ]) dnl For those cases where a variable contains several -L and -l options dnl referring to unknown libraries and directories, this macro determines the dnl necessary additional linker options for the runtime path. dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL]) dnl sets LDADDVAR to linker options needed together with LIBSVALUE. dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed, dnl otherwise linking without libtool is assumed. AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS], [ AC_REQUIRE([AC_LIB_RPATH]) AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) $1= if test "$enable_rpath" != no; then if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then dnl Use an explicit option to hardcode directories into the resulting dnl binary. rpathdirs= next= for opt in $2; do if test -n "$next"; then dir="$next" dnl No need to hardcode the standard /usr/lib. if test "X$dir" != "X/usr/$acl_libdirstem"; then rpathdirs="$rpathdirs $dir" fi next= else case $opt in -L) next=yes ;; -L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'` dnl No need to hardcode the standard /usr/lib. if test "X$dir" != "X/usr/$acl_libdirstem"; then rpathdirs="$rpathdirs $dir" fi next= ;; *) next= ;; esac fi done if test "X$rpathdirs" != "X"; then if test -n ""$3""; then dnl libtool is used for linking. Use -R options. for dir in $rpathdirs; do $1="${$1}${$1:+ }-R$dir" done else dnl The linker is used for linking directly. if test -n "$hardcode_libdir_separator"; then dnl Weird platform: only the last -rpath option counts, the user dnl must pass all path elements in one option. alldirs= for dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$dir" done acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" $1="$flag" else dnl The -rpath options are cumulative. for dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$dir" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" $1="${$1}${$1:+ }$flag" done fi fi fi fi fi AC_SUBST([$1]) ]) gnunet-0.9.3/m4/iconv.m40000644000175000017500000000642611317762540011662 00000000000000# iconv.m4 serial AM4 (gettext-0.11.3) dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], [ dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV dnl accordingly. AC_LIB_LINKFLAGS_BODY([iconv]) ]) AC_DEFUN([AM_ICONV_LINK], [ dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and dnl those with the standalone portable GNU libiconv installed). dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV dnl accordingly. AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) dnl Add $INCICONV to CPPFLAGS before performing the following checks, dnl because if the user has installed libiconv and not disabled its use dnl via --without-libiconv-prefix, he wants to use it. The first dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed. am_save_CPPFLAGS="$CPPFLAGS" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [ am_cv_func_iconv="no, consider installing GNU libiconv" am_cv_lib_iconv=no AC_TRY_LINK([#include #include ], [iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);], am_cv_func_iconv=yes) if test "$am_cv_func_iconv" != yes; then am_save_LIBS="$LIBS" LIBS="$LIBS $LIBICONV" AC_TRY_LINK([#include #include ], [iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);], am_cv_lib_iconv=yes am_cv_func_iconv=yes) LIBS="$am_save_LIBS" fi ]) if test "$am_cv_func_iconv" = yes; then AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.]) fi if test "$am_cv_lib_iconv" = yes; then AC_MSG_CHECKING([how to link with libiconv]) AC_MSG_RESULT([$LIBICONV]) else dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV dnl either. CPPFLAGS="$am_save_CPPFLAGS" LIBICONV= LTLIBICONV= fi AC_SUBST(LIBICONV) AC_SUBST(LTLIBICONV) ]) AC_DEFUN([AM_ICONV], [ AM_ICONV_LINK if test "$am_cv_func_iconv" = yes; then AC_MSG_CHECKING([for iconv declaration]) AC_CACHE_VAL(am_cv_proto_iconv, [ AC_TRY_COMPILE([ #include #include extern #ifdef __cplusplus "C" #endif #if defined(__STDC__) || defined(__cplusplus) size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); #else size_t iconv(); #endif ], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const") am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` AC_MSG_RESULT([$]{ac_t:- }[$]am_cv_proto_iconv) AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1, [Define as const if the declaration of iconv() needs const.]) fi ]) gnunet-0.9.3/m4/inttypes_h.m40000644000175000017500000000164411317762540012727 00000000000000# inttypes_h.m4 serial 7 dnl Copyright (C) 1997-2004, 2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Paul Eggert. # Define HAVE_INTTYPES_H_WITH_UINTMAX if exists, # doesn't clash with , and declares uintmax_t. AC_DEFUN([gl_AC_HEADER_INTTYPES_H], [ AC_CACHE_CHECK([for inttypes.h], gl_cv_header_inttypes_h, [AC_TRY_COMPILE( [#include #include ], [uintmax_t i = (uintmax_t) -1; return !i;], gl_cv_header_inttypes_h=yes, gl_cv_header_inttypes_h=no)]) if test $gl_cv_header_inttypes_h = yes; then AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H_WITH_UINTMAX, 1, [Define if exists, doesn't clash with , and declares uintmax_t. ]) fi ]) gnunet-0.9.3/m4/lt~obsolete.m40000644000175000017500000001311311762217203013100 00000000000000# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 4 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) gnunet-0.9.3/m4/lcmessage.m40000644000175000017500000000240411317762540012477 00000000000000# lcmessage.m4 serial 4 (gettext-0.14.2) dnl Copyright (C) 1995-2002, 2004-2005 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1995. # Check whether LC_MESSAGES is available in . AC_DEFUN([gt_LC_MESSAGES], [ AC_CACHE_CHECK([for LC_MESSAGES], gt_cv_val_LC_MESSAGES, [AC_TRY_LINK([#include ], [return LC_MESSAGES], gt_cv_val_LC_MESSAGES=yes, gt_cv_val_LC_MESSAGES=no)]) if test $gt_cv_val_LC_MESSAGES = yes; then AC_DEFINE(HAVE_LC_MESSAGES, 1, [Define if your file defines LC_MESSAGES.]) fi ]) gnunet-0.9.3/acinclude.m40000644000175000017500000000275711260753602012152 00000000000000# See: http://gcc.gnu.org/ml/gcc/2000-05/msg01141.html AC_DEFUN([CHECK_PTHREAD], [ AC_CHECK_LIB(pthread,pthread_create, [ PTHREAD_CPPFLAGS= PTHREAD_LDFLAGS= PTHREAD_LIBS=-lpthread ],[ AC_MSG_CHECKING(if compiler supports -pthread) save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS -pthread" AC_TRY_LINK( [ #include ],[ pthread_create(0,0,0,0); ],[ AC_MSG_RESULT(yes) PTHREAD_CPPFLAGS=-pthread PTHREAD_LDFLAGS=-pthread PTHREAD_LIBS= ],[ AC_MSG_RESULT(no) AC_MSG_CHECKING(if compiler supports -pthreads) save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$save_CPPFLAGS -pthreads" AC_TRY_LINK( [ #include ],[ pthread_create(0,0,0,0); ],[ AC_MSG_RESULT(yes) PTHREAD_CPPFLAGS=-pthreads PTHREAD_LDFLAGS=-pthreads PTHREAD_LIBS= ],[ AC_MSG_RESULT(no) AC_MSG_CHECKING(if compiler supports -threads) save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$save_CPPFLAGS -threads" AC_TRY_LINK( [ #include ],[ pthread_create(0,0,0,0); ],[ AC_MSG_RESULT(yes) PTHREAD_CPPFLAGS=-threads PTHREAD_LDFLAGS=-threads PTHREAD_LIBS= ],[ AC_MSG_ERROR([Your system is not supporting pthreads!]) ]) ]) ]) CPPFLAGS="$save_CPPFLAGS" ]) ]) dnl Checks for all prerequisites of the intl subdirectory, dnl except for INTL_LIBTOOL_SUFFIX_PREFIX (and possibly LIBTOOL), INTLOBJS, dnl USE_INCLUDED_LIBINTL, BUILD_INCLUDED_LIBINTL. AC_DEFUN([AM_INTL_SUBDIR], [])gnunet-0.9.3/COPYING0000644000175000017500000010451311260753602011005 00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . gnunet-0.9.3/AUTHORS0000644000175000017500000000730211746441621011024 00000000000000Program: GNUnet Homepage: https://gnunet.org/ Maintainer: Christian Grothoff Bug reports: https://gnunet.org/bugs/ Security related bug reports: security@gnunet.org License: some GPLv2+, mostly GPLv3+ Primary developers (0.9.x series): Bart Polot Christian Grothoff David Brodski Heikki Lindholm LRN Matthias Wachs Milan Bouchet-Valat Nathan Evans Nils Durner Safey Allah Mohammed Philipp Tölke , Vitaly Minko Sree Harsha Totakura --- http://sreeharsha.totakura.in/ Martin Schanzenbach Maximilian Szengel Code contributions also came from: Adam Warrington [ UPnP ] Alex Harper [ OS X CPU load ] Andrew McDonald [ SHA-512] Antti Salonen Blake Matheny Clytie Siddall David Kuehling Enrico Scholz Eric Haumant Eric Noack Felix von Leitner [ diet libc snprintf for win32 ] Gabor Adam Toth Gerd Knorr Glenn McGrath Hendrik Pagenhardt Heikki Lindholm Igor Wronsky Ioana Patrascu Jacob Appelbaum Jake Dust James Blackwell Jean-Luc Cooke [ SHA-512] Jussi Eloranta Jürgen Appel Kevin Vandersloot [original code of gnome-system-monitor] Krista Bennett Grothoff Kyle McMartin [ SHA-512] Larry Waldo Ludovic Courtès Marko Räihä Michael John Wensley Paul Ruth Renaldo Ferreira Risto Saarelma Roman Zippel Romain Lievin sheda Simo Viitanen Tiberius Stef Tomi Tukiainen Tuomas Toivonen Tzvetan Horozov Uli Luckas Vasil Dimov Werner Koch [original code of libgcrypt] Translations (webpage, documentation, as far as known): Chinese : Di Ma Danish : Jens Palsberg Deutsch : Christian Grothoff , Nils Durner French : Mathieu , Eric Haumant Milan Japanese : Hiroshi Yamauchi Polish : Adam Welc Romaneste : Bogdan Carbunar Kinyarwanda: Steven Michael Murphy Vietnamese : Phan Vinh Thinh and Clytie Siddall Swedish : Daniel Nylander Spanish : Miguel Angel Arruga Vivas Turkish : Nilgün Belma Bugüner Logos: GNU in Net : Christian Muellner GNU with Net : Christian Muellner AFS Face : Alex Jones new GNU in Net: Nicklas Larsson Maintainers: FreeBSD : Kirill Ponomarew Debian GNU/Linux: Daniel Baumann OS X : Jussi Eloranta If you have contributed and are not listed here, please notify one of the maintainers in order to be added. gnunet-0.9.3/configure0000755000175000017500000340002211762217207011661 00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.67 for gnunet 0.9.3. # # Report bugs to . # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software # Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and bug-gnunet@gnu.org $0: about your system, including any error possibly output $0: before this message. Then install a modern shell, or $0: manually run the script under such a shell if you do $0: have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" # Check that we are running under the correct shell. SHELL=${CONFIG_SHELL-/bin/sh} case X$lt_ECHO in X*--fallback-echo) # Remove one level of quotation (which was required for Make). ECHO=`echo "$lt_ECHO" | sed 's,\\\\\$\\$0,'$0','` ;; esac ECHO=${lt_ECHO-echo} if test "X$1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X$1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then # Yippee, $ECHO works! : else # Restart under the correct shell. exec $SHELL "$0" --no-reexec ${1+"$@"} fi if test "X$1" = X--fallback-echo; then # used as fallback echo shift cat <<_LT_EOF $* _LT_EOF exit 0 fi # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test -z "$lt_ECHO"; then if test "X${echo_test_string+set}" != Xset; then # find a string as large as possible, as long as the shell can cope with it for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... if { echo_test_string=`eval $cmd`; } 2>/dev/null && { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null then break fi done fi if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then : else # The Solaris, AIX, and Digital Unix default echo programs unquote # backslashes. This makes it impossible to quote backslashes using # echo "$something" | sed 's/\\/\\\\/g' # # So, first we look for a working echo in the user's PATH. lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for dir in $PATH /usr/ucb; do IFS="$lt_save_ifs" if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then ECHO="$dir/echo" break fi done IFS="$lt_save_ifs" if test "X$ECHO" = Xecho; then # We didn't find a better echo, so look for alternatives. if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # This shell has a builtin print -r that does the trick. ECHO='print -r' elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && test "X$CONFIG_SHELL" != X/bin/ksh; then # If we have ksh, try running configure again with it. ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} export ORIGINAL_CONFIG_SHELL CONFIG_SHELL=/bin/ksh export CONFIG_SHELL exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"} else # Try using printf. ECHO='printf %s\n' if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # Cool, printf works : elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL export CONFIG_SHELL SHELL="$CONFIG_SHELL" export SHELL ECHO="$CONFIG_SHELL $0 --fallback-echo" elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then ECHO="$CONFIG_SHELL $0 --fallback-echo" else # maybe with a smaller string... prev=: for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null then break fi prev="$cmd" done if test "$prev" != 'sed 50q "$0"'; then echo_test_string=`eval $prev` export echo_test_string exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} else # Oops. We lost completely, so just stick with echo. ECHO=echo fi fi fi fi fi fi # Copy echo and quote the copy suitably for passing to libtool from # the Makefile, instead of quoting the original, which is used later. lt_ECHO=$ECHO if test "X$lt_ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then lt_ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" fi lt_ltdl_dir='libltdl' lt_dlopen_dir="$lt_ltdl_dir" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='gnunet' PACKAGE_TARNAME='gnunet' PACKAGE_VERSION='0.9.3' PACKAGE_STRING='gnunet 0.9.3' PACKAGE_BUGREPORT='bug-gnunet@gnu.org' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" enable_option_checking=no gt_needs= ac_subst_vars='ltdl_LTLIBOBJS ltdl_LIBOBJS am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS USE_COVERAGE_FALSE USE_COVERAGE_TRUE HAVE_EXPERIMENTAL_FALSE HAVE_EXPERIMENTAL_TRUE HAVE_BENCHMARKS_FALSE HAVE_BENCHMARKS_TRUE JAVAPORT HAVE_EXPENSIVE_TESTS_FALSE HAVE_EXPENSIVE_TESTS_TRUE MONKEYPREFIX ENABLE_MONKEY_FALSE ENABLE_MONKEY_TRUE ENABLE_TEST_RUN_FALSE ENABLE_TEST_RUN_TRUE GNUNETDNS_GROUP HAVE_SUDO_FALSE HAVE_SUDO_TRUE SUDO_BINARY DLLDIR LIBPREFIX EXT_LIBS EXT_LIB_PATH GN_LIBINTL GN_INTLINCL GN_PLUGIN_LDFLAGS GN_LIB_LDFLAGS WANT_FRAMEWORK_FALSE WANT_FRAMEWORK_TRUE GN_DAEMON_CONFIG_DIR GN_DAEMON_HOME_DIR GN_USER_HOME_DIR LIBOBJS POSUB LTLIBINTL LIBINTL INTLLIBS INTL_MACOSX_LIBS MSGMERGE XGETTEXT_015 XGETTEXT GMSGFMT_015 MSGFMT_015 GMSGFMT MSGFMT USE_NLS HAVE_PYTHON_PEXPECT_FALSE HAVE_PYTHON_PEXPECT_TRUE HAVE_PYTHON_FALSE HAVE_PYTHON_TRUE pkgpyexecdir pyexecdir pkgpythondir pythondir PYTHON_PLATFORM PYTHON_EXEC_PREFIX PYTHON_PREFIX PYTHON_VERSION PYTHON HAVE_MHD_FALSE HAVE_MHD_TRUE HAVE_MYSQLE_FALSE HAVE_MYSQLE_TRUE HAVE_MYSQL_FALSE HAVE_MYSQL_TRUE MYSQL_CPPFLAGS MYSQL_LDFLAGS HAVE_ZLIB_FALSE HAVE_ZLIB_TRUE POSTGRES_LDFLAGS POSTGRES_CPPFLAGS HAVE_POSTGRES_FALSE HAVE_POSTGRES_TRUE SQLITE_LDFLAGS SQLITE_CPPFLAGS HAVE_SQLITE_FALSE HAVE_SQLITE_TRUE LTLIBUNISTRING LIBUNISTRING HAVE_LIBUNISTRING LTLIBICONV LIBICONV HAVE_GLIBCNSS_FALSE HAVE_GLIBCNSS_TRUE HAVE_LIBGLPK_FALSE HAVE_LIBGLPK_TRUE LIBCURL LIBCURL_CPPFLAGS _libcurl_config LIBGCRYPT_LIBS LIBGCRYPT_CFLAGS LIBGCRYPT_CONFIG build_target LINUX_FALSE LINUX_TRUE OPENBSD_FALSE OPENBSD_TRUE XFREEBSD_FALSE XFREEBSD_TRUE SOLARIS_FALSE SOLARIS_TRUE MINGW_FALSE MINGW_TRUE CYGWIN_FALSE CYGWIN_TRUE DARWIN_FALSE DARWIN_TRUE UNIXONLY DEFAULT_INTERFACE X_EXTRA_LIBS X_LIBS X_PRE_LIBS X_CFLAGS XMKMF LTDLOPEN LT_CONFIG_H subdirs CONVENIENCE_LTDL_FALSE CONVENIENCE_LTDL_TRUE INSTALL_LTDL_FALSE INSTALL_LTDL_TRUE ARGZ_H sys_symbol_underscore LIBADD_DL LT_DLPREOPEN LIBADD_DLD_LINK LIBADD_SHL_LOAD LIBADD_DLOPEN LT_DLLOADERS INCLTDL LTDLINCL LTDLDEPS LIBLTDL CXXCPP OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL lt_ECHO RANLIB AR NM ac_ct_DUMPBIN DUMPBIN LD FGREP EGREP GREP SED LIBTOOL OBJDUMP DLLTOOL AS LN_S am__fastdepOBJC_FALSE am__fastdepOBJC_TRUE OBJCDEPMODE ac_ct_OBJC OBJCFLAGS OBJC am__fastdepCXX_FALSE am__fastdepCXX_TRUE CXXDEPMODE ac_ct_CXX CXXFLAGS CXX CPP am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC AM_BACKSLASH AM_DEFAULT_VERBOSITY am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_os target_vendor target_cpu target host_os host_vendor host_cpu host build_os build_vendor build_cpu build target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_dependency_tracking enable_static enable_shared with_pic enable_fast_install with_gnu_ld enable_libtool_lock with_included_ltdl with_ltdl_include with_ltdl_lib enable_ltdl_install enable_largefile with_x with_libgcrypt_prefix enable_gcc_hardening enable_linker_hardening enable_logging with_libcurl with_extractor enable_rpath with_libiconv_prefix with_libunistring_prefix with_sqlite with_postgres with_mysql enable_mysql_version_check with_microhttpd enable_nls with_libintl_prefix with_user_home_dir with_daemon_home_dir with_daemon_config_dir enable_framework with_sudo with_gnunetdns enable_testruns enable_monkey enable_expensivetests enable_javaports enable_benchmarks enable_experimental enable_windows_workarounds enable_coverage ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP CXX CXXFLAGS CCC OBJC OBJCFLAGS CXXCPP XMKMF' ac_subdirs_all='libltdl' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures gnunet 0.9.3 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/gnunet] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names X features: --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] --target=TARGET configure for building compilers for TARGET [HOST] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of gnunet 0.9.3:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: `make V=1') --disable-silent-rules verbose build output (undo: `make V=0') --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors --enable-static[=PKGS] build static libraries [default=no] --enable-shared[=PKGS] build shared libraries [default=yes] --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) --enable-ltdl-install install libltdl --disable-largefile omit support for large files --enable-gcc-hardening enable compiler security checks --enable-linker-hardening enable linker security fixups --enable-logging[=value] Enable logging calls. Possible values: yes,no,verbose,veryverbose ('yes' is the default) --disable-rpath do not hardcode runtime library paths --disable-mysql-version-check do not check MySQL version --disable-nls do not use Native Language Support --enable-framework enable Mac OS X framework build helpers --disable-testruns disable running tests on make check (default is YES) --enable-monkey enable running with monkey --enable-expensivetests enable running expensive testcases --enable-javaports use non-zero ports for services with Java bindings (default is NO) --enable-benchmarks enable running benchmarks during make check --enable-experimental enable compiling experimental code --enable-windows_workarounds enable workarounds used on Windows (only useful for test cases) --enable-coverage compile the library with code coverage support Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-included-ltdl use the GNU ltdl sources included here --with-ltdl-include=DIR use the ltdl headers installed in DIR --with-ltdl-lib=DIR use the libltdl.la installed in DIR --with-x use the X Window System --with-libgcrypt-prefix=PFX prefix where LIBGCRYPT is installed (optional) --with-libcurl=PREFIX look for the curl library in PREFIX/lib and headers in PREFIX/include --with-extractor=PFX base of libextractor installation --with-gnu-ld assume the C compiler uses GNU ld default=no --with-libiconv-prefix[=DIR] search for libiconv in DIR/include and DIR/lib --without-libiconv-prefix don't search for libiconv in includedir and libdir --with-libunistring-prefix[=DIR] search for libunistring in DIR/include and DIR/lib --without-libunistring-prefix don't search for libunistring in includedir and libdir --with-sqlite=PFX base of SQLite installation --with-postgres=PFX base of postgres installation --with-mysql=PFX base of MySQL installation --with-microhttpd=PFX base of libmicrohttpd installation --with-libintl-prefix[=DIR] search for libintl in DIR/include and DIR/lib --without-libintl-prefix don't search for libintl in includedir and libdir --with-user-home-dir=DIR default user home directory (~/.gnunet) --with-daemon-home-dir=DIR default daemon home directory (/var/lib/gnunet) --with-daemon-config-dir=DIR default daemon config directory (/etc) --with-sudo=PATH path to sudo binary (or just yes) --with-gnunetdns=GRPNAME name for gnunetdns group Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor CXX C++ compiler command CXXFLAGS C++ compiler flags OBJC Objective C compiler command OBJCFLAGS Objective C compiler flags CXXCPP C++ preprocessor XMKMF Path to xmkmf, Makefile generator for X Window System Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF gnunet configure 0.9.3 generated by GNU Autoconf 2.67 Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_objc_try_compile LINENO # ----------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_objc_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_objc_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_objc_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_compile # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_func # ac_fn_cxx_try_cpp LINENO # ------------------------ # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_cxx_try_cpp # ac_fn_cxx_try_link LINENO # ------------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_cxx_try_link # ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES # --------------------------------------------- # Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR # accordingly. ac_fn_c_check_decl () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack as_decl_name=`echo $2|sed 's/ *(.*//'` as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 $as_echo_n "checking whether $as_decl_name is declared... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { #ifndef $as_decl_name #ifdef __cplusplus (void) $as_decl_use; #else (void) $as_decl_name; #endif #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_decl # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_type # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval "test \"\${$3+set}\"" = set; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## --------------------------------- ## ## Report this to bug-gnunet@gnu.org ## ## --------------------------------- ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_mongrel # ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES # ---------------------------------------------------- # Tries to find if the field MEMBER exists in type AGGR, after including # INCLUDES, setting cache variable VAR accordingly. ac_fn_c_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 $as_echo_n "checking for $2.$3... " >&6; } if eval "test \"\${$4+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (sizeof ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else eval "$4=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$4 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_member # ac_fn_c_compute_int LINENO EXPR VAR INCLUDES # -------------------------------------------- # Tries to find the compile-time value of EXPR in a program that includes # INCLUDES, setting VAR accordingly. Returns whether the value could be # computed ac_fn_c_compute_int () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0 ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=0 ac_mid=0 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid; break else as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0 ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=-1 ac_mid=-1 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=$ac_mid; break else as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid else as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in #(( ?*) eval "$3=\$ac_lo"; ac_retval=0 ;; '') ac_retval=1 ;; esac else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 static long int longval () { return $2; } static unsigned long int ulongval () { return $2; } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (($2) < 0) { long int i = longval (); if (i != ($2)) return 1; fprintf (f, "%ld", i); } else { unsigned long int i = ulongval (); if (i != ($2)) return 1; fprintf (f, "%lu", i); } /* Do not output a trailing newline, as this causes \r\n confusion on some platforms. */ return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : echo >>conftest.val; read $3 config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by gnunet $as_me 0.9.3, which was generated by GNU Autoconf 2.67. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5 ; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi gt_needs="$gt_needs " # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if test "${ac_cv_build+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5 ;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if test "${ac_cv_host+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5 ;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 $as_echo_n "checking target system type... " >&6; } if test "${ac_cv_target+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "x$target_alias" = x; then ac_cv_target=$ac_cv_host else ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 $as_echo "$ac_cv_target" >&6; } case $ac_cv_target in *-*-*) ;; *) as_fn_error $? "invalid value of canonical target" "$LINENO" 5 ;; esac target=$ac_cv_target ac_save_IFS=$IFS; IFS='-' set x $ac_cv_target shift target_cpu=$1 target_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: target_os=$* IFS=$ac_save_IFS case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac # The aliases save the names the user supplied, while $host etc. # will get canonicalized. test -n "$target_alias" && test "$program_prefix$program_suffix$program_transform_name" = \ NONENONEs,x,x, && program_prefix=${target_alias}- am__api_version='1.11' # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Just in case sleep 1 echo timestamp > conftest.file # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5 ;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: \`$srcdir'" "$LINENO" 5 ;; esac # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi rm -f conftest.file if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} fi if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_STRIP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if test "${ac_cv_path_mkdir+set}" = set; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } mkdir_p="$MKDIR_P" case $mkdir_p in [\\/$]* | ?:[\\/]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_AWK+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE=gnunet VERSION=0.9.3 cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. AMTAR=${AMTAR-"${am_missing_run}tar"} am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=0;; esac AM_BACKSLASH='\' ac_config_headers="$ac_config_headers gnunet_config.h" for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_AWK+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5 ; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5 ; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5 ; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5 ; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if test "${ac_cv_objext+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5 ; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if test "${ac_cv_c_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if test "${ac_cv_prog_cc_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if test "${ac_cv_prog_cc_c89+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from `make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test "${ac_cv_prog_CPP+set}" = set; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5 ; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if test "${ac_cv_cxx_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if test "${ac_cv_prog_cxx_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CXX" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CXX_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CXX_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CXX_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 $as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then am__fastdepCXX_TRUE= am__fastdepCXX_FALSE='#' else am__fastdepCXX_TRUE='#' am__fastdepCXX_FALSE= fi ac_ext=m ac_cpp='$OBJCPP $CPPFLAGS' ac_compile='$OBJC -c $OBJCFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$OBJC -o conftest$ac_exeext $OBJCFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_objc_compiler_gnu if test -n "$ac_tool_prefix"; then for ac_prog in gcc objcc objc cc CC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_OBJC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJC"; then ac_cv_prog_OBJC="$OBJC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_OBJC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OBJC=$ac_cv_prog_OBJC if test -n "$OBJC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJC" >&5 $as_echo "$OBJC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$OBJC" && break done fi if test -z "$OBJC"; then ac_ct_OBJC=$OBJC for ac_prog in gcc objcc objc cc CC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_OBJC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJC"; then ac_cv_prog_ac_ct_OBJC="$ac_ct_OBJC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_OBJC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OBJC=$ac_cv_prog_ac_ct_OBJC if test -n "$ac_ct_OBJC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJC" >&5 $as_echo "$ac_ct_OBJC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_OBJC" && break done if test "x$ac_ct_OBJC" = x; then OBJC="gcc" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJC=$ac_ct_OBJC fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for Objective C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU Objective C compiler" >&5 $as_echo_n "checking whether we are using the GNU Objective C compiler... " >&6; } if test "${ac_cv_objc_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_objc_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_objc_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objc_compiler_gnu" >&5 $as_echo "$ac_cv_objc_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GOBJC=yes else GOBJC= fi ac_test_OBJCFLAGS=${OBJCFLAGS+set} ac_save_OBJCFLAGS=$OBJCFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $OBJC accepts -g" >&5 $as_echo_n "checking whether $OBJC accepts -g... " >&6; } if test "${ac_cv_prog_objc_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_objc_werror_flag=$ac_objc_werror_flag ac_objc_werror_flag=yes ac_cv_prog_objc_g=no OBJCFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_objc_try_compile "$LINENO"; then : ac_cv_prog_objc_g=yes else OBJCFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_objc_try_compile "$LINENO"; then : else ac_objc_werror_flag=$ac_save_objc_werror_flag OBJCFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_objc_try_compile "$LINENO"; then : ac_cv_prog_objc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_objc_werror_flag=$ac_save_objc_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_objc_g" >&5 $as_echo "$ac_cv_prog_objc_g" >&6; } if test "$ac_test_OBJCFLAGS" = set; then OBJCFLAGS=$ac_save_OBJCFLAGS elif test $ac_cv_prog_objc_g = yes; then if test "$GOBJC" = yes; then OBJCFLAGS="-g -O2" else OBJCFLAGS="-g" fi else if test "$GOBJC" = yes; then OBJCFLAGS="-O2" else OBJCFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$OBJC" am_compiler_list='gcc3 gcc' { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if test "${am_cv_OBJC_dependencies_compiler_type+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_OBJC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_OBJC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_OBJC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_OBJC_dependencies_compiler_type" >&5 $as_echo "$am_cv_OBJC_dependencies_compiler_type" >&6; } OBJCDEPMODE=depmode=$am_cv_OBJC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_OBJC_dependencies_compiler_type" = gcc3; then am__fastdepOBJC_TRUE= am__fastdepOBJC_FALSE='#' else am__fastdepOBJC_TRUE='#' am__fastdepOBJC_FALSE= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi if test "x$CC" != xcc; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC and cc understand -c and -o together" >&5 $as_echo_n "checking whether $CC and cc understand -c and -o together... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether cc understands -c and -o together" >&5 $as_echo_n "checking whether cc understands -c and -o together... " >&6; } fi set dummy $CC; ac_cc=`$as_echo "$2" | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` if eval "test \"\${ac_cv_prog_cc_${ac_cc}_c_o+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # We do the test twice because some compilers refuse to overwrite an # existing .o file with -o, though they will create one. ac_try='$CC -c conftest.$ac_ext -o conftest2.$ac_objext >&5' rm -f conftest2.* if { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -f conftest2.$ac_objext && { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then eval ac_cv_prog_cc_${ac_cc}_c_o=yes if test "x$CC" != xcc; then # Test first that cc exists at all. if { ac_try='cc -c conftest.$ac_ext >&5' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then ac_try='cc -c conftest.$ac_ext -o conftest2.$ac_objext >&5' rm -f conftest2.* if { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -f conftest2.$ac_objext && { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # cc works too. : else # cc exists but doesn't like -o. eval ac_cv_prog_cc_${ac_cc}_c_o=no fi fi fi else eval ac_cv_prog_cc_${ac_cc}_c_o=no fi rm -f core conftest* fi if eval test \$ac_cv_prog_cc_${ac_cc}_c_o = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "#define NO_MINUS_C_MINUS_O 1" >>confdefs.h fi # FIXME: we rely on the cache variable name because # there is no other way. set dummy $CC am_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o if test "$am_t" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi case `pwd` in *\ * | *\ *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 $as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac macro_version='2.2.6b' macro_revision='1.3017' ltmain="$ac_aux_dir/ltmain.sh" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if test "${ac_cv_path_SED+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 $as_echo "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if test "${ac_cv_path_GREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if test "${ac_cv_path_EGREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 $as_echo_n "checking for fgrep... " >&6; } if test "${ac_cv_path_FGREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 then ac_cv_path_FGREP="$GREP -F" else if test -z "$FGREP"; then ac_path_FGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in fgrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP case `"$ac_path_FGREP" --version 2>&1` in *GNU*) ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'FGREP' >> "conftest.nl" "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_FGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_FGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_FGREP"; then as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_FGREP=$FGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 $as_echo "$ac_cv_path_FGREP" >&6; } FGREP="$ac_cv_path_FGREP" test -z "$GREP" && GREP=grep # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if test "${lt_cv_path_LD+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if test "${lt_cv_prog_gnu_ld+set}" = set; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 $as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } if test "${lt_cv_path_NM+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 $as_echo "$lt_cv_path_NM" >&6; } if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$ac_tool_prefix"; then for ac_prog in "dumpbin -symbols" "link -dump -symbols" do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_DUMPBIN+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$DUMPBIN"; then ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DUMPBIN=$ac_cv_prog_DUMPBIN if test -n "$DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 $as_echo "$DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$DUMPBIN" && break done fi if test -z "$DUMPBIN"; then ac_ct_DUMPBIN=$DUMPBIN for ac_prog in "dumpbin -symbols" "link -dump -symbols" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_DUMPBIN+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DUMPBIN"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN if test -n "$ac_ct_DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 $as_echo "$ac_ct_DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_DUMPBIN" && break done if test "x$ac_ct_DUMPBIN" = x; then DUMPBIN=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DUMPBIN=$ac_ct_DUMPBIN fi fi if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if test "${lt_cv_nm_interface+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:6398: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:6401: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:6404: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 $as_echo "$lt_cv_nm_interface" >&6; } # find the maximum length of command line arguments { $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 $as_echo_n "checking the maximum length of command line arguments... " >&6; } if test "${lt_cv_sys_max_cmd_len+set}" = set; then : $as_echo_n "(cached) " >&6 else i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`$SHELL $0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ = "XX$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac fi if test -n $lt_cv_sys_max_cmd_len ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 $as_echo "$lt_cv_sys_max_cmd_len" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len : ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 $as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 $as_echo "$xsi_shell" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 $as_echo_n "checking whether the shell understands \"+=\"... " >&6; } lt_shell_append=no ( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 $as_echo "$lt_shell_append" >&6; } if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 $as_echo_n "checking for $LD option to reload object files... " >&6; } if test "${lt_cv_ld_reload_flag+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_reload_flag='-r' fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 $as_echo "$lt_cv_ld_reload_flag" >&6; } reload_flag=$lt_cv_ld_reload_flag case $reload_flag in "" | " "*) ;; *) reload_flag=" $reload_flag" ;; esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in darwin*) if test "$GCC" = yes; then reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi ;; esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_OBJDUMP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_OBJDUMP="objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi test -z "$OBJDUMP" && OBJDUMP=objdump { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 $as_echo_n "checking how to recognize dependent libraries... " >&6; } if test "${lt_cv_deplibs_check_method+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # `unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # which responds to the $file_magic_cmd with a given extended regex. # If you have `file' or equivalent on your system and you're not sure # whether `pass_all' will *always* work, you probably want this one. case $host_os in aix[4-9]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[45]*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. if ( file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[3-9]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be Linux ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 $as_echo "$lt_cv_deplibs_check_method" >&6; } file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_AR+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AR="${ac_tool_prefix}ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_AR"; then ac_ct_AR=$AR # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_AR+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_AR="ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi else AR="$ac_cv_prog_AR" fi test -z "$AR" && AR=ar test -z "$AR_FLAGS" && AR_FLAGS=cru if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_STRIP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi test -z "$STRIP" && STRIP=: if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_RANLIB+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi test -z "$RANLIB" && RANLIB=: # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" fi # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Check for command to grab the raw symbol name followed by C symbol from nm. { $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 $as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then : $as_echo_n "(cached) " >&6 else # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[BCDEGRST]' # Regexp to match symbols that can be accessed directly from C. sympat='\([_A-Za-z][_A-Za-z0-9]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[BCDT]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[ABCDGISTW]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[ABCDEGRST]' fi ;; irix* | nonstopux*) symcode='[BCDEGRST]' ;; osf*) symcode='[BCDEGQRST]' ;; solaris*) symcode='[BDRT]' ;; sco3.2v5*) symcode='[DT]' ;; sysv4.2uw2*) symcode='[DT]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[ABDT]' ;; sysv4) symcode='[DFNSTU]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[ABCDGIRSTW]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK '"\ " {last_section=section; section=\$ 3};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\""; } >&5 (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ const struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_save_LIBS="$LIBS" lt_save_CFLAGS="$CFLAGS" LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS="$lt_save_LIBS" CFLAGS="$lt_save_CFLAGS" else echo "cannot find nm_test_func in $nlist" >&5 fi else echo "cannot find nm_test_var in $nlist" >&5 fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 fi else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done fi if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } fi # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '#line 7596 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } if test "${lt_cv_cc_needs_belf+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_cc_needs_belf=yes else lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 $as_echo "$lt_cv_cc_needs_belf" >&6; } if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; sparc*-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) LD="${LD-ld} -m elf64_sparc" ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" case $host_os in rhapsody* | darwin*) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_DSYMUTIL+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$DSYMUTIL"; then ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DSYMUTIL=$ac_cv_prog_DSYMUTIL if test -n "$DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 $as_echo "$DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DSYMUTIL"; then ac_ct_DSYMUTIL=$DSYMUTIL # Extract the first word of "dsymutil", so it can be a program name with args. set dummy dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_DSYMUTIL+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DSYMUTIL"; then ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL if test -n "$ac_ct_DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 $as_echo "$ac_ct_DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DSYMUTIL" = x; then DSYMUTIL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DSYMUTIL=$ac_ct_DSYMUTIL fi else DSYMUTIL="$ac_cv_prog_DSYMUTIL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. set dummy ${ac_tool_prefix}nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_NMEDIT+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$NMEDIT"; then ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi NMEDIT=$ac_cv_prog_NMEDIT if test -n "$NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 $as_echo "$NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_NMEDIT"; then ac_ct_NMEDIT=$NMEDIT # Extract the first word of "nmedit", so it can be a program name with args. set dummy nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_NMEDIT+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_NMEDIT"; then ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_NMEDIT="nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT if test -n "$ac_ct_NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 $as_echo "$ac_ct_NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_NMEDIT" = x; then NMEDIT=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac NMEDIT=$ac_ct_NMEDIT fi else NMEDIT="$ac_cv_prog_NMEDIT" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. set dummy ${ac_tool_prefix}lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_LIPO+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$LIPO"; then ac_cv_prog_LIPO="$LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_LIPO="${ac_tool_prefix}lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LIPO=$ac_cv_prog_LIPO if test -n "$LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 $as_echo "$LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_LIPO"; then ac_ct_LIPO=$LIPO # Extract the first word of "lipo", so it can be a program name with args. set dummy lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_LIPO+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_LIPO"; then ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_LIPO="lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO if test -n "$ac_ct_LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 $as_echo "$ac_ct_LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_LIPO" = x; then LIPO=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LIPO=$ac_ct_LIPO fi else LIPO="$ac_cv_prog_LIPO" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. set dummy ${ac_tool_prefix}otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_OTOOL+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL"; then ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_OTOOL="${ac_tool_prefix}otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL=$ac_cv_prog_OTOOL if test -n "$OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 $as_echo "$OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL"; then ac_ct_OTOOL=$OTOOL # Extract the first word of "otool", so it can be a program name with args. set dummy otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_OTOOL+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL"; then ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_OTOOL="otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL if test -n "$ac_ct_OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 $as_echo "$ac_ct_OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL" = x; then OTOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL=$ac_ct_OTOOL fi else OTOOL="$ac_cv_prog_OTOOL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. set dummy ${ac_tool_prefix}otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_OTOOL64+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL64"; then ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL64=$ac_cv_prog_OTOOL64 if test -n "$OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 $as_echo "$OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL64"; then ac_ct_OTOOL64=$OTOOL64 # Extract the first word of "otool64", so it can be a program name with args. set dummy otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_OTOOL64+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL64"; then ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_OTOOL64="otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 if test -n "$ac_ct_OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 $as_echo "$ac_ct_OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL64" = x; then OTOOL64=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL64=$ac_ct_OTOOL64 fi else OTOOL64="$ac_cv_prog_OTOOL64" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 $as_echo_n "checking for -single_module linker flag... " >&6; } if test "${lt_cv_apple_cc_single_mod+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&5 $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 fi rm -rf libconftest.dylib* rm -f conftest.* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 $as_echo "$lt_cv_apple_cc_single_mod" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 $as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } if test "${lt_cv_ld_exported_symbols_list+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_ld_exported_symbols_list=yes else lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } case $host_os in rhapsody* | darwin1.[012]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[91]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[012]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if test "${ac_cv_header_stdc+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in dlfcn.h do : ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default " if test "x$ac_cv_header_dlfcn_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLFCN_H 1 _ACEOF fi done ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if test "${ac_cv_cxx_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if test "${ac_cv_prog_cxx_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CXX" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CXX_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CXX_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CXX_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 $as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then am__fastdepCXX_TRUE= am__fastdepCXX_FALSE='#' else am__fastdepCXX_TRUE='#' am__fastdepCXX_FALSE= fi if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 $as_echo_n "checking how to run the C++ preprocessor... " >&6; } if test -z "$CXXCPP"; then if test "${ac_cv_prog_CXXCPP+set}" = set; then : $as_echo_n "(cached) " >&6 else # Double quotes because CXXCPP needs to be expanded for CXXCPP in "$CXX -E" "/lib/cpp" do ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CXXCPP=$CXXCPP fi CXXCPP=$ac_cv_prog_CXXCPP else ac_cv_prog_CXXCPP=$CXXCPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 $as_echo "$CXXCPP" >&6; } ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} _lt_caught_CXX_error=yes; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu else _lt_caught_CXX_error=yes fi # Set options # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac else enable_static=no fi enable_dlopen=yes enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args. set dummy ${ac_tool_prefix}as; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_AS+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$AS"; then ac_cv_prog_AS="$AS" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AS="${ac_tool_prefix}as" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AS=$ac_cv_prog_AS if test -n "$AS"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AS" >&5 $as_echo "$AS" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_AS"; then ac_ct_AS=$AS # Extract the first word of "as", so it can be a program name with args. set dummy as; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_AS+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AS"; then ac_cv_prog_ac_ct_AS="$ac_ct_AS" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_AS="as" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AS=$ac_cv_prog_ac_ct_AS if test -n "$ac_ct_AS"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AS" >&5 $as_echo "$ac_ct_AS" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_AS" = x; then AS="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AS=$ac_ct_AS fi else AS="$ac_cv_prog_AS" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_DLLTOOL+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 $as_echo "$DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLTOOL"; then ac_ct_DLLTOOL=$DLLTOOL # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_DLLTOOL+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_DLLTOOL="dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 $as_echo "$ac_ct_DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DLLTOOL=$ac_ct_DLLTOOL fi else DLLTOOL="$ac_cv_prog_DLLTOOL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_OBJDUMP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_OBJDUMP="objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi ;; esac test -z "$AS" && AS=as test -z "$DLLTOOL" && DLLTOOL=dlltool test -z "$OBJDUMP" && OBJDUMP=objdump # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac else enable_shared=yes fi # Check whether --with-pic was given. if test "${with_pic+set}" = set; then : withval=$with_pic; pic_mode="$withval" else pic_mode=default fi test -z "$pic_mode" && pic_mode=default # Check whether --enable-fast-install was given. if test "${enable_fast_install+set}" = set; then : enableval=$enable_fast_install; p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac else enable_fast_install=yes fi # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' test -z "$LN_S" && LN_S="ln -s" if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 $as_echo_n "checking for objdir... " >&6; } if test "${lt_cv_objdir+set}" = set; then : $as_echo_n "(cached) " >&6 else rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 $as_echo "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir cat >>confdefs.h <<_ACEOF #define LT_OBJDIR "$lt_cv_objdir/" _ACEOF case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='s/\(["`$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 $as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } if test "${lt_cv_path_MAGIC_CMD+set}" = set; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/${ac_tool_prefix}file; then lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 $as_echo_n "checking for file... " >&6; } if test "${lt_cv_path_MAGIC_CMD+set}" = set; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/file; then lt_cv_path_MAGIC_CMD="$ac_dir/file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else MAGIC_CMD=: fi fi fi ;; esac # Use C for the default configuration in the libtool script lt_save_CC="$CC" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o objext=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then lt_prog_compiler_no_builtin_flag= if test "$GCC" = yes; then lt_prog_compiler_no_builtin_flag=' -fno-builtin' { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:9811: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:9815: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl= lt_prog_compiler_pic= lt_prog_compiler_static= { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if test "$GCC" = yes; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) lt_prog_compiler_pic='-fPIC' ;; esac ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic=-Kconform_pic fi ;; *) lt_prog_compiler_pic='-fPIC' ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; # Lahey Fortran 8.1. lf95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='--shared' lt_prog_compiler_static='--static' ;; pgcc* | pgf77* | pgf90* | pgf95*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; ccc*) lt_prog_compiler_wl='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; xl*) # IBM XL C 8.0/Fortran 10.1 on PPC lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-qpic' lt_prog_compiler_static='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Wl,' ;; *Sun\ F*) # Sun Fortran 8.3 passes all unrecognized flags to the linker lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='' ;; esac ;; esac ;; newsos6) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static='-non_shared' ;; rdos*) lt_prog_compiler_static='-non_shared' ;; solaris*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in f77* | f90* | f95*) lt_prog_compiler_wl='-Qoption ld ';; *) lt_prog_compiler_wl='-Wl,';; esac ;; sunos4*) lt_prog_compiler_wl='-Qoption ld ' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; unicos*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_can_build_shared=no ;; uts4*) lt_prog_compiler_pic='-pic' lt_prog_compiler_static='-Bstatic' ;; *) lt_prog_compiler_can_build_shared=no ;; esac fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5 $as_echo "$lt_prog_compiler_pic" >&6; } # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if test "${lt_cv_prog_compiler_pic_works+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:10150: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:10154: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 $as_echo "$lt_cv_prog_compiler_pic_works" >&6; } if test x"$lt_cv_prog_compiler_pic_works" = xyes; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; esac else lt_prog_compiler_pic= lt_prog_compiler_can_build_shared=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if test "${lt_cv_prog_compiler_static_works+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works=yes fi else lt_cv_prog_compiler_static_works=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 $as_echo "$lt_cv_prog_compiler_static_works" >&6; } if test x"$lt_cv_prog_compiler_static_works" = xyes; then : else lt_prog_compiler_static= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if test "${lt_cv_prog_compiler_c_o+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:10255: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:10259: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if test "${lt_cv_prog_compiler_c_o+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:10310: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:10314: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag= always_export_symbols=no archive_cmds= archive_expsym_cmds= compiler_needs_object=no enable_shared_with_static_runtimes=no export_dynamic_flag_spec= export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' hardcode_automatic=no hardcode_direct=no hardcode_direct_absolute=no hardcode_libdir_flag_spec= hardcode_libdir_flag_spec_ld= hardcode_libdir_separator= hardcode_minus_L=no hardcode_shlibpath_var=unsupported inherit_rpath=no link_all_deplibs=unknown module_cmds= module_expsym_cmds= old_archive_from_new_cmds= old_archive_from_expsyms_cmds= thread_safe_flag_spec= whole_archive_flag_spec= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; linux* | k*bsd*-gnu) link_all_deplibs=no ;; esac ld_shlibs=yes if test "$with_gnu_ld" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[3-9]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.9.1, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to modify your PATH *** so that a non-GNU linker is found, and then restart. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs=no fi ;; interix[3-9]*) hardcode_direct=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag= tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 whole_archive_flag_spec= tmp_sharedflag='--shared' ;; xl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' hardcode_libdir_flag_spec= hardcode_libdir_flag_spec_ld='-rpath $libdir' archive_cmds='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else ld_shlibs=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac ;; sunos4*) archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct=yes hardcode_shlibpath_var=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = no; then runpath_var= hardcode_libdir_flag_spec= export_dynamic_flag_spec= whole_archive_flag_spec= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag=unsupported always_export_symbols=yes archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix[4-9]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds='' hardcode_direct=yes hardcode_direct_absolute=yes hardcode_libdir_separator=':' link_all_deplibs=yes file_list_spec='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi link_all_deplibs=no else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi export_dynamic_flag_spec='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an # empty executable. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/ p } }' aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag="-z nodefs" archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/ p } }' aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag=' ${wl}-bernotok' allow_undefined_flag=' ${wl}-berok' # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec='$convenience' archive_cmds_need_lc=yes # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; bsdi[45]*) export_dynamic_flag_spec=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_from_new_cmds='true' # FIXME: Should let the user specify the lib program. old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' fix_srcfile_path='`cygpath -w "$srcfile"`' enable_shared_with_static_runtimes=yes ;; darwin* | rhapsody*) archive_cmds_need_lc=no hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported whole_archive_flag_spec='' link_all_deplibs=yes allow_undefined_flag="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=echo archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" else ld_shlibs=no fi ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; freebsd1*) ld_shlibs=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9*) if test "$GCC" = yes; then archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes export_dynamic_flag_spec='${wl}-E' ;; hpux10*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_flag_spec_ld='+b $libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no hardcode_shlibpath_var=no ;; *) hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int foo(void) {} _ACEOF if ac_fn_c_try_link "$LINENO"; then : archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: inherit_rpath=yes link_all_deplibs=yes ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; newsos6) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: hardcode_shlibpath_var=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes hardcode_shlibpath_var=no hardcode_direct_absolute=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' else case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-R$libdir' ;; *) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi archive_cmds_need_lc='no' hardcode_libdir_separator=: ;; solaris*) no_undefined_flag=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else whole_archive_flag_spec='-z allextract$convenience -z defaultextract' fi ;; esac link_all_deplibs=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; sysv4) case $host_vendor in sni) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds='$CC -r -o $output$reload_objs' hardcode_direct=no ;; motorola) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; sysv4.3*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no export_dynamic_flag_spec='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag='${wl}-z,text' archive_cmds_need_lc=no hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag='${wl}-z,text' allow_undefined_flag='${wl}-z,nodefs' archive_cmds_need_lc=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-R,$libdir' hardcode_libdir_separator=':' link_all_deplibs=yes export_dynamic_flag_spec='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; *) ld_shlibs=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) export_dynamic_flag_spec='${wl}-Blargedynsym' ;; esac fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 $as_echo "$ld_shlibs" >&6; } test "$ld_shlibs" = no && can_build_shared=no with_gnu_ld=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc" in x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl pic_flag=$lt_prog_compiler_pic compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then archive_cmds_need_lc=no else archive_cmds_need_lc=yes fi allow_undefined_flag=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc" >&5 $as_echo "$archive_cmds_need_lc" >&6; } ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` else lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[lt_foo]++; } if (lt_freq[lt_foo] == 1) { print lt_foo; } }'` sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[4-9]*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[123]*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; interix[3-9]*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || test "X$hardcode_automatic" = "Xyes" ; then # We can hardcode non-existent directories. if test "$hardcode_direct" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && test "$hardcode_minus_L" != no; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 $as_echo "$hardcode_action" >&6; } if test "$hardcode_action" = relink || test "$inherit_rpath" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if test "${ac_cv_lib_dl_dlopen+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = x""yes; then : lt_cv_dlopen="shl_load" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if test "${ac_cv_lib_dld_shl_load+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = x""yes; then : lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" else ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = x""yes; then : lt_cv_dlopen="dlopen" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if test "${ac_cv_lib_dl_dlopen+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } if test "${ac_cv_lib_svld_dlopen+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = x""yes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } if test "${ac_cv_lib_dld_dld_link+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dld_link (); int main () { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = x""yes; then : lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" fi fi fi fi fi fi ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } if test "${lt_cv_dlopen_self+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line 12694 "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } if test "${lt_cv_dlopen_self_static+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line 12790 "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 $as_echo "$lt_cv_dlopen_self_static" >&6; } fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi striplib= old_striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac fi # Report which library types will actually be built { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 $as_echo "$can_build_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 $as_echo "$enable_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu archive_cmds_need_lc_CXX=no allow_undefined_flag_CXX= always_export_symbols_CXX=no archive_expsym_cmds_CXX= compiler_needs_object_CXX=no export_dynamic_flag_spec_CXX= hardcode_direct_CXX=no hardcode_direct_absolute_CXX=no hardcode_libdir_flag_spec_CXX= hardcode_libdir_flag_spec_ld_CXX= hardcode_libdir_separator_CXX= hardcode_minus_L_CXX=no hardcode_shlibpath_var_CXX=unsupported hardcode_automatic_CXX=no inherit_rpath_CXX=no module_cmds_CXX= module_expsym_cmds_CXX= link_all_deplibs_CXX=unknown old_archive_cmds_CXX=$old_archive_cmds no_undefined_flag_CXX= whole_archive_flag_spec_CXX= enable_shared_with_static_runtimes_CXX=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o objext_CXX=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_caught_CXX_error" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} compiler=$CC compiler_CXX=$CC for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' else lt_prog_compiler_no_builtin_flag_CXX= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if test "${lt_cv_path_LD+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if test "${lt_cv_prog_gnu_ld+set}" = set; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec_CXX= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } ld_shlibs_CXX=yes case $host_os in aix3*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aix[4-9]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds_CXX='' hardcode_direct_CXX=yes hardcode_direct_absolute_CXX=yes hardcode_libdir_separator_CXX=':' link_all_deplibs_CXX=yes file_list_spec_CXX='${wl}-f,' if test "$GXX" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct_CXX=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L_CXX=yes hardcode_libdir_flag_spec_CXX='-L$libdir' hardcode_libdir_separator_CXX= fi esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi export_dynamic_flag_spec_CXX='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. always_export_symbols_CXX=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag_CXX='-berok' # Determine the default libpath from the value encoded in an empty # executable. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/ p } }' aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag_CXX="-z nodefs" archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/ p } }' aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag_CXX=' ${wl}-bernotok' allow_undefined_flag_CXX=' ${wl}-berok' # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec_CXX='$convenience' archive_cmds_need_lc_CXX=yes # This is similar to how AIX traditionally builds its shared # libraries. archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag_CXX=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs_CXX=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec_CXX='-L$libdir' allow_undefined_flag_CXX=unsupported always_export_symbols_CXX=no enable_shared_with_static_runtimes_CXX=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs_CXX=no fi ;; darwin* | rhapsody*) archive_cmds_need_lc_CXX=no hardcode_direct_CXX=no hardcode_automatic_CXX=yes hardcode_shlibpath_var_CXX=unsupported whole_archive_flag_spec_CXX='' link_all_deplibs_CXX=yes allow_undefined_flag_CXX="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=echo archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" if test "$lt_cv_apple_cc_single_mod" != "yes"; then archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" fi else ld_shlibs_CXX=no fi ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; freebsd[12]*) # C++ shared libraries reported to be fairly broken before # switch to ELF ld_shlibs_CXX=no ;; freebsd-elf*) archive_cmds_need_lc_CXX=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions ld_shlibs_CXX=yes ;; gnu*) ;; hpux9*) hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' hardcode_libdir_separator_CXX=: export_dynamic_flag_spec_CXX='${wl}-E' hardcode_direct_CXX=yes hardcode_minus_L_CXX=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aCC*) archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; *) if test "$GXX" = yes; then archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' hardcode_libdir_separator_CXX=: case $host_cpu in hppa*64*|ia64*) ;; *) export_dynamic_flag_spec_CXX='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) hardcode_direct_CXX=no hardcode_shlibpath_var_CXX=no ;; *) hardcode_direct_CXX=yes hardcode_direct_absolute_CXX=yes hardcode_minus_L_CXX=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aCC*) case $host_cpu in hppa*64*) archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; interix[3-9]*) hardcode_direct_CXX=no hardcode_shlibpath_var_CXX=no hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' export_dynamic_flag_spec_CXX='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib' fi fi link_all_deplibs_CXX=yes ;; esac hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_CXX=: inherit_rpath_CXX=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac archive_cmds_need_lc_CXX=no hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [1-5]* | *pgcpp\ [1-5]*) prelink_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"' old_archive_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~ $RANLIB $oldlib' archive_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' archive_expsym_cmds_CXX='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; *) # Version 6 will use weak symbols archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; esac hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec_CXX='-rpath $libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; xl*) # IBM XL 8.0 on PPC, with GNU ld hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 no_undefined_flag_CXX=' -zdefs' archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' hardcode_libdir_flag_spec_CXX='-R$libdir' whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object_CXX=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='echo' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; m88k*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= hardcode_libdir_flag_spec_CXX='-R$libdir' hardcode_direct_CXX=yes hardcode_shlibpath_var_CXX=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) ld_shlibs_CXX=yes ;; openbsd2*) # C++ shared libraries are fairly broken ld_shlibs_CXX=no ;; openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct_CXX=yes hardcode_shlibpath_var_CXX=no hardcode_direct_absolute_CXX=yes archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' export_dynamic_flag_spec_CXX='${wl}-E' whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd=echo else ld_shlibs_CXX=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' hardcode_libdir_separator_CXX=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; cxx*) case $host in osf3*) allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' ;; *) allow_undefined_flag_CXX=' -expect_unresolved \*' archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' hardcode_libdir_flag_spec_CXX='-rpath $libdir' ;; esac hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; solaris*) case $cc_basename in CC*) # Sun C++ 4.2, 5.x and Centerline C++ archive_cmds_need_lc_CXX=yes no_undefined_flag_CXX=' -zdefs' archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' hardcode_libdir_flag_spec_CXX='-R$libdir' hardcode_shlibpath_var_CXX=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' ;; esac link_all_deplibs_CXX=yes output_verbose_link_cmd='echo' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then no_undefined_flag_CXX=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' fi hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag_CXX='${wl}-z,text' archive_cmds_need_lc_CXX=no hardcode_shlibpath_var_CXX=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag_CXX='${wl}-z,text' allow_undefined_flag_CXX='${wl}-z,nodefs' archive_cmds_need_lc_CXX=no hardcode_shlibpath_var_CXX=no hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir' hardcode_libdir_separator_CXX=':' link_all_deplibs_CXX=yes export_dynamic_flag_spec_CXX='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 $as_echo "$ld_shlibs_CXX" >&6; } test "$ld_shlibs_CXX" = no && can_build_shared=no GCC_CXX="$GXX" LD_CXX="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... # Dependencies to place before and after the object being linked: predep_objects_CXX= postdep_objects_CXX= predeps_CXX= postdeps_CXX= compiler_lib_search_path_CXX= cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case $p in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" || test $p = "-R"; then prev=$p continue else prev= fi if test "$pre_test_object_deps_done" = no; then case $p in -L* | -R*) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$compiler_lib_search_path_CXX"; then compiler_lib_search_path_CXX="${prev}${p}" else compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$postdeps_CXX"; then postdeps_CXX="${prev}${p}" else postdeps_CXX="${postdeps_CXX} ${prev}${p}" fi fi ;; *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$predep_objects_CXX"; then predep_objects_CXX="$p" else predep_objects_CXX="$predep_objects_CXX $p" fi else if test -z "$postdep_objects_CXX"; then postdep_objects_CXX="$p" else postdep_objects_CXX="$postdep_objects_CXX $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling CXX test program" fi $RM -f confest.$objext # PORTME: override above test on systems where it is broken case $host_os in interix[3-9]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. predep_objects_CXX= postdep_objects_CXX= postdeps_CXX= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then postdeps_CXX='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then postdeps_CXX='-library=Cstd -library=Crun' fi ;; esac ;; esac case " $postdeps_CXX " in *" -lc "*) archive_cmds_need_lc_CXX=no ;; esac compiler_lib_search_dirs_CXX= if test -n "${compiler_lib_search_path_CXX}"; then compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` fi lt_prog_compiler_wl_CXX= lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX= { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_CXX='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic_CXX='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic_CXX='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic_CXX='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all lt_prog_compiler_pic_CXX= ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic_CXX=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) lt_prog_compiler_pic_CXX='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic_CXX='-fPIC -shared' ;; *) lt_prog_compiler_pic_CXX='-fPIC' ;; esac else case $host_os in aix[4-9]*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_CXX='-Bstatic' else lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; dgux*) case $cc_basename in ec++*) lt_prog_compiler_pic_CXX='-KPIC' ;; ghcx*) # Green Hills C++ Compiler lt_prog_compiler_pic_CXX='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then lt_prog_compiler_pic_CXX='+Z' fi ;; aCC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic_CXX='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # KAI C++ Compiler lt_prog_compiler_wl_CXX='--backend -Wl,' lt_prog_compiler_pic_CXX='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64 which still supported -KPIC. lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-fPIC' lt_prog_compiler_static_CXX='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-fpic' lt_prog_compiler_static_CXX='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX='-non_shared' ;; xlc* | xlC*) # IBM XL 8.0 on PPC lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-qpic' lt_prog_compiler_static_CXX='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-Bstatic' lt_prog_compiler_wl_CXX='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) lt_prog_compiler_pic_CXX='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic_CXX='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) lt_prog_compiler_wl_CXX='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 lt_prog_compiler_pic_CXX='-pic' ;; cxx*) # Digital/Compaq C++ lt_prog_compiler_wl_CXX='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC*) # Sun C++ 4.2, 5.x and Centerline C++ lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-Bstatic' lt_prog_compiler_wl_CXX='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler lt_prog_compiler_pic_CXX='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x lt_prog_compiler_pic_CXX='-pic' lt_prog_compiler_static_CXX='-Bstatic' ;; lcc*) # Lucid lt_prog_compiler_pic_CXX='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 lt_prog_compiler_pic_CXX='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) lt_prog_compiler_can_build_shared_CXX=no ;; esac fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic_CXX= ;; *) lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_CXX" >&5 $as_echo "$lt_prog_compiler_pic_CXX" >&6; } # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } if test "${lt_cv_prog_compiler_pic_works_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works_CXX=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:14746: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:14750: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works_CXX=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 $as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; } if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then case $lt_prog_compiler_pic_CXX in "" | " "*) ;; *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; esac else lt_prog_compiler_pic_CXX= lt_prog_compiler_can_build_shared_CXX=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if test "${lt_cv_prog_compiler_static_works_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works_CXX=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works_CXX=yes fi else lt_cv_prog_compiler_static_works_CXX=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5 $as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; } if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then : else lt_prog_compiler_static_CXX= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o_CXX=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:14845: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:14849: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o_CXX=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 $as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o_CXX=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:14897: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:14901: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o_CXX=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 $as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' case $host_os in aix[4-9]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) export_symbols_cmds_CXX="$ltdll_cmds" ;; cygwin* | mingw* | cegcc*) export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;/^.*[ ]__nm__/s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' ;; linux* | k*bsd*-gnu) link_all_deplibs_CXX=no ;; *) export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 $as_echo "$ld_shlibs_CXX" >&6; } test "$ld_shlibs_CXX" = no && can_build_shared=no with_gnu_ld_CXX=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc_CXX" in x|xyes) # Assume -lc should be added archive_cmds_need_lc_CXX=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds_CXX in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl_CXX pic_flag=$lt_prog_compiler_pic_CXX compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag_CXX allow_undefined_flag_CXX= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then archive_cmds_need_lc_CXX=no else archive_cmds_need_lc_CXX=yes fi allow_undefined_flag_CXX=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc_CXX" >&5 $as_echo "$archive_cmds_need_lc_CXX" >&6; } ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[4-9]*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[123]*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; interix[3-9]*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action_CXX= if test -n "$hardcode_libdir_flag_spec_CXX" || test -n "$runpath_var_CXX" || test "X$hardcode_automatic_CXX" = "Xyes" ; then # We can hardcode non-existent directories. if test "$hardcode_direct_CXX" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no && test "$hardcode_minus_L_CXX" != no; then # Linking always hardcodes the temporary library directory. hardcode_action_CXX=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action_CXX=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action_CXX=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 $as_echo "$hardcode_action_CXX" >&6; } if test "$hardcode_action_CXX" = relink || test "$inherit_rpath_CXX" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi fi # test -n "$compiler" CC=$lt_save_CC LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test "$_lt_caught_CXX_error" != yes ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_commands="$ac_config_commands libtool" # Only expand once: { $as_echo "$as_me:${as_lineno-$LINENO}: checking which extension is used for runtime loadable modules" >&5 $as_echo_n "checking which extension is used for runtime loadable modules... " >&6; } if test "${libltdl_cv_shlibext+set}" = set; then : $as_echo_n "(cached) " >&6 else module=yes eval libltdl_cv_shlibext=$shrext_cmds fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libltdl_cv_shlibext" >&5 $as_echo "$libltdl_cv_shlibext" >&6; } if test -n "$libltdl_cv_shlibext"; then cat >>confdefs.h <<_ACEOF #define LT_MODULE_EXT "$libltdl_cv_shlibext" _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking which variable specifies run-time module search path" >&5 $as_echo_n "checking which variable specifies run-time module search path... " >&6; } if test "${lt_cv_module_path_var+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_module_path_var="$shlibpath_var" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_module_path_var" >&5 $as_echo "$lt_cv_module_path_var" >&6; } if test -n "$lt_cv_module_path_var"; then cat >>confdefs.h <<_ACEOF #define LT_MODULE_PATH_VAR "$lt_cv_module_path_var" _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the default library search path" >&5 $as_echo_n "checking for the default library search path... " >&6; } if test "${lt_cv_sys_dlsearch_path+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_sys_dlsearch_path="$sys_lib_dlsearch_path_spec" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_dlsearch_path" >&5 $as_echo "$lt_cv_sys_dlsearch_path" >&6; } if test -n "$lt_cv_sys_dlsearch_path"; then sys_dlsearch_path= for dir in $lt_cv_sys_dlsearch_path; do if test -z "$sys_dlsearch_path"; then sys_dlsearch_path="$dir" else sys_dlsearch_path="$sys_dlsearch_path$PATH_SEPARATOR$dir" fi done cat >>confdefs.h <<_ACEOF #define LT_DLSEARCH_PATH "$sys_dlsearch_path" _ACEOF fi LT_DLLOADERS= ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu LIBADD_DLOPEN= { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5 $as_echo_n "checking for library containing dlopen... " >&6; } if test "${ac_cv_search_dlopen+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF for ac_lib in '' dl; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_dlopen=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if test "${ac_cv_search_dlopen+set}" = set; then : break fi done if test "${ac_cv_search_dlopen+set}" = set; then : else ac_cv_search_dlopen=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5 $as_echo "$ac_cv_search_dlopen" >&6; } ac_res=$ac_cv_search_dlopen if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" $as_echo "#define HAVE_LIBDL 1" >>confdefs.h if test "$ac_cv_search_dlopen" != "none required" ; then LIBADD_DLOPEN="-ldl" fi libltdl_cv_lib_dl_dlopen="yes" LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if HAVE_DLFCN_H # include #endif int main () { dlopen(0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : $as_echo "#define HAVE_LIBDL 1" >>confdefs.h libltdl_cv_func_dlopen="yes" LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } if test "${ac_cv_lib_svld_dlopen+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = x""yes; then : $as_echo "#define HAVE_LIBDL 1" >>confdefs.h LIBADD_DLOPEN="-lsvld" libltdl_cv_func_dlopen="yes" LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la" fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi if test x"$libltdl_cv_func_dlopen" = xyes || test x"$libltdl_cv_lib_dl_dlopen" = xyes then lt_save_LIBS="$LIBS" LIBS="$LIBS $LIBADD_DLOPEN" for ac_func in dlerror do : ac_fn_c_check_func "$LINENO" "dlerror" "ac_cv_func_dlerror" if test "x$ac_cv_func_dlerror" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLERROR 1 _ACEOF fi done LIBS="$lt_save_LIBS" fi LIBADD_SHL_LOAD= ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = x""yes; then : $as_echo "#define HAVE_SHL_LOAD 1" >>confdefs.h LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if test "${ac_cv_lib_dld_shl_load+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = x""yes; then : $as_echo "#define HAVE_SHL_LOAD 1" >>confdefs.h LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la" LIBADD_SHL_LOAD="-ldld" fi fi case $host_os in darwin[1567].*) # We only want this for pre-Mac OS X 10.4. ac_fn_c_check_func "$LINENO" "_dyld_func_lookup" "ac_cv_func__dyld_func_lookup" if test "x$ac_cv_func__dyld_func_lookup" = x""yes; then : $as_echo "#define HAVE_DYLD 1" >>confdefs.h LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dyld.la" fi ;; beos*) LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}load_add_on.la" ;; cygwin* | mingw* | os2* | pw32*) ac_fn_c_check_decl "$LINENO" "cygwin_conv_path" "ac_cv_have_decl_cygwin_conv_path" "#include " if test "x$ac_cv_have_decl_cygwin_conv_path" = x""yes; then : ac_have_decl=1 else ac_have_decl=0 fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_CYGWIN_CONV_PATH $ac_have_decl _ACEOF LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}loadlibrary.la" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } if test "${ac_cv_lib_dld_dld_link+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dld_link (); int main () { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = x""yes; then : $as_echo "#define HAVE_DLD 1" >>confdefs.h LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dld_link.la" fi LT_DLPREOPEN= if test -n "$LT_DLLOADERS" then for lt_loader in $LT_DLLOADERS; do LT_DLPREOPEN="$LT_DLPREOPEN-dlpreopen $lt_loader " done $as_echo "#define HAVE_LIBDLLOADER 1" >>confdefs.h fi LIBADD_DL="$LIBADD_DLOPEN $LIBADD_SHL_LOAD" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _ prefix in compiled symbols" >&5 $as_echo_n "checking for _ prefix in compiled symbols... " >&6; } if test "${lt_cv_sys_symbol_underscore+set}" = set; then : $as_echo_n "(cached) " >&6 else lt_cv_sys_symbol_underscore=no cat > conftest.$ac_ext <<_LT_EOF void nm_test_func(){} int main(){nm_test_func;return 0;} _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. ac_nlist=conftest.nm if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $ac_nlist\""; } >&5 (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $ac_nlist) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "$ac_nlist"; then # See whether the symbols have a leading underscore. if grep '^. _nm_test_func' "$ac_nlist" >/dev/null; then lt_cv_sys_symbol_underscore=yes else if grep '^. nm_test_func ' "$ac_nlist" >/dev/null; then : else echo "configure: cannot find nm_test_func in $ac_nlist" >&5 fi fi else echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&5 fi else echo "configure: failed program was:" >&5 cat conftest.c >&5 fi rm -rf conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_symbol_underscore" >&5 $as_echo "$lt_cv_sys_symbol_underscore" >&6; } sys_symbol_underscore=$lt_cv_sys_symbol_underscore if test x"$lt_cv_sys_symbol_underscore" = xyes; then if test x"$libltdl_cv_func_dlopen" = xyes || test x"$libltdl_cv_lib_dl_dlopen" = xyes ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we have to add an underscore for dlsym" >&5 $as_echo_n "checking whether we have to add an underscore for dlsym... " >&6; } if test "${libltdl_cv_need_uscore+set}" = set; then : $as_echo_n "(cached) " >&6 else libltdl_cv_need_uscore=unknown save_LIBS="$LIBS" LIBS="$LIBS $LIBADD_DLOPEN" if test "$cross_compiling" = yes; then : libltdl_cv_need_uscore=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line 16309 "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) libltdl_cv_need_uscore=no ;; x$lt_dlneed_uscore) libltdl_cv_need_uscore=yes ;; x$lt_dlunknown|x*) ;; esac else : # compilation failed fi fi rm -fr conftest* LIBS="$save_LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libltdl_cv_need_uscore" >&5 $as_echo "$libltdl_cv_need_uscore" >&6; } fi fi if test x"$libltdl_cv_need_uscore" = xyes; then $as_echo "#define NEED_USCORE 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether deplibs are loaded by dlopen" >&5 $as_echo_n "checking whether deplibs are loaded by dlopen... " >&6; } if test "${lt_cv_sys_dlopen_deplibs+set}" = set; then : $as_echo_n "(cached) " >&6 else # PORTME does your system automatically load deplibs for dlopen? # or its logical equivalent (e.g. shl_load for HP-UX < 11) # For now, we just catch OSes we know something about -- in the # future, we'll try test this programmatically. lt_cv_sys_dlopen_deplibs=unknown case $host_os in aix3*|aix4.1.*|aix4.2.*) # Unknown whether this is true for these versions of AIX, but # we want this `case' here to explicitly catch those versions. lt_cv_sys_dlopen_deplibs=unknown ;; aix[4-9]*) lt_cv_sys_dlopen_deplibs=yes ;; amigaos*) case $host_cpu in powerpc) lt_cv_sys_dlopen_deplibs=no ;; esac ;; darwin*) # Assuming the user has installed a libdl from somewhere, this is true # If you are looking for one http://www.opendarwin.org/projects/dlcompat lt_cv_sys_dlopen_deplibs=yes ;; freebsd* | dragonfly*) lt_cv_sys_dlopen_deplibs=yes ;; gnu* | linux* | k*bsd*-gnu | kopensolaris*-gnu) # GNU and its variants, using gnu ld.so (Glibc) lt_cv_sys_dlopen_deplibs=yes ;; hpux10*|hpux11*) lt_cv_sys_dlopen_deplibs=yes ;; interix*) lt_cv_sys_dlopen_deplibs=yes ;; irix[12345]*|irix6.[01]*) # Catch all versions of IRIX before 6.2, and indicate that we don't # know how it worked for any of those versions. lt_cv_sys_dlopen_deplibs=unknown ;; irix*) # The case above catches anything before 6.2, and it's known that # at 6.2 and later dlopen does load deplibs. lt_cv_sys_dlopen_deplibs=yes ;; netbsd* | netbsdelf*-gnu) lt_cv_sys_dlopen_deplibs=yes ;; openbsd*) lt_cv_sys_dlopen_deplibs=yes ;; osf[1234]*) # dlopen did load deplibs (at least at 4.x), but until the 5.x series, # it did *not* use an RPATH in a shared library to find objects the # library depends on, so we explicitly say `no'. lt_cv_sys_dlopen_deplibs=no ;; osf5.0|osf5.0a|osf5.1) # dlopen *does* load deplibs and with the right loader patch applied # it even uses RPATH in a shared library to search for shared objects # that the library depends on, but there's no easy way to know if that # patch is installed. Since this is the case, all we can really # say is unknown -- it depends on the patch being installed. If # it is, this changes to `yes'. Without it, it would be `no'. lt_cv_sys_dlopen_deplibs=unknown ;; osf*) # the two cases above should catch all versions of osf <= 5.1. Read # the comments above for what we know about them. # At > 5.1, deplibs are loaded *and* any RPATH in a shared library # is used to find them so we can finally say `yes'. lt_cv_sys_dlopen_deplibs=yes ;; qnx*) lt_cv_sys_dlopen_deplibs=yes ;; solaris*) lt_cv_sys_dlopen_deplibs=yes ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) libltdl_cv_sys_dlopen_deplibs=yes ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_dlopen_deplibs" >&5 $as_echo "$lt_cv_sys_dlopen_deplibs" >&6; } if test "$lt_cv_sys_dlopen_deplibs" != yes; then $as_echo "#define LTDL_DLOPEN_DEPLIBS 1" >>confdefs.h fi : for ac_header in argz.h do : ac_fn_c_check_header_compile "$LINENO" "argz.h" "ac_cv_header_argz_h" "$ac_includes_default " if test "x$ac_cv_header_argz_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_ARGZ_H 1 _ACEOF fi done ac_fn_c_check_type "$LINENO" "error_t" "ac_cv_type_error_t" "#if defined(HAVE_ARGZ_H) # include #endif " if test "x$ac_cv_type_error_t" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_ERROR_T 1 _ACEOF else $as_echo "#define error_t int" >>confdefs.h $as_echo "#define __error_t_defined 1" >>confdefs.h fi ARGZ_H= for ac_func in argz_add argz_append argz_count argz_create_sep argz_insert \ argz_next argz_stringify do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF else ARGZ_H=argz.h; _LT_LIBOBJS="$_LT_LIBOBJS argz.$ac_objext" fi done if test -z "$ARGZ_H"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking if argz actually works" >&5 $as_echo_n "checking if argz actually works... " >&6; } if test "${lt_cv_sys_argz_works+set}" = set; then : $as_echo_n "(cached) " >&6 else case $host_os in #( *cygwin*) lt_cv_sys_argz_works=no if test "$cross_compiling" != no; then lt_cv_sys_argz_works="guessing no" else lt_sed_extract_leading_digits='s/^\([0-9\.]*\).*/\1/' save_IFS=$IFS IFS=-. set x `uname -r | sed -e "$lt_sed_extract_leading_digits"` IFS=$save_IFS lt_os_major=${2-0} lt_os_minor=${3-0} lt_os_micro=${4-0} if test "$lt_os_major" -gt 1 \ || { test "$lt_os_major" -eq 1 \ && { test "$lt_os_minor" -gt 5 \ || { test "$lt_os_minor" -eq 5 \ && test "$lt_os_micro" -gt 24; }; }; }; then lt_cv_sys_argz_works=yes fi fi ;; #( *) lt_cv_sys_argz_works=yes ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_argz_works" >&5 $as_echo "$lt_cv_sys_argz_works" >&6; } if test $lt_cv_sys_argz_works = yes; then : $as_echo "#define HAVE_WORKING_ARGZ 1" >>confdefs.h else ARGZ_H=argz.h _LT_LIBOBJS="$_LT_LIBOBJS argz.$ac_objext" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether libtool supports -dlopen/-dlpreopen" >&5 $as_echo_n "checking whether libtool supports -dlopen/-dlpreopen... " >&6; } if test "${libltdl_cv_preloaded_symbols+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$lt_cv_sys_global_symbol_pipe"; then libltdl_cv_preloaded_symbols=yes else libltdl_cv_preloaded_symbols=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libltdl_cv_preloaded_symbols" >&5 $as_echo "$libltdl_cv_preloaded_symbols" >&6; } if test x"$libltdl_cv_preloaded_symbols" = xyes; then $as_echo "#define HAVE_PRELOADED_SYMBOLS 1" >>confdefs.h fi # Set options # Check whether --with-included_ltdl was given. if test "${with_included_ltdl+set}" = set; then : withval=$with_included_ltdl; fi if test "x$with_included_ltdl" != xyes; then # We are not being forced to use the included libltdl sources, so # decide whether there is a useful installed version we can use. ac_fn_c_check_header_compile "$LINENO" "ltdl.h" "ac_cv_header_ltdl_h" "$ac_includes_default " if test "x$ac_cv_header_ltdl_h" = x""yes; then : ac_fn_c_check_decl "$LINENO" "lt_dlinterface_register" "ac_cv_have_decl_lt_dlinterface_register" "$ac_includes_default #include " if test "x$ac_cv_have_decl_lt_dlinterface_register" = x""yes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lt_dladvise_preload in -lltdl" >&5 $as_echo_n "checking for lt_dladvise_preload in -lltdl... " >&6; } if test "${ac_cv_lib_ltdl_lt_dladvise_preload+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lltdl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char lt_dladvise_preload (); int main () { return lt_dladvise_preload (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ltdl_lt_dladvise_preload=yes else ac_cv_lib_ltdl_lt_dladvise_preload=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ltdl_lt_dladvise_preload" >&5 $as_echo "$ac_cv_lib_ltdl_lt_dladvise_preload" >&6; } if test "x$ac_cv_lib_ltdl_lt_dladvise_preload" = x""yes; then : with_included_ltdl=no else with_included_ltdl=yes fi else with_included_ltdl=yes fi else with_included_ltdl=yes fi fi # Check whether --with-ltdl_include was given. if test "${with_ltdl_include+set}" = set; then : withval=$with_ltdl_include; fi if test -n "$with_ltdl_include"; then if test -f "$with_ltdl_include/ltdl.h"; then : else as_fn_error $? "invalid ltdl include directory: \`$with_ltdl_include'" "$LINENO" 5 fi else with_ltdl_include=no fi # Check whether --with-ltdl_lib was given. if test "${with_ltdl_lib+set}" = set; then : withval=$with_ltdl_lib; fi if test -n "$with_ltdl_lib"; then if test -f "$with_ltdl_lib/libltdl.la"; then : else as_fn_error $? "invalid ltdl library directory: \`$with_ltdl_lib'" "$LINENO" 5 fi else with_ltdl_lib=no fi case ,$with_included_ltdl,$with_ltdl_include,$with_ltdl_lib, in ,yes,no,no,) case $enable_ltdl_convenience in no) as_fn_error $? "this package needs a convenience libltdl" "$LINENO" 5 ;; "") enable_ltdl_convenience=yes ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; esac LIBLTDL='${top_build_prefix}'"${lt_ltdl_dir+$lt_ltdl_dir/}libltdlc.la" LTDLDEPS=$LIBLTDL LTDLINCL='-I${top_srcdir}'"${lt_ltdl_dir+/$lt_ltdl_dir}" # For backwards non-gettext consistent compatibility... INCLTDL="$LTDLINCL" ;; ,no,no,no,) # If the included ltdl is not to be used, then use the # preinstalled libltdl we found. $as_echo "#define HAVE_LTDL 1" >>confdefs.h LIBLTDL=-lltdl LTDLDEPS= LTDLINCL= ;; ,no*,no,*) as_fn_error $? "\`--with-ltdl-include' and \`--with-ltdl-lib' options must be used together" "$LINENO" 5 ;; *) with_included_ltdl=no LIBLTDL="-L$with_ltdl_lib -lltdl" LTDLDEPS= LTDLINCL="-I$with_ltdl_include" ;; esac INCLTDL="$LTDLINCL" # Report our decision... { $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find libltdl headers" >&5 $as_echo_n "checking where to find libltdl headers... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LTDLINCL" >&5 $as_echo "$LTDLINCL" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find libltdl library" >&5 $as_echo_n "checking where to find libltdl library... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBLTDL" >&5 $as_echo "$LIBLTDL" >&6; } # Check whether --enable-ltdl-install was given. if test "${enable_ltdl_install+set}" = set; then : enableval=$enable_ltdl_install; fi case ,${enable_ltdl_install},${enable_ltdl_convenience} in *yes*) ;; *) enable_ltdl_convenience=yes ;; esac if test x"${enable_ltdl_install-no}" != xno; then INSTALL_LTDL_TRUE= INSTALL_LTDL_FALSE='#' else INSTALL_LTDL_TRUE='#' INSTALL_LTDL_FALSE= fi if test x"${enable_ltdl_convenience-no}" != xno; then CONVENIENCE_LTDL_TRUE= CONVENIENCE_LTDL_FALSE='#' else CONVENIENCE_LTDL_TRUE='#' CONVENIENCE_LTDL_FALSE= fi subdirs="$subdirs libltdl" # In order that ltdl.c can compile, find out the first AC_CONFIG_HEADERS # the user used. This is so that ltdl.h can pick up the parent projects # config.h file, The first file in AC_CONFIG_HEADERS must contain the # definitions required by ltdl.c. # FIXME: Remove use of undocumented AC_LIST_HEADERS (2.59 compatibility). for ac_header in unistd.h dl.h sys/dl.h dld.h mach-o/dyld.h dirent.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in closedir opendir readdir do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF else _LT_LIBOBJS="$_LT_LIBOBJS lt__dirent.$ac_objext" fi done for ac_func in strlcat strlcpy do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF else _LT_LIBOBJS="$_LT_LIBOBJS lt__strl.$ac_objext" fi done cat >>confdefs.h <<_ACEOF #define LT_LIBEXT "$libext" _ACEOF name=ltdl LTDLOPEN=`eval "\\$ECHO \"$libname_spec\""` # Only expand once: # large file support # Check whether --enable-largefile was given. if test "${enable_largefile+set}" = set; then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 $as_echo_n "checking for special C compiler options needed for large files... " >&6; } if test "${ac_cv_sys_largefile_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_sys_largefile_CC=no if test "$GCC" != yes; then ac_save_CC=$CC while :; do # IRIX 6.2 and later do not support large files by default, # so use the C compiler's -n32 option if that helps. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : break fi rm -f core conftest.err conftest.$ac_objext CC="$CC -n32" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_largefile_CC=' -n32'; break fi rm -f core conftest.err conftest.$ac_objext break done CC=$ac_save_CC rm -f conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 $as_echo "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 $as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } if test "${ac_cv_sys_file_offset_bits+set}" = set; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=64; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 $as_echo "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits _ACEOF ;; esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 $as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } if test "${ac_cv_sys_large_files+set}" = set; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGE_FILES 1 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=1; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_large_files=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 $as_echo "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGE_FILES $ac_cv_sys_large_files _ACEOF ;; esac rm -rf conftest* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGEFILE_SOURCE value needed for large files" >&5 $as_echo_n "checking for _LARGEFILE_SOURCE value needed for large files... " >&6; } if test "${ac_cv_sys_largefile_source+set}" = set; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* for off_t */ #include int main () { int (*fp) (FILE *, off_t, int) = fseeko; return fseeko (stdin, 0, 0) && fp (stdin, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_sys_largefile_source=no; break fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGEFILE_SOURCE 1 #include /* for off_t */ #include int main () { int (*fp) (FILE *, off_t, int) = fseeko; return fseeko (stdin, 0, 0) && fp (stdin, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_sys_largefile_source=1; break fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_cv_sys_largefile_source=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_source" >&5 $as_echo "$ac_cv_sys_largefile_source" >&6; } case $ac_cv_sys_largefile_source in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGEFILE_SOURCE $ac_cv_sys_largefile_source _ACEOF ;; esac rm -rf conftest* # We used to try defining _XOPEN_SOURCE=500 too, to work around a bug # in glibc 2.1.3, but that breaks too many other things. # If you want fseeko and ftello with glibc, upgrade to a fixed glibc. if test $ac_cv_sys_largefile_source != unknown; then $as_echo "#define HAVE_FSEEKO 1" >>confdefs.h fi if test "$enable_shared" = "no" then as_fn_error $? "GNUnet only works with shared libraries. Sorry." "$LINENO" 5 fi CFLAGS="-Wall $CFLAGS" # use '-fno-strict-aliasing', but only if the compiler can take it if gcc -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then CFLAGS="-fno-strict-aliasing $CFLAGS" fi # Use Linux interface name unless the OS has a different preference DEFAULT_INTERFACE="\"eth0\"" funcstocheck="socket select inet_ntoa getnameinfo gethostname gethostbyname gethostbyaddr getaddrinfo" # Check system type case "$host_os" in *darwin* | *rhapsody* | *macosx*) cat >>confdefs.h <<_ACEOF #define DARWIN 1 _ACEOF CPPFLAGS="-D_APPLE_C_SOURCE $CPPFLAGS" CFLAGS="-no-cpp-precomp -fno-common $CFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: The VPN application cannot be compiled on your OS" >&5 $as_echo "$as_me: WARNING: The VPN application cannot be compiled on your OS" >&2;} build_target="darwin" DEFAULT_INTERFACE="\"en0\"" LIBPREFIX= DLLDIR=lib UNIXONLY="#" ;; linux*) cat >>confdefs.h <<_ACEOF #define LINUX 1 _ACEOF build_target="linux" LIBPREFIX= DLLDIR=lib UNIXONLY="#" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5 $as_echo_n "checking for X... " >&6; } # Check whether --with-x was given. if test "${with_x+set}" = set; then : withval=$with_x; fi # $have_x is `yes', `no', `disabled', or empty when we do not yet know. if test "x$with_x" = xno; then # The user explicitly disabled X. have_x=disabled else case $x_includes,$x_libraries in #( *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5 ;; #( *,NONE | NONE,*) if test "${ac_cv_have_x+set}" = set; then : $as_echo_n "(cached) " >&6 else # One or both of the vars are not set, and there is no cached value. ac_x_includes=no ac_x_libraries=no rm -f -r conftest.dir if mkdir conftest.dir; then cd conftest.dir cat >Imakefile <<'_ACEOF' incroot: @echo incroot='${INCROOT}' usrlibdir: @echo usrlibdir='${USRLIBDIR}' libdir: @echo libdir='${LIBDIR}' _ACEOF if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. for ac_var in incroot usrlibdir libdir; do eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" done # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. for ac_extension in a so sl dylib la dll; do if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && test -f "$ac_im_libdir/libX11.$ac_extension"; then ac_im_usrlibdir=$ac_im_libdir; break fi done # Screen out bogus values from the imake configuration. They are # bogus both because they are the default anyway, and because # using them would break gcc on systems where it needs fixed includes. case $ac_im_incroot in /usr/include) ac_x_includes= ;; *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; esac case $ac_im_usrlibdir in /usr/lib | /usr/lib64 | /lib | /lib64) ;; *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; esac fi cd .. rm -f -r conftest.dir fi # Standard set of common directories for X headers. # Check X11 before X11Rn because it is often a symlink to the current release. ac_x_header_dirs=' /usr/X11/include /usr/X11R7/include /usr/X11R6/include /usr/X11R5/include /usr/X11R4/include /usr/include/X11 /usr/include/X11R7 /usr/include/X11R6 /usr/include/X11R5 /usr/include/X11R4 /usr/local/X11/include /usr/local/X11R7/include /usr/local/X11R6/include /usr/local/X11R5/include /usr/local/X11R4/include /usr/local/include/X11 /usr/local/include/X11R7 /usr/local/include/X11R6 /usr/local/include/X11R5 /usr/local/include/X11R4 /usr/X386/include /usr/x386/include /usr/XFree86/include/X11 /usr/include /usr/local/include /usr/unsupported/include /usr/athena/include /usr/local/x11r5/include /usr/lpp/Xamples/include /usr/openwin/include /usr/openwin/share/include' if test "$ac_x_includes" = no; then # Guess where to find include files, by looking for Xlib.h. # First, try using that file with no special directory specified. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # We can compile using X headers with no special include directory. ac_x_includes= else for ac_dir in $ac_x_header_dirs; do if test -r "$ac_dir/X11/Xlib.h"; then ac_x_includes=$ac_dir break fi done fi rm -f conftest.err conftest.i conftest.$ac_ext fi # $ac_x_includes = no if test "$ac_x_libraries" = no; then # Check for the libraries. # See if we find them without any special options. # Don't add to $LIBS permanently. ac_save_LIBS=$LIBS LIBS="-lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { XrmInitialize () ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : LIBS=$ac_save_LIBS # We can link X programs with no special library path. ac_x_libraries= else LIBS=$ac_save_LIBS for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` do # Don't even attempt the hair of trying to link an X program! for ac_extension in a so sl dylib la dll; do if test -r "$ac_dir/libX11.$ac_extension"; then ac_x_libraries=$ac_dir break 2 fi done done fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi # $ac_x_libraries = no case $ac_x_includes,$ac_x_libraries in #( no,* | *,no | *\'*) # Didn't find X, or a directory has "'" in its name. ac_cv_have_x="have_x=no";; #( *) # Record where we found X for the cache. ac_cv_have_x="have_x=yes\ ac_x_includes='$ac_x_includes'\ ac_x_libraries='$ac_x_libraries'" esac fi ;; #( *) have_x=yes;; esac eval "$ac_cv_have_x" fi # $with_x != no if test "$have_x" != yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 $as_echo "$have_x" >&6; } no_x=yes else # If each of the values was on the command line, it overrides each guess. test "x$x_includes" = xNONE && x_includes=$ac_x_includes test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries # Update the cache value to reflect the command line values. ac_cv_have_x="have_x=yes\ ac_x_includes='$x_includes'\ ac_x_libraries='$x_libraries'" { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 $as_echo "libraries $x_libraries, headers $x_includes" >&6; } fi if test "$no_x" = yes; then # Not all programs may use this symbol, but it does not hurt to define it. $as_echo "#define X_DISPLAY_MISSING 1" >>confdefs.h X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS= else if test -n "$x_includes"; then X_CFLAGS="$X_CFLAGS -I$x_includes" fi # It would also be nice to do this for all -L options, not just this one. if test -n "$x_libraries"; then X_LIBS="$X_LIBS -L$x_libraries" # For Solaris; some versions of Sun CC require a space after -R and # others require no space. Words are not sufficient . . . . { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -R must be followed by a space" >&5 $as_echo_n "checking whether -R must be followed by a space... " >&6; } ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries" ac_xsave_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } X_LIBS="$X_LIBS -R$x_libraries" else LIBS="$ac_xsave_LIBS -R $x_libraries" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } X_LIBS="$X_LIBS -R $x_libraries" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: neither works" >&5 $as_echo "neither works" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_c_werror_flag=$ac_xsave_c_werror_flag LIBS=$ac_xsave_LIBS fi # Check for system-dependent libraries X programs must link with. # Do this before checking for the system-independent R6 libraries # (-lICE), since we may need -lsocket or whatever for X linking. if test "$ISC" = yes; then X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet" else # Martyn Johnson says this is needed for Ultrix, if the X # libraries were built with DECnet support. And Karl Berry says # the Alpha needs dnet_stub (dnet does not exist). ac_xsave_LIBS="$LIBS"; LIBS="$LIBS $X_LIBS -lX11" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XOpenDisplay (); int main () { return XOpenDisplay (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet" >&5 $as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; } if test "${ac_cv_lib_dnet_dnet_ntoa+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldnet $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dnet_ntoa (); int main () { return dnet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dnet_dnet_ntoa=yes else ac_cv_lib_dnet_dnet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_dnet_ntoa" >&5 $as_echo "$ac_cv_lib_dnet_dnet_ntoa" >&6; } if test "x$ac_cv_lib_dnet_dnet_ntoa" = x""yes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet" fi if test $ac_cv_lib_dnet_dnet_ntoa = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet_stub" >&5 $as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; } if test "${ac_cv_lib_dnet_stub_dnet_ntoa+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldnet_stub $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dnet_ntoa (); int main () { return dnet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dnet_stub_dnet_ntoa=yes else ac_cv_lib_dnet_stub_dnet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5 $as_echo "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; } if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = x""yes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub" fi fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$ac_xsave_LIBS" # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, # to get the SysV transport functions. # Chad R. Larson says the Pyramis MIS-ES running DC/OSx (SVR4) # needs -lnsl. # The nsl library prevents programs from opening the X display # on Irix 5.2, according to T.E. Dickey. # The functions gethostbyname, getservbyname, and inet_addr are # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking. ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" if test "x$ac_cv_func_gethostbyname" = x""yes; then : fi if test $ac_cv_func_gethostbyname = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 $as_echo_n "checking for gethostbyname in -lnsl... " >&6; } if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nsl_gethostbyname=yes else ac_cv_lib_nsl_gethostbyname=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5 $as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } if test "x$ac_cv_lib_nsl_gethostbyname" = x""yes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl" fi if test $ac_cv_lib_nsl_gethostbyname = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lbsd" >&5 $as_echo_n "checking for gethostbyname in -lbsd... " >&6; } if test "${ac_cv_lib_bsd_gethostbyname+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lbsd $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_bsd_gethostbyname=yes else ac_cv_lib_bsd_gethostbyname=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_gethostbyname" >&5 $as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; } if test "x$ac_cv_lib_bsd_gethostbyname" = x""yes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd" fi fi fi # lieder@skyler.mavd.honeywell.com says without -lsocket, # socket/setsockopt and other routines are undefined under SCO ODT # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary # on later versions), says Simon Leinen: it contains gethostby* # variants that don't use the name server (or something). -lsocket # must be given before -lnsl if both are needed. We assume that # if connect needs -lnsl, so does gethostbyname. ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" if test "x$ac_cv_func_connect" = x""yes; then : fi if test $ac_cv_func_connect = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5 $as_echo_n "checking for connect in -lsocket... " >&6; } if test "${ac_cv_lib_socket_connect+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $X_EXTRA_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char connect (); int main () { return connect (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_socket_connect=yes else ac_cv_lib_socket_connect=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect" >&5 $as_echo "$ac_cv_lib_socket_connect" >&6; } if test "x$ac_cv_lib_socket_connect" = x""yes; then : X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS" fi fi # Guillermo Gomez says -lposix is necessary on A/UX. ac_fn_c_check_func "$LINENO" "remove" "ac_cv_func_remove" if test "x$ac_cv_func_remove" = x""yes; then : fi if test $ac_cv_func_remove = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for remove in -lposix" >&5 $as_echo_n "checking for remove in -lposix... " >&6; } if test "${ac_cv_lib_posix_remove+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lposix $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char remove (); int main () { return remove (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_posix_remove=yes else ac_cv_lib_posix_remove=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix_remove" >&5 $as_echo "$ac_cv_lib_posix_remove" >&6; } if test "x$ac_cv_lib_posix_remove" = x""yes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix" fi fi # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. ac_fn_c_check_func "$LINENO" "shmat" "ac_cv_func_shmat" if test "x$ac_cv_func_shmat" = x""yes; then : fi if test $ac_cv_func_shmat = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shmat in -lipc" >&5 $as_echo_n "checking for shmat in -lipc... " >&6; } if test "${ac_cv_lib_ipc_shmat+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lipc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shmat (); int main () { return shmat (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ipc_shmat=yes else ac_cv_lib_ipc_shmat=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ipc_shmat" >&5 $as_echo "$ac_cv_lib_ipc_shmat" >&6; } if test "x$ac_cv_lib_ipc_shmat" = x""yes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc" fi fi fi # Check for libraries that X11R6 Xt/Xaw programs need. ac_save_LDFLAGS=$LDFLAGS test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries" # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to # check for ICE first), but we must link in the order -lSM -lICE or # we get undefined symbols. So assume we have SM if we have ICE. # These have to be linked with before -lX11, unlike the other # libraries we check for below, so use a different variable. # John Interrante, Karl Berry { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IceConnectionNumber in -lICE" >&5 $as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; } if test "${ac_cv_lib_ICE_IceConnectionNumber+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lICE $X_EXTRA_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char IceConnectionNumber (); int main () { return IceConnectionNumber (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ICE_IceConnectionNumber=yes else ac_cv_lib_ICE_IceConnectionNumber=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5 $as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; } if test "x$ac_cv_lib_ICE_IceConnectionNumber" = x""yes; then : X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE" fi LDFLAGS=$ac_save_LDFLAGS fi ;; freebsd*) cat >>confdefs.h <<_ACEOF #define SOMEBSD 1 _ACEOF cat >>confdefs.h <<_ACEOF #define FREEBSD 1 _ACEOF CFLAGS="-D_THREAD_SAFE $CFLAGS" build_target="freebsd" LIBPREFIX= DLLDIR=lib UNIXONLY="#" ;; openbsd*) cat >>confdefs.h <<_ACEOF #define SOMEBSD 1 _ACEOF cat >>confdefs.h <<_ACEOF #define OPENBSD 1 _ACEOF LIBS=`echo $LIBS | sed -e "s/-ldl//"` build_target="openbsd" LIBPREFIX= DLLDIR=lib UNIXONLY="#" ;; netbsd*) cat >>confdefs.h <<_ACEOF #define SOMEBSD 1 _ACEOF cat >>confdefs.h <<_ACEOF #define NETBSD 1 _ACEOF LIBPREFIX= DLLDIR=lib UNIXONLY="#" ;; *solaris*) cat >>confdefs.h <<_ACEOF #define SOLARIS 1 _ACEOF cat >>confdefs.h <<_ACEOF #define _REENTRANT 1 _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: checking for res_init in -lresolv" >&5 $as_echo_n "checking for res_init in -lresolv... " >&6; } if test "${ac_cv_lib_resolv_res_init+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lresolv $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char res_init (); int main () { return res_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_resolv_res_init=yes else ac_cv_lib_resolv_res_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_res_init" >&5 $as_echo "$ac_cv_lib_resolv_res_init" >&6; } if test "x$ac_cv_lib_resolv_res_init" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBRESOLV 1 _ACEOF LIBS="-lresolv $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nanosleep in -lrt" >&5 $as_echo_n "checking for nanosleep in -lrt... " >&6; } if test "${ac_cv_lib_rt_nanosleep+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char nanosleep (); int main () { return nanosleep (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_rt_nanosleep=yes else ac_cv_lib_rt_nanosleep=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_nanosleep" >&5 $as_echo "$ac_cv_lib_rt_nanosleep" >&6; } if test "x$ac_cv_lib_rt_nanosleep" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBRT 1 _ACEOF LIBS="-lrt $LIBS" fi build_target="solaris" LIBPREFIX= DLLDIR=lib UNIXONLY="#" ;; *arm-linux*) cat >>confdefs.h <<_ACEOF #define LINUX 1 _ACEOF CFLAGS="-D_REENTRANT -fPIC -pipe $CFLAGS" build_target="linux" LIBPREFIX= DLLDIR=lib UNIXONLY="#" ;; *cygwin*) cat >>confdefs.h <<_ACEOF #define CYGWIN 1 _ACEOF cat >>confdefs.h <<_ACEOF #define WINDOWS 1 _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gettext in -lintl" >&5 $as_echo_n "checking for gettext in -lintl... " >&6; } if test "${ac_cv_lib_intl_gettext+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lintl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gettext (); int main () { return gettext (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_intl_gettext=yes else ac_cv_lib_intl_gettext=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_gettext" >&5 $as_echo "$ac_cv_lib_intl_gettext" >&6; } if test "x$ac_cv_lib_intl_gettext" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBINTL 1 _ACEOF LIBS="-lintl $LIBS" fi LDFLAGS="$LDFLAGS -no-undefined" CFLAGS="-mms-bitfields $CFLAGS" build_target="cygwin" LIBPREFIX=lib DLLDIR=bin ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if test "${ac_cv_cxx_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if test "${ac_cv_prog_cxx_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CXX" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CXX_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CXX_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CXX_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 $as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then am__fastdepCXX_TRUE= am__fastdepCXX_FALSE='#' else am__fastdepCXX_TRUE='#' am__fastdepCXX_FALSE= fi UNIXONLY="" ;; *mingw*) cat >>confdefs.h <<_ACEOF #define MINGW 1 _ACEOF cat >>confdefs.h <<_ACEOF #define WINDOWS 1 _ACEOF cat >>confdefs.h <<_ACEOF #define _WIN32 1 _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gettext in -lintl" >&5 $as_echo_n "checking for gettext in -lintl... " >&6; } if test "${ac_cv_lib_intl_gettext+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lintl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gettext (); int main () { return gettext (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_intl_gettext=yes else ac_cv_lib_intl_gettext=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_gettext" >&5 $as_echo "$ac_cv_lib_intl_gettext" >&6; } if test "x$ac_cv_lib_intl_gettext" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBINTL 1 _ACEOF LIBS="-lintl $LIBS" fi LDFLAGS="$LDFLAGS -Wl,-no-undefined -Wl,--export-all-symbols" LIBS="$LIBS -lws2_32 -lplibc -lgnurx -lole32" CFLAGS="-mms-bitfields $CFLAGS" CPPFLAGS="-D_WIN32_WINNT=0x0501 -DHAVE_STAT64=1 $CPPFLAGS" build_target="mingw" ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if test "${ac_cv_cxx_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if test "${ac_cv_prog_cxx_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CXX" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CXX_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CXX_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CXX_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 $as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then am__fastdepCXX_TRUE= am__fastdepCXX_FALSE='#' else am__fastdepCXX_TRUE='#' am__fastdepCXX_FALSE= fi LIBPREFIX=lib DLLDIR=bin UNIXONLY="" funcstocheck="" ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Unrecognised OS $host_os" >&5 $as_echo "Unrecognised OS $host_os" >&6; } cat >>confdefs.h <<_ACEOF #define OTHEROS 1 _ACEOF UNIXONLY="" ;; esac cat >>confdefs.h <<_ACEOF #define GNUNET_DEFAULT_INTERFACE $DEFAULT_INTERFACE _ACEOF # Disable TCP-based IPC on systems that support UNIX domain # sockets in default configuratin: { $as_echo "$as_me:${as_lineno-$LINENO}: checking for build target" >&5 $as_echo_n "checking for build target... " >&6; } if test "$build_target" = "darwin"; then DARWIN_TRUE= DARWIN_FALSE='#' else DARWIN_TRUE='#' DARWIN_FALSE= fi if test "$build_target" = "cygwin"; then CYGWIN_TRUE= CYGWIN_FALSE='#' else CYGWIN_TRUE='#' CYGWIN_FALSE= fi if test "$build_target" = "mingw"; then MINGW_TRUE= MINGW_FALSE='#' else MINGW_TRUE='#' MINGW_FALSE= fi if test "$build_target" = "solaris"; then SOLARIS_TRUE= SOLARIS_FALSE='#' else SOLARIS_TRUE='#' SOLARIS_FALSE= fi if test "$build_target" = "freebsd"; then XFREEBSD_TRUE= XFREEBSD_FALSE='#' else XFREEBSD_TRUE='#' XFREEBSD_FALSE= fi if test "$build_target" = "openbsd"; then OPENBSD_TRUE= OPENBSD_FALSE='#' else OPENBSD_TRUE='#' OPENBSD_FALSE= fi if test "$build_target" = "linux"; then LINUX_TRUE= LINUX_FALSE='#' else LINUX_TRUE='#' LINUX_FALSE= fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $build_target" >&5 $as_echo "$build_target" >&6; } if false; then am__fastdepOBJC_TRUE= am__fastdepOBJC_FALSE='#' else am__fastdepOBJC_TRUE='#' am__fastdepOBJC_FALSE= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether unaligned 64-bit access works" >&5 $as_echo_n "checking whether unaligned 64-bit access works... " >&6; } if test "${ac_cv_unaligned_64_access+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_unaligned_64_access=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ struct S { int a,b,c;}; int main () { struct S s = {0,0,0}; long long * p = (long long *) &s.b; void *bp = malloc (50); long long x = *p; long long *be = (long long*) &bp1; long long y = *be; return (int) x*y; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_unaligned_64_access=yes else ac_cv_unaligned_64_access=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_unaligned_64_access" >&5 $as_echo "$ac_cv_unaligned_64_access" >&6; } case "$ac_cv_unaligned_64_access" in *yes) value=1;; *) value=0;; esac cat >>confdefs.h <<_ACEOF #define HAVE_UNALIGNED_64_ACCESS $value _ACEOF # some other checks for standard libs { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing gethostbyname" >&5 $as_echo_n "checking for library containing gethostbyname... " >&6; } if test "${ac_cv_search_gethostbyname+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF for ac_lib in '' nsl ws2_32; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_gethostbyname=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if test "${ac_cv_search_gethostbyname+set}" = set; then : break fi done if test "${ac_cv_search_gethostbyname+set}" = set; then : else ac_cv_search_gethostbyname=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gethostbyname" >&5 $as_echo "$ac_cv_search_gethostbyname" >&6; } ac_res=$ac_cv_search_gethostbyname if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5 $as_echo_n "checking for socket in -lsocket... " >&6; } if test "${ac_cv_lib_socket_socket+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char socket (); int main () { return socket (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_socket_socket=yes else ac_cv_lib_socket_socket=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5 $as_echo "$ac_cv_lib_socket_socket" >&6; } if test "x$ac_cv_lib_socket_socket" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSOCKET 1 _ACEOF LIBS="-lsocket $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for log in -lm" >&5 $as_echo_n "checking for log in -lm... " >&6; } if test "${ac_cv_lib_m_log+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char log (); int main () { return log (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_m_log=yes else ac_cv_lib_m_log=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_log" >&5 $as_echo "$ac_cv_lib_m_log" >&6; } if test "x$ac_cv_lib_m_log" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBM 1 _ACEOF LIBS="-lm $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getloadavg in -lc" >&5 $as_echo_n "checking for getloadavg in -lc... " >&6; } if test "${ac_cv_lib_c_getloadavg+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char getloadavg (); int main () { return getloadavg (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_c_getloadavg=yes else ac_cv_lib_c_getloadavg=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_getloadavg" >&5 $as_echo "$ac_cv_lib_c_getloadavg" >&6; } if test "x$ac_cv_lib_c_getloadavg" = x""yes; then : $as_echo "#define HAVE_GETLOADAVG 1" >>confdefs.h fi # 'save' libs; only those libs found so far will be # linked against _everywhere_. For the others, we # will be more selective! SAVE_LIBS=$LIBS # libgnurx (regex library for W32) gnurx=0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for regexec in -lgnurx" >&5 $as_echo_n "checking for regexec in -lgnurx... " >&6; } if test "${ac_cv_lib_gnurx_regexec+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lgnurx $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char regexec (); int main () { return regexec (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_gnurx_regexec=yes else ac_cv_lib_gnurx_regexec=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gnurx_regexec" >&5 $as_echo "$ac_cv_lib_gnurx_regexec" >&6; } if test "x$ac_cv_lib_gnurx_regexec" = x""yes; then : gnurx=1 fi if test "x$gnurx" = "x0" -a "x$build_target" = "xmingw" then as_fn_error $? "on W32 GNUnet needs libgnurx" "$LINENO" 5 fi # libgcrypt gcrypt=0 # Check whether --with-libgcrypt-prefix was given. if test "${with_libgcrypt_prefix+set}" = set; then : withval=$with_libgcrypt_prefix; libgcrypt_config_prefix="$withval" else libgcrypt_config_prefix="" fi if test x$libgcrypt_config_prefix != x ; then if test x${LIBGCRYPT_CONFIG+set} != xset ; then LIBGCRYPT_CONFIG=$libgcrypt_config_prefix/bin/libgcrypt-config fi fi # Extract the first word of "libgcrypt-config", so it can be a program name with args. set dummy libgcrypt-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_LIBGCRYPT_CONFIG+set}" = set; then : $as_echo_n "(cached) " >&6 else case $LIBGCRYPT_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_LIBGCRYPT_CONFIG="$LIBGCRYPT_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_LIBGCRYPT_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_LIBGCRYPT_CONFIG" && ac_cv_path_LIBGCRYPT_CONFIG="no" ;; esac fi LIBGCRYPT_CONFIG=$ac_cv_path_LIBGCRYPT_CONFIG if test -n "$LIBGCRYPT_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBGCRYPT_CONFIG" >&5 $as_echo "$LIBGCRYPT_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi tmp=1.2.0 if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then req_libgcrypt_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'` min_libgcrypt_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'` else req_libgcrypt_api=0 min_libgcrypt_version="$tmp" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBGCRYPT - version >= $min_libgcrypt_version" >&5 $as_echo_n "checking for LIBGCRYPT - version >= $min_libgcrypt_version... " >&6; } ok=no if test "$LIBGCRYPT_CONFIG" != "no" ; then req_major=`echo $min_libgcrypt_version | \ sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'` req_minor=`echo $min_libgcrypt_version | \ sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'` req_micro=`echo $min_libgcrypt_version | \ sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'` libgcrypt_config_version=`$LIBGCRYPT_CONFIG --version` major=`echo $libgcrypt_config_version | \ sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\1/'` minor=`echo $libgcrypt_config_version | \ sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\2/'` micro=`echo $libgcrypt_config_version | \ sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\3/'` if test "$major" -gt "$req_major"; then ok=yes else if test "$major" -eq "$req_major"; then if test "$minor" -gt "$req_minor"; then ok=yes else if test "$minor" -eq "$req_minor"; then if test "$micro" -ge "$req_micro"; then ok=yes fi fi fi fi fi fi if test $ok = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test $ok = yes; then # If we have a recent libgcrypt, we should also check that the # API is compatible if test "$req_libgcrypt_api" -gt 0 ; then tmp=`$LIBGCRYPT_CONFIG --api-version 2>/dev/null || echo 0` if test "$tmp" -gt 0 ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking LIBGCRYPT API version" >&5 $as_echo_n "checking LIBGCRYPT API version... " >&6; } if test "$req_libgcrypt_api" -eq "$tmp" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: okay" >&5 $as_echo "okay" >&6; } else ok=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: does not match (want=$req_libgcrypt_api got=$tmp)" >&5 $as_echo "does not match (want=$req_libgcrypt_api got=$tmp)" >&6; } fi fi fi fi if test $ok = yes; then LIBGCRYPT_CFLAGS=`$LIBGCRYPT_CONFIG --cflags` LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG --libs` gcrypt=1 else LIBGCRYPT_CFLAGS="" LIBGCRYPT_LIBS="" : fi ac_fn_c_check_decl "$LINENO" "gcry_mpi_lshift" "ac_cv_have_decl_gcry_mpi_lshift" "#include " if test "x$ac_cv_have_decl_gcry_mpi_lshift" = x""yes; then : ac_have_decl=1 else ac_have_decl=0 fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_GCRY_MPI_LSHIFT $ac_have_decl _ACEOF if test $gcrypt = 0 then as_fn_error $? "GNUnet needs libgcrypt" "$LINENO" 5 fi # Adam shostack suggests the following for Windows: # -D_FORTIFY_SOURCE=2 -fstack-protector-all # Check whether --enable-gcc-hardening was given. if test "${enable_gcc_hardening+set}" = set; then : enableval=$enable_gcc_hardening; if test x$enableval = xyes; then CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2 -fstack-protector-all" CFLAGS="$CFLAGS -fwrapv -fPIE -Wstack-protector" CFLAGS="$CFLAGS --param ssp-buffer-size=1" LDFLAGS="$LDFLAGS -pie" fi fi # Linker hardening options # Currently these options are ELF specific - you can't use this with MacOSX # Check whether --enable-linker-hardening was given. if test "${enable_linker_hardening+set}" = set; then : enableval=$enable_linker_hardening; if test x$enableval = xyes; then LDFLAGS="$LDFLAGS -z relro -z now" fi fi extra_logging=GNUNET_NO # Check whether --enable-logging was given. if test "${enable_logging+set}" = set; then : enableval=$enable_logging; if test "x$enableval" = "xyes"; then : elif test "x$enableval" = "xno"; then : $as_echo "#define GNUNET_CULL_LOGGING /**/" >>confdefs.h elif test "x$enableval" = "xverbose"; then : extra_logging=GNUNET_YES test "x$enableval" = "xveryverbose" else extra_logging=\(GNUNET_YES+1\) fi fi cat >>confdefs.h <<_ACEOF #define GNUNET_EXTRA_LOGGING $extra_logging _ACEOF if test $build = $target then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working HMAC" >&5 $as_echo_n "checking for working HMAC... " >&6; } ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu LIBS="$LIBS $LIBGCRYPT_LIBS" CFLAGS="$CFLAGS $LIBGCRYPT_CFLAGS" if test "$cross_compiling" = yes; then : { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5 ; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { gcry_md_hd_t mac; unsigned char data[] = { 0xbf, 0x16, 0x6e, 0x46, 0x3a, 0x6c, 0xf3, 0x93, 0xa7, 0x72, 0x11, 0xa1, 0xdc, 0x0b, 0x07, 0xdb, 0x1a, 0x5e, 0xd9, 0xb9, 0x81, 0xbe, 0xea, 0xe4, 0x31, 0x5f, 0x24, 0xff, 0xfe, 0x50, 0x8a, 0xde }; unsigned char key[] = { 0xfc, 0x62, 0x76, 0x35 }; unsigned char result[] = {0xa2, 0xb, 0x1, 0xd9, 0xc0, 0x8b, 0x5a, 0x12, 0x80, 0xd5, 0x50, 0x12, 0x8e, 0xd0, 0x5b, 0xb6, 0x5c, 0x87, 0x24, 0xe2, 0xd0, 0xd2, 0xaf, 0x63, 0xae, 0xd1, 0xd6, 0x64, 0x14, 0xe3, 0x6e, 0x61, 0x5b, 0xd, 0xba, 0x17, 0x7d, 0xd3, 0x10, 0xb1, 0x37, 0x41, 0x91, 0x7d, 0xeb, 0x1, 0x4d, 0x71, 0xe8, 0x59, 0x71, 0x42, 0x8e, 0xd6, 0xf3, 0x29, 0x3b, 0x90, 0xf2, 0xd1, 0xaf, 0x65, 0x1e, 0xb3}; if (!gcry_check_version (GCRYPT_VERSION)) { fprintf (stderr, "Version mismatch %s <-> %s \n", gcry_check_version (NULL), GCRYPT_VERSION); return 1; } gcry_control (GCRYCTL_DISABLE_SECMEM, 0); gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); if (gcry_md_open(&mac, GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC) != GPG_ERR_NO_ERROR) { fprintf (stderr, "gcry_md_open error\n"); return 2; } gcry_md_setkey (mac, key, sizeof (key)); gcry_md_write (mac, data, sizeof (data)); if (memcmp(gcry_md_read (mac, 0), result, gcry_md_get_algo_dlen (gcry_md_get_algo (mac))) != 0) { fprintf (stderr, "memcmp error\n"); return 3; } gcry_md_close (mac); return 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else RESULT=$? if test $RESULT = 3 then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "HMAC test vector does not match. This is a known problem with libgcrypt 1.2.2 on Windows and fixed in 1.4.6. See \`config.log' for more details" "$LINENO" 5 ; } fi if test $RESULT = 2 then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "HMAC test failed See \`config.log' for more details" "$LINENO" 5 ; } fi if test $RESULT = 1 then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "libgcrypt header version does not match library version See \`config.log' for more details" "$LINENO" 5 ; } fi fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi # $build = $target # libcurl # Check whether --with-libcurl was given. if test "${with_libcurl+set}" = set; then : withval=$with_libcurl; _libcurl_with=$withval else _libcurl_with=yes fi if test "$_libcurl_with" != "no" ; then for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_AWK+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done _libcurl_version_parse="eval $AWK '{split(\$NF,A,\".\"); X=256*256*A[1]+256*A[2]+A[3]; print X;}'" _libcurl_try_link=yes if test -d "$_libcurl_with" ; then LIBCURL_CPPFLAGS="-I$withval/include" _libcurl_ldflags="-L$withval/lib" # Extract the first word of "curl-config", so it can be a program name with args. set dummy curl-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path__libcurl_config+set}" = set; then : $as_echo_n "(cached) " >&6 else case $_libcurl_config in [\\/]* | ?:[\\/]*) ac_cv_path__libcurl_config="$_libcurl_config" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in "$withval/bin" do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path__libcurl_config="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi _libcurl_config=$ac_cv_path__libcurl_config if test -n "$_libcurl_config"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_libcurl_config" >&5 $as_echo "$_libcurl_config" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else # Extract the first word of "curl-config", so it can be a program name with args. set dummy curl-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path__libcurl_config+set}" = set; then : $as_echo_n "(cached) " >&6 else case $_libcurl_config in [\\/]* | ?:[\\/]*) ac_cv_path__libcurl_config="$_libcurl_config" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path__libcurl_config="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi _libcurl_config=$ac_cv_path__libcurl_config if test -n "$_libcurl_config"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_libcurl_config" >&5 $as_echo "$_libcurl_config" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test x$_libcurl_config != "x" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the version of libcurl" >&5 $as_echo_n "checking for the version of libcurl... " >&6; } if test "${libcurl_cv_lib_curl_version+set}" = set; then : $as_echo_n "(cached) " >&6 else libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $2}'` fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libcurl_cv_lib_curl_version" >&5 $as_echo "$libcurl_cv_lib_curl_version" >&6; } _libcurl_version=`echo $libcurl_cv_lib_curl_version | $_libcurl_version_parse` _libcurl_wanted=`echo 7.20.1 | $_libcurl_version_parse` if test $_libcurl_wanted -gt 0 ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libcurl >= version 7.20.1" >&5 $as_echo_n "checking for libcurl >= version 7.20.1... " >&6; } if test "${libcurl_cv_lib_version_ok+set}" = set; then : $as_echo_n "(cached) " >&6 else if test $_libcurl_version -ge $_libcurl_wanted ; then libcurl_cv_lib_version_ok=yes else libcurl_cv_lib_version_ok=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libcurl_cv_lib_version_ok" >&5 $as_echo "$libcurl_cv_lib_version_ok" >&6; } fi if test $_libcurl_wanted -eq 0 || test x$libcurl_cv_lib_version_ok = xyes ; then if test x"$LIBCURL_CPPFLAGS" = "x" ; then LIBCURL_CPPFLAGS=`$_libcurl_config --cflags` fi if test x"$LIBCURL" = "x" ; then LIBCURL=`$_libcurl_config --libs` # This is so silly, but Apple actually has a bug in their # curl-config script. Fixed in Tiger, but there are still # lots of Panther installs around. case "${host}" in powerpc-apple-darwin7*) LIBCURL=`echo $LIBCURL | sed -e 's|-arch i386||g'` ;; esac fi # All curl-config scripts support --feature _libcurl_features=`$_libcurl_config --feature` # Is it modern enough to have --protocols? (7.12.4) if test $_libcurl_version -ge 461828 ; then _libcurl_protocols=`$_libcurl_config --protocols` fi else _libcurl_try_link=no fi unset _libcurl_wanted fi if test $_libcurl_try_link = yes ; then # we didn't find curl-config, so let's see if the user-supplied # link line (or failing that, "-lcurl") is enough. LIBCURL=${LIBCURL-"$_libcurl_ldflags -lcurl"} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether libcurl is usable" >&5 $as_echo_n "checking whether libcurl is usable... " >&6; } if test "${libcurl_cv_lib_curl_usable+set}" = set; then : $as_echo_n "(cached) " >&6 else _libcurl_save_cppflags=$CPPFLAGS CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS" _libcurl_save_libs=$LIBS LIBS="$LIBCURL $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { /* Try and use a few common options to force a failure if we are missing symbols or can't link. */ int x; curl_easy_setopt(NULL,CURLOPT_URL,NULL); x=CURL_ERROR_SIZE; x=CURLOPT_WRITEFUNCTION; x=CURLOPT_FILE; x=CURLOPT_ERRORBUFFER; x=CURLOPT_STDERR; x=CURLOPT_VERBOSE; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : libcurl_cv_lib_curl_usable=yes else libcurl_cv_lib_curl_usable=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CPPFLAGS=$_libcurl_save_cppflags LIBS=$_libcurl_save_libs unset _libcurl_save_cppflags unset _libcurl_save_libs fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libcurl_cv_lib_curl_usable" >&5 $as_echo "$libcurl_cv_lib_curl_usable" >&6; } if test $libcurl_cv_lib_curl_usable = yes ; then # Does curl_free() exist in this version of libcurl? # If not, fake it with free() _libcurl_save_cppflags=$CPPFLAGS CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS" _libcurl_save_libs=$LIBS LIBS="$LIBS $LIBCURL" ac_fn_c_check_func "$LINENO" "curl_free" "ac_cv_func_curl_free" if test "x$ac_cv_func_curl_free" = x""yes; then : else $as_echo "#define curl_free free" >>confdefs.h fi CPPFLAGS=$_libcurl_save_cppflags LIBS=$_libcurl_save_libs unset _libcurl_save_cppflags unset _libcurl_save_libs $as_echo "#define HAVE_LIBCURL 1" >>confdefs.h for _libcurl_feature in $_libcurl_features ; do cat >>confdefs.h <<_ACEOF #define `$as_echo "libcurl_feature_$_libcurl_feature" | $as_tr_cpp` 1 _ACEOF eval `$as_echo "libcurl_feature_$_libcurl_feature" | $as_tr_sh`=yes done if test "x$_libcurl_protocols" = "x" ; then # We don't have --protocols, so just assume that all # protocols are available _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP" if test x$libcurl_feature_SSL = xyes ; then _libcurl_protocols="$_libcurl_protocols HTTPS" # FTPS wasn't standards-compliant until version # 7.11.0 (0x070b00 == 461568) if test $_libcurl_version -ge 461568; then _libcurl_protocols="$_libcurl_protocols FTPS" fi fi # RTSP, IMAP, POP3 and SMTP were added in # 7.20.0 (0x071400 == 463872) if test $_libcurl_version -ge 463872; then _libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP" fi fi for _libcurl_protocol in $_libcurl_protocols ; do cat >>confdefs.h <<_ACEOF #define `$as_echo "libcurl_protocol_$_libcurl_protocol" | $as_tr_cpp` 1 _ACEOF eval `$as_echo "libcurl_protocol_$_libcurl_protocol" | $as_tr_sh`=yes done else unset LIBCURL unset LIBCURL_CPPFLAGS fi fi unset _libcurl_try_link unset _libcurl_version_parse unset _libcurl_config unset _libcurl_feature unset _libcurl_features unset _libcurl_protocol unset _libcurl_protocols unset _libcurl_version unset _libcurl_ldflags fi if test x$_libcurl_with = xno || test x$libcurl_cv_lib_curl_usable != xyes ; then # This is the IF-NO path as_fn_error $? "GNUnet requires libcurl >= 7.20.1" "$LINENO" 5 else # This is the IF-YES path : fi unset _libcurl_with # restore LIBS LIBS=$SAVE_LIBS for ac_header in glpk.h do : ac_fn_c_check_header_mongrel "$LINENO" "glpk.h" "ac_cv_header_glpk_h" "$ac_includes_default" if test "x$ac_cv_header_glpk_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GLPK_H 1 _ACEOF glpk=true else gplk=false fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for glp_create_prob in -lglpk" >&5 $as_echo_n "checking for glp_create_prob in -lglpk... " >&6; } if test "${ac_cv_lib_glpk_glp_create_prob+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lglpk $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char glp_create_prob (); int main () { return glp_create_prob (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_glpk_glp_create_prob=yes else ac_cv_lib_glpk_glp_create_prob=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_glpk_glp_create_prob" >&5 $as_echo "$ac_cv_lib_glpk_glp_create_prob" >&6; } if test "x$ac_cv_lib_glpk_glp_create_prob" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBGLPK 1 _ACEOF LIBS="-lglpk $LIBS" else gplk=false fi # GLPK must support atm MLP presolving, version >= 4.32 ac_fn_c_check_member "$LINENO" "glp_iocp" "presolve" "ac_cv_member_glp_iocp_presolve" "#include " if test "x$ac_cv_member_glp_iocp_presolve" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GLP_IOCP_PRESOLVE 1 _ACEOF else gplk=false fi if test x$gplk = xfalse then if false; then HAVE_LIBGLPK_TRUE= HAVE_LIBGLPK_FALSE='#' else HAVE_LIBGLPK_TRUE='#' HAVE_LIBGLPK_FALSE= fi { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: GNUnet requires GLPK >= 4.32" >&5 $as_echo "$as_me: WARNING: GNUnet requires GLPK >= 4.32" >&2;} else if true; then HAVE_LIBGLPK_TRUE= HAVE_LIBGLPK_FALSE='#' else HAVE_LIBGLPK_TRUE='#' HAVE_LIBGLPK_FALSE= fi $as_echo "#define HAVE_LIBGLPK 1" >>confdefs.h fi for ac_header in nss.h do : ac_fn_c_check_header_mongrel "$LINENO" "nss.h" "ac_cv_header_nss_h" "$ac_includes_default" if test "x$ac_cv_header_nss_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NSS_H 1 _ACEOF nss=true else nss=false fi done if test x$nss = xfalse then if false; then HAVE_GLIBCNSS_TRUE= HAVE_GLIBCNSS_FALSE='#' else HAVE_GLIBCNSS_TRUE='#' HAVE_GLIBCNSS_FALSE= fi { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: No GNU libc nss header, will not build NSS plugin" >&5 $as_echo "$as_me: WARNING: No GNU libc nss header, will not build NSS plugin" >&2;} else if true; then HAVE_GLIBCNSS_TRUE= HAVE_GLIBCNSS_FALSE='#' else HAVE_GLIBCNSS_TRUE='#' HAVE_GLIBCNSS_FALSE= fi fi # test for kvm and kstat (for CPU stats under BSD/Solaris) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for kvm_open in -lkvm" >&5 $as_echo_n "checking for kvm_open in -lkvm... " >&6; } if test "${ac_cv_lib_kvm_kvm_open+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lkvm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char kvm_open (); int main () { return kvm_open (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_kvm_kvm_open=yes else ac_cv_lib_kvm_kvm_open=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_kvm_kvm_open" >&5 $as_echo "$ac_cv_lib_kvm_kvm_open" >&6; } if test "x$ac_cv_lib_kvm_kvm_open" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBKVM 1 _ACEOF LIBS="-lkvm $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for kstat_open in -lkstat" >&5 $as_echo_n "checking for kstat_open in -lkstat... " >&6; } if test "${ac_cv_lib_kstat_kstat_open+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lkstat $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char kstat_open (); int main () { return kstat_open (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_kstat_kstat_open=yes else ac_cv_lib_kstat_kstat_open=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_kstat_kstat_open" >&5 $as_echo "$ac_cv_lib_kstat_kstat_open" >&6; } if test "x$ac_cv_lib_kstat_kstat_open" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBKSTAT 1 _ACEOF LIBS="-lkstat $LIBS" fi # test for libextractor extractor=0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libextractor" >&5 $as_echo_n "checking for libextractor... " >&6; } # Check whether --with-extractor was given. if test "${with_extractor+set}" = set; then : withval=$with_extractor; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_extractor" >&5 $as_echo "$with_extractor" >&6; } case $with_extractor in no) ;; yes) for ac_header in extractor.h do : ac_fn_c_check_header_mongrel "$LINENO" "extractor.h" "ac_cv_header_extractor_h" "$ac_includes_default" if test "x$ac_cv_header_extractor_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_EXTRACTOR_H 1 _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EXTRACTOR_plugin_add_defaults in -lextractor" >&5 $as_echo_n "checking for EXTRACTOR_plugin_add_defaults in -lextractor... " >&6; } if test "${ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lextractor $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char EXTRACTOR_plugin_add_defaults (); int main () { return EXTRACTOR_plugin_add_defaults (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults=yes else ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults" >&5 $as_echo "$ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults" >&6; } if test "x$ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults" = x""yes; then : extractor=1 fi fi done ;; *) LDFLAGS="-L$with_extractor/lib $LDFLAGS" CPPFLAGS="-I$with_extractor/include $CPPFLAGS" for ac_header in extractor.h do : ac_fn_c_check_header_mongrel "$LINENO" "extractor.h" "ac_cv_header_extractor_h" "$ac_includes_default" if test "x$ac_cv_header_extractor_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_EXTRACTOR_H 1 _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EXTRACTOR_plugin_add_defaults in -lextractor" >&5 $as_echo_n "checking for EXTRACTOR_plugin_add_defaults in -lextractor... " >&6; } if test "${ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lextractor $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char EXTRACTOR_plugin_add_defaults (); int main () { return EXTRACTOR_plugin_add_defaults (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults=yes else ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults" >&5 $as_echo "$ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults" >&6; } if test "x$ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults" = x""yes; then : EXT_LIB_PATH="-L$with_extractor/lib $EXT_LIB_PATH" extractor=1 fi fi done ;; esac else { $as_echo "$as_me:${as_lineno-$LINENO}: result: --with-extractor not specified" >&5 $as_echo "--with-extractor not specified" >&6; } for ac_header in extractor.h do : ac_fn_c_check_header_mongrel "$LINENO" "extractor.h" "ac_cv_header_extractor_h" "$ac_includes_default" if test "x$ac_cv_header_extractor_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_EXTRACTOR_H 1 _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EXTRACTOR_plugin_add_defaults in -lextractor" >&5 $as_echo_n "checking for EXTRACTOR_plugin_add_defaults in -lextractor... " >&6; } if test "${ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lextractor $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char EXTRACTOR_plugin_add_defaults (); int main () { return EXTRACTOR_plugin_add_defaults (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults=yes else ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults" >&5 $as_echo "$ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults" >&6; } if test "x$ac_cv_lib_extractor_EXTRACTOR_plugin_add_defaults" = x""yes; then : extractor=1 fi fi done fi if test "$extractor" != 1 then as_fn_error $? "GNUnet requires libextractor" "$LINENO" 5 fi # restore LIBS LIBS=$SAVE_LIBS # test for libunistring if test "X$prefix" = "XNONE"; then acl_final_prefix="$ac_default_prefix" else acl_final_prefix="$prefix" fi if test "X$exec_prefix" = "XNONE"; then acl_final_exec_prefix='${prefix}' else acl_final_exec_prefix="$exec_prefix" fi acl_save_prefix="$prefix" prefix="$acl_final_prefix" eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" prefix="$acl_save_prefix" # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi # Prepare PATH_SEPARATOR. # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by GCC" >&5 $as_echo_n "checking for ld used by GCC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | [A-Za-z]:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the path of ld ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if test "${acl_cv_path_LD+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then acl_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in *GNU* | *'with BFD'*) test "$with_gnu_ld" != no && break ;; *) test "$with_gnu_ld" != yes && break ;; esac fi done IFS="$ac_save_ifs" else acl_cv_path_LD="$LD" # Let the user override the test with a path. fi fi LD="$acl_cv_path_LD" if test -n "$LD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if test "${acl_cv_prog_gnu_ld+set}" = set; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU ld's only accept -v. case `$LD -v 2>&1 &5 $as_echo "$acl_cv_prog_gnu_ld" >&6; } with_gnu_ld=$acl_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shared library run path origin" >&5 $as_echo_n "checking for shared library run path origin... " >&6; } if test "${acl_cv_rpath+set}" = set; then : $as_echo_n "(cached) " >&6 else CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh . ./conftest.sh rm -f ./conftest.sh acl_cv_rpath=done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acl_cv_rpath" >&5 $as_echo "$acl_cv_rpath" >&6; } wl="$acl_cv_wl" libext="$acl_cv_libext" shlibext="$acl_cv_shlibext" hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" hardcode_direct="$acl_cv_hardcode_direct" hardcode_minus_L="$acl_cv_hardcode_minus_L" # Check whether --enable-rpath was given. if test "${enable_rpath+set}" = set; then : enableval=$enable_rpath; : else enable_rpath=yes fi acl_libdirstem=lib searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` if test -n "$searchpath"; then acl_save_IFS="${IFS= }"; IFS=":" for searchdir in $searchpath; do if test -d "$searchdir"; then case "$searchdir" in */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; *) searchdir=`cd "$searchdir" && pwd` case "$searchdir" in */lib64 ) acl_libdirstem=lib64 ;; esac ;; esac fi done IFS="$acl_save_IFS" fi use_additional=yes acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" # Check whether --with-libiconv-prefix was given. if test "${with_libiconv_prefix+set}" = set; then : withval=$with_libiconv_prefix; if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" fi fi fi LIBICONV= LTLIBICONV= INCICONV= rpathdirs= ltrpathdirs= names_already_handled= names_next_round='iconv ' while test -n "$names_next_round"; do names_this_round="$names_next_round" names_next_round= for name in $names_this_round; do already_handled= for n in $names_already_handled; do if test "$n" = "$name"; then already_handled=yes break fi done if test -z "$already_handled"; then names_already_handled="$names_already_handled $name" uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` eval value=\"\$HAVE_LIB$uppername\" if test -n "$value"; then if test "$value" = yes; then eval value=\"\$LIB$uppername\" test -z "$value" || LIBICONV="${LIBICONV}${LIBICONV:+ }$value" eval value=\"\$LTLIB$uppername\" test -z "$value" || LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }$value" else : fi else found_dir= found_la= found_so= found_a= if test $use_additional = yes; then if test -n "$shlibext" \ && { test -f "$additional_libdir/lib$name.$shlibext" \ || { test "$shlibext" = dll \ && test -f "$additional_libdir/lib$name.dll.a"; }; }; then found_dir="$additional_libdir" if test -f "$additional_libdir/lib$name.$shlibext"; then found_so="$additional_libdir/lib$name.$shlibext" else found_so="$additional_libdir/lib$name.dll.a" fi if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi else if test -f "$additional_libdir/lib$name.$libext"; then found_dir="$additional_libdir" found_a="$additional_libdir/lib$name.$libext" if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi fi fi fi if test "X$found_dir" = "X"; then for x in $LDFLAGS $LTLIBICONV; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" case "$x" in -L*) dir=`echo "X$x" | sed -e 's/^X-L//'` if test -n "$shlibext" \ && { test -f "$dir/lib$name.$shlibext" \ || { test "$shlibext" = dll \ && test -f "$dir/lib$name.dll.a"; }; }; then found_dir="$dir" if test -f "$dir/lib$name.$shlibext"; then found_so="$dir/lib$name.$shlibext" else found_so="$dir/lib$name.dll.a" fi if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi else if test -f "$dir/lib$name.$libext"; then found_dir="$dir" found_a="$dir/lib$name.$libext" if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi fi fi ;; esac if test "X$found_dir" != "X"; then break fi done fi if test "X$found_dir" != "X"; then LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$found_dir -l$name" if test "X$found_so" != "X"; then if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" else haveit= for x in $ltrpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $found_dir" fi if test "$hardcode_direct" = yes; then LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" else if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" haveit= for x in $rpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $found_dir" fi else haveit= for x in $LDFLAGS $LIBICONV; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then LIBICONV="${LIBICONV}${LIBICONV:+ }-L$found_dir" fi if test "$hardcode_minus_L" != no; then LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" else LIBICONV="${LIBICONV}${LIBICONV:+ }-l$name" fi fi fi fi else if test "X$found_a" != "X"; then LIBICONV="${LIBICONV}${LIBICONV:+ }$found_a" else LIBICONV="${LIBICONV}${LIBICONV:+ }-L$found_dir -l$name" fi fi additional_includedir= case "$found_dir" in */$acl_libdirstem | */$acl_libdirstem/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` additional_includedir="$basedir/include" ;; esac if test "X$additional_includedir" != "X"; then if test "X$additional_includedir" != "X/usr/include"; then haveit= if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then for x in $CPPFLAGS $INCICONV; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_includedir"; then INCICONV="${INCICONV}${INCICONV:+ }-I$additional_includedir" fi fi fi fi fi if test -n "$found_la"; then save_libdir="$libdir" case "$found_la" in */* | *\\*) . "$found_la" ;; *) . "./$found_la" ;; esac libdir="$save_libdir" for dep in $dependency_libs; do case "$dep" in -L*) additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then haveit= if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then haveit= for x in $LDFLAGS $LIBICONV; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then LIBICONV="${LIBICONV}${LIBICONV:+ }-L$additional_libdir" fi fi haveit= for x in $LDFLAGS $LTLIBICONV; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$additional_libdir" fi fi fi fi ;; -R*) dir=`echo "X$dep" | sed -e 's/^X-R//'` if test "$enable_rpath" != no; then haveit= for x in $rpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $dir" fi haveit= for x in $ltrpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $dir" fi fi ;; -l*) names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` ;; *.la) names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` ;; *) LIBICONV="${LIBICONV}${LIBICONV:+ }$dep" LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }$dep" ;; esac done fi else LIBICONV="${LIBICONV}${LIBICONV:+ }-l$name" LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-l$name" fi fi fi done done if test "X$rpathdirs" != "X"; then if test -n "$hardcode_libdir_separator"; then alldirs= for found_dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" done acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIBICONV="${LIBICONV}${LIBICONV:+ }$flag" else for found_dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$found_dir" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIBICONV="${LIBICONV}${LIBICONV:+ }$flag" done fi fi if test "X$ltrpathdirs" != "X"; then for found_dir in $ltrpathdirs; do LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-R$found_dir" done fi am_save_CPPFLAGS="$CPPFLAGS" for element in $INCICONV; do haveit= for x in $CPPFLAGS; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X$element"; then haveit=yes break fi done if test -z "$haveit"; then CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv" >&5 $as_echo_n "checking for iconv... " >&6; } if test "${am_cv_func_iconv+set}" = set; then : $as_echo_n "(cached) " >&6 else am_cv_func_iconv="no, consider installing GNU libiconv" am_cv_lib_iconv=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : am_cv_func_iconv=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$am_cv_func_iconv" != yes; then am_save_LIBS="$LIBS" LIBS="$LIBS $LIBICONV" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : am_cv_lib_iconv=yes am_cv_func_iconv=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$am_save_LIBS" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv" >&5 $as_echo "$am_cv_func_iconv" >&6; } if test "$am_cv_func_iconv" = yes; then $as_echo "#define HAVE_ICONV 1" >>confdefs.h fi if test "$am_cv_lib_iconv" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libiconv" >&5 $as_echo_n "checking how to link with libiconv... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBICONV" >&5 $as_echo "$LIBICONV" >&6; } else CPPFLAGS="$am_save_CPPFLAGS" LIBICONV= LTLIBICONV= fi if test "$am_cv_func_iconv" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv declaration" >&5 $as_echo_n "checking for iconv declaration... " >&6; } if test "${am_cv_proto_iconv+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include extern #ifdef __cplusplus "C" #endif #if defined(__STDC__) || defined(__cplusplus) size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); #else size_t iconv(); #endif int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : am_cv_proto_iconv_arg1="" else am_cv_proto_iconv_arg1="const" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);" fi am_cv_proto_iconv=`echo "$am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_t:- }$am_cv_proto_iconv" >&5 $as_echo "${ac_t:- }$am_cv_proto_iconv" >&6; } cat >>confdefs.h <<_ACEOF #define ICONV_CONST $am_cv_proto_iconv_arg1 _ACEOF fi if test -n "$LIBICONV"; then use_additional=yes acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" # Check whether --with-libunistring-prefix was given. if test "${with_libunistring_prefix+set}" = set; then : withval=$with_libunistring_prefix; if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" fi fi fi LIBUNISTRING= LTLIBUNISTRING= INCUNISTRING= rpathdirs= ltrpathdirs= names_already_handled= names_next_round='unistring ' while test -n "$names_next_round"; do names_this_round="$names_next_round" names_next_round= for name in $names_this_round; do already_handled= for n in $names_already_handled; do if test "$n" = "$name"; then already_handled=yes break fi done if test -z "$already_handled"; then names_already_handled="$names_already_handled $name" uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` eval value=\"\$HAVE_LIB$uppername\" if test -n "$value"; then if test "$value" = yes; then eval value=\"\$LIB$uppername\" test -z "$value" || LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$value" eval value=\"\$LTLIB$uppername\" test -z "$value" || LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }$value" else : fi else found_dir= found_la= found_so= found_a= if test $use_additional = yes; then if test -n "$shlibext" \ && { test -f "$additional_libdir/lib$name.$shlibext" \ || { test "$shlibext" = dll \ && test -f "$additional_libdir/lib$name.dll.a"; }; }; then found_dir="$additional_libdir" if test -f "$additional_libdir/lib$name.$shlibext"; then found_so="$additional_libdir/lib$name.$shlibext" else found_so="$additional_libdir/lib$name.dll.a" fi if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi else if test -f "$additional_libdir/lib$name.$libext"; then found_dir="$additional_libdir" found_a="$additional_libdir/lib$name.$libext" if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi fi fi fi if test "X$found_dir" = "X"; then for x in $LDFLAGS $LTLIBUNISTRING; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" case "$x" in -L*) dir=`echo "X$x" | sed -e 's/^X-L//'` if test -n "$shlibext" \ && { test -f "$dir/lib$name.$shlibext" \ || { test "$shlibext" = dll \ && test -f "$dir/lib$name.dll.a"; }; }; then found_dir="$dir" if test -f "$dir/lib$name.$shlibext"; then found_so="$dir/lib$name.$shlibext" else found_so="$dir/lib$name.dll.a" fi if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi else if test -f "$dir/lib$name.$libext"; then found_dir="$dir" found_a="$dir/lib$name.$libext" if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi fi fi ;; esac if test "X$found_dir" != "X"; then break fi done fi if test "X$found_dir" != "X"; then LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-L$found_dir -l$name" if test "X$found_so" != "X"; then if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" else haveit= for x in $ltrpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $found_dir" fi if test "$hardcode_direct" = yes; then LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" else if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" haveit= for x in $rpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $found_dir" fi else haveit= for x in $LDFLAGS $LIBUNISTRING; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-L$found_dir" fi if test "$hardcode_minus_L" != no; then LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" else LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-l$name" fi fi fi fi else if test "X$found_a" != "X"; then LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_a" else LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-L$found_dir -l$name" fi fi additional_includedir= case "$found_dir" in */$acl_libdirstem | */$acl_libdirstem/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` additional_includedir="$basedir/include" ;; esac if test "X$additional_includedir" != "X"; then if test "X$additional_includedir" != "X/usr/include"; then haveit= if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then for x in $CPPFLAGS $INCUNISTRING; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_includedir"; then INCUNISTRING="${INCUNISTRING}${INCUNISTRING:+ }-I$additional_includedir" fi fi fi fi fi if test -n "$found_la"; then save_libdir="$libdir" case "$found_la" in */* | *\\*) . "$found_la" ;; *) . "./$found_la" ;; esac libdir="$save_libdir" for dep in $dependency_libs; do case "$dep" in -L*) additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then haveit= if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then haveit= for x in $LDFLAGS $LIBUNISTRING; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-L$additional_libdir" fi fi haveit= for x in $LDFLAGS $LTLIBUNISTRING; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-L$additional_libdir" fi fi fi fi ;; -R*) dir=`echo "X$dep" | sed -e 's/^X-R//'` if test "$enable_rpath" != no; then haveit= for x in $rpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $dir" fi haveit= for x in $ltrpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $dir" fi fi ;; -l*) names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` ;; *.la) names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` ;; *) LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$dep" LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }$dep" ;; esac done fi else LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-l$name" LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-l$name" fi fi fi done done if test "X$rpathdirs" != "X"; then if test -n "$hardcode_libdir_separator"; then alldirs= for found_dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" done acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$flag" else for found_dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$found_dir" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$flag" done fi fi if test "X$ltrpathdirs" != "X"; then for found_dir in $ltrpathdirs; do LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-R$found_dir" done fi ac_save_CPPFLAGS="$CPPFLAGS" for element in $INCUNISTRING; do haveit= for x in $CPPFLAGS; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X$element"; then haveit=yes break fi done if test -z "$haveit"; then CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libunistring" >&5 $as_echo_n "checking for libunistring... " >&6; } if test "${ac_cv_libunistring+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_LIBS="$LIBS" LIBS="$LIBS $LIBUNISTRING" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { u8_strconv_from_locale((char*)0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_libunistring=yes else ac_cv_libunistring=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$ac_save_LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libunistring" >&5 $as_echo "$ac_cv_libunistring" >&6; } if test "$ac_cv_libunistring" = yes; then HAVE_LIBUNISTRING=yes $as_echo "#define HAVE_LIBUNISTRING 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libunistring" >&5 $as_echo_n "checking how to link with libunistring... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBUNISTRING" >&5 $as_echo "$LIBUNISTRING" >&6; } else HAVE_LIBUNISTRING=no CPPFLAGS="$ac_save_CPPFLAGS" LIBUNISTRING= LTLIBUNISTRING= fi if test "$ac_cv_libunistring" != yes; then unset ac_cv_libunistring glus_save_LIBS="$LIBS" LIBS="$LIBS $LIBICONV" use_additional=yes acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" # Check whether --with-libunistring-prefix was given. if test "${with_libunistring_prefix+set}" = set; then : withval=$with_libunistring_prefix; if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" fi fi fi LIBUNISTRING= LTLIBUNISTRING= INCUNISTRING= rpathdirs= ltrpathdirs= names_already_handled= names_next_round='unistring ' while test -n "$names_next_round"; do names_this_round="$names_next_round" names_next_round= for name in $names_this_round; do already_handled= for n in $names_already_handled; do if test "$n" = "$name"; then already_handled=yes break fi done if test -z "$already_handled"; then names_already_handled="$names_already_handled $name" uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` eval value=\"\$HAVE_LIB$uppername\" if test -n "$value"; then if test "$value" = yes; then eval value=\"\$LIB$uppername\" test -z "$value" || LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$value" eval value=\"\$LTLIB$uppername\" test -z "$value" || LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }$value" else : fi else found_dir= found_la= found_so= found_a= if test $use_additional = yes; then if test -n "$shlibext" \ && { test -f "$additional_libdir/lib$name.$shlibext" \ || { test "$shlibext" = dll \ && test -f "$additional_libdir/lib$name.dll.a"; }; }; then found_dir="$additional_libdir" if test -f "$additional_libdir/lib$name.$shlibext"; then found_so="$additional_libdir/lib$name.$shlibext" else found_so="$additional_libdir/lib$name.dll.a" fi if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi else if test -f "$additional_libdir/lib$name.$libext"; then found_dir="$additional_libdir" found_a="$additional_libdir/lib$name.$libext" if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi fi fi fi if test "X$found_dir" = "X"; then for x in $LDFLAGS $LTLIBUNISTRING; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" case "$x" in -L*) dir=`echo "X$x" | sed -e 's/^X-L//'` if test -n "$shlibext" \ && { test -f "$dir/lib$name.$shlibext" \ || { test "$shlibext" = dll \ && test -f "$dir/lib$name.dll.a"; }; }; then found_dir="$dir" if test -f "$dir/lib$name.$shlibext"; then found_so="$dir/lib$name.$shlibext" else found_so="$dir/lib$name.dll.a" fi if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi else if test -f "$dir/lib$name.$libext"; then found_dir="$dir" found_a="$dir/lib$name.$libext" if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi fi fi ;; esac if test "X$found_dir" != "X"; then break fi done fi if test "X$found_dir" != "X"; then LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-L$found_dir -l$name" if test "X$found_so" != "X"; then if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" else haveit= for x in $ltrpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $found_dir" fi if test "$hardcode_direct" = yes; then LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" else if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" haveit= for x in $rpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $found_dir" fi else haveit= for x in $LDFLAGS $LIBUNISTRING; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-L$found_dir" fi if test "$hardcode_minus_L" != no; then LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" else LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-l$name" fi fi fi fi else if test "X$found_a" != "X"; then LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_a" else LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-L$found_dir -l$name" fi fi additional_includedir= case "$found_dir" in */$acl_libdirstem | */$acl_libdirstem/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` additional_includedir="$basedir/include" ;; esac if test "X$additional_includedir" != "X"; then if test "X$additional_includedir" != "X/usr/include"; then haveit= if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then for x in $CPPFLAGS $INCUNISTRING; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_includedir"; then INCUNISTRING="${INCUNISTRING}${INCUNISTRING:+ }-I$additional_includedir" fi fi fi fi fi if test -n "$found_la"; then save_libdir="$libdir" case "$found_la" in */* | *\\*) . "$found_la" ;; *) . "./$found_la" ;; esac libdir="$save_libdir" for dep in $dependency_libs; do case "$dep" in -L*) additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then haveit= if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then haveit= for x in $LDFLAGS $LIBUNISTRING; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-L$additional_libdir" fi fi haveit= for x in $LDFLAGS $LTLIBUNISTRING; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-L$additional_libdir" fi fi fi fi ;; -R*) dir=`echo "X$dep" | sed -e 's/^X-R//'` if test "$enable_rpath" != no; then haveit= for x in $rpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $dir" fi haveit= for x in $ltrpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $dir" fi fi ;; -l*) names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` ;; *.la) names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` ;; *) LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$dep" LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }$dep" ;; esac done fi else LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-l$name" LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-l$name" fi fi fi done done if test "X$rpathdirs" != "X"; then if test -n "$hardcode_libdir_separator"; then alldirs= for found_dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" done acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$flag" else for found_dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$found_dir" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$flag" done fi fi if test "X$ltrpathdirs" != "X"; then for found_dir in $ltrpathdirs; do LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-R$found_dir" done fi ac_save_CPPFLAGS="$CPPFLAGS" for element in $INCUNISTRING; do haveit= for x in $CPPFLAGS; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X$element"; then haveit=yes break fi done if test -z "$haveit"; then CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libunistring" >&5 $as_echo_n "checking for libunistring... " >&6; } if test "${ac_cv_libunistring+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_LIBS="$LIBS" LIBS="$LIBS $LIBUNISTRING" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { u8_strconv_from_locale((char*)0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_libunistring=yes else ac_cv_libunistring=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$ac_save_LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libunistring" >&5 $as_echo "$ac_cv_libunistring" >&6; } if test "$ac_cv_libunistring" = yes; then HAVE_LIBUNISTRING=yes $as_echo "#define HAVE_LIBUNISTRING 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libunistring" >&5 $as_echo_n "checking how to link with libunistring... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBUNISTRING" >&5 $as_echo "$LIBUNISTRING" >&6; } else HAVE_LIBUNISTRING=no CPPFLAGS="$ac_save_CPPFLAGS" LIBUNISTRING= LTLIBUNISTRING= fi if test -n "$LIBUNISTRING"; then LIBUNISTRING="$LIBUNISTRING $LIBICONV" LTLIBUNISTRING="$LTLIBUNISTRING $LTLIBICONV" fi LIBS="$glus_save_LIBS" fi else use_additional=yes acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" # Check whether --with-libunistring-prefix was given. if test "${with_libunistring_prefix+set}" = set; then : withval=$with_libunistring_prefix; if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" fi fi fi LIBUNISTRING= LTLIBUNISTRING= INCUNISTRING= rpathdirs= ltrpathdirs= names_already_handled= names_next_round='unistring ' while test -n "$names_next_round"; do names_this_round="$names_next_round" names_next_round= for name in $names_this_round; do already_handled= for n in $names_already_handled; do if test "$n" = "$name"; then already_handled=yes break fi done if test -z "$already_handled"; then names_already_handled="$names_already_handled $name" uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` eval value=\"\$HAVE_LIB$uppername\" if test -n "$value"; then if test "$value" = yes; then eval value=\"\$LIB$uppername\" test -z "$value" || LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$value" eval value=\"\$LTLIB$uppername\" test -z "$value" || LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }$value" else : fi else found_dir= found_la= found_so= found_a= if test $use_additional = yes; then if test -n "$shlibext" \ && { test -f "$additional_libdir/lib$name.$shlibext" \ || { test "$shlibext" = dll \ && test -f "$additional_libdir/lib$name.dll.a"; }; }; then found_dir="$additional_libdir" if test -f "$additional_libdir/lib$name.$shlibext"; then found_so="$additional_libdir/lib$name.$shlibext" else found_so="$additional_libdir/lib$name.dll.a" fi if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi else if test -f "$additional_libdir/lib$name.$libext"; then found_dir="$additional_libdir" found_a="$additional_libdir/lib$name.$libext" if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi fi fi fi if test "X$found_dir" = "X"; then for x in $LDFLAGS $LTLIBUNISTRING; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" case "$x" in -L*) dir=`echo "X$x" | sed -e 's/^X-L//'` if test -n "$shlibext" \ && { test -f "$dir/lib$name.$shlibext" \ || { test "$shlibext" = dll \ && test -f "$dir/lib$name.dll.a"; }; }; then found_dir="$dir" if test -f "$dir/lib$name.$shlibext"; then found_so="$dir/lib$name.$shlibext" else found_so="$dir/lib$name.dll.a" fi if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi else if test -f "$dir/lib$name.$libext"; then found_dir="$dir" found_a="$dir/lib$name.$libext" if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi fi fi ;; esac if test "X$found_dir" != "X"; then break fi done fi if test "X$found_dir" != "X"; then LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-L$found_dir -l$name" if test "X$found_so" != "X"; then if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" else haveit= for x in $ltrpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $found_dir" fi if test "$hardcode_direct" = yes; then LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" else if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" haveit= for x in $rpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $found_dir" fi else haveit= for x in $LDFLAGS $LIBUNISTRING; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-L$found_dir" fi if test "$hardcode_minus_L" != no; then LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_so" else LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-l$name" fi fi fi fi else if test "X$found_a" != "X"; then LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$found_a" else LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-L$found_dir -l$name" fi fi additional_includedir= case "$found_dir" in */$acl_libdirstem | */$acl_libdirstem/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` additional_includedir="$basedir/include" ;; esac if test "X$additional_includedir" != "X"; then if test "X$additional_includedir" != "X/usr/include"; then haveit= if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then for x in $CPPFLAGS $INCUNISTRING; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_includedir"; then INCUNISTRING="${INCUNISTRING}${INCUNISTRING:+ }-I$additional_includedir" fi fi fi fi fi if test -n "$found_la"; then save_libdir="$libdir" case "$found_la" in */* | *\\*) . "$found_la" ;; *) . "./$found_la" ;; esac libdir="$save_libdir" for dep in $dependency_libs; do case "$dep" in -L*) additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then haveit= if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then haveit= for x in $LDFLAGS $LIBUNISTRING; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-L$additional_libdir" fi fi haveit= for x in $LDFLAGS $LTLIBUNISTRING; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-L$additional_libdir" fi fi fi fi ;; -R*) dir=`echo "X$dep" | sed -e 's/^X-R//'` if test "$enable_rpath" != no; then haveit= for x in $rpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $dir" fi haveit= for x in $ltrpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $dir" fi fi ;; -l*) names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` ;; *.la) names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` ;; *) LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$dep" LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }$dep" ;; esac done fi else LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }-l$name" LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-l$name" fi fi fi done done if test "X$rpathdirs" != "X"; then if test -n "$hardcode_libdir_separator"; then alldirs= for found_dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" done acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$flag" else for found_dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$found_dir" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIBUNISTRING="${LIBUNISTRING}${LIBUNISTRING:+ }$flag" done fi fi if test "X$ltrpathdirs" != "X"; then for found_dir in $ltrpathdirs; do LTLIBUNISTRING="${LTLIBUNISTRING}${LTLIBUNISTRING:+ }-R$found_dir" done fi ac_save_CPPFLAGS="$CPPFLAGS" for element in $INCUNISTRING; do haveit= for x in $CPPFLAGS; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X$element"; then haveit=yes break fi done if test -z "$haveit"; then CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libunistring" >&5 $as_echo_n "checking for libunistring... " >&6; } if test "${ac_cv_libunistring+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_LIBS="$LIBS" LIBS="$LIBS $LIBUNISTRING" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { u8_strconv_from_locale((char*)0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_libunistring=yes else ac_cv_libunistring=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$ac_save_LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libunistring" >&5 $as_echo "$ac_cv_libunistring" >&6; } if test "$ac_cv_libunistring" = yes; then HAVE_LIBUNISTRING=yes $as_echo "#define HAVE_LIBUNISTRING 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libunistring" >&5 $as_echo_n "checking how to link with libunistring... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBUNISTRING" >&5 $as_echo "$LIBUNISTRING" >&6; } else HAVE_LIBUNISTRING=no CPPFLAGS="$ac_save_CPPFLAGS" LIBUNISTRING= LTLIBUNISTRING= fi fi if test $HAVE_LIBUNISTRING = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libunistring version" >&5 $as_echo_n "checking for libunistring version... " >&6; } if test "${gl_cv_libunistring_version+set}" = set; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "_LIBUNISTRING_VERSION" "gl_libunistring_hexversion" "#include "; then : fi if test $gl_libunistring_hexversion = 9; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : gl_cv_libunistring_version092=true else gl_cv_libunistring_version092=false fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if $gl_cv_libunistring_version092; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF case "$host_os" in aix*) gl_absname_cpp="$ac_cpp -C" ;; *) gl_absname_cpp="$ac_cpp" ;; esac gl_cv_absolute_unistr_h=`(eval "$gl_absname_cpp conftest.$ac_ext") 2>&5 | sed -n '\#/unistr.h#{ s#.*"\(.*/unistr.h\)".*#\1# s#^/[^/]#//&# p q }'` if test -n "$gl_cv_absolute_unistr_h" \ && grep 'Copy no more than N units of SRC to DEST. Return a pointer' $gl_cv_absolute_unistr_h > /dev/null; then gl_libunistring_hexversion=2307 else gl_libunistring_hexversion=2306 fi else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include casing_suffix_context_t ct; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : gl_cv_libunistring_version091=true else gl_cv_libunistring_version091=false fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if $gl_cv_libunistring_version091; then gl_libunistring_hexversion=2305 else gl_libunistring_hexversion=2304 fi fi fi gl_libunistring_major=`expr $gl_libunistring_hexversion / 65536` gl_libunistring_minor=`expr $gl_libunistring_hexversion / 256 % 256` gl_libunistring_subminor=`expr $gl_libunistring_hexversion % 256` gl_cv_libunistring_version="$gl_libunistring_major.$gl_libunistring_minor.$gl_libunistring_subminor" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_libunistring_version" >&5 $as_echo "$gl_cv_libunistring_version" >&6; } LIBUNISTRING_VERSION="$gl_cv_libunistring_version" fi if test $HAVE_LIBUNISTRING != yes; then as_fn_error $? "GNUnet requires libunistring" "$LINENO" 5 fi if test $gl_libunistring_hexversion -le 2305; then as_fn_error $? "GNUnet requires libunistring >= 0.9.1.1" "$LINENO" 5 fi # restore LIBS LIBS=$SAVE_LIBS # Checks for standard header files. ac_header_dirent=no for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 $as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } if eval "test \"\${$as_ac_Header+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include <$ac_hdr> int main () { if ((DIR *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$as_ac_Header=yes" else eval "$as_ac_Header=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$as_ac_Header { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 _ACEOF ac_header_dirent=$ac_hdr; break fi done # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. if test $ac_header_dirent = dirent.h; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } if test "${ac_cv_search_opendir+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { return opendir (); ; return 0; } _ACEOF for ac_lib in '' dir; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if test "${ac_cv_search_opendir+set}" = set; then : break fi done if test "${ac_cv_search_opendir+set}" = set; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 $as_echo "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } if test "${ac_cv_search_opendir+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { return opendir (); ; return 0; } _ACEOF for ac_lib in '' x; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if test "${ac_cv_search_opendir+set}" = set; then : break fi done if test "${ac_cv_search_opendir+set}" = set; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 $as_echo "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if test "${ac_cv_header_stdc+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # Check for headers that are ALWAYS required for ac_header in fcntl.h math.h errno.h ctype.h limits.h stdio.h stdlib.h string.h unistd.h stdarg.h signal.h locale.h sys/stat.h sys/types.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF else as_fn_error $? "Compiling GNUnet requires standard UNIX headers files" "$LINENO" 5 fi done # Checks for headers that are only required on some systems or opional (and where we do NOT abort if they are not there) for ac_header in langinfo.h sys/param.h sys/mount.h sys/statvfs.h sys/select.h sockLib.h sys/mman.h sys/msg.h sys/vfs.h arpa/inet.h fcntl.h libintl.h netdb.h netinet/in.h netinet/in_systm.h sys/ioctl.h sys/socket.h sys/time.h unistd.h kstat.h sys/sysinfo.h kvm.h sys/file.h sys/resource.h ifaddrs.h mach/mach.h stddef.h sys/timeb.h terminos.h argz.h ucred.h endian.h sys/endian.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done SAVE_LDFLAGS=$LDFLAGS SAVE_CPPFLAGS=$CPPFLAGS # test for sqlite sqlite=false { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SQLite" >&5 $as_echo_n "checking for SQLite... " >&6; } # Check whether --with-sqlite was given. if test "${with_sqlite+set}" = set; then : withval=$with_sqlite; { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$with_sqlite\"" >&5 $as_echo "\"$with_sqlite\"" >&6; } case $with_sqlite in no) ;; yes) for ac_header in sqlite3.h do : ac_fn_c_check_header_mongrel "$LINENO" "sqlite3.h" "ac_cv_header_sqlite3_h" "$ac_includes_default" if test "x$ac_cv_header_sqlite3_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SQLITE3_H 1 _ACEOF sqlite=true fi done ;; *) LDFLAGS="-L$with_sqlite/lib $LDFLAGS" CPPFLAGS="-I$with_sqlite/include $CPPFLAGS" for ac_header in sqlite3.h do : ac_fn_c_check_header_mongrel "$LINENO" "sqlite3.h" "ac_cv_header_sqlite3_h" "$ac_includes_default" if test "x$ac_cv_header_sqlite3_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SQLITE3_H 1 _ACEOF EXT_LIB_PATH="-L$with_sqlite/lib $EXT_LIB_PATH" SQLITE_LDFLAGS="-L$with_sqlite/lib" SQLITE_CPPFLAGS="-I$with_sqlite/include" sqlite=true fi done LDFLAGS=$SAVE_LDFLAGS CPPFLAGS=$SAVE_CPPFLAGS ;; esac else { $as_echo "$as_me:${as_lineno-$LINENO}: result: --with-sqlite not specified" >&5 $as_echo "--with-sqlite not specified" >&6; } for ac_header in sqlite3.h do : ac_fn_c_check_header_mongrel "$LINENO" "sqlite3.h" "ac_cv_header_sqlite3_h" "$ac_includes_default" if test "x$ac_cv_header_sqlite3_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SQLITE3_H 1 _ACEOF sqlite=true fi done fi if test x$sqlite = xtrue; then HAVE_SQLITE_TRUE= HAVE_SQLITE_FALSE='#' else HAVE_SQLITE_TRUE='#' HAVE_SQLITE_FALSE= fi # test for postgres postgres=false { $as_echo "$as_me:${as_lineno-$LINENO}: checking for postgres" >&5 $as_echo_n "checking for postgres... " >&6; } # Check whether --with-postgres was given. if test "${with_postgres+set}" = set; then : withval=$with_postgres; { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$with_postgres\"" >&5 $as_echo "\"$with_postgres\"" >&6; } case $with_postgres in no) ;; yes) for ac_header in postgresql/libpq-fe.h do : ac_fn_c_check_header_mongrel "$LINENO" "postgresql/libpq-fe.h" "ac_cv_header_postgresql_libpq_fe_h" "$ac_includes_default" if test "x$ac_cv_header_postgresql_libpq_fe_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_POSTGRESQL_LIBPQ_FE_H 1 _ACEOF postgres=true fi done ;; *) LDFLAGS="-L$with_postgres/lib $LDFLAGS" CPPFLAGS="-I$with_postgres/include $CPPFLAGS" for ac_header in postgresql/libpq-fe.h do : ac_fn_c_check_header_mongrel "$LINENO" "postgresql/libpq-fe.h" "ac_cv_header_postgresql_libpq_fe_h" "$ac_includes_default" if test "x$ac_cv_header_postgresql_libpq_fe_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_POSTGRESQL_LIBPQ_FE_H 1 _ACEOF EXT_LIB_PATH="-L$with_postgres/lib $EXT_LIB_PATH" POSTGRES_LDFLAGS="-L$with_postgres/lib" POSTGRES_CPPFLAGS="-I$with_postgres/include" postgres=true fi done LDFLAGS=$SAVE_LDFLAGS CPPFLAGS=$SAVE_CPPFLAGS ;; esac else { $as_echo "$as_me:${as_lineno-$LINENO}: result: --with-postgres not specified" >&5 $as_echo "--with-postgres not specified" >&6; } for ac_header in postgresql/libpq-fe.h do : ac_fn_c_check_header_mongrel "$LINENO" "postgresql/libpq-fe.h" "ac_cv_header_postgresql_libpq_fe_h" "$ac_includes_default" if test "x$ac_cv_header_postgresql_libpq_fe_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_POSTGRESQL_LIBPQ_FE_H 1 _ACEOF postgres=true fi done fi if test x$postgres = xtrue; then HAVE_POSTGRES_TRUE= HAVE_POSTGRES_FALSE='#' else HAVE_POSTGRES_TRUE='#' HAVE_POSTGRES_FALSE= fi # test for libz (maybe required for linking mysql) zlib=1 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for compress in -lz" >&5 $as_echo_n "checking for compress in -lz... " >&6; } if test "${ac_cv_lib_z_compress+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lz $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char compress (); int main () { return compress (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_z_compress=yes else ac_cv_lib_z_compress=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_compress" >&5 $as_echo "$ac_cv_lib_z_compress" >&6; } if test "x$ac_cv_lib_z_compress" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBZ 1 _ACEOF LIBS="-lz $LIBS" else zlib=0 fi if test x$zlib = x1; then HAVE_ZLIB_TRUE= HAVE_ZLIB_FALSE='#' else HAVE_ZLIB_TRUE='#' HAVE_ZLIB_FALSE= fi if test "$zlib" != 1 then as_fn_error $? "GNUnet requires zlib" "$LINENO" 5 fi # mysql & windows ac_fn_c_check_type "$LINENO" "sigset_t" "ac_cv_type_sigset_t" "#include " if test "x$ac_cv_type_sigset_t" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SIGSET_T 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "#include " if test "x$ac_cv_type_off_t" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_OFF_T 1 _ACEOF fi ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "#include " if test "x$ac_cv_type_size_t" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SIZE_T 1 _ACEOF fi if test "$build_target" = "mingw" then CYGWIN_MYSQL_MAGIC="#include " fi # test for mysql mysql=false mysqlfail=false SAVE_LDFLAGS=$LDFLAGS SAVE_CPPFLAGS=$CPPFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql" >&5 $as_echo_n "checking for mysql... " >&6; } # Check whether --with-mysql was given. if test "${with_mysql+set}" = set; then : withval=$with_mysql; { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$with_mysql\"" >&5 $as_echo "\"$with_mysql\"" >&6; } if test "$with_mysql" != "no" then if test "$with_mysql" != "yes" then LDFLAGS="-L$with_mysql/lib -L$with_mysql/lib/mysql $LDFLAGS $ZLIBS" CPPFLAGS="-I$with_mysql/include $CPPFLAGS" fi for ac_header in mysql/mysql.h do : ac_fn_c_check_header_compile "$LINENO" "mysql/mysql.h" "ac_cv_header_mysql_mysql_h" "$CYGWIN_MYSQL_MAGIC " if test "x$ac_cv_header_mysql_mysql_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_MYSQL_MYSQL_H 1 _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql_init in -lmysqlclient" >&5 $as_echo_n "checking for mysql_init in -lmysqlclient... " >&6; } if test "${ac_cv_lib_mysqlclient_mysql_init+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lmysqlclient $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char mysql_init (); int main () { return mysql_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_mysqlclient_mysql_init=yes else ac_cv_lib_mysqlclient_mysql_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mysqlclient_mysql_init" >&5 $as_echo "$ac_cv_lib_mysqlclient_mysql_init" >&6; } if test "x$ac_cv_lib_mysqlclient_mysql_init" = x""yes; then : MYSQL_LDFLAGS="-L$with_mysql/lib -L$with_mysql/lib/mysql" MYSQL_CPPFLAGS="-I$with_mysql/include" mysql=true fi fi done fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: --with-mysql not specified" >&5 $as_echo "--with-mysql not specified" >&6; } LDFLAGS="-L/usr/lib/mysql $LDFLAGS $ZLIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql_init in -lmysqlclient" >&5 $as_echo_n "checking for mysql_init in -lmysqlclient... " >&6; } if test "${ac_cv_lib_mysqlclient_mysql_init+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lmysqlclient $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char mysql_init (); int main () { return mysql_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_mysqlclient_mysql_init=yes else ac_cv_lib_mysqlclient_mysql_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mysqlclient_mysql_init" >&5 $as_echo "$ac_cv_lib_mysqlclient_mysql_init" >&6; } if test "x$ac_cv_lib_mysqlclient_mysql_init" = x""yes; then : for ac_header in mysql/mysql.h do : ac_fn_c_check_header_compile "$LINENO" "mysql/mysql.h" "ac_cv_header_mysql_mysql_h" "$CYGWIN_MYSQL_MAGIC " if test "x$ac_cv_header_mysql_mysql_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_MYSQL_MYSQL_H 1 _ACEOF MYSQL_LDFLAGS="-L/usr/lib/mysql" mysql=true fi done fi fi # additional version check for mysql # Check whether --enable-mysql-version-check was given. if test "${enable_mysql_version_check+set}" = set; then : enableval=$enable_mysql_version_check; else enable_mysql_version_check=yes fi if test "$mysql" = "true" -a "x$enable_mysql_version_check" = "xyes" then { $as_echo "$as_me:${as_lineno-$LINENO}: checking mysql version" >&5 $as_echo_n "checking mysql version... " >&6; } if test "$cross_compiling" = yes; then : { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5 ; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $CYGWIN_MYSQL_MAGIC #include int main () { if (MYSQL_VERSION_ID < 40100) return(-1); else return(0); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : mysql=true else mysql=false fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "$mysql" = "false" then mysqlfail=true { $as_echo "$as_me:${as_lineno-$LINENO}: result: fail, >= 4.1 required" >&5 $as_echo "fail, >= 4.1 required" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } fi fi if test x$mysql = xtrue; then HAVE_MYSQL_TRUE= HAVE_MYSQL_FALSE='#' else HAVE_MYSQL_TRUE='#' HAVE_MYSQL_FALSE= fi if test "0" = "1"; then HAVE_MYSQLE_TRUE= HAVE_MYSQLE_FALSE='#' else HAVE_MYSQLE_TRUE='#' HAVE_MYSQLE_FALSE= fi # restore LIBS LIBS=$SAVE_LIBS LDFLAGS=$SAVE_LDFLAGS CPPFLAGS=$SAVE_CPPFLAGS if test "$sqlite" = 0 -a "$mysql" = 0 then as_fn_error $? "GNUnet requires SQLite or MySQL" "$LINENO" 5 fi # libmicrohttpd lmhd=0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libmicrohttpd" >&5 $as_echo_n "checking for libmicrohttpd... " >&6; } # Check whether --with-microhttpd was given. if test "${with_microhttpd+set}" = set; then : withval=$with_microhttpd; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_microhttpd" >&5 $as_echo "$with_microhttpd" >&6; } case $with_microhttpd in no) ;; yes) for ac_header in microhttpd.h do : ac_fn_c_check_header_compile "$LINENO" "microhttpd.h" "ac_cv_header_microhttpd_h" "#include \"$srcdir/src/include/platform.h\" " if test "x$ac_cv_header_microhttpd_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_MICROHTTPD_H 1 _ACEOF ac_fn_c_check_decl "$LINENO" "MHD_OPTION_PER_IP_CONNECTION_LIMIT" "ac_cv_have_decl_MHD_OPTION_PER_IP_CONNECTION_LIMIT" "#include \"$srcdir/src/include/platform.h\" #include " if test "x$ac_cv_have_decl_MHD_OPTION_PER_IP_CONNECTION_LIMIT" = x""yes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for MHD_start_daemon in -lmicrohttpd" >&5 $as_echo_n "checking for MHD_start_daemon in -lmicrohttpd... " >&6; } if test "${ac_cv_lib_microhttpd_MHD_start_daemon+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lmicrohttpd $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char MHD_start_daemon (); int main () { return MHD_start_daemon (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_microhttpd_MHD_start_daemon=yes else ac_cv_lib_microhttpd_MHD_start_daemon=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_microhttpd_MHD_start_daemon" >&5 $as_echo "$ac_cv_lib_microhttpd_MHD_start_daemon" >&6; } if test "x$ac_cv_lib_microhttpd_MHD_start_daemon" = x""yes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libmicrohttpd >= 0.9.18" >&5 $as_echo_n "checking for libmicrohttpd >= 0.9.18... " >&6; } if test "$cross_compiling" = yes; then : lmhd=1 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include "$srcdir/src/include/platform.h" #include int main () { return MHD_VERSION >= 0x0091200 ? 0 : 1; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } lmhd=1 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi fi done ;; *) LDFLAGS="-L$with_microhttpd/lib $LDFLAGS" CPPFLAGS="-I$with_microhttpd/include $CPPFLAGS" for ac_header in microhttpd.h do : ac_fn_c_check_header_compile "$LINENO" "microhttpd.h" "ac_cv_header_microhttpd_h" "#include \"$srcdir/src/include/platform.h\" " if test "x$ac_cv_header_microhttpd_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_MICROHTTPD_H 1 _ACEOF ac_fn_c_check_decl "$LINENO" "MHD_OPTION_PER_IP_CONNECTION_LIMIT" "ac_cv_have_decl_MHD_OPTION_PER_IP_CONNECTION_LIMIT" "#include \"$srcdir/src/include/platform.h\" #include " if test "x$ac_cv_have_decl_MHD_OPTION_PER_IP_CONNECTION_LIMIT" = x""yes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for MHD_start_daemon in -lmicrohttpd" >&5 $as_echo_n "checking for MHD_start_daemon in -lmicrohttpd... " >&6; } if test "${ac_cv_lib_microhttpd_MHD_start_daemon+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lmicrohttpd $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char MHD_start_daemon (); int main () { return MHD_start_daemon (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_microhttpd_MHD_start_daemon=yes else ac_cv_lib_microhttpd_MHD_start_daemon=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_microhttpd_MHD_start_daemon" >&5 $as_echo "$ac_cv_lib_microhttpd_MHD_start_daemon" >&6; } if test "x$ac_cv_lib_microhttpd_MHD_start_daemon" = x""yes; then : EXT_LIB_PATH="-L$with_microhttpd/lib $EXT_LIB_PATH" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libmicrohttpd >= 0.9.18" >&5 $as_echo_n "checking for libmicrohttpd >= 0.9.18... " >&6; } if test "$cross_compiling" = yes; then : lmhd=1 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include "$srcdir/src/include/platform.h" #include int main () { return MHD_VERSION >= 0x0091200 ? 0 : 1; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } lmhd=1 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi fi done ;; esac else { $as_echo "$as_me:${as_lineno-$LINENO}: result: --with-microhttpd not specified" >&5 $as_echo "--with-microhttpd not specified" >&6; } for ac_header in microhttpd.h do : ac_fn_c_check_header_compile "$LINENO" "microhttpd.h" "ac_cv_header_microhttpd_h" "#include \"$srcdir/src/include/platform.h\" " if test "x$ac_cv_header_microhttpd_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_MICROHTTPD_H 1 _ACEOF ac_fn_c_check_decl "$LINENO" "MHD_OPTION_PER_IP_CONNECTION_LIMIT" "ac_cv_have_decl_MHD_OPTION_PER_IP_CONNECTION_LIMIT" "#include \"$srcdir/src/include/platform.h\" #include " if test "x$ac_cv_have_decl_MHD_OPTION_PER_IP_CONNECTION_LIMIT" = x""yes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for MHD_start_daemon in -lmicrohttpd" >&5 $as_echo_n "checking for MHD_start_daemon in -lmicrohttpd... " >&6; } if test "${ac_cv_lib_microhttpd_MHD_start_daemon+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lmicrohttpd $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char MHD_start_daemon (); int main () { return MHD_start_daemon (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_microhttpd_MHD_start_daemon=yes else ac_cv_lib_microhttpd_MHD_start_daemon=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_microhttpd_MHD_start_daemon" >&5 $as_echo "$ac_cv_lib_microhttpd_MHD_start_daemon" >&6; } if test "x$ac_cv_lib_microhttpd_MHD_start_daemon" = x""yes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libmicrohttpd >= 0.9.18" >&5 $as_echo_n "checking for libmicrohttpd >= 0.9.18... " >&6; } if test "$cross_compiling" = yes; then : lmhd=1 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include "$srcdir/src/include/platform.h" #include int main () { return MHD_VERSION >= 0x0091200 ? 0 : 1; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } lmhd=1 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi fi done fi if test x$lmhd = x1; then HAVE_MHD_TRUE= HAVE_MHD_FALSE='#' else HAVE_MHD_TRUE='#' HAVE_MHD_FALSE= fi cat >>confdefs.h <<_ACEOF #define HAVE_MHD $lmhd _ACEOF # restore LIBS LIBS=$SAVE_LIBS # check for python & pexpect (used for some testcases only) if test -n "$PYTHON"; then # If the user set $PYTHON, use it and don't search something else. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $PYTHON version >= 2.6" >&5 $as_echo_n "checking whether $PYTHON version >= 2.6... " >&6; } prog="import sys # split strings by '.' and convert to numeric. Append some zeros # because we need at least 4 digits for the hex conversion. # map returns an iterator in Python 3.0 and a list in 2.x minver = list(map(int, '2.6'.split('.'))) + [0, 0, 0] minverhex = 0 # xrange is not present in Python 3.0 and range returns an iterator for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[i] sys.exit(sys.hexversion < minverhex)" if { echo "$as_me:$LINENO: $PYTHON -c "$prog"" >&5 ($PYTHON -c "$prog") >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else as_fn_error $? "too old" "$LINENO" 5 fi am_display_PYTHON=$PYTHON else # Otherwise, try each interpreter until we find one that satisfies # VERSION. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a Python interpreter with version >= 2.6" >&5 $as_echo_n "checking for a Python interpreter with version >= 2.6... " >&6; } if test "${am_cv_pathless_PYTHON+set}" = set; then : $as_echo_n "(cached) " >&6 else for am_cv_pathless_PYTHON in python python2 python3 python3.0 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 none; do test "$am_cv_pathless_PYTHON" = none && break prog="import sys # split strings by '.' and convert to numeric. Append some zeros # because we need at least 4 digits for the hex conversion. # map returns an iterator in Python 3.0 and a list in 2.x minver = list(map(int, '2.6'.split('.'))) + [0, 0, 0] minverhex = 0 # xrange is not present in Python 3.0 and range returns an iterator for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[i] sys.exit(sys.hexversion < minverhex)" if { echo "$as_me:$LINENO: $am_cv_pathless_PYTHON -c "$prog"" >&5 ($am_cv_pathless_PYTHON -c "$prog") >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then : break fi done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_pathless_PYTHON" >&5 $as_echo "$am_cv_pathless_PYTHON" >&6; } # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON. if test "$am_cv_pathless_PYTHON" = none; then PYTHON=: else # Extract the first word of "$am_cv_pathless_PYTHON", so it can be a program name with args. set dummy $am_cv_pathless_PYTHON; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_PYTHON+set}" = set; then : $as_echo_n "(cached) " >&6 else case $PYTHON in [\\/]* | ?:[\\/]*) ac_cv_path_PYTHON="$PYTHON" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_PYTHON="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PYTHON=$ac_cv_path_PYTHON if test -n "$PYTHON"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON" >&5 $as_echo "$PYTHON" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi am_display_PYTHON=$am_cv_pathless_PYTHON fi if test "$PYTHON" = :; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON version" >&5 $as_echo_n "checking for $am_display_PYTHON version... " >&6; } if test "${am_cv_python_version+set}" = set; then : $as_echo_n "(cached) " >&6 else am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[:3])"` fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_version" >&5 $as_echo "$am_cv_python_version" >&6; } PYTHON_VERSION=$am_cv_python_version PYTHON_PREFIX='${prefix}' PYTHON_EXEC_PREFIX='${exec_prefix}' { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON platform" >&5 $as_echo_n "checking for $am_display_PYTHON platform... " >&6; } if test "${am_cv_python_platform+set}" = set; then : $as_echo_n "(cached) " >&6 else am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"` fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_platform" >&5 $as_echo "$am_cv_python_platform" >&6; } PYTHON_PLATFORM=$am_cv_python_platform { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON script directory" >&5 $as_echo_n "checking for $am_display_PYTHON script directory... " >&6; } if test "${am_cv_python_pythondir+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "x$prefix" = xNONE then am_py_prefix=$ac_default_prefix else am_py_prefix=$prefix fi am_cv_python_pythondir=`$PYTHON -c "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_python_lib(0,0,prefix='$am_py_prefix'))" 2>/dev/null || echo "$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages"` case $am_cv_python_pythondir in $am_py_prefix*) am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'` am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"` ;; *) case $am_py_prefix in /usr|/System*) ;; *) am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages ;; esac ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pythondir" >&5 $as_echo "$am_cv_python_pythondir" >&6; } pythondir=$am_cv_python_pythondir pkgpythondir=\${pythondir}/$PACKAGE { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON extension module directory" >&5 $as_echo_n "checking for $am_display_PYTHON extension module directory... " >&6; } if test "${am_cv_python_pyexecdir+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "x$exec_prefix" = xNONE then am_py_exec_prefix=$am_py_prefix else am_py_exec_prefix=$exec_prefix fi am_cv_python_pyexecdir=`$PYTHON -c "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_python_lib(1,0,prefix='$am_py_exec_prefix'))" 2>/dev/null || echo "$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages"` case $am_cv_python_pyexecdir in $am_py_exec_prefix*) am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'` am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"` ;; *) case $am_py_exec_prefix in /usr|/System*) ;; *) am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages ;; esac ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pyexecdir" >&5 $as_echo "$am_cv_python_pyexecdir" >&6; } pyexecdir=$am_cv_python_pyexecdir pkgpyexecdir=\${pyexecdir}/$PACKAGE fi if test "$PYTHON" != :; then HAVE_PYTHON_TRUE= HAVE_PYTHON_FALSE='#' else HAVE_PYTHON_TRUE='#' HAVE_PYTHON_FALSE= fi if test "$PYTHON" != : then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pexpect" >&5 $as_echo_n "checking for pexpect... " >&6; } $PYTHON -c "import pexpect" > /dev/null 2> /dev/null PYEX=$? if test $PYEX -eq 0; then HAVE_PYTHON_PEXPECT_TRUE= HAVE_PYTHON_PEXPECT_FALSE='#' else HAVE_PYTHON_PEXPECT_TRUE='#' HAVE_PYTHON_PEXPECT_FALSE= fi if test $PYEX -eq 0 then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } fi else if 0; then HAVE_PYTHON_PEXPECT_TRUE= HAVE_PYTHON_PEXPECT_FALSE='#' else HAVE_PYTHON_PEXPECT_TRUE='#' HAVE_PYTHON_PEXPECT_FALSE= fi fi # check for gettext { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether NLS is requested" >&5 $as_echo_n "checking whether NLS is requested... " >&6; } # Check whether --enable-nls was given. if test "${enable_nls+set}" = set; then : enableval=$enable_nls; USE_NLS=$enableval else USE_NLS=yes fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_NLS" >&5 $as_echo "$USE_NLS" >&6; } # Prepare PATH_SEPARATOR. # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi # Find out how to test for executable files. Don't use a zero-byte file, # as systems may use methods other than mode bits to determine executability. cat >conf$$.file <<_ASEOF #! /bin/sh exit 0 _ASEOF chmod +x conf$$.file if test -x conf$$.file >/dev/null 2>&1; then ac_executable_p="test -x" else ac_executable_p="test -f" fi rm -f conf$$.file # Extract the first word of "msgfmt", so it can be a program name with args. set dummy msgfmt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_MSGFMT+set}" = set; then : $as_echo_n "(cached) " >&6 else case "$MSGFMT" in [\\/]* | ?:[\\/]*) ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a path. ;; *) ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$ac_save_IFS" test -z "$ac_dir" && ac_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then echo "$as_me: trying $ac_dir/$ac_word..." >&5 if $ac_dir/$ac_word --statistics /dev/null >&5 2>&1 && (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then ac_cv_path_MSGFMT="$ac_dir/$ac_word$ac_exec_ext" break 2 fi fi done done IFS="$ac_save_IFS" test -z "$ac_cv_path_MSGFMT" && ac_cv_path_MSGFMT=":" ;; esac fi MSGFMT="$ac_cv_path_MSGFMT" if test "$MSGFMT" != ":"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGFMT" >&5 $as_echo "$MSGFMT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "gmsgfmt", so it can be a program name with args. set dummy gmsgfmt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_GMSGFMT+set}" = set; then : $as_echo_n "(cached) " >&6 else case $GMSGFMT in [\\/]* | ?:[\\/]*) ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_GMSGFMT="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_GMSGFMT" && ac_cv_path_GMSGFMT="$MSGFMT" ;; esac fi GMSGFMT=$ac_cv_path_GMSGFMT if test -n "$GMSGFMT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GMSGFMT" >&5 $as_echo "$GMSGFMT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi case `$MSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) MSGFMT_015=: ;; *) MSGFMT_015=$MSGFMT ;; esac case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) GMSGFMT_015=: ;; *) GMSGFMT_015=$GMSGFMT ;; esac # Prepare PATH_SEPARATOR. # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi # Find out how to test for executable files. Don't use a zero-byte file, # as systems may use methods other than mode bits to determine executability. cat >conf$$.file <<_ASEOF #! /bin/sh exit 0 _ASEOF chmod +x conf$$.file if test -x conf$$.file >/dev/null 2>&1; then ac_executable_p="test -x" else ac_executable_p="test -f" fi rm -f conf$$.file # Extract the first word of "xgettext", so it can be a program name with args. set dummy xgettext; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_XGETTEXT+set}" = set; then : $as_echo_n "(cached) " >&6 else case "$XGETTEXT" in [\\/]* | ?:[\\/]*) ac_cv_path_XGETTEXT="$XGETTEXT" # Let the user override the test with a path. ;; *) ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$ac_save_IFS" test -z "$ac_dir" && ac_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then echo "$as_me: trying $ac_dir/$ac_word..." >&5 if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >&5 2>&1 && (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then ac_cv_path_XGETTEXT="$ac_dir/$ac_word$ac_exec_ext" break 2 fi fi done done IFS="$ac_save_IFS" test -z "$ac_cv_path_XGETTEXT" && ac_cv_path_XGETTEXT=":" ;; esac fi XGETTEXT="$ac_cv_path_XGETTEXT" if test "$XGETTEXT" != ":"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XGETTEXT" >&5 $as_echo "$XGETTEXT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f messages.po case `$XGETTEXT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) XGETTEXT_015=: ;; *) XGETTEXT_015=$XGETTEXT ;; esac # Prepare PATH_SEPARATOR. # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi # Find out how to test for executable files. Don't use a zero-byte file, # as systems may use methods other than mode bits to determine executability. cat >conf$$.file <<_ASEOF #! /bin/sh exit 0 _ASEOF chmod +x conf$$.file if test -x conf$$.file >/dev/null 2>&1; then ac_executable_p="test -x" else ac_executable_p="test -f" fi rm -f conf$$.file # Extract the first word of "msgmerge", so it can be a program name with args. set dummy msgmerge; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_MSGMERGE+set}" = set; then : $as_echo_n "(cached) " >&6 else case "$MSGMERGE" in [\\/]* | ?:[\\/]*) ac_cv_path_MSGMERGE="$MSGMERGE" # Let the user override the test with a path. ;; *) ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$ac_save_IFS" test -z "$ac_dir" && ac_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then echo "$as_me: trying $ac_dir/$ac_word..." >&5 if $ac_dir/$ac_word --update -q /dev/null /dev/null >&5 2>&1; then ac_cv_path_MSGMERGE="$ac_dir/$ac_word$ac_exec_ext" break 2 fi fi done done IFS="$ac_save_IFS" test -z "$ac_cv_path_MSGMERGE" && ac_cv_path_MSGMERGE=":" ;; esac fi MSGMERGE="$ac_cv_path_MSGMERGE" if test "$MSGMERGE" != ":"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGMERGE" >&5 $as_echo "$MSGMERGE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$localedir" || localedir='${datadir}/locale' ac_config_commands="$ac_config_commands po-directories" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFPreferencesCopyAppValue" >&5 $as_echo_n "checking for CFPreferencesCopyAppValue... " >&6; } if test "${gt_cv_func_CFPreferencesCopyAppValue+set}" = set; then : $as_echo_n "(cached) " >&6 else gt_save_LIBS="$LIBS" LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { CFPreferencesCopyAppValue(NULL, NULL) ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : gt_cv_func_CFPreferencesCopyAppValue=yes else gt_cv_func_CFPreferencesCopyAppValue=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$gt_save_LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFPreferencesCopyAppValue" >&5 $as_echo "$gt_cv_func_CFPreferencesCopyAppValue" >&6; } if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then $as_echo "#define HAVE_CFPREFERENCESCOPYAPPVALUE 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFLocaleCopyCurrent" >&5 $as_echo_n "checking for CFLocaleCopyCurrent... " >&6; } if test "${gt_cv_func_CFLocaleCopyCurrent+set}" = set; then : $as_echo_n "(cached) " >&6 else gt_save_LIBS="$LIBS" LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { CFLocaleCopyCurrent(); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : gt_cv_func_CFLocaleCopyCurrent=yes else gt_cv_func_CFLocaleCopyCurrent=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$gt_save_LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFLocaleCopyCurrent" >&5 $as_echo "$gt_cv_func_CFLocaleCopyCurrent" >&6; } if test $gt_cv_func_CFLocaleCopyCurrent = yes; then $as_echo "#define HAVE_CFLOCALECOPYCURRENT 1" >>confdefs.h fi INTL_MACOSX_LIBS= if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation" fi LIBINTL= LTLIBINTL= POSUB= case " $gt_needs " in *" need-formatstring-macros "*) gt_api_version=3 ;; *" need-ngettext "*) gt_api_version=2 ;; *) gt_api_version=1 ;; esac gt_func_gnugettext_libc="gt_cv_func_gnugettext${gt_api_version}_libc" gt_func_gnugettext_libintl="gt_cv_func_gnugettext${gt_api_version}_libintl" if test "$USE_NLS" = "yes"; then gt_use_preinstalled_gnugettext=no if test $gt_api_version -ge 3; then gt_revision_test_code=' #ifndef __GNU_GETTEXT_SUPPORTED_REVISION #define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) #endif typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; ' else gt_revision_test_code= fi if test $gt_api_version -ge 2; then gt_expression_test_code=' + * ngettext ("", "", 0)' else gt_expression_test_code= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU gettext in libc" >&5 $as_echo_n "checking for GNU gettext in libc... " >&6; } if eval "test \"\${$gt_func_gnugettext_libc+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include $gt_revision_test_code extern int _nl_msg_cat_cntr; extern int *_nl_domain_bindings; int main () { bindtextdomain ("", ""); return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_domain_bindings ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$gt_func_gnugettext_libc=yes" else eval "$gt_func_gnugettext_libc=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$gt_func_gnugettext_libc { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then am_save_CPPFLAGS="$CPPFLAGS" for element in $INCICONV; do haveit= for x in $CPPFLAGS; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X$element"; then haveit=yes break fi done if test -z "$haveit"; then CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv" >&5 $as_echo_n "checking for iconv... " >&6; } if test "${am_cv_func_iconv+set}" = set; then : $as_echo_n "(cached) " >&6 else am_cv_func_iconv="no, consider installing GNU libiconv" am_cv_lib_iconv=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : am_cv_func_iconv=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$am_cv_func_iconv" != yes; then am_save_LIBS="$LIBS" LIBS="$LIBS $LIBICONV" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : am_cv_lib_iconv=yes am_cv_func_iconv=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$am_save_LIBS" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv" >&5 $as_echo "$am_cv_func_iconv" >&6; } if test "$am_cv_func_iconv" = yes; then $as_echo "#define HAVE_ICONV 1" >>confdefs.h fi if test "$am_cv_lib_iconv" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libiconv" >&5 $as_echo_n "checking how to link with libiconv... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBICONV" >&5 $as_echo "$LIBICONV" >&6; } else CPPFLAGS="$am_save_CPPFLAGS" LIBICONV= LTLIBICONV= fi use_additional=yes acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" # Check whether --with-libintl-prefix was given. if test "${with_libintl_prefix+set}" = set; then : withval=$with_libintl_prefix; if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" fi fi fi LIBINTL= LTLIBINTL= INCINTL= rpathdirs= ltrpathdirs= names_already_handled= names_next_round='intl ' while test -n "$names_next_round"; do names_this_round="$names_next_round" names_next_round= for name in $names_this_round; do already_handled= for n in $names_already_handled; do if test "$n" = "$name"; then already_handled=yes break fi done if test -z "$already_handled"; then names_already_handled="$names_already_handled $name" uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` eval value=\"\$HAVE_LIB$uppername\" if test -n "$value"; then if test "$value" = yes; then eval value=\"\$LIB$uppername\" test -z "$value" || LIBINTL="${LIBINTL}${LIBINTL:+ }$value" eval value=\"\$LTLIB$uppername\" test -z "$value" || LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }$value" else : fi else found_dir= found_la= found_so= found_a= if test $use_additional = yes; then if test -n "$shlibext" \ && { test -f "$additional_libdir/lib$name.$shlibext" \ || { test "$shlibext" = dll \ && test -f "$additional_libdir/lib$name.dll.a"; }; }; then found_dir="$additional_libdir" if test -f "$additional_libdir/lib$name.$shlibext"; then found_so="$additional_libdir/lib$name.$shlibext" else found_so="$additional_libdir/lib$name.dll.a" fi if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi else if test -f "$additional_libdir/lib$name.$libext"; then found_dir="$additional_libdir" found_a="$additional_libdir/lib$name.$libext" if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi fi fi fi if test "X$found_dir" = "X"; then for x in $LDFLAGS $LTLIBINTL; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" case "$x" in -L*) dir=`echo "X$x" | sed -e 's/^X-L//'` if test -n "$shlibext" \ && { test -f "$dir/lib$name.$shlibext" \ || { test "$shlibext" = dll \ && test -f "$dir/lib$name.dll.a"; }; }; then found_dir="$dir" if test -f "$dir/lib$name.$shlibext"; then found_so="$dir/lib$name.$shlibext" else found_so="$dir/lib$name.dll.a" fi if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi else if test -f "$dir/lib$name.$libext"; then found_dir="$dir" found_a="$dir/lib$name.$libext" if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi fi fi ;; esac if test "X$found_dir" != "X"; then break fi done fi if test "X$found_dir" != "X"; then LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-L$found_dir -l$name" if test "X$found_so" != "X"; then if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" else haveit= for x in $ltrpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $found_dir" fi if test "$hardcode_direct" = yes; then LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" else if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" haveit= for x in $rpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $found_dir" fi else haveit= for x in $LDFLAGS $LIBINTL; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then LIBINTL="${LIBINTL}${LIBINTL:+ }-L$found_dir" fi if test "$hardcode_minus_L" != no; then LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" else LIBINTL="${LIBINTL}${LIBINTL:+ }-l$name" fi fi fi fi else if test "X$found_a" != "X"; then LIBINTL="${LIBINTL}${LIBINTL:+ }$found_a" else LIBINTL="${LIBINTL}${LIBINTL:+ }-L$found_dir -l$name" fi fi additional_includedir= case "$found_dir" in */$acl_libdirstem | */$acl_libdirstem/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` additional_includedir="$basedir/include" ;; esac if test "X$additional_includedir" != "X"; then if test "X$additional_includedir" != "X/usr/include"; then haveit= if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then for x in $CPPFLAGS $INCINTL; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_includedir"; then INCINTL="${INCINTL}${INCINTL:+ }-I$additional_includedir" fi fi fi fi fi if test -n "$found_la"; then save_libdir="$libdir" case "$found_la" in */* | *\\*) . "$found_la" ;; *) . "./$found_la" ;; esac libdir="$save_libdir" for dep in $dependency_libs; do case "$dep" in -L*) additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then haveit= if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then haveit= for x in $LDFLAGS $LIBINTL; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then LIBINTL="${LIBINTL}${LIBINTL:+ }-L$additional_libdir" fi fi haveit= for x in $LDFLAGS $LTLIBINTL; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-L$additional_libdir" fi fi fi fi ;; -R*) dir=`echo "X$dep" | sed -e 's/^X-R//'` if test "$enable_rpath" != no; then haveit= for x in $rpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $dir" fi haveit= for x in $ltrpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $dir" fi fi ;; -l*) names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` ;; *.la) names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` ;; *) LIBINTL="${LIBINTL}${LIBINTL:+ }$dep" LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }$dep" ;; esac done fi else LIBINTL="${LIBINTL}${LIBINTL:+ }-l$name" LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-l$name" fi fi fi done done if test "X$rpathdirs" != "X"; then if test -n "$hardcode_libdir_separator"; then alldirs= for found_dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" done acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIBINTL="${LIBINTL}${LIBINTL:+ }$flag" else for found_dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$found_dir" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIBINTL="${LIBINTL}${LIBINTL:+ }$flag" done fi fi if test "X$ltrpathdirs" != "X"; then for found_dir in $ltrpathdirs; do LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-R$found_dir" done fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU gettext in libintl" >&5 $as_echo_n "checking for GNU gettext in libintl... " >&6; } if eval "test \"\${$gt_func_gnugettext_libintl+set}\"" = set; then : $as_echo_n "(cached) " >&6 else gt_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $INCINTL" gt_save_LIBS="$LIBS" LIBS="$LIBS $LIBINTL" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include $gt_revision_test_code extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias (const char *); int main () { bindtextdomain ("", ""); return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("") ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$gt_func_gnugettext_libintl=yes" else eval "$gt_func_gnugettext_libintl=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" != yes; } && test -n "$LIBICONV"; then LIBS="$LIBS $LIBICONV" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include $gt_revision_test_code extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias (const char *); int main () { bindtextdomain ("", ""); return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("") ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : LIBINTL="$LIBINTL $LIBICONV" LTLIBINTL="$LTLIBINTL $LTLIBICONV" eval "$gt_func_gnugettext_libintl=yes" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi CPPFLAGS="$gt_save_CPPFLAGS" LIBS="$gt_save_LIBS" fi eval ac_res=\$$gt_func_gnugettext_libintl { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" = "yes"; } \ || { { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; } \ && test "$PACKAGE" != gettext-runtime \ && test "$PACKAGE" != gettext-tools; }; then gt_use_preinstalled_gnugettext=yes else LIBINTL= LTLIBINTL= INCINTL= fi if test -n "$INTL_MACOSX_LIBS"; then if test "$gt_use_preinstalled_gnugettext" = "yes" \ || test "$nls_cv_use_gnu_gettext" = "yes"; then LIBINTL="$LIBINTL $INTL_MACOSX_LIBS" LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS" fi fi if test "$gt_use_preinstalled_gnugettext" = "yes" \ || test "$nls_cv_use_gnu_gettext" = "yes"; then $as_echo "#define ENABLE_NLS 1" >>confdefs.h else USE_NLS=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use NLS" >&5 $as_echo_n "checking whether to use NLS... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_NLS" >&5 $as_echo "$USE_NLS" >&6; } if test "$USE_NLS" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking where the gettext function comes from" >&5 $as_echo_n "checking where the gettext function comes from... " >&6; } if test "$gt_use_preinstalled_gnugettext" = "yes"; then if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then gt_source="external libintl" else gt_source="libc" fi else gt_source="included intl directory" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_source" >&5 $as_echo "$gt_source" >&6; } fi if test "$USE_NLS" = "yes"; then if test "$gt_use_preinstalled_gnugettext" = "yes"; then if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libintl" >&5 $as_echo_n "checking how to link with libintl... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBINTL" >&5 $as_echo "$LIBINTL" >&6; } for element in $INCINTL; do haveit= for x in $CPPFLAGS; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X$element"; then haveit=yes break fi done if test -z "$haveit"; then CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" fi done fi $as_echo "#define HAVE_GETTEXT 1" >>confdefs.h $as_echo "#define HAVE_DCGETTEXT 1" >>confdefs.h fi POSUB=po fi INTLLIBS="$LIBINTL" # check for iconv am_save_CPPFLAGS="$CPPFLAGS" for element in $INCICONV; do haveit= for x in $CPPFLAGS; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X$element"; then haveit=yes break fi done if test -z "$haveit"; then CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv" >&5 $as_echo_n "checking for iconv... " >&6; } if test "${am_cv_func_iconv+set}" = set; then : $as_echo_n "(cached) " >&6 else am_cv_func_iconv="no, consider installing GNU libiconv" am_cv_lib_iconv=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : am_cv_func_iconv=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$am_cv_func_iconv" != yes; then am_save_LIBS="$LIBS" LIBS="$LIBS $LIBICONV" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : am_cv_lib_iconv=yes am_cv_func_iconv=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$am_save_LIBS" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv" >&5 $as_echo "$am_cv_func_iconv" >&6; } if test "$am_cv_func_iconv" = yes; then $as_echo "#define HAVE_ICONV 1" >>confdefs.h fi if test "$am_cv_lib_iconv" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libiconv" >&5 $as_echo_n "checking how to link with libiconv... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBICONV" >&5 $as_echo "$LIBICONV" >&6; } else CPPFLAGS="$am_save_CPPFLAGS" LIBICONV= LTLIBICONV= fi if test "$am_cv_func_iconv" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv declaration" >&5 $as_echo_n "checking for iconv declaration... " >&6; } if test "${am_cv_proto_iconv+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include extern #ifdef __cplusplus "C" #endif #if defined(__STDC__) || defined(__cplusplus) size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); #else size_t iconv(); #endif int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : am_cv_proto_iconv_arg1="" else am_cv_proto_iconv_arg1="const" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);" fi am_cv_proto_iconv=`echo "$am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_t:- }$am_cv_proto_iconv" >&5 $as_echo "${ac_t:- }$am_cv_proto_iconv" >&6; } cat >>confdefs.h <<_ACEOF #define ICONV_CONST $am_cv_proto_iconv_arg1 _ACEOF fi # Checks for standard typedefs, structures, and compiler characteristics. ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" if test "x$ac_cv_type_pid_t" = x""yes; then : else cat >>confdefs.h <<_ACEOF #define pid_t int _ACEOF fi ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = x""yes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned int _ACEOF fi ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" if test "x$ac_cv_type_mode_t" = x""yes; then : else cat >>confdefs.h <<_ACEOF #define mode_t int _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 $as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } if test "${ac_cv_header_time+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main () { if ((struct tm *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_time=yes else ac_cv_header_time=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5 $as_echo "$ac_cv_header_time" >&6; } if test $ac_cv_header_time = yes; then $as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stat file-mode macros are broken" >&5 $as_echo_n "checking whether stat file-mode macros are broken... " >&6; } if test "${ac_cv_header_stat_broken+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if defined S_ISBLK && defined S_IFDIR extern char c1[S_ISBLK (S_IFDIR) ? -1 : 1]; #endif #if defined S_ISBLK && defined S_IFCHR extern char c2[S_ISBLK (S_IFCHR) ? -1 : 1]; #endif #if defined S_ISLNK && defined S_IFREG extern char c3[S_ISLNK (S_IFREG) ? -1 : 1]; #endif #if defined S_ISSOCK && defined S_IFREG extern char c4[S_ISSOCK (S_IFREG) ? -1 : 1]; #endif _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stat_broken=no else ac_cv_header_stat_broken=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stat_broken" >&5 $as_echo "$ac_cv_header_stat_broken" >&6; } if test $ac_cv_header_stat_broken = yes; then $as_echo "#define STAT_MACROS_BROKEN 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5 $as_echo_n "checking for stdbool.h that conforms to C99... " >&6; } if test "${ac_cv_header_stdbool_h+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifndef bool "error: bool is not defined" #endif #ifndef false "error: false is not defined" #endif #if false "error: false is not 0" #endif #ifndef true "error: true is not defined" #endif #if true != 1 "error: true is not 1" #endif #ifndef __bool_true_false_are_defined "error: __bool_true_false_are_defined is not defined" #endif struct s { _Bool s: 1; _Bool t; } s; char a[true == 1 ? 1 : -1]; char b[false == 0 ? 1 : -1]; char c[__bool_true_false_are_defined == 1 ? 1 : -1]; char d[(bool) 0.5 == true ? 1 : -1]; bool e = &s; char f[(_Bool) 0.0 == false ? 1 : -1]; char g[true]; char h[sizeof (_Bool)]; char i[sizeof s.t]; enum { j = false, k = true, l = false * true, m = true * 256 }; /* The following fails for HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */ _Bool n[m]; char o[sizeof n == m * sizeof n[0] ? 1 : -1]; char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1]; # if defined __xlc__ || defined __GNUC__ /* Catch a bug in IBM AIX xlc compiler version 6.0.0.0 reported by James Lemley on 2005-10-05; see http://lists.gnu.org/archive/html/bug-coreutils/2005-10/msg00086.html This test is not quite right, since xlc is allowed to reject this program, as the initializer for xlcbug is not one of the forms that C requires support for. However, doing the test right would require a runtime test, and that would make cross-compilation harder. Let us hope that IBM fixes the xlc bug, and also adds support for this kind of constant expression. In the meantime, this test will reject xlc, which is OK, since our stdbool.h substitute should suffice. We also test this with GCC, where it should work, to detect more quickly whether someone messes up the test in the future. */ char digs[] = "0123456789"; int xlcbug = 1 / (&(digs + 5)[-2 + (bool) 1] == &digs[4] ? 1 : -1); # endif /* Catch a bug in an HP-UX C compiler. See http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html */ _Bool q = true; _Bool *pq = &q; int main () { *pq |= q; *pq |= ! q; /* Refer to every declared value, to avoid compiler optimizations. */ return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l + !m + !n + !o + !p + !q + !pq); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdbool_h=yes else ac_cv_header_stdbool_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5 $as_echo "$ac_cv_header_stdbool_h" >&6; } ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default" if test "x$ac_cv_type__Bool" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE__BOOL 1 _ACEOF fi if test $ac_cv_header_stdbool_h = yes; then $as_echo "#define HAVE_STDBOOL_H 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 $as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } if test "${ac_cv_struct_tm+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { struct tm tm; int *p = &tm.tm_sec; return !p; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_struct_tm=time.h else ac_cv_struct_tm=sys/time.h fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 $as_echo "$ac_cv_struct_tm" >&6; } if test $ac_cv_struct_tm = sys/time.h; then $as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct sockaddr_in" "sin_len" "ac_cv_member_struct_sockaddr_in_sin_len" " #include #include #include " if test "x$ac_cv_member_struct_sockaddr_in_sin_len" = x""yes; then : $as_echo "#define HAVE_SOCKADDR_IN_SIN_LEN 1" >>confdefs.h fi # Checks for library functions. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether closedir returns void" >&5 $as_echo_n "checking whether closedir returns void... " >&6; } if test "${ac_cv_func_closedir_void+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_closedir_void=yes else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #include <$ac_header_dirent> #ifndef __cplusplus int closedir (); #endif int main () { return closedir (opendir (".")) != 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_closedir_void=no else ac_cv_func_closedir_void=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_closedir_void" >&5 $as_echo "$ac_cv_func_closedir_void" >&6; } if test $ac_cv_func_closedir_void = yes; then $as_echo "#define CLOSEDIR_VOID 1" >>confdefs.h fi for ac_header in vfork.h do : ac_fn_c_check_header_mongrel "$LINENO" "vfork.h" "ac_cv_header_vfork_h" "$ac_includes_default" if test "x$ac_cv_header_vfork_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_VFORK_H 1 _ACEOF fi done for ac_func in fork vfork do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done if test "x$ac_cv_func_fork" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5 $as_echo_n "checking for working fork... " >&6; } if test "${ac_cv_func_fork_works+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_fork_works=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* By Ruediger Kuhlmann. */ return fork () < 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_fork_works=yes else ac_cv_func_fork_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fork_works" >&5 $as_echo "$ac_cv_func_fork_works" >&6; } else ac_cv_func_fork_works=$ac_cv_func_fork fi if test "x$ac_cv_func_fork_works" = xcross; then case $host in *-*-amigaos* | *-*-msdosdjgpp*) # Override, as these systems have only a dummy fork() stub ac_cv_func_fork_works=no ;; *) ac_cv_func_fork_works=yes ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5 $as_echo "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;} fi ac_cv_func_vfork_works=$ac_cv_func_vfork if test "x$ac_cv_func_vfork" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5 $as_echo_n "checking for working vfork... " >&6; } if test "${ac_cv_func_vfork_works+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_vfork_works=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Thanks to Paul Eggert for this test. */ $ac_includes_default #include #ifdef HAVE_VFORK_H # include #endif /* On some sparc systems, changes by the child to local and incoming argument registers are propagated back to the parent. The compiler is told about this with #include , but some compilers (e.g. gcc -O) don't grok . Test for this by using a static variable whose address is put into a register that is clobbered by the vfork. */ static void #ifdef __cplusplus sparc_address_test (int arg) # else sparc_address_test (arg) int arg; #endif { static pid_t child; if (!child) { child = vfork (); if (child < 0) { perror ("vfork"); _exit(2); } if (!child) { arg = getpid(); write(-1, "", 0); _exit (arg); } } } int main () { pid_t parent = getpid (); pid_t child; sparc_address_test (0); child = vfork (); if (child == 0) { /* Here is another test for sparc vfork register problems. This test uses lots of local variables, at least as many local variables as main has allocated so far including compiler temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should reuse the register of parent for one of the local variables, since it will think that parent can't possibly be used any more in this routine. Assigning to the local variable will thus munge parent in the parent process. */ pid_t p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); /* Convince the compiler that p..p7 are live; otherwise, it might use the same hardware register for all 8 local variables. */ if (p != p1 || p != p2 || p != p3 || p != p4 || p != p5 || p != p6 || p != p7) _exit(1); /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent from child file descriptors. If the child closes a descriptor before it execs or exits, this munges the parent's descriptor as well. Test for this by closing stdout in the child. */ _exit(close(fileno(stdout)) != 0); } else { int status; struct stat st; while (wait(&status) != child) ; return ( /* Was there some problem with vforking? */ child < 0 /* Did the child fail? (This shouldn't happen.) */ || status /* Did the vfork/compiler bug occur? */ || parent != getpid() /* Did the file descriptor bug occur? */ || fstat(fileno(stdout), &st) != 0 ); } } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_vfork_works=yes else ac_cv_func_vfork_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vfork_works" >&5 $as_echo "$ac_cv_func_vfork_works" >&6; } fi; if test "x$ac_cv_func_fork_works" = xcross; then ac_cv_func_vfork_works=$ac_cv_func_vfork { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5 $as_echo "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;} fi if test "x$ac_cv_func_vfork_works" = xyes; then $as_echo "#define HAVE_WORKING_VFORK 1" >>confdefs.h else $as_echo "#define vfork fork" >>confdefs.h fi if test "x$ac_cv_func_fork_works" = xyes; then $as_echo "#define HAVE_WORKING_FORK 1" >>confdefs.h fi if test $ac_cv_c_compiler_gnu = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC needs -traditional" >&5 $as_echo_n "checking whether $CC needs -traditional... " >&6; } if test "${ac_cv_prog_gcc_traditional+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_pattern="Autoconf.*'x'" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Autoconf TIOCGETP _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "$ac_pattern" >/dev/null 2>&1; then : ac_cv_prog_gcc_traditional=yes else ac_cv_prog_gcc_traditional=no fi rm -f conftest* if test $ac_cv_prog_gcc_traditional = no; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Autoconf TCGETA _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "$ac_pattern" >/dev/null 2>&1; then : ac_cv_prog_gcc_traditional=yes fi rm -f conftest* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gcc_traditional" >&5 $as_echo "$ac_cv_prog_gcc_traditional" >&6; } if test $ac_cv_prog_gcc_traditional = yes; then CC="$CC -traditional" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working memcmp" >&5 $as_echo_n "checking for working memcmp... " >&6; } if test "${ac_cv_func_memcmp_working+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_memcmp_working=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* Some versions of memcmp are not 8-bit clean. */ char c0 = '\100', c1 = '\200', c2 = '\201'; if (memcmp(&c0, &c2, 1) >= 0 || memcmp(&c1, &c2, 1) >= 0) return 1; /* The Next x86 OpenStep bug shows up only when comparing 16 bytes or more and with at least one buffer not starting on a 4-byte boundary. William Lewis provided this test program. */ { char foo[21]; char bar[21]; int i; for (i = 0; i < 4; i++) { char *a = foo + i; char *b = bar + i; strcpy (a, "--------01111111"); strcpy (b, "--------10000000"); if (memcmp (a, b, 16) >= 0) return 1; } return 0; } ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_memcmp_working=yes else ac_cv_func_memcmp_working=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_memcmp_working" >&5 $as_echo "$ac_cv_func_memcmp_working" >&6; } test $ac_cv_func_memcmp_working = no && case " $LIBOBJS " in *" memcmp.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS memcmp.$ac_objext" ;; esac for ac_header in sys/select.h sys/socket.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking types of arguments for select" >&5 $as_echo_n "checking types of arguments for select... " >&6; } if test "${ac_cv_func_select_args+set}" = set; then : $as_echo_n "(cached) " >&6 else for ac_arg234 in 'fd_set *' 'int *' 'void *'; do for ac_arg1 in 'int' 'size_t' 'unsigned long int' 'unsigned int'; do for ac_arg5 in 'struct timeval *' 'const struct timeval *'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #ifdef HAVE_SYS_SELECT_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif int main () { extern int select ($ac_arg1, $ac_arg234, $ac_arg234, $ac_arg234, $ac_arg5); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_func_select_args="$ac_arg1,$ac_arg234,$ac_arg5"; break 3 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done done done # Provide a safe default value. : ${ac_cv_func_select_args='int,int *,struct timeval *'} fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_select_args" >&5 $as_echo "$ac_cv_func_select_args" >&6; } ac_save_IFS=$IFS; IFS=',' set dummy `echo "$ac_cv_func_select_args" | sed 's/\*/\*/g'` IFS=$ac_save_IFS shift cat >>confdefs.h <<_ACEOF #define SELECT_TYPE_ARG1 $1 _ACEOF cat >>confdefs.h <<_ACEOF #define SELECT_TYPE_ARG234 ($2) _ACEOF cat >>confdefs.h <<_ACEOF #define SELECT_TYPE_ARG5 ($3) _ACEOF rm -f conftest* { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 $as_echo_n "checking for uid_t in sys/types.h... " >&6; } if test "${ac_cv_type_uid_t+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "uid_t" >/dev/null 2>&1; then : ac_cv_type_uid_t=yes else ac_cv_type_uid_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 $as_echo "$ac_cv_type_uid_t" >&6; } if test $ac_cv_type_uid_t = no; then $as_echo "#define uid_t int" >>confdefs.h $as_echo "#define gid_t int" >>confdefs.h fi for ac_header in unistd.h do : ac_fn_c_check_header_mongrel "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default" if test "x$ac_cv_header_unistd_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UNISTD_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working chown" >&5 $as_echo_n "checking for working chown... " >&6; } if test "${ac_cv_func_chown_works+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_chown_works=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #include int main () { char *f = "conftest.chown"; struct stat before, after; if (creat (f, 0600) < 0) return 1; if (stat (f, &before) < 0) return 1; if (chown (f, (uid_t) -1, (gid_t) -1) == -1) return 1; if (stat (f, &after) < 0) return 1; return ! (before.st_uid == after.st_uid && before.st_gid == after.st_gid); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_chown_works=yes else ac_cv_func_chown_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f conftest.chown fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_chown_works" >&5 $as_echo "$ac_cv_func_chown_works" >&6; } if test $ac_cv_func_chown_works = yes; then $as_echo "#define HAVE_CHOWN 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5 $as_echo_n "checking return type of signal handlers... " >&6; } if test "${ac_cv_type_signal+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { return *(signal (0, 0)) (0) == 1; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_type_signal=int else ac_cv_type_signal=void fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5 $as_echo "$ac_cv_type_signal" >&6; } cat >>confdefs.h <<_ACEOF #define RETSIGTYPE $ac_cv_type_signal _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lstat correctly handles trailing slash" >&5 $as_echo_n "checking whether lstat correctly handles trailing slash... " >&6; } if test "${ac_cv_func_lstat_dereferences_slashed_symlink+set}" = set; then : $as_echo_n "(cached) " >&6 else rm -f conftest.sym conftest.file echo >conftest.file if test "$as_ln_s" = "ln -s" && ln -s conftest.file conftest.sym; then if test "$cross_compiling" = yes; then : ac_cv_func_lstat_dereferences_slashed_symlink=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { struct stat sbuf; /* Linux will dereference the symlink and fail, as required by POSIX. That is better in the sense that it means we will not have to compile and use the lstat wrapper. */ return lstat ("conftest.sym/", &sbuf) == 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_lstat_dereferences_slashed_symlink=yes else ac_cv_func_lstat_dereferences_slashed_symlink=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi else # If the `ln -s' command failed, then we probably don't even # have an lstat function. ac_cv_func_lstat_dereferences_slashed_symlink=no fi rm -f conftest.sym conftest.file fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_lstat_dereferences_slashed_symlink" >&5 $as_echo "$ac_cv_func_lstat_dereferences_slashed_symlink" >&6; } test $ac_cv_func_lstat_dereferences_slashed_symlink = yes && cat >>confdefs.h <<_ACEOF #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 _ACEOF if test "x$ac_cv_func_lstat_dereferences_slashed_symlink" = xno; then case " $LIBOBJS " in *" lstat.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS lstat.$ac_objext" ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stat accepts an empty string" >&5 $as_echo_n "checking whether stat accepts an empty string... " >&6; } if test "${ac_cv_func_stat_empty_string_bug+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_stat_empty_string_bug=yes else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { struct stat sbuf; return stat ("", &sbuf) == 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_stat_empty_string_bug=no else ac_cv_func_stat_empty_string_bug=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_stat_empty_string_bug" >&5 $as_echo "$ac_cv_func_stat_empty_string_bug" >&6; } if test $ac_cv_func_stat_empty_string_bug = yes; then case " $LIBOBJS " in *" stat.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS stat.$ac_objext" ;; esac cat >>confdefs.h <<_ACEOF #define HAVE_STAT_EMPTY_STRING_BUG 1 _ACEOF fi for ac_func in strftime do : ac_fn_c_check_func "$LINENO" "strftime" "ac_cv_func_strftime" if test "x$ac_cv_func_strftime" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRFTIME 1 _ACEOF else # strftime is in -lintl on SCO UNIX. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strftime in -lintl" >&5 $as_echo_n "checking for strftime in -lintl... " >&6; } if test "${ac_cv_lib_intl_strftime+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lintl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char strftime (); int main () { return strftime (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_intl_strftime=yes else ac_cv_lib_intl_strftime=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_strftime" >&5 $as_echo "$ac_cv_lib_intl_strftime" >&6; } if test "x$ac_cv_lib_intl_strftime" = x""yes; then : $as_echo "#define HAVE_STRFTIME 1" >>confdefs.h LIBS="-lintl $LIBS" fi fi done for ac_func in vprintf do : ac_fn_c_check_func "$LINENO" "vprintf" "ac_cv_func_vprintf" if test "x$ac_cv_func_vprintf" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_VPRINTF 1 _ACEOF ac_fn_c_check_func "$LINENO" "_doprnt" "ac_cv_func__doprnt" if test "x$ac_cv_func__doprnt" = x""yes; then : $as_echo "#define HAVE_DOPRNT 1" >>confdefs.h fi fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 $as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } if test "${ac_cv_header_sys_wait_h+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) #endif #ifndef WIFEXITED # define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif int main () { int s; wait (&s); s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_sys_wait_h=yes else ac_cv_header_sys_wait_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 $as_echo "$ac_cv_header_sys_wait_h" >&6; } if test $ac_cv_header_sys_wait_h = yes; then $as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" if test "x$ac_cv_type_off_t" = x""yes; then : else cat >>confdefs.h <<_ACEOF #define off_t long int _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 $as_echo_n "checking for uid_t in sys/types.h... " >&6; } if test "${ac_cv_type_uid_t+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "uid_t" >/dev/null 2>&1; then : ac_cv_type_uid_t=yes else ac_cv_type_uid_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 $as_echo "$ac_cv_type_uid_t" >&6; } if test $ac_cv_type_uid_t = no; then $as_echo "#define uid_t int" >>confdefs.h $as_echo "#define gid_t int" >>confdefs.h fi for ac_func in floor memmove rmdir strncasecmp strrchr strtol atoll dup2 fdatasync ftruncate gettimeofday memset mkdir mkfifo strcasecmp strchr strdup strerror strstr clock_gettime getrusage rand uname setlocale getcwd mktime gmtime_r gmtime strlcpy strlcat ftruncate stat64 sbrk mmap mremap setrlimit sysconf initgroups getifaddrs freeifaddrs localtime_r nl_langinfo putenv realpath strndup gethostbyname2 gethostbyname getpeerucred getpeereid setresuid $funcstocheck do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done # restore LIBS LIBS=$SAVE_LIBS gn_user_home_dir="~/.gnunet" # Check whether --with-user-home-dir was given. if test "${with_user_home_dir+set}" = set; then : withval=$with_user_home_dir; gn_user_home_dir=$withval fi GN_USER_HOME_DIR=$gn_user_home_dir gn_daemon_home_dir="/var/lib/gnunet" # Check whether --with-daemon-home-dir was given. if test "${with_daemon_home_dir+set}" = set; then : withval=$with_daemon_home_dir; gn_daemon_home_dir=$withval fi GN_DAEMON_HOME_DIR=$gn_daemon_home_dir gn_daemon_config_dir="/etc" # Check whether --with-daemon-config-dir was given. if test "${with_daemon_config_dir+set}" = set; then : withval=$with_daemon_config_dir; gn_daemon_config_dir=$withval fi GN_DAEMON_CONFIG_DIR=$gn_daemon_config_dir GN_INTLINCL="" GN_LIBINTL="$LTLIBINTL" # Check whether --enable-framework was given. if test "${enable_framework+set}" = set; then : enableval=$enable_framework; enable_framework_build=$enableval fi if test x$enable_framework_build = xyes; then WANT_FRAMEWORK_TRUE= WANT_FRAMEWORK_FALSE='#' else WANT_FRAMEWORK_TRUE='#' WANT_FRAMEWORK_FALSE= fi if test x$enable_framework_build = xyes then $as_echo "#define FRAMEWORK_BUILD 1" >>confdefs.h GN_INTLINCL='-I$(top_srcdir)/src/intlemu' GN_LIBINTL='$(top_builddir)/src/intlemu/libintlemu.la -framework CoreFoundation' for element in $GN_INTLINCL; do haveit= for x in $CPPFLAGS; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X$element"; then haveit=yes break fi done if test -z "$haveit"; then CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" fi done fi GN_LIB_LDFLAGS="-export-dynamic -no-undefined" GN_PLUGIN_LDFLAGS="-export-dynamic -avoid-version -module -no-undefined" # test for sudo { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sudo" >&5 $as_echo_n "checking for sudo... " >&6; } # Check whether --with-sudo was given. if test "${with_sudo+set}" = set; then : withval=$with_sudo; { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$with_sudo\"" >&5 $as_echo "\"$with_sudo\"" >&6; } case $with_sudo in no) SUDO_BINARY= ;; yes) SUDO_BINARY=sudo ;; *) SUDO_BINARY=$with_sudo ;; esac else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$SUDO_BINARY" != "x" -o -w /; then HAVE_SUDO_TRUE= HAVE_SUDO_FALSE='#' else HAVE_SUDO_TRUE='#' HAVE_SUDO_FALSE= fi # test for gnunetdns group name GNUNETDNS_GROUP=gnunetdns { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gnunetdns group name" >&5 $as_echo_n "checking for gnunetdns group name... " >&6; } # Check whether --with-gnunetdns was given. if test "${with_gnunetdns+set}" = set; then : withval=$with_gnunetdns; { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$with_gnunetdns\"" >&5 $as_echo "\"$with_gnunetdns\"" >&6; } case $with_gnunetdns in no) GNUNETDNS_GROUP=gnunet ;; yes) GNUNETDNS_GROUP=gnunetdns ;; *) GNUNETDNS_GROUP=$with_gnunetdns ;; esac else { $as_echo "$as_me:${as_lineno-$LINENO}: result: gnunetdns" >&5 $as_echo "gnunetdns" >&6; } fi # should 'make check' run tests? { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to run tests" >&5 $as_echo_n "checking whether to run tests... " >&6; } # Check whether --enable-testruns was given. if test "${enable_testruns+set}" = set; then : enableval=$enable_testruns; enable_tests_run=${enableval} else enable_tests_run=yes fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_test_run" >&5 $as_echo "$enable_test_run" >&6; } if test "x$enable_tests_run" = "xyes"; then ENABLE_TEST_RUN_TRUE= ENABLE_TEST_RUN_FALSE='#' else ENABLE_TEST_RUN_TRUE='#' ENABLE_TEST_RUN_FALSE= fi # should monkey be used when running (certain) services? { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to run with monkey" >&5 $as_echo_n "checking whether to run with monkey... " >&6; } # Check whether --enable-monkey was given. if test "${enable_monkey+set}" = set; then : enableval=$enable_monkey; enable_monkey=${enableval} else enable_monkey=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_monkey" >&5 $as_echo "$enable_monkey" >&6; } if test "x$enable_monkey" = "xyes"; then ENABLE_MONKEY_TRUE= ENABLE_MONKEY_FALSE='#' else ENABLE_MONKEY_TRUE='#' ENABLE_MONKEY_FALSE= fi if test "x$enable_monkey" = "xyes" then MONKEYPREFIX="monkey" else MONKEYPREFIX="" fi # should expensive tests be run? { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to run expensive tests" >&5 $as_echo_n "checking whether to run expensive tests... " >&6; } # Check whether --enable-expensivetests was given. if test "${enable_expensivetests+set}" = set; then : enableval=$enable_expensivetests; enable_expensive=${enableval} else enable_expensive=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_expensive" >&5 $as_echo "$enable_expensive" >&6; } if test "x$enable_expensive" = "xyes"; then HAVE_EXPENSIVE_TESTS_TRUE= HAVE_EXPENSIVE_TESTS_FALSE='#' else HAVE_EXPENSIVE_TESTS_TRUE='#' HAVE_EXPENSIVE_TESTS_FALSE= fi # should ports be open for Java services? { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable ports for gnunet-java" >&5 $as_echo_n "checking whether to enable ports for gnunet-java... " >&6; } # Check whether --enable-javaports was given. if test "${enable_javaports+set}" = set; then : enableval=$enable_javaports; enable_java_ports=${enableval} else enable_java_ports=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_java_ports" >&5 $as_echo "$enable_java_ports" >&6; } if test "x$enable_java_ports" = "xyes" then JAVAPORT="" else JAVAPORT="$UNIXONLY" fi # should benchmarks be run? { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to run benchmarks during make check" >&5 $as_echo_n "checking whether to run benchmarks during make check... " >&6; } # Check whether --enable-benchmarks was given. if test "${enable_benchmarks+set}" = set; then : enableval=$enable_benchmarks; enable_benchmarks=${enableval} else enable_benchmarks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_benchmarks" >&5 $as_echo "$enable_benchmarks" >&6; } if test "x$enable_benchmarks" = "xyes"; then HAVE_BENCHMARKS_TRUE= HAVE_BENCHMARKS_FALSE='#' else HAVE_BENCHMARKS_TRUE='#' HAVE_BENCHMARKS_FALSE= fi # should experimental code be compiled (code that may not yet compile)? { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile experimental code" >&5 $as_echo_n "checking whether to compile experimental code... " >&6; } # Check whether --enable-experimental was given. if test "${enable_experimental+set}" = set; then : enableval=$enable_experimental; enable_experimental=${enableval} else enable_experimental=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_experimental" >&5 $as_echo "$enable_experimental" >&6; } if test "x$enable_experimental" = "xyes"; then HAVE_EXPERIMENTAL_TRUE= HAVE_EXPERIMENTAL_FALSE='#' else HAVE_EXPERIMENTAL_TRUE='#' HAVE_EXPERIMENTAL_FALSE= fi # should code be enabled that works around missing OS functionality on Windows? # used for test cases if test $build_target = "mingw" then workarounds=1 cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { int s = socket (0, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : cat >>confdefs.h <<_ACEOF #define HAVE_SOCKET 1 _ACEOF else cat >>confdefs.h <<_ACEOF #define HAVE_SOCKET 0 _ACEOF fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { int s = select (0, NULL, NULL, NULL, NULL); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : cat >>confdefs.h <<_ACEOF #define HAVE_SELECT 1 _ACEOF else cat >>confdefs.h <<_ACEOF #define HAVE_SELECT 0 _ACEOF fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { struct in_addr i; char *s = inet_ntoa (i); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : cat >>confdefs.h <<_ACEOF #define HAVE_INET_NTOA 1 _ACEOF else cat >>confdefs.h <<_ACEOF #define HAVE_INET_NTOA 0 _ACEOF fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { int s = getnameinfo (NULL, 0, NULL, 0, NULL, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETNAMEINFO 1 _ACEOF else cat >>confdefs.h <<_ACEOF #define HAVE_GETNAMEINFO 0 _ACEOF fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { int s = gethostname (NULL, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETHOSTNAME 1 _ACEOF else cat >>confdefs.h <<_ACEOF #define HAVE_GETHOSTNAME 0 _ACEOF fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { void *s = gethostbyname (NULL); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETHOSTBYNAME 1 _ACEOF else cat >>confdefs.h <<_ACEOF #define HAVE_GETHOSTBYNAME 0 _ACEOF fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { void *s = gethostbyaddr (NULL, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETHOSTBYADDR 1 _ACEOF else cat >>confdefs.h <<_ACEOF #define HAVE_GETHOSTBYADDR 0 _ACEOF fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { int s = getaddrinfo (NULL, NULL, NULL, NULL); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETADDRINFO 1 _ACEOF else cat >>confdefs.h <<_ACEOF #define HAVE_GETADDRINFO 1 _ACEOF fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext else { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable windows workarounds" >&5 $as_echo_n "checking whether to enable windows workarounds... " >&6; } # Check whether --enable-windows_workarounds was given. if test "${enable_windows_workarounds+set}" = set; then : enableval=$enable_windows_workarounds; enable_workarounds=${enableval} else enable_workarounds=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_workarounds" >&5 $as_echo "$enable_workarounds" >&6; } if test x$enable_windows_workarounds = "xyes" then workarounds=1 else workarounds=0 fi fi cat >>confdefs.h <<_ACEOF #define ENABLE_WINDOWS_WORKAROUNDS $workarounds _ACEOF # gcov compilation { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with support for code coverage analysis" >&5 $as_echo_n "checking whether to compile with support for code coverage analysis... " >&6; } # Check whether --enable-coverage was given. if test "${enable_coverage+set}" = set; then : enableval=$enable_coverage; use_gcov=${enableval} else use_gcov=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $use_gcov" >&5 $as_echo "$use_gcov" >&6; } if test "x$use_gcov" = "xyes"; then USE_COVERAGE_TRUE= USE_COVERAGE_FALSE='#' else USE_COVERAGE_TRUE='#' USE_COVERAGE_FALSE= fi ac_config_files="$ac_config_files Makefile contrib/Makefile doc/Makefile doc/man/Makefile m4/Makefile po/Makefile.in src/Makefile src/arm/Makefile src/arm/arm.conf src/ats/Makefile src/ats/ats.conf src/block/Makefile src/chat/Makefile src/chat/chat.conf src/core/Makefile src/core/core.conf src/datacache/Makefile src/datastore/Makefile src/datastore/datastore.conf src/dht/Makefile src/dht/dht.conf src/dns/Makefile src/dns/dns.conf src/dv/Makefile src/dv/dv.conf src/exit/Makefile src/fragmentation/Makefile src/fs/Makefile src/fs/fs.conf src/gns/Makefile src/gns/gns.conf src/gns/nss/Makefile src/hello/Makefile src/include/Makefile src/include/gnunet_directories.h src/hostlist/Makefile src/lockmanager/Makefile src/lockmanager/lockmanager.conf src/mesh/Makefile src/mesh/mesh.conf src/mysql/Makefile src/namestore/Makefile src/namestore/namestore.conf src/nat/Makefile src/nse/Makefile src/nse/nse.conf src/peerinfo/Makefile src/peerinfo/peerinfo.conf src/peerinfo-tool/Makefile src/postgres/Makefile src/pt/Makefile src/regex/Makefile src/statistics/Makefile src/statistics/statistics.conf src/stream/Makefile src/template/Makefile src/testbed/Makefile src/testing/Makefile src/topology/Makefile src/transport/Makefile src/transport/transport.conf src/tun/Makefile src/util/Makefile src/util/resolver.conf src/vpn/Makefile src/vpn/vpn.conf src/integration-tests/Makefile pkgconfig/Makefile pkgconfig/gnunetarm.pc pkgconfig/gnunetblock.pc pkgconfig/gnunetcore.pc pkgconfig/gnunetdatacache.pc pkgconfig/gnunetdatastore.pc pkgconfig/gnunetdht.pc pkgconfig/gnunetdhtlog.pc pkgconfig/gnunetdv.pc pkgconfig/gnunetfragmentation.pc pkgconfig/gnunetfs.pc pkgconfig/gnunethello.pc pkgconfig/gnunetnat.pc pkgconfig/gnunetnse.pc pkgconfig/gnunetpeerinfo.pc pkgconfig/gnunetregex.pc pkgconfig/gnunetstatistics.pc pkgconfig/gnunettesting.pc pkgconfig/gnunettransport.pc pkgconfig/gnunetutil.pc" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then test "x$cache_file" != "x/dev/null" && { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} cat confcache >$cache_file else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepOBJC_TRUE}" && test -z "${am__fastdepOBJC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepOBJC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${INSTALL_LTDL_TRUE}" && test -z "${INSTALL_LTDL_FALSE}"; then as_fn_error $? "conditional \"INSTALL_LTDL\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${CONVENIENCE_LTDL_TRUE}" && test -z "${CONVENIENCE_LTDL_FALSE}"; then as_fn_error $? "conditional \"CONVENIENCE_LTDL\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi LT_CONFIG_H=gnunet_config.h _ltdl_libobjs= _ltdl_ltlibobjs= if test -n "$_LT_LIBOBJS"; then # Remove the extension. _lt_sed_drop_objext='s/\.o$//;s/\.obj$//' for i in `for i in $_LT_LIBOBJS; do echo "$i"; done | sed "$_lt_sed_drop_objext" | sort -u`; do _ltdl_libobjs="$_ltdl_libobjs $lt_libobj_prefix$i.$ac_objext" _ltdl_ltlibobjs="$_ltdl_ltlibobjs $lt_libobj_prefix$i.lo" done fi ltdl_LIBOBJS=$_ltdl_libobjs ltdl_LTLIBOBJS=$_ltdl_ltlibobjs if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${DARWIN_TRUE}" && test -z "${DARWIN_FALSE}"; then as_fn_error $? "conditional \"DARWIN\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${CYGWIN_TRUE}" && test -z "${CYGWIN_FALSE}"; then as_fn_error $? "conditional \"CYGWIN\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${MINGW_TRUE}" && test -z "${MINGW_FALSE}"; then as_fn_error $? "conditional \"MINGW\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${SOLARIS_TRUE}" && test -z "${SOLARIS_FALSE}"; then as_fn_error $? "conditional \"SOLARIS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${XFREEBSD_TRUE}" && test -z "${XFREEBSD_FALSE}"; then as_fn_error $? "conditional \"XFREEBSD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OPENBSD_TRUE}" && test -z "${OPENBSD_FALSE}"; then as_fn_error $? "conditional \"OPENBSD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${LINUX_TRUE}" && test -z "${LINUX_FALSE}"; then as_fn_error $? "conditional \"LINUX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepOBJC_TRUE}" && test -z "${am__fastdepOBJC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepOBJC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_LIBGLPK_TRUE}" && test -z "${HAVE_LIBGLPK_FALSE}"; then as_fn_error $? "conditional \"HAVE_LIBGLPK\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_LIBGLPK_TRUE}" && test -z "${HAVE_LIBGLPK_FALSE}"; then as_fn_error $? "conditional \"HAVE_LIBGLPK\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_GLIBCNSS_TRUE}" && test -z "${HAVE_GLIBCNSS_FALSE}"; then as_fn_error $? "conditional \"HAVE_GLIBCNSS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_GLIBCNSS_TRUE}" && test -z "${HAVE_GLIBCNSS_FALSE}"; then as_fn_error $? "conditional \"HAVE_GLIBCNSS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_SQLITE_TRUE}" && test -z "${HAVE_SQLITE_FALSE}"; then as_fn_error $? "conditional \"HAVE_SQLITE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_POSTGRES_TRUE}" && test -z "${HAVE_POSTGRES_FALSE}"; then as_fn_error $? "conditional \"HAVE_POSTGRES\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_ZLIB_TRUE}" && test -z "${HAVE_ZLIB_FALSE}"; then as_fn_error $? "conditional \"HAVE_ZLIB\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_MYSQL_TRUE}" && test -z "${HAVE_MYSQL_FALSE}"; then as_fn_error $? "conditional \"HAVE_MYSQL\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_MYSQLE_TRUE}" && test -z "${HAVE_MYSQLE_FALSE}"; then as_fn_error $? "conditional \"HAVE_MYSQLE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_MHD_TRUE}" && test -z "${HAVE_MHD_FALSE}"; then as_fn_error $? "conditional \"HAVE_MHD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_PYTHON_TRUE}" && test -z "${HAVE_PYTHON_FALSE}"; then as_fn_error $? "conditional \"HAVE_PYTHON\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_PYTHON_PEXPECT_TRUE}" && test -z "${HAVE_PYTHON_PEXPECT_FALSE}"; then as_fn_error $? "conditional \"HAVE_PYTHON_PEXPECT\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_PYTHON_PEXPECT_TRUE}" && test -z "${HAVE_PYTHON_PEXPECT_FALSE}"; then as_fn_error $? "conditional \"HAVE_PYTHON_PEXPECT\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WANT_FRAMEWORK_TRUE}" && test -z "${WANT_FRAMEWORK_FALSE}"; then as_fn_error $? "conditional \"WANT_FRAMEWORK\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_SUDO_TRUE}" && test -z "${HAVE_SUDO_FALSE}"; then as_fn_error $? "conditional \"HAVE_SUDO\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_TEST_RUN_TRUE}" && test -z "${ENABLE_TEST_RUN_FALSE}"; then as_fn_error $? "conditional \"ENABLE_TEST_RUN\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_MONKEY_TRUE}" && test -z "${ENABLE_MONKEY_FALSE}"; then as_fn_error $? "conditional \"ENABLE_MONKEY\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_EXPENSIVE_TESTS_TRUE}" && test -z "${HAVE_EXPENSIVE_TESTS_FALSE}"; then as_fn_error $? "conditional \"HAVE_EXPENSIVE_TESTS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_BENCHMARKS_TRUE}" && test -z "${HAVE_BENCHMARKS_FALSE}"; then as_fn_error $? "conditional \"HAVE_BENCHMARKS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_EXPERIMENTAL_TRUE}" && test -z "${HAVE_EXPERIMENTAL_FALSE}"; then as_fn_error $? "conditional \"HAVE_EXPERIMENTAL\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${USE_COVERAGE_TRUE}" && test -z "${USE_COVERAGE_FALSE}"; then as_fn_error $? "conditional \"USE_COVERAGE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : ${CONFIG_STATUS=./config.status} ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by gnunet $as_me 0.9.3, which was generated by GNU Autoconf 2.67. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ gnunet config.status 0.9.3 configured by $0, generated by GNU Autoconf 2.67, with options \\"\$ac_cs_config\\" Copyright (C) 2010 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' macro_version='`$ECHO "X$macro_version" | $Xsed -e "$delay_single_quote_subst"`' macro_revision='`$ECHO "X$macro_revision" | $Xsed -e "$delay_single_quote_subst"`' enable_static='`$ECHO "X$enable_static" | $Xsed -e "$delay_single_quote_subst"`' AS='`$ECHO "X$AS" | $Xsed -e "$delay_single_quote_subst"`' DLLTOOL='`$ECHO "X$DLLTOOL" | $Xsed -e "$delay_single_quote_subst"`' OBJDUMP='`$ECHO "X$OBJDUMP" | $Xsed -e "$delay_single_quote_subst"`' enable_shared='`$ECHO "X$enable_shared" | $Xsed -e "$delay_single_quote_subst"`' pic_mode='`$ECHO "X$pic_mode" | $Xsed -e "$delay_single_quote_subst"`' enable_fast_install='`$ECHO "X$enable_fast_install" | $Xsed -e "$delay_single_quote_subst"`' host_alias='`$ECHO "X$host_alias" | $Xsed -e "$delay_single_quote_subst"`' host='`$ECHO "X$host" | $Xsed -e "$delay_single_quote_subst"`' host_os='`$ECHO "X$host_os" | $Xsed -e "$delay_single_quote_subst"`' build_alias='`$ECHO "X$build_alias" | $Xsed -e "$delay_single_quote_subst"`' build='`$ECHO "X$build" | $Xsed -e "$delay_single_quote_subst"`' build_os='`$ECHO "X$build_os" | $Xsed -e "$delay_single_quote_subst"`' SED='`$ECHO "X$SED" | $Xsed -e "$delay_single_quote_subst"`' Xsed='`$ECHO "X$Xsed" | $Xsed -e "$delay_single_quote_subst"`' GREP='`$ECHO "X$GREP" | $Xsed -e "$delay_single_quote_subst"`' EGREP='`$ECHO "X$EGREP" | $Xsed -e "$delay_single_quote_subst"`' FGREP='`$ECHO "X$FGREP" | $Xsed -e "$delay_single_quote_subst"`' LD='`$ECHO "X$LD" | $Xsed -e "$delay_single_quote_subst"`' NM='`$ECHO "X$NM" | $Xsed -e "$delay_single_quote_subst"`' LN_S='`$ECHO "X$LN_S" | $Xsed -e "$delay_single_quote_subst"`' max_cmd_len='`$ECHO "X$max_cmd_len" | $Xsed -e "$delay_single_quote_subst"`' ac_objext='`$ECHO "X$ac_objext" | $Xsed -e "$delay_single_quote_subst"`' exeext='`$ECHO "X$exeext" | $Xsed -e "$delay_single_quote_subst"`' lt_unset='`$ECHO "X$lt_unset" | $Xsed -e "$delay_single_quote_subst"`' lt_SP2NL='`$ECHO "X$lt_SP2NL" | $Xsed -e "$delay_single_quote_subst"`' lt_NL2SP='`$ECHO "X$lt_NL2SP" | $Xsed -e "$delay_single_quote_subst"`' reload_flag='`$ECHO "X$reload_flag" | $Xsed -e "$delay_single_quote_subst"`' reload_cmds='`$ECHO "X$reload_cmds" | $Xsed -e "$delay_single_quote_subst"`' deplibs_check_method='`$ECHO "X$deplibs_check_method" | $Xsed -e "$delay_single_quote_subst"`' file_magic_cmd='`$ECHO "X$file_magic_cmd" | $Xsed -e "$delay_single_quote_subst"`' AR='`$ECHO "X$AR" | $Xsed -e "$delay_single_quote_subst"`' AR_FLAGS='`$ECHO "X$AR_FLAGS" | $Xsed -e "$delay_single_quote_subst"`' STRIP='`$ECHO "X$STRIP" | $Xsed -e "$delay_single_quote_subst"`' RANLIB='`$ECHO "X$RANLIB" | $Xsed -e "$delay_single_quote_subst"`' old_postinstall_cmds='`$ECHO "X$old_postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' old_postuninstall_cmds='`$ECHO "X$old_postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' old_archive_cmds='`$ECHO "X$old_archive_cmds" | $Xsed -e "$delay_single_quote_subst"`' CC='`$ECHO "X$CC" | $Xsed -e "$delay_single_quote_subst"`' CFLAGS='`$ECHO "X$CFLAGS" | $Xsed -e "$delay_single_quote_subst"`' compiler='`$ECHO "X$compiler" | $Xsed -e "$delay_single_quote_subst"`' GCC='`$ECHO "X$GCC" | $Xsed -e "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_pipe='`$ECHO "X$lt_cv_sys_global_symbol_pipe" | $Xsed -e "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_cdecl='`$ECHO "X$lt_cv_sys_global_symbol_to_cdecl" | $Xsed -e "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address" | $Xsed -e "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`' objdir='`$ECHO "X$objdir" | $Xsed -e "$delay_single_quote_subst"`' SHELL='`$ECHO "X$SHELL" | $Xsed -e "$delay_single_quote_subst"`' ECHO='`$ECHO "X$ECHO" | $Xsed -e "$delay_single_quote_subst"`' MAGIC_CMD='`$ECHO "X$MAGIC_CMD" | $Xsed -e "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag='`$ECHO "X$lt_prog_compiler_no_builtin_flag" | $Xsed -e "$delay_single_quote_subst"`' lt_prog_compiler_wl='`$ECHO "X$lt_prog_compiler_wl" | $Xsed -e "$delay_single_quote_subst"`' lt_prog_compiler_pic='`$ECHO "X$lt_prog_compiler_pic" | $Xsed -e "$delay_single_quote_subst"`' lt_prog_compiler_static='`$ECHO "X$lt_prog_compiler_static" | $Xsed -e "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o='`$ECHO "X$lt_cv_prog_compiler_c_o" | $Xsed -e "$delay_single_quote_subst"`' need_locks='`$ECHO "X$need_locks" | $Xsed -e "$delay_single_quote_subst"`' DSYMUTIL='`$ECHO "X$DSYMUTIL" | $Xsed -e "$delay_single_quote_subst"`' NMEDIT='`$ECHO "X$NMEDIT" | $Xsed -e "$delay_single_quote_subst"`' LIPO='`$ECHO "X$LIPO" | $Xsed -e "$delay_single_quote_subst"`' OTOOL='`$ECHO "X$OTOOL" | $Xsed -e "$delay_single_quote_subst"`' OTOOL64='`$ECHO "X$OTOOL64" | $Xsed -e "$delay_single_quote_subst"`' libext='`$ECHO "X$libext" | $Xsed -e "$delay_single_quote_subst"`' shrext_cmds='`$ECHO "X$shrext_cmds" | $Xsed -e "$delay_single_quote_subst"`' extract_expsyms_cmds='`$ECHO "X$extract_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`' archive_cmds_need_lc='`$ECHO "X$archive_cmds_need_lc" | $Xsed -e "$delay_single_quote_subst"`' enable_shared_with_static_runtimes='`$ECHO "X$enable_shared_with_static_runtimes" | $Xsed -e "$delay_single_quote_subst"`' export_dynamic_flag_spec='`$ECHO "X$export_dynamic_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' whole_archive_flag_spec='`$ECHO "X$whole_archive_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' compiler_needs_object='`$ECHO "X$compiler_needs_object" | $Xsed -e "$delay_single_quote_subst"`' old_archive_from_new_cmds='`$ECHO "X$old_archive_from_new_cmds" | $Xsed -e "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds='`$ECHO "X$old_archive_from_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`' archive_cmds='`$ECHO "X$archive_cmds" | $Xsed -e "$delay_single_quote_subst"`' archive_expsym_cmds='`$ECHO "X$archive_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`' module_cmds='`$ECHO "X$module_cmds" | $Xsed -e "$delay_single_quote_subst"`' module_expsym_cmds='`$ECHO "X$module_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`' with_gnu_ld='`$ECHO "X$with_gnu_ld" | $Xsed -e "$delay_single_quote_subst"`' allow_undefined_flag='`$ECHO "X$allow_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`' no_undefined_flag='`$ECHO "X$no_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`' hardcode_libdir_flag_spec='`$ECHO "X$hardcode_libdir_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' hardcode_libdir_flag_spec_ld='`$ECHO "X$hardcode_libdir_flag_spec_ld" | $Xsed -e "$delay_single_quote_subst"`' hardcode_libdir_separator='`$ECHO "X$hardcode_libdir_separator" | $Xsed -e "$delay_single_quote_subst"`' hardcode_direct='`$ECHO "X$hardcode_direct" | $Xsed -e "$delay_single_quote_subst"`' hardcode_direct_absolute='`$ECHO "X$hardcode_direct_absolute" | $Xsed -e "$delay_single_quote_subst"`' hardcode_minus_L='`$ECHO "X$hardcode_minus_L" | $Xsed -e "$delay_single_quote_subst"`' hardcode_shlibpath_var='`$ECHO "X$hardcode_shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`' hardcode_automatic='`$ECHO "X$hardcode_automatic" | $Xsed -e "$delay_single_quote_subst"`' inherit_rpath='`$ECHO "X$inherit_rpath" | $Xsed -e "$delay_single_quote_subst"`' link_all_deplibs='`$ECHO "X$link_all_deplibs" | $Xsed -e "$delay_single_quote_subst"`' fix_srcfile_path='`$ECHO "X$fix_srcfile_path" | $Xsed -e "$delay_single_quote_subst"`' always_export_symbols='`$ECHO "X$always_export_symbols" | $Xsed -e "$delay_single_quote_subst"`' export_symbols_cmds='`$ECHO "X$export_symbols_cmds" | $Xsed -e "$delay_single_quote_subst"`' exclude_expsyms='`$ECHO "X$exclude_expsyms" | $Xsed -e "$delay_single_quote_subst"`' include_expsyms='`$ECHO "X$include_expsyms" | $Xsed -e "$delay_single_quote_subst"`' prelink_cmds='`$ECHO "X$prelink_cmds" | $Xsed -e "$delay_single_quote_subst"`' file_list_spec='`$ECHO "X$file_list_spec" | $Xsed -e "$delay_single_quote_subst"`' variables_saved_for_relink='`$ECHO "X$variables_saved_for_relink" | $Xsed -e "$delay_single_quote_subst"`' need_lib_prefix='`$ECHO "X$need_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`' need_version='`$ECHO "X$need_version" | $Xsed -e "$delay_single_quote_subst"`' version_type='`$ECHO "X$version_type" | $Xsed -e "$delay_single_quote_subst"`' runpath_var='`$ECHO "X$runpath_var" | $Xsed -e "$delay_single_quote_subst"`' shlibpath_var='`$ECHO "X$shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`' shlibpath_overrides_runpath='`$ECHO "X$shlibpath_overrides_runpath" | $Xsed -e "$delay_single_quote_subst"`' libname_spec='`$ECHO "X$libname_spec" | $Xsed -e "$delay_single_quote_subst"`' library_names_spec='`$ECHO "X$library_names_spec" | $Xsed -e "$delay_single_quote_subst"`' soname_spec='`$ECHO "X$soname_spec" | $Xsed -e "$delay_single_quote_subst"`' postinstall_cmds='`$ECHO "X$postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' postuninstall_cmds='`$ECHO "X$postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' finish_cmds='`$ECHO "X$finish_cmds" | $Xsed -e "$delay_single_quote_subst"`' finish_eval='`$ECHO "X$finish_eval" | $Xsed -e "$delay_single_quote_subst"`' hardcode_into_libs='`$ECHO "X$hardcode_into_libs" | $Xsed -e "$delay_single_quote_subst"`' sys_lib_search_path_spec='`$ECHO "X$sys_lib_search_path_spec" | $Xsed -e "$delay_single_quote_subst"`' sys_lib_dlsearch_path_spec='`$ECHO "X$sys_lib_dlsearch_path_spec" | $Xsed -e "$delay_single_quote_subst"`' hardcode_action='`$ECHO "X$hardcode_action" | $Xsed -e "$delay_single_quote_subst"`' enable_dlopen='`$ECHO "X$enable_dlopen" | $Xsed -e "$delay_single_quote_subst"`' enable_dlopen_self='`$ECHO "X$enable_dlopen_self" | $Xsed -e "$delay_single_quote_subst"`' enable_dlopen_self_static='`$ECHO "X$enable_dlopen_self_static" | $Xsed -e "$delay_single_quote_subst"`' old_striplib='`$ECHO "X$old_striplib" | $Xsed -e "$delay_single_quote_subst"`' striplib='`$ECHO "X$striplib" | $Xsed -e "$delay_single_quote_subst"`' compiler_lib_search_dirs='`$ECHO "X$compiler_lib_search_dirs" | $Xsed -e "$delay_single_quote_subst"`' predep_objects='`$ECHO "X$predep_objects" | $Xsed -e "$delay_single_quote_subst"`' postdep_objects='`$ECHO "X$postdep_objects" | $Xsed -e "$delay_single_quote_subst"`' predeps='`$ECHO "X$predeps" | $Xsed -e "$delay_single_quote_subst"`' postdeps='`$ECHO "X$postdeps" | $Xsed -e "$delay_single_quote_subst"`' compiler_lib_search_path='`$ECHO "X$compiler_lib_search_path" | $Xsed -e "$delay_single_quote_subst"`' LD_CXX='`$ECHO "X$LD_CXX" | $Xsed -e "$delay_single_quote_subst"`' old_archive_cmds_CXX='`$ECHO "X$old_archive_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' compiler_CXX='`$ECHO "X$compiler_CXX" | $Xsed -e "$delay_single_quote_subst"`' GCC_CXX='`$ECHO "X$GCC_CXX" | $Xsed -e "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "X$lt_prog_compiler_no_builtin_flag_CXX" | $Xsed -e "$delay_single_quote_subst"`' lt_prog_compiler_wl_CXX='`$ECHO "X$lt_prog_compiler_wl_CXX" | $Xsed -e "$delay_single_quote_subst"`' lt_prog_compiler_pic_CXX='`$ECHO "X$lt_prog_compiler_pic_CXX" | $Xsed -e "$delay_single_quote_subst"`' lt_prog_compiler_static_CXX='`$ECHO "X$lt_prog_compiler_static_CXX" | $Xsed -e "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o_CXX='`$ECHO "X$lt_cv_prog_compiler_c_o_CXX" | $Xsed -e "$delay_single_quote_subst"`' archive_cmds_need_lc_CXX='`$ECHO "X$archive_cmds_need_lc_CXX" | $Xsed -e "$delay_single_quote_subst"`' enable_shared_with_static_runtimes_CXX='`$ECHO "X$enable_shared_with_static_runtimes_CXX" | $Xsed -e "$delay_single_quote_subst"`' export_dynamic_flag_spec_CXX='`$ECHO "X$export_dynamic_flag_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`' whole_archive_flag_spec_CXX='`$ECHO "X$whole_archive_flag_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`' compiler_needs_object_CXX='`$ECHO "X$compiler_needs_object_CXX" | $Xsed -e "$delay_single_quote_subst"`' old_archive_from_new_cmds_CXX='`$ECHO "X$old_archive_from_new_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds_CXX='`$ECHO "X$old_archive_from_expsyms_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' archive_cmds_CXX='`$ECHO "X$archive_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' archive_expsym_cmds_CXX='`$ECHO "X$archive_expsym_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' module_cmds_CXX='`$ECHO "X$module_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' module_expsym_cmds_CXX='`$ECHO "X$module_expsym_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' with_gnu_ld_CXX='`$ECHO "X$with_gnu_ld_CXX" | $Xsed -e "$delay_single_quote_subst"`' allow_undefined_flag_CXX='`$ECHO "X$allow_undefined_flag_CXX" | $Xsed -e "$delay_single_quote_subst"`' no_undefined_flag_CXX='`$ECHO "X$no_undefined_flag_CXX" | $Xsed -e "$delay_single_quote_subst"`' hardcode_libdir_flag_spec_CXX='`$ECHO "X$hardcode_libdir_flag_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`' hardcode_libdir_flag_spec_ld_CXX='`$ECHO "X$hardcode_libdir_flag_spec_ld_CXX" | $Xsed -e "$delay_single_quote_subst"`' hardcode_libdir_separator_CXX='`$ECHO "X$hardcode_libdir_separator_CXX" | $Xsed -e "$delay_single_quote_subst"`' hardcode_direct_CXX='`$ECHO "X$hardcode_direct_CXX" | $Xsed -e "$delay_single_quote_subst"`' hardcode_direct_absolute_CXX='`$ECHO "X$hardcode_direct_absolute_CXX" | $Xsed -e "$delay_single_quote_subst"`' hardcode_minus_L_CXX='`$ECHO "X$hardcode_minus_L_CXX" | $Xsed -e "$delay_single_quote_subst"`' hardcode_shlibpath_var_CXX='`$ECHO "X$hardcode_shlibpath_var_CXX" | $Xsed -e "$delay_single_quote_subst"`' hardcode_automatic_CXX='`$ECHO "X$hardcode_automatic_CXX" | $Xsed -e "$delay_single_quote_subst"`' inherit_rpath_CXX='`$ECHO "X$inherit_rpath_CXX" | $Xsed -e "$delay_single_quote_subst"`' link_all_deplibs_CXX='`$ECHO "X$link_all_deplibs_CXX" | $Xsed -e "$delay_single_quote_subst"`' fix_srcfile_path_CXX='`$ECHO "X$fix_srcfile_path_CXX" | $Xsed -e "$delay_single_quote_subst"`' always_export_symbols_CXX='`$ECHO "X$always_export_symbols_CXX" | $Xsed -e "$delay_single_quote_subst"`' export_symbols_cmds_CXX='`$ECHO "X$export_symbols_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' exclude_expsyms_CXX='`$ECHO "X$exclude_expsyms_CXX" | $Xsed -e "$delay_single_quote_subst"`' include_expsyms_CXX='`$ECHO "X$include_expsyms_CXX" | $Xsed -e "$delay_single_quote_subst"`' prelink_cmds_CXX='`$ECHO "X$prelink_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' file_list_spec_CXX='`$ECHO "X$file_list_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`' hardcode_action_CXX='`$ECHO "X$hardcode_action_CXX" | $Xsed -e "$delay_single_quote_subst"`' compiler_lib_search_dirs_CXX='`$ECHO "X$compiler_lib_search_dirs_CXX" | $Xsed -e "$delay_single_quote_subst"`' predep_objects_CXX='`$ECHO "X$predep_objects_CXX" | $Xsed -e "$delay_single_quote_subst"`' postdep_objects_CXX='`$ECHO "X$postdep_objects_CXX" | $Xsed -e "$delay_single_quote_subst"`' predeps_CXX='`$ECHO "X$predeps_CXX" | $Xsed -e "$delay_single_quote_subst"`' postdeps_CXX='`$ECHO "X$postdeps_CXX" | $Xsed -e "$delay_single_quote_subst"`' compiler_lib_search_path_CXX='`$ECHO "X$compiler_lib_search_path_CXX" | $Xsed -e "$delay_single_quote_subst"`' LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # Quote evaled strings. for var in SED \ GREP \ EGREP \ FGREP \ LD \ NM \ LN_S \ lt_SP2NL \ lt_NL2SP \ reload_flag \ deplibs_check_method \ file_magic_cmd \ AR \ AR_FLAGS \ STRIP \ RANLIB \ CC \ CFLAGS \ compiler \ lt_cv_sys_global_symbol_pipe \ lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ SHELL \ ECHO \ lt_prog_compiler_no_builtin_flag \ lt_prog_compiler_wl \ lt_prog_compiler_pic \ lt_prog_compiler_static \ lt_cv_prog_compiler_c_o \ need_locks \ DSYMUTIL \ NMEDIT \ LIPO \ OTOOL \ OTOOL64 \ shrext_cmds \ export_dynamic_flag_spec \ whole_archive_flag_spec \ compiler_needs_object \ with_gnu_ld \ allow_undefined_flag \ no_undefined_flag \ hardcode_libdir_flag_spec \ hardcode_libdir_flag_spec_ld \ hardcode_libdir_separator \ fix_srcfile_path \ exclude_expsyms \ include_expsyms \ file_list_spec \ variables_saved_for_relink \ libname_spec \ library_names_spec \ soname_spec \ finish_eval \ old_striplib \ striplib \ compiler_lib_search_dirs \ predep_objects \ postdep_objects \ predeps \ postdeps \ compiler_lib_search_path \ LD_CXX \ compiler_CXX \ lt_prog_compiler_no_builtin_flag_CXX \ lt_prog_compiler_wl_CXX \ lt_prog_compiler_pic_CXX \ lt_prog_compiler_static_CXX \ lt_cv_prog_compiler_c_o_CXX \ export_dynamic_flag_spec_CXX \ whole_archive_flag_spec_CXX \ compiler_needs_object_CXX \ with_gnu_ld_CXX \ allow_undefined_flag_CXX \ no_undefined_flag_CXX \ hardcode_libdir_flag_spec_CXX \ hardcode_libdir_flag_spec_ld_CXX \ hardcode_libdir_separator_CXX \ fix_srcfile_path_CXX \ exclude_expsyms_CXX \ include_expsyms_CXX \ file_list_spec_CXX \ compiler_lib_search_dirs_CXX \ predep_objects_CXX \ postdep_objects_CXX \ predeps_CXX \ postdeps_CXX \ compiler_lib_search_path_CXX; do case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in reload_cmds \ old_postinstall_cmds \ old_postuninstall_cmds \ old_archive_cmds \ extract_expsyms_cmds \ old_archive_from_new_cmds \ old_archive_from_expsyms_cmds \ archive_cmds \ archive_expsym_cmds \ module_cmds \ module_expsym_cmds \ export_symbols_cmds \ prelink_cmds \ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ sys_lib_dlsearch_path_spec \ old_archive_cmds_CXX \ old_archive_from_new_cmds_CXX \ old_archive_from_expsyms_cmds_CXX \ archive_cmds_CXX \ archive_expsym_cmds_CXX \ module_cmds_CXX \ module_expsym_cmds_CXX \ export_symbols_cmds_CXX \ prelink_cmds_CXX; do case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Fix-up fallback echo if it was mangled by the above quoting rules. case \$lt_ECHO in *'\\\$0 --fallback-echo"') lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\$0 --fallback-echo"\$/\$0 --fallback-echo"/'\` ;; esac ac_aux_dir='$ac_aux_dir' xsi_shell='$xsi_shell' lt_shell_append='$lt_shell_append' # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile' # Capture the value of obsolete ALL_LINGUAS because we need it to compute # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it # from automake < 1.5. eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"' # Capture the value of LINGUAS because we need it to compute CATALOGS. LINGUAS="${LINGUAS-%UNSET%}" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "gnunet_config.h") CONFIG_HEADERS="$CONFIG_HEADERS gnunet_config.h" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; "po-directories") CONFIG_COMMANDS="$CONFIG_COMMANDS po-directories" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "contrib/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/Makefile" ;; "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; "doc/man/Makefile") CONFIG_FILES="$CONFIG_FILES doc/man/Makefile" ;; "m4/Makefile") CONFIG_FILES="$CONFIG_FILES m4/Makefile" ;; "po/Makefile.in") CONFIG_FILES="$CONFIG_FILES po/Makefile.in" ;; "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; "src/arm/Makefile") CONFIG_FILES="$CONFIG_FILES src/arm/Makefile" ;; "src/arm/arm.conf") CONFIG_FILES="$CONFIG_FILES src/arm/arm.conf" ;; "src/ats/Makefile") CONFIG_FILES="$CONFIG_FILES src/ats/Makefile" ;; "src/ats/ats.conf") CONFIG_FILES="$CONFIG_FILES src/ats/ats.conf" ;; "src/block/Makefile") CONFIG_FILES="$CONFIG_FILES src/block/Makefile" ;; "src/chat/Makefile") CONFIG_FILES="$CONFIG_FILES src/chat/Makefile" ;; "src/chat/chat.conf") CONFIG_FILES="$CONFIG_FILES src/chat/chat.conf" ;; "src/core/Makefile") CONFIG_FILES="$CONFIG_FILES src/core/Makefile" ;; "src/core/core.conf") CONFIG_FILES="$CONFIG_FILES src/core/core.conf" ;; "src/datacache/Makefile") CONFIG_FILES="$CONFIG_FILES src/datacache/Makefile" ;; "src/datastore/Makefile") CONFIG_FILES="$CONFIG_FILES src/datastore/Makefile" ;; "src/datastore/datastore.conf") CONFIG_FILES="$CONFIG_FILES src/datastore/datastore.conf" ;; "src/dht/Makefile") CONFIG_FILES="$CONFIG_FILES src/dht/Makefile" ;; "src/dht/dht.conf") CONFIG_FILES="$CONFIG_FILES src/dht/dht.conf" ;; "src/dns/Makefile") CONFIG_FILES="$CONFIG_FILES src/dns/Makefile" ;; "src/dns/dns.conf") CONFIG_FILES="$CONFIG_FILES src/dns/dns.conf" ;; "src/dv/Makefile") CONFIG_FILES="$CONFIG_FILES src/dv/Makefile" ;; "src/dv/dv.conf") CONFIG_FILES="$CONFIG_FILES src/dv/dv.conf" ;; "src/exit/Makefile") CONFIG_FILES="$CONFIG_FILES src/exit/Makefile" ;; "src/fragmentation/Makefile") CONFIG_FILES="$CONFIG_FILES src/fragmentation/Makefile" ;; "src/fs/Makefile") CONFIG_FILES="$CONFIG_FILES src/fs/Makefile" ;; "src/fs/fs.conf") CONFIG_FILES="$CONFIG_FILES src/fs/fs.conf" ;; "src/gns/Makefile") CONFIG_FILES="$CONFIG_FILES src/gns/Makefile" ;; "src/gns/gns.conf") CONFIG_FILES="$CONFIG_FILES src/gns/gns.conf" ;; "src/gns/nss/Makefile") CONFIG_FILES="$CONFIG_FILES src/gns/nss/Makefile" ;; "src/hello/Makefile") CONFIG_FILES="$CONFIG_FILES src/hello/Makefile" ;; "src/include/Makefile") CONFIG_FILES="$CONFIG_FILES src/include/Makefile" ;; "src/include/gnunet_directories.h") CONFIG_FILES="$CONFIG_FILES src/include/gnunet_directories.h" ;; "src/hostlist/Makefile") CONFIG_FILES="$CONFIG_FILES src/hostlist/Makefile" ;; "src/lockmanager/Makefile") CONFIG_FILES="$CONFIG_FILES src/lockmanager/Makefile" ;; "src/lockmanager/lockmanager.conf") CONFIG_FILES="$CONFIG_FILES src/lockmanager/lockmanager.conf" ;; "src/mesh/Makefile") CONFIG_FILES="$CONFIG_FILES src/mesh/Makefile" ;; "src/mesh/mesh.conf") CONFIG_FILES="$CONFIG_FILES src/mesh/mesh.conf" ;; "src/mysql/Makefile") CONFIG_FILES="$CONFIG_FILES src/mysql/Makefile" ;; "src/namestore/Makefile") CONFIG_FILES="$CONFIG_FILES src/namestore/Makefile" ;; "src/namestore/namestore.conf") CONFIG_FILES="$CONFIG_FILES src/namestore/namestore.conf" ;; "src/nat/Makefile") CONFIG_FILES="$CONFIG_FILES src/nat/Makefile" ;; "src/nse/Makefile") CONFIG_FILES="$CONFIG_FILES src/nse/Makefile" ;; "src/nse/nse.conf") CONFIG_FILES="$CONFIG_FILES src/nse/nse.conf" ;; "src/peerinfo/Makefile") CONFIG_FILES="$CONFIG_FILES src/peerinfo/Makefile" ;; "src/peerinfo/peerinfo.conf") CONFIG_FILES="$CONFIG_FILES src/peerinfo/peerinfo.conf" ;; "src/peerinfo-tool/Makefile") CONFIG_FILES="$CONFIG_FILES src/peerinfo-tool/Makefile" ;; "src/postgres/Makefile") CONFIG_FILES="$CONFIG_FILES src/postgres/Makefile" ;; "src/pt/Makefile") CONFIG_FILES="$CONFIG_FILES src/pt/Makefile" ;; "src/regex/Makefile") CONFIG_FILES="$CONFIG_FILES src/regex/Makefile" ;; "src/statistics/Makefile") CONFIG_FILES="$CONFIG_FILES src/statistics/Makefile" ;; "src/statistics/statistics.conf") CONFIG_FILES="$CONFIG_FILES src/statistics/statistics.conf" ;; "src/stream/Makefile") CONFIG_FILES="$CONFIG_FILES src/stream/Makefile" ;; "src/template/Makefile") CONFIG_FILES="$CONFIG_FILES src/template/Makefile" ;; "src/testbed/Makefile") CONFIG_FILES="$CONFIG_FILES src/testbed/Makefile" ;; "src/testing/Makefile") CONFIG_FILES="$CONFIG_FILES src/testing/Makefile" ;; "src/topology/Makefile") CONFIG_FILES="$CONFIG_FILES src/topology/Makefile" ;; "src/transport/Makefile") CONFIG_FILES="$CONFIG_FILES src/transport/Makefile" ;; "src/transport/transport.conf") CONFIG_FILES="$CONFIG_FILES src/transport/transport.conf" ;; "src/tun/Makefile") CONFIG_FILES="$CONFIG_FILES src/tun/Makefile" ;; "src/util/Makefile") CONFIG_FILES="$CONFIG_FILES src/util/Makefile" ;; "src/util/resolver.conf") CONFIG_FILES="$CONFIG_FILES src/util/resolver.conf" ;; "src/vpn/Makefile") CONFIG_FILES="$CONFIG_FILES src/vpn/Makefile" ;; "src/vpn/vpn.conf") CONFIG_FILES="$CONFIG_FILES src/vpn/vpn.conf" ;; "src/integration-tests/Makefile") CONFIG_FILES="$CONFIG_FILES src/integration-tests/Makefile" ;; "pkgconfig/Makefile") CONFIG_FILES="$CONFIG_FILES pkgconfig/Makefile" ;; "pkgconfig/gnunetarm.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetarm.pc" ;; "pkgconfig/gnunetblock.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetblock.pc" ;; "pkgconfig/gnunetcore.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetcore.pc" ;; "pkgconfig/gnunetdatacache.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetdatacache.pc" ;; "pkgconfig/gnunetdatastore.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetdatastore.pc" ;; "pkgconfig/gnunetdht.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetdht.pc" ;; "pkgconfig/gnunetdhtlog.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetdhtlog.pc" ;; "pkgconfig/gnunetdv.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetdv.pc" ;; "pkgconfig/gnunetfragmentation.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetfragmentation.pc" ;; "pkgconfig/gnunetfs.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetfs.pc" ;; "pkgconfig/gnunethello.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunethello.pc" ;; "pkgconfig/gnunetnat.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetnat.pc" ;; "pkgconfig/gnunetnse.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetnse.pc" ;; "pkgconfig/gnunetpeerinfo.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetpeerinfo.pc" ;; "pkgconfig/gnunetregex.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetregex.pc" ;; "pkgconfig/gnunetstatistics.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetstatistics.pc" ;; "pkgconfig/gnunettesting.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunettesting.pc" ;; "pkgconfig/gnunettransport.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunettransport.pc" ;; "pkgconfig/gnunetutil.pc") CONFIG_FILES="$CONFIG_FILES pkgconfig/gnunetutil.pc" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= trap 'exit_status=$? { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_t=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_t"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$tmp/stdin" case $ac_file in -) cat "$tmp/out" && rm -f "$tmp/out";; *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" } >"$tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Autoconf 2.62 quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ;; "libtool":C) # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008 Free Software Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # The names of the tagged configurations supported by this script. available_tags="CXX " # ### BEGIN LIBTOOL CONFIG # Which release of libtool.m4 was used? macro_version=$macro_version macro_revision=$macro_revision # Whether or not to build static libraries. build_old_libs=$enable_static # Assembler program. AS=$AS # DLL creation program. DLLTOOL=$DLLTOOL # Object dumper program. OBJDUMP=$OBJDUMP # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # What type of objects to build. pic_mode=$pic_mode # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="\$SED -e 1s/^X//" # A grep program that handles long lines. GREP=$lt_GREP # An ERE matcher. EGREP=$lt_EGREP # A literal string matcher. FGREP=$lt_FGREP # A BSD- or MS-compatible name lister. NM=$lt_NM # Whether we need soft or hard links. LN_S=$lt_LN_S # What is the maximum length of a command? max_cmd_len=$max_cmd_len # Object file suffix (normally "o"). objext=$ac_objext # Executable file suffix (normally ""). exeext=$exeext # whether the shell understands "unset". lt_unset=$lt_unset # turn spaces into newlines. SP2NL=$lt_lt_SP2NL # turn newlines into spaces. NL2SP=$lt_lt_NL2SP # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method == "file_magic". file_magic_cmd=$lt_file_magic_cmd # The archiver. AR=$lt_AR AR_FLAGS=$lt_AR_FLAGS # A symbol stripping program. STRIP=$lt_STRIP # Commands used to install an old-style archive. RANLIB=$lt_RANLIB old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # A C compiler. LTCC=$lt_CC # LTCC compiler flags. LTCFLAGS=$lt_CFLAGS # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration. global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair. global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix # The name of the directory that contains temporary libtool files. objdir=$objdir # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # An echo program that does not interpret backslashes. ECHO=$lt_ECHO # Used to examine libraries when file_magic_cmd begins with "file". MAGIC_CMD=$MAGIC_CMD # Must we lock files when doing compilation? need_locks=$lt_need_locks # Tool to manipulate archived DWARF debug symbol files on Mac OS X. DSYMUTIL=$lt_DSYMUTIL # Tool to change global to local symbols on Mac OS X. NMEDIT=$lt_NMEDIT # Tool to manipulate fat objects and archives on Mac OS X. LIPO=$lt_LIPO # ldd/readelf like tool for Mach-O binaries on Mac OS X. OTOOL=$lt_OTOOL # ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. OTOOL64=$lt_OTOOL64 # Old archive suffix (normally "a"). libext=$libext # Shared library suffix (normally ".so"). shrext_cmds=$lt_shrext_cmds # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Variables whose values should be saved in libtool wrapper scripts and # restored at link time. variables_saved_for_relink=$lt_variables_saved_for_relink # Do we need the "lib" prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Library versioning type. version_type=$version_type # Shared library runtime path variable. runpath_var=$runpath_var # Shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Command to use after installation of a shared archive. postinstall_cmds=$lt_postinstall_cmds # Command to use after uninstallation of a shared archive. postuninstall_cmds=$lt_postuninstall_cmds # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # As "finish_cmds", except a single script fragment to be evaled but # not shown. finish_eval=$lt_finish_eval # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Compile-time system search path for libraries. sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # The linker used to build libraries. LD=$lt_LD # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds # A language specific compiler. CC=$lt_compiler # Is the compiler the GNU compiler? with_gcc=$GCC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds archive_expsym_cmds=$lt_archive_expsym_cmds # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds module_expsym_cmds=$lt_module_expsym_cmds # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # If ld is used when linking, flag to hardcode \$libdir into a binary # during linking. This must work even if \$libdir does not exist. hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \${shlibpath_var} if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path=$lt_fix_srcfile_path # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms # Symbols that must always be exported. include_expsyms=$lt_include_expsyms # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds # Specify filename containing input files. file_list_spec=$lt_file_list_spec # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # The directories searched by this compiler when creating a shared library. compiler_lib_search_dirs=$lt_compiler_lib_search_dirs # Dependencies to place before and after the objects being linked to # create a shared library. predep_objects=$lt_predep_objects postdep_objects=$lt_postdep_objects predeps=$lt_predeps postdeps=$lt_postdeps # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_compiler_lib_search_path # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac ltmain="$ac_aux_dir/ltmain.sh" # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) case $xsi_shell in yes) cat << \_LT_EOF >> "$cfgfile" # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac } # func_basename file func_basename () { func_basename_result="${1##*/}" } # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac func_basename_result="${1##*/}" } # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). func_stripname () { # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary parameter first. func_stripname_result=${3} func_stripname_result=${func_stripname_result#"${1}"} func_stripname_result=${func_stripname_result%"${2}"} } # func_opt_split func_opt_split () { func_opt_split_opt=${1%%=*} func_opt_split_arg=${1#*=} } # func_lo2o object func_lo2o () { case ${1} in *.lo) func_lo2o_result=${1%.lo}.${objext} ;; *) func_lo2o_result=${1} ;; esac } # func_xform libobj-or-source func_xform () { func_xform_result=${1%.*}.lo } # func_arith arithmetic-term... func_arith () { func_arith_result=$(( $* )) } # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=${#1} } _LT_EOF ;; *) # Bourne compatible functions. cat << \_LT_EOF >> "$cfgfile" # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi } # func_basename file func_basename () { func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` } # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # func_strip_suffix prefix name func_stripname () { case ${2} in .*) func_stripname_result=`$ECHO "X${3}" \ | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "X${3}" \ | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; esac } # sed scripts: my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q' my_sed_long_arg='1s/^-[^=]*=//' # func_opt_split func_opt_split () { func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` } # func_lo2o object func_lo2o () { func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` } # func_xform libobj-or-source func_xform () { func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[^.]*$/.lo/'` } # func_arith arithmetic-term... func_arith () { func_arith_result=`expr "$@"` } # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` } _LT_EOF esac case $lt_shell_append in yes) cat << \_LT_EOF >> "$cfgfile" # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "$1+=\$2" } _LT_EOF ;; *) cat << \_LT_EOF >> "$cfgfile" # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "$1=\$$1\$2" } _LT_EOF ;; esac sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" cat <<_LT_EOF >> "$ofile" # ### BEGIN LIBTOOL TAG CONFIG: CXX # The linker used to build libraries. LD=$lt_LD_CXX # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds_CXX # A language specific compiler. CC=$lt_compiler_CXX # Is the compiler the GNU compiler? with_gcc=$GCC_CXX # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl_CXX # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic_CXX # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static_CXX # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc_CXX # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object_CXX # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds_CXX archive_expsym_cmds=$lt_archive_expsym_cmds_CXX # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds_CXX module_expsym_cmds=$lt_module_expsym_cmds_CXX # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld_CXX # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag_CXX # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag_CXX # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX # If ld is used when linking, flag to hardcode \$libdir into a binary # during linking. This must work even if \$libdir does not exist. hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct_CXX # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \${shlibpath_var} if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute_CXX # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L_CXX # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic_CXX # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath_CXX # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs_CXX # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path=$lt_fix_srcfile_path_CXX # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols_CXX # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds_CXX # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms_CXX # Symbols that must always be exported. include_expsyms=$lt_include_expsyms_CXX # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds_CXX # Specify filename containing input files. file_list_spec=$lt_file_list_spec_CXX # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action_CXX # The directories searched by this compiler when creating a shared library. compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX # Dependencies to place before and after the objects being linked to # create a shared library. predep_objects=$lt_predep_objects_CXX postdep_objects=$lt_postdep_objects_CXX predeps=$lt_predeps_CXX postdeps=$lt_postdeps_CXX # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_compiler_lib_search_path_CXX # ### END LIBTOOL TAG CONFIG: CXX _LT_EOF ;; "po-directories":C) for ac_file in $CONFIG_FILES; do # Support "outfile[:infile[:infile...]]" case "$ac_file" in *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; esac # PO directories have a Makefile.in generated from Makefile.in.in. case "$ac_file" in */Makefile.in) # Adjust a relative srcdir. ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` # In autoconf-2.13 it is called $ac_given_srcdir. # In autoconf-2.50 it is called $srcdir. test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" case "$ac_given_srcdir" in .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; /*) top_srcdir="$ac_given_srcdir" ;; *) top_srcdir="$ac_dots$ac_given_srcdir" ;; esac # Treat a directory as a PO directory if and only if it has a # POTFILES.in file. This allows packages to have multiple PO # directories under different names or in different locations. if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then rm -f "$ac_dir/POTFILES" test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" POMAKEFILEDEPS="POTFILES.in" # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend # on $ac_dir but don't depend on user-specified configuration # parameters. if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then # The LINGUAS file contains the set of available languages. if test -n "$OBSOLETE_ALL_LINGUAS"; then test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" fi ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` # Hide the ALL_LINGUAS assigment from automake < 1.5. eval 'ALL_LINGUAS''=$ALL_LINGUAS_' POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" else # The set of available languages was given in configure.in. # Hide the ALL_LINGUAS assigment from automake < 1.5. eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS' fi # Compute POFILES # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) # Compute UPDATEPOFILES # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) # Compute DUMMYPOFILES # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) # Compute GMOFILES # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) case "$ac_given_srcdir" in .) srcdirpre= ;; *) srcdirpre='$(srcdir)/' ;; esac POFILES= UPDATEPOFILES= DUMMYPOFILES= GMOFILES= for lang in $ALL_LINGUAS; do POFILES="$POFILES $srcdirpre$lang.po" UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" DUMMYPOFILES="$DUMMYPOFILES $lang.nop" GMOFILES="$GMOFILES $srcdirpre$lang.gmo" done # CATALOGS depends on both $ac_dir and the user's LINGUAS # environment variable. INST_LINGUAS= if test -n "$ALL_LINGUAS"; then for presentlang in $ALL_LINGUAS; do useit=no if test "%UNSET%" != "$LINGUAS"; then desiredlanguages="$LINGUAS" else desiredlanguages="$ALL_LINGUAS" fi for desiredlang in $desiredlanguages; do # Use the presentlang catalog if desiredlang is # a. equal to presentlang, or # b. a variant of presentlang (because in this case, # presentlang can be used as a fallback for messages # which are not translated in the desiredlang catalog). case "$desiredlang" in "$presentlang"*) useit=yes;; esac done if test $useit = yes; then INST_LINGUAS="$INST_LINGUAS $presentlang" fi done fi CATALOGS= if test -n "$INST_LINGUAS"; then for lang in $INST_LINGUAS; do CATALOGS="$CATALOGS $lang.gmo" done fi test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do if test -f "$f"; then case "$f" in *.orig | *.bak | *~) ;; *) cat "$f" >> "$ac_dir/Makefile" ;; esac fi done fi ;; esac done ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi # # CONFIG_SUBDIRS section. # if test "$no_recursion" != yes; then # Remove --cache-file, --srcdir, and --disable-option-checking arguments # so they do not pile up. ac_sub_configure_args= ac_prev= eval "set x $ac_configure_args" shift for ac_arg do if test -n "$ac_prev"; then ac_prev= continue fi case $ac_arg in -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \ | --c=*) ;; --config-cache | -C) ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) ;; --disable-option-checking) ;; *) case $ac_arg in *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_sub_configure_args " '$ac_arg'" ;; esac done # Always prepend --prefix to ensure using the same prefix # in subdir configurations. ac_arg="--prefix=$prefix" case $ac_arg in *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args" # Pass --silent if test "$silent" = yes; then ac_sub_configure_args="--silent $ac_sub_configure_args" fi # Always prepend --disable-option-checking to silence warnings, since # different subdirs can have different --enable and --with options. ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args" ac_popdir=`pwd` for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue # Do not complain, so a configure script can configure whichever # parts of a large source tree are present. test -d "$srcdir/$ac_dir" || continue ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)" $as_echo "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5 $as_echo "$ac_msg" >&6 as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" # Check for guested configure; otherwise get Cygnus style configure. if test -f "$ac_srcdir/configure.gnu"; then ac_sub_configure=$ac_srcdir/configure.gnu elif test -f "$ac_srcdir/configure"; then ac_sub_configure=$ac_srcdir/configure elif test -f "$ac_srcdir/configure.in"; then # This should be Cygnus configure. ac_sub_configure=$ac_aux_dir/configure else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5 $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2;} ac_sub_configure= fi # The recursion is here. if test -n "$ac_sub_configure"; then # Make the cache file name correct relative to the subdirectory. case $cache_file in [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;; *) # Relative name. ac_sub_cache_file=$ac_top_build_prefix$cache_file ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5 $as_echo "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;} # The eval makes quoting arguments work. eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \ --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" || as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5 fi cd "$ac_popdir" done fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi # Finally: summary! # warn user if mysql found but not used due to version if test "$mysqlfail" = "true" then { $as_echo "$as_me:${as_lineno-$LINENO}: NOTICE: MySQL found, but too old. MySQL support will not be compiled." >&5 $as_echo "$as_me: NOTICE: MySQL found, but too old. MySQL support will not be compiled." >&6;} fi # sqlite if test "x$sqlite" = "x0" then { $as_echo "$as_me:${as_lineno-$LINENO}: NOTICE: sqlite not found. sqLite support will not be compiled." >&5 $as_echo "$as_me: NOTICE: sqlite not found. sqLite support will not be compiled." >&6;} fi # java ports if test "x$enable_java_ports" = "xyes" then { $as_echo "$as_me:${as_lineno-$LINENO}: NOTICE: opening ports for gnunet-java bindings by default." >&5 $as_echo "$as_me: NOTICE: opening ports for gnunet-java bindings by default." >&6;} fi if test "x$lmhd" != "x1" then { $as_echo "$as_me:${as_lineno-$LINENO}: NOTICE: libmicrohttpd not found, http transport will not be installed." >&5 $as_echo "$as_me: NOTICE: libmicrohttpd not found, http transport will not be installed." >&6;} fi { $as_echo "$as_me:${as_lineno-$LINENO}: NOTICE: Database support is set to MySQL: $mysql, SQLite: $sqlite, Postgres: $postgres" >&5 $as_echo "$as_me: NOTICE: Database support is set to MySQL: $mysql, SQLite: $sqlite, Postgres: $postgres" >&6;} if test "$enable_framework_build" = "yes" then { $as_echo "$as_me:${as_lineno-$LINENO}: NOTICE: Mac OS X framework build enabled." >&5 $as_echo "$as_me: NOTICE: Mac OS X framework build enabled." >&6;} fi if test "x$SUDO_BINARY" = "x" -a ! -w / then { $as_echo "$as_me:${as_lineno-$LINENO}: NOTICE: --with-sudo not specified and not running as 'root', will not install GNS NSS library" >&5 $as_echo "$as_me: NOTICE: --with-sudo not specified and not running as 'root', will not install GNS NSS library" >&6;} fi { $as_echo "$as_me:${as_lineno-$LINENO}: ******************************************** You can compile GNUnet with make now. After that, run (if necessary as 'root') make install to install everything. You may want to create a new user account to run the GNUnet service: adduser gnunet You also need to create an configuration file that should specify the path where GNUnet should store data. For example, you could store in \"/etc/gnunet.conf\" the following lines: [PATHS] SERVICEHOME = /var/lib/gnunet DEFAULTCONFIG = /etc/gnunet.conf Now, in order to start your peer, run as the 'gnunet' user gnunet-arm -s Each GNUnet user should also create an (at least initially) empty configuration file: mkdir $HOME/.gnunet/ touch $HOME/.gnunet/gnunet.conf Optionally, download and compile: - gnunet-gtk to get a GUI for file-sharing and configuration. ********************************************" >&5 $as_echo "$as_me: ******************************************** You can compile GNUnet with make now. After that, run (if necessary as 'root') make install to install everything. You may want to create a new user account to run the GNUnet service: adduser gnunet You also need to create an configuration file that should specify the path where GNUnet should store data. For example, you could store in \"/etc/gnunet.conf\" the following lines: [PATHS] SERVICEHOME = /var/lib/gnunet DEFAULTCONFIG = /etc/gnunet.conf Now, in order to start your peer, run as the 'gnunet' user gnunet-arm -s Each GNUnet user should also create an (at least initially) empty configuration file: mkdir $HOME/.gnunet/ touch $HOME/.gnunet/gnunet.conf Optionally, download and compile: - gnunet-gtk to get a GUI for file-sharing and configuration. ********************************************" >&6;} gnunet-0.9.3/configure.ac0000644000175000017500000010240411762217174012243 00000000000000# This file is part of GNUnet. # (C) 2001--2012 Christian Grothoff (and other contributing authors) # # GNUnet is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2, or (at your # option) any later version. # # GNUnet is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNUnet; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # # Process this file with autoconf to produce a configure script. # # AC_PREREQ(2.61) # Checks for programs. AC_INIT([gnunet], [0.9.3],[bug-gnunet@gnu.org]) AC_CANONICAL_TARGET AC_CANONICAL_HOST AC_CANONICAL_SYSTEM AM_INIT_AUTOMAKE([gnunet], [0.9.3]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AC_CONFIG_HEADERS([gnunet_config.h]) AH_TOP([#define _GNU_SOURCE 1]) AC_PROG_AWK AC_PROG_CC AC_PROG_CPP AC_PROG_CXX AC_PROG_OBJC AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET AM_PROG_CC_C_O LT_INIT([disable-static dlopen win32-dll]) LTDL_INIT AC_SUBST(LTDLINCL) AC_SUBST(LIBLTDL) AC_SUBST(MKDIR_P) # large file support AC_SYS_LARGEFILE AC_FUNC_FSEEKO if test "$enable_shared" = "no" then AC_MSG_ERROR([GNUnet only works with shared libraries. Sorry.]) fi CFLAGS="-Wall $CFLAGS" # use '-fno-strict-aliasing', but only if the compiler can take it if gcc -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then CFLAGS="-fno-strict-aliasing $CFLAGS" fi # Use Linux interface name unless the OS has a different preference DEFAULT_INTERFACE="\"eth0\"" funcstocheck="socket select inet_ntoa getnameinfo gethostname gethostbyname gethostbyaddr getaddrinfo" # Check system type case "$host_os" in *darwin* | *rhapsody* | *macosx*) AC_DEFINE_UNQUOTED(DARWIN,1,[This is an Apple Darwin system]) CPPFLAGS="-D_APPLE_C_SOURCE $CPPFLAGS" CFLAGS="-no-cpp-precomp -fno-common $CFLAGS" AC_MSG_WARN([The VPN application cannot be compiled on your OS]) build_target="darwin" DEFAULT_INTERFACE="\"en0\"" LIBPREFIX= DLLDIR=lib UNIXONLY="#" ;; linux*) AC_DEFINE_UNQUOTED(LINUX,1,[This is a Linux system]) build_target="linux" LIBPREFIX= DLLDIR=lib UNIXONLY="#" AC_PATH_XTRA ;; freebsd*) AC_DEFINE_UNQUOTED(SOMEBSD,1,[This is a BSD system]) AC_DEFINE_UNQUOTED(FREEBSD,1,[This is a FreeBSD system]) CFLAGS="-D_THREAD_SAFE $CFLAGS" build_target="freebsd" LIBPREFIX= DLLDIR=lib UNIXONLY="#" ;; openbsd*) AC_DEFINE_UNQUOTED(SOMEBSD,1,[This is a BSD system]) AC_DEFINE_UNQUOTED(OPENBSD,1,[This is an OpenBSD system]) LIBS=`echo $LIBS | sed -e "s/-ldl//"` build_target="openbsd" LIBPREFIX= DLLDIR=lib UNIXONLY="#" ;; netbsd*) AC_DEFINE_UNQUOTED(SOMEBSD,1,[This is a BSD system]) AC_DEFINE_UNQUOTED(NETBSD,1,[This is a NetBSD system]) LIBPREFIX= DLLDIR=lib UNIXONLY="#" ;; *solaris*) AC_DEFINE_UNQUOTED(SOLARIS,1,[This is a Solaris system]) AC_DEFINE_UNQUOTED(_REENTRANT,1,[Need with solaris or errno doesnt work]) AC_CHECK_LIB(resolv, res_init) AC_CHECK_LIB(rt, nanosleep) build_target="solaris" LIBPREFIX= DLLDIR=lib UNIXONLY="#" ;; *arm-linux*) AC_DEFINE_UNQUOTED(LINUX,1,[This is a Linux system]) CFLAGS="-D_REENTRANT -fPIC -pipe $CFLAGS" build_target="linux" LIBPREFIX= DLLDIR=lib UNIXONLY="#" ;; *cygwin*) AC_DEFINE_UNQUOTED(CYGWIN,1,[This is a Cygwin system]) AC_DEFINE_UNQUOTED(WINDOWS,1,[This is a Windows system]) AC_CHECK_LIB(intl, gettext) LDFLAGS="$LDFLAGS -no-undefined" CFLAGS="-mms-bitfields $CFLAGS" build_target="cygwin" LIBPREFIX=lib DLLDIR=bin AC_PROG_CXX UNIXONLY="" ;; *mingw*) AC_DEFINE_UNQUOTED(MINGW,1,[This is a MinGW system]) AC_DEFINE_UNQUOTED(WINDOWS,1,[This is a Windows system]) AC_DEFINE_UNQUOTED(_WIN32,1,[This is a Windows system]) AC_CHECK_LIB(intl, gettext) LDFLAGS="$LDFLAGS -Wl,-no-undefined -Wl,--export-all-symbols" LIBS="$LIBS -lws2_32 -lplibc -lgnurx -lole32" CFLAGS="-mms-bitfields $CFLAGS" CPPFLAGS="-D_WIN32_WINNT=0x0501 -DHAVE_STAT64=1 $CPPFLAGS" build_target="mingw" AC_PROG_CXX LIBPREFIX=lib DLLDIR=bin UNIXONLY="" funcstocheck="" ;; *) AC_MSG_RESULT(Unrecognised OS $host_os) AC_DEFINE_UNQUOTED(OTHEROS,1,[Some strange OS]) UNIXONLY="" ;; esac AC_DEFINE_UNQUOTED([GNUNET_DEFAULT_INTERFACE], $DEFAULT_INTERFACE, [This should be the default choice for the name of the first network interface]) AC_SUBST(DEFAULT_INTERFACE) # Disable TCP-based IPC on systems that support UNIX domain # sockets in default configuratin: AC_SUBST(UNIXONLY) AC_MSG_CHECKING([for build target]) AM_CONDITIONAL(DARWIN, test "$build_target" = "darwin") AM_CONDITIONAL(CYGWIN, test "$build_target" = "cygwin") AM_CONDITIONAL(MINGW, test "$build_target" = "mingw") AM_CONDITIONAL(SOLARIS, test "$build_target" = "solaris") AM_CONDITIONAL(XFREEBSD, test "$build_target" = "freebsd") AM_CONDITIONAL(OPENBSD, test "$build_target" = "openbsd") AM_CONDITIONAL(LINUX, test "$build_target" = "linux") AC_MSG_RESULT([$build_target]) AC_SUBST(build_target) AM_CONDITIONAL([am__fastdepOBJC], false) AC_UNALIGNED_64_ACCESS # some other checks for standard libs AC_SEARCH_LIBS([gethostbyname], [nsl ws2_32]) AC_CHECK_LIB(socket, socket) AC_CHECK_LIB(m, log) AC_CHECK_LIB(c, getloadavg, AC_DEFINE(HAVE_GETLOADAVG,1,[getloadavg supported])) # 'save' libs; only those libs found so far will be # linked against _everywhere_. For the others, we # will be more selective! SAVE_LIBS=$LIBS # libgnurx (regex library for W32) gnurx=0 AC_CHECK_LIB(gnurx, regexec, gnurx=1) if test "x$gnurx" = "x0" -a "x$build_target" = "xmingw" then AC_MSG_ERROR([on W32 GNUnet needs libgnurx]) fi # libgcrypt gcrypt=0 AM_PATH_LIBGCRYPT(1.2.0, gcrypt=1) AC_CHECK_DECLS([gcry_mpi_lshift], [], [], [[#include ]]) if test $gcrypt = 0 then AC_MSG_ERROR([GNUnet needs libgcrypt]) fi # Adam shostack suggests the following for Windows: # -D_FORTIFY_SOURCE=2 -fstack-protector-all AC_ARG_ENABLE(gcc-hardening, AS_HELP_STRING(--enable-gcc-hardening, enable compiler security checks), [if test x$enableval = xyes; then CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2 -fstack-protector-all" CFLAGS="$CFLAGS -fwrapv -fPIE -Wstack-protector" CFLAGS="$CFLAGS --param ssp-buffer-size=1" LDFLAGS="$LDFLAGS -pie" fi]) # Linker hardening options # Currently these options are ELF specific - you can't use this with MacOSX AC_ARG_ENABLE(linker-hardening, AS_HELP_STRING(--enable-linker-hardening, enable linker security fixups), [if test x$enableval = xyes; then LDFLAGS="$LDFLAGS -z relro -z now" fi]) extra_logging=GNUNET_NO AC_ARG_ENABLE([logging], AS_HELP_STRING([--enable-logging@<:@=value@:>@],[Enable logging calls. Possible values: yes,no,verbose,veryverbose ('yes' is the default)]), [AS_IF([test "x$enableval" = "xyes"], [], [test "x$enableval" = "xno"], [AC_DEFINE([GNUNET_CULL_LOGGING],[],[Define to cull all logging calls])], [test "x$enableval" = "xverbose"], [extra_logging=GNUNET_YES] [test "x$enableval" = "xveryverbose"], [extra_logging=\(GNUNET_YES+1\)]) ], []) AC_DEFINE_UNQUOTED([GNUNET_EXTRA_LOGGING],[$extra_logging],[1 if extra logging is enabled, 2 for very verbose extra logging, 0 otherwise]) if test $build = $target then AC_MSG_CHECKING([for working HMAC]) AC_LANG_PUSH(C) LIBS="$LIBS $LIBGCRYPT_LIBS" CFLAGS="$CFLAGS $LIBGCRYPT_CFLAGS" AC_RUN_IFELSE( [AC_LANG_PROGRAM([#include #include ], [[ gcry_md_hd_t mac; unsigned char data[] = { 0xbf, 0x16, 0x6e, 0x46, 0x3a, 0x6c, 0xf3, 0x93, 0xa7, 0x72, 0x11, 0xa1, 0xdc, 0x0b, 0x07, 0xdb, 0x1a, 0x5e, 0xd9, 0xb9, 0x81, 0xbe, 0xea, 0xe4, 0x31, 0x5f, 0x24, 0xff, 0xfe, 0x50, 0x8a, 0xde }; unsigned char key[] = { 0xfc, 0x62, 0x76, 0x35 }; unsigned char result[] = {0xa2, 0xb, 0x1, 0xd9, 0xc0, 0x8b, 0x5a, 0x12, 0x80, 0xd5, 0x50, 0x12, 0x8e, 0xd0, 0x5b, 0xb6, 0x5c, 0x87, 0x24, 0xe2, 0xd0, 0xd2, 0xaf, 0x63, 0xae, 0xd1, 0xd6, 0x64, 0x14, 0xe3, 0x6e, 0x61, 0x5b, 0xd, 0xba, 0x17, 0x7d, 0xd3, 0x10, 0xb1, 0x37, 0x41, 0x91, 0x7d, 0xeb, 0x1, 0x4d, 0x71, 0xe8, 0x59, 0x71, 0x42, 0x8e, 0xd6, 0xf3, 0x29, 0x3b, 0x90, 0xf2, 0xd1, 0xaf, 0x65, 0x1e, 0xb3}; if (!gcry_check_version (GCRYPT_VERSION)) { fprintf (stderr, "Version mismatch %s <-> %s \n", gcry_check_version (NULL), GCRYPT_VERSION); return 1; } gcry_control (GCRYCTL_DISABLE_SECMEM, 0); gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); if (gcry_md_open(&mac, GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC) != GPG_ERR_NO_ERROR) { fprintf (stderr, "gcry_md_open error\n"); return 2; } gcry_md_setkey (mac, key, sizeof (key)); gcry_md_write (mac, data, sizeof (data)); if (memcmp(gcry_md_read (mac, 0), result, gcry_md_get_algo_dlen (gcry_md_get_algo (mac))) != 0) { fprintf (stderr, "memcmp error\n"); return 3; } gcry_md_close (mac); return 0; ]])], [AC_MSG_RESULT([yes])], [ RESULT=$? if test $RESULT = 3 then AC_MSG_FAILURE([HMAC test vector does not match. This is a known problem with libgcrypt 1.2.2 on Windows and fixed in 1.4.6.]) fi if test $RESULT = 2 then AC_MSG_FAILURE([HMAC test failed]) fi if test $RESULT = 1 then AC_MSG_FAILURE([libgcrypt header version does not match library version]) fi ]) AC_LANG_POP(C) fi # $build = $target # libcurl LIBCURL_CHECK_CONFIG(,7.20.1,,AC_MSG_ERROR([GNUnet requires libcurl >= 7.20.1])) # restore LIBS LIBS=$SAVE_LIBS AC_CHECK_HEADERS([glpk.h],[glpk=true],[gplk=false]) AC_CHECK_LIB([glpk],[glp_create_prob],,[gplk=false]) # GLPK must support atm MLP presolving, version >= 4.32 AC_CHECK_MEMBERS(glp_iocp.presolve,,[gplk=false],[[#include ]]) if test x$gplk = xfalse then AM_CONDITIONAL(HAVE_LIBGLPK, false) AC_MSG_WARN([GNUnet requires GLPK >= 4.32]) else AM_CONDITIONAL(HAVE_LIBGLPK, true) AC_DEFINE([HAVE_LIBGLPK],[1],[Have GLPK]) fi AC_CHECK_HEADERS([nss.h],[nss=true],[nss=false]) if test x$nss = xfalse then AM_CONDITIONAL(HAVE_GLIBCNSS, false) AC_MSG_WARN([No GNU libc nss header, will not build NSS plugin]) else AM_CONDITIONAL(HAVE_GLIBCNSS, true) fi # test for kvm and kstat (for CPU stats under BSD/Solaris) AC_CHECK_LIB([kvm],[kvm_open]) AC_CHECK_LIB([kstat],[kstat_open]) # test for libextractor extractor=0 AC_MSG_CHECKING(for libextractor) AC_ARG_WITH(extractor, [ --with-extractor=PFX base of libextractor installation], [AC_MSG_RESULT([$with_extractor]) case $with_extractor in no) ;; yes) AC_CHECK_HEADERS(extractor.h, AC_CHECK_LIB([extractor], [EXTRACTOR_plugin_add_defaults], extractor=1)) ;; *) LDFLAGS="-L$with_extractor/lib $LDFLAGS" CPPFLAGS="-I$with_extractor/include $CPPFLAGS" AC_CHECK_HEADERS(extractor.h, AC_CHECK_LIB([extractor], [EXTRACTOR_plugin_add_defaults], EXT_LIB_PATH="-L$with_extractor/lib $EXT_LIB_PATH" extractor=1)) ;; esac ], [AC_MSG_RESULT([--with-extractor not specified]) AC_CHECK_HEADERS(extractor.h, AC_CHECK_LIB([extractor], [EXTRACTOR_plugin_add_defaults], extractor=1))]) if test "$extractor" != 1 then AC_MSG_ERROR([GNUnet requires libextractor]) fi # restore LIBS LIBS=$SAVE_LIBS # test for libunistring gl_LIBUNISTRING if test $HAVE_LIBUNISTRING != yes; then AC_MSG_ERROR([GNUnet requires libunistring]) fi if test $gl_libunistring_hexversion -le 2305; then AC_MSG_ERROR([GNUnet requires libunistring >= 0.9.1.1]) fi # restore LIBS LIBS=$SAVE_LIBS # Checks for standard header files. AC_HEADER_DIRENT AC_HEADER_STDC # Check for headers that are ALWAYS required AC_CHECK_HEADERS([fcntl.h math.h errno.h ctype.h limits.h stdio.h stdlib.h string.h unistd.h stdarg.h signal.h locale.h sys/stat.h sys/types.h],,AC_MSG_ERROR([Compiling GNUnet requires standard UNIX headers files])) # Checks for headers that are only required on some systems or opional (and where we do NOT abort if they are not there) AC_CHECK_HEADERS([langinfo.h sys/param.h sys/mount.h sys/statvfs.h sys/select.h sockLib.h sys/mman.h sys/msg.h sys/vfs.h arpa/inet.h fcntl.h libintl.h netdb.h netinet/in.h netinet/in_systm.h sys/ioctl.h sys/socket.h sys/time.h unistd.h kstat.h sys/sysinfo.h kvm.h sys/file.h sys/resource.h ifaddrs.h mach/mach.h stddef.h sys/timeb.h terminos.h argz.h ucred.h endian.h sys/endian.h]) SAVE_LDFLAGS=$LDFLAGS SAVE_CPPFLAGS=$CPPFLAGS # test for sqlite sqlite=false AC_MSG_CHECKING(for SQLite) AC_ARG_WITH(sqlite, [ --with-sqlite=PFX base of SQLite installation], [AC_MSG_RESULT("$with_sqlite") case $with_sqlite in no) ;; yes) AC_CHECK_HEADERS(sqlite3.h, sqlite=true) ;; *) LDFLAGS="-L$with_sqlite/lib $LDFLAGS" CPPFLAGS="-I$with_sqlite/include $CPPFLAGS" AC_CHECK_HEADERS(sqlite3.h, EXT_LIB_PATH="-L$with_sqlite/lib $EXT_LIB_PATH" SQLITE_LDFLAGS="-L$with_sqlite/lib" SQLITE_CPPFLAGS="-I$with_sqlite/include" sqlite=true) LDFLAGS=$SAVE_LDFLAGS CPPFLAGS=$SAVE_CPPFLAGS ;; esac ], [AC_MSG_RESULT([--with-sqlite not specified]) AC_CHECK_HEADERS(sqlite3.h, sqlite=true)]) AM_CONDITIONAL(HAVE_SQLITE, test x$sqlite = xtrue) AC_SUBST(SQLITE_CPPFLAGS) AC_SUBST(SQLITE_LDFLAGS) # test for postgres postgres=false AC_MSG_CHECKING(for postgres) AC_ARG_WITH(postgres, [ --with-postgres=PFX base of postgres installation], [AC_MSG_RESULT("$with_postgres") case $with_postgres in no) ;; yes) AC_CHECK_HEADERS(postgresql/libpq-fe.h, postgres=true) ;; *) LDFLAGS="-L$with_postgres/lib $LDFLAGS" CPPFLAGS="-I$with_postgres/include $CPPFLAGS" AC_CHECK_HEADERS(postgresql/libpq-fe.h, EXT_LIB_PATH="-L$with_postgres/lib $EXT_LIB_PATH" POSTGRES_LDFLAGS="-L$with_postgres/lib" POSTGRES_CPPFLAGS="-I$with_postgres/include" postgres=true) LDFLAGS=$SAVE_LDFLAGS CPPFLAGS=$SAVE_CPPFLAGS ;; esac ], [AC_MSG_RESULT([--with-postgres not specified]) AC_CHECK_HEADERS(postgresql/libpq-fe.h, postgres=true)]) AM_CONDITIONAL(HAVE_POSTGRES, test x$postgres = xtrue) AC_SUBST(POSTGRES_CPPFLAGS) AC_SUBST(POSTGRES_LDFLAGS) # test for libz (maybe required for linking mysql) zlib=1 AC_CHECK_LIB(z, compress,,zlib=0) AM_CONDITIONAL(HAVE_ZLIB, test x$zlib = x1) if test "$zlib" != 1 then AC_MSG_ERROR([GNUnet requires zlib]) fi # mysql & windows AC_CHECK_TYPES([sigset_t, off_t], [], [], [#include ]) AC_CHECK_TYPES([size_t], [], [], [#include ]) if test "$build_target" = "mingw" then CYGWIN_MYSQL_MAGIC="#include " fi # test for mysql mysql=false mysqlfail=false SAVE_LDFLAGS=$LDFLAGS SAVE_CPPFLAGS=$CPPFLAGS AC_MSG_CHECKING(for mysql) AC_ARG_WITH(mysql, [ --with-mysql=PFX base of MySQL installation], [AC_MSG_RESULT("$with_mysql") if test "$with_mysql" != "no" then if test "$with_mysql" != "yes" then LDFLAGS="-L$with_mysql/lib -L$with_mysql/lib/mysql $LDFLAGS $ZLIBS" CPPFLAGS="-I$with_mysql/include $CPPFLAGS" fi AC_CHECK_HEADERS(mysql/mysql.h, AC_CHECK_LIB(mysqlclient, mysql_init, MYSQL_LDFLAGS="-L$with_mysql/lib -L$with_mysql/lib/mysql" MYSQL_CPPFLAGS="-I$with_mysql/include" mysql=true), [], [$CYGWIN_MYSQL_MAGIC]) fi ], [AC_MSG_RESULT([--with-mysql not specified]) LDFLAGS="-L/usr/lib/mysql $LDFLAGS $ZLIBS" AC_CHECK_LIB(mysqlclient, mysql_init, [AC_CHECK_HEADERS(mysql/mysql.h, MYSQL_LDFLAGS="-L/usr/lib/mysql" mysql=true , [], [$CYGWIN_MYSQL_MAGIC])]) ]) AC_SUBST(MYSQL_LDFLAGS) AC_SUBST(MYSQL_CPPFLAGS) # additional version check for mysql AC_ARG_ENABLE(mysql-version-check, [ --disable-mysql-version-check do not check MySQL version],, enable_mysql_version_check=yes) if test "$mysql" = "true" -a "x$enable_mysql_version_check" = "xyes" then AC_MSG_CHECKING(mysql version) AC_RUN_IFELSE([AC_LANG_PROGRAM( [[$CYGWIN_MYSQL_MAGIC #include ]], [[if (MYSQL_VERSION_ID < 40100) return(-1); else return(0); ]]) ],mysql=true,mysql=false) if test "$mysql" = "false" then mysqlfail=true AC_MSG_RESULT([fail, >= 4.1 required]) else AC_MSG_RESULT(ok) fi fi AM_CONDITIONAL(HAVE_MYSQL, test x$mysql = xtrue) AM_CONDITIONAL(HAVE_MYSQLE, test "0" = "1") # restore LIBS LIBS=$SAVE_LIBS LDFLAGS=$SAVE_LDFLAGS CPPFLAGS=$SAVE_CPPFLAGS if test "$sqlite" = 0 -a "$mysql" = 0 then AC_MSG_ERROR([GNUnet requires SQLite or MySQL]) fi # libmicrohttpd lmhd=0 AC_MSG_CHECKING([for libmicrohttpd]) AC_ARG_WITH(microhttpd, [ --with-microhttpd=PFX base of libmicrohttpd installation], [AC_MSG_RESULT([$with_microhttpd]) case $with_microhttpd in no) ;; yes) AC_CHECK_HEADERS([microhttpd.h], AC_CHECK_DECL(MHD_OPTION_PER_IP_CONNECTION_LIMIT, AC_CHECK_LIB([microhttpd], [MHD_start_daemon], [AC_MSG_CHECKING([for libmicrohttpd >= 0.9.18]) AC_RUN_IFELSE([ #include "$srcdir/src/include/platform.h" #include int main () { return MHD_VERSION >= 0x0091200 ? 0 : 1; } ], [ AC_MSG_RESULT(ok) lmhd=1],[AC_MSG_RESULT(failed)],lmhd=1)]), [],[#include "$srcdir/src/include/platform.h" #include ]),, [#include "$srcdir/src/include/platform.h"]) ;; *) LDFLAGS="-L$with_microhttpd/lib $LDFLAGS" CPPFLAGS="-I$with_microhttpd/include $CPPFLAGS" AC_CHECK_HEADERS(microhttpd.h, AC_CHECK_DECL(MHD_OPTION_PER_IP_CONNECTION_LIMIT, AC_CHECK_LIB([microhttpd], [MHD_start_daemon], EXT_LIB_PATH="-L$with_microhttpd/lib $EXT_LIB_PATH" [AC_MSG_CHECKING([for libmicrohttpd >= 0.9.18]) AC_RUN_IFELSE([ #include "$srcdir/src/include/platform.h" #include int main () { return MHD_VERSION >= 0x0091200 ? 0 : 1; } ], [ AC_MSG_RESULT(ok) lmhd=1],[AC_MSG_RESULT(failed)],lmhd=1)]), [],[#include "$srcdir/src/include/platform.h" #include ]),, [#include "$srcdir/src/include/platform.h"]) ;; esac ], [AC_MSG_RESULT([--with-microhttpd not specified]) AC_CHECK_HEADERS([microhttpd.h], AC_CHECK_DECL(MHD_OPTION_PER_IP_CONNECTION_LIMIT, AC_CHECK_LIB([microhttpd], [MHD_start_daemon], [AC_MSG_CHECKING([for libmicrohttpd >= 0.9.18]) AC_RUN_IFELSE([ #include "$srcdir/src/include/platform.h" #include int main () { return MHD_VERSION >= 0x0091200 ? 0 : 1; } ], [ AC_MSG_RESULT(ok) lmhd=1],[AC_MSG_RESULT(failed)],lmhd=1)]), [],[#include "$srcdir/src/include/platform.h" #include ]),, [#include "$srcdir/src/include/platform.h"])]) AM_CONDITIONAL(HAVE_MHD, test x$lmhd = x1) AC_DEFINE_UNQUOTED([HAVE_MHD], $lmhd, [We have libmicrohttpd]) # restore LIBS LIBS=$SAVE_LIBS # check for python & pexpect (used for some testcases only) AM_PATH_PYTHON([2.6],, [:]) AM_CONDITIONAL([HAVE_PYTHON], [test "$PYTHON" != :]) if test "$PYTHON" != : then AC_MSG_CHECKING([for pexpect]) $PYTHON -c "import pexpect" > /dev/null 2> /dev/null PYEX=$? AM_CONDITIONAL(HAVE_PYTHON_PEXPECT, test $PYEX -eq 0) if test $PYEX -eq 0 then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([not found]) fi else AM_CONDITIONAL(HAVE_PYTHON_PEXPECT, 0) fi # check for gettext AM_GNU_GETTEXT([external]) AM_GNU_GETTEXT_VERSION([0.16.1]) # check for iconv AM_ICONV # Checks for standard typedefs, structures, and compiler characteristics. AC_TYPE_PID_T AC_TYPE_SIZE_T AC_TYPE_MODE_T AC_HEADER_TIME AC_HEADER_STAT AC_HEADER_STDBOOL AC_STRUCT_TM AC_CHECK_MEMBER([struct sockaddr_in.sin_len], [ AC_DEFINE(HAVE_SOCKADDR_IN_SIN_LEN, 1, [Do we have sockaddr_in.sin_len?]) ], [], [ #include #include #include ]) # Checks for library functions. AC_FUNC_CLOSEDIR_VOID AC_FUNC_FORK AC_PROG_GCC_TRADITIONAL AC_FUNC_MEMCMP AC_FUNC_SELECT_ARGTYPES AC_FUNC_CHOWN AC_TYPE_SIGNAL AC_FUNC_STAT AC_FUNC_STRFTIME AC_FUNC_VPRINTF AC_HEADER_SYS_WAIT AC_TYPE_OFF_T AC_TYPE_UID_T AC_CHECK_FUNCS([floor memmove rmdir strncasecmp strrchr strtol atoll dup2 fdatasync ftruncate gettimeofday memset mkdir mkfifo strcasecmp strchr strdup strerror strstr clock_gettime getrusage rand uname setlocale getcwd mktime gmtime_r gmtime strlcpy strlcat ftruncate stat64 sbrk mmap mremap setrlimit sysconf initgroups getifaddrs freeifaddrs localtime_r nl_langinfo putenv realpath strndup gethostbyname2 gethostbyname getpeerucred getpeereid setresuid $funcstocheck]) # restore LIBS LIBS=$SAVE_LIBS gn_user_home_dir="~/.gnunet" AC_ARG_WITH(user-home-dir, AC_HELP_STRING( [--with-user-home-dir=DIR], [default user home directory (~/.gnunet)]), [gn_user_home_dir=$withval]) AC_SUBST(GN_USER_HOME_DIR, $gn_user_home_dir) gn_daemon_home_dir="/var/lib/gnunet" AC_ARG_WITH(daemon-home-dir, AC_HELP_STRING( [--with-daemon-home-dir=DIR], [default daemon home directory (/var/lib/gnunet)]), [gn_daemon_home_dir=$withval]) AC_SUBST(GN_DAEMON_HOME_DIR, $gn_daemon_home_dir) gn_daemon_config_dir="/etc" AC_ARG_WITH(daemon-config-dir, AC_HELP_STRING( [--with-daemon-config-dir=DIR], [default daemon config directory (/etc)]), [gn_daemon_config_dir=$withval]) AC_SUBST(GN_DAEMON_CONFIG_DIR, $gn_daemon_config_dir) GN_INTLINCL="" GN_LIBINTL="$LTLIBINTL" AC_ARG_ENABLE(framework, [ --enable-framework enable Mac OS X framework build helpers],enable_framework_build=$enableval) AM_CONDITIONAL(WANT_FRAMEWORK, test x$enable_framework_build = xyes) if test x$enable_framework_build = xyes then AC_DEFINE([FRAMEWORK_BUILD], 1, [Build a Mac OS X Framework]) GN_INTLINCL='-I$(top_srcdir)/src/intlemu' GN_LIBINTL='$(top_builddir)/src/intlemu/libintlemu.la -framework CoreFoundation' AC_LIB_APPENDTOVAR([CPPFLAGS], [$GN_INTLINCL]) fi GN_LIB_LDFLAGS="-export-dynamic -no-undefined" GN_PLUGIN_LDFLAGS="-export-dynamic -avoid-version -module -no-undefined" AC_SUBST(GN_LIB_LDFLAGS) AC_SUBST(GN_PLUGIN_LDFLAGS) AC_SUBST(GN_INTLINCL) AC_SUBST(GN_LIBINTL) AC_SUBST(CPPFLAGS) AC_SUBST(LIBS) AC_SUBST(LDFLAGS) AC_SUBST(EXT_LIB_PATH) AC_SUBST(EXT_LIBS) AC_SUBST(LIBPREFIX) AC_SUBST(DLLDIR) AC_SUBST(EXT_LIB_PATH) # test for sudo AC_MSG_CHECKING(for sudo) AC_ARG_WITH(sudo, [ --with-sudo=PATH path to sudo binary (or just yes)], [AC_MSG_RESULT("$with_sudo") case $with_sudo in no) SUDO_BINARY= ;; yes) SUDO_BINARY=sudo ;; *) SUDO_BINARY=$with_sudo ;; esac ], [AC_MSG_RESULT([no])]) AC_SUBST(SUDO_BINARY) AM_CONDITIONAL([HAVE_SUDO], [test "x$SUDO_BINARY" != "x" -o -w /]) # test for gnunetdns group name GNUNETDNS_GROUP=gnunetdns AC_MSG_CHECKING(for gnunetdns group name) AC_ARG_WITH(gnunetdns, [ --with-gnunetdns=GRPNAME name for gnunetdns group], [AC_MSG_RESULT("$with_gnunetdns") case $with_gnunetdns in no) GNUNETDNS_GROUP=gnunet ;; yes) GNUNETDNS_GROUP=gnunetdns ;; *) GNUNETDNS_GROUP=$with_gnunetdns ;; esac ], [AC_MSG_RESULT([gnunetdns])]) AC_SUBST(GNUNETDNS_GROUP) # should 'make check' run tests? AC_MSG_CHECKING(whether to run tests) AC_ARG_ENABLE([testruns], [AS_HELP_STRING([--disable-testruns], [disable running tests on make check (default is YES)])], [enable_tests_run=${enableval}], [enable_tests_run=yes]) AC_MSG_RESULT($enable_test_run) AM_CONDITIONAL([ENABLE_TEST_RUN], [test "x$enable_tests_run" = "xyes"]) # should monkey be used when running (certain) services? AC_MSG_CHECKING(whether to run with monkey) AC_ARG_ENABLE([monkey], [AS_HELP_STRING([--enable-monkey], [enable running with monkey])], [enable_monkey=${enableval}], [enable_monkey=no]) AC_MSG_RESULT($enable_monkey) AM_CONDITIONAL([ENABLE_MONKEY], [test "x$enable_monkey" = "xyes"]) if test "x$enable_monkey" = "xyes" then MONKEYPREFIX="monkey" else MONKEYPREFIX="" fi AC_SUBST(MONKEYPREFIX) # should expensive tests be run? AC_MSG_CHECKING(whether to run expensive tests) AC_ARG_ENABLE([expensivetests], [AS_HELP_STRING([--enable-expensivetests], [enable running expensive testcases])], [enable_expensive=${enableval}], [enable_expensive=no]) AC_MSG_RESULT($enable_expensive) AM_CONDITIONAL([HAVE_EXPENSIVE_TESTS], [test "x$enable_expensive" = "xyes"]) # should ports be open for Java services? AC_MSG_CHECKING(whether to enable ports for gnunet-java) AC_ARG_ENABLE([javaports], [AS_HELP_STRING([--enable-javaports], [use non-zero ports for services with Java bindings (default is NO)])], [enable_java_ports=${enableval}], [enable_java_ports=no]) AC_MSG_RESULT($enable_java_ports) if test "x$enable_java_ports" = "xyes" then JAVAPORT="" else JAVAPORT="$UNIXONLY" fi AC_SUBST(JAVAPORT) # should benchmarks be run? AC_MSG_CHECKING(whether to run benchmarks during make check) AC_ARG_ENABLE([benchmarks], [AS_HELP_STRING([--enable-benchmarks], [enable running benchmarks during make check])], [enable_benchmarks=${enableval}], [enable_benchmarks=no]) AC_MSG_RESULT($enable_benchmarks) AM_CONDITIONAL([HAVE_BENCHMARKS], [test "x$enable_benchmarks" = "xyes"]) # should experimental code be compiled (code that may not yet compile)? AC_MSG_CHECKING(whether to compile experimental code) AC_ARG_ENABLE([experimental], [AS_HELP_STRING([--enable-experimental], [enable compiling experimental code])], [enable_experimental=${enableval}], [enable_experimental=no]) AC_MSG_RESULT($enable_experimental) AM_CONDITIONAL([HAVE_EXPERIMENTAL], [test "x$enable_experimental" = "xyes"]) # should code be enabled that works around missing OS functionality on Windows? # used for test cases if test $build_target = "mingw" then workarounds=1 AC_LINK_IFELSE( [AC_LANG_PROGRAM( [#include ],[ int s = socket (0, 0, 0);]) ],[ AC_DEFINE_UNQUOTED([HAVE_SOCKET],1,[Define this if socket() is available]) ],[ AC_DEFINE_UNQUOTED([HAVE_SOCKET],0,[Define this if socket() is available]) ]) AC_LINK_IFELSE( [AC_LANG_PROGRAM( [#include ],[ int s = select (0, NULL, NULL, NULL, NULL);]) ],[ AC_DEFINE_UNQUOTED([HAVE_SELECT],1,[Define this if select() is available]) ],[ AC_DEFINE_UNQUOTED([HAVE_SELECT],0,[Define this if select() is available]) ]) AC_LINK_IFELSE( [AC_LANG_PROGRAM( [#include ],[ struct in_addr i; char *s = inet_ntoa (i);]) ],[ AC_DEFINE_UNQUOTED([HAVE_INET_NTOA],1,[Define this if inet_ntoa() is available]) ],[ AC_DEFINE_UNQUOTED([HAVE_INET_NTOA],0,[Define this if inet_ntoa() is available]) ]) AC_LINK_IFELSE( [AC_LANG_PROGRAM( [#include ],[ int s = getnameinfo (NULL, 0, NULL, 0, NULL, 0, 0);]) ],[ AC_DEFINE_UNQUOTED([HAVE_GETNAMEINFO],1,[Define this if getnameinfo() is available]) ],[ AC_DEFINE_UNQUOTED([HAVE_GETNAMEINFO],0,[Define this if getnameinfo() is available]) ]) AC_LINK_IFELSE( [AC_LANG_PROGRAM( [#include ],[ int s = gethostname (NULL, 0);]) ],[ AC_DEFINE_UNQUOTED([HAVE_GETHOSTNAME],1,[Define this if gethostname() is available]) ],[ AC_DEFINE_UNQUOTED([HAVE_GETHOSTNAME],0,[Define this if gethostname() is available]) ]) AC_LINK_IFELSE( [AC_LANG_PROGRAM( [#include ],[ void *s = gethostbyname (NULL);]) ],[ AC_DEFINE_UNQUOTED([HAVE_GETHOSTBYNAME],1,[Define this if gethostbyname() is available]) ],[ AC_DEFINE_UNQUOTED([HAVE_GETHOSTBYNAME],0,[Define this if gethostbyname() is available]) ]) AC_LINK_IFELSE( [AC_LANG_PROGRAM( [#include ],[ void *s = gethostbyaddr (NULL, 0, 0);]) ],[ AC_DEFINE_UNQUOTED([HAVE_GETHOSTBYADDR],1,[Define this if gethostbyaddr() is available]) ],[ AC_DEFINE_UNQUOTED([HAVE_GETHOSTBYADDR],0,[Define this if gethostbyaddr() is available]) ]) AC_LINK_IFELSE( [AC_LANG_PROGRAM( [#include ],[ int s = getaddrinfo (NULL, NULL, NULL, NULL);]) ],[ AC_DEFINE_UNQUOTED([HAVE_GETADDRINFO],1,[Define this if getaddrinfo() is available]) ],[ AC_DEFINE_UNQUOTED([HAVE_GETADDRINFO],1,[Define this if getaddrinfo() is available]) ]) else AC_MSG_CHECKING(whether to enable windows workarounds) AC_ARG_ENABLE([windows_workarounds], [AS_HELP_STRING([--enable-windows_workarounds], [enable workarounds used on Windows (only useful for test cases)])], [enable_workarounds=${enableval}], [enable_workarounds=no]) AC_MSG_RESULT($enable_workarounds) if test x$enable_windows_workarounds = "xyes" then workarounds=1 else workarounds=0 fi fi AC_DEFINE_UNQUOTED([ENABLE_WINDOWS_WORKAROUNDS], $workarounds, [enable workarounds used on Windows (only useful for test cases)]) # gcov compilation AC_MSG_CHECKING(whether to compile with support for code coverage analysis) AC_ARG_ENABLE([coverage], AS_HELP_STRING([--enable-coverage], [compile the library with code coverage support]), [use_gcov=${enableval}], [use_gcov=no]) AC_MSG_RESULT($use_gcov) AM_CONDITIONAL([USE_COVERAGE], [test "x$use_gcov" = "xyes"]) AC_CONFIG_FILES([ Makefile contrib/Makefile doc/Makefile doc/man/Makefile m4/Makefile po/Makefile.in src/Makefile src/arm/Makefile src/arm/arm.conf src/ats/Makefile src/ats/ats.conf src/block/Makefile src/chat/Makefile src/chat/chat.conf src/core/Makefile src/core/core.conf src/datacache/Makefile src/datastore/Makefile src/datastore/datastore.conf src/dht/Makefile src/dht/dht.conf src/dns/Makefile src/dns/dns.conf src/dv/Makefile src/dv/dv.conf src/exit/Makefile src/fragmentation/Makefile src/fs/Makefile src/fs/fs.conf src/gns/Makefile src/gns/gns.conf src/gns/nss/Makefile src/hello/Makefile src/include/Makefile src/include/gnunet_directories.h src/hostlist/Makefile src/lockmanager/Makefile src/lockmanager/lockmanager.conf src/mesh/Makefile src/mesh/mesh.conf src/mysql/Makefile src/namestore/Makefile src/namestore/namestore.conf src/nat/Makefile src/nse/Makefile src/nse/nse.conf src/peerinfo/Makefile src/peerinfo/peerinfo.conf src/peerinfo-tool/Makefile src/postgres/Makefile src/pt/Makefile src/regex/Makefile src/statistics/Makefile src/statistics/statistics.conf src/stream/Makefile src/template/Makefile src/testbed/Makefile src/testing/Makefile src/topology/Makefile src/transport/Makefile src/transport/transport.conf src/tun/Makefile src/util/Makefile src/util/resolver.conf src/vpn/Makefile src/vpn/vpn.conf src/integration-tests/Makefile pkgconfig/Makefile pkgconfig/gnunetarm.pc pkgconfig/gnunetblock.pc pkgconfig/gnunetcore.pc pkgconfig/gnunetdatacache.pc pkgconfig/gnunetdatastore.pc pkgconfig/gnunetdht.pc pkgconfig/gnunetdhtlog.pc pkgconfig/gnunetdv.pc pkgconfig/gnunetfragmentation.pc pkgconfig/gnunetfs.pc pkgconfig/gnunethello.pc pkgconfig/gnunetnat.pc pkgconfig/gnunetnse.pc pkgconfig/gnunetpeerinfo.pc pkgconfig/gnunetregex.pc pkgconfig/gnunetstatistics.pc pkgconfig/gnunettesting.pc pkgconfig/gnunettransport.pc pkgconfig/gnunetutil.pc ]) AC_OUTPUT # Finally: summary! # warn user if mysql found but not used due to version if test "$mysqlfail" = "true" then AC_MSG_NOTICE([NOTICE: MySQL found, but too old. MySQL support will not be compiled.]) fi # sqlite if test "x$sqlite" = "x0" then AC_MSG_NOTICE([NOTICE: sqlite not found. sqLite support will not be compiled.]) fi # java ports if test "x$enable_java_ports" = "xyes" then AC_MSG_NOTICE([NOTICE: opening ports for gnunet-java bindings by default.]) fi if test "x$lmhd" != "x1" then AC_MSG_NOTICE([NOTICE: libmicrohttpd not found, http transport will not be installed.]) fi AC_MSG_NOTICE([NOTICE: Database support is set to MySQL: $mysql, SQLite: $sqlite, Postgres: $postgres]) if test "$enable_framework_build" = "yes" then AC_MSG_NOTICE([NOTICE: Mac OS X framework build enabled.]) fi if test "x$SUDO_BINARY" = "x" -a ! -w / then AC_MSG_NOTICE([NOTICE: --with-sudo not specified and not running as 'root', will not install GNS NSS library]) fi AC_MSG_NOTICE([******************************************** You can compile GNUnet with make now. After that, run (if necessary as 'root') make install to install everything. You may want to create a new user account to run the GNUnet service: adduser gnunet You also need to create an configuration file that should specify the path where GNUnet should store data. For example, you could store in "/etc/gnunet.conf" the following lines: [[PATHS]] SERVICEHOME = /var/lib/gnunet DEFAULTCONFIG = /etc/gnunet.conf Now, in order to start your peer, run as the 'gnunet' user gnunet-arm -s Each GNUnet user should also create an (at least initially) empty configuration file: mkdir $HOME/.gnunet/ touch $HOME/.gnunet/gnunet.conf Optionally, download and compile: - gnunet-gtk to get a GUI for file-sharing and configuration. ********************************************]) gnunet-0.9.3/INSTALL0000644000175000017500000003633211762217214011007 00000000000000Installation Instructions ************************* Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. Basic Installation ================== Briefly, the shell commands `./configure; make; make install' should configure, build, and install this package. The following more-detailed instructions are generic; see the `README' file for instructions specific to this package. Some packages provide this `INSTALL' file but do not implement all of the features documented below. The lack of an optional feature in a given package is not necessarily a bug. More recommendations for GNU packages can be found in *note Makefile Conventions: (standards)Makefile Conventions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. Running `configure' might take a while. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package, generally using the just-built uninstalled binaries. 4. Type `make install' to install the programs and any data files and documentation. When installing into a prefix owned by root, it is recommended that the package be configured and built as a regular user, and only the `make install' phase executed with root privileges. 5. Optionally, type `make installcheck' to repeat any self-tests, but this time using the binaries in their final installed location. This target does not install anything. Running this target as a regular user, particularly if the prior `make install' required root privileges, verifies that the installation completed correctly. 6. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. 7. Often, you can also type `make uninstall' to remove the installed files again. In practice, not all packages have tested that uninstallation works correctly, even though it is required by the GNU Coding Standards. 8. Some packages, particularly those that use Automake, provide `make distcheck', which can by used by developers to test that all other targets like `make install' and `make uninstall' work correctly. This target is generally not run by end users. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you can use GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. This is known as a "VPATH" build. With a non-GNU `make', it is safer to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. On MacOS X 10.5 and later systems, you can create libraries and executables that work on multiple system types--known as "fat" or "universal" binaries--by specifying multiple `-arch' options to the compiler but only a single `-arch' option to the preprocessor. Like this: ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CPP="gcc -E" CXXCPP="g++ -E" This is not guaranteed to produce working output in all cases, you may have to build one architecture at a time and combine the results using the `lipo' tool if you have problems. Installation Names ================== By default, `make install' installs the package's commands under `/usr/local/bin', include files under `/usr/local/include', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX', where PREFIX must be an absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option `--exec-prefix=PREFIX' to `configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. In general, the default for these options is expressed in terms of `${prefix}', so that specifying just `--prefix' will affect all of the other directory specifications that were not explicitly provided. The most portable way to affect installation locations is to pass the correct locations to `configure'; however, many packages provide one or both of the following shortcuts of passing variable assignments to the `make install' command line to change installation locations without having to reconfigure or recompile. The first method involves providing an override variable for each affected directory. For example, `make install prefix=/alternate/directory' will choose an alternate location for all directory configuration variables that were expressed in terms of `${prefix}'. Any directories that were specified during `configure', but not in terms of `${prefix}', must each be overridden at install time for the entire installation to be relocated. The approach of makefile variable overrides for each directory variable is required by the GNU Coding Standards, and ideally causes no recompilation. However, some platforms have known limitations with the semantics of shared libraries that end up requiring recompilation when using this method, particularly noticeable in packages that use GNU Libtool. The second method involves providing the `DESTDIR' variable. For example, `make install DESTDIR=/alternate/directory' will prepend `/alternate/directory' before all installation names. The approach of `DESTDIR' overrides is not required by the GNU Coding Standards, and does not work on platforms that have drive letters. On the other hand, it does better at avoiding recompilation issues, and works well even when some directory options were not specified in terms of `${prefix}' at `configure' time. Optional Features ================= If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Some packages offer the ability to configure how verbose the execution of `make' will be. For these packages, running `./configure --enable-silent-rules' sets the default to minimal output, which can be overridden with `make V=1'; while running `./configure --disable-silent-rules' sets the default to verbose, which can be overridden with `make V=0'. Particular systems ================== On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC is not installed, it is recommended to use the following options in order to use an ANSI C compiler: ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" and if that doesn't work, install pre-built binaries of GCC for HP-UX. On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot parse its `' header file. The option `-nodtk' can be used as a workaround. If GNU CC is not installed, it is therefore recommended to try ./configure CC="cc" and if that doesn't work, try ./configure CC="cc -nodtk" On Solaris, don't put `/usr/ucb' early in your `PATH'. This directory contains several dysfunctional programs; working variants of these programs are available in `/usr/bin'. So, if you need `/usr/ucb' in your `PATH', put it _after_ `/usr/bin'. On Haiku, software installed for all users goes in `/boot/common', not `/usr/local'. It is recommended to use the following options: ./configure --prefix=/boot/common Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the option `--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for `CONFIG_SHELL' due to an Autoconf bug. Until the bug is fixed you can use this workaround: CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of all of the options to `configure', and exit. `--help=short' `--help=recursive' Print a summary of the options unique to this package's `configure', and exit. The `short' variant lists options used only in the top level, while the `recursive' variant lists options also present in any nested packages. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--prefix=DIR' Use DIR as the installation prefix. *note Installation Names:: for more details, including other options available for fine-tuning the installation locations. `--no-create' `-n' Run the configure checks, but stop before creating any output files. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. gnunet-0.9.3/ChangeLog0000644000175000017500000023403711762521677011545 000000000000002012-06-02 14:39 grothoff * [r21729] configure.ac, src/include/plibc.h, src/util/server.c, src/util/winproc.c: LRN: Update plibc and utf8ization 2012-06-01 18:51 wachs * [r21714] src/transport/plugin_transport_http_client.c, src/transport/plugin_transport_http_server.c: fix for 2395 2012-06-01 15:36 wachs * [r21704] src/ats/gnunet-service-ats_addresses.c: fix for 0002392 2012-06-01 08:58 schanzen * [r21684] src/gns/nss/Makefile.am, src/gns/nss/nss_gns.c, src/gns/nss/nss_gns_query.c, src/gns/nss/nss_gns_query.h, src/gns/nss/query.c, src/gns/nss/query.h, src/gns/nss/util.c, src/gns/nss/util.h: cleanup 2012-06-01 08:53 wachs * [r21683] src/transport/plugin_transport_unix.c: additional error message 2012-06-01 08:53 wachs * [r21682] src/transport/plugin_transport_http_server.c: remove unused variable 2012-05-30 21:21 harsha * [r21647] src/testing/Makefile.am, src/testing/testing_new.c: test case for peer startup in new testing library 2012-05-30 14:47 wachs * [r21646] src/util/Makefile.am, src/util/program.c, src/util/service.c, src/util/speedup.c, src/util/test_speedup.c, src/util/test_speedup_data.conf, src/util/util.conf: speedup mechanism to manipulate gnunet time 2012-05-30 14:34 harsha * [r21645] src/testing/testing_new.c: comments and fixed NULL check for tm 2012-05-30 14:26 harsha * [r21644] src/testing/testing_new.c: refined GNUNET_TESTING_service_run 2012-05-29 14:06 harsha * [r21634] src/testing/testing_new.c: removed double rsa key free 2012-05-27 21:46 grothoff * [r21608] src/ats/gnunet-service-ats_addresses.c, src/ats/gnunet-service-ats_addresses_mlp.c, src/ats/test_ats_api_update_address.c, src/core/core_api_is_connected.c, src/core/core_api_iterate_peers.c, src/dns/plugin_block_dns.c, src/dv/gnunet-service-dv.c, src/gns/gnunet-service-gns_resolver.c, src/gns/plugin_block_gns.c, src/gns/test_gns_dht_delegated_lookup.c, src/gns/test_gns_max_queries.c, src/gns/test_gns_pseu_shorten.c, src/gns/test_gns_simple_delegated_lookup.c, src/gns/test_gns_simple_get_authority.c, src/gns/test_gns_simple_lookup.c, src/gns/test_gns_simple_mx_lookup.c, src/gns/test_gns_simple_shorten.c, src/gns/test_gns_simple_zkey_lookup.c, src/hostlist/hostlist-client.c, src/include/gnunet_time_lib.h, src/integration-tests/connection_watchdog.c, src/mesh/gnunet-service-mesh.c, src/mesh/test_mesh_2dtorus.c, src/mesh/test_mesh_small.c, src/namestore/gnunet-namestore.c, src/namestore/gnunet-service-namestore.c, src/namestore/namestore_api.c, src/namestore/test_namestore_api.c, src/namestore/test_namestore_api_create.c, src/namestore/test_namestore_api_create_update.c, src/namestore/test_namestore_api_lookup.c, src/namestore/test_namestore_api_lookup_specific_type.c, src/namestore/test_namestore_api_put.c, src/namestore/test_namestore_api_remove.c, src/namestore/test_namestore_api_remove_not_existing_record.c, src/namestore/test_namestore_api_zone_iteration.c, src/namestore/test_namestore_api_zone_iteration_specific_zone.c, src/namestore/test_namestore_api_zone_iteration_stop.c, src/namestore/test_namestore_record_serialization.c, src/nse/gnunet-nse-profiler.c, src/nse/nse_profiler_test.conf, src/testing/test_testing_2dtorus.c, src/testing/testing_group.c, src/transport/plugin_transport_http.c, src/transport/plugin_transport_http_server.c, src/transport/plugin_transport_udp.c, src/util/test_time.c, src/util/time.c: renaming GNUNET_TIME_relative_get_forever and GNUNET_TIME_absolute_get_forever methods, adding underscore, to make it clear that the respective #defines should be used instead; replacing use of direct function calls with respective macros where applicable; adding additional GNUNET_TIME_relative_get_xxx-functions to avoid calls to GNUNET_TIME_relative_multiply, which turn out to have gotten performance-relevant 2012-05-27 21:11 grothoff * [r21607] src/util/server.c: use GNUNET_SCHEDULER_add_read_net_with_priority instead of constructing fd sets in server with only one active listen socket 2012-05-27 21:10 grothoff * [r21606] src/gns/gnunet-service-gns.c, src/include/gnunet_scheduler_lib.h, src/util/scheduler.c: adding GNUNET_SCHEDULER_add_read_net_with_priority 2012-05-26 15:14 harsha * [r21586] src/testing/test_testing_new_portreservation.c, src/testing/testing_new.c: port reservation - release 2012-05-26 14:04 harsha * [r21585] src/testing, src/testing/Makefile.am, src/testing/test_testing_new_portreservation.c, src/testing/testing_new.c: port reservation and test cases 2012-05-25 14:40 harsha * [r21578] src/testing/testing_new.c: testing port reservation 2012-05-25 09:34 wachs * [r21573] src/transport/plugin_transport_tcp.c, src/transport/plugin_transport_udp.c: session timeout for udp and tcp 2012-05-25 08:25 wachs * [r21572] src/transport/gnunet-service-transport_neighbours.c: 2012-05-23 07:10 wachs * [r21562] contrib/gnunet_janitor.py.in: LRN's patch 2012-05-22 15:43 harsha * [r21561] src/stream, src/testing/testing_new.c: testing port checking (incomplete) 2012-05-22 15:03 harsha * [r21560] src/stream/test_stream_2peers.c, src/stream/test_stream_2peers_halfclose.c, src/stream/test_stream_local.c: fixed segmentation fault due to missing GNUNET_STREAM_OPTION_END 2012-05-20 15:06 harsha * [r21552] src/testing/testing_new.c: testing system 2012-05-15 14:07 harsha * [r21499] src/lockmanager, src/lockmanager/lockmanager_api.c, src/lockmanager/test_lockmanager_api.c, src/lockmanager/test_lockmanager_api_servercrash.c: handling replies continuously from server 2012-05-15 13:09 harsha * [r21497] src/lockmanager/Makefile.am, src/lockmanager/lockmanager_api.c, src/lockmanager/test_lockmanager_api_servercrash.c: server crash test case 2012-05-15 10:00 wachs * [r21492] src/transport/gnunet-service-transport_neighbours.c: fix for mantis 2356 2012-05-15 09:11 wachs * [r21491] src/transport/plugin_transport_wlan.c: fix memleak 2012-05-15 08:09 wachs * [r21490] src/transport/gnunet-service-transport_neighbours.c: fix for mantis 2355 2012-05-14 13:32 harsha * [r21476] src/lockmanager/lockmanager_api.c: removed local function 2012-05-14 13:04 harsha * [r21475] src/stream/stream_api.c, src/stream/test_stream_2peers_halfclose.c: warnings 2012-05-14 09:06 wachs * [r21469] src/transport/plugin_transport_udp.c: fix for mantis 2346 2012-05-13 18:07 harsha * [r21463] src/include/gnunet_lockmanager_service.h, src/lockmanager/lockmanager_api.c: change in API documentation and function for finding lockingRequest in hashmap 2012-05-13 17:21 harsha * [r21462] src/lockmanager, src/lockmanager/Makefile.am, src/lockmanager/gnunet-service-lockmanager.c, src/lockmanager/lockmanager_api.c, src/lockmanager/test_lockmanager_api.conf, src/lockmanager/test_lockmanager_api_lockrelease.c: clean shutdown in lockmanager, test case for lock release and message format checks for incoming msg in lockmanager API 2012-05-12 08:40 harsha * [r21447] src/stream/stream_api.c: peer ids in logging and indentation 2012-05-11 21:50 harsha * [r21442] src/lockmanager/gnunet-service-lockmanager.c: inlining of helper functions 2012-05-11 13:55 grothoff * [r21440] src/lockmanager/gnunet-service-lockmanager.c, src/transport/plugin_transport_wlan.c: doxygen 2012-05-11 08:18 harsha * [r21435] src/stream/stream_api.c: logging and indentation 2012-05-10 16:26 wachs * [r21421] src/transport/plugin_transport_wlan.c: fixing WLAN 2012-05-10 15:44 harsha * [r21420] src/lockmanager/gnunet-service-lockmanager.c: NULL check on disconnect handler 2012-05-10 15:26 harsha * [r21419] src/lockmanager/gnunet-service-lockmanager.c: lockmanager with new datastructure 2012-05-09 14:29 szengel * [r21387] src/regex/regex.c: fixes 2012-05-09 13:32 wachs * [r21383] src/util/server_nc.c: fix for mantis 2330#c5818 GNUNET_SERVER_notification_context_destroy does not cancel transmit_ready 2012-05-09 13:25 szengel * [r21382] src/regex/regex.c: Fixed warning 2012-05-09 09:59 harsha * [r21369] src/lockmanager/gnunet-service-lockmanager.c: processing upon lock release 2012-05-09 08:29 harsha * [r21367] src/lockmanager/gnunet-service-lockmanager.c: lock acquire and release 2012-05-09 07:09 harsha * [r21366] src/lockmanager/gnunet-service-lockmanager.c: added list processing 2012-05-08 17:10 bartpolot * [r21352] src/arm/gnunet-service-arm.c, src/ats/test_ats_api_bandwidth_consumption.c, src/ats/test_ats_api_scheduling.c, src/chat/test_chat.c, src/chat/test_chat_private.c, src/core/test_core_api.c, src/core/test_core_api_reliability.c, src/core/test_core_api_send_to_self.c, src/core/test_core_api_start_only.c, src/core/test_core_quota_compliance.c, src/datastore/perf_datastore_api.c, src/datastore/test_datastore_api.c, src/datastore/test_datastore_api_management.c, src/dht/test_dht_api.c, src/fs/test_fs.c, src/fs/test_fs_download.c, src/fs/test_fs_download_indexed.c, src/fs/test_fs_download_persistence.c, src/fs/test_fs_download_recursive.c, src/fs/test_fs_list_indexed.c, src/fs/test_fs_namespace.c, src/fs/test_fs_namespace_list_updateable.c, src/fs/test_fs_publish.c, src/fs/test_fs_publish_persistence.c, src/fs/test_fs_search.c, src/fs/test_fs_search_persistence.c, src/fs/test_fs_search_probes.c, src/fs/test_fs_search_ranking.c, src/fs/test_fs_start_stop.c, src/fs/test_fs_unindex.c, src/fs/test_fs_unindex_persistence.c, src/hostlist/test_gnunet_daemon_hostlist.c, src/hostlist/test_gnunet_daemon_hostlist_learning.c, src/hostlist/test_gnunet_daemon_hostlist_reconnect.c, src/include/gnunet_os_lib.h, src/lockmanager/test_lockmanager_api.c, src/mesh/test_mesh_api.c, src/mesh/test_mesh_local_1.c, src/mesh/test_mesh_local_2.c, src/namestore/test_namestore_api.c, src/namestore/test_namestore_api_create.c, src/namestore/test_namestore_api_create_update.c, src/namestore/test_namestore_api_lookup.c, src/namestore/test_namestore_api_lookup_specific_type.c, src/namestore/test_namestore_api_put.c, src/namestore/test_namestore_api_remove.c, src/namestore/test_namestore_api_remove_not_existing_record.c, src/namestore/test_namestore_api_zone_iteration.c, src/namestore/test_namestore_api_zone_iteration_specific_zone.c, src/namestore/test_namestore_api_zone_iteration_stop.c, src/namestore/test_namestore_api_zone_to_name.c, src/nat/nat.c, src/nat/nat_mini.c, src/nat/test_nat_test.c, src/nse/test_nse_api.c, src/peerinfo/perf_peerinfo_api.c, src/peerinfo/test_peerinfo_api.c, src/statistics/test_statistics_api.c, src/statistics/test_statistics_api_loop.c, src/statistics/test_statistics_api_watch.c, src/statistics/test_statistics_api_watch_zero_value.c, src/stream/test_stream_api.c, src/stream/test_stream_local.c, src/testing/test_testing_large_topology.c, src/testing/test_testing_topology.c, src/testing/testing.c, src/testing/testing_group.c, src/transport/gnunet-transport-certificate-creation.c, src/transport/gnunet-transport.c, src/transport/plugin_transport_http_server.c, src/transport/plugin_transport_wlan.c, src/transport/transport-testing.c, src/util/crypto_random.c, src/util/helper.c, src/util/os_priority.c, src/util/test_common_logging_runtime_loglevels.c, src/util/test_os_start_process.c, src/util/test_resolver_api.c, src/vpn/test_gnunet_vpn.c: Renamed GNUNET_OS_process_close to GNUNET_OS_process_destroy 2012-05-07 17:31 szengel * [r21330] src/regex/regex.c, src/regex/test_regex_iterate_api.c: Fixed compilation warnings 2012-05-07 13:35 grothoff * [r21324] contrib/Makefile.am, contrib/timeout_watchdog_w32.c: LRN: creating watchdog helper binary for W32 2012-05-07 08:25 wachs * [r21315] src/transport/gnunet-service-transport_neighbours.c: fix for mantis 2320 2012-05-04 12:57 bartpolot * [r21271] src/dht/dht.h, src/dht/dht_api.c, src/dht/gnunet-service-dht_clients.c: Added stop operation for dht monitoring 2012-05-03 13:49 grothoff * [r21248] src/peerinfo/peerinfo_api.c: doxygen 2012-05-03 11:36 grothoff * [r21244] src/peerinfo/perf_peerinfo_api.c, src/peerinfo/test_peerinfo_api.c: f-xi 2012-05-02 13:24 wachs * [r21223] src/peerinfo-tool/gnunet-peerinfo.c: fix 2297 2012-04-27 13:44 wachs * [r21203] src/transport/plugin_transport_unix.c: working string toaddress 2012-04-22 19:52 grothoff * [r21075] src/arm/gnunet-service-arm.c, src/ats/gnunet-service-ats.c, src/include/gnunet_server_lib.h, src/include/gnunet_service_lib.h, src/namestore/gnunet-service-namestore.c, src/peerinfo/gnunet-service-peerinfo.c, src/statistics/gnunet-service-statistics.c, src/transport/gnunet-service-transport.c, src/transport/gnunet-service-transport_blacklist.c, src/transport/gnunet-service-transport_clients.c, src/transport/plugin_transport_tcp.c, src/util/server.c, src/util/service.c: introducing soft shutdown concept for services; during soft shutdown, services that are still managing non-monitor clients continue to run until those clients disconnect; however, the services do stop to accept new connections (will stop listening); soft shutdown is now used by ats, transport, peerinfo, namestore and most importantly statistics; this should fix #2197 2012-04-21 18:16 grothoff * [r21060] src/include/gnunet_container_lib.h, src/util/container_bloomfilter.c: changing bloomfilter to allow GNUNET_CONTAINER_bloomfilter_init with sizes that are not powers of 2 -- GNUNET_CONTAINER_bloomfilter_load will continue to round up to power of two 2012-04-20 12:35 szengel * [r21054] src/regex/regex.c, src/regex/test_regex_iterate_api.c: recursion for dfa construction 2012-04-19 11:39 szengel * [r21025] src/regex/regex.c, src/regex/test_regex_eval_api.c, src/regex/test_regex_iterate_api.c: dfa minimization fix 2012-04-18 14:02 szengel * [r21011] src/include/gnunet_regex_lib.h, src/regex/Makefile.am, src/regex/regex.c, src/regex/test_regex.c, src/regex/test_regex_eval_api.c, src/regex/test_regex_iterate_api.c: test update 2012-04-18 13:49 wachs * [r21009] src/statistics/statistics_api.c: fix 2273 2012-04-18 09:55 wachs * [r21005] src/statistics/Makefile.am, src/statistics/gnunet-service-statistics.c, src/statistics/test_statistics_api_watch_zero_value.c: fixing bug 2272: added functionality for watch to notifz about fresh created entries with value 0 2012-04-18 09:30 szengel * [r21004] src/include/gnunet_regex_lib.h, src/regex/regex.c: added accepting state info to api 2012-04-17 20:43 szengel * [r21001] src/include/gnunet_regex_lib.h, src/regex/regex.c: api changes 2012-04-12 13:28 szengel * [r20965] src/regex/regex.c: bugfix 2012-04-12 11:48 szengel * [r20959] src/regex/regex.c, src/regex/test_regex.c: Added '?' operator 2012-04-11 15:30 szengel * [r20947] src/regex/regex.c: comments 2012-04-11 14:13 szengel * [r20943] src/regex/regex.c: doxygen fix 2012-04-10 14:37 szengel * [r20925] src/regex/regex.c, src/regex/test_regex.c: fix 2012-04-10 14:30 szengel * [r20924] src/regex/regex.c, src/regex/test_regex.c: dfa minimization wip 2012-04-09 14:56 szengel * [r20911] src/regex/regex.c, src/regex/test_regex.c: fixes 2012-04-05 14:28 szengel * [r20905] src/regex/regex.c, src/regex/test_regex.c: removing unreachable states 2012-04-05 12:38 szengel * [r20904] src/regex/test_regex.c: better testing 2012-04-05 11:46 szengel * [r20902] src/regex/regex.c, src/regex/test_regex.c: Automatic regex generation for testing 2012-04-04 08:21 grothoff * [r20893] configure.ac, src/fs/fs.conf.in: adding configure option to run GNUnet with monkey 2012-04-03 13:46 szengel * [r20883] src/include/gnunet_regex_lib.h, src/regex/Makefile.am, src/regex/regex.c, src/regex/regex.h, src/regex/test_regex.c: fix 2012-04-02 11:20 wachs * [r20848] src/transport/plugin_transport_http.c, src/transport/transport.conf.in: fixing 0002249: report only new addresses 2012-04-02 10:19 szengel * [r20847] src/regex/regex.c, src/regex/test_regex.c: NFA evaluation 2012-04-02 09:39 szengel * [r20845] src/include/gnunet_regex_lib.h, src/regex/regex.c, src/regex/test_regex.c: DFA evaluation 2012-04-01 09:13 grothoff * [r20826] src/core/gnunet-service-core_kx.c: implementing rekeying, some code cleanup 2012-04-01 07:56 grothoff * [r20825] doc/man/Makefile.am, doc/man/gnunet-core.1, src/core/Makefile.am, src/core/gnunet-core-list-connections.c, src/core/gnunet-core.c, src/include/gnunet_fs_service.h: renaming gnunet-core-list-connections to gnunet-core, adding man page 2012-03-30 15:43 wachs * [r20819] src/transport/gnunet-service-transport_neighbours.c: 2012-03-28 19:27 szengel * [r20801] src/include/gnunet_regex_lib.h, src/regex/regex.c: doxygen fix 2012-03-28 15:49 szengel * [r20800] src/include/gnunet_regex_lib.h, src/regex/regex.c, src/regex/test_regex.c: api changes 2012-03-27 16:37 szengel * [r20790] src/regex/regex.c, src/regex/test_regex.c: formatting 2012-03-24 19:13 grothoff * [r20751] src/fs/fs_api.c, src/fs/fs_publish.c, src/fs/fs_tree.c: fixing issue with gnunet-publish not closing files early enough when publishing directories with more than FD_MAX files (#2239) 2012-03-24 09:05 harsha * [r20740] src/include/gnunet_stream_lib.h, src/stream/stream_api.c: fixed compile error from r20729 2012-03-23 17:40 szengel * [r20738] src/include/gnunet_regex_lib.h, src/regex/regex.c, src/regex/test_regex.c: towards dfa 2012-03-23 11:15 harsha * [r20714] src/stream/stream_api.c: bugfix 2012-03-23 10:58 harsha * [r20711] src/stream/stream_api.c, src/stream/stream_protocol.h: fixed read packets removal after read processor, byte ordering bugs, ack_bitmap handling in handle_ack ack_task cancelling in socket close 2012-03-23 08:04 szengel * [r20699] src/regex/regex.c: fix 2012-03-22 21:25 szengel * [r20698] src/regex/regex.c: cleanup 2012-03-22 19:41 szengel * [r20697] configure.ac, pkgconfig/gnunetregex.pc, src/include/gnunet_regex_lib.h, src/regex/Makefile.am, src/regex/regex.c, src/regex/regex.h, src/regex/test_regex.c: Added initial version of regex lib 2012-03-22 18:47 grothoff * [r20693] configure.ac, src/Makefile.am, src/datacache/Makefile.am, src/datacache/plugin_datacache_postgres.c, src/datastore/plugin_datastore_postgres.c, src/include/Makefile.am, src/include/gnunet_mysql_lib.h, src/include/gnunet_postgres_lib.h, src/postgres, src/postgres/Makefile.am, src/postgres/postgres.c: adding libgnunetpostgres for shared postgres functionality between postgres datastore/datacache backends 2012-03-22 11:05 wachs * [r20670] src/include/gnunet_namestore_service.h, src/namestore/gnunet-service-namestore.c, src/namestore/namestore.h, src/namestore/namestore_common.c: 2012-03-21 12:32 harsha * [r20644] src/stream/stream_api.c, src/stream/test_stream_local.c: fixed read timeout problem and added ack sending incase of ignored data messages 2012-03-21 09:43 grothoff * [r20643] src/Makefile.am, src/include/Makefile.am, src/mysql, src/mysql/Makefile.am, src/mysql/mysql.c: creating mysql helper library for the various mysql backends 2012-03-21 07:06 harsha * [r20639] src/stream/stream_api.c, src/stream/test_stream_local.c: fixed listen callback to happen after reaching ESTABLISHED state 2012-03-19 14:53 grothoff * [r20606] configure.ac, src/core/core.conf.in, src/dht/dht.conf.in, src/nse/nse.conf.in, src/statistics/statistics.conf.in: add configure option --enable-javaports to open ports of services with Java bindings by default (#2228) 2012-03-19 10:17 grothoff * [r20598] doc/man/gnunet-rsa.1, src/datastore/datastore.h, src/exit/exit.h, src/fs/gnunet-service-fs.h, src/include/block_dns.h, src/include/gnunet_common.h, src/include/gnunet_crypto_lib.h, src/include/gnunet_strings_lib.h, src/util/crypto_hash.c, src/util/gnunet-rsa.c, src/util/strings.c, src/vpn/vpn.h: adding API for short (256-bit) hash codes 2012-03-16 14:47 grothoff * [r20570] src/gns/gnunet-gns-fcfsd.c: fix 2012-03-15 21:24 wachs * [r20551] src/namestore/gnunet-namestore.c: 2012-03-15 18:22 wachs * [r20548] src/namestore/gnunet-service-namestore.c: fix segfault 2012-03-15 10:59 grothoff * [r20515] doc/man/gnunet-rsa.1, src/util/gnunet-rsa.c: add -P option for printing peer identities with gnunet-rsa 2012-03-11 22:51 grothoff * [r20445] src/hostlist/hostlist-server.c, src/hostlist/hostlist.conf: vminko: implementing BINDTO option for hostlist service (#2140) 2012-03-10 23:17 grothoff * [r20431] src/include/gnunet_transport_plugin.h, src/transport/plugin_transport_http.c, src/transport/plugin_transport_tcp.c, src/transport/plugin_transport_udp.c, src/transport/plugin_transport_unix.c, src/transport/plugin_transport_wlan.c: add support for stub-mode for transport plugins 2012-03-10 15:09 harsha * [r20424] src/stream/stream_api.c: using GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH 2012-03-10 09:13 harsha * [r20423] src/stream/stream_api.c, src/stream/test_stream_local.c: fixed retransmission task 2012-03-09 15:16 grothoff * [r20415] src/fs/fs_api.c, src/fs/fs_api.h, src/fs/fs_unindex.c: implementing removal of KBlocks during unindex operation (#1926) 2012-03-09 12:53 harsha * [r20407] src/stream/stream_api.c, src/stream/stream_protocol.h, src/stream/test_stream_local.c: fixed byte conversion bugs 2012-03-09 11:39 grothoff * [r20398] src/arm/gnunet-service-arm.c: adding code to measure and report shutdown time for services to gnunet-service-arm at INFO level logging 2012-03-09 08:50 harsha * [r20390] src/stream/stream_api.c: corrected HELLO_ACK message size 2012-03-08 17:26 wachs * [r20375] src/namestore/gnunet-service-namestore.c, src/namestore/hostkey, src/namestore/hostkey2, src/namestore/namestore.conf.in, src/namestore/test_namestore_api.c, src/namestore/test_namestore_api.conf, src/namestore/test_namestore_api_create.c, src/namestore/test_namestore_api_create_update.c, src/namestore/test_namestore_api_lookup.c, src/namestore/test_namestore_api_lookup_specific_type.c, src/namestore/test_namestore_api_put.c, src/namestore/test_namestore_api_remove.c, src/namestore/test_namestore_api_remove_not_existing_record.c, src/namestore/test_namestore_api_sign_verify.c, src/namestore/test_namestore_api_zone_iteration.c, src/namestore/test_namestore_api_zone_iteration_specific_zone.c, src/namestore/test_namestore_api_zone_iteration_stop.c, src/namestore/test_namestore_api_zone_to_name.c, src/namestore/zonefiles, src/namestore/zonefiles/4UCICULTINKC87UO4326KEEDQ9MTEP2AJT88MJFVGTGNK12QNGMQI2S41VI07UUU6EO19BTB06PDL0HE6VP1OM50HOJEI75RHP4JP80.zone, src/namestore/zonefiles/KJI3AL00K91EDPFJF58DAJM7H61D189TLP70N56JL8SVDCJE1SJ3SNNBOQPPONTL37FMHPS39SMK2NMVC0GQMGA6QCMHITT78O8GF80.zone: namestore manages zonekey files with private keys 2012-03-08 16:30 harsha * [r20373] src/stream/stream_api.c: peer interning 2012-03-08 13:23 harsha * [r20365] src/stream/stream_api.c, src/stream/test_stream_local.c: more assertions 2012-03-08 07:45 harsha * [r20362] src/stream/stream_api.c, src/stream/test_stream_local.c: Data message retransmissions 2012-03-07 12:45 wachs * [r20336] src/gns/gnunet-gns-fcfsd.c, src/gns/namestore_stub_api.c, src/gns/test_gns_dht_delegated_lookup.c, src/gns/test_gns_simple_delegated_lookup.c, src/gns/test_gns_simple_lookup.c, src/gns/test_gns_twopeer.c, src/include/gnunet_namestore_service.h, src/namestore/gnunet-namestore.c, src/namestore/gnunet-service-namestore.c, src/namestore/namestore_api.c, src/namestore/test_namestore_api.conf, src/namestore/test_namestore_api_create.c, src/namestore/test_namestore_api_create_update.c, src/namestore/test_namestore_api_zone_iteration.c, src/namestore/test_namestore_api_zone_iteration_specific_zone.c, src/namestore/test_namestore_api_zone_iteration_stop.c: namestore api change: include block expiration time in record create 2012-03-07 10:11 grothoff * [r20329] src/namestore/namestore_common.c: implementing more of GNUNET_NAMESTORE_value_to_string 2012-03-06 09:50 grothoff * [r20302] src/namestore/namestore.h: breaking stuff 2012-03-05 21:04 grothoff * [r20294] src/statistics/gnunet-service-statistics.c: fix 2012-03-05 15:38 grothoff * [r20282] src/include/gnunet_gns_service.h: fix 2012-03-04 22:55 grothoff * [r20258] src/fs/fs.conf.in, src/fs/fs_api.c: adding fs/ to all default directory names relating to file sharing 2012-03-04 22:10 grothoff * [r20252] src/fs/fs_api.c: fixing #1927 by further limiting the time a download probe can be active at a time in the download queue; this is equivalent to it having a low priority 2012-03-04 20:59 grothoff * [r20246] src/statistics/gnunet-service-statistics.c, src/statistics/statistics.h, src/statistics/statistics_api.c: make gnunet-service-statistics not exit on external shutdown signal as long as there are connected clients to be managed 2012-03-04 15:02 grothoff * [r20241] doc/man/Makefile.am, doc/man/gnunet-gns.1, src/gns/Makefile.am, src/gns/gnunet-gns.c: adding gnunet-gns, a new tool for zone manipulations 2012-03-04 14:37 grothoff * [r20237] doc/man/Makefile.am, doc/man/gnunet-rsa.1, src/util/Makefile.am, src/util/gnunet-rsa.c: adding gnunet-rsa, a new tool to create RSA keys and to print the public key 2012-03-04 13:51 grothoff * [r20232] src/include/gnunet_crypto_lib.h, src/util/crypto_hash.c: LRN: adding generic functions for conversion of binary data to ascii and back: GNUNET_CRYPTO_string_to_data and GNUNET_CRYPTO_data_to_string 2012-03-02 17:29 wachs * [r20206] src/namestore/Makefile.am, src/namestore/gnunet-service-namestore.c, src/namestore/namestore.h, src/namestore/namestore_api.c, src/namestore/test_namestore_api_put.c: 2012-03-02 15:39 wachs * [r20205] src/transport/plugin_transport_tcp.c: fix for mantis 2189 2012-03-01 11:58 szengel * [r20164] src/arm/gnunet-service-arm.c: Using GNUNET_snprintf. 2012-03-01 08:24 grothoff * [r20154] src/chat/gnunet-chat.c, src/fs/fs_uri.c, src/fs/gnunet-pseudonym.c, src/include/gnunet_pseudonym_lib.h, src/util/pseudonym.c, src/util/test_pseudonym.c: LRN: updates to pseudonym API from #1952, change pseudonym management 2012-02-29 19:21 wachs * [r20150] src/include/gnunet_crypto_lib.h, src/util/crypto_rsa.c: serialize privat key 2012-02-29 12:50 grothoff * [r20143] src/include/gnunet_common.h, src/include/gnunet_dnsparser_lib.h, src/include/gnunet_tun_lib.h: LRN: Enforce GCC bitfield layout for some structs on W32 2012-02-29 11:11 wachs * [r20142] src/include/gnunet_namestore_plugin.h, src/include/gnunet_namestore_service.h, src/namestore/gnunet-service-namestore.c, src/namestore/namestore_api.c, src/namestore/plugin_namestore_sqlite.c, src/namestore/test_namestore_api_lookup.c: nametore api change 2012-02-29 08:59 szengel * [r20135] src/arm/arm.h, src/arm/arm_api.c, src/arm/gnunet-arm.c, src/arm/gnunet-service-arm.c, src/include/gnunet_arm_service.h, src/include/gnunet_protocols.h: Adding arm list/info feature. 2012-02-28 19:08 grothoff * [r20127] src/include/gnunet_crypto_lib.h, src/util/crypto_rsa.c, src/vpn/test_gnunet_vpn.c: adding GNUNET_CRYPTO_setup_hostkey to setup a hostkey ahead of time, using this function in the VPN testcases to avoid timeouts in cases where creating a hostkey just takes too long --- such as on our UltraSprac 2012-02-28 17:29 grothoff * [r20121] src/util/os_priority.c: LRN: Apparently cleanup is not for W32 2012-02-28 17:28 grothoff * [r20120] po/de.po, po/es.po, po/sv.po, po/vi.po, po/zh_CN.po, src/util/os_priority.c: LRN: W32 pipe name generation needs random 2012-02-28 10:54 grothoff * [r20112] po/de.po, po/es.po, po/sv.po, po/vi.po, po/zh_CN.po: releasing GNUnet 0.9.2 2012-02-28 09:32 grothoff * [r20097] configure.ac, src/Makefile.am: add gns 2012-02-28 09:08 schanzen * [r20093] src/gns/plugin_block_gns.c: -fix 2012-02-27 20:00 wachs * [r20087] configure.ac: enabling libglpk detection 2012-02-27 11:00 grothoff * [r20060] src/arm/arm_api.c, src/arm/do_start_process.c, src/arm/gnunet-service-arm.c, src/ats/test_ats_api_bandwidth_consumption.c, src/ats/test_ats_api_scheduling.c, src/chat/test_chat.c, src/chat/test_chat_private.c, src/core/test_core_api.c, src/core/test_core_api_reliability.c, src/core/test_core_api_send_to_self.c, src/core/test_core_api_start_only.c, src/core/test_core_defaults.conf, src/core/test_core_quota_compliance.c, src/datastore/perf_datastore_api.c, src/datastore/test_datastore_api.c, src/datastore/test_datastore_api_management.c, src/datastore/test_defaults.conf, src/dht/test_dht_api.c, src/fs/test_fs_defaults.conf, src/fs/test_fs_download.c, src/fs/test_fs_download_indexed.c, src/fs/test_fs_download_persistence.c, src/fs/test_fs_list_indexed.c, src/fs/test_fs_namespace.c, src/fs/test_fs_namespace_list_updateable.c, src/fs/test_fs_publish.c, src/fs/test_fs_publish_persistence.c, src/fs/test_fs_search.c, src/fs/test_fs_search_persistence.c, src/fs/test_fs_start_stop.c, src/fs/test_fs_unindex.c, src/fs/test_fs_unindex_persistence.c, src/hostlist/test_gnunet_daemon_hostlist.c, src/hostlist/test_gnunet_daemon_hostlist_learning.c, src/hostlist/test_gnunet_daemon_hostlist_reconnect.c, src/hostlist/test_hostlist_defaults.conf, src/include/gnunet_disk_lib.h, src/include/gnunet_os_lib.h, src/include/platform.h, src/mesh/test_mesh_api.c, src/mesh/test_mesh_local_1.c, src/mesh/test_mesh_local_2.c, src/namestore/test_namestore_api.c, src/nat/nat.c, src/nat/nat_mini.c, src/nat/test_nat_test.c, src/nse/test_nse_api.c, src/peerinfo/test_peerinfo_api.c, src/statistics/test_statistics_api.c, src/statistics/test_statistics_api_loop.c, src/statistics/test_statistics_api_watch.c, src/stream/test_stream_local.c, src/stream/test_stream_local_halfclose.c, src/testing/test_testing_defaults.conf, src/testing/testing.c, src/testing/testing_group.c, src/transport/gnunet-transport-certificate-creation.c, src/transport/gnunet-transport-connect-running-peers.c, src/transport/gnunet-transport.c, src/transport/plugin_transport_http_server.c, src/transport/plugin_transport_wlan.c, src/transport/transport-testing.c, src/util/crypto_random.c, src/util/disk.c, src/util/helper.c, src/util/os_priority.c, src/util/scheduler.c, src/util/test_common_logging_runtime_loglevels.c, src/util/test_os_start_process.c, src/util/test_resolver_api.c, src/util/test_strings.c, src/vpn/test_gnunet_vpn.c: enabling use of pipes for signal communication also on UNIX to enable future integration with Java services 2012-02-27 10:54 wachs * [r20059] src/transport/test_transport_api.c: adding error messages 2012-02-25 19:08 grothoff * [r20026] doc/man/gnunet-directory.1, doc/man/gnunet-download.1, doc/man/gnunet-nat-server.1, doc/man/gnunet-pseudonym.1, doc/man/gnunet-publish.1, doc/man/gnunet-search.1, doc/man/gnunet-vpn.1: Igor/CG: various minor updates to man pages 2012-02-24 06:54 grothoff * [r19998] src/include/winproc.h, src/util/os_network.c: bratao/LRN: Use-bigger-buffer-for-EnumNICs3_results 2012-02-23 18:09 wachs * [r19993] src/transport/gnunet-service-transport_validation.c: not an error: plugin can return NULL (e.g. for IPv6 address when does not support IPv6) 2012-02-23 18:08 wachs * [r19992] src/transport/plugin_transport_unix.c: improved rescheduling improved recv error handling 2012-02-23 17:35 wachs * [r19983] src/transport/plugin_transport_udp.c, src/transport/plugin_transport_udp.h: splitted ipv4 and ipv6 socket select scheduling removed looping for write select improved ipv4/v6 en/disabling session management 2012-02-23 16:41 grothoff * [r19979] AUTHORS, src/include/gnunet_common.h, src/include/gnunet_crypto_lib.h, src/include/gnunet_server_lib.h, src/util/common_logging.c, src/util/crypto_hash.c, src/util/server.c: TG: attached are the following patches for GNUnet: - 1: added GNUNET_i2s_full - full variant of GNUNET_i2s - 2: GNUNET_CRYPTO_hash_from_string2 with additional length parameter, useful to prevent an additional strlen call when the caller already knows the length - 3: custom mst callbacks for the server, enables using the server with a custom parser - 4: added GNUNET_SERVER_client_set_finish_pending_write - enables changing the server behavior to finish pending writes when closing the connection Best regards, Gabor Adam Toth 2012-02-23 16:01 wachs * [r19975] src/transport/plugin_transport_unix.c: fix to the 100% CPU load problem 2012-02-23 15:34 wachs * [r19974] src/transport/gnunet-service-transport_neighbours.c: fix: ats suggested address for unknown plugin 2012-02-23 14:40 wachs * [r19968] src/ats/Makefile.am, src/ats/gnunet-service-ats_addresses_mlp.c, src/ats/gnunet-service-ats_addresses_mlp.h, src/ats/test_ats_api.conf, src/ats/test_ats_mlp.c: averaging fast changing quality values 2012-02-23 10:28 wachs * [r19962] src/transport/plugin_transport_udp.c: fix for mantis bug 0002154: change order of calls: - discard unsend messages - call transmit send continuation - call session_end 2012-02-23 10:18 wachs * [r19961] src/transport/plugin_transport_udp.c: fix to use correct queue 2012-02-22 18:34 grothoff * [r19949] src/fs/fs_api.c, src/fs/fs_dirmetascan.c, src/fs/fs_file_information.c, src/fs/fs_publish.c, src/fs/fs_sharetree.c, src/fs/gnunet-helper-fs-publish.c, src/fs/gnunet-publish.c: LRN: two directory patches change the way "is_directory" is evaluated. Now it must be GNUNET_YES for the execution flow to switch to a branch where something is considered to be a directory. The reason for that is that some functions might return GNUNET_SYSERR when asked whether something is a directory or not. Checking this value as "!= GNUNET_NO" will produce positive result, even though it's not a directory. 2012-02-22 12:43 wachs * [r19932] src/transport/gnunet-service-transport_validation.c: fix coverity 10138 2012-02-22 10:10 harsha * [r19915] src/stream/stream_api.c: added ack sending 2012-02-21 19:08 grothoff * [r19906] src/util/os_priority.c: LRN: Escape-trailing-slash-when-spawning-W32-process: 2012-02-21 10:12 schanzen * [r19881] src/gns/gnunet-service-gns.c, src/gns/namestore_stub_api.c: Better logging modified ns stub 2012-02-20 14:28 schanzen * [r19868] src/gns/Makefile.am, src/gns/gns_api.c, src/gns/gnunet-service-gns.c, src/gns/namestore_stub_api.c, src/include/gnunet_gns_service.h, src/include/gnunet_namestore_service.h: namestore stub api added fixes to namestore api 2012-02-20 12:08 grothoff * [r19864] src/fs/gnunet-helper-fs-publish.c: LRN: Do-partial-serialization-in-fs-publish-helper: 2012-02-20 09:09 grothoff * [r19859] src/fs/fs_sharetree.c: LRN: Iterate-over-a-copy-of-ksk-when-removing-items 2012-02-20 09:09 grothoff * [r19858] src/fs/gnunet-service-fs_put.c: LRN: check for tc being NULL 2012-02-18 19:03 grothoff * [r19844] src/fs/Makefile.am, src/fs/fs_api.h, src/fs/fs_list_indexed.c, src/fs/fs_namespace.c, src/fs/fs_namespace_advertise.c, src/fs/fs_publish.c, src/fs/fs_publish_ksk.c, src/fs/fs_tree.c, src/fs/gnunet-fs.c, src/fs/gnunet-publish.c, src/include/gnunet_fs_service.h: make all (?) asynchronously operating FS operations actually cancel-able 2012-02-18 15:16 grothoff * [r19837] src/fs/fs_namespace.c, src/include/gnunet_fs_service.h: add GNUNET_FS_namespace_dup API call 2012-02-18 13:50 grothoff * [r19836] src/util/disk.c: LRN: don't free memory on the stack 2012-02-16 14:29 wachs * [r19820] src/transport/gnunet-service-transport_neighbours.c: fix for fast reconnect: send ack after fast reconnect even when we are already connected since other peer waits for it 2012-02-16 14:28 wachs * [r19819] src/transport/test_transport_api_restart_1peer.c: fix test for peer restart 2012-02-16 12:58 grothoff * [r19817] src/fs/gnunet-helper-fs-publish.c: LRN: Use binary mode on W32 (lol -CG) 2012-02-15 13:39 schanzen * [r19812] src/gns/gns_api.c, src/gns/gnunet-gns-add.c, src/gns/gnunet-gns-lookup.c, src/gns/gnunet-service-gns.c, src/include/gnunet_gns_service.h: Added preliminary API and stubs for GNS 2012-02-15 09:49 wachs * [r19811] src/transport/gnunet-service-transport_neighbours.c: fix for Assertion failed at gnunet-service-ats_addresses.c:587 2012-02-13 16:36 wachs * [r19795] src/include/gnunet_transport_plugin.h: changes in includes 2012-02-13 16:02 wachs * [r19791] src/transport/gnunet-service-transport_neighbours.c, src/transport/gnunet-service-transport_validation.c, src/transport/plugin_transport_http.c, src/transport/plugin_transport_tcp.c, src/transport/plugin_transport_template.c, src/transport/plugin_transport_udp.c, src/transport/plugin_transport_unix.c, src/transport/plugin_transport_wlan.c: removing legacy send functions from plugins and renaming new send function 2012-02-13 15:38 wachs * [r19790] src/transport/gnunet-service-transport_validation.c, src/transport/plugin_transport_http.h: new sending in validation 2012-02-13 13:27 wachs * [r19777] src/transport/plugin_transport_tcp.c: fix access before null check 2012-02-13 12:22 wachs * [r19775] src/transport/gnunet-service-transport_neighbours.c: removing old send code from neighbours 2012-02-13 11:57 wachs * [r19771] src/transport/Makefile.am, src/transport/gnunet-service-transport_neighbours.c, src/transport/plugin_transport_udp.c, src/transport/plugin_transport_udp.h, src/transport/plugin_transport_udp_broadcasting.c, src/transport/plugin_transport_udp_new.h, src/transport/plugin_transport_udp_new_broadcasting.c: adding rewritten udp plugin 2012-02-13 10:58 wachs * [r19770] src/ats/gnunet-service-ats_math.c, src/ats/gnunet-service-ats_math.h: removing backup ATS code 2012-02-08 15:23 bartpolot * [r19733] src/mesh/gnunet-service-mesh.c, src/mesh/mesh_api.c, src/mesh/test_mesh_small.c: Attemp to fix ctrl-c crashes - disconnect from services before calling daemons_stop, since the cfg is free'd in the latter. 2012-02-06 09:34 grothoff * [r19707] doc/man/gnunet-transport.1, src/transport/gnunet-transport.c: adding -m option to gnunet-transport to enable monitor mode (see #1972) 2012-02-01 17:37 bartpolot * [r19608] src/include/gnunet_common.h: Let the compiler not include debug strings in binary when make is not configured with verbose 2012-02-01 17:08 wachs * [r19603] src/transport/Makefile.am, src/transport/gnunet-service-transport_blacklist.c, src/transport/test_transport_api_blacklisting.c, src/transport/transport_api_blacklist.c: fixing and testing blacklisting api and service 2012-02-01 15:00 wachs * [r19598] src/transport/test_transport_api_blacklisting.c: improved blacklisting test 2012-02-01 14:59 wachs * [r19597] src/transport/transport_api_blacklist.c: fix 2 crashes in blacklisting api - client transmit handle was not sent to NULL after sending - BlacklistMessage was not checked for NULL 2012-02-01 13:26 wachs * [r19596] src/transport/transport_api_blacklist.c: fix segfault: api never saved callback and callback_cls 2012-02-01 09:04 wachs * [r19591] src/transport/gnunet-service-transport_blacklist.c: added assertion (which is successfully failing ;-) ) 2012-01-31 13:46 wachs * [r19571] src/transport/plugin_transport_wlan.c: session based sending for wlan 2012-01-31 13:12 wachs * [r19568] src/util/os_network.c: ifconfig parsing Shum's patch bugs fixed in patch: - IPv4 loopback address was not included: added line 179 - stack allocated strings were not zeroed out, so last value was used if value was not included in current line - IPv4 netmask was passed as broadcast address (patch line 81) - IPv4 netmask was passed as IPv6 netmask, caused invalid address conversion (patch line 113) 2012-01-31 13:04 wachs * [r19567] src/util/test_os_network.c: adding verbose message 2012-01-31 08:25 wachs * [r19563] src/ats/ats_api_scheduling.c, src/hello/address.c, src/include/gnunet_ats_service.h: fixing const api and add check to address 2012-01-31 08:19 wachs * [r19562] src/transport/test_transport_api.c: fix assertion 2012-01-30 16:38 wachs * [r19543] src/transport/test_transport_api.c: variable message size 2012-01-27 15:51 wachs * [r19486] src/transport/plugin_transport_unix.c: implemented sessions 2012-01-27 14:30 wachs * [r19485] src/transport/plugin_transport_unix.c: removing retry code removing unused structs removing UDP Address structs fixed PrettyPrinter (printed UDP addresses???) 2012-01-27 13:48 wachs * [r19484] src/transport/plugin_transport_unix.c: complete select write implementation 2012-01-27 13:21 wachs * [r19483] src/transport/test_transport_api.c: fix memory leaks 2012-01-26 14:53 wachs * [r19440] src/transport/gnunet-service-transport_neighbours.c: fixing mantis 2101 2012-01-26 14:09 wachs * [r19437] src/transport/gnunet-service-transport_neighbours.c, src/transport/plugin_transport_http.c, src/transport/plugin_transport_http_server.c: implemented session based sending in transport service (coexisting with old code) 2012-01-26 14:01 bartpolot * [r19436] src/mesh/gnunet-service-mesh.c: Workaround for #2104, initialize local tid when local type destination connects after tunnel connect request by origin 2012-01-26 13:23 wachs * [r19435] src/ats/ats_api.c, src/ats/gnunet-service-ats_addresses_mlp.c: cppcheck 2012-01-25 14:22 wachs * [r19389] src/ats/gnunet-service-ats_scheduling.c: clang: mem access if plugin_name_length == 0 2012-01-25 13:56 wachs * [r19387] src/transport/plugin_transport_tcp.c: coverity 10054 2012-01-25 13:55 wachs * [r19386] src/transport/plugin_transport_http_client.c: coverity 10048 2012-01-24 20:28 grothoff * [r19359] src/vpn: ign 2012-01-24 01:32 bartpolot * [r19334] src/mesh/gnunet-service-mesh.c: Changed incoming tunnel notification to delay until relvant traffic is received from remote peer. Allowed several remote clients for each tunnel. 2012-01-23 15:45 wachs * [r19331] src/ats/gnunet-service-ats_addresses.c: fixing mantis 2098: ats did not lookup addresses correctly ats overwrote existing session when updating addresses 2012-01-23 15:43 wachs * [r19330] src/transport/gnunet-service-transport_neighbours.c: fixing: mantis 0002098: transport did not propagate session to ats 2012-01-23 14:54 grothoff * [r19329] src/include/gnunet_common.h: use noreturn macro for GNUNET_abort to help gcc and others 2012-01-23 09:14 grothoff * [r19322] src/util/win.cc: It-might-be-NULL 2012-01-20 15:41 bartpolot * [r19283] src/include/gnunet_mesh_service.h: Reflected changes in r19282. 2012-01-20 15:40 bartpolot * [r19282] src/mesh/mesh_api.c: Don't call cleaner on tunnels explicity destroyed. Updated and improved documentation. 2012-01-20 12:49 bartpolot * [r19280] src/mesh/gnunet-service-mesh.c: Fixed bug with remote tunnel traffic reception 2012-01-20 12:48 bartpolot * [r19279] src/mesh/mesh_api.c: Added more debug info 2012-01-19 23:17 bartpolot * [r19274] src/mesh/gnunet-service-mesh.c: Added TTL and MID initialization to tunnel refresh packets. 2012-01-19 23:00 bartpolot * [r19273] src/mesh/gnunet-service-mesh.c: Fixed #2088, don't call receive_done on traffic not generated by client. Improved debug output. 2012-01-19 22:39 bartpolot * [r19272] src/mesh/gnunet-service-mesh.c: Fixed #2087, wrong local tunnel number sent when multiple clients are subscribed to one type message on same peer and one clientis owner of the tunnel and the other is target 2012-01-19 22:13 bartpolot * [r19271] src/mesh/mesh_api.c: Fixed a memory leak on disconnect, double peer_rc decrease on tunnel destroy, adjusted backoff, completed doxygen 2012-01-19 15:20 bartpolot * [r19260] src/mesh/gnunet-service-mesh.c: Fixed client disconnect bug, delimited debug messages. 2012-01-19 14:33 bartpolot * [r19258] src/mesh/mesh_api.c: Fixed a peer_rc bug. 2012-01-19 11:06 bartpolot * [r19253] src/mesh/gnunet-service-mesh.c: Fixed an assert error when a client disconnects with open tunnels and without doing MESH_disconnect 2012-01-19 10:58 bartpolot * [r19252] src/mesh/mesh_api.c: Improved debug message 2012-01-18 19:28 grothoff * [r19248] src/include/gnunet_testing_lib.h, src/testing/Makefile.am, src/testing/helper.c: implementing GNUNET_TESTING_get_peer_identity (addressing #2083) 2012-01-18 15:10 bartpolot * [r19244] src/mesh/gnunet-service-mesh.c: Fixed client shutdown case, various minor fixes 2012-01-18 12:47 bartpolot * [r19233] src/mesh/gnunet-service-mesh.c: Implemented workaround for #2071 2012-01-18 11:27 bartpolot * [r19228] src/mesh/gnunet-service-mesh.c: Allowed client to send again 2012-01-18 11:17 bartpolot * [r19227] src/mesh/gnunet-service-mesh.c: Fixed a bug when a multicast packet is delivered exclusively to local clients 2012-01-17 19:45 bartpolot * [r19217] src/mesh/mesh_api.c: Added debug info for #2071 2012-01-17 17:29 bartpolot * [r19208] src/mesh/gnunet-service-mesh.c: Fixed #2070 and simplified data transmission unicast/multicast handling 2012-01-17 16:17 bartpolot * [r19206] src/mesh/gnunet-service-mesh.c: Temporal workaround for #2070 2012-01-17 16:13 bartpolot * [r19204] src/mesh/gnunet-service-mesh.c: Temporl workaround for #2070 2012-01-17 15:36 bartpolot * [r19196] src/mesh/mesh_api.c: Fixed queue bug 2012-01-16 21:11 grothoff * [r19181] src/pt/gnunet-daemon-pt.c: implemented new protocol translation daemon (#2063) 2012-01-16 17:17 harsha * [r19176] src/stream/test_stream_local.c, src/stream/test_stream_local_halfclose.c: refined test cases 2012-01-15 23:40 grothoff * [r19169] doc/man/Makefile.am, doc/man/gnunet-download-manager.1, src/fs/Makefile.am, src/fs/gnunet-download-manager.scm: adding Ludo's gnunet-download-manager.scm back to SVN HEAD 2012-01-14 23:18 grothoff * [r19146] src/arm/gnunet-service-arm.c, src/fs/fs_dirmetascan.c, src/include/gnunet_disk_lib.h, src/nat/nat.c, src/nat/nat_mini.c, src/testing/testing.c, src/transport/plugin_transport_wlan.c, src/util/disk.c, src/util/helper.c, src/util/os_priority.c, src/util/scheduler.c, src/util/test_common_logging_runtime_loglevels.c, src/util/test_os_start_process.c, src/util/test_scheduler.c: LRN: enable more fine-grained control over blocking/non-blocking pipe operation 2012-01-14 20:58 grothoff * [r19141] src/exit/exit.conf, src/exit/gnunet-daemon-exit.c, src/exit/gnunet-helper-exit.c: changing exit helper code to automatically do the network configuration for an exit node (by running sysctl/iptables commands as necessary) 2012-01-14 15:24 grothoff * [r19135] src/fs/Makefile.am, src/include/gnunet_fs_service.h: LRN: new threaded directory metadata scanner 2012-01-14 15:20 grothoff * [r19134] src/fs/fs_uri.c: LRN: skip short keywords when generating keywords automatically from metadata 2012-01-14 15:20 grothoff * [r19133] src/include/gnunet_disk_lib.h, src/util/disk.c: LRN: new pipe creation function GNUNET_DISK_pipe_from_fd to wrap existing file descriptor pair 2012-01-14 15:17 grothoff * [r19131] src/include/gnunet_strings_lib.h, src/util/strings.c: LRN: add function GNUNET_STRINGS_get_short_name to get basename 2012-01-13 22:14 harsha * [r19130] src/stream/test_stream_local.c: added half-closed shutdown test 2012-01-13 22:10 grothoff * [r19129] configure.ac, src/dht/dht.conf.in, src/dns/Makefile.am, src/dns/dns.conf.in, src/dv/dv.conf.in, src/transport/transport.conf.in, src/util/service.c, src/vpn/vpn.conf.in: improving code and build system to be in line with gnunet access control model for services as described at https://gnunet.org/gnunet-access-control-model 2012-01-13 21:33 harsha * [r19128] src/stream/test_stream_local.c: added shutdown call in testcase 2012-01-13 21:33 harsha * [r19127] src/include/gnunet_stream_lib.h: removed ambigious description 2012-01-13 18:10 harsha * [r19126] src/stream/stream_protocol.h, src/stream/test_stream_local.c, src/stream/test_stream_local.conf: test case for stream API 2012-01-13 17:41 harsha * [r19125] src/include/gnunet_stream_lib.h: generic type for read data 2012-01-13 17:04 grothoff * [r19123] configure.ac, src/arm/Makefile.am, src/arm/arm.conf, src/arm/arm.conf.in, src/ats/Makefile.am, src/ats/ats.conf, src/ats/ats.conf.in, src/chat/Makefile.am, src/chat/chat.conf, src/chat/chat.conf.in, src/core/Makefile.am, src/core/core.conf, src/core/core.conf.in, src/datastore/Makefile.am, src/datastore/datastore.conf, src/datastore/datastore.conf.in, src/dht/Makefile.am, src/dht/dht.conf, src/dht/dht.conf.in, src/dns/Makefile.am, src/dns/dns.conf, src/dns/dns.conf.in, src/dv/Makefile.am, src/dv/dv.conf, src/dv/dv.conf.in, src/exit/exit.conf, src/fs/Makefile.am, src/fs/fs.conf, src/fs/fs.conf.in, src/mesh/Makefile.am, src/mesh/mesh.conf, src/mesh/mesh.conf.in, src/nse/Makefile.am, src/nse/nse.conf, src/nse/nse.conf.in, src/peerinfo/Makefile.am, src/peerinfo/peerinfo.conf, src/peerinfo/peerinfo.conf.in, src/statistics/Makefile.am, src/statistics/statistics.conf, src/statistics/statistics.conf.in, src/transport/Makefile.am, src/transport/transport.conf, src/transport/transport.conf.in, src/util/Makefile.am, src/util/client.c, src/util/resolver.conf, src/util/resolver.conf.in, src/vpn/Makefile.am, src/vpn/vpn.conf, src/vpn/vpn.conf.in: change default configurations on systems with UNIX domain sockets to NOT specify any port for TCP-based IPC (and interpret that as no TCP-based IPC desired), as we can and want to use UNIX domain sockets in this case by default 2012-01-12 09:26 wachs * [r19101] src/vpn/gnunet-service-vpn.c: fix compile errors 2012-01-11 21:11 grothoff * [r19093] src/fs/fs_api.c, src/fs/fs_api.h, src/fs/fs_publish.c: fixing bug to ensure that we properly descend into deep directories for the various publish start/stop/suspend/resume event callbacks 2012-01-11 13:18 wachs * [r19085] src/ats/ats.conf, src/ats/gnunet-service-ats_addresses.c: mlp configuration 2012-01-11 12:41 wachs * [r19084] src/ats/Makefile.am: adding glpk to the makefile 2012-01-10 23:18 harsha * [r19082] src/stream/stream_protocol.h: stream P2P protocol message specification 2012-01-10 16:06 wachs * [r19078] src/vpn/vpn.conf: fix: wrong binary and duplicate unix path 2012-01-10 15:54 wachs * [r19077] src/integration-tests/confs/c_bootstrap_server.conf, src/integration-tests/confs/c_nat_client.conf, src/integration-tests/confs/c_no_nat_client.conf: added section to solve vpn conflicts 2012-01-09 16:38 grothoff * [r19069] src/include/gnunet_disk_lib.h, src/util/disk.c: LRN: make disk iterator start return GNUNET_SYSERR if run on empty directory 2012-01-05 21:04 grothoff * [r19023] src/exit/Makefile.am: fix 2012-01-05 20:58 bartpolot * [r19021] src/dht, src/dht/Makefile.am, src/dht/dht_api.c, src/dht/test_dht_monitor.c: Added testcase for DHT monitoring. 2012-01-05 20:18 grothoff * [r19017] src/include/gnunet_crypto_lib.h, src/util/crypto_crc.c: fix crc16 prototypes 2012-01-04 20:00 bartpolot * [r18989] src/dht/dht.h, src/dht/dht_api.c, src/dht/gnunet-service-dht_clients.c, src/dht/gnunet-service-dht_clients.h, src/dht/gnunet-service-dht_neighbours.c, src/include/gnunet_dht_service.h, src/include/gnunet_protocols.h: New DHT-monitor functionality 2012-01-04 15:48 grothoff * [r18988] doc/man/Makefile.am, doc/man/gnunet-monkey.1: move monkey man page to monkey 2012-01-04 14:20 grothoff * [r18982] src/dns/dnsparser.c, src/dns/gnunet-dns-monitor.c, src/dns/gnunet-service-dns_new.c: adding missing file 2012-01-02 12:23 grothoff * [r18937] src/dns/Makefile.am, src/dns/gnunet-helper-dns.c: DNS helper for DNS redesign 2012-01-02 10:22 grothoff * [r18929] src/include/gnunet_crypto_lib.h, src/util/crypto_crc.c: adding crc16 to gnunet_crypto_lib.h 2012-01-02 09:26 grothoff * [r18924] src/include/Makefile.am, src/include/gnunet_helper_lib.h, src/util/Makefile.am, src/util/helper.c: adding new GNUNET_HELPER_ API for communication with (SUID) helper binaries via stdin/stdout using standard GNUNET messages 2012-01-02 08:24 grothoff * [r18923] src/include/gnunet_os_lib.h, src/util/os_priority.c: adding GNUNET_OS_start_process_vap function 2012-01-02 03:51 grothoff * [r18912] src/dns/gnunet-helper-hijack-dns.c: dns hijacker code review 2012-01-01 23:39 grothoff * [r18908] src/dns/Makefile.am, src/dns/dns_api.c, src/include/gnunet_dns_service.h, src/vpn/Makefile.am, src/vpn/gnunet-daemon-vpn-dns.c, src/vpn/gnunet-daemon-vpn-dns.h, src/vpn/gnunet-daemon-vpn-helper.c, src/vpn/gnunet-daemon-vpn.c, src/vpn/gnunet-daemon-vpn.h: first quick hack to extract an initial DNS service API 2012-01-01 21:12 grothoff * [r18889] src/arm/gnunet-service-arm.c, src/chat/gnunet-chat.c, src/datastore/gnunet-service-datastore.c, src/fs/fs_api.c, src/fs/gnunet-service-fs_cp.c, src/include/gnunet_scheduler_lib.h, src/nse/gnunet-service-nse.c, src/peerinfo/gnunet-service-peerinfo.c, src/util/crypto_hash.c, src/util/scheduler.c: changing scheduler priorities to revert to DEFAULT instead of inheriting parent-task priority unless something else is explicitly specified 2011-12-30 22:25 grothoff * [r18853] src/fs/Makefile.am, src/fs/fs_uri.c: LRN: normalize keywords (decapitalize, split) using libunistring - #2052 2011-12-26 19:31 grothoff * [r18828] src/fs/fs_misc.c, src/include/gnunet_fs_service.h, src/util/os_network.c: adding GNUNET_FS_time_to_year function to FS API 2011-12-25 20:45 grothoff * [r18815] src/fs/gnunet-service-fs_cp.h, src/fs/gnunet-service-fs_pr.c: fixing migration stop delay calculation, largely by first calculating datastore load correctly and then by better distinguishing between datastore full, datastore timeout and success and finally by adding per-peer tracking of the current block interval to adjust to repeated undesireable behavior. See #2029. 2011-12-23 20:13 wachs * [r18794] src/ats/Makefile.am: missing file 2011-12-22 14:15 wachs * [r18756] src/transport/gnunet-transport.c: include plugin in gnunet-transport output 2011-12-21 18:03 bartpolot * [r18754] src/nse/gnunet-nse-profiler.c, src/nse/gnunet-service-nse.c: Added statistic reading to NSE, fixed some minor bugs 2011-12-21 16:39 wachs * [r18751] src/vpn/gnunet-helper-vpn.c: fix compile error 2011-12-21 14:33 wachs * [r18742] src/transport/plugin_transport_http.c: fixed assertion in gnunet-service resolver improved address printing for IPv6 addresses, especially if reverse lookup is not successful 2011-12-21 12:39 wachs * [r18735] src/transport/plugin_transport_udp.c: fixed assertion: wrong return value 2011-12-21 09:56 grothoff * [r18732] contrib/report.sh: add version reporting for MHD to report.sh 2011-12-21 09:40 grothoff * [r18730] src/arm/arm.h, src/ats-test/test_transport_ats_multiple_peers.c, src/ats/ats.h, src/chat/chat.h, src/core/core.h, src/core/gnunet-service-core_kx.c, src/datastore/datastore.h, src/dht/dht.h, src/dht/gnunet-service-dht_neighbours.c, src/dv/dv.h, src/dv/test_transport_api_dv.c, src/fragmentation/fragmentation.h, src/fs/fs.h, src/fs/gnunet-service-fs.h, src/hello/hello.c, src/hostlist/gnunet-daemon-hostlist.c, src/include/block_dns.h, src/include/block_fs.h, src/include/gnunet_ats_service.h, src/include/gnunet_bandwidth_lib.h, src/include/gnunet_common.h, src/include/gnunet_crypto_lib.h, src/include/gnunet_time_lib.h, src/mesh/mesh.h, src/mesh/mesh_protocol.h, src/nat/nat.h, src/nse/gnunet-service-nse.c, src/nse/nse.h, src/peerinfo/peerinfo.h, src/statistics/statistics.h, src/testing/test_testing_large_topology.c, src/testing/test_testing_topology.c, src/testing/test_testing_topology_blacklist.c, src/testing/test_testing_topology_churn.c, src/transport/gnunet-helper-transport-wlan.c, src/transport/gnunet-service-transport_neighbours.c, src/transport/gnunet-service-transport_validation.c, src/transport/gnunet-transport-wlan-sender.c, src/transport/plugin_transport_http.h, src/transport/plugin_transport_smtp.c, src/transport/plugin_transport_tcp.c, src/transport/plugin_transport_udp.c, src/transport/plugin_transport_udp_new.c, src/transport/plugin_transport_unix.c, src/transport/plugin_transport_wlan.c, src/transport/plugin_transport_wlan.h, src/transport/test_quota_compliance.c, src/transport/test_transport_api_reliability.c, src/transport/test_transport_api_unreliability.c, src/transport/test_transport_api_unreliability_constant.c, src/transport/transport.h, src/util/crypto_ksk.c, src/util/crypto_rsa.c, src/util/resolver.h, src/vpn/gnunet-service-dns-p.h, src/vpn/gnunet-service-dns.c, src/vpn/gnunet-vpn-packet.h: fixing 2012: network structure alignment now forced to be correct even on W32 using #pragma pack from gcc 4.x 2011-12-20 16:41 wachs * [r18726] src/transport/gnunet-service-transport_neighbours.c: fix for mantis 1959 compare addresses and only mark address when addresses match 2011-12-20 16:01 wachs * [r18723] src/transport/gnunet-service-transport_clients.c: fix for mantis #2008 2011-12-20 15:48 wachs * [r18722] src/transport/transport_api.c: Improvement in reconnect: first disconnect, then destroy neighbours 2011-12-20 12:58 wachs * [r18719] src/include/gnunet_transport_plugin.h, src/transport/plugin_transport_tcp.c: first changes for new plugin api 2011-12-20 09:20 grothoff * [r18714] AUTHORS, configure.ac, src/dht/test_dht_2dtorus.conf: Adding optional compiler and linker hardening options as per suggestion from Jacob 2011-12-19 23:24 grothoff * [r18710] src/dht/test_dht_2dtorus.conf: do not run with full on NSE during testing 2011-12-19 21:26 grothoff * [r18704] src/include/gnunet_statistics_service.h, src/statistics/statistics_api.c: implement watch_cancel function 2011-12-19 17:15 grothoff * [r18698] src/fs/fs_api.c, src/fs/fs_api.h, src/fs/fs_search.c: improving results seen communication to consider which exact keywords a particular result has been seen for so far 2011-12-19 17:10 wachs * [r18697] src/integration-tests/Makefile.am, src/integration-tests/gnunet_testing.py.in, src/integration-tests/test_integration_disconnect.py.in: a new nat disconnect test 2011-12-19 16:31 grothoff * [r18696] src/transport/gnunet-service-transport_neighbours.c: fixing #2014 2011-12-19 15:59 grothoff * [r18693] src/fs/gnunet-service-fs_pr.c: limit lifetime of migrated content to at most 1 year 2011-12-19 15:52 grothoff * [r18692] src/fs/gnunet-service-fs_cp.c, src/fs/gnunet-service-fs_cp.h, src/fs/gnunet-service-fs_pr.c: block data migration based on lowest discarded expiration of content in the datastore to avoid wasting bandwidth on migrating content that is just instantly discarded again anyway 2011-12-19 15:02 wachs * [r18691] src/integration-tests/test_integration_clique.py.in, src/integration-tests/test_integration_disconnect.py.in, src/integration-tests/test_integration_restart.py.in: fixing some timeouts 2011-12-19 14:26 wachs * [r18690] src/ats/ats_api_scheduling.c: 2011-12-19 14:25 wachs * [r18689] src/ats/ats_api_scheduling.c, src/transport/gnunet-service-transport_neighbours.c: fixes for mantis #1988 and cleanup 2011-12-19 14:10 grothoff * [r18688] src/fs/gnunet-service-fs_cp.c, src/fs/gnunet-service-fs_pr.c, src/fs/gnunet-service-fs_pr.h: actually limit FS memory consumption by limiting how many requests we track from other peers (respective GSF-option had not been set; new code also inverts the meaning of the bit, so it does not have to be set for peers but rather is now set for clients to excempt them from the limitation) 2011-12-19 13:54 grothoff * [r18686] src/datastore/datastore.h, src/datastore/datastore_api.c, src/datastore/perf_datastore_api.c, src/datastore/test_datastore_api.c, src/datastore/test_datastore_api_management.c, src/fs/fs_namespace.c, src/fs/fs_publish.c, src/fs/fs_unindex.c, src/fs/gnunet-service-fs_indexing.c, src/fs/gnunet-service-fs_pr.c, src/include/gnunet_datastore_service.h: adding min_expiration argument to GNUNET_DATASTORE_ContinuationWithStatus callback to communicate which content has a chance of being stored in the medium term 2011-12-19 13:08 wachs * [r18684] src/hostlist/test_gnunet_daemon_hostlist.c: added LRN's patch from mantis bug 1998 2011-12-19 12:12 wachs * [r18682] src/include/gnunet_ats_service.h, src/transport/plugin_transport_wlan.c: additional network type for WLAN 2011-12-19 12:08 wachs * [r18681] src/ats/ats_api_scheduling.c: checked mantis #0002016 and added additional assertion 2011-12-19 10:59 grothoff * [r18680] src/nat/gnunet-helper-nat-server.c: Jacob Appelbaum reviewed gnunet-helper-nat-server and affirms that the code 'seems fine' 2011-12-19 09:32 grothoff * [r18678] src/datastore/gnunet-service-datastore.c: fixing calculation of Bloom filter size that was too large by 1024x because it was not adjusted when the unit for the quota was changed from kb to bytes 2011-12-17 18:32 grothoff * [r18662] contrib/apparmor, contrib/apparmor/usr.bin.gnunet-helper-nat-server: adding apparmor profile for gnunet-helper-nat-server from Jacob 2011-12-16 22:42 grothoff * [r18653] src/datastore/plugin_datastore_sqlite.c: implementing get_keys API for sqlite datastore plugin (#2013) 2011-12-16 22:19 grothoff * [r18652] src/statistics/statistics_api.c, src/statistics/test_statistics_api_watch.c: code cleanup, also trying to fix #2011 2011-12-16 22:13 grothoff * [r18650] src/nat/gnunet-helper-nat-client.c: really minimizing gnunet-helper-nat-client code running with root rights 2011-12-16 22:04 grothoff * [r18649] src/nat/gnunet-helper-nat-server-windows.c, src/nat/gnunet-helper-nat-server.c: really minimizing code running with root rights 2011-12-16 21:19 grothoff * [r18647] src/util/container_bloomfilter.c: cleaning up bloomfilter code and disk file size tests 2011-12-16 17:15 wachs * [r18635] src/integration-tests/confs/c_nat_client.conf, src/integration-tests/gnunet_testing.py.in, src/integration-tests/test_integration_clique_nat.py.in: 2011-12-16 16:27 wachs * [r18634] src/integration-tests/gnunet_testing.py.in, src/integration-tests/test_integration_clique_nat.py.in: improvements and fixes 2011-12-16 16:12 wachs * [r18633] src/integration-tests/confs/c_nat_client.conf, src/integration-tests/gnunet_testing.py.in, src/integration-tests/test_integration_clique_nat.py.in: fix 2011-12-16 14:49 wachs * [r18632] src/integration-tests/Makefile.am, src/integration-tests/confs/c_nat_client.conf, src/integration-tests/test_integration_clique_nat.py.in: adding nat clique test 2011-12-16 14:03 wachs * [r18631] src/integration-tests/gnunet_testing.py.in: improved statisc output 2011-12-16 13:43 wachs * [r18630] src/integration-tests/test_integration_restart.py.in: new test: connect after peer restart? 2011-12-16 13:43 wachs * [r18629] src/integration-tests/Makefile.am, src/integration-tests/test_integration_bootstrap_and_connect.py.in, src/integration-tests/test_integration_clique.py.in, src/integration-tests/test_integration_disconnect.py.in: 2011-12-16 12:25 wachs * [r18627] src/integration-tests/gnunet_testing.py.in, src/integration-tests/test_integration_bootstrap_and_connect.py.in, src/integration-tests/test_integration_clique.py.in, src/integration-tests/test_integration_disconnect.py.in: added support for interupting a test 2011-12-16 11:19 grothoff * [r18625] src/nat/gnunet-helper-nat-client.c, src/nat/gnunet-helper-nat-server.c: additional stylistic changes to gnunet-helper-nat-client anticipating next round of suggestions from Jacob Applebaum 2011-12-16 11:16 grothoff * [r18624] configure.ac, src/nat/gnunet-helper-nat-server.c: some very minor stylistic changes to gnunet-helper-nat-server based on suggestions from Jacob Applebaum 2011-12-15 17:03 wachs * [r18620] src/integration-tests/gnunet_testing.py.in, src/integration-tests/test_integration_bootstrap_and_connect.py.in, src/integration-tests/test_integration_clique.py.in, src/integration-tests/test_integration_disconnect.py.in: improved tests 2011-12-15 15:56 wachs * [r18617] src/integration-tests/Makefile.am, src/integration-tests/gnunet_testing.py.in, src/integration-tests/test_integration_bootstrap_and_connect.py.in, src/integration-tests/test_integration_clique.py.in: improved test framework 2011-12-15 15:20 wachs * [r18615] src/integration-tests/gnunet_testing.py.in: added improved check management 2011-12-15 14:56 grothoff * [r18614] src/fs/gnunet-service-fs_cp.c, src/fs/gnunet-service-fs_pr.c: use better heuristic to deal with datastore put failures; log migration stop message transmissions 2011-12-15 14:55 grothoff * [r18613] src/datastore/gnunet-service-datastore.c, src/include/gnunet_datastore_plugin.h: adding support for detection quota changes / missing bloomfilter files and reconstruction/recovery code 2011-12-15 14:21 wachs * [r18603] src/integration-tests/gnunet_testing.py.in: peer get automatically stopped 2011-12-15 14:09 wachs * [r18602] src/integration-tests/gnunet_testing.py.in: improved peer management 2011-12-15 12:44 grothoff * [r18601] src/util/container_bloomfilter.c: only try to read bf from disk if we didn't just create the file 2011-12-15 12:41 grothoff * [r18600] src/datastore/datastore.conf: store Bloomfilter with rest of datastore data 2011-12-15 12:40 grothoff * [r18599] src/include/gnunet_disk_lib.h, src/util/container_bloomfilter.c, src/util/disk.c: extra error checking in Bloom filter to check that the size of the file on disk corresponds to the expected size for the given filter 2011-12-15 09:51 wachs * [r18597] README: added python remark to hacking This line, and those below, will be ignored -- M README 2011-12-15 09:46 wachs * [r18596] configure.ac: Python version required to run tests is >= 2.6 2011-12-14 13:32 wachs * [r18590] src/include/gnunet_ats_service.h, src/transport/gnunet-service-transport.c, src/transport/plugin_transport_http.c, src/transport/plugin_transport_udp.c, src/transport/plugin_transport_unix.c: wan/lan detection in plugins 2011-12-14 13:31 wachs * [r18589] src/ats/ats_api_scheduling.c: adding detection for AF_UNIX 2011-12-14 10:25 wachs * [r18588] src/transport/plugin_transport_http.c, src/transport/plugin_transport_http.h, src/transport/plugin_transport_http_server.c, src/transport/plugin_transport_tcp.c: WAN/LAN for HTTP/S 2011-12-14 08:53 wachs * [r18587] src/include/gnunet_transport_plugin.h, src/transport/gnunet-service-transport.c, src/transport/gnunet-service-transport_plugins.c, src/transport/gnunet-service-transport_plugins.h, src/transport/plugin_transport_tcp.c: removing ats functions from plugins, instead provide callback function 2011-12-14 08:52 wachs * [r18586] src/ats/ats_api_scheduling.c: 2011-12-13 16:26 wachs * [r18578] src/include/gnunet_transport_plugin.h: missing 2011-12-13 16:20 wachs * [r18577] src/transport/gnunet-service-transport.c, src/transport/gnunet-service-transport_plugins.c, src/transport/plugin_transport_tcp.c: changes: changed order of startup since ats is now required for plugins transport provides ATS handles for plugins network detection for tcp 2011-12-13 15:19 wachs * [r18576] src/transport/plugin_transport_wlan.c: address type in WLAN 2011-12-13 15:15 wachs * [r18575] src/transport/plugin_transport_unix.c: added ATS addresstype information to unix 2011-12-13 15:13 wachs * [r18574] src/ats/ats_api_scheduling.c, src/ats/gnunet-service-ats_addresses.c: fixing crash 0002007 adding network information to addresses 2011-12-13 15:02 wachs * [r18573] src/util/os_network.c: LRN's patch argument order 2011-12-13 14:36 grothoff * [r18572] src/fs/gnunet-service-fs.c, src/fs/gnunet-service-fs_lc.c, src/fs/gnunet-service-fs_pr.h: trying to fix #2000 2011-12-13 12:31 wachs * [r18566] src/ats/Makefile.am, src/ats/ats_api_scheduling.c, src/ats/gnunet-service-ats_addresses.c, src/ats/gnunet-service-ats_addresses.h, src/include/gnunet_ats_service.h: move code from service to api fix bug add test 2011-12-12 17:11 wachs * [r18562] src/ats/gnunet-service-ats_addresses.c, src/include/gnunet_ats_service.h: WAN/LAN detection Mantis 1991 2011-12-12 13:58 wachs * [r18560] src/ats/gnunet-service-ats_addresses.c, src/ats/gnunet-service-ats_addresses.h: IPv4 check implemented TODO: IPv6 2011-12-12 12:52 wachs * [r18559] src/ats/gnunet-service-ats_addresses.c, src/ats/gnunet-service-ats_addresses.h: WAN/LAN detection 2011-12-12 12:05 wachs * [r18558] src/Makefile.am, src/integration-tests/test_integration_clique.py.in: including integration tests in checks 2011-12-11 15:39 grothoff * [r18556] src/transport, src/transport/Makefile.am, src/transport/gnunet-helper-transport-wlan-dummy.c, src/transport/gnunet-helper-transport-wlan.c, src/transport/gnunet-transport-wlan-helper-dummy.c, src/transport/gnunet-transport-wlan-helper.c, src/transport/gnunet-transport-wlan-sender.c, src/transport/plugin_transport_wlan.c: renaming WLAN helper process to gnunet-helper-transport-wlan in order to satisfy naming conventions 2011-12-10 13:49 harsha * [r18543] src/include/gnunet_stream_lib.h: syntax 2011-12-09 17:31 wachs * [r18541] src/integration-tests/Makefile.am, src/integration-tests/confs/c_no_nat_client_2.conf, src/integration-tests/hostkeys/0002-hostkey, src/integration-tests/hostkeys/0003-hostkey, src/integration-tests/hostkeys/0004-hostkey, src/integration-tests/hostkeys/0005-hostkey, src/integration-tests/hostkeys/0006-hostkey, src/integration-tests/hostkeys/0007-hostkey, src/integration-tests/hostkeys/0008-hostkey, src/integration-tests/hostkeys/0009-hostkey, src/integration-tests/test_integration_clique.py.in, src/integration-tests/test_integration_disconnect.py.in: clique 2011-12-09 16:18 wachs * [r18534] src/integration-tests/Makefile.am, src/integration-tests/test_integration_bootstrap_and_connect.py.in, src/integration-tests/test_integration_disconnect.py.in: disconnect test 2011-12-09 16:09 grothoff * [r18533] src/statistics/statistics_api.c: fix crash 2011-12-09 15:57 harsha * [r18532] src/include/gnunet_stream_lib.h: fixed missing doc comment 2011-12-09 15:55 harsha * [r18531] src/include/gnunet_stream_lib.h, src/stream, src/stream/README: added API definitions for stream library 2011-12-09 15:19 wachs * [r18530] src/integration-tests/test_integration_bootstrap_and_connect.py.in: added core sessions 2011-12-09 14:48 wachs * [r18528] src/integration-tests/confs/c_bootstrap_server.conf, src/integration-tests/confs/c_no_nat_client.conf, src/integration-tests/test_integration_bootstrap_and_connect.py.in: first test ready 2011-12-09 12:41 wachs * [r18526] src/integration-tests/test_integration_bootstrap_and_connect.py.in: test now checks if boths transports are connecting 2011-12-09 10:40 wachs * [r18525] src/statistics/gnunet-statistics.c: added quiet mode just printing the value 2011-12-08 16:16 wachs * [r18517] src/integration-tests/Makefile.am, src/integration-tests/confs, src/integration-tests/confs/c_bootstrap_server.conf, src/integration-tests/confs/c_nat_client.conf, src/integration-tests/confs/c_no_nat_client.conf, src/integration-tests/test_integration_bootstrap_and_connect.py.in, src/integration-tests/test_integration_clique.py.in: step by step 2011-12-08 15:45 grothoff * [r18515] doc/man/gnunet-arm.1, po/POTFILES.in, src/arm/Makefile.am, src/arm/arm.h, src/arm/arm_api.c, src/arm/do_start_process.c, src/arm/gnunet-arm.c, src/arm/gnunet-service-arm.c, src/arm/mockup-service.c, src/arm/test_arm_api.c, src/arm/test_exponential_backoff.c, src/arm/test_gnunet_arm.sh, src/arm/test_gnunet_service_manager.c, src/include/gnunet_arm_service.h, src/include/gnunet_protocols.h: major rewrite of ARM service and a bit of the ARM IPC to take advantage of the simplifications possible now that we no longer intercept traffic; the new code in particular is better at communicating what exactly ARM was doing in response to requests. A major change is that gnunet-arm -i/-k now only impacts if a service is running by-default, on-demand starting is no longer impacted, option -t from gnunet-arm was removed 2011-12-08 15:32 wachs * [r18512] src/testing/gnunet-testing.c: modified to create cfg with default without template 2011-12-08 13:43 wachs * [r18511] src/testing/gnunet-testing.c: added option to specify hostkey file 2011-12-08 13:16 wachs * [r18510] configure.ac, src/integration-tests, src/integration-tests/Makefile.am, src/integration-tests/test_integration_clique.py.in: basics for integration tests 2011-12-08 13:04 wachs * [r18509] src/testing/Makefile.am: space after backslash 2011-12-08 12:42 grothoff * [r18506] src/nse/gnunet-service-nse.c: add statistic to track estimated network diameter 2011-12-08 12:38 grothoff * [r18505] src/nse/gnunet-service-nse.c: fixing issue with sending back size estimate messages to peers that already have good estimate information 2011-12-07 17:02 wachs * [r18497] src/testing/gnunet-testing.c: added hostkey generation functionality 2011-12-07 15:34 wachs * [r18496] src/include/gnunet_testing_lib.h, src/testing/gnunet-testing.c, src/testing/testing_group.c: 2011-12-07 15:33 bartpolot * [r18495] src/nse/nse_api.c: Made sure that NSE never returns invalid standard deviation values 2011-12-07 13:23 wachs * [r18492] src/testing/gnunet-testing.c: 2011-12-07 12:42 wachs * [r18491] src/include/gnunet_getopt_lib.h, src/util/getopt_helpers.c: fixed docu 2011-12-07 12:28 wachs * [r18490] src/testing/Makefile.am, src/testing/gnunet-testing.c: testing cmd line tool 2011-12-06 20:20 grothoff * [r18484] src/arm/gnunet-service-arm_interceptor.c: removing ARM interceptor connection forwarding post-accept code, now using lsocks everywhere 2011-12-06 20:07 grothoff * [r18479] src/include/gnunet_common.h, src/include/gnunet_network_lib.h, src/include/gnunet_server_lib.h, src/transport/Makefile.am, src/transport/gnunet-transport-wlan-helper.c, src/util/pseudonym.c: eliminating last dependency on util code from wlan helper by inlining 2011-12-06 19:06 grothoff * [r18476] src/util/common_logging.c: LRN: correct behaviour when logfile does not exist 2011-12-06 18:06 grothoff * [r18475] src/arm/gnunet-service-arm_interceptor.c: fix compile 2011-12-06 18:06 grothoff * [r18474] src/util/common_logging.c: LRN: Ensure that GTK can then do the internal call write(2, message, strlen (message)); successfully by default. 2011-12-06 17:58 grothoff * [r18473] src/arm/do_start_process.c, src/arm/gnunet-service-arm.c, src/arm/gnunet-service-arm.h, src/arm/gnunet-service-arm_interceptor.c, src/include/gnunet_network_lib.h, src/include/gnunet_os_lib.h, src/include/platform.h, src/util/network.c, src/util/os_priority.c, src/util/service.c: Implement passing sockets in IPC on W32 (#1975) 2011-12-06 14:55 wachs * [r18463] src/include/gnunet_common.h, src/transport/gnunet-transport-wlan-helper.c, src/transport/gnunet_wlan_sender.c, src/transport/plugin_transport_wlan.c: adding GNUnet endian operations 2011-12-06 14:19 wachs * [r18461] src/transport/gnunet_wlan_sender.c: timestamp not supported on fedora core 8 2011-12-06 14:13 grothoff * [r18460] src/datastore/gnunet-service-datastore.c, src/util/common_allocation.c, src/util/container_bloomfilter.c: Fixing #1976 by allowing allocations between INT_MAX and SIZE_MAX and at the same time limiting BF size for datastore to 2 GB. Also fixing infinite loop when creating BFs of sizes between 2-4 GB 2011-12-06 13:54 grothoff * [r18456] src/arm/gnunet-service-arm_interceptor.c, src/include/gnunet_common.h, src/util/common_endian.c: use uint64_t instead of long long for GNUNET_ntohll/GNUNET_htonll 2011-12-06 13:35 bartpolot * [r18451] src/include/platform.h: Removed legacy code 2011-12-06 12:49 grothoff * [r18445] src/include/platform.h, src/include/winproc.h, src/nat/gnunet-helper-nat-client-windows.c, src/nat/gnunet-helper-nat-server-windows.c: LRN: Fixing Mantis #1974: On W32 winsock2.h defines FD_SETSIZE (if it was not defined before inclusion of the header) to 64, which means that it's not possible to select on more than 64 sockets at once. This might work during the tests, but in the wild people might want to have more than 60 connections, at least in the transport service. The patch attached should increase the limit to 1024. 2011-12-06 09:44 grothoff * [r18432] README: fix 2011-12-06 01:56 grothoff * [r18431] contrib/Makefile.am: distfix 2011-12-01 09:17 grothoff * [r18412] src/datastore/perf_plugin_datastore.c, src/util/winproc.c: LRN: Adding vectored exception handling for W32 (#1965) Whenever an exception occurs, and the process is not being debugged, it will run a debugger specified by GNUNET_DEBUGGER environment variable, and wait for it to attach. The net effect is the same as using JIT debugging (AeDebug), but without the stack being broken by SEH (because VEH has a priority over SEH), which allows for fuller backtraces for any exception, not just for GNUNET_abort() calls. 2011-11-30 15:21 grothoff * [r18410] Makefile.am, configure.ac, po/de.po, po/es.po, po/sv.po, po/vi.po, po/zh_CN.po: releasing GNUnet 0.9.0 gnunet-0.9.3/Makefile.in0000644000175000017500000007151411762217214012024 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = . DIST_COMMON = README $(am__configure_deps) $(gnunetinclude_HEADERS) \ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/gnunet_config.h.in $(top_srcdir)/configure ABOUT-NLS \ AUTHORS COPYING ChangeLog INSTALL NEWS compile config.guess \ config.rpath config.sub depcomp install-sh ltmain.sh missing ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(docdir)" \ "$(DESTDIR)$(gnunetincludedir)" DATA = $(doc_DATA) HEADERS = $(gnunetinclude_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir dist dist-all distcheck ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ { test ! -d "$(distdir)" \ || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -fr "$(distdir)"; }; } am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best distuninstallcheck_listfiles = find . -type f -print distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = $(datadir)/doc/gnunet/ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include SUBDIRS = contrib doc m4 src po pkgconfig EXTRA_DIST = \ ABOUT-NLS \ config.rpath \ install-sh \ acinclude.m4 gnunetincludedir = $(includedir)/gnunet gnunetinclude_HEADERS = gnunet_config.h doc_DATA = COPYING ACLOCAL_AMFLAGS = -I m4 all: gnunet_config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: am--refresh: @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): gnunet_config.h: stamp-h1 @if test ! -f $@; then \ rm -f stamp-h1; \ $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ else :; fi stamp-h1: $(srcdir)/gnunet_config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status gnunet_config.h $(srcdir)/gnunet_config.h.in: $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f gnunet_config.h stamp-h1 mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool config.lt install-docDATA: $(doc_DATA) @$(NORMAL_INSTALL) test -z "$(docdir)" || $(MKDIR_P) "$(DESTDIR)$(docdir)" @list='$(doc_DATA)'; test -n "$(docdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \ done uninstall-docDATA: @$(NORMAL_UNINSTALL) @list='$(doc_DATA)'; test -n "$(docdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(docdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(docdir)" && rm -f $$files install-gnunetincludeHEADERS: $(gnunetinclude_HEADERS) @$(NORMAL_INSTALL) test -z "$(gnunetincludedir)" || $(MKDIR_P) "$(DESTDIR)$(gnunetincludedir)" @list='$(gnunetinclude_HEADERS)'; test -n "$(gnunetincludedir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(gnunetincludedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(gnunetincludedir)" || exit $$?; \ done uninstall-gnunetincludeHEADERS: @$(NORMAL_UNINSTALL) @list='$(gnunetinclude_HEADERS)'; test -n "$(gnunetincludedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(gnunetincludedir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(gnunetincludedir)" && rm -f $$files # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. # To change the values of `make' variables: instead of editing Makefiles, # (1) if the variable is set in `config.status', edit `config.status' # (which will cause the Makefiles to be regenerated when you run `make'); # (2) otherwise, pass the desired values on the `make' command line. $(RECURSIVE_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ list='$(SUBDIRS)'; for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ rev="$$rev ."; \ target=`echo $@ | sed s/-recursive//`; \ for subdir in $$rev; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) gnunet_config.h.in $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) gnunet_config.h.in $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) gnunet_config.h.in $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) gnunet_config.h.in $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 $(am__remove_distdir) dist-lzma: distdir tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma $(am__remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz $(am__remove_distdir) dist-tarZ: distdir tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__remove_distdir) dist dist-all: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lzma*) \ lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir); chmod a+w $(distdir) mkdir $(distdir)/_build mkdir $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @$(am__cd) '$(distuninstallcheck_dir)' \ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile $(DATA) $(HEADERS) gnunet_config.h installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(docdir)" "$(DESTDIR)$(gnunetincludedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr \ distclean-libtool distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-docDATA install-gnunetincludeHEADERS install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-docDATA uninstall-gnunetincludeHEADERS .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all \ ctags-recursive install-am install-strip tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am am--refresh check check-am clean clean-generic \ clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \ dist-gzip dist-lzma dist-shar dist-tarZ dist-xz dist-zip \ distcheck distclean distclean-generic distclean-hdr \ distclean-libtool distclean-tags distcleancheck distdir \ distuninstallcheck dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-docDATA install-dvi install-dvi-am install-exec \ install-exec-am install-gnunetincludeHEADERS install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-recursive uninstall uninstall-am \ uninstall-docDATA uninstall-gnunetincludeHEADERS ChangeLog: if test -f $(top_srcdir)/.svn/entries; then \ svn log -v --xml -r HEAD:18409 | \ xsltproc --stringparam ignore-message-starting "-" \ --stringparam strip-prefix "gnunet" \ --stringparam include-rev "yes" $(top_srcdir)/contrib/svn2cl.xsl - > $@; \ fi dist: ChangeLog .PHONY: ChangeLog # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/0000755000175000017500000000000011763406747010632 500000000000000gnunet-0.9.3/src/tun/0000755000175000017500000000000011763406747011440 500000000000000gnunet-0.9.3/src/tun/Makefile.am0000644000175000017500000000116111722750157013403 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIB = -lgcov endif lib_LTLIBRARIES = libgnunettun.la libgnunettun_la_SOURCES = \ tun.c libgnunettun_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la $(XLIB) libgnunettun_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:0:0 check_PROGRAMS = \ test_tun if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) endif test_tun_SOURCES = \ test_tun.c test_tun_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/tun/libgnunettun.la gnunet-0.9.3/src/tun/test_tun.c0000644000175000017500000000365511760502550013364 00000000000000/* This file is part of GNUnet. (C) 2010, 2011, 2012 Christian Grothoff GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file tun/test_tun.c * @brief test for tun.c * @author Christian Grothoff */ #include "platform.h" #include "gnunet_tun_lib.h" static int ret; static void test_udp (size_t pll, int pl_fill, uint16_t crc) { struct GNUNET_TUN_IPv4Header ip; struct GNUNET_TUN_UdpHeader udp; char payload[pll]; struct in_addr src; struct in_addr dst; GNUNET_assert (1 == inet_pton (AF_INET, "1.2.3.4", &src)); GNUNET_assert (1 == inet_pton (AF_INET, "122.2.3.5", &dst)); memset (payload, pl_fill, sizeof (payload)); GNUNET_TUN_initialize_ipv4_header (&ip, IPPROTO_UDP, pll + sizeof (udp), &src, &dst); udp.source_port = htons (4242); udp.destination_port = htons (4242); udp.len = htons (pll); GNUNET_TUN_calculate_udp4_checksum (&ip, &udp, payload, pll); if (crc != ntohs (udp.crc)) { fprintf (stderr, "Got CRC: %u, wanted: %u\n", ntohs (udp.crc), crc); ret = 1; } } int main (int argc, char **argv) { test_udp (4, 3, 22439); test_udp (4, 1, 23467); test_udp (7, 17, 6516); test_udp (12451, 251, 42771); return ret; } gnunet-0.9.3/src/tun/tun.c0000644000175000017500000002145211760502550012320 00000000000000/* This file is part of GNUnet. (C) 2010, 2011, 2012 Christian Grothoff GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file tun/tun.c * @brief standard IP calculations for TUN interaction * @author Philipp Toelke * @author Christian Grothoff */ #include "platform.h" #include "gnunet_tun_lib.h" /** * IP TTL we use for packets that we assemble (8 bit unsigned integer) */ #define FRESH_TTL 64 /** * Initialize an IPv4 header. * * @param ip header to initialize * @param protocol protocol to use (i.e. IPPROTO_UDP) * @param payload_length number of bytes of payload that follow (excluding IPv4 header) * @param src source IP address to use * @param dst destination IP address to use */ void GNUNET_TUN_initialize_ipv4_header (struct GNUNET_TUN_IPv4Header *ip, uint8_t protocol, uint16_t payload_length, const struct in_addr *src, const struct in_addr *dst) { GNUNET_assert (20 == sizeof (struct GNUNET_TUN_IPv4Header)); GNUNET_assert (payload_length <= UINT16_MAX - sizeof (struct GNUNET_TUN_IPv4Header)); memset (ip, 0, sizeof (struct GNUNET_TUN_IPv4Header)); ip->header_length = sizeof (struct GNUNET_TUN_IPv4Header) / 4; ip->version = 4; ip->total_length = htons (sizeof (struct GNUNET_TUN_IPv4Header) + payload_length); ip->identification = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 65536); ip->ttl = FRESH_TTL; ip->protocol = protocol; ip->source_address = *src; ip->destination_address = *dst; ip->checksum = GNUNET_CRYPTO_crc16_n (ip, sizeof (struct GNUNET_TUN_IPv4Header)); } /** * Initialize an IPv6 header. * * @param ip header to initialize * @param protocol protocol to use (i.e. IPPROTO_UDP), technically "next_header" for IPv6 * @param payload_length number of bytes of payload that follow (excluding IPv4 header) * @param src source IP address to use * @param dst destination IP address to use */ void GNUNET_TUN_initialize_ipv6_header (struct GNUNET_TUN_IPv6Header *ip, uint8_t protocol, uint16_t payload_length, const struct in6_addr *src, const struct in6_addr *dst) { GNUNET_assert (40 == sizeof (struct GNUNET_TUN_IPv6Header)); GNUNET_assert (payload_length <= UINT16_MAX - sizeof (struct GNUNET_TUN_IPv6Header)); memset (ip, 0, sizeof (struct GNUNET_TUN_IPv6Header)); ip->version = 6; ip->next_header = protocol; ip->payload_length = htons ((uint16_t) payload_length); ip->hop_limit = FRESH_TTL; ip->destination_address = *dst; ip->source_address = *src; } /** * Calculate IPv4 TCP checksum. * * @param ip ipv4 header fully initialized * @param tcp TCP header (initialized except for CRC) * @param payload the TCP payload * @param payload_length number of bytes of TCP payload */ void GNUNET_TUN_calculate_tcp4_checksum (const struct GNUNET_TUN_IPv4Header *ip, struct GNUNET_TUN_TcpHeader *tcp, const void *payload, uint16_t payload_length) { uint32_t sum; uint16_t tmp; GNUNET_assert (20 == sizeof (struct GNUNET_TUN_TcpHeader)); GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_TcpHeader) == ntohs (ip->total_length)); GNUNET_assert (IPPROTO_TCP == ip->protocol); tcp->crc = 0; sum = GNUNET_CRYPTO_crc16_step (0, &ip->source_address, sizeof (struct in_addr) * 2); tmp = htons (IPPROTO_TCP); sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint16_t)); tmp = htons (payload_length + sizeof (struct GNUNET_TUN_TcpHeader)); sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint16_t)); sum = GNUNET_CRYPTO_crc16_step (sum, tcp, sizeof (struct GNUNET_TUN_TcpHeader)); sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length); tcp->crc = GNUNET_CRYPTO_crc16_finish (sum); } /** * Calculate IPv6 TCP checksum. * * @param ip ipv6 header fully initialized * @param tcp header (initialized except for CRC) * @param payload the TCP payload * @param payload_length number of bytes of TCP payload */ void GNUNET_TUN_calculate_tcp6_checksum (const struct GNUNET_TUN_IPv6Header *ip, struct GNUNET_TUN_TcpHeader *tcp, const void *payload, uint16_t payload_length) { uint32_t sum; uint32_t tmp; GNUNET_assert (20 == sizeof (struct GNUNET_TUN_TcpHeader)); GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_TcpHeader) == ntohs (ip->payload_length)); GNUNET_assert (IPPROTO_TCP == ip->next_header); tcp->crc = 0; sum = GNUNET_CRYPTO_crc16_step (0, &ip->source_address, 2 * sizeof (struct in6_addr)); tmp = htonl (sizeof (struct GNUNET_TUN_TcpHeader) + payload_length); sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); tmp = htonl (IPPROTO_TCP); sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); sum = GNUNET_CRYPTO_crc16_step (sum, tcp, sizeof (struct GNUNET_TUN_TcpHeader)); sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length); tcp->crc = GNUNET_CRYPTO_crc16_finish (sum); } /** * Calculate IPv4 UDP checksum. * * @param ip ipv4 header fully initialized * @param udp UDP header (initialized except for CRC) * @param payload the UDP payload * @param payload_length number of bytes of UDP payload */ void GNUNET_TUN_calculate_udp4_checksum (const struct GNUNET_TUN_IPv4Header *ip, struct GNUNET_TUN_UdpHeader *udp, const void *payload, uint16_t payload_length) { uint32_t sum; uint16_t tmp; GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_UdpHeader) == ntohs (ip->total_length)); GNUNET_assert (IPPROTO_UDP == ip->protocol); udp->crc = 0; /* technically optional, but we calculate it anyway, just to be sure */ sum = GNUNET_CRYPTO_crc16_step (0, &ip->source_address, sizeof (struct in_addr) * 2); tmp = htons (IPPROTO_UDP); sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint16_t)); tmp = htons (sizeof (struct GNUNET_TUN_UdpHeader) + payload_length); sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint16_t)); sum = GNUNET_CRYPTO_crc16_step (sum, udp, sizeof (struct GNUNET_TUN_UdpHeader)); sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length); udp->crc = GNUNET_CRYPTO_crc16_finish (sum); } /** * Calculate IPv6 UDP checksum. * * @param ip ipv6 header fully initialized * @param udp UDP header (initialized except for CRC) * @param payload the UDP payload * @param payload_length number of bytes of UDP payload */ void GNUNET_TUN_calculate_udp6_checksum (const struct GNUNET_TUN_IPv6Header *ip, struct GNUNET_TUN_UdpHeader *udp, const void *payload, uint16_t payload_length) { uint32_t sum; uint32_t tmp; GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_UdpHeader) == ntohs (ip->payload_length)); GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_UdpHeader) == ntohs (udp->len)); GNUNET_assert (IPPROTO_UDP == ip->next_header); udp->crc = 0; sum = GNUNET_CRYPTO_crc16_step (0, &ip->source_address, sizeof (struct in6_addr) * 2); tmp = htons (sizeof (struct GNUNET_TUN_UdpHeader) + payload_length); /* aka udp->len */ sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); tmp = htons (ip->next_header); sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); sum = GNUNET_CRYPTO_crc16_step (sum, udp, sizeof (struct GNUNET_TUN_UdpHeader)); sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length); udp->crc = GNUNET_CRYPTO_crc16_finish (sum); } /** * Calculate ICMP checksum. * * @param icmp IMCP header (initialized except for CRC) * @param payload the ICMP payload * @param payload_length number of bytes of ICMP payload */ void GNUNET_TUN_calculate_icmp_checksum (struct GNUNET_TUN_IcmpHeader *icmp, const void *payload, uint16_t payload_length) { uint32_t sum; GNUNET_assert (8 == sizeof (struct GNUNET_TUN_IcmpHeader)); icmp->crc = 0; sum = GNUNET_CRYPTO_crc16_step (0, icmp, sizeof (struct GNUNET_TUN_IcmpHeader)); sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length); icmp->crc = GNUNET_CRYPTO_crc16_finish (sum); } /* end of tun.c */ gnunet-0.9.3/src/tun/Makefile.in0000644000175000017500000006011511762217213013413 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ check_PROGRAMS = test_tun$(EXEEXT) subdir = src/tun DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libgnunettun_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_libgnunettun_la_OBJECTS = tun.lo libgnunettun_la_OBJECTS = $(am_libgnunettun_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunettun_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunettun_la_LDFLAGS) $(LDFLAGS) \ -o $@ am_test_tun_OBJECTS = test_tun.$(OBJEXT) test_tun_OBJECTS = $(am_test_tun_OBJECTS) test_tun_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/tun/libgnunettun.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunettun_la_SOURCES) $(test_tun_SOURCES) DIST_SOURCES = $(libgnunettun_la_SOURCES) $(test_tun_SOURCES) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @USE_COVERAGE_TRUE@XLIB = -lgcov lib_LTLIBRARIES = libgnunettun.la libgnunettun_la_SOURCES = \ tun.c libgnunettun_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la $(XLIB) libgnunettun_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:0:0 @ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) test_tun_SOURCES = \ test_tun.c test_tun_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/tun/libgnunettun.la all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/tun/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/tun/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunettun.la: $(libgnunettun_la_OBJECTS) $(libgnunettun_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunettun_la_LINK) -rpath $(libdir) $(libgnunettun_la_OBJECTS) $(libgnunettun_la_LIBADD) $(LIBS) clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list test_tun$(EXEEXT): $(test_tun_OBJECTS) $(test_tun_DEPENDENCIES) @rm -f test_tun$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_tun_OBJECTS) $(test_tun_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_tun.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tun.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool ctags distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-libLTLIBRARIES \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ uninstall-am uninstall-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/datastore/0000755000175000017500000000000011763406747012620 500000000000000gnunet-0.9.3/src/datastore/datastore.h0000644000175000017500000001253711760502551014672 00000000000000/* This file is part of GNUnet (C) 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file datastore/datastore.h * @brief structs for communication between datastore service and API * @author Christian Grothoff */ #ifndef DATASTORE_H #define DATASTORE_H #include "gnunet_util_lib.h" GNUNET_NETWORK_STRUCT_BEGIN /** * Message from datastore service informing client about * the current size of the datastore. */ struct ReserveMessage { /** * Type is GNUNET_MESSAGE_TYPE_DATASTORE_RESERVE. */ struct GNUNET_MessageHeader header; /** * Number of items to reserve. */ uint32_t entries GNUNET_PACKED; /** * Number of bytes to reserve. */ uint64_t amount GNUNET_PACKED; }; /** * Message from datastore service informing client about * the success or failure of a requested operation. * This header is optionally followed by a variable-size, * 0-terminated error message. */ struct StatusMessage { /** * Type is GNUNET_MESSAGE_TYPE_DATASTORE_STATUS. */ struct GNUNET_MessageHeader header; /** * Status code, -1 for errors. */ int32_t status GNUNET_PACKED; /** * Minimum expiration time required for content to be stored * by the datacache at this time, zero for unknown or no limit. */ struct GNUNET_TIME_AbsoluteNBO min_expiration; }; /** * Message from datastore client informing service that * the remainder of the reserved bytes can now be released * for other requests. */ struct ReleaseReserveMessage { /** * Type is GNUNET_MESSAGE_TYPE_DATASTORE_RELEASE_RESERVE. */ struct GNUNET_MessageHeader header; /** * Reservation id. */ int32_t rid GNUNET_PACKED; }; /** * Message to the datastore service asking about specific * content. */ struct GetMessage { /** * Type is GNUNET_MESSAGE_TYPE_DATASTORE_GET. Size * can either be "sizeof(struct GetMessage)" or * "sizeof(struct GetMessage) - sizeof(GNUNET_HashCode)"! */ struct GNUNET_MessageHeader header; /** * Desired content type. (actually an enum GNUNET_BLOCK_Type) */ uint32_t type GNUNET_PACKED; /** * Offset of the result. */ uint64_t offset GNUNET_PACKED; /** * Desired key (optional). Check the "size" of the * header to see if the key is actually present. */ GNUNET_HashCode key; }; /** * Message to the datastore service asking about zero * anonymity content. */ struct GetZeroAnonymityMessage { /** * Type is GNUNET_MESSAGE_TYPE_DATASTORE_GET_ZERO_ANONYMITY. */ struct GNUNET_MessageHeader header; /** * Desired content type (actually an enum GNUNET_BLOCK_Type) */ uint32_t type GNUNET_PACKED; /** * Offset of the result. */ uint64_t offset GNUNET_PACKED; }; /** * Message to the datastore service requesting an update * to the priority or expiration for some content. */ struct UpdateMessage { /** * Type is GNUNET_MESSAGE_TYPE_DATASTORE_UPDATE. */ struct GNUNET_MessageHeader header; /** * Desired priority increase. */ int32_t priority GNUNET_PACKED; /** * Desired new expiration time. */ struct GNUNET_TIME_AbsoluteNBO expiration; /** * Unique ID for the content. */ uint64_t uid; }; /** * Message transmitting content from or to the datastore * service. */ struct DataMessage { /** * Type is either GNUNET_MESSAGE_TYPE_DATASTORE_PUT, * GNUNET_MESSAGE_TYPE_DATASTORE_REMOVE or * GNUNET_MESSAGE_TYPE_DATASTORE_DATA. Depending on the message * type, some fields may simply have values of zero. */ struct GNUNET_MessageHeader header; /** * Reservation ID to use; use zero for none. */ uint32_t rid GNUNET_PACKED; /** * Number of bytes in the item (NBO). */ uint32_t size GNUNET_PACKED; /** * Type of the item (NBO), zero for remove, (actually an enum GNUNET_BLOCK_Type) */ uint32_t type GNUNET_PACKED; /** * Priority of the item (NBO), zero for remove. */ uint32_t priority GNUNET_PACKED; /** * Desired anonymity level (NBO), zero for remove. */ uint32_t anonymity GNUNET_PACKED; /** * Desired replication level. 0 from service to API. */ uint32_t replication GNUNET_PACKED; /** * For alignment. */ uint32_t reserved GNUNET_PACKED; /** * Unique ID for the content (can be used for UPDATE); * can be zero for remove (which indicates that * the datastore should use whatever UID matches * the key and content). */ uint64_t uid; /** * Expiration time (NBO); zero for remove. */ struct GNUNET_TIME_AbsoluteNBO expiration; /** * Key under which the item can be found. */ GNUNET_HashCode key; }; GNUNET_NETWORK_STRUCT_END #endif gnunet-0.9.3/src/datastore/Makefile.am0000644000175000017500000001535511736522673014602 00000000000000INCLUDES = -I$(top_srcdir)/src/include plugindir = $(libdir)/gnunet pkgcfgdir= $(pkgdatadir)/config.d/ pkgcfg_DATA = \ datastore.conf if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIBS = -lgcov endif lib_LTLIBRARIES = \ libgnunetdatastore.la libgnunetdatastore_la_SOURCES = \ datastore_api.c datastore.h libgnunetdatastore_la_LIBADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) libgnunetdatastore_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 1:0:0 bin_PROGRAMS = \ gnunet-service-datastore gnunet_service_datastore_SOURCES = \ gnunet-service-datastore.c gnunet_service_datastore_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) if HAVE_MYSQL MYSQL_PLUGIN = libgnunet_plugin_datastore_mysql.la if HAVE_BENCHMARKS MYSQL_BENCHMARKS = \ perf_datastore_api_mysql \ perf_plugin_datastore_mysql endif MYSQL_TESTS = \ test_datastore_api_mysql \ test_datastore_api_management_mysql \ test_plugin_datastore_mysql \ $(MYSQL_BENCHMARKS) endif if HAVE_SQLITE SQLITE_PLUGIN = libgnunet_plugin_datastore_sqlite.la if HAVE_BENCHMARKS SQLITE_BENCHMARKS = \ perf_datastore_api_sqlite \ perf_plugin_datastore_sqlite endif SQLITE_TESTS = \ test_datastore_api_sqlite \ test_datastore_api_management_sqlite \ test_plugin_datastore_sqlite \ $(SQLITE_BENCHMARKS) endif if HAVE_POSTGRES POSTGRES_PLUGIN = libgnunet_plugin_datastore_postgres.la if HAVE_BENCHMARKS POSTGRES_BENCHMARKS = \ perf_datastore_api_postgres \ perf_plugin_datastore_postgres endif POSTGRES_TESTS = \ test_datastore_api_postgres \ test_datastore_api_management_postgres \ test_plugin_datastore_postgres \ $(POSTGRES_BENCHMARKS) endif plugin_LTLIBRARIES = \ $(SQLITE_PLUGIN) \ $(MYSQL_PLUGIN) \ $(POSTGRES_PLUGIN) \ libgnunet_plugin_datastore_template.la libgnunet_plugin_datastore_sqlite_la_SOURCES = \ plugin_datastore_sqlite.c libgnunet_plugin_datastore_sqlite_la_LIBADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 libgnunet_plugin_datastore_sqlite_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_datastore_mysql_la_SOURCES = \ plugin_datastore_mysql.c libgnunet_plugin_datastore_mysql_la_LIBADD = \ $(top_builddir)/src/mysql/libgnunetmysql.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lz -lmysqlclient libgnunet_plugin_datastore_mysql_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) $(MYSQL_LDFLAGS) -lmysqlclient libgnunet_plugin_datastore_mysql_la_CPPFLAGS = \ $(MYSQL_CPPFLAGS) libgnunet_plugin_datastore_postgres_la_SOURCES = \ plugin_datastore_postgres.c libgnunet_plugin_datastore_postgres_la_LIBADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/postgres/libgnunetpostgres.la \ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lpq libgnunet_plugin_datastore_postgres_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) $(POSTGRES_LDFLAGS) -lpq libgnunet_plugin_datastore_postgres_la_CPPFLAGS = \ $(POSTGRES_CPPFLAGS) libgnunet_plugin_datastore_template_la_SOURCES = \ plugin_datastore_template.c libgnunet_plugin_datastore_template_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) libgnunet_plugin_datastore_template_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) check_PROGRAMS = \ $(SQLITE_TESTS) \ $(MYSQL_TESTS) \ $(POSTGRES_TESTS) if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) endif test_datastore_api_sqlite_SOURCES = \ test_datastore_api.c test_datastore_api_sqlite_LDADD = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la test_datastore_api_management_sqlite_SOURCES = \ test_datastore_api_management.c test_datastore_api_management_sqlite_LDADD = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la perf_datastore_api_sqlite_SOURCES = \ perf_datastore_api.c perf_datastore_api_sqlite_LDADD = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la perf_plugin_datastore_sqlite_SOURCES = \ perf_plugin_datastore.c perf_plugin_datastore_sqlite_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_plugin_datastore_sqlite_SOURCES = \ test_plugin_datastore.c test_plugin_datastore_sqlite_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_datastore_api_mysql_SOURCES = \ test_datastore_api.c test_datastore_api_mysql_LDADD = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la test_datastore_api_management_mysql_SOURCES = \ test_datastore_api_management.c test_datastore_api_management_mysql_LDADD = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la perf_datastore_api_mysql_SOURCES = \ perf_datastore_api.c perf_datastore_api_mysql_LDADD = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la test_plugin_datastore_mysql_SOURCES = \ test_plugin_datastore.c test_plugin_datastore_mysql_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la perf_plugin_datastore_mysql_SOURCES = \ perf_plugin_datastore.c perf_plugin_datastore_mysql_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_datastore_api_postgres_SOURCES = \ test_datastore_api.c test_datastore_api_postgres_LDADD = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la test_datastore_api_management_postgres_SOURCES = \ test_datastore_api_management.c test_datastore_api_management_postgres_LDADD = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la perf_datastore_api_postgres_SOURCES = \ perf_datastore_api.c perf_datastore_api_postgres_LDADD = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la test_plugin_datastore_postgres_SOURCES = \ test_plugin_datastore.c test_plugin_datastore_postgres_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la perf_plugin_datastore_postgres_SOURCES = \ perf_plugin_datastore.c perf_plugin_datastore_postgres_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ test_defaults.conf \ test_datastore_api_data_sqlite.conf \ perf_plugin_datastore_data_sqlite.conf \ test_datastore_api_data_mysql.conf \ perf_plugin_datastore_data_mysql.conf \ test_datastore_api_data_postgres.conf \ perf_plugin_datastore_data_postgres.conf \ test_plugin_datastore_data_mysql.conf \ test_plugin_datastore_data_postgres.conf \ test_plugin_datastore_data_sqlite.confgnunet-0.9.3/src/datastore/test_datastore_api.c0000644000175000017500000004102111760502550016542 00000000000000/* This file is part of GNUnet. (C) 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * @file datastore/test_datastore_api.c * @brief Test for the basic datastore API. * @author Christian Grothoff * * TODO: * - test reservation failure */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_protocols.h" #include "gnunet_datastore_service.h" #define VERBOSE GNUNET_NO #define START_DATASTORE GNUNET_YES /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) #define ITERATIONS 256 static struct GNUNET_DATASTORE_Handle *datastore; static struct GNUNET_TIME_Absolute now; static int ok; /** * Name of plugin under test. */ static const char *plugin_name; static size_t get_size (int i) { return 8 * i; } static const void * get_data (int i) { static char buf[60000]; memset (buf, i, 8 * i); return buf; } static int get_type (int i) { return i + 1; } static int get_priority (int i) { return i + 1; } static int get_anonymity (int i) { return i; } static struct GNUNET_TIME_Absolute get_expiration (int i) { struct GNUNET_TIME_Absolute av; av.abs_value = now.abs_value + 20000000 - i * 1000; return av; } enum RunPhase { RP_DONE = 0, RP_PUT = 1, RP_GET = 2, RP_DEL = 3, RP_DO_DEL = 4, RP_DELVALIDATE = 5, RP_RESERVE = 6, RP_PUT_MULTIPLE = 7, RP_PUT_MULTIPLE_NEXT = 8, RP_GET_MULTIPLE = 9, RP_GET_MULTIPLE_NEXT = 10, RP_UPDATE = 11, RP_UPDATE_VALIDATE = 12, RP_ERROR }; struct CpsRunContext { GNUNET_HashCode key; int i; int rid; const struct GNUNET_CONFIGURATION_Handle *cfg; void *data; size_t size; enum RunPhase phase; uint64_t uid; uint64_t offset; uint64_t first_uid; }; static void run_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); static void check_success (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) { struct CpsRunContext *crc = cls; if (GNUNET_OK != success) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Operation %d/%d not successfull: `%s'\n", crc->phase, crc->i, msg); crc->phase = RP_ERROR; } GNUNET_free_non_null (crc->data); crc->data = NULL; GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } static void get_reserved (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) { struct CpsRunContext *crc = cls; if (0 >= success) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error obtaining reservation: `%s'\n", msg); GNUNET_assert (0 < success); crc->rid = success; GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } static void check_value (void *cls, const GNUNET_HashCode * key, size_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct CpsRunContext *crc = cls; int i; i = crc->i; if (NULL == key) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Value check failed (got NULL key) in %d/%d\n", crc->phase, crc->i); crc->phase = RP_ERROR; GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, GNUNET_SCHEDULER_REASON_PREREQ_DONE); return; } #if 0 FPRINTF (stderr, "Check value got `%s' of size %u, type %d, expire %llu\n", GNUNET_h2s (key), (unsigned int) size, type, (unsigned long long) expiration.abs_value); FPRINTF (stderr, "Check value iteration %d wants size %u, type %d, expire %llu\n", i, (unsigned int) get_size (i), get_type (i), (unsigned long long) get_expiration (i).abs_value); #endif GNUNET_assert (size == get_size (i)); GNUNET_assert (0 == memcmp (data, get_data (i), size)); GNUNET_assert (type == get_type (i)); GNUNET_assert (priority == get_priority (i)); GNUNET_assert (anonymity == get_anonymity (i)); GNUNET_assert (expiration.abs_value == get_expiration (i).abs_value); crc->offset++; if (crc->i == 0) { crc->phase = RP_DEL; crc->i = ITERATIONS; } GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } static void delete_value (void *cls, const GNUNET_HashCode * key, size_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct CpsRunContext *crc = cls; GNUNET_assert (crc->data == NULL); GNUNET_assert (NULL != key); crc->size = size; crc->key = *key; crc->data = GNUNET_malloc (size); memcpy (crc->data, data, size); crc->phase = RP_DO_DEL; GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } static void check_nothing (void *cls, const GNUNET_HashCode * key, size_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct CpsRunContext *crc = cls; GNUNET_assert (key == NULL); if (crc->i == 0) crc->phase = RP_RESERVE; GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } static void check_multiple (void *cls, const GNUNET_HashCode * key, size_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct CpsRunContext *crc = cls; GNUNET_assert (key != NULL); switch (crc->phase) { case RP_GET_MULTIPLE: crc->phase = RP_GET_MULTIPLE_NEXT; crc->first_uid = uid; crc->offset++; break; case RP_GET_MULTIPLE_NEXT: GNUNET_assert (uid != crc->first_uid); crc->phase = RP_UPDATE; break; default: GNUNET_break (0); crc->phase = RP_ERROR; break; } if (priority == get_priority (42)) crc->uid = uid; GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } static void check_update (void *cls, const GNUNET_HashCode * key, size_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct CpsRunContext *crc = cls; GNUNET_assert (key != NULL); if ((anonymity == get_anonymity (42)) && (size == get_size (42)) && (priority == get_priority (42) + 100)) crc->phase = RP_DONE; else { GNUNET_assert (size == get_size (43)); crc->offset++; } GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } static void run_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct CpsRunContext *crc = cls; ok = (int) crc->phase; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test in phase %u\n", crc->phase); #endif switch (crc->phase) { case RP_PUT: #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "PUT", crc->i); #endif GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key); GNUNET_DATASTORE_put (datastore, 0, &crc->key, get_size (crc->i), get_data (crc->i), get_type (crc->i), get_priority (crc->i), get_anonymity (crc->i), 0, get_expiration (crc->i), 1, 1, TIMEOUT, &check_success, crc); crc->i++; if (crc->i == ITERATIONS) crc->phase = RP_GET; break; case RP_GET: crc->i--; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "GET", crc->i); #endif GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key); GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key, get_type (crc->i), 1, 1, TIMEOUT, &check_value, crc); break; case RP_DEL: crc->i--; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "DEL", crc->i); #endif crc->data = NULL; GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key); GNUNET_assert (NULL != GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key, get_type (crc->i), 1, 1, TIMEOUT, &delete_value, crc)); break; case RP_DO_DEL: #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "DO_DEL", crc->i); #endif if (crc->i == 0) { crc->i = ITERATIONS; crc->phase = RP_DELVALIDATE; } else { crc->phase = RP_DEL; } GNUNET_assert (NULL != GNUNET_DATASTORE_remove (datastore, &crc->key, crc->size, crc->data, 1, 1, TIMEOUT, &check_success, crc)); break; case RP_DELVALIDATE: crc->i--; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "DEL-VALIDATE", crc->i); #endif GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key); GNUNET_assert (NULL != GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key, get_type (crc->i), 1, 1, TIMEOUT, &check_nothing, crc)); break; case RP_RESERVE: crc->phase = RP_PUT_MULTIPLE; GNUNET_DATASTORE_reserve (datastore, 128 * 1024, 2, 1, 1, TIMEOUT, &get_reserved, crc); break; case RP_PUT_MULTIPLE: crc->phase = RP_PUT_MULTIPLE_NEXT; GNUNET_DATASTORE_put (datastore, crc->rid, &crc->key, get_size (42), get_data (42), get_type (42), get_priority (42), get_anonymity (42), 0, get_expiration (42), 1, 1, TIMEOUT, &check_success, crc); break; case RP_PUT_MULTIPLE_NEXT: crc->phase = RP_GET_MULTIPLE; GNUNET_DATASTORE_put (datastore, crc->rid, &crc->key, get_size (43), get_data (43), get_type (42), get_priority (43), get_anonymity (43), 0, get_expiration (43), 1, 1, TIMEOUT, &check_success, crc); break; case RP_GET_MULTIPLE: GNUNET_assert (NULL != GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key, get_type (42), 1, 1, TIMEOUT, &check_multiple, crc)); break; case RP_GET_MULTIPLE_NEXT: GNUNET_assert (NULL != GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key, get_type (42), 1, 1, TIMEOUT, &check_multiple, crc)); break; case RP_UPDATE: GNUNET_assert (crc->uid > 0); crc->phase = RP_UPDATE_VALIDATE; GNUNET_DATASTORE_update (datastore, crc->uid, 100, get_expiration (42), 1, 1, TIMEOUT, &check_success, crc); break; case RP_UPDATE_VALIDATE: GNUNET_assert (NULL != GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key, get_type (42), 1, 1, TIMEOUT, &check_update, crc)); break; case RP_DONE: #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished, disconnecting\n"); #endif GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES); GNUNET_free (crc); ok = 0; break; case RP_ERROR: GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES); GNUNET_free (crc); ok = 43; break; } } static void run_tests (void *cls, int32_t success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) { struct CpsRunContext *crc = cls; switch (success) { case GNUNET_YES: GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, GNUNET_SCHEDULER_REASON_PREREQ_DONE); return; case GNUNET_NO: FPRINTF (stderr, "%s", "Test 'put' operation failed, key already exists (!?)\n"); GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES); GNUNET_free (crc); return; case GNUNET_SYSERR: FPRINTF (stderr, "Test 'put' operation failed with error `%s' database likely not setup, skipping test.\n", msg); GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES); GNUNET_free (crc); return; default: GNUNET_assert (0); } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct CpsRunContext *crc; static GNUNET_HashCode zkey; crc = GNUNET_malloc (sizeof (struct CpsRunContext)); crc->cfg = cfg; crc->phase = RP_PUT; now = GNUNET_TIME_absolute_get (); datastore = GNUNET_DATASTORE_connect (cfg); if (NULL == GNUNET_DATASTORE_put (datastore, 0, &zkey, 4, "TEST", GNUNET_BLOCK_TYPE_TEST, 0, 0, 0, GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_SECONDS), 0, 1, GNUNET_TIME_UNIT_MINUTES, &run_tests, crc)) { FPRINTF (stderr, "%s", "Test 'put' operation failed.\n"); ok = 1; GNUNET_free (crc); } } static int check () { char cfg_name[128]; #if START_DATASTORE struct GNUNET_OS_Process *proc; #endif char *const argv[] = { "test-datastore-api", "-c", cfg_name, #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_snprintf (cfg_name, sizeof (cfg_name), "test_datastore_api_data_%s.conf", plugin_name); #if START_DATASTORE proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE "-L", "DEBUG", #endif "-c", cfg_name, NULL); #endif GNUNET_assert (NULL != proc); GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-datastore-api", "nohelp", options, &run, NULL); #if START_DATASTORE sleep (1); /* give datastore chance to receive 'DROP' request */ if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); ok = 1; } GNUNET_OS_process_wait (proc); GNUNET_OS_process_destroy (proc); proc = NULL; #endif if (ok != 0) FPRINTF (stderr, "Missed some testcases: %u\n", ok); return ok; } int main (int argc, char *argv[]) { int ret; char *pos; char dir_name[128]; sleep (1); /* determine name of plugin to use */ plugin_name = argv[0]; while (NULL != (pos = strstr (plugin_name, "_"))) plugin_name = pos + 1; if (NULL != (pos = strstr (plugin_name, "."))) pos[0] = 0; else pos = (char *) plugin_name; GNUNET_snprintf (dir_name, sizeof (dir_name), "/tmp/test-gnunet-datastore-%s", plugin_name); GNUNET_DISK_directory_remove (dir_name); GNUNET_log_setup ("test-datastore-api", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); if (pos != plugin_name) pos[0] = '.'; GNUNET_DISK_directory_remove (dir_name); return ret; } /* end of test_datastore_api.c */ gnunet-0.9.3/src/datastore/test_plugin_datastore_data_postgres.conf0000644000175000017500000000035311634323402022711 00000000000000@INLINE@ test_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-datastore-plugin-postgres/ DEFAULTCONFIG = test_plugin_datastore_data_postgres.conf [datastore] DATABASE = postgres [datastore-postgres] CONFIG = dbname=gnunetcheck gnunet-0.9.3/src/datastore/test_plugin_datastore_data_sqlite.conf0000644000175000017500000000022411634323402022341 00000000000000@INLINE@ test_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-datastore-plugin-sqlite/ DEFAULTCONFIG = test_plugin_datastore_data_sqlite.conf gnunet-0.9.3/src/datastore/plugin_datastore_sqlite.c0000644000175000017500000011642311760502550017622 00000000000000 /* * This file is part of GNUnet * (C) 2009, 2011 Christian Grothoff (and other contributing authors) * * GNUnet is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 3, or (at your * option) any later version. * * GNUnet is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNUnet; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /** * @file datastore/plugin_datastore_sqlite.c * @brief sqlite-based datastore backend * @author Christian Grothoff */ #include "platform.h" #include "gnunet_datastore_plugin.h" #include /** * We allocate items on the stack at times. To prevent a stack * overflow, we impose a limit on the maximum size for the data per * item. 64k should be enough. */ #define MAX_ITEM_SIZE 65536 /** * After how many ms "busy" should a DB operation fail for good? * A low value makes sure that we are more responsive to requests * (especially PUTs). A high value guarantees a higher success * rate (SELECTs in iterate can take several seconds despite LIMIT=1). * * The default value of 250ms should ensure that users do not experience * huge latencies while at the same time allowing operations to succeed * with reasonable probability. */ #define BUSY_TIMEOUT_MS 250 /** * Log an error message at log-level 'level' that indicates * a failure of the command 'cmd' on file 'filename' * with the message given by strerror(errno). */ #define LOG_SQLITE(db, msg, level, cmd) do { GNUNET_log_from (level, "sqlite", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); if (msg != NULL) GNUNET_asprintf(msg, _("`%s' failed at %s:%u with error: %s"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); } while(0) /** * Context for all functions in this plugin. */ struct Plugin { /** * Our execution environment. */ struct GNUNET_DATASTORE_PluginEnvironment *env; /** * Database filename. */ char *fn; /** * Native SQLite database handle. */ sqlite3 *dbh; /** * Precompiled SQL for deletion. */ sqlite3_stmt *delRow; /** * Precompiled SQL for update. */ sqlite3_stmt *updPrio; /** * Get maximum repl value in database. */ sqlite3_stmt *maxRepl; /** * Precompiled SQL for replication decrement. */ sqlite3_stmt *updRepl; /** * Precompiled SQL for replication selection. */ sqlite3_stmt *selRepl; /** * Precompiled SQL for expiration selection. */ sqlite3_stmt *selExpi; /** * Precompiled SQL for expiration selection. */ sqlite3_stmt *selZeroAnon; /** * Precompiled SQL for insertion. */ sqlite3_stmt *insertContent; /** * Should the database be dropped on shutdown? */ int drop_on_shutdown; }; /** * @brief Prepare a SQL statement * * @param dbh handle to the database * @param zSql SQL statement, UTF-8 encoded * @param ppStmt set to the prepared statement * @return 0 on success */ static int sq_prepare (sqlite3 * dbh, const char *zSql, sqlite3_stmt ** ppStmt) { char *dummy; int result; result = sqlite3_prepare_v2 (dbh, zSql, strlen (zSql), ppStmt, (const char **) &dummy); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Prepared `%s' / %p: %d\n", zSql, *ppStmt, result); return result; } /** * Create our database indices. * * @param dbh handle to the database */ static void create_indices (sqlite3 * dbh) { /* create indices */ if ((SQLITE_OK != sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS idx_hash ON gn090 (hash)", NULL, NULL, NULL)) || (SQLITE_OK != sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS idx_hash_vhash ON gn090 (hash,vhash)", NULL, NULL, NULL)) || (SQLITE_OK != sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS idx_expire_repl ON gn090 (expire ASC,repl DESC)", NULL, NULL, NULL)) || (SQLITE_OK != sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS idx_comb ON gn090 (anonLevel ASC,expire ASC,prio,type,hash)", NULL, NULL, NULL)) || (SQLITE_OK != sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS idx_anon_type_hash ON gn090 (anonLevel ASC,type,hash)", NULL, NULL, NULL)) || (SQLITE_OK != sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS idx_expire ON gn090 (expire ASC)", NULL, NULL, NULL)) || (SQLITE_OK != sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS idx_repl_rvalue ON gn090 (repl,rvalue)", NULL, NULL, NULL)) || (SQLITE_OK != sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS idx_repl ON gn090 (repl DESC)", NULL, NULL, NULL))) GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "sqlite", "Failed to create indices: %s\n", sqlite3_errmsg (dbh)); } #if 0 #define CHECK(a) GNUNET_break(a) #define ENULL NULL #else #define ENULL &e #define ENULL_DEFINED 1 #define CHECK(a) if (! a) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "%s\n", e); sqlite3_free(e); } #endif /** * Initialize the database connections and associated * data structures (create tables and indices * as needed as well). * * @param cfg our configuration * @param plugin the plugin context (state for this module) * @return GNUNET_OK on success */ static int database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg, struct Plugin *plugin) { sqlite3_stmt *stmt; char *afsdir; #if ENULL_DEFINED char *e; #endif if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "datastore-sqlite", "FILENAME", &afsdir)) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "sqlite", _ ("Option `%s' in section `%s' missing in configuration!\n"), "FILENAME", "datastore-sqlite"); return GNUNET_SYSERR; } if (GNUNET_OK != GNUNET_DISK_file_test (afsdir)) { if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (afsdir)) { GNUNET_break (0); GNUNET_free (afsdir); return GNUNET_SYSERR; } /* database is new or got deleted, reset payload to zero! */ plugin->env->duc (plugin->env->cls, 0); } #ifdef ENABLE_NLS plugin->fn = GNUNET_STRINGS_to_utf8 (afsdir, strlen (afsdir), nl_langinfo (CODESET)); #else plugin->fn = GNUNET_STRINGS_to_utf8 (afsdir, strlen (afsdir), "UTF-8"); /* good luck */ #endif GNUNET_free (afsdir); /* Open database and precompile statements */ if (sqlite3_open (plugin->fn, &plugin->dbh) != SQLITE_OK) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "sqlite", _("Unable to initialize SQLite: %s.\n"), sqlite3_errmsg (plugin->dbh)); return GNUNET_SYSERR; } CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "PRAGMA temp_store=MEMORY", NULL, NULL, ENULL)); CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "PRAGMA synchronous=OFF", NULL, NULL, ENULL)); CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "PRAGMA legacy_file_format=OFF", NULL, NULL, ENULL)); CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL", NULL, NULL, ENULL)); CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "PRAGMA locking_mode=EXCLUSIVE", NULL, NULL, ENULL)); CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "PRAGMA count_changes=OFF", NULL, NULL, ENULL)); CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "PRAGMA page_size=4092", NULL, NULL, ENULL)); CHECK (SQLITE_OK == sqlite3_busy_timeout (plugin->dbh, BUSY_TIMEOUT_MS)); /* We have to do it here, because otherwise precompiling SQL might fail */ CHECK (SQLITE_OK == sq_prepare (plugin->dbh, "SELECT 1 FROM sqlite_master WHERE tbl_name = 'gn090'", &stmt)); if ((sqlite3_step (stmt) == SQLITE_DONE) && (sqlite3_exec (plugin->dbh, "CREATE TABLE gn090 (" " repl INT4 NOT NULL DEFAULT 0," " type INT4 NOT NULL DEFAULT 0," " prio INT4 NOT NULL DEFAULT 0," " anonLevel INT4 NOT NULL DEFAULT 0," " expire INT8 NOT NULL DEFAULT 0," " rvalue INT8 NOT NULL," " hash TEXT NOT NULL DEFAULT ''," " vhash TEXT NOT NULL DEFAULT ''," " value BLOB NOT NULL DEFAULT '')", NULL, NULL, NULL) != SQLITE_OK)) { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec"); sqlite3_finalize (stmt); return GNUNET_SYSERR; } sqlite3_finalize (stmt); create_indices (plugin->dbh); if ((sq_prepare (plugin->dbh, "UPDATE gn090 " "SET prio = prio + ?, expire = MAX(expire,?) WHERE _ROWID_ = ?", &plugin->updPrio) != SQLITE_OK) || (sq_prepare (plugin->dbh, "UPDATE gn090 " "SET repl = MAX (0, repl - 1) WHERE _ROWID_ = ?", &plugin->updRepl) != SQLITE_OK) || (sq_prepare (plugin->dbh, "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 " #if SQLITE_VERSION_NUMBER >= 3007000 "INDEXED BY idx_repl_rvalue " #endif "WHERE repl=?2 AND " " (rvalue>=?1 OR " " NOT EXISTS (SELECT 1 FROM gn090 " #if SQLITE_VERSION_NUMBER >= 3007000 "INDEXED BY idx_repl_rvalue " #endif "WHERE repl=?2 AND rvalue>=?1 LIMIT 1) ) " "ORDER BY rvalue ASC LIMIT 1", &plugin->selRepl) != SQLITE_OK) || (sq_prepare (plugin->dbh, "SELECT MAX(repl) FROM gn090" #if SQLITE_VERSION_NUMBER >= 3007000 " INDEXED BY idx_repl_rvalue" #endif "", &plugin->maxRepl) != SQLITE_OK) || (sq_prepare (plugin->dbh, "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 " #if SQLITE_VERSION_NUMBER >= 3007000 "INDEXED BY idx_expire " #endif "WHERE NOT EXISTS (SELECT 1 FROM gn090 WHERE expire < ?1 LIMIT 1) OR (expire < ?1) " "ORDER BY expire ASC LIMIT 1", &plugin->selExpi) != SQLITE_OK) || (sq_prepare (plugin->dbh, "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 " #if SQLITE_VERSION_NUMBER >= 3007000 "INDEXED BY idx_anon_type_hash " #endif "WHERE (anonLevel = 0 AND type=?1) " "ORDER BY hash DESC LIMIT 1 OFFSET ?2", &plugin->selZeroAnon) != SQLITE_OK) || (sq_prepare (plugin->dbh, "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) " "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", &plugin->insertContent) != SQLITE_OK) || (sq_prepare (plugin->dbh, "DELETE FROM gn090 WHERE _ROWID_ = ?", &plugin->delRow) != SQLITE_OK)) { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR, "precompiling"); return GNUNET_SYSERR; } return GNUNET_OK; } /** * Shutdown database connection and associate data * structures. * @param plugin the plugin context (state for this module) */ static void database_shutdown (struct Plugin *plugin) { int result; #if SQLITE_VERSION_NUMBER >= 3007000 sqlite3_stmt *stmt; #endif if (plugin->delRow != NULL) sqlite3_finalize (plugin->delRow); if (plugin->updPrio != NULL) sqlite3_finalize (plugin->updPrio); if (plugin->updRepl != NULL) sqlite3_finalize (plugin->updRepl); if (plugin->selRepl != NULL) sqlite3_finalize (plugin->selRepl); if (plugin->maxRepl != NULL) sqlite3_finalize (plugin->maxRepl); if (plugin->selExpi != NULL) sqlite3_finalize (plugin->selExpi); if (plugin->selZeroAnon != NULL) sqlite3_finalize (plugin->selZeroAnon); if (plugin->insertContent != NULL) sqlite3_finalize (plugin->insertContent); result = sqlite3_close (plugin->dbh); #if SQLITE_VERSION_NUMBER >= 3007000 if (result == SQLITE_BUSY) { GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite", _ ("Tried to close sqlite without finalizing all prepared statements.\n")); stmt = sqlite3_next_stmt (plugin->dbh, NULL); while (stmt != NULL) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Closing statement %p\n", stmt); result = sqlite3_finalize (stmt); if (result != SQLITE_OK) GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite", "Failed to close statement %p: %d\n", stmt, result); stmt = sqlite3_next_stmt (plugin->dbh, NULL); } result = sqlite3_close (plugin->dbh); } #endif if (SQLITE_OK != result) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close"); GNUNET_free_non_null (plugin->fn); } /** * Delete the database entry with the given * row identifier. * * @param plugin the plugin context (state for this module) * @param rid the ID of the row to delete */ static int delete_by_rowid (struct Plugin *plugin, unsigned long long rid) { if (SQLITE_OK != sqlite3_bind_int64 (plugin->delRow, 1, rid)) { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); if (SQLITE_OK != sqlite3_reset (plugin->delRow)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); return GNUNET_SYSERR; } if (SQLITE_DONE != sqlite3_step (plugin->delRow)) { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); if (SQLITE_OK != sqlite3_reset (plugin->delRow)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); return GNUNET_SYSERR; } if (SQLITE_OK != sqlite3_reset (plugin->delRow)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); return GNUNET_OK; } /** * Store an item in the datastore. * * @param cls closure * @param key key for the item * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param replication replication-level for the content * @param expiration expiration time for the content * @param msg set to an error message * @return GNUNET_OK on success */ static int sqlite_plugin_put (void *cls, const GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, uint32_t replication, struct GNUNET_TIME_Absolute expiration, char **msg) { struct Plugin *plugin = cls; int n; int ret; sqlite3_stmt *stmt; GNUNET_HashCode vhash; uint64_t rvalue; if (size > MAX_ITEM_SIZE) return GNUNET_SYSERR; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Storing in database block with type %u/key `%s'/priority %u/expiration in %llu ms (%lld).\n", type, GNUNET_h2s (key), priority, (unsigned long long) GNUNET_TIME_absolute_get_remaining (expiration).rel_value, (long long) expiration.abs_value); GNUNET_CRYPTO_hash (data, size, &vhash); stmt = plugin->insertContent; rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, replication)) || (SQLITE_OK != sqlite3_bind_int (stmt, 2, type)) || (SQLITE_OK != sqlite3_bind_int (stmt, 3, priority)) || (SQLITE_OK != sqlite3_bind_int (stmt, 4, anonymity)) || (SQLITE_OK != sqlite3_bind_int64 (stmt, 5, expiration.abs_value)) || (SQLITE_OK != sqlite3_bind_int64 (stmt, 6, rvalue)) || (SQLITE_OK != sqlite3_bind_blob (stmt, 7, key, sizeof (GNUNET_HashCode), SQLITE_TRANSIENT)) || (SQLITE_OK != sqlite3_bind_blob (stmt, 8, &vhash, sizeof (GNUNET_HashCode), SQLITE_TRANSIENT)) || (SQLITE_OK != sqlite3_bind_blob (stmt, 9, data, size, SQLITE_TRANSIENT))) { LOG_SQLITE (plugin, msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); return GNUNET_SYSERR; } n = sqlite3_step (stmt); switch (n) { case SQLITE_DONE: plugin->env->duc (plugin->env->cls, size + GNUNET_DATASTORE_ENTRY_OVERHEAD); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Stored new entry (%u bytes)\n", size + GNUNET_DATASTORE_ENTRY_OVERHEAD); ret = GNUNET_OK; break; case SQLITE_BUSY: GNUNET_break (0); LOG_SQLITE (plugin, msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); ret = GNUNET_SYSERR; break; default: LOG_SQLITE (plugin, msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); database_shutdown (plugin); database_setup (plugin->env->cfg, plugin); return GNUNET_SYSERR; } if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); return ret; } /** * Update the priority for a particular key in the datastore. If * the expiration time in value is different than the time found in * the datastore, the higher value should be kept. For the * anonymity level, the lower value is to be used. The specified * priority should be added to the existing priority, ignoring the * priority in value. * * Note that it is possible for multiple values to match this put. * In that case, all of the respective values are updated. * * @param cls the plugin context (state for this module) * @param uid unique identifier of the datum * @param delta by how much should the priority * change? If priority + delta < 0 the * priority should be set to 0 (never go * negative). * @param expire new expiration time should be the * MAX of any existing expiration time and * this value * @param msg set to an error message * @return GNUNET_OK on success */ static int sqlite_plugin_update (void *cls, uint64_t uid, int delta, struct GNUNET_TIME_Absolute expire, char **msg) { struct Plugin *plugin = cls; int n; if ((SQLITE_OK != sqlite3_bind_int (plugin->updPrio, 1, delta)) || (SQLITE_OK != sqlite3_bind_int64 (plugin->updPrio, 2, expire.abs_value)) || (SQLITE_OK != sqlite3_bind_int64 (plugin->updPrio, 3, uid))) { LOG_SQLITE (plugin, msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); if (SQLITE_OK != sqlite3_reset (plugin->updPrio)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); return GNUNET_SYSERR; } n = sqlite3_step (plugin->updPrio); if (SQLITE_OK != sqlite3_reset (plugin->updPrio)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); switch (n) { case SQLITE_DONE: GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Block updated\n"); return GNUNET_OK; case SQLITE_BUSY: LOG_SQLITE (plugin, msg, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); return GNUNET_NO; default: LOG_SQLITE (plugin, msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); return GNUNET_SYSERR; } } /** * Execute statement that gets a row and call the callback * with the result. Resets the statement afterwards. * * @param plugin the plugin * @param stmt the statement * @param proc processor to call * @param proc_cls closure for 'proc' */ static void execute_get (struct Plugin *plugin, sqlite3_stmt * stmt, PluginDatumProcessor proc, void *proc_cls) { int n; struct GNUNET_TIME_Absolute expiration; unsigned long long rowid; unsigned int size; int ret; n = sqlite3_step (stmt); switch (n) { case SQLITE_ROW: size = sqlite3_column_bytes (stmt, 5); rowid = sqlite3_column_int64 (stmt, 6); if (sqlite3_column_bytes (stmt, 4) != sizeof (GNUNET_HashCode)) { GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite", _ ("Invalid data in database. Trying to fix (by deletion).\n")); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); if (GNUNET_OK == delete_by_rowid (plugin, rowid)) plugin->env->duc (plugin->env->cls, -(size + GNUNET_DATASTORE_ENTRY_OVERHEAD)); break; } expiration.abs_value = sqlite3_column_int64 (stmt, 3); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Found reply in database with expiration %llu\n", (unsigned long long) expiration.abs_value); ret = proc (proc_cls, sqlite3_column_blob (stmt, 4) /* key */ , size, sqlite3_column_blob (stmt, 5) /* data */ , sqlite3_column_int (stmt, 0) /* type */ , sqlite3_column_int (stmt, 1) /* priority */ , sqlite3_column_int (stmt, 2) /* anonymity */ , expiration, rowid); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); if ((GNUNET_NO == ret) && (GNUNET_OK == delete_by_rowid (plugin, rowid))) plugin->env->duc (plugin->env->cls, -(size + GNUNET_DATASTORE_ENTRY_OVERHEAD)); return; case SQLITE_DONE: /* database must be empty */ if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); break; case SQLITE_BUSY: case SQLITE_ERROR: case SQLITE_MISUSE: default: LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); GNUNET_break (0); database_shutdown (plugin); database_setup (plugin->env->cfg, plugin); break; } if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); } /** * Select a subset of the items in the datastore and call * the given processor for the item. * * @param cls our plugin context * @param offset offset of the result (modulo num-results); * specific ordering does not matter for the offset * @param type entries of which type should be considered? * Use 0 for any type. * @param proc function to call on each matching value; * will be called once with a NULL value at the end * @param proc_cls closure for proc */ static void sqlite_plugin_get_zero_anonymity (void *cls, uint64_t offset, enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc, void *proc_cls) { struct Plugin *plugin = cls; sqlite3_stmt *stmt; GNUNET_assert (type != GNUNET_BLOCK_TYPE_ANY); stmt = plugin->selZeroAnon; if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, type)) || (SQLITE_OK != sqlite3_bind_int64 (stmt, 2, offset))) { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } execute_get (plugin, stmt, proc, proc_cls); } /** * Get results for a particular key in the datastore. * * @param cls closure * @param offset offset (mod count). * @param key key to match, never NULL * @param vhash hash of the value, maybe NULL (to * match all values that have the right key). * Note that for DBlocks there is no difference * betwen key and vhash, but for other blocks * there may be! * @param type entries of which type are relevant? * Use 0 for any type. * @param proc function to call on each matching value; * will be called once with a NULL value at the end * @param proc_cls closure for proc */ static void sqlite_plugin_get_key (void *cls, uint64_t offset, const GNUNET_HashCode * key, const GNUNET_HashCode * vhash, enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc, void *proc_cls) { struct Plugin *plugin = cls; int ret; int total; int limit_off; unsigned int sqoff; sqlite3_stmt *stmt; char scratch[256]; GNUNET_assert (proc != NULL); GNUNET_assert (key != NULL); GNUNET_snprintf (scratch, sizeof (scratch), "SELECT count(*) FROM gn090 WHERE hash=?%s%s", vhash == NULL ? "" : " AND vhash=?", type == 0 ? "" : " AND type=?"); if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK) { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite_prepare"); proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } sqoff = 1; ret = sqlite3_bind_blob (stmt, sqoff++, key, sizeof (GNUNET_HashCode), SQLITE_TRANSIENT); if ((vhash != NULL) && (ret == SQLITE_OK)) ret = sqlite3_bind_blob (stmt, sqoff++, vhash, sizeof (GNUNET_HashCode), SQLITE_TRANSIENT); if ((type != 0) && (ret == SQLITE_OK)) ret = sqlite3_bind_int (stmt, sqoff++, type); if (SQLITE_OK != ret) { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite_bind"); sqlite3_finalize (stmt); proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } ret = sqlite3_step (stmt); if (ret != SQLITE_ROW) { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite_step"); sqlite3_finalize (stmt); proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } total = sqlite3_column_int (stmt, 0); sqlite3_finalize (stmt); if (0 == total) { proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } limit_off = (int) (offset % total); if (limit_off < 0) limit_off += total; GNUNET_snprintf (scratch, sizeof (scratch), "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ " "FROM gn090 WHERE hash=?%s%s " "ORDER BY _ROWID_ ASC LIMIT 1 OFFSET ?", vhash == NULL ? "" : " AND vhash=?", type == 0 ? "" : " AND type=?"); if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK) { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite_prepare"); proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } sqoff = 1; ret = sqlite3_bind_blob (stmt, sqoff++, key, sizeof (GNUNET_HashCode), SQLITE_TRANSIENT); if ((vhash != NULL) && (ret == SQLITE_OK)) ret = sqlite3_bind_blob (stmt, sqoff++, vhash, sizeof (GNUNET_HashCode), SQLITE_TRANSIENT); if ((type != 0) && (ret == SQLITE_OK)) ret = sqlite3_bind_int (stmt, sqoff++, type); if (ret == SQLITE_OK) ret = sqlite3_bind_int64 (stmt, sqoff++, limit_off); if (ret != SQLITE_OK) { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite_bind"); proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } execute_get (plugin, stmt, proc, proc_cls); sqlite3_finalize (stmt); } /** * Context for 'repl_proc' function. */ struct ReplCtx { /** * Function to call for the result (or the NULL). */ PluginDatumProcessor proc; /** * Closure for proc. */ void *proc_cls; /** * UID to use. */ uint64_t uid; /** * Yes if UID was set. */ int have_uid; }; /** * Wrapper for the processor for 'sqlite_plugin_replication_get'. * Decrements the replication counter and calls the original * processor. * * @param cls closure * @param key key for the content * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param expiration expiration time for the content * @param uid unique identifier for the datum; * maybe 0 if no unique identifier is available * * @return GNUNET_OK for normal return, * GNUNET_NO to delete the item */ static int repl_proc (void *cls, const GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct ReplCtx *rc = cls; int ret; ret = rc->proc (rc->proc_cls, key, size, data, type, priority, anonymity, expiration, uid); if (key != NULL) { rc->uid = uid; rc->have_uid = GNUNET_YES; } return ret; } /** * Get a random item for replication. Returns a single random item * from those with the highest replication counters. The item's * replication counter is decremented by one IF it was positive before. * Call 'proc' with all values ZERO or NULL if the datastore is empty. * * @param cls closure * @param proc function to call the value (once only). * @param proc_cls closure for proc */ static void sqlite_plugin_get_replication (void *cls, PluginDatumProcessor proc, void *proc_cls) { struct Plugin *plugin = cls; struct ReplCtx rc; uint64_t rvalue; uint32_t repl; sqlite3_stmt *stmt; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Getting random block based on replication order.\n"); rc.have_uid = GNUNET_NO; rc.proc = proc; rc.proc_cls = proc_cls; stmt = plugin->maxRepl; if (SQLITE_ROW != sqlite3_step (stmt)) { if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); /* DB empty */ proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } repl = sqlite3_column_int (stmt, 0); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); stmt = plugin->selRepl; rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); if (SQLITE_OK != sqlite3_bind_int64 (stmt, 1, rvalue)) { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } if (SQLITE_OK != sqlite3_bind_int (stmt, 2, repl)) { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } execute_get (plugin, stmt, &repl_proc, &rc); if (GNUNET_YES == rc.have_uid) { if (SQLITE_OK != sqlite3_bind_int64 (plugin->updRepl, 1, rc.uid)) { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); if (SQLITE_OK != sqlite3_reset (plugin->updRepl)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); return; } if (SQLITE_DONE != sqlite3_step (plugin->updRepl)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); if (SQLITE_OK != sqlite3_reset (plugin->updRepl)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); } } /** * Get a random item that has expired or has low priority. * Call 'proc' with all values ZERO or NULL if the datastore is empty. * * @param cls closure * @param proc function to call the value (once only). * @param proc_cls closure for proc */ static void sqlite_plugin_get_expiration (void *cls, PluginDatumProcessor proc, void *proc_cls) { struct Plugin *plugin = cls; sqlite3_stmt *stmt; struct GNUNET_TIME_Absolute now; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Getting random block based on expiration and priority order.\n"); now = GNUNET_TIME_absolute_get (); stmt = plugin->selExpi; if (SQLITE_OK != sqlite3_bind_int64 (stmt, 1, now.abs_value)) { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } execute_get (plugin, stmt, proc, proc_cls); } /** * Get all of the keys in the datastore. * * @param cls closure * @param proc function to call on each key * @param proc_cls closure for proc */ static void sqlite_plugin_get_keys (void *cls, PluginKeyProcessor proc, void *proc_cls) { struct Plugin *plugin = cls; const GNUNET_HashCode *key; sqlite3_stmt *stmt; int ret; GNUNET_assert (proc != NULL); if (sq_prepare (plugin->dbh, "SELECT hash FROM gn090", &stmt) != SQLITE_OK) { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite_prepare"); return; } while (SQLITE_ROW == (ret = sqlite3_step (stmt))) { key = sqlite3_column_blob (stmt, 1); if (sizeof (GNUNET_HashCode) == sqlite3_column_bytes (stmt, 1)) proc (proc_cls, key, 1); } if (SQLITE_DONE != ret) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite_step"); sqlite3_finalize (stmt); } /** * Drop database. * * @param cls our plugin context */ static void sqlite_plugin_drop (void *cls) { struct Plugin *plugin = cls; plugin->drop_on_shutdown = GNUNET_YES; } /** * Get an estimate of how much space the database is * currently using. * * @param cls the 'struct Plugin' * @return the size of the database on disk (estimate) */ static unsigned long long sqlite_plugin_estimate_size (void *cls) { struct Plugin *plugin = cls; sqlite3_stmt *stmt; uint64_t pages; uint64_t page_size; #if ENULL_DEFINED char *e; #endif if (SQLITE_VERSION_NUMBER < 3006000) { GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "datastore-sqlite", _ ("sqlite version to old to determine size, assuming zero\n")); return 0; } CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "VACUUM", NULL, NULL, ENULL)); CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL", NULL, NULL, ENULL)); CHECK (SQLITE_OK == sq_prepare (plugin->dbh, "PRAGMA page_count", &stmt)); if (SQLITE_ROW == sqlite3_step (stmt)) pages = sqlite3_column_int64 (stmt, 0); else pages = 0; sqlite3_finalize (stmt); CHECK (SQLITE_OK == sq_prepare (plugin->dbh, "PRAGMA page_size", &stmt)); CHECK (SQLITE_ROW == sqlite3_step (stmt)); page_size = sqlite3_column_int64 (stmt, 0); sqlite3_finalize (stmt); GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Using sqlite page utilization to estimate payload (%llu pages of size %llu bytes)\n"), (unsigned long long) pages, (unsigned long long) page_size); return pages * page_size; } /** * Entry point for the plugin. * * @param cls the "struct GNUNET_DATASTORE_PluginEnvironment*" * @return NULL on error, othrewise the plugin context */ void * libgnunet_plugin_datastore_sqlite_init (void *cls) { static struct Plugin plugin; struct GNUNET_DATASTORE_PluginEnvironment *env = cls; struct GNUNET_DATASTORE_PluginFunctions *api; if (plugin.env != NULL) return NULL; /* can only initialize once! */ memset (&plugin, 0, sizeof (struct Plugin)); plugin.env = env; if (GNUNET_OK != database_setup (env->cfg, &plugin)) { database_shutdown (&plugin); return NULL; } api = GNUNET_malloc (sizeof (struct GNUNET_DATASTORE_PluginFunctions)); api->cls = &plugin; api->estimate_size = &sqlite_plugin_estimate_size; api->put = &sqlite_plugin_put; api->update = &sqlite_plugin_update; api->get_key = &sqlite_plugin_get_key; api->get_replication = &sqlite_plugin_get_replication; api->get_expiration = &sqlite_plugin_get_expiration; api->get_zero_anonymity = &sqlite_plugin_get_zero_anonymity; api->get_keys = &sqlite_plugin_get_keys; api->drop = &sqlite_plugin_drop; GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "sqlite", _("Sqlite database running\n")); return api; } /** * Exit point from the plugin. * * @param cls the plugin context (as returned by "init") * @return always NULL */ void * libgnunet_plugin_datastore_sqlite_done (void *cls) { char *fn; struct GNUNET_DATASTORE_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "sqlite plugin is done\n"); fn = NULL; if (plugin->drop_on_shutdown) fn = GNUNET_strdup (plugin->fn); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Shutting down database\n"); database_shutdown (plugin); plugin->env = NULL; GNUNET_free (api); if (fn != NULL) { if (0 != UNLINK (fn)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn); GNUNET_free (fn); } GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "sqlite plugin is finished\n"); return NULL; } /* end of plugin_datastore_sqlite.c */ gnunet-0.9.3/src/datastore/test_datastore_api_data_sqlite.conf0000644000175000017500000000046111654602164021626 00000000000000@INLINE@ test_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-datastore-sqlite/ DEFAULTCONFIG = test_datastore_api_data_sqlite.conf [TESTING] WEAKRANDOM = YES [arm] PORT = 42466 DEFAULTSERVICES = [statistics] PORT = 22667 [resolver] PORT = 42464 [datastore] QUOTA = 10 MB [fs] AUTOSTART = NO gnunet-0.9.3/src/datastore/test_plugin_datastore_data_mysql.conf0000644000175000017500000000033211634323402022205 00000000000000@INLINE@ test_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-datastore-plugin-mysql/ DEFAULTCONFIG = test_plugin_datastore_data_mysql.conf [datastore] DATABASE = mysql [datastore-mysql] DATABASE = gnunetcheck gnunet-0.9.3/src/datastore/test_plugin_datastore.c0000644000175000017500000002466711760502550017310 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * @file test_plugin_datastore.c * @brief Test database plugin directly, calling each API function once * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_protocols.h" #include "gnunet_datastore_plugin.h" #define VERBOSE GNUNET_NO /** * Number of put operations to perform. */ #define PUT_10 10 static unsigned long long stored_bytes; static unsigned long long stored_entries; static unsigned long long stored_ops; static const char *plugin_name; static int ok; enum RunPhase { RP_ERROR = 0, RP_PUT, RP_GET, RP_UPDATE, RP_ITER_ZERO, RP_REPL_GET, RP_EXPI_GET, RP_DROP }; struct CpsRunContext { const struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_DATASTORE_PluginFunctions *api; enum RunPhase phase; unsigned int cnt; unsigned int i; uint64_t offset; }; /** * Function called by plugins to notify us about a * change in their disk utilization. * * @param cls closure (NULL) * @param delta change in disk utilization, * 0 for "reset to empty" */ static void disk_utilization_change_cb (void *cls, int delta) { /* do nothing */ } static void gen_key (int i, GNUNET_HashCode * key) { memset (key, 0, sizeof (GNUNET_HashCode)); key->bits[0] = (unsigned int) i; GNUNET_CRYPTO_hash (key, sizeof (GNUNET_HashCode), key); } static void put_value (struct GNUNET_DATASTORE_PluginFunctions *api, int i, int k) { char value[65536]; size_t size; GNUNET_HashCode key; char *msg; unsigned int prio; /* most content is 32k */ size = 32 * 1024; if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16) == 0) /* but some of it is less! */ size = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 32 * 1024); size = size - (size & 7); /* always multiple of 8 */ /* generate random key */ gen_key (i, &key); memset (value, i, size); if (i > 255) memset (value, i - 255, size / 2); value[0] = k; msg = NULL; prio = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100); #if VERBOSE FPRINTF (stderr, "putting type %u, anon %u under key %s\n", i + 1, i, GNUNET_h2s (&key)); #endif if (GNUNET_OK != api->put (api->cls, &key, size, value, i + 1 /* type */ , prio, i /* anonymity */ , 0 /* replication */ , GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 60 * 60 * 60 * 1000 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000))), &msg)) { FPRINTF (stderr, "ERROR: `%s'\n", msg); GNUNET_free_non_null (msg); return; } stored_bytes += size; stored_ops++; stored_entries++; } static void test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); static uint64_t guid; static int iterate_one_shot (void *cls, const GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct CpsRunContext *crc = cls; GNUNET_assert (key != NULL); guid = uid; crc->phase++; #if VERBOSE FPRINTF (stderr, "Found result type=%u, priority=%u, size=%u, expire=%llu, key %s\n", type, priority, size, (unsigned long long) expiration.abs_value, GNUNET_h2s (key)); #endif GNUNET_SCHEDULER_add_now (&test, crc); return GNUNET_OK; } /** * Function called when the service shuts * down. Unloads our datastore plugin. * * @param api api to unload * @param cfg configuration to use */ static void unload_plugin (struct GNUNET_DATASTORE_PluginFunctions *api, const struct GNUNET_CONFIGURATION_Handle *cfg) { char *name; char *libname; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "DATASTORE", "DATABASE", &name)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("No `%s' specified for `%s' in configuration!\n"), "DATABASE", "DATASTORE"); return; } GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", name); GNUNET_break (NULL == GNUNET_PLUGIN_unload (libname, api)); GNUNET_free (libname); GNUNET_free (name); } /** * Last task run during shutdown. Disconnects us from * the transport and core. */ static void cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct CpsRunContext *crc = cls; unload_plugin (crc->api, crc->cfg); GNUNET_free (crc); } static void test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct CpsRunContext *crc = cls; int j; unsigned long long os; unsigned long long cs; GNUNET_HashCode key; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Test aborted.\n"); crc->phase = RP_ERROR; } #if VERBOSE FPRINTF (stderr, "In phase %d, iteration %u\n", crc->phase, crc->cnt); #endif switch (crc->phase) { case RP_ERROR: ok = 1; GNUNET_break (0); crc->api->drop (crc->api->cls); GNUNET_SCHEDULER_add_now (&cleaning_task, crc); break; case RP_PUT: os = 0; for (j = 0; j < PUT_10; j++) { put_value (crc->api, j, crc->i); cs = crc->api->estimate_size (crc->api->cls); GNUNET_assert (os <= cs); os = cs; } crc->phase++; GNUNET_SCHEDULER_add_now (&test, crc); break; case RP_GET: if (crc->cnt == 1) { crc->cnt = 0; crc->phase++; GNUNET_SCHEDULER_add_now (&test, crc); break; } gen_key (5, &key); crc->api->get_key (crc->api->cls, crc->offset++, &key, NULL, GNUNET_BLOCK_TYPE_ANY, &iterate_one_shot, crc); break; case RP_UPDATE: GNUNET_assert (GNUNET_OK == crc->api->update (crc->api->cls, guid, 1, GNUNET_TIME_UNIT_ZERO_ABS, NULL)); crc->phase++; GNUNET_SCHEDULER_add_now (&test, crc); break; case RP_ITER_ZERO: if (crc->cnt == 1) { crc->cnt = 0; crc->phase++; GNUNET_SCHEDULER_add_now (&test, crc); break; } crc->api->get_zero_anonymity (crc->api->cls, 0, 1, &iterate_one_shot, crc); break; case RP_REPL_GET: crc->api->get_replication (crc->api->cls, &iterate_one_shot, crc); break; case RP_EXPI_GET: crc->api->get_expiration (crc->api->cls, &iterate_one_shot, crc); break; case RP_DROP: crc->api->drop (crc->api->cls); GNUNET_SCHEDULER_add_now (&cleaning_task, crc); break; } } /** * Load the datastore plugin. */ static struct GNUNET_DATASTORE_PluginFunctions * load_plugin (const struct GNUNET_CONFIGURATION_Handle *cfg) { static struct GNUNET_DATASTORE_PluginEnvironment env; struct GNUNET_DATASTORE_PluginFunctions *ret; char *name; char *libname; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "DATASTORE", "DATABASE", &name)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("No `%s' specified for `%s' in configuration!\n"), "DATABASE", "DATASTORE"); return NULL; } env.cfg = cfg; env.duc = &disk_utilization_change_cb; env.cls = NULL; GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' datastore plugin\n"), name); GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", name); if (NULL == (ret = GNUNET_PLUGIN_load (libname, &env))) { FPRINTF (stderr, "Failed to load plugin `%s'!\n", name); return NULL; } GNUNET_free (libname); GNUNET_free (name); return ret; } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { struct GNUNET_DATASTORE_PluginFunctions *api; struct CpsRunContext *crc; api = load_plugin (c); if (api == NULL) { FPRINTF (stderr, "%s", "Could not initialize plugin, assuming database not configured. Test not run!\n"); return; } crc = GNUNET_malloc (sizeof (struct CpsRunContext)); crc->api = api; crc->cfg = c; crc->phase = RP_PUT; GNUNET_SCHEDULER_add_now (&test, crc); } static int check () { char cfg_name[128]; char *const argv[] = { "test-plugin-datastore", "-c", cfg_name, #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_snprintf (cfg_name, sizeof (cfg_name), "test_plugin_datastore_data_%s.conf", plugin_name); GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-plugin-datastore", "nohelp", options, &run, NULL); if (ok != 0) FPRINTF (stderr, "Missed some testcases: %u\n", ok); return ok; } int main (int argc, char *argv[]) { int ret; char *pos; char dir_name[128]; sleep (1); /* determine name of plugin to use */ plugin_name = argv[0]; while (NULL != (pos = strstr (plugin_name, "_"))) plugin_name = pos + 1; if (NULL != (pos = strstr (plugin_name, "."))) pos[0] = 0; else pos = (char *) plugin_name; GNUNET_snprintf (dir_name, sizeof (dir_name), "/tmp/test-gnunet-datastore-plugin-%s", plugin_name); GNUNET_DISK_directory_remove (dir_name); GNUNET_log_setup ("test-plugin-datastore", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); if (pos != plugin_name) pos[0] = '.'; GNUNET_DISK_directory_remove (dir_name); return ret; } /* end of test_plugin_datastore.c */ gnunet-0.9.3/src/datastore/perf_plugin_datastore_data_sqlite.conf0000644000175000017500000000021511634323402022316 00000000000000@INLINE@ test_defaults.conf [PATHS] SERVICEHOME = /tmp/perf-gnunet-datastore-sqlite/ DEFAULTCONFIG = perf_plugin_datastore_data_sqlite.conf gnunet-0.9.3/src/datastore/perf_plugin_datastore.c0000644000175000017500000003375611760502550017264 00000000000000/* This file is part of GNUnet. (C) 2004, 2005, 2006, 2007, 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * @file perf_plugin_datastore.c * @brief Profile database plugin directly, focusing on iterators. * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_protocols.h" #include "gnunet_datastore_plugin.h" #include #define VERBOSE GNUNET_NO /** * Target datastore size (in bytes). Realistic sizes are * more like 16 GB (not the default of 16 MB); however, * those take too long to run them in the usual "make check" * sequence. Hence the value used for shipping is tiny. */ #define MAX_SIZE 1024LL * 1024 * 16 * 1 #define ITERATIONS 2 /** * Number of put operations equivalent to 1/10th of MAX_SIZE */ #define PUT_10 (MAX_SIZE / 32 / 1024 / ITERATIONS) static char category[256]; static unsigned int hits[PUT_10 / 8 + 1]; static unsigned long long stored_bytes; static unsigned long long stored_entries; static unsigned long long stored_ops; static const char *plugin_name; static int ok; enum RunPhase { RP_ERROR = 0, RP_PUT, RP_REP_GET, RP_ZA_GET, RP_EXP_GET, RP_DONE }; struct CpsRunContext { unsigned int i; struct GNUNET_TIME_Absolute start; struct GNUNET_TIME_Absolute end; const struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_DATASTORE_PluginFunctions *api; enum RunPhase phase; unsigned int cnt; unsigned int iter; uint64_t offset; }; /** * Function called by plugins to notify us about a * change in their disk utilization. * * @param cls closure (NULL) * @param delta change in disk utilization, * 0 for "reset to empty" */ static void disk_utilization_change_cb (void *cls, int delta) { } static void putValue (struct GNUNET_DATASTORE_PluginFunctions *api, int i, int k) { char value[65536]; size_t size; static GNUNET_HashCode key; static int ic; char *msg; unsigned int prio; /* most content is 32k */ size = 32 * 1024; if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16) == 0) /* but some of it is less! */ size = 8 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 32 * 1024); size = size - (size & 7); /* always multiple of 8 */ /* generate random key */ key.bits[0] = (unsigned int) GNUNET_TIME_absolute_get ().abs_value; GNUNET_CRYPTO_hash (&key, sizeof (GNUNET_HashCode), &key); memset (value, i, size); if (i > 255) memset (value, i - 255, size / 2); value[0] = k; memcpy (&value[4], &i, sizeof (i)); msg = NULL; prio = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100); if (GNUNET_OK != api->put (api->cls, &key, size, value, 1 + i % 4 /* type */ , prio, i % 4 /* anonymity */ , 0 /* replication */ , GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 60 * 60 * 60 * 1000 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000))), &msg)) { FPRINTF (stderr, "ERROR: `%s'\n", msg); GNUNET_free_non_null (msg); return; } ic++; stored_bytes += size; stored_ops++; stored_entries++; } static void test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); static int iterate_zeros (void *cls, const GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct CpsRunContext *crc = cls; int i; const char *cdata = data; GNUNET_assert (key != NULL); GNUNET_assert (size >= 8); memcpy (&i, &cdata[4], sizeof (i)); hits[i / 8] |= (1 << (i % 8)); #if VERBOSE FPRINTF (stderr, "Found result type=%u, priority=%u, size=%u, expire=%llu\n", type, priority, size, (unsigned long long) expiration.abs_value); #endif crc->cnt++; if (crc->cnt == PUT_10 / 4 - 1) { unsigned int bc; bc = 0; for (i = 0; i < PUT_10; i++) if (0 != (hits[i / 8] & (1 << (i % 8)))) bc++; crc->end = GNUNET_TIME_absolute_get (); printf ("%s took %llu ms yielding %u/%u items\n", "Select random zero-anonymity item", (unsigned long long) (crc->end.abs_value - crc->start.abs_value), bc, crc->cnt); if (crc->cnt > 0) GAUGER (category, "Select random zero-anonymity item", (crc->end.abs_value - crc->start.abs_value) / crc->cnt, "ms/item"); memset (hits, 0, sizeof (hits)); crc->phase++; crc->cnt = 0; crc->start = GNUNET_TIME_absolute_get (); } GNUNET_SCHEDULER_add_now (&test, crc); return GNUNET_OK; } static int expiration_get (void *cls, const GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct CpsRunContext *crc = cls; int i; const char *cdata = data; GNUNET_assert (size >= 8); memcpy (&i, &cdata[4], sizeof (i)); hits[i / 8] |= (1 << (i % 8)); crc->cnt++; if (PUT_10 <= crc->cnt) { unsigned int bc; bc = 0; for (i = 0; i < PUT_10; i++) if (0 != (hits[i / 8] & (1 << (i % 8)))) bc++; crc->end = GNUNET_TIME_absolute_get (); printf ("%s took %llu ms yielding %u/%u items\n", "Selecting and deleting by expiration", (unsigned long long) (crc->end.abs_value - crc->start.abs_value), bc, (unsigned int) PUT_10); if (crc->cnt > 0) GAUGER (category, "Selecting and deleting by expiration", (crc->end.abs_value - crc->start.abs_value) / crc->cnt, "ms/item"); memset (hits, 0, sizeof (hits)); if (++crc->iter == ITERATIONS) crc->phase++; else crc->phase = RP_PUT; crc->cnt = 0; crc->start = GNUNET_TIME_absolute_get (); } GNUNET_SCHEDULER_add_now (&test, crc); return GNUNET_NO; } static int replication_get (void *cls, const GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct CpsRunContext *crc = cls; int i; const char *cdata = data; GNUNET_assert (NULL != key); GNUNET_assert (size >= 8); memcpy (&i, &cdata[4], sizeof (i)); hits[i / 8] |= (1 << (i % 8)); crc->cnt++; if (PUT_10 <= crc->cnt) { unsigned int bc; bc = 0; for (i = 0; i < PUT_10; i++) if (0 != (hits[i / 8] & (1 << (i % 8)))) bc++; crc->end = GNUNET_TIME_absolute_get (); printf ("%s took %llu ms yielding %u/%u items\n", "Selecting random item for replication", (unsigned long long) (crc->end.abs_value - crc->start.abs_value), bc, (unsigned int) PUT_10); if (crc->cnt > 0) GAUGER (category, "Selecting random item for replication", (crc->end.abs_value - crc->start.abs_value) / crc->cnt, "ms/item"); memset (hits, 0, sizeof (hits)); crc->phase++; crc->offset = 0; crc->cnt = 0; crc->start = GNUNET_TIME_absolute_get (); } GNUNET_SCHEDULER_add_now (&test, crc); return GNUNET_OK; } /** * Function called when the service shuts * down. Unloads our datastore plugin. * * @param api api to unload * @param cfg configuration to use */ static void unload_plugin (struct GNUNET_DATASTORE_PluginFunctions *api, const struct GNUNET_CONFIGURATION_Handle *cfg) { char *name; char *libname; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "DATASTORE", "DATABASE", &name)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("No `%s' specified for `%s' in configuration!\n"), "DATABASE", "DATASTORE"); return; } GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", name); GNUNET_break (NULL == GNUNET_PLUGIN_unload (libname, api)); GNUNET_free (libname); GNUNET_free (name); } /** * Last task run during shutdown. Disconnects us from * the transport and core. */ static void cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct CpsRunContext *crc = cls; unload_plugin (crc->api, crc->cfg); GNUNET_free (crc); } static void test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct CpsRunContext *crc = cls; int j; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) { GNUNET_break (0); crc->phase = RP_ERROR; } #if VERBOSE FPRINTF (stderr, "In phase %d, iteration %u\n", crc->phase, crc->cnt); #endif switch (crc->phase) { case RP_ERROR: GNUNET_break (0); crc->api->drop (crc->api->cls); ok = 1; GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, &cleaning_task, crc); break; case RP_PUT: crc->start = GNUNET_TIME_absolute_get (); for (j = 0; j < PUT_10; j++) putValue (crc->api, j, crc->i); crc->end = GNUNET_TIME_absolute_get (); { printf ("%s took %llu ms for %llu items\n", "Storing an item", (unsigned long long) (crc->end.abs_value - crc->start.abs_value), PUT_10); if (PUT_10 > 0) GAUGER (category, "Storing an item", (crc->end.abs_value - crc->start.abs_value) / PUT_10, "ms/item"); } crc->i++; crc->start = GNUNET_TIME_absolute_get (); crc->phase++; GNUNET_SCHEDULER_add_now (&test, crc); break; case RP_REP_GET: crc->api->get_replication (crc->api->cls, &replication_get, crc); break; case RP_ZA_GET: crc->api->get_zero_anonymity (crc->api->cls, crc->offset++, 1, &iterate_zeros, crc); break; case RP_EXP_GET: crc->api->get_expiration (crc->api->cls, &expiration_get, crc); break; case RP_DONE: crc->api->drop (crc->api->cls); ok = 0; GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, &cleaning_task, crc); break; } } /** * Load the datastore plugin. */ static struct GNUNET_DATASTORE_PluginFunctions * load_plugin (const struct GNUNET_CONFIGURATION_Handle *cfg) { static struct GNUNET_DATASTORE_PluginEnvironment env; struct GNUNET_DATASTORE_PluginFunctions *ret; char *name; char *libname; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "DATASTORE", "DATABASE", &name)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("No `%s' specified for `%s' in configuration!\n"), "DATABASE", "DATASTORE"); return NULL; } env.cfg = cfg; env.duc = &disk_utilization_change_cb; env.cls = NULL; GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' datastore plugin\n"), name); GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", name); if (NULL == (ret = GNUNET_PLUGIN_load (libname, &env))) { FPRINTF (stderr, "Failed to load plugin `%s'!\n", name); return NULL; } GNUNET_free (libname); GNUNET_free (name); return ret; } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { struct GNUNET_DATASTORE_PluginFunctions *api; struct CpsRunContext *crc; api = load_plugin (c); if (api == NULL) { FPRINTF (stderr, "%s", "Could not initialize plugin, assuming database not configured. Test not run!\n"); return; } crc = GNUNET_malloc (sizeof (struct CpsRunContext)); crc->api = api; crc->cfg = c; crc->phase = RP_PUT; ok = 2; GNUNET_SCHEDULER_add_now (&test, crc); } static int check () { char cfg_name[128]; char *const argv[] = { "perf-plugin-datastore", "-c", cfg_name, #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_snprintf (category, sizeof (category), "DATASTORE-%s", plugin_name); GNUNET_snprintf (cfg_name, sizeof (cfg_name), "perf_plugin_datastore_data_%s.conf", plugin_name); GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "perf-plugin-datastore", "nohelp", options, &run, NULL); if (ok != 0) FPRINTF (stderr, "Missed some testcases: %u\n", ok); return ok; } int main (int argc, char *argv[]) { int ret; char *pos; char dir_name[128]; sleep (1); /* determine name of plugin to use */ plugin_name = argv[0]; while (NULL != (pos = strstr (plugin_name, "_"))) plugin_name = pos + 1; if (NULL != (pos = strstr (plugin_name, "."))) pos[0] = 0; else pos = (char *) plugin_name; GNUNET_snprintf (dir_name, sizeof (dir_name), "/tmp/perf-gnunet-datastore-%s", plugin_name); GNUNET_DISK_directory_remove (dir_name); GNUNET_log_setup ("perf-plugin-datastore", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); if (pos != plugin_name) pos[0] = '.'; GNUNET_DISK_directory_remove (dir_name); return ret; } /* end of perf_plugin_datastore.c */ gnunet-0.9.3/src/datastore/datastore.conf.in0000644000175000017500000000121111760502552015761 00000000000000[datastore] AUTOSTART = YES UNIXPATH = /tmp/gnunet-service-datastore.sock UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES @UNIXONLY@ PORT = 2093 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-datastore ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; QUOTA = 100 MB BLOOMFILTER = $SERVICEHOME/datastore/bloomfilter DATABASE = sqlite # DISABLE_SOCKET_FORWARDING = NO [datastore-sqlite] FILENAME = $SERVICEHOME/datastore/sqlite.db [datastore-postgres] CONFIG = connect_timeout=10; dbname=gnunet [datastore-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf # USER = gnunet # PASSWORD = # HOST = localhost # PORT = 3306 gnunet-0.9.3/src/datastore/test_datastore_api_data_postgres.conf0000644000175000017500000000057311654602174022200 00000000000000@INLINE@ test_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-datastore-postgres/ DEFAULTCONFIG = test_datastore_api_data_postgres.conf [TESTING] WEAKRANDOM = YES [arm] PORT = 42466 DEFAULTSERVICES = [statistics] PORT = 22667 [resolver] PORT = 42464 [datastore] QUOTA = 10 MB DATABASE = postgres [datastore-postgres] CONFIG = dbname=gnunetcheck [fs] AUTOSTART = NO gnunet-0.9.3/src/datastore/test_datastore_api_data_mysql.conf0000644000175000017500000000055211654602203021465 00000000000000@INLINE@ test_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-datastore-mysql/ DEFAULTCONFIG = test_datastore_api_data_mysql.conf [TESTING] WEAKRANDOM = YES [arm] PORT = 42466 DEFAULTSERVICES = [statistics] PORT = 22667 [resolver] PORT = 42464 [datastore] QUOTA = 10 MB DATABASE = mysql [datastore-mysql] DATABASE = gnunetcheck [fs] AUTOSTART = NO gnunet-0.9.3/src/datastore/plugin_datastore_mysql.c0000644000175000017500000010500711760502550017462 00000000000000/* This file is part of GNUnet (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file datastore/plugin_datastore_mysql.c * @brief mysql-based datastore backend * @author Igor Wronsky * @author Christian Grothoff * * NOTE: This db module does NOT work with mysql prior to 4.1 since * it uses prepared statements. MySQL 5.0.46 promises to fix a bug * in MyISAM that is causing us grief. At the time of this writing, * that version is yet to be released. In anticipation, the code * will use MyISAM with 5.0.46 (and higher). If you run such a * version, please run "make check" to verify that the MySQL bug * was actually fixed in your version (and if not, change the * code below to use MyISAM for gn071). * * HIGHLIGHTS * * Pros * + On up-to-date hardware where mysql can be used comfortably, this * module will have better performance than the other db choices * (according to our tests). * + Its often possible to recover the mysql database from internal * inconsistencies. The other db choices do not support repair! * Cons * - Memory usage (Comment: "I have 1G and it never caused me trouble") * - Manual setup * * MANUAL SETUP INSTRUCTIONS * * 1) in /etc/gnunet.conf, set * @verbatim [datastore] DATABASE = "mysql" @endverbatim * 2) Then access mysql as root, * @verbatim $ mysql -u root -p @endverbatim * and do the following. [You should replace $USER with the username * that will be running the gnunetd process]. * @verbatim CREATE DATABASE gnunet; GRANT select,insert,update,delete,create,alter,drop,create temporary tables ON gnunet.* TO $USER@localhost; SET PASSWORD FOR $USER@localhost=PASSWORD('$the_password_you_like'); FLUSH PRIVILEGES; @endverbatim * 3) In the $HOME directory of $USER, create a ".my.cnf" file * with the following lines * @verbatim [client] user=$USER password=$the_password_you_like @endverbatim * * Thats it. Note that .my.cnf file is a security risk unless its on * a safe partition etc. The $HOME/.my.cnf can of course be a symbolic * link. Even greater security risk can be achieved by setting no * password for $USER. Luckily $USER has only priviledges to mess * up GNUnet's tables, nothing else (unless you give him more, * of course).

    * * 4) Still, perhaps you should briefly try if the DB connection * works. First, login as $USER. Then use, * * @verbatim $ mysql -u $USER -p $the_password_you_like mysql> use gnunet; @endverbatim * * If you get the message "Database changed" it probably works. * * [If you get "ERROR 2002: Can't connect to local MySQL server * through socket '/tmp/mysql.sock' (2)" it may be resolvable by * "ln -s /var/run/mysqld/mysqld.sock /tmp/mysql.sock" * so there may be some additional trouble depending on your mysql setup.] * * REPAIRING TABLES * * - Its probably healthy to check your tables for inconsistencies * every now and then. * - If you get odd SEGVs on gnunetd startup, it might be that the mysql * databases have been corrupted. * - The tables can be verified/fixed in two ways; * 1) by running mysqlcheck -A, or * 2) by executing (inside of mysql using the GNUnet database): * @verbatim mysql> REPAIR TABLE gn090; @endverbatim * * PROBLEMS? * * If you have problems related to the mysql module, your best * friend is probably the mysql manual. The first thing to check * is that mysql is basically operational, that you can connect * to it, create tables, issue queries etc. */ #include "platform.h" #include "gnunet_datastore_plugin.h" #include "gnunet_util_lib.h" #include "gnunet_mysql_lib.h" #define MAX_DATUM_SIZE 65536 /** * Context for all functions in this plugin. */ struct Plugin { /** * Our execution environment. */ struct GNUNET_DATASTORE_PluginEnvironment *env; /** * Handle to talk to MySQL. */ struct GNUNET_MYSQL_Context *mc; /** * Prepared statements. */ #define INSERT_ENTRY "INSERT INTO gn090 (repl,type,prio,anonLevel,expire,rvalue,hash,vhash,value) VALUES (?,?,?,?,?,?,?,?,?)" struct GNUNET_MYSQL_StatementHandle *insert_entry; #define DELETE_ENTRY_BY_UID "DELETE FROM gn090 WHERE uid=?" struct GNUNET_MYSQL_StatementHandle *delete_entry_by_uid; #define COUNT_ENTRY_BY_HASH "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash) WHERE hash=?" struct GNUNET_MYSQL_StatementHandle *count_entry_by_hash; #define SELECT_ENTRY_BY_HASH "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash) WHERE hash=? ORDER BY uid LIMIT 1 OFFSET ?" struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash; #define COUNT_ENTRY_BY_HASH_AND_VHASH "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=?" struct GNUNET_MYSQL_StatementHandle *count_entry_by_hash_and_vhash; #define SELECT_ENTRY_BY_HASH_AND_VHASH "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=? ORDER BY uid LIMIT 1 OFFSET ?" struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_and_vhash; #define COUNT_ENTRY_BY_HASH_AND_TYPE "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash_type_uid) WHERE hash=? AND type=?" struct GNUNET_MYSQL_StatementHandle *count_entry_by_hash_and_type; #define SELECT_ENTRY_BY_HASH_AND_TYPE "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash_type_uid) WHERE hash=? AND type=? ORDER BY uid LIMIT 1 OFFSET ?" struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_and_type; #define COUNT_ENTRY_BY_HASH_VHASH_AND_TYPE "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=? AND type=?" struct GNUNET_MYSQL_StatementHandle *count_entry_by_hash_vhash_and_type; #define SELECT_ENTRY_BY_HASH_VHASH_AND_TYPE "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=? AND type=? ORDER BY uid ASC LIMIT 1 OFFSET ?" struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_vhash_and_type; #define UPDATE_ENTRY "UPDATE gn090 SET prio=prio+?,expire=IF(expire>=?,expire,?) WHERE uid=?" struct GNUNET_MYSQL_StatementHandle *update_entry; #define DEC_REPL "UPDATE gn090 SET repl=GREATEST (0, repl - 1) WHERE uid=?" struct GNUNET_MYSQL_StatementHandle *dec_repl; #define SELECT_SIZE "SELECT SUM(BIT_LENGTH(value) DIV 8) FROM gn090" struct GNUNET_MYSQL_StatementHandle *get_size; #define SELECT_IT_NON_ANONYMOUS "SELECT type,prio,anonLevel,expire,hash,value,uid "\ "FROM gn090 FORCE INDEX (idx_anonLevel_type_rvalue) "\ "WHERE anonLevel=0 AND type=? AND "\ "(rvalue >= ? OR"\ " NOT EXISTS (SELECT 1 FROM gn090 FORCE INDEX (idx_anonLevel_type_rvalue) WHERE anonLevel=0 AND type=? AND rvalue>=?)) "\ "ORDER BY rvalue ASC LIMIT 1" struct GNUNET_MYSQL_StatementHandle *zero_iter; #define SELECT_IT_EXPIRATION "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_expire) WHERE expire < ? ORDER BY expire ASC LIMIT 1" struct GNUNET_MYSQL_StatementHandle *select_expiration; #define SELECT_IT_PRIORITY "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_prio) ORDER BY prio ASC LIMIT 1" struct GNUNET_MYSQL_StatementHandle *select_priority; #define SELECT_IT_REPLICATION "SELECT type,prio,anonLevel,expire,hash,value,uid "\ "FROM gn090 FORCE INDEX (idx_repl_rvalue) "\ "WHERE repl=? AND "\ " (rvalue>=? OR"\ " NOT EXISTS (SELECT 1 FROM gn090 FORCE INDEX (idx_repl_rvalue) WHERE repl=? AND rvalue>=?)) "\ "ORDER BY rvalue ASC "\ "LIMIT 1" struct GNUNET_MYSQL_StatementHandle *select_replication; #define SELECT_MAX_REPL "SELECT MAX(repl) FROM gn090" struct GNUNET_MYSQL_StatementHandle *max_repl; #define GET_ALL_KEYS "SELECT hash from gn090" struct GNUNET_MYSQL_StatementHandle *get_all_keys; }; /** * Delete an entry from the gn090 table. * * @param plugin plugin context * @param uid unique ID of the entry to delete * @return GNUNET_OK on success, GNUNET_NO if no such value exists, GNUNET_SYSERR on error */ static int do_delete_entry (struct Plugin *plugin, unsigned long long uid) { int ret; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting value %llu from gn090 table\n", uid); ret = GNUNET_MYSQL_statement_run_prepared (plugin->mc, plugin->delete_entry_by_uid, NULL, MYSQL_TYPE_LONGLONG, &uid, GNUNET_YES, -1); if (ret >= 0) return GNUNET_OK; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Deleting value %llu from gn090 table failed\n", uid); return ret; } /** * Get an estimate of how much space the database is * currently using. * * @param cls our "struct Plugin *" * @return number of bytes used on disk */ static unsigned long long mysql_plugin_estimate_size (void *cls) { struct Plugin *plugin = cls; MYSQL_BIND cbind[1]; long long total; memset (cbind, 0, sizeof (cbind)); total = 0; cbind[0].buffer_type = MYSQL_TYPE_LONGLONG; cbind[0].buffer = &total; cbind[0].is_unsigned = GNUNET_NO; if (GNUNET_OK != GNUNET_MYSQL_statement_run_prepared_select (plugin->mc, plugin->get_size, 1, cbind, NULL, NULL, -1)) return 0; return total; } /** * Store an item in the datastore. * * @param cls closure * @param key key for the item * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param replication replication-level for the content * @param expiration expiration time for the content * @param msg set to error message * @return GNUNET_OK on success */ static int mysql_plugin_put (void *cls, const GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, uint32_t replication, struct GNUNET_TIME_Absolute expiration, char **msg) { struct Plugin *plugin = cls; unsigned int irepl = replication; unsigned int ipriority = priority; unsigned int ianonymity = anonymity; unsigned long long lexpiration = expiration.abs_value; unsigned long long lrvalue = (unsigned long long) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); unsigned long hashSize; unsigned long hashSize2; unsigned long lsize; GNUNET_HashCode vhash; if (size > MAX_DATUM_SIZE) { GNUNET_break (0); return GNUNET_SYSERR; } hashSize = sizeof (GNUNET_HashCode); hashSize2 = sizeof (GNUNET_HashCode); lsize = size; GNUNET_CRYPTO_hash (data, size, &vhash); if (GNUNET_OK != GNUNET_MYSQL_statement_run_prepared (plugin->mc, plugin->insert_entry, NULL, MYSQL_TYPE_LONG, &irepl, GNUNET_YES, MYSQL_TYPE_LONG, &type, GNUNET_YES, MYSQL_TYPE_LONG, &ipriority, GNUNET_YES, MYSQL_TYPE_LONG, &ianonymity, GNUNET_YES, MYSQL_TYPE_LONGLONG, &lexpiration, GNUNET_YES, MYSQL_TYPE_LONGLONG, &lrvalue, GNUNET_YES, MYSQL_TYPE_BLOB, key, hashSize, &hashSize, MYSQL_TYPE_BLOB, &vhash, hashSize2, &hashSize2, MYSQL_TYPE_BLOB, data, lsize, &lsize, -1)) return GNUNET_SYSERR; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Inserted value `%s' with size %u into gn090 table\n", GNUNET_h2s (key), (unsigned int) size); if (size > 0) plugin->env->duc (plugin->env->cls, size); return GNUNET_OK; } /** * Update the priority for a particular key in the datastore. If * the expiration time in value is different than the time found in * the datastore, the higher value should be kept. For the * anonymity level, the lower value is to be used. The specified * priority should be added to the existing priority, ignoring the * priority in value. * * Note that it is possible for multiple values to match this put. * In that case, all of the respective values are updated. * * @param cls our "struct Plugin*" * @param uid unique identifier of the datum * @param delta by how much should the priority * change? If priority + delta < 0 the * priority should be set to 0 (never go * negative). * @param expire new expiration time should be the * MAX of any existing expiration time and * this value * @param msg set to error message * @return GNUNET_OK on success */ static int mysql_plugin_update (void *cls, uint64_t uid, int delta, struct GNUNET_TIME_Absolute expire, char **msg) { struct Plugin *plugin = cls; unsigned long long vkey = uid; unsigned long long lexpire = expire.abs_value; int ret; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating value %llu adding %d to priority and maxing exp at %llu\n", vkey, delta, lexpire); ret = GNUNET_MYSQL_statement_run_prepared (plugin->mc, plugin->update_entry, NULL, MYSQL_TYPE_LONG, &delta, GNUNET_NO, MYSQL_TYPE_LONGLONG, &lexpire, GNUNET_YES, MYSQL_TYPE_LONGLONG, &lexpire, GNUNET_YES, MYSQL_TYPE_LONGLONG, &vkey, GNUNET_YES, -1); if (ret != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to update value %llu\n", vkey); } return ret; } /** * Run the given select statement and call 'proc' on the resulting * values (which must be in particular positions). * * @param plugin the plugin handle * @param stmt select statement to run * @param proc function to call on result * @param proc_cls closure for proc * @param ... arguments to initialize stmt */ static void execute_select (struct Plugin *plugin, struct GNUNET_MYSQL_StatementHandle *stmt, PluginDatumProcessor proc, void *proc_cls, ...) { va_list ap; int ret; unsigned int type; unsigned int priority; unsigned int anonymity; unsigned long long exp; unsigned long hashSize; unsigned long size; unsigned long long uid; char value[GNUNET_DATASTORE_MAX_VALUE_SIZE]; GNUNET_HashCode key; struct GNUNET_TIME_Absolute expiration; MYSQL_BIND rbind[7]; hashSize = sizeof (GNUNET_HashCode); memset (rbind, 0, sizeof (rbind)); rbind[0].buffer_type = MYSQL_TYPE_LONG; rbind[0].buffer = &type; rbind[0].is_unsigned = 1; rbind[1].buffer_type = MYSQL_TYPE_LONG; rbind[1].buffer = &priority; rbind[1].is_unsigned = 1; rbind[2].buffer_type = MYSQL_TYPE_LONG; rbind[2].buffer = &anonymity; rbind[2].is_unsigned = 1; rbind[3].buffer_type = MYSQL_TYPE_LONGLONG; rbind[3].buffer = &exp; rbind[3].is_unsigned = 1; rbind[4].buffer_type = MYSQL_TYPE_BLOB; rbind[4].buffer = &key; rbind[4].buffer_length = hashSize; rbind[4].length = &hashSize; rbind[5].buffer_type = MYSQL_TYPE_BLOB; rbind[5].buffer = value; rbind[5].buffer_length = size = sizeof (value); rbind[5].length = &size; rbind[6].buffer_type = MYSQL_TYPE_LONGLONG; rbind[6].buffer = &uid; rbind[6].is_unsigned = 1; va_start (ap, proc_cls); ret = GNUNET_MYSQL_statement_run_prepared_select_va (plugin->mc, stmt, 7, rbind, NULL, NULL, ap); va_end (ap); if (ret <= 0) { proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } GNUNET_assert (size <= sizeof (value)); if ((rbind[4].buffer_length != sizeof (GNUNET_HashCode)) || (hashSize != sizeof (GNUNET_HashCode))) { GNUNET_break (0); proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found %u-byte value under key `%s' with prio %u, anon %u, expire %llu selecting from gn090 table\n", (unsigned int) size, GNUNET_h2s (&key), priority, anonymity, exp); GNUNET_assert (size < MAX_DATUM_SIZE); expiration.abs_value = exp; ret = proc (proc_cls, &key, size, value, type, priority, anonymity, expiration, uid); if (ret == GNUNET_NO) { do_delete_entry (plugin, uid); if (size != 0) plugin->env->duc (plugin->env->cls, -size); } } /** * Get one of the results for a particular key in the datastore. * * @param cls closure * @param offset offset of the result (modulo num-results); * specific ordering does not matter for the offset * @param key key to match, never NULL * @param vhash hash of the value, maybe NULL (to * match all values that have the right key). * Note that for DBlocks there is no difference * betwen key and vhash, but for other blocks * there may be! * @param type entries of which type are relevant? * Use 0 for any type. * @param proc function to call on the matching value, * with NULL for if no value matches * @param proc_cls closure for proc */ static void mysql_plugin_get_key (void *cls, uint64_t offset, const GNUNET_HashCode * key, const GNUNET_HashCode * vhash, enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc, void *proc_cls) { struct Plugin *plugin = cls; int ret; MYSQL_BIND cbind[1]; long long total; unsigned long hashSize; unsigned long hashSize2; unsigned long long off; GNUNET_assert (key != NULL); GNUNET_assert (NULL != proc); hashSize = sizeof (GNUNET_HashCode); hashSize2 = sizeof (GNUNET_HashCode); memset (cbind, 0, sizeof (cbind)); total = -1; cbind[0].buffer_type = MYSQL_TYPE_LONGLONG; cbind[0].buffer = &total; cbind[0].is_unsigned = GNUNET_NO; if (type != 0) { if (vhash != NULL) { ret = GNUNET_MYSQL_statement_run_prepared_select (plugin->mc, plugin-> count_entry_by_hash_vhash_and_type, 1, cbind, NULL, NULL, MYSQL_TYPE_BLOB, key, hashSize, &hashSize, MYSQL_TYPE_BLOB, vhash, hashSize2, &hashSize2, MYSQL_TYPE_LONG, &type, GNUNET_YES, -1); } else { ret = GNUNET_MYSQL_statement_run_prepared_select (plugin->mc, plugin->count_entry_by_hash_and_type, 1, cbind, NULL, NULL, MYSQL_TYPE_BLOB, key, hashSize, &hashSize, MYSQL_TYPE_LONG, &type, GNUNET_YES, -1); } } else { if (vhash != NULL) { ret = GNUNET_MYSQL_statement_run_prepared_select (plugin->mc, plugin->count_entry_by_hash_and_vhash, 1, cbind, NULL, NULL, MYSQL_TYPE_BLOB, key, hashSize, &hashSize, MYSQL_TYPE_BLOB, vhash, hashSize2, &hashSize2, -1); } else { ret = GNUNET_MYSQL_statement_run_prepared_select (plugin->mc, plugin->count_entry_by_hash, 1, cbind, NULL, NULL, MYSQL_TYPE_BLOB, key, hashSize, &hashSize, -1); } } if ((ret != GNUNET_OK) || (0 >= total)) { proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } offset = offset % total; off = (unsigned long long) offset; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Obtaining %llu/%lld result for GET `%s'\n", off, total, GNUNET_h2s (key)); if (type != GNUNET_BLOCK_TYPE_ANY) { if (NULL != vhash) { execute_select (plugin, plugin->select_entry_by_hash_vhash_and_type, proc, proc_cls, MYSQL_TYPE_BLOB, key, hashSize, &hashSize, MYSQL_TYPE_BLOB, vhash, hashSize, &hashSize, MYSQL_TYPE_LONG, &type, GNUNET_YES, MYSQL_TYPE_LONGLONG, &off, GNUNET_YES, -1); } else { execute_select (plugin, plugin->select_entry_by_hash_and_type, proc, proc_cls, MYSQL_TYPE_BLOB, key, hashSize, &hashSize, MYSQL_TYPE_LONG, &type, GNUNET_YES, MYSQL_TYPE_LONGLONG, &off, GNUNET_YES, -1); } } else { if (NULL != vhash) { execute_select (plugin, plugin->select_entry_by_hash_and_vhash, proc, proc_cls, MYSQL_TYPE_BLOB, key, hashSize, &hashSize, MYSQL_TYPE_BLOB, vhash, hashSize, &hashSize, MYSQL_TYPE_LONGLONG, &off, GNUNET_YES, -1); } else { execute_select (plugin, plugin->select_entry_by_hash, proc, proc_cls, MYSQL_TYPE_BLOB, key, hashSize, &hashSize, MYSQL_TYPE_LONGLONG, &off, GNUNET_YES, -1); } } } /** * Get a zero-anonymity datum from the datastore. * * @param cls our "struct Plugin*" * @param offset offset of the result * @param type entries of which type should be considered? * Use 0 for any type. * @param proc function to call on a matching value or NULL * @param proc_cls closure for iter */ static void mysql_plugin_get_zero_anonymity (void *cls, uint64_t offset, enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc, void *proc_cls) { struct Plugin *plugin = cls; unsigned long long rvalue = (unsigned long long) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); execute_select (plugin, plugin->zero_iter, proc, proc_cls, MYSQL_TYPE_LONG, &type, GNUNET_YES, MYSQL_TYPE_LONGLONG, &rvalue, GNUNET_YES, MYSQL_TYPE_LONG, &type, GNUNET_YES, MYSQL_TYPE_LONGLONG, &rvalue, GNUNET_YES, -1); } /** * Context for 'repl_proc' function. */ struct ReplCtx { /** * Plugin handle. */ struct Plugin *plugin; /** * Function to call for the result (or the NULL). */ PluginDatumProcessor proc; /** * Closure for proc. */ void *proc_cls; }; /** * Wrapper for the processor for 'mysql_plugin_get_replication'. * Decrements the replication counter and calls the original * iterator. * * @param cls closure * @param key key for the content * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param expiration expiration time for the content * @param uid unique identifier for the datum; * maybe 0 if no unique identifier is available * * @return GNUNET_SYSERR to abort the iteration, GNUNET_OK to continue * (continue on call to "next", of course), * GNUNET_NO to delete the item and continue (if supported) */ static int repl_proc (void *cls, const GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct ReplCtx *rc = cls; struct Plugin *plugin = rc->plugin; unsigned long long oid; int ret; int iret; ret = rc->proc (rc->proc_cls, key, size, data, type, priority, anonymity, expiration, uid); if (NULL != key) { oid = (unsigned long long) uid; iret = GNUNET_MYSQL_statement_run_prepared (plugin->mc, plugin->dec_repl, NULL, MYSQL_TYPE_LONGLONG, &oid, GNUNET_YES, -1); if (iret == GNUNET_SYSERR) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to reduce replication counter\n"); return GNUNET_SYSERR; } } return ret; } /** * Get a random item for replication. Returns a single, not expired, * random item from those with the highest replication counters. The * item's replication counter is decremented by one IF it was positive * before. Call 'proc' with all values ZERO or NULL if the datastore * is empty. * * @param cls closure * @param proc function to call the value (once only). * @param proc_cls closure for proc */ static void mysql_plugin_get_replication (void *cls, PluginDatumProcessor proc, void *proc_cls) { struct Plugin *plugin = cls; struct ReplCtx rc; unsigned long long rvalue; unsigned long repl; MYSQL_BIND results; rc.plugin = plugin; rc.proc = proc; rc.proc_cls = proc_cls; memset (&results, 0, sizeof (results)); results.buffer_type = MYSQL_TYPE_LONG; results.buffer = &repl; results.is_unsigned = GNUNET_YES; if (1 != GNUNET_MYSQL_statement_run_prepared_select (plugin->mc, plugin->max_repl, 1, &results, NULL, NULL, -1)) { proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } rvalue = (unsigned long long) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); execute_select (plugin, plugin->select_replication, &repl_proc, &rc, MYSQL_TYPE_LONG, &repl, GNUNET_YES, MYSQL_TYPE_LONGLONG, &rvalue, GNUNET_YES, MYSQL_TYPE_LONG, &repl, GNUNET_YES, MYSQL_TYPE_LONGLONG, &rvalue, GNUNET_YES, -1); } /** * Get all of the keys in the datastore. * * @param cls closure * @param proc function to call on each key * @param proc_cls closure for proc */ static void mysql_plugin_get_keys (void *cls, PluginKeyProcessor proc, void *proc_cls) { struct Plugin *plugin = cls; const char *query = "SELECT hash FROM gn090"; int ret; MYSQL_STMT *statement; GNUNET_HashCode key; MYSQL_BIND cbind[1]; unsigned long length; statement = GNUNET_MYSQL_statement_get_stmt (plugin->mc, plugin->get_all_keys); if (statement == NULL) { GNUNET_MYSQL_statements_invalidate (plugin->mc); return; } if (mysql_stmt_prepare (statement, query, strlen (query))) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "mysql", _("Failed to prepare statement `%s'\n"), query); GNUNET_MYSQL_statements_invalidate (plugin->mc); return; } GNUNET_assert (proc != NULL); if (mysql_stmt_execute (statement)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("`%s' for `%s' failed at %s:%d with error: %s\n"), "mysql_stmt_execute", query, __FILE__, __LINE__, mysql_stmt_error (statement)); GNUNET_MYSQL_statements_invalidate (plugin->mc); return; } memset (cbind, 0, sizeof (cbind)); cbind[0].buffer_type = MYSQL_TYPE_BLOB; cbind[0].buffer = &key; cbind[0].buffer_length = sizeof (key); cbind[0].length = &length; cbind[0].is_unsigned = GNUNET_NO; if (mysql_stmt_bind_result (statement, cbind)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("`%s' failed at %s:%d with error: %s\n"), "mysql_stmt_bind_result", __FILE__, __LINE__, mysql_stmt_error (statement)); GNUNET_MYSQL_statements_invalidate (plugin->mc); return; } while (0 == (ret = mysql_stmt_fetch (statement))) { if (sizeof (GNUNET_HashCode) == length) proc (proc_cls, &key, 1); } if (ret != MYSQL_NO_DATA) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("`%s' failed at %s:%d with error: %s\n"), "mysql_stmt_fetch", __FILE__, __LINE__, mysql_stmt_error (statement)); GNUNET_MYSQL_statements_invalidate (plugin->mc); return; } mysql_stmt_reset (statement); } /** * Context for 'expi_proc' function. */ struct ExpiCtx { /** * Plugin handle. */ struct Plugin *plugin; /** * Function to call for the result (or the NULL). */ PluginDatumProcessor proc; /** * Closure for proc. */ void *proc_cls; }; /** * Wrapper for the processor for 'mysql_plugin_get_expiration'. * If no expired value was found, we do a second query for * low-priority content. * * @param cls closure * @param key key for the content * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param expiration expiration time for the content * @param uid unique identifier for the datum; * maybe 0 if no unique identifier is available * * @return GNUNET_SYSERR to abort the iteration, GNUNET_OK to continue * (continue on call to "next", of course), * GNUNET_NO to delete the item and continue (if supported) */ static int expi_proc (void *cls, const GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct ExpiCtx *rc = cls; struct Plugin *plugin = rc->plugin; if (NULL == key) { execute_select (plugin, plugin->select_priority, rc->proc, rc->proc_cls, -1); return GNUNET_SYSERR; } return rc->proc (rc->proc_cls, key, size, data, type, priority, anonymity, expiration, uid); } /** * Get a random item for expiration. * Call 'proc' with all values ZERO or NULL if the datastore is empty. * * @param cls closure * @param proc function to call the value (once only). * @param proc_cls closure for proc */ static void mysql_plugin_get_expiration (void *cls, PluginDatumProcessor proc, void *proc_cls) { struct Plugin *plugin = cls; long long nt; struct ExpiCtx rc; rc.plugin = plugin; rc.proc = proc; rc.proc_cls = proc_cls; nt = (long long) GNUNET_TIME_absolute_get ().abs_value; execute_select (plugin, plugin->select_expiration, expi_proc, &rc, MYSQL_TYPE_LONGLONG, &nt, GNUNET_YES, -1); } /** * Drop database. * * @param cls the "struct Plugin*" */ static void mysql_plugin_drop (void *cls) { struct Plugin *plugin = cls; if (GNUNET_OK != GNUNET_MYSQL_statement_run (plugin->mc, "DROP TABLE gn090")) return; /* error */ plugin->env->duc (plugin->env->cls, 0); } /** * Entry point for the plugin. * * @param cls the "struct GNUNET_DATASTORE_PluginEnvironment*" * @return our "struct Plugin*" */ void * libgnunet_plugin_datastore_mysql_init (void *cls) { struct GNUNET_DATASTORE_PluginEnvironment *env = cls; struct GNUNET_DATASTORE_PluginFunctions *api; struct Plugin *plugin; plugin = GNUNET_malloc (sizeof (struct Plugin)); plugin->env = env; plugin->mc = GNUNET_MYSQL_context_create (env->cfg, "datastore-mysql"); if (NULL == plugin->mc) { GNUNET_free (plugin); return NULL; } #define MRUNS(a) (GNUNET_OK != GNUNET_MYSQL_statement_run (plugin->mc, a) ) #define PINIT(a,b) (NULL == (a = GNUNET_MYSQL_statement_prepare (plugin->mc, b))) if (MRUNS ("CREATE TABLE IF NOT EXISTS gn090 (" " repl INT(11) UNSIGNED NOT NULL DEFAULT 0," " type INT(11) UNSIGNED NOT NULL DEFAULT 0," " prio INT(11) UNSIGNED NOT NULL DEFAULT 0," " anonLevel INT(11) UNSIGNED NOT NULL DEFAULT 0," " expire BIGINT UNSIGNED NOT NULL DEFAULT 0," " rvalue BIGINT UNSIGNED NOT NULL," " hash BINARY(64) NOT NULL DEFAULT ''," " vhash BINARY(64) NOT NULL DEFAULT ''," " value BLOB NOT NULL DEFAULT ''," " uid BIGINT NOT NULL AUTO_INCREMENT," " PRIMARY KEY (uid)," " INDEX idx_hash (hash(64))," " INDEX idx_hash_uid (hash(64),uid)," " INDEX idx_hash_vhash (hash(64),vhash(64))," " INDEX idx_hash_type_uid (hash(64),type,rvalue)," " INDEX idx_prio (prio)," " INDEX idx_repl_rvalue (repl,rvalue)," " INDEX idx_expire (expire)," " INDEX idx_anonLevel_type_rvalue (anonLevel,type,rvalue)" ") ENGINE=InnoDB") || MRUNS ("SET AUTOCOMMIT = 1") || PINIT (plugin->insert_entry, INSERT_ENTRY) || PINIT (plugin->delete_entry_by_uid, DELETE_ENTRY_BY_UID) || PINIT (plugin->select_entry_by_hash, SELECT_ENTRY_BY_HASH) || PINIT (plugin->select_entry_by_hash_and_vhash, SELECT_ENTRY_BY_HASH_AND_VHASH) || PINIT (plugin->select_entry_by_hash_and_type, SELECT_ENTRY_BY_HASH_AND_TYPE) || PINIT (plugin->select_entry_by_hash_vhash_and_type, SELECT_ENTRY_BY_HASH_VHASH_AND_TYPE) || PINIT (plugin->count_entry_by_hash, COUNT_ENTRY_BY_HASH) || PINIT (plugin->get_size, SELECT_SIZE) || PINIT (plugin->count_entry_by_hash_and_vhash, COUNT_ENTRY_BY_HASH_AND_VHASH) || PINIT (plugin->count_entry_by_hash_and_type, COUNT_ENTRY_BY_HASH_AND_TYPE) || PINIT (plugin->count_entry_by_hash_vhash_and_type, COUNT_ENTRY_BY_HASH_VHASH_AND_TYPE) || PINIT (plugin->update_entry, UPDATE_ENTRY) || PINIT (plugin->dec_repl, DEC_REPL) || PINIT (plugin->zero_iter, SELECT_IT_NON_ANONYMOUS) || PINIT (plugin->select_expiration, SELECT_IT_EXPIRATION) || PINIT (plugin->select_priority, SELECT_IT_PRIORITY) || PINIT (plugin->max_repl, SELECT_MAX_REPL) || PINIT (plugin->get_all_keys, GET_ALL_KEYS) || PINIT (plugin->select_replication, SELECT_IT_REPLICATION)) { GNUNET_MYSQL_context_destroy (plugin->mc); GNUNET_free (plugin); return NULL; } #undef PINIT #undef MRUNS api = GNUNET_malloc (sizeof (struct GNUNET_DATASTORE_PluginFunctions)); api->cls = plugin; api->estimate_size = &mysql_plugin_estimate_size; api->put = &mysql_plugin_put; api->update = &mysql_plugin_update; api->get_key = &mysql_plugin_get_key; api->get_replication = &mysql_plugin_get_replication; api->get_expiration = &mysql_plugin_get_expiration; api->get_zero_anonymity = &mysql_plugin_get_zero_anonymity; api->get_keys = &mysql_plugin_get_keys; api->drop = &mysql_plugin_drop; GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "mysql", _("Mysql database running\n")); return api; } /** * Exit point from the plugin. * @param cls our "struct Plugin*" * @return always NULL */ void * libgnunet_plugin_datastore_mysql_done (void *cls) { struct GNUNET_DATASTORE_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; GNUNET_MYSQL_context_destroy (plugin->mc); GNUNET_free (plugin); GNUNET_free (api); return NULL; } /* end of plugin_datastore_mysql.c */ gnunet-0.9.3/src/datastore/plugin_datastore_postgres.c0000644000175000017500000007066711760502550020200 00000000000000/* This file is part of GNUnet (C) 2009, 2010, 2011, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file datastore/plugin_datastore_postgres.c * @brief postgres-based datastore backend * @author Christian Grothoff */ #include "platform.h" #include "gnunet_datastore_plugin.h" #include "gnunet_postgres_lib.h" #include /** * After how many ms "busy" should a DB operation fail for good? * A low value makes sure that we are more responsive to requests * (especially PUTs). A high value guarantees a higher success * rate (SELECTs in iterate can take several seconds despite LIMIT=1). * * The default value of 1s should ensure that users do not experience * huge latencies while at the same time allowing operations to succeed * with reasonable probability. */ #define BUSY_TIMEOUT GNUNET_TIME_UNIT_SECONDS /** * Context for all functions in this plugin. */ struct Plugin { /** * Our execution environment. */ struct GNUNET_DATASTORE_PluginEnvironment *env; /** * Native Postgres database handle. */ PGconn *dbh; }; /** * @brief Get a database handle * * @param plugin global context * @return GNUNET_OK on success, GNUNET_SYSERR on error */ static int init_connection (struct Plugin *plugin) { PGresult *ret; plugin->dbh = GNUNET_POSTGRES_connect (plugin->env->cfg, "datastore-postgres"); if (NULL == plugin->dbh) return GNUNET_SYSERR; ret = PQexec (plugin->dbh, "CREATE TABLE gn090 (" " repl INTEGER NOT NULL DEFAULT 0," " type INTEGER NOT NULL DEFAULT 0," " prio INTEGER NOT NULL DEFAULT 0," " anonLevel INTEGER NOT NULL DEFAULT 0," " expire BIGINT NOT NULL DEFAULT 0," " rvalue BIGINT NOT NULL DEFAULT 0," " hash BYTEA NOT NULL DEFAULT ''," " vhash BYTEA NOT NULL DEFAULT ''," " value BYTEA NOT NULL DEFAULT '')" "WITH OIDS"); if ((ret == NULL) || ((PQresultStatus (ret) != PGRES_COMMAND_OK) && (0 != strcmp ("42P07", /* duplicate table */ PQresultErrorField (ret, PG_DIAG_SQLSTATE))))) { (void) GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_COMMAND_OK, "CREATE TABLE", "gn090"); PQfinish (plugin->dbh); plugin->dbh = NULL; return GNUNET_SYSERR; } if (PQresultStatus (ret) == PGRES_COMMAND_OK) { if ((GNUNET_OK != GNUNET_POSTGRES_exec (plugin->dbh, "CREATE INDEX idx_hash ON gn090 (hash)")) || (GNUNET_OK != GNUNET_POSTGRES_exec (plugin->dbh, "CREATE INDEX idx_hash_vhash ON gn090 (hash,vhash)")) || (GNUNET_OK != GNUNET_POSTGRES_exec (plugin->dbh, "CREATE INDEX idx_prio ON gn090 (prio)")) || (GNUNET_OK != GNUNET_POSTGRES_exec (plugin->dbh, "CREATE INDEX idx_expire ON gn090 (expire)")) || (GNUNET_OK != GNUNET_POSTGRES_exec (plugin->dbh, "CREATE INDEX idx_prio_anon ON gn090 (prio,anonLevel)")) || (GNUNET_OK != GNUNET_POSTGRES_exec (plugin->dbh, "CREATE INDEX idx_prio_hash_anon ON gn090 (prio,hash,anonLevel)")) || (GNUNET_OK != GNUNET_POSTGRES_exec (plugin->dbh, "CREATE INDEX idx_repl_rvalue ON gn090 (repl,rvalue)")) || (GNUNET_OK != GNUNET_POSTGRES_exec (plugin->dbh, "CREATE INDEX idx_expire_hash ON gn090 (expire,hash)"))) { PQclear (ret); PQfinish (plugin->dbh); plugin->dbh = NULL; return GNUNET_SYSERR; } } PQclear (ret); ret = PQexec (plugin->dbh, "ALTER TABLE gn090 ALTER value SET STORAGE EXTERNAL"); if (GNUNET_OK != GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_COMMAND_OK, "ALTER TABLE", "gn090")) { PQfinish (plugin->dbh); plugin->dbh = NULL; return GNUNET_SYSERR; } PQclear (ret); ret = PQexec (plugin->dbh, "ALTER TABLE gn090 ALTER hash SET STORAGE PLAIN"); if (GNUNET_OK != GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_COMMAND_OK, "ALTER TABLE", "gn090")) { PQfinish (plugin->dbh); plugin->dbh = NULL; return GNUNET_SYSERR; } PQclear (ret); ret = PQexec (plugin->dbh, "ALTER TABLE gn090 ALTER vhash SET STORAGE PLAIN"); if (GNUNET_OK != GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_COMMAND_OK, "ALTER TABLE", "gn090")) { PQfinish (plugin->dbh); plugin->dbh = NULL; return GNUNET_SYSERR; } PQclear (ret); if ((GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, "getvt", "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " "WHERE hash=$1 AND vhash=$2 AND type=$3 " "ORDER BY oid ASC LIMIT 1 OFFSET $4", 4)) || (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, "gett", "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " "WHERE hash=$1 AND type=$2 " "ORDER BY oid ASC LIMIT 1 OFFSET $3", 3)) || (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, "getv", "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " "WHERE hash=$1 AND vhash=$2 " "ORDER BY oid ASC LIMIT 1 OFFSET $3", 3)) || (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, "get", "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " "WHERE hash=$1 " "ORDER BY oid ASC LIMIT 1 OFFSET $2", 2)) || (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, "put", "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) " "VALUES ($1, $2, $3, $4, $5, RANDOM(), $6, $7, $8)", 9)) || (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, "update", "UPDATE gn090 SET prio = prio + $1, expire = CASE WHEN expire < $2 THEN $2 ELSE expire END " "WHERE oid = $3", 3)) || (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, "decrepl", "UPDATE gn090 SET repl = GREATEST (repl - 1, 0) " "WHERE oid = $1", 1)) || (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, "select_non_anonymous", "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " "WHERE anonLevel = 0 AND type = $1 ORDER BY oid DESC LIMIT 1 OFFSET $2", 1)) || (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, "select_expiration_order", "(SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " "WHERE expire < $1 ORDER BY prio ASC LIMIT 1) " "UNION " "(SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " "ORDER BY prio ASC LIMIT 1) " "ORDER BY expire ASC LIMIT 1", 1)) || (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, "select_replication_order", "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " "ORDER BY repl DESC,RANDOM() LIMIT 1", 0)) || (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, "delrow", "DELETE FROM gn090 " "WHERE oid=$1", 1)) || (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, "get_keys", "SELECT hash FROM gn090", 0))) { PQfinish (plugin->dbh); plugin->dbh = NULL; return GNUNET_SYSERR; } return GNUNET_OK; } /** * Get an estimate of how much space the database is * currently using. * * @param cls our "struct Plugin*" * @return number of bytes used on disk */ static unsigned long long postgres_plugin_estimate_size (void *cls) { struct Plugin *plugin = cls; unsigned long long total; PGresult *ret; ret = PQexecParams (plugin->dbh, "SELECT SUM(LENGTH(value))+256*COUNT(*) FROM gn090", 0, NULL, NULL, NULL, NULL, 1); if (GNUNET_OK != GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_TUPLES_OK, "PQexecParams", "get_size")) { return 0; } if ((PQntuples (ret) != 1) || (PQnfields (ret) != 1) ) { GNUNET_break (0); PQclear (ret); return 0; } if (PQgetlength (ret, 0, 0) != sizeof (unsigned long long)) { GNUNET_break (0 == PQgetlength (ret, 0, 0)); PQclear (ret); return 0; } total = GNUNET_ntohll (*(const unsigned long long *) PQgetvalue (ret, 0, 0)); PQclear (ret); return total; } /** * Store an item in the datastore. * * @param cls closure with the 'struct Plugin' * @param key key for the item * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param replication replication-level for the content * @param expiration expiration time for the content * @param msg set to error message * @return GNUNET_OK on success */ static int postgres_plugin_put (void *cls, const GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, uint32_t replication, struct GNUNET_TIME_Absolute expiration, char **msg) { struct Plugin *plugin = cls; GNUNET_HashCode vhash; PGresult *ret; uint32_t btype = htonl (type); uint32_t bprio = htonl (priority); uint32_t banon = htonl (anonymity); uint32_t brepl = htonl (replication); uint64_t bexpi = GNUNET_TIME_absolute_hton (expiration).abs_value__; const char *paramValues[] = { (const char *) &brepl, (const char *) &btype, (const char *) &bprio, (const char *) &banon, (const char *) &bexpi, (const char *) key, (const char *) &vhash, (const char *) data }; int paramLengths[] = { sizeof (brepl), sizeof (btype), sizeof (bprio), sizeof (banon), sizeof (bexpi), sizeof (GNUNET_HashCode), sizeof (GNUNET_HashCode), size }; const int paramFormats[] = { 1, 1, 1, 1, 1, 1, 1, 1 }; GNUNET_CRYPTO_hash (data, size, &vhash); ret = PQexecPrepared (plugin->dbh, "put", 8, paramValues, paramLengths, paramFormats, 1); if (GNUNET_OK != GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_COMMAND_OK, "PQexecPrepared", "put")) return GNUNET_SYSERR; PQclear (ret); plugin->env->duc (plugin->env->cls, size + GNUNET_DATASTORE_ENTRY_OVERHEAD); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "datastore-postgres", "Stored %u bytes in database\n", (unsigned int) size); return GNUNET_OK; } /** * Function invoked to process the result and call * the processor. * * @param plugin global plugin data * @param proc function to call the value (once only). * @param proc_cls closure for proc * @param res result from exec * @param filename filename for error messages * @param line line number for error messages */ static void process_result (struct Plugin *plugin, PluginDatumProcessor proc, void *proc_cls, PGresult * res, const char *filename, int line) { int iret; enum GNUNET_BLOCK_Type type; uint32_t anonymity; uint32_t priority; uint32_t size; unsigned int rowid; struct GNUNET_TIME_Absolute expiration_time; GNUNET_HashCode key; if (GNUNET_OK != GNUNET_POSTGRES_check_result_ (plugin->dbh, res, PGRES_TUPLES_OK, "PQexecPrepared", "select", filename, line)) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "datastore-postgres", "Ending iteration (postgres error)\n"); proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } if (0 == PQntuples (res)) { /* no result */ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "datastore-postgres", "Ending iteration (no more results)\n"); proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); PQclear (res); return; } if ((1 != PQntuples (res)) || (7 != PQnfields (res)) || (sizeof (uint32_t) != PQfsize (res, 0)) || (sizeof (uint32_t) != PQfsize (res, 6))) { GNUNET_break (0); proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); PQclear (res); return; } rowid = ntohl (*(uint32_t *) PQgetvalue (res, 0, 6)); if ((sizeof (uint32_t) != PQfsize (res, 0)) || (sizeof (uint32_t) != PQfsize (res, 1)) || (sizeof (uint32_t) != PQfsize (res, 2)) || (sizeof (uint64_t) != PQfsize (res, 3)) || (sizeof (GNUNET_HashCode) != PQgetlength (res, 0, 4))) { GNUNET_break (0); PQclear (res); GNUNET_POSTGRES_delete_by_rowid (plugin->dbh, "delrow", rowid); proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } type = ntohl (*(uint32_t *) PQgetvalue (res, 0, 0)); priority = ntohl (*(uint32_t *) PQgetvalue (res, 0, 1)); anonymity = ntohl (*(uint32_t *) PQgetvalue (res, 0, 2)); expiration_time.abs_value = GNUNET_ntohll (*(uint64_t *) PQgetvalue (res, 0, 3)); memcpy (&key, PQgetvalue (res, 0, 4), sizeof (GNUNET_HashCode)); size = PQgetlength (res, 0, 5); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "datastore-postgres", "Found result of size %u bytes and type %u in database\n", (unsigned int) size, (unsigned int) type); iret = proc (proc_cls, &key, size, PQgetvalue (res, 0, 5), (enum GNUNET_BLOCK_Type) type, priority, anonymity, expiration_time, rowid); PQclear (res); if (iret == GNUNET_NO) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processor asked for item %u to be removed.\n", rowid); if (GNUNET_OK == GNUNET_POSTGRES_delete_by_rowid (plugin->dbh, "delrow", rowid)) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "datastore-postgres", "Deleting %u bytes from database\n", (unsigned int) size); plugin->env->duc (plugin->env->cls, -(size + GNUNET_DATASTORE_ENTRY_OVERHEAD)); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "datastore-postgres", "Deleted %u bytes from database\n", (unsigned int) size); } } } /** * Iterate over the results for a particular key * in the datastore. * * @param cls closure with the 'struct Plugin' * @param offset offset of the result (modulo num-results); * specific ordering does not matter for the offset * @param key maybe NULL (to match all entries) * @param vhash hash of the value, maybe NULL (to * match all values that have the right key). * Note that for DBlocks there is no difference * betwen key and vhash, but for other blocks * there may be! * @param type entries of which type are relevant? * Use 0 for any type. * @param proc function to call on the matching value; * will be called once with a NULL if no value matches * @param proc_cls closure for iter */ static void postgres_plugin_get_key (void *cls, uint64_t offset, const GNUNET_HashCode * key, const GNUNET_HashCode * vhash, enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc, void *proc_cls) { struct Plugin *plugin = cls; const int paramFormats[] = { 1, 1, 1, 1, 1 }; int paramLengths[4]; const char *paramValues[4]; int nparams; const char *pname; PGresult *ret; uint64_t total; uint64_t blimit_off; uint32_t btype; GNUNET_assert (key != NULL); paramValues[0] = (const char *) key; paramLengths[0] = sizeof (GNUNET_HashCode); btype = htonl (type); if (type != 0) { if (vhash != NULL) { paramValues[1] = (const char *) vhash; paramLengths[1] = sizeof (GNUNET_HashCode); paramValues[2] = (const char *) &btype; paramLengths[2] = sizeof (btype); paramValues[3] = (const char *) &blimit_off; paramLengths[3] = sizeof (blimit_off); nparams = 4; pname = "getvt"; ret = PQexecParams (plugin->dbh, "SELECT count(*) FROM gn090 WHERE hash=$1 AND vhash=$2 AND type=$3", 3, NULL, paramValues, paramLengths, paramFormats, 1); } else { paramValues[1] = (const char *) &btype; paramLengths[1] = sizeof (btype); paramValues[2] = (const char *) &blimit_off; paramLengths[2] = sizeof (blimit_off); nparams = 3; pname = "gett"; ret = PQexecParams (plugin->dbh, "SELECT count(*) FROM gn090 WHERE hash=$1 AND type=$2", 2, NULL, paramValues, paramLengths, paramFormats, 1); } } else { if (vhash != NULL) { paramValues[1] = (const char *) vhash; paramLengths[1] = sizeof (GNUNET_HashCode); paramValues[2] = (const char *) &blimit_off; paramLengths[2] = sizeof (blimit_off); nparams = 3; pname = "getv"; ret = PQexecParams (plugin->dbh, "SELECT count(*) FROM gn090 WHERE hash=$1 AND vhash=$2", 2, NULL, paramValues, paramLengths, paramFormats, 1); } else { paramValues[1] = (const char *) &blimit_off; paramLengths[1] = sizeof (blimit_off); nparams = 2; pname = "get"; ret = PQexecParams (plugin->dbh, "SELECT count(*) FROM gn090 WHERE hash=$1", 1, NULL, paramValues, paramLengths, paramFormats, 1); } } if (GNUNET_OK != GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_TUPLES_OK, "PQexecParams", pname)) { proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } if ((PQntuples (ret) != 1) || (PQnfields (ret) != 1) || (PQgetlength (ret, 0, 0) != sizeof (unsigned long long))) { GNUNET_break (0); PQclear (ret); proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } total = GNUNET_ntohll (*(const unsigned long long *) PQgetvalue (ret, 0, 0)); PQclear (ret); if (total == 0) { proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } blimit_off = GNUNET_htonll (offset % total); ret = PQexecPrepared (plugin->dbh, pname, nparams, paramValues, paramLengths, paramFormats, 1); process_result (plugin, proc, proc_cls, ret, __FILE__, __LINE__); } /** * Select a subset of the items in the datastore and call * the given iterator for each of them. * * @param cls our "struct Plugin*" * @param offset offset of the result (modulo num-results); * specific ordering does not matter for the offset * @param type entries of which type should be considered? * Use 0 for any type. * @param proc function to call on the matching value; * will be called with a NULL if no value matches * @param proc_cls closure for proc */ static void postgres_plugin_get_zero_anonymity (void *cls, uint64_t offset, enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc, void *proc_cls) { struct Plugin *plugin = cls; uint32_t btype; uint64_t boff; const int paramFormats[] = { 1, 1 }; int paramLengths[] = { sizeof (btype), sizeof (boff) }; const char *paramValues[] = { (const char *) &btype, (const char *) &boff }; PGresult *ret; btype = htonl ((uint32_t) type); boff = GNUNET_htonll (offset); ret = PQexecPrepared (plugin->dbh, "select_non_anonymous", 2, paramValues, paramLengths, paramFormats, 1); process_result (plugin, proc, proc_cls, ret, __FILE__, __LINE__); } /** * Context for 'repl_iter' function. */ struct ReplCtx { /** * Plugin handle. */ struct Plugin *plugin; /** * Function to call for the result (or the NULL). */ PluginDatumProcessor proc; /** * Closure for proc. */ void *proc_cls; }; /** * Wrapper for the iterator for 'sqlite_plugin_replication_get'. * Decrements the replication counter and calls the original * iterator. * * @param cls closure with the 'struct ReplCtx*' * @param key key for the content * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param expiration expiration time for the content * @param uid unique identifier for the datum; * maybe 0 if no unique identifier is available * * @return GNUNET_SYSERR to abort the iteration, GNUNET_OK to continue * (continue on call to "next", of course), * GNUNET_NO to delete the item and continue (if supported) */ static int repl_proc (void *cls, const GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct ReplCtx *rc = cls; struct Plugin *plugin = rc->plugin; int ret; PGresult *qret; uint32_t boid; ret = rc->proc (rc->proc_cls, key, size, data, type, priority, anonymity, expiration, uid); if (NULL != key) { boid = htonl ((uint32_t) uid); const char *paramValues[] = { (const char *) &boid, }; int paramLengths[] = { sizeof (boid), }; const int paramFormats[] = { 1 }; qret = PQexecPrepared (plugin->dbh, "decrepl", 1, paramValues, paramLengths, paramFormats, 1); if (GNUNET_OK != GNUNET_POSTGRES_check_result (plugin->dbh, qret, PGRES_COMMAND_OK, "PQexecPrepared", "decrepl")) return GNUNET_SYSERR; PQclear (qret); } return ret; } /** * Get a random item for replication. Returns a single, not expired, random item * from those with the highest replication counters. The item's * replication counter is decremented by one IF it was positive before. * Call 'proc' with all values ZERO or NULL if the datastore is empty. * * @param cls closure with the 'struct Plugin' * @param proc function to call the value (once only). * @param proc_cls closure for proc */ static void postgres_plugin_get_replication (void *cls, PluginDatumProcessor proc, void *proc_cls) { struct Plugin *plugin = cls; struct ReplCtx rc; PGresult *ret; rc.plugin = plugin; rc.proc = proc; rc.proc_cls = proc_cls; ret = PQexecPrepared (plugin->dbh, "select_replication_order", 0, NULL, NULL, NULL, 1); process_result (plugin, &repl_proc, &rc, ret, __FILE__, __LINE__); } /** * Get a random item for expiration. * Call 'proc' with all values ZERO or NULL if the datastore is empty. * * @param cls closure with the 'struct Plugin' * @param proc function to call the value (once only). * @param proc_cls closure for proc */ static void postgres_plugin_get_expiration (void *cls, PluginDatumProcessor proc, void *proc_cls) { struct Plugin *plugin = cls; uint64_t btime; const int paramFormats[] = { 1 }; int paramLengths[] = { sizeof (btime) }; const char *paramValues[] = { (const char *) &btime }; PGresult *ret; btime = GNUNET_htonll (GNUNET_TIME_absolute_get ().abs_value); ret = PQexecPrepared (plugin->dbh, "select_expiration_order", 1, paramValues, paramLengths, paramFormats, 1); process_result (plugin, proc, proc_cls, ret, __FILE__, __LINE__); } /** * Update the priority for a particular key in the datastore. If * the expiration time in value is different than the time found in * the datastore, the higher value should be kept. For the * anonymity level, the lower value is to be used. The specified * priority should be added to the existing priority, ignoring the * priority in value. * * Note that it is possible for multiple values to match this put. * In that case, all of the respective values are updated. * * @param cls our "struct Plugin*" * @param uid unique identifier of the datum * @param delta by how much should the priority * change? If priority + delta < 0 the * priority should be set to 0 (never go * negative). * @param expire new expiration time should be the * MAX of any existing expiration time and * this value * @param msg set to error message * @return GNUNET_OK on success */ static int postgres_plugin_update (void *cls, uint64_t uid, int delta, struct GNUNET_TIME_Absolute expire, char **msg) { struct Plugin *plugin = cls; PGresult *ret; int32_t bdelta = (int32_t) htonl ((uint32_t) delta); uint32_t boid = htonl ((uint32_t) uid); uint64_t bexpire = GNUNET_TIME_absolute_hton (expire).abs_value__; const char *paramValues[] = { (const char *) &bdelta, (const char *) &bexpire, (const char *) &boid, }; int paramLengths[] = { sizeof (bdelta), sizeof (bexpire), sizeof (boid), }; const int paramFormats[] = { 1, 1, 1 }; ret = PQexecPrepared (plugin->dbh, "update", 3, paramValues, paramLengths, paramFormats, 1); if (GNUNET_OK != GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_COMMAND_OK, "PQexecPrepared", "update")) return GNUNET_SYSERR; PQclear (ret); return GNUNET_OK; } /** * Get all of the keys in the datastore. * * @param cls closure with the 'struct Plugin' * @param proc function to call on each key * @param proc_cls closure for proc */ static void postgres_plugin_get_keys (void *cls, PluginKeyProcessor proc, void *proc_cls) { struct Plugin *plugin = cls; int ret; int i; GNUNET_HashCode key; PGresult * res; res = PQexecPrepared (plugin->dbh, "get_keys", 0, NULL, NULL, NULL, 1); ret = PQntuples (res); for (i=0;idbh, "DROP TABLE gn090")) GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "postgres", _("Failed to drop table from database.\n")); } /** * Entry point for the plugin. * * @param cls the "struct GNUNET_DATASTORE_PluginEnvironment*" * @return our "struct Plugin*" */ void * libgnunet_plugin_datastore_postgres_init (void *cls) { struct GNUNET_DATASTORE_PluginEnvironment *env = cls; struct GNUNET_DATASTORE_PluginFunctions *api; struct Plugin *plugin; plugin = GNUNET_malloc (sizeof (struct Plugin)); plugin->env = env; if (GNUNET_OK != init_connection (plugin)) { GNUNET_free (plugin); return NULL; } api = GNUNET_malloc (sizeof (struct GNUNET_DATASTORE_PluginFunctions)); api->cls = plugin; api->estimate_size = &postgres_plugin_estimate_size; api->put = &postgres_plugin_put; api->update = &postgres_plugin_update; api->get_key = &postgres_plugin_get_key; api->get_replication = &postgres_plugin_get_replication; api->get_expiration = &postgres_plugin_get_expiration; api->get_zero_anonymity = &postgres_plugin_get_zero_anonymity; api->get_keys = &postgres_plugin_get_keys; api->drop = &postgres_plugin_drop; GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "datastore-postgres", _("Postgres database running\n")); return api; } /** * Exit point from the plugin. * @param cls our "struct Plugin*" * @return always NULL */ void * libgnunet_plugin_datastore_postgres_done (void *cls) { struct GNUNET_DATASTORE_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; PQfinish (plugin->dbh); GNUNET_free (plugin); GNUNET_free (api); return NULL; } /* end of plugin_datastore_postgres.c */ gnunet-0.9.3/src/datastore/perf_datastore_api.c0000644000175000017500000002672111760502550016531 00000000000000/* This file is part of GNUnet. (C) 2004, 2005, 2006, 2007, 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * @file datastore/perf_datastore_api.c * @brief performance measurement for the datastore implementation * @author Christian Grothoff * * This testcase inserts a bunch of (variable size) data and then * deletes data until the (reported) database size drops below a given * threshold. This is iterated 10 times, with the actual size of the * content stored and the number of operations performed being printed * for each iteration. The code also prints a "I" for every 40 blocks * inserted and a "D" for every 40 blocks deleted. The deletion * strategy uses the "random" iterator. Priorities and expiration * dates are set using a pseudo-random value within a realistic range. */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_protocols.h" #include "gnunet_datastore_service.h" #include #define VERBOSE GNUNET_NO /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) static const char *plugin_name; static struct GNUNET_DATASTORE_Handle *datastore; /** * Target datastore size (in bytes). */ #define MAX_SIZE 1024LL * 1024 * 4 /** * Report progress outside of major reports? Should probably be GNUNET_YES if * size is > 16 MB. */ #define REPORT_ID GNUNET_YES /** * Number of put operations equivalent to 1/3rd of MAX_SIZE */ #define PUT_10 MAX_SIZE / 32 / 1024 / 3 /** * Total number of iterations (each iteration doing * PUT_10 put operations); we report full status every * 10 iterations. Abort with CTRL-C. */ #define ITERATIONS 8 static unsigned long long stored_bytes; static unsigned long long stored_entries; static unsigned long long stored_ops; static struct GNUNET_TIME_Absolute start_time; static int ok; enum RunPhase { RP_DONE = 0, RP_PUT, RP_CUT, RP_REPORT, RP_ERROR }; struct CpsRunContext { const struct GNUNET_CONFIGURATION_Handle *cfg; enum RunPhase phase; int j; unsigned long long size; int i; }; static void run_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); static void check_success (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) { struct CpsRunContext *crc = cls; if (GNUNET_OK != success) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Check success failed: `%s'\n", msg); crc->phase = RP_ERROR; GNUNET_SCHEDULER_add_now (&run_continuation, crc); return; } #if REPORT_ID FPRINTF (stderr, "%s", "I"); #endif stored_bytes += crc->size; stored_ops++; stored_entries++; crc->j++; if (crc->j >= PUT_10) { crc->j = 0; crc->i++; if (crc->i == ITERATIONS) crc->phase = RP_DONE; else crc->phase = RP_CUT; } GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } /** * Continuation called to notify client about result of the * operation. * * @param cls closure * @param success GNUNET_SYSERR on failure * @param min_expiration minimum expiration time required for content to be stored * by the datacache at this time, zero for unknown * @param msg NULL on success, otherwise an error message */ static void remove_next (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) { struct CpsRunContext *crc = cls; if (GNUNET_OK != success) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "remove_next failed: `%s'\n", msg); crc->phase = RP_ERROR; GNUNET_SCHEDULER_add_now (&run_continuation, crc); return; } #if REPORT_ID FPRINTF (stderr, "%s", "D"); #endif GNUNET_assert (GNUNET_OK == success); GNUNET_SCHEDULER_add_now (&run_continuation, crc); } static void delete_value (void *cls, const GNUNET_HashCode * key, size_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct CpsRunContext *crc = cls; GNUNET_assert (NULL != key); stored_ops++; stored_bytes -= size; stored_entries--; stored_ops++; if (stored_bytes < MAX_SIZE) crc->phase = RP_PUT; GNUNET_assert (NULL != GNUNET_DATASTORE_remove (datastore, key, size, data, 1, 1, TIMEOUT, &remove_next, crc)); } static void run_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct CpsRunContext *crc = cls; size_t size; static GNUNET_HashCode key; static char data[65536]; int i; int k; char gstr[128]; ok = (int) crc->phase; switch (crc->phase) { case RP_PUT: memset (&key, 256 - crc->i, sizeof (GNUNET_HashCode)); i = crc->j; k = crc->i; /* most content is 32k */ size = 32 * 1024; if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16) == 0) /* but some of it is less! */ size = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 32 * 1024); crc->size = size = size - (size & 7); /* always multiple of 8 */ GNUNET_CRYPTO_hash (&key, sizeof (GNUNET_HashCode), &key); memset (data, i, size); if (i > 255) memset (data, i - 255, size / 2); data[0] = k; GNUNET_assert (NULL != GNUNET_DATASTORE_put (datastore, 0, &key, size, data, i + 1, GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100), i, 0, GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000))), 1, 1, TIMEOUT, &check_success, crc)); break; case RP_CUT: /* trim down below MAX_SIZE again */ GNUNET_assert (NULL != GNUNET_DATASTORE_get_for_replication (datastore, 1, 1, TIMEOUT, &delete_value, crc)); break; case RP_REPORT: printf ( #if REPORT_ID "\n" #endif "Stored %llu kB / %lluk ops / %llu ops/s\n", stored_bytes / 1024, /* used size in k */ stored_ops / 1024, /* total operations (in k) */ 1000 * stored_ops / (1 + GNUNET_TIME_absolute_get_duration (start_time).rel_value)); crc->phase = RP_PUT; crc->j = 0; GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case RP_DONE: GNUNET_snprintf (gstr, sizeof (gstr), "DATASTORE-%s", plugin_name); if ((crc->i == ITERATIONS) && (stored_ops > 0)) GAUGER (gstr, "PUT operation duration", GNUNET_TIME_absolute_get_duration (start_time).rel_value / stored_ops, "ms/operation"); GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES); GNUNET_free (crc); ok = 0; break; case RP_ERROR: GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES); GNUNET_free (crc); ok = 1; break; default: GNUNET_assert (0); } } static void run_tests (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) { struct CpsRunContext *crc = cls; if (success != GNUNET_YES) { FPRINTF (stderr, "Test 'put' operation failed with error `%s' database likely not setup, skipping test.\n", msg); GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES); GNUNET_free (crc); return; } GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct CpsRunContext *crc; static GNUNET_HashCode zkey; datastore = GNUNET_DATASTORE_connect (cfg); start_time = GNUNET_TIME_absolute_get (); crc = GNUNET_malloc (sizeof (struct CpsRunContext)); crc->cfg = cfg; crc->phase = RP_PUT; if (NULL == GNUNET_DATASTORE_put (datastore, 0, &zkey, 4, "TEST", GNUNET_BLOCK_TYPE_TEST, 0, 0, 0, GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_SECONDS), 0, 1, GNUNET_TIME_UNIT_MINUTES, &run_tests, crc)) { FPRINTF (stderr, "%s", "Test 'put' operation failed.\n"); ok = 1; GNUNET_free (crc); } } static int check () { struct GNUNET_OS_Process *proc; char cfg_name[128]; char *const argv[] = { "perf-datastore-api", "-c", cfg_name, #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_snprintf (cfg_name, sizeof (cfg_name), "test_datastore_api_data_%s.conf", plugin_name); proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE "-L", "DEBUG", #endif "-c", cfg_name, NULL); GNUNET_assert (NULL != proc); GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "perf-datastore-api", "nohelp", options, &run, NULL); sleep (1); /* give datastore chance to process 'DROP' */ if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); ok = 1; } GNUNET_OS_process_wait (proc); GNUNET_OS_process_destroy (proc); proc = NULL; return ok; } int main (int argc, char *argv[]) { int ret; char *pos; char dir_name[128]; sleep (1); /* determine name of plugin to use */ plugin_name = argv[0]; while (NULL != (pos = strstr (plugin_name, "_"))) plugin_name = pos + 1; if (NULL != (pos = strstr (plugin_name, "."))) pos[0] = 0; else pos = (char *) plugin_name; GNUNET_snprintf (dir_name, sizeof (dir_name), "/tmp/test-gnunet-datastore-%s", plugin_name); GNUNET_DISK_directory_remove (dir_name); GNUNET_log_setup ("perf-datastore-api", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); if (pos != plugin_name) pos[0] = '.'; #if REPORT_ID FPRINTF (stderr, "%s", "\n"); #endif GNUNET_DISK_directory_remove (dir_name); return ret; } /* end of perf_datastore_api.c */ gnunet-0.9.3/src/datastore/test_datastore_api_management.c0000644000175000017500000002324311760502550020744 00000000000000/* This file is part of GNUnet. (C) 2004, 2005, 2006, 2007, 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * @file datastore/test_datastore_api_management.c * @brief Test for the space management functions of the datastore implementation. * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_protocols.h" #include "gnunet_datastore_service.h" #define VERBOSE GNUNET_NO /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) /** * Number of iterations to run; must be large enough * so that the quota will be exceeded! */ #define ITERATIONS 5000 static struct GNUNET_DATASTORE_Handle *datastore; static struct GNUNET_TIME_Absolute now; static int ok; static const char *plugin_name; static size_t get_size (int i) { return 8 + 8 * (i % 256); } static const void * get_data (int i) { static char buf[60000]; memset (buf, i, 8 + 8 * (i % 256)); return buf; } static int get_type (int i) { return 1; } static int get_priority (int i) { return i + 1; } static int get_anonymity (int i) { return i; } static struct GNUNET_TIME_Absolute get_expiration (int i) { struct GNUNET_TIME_Absolute av; av.abs_value = now.abs_value + i * 1000; return av; } enum RunPhase { RP_PUT, RP_GET, RP_DONE, RP_GET_FAIL }; struct CpsRunContext { GNUNET_HashCode key; int i; int found; const struct GNUNET_CONFIGURATION_Handle *cfg; void *data; enum RunPhase phase; uint64_t offset; }; static void run_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); static void check_success (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) { struct CpsRunContext *crc = cls; if (GNUNET_OK != success) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", msg); GNUNET_assert (GNUNET_OK == success); GNUNET_free_non_null (crc->data); crc->data = NULL; GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } static void check_value (void *cls, const GNUNET_HashCode * key, size_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct CpsRunContext *crc = cls; int i; if (NULL == key) { crc->phase = RP_GET_FAIL; GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, GNUNET_SCHEDULER_REASON_PREREQ_DONE); return; } i = crc->i; GNUNET_assert (size == get_size (i)); GNUNET_assert (0 == memcmp (data, get_data (i), size)); GNUNET_assert (type == get_type (i)); GNUNET_assert (priority == get_priority (i)); GNUNET_assert (anonymity == get_anonymity (i)); GNUNET_assert (expiration.abs_value == get_expiration (i).abs_value); crc->offset++; crc->i--; if (crc->i == 0) crc->phase = RP_DONE; GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } static void check_nothing (void *cls, const GNUNET_HashCode * key, size_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct CpsRunContext *crc = cls; GNUNET_assert (key == NULL); if (0 == --crc->i) crc->phase = RP_DONE; GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } static void run_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct CpsRunContext *crc = cls; ok = (int) crc->phase; switch (crc->phase) { case RP_PUT: #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "PUT", crc->i); #endif GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key); GNUNET_DATASTORE_put (datastore, 0, &crc->key, get_size (crc->i), get_data (crc->i), get_type (crc->i), get_priority (crc->i), get_anonymity (crc->i), 0, get_expiration (crc->i), 1, 1, TIMEOUT, &check_success, crc); crc->i++; if (crc->i == ITERATIONS) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Sleeping to give datastore time to clean up\n"); sleep (1); crc->phase = RP_GET; crc->i--; } break; case RP_GET: #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "GET", crc->i); #endif GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key); GNUNET_DATASTORE_get_key (datastore, crc->offset++, &crc->key, get_type (crc->i), 1, 1, TIMEOUT, &check_value, crc); break; case RP_GET_FAIL: #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "GET(f)", crc->i); #endif GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key); GNUNET_DATASTORE_get_key (datastore, crc->offset++, &crc->key, get_type (crc->i), 1, 1, TIMEOUT, &check_nothing, crc); break; case RP_DONE: GNUNET_assert (0 == crc->i); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished, disconnecting\n"); #endif GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES); GNUNET_free (crc); ok = 0; } } static void run_tests (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) { struct CpsRunContext *crc = cls; if (success != GNUNET_YES) { FPRINTF (stderr, "Test 'put' operation failed with error `%s' database likely not setup, skipping test.\n", msg); GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES); GNUNET_free (crc); return; } GNUNET_SCHEDULER_add_continuation (&run_continuation, crc, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct CpsRunContext *crc; static GNUNET_HashCode zkey; crc = GNUNET_malloc (sizeof (struct CpsRunContext)); crc->cfg = cfg; crc->phase = RP_PUT; now = GNUNET_TIME_absolute_get (); datastore = GNUNET_DATASTORE_connect (cfg); if (NULL == GNUNET_DATASTORE_put (datastore, 0, &zkey, 4, "TEST", GNUNET_BLOCK_TYPE_TEST, 0, 0, 0, GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_SECONDS), 0, 1, GNUNET_TIME_UNIT_MINUTES, &run_tests, crc)) { FPRINTF (stderr, "%s", "Test 'put' operation failed.\n"); GNUNET_free (crc); ok = 1; } } static int check () { struct GNUNET_OS_Process *proc; char cfg_name[128]; char *const argv[] = { "test-datastore-api-management", "-c", cfg_name, #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_snprintf (cfg_name, sizeof (cfg_name), "test_datastore_api_data_%s.conf", plugin_name); proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE "-L", "DEBUG", #endif "-c", cfg_name, NULL); GNUNET_assert (NULL != proc); GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-datastore-api-management", "nohelp", options, &run, NULL); sleep (1); /* give datastore chance to process 'DROP' request */ if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); ok = 1; } GNUNET_OS_process_wait (proc); GNUNET_OS_process_destroy (proc); proc = NULL; if (ok != 0) FPRINTF (stderr, "Missed some testcases: %u\n", ok); return ok; } int main (int argc, char *argv[]) { int ret; char *pos; char dir_name[128]; sleep (1); /* determine name of plugin to use */ plugin_name = argv[0]; while (NULL != (pos = strstr (plugin_name, "_"))) plugin_name = pos + 1; if (NULL != (pos = strstr (plugin_name, "."))) pos[0] = 0; else pos = (char *) plugin_name; GNUNET_snprintf (dir_name, sizeof (dir_name), "/tmp/test-gnunet-datastore-%s", plugin_name); GNUNET_DISK_directory_remove (dir_name); GNUNET_log_setup ("test-datastore-api-management", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); if (pos != plugin_name) pos[0] = '.'; GNUNET_DISK_directory_remove (dir_name); return ret; } /* end of test_datastore_api_management.c */ gnunet-0.9.3/src/datastore/perf_plugin_datastore_data_mysql.conf0000644000175000017500000000032311634323402022162 00000000000000@INLINE@ test_defaults.conf [PATHS] SERVICEHOME = /tmp/perf-gnunet-datastore-mysql/ DEFAULTCONFIG = perf_plugin_datastore_data_mysql.conf [datastore] DATABASE = mysql [datastore-mysql] DATABASE = gnunetcheck gnunet-0.9.3/src/datastore/Makefile.in0000644000175000017500000015615511762217211014603 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-service-datastore$(EXEEXT) check_PROGRAMS = $(am__EXEEXT_2) $(am__EXEEXT_4) $(am__EXEEXT_6) subdir = src/datastore DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/datastore.conf.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = datastore.conf CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \ "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) $(plugin_LTLIBRARIES) am__DEPENDENCIES_1 = libgnunet_plugin_datastore_mysql_la_DEPENDENCIES = \ $(top_builddir)/src/mysql/libgnunetmysql.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_libgnunet_plugin_datastore_mysql_la_OBJECTS = \ libgnunet_plugin_datastore_mysql_la-plugin_datastore_mysql.lo libgnunet_plugin_datastore_mysql_la_OBJECTS = \ $(am_libgnunet_plugin_datastore_mysql_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunet_plugin_datastore_mysql_la_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libgnunet_plugin_datastore_mysql_la_LDFLAGS) $(LDFLAGS) -o \ $@ @HAVE_MYSQL_TRUE@am_libgnunet_plugin_datastore_mysql_la_rpath = \ @HAVE_MYSQL_TRUE@ -rpath $(plugindir) libgnunet_plugin_datastore_postgres_la_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/postgres/libgnunetpostgres.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_libgnunet_plugin_datastore_postgres_la_OBJECTS = libgnunet_plugin_datastore_postgres_la-plugin_datastore_postgres.lo libgnunet_plugin_datastore_postgres_la_OBJECTS = \ $(am_libgnunet_plugin_datastore_postgres_la_OBJECTS) libgnunet_plugin_datastore_postgres_la_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libgnunet_plugin_datastore_postgres_la_LDFLAGS) $(LDFLAGS) \ -o $@ @HAVE_POSTGRES_TRUE@am_libgnunet_plugin_datastore_postgres_la_rpath = \ @HAVE_POSTGRES_TRUE@ -rpath $(plugindir) libgnunet_plugin_datastore_sqlite_la_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_libgnunet_plugin_datastore_sqlite_la_OBJECTS = \ plugin_datastore_sqlite.lo libgnunet_plugin_datastore_sqlite_la_OBJECTS = \ $(am_libgnunet_plugin_datastore_sqlite_la_OBJECTS) libgnunet_plugin_datastore_sqlite_la_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libgnunet_plugin_datastore_sqlite_la_LDFLAGS) $(LDFLAGS) -o \ $@ @HAVE_SQLITE_TRUE@am_libgnunet_plugin_datastore_sqlite_la_rpath = \ @HAVE_SQLITE_TRUE@ -rpath $(plugindir) libgnunet_plugin_datastore_template_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_libgnunet_plugin_datastore_template_la_OBJECTS = \ plugin_datastore_template.lo libgnunet_plugin_datastore_template_la_OBJECTS = \ $(am_libgnunet_plugin_datastore_template_la_OBJECTS) libgnunet_plugin_datastore_template_la_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libgnunet_plugin_datastore_template_la_LDFLAGS) $(LDFLAGS) \ -o $@ libgnunetdatastore_la_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_libgnunetdatastore_la_OBJECTS = datastore_api.lo libgnunetdatastore_la_OBJECTS = $(am_libgnunetdatastore_la_OBJECTS) libgnunetdatastore_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetdatastore_la_LDFLAGS) \ $(LDFLAGS) -o $@ @HAVE_BENCHMARKS_TRUE@@HAVE_SQLITE_TRUE@am__EXEEXT_1 = perf_datastore_api_sqlite$(EXEEXT) \ @HAVE_BENCHMARKS_TRUE@@HAVE_SQLITE_TRUE@ perf_plugin_datastore_sqlite$(EXEEXT) @HAVE_SQLITE_TRUE@am__EXEEXT_2 = test_datastore_api_sqlite$(EXEEXT) \ @HAVE_SQLITE_TRUE@ test_datastore_api_management_sqlite$(EXEEXT) \ @HAVE_SQLITE_TRUE@ test_plugin_datastore_sqlite$(EXEEXT) \ @HAVE_SQLITE_TRUE@ $(am__EXEEXT_1) @HAVE_BENCHMARKS_TRUE@@HAVE_MYSQL_TRUE@am__EXEEXT_3 = perf_datastore_api_mysql$(EXEEXT) \ @HAVE_BENCHMARKS_TRUE@@HAVE_MYSQL_TRUE@ perf_plugin_datastore_mysql$(EXEEXT) @HAVE_MYSQL_TRUE@am__EXEEXT_4 = test_datastore_api_mysql$(EXEEXT) \ @HAVE_MYSQL_TRUE@ test_datastore_api_management_mysql$(EXEEXT) \ @HAVE_MYSQL_TRUE@ test_plugin_datastore_mysql$(EXEEXT) \ @HAVE_MYSQL_TRUE@ $(am__EXEEXT_3) @HAVE_BENCHMARKS_TRUE@@HAVE_POSTGRES_TRUE@am__EXEEXT_5 = perf_datastore_api_postgres$(EXEEXT) \ @HAVE_BENCHMARKS_TRUE@@HAVE_POSTGRES_TRUE@ perf_plugin_datastore_postgres$(EXEEXT) @HAVE_POSTGRES_TRUE@am__EXEEXT_6 = \ @HAVE_POSTGRES_TRUE@ test_datastore_api_postgres$(EXEEXT) \ @HAVE_POSTGRES_TRUE@ test_datastore_api_management_postgres$(EXEEXT) \ @HAVE_POSTGRES_TRUE@ test_plugin_datastore_postgres$(EXEEXT) \ @HAVE_POSTGRES_TRUE@ $(am__EXEEXT_5) PROGRAMS = $(bin_PROGRAMS) am_gnunet_service_datastore_OBJECTS = \ gnunet-service-datastore.$(OBJEXT) gnunet_service_datastore_OBJECTS = \ $(am_gnunet_service_datastore_OBJECTS) gnunet_service_datastore_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_perf_datastore_api_mysql_OBJECTS = perf_datastore_api.$(OBJEXT) perf_datastore_api_mysql_OBJECTS = \ $(am_perf_datastore_api_mysql_OBJECTS) perf_datastore_api_mysql_DEPENDENCIES = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la am_perf_datastore_api_postgres_OBJECTS = perf_datastore_api.$(OBJEXT) perf_datastore_api_postgres_OBJECTS = \ $(am_perf_datastore_api_postgres_OBJECTS) perf_datastore_api_postgres_DEPENDENCIES = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la am_perf_datastore_api_sqlite_OBJECTS = perf_datastore_api.$(OBJEXT) perf_datastore_api_sqlite_OBJECTS = \ $(am_perf_datastore_api_sqlite_OBJECTS) perf_datastore_api_sqlite_DEPENDENCIES = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la am_perf_plugin_datastore_mysql_OBJECTS = \ perf_plugin_datastore.$(OBJEXT) perf_plugin_datastore_mysql_OBJECTS = \ $(am_perf_plugin_datastore_mysql_OBJECTS) perf_plugin_datastore_mysql_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_perf_plugin_datastore_postgres_OBJECTS = \ perf_plugin_datastore.$(OBJEXT) perf_plugin_datastore_postgres_OBJECTS = \ $(am_perf_plugin_datastore_postgres_OBJECTS) perf_plugin_datastore_postgres_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_perf_plugin_datastore_sqlite_OBJECTS = \ perf_plugin_datastore.$(OBJEXT) perf_plugin_datastore_sqlite_OBJECTS = \ $(am_perf_plugin_datastore_sqlite_OBJECTS) perf_plugin_datastore_sqlite_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_datastore_api_management_mysql_OBJECTS = \ test_datastore_api_management.$(OBJEXT) test_datastore_api_management_mysql_OBJECTS = \ $(am_test_datastore_api_management_mysql_OBJECTS) test_datastore_api_management_mysql_DEPENDENCIES = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_datastore_api_management_postgres_OBJECTS = \ test_datastore_api_management.$(OBJEXT) test_datastore_api_management_postgres_OBJECTS = \ $(am_test_datastore_api_management_postgres_OBJECTS) test_datastore_api_management_postgres_DEPENDENCIES = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_datastore_api_management_sqlite_OBJECTS = \ test_datastore_api_management.$(OBJEXT) test_datastore_api_management_sqlite_OBJECTS = \ $(am_test_datastore_api_management_sqlite_OBJECTS) test_datastore_api_management_sqlite_DEPENDENCIES = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_datastore_api_mysql_OBJECTS = test_datastore_api.$(OBJEXT) test_datastore_api_mysql_OBJECTS = \ $(am_test_datastore_api_mysql_OBJECTS) test_datastore_api_mysql_DEPENDENCIES = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_datastore_api_postgres_OBJECTS = test_datastore_api.$(OBJEXT) test_datastore_api_postgres_OBJECTS = \ $(am_test_datastore_api_postgres_OBJECTS) test_datastore_api_postgres_DEPENDENCIES = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_datastore_api_sqlite_OBJECTS = test_datastore_api.$(OBJEXT) test_datastore_api_sqlite_OBJECTS = \ $(am_test_datastore_api_sqlite_OBJECTS) test_datastore_api_sqlite_DEPENDENCIES = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_plugin_datastore_mysql_OBJECTS = \ test_plugin_datastore.$(OBJEXT) test_plugin_datastore_mysql_OBJECTS = \ $(am_test_plugin_datastore_mysql_OBJECTS) test_plugin_datastore_mysql_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_plugin_datastore_postgres_OBJECTS = \ test_plugin_datastore.$(OBJEXT) test_plugin_datastore_postgres_OBJECTS = \ $(am_test_plugin_datastore_postgres_OBJECTS) test_plugin_datastore_postgres_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_plugin_datastore_sqlite_OBJECTS = \ test_plugin_datastore.$(OBJEXT) test_plugin_datastore_sqlite_OBJECTS = \ $(am_test_plugin_datastore_sqlite_OBJECTS) test_plugin_datastore_sqlite_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunet_plugin_datastore_mysql_la_SOURCES) \ $(libgnunet_plugin_datastore_postgres_la_SOURCES) \ $(libgnunet_plugin_datastore_sqlite_la_SOURCES) \ $(libgnunet_plugin_datastore_template_la_SOURCES) \ $(libgnunetdatastore_la_SOURCES) \ $(gnunet_service_datastore_SOURCES) \ $(perf_datastore_api_mysql_SOURCES) \ $(perf_datastore_api_postgres_SOURCES) \ $(perf_datastore_api_sqlite_SOURCES) \ $(perf_plugin_datastore_mysql_SOURCES) \ $(perf_plugin_datastore_postgres_SOURCES) \ $(perf_plugin_datastore_sqlite_SOURCES) \ $(test_datastore_api_management_mysql_SOURCES) \ $(test_datastore_api_management_postgres_SOURCES) \ $(test_datastore_api_management_sqlite_SOURCES) \ $(test_datastore_api_mysql_SOURCES) \ $(test_datastore_api_postgres_SOURCES) \ $(test_datastore_api_sqlite_SOURCES) \ $(test_plugin_datastore_mysql_SOURCES) \ $(test_plugin_datastore_postgres_SOURCES) \ $(test_plugin_datastore_sqlite_SOURCES) DIST_SOURCES = $(libgnunet_plugin_datastore_mysql_la_SOURCES) \ $(libgnunet_plugin_datastore_postgres_la_SOURCES) \ $(libgnunet_plugin_datastore_sqlite_la_SOURCES) \ $(libgnunet_plugin_datastore_template_la_SOURCES) \ $(libgnunetdatastore_la_SOURCES) \ $(gnunet_service_datastore_SOURCES) \ $(perf_datastore_api_mysql_SOURCES) \ $(perf_datastore_api_postgres_SOURCES) \ $(perf_datastore_api_sqlite_SOURCES) \ $(perf_plugin_datastore_mysql_SOURCES) \ $(perf_plugin_datastore_postgres_SOURCES) \ $(perf_plugin_datastore_sqlite_SOURCES) \ $(test_datastore_api_management_mysql_SOURCES) \ $(test_datastore_api_management_postgres_SOURCES) \ $(test_datastore_api_management_sqlite_SOURCES) \ $(test_datastore_api_mysql_SOURCES) \ $(test_datastore_api_postgres_SOURCES) \ $(test_datastore_api_sqlite_SOURCES) \ $(test_plugin_datastore_mysql_SOURCES) \ $(test_plugin_datastore_postgres_SOURCES) \ $(test_plugin_datastore_sqlite_SOURCES) DATA = $(pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include plugindir = $(libdir)/gnunet pkgcfgdir = $(pkgdatadir)/config.d/ pkgcfg_DATA = \ datastore.conf @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @USE_COVERAGE_TRUE@XLIBS = -lgcov lib_LTLIBRARIES = \ libgnunetdatastore.la libgnunetdatastore_la_SOURCES = \ datastore_api.c datastore.h libgnunetdatastore_la_LIBADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) libgnunetdatastore_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 1:0:0 gnunet_service_datastore_SOURCES = \ gnunet-service-datastore.c gnunet_service_datastore_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) @HAVE_MYSQL_TRUE@MYSQL_PLUGIN = libgnunet_plugin_datastore_mysql.la @HAVE_BENCHMARKS_TRUE@@HAVE_MYSQL_TRUE@MYSQL_BENCHMARKS = \ @HAVE_BENCHMARKS_TRUE@@HAVE_MYSQL_TRUE@ perf_datastore_api_mysql \ @HAVE_BENCHMARKS_TRUE@@HAVE_MYSQL_TRUE@ perf_plugin_datastore_mysql @HAVE_MYSQL_TRUE@MYSQL_TESTS = \ @HAVE_MYSQL_TRUE@ test_datastore_api_mysql \ @HAVE_MYSQL_TRUE@ test_datastore_api_management_mysql \ @HAVE_MYSQL_TRUE@ test_plugin_datastore_mysql \ @HAVE_MYSQL_TRUE@ $(MYSQL_BENCHMARKS) @HAVE_SQLITE_TRUE@SQLITE_PLUGIN = libgnunet_plugin_datastore_sqlite.la @HAVE_BENCHMARKS_TRUE@@HAVE_SQLITE_TRUE@SQLITE_BENCHMARKS = \ @HAVE_BENCHMARKS_TRUE@@HAVE_SQLITE_TRUE@ perf_datastore_api_sqlite \ @HAVE_BENCHMARKS_TRUE@@HAVE_SQLITE_TRUE@ perf_plugin_datastore_sqlite @HAVE_SQLITE_TRUE@SQLITE_TESTS = \ @HAVE_SQLITE_TRUE@ test_datastore_api_sqlite \ @HAVE_SQLITE_TRUE@ test_datastore_api_management_sqlite \ @HAVE_SQLITE_TRUE@ test_plugin_datastore_sqlite \ @HAVE_SQLITE_TRUE@ $(SQLITE_BENCHMARKS) @HAVE_POSTGRES_TRUE@POSTGRES_PLUGIN = libgnunet_plugin_datastore_postgres.la @HAVE_BENCHMARKS_TRUE@@HAVE_POSTGRES_TRUE@POSTGRES_BENCHMARKS = \ @HAVE_BENCHMARKS_TRUE@@HAVE_POSTGRES_TRUE@ perf_datastore_api_postgres \ @HAVE_BENCHMARKS_TRUE@@HAVE_POSTGRES_TRUE@ perf_plugin_datastore_postgres @HAVE_POSTGRES_TRUE@POSTGRES_TESTS = \ @HAVE_POSTGRES_TRUE@ test_datastore_api_postgres \ @HAVE_POSTGRES_TRUE@ test_datastore_api_management_postgres \ @HAVE_POSTGRES_TRUE@ test_plugin_datastore_postgres \ @HAVE_POSTGRES_TRUE@ $(POSTGRES_BENCHMARKS) plugin_LTLIBRARIES = \ $(SQLITE_PLUGIN) \ $(MYSQL_PLUGIN) \ $(POSTGRES_PLUGIN) \ libgnunet_plugin_datastore_template.la libgnunet_plugin_datastore_sqlite_la_SOURCES = \ plugin_datastore_sqlite.c libgnunet_plugin_datastore_sqlite_la_LIBADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 libgnunet_plugin_datastore_sqlite_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_datastore_mysql_la_SOURCES = \ plugin_datastore_mysql.c libgnunet_plugin_datastore_mysql_la_LIBADD = \ $(top_builddir)/src/mysql/libgnunetmysql.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lz -lmysqlclient libgnunet_plugin_datastore_mysql_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) $(MYSQL_LDFLAGS) -lmysqlclient libgnunet_plugin_datastore_mysql_la_CPPFLAGS = \ $(MYSQL_CPPFLAGS) libgnunet_plugin_datastore_postgres_la_SOURCES = \ plugin_datastore_postgres.c libgnunet_plugin_datastore_postgres_la_LIBADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/postgres/libgnunetpostgres.la \ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lpq libgnunet_plugin_datastore_postgres_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) $(POSTGRES_LDFLAGS) -lpq libgnunet_plugin_datastore_postgres_la_CPPFLAGS = \ $(POSTGRES_CPPFLAGS) libgnunet_plugin_datastore_template_la_SOURCES = \ plugin_datastore_template.c libgnunet_plugin_datastore_template_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) libgnunet_plugin_datastore_template_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) @ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) test_datastore_api_sqlite_SOURCES = \ test_datastore_api.c test_datastore_api_sqlite_LDADD = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la test_datastore_api_management_sqlite_SOURCES = \ test_datastore_api_management.c test_datastore_api_management_sqlite_LDADD = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la perf_datastore_api_sqlite_SOURCES = \ perf_datastore_api.c perf_datastore_api_sqlite_LDADD = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la perf_plugin_datastore_sqlite_SOURCES = \ perf_plugin_datastore.c perf_plugin_datastore_sqlite_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_plugin_datastore_sqlite_SOURCES = \ test_plugin_datastore.c test_plugin_datastore_sqlite_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_datastore_api_mysql_SOURCES = \ test_datastore_api.c test_datastore_api_mysql_LDADD = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la test_datastore_api_management_mysql_SOURCES = \ test_datastore_api_management.c test_datastore_api_management_mysql_LDADD = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la perf_datastore_api_mysql_SOURCES = \ perf_datastore_api.c perf_datastore_api_mysql_LDADD = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la test_plugin_datastore_mysql_SOURCES = \ test_plugin_datastore.c test_plugin_datastore_mysql_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la perf_plugin_datastore_mysql_SOURCES = \ perf_plugin_datastore.c perf_plugin_datastore_mysql_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_datastore_api_postgres_SOURCES = \ test_datastore_api.c test_datastore_api_postgres_LDADD = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la test_datastore_api_management_postgres_SOURCES = \ test_datastore_api_management.c test_datastore_api_management_postgres_LDADD = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la perf_datastore_api_postgres_SOURCES = \ perf_datastore_api.c perf_datastore_api_postgres_LDADD = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la test_plugin_datastore_postgres_SOURCES = \ test_plugin_datastore.c test_plugin_datastore_postgres_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la perf_plugin_datastore_postgres_SOURCES = \ perf_plugin_datastore.c perf_plugin_datastore_postgres_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ test_defaults.conf \ test_datastore_api_data_sqlite.conf \ perf_plugin_datastore_data_sqlite.conf \ test_datastore_api_data_mysql.conf \ perf_plugin_datastore_data_mysql.conf \ test_datastore_api_data_postgres.conf \ perf_plugin_datastore_data_postgres.conf \ test_plugin_datastore_data_mysql.conf \ test_plugin_datastore_data_postgres.conf \ test_plugin_datastore_data_sqlite.conf all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/datastore/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/datastore/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): datastore.conf: $(top_builddir)/config.status $(srcdir)/datastore.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ } uninstall-pluginLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ done clean-pluginLTLIBRARIES: -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunet_plugin_datastore_mysql.la: $(libgnunet_plugin_datastore_mysql_la_OBJECTS) $(libgnunet_plugin_datastore_mysql_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_datastore_mysql_la_LINK) $(am_libgnunet_plugin_datastore_mysql_la_rpath) $(libgnunet_plugin_datastore_mysql_la_OBJECTS) $(libgnunet_plugin_datastore_mysql_la_LIBADD) $(LIBS) libgnunet_plugin_datastore_postgres.la: $(libgnunet_plugin_datastore_postgres_la_OBJECTS) $(libgnunet_plugin_datastore_postgres_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_datastore_postgres_la_LINK) $(am_libgnunet_plugin_datastore_postgres_la_rpath) $(libgnunet_plugin_datastore_postgres_la_OBJECTS) $(libgnunet_plugin_datastore_postgres_la_LIBADD) $(LIBS) libgnunet_plugin_datastore_sqlite.la: $(libgnunet_plugin_datastore_sqlite_la_OBJECTS) $(libgnunet_plugin_datastore_sqlite_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_datastore_sqlite_la_LINK) $(am_libgnunet_plugin_datastore_sqlite_la_rpath) $(libgnunet_plugin_datastore_sqlite_la_OBJECTS) $(libgnunet_plugin_datastore_sqlite_la_LIBADD) $(LIBS) libgnunet_plugin_datastore_template.la: $(libgnunet_plugin_datastore_template_la_OBJECTS) $(libgnunet_plugin_datastore_template_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_datastore_template_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_datastore_template_la_OBJECTS) $(libgnunet_plugin_datastore_template_la_LIBADD) $(LIBS) libgnunetdatastore.la: $(libgnunetdatastore_la_OBJECTS) $(libgnunetdatastore_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetdatastore_la_LINK) -rpath $(libdir) $(libgnunetdatastore_la_OBJECTS) $(libgnunetdatastore_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-service-datastore$(EXEEXT): $(gnunet_service_datastore_OBJECTS) $(gnunet_service_datastore_DEPENDENCIES) @rm -f gnunet-service-datastore$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_service_datastore_OBJECTS) $(gnunet_service_datastore_LDADD) $(LIBS) perf_datastore_api_mysql$(EXEEXT): $(perf_datastore_api_mysql_OBJECTS) $(perf_datastore_api_mysql_DEPENDENCIES) @rm -f perf_datastore_api_mysql$(EXEEXT) $(AM_V_CCLD)$(LINK) $(perf_datastore_api_mysql_OBJECTS) $(perf_datastore_api_mysql_LDADD) $(LIBS) perf_datastore_api_postgres$(EXEEXT): $(perf_datastore_api_postgres_OBJECTS) $(perf_datastore_api_postgres_DEPENDENCIES) @rm -f perf_datastore_api_postgres$(EXEEXT) $(AM_V_CCLD)$(LINK) $(perf_datastore_api_postgres_OBJECTS) $(perf_datastore_api_postgres_LDADD) $(LIBS) perf_datastore_api_sqlite$(EXEEXT): $(perf_datastore_api_sqlite_OBJECTS) $(perf_datastore_api_sqlite_DEPENDENCIES) @rm -f perf_datastore_api_sqlite$(EXEEXT) $(AM_V_CCLD)$(LINK) $(perf_datastore_api_sqlite_OBJECTS) $(perf_datastore_api_sqlite_LDADD) $(LIBS) perf_plugin_datastore_mysql$(EXEEXT): $(perf_plugin_datastore_mysql_OBJECTS) $(perf_plugin_datastore_mysql_DEPENDENCIES) @rm -f perf_plugin_datastore_mysql$(EXEEXT) $(AM_V_CCLD)$(LINK) $(perf_plugin_datastore_mysql_OBJECTS) $(perf_plugin_datastore_mysql_LDADD) $(LIBS) perf_plugin_datastore_postgres$(EXEEXT): $(perf_plugin_datastore_postgres_OBJECTS) $(perf_plugin_datastore_postgres_DEPENDENCIES) @rm -f perf_plugin_datastore_postgres$(EXEEXT) $(AM_V_CCLD)$(LINK) $(perf_plugin_datastore_postgres_OBJECTS) $(perf_plugin_datastore_postgres_LDADD) $(LIBS) perf_plugin_datastore_sqlite$(EXEEXT): $(perf_plugin_datastore_sqlite_OBJECTS) $(perf_plugin_datastore_sqlite_DEPENDENCIES) @rm -f perf_plugin_datastore_sqlite$(EXEEXT) $(AM_V_CCLD)$(LINK) $(perf_plugin_datastore_sqlite_OBJECTS) $(perf_plugin_datastore_sqlite_LDADD) $(LIBS) test_datastore_api_management_mysql$(EXEEXT): $(test_datastore_api_management_mysql_OBJECTS) $(test_datastore_api_management_mysql_DEPENDENCIES) @rm -f test_datastore_api_management_mysql$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_datastore_api_management_mysql_OBJECTS) $(test_datastore_api_management_mysql_LDADD) $(LIBS) test_datastore_api_management_postgres$(EXEEXT): $(test_datastore_api_management_postgres_OBJECTS) $(test_datastore_api_management_postgres_DEPENDENCIES) @rm -f test_datastore_api_management_postgres$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_datastore_api_management_postgres_OBJECTS) $(test_datastore_api_management_postgres_LDADD) $(LIBS) test_datastore_api_management_sqlite$(EXEEXT): $(test_datastore_api_management_sqlite_OBJECTS) $(test_datastore_api_management_sqlite_DEPENDENCIES) @rm -f test_datastore_api_management_sqlite$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_datastore_api_management_sqlite_OBJECTS) $(test_datastore_api_management_sqlite_LDADD) $(LIBS) test_datastore_api_mysql$(EXEEXT): $(test_datastore_api_mysql_OBJECTS) $(test_datastore_api_mysql_DEPENDENCIES) @rm -f test_datastore_api_mysql$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_datastore_api_mysql_OBJECTS) $(test_datastore_api_mysql_LDADD) $(LIBS) test_datastore_api_postgres$(EXEEXT): $(test_datastore_api_postgres_OBJECTS) $(test_datastore_api_postgres_DEPENDENCIES) @rm -f test_datastore_api_postgres$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_datastore_api_postgres_OBJECTS) $(test_datastore_api_postgres_LDADD) $(LIBS) test_datastore_api_sqlite$(EXEEXT): $(test_datastore_api_sqlite_OBJECTS) $(test_datastore_api_sqlite_DEPENDENCIES) @rm -f test_datastore_api_sqlite$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_datastore_api_sqlite_OBJECTS) $(test_datastore_api_sqlite_LDADD) $(LIBS) test_plugin_datastore_mysql$(EXEEXT): $(test_plugin_datastore_mysql_OBJECTS) $(test_plugin_datastore_mysql_DEPENDENCIES) @rm -f test_plugin_datastore_mysql$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_plugin_datastore_mysql_OBJECTS) $(test_plugin_datastore_mysql_LDADD) $(LIBS) test_plugin_datastore_postgres$(EXEEXT): $(test_plugin_datastore_postgres_OBJECTS) $(test_plugin_datastore_postgres_DEPENDENCIES) @rm -f test_plugin_datastore_postgres$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_plugin_datastore_postgres_OBJECTS) $(test_plugin_datastore_postgres_LDADD) $(LIBS) test_plugin_datastore_sqlite$(EXEEXT): $(test_plugin_datastore_sqlite_OBJECTS) $(test_plugin_datastore_sqlite_DEPENDENCIES) @rm -f test_plugin_datastore_sqlite$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_plugin_datastore_sqlite_OBJECTS) $(test_plugin_datastore_sqlite_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/datastore_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-datastore.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_datastore_mysql_la-plugin_datastore_mysql.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_datastore_postgres_la-plugin_datastore_postgres.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perf_datastore_api.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perf_plugin_datastore.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_datastore_sqlite.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_datastore_template.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_datastore_api.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_datastore_api_management.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_plugin_datastore.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< libgnunet_plugin_datastore_mysql_la-plugin_datastore_mysql.lo: plugin_datastore_mysql.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_datastore_mysql_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_datastore_mysql_la-plugin_datastore_mysql.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_datastore_mysql_la-plugin_datastore_mysql.Tpo -c -o libgnunet_plugin_datastore_mysql_la-plugin_datastore_mysql.lo `test -f 'plugin_datastore_mysql.c' || echo '$(srcdir)/'`plugin_datastore_mysql.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_datastore_mysql_la-plugin_datastore_mysql.Tpo $(DEPDIR)/libgnunet_plugin_datastore_mysql_la-plugin_datastore_mysql.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_datastore_mysql.c' object='libgnunet_plugin_datastore_mysql_la-plugin_datastore_mysql.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_datastore_mysql_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_datastore_mysql_la-plugin_datastore_mysql.lo `test -f 'plugin_datastore_mysql.c' || echo '$(srcdir)/'`plugin_datastore_mysql.c libgnunet_plugin_datastore_postgres_la-plugin_datastore_postgres.lo: plugin_datastore_postgres.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_datastore_postgres_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_datastore_postgres_la-plugin_datastore_postgres.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_datastore_postgres_la-plugin_datastore_postgres.Tpo -c -o libgnunet_plugin_datastore_postgres_la-plugin_datastore_postgres.lo `test -f 'plugin_datastore_postgres.c' || echo '$(srcdir)/'`plugin_datastore_postgres.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_datastore_postgres_la-plugin_datastore_postgres.Tpo $(DEPDIR)/libgnunet_plugin_datastore_postgres_la-plugin_datastore_postgres.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_datastore_postgres.c' object='libgnunet_plugin_datastore_postgres_la-plugin_datastore_postgres.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_datastore_postgres_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_datastore_postgres_la-plugin_datastore_postgres.lo `test -f 'plugin_datastore_postgres.c' || echo '$(srcdir)/'`plugin_datastore_postgres.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgcfgDATA: $(pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool clean-pluginLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgcfgDATA install-pluginLTLIBRARIES install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool clean-pluginLTLIBRARIES \ ctags distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-libLTLIBRARIES \ install-man install-pdf install-pdf-am install-pkgcfgDATA \ install-pluginLTLIBRARIES install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/datastore/datastore_api.c0000644000175000017500000013404611760502550015515 00000000000000/* This file is part of GNUnet (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file datastore/datastore_api.c * @brief Management for the datastore for files stored on a GNUnet node. Implements * a priority queue for requests (with timeouts). * @author Christian Grothoff */ #include "platform.h" #include "gnunet_arm_service.h" #include "gnunet_constants.h" #include "gnunet_datastore_service.h" #include "gnunet_statistics_service.h" #include "datastore.h" #define LOG(kind,...) GNUNET_log_from (kind, "datastore-api",__VA_ARGS__) /** * If a client stopped asking for more results, how many more do * we receive from the DB before killing the connection? Trade-off * between re-doing TCP handshakes and (needlessly) receiving * useless results. */ #define MAX_EXCESS_RESULTS 8 /** * Context for processing status messages. */ struct StatusContext { /** * Continuation to call with the status. */ GNUNET_DATASTORE_ContinuationWithStatus cont; /** * Closure for cont. */ void *cont_cls; }; /** * Context for processing result messages. */ struct ResultContext { /** * Function to call with the result. */ GNUNET_DATASTORE_DatumProcessor proc; /** * Closure for proc. */ void *proc_cls; }; /** * Context for a queue operation. */ union QueueContext { struct StatusContext sc; struct ResultContext rc; }; /** * Entry in our priority queue. */ struct GNUNET_DATASTORE_QueueEntry { /** * This is a linked list. */ struct GNUNET_DATASTORE_QueueEntry *next; /** * This is a linked list. */ struct GNUNET_DATASTORE_QueueEntry *prev; /** * Handle to the master context. */ struct GNUNET_DATASTORE_Handle *h; /** * Response processor (NULL if we are not waiting for a response). * This struct should be used for the closure, function-specific * arguments can be passed via 'qc'. */ GNUNET_CLIENT_MessageHandler response_proc; /** * Function to call after transmission of the request. */ GNUNET_DATASTORE_ContinuationWithStatus cont; /** * Closure for 'cont'. */ void *cont_cls; /** * Context for the operation. */ union QueueContext qc; /** * Task for timeout signalling. */ GNUNET_SCHEDULER_TaskIdentifier task; /** * Timeout for the current operation. */ struct GNUNET_TIME_Absolute timeout; /** * Priority in the queue. */ unsigned int priority; /** * Maximum allowed length of queue (otherwise * this request should be discarded). */ unsigned int max_queue; /** * Number of bytes in the request message following * this struct. 32-bit value for nicer memory * access (and overall struct alignment). */ uint32_t message_size; /** * Has this message been transmitted to the service? * Only ever GNUNET_YES for the head of the queue. * Note that the overall struct should end at a * multiple of 64 bits. */ int was_transmitted; }; /** * Handle to the datastore service. */ struct GNUNET_DATASTORE_Handle { /** * Our configuration. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Current connection to the datastore service. */ struct GNUNET_CLIENT_Connection *client; /** * Handle for statistics. */ struct GNUNET_STATISTICS_Handle *stats; /** * Current transmit handle. */ struct GNUNET_CLIENT_TransmitHandle *th; /** * Current head of priority queue. */ struct GNUNET_DATASTORE_QueueEntry *queue_head; /** * Current tail of priority queue. */ struct GNUNET_DATASTORE_QueueEntry *queue_tail; /** * Task for trying to reconnect. */ GNUNET_SCHEDULER_TaskIdentifier reconnect_task; /** * How quickly should we retry? Used for exponential back-off on * connect-errors. */ struct GNUNET_TIME_Relative retry_time; /** * Number of entries in the queue. */ unsigned int queue_size; /** * Number of results we're receiving for the current query * after application stopped to care. Used to determine when * to reset the connection. */ unsigned int result_count; /** * Are we currently trying to receive from the service? */ int in_receive; /** * We should ignore the next message(s) from the service. */ unsigned int skip_next_messages; }; /** * Connect to the datastore service. * * @param cfg configuration to use * @return handle to use to access the service */ struct GNUNET_DATASTORE_Handle * GNUNET_DATASTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_CLIENT_Connection *c; struct GNUNET_DATASTORE_Handle *h; c = GNUNET_CLIENT_connect ("datastore", cfg); if (c == NULL) return NULL; /* oops */ h = GNUNET_malloc (sizeof (struct GNUNET_DATASTORE_Handle) + GNUNET_SERVER_MAX_MESSAGE_SIZE - 1); h->client = c; h->cfg = cfg; h->stats = GNUNET_STATISTICS_create ("datastore-api", cfg); return h; } /** * Task used by 'transmit_drop' to disconnect the datastore. * * @param cls the datastore handle * @param tc scheduler context */ static void disconnect_after_drop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_DATASTORE_Handle *h = cls; GNUNET_DATASTORE_disconnect (h, GNUNET_NO); } /** * Transmit DROP message to datastore service. * * @param cls the 'struct GNUNET_DATASTORE_Handle' * @param size number of bytes that can be copied to buf * @param buf where to copy the drop message * @return number of bytes written to buf */ static size_t transmit_drop (void *cls, size_t size, void *buf) { struct GNUNET_DATASTORE_Handle *h = cls; struct GNUNET_MessageHeader *hdr; if (buf == NULL) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Failed to transmit request to drop database.\n")); GNUNET_SCHEDULER_add_continuation (&disconnect_after_drop, h, GNUNET_SCHEDULER_REASON_PREREQ_DONE); return 0; } GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); hdr = buf; hdr->size = htons (sizeof (struct GNUNET_MessageHeader)); hdr->type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_DROP); GNUNET_SCHEDULER_add_continuation (&disconnect_after_drop, h, GNUNET_SCHEDULER_REASON_PREREQ_DONE); return sizeof (struct GNUNET_MessageHeader); } /** * Disconnect from the datastore service (and free * associated resources). * * @param h handle to the datastore * @param drop set to GNUNET_YES to delete all data in datastore (!) */ void GNUNET_DATASTORE_disconnect (struct GNUNET_DATASTORE_Handle *h, int drop) { struct GNUNET_DATASTORE_QueueEntry *qe; LOG (GNUNET_ERROR_TYPE_DEBUG, "Datastore disconnect\n"); if (NULL != h->th) { GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); h->th = NULL; } if (h->client != NULL) { GNUNET_CLIENT_disconnect (h->client); h->client = NULL; } if (h->reconnect_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (h->reconnect_task); h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; } while (NULL != (qe = h->queue_head)) { GNUNET_assert (NULL != qe->response_proc); qe->response_proc (h, NULL); } if (GNUNET_YES == drop) { h->client = GNUNET_CLIENT_connect ("datastore", h->cfg); if (h->client != NULL) { if (NULL != GNUNET_CLIENT_notify_transmit_ready (h->client, sizeof (struct GNUNET_MessageHeader), GNUNET_TIME_UNIT_MINUTES, GNUNET_YES, &transmit_drop, h)) return; GNUNET_CLIENT_disconnect (h->client); h->client = NULL; } GNUNET_break (0); } GNUNET_STATISTICS_destroy (h->stats, GNUNET_NO); h->stats = NULL; GNUNET_free (h); } /** * A request has timed out (before being transmitted to the service). * * @param cls the 'struct GNUNET_DATASTORE_QueueEntry' * @param tc scheduler context */ static void timeout_queue_entry (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_DATASTORE_QueueEntry *qe = cls; GNUNET_STATISTICS_update (qe->h->stats, gettext_noop ("# queue entry timeouts"), 1, GNUNET_NO); qe->task = GNUNET_SCHEDULER_NO_TASK; GNUNET_assert (qe->was_transmitted == GNUNET_NO); LOG (GNUNET_ERROR_TYPE_DEBUG, "Timeout of request in datastore queue\n"); qe->response_proc (qe->h, NULL); } /** * Create a new entry for our priority queue (and possibly discard other entires if * the queue is getting too long). * * @param h handle to the datastore * @param msize size of the message to queue * @param queue_priority priority of the entry * @param max_queue_size at what queue size should this request be dropped * (if other requests of higher priority are in the queue) * @param timeout timeout for the operation * @param response_proc function to call with replies (can be NULL) * @param qc client context (NOT a closure for response_proc) * @return NULL if the queue is full */ static struct GNUNET_DATASTORE_QueueEntry * make_queue_entry (struct GNUNET_DATASTORE_Handle *h, size_t msize, unsigned int queue_priority, unsigned int max_queue_size, struct GNUNET_TIME_Relative timeout, GNUNET_CLIENT_MessageHandler response_proc, const union QueueContext *qc) { struct GNUNET_DATASTORE_QueueEntry *ret; struct GNUNET_DATASTORE_QueueEntry *pos; unsigned int c; c = 0; pos = h->queue_head; while ((pos != NULL) && (c < max_queue_size) && (pos->priority >= queue_priority)) { c++; pos = pos->next; } if (c >= max_queue_size) { GNUNET_STATISTICS_update (h->stats, gettext_noop ("# queue overflows"), 1, GNUNET_NO); return NULL; } ret = GNUNET_malloc (sizeof (struct GNUNET_DATASTORE_QueueEntry) + msize); ret->h = h; ret->response_proc = response_proc; ret->qc = *qc; ret->timeout = GNUNET_TIME_relative_to_absolute (timeout); ret->priority = queue_priority; ret->max_queue = max_queue_size; ret->message_size = msize; ret->was_transmitted = GNUNET_NO; if (pos == NULL) { /* append at the tail */ pos = h->queue_tail; } else { pos = pos->prev; /* do not insert at HEAD if HEAD query was already * transmitted and we are still receiving replies! */ if ((pos == NULL) && (h->queue_head->was_transmitted)) pos = h->queue_head; } c++; GNUNET_STATISTICS_update (h->stats, gettext_noop ("# queue entries created"), 1, GNUNET_NO); GNUNET_CONTAINER_DLL_insert_after (h->queue_head, h->queue_tail, pos, ret); h->queue_size++; ret->task = GNUNET_SCHEDULER_add_delayed (timeout, &timeout_queue_entry, ret); pos = ret->next; while (pos != NULL) { if ((pos->max_queue < h->queue_size) && (pos->was_transmitted == GNUNET_NO)) { GNUNET_assert (pos->response_proc != NULL); /* move 'pos' element to head so that it will be * killed on 'NULL' call below */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Dropping request from datastore queue\n"); GNUNET_CONTAINER_DLL_remove (h->queue_head, h->queue_tail, pos); GNUNET_CONTAINER_DLL_insert (h->queue_head, h->queue_tail, pos); GNUNET_STATISTICS_update (h->stats, gettext_noop ("# Requests dropped from datastore queue"), 1, GNUNET_NO); GNUNET_assert (h->queue_head == pos); pos->response_proc (h, NULL); break; } pos = pos->next; } return ret; } /** * Process entries in the queue (or do nothing if we are already * doing so). * * @param h handle to the datastore */ static void process_queue (struct GNUNET_DATASTORE_Handle *h); /** * Try reconnecting to the datastore service. * * @param cls the 'struct GNUNET_DATASTORE_Handle' * @param tc scheduler context */ static void try_reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_DATASTORE_Handle *h = cls; if (h->retry_time.rel_value < GNUNET_CONSTANTS_SERVICE_RETRY.rel_value) h->retry_time = GNUNET_CONSTANTS_SERVICE_RETRY; else h->retry_time = GNUNET_TIME_relative_multiply (h->retry_time, 2); if (h->retry_time.rel_value > GNUNET_CONSTANTS_SERVICE_TIMEOUT.rel_value) h->retry_time = GNUNET_CONSTANTS_SERVICE_TIMEOUT; h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; h->client = GNUNET_CLIENT_connect ("datastore", h->cfg); if (h->client == NULL) { LOG (GNUNET_ERROR_TYPE_ERROR, "DATASTORE reconnect failed (fatally)\n"); return; } GNUNET_STATISTICS_update (h->stats, gettext_noop ("# datastore connections (re)created"), 1, GNUNET_NO); LOG (GNUNET_ERROR_TYPE_DEBUG, "Reconnected to DATASTORE\n"); process_queue (h); } /** * Disconnect from the service and then try reconnecting to the datastore service * after some delay. * * @param h handle to datastore to disconnect and reconnect */ static void do_disconnect (struct GNUNET_DATASTORE_Handle *h) { if (h->client == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "client NULL in disconnect, will not try to reconnect\n"); return; } #if 0 GNUNET_STATISTICS_update (stats, gettext_noop ("# reconnected to DATASTORE"), 1, GNUNET_NO); #endif GNUNET_CLIENT_disconnect (h->client); h->skip_next_messages = 0; h->client = NULL; h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->retry_time, &try_reconnect, h); } /** * Function called whenever we receive a message from * the service. Calls the appropriate handler. * * @param cls the 'struct GNUNET_DATASTORE_Handle' * @param msg the received message */ static void receive_cb (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_DATASTORE_Handle *h = cls; struct GNUNET_DATASTORE_QueueEntry *qe; h->in_receive = GNUNET_NO; LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving reply from datastore\n"); if (h->skip_next_messages > 0) { h->skip_next_messages--; process_queue (h); return; } if (NULL == (qe = h->queue_head)) { GNUNET_break (0); process_queue (h); return; } qe->response_proc (h, msg); } /** * Transmit request from queue to datastore service. * * @param cls the 'struct GNUNET_DATASTORE_Handle' * @param size number of bytes that can be copied to buf * @param buf where to copy the drop message * @return number of bytes written to buf */ static size_t transmit_request (void *cls, size_t size, void *buf) { struct GNUNET_DATASTORE_Handle *h = cls; struct GNUNET_DATASTORE_QueueEntry *qe; size_t msize; h->th = NULL; if (NULL == (qe = h->queue_head)) return 0; /* no entry in queue */ if (buf == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to transmit request to DATASTORE.\n"); GNUNET_STATISTICS_update (h->stats, gettext_noop ("# transmission request failures"), 1, GNUNET_NO); do_disconnect (h); return 0; } if (size < (msize = qe->message_size)) { process_queue (h); return 0; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting %u byte request to DATASTORE\n", msize); memcpy (buf, &qe[1], msize); qe->was_transmitted = GNUNET_YES; GNUNET_SCHEDULER_cancel (qe->task); qe->task = GNUNET_SCHEDULER_NO_TASK; GNUNET_assert (GNUNET_NO == h->in_receive); h->in_receive = GNUNET_YES; GNUNET_CLIENT_receive (h->client, &receive_cb, h, GNUNET_TIME_absolute_get_remaining (qe->timeout)); GNUNET_STATISTICS_update (h->stats, gettext_noop ("# bytes sent to datastore"), 1, GNUNET_NO); return msize; } /** * Process entries in the queue (or do nothing if we are already * doing so). * * @param h handle to the datastore */ static void process_queue (struct GNUNET_DATASTORE_Handle *h) { struct GNUNET_DATASTORE_QueueEntry *qe; if (NULL == (qe = h->queue_head)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Queue empty\n"); return; /* no entry in queue */ } if (qe->was_transmitted == GNUNET_YES) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Head request already transmitted\n"); return; /* waiting for replies */ } if (h->th != NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Pending transmission request\n"); return; /* request pending */ } if (h->client == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Not connected\n"); return; /* waiting for reconnect */ } if (GNUNET_YES == h->in_receive) { /* wait for response to previous query */ return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Queueing %u byte request to DATASTORE\n", qe->message_size); h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, qe->message_size, GNUNET_TIME_absolute_get_remaining (qe->timeout), GNUNET_YES, &transmit_request, h); GNUNET_assert (GNUNET_NO == h->in_receive); GNUNET_break (NULL != h->th); } /** * Dummy continuation used to do nothing (but be non-zero). * * @param cls closure * @param result result * @param min_expiration expiration time * @param emsg error message */ static void drop_status_cont (void *cls, int32_t result, struct GNUNET_TIME_Absolute min_expiration, const char *emsg) { /* do nothing */ } /** * Free a queue entry. Removes the given entry from the * queue and releases associated resources. Does NOT * call the callback. * * @param qe entry to free. */ static void free_queue_entry (struct GNUNET_DATASTORE_QueueEntry *qe) { struct GNUNET_DATASTORE_Handle *h = qe->h; GNUNET_CONTAINER_DLL_remove (h->queue_head, h->queue_tail, qe); if (qe->task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (qe->task); qe->task = GNUNET_SCHEDULER_NO_TASK; } h->queue_size--; qe->was_transmitted = GNUNET_SYSERR; /* use-after-free warning */ GNUNET_free (qe); } /** * Type of a function to call when we receive a message * from the service. * * @param cls closure * @param msg message received, NULL on timeout or fatal error */ static void process_status_message (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_DATASTORE_Handle *h = cls; struct GNUNET_DATASTORE_QueueEntry *qe; struct StatusContext rc; const struct StatusMessage *sm; const char *emsg; int32_t status; int was_transmitted; if (NULL == (qe = h->queue_head)) { GNUNET_break (0); do_disconnect (h); return; } rc = qe->qc.sc; if (msg == NULL) { was_transmitted = qe->was_transmitted; free_queue_entry (qe); if (was_transmitted == GNUNET_YES) do_disconnect (h); else process_queue (h); if (rc.cont != NULL) rc.cont (rc.cont_cls, GNUNET_SYSERR, GNUNET_TIME_UNIT_ZERO_ABS, _("Failed to receive status response from database.")); return; } GNUNET_assert (GNUNET_YES == qe->was_transmitted); free_queue_entry (qe); if ((ntohs (msg->size) < sizeof (struct StatusMessage)) || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_DATASTORE_STATUS)) { GNUNET_break (0); h->retry_time = GNUNET_TIME_UNIT_ZERO; do_disconnect (h); if (rc.cont != NULL) rc.cont (rc.cont_cls, GNUNET_SYSERR, GNUNET_TIME_UNIT_ZERO_ABS, _("Error reading response from datastore service")); return; } sm = (const struct StatusMessage *) msg; status = ntohl (sm->status); emsg = NULL; if (ntohs (msg->size) > sizeof (struct StatusMessage)) { emsg = (const char *) &sm[1]; if (emsg[ntohs (msg->size) - sizeof (struct StatusMessage) - 1] != '\0') { GNUNET_break (0); emsg = _("Invalid error message received from datastore service"); } } if ((status == GNUNET_SYSERR) && (emsg == NULL)) { GNUNET_break (0); emsg = _("Invalid error message received from datastore service"); } LOG (GNUNET_ERROR_TYPE_DEBUG, "Received status %d/%s\n", (int) status, emsg); GNUNET_STATISTICS_update (h->stats, gettext_noop ("# status messages received"), 1, GNUNET_NO); h->retry_time.rel_value = 0; process_queue (h); if (rc.cont != NULL) rc.cont (rc.cont_cls, status, GNUNET_TIME_absolute_ntoh (sm->min_expiration), emsg); } /** * Store an item in the datastore. If the item is already present, * the priorities are summed up and the higher expiration time and * lower anonymity level is used. * * @param h handle to the datastore * @param rid reservation ID to use (from "reserve"); use 0 if no * prior reservation was made * @param key key for the value * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param replication how often should the content be replicated to other peers? * @param expiration expiration time for the content * @param queue_priority ranking of this request in the priority queue * @param max_queue_size at what queue size should this request be dropped * (if other requests of higher priority are in the queue) * @param timeout timeout for the operation * @param cont continuation to call when done * @param cont_cls closure for cont * @return NULL if the entry was not queued, otherwise a handle that can be used to * cancel; note that even if NULL is returned, the callback will be invoked * (or rather, will already have been invoked) */ struct GNUNET_DATASTORE_QueueEntry * GNUNET_DATASTORE_put (struct GNUNET_DATASTORE_Handle *h, uint32_t rid, const GNUNET_HashCode * key, size_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, uint32_t replication, struct GNUNET_TIME_Absolute expiration, unsigned int queue_priority, unsigned int max_queue_size, struct GNUNET_TIME_Relative timeout, GNUNET_DATASTORE_ContinuationWithStatus cont, void *cont_cls) { struct GNUNET_DATASTORE_QueueEntry *qe; struct DataMessage *dm; size_t msize; union QueueContext qc; LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to put %u bytes of data under key `%s' for %llu ms\n", size, GNUNET_h2s (key), GNUNET_TIME_absolute_get_remaining (expiration).rel_value); msize = sizeof (struct DataMessage) + size; GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE); qc.sc.cont = cont; qc.sc.cont_cls = cont_cls; qe = make_queue_entry (h, msize, queue_priority, max_queue_size, timeout, &process_status_message, &qc); if (qe == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Could not create queue entry for PUT\n"); return NULL; } GNUNET_STATISTICS_update (h->stats, gettext_noop ("# PUT requests executed"), 1, GNUNET_NO); dm = (struct DataMessage *) &qe[1]; dm->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_PUT); dm->header.size = htons (msize); dm->rid = htonl (rid); dm->size = htonl ((uint32_t) size); dm->type = htonl (type); dm->priority = htonl (priority); dm->anonymity = htonl (anonymity); dm->replication = htonl (replication); dm->reserved = htonl (0); dm->uid = GNUNET_htonll (0); dm->expiration = GNUNET_TIME_absolute_hton (expiration); dm->key = *key; memcpy (&dm[1], data, size); process_queue (h); return qe; } /** * Reserve space in the datastore. This function should be used * to avoid "out of space" failures during a longer sequence of "put" * operations (for example, when a file is being inserted). * * @param h handle to the datastore * @param amount how much space (in bytes) should be reserved (for content only) * @param entries how many entries will be created (to calculate per-entry overhead) * @param queue_priority ranking of this request in the priority queue * @param max_queue_size at what queue size should this request be dropped * (if other requests of higher priority are in the queue) * @param timeout how long to wait at most for a response (or before dying in queue) * @param cont continuation to call when done; "success" will be set to * a positive reservation value if space could be reserved. * @param cont_cls closure for cont * @return NULL if the entry was not queued, otherwise a handle that can be used to * cancel; note that even if NULL is returned, the callback will be invoked * (or rather, will already have been invoked) */ struct GNUNET_DATASTORE_QueueEntry * GNUNET_DATASTORE_reserve (struct GNUNET_DATASTORE_Handle *h, uint64_t amount, uint32_t entries, unsigned int queue_priority, unsigned int max_queue_size, struct GNUNET_TIME_Relative timeout, GNUNET_DATASTORE_ContinuationWithStatus cont, void *cont_cls) { struct GNUNET_DATASTORE_QueueEntry *qe; struct ReserveMessage *rm; union QueueContext qc; if (cont == NULL) cont = &drop_status_cont; LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to reserve %llu bytes of data and %u entries\n", (unsigned long long) amount, (unsigned int) entries); qc.sc.cont = cont; qc.sc.cont_cls = cont_cls; qe = make_queue_entry (h, sizeof (struct ReserveMessage), queue_priority, max_queue_size, timeout, &process_status_message, &qc); if (qe == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Could not create queue entry to reserve\n"); return NULL; } GNUNET_STATISTICS_update (h->stats, gettext_noop ("# RESERVE requests executed"), 1, GNUNET_NO); rm = (struct ReserveMessage *) &qe[1]; rm->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_RESERVE); rm->header.size = htons (sizeof (struct ReserveMessage)); rm->entries = htonl (entries); rm->amount = GNUNET_htonll (amount); process_queue (h); return qe; } /** * Signal that all of the data for which a reservation was made has * been stored and that whatever excess space might have been reserved * can now be released. * * @param h handle to the datastore * @param rid reservation ID (value of "success" in original continuation * from the "reserve" function). * @param queue_priority ranking of this request in the priority queue * @param max_queue_size at what queue size should this request be dropped * (if other requests of higher priority are in the queue) * @param queue_priority ranking of this request in the priority queue * @param max_queue_size at what queue size should this request be dropped * (if other requests of higher priority are in the queue) * @param timeout how long to wait at most for a response * @param cont continuation to call when done * @param cont_cls closure for cont * @return NULL if the entry was not queued, otherwise a handle that can be used to * cancel; note that even if NULL is returned, the callback will be invoked * (or rather, will already have been invoked) */ struct GNUNET_DATASTORE_QueueEntry * GNUNET_DATASTORE_release_reserve (struct GNUNET_DATASTORE_Handle *h, uint32_t rid, unsigned int queue_priority, unsigned int max_queue_size, struct GNUNET_TIME_Relative timeout, GNUNET_DATASTORE_ContinuationWithStatus cont, void *cont_cls) { struct GNUNET_DATASTORE_QueueEntry *qe; struct ReleaseReserveMessage *rrm; union QueueContext qc; if (cont == NULL) cont = &drop_status_cont; LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to release reserve %d\n", rid); qc.sc.cont = cont; qc.sc.cont_cls = cont_cls; qe = make_queue_entry (h, sizeof (struct ReleaseReserveMessage), queue_priority, max_queue_size, timeout, &process_status_message, &qc); if (qe == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Could not create queue entry to release reserve\n"); return NULL; } GNUNET_STATISTICS_update (h->stats, gettext_noop ("# RELEASE RESERVE requests executed"), 1, GNUNET_NO); rrm = (struct ReleaseReserveMessage *) &qe[1]; rrm->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_RELEASE_RESERVE); rrm->header.size = htons (sizeof (struct ReleaseReserveMessage)); rrm->rid = htonl (rid); process_queue (h); return qe; } /** * Update a value in the datastore. * * @param h handle to the datastore * @param uid identifier for the value * @param priority how much to increase the priority of the value * @param expiration new expiration value should be MAX of existing and this argument * @param queue_priority ranking of this request in the priority queue * @param max_queue_size at what queue size should this request be dropped * (if other requests of higher priority are in the queue) * @param timeout how long to wait at most for a response * @param cont continuation to call when done * @param cont_cls closure for cont * @return NULL if the entry was not queued, otherwise a handle that can be used to * cancel; note that even if NULL is returned, the callback will be invoked * (or rather, will already have been invoked) */ struct GNUNET_DATASTORE_QueueEntry * GNUNET_DATASTORE_update (struct GNUNET_DATASTORE_Handle *h, uint64_t uid, uint32_t priority, struct GNUNET_TIME_Absolute expiration, unsigned int queue_priority, unsigned int max_queue_size, struct GNUNET_TIME_Relative timeout, GNUNET_DATASTORE_ContinuationWithStatus cont, void *cont_cls) { struct GNUNET_DATASTORE_QueueEntry *qe; struct UpdateMessage *um; union QueueContext qc; if (cont == NULL) cont = &drop_status_cont; LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to update entry %llu raising priority by %u and expiration to %llu\n", uid, (unsigned int) priority, (unsigned long long) expiration.abs_value); qc.sc.cont = cont; qc.sc.cont_cls = cont_cls; qe = make_queue_entry (h, sizeof (struct UpdateMessage), queue_priority, max_queue_size, timeout, &process_status_message, &qc); if (qe == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Could not create queue entry for UPDATE\n"); return NULL; } GNUNET_STATISTICS_update (h->stats, gettext_noop ("# UPDATE requests executed"), 1, GNUNET_NO); um = (struct UpdateMessage *) &qe[1]; um->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_UPDATE); um->header.size = htons (sizeof (struct UpdateMessage)); um->priority = htonl (priority); um->expiration = GNUNET_TIME_absolute_hton (expiration); um->uid = GNUNET_htonll (uid); process_queue (h); return qe; } /** * Explicitly remove some content from the database. * The "cont"inuation will be called with status * "GNUNET_OK" if content was removed, "GNUNET_NO" * if no matching entry was found and "GNUNET_SYSERR" * on all other types of errors. * * @param h handle to the datastore * @param key key for the value * @param size number of bytes in data * @param data content stored * @param queue_priority ranking of this request in the priority queue * @param max_queue_size at what queue size should this request be dropped * (if other requests of higher priority are in the queue) * @param timeout how long to wait at most for a response * @param cont continuation to call when done * @param cont_cls closure for cont * @return NULL if the entry was not queued, otherwise a handle that can be used to * cancel; note that even if NULL is returned, the callback will be invoked * (or rather, will already have been invoked) */ struct GNUNET_DATASTORE_QueueEntry * GNUNET_DATASTORE_remove (struct GNUNET_DATASTORE_Handle *h, const GNUNET_HashCode * key, size_t size, const void *data, unsigned int queue_priority, unsigned int max_queue_size, struct GNUNET_TIME_Relative timeout, GNUNET_DATASTORE_ContinuationWithStatus cont, void *cont_cls) { struct GNUNET_DATASTORE_QueueEntry *qe; struct DataMessage *dm; size_t msize; union QueueContext qc; if (cont == NULL) cont = &drop_status_cont; LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to remove %u bytes under key `%s'\n", size, GNUNET_h2s (key)); qc.sc.cont = cont; qc.sc.cont_cls = cont_cls; msize = sizeof (struct DataMessage) + size; GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE); qe = make_queue_entry (h, msize, queue_priority, max_queue_size, timeout, &process_status_message, &qc); if (qe == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Could not create queue entry for REMOVE\n"); return NULL; } GNUNET_STATISTICS_update (h->stats, gettext_noop ("# REMOVE requests executed"), 1, GNUNET_NO); dm = (struct DataMessage *) &qe[1]; dm->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_REMOVE); dm->header.size = htons (msize); dm->rid = htonl (0); dm->size = htonl (size); dm->type = htonl (0); dm->priority = htonl (0); dm->anonymity = htonl (0); dm->uid = GNUNET_htonll (0); dm->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_ZERO_ABS); dm->key = *key; memcpy (&dm[1], data, size); process_queue (h); return qe; } /** * Type of a function to call when we receive a message * from the service. * * @param cls closure * @param msg message received, NULL on timeout or fatal error */ static void process_result_message (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_DATASTORE_Handle *h = cls; struct GNUNET_DATASTORE_QueueEntry *qe; struct ResultContext rc; const struct DataMessage *dm; int was_transmitted; if (msg == NULL) { qe = h->queue_head; GNUNET_assert (NULL != qe); rc = qe->qc.rc; was_transmitted = qe->was_transmitted; free_queue_entry (qe); if (was_transmitted == GNUNET_YES) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Failed to receive response from database.\n")); do_disconnect (h); } else { process_queue (h); } if (rc.proc != NULL) rc.proc (rc.proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_DATASTORE_DATA_END) { GNUNET_break (ntohs (msg->size) == sizeof (struct GNUNET_MessageHeader)); qe = h->queue_head; rc = qe->qc.rc; GNUNET_assert (GNUNET_YES == qe->was_transmitted); free_queue_entry (qe); LOG (GNUNET_ERROR_TYPE_DEBUG, "Received end of result set, new queue size is %u\n", h->queue_size); h->retry_time.rel_value = 0; h->result_count = 0; process_queue (h); if (rc.proc != NULL) rc.proc (rc.proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } qe = h->queue_head; GNUNET_assert (NULL != qe); rc = qe->qc.rc; if (GNUNET_YES != qe->was_transmitted) { GNUNET_break (0); free_queue_entry (qe); h->retry_time = GNUNET_TIME_UNIT_ZERO; do_disconnect (h); if (rc.proc != NULL) rc.proc (rc.proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } if ((ntohs (msg->size) < sizeof (struct DataMessage)) || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_DATASTORE_DATA) || (ntohs (msg->size) != sizeof (struct DataMessage) + ntohl (((const struct DataMessage *) msg)->size))) { GNUNET_break (0); free_queue_entry (qe); h->retry_time = GNUNET_TIME_UNIT_ZERO; do_disconnect (h); if (rc.proc != NULL) rc.proc (rc.proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } GNUNET_STATISTICS_update (h->stats, gettext_noop ("# Results received"), 1, GNUNET_NO); dm = (const struct DataMessage *) msg; LOG (GNUNET_ERROR_TYPE_DEBUG, "Received result %llu with type %u and size %u with key %s\n", (unsigned long long) GNUNET_ntohll (dm->uid), ntohl (dm->type), ntohl (dm->size), GNUNET_h2s (&dm->key)); free_queue_entry (qe); h->retry_time.rel_value = 0; process_queue (h); if (rc.proc != NULL) rc.proc (rc.proc_cls, &dm->key, ntohl (dm->size), &dm[1], ntohl (dm->type), ntohl (dm->priority), ntohl (dm->anonymity), GNUNET_TIME_absolute_ntoh (dm->expiration), GNUNET_ntohll (dm->uid)); } /** * Get a random value from the datastore for content replication. * Returns a single, random value among those with the highest * replication score, lowering positive replication scores by one for * the chosen value (if only content with a replication score exists, * a random value is returned and replication scores are not changed). * * @param h handle to the datastore * @param queue_priority ranking of this request in the priority queue * @param max_queue_size at what queue size should this request be dropped * (if other requests of higher priority are in the queue) * @param timeout how long to wait at most for a response * @param proc function to call on a random value; it * will be called once with a value (if available) * and always once with a value of NULL. * @param proc_cls closure for proc * @return NULL if the entry was not queued, otherwise a handle that can be used to * cancel */ struct GNUNET_DATASTORE_QueueEntry * GNUNET_DATASTORE_get_for_replication (struct GNUNET_DATASTORE_Handle *h, unsigned int queue_priority, unsigned int max_queue_size, struct GNUNET_TIME_Relative timeout, GNUNET_DATASTORE_DatumProcessor proc, void *proc_cls) { struct GNUNET_DATASTORE_QueueEntry *qe; struct GNUNET_MessageHeader *m; union QueueContext qc; GNUNET_assert (NULL != proc); LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to get replication entry in %llu ms\n", (unsigned long long) timeout.rel_value); qc.rc.proc = proc; qc.rc.proc_cls = proc_cls; qe = make_queue_entry (h, sizeof (struct GNUNET_MessageHeader), queue_priority, max_queue_size, timeout, &process_result_message, &qc); if (qe == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Could not create queue entry for GET REPLICATION\n"); return NULL; } GNUNET_STATISTICS_update (h->stats, gettext_noop ("# GET REPLICATION requests executed"), 1, GNUNET_NO); m = (struct GNUNET_MessageHeader *) &qe[1]; m->type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_GET_REPLICATION); m->size = htons (sizeof (struct GNUNET_MessageHeader)); process_queue (h); return qe; } /** * Get a single zero-anonymity value from the datastore. * * @param h handle to the datastore * @param offset offset of the result (modulo num-results); set to * a random 64-bit value initially; then increment by * one each time; detect that all results have been found by uid * being again the first uid ever returned. * @param queue_priority ranking of this request in the priority queue * @param max_queue_size at what queue size should this request be dropped * (if other requests of higher priority are in the queue) * @param timeout how long to wait at most for a response * @param type allowed type for the operation (never zero) * @param proc function to call on a random value; it * will be called once with a value (if available) * or with NULL if none value exists. * @param proc_cls closure for proc * @return NULL if the entry was not queued, otherwise a handle that can be used to * cancel */ struct GNUNET_DATASTORE_QueueEntry * GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h, uint64_t offset, unsigned int queue_priority, unsigned int max_queue_size, struct GNUNET_TIME_Relative timeout, enum GNUNET_BLOCK_Type type, GNUNET_DATASTORE_DatumProcessor proc, void *proc_cls) { struct GNUNET_DATASTORE_QueueEntry *qe; struct GetZeroAnonymityMessage *m; union QueueContext qc; GNUNET_assert (NULL != proc); GNUNET_assert (type != GNUNET_BLOCK_TYPE_ANY); LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to get %llu-th zero-anonymity entry of type %d in %llu ms\n", (unsigned long long) offset, type, (unsigned long long) timeout.rel_value); qc.rc.proc = proc; qc.rc.proc_cls = proc_cls; qe = make_queue_entry (h, sizeof (struct GetZeroAnonymityMessage), queue_priority, max_queue_size, timeout, &process_result_message, &qc); if (qe == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Could not create queue entry for zero-anonymity procation\n"); return NULL; } GNUNET_STATISTICS_update (h->stats, gettext_noop ("# GET ZERO ANONYMITY requests executed"), 1, GNUNET_NO); m = (struct GetZeroAnonymityMessage *) &qe[1]; m->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_GET_ZERO_ANONYMITY); m->header.size = htons (sizeof (struct GetZeroAnonymityMessage)); m->type = htonl ((uint32_t) type); m->offset = GNUNET_htonll (offset); process_queue (h); return qe; } /** * Get a result for a particular key from the datastore. The processor * will only be called once. * * @param h handle to the datastore * @param offset offset of the result (modulo num-results); set to * a random 64-bit value initially; then increment by * one each time; detect that all results have been found by uid * being again the first uid ever returned. * @param key maybe NULL (to match all entries) * @param type desired type, 0 for any * @param queue_priority ranking of this request in the priority queue * @param max_queue_size at what queue size should this request be dropped * (if other requests of higher priority are in the queue) * @param timeout how long to wait at most for a response * @param proc function to call on each matching value; * will be called once with a NULL value at the end * @param proc_cls closure for proc * @return NULL if the entry was not queued, otherwise a handle that can be used to * cancel */ struct GNUNET_DATASTORE_QueueEntry * GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h, uint64_t offset, const GNUNET_HashCode * key, enum GNUNET_BLOCK_Type type, unsigned int queue_priority, unsigned int max_queue_size, struct GNUNET_TIME_Relative timeout, GNUNET_DATASTORE_DatumProcessor proc, void *proc_cls) { struct GNUNET_DATASTORE_QueueEntry *qe; struct GetMessage *gm; union QueueContext qc; GNUNET_assert (NULL != proc); LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to look for data of type %u under key `%s'\n", (unsigned int) type, GNUNET_h2s (key)); qc.rc.proc = proc; qc.rc.proc_cls = proc_cls; qe = make_queue_entry (h, sizeof (struct GetMessage), queue_priority, max_queue_size, timeout, &process_result_message, &qc); if (qe == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Could not queue request for `%s'\n", GNUNET_h2s (key)); return NULL; } GNUNET_STATISTICS_update (h->stats, gettext_noop ("# GET requests executed"), 1, GNUNET_NO); gm = (struct GetMessage *) &qe[1]; gm->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_GET); gm->type = htonl (type); gm->offset = GNUNET_htonll (offset); if (key != NULL) { gm->header.size = htons (sizeof (struct GetMessage)); gm->key = *key; } else { gm->header.size = htons (sizeof (struct GetMessage) - sizeof (GNUNET_HashCode)); } process_queue (h); return qe; } /** * Cancel a datastore operation. The final callback from the * operation must not have been done yet. * * @param qe operation to cancel */ void GNUNET_DATASTORE_cancel (struct GNUNET_DATASTORE_QueueEntry *qe) { struct GNUNET_DATASTORE_Handle *h; GNUNET_assert (GNUNET_SYSERR != qe->was_transmitted); h = qe->h; LOG (GNUNET_ERROR_TYPE_DEBUG, "Pending DATASTORE request %p cancelled (%d, %d)\n", qe, qe->was_transmitted, h->queue_head == qe); if (GNUNET_YES == qe->was_transmitted) { free_queue_entry (qe); h->skip_next_messages++; return; } free_queue_entry (qe); process_queue (h); } /* end of datastore_api.c */ gnunet-0.9.3/src/datastore/plugin_datastore_template.c0000644000175000017500000001703311760502550020131 00000000000000/* This file is part of GNUnet (C) 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file datastore/plugin_datastore_template.c * @brief template-based datastore backend * @author Christian Grothoff */ #include "platform.h" #include "gnunet_datastore_plugin.h" /** * Context for all functions in this plugin. */ struct Plugin { /** * Our execution environment. */ struct GNUNET_DATASTORE_PluginEnvironment *env; }; /** * Get an estimate of how much space the database is * currently using. * * @param cls our "struct Plugin*" * @return number of bytes used on disk */ static unsigned long long template_plugin_estimate_size (void *cls) { GNUNET_break (0); return 0; } /** * Store an item in the datastore. * * @param cls closure * @param key key for the item * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param replication replication-level for the content * @param expiration expiration time for the content * @param msg set to error message * @return GNUNET_OK on success */ static int template_plugin_put (void *cls, const GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, uint32_t replication, struct GNUNET_TIME_Absolute expiration, char **msg) { GNUNET_break (0); *msg = GNUNET_strdup ("not implemented"); return GNUNET_SYSERR; } /** * Get one of the results for a particular key in the datastore. * * @param cls closure * @param offset offset of the result (modulo num-results); * specific ordering does not matter for the offset * @param key maybe NULL (to match all entries) * @param vhash hash of the value, maybe NULL (to * match all values that have the right key). * Note that for DBlocks there is no difference * betwen key and vhash, but for other blocks * there may be! * @param type entries of which type are relevant? * Use 0 for any type. * @param proc function to call on each matching value; * will be called with NULL if nothing matches * @param proc_cls closure for proc */ static void template_plugin_get_key (void *cls, uint64_t offset, const GNUNET_HashCode * key, const GNUNET_HashCode * vhash, enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc, void *proc_cls) { GNUNET_break (0); } /** * Get a random item for replication. Returns a single, not expired, * random item from those with the highest replication counters. The * item's replication counter is decremented by one IF it was positive * before. Call 'proc' with all values ZERO or NULL if the datastore * is empty. * * @param cls closure * @param proc function to call the value (once only). * @param proc_cls closure for proc */ static void template_plugin_get_replication (void *cls, PluginDatumProcessor proc, void *proc_cls) { GNUNET_break (0); } /** * Get a random item for expiration. Call 'proc' with all values ZERO * or NULL if the datastore is empty. * * @param cls closure * @param proc function to call the value (once only). * @param proc_cls closure for proc */ static void template_plugin_get_expiration (void *cls, PluginDatumProcessor proc, void *proc_cls) { GNUNET_break (0); } /** * Update the priority for a particular key in the datastore. If * the expiration time in value is different than the time found in * the datastore, the higher value should be kept. For the * anonymity level, the lower value is to be used. The specified * priority should be added to the existing priority, ignoring the * priority in value. * * Note that it is possible for multiple values to match this put. * In that case, all of the respective values are updated. * * @param cls our "struct Plugin*" * @param uid unique identifier of the datum * @param delta by how much should the priority * change? If priority + delta < 0 the * priority should be set to 0 (never go * negative). * @param expire new expiration time should be the * MAX of any existing expiration time and * this value * @param msg set to error message * @return GNUNET_OK on success */ static int template_plugin_update (void *cls, uint64_t uid, int delta, struct GNUNET_TIME_Absolute expire, char **msg) { GNUNET_break (0); *msg = GNUNET_strdup ("not implemented"); return GNUNET_SYSERR; } /** * Call the given processor on an item with zero anonymity. * * @param cls our "struct Plugin*" * @param offset offset of the result (modulo num-results); * specific ordering does not matter for the offset * @param type entries of which type should be considered? * Use 0 for any type. * @param proc function to call on each matching value; * will be called with NULL if no value matches * @param proc_cls closure for proc */ static void template_plugin_get_zero_anonymity (void *cls, uint64_t offset, enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc, void *proc_cls) { GNUNET_break (0); } /** * Drop database. */ static void template_plugin_drop (void *cls) { GNUNET_break (0); } /** * Entry point for the plugin. * * @param cls the "struct GNUNET_DATASTORE_PluginEnvironment*" * @return our "struct Plugin*" */ void * libgnunet_plugin_datastore_template_init (void *cls) { struct GNUNET_DATASTORE_PluginEnvironment *env = cls; struct GNUNET_DATASTORE_PluginFunctions *api; struct Plugin *plugin; plugin = GNUNET_malloc (sizeof (struct Plugin)); plugin->env = env; api = GNUNET_malloc (sizeof (struct GNUNET_DATASTORE_PluginFunctions)); api->cls = plugin; api->estimate_size = &template_plugin_estimate_size; api->put = &template_plugin_put; api->update = &template_plugin_update; api->get_key = &template_plugin_get_key; api->get_replication = &template_plugin_get_replication; api->get_expiration = &template_plugin_get_expiration; api->get_zero_anonymity = &template_plugin_get_zero_anonymity; api->drop = &template_plugin_drop; GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "template", _("Template database running\n")); return api; } /** * Exit point from the plugin. * @param cls our "struct Plugin*" * @return always NULL */ void * libgnunet_plugin_datastore_template_done (void *cls) { struct GNUNET_DATASTORE_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; GNUNET_free (plugin); GNUNET_free (api); return NULL; } /* end of plugin_datastore_template.c */ gnunet-0.9.3/src/datastore/test_defaults.conf0000644000175000017500000000041011725220620016226 00000000000000[datastore] PORT = 22654 QUOTA = 1 MB [dht] AUTOSTART = NO [dns] AUTOSTART = NO [mesh] AUTOSTART = NO [nse] AUTOSTART = NO [dv] AUTOSTART = NO [chat] AUTOSTART = NO [vpn] AUTOSTART = NO [gns] AUTOSTART = NO [dv] AUTOSTART = NO [namestore] AUTOSTART = NO gnunet-0.9.3/src/datastore/gnunet-service-datastore.c0000644000175000017500000013646411760502550017626 00000000000000/* This file is part of GNUnet (C) 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file datastore/gnunet-service-datastore.c * @brief Management for the datastore for files stored on a GNUnet node * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_protocols.h" #include "gnunet_statistics_service.h" #include "gnunet_datastore_plugin.h" #include "datastore.h" /** * How many messages do we queue at most per client? */ #define MAX_PENDING 1024 /** * How long are we at most keeping "expired" content * past the expiration date in the database? */ #define MAX_EXPIRE_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) /** * How fast are we allowed to query the database for deleting * expired content? (1 item per second). */ #define MIN_EXPIRE_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) /** * Name under which we store current space consumption. */ static char *quota_stat_name; /** * After how many payload-changing operations * do we sync our statistics? */ #define MAX_STAT_SYNC_LAG 50 /** * Our datastore plugin. */ struct DatastorePlugin { /** * API of the transport as returned by the plugin's * initialization function. */ struct GNUNET_DATASTORE_PluginFunctions *api; /** * Short name for the plugin (i.e. "sqlite"). */ char *short_name; /** * Name of the library (i.e. "gnunet_plugin_datastore_sqlite"). */ char *lib_name; /** * Environment this transport service is using * for this plugin. */ struct GNUNET_DATASTORE_PluginEnvironment env; }; /** * Linked list of active reservations. */ struct ReservationList { /** * This is a linked list. */ struct ReservationList *next; /** * Client that made the reservation. */ struct GNUNET_SERVER_Client *client; /** * Number of bytes (still) reserved. */ uint64_t amount; /** * Number of items (still) reserved. */ uint64_t entries; /** * Reservation identifier. */ int32_t rid; }; /** * Our datastore plugin (NULL if not available). */ static struct DatastorePlugin *plugin; /** * Linked list of space reservations made by clients. */ static struct ReservationList *reservations; /** * Bloomfilter to quickly tell if we don't have the content. */ static struct GNUNET_CONTAINER_BloomFilter *filter; /** * How much space are we allowed to use? */ static unsigned long long quota; /** * Should the database be dropped on exit? */ static int do_drop; /** * Name of our plugin. */ static char *plugin_name; /** * How much space are we using for the cache? (space available for * insertions that will be instantly reclaimed by discarding less * important content --- or possibly whatever we just inserted into * the "cache"). */ static unsigned long long cache_size; /** * How much space have we currently reserved? */ static unsigned long long reserved; /** * How much data are we currently storing * in the database? */ static unsigned long long payload; /** * Number of updates that were made to the * payload value since we last synchronized * it with the statistics service. */ static unsigned int lastSync; /** * Did we get an answer from statistics? */ static int stats_worked; /** * Identity of the task that is used to delete * expired content. */ static GNUNET_SCHEDULER_TaskIdentifier expired_kill_task; /** * Our configuration. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Minimum time that content should have to not be discarded instantly * (time stamp of any content that we've been discarding recently to * stay below the quota). FOREVER if we had to expire content with * non-zero priority. */ static struct GNUNET_TIME_Absolute min_expiration; /** * Handle for reporting statistics. */ static struct GNUNET_STATISTICS_Handle *stats; /** * Synchronize our utilization statistics with the * statistics service. */ static void sync_stats () { GNUNET_STATISTICS_set (stats, quota_stat_name, payload, GNUNET_YES); GNUNET_STATISTICS_set (stats, "# utilization by current datastore", payload, GNUNET_NO); lastSync = 0; } /** * Context for transmitting replies to clients. */ struct TransmitCallbackContext { /** * We keep these in a doubly-linked list (for cleanup). */ struct TransmitCallbackContext *next; /** * We keep these in a doubly-linked list (for cleanup). */ struct TransmitCallbackContext *prev; /** * The message that we're asked to transmit. */ struct GNUNET_MessageHeader *msg; /** * Handle for the transmission request. */ struct GNUNET_SERVER_TransmitHandle *th; /** * Client that we are transmitting to. */ struct GNUNET_SERVER_Client *client; }; /** * Head of the doubly-linked list (for cleanup). */ static struct TransmitCallbackContext *tcc_head; /** * Tail of the doubly-linked list (for cleanup). */ static struct TransmitCallbackContext *tcc_tail; /** * Have we already cleaned up the TCCs and are hence no longer * willing (or able) to transmit anything to anyone? */ static int cleaning_done; /** * Handle for pending get request. */ static struct GNUNET_STATISTICS_GetHandle *stat_get; /** * Task that is used to remove expired entries from * the datastore. This task will schedule itself * again automatically to always delete all expired * content quickly. * * @param cls not used * @param tc task context */ static void delete_expired (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Iterate over the expired items stored in the datastore. * Delete all expired items; once we have processed all * expired items, re-schedule the "delete_expired" task. * * @param cls not used * @param key key for the content * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param expiration expiration time for the content * @param uid unique identifier for the datum; * maybe 0 if no unique identifier is available * * @return GNUNET_SYSERR to abort the iteration, GNUNET_OK to continue * (continue on call to "next", of course), * GNUNET_NO to delete the item and continue (if supported) */ static int expired_processor (void *cls, const GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct GNUNET_TIME_Absolute now; if (key == NULL) { expired_kill_task = GNUNET_SCHEDULER_add_delayed_with_priority (MAX_EXPIRE_DELAY, GNUNET_SCHEDULER_PRIORITY_IDLE, &delete_expired, NULL); return GNUNET_SYSERR; } now = GNUNET_TIME_absolute_get (); if (expiration.abs_value > now.abs_value) { /* finished processing */ expired_kill_task = GNUNET_SCHEDULER_add_delayed_with_priority (MAX_EXPIRE_DELAY, GNUNET_SCHEDULER_PRIORITY_IDLE, &delete_expired, NULL); return GNUNET_SYSERR; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting content `%s' of type %u that expired %llu ms ago\n", GNUNET_h2s (key), type, (unsigned long long) (now.abs_value - expiration.abs_value)); min_expiration = now; GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes expired"), size, GNUNET_YES); GNUNET_CONTAINER_bloomfilter_remove (filter, key); expired_kill_task = GNUNET_SCHEDULER_add_delayed_with_priority (MIN_EXPIRE_DELAY, GNUNET_SCHEDULER_PRIORITY_IDLE, &delete_expired, NULL); return GNUNET_NO; } /** * Task that is used to remove expired entries from * the datastore. This task will schedule itself * again automatically to always delete all expired * content quickly. * * @param cls not used * @param tc task context */ static void delete_expired (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { expired_kill_task = GNUNET_SCHEDULER_NO_TASK; plugin->api->get_expiration (plugin->api->cls, &expired_processor, NULL); } /** * An iterator over a set of items stored in the datastore * that deletes until we're happy with respect to our quota. * * @param cls closure * @param key key for the content * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param expiration expiration time for the content * @param uid unique identifier for the datum; * maybe 0 if no unique identifier is available * * @return GNUNET_SYSERR to abort the iteration, GNUNET_OK to continue * (continue on call to "next", of course), * GNUNET_NO to delete the item and continue (if supported) */ static int quota_processor (void *cls, const GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { unsigned long long *need = cls; if (NULL == key) return GNUNET_SYSERR; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting %llu bytes of low-priority (%u) content `%s' of type %u at %llu ms prior to expiration (still trying to free another %llu bytes)\n", (unsigned long long) (size + GNUNET_DATASTORE_ENTRY_OVERHEAD), (unsigned int) priority, GNUNET_h2s (key), type, (unsigned long long) GNUNET_TIME_absolute_get_remaining (expiration).rel_value, *need); if (size + GNUNET_DATASTORE_ENTRY_OVERHEAD > *need) *need = 0; else *need -= size + GNUNET_DATASTORE_ENTRY_OVERHEAD; if (priority > 0) min_expiration = GNUNET_TIME_UNIT_FOREVER_ABS; else min_expiration = expiration; GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes purged (low-priority)"), size, GNUNET_YES); GNUNET_CONTAINER_bloomfilter_remove (filter, key); return GNUNET_NO; } /** * Manage available disk space by running tasks * that will discard content if necessary. This * function will be run whenever a request for * "need" bytes of storage could only be satisfied * by eating into the "cache" (and we want our cache * space back). * * @param need number of bytes of content that were * placed into the "cache" (and hence the * number of bytes that should be removed). */ static void manage_space (unsigned long long need) { unsigned long long last; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asked to free up %llu bytes of cache space\n", need); last = 0; while ((need > 0) && (last != need)) { last = need; plugin->api->get_expiration (plugin->api->cls, "a_processor, &need); } } /** * Function called to notify a client about the socket * begin ready to queue more data. "buf" will be * NULL and "size" zero if the socket was closed for * writing in the meantime. * * @param cls closure * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_callback (void *cls, size_t size, void *buf) { struct TransmitCallbackContext *tcc = cls; size_t msize; tcc->th = NULL; GNUNET_CONTAINER_DLL_remove (tcc_head, tcc_tail, tcc); msize = ntohs (tcc->msg->size); if (size == 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Transmission to client failed!\n")); GNUNET_SERVER_receive_done (tcc->client, GNUNET_SYSERR); GNUNET_SERVER_client_drop (tcc->client); GNUNET_free (tcc->msg); GNUNET_free (tcc); return 0; } GNUNET_assert (size >= msize); memcpy (buf, tcc->msg, msize); GNUNET_SERVER_receive_done (tcc->client, GNUNET_OK); GNUNET_SERVER_client_drop (tcc->client); GNUNET_free (tcc->msg); GNUNET_free (tcc); return msize; } /** * Transmit the given message to the client. * * @param client target of the message * @param msg message to transmit, will be freed! */ static void transmit (struct GNUNET_SERVER_Client *client, struct GNUNET_MessageHeader *msg) { struct TransmitCallbackContext *tcc; if (GNUNET_YES == cleaning_done) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Shutdown in progress, aborting transmission.\n")); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); GNUNET_free (msg); return; } tcc = GNUNET_malloc (sizeof (struct TransmitCallbackContext)); tcc->msg = msg; tcc->client = client; if (NULL == (tcc->th = GNUNET_SERVER_notify_transmit_ready (client, ntohs (msg->size), GNUNET_TIME_UNIT_FOREVER_REL, &transmit_callback, tcc))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); GNUNET_free (msg); GNUNET_free (tcc); return; } GNUNET_SERVER_client_keep (client); GNUNET_CONTAINER_DLL_insert (tcc_head, tcc_tail, tcc); } /** * Transmit a status code to the client. * * @param client receiver of the response * @param code status code * @param msg optional error message (can be NULL) */ static void transmit_status (struct GNUNET_SERVER_Client *client, int code, const char *msg) { struct StatusMessage *sm; size_t slen; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' message with value %d and message `%s'\n", "STATUS", code, msg != NULL ? msg : "(none)"); slen = (msg == NULL) ? 0 : strlen (msg) + 1; sm = GNUNET_malloc (sizeof (struct StatusMessage) + slen); sm->header.size = htons (sizeof (struct StatusMessage) + slen); sm->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_STATUS); sm->status = htonl (code); sm->min_expiration = GNUNET_TIME_absolute_hton (min_expiration); if (slen > 0) memcpy (&sm[1], msg, slen); transmit (client, &sm->header); } /** * Function that will transmit the given datastore entry * to the client. * * @param cls closure, pointer to the client (of type GNUNET_SERVER_Client). * @param key key for the content * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param expiration expiration time for the content * @param uid unique identifier for the datum; * maybe 0 if no unique identifier is available * * @return GNUNET_SYSERR to abort the iteration, GNUNET_OK to continue, * GNUNET_NO to delete the item and continue (if supported) */ static int transmit_item (void *cls, const GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct GNUNET_SERVER_Client *client = cls; struct GNUNET_MessageHeader *end; struct DataMessage *dm; if (key == NULL) { /* transmit 'DATA_END' */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' message\n", "DATA_END"); end = GNUNET_malloc (sizeof (struct GNUNET_MessageHeader)); end->size = htons (sizeof (struct GNUNET_MessageHeader)); end->type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_DATA_END); transmit (client, end); GNUNET_SERVER_client_drop (client); return GNUNET_OK; } GNUNET_assert (sizeof (struct DataMessage) + size < GNUNET_SERVER_MAX_MESSAGE_SIZE); dm = GNUNET_malloc (sizeof (struct DataMessage) + size); dm->header.size = htons (sizeof (struct DataMessage) + size); dm->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_DATA); dm->rid = htonl (0); dm->size = htonl (size); dm->type = htonl (type); dm->priority = htonl (priority); dm->anonymity = htonl (anonymity); dm->replication = htonl (0); dm->reserved = htonl (0); dm->expiration = GNUNET_TIME_absolute_hton (expiration); dm->uid = GNUNET_htonll (uid); dm->key = *key; memcpy (&dm[1], data, size); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' message for `%s' of type %u with expiration %llu (now: %llu)\n", "DATA", GNUNET_h2s (key), type, (unsigned long long) expiration.abs_value, (unsigned long long) GNUNET_TIME_absolute_get ().abs_value); GNUNET_STATISTICS_update (stats, gettext_noop ("# results found"), 1, GNUNET_NO); transmit (client, &dm->header); GNUNET_SERVER_client_drop (client); return GNUNET_OK; } /** * Handle RESERVE-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_reserve (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { /** * Static counter to produce reservation identifiers. */ static int reservation_gen; const struct ReserveMessage *msg = (const struct ReserveMessage *) message; struct ReservationList *e; unsigned long long used; unsigned long long req; uint64_t amount; uint32_t entries; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' request\n", "RESERVE"); amount = GNUNET_ntohll (msg->amount); entries = ntohl (msg->entries); used = payload + reserved; req = amount + ((unsigned long long) GNUNET_DATASTORE_ENTRY_OVERHEAD) * entries; if (used + req > quota) { if (quota < used) used = quota; /* cheat a bit for error message (to avoid negative numbers) */ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Insufficient space (%llu bytes are available) to satisfy `%s' request for %llu bytes\n"), quota - used, "RESERVE", req); if (cache_size < req) { /* TODO: document this in the FAQ; essentially, if this * message happens, the insertion request could be blocked * by less-important content from migration because it is * larger than 1/8th of the overall available space, and * we only reserve 1/8th for "fresh" insertions */ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("The requested amount (%llu bytes) is larger than the cache size (%llu bytes)\n"), req, cache_size); transmit_status (client, 0, gettext_noop ("Insufficient space to satisfy request and " "requested amount is larger than cache size")); } else { transmit_status (client, 0, gettext_noop ("Insufficient space to satisfy request")); } return; } reserved += req; GNUNET_STATISTICS_set (stats, gettext_noop ("# reserved"), reserved, GNUNET_NO); e = GNUNET_malloc (sizeof (struct ReservationList)); e->next = reservations; reservations = e; e->client = client; e->amount = amount; e->entries = entries; e->rid = ++reservation_gen; if (reservation_gen < 0) reservation_gen = 0; /* wrap around */ transmit_status (client, e->rid, NULL); } /** * Handle RELEASE_RESERVE-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_release_reserve (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct ReleaseReserveMessage *msg = (const struct ReleaseReserveMessage *) message; struct ReservationList *pos; struct ReservationList *prev; struct ReservationList *next; int rid = ntohl (msg->rid); unsigned long long rem; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' request\n", "RELEASE_RESERVE"); next = reservations; prev = NULL; while (NULL != (pos = next)) { next = pos->next; if (rid == pos->rid) { if (prev == NULL) reservations = next; else prev->next = next; rem = pos->amount + ((unsigned long long) GNUNET_DATASTORE_ENTRY_OVERHEAD) * pos->entries; GNUNET_assert (reserved >= rem); reserved -= rem; GNUNET_STATISTICS_set (stats, gettext_noop ("# reserved"), reserved, GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Returning %llu remaining reserved bytes to storage pool\n", rem); GNUNET_free (pos); transmit_status (client, GNUNET_OK, NULL); return; } prev = pos; } GNUNET_break (0); transmit_status (client, GNUNET_SYSERR, gettext_noop ("Could not find matching reservation")); } /** * Check that the given message is a valid data message. * * @return NULL if the message is not well-formed, otherwise the message */ static const struct DataMessage * check_data (const struct GNUNET_MessageHeader *message) { uint16_t size; uint32_t dsize; const struct DataMessage *dm; size = ntohs (message->size); if (size < sizeof (struct DataMessage)) { GNUNET_break (0); return NULL; } dm = (const struct DataMessage *) message; dsize = ntohl (dm->size); if (size != dsize + sizeof (struct DataMessage)) { GNUNET_break (0); return NULL; } return dm; } /** * Context for a PUT request used to see if the content is * already present. */ struct PutContext { /** * Client to notify on completion. */ struct GNUNET_SERVER_Client *client; #if ! HAVE_UNALIGNED_64_ACCESS void *reserved; #endif /* followed by the 'struct DataMessage' */ }; /** * Actually put the data message. * * @param client sender of the message * @param dm message with the data to store */ static void execute_put (struct GNUNET_SERVER_Client *client, const struct DataMessage *dm) { uint32_t size; char *msg; int ret; size = ntohl (dm->size); msg = NULL; ret = plugin->api->put (plugin->api->cls, &dm->key, size, &dm[1], ntohl (dm->type), ntohl (dm->priority), ntohl (dm->anonymity), ntohl (dm->replication), GNUNET_TIME_absolute_ntoh (dm->expiration), &msg); if (GNUNET_OK == ret) { GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes stored"), size, GNUNET_YES); GNUNET_CONTAINER_bloomfilter_add (filter, &dm->key); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully stored %u bytes of type %u under key `%s'\n", size, ntohl (dm->type), GNUNET_h2s (&dm->key)); } transmit_status (client, ret, msg); GNUNET_free_non_null (msg); if (quota - reserved - cache_size < payload) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Need %llu bytes more space (%llu allowed, using %llu)\n"), (unsigned long long) size + GNUNET_DATASTORE_ENTRY_OVERHEAD, (unsigned long long) (quota - reserved - cache_size), (unsigned long long) payload); manage_space (size + GNUNET_DATASTORE_ENTRY_OVERHEAD); } } /** * Function that will check if the given datastore entry * matches the put and if none match executes the put. * * @param cls closure, pointer to the client (of type 'struct PutContext'). * @param key key for the content * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param expiration expiration time for the content * @param uid unique identifier for the datum; * maybe 0 if no unique identifier is available * * @return GNUNET_OK usually * GNUNET_NO to delete the item */ static int check_present (void *cls, const GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct PutContext *pc = cls; const struct DataMessage *dm; dm = (const struct DataMessage *) &pc[1]; if (key == NULL) { execute_put (pc->client, dm); GNUNET_SERVER_client_drop (pc->client); GNUNET_free (pc); return GNUNET_OK; } if ((GNUNET_BLOCK_TYPE_FS_DBLOCK == type) || (GNUNET_BLOCK_TYPE_FS_IBLOCK == type) || ((size == ntohl (dm->size)) && (0 == memcmp (&dm[1], data, size)))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result already present in datastore\n"); /* FIXME: change API to allow increasing 'replication' counter */ if ((ntohl (dm->priority) > 0) || (GNUNET_TIME_absolute_ntoh (dm->expiration).abs_value > expiration.abs_value)) plugin->api->update (plugin->api->cls, uid, (int32_t) ntohl (dm->priority), GNUNET_TIME_absolute_ntoh (dm->expiration), NULL); transmit_status (pc->client, GNUNET_NO, NULL); GNUNET_SERVER_client_drop (pc->client); GNUNET_free (pc); } else { execute_put (pc->client, dm); GNUNET_SERVER_client_drop (pc->client); GNUNET_free (pc); } return GNUNET_OK; } /** * Handle PUT-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_put (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct DataMessage *dm = check_data (message); int rid; struct ReservationList *pos; struct PutContext *pc; GNUNET_HashCode vhash; uint32_t size; if ((dm == NULL) || (ntohl (dm->type) == 0)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' request for `%s' of type %u\n", "PUT", GNUNET_h2s (&dm->key), ntohl (dm->type)); rid = ntohl (dm->rid); size = ntohl (dm->size); if (rid > 0) { pos = reservations; while ((NULL != pos) && (rid != pos->rid)) pos = pos->next; GNUNET_break (pos != NULL); if (NULL != pos) { GNUNET_break (pos->entries > 0); GNUNET_break (pos->amount >= size); pos->entries--; pos->amount -= size; reserved -= (size + GNUNET_DATASTORE_ENTRY_OVERHEAD); GNUNET_STATISTICS_set (stats, gettext_noop ("# reserved"), reserved, GNUNET_NO); } } if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (filter, &dm->key)) { GNUNET_CRYPTO_hash (&dm[1], size, &vhash); pc = GNUNET_malloc (sizeof (struct PutContext) + size + sizeof (struct DataMessage)); pc->client = client; GNUNET_SERVER_client_keep (client); memcpy (&pc[1], dm, size + sizeof (struct DataMessage)); plugin->api->get_key (plugin->api->cls, 0, &dm->key, &vhash, ntohl (dm->type), &check_present, pc); return; } execute_put (client, dm); } /** * Handle GET-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_get (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct GetMessage *msg; uint16_t size; size = ntohs (message->size); if ((size != sizeof (struct GetMessage)) && (size != sizeof (struct GetMessage) - sizeof (GNUNET_HashCode))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } msg = (const struct GetMessage *) message; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' request for `%s' of type %u\n", "GET", GNUNET_h2s (&msg->key), ntohl (msg->type)); GNUNET_STATISTICS_update (stats, gettext_noop ("# GET requests received"), 1, GNUNET_NO); GNUNET_SERVER_client_keep (client); if ((size == sizeof (struct GetMessage)) && (GNUNET_YES != GNUNET_CONTAINER_bloomfilter_test (filter, &msg->key))) { /* don't bother database... */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Empty result set for `%s' request for `%s' (bloomfilter).\n", "GET", GNUNET_h2s (&msg->key)); GNUNET_STATISTICS_update (stats, gettext_noop ("# requests filtered by bloomfilter"), 1, GNUNET_NO); transmit_item (client, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } plugin->api->get_key (plugin->api->cls, GNUNET_ntohll (msg->offset), ((size == sizeof (struct GetMessage)) ? &msg->key : NULL), NULL, ntohl (msg->type), &transmit_item, client); } /** * Handle UPDATE-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_update (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct UpdateMessage *msg; int ret; char *emsg; GNUNET_STATISTICS_update (stats, gettext_noop ("# UPDATE requests received"), 1, GNUNET_NO); msg = (const struct UpdateMessage *) message; emsg = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' request for %llu\n", "UPDATE", (unsigned long long) GNUNET_ntohll (msg->uid)); ret = plugin->api->update (plugin->api->cls, GNUNET_ntohll (msg->uid), (int32_t) ntohl (msg->priority), GNUNET_TIME_absolute_ntoh (msg->expiration), &emsg); transmit_status (client, ret, emsg); GNUNET_free_non_null (emsg); } /** * Handle GET_REPLICATION-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_get_replication (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' request\n", "GET_REPLICATION"); GNUNET_STATISTICS_update (stats, gettext_noop ("# GET REPLICATION requests received"), 1, GNUNET_NO); GNUNET_SERVER_client_keep (client); plugin->api->get_replication (plugin->api->cls, &transmit_item, client); } /** * Handle GET_ZERO_ANONYMITY-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_get_zero_anonymity (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct GetZeroAnonymityMessage *msg = (const struct GetZeroAnonymityMessage *) message; enum GNUNET_BLOCK_Type type; type = (enum GNUNET_BLOCK_Type) ntohl (msg->type); if (type == GNUNET_BLOCK_TYPE_ANY) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' request\n", "GET_ZERO_ANONYMITY"); GNUNET_STATISTICS_update (stats, gettext_noop ("# GET ZERO ANONYMITY requests received"), 1, GNUNET_NO); GNUNET_SERVER_client_keep (client); plugin->api->get_zero_anonymity (plugin->api->cls, GNUNET_ntohll (msg->offset), type, &transmit_item, client); } /** * Callback function that will cause the item that is passed * in to be deleted (by returning GNUNET_NO). */ static int remove_callback (void *cls, const GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct GNUNET_SERVER_Client *client = cls; if (key == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No further matches for `%s' request.\n", "REMOVE"); transmit_status (client, GNUNET_NO, _("Content not found")); GNUNET_SERVER_client_drop (client); return GNUNET_OK; /* last item */ } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Item %llu matches `%s' request for key `%s' and type %u.\n", (unsigned long long) uid, "REMOVE", GNUNET_h2s (key), type); GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes removed (explicit request)"), size, GNUNET_YES); GNUNET_CONTAINER_bloomfilter_remove (filter, key); transmit_status (client, GNUNET_OK, NULL); GNUNET_SERVER_client_drop (client); return GNUNET_NO; } /** * Handle REMOVE-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_remove (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct DataMessage *dm = check_data (message); GNUNET_HashCode vhash; if (dm == NULL) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' request for `%s' of type %u\n", "REMOVE", GNUNET_h2s (&dm->key), ntohl (dm->type)); GNUNET_STATISTICS_update (stats, gettext_noop ("# REMOVE requests received"), 1, GNUNET_NO); GNUNET_SERVER_client_keep (client); GNUNET_CRYPTO_hash (&dm[1], ntohl (dm->size), &vhash); plugin->api->get_key (plugin->api->cls, 0, &dm->key, &vhash, (enum GNUNET_BLOCK_Type) ntohl (dm->type), &remove_callback, client); } /** * Handle DROP-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_drop (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' request\n", "DROP"); do_drop = GNUNET_YES; GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Function called by plugins to notify us about a * change in their disk utilization. * * @param cls closure (NULL) * @param delta change in disk utilization, * 0 for "reset to empty" */ static void disk_utilization_change_cb (void *cls, int delta) { if ((delta < 0) && (payload < -delta)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Datastore payload inaccurate (%lld < %lld). Trying to fix.\n"), (long long) payload, (long long) -delta); payload = plugin->api->estimate_size (plugin->api->cls); sync_stats (); return; } payload += delta; lastSync++; if (lastSync >= MAX_STAT_SYNC_LAG) sync_stats (); } /** * Callback function to process statistic values. * * @param cls closure (struct Plugin*) * @param subsystem name of subsystem that created the statistic * @param name the name of the datum * @param value the current value * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration */ static int process_stat_in (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent) { GNUNET_assert (stats_worked == GNUNET_NO); stats_worked = GNUNET_YES; payload += value; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Notification from statistics about existing payload (%llu), new payload is %llu\n", value, payload); return GNUNET_OK; } static void process_stat_done (void *cls, int success) { struct DatastorePlugin *plugin = cls; stat_get = NULL; if (stats_worked == GNUNET_NO) payload = plugin->api->estimate_size (plugin->api->cls); } /** * Load the datastore plugin. */ static struct DatastorePlugin * load_plugin () { struct DatastorePlugin *ret; char *libname; ret = GNUNET_malloc (sizeof (struct DatastorePlugin)); ret->env.cfg = cfg; ret->env.duc = &disk_utilization_change_cb; ret->env.cls = NULL; GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' datastore plugin\n"), plugin_name); GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", plugin_name); ret->short_name = GNUNET_strdup (plugin_name); ret->lib_name = libname; ret->api = GNUNET_PLUGIN_load (libname, &ret->env); if (ret->api == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to load datastore plugin for `%s'\n"), plugin_name); GNUNET_free (ret->short_name); GNUNET_free (libname); GNUNET_free (ret); return NULL; } return ret; } /** * Function called when the service shuts * down. Unloads our datastore plugin. * * @param plug plugin to unload */ static void unload_plugin (struct DatastorePlugin *plug) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Datastore service is unloading plugin...\n"); GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api)); GNUNET_free (plug->lib_name); GNUNET_free (plug->short_name); GNUNET_free (plug); GNUNET_free (quota_stat_name); quota_stat_name = NULL; } /** * Final task run after shutdown. Unloads plugins and disconnects us from * statistics. */ static void unload_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (lastSync > 0) sync_stats (); if (GNUNET_YES == do_drop) plugin->api->drop (plugin->api->cls); unload_plugin (plugin); plugin = NULL; if (filter != NULL) { GNUNET_CONTAINER_bloomfilter_free (filter); filter = NULL; } if (stat_get != NULL) { GNUNET_STATISTICS_get_cancel (stat_get); stat_get = NULL; } if (stats != NULL) { GNUNET_STATISTICS_destroy (stats, GNUNET_YES); stats = NULL; } GNUNET_free_non_null (plugin_name); plugin_name = NULL; } /** * Last task run during shutdown. Disconnects us from * the transport and core. */ static void cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct TransmitCallbackContext *tcc; cleaning_done = GNUNET_YES; while (NULL != (tcc = tcc_head)) { GNUNET_CONTAINER_DLL_remove (tcc_head, tcc_tail, tcc); if (tcc->th != NULL) { GNUNET_SERVER_notify_transmit_ready_cancel (tcc->th); GNUNET_SERVER_client_drop (tcc->client); } GNUNET_free (tcc->msg); GNUNET_free (tcc); } if (expired_kill_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (expired_kill_task); expired_kill_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_SCHEDULER_add_continuation (&unload_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } /** * Function that removes all active reservations made * by the given client and releases the space for other * requests. * * @param cls closure * @param client identification of the client */ static void cleanup_reservations (void *cls, struct GNUNET_SERVER_Client *client) { struct ReservationList *pos; struct ReservationList *prev; struct ReservationList *next; if (client == NULL) return; prev = NULL; pos = reservations; while (NULL != pos) { next = pos->next; if (pos->client == client) { if (prev == NULL) reservations = next; else prev->next = next; reserved -= pos->amount + pos->entries * GNUNET_DATASTORE_ENTRY_OVERHEAD; GNUNET_free (pos); } else { prev = pos; } pos = next; } GNUNET_STATISTICS_set (stats, gettext_noop ("# reserved"), reserved, GNUNET_NO); } /** * Adds a given key to the bloomfilter 'count' times. * * @param cls the bloomfilter * @param key key to add * @param count number of times to add key */ static void add_key_to_bloomfilter (void *cls, const GNUNET_HashCode *key, unsigned int count) { struct GNUNET_CONTAINER_BloomFilter *bf = cls; while (0 < count--) GNUNET_CONTAINER_bloomfilter_add (bf, key); } /** * Process datastore requests. * * @param cls closure * @param server the initialized server * @param c configuration to use */ static void run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *c) { static const struct GNUNET_SERVER_MessageHandler handlers[] = { {&handle_reserve, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_RESERVE, sizeof (struct ReserveMessage)}, {&handle_release_reserve, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_RELEASE_RESERVE, sizeof (struct ReleaseReserveMessage)}, {&handle_put, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_PUT, 0}, {&handle_update, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_UPDATE, sizeof (struct UpdateMessage)}, {&handle_get, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_GET, 0}, {&handle_get_replication, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_GET_REPLICATION, sizeof (struct GNUNET_MessageHeader)}, {&handle_get_zero_anonymity, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_GET_ZERO_ANONYMITY, sizeof (struct GetZeroAnonymityMessage)}, {&handle_remove, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_REMOVE, 0}, {&handle_drop, NULL, GNUNET_MESSAGE_TYPE_DATASTORE_DROP, sizeof (struct GNUNET_MessageHeader)}, {NULL, NULL, 0, 0} }; char *fn; char *pfn; unsigned int bf_size; int refresh_bf; cfg = c; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "DATASTORE", "DATABASE", &plugin_name)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("No `%s' specified for `%s' in configuration!\n"), "DATABASE", "DATASTORE"); return; } GNUNET_asprintf ("a_stat_name, _("# bytes used in file-sharing datastore `%s'"), plugin_name); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_size (cfg, "DATASTORE", "QUOTA", "a)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("No `%s' specified for `%s' in configuration!\n"), "QUOTA", "DATASTORE"); return; } stats = GNUNET_STATISTICS_create ("datastore", cfg); GNUNET_STATISTICS_set (stats, gettext_noop ("# quota"), quota, GNUNET_NO); cache_size = quota / 8; /* Or should we make this an option? */ GNUNET_STATISTICS_set (stats, gettext_noop ("# cache size"), cache_size, GNUNET_NO); if (quota / (32 * 1024LL) > (1 << 31)) bf_size = (1 << 31); /* absolute limit: ~2 GB, beyond that BF just won't help anyway */ else bf_size = quota / (32 * 1024LL); /* 8 bit per entry, 1 bit per 32 kb in DB */ fn = NULL; if ((GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "DATASTORE", "BLOOMFILTER", &fn)) || (GNUNET_OK != GNUNET_DISK_directory_create_for_file (fn))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Could not use specified filename `%s' for bloomfilter.\n"), fn != NULL ? fn : ""); GNUNET_free_non_null (fn); fn = NULL; } if (fn != NULL) { GNUNET_asprintf (&pfn, "%s.%s", fn, plugin_name); if (GNUNET_YES == GNUNET_DISK_file_test (pfn)) { filter = GNUNET_CONTAINER_bloomfilter_load (pfn, bf_size, 5); /* approx. 3% false positives at max use */ if (NULL == filter) { /* file exists but not valid, remove and try again, but refresh */ if (0 != UNLINK (pfn)) { /* failed to remove, run without file */ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to remove bogus bloomfilter file `%s'\n"), pfn); GNUNET_free (pfn); pfn = NULL; filter = GNUNET_CONTAINER_bloomfilter_load (NULL, bf_size, 5); /* approx. 3% false positives at max use */ refresh_bf = GNUNET_YES; } else { /* try again after remove */ filter = GNUNET_CONTAINER_bloomfilter_load (pfn, bf_size, 5); /* approx. 3% false positives at max use */ refresh_bf = GNUNET_YES; if (NULL == filter) { /* failed yet again, give up on using file */ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to remove bogus bloomfilter file `%s'\n"), pfn); GNUNET_free (pfn); pfn = NULL; filter = GNUNET_CONTAINER_bloomfilter_load (NULL, bf_size, 5); /* approx. 3% false positives at max use */ } } } else { /* normal case: have an existing valid bf file, no need to refresh */ refresh_bf = GNUNET_NO; } } else { filter = GNUNET_CONTAINER_bloomfilter_load (pfn, bf_size, 5); /* approx. 3% false positives at max use */ refresh_bf = GNUNET_YES; } GNUNET_free (pfn); } else { filter = GNUNET_CONTAINER_bloomfilter_init (NULL, bf_size, 5); /* approx. 3% false positives at max use */ refresh_bf = GNUNET_YES; } GNUNET_free_non_null (fn); if (filter == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to initialize bloomfilter.\n")); if (stats != NULL) { GNUNET_STATISTICS_destroy (stats, GNUNET_YES); stats = NULL; } return; } plugin = load_plugin (); if (NULL == plugin) { GNUNET_CONTAINER_bloomfilter_free (filter); filter = NULL; if (stats != NULL) { GNUNET_STATISTICS_destroy (stats, GNUNET_YES); stats = NULL; } return; } stat_get = GNUNET_STATISTICS_get (stats, "datastore", quota_stat_name, GNUNET_TIME_UNIT_SECONDS, &process_stat_done, &process_stat_in, plugin); GNUNET_SERVER_disconnect_notify (server, &cleanup_reservations, NULL); GNUNET_SERVER_add_handlers (server, handlers); if (GNUNET_YES == refresh_bf) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Rebuilding bloomfilter. Please be patient.\n")); if (NULL != plugin->api->get_keys) plugin->api->get_keys (plugin->api->cls, &add_key_to_bloomfilter, filter); else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Plugin does not support get_keys function. Please fix!\n")); GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Bloomfilter construction complete.\n")); } expired_kill_task = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, &delete_expired, NULL); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleaning_task, NULL); } /** * The main function for the datastore service. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { int ret; ret = (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "datastore", GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; return ret; } /* end of gnunet-service-datastore.c */ gnunet-0.9.3/src/datastore/perf_plugin_datastore_data_postgres.conf0000644000175000017500000000034411634323402022666 00000000000000@INLINE@ test_defaults.conf [PATHS] SERVICEHOME = /tmp/perf-gnunet-datastore-postgres/ DEFAULTCONFIG = perf_plugin_datastore_data_postgres.conf [datastore] DATABASE = postgres [datastore-postgres] CONFIG = dbname=gnunetcheck gnunet-0.9.3/src/lockmanager/0000755000175000017500000000000011763406750013107 500000000000000gnunet-0.9.3/src/lockmanager/gnunet-service-lockmanager.c0000644000175000017500000005543511760502550020416 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file lockmanager/gnunet-service-lockmanager.c * @brief implementation of the LOCKMANAGER service * @author Sree Harsha Totakura */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_container_lib.h" #include "gnunet_protocols.h" #include "gnunet_service_lib.h" #include "gnunet_server_lib.h" #include "lockmanager.h" #define LOG(kind,...) \ GNUNET_log (kind, __VA_ARGS__) #define TIME_REL_MINS(min) \ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, min) #define TIMEOUT TIME_REL_MINS(3) /** * Doubly linked list of clients having connections to us */ struct ClientList; /** * Doubly linked list of clients waiting for a lock */ struct WaitList { /** * The next client structure */ struct WaitList *next; /** * The prev client structure */ struct WaitList *prev; /** * Pointer to the client */ struct ClientList *cl_entry; }; /** * Structure representing a Lock */ struct Lock { /** * List head of clients waiting for this lock */ struct WaitList *wl_head; /** * List tail of clients waiting for this lock */ struct WaitList *wl_tail; /** * The client which is currently holding this lock */ struct ClientList *cl_entry; /** * The name of the locking domain this lock belongs to */ char *domain_name; /** * The number of this lock */ uint32_t lock_num; }; /** * A Lock element for a doubly linked list */ struct LockList { /** * The next element pointer */ struct LockList *next; /** * Pointer to the previous element */ struct LockList *prev; /** * Pointer to the Lock */ struct Lock *lock; }; /** * Doubly linked list of clients having connections to us */ struct ClientList { /** * The next client structure */ struct ClientList *next; /** * The previous client structure */ struct ClientList *prev; /** * Head of the doubly linked list of the currently held locks by this client */ struct LockList *ll_head; /** * Tail of the doubly linked list of the currently held locks by this client */ struct LockList *ll_tail; /** * Pointer to the client */ struct GNUNET_SERVER_Client *client; }; /** * Structure for matching a lock */ struct LockMatch { /** * The matched LockingRequest entry; Should be NULL if no entry is found */ struct Lock *matched_entry; /** * The locking domain name of the lock */ const char *domain_name; /** * The lock number */ uint32_t lock_num; }; /** * Map of lock-keys to the 'struct LockList' entry for the key. */ static struct GNUNET_CONTAINER_MultiHashMap *lock_map; /** * Head of the doubly linked list of clients currently connected */ static struct ClientList *cl_head; /** * Tail of the doubly linked list of clients currently connected */ static struct ClientList *cl_tail; /** * Get the key for the given lock in the 'lock_map'. * * @param domain_name * @param lock_number * @param key set to the key */ static void get_key (const char *domain_name, uint32_t lock_number, struct GNUNET_HashCode *key) { uint32_t *last_32; GNUNET_CRYPTO_hash (domain_name, strlen (domain_name), key); last_32 = (uint32_t *) key; *last_32 ^= lock_number; } /** * Hashmap iterator for matching a lock * * @param cls the LockMatch structure * @param key current key code * @param value value in the hash map (struct Lock) * @return GNUNET_YES if we should continue to * iterate, * GNUNET_NO if not. */ static int match_iterator (void *cls, const GNUNET_HashCode *key, void *value) { struct LockMatch *match = cls; struct Lock *lock = value; if ( (match->lock_num == lock->lock_num) && (0 == strcmp (match->domain_name, lock->domain_name)) ) { match->matched_entry = lock; return GNUNET_NO; } return GNUNET_YES; } /** * Function to search for a lock in the global lock hashmap * * @param domain_name the name of the locking domain * @param lock_num the number of the lock * @return the lock if found; NULL if not */ static struct Lock * find_lock (const char *domain_name, const uint32_t lock_num) { struct LockMatch match; struct GNUNET_HashCode key; match.lock_num = lock_num; match.domain_name = domain_name; match.matched_entry = NULL; get_key (domain_name, lock_num, &key); GNUNET_CONTAINER_multihashmap_get_multiple (lock_map, &key, &match_iterator, &match); return match.matched_entry; } /** * Adds a lock to the global lock hashmap * * @param domain_name the name of the lock's locking domain * @param lock_num the lock number * @return pointer to the lock structure which is added to lock map */ static struct Lock * add_lock (const char *domain_name, uint32_t lock_num) { struct Lock *lock; struct GNUNET_HashCode key; size_t domain_name_len; lock = GNUNET_malloc (sizeof (struct Lock)); domain_name_len = strlen (domain_name) + 1; lock->domain_name = GNUNET_malloc (domain_name_len); strncpy (lock->domain_name, domain_name, domain_name_len); lock->lock_num = lock_num; get_key (domain_name, lock_num, &key); LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding a lock with num: %d and domain: %s to the lock map\n", lock->lock_num, lock->domain_name); GNUNET_CONTAINER_multihashmap_put (lock_map, &key, lock, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); return lock; } /** * Removes a lock from the lock map. The WaitList of the lock should be empty * * @param lock the lock to remove */ static void remove_lock (struct Lock *lock) { struct GNUNET_HashCode key; GNUNET_assert (NULL == lock->wl_head); get_key (lock->domain_name, lock->lock_num, &key); LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing lock with num: %u, domain: %s from lock map\n", lock->lock_num, lock->domain_name); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (lock_map, &key, lock)); GNUNET_free (lock->domain_name); GNUNET_free (lock); } /** * Find the LockList entry corresponding to the given Lock in a ClientList * entry * * @param cl_entry the ClientList entry whose lock list has to be searched * @param lock the lock which has to be matched * @return the matching LockList entry; NULL if no match is found */ static struct LockList * cl_ll_find_lock (struct ClientList *cl_entry, const struct Lock *lock) { struct LockList *ll_entry; for (ll_entry = cl_entry->ll_head; NULL != ll_entry; ll_entry = ll_entry->next) { if (lock == ll_entry->lock) return ll_entry; } return NULL; } /** * Function to append a lock to the lock list of a ClientList entry * * @param cl_entry the client which currently owns this lock * @param lock the lock to be added to the cl_entry's lock list */ static void cl_ll_add_lock (struct ClientList *cl_entry, struct Lock *lock) { struct LockList *ll_entry; ll_entry = GNUNET_malloc (sizeof (struct LockList)); ll_entry->lock = lock; LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding a lock with num: %u and domain: %s to lock list\n", lock->lock_num, lock->domain_name); GNUNET_CONTAINER_DLL_insert_tail (cl_entry->ll_head, cl_entry->ll_tail, ll_entry); } /** * Function to delete a lock from the lock list of the given ClientList entry * * @param cl_entry the ClientList entry * @param ll_entry the LockList entry to be deleted */ static void cl_ll_remove_lock (struct ClientList *cl_entry, struct LockList *ll_entry) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing lock with num: %u, domain: %s from lock list of a client\n", ll_entry->lock->lock_num, ll_entry->lock->domain_name); GNUNET_assert (NULL != cl_entry->ll_head); GNUNET_CONTAINER_DLL_remove (cl_entry->ll_head, cl_entry->ll_tail, ll_entry); GNUNET_free (ll_entry); } /** * Find a WaitList entry in the waiting list of a lock * * @param lock the lock whose wait list has to be searched * @param cl_entry the ClientList entry to be searched * @return the WaitList entry matching the given cl_entry; NULL if not match * was found */ static struct WaitList * lock_wl_find (const struct Lock *lock, const struct ClientList *cl_entry) { struct WaitList *wl_entry; for (wl_entry = lock->wl_head; NULL != wl_entry; wl_entry = wl_entry->next) { if (cl_entry == wl_entry->cl_entry) return wl_entry; } return NULL; } /** * Add a client to the wait list of given lock * * @param lock the lock list entry of a lock * @param cl_entry the client to queue for the lock's wait list */ static void lock_wl_add_client (struct Lock *lock, struct ClientList *cl_entry) { struct WaitList *wl_entry; LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding a client to lock's wait list (lock num: %u, domain: %s)\n", lock->lock_num, lock->domain_name); wl_entry = GNUNET_malloc (sizeof (struct WaitList)); wl_entry->cl_entry = cl_entry; GNUNET_CONTAINER_DLL_insert_tail (lock->wl_head, lock->wl_tail, wl_entry); } /** * Remove an entry from the wait list of the given lock * * @param lock the lock * @param wl_entry the wait list entry to be removed */ static void lock_wl_remove (struct Lock *lock, struct WaitList *wl_entry) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing client from wait list of lock with num: %u, domain: %s\n", lock->lock_num, lock->domain_name); GNUNET_CONTAINER_DLL_remove (lock->wl_head, lock->wl_tail, wl_entry); GNUNET_free (wl_entry); } /** * Search for a client in the client list * * @param client the client to be searched for * @return the ClientList entry; NULL if the client is not found */ static struct ClientList * cl_find_client (const struct GNUNET_SERVER_Client *client) { struct ClientList *current; for (current = cl_head; NULL != current; current = current->next) if (client == current->client) return current; return NULL; } /** * Append a client to the client list * * @param client the client to be appended to the list * @return the client list entry which is added to the client list */ static struct ClientList * cl_add_client (struct GNUNET_SERVER_Client *client) { struct ClientList *new_client; LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding a client to the client list\n"); new_client = GNUNET_malloc (sizeof (struct ClientList)); GNUNET_SERVER_client_keep (client); new_client->client = client; GNUNET_CONTAINER_DLL_insert_tail (cl_head, cl_tail, new_client); return new_client; } /** * Delete the given client from the client list. The LockList should be empty * * @param cl_entry the client list entry to delete */ static void cl_remove_client (struct ClientList *cl_entry) { GNUNET_assert (NULL == cl_entry->ll_head); LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing a client from the client list\n"); GNUNET_SERVER_client_drop (cl_entry->client); GNUNET_CONTAINER_DLL_remove (cl_head, cl_tail, cl_entry); GNUNET_free (cl_entry); } /** * Transmit notify for sending message to client * * @param cls the message to send * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_notify (void *cls, size_t size, void *buf) { struct GNUNET_LOCKMANAGER_Message *msg = cls; uint16_t msg_size; if ((0 == size) || (NULL == buf)) { /* FIXME: Timed out -- requeue? */ return 0; } msg_size = ntohs (msg->header.size); GNUNET_assert (size >= msg_size); memcpy (buf, msg, msg_size); GNUNET_free (msg); LOG (GNUNET_ERROR_TYPE_DEBUG, "Message of size %u sent\n", msg_size); return msg_size; } /** * Send SUCCESS message to the client * * @param client the client to which the message has to be sent * @param domain_name the locking domain of the successfully acquried lock * @param lock_num the number of the successfully acquired lock */ static void send_success_msg (struct GNUNET_SERVER_Client *client, const char *domain_name, int lock_num) { struct GNUNET_LOCKMANAGER_Message *reply; size_t domain_name_len; uint16_t reply_size; domain_name_len = strlen (domain_name) + 1; reply_size = sizeof (struct GNUNET_LOCKMANAGER_Message) + domain_name_len; reply = GNUNET_malloc (reply_size); reply->header.size = htons (reply_size); reply->header.type = htons (GNUNET_MESSAGE_TYPE_LOCKMANAGER_SUCCESS); reply->lock = htonl (lock_num); strncpy ((char *) &reply[1], domain_name, domain_name_len); LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS message for lock with num: %u, domain: %s\n", lock_num, domain_name); GNUNET_SERVER_notify_transmit_ready (client, reply_size, TIMEOUT, &transmit_notify, reply); } /** * Handler for GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE * * @param cls NULL * @param client the client sending this message * @param message GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE message */ static void handle_acquire (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct GNUNET_LOCKMANAGER_Message *request; const char *domain_name; struct Lock *lock; struct ClientList *cl_entry; uint32_t lock_num; uint16_t msize; msize = htons (message->size); if (msize <= sizeof (struct GNUNET_LOCKMANAGER_Message)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } request = (struct GNUNET_LOCKMANAGER_Message *) message; domain_name = (const char *) &request[1]; msize -= sizeof (struct GNUNET_LOCKMANAGER_Message); if ('\0' != domain_name[msize]) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } lock_num = ntohl (request->lock); LOG (GNUNET_ERROR_TYPE_DEBUG, "Received an ACQUIRE message for lock num: %u domain: %s\n", lock_num, domain_name); if (NULL == (cl_entry = cl_find_client (client))) cl_entry = cl_add_client (client); /* Add client if not in client list */ if (NULL != (lock = find_lock (domain_name,lock_num))) { if (lock->cl_entry == cl_entry) { /* Client is requesting a lock it already owns */ GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } lock_wl_add_client (lock, cl_entry); cl_ll_add_lock (cl_entry, lock); } else /* Lock not present */ { lock = add_lock (domain_name, lock_num); lock->cl_entry = cl_entry; cl_ll_add_lock (cl_entry, lock); send_success_msg (cl_entry->client, domain_name, lock_num); } GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * This function gives the lock to the first client in the wait list of the * lock. If no clients are currently waiting for this lock, the lock is then * destroyed. * * @param lock the lock which has to be processed for release */ static void process_lock_release (struct Lock *lock) { struct WaitList *wl_entry; LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing lock release for lock with num: %u, domain: %s\n", lock->lock_num, lock->domain_name); wl_entry = lock->wl_head; if (NULL == wl_entry) { remove_lock (lock); /* No clients waiting for this lock - delete */ return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Giving lock to a client from wait list\n"); lock->cl_entry = wl_entry->cl_entry; lock_wl_remove(lock, wl_entry); send_success_msg (lock->cl_entry->client, lock->domain_name, lock->lock_num); return; } /** * Handle for GNUNET_MESSAGE_TYPE_LOCKMANAGER_RELEASE * * @param cls NULL * @param client the client sending this message * @param message the LOCKMANAGER_RELEASE message */ static void handle_release (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct GNUNET_LOCKMANAGER_Message *request; struct ClientList *cl_entry; struct WaitList *wl_entry; struct LockList *ll_entry; const char *domain_name; struct Lock *lock; uint32_t lock_num; uint16_t msize; msize = ntohs (message->size); if (msize <= sizeof (struct GNUNET_LOCKMANAGER_Message)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } request = (const struct GNUNET_LOCKMANAGER_Message *) message; domain_name = (const char *) &request[1]; msize -= sizeof (struct GNUNET_LOCKMANAGER_Message); if ('\0' != domain_name[msize-1]) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } lock_num = ntohl (request->lock); LOG (GNUNET_ERROR_TYPE_DEBUG, "Received RELEASE message for lock with num: %d, domain: %s\n", lock_num, domain_name); if (NULL == (cl_entry = cl_find_client (client))) { GNUNET_break(0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } lock = find_lock (domain_name, lock_num); if(NULL == lock) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } if (NULL == (ll_entry = cl_ll_find_lock (cl_entry, lock))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } cl_ll_remove_lock (cl_entry, ll_entry); if (cl_entry == lock->cl_entry) { process_lock_release (lock); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } /* remove 'client' from wait list (check that it is not there...) */ if (NULL != (wl_entry = lock_wl_find (lock, cl_entry))) { lock_wl_remove (lock, wl_entry); } GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Callback for client disconnect * * @param cls NULL * @param client the client which has disconnected */ static void client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client) { struct ClientList *cl_entry; struct LockList *ll_entry; struct Lock *lock; if (NULL == client) return; LOG (GNUNET_ERROR_TYPE_DEBUG, "A client has been disconnected -- freeing its locks and resources\n"); cl_entry = cl_find_client (client); if (NULL == cl_entry) return; while (NULL != (ll_entry = cl_entry->ll_head)) { lock = ll_entry->lock; cl_ll_remove_lock (cl_entry, ll_entry); process_lock_release (lock); } cl_remove_client (cl_entry); } /** * Hashmap Iterator to delete lock entries in hash map * * @param cls NULL * @param key current key code * @param value value in the hash map * @return GNUNET_YES if we should continue to * iterate, * GNUNET_NO if not. */ static int lock_delete_iterator (void *cls, const GNUNET_HashCode * key, void *value) { struct Lock *lock = value; GNUNET_assert (NULL != lock); while (NULL != lock->wl_head) { lock_wl_remove (lock, lock->wl_head); } GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(lock_map, key, lock)); GNUNET_free (lock->domain_name); GNUNET_free (lock); return GNUNET_YES; } /** * Task to clean up and shutdown nicely * * @param cls NULL * @param tc the TaskContext from scheduler */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down lock manager\n"); /* Clean the global ClientList */ while (NULL != cl_head) { while (NULL != cl_head->ll_head) /* Clear the LockList */ { cl_ll_remove_lock (cl_head, cl_head->ll_head); } cl_remove_client (cl_head); } /* Clean the global hash table */ GNUNET_CONTAINER_multihashmap_iterate (lock_map, &lock_delete_iterator, NULL); GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (lock_map)); GNUNET_CONTAINER_multihashmap_destroy (lock_map); } /** * Lock manager setup * * @param cls closure * @param server the initialized server * @param cfg configuration to use */ static void lockmanager_run (void *cls, struct GNUNET_SERVER_Handle * server, const struct GNUNET_CONFIGURATION_Handle *cfg) { static const struct GNUNET_SERVER_MessageHandler message_handlers[] = { {&handle_acquire, NULL, GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE, 0}, {&handle_release, NULL, GNUNET_MESSAGE_TYPE_LOCKMANAGER_RELEASE, 0}, {NULL} }; GNUNET_SERVER_add_handlers (server, message_handlers); GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL); lock_map = GNUNET_CONTAINER_multihashmap_create (30); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); } /** * The starting point of execution */ int main (int argc, char *const *argv) { return (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "lockmanager", GNUNET_SERVICE_OPTION_NONE, &lockmanager_run, NULL)) ? 0 : 1; } gnunet-0.9.3/src/lockmanager/Makefile.am0000644000175000017500000000313411760460615015061 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIB = -lgcov endif pkgcfgdir= $(pkgdatadir)/config.d/ pkgcfg_DATA = \ lockmanager.conf bin_PROGRAMS = \ gnunet-service-lockmanager lib_LTLIBRARIES = \ libgnunetlockmanager.la gnunet_service_lockmanager_SOURCES = \ gnunet-service-lockmanager.c \ lockmanager.h gnunet_service_lockmanager_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la gnunet_service_lockmanager_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la libgnunetlockmanager_la_SOURCES = \ lockmanager_api.c lockmanager.h libgnunetlockmanager_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(XLIB) libgnunetlockmanager_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 0:0:0 check_PROGRAMS = \ test-lockmanager-api \ test-lockmanager-api-lockrelease \ test-lockmanager-api-servercrash EXTRA_DIST = \ test_lockmanager_api.conf if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) endif test_lockmanager_api_SOURCES = \ test_lockmanager_api.c test_lockmanager_api_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ libgnunetlockmanager.la test_lockmanager_api_lockrelease_SOURCES = \ test_lockmanager_api_lockrelease.c test_lockmanager_api_lockrelease_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ libgnunetlockmanager.la test_lockmanager_api_servercrash_SOURCES = \ test_lockmanager_api_servercrash.c test_lockmanager_api_servercrash_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ libgnunetlockmanager.lagnunet-0.9.3/src/lockmanager/test_lockmanager_api.c0000644000175000017500000001573411760502550017350 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file lockmanager/test_lockmanager_api.c * @brief Test cases for lockmanager_api.c * @author Sree Harsha Totakura */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_lockmanager_service.h" #define VERBOSE GNUNET_YES #define VERBOSE_ARM 1 #define LOG(kind,...) \ GNUNET_log (kind, __VA_ARGS__) #define TIME_REL_SECONDS(min) \ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, min) /** * Enumeration of testing steps */ enum Test { TEST_FAIL, TEST_INIT, LOCK1_ACQUIRE, LOCK2_ACQUIRE }; /** * The testing result */ static enum Test result; /** * The process id of the GNUNET ARM process */ static struct GNUNET_OS_Process *arm_pid = NULL; /** * Configuration Handle */ static struct GNUNET_CONFIGURATION_Handle *config; /** * The handle to the lockmanager service */ static struct GNUNET_LOCKMANAGER_Handle *handle; /** * The locking request */ static struct GNUNET_LOCKMANAGER_LockingRequest *request; /** * The second locking request */ static struct GNUNET_LOCKMANAGER_LockingRequest *request2; /** * Abort task identifier */ static GNUNET_SCHEDULER_TaskIdentifier abort_task_id; /** * Shutdown nicely * * @param cls * @param tc the task context */ static void do_shutdown (void *cls, const const struct GNUNET_SCHEDULER_TaskContext *tc) { if (GNUNET_SCHEDULER_NO_TASK != abort_task_id) { GNUNET_SCHEDULER_cancel (abort_task_id); abort_task_id = GNUNET_SCHEDULER_NO_TASK; } if (NULL != request) GNUNET_LOCKMANAGER_cancel_request (request); if (NULL != request2) GNUNET_LOCKMANAGER_cancel_request (request2); GNUNET_LOCKMANAGER_disconnect (handle); if (0 != GNUNET_OS_process_kill (arm_pid, SIGTERM)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Kill gnunet-service-arm manually\n"); } GNUNET_OS_process_wait (arm_pid); GNUNET_OS_process_destroy (arm_pid); if (NULL != config) GNUNET_CONFIGURATION_destroy (config); } /** * Shutdown nicely * * @param cls * @param tc the task context */ static void do_abort (void *cls, const const struct GNUNET_SCHEDULER_TaskContext *tc) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Aborting test...\n"); abort_task_id = GNUNET_SCHEDULER_NO_TASK; result = TEST_FAIL; do_shutdown (cls, tc); } /** * Callback for lock status changes * * @param cls the closure from GNUNET_LOCKMANAGER_lock call * * @param domain_name the locking domain of the lock * * @param lock the lock for which this status is relevant * * @param status GNUNET_LOCKMANAGER_SUCCESS if the lock has been successfully * acquired; GNUNET_LOCKMANAGER_RELEASE when the acquired lock is lost */ static void status_cb (void *cls, const char *domain_name, uint32_t lock, enum GNUNET_LOCKMANAGER_Status status) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Status change callback called on lock: %d of domain: %s\n", lock, domain_name); switch (result) { case LOCK1_ACQUIRE: GNUNET_assert (GNUNET_LOCKMANAGER_SUCCESS == status); GNUNET_assert (NULL != request); //GNUNET_LOCKMANAGER_cancel_request (request); //request = NULL; result = LOCK2_ACQUIRE; request2 = GNUNET_LOCKMANAGER_acquire_lock (handle, "GNUNET_LOCKMANAGER_TESTING", 100, &status_cb, NULL); GNUNET_assert (NULL != request2); break; case LOCK2_ACQUIRE: GNUNET_assert (GNUNET_LOCKMANAGER_SUCCESS == status); GNUNET_assert (NULL != request); GNUNET_SCHEDULER_add_delayed (TIME_REL_SECONDS (1), &do_shutdown, NULL); break; default: GNUNET_break (0); } } /** * Testing function * * @param cls NULL * @param tc the task context */ static void test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { handle = GNUNET_LOCKMANAGER_connect (config); GNUNET_assert (NULL != handle); result = LOCK1_ACQUIRE; request = GNUNET_LOCKMANAGER_acquire_lock (handle, "GNUNET_LOCKMANAGER_TESTING", 99, &status_cb, NULL); abort_task_id = GNUNET_SCHEDULER_add_delayed (TIME_REL_SECONDS (10), &do_abort, NULL); } /** * Main point of test execution */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting test...\n"); config = GNUNET_CONFIGURATION_dup (cfg); arm_pid = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE_ARM "-L", "DEBUG", #endif "-c", "test_lockmanager_api.conf", NULL); GNUNET_assert (NULL != arm_pid); GNUNET_SCHEDULER_add_delayed (TIME_REL_SECONDS (3), &test, NULL); } /** * Main function */ int main (int argc, char **argv) { int ret; char *const argv2[] = { "test-lockmanager-api", "-c", "test_lockmanager_api.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("test-lockmanager-api", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, "test-lockmanager-api", "nohelp", options, &run, NULL); if (GNUNET_OK != ret) { LOG (GNUNET_ERROR_TYPE_WARNING, "run failed with error code %d\n", ret); return 1; } if (TEST_FAIL == result) { LOG (GNUNET_ERROR_TYPE_WARNING, "test failed\n"); return 1; } LOG (GNUNET_ERROR_TYPE_INFO, "test OK\n"); return 0; } gnunet-0.9.3/src/lockmanager/test_lockmanager_api_lockrelease.c0000644000175000017500000001717311760502550021720 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file lockmanager/test_lockmanager_api_lockrelease.c * @brief Test cases for lockmanager_api where client disconnects abruptly * @author Sree Harsha Totakura */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_lockmanager_service.h" #define VERBOSE GNUNET_YES #define VERBOSE_ARM 1 #define LOG(kind,...) \ GNUNET_log (kind, __VA_ARGS__) #define TIME_REL_SECONDS(min) \ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, min) /** * Various steps of the test */ enum Test { /** * Signal test failure */ TEST_FAIL, /** * Testing just began */ TEST_INIT, /** * Client 1 has got the lock successfully; Client 2 should try to acquire * the lock now; after some time client 1 has to release the lock */ TEST_CLIENT1_LOCK_SUCCESS, /** * Client 2 has got the lock; Should release it and call shutdown */ TEST_CLIENT2_LOCK_SUCCESS, }; /** * The testing result */ static enum Test result; /** * The process id of the GNUNET ARM process */ static struct GNUNET_OS_Process *arm_pid = NULL; /** * Configuration Handle */ static struct GNUNET_CONFIGURATION_Handle *config; /** * The handle to the lockmanager service */ static struct GNUNET_LOCKMANAGER_Handle *handle; /** * A second client handle to the lockmanager service */ static struct GNUNET_LOCKMANAGER_Handle *handle2; /** * The locking request */ static struct GNUNET_LOCKMANAGER_LockingRequest *request; /** * The locking request of second client */ static struct GNUNET_LOCKMANAGER_LockingRequest *request2; /** * Abort task identifier */ static GNUNET_SCHEDULER_TaskIdentifier abort_task_id; /** * Shutdown nicely * * @param cls * @param tc the task context */ static void do_shutdown (void *cls, const const struct GNUNET_SCHEDULER_TaskContext *tc) { if (GNUNET_SCHEDULER_NO_TASK != abort_task_id) { GNUNET_SCHEDULER_cancel (abort_task_id); abort_task_id = GNUNET_SCHEDULER_NO_TASK; } GNUNET_LOCKMANAGER_disconnect (handle); GNUNET_LOCKMANAGER_disconnect (handle2); if (0 != GNUNET_OS_process_kill (arm_pid, SIGTERM)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Kill gnunet-service-arm manually\n"); } GNUNET_OS_process_wait (arm_pid); GNUNET_OS_process_destroy (arm_pid); if (NULL != config) GNUNET_CONFIGURATION_destroy (config); } /** * Abort * * @param cls * @param tc the task context */ static void do_abort (void *cls, const const struct GNUNET_SCHEDULER_TaskContext *tc) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Aborting test...\n"); abort_task_id = GNUNET_SCHEDULER_NO_TASK; result = TEST_FAIL; do_shutdown (cls, tc); } /** * Callback for lock status changes * * @param cls the handle * * @param domain_name the locking domain of the lock * * @param lock the lock for which this status is relevant * * @param status GNUNET_LOCKMANAGER_SUCCESS if the lock has been successfully * acquired; GNUNET_LOCKMANAGER_RELEASE when the acquired lock is lost */ static void status_cb (void *cls, const char *domain_name, uint32_t lock, enum GNUNET_LOCKMANAGER_Status status) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Status change callback called on lock: %d of domain: %s\n", lock, domain_name); GNUNET_assert (GNUNET_LOCKMANAGER_SUCCESS == status); switch (result) { case TEST_INIT: GNUNET_assert (handle == cls); result = TEST_CLIENT1_LOCK_SUCCESS; request2 = GNUNET_LOCKMANAGER_acquire_lock (handle2, "GNUNET_LOCKMANAGER_TESTING", 99, &status_cb, handle2); GNUNET_assert (NULL != request2); GNUNET_LOCKMANAGER_cancel_request (request); request = NULL; break; case TEST_CLIENT1_LOCK_SUCCESS: GNUNET_assert (handle2 == cls); result = TEST_CLIENT2_LOCK_SUCCESS; GNUNET_LOCKMANAGER_cancel_request (request2); GNUNET_SCHEDULER_add_delayed (TIME_REL_SECONDS (1), &do_shutdown, NULL); break; default: GNUNET_assert (0); /* We should never reach here */ } } /** * Testing function * * @param cls NULL * @param tc the task context */ static void test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { result = TEST_INIT; handle = GNUNET_LOCKMANAGER_connect (config); GNUNET_assert (NULL != handle); handle2 = GNUNET_LOCKMANAGER_connect (config); request = GNUNET_LOCKMANAGER_acquire_lock (handle, "GNUNET_LOCKMANAGER_TESTING", 99, &status_cb, handle); GNUNET_assert (NULL != request); abort_task_id = GNUNET_SCHEDULER_add_delayed (TIME_REL_SECONDS (10), &do_abort, NULL); } /** * Main point of test execution */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting test...\n"); config = GNUNET_CONFIGURATION_dup (cfg); arm_pid = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE_ARM "-L", "DEBUG", #endif "-c", "test_lockmanager_api.conf", NULL); GNUNET_assert (NULL != arm_pid); GNUNET_SCHEDULER_add_delayed (TIME_REL_SECONDS (3), &test, NULL); } /** * Main function */ int main (int argc, char **argv) { int ret; char *const argv2[] = { "test-lockmanager-api-lockrelease", "-c", "test_lockmanager_api.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("test-lockmanager-api-lockrelease", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, "test-lockmanager-api-lockrelease", "nohelp", options, &run, NULL); if (GNUNET_OK != ret) { LOG (GNUNET_ERROR_TYPE_WARNING, "run failed with error code %d\n", ret); return 1; } if (TEST_CLIENT2_LOCK_SUCCESS != result) { LOG (GNUNET_ERROR_TYPE_WARNING, "test failed\n"); return 1; } LOG (GNUNET_ERROR_TYPE_INFO, "test OK\n"); return 0; } gnunet-0.9.3/src/lockmanager/test_lockmanager_api.conf0000644000175000017500000000202011760460615020040 00000000000000[lockmanager] DEBUG = YES AUTOSTART = NO PORT = 12112 ACCEPT_FROM = 127.0.0.1; HOSTNAME = localhost # PREFIX = valgrind --leak-check=full # PREFIX = xterm -geometry 100x85 -T peer1 -e libtool --mode=execute gdb --args [fs] AUTOSTART = NO [resolver] AUTOSTART = NO [mesh] AUTOSTART = NO [dht] AUTOSTART = NO [block] plugins = dht test [dhtcache] QUOTA = 1 MB DATABASE = sqlite [transport] PLUGINS = tcp DEBUG = NO ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; NEIGHBOUR_LIMIT = 50 PORT = 12365 [ats] WAN_QUOTA_OUT = 3932160 WAN_QUOTA_IN = 3932160 [core] PORT = 12092 [arm] DEFAULTSERVICES = core lockmanager PORT = 12366 DEBUG = NO [transport-tcp] TIMEOUT = 300 s PORT = 12368 [TESTING] NUM_PEERS = 5 WEAKRANDOM = YES DEBUG = YES HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat MAX_CONCURRENT_SSH = 10 USE_PROGRESSBARS = YES PEERGROUP_TIMEOUT = 2400 s [gnunetd] HOSTKEY = $SERVICEHOME/.hostkey [PATHS] DEFAULTCONFIG = test_lockmanager_api.conf SERVICEHOME = /tmp/test-lockmanager/ [dns] AUTOSTART = NO [nse] AUTOSTART = NO gnunet-0.9.3/src/lockmanager/lockmanager.h0000644000175000017500000000332111760502551015453 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file lockmanager/lockmanager.h * @brief client-server protocol messages for LOCKMANAGER service * @author Sree Harsha Totakura */ #ifndef LOCKMANAGER_H #define LOCKMANAGER_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_common.h" /** * Structure of Lockmanager message */ struct GNUNET_LOCKMANAGER_Message { /** * The generic message header */ struct GNUNET_MessageHeader header; /** * The lock */ uint32_t lock; /** * The locking domain name(NULL terminated string of characters) should * follow here. The size of the header should include the size of this string * with its trailing NULL */ }; #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef LOCKMANAGER_H */ #endif /* end of lockmanager.h */ gnunet-0.9.3/src/lockmanager/lockmanager_api.c0000644000175000017500000004561211760502550016307 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file lockmanager/lockmanager_api.c * @brief API implementation of gnunet_lockmanager_service.h * @author Sree Harsha Totakura */ /** * To be fixed: * Should the handle be freed when the connection to service is lost? * Should cancel_request have a call back (else simultaneous calls break) */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_container_lib.h" #include "gnunet_client_lib.h" #include "gnunet_crypto_lib.h" #include "gnunet_lockmanager_service.h" #include "gnunet_protocols.h" #include "lockmanager.h" #define LOG(kind,...) \ GNUNET_log_from (kind, "lockmanager-api",__VA_ARGS__) #define TIME_REL_MINS(min) \ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, min) #define TIMEOUT TIME_REL_MINS(3) /** * The message queue */ struct MessageQueue { /** * The next pointer for doubly linked list */ struct MessageQueue *next; /** * The prev pointer for doubly linked list */ struct MessageQueue *prev; /** * The LOCKMANAGER Message */ struct GNUNET_LOCKMANAGER_Message *msg; }; /** * Handler for the lockmanager service */ struct GNUNET_LOCKMANAGER_Handle { /** * The client connection to the service */ struct GNUNET_CLIENT_Connection *conn; /** * The transmit handle for transmissions using conn */ struct GNUNET_CLIENT_TransmitHandle *transmit_handle; /** * Hashmap handle */ struct GNUNET_CONTAINER_MultiHashMap *hashmap; /** * Double linked list head for message queue */ struct MessageQueue *mq_head; /** * Double linked list tail for message queue */ struct MessageQueue *mq_tail; }; /** * Structure for Locking Request */ struct GNUNET_LOCKMANAGER_LockingRequest { /** * The handle associated with this request */ struct GNUNET_LOCKMANAGER_Handle *handle; /** * The status callback */ GNUNET_LOCKMANAGER_StatusCallback status_cb; /** * Closure for the status callback */ void *status_cb_cls; /** * The locking domain of this request */ char *domain; /** * The lock */ uint32_t lock; /** * The status of the lock */ enum GNUNET_LOCKMANAGER_Status status; }; /** * Structure for matching a lock */ struct LockingRequestMatch { /** * The matched LockingRequest entry; Should be NULL if no entry is found */ struct GNUNET_LOCKMANAGER_LockingRequest *matched_entry; /** * The locking domain name of the lock */ const char *domain; /** * The lock number */ uint32_t lock; }; /** * Transmit notify for sending message to server * * @param cls the lockmanager handle * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_notify (void *cls, size_t size, void *buf) { struct GNUNET_LOCKMANAGER_Handle *handle = cls; struct MessageQueue *queue_entity; uint16_t msg_size; handle->transmit_handle = NULL; if ((0 == size) || (NULL == buf)) { /* FIXME: Timed out -- requeue? */ return 0; } queue_entity = handle->mq_head; GNUNET_assert (NULL != queue_entity); msg_size = ntohs (queue_entity->msg->header.size); GNUNET_assert (size >= msg_size); memcpy (buf, queue_entity->msg, msg_size); LOG (GNUNET_ERROR_TYPE_DEBUG, "Message of size %u sent\n", msg_size); GNUNET_free (queue_entity->msg); GNUNET_CONTAINER_DLL_remove (handle->mq_head, handle->mq_tail, queue_entity); GNUNET_free (queue_entity); queue_entity = handle->mq_head; if (NULL != queue_entity) { handle->transmit_handle = GNUNET_CLIENT_notify_transmit_ready (handle->conn, ntohs (queue_entity->msg->header.size), TIMEOUT, GNUNET_YES, &transmit_notify, handle); } return msg_size; } /** * Queues a message into handle's send message queue * * @param handle the lockmanager handle whose queue will be used * @param msg the message to be queued */ static void queue_message (struct GNUNET_LOCKMANAGER_Handle *handle, struct GNUNET_LOCKMANAGER_Message *msg) { struct MessageQueue *queue_entity; GNUNET_assert (NULL != msg); queue_entity = GNUNET_malloc (sizeof (struct MessageQueue)); queue_entity->msg = msg; GNUNET_CONTAINER_DLL_insert_tail (handle->mq_head, handle->mq_tail, queue_entity); if (NULL == handle->transmit_handle) { handle->transmit_handle = GNUNET_CLIENT_notify_transmit_ready (handle->conn, ntohs (msg->header.size), TIMEOUT, GNUNET_YES, &transmit_notify, handle); } } /** * Get the key for the given lock in the 'lock_map'. * * @param domain_name * @param lock_number * @param key set to the key */ static void get_key (const char *domain_name, uint32_t lock_number, struct GNUNET_HashCode *key) { uint32_t *last_32; GNUNET_CRYPTO_hash (domain_name, strlen (domain_name), key); last_32 = (uint32_t *) key; *last_32 ^= lock_number; } /** * Hashmap iterator for matching a LockingRequest * * @param cls the LockingRequestMatch structure * @param key current key code * @param value value in the hash map (struct GNUNET_LOCKMANAGER_LockingRequest) * @return GNUNET_YES if we should continue to * iterate, * GNUNET_NO if not. */ static int match_iterator (void *cls, const GNUNET_HashCode *key, void *value) { struct LockingRequestMatch *match = cls; struct GNUNET_LOCKMANAGER_LockingRequest *lr = value; if ( (match->lock == lr->lock) && (0 == strcmp (match->domain, lr->domain)) ) { match->matched_entry = lr; return GNUNET_NO; } return GNUNET_YES; } /** * Function to find a LockingRequest associated with the given domain and lock * attributes in the map * * @param map the map where the LockingRequests are stored * @param domain the locking domain name * @param lock the lock number * @return the found LockingRequest; NULL if a matching LockingRequest wasn't * found */ static struct GNUNET_LOCKMANAGER_LockingRequest * hashmap_find_lockingrequest (const struct GNUNET_CONTAINER_MultiHashMap *map, const char *domain, uint32_t lock) { struct GNUNET_HashCode hash; struct LockingRequestMatch lock_match; lock_match.matched_entry = NULL; lock_match.domain = domain; lock_match.lock = lock; get_key (domain, lock, &hash); GNUNET_CONTAINER_multihashmap_get_multiple (map, &hash, &match_iterator, &lock_match); return lock_match.matched_entry; } /** * Task for calling status change callback for a lock * * @param cls the LockingRequest associated with this lock * @param tc the TaskScheduler context */ static void call_status_cb_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { const struct GNUNET_LOCKMANAGER_LockingRequest *r = cls; if (NULL != r->status_cb) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Calling status change for SUCCESS on lock num: %d, domain: %s\n", r->lock, r->domain); r->status_cb (r->status_cb_cls, r->domain, r->lock, r->status); } } /** * Iterator to call relase and free all LockingRequest entries * * @param cls the lockmanager handle * @param key current key code * @param value the Locking request * @return GNUNET_YES if we should continue to * iterate, * GNUNET_NO if not. */ static int release_iterator(void *cls, const GNUNET_HashCode * key, void *value) { struct GNUNET_LOCKMANAGER_Handle *h = cls; struct GNUNET_LOCKMANAGER_LockingRequest *r = value; if (NULL != r->status_cb) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Calling status change for RELEASE on lock num: %d, domain: %s\n", r->lock, r->domain); r->status_cb (r->status_cb_cls, r->domain, r->lock, GNUNET_LOCKMANAGER_RELEASE); } GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (h->hashmap, key, value)); GNUNET_free (r->domain); GNUNET_free (r); return GNUNET_YES; } /** * Handler for server replies * * @param cls the LOCKMANAGER_Handle * @param msg received message, NULL on timeout or fatal error */ static void handle_replies (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_LOCKMANAGER_Handle *handle = cls; const struct GNUNET_LOCKMANAGER_Message *m; struct GNUNET_LOCKMANAGER_LockingRequest *lr; const char *domain; struct GNUNET_HashCode hash; uint32_t lock; uint16_t msize; if (NULL == msg) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Lockmanager service not available or went down\n"); /* Should release all locks and free its locking requests */ GNUNET_CONTAINER_multihashmap_iterate (handle->hashmap, &release_iterator, handle); return; } GNUNET_CLIENT_receive (handle->conn, &handle_replies, handle, GNUNET_TIME_UNIT_FOREVER_REL); if (GNUNET_MESSAGE_TYPE_LOCKMANAGER_SUCCESS != ntohs(msg->type)) { GNUNET_break (0); return; } msize = ntohs (msg->size); if (msize <= sizeof (struct GNUNET_LOCKMANAGER_Message)) { GNUNET_break (0); return; } m = (const struct GNUNET_LOCKMANAGER_Message *) msg; domain = (const char *) &m[1]; msize -= sizeof (struct GNUNET_LOCKMANAGER_Message); if ('\0' != domain[msize-1]) { GNUNET_break (0); return; } lock = ntohl (m->lock); get_key (domain, lock, &hash); LOG (GNUNET_ERROR_TYPE_DEBUG, "Received SUCCESS message for lock: %d, domain %s\n", lock, domain); if (NULL == (lr = hashmap_find_lockingrequest (handle->hashmap, domain, lock))) { GNUNET_break (0); return; } if (GNUNET_LOCKMANAGER_SUCCESS == lr->status) { GNUNET_break (0); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Changing status for lock: %d in domain: %s to SUCCESS\n", lr->lock, lr->domain); lr->status = GNUNET_LOCKMANAGER_SUCCESS; GNUNET_SCHEDULER_add_continuation (&call_status_cb_task, lr, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } /** * Iterator to free hash map entries. * * @param cls the lockmanger handle * @param key current key code * @param value the Locking request * @return GNUNET_YES if we should continue to * iterate, * GNUNET_NO if not. */ static int free_iterator(void *cls, const GNUNET_HashCode * key, void *value) { struct GNUNET_LOCKMANAGER_Handle *h = cls; struct GNUNET_LOCKMANAGER_LockingRequest *r = value; LOG (GNUNET_ERROR_TYPE_DEBUG, "Clearing locking request\n"); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (h->hashmap, key, value)); GNUNET_free (r->domain); GNUNET_free (r); return GNUNET_YES; } /*******************/ /* API Definitions */ /*******************/ /** * Connect to the lockmanager service * * @param cfg the configuration to use * * @return upon success the handle to the service; NULL upon error */ struct GNUNET_LOCKMANAGER_Handle * GNUNET_LOCKMANAGER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_LOCKMANAGER_Handle *h; LOG (GNUNET_ERROR_TYPE_DEBUG, "%s()\n", __func__); h = GNUNET_malloc (sizeof (struct GNUNET_LOCKMANAGER_Handle)); h->conn = GNUNET_CLIENT_connect ("lockmanager", cfg); if (NULL == h->conn) { GNUNET_free (h); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__); return NULL; } h->hashmap = GNUNET_CONTAINER_multihashmap_create (15); GNUNET_assert (NULL != h->hashmap); GNUNET_CLIENT_receive (h->conn, &handle_replies, h, GNUNET_TIME_UNIT_FOREVER_REL); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__); return h; } /** * Disconnect from the lockmanager service * * @param handle the handle to the lockmanager service */ void GNUNET_LOCKMANAGER_disconnect (struct GNUNET_LOCKMANAGER_Handle *handle) { struct MessageQueue *head; LOG (GNUNET_ERROR_TYPE_DEBUG, "%s()\n", __func__); if (0 != GNUNET_CONTAINER_multihashmap_size (handle->hashmap)) { LOG (GNUNET_ERROR_TYPE_WARNING, "Some locking requests are still present. Cancel them before " "calling %s\n", __func__); GNUNET_CONTAINER_multihashmap_iterate (handle->hashmap, &free_iterator, handle); } GNUNET_CONTAINER_multihashmap_destroy (handle->hashmap); /* Clear the message queue */ if (NULL != handle->transmit_handle) { GNUNET_CLIENT_notify_transmit_ready_cancel (handle->transmit_handle); } head = handle->mq_head; while (NULL != head) { GNUNET_CONTAINER_DLL_remove (handle->mq_head, handle->mq_tail, head); GNUNET_free (head->msg); GNUNET_free (head); head = handle->mq_head; } GNUNET_CLIENT_disconnect (handle->conn); GNUNET_free (handle); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__); } /** * Tries to acquire the given lock(even if the lock has been lost) until the * request is called. If the lock is available the status_cb will be * called. If the lock is busy then the request is queued and status_cb * will be called when the lock has been made available and acquired by us. * * @param handle the handle to the lockmanager service * * @param domain_name name of the locking domain. Clients who want to share * locks must use the same name for the locking domain. Also the * domain_name should be selected with the prefix * "GNUNET__" to avoid domain name collisions. * * * @param lock which lock to lock * * @param status_cb the callback for signalling when the lock is acquired and * when it is lost * * @param status_cb_cls the closure to the above callback * * @return the locking request handle for this request */ struct GNUNET_LOCKMANAGER_LockingRequest * GNUNET_LOCKMANAGER_acquire_lock (struct GNUNET_LOCKMANAGER_Handle *handle, const char *domain_name, uint32_t lock, GNUNET_LOCKMANAGER_StatusCallback status_cb, void *status_cb_cls) { struct GNUNET_LOCKMANAGER_LockingRequest *r; struct GNUNET_LOCKMANAGER_Message *msg; struct GNUNET_HashCode hash; uint16_t msg_size; size_t domain_name_length; LOG (GNUNET_ERROR_TYPE_DEBUG, "%s()\n", __func__); r = GNUNET_malloc (sizeof (struct GNUNET_LOCKMANAGER_LockingRequest)); domain_name_length = strlen (domain_name) + 1; r->handle = handle; r->lock = lock; r->domain = GNUNET_malloc (domain_name_length); r->status = GNUNET_LOCKMANAGER_RELEASE; r->status_cb = status_cb; r->status_cb_cls = status_cb_cls; memcpy (r->domain, domain_name, domain_name_length); msg_size = sizeof (struct GNUNET_LOCKMANAGER_Message) + domain_name_length; msg = GNUNET_malloc (msg_size); msg->header.type = htons (GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE); msg->header.size = htons (msg_size); msg->lock = htonl (lock); memcpy (&msg[1], r->domain, domain_name_length); LOG (GNUNET_ERROR_TYPE_DEBUG, "Queueing ACQUIRE message\n"); queue_message (handle, msg); get_key (r->domain, r->lock, &hash); GNUNET_CONTAINER_multihashmap_put (r->handle->hashmap, &hash, r, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__); return r; } /** * Function to cancel the locking request generated by * GNUNET_LOCKMANAGER_acquire_lock. If the lock is acquired us then the lock is * released. GNUNET_LOCKMANAGER_StatusCallback will not be called upon any * status changes resulting due to this call. * * @param request the LockingRequest to cancel */ void GNUNET_LOCKMANAGER_cancel_request (struct GNUNET_LOCKMANAGER_LockingRequest *request) { struct GNUNET_LOCKMANAGER_Message *msg; struct GNUNET_HashCode hash; uint16_t msg_size; size_t domain_name_length; LOG (GNUNET_ERROR_TYPE_DEBUG, "%s()\n", __func__); /* FIXME: Stop ACQUIRE retransmissions */ if (GNUNET_LOCKMANAGER_SUCCESS == request->status) { domain_name_length = strlen (request->domain) + 1; msg_size = sizeof (struct GNUNET_LOCKMANAGER_Message) + domain_name_length; msg = GNUNET_malloc (msg_size); msg->header.type = htons (GNUNET_MESSAGE_TYPE_LOCKMANAGER_RELEASE); msg->header.size = htons (msg_size); msg->lock = htonl (request->lock); memcpy (&msg[1], request->domain, domain_name_length); queue_message (request->handle, msg); } get_key (request->domain, request->lock, &hash); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (request->handle->hashmap, &hash, request)); GNUNET_free (request->domain); GNUNET_free (request); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__); } gnunet-0.9.3/src/lockmanager/Makefile.in0000644000175000017500000007534711762217212015104 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-service-lockmanager$(EXEEXT) check_PROGRAMS = test-lockmanager-api$(EXEEXT) \ test-lockmanager-api-lockrelease$(EXEEXT) \ test-lockmanager-api-servercrash$(EXEEXT) subdir = src/lockmanager DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/lockmanager.conf.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = lockmanager.conf CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libgnunetlockmanager_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_libgnunetlockmanager_la_OBJECTS = lockmanager_api.lo libgnunetlockmanager_la_OBJECTS = \ $(am_libgnunetlockmanager_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunetlockmanager_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetlockmanager_la_LDFLAGS) \ $(LDFLAGS) -o $@ PROGRAMS = $(bin_PROGRAMS) am_gnunet_service_lockmanager_OBJECTS = \ gnunet-service-lockmanager.$(OBJEXT) gnunet_service_lockmanager_OBJECTS = \ $(am_gnunet_service_lockmanager_OBJECTS) am_test_lockmanager_api_OBJECTS = test_lockmanager_api.$(OBJEXT) test_lockmanager_api_OBJECTS = $(am_test_lockmanager_api_OBJECTS) test_lockmanager_api_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ libgnunetlockmanager.la am_test_lockmanager_api_lockrelease_OBJECTS = \ test_lockmanager_api_lockrelease.$(OBJEXT) test_lockmanager_api_lockrelease_OBJECTS = \ $(am_test_lockmanager_api_lockrelease_OBJECTS) test_lockmanager_api_lockrelease_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ libgnunetlockmanager.la am_test_lockmanager_api_servercrash_OBJECTS = \ test_lockmanager_api_servercrash.$(OBJEXT) test_lockmanager_api_servercrash_OBJECTS = \ $(am_test_lockmanager_api_servercrash_OBJECTS) test_lockmanager_api_servercrash_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ libgnunetlockmanager.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunetlockmanager_la_SOURCES) \ $(gnunet_service_lockmanager_SOURCES) \ $(test_lockmanager_api_SOURCES) \ $(test_lockmanager_api_lockrelease_SOURCES) \ $(test_lockmanager_api_servercrash_SOURCES) DIST_SOURCES = $(libgnunetlockmanager_la_SOURCES) \ $(gnunet_service_lockmanager_SOURCES) \ $(test_lockmanager_api_SOURCES) \ $(test_lockmanager_api_lockrelease_SOURCES) \ $(test_lockmanager_api_servercrash_SOURCES) DATA = $(pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @USE_COVERAGE_TRUE@XLIB = -lgcov pkgcfgdir = $(pkgdatadir)/config.d/ pkgcfg_DATA = \ lockmanager.conf lib_LTLIBRARIES = \ libgnunetlockmanager.la gnunet_service_lockmanager_SOURCES = \ gnunet-service-lockmanager.c \ lockmanager.h gnunet_service_lockmanager_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la gnunet_service_lockmanager_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la libgnunetlockmanager_la_SOURCES = \ lockmanager_api.c lockmanager.h libgnunetlockmanager_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(XLIB) libgnunetlockmanager_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 0:0:0 EXTRA_DIST = \ test_lockmanager_api.conf @ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) test_lockmanager_api_SOURCES = \ test_lockmanager_api.c test_lockmanager_api_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ libgnunetlockmanager.la test_lockmanager_api_lockrelease_SOURCES = \ test_lockmanager_api_lockrelease.c test_lockmanager_api_lockrelease_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ libgnunetlockmanager.la test_lockmanager_api_servercrash_SOURCES = \ test_lockmanager_api_servercrash.c test_lockmanager_api_servercrash_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ libgnunetlockmanager.la all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/lockmanager/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/lockmanager/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): lockmanager.conf: $(top_builddir)/config.status $(srcdir)/lockmanager.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunetlockmanager.la: $(libgnunetlockmanager_la_OBJECTS) $(libgnunetlockmanager_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetlockmanager_la_LINK) -rpath $(libdir) $(libgnunetlockmanager_la_OBJECTS) $(libgnunetlockmanager_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-service-lockmanager$(EXEEXT): $(gnunet_service_lockmanager_OBJECTS) $(gnunet_service_lockmanager_DEPENDENCIES) @rm -f gnunet-service-lockmanager$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_service_lockmanager_OBJECTS) $(gnunet_service_lockmanager_LDADD) $(LIBS) test-lockmanager-api$(EXEEXT): $(test_lockmanager_api_OBJECTS) $(test_lockmanager_api_DEPENDENCIES) @rm -f test-lockmanager-api$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_lockmanager_api_OBJECTS) $(test_lockmanager_api_LDADD) $(LIBS) test-lockmanager-api-lockrelease$(EXEEXT): $(test_lockmanager_api_lockrelease_OBJECTS) $(test_lockmanager_api_lockrelease_DEPENDENCIES) @rm -f test-lockmanager-api-lockrelease$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_lockmanager_api_lockrelease_OBJECTS) $(test_lockmanager_api_lockrelease_LDADD) $(LIBS) test-lockmanager-api-servercrash$(EXEEXT): $(test_lockmanager_api_servercrash_OBJECTS) $(test_lockmanager_api_servercrash_DEPENDENCIES) @rm -f test-lockmanager-api-servercrash$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_lockmanager_api_servercrash_OBJECTS) $(test_lockmanager_api_servercrash_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-lockmanager.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lockmanager_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lockmanager_api.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lockmanager_api_lockrelease.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lockmanager_api_servercrash.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgcfgDATA: $(pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgcfgDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-binPROGRAMS install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-pkgcfgDATA install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/lockmanager/test_lockmanager_api_servercrash.c0000644000175000017500000002067411760502550021756 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file lockmanager/test_lockmanager_api_servercrash.c * @brief Test cases for lockmanager_api where the server crashes * @author Sree Harsha Totakura */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_lockmanager_service.h" #define VERBOSE GNUNET_YES #define VERBOSE_ARM 1 #define LOG(kind,...) \ GNUNET_log (kind, __VA_ARGS__) #define TIME_REL_SECONDS(min) \ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, min) /** * Various steps of the test */ enum Test { /** * Signal test failure */ TEST_FAIL, /** * Testing just began */ TEST_INIT, /** * Client 1 has got the lock successfully; Client 2 should try to acquire * the lock now; after some time client 1 has to release the lock */ TEST_CLIENT1_LOCK_SUCCESS, /** * Client 2 has got the lock; Server should crash now; */ TEST_CLIENT2_LOCK_SUCCESS, /** * Client 2 should get lock release due to server crash; Should call * shutdown now */ TEST_CLIENT2_SERVER_CRASH_SUCCESS }; /** * The testing result */ static enum Test result; /** * The process id of the GNUNET ARM process */ static struct GNUNET_OS_Process *arm_pid = NULL; /** * Configuration Handle */ static struct GNUNET_CONFIGURATION_Handle *config; /** * The handle to the lockmanager service */ static struct GNUNET_LOCKMANAGER_Handle *handle; /** * A second client handle to the lockmanager service */ static struct GNUNET_LOCKMANAGER_Handle *handle2; /** * The locking request */ static struct GNUNET_LOCKMANAGER_LockingRequest *request; /** * The locking request of second client */ static struct GNUNET_LOCKMANAGER_LockingRequest *request2; /** * Abort task identifier */ static GNUNET_SCHEDULER_TaskIdentifier abort_task_id; /** * Shutdown nicely * * @param cls * @param tc the task context */ static void do_shutdown (void *cls, const const struct GNUNET_SCHEDULER_TaskContext *tc) { if (GNUNET_SCHEDULER_NO_TASK != abort_task_id) { GNUNET_SCHEDULER_cancel (abort_task_id); abort_task_id = GNUNET_SCHEDULER_NO_TASK; } if (NULL != handle) GNUNET_LOCKMANAGER_disconnect (handle); if (NULL != handle2) GNUNET_LOCKMANAGER_disconnect (handle2); if (NULL != arm_pid) { if (0 != GNUNET_OS_process_kill (arm_pid, SIGTERM)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Kill gnunet-service-arm manually\n"); } GNUNET_OS_process_wait (arm_pid); GNUNET_OS_process_destroy (arm_pid); } if (NULL != config) GNUNET_CONFIGURATION_destroy (config); } /** * Abort * * @param cls * @param tc the task context */ static void do_abort (void *cls, const const struct GNUNET_SCHEDULER_TaskContext *tc) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Aborting test...\n"); abort_task_id = GNUNET_SCHEDULER_NO_TASK; result = TEST_FAIL; do_shutdown (cls, tc); } /** * Callback for lock status changes * * @param cls the handle * * @param domain_name the locking domain of the lock * * @param lock the lock for which this status is relevant * * @param status GNUNET_LOCKMANAGER_SUCCESS if the lock has been successfully * acquired; GNUNET_LOCKMANAGER_RELEASE when the acquired lock is lost */ static void status_cb (void *cls, const char *domain_name, uint32_t lock, enum GNUNET_LOCKMANAGER_Status status) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Status change callback called on lock: %d of domain: %s\n", lock, domain_name); switch (result) { case TEST_INIT: GNUNET_assert (handle == cls); GNUNET_assert (GNUNET_LOCKMANAGER_SUCCESS == status); result = TEST_CLIENT1_LOCK_SUCCESS; request2 = GNUNET_LOCKMANAGER_acquire_lock (handle2, "GNUNET_LOCKMANAGER_TESTING", 99, &status_cb, handle2); GNUNET_assert (NULL != request2); GNUNET_LOCKMANAGER_cancel_request (request); request = NULL; break; case TEST_CLIENT1_LOCK_SUCCESS: GNUNET_assert (handle2 == cls); GNUNET_assert (GNUNET_LOCKMANAGER_SUCCESS == status); result = TEST_CLIENT2_LOCK_SUCCESS; /* We should kill the lockmanager process */ if (0 != GNUNET_OS_process_kill (arm_pid, SIGTERM)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Kill gnunet-service-arm manually\n"); } GNUNET_OS_process_wait (arm_pid); GNUNET_OS_process_destroy (arm_pid); arm_pid =NULL; break; case TEST_CLIENT2_LOCK_SUCCESS: GNUNET_assert (handle2 == cls); GNUNET_assert (GNUNET_LOCKMANAGER_RELEASE == status); GNUNET_assert (99 == lock); GNUNET_assert (0 == strcmp (domain_name, "GNUNET_LOCKMANAGER_TESTING")); result = TEST_CLIENT2_SERVER_CRASH_SUCCESS; GNUNET_SCHEDULER_add_delayed (TIME_REL_SECONDS (1), &do_shutdown, NULL); break; default: GNUNET_assert (0); /* We should never reach here */ } } /** * Testing function * * @param cls NULL * @param tc the task context */ static void test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { result = TEST_INIT; handle = GNUNET_LOCKMANAGER_connect (config); GNUNET_assert (NULL != handle); handle2 = GNUNET_LOCKMANAGER_connect (config); request = GNUNET_LOCKMANAGER_acquire_lock (handle, "GNUNET_LOCKMANAGER_TESTING", 99, &status_cb, handle); GNUNET_assert (NULL != request); abort_task_id = GNUNET_SCHEDULER_add_delayed (TIME_REL_SECONDS (10), &do_abort, NULL); } /** * Main point of test execution */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting test...\n"); config = GNUNET_CONFIGURATION_dup (cfg); arm_pid = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE_ARM "-L", "DEBUG", #endif "-c", "test_lockmanager_api.conf", NULL); GNUNET_assert (NULL != arm_pid); GNUNET_SCHEDULER_add_delayed (TIME_REL_SECONDS (3), &test, NULL); } /** * Main function */ int main (int argc, char **argv) { int ret; char *const argv2[] = { "test-lockmanager-api-servercrash", "-c", "test_lockmanager_api.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("test-lockmanager-api-servercrash", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, "test-lockmanager-api-servercrash", "nohelp", options, &run, NULL); if (GNUNET_OK != ret) { LOG (GNUNET_ERROR_TYPE_WARNING, "run failed with error code %d\n", ret); return 1; } if (TEST_CLIENT2_SERVER_CRASH_SUCCESS != result) { LOG (GNUNET_ERROR_TYPE_WARNING, "test failed\n"); return 1; } LOG (GNUNET_ERROR_TYPE_INFO, "test OK\n"); return 0; } gnunet-0.9.3/src/lockmanager/lockmanager.conf.in0000644000175000017500000000044211762202311016550 00000000000000[lockmanager] AUTOSTART = YES @UNIXONLY@ PORT = 2100 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-lockmanager ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-lockmanager.sock UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES gnunet-0.9.3/src/integration-tests/0000755000175000017500000000000011763406751014310 500000000000000gnunet-0.9.3/src/integration-tests/test_integration_bootstrap_and_connect.py.in0000755000175000017500000000742111760502552025221 00000000000000#!@PYTHON@ # This file is part of GNUnet. # (C) 2010 Christian Grothoff (and other contributing authors) # # GNUnet is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2, or (at your # option) any later version. # # GNUnet is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNUnet; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # import sys import os import subprocess import re import shutil import time import pexpect from gnunet_testing import Peer from gnunet_testing import Test from gnunet_testing import Check from gnunet_testing import Condition from gnunet_testing import * # # This test tests if a fresh peer bootstraps from a hostlist server and then # successfully connects to the server # # Conditions for successful exit: # Both peers have 1 connected peer in transport, core, topology, fs # # This test tests if a fresh peer bootstraps from a hostlist server and then # successfully connects to the server # # Conditions for successful exit: # Both peers have 1 connected peer in transport, core, topology, fs #definitions testname = "test_integration_bootstrap_and_connect" verbose = True check_timeout = 180 def cleanup (): if os.name == "nt": shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-ns"), True) shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_no_nat_client"), True) else: shutil.rmtree ("/tmp/c_bootstrap_server/", True) shutil.rmtree ("/tmp/c_no_nat_client/", True) def success_cont (check): global success success = True; def fail_cont (check): global success success = False; check.evaluate(True) def check (): check = Check (test) check.add (StatisticsCondition (client, 'transport', '# peers connected',1)) check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',1)) check.add (StatisticsCondition (client, 'core', '# peers connected',1)) check.add (StatisticsCondition (client, 'topology', '# peers connected',1)) check.add (StatisticsCondition (client, 'fs', '# peers connected',1)) check.add (StatisticsCondition (server, 'transport', '# peers connected',1)) check.add (StatisticsCondition (server, 'core', '# neighbour entries allocated',1)) check.add (StatisticsCondition (server, 'core', '# peers connected',1)) check.add (StatisticsCondition (server, 'topology', '# peers connected',1)) check.add (StatisticsCondition (server, 'fs', '# peers connected',1)) check.run_blocking (check_timeout, success_cont, fail_cont) # # Test execution # def run (): global success global test global server global client success = False test = Test ('test_integration_bootstrap_and_connect.py', verbose) server = Peer(test, './confs/c_bootstrap_server.conf'); client = Peer(test, './confs/c_no_nat_client.conf'); assert (True == server.start()); assert (True == client.start()); if ((client.started == True) and (server.started == True)): test.p ('Peers started, running check') time.sleep(5) check () server.stop () client.stop () cleanup () if (success == False): print ('Test failed') return False else: return True try: run () except (KeyboardInterrupt, SystemExit): print 'Test interrupted' server.stop () client.stop () cleanup () if (success == False): sys.exit(1) else: sys.exit(0) gnunet-0.9.3/src/integration-tests/connection_watchdog.c0000644000175000017500000007213111760516240020407 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file integration-tests/connection_watchdog.c * @brief tool to monitor core and transport connections for consistency * @author Matthias Wachs */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_constants.h" #include "gnunet_arm_service.h" #include "gnunet_core_service.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_transport_service.h" #include "gnunet_statistics_service.h" #define CHECK_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) #define STATS_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) #define REPEATED_STATS_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) #define STATS_VALUES 4 /** * Final status code. */ static int ret; static int ping; static int have_tcp; static int have_udp; static int have_http; static int have_https; static int have_unix; static struct GNUNET_TRANSPORT_Handle *th; static struct GNUNET_CORE_Handle *ch; static struct GNUNET_PeerIdentity my_peer_id; static const struct GNUNET_CONFIGURATION_Handle *mycfg; static struct GNUNET_STATISTICS_Handle *stats; static unsigned int transport_connections; static unsigned int core_connections; static GNUNET_SCHEDULER_TaskIdentifier check_task; static GNUNET_SCHEDULER_TaskIdentifier statistics_task; static uint64_t statistics_transport_connections; static uint64_t statistics_transport_tcp_connections; static uint64_t statistics_core_neighbour_entries; static uint64_t statistics_core_entries_session_map; int stat_check_running; static struct GNUNET_CONTAINER_MultiHashMap *peers; struct PeerContainer { struct GNUNET_PeerIdentity id; int transport_connected; int core_connected; struct GNUNET_TRANSPORT_TransmitHandle *th_ping; struct GNUNET_CORE_TransmitHandle *ch_ping; struct GNUNET_TRANSPORT_TransmitHandle *th_pong; struct GNUNET_CORE_TransmitHandle *ch_pong; }; enum protocol { tcp, udp, unixdomain }; struct TransportPlugin { /** * This is a doubly-linked list. */ struct TransportPlugin *next; /** * This is a doubly-linked list. */ struct TransportPlugin *prev; /** * Short name for the plugin (i.e. "tcp"). */ char *short_name; int port; int protocol; }; struct TransportPlugin *phead; struct TransportPlugin *ptail; static int map_check_it (void *cls, const GNUNET_HashCode * key, void *value) { int *fail = cls; struct PeerContainer *pc = value; if (pc->core_connected != pc->transport_connected) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Inconsistent peer `%s': TRANSPORT %s <-> CORE %s\n", GNUNET_i2s (&pc->id), (GNUNET_YES == pc->transport_connected) ? "YES" : "NO", (GNUNET_YES == pc->core_connected) ? "YES" : "NO"); (*fail) ++; } return GNUNET_OK; } static int map_cleanup_it (void *cls, const GNUNET_HashCode * key, void *value) { struct PeerContainer *pc = value; GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove(peers, key, value)); if (NULL != pc->th_ping) { GNUNET_TRANSPORT_notify_transmit_ready_cancel(pc->th_ping); pc->th_ping = NULL; } if (NULL != pc->th_pong) { GNUNET_TRANSPORT_notify_transmit_ready_cancel(pc->th_pong); pc->th_pong = NULL; } if (NULL != pc->ch_ping) { GNUNET_CORE_notify_transmit_ready_cancel (pc->ch_ping); pc->ch_ping = NULL; } if (NULL != pc->ch_pong) { GNUNET_CORE_notify_transmit_ready_cancel(pc->ch_pong); pc->ch_pong = NULL; } GNUNET_free (pc); return GNUNET_OK; } static void map_cleanup (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_CONTAINER_multihashmap_iterate (peers, &map_cleanup_it, NULL); GNUNET_CONTAINER_multihashmap_destroy(peers); } static void map_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { int fail = 0; check_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_CONTAINER_multihashmap_iterate (peers, &map_check_it, &fail); if (0 > fail) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Inconsistent peers after connection consistency check: %u\n", fail); else GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Inconsistent peers after connection consistency check: %u\n", fail); if (NULL != cls) { GNUNET_SCHEDULER_add_now (cls, NULL); } } static void stats_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); static int check_lowlevel_connections (int port, int protocol) { FILE *f; char * cmdline; char * proto; char line[1024]; int count = -1; #ifdef MINGW /* not supported */ return count; #else switch (protocol) { case tcp: proto = "-t"; break; case udp: proto = "-u"; break; case unixdomain: proto = "-x"; break; default: proto = ""; break; } /* Use netstat to get a numeric list of all connections on port 'port' in state 'ESTABLISHED' */ GNUNET_asprintf(&cmdline, "netstat -n %s | grep %u | grep ESTABLISHED", proto, port); if (system ("netstat -n > /dev/null 2> /dev/null")) if (system ("netstat -n > /dev/null 2> /dev/null") == 0) f = popen (cmdline, "r"); else f = NULL; else f = popen (cmdline, "r"); if (!f) { GNUNET_log_strerror(GNUNET_ERROR_TYPE_ERROR, "ss"); GNUNET_free (cmdline); return -1; } count = 0; while (NULL != fgets (line, sizeof (line), f)) { /* read */ //printf ("%s", line); count ++; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%i TCP connections established with port %u\n", count, port); pclose (f); GNUNET_free (cmdline); return count; #endif } static struct TransportPlugin * find_plugin (char * name) { struct TransportPlugin *cur = NULL; for (cur = phead; cur != NULL; cur = cur->next) { if (0 == strcmp(name, cur->short_name)) return cur; } return cur; } static int stats_check_cb (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent) { static int counter; uint64_t *val = cls; if (NULL != val) (*val) = value; counter ++; if ((STATS_VALUES == counter) || ((GNUNET_NO == have_tcp) && (STATS_VALUES - 1 == counter))) { int fail = GNUNET_NO; int low_level_connections_udp = check_lowlevel_connections (2086, udp); if (transport_connections != core_connections) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%u transport notifications <-> %u core notifications\n", transport_connections, core_connections); fail = GNUNET_YES; } if (transport_connections != statistics_transport_connections) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%u transport notifications <-> %u in statistics (peers connected)\n", transport_connections, statistics_transport_connections); fail = GNUNET_YES; } if (core_connections != statistics_core_entries_session_map) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%u core notifications <-> %u in statistics (entries session map)\n", core_connections, statistics_core_entries_session_map); fail = GNUNET_YES; } if (core_connections != statistics_core_neighbour_entries) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%u core notifications <-> %u in statistics (neighbour entries allocated)\n", core_connections, statistics_core_neighbour_entries); fail = GNUNET_YES; } if (GNUNET_NO == fail) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Check successful : (%u transport / %u core) connections established\n", transport_connections, core_connections); /* TCP plugin specific checks */ if (GNUNET_YES == have_tcp) { struct TransportPlugin * p = find_plugin ("tcp"); int low_level_connections_tcp = check_lowlevel_connections (p->port, p->protocol); if (low_level_connections_tcp != -1) { if (statistics_transport_tcp_connections > low_level_connections_tcp) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%u transport tcp sessions <-> %i established tcp connections\n", statistics_transport_tcp_connections, low_level_connections_tcp); fail = GNUNET_YES; } else if (low_level_connections_tcp != -1) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u TCP connections, %u UDP connections \n", low_level_connections_tcp, low_level_connections_udp); } } if (transport_connections > statistics_transport_tcp_connections) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%u transport notifications <-> %u in statistics (statistics_transport_tcp_connections)\n", transport_connections, statistics_transport_tcp_connections); fail = GNUNET_YES; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %u transport notifications <-> %u in statistics (statistics_transport_tcp_connections)\n", transport_connections, statistics_transport_tcp_connections); } } if (GNUNET_SCHEDULER_NO_TASK == statistics_task) statistics_task = GNUNET_SCHEDULER_add_delayed(REPEATED_STATS_DELAY, &stats_check, NULL); stat_check_running = GNUNET_NO; counter = 0; } return GNUNET_OK; } GNUNET_NETWORK_STRUCT_BEGIN struct PING { struct GNUNET_MessageHeader header; uint16_t src; }; struct PONG { struct GNUNET_MessageHeader header; uint16_t src; }; GNUNET_NETWORK_STRUCT_END static size_t send_transport_ping_cb (void *cls, size_t size, void *buf) { struct PeerContainer * pc = cls; struct PING ping; size_t mlen = sizeof (struct PING); if (size < mlen) { GNUNET_break (0); return 0; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending transport ping to `%s'\n", GNUNET_i2s (&pc->id)); ping.header.size = htons (mlen); ping.header.type = htons (1234); ping.src = htons (0); pc->th_ping = NULL; memcpy (buf, &ping, mlen); return mlen; } size_t send_core_ping_cb (void *cls, size_t size, void *buf) { struct PeerContainer * pc = cls; struct PING ping; size_t mlen = sizeof (struct PING); if (size < mlen) { GNUNET_break (0); return 0; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending core ping to `%s'\n", GNUNET_i2s (&pc->id)); ping.header.size = htons (mlen); ping.header.type = htons (1234); ping.src = htons (1); pc->ch_ping = NULL; memcpy (buf, &ping, mlen); return mlen; } int map_ping_it (void *cls, const GNUNET_HashCode * key, void *value) { struct PeerContainer *pc = value; if (ping == GNUNET_YES) { if ((GNUNET_YES == pc->transport_connected) && (NULL == pc->th_ping)) pc->th_ping = GNUNET_TRANSPORT_notify_transmit_ready(th, &pc->id, sizeof (struct PING), UINT_MAX, GNUNET_TIME_UNIT_FOREVER_REL, &send_transport_ping_cb, pc); else GNUNET_break(0); if ((GNUNET_YES == pc->core_connected) && (NULL == pc->ch_ping)) pc->ch_ping = GNUNET_CORE_notify_transmit_ready(ch, GNUNET_NO, UINT_MAX, GNUNET_TIME_UNIT_FOREVER_REL, &pc->id, sizeof (struct PING), send_core_ping_cb, pc); else GNUNET_break (0); } return GNUNET_OK; } static void stats_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { statistics_task = GNUNET_SCHEDULER_NO_TASK; if (GNUNET_YES == stat_check_running) { statistics_task = GNUNET_SCHEDULER_add_delayed(STATS_DELAY, &stats_check, NULL); } GNUNET_CONTAINER_multihashmap_iterate (peers, &map_ping_it, NULL); stat_check_running = GNUNET_YES; statistics_transport_connections = 0 ; statistics_core_entries_session_map = 0; statistics_core_neighbour_entries = 0; GNUNET_STATISTICS_get (stats, "transport", "# peers connected", GNUNET_TIME_UNIT_MINUTES, NULL, &stats_check_cb, &statistics_transport_connections); GNUNET_STATISTICS_get (stats, "core", "# neighbour entries allocated", GNUNET_TIME_UNIT_MINUTES, NULL, &stats_check_cb, &statistics_core_neighbour_entries); GNUNET_STATISTICS_get (stats, "core", "# peers connected", GNUNET_TIME_UNIT_MINUTES, NULL, &stats_check_cb, &statistics_core_entries_session_map); /* TCP plugin specific checks */ if (GNUNET_YES == have_tcp) GNUNET_STATISTICS_get (stats, "transport", "# TCP sessions active", GNUNET_TIME_UNIT_MINUTES, NULL, &stats_check_cb, &statistics_transport_tcp_connections); } size_t send_transport_pong_cb (void *cls, size_t size, void *buf) { struct PeerContainer * pc = cls; struct PING ping; size_t mlen = sizeof (struct PING); if (size < mlen) { GNUNET_break (0); return 0; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending transport pong to `%s'\n", GNUNET_i2s (&pc->id)); ping.header.size = htons (mlen); ping.header.type = htons (4321); ping.src = htons (0); pc->th_pong = NULL; memcpy (buf, &ping, mlen); return mlen; } static size_t send_core_pong_cb (void *cls, size_t size, void *buf) { struct PeerContainer * pc = cls; struct PING ping; size_t mlen = sizeof (struct PING); if (size < mlen) { GNUNET_break (0); return 0; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending core pong to `%s'\n", GNUNET_i2s (&pc->id)); ping.header.size = htons (mlen); ping.header.type = htons (4321); ping.src = htons (1); pc->ch_pong = NULL; memcpy (buf, &ping, mlen); return mlen; } static void map_connect (const struct GNUNET_PeerIdentity *peer, void * source) { struct PeerContainer * pc; if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(peers, &peer->hashPubKey)) { pc = GNUNET_malloc (sizeof (struct PeerContainer)); pc->id = *peer; pc->core_connected = GNUNET_NO; pc->transport_connected = GNUNET_NO; GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(peers, &peer->hashPubKey, pc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); } pc = GNUNET_CONTAINER_multihashmap_get(peers, &peer->hashPubKey); if (source == th) { if (GNUNET_NO == pc->transport_connected) { pc->transport_connected = GNUNET_YES; if (GNUNET_YES == ping) { if (NULL == pc->th_ping) pc->th_ping = GNUNET_TRANSPORT_notify_transmit_ready(th, peer, sizeof (struct PING), UINT_MAX, GNUNET_TIME_UNIT_FOREVER_REL, &send_transport_ping_cb, pc); else GNUNET_break(0); } } else { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s notified multiple times about for peers `%s' (%s : %s)\n", "TRANSPORT", GNUNET_i2s (&pc->id), "CORE", (pc->core_connected == GNUNET_YES) ? "yes" : "no"); GNUNET_break (0); } } if (source == ch) { if (GNUNET_NO == pc->core_connected) { pc->core_connected = GNUNET_YES; if (GNUNET_YES == ping) { if (NULL == pc->ch_ping) pc->ch_ping = GNUNET_CORE_notify_transmit_ready(ch, GNUNET_NO, UINT_MAX, GNUNET_TIME_UNIT_FOREVER_REL, peer, sizeof (struct PING), send_core_ping_cb, pc); else GNUNET_break (0); } } else { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s notified multiple times about for peers `%s' (%s : %s)\n", "CORE", GNUNET_i2s (&pc->id), "TRANSPORT", (pc->transport_connected == GNUNET_YES) ? "yes" : "no"); GNUNET_break (0); } } if (GNUNET_SCHEDULER_NO_TASK != check_task) GNUNET_SCHEDULER_cancel(check_task); check_task = GNUNET_SCHEDULER_add_delayed(CHECK_DELAY, &map_check, NULL); if (GNUNET_SCHEDULER_NO_TASK != statistics_task) GNUNET_SCHEDULER_cancel(statistics_task); statistics_task = GNUNET_SCHEDULER_add_delayed(STATS_DELAY, &stats_check, NULL); } static void map_disconnect (const struct GNUNET_PeerIdentity * peer, void * source) { struct PeerContainer * pc; if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(peers, &peer->hashPubKey)) { if (source == th) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s disconnect notification for unknown peer `%s'\n", "TRANSPORT", GNUNET_i2s (peer)); GNUNET_break (0); return; } if (source == ch) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s disconnect notification for unknown peer `%s'\n", "CORE", GNUNET_i2s (peer)); return; } } pc = GNUNET_CONTAINER_multihashmap_get(peers, &peer->hashPubKey); if (source == th) { if (NULL != pc->th_ping) { GNUNET_TRANSPORT_notify_transmit_ready_cancel(pc->th_ping); pc->th_ping = NULL; } if (NULL != pc->th_pong) { GNUNET_TRANSPORT_notify_transmit_ready_cancel(pc->th_pong); pc->th_pong = NULL; } if (GNUNET_YES == pc->transport_connected) { pc->transport_connected = GNUNET_NO; } else { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s notified for not connected peer `%s' (%s : %s)\n", "TRANSPORT", GNUNET_i2s (&pc->id), "CORE", (pc->core_connected == GNUNET_YES) ? "yes" : "no"); GNUNET_break (0); } } if (source == ch) { if (NULL != pc->ch_ping) { GNUNET_CORE_notify_transmit_ready_cancel (pc->ch_ping); pc->ch_ping = NULL; } if (NULL != pc->ch_pong) { GNUNET_CORE_notify_transmit_ready_cancel (pc->ch_pong); pc->ch_pong = NULL; } if (GNUNET_YES == pc->core_connected) { pc->core_connected = GNUNET_NO; } else { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s notified for not connected peer `%s' (%s : %s)\n", "CORE", GNUNET_i2s (&pc->id), "TRANSPORT", (pc->transport_connected == GNUNET_YES) ? "yes" : "no"); GNUNET_break (0); } } if ((GNUNET_NO == pc->core_connected) && (GNUNET_NO == pc->transport_connected)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing peer `%s'\n", GNUNET_i2s (&pc->id)); GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (peers, &peer->hashPubKey, pc)); GNUNET_free (pc); } if (GNUNET_SCHEDULER_NO_TASK != check_task) GNUNET_SCHEDULER_cancel(check_task); check_task = GNUNET_SCHEDULER_add_delayed(CHECK_DELAY, &map_check, NULL); if (GNUNET_SCHEDULER_NO_TASK != statistics_task) GNUNET_SCHEDULER_cancel(statistics_task); statistics_task = GNUNET_SCHEDULER_add_delayed(STATS_DELAY, &stats_check, NULL); } static void cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct TransportPlugin * cur = phead; if (NULL != th) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Disconnecting from transport service\n"); GNUNET_TRANSPORT_disconnect (th); th = NULL; } if (NULL != ch) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Disconnecting from core service\n"); GNUNET_CORE_disconnect (ch); ch = NULL; } if (GNUNET_SCHEDULER_NO_TASK != statistics_task) { GNUNET_SCHEDULER_cancel(statistics_task); statistics_task = GNUNET_SCHEDULER_NO_TASK; } if (GNUNET_SCHEDULER_NO_TASK != check_task) { GNUNET_SCHEDULER_cancel(check_task); check_task = GNUNET_SCHEDULER_NO_TASK; } for (cur = phead; cur != NULL; cur = phead) { GNUNET_CONTAINER_DLL_remove(phead, ptail, cur); GNUNET_free (cur->short_name); GNUNET_free (cur); } check_task = GNUNET_SCHEDULER_add_now (&map_check, &map_cleanup); } static void transport_notify_connect_cb (void *cls, const struct GNUNET_PeerIdentity * peer, const struct GNUNET_ATS_Information * ats, uint32_t ats_count) { transport_connections ++; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "TRANSPORT connect for peer `%s' (%u total)\n", GNUNET_i2s (peer), transport_connections); map_connect (peer, th); } /** * Function called to notify transport users that another * peer disconnected from us. * * @param cls closure * @param peer the peer that disconnected */ static void transport_notify_disconnect_cb (void *cls, const struct GNUNET_PeerIdentity * peer) { GNUNET_assert (transport_connections > 0); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "TRANSPORT disconnect for peer `%s' (%u total)\n", GNUNET_i2s (peer), transport_connections) ; map_disconnect (peer, th); transport_connections --; } static void transport_notify_receive_cb (void *cls, const struct GNUNET_PeerIdentity * peer, const struct GNUNET_MessageHeader * message, const struct GNUNET_ATS_Information * ats, uint32_t ats_count) { struct PeerContainer *pc = NULL; pc = GNUNET_CONTAINER_multihashmap_get(peers, &peer->hashPubKey); if (NULL == pc) { GNUNET_break (0); return; } if ((message->size == ntohs (sizeof (struct PING))) && (message->type == ntohs (1234))) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received %s %s from peer `%s'\n", "TRANSPORT", "PING", GNUNET_i2s (peer)) ; if (GNUNET_YES == ping) { if (NULL == pc->th_pong) pc->th_pong = GNUNET_TRANSPORT_notify_transmit_ready(th, peer, sizeof (struct PONG), UINT_MAX, GNUNET_TIME_UNIT_FOREVER_REL, &send_transport_pong_cb, pc); else GNUNET_break (0); } } if ((message->size == ntohs (sizeof (struct PONG))) && (message->type == ntohs (4321))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Received %s %s from peer `%s'\n", "TRANSPORT", "PONG", GNUNET_i2s (peer)); } } static int core_notify_receive_cb (void *cls, const struct GNUNET_PeerIdentity * peer, const struct GNUNET_MessageHeader * message, const struct GNUNET_ATS_Information* atsi, unsigned int atsi_count) { struct PeerContainer *pc = NULL; pc = GNUNET_CONTAINER_multihashmap_get(peers, &peer->hashPubKey); if (NULL == pc) { if (0 == memcmp (peer, &my_peer_id, sizeof (my_peer_id))) return GNUNET_OK; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Received unexpected message type %u from unknown peer `%s'\n", ntohs (message->type), GNUNET_i2s (peer)); GNUNET_break (0); return GNUNET_OK; } if ((message->size == ntohs (sizeof (struct PING))) && (message->type == ntohs (1234))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Received %s %s from peer `%s'\n", "CORE", "PING", GNUNET_i2s (peer)); if (GNUNET_YES == ping) { if (NULL == pc->ch_pong) pc->ch_pong = GNUNET_CORE_notify_transmit_ready(ch, GNUNET_NO, UINT_MAX, GNUNET_TIME_UNIT_FOREVER_REL, peer, sizeof (struct PONG), send_core_pong_cb, pc); else GNUNET_break (0); } } if ((message->size == ntohs (sizeof (struct PONG))) && (message->type == ntohs (4321))) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received %s %s from peer `%s'\n", "CORE", "PONG", GNUNET_i2s (peer)); } return GNUNET_OK; } static void core_connect_cb (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { if (0 != memcmp (peer, &my_peer_id, sizeof (struct GNUNET_PeerIdentity))) { core_connections ++; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "CORE connect for peer `%s' (%u total)\n", GNUNET_i2s (peer), core_connections); map_connect (peer, ch); } else { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "CORE connect for myself `%s' (%u total)\n", GNUNET_i2s (peer), core_connections); } } static void core_disconnect_cb (void *cls, const struct GNUNET_PeerIdentity * peer) { if (0 != memcmp (peer, &my_peer_id, sizeof (struct GNUNET_PeerIdentity))) { GNUNET_assert (core_connections > 0); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "CORE disconnect for peer `%s' (%u total)\n", GNUNET_i2s (peer), core_connections); map_disconnect (peer, ch); core_connections --; } else { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "CORE disconnect for myself `%s' (%u total)\n", GNUNET_i2s (peer), core_connections); } } static void core_init_cb (void *cls, struct GNUNET_CORE_Handle *server, const struct GNUNET_PeerIdentity *my_identity) { my_peer_id = *my_identity; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to core service\n"); } static void init () { struct TransportPlugin * cur; char *plugs; char *pos; char *secname; int counter; unsigned long long port; have_tcp = GNUNET_NO; have_udp = GNUNET_NO; have_http = GNUNET_NO; have_https = GNUNET_NO; have_unix = GNUNET_NO; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (mycfg, "TRANSPORT", "PLUGINS", &plugs)) return; counter = 0; for (pos = strtok (plugs, " "); pos != NULL; pos = strtok (NULL, " ")) { counter++; GNUNET_asprintf(&secname, "transport-%s", pos); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (mycfg, secname, "PORT", &port)) { GNUNET_free (secname); continue; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport plugin: `%s' port %llu\n"), pos, port); cur = GNUNET_malloc(sizeof (struct TransportPlugin)); cur->short_name = GNUNET_strdup (pos); cur->port = port; if (0 == strcmp("tcp", pos)) { have_tcp = GNUNET_YES; cur->protocol = tcp; } if (0 == strcmp("udp", pos)) { have_udp = GNUNET_YES; cur->protocol = udp; } if (0 == strcmp("http", pos)) { have_http = GNUNET_YES; cur->protocol = tcp; } if (0 == strcmp("https", pos)) { have_https = GNUNET_YES; cur->protocol = tcp; } if (0 == strcmp("unix", pos)) { have_unix = GNUNET_YES; cur->protocol = unixdomain; } GNUNET_CONTAINER_DLL_insert(phead, ptail, cur); GNUNET_free (secname); } GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Found %u transport plugins: `%s'\n"), counter, plugs); GNUNET_free (plugs); } /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param cfg configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { transport_connections = 0; core_connections = 0; mycfg = cfg; init(); stats = GNUNET_STATISTICS_create ("watchdog", cfg); peers = GNUNET_CONTAINER_multihashmap_create (20); th = GNUNET_TRANSPORT_connect(cfg, NULL, NULL, &transport_notify_receive_cb, &transport_notify_connect_cb, &transport_notify_disconnect_cb); GNUNET_assert (th != NULL); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to transport service\n"); ch = GNUNET_CORE_connect (cfg, 1, NULL, &core_init_cb, &core_connect_cb, &core_disconnect_cb, &core_notify_receive_cb, GNUNET_NO, NULL, GNUNET_NO, NULL); GNUNET_assert (ch != NULL); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, NULL); } /** * The main function. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { ping = GNUNET_NO; static const struct GNUNET_GETOPT_CommandLineOption options[] = { {'p', "ping", NULL, gettext_noop ("Send ping messages to test connectivity (default == NO)"), GNUNET_NO, &GNUNET_GETOPT_set_one, &ping}, GNUNET_GETOPT_OPTION_END }; return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "cn", gettext_noop ("help text"), options, &run, NULL)) ? ret : 1; } /* end of connection_watchdog.c */ gnunet-0.9.3/src/integration-tests/test_integration_bootstrap_and_connect_and_disconnect_nat.py.in0000755000175000017500000001046411760502552031117 00000000000000#!@PYTHON@ # This file is part of GNUnet. # (C) 2010 Christian Grothoff (and other contributing authors) # # GNUnet is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2, or (at your # option) any later version. # # GNUnet is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNUnet; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # import sys import os import subprocess import re import shutil import time import pexpect from gnunet_testing import Peer from gnunet_testing import Test from gnunet_testing import Check from gnunet_testing import Condition from gnunet_testing import * # # This test tests if a fresh peer bootstraps from a hostlist server and then # successfully connects to the server # # Conditions for successful exit: # Both peers have 1 connected peer in transport, core, topology, fs # # This test tests if a fresh peer bootstraps from a hostlist server and then # successfully connects to the server # # Conditions for successful exit: # Both peers have 1 connected peer in transport, core, topology, fs #definitions testname = "test_integration_bootstrap_and_connect" verbose = True check_timeout = 180 def cleanup (): if os.name == "nt": shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-ns"), True) shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_no_nat_client"), True) else: shutil.rmtree ("/tmp/c_bootstrap_server/", True) shutil.rmtree ("/tmp/c_no_nat_client/", True) def success_server_stop_cont (check): global success success = True; def success_cont (check): server.stop() check = Check (test) check.add (StatisticsCondition (client, 'transport', '# peers connected',0)) check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',0)) check.add (StatisticsCondition (client, 'core', '# peers connected',0)) check.add (StatisticsCondition (client, 'topology', '# peers connected',0)) check.add (StatisticsCondition (client, 'fs', '# peers connected',0)) check.run_blocking (check_timeout, success_server_stop_cont, fail_cont) def fail_cont (check): global success success = False; check.evaluate(True) def check (): check = Check (test) check.add (StatisticsCondition (client, 'transport', '# peers connected',1)) check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',1)) check.add (StatisticsCondition (client, 'core', '# peers connected',1)) check.add (StatisticsCondition (client, 'topology', '# peers connected',1)) check.add (StatisticsCondition (client, 'fs', '# peers connected',1)) check.add (StatisticsCondition (server, 'transport', '# peers connected',1)) check.add (StatisticsCondition (server, 'core', '# neighbour entries allocated',1)) check.add (StatisticsCondition (server, 'core', '# peers connected',1)) check.add (StatisticsCondition (server, 'topology', '# peers connected',1)) check.add (StatisticsCondition (server, 'fs', '# peers connected',1)) check.run_blocking (check_timeout, success_cont, fail_cont) # # Test execution # def run (): global success global test global server global client success = False test = Test ('test_integration_bootstrap_and_connect.py', verbose) server = Peer(test, './confs/c_bootstrap_server.conf'); client = Peer(test, './confs/c_nat_client.conf'); assert (True == server.start()); assert (True == client.start()); if ((client.started == True) and (server.started == True)): test.p ('Peers started, running check') time.sleep(5) check () server.stop () client.stop () cleanup () if (success == False): print ('Test failed') return False else: return True try: run () except (KeyboardInterrupt, SystemExit): print 'Test interrupted' server.stop () client.stop () cleanup () if (success == False): sys.exit(1) else: sys.exit(0) gnunet-0.9.3/src/integration-tests/Makefile.am0000644000175000017500000001451211762207770016266 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIB = -lgcov endif #bin_PROGRAMS = \ # connection_watchdog noinst_PROGRAMS = connection_watchdog noinst_SCRIPTS = \ gnunet_testing.py \ gnunet_pyexpect.py \ test_integration_connection_values_tcp.py \ test_integration_connection_values_tcp_udp.py \ test_integration_connection_values_tcp_udp_http.py if HAVE_PYTHON_PEXPECT check_SCRIPTS = \ test_integration_bootstrap_and_connect.py \ test_integration_bootstrap_and_connect_and_disconnect.py \ test_integration_bootstrap_and_connect_and_disconnect_nat.py \ test_integration_restart.py \ test_integration_clique.py \ test_integration_clique_nat.py \ test_integration_connect_on_restart.py endif # test_integration_disconnect.py check_PROGRAMS = \ test_connection_stability if ENABLE_TEST_RUN TESTS = \ $(check_SCRIPTS) endif connection_watchdog_SOURCE = \ connection_watchdog.c connection_watchdog_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' %.py: %.py.in Makefile $(do_subst) < $(srcdir)/$< > $@ chmod +x $@ gnunet_testing.py: gnunet_testing.py.in Makefile $(do_subst) < $(srcdir)/gnunet_testing.py.in > gnunet_testing.py chmod +x gnunet_testing.py gnunet_pyexpect.py: gnunet_pyexpect.py.in Makefile $(do_subst) < $(srcdir)/gnunet_pyexpect.py.in > gnunet_pyexpect.py chmod +x gnunet_pyexpect.py test_integration_bootstrap_and_connect.py: test_integration_bootstrap_and_connect.py.in Makefile $(do_subst) < $(srcdir)/test_integration_bootstrap_and_connect.py.in > test_integration_bootstrap_and_connect.py chmod +x test_integration_bootstrap_and_connect.py test_integration_bootstrap_and_connect_and_disconnect.py: test_integration_bootstrap_and_connect_and_disconnect.py.in Makefile $(do_subst) < $(srcdir)/test_integration_bootstrap_and_connect_and_disconnect.py.in > test_integration_bootstrap_and_connect_and_disconnect.py chmod +x test_integration_bootstrap_and_connect_and_disconnect.py test_integration_bootstrap_and_connect_and_disconnect_nat.py: test_integration_bootstrap_and_connect_and_disconnect_nat.py.in Makefile $(do_subst) < $(srcdir)/test_integration_bootstrap_and_connect_and_disconnect_nat.py.in > test_integration_bootstrap_and_connect_and_disconnect_nat.py chmod +x test_integration_bootstrap_and_connect_and_disconnect_nat.py test_integration_disconnect.py: test_integration_disconnect.py.in Makefile $(do_subst) < $(srcdir)/test_integration_disconnect.py.in > test_integration_disconnect.py chmod +x test_integration_disconnect.py #test_integration_disconnect_nat.py: test_integration_disconnect_nat.py.in Makefile # $(do_subst) < $(srcdir)/test_integration_disconnect_nat.py.in > test_integration_disconnect_nat.py # chmod +x test_integration_disconnect_nat.py test_integration_restart.py: test_integration_restart.py.in Makefile $(do_subst) < $(srcdir)/test_integration_restart.py.in > test_integration_restart.py chmod +x test_integration_restart.py test_integration_clique.py: test_integration_clique.py.in Makefile $(do_subst) < $(srcdir)/test_integration_clique.py.in > test_integration_clique.py chmod +x test_integration_clique.py test_integration_clique_nat.py: test_integration_clique_nat.py.in Makefile $(do_subst) < $(srcdir)/test_integration_clique_nat.py.in > test_integration_clique_nat.py chmod +x test_integration_clique_nat.py test_integration_connect_on_restart.py: test_integration_connect_on_restart.py.in Makefile $(do_subst) < $(srcdir)/test_integration_connect_on_restart.py.in > test_integration_connect_on_restart.py chmod +x test_integration_connect_on_restart.py test_integration_connection_values_tcp.py: test_integration_connection_values_tcp.py.in Makefile $(do_subst) < $(srcdir)/test_integration_connection_values_tcp.py.in > test_integration_connection_values_tcp.py chmod +x test_integration_connection_values_tcp.py test_integration_connection_values_tcp_udp.py: test_integration_connection_values_tcp_udp.py.in Makefile $(do_subst) < $(srcdir)/test_integration_connection_values_tcp_udp.py.in > test_integration_connection_values_tcp_udp.py chmod +x test_integration_connection_values_tcp_udp.py test_integration_connection_values_tcp_udp_http.py: test_integration_connection_values_tcp_udp_http.py.in Makefile $(do_subst) < $(srcdir)/test_integration_connection_values_tcp_udp_http.py.in > test_integration_connection_values_tcp_udp_http.py chmod +x test_integration_connection_values_tcp_udp_http.py test_connection_stability_SOURCES = \ test_connection_stability.c test_connection_stability_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ gnunet_testing.py.in \ gnunet_pyexpect.py.in \ test_integration_connection_values_tcp.py.in \ test_integration_connection_values_tcp_udp.py.in \ test_integration_connection_values_tcp_udp_http.py.in \ test_integration_bootstrap_and_connect.py.in \ test_integration_bootstrap_and_connect_and_disconnect.py.in \ test_integration_bootstrap_and_connect_and_disconnect_nat.py.in \ test_integration_connect_on_restart.py.in \ test_integration_disconnect.py.in \ test_integration_restart.py.in \ test_integration_clique.py.in \ test_integration_clique_nat.py.in \ confs/c_bootstrap_server.conf \ confs/c_nat_client.conf \ confs/c_no_nat_client_2.conf \ confs/c_no_nat_client.conf \ confs/c_normal_client_tcp.conf \ confs/c_normal_client_tcp_udp.conf \ confs/c_normal_client_tcp_udp_http.conf \ confs/c_no_nat_client_http.conf \ confs/c_no_nat_client_http_2.conf\ confs/c_no_nat_client_http.conf \ confs/c_no_nat_client_http_2.conf \ confs/c_no_nat_client_unix.conf \ confs/c_no_nat_client_unix_2.conf \ test_connection_stability.conf \ hostkeys/0000-hostkey \ hostkeys/0001-hostkey \ hostkeys/0002-hostkey \ hostkeys/0003-hostkey \ hostkeys/0004-hostkey \ hostkeys/0005-hostkey \ hostkeys/0006-hostkey \ hostkeys/0007-hostkey \ hostkeys/0008-hostkey \ hostkeys/0009-hostkey # test_integration_disconnect_nat.py CLEANFILES = \ $(check_SCRIPTS) \ gnunet_testing.py gnunet-0.9.3/src/integration-tests/test_integration_restart.py.in0000755000175000017500000001160611760502552022335 00000000000000#!@PYTHON@ # This file is part of GNUnet. # (C) 2010 Christian Grothoff (and other contributing authors) # # GNUnet is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2, or (at your # option) any later version. # # GNUnet is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNUnet; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # import sys import os import subprocess import re import shutil import time import pexpect from gnunet_testing import Peer from gnunet_testing import Test from gnunet_testing import Check from gnunet_testing import Condition from gnunet_testing import * # # This test tests if a fresh peer bootstraps from a hostlist server and then # successfully connects to the server. When both peers are connected # in transport, core, topology, fs, botth peers are shutdown and restarted # # Conditions for successful exit: # Both peers have 1 connected peer in transport, core, topology, fs after restart #definitions testname = "test_integration_restart" verbose = False check_timeout = 180 def cleanup (): if os.name == "nt": shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-ns"), True) shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_no_nat_client"), True) else: shutil.rmtree ("/tmp/c_bootstrap_server/", True) shutil.rmtree ("/tmp/c_no_nat_client/", True) def success_restart_cont (check): global success test.p ('Shutting down client & server') server.stop () client.stop () success = True; def fail_restart_cont (check): global success success = False; check.evaluate(True) def success_connect_cont (check): test.p ('Shutting down client & server for restart') server.stop () client.stop () time.sleep(5) test.p ('Restarting client & server') server.start () client.start () check = Check (test) check.add (StatisticsCondition (client, 'transport', '# peers connected',1)) check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',1)) check.add (StatisticsCondition (client, 'core', '# peers connected',1)) check.add (StatisticsCondition (client, 'topology', '# peers connected',1)) check.add (StatisticsCondition (client, 'fs', '# peers connected',1)) check.add (StatisticsCondition (server, 'transport', '# peers connected',1)) check.add (StatisticsCondition (server, 'core', '# neighbour entries allocated',1)) check.add (StatisticsCondition (server, 'core', '# peers connected',1)) check.add (StatisticsCondition (server, 'topology', '# peers connected',1)) check.add (StatisticsCondition (server, 'fs', '# peers connected',1)) check.run_blocking (check_timeout, success_restart_cont, fail_restart_cont) def fail_connect_cont (check): global success success= False; check.evaluate(True) def check_connect (): check = Check (test) check.add (StatisticsCondition (client, 'transport', '# peers connected',1)) check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',1)) check.add (StatisticsCondition (client, 'core', '# peers connected',1)) check.add (StatisticsCondition (client, 'topology', '# peers connected',1)) check.add (StatisticsCondition (client, 'fs', '# peers connected',1)) check.add (StatisticsCondition (server, 'transport', '# peers connected',1)) check.add (StatisticsCondition (server, 'core', '# neighbour entries allocated',1)) check.add (StatisticsCondition (server, 'core', '# peers connected',1)) check.add (StatisticsCondition (server, 'topology', '# peers connected',1)) check.add (StatisticsCondition (server, 'fs', '# peers connected',1)) check.run_blocking (check_timeout, success_connect_cont, fail_connect_cont) # # Test execution # def run (): global success global test global server global client success = False test = Test ('test_integration_disconnect', verbose) server = Peer(test, './confs/c_bootstrap_server.conf'); server.start(); client = Peer(test, './confs/c_no_nat_client.conf'); client.start(); if ((client.started == True) and (server.started == True)): test.p ('Peers started, running check') check_connect () server.stop () client.stop () cleanup () if (success == False): print ('Test failed') return True else: return False try: run () except (KeyboardInterrupt, SystemExit): print 'Test interrupted' server.stop () client.stop () cleanup () if (success == False): sys.exit(1) else: sys.exit(0) gnunet-0.9.3/src/integration-tests/test_integration_connection_values_tcp_udp_http.py.in0000755000175000017500000000623311760502552027144 00000000000000#!@PYTHON@ # This file is part of GNUnet. # (C) 2010 Christian Grothoff (and other contributing authors) # # GNUnet is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2, or (at your # option) any later version. # # GNUnet is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNUnet; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # # # This test starts 3 peers and expects bootstrap and a connected clique # # Conditions for successful exit: # Both peers have 1 connected peer in transport, core, topology, fs import sys import os import subprocess import re import shutil import time import pexpect from gnunet_testing import Peer from gnunet_testing import Test from gnunet_testing import Check from gnunet_testing import Condition from gnunet_testing import * #definitions testname = "test_integration_connection_value" verbose = True check_timeout = 180 def cleanup (): if os.name == "nt": shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_normal_client"), True) else: shutil.rmtree ("/tmp/c_normal_client/", True) def success_cont (check): global success success = True; def fail_cont (check): global success success= False; check.evaluate(True) def check_connect (): check = Check (test) check.add (EqualStatisticsCondition (client, 'transport', '# peers connected', client, 'core', '# neighbour entries allocated')) check.add (EqualStatisticsCondition (client, 'transport', '# peers connected', client, 'core', '# peers connected')) check.add (EqualStatisticsCondition (client, 'core', '# neighbour entries allocated', client, 'core', '# peers connected')) check.add (EqualStatisticsCondition (client, 'transport', '# peers connected', client, 'topology', '# peers connected')) check.add (EqualStatisticsCondition (client, 'topology', '# peers connected', client, 'core', '# peers connected')) while True: check.reset() res = check.run_once (None, None) print "Values are equal" check.evaluate (False) #if (False == res): # break time.sleep (5) # # Test execution # def run (): global success global test global client success = False test = Test ('test_integration_connection_value', verbose) client = Peer(test, './confs/c_normal_client_tcp_udp_http.conf'); client.start(); if (client.started == True): test.p ('Peers started, running check') check_connect () client.stop () cleanup () if (success == False): print ('Test failed') return False else: return True try: run () except (KeyboardInterrupt, SystemExit): print 'Test interrupted' client.stop () cleanup () if (success == False): sys.exit(1) else: sys.exit(0) gnunet-0.9.3/src/integration-tests/test_integration_bootstrap_and_connect_and_disconnect.py.in0000755000175000017500000001046711760502552030260 00000000000000#!@PYTHON@ # This file is part of GNUnet. # (C) 2010 Christian Grothoff (and other contributing authors) # # GNUnet is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2, or (at your # option) any later version. # # GNUnet is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNUnet; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # import sys import os import subprocess import re import shutil import time import pexpect from gnunet_testing import Peer from gnunet_testing import Test from gnunet_testing import Check from gnunet_testing import Condition from gnunet_testing import * # # This test tests if a fresh peer bootstraps from a hostlist server and then # successfully connects to the server # # Conditions for successful exit: # Both peers have 1 connected peer in transport, core, topology, fs # # This test tests if a fresh peer bootstraps from a hostlist server and then # successfully connects to the server # # Conditions for successful exit: # Both peers have 1 connected peer in transport, core, topology, fs #definitions testname = "test_integration_bootstrap_and_connect" verbose = True check_timeout = 180 def cleanup (): if os.name == "nt": shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-ns"), True) shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_no_nat_client"), True) else: shutil.rmtree ("/tmp/c_bootstrap_server/", True) shutil.rmtree ("/tmp/c_no_nat_client/", True) def success_server_stop_cont (check): global success success = True; def success_cont (check): server.stop() check = Check (test) check.add (StatisticsCondition (client, 'transport', '# peers connected',0)) check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',0)) check.add (StatisticsCondition (client, 'core', '# peers connected',0)) check.add (StatisticsCondition (client, 'topology', '# peers connected',0)) check.add (StatisticsCondition (client, 'fs', '# peers connected',0)) check.run_blocking (check_timeout, success_server_stop_cont, fail_cont) def fail_cont (check): global success success = False; check.evaluate(True) def check (): check = Check (test) check.add (StatisticsCondition (client, 'transport', '# peers connected',1)) check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',1)) check.add (StatisticsCondition (client, 'core', '# peers connected',1)) check.add (StatisticsCondition (client, 'topology', '# peers connected',1)) check.add (StatisticsCondition (client, 'fs', '# peers connected',1)) check.add (StatisticsCondition (server, 'transport', '# peers connected',1)) check.add (StatisticsCondition (server, 'core', '# neighbour entries allocated',1)) check.add (StatisticsCondition (server, 'core', '# peers connected',1)) check.add (StatisticsCondition (server, 'topology', '# peers connected',1)) check.add (StatisticsCondition (server, 'fs', '# peers connected',1)) check.run_blocking (check_timeout, success_cont, fail_cont) # # Test execution # def run (): global success global test global server global client success = False test = Test ('test_integration_bootstrap_and_connect.py', verbose) server = Peer(test, './confs/c_bootstrap_server.conf'); client = Peer(test, './confs/c_no_nat_client.conf'); assert (True == server.start()); assert (True == client.start()); if ((client.started == True) and (server.started == True)): test.p ('Peers started, running check') time.sleep(5) check () server.stop () client.stop () cleanup () if (success == False): print ('Test failed') return False else: return True try: run () except (KeyboardInterrupt, SystemExit): print 'Test interrupted' server.stop () client.stop () cleanup () if (success == False): sys.exit(1) else: sys.exit(0) gnunet-0.9.3/src/integration-tests/test_integration_connection_values_tcp.py.in0000755000175000017500000000622211760502552025233 00000000000000#!@PYTHON@ # This file is part of GNUnet. # (C) 2010 Christian Grothoff (and other contributing authors) # # GNUnet is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2, or (at your # option) any later version. # # GNUnet is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNUnet; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # # # This test starts 3 peers and expects bootstrap and a connected clique # # Conditions for successful exit: # Both peers have 1 connected peer in transport, core, topology, fs import sys import os import subprocess import re import shutil import time import pexpect from gnunet_testing import Peer from gnunet_testing import Test from gnunet_testing import Check from gnunet_testing import Condition from gnunet_testing import * #definitions testname = "test_integration_connection_value" verbose = True check_timeout = 180 def cleanup (): if os.name == "nt": shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_normal_client"), True) else: shutil.rmtree ("/tmp/c_normal_client/", True) def success_cont (check): global success success = True; def fail_cont (check): global success success= False; check.evaluate(True) def check_connect (): check = Check (test) check.add (EqualStatisticsCondition (client, 'transport', '# peers connected', client, 'core', '# neighbour entries allocated')) check.add (EqualStatisticsCondition (client, 'transport', '# peers connected', client, 'core', '# peers connected')) check.add (EqualStatisticsCondition (client, 'core', '# neighbour entries allocated', client, 'core', '# peers connected')) check.add (EqualStatisticsCondition (client, 'transport', '# peers connected', client, 'topology', '# peers connected')) check.add (EqualStatisticsCondition (client, 'topology', '# peers connected', client, 'core', '# peers connected')) while True: check.reset() res = check.run_once (None, None) print "Values are equal" check.evaluate (False) #if (False == res): # break time.sleep (5) # # Test execution # def run (): global success global test global client success = False test = Test ('test_integration_connection_value', verbose) client = Peer(test, './confs/c_normal_client_tcp.conf'); client.start(); if (client.started == True): test.p ('Peers started, running check') check_connect () client.stop () cleanup () if (success == False): print ('Test failed') return False else: return True try: run () except (KeyboardInterrupt, SystemExit): print 'Test interrupted' client.stop () cleanup () if (success == False): sys.exit(1) else: sys.exit(0) gnunet-0.9.3/src/integration-tests/gnunet_pyexpect.py.in0000644000175000017500000000543111760502552020424 00000000000000#!@PYTHON@ # This file is part of GNUnet. # (C) 2010 Christian Grothoff (and other contributing authors) # # GNUnet is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2, or (at your # option) any later version. # # GNUnet is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNUnet; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # Testcase for gnunet-peerinfo from __future__ import print_function import os import re import subprocess import sys import shutil import time class pexpect (object): def __init__ (self): super (pexpect, self).__init__ () def spawn (self, stdin, arglist, *pargs, **kwargs): env = kwargs.pop ('env', None) if env is None: env = os.environ.copy () # This messes up some testcases, disable log redirection env.pop ('GNUNET_FORCE_LOGFILE', None) self.proc = subprocess.Popen (arglist, *pargs, env=env, **kwargs) if self.proc is None: print ("Failed to spawn a process {0}".format (arglist)) sys.exit (1) if stdin is not None: self.stdo, self.stde = self.proc.communicate (stdin) else: self.stdo, self.stde = self.proc.communicate () return self.proc def expect (self, s, r, flags=0): stream = self.stdo if s == 'stdout' else self.stde if isinstance (r, str): if r == "EOF": if len (stream) == 0: return True else: print ("Failed to find `{1}' in {0}, which is `{2}' ({3})".format (s, r, stream, len (stream))) sys.exit (2) raise ValueError ("Argument `r' should be an instance of re.RegexObject or a special string, but is `{0}'".format (r)) m = r.search (stream, flags) if not m: print ("Failed to find `{1}' in {0}, which is is `{2}'".format (s, r.pattern, stream)) sys.exit (2) stream = stream[m.end ():] if s == 'stdout': self.stdo = stream else: self.stde = stream return m def read (self, s, size=-1): stream = self.stdo if s == 'stdout' else self.stde result = "" if size < 0: result = stream new_stream = "" else: result = stream[0:size] new_stream = stream[size:] if s == 'stdout': self.stdo = new_stream else: self.stde = new_stream return result gnunet-0.9.3/src/integration-tests/test_connection_stability.conf0000644000175000017500000000156511761753146022371 00000000000000[PATHS] SERVICEHOME = /tmp/test_connection_stability/ DEFAULTCONFIG = test_connection_stability.conf [resolver] PORT = 2564 [transport] PORT = 2565 PLUGINS = tcp [arm] PORT = 2566 DEFAULTSERVICES = [statistics] PORT = 2567 [transport-tcp] PORT = 2568 BINDTO = 127.0.0.1 [peerinfo] PORT = 2569 [core] PORT = 2570 [testing] NUM_PEERS = 5 WEAKRANDOM = YES F2F = YES HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat [dht] AUTOSTART = NO [nat] DISABLEV6 = YES ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 USE_LOCALADDR = NO [dns] AUTOSTART = NO [nse] AUTOSTART = NO [mesh] AUTOSTART = NO [datastore] AUTOSTART = NO [fs] AUTOSTART = NO [dv] AUTOSTART = NO [chat] AUTOSTART = NO [vpn] AUTOSTART = NO [gns] AUTOSTART = NO [namestore] AUTOSTART = NO [lockmanager] AUTOSTART = NO [arm] DEFAULTSERVICES = core gnunet-0.9.3/src/integration-tests/hostkeys/0000755000175000017500000000000011763406751016161 500000000000000gnunet-0.9.3/src/integration-tests/hostkeys/0005-hostkey0000644000175000017500000000162211671106247020070 00000000000000’€€â\"ÚƒÀüë <ëºgñÈôÂ@ª0µ] ŠjL1pœ“O&Ä4Ÿæw%œã9é2`ûú&Ê ®9÷EÁ&rè9–ºµ·Êåp˜Lj!çEâѦ;´ïK”ÛÁ€×åý¿Fz=É=ŠåIæwu†=ä›OŒÒž/E Þ`p[‡’Zr5}[Ç‹»ŒŠò›ßK‰ Ÿ~Æc‘m6Ól›eu&rç\õö3¥tvÅÅãoCv×9·ËïÚ€4×yý¤ Š·‚¶+m¾j}nî8rñÌPñ/)`é¬IµEü0ˤ·sôg¤r«Z±@nXجÏrBƒüf™1µÅ ™z4Ì`¥ýòéðÊ{«[±üy1ðõ “½,.`"Õ9ˆÁ‚yÑû%F°íz"’üšøúÐ9QÏ-/¤  *Ï¿{ç ¬].[Ÿk6ù4:•|V{¿ƒl:x>Ï+wr¢…¹Š9£Ìb©áeн֥D*”ÉEäÒ]ùä›XšUÆÈÅ–—,DøŒ¤‚ØZKpœøÿÄBµfê$Y z,RÔ„½|Tß4åÁþe${}'À“æYòˆæaKEòÙírÿ¥¹˜ÌÖì<lÛµ$|îè[†èmrAå ËÇ="\5mí1ÁáL=‡N{þ4þ-cÓ¢@ˆ7ë´M¸Z”ì‚G¸ |¹‚æ( ®„ø¿áèWYlÙ‘R5þ~ò‘±ùú”²¢Ë"e+¯e´růP€¦ÚÌï'R)z¶Ê_ Œ6ŠHUŒ7>·C£qý8eã÷ê<ºþêÚø¹S±ªãúKi•ã¶kvz~˜]L+ýp®á·¤­åŠ='›ÌÚE:¯Ü ò2qʼnÃT#˜´gõióVM•g¢¸‡¹“±>™ú±®µWºþ±¼å ãM˜ã¤kvðgf7Üé½U³‰2C_E†xmKFÄbVÄhØsˆ}8ȯ­*IX4>õAîv•G0 ´€ݵ¶ú¹¬éÞ‚:Ó=³ÌûQç±ZÁ1§8î¿P4^ßq±â“×Ó`_»ÛÕ»ˆÇ2W¿‡»Óѽ±0ð^>èð€=|1uÔuØSô úÞ˜å N?‰ñÚIU-áɱ*º`Q>ôV-nnÏ¥n÷r›äî¢g |‰gnunet-0.9.3/src/integration-tests/hostkeys/0008-hostkey0000644000175000017500000000162211671106247020073 00000000000000’€€ÙÚ1@["œïß8þ“—KEë¥Ý}E˜úŸ£ÞvÅ>©Š[ÛárXŸT¢oÐã@“ÊbµK¿ÎŸÁp0Áž¢FZµ`.$xaUˆ8mØpZ©3Êìï;(Ò÷ý@ÀmÄFÚ»Âp×özoùï}ÂVåÒ+[AଳPÅ1 €mÏÝ/FV=£™¹+-JüÐCE7„½úž>Ƨ2 Ý2ø²%ó)7öß"‡ Kq4i™#½fÒvÜxs•ån±“<ê©öuŒûc'A(Ïgâ“%u; z°’©Å_lÜð)Á¡?aÐòÓTáôÿCáÎ:oéš;wx½¯{Žw‡}/xæVeî›Íê½S‰ÛVM^O+¡ –ºŽ‚£¨‚b[(<;ÄçlˆV1UR×Èžšï?(?>6,Òˆi9÷hbwq.à)¯¥Ç^Ñ·ž $ë#ƒ=<%Ä–=OrÃ-D=åésÿÂy´e~«òa #ˆS´¢_¼”®ÄZ‰‚ލŽì£b,™® BŸ ‘<˜$ $×6Wèo*Mq()ñ¡Zïîs”ÀÙŒ'^Xä‡-ŽÛâU×?üÑ’k‚cüΑgóõ¾<ÂDn¸WöÖ27`Ÿ0Åw#]z÷àɯVçŠ$>û¨Uò¾UXˆÑíû;”0v7tm¢®˜aŒ«“}B'ØíÂv é¢44‚&Ø­m”Jq Û ¿¯„Ôçæún*‰1}¢ÁÐù®¤NT{ëäáù‚:nö89ë,àÃ5™>–ù%°ìæÞÕ1qKou=£K/fÁéT£OHÌ&eñ.F¿ë\9êXÌÙˆ ‚ ÿÕ]»ñLY È8ä äWdS¸–ÙbjvÕ#[·3¾ZM£•Ã}øž ç¶±±ÿ‚ƒz³y—D ç.>I§_Ê{ Q7}Ä’˜1NæK³›NuøTAît«IÐ^÷z¾œ©‹‰ièî ¬AØþŒÁ7\{%¼ËIsu~1¿ãҧȆè‡S;'ÜN”Ëð*ì‡b6– Ì¸GCÌË–ÂQî¯O+ÑP‹ $íÁ:Åþ?‡.É…ºA¬€ËlÔ‰ ÝŽI†­al˜‘å†;â}P¥`1øï„° ½Ì»5b¼P€e}È”6Mÿ[´jgnunet-0.9.3/src/integration-tests/hostkeys/0001-hostkey0000644000175000017500000000162211671106247020064 00000000000000’€€ÕÜ*H¾ BÞ;˜ò¾5¦H‘+¸E?wß²£…g'ˆ˜qÕûo†ŒP¢Ât¤ÈK¯äÛ7Ÿ—Ró LLOAH™§îŒËæÛ´åx¬m„OÈfènÅš)ÌœLpØfŒˆCÀžÁûj>^ÞP£Ÿ|lžðj\‡† M¶ÖÊ Þê²néù rÛcT]…hMÏJyë~ýÜUÊm¢êÐ]á°A<¦d åb#åÏ·[„U%_ÑúGØóStùþEµÓðYÓ‚q$( ô»ÇÝ·+Æ[5¥ùQ]çÙ:' n E5<U£¬üOاâ[^ t¨íûÇIȃ ;àZ{‰ý뜈ÄCˆå_t3š Î÷äçšîŒú¹JÖ&2–,.f24 ˆ¸nBM°{SÏ«4¤O¶OÞ@Ù’ÙæÅÐ9ßõ'TÃv¾S'¯»åNûBÅ$æçHJ^9ˆ‘¸HpÏÑ÷ŸS˵0bQÇ\ö± 7 :;b¨ëèÈ&:¼$È.=Ó7DºñœÇY5§Ñsåô9\iÜÉ.GÓo…´ÎQæ$©“qfÇÕÉM„ZõÖêÚö7ËÅÙo;|º±yÖ¨4*¥ëiâüß¹ .Ì9üÂgkn «¿ÐÞ„¤s'Ã4eŽMãoíΫQüÖé£Bü6Ù¥û‰‰Ø¹ç[Q`Ÿ§Yz¢ÝãH¹!¨1*M%…¸âó!0v¯ØŠEQ2üœìpz‰‘¡¡‡}âh/þÓsèºv©g,ñŠÏæ{‚ò”~x"òþÌiU¶dï/ ZI™ÉúŒÝÒ½>öLr¬m•ÕÌÛ­ßd½rÓ_GÙ§òîµ2Éùôå{·ÂÇ«JìûŸf“Û×<ÏOªA4Ô¾©PìÂxäBSDp2<*Ç} §± YÅQûš<(cBÅý†³U‡áúØ…¬ˆ Ba":øÊZJEW-e¿yøöšU:®F¾ß#¼FÚióüÛÒ™{™åÄî­qRŽ£<îŸR‘4Áà’Z'´'£O·’+ÛÒoXøKæp2J[‹Äl£]”…xÇQ÷qä`qB×wòJ+FDçuxy߯zïà?ÙX²`®ÌB\\ýãî n>êÔH?TM©}ªAä8“¢“–Ê»ÕS'M2J‘n ÚQ˜)gnunet-0.9.3/src/integration-tests/hostkeys/0009-hostkey0000644000175000017500000000162211671106247020074 00000000000000’€€£_jñÂôÂð)“¦pá ‘—{L/³—LJµÈ¿@ã¦:§tøTìËre~Ÿ/4ökHªóf…CI¿ì'- pRA+‰9Ÿp´eì´ŒGl½jݽ±Cbù’â÷vĘŒ1¢ Q4dr>Òx1>1÷;(û%AžÓ´t³B¯â û‚Ó½K'¼ômìCð‚<œ Þòä”­¶Q|‚Ƚ$ÍP¢ýWÁv´b¨qÅäÖb8£ñÈuzá4àG'ùfPqâ8½VÅ,K›û;ý˜\Ú¤gnunet-0.9.3/src/integration-tests/hostkeys/0004-hostkey0000644000175000017500000000162211671106247020067 00000000000000’€€È‹­5cF f+’Tñ(¾QêÃãWÛeÂÒN‚3ñíK^™ìñb®È'KÐ1õQ¿×X#Ý‹¯&ñÚšuHÿ ]¿æ‰?Ï E¡…‘˜~ê ‚B)žùƒ)±ÓMéÿZ0E¢G †Úš%s8ã×ôB3><®fk÷FæÝ:¶9Ýšì1xhMGKS5fo{s_L[‹Q“”›2¨äÛHmT´õ‡HEúN'IJ9Ãué:r·Ó²{l$\£ÏE"EØ ÙxrÙƒ¸ n0¯#Ä’<(Hl^`ˆ…¸Ú½V©»ˆ)ÖÒX”¬]ŒíX¹ÁXÒª"eÚGè!Ú=a¾0V~ߊöf\çgÇ\0a¿®‘k¯ IÕýž4x¯ðT^¤ 9Ô‹ñ>%ó$UÂbÙi´d@ýèfUTÆålêÄoå %Q?†µ“ŽÂñ âƒFOh£ŸDŽ¥/ãH~k¹wå.û¸M³Œ(êe=*.V5ßœúw]}oŸhÎòë5H.ÎøÔ›¢^ʺ#4q¥‘Ô/²®½Ù½ÈÑ}ÀeýƒÑô}oE¨À ¨º3óÒ‚¨ÊZÿqžˆ‰2G¦;w¶;ùʔՔÈB>Š)´ÀJ/ÌL‹Çv#B>M 8‰„hœÉ–Ö+cç?I‡7¼Ä!^#çºi·yg:¿†ÐÚcãÔ£Š?Vpd©Ýæž’|—©FKýŒŽ-c¾U÷„Ó½:gìãêÏäV’:œÆ? Ÿ"=üSµà¹<Œ‚ù%Ó÷Ž„iÆÉÞ¢ÜI/<ÌÎÂë‹8,×äÄpp.;Pô+ØD[¼fÙ>,&’é›÷G«Ëæ®ü óÅ ÊþV#á}Û+|VnüC0F–tl«µoûߤ¿BF¼uíªÝ6KóOfÛÅ—ŽMÊ:>J›…ߊ ÜÚ¦óQ× Ï†ñ) <Õu> º‹ÃÊ•‰ˆ80/häaùKˆ´Òt~²Y€z~¥¢¯«ÉÈÖùo8Uµ‰ðØNÆêLm‡¹þb–ÕsFuDý:F_@Ù*g×áw!„°HÅŠ~kí Hût°«…H€E&øtNX  $óô‡‰N¥y"ÉBs%ð9½•«ÅâG½I1h$gÖi@fÇd´PþŸ?‚½‚ÆÑôÎ- 7|Xʃ¢ùtÖ~~€1Üõ+A9ÝzÄ¿gnunet-0.9.3/src/integration-tests/hostkeys/0000-hostkey0000644000175000017500000000162211671106247020063 00000000000000’€€ÀåñÜ÷¢6¯]’‹íléÞ‘¯Uøê‘—— ®9"&ú|¾Tô˜1Ü/âl‚J…ç¿—Àä4 ·fa«€*÷š«6lq¦°íšÞëºéUœ&tÇìJê ãF¶²€+qÀ´ÈÈ ›l|ÇFáq´2ziÜIÖdAñâir"¼P+Qr'' ŸpÔáM‚å.™{zU÷OEÕHx¢©[ò´*©ÎE<¼:}$ÊAv}_ä‡Í[¦À1Ãê´âÖü«ÏQ¡á"À©¹á@ÕØ-ÙYß3ë4d\°ë æ¶}µ Mñz± ª ñq8UÐ_ž8UŒïÜb)—{”ùÿº†š8Õú~øå>²âÄå×÷ÒkIOvžÌAM*¦yàrÅ- KÐN'UC>JþáÉä3u.‰š»¶pA»}Ì¡.7³ÉE”gç.s˜XzÚX[Ý>ÆT…¬Æ6H‚ÕrÍ“‡8Ð@3âxX-(u­¤÷³!³æäpQ3Ð9aq ¢§Ð:æ{r‚;L™ ~hŠ=^,2ØÛJ&&î ŽVz¾ç U)ž¯¥d&`øá.ƒe2„yx!Ê!a ¼˜ˆç+Mô” {sðé`¯Ù Y¥.NÌ]RNV?¥jK“¸•¢a¹zp©d{¶Ú͹Y62U©iÌÀY ×½sk ;Ë\ca•/Ô¦œþÊÞøó]1ýŽ»¯qtw#@FßбïÇðqÍç‘ö¬M„Œ÷P|Èy¦´–€*DMMÍ íz®p.F½?ý £gnunet-0.9.3/src/integration-tests/hostkeys/0006-hostkey0000644000175000017500000000162211671106247020071 00000000000000’€€ŸGUÓÐ0í_ZêÚY5ãx²r+H`Y…ŽÔ—á9€ý¦ï8Î\¿G¯¹ëοõ x´ ;ëàq9·*!··H@¬‚óÌc,æ&!Wn-ärB}ã^•ˆå$Yð)í(€Úp¬È=³¹°{ψ8Ü ûù“ªï“äæ”¬àa#øûÄáý à ¥åu.<ÜH3amïä¹Oªýü $­$àX#ƒÐ~uÖ›h°v'ºq3­ÞËX B‹³Æ©V%!®îræ ;˜KôÇS:`mðjtÅršËbþÎ|¬ÁgÛ“ñès•á•„>‘¶D(¥ì¨±¬[i²»J¸ûÜØ{®%Œæ4sAî¬À$ÝòÁs9 üh:  ¦i’?àf¾&tNtjÒˆï7Áu×®¥&äÜFÁíeÄ båÙÙysæÞ#*u”®ÃRGq«?À+7Á>®òÃòa€y‡ÉZQùã‘t  ·ì¥‚½:)f:SŠQ¯(aÙ`@;©ËI6¹Ë“[“øŽN½Ã 2ŸÃ²=ŽfÑ‹2;_×Tw°‘u“øomo'Án”vû$«ï²C¥²(ZÜü M É¿#¢zÒÑÙOøIe­q¨9qø|ñ¯áI"è}O6àh\4pè£Y»|úÄ2þƒ'˜È*]óR^RéM¾.<Ìø¢ÞEøå+eížEAî#° èôæ¤_úÄF÷ÄubH>|œŠ1yN¬¸W?uþ;i{mÔ¶9j½=3d6Vò¤€E€ü˜ÝŠçð#È«¸,ÎÉ,òŠoÃ'iìÏËëë¡>Ø¢­‹M‹ÉÅuúªmµ¾ÓÜkÍ”ñžw~~äùì¿'V\1ϱá(}µD<Ü¡yOÞ–#‡ë>s+Ùë.›çG€WÌ¥&Ø)eòÉŽ|1"ËÇí‡P3j_{\/rq0î6‰}˜~pp(ñf•ü±å,*‡lÔ¸ G©ì©[ÐëŒd5Rª8OCU¡ƒ …?ÌÐR]gÌ-šU[têïµ^ )I®õ¥…hWhÆN‡s€õ~ýÌ·Ÿ¦ú¨+ ÀÐÈ£ØyñŽVs°ôdlç!µÍ):V±‘OYåQüƒ?Ë, ’‰­½ÉTl5!ê†#&åuF±¯›VàoñÍ¥šÔ m»ø\\¢Ø?±MsƳµXäeÇ, ŽíwDg›ïÇ8} V³hÇB¡´ÎÙÚñŸSÑg“âKaÍ¿ö½lñRÞ0ºfæñ7èjeþ0HЄñÚº‘85Ø< S“`;0ü}™Ïv¶ÌAj5Î%ùŽöÝDÑ’K±}vd¤Ý0kàï‡!ÙÛ‘éa„Ò-‚Â$Ñqûˆˆ0ctÅlúÔ©\TTýÓ˜’ójÇš>2Óº¸ï”²5],®ŽXî_ÜWgÐ]9ùÍ- Ó5#ø¾<¨—¸P5Ä&Š¥vgnunet-0.9.3/src/integration-tests/hostkeys/0003-hostkey0000644000175000017500000000162211671106247020066 00000000000000’€€ô ÆZ¸Õ¹ò1=ÂB¬×ØÌò[Нɻ´ð¾Tˆ„º$ìmFg{ ÄW Q-ŸÐ…“ÏIµRæO:Zµä6LCõY¾Òlùà,øW½1¨nß»5öøù7†ó4Éݯ'¤v^h…\Ëb0»Låù0–A…þêŒGÖWÞ(¥Ó8Êô:D¸ëXIÖkGD‹ÏÕ/†÷moI%UÿÝz}ÿýFæûô¦¿B>¦Å¿BDÊþò‡Ùª2€õU¦ÏxdÂγÿM>×õܶ& e%Mú::C+i½¯a^&(µä·)‰È{,Äb}äýËA=HKdÊâïÕÛŒã<ç9Ci—m]5œí?{FŠQ;{^FZ+þ¢\®\º©2Å–¬#~V£†Y¹½pb¿Õ„²¶¸d¡ˆËŠõ.réßoh›PÂJÁËë¼!ï¦Æ<>32¼íºÐ~èYOÊjÜ Ô{¨ZõKK\Wðt%_µ•ÿÉé–vÚ(â¬Î ™q€—!Ü©ÏÛ=·2bT§q¢„7Øû‡ö]'^ Ì€a½ß^â1ŽÜß+oê-*@¾¡W Ùß='!õ9ÿoÐŽ•†rð[üp\e­•[&²[½Kû°¦á´hýóÀŠ q Ùq!?áà¶‚ÛQ²‡!ÓµÔÕߪS/«êMû˜{'ùþN”Û÷²xÎ2ø |+Ôøç­:$ö2ʈhÚu£&þ§6FçHœ'3ÿ×\Ù1ñ5öÚ™Ekò;EÝ.?.ÅQ”Jß,?ê±Yºr‹78Ûðís¥Ù£1›g¿ØìŸj÷—1ÎRŸºÐc¾Åre)²ä´Ý;08wDóÁÛõ­··e¬™Sí]ÀˆŽ|õõÌÙÂüQr©z]‹¸SƒT®ZÝÓÞº¿v«üþ¢¨ôÖ€õgLmëÏ”Ükß½)£Åß„r›EhâνÛ^éÙÈÀ±€”›(2®Þ'œvtÎÂ?¿@}º^ Ž?,ŠiPò“ÛõÙ˜„ޏæîÿÝÇW8ÌG]Õt¾ò$G_¯—\{~wXsoعÕ§lÖIKœgªÝ¢Ñ“tñí1o¹ìh;:¦Ù#'9<6g"O†Í!„h;öp-i©¶LÙ›=×ü¡h ºâœÿ sGäúà§l`K—¶IêÌEË)ÝWŒ10¿…Âgnunet-0.9.3/src/integration-tests/hostkeys/0007-hostkey0000644000175000017500000000162211671106247020072 00000000000000’€€èð'ÎÞÊÿ†üíA¬½Ô‘%<ý•më¤ÿY§$Ii CÚ{'­ÎÄÈp–ä)‡ëü@qÙ2·Û{8JãÏâ~G}RöÓð‚ZñæÙƒUy‚Ü'}ƒk]†Êøä""`#è`ž°œ?Í£o€ÿ™“xæÌVJ˨>Ú¶Š_Sþ¥{­üa|ÙgªBAªòO}6ìÎV°Bigˆæ„(ýÝ<í §¦wSmxzز„¨®lZ~86Dø€ŽÒ4¥S ëKŽJkM*1+Å[µPõ奡ì¹dPF~²w| n.C;Åž2{Ú¨¤ÚÝqI´`Ó¬ ØÈA'"?‘w¡vf¶S)VIX«­7ÇoEϦ“°øç’4M®&lëù“tŽ@Ók,Púæ$iLÚUV<õá!lêTjG…?äÉ _¼b’âë­‘‹Áâöö›ÐûƒxãŸ?éw52±’H ܇Ôô×DÙ%ˆÙè©N@ÿgÆòÛ]UøÊ|%l;ú› f_õûã^F|Š 9±T/ˆº¦æwšØM1f¥ÝõÐ>³UƒIJÖc94ï˜[«Œ5)=jëÎÂcŠ2 t”ÈRdÿPñØ„aL&^Ë-Ê,^ƒJõºñH‚¡WMf¹(«-½mC]Œ®‘÷È4—d²‹C²º?q {i‡ ¼á:Ò¿¢ÝÊóŸ°ÿ GHŸ×$Lðê= ‚;!uá;͎ߘeÃÁ#ç@¨Bñ–ÂÝ6h«5>4%›W‹ª%*5–íÔ ß'§%;Gÿ–M/À,,Ìn€‚Ì C­µª—§KQð©ê߈ c‚·¸Ò-f¦üÓ*5SA +Ÿeí]1E4T‰Ü¬~Ànâlz­+@É ‡L,Á„yjuXœ3œý@G‘ÎmZ1CíàmôЮë³×“ â°j‘ëE§÷l®ë8ƒ]%·@OR–)<´Ó•ê"2–»»d£šµI™ã¶÷±žIäyΈ z '_I“ðàmzÇÞ(+É~´WҜꀭãbå’èîÐìûC¬k§àð —ìy޾²ç`[7§/¨Úç³91NJ?öWSr–9'ž~뺉Õ˜&k©í±Vf`GRý™e'‚ƒ^•úÂ|Bûh ÚL&~gnunet-0.9.3/src/integration-tests/test_integration_connect_on_restart.py.in0000755000175000017500000001275111760502552024544 00000000000000#!@PYTHON@ # This file is part of GNUnet. # (C) 2010 Christian Grothoff (and other contributing authors) # # GNUnet is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2, or (at your # option) any later version. # # GNUnet is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNUnet; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # # # This test starts 3 peers and expects bootstrap and a connected clique # After a successful clique it shuts down all peers and starts the non-bootstrap # peers, expecting them to reconnect # # Conditions for successful exit: # Both peers have 1 connected peer in transport, core, topology, fs import sys import os import subprocess import re import shutil import time import pexpect from gnunet_testing import Peer from gnunet_testing import Test from gnunet_testing import Check from gnunet_testing import Condition from gnunet_testing import * #definitions testname = "test_integration_clique" verbose = True check_timeout = 180 def cleanup (): if os.name == "nt": shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_bootstrap_server"), True) shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_no_nat_client"), True) shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_no_nat_client_2"), True) else: shutil.rmtree ("/tmp/c_bootstrap_server/", True) shutil.rmtree ("/tmp/c_no_nat_client/", True) shutil.rmtree ("/tmp/c_no_nat_client_2/", True) def success_cont (check): global success success = True; check.evaluate(True) def fail_cont (check): global success success = False; check.evaluate(False) def success_connect_cont (check): check.evaluate(True) print "Connected clique, shutdown" server.stop () client.stop () client2.stop () time.sleep (3) client.start () client2.start () check = Check (test) check.add (StatisticsCondition (client, 'transport', '# peers connected',1)) check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',1)) check.add (StatisticsCondition (client, 'core', '# peers connected',1)) check.add (StatisticsCondition (client, 'topology', '# peers connected',1)) check.add (StatisticsCondition (client, 'fs', '# peers connected',1)) check.add (StatisticsCondition (client2, 'transport', '# peers connected',1)) check.add (StatisticsCondition (client2, 'core', '# neighbour entries allocated',1)) check.add (StatisticsCondition (client2, 'core', '# peers connected',1)) check.add (StatisticsCondition (client2, 'topology', '# peers connected',1)) check.add (StatisticsCondition (client2, 'fs', '# peers connected',1)) check.run_blocking (check_timeout, success_cont, fail_cont) def fail_connect_cont (check): global success print "Failed to connect clique, shutdown" success = False; check.evaluate(False) def check_connect (): check = Check (test) check.add (StatisticsCondition (client, 'transport', '# peers connected',2)) check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',2)) check.add (StatisticsCondition (client, 'core', '# peers connected',2)) check.add (StatisticsCondition (client, 'topology', '# peers connected',2)) check.add (StatisticsCondition (client, 'fs', '# peers connected',2)) check.add (StatisticsCondition (client2, 'transport', '# peers connected',2)) check.add (StatisticsCondition (client2, 'core', '# neighbour entries allocated',2)) check.add (StatisticsCondition (client2, 'core', '# peers connected',2)) check.add (StatisticsCondition (client2, 'topology', '# peers connected',2)) check.add (StatisticsCondition (client2, 'fs', '# peers connected',2)) check.add (StatisticsCondition (server, 'transport', '# peers connected',2)) check.add (StatisticsCondition (server, 'core', '# neighbour entries allocated',2)) check.add (StatisticsCondition (server, 'core', '# peers connected',2)) check.add (StatisticsCondition (server, 'topology', '# peers connected',2)) check.add (StatisticsCondition (server, 'fs', '# peers connected',2)) check.run_blocking (check_timeout, success_connect_cont, fail_connect_cont) # # Test execution # def run (): global success global test global server global client global client2 success = False test = Test ('test_integration_disconnect', verbose) server = Peer(test, './confs/c_bootstrap_server.conf'); server.start(); client = Peer(test, './confs/c_no_nat_client.conf'); client.start(); client2 = Peer(test, './confs/c_no_nat_client_2.conf'); client2.start(); if ((client.started == True) and (client2.started == True) and (server.started == True)): test.p ('Peers started, running check') check_connect () server.stop () client.stop () client2.stop () cleanup () if (success == False): print ('Test failed') return False else: return True try: run () except (KeyboardInterrupt, SystemExit): print 'Test interrupted' server.stop () client.stop () client2.stop () cleanup () if (success == False): sys.exit(1) else: sys.exit(0) gnunet-0.9.3/src/integration-tests/test_integration_connection_values_tcp_udp.py.in0000755000175000017500000000622611760502552026107 00000000000000#!@PYTHON@ # This file is part of GNUnet. # (C) 2010 Christian Grothoff (and other contributing authors) # # GNUnet is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2, or (at your # option) any later version. # # GNUnet is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNUnet; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # # # This test starts 3 peers and expects bootstrap and a connected clique # # Conditions for successful exit: # Both peers have 1 connected peer in transport, core, topology, fs import sys import os import subprocess import re import shutil import time import pexpect from gnunet_testing import Peer from gnunet_testing import Test from gnunet_testing import Check from gnunet_testing import Condition from gnunet_testing import * #definitions testname = "test_integration_connection_value" verbose = True check_timeout = 180 def cleanup (): if os.name == "nt": shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_normal_client"), True) else: shutil.rmtree ("/tmp/c_normal_client/", True) def success_cont (check): global success success = True; def fail_cont (check): global success success= False; check.evaluate(True) def check_connect (): check = Check (test) check.add (EqualStatisticsCondition (client, 'transport', '# peers connected', client, 'core', '# neighbour entries allocated')) check.add (EqualStatisticsCondition (client, 'transport', '# peers connected', client, 'core', '# peers connected')) check.add (EqualStatisticsCondition (client, 'core', '# neighbour entries allocated', client, 'core', '# peers connected')) check.add (EqualStatisticsCondition (client, 'transport', '# peers connected', client, 'topology', '# peers connected')) check.add (EqualStatisticsCondition (client, 'topology', '# peers connected', client, 'core', '# peers connected')) while True: check.reset() res = check.run_once (None, None) print "Values are equal" check.evaluate (False) #if (False == res): # break time.sleep (5) # # Test execution # def run (): global success global test global client success = False test = Test ('test_integration_connection_value', verbose) client = Peer(test, './confs/c_normal_client_tcp_udp.conf'); client.start(); if (client.started == True): test.p ('Peers started, running check') check_connect () client.stop () cleanup () if (success == False): print ('Test failed') return False else: return True try: run () except (KeyboardInterrupt, SystemExit): print 'Test interrupted' client.stop () cleanup () if (success == False): sys.exit(1) else: sys.exit(0) gnunet-0.9.3/src/integration-tests/test_integration_disconnect.py.in0000755000175000017500000001057411760502552023005 00000000000000#!@PYTHON@ # This file is part of GNUnet. # (C) 2010 Christian Grothoff (and other contributing authors) # # GNUnet is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2, or (at your # option) any later version. # # GNUnet is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNUnet; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # import sys import os import subprocess import re import shutil import time import pexpect from gnunet_testing import Peer from gnunet_testing import Test from gnunet_testing import Check from gnunet_testing import Condition from gnunet_testing import * # # This test tests if a fresh peer bootstraps from a hostlist server and then # successfully connects to the server. When both peers are connected # in transport, core, topology, fs, the server is shutdown # # Conditions for successful exit: # Both peers have 0 connected peer in transport, core, topology, fs #definitions testname = "test_integration_disconnect" verbose = True check_timeout = 180 def cleanup (): if os.name == "nt": shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_bootstrap_server"), True) shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_no_nat_client"), True) else: shutil.rmtree ("/tmp/c_bootstrap_server/", True) shutil.rmtree ("/tmp/c_no_nat_client/", True) def success_disconnect_cont (check): global success success = True; def fail_disconnect_cont (check): global success success = False; check.evaluate(True) def check_disconnect (): test.p ('Shutting down bootstrap server') server.stop () check = Check (test) check.add (StatisticsCondition (client, 'transport', '# peers connected',0)) check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',0)) check.add (StatisticsCondition (client, 'core', '# peers connected',0)) check.add (StatisticsCondition (client, 'topology', '# peers connected',0)) check.add (StatisticsCondition (client, 'fs', '# peers connected',0)) check.run_blocking (check_timeout, success_disconnect_cont, fail_disconnect_cont) def success_connect_cont (check): check_disconnect () def fail_connect_cont (check): global success success= False; check.evaluate(True) def check_connect (): check = Check (test) check.add (StatisticsCondition (client, 'transport', '# peers connected',1)) check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',1)) check.add (StatisticsCondition (client, 'core', '# peers connected',1)) check.add (StatisticsCondition (client, 'topology', '# peers connected',1)) check.add (StatisticsCondition (client, 'fs', '# peers connected',1)) check.add (StatisticsCondition (server, 'transport', '# peers connected',1)) check.add (StatisticsCondition (server, 'core', '# neighbour entries allocated',1)) check.add (StatisticsCondition (server, 'core', '# peers connected',1)) check.add (StatisticsCondition (server, 'topology', '# peers connected',1)) check.add (StatisticsCondition (server, 'fs', '# peers connected',1)) check.run_blocking (check_timeout, success_connect_cont, fail_connect_cont) # # Test execution # def run (): global success global test global server global client success = False test = Test ('test_integration_disconnect', verbose) server = Peer(test, './confs/c_bootstrap_server.conf'); server.start(); client = Peer(test, './confs/c_no_nat_client.conf'); client.start(); if ((client.started == True) and (server.started == True)): test.p ('Peers started, running check') check_connect () server.stop () client.stop () cleanup () if (success == False): print ('Test failed') return True else: return False try: run () except (KeyboardInterrupt, SystemExit): print 'Test interrupted' server.stop () client.stop () cleanup () if (success == False): sys.exit(1) else: sys.exit(0) gnunet-0.9.3/src/integration-tests/test_integration_clique.py.in0000755000175000017500000001413711760502552022135 00000000000000#!@PYTHON@ # This file is part of GNUnet. # (C) 2010 Christian Grothoff (and other contributing authors) # # GNUnet is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2, or (at your # option) any later version. # # GNUnet is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNUnet; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # # # This test starts 3 peers and expects bootstrap and a connected clique # # Conditions for successful exit: # Both peers have 1 connected peer in transport, core, topology, fs import sys import os import subprocess import re import shutil import time import pexpect from gnunet_testing import Peer from gnunet_testing import Test from gnunet_testing import Check from gnunet_testing import Condition from gnunet_testing import * #definitions testname = "test_integration_clique" verbose = True check_timeout = 180 def cleanup (): if os.name == "nt": shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-ns"), True) shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_no_nat_client"), True) shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_no_nat_client_2"), True) else: shutil.rmtree ("/tmp/c_bootstrap_server/", True) shutil.rmtree ("/tmp/c_no_nat_client/", True) shutil.rmtree ("/tmp/c_no_nat_client_2/", True) def success_cont (check): global success success = True; def fail_cont (check): global success success= False; check.evaluate(True) def check_disconnect_client (): test.p ('Shutting down bootstrap client') client.stop () check = Check (test) check.add (StatisticsCondition (client2, 'transport', '# peers connected',0)) check.add (StatisticsCondition (client2, 'core', '# neighbour entries allocated',0)) check.add (StatisticsCondition (client2, 'core', '# peers connected',0)) check.add (StatisticsCondition (client2, 'topology', '# peers connected',0)) check.add (StatisticsCondition (client2, 'fs', '# peers connected',0)) check.run_blocking (check_timeout, success_cont, fail_cont) def success_disconnect_server_cont (check): check_disconnect_client () def fail_disconnect_server_cont (check): global success success= False; check.evaluate(True) def check_disconnect_server (): test.p ('Shutting down bootstrap server') server.stop () check = Check (test) check.add (StatisticsCondition (client, 'transport', '# peers connected',1)) check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',1)) check.add (StatisticsCondition (client, 'core', '# peers connected',1)) check.add (StatisticsCondition (client, 'topology', '# peers connected',1)) check.add (StatisticsCondition (client, 'fs', '# peers connected',1)) check.add (StatisticsCondition (client2, 'transport', '# peers connected',1)) check.add (StatisticsCondition (client2, 'core', '# neighbour entries allocated',1)) check.add (StatisticsCondition (client2, 'core', '# peers connected',1)) check.add (StatisticsCondition (client2, 'topology', '# peers connected',1)) check.add (StatisticsCondition (client2, 'fs', '# peers connected',1)) check.run_blocking (check_timeout, success_disconnect_server_cont, fail_disconnect_server_cont) def success_connect_cont (check): check_disconnect_server () def fail_connect_cont (check): global success success= False; check.evaluate(True) def check_connect (): check = Check (test) check.add (StatisticsCondition (client, 'transport', '# peers connected',2)) check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',2)) check.add (StatisticsCondition (client, 'core', '# peers connected',2)) check.add (StatisticsCondition (client, 'topology', '# peers connected',2)) check.add (StatisticsCondition (client, 'fs', '# peers connected',2)) check.add (StatisticsCondition (client2, 'transport', '# peers connected',2)) check.add (StatisticsCondition (client2, 'core', '# neighbour entries allocated',2)) check.add (StatisticsCondition (client2, 'core', '# peers connected',2)) check.add (StatisticsCondition (client2, 'topology', '# peers connected',2)) check.add (StatisticsCondition (client2, 'fs', '# peers connected',2)) check.add (StatisticsCondition (server, 'transport', '# peers connected',2)) check.add (StatisticsCondition (server, 'core', '# neighbour entries allocated',2)) check.add (StatisticsCondition (server, 'core', '# peers connected',2)) check.add (StatisticsCondition (server, 'topology', '# peers connected',2)) check.add (StatisticsCondition (server, 'fs', '# peers connected',2)) check.run_blocking (check_timeout, success_connect_cont, fail_connect_cont) # # Test execution # def run (): global success global test global server global client global client2 success = False test = Test ('test_integration_disconnect', verbose) server = Peer(test, './confs/c_bootstrap_server.conf'); server.start(); client = Peer(test, './confs/c_no_nat_client.conf'); client.start(); client2 = Peer(test, './confs/c_no_nat_client_2.conf'); client2.start(); if ((client.started == True) and (client2.started == True) and (server.started == True)): test.p ('Peers started, running check') check_connect () server.stop () client.stop () client2.stop () cleanup () if (success == False): print ('Test failed') return False else: return True try: run () except (KeyboardInterrupt, SystemExit): print 'Test interrupted' server.stop () client.stop () client2.stop () cleanup () if (success == False): sys.exit(1) else: sys.exit(0) gnunet-0.9.3/src/integration-tests/test_connection_stability.c0000644000175000017500000000611311761753146021660 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file integretion-tests/test_connection_stability.c * @brief testcase for connection stability */ #include "platform.h" #include "gnunet_testing_lib.h" #define VERBOSE GNUNET_YES #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) static int ok; static void end_cb (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Ending with error: %s\n", emsg); ok = 1; } else { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon terminated, will now exit.\n"); #endif ok = 0; } } void do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TESTING_Daemon *d = cls; GNUNET_TESTING_daemon_stop (d, TIMEOUT, &end_cb, NULL, GNUNET_YES, GNUNET_NO); } static void my_cb (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { GNUNET_assert (id != NULL); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon `%s' started, will now stop it.\n", GNUNET_i2s (id)); #endif GNUNET_SCHEDULER_add_now (&do_shutdown, d); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_TESTING_Daemon *d; ok = 1; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemon.\n"); #endif d = GNUNET_TESTING_daemon_start (cfg, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, NULL, NULL, &my_cb, NULL); GNUNET_assert (d != NULL); } static int check () { char *const argv[] = { "test_connection_stability", "-c", "test_connection_stability.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-testing", "nohelp", options, &run, &ok); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test_connection_stability", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); return ret; } /* end of test_connection_stability.c */ gnunet-0.9.3/src/integration-tests/confs/0000755000175000017500000000000011763406751015420 500000000000000gnunet-0.9.3/src/integration-tests/confs/c_no_nat_client.conf0000644000175000017500000001562711760501626021332 00000000000000[PATHS] SERVICEHOME = /tmp/c_no_nat_client/ DEFAULTCONFIG = confs/c_no_nat_client.conf [gnunetd] #HOSTKEY = $SERVICEHOME/.hostkey HOSTKEY = hostkeys/0001-hostkey [gns] AUTOSTART = NO [namestore] AUTOSTART = NO [vpn] AUTOSTART = YES PORT = 0 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dns ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-vpn-29 [resolver] AUTOSTART = YES PORT = 20035 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-resolver ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-resolver-28 UNIX_MATCH_UID = NO UNIX_MATCH_GID = NO [mesh] AUTOSTART = YES PORT = 20034 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-mesh ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-mesh-27 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [nse] AUTOSTART = YES PORT = 20033 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-nse ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-nse-26 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PROOFFILE = $SERVICEHOME/.nse-proof HISTOGRAM = $SERVICEHOME/nse-history.log WORKDELAY = 5 ms INTERVAL = 1 h WORKBITS = 26 [topology] MINIMUM-FRIENDS = 0 FRIENDS-ONLY = NO AUTOCONNECT = YES TARGET-CONNECTION-COUNT = 16 FRIENDS = $SERVICEHOME/friends CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-topology [datastore] AUTOSTART = YES UNIXPATH = /tmp/test-service-datastore-25 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PORT = 20032 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-datastore ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; QUOTA = 100 MB BLOOMFILTER = $SERVICEHOME/fs/bloomfilter DATABASE = sqlite [datastore-sqlite] FILENAME = $SERVICEHOME/datastore/sqlite.db [datastore-postgres] CONFIG = connect_timeout=10; dbname=gnunet [datastore-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf [peerinfo] AUTOSTART = YES PORT = 20031 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-peerinfo ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-peerinfo-24 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES HOSTS = $SERVICEHOME/data/hosts/ [client] HOME = $SERVICEHOME [TESTING] WEAKRANDOM = NO CONNECT_TIMEOUT = 30 s CONNECT_ATTEMPTS = 3 MAX_OUTSTANDING_CONNECTIONS = 50 DELETE_FILES = YES [ats] AUTOSTART = YES PORT = 20030 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-ats ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-ats-23 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES WAN_QUOTA_IN = 65536 WAN_QUOTA_OUT = 65536 DUMP_MLP = NO DUMP_SOLUTION = NO DUMP_OVERWRITE = NO DUMP_MIN_PEERS = 0 DUMP_MIN_ADDRS = 0 ATS_MIN_INTERVAL = 15000 ATS_EXEC_INTERVAL = 30000 [transport] #DEBUG = YES AUTOSTART = YES PORT = 20029 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-transport NEIGHBOUR_LIMIT = 50 ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; PLUGINS = tcp UNIXPATH = /tmp/test-service-transport-22 BLACKLIST_FILE = $SERVICEHOME/blacklist UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [transport-tcp] USE_LOCALADDR = YES PORT = 20028 ADVERTISED_PORT = 20028 MAX_CONNECTIONS = 128 TIMEOUT = 5 s [transport-udp] USE_LOCALADDR = YES PORT = 20027 BROADCAST = YES BROADCAST_INTERVAL = 30000 MAX_BPS = 1000000 [transport-http] PORT = 20026 MAX_CONNECTIONS = 128 [transport-https] PORT = 20025 CRYPTO_INIT = NORMAL KEY_FILE = https.key CERT_FILE = https.cert MAX_CONNECTIONS = 128 [transport-wlan] INTERFACE = mon0 TESTMODE = 0 [datacache-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf [datacache-postgres] CONFIG = connect_timeout=10; dbname=gnunet [template] AUTOSTART = NO PORT = 20024 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-template ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-template-21 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [fs] AUTOSTART = YES INDEXDB = $SERVICEHOME/idxinfo.lst TRUST = $SERVICEHOME/data/credit/ IDENTITY_DIR = $SERVICEHOME/identities/ STATE_DIR = $SERVICEHOME/persistence/ UPDATE_DIR = $SERVICEHOME/updates/ PORT = 20023 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-fs ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DELAY = YES CONTENT_CACHING = YES CONTENT_PUSHING = YES UNIXPATH = /tmp/test-service-fs-20 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES MAX_PENDING_REQUESTS = 65536 MIN_MIGRATION_DELAY = 100 ms EXPECTED_NEIGHBOUR_COUNT = 128 [vpn] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-vpn IPV6ADDR = 1234::1 IPV6PREFIX = 32 IPV4ADDR = 10.11.10.1 IPV4MASK = 255.255.0.0 VIRTDNS = 10.11.10.2 VIRTDNS6 = 1234::17 IFNAME = vpn-gnunet [exit] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-exit IPV6ADDR = 1234:1::1 IPV6PREFIX = 32 IPV4ADDR = 10.10.1.1 IPV4MASK = 255.255.0.0 IFNAME = exit-gnunet ENABLE_UDP = NO ENABLE_TCP = NO [dns] AUTOSTART = YES PORT = 0 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dns ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-dns-19 PROVIDE_EXIT = NO [arm] PORT = 20022 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-arm ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DEFAULTSERVICES = topology hostlist fs UNIXPATH = /tmp/test-service-arm-18 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [hostlist] HTTPPORT = 8080 HOME = $SERVICEHOME HOSTLISTFILE = $SERVICEHOME/hostlist/learned.data CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-hostlist OPTIONS = -b SERVERS = http://localhost:8080/ HTTP-PROXY = [core] AUTOSTART = YES PORT = 20021 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-core ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-core-17 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [nat] EXTERNAL_ADDRESS = 127.0.0.1 INTERNAL_ADDRESS = 127.0.0.1 BINDTO = 127.0.0.1 BEHIND_NAT = NO PUNCHED_NAT = NO ENABLE_UPNP = NO USE_LOCALADDR = YES USE_HOSTNAME = NO ENABLE_ICMP_CLIENT = NO ENABLE_ICMP_SERVER = NO DISABLEV6 = YES RETURN_LOCAL_ADDRESSES = NO HOSTNAME_DNS_FREQUENCY = 1200000 IFC_SCAN_FREQUENCY = 3000000 DYNDNS_FREQUENCY = 140000 [gnunet-nat-server] HOSTNAME = gnunet.org PORT = 20020 [statistics] AUTOSTART = YES PORT = 20019 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-statistics ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-statistics-16 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES [dht] AUTOSTART = YES PORT = 20018 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dht ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; BUCKET_SIZE = 4 UNIXPATH = /tmp/test-service-dht-15 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [dhtcache] DATABASE = sqlite QUOTA = 1 MB [lockmanager] AUTOSTART = NO gnunet-0.9.3/src/integration-tests/confs/c_bootstrap_server.conf0000644000175000017500000001561511760501567022122 00000000000000[PATHS] SERVICEHOME = /tmp/c_bootstrap_server/ DEFAULTCONFIG = confs/c_bootstrap_server.conf [gnunetd] #HOSTKEY = $SERVICEHOME/.hostkey HOSTKEY = hostkeys/0000-hostkey [vpn] AUTOSTART = YES PORT = 0 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dns ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-vpn-15 [resolver] AUTOSTART = YES PORT = 20017 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-resolver ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-resolver-14 UNIX_MATCH_UID = NO UNIX_MATCH_GID = NO [mesh] AUTOSTART = YES PORT = 20016 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-mesh ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-mesh-13 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [nse] AUTOSTART = YES PORT = 20015 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-nse ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-nse-12 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PROOFFILE = $SERVICEHOME/.nse-proof HISTOGRAM = $SERVICEHOME/nse-history.log WORKDELAY = 5 ms INTERVAL = 1 h WORKBITS = 26 [topology] MINIMUM-FRIENDS = 0 FRIENDS-ONLY = NO AUTOCONNECT = YES TARGET-CONNECTION-COUNT = 16 FRIENDS = $SERVICEHOME/friends CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-topology [datastore] AUTOSTART = YES UNIXPATH = /tmp/test-service-datastore-11 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PORT = 20014 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-datastore ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; QUOTA = 100 MB BLOOMFILTER = $SERVICEHOME/fs/bloomfilter DATABASE = sqlite [datastore-sqlite] FILENAME = $SERVICEHOME/datastore/sqlite.db [datastore-postgres] CONFIG = connect_timeout=10; dbname=gnunet [datastore-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf [peerinfo] AUTOSTART = YES PORT = 20013 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-peerinfo ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-peerinfo-10 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES HOSTS = $SERVICEHOME/data/hosts/ [client] HOME = $SERVICEHOME [TESTING] WEAKRANDOM = YES CONNECT_TIMEOUT = 30 s CONNECT_ATTEMPTS = 3 MAX_OUTSTANDING_CONNECTIONS = 50 DELETE_FILES = YES [ats] AUTOSTART = YES PORT = 20012 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-ats ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-ats-9 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES WAN_QUOTA_IN = 65536 WAN_QUOTA_OUT = 65536 DUMP_MLP = NO DUMP_SOLUTION = NO DUMP_OVERWRITE = NO DUMP_MIN_PEERS = 0 DUMP_MIN_ADDRS = 0 ATS_MIN_INTERVAL = 15000 ATS_EXEC_INTERVAL = 30000 [transport] AUTOSTART = YES PORT = 20011 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-transport NEIGHBOUR_LIMIT = 50 ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; PLUGINS = tcp UNIXPATH = /tmp/test-service-transport-8 BLACKLIST_FILE = $SERVICEHOME/blacklist UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [transport-tcp] USE_LOCALADDR = YES PORT = 20010 ADVERTISED_PORT = 20010 MAX_CONNECTIONS = 128 TIMEOUT = 5 s [transport-udp] USE_LOCALADDR = YES PORT = 20009 BROADCAST = YES BROADCAST_INTERVAL = 30000 MAX_BPS = 1000000 [transport-http] PORT = 20008 MAX_CONNECTIONS = 128 [transport-https] PORT = 20007 CRYPTO_INIT = NORMAL KEY_FILE = https.key CERT_FILE = https.cert MAX_CONNECTIONS = 128 [transport-wlan] INTERFACE = mon0 TESTMODE = 0 [datacache-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf [datacache-postgres] CONFIG = connect_timeout=10; dbname=gnunet [template] AUTOSTART = NO PORT = 20006 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-template ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-template-7 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [fs] AUTOSTART = YES INDEXDB = $SERVICEHOME/idxinfo.lst TRUST = $SERVICEHOME/data/credit/ IDENTITY_DIR = $SERVICEHOME/identities/ STATE_DIR = $SERVICEHOME/persistence/ UPDATE_DIR = $SERVICEHOME/updates/ PORT = 20005 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-fs ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DELAY = YES CONTENT_CACHING = YES CONTENT_PUSHING = YES UNIXPATH = /tmp/test-service-fs-6 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES MAX_PENDING_REQUESTS = 65536 MIN_MIGRATION_DELAY = 100 ms EXPECTED_NEIGHBOUR_COUNT = 128 [vpn] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-vpn IPV6ADDR = 1234::1 IPV6PREFIX = 32 IPV4ADDR = 10.11.10.1 IPV4MASK = 255.255.0.0 VIRTDNS = 10.11.10.2 VIRTDNS6 = 1234::17 IFNAME = vpn-gnunet [exit] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-exit IPV6ADDR = 1234:1::1 IPV6PREFIX = 32 IPV4ADDR = 10.10.1.1 IPV4MASK = 255.255.0.0 IFNAME = exit-gnunet ENABLE_UDP = NO ENABLE_TCP = NO [dns] AUTOSTART = YES PORT = 0 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dns ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-dns-5 PROVIDE_EXIT = NO [arm] PORT = 20004 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-arm ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DEFAULTSERVICES = topology hostlist fs UNIXPATH = /tmp/test-service-arm-4 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [hostlist] HTTPPORT = 8080 HOME = $SERVICEHOME HOSTLISTFILE = $SERVICEHOME/hostlist/learned.data CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-hostlist OPTIONS = -p #SERVERS = http://v9.gnunet.org:58080/ HTTP-PROXY = [core] AUTOSTART = YES PORT = 20003 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-core ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-core-3 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [nat] EXTERNAL_ADDRESS = 127.0.0.1 INTERNAL_ADDRESS = 127.0.0.1 BINDTO = 127.0.0.1 BEHIND_NAT = NO PUNCHED_NAT = NO ENABLE_UPNP = NO USE_LOCALADDR = YES USE_HOSTNAME = NO ENABLE_ICMP_CLIENT = NO ENABLE_ICMP_SERVER = NO DISABLEV6 = YES RETURN_LOCAL_ADDRESSES = NO HOSTNAME_DNS_FREQUENCY = 1200000 IFC_SCAN_FREQUENCY = 3000000 DYNDNS_FREQUENCY = 140000 [gnunet-nat-server] HOSTNAME = gnunet.org PORT = 20002 [statistics] AUTOSTART = YES PORT = 20001 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-statistics ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-statistics-2 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES [dht] AUTOSTART = YES PORT = 20000 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dht ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; BUCKET_SIZE = 4 UNIXPATH = /tmp/test-service-dht-1 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [dhtcache] DATABASE = sqlite QUOTA = 1 MB [gns] AUTOSTART = NO [namestore] AUTOSTART = NO [lockmanager] AUTOSTART = NOgnunet-0.9.3/src/integration-tests/confs/c_no_nat_client_2.conf0000644000175000017500000001524211753027570021547 00000000000000[PATHS] SERVICEHOME = /tmp/c_no_nat_client_2/ DEFAULTCONFIG = confs/c_no_nat_client_2.conf [gnunetd] #HOSTKEY = $SERVICEHOME/.hostkey HOSTKEY = hostkeys/0002-hostkey [resolver] AUTOSTART = YES PORT = 20053 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-resolver ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-resolver-42 UNIX_MATCH_UID = NO UNIX_MATCH_GID = NO [mesh] AUTOSTART = YES PORT = 20052 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-mesh ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-mesh-41 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [nse] AUTOSTART = YES PORT = 20051 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-nse ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-nse-40 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PROOFFILE = $SERVICEHOME/.nse-proof HISTOGRAM = $SERVICEHOME/nse-history.log WORKDELAY = 5 ms INTERVAL = 1 h WORKBITS = 26 [topology] MINIMUM-FRIENDS = 0 FRIENDS-ONLY = NO AUTOCONNECT = YES TARGET-CONNECTION-COUNT = 16 FRIENDS = $SERVICEHOME/friends CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-topology [datastore] AUTOSTART = YES UNIXPATH = /tmp/test-service-datastore-39 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PORT = 20050 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-datastore ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; QUOTA = 100 MB BLOOMFILTER = $SERVICEHOME/fs/bloomfilter DATABASE = sqlite [datastore-sqlite] FILENAME = $SERVICEHOME/datastore/sqlite.db [datastore-postgres] CONFIG = connect_timeout=10; dbname=gnunet [datastore-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf [peerinfo] AUTOSTART = YES PORT = 20049 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-peerinfo ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-peerinfo-38 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES HOSTS = $SERVICEHOME/data/hosts/ [client] HOME = $SERVICEHOME [TESTING] WEAKRANDOM = NO CONNECT_TIMEOUT = 30 s CONNECT_ATTEMPTS = 3 MAX_OUTSTANDING_CONNECTIONS = 50 DELETE_FILES = YES [ats] AUTOSTART = YES PORT = 20048 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-ats ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-ats-37 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES WAN_QUOTA_IN = 65536 WAN_QUOTA_OUT = 65536 DUMP_MLP = NO DUMP_SOLUTION = NO DUMP_OVERWRITE = NO DUMP_MIN_PEERS = 0 DUMP_MIN_ADDRS = 0 ATS_MIN_INTERVAL = 15000 ATS_EXEC_INTERVAL = 30000 [transport] AUTOSTART = YES PORT = 20047 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-transport NEIGHBOUR_LIMIT = 50 ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; PLUGINS = tcp UNIXPATH = /tmp/test-service-transport-36 BLACKLIST_FILE = $SERVICEHOME/blacklist UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [transport-tcp] PORT = 20046 ADVERTISED_PORT = 20046 MAX_CONNECTIONS = 128 TIMEOUT = 5 s USE_LOCALADDR = YES [transport-udp] PORT = 20045 BROADCAST = YES BROADCAST_INTERVAL = 30000 MAX_BPS = 1000000 USE_LOCALADDR = YES [transport-http] PORT = 20044 MAX_CONNECTIONS = 128 [transport-https] PORT = 20043 CRYPTO_INIT = NORMAL KEY_FILE = https.key CERT_FILE = https.cert MAX_CONNECTIONS = 128 [transport-wlan] INTERFACE = mon0 TESTMODE = 0 [datacache-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf [datacache-postgres] CONFIG = connect_timeout=10; dbname=gnunet [template] AUTOSTART = NO PORT = 20042 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-template ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-template-35 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [fs] AUTOSTART = YES INDEXDB = $SERVICEHOME/idxinfo.lst TRUST = $SERVICEHOME/data/credit/ IDENTITY_DIR = $SERVICEHOME/identities/ STATE_DIR = $SERVICEHOME/persistence/ UPDATE_DIR = $SERVICEHOME/updates/ PORT = 20041 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-fs ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DELAY = YES CONTENT_CACHING = YES CONTENT_PUSHING = YES UNIXPATH = /tmp/test-service-fs-34 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES MAX_PENDING_REQUESTS = 65536 MIN_MIGRATION_DELAY = 100 ms EXPECTED_NEIGHBOUR_COUNT = 128 [vpn] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-vpn IPV6ADDR = 1234::1 IPV6PREFIX = 32 IPV4ADDR = 10.11.10.1 IPV4MASK = 255.255.0.0 VIRTDNS = 10.11.10.2 VIRTDNS6 = 1234::17 IFNAME = vpn-gnunet [exit] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-exit IPV6ADDR = 1234:1::1 IPV6PREFIX = 32 IPV4ADDR = 10.10.1.1 IPV4MASK = 255.255.0.0 IFNAME = exit-gnunet ENABLE_UDP = NO ENABLE_TCP = NO [dns] AUTOSTART = YES PORT = 0 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dns ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-dns-33 PROVIDE_EXIT = NO [arm] PORT = 20040 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-arm ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DEFAULTSERVICES = topology hostlist fs UNIXPATH = /tmp/test-service-arm-32 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [hostlist] HTTPPORT = 8080 HOME = $SERVICEHOME HOSTLISTFILE = $SERVICEHOME/hostlist/learned.data CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-hostlist OPTIONS = -b SERVERS = http://localhost:8080/ HTTP-PROXY = [core] AUTOSTART = YES PORT = 20039 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-core ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-core-31 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [nat] BEHIND_NAT = NO PUNCHED_NAT = NO ENABLE_UPNP = NO USE_LOCALADDR = YES USE_HOSTNAME = NO ENABLE_ICMP_CLIENT = NO ENABLE_ICMP_SERVER = NO DISABLEV6 = YES RETURN_LOCAL_ADDRESSES = NO HOSTNAME_DNS_FREQUENCY = 1200000 IFC_SCAN_FREQUENCY = 3000000 DYNDNS_FREQUENCY = 140000 EXTERNAL_ADDRESS = 127.0.0.1 INTERNAL_ADDRESS = 127.0.0.1 BINDTO = 127.0.0.1 [gnunet-nat-server] HOSTNAME = gnunet.org PORT = 20038 [statistics] AUTOSTART = YES PORT = 20037 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-statistics ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-statistics-30 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES [dht] AUTOSTART = YES PORT = 20036 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dht ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; BUCKET_SIZE = 4 UNIXPATH = /tmp/test-service-dht-29 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [dhtcache] DATABASE = sqlite QUOTA = 1 MB [gns] AUTOSTART = NO [namestore] AUTOSTART = NO gnunet-0.9.3/src/integration-tests/confs/c_normal_client_tcp.conf0000644000175000017500000001554711753027570022216 00000000000000[PATHS] SERVICEHOME = /tmp/c_normal_client DEFAULTCONFIG = confs/c_normal_client_tcp.conf [gnunetd] HOSTKEY = hostkeys/0002-hostkey [client] HOME = $SERVICEHOME [gns] AUTOSTART = NO [namestore] AUTOSTART = NO [vpn] AUTOSTART = YES PORT = 0 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dns ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-vpn-57 [resolver] AUTOSTART = YES PORT = 20071 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-resolver ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-resolver-56 UNIX_MATCH_UID = NO UNIX_MATCH_GID = NO [mesh] AUTOSTART = YES PORT = 20070 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-mesh ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-mesh-55 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [nse] AUTOSTART = YES PORT = 20069 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-nse ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-nse-54 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PROOFFILE = $SERVICEHOME/.nse-proof HISTOGRAM = $SERVICEHOME/nse-history.log WORKDELAY = 5 ms INTERVAL = 1 h WORKBITS = 26 [topology] MINIMUM-FRIENDS = 0 FRIENDS-ONLY = NO AUTOCONNECT = YES TARGET-CONNECTION-COUNT = 16 FRIENDS = $SERVICEHOME/friends CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-topology [datastore] AUTOSTART = YES UNIXPATH = /tmp/test-service-datastore-53 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PORT = 20068 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-datastore ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; QUOTA = 100 MB BLOOMFILTER = $SERVICEHOME/fs/bloomfilter DATABASE = sqlite [datastore-sqlite] FILENAME = $SERVICEHOME/datastore/sqlite.db [datastore-postgres] CONFIG = connect_timeout=10; dbname=gnunet [datastore-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf [peerinfo] AUTOSTART = YES PORT = 20067 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-peerinfo ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-peerinfo-52 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES HOSTS = $SERVICEHOME/data/hosts/ [TESTING] WEAKRANDOM = NO CONNECT_TIMEOUT = 30 s CONNECT_ATTEMPTS = 3 MAX_OUTSTANDING_CONNECTIONS = 50 DELETE_FILES = YES [ats] AUTOSTART = YES PORT = 20066 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-ats ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-ats-51 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES WAN_QUOTA_IN = 65536 WAN_QUOTA_OUT = 65536 DUMP_MLP = NO DUMP_SOLUTION = NO DUMP_OVERWRITE = NO DUMP_MIN_PEERS = 0 DUMP_MIN_ADDRS = 0 ATS_MIN_INTERVAL = 15000 ATS_EXEC_INTERVAL = 30000 [transport] AUTOSTART = YES PORT = 20065 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-transport NEIGHBOUR_LIMIT = 50 ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; PLUGINS = tcp UNIXPATH = /tmp/test-service-transport-50 BLACKLIST_FILE = $SERVICEHOME/blacklist UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [transport-tcp] PORT = 0 ADVERTISED_PORT = 20064 MAX_CONNECTIONS = 128 TIMEOUT = 5 s USE_LOCALADDR = YES [transport-udp] PORT = 0 BROADCAST = YES BROADCAST_INTERVAL = 30000 MAX_BPS = 1000000 USE_LOCALADDR = YES [transport-http] PORT = 0 MAX_CONNECTIONS = 128 [transport-https] PORT = 0 CRYPTO_INIT = NORMAL KEY_FILE = https.key CERT_FILE = https.cert MAX_CONNECTIONS = 128 [transport-wlan] INTERFACE = mon0 TESTMODE = 0 [datacache-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf [datacache-postgres] CONFIG = connect_timeout=10; dbname=gnunet [template] AUTOSTART = NO PORT = 20060 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-template ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-template-49 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [fs] AUTOSTART = YES INDEXDB = $SERVICEHOME/idxinfo.lst TRUST = $SERVICEHOME/data/credit/ IDENTITY_DIR = $SERVICEHOME/identities/ STATE_DIR = $SERVICEHOME/persistence/ UPDATE_DIR = $SERVICEHOME/updates/ PORT = 20059 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-fs ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DELAY = YES CONTENT_CACHING = YES CONTENT_PUSHING = YES UNIXPATH = /tmp/test-service-fs-48 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES MAX_PENDING_REQUESTS = 65536 MIN_MIGRATION_DELAY = 100 ms EXPECTED_NEIGHBOUR_COUNT = 128 [vpn] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-vpn IPV6ADDR = 1234::1 IPV6PREFIX = 32 IPV4ADDR = 10.11.10.1 IPV4MASK = 255.255.0.0 VIRTDNS = 10.11.10.2 VIRTDNS6 = 1234::17 IFNAME = vpn-gnunet [exit] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-exit IPV6ADDR = 1234:1::1 IPV6PREFIX = 32 IPV4ADDR = 10.10.1.1 IPV4MASK = 255.255.0.0 IFNAME = exit-gnunet ENABLE_UDP = NO ENABLE_TCP = NO [dns] AUTOSTART = YES PORT = 0 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dns ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-dns-47 PROVIDE_EXIT = NO [arm] PORT = 20058 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-arm ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DEFAULTSERVICES = topology hostlist fs UNIXPATH = /tmp/test-service-arm-46 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [hostlist] HTTPPORT = 8080 HOME = $SERVICEHOME HOSTLISTFILE = $SERVICEHOME/hostlist/learned.data CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-hostlist OPTIONS = -b SERVERS = http://v9.gnunet.org/hostlist http://ioerror.gnunet.org:65535/ HTTP-PROXY = [core] AUTOSTART = YES PORT = 20057 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-core ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-core-45 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [nat] BEHIND_NAT = YES PUNCHED_NAT = NO ENABLE_UPNP = NO USE_LOCALADDR = YES USE_HOSTNAME = NO ENABLE_ICMP_CLIENT = NO ENABLE_ICMP_SERVER = NO DISABLEV6 = YES RETURN_LOCAL_ADDRESSES = NO HOSTNAME_DNS_FREQUENCY = 1200000 IFC_SCAN_FREQUENCY = 3000000 DYNDNS_FREQUENCY = 140000 EXTERNAL_ADDRESS = 127.0.0.1 INTERNAL_ADDRESS = 127.0.0.1 BINDTO = 127.0.0.1 [gnunet-nat-server] HOSTNAME = gnunet.org PORT = 20056 [statistics] AUTOSTART = YES PORT = 20055 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-statistics ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-statistics-44 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES [dht] AUTOSTART = YES PORT = 20054 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dht ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; BUCKET_SIZE = 4 UNIXPATH = /tmp/test-service-dht-43 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [dhtcache] DATABASE = sqlite QUOTA = 1 MBgnunet-0.9.3/src/integration-tests/confs/c_nat_client.conf0000644000175000017500000001552311760501576020635 00000000000000[PATHS] SERVICEHOME = /tmp/c_nat_client DEFAULTCONFIG = confs/c_nat_client.conf [gnunetd] HOSTKEY = hostkeys/0002-hostkey [client] HOME = $SERVICEHOME [gns] AUTOSTART = NO [namestore] AUTOSTART = NO [vpn] AUTOSTART = YES PORT = 0 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dns ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-vpn-57 [resolver] AUTOSTART = YES PORT = 20071 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-resolver ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-resolver-56 UNIX_MATCH_UID = NO UNIX_MATCH_GID = NO [mesh] AUTOSTART = YES PORT = 20070 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-mesh ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-mesh-55 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [nse] AUTOSTART = YES PORT = 20069 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-nse ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-nse-54 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PROOFFILE = $SERVICEHOME/.nse-proof HISTOGRAM = $SERVICEHOME/nse-history.log WORKDELAY = 5 ms INTERVAL = 1 h WORKBITS = 26 [topology] MINIMUM-FRIENDS = 0 FRIENDS-ONLY = NO AUTOCONNECT = YES TARGET-CONNECTION-COUNT = 16 FRIENDS = $SERVICEHOME/friends CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-topology [datastore] AUTOSTART = YES UNIXPATH = /tmp/test-service-datastore-53 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PORT = 20068 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-datastore ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; QUOTA = 100 MB BLOOMFILTER = $SERVICEHOME/fs/bloomfilter DATABASE = sqlite [datastore-sqlite] FILENAME = $SERVICEHOME/datastore/sqlite.db [datastore-postgres] CONFIG = connect_timeout=10; dbname=gnunet [datastore-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf [peerinfo] AUTOSTART = YES PORT = 20067 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-peerinfo ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-peerinfo-52 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES HOSTS = $SERVICEHOME/data/hosts/ [TESTING] WEAKRANDOM = NO CONNECT_TIMEOUT = 30 s CONNECT_ATTEMPTS = 3 MAX_OUTSTANDING_CONNECTIONS = 50 DELETE_FILES = YES [ats] AUTOSTART = YES PORT = 20066 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-ats ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-ats-51 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES WAN_QUOTA_IN = 65536 WAN_QUOTA_OUT = 65536 DUMP_MLP = NO DUMP_SOLUTION = NO DUMP_OVERWRITE = NO DUMP_MIN_PEERS = 0 DUMP_MIN_ADDRS = 0 ATS_MIN_INTERVAL = 15000 ATS_EXEC_INTERVAL = 30000 [transport] AUTOSTART = YES PORT = 20065 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-transport NEIGHBOUR_LIMIT = 50 ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; PLUGINS = tcp UNIXPATH = /tmp/test-service-transport-50 BLACKLIST_FILE = $SERVICEHOME/blacklist UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [transport-tcp] PORT = 0 ADVERTISED_PORT = 20064 MAX_CONNECTIONS = 128 TIMEOUT = 5 s USE_LOCALADDR = YES [transport-udp] PORT = 0 BROADCAST = YES BROADCAST_INTERVAL = 30000 MAX_BPS = 1000000 USE_LOCALADDR = YES [transport-http] PORT = 0 MAX_CONNECTIONS = 128 [transport-https] PORT = 0 CRYPTO_INIT = NORMAL KEY_FILE = https.key CERT_FILE = https.cert MAX_CONNECTIONS = 128 [transport-wlan] INTERFACE = mon0 TESTMODE = 0 [datacache-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf [datacache-postgres] CONFIG = connect_timeout=10; dbname=gnunet [template] AUTOSTART = NO PORT = 20060 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-template ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-template-49 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [fs] AUTOSTART = YES INDEXDB = $SERVICEHOME/idxinfo.lst TRUST = $SERVICEHOME/data/credit/ IDENTITY_DIR = $SERVICEHOME/identities/ STATE_DIR = $SERVICEHOME/persistence/ UPDATE_DIR = $SERVICEHOME/updates/ PORT = 20059 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-fs ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DELAY = YES CONTENT_CACHING = YES CONTENT_PUSHING = YES UNIXPATH = /tmp/test-service-fs-48 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES MAX_PENDING_REQUESTS = 65536 MIN_MIGRATION_DELAY = 100 ms EXPECTED_NEIGHBOUR_COUNT = 128 [vpn] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-vpn IPV6ADDR = 1234::1 IPV6PREFIX = 32 IPV4ADDR = 10.11.10.1 IPV4MASK = 255.255.0.0 VIRTDNS = 10.11.10.2 VIRTDNS6 = 1234::17 IFNAME = vpn-gnunet [exit] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-exit IPV6ADDR = 1234:1::1 IPV6PREFIX = 32 IPV4ADDR = 10.10.1.1 IPV4MASK = 255.255.0.0 IFNAME = exit-gnunet ENABLE_UDP = NO ENABLE_TCP = NO [dns] AUTOSTART = YES PORT = 0 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dns ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-dns-47 PROVIDE_EXIT = NO [arm] PORT = 20058 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-arm ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DEFAULTSERVICES = topology hostlist fs UNIXPATH = /tmp/test-service-arm-46 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [hostlist] HTTPPORT = 8080 HOME = $SERVICEHOME HOSTLISTFILE = $SERVICEHOME/hostlist/learned.data CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-hostlist OPTIONS = -b SERVERS = http://localhost:8080/ HTTP-PROXY = [core] AUTOSTART = YES PORT = 20057 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-core ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-core-45 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [nat] BEHIND_NAT = YES PUNCHED_NAT = NO ENABLE_UPNP = NO USE_LOCALADDR = YES USE_HOSTNAME = NO ENABLE_ICMP_CLIENT = NO ENABLE_ICMP_SERVER = NO DISABLEV6 = YES RETURN_LOCAL_ADDRESSES = NO HOSTNAME_DNS_FREQUENCY = 1200000 IFC_SCAN_FREQUENCY = 3000000 DYNDNS_FREQUENCY = 140000 EXTERNAL_ADDRESS = 127.0.0.1 INTERNAL_ADDRESS = 127.0.0.1 BINDTO = 127.0.0.1 [gnunet-nat-server] HOSTNAME = gnunet.org PORT = 20056 [statistics] AUTOSTART = YES PORT = 20055 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-statistics ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-statistics-44 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES [dht] AUTOSTART = YES PORT = 20054 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dht ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; BUCKET_SIZE = 4 UNIXPATH = /tmp/test-service-dht-43 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [dhtcache] DATABASE = sqlite QUOTA = 1 MB [lockmanager] AUTOSTART = NOgnunet-0.9.3/src/integration-tests/confs/c_no_nat_client_http_2.conf0000644000175000017500000001534511753027570022612 00000000000000[PATHS] SERVICEHOME = /tmp/c_no_nat_client_2/ DEFAULTCONFIG = confs/c_no_nat_client_http_2.conf [gnunetd] #HOSTKEY = $SERVICEHOME/.hostkey HOSTKEY = hostkeys/0002-hostkey [gns] AUTOSTART = NO [namestore] AUTOSTART = NO [resolver] AUTOSTART = YES PORT = 20053 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-resolver ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-resolver-42 UNIX_MATCH_UID = NO UNIX_MATCH_GID = NO [mesh] AUTOSTART = YES PORT = 20052 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-mesh ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-mesh-41 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [nse] AUTOSTART = YES PORT = 20051 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-nse ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-nse-40 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PROOFFILE = $SERVICEHOME/.nse-proof HISTOGRAM = $SERVICEHOME/nse-history.log WORKDELAY = 5 ms INTERVAL = 1 h WORKBITS = 26 [topology] MINIMUM-FRIENDS = 0 FRIENDS-ONLY = NO AUTOCONNECT = YES TARGET-CONNECTION-COUNT = 16 FRIENDS = $SERVICEHOME/friends CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-topology [datastore] AUTOSTART = YES UNIXPATH = /tmp/test-service-datastore-39 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PORT = 20050 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-datastore ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; QUOTA = 100 MB BLOOMFILTER = $SERVICEHOME/fs/bloomfilter DATABASE = sqlite [datastore-sqlite] FILENAME = $SERVICEHOME/datastore/sqlite.db [datastore-postgres] CONFIG = connect_timeout=10; dbname=gnunet [datastore-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf [peerinfo] AUTOSTART = YES PORT = 20049 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-peerinfo ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-peerinfo-38 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES HOSTS = $SERVICEHOME/data/hosts/ [client] HOME = $SERVICEHOME [TESTING] WEAKRANDOM = NO CONNECT_TIMEOUT = 30 s CONNECT_ATTEMPTS = 3 MAX_OUTSTANDING_CONNECTIONS = 50 DELETE_FILES = YES [ats] AUTOSTART = YES PORT = 20048 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-ats ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-ats-37 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES WAN_QUOTA_IN = 65536 WAN_QUOTA_OUT = 65536 DUMP_MLP = NO DUMP_SOLUTION = NO DUMP_OVERWRITE = NO DUMP_MIN_PEERS = 0 DUMP_MIN_ADDRS = 0 ATS_MIN_INTERVAL = 15000 ATS_EXEC_INTERVAL = 30000 [transport] PREFIX = valgrind --leak-check=full #PREFIX = gdb --args AUTOSTART = YES PORT = 20047 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-transport NEIGHBOUR_LIMIT = 50 ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; PLUGINS = http UNIXPATH = /tmp/test-service-transport-36 BLACKLIST_FILE = $SERVICEHOME/blacklist UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [transport-tcp] PORT = 20046 ADVERTISED_PORT = 20046 MAX_CONNECTIONS = 128 TIMEOUT = 5 s USE_LOCALADDR = YES [transport-udp] PORT = 20045 BROADCAST = YES BROADCAST_INTERVAL = 30000 MAX_BPS = 1000000 USE_LOCALADDR = YES [transport-http] PORT = 20044 MAX_CONNECTIONS = 128 [transport-https] PORT = 20043 CRYPTO_INIT = NORMAL KEY_FILE = https.key CERT_FILE = https.cert MAX_CONNECTIONS = 128 [transport-wlan] INTERFACE = mon0 TESTMODE = 0 [datacache-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf [datacache-postgres] CONFIG = connect_timeout=10; dbname=gnunet [template] AUTOSTART = NO PORT = 20042 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-template ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-template-35 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [fs] AUTOSTART = YES INDEXDB = $SERVICEHOME/idxinfo.lst TRUST = $SERVICEHOME/data/credit/ IDENTITY_DIR = $SERVICEHOME/identities/ STATE_DIR = $SERVICEHOME/persistence/ UPDATE_DIR = $SERVICEHOME/updates/ PORT = 20041 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-fs ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DELAY = YES CONTENT_CACHING = YES CONTENT_PUSHING = YES UNIXPATH = /tmp/test-service-fs-34 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES MAX_PENDING_REQUESTS = 65536 MIN_MIGRATION_DELAY = 100 ms EXPECTED_NEIGHBOUR_COUNT = 128 [vpn] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-vpn IPV6ADDR = 1234::1 IPV6PREFIX = 32 IPV4ADDR = 10.11.10.1 IPV4MASK = 255.255.0.0 VIRTDNS = 10.11.10.2 VIRTDNS6 = 1234::17 IFNAME = vpn-gnunet [exit] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-exit IPV6ADDR = 1234:1::1 IPV6PREFIX = 32 IPV4ADDR = 10.10.1.1 IPV4MASK = 255.255.0.0 IFNAME = exit-gnunet ENABLE_UDP = NO ENABLE_TCP = NO [dns] AUTOSTART = YES PORT = 0 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dns ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-dns-33 PROVIDE_EXIT = NO [arm] PORT = 20040 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-arm ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DEFAULTSERVICES = topology hostlist fs core UNIXPATH = /tmp/test-service-arm-32 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [hostlist] HTTPPORT = 8080 HOME = $SERVICEHOME HOSTLISTFILE = $SERVICEHOME/hostlist/learned.data CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-hostlist OPTIONS = -b SERVERS = http://localhost:8080/ HTTP-PROXY = [core] AUTOSTART = YES PORT = 20039 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-core ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-core-31 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [nat] BEHIND_NAT = NO PUNCHED_NAT = NO ENABLE_UPNP = NO USE_LOCALADDR = YES USE_HOSTNAME = NO ENABLE_ICMP_CLIENT = NO ENABLE_ICMP_SERVER = NO DISABLEV6 = YES RETURN_LOCAL_ADDRESSES = NO HOSTNAME_DNS_FREQUENCY = 1200000 IFC_SCAN_FREQUENCY = 3000000 DYNDNS_FREQUENCY = 140000 EXTERNAL_ADDRESS = 127.0.0.1 INTERNAL_ADDRESS = 127.0.0.1 BINDTO = 127.0.0.1 [gnunet-nat-server] HOSTNAME = gnunet.org PORT = 20038 [statistics] AUTOSTART = YES PORT = 20037 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-statistics ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-statistics-30 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES [dht] AUTOSTART = YES PORT = 20036 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dht ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; BUCKET_SIZE = 4 UNIXPATH = /tmp/test-service-dht-29 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [dhtcache] DATABASE = sqlite QUOTA = 1 MB gnunet-0.9.3/src/integration-tests/confs/c_no_nat_client_unix.conf0000644000175000017500000001572111753027570022373 00000000000000[PATHS] SERVICEHOME = /tmp/c_no_nat_client/ DEFAULTCONFIG = confs/c_no_nat_client_unix.conf [gnunetd] #HOSTKEY = $SERVICEHOME/.hostkey HOSTKEY = hostkeys/0001-hostkey [gns] AUTOSTART = NO [namestore] AUTOSTART = NO [vpn] AUTOSTART = YES PORT = 0 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dns ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-vpn-29 [resolver] AUTOSTART = YES PORT = 20035 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-resolver ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-resolver-28 UNIX_MATCH_UID = NO UNIX_MATCH_GID = NO [mesh] AUTOSTART = YES PORT = 20034 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-mesh ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-mesh-27 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [nse] AUTOSTART = YES PORT = 20033 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-nse ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-nse-26 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PROOFFILE = $SERVICEHOME/.nse-proof HISTOGRAM = $SERVICEHOME/nse-history.log WORKDELAY = 5 ms INTERVAL = 1 h WORKBITS = 26 [topology] MINIMUM-FRIENDS = 0 FRIENDS-ONLY = NO AUTOCONNECT = YES TARGET-CONNECTION-COUNT = 16 FRIENDS = $SERVICEHOME/friends CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-topology [datastore] AUTOSTART = YES UNIXPATH = /tmp/test-service-datastore-25 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PORT = 20032 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-datastore ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; QUOTA = 100 MB BLOOMFILTER = $SERVICEHOME/fs/bloomfilter DATABASE = sqlite [datastore-sqlite] FILENAME = $SERVICEHOME/datastore/sqlite.db [datastore-postgres] CONFIG = connect_timeout=10; dbname=gnunet [datastore-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf [peerinfo] AUTOSTART = YES PORT = 20031 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-peerinfo ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-peerinfo-24 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES HOSTS = $SERVICEHOME/data/hosts/ [client] HOME = $SERVICEHOME [TESTING] WEAKRANDOM = NO CONNECT_TIMEOUT = 30 s CONNECT_ATTEMPTS = 3 MAX_OUTSTANDING_CONNECTIONS = 50 DELETE_FILES = YES [ats] AUTOSTART = YES PORT = 20030 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-ats ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-ats-23 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES WAN_QUOTA_IN = 65536 WAN_QUOTA_OUT = 65536 DUMP_MLP = NO DUMP_SOLUTION = NO DUMP_OVERWRITE = NO DUMP_MIN_PEERS = 0 DUMP_MIN_ADDRS = 0 ATS_MIN_INTERVAL = 15000 ATS_EXEC_INTERVAL = 30000 [transport] PREFIX = valgrind --leak-check=full #DEBUG = YES AUTOSTART = YES PORT = 20029 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-transport NEIGHBOUR_LIMIT = 50 ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; PLUGINS = unix tcp udp http UNIXPATH = /tmp/test-service-transport-22 BLACKLIST_FILE = $SERVICEHOME/blacklist UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [transport-unix] PORT = 22087 [transport-tcp] USE_LOCALADDR = YES PORT = 20028 ADVERTISED_PORT = 20028 MAX_CONNECTIONS = 128 TIMEOUT = 5 s [transport-udp] USE_LOCALADDR = YES PORT = 20027 BROADCAST = YES BROADCAST_INTERVAL = 30000 MAX_BPS = 1000000 [transport-http] PORT = 0 MAX_CONNECTIONS = 128 [transport-https] PORT = 20025 CRYPTO_INIT = NORMAL KEY_FILE = https.key CERT_FILE = https.cert MAX_CONNECTIONS = 128 [transport-wlan] INTERFACE = mon0 TESTMODE = 0 [datacache-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf [datacache-postgres] CONFIG = connect_timeout=10; dbname=gnunet [template] AUTOSTART = NO PORT = 20024 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-template ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-template-21 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [fs] AUTOSTART = YES INDEXDB = $SERVICEHOME/idxinfo.lst TRUST = $SERVICEHOME/data/credit/ IDENTITY_DIR = $SERVICEHOME/identities/ STATE_DIR = $SERVICEHOME/persistence/ UPDATE_DIR = $SERVICEHOME/updates/ PORT = 20023 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-fs ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DELAY = YES CONTENT_CACHING = YES CONTENT_PUSHING = YES UNIXPATH = /tmp/test-service-fs-20 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES MAX_PENDING_REQUESTS = 65536 MIN_MIGRATION_DELAY = 100 ms EXPECTED_NEIGHBOUR_COUNT = 128 [vpn] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-vpn IPV6ADDR = 1234::1 IPV6PREFIX = 32 IPV4ADDR = 10.11.10.1 IPV4MASK = 255.255.0.0 VIRTDNS = 10.11.10.2 VIRTDNS6 = 1234::17 IFNAME = vpn-gnunet [exit] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-exit IPV6ADDR = 1234:1::1 IPV6PREFIX = 32 IPV4ADDR = 10.10.1.1 IPV4MASK = 255.255.0.0 IFNAME = exit-gnunet ENABLE_UDP = NO ENABLE_TCP = NO [dns] AUTOSTART = YES PORT = 0 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dns ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-dns-19 PROVIDE_EXIT = NO [arm] PORT = 20022 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-arm ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DEFAULTSERVICES = topology hostlist fs core UNIXPATH = /tmp/test-service-arm-18 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [hostlist] HTTPPORT = 8080 HOME = $SERVICEHOME HOSTLISTFILE = $SERVICEHOME/hostlist/learned.data CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-hostlist OPTIONS = -b SERVERS = http://localhost:8080/ HTTP-PROXY = [core] AUTOSTART = YES PORT = 20021 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-core ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-core-17 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [nat] EXTERNAL_ADDRESS = 127.0.0.1 INTERNAL_ADDRESS = 127.0.0.1 BINDTO = 127.0.0.1 BEHIND_NAT = NO PUNCHED_NAT = NO ENABLE_UPNP = NO USE_LOCALADDR = YES USE_HOSTNAME = NO ENABLE_ICMP_CLIENT = NO ENABLE_ICMP_SERVER = NO DISABLEV6 = YES RETURN_LOCAL_ADDRESSES = NO HOSTNAME_DNS_FREQUENCY = 1200000 IFC_SCAN_FREQUENCY = 3000000 DYNDNS_FREQUENCY = 140000 [gnunet-nat-server] HOSTNAME = gnunet.org PORT = 20020 [statistics] AUTOSTART = YES PORT = 20019 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-statistics ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-statistics-16 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES [dht] AUTOSTART = YES PORT = 20018 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dht ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; BUCKET_SIZE = 4 UNIXPATH = /tmp/test-service-dht-15 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [dhtcache] DATABASE = sqlite QUOTA = 1 MB gnunet-0.9.3/src/integration-tests/confs/c_no_nat_client_http.conf0000644000175000017500000001565111753027570022371 00000000000000[PATHS] SERVICEHOME = /tmp/c_no_nat_client/ DEFAULTCONFIG = confs/c_no_nat_client_http.conf [gnunetd] #HOSTKEY = $SERVICEHOME/.hostkey HOSTKEY = hostkeys/0001-hostkey [gns] AUTOSTART = NO [namestore] AUTOSTART = NO [vpn] AUTOSTART = YES PORT = 0 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dns ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-vpn-29 [resolver] AUTOSTART = YES PORT = 20035 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-resolver ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-resolver-28 UNIX_MATCH_UID = NO UNIX_MATCH_GID = NO [mesh] AUTOSTART = YES PORT = 20034 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-mesh ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-mesh-27 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [nse] AUTOSTART = YES PORT = 20033 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-nse ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-nse-26 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PROOFFILE = $SERVICEHOME/.nse-proof HISTOGRAM = $SERVICEHOME/nse-history.log WORKDELAY = 5 ms INTERVAL = 1 h WORKBITS = 26 [topology] MINIMUM-FRIENDS = 0 FRIENDS-ONLY = NO AUTOCONNECT = YES TARGET-CONNECTION-COUNT = 16 FRIENDS = $SERVICEHOME/friends CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-topology [datastore] AUTOSTART = YES UNIXPATH = /tmp/test-service-datastore-25 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PORT = 20032 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-datastore ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; QUOTA = 100 MB BLOOMFILTER = $SERVICEHOME/fs/bloomfilter DATABASE = sqlite [datastore-sqlite] FILENAME = $SERVICEHOME/datastore/sqlite.db [datastore-postgres] CONFIG = connect_timeout=10; dbname=gnunet [datastore-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf [peerinfo] AUTOSTART = YES PORT = 20031 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-peerinfo ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-peerinfo-24 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES HOSTS = $SERVICEHOME/data/hosts/ [client] HOME = $SERVICEHOME [TESTING] WEAKRANDOM = NO CONNECT_TIMEOUT = 30 s CONNECT_ATTEMPTS = 3 MAX_OUTSTANDING_CONNECTIONS = 50 DELETE_FILES = YES [ats] AUTOSTART = YES PORT = 20030 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-ats ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-ats-23 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES WAN_QUOTA_IN = 65536 WAN_QUOTA_OUT = 65536 DUMP_MLP = NO DUMP_SOLUTION = NO DUMP_OVERWRITE = NO DUMP_MIN_PEERS = 0 DUMP_MIN_ADDRS = 0 ATS_MIN_INTERVAL = 15000 ATS_EXEC_INTERVAL = 30000 [transport] PREFIX = valgrind --leak-check=full #DEBUG = YES AUTOSTART = YES PORT = 20029 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-transport NEIGHBOUR_LIMIT = 50 ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; PLUGINS = http UNIXPATH = /tmp/test-service-transport-22 BLACKLIST_FILE = $SERVICEHOME/blacklist UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [transport-tcp] USE_LOCALADDR = YES PORT = 20028 ADVERTISED_PORT = 20028 MAX_CONNECTIONS = 128 TIMEOUT = 5 s [transport-udp] USE_LOCALADDR = YES PORT = 20027 BROADCAST = YES BROADCAST_INTERVAL = 30000 MAX_BPS = 1000000 [transport-http] PORT = 20026 MAX_CONNECTIONS = 128 [transport-https] PORT = 20025 CRYPTO_INIT = NORMAL KEY_FILE = https.key CERT_FILE = https.cert MAX_CONNECTIONS = 128 [transport-wlan] INTERFACE = mon0 TESTMODE = 0 [datacache-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf [datacache-postgres] CONFIG = connect_timeout=10; dbname=gnunet [template] AUTOSTART = NO PORT = 20024 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-template ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-template-21 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [fs] AUTOSTART = YES INDEXDB = $SERVICEHOME/idxinfo.lst TRUST = $SERVICEHOME/data/credit/ IDENTITY_DIR = $SERVICEHOME/identities/ STATE_DIR = $SERVICEHOME/persistence/ UPDATE_DIR = $SERVICEHOME/updates/ PORT = 20023 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-fs ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DELAY = YES CONTENT_CACHING = YES CONTENT_PUSHING = YES UNIXPATH = /tmp/test-service-fs-20 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES MAX_PENDING_REQUESTS = 65536 MIN_MIGRATION_DELAY = 100 ms EXPECTED_NEIGHBOUR_COUNT = 128 [vpn] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-vpn IPV6ADDR = 1234::1 IPV6PREFIX = 32 IPV4ADDR = 10.11.10.1 IPV4MASK = 255.255.0.0 VIRTDNS = 10.11.10.2 VIRTDNS6 = 1234::17 IFNAME = vpn-gnunet [exit] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-exit IPV6ADDR = 1234:1::1 IPV6PREFIX = 32 IPV4ADDR = 10.10.1.1 IPV4MASK = 255.255.0.0 IFNAME = exit-gnunet ENABLE_UDP = NO ENABLE_TCP = NO [dns] AUTOSTART = YES PORT = 0 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dns ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-dns-19 PROVIDE_EXIT = NO [arm] PORT = 20022 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-arm ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DEFAULTSERVICES = topology hostlist fs core UNIXPATH = /tmp/test-service-arm-18 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [hostlist] HTTPPORT = 8080 HOME = $SERVICEHOME HOSTLISTFILE = $SERVICEHOME/hostlist/learned.data CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-hostlist OPTIONS = -b SERVERS = http://localhost:8080/ HTTP-PROXY = [core] AUTOSTART = YES PORT = 20021 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-core ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-core-17 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [nat] EXTERNAL_ADDRESS = 127.0.0.1 INTERNAL_ADDRESS = 127.0.0.1 BINDTO = 127.0.0.1 BEHIND_NAT = NO PUNCHED_NAT = NO ENABLE_UPNP = NO USE_LOCALADDR = YES USE_HOSTNAME = NO ENABLE_ICMP_CLIENT = NO ENABLE_ICMP_SERVER = NO DISABLEV6 = YES RETURN_LOCAL_ADDRESSES = NO HOSTNAME_DNS_FREQUENCY = 1200000 IFC_SCAN_FREQUENCY = 3000000 DYNDNS_FREQUENCY = 140000 [gnunet-nat-server] HOSTNAME = gnunet.org PORT = 20020 [statistics] AUTOSTART = YES PORT = 20019 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-statistics ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-statistics-16 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES [dht] AUTOSTART = YES PORT = 20018 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dht ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; BUCKET_SIZE = 4 UNIXPATH = /tmp/test-service-dht-15 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [dhtcache] DATABASE = sqlite QUOTA = 1 MB gnunet-0.9.3/src/integration-tests/confs/c_no_nat_client_unix_2.conf0000644000175000017500000001542111753027570022611 00000000000000[PATHS] SERVICEHOME = /tmp/c_no_nat_client_2/ DEFAULTCONFIG = confs/c_no_nat_client_unix_2.conf [gnunetd] #HOSTKEY = $SERVICEHOME/.hostkey HOSTKEY = hostkeys/0002-hostkey [gns] AUTOSTART = NO [namestore] AUTOSTART = NO [resolver] AUTOSTART = YES PORT = 20053 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-resolver ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-resolver-42 UNIX_MATCH_UID = NO UNIX_MATCH_GID = NO [mesh] AUTOSTART = YES PORT = 20052 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-mesh ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-mesh-41 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [nse] AUTOSTART = YES PORT = 20051 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-nse ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-nse-40 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PROOFFILE = $SERVICEHOME/.nse-proof HISTOGRAM = $SERVICEHOME/nse-history.log WORKDELAY = 5 ms INTERVAL = 1 h WORKBITS = 26 [topology] MINIMUM-FRIENDS = 0 FRIENDS-ONLY = NO AUTOCONNECT = YES TARGET-CONNECTION-COUNT = 16 FRIENDS = $SERVICEHOME/friends CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-topology [datastore] AUTOSTART = YES UNIXPATH = /tmp/test-service-datastore-39 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PORT = 20050 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-datastore ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; QUOTA = 100 MB BLOOMFILTER = $SERVICEHOME/fs/bloomfilter DATABASE = sqlite [datastore-sqlite] FILENAME = $SERVICEHOME/datastore/sqlite.db [datastore-postgres] CONFIG = connect_timeout=10; dbname=gnunet [datastore-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf [peerinfo] AUTOSTART = YES PORT = 20049 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-peerinfo ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-peerinfo-38 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES HOSTS = $SERVICEHOME/data/hosts/ [client] HOME = $SERVICEHOME [TESTING] WEAKRANDOM = NO CONNECT_TIMEOUT = 30 s CONNECT_ATTEMPTS = 3 MAX_OUTSTANDING_CONNECTIONS = 50 DELETE_FILES = YES [ats] AUTOSTART = YES PORT = 20048 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-ats ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-ats-37 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES WAN_QUOTA_IN = 65536 WAN_QUOTA_OUT = 65536 DUMP_MLP = NO DUMP_SOLUTION = NO DUMP_OVERWRITE = NO DUMP_MIN_PEERS = 0 DUMP_MIN_ADDRS = 0 ATS_MIN_INTERVAL = 15000 ATS_EXEC_INTERVAL = 30000 [transport] PREFIX = valgrind --leak-check=full #PREFIX = gdb --args AUTOSTART = YES PORT = 20047 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-transport NEIGHBOUR_LIMIT = 50 ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; PLUGINS = unix tcp udp http UNIXPATH = /tmp/test-service-transport-36 BLACKLIST_FILE = $SERVICEHOME/blacklist UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [transport-unix] PORT = 22086 [transport-tcp] PORT = 20046 ADVERTISED_PORT = 20046 MAX_CONNECTIONS = 128 TIMEOUT = 5 s USE_LOCALADDR = YES [transport-udp] PORT = 20045 BROADCAST = YES BROADCAST_INTERVAL = 30000 MAX_BPS = 1000000 USE_LOCALADDR = YES [transport-http] PORT = 20044 MAX_CONNECTIONS = 128 [transport-https] PORT = 20043 CRYPTO_INIT = NORMAL KEY_FILE = https.key CERT_FILE = https.cert MAX_CONNECTIONS = 128 [transport-wlan] INTERFACE = mon0 TESTMODE = 0 [datacache-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf [datacache-postgres] CONFIG = connect_timeout=10; dbname=gnunet [template] AUTOSTART = NO PORT = 20042 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-template ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-template-35 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [fs] AUTOSTART = YES INDEXDB = $SERVICEHOME/idxinfo.lst TRUST = $SERVICEHOME/data/credit/ IDENTITY_DIR = $SERVICEHOME/identities/ STATE_DIR = $SERVICEHOME/persistence/ UPDATE_DIR = $SERVICEHOME/updates/ PORT = 20041 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-fs ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DELAY = YES CONTENT_CACHING = YES CONTENT_PUSHING = YES UNIXPATH = /tmp/test-service-fs-34 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES MAX_PENDING_REQUESTS = 65536 MIN_MIGRATION_DELAY = 100 ms EXPECTED_NEIGHBOUR_COUNT = 128 [vpn] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-vpn IPV6ADDR = 1234::1 IPV6PREFIX = 32 IPV4ADDR = 10.11.10.1 IPV4MASK = 255.255.0.0 VIRTDNS = 10.11.10.2 VIRTDNS6 = 1234::17 IFNAME = vpn-gnunet [exit] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-exit IPV6ADDR = 1234:1::1 IPV6PREFIX = 32 IPV4ADDR = 10.10.1.1 IPV4MASK = 255.255.0.0 IFNAME = exit-gnunet ENABLE_UDP = NO ENABLE_TCP = NO [dns] AUTOSTART = YES PORT = 0 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dns ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-dns-33 PROVIDE_EXIT = NO [arm] PORT = 20040 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-arm ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DEFAULTSERVICES = topology hostlist fs core UNIXPATH = /tmp/test-service-arm-32 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [hostlist] HTTPPORT = 8080 HOME = $SERVICEHOME HOSTLISTFILE = $SERVICEHOME/hostlist/learned.data CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-hostlist OPTIONS = -b SERVERS = http://localhost:8080/ HTTP-PROXY = [core] AUTOSTART = YES PORT = 20039 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-core ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-core-31 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [nat] BEHIND_NAT = NO PUNCHED_NAT = NO ENABLE_UPNP = NO USE_LOCALADDR = YES USE_HOSTNAME = NO ENABLE_ICMP_CLIENT = NO ENABLE_ICMP_SERVER = NO DISABLEV6 = YES RETURN_LOCAL_ADDRESSES = NO HOSTNAME_DNS_FREQUENCY = 1200000 IFC_SCAN_FREQUENCY = 3000000 DYNDNS_FREQUENCY = 140000 EXTERNAL_ADDRESS = 127.0.0.1 INTERNAL_ADDRESS = 127.0.0.1 BINDTO = 127.0.0.1 [gnunet-nat-server] HOSTNAME = gnunet.org PORT = 20038 [statistics] AUTOSTART = YES PORT = 20037 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-statistics ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-statistics-30 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES [dht] AUTOSTART = YES PORT = 20036 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dht ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; BUCKET_SIZE = 4 UNIXPATH = /tmp/test-service-dht-29 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [dhtcache] DATABASE = sqlite QUOTA = 1 MB gnunet-0.9.3/src/integration-tests/confs/c_normal_client_tcp_udp.conf0000644000175000017500000001555711753027570023067 00000000000000[PATHS] SERVICEHOME = /tmp/c_normal_client DEFAULTCONFIG = confs/c_normal_client_tcp_udp.conf [gnunetd] HOSTKEY = hostkeys/0002-hostkey [client] HOME = $SERVICEHOME [gns] AUTOSTART = NO [namestore] AUTOSTART = NO [vpn] AUTOSTART = YES PORT = 0 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dns ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-vpn-57 [resolver] AUTOSTART = YES PORT = 20071 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-resolver ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-resolver-56 UNIX_MATCH_UID = NO UNIX_MATCH_GID = NO [mesh] AUTOSTART = YES PORT = 20070 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-mesh ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-mesh-55 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [nse] AUTOSTART = YES PORT = 20069 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-nse ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-nse-54 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PROOFFILE = $SERVICEHOME/.nse-proof HISTOGRAM = $SERVICEHOME/nse-history.log WORKDELAY = 5 ms INTERVAL = 1 h WORKBITS = 26 [topology] MINIMUM-FRIENDS = 0 FRIENDS-ONLY = NO AUTOCONNECT = YES TARGET-CONNECTION-COUNT = 16 FRIENDS = $SERVICEHOME/friends CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-topology [datastore] AUTOSTART = YES UNIXPATH = /tmp/test-service-datastore-53 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PORT = 20068 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-datastore ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; QUOTA = 100 MB BLOOMFILTER = $SERVICEHOME/fs/bloomfilter DATABASE = sqlite [datastore-sqlite] FILENAME = $SERVICEHOME/datastore/sqlite.db [datastore-postgres] CONFIG = connect_timeout=10; dbname=gnunet [datastore-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf [peerinfo] AUTOSTART = YES PORT = 20067 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-peerinfo ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-peerinfo-52 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES HOSTS = $SERVICEHOME/data/hosts/ [TESTING] WEAKRANDOM = NO CONNECT_TIMEOUT = 30 s CONNECT_ATTEMPTS = 3 MAX_OUTSTANDING_CONNECTIONS = 50 DELETE_FILES = YES [ats] AUTOSTART = YES PORT = 20066 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-ats ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-ats-51 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES WAN_QUOTA_IN = 65536 WAN_QUOTA_OUT = 65536 DUMP_MLP = NO DUMP_SOLUTION = NO DUMP_OVERWRITE = NO DUMP_MIN_PEERS = 0 DUMP_MIN_ADDRS = 0 ATS_MIN_INTERVAL = 15000 ATS_EXEC_INTERVAL = 30000 [transport] AUTOSTART = YES PORT = 20065 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-transport NEIGHBOUR_LIMIT = 50 ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; PLUGINS = tcp udp UNIXPATH = /tmp/test-service-transport-50 BLACKLIST_FILE = $SERVICEHOME/blacklist UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [transport-tcp] PORT = 0 ADVERTISED_PORT = 20064 MAX_CONNECTIONS = 128 TIMEOUT = 5 s USE_LOCALADDR = YES [transport-udp] PORT = 0 BROADCAST = YES BROADCAST_INTERVAL = 30000 MAX_BPS = 1000000 USE_LOCALADDR = YES [transport-http] PORT = 0 MAX_CONNECTIONS = 128 [transport-https] PORT = 0 CRYPTO_INIT = NORMAL KEY_FILE = https.key CERT_FILE = https.cert MAX_CONNECTIONS = 128 [transport-wlan] INTERFACE = mon0 TESTMODE = 0 [datacache-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf [datacache-postgres] CONFIG = connect_timeout=10; dbname=gnunet [template] AUTOSTART = NO PORT = 20060 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-template ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-template-49 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [fs] AUTOSTART = YES INDEXDB = $SERVICEHOME/idxinfo.lst TRUST = $SERVICEHOME/data/credit/ IDENTITY_DIR = $SERVICEHOME/identities/ STATE_DIR = $SERVICEHOME/persistence/ UPDATE_DIR = $SERVICEHOME/updates/ PORT = 20059 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-fs ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DELAY = YES CONTENT_CACHING = YES CONTENT_PUSHING = YES UNIXPATH = /tmp/test-service-fs-48 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES MAX_PENDING_REQUESTS = 65536 MIN_MIGRATION_DELAY = 100 ms EXPECTED_NEIGHBOUR_COUNT = 128 [vpn] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-vpn IPV6ADDR = 1234::1 IPV6PREFIX = 32 IPV4ADDR = 10.11.10.1 IPV4MASK = 255.255.0.0 VIRTDNS = 10.11.10.2 VIRTDNS6 = 1234::17 IFNAME = vpn-gnunet [exit] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-exit IPV6ADDR = 1234:1::1 IPV6PREFIX = 32 IPV4ADDR = 10.10.1.1 IPV4MASK = 255.255.0.0 IFNAME = exit-gnunet ENABLE_UDP = NO ENABLE_TCP = NO [dns] AUTOSTART = YES PORT = 0 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dns ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-dns-47 PROVIDE_EXIT = NO [arm] PORT = 20058 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-arm ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DEFAULTSERVICES = topology hostlist fs UNIXPATH = /tmp/test-service-arm-46 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [hostlist] HTTPPORT = 8080 HOME = $SERVICEHOME HOSTLISTFILE = $SERVICEHOME/hostlist/learned.data CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-hostlist OPTIONS = -b SERVERS = http://v9.gnunet.org/hostlist http://ioerror.gnunet.org:65535/ HTTP-PROXY = [core] AUTOSTART = YES PORT = 20057 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-core ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-core-45 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [nat] BEHIND_NAT = YES PUNCHED_NAT = NO ENABLE_UPNP = NO USE_LOCALADDR = YES USE_HOSTNAME = NO ENABLE_ICMP_CLIENT = NO ENABLE_ICMP_SERVER = NO DISABLEV6 = YES RETURN_LOCAL_ADDRESSES = NO HOSTNAME_DNS_FREQUENCY = 1200000 IFC_SCAN_FREQUENCY = 3000000 DYNDNS_FREQUENCY = 140000 EXTERNAL_ADDRESS = 127.0.0.1 INTERNAL_ADDRESS = 127.0.0.1 BINDTO = 127.0.0.1 [gnunet-nat-server] HOSTNAME = gnunet.org PORT = 20056 [statistics] AUTOSTART = YES PORT = 20055 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-statistics ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-statistics-44 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES [dht] AUTOSTART = YES PORT = 20054 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dht ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; BUCKET_SIZE = 4 UNIXPATH = /tmp/test-service-dht-43 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [dhtcache] DATABASE = sqlite QUOTA = 1 MBgnunet-0.9.3/src/integration-tests/confs/c_normal_client_tcp_udp_http.conf0000644000175000017500000001557111753027570024122 00000000000000[PATHS] SERVICEHOME = /tmp/c_normal_client DEFAULTCONFIG = confs/c_normal_client_tcp_udp_http.conf [gnunetd] HOSTKEY = hostkeys/0002-hostkey [client] HOME = $SERVICEHOME [gns] AUTOSTART = NO [namestore] AUTOSTART = NO [vpn] AUTOSTART = YES PORT = 0 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dns ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-vpn-57 [resolver] AUTOSTART = YES PORT = 20071 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-resolver ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-resolver-56 UNIX_MATCH_UID = NO UNIX_MATCH_GID = NO [mesh] AUTOSTART = YES PORT = 20070 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-mesh ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-mesh-55 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [nse] AUTOSTART = YES PORT = 20069 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-nse ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-nse-54 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PROOFFILE = $SERVICEHOME/.nse-proof HISTOGRAM = $SERVICEHOME/nse-history.log WORKDELAY = 5 ms INTERVAL = 1 h WORKBITS = 26 [topology] MINIMUM-FRIENDS = 0 FRIENDS-ONLY = NO AUTOCONNECT = YES TARGET-CONNECTION-COUNT = 16 FRIENDS = $SERVICEHOME/friends CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-topology [datastore] AUTOSTART = YES UNIXPATH = /tmp/test-service-datastore-53 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PORT = 20068 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-datastore ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; QUOTA = 100 MB BLOOMFILTER = $SERVICEHOME/fs/bloomfilter DATABASE = sqlite [datastore-sqlite] FILENAME = $SERVICEHOME/datastore/sqlite.db [datastore-postgres] CONFIG = connect_timeout=10; dbname=gnunet [datastore-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf [peerinfo] AUTOSTART = YES PORT = 20067 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-peerinfo ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-peerinfo-52 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES HOSTS = $SERVICEHOME/data/hosts/ [TESTING] WEAKRANDOM = NO CONNECT_TIMEOUT = 30 s CONNECT_ATTEMPTS = 3 MAX_OUTSTANDING_CONNECTIONS = 50 DELETE_FILES = YES [ats] AUTOSTART = YES PORT = 20066 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-ats ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-ats-51 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES WAN_QUOTA_IN = 65536 WAN_QUOTA_OUT = 65536 DUMP_MLP = NO DUMP_SOLUTION = NO DUMP_OVERWRITE = NO DUMP_MIN_PEERS = 0 DUMP_MIN_ADDRS = 0 ATS_MIN_INTERVAL = 15000 ATS_EXEC_INTERVAL = 30000 [transport] AUTOSTART = YES PORT = 20065 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-transport NEIGHBOUR_LIMIT = 50 ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; PLUGINS = tcp udp http UNIXPATH = /tmp/test-service-transport-50 BLACKLIST_FILE = $SERVICEHOME/blacklist UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [transport-tcp] PORT = 0 ADVERTISED_PORT = 20064 MAX_CONNECTIONS = 128 TIMEOUT = 5 s USE_LOCALADDR = YES [transport-udp] PORT = 0 BROADCAST = YES BROADCAST_INTERVAL = 30000 MAX_BPS = 1000000 USE_LOCALADDR = YES [transport-http] PORT = 0 MAX_CONNECTIONS = 128 [transport-https] PORT = 0 CRYPTO_INIT = NORMAL KEY_FILE = https.key CERT_FILE = https.cert MAX_CONNECTIONS = 128 [transport-wlan] INTERFACE = mon0 TESTMODE = 0 [datacache-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf [datacache-postgres] CONFIG = connect_timeout=10; dbname=gnunet [template] AUTOSTART = NO PORT = 20060 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-template ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-template-49 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [fs] AUTOSTART = YES INDEXDB = $SERVICEHOME/idxinfo.lst TRUST = $SERVICEHOME/data/credit/ IDENTITY_DIR = $SERVICEHOME/identities/ STATE_DIR = $SERVICEHOME/persistence/ UPDATE_DIR = $SERVICEHOME/updates/ PORT = 20059 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-fs ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DELAY = YES CONTENT_CACHING = YES CONTENT_PUSHING = YES UNIXPATH = /tmp/test-service-fs-48 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES MAX_PENDING_REQUESTS = 65536 MIN_MIGRATION_DELAY = 100 ms EXPECTED_NEIGHBOUR_COUNT = 128 [vpn] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-vpn IPV6ADDR = 1234::1 IPV6PREFIX = 32 IPV4ADDR = 10.11.10.1 IPV4MASK = 255.255.0.0 VIRTDNS = 10.11.10.2 VIRTDNS6 = 1234::17 IFNAME = vpn-gnunet [exit] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-exit IPV6ADDR = 1234:1::1 IPV6PREFIX = 32 IPV4ADDR = 10.10.1.1 IPV4MASK = 255.255.0.0 IFNAME = exit-gnunet ENABLE_UDP = NO ENABLE_TCP = NO [dns] AUTOSTART = YES PORT = 0 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dns ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-dns-47 PROVIDE_EXIT = NO [arm] PORT = 20058 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-arm ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DEFAULTSERVICES = topology hostlist fs UNIXPATH = /tmp/test-service-arm-46 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [hostlist] HTTPPORT = 8080 HOME = $SERVICEHOME HOSTLISTFILE = $SERVICEHOME/hostlist/learned.data CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-hostlist OPTIONS = -b SERVERS = http://v9.gnunet.org/hostlist http://ioerror.gnunet.org:65535/ HTTP-PROXY = [core] AUTOSTART = YES PORT = 20057 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-core ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-core-45 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [nat] BEHIND_NAT = YES PUNCHED_NAT = NO ENABLE_UPNP = NO USE_LOCALADDR = YES USE_HOSTNAME = NO ENABLE_ICMP_CLIENT = NO ENABLE_ICMP_SERVER = NO DISABLEV6 = YES RETURN_LOCAL_ADDRESSES = NO HOSTNAME_DNS_FREQUENCY = 1200000 IFC_SCAN_FREQUENCY = 3000000 DYNDNS_FREQUENCY = 140000 EXTERNAL_ADDRESS = 127.0.0.1 INTERNAL_ADDRESS = 127.0.0.1 BINDTO = 127.0.0.1 [gnunet-nat-server] HOSTNAME = gnunet.org PORT = 20056 [statistics] AUTOSTART = YES PORT = 20055 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-statistics ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-service-statistics-44 UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES [dht] AUTOSTART = YES PORT = 20054 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dht ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; BUCKET_SIZE = 4 UNIXPATH = /tmp/test-service-dht-43 UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES [dhtcache] DATABASE = sqlite QUOTA = 1 MBgnunet-0.9.3/src/integration-tests/gnunet_testing.py.in0000644000175000017500000002504511760502552020243 00000000000000#!@PYTHON@ # This file is part of GNUnet. # (C) 2010 Christian Grothoff (and other contributing authors) # # GNUnet is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2, or (at your # option) any later version. # # GNUnet is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNUnet; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # Functions for integration testing import os import subprocess import sys import shutil import time from gnunet_pyexpect import pexpect class Check: def __init__(self, test): self.fulfilled = False self.conditions = list() self.test = test def add (self, condition): self.conditions.append(condition) def run (self): fulfilled = True pos = 0 neg = 0 for c in self.conditions: if (False == c.check ()): fulfilled = False neg += 1 else: pos += 1 return fulfilled def run_blocking (self, timeout, pos_cont, neg_cont): execs = 0; res = False while ((False == res) and (execs < timeout)): res = self.run() time.sleep(1) execs += 1 if ((False == res) and (execs >= timeout)): print ('Check had timeout after ' +str(timeout)+ ' seconds') neg_cont (self) elif ((False == res) and (execs >= timeout)): neg_cont (self) else: pos_cont (self) return res def run_once (self, pos_cont, neg_cont): execs = 0; res = False res = self.run() if ((res == False) and (neg_cont != None)): neg_cont (self) if ((res == True) and (pos_cont != None)): pos_cont (self) return res def evaluate (self, failed_only): pos = 0 neg = 0 for c in self.conditions: if (False == c.evaluate (failed_only)): neg += 1 else: pos += 1 print (str(pos) +' out of '+ str (pos+neg) + ' conditions fulfilled') return self.fulfilled def reset (self): self.fulfilled = False for c in self.conditions: c.fulfilled = False class Condition: def __init__(self): self.fulfilled = False self.type = 'generic' def __init__(self, type): self.fulfilled = False self.type = type def check(self): return False; def evaluate (self, failed_only): if ((self.fulfilled == False) and (failed_only == True)): print str(self.type) + 'condition for was ' + str(self.fulfilled) elif (failed_only == False): print str(self.type) + 'condition for was ' + str(self.fulfilled) return self.fulfilled class FileExistCondition (Condition): def __init__(self, file): self.fulfilled = False self.type = 'file' self.file = file def check(self): if (self.fulfilled == False): res = os.path.isfile(self.file) if (res == True): self.fulfilled = True return True else: return False else: return True def evaluate (self, failed_only): if ((self.fulfilled == False) and (failed_only == True)): print str(self.type) + 'condition for file '+self.file+' was ' + str(self.fulfilled) elif (failed_only == False): print str(self.type) + 'condition for file '+self.file+' was ' + str(self.fulfilled) return self.fulfilled class StatisticsCondition (Condition): def __init__(self, peer, subsystem, name, value): self.fulfilled = False self.type = 'statistics' self.peer = peer; self.subsystem = subsystem; self.name = name; self.value = value; self.result = -1; def check(self): if (self.fulfilled == False): self.result = self.peer.get_statistics_value (self.subsystem, self.name) if (str(self.result) == str(self.value)): self.fulfilled = True return True else: return False else: return True def evaluate (self, failed_only): if (self.result == -1): res = 'NaN' else: res = str(self.result) if (self.fulfilled == False): fail = " FAIL!" op = " != " else: fail = "" op = " == " if (((self.fulfilled == False) and (failed_only == True)) or (failed_only == False)): print self.peer.id[:4] + " " +self.peer.cfg + " " + str(self.type) + ' condition in subsystem "' + self.subsystem.ljust(12) +'" : "' + self.name.ljust(30) +'" : (expected/real value) ' + str(self.value) + op + res + fail return self.fulfilled # Specify two statistic values and check if they are equal class EqualStatisticsCondition (Condition): def __init__(self, peer, subsystem, name, peer2, subsystem2, name2): self.fulfilled = False self.type = 'equalstatistics' self.peer = peer; self.subsystem = subsystem; self.name = name; self.result = -1; self.peer2 = peer2; self.subsystem2 = subsystem2; self.name2 = name2; self.result2 = -1; def check(self): if (self.fulfilled == False): self.result = self.peer.get_statistics_value (self.subsystem, self.name); self.result2 = self.peer2.get_statistics_value (self.subsystem2, self.name2); if (str(self.result) == str(self.result2)): self.fulfilled = True return True else: return False else: return True def evaluate (self, failed_only): if (self.result == -1): res = 'NaN' else: res = str(self.result) if (self.result2 == -1): res2 = 'NaN' else: res2 = str(self.result2) if (self.fulfilled == False): fail = " FAIL!" op = " != " else: fail = "" op = " == " if (((self.fulfilled == False) and (failed_only == True)) or (failed_only == False)): print self.peer.id[:4] + ' "' + self.subsystem.ljust(12) + '" "' + self.name.ljust(30) + '" == ' + str(self.result) +" " + self.peer2.id[:4] + ' "' + self.subsystem2.ljust(12) + '" '+ self.name2.ljust(30) + '" ' + str(self.result2) return self.fulfilled class Test: def __init__(self, testname, verbose): self.peers = list() self.verbose = verbose; self.name = testname; srcdir = "../.." gnunet_pyexpect_dir = os.path.join (srcdir, "contrib") if gnunet_pyexpect_dir not in sys.path: sys.path.append (gnunet_pyexpect_dir) self.gnunetarm = '' self.gnunetstatistics = '' if os.name == 'posix': self.gnunetarm = 'gnunet-arm' self.gnunetstatistics = 'gnunet-statistics' self.gnunetpeerinfo = 'gnunet-peerinfo' elif os.name == 'nt': self.gnunetarm = 'gnunet-arm.exe' self.gnunetstatistics = 'gnunet-statistics.exe' self.gnunetpeerinfo = 'gnunet-peerinfo.exe' if os.name == "nt": shutil.rmtree (os.path.join (os.getenv ("TEMP"), testname), True) else: shutil.rmtree ("/tmp/" + testname, True) def add_peer (self, peer): self.peers.append(peer) def p (self, msg): if (self.verbose == True): print msg class Peer: def __init__(self, test, cfg_file): if (False == os.path.isfile(cfg_file)): print ("Peer cfg " + cfg_file + ": FILE NOT FOUND") self.id = "" self.test = test self.started = False self.cfg = cfg_file def __del__(self): if (self.started == True): print 'ERROR! Peer using cfg ' + self.cfg + ' was not stopped' ret = self.stop () if (False == ret): print 'ERROR! Peer using cfg ' + self.cfg + ' could not be stopped' self.started = False return ret else: return False def start (self): self.test.p ("Starting peer using cfg " + self.cfg) try: server = subprocess.Popen ([self.test.gnunetarm, '-sq', '-c', self.cfg]) server.communicate () except OSError: print "Can not start peer" self.started = False return False self.started = True; test = '' try: server = pexpect () server.spawn (None, [self.test.gnunetpeerinfo, '-c', self.cfg ,'-s'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) test = server.read("stdout", 1024) except OSError: print "Can not get peer identity" test = (test.split('`')[1]) self.id = test.split('\'')[0] return True def stop (self): if (self.started == False): return False self.test.p ("Stopping peer using cfg " + self.cfg) try: server = subprocess.Popen ([self.test.gnunetarm, '-eq', '-c', self.cfg]) server.communicate () except OSError: print "Can not stop peer" return False self.started = False return True; def get_statistics_value (self, subsystem, name): server = pexpect () server.spawn (None, [self.test.gnunetstatistics, '-c', self.cfg ,'-q','-n', name, '-s', subsystem ], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) #server.expect ("stdout", re.compile (r"")) test = server.read("stdout", 10240) tests = test.partition('\n') # On W32 GNUnet outputs with \r\n, rather than \n if os.name == 'nt' and tests[1] == '\n' and tests[0][-1] == '\r': tests = (tests[0][:-1], tests[1], tests[2]) tests = tests[0] if (tests.isdigit() == True): return tests else: return -1 gnunet-0.9.3/src/integration-tests/Makefile.in0000644000175000017500000007027311762217212016275 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ noinst_PROGRAMS = connection_watchdog$(EXEEXT) check_PROGRAMS = test_connection_stability$(EXEEXT) subdir = src/integration-tests DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = PROGRAMS = $(noinst_PROGRAMS) connection_watchdog_SOURCES = connection_watchdog.c connection_watchdog_OBJECTS = connection_watchdog.$(OBJEXT) connection_watchdog_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent am_test_connection_stability_OBJECTS = \ test_connection_stability.$(OBJEXT) test_connection_stability_OBJECTS = \ $(am_test_connection_stability_OBJECTS) test_connection_stability_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la SCRIPTS = $(noinst_SCRIPTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = connection_watchdog.c $(test_connection_stability_SOURCES) DIST_SOURCES = connection_watchdog.c \ $(test_connection_stability_SOURCES) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @USE_COVERAGE_TRUE@XLIB = -lgcov noinst_SCRIPTS = \ gnunet_testing.py \ gnunet_pyexpect.py \ test_integration_connection_values_tcp.py \ test_integration_connection_values_tcp_udp.py \ test_integration_connection_values_tcp_udp_http.py @HAVE_PYTHON_PEXPECT_TRUE@check_SCRIPTS = \ @HAVE_PYTHON_PEXPECT_TRUE@ test_integration_bootstrap_and_connect.py \ @HAVE_PYTHON_PEXPECT_TRUE@ test_integration_bootstrap_and_connect_and_disconnect.py \ @HAVE_PYTHON_PEXPECT_TRUE@ test_integration_bootstrap_and_connect_and_disconnect_nat.py \ @HAVE_PYTHON_PEXPECT_TRUE@ test_integration_restart.py \ @HAVE_PYTHON_PEXPECT_TRUE@ test_integration_clique.py \ @HAVE_PYTHON_PEXPECT_TRUE@ test_integration_clique_nat.py \ @HAVE_PYTHON_PEXPECT_TRUE@ test_integration_connect_on_restart.py @ENABLE_TEST_RUN_TRUE@TESTS = \ @ENABLE_TEST_RUN_TRUE@ $(check_SCRIPTS) connection_watchdog_SOURCE = \ connection_watchdog.c connection_watchdog_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' test_connection_stability_SOURCES = \ test_connection_stability.c test_connection_stability_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ gnunet_testing.py.in \ gnunet_pyexpect.py.in \ test_integration_connection_values_tcp.py.in \ test_integration_connection_values_tcp_udp.py.in \ test_integration_connection_values_tcp_udp_http.py.in \ test_integration_bootstrap_and_connect.py.in \ test_integration_bootstrap_and_connect_and_disconnect.py.in \ test_integration_bootstrap_and_connect_and_disconnect_nat.py.in \ test_integration_connect_on_restart.py.in \ test_integration_disconnect.py.in \ test_integration_restart.py.in \ test_integration_clique.py.in \ test_integration_clique_nat.py.in \ confs/c_bootstrap_server.conf \ confs/c_nat_client.conf \ confs/c_no_nat_client_2.conf \ confs/c_no_nat_client.conf \ confs/c_normal_client_tcp.conf \ confs/c_normal_client_tcp_udp.conf \ confs/c_normal_client_tcp_udp_http.conf \ confs/c_no_nat_client_http.conf \ confs/c_no_nat_client_http_2.conf\ confs/c_no_nat_client_http.conf \ confs/c_no_nat_client_http_2.conf \ confs/c_no_nat_client_unix.conf \ confs/c_no_nat_client_unix_2.conf \ test_connection_stability.conf \ hostkeys/0000-hostkey \ hostkeys/0001-hostkey \ hostkeys/0002-hostkey \ hostkeys/0003-hostkey \ hostkeys/0004-hostkey \ hostkeys/0005-hostkey \ hostkeys/0006-hostkey \ hostkeys/0007-hostkey \ hostkeys/0008-hostkey \ hostkeys/0009-hostkey # test_integration_disconnect_nat.py CLEANFILES = \ $(check_SCRIPTS) \ gnunet_testing.py all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/integration-tests/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/integration-tests/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list connection_watchdog$(EXEEXT): $(connection_watchdog_OBJECTS) $(connection_watchdog_DEPENDENCIES) @rm -f connection_watchdog$(EXEEXT) $(AM_V_CCLD)$(LINK) $(connection_watchdog_OBJECTS) $(connection_watchdog_LDADD) $(LIBS) test_connection_stability$(EXEEXT): $(test_connection_stability_OBJECTS) $(test_connection_stability_DEPENDENCIES) @rm -f test_connection_stability$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_connection_stability_OBJECTS) $(test_connection_stability_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connection_watchdog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_connection_stability.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(check_SCRIPTS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(PROGRAMS) $(SCRIPTS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ clean-noinstPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-checkPROGRAMS clean-generic clean-libtool \ clean-noinstPROGRAMS ctags distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am %.py: %.py.in Makefile $(do_subst) < $(srcdir)/$< > $@ chmod +x $@ gnunet_testing.py: gnunet_testing.py.in Makefile $(do_subst) < $(srcdir)/gnunet_testing.py.in > gnunet_testing.py chmod +x gnunet_testing.py gnunet_pyexpect.py: gnunet_pyexpect.py.in Makefile $(do_subst) < $(srcdir)/gnunet_pyexpect.py.in > gnunet_pyexpect.py chmod +x gnunet_pyexpect.py test_integration_bootstrap_and_connect.py: test_integration_bootstrap_and_connect.py.in Makefile $(do_subst) < $(srcdir)/test_integration_bootstrap_and_connect.py.in > test_integration_bootstrap_and_connect.py chmod +x test_integration_bootstrap_and_connect.py test_integration_bootstrap_and_connect_and_disconnect.py: test_integration_bootstrap_and_connect_and_disconnect.py.in Makefile $(do_subst) < $(srcdir)/test_integration_bootstrap_and_connect_and_disconnect.py.in > test_integration_bootstrap_and_connect_and_disconnect.py chmod +x test_integration_bootstrap_and_connect_and_disconnect.py test_integration_bootstrap_and_connect_and_disconnect_nat.py: test_integration_bootstrap_and_connect_and_disconnect_nat.py.in Makefile $(do_subst) < $(srcdir)/test_integration_bootstrap_and_connect_and_disconnect_nat.py.in > test_integration_bootstrap_and_connect_and_disconnect_nat.py chmod +x test_integration_bootstrap_and_connect_and_disconnect_nat.py test_integration_disconnect.py: test_integration_disconnect.py.in Makefile $(do_subst) < $(srcdir)/test_integration_disconnect.py.in > test_integration_disconnect.py chmod +x test_integration_disconnect.py #test_integration_disconnect_nat.py: test_integration_disconnect_nat.py.in Makefile # $(do_subst) < $(srcdir)/test_integration_disconnect_nat.py.in > test_integration_disconnect_nat.py # chmod +x test_integration_disconnect_nat.py test_integration_restart.py: test_integration_restart.py.in Makefile $(do_subst) < $(srcdir)/test_integration_restart.py.in > test_integration_restart.py chmod +x test_integration_restart.py test_integration_clique.py: test_integration_clique.py.in Makefile $(do_subst) < $(srcdir)/test_integration_clique.py.in > test_integration_clique.py chmod +x test_integration_clique.py test_integration_clique_nat.py: test_integration_clique_nat.py.in Makefile $(do_subst) < $(srcdir)/test_integration_clique_nat.py.in > test_integration_clique_nat.py chmod +x test_integration_clique_nat.py test_integration_connect_on_restart.py: test_integration_connect_on_restart.py.in Makefile $(do_subst) < $(srcdir)/test_integration_connect_on_restart.py.in > test_integration_connect_on_restart.py chmod +x test_integration_connect_on_restart.py test_integration_connection_values_tcp.py: test_integration_connection_values_tcp.py.in Makefile $(do_subst) < $(srcdir)/test_integration_connection_values_tcp.py.in > test_integration_connection_values_tcp.py chmod +x test_integration_connection_values_tcp.py test_integration_connection_values_tcp_udp.py: test_integration_connection_values_tcp_udp.py.in Makefile $(do_subst) < $(srcdir)/test_integration_connection_values_tcp_udp.py.in > test_integration_connection_values_tcp_udp.py chmod +x test_integration_connection_values_tcp_udp.py test_integration_connection_values_tcp_udp_http.py: test_integration_connection_values_tcp_udp_http.py.in Makefile $(do_subst) < $(srcdir)/test_integration_connection_values_tcp_udp_http.py.in > test_integration_connection_values_tcp_udp_http.py chmod +x test_integration_connection_values_tcp_udp_http.py # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/integration-tests/test_integration_clique_nat.py.in0000755000175000017500000001421011760502552022767 00000000000000#!@PYTHON@ # This file is part of GNUnet. # (C) 2010 Christian Grothoff (and other contributing authors) # # GNUnet is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2, or (at your # option) any later version. # # GNUnet is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNUnet; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # # # This test starts 3 peers (1 bootstrap server, 1 not nat'ed peer, 1 nat'ed peer) # and expects bootstrap and a connected clique # # Conditions for successful exit: # Both peers have 1 connected peer in transport, core, topology, fs import sys import os import subprocess import re import shutil import time import pexpect from gnunet_testing import Peer from gnunet_testing import Test from gnunet_testing import Check from gnunet_testing import Condition from gnunet_testing import * #definitions testname = "test_integration_clique_nat" verbose = True check_timeout = 180 def cleanup (): if os.name == "nt": shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_bootstrap_server"), True) shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_no_nat_client"), True) shutil.rmtree (os.path.join (os.getenv ("TEMP"), "c_nat_client"), True) else: shutil.rmtree ("/tmp/c_bootstrap_server/", True) shutil.rmtree ("/tmp/c_no_nat_client/", True) shutil.rmtree ("/tmp/c_nat_client/", True) def success_cont (check): global success success = True; def fail_cont (check): global success success= False; check.evaluate(True) def check_disconnect_client (): test.p ('Shutting down bootstrap client') client.stop () check = Check (test) check.add (StatisticsCondition (client2, 'transport', '# peers connected',0)) check.add (StatisticsCondition (client2, 'core', '# neighbour entries allocated',0)) check.add (StatisticsCondition (client2, 'core', '# peers connected',0)) check.add (StatisticsCondition (client2, 'topology', '# peers connected',0)) check.add (StatisticsCondition (client2, 'fs', '# peers connected',0)) check.run_blocking (check_timeout, success_cont, fail_cont) def success_disconnect_server_cont (check): check_disconnect_client () def fail_disconnect_server_cont (check): global success success= False; check.evaluate(False) def check_disconnect_server (): test.p ('Shutting down bootstrap server') server.stop () check = Check (test) check.add (StatisticsCondition (client, 'transport', '# peers connected',1)) check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',1)) check.add (StatisticsCondition (client, 'core', '# peers connected',1)) check.add (StatisticsCondition (client, 'topology', '# peers connected',1)) check.add (StatisticsCondition (client, 'fs', '# peers connected',1)) check.add (StatisticsCondition (client2, 'transport', '# peers connected',1)) check.add (StatisticsCondition (client2, 'core', '# neighbour entries allocated',1)) check.add (StatisticsCondition (client2, 'core', '# peers connected',1)) check.add (StatisticsCondition (client2, 'topology', '# peers connected',1)) check.add (StatisticsCondition (client2, 'fs', '# peers connected',1)) check.run_blocking (check_timeout, success_disconnect_server_cont, fail_disconnect_server_cont) def success_connect_cont (check): check_disconnect_server () def fail_connect_cont (check): global success success= False; check.evaluate(False) def check_connect (): check = Check (test) check.add (StatisticsCondition (client, 'transport', '# peers connected',2)) check.add (StatisticsCondition (client, 'core', '# neighbour entries allocated',2)) check.add (StatisticsCondition (client, 'core', '# peers connected',2)) check.add (StatisticsCondition (client, 'topology', '# peers connected',2)) check.add (StatisticsCondition (client, 'fs', '# peers connected',2)) check.add (StatisticsCondition (client2, 'transport', '# peers connected',2)) check.add (StatisticsCondition (client2, 'core', '# neighbour entries allocated',2)) check.add (StatisticsCondition (client2, 'core', '# peers connected',2)) check.add (StatisticsCondition (client2, 'topology', '# peers connected',2)) check.add (StatisticsCondition (client2, 'fs', '# peers connected',2)) check.add (StatisticsCondition (server, 'transport', '# peers connected',2)) check.add (StatisticsCondition (server, 'core', '# neighbour entries allocated',2)) check.add (StatisticsCondition (server, 'core', '# peers connected',2)) check.add (StatisticsCondition (server, 'topology', '# peers connected',2)) check.add (StatisticsCondition (server, 'fs', '# peers connected',2)) check.run_blocking (check_timeout, success_connect_cont, fail_connect_cont) # # Test execution # def run (): global success global test global server global client global client2 success = False test = Test ('test_integration_disconnect', verbose) server = Peer(test, './confs/c_bootstrap_server.conf'); server.start(); client = Peer(test, './confs/c_no_nat_client.conf'); client.start(); client2 = Peer(test, './confs/c_nat_client.conf'); client2.start(); if ((client.started == True) and (client2.started == True) and (server.started == True)): test.p ('Peers started, running check') check_connect () server.stop () client.stop () client2.stop () cleanup () if (success == False): print ('Test failed') return False else: return True try: run () except (KeyboardInterrupt, SystemExit): print 'Test interrupted' server.stop () client.stop () client2.stop () cleanup () if (success == False): sys.exit(1) else: sys.exit(0) gnunet-0.9.3/src/namestore/0000755000175000017500000000000011763406747012627 500000000000000gnunet-0.9.3/src/namestore/test_namestore_api_remove_not_existing_record.c0000644000175000017500000001744311760517404024304 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file namestore/test_namestore_api.c * @brief testcase for namestore_api.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_namestore_service.h" #include "namestore.h" #include "gnunet_signatures.h" #define VERBOSE GNUNET_NO #define RECORDS 5 #define TEST_RECORD_TYPE 1234 #define TEST_RECORD_DATALEN 123 #define TEST_RECORD_DATA 'a' #define TEST_REMOVE_RECORD_TYPE 4321 #define TEST_REMOVE_RECORD_DATALEN 255 #define TEST_REMOVE_RECORD_DATA 'b' #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) static struct GNUNET_NAMESTORE_Handle * nsh; static GNUNET_SCHEDULER_TaskIdentifier endbadly_task; static struct GNUNET_OS_Process *arm; static struct GNUNET_CRYPTO_RsaPrivateKey * privkey; static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubkey; struct GNUNET_CRYPTO_RsaSignature *s_signature; static GNUNET_HashCode s_zone; struct GNUNET_NAMESTORE_RecordData *s_rd; static char *s_name; static int res; static void start_arm (const char *cfgname) { arm = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, #if VERBOSE_PEERS "-L", "DEBUG", #else "-L", "ERROR", #endif NULL); } static void stop_arm () { if (NULL != arm) { if (0 != GNUNET_OS_process_kill (arm, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); GNUNET_OS_process_wait (arm); GNUNET_OS_process_destroy (arm); arm = NULL; } } /** * Re-establish the connection to the service. * * @param cls handle to use to re-connect. * @param tc scheduler context */ static void endbadly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (nsh != NULL) GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); nsh = NULL; if (privkey != NULL) GNUNET_CRYPTO_rsa_key_free (privkey); privkey = NULL; if (NULL != arm) stop_arm(); res = 1; } static void end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (endbadly_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (endbadly_task); endbadly_task = GNUNET_SCHEDULER_NO_TASK; } int c; for (c = 0; c < RECORDS; c++) GNUNET_free_non_null((void *) s_rd[c].data); GNUNET_free (s_rd); if (privkey != NULL) GNUNET_CRYPTO_rsa_key_free (privkey); privkey = NULL; if (nsh != NULL) GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); nsh = NULL; if (NULL != arm) stop_arm(); } void remove_cont (void *cls, int32_t success, const char *emsg) { char *name = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Remove record for `%s': %s `%s'\n", name, (success == GNUNET_YES) ? "SUCCESS" : "FAIL", emsg); if (GNUNET_NO == success) { res = 0; } else { res = 1; GNUNET_break (0); } GNUNET_SCHEDULER_add_now(&end, NULL); } void put_cont (void *cls, int32_t success, const char *emsg) { char *name = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Name store added record for `%s': %s\n", name, (success == GNUNET_OK) ? "SUCCESS" : "FAIL"); if (success == GNUNET_OK) { res = 0; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing non existing record for `%s'\n", name); struct GNUNET_NAMESTORE_RecordData rd; char data[TEST_REMOVE_RECORD_DATALEN]; rd.expiration = GNUNET_TIME_absolute_get(); rd.record_type = TEST_REMOVE_RECORD_TYPE; rd.data_size = TEST_REMOVE_RECORD_DATALEN; rd.data = &data; GNUNET_NAMESTORE_record_remove (nsh, privkey, name, &rd, &remove_cont, name); } else { res = 1; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to put records for name `%s'\n", name); GNUNET_SCHEDULER_add_now(&end, NULL); } } static struct GNUNET_NAMESTORE_RecordData * create_record (int count) { int c; struct GNUNET_NAMESTORE_RecordData * rd; rd = GNUNET_malloc (count * sizeof (struct GNUNET_NAMESTORE_RecordData)); for (c = 0; c < RECORDS; c++) { rd[c].expiration = GNUNET_TIME_absolute_get(); rd[c].record_type = TEST_RECORD_TYPE; rd[c].data_size = TEST_RECORD_DATALEN; rd[c].data = GNUNET_malloc(TEST_RECORD_DATALEN); memset ((char *) rd[c].data, TEST_RECORD_DATA, TEST_RECORD_DATALEN); } return rd; } void delete_existing_db (const struct GNUNET_CONFIGURATION_Handle *cfg) { char *afsdir; if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, "namestore-sqlite", "FILENAME", &afsdir)) { if (GNUNET_OK == GNUNET_DISK_file_test (afsdir)) if (GNUNET_OK == GNUNET_DISK_file_test (afsdir)) if (GNUNET_OK == GNUNET_DISK_directory_remove(afsdir)) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleted existing database `%s' \n", afsdir); GNUNET_free (afsdir); } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { delete_existing_db(cfg); endbadly_task = GNUNET_SCHEDULER_add_delayed(TIMEOUT,endbadly, NULL); size_t rd_ser_len; /* load privat key */ char *hostkey_file; GNUNET_asprintf(&hostkey_file,"zonefiles%s%s",DIR_SEPARATOR_STR, "N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using zonekey file `%s' \n", hostkey_file); privkey = GNUNET_CRYPTO_rsa_key_create_from_file(hostkey_file); GNUNET_free (hostkey_file); GNUNET_assert (privkey != NULL); /* get public key */ GNUNET_CRYPTO_rsa_key_get_public(privkey, &pubkey); /* create record */ s_name = "dummy.dummy.gnunet"; s_rd = create_record (RECORDS); rd_ser_len = GNUNET_NAMESTORE_records_get_size(RECORDS, s_rd); char rd_ser[rd_ser_len]; GNUNET_NAMESTORE_records_serialize(RECORDS, s_rd, rd_ser_len, rd_ser); /* sign */ s_signature = GNUNET_NAMESTORE_create_signature(privkey, s_rd[0].expiration, s_name, s_rd, RECORDS); /* create random zone hash */ GNUNET_CRYPTO_hash (&pubkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &s_zone); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Name: `%s' Zone: `%s' \n", s_name, GNUNET_h2s_full(&s_zone)); start_arm (cfgfile); GNUNET_assert (arm != NULL); nsh = GNUNET_NAMESTORE_connect (cfg); GNUNET_break (NULL != nsh); GNUNET_break (s_rd != NULL); GNUNET_break (s_name != NULL); GNUNET_NAMESTORE_record_put (nsh, &pubkey, s_name, GNUNET_TIME_UNIT_FOREVER_ABS, RECORDS, s_rd, s_signature, put_cont, s_name); } static int check () { static char *const argv[] = { "test-namestore-api", "-c", "test_namestore_api.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; res = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-namestore-api", "nohelp", options, &run, &res); return res; } int main (int argc, char *argv[]) { int ret; ret = check (); GNUNET_free (s_signature); return ret; } /* end of test_namestore_api.c */ gnunet-0.9.3/src/namestore/gnunet-service-namestore.c0000644000175000017500000017342111760515307017642 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file namestore/gnunet-service-namestore.c * @brief namestore for the GNUnet naming system * @author Matthias Wachs */ #include "platform.h" #include "gnunet_getopt_lib.h" #include "gnunet_service_lib.h" #include "gnunet_namestore_service.h" #include "gnunet_namestore_plugin.h" #include "gnunet_signatures.h" #include "namestore.h" #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) /** * A namestore operation. */ struct GNUNET_NAMESTORE_ZoneIteration { struct GNUNET_NAMESTORE_ZoneIteration *next; struct GNUNET_NAMESTORE_ZoneIteration *prev; struct GNUNET_NAMESTORE_Client * client; int has_zone; struct GNUNET_CRYPTO_ShortHashCode zone; uint64_t request_id; uint32_t offset; /** * Which flags must be included */ uint16_t must_have_flags; /** * Which flags must not be included */ uint16_t must_not_have_flags; }; /** * A namestore client */ struct GNUNET_NAMESTORE_Client { struct GNUNET_NAMESTORE_Client *next; struct GNUNET_NAMESTORE_Client *prev; struct GNUNET_SERVER_Client * client; struct GNUNET_NAMESTORE_ZoneIteration *op_head; struct GNUNET_NAMESTORE_ZoneIteration *op_tail; }; struct GNUNET_NAMESTORE_CryptoContainer { char * filename; struct GNUNET_CRYPTO_ShortHashCode zone; struct GNUNET_CRYPTO_RsaPrivateKey *privkey; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pubkey; }; /** * Configuration handle. */ const struct GNUNET_CONFIGURATION_Handle *GSN_cfg; /** * Database handle */ struct GNUNET_NAMESTORE_PluginFunctions *GSN_database; /** * Zonefile directory */ static char *zonefile_directory; static char *db_lib_name; /** * Our notification context. */ static struct GNUNET_SERVER_NotificationContext *snc; static struct GNUNET_NAMESTORE_Client *client_head; static struct GNUNET_NAMESTORE_Client *client_tail; struct GNUNET_CONTAINER_MultiHashMap *zonekeys; /** * Write zonefile to disk * @param filename where to write * @param c the crypto container * * @return GNUNET_OK on success, GNUNET_SYSERR on fail */ int write_key_to_file (const char *filename, struct GNUNET_NAMESTORE_CryptoContainer *c) { struct GNUNET_CRYPTO_RsaPrivateKey *ret = c->privkey; struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *enc; struct GNUNET_DISK_FileHandle *fd; if (GNUNET_YES == GNUNET_DISK_file_test (filename)) { struct GNUNET_CRYPTO_ShortHashCode zone; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubkey; struct GNUNET_CRYPTO_RsaPrivateKey * privkey; privkey = GNUNET_CRYPTO_rsa_key_create_from_file(filename); if (privkey == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("File zone `%s' but corrupt content already exists, failed to write! \n"), GNUNET_short_h2s (&zone)); return GNUNET_SYSERR; } GNUNET_CRYPTO_rsa_key_get_public (privkey, &pubkey); GNUNET_CRYPTO_short_hash (&pubkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &zone); GNUNET_CRYPTO_rsa_key_free (privkey); if (0 == memcmp (&zone, &c->zone, sizeof(zone))) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("File zone `%s' containing this key already exists\n"), GNUNET_short_h2s (&zone)); return GNUNET_OK; } else { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("File zone `%s' but different zone key already exists, failed to write! \n"), GNUNET_short_h2s (&zone)); return GNUNET_OK; } } fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_FAILIFEXISTS, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (NULL == fd) { if (errno == EEXIST) { if (GNUNET_YES != GNUNET_DISK_file_test (filename)) { /* must exist but not be accessible, fail for good! */ if (0 != ACCESS (filename, R_OK)) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", filename); else GNUNET_break (0); /* what is going on!? */ return GNUNET_SYSERR; } } LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename); return GNUNET_SYSERR; } if (GNUNET_YES != GNUNET_DISK_file_lock (fd, 0, sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded), GNUNET_YES)) { GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd)); return GNUNET_SYSERR; } enc = GNUNET_CRYPTO_rsa_encode_key (ret); GNUNET_assert (enc != NULL); GNUNET_assert (ntohs (enc->len) == GNUNET_DISK_file_write (fd, enc, ntohs (enc->len))); GNUNET_free (enc); GNUNET_DISK_file_sync (fd); if (GNUNET_YES != GNUNET_DISK_file_unlock (fd, 0, sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded))) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Stored zonekey for zone `%s' in file `%s'\n"), GNUNET_short_h2s(&c->zone), c->filename); return GNUNET_OK; } int zone_to_disk_it (void *cls, const GNUNET_HashCode *key, void *value) { struct GNUNET_NAMESTORE_CryptoContainer * c = value; if (c->filename != NULL) write_key_to_file(c->filename, c); else { GNUNET_asprintf(&c->filename, "%s/%s.zkey", zonefile_directory, GNUNET_short_h2s (&c->zone)); write_key_to_file(c->filename, c); } GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (zonekeys, key, value)); GNUNET_CRYPTO_rsa_key_free (c->privkey); GNUNET_free (c->pubkey); GNUNET_free (c->filename); GNUNET_free (c); return GNUNET_OK; } struct GNUNET_TIME_Absolute get_block_expiration_time (unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd) { unsigned int c; struct GNUNET_TIME_Absolute expire = GNUNET_TIME_UNIT_FOREVER_ABS; if (NULL == rd) return GNUNET_TIME_UNIT_ZERO_ABS; for (c = 0; c < rd_count; c++) expire = GNUNET_TIME_absolute_min (rd[c].expiration, expire); return expire; } /** * Task run during shutdown. * * @param cls unused * @param tc unused */ static void cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping namestore service\n"); struct GNUNET_NAMESTORE_ZoneIteration * no; struct GNUNET_NAMESTORE_ZoneIteration * tmp; struct GNUNET_NAMESTORE_Client * nc; struct GNUNET_NAMESTORE_Client * next; GNUNET_SERVER_notification_context_destroy (snc); snc = NULL; GNUNET_CONTAINER_multihashmap_iterate(zonekeys, &zone_to_disk_it, NULL); GNUNET_CONTAINER_multihashmap_destroy(zonekeys); for (nc = client_head; nc != NULL; nc = next) { next = nc->next; for (no = nc->op_head; no != NULL; no = tmp) { GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no); tmp = no->next; GNUNET_free (no); } GNUNET_SERVER_client_drop(nc->client); GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc); GNUNET_free (nc); } GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, GSN_database)); GNUNET_free (db_lib_name); GNUNET_free_non_null(zonefile_directory); } static struct GNUNET_NAMESTORE_Client * client_lookup (struct GNUNET_SERVER_Client *client) { struct GNUNET_NAMESTORE_Client * nc; GNUNET_assert (NULL != client); for (nc = client_head; nc != NULL; nc = nc->next) { if (client == nc->client) break; } return nc; } /** * Called whenever a client is disconnected. Frees our * resources associated with that client. * * @param cls closure * @param client identification of the client */ static void client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client) { struct GNUNET_NAMESTORE_ZoneIteration * no; struct GNUNET_NAMESTORE_Client * nc; if (NULL == client) return; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected \n", client); nc = client_lookup (client); if ((NULL == client) || (NULL == nc)) return; no = nc->op_head; while (NULL != no) { GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no); GNUNET_free (no); no = nc->op_head; } GNUNET_SERVER_client_drop(nc->client); GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc); GNUNET_free (nc); nc = NULL; } static void handle_start (void *cls, struct GNUNET_SERVER_Client * client, const struct GNUNET_MessageHeader * message) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client); struct GNUNET_NAMESTORE_Client * nc = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Client)); nc->client = client; GNUNET_SERVER_notification_context_add (snc, client); GNUNET_CONTAINER_DLL_insert(client_head, client_tail, nc); GNUNET_SERVER_client_keep (client); GNUNET_SERVER_receive_done (client, GNUNET_OK); } struct LookupNameContext { struct GNUNET_NAMESTORE_Client *nc; uint32_t request_id; uint32_t record_type; struct GNUNET_CRYPTO_ShortHashCode *zone; char * name; }; void drop_iterator (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *name, unsigned int rd_len, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { struct GNUNET_CRYPTO_ShortHashCode zone_hash; int * stop = cls; if (NULL != zone_key) { GNUNET_CRYPTO_short_hash(zone_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &zone_hash); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting zone `%s'\n", GNUNET_short_h2s (&zone_hash)); GSN_database->delete_zone (GSN_database->cls, &zone_hash); } else { (*stop) = GNUNET_YES; } } static void handle_lookup_name_it (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *name, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { /* send response */ struct LookupNameContext *lnc = cls; struct LookupNameResponseMessage *lnr_msg; struct GNUNET_NAMESTORE_RecordData *rd_selected = NULL; struct GNUNET_NAMESTORE_CryptoContainer *cc; struct GNUNET_CRYPTO_RsaSignature *signature_new = NULL; struct GNUNET_TIME_Absolute e; struct GNUNET_CRYPTO_ShortHashCode zone_key_hash; GNUNET_HashCode long_hash; char *rd_tmp; char *name_tmp; size_t rd_ser_len; size_t r_size = 0; size_t name_len = 0; int copied_elements = 0; int contains_signature = GNUNET_NO; int authoritative = GNUNET_NO; int c; if (NULL != name) name_len = strlen(name) + 1; /* count records to copy */ if (rd_count != 0) { if (lnc->record_type != 0) { /* special record type needed */ for (c = 0; c < rd_count; c ++) if (rd[c].record_type == lnc->record_type) copied_elements++; /* found matching record */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found %u records with type %u for name `%s' in zone `%s'\n", copied_elements, lnc->record_type, lnc->name, GNUNET_short_h2s(lnc->zone)); rd_selected = GNUNET_malloc (copied_elements * sizeof (struct GNUNET_NAMESTORE_RecordData)); copied_elements = 0; for (c = 0; c < rd_count; c ++) { if (rd[c].record_type == lnc->record_type) { /* found matching record */ memcpy (&rd_selected[copied_elements], &rd[c], sizeof (struct GNUNET_NAMESTORE_RecordData)); copied_elements++; } } } else { copied_elements = rd_count; rd_selected = (struct GNUNET_NAMESTORE_RecordData *) rd; } } else { /* No results */ copied_elements = 0; rd_selected = NULL; expire = GNUNET_TIME_UNIT_ZERO_ABS; } rd_ser_len = GNUNET_NAMESTORE_records_get_size(copied_elements, rd_selected); char rd_ser[rd_ser_len]; GNUNET_NAMESTORE_records_serialize(copied_elements, rd_selected, rd_ser_len, rd_ser); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found %u records for name `%s' in zone `%s'\n", copied_elements, lnc->name, GNUNET_short_h2s(lnc->zone)); if ((copied_elements == rd_count) && (NULL != signature)) contains_signature = GNUNET_YES; /* returning all records, so include signature */ else contains_signature = GNUNET_NO; /* returning not all records, so do not include signature */ if ((NULL != zone_key) && (copied_elements == rd_count)) { GNUNET_CRYPTO_short_hash(zone_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &zone_key_hash); GNUNET_CRYPTO_short_hash_double (&zone_key_hash, &long_hash); if (GNUNET_CONTAINER_multihashmap_contains(zonekeys, &long_hash)) { cc = GNUNET_CONTAINER_multihashmap_get(zonekeys, &long_hash); e = get_block_expiration_time(rd_count, rd); signature_new = GNUNET_NAMESTORE_create_signature(cc->privkey, e, name, rd, rd_count); GNUNET_assert (signature_new != NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating signature for name `%s' with %u records in zone `%s'\n",name, copied_elements, GNUNET_short_h2s(&zone_key_hash)); authoritative = GNUNET_YES; } else GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "I am not authoritative for name `%s' in zone `%s'\n",name, GNUNET_short_h2s(&zone_key_hash)); } r_size = sizeof (struct LookupNameResponseMessage) + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + name_len + rd_ser_len; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message\n", "NAMESTORE_LOOKUP_NAME_RESPONSE"); lnr_msg = GNUNET_malloc (r_size); lnr_msg->gns_header.header.type = ntohs (GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME_RESPONSE); lnr_msg->gns_header.header.size = ntohs (r_size); lnr_msg->gns_header.r_id = htonl (lnc->request_id); lnr_msg->rd_count = htons (copied_elements); lnr_msg->rd_len = htons (rd_ser_len); lnr_msg->name_len = htons (name_len); lnr_msg->expire = GNUNET_TIME_absolute_hton(get_block_expiration_time(copied_elements, rd_selected)); if (rd_selected != rd) GNUNET_free (rd_selected); if (zone_key != NULL) lnr_msg->public_key = (*zone_key); else memset(&lnr_msg->public_key, '\0', sizeof (lnr_msg->public_key)); if (GNUNET_YES == authoritative) { /* use new created signature */ lnr_msg->contains_sig = htons (GNUNET_YES); GNUNET_assert (signature_new != NULL); lnr_msg->signature = *signature_new; GNUNET_free (signature_new); } else if (GNUNET_YES == contains_signature) { /* use existing signature */ lnr_msg->contains_sig = htons (GNUNET_YES); GNUNET_assert (signature != NULL); lnr_msg->signature = *signature; } else { /* use no signature */ memset (&lnr_msg->signature, '\0', sizeof (lnr_msg->signature)); } name_tmp = (char *) &lnr_msg[1]; rd_tmp = &name_tmp[name_len]; memcpy (name_tmp, name, name_len); memcpy (rd_tmp, rd_ser, rd_ser_len); GNUNET_SERVER_notification_context_unicast (snc, lnc->nc->client, (const struct GNUNET_MessageHeader *) lnr_msg, GNUNET_NO); GNUNET_free (lnr_msg); } static void handle_lookup_name (void *cls, struct GNUNET_SERVER_Client * client, const struct GNUNET_MessageHeader * message) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "NAMESTORE_LOOKUP_NAME"); struct LookupNameContext lnc; struct GNUNET_NAMESTORE_Client *nc; size_t name_len; char * name; uint32_t rid = 0; uint32_t type = 0; if (ntohs (message->size) < sizeof (struct LookupNameMessage)) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } nc = client_lookup(client); if (nc == NULL) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } struct LookupNameMessage * ln_msg = (struct LookupNameMessage *) message; rid = ntohl (ln_msg->gns_header.r_id); name_len = ntohl (ln_msg->name_len); type = ntohl (ln_msg->record_type); if ((name_len == 0) || (name_len > 256)) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } name = (char *) &ln_msg[1]; if (name[name_len -1] != '\0') { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } if (0 == type) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking up all records for name `%s' in zone `%s'\n", name, GNUNET_short_h2s(&ln_msg->zone)); else GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking up records with type %u for name `%s' in zone `%s'\n", type, name, GNUNET_short_h2s(&ln_msg->zone)); /* do the actual lookup */ lnc.request_id = rid; lnc.nc = nc; lnc.record_type = type; lnc.name = name; lnc.zone = &ln_msg->zone; GSN_database->iterate_records(GSN_database->cls, &ln_msg->zone, name, 0, &handle_lookup_name_it, &lnc); GNUNET_SERVER_receive_done (client, GNUNET_OK); } static void handle_record_put (void *cls, struct GNUNET_SERVER_Client * client, const struct GNUNET_MessageHeader * message) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "NAMESTORE_RECORD_PUT"); struct GNUNET_NAMESTORE_Client *nc; struct GNUNET_TIME_Absolute expire; struct GNUNET_CRYPTO_RsaSignature *signature; struct RecordPutResponseMessage rpr_msg; size_t name_len; size_t msg_size; size_t msg_size_exp; char * name; char * rd_ser; uint32_t rid = 0; uint32_t rd_ser_len; uint32_t rd_count; int res = GNUNET_SYSERR; if (ntohs (message->size) < sizeof (struct RecordPutMessage)) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } nc = client_lookup (client); if (nc == NULL) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } struct RecordPutMessage * rp_msg = (struct RecordPutMessage *) message; rid = ntohl (rp_msg->gns_header.r_id); msg_size = ntohs (rp_msg->gns_header.header.size); name_len = ntohs (rp_msg->name_len); rd_count = ntohs (rp_msg->rd_count); rd_ser_len = ntohs(rp_msg->rd_len); if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } if ((rd_count < 1) || (rd_ser_len < 1) || (name_len >=256) || (name_len == 0)) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } msg_size_exp = sizeof (struct RecordPutMessage) + name_len + rd_ser_len; if (msg_size != msg_size_exp) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Expected message %u size but message size is %u \n", msg_size_exp, msg_size); GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } if ((name_len == 0) || (name_len > 256)) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } name = (char *) &rp_msg[1]; if (name[name_len -1] != '\0') { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } expire = GNUNET_TIME_absolute_ntoh(rp_msg->expire); signature = (struct GNUNET_CRYPTO_RsaSignature *) &rp_msg->signature; rd_ser = &name[name_len]; struct GNUNET_NAMESTORE_RecordData rd[rd_count]; res = GNUNET_NAMESTORE_records_deserialize(rd_ser_len, rd_ser, rd_count, rd); if (res != GNUNET_OK) { GNUNET_break_op (0); goto send; } struct GNUNET_CRYPTO_ShortHashCode zone_hash; GNUNET_CRYPTO_short_hash (&rp_msg->public_key, sizeof (rp_msg->public_key), &zone_hash); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Putting %u record for name `%s' in zone `%s'\n", rd_count, name, GNUNET_short_h2s(&zone_hash)); /* Database operation */ res = GSN_database->put_records(GSN_database->cls, &rp_msg->public_key, expire, name, rd_count, rd, signature); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Putting record for name `%s': %s\n", name, (res == GNUNET_OK) ? "OK" : "FAIL"); /* Send response */ send: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message\n", "RECORD_PUT_RESPONSE"); rpr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT_RESPONSE); rpr_msg.gns_header.header.size = htons (sizeof (struct RecordPutResponseMessage)); rpr_msg.gns_header.r_id = htonl (rid); rpr_msg.op_result = htonl (res); GNUNET_SERVER_notification_context_unicast (snc, nc->client, (const struct GNUNET_MessageHeader *) &rpr_msg, GNUNET_NO); GNUNET_SERVER_receive_done (client, GNUNET_OK); } struct CreateRecordContext { struct GNUNET_NAMESTORE_RecordData *rd; struct GNUNET_CRYPTO_RsaPrivateKey *pkey; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pubkey; struct GNUNET_TIME_Absolute expire; char *name; int res; }; static void handle_create_record_it (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pubkey, struct GNUNET_TIME_Absolute expire, const char *name, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { struct CreateRecordContext * crc = cls; struct GNUNET_NAMESTORE_RecordData *rd_new = NULL; struct GNUNET_CRYPTO_RsaSignature dummy_signature; struct GNUNET_TIME_Absolute block_expiration; int res; int exist = GNUNET_SYSERR; int update = GNUNET_NO; int c; int rd_count_new = 0; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found %u existing records for `%s'\n", rd_count, crc->name); for (c = 0; c < rd_count; c++) { if ((crc->rd->record_type == GNUNET_NAMESTORE_TYPE_PKEY) && (rd[c].record_type == GNUNET_NAMESTORE_TYPE_PKEY)) { /* Update unique PKEY */ exist = c; update = GNUNET_YES; break; } else if ((crc->rd->record_type == GNUNET_NAMESTORE_TYPE_PSEU) && (rd[c].record_type == GNUNET_NAMESTORE_TYPE_PSEU)) { /* Update unique PSEU */ exist = c; update = GNUNET_YES; break; } else if ((crc->rd->record_type == rd[c].record_type) && (crc->rd->data_size == rd[c].data_size) && (0 == memcmp (crc->rd->data, rd[c].data, rd[c].data_size))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found existing records for `%s' to update expiration date!\n", crc->name); exist = c; if (crc->rd->expiration.abs_value != rd[c].expiration.abs_value) update = GNUNET_YES; break; } } if (exist == GNUNET_SYSERR) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New record does not exist for name `%s'!\n", crc->name); if (exist == GNUNET_SYSERR) { rd_new = GNUNET_malloc ((rd_count+1) * sizeof (struct GNUNET_NAMESTORE_RecordData)); memcpy (rd_new, rd, rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData)); rd_count_new = rd_count + 1; rd_new[rd_count] = *(crc->rd); } else if (update == GNUNET_NO) { /* Exact same record already exists */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No update for %s' record required!\n", crc->name); res = GNUNET_NO; goto end; } else if (update == GNUNET_YES) { /* Update record */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating existing records for `%s'!\n", crc->name); rd_new = GNUNET_malloc ((rd_count) * sizeof (struct GNUNET_NAMESTORE_RecordData)); memcpy (rd_new, rd, rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData)); rd_count_new = rd_count; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating expiration from %llu to %llu!\n", rd_new[exist].expiration.abs_value, crc->rd->expiration.abs_value); rd_new[exist] = *(crc->rd); } block_expiration = GNUNET_TIME_absolute_max(crc->expire, expire); if (block_expiration.abs_value != expire.abs_value) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updated block expiration time\n"); memset (&dummy_signature, '\0', sizeof (dummy_signature)); /* Database operation */ GNUNET_assert ((rd_new != NULL) && (rd_count_new > 0)); res = GSN_database->put_records(GSN_database->cls, (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *) crc->pubkey, block_expiration, crc->name, rd_count_new, rd_new, &dummy_signature); GNUNET_break (GNUNET_OK == res); if (res == GNUNET_OK) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully put record for `%s' in database \n", crc->name); else GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to put record for `%s' in database \n", crc->name); res = GNUNET_YES; end: GNUNET_free_non_null (rd_new); switch (res) { case GNUNET_SYSERR: /* failed to create the record */ crc->res = GNUNET_SYSERR; break; case GNUNET_YES: /* database operations OK */ if (GNUNET_YES == update) { /* we updated an existing record */ crc->res = GNUNET_NO; } else { /* we created a new record */ crc->res = GNUNET_YES; } break; case GNUNET_NO: /* identical entry existed, so we did nothing */ crc->res = GNUNET_NO; break; default: break; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Update result for name `%s' %u\n", crc->name, res); } static void handle_record_create (void *cls, struct GNUNET_SERVER_Client * client, const struct GNUNET_MessageHeader * message) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "NAMESTORE_RECORD_CREATE"); struct GNUNET_NAMESTORE_Client *nc; struct GNUNET_NAMESTORE_CryptoContainer *cc; struct CreateRecordContext crc; struct GNUNET_CRYPTO_RsaPrivateKey *pkey; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub; struct RecordCreateResponseMessage rcr_msg; struct GNUNET_CRYPTO_ShortHashCode pubkey_hash; GNUNET_HashCode long_hash; size_t name_len; size_t msg_size; size_t msg_size_exp; size_t rd_ser_len; size_t key_len; uint32_t rid = 0; char *pkey_tmp; char *name_tmp; char *rd_ser; int rd_count; int res = GNUNET_SYSERR; crc.res = GNUNET_SYSERR; if (ntohs (message->size) < sizeof (struct RecordCreateMessage)) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } nc = client_lookup(client); if (nc == NULL) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } struct RecordCreateMessage * rp_msg = (struct RecordCreateMessage *) message; rid = ntohl (rp_msg->gns_header.r_id); name_len = ntohs (rp_msg->name_len); msg_size = ntohs (message->size); rd_count = ntohs (rp_msg->rd_count); rd_ser_len = ntohs (rp_msg->rd_len); key_len = ntohs (rp_msg->pkey_len); msg_size_exp = sizeof (struct RecordCreateMessage) + key_len + name_len + rd_ser_len; if (msg_size != msg_size_exp) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Expected message %u size but message size is %u \n", msg_size_exp, msg_size); GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } if ((name_len == 0) || (name_len > 256)) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } pkey_tmp = (char *) &rp_msg[1]; name_tmp = &pkey_tmp[key_len]; rd_ser = &name_tmp[name_len]; if (name_tmp[name_len -1] != '\0') { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } struct GNUNET_NAMESTORE_RecordData rd[rd_count]; res = GNUNET_NAMESTORE_records_deserialize(rd_ser_len, rd_ser, rd_count, rd); if ((res != GNUNET_OK) || (rd_count != 1)) { GNUNET_break_op (0); goto send; } /* Extracting and converting private key */ pkey = GNUNET_CRYPTO_rsa_decode_key((char *) pkey_tmp, key_len); GNUNET_assert (pkey != NULL); GNUNET_CRYPTO_rsa_key_get_public(pkey, &pub); GNUNET_CRYPTO_short_hash (&pub, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &pubkey_hash); GNUNET_CRYPTO_short_hash_double (&pubkey_hash, &long_hash); if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(zonekeys, &long_hash)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received new private key for zone `%s'\n",GNUNET_short_h2s(&pubkey_hash)); cc = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_CryptoContainer)); cc->privkey = GNUNET_CRYPTO_rsa_decode_key((char *) pkey_tmp, key_len); cc->pubkey = GNUNET_malloc(sizeof (pub)); memcpy (cc->pubkey, &pub, sizeof(pub)); cc->zone = pubkey_hash; GNUNET_CONTAINER_multihashmap_put(zonekeys, &long_hash, cc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); } crc.expire = GNUNET_TIME_absolute_ntoh(rp_msg->expire); crc.res = GNUNET_SYSERR; crc.pkey = pkey; crc.pubkey = &pub; crc.rd = rd; crc.name = name_tmp; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating record for name `%s' in zone `%s'\n", name_tmp, GNUNET_short_h2s(&pubkey_hash)); /* Get existing records for name */ res = GSN_database->iterate_records(GSN_database->cls, &pubkey_hash, name_tmp, 0, &handle_create_record_it, &crc); if (res != GNUNET_SYSERR) res = GNUNET_OK; GNUNET_CRYPTO_rsa_key_free(pkey); pkey = NULL; /* Send response */ send: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message\n", "RECORD_CREATE_RESPONSE"); rcr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE_RESPONSE); rcr_msg.gns_header.header.size = htons (sizeof (struct RecordCreateResponseMessage)); rcr_msg.gns_header.r_id = htonl (rid); if ((GNUNET_OK == res) && (crc.res == GNUNET_YES)) rcr_msg.op_result = htonl (GNUNET_YES); else if ((GNUNET_OK == res) && (crc.res == GNUNET_NO)) rcr_msg.op_result = htonl (GNUNET_NO); else rcr_msg.op_result = htonl (GNUNET_SYSERR); GNUNET_SERVER_notification_context_unicast (snc, nc->client, (const struct GNUNET_MessageHeader *) &rcr_msg, GNUNET_NO); GNUNET_SERVER_receive_done (client, GNUNET_OK); } struct RemoveRecordContext { struct GNUNET_NAMESTORE_RecordData *rd; struct GNUNET_CRYPTO_RsaPrivateKey *pkey; int remove_name; uint16_t op_res; }; static void handle_record_remove_it (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *name, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { struct RemoveRecordContext *rrc = cls; unsigned int c; int res; int found; unsigned int rd_count_new; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Name `%s 'currently has %u records\n", name, rd_count); if (rd_count == 0) { /* Could not find record to remove */ rrc->op_res = 1; return; } /* Find record to remove */ found = GNUNET_SYSERR; for (c = 0; c < rd_count; c++) { /* if (rd[c].flags != rrc->rd->flags) continue;*/ if (rd[c].record_type != rrc->rd->record_type) continue; /* if (rd[c].data_size != rrc->rd->data_size) continue; GNUNET_break(0); if (0 != memcmp (rd[c].data, rrc->rd->data, rrc->rd->data_size)) continue; GNUNET_break(0); */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found record to remove!\n", rd_count); found = c; break; } if (GNUNET_SYSERR == found) { /* Could not find record to remove */ rrc->op_res = 2; return; } if (rd_count-1 == 0) { struct GNUNET_CRYPTO_ShortHashCode pubkey_hash; GNUNET_CRYPTO_short_hash (zone_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &pubkey_hash); res = GSN_database->remove_records (GSN_database->cls, &pubkey_hash, name); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No records left for name `%s', removing name\n", name, res); if (GNUNET_OK != res) { /* Could put records into database */ rrc->op_res = 4; return; } rrc->op_res = 0; return; } rd_count_new = rd_count -1; struct GNUNET_NAMESTORE_RecordData rd_new[rd_count_new]; unsigned int c2 = 0; for (c = 0; c < rd_count; c++) { if (c != found) { GNUNET_assert (c2 < rd_count_new); rd_new[c2] = rd[c]; c2++; } } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Name `%s' now has %u records\n", name, rd_count_new); /* Create dummy signature */ struct GNUNET_CRYPTO_RsaSignature dummy_signature; memset (&dummy_signature, '\0', sizeof (dummy_signature)); /* Put records */ res = GSN_database->put_records(GSN_database->cls, zone_key, expire, name, rd_count_new, rd_new, &dummy_signature); if (GNUNET_OK != res) { /* Could put records into database */ rrc->op_res = 4; return; } rrc->op_res = 0; } static void handle_record_remove (void *cls, struct GNUNET_SERVER_Client * client, const struct GNUNET_MessageHeader * message) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "NAMESTORE_RECORD_REMOVE"); struct GNUNET_NAMESTORE_Client *nc; struct RecordRemoveResponseMessage rrr_msg; struct GNUNET_CRYPTO_RsaPrivateKey *pkey; struct GNUNET_NAMESTORE_CryptoContainer *cc = NULL; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub; struct GNUNET_CRYPTO_ShortHashCode pubkey_hash; GNUNET_HashCode long_hash; char * pkey_tmp = NULL; char * name_tmp = NULL; char * rd_ser = NULL; size_t key_len = 0; size_t name_len = 0; size_t rd_ser_len = 0; size_t msg_size = 0; size_t msg_size_exp = 0; uint32_t rd_count; uint32_t rid = 0; int res = GNUNET_SYSERR; if (ntohs (message->size) < sizeof (struct RecordRemoveMessage)) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } nc = client_lookup(client); if (nc == NULL) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } struct RecordRemoveMessage * rr_msg = (struct RecordRemoveMessage *) message; rid = ntohl (rr_msg->gns_header.r_id); name_len = ntohs (rr_msg->name_len); rd_ser_len = ntohs (rr_msg->rd_len); rd_count = ntohs (rr_msg->rd_count); key_len = ntohs (rr_msg->pkey_len); msg_size = ntohs (message->size); if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } if ((name_len >=256) || (name_len == 0)) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } msg_size_exp = sizeof (struct RecordRemoveMessage) + key_len + name_len + rd_ser_len; if (msg_size != msg_size_exp) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Expected message %u size but message size is %u \n", msg_size_exp, msg_size); GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } pkey_tmp = (char *) &rr_msg[1]; name_tmp = &pkey_tmp[key_len]; rd_ser = &name_tmp[name_len]; if ((name_len == 0) || (name_len > 256)) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } if (name_tmp[name_len -1] != '\0') { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } /* Extracting and converting private key */ pkey = GNUNET_CRYPTO_rsa_decode_key((char *) pkey_tmp, key_len); GNUNET_assert (pkey != NULL); GNUNET_CRYPTO_rsa_key_get_public(pkey, &pub); GNUNET_CRYPTO_short_hash (&pub, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &pubkey_hash); GNUNET_CRYPTO_short_hash_double (&pubkey_hash, &long_hash); if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(zonekeys, &long_hash)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received new private key for zone `%s'\n",GNUNET_short_h2s(&pubkey_hash)); cc = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_CryptoContainer)); cc->privkey = GNUNET_CRYPTO_rsa_decode_key((char *) pkey_tmp, key_len); cc->pubkey = GNUNET_malloc(sizeof (pub)); memcpy (cc->pubkey, &pub, sizeof(pub)); cc->zone = pubkey_hash; GNUNET_CONTAINER_multihashmap_put(zonekeys, &long_hash, cc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); } struct GNUNET_NAMESTORE_RecordData rd[rd_count]; res = GNUNET_NAMESTORE_records_deserialize(rd_ser_len, rd_ser, rd_count, rd); if ((res != GNUNET_OK) || (rd_count > 1)) { GNUNET_break_op (0); goto send; } if (0 == rd_count) { /* remove the whole name and all records */ /* Database operation */ res = GSN_database->remove_records (GSN_database->cls, &pubkey_hash, name_tmp); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing name `%s': %s\n", name_tmp, (GNUNET_OK == res) ? "OK" : "FAIL"); if (GNUNET_OK != res) /* Could not remove entry from database */ res = 4; else res = 0; } else { /* remove a single record */ struct RemoveRecordContext rrc; rrc.rd = rd; rrc.pkey = pkey; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing record for name `%s' in zone `%s'\n", name_tmp, GNUNET_short_h2s(&pubkey_hash)); /* Database operation */ res = GSN_database->iterate_records (GSN_database->cls, &pubkey_hash, name_tmp, 0, handle_record_remove_it, &rrc); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing record for name `%s': %s\n", name_tmp, (rrc.op_res == 0) ? "OK" : "FAIL"); res = rrc.op_res; } /* Send response */ send: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message\n", "RECORD_REMOVE_RESPONSE"); rrr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE_RESPONSE); rrr_msg.gns_header.header.size = htons (sizeof (struct RecordRemoveResponseMessage)); rrr_msg.gns_header.r_id = htonl (rid); rrr_msg.op_result = htonl (res); GNUNET_SERVER_notification_context_unicast (snc, nc->client, (const struct GNUNET_MessageHeader *) &rrr_msg, GNUNET_NO); GNUNET_CRYPTO_rsa_key_free (pkey); GNUNET_SERVER_receive_done (client, GNUNET_OK); } struct ZoneToNameCtx { struct GNUNET_NAMESTORE_Client *nc; uint32_t rid; }; static void handle_zone_to_name_it (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *name, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { struct ZoneToNameCtx * ztn_ctx = cls; struct ZoneToNameResponseMessage *ztnr_msg; int16_t res = GNUNET_SYSERR; uint16_t name_len = 0; uint16_t rd_ser_len = 0 ; int32_t contains_sig = 0; size_t msg_size = 0; char *rd_ser = NULL; char *name_tmp; char *rd_tmp; char *sig_tmp; if ((zone_key != NULL) && (name != NULL)) { /* found result */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found results: name is `%s', has %u records\n", name, rd_count); res = GNUNET_YES; name_len = strlen (name) +1; } else { /* no result found */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found no results\n"); res = GNUNET_NO; name_len = 0; } if (rd_count > 0) { rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd); rd_ser = GNUNET_malloc (rd_ser_len); GNUNET_NAMESTORE_records_serialize(rd_count, rd, rd_ser_len, rd_ser); } else rd_ser_len = 0; if (signature != NULL) contains_sig = GNUNET_YES; else contains_sig = GNUNET_NO; msg_size = sizeof (struct ZoneToNameResponseMessage) + name_len + rd_ser_len + contains_sig * sizeof (struct GNUNET_CRYPTO_RsaSignature); ztnr_msg = GNUNET_malloc (msg_size); name_tmp = (char *) &ztnr_msg[1]; rd_tmp = &name_tmp[name_len]; sig_tmp = &rd_tmp[rd_ser_len]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message\n", "ZONE_TO_NAME_RESPONSE"); ztnr_msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE); ztnr_msg->gns_header.header.size = htons (msg_size); ztnr_msg->gns_header.r_id = htonl (ztn_ctx->rid); ztnr_msg->res = htons (res); ztnr_msg->rd_len = htons (rd_ser_len); ztnr_msg->rd_count = htons (rd_count); ztnr_msg->name_len = htons (name_len); ztnr_msg->expire = GNUNET_TIME_absolute_hton(expire); if (zone_key != NULL) ztnr_msg->zone_key = *zone_key; else memset (&ztnr_msg->zone_key, '\0', sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); if ((name_len > 0) && (name != NULL)) memcpy (name_tmp, name, name_len); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Name is `%s', has %u records, rd ser len %u msg_size %u\n", name, rd_count, rd_ser_len, msg_size); if ((rd_ser_len > 0) && (rd_ser != NULL)) memcpy (rd_tmp, rd_ser, rd_ser_len); if ((GNUNET_YES == contains_sig) && (signature != NULL)) memcpy (sig_tmp, signature, contains_sig * sizeof (struct GNUNET_CRYPTO_RsaSignature)); GNUNET_SERVER_notification_context_unicast (snc, ztn_ctx->nc->client, (const struct GNUNET_MessageHeader *) ztnr_msg, GNUNET_NO); GNUNET_free (ztnr_msg); GNUNET_free_non_null (rd_ser); } static void handle_zone_to_name (void *cls, struct GNUNET_SERVER_Client * client, const struct GNUNET_MessageHeader * message) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_TO_NAME"); struct GNUNET_NAMESTORE_Client *nc; struct ZoneToNameCtx ztn_ctx; size_t msg_size = 0; uint32_t rid = 0; if (ntohs (message->size) != sizeof (struct ZoneToNameMessage)) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } nc = client_lookup(client); if (nc == NULL) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } struct ZoneToNameMessage *ztn_msg = (struct ZoneToNameMessage *) message; if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } rid = ntohl (ztn_msg->gns_header.r_id); ztn_ctx.rid = rid; ztn_ctx.nc = nc; struct GNUNET_CRYPTO_ShortHashAsciiEncoded z_tmp; GNUNET_CRYPTO_short_hash_to_enc(&ztn_msg->zone, &z_tmp); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking up name for zone `%s' in zone `%s'\n", (char *) &z_tmp, GNUNET_short_h2s (&ztn_msg->value_zone)); GSN_database->zone_to_name (GSN_database->cls, &ztn_msg->zone, &ztn_msg->value_zone, &handle_zone_to_name_it, &ztn_ctx); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Copy record, data has to be free separetely */ void copy_record (const struct GNUNET_NAMESTORE_RecordData *src, struct GNUNET_NAMESTORE_RecordData *dest) { memcpy (dest, src, sizeof (struct GNUNET_NAMESTORE_RecordData)); dest->data = GNUNET_malloc (src->data_size); memcpy ((void *) dest->data, src->data, src->data_size); } struct ZoneIterationProcResult { struct GNUNET_NAMESTORE_ZoneIteration *zi; int res_iteration_finished; int records_included; int has_signature; char *name; struct GNUNET_CRYPTO_ShortHashCode zone_hash; struct GNUNET_NAMESTORE_RecordData *rd; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded zone_key; struct GNUNET_CRYPTO_RsaSignature signature; struct GNUNET_TIME_Absolute expire; }; void zone_iteraterate_proc (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *name, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { struct ZoneIterationProcResult *proc = cls; struct GNUNET_NAMESTORE_RecordData *rd_filtered; struct GNUNET_CRYPTO_RsaSignature * new_signature; struct GNUNET_NAMESTORE_CryptoContainer *cc; struct GNUNET_CRYPTO_ShortHashCode hash; GNUNET_HashCode long_hash; struct GNUNET_TIME_Absolute e; unsigned int rd_count_filtered = 0; int include; int c; proc->res_iteration_finished = GNUNET_NO; proc->records_included = 0; if ((zone_key == NULL) && (name == NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Iteration done\n"); proc->res_iteration_finished = GNUNET_YES; proc->rd = NULL; proc->name = NULL; } else if ((zone_key != NULL) && (name != NULL)) /* just a safety check */ { rd_filtered = GNUNET_malloc (rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received result for zone iteration: `%s'\n", name); for (c = 0; c < rd_count; c++) { include = GNUNET_YES; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: 0x%x must have 0x%x \n", c, rd[c].flags, proc->zi->must_have_flags); /* Checking must have flags */ if ((rd[c].flags & proc->zi->must_have_flags) == proc->zi->must_have_flags) { /* Include */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: Include \n", c); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: Not include \n", c); include = GNUNET_NO; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: 0x%x must not have 0x%x\n", c, rd[c].flags, proc->zi->must_not_have_flags); if ((rd[c].flags & proc->zi->must_not_have_flags) != 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: Not include \n", c); include = GNUNET_NO; } else { /* Include */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: Include \n", c); } if (GNUNET_YES == include) { copy_record (&rd[c], &rd_filtered[rd_count_filtered]); rd_count_filtered++; } } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Included %i of %i records \n", rd_count_filtered, rd_count); proc->records_included = rd_count_filtered; if (0 == rd_count_filtered) { GNUNET_free (rd_filtered); rd_filtered = NULL; } proc->rd = rd_filtered; proc->name = GNUNET_strdup(name); memcpy (&proc->zone_key, zone_key, sizeof (proc->zone_key)); /* Signature */ proc->has_signature = GNUNET_NO; GNUNET_CRYPTO_short_hash (zone_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &hash); GNUNET_CRYPTO_short_hash_double(&hash, &long_hash); proc->zone_hash = hash; if (GNUNET_CONTAINER_multihashmap_contains(zonekeys, &long_hash)) { cc = GNUNET_CONTAINER_multihashmap_get(zonekeys, &long_hash); e = get_block_expiration_time(rd_count_filtered, rd_filtered); proc->expire = e; new_signature = GNUNET_NAMESTORE_create_signature(cc->privkey, e, name, rd_filtered, rd_count_filtered); GNUNET_assert (signature != NULL); proc->signature = (*new_signature); GNUNET_free (new_signature); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating signature for `%s' in zone `%s' with %u records and expiration %llu\n", name, GNUNET_short_h2s(&hash), rd_count_filtered, e.abs_value); proc->has_signature = GNUNET_YES; } else if (rd_count_filtered == rd_count) { proc->expire = expire; if (NULL != signature) { proc->signature = (*signature); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using provided signature for `%s' in zone `%s' with %u records and expiration %llu\n", name, GNUNET_short_h2s(&hash), rd_count_filtered, expire.abs_value); proc->has_signature = GNUNET_YES; } else { memset (&proc->signature, '\0', sizeof (proc->signature)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No signature provided for `%s'\n", name); } } } else { GNUNET_break (0); return; } } void find_next_zone_iteration_result (struct ZoneIterationProcResult *proc) { struct GNUNET_CRYPTO_ShortHashCode *zone; if (GNUNET_YES == proc->zi->has_zone) zone = &proc->zi->zone; else zone = NULL; do { GSN_database->iterate_records (GSN_database->cls, zone , NULL, proc->zi->offset, &zone_iteraterate_proc, proc); proc->zi->offset++; } while ((proc->records_included == 0) && (GNUNET_NO == proc->res_iteration_finished)); } void send_zone_iteration_result (struct ZoneIterationProcResult *proc) { struct GNUNET_NAMESTORE_ZoneIteration *zi = proc->zi; if (GNUNET_YES == proc->res_iteration_finished) { struct ZoneIterationResponseMessage zir_msg; if (zi->has_zone == GNUNET_YES) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No more results for zone `%s'\n", GNUNET_short_h2s(&zi->zone)); else GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No more results for all zones\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending empty `%s' message\n", "ZONE_ITERATION_RESPONSE"); zir_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE); zir_msg.gns_header.header.size = htons (sizeof (struct ZoneIterationResponseMessage)); zir_msg.gns_header.r_id = htonl(zi->request_id); zir_msg.expire = GNUNET_TIME_absolute_hton(GNUNET_TIME_UNIT_ZERO_ABS); zir_msg.name_len = htons (0); zir_msg.reserved = htons (0); zir_msg.rd_count = htons (0); zir_msg.rd_len = htons (0); memset (&zir_msg.public_key, '\0', sizeof (zir_msg.public_key)); memset (&zir_msg.signature, '\0', sizeof (zir_msg.signature)); GNUNET_SERVER_notification_context_unicast (snc, zi->client->client, (const struct GNUNET_MessageHeader *) &zir_msg, GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing zone iterator\n"); GNUNET_CONTAINER_DLL_remove (zi->client->op_head, zi->client->op_tail, zi); GNUNET_free (zi); return; } else { GNUNET_assert (proc->records_included > 0); struct ZoneIterationResponseMessage *zir_msg; if (zi->has_zone == GNUNET_YES) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending name `%s' for iteration over zone `%s'\n", proc->name, GNUNET_short_h2s(&zi->zone)); if (zi->has_zone == GNUNET_NO) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending name `%s' for iteration over all zones\n", proc->name); size_t name_len; size_t rd_ser_len; size_t msg_size; char *name_tmp; char *rd_tmp; name_len = strlen (proc->name) +1; rd_ser_len = GNUNET_NAMESTORE_records_get_size(proc->records_included, proc->rd); char rd_ser[rd_ser_len]; GNUNET_NAMESTORE_records_serialize(proc->records_included, proc->rd, rd_ser_len, rd_ser); msg_size = sizeof (struct ZoneIterationResponseMessage) + name_len + rd_ser_len; zir_msg = GNUNET_malloc(msg_size); name_tmp = (char *) &zir_msg[1]; rd_tmp = &name_tmp[name_len]; zir_msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE); zir_msg->gns_header.header.size = htons (msg_size); zir_msg->gns_header.r_id = htonl(zi->request_id); zir_msg->expire = GNUNET_TIME_absolute_hton(proc->expire); zir_msg->reserved = htons (0); zir_msg->name_len = htons (name_len); zir_msg->rd_count = htons (proc->records_included); zir_msg->rd_len = htons (rd_ser_len); zir_msg->signature = proc->signature; zir_msg->public_key = proc->zone_key; memcpy (name_tmp, proc->name, name_len); memcpy (rd_tmp, rd_ser, rd_ser_len); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with size %u\n", "ZONE_ITERATION_RESPONSE", msg_size); GNUNET_SERVER_notification_context_unicast (snc, zi->client->client, (const struct GNUNET_MessageHeader *) zir_msg, GNUNET_NO); GNUNET_free (zir_msg); } } void clean_up_zone_iteration_result (struct ZoneIterationProcResult *proc) { int c; GNUNET_free_non_null (proc->name); for (c = 0; c < proc->records_included; c++) { GNUNET_free ((void *) proc->rd[c].data); } GNUNET_free_non_null (proc->rd); proc->name = NULL; proc->rd = NULL; } static void handle_iteration_start (void *cls, struct GNUNET_SERVER_Client * client, const struct GNUNET_MessageHeader * message) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_START"); struct ZoneIterationStartMessage * zis_msg = (struct ZoneIterationStartMessage *) message; struct GNUNET_NAMESTORE_Client *nc; struct GNUNET_NAMESTORE_ZoneIteration *zi; nc = client_lookup(client); if (nc == NULL) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } zi = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_ZoneIteration)); zi->request_id = ntohl (zis_msg->gns_header.r_id); zi->offset = 0; zi->client = nc; zi->must_have_flags = ntohs (zis_msg->must_have_flags); zi->must_not_have_flags = ntohs (zis_msg->must_not_have_flags); struct GNUNET_CRYPTO_ShortHashCode dummy; memset (&dummy, '\0', sizeof (dummy)); if (0 == memcmp (&dummy, &zis_msg->zone, sizeof (dummy))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting to iterate over all zones\n"); zi->zone = zis_msg->zone; zi->has_zone = GNUNET_NO; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting to iterate over zone `%s'\n", GNUNET_short_h2s (&zis_msg->zone)); zi->zone = zis_msg->zone; zi->has_zone = GNUNET_YES; } GNUNET_CONTAINER_DLL_insert (nc->op_head, nc->op_tail, zi); struct ZoneIterationProcResult proc; proc.zi = zi; find_next_zone_iteration_result (&proc); if (GNUNET_YES == proc.res_iteration_finished) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Zone iteration done\n"); } else if (proc.records_included != 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Zone iteration return %u records\n", proc.records_included); } send_zone_iteration_result (&proc); clean_up_zone_iteration_result (&proc); GNUNET_SERVER_receive_done (client, GNUNET_OK); } static void handle_iteration_stop (void *cls, struct GNUNET_SERVER_Client * client, const struct GNUNET_MessageHeader * message) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_STOP"); struct GNUNET_NAMESTORE_Client *nc; struct GNUNET_NAMESTORE_ZoneIteration *zi; struct ZoneIterationStopMessage * zis_msg = (struct ZoneIterationStopMessage *) message; uint32_t rid; nc = client_lookup(client); if (nc == NULL) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } rid = ntohl (zis_msg->gns_header.r_id); for (zi = nc->op_head; zi != NULL; zi = zi->next) { if (zi->request_id == rid) break; } if (zi == NULL) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } GNUNET_CONTAINER_DLL_remove(nc->op_head, nc->op_tail, zi); if (GNUNET_YES == zi->has_zone) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopped zone iteration for zone `%s'\n", GNUNET_short_h2s (&zi->zone)); else GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopped zone iteration all zones\n"); GNUNET_free (zi); GNUNET_SERVER_receive_done (client, GNUNET_OK); } static void handle_iteration_next (void *cls, struct GNUNET_SERVER_Client * client, const struct GNUNET_MessageHeader * message) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_NEXT"); struct GNUNET_NAMESTORE_Client *nc; struct GNUNET_NAMESTORE_ZoneIteration *zi; struct ZoneIterationStopMessage * zis_msg = (struct ZoneIterationStopMessage *) message; uint32_t rid; nc = client_lookup(client); if (nc == NULL) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } rid = ntohl (zis_msg->gns_header.r_id); for (zi = nc->op_head; zi != NULL; zi = zi->next) { if (zi->request_id == rid) break; } if (zi == NULL) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } struct ZoneIterationProcResult proc; proc.zi = zi; find_next_zone_iteration_result (&proc); if (GNUNET_YES == proc.res_iteration_finished) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Zone iteration done\n"); } else if (proc.records_included != 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Zone iteration return %u records\n", proc.records_included); } send_zone_iteration_result (&proc); clean_up_zone_iteration_result (&proc); GNUNET_SERVER_receive_done (client, GNUNET_OK); } int zonekey_file_it (void *cls, const char *filename) { GNUNET_HashCode long_hash; int *counter = cls; if ((filename != NULL) && (NULL != strstr(filename, ".zkey"))) { struct GNUNET_CRYPTO_RsaPrivateKey * privkey; struct GNUNET_NAMESTORE_CryptoContainer *c; privkey = GNUNET_CRYPTO_rsa_key_create_from_file(filename); if (privkey == NULL) return GNUNET_OK; c = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_CryptoContainer)); c->pubkey = GNUNET_malloc(sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); c->privkey = privkey; GNUNET_CRYPTO_rsa_key_get_public(privkey, c->pubkey); GNUNET_CRYPTO_short_hash(c->pubkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &c->zone); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found zonefile for zone `%s'\n", GNUNET_short_h2s (&c->zone)); GNUNET_CRYPTO_short_hash_double (&c->zone, &long_hash); GNUNET_CONTAINER_multihashmap_put(zonekeys, &long_hash, c, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); (*counter) ++; } return GNUNET_OK; } /** * Process template requests. * * @param cls closure * @param server the initialized server * @param cfg configuration to use */ static void run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *cfg) { char * database; int counter = 0; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namestore service\n"); static const struct GNUNET_SERVER_MessageHandler handlers[] = { {&handle_start, NULL, GNUNET_MESSAGE_TYPE_NAMESTORE_START, sizeof (struct StartMessage)}, {&handle_lookup_name, NULL, GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME, 0}, {&handle_record_put, NULL, GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT, 0}, {&handle_record_create, NULL, GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE, 0}, {&handle_record_remove, NULL, GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE, 0}, {&handle_zone_to_name, NULL, GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME, 0}, {&handle_iteration_start, NULL, GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START, sizeof (struct ZoneIterationStartMessage)}, {&handle_iteration_next, NULL, GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT, 0}, {&handle_iteration_stop, NULL, GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP, 0}, {NULL, NULL, 0, 0} }; GSN_cfg = cfg; /* Load private keys from disk */ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "namestore", "zonefile_directory", &zonefile_directory)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("No directory to load zonefiles specified in configuration\n")); GNUNET_SCHEDULER_add_now (&cleanup_task, NULL); return; } if (GNUNET_NO == GNUNET_DISK_file_test (zonefile_directory)) { if (GNUNET_SYSERR == GNUNET_DISK_directory_create (zonefile_directory)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Creating directory `%s' for zone files failed!\n"), zonefile_directory); GNUNET_SCHEDULER_add_now (&cleanup_task, NULL); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created directory `%s' for zone files\n", zonefile_directory); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scanning directory `%s' for zone files\n", zonefile_directory); zonekeys = GNUNET_CONTAINER_multihashmap_create (10); GNUNET_DISK_directory_scan (zonefile_directory, zonekey_file_it, &counter); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found %u zone files\n", counter); /* Loading database plugin */ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "namestore", "database", &database)) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n"); GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", database); GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg); GNUNET_free (database); if (GSN_database == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not load database backend `%s'\n", db_lib_name); GNUNET_SCHEDULER_add_now (&cleanup_task, NULL); return; } /* Configuring server handles */ GNUNET_SERVER_add_handlers (server, handlers); snc = GNUNET_SERVER_notification_context_create (server, 16); GNUNET_SERVER_disconnect_notify (server, &client_disconnect_notification, NULL); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, NULL); } /** * The main function for the template service. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { return (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "namestore", GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; } /* end of gnunet-service-namestore.c */ gnunet-0.9.3/src/namestore/test_plugin_namestore.c0000644000175000017500000001622211760502550017312 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * @file namestore/test_plugin_namestore.c * @brief Test for the namestore plugins * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_namestore_plugin.h" #define VERBOSE GNUNET_NO #define ASSERT(x) do { if (! (x)) { printf("Error at %s:%d\n", __FILE__, __LINE__); goto FAILURE;} } while (0) static int ok; /** * Name of plugin under test. */ static const char *plugin_name; /** * Function called when the service shuts down. Unloads our namestore * plugin. * * @param api api to unload */ static void unload_plugin (struct GNUNET_NAMESTORE_PluginFunctions *api) { char *libname; GNUNET_asprintf (&libname, "libgnunet_plugin_namestore_%s", plugin_name); GNUNET_break (NULL == GNUNET_PLUGIN_unload (libname, api)); GNUNET_free (libname); } /** * Load the namestore plugin. * * @param cfg configuration to pass * @return NULL on error */ static struct GNUNET_NAMESTORE_PluginFunctions * load_plugin (const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_NAMESTORE_PluginFunctions *ret; char *libname; GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' namestore plugin\n"), plugin_name); GNUNET_asprintf (&libname, "libgnunet_plugin_namestore_%s", plugin_name); if (NULL == (ret = GNUNET_PLUGIN_load (libname, (void*) cfg))) { FPRINTF (stderr, "Failed to load plugin `%s'!\n", plugin_name); return NULL; } GNUNET_free (libname); return ret; } /** * Function called by for each matching record. * * @param cls closure * @param zone_key public key of the zone * @param expire when does the corresponding block in the DHT expire (until * when should we never do a DHT lookup for the same name again)? * @param name name that is being mapped (at most 255 characters long) * @param rd_count number of entries in 'rd' array * @param rd array of records with data to store * @param signature signature of the record block, NULL if signature is unavailable (i.e. * because the user queried for a particular record type only) */ static void test_record (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *name, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { int *idp = cls; int id = *idp; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded tzone_key; char tname[64]; unsigned int trd_count = 1 + (id % 1024); struct GNUNET_CRYPTO_RsaSignature tsignature; unsigned int i; GNUNET_snprintf (tname, sizeof (tname), "a%u", (unsigned int ) id); for (i=0;iiterate_records (nsp->cls, NULL, NULL, 0, &test_record, &id)); } static void put_record (struct GNUNET_NAMESTORE_PluginFunctions *nsp, int id) { struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded zone_key; struct GNUNET_TIME_Absolute expire; char name[64]; unsigned int rd_count = 1 + (id % 1024); struct GNUNET_NAMESTORE_RecordData rd[rd_count]; struct GNUNET_CRYPTO_RsaSignature signature; unsigned int i; GNUNET_snprintf (name, sizeof (name), "a%u", (unsigned int ) id); expire = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); for (i=0;iput_records (nsp->cls, &zone_key, expire, name, rd_count, rd, &signature)); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_NAMESTORE_PluginFunctions *nsp; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded zone_key; struct GNUNET_CRYPTO_ShortHashCode zone; ok = 0; nsp = load_plugin (cfg); if (NULL == nsp) { FPRINTF (stderr, "%s", "Failed to initialize namestore. Database likely not setup, skipping test.\n"); return; } put_record (nsp, 1); get_record (nsp, 1); memset (&zone_key, 1, sizeof (zone_key)); GNUNET_CRYPTO_short_hash (&zone_key, sizeof (zone_key), &zone); nsp->delete_zone (nsp->cls, &zone); unload_plugin (nsp); } int main (int argc, char *argv[]) { char *pos; char cfg_name[128]; char *const xargv[] = { "test-plugin-namestore", "-c", cfg_name, #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-namestore-sqlite"); GNUNET_log_setup ("test-plugin-namestore", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); /* determine name of plugin to use */ plugin_name = argv[0]; while (NULL != (pos = strstr (plugin_name, "_"))) plugin_name = pos + 1; if (NULL != (pos = strstr (plugin_name, "."))) pos[0] = 0; else pos = (char *) plugin_name; GNUNET_snprintf (cfg_name, sizeof (cfg_name), "test_plugin_namestore_%s.conf", plugin_name); GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1, xargv, "test-plugin-namestore", "nohelp", options, &run, NULL); if (ok != 0) FPRINTF (stderr, "Missed some testcases: %d\n", ok); GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-namestore-sqlite"); return ok; } /* end of test_plugin_namestore.c */ gnunet-0.9.3/src/namestore/test_namestore_api_remove.c0000644000175000017500000002320211760517422020142 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file namestore/test_namestore_api.c * @brief testcase for namestore_api.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_namestore_service.h" #include "namestore.h" #include "gnunet_signatures.h" #define VERBOSE GNUNET_NO #define RECORDS 5 #define TEST_RECORD_TYPE 1234 #define TEST_RECORD_DATALEN 123 #define TEST_RECORD_DATA 'a' #define TEST_REMOVE_RECORD_TYPE 4321 #define TEST_REMOVE_RECORD_DATALEN 255 #define TEST_REMOVE_RECORD_DATA 'b' #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) static struct GNUNET_NAMESTORE_Handle * nsh; static GNUNET_SCHEDULER_TaskIdentifier endbadly_task; static struct GNUNET_OS_Process *arm; static struct GNUNET_CRYPTO_RsaPrivateKey * privkey; static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubkey; struct GNUNET_CRYPTO_RsaSignature *s_signature; static struct GNUNET_CRYPTO_ShortHashCode s_zone; struct GNUNET_NAMESTORE_RecordData *s_rd; static char *s_name; static int res; static void start_arm (const char *cfgname) { arm = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, #if VERBOSE_PEERS "-L", "DEBUG", #else "-L", "ERROR", #endif NULL); } static void stop_arm () { if (NULL != arm) { if (0 != GNUNET_OS_process_kill (arm, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); GNUNET_OS_process_wait (arm); GNUNET_OS_process_destroy (arm); arm = NULL; } } /** * Re-establish the connection to the service. * * @param cls handle to use to re-connect. * @param tc scheduler context */ static void endbadly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (nsh != NULL) GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); nsh = NULL; if (privkey != NULL) GNUNET_CRYPTO_rsa_key_free (privkey); privkey = NULL; if (NULL != arm) stop_arm(); res = 1; } static void end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (endbadly_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (endbadly_task); endbadly_task = GNUNET_SCHEDULER_NO_TASK; } int c; for (c = 0; c < RECORDS; c++) GNUNET_free_non_null((void *) s_rd[c].data); GNUNET_free (s_rd); if (privkey != NULL) GNUNET_CRYPTO_rsa_key_free (privkey); privkey = NULL; if (nsh != NULL) GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); nsh = NULL; if (NULL != arm) stop_arm(); } void name_lookup_proc (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *n, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { static int found = GNUNET_NO; int failed = GNUNET_NO; int c; if (n != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Lookup for name `%s' returned %u records\n", n, rd_count); if (0 != memcmp (zone_key, &pubkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded))) { GNUNET_break (0); failed = GNUNET_YES; } if (0 != strcmp(n, s_name)) { GNUNET_break (0); failed = GNUNET_YES; } if (RECORDS-1 != rd_count) { GNUNET_break (0); failed = GNUNET_YES; } for (c = 0; c < rd_count; c++) { if (GNUNET_NO == GNUNET_NAMESTORE_records_cmp (&rd[c], &s_rd[c+1])) { GNUNET_break (0); failed = GNUNET_YES; } } if (GNUNET_OK != GNUNET_NAMESTORE_verify_signature(&pubkey, expire, n, rd_count, rd, signature)) { GNUNET_break (0); failed = GNUNET_YES; } if (failed == GNUNET_NO) res = 0; else res = 1; } else { if (found != GNUNET_YES) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to lookup records for name `%s'\n", s_name); res = 1; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Lookup done for name %s'\n", s_name); } GNUNET_SCHEDULER_add_now(&end, NULL); } void remove_cont (void *cls, int32_t success, const char *emsg) { char *name = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Remove record for `%s': %s\n", name, (success == GNUNET_YES) ? "SUCCESS" : "FAIL", emsg); if (success == GNUNET_OK) { res = 0; GNUNET_NAMESTORE_lookup_record (nsh, &s_zone, name, 0, &name_lookup_proc, name); } else { res = 1; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to remove record for name `%s'\n", name); GNUNET_SCHEDULER_add_now(&end, NULL); } } void put_cont (void *cls, int32_t success, const char *emsg) { char *name = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Name store added record for `%s': %s\n", name, (success == GNUNET_OK) ? "SUCCESS" : "FAIL"); if (success == GNUNET_OK) { res = 0; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing record for `%s'\n", name); GNUNET_NAMESTORE_record_remove (nsh, privkey, name, &s_rd[0], &remove_cont, name); } else { res = 1; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to put records for name `%s'\n", name); GNUNET_SCHEDULER_add_now(&end, NULL); } } static struct GNUNET_NAMESTORE_RecordData * create_record (int count) { int c; struct GNUNET_NAMESTORE_RecordData * rd; rd = GNUNET_malloc (count * sizeof (struct GNUNET_NAMESTORE_RecordData)); rd[0].expiration = GNUNET_TIME_absolute_get(); rd[0].record_type = 0; rd[0].data_size = TEST_REMOVE_RECORD_DATALEN; rd[0].data = GNUNET_malloc(TEST_REMOVE_RECORD_DATALEN); memset ((char *) rd[0].data, TEST_RECORD_DATA, TEST_RECORD_DATALEN); for (c = 1; c < RECORDS; c++) { rd[c].expiration = GNUNET_TIME_UNIT_ZERO_ABS; rd[c].record_type = TEST_RECORD_TYPE; rd[c].data_size = TEST_RECORD_DATALEN; rd[c].data = GNUNET_malloc(TEST_RECORD_DATALEN); memset ((char *) rd[c].data, TEST_RECORD_DATA, TEST_RECORD_DATALEN); } return rd; } void delete_existing_db (const struct GNUNET_CONFIGURATION_Handle *cfg) { char *afsdir; if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, "namestore-sqlite", "FILENAME", &afsdir)) { if (GNUNET_OK == GNUNET_DISK_file_test (afsdir)) if (GNUNET_OK == GNUNET_DISK_file_test (afsdir)) if (GNUNET_OK == GNUNET_DISK_directory_remove(afsdir)) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleted existing database `%s' \n", afsdir); GNUNET_free (afsdir); } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { delete_existing_db(cfg); endbadly_task = GNUNET_SCHEDULER_add_delayed(TIMEOUT,endbadly, NULL); size_t rd_ser_len; /* load privat key */ char *hostkey_file; GNUNET_asprintf(&hostkey_file,"zonefiles%s%s",DIR_SEPARATOR_STR, "N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using zonekey file `%s' \n", hostkey_file); privkey = GNUNET_CRYPTO_rsa_key_create_from_file(hostkey_file); GNUNET_free (hostkey_file); GNUNET_assert (privkey != NULL); /* get public key */ GNUNET_CRYPTO_rsa_key_get_public(privkey, &pubkey); /* create record */ s_name = "dummy.dummy.gnunet"; s_rd = create_record (RECORDS); rd_ser_len = GNUNET_NAMESTORE_records_get_size(RECORDS, s_rd); char rd_ser[rd_ser_len]; GNUNET_NAMESTORE_records_serialize(RECORDS, s_rd, rd_ser_len, rd_ser); /* sign */ s_signature = GNUNET_NAMESTORE_create_signature(privkey, s_rd[0].expiration, s_name, s_rd, RECORDS); /* create random zone hash */ GNUNET_CRYPTO_short_hash (&pubkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &s_zone); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Name: `%s' Zone: `%s' \n", s_name, GNUNET_short_h2s (&s_zone)); start_arm (cfgfile); GNUNET_assert (arm != NULL); nsh = GNUNET_NAMESTORE_connect (cfg); GNUNET_break (NULL != nsh); GNUNET_break (s_rd != NULL); GNUNET_break (s_name != NULL); GNUNET_NAMESTORE_record_put (nsh, &pubkey, s_name, GNUNET_TIME_UNIT_FOREVER_ABS, RECORDS, s_rd, s_signature, put_cont, s_name); } static int check () { static char *const argv[] = { "test-namestore-api", "-c", "test_namestore_api.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; res = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-namestore-api", "nohelp", options, &run, &res); return res; } int main (int argc, char *argv[]) { int ret; ret = check (); GNUNET_free (s_signature); return ret; } /* end of test_namestore_api.c */ gnunet-0.9.3/src/namestore/namestore_api.c0000644000175000017500000013155211760515202015530 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file namestore/namestore_api.c * @brief API to access the NAMESTORE service * @author Martin Schanzenbach * @author Matthias Wachs */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_crypto_lib.h" #include "gnunet_constants.h" #include "gnunet_dnsparser_lib.h" #include "gnunet_arm_service.h" #include "gnunet_signatures.h" #include "gnunet_namestore_service.h" #include "namestore.h" #define LOG(kind,...) GNUNET_log_from (kind, "gns-api",__VA_ARGS__) /** * A QueueEntry. */ struct GNUNET_NAMESTORE_QueueEntry { /** * Kept in a DLL. */ struct GNUNET_NAMESTORE_QueueEntry *next; /** * Kept in a DLL. */ struct GNUNET_NAMESTORE_QueueEntry *prev; struct GNUNET_NAMESTORE_Handle *nsh; uint32_t op_id; GNUNET_NAMESTORE_ContinuationWithStatus cont; void *cont_cls; GNUNET_NAMESTORE_RecordProcessor proc; void *proc_cls; char *data; /*stub data pointer*/ }; /** * Zone iterator */ struct GNUNET_NAMESTORE_ZoneIterator { /** * Kept in a DLL. */ struct GNUNET_NAMESTORE_ZoneIterator *next; /** * Kept in a DLL. */ struct GNUNET_NAMESTORE_ZoneIterator *prev; uint32_t op_id; struct GNUNET_NAMESTORE_Handle *h; GNUNET_NAMESTORE_RecordProcessor proc; void* proc_cls; struct GNUNET_CRYPTO_ShortHashCode zone; uint32_t no_flags; uint32_t flags; int has_zone; }; /** * Message in linked list we should send to the service. The * actual binary message follows this struct. */ struct PendingMessage { /** * Kept in a DLL. */ struct PendingMessage *next; /** * Kept in a DLL. */ struct PendingMessage *prev; /** * Size of the message. */ size_t size; /** * Is this the 'START' message? */ int is_init; }; /** * Connection to the NAMESTORE service. */ struct GNUNET_NAMESTORE_Handle { /** * Configuration to use. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Socket (if available). */ struct GNUNET_CLIENT_Connection *client; /** * Currently pending transmission request (or NULL). */ struct GNUNET_CLIENT_TransmitHandle *th; /** * Reconnect task */ GNUNET_SCHEDULER_TaskIdentifier reconnect_task; /** * Pending messages to send to the service */ struct PendingMessage * pending_head; struct PendingMessage * pending_tail; /** * Should we reconnect to service due to some serious error? */ int reconnect; /** * Pending namestore queue entries */ struct GNUNET_NAMESTORE_QueueEntry * op_head; struct GNUNET_NAMESTORE_QueueEntry * op_tail; uint32_t op_id; /** * Pending namestore zone iterator entries */ struct GNUNET_NAMESTORE_ZoneIterator * z_head; struct GNUNET_NAMESTORE_ZoneIterator * z_tail; }; struct GNUNET_NAMESTORE_SimpleRecord { /** * DLL */ struct GNUNET_NAMESTORE_SimpleRecord *next; /** * DLL */ struct GNUNET_NAMESTORE_SimpleRecord *prev; const char *name; const struct GNUNET_CRYPTO_ShortHashCode *zone; uint32_t record_type; struct GNUNET_TIME_Absolute expiration; enum GNUNET_NAMESTORE_RecordFlags flags; size_t data_size; const void *data; }; /** * Disconnect from service and then reconnect. * * @param h our handle */ static void force_reconnect (struct GNUNET_NAMESTORE_Handle *h); static void handle_lookup_name_response (struct GNUNET_NAMESTORE_QueueEntry *qe, struct LookupNameResponseMessage * msg, size_t size) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' \n", "LOOKUP_NAME_RESPONSE"); struct GNUNET_NAMESTORE_Handle *h = qe->nsh; /* Operation done, remove */ GNUNET_CONTAINER_DLL_remove(h->op_head, h->op_tail, qe); char *name; char * rd_tmp; struct GNUNET_CRYPTO_RsaSignature *signature = NULL; struct GNUNET_TIME_Absolute expire; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key_tmp; size_t exp_msg_len; size_t msg_len = 0; size_t name_len = 0; size_t rd_len = 0; int contains_sig = GNUNET_NO; int rd_count = 0; rd_len = ntohs (msg->rd_len); rd_count = ntohs (msg->rd_count); msg_len = ntohs (msg->gns_header.header.size); name_len = ntohs (msg->name_len); contains_sig = ntohs (msg->contains_sig); expire = GNUNET_TIME_absolute_ntoh(msg->expire); exp_msg_len = sizeof (struct LookupNameResponseMessage) + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + name_len + rd_len; if (msg_len != exp_msg_len) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message size describes with `%u' bytes but calculated size is %u bytes \n", msg_len, exp_msg_len); GNUNET_break_op (0); return; } name = (char *) &msg[1]; if (name_len > 0) { GNUNET_assert ('\0' == name[name_len -1]); GNUNET_assert ((name_len - 1) == strlen(name)); } rd_tmp = &name[name_len]; /* deserialize records */ struct GNUNET_NAMESTORE_RecordData rd[rd_count]; if (GNUNET_OK != GNUNET_NAMESTORE_records_deserialize(rd_len, rd_tmp, rd_count, rd)) { GNUNET_break_op (0); return; } /* reset values if values not contained */ if (contains_sig == GNUNET_NO) signature = NULL; else signature = &msg->signature; if (name_len == 0) name = NULL; if (name != NULL) public_key_tmp = &msg->public_key; else public_key_tmp = NULL; if (qe->proc != NULL) { qe->proc (qe->proc_cls, public_key_tmp, expire, name, rd_count, (rd_count > 0) ? rd : NULL, signature); } GNUNET_free (qe); } static void handle_record_put_response (struct GNUNET_NAMESTORE_QueueEntry *qe, struct RecordPutResponseMessage* msg, size_t size) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' \n", "RECORD_PUT_RESPONSE"); struct GNUNET_NAMESTORE_Handle *h = qe->nsh; /* Operation done, remove */ GNUNET_CONTAINER_DLL_remove(h->op_head, h->op_tail, qe); int res = ntohl (msg->op_result); if (res == GNUNET_OK) { if (qe->cont != NULL) { qe->cont (qe->cont_cls, res, _("Namestore added record successfully")); } } else if (res == GNUNET_SYSERR) { if (qe->cont != NULL) { qe->cont (qe->cont_cls, res, _("Namestore failed to add record")); } } else { GNUNET_break_op (0); return; } GNUNET_free (qe); } static void handle_record_create_response (struct GNUNET_NAMESTORE_QueueEntry *qe, struct RecordCreateResponseMessage* msg, size_t size) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' \n", "RECORD_CREATE_RESPONSE"); struct GNUNET_NAMESTORE_Handle *h = qe->nsh; /* Operation done, remove */ GNUNET_CONTAINER_DLL_remove(h->op_head, h->op_tail, qe); int res = ntohl (msg->op_result); if (res == GNUNET_YES) { if (qe->cont != NULL) { qe->cont (qe->cont_cls, res, _("Namestore added record successfully")); } } else if (res == GNUNET_NO) { if (qe->cont != NULL) { qe->cont (qe->cont_cls, res, _("Namestore record already existed")); } } else { if (qe->cont != NULL) { qe->cont (qe->cont_cls, GNUNET_SYSERR, _("Namestore failed to add record\n")); } } GNUNET_free (qe); } static void handle_record_remove_response (struct GNUNET_NAMESTORE_QueueEntry *qe, struct RecordRemoveResponseMessage* msg, size_t size) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' \n", "RECORD_REMOVE_RESPONSE"); struct GNUNET_NAMESTORE_Handle *h = qe->nsh; /* Operation done, remove */ GNUNET_CONTAINER_DLL_remove(h->op_head, h->op_tail, qe); int res = ntohl (msg->op_result); /** * result: * 0 : successful * 1 : No records for entry * 2 : Could not find record to remove * 3 : Failed to create new signature * 4 : Failed to put new set of records in database */ switch (res) { case 0: if (qe->cont != NULL) { qe->cont (qe->cont_cls, GNUNET_YES, _("Namestore removed record successfully")); } break; case 1: if (qe->cont != NULL) { qe->cont (qe->cont_cls, GNUNET_NO, _("No records for entry")); } break; case 2: if (qe->cont != NULL) { qe->cont (qe->cont_cls, GNUNET_NO, _("Could not find record to remove")); } break; case 3: if (qe->cont != NULL) { qe->cont (qe->cont_cls, GNUNET_SYSERR, _("Failed to create new signature")); } break; case 4: if (qe->cont != NULL) { qe->cont (qe->cont_cls, GNUNET_SYSERR, _("Failed to put new set of records in database")); } break; default: GNUNET_break_op (0); break; } GNUNET_free (qe); } static void handle_zone_to_name_response (struct GNUNET_NAMESTORE_QueueEntry *qe, struct ZoneToNameResponseMessage* msg, size_t size) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' \n", "ZONE_TO_NAME_RESPONSE"); struct GNUNET_NAMESTORE_Handle *h = qe->nsh; /* Operation done, remove */ GNUNET_CONTAINER_DLL_remove(h->op_head, h->op_tail, qe); int res = ntohs (msg->res); struct GNUNET_TIME_Absolute expire; size_t name_len; size_t rd_ser_len; unsigned int rd_count; char * name_tmp; char * rd_tmp; if (res == GNUNET_SYSERR) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "An error occured during zone to name operation\n"); if (qe->proc != NULL) qe->proc (qe->proc_cls, NULL, GNUNET_TIME_UNIT_ZERO_ABS, NULL, 0, NULL, NULL); } else if (res == GNUNET_NO) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Namestore has no result for zone to name mapping \n"); if (qe->proc != NULL) qe->proc (qe->proc_cls, NULL, GNUNET_TIME_UNIT_ZERO_ABS, NULL, 0, NULL, NULL); } else if (res == GNUNET_YES) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Namestore has result for zone to name mapping \n"); name_len = ntohs (msg->name_len); rd_count = ntohs (msg->rd_count); rd_ser_len = ntohs (msg->rd_len); expire = GNUNET_TIME_absolute_ntoh(msg->expire); name_tmp = (char *) &msg[1]; if (name_len > 0) { GNUNET_assert ('\0' == name_tmp[name_len -1]); GNUNET_assert (name_len -1 == strlen(name_tmp)); } rd_tmp = &name_tmp[name_len]; struct GNUNET_NAMESTORE_RecordData rd[rd_count]; if (GNUNET_OK != GNUNET_NAMESTORE_records_deserialize(rd_ser_len, rd_tmp, rd_count, rd)) { GNUNET_break_op (0); return; } if (qe->proc != NULL) qe->proc (qe->proc_cls, &msg->zone_key, expire, name_tmp, rd_count, rd, &msg->signature); } else GNUNET_break_op (0); GNUNET_free (qe); } static void manage_record_operations (struct GNUNET_NAMESTORE_QueueEntry *qe, const struct GNUNET_MessageHeader *msg, int type, size_t size) { /* handle different message type */ switch (type) { case GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME_RESPONSE: if (size < sizeof (struct LookupNameResponseMessage)) { GNUNET_break_op (0); break; } handle_lookup_name_response (qe, (struct LookupNameResponseMessage *) msg, size); break; case GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT_RESPONSE: if (size != sizeof (struct RecordPutResponseMessage)) { GNUNET_break_op (0); break; } handle_record_put_response (qe, (struct RecordPutResponseMessage *) msg, size); break; case GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE_RESPONSE: if (size != sizeof (struct RecordCreateResponseMessage)) { GNUNET_break_op (0); break; } handle_record_create_response (qe, (struct RecordCreateResponseMessage *) msg, size); break; case GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE_RESPONSE: if (size != sizeof (struct RecordRemoveResponseMessage)) { GNUNET_break_op (0); break; } handle_record_remove_response (qe, (struct RecordRemoveResponseMessage *) msg, size); break; case GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE: if (size < sizeof (struct ZoneToNameResponseMessage)) { GNUNET_break_op (0); break; } handle_zone_to_name_response (qe, (struct ZoneToNameResponseMessage *) msg, size); break; default: GNUNET_break_op (0); break; } } static void handle_zone_iteration_response (struct GNUNET_NAMESTORE_ZoneIterator *ze, struct ZoneIterationResponseMessage *msg, size_t size) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' \n", "ZONE_ITERATION_RESPONSE"); struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubdummy; size_t msg_len = 0; size_t exp_msg_len = 0; size_t name_len = 0; size_t rd_len = 0; unsigned rd_count = 0; char *name_tmp; char *rd_ser_tmp; struct GNUNET_TIME_Absolute expire; msg_len = ntohs (msg->gns_header.header.size); rd_len = ntohs (msg->rd_len); rd_count = ntohs (msg->rd_count); name_len = ntohs (msg->name_len); expire = GNUNET_TIME_absolute_ntoh (msg->expire); exp_msg_len = sizeof (struct ZoneIterationResponseMessage) + name_len + rd_len; if (msg_len != exp_msg_len) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message size describes with `%u' bytes but calculated size is %u bytes \n", msg_len, exp_msg_len); GNUNET_break_op (0); return; } if (0 != ntohs (msg->reserved)) { GNUNET_break_op (0); return; } memset (&pubdummy, '\0', sizeof (pubdummy)); if ((0 == name_len) && (0 == (memcmp (&msg->public_key, &pubdummy, sizeof (pubdummy))))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Zone iteration is completed!\n"); GNUNET_CONTAINER_DLL_remove(ze->h->z_head, ze->h->z_tail, ze); if (ze->proc != NULL) ze->proc(ze->proc_cls, NULL, GNUNET_TIME_UNIT_ZERO_ABS, NULL , 0, NULL, NULL); GNUNET_free (ze); return; } name_tmp = (char *) &msg[1]; if ((name_tmp[name_len -1] != '\0') || (name_len > 256)) { GNUNET_break_op (0); return; } rd_ser_tmp = (char *) &name_tmp[name_len]; struct GNUNET_NAMESTORE_RecordData rd[rd_count]; if (GNUNET_OK != GNUNET_NAMESTORE_records_deserialize (rd_len, rd_ser_tmp, rd_count, rd)) { GNUNET_break_op (0); return; } if (ze->proc != NULL) ze->proc(ze->proc_cls, &msg->public_key, expire, name_tmp, rd_count, rd, &msg->signature); } static void manage_zone_operations (struct GNUNET_NAMESTORE_ZoneIterator *ze, const struct GNUNET_MessageHeader *msg, int type, size_t size) { /* handle different message type */ switch (type) { case GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE: if (size < sizeof (struct ZoneIterationResponseMessage)) { GNUNET_break_op (0); break; } handle_zone_iteration_response (ze, (struct ZoneIterationResponseMessage *) msg, size); break; default: GNUNET_break_op (0); break; } } /** * Type of a function to call when we receive a message * from the service. * * @param cls the 'struct GNUNET_NAMESTORE_SchedulingHandle' * @param msg message received, NULL on timeout or fatal error */ static void process_namestore_message (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_NAMESTORE_Handle *h = cls; struct GNUNET_NAMESTORE_Header * gm; struct GNUNET_NAMESTORE_QueueEntry *qe; struct GNUNET_NAMESTORE_ZoneIterator *ze; uint16_t size; uint16_t type; uint32_t r_id = UINT32_MAX; if (NULL == msg) { force_reconnect (h); return; } size = ntohs (msg->size); type = ntohs (msg->type); if (size < sizeof (struct GNUNET_NAMESTORE_Header)) { GNUNET_break_op (0); GNUNET_CLIENT_receive (h->client, &process_namestore_message, h, GNUNET_TIME_UNIT_FOREVER_REL); return; } gm = (struct GNUNET_NAMESTORE_Header *) msg; r_id = ntohl (gm->r_id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received message type %i size %i op %u\n", type, size, r_id); /* Find matching operation */ if (r_id > h->op_id) { /* No matching pending operation found */ GNUNET_break_op (0); GNUNET_CLIENT_receive (h->client, &process_namestore_message, h, GNUNET_TIME_UNIT_FOREVER_REL); return; } /* Is it a record related operation ? */ for (qe = h->op_head; qe != NULL; qe = qe->next) { if (qe->op_id == r_id) break; } if (qe != NULL) { manage_record_operations (qe, msg, type, size); } /* Is it a zone iteration operation ? */ for (ze = h->z_head; ze != NULL; ze = ze->next) { if (ze->op_id == r_id) break; } if (ze != NULL) { manage_zone_operations (ze, msg, type, size); } GNUNET_CLIENT_receive (h->client, &process_namestore_message, h, GNUNET_TIME_UNIT_FOREVER_REL); if (GNUNET_YES == h->reconnect) force_reconnect (h); } /** * Transmit messages from the message queue to the service * (if there are any, and if we are not already trying). * * @param h handle to use */ static void do_transmit (struct GNUNET_NAMESTORE_Handle *h); /** * We can now transmit a message to NAMESTORE. Do it. * * @param cls the 'struct GNUNET_NAMESTORE_Handle' * @param size number of bytes we can transmit * @param buf where to copy the messages * @return number of bytes copied into buf */ static size_t transmit_message_to_namestore (void *cls, size_t size, void *buf) { struct GNUNET_NAMESTORE_Handle *h = cls; struct PendingMessage *p; size_t ret; char *cbuf; h->th = NULL; if ((size == 0) || (buf == NULL)) { force_reconnect (h); return 0; } ret = 0; cbuf = buf; while ((NULL != (p = h->pending_head)) && (p->size <= size)) { memcpy (&cbuf[ret], &p[1], p->size); ret += p->size; size -= p->size; GNUNET_CONTAINER_DLL_remove (h->pending_head, h->pending_tail, p); if (GNUNET_YES == p->is_init) GNUNET_CLIENT_receive (h->client, &process_namestore_message, h, GNUNET_TIME_UNIT_FOREVER_REL); GNUNET_free (p); } do_transmit (h); return ret; } /** * Transmit messages from the message queue to the service * (if there are any, and if we are not already trying). * * @param h handle to use */ static void do_transmit (struct GNUNET_NAMESTORE_Handle *h) { struct PendingMessage *p; if (NULL != h->th) return; if (NULL == (p = h->pending_head)) return; if (NULL == h->client) return; /* currently reconnecting */ h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, p->size, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_NO, &transmit_message_to_namestore, h); } /** * Reconnect to namestore service. * * @param h the handle to the namestore service */ static void reconnect (struct GNUNET_NAMESTORE_Handle *h) { struct PendingMessage *p; struct StartMessage *init; GNUNET_assert (NULL == h->client); h->client = GNUNET_CLIENT_connect ("namestore", h->cfg); GNUNET_assert (NULL != h->client); if ((NULL == (p = h->pending_head)) || (GNUNET_YES != p->is_init)) { p = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (struct StartMessage)); p->size = sizeof (struct StartMessage); p->is_init = GNUNET_YES; init = (struct StartMessage *) &p[1]; init->header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_START); init->header.size = htons (sizeof (struct StartMessage)); GNUNET_CONTAINER_DLL_insert (h->pending_head, h->pending_tail, p); } do_transmit (h); } /** * Re-establish the connection to the service. * * @param cls handle to use to re-connect. * @param tc scheduler context */ static void reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_NAMESTORE_Handle *h = cls; h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; reconnect (h); } /** * Disconnect from service and then reconnect. * * @param h our handle */ static void force_reconnect (struct GNUNET_NAMESTORE_Handle *h) { h->reconnect = GNUNET_NO; GNUNET_CLIENT_disconnect (h->client); h->client = NULL; h->reconnect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task, h); } static uint32_t get_op_id (struct GNUNET_NAMESTORE_Handle *h) { uint32_t op_id = h->op_id; h->op_id ++; return op_id; } /** * Initialize the connection with the NAMESTORE service. * * @param cfg configuration to use * @return handle to the GNS service, or NULL on error */ struct GNUNET_NAMESTORE_Handle * GNUNET_NAMESTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_NAMESTORE_Handle *h; h = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Handle)); h->cfg = cfg; h->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect_task, h); h->op_id = 0; return h; } static void clean_up_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PendingMessage *p; struct GNUNET_NAMESTORE_QueueEntry *q; struct GNUNET_NAMESTORE_ZoneIterator *z; struct GNUNET_NAMESTORE_Handle *h = cls; GNUNET_assert (h != NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n"); while (NULL != (p = h->pending_head)) { GNUNET_CONTAINER_DLL_remove (h->pending_head, h->pending_tail, p); GNUNET_free (p); } while (NULL != (q = h->op_head)) { GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, q); GNUNET_free (q); } while (NULL != (z = h->z_head)) { GNUNET_CONTAINER_DLL_remove (h->z_head, h->z_tail, z); GNUNET_free (z); } if (NULL != h->client) { GNUNET_CLIENT_disconnect (h->client); h->client = NULL; } if (GNUNET_SCHEDULER_NO_TASK != h->reconnect_task) { GNUNET_SCHEDULER_cancel (h->reconnect_task); h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_free(h); h = NULL; } /** * Disconnect from the namestore service (and free associated * resources). * * @param h handle to the namestore * @param drop set to GNUNET_YES to delete all data in namestore (!) */ void GNUNET_NAMESTORE_disconnect (struct GNUNET_NAMESTORE_Handle *h, int drop) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from namestore service\n"); GNUNET_SCHEDULER_add_now (&clean_up_task, h); } /** * Store an item in the namestore. If the item is already present, * the expiration time is updated to the max of the existing time and * the new time. This API is used when we cache signatures from other * authorities. * * @param h handle to the namestore * @param zone_key public key of the zone * @param name name that is being mapped (at most 255 characters long) * @param freshness when does the corresponding block in the DHT expire (until * when should we never do a DHT lookup for the same name again)? * @param rd_count number of entries in 'rd' array * @param rd array of records with data to store * @param signature signature for all the records in the zone under the given name * @param cont continuation to call when done * @param cont_cls closure for cont * @return handle to abort the request */ struct GNUNET_NAMESTORE_QueueEntry * GNUNET_NAMESTORE_record_put (struct GNUNET_NAMESTORE_Handle *h, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, const char *name, struct GNUNET_TIME_Absolute freshness, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature, GNUNET_NAMESTORE_ContinuationWithStatus cont, void *cont_cls) { struct GNUNET_NAMESTORE_QueueEntry *qe; struct PendingMessage *pe; /* pointer to elements */ char * rd_tmp; char * name_tmp; size_t msg_size = 0; size_t name_len = 0; size_t rd_ser_len = 0; uint32_t rid = 0; GNUNET_assert (NULL != h); GNUNET_assert (NULL != zone_key); GNUNET_assert (NULL != name); GNUNET_assert (NULL != rd); GNUNET_assert (NULL != signature); name_len = strlen(name) + 1; if (name_len > 256) { GNUNET_break (0); return NULL; } rid = get_op_id(h); qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); qe->nsh = h; qe->cont = cont; qe->cont_cls = cont_cls; qe->op_id = rid; GNUNET_CONTAINER_DLL_insert_tail(h->op_head, h->op_tail, qe); /* set msg_size*/ rd_ser_len = GNUNET_NAMESTORE_records_get_size(rd_count, rd); char rd_ser[rd_ser_len]; GNUNET_NAMESTORE_records_serialize(rd_count, rd, rd_ser_len, rd_ser); struct RecordPutMessage * msg; msg_size = sizeof (struct RecordPutMessage) + name_len + rd_ser_len; /* create msg here */ pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); pe->size = msg_size; pe->is_init = GNUNET_NO; msg = (struct RecordPutMessage *) &pe[1]; name_tmp = (char *) &msg[1]; rd_tmp = &name_tmp[name_len]; msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT); msg->gns_header.header.size = htons (msg_size); msg->gns_header.r_id = htonl (rid); msg->signature = *signature; msg->name_len = htons (name_len); msg->expire = GNUNET_TIME_absolute_hton (freshness); msg->rd_len = htons (rd_ser_len); msg->rd_count = htons (rd_count); msg->public_key = *zone_key; memcpy (name_tmp, name, name_len); memcpy (rd_tmp, rd_ser, rd_ser_len); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for name `%s' with size %u\n", "NAMESTORE_RECORD_PUT", name, msg_size); GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); do_transmit(h); return qe; } /** * Check if a signature is valid. This API is used by the GNS Block * to validate signatures received from the network. * * @param public_key public key of the zone * @param expire block expiration * @param name name that is being mapped (at most 255 characters long) * @param rd_count number of entries in 'rd' array * @param rd array of records with data to store * @param signature signature for all the records in the zone under the given name * @return GNUNET_OK if the signature is valid */ int GNUNET_NAMESTORE_verify_signature (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, const struct GNUNET_TIME_Absolute expire, const char *name, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { int res = GNUNET_SYSERR; size_t rd_ser_len = 0; size_t name_len = 0; char * name_tmp; char * rd_tmp; struct GNUNET_CRYPTO_RsaSignaturePurpose *sig_purpose; struct GNUNET_TIME_AbsoluteNBO *expire_tmp; struct GNUNET_TIME_AbsoluteNBO expire_nbo = GNUNET_TIME_absolute_hton(expire); GNUNET_assert (public_key != NULL); GNUNET_assert (name != NULL); GNUNET_assert (rd != NULL); GNUNET_assert (signature != NULL); rd_ser_len = GNUNET_NAMESTORE_records_get_size(rd_count, rd); char rd_ser[rd_ser_len]; GNUNET_NAMESTORE_records_serialize(rd_count, rd, rd_ser_len, rd_ser); name_len = strlen (name) + 1; if (name_len > 256) { GNUNET_break (0); return GNUNET_SYSERR; } sig_purpose = GNUNET_malloc(sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + rd_ser_len + name_len); sig_purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose)+ rd_ser_len + name_len); sig_purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); expire_tmp = (struct GNUNET_TIME_AbsoluteNBO *) &sig_purpose[1]; name_tmp = (char *) &expire_tmp[1]; rd_tmp = &name_tmp[name_len]; memcpy (expire_tmp, &expire_nbo, sizeof (struct GNUNET_TIME_AbsoluteNBO)); memcpy (name_tmp, name, name_len); memcpy (rd_tmp, rd_ser, rd_ser_len); res = GNUNET_CRYPTO_rsa_verify(GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN, sig_purpose, signature, public_key); GNUNET_free (sig_purpose); return res; } /** * Store an item in the namestore. If the item is already present, * the expiration time is updated to the max of the existing time and * the new time. This API is used by the authority of a zone. * * @param h handle to the namestore * @param pkey private key of the zone * @param name name that is being mapped (at most 255 characters long) * @param rd record data to store * @param cont continuation to call when done * @param cont_cls closure for cont * @return handle to abort the request */ struct GNUNET_NAMESTORE_QueueEntry * GNUNET_NAMESTORE_record_create (struct GNUNET_NAMESTORE_Handle *h, const struct GNUNET_CRYPTO_RsaPrivateKey *pkey, const char *name, const struct GNUNET_NAMESTORE_RecordData *rd, GNUNET_NAMESTORE_ContinuationWithStatus cont, void *cont_cls) { struct GNUNET_NAMESTORE_QueueEntry *qe; struct PendingMessage *pe; char * name_tmp; char * pkey_tmp; char * rd_tmp; size_t rd_ser_len = 0; size_t msg_size = 0; size_t name_len = 0; size_t key_len = 0; uint32_t rid = 0; GNUNET_assert (NULL != h); GNUNET_assert (NULL != pkey); GNUNET_assert (NULL != name); GNUNET_assert (NULL != rd); name_len = strlen(name) + 1; if (name_len > 256) { GNUNET_break (0); return NULL; } rid = get_op_id(h); qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); qe->nsh = h; qe->cont = cont; qe->cont_cls = cont_cls; qe->op_id = rid; GNUNET_CONTAINER_DLL_insert_tail(h->op_head, h->op_tail, qe); /* set msg_size*/ struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded * pkey_enc = GNUNET_CRYPTO_rsa_encode_key (pkey); GNUNET_assert (pkey_enc != NULL); key_len = ntohs (pkey_enc->len); rd_ser_len = GNUNET_NAMESTORE_records_get_size(1, rd); char rd_ser[rd_ser_len]; GNUNET_NAMESTORE_records_serialize(1, rd, rd_ser_len, rd_ser); struct RecordCreateMessage * msg; msg_size = sizeof (struct RecordCreateMessage) + key_len + name_len + rd_ser_len; /* create msg here */ pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); pe->size = msg_size; pe->is_init = GNUNET_NO; msg = (struct RecordCreateMessage *) &pe[1]; pkey_tmp = (char *) &msg[1]; name_tmp = &pkey_tmp[key_len]; rd_tmp = &name_tmp[name_len]; msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE); msg->gns_header.header.size = htons (msg_size); msg->gns_header.r_id = htonl (rid); msg->name_len = htons (name_len); msg->rd_count = htons (1); msg->rd_len = htons (rd_ser_len); msg->pkey_len = htons (key_len); msg->expire = GNUNET_TIME_absolute_hton(GNUNET_TIME_UNIT_FOREVER_ABS); memcpy (pkey_tmp, pkey_enc, key_len); memcpy (name_tmp, name, name_len); memcpy (rd_tmp, rd_ser, rd_ser_len); GNUNET_free (pkey_enc); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for name `%s' with size %u\n", "NAMESTORE_RECORD_CREATE", name, msg_size); GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); do_transmit(h); return qe; } /** * Explicitly remove some content from the database. The * "cont"inuation will be called with status "GNUNET_OK" if content * was removed, "GNUNET_NO" if no matching entry was found and * "GNUNET_SYSERR" on all other types of errors. * This API is used by the authority of a zone. * * @param h handle to the namestore * @param pkey private key of the zone * @param name name that is being mapped (at most 255 characters long) * @param rd record data, remove specific record, NULL to remove the name and all records * @param cont continuation to call when done * @param cont_cls closure for cont * @return handle to abort the request */ struct GNUNET_NAMESTORE_QueueEntry * GNUNET_NAMESTORE_record_remove (struct GNUNET_NAMESTORE_Handle *h, const struct GNUNET_CRYPTO_RsaPrivateKey *pkey, const char *name, const struct GNUNET_NAMESTORE_RecordData *rd, GNUNET_NAMESTORE_ContinuationWithStatus cont, void *cont_cls) { struct GNUNET_NAMESTORE_QueueEntry *qe; struct PendingMessage *pe; char *pkey_tmp; char *rd_tmp; char *name_tmp; size_t rd_ser_len = 0; size_t msg_size = 0; size_t name_len = 0; size_t key_len = 0; uint32_t rid = 0; uint16_t rd_count = 1; GNUNET_assert (NULL != h); rid = get_op_id(h); qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); qe->nsh = h; qe->cont = cont; qe->cont_cls = cont_cls; qe->op_id = rid; GNUNET_CONTAINER_DLL_insert_tail(h->op_head, h->op_tail, qe); /* set msg_size*/ struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded * pkey_enc = GNUNET_CRYPTO_rsa_encode_key (pkey); GNUNET_assert (pkey_enc != NULL); key_len = ntohs (pkey_enc->len); if (NULL == rd) rd_count = 0; else rd_count = 1; rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd); char rd_ser[rd_ser_len]; GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_ser_len, rd_ser); name_len = strlen (name) + 1; struct RecordRemoveMessage * msg; msg_size = sizeof (struct RecordRemoveMessage) + key_len + name_len + rd_ser_len; /* create msg here */ pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); pe->size = msg_size; pe->is_init = GNUNET_NO; msg = (struct RecordRemoveMessage *) &pe[1]; pkey_tmp = (char *) &msg[1]; name_tmp = &pkey_tmp[key_len]; rd_tmp = &name_tmp[name_len]; msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE); msg->gns_header.header.size = htons (msg_size); msg->gns_header.r_id = htonl (rid); msg->name_len = htons (name_len); msg->rd_len = htons (rd_ser_len); msg->rd_count = htons (rd_count); msg->pkey_len = htons (key_len); memcpy (pkey_tmp, pkey_enc, key_len); memcpy (name_tmp, name, name_len); memcpy (rd_tmp, rd_ser, rd_ser_len); GNUNET_free (pkey_enc); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for name `%s' with size %u\n", "NAMESTORE_RECORD_REMOVE", name, msg_size); GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); do_transmit(h); return qe; } /** * Get a result for a particular key from the namestore. The processor * will only be called once. * * @param h handle to the namestore * @param zone zone to look up a record from * @param name name to look up * @param record_type desired record type, 0 for all * @param proc function to call on the matching records, or with * NULL (rd_count == 0) if there are no matching records * @param proc_cls closure for proc * @return a handle that can be used to * cancel */ struct GNUNET_NAMESTORE_QueueEntry * GNUNET_NAMESTORE_lookup_record (struct GNUNET_NAMESTORE_Handle *h, const struct GNUNET_CRYPTO_ShortHashCode *zone, const char *name, uint32_t record_type, GNUNET_NAMESTORE_RecordProcessor proc, void *proc_cls) { struct GNUNET_NAMESTORE_QueueEntry *qe; struct PendingMessage *pe; size_t msg_size = 0; size_t name_len = 0; uint32_t rid = 0; GNUNET_assert (NULL != h); GNUNET_assert (NULL != zone); GNUNET_assert (NULL != name); name_len = strlen (name) + 1; if ((name_len == 0) || (name_len > 256)) { GNUNET_break (0); return NULL; } rid = get_op_id(h); qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); qe->nsh = h; qe->proc = proc; qe->proc_cls = proc_cls; qe->op_id = rid; GNUNET_CONTAINER_DLL_insert_tail(h->op_head, h->op_tail, qe); /* set msg_size*/ msg_size = sizeof (struct LookupNameMessage) + name_len; pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); /* create msg here */ struct LookupNameMessage * msg; pe->size = msg_size; pe->is_init = GNUNET_NO; msg = (struct LookupNameMessage *) &pe[1]; msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME); msg->gns_header.header.size = htons (msg_size); msg->gns_header.r_id = htonl (rid); msg->record_type = htonl (record_type); msg->name_len = htonl (name_len); msg->zone = *zone; memcpy (&msg[1], name, name_len); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for name `%s'\n", "NAMESTORE_LOOKUP_NAME", name); /* transmit message */ GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); do_transmit(h); return qe; } /** * Look for an existing PKEY delegation record for a given public key. * Returns at most one result to the processor. * * @param h handle to the namestore * @param zone hash of public key of the zone to look up in, never NULL * @param value_zone hash of the public key of the target zone (value), never NULL * @param proc function to call on the matching records, or with * NULL (rd_count == 0) if there are no matching records * @param proc_cls closure for proc * @return a handle that can be used to * cancel */ struct GNUNET_NAMESTORE_QueueEntry * GNUNET_NAMESTORE_zone_to_name (struct GNUNET_NAMESTORE_Handle *h, const struct GNUNET_CRYPTO_ShortHashCode *zone, const struct GNUNET_CRYPTO_ShortHashCode *value_zone, GNUNET_NAMESTORE_RecordProcessor proc, void *proc_cls) { struct GNUNET_NAMESTORE_QueueEntry *qe; struct PendingMessage *pe; size_t msg_size = 0; uint32_t rid = 0; GNUNET_assert (NULL != h); GNUNET_assert (NULL != zone); GNUNET_assert (NULL != value_zone); rid = get_op_id(h); qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); qe->nsh = h; qe->proc = proc; qe->proc_cls = proc_cls; qe->op_id = rid; GNUNET_CONTAINER_DLL_insert_tail(h->op_head, h->op_tail, qe); /* set msg_size*/ msg_size = sizeof (struct ZoneToNameMessage); pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); /* create msg here */ struct ZoneToNameMessage * msg; pe->size = msg_size; pe->is_init = GNUNET_NO; msg = (struct ZoneToNameMessage *) &pe[1]; msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME); msg->gns_header.header.size = htons (msg_size); msg->gns_header.r_id = htonl (rid); msg->zone = *zone; msg->value_zone = *value_zone; char * z_tmp = GNUNET_strdup (GNUNET_short_h2s (zone)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for zone `%s' in zone `%s'\n", "NAMESTORE_ZONE_TO_NAME", z_tmp, GNUNET_short_h2s (value_zone)); GNUNET_free (z_tmp); /* transmit message */ GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); do_transmit(h); return qe; } /** * Starts a new zone iteration (used to periodically PUT all of our * records into our DHT). This MUST lock the GNUNET_NAMESTORE_Handle * for any other calls than GNUNET_NAMESTORE_zone_iterator_next and * GNUNET_NAMESTORE_zone_iteration_stop. "proc" will be called once * immediately, and then again after * "GNUNET_NAMESTORE_zone_iterator_next" is invoked. * * @param h handle to the namestore * @param zone zone to access, NULL for all zones * @param must_have_flags flags that must be set for the record to be returned * @param must_not_have_flags flags that must NOT be set for the record to be returned * @param proc function to call on each name from the zone; it * will be called repeatedly with a value (if available) * and always once at the end with a name of NULL. * @param proc_cls closure for proc * @return an iterator handle to use for iteration */ struct GNUNET_NAMESTORE_ZoneIterator * GNUNET_NAMESTORE_zone_iteration_start (struct GNUNET_NAMESTORE_Handle *h, const struct GNUNET_CRYPTO_ShortHashCode *zone, enum GNUNET_NAMESTORE_RecordFlags must_have_flags, enum GNUNET_NAMESTORE_RecordFlags must_not_have_flags, GNUNET_NAMESTORE_RecordProcessor proc, void *proc_cls) { struct GNUNET_NAMESTORE_ZoneIterator *it; struct PendingMessage *pe; size_t msg_size = 0; uint32_t rid = 0; GNUNET_assert (NULL != h); rid = get_op_id(h); it = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_ZoneIterator)); it->h = h; it->proc = proc; it->proc_cls = proc_cls; it->op_id = rid; if (NULL != zone) { it->zone = *zone; it->has_zone = GNUNET_YES; } else { memset (&it->zone, '\0', sizeof (it->zone)); it->has_zone = GNUNET_NO; } GNUNET_CONTAINER_DLL_insert_tail(h->z_head, h->z_tail, it); /* set msg_size*/ msg_size = sizeof (struct ZoneIterationStartMessage); pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); /* create msg here */ struct ZoneIterationStartMessage * msg; pe->size = msg_size; pe->is_init = GNUNET_NO; msg = (struct ZoneIterationStartMessage *) &pe[1]; msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START); msg->gns_header.header.size = htons (msg_size); msg->gns_header.r_id = htonl (rid); if (NULL != zone) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for zone `%s'\n", "ZONE_ITERATION_START", GNUNET_short_h2s(zone)); msg->zone = *zone; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for all zones\n", "ZONE_ITERATION_START"); memset (&msg->zone, '\0', sizeof (msg->zone)); } msg->must_have_flags = ntohs (must_have_flags); msg->must_not_have_flags = ntohs (must_not_have_flags); /* transmit message */ GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); do_transmit(h); return it; } /** * Calls the record processor specified in GNUNET_NAMESTORE_zone_iteration_start * for the next record. * * @param it the iterator */ void GNUNET_NAMESTORE_zone_iterator_next (struct GNUNET_NAMESTORE_ZoneIterator *it) { struct GNUNET_NAMESTORE_Handle *h; struct PendingMessage *pe; size_t msg_size = 0; GNUNET_assert (NULL != it); h = it->h; struct GNUNET_NAMESTORE_ZoneIterator *tmp = it->h->z_head; while (tmp != NULL) { if (tmp == it) break; tmp = tmp->next; } GNUNET_assert (NULL != tmp); /* set msg_size*/ msg_size = sizeof (struct ZoneIterationNextMessage); pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); /* create msg here */ struct ZoneIterationNextMessage * msg; pe->size = msg_size; pe->is_init = GNUNET_NO; msg = (struct ZoneIterationNextMessage *) &pe[1]; msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT); msg->gns_header.header.size = htons (msg_size); msg->gns_header.r_id = htonl (it->op_id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message\n", "ZONE_ITERATION_NEXT"); /* transmit message */ GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); do_transmit(h); } /** * Stops iteration and releases the namestore handle for further calls. * * @param it the iterator */ void GNUNET_NAMESTORE_zone_iteration_stop (struct GNUNET_NAMESTORE_ZoneIterator *it) { GNUNET_assert (NULL != it); struct PendingMessage *pe; size_t msg_size = 0; struct GNUNET_NAMESTORE_Handle *h = it->h; struct GNUNET_NAMESTORE_ZoneIterator *tmp = it->h->z_head; while (tmp != NULL) { if (tmp == it) break; tmp = tmp->next; } GNUNET_assert (NULL != tmp); /* set msg_size*/ msg_size = sizeof (struct ZoneIterationStopMessage); pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); /* create msg here */ struct ZoneIterationStopMessage * msg; pe->size = msg_size; pe->is_init = GNUNET_NO; msg = (struct ZoneIterationStopMessage *) &pe[1]; msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP); msg->gns_header.header.size = htons (msg_size); msg->gns_header.r_id = htonl (it->op_id); if (GNUNET_YES == it->has_zone) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for zone `%s'\n", "ZONE_ITERATION_STOP", GNUNET_short_h2s(&it->zone)); else GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for all zones\n", "ZONE_ITERATION_STOP"); /* transmit message */ GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); do_transmit(h); } /** * Cancel a namestore operation. The final callback from the * operation must not have been done yet. * * @param qe operation to cancel */ void GNUNET_NAMESTORE_cancel (struct GNUNET_NAMESTORE_QueueEntry *qe) { struct GNUNET_NAMESTORE_Handle *h = qe->nsh; GNUNET_assert (qe != NULL); GNUNET_CONTAINER_DLL_remove(h->op_head, h->op_tail, qe); GNUNET_free(qe); } /* end of namestore_api.c */ gnunet-0.9.3/src/namestore/test_namestore_api_zone_iteration_specific_zone.c0000644000175000017500000003037611760517435024614 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file namestore/test_namestore_api_zone_iteration_specific_zone.c * @brief testcase for zone iteration functionality: iterate of a specific zone */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_namestore_service.h" #include "namestore.h" #define VERBOSE GNUNET_NO #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) static struct GNUNET_NAMESTORE_Handle * nsh; static GNUNET_SCHEDULER_TaskIdentifier endbadly_task; static GNUNET_SCHEDULER_TaskIdentifier stopiteration_task; static struct GNUNET_OS_Process *arm; static struct GNUNET_CRYPTO_RsaPrivateKey * privkey; static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubkey; static struct GNUNET_CRYPTO_ShortHashCode zone; static struct GNUNET_CRYPTO_RsaPrivateKey * privkey2; static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubkey2; static struct GNUNET_CRYPTO_ShortHashCode zone2; static struct GNUNET_NAMESTORE_ZoneIterator *zi; static int res; static int returned_records; struct GNUNET_CRYPTO_RsaSignature *sig_1; char * s_name_1; struct GNUNET_NAMESTORE_RecordData *s_rd_1; struct GNUNET_CRYPTO_RsaSignature *sig_2; char * s_name_2; struct GNUNET_NAMESTORE_RecordData *s_rd_2; struct GNUNET_CRYPTO_RsaSignature *sig_3; char * s_name_3; struct GNUNET_NAMESTORE_RecordData *s_rd_3; static void start_arm (const char *cfgname) { arm = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, #if VERBOSE_PEERS "-L", "DEBUG", #else "-L", "ERROR", #endif NULL); } static void stop_arm () { if (NULL != arm) { if (0 != GNUNET_OS_process_kill (arm, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); GNUNET_OS_process_wait (arm); GNUNET_OS_process_destroy (arm); arm = NULL; } } /** * Re-establish the connection to the service. * * @param cls handle to use to re-connect. * @param tc scheduler context */ static void endbadly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (stopiteration_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (stopiteration_task); stopiteration_task = GNUNET_SCHEDULER_NO_TASK; } if (nsh != NULL) GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); nsh = NULL; GNUNET_free_non_null(sig_1); GNUNET_free_non_null(sig_2); GNUNET_free_non_null(sig_3); GNUNET_free_non_null(s_name_1); GNUNET_free_non_null(s_name_2); GNUNET_free_non_null(s_name_3); if (s_rd_1 != NULL) { GNUNET_free ((void *)s_rd_1->data); GNUNET_free (s_rd_1); } if (s_rd_2 != NULL) { GNUNET_free ((void *)s_rd_2->data); GNUNET_free (s_rd_2); } if (s_rd_3 != NULL) { GNUNET_free ((void *)s_rd_3->data); GNUNET_free (s_rd_3); } if (privkey != NULL) GNUNET_CRYPTO_rsa_key_free (privkey); privkey = NULL; if (privkey2 != NULL) GNUNET_CRYPTO_rsa_key_free (privkey2); privkey2 = NULL; if (NULL != arm) stop_arm(); res = 1; } static void end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (stopiteration_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (stopiteration_task); stopiteration_task = GNUNET_SCHEDULER_NO_TASK; } if (endbadly_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (endbadly_task); endbadly_task = GNUNET_SCHEDULER_NO_TASK; } if (privkey != NULL) GNUNET_CRYPTO_rsa_key_free (privkey); privkey = NULL; if (privkey2 != NULL) GNUNET_CRYPTO_rsa_key_free (privkey2); privkey2 = NULL; GNUNET_free (sig_1); GNUNET_free (sig_2); GNUNET_free (sig_3); GNUNET_free (s_name_1); GNUNET_free (s_name_2); GNUNET_free (s_name_3); if (s_rd_1 != NULL) { GNUNET_free ((void *)s_rd_1->data); GNUNET_free (s_rd_1); } if (s_rd_2 != NULL) { GNUNET_free ((void *)s_rd_2->data); GNUNET_free (s_rd_2); } if (s_rd_3 != NULL) { GNUNET_free ((void *)s_rd_3->data); GNUNET_free (s_rd_3); } if (nsh != NULL) GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); nsh = NULL; if (NULL != arm) stop_arm(); } void zone_proc (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *name, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { int failed = GNUNET_NO; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Callback for zone `%s'\n", GNUNET_short_h2s (&zone)); if ((zone_key == NULL) && (name == NULL)) { GNUNET_break (2 == returned_records); if (2 == returned_records) res = 0; else res = 1; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received last result, iteration done after %u records\n", returned_records); GNUNET_SCHEDULER_add_now (&end, NULL); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Comparing results name %s \n", name); if (0 == strcmp (name, s_name_1)) { if (rd_count == 1) { if (GNUNET_YES != GNUNET_NAMESTORE_records_cmp(rd, s_rd_1)) { failed = GNUNET_YES; GNUNET_break (0); } } else { failed = GNUNET_YES; GNUNET_break (0); } if (0 != memcmp (signature, sig_1, sizeof (struct GNUNET_CRYPTO_RsaSignature))) { failed = GNUNET_YES; GNUNET_break (0); } } else if (0 == strcmp (name, s_name_2)) { if (rd_count == 1) { if (GNUNET_YES != GNUNET_NAMESTORE_records_cmp(rd, s_rd_2)) { failed = GNUNET_YES; GNUNET_break (0); } } else { failed = GNUNET_YES; GNUNET_break (0); } if (0 != memcmp (signature, sig_2, sizeof (struct GNUNET_CRYPTO_RsaSignature))) { failed = GNUNET_YES; GNUNET_break (0); } } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Comparing result failed: got name `%s'\n", name); res = 1; GNUNET_break (0); GNUNET_SCHEDULER_add_now (&end, NULL); } if (failed == GNUNET_NO) { returned_records ++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Telling namestore to send the next result\n"); GNUNET_NAMESTORE_zone_iterator_next (zi); } else { GNUNET_break (0); GNUNET_SCHEDULER_add_now (&end, NULL); } } } void delete_existing_db (const struct GNUNET_CONFIGURATION_Handle *cfg) { char *afsdir; if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, "namestore-sqlite", "FILENAME", &afsdir)) { if (GNUNET_OK == GNUNET_DISK_file_test (afsdir)) if (GNUNET_OK == GNUNET_DISK_file_test (afsdir)) if (GNUNET_OK == GNUNET_DISK_directory_remove(afsdir)) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleted existing database `%s' \n", afsdir); GNUNET_free (afsdir); } } void put_cont (void *cls, int32_t success, const char *emsg) { static int c = 0; if (success == GNUNET_OK) { c++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created record %u \n", c); } else { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to created records\n"); GNUNET_break (0); GNUNET_SCHEDULER_cancel (endbadly_task); endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL); } if (c == 3) { res = 1; returned_records = 0; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All records created, starting iteration over zone `%s'\n", GNUNET_short_h2s(&zone)); zi = GNUNET_NAMESTORE_zone_iteration_start(nsh, &zone, GNUNET_NAMESTORE_RF_NONE, GNUNET_NAMESTORE_RF_NONE, zone_proc, &zone); if (zi == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to create zone iterator\n"); GNUNET_break (0); GNUNET_SCHEDULER_cancel (endbadly_task); endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL); } } } static struct GNUNET_NAMESTORE_RecordData * create_record (int count) { int c; struct GNUNET_NAMESTORE_RecordData * rd; rd = GNUNET_malloc (count * sizeof (struct GNUNET_NAMESTORE_RecordData)); for (c = 0; c < count; c++) { rd[c].expiration = GNUNET_TIME_absolute_get(); rd[c].record_type = 1111; rd[c].data_size = 50; rd[c].data = GNUNET_malloc(50); memset ((char *) rd[c].data, 'a', 50); } return rd; } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { delete_existing_db(cfg); endbadly_task = GNUNET_SCHEDULER_add_delayed(TIMEOUT,&endbadly, NULL); char *hostkey_file; GNUNET_asprintf(&hostkey_file,"zonefiles%s%s",DIR_SEPARATOR_STR, "N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using zonekey file `%s' \n", hostkey_file); privkey = GNUNET_CRYPTO_rsa_key_create_from_file(hostkey_file); GNUNET_free (hostkey_file); GNUNET_assert (privkey != NULL); GNUNET_CRYPTO_rsa_key_get_public(privkey, &pubkey); GNUNET_CRYPTO_short_hash (&pubkey, sizeof (pubkey), &zone); GNUNET_asprintf(&hostkey_file,"zonefiles%s%s",DIR_SEPARATOR_STR, "HGU0A0VCU334DN7F2I9UIUMVQMM7JMSD142LIMNUGTTV9R0CF4EG.zkey"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using zonekey file `%s' \n", hostkey_file); privkey2 = GNUNET_CRYPTO_rsa_key_create_from_file(hostkey_file); GNUNET_free (hostkey_file); GNUNET_assert (privkey2 != NULL); GNUNET_CRYPTO_rsa_key_get_public(privkey2, &pubkey2); GNUNET_CRYPTO_short_hash (&pubkey2, sizeof (pubkey), &zone2); start_arm (cfgfile); GNUNET_assert (arm != NULL); nsh = GNUNET_NAMESTORE_connect (cfg); GNUNET_break (NULL != nsh); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created record 1\n"); GNUNET_asprintf(&s_name_1, "dummy1"); s_rd_1 = create_record(1); sig_1 = GNUNET_NAMESTORE_create_signature(privkey, s_rd_1[0].expiration ,s_name_1, s_rd_1, 1); GNUNET_NAMESTORE_record_create(nsh, privkey, s_name_1, s_rd_1, &put_cont, NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created record 2 \n"); GNUNET_asprintf(&s_name_2, "dummy2"); s_rd_2 = create_record(1); sig_2 = GNUNET_NAMESTORE_create_signature(privkey, s_rd_2[0].expiration, s_name_2, s_rd_2, 1); GNUNET_NAMESTORE_record_create(nsh, privkey, s_name_2, s_rd_2, &put_cont, NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created record 3\n"); /* name in different zone */ GNUNET_asprintf(&s_name_3, "dummy3"); s_rd_3 = create_record(1); sig_3 = GNUNET_NAMESTORE_create_signature(privkey, s_rd_3[0].expiration, s_name_3, s_rd_3, 1); GNUNET_NAMESTORE_record_put (nsh, &pubkey2, s_name_3, GNUNET_TIME_UNIT_FOREVER_ABS, 1, s_rd_3, sig_3, &put_cont, NULL); } static int check () { static char *const argv[] = { "test_namestore_api_zone_iteration", "-c", "test_namestore_api.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; res = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test_namestore_api_zone_iteration", "nohelp", options, &run, &res); return res; } int main (int argc, char *argv[]) { int ret; ret = check (); return ret; } /* end of test_namestore_api_zone_iteration_specific_zone.c */ gnunet-0.9.3/src/namestore/Makefile.am0000644000175000017500000001425611751542714014603 00000000000000INCLUDES = -I$(top_srcdir)/src/include plugindir = $(libdir)/gnunet pkgcfgdir= $(pkgdatadir)/config.d/ pkgcfg_DATA = \ namestore.conf if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIBS = -lgcov endif if HAVE_SQLITE SQLITE_TESTS = \ test_plugin_namestore_sqlite endif check_PROGRAMS = \ $(SQLITE_TESTS) \ test_namestore_record_serialization \ test_namestore_api_sign_verify \ test_namestore_api \ test_namestore_api_put \ test_namestore_api_lookup \ test_namestore_api_lookup_specific_type \ test_namestore_api_create \ test_namestore_api_create_update \ test_namestore_api_remove \ test_namestore_api_remove_not_existing_record \ test_namestore_api_zone_to_name \ test_namestore_api_zone_iteration \ test_namestore_api_zone_iteration_specific_zone \ test_namestore_api_zone_iteration_stop if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) endif lib_LTLIBRARIES = \ libgnunetnamestore.la libgnunetnamestore_la_SOURCES = \ namestore_api.c namestore_common.c namestore.h libgnunetnamestore_la_LIBADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) libgnunetnamestore_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 0:0:0 bin_PROGRAMS = \ gnunet-service-namestore \ gnunet-namestore gnunet_namestore_SOURCES = \ gnunet-namestore.c gnunet_namestore_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ libgnunetnamestore.la \ $(GN_LIBINTL) gnunet_namestore_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ libgnunetnamestore.la gnunet_service_namestore_SOURCES = \ gnunet-service-namestore.c gnunet_service_namestore_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ libgnunetnamestore.la \ $(GN_LIBINTL) gnunet_service_namestore_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ libgnunetnamestore.la if HAVE_SQLITE SQLITE_PLUGIN = libgnunet_plugin_namestore_sqlite.la endif plugin_LTLIBRARIES = \ $(SQLITE_PLUGIN) libgnunet_plugin_namestore_sqlite_la_SOURCES = \ plugin_namestore_sqlite.c namestore_common.c libgnunet_plugin_namestore_sqlite_la_LIBADD = \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 libgnunet_plugin_namestore_sqlite_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_namestore_sqlite_la_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ libgnunetnamestore.la test_namestore_api_sign_verify_SOURCES = \ test_namestore_api_sign_verify.c test_namestore_api_sign_verify_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_SOURCES = \ test_namestore_api.c test_namestore_api_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_put_SOURCES = \ test_namestore_api_put.c test_namestore_api_put_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_lookup_SOURCES = \ test_namestore_api_lookup.c test_namestore_api_lookup_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_lookup_specific_type_SOURCES = \ test_namestore_api_lookup_specific_type.c test_namestore_api_lookup_specific_type_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_create_SOURCES = \ test_namestore_api_create.c test_namestore_api_create_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_create_update_SOURCES = \ test_namestore_api_create_update.c test_namestore_api_create_update_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_remove_SOURCES = \ test_namestore_api_remove.c test_namestore_api_remove_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_remove_not_existing_record_SOURCES = \ test_namestore_api_remove_not_existing_record.c test_namestore_api_remove_not_existing_record_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_zone_to_name_SOURCES = \ test_namestore_api_zone_to_name.c test_namestore_api_zone_to_name_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_zone_iteration_SOURCES = \ test_namestore_api_zone_iteration.c test_namestore_api_zone_iteration_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_zone_iteration_specific_zone_SOURCES = \ test_namestore_api_zone_iteration_specific_zone.c test_namestore_api_zone_iteration_specific_zone_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_zone_iteration_stop_SOURCES = \ test_namestore_api_zone_iteration_stop.c test_namestore_api_zone_iteration_stop_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_record_serialization_SOURCES = \ test_namestore_record_serialization.c test_namestore_record_serialization_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la EXTRA_DIST = \ test_namestore_api.conf \ test_plugin_namestore_sqlite.conf\ test_hostkey \ zonefiles/HGU0A0VCU334DN7F2I9UIUMVQMM7JMSD142LIMNUGTTV9R0CF4EG.zkey \ zonefiles/N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey test_plugin_namestore_sqlite_SOURCES = \ test_plugin_namestore.c test_plugin_namestore_sqlite_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la gnunet-0.9.3/src/namestore/gnunet-namestore.c0000644000175000017500000003145311760515322016177 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file gnunet-namestore.c * @brief command line tool to manipulate the local zone * @author Christian Grothoff * * TODO: * - allow users to set record options (not just 'RF_AUTHORITY') * - test * - add options to list/lookup individual records */ #include "platform.h" #include #include #include /** * Handle to the namestore. */ static struct GNUNET_NAMESTORE_Handle *ns; /** * Hash of the public key of our zone. */ static struct GNUNET_CRYPTO_ShortHashCode zone; /** * Private key for the our zone. */ static struct GNUNET_CRYPTO_RsaPrivateKey *zone_pkey; /** * Keyfile to manipulate. */ static char *keyfile; /** * Desired action is to add a record. */ static int add; /** * Queue entry for the 'add' operation. */ static struct GNUNET_NAMESTORE_QueueEntry *add_qe; /** * Desired action is to list records. */ static int list; /** * List iterator for the 'list' operation. */ static struct GNUNET_NAMESTORE_ZoneIterator *list_it; /** * Desired action is to remove a record. */ static int del; /** * Is record public */ static int public; /** * Is record authority */ static int nonauthority; /** * Queue entry for the 'del' operation. */ static struct GNUNET_NAMESTORE_QueueEntry *del_qe; /** * Name of the records to add/list/remove. */ static char *name; /** * Value of the record to add/remove. */ static char *value; /** * Type of the record to add/remove, NULL to remove all. */ static char *typestring; /** * Desired expiration time. */ static char *expirationstring; /** * Task run on shutdown. Cleans up everything. * * @param cls unused * @param tc scheduler context */ static void do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (NULL != ns) { GNUNET_NAMESTORE_disconnect (ns, GNUNET_NO); ns = NULL; } if (NULL != zone_pkey) { GNUNET_CRYPTO_rsa_key_free (zone_pkey); zone_pkey = NULL; } } /** * Continuation called to notify client about result of the * operation. * * @param cls closure, unused * @param success GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate) * GNUNET_NO if content was already there * GNUNET_YES (or other positive value) on success * @param emsg NULL on success, otherwise an error message */ static void add_continuation (void *cls, int32_t success, const char *emsg) { add_qe = NULL; if (success != GNUNET_YES) fprintf (stderr, _("Adding record failed: %s\n"), (success == GNUNET_NO) ? "record exists" : emsg); if ( (NULL == del_qe) && (NULL == list_it) ) GNUNET_SCHEDULER_shutdown (); } /** * Continuation called to notify client about result of the * operation. * * @param cls closure, unused * @param success GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate) * GNUNET_NO if content was already there * GNUNET_YES (or other positive value) on success * @param emsg NULL on success, otherwise an error message */ static void del_continuation (void *cls, int32_t success, const char *emsg) { del_qe = NULL; if (success != GNUNET_YES) fprintf (stderr, _("Deleting record failed: %s\n"), emsg); if ( (NULL == add_qe) && (NULL == list_it) ) GNUNET_SCHEDULER_shutdown (); } /** * Process a record that was stored in the namestore. * * @param cls closure * @param zone_key public key of the zone * @param expire when does the corresponding block in the DHT expire (until * when should we never do a DHT lookup for the same name again)?; * GNUNET_TIME_UNIT_ZERO_ABS if there are no records of any type in the namestore, * or the expiration time of the block in the namestore (even if there are zero * records matching the desired record type) * @param name name that is being mapped (at most 255 characters long) * @param rd_len number of entries in 'rd' array * @param rd array of records with data to store * @param signature signature of the record block, NULL if signature is unavailable (i.e. * because the user queried for a particular record type only) */ static void display_record (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *name, unsigned int rd_len, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { const char *typestring; char *s; unsigned int i; if (NULL == name) { list_it = NULL; if ( (NULL == del_qe) && (NULL == add_qe) ) GNUNET_SCHEDULER_shutdown (); return; } FPRINTF (stdout, "%s:\n", name); for (i=0;idata); GNUNET_free (s_rd_1); } if (s_rd_2 != NULL) { GNUNET_free ((void *)s_rd_2->data); GNUNET_free (s_rd_2); } if (s_rd_3 != NULL) { GNUNET_free ((void *)s_rd_3->data); GNUNET_free (s_rd_3); } if (privkey != NULL) GNUNET_CRYPTO_rsa_key_free (privkey); privkey = NULL; if (privkey2 != NULL) GNUNET_CRYPTO_rsa_key_free (privkey2); privkey2 = NULL; if (NULL != arm) stop_arm(); res = 1; } static void end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (stopiteration_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (stopiteration_task); stopiteration_task = GNUNET_SCHEDULER_NO_TASK; } if (endbadly_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (endbadly_task); endbadly_task = GNUNET_SCHEDULER_NO_TASK; } if (privkey != NULL) GNUNET_CRYPTO_rsa_key_free (privkey); privkey = NULL; if (privkey2 != NULL) GNUNET_CRYPTO_rsa_key_free (privkey2); privkey2 = NULL; GNUNET_free (sig_1); GNUNET_free (sig_2); GNUNET_free (sig_3); GNUNET_free (s_name_1); GNUNET_free (s_name_2); GNUNET_free (s_name_3); if (s_rd_1 != NULL) { GNUNET_free ((void *)s_rd_1->data); GNUNET_free (s_rd_1); } if (s_rd_2 != NULL) { GNUNET_free ((void *)s_rd_2->data); GNUNET_free (s_rd_2); } if (s_rd_3 != NULL) { GNUNET_free ((void *)s_rd_3->data); GNUNET_free (s_rd_3); } if (nsh != NULL) GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); nsh = NULL; if (NULL != arm) stop_arm(); if (returned_records == 1) res = 0; else res = 1; } void zone_proc (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *name, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { int failed = GNUNET_NO; if ((zone_key == NULL) && (name == NULL)) { GNUNET_break (3 == returned_records); if (3 == returned_records) res = 0; else res = 1; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received last result, iteration done after receing %u results\n",returned_records ); GNUNET_SCHEDULER_add_now (&end, NULL); } else { /* verify signature returned from name store */ if (GNUNET_OK != GNUNET_NAMESTORE_verify_signature(zone_key, expire, name, rd_count, rd, signature)) { failed = GNUNET_YES; GNUNET_break (0); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Comparing results name %s \n", name); if (0 == strcmp (name, s_name_1)) { /* name_1 */ if (rd_count == 1) { if (GNUNET_YES != GNUNET_NAMESTORE_records_cmp(rd, s_rd_1)) { failed = GNUNET_YES; GNUNET_break (0); } } else { failed = GNUNET_YES; GNUNET_break (0); } if (GNUNET_OK != GNUNET_NAMESTORE_verify_signature(&pubkey, expire, s_name_1, 1, s_rd_1, signature)) { failed = GNUNET_YES; GNUNET_break (0); } } else if (0 == strcmp (name, s_name_2)) { /* name_2 */ if (rd_count == 1) { if (GNUNET_YES != GNUNET_NAMESTORE_records_cmp(rd, s_rd_2)) { failed = GNUNET_YES; GNUNET_break (0); } } else { failed = GNUNET_YES; GNUNET_break (0); } if (GNUNET_OK != GNUNET_NAMESTORE_verify_signature(&pubkey, expire, s_name_2, 1, s_rd_2, signature)) { failed = GNUNET_YES; GNUNET_break (0); } } else if (0 == strcmp (name, s_name_3)) { /* name_3 */ if (rd_count == 1) { if (GNUNET_YES != GNUNET_NAMESTORE_records_cmp(rd, s_rd_3)) { failed = GNUNET_YES; GNUNET_break (0); } } else { failed = GNUNET_YES; GNUNET_break (0); } if (GNUNET_OK != GNUNET_NAMESTORE_verify_signature(&pubkey2, expire, s_name_3, 1, s_rd_3, signature)) { failed = GNUNET_YES; GNUNET_break (0); } } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Comparing result failed: got name `%s'\n", name); res = 1; GNUNET_break (0); GNUNET_SCHEDULER_add_now (&end, NULL); } if (failed == GNUNET_NO) { returned_records ++; if (1 == returned_records) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping zone iteration after %u received record \n",returned_records ); GNUNET_NAMESTORE_zone_iteration_stop (zi); if (endbadly_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (endbadly_task); endbadly_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3), &end , NULL); return; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Telling namestore to send the next result\n"); GNUNET_NAMESTORE_zone_iterator_next (zi); } } else { GNUNET_break (0); GNUNET_SCHEDULER_add_now (&end, NULL); } } } void delete_existing_db (const struct GNUNET_CONFIGURATION_Handle *cfg) { char *afsdir; if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, "namestore-sqlite", "FILENAME", &afsdir)) { if (GNUNET_OK == GNUNET_DISK_file_test (afsdir)) if (GNUNET_OK == GNUNET_DISK_file_test (afsdir)) if (GNUNET_OK == GNUNET_DISK_directory_remove(afsdir)) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleted existing database `%s' \n", afsdir); GNUNET_free (afsdir); } } void put_cont (void *cls, int32_t success, const char *emsg) { static int c = 0; if (success == GNUNET_OK) { c++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created record %u \n", c); } else { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to created records\n"); GNUNET_break (0); GNUNET_SCHEDULER_cancel (endbadly_task); endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL); } if (c == 3) { res = 1; returned_records = 0; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All records created, starting iteration over all zones \n"); zi = GNUNET_NAMESTORE_zone_iteration_start(nsh, NULL, GNUNET_NAMESTORE_RF_NONE, GNUNET_NAMESTORE_RF_NONE, zone_proc, &zone); if (zi == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to create zone iterator\n"); GNUNET_break (0); GNUNET_SCHEDULER_cancel (endbadly_task); endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL); } } } static struct GNUNET_NAMESTORE_RecordData * create_record (int count) { int c; struct GNUNET_NAMESTORE_RecordData * rd; rd = GNUNET_malloc (count * sizeof (struct GNUNET_NAMESTORE_RecordData)); for (c = 0; c < count; c++) { rd[c].expiration = GNUNET_TIME_absolute_get(); rd[c].record_type = 1111; rd[c].data_size = 50; rd[c].data = GNUNET_malloc(50); memset ((char *) rd[c].data, 'a', 50); } return rd; } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { delete_existing_db(cfg); endbadly_task = GNUNET_SCHEDULER_add_delayed(TIMEOUT,&endbadly, NULL); char *hostkey_file; GNUNET_asprintf(&hostkey_file,"zonefiles%s%s",DIR_SEPARATOR_STR, "N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using zonekey file `%s' \n", hostkey_file); privkey = GNUNET_CRYPTO_rsa_key_create_from_file(hostkey_file); GNUNET_free (hostkey_file); GNUNET_assert (privkey != NULL); GNUNET_CRYPTO_rsa_key_get_public(privkey, &pubkey); GNUNET_CRYPTO_hash(&pubkey, sizeof (pubkey), &zone); GNUNET_asprintf(&hostkey_file,"zonefiles%s%s",DIR_SEPARATOR_STR, "HGU0A0VCU334DN7F2I9UIUMVQMM7JMSD142LIMNUGTTV9R0CF4EG.zkey"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using zonekey file `%s' \n", hostkey_file); privkey2 = GNUNET_CRYPTO_rsa_key_create_from_file(hostkey_file); GNUNET_free (hostkey_file); GNUNET_assert (privkey2 != NULL); GNUNET_CRYPTO_rsa_key_get_public(privkey2, &pubkey2); GNUNET_CRYPTO_hash(&pubkey2, sizeof (pubkey), &zone2); start_arm (cfgfile); GNUNET_assert (arm != NULL); nsh = GNUNET_NAMESTORE_connect (cfg); GNUNET_break (NULL != nsh); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created record 1\n"); GNUNET_asprintf(&s_name_1, "dummy1"); s_rd_1 = create_record(1); sig_1 = GNUNET_NAMESTORE_create_signature(privkey, s_rd_1[0].expiration, s_name_1, s_rd_1, 1); GNUNET_NAMESTORE_record_create(nsh, privkey, s_name_1, s_rd_1, &put_cont, NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created record 2 \n"); GNUNET_asprintf(&s_name_2, "dummy2"); s_rd_2 = create_record(1); sig_2 = GNUNET_NAMESTORE_create_signature(privkey, s_rd_2[0].expiration, s_name_2, s_rd_2, 1); GNUNET_NAMESTORE_record_create(nsh, privkey, s_name_2, s_rd_2, &put_cont, NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created record 3\n"); /* name in different zone */ GNUNET_asprintf(&s_name_3, "dummy3"); s_rd_3 = create_record(1); sig_3 = GNUNET_NAMESTORE_create_signature(privkey2, s_rd_3[0].expiration, s_name_3, s_rd_3, 1); GNUNET_NAMESTORE_record_put (nsh, &pubkey2, s_name_3, GNUNET_TIME_UNIT_FOREVER_ABS, 1, s_rd_3, sig_3, &put_cont, NULL); } static int check () { static char *const argv[] = { "test_namestore_api_zone_iteration", "-c", "test_namestore_api.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; res = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test_namestore_api_zone_iteration", "nohelp", options, &run, &res); return res; } int main (int argc, char *argv[]) { int ret; ret = check (); return ret; } /* end of test_namestore_api_zone_iteration.c */ gnunet-0.9.3/src/namestore/test_namestore_api_create_update.c0000644000175000017500000003440511760517573021470 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file namestore/test_namestore_api.c * @brief testcase for namestore_api.c for updating an existing record */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_namestore_service.h" #include "namestore.h" #include "gnunet_signatures.h" #define VERBOSE GNUNET_NO #define RECORDS 1 #define TEST_RECORD_TYPE 1234 #define TEST_RECORD_DATALEN 123 #define TEST_RECORD_DATA 'a' #define TEST_CREATE_RECORD_TYPE 4321 #define TEST_CREATE_RECORD_DATALEN 255 #define TEST_CREATE_RECORD_DATA 'b' #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) static struct GNUNET_NAMESTORE_Handle * nsh; static GNUNET_SCHEDULER_TaskIdentifier endbadly_task; static struct GNUNET_OS_Process *arm; static struct GNUNET_CRYPTO_RsaPrivateKey * privkey; static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubkey; struct GNUNET_CRYPTO_RsaSignature *s_signature; struct GNUNET_CRYPTO_RsaSignature *s_signature_updated; static struct GNUNET_CRYPTO_ShortHashCode s_zone; struct GNUNET_NAMESTORE_RecordData *s_first_record; struct GNUNET_NAMESTORE_RecordData *s_second_record; static char *s_name; static int res; static void start_arm (const char *cfgname) { arm = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, #if VERBOSE_PEERS "-L", "DEBUG", #else "-L", "ERROR", #endif NULL); } static void stop_arm () { if (NULL != arm) { if (0 != GNUNET_OS_process_kill (arm, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); GNUNET_OS_process_wait (arm); GNUNET_OS_process_destroy (arm); arm = NULL; } } /** * Re-establish the connection to the service. * * @param cls handle to use to re-connect. * @param tc scheduler context */ static void endbadly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (nsh != NULL) GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); nsh = NULL; if (privkey != NULL) GNUNET_CRYPTO_rsa_key_free (privkey); privkey = NULL; if (NULL != arm) stop_arm(); res = 1; } static void end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (endbadly_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (endbadly_task); endbadly_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_free ((void *) s_first_record->data); GNUNET_free (s_first_record); GNUNET_free_non_null (s_second_record); if (privkey != NULL) GNUNET_CRYPTO_rsa_key_free (privkey); privkey = NULL; if (nsh != NULL) GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); nsh = NULL; if (NULL != arm) stop_arm(); } void name_lookup_second_proc (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *n, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { static int found = GNUNET_NO; int failed = GNUNET_NO; int c; if (n != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking returned results\n"); if (0 != memcmp (zone_key, &pubkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded))) { GNUNET_break (0); failed = GNUNET_YES; } if (0 != strcmp(n, s_name)) { GNUNET_break (0); failed = GNUNET_YES; } if (2 != rd_count) { GNUNET_break (0); failed = GNUNET_YES; } for (c = 0; c < rd_count; c++) { if ((GNUNET_NO == GNUNET_NAMESTORE_records_cmp(&rd[c], s_first_record)) && (GNUNET_NO == GNUNET_NAMESTORE_records_cmp(&rd[c], s_second_record))) { GNUNET_break (0); failed = GNUNET_YES; } } if (GNUNET_OK != GNUNET_NAMESTORE_verify_signature(&pubkey, expire, n, rd_count, rd, signature)) { GNUNET_break (0); failed = GNUNET_YES; } struct GNUNET_NAMESTORE_RecordData rd_new[2]; rd_new[0] = *s_first_record; rd_new[1] = *s_second_record; s_signature_updated = GNUNET_NAMESTORE_create_signature(privkey, expire, s_name, rd_new, 2); if (0 != memcmp (s_signature_updated, signature, sizeof (struct GNUNET_CRYPTO_RsaSignature))) { GNUNET_break (0); failed = GNUNET_YES; } found = GNUNET_YES; if (failed == GNUNET_NO) res = 0; else res = 1; } else { if (found != GNUNET_YES) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to lookup records for name `%s'\n", s_name); res = 1; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Lookup done for name %s'\n", s_name); } GNUNET_SCHEDULER_add_now(&end, NULL); } void create_second_cont (void *cls, int32_t success, const char *emsg) { char *name = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Create second record for `%s': %s\n", name, (success == GNUNET_OK) ? "SUCCESS" : "FAIL"); if (success == GNUNET_OK) { res = 0; GNUNET_NAMESTORE_lookup_record (nsh, &s_zone, name, 0, &name_lookup_second_proc, name); } else { res = 1; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to put records for name `%s'\n", name); GNUNET_SCHEDULER_add_now(&end, NULL); } } void name_lookup_initial_proc (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *n, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { char * name = cls; static int found = GNUNET_NO; int failed = GNUNET_NO; int c; if (n != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking returned results\n"); if (0 != memcmp (zone_key, &pubkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded))) { GNUNET_break (0); failed = GNUNET_YES; } if (0 != strcmp(n, s_name)) { GNUNET_break (0); failed = GNUNET_YES; } if (RECORDS != rd_count) { GNUNET_break (0); failed = GNUNET_YES; } for (c = 0; c < RECORDS; c++) { if (GNUNET_NO == GNUNET_NAMESTORE_records_cmp(&rd[c], &s_first_record[c])) { GNUNET_break (0); failed = GNUNET_YES; } } if (GNUNET_OK != GNUNET_NAMESTORE_verify_signature(&pubkey, expire, n, rd_count, rd, signature)) { GNUNET_break (0); failed = GNUNET_YES; } if (0 != memcmp (s_signature, signature, sizeof (struct GNUNET_CRYPTO_RsaSignature))) { GNUNET_break (0); failed = GNUNET_YES; } found = GNUNET_YES; if (failed == GNUNET_NO) res = 0; else res = 1; /* create a second record */ s_second_record = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_RecordData) + TEST_CREATE_RECORD_DATALEN); s_second_record->expiration = GNUNET_TIME_UNIT_FOREVER_ABS; s_second_record->record_type = TEST_CREATE_RECORD_TYPE; s_second_record->flags = GNUNET_NAMESTORE_RF_AUTHORITY; s_second_record->data = &s_second_record[1]; s_second_record->data_size = TEST_CREATE_RECORD_DATALEN; memset ((char *) s_second_record->data, TEST_CREATE_RECORD_DATA, TEST_CREATE_RECORD_DATALEN); GNUNET_NAMESTORE_record_create (nsh, privkey, name, s_second_record, &create_second_cont, name); } else { if (found != GNUNET_YES) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to lookup records for name `%s'\n", s_name); res = 1; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Lookup done for name %s'\n", s_name); GNUNET_SCHEDULER_add_now (&end, NULL); } } void create_updated_cont (void *cls, int32_t success, const char *emsg) { char *name = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating expiration for record `%s': %s `%s'\n", name, ((success == GNUNET_YES) || (success == GNUNET_NO)) ? "SUCCESS" : "FAIL", emsg); if (success == GNUNET_NO) { res = 0; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updated record for name `%s'\n", name); } else if (success == GNUNET_OK) { res = 1; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "FAIL, Create new record for name `%s'\n", name); } else { res = 1; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to create records for name `%s'\n", name); } GNUNET_SCHEDULER_add_now(&end, NULL); } void create_identical_cont (void *cls, int32_t success, const char *emsg) { char *name = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating identical record for `%s': %s `%s'\n", name, ((success == GNUNET_YES) || (success == GNUNET_NO)) ? "SUCCESS" : "FAIL", emsg); if (success == GNUNET_NO) { res = 0; s_first_record->expiration = GNUNET_TIME_absolute_get (); GNUNET_NAMESTORE_record_create (nsh, privkey, s_name, s_first_record, &create_updated_cont, s_name); } else { res = 1; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating identical record for `%s': %s `%s'\n", name, ((success == GNUNET_YES) || (success == GNUNET_NO)) ? "SUCCESS" : "FAIL", emsg); GNUNET_SCHEDULER_add_now(&end, NULL); } } void create_first_cont (void *cls, int32_t success, const char *emsg) { char *name = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Create record for `%s': %s `%s'\n", name, (success == GNUNET_OK) ? "SUCCESS" : "FAIL", emsg); if (success == GNUNET_OK) { res = 0; /* check if record was created correct */ GNUNET_NAMESTORE_record_create (nsh, privkey, s_name, s_first_record, &create_identical_cont, s_name); } else { res = 1; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to put records for name `%s'\n", name); GNUNET_SCHEDULER_add_now(&end, NULL); } } void put_cont (void *cls, int32_t success, const char *emsg) { char *name = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Name store added record for `%s': %s `%s'\n", name, (success == GNUNET_OK) ? "SUCCESS" : "FAIL", emsg); if (success == GNUNET_OK) { } else { res = 1; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to put records for name `%s'\n", name); GNUNET_SCHEDULER_add_now(&end, NULL); } } static struct GNUNET_NAMESTORE_RecordData * create_record (int count) { int c; struct GNUNET_NAMESTORE_RecordData * rd; rd = GNUNET_malloc (count * sizeof (struct GNUNET_NAMESTORE_RecordData)); for (c = 0; c < count; c++) { rd[c].expiration = GNUNET_TIME_UNIT_ZERO_ABS; rd[c].record_type = TEST_RECORD_TYPE; rd[c].data_size = TEST_RECORD_DATALEN; rd[c].data = GNUNET_malloc(TEST_RECORD_DATALEN); memset ((char *) rd[c].data, TEST_RECORD_DATA, TEST_RECORD_DATALEN); } return rd; } void delete_existing_db (const struct GNUNET_CONFIGURATION_Handle *cfg) { char *afsdir; if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, "namestore-sqlite", "FILENAME", &afsdir)) { if (GNUNET_OK == GNUNET_DISK_file_test (afsdir)) if (GNUNET_OK == GNUNET_DISK_file_test (afsdir)) if (GNUNET_OK == GNUNET_DISK_directory_remove(afsdir)) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleted existing database `%s' \n", afsdir); GNUNET_free (afsdir); } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { delete_existing_db(cfg); endbadly_task = GNUNET_SCHEDULER_add_delayed(TIMEOUT,endbadly, NULL); size_t rd_ser_len; /* load privat key */ char *hostkey_file; GNUNET_asprintf(&hostkey_file,"zonefiles%s%s",DIR_SEPARATOR_STR, "N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using zonekey file `%s' \n", hostkey_file); privkey = GNUNET_CRYPTO_rsa_key_create_from_file(hostkey_file); GNUNET_free (hostkey_file); GNUNET_assert (privkey != NULL); /* get public key */ GNUNET_CRYPTO_rsa_key_get_public(privkey, &pubkey); /* create record */ s_name = "dummy.dummy.gnunet"; s_first_record = create_record (1); rd_ser_len = GNUNET_NAMESTORE_records_get_size(1, s_first_record); char rd_ser[rd_ser_len]; GNUNET_NAMESTORE_records_serialize(1, s_first_record, rd_ser_len, rd_ser); s_signature = GNUNET_NAMESTORE_create_signature(privkey, s_first_record->expiration, s_name, s_first_record, 1); /* create random zone hash */ GNUNET_CRYPTO_short_hash (&pubkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &s_zone); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Name: `%s' Zone: `%s' \n", s_name, GNUNET_short_h2s (&s_zone)); start_arm (cfgfile); GNUNET_assert (arm != NULL); nsh = GNUNET_NAMESTORE_connect (cfg); GNUNET_break (NULL != nsh); GNUNET_break (s_first_record != NULL); GNUNET_break (s_name != NULL); /* create initial record */ GNUNET_NAMESTORE_record_create (nsh, privkey, s_name, s_first_record, &create_first_cont, s_name); } static int check () { static char *const argv[] = { "test-namestore-api", "-c", "test_namestore_api.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; res = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-namestore-api", "nohelp", options, &run, &res); return res; } int main (int argc, char *argv[]) { int ret; ret = check (); GNUNET_free (s_signature); return ret; } /* end of test_namestore_api.c */ gnunet-0.9.3/src/namestore/plugin_namestore_sqlite.c0000644000175000017500000006601111760502550017635 00000000000000 /* * This file is part of GNUnet * (C) 2009, 2011, 2012 Christian Grothoff (and other contributing authors) * * GNUnet is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 3, or (at your * option) any later version. * * GNUnet is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNUnet; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /** * @file namestore/plugin_namestore_sqlite.c * @brief sqlite-based namestore backend * @author Christian Grothoff */ #include "platform.h" #include "gnunet_namestore_plugin.h" #include "gnunet_namestore_service.h" #include "namestore.h" #include /** * After how many ms "busy" should a DB operation fail for good? * A low value makes sure that we are more responsive to requests * (especially PUTs). A high value guarantees a higher success * rate (SELECTs in iterate can take several seconds despite LIMIT=1). * * The default value of 1s should ensure that users do not experience * huge latencies while at the same time allowing operations to succeed * with reasonable probability. */ #define BUSY_TIMEOUT_MS 1000 /** * Log an error message at log-level 'level' that indicates * a failure of the command 'cmd' on file 'filename' * with the message given by strerror(errno). */ #define LOG_SQLITE(db, level, cmd) do { GNUNET_log_from (level, "namestore-sqlite", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); } while(0) #define LOG(kind,...) GNUNET_log_from (kind, "namestore-sqlite", __VA_ARGS__) /** * Context for all functions in this plugin. */ struct Plugin { const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Database filename. */ char *fn; /** * Native SQLite database handle. */ sqlite3 *dbh; /** * Precompiled SQL for put record */ sqlite3_stmt *put_records; /** * Precompiled SQL for remove record */ sqlite3_stmt *remove_records; /** * Precompiled SQL for iterate over all records. */ sqlite3_stmt *iterate_all; /** * Precompiled SQL for iterate records with same name. */ sqlite3_stmt *iterate_by_name; /** * Precompiled SQL for iterate records with same zone. */ sqlite3_stmt *iterate_by_zone; /** * Precompiled SQL for iterate records with same name and zone. */ sqlite3_stmt *iterate_records; /** * Precompiled SQL to get the name for a given zone-value. */ sqlite3_stmt *zone_to_name; /** * Precompiled SQL for delete zone */ sqlite3_stmt *delete_zone; }; /** * @brief Prepare a SQL statement * * @param dbh handle to the database * @param zSql SQL statement, UTF-8 encoded * @param ppStmt set to the prepared statement * @return 0 on success */ static int sq_prepare (sqlite3 * dbh, const char *zSql, sqlite3_stmt ** ppStmt) { char *dummy; int result; result = sqlite3_prepare_v2 (dbh, zSql, strlen (zSql), ppStmt, (const char **) &dummy); LOG (GNUNET_ERROR_TYPE_DEBUG, "Prepared `%s' / %p: %d\n", zSql, *ppStmt, result); return result; } /** * Create our database indices. * * @param dbh handle to the database */ static void create_indices (sqlite3 * dbh) { /* create indices */ if ( (SQLITE_OK != sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_zone_name_rv ON ns091records (zone_hash,record_name_hash,rvalue)", NULL, NULL, NULL)) || (SQLITE_OK != sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_zone_delegation ON ns091records (zone_hash,zone_delegation)", NULL, NULL, NULL)) || (SQLITE_OK != sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_zone_rv ON ns091records (zone_hash,rvalue)", NULL, NULL, NULL)) || (SQLITE_OK != sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_zone ON ns091records (zone_hash)", NULL, NULL, NULL)) || (SQLITE_OK != sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_name_rv ON ns091records (record_name_hash,rvalue)", NULL, NULL, NULL)) || (SQLITE_OK != sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_rv ON ns091records (rvalue)", NULL, NULL, NULL)) ) LOG (GNUNET_ERROR_TYPE_ERROR, "Failed to create indices: %s\n", sqlite3_errmsg (dbh)); } #if 0 #define CHECK(a) GNUNET_break(a) #define ENULL NULL #else #define ENULL &e #define ENULL_DEFINED 1 #define CHECK(a) if (! a) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "%s\n", e); sqlite3_free(e); } #endif /** * Initialize the database connections and associated * data structures (create tables and indices * as needed as well). * * @param plugin the plugin context (state for this module) * @return GNUNET_OK on success */ static int database_setup (struct Plugin *plugin) { sqlite3_stmt *stmt; char *afsdir; #if ENULL_DEFINED char *e; #endif if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, "namestore-sqlite", "FILENAME", &afsdir)) { LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Option `%s' in section `%s' missing in configuration!\n"), "FILENAME", "namestore-sqlite"); return GNUNET_SYSERR; } if (GNUNET_OK != GNUNET_DISK_file_test (afsdir)) { if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (afsdir)) { GNUNET_break (0); GNUNET_free (afsdir); return GNUNET_SYSERR; } } #ifdef ENABLE_NLS plugin->fn = GNUNET_STRINGS_to_utf8 (afsdir, strlen (afsdir), nl_langinfo (CODESET)); #else plugin->fn = GNUNET_STRINGS_to_utf8 (afsdir, strlen (afsdir), "UTF-8"); /* good luck */ #endif GNUNET_free (afsdir); /* Open database and precompile statements */ if (sqlite3_open (plugin->fn, &plugin->dbh) != SQLITE_OK) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Unable to initialize SQLite: %s.\n"), sqlite3_errmsg (plugin->dbh)); return GNUNET_SYSERR; } CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "PRAGMA temp_store=MEMORY", NULL, NULL, ENULL)); CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "PRAGMA synchronous=NORMAL", NULL, NULL, ENULL)); CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "PRAGMA legacy_file_format=OFF", NULL, NULL, ENULL)); CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL", NULL, NULL, ENULL)); CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "PRAGMA encoding=\"UTF-8\"", NULL, NULL, ENULL)); CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "PRAGMA locking_mode=EXCLUSIVE", NULL, NULL, ENULL)); CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "PRAGMA count_changes=OFF", NULL, NULL, ENULL)); CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "PRAGMA page_size=4092", NULL, NULL, ENULL)); CHECK (SQLITE_OK == sqlite3_busy_timeout (plugin->dbh, BUSY_TIMEOUT_MS)); /* Create tables */ CHECK (SQLITE_OK == sq_prepare (plugin->dbh, "SELECT 1 FROM sqlite_master WHERE tbl_name = 'ns091records'", &stmt)); if ((sqlite3_step (stmt) == SQLITE_DONE) && (sqlite3_exec (plugin->dbh, "CREATE TABLE ns091records (" " zone_key BLOB NOT NULL DEFAULT ''," " zone_delegation BLOB NOT NULL DEFAULT ''," " zone_hash BLOB NOT NULL DEFAULT ''," " record_count INT NOT NULL DEFAULT 0," " record_data BLOB NOT NULL DEFAULT ''," " block_expiration_time INT8 NOT NULL DEFAULT 0," " signature BLOB NOT NULL DEFAULT ''," " record_name TEXT NOT NULL DEFAULT ''," " record_name_hash BLOB NOT NULL DEFAULT ''," " rvalue INT8 NOT NULL DEFAULT ''" ")", NULL, NULL, NULL) != SQLITE_OK)) { LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec"); sqlite3_finalize (stmt); return GNUNET_SYSERR; } sqlite3_finalize (stmt); create_indices (plugin->dbh); #define ALL "zone_key, record_name, record_count, record_data, block_expiration_time, signature" if ((sq_prepare (plugin->dbh, "INSERT INTO ns091records (" ALL ", zone_delegation, zone_hash, record_name_hash, rvalue) VALUES " "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", &plugin->put_records) != SQLITE_OK) || (sq_prepare (plugin->dbh, "DELETE FROM ns091records WHERE zone_hash=? AND record_name_hash=?", &plugin->remove_records) != SQLITE_OK) || (sq_prepare (plugin->dbh, "SELECT " ALL " FROM ns091records WHERE zone_hash=? AND record_name_hash=? ORDER BY rvalue LIMIT 1 OFFSET ?", &plugin->iterate_records) != SQLITE_OK) || (sq_prepare (plugin->dbh, "SELECT " ALL " FROM ns091records WHERE zone_hash=? ORDER BY rvalue LIMIT 1 OFFSET ?", &plugin->iterate_by_zone) != SQLITE_OK) || (sq_prepare (plugin->dbh, "SELECT " ALL " FROM ns091records WHERE record_name_hash=? ORDER BY rvalue LIMIT 1 OFFSET ?", &plugin->iterate_by_name) != SQLITE_OK) || (sq_prepare (plugin->dbh, "SELECT " ALL " FROM ns091records ORDER BY rvalue LIMIT 1 OFFSET ?", &plugin->iterate_all) != SQLITE_OK) || (sq_prepare (plugin->dbh, "SELECT " ALL " FROM ns091records WHERE zone_hash=? AND zone_delegation=?", &plugin->zone_to_name) != SQLITE_OK) || (sq_prepare (plugin->dbh, "DELETE FROM ns091records WHERE zone_hash=?", &plugin->delete_zone) != SQLITE_OK) ) { LOG_SQLITE (plugin,GNUNET_ERROR_TYPE_ERROR, "precompiling"); return GNUNET_SYSERR; } #undef ALL return GNUNET_OK; } /** * Shutdown database connection and associate data * structures. * @param plugin the plugin context (state for this module) */ static void database_shutdown (struct Plugin *plugin) { int result; sqlite3_stmt *stmt; if (NULL != plugin->put_records) sqlite3_finalize (plugin->put_records); if (NULL != plugin->remove_records) sqlite3_finalize (plugin->remove_records); if (NULL != plugin->iterate_records) sqlite3_finalize (plugin->iterate_records); if (NULL != plugin->iterate_by_zone) sqlite3_finalize (plugin->iterate_by_zone); if (NULL != plugin->iterate_by_name) sqlite3_finalize (plugin->iterate_by_name); if (NULL != plugin->iterate_all) sqlite3_finalize (plugin->iterate_all); if (NULL != plugin->zone_to_name) sqlite3_finalize (plugin->zone_to_name); if (NULL != plugin->delete_zone) sqlite3_finalize (plugin->delete_zone); result = sqlite3_close (plugin->dbh); if (result == SQLITE_BUSY) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Tried to close sqlite without finalizing all prepared statements.\n")); stmt = sqlite3_next_stmt (plugin->dbh, NULL); while (stmt != NULL) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Closing statement %p\n", stmt); result = sqlite3_finalize (stmt); if (result != SQLITE_OK) GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite", "Failed to close statement %p: %d\n", stmt, result); stmt = sqlite3_next_stmt (plugin->dbh, NULL); } result = sqlite3_close (plugin->dbh); } if (SQLITE_OK != result) LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close"); GNUNET_free_non_null (plugin->fn); } /** * Removes any existing record in the given zone with the same name. * * @param cls closure (internal context for the plugin) * @param zone hash of the public key of the zone * @param name name to remove (at most 255 characters long) * @return GNUNET_OK on success */ static int namestore_sqlite_remove_records (void *cls, const struct GNUNET_CRYPTO_ShortHashCode *zone, const char *name) { struct Plugin *plugin = cls; struct GNUNET_CRYPTO_ShortHashCode nh; size_t name_len; int n; name_len = strlen (name); GNUNET_CRYPTO_short_hash (name, name_len, &nh); if ((SQLITE_OK != sqlite3_bind_blob (plugin->remove_records, 1, zone, sizeof (struct GNUNET_CRYPTO_ShortHashCode), SQLITE_STATIC)) || (SQLITE_OK != sqlite3_bind_blob (plugin->remove_records, 2, &nh, sizeof (struct GNUNET_CRYPTO_ShortHashCode), SQLITE_STATIC))) { LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); if (SQLITE_OK != sqlite3_reset (plugin->remove_records)) LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); return GNUNET_SYSERR; } n = sqlite3_step (plugin->remove_records); if (SQLITE_OK != sqlite3_reset (plugin->remove_records)) LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); switch (n) { case SQLITE_DONE: GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Record removed\n"); return GNUNET_OK; case SQLITE_BUSY: LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); return GNUNET_NO; default: LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); return GNUNET_SYSERR; } } /** * Store a record in the datastore. Removes any existing record in the * same zone with the same name. * * @param cls closure (internal context for the plugin) * @param zone_key public key of the zone * @param expire when does the corresponding block in the DHT expire (until * when should we never do a DHT lookup for the same name again)? * @param name name that is being mapped (at most 255 characters long) * @param rd_count number of entries in 'rd' array * @param rd array of records with data to store * @param signature signature of the record block, NULL if signature is unavailable (i.e. * because the user queried for a particular record type only) * @return GNUNET_OK on success, else GNUNET_SYSERR */ static int namestore_sqlite_put_records (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *name, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { struct Plugin *plugin = cls; int n; struct GNUNET_CRYPTO_ShortHashCode zone; struct GNUNET_CRYPTO_ShortHashCode zone_delegation; struct GNUNET_CRYPTO_ShortHashCode nh; size_t name_len; uint64_t rvalue; size_t data_size; unsigned int i; GNUNET_CRYPTO_short_hash (zone_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &zone); (void) namestore_sqlite_remove_records (plugin, &zone, name); name_len = strlen (name); GNUNET_CRYPTO_short_hash (name, name_len, &nh); memset (&zone_delegation, 0, sizeof (zone_delegation)); for (i=0;i 64 * 65536) { GNUNET_break (0); return GNUNET_SYSERR; } { char data[data_size]; if (data_size != GNUNET_NAMESTORE_records_serialize (rd_count, rd, data_size, data)) { GNUNET_break (0); return GNUNET_SYSERR; } if ((SQLITE_OK != sqlite3_bind_blob (plugin->put_records, 1, zone_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), SQLITE_STATIC)) || (SQLITE_OK != sqlite3_bind_text (plugin->put_records, 2, name, -1, SQLITE_STATIC)) || (SQLITE_OK != sqlite3_bind_int (plugin->put_records, 3, rd_count)) || (SQLITE_OK != sqlite3_bind_blob (plugin->put_records, 4, data, data_size, SQLITE_STATIC)) || (SQLITE_OK != sqlite3_bind_int64 (plugin->put_records, 5, expire.abs_value)) || (SQLITE_OK != sqlite3_bind_blob (plugin->put_records, 6, signature, sizeof (struct GNUNET_CRYPTO_RsaSignature), SQLITE_STATIC)) || (SQLITE_OK != sqlite3_bind_blob (plugin->put_records, 7, &zone_delegation, sizeof (struct GNUNET_CRYPTO_ShortHashCode), SQLITE_STATIC)) || (SQLITE_OK != sqlite3_bind_blob (plugin->put_records, 8, &zone, sizeof (struct GNUNET_CRYPTO_ShortHashCode), SQLITE_STATIC)) || (SQLITE_OK != sqlite3_bind_blob (plugin->put_records, 9, &nh, sizeof (struct GNUNET_CRYPTO_ShortHashCode), SQLITE_STATIC)) || (SQLITE_OK != sqlite3_bind_int64 (plugin->put_records, 10, rvalue)) ) { LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); if (SQLITE_OK != sqlite3_reset (plugin->put_records)) LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); return GNUNET_SYSERR; } n = sqlite3_step (plugin->put_records); if (SQLITE_OK != sqlite3_reset (plugin->put_records)) LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); } switch (n) { case SQLITE_DONE: GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Record stored\n"); return GNUNET_OK; case SQLITE_BUSY: LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); return GNUNET_NO; default: LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); return GNUNET_SYSERR; } } /** * The given 'sqlite' statement has been prepared to be run. * It will return a record which should be given to the iterator. * Runs the statement and parses the returned record. * * @param plugin plugin context * @param stmt to run (and then clean up) * @param iter iterator to call with the result * @param iter_cls closure for 'iter' * @return GNUNET_OK on success, GNUNET_NO if there were no results, GNUNET_SYSERR on error */ static int get_record_and_call_iterator (struct Plugin *plugin, sqlite3_stmt *stmt, GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls) { int ret; int sret; unsigned int record_count; size_t data_size; const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key; const struct GNUNET_CRYPTO_RsaSignature *sig; struct GNUNET_TIME_Absolute expiration; const char *data; const char *name; ret = GNUNET_NO; if (SQLITE_ROW == (sret = sqlite3_step (stmt))) { ret = GNUNET_YES; zone_key = sqlite3_column_blob (stmt, 0); name = (const char*) sqlite3_column_text (stmt, 1); record_count = sqlite3_column_int (stmt, 2); data_size = sqlite3_column_bytes (stmt, 3); data = sqlite3_column_blob (stmt, 3); expiration.abs_value = (uint64_t) sqlite3_column_int64 (stmt, 4); sig = sqlite3_column_blob (stmt, 5); if ( (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) != sqlite3_column_bytes (stmt, 0)) || (sizeof (struct GNUNET_CRYPTO_RsaSignature) != sqlite3_column_bytes (stmt, 5)) ) { GNUNET_break (0); ret = GNUNET_SYSERR; } else { struct GNUNET_NAMESTORE_RecordData rd[record_count]; if (GNUNET_OK != GNUNET_NAMESTORE_records_deserialize (data_size, data, record_count, rd)) { GNUNET_break (0); ret = GNUNET_SYSERR; record_count = 0; } else { iter (iter_cls, zone_key, expiration, name, record_count, rd, sig); } } } else { if (SQLITE_DONE != sret) LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step"); iter (iter_cls, NULL, GNUNET_TIME_UNIT_ZERO_ABS, NULL, 0, NULL, NULL); } if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); return ret; } /** * Iterate over the results for a particular key and zone in the * datastore. Will return at most one result to the iterator. * * @param cls closure (internal context for the plugin) * @param zone hash of public key of the zone, NULL to iterate over all zones * @param name name as string, NULL to iterate over all records of the zone * @param offset offset in the list of all matching records * @param iter function to call with the result * @param iter_cls closure for iter * @return GNUNET_OK on success, GNUNET_NO if there were no results, GNUNET_SYSERR on error */ static int namestore_sqlite_iterate_records (void *cls, const struct GNUNET_CRYPTO_ShortHashCode *zone, const char *name, uint64_t offset, GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls) { struct Plugin *plugin = cls; sqlite3_stmt *stmt; struct GNUNET_CRYPTO_ShortHashCode name_hase; unsigned int boff; if (NULL == zone) if (NULL == name) stmt = plugin->iterate_all; else { GNUNET_CRYPTO_short_hash (name, strlen(name), &name_hase); stmt = plugin->iterate_by_name; } else if (NULL == name) stmt = plugin->iterate_by_zone; else { GNUNET_CRYPTO_short_hash (name, strlen(name), &name_hase); stmt = plugin->iterate_records; } boff = 0; if ( (NULL != zone) && (SQLITE_OK != sqlite3_bind_blob (stmt, ++boff, zone, sizeof (struct GNUNET_CRYPTO_ShortHashCode), SQLITE_STATIC)) ) { LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); return GNUNET_SYSERR; } if ( (NULL != name) && (SQLITE_OK != sqlite3_bind_blob (stmt, ++boff, &name_hase, sizeof (struct GNUNET_CRYPTO_ShortHashCode), SQLITE_STATIC)) ) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ITERATE NAME HASH: `%8s'", GNUNET_short_h2s(&name_hase)); LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); return GNUNET_SYSERR; } if (SQLITE_OK != sqlite3_bind_int64 (stmt, ++boff, offset)) { LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); return GNUNET_SYSERR; } return get_record_and_call_iterator (plugin, stmt, iter, iter_cls); } /** * Look for an existing PKEY delegation record for a given public key. * Returns at most one result to the iterator. * * @param cls closure (internal context for the plugin) * @param zone hash of public key of the zone to look up in, never NULL * @param value_zone hash of the public key of the target zone (value), never NULL * @param iter function to call with the result * @param iter_cls closure for iter * @return GNUNET_OK on success, GNUNET_NO if there were no results, GNUNET_SYSERR on error */ static int namestore_sqlite_zone_to_name (void *cls, const struct GNUNET_CRYPTO_ShortHashCode *zone, const struct GNUNET_CRYPTO_ShortHashCode *value_zone, GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls) { struct Plugin *plugin = cls; sqlite3_stmt *stmt; stmt = plugin->zone_to_name; if ( (SQLITE_OK != sqlite3_bind_blob (stmt, 1, zone, sizeof (struct GNUNET_CRYPTO_ShortHashCode), SQLITE_STATIC)) || (SQLITE_OK != sqlite3_bind_blob (stmt, 2, value_zone, sizeof (struct GNUNET_CRYPTO_ShortHashCode), SQLITE_STATIC)) ) { LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); return GNUNET_SYSERR; } return get_record_and_call_iterator (plugin, stmt, iter, iter_cls); } /** * Delete an entire zone (all records). Not used in normal operation. * * @param cls closure (internal context for the plugin) * @param zone zone to delete */ static void namestore_sqlite_delete_zone (void *cls, const struct GNUNET_CRYPTO_ShortHashCode *zone) { struct Plugin *plugin = cls; sqlite3_stmt *stmt = plugin->delete_zone; int n; if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, zone, sizeof (struct GNUNET_CRYPTO_ShortHashCode), SQLITE_STATIC)) { LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); return; } n = sqlite3_step (stmt); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); switch (n) { case SQLITE_DONE: GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Values deleted\n"); break; case SQLITE_BUSY: LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); break; default: LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); break; } } /** * Entry point for the plugin. * * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*" * @return NULL on error, othrewise the plugin context */ void * libgnunet_plugin_namestore_sqlite_init (void *cls) { static struct Plugin plugin; const struct GNUNET_CONFIGURATION_Handle *cfg = cls; struct GNUNET_NAMESTORE_PluginFunctions *api; if (NULL != plugin.cfg) return NULL; /* can only initialize once! */ memset (&plugin, 0, sizeof (struct Plugin)); plugin.cfg = cfg; if (GNUNET_OK != database_setup (&plugin)) { database_shutdown (&plugin); return NULL; } api = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_PluginFunctions)); api->cls = &plugin; api->put_records = &namestore_sqlite_put_records; api->remove_records = &namestore_sqlite_remove_records; api->iterate_records = &namestore_sqlite_iterate_records; api->zone_to_name = &namestore_sqlite_zone_to_name; api->delete_zone = &namestore_sqlite_delete_zone; LOG (GNUNET_ERROR_TYPE_INFO, _("Sqlite database running\n")); return api; } /** * Exit point from the plugin. * * @param cls the plugin context (as returned by "init") * @return always NULL */ void * libgnunet_plugin_namestore_sqlite_done (void *cls) { struct GNUNET_NAMESTORE_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; LOG (GNUNET_ERROR_TYPE_DEBUG, "sqlite plugin is done\n"); database_shutdown (plugin); plugin->cfg = NULL; GNUNET_free (api); LOG (GNUNET_ERROR_TYPE_DEBUG, "sqlite plugin is finished\n"); return NULL; } /* end of plugin_namestore_sqlite.c */ gnunet-0.9.3/src/namestore/test_namestore_api_create.c0000644000175000017500000003162211760517605020120 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file namestore/test_namestore_api.c * @brief testcase for namestore_api.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_namestore_service.h" #include "namestore.h" #include "gnunet_signatures.h" #define VERBOSE GNUNET_NO #define RECORDS 1 #define TEST_RECORD_TYPE 1234 #define TEST_RECORD_DATALEN 123 #define TEST_RECORD_DATA 'a' #define TEST_CREATE_RECORD_TYPE 4321 #define TEST_CREATE_RECORD_DATALEN 255 #define TEST_CREATE_RECORD_DATA 'b' #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) static struct GNUNET_NAMESTORE_Handle * nsh; static GNUNET_SCHEDULER_TaskIdentifier endbadly_task; static struct GNUNET_OS_Process *arm; static struct GNUNET_CRYPTO_RsaPrivateKey * privkey; static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubkey; struct GNUNET_CRYPTO_RsaSignature *s_signature; struct GNUNET_CRYPTO_RsaSignature *s_signature_updated; static struct GNUNET_CRYPTO_ShortHashCode s_zone; struct GNUNET_NAMESTORE_RecordData *s_first_record; struct GNUNET_NAMESTORE_RecordData *s_second_record; static char *s_name; static int res; static void start_arm (const char *cfgname) { arm = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, #if VERBOSE_PEERS "-L", "DEBUG", #else "-L", "ERROR", #endif NULL); } static void stop_arm () { if (NULL != arm) { if (0 != GNUNET_OS_process_kill (arm, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); GNUNET_OS_process_wait (arm); GNUNET_OS_process_destroy (arm); arm = NULL; } } /** * Re-establish the connection to the service. * * @param cls handle to use to re-connect. * @param tc scheduler context */ static void endbadly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (nsh != NULL) GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); nsh = NULL; if (privkey != NULL) GNUNET_CRYPTO_rsa_key_free (privkey); privkey = NULL; if (NULL != arm) stop_arm(); res = 1; } static void end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (endbadly_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (endbadly_task); endbadly_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_free ((void *) s_first_record->data); GNUNET_free (s_first_record); GNUNET_free_non_null (s_second_record); if (privkey != NULL) GNUNET_CRYPTO_rsa_key_free (privkey); privkey = NULL; if (nsh != NULL) GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); nsh = NULL; if (NULL != arm) stop_arm(); } void name_lookup_second_proc (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *n, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { static int found = GNUNET_NO; int failed = GNUNET_NO; int c; if (n != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking returned results\n"); if (0 != memcmp (zone_key, &pubkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded))) { GNUNET_break (0); failed = GNUNET_YES; } if (0 != strcmp(n, s_name)) { GNUNET_break (0); failed = GNUNET_YES; } if (2 != rd_count) { GNUNET_break (0); failed = GNUNET_YES; } for (c = 0; c < rd_count; c++) { if ((GNUNET_NO == GNUNET_NAMESTORE_records_cmp(&rd[c], s_first_record)) && (GNUNET_NO == GNUNET_NAMESTORE_records_cmp(&rd[c], s_second_record))) { GNUNET_break (0); failed = GNUNET_YES; } } if (GNUNET_OK != GNUNET_NAMESTORE_verify_signature(zone_key, expire, n, rd_count, rd, signature)) { GNUNET_break (0); failed = GNUNET_YES; } if (GNUNET_OK != GNUNET_NAMESTORE_verify_signature(&pubkey, expire, n, rd_count, rd, signature)) { GNUNET_break (0); failed = GNUNET_YES; } struct GNUNET_NAMESTORE_RecordData rd_new[2]; rd_new[0] = *s_first_record; rd_new[1] = *s_second_record; s_signature_updated = GNUNET_NAMESTORE_create_signature(privkey, expire, s_name, rd_new, 2); if (0 != memcmp (s_signature_updated, signature, sizeof (struct GNUNET_CRYPTO_RsaSignature))) { GNUNET_break (0); failed = GNUNET_YES; } found = GNUNET_YES; if (failed == GNUNET_NO) res = 0; else res = 1; } else { if (found != GNUNET_YES) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to lookup records for name `%s'\n", s_name); res = 1; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Lookup done for name %s'\n", s_name); } GNUNET_SCHEDULER_add_now(&end, NULL); } void create_second_cont (void *cls, int32_t success, const char *emsg) { char *name = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Create second record for `%s': %s\n", name, (success == GNUNET_OK) ? "SUCCESS" : "FAIL"); if (success == GNUNET_OK) { res = 0; GNUNET_NAMESTORE_lookup_record (nsh, &s_zone, name, 0, &name_lookup_second_proc, name); } else { res = 1; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to put records for name `%s'\n", name); GNUNET_SCHEDULER_add_now(&end, NULL); } } void name_lookup_initial_proc (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *n, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { char * name = cls; static int found = GNUNET_NO; int failed = GNUNET_NO; int c; if (n != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking returned results\n"); if (0 != memcmp (zone_key, &pubkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded))) { GNUNET_break (0); failed = GNUNET_YES; } if (0 != strcmp(n, s_name)) { GNUNET_break (0); failed = GNUNET_YES; } if (RECORDS != rd_count) { GNUNET_break (0); failed = GNUNET_YES; } for (c = 0; c < RECORDS; c++) { if (GNUNET_NO == GNUNET_NAMESTORE_records_cmp(&rd[c], &s_first_record[c])) { GNUNET_break (0); failed = GNUNET_YES; } } if (GNUNET_OK != GNUNET_NAMESTORE_verify_signature(&pubkey, expire,n, rd_count, rd, signature)) { GNUNET_break (0); failed = GNUNET_YES; } if (0 != memcmp (s_signature, signature, sizeof (struct GNUNET_CRYPTO_RsaSignature))) { GNUNET_break (0); failed = GNUNET_YES; } found = GNUNET_YES; if (failed == GNUNET_NO) res = 0; else res = 1; /* create a second record */ s_second_record = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_RecordData) + TEST_CREATE_RECORD_DATALEN); s_second_record->expiration = GNUNET_TIME_UNIT_FOREVER_ABS; s_second_record->record_type = TEST_CREATE_RECORD_TYPE; s_second_record->flags = GNUNET_NAMESTORE_RF_AUTHORITY; s_second_record->data = &s_second_record[1]; s_second_record->data_size = TEST_CREATE_RECORD_DATALEN; memset ((char *) s_second_record->data, TEST_CREATE_RECORD_DATA, TEST_CREATE_RECORD_DATALEN); GNUNET_NAMESTORE_record_create (nsh, privkey, name, s_second_record, &create_second_cont, name); } else { if (found != GNUNET_YES) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to lookup records for name `%s'\n", s_name); res = 1; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Lookup done for name %s'\n", s_name); GNUNET_SCHEDULER_add_now (&end, NULL); } } void create_first_cont (void *cls, int32_t success, const char *emsg) { char *name = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Create record for `%s': %s\n", name, (success == GNUNET_OK) ? "SUCCESS" : "FAIL"); if (success == GNUNET_OK) { res = 0; /* check if record was created correct */ GNUNET_NAMESTORE_lookup_record (nsh, &s_zone, name, 0, &name_lookup_initial_proc, name); } else { res = 1; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to put records for name `%s'\n", name); GNUNET_SCHEDULER_add_now(&end, NULL); } } void put_cont (void *cls, int32_t success, const char *emsg) { char *name = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Name store added record for `%s': %s\n", name, (success == GNUNET_OK) ? "SUCCESS" : "FAIL"); if (success == GNUNET_OK) { } else { res = 1; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to put records for name `%s'\n", name); GNUNET_SCHEDULER_add_now(&end, NULL); } } static struct GNUNET_NAMESTORE_RecordData * create_record (int count) { int c; struct GNUNET_NAMESTORE_RecordData * rd; rd = GNUNET_malloc (count * sizeof (struct GNUNET_NAMESTORE_RecordData)); for (c = 0; c < count; c++) { rd[c].expiration = GNUNET_TIME_absolute_get(); rd[c].record_type = TEST_RECORD_TYPE; rd[c].data_size = TEST_RECORD_DATALEN; rd[c].data = GNUNET_malloc(TEST_RECORD_DATALEN); memset ((char *) rd[c].data, TEST_RECORD_DATA, TEST_RECORD_DATALEN); } return rd; } void delete_existing_db (const struct GNUNET_CONFIGURATION_Handle *cfg) { char *afsdir; if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, "namestore-sqlite", "FILENAME", &afsdir)) { if (GNUNET_OK == GNUNET_DISK_file_test (afsdir)) if (GNUNET_OK == GNUNET_DISK_file_test (afsdir)) if (GNUNET_OK == GNUNET_DISK_directory_remove(afsdir)) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleted existing database `%s' \n", afsdir); GNUNET_free (afsdir); } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { delete_existing_db(cfg); endbadly_task = GNUNET_SCHEDULER_add_delayed(TIMEOUT,endbadly, NULL); size_t rd_ser_len; /* load privat key */ char *hostkey_file; GNUNET_asprintf(&hostkey_file,"zonefiles%s%s",DIR_SEPARATOR_STR, "N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using zonekey file `%s' \n", hostkey_file); privkey = GNUNET_CRYPTO_rsa_key_create_from_file(hostkey_file); GNUNET_free (hostkey_file); /* get public key */ GNUNET_CRYPTO_rsa_key_get_public(privkey, &pubkey); /* create record */ s_name = "dummy.dummy.gnunet"; s_first_record = create_record (1); rd_ser_len = GNUNET_NAMESTORE_records_get_size(1, s_first_record); char rd_ser[rd_ser_len]; GNUNET_NAMESTORE_records_serialize(1, s_first_record, rd_ser_len, rd_ser); s_signature = GNUNET_NAMESTORE_create_signature(privkey, s_first_record->expiration, s_name, s_first_record, 1); /* create random zone hash */ GNUNET_CRYPTO_short_hash (&pubkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &s_zone); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Name: `%s' Zone: `%s' \n", s_name, GNUNET_short_h2s (&s_zone)); start_arm (cfgfile); GNUNET_assert (arm != NULL); nsh = GNUNET_NAMESTORE_connect (cfg); GNUNET_break (NULL != nsh); GNUNET_break (s_first_record != NULL); GNUNET_break (s_name != NULL); /* create initial record */ GNUNET_NAMESTORE_record_create (nsh, privkey, s_name, s_first_record, &create_first_cont, s_name); } static int check () { static char *const argv[] = { "test-namestore-api", "-c", "test_namestore_api.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; res = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-namestore-api", "nohelp", options, &run, &res); return res; } int main (int argc, char *argv[]) { int ret; ret = check (); GNUNET_free (s_signature); return ret; } /* end of test_namestore_api.c */ gnunet-0.9.3/src/namestore/test_hostkey0000644000175000017500000000162211726433661015212 00000000000000’€€ÆCO{/0FC+¬ëœ% Ö »í—~‡ÐÛ²C¥²(ZÜü M É¿#¢zÒÑÙOøIe­q¨9qø|ñ¯áI"è}O6àh\4pè£Y»|úÄ2þƒ'˜È*]óR^RéM¾.<Ìø¢ÞEøå+eížEAî#° èôæ¤_úÄF÷ÄubH>|œŠ1yN¬¸W?uþ;i{mÔ¶9j½=3d6Vò¤€E€ü˜ÝŠçð#È«¸,ÎÉ,òŠoÃ'iìÏËëë¡>Ø¢­‹M‹ÉÅuúªmµ¾ÓÜkÍ”ñžw~~äùì¿'V\1ϱá(}µD<Ü¡yOÞ–#‡ë>s+Ùë.›çG€WÌ¥&Ø)eòÉŽ|1"ËÇí‡P3j_{\/rq0î6‰}˜~pp(ñf•ü±å,*‡lÔ¸ G©ì©[ÐëŒd5Rª8OCU¡ƒ …?ÌÐR]gÌ-šU[têïµ^ )I®õ¥…hWhÆN‡s€õ~ýÌ·Ÿ¦ú¨+ ÀÐÈ£ØyñŽVs°ôdlç!µÍ):V±‘OYåQüƒ?Ë, ’‰­½ÉTl5!ê†#&åuF±¯›VàoñÍ¥šÔ m»ø\\¢Ø?±MsƳµXäeÇ, ŽíwDg›ïÇ8} V³hÇB¡´ÎÙÚñŸSÑg“âKaÍ¿ö½lñRÞ0ºfæñ7èjeþ0HЄñÚº‘85Ø< S“`;0ü}™Ïv¶ÌAj5Î%ùŽöÝDÑ’K±}vd¤Ý0kàï‡!ÙÛ‘éa„Ò-‚Â$Ñqûˆˆ0ctÅlúÔ©\TTýÓ˜’ójÇš>2Óº¸ï”²5],®ŽXî_ÜWgÐ]9ùÍ- Ó5#ø¾<¨—¸P5Ä&Š¥vgnunet-0.9.3/src/namestore/zonefiles/0000755000175000017500000000000011763406747014625 500000000000000gnunet-0.9.3/src/namestore/zonefiles/HGU0A0VCU334DN7F2I9UIUMVQMM7JMSD142LIMNUGTTV9R0CF4EG.zkey0000644000175000017500000000162111731702723024547 00000000000000‘ÿ€€ÍxÑ‚™?uŽÄóóÉòµÀ]3ðõp®.°¡šU0d¯ ÿðÔvàñq‚ôÅEøQò=–‹Þ{ý‚égLÞǶ(#ªýŒ!!¸§î—ÌÓÛÎÂDuQ·Íô3Äçö´ÌëðåY€ßã&OR¾Ë•³dBA¬9#Ñô{xï¿íç-hDdÙ?hžÌ áeo×àÅÒìHø¶%1“<â8YÓ¸I2.tˆû¿}õN§"ï³ÊhórUúµ+cIÔ×þ2ö¥3x\á †” ¯0QÞ2Á£¬ûR¨xT…IP—j‘x[~µ‘ú˜[8ɾ‘µí¯|!§¹²ŒÕ ŒÐzž<5ä6¿Ý/kÛÐG! ú/´¼8RJãk7Výgo> LŒ•+øPɃj°@„aà z™ÎÞ›×wV–*[õzWÓZ½ùÏP¿¨ ]“hþL)øÍc=x®`¤8ãtü ’E€‰½ãŸdd¹56v7=ï¼’k ¯3r ±Üöª5SkÔïú‘7ôž{:•Í[8¡Þ¯Ó&“Û&Ÿ‘ÿ~ª €(jòáöƒ»m ì¿»‘¹“³eÃØ8BžR[’X:Ùm¬d¸b ±õÒ@Œç0¥ d£dDÜ T’žcÍj’ ÆÁcu“!;â- Úöæ•ù©íÙ nø E‘ï[‘ñ‹n9ú3î0kÏ ApÓªÀ}‹G¡Å©)?5/6Dþ ±ð--çuÿ‰äTDz¯L“™çõ”*›xV Ù< ^ôW (¡Î©VPQ“M+ÌB‹)Ð|`¾¶ôwLùž3lÿ!+Ë'gÅäiþ)S!A4Ÿ×û)Ùÿ&=¹iHZJ–#p驿=~³´p—å@ø4•:Vð›HòRÅ |Ƈ3ºt?8A7OnÒû‰†óšÎ¬ £¹ª­5<â WÉ¡LeGmÆNØN%­86:¦À–…Ö0EHð«v¸«]hÝíC²fмäɵx}(Q†Ç1Ãxéo ¸Š»î×Dã-¥³+ï{r)ÛÊ ë‚rFÏ¿<ïî¿pÍãT»íæ#ÞÉ¥kA5êðϳòÖ¤‚œxÁÁâ‹‘“b.{´9}ŒúDx3«Cªv Ÿý{Q„®ëVÚÀ[~u9È^Ognunet-0.9.3/src/namestore/zonefiles/N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey0000644000175000017500000000162211731702723024232 00000000000000’€€ÕÜ*H¾ BÞ;˜ò¾5¦H‘+¸E?wß²£…g'ˆ˜qÕûo†ŒP¢Ât¤ÈK¯äÛ7Ÿ—Ró LLOAH™§îŒËæÛ´åx¬m„OÈfènÅš)ÌœLpØfŒˆCÀžÁûj>^ÞP£Ÿ|lžðj\‡† M¶ÖÊ Þê²néù rÛcT]…hMÏJyë~ýÜUÊm¢êÐ]á°A<¦d åb#åÏ·[„U%_ÑúGØóStùþEµÓðYÓ‚q$( ô»ÇÝ·+Æ[5¥ùQ]çÙ:' n E5<U£¬üOاâ[^ t¨íûÇIȃ ;àZ{‰ý뜈ÄCˆå_t3š Î÷äçšîŒú¹JÖ&2–,.f24 ˆ¸nBM°{SÏ«4¤O¶OÞ@Ù’ÙæÅÐ9ßõ'TÃv¾S'¯»åNûBÅ$æçHJ^9ˆ‘¸HpÏÑ÷ŸS˵0bQÇ\ö± 7 :;b¨ëèÈ&:¼$È.=Ó7DºñœÇY5§Ñsåô9\iÜÉ.GÓo…´ÎQæ$©“qfÇÕÉM„ZõÖêÚö7ËÅÙo;|º±yÖ¨4*¥ëiâüß¹ .Ì9üÂgkn «¿ÐÞ„¤s'Ã4eŽMãoíΫQüÖé£Bü6Ù¥û‰‰Ø¹ç[Q`Ÿ§Yz¢ÝãH¹!¨1*M%…¸âó!0v¯ØŠEQ2üœìpz‰‘¡¡‡}âh/þÓsèºv©g,ñŠÏæ{‚ò”~x"òþÌiU¶dï/ ZI™ÉúŒÝÒ½>öLr¬m•ÕÌÛ­ßd½rÓ_GÙ§òîµ2Éùôå{·ÂÇ«JìûŸf“Û×<ÏOªA4Ô¾©PìÂxäBSDp2<*Ç} §± YÅQûš<(cBÅý†³U‡áúØ…¬ˆ Ba":øÊZJEW-e¿yøöšU:®F¾ß#¼FÚióüÛÒ™{™åÄî­qRŽ£<îŸR‘4Áà’Z'´'£O·’+ÛÒoXøKæp2J[‹Äl£]”…xÇQ÷qä`qB×wòJ+FDçuxy߯zïà?ÙX²`®ÌB\\ýãî n>êÔH?TM©}ªAä8“¢“–Ê»ÕS'M2J‘n ÚQ˜)gnunet-0.9.3/src/namestore/test_namestore_api_zone_to_name.c0000644000175000017500000001743111760502550021325 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file namestore/test_namestore_api_zone_to_name.c * @brief testcase for zone to name translation */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_namestore_service.h" #include "namestore.h" #include "gnunet_signatures.h" #define VERBOSE GNUNET_NO #define RECORDS 5 #define TEST_RECORD_TYPE 1234 #define TEST_RECORD_DATALEN 123 #define TEST_RECORD_DATA 'a' #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) static struct GNUNET_NAMESTORE_Handle * nsh; static GNUNET_SCHEDULER_TaskIdentifier endbadly_task; static struct GNUNET_OS_Process *arm; static struct GNUNET_CRYPTO_RsaPrivateKey * privkey; static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubkey; struct GNUNET_TIME_Absolute expire; static struct GNUNET_CRYPTO_ShortHashCode s_zone; static struct GNUNET_CRYPTO_ShortHashCode s_zone_value; char * s_name; struct GNUNET_NAMESTORE_RecordData *s_rd; struct GNUNET_CRYPTO_RsaSignature *s_signature; static int res; static void start_arm (const char *cfgname) { arm = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, #if VERBOSE_PEERS "-L", "DEBUG", #else "-L", "ERROR", #endif NULL); } static void stop_arm () { if (NULL != arm) { if (0 != GNUNET_OS_process_kill (arm, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); GNUNET_OS_process_wait (arm); GNUNET_OS_process_destroy (arm); arm = NULL; } } /** * Re-establish the connection to the service. * * @param cls handle to use to re-connect. * @param tc scheduler context */ static void endbadly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (nsh != NULL) GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); nsh = NULL; if (privkey != NULL) GNUNET_CRYPTO_rsa_key_free (privkey); privkey = NULL; if (NULL != arm) stop_arm(); res = 1; } static void end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (endbadly_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (endbadly_task); endbadly_task = GNUNET_SCHEDULER_NO_TASK; } if (privkey != NULL) GNUNET_CRYPTO_rsa_key_free (privkey); privkey = NULL; if (nsh != NULL) GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); nsh = NULL; if (NULL != arm) stop_arm(); } void zone_to_name_proc (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *n, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { int fail = GNUNET_NO; if ((zone_key == NULL) && (n == NULL) && (rd_count == 0) && (rd == NULL) && (signature == NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No result found\n"); res = 1; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result found: `%s'\n", n); if ((n == NULL) || (0 != strcmp(n, s_name))) { fail = GNUNET_YES; GNUNET_break (0); } if (rd_count != 1) { fail = GNUNET_YES; GNUNET_break (0); } if ((zone_key == NULL) || (0 != memcmp (zone_key, &pubkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))) { fail = GNUNET_YES; GNUNET_break (0); } if (fail == GNUNET_NO) res = 0; else res = 1; } GNUNET_SCHEDULER_add_now(&end, NULL); } void delete_existing_db (const struct GNUNET_CONFIGURATION_Handle *cfg) { char *afsdir; if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, "namestore-sqlite", "FILENAME", &afsdir)) { if (GNUNET_OK == GNUNET_DISK_file_test (afsdir)) if (GNUNET_OK == GNUNET_DISK_file_test (afsdir)) if (GNUNET_OK == GNUNET_DISK_directory_remove(afsdir)) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleted existing database `%s' \n", afsdir); GNUNET_free (afsdir); } } void put_cont (void *cls, int32_t success, const char *emsg) { char *name = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Name store added record for `%s': %s\n", name, (success == GNUNET_OK) ? "SUCCESS" : "FAIL"); if (success == GNUNET_OK) { res = 0; /* create initial record */ GNUNET_NAMESTORE_zone_to_name (nsh, &s_zone, &s_zone_value, zone_to_name_proc, NULL); } else { res = 1; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to put records for name `%s'\n", name); GNUNET_SCHEDULER_add_now(&end, NULL); } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { delete_existing_db(cfg); endbadly_task = GNUNET_SCHEDULER_add_delayed(TIMEOUT,endbadly, NULL); GNUNET_asprintf(&s_name, "dummy"); /* load privat key */ char *hostkey_file; GNUNET_asprintf(&hostkey_file,"zonefiles%s%s",DIR_SEPARATOR_STR, "N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using zonekey file `%s' \n", hostkey_file); privkey = GNUNET_CRYPTO_rsa_key_create_from_file(hostkey_file); GNUNET_free (hostkey_file); GNUNET_assert (privkey != NULL); /* get public key */ GNUNET_CRYPTO_rsa_key_get_public(privkey, &pubkey); /* zone hash */ GNUNET_CRYPTO_short_hash (&pubkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &s_zone); GNUNET_CRYPTO_short_hash (s_name, strlen (s_name) + 1, &s_zone_value); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using PKEY `%s' \n", GNUNET_short_h2s (&s_zone_value)); struct GNUNET_NAMESTORE_RecordData rd; rd.expiration = GNUNET_TIME_absolute_get(); rd.record_type = GNUNET_NAMESTORE_TYPE_PKEY; rd.data_size = sizeof (struct GNUNET_CRYPTO_ShortHashCode); rd.data = GNUNET_malloc(sizeof (struct GNUNET_CRYPTO_ShortHashCode)); memcpy ((char *) rd.data, &s_zone_value, sizeof (struct GNUNET_CRYPTO_ShortHashCode)); start_arm (cfgfile); GNUNET_assert (arm != NULL); nsh = GNUNET_NAMESTORE_connect (cfg); GNUNET_break (NULL != nsh); expire = GNUNET_TIME_absolute_get (); s_signature = GNUNET_NAMESTORE_create_signature(privkey, rd.expiration, s_name, &rd, 1); GNUNET_NAMESTORE_record_put(nsh, &pubkey, s_name, expire, 1, &rd, s_signature, put_cont, NULL); GNUNET_free ((void *) rd.data); } static int check () { static char *const argv[] = { "test-namestore-api", "-c", "test_namestore_api.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; res = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-namestore-api", "nohelp", options, &run, &res); return res; } int main (int argc, char *argv[]) { int ret; ret = check (); return ret; } /* end of test_namestore_api.c */ gnunet-0.9.3/src/namestore/namestore.conf.in0000644000175000017500000000113611760502552016005 00000000000000[namestore] AUTOSTART = YES UNIXPATH = /tmp/gnunet-service-namestore.sock UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES @UNIXONLY@ PORT = 2099 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-namestore ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DATABASE = sqlite ZONEFILE_DIRECTORY = $SERVICEHOME/namestore/zonefiles [namestore-sqlite] FILENAME = $SERVICEHOME/namestore/sqlite.db [namestore-postgres] CONFIG = connect_timeout=10; dbname=gnunet [namestore-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf # USER = gnunet # PASSWORD = # HOST = localhost # PORT = 3306 gnunet-0.9.3/src/namestore/namestore.h0000644000175000017500000002633611760502551014712 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file namestore/namestore.h * @brief common internal definitions for namestore service * @author Matthias Wachs */ #ifndef NAMESTORE_H #define NAMESTORE_H /* * Collect message types here, move to protocols later */ #define GNUNET_MESSAGE_TYPE_NAMESTORE_START 430 #define GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME 431 #define GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME_RESPONSE 432 #define GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT 433 #define GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT_RESPONSE 434 #define GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE 435 #define GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE_RESPONSE 436 #define GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE 437 #define GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE_RESPONSE 438 #define GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME 439 #define GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE 440 #define GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START 445 #define GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE 446 #define GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT 447 #define GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP 448 /** * Convert a short hash to a string (for printing debug messages). * This is one of the very few calls in the entire API that is * NOT reentrant! * * @param hc the short hash code * @return string form; will be overwritten by next call to GNUNET_h2s. */ const char * GNUNET_short_h2s (const struct GNUNET_CRYPTO_ShortHashCode * hc); /** * Sign name and records * * @param key the private key * @param expire block expiration * @param name the name * @param rd record data * @param rd_count number of records * * @return the signature */ struct GNUNET_CRYPTO_RsaSignature * GNUNET_NAMESTORE_create_signature (const struct GNUNET_CRYPTO_RsaPrivateKey *key, struct GNUNET_TIME_Absolute expire, const char *name, const struct GNUNET_NAMESTORE_RecordData *rd, unsigned int rd_count); /** * Compares if two records are equal * * @param a Record a * @param b Record b * * @return GNUNET_YES or GNUNET_NO */ int GNUNET_NAMESTORE_records_cmp (const struct GNUNET_NAMESTORE_RecordData *a, const struct GNUNET_NAMESTORE_RecordData *b); GNUNET_NETWORK_STRUCT_BEGIN /** * A GNS record serialized for network transmission. * * Layout is [struct GNUNET_NAMESTORE_NetworkRecord][char[data_size] data] */ struct GNUNET_NAMESTORE_NetworkRecord { /** * Expiration time for the DNS record. */ struct GNUNET_TIME_AbsoluteNBO expiration; /** * Number of bytes in 'data'. */ uint32_t data_size; /** * Type of the GNS/DNS record. */ uint32_t record_type; /** * Flags for the record. */ uint32_t flags; }; /** * Connect to namestore service. FIXME: UNNECESSARY. */ struct StartMessage { /** * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_START */ struct GNUNET_MessageHeader header; }; /** * Generic namestore message with op id */ struct GNUNET_NAMESTORE_Header { /** * header.type will be GNUNET_MESSAGE_TYPE_NAMESTORE_* * header.size will be message size */ struct GNUNET_MessageHeader header; /** * Request ID in NBO */ uint32_t r_id; }; /** * Lookup a name in the namestore */ struct LookupNameMessage { struct GNUNET_NAMESTORE_Header gns_header; /** * The zone */ struct GNUNET_CRYPTO_ShortHashCode zone; /** * Requested record type */ uint32_t record_type; /** * Length of the name */ uint32_t name_len; /* 0-terminated name here */ }; /** * Lookup response */ struct LookupNameResponseMessage { /** * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME_RESPONSE */ struct GNUNET_NAMESTORE_Header gns_header; /** * Expiration time */ struct GNUNET_TIME_AbsoluteNBO expire; /** * Name length */ uint16_t name_len; /** * Bytes of serialized record data */ uint16_t rd_len; /** * Number of records contained */ uint16_t rd_count; /** * Is the signature valid * GNUNET_YES or GNUNET_NO */ int16_t contains_sig; /** * All zeros if 'contains_sig' is GNUNET_NO. */ struct GNUNET_CRYPTO_RsaSignature signature; /** * The public key for the name */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; /* 0-terminated name and serialized record data */ /* rd_len bytes serialized record data */ }; /** * Put a record to the namestore */ struct RecordPutMessage { /** * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_RECORD_PUT */ struct GNUNET_NAMESTORE_Header gns_header; /** * Expiration time */ struct GNUNET_TIME_AbsoluteNBO expire; /** * Name length */ uint16_t name_len; /** * Length of serialized record data */ uint16_t rd_len; /** * Number of records contained */ uint16_t rd_count; /** * always zero (for alignment) */ uint16_t reserved; /** * The signature */ struct GNUNET_CRYPTO_RsaSignature signature; /** * The public key */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; /* name (0-terminated) followed by "rd_count" serialized records */ }; /** * Put a record to the namestore response */ struct RecordPutResponseMessage { /** * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT_RESPONSE */ struct GNUNET_NAMESTORE_Header gns_header; /** * result: * GNUNET_SYSERR on failure * GNUNET_OK on success */ int32_t op_result; }; /** * Create a record and put it to the namestore * Memory layout: */ struct RecordCreateMessage { /** * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE */ struct GNUNET_NAMESTORE_Header gns_header; struct GNUNET_TIME_AbsoluteNBO expire; /** * Name length */ uint16_t name_len; /** * Length of serialized record data */ uint16_t rd_len; /** * Record count */ uint16_t rd_count; /** * private key length */ uint16_t pkey_len; /* followed by: * GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded private key with length pkey_len * name with length name_len * serialized record data with length rd_len * */ }; /** * Create a record to the namestore response */ struct RecordCreateResponseMessage { /** * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE_RESPONSE */ struct GNUNET_NAMESTORE_Header gns_header; /** * name length: GNUNET_NO already exists, GNUNET_YES on success, GNUNET_SYSERR error */ int32_t op_result; }; /** * Remove a record from the namestore * Memory layout: */ struct RecordRemoveMessage { /** * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE */ struct GNUNET_NAMESTORE_Header gns_header; /** * Name length */ uint16_t name_len; /** * Length of serialized rd data */ uint16_t rd_len; /** * Number of records contained */ uint16_t rd_count; /** * Length of private key */ uint16_t pkey_len; /* followed by: * GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded private key with length pkey_len * name with length name_len * serialized record data with length rd_len * */ }; /** * Remove a record from the namestore response */ struct RecordRemoveResponseMessage { /** * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE_RESPONSE */ struct GNUNET_NAMESTORE_Header gns_header; /** * result: * 0 : successful * 1 : no records for entry * 2 : Could not find record to remove * 3 : Failed to create new signature * 4 : Failed to put new set of records in database */ int32_t op_result; }; /** * Lookup a name for a zone hash */ struct ZoneToNameMessage { /** * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME */ struct GNUNET_NAMESTORE_Header gns_header; /** * The hash of public key of the zone to look up in */ struct GNUNET_CRYPTO_ShortHashCode zone; /** * The hash of the public key of the target zone */ struct GNUNET_CRYPTO_ShortHashCode value_zone; }; /** * Respone for zone to name lookup */ struct ZoneToNameResponseMessage { /** * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE */ struct GNUNET_NAMESTORE_Header gns_header; /** * Record block expiration */ struct GNUNET_TIME_AbsoluteNBO expire; /** * Length of the name */ uint16_t name_len; /** * Length of serialized record data */ uint16_t rd_len; /** * Number of records contained */ uint16_t rd_count; /* result in NBO: GNUNET_OK on success, GNUNET_NO if there were no results, GNUNET_SYSERR on error */ int16_t res; /** * Signature */ struct GNUNET_CRYPTO_RsaSignature signature; /** * Publik key */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded zone_key; }; /** * Start a zone iteration for the given zone */ struct ZoneIterationStartMessage { /** * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START */ struct GNUNET_NAMESTORE_Header gns_header; /** * Zone hash */ struct GNUNET_CRYPTO_ShortHashCode zone; /** * Which flags must be included */ uint16_t must_have_flags; /** * Which flags must not be included */ uint16_t must_not_have_flags; }; /** * Ask for next result of zone iteration for the given operation */ struct ZoneIterationNextMessage { /** * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT */ struct GNUNET_NAMESTORE_Header gns_header; }; /** * Stop zone iteration for the given operation */ struct ZoneIterationStopMessage { /** * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP */ struct GNUNET_NAMESTORE_Header gns_header; }; /** * Next result of zone iteration for the given operation * // FIXME: use 'struct LookupResponseMessage' instead? (identical except * for having 'contains_sig' instead of 'reserved', but fully compatible otherwise). */ struct ZoneIterationResponseMessage { /** * Type will be GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE */ struct GNUNET_NAMESTORE_Header gns_header; struct GNUNET_TIME_AbsoluteNBO expire; uint16_t name_len; /* Record data length */ uint16_t rd_len; /** * Number of records contained */ uint16_t rd_count; /** * always zero (for alignment) */ uint16_t reserved; /** * All zeros if 'contains_sig' is GNUNET_NO. */ struct GNUNET_CRYPTO_RsaSignature signature; /** * The public key */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; }; GNUNET_NETWORK_STRUCT_END /* end of namestore.h */ #endif gnunet-0.9.3/src/namestore/test_namestore_api_sign_verify.c0000644000175000017500000001014211760502550021164 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file namestore/test_namestore_api_sign_verify.c * @brief testcase for signing and verifying */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_namestore_service.h" #include "namestore.h" #include "gnunet_signatures.h" #define VERBOSE GNUNET_NO #define RECORDS 5 #define TEST_RECORD_TYPE 1234 #define TEST_RECORD_DATALEN 123 #define TEST_RECORD_DATA 'a' #define TEST_REMOVE_RECORD_TYPE 4321 #define TEST_REMOVE_RECORD_DATALEN 255 #define TEST_REMOVE_RECORD_DATA 'b' static struct GNUNET_CRYPTO_RsaPrivateKey * privkey; static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubkey; struct GNUNET_CRYPTO_RsaSignature s_signature; struct GNUNET_NAMESTORE_RecordData *s_rd; static char *s_name; static int res; static struct GNUNET_NAMESTORE_RecordData * create_record (int count) { int c; struct GNUNET_NAMESTORE_RecordData * rd; rd = GNUNET_malloc (count * sizeof (struct GNUNET_NAMESTORE_RecordData)); for (c = 0; c < RECORDS; c++) { rd[c].expiration = GNUNET_TIME_absolute_get(); rd[c].record_type = TEST_RECORD_TYPE; rd[c].data_size = TEST_RECORD_DATALEN; rd[c].data = GNUNET_malloc(TEST_RECORD_DATALEN); memset ((char *) rd[c].data, TEST_RECORD_DATA, TEST_RECORD_DATALEN); } return rd; } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_CRYPTO_RsaSignature * signature; /* load privat key */ char *hostkey_file; GNUNET_asprintf(&hostkey_file,"zonefiles%s%s",DIR_SEPARATOR_STR, "N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using zonekey file `%s' \n", hostkey_file); privkey = GNUNET_CRYPTO_rsa_key_create_from_file(hostkey_file); GNUNET_free (hostkey_file); GNUNET_assert (privkey != NULL); struct GNUNET_TIME_Absolute expire = GNUNET_TIME_absolute_get(); /* get public key */ GNUNET_CRYPTO_rsa_key_get_public(privkey, &pubkey); int res_c; int res_w; /* create record */ s_name = "dummy.dummy.gnunet"; s_rd = create_record (RECORDS); signature = GNUNET_NAMESTORE_create_signature (privkey, expire, s_name, s_rd, RECORDS); GNUNET_assert (signature != NULL); res_c = GNUNET_NAMESTORE_verify_signature(&pubkey, expire, s_name, RECORDS, s_rd, signature); GNUNET_break (res == GNUNET_OK); GNUNET_free (signature); signature = GNUNET_NAMESTORE_create_signature (privkey, expire, s_name, s_rd, RECORDS); GNUNET_break (signature != NULL); GNUNET_log_skip(1, GNUNET_NO); res_w = GNUNET_NAMESTORE_verify_signature(&pubkey, expire, s_name, RECORDS - 1, s_rd, signature); GNUNET_break (res_w == GNUNET_SYSERR); GNUNET_free (signature); if ((res_c == GNUNET_OK) && (res_w == GNUNET_SYSERR)) res = 0; else res = 1; } static int check () { static char *const argv[] = { "test-namestore-api", "-c", "test_namestore_api.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; res = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-namestore-api", "nohelp", options, &run, &res); return res; } int main (int argc, char *argv[]) { int ret; ret = check (); return ret; } /* end of test_namestore_api_sign_verify.c */ gnunet-0.9.3/src/namestore/test_namestore_api.conf0000644000175000017500000000132411726433661017275 00000000000000[arm] PORT = 12000 DEFAULTSERVICES = namestore UNIXPATH = /tmp/gnunet-p1-service-arm.sock [namestore] #PREFIX = valgrind --leak-check=full --track-origins=yes AUTOSTART = YES UNIXPATH = /tmp/gnunet-service-namestore.sock UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES PORT = 2099 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-namestore ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DATABASE = sqlite ZONEFILE_DIRECTORY = zonefiles [namestore-sqlite] FILENAME = $SERVICEHOME/namestore/sqlite_test.db [namestore-postgres] CONFIG = connect_timeout=10; dbname=gnunet [namestore-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf # USER = gnunet # PASSWORD = # HOST = localhost # PORT = 3306 gnunet-0.9.3/src/namestore/test_namestore_api_lookup_specific_type.c0000644000175000017500000002461111760517543023075 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file namestore/test_namestore_api.c * @brief testcase for namestore_api.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_namestore_service.h" #include "namestore.h" #include "gnunet_signatures.h" #define VERBOSE GNUNET_NO #define RECORDS 5 #define TEST_RECORD_TYPE 1234 #define TEST_RECORD_DATALEN 123 #define TEST_RECORD_DATA 'a' #define TEST_RECORD_LOOKUP_TYPE_NOT_EXISTING 11111 #define TEST_RECORD_LOOKUP_TYPE_EXISTING 22222 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) static struct GNUNET_NAMESTORE_Handle * nsh; static GNUNET_SCHEDULER_TaskIdentifier endbadly_task; static struct GNUNET_OS_Process *arm; static struct GNUNET_CRYPTO_RsaPrivateKey * privkey; static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubkey; struct GNUNET_CRYPTO_RsaSignature *s_signature; static struct GNUNET_CRYPTO_ShortHashCode s_zone; struct GNUNET_NAMESTORE_RecordData *s_rd; static char *s_name; static int res; static void start_arm (const char *cfgname) { arm = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, #if VERBOSE_PEERS "-L", "DEBUG", #else "-L", "ERROR", #endif NULL); } static void stop_arm () { if (NULL != arm) { if (0 != GNUNET_OS_process_kill (arm, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); GNUNET_OS_process_wait (arm); GNUNET_OS_process_destroy (arm); arm = NULL; } } /** * Re-establish the connection to the service. * * @param cls handle to use to re-connect. * @param tc scheduler context */ static void endbadly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (nsh != NULL) GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); nsh = NULL; if (privkey != NULL) GNUNET_CRYPTO_rsa_key_free (privkey); privkey = NULL; if (NULL != arm) stop_arm(); res = 1; } static void end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (endbadly_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (endbadly_task); endbadly_task = GNUNET_SCHEDULER_NO_TASK; } int c; for (c = 0; c < RECORDS; c++) { GNUNET_free_non_null((void *) s_rd[c].data); } GNUNET_free (s_rd); if (privkey != NULL) GNUNET_CRYPTO_rsa_key_free (privkey); privkey = NULL; if (nsh != NULL) GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); nsh = NULL; if (NULL != arm) stop_arm(); } void name_lookup_existing_record_type (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *n, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { int failed = GNUNET_NO; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Namestore returned %u records\n", rd_count); if ((NULL == n) || (0 != memcmp(zone_key, &pubkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))) { GNUNET_break(0); failed = GNUNET_YES; } if ((NULL == n) || (0 != strcmp(n, s_name))) { GNUNET_break(0); failed = GNUNET_YES; } if (1 != rd_count) { GNUNET_break(0); failed = GNUNET_YES; } if (NULL == rd) { GNUNET_break(0); failed = GNUNET_YES; } if (NULL != signature) { GNUNET_break(0); failed = GNUNET_YES; } if (failed == GNUNET_YES) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Namestore returned invalid response\n"); res = 1; } else { res = 0; } GNUNET_SCHEDULER_add_now(&end, NULL); } void name_lookup_non_existing_record_type (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *n, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { int failed = GNUNET_NO; /* We expect zone key != NULL, name != NULL, rd_count 0, rd NULL, signature NULL */ if (NULL == zone_key) { GNUNET_break(0); failed = GNUNET_YES; } if (NULL == n) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Name %s!\n", n); GNUNET_break(0); failed = GNUNET_YES; } if (0 != rd_count) { GNUNET_break(0); failed = GNUNET_YES; } if (NULL != rd) { GNUNET_break(0); failed = GNUNET_YES; } if (NULL != signature) { GNUNET_break(0); failed = GNUNET_YES; } if ((rd_count == 1) && (rd != NULL)) { if (GNUNET_NO == GNUNET_NAMESTORE_records_cmp(rd, &rd[RECORDS-1])) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Records are not equal!\n"); failed = GNUNET_YES; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Records are equal!\n"); } } if (failed == GNUNET_YES) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Namestore returned invalid response\n"); res = 1; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Namestore returned valid response\n"); GNUNET_NAMESTORE_lookup_record (nsh, &s_zone, s_name, TEST_RECORD_LOOKUP_TYPE_EXISTING, &name_lookup_existing_record_type, NULL); res = 0; } } void put_cont (void *cls, int32_t success, const char *emsg) { char * name = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Name store added record for `%s': %s\n", name, (success == GNUNET_OK) ? "SUCCESS" : "FAIL"); if (success == GNUNET_OK) { res = 0; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking up non-existing record type %u for name `%s'\n", TEST_RECORD_LOOKUP_TYPE_NOT_EXISTING, name); GNUNET_NAMESTORE_lookup_record (nsh, &s_zone, name, TEST_RECORD_LOOKUP_TYPE_NOT_EXISTING, &name_lookup_non_existing_record_type, NULL); } else { res = 1; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to put records for name `%s'\n", name); GNUNET_SCHEDULER_add_now(&end, NULL); } } static struct GNUNET_NAMESTORE_RecordData * create_record (int count) { int c; struct GNUNET_NAMESTORE_RecordData * rd; rd = GNUNET_malloc (count * sizeof (struct GNUNET_NAMESTORE_RecordData)); for (c = 0; c < RECORDS-1; c++) { rd[c].expiration = GNUNET_TIME_UNIT_ZERO_ABS; rd[c].record_type = 1; rd[c].data_size = TEST_RECORD_DATALEN; rd[c].data = GNUNET_malloc(TEST_RECORD_DATALEN); memset ((char *) rd[c].data, TEST_RECORD_DATA, TEST_RECORD_DATALEN); } rd[c].expiration = GNUNET_TIME_absolute_get(); rd[c].record_type = TEST_RECORD_LOOKUP_TYPE_EXISTING; rd[c].data_size = TEST_RECORD_DATALEN; rd[c].data = GNUNET_malloc(TEST_RECORD_DATALEN); memset ((char *) rd[c].data, TEST_RECORD_DATA, TEST_RECORD_DATALEN); return rd; } void delete_existing_db (const struct GNUNET_CONFIGURATION_Handle *cfg) { char *afsdir; if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, "namestore-sqlite", "FILENAME", &afsdir)) { if (GNUNET_OK == GNUNET_DISK_file_test (afsdir)) if (GNUNET_OK == GNUNET_DISK_file_test (afsdir)) if (GNUNET_OK == GNUNET_DISK_directory_remove(afsdir)) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleted existing database `%s' \n", afsdir); GNUNET_free (afsdir); } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { delete_existing_db(cfg); endbadly_task = GNUNET_SCHEDULER_add_delayed(TIMEOUT,endbadly, NULL); size_t rd_ser_len; /* load privat key */ char *hostkey_file; GNUNET_asprintf(&hostkey_file,"zonefiles%s%s",DIR_SEPARATOR_STR, "N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using zonekey file `%s' \n", hostkey_file); privkey = GNUNET_CRYPTO_rsa_key_create_from_file(hostkey_file); GNUNET_free (hostkey_file); GNUNET_assert (privkey != NULL); /* get public key */ GNUNET_CRYPTO_rsa_key_get_public(privkey, &pubkey); /* create record */ s_name = "dummy.dummy.gnunet"; s_rd = create_record (RECORDS); rd_ser_len = GNUNET_NAMESTORE_records_get_size(RECORDS, s_rd); char rd_ser[rd_ser_len]; GNUNET_NAMESTORE_records_serialize(RECORDS, s_rd, rd_ser_len, rd_ser); /* sign */ s_signature = GNUNET_NAMESTORE_create_signature(privkey, s_rd[RECORDS -1].expiration, s_name, s_rd, RECORDS); /* create random zone hash */ GNUNET_CRYPTO_short_hash (&pubkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &s_zone); start_arm (cfgfile); GNUNET_assert (arm != NULL); nsh = GNUNET_NAMESTORE_connect (cfg); GNUNET_break (NULL != nsh); GNUNET_break (s_rd != NULL); GNUNET_break (s_name != NULL); GNUNET_NAMESTORE_record_put (nsh, &pubkey, s_name, GNUNET_TIME_UNIT_FOREVER_ABS, RECORDS, s_rd, s_signature, put_cont, s_name); } static int check () { static char *const argv[] = { "test-namestore-api", "-c", "test_namestore_api.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; res = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-namestore-api", "nohelp", options, &run, &res); return res; } int main (int argc, char *argv[]) { int ret; ret = check (); GNUNET_free (s_signature); return ret; } /* end of test_namestore_api.c */ gnunet-0.9.3/src/namestore/test_namestore_api_lookup.c0000644000175000017500000002012011762422560020152 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file namestore/test_namestore_api.c * @brief testcase for namestore_api.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_namestore_service.h" #include "namestore.h" #include "gnunet_signatures.h" #define VERBOSE GNUNET_NO #define RECORDS 5 #define TEST_RECORD_TYPE 1234 #define TEST_RECORD_DATALEN 123 #define TEST_RECORD_DATA 'a' #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) static struct GNUNET_NAMESTORE_Handle * nsh; static GNUNET_SCHEDULER_TaskIdentifier endbadly_task; static struct GNUNET_OS_Process *arm; static struct GNUNET_CRYPTO_RsaPrivateKey * privkey; static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubkey; struct GNUNET_CRYPTO_RsaSignature *s_signature; static struct GNUNET_CRYPTO_ShortHashCode s_zone; struct GNUNET_NAMESTORE_RecordData *s_rd; static char *s_name; static int res; static void start_arm (const char *cfgname) { arm = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, #if VERBOSE_PEERS "-L", "DEBUG", #else "-L", "ERROR", #endif NULL); } static void stop_arm () { if (NULL != arm) { if (0 != GNUNET_OS_process_kill (arm, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); GNUNET_OS_process_wait (arm); GNUNET_OS_process_destroy (arm); arm = NULL; } } /** * Re-establish the connection to the service. * * @param cls handle to use to re-connect. * @param tc scheduler context */ static void endbadly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (nsh != NULL) GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); nsh = NULL; if (privkey != NULL) GNUNET_CRYPTO_rsa_key_free (privkey); privkey = NULL; if (NULL != arm) stop_arm(); res = 1; } static void end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (endbadly_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (endbadly_task); endbadly_task = GNUNET_SCHEDULER_NO_TASK; } int c; for (c = 0; c < RECORDS; c++) GNUNET_free_non_null((void *) s_rd[c].data); GNUNET_free (s_rd); if (privkey != NULL) GNUNET_CRYPTO_rsa_key_free (privkey); privkey = NULL; if (nsh != NULL) GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); nsh = NULL; if (NULL != arm) stop_arm(); } void name_lookup_proc (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *n, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { static int found = GNUNET_NO; int c; if (n != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking returned results\n"); if (0 != memcmp (zone_key, &pubkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded))) { GNUNET_break (0); } if (0 != memcmp (signature, s_signature, sizeof (struct GNUNET_CRYPTO_RsaSignature))) { GNUNET_break (0); } if (0 != strcmp(n, s_name)) { GNUNET_break (0); } if (RECORDS != rd_count) { GNUNET_break (0); } for (c = 0; c < RECORDS; c++) { if (GNUNET_NO == GNUNET_NAMESTORE_records_cmp (&rd[c], &s_rd[c])) { GNUNET_break (0); } } found = GNUNET_YES; res = 0; } else { if (found != GNUNET_YES) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to lookup records for name `%s'\n", s_name); res = 1; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Lookup done for name %s'\n", s_name); } GNUNET_SCHEDULER_add_now(&end, NULL); } void put_cont (void *cls, int32_t success, const char *emsg) { char * name = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Name store added record for `%s': %s\n", name, (success == GNUNET_OK) ? "SUCCESS" : "FAIL"); if (success == GNUNET_OK) { res = 0; GNUNET_NAMESTORE_lookup_record (nsh, &s_zone, name, 0, &name_lookup_proc, NULL); } else { res = 1; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to put records for name `%s'\n", name); GNUNET_SCHEDULER_add_now(&end, NULL); } } static struct GNUNET_NAMESTORE_RecordData * create_record (int count) { int c; struct GNUNET_NAMESTORE_RecordData * rd; rd = GNUNET_malloc (count * sizeof (struct GNUNET_NAMESTORE_RecordData)); for (c = 0; c < RECORDS; c++) { rd[c].expiration = GNUNET_TIME_absolute_get(); rd[c].record_type = TEST_RECORD_TYPE; rd[c].data_size = TEST_RECORD_DATALEN; rd[c].data = GNUNET_malloc(TEST_RECORD_DATALEN); memset ((char *) rd[c].data, TEST_RECORD_DATA, TEST_RECORD_DATALEN); } return rd; } void delete_existing_db (const struct GNUNET_CONFIGURATION_Handle *cfg) { char *afsdir; if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, "namestore-sqlite", "FILENAME", &afsdir)) { if (GNUNET_OK == GNUNET_DISK_file_test (afsdir)) if (GNUNET_OK == GNUNET_DISK_file_test (afsdir)) if (GNUNET_OK == GNUNET_DISK_directory_remove(afsdir)) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleted existing database `%s' \n", afsdir); GNUNET_free (afsdir); } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { delete_existing_db(cfg); endbadly_task = GNUNET_SCHEDULER_add_delayed(TIMEOUT,endbadly, NULL); size_t rd_ser_len; /* load privat key from file not included in zonekey dir */ privkey = GNUNET_CRYPTO_rsa_key_create_from_file("test_hostkey"); GNUNET_assert (privkey != NULL); /* get public key */ GNUNET_CRYPTO_rsa_key_get_public(privkey, &pubkey); /* create record */ s_name = "dummy.dummy.gnunet"; s_rd = create_record (RECORDS); rd_ser_len = GNUNET_NAMESTORE_records_get_size(RECORDS, s_rd); char rd_ser[rd_ser_len]; GNUNET_NAMESTORE_records_serialize(RECORDS, s_rd, rd_ser_len, rd_ser); /* sign */ s_signature = GNUNET_NAMESTORE_create_signature(privkey, s_rd[0].expiration, s_name, s_rd, RECORDS); /* create random zone hash */ GNUNET_CRYPTO_short_hash (&pubkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &s_zone); start_arm (cfgfile); GNUNET_assert (arm != NULL); nsh = GNUNET_NAMESTORE_connect (cfg); GNUNET_break (NULL != nsh); GNUNET_break (s_rd != NULL); GNUNET_break (s_name != NULL); GNUNET_NAMESTORE_record_put (nsh, &pubkey, s_name, GNUNET_TIME_UNIT_FOREVER_ABS, RECORDS, s_rd, s_signature, put_cont, s_name); } static int check () { static char *const argv[] = { "test-namestore-api", "-c", "test_namestore_api.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; res = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-namestore-api", "nohelp", options, &run, &res); return res; } int main (int argc, char *argv[]) { int ret; ret = check (); GNUNET_free (s_signature); return ret; } /* end of test_namestore_api.c */ gnunet-0.9.3/src/namestore/test_plugin_namestore_sqlite.conf0000644000175000017500000000012111721257132021365 00000000000000[namestore-sqlite] FILENAME = /tmp/gnunet-test-plugin-namestore-sqlite/sqlite.db gnunet-0.9.3/src/namestore/Makefile.in0000644000175000017500000014061511762217212014605 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ check_PROGRAMS = $(am__EXEEXT_1) \ test_namestore_record_serialization$(EXEEXT) \ test_namestore_api_sign_verify$(EXEEXT) \ test_namestore_api$(EXEEXT) test_namestore_api_put$(EXEEXT) \ test_namestore_api_lookup$(EXEEXT) \ test_namestore_api_lookup_specific_type$(EXEEXT) \ test_namestore_api_create$(EXEEXT) \ test_namestore_api_create_update$(EXEEXT) \ test_namestore_api_remove$(EXEEXT) \ test_namestore_api_remove_not_existing_record$(EXEEXT) \ test_namestore_api_zone_to_name$(EXEEXT) \ test_namestore_api_zone_iteration$(EXEEXT) \ test_namestore_api_zone_iteration_specific_zone$(EXEEXT) \ test_namestore_api_zone_iteration_stop$(EXEEXT) bin_PROGRAMS = gnunet-service-namestore$(EXEEXT) \ gnunet-namestore$(EXEEXT) subdir = src/namestore DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/namestore.conf.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = namestore.conf CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \ "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) $(plugin_LTLIBRARIES) am__DEPENDENCIES_1 = am_libgnunet_plugin_namestore_sqlite_la_OBJECTS = \ plugin_namestore_sqlite.lo namestore_common.lo libgnunet_plugin_namestore_sqlite_la_OBJECTS = \ $(am_libgnunet_plugin_namestore_sqlite_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunet_plugin_namestore_sqlite_la_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libgnunet_plugin_namestore_sqlite_la_LDFLAGS) $(LDFLAGS) -o \ $@ @HAVE_SQLITE_TRUE@am_libgnunet_plugin_namestore_sqlite_la_rpath = \ @HAVE_SQLITE_TRUE@ -rpath $(plugindir) libgnunetnamestore_la_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_libgnunetnamestore_la_OBJECTS = namestore_api.lo \ namestore_common.lo libgnunetnamestore_la_OBJECTS = $(am_libgnunetnamestore_la_OBJECTS) libgnunetnamestore_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetnamestore_la_LDFLAGS) \ $(LDFLAGS) -o $@ @HAVE_SQLITE_TRUE@am__EXEEXT_1 = \ @HAVE_SQLITE_TRUE@ test_plugin_namestore_sqlite$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) am_gnunet_namestore_OBJECTS = gnunet-namestore.$(OBJEXT) gnunet_namestore_OBJECTS = $(am_gnunet_namestore_OBJECTS) am_gnunet_service_namestore_OBJECTS = \ gnunet-service-namestore.$(OBJEXT) gnunet_service_namestore_OBJECTS = \ $(am_gnunet_service_namestore_OBJECTS) am_test_namestore_api_OBJECTS = test_namestore_api.$(OBJEXT) test_namestore_api_OBJECTS = $(am_test_namestore_api_OBJECTS) test_namestore_api_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la am_test_namestore_api_create_OBJECTS = \ test_namestore_api_create.$(OBJEXT) test_namestore_api_create_OBJECTS = \ $(am_test_namestore_api_create_OBJECTS) test_namestore_api_create_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la am_test_namestore_api_create_update_OBJECTS = \ test_namestore_api_create_update.$(OBJEXT) test_namestore_api_create_update_OBJECTS = \ $(am_test_namestore_api_create_update_OBJECTS) test_namestore_api_create_update_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la am_test_namestore_api_lookup_OBJECTS = \ test_namestore_api_lookup.$(OBJEXT) test_namestore_api_lookup_OBJECTS = \ $(am_test_namestore_api_lookup_OBJECTS) test_namestore_api_lookup_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la am_test_namestore_api_lookup_specific_type_OBJECTS = \ test_namestore_api_lookup_specific_type.$(OBJEXT) test_namestore_api_lookup_specific_type_OBJECTS = \ $(am_test_namestore_api_lookup_specific_type_OBJECTS) test_namestore_api_lookup_specific_type_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la am_test_namestore_api_put_OBJECTS = test_namestore_api_put.$(OBJEXT) test_namestore_api_put_OBJECTS = $(am_test_namestore_api_put_OBJECTS) test_namestore_api_put_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la am_test_namestore_api_remove_OBJECTS = \ test_namestore_api_remove.$(OBJEXT) test_namestore_api_remove_OBJECTS = \ $(am_test_namestore_api_remove_OBJECTS) test_namestore_api_remove_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la am_test_namestore_api_remove_not_existing_record_OBJECTS = \ test_namestore_api_remove_not_existing_record.$(OBJEXT) test_namestore_api_remove_not_existing_record_OBJECTS = \ $(am_test_namestore_api_remove_not_existing_record_OBJECTS) test_namestore_api_remove_not_existing_record_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la am_test_namestore_api_sign_verify_OBJECTS = \ test_namestore_api_sign_verify.$(OBJEXT) test_namestore_api_sign_verify_OBJECTS = \ $(am_test_namestore_api_sign_verify_OBJECTS) test_namestore_api_sign_verify_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la am_test_namestore_api_zone_iteration_OBJECTS = \ test_namestore_api_zone_iteration.$(OBJEXT) test_namestore_api_zone_iteration_OBJECTS = \ $(am_test_namestore_api_zone_iteration_OBJECTS) test_namestore_api_zone_iteration_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la am_test_namestore_api_zone_iteration_specific_zone_OBJECTS = \ test_namestore_api_zone_iteration_specific_zone.$(OBJEXT) test_namestore_api_zone_iteration_specific_zone_OBJECTS = \ $(am_test_namestore_api_zone_iteration_specific_zone_OBJECTS) test_namestore_api_zone_iteration_specific_zone_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la am_test_namestore_api_zone_iteration_stop_OBJECTS = \ test_namestore_api_zone_iteration_stop.$(OBJEXT) test_namestore_api_zone_iteration_stop_OBJECTS = \ $(am_test_namestore_api_zone_iteration_stop_OBJECTS) test_namestore_api_zone_iteration_stop_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la am_test_namestore_api_zone_to_name_OBJECTS = \ test_namestore_api_zone_to_name.$(OBJEXT) test_namestore_api_zone_to_name_OBJECTS = \ $(am_test_namestore_api_zone_to_name_OBJECTS) test_namestore_api_zone_to_name_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la am_test_namestore_record_serialization_OBJECTS = \ test_namestore_record_serialization.$(OBJEXT) test_namestore_record_serialization_OBJECTS = \ $(am_test_namestore_record_serialization_OBJECTS) test_namestore_record_serialization_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la am_test_plugin_namestore_sqlite_OBJECTS = \ test_plugin_namestore.$(OBJEXT) test_plugin_namestore_sqlite_OBJECTS = \ $(am_test_plugin_namestore_sqlite_OBJECTS) test_plugin_namestore_sqlite_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunet_plugin_namestore_sqlite_la_SOURCES) \ $(libgnunetnamestore_la_SOURCES) $(gnunet_namestore_SOURCES) \ $(gnunet_service_namestore_SOURCES) \ $(test_namestore_api_SOURCES) \ $(test_namestore_api_create_SOURCES) \ $(test_namestore_api_create_update_SOURCES) \ $(test_namestore_api_lookup_SOURCES) \ $(test_namestore_api_lookup_specific_type_SOURCES) \ $(test_namestore_api_put_SOURCES) \ $(test_namestore_api_remove_SOURCES) \ $(test_namestore_api_remove_not_existing_record_SOURCES) \ $(test_namestore_api_sign_verify_SOURCES) \ $(test_namestore_api_zone_iteration_SOURCES) \ $(test_namestore_api_zone_iteration_specific_zone_SOURCES) \ $(test_namestore_api_zone_iteration_stop_SOURCES) \ $(test_namestore_api_zone_to_name_SOURCES) \ $(test_namestore_record_serialization_SOURCES) \ $(test_plugin_namestore_sqlite_SOURCES) DIST_SOURCES = $(libgnunet_plugin_namestore_sqlite_la_SOURCES) \ $(libgnunetnamestore_la_SOURCES) $(gnunet_namestore_SOURCES) \ $(gnunet_service_namestore_SOURCES) \ $(test_namestore_api_SOURCES) \ $(test_namestore_api_create_SOURCES) \ $(test_namestore_api_create_update_SOURCES) \ $(test_namestore_api_lookup_SOURCES) \ $(test_namestore_api_lookup_specific_type_SOURCES) \ $(test_namestore_api_put_SOURCES) \ $(test_namestore_api_remove_SOURCES) \ $(test_namestore_api_remove_not_existing_record_SOURCES) \ $(test_namestore_api_sign_verify_SOURCES) \ $(test_namestore_api_zone_iteration_SOURCES) \ $(test_namestore_api_zone_iteration_specific_zone_SOURCES) \ $(test_namestore_api_zone_iteration_stop_SOURCES) \ $(test_namestore_api_zone_to_name_SOURCES) \ $(test_namestore_record_serialization_SOURCES) \ $(test_plugin_namestore_sqlite_SOURCES) DATA = $(pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include plugindir = $(libdir)/gnunet pkgcfgdir = $(pkgdatadir)/config.d/ pkgcfg_DATA = \ namestore.conf @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @USE_COVERAGE_TRUE@XLIBS = -lgcov @HAVE_SQLITE_TRUE@SQLITE_TESTS = \ @HAVE_SQLITE_TRUE@ test_plugin_namestore_sqlite @ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) lib_LTLIBRARIES = \ libgnunetnamestore.la libgnunetnamestore_la_SOURCES = \ namestore_api.c namestore_common.c namestore.h libgnunetnamestore_la_LIBADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) libgnunetnamestore_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 0:0:0 gnunet_namestore_SOURCES = \ gnunet-namestore.c gnunet_namestore_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ libgnunetnamestore.la \ $(GN_LIBINTL) gnunet_namestore_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ libgnunetnamestore.la gnunet_service_namestore_SOURCES = \ gnunet-service-namestore.c gnunet_service_namestore_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ libgnunetnamestore.la \ $(GN_LIBINTL) gnunet_service_namestore_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ libgnunetnamestore.la @HAVE_SQLITE_TRUE@SQLITE_PLUGIN = libgnunet_plugin_namestore_sqlite.la plugin_LTLIBRARIES = \ $(SQLITE_PLUGIN) libgnunet_plugin_namestore_sqlite_la_SOURCES = \ plugin_namestore_sqlite.c namestore_common.c libgnunet_plugin_namestore_sqlite_la_LIBADD = \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 libgnunet_plugin_namestore_sqlite_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_namestore_sqlite_la_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ libgnunetnamestore.la test_namestore_api_sign_verify_SOURCES = \ test_namestore_api_sign_verify.c test_namestore_api_sign_verify_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_SOURCES = \ test_namestore_api.c test_namestore_api_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_put_SOURCES = \ test_namestore_api_put.c test_namestore_api_put_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_lookup_SOURCES = \ test_namestore_api_lookup.c test_namestore_api_lookup_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_lookup_specific_type_SOURCES = \ test_namestore_api_lookup_specific_type.c test_namestore_api_lookup_specific_type_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_create_SOURCES = \ test_namestore_api_create.c test_namestore_api_create_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_create_update_SOURCES = \ test_namestore_api_create_update.c test_namestore_api_create_update_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_remove_SOURCES = \ test_namestore_api_remove.c test_namestore_api_remove_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_remove_not_existing_record_SOURCES = \ test_namestore_api_remove_not_existing_record.c test_namestore_api_remove_not_existing_record_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_zone_to_name_SOURCES = \ test_namestore_api_zone_to_name.c test_namestore_api_zone_to_name_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_zone_iteration_SOURCES = \ test_namestore_api_zone_iteration.c test_namestore_api_zone_iteration_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_zone_iteration_specific_zone_SOURCES = \ test_namestore_api_zone_iteration_specific_zone.c test_namestore_api_zone_iteration_specific_zone_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_api_zone_iteration_stop_SOURCES = \ test_namestore_api_zone_iteration_stop.c test_namestore_api_zone_iteration_stop_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la test_namestore_record_serialization_SOURCES = \ test_namestore_record_serialization.c test_namestore_record_serialization_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la EXTRA_DIST = \ test_namestore_api.conf \ test_plugin_namestore_sqlite.conf\ test_hostkey \ zonefiles/HGU0A0VCU334DN7F2I9UIUMVQMM7JMSD142LIMNUGTTV9R0CF4EG.zkey \ zonefiles/N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey test_plugin_namestore_sqlite_SOURCES = \ test_plugin_namestore.c test_plugin_namestore_sqlite_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/namestore/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/namestore/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): namestore.conf: $(top_builddir)/config.status $(srcdir)/namestore.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ } uninstall-pluginLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ done clean-pluginLTLIBRARIES: -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunet_plugin_namestore_sqlite.la: $(libgnunet_plugin_namestore_sqlite_la_OBJECTS) $(libgnunet_plugin_namestore_sqlite_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_namestore_sqlite_la_LINK) $(am_libgnunet_plugin_namestore_sqlite_la_rpath) $(libgnunet_plugin_namestore_sqlite_la_OBJECTS) $(libgnunet_plugin_namestore_sqlite_la_LIBADD) $(LIBS) libgnunetnamestore.la: $(libgnunetnamestore_la_OBJECTS) $(libgnunetnamestore_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetnamestore_la_LINK) -rpath $(libdir) $(libgnunetnamestore_la_OBJECTS) $(libgnunetnamestore_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-namestore$(EXEEXT): $(gnunet_namestore_OBJECTS) $(gnunet_namestore_DEPENDENCIES) @rm -f gnunet-namestore$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_namestore_OBJECTS) $(gnunet_namestore_LDADD) $(LIBS) gnunet-service-namestore$(EXEEXT): $(gnunet_service_namestore_OBJECTS) $(gnunet_service_namestore_DEPENDENCIES) @rm -f gnunet-service-namestore$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_service_namestore_OBJECTS) $(gnunet_service_namestore_LDADD) $(LIBS) test_namestore_api$(EXEEXT): $(test_namestore_api_OBJECTS) $(test_namestore_api_DEPENDENCIES) @rm -f test_namestore_api$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_namestore_api_OBJECTS) $(test_namestore_api_LDADD) $(LIBS) test_namestore_api_create$(EXEEXT): $(test_namestore_api_create_OBJECTS) $(test_namestore_api_create_DEPENDENCIES) @rm -f test_namestore_api_create$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_namestore_api_create_OBJECTS) $(test_namestore_api_create_LDADD) $(LIBS) test_namestore_api_create_update$(EXEEXT): $(test_namestore_api_create_update_OBJECTS) $(test_namestore_api_create_update_DEPENDENCIES) @rm -f test_namestore_api_create_update$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_namestore_api_create_update_OBJECTS) $(test_namestore_api_create_update_LDADD) $(LIBS) test_namestore_api_lookup$(EXEEXT): $(test_namestore_api_lookup_OBJECTS) $(test_namestore_api_lookup_DEPENDENCIES) @rm -f test_namestore_api_lookup$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_namestore_api_lookup_OBJECTS) $(test_namestore_api_lookup_LDADD) $(LIBS) test_namestore_api_lookup_specific_type$(EXEEXT): $(test_namestore_api_lookup_specific_type_OBJECTS) $(test_namestore_api_lookup_specific_type_DEPENDENCIES) @rm -f test_namestore_api_lookup_specific_type$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_namestore_api_lookup_specific_type_OBJECTS) $(test_namestore_api_lookup_specific_type_LDADD) $(LIBS) test_namestore_api_put$(EXEEXT): $(test_namestore_api_put_OBJECTS) $(test_namestore_api_put_DEPENDENCIES) @rm -f test_namestore_api_put$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_namestore_api_put_OBJECTS) $(test_namestore_api_put_LDADD) $(LIBS) test_namestore_api_remove$(EXEEXT): $(test_namestore_api_remove_OBJECTS) $(test_namestore_api_remove_DEPENDENCIES) @rm -f test_namestore_api_remove$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_namestore_api_remove_OBJECTS) $(test_namestore_api_remove_LDADD) $(LIBS) test_namestore_api_remove_not_existing_record$(EXEEXT): $(test_namestore_api_remove_not_existing_record_OBJECTS) $(test_namestore_api_remove_not_existing_record_DEPENDENCIES) @rm -f test_namestore_api_remove_not_existing_record$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_namestore_api_remove_not_existing_record_OBJECTS) $(test_namestore_api_remove_not_existing_record_LDADD) $(LIBS) test_namestore_api_sign_verify$(EXEEXT): $(test_namestore_api_sign_verify_OBJECTS) $(test_namestore_api_sign_verify_DEPENDENCIES) @rm -f test_namestore_api_sign_verify$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_namestore_api_sign_verify_OBJECTS) $(test_namestore_api_sign_verify_LDADD) $(LIBS) test_namestore_api_zone_iteration$(EXEEXT): $(test_namestore_api_zone_iteration_OBJECTS) $(test_namestore_api_zone_iteration_DEPENDENCIES) @rm -f test_namestore_api_zone_iteration$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_namestore_api_zone_iteration_OBJECTS) $(test_namestore_api_zone_iteration_LDADD) $(LIBS) test_namestore_api_zone_iteration_specific_zone$(EXEEXT): $(test_namestore_api_zone_iteration_specific_zone_OBJECTS) $(test_namestore_api_zone_iteration_specific_zone_DEPENDENCIES) @rm -f test_namestore_api_zone_iteration_specific_zone$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_namestore_api_zone_iteration_specific_zone_OBJECTS) $(test_namestore_api_zone_iteration_specific_zone_LDADD) $(LIBS) test_namestore_api_zone_iteration_stop$(EXEEXT): $(test_namestore_api_zone_iteration_stop_OBJECTS) $(test_namestore_api_zone_iteration_stop_DEPENDENCIES) @rm -f test_namestore_api_zone_iteration_stop$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_namestore_api_zone_iteration_stop_OBJECTS) $(test_namestore_api_zone_iteration_stop_LDADD) $(LIBS) test_namestore_api_zone_to_name$(EXEEXT): $(test_namestore_api_zone_to_name_OBJECTS) $(test_namestore_api_zone_to_name_DEPENDENCIES) @rm -f test_namestore_api_zone_to_name$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_namestore_api_zone_to_name_OBJECTS) $(test_namestore_api_zone_to_name_LDADD) $(LIBS) test_namestore_record_serialization$(EXEEXT): $(test_namestore_record_serialization_OBJECTS) $(test_namestore_record_serialization_DEPENDENCIES) @rm -f test_namestore_record_serialization$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_namestore_record_serialization_OBJECTS) $(test_namestore_record_serialization_LDADD) $(LIBS) test_plugin_namestore_sqlite$(EXEEXT): $(test_plugin_namestore_sqlite_OBJECTS) $(test_plugin_namestore_sqlite_DEPENDENCIES) @rm -f test_plugin_namestore_sqlite$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_plugin_namestore_sqlite_OBJECTS) $(test_plugin_namestore_sqlite_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-namestore.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-namestore.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/namestore_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/namestore_common.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_namestore_sqlite.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_namestore_api.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_namestore_api_create.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_namestore_api_create_update.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_namestore_api_lookup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_namestore_api_lookup_specific_type.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_namestore_api_put.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_namestore_api_remove.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_namestore_api_remove_not_existing_record.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_namestore_api_sign_verify.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_namestore_api_zone_iteration.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_namestore_api_zone_iteration_specific_zone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_namestore_api_zone_iteration_stop.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_namestore_api_zone_to_name.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_namestore_record_serialization.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_plugin_namestore.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgcfgDATA: $(pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool clean-pluginLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgcfgDATA install-pluginLTLIBRARIES install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool clean-pluginLTLIBRARIES \ ctags distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-libLTLIBRARIES \ install-man install-pdf install-pdf-am install-pkgcfgDATA \ install-pluginLTLIBRARIES install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/namestore/test_namestore_api.c0000644000175000017500000001456111760517513016576 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file namestore/test_namestore_api.c * @brief testcase for namestore_api.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_namestore_service.h" #define VERBOSE GNUNET_NO #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) static struct GNUNET_NAMESTORE_Handle * nsh; static GNUNET_SCHEDULER_TaskIdentifier endbadly_task; static struct GNUNET_OS_Process *arm; static struct GNUNET_CRYPTO_RsaPrivateKey * privkey; static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubkey; static struct GNUNET_CRYPTO_ShortHashCode zone; static int res; #define TEST_RECORD_TYPE 1234 #define TEST_RECORD_DATALEN 123 #define TEST_RECORD_DATA 'a' static void start_arm (const char *cfgname) { arm = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, #if VERBOSE_PEERS "-L", "DEBUG", #else "-L", "ERROR", #endif NULL); } static void stop_arm () { if (NULL != arm) { if (0 != GNUNET_OS_process_kill (arm, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); GNUNET_OS_process_wait (arm); GNUNET_OS_process_destroy (arm); arm = NULL; } } /** * Re-establish the connection to the service. * * @param cls handle to use to re-connect. * @param tc scheduler context */ static void endbadly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (nsh != NULL) GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); nsh = NULL; if (privkey != NULL) GNUNET_CRYPTO_rsa_key_free (privkey); privkey = NULL; if (NULL != arm) stop_arm(); res = 1; } static void end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (endbadly_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (endbadly_task); endbadly_task = GNUNET_SCHEDULER_NO_TASK; } if (privkey != NULL) GNUNET_CRYPTO_rsa_key_free (privkey); privkey = NULL; if (nsh != NULL) GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); nsh = NULL; if (NULL != arm) stop_arm(); res = 0; } void name_lookup_proc (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *name, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Namestore lookup result %p `%s' %i %p %p\n", zone_key, name, rd_count, rd, signature); res = 0; GNUNET_SCHEDULER_add_now(&end, NULL); } void put_cont (void *cls, int32_t success, const char *emsg) { char * name = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Name store added record for `%s': %s\n", name, (success == GNUNET_OK) ? "SUCCESS" : "FAIL"); GNUNET_NAMESTORE_lookup_record (nsh, &zone, name, 0, &name_lookup_proc, NULL); } void delete_existing_db (const struct GNUNET_CONFIGURATION_Handle *cfg) { char *afsdir; if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, "namestore-sqlite", "FILENAME", &afsdir)) { if (GNUNET_OK == GNUNET_DISK_file_test (afsdir)) if (GNUNET_OK == GNUNET_DISK_file_test (afsdir)) if (GNUNET_OK == GNUNET_DISK_directory_remove(afsdir)) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleted existing database `%s' \n", afsdir); GNUNET_free (afsdir); } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { delete_existing_db(cfg); endbadly_task = GNUNET_SCHEDULER_add_delayed(TIMEOUT,endbadly, NULL); char *hostkey_file; GNUNET_asprintf(&hostkey_file,"zonefiles%s%s",DIR_SEPARATOR_STR, "N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using zonekey file `%s' \n", hostkey_file); privkey = GNUNET_CRYPTO_rsa_key_create_from_file(hostkey_file); GNUNET_free (hostkey_file); GNUNET_assert (privkey != NULL); GNUNET_CRYPTO_rsa_key_get_public(privkey, &pubkey); GNUNET_CRYPTO_short_hash (&pubkey, sizeof (pubkey), &zone); struct GNUNET_CRYPTO_RsaSignature signature; memset (&signature, '\0', sizeof (signature)); struct GNUNET_NAMESTORE_RecordData rd; rd.expiration = GNUNET_TIME_absolute_get(); rd.record_type = TEST_RECORD_TYPE; rd.data_size = TEST_RECORD_DATALEN; rd.data = GNUNET_malloc(TEST_RECORD_DATALEN); memset ((char *) rd.data, 'a', TEST_RECORD_DATALEN); char * name = "dummy.dummy.gnunet"; start_arm (cfgfile); GNUNET_assert (arm != NULL); nsh = GNUNET_NAMESTORE_connect (cfg); GNUNET_break (NULL != nsh); GNUNET_NAMESTORE_record_put (nsh, &pubkey, name, GNUNET_TIME_UNIT_FOREVER_ABS, 1, &rd, &signature, put_cont, name); GNUNET_free ((void *)rd.data); } static int check () { static char *const argv[] = { "test-namestore-api", "-c", "test_namestore_api.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; res = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-namestore-api", "nohelp", options, &run, &res); return res; } int main (int argc, char *argv[]) { int ret; ret = check (); return ret; } /* end of test_namestore_api.c */ gnunet-0.9.3/src/namestore/test_namestore_api_zone_iteration.c0000644000175000017500000003240011760517620021676 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file namestore/test_namestore_api_zone_iteration.c * @brief testcase for zone iteration functionality: iterate of a specific zone */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_namestore_service.h" #include "namestore.h" #define VERBOSE GNUNET_NO #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) static struct GNUNET_NAMESTORE_Handle * nsh; static GNUNET_SCHEDULER_TaskIdentifier endbadly_task; static GNUNET_SCHEDULER_TaskIdentifier stopiteration_task; static struct GNUNET_OS_Process *arm; static struct GNUNET_CRYPTO_RsaPrivateKey * privkey; static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubkey; static GNUNET_HashCode zone; static struct GNUNET_CRYPTO_RsaPrivateKey * privkey2; static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubkey2; static GNUNET_HashCode zone2; static struct GNUNET_NAMESTORE_ZoneIterator *zi; static int res; static int returned_records; struct GNUNET_CRYPTO_RsaSignature *sig_1; char * s_name_1; struct GNUNET_NAMESTORE_RecordData *s_rd_1; struct GNUNET_CRYPTO_RsaSignature *sig_2; char * s_name_2; struct GNUNET_NAMESTORE_RecordData *s_rd_2; struct GNUNET_CRYPTO_RsaSignature *sig_3; char * s_name_3; struct GNUNET_NAMESTORE_RecordData *s_rd_3; static void start_arm (const char *cfgname) { arm = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, #if VERBOSE_PEERS "-L", "DEBUG", #else "-L", "ERROR", #endif NULL); } static void stop_arm () { if (NULL != arm) { if (0 != GNUNET_OS_process_kill (arm, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); GNUNET_OS_process_wait (arm); GNUNET_OS_process_destroy (arm); arm = NULL; } } /** * Re-establish the connection to the service. * * @param cls handle to use to re-connect. * @param tc scheduler context */ static void endbadly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (stopiteration_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (stopiteration_task); stopiteration_task = GNUNET_SCHEDULER_NO_TASK; } if (nsh != NULL) GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); nsh = NULL; GNUNET_free_non_null(sig_1); GNUNET_free_non_null(sig_2); GNUNET_free_non_null(sig_3); GNUNET_free_non_null(s_name_1); GNUNET_free_non_null(s_name_2); GNUNET_free_non_null(s_name_3); if (s_rd_1 != NULL) { GNUNET_free ((void *)s_rd_1->data); GNUNET_free (s_rd_1); } if (s_rd_2 != NULL) { GNUNET_free ((void *)s_rd_2->data); GNUNET_free (s_rd_2); } if (s_rd_3 != NULL) { GNUNET_free ((void *)s_rd_3->data); GNUNET_free (s_rd_3); } if (privkey != NULL) GNUNET_CRYPTO_rsa_key_free (privkey); privkey = NULL; if (privkey2 != NULL) GNUNET_CRYPTO_rsa_key_free (privkey2); privkey2 = NULL; if (NULL != arm) stop_arm(); res = 1; } static void end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (stopiteration_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (stopiteration_task); stopiteration_task = GNUNET_SCHEDULER_NO_TASK; } if (endbadly_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (endbadly_task); endbadly_task = GNUNET_SCHEDULER_NO_TASK; } if (privkey != NULL) GNUNET_CRYPTO_rsa_key_free (privkey); privkey = NULL; if (privkey2 != NULL) GNUNET_CRYPTO_rsa_key_free (privkey2); privkey2 = NULL; GNUNET_free (sig_1); GNUNET_free (sig_2); GNUNET_free (sig_3); GNUNET_free (s_name_1); GNUNET_free (s_name_2); GNUNET_free (s_name_3); if (s_rd_1 != NULL) { GNUNET_free ((void *)s_rd_1->data); GNUNET_free (s_rd_1); } if (s_rd_2 != NULL) { GNUNET_free ((void *)s_rd_2->data); GNUNET_free (s_rd_2); } if (s_rd_3 != NULL) { GNUNET_free ((void *)s_rd_3->data); GNUNET_free (s_rd_3); } if (nsh != NULL) GNUNET_NAMESTORE_disconnect (nsh, GNUNET_YES); nsh = NULL; if (NULL != arm) stop_arm(); } void zone_proc (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *name, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { int failed = GNUNET_NO; if ((zone_key == NULL) && (name == NULL)) { GNUNET_break (3 == returned_records); if (3 == returned_records) res = 0; else res = 1; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received last result, iteration done after receing %u results\n",returned_records ); GNUNET_SCHEDULER_add_now (&end, NULL); } else { /* verify signature returned from name store */ if (GNUNET_OK != GNUNET_NAMESTORE_verify_signature (zone_key, expire, name, rd_count, rd, signature)) { GNUNET_HashCode zone_key_hash; GNUNET_CRYPTO_hash (zone_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &zone_key_hash); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Verifying signature for `%s' in zone `%s' with %u records and expiration %llu failed\n", name, GNUNET_h2s(&zone_key_hash), rd_count, expire.abs_value); failed = GNUNET_YES; GNUNET_break (0); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Comparing results name %s \n", name); if (0 == strcmp (name, s_name_1)) { if (rd_count == 1) { if (GNUNET_YES != GNUNET_NAMESTORE_records_cmp(rd, s_rd_1)) { failed = GNUNET_YES; GNUNET_break (0); } } else { failed = GNUNET_YES; GNUNET_break (0); } if (0 != memcmp (signature, sig_1, sizeof (struct GNUNET_CRYPTO_RsaSignature))) { failed = GNUNET_YES; GNUNET_break (0); } } else if (0 == strcmp (name, s_name_2)) { if (rd_count == 1) { if (GNUNET_YES != GNUNET_NAMESTORE_records_cmp(rd, s_rd_2)) { failed = GNUNET_YES; GNUNET_break (0); } } else { failed = GNUNET_YES; GNUNET_break (0); } if (0 != memcmp (signature, sig_2, sizeof (struct GNUNET_CRYPTO_RsaSignature))) { failed = GNUNET_YES; GNUNET_break (0); } } else if (0 == strcmp (name, s_name_3)) { if (rd_count == 1) { if (GNUNET_YES != GNUNET_NAMESTORE_records_cmp(rd, s_rd_3)) { failed = GNUNET_YES; GNUNET_break (0); } } else { failed = GNUNET_YES; GNUNET_break (0); } if (GNUNET_OK != GNUNET_NAMESTORE_verify_signature(zone_key, expire, name, rd_count, rd, signature)) { failed = GNUNET_YES; GNUNET_break (0); } if (0 != memcmp (signature, sig_3, sizeof (struct GNUNET_CRYPTO_RsaSignature))) { failed = GNUNET_YES; GNUNET_break (0); } } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Comparing result failed: got name `%s'\n", name); res = 1; GNUNET_break (0); GNUNET_SCHEDULER_add_now (&end, NULL); } if (failed == GNUNET_NO) { returned_records ++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Telling namestore to send the next result\n"); GNUNET_NAMESTORE_zone_iterator_next (zi); } else { GNUNET_break (0); GNUNET_SCHEDULER_add_now (&end, NULL); } } } void delete_existing_db (const struct GNUNET_CONFIGURATION_Handle *cfg) { char *afsdir; if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, "namestore-sqlite", "FILENAME", &afsdir)) { if (GNUNET_OK == GNUNET_DISK_file_test (afsdir)) if (GNUNET_OK == GNUNET_DISK_file_test (afsdir)) if (GNUNET_OK == GNUNET_DISK_directory_remove(afsdir)) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleted existing database `%s' \n", afsdir); GNUNET_free (afsdir); } } void put_cont (void *cls, int32_t success, const char *emsg) { static int c = 0; if (success == GNUNET_OK) { c++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created record %u \n", c); } else { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to created records\n"); GNUNET_break (0); GNUNET_SCHEDULER_cancel (endbadly_task); endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL); } if (c == 3) { res = 1; returned_records = 0; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All records created, starting iteration over all zones \n"); zi = GNUNET_NAMESTORE_zone_iteration_start(nsh, NULL, GNUNET_NAMESTORE_RF_NONE, GNUNET_NAMESTORE_RF_NONE, zone_proc, &zone); if (zi == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to create zone iterator\n"); GNUNET_break (0); GNUNET_SCHEDULER_cancel (endbadly_task); endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL); } } } static struct GNUNET_NAMESTORE_RecordData * create_record (int count) { int c; struct GNUNET_NAMESTORE_RecordData * rd; rd = GNUNET_malloc (count * sizeof (struct GNUNET_NAMESTORE_RecordData)); for (c = 0; c < count; c++) { rd[c].expiration = GNUNET_TIME_absolute_get(); rd[c].record_type = 1111; rd[c].data_size = 50; rd[c].data = GNUNET_malloc(50); memset ((char *) rd[c].data, 'a', 50); } return rd; } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { delete_existing_db(cfg); endbadly_task = GNUNET_SCHEDULER_add_delayed(TIMEOUT,&endbadly, NULL); char *hostkey_file; GNUNET_asprintf(&hostkey_file,"zonefiles%s%s",DIR_SEPARATOR_STR, "N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using zonekey file `%s' \n", hostkey_file); privkey = GNUNET_CRYPTO_rsa_key_create_from_file(hostkey_file); GNUNET_free (hostkey_file); GNUNET_assert (privkey != NULL); GNUNET_CRYPTO_rsa_key_get_public(privkey, &pubkey); GNUNET_CRYPTO_hash(&pubkey, sizeof (pubkey), &zone); GNUNET_asprintf(&hostkey_file,"zonefiles%s%s",DIR_SEPARATOR_STR, "HGU0A0VCU334DN7F2I9UIUMVQMM7JMSD142LIMNUGTTV9R0CF4EG.zkey"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using zonekey file `%s' \n", hostkey_file); privkey2 = GNUNET_CRYPTO_rsa_key_create_from_file(hostkey_file); GNUNET_free (hostkey_file); GNUNET_assert (privkey2 != NULL); GNUNET_CRYPTO_rsa_key_get_public(privkey2, &pubkey2); GNUNET_CRYPTO_hash(&pubkey2, sizeof (pubkey), &zone2); start_arm (cfgfile); GNUNET_assert (arm != NULL); nsh = GNUNET_NAMESTORE_connect (cfg); GNUNET_break (NULL != nsh); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created record 1\n"); GNUNET_asprintf(&s_name_1, "dummy1"); s_rd_1 = create_record(1); sig_1 = GNUNET_NAMESTORE_create_signature(privkey, s_rd_1->expiration, s_name_1, s_rd_1, 1); GNUNET_NAMESTORE_record_create(nsh, privkey, s_name_1, s_rd_1, &put_cont, NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created record 2 \n"); GNUNET_asprintf(&s_name_2, "dummy2"); s_rd_2 = create_record(1); sig_2 = GNUNET_NAMESTORE_create_signature(privkey, s_rd_2->expiration, s_name_2, s_rd_2, 1); GNUNET_NAMESTORE_record_create(nsh, privkey, s_name_2, s_rd_2, &put_cont, NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created record 3\n"); /* name in different zone */ GNUNET_asprintf(&s_name_3, "dummy3"); s_rd_3 = create_record(1); sig_3 = GNUNET_NAMESTORE_create_signature(privkey2, s_rd_3->expiration, s_name_3, s_rd_3, 1); GNUNET_NAMESTORE_record_put (nsh, &pubkey2, s_name_3, GNUNET_TIME_UNIT_FOREVER_ABS, 1, s_rd_3, sig_3, &put_cont, NULL); } static int check () { static char *const argv[] = { "test_namestore_api_zone_iteration", "-c", "test_namestore_api.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; res = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test_namestore_api_zone_iteration", "nohelp", options, &run, &res); return res; } int main (int argc, char *argv[]) { int ret; ret = check (); return ret; } /* end of test_namestore_api_zone_iteration.c */ gnunet-0.9.3/src/namestore/namestore_common.c0000644000175000017500000003627311760502550016255 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file namestore/namestore_common.c * @brief API to access the NAMESTORE service * @author Martin Schanzenbach * @author Matthias Wachs */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_constants.h" #include "gnunet_signatures.h" #include "gnunet_arm_service.h" #include "gnunet_namestore_service.h" #include "gnunet_dnsparser_lib.h" #include "namestore.h" #define LOG(kind,...) GNUNET_log_from (kind, "gns-api",__VA_ARGS__) /** * Internal format of a record in the serialized form. */ struct NetworkRecord { /** * Expiration time for the DNS record. */ struct GNUNET_TIME_AbsoluteNBO expiration; /** * Number of bytes in 'data', network byte order. */ uint32_t data_size; /** * Type of the GNS/DNS record, network byte order. */ uint32_t record_type; /** * Flags for the record, network byte order. */ uint32_t flags; }; /** * Convert a short hash to a string (for printing debug messages). * This is one of the very few calls in the entire API that is * NOT reentrant! * * @param hc the short hash code * @return string form; will be overwritten by next call to GNUNET_h2s. */ const char * GNUNET_short_h2s (const struct GNUNET_CRYPTO_ShortHashCode * hc) { static struct GNUNET_CRYPTO_ShortHashAsciiEncoded ret; GNUNET_CRYPTO_short_hash_to_enc (hc, &ret); return (const char *) &ret; } /** * Calculate how many bytes we will need to serialize the given * records. * * @param rd_count number of records in the rd array * @param rd array of GNUNET_NAMESTORE_RecordData with rd_count elements * * @return the required size to serialize * */ size_t GNUNET_NAMESTORE_records_get_size (unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd) { unsigned int i; size_t ret; ret = sizeof (struct NetworkRecord) * rd_count; for (i=0;i= ret); ret += rd[i].data_size; } return ret; } /** * Serialize the given records to the given destination buffer. * * @param rd_count number of records in the rd array * @param rd array of GNUNET_NAMESTORE_RecordData with rd_count elements * @param dest_size size of the destination array * @param dest where to write the result * * @return the size of serialized records */ ssize_t GNUNET_NAMESTORE_records_serialize (unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, size_t dest_size, char *dest) { struct NetworkRecord rec; unsigned int i; size_t off; off = 0; for (i=0;i dest_size) return -1; memcpy (&dest[off], &rec, sizeof (rec)); off += sizeof (rec); if (off + rd[i].data_size > dest_size) return -1; memcpy (&dest[off], rd[i].data, rd[i].data_size); off += rd[i].data_size; } return off; } /** * Compares if two records are equal * * @param a record * @param b record * * @return GNUNET_YES or GNUNET_NO */ int GNUNET_NAMESTORE_records_cmp (const struct GNUNET_NAMESTORE_RecordData *a, const struct GNUNET_NAMESTORE_RecordData *b) { if ((a->record_type == b->record_type) && (a->expiration.abs_value == b->expiration.abs_value) && (a->data_size == b->data_size) && (0 == memcmp (a->data, b->data, a->data_size))) return GNUNET_YES; else return GNUNET_NO; } /** * Deserialize the given records to the given destination. * * @param len size of the serialized record data * @param src the serialized record data * @param rd_count number of records in the rd array * @param dest where to put the data * * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_NAMESTORE_records_deserialize (size_t len, const char *src, unsigned int rd_count, struct GNUNET_NAMESTORE_RecordData *dest) { struct NetworkRecord rec; unsigned int i; size_t off; off = 0; for (i=0;i len) return GNUNET_SYSERR; memcpy (&rec, &src[off], sizeof (rec)); dest[i].expiration = GNUNET_TIME_absolute_ntoh (rec.expiration); dest[i].data_size = ntohl ((uint32_t) rec.data_size); dest[i].record_type = ntohl (rec.record_type); dest[i].flags = ntohl (rec.flags); off += sizeof (rec); if (off + dest[i].data_size > len) return GNUNET_SYSERR; dest[i].data = &src[off]; off += dest[i].data_size; } return GNUNET_OK; } /** * Sign name and records * * @param key the private key * @param expire block expiration * @param name the name * @param rd record data * @param rd_count number of records * * @return the signature */ struct GNUNET_CRYPTO_RsaSignature * GNUNET_NAMESTORE_create_signature (const struct GNUNET_CRYPTO_RsaPrivateKey *key, struct GNUNET_TIME_Absolute expire, const char *name, const struct GNUNET_NAMESTORE_RecordData *rd, unsigned int rd_count) { struct GNUNET_CRYPTO_RsaSignature *sig = GNUNET_malloc(sizeof (struct GNUNET_CRYPTO_RsaSignature)); struct GNUNET_CRYPTO_RsaSignaturePurpose *sig_purpose; struct GNUNET_TIME_AbsoluteNBO expire_nbo = GNUNET_TIME_absolute_hton(expire); size_t rd_ser_len; size_t name_len; struct GNUNET_TIME_AbsoluteNBO *expire_tmp; char * name_tmp; char * rd_tmp; int res; if (name == NULL) { GNUNET_break (0); GNUNET_free (sig); return NULL; } name_len = strlen (name) + 1; rd_ser_len = GNUNET_NAMESTORE_records_get_size(rd_count, rd); char rd_ser[rd_ser_len]; GNUNET_NAMESTORE_records_serialize(rd_count, rd, rd_ser_len, rd_ser); sig_purpose = GNUNET_malloc(sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + rd_ser_len + name_len); sig_purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose)+ rd_ser_len + name_len); sig_purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); expire_tmp = (struct GNUNET_TIME_AbsoluteNBO *) &sig_purpose[1]; name_tmp = (char *) &expire_tmp[1]; rd_tmp = &name_tmp[name_len]; memcpy (expire_tmp, &expire_nbo, sizeof (struct GNUNET_TIME_AbsoluteNBO)); memcpy (name_tmp, name, name_len); memcpy (rd_tmp, rd_ser, rd_ser_len); res = GNUNET_CRYPTO_rsa_sign (key, sig_purpose, sig); GNUNET_free (sig_purpose); if (GNUNET_OK != res) { GNUNET_break (0); GNUNET_free (sig); return NULL; } return sig; } /** * Checks if a name is wellformed * * @param name the name to check * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_NAMESTORE_check_name (const char * name) { if (name == NULL) return GNUNET_SYSERR; if (strlen (name) > 63) return GNUNET_SYSERR; return GNUNET_OK; } /** * Convert the 'value' of a record to a string. * * @param type type of the record * @param data value in binary encoding * @param data_size number of bytes in data * @return NULL on error, otherwise human-readable representation of the value */ char * GNUNET_NAMESTORE_value_to_string (uint32_t type, const void *data, size_t data_size) { char tmp[INET6_ADDRSTRLEN]; struct GNUNET_CRYPTO_ShortHashAsciiEncoded enc; uint16_t mx_pref; char* result; char* soa_rname; char* soa_mname; uint32_t* soa_data; uint32_t soa_serial; uint32_t soa_refresh; uint32_t soa_retry; uint32_t soa_expire; uint32_t soa_min; switch (type) { case 0: return NULL; case GNUNET_DNSPARSER_TYPE_A: if (data_size != sizeof (struct in_addr)) return NULL; if (NULL == inet_ntop (AF_INET, data, tmp, sizeof (tmp))) return NULL; return GNUNET_strdup (tmp); case GNUNET_DNSPARSER_TYPE_NS: return GNUNET_strndup (data, data_size); case GNUNET_DNSPARSER_TYPE_CNAME: return GNUNET_strndup (data, data_size); case GNUNET_DNSPARSER_TYPE_SOA: soa_rname = (char*)data; soa_mname = (char*)data+strlen(soa_rname)+1; soa_data = (uint32_t*)(soa_mname+strlen(soa_mname)+1); soa_serial = ntohl(soa_data[0]); soa_refresh = ntohl(soa_data[1]); soa_retry = ntohl(soa_data[2]); soa_expire = ntohl(soa_data[3]); soa_min = ntohl(soa_data[4]); if (GNUNET_asprintf(&result, "rname=%s mname=%s %lu,%lu,%lu,%lu,%lu", soa_rname, soa_mname, soa_serial, soa_refresh, soa_retry, soa_expire, soa_min)) return result; else return NULL; case GNUNET_DNSPARSER_TYPE_PTR: return GNUNET_strndup (data, data_size); case GNUNET_DNSPARSER_TYPE_MX: mx_pref = ntohs(*((uint16_t*)data)); if (GNUNET_asprintf(&result, "%hu,%s", mx_pref, data+sizeof(uint16_t)) != 0) return result; else return NULL; case GNUNET_DNSPARSER_TYPE_TXT: return GNUNET_strndup (data, data_size); case GNUNET_DNSPARSER_TYPE_AAAA: if (data_size != sizeof (struct in6_addr)) return NULL; if (NULL == inet_ntop (AF_INET6, data, tmp, sizeof (tmp))) return NULL; return GNUNET_strdup (tmp); case GNUNET_NAMESTORE_TYPE_PKEY: if (data_size != sizeof (struct GNUNET_CRYPTO_ShortHashCode)) return NULL; GNUNET_CRYPTO_short_hash_to_enc (data, &enc); return GNUNET_strdup ((const char*) enc.short_encoding); case GNUNET_NAMESTORE_TYPE_PSEU: return GNUNET_strndup (data, data_size); case GNUNET_NAMESTORE_TYPE_LEHO: return GNUNET_strndup (data, data_size); default: GNUNET_break (0); } GNUNET_break (0); // not implemented return NULL; } /** * Convert human-readable version of a 'value' of a record to the binary * representation. * * @param type type of the record * @param s human-readable string * @param data set to value in binary encoding (will be allocated) * @param data_size set to number of bytes in data * @return GNUNET_OK on success */ int GNUNET_NAMESTORE_string_to_value (uint32_t type, const char *s, void **data, size_t *data_size) { struct in_addr value_a; struct in6_addr value_aaaa; struct GNUNET_CRYPTO_ShortHashCode pkey; uint16_t mx_pref; uint16_t mx_pref_n; uint32_t soa_data[5]; char result[253]; char soa_rname[63]; char soa_mname[63]; uint32_t soa_serial; uint32_t soa_refresh; uint32_t soa_retry; uint32_t soa_expire; uint32_t soa_min; switch (type) { case 0: return GNUNET_SYSERR; case GNUNET_DNSPARSER_TYPE_A: if (1 != inet_pton (AF_INET, s, &value_a)) return GNUNET_SYSERR; *data = GNUNET_malloc (sizeof (struct in_addr)); memcpy (*data, &value_a, sizeof (value_a)); *data_size = sizeof (value_a); return GNUNET_OK; case GNUNET_DNSPARSER_TYPE_NS: *data = GNUNET_strdup (s); *data_size = strlen (s); return GNUNET_OK; case GNUNET_DNSPARSER_TYPE_CNAME: *data = GNUNET_strdup (s); *data_size = strlen (s); return GNUNET_OK; case GNUNET_DNSPARSER_TYPE_SOA: if (SSCANF(s, "rname=%s mname=%s %u,%u,%u,%u,%u", soa_rname, soa_mname, &soa_serial, &soa_refresh, &soa_retry, &soa_expire, &soa_min) != 7) return GNUNET_SYSERR; *data_size = sizeof (soa_data)+strlen(soa_rname)+strlen(soa_mname)+2; *data = GNUNET_malloc (*data_size); soa_data[0] = htonl(soa_serial); soa_data[1] = htonl(soa_refresh); soa_data[2] = htonl(soa_retry); soa_data[3] = htonl(soa_expire); soa_data[4] = htonl(soa_min); strcpy(*data, soa_rname); strcpy(*data+strlen(*data)+1, soa_mname); memcpy(*data+strlen(*data)+1+strlen(soa_mname)+1, soa_data, sizeof(soa_data)); return GNUNET_OK; case GNUNET_DNSPARSER_TYPE_PTR: *data = GNUNET_strdup (s); *data_size = strlen (s); return GNUNET_OK; case GNUNET_DNSPARSER_TYPE_MX: if (SSCANF(s, "%hu,%s", &mx_pref, result) != 2) return GNUNET_SYSERR; *data_size = sizeof (uint16_t)+strlen(result)+1; *data = GNUNET_malloc (*data_size); mx_pref_n = htons(mx_pref); memcpy(*data, &mx_pref_n, sizeof (uint16_t)); strcpy((*data)+sizeof (uint16_t), result); return GNUNET_OK; case GNUNET_DNSPARSER_TYPE_TXT: *data = GNUNET_strdup (s); *data_size = strlen (s); return GNUNET_OK; case GNUNET_DNSPARSER_TYPE_AAAA: if (1 != inet_pton (AF_INET6, s, &value_aaaa)) return GNUNET_SYSERR; *data = GNUNET_malloc (sizeof (struct in6_addr)); *data_size = sizeof (struct in6_addr); memcpy (*data, &value_aaaa, sizeof (value_aaaa)); return GNUNET_OK; case GNUNET_NAMESTORE_TYPE_PKEY: if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string (s, &pkey)) return GNUNET_SYSERR; *data = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_ShortHashCode)); memcpy (*data, &pkey, sizeof (pkey)); *data_size = sizeof (struct GNUNET_CRYPTO_ShortHashCode); return GNUNET_OK; case GNUNET_NAMESTORE_TYPE_PSEU: *data = GNUNET_strdup (s); *data_size = strlen (s); return GNUNET_OK; case GNUNET_NAMESTORE_TYPE_LEHO: *data = GNUNET_strdup (s); *data_size = strlen (s); return GNUNET_OK; default: GNUNET_break (0); } return GNUNET_SYSERR; } static struct { const char *name; uint32_t number; } name_map[] = { { "A", GNUNET_DNSPARSER_TYPE_A }, { "NS", GNUNET_DNSPARSER_TYPE_NS }, { "CNAME", GNUNET_DNSPARSER_TYPE_CNAME }, { "SOA", GNUNET_DNSPARSER_TYPE_SOA }, { "PTR", GNUNET_DNSPARSER_TYPE_PTR }, { "MX", GNUNET_DNSPARSER_TYPE_MX }, { "TXT", GNUNET_DNSPARSER_TYPE_TXT }, { "AAAA", GNUNET_DNSPARSER_TYPE_AAAA }, { "PKEY", GNUNET_NAMESTORE_TYPE_PKEY }, { "PSEU", GNUNET_NAMESTORE_TYPE_PSEU }, { "LEHO", GNUNET_NAMESTORE_TYPE_LEHO }, { NULL, UINT32_MAX } }; /** * Convert a type name (i.e. "AAAA") to the corresponding number. * * @param typename name to convert * @return corresponding number, UINT32_MAX on error */ uint32_t GNUNET_NAMESTORE_typename_to_number (const char *typename) { unsigned int i; i=0; while ( (name_map[i].name != NULL) && (0 != strcasecmp (typename, name_map[i].name)) ) i++; return name_map[i].number; } /** * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A") * * @param type number of a type to convert * @return corresponding typestring, NULL on error */ const char * GNUNET_NAMESTORE_number_to_typename (uint32_t type) { unsigned int i; i=0; while ( (name_map[i].name != NULL) && (type != name_map[i].number) ) i++; return name_map[i].name; } /* end of namestore_common.c */ gnunet-0.9.3/src/core/0000755000175000017500000000000011763406750011554 500000000000000gnunet-0.9.3/src/core/gnunet-service-core_sessions.c0000644000175000017500000005740011760502550017450 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file core/gnunet-service-core_sessions.c * @brief code for managing of 'encrypted' sessions (key exchange done) * @author Christian Grothoff */ #include "platform.h" #include "gnunet-service-core.h" #include "gnunet-service-core_neighbours.h" #include "gnunet-service-core_kx.h" #include "gnunet-service-core_typemap.h" #include "gnunet-service-core_sessions.h" #include "gnunet-service-core_clients.h" #include "gnunet_constants.h" /** * How often do we transmit our typemap? */ #define TYPEMAP_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) /** * Message ready for encryption. This struct is followed by the * actual content of the message. */ struct SessionMessageEntry { /** * We keep messages in a doubly linked list. */ struct SessionMessageEntry *next; /** * We keep messages in a doubly linked list. */ struct SessionMessageEntry *prev; /** * Deadline for transmission, 1s after we received it (if we * are not corking), otherwise "now". Note that this message * does NOT expire past its deadline. */ struct GNUNET_TIME_Absolute deadline; /** * How long is the message? (number of bytes following the "struct * MessageEntry", but not including the size of "struct * MessageEntry" itself!) */ size_t size; }; /** * Data kept per session. */ struct Session { /** * Identity of the other peer. */ struct GNUNET_PeerIdentity peer; /** * Head of list of requests from clients for transmission to * this peer. */ struct GSC_ClientActiveRequest *active_client_request_head; /** * Tail of list of requests from clients for transmission to * this peer. */ struct GSC_ClientActiveRequest *active_client_request_tail; /** * Head of list of messages ready for encryption. */ struct SessionMessageEntry *sme_head; /** * Tail of list of messages ready for encryption. */ struct SessionMessageEntry *sme_tail; /** * Information about the key exchange with the other peer. */ struct GSC_KeyExchangeInfo *kxinfo; /** * Current type map for this peer. */ struct GSC_TypeMap *tmap; /** * At what time did we initially establish this session? * (currently unused, should be integrated with ATS in the * future...). */ struct GNUNET_TIME_Absolute time_established; /** * Task to transmit corked messages with a delay. */ GNUNET_SCHEDULER_TaskIdentifier cork_task; /** * Task to transmit our type map. */ GNUNET_SCHEDULER_TaskIdentifier typemap_task; /** * Is the neighbour queue empty and thus ready for us * to transmit an encrypted message? */ int ready_to_transmit; }; /** * Map of peer identities to 'struct Session'. */ static struct GNUNET_CONTAINER_MultiHashMap *sessions; /** * Find the session for the given peer. * * @param peer identity of the peer * @return NULL if we are not connected, otherwise the * session handle */ static struct Session * find_session (const struct GNUNET_PeerIdentity *peer) { return GNUNET_CONTAINER_multihashmap_get (sessions, &peer->hashPubKey); } /** * End the session with the given peer (we are no longer * connected). * * @param pid identity of peer to kill session with */ void GSC_SESSIONS_end (const struct GNUNET_PeerIdentity *pid) { struct Session *session; struct GSC_ClientActiveRequest *car; struct SessionMessageEntry *sme; session = find_session (pid); if (NULL == session) return; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Destroying session for peer `%4s'\n", GNUNET_i2s (&session->peer)); if (GNUNET_SCHEDULER_NO_TASK != session->cork_task) { GNUNET_SCHEDULER_cancel (session->cork_task); session->cork_task = GNUNET_SCHEDULER_NO_TASK; } while (NULL != (car = session->active_client_request_head)) { GNUNET_CONTAINER_DLL_remove (session->active_client_request_head, session->active_client_request_tail, car); GSC_CLIENTS_reject_request (car); } while (NULL != (sme = session->sme_head)) { GNUNET_CONTAINER_DLL_remove (session->sme_head, session->sme_tail, sme); GNUNET_free (sme); } GNUNET_SCHEDULER_cancel (session->typemap_task); GSC_CLIENTS_notify_clients_about_neighbour (&session->peer, NULL, 0 /* FIXME: ATSI */ , session->tmap, NULL); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (sessions, &session-> peer.hashPubKey, session)); GNUNET_STATISTICS_set (GSC_stats, gettext_noop ("# peers connected"), GNUNET_CONTAINER_multihashmap_size (sessions), GNUNET_NO); GSC_TYPEMAP_destroy (session->tmap); session->tmap = NULL; GNUNET_free (session); } /** * Transmit our current typemap message to the other peer. * (Done periodically in case an update got lost). * * @param cls the 'struct Session*' * @param tc unused */ static void transmit_typemap_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Session *session = cls; struct GNUNET_MessageHeader *hdr; struct GNUNET_TIME_Relative delay; delay = TYPEMAP_FREQUENCY; /* randomize a bit to avoid spont. sync */ delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000); session->typemap_task = GNUNET_SCHEDULER_add_delayed (delay, &transmit_typemap_task, session); GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# type map refreshes sent"), 1, GNUNET_NO); hdr = GSC_TYPEMAP_compute_type_map_message (); GSC_KX_encrypt_and_transmit (session->kxinfo, hdr, ntohs (hdr->size)); GNUNET_free (hdr); } /** * Create a session, a key exchange was just completed. * * @param peer peer that is now connected * @param kx key exchange that completed */ void GSC_SESSIONS_create (const struct GNUNET_PeerIdentity *peer, struct GSC_KeyExchangeInfo *kx) { struct Session *session; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating session for peer `%4s'\n", GNUNET_i2s (peer)); session = GNUNET_malloc (sizeof (struct Session)); session->tmap = GSC_TYPEMAP_create (); session->peer = *peer; session->kxinfo = kx; session->time_established = GNUNET_TIME_absolute_get (); session->typemap_task = GNUNET_SCHEDULER_add_now (&transmit_typemap_task, session); GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (sessions, &peer->hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); GNUNET_STATISTICS_set (GSC_stats, gettext_noop ("# peers connected"), GNUNET_CONTAINER_multihashmap_size (sessions), GNUNET_NO); GSC_CLIENTS_notify_clients_about_neighbour (peer, NULL, 0 /* FIXME: ATSI */ , NULL, session->tmap); } /** * Notify the given client about the session (client is new). * * @param cls the 'struct GSC_Client' * @param key peer identity * @param value the 'struct Session' * @return GNUNET_OK (continue to iterate) */ static int notify_client_about_session (void *cls, const GNUNET_HashCode * key, void *value) { struct GSC_Client *client = cls; struct Session *session = value; GSC_CLIENTS_notify_client_about_neighbour (client, &session->peer, NULL, 0, /* FIXME: ATS!? */ NULL, /* old TMAP: none */ session->tmap); return GNUNET_OK; } /** * We have a new client, notify it about all current sessions. * * @param client the new client */ void GSC_SESSIONS_notify_client_about_sessions (struct GSC_Client *client) { /* notify new client about existing sessions */ GNUNET_CONTAINER_multihashmap_iterate (sessions, ¬ify_client_about_session, client); } /** * Try to perform a transmission on the given session. Will solicit * additional messages if the 'sme' queue is not full enough. * * @param session session to transmit messages from */ static void try_transmission (struct Session *session); /** * Queue a request from a client for transmission to a particular peer. * * @param car request to queue; this handle is then shared between * the caller (CLIENTS subsystem) and SESSIONS and must not * be released by either until either 'GNUNET_SESSIONS_dequeue', * 'GNUNET_SESSIONS_transmit' or 'GNUNET_CLIENTS_failed' * have been invoked on it */ void GSC_SESSIONS_queue_request (struct GSC_ClientActiveRequest *car) { struct Session *session; session = find_session (&car->target); if (session == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Dropped client request for transmission (am disconnected)\n"); GNUNET_break (0); /* should have been rejected earlier */ GSC_CLIENTS_reject_request (car); return; } if (car->msize > GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE) { GNUNET_break (0); GSC_CLIENTS_reject_request (car); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received client transmission request. queueing\n"); GNUNET_CONTAINER_DLL_insert (session->active_client_request_head, session->active_client_request_tail, car); try_transmission (session); } /** * Dequeue a request from a client from transmission to a particular peer. * * @param car request to dequeue; this handle will then be 'owned' by * the caller (CLIENTS sysbsystem) */ void GSC_SESSIONS_dequeue_request (struct GSC_ClientActiveRequest *car) { struct Session *s; if (0 == memcmp (&car->target, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity))) return; s = find_session (&car->target); GNUNET_assert (NULL != s); GNUNET_CONTAINER_DLL_remove (s->active_client_request_head, s->active_client_request_tail, car); } /** * Discard all expired active transmission requests from clients. * * @param session session to clean up */ static void discard_expired_requests (struct Session *session) { struct GSC_ClientActiveRequest *pos; struct GSC_ClientActiveRequest *nxt; struct GNUNET_TIME_Absolute now; now = GNUNET_TIME_absolute_get (); pos = NULL; nxt = session->active_client_request_head; while (NULL != nxt) { pos = nxt; nxt = pos->next; if ((pos->deadline.abs_value < now.abs_value) && (GNUNET_YES != pos->was_solicited)) { GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# messages discarded (expired prior to transmission)"), 1, GNUNET_NO); GNUNET_CONTAINER_DLL_remove (session->active_client_request_head, session->active_client_request_tail, pos); GSC_CLIENTS_reject_request (pos); } } } /** * Solicit messages for transmission. * * @param session session to solict messages for */ static void solicit_messages (struct Session *session) { struct GSC_ClientActiveRequest *car; struct GSC_ClientActiveRequest *nxt; size_t so_size; discard_expired_requests (session); so_size = 0; nxt = session->active_client_request_head; while (NULL != (car = nxt)) { nxt = car->next; if (so_size + car->msize > GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE) break; so_size += car->msize; if (car->was_solicited == GNUNET_YES) continue; car->was_solicited = GNUNET_YES; GSC_CLIENTS_solicit_request (car); } } /** * Some messages were delayed (corked), but the timeout has now expired. * Send them now. * * @param cls 'struct Session' with the messages to transmit now * @param tc scheduler context (unused) */ static void pop_cork_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Session *session = cls; session->cork_task = GNUNET_SCHEDULER_NO_TASK; try_transmission (session); } /** * Try to perform a transmission on the given session. Will solicit * additional messages if the 'sme' queue is not full enough. * * @param session session to transmit messages from */ static void try_transmission (struct Session *session) { struct SessionMessageEntry *pos; size_t msize; struct GNUNET_TIME_Absolute now; struct GNUNET_TIME_Absolute min_deadline; if (GNUNET_YES != session->ready_to_transmit) return; msize = 0; min_deadline = GNUNET_TIME_UNIT_FOREVER_ABS; /* check 'ready' messages */ pos = session->sme_head; while ((NULL != pos) && (msize + pos->size <= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)) { GNUNET_assert (pos->size < GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE); msize += pos->size; min_deadline = GNUNET_TIME_absolute_min (min_deadline, pos->deadline); pos = pos->next; } now = GNUNET_TIME_absolute_get (); if ((msize == 0) || ((msize < GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE / 2) && (min_deadline.abs_value > now.abs_value))) { /* not enough ready yet, try to solicit more */ solicit_messages (session); if (msize > 0) { /* if there is data to send, just not yet, make sure we do transmit * it once the deadline is reached */ if (session->cork_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (session->cork_task); session->cork_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (min_deadline), &pop_cork_task, session); } return; } /* create plaintext buffer of all messages, encrypt and transmit */ { static unsigned long long total_bytes; static unsigned int total_msgs; char pbuf[msize]; /* plaintext */ size_t used; used = 0; while ((NULL != (pos = session->sme_head)) && (used + pos->size <= msize)) { memcpy (&pbuf[used], &pos[1], pos->size); used += pos->size; GNUNET_CONTAINER_DLL_remove (session->sme_head, session->sme_tail, pos); GNUNET_free (pos); } /* compute average payload size */ total_bytes += used; total_msgs++; if (0 == total_msgs) { /* 2^32 messages, wrap around... */ total_msgs = 1; total_bytes = used; } GNUNET_STATISTICS_set (GSC_stats, "# avg payload per encrypted message", total_bytes / total_msgs, GNUNET_NO); /* now actually transmit... */ session->ready_to_transmit = GNUNET_NO; GSC_KX_encrypt_and_transmit (session->kxinfo, pbuf, used); } } /** * Send a message to the neighbour now. * * @param cls the message * @param key neighbour's identity * @param value 'struct Neighbour' of the target * @return always GNUNET_OK */ static int do_send_message (void *cls, const GNUNET_HashCode * key, void *value) { const struct GNUNET_MessageHeader *hdr = cls; struct Session *session = value; struct SessionMessageEntry *m; uint16_t size; size = ntohs (hdr->size); m = GNUNET_malloc (sizeof (struct SessionMessageEntry) + size); memcpy (&m[1], hdr, size); m->size = size; GNUNET_CONTAINER_DLL_insert (session->sme_head, session->sme_tail, m); try_transmission (session); return GNUNET_OK; } /** * Broadcast a message to all neighbours. * * @param msg message to transmit */ void GSC_SESSIONS_broadcast (const struct GNUNET_MessageHeader *msg) { if (NULL == sessions) return; GNUNET_CONTAINER_multihashmap_iterate (sessions, &do_send_message, (void *) msg); } /** * Traffic is being solicited for the given peer. This means that the * message queue on the transport-level (NEIGHBOURS subsystem) is now * empty and it is now OK to transmit another (non-control) message. * * @param pid identity of peer ready to receive data */ void GSC_SESSIONS_solicit (const struct GNUNET_PeerIdentity *pid) { struct Session *session; session = find_session (pid); if (NULL == session) return; session->ready_to_transmit = GNUNET_YES; try_transmission (session); } /** * Transmit a message to a particular peer. * * @param car original request that was queued and then solicited; * this handle will now be 'owned' by the SESSIONS subsystem * @param msg message to transmit * @param cork is corking allowed? */ void GSC_SESSIONS_transmit (struct GSC_ClientActiveRequest *car, const struct GNUNET_MessageHeader *msg, int cork) { struct Session *session; struct SessionMessageEntry *sme; size_t msize; session = find_session (&car->target); if (NULL == session) return; msize = ntohs (msg->size); sme = GNUNET_malloc (sizeof (struct SessionMessageEntry) + msize); memcpy (&sme[1], msg, msize); sme->size = msize; if (GNUNET_YES == cork) sme->deadline = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_MAX_CORK_DELAY); GNUNET_CONTAINER_DLL_insert_tail (session->sme_head, session->sme_tail, sme); try_transmission (session); } /** * Helper function for GSC_SESSIONS_handle_client_iterate_peers. * * @param cls the 'struct GNUNET_SERVER_TransmitContext' to queue replies * @param key identity of the connected peer * @param value the 'struct Neighbour' for the peer * @return GNUNET_OK (continue to iterate) */ #include "core.h" static int queue_connect_message (void *cls, const GNUNET_HashCode * key, void *value) { struct GNUNET_SERVER_TransmitContext *tc = cls; struct Session *session = value; struct ConnectNotifyMessage cnm; /* FIXME: code duplication with clients... */ cnm.header.size = htons (sizeof (struct ConnectNotifyMessage)); cnm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT); // FIXME: full ats... cnm.ats_count = htonl (0); cnm.peer = session->peer; GNUNET_SERVER_transmit_context_append_message (tc, &cnm.header); return GNUNET_OK; } /** * Handle CORE_ITERATE_PEERS request. For this request type, the client * does not have to have transmitted an INIT request. All current peers * are returned, regardless of which message types they accept. * * @param cls unused * @param client client sending the iteration request * @param message iteration request message */ void GSC_SESSIONS_handle_client_iterate_peers (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct GNUNET_MessageHeader done_msg; struct GNUNET_SERVER_TransmitContext *tc; tc = GNUNET_SERVER_transmit_context_create (client); GNUNET_CONTAINER_multihashmap_iterate (sessions, &queue_connect_message, tc); done_msg.size = htons (sizeof (struct GNUNET_MessageHeader)); done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END); GNUNET_SERVER_transmit_context_append_message (tc, &done_msg); GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); } /** * Handle CORE_PEER_CONNECTED request. Notify client about connection * to the given neighbour. For this request type, the client does not * have to have transmitted an INIT request. All current peers are * returned, regardless of which message types they accept. * * @param cls unused * @param client client sending the iteration request * @param message iteration request message */ void GSC_SESSIONS_handle_client_have_peer (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct GNUNET_MessageHeader done_msg; struct GNUNET_SERVER_TransmitContext *tc; const struct GNUNET_PeerIdentity *peer; peer = (const struct GNUNET_PeerIdentity *) &message[1]; // YUCK! tc = GNUNET_SERVER_transmit_context_create (client); GNUNET_CONTAINER_multihashmap_get_multiple (sessions, &peer->hashPubKey, &queue_connect_message, tc); done_msg.size = htons (sizeof (struct GNUNET_MessageHeader)); done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END); GNUNET_SERVER_transmit_context_append_message (tc, &done_msg); GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); } /** * We've received a typemap message from a peer, update ours. * Notifies clients about the session. * * @param peer peer this is about * @param msg typemap update message */ void GSC_SESSIONS_set_typemap (const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *msg) { struct Session *session; struct GSC_TypeMap *nmap; nmap = GSC_TYPEMAP_get_from_message (msg); if (NULL == nmap) return; /* malformed */ session = find_session (peer); if (NULL == session) { GNUNET_break (0); return; } GSC_CLIENTS_notify_clients_about_neighbour (peer, NULL, 0, /* FIXME: ATS */ session->tmap, nmap); GSC_TYPEMAP_destroy (session->tmap); session->tmap = nmap; } /** * The given peer send a message of the specified type. Make sure the * respective bit is set in its type-map and that clients are notified * about the session. * * @param peer peer this is about * @param type type of the message */ void GSC_SESSIONS_add_to_typemap (const struct GNUNET_PeerIdentity *peer, uint16_t type) { struct Session *session; struct GSC_TypeMap *nmap; if (0 == memcmp (peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity))) return; session = find_session (peer); GNUNET_assert (NULL != session); if (GNUNET_YES == GSC_TYPEMAP_test_match (session->tmap, &type, 1)) return; /* already in it */ nmap = GSC_TYPEMAP_extend (session->tmap, &type, 1); GSC_CLIENTS_notify_clients_about_neighbour (peer, NULL, 0, /* FIXME: ATS */ session->tmap, nmap); GSC_TYPEMAP_destroy (session->tmap); session->tmap = nmap; } /** * Initialize sessions subsystem. */ void GSC_SESSIONS_init () { sessions = GNUNET_CONTAINER_multihashmap_create (128); } /** * Helper function for GSC_SESSIONS_handle_client_iterate_peers. * * @param cls NULL * @param key identity of the connected peer * @param value the 'struct Session' for the peer * @return GNUNET_OK (continue to iterate) */ static int free_session_helper (void *cls, const GNUNET_HashCode * key, void *value) { struct Session *session = value; GSC_SESSIONS_end (&session->peer); return GNUNET_OK; } /** * Shutdown sessions subsystem. */ void GSC_SESSIONS_done () { GNUNET_CONTAINER_multihashmap_iterate (sessions, &free_session_helper, NULL); GNUNET_CONTAINER_multihashmap_destroy (sessions); sessions = NULL; } /* end of gnunet-service-core_sessions.c */ gnunet-0.9.3/src/core/test_core_api_data.conf0000644000175000017500000000035611665224123016151 00000000000000@INLINE@ test_core_defaults.conf [PATHS] DEFAULTCONFIG = test_core_api_data.conf [arm] DEFAULTSERVICES = topology hostlist [ats] WAN_QUOTA_IN = 64 kiB WAN_QUOTA_OUT = 64 kiB [core] PORT = 2092 UNIXPATH = /tmp/gnunet-service-core.sock gnunet-0.9.3/src/core/test_core_quota_asymmetric_recv_limited_peer2.conf0000644000175000017500000000162211751071052023612 00000000000000@INLINE@ test_core_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-core-quota-asym-recv-lim-peer-2/ DEFAULTCONFIG = test_core_quota_asymmetric_recv_limited_peer2.conf [arm] PORT = 22486 UNIXPATH = /tmp/gnunet-core-asym-recv-p2-service-arm.sock [statistics] PORT = 22487 UNIXPATH = /tmp/gnunet-core-asym-recv-p2-service-statistics.sock [resolver] PORT = 22484 UNIXPATH = /tmp/gnunet-core-asym-recv-p2-service-resolver.sock [peerinfo] PORT = 22489 UNIXPATH = /tmp/gnunet-core-asym-recv-p2-service-peerinfo.sock [transport] PORT = 22485 UNIXPATH = /tmp/gnunet-core-asym-recv-p2-service-transport.sock [core] PORT = 22490 UNIXPATH = /tmp/gnunet-core-asym-recv-p2-service-core.sock DEBUG = NO [ats] PORT = 22491 UNIXPATH = /tmp/gnunet-core-asym-recv-p2-service-ats.sock WAN_QUOTA_IN = 10 kiB WAN_QUOTA_OUT = 10 kiB [transport-tcp] PORT = 22467 [transport-unix] PORT = 22468 [transport-http] PORT = 22469gnunet-0.9.3/src/core/test_core_quota_peer1.conf0000644000175000017500000000141511723125463016633 00000000000000@INLINE@ test_core_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-core-quota-sym-peer-1/ DEFAULTCONFIG = test_core_quota_peer1.conf [transport-tcp] PORT = 12468 [arm] PORT = 12476 UNIXPATH = /tmp/gnunet-core-sym-p1-service-arm.sock [statistics] PORT = 12477 UNIXPATH = /tmp/gnunet-core-sym-p1-service-statistics.sock [resolver] PORT = 12474 UNIXPATH = /tmp/gnunet-core-sym-p1-service-resolver.sock [peerinfo] PORT = 12479 UNIXPATH = /tmp/gnunet-core-sym-p1-service-peerinfo.sock [transport] PORT = 12475 UNIXPATH = /tmp/gnunet-core-sym-p1-service-transport.sock [ats] WAN_QUOTA_IN = 10240 WAN_QUOTA_OUT = 10240 [core] PORT = 12480 UNIXPATH = /tmp/gnunet-core-sym-p1-service-core.sock DEBUG = NO [ats] PORT = 12481 UNIXPATH = /tmp/gnunet-core-sym-p1-service-ats.sock gnunet-0.9.3/src/core/Makefile.am0000644000175000017500000001022511750306136013521 00000000000000INCLUDES = -I$(top_srcdir)/src/include pkgcfgdir= $(pkgdatadir)/config.d/ pkgcfg_DATA = \ core.conf if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIB = -lgcov endif lib_LTLIBRARIES = \ libgnunetcore.la libgnunetcore_la_SOURCES = \ core_api.c core.h \ core_api_iterate_peers.c \ core_api_is_connected.c libgnunetcore_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) $(XLIB) libgnunetcore_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 0:0:0 bin_PROGRAMS = \ gnunet-service-core \ gnunet-core gnunet_service_core_SOURCES = \ gnunet-service-core.c gnunet-service-core.h \ gnunet-service-core_clients.c gnunet-service-core_clients.h \ gnunet-service-core_neighbours.c gnunet-service-core_neighbours.h \ gnunet-service-core_kx.c gnunet-service-core_kx.h \ gnunet-service-core_sessions.c gnunet-service-core_sessions.h \ gnunet-service-core_typemap.c gnunet-service-core_typemap.h gnunet_service_core_LDADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) -lz gnunet_core_SOURCES = \ gnunet-core.c gnunet_core_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la gnunet_core_DEPENDENCIES = \ libgnunetcore.la check_PROGRAMS = \ test_core_api_start_only \ test_core_api \ test_core_api_reliability \ test_core_quota_compliance_symmetric \ test_core_quota_compliance_asymmetric_send_limited \ test_core_quota_compliance_asymmetric_recv_limited \ test_core_api_send_to_self if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) endif test_core_api_SOURCES = \ test_core_api.c test_core_api_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la test_core_api_reliability_SOURCES = \ test_core_api_reliability.c test_core_api_reliability_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la test_core_api_send_to_self_SOURCES = \ test_core_api_send_to_self.c test_core_api_send_to_self_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la test_core_api_start_only_SOURCES = \ test_core_api_start_only.c test_core_api_start_only_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_core_quota_compliance_symmetric_SOURCES = \ test_core_quota_compliance.c test_core_quota_compliance_symmetric_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la test_core_quota_compliance_asymmetric_send_limited_SOURCES = \ test_core_quota_compliance.c test_core_quota_compliance_asymmetric_send_limited_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la test_core_quota_compliance_asymmetric_recv_limited_SOURCES = \ test_core_quota_compliance.c test_core_quota_compliance_asymmetric_recv_limited_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la EXTRA_DIST = \ test_core_defaults.conf \ test_core_api_data.conf \ test_core_api_peer1.conf \ test_core_api_peer2.conf \ test_core_api_send_to_self.conf \ test_core_quota_asymmetric_recv_limited_peer1.conf \ test_core_quota_asymmetric_recv_limited_peer2.conf \ test_core_quota_asymmetric_send_limit_peer1.conf \ test_core_quota_asymmetric_send_limit_peer2.conf \ test_core_quota_peer1.conf \ test_core_quota_peer2.conf gnunet-0.9.3/src/core/test_core_quota_asymmetric_recv_limited_peer1.conf0000644000175000017500000000152011723125421023605 00000000000000@INLINE@ test_core_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-core-quota-asym-recv-lim-peer-1/ DEFAULTCONFIG = test_core_quota_asymmetric_recv_limited_peer1.conf [transport-tcp] PORT = 12488 [arm] PORT = 12486 UNIXPATH = /tmp/gnunet-core-asym-recv-p1-service-arm.sock [statistics] PORT = 12487 UNIXPATH = /tmp/gnunet-core-asym-recv-p1-service-statistics.sock [resolver] PORT = 12484 UNIXPATH = /tmp/gnunet-core-asym-recv-1-service-resolver.sock [peerinfo] PORT = 12489 UNIXPATH = /tmp/gnunet-core-asym-recv-p1-service-peerinfo.sock [transport] PORT = 12485 UNIXPATH = /tmp/gnunet-core-asym-recv-p1-service-transport.sock [ats] PORT = 12491 UNIXPATH = /tmp/gnunet-core-asym-recv-p1-service-ats.sock WAN_QUOTA_IN = 1 MB WAN_QUOTA_OUT = 1 MB [core] PORT = 12490 UNIXPATH = /tmp/gnunet-core-asym-recv-p1-service-core.sock DEBUG = NO gnunet-0.9.3/src/core/gnunet-service-core_clients.c0000644000175000017500000007271711760502550017253 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file core/gnunet-service-core_clients.c * @brief code for managing interactions with clients of core service * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" #include "gnunet-service-core.h" #include "gnunet-service-core_clients.h" #include "gnunet-service-core_sessions.h" #include "gnunet-service-core_typemap.h" #include "core.h" /** * How many messages do we queue up at most for optional * notifications to a client? (this can cause notifications * about outgoing messages to be dropped). */ #define MAX_NOTIFY_QUEUE 1024 /** * Data structure for each client connected to the core service. */ struct GSC_Client { /** * Clients are kept in a linked list. */ struct GSC_Client *next; /** * Clients are kept in a linked list. */ struct GSC_Client *prev; /** * Handle for the client with the server API. */ struct GNUNET_SERVER_Client *client_handle; /** * Array of the types of messages this peer cares * about (with "tcnt" entries). Allocated as part * of this client struct, do not free! */ const uint16_t *types; /** * Map of peer identities to active transmission requests of this * client to the peer (of type 'struct GSC_ClientActiveRequest'). */ struct GNUNET_CONTAINER_MultiHashMap *requests; /** * Map containing all peers that this client knows we're connected to. */ struct GNUNET_CONTAINER_MultiHashMap *connectmap; /** * Options for messages this client cares about, * see GNUNET_CORE_OPTION_ values. */ uint32_t options; /** * Number of types of incoming messages this client * specifically cares about. Size of the "types" array. */ unsigned int tcnt; }; /** * Big "or" of all client options. */ static uint32_t all_client_options; /** * Head of linked list of our clients. */ static struct GSC_Client *client_head; /** * Tail of linked list of our clients. */ static struct GSC_Client *client_tail; /** * Context for notifications we need to send to our clients. */ static struct GNUNET_SERVER_NotificationContext *notifier; /** * Tokenizer for messages received from clients. */ static struct GNUNET_SERVER_MessageStreamTokenizer *client_mst; /** * Lookup our client struct given the server's client handle. * * @param client server client handle to look up * @return our client handle for the client */ static struct GSC_Client * find_client (struct GNUNET_SERVER_Client *client) { struct GSC_Client *c; c = client_head; while ((c != NULL) && (c->client_handle != client)) c = c->next; return c; } /** * Send a message to one of our clients. * * @param client target for the message * @param msg message to transmit * @param can_drop could this message be dropped if the * client's queue is getting too large? */ static void send_to_client (struct GSC_Client *client, const struct GNUNET_MessageHeader *msg, int can_drop) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Preparing to send %u bytes of message of type %u to client.\n", (unsigned int) ntohs (msg->size), (unsigned int) ntohs (msg->type)); GNUNET_SERVER_notification_context_unicast (notifier, client->client_handle, msg, can_drop); } /** * Send a message to one of our clients. * * @param client target for the message * @param msg message to transmit * @param can_drop could this message be dropped if the * client's queue is getting too large? */ void GSC_CLIENTS_send_to_client (struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *msg, int can_drop) { struct GSC_Client *c; c = find_client (client); if (NULL == c) { GNUNET_break (0); return; } send_to_client (c, msg, can_drop); } /** * Test if the client is interested in messages of the given type. * * @param type message type * @param c client to test * @return GNUNET_YES if 'c' is interested, GNUNET_NO if not. */ static int type_match (uint16_t type, struct GSC_Client *c) { unsigned int i; if (c->tcnt == 0) return GNUNET_YES; /* peer without handlers matches ALL */ for (i = 0; i < c->tcnt; i++) if (type == c->types[i]) return GNUNET_YES; return GNUNET_NO; } /** * Send a message to all of our current clients that have the right * options set. * * @param partner origin (or destination) of the message (used to check that this peer is * known to be connected to the respective client) * @param msg message to multicast * @param can_drop can this message be discarded if the queue is too long * @param options mask to use * @param type type of the embedded message, 0 for none */ static void send_to_all_clients (const struct GNUNET_PeerIdentity *partner, const struct GNUNET_MessageHeader *msg, int can_drop, uint32_t options, uint16_t type) { struct GSC_Client *c; int tm; for (c = client_head; c != NULL; c = c->next) { tm = type_match (type, c); if (! ( (0 != (c->options & options)) || ( (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) && (GNUNET_YES == tm) ) ) ) continue; /* neither options nor type match permit the message */ if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)) && ( (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) || (GNUNET_YES == tm) ) ) continue; if ( (0 != (options & GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND)) && (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND)) ) continue; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Sending %u message with %u bytes to client interested in messages of type %u.\n", options, ntohs (msg->size), (unsigned int) type); GNUNET_assert ( (0 == (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) || (GNUNET_YES != tm) || (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (c->connectmap, &partner->hashPubKey)) ); send_to_client (c, msg, can_drop); } } /** * Handle CORE_INIT request. * * @param cls unused * @param client new client that sent INIT * @param message the 'struct InitMessage' (presumably) */ static void handle_client_init (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct InitMessage *im; struct InitReplyMessage irm; struct GSC_Client *c; uint16_t msize; const uint16_t *types; uint16_t *wtypes; unsigned int i; /* check that we don't have an entry already */ c = find_client (client); if (NULL != c) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } msize = ntohs (message->size); if (msize < sizeof (struct InitMessage)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_SERVER_notification_context_add (notifier, client); im = (const struct InitMessage *) message; types = (const uint16_t *) &im[1]; msize -= sizeof (struct InitMessage); c = GNUNET_malloc (sizeof (struct GSC_Client) + msize); c->client_handle = client; c->tcnt = msize / sizeof (uint16_t); c->options = ntohl (im->options); all_client_options |= c->options; c->types = (const uint16_t *) &c[1]; c->connectmap = GNUNET_CONTAINER_multihashmap_create (16); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_put (c->connectmap, &GSC_my_identity.hashPubKey, NULL, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); wtypes = (uint16_t *) & c[1]; for (i = 0; i < c->tcnt; i++) wtypes[i] = ntohs (types[i]); GSC_TYPEMAP_add (wtypes, c->tcnt); GNUNET_CONTAINER_DLL_insert (client_head, client_tail, c); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client connecting to core service is interested in %u message types\n", (unsigned int) c->tcnt); /* send init reply message */ irm.header.size = htons (sizeof (struct InitReplyMessage)); irm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY); irm.reserved = htonl (0); irm.my_identity = GSC_my_identity; send_to_client (c, &irm.header, GNUNET_NO); GSC_SESSIONS_notify_client_about_sessions (c); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Handle CORE_SEND_REQUEST message. * * @param cls unused * @param client new client that sent CORE_SEND_REQUEST * @param message the 'struct SendMessageRequest' (presumably) */ static void handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct SendMessageRequest *req; struct GSC_Client *c; struct GSC_ClientActiveRequest *car; int is_loopback; req = (const struct SendMessageRequest *) message; c = find_client (client); if (c == NULL) { /* client did not send INIT first! */ GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } if (c->requests == NULL) c->requests = GNUNET_CONTAINER_multihashmap_create (16); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client asked for transmission to `%s'\n", GNUNET_i2s (&req->peer)); is_loopback = (0 == memcmp (&req->peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity))); if ((!is_loopback) && (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (c->connectmap, &req->peer.hashPubKey))) { /* neighbour must have disconnected since request was issued, * ignore (client will realize it once it processes the * disconnect notification) */ GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# send requests dropped (disconnected)"), 1, GNUNET_NO); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } car = GNUNET_CONTAINER_multihashmap_get (c->requests, &req->peer.hashPubKey); if (car == NULL) { /* create new entry */ car = GNUNET_malloc (sizeof (struct GSC_ClientActiveRequest)); GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (c->requests, &req->peer.hashPubKey, car, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); car->client_handle = c; } else { GSC_SESSIONS_dequeue_request (car); } car->target = req->peer; car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline); car->priority = ntohl (req->priority); car->msize = ntohs (req->size); car->smr_id = req->smr_id; car->was_solicited = GNUNET_NO; if (is_loopback) { /* loopback, satisfy immediately */ GSC_CLIENTS_solicit_request (car); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } GSC_SESSIONS_queue_request (car); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Closure for the 'client_tokenizer_callback'. */ struct TokenizerContext { /** * Active request handle for the message. */ struct GSC_ClientActiveRequest *car; /** * Is corking allowed (set only once we have the real message). */ int cork; }; /** * Handle CORE_SEND request. * * @param cls unused * @param client the client issuing the request * @param message the "struct SendMessage" */ static void handle_client_send (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct SendMessage *sm; struct GSC_Client *c; struct TokenizerContext tc; uint16_t msize; msize = ntohs (message->size); if (msize < sizeof (struct SendMessage) + sizeof (struct GNUNET_MessageHeader)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } sm = (const struct SendMessage *) message; msize -= sizeof (struct SendMessage); GNUNET_break (0 == ntohl (sm->reserved)); c = find_client (client); if (c == NULL) { /* client did not send INIT first! */ GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } tc.car = GNUNET_CONTAINER_multihashmap_get (c->requests, &sm->peer.hashPubKey); if (NULL == tc.car) { /* Must have been that we first approved the request, then got disconnected * (which triggered removal of the 'car') and now the client gives us a message * just *before* the client learns about the disconnect. Theoretically, we * might also now be *again* connected. So this can happen (but should be * rare). If it does happen, the message is discarded. */ GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# messages discarded (session disconnected)"), 1, GNUNET_NO); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (c->requests, &sm->peer.hashPubKey, tc.car)); tc.cork = ntohl (sm->cork); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client asked for transmission of %u bytes to `%s' %s\n", msize, GNUNET_i2s (&sm->peer), tc.cork ? "now" : ""); GNUNET_SERVER_mst_receive (client_mst, &tc, (const char *) &sm[1], msize, GNUNET_YES, GNUNET_NO); if (0 != memcmp (&tc.car->target, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity))) GSC_SESSIONS_dequeue_request (tc.car); GNUNET_free (tc.car); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Functions with this signature are called whenever a complete * message is received by the tokenizer. Used by the 'client_mst' for * dispatching messages from clients to either the SESSION subsystem * or other CLIENT (for loopback). * * @param cls closure * @param client reservation request ('struct GSC_ClientActiveRequest') * @param message the actual message */ static int client_tokenizer_callback (void *cls, void *client, const struct GNUNET_MessageHeader *message) { struct TokenizerContext *tc = client; struct GSC_ClientActiveRequest *car = tc->car; if (0 == memcmp (&car->target, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Delivering message of type %u to myself\n", ntohs (message->type)); GSC_CLIENTS_deliver_message (&GSC_my_identity, NULL, 0, message, ntohs (message->size), GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND); GSC_CLIENTS_deliver_message (&GSC_my_identity, NULL, 0, message, sizeof (struct GNUNET_MessageHeader), GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND); GSC_CLIENTS_deliver_message (&GSC_my_identity, NULL, 0, message, ntohs (message->size), GNUNET_CORE_OPTION_SEND_FULL_INBOUND); GSC_CLIENTS_deliver_message (&GSC_my_identity, NULL, 0, message, sizeof (struct GNUNET_MessageHeader), GNUNET_CORE_OPTION_SEND_HDR_INBOUND); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Delivering message of type %u to %s\n", ntohs (message->type), GNUNET_i2s (&car->target)); GSC_CLIENTS_deliver_message (&car->target, NULL, 0, message, ntohs (message->size), GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND); GSC_CLIENTS_deliver_message (&car->target, NULL, 0, message, sizeof (struct GNUNET_MessageHeader), GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND); GSC_SESSIONS_transmit (car, message, tc->cork); } return GNUNET_OK; } /** * Free client request records. * * @param cls NULL * @param key identity of peer for which this is an active request * @param value the 'struct GSC_ClientActiveRequest' to free * @return GNUNET_YES (continue iteration) */ static int destroy_active_client_request (void *cls, const GNUNET_HashCode * key, void *value) { struct GSC_ClientActiveRequest *car = value; GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (car-> client_handle->requests, &car->target.hashPubKey, car)); GSC_SESSIONS_dequeue_request (car); GNUNET_free (car); return GNUNET_YES; } /** * A client disconnected, clean up. * * @param cls closure * @param client identification of the client */ static void handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) { struct GSC_Client *c; if (client == NULL) return; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p has disconnected from core service.\n", client); c = find_client (client); if (c == NULL) return; /* client never sent INIT */ GNUNET_CONTAINER_DLL_remove (client_head, client_tail, c); if (c->requests != NULL) { GNUNET_CONTAINER_multihashmap_iterate (c->requests, &destroy_active_client_request, NULL); GNUNET_CONTAINER_multihashmap_destroy (c->requests); } GNUNET_CONTAINER_multihashmap_destroy (c->connectmap); c->connectmap = NULL; GSC_TYPEMAP_remove (c->types, c->tcnt); GNUNET_free (c); /* recalculate 'all_client_options' */ all_client_options = 0; for (c = client_head; NULL != c ; c = c->next) all_client_options |= c->options; } /** * Tell a client that we are ready to receive the message. * * @param car request that is now ready; the responsibility * for the handle remains shared between CLIENTS * and SESSIONS after this call. */ void GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car) { struct GSC_Client *c; struct SendMessageReady smr; c = car->client_handle; if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (c->connectmap, &car->target.hashPubKey)) { /* connection has gone down since, drop request */ GNUNET_assert (0 != memcmp (&car->target, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity))); GSC_SESSIONS_dequeue_request (car); GSC_CLIENTS_reject_request (car); return; } smr.header.size = htons (sizeof (struct SendMessageReady)); smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY); smr.size = htons (car->msize); smr.smr_id = car->smr_id; smr.peer = car->target; send_to_client (c, &smr.header, GNUNET_NO); } /** * Tell a client that we will never be ready to receive the * given message in time (disconnect or timeout). * * @param car request that now permanently failed; the * responsibility for the handle is now returned * to CLIENTS (SESSIONS is done with it). */ void GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car) { GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (car-> client_handle->requests, &car->target.hashPubKey, car)); GNUNET_free (car); } /** * Notify a particular client about a change to existing connection to * one of our neighbours (check if the client is interested). Called * from 'GSC_SESSIONS_notify_client_about_sessions'. * * @param client client to notify * @param neighbour identity of the neighbour that changed status * @param atsi performance information about neighbour * @param atsi_count number of entries in 'ats' array * @param tmap_old previous type map for the neighbour, NULL for disconnect * @param tmap_new updated type map for the neighbour, NULL for disconnect */ void GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client, const struct GNUNET_PeerIdentity *neighbour, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count, const struct GSC_TypeMap *tmap_old, const struct GSC_TypeMap *tmap_new) { struct ConnectNotifyMessage *cnm; size_t size; char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN; struct GNUNET_ATS_Information *a; struct DisconnectNotifyMessage dcm; int old_match; int new_match; old_match = GSC_TYPEMAP_test_match (tmap_old, client->types, client->tcnt); new_match = GSC_TYPEMAP_test_match (tmap_new, client->types, client->tcnt); if (old_match == new_match) { GNUNET_assert (old_match == GNUNET_CONTAINER_multihashmap_contains (client->connectmap, &neighbour->hashPubKey)); return; /* no change */ } if (old_match == GNUNET_NO) { /* send connect */ GNUNET_assert (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (client->connectmap, &neighbour->hashPubKey)); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_put (client->connectmap, &neighbour->hashPubKey, NULL, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); size = sizeof (struct ConnectNotifyMessage) + (atsi_count) * sizeof (struct GNUNET_ATS_Information); if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); /* recovery strategy: throw away performance data */ atsi_count = 0; size = sizeof (struct ConnectNotifyMessage); } cnm = (struct ConnectNotifyMessage *) buf; cnm->header.size = htons (size); cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT); cnm->ats_count = htonl (atsi_count); a = (struct GNUNET_ATS_Information *) &cnm[1]; memcpy (a, atsi, sizeof (struct GNUNET_ATS_Information) * atsi_count); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n", "NOTIFY_CONNECT"); cnm->peer = *neighbour; send_to_client (client, &cnm->header, GNUNET_NO); } else { /* send disconnect */ GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (client->connectmap, &neighbour->hashPubKey)); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (client->connectmap, &neighbour->hashPubKey, NULL)); dcm.header.size = htons (sizeof (struct DisconnectNotifyMessage)); dcm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT); dcm.reserved = htonl (0); dcm.peer = *neighbour; send_to_client (client, &dcm.header, GNUNET_NO); } } /** * Notify all clients about a change to existing session. * Called from SESSIONS whenever there is a change in sessions * or types processed by the respective peer. * * @param neighbour identity of the neighbour that changed status * @param atsi performance information about neighbour * @param atsi_count number of entries in 'ats' array * @param tmap_old previous type map for the neighbour, NULL for disconnect * @param tmap_new updated type map for the neighbour, NULL for disconnect */ void GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count, const struct GSC_TypeMap *tmap_old, const struct GSC_TypeMap *tmap_new) { struct GSC_Client *c; for (c = client_head; c != NULL; c = c->next) GSC_CLIENTS_notify_client_about_neighbour (c, neighbour, atsi, atsi_count, tmap_old, tmap_new); } /** * Deliver P2P message to interested clients. Caller must have checked * that the sending peer actually lists the given message type as one * of its types. * * @param sender peer who sent us the message * @param atsi performance information about neighbour * @param atsi_count number of entries in 'ats' array * @param msg the message * @param msize number of bytes to transmit * @param options options for checking which clients should * receive the message */ void GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count, const struct GNUNET_MessageHeader *msg, uint16_t msize, uint32_t options) { size_t size = msize + sizeof (struct NotifyTrafficMessage) + atsi_count * sizeof (struct GNUNET_ATS_Information); char buf[size] GNUNET_ALIGN; struct NotifyTrafficMessage *ntm; struct GNUNET_ATS_Information *a; if (0 == options) { GNUNET_snprintf (buf, sizeof (buf), gettext_noop ("# bytes of messages of type %u received"), (unsigned int) ntohs (msg->type)); GNUNET_STATISTICS_update (GSC_stats, buf, msize, GNUNET_NO); } if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); /* recovery strategy: throw performance data away... */ atsi_count = 0; size = msize + sizeof (struct NotifyTrafficMessage); } if (! ( (0 != (all_client_options & options)) || (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) )) return; /* no client cares about this message notification */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service passes message from `%4s' of type %u to client.\n", GNUNET_i2s (sender), (unsigned int) ntohs (msg->type)); GSC_SESSIONS_add_to_typemap (sender, ntohs (msg->type)); ntm = (struct NotifyTrafficMessage *) buf; ntm->header.size = htons (size); if (0 != (options & (GNUNET_CORE_OPTION_SEND_FULL_INBOUND | GNUNET_CORE_OPTION_SEND_HDR_INBOUND))) ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND); else ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND); ntm->ats_count = htonl (atsi_count); ntm->peer = *sender; a = (struct GNUNET_ATS_Information*) &ntm[1]; memcpy (a, atsi, sizeof (struct GNUNET_ATS_Information) * atsi_count); memcpy (&a[atsi_count], msg, msize); send_to_all_clients (sender, &ntm->header, GNUNET_YES, options, ntohs (msg->type)); } /** * Initialize clients subsystem. * * @param server handle to server clients connect to */ void GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server) { static const struct GNUNET_SERVER_MessageHandler handlers[] = { {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_CORE_INIT, 0}, {&GSC_SESSIONS_handle_client_iterate_peers, NULL, GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS, sizeof (struct GNUNET_MessageHeader)}, {&GSC_SESSIONS_handle_client_have_peer, NULL, GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED, sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_PeerIdentity)}, {&handle_client_send_request, NULL, GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST, sizeof (struct SendMessageRequest)}, {&handle_client_send, NULL, GNUNET_MESSAGE_TYPE_CORE_SEND, 0}, {NULL, NULL, 0, 0} }; /* setup notification */ client_mst = GNUNET_SERVER_mst_create (&client_tokenizer_callback, NULL); notifier = GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE); GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); GNUNET_SERVER_add_handlers (server, handlers); } /** * Shutdown clients subsystem. */ void GSC_CLIENTS_done () { struct GSC_Client *c; while (NULL != (c = client_head)) handle_client_disconnect (NULL, c->client_handle); if (NULL != notifier) { GNUNET_SERVER_notification_context_destroy (notifier); notifier = NULL; } GNUNET_SERVER_mst_destroy (client_mst); client_mst = NULL; } /* end of gnunet-service-core_clients.c */ gnunet-0.9.3/src/core/test_core_api_send_to_self.c0000644000175000017500000001530311760502550017176 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file core/test_core_api_send_to_self.c * @brief * @author Philipp Toelke */ #include #include #include #include #include #include /** * Final status code. */ static int ret; /** * Handle to the cleanup task. */ GNUNET_SCHEDULER_TaskIdentifier die_task; static struct GNUNET_PeerIdentity myself; /** * Configuration to load for the new peer. */ struct GNUNET_CONFIGURATION_Handle *core_cfg; /** * The handle to core */ struct GNUNET_CORE_Handle *core; /** * Handle to gnunet-service-arm. */ struct GNUNET_OS_Process *arm_proc; /** * Function scheduled as very last function, cleans up after us */ static void cleanup (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tskctx) { die_task = GNUNET_SCHEDULER_NO_TASK; if (core != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting core.\n"); GNUNET_CORE_disconnect (core); core = NULL; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peer\n"); if (0 != GNUNET_OS_process_kill (arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (arm_proc)); GNUNET_OS_process_destroy (arm_proc); arm_proc = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n"); } static int receive (void *cls, const struct GNUNET_PeerIdentity *other, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received message from peer %s\n", GNUNET_i2s (other)); GNUNET_SCHEDULER_add_now (&cleanup, NULL); ret = 0; return GNUNET_OK; } static size_t send_message (void *cls, size_t size, void *buf) { if (size == 0 || buf == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not send; got 0 buffer\n"); return 0; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending!\n"); struct GNUNET_MessageHeader *hdr = buf; hdr->size = htons (sizeof (struct GNUNET_MessageHeader)); hdr->type = htons (GNUNET_MESSAGE_TYPE_DUMMY); return ntohs (hdr->size); } static void init (void *cls, struct GNUNET_CORE_Handle *core, const struct GNUNET_PeerIdentity *my_identity) { if (core == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could NOT connect to CORE;\n"); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Correctly connected to CORE; we are the peer %s.\n", GNUNET_i2s (my_identity)); memcpy (&myself, my_identity, sizeof (struct GNUNET_PeerIdentity)); } static void connect_cb (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected to peer %s.\n", GNUNET_i2s (peer)); if (0 == memcmp (peer, &myself, sizeof (struct GNUNET_PeerIdentity))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected to myself; sending message!\n"); GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 0, GNUNET_TIME_UNIT_FOREVER_REL, peer, sizeof (struct GNUNET_MessageHeader), send_message, NULL); } } /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param cfg configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { const static struct GNUNET_CORE_MessageHandler handlers[] = { {&receive, GNUNET_MESSAGE_TYPE_DUMMY, 0}, {NULL, 0, 0} }; core_cfg = GNUNET_CONFIGURATION_create (); arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE "-L", "DEBUG", #endif "-c", "test_core_api_peer1.conf", NULL); GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (core_cfg, "test_core_api_peer1.conf")); core = GNUNET_CORE_connect (core_cfg, 42, NULL, &init, &connect_cb, NULL, NULL, 0, NULL, 0, handlers); die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300), &cleanup, cls); } static int check () { char *const argv[] = { "test-core-api-send-to-self", "-c", "test_core_api_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; static const struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; ret = 1; return (GNUNET_OK == GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test_core_api_send_to_self", gettext_noop ("help text"), options, &run, NULL)) ? ret : 1; } /** * The main function to obtain template from gnunetd. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *argv[]) { GNUNET_log_setup ("test-core-api-send-to-self", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-1"); return ret; } /* end of test_core_api_send_to_self.c */ gnunet-0.9.3/src/core/gnunet-service-core_clients.h0000644000175000017500000001243311760502551017246 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file core/gnunet-service-core_clients.h * @brief code for managing interactions with clients of core service * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_CORE_CLIENTS_H #define GNUNET_SERVICE_CORE_CLIENTS_H #include "gnunet_util_lib.h" #include "gnunet-service-core.h" #include "gnunet-service-core_typemap.h" /** * Send a message to one of our clients. * * @param client target for the message * @param msg message to transmit * @param can_drop could this message be dropped if the * client's queue is getting too large? */ void GSC_CLIENTS_send_to_client (struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *msg, int can_drop); /** * Notify a particular client about a change to existing connection to * one of our neighbours (check if the client is interested). Called * from 'GSC_SESSIONS_notify_client_about_sessions'. * * @param client client to notify * @param neighbour identity of the neighbour that changed status * @param atsi performance information about neighbour * @param atsi_count number of entries in 'ats' array * @param tmap_old previous type map for the neighbour, NULL for disconnect * @param tmap_new updated type map for the neighbour, NULL for disconnect */ void GSC_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client, const struct GNUNET_PeerIdentity *neighbour, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count, const struct GSC_TypeMap *tmap_old, const struct GSC_TypeMap *tmap_new); /** * Notify all clients about a change to existing session. * Called from SESSIONS whenever there is a change in sessions * or types processed by the respective peer. * * @param neighbour identity of the neighbour that changed status * @param atsi performance information about neighbour * @param atsi_count number of entries in 'ats' array * @param tmap_old previous type map for the neighbour, NULL for disconnect * @param tmap_new updated type map for the neighbour, NULL for disconnect */ void GSC_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count, const struct GSC_TypeMap *tmap_old, const struct GSC_TypeMap *tmap_new); /** * Deliver P2P message to interested clients. Caller must have checked * that the sending peer actually lists the given message type as one * of its types. * * @param sender peer who sent us the message * @param atsi performance information about neighbour * @param atsi_count number of entries in 'ats' array * @param msg the message * @param msize number of bytes to transmit * @param options options for checking which clients should * receive the message */ void GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count, const struct GNUNET_MessageHeader *msg, uint16_t msize, uint32_t options); /** * Tell a client that we are ready to receive the message. * * @param car request that is now ready; the responsibility * for the handle remains shared between CLIENTS * and SESSIONS after this call. */ void GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car); /** * Tell a client that we will never be ready to receive the * given message in time (disconnect or timeout). * * @param car request that now permanently failed; the * responsibility for the handle is now returned * to CLIENTS (SESSIONS is done with it). */ void GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car); /** * Initialize clients subsystem. * * @param server handle to server clients connect to */ void GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server); /** * Shutdown clients subsystem. */ void GSC_CLIENTS_done (void); #endif /* end of gnunet-service-core_clients.h */ gnunet-0.9.3/src/core/test_core_api_send_to_self.conf0000644000175000017500000000115111665224123017676 00000000000000@INLINE@ test_core_defaults.conf [PATHS] SERVICEHOME = ~/.gnunet/ DEFAULTCONFIG = test_core_api_send_to_self.conf [arm] PORT = 2425 DEFAULTSERVICES = core test-sts [core] PORT = 24512 UNIXPATH = /tmp/gnunet-service-core.sock [ats] WAN_QUOTA_IN = 104857600 WAN_QUOTA_OUT = 104757600 PORT = 24571 UNIXPATH = /tmp/gnunet-p1-service-ats.sock [test-sts] AUTOSTART = YES PORT = 9252 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = test_core_api_send_to_self ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; TOTAL_QUOTA_IN = 65536 TOTAL_QUOTA_OUT = 65536 UNIXPATH = /tmp/gnunet-service-sts.sock gnunet-0.9.3/src/core/core.conf.in0000644000175000017500000000064411760502552013676 00000000000000[core] AUTOSTART = YES @JAVAPORT@PORT = 2092 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-core ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-core.sock UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES # DISABLE_SOCKET_FORWARDING = NO # DEBUG = YES # USERNAME = # MAXBUF = # TIMEOUT = # DISABLEV6 = # BINDTO = # REJECT_FROM = # REJECT_FROM6 = # PREFIX = gnunet-0.9.3/src/core/test_core_api_start_only.c0000644000175000017500000001514511760502550016734 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/test_core_api_start_only.c * @brief testcase for core_api.c that only starts two peers, * connects to the core service and shuts down again */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_arm_service.h" #include "gnunet_core_service.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #define VERBOSE GNUNET_NO #define TIMEOUT 5 #define START_ARM GNUNET_YES #define MTYPE 12345 struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_CORE_Handle *ch; struct GNUNET_PeerIdentity id; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static struct PeerContext p1; static struct PeerContext p2; static GNUNET_SCHEDULER_TaskIdentifier timeout_task_id; static int ok; #if VERBOSE #define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) #else #define OKPP do { ok++; } while (0) #endif static void connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { } static void disconnect_notify (void *cls, const struct GNUNET_PeerIdentity *peer) { } static int inbound_notify (void *cls, const struct GNUNET_PeerIdentity *other, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { return GNUNET_OK; } static int outbound_notify (void *cls, const struct GNUNET_PeerIdentity *other, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { return GNUNET_OK; } static struct GNUNET_CORE_MessageHandler handlers[] = { {NULL, 0, 0} }; static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_CORE_disconnect (p1.ch); p1.ch = NULL; GNUNET_CORE_disconnect (p2.ch); p2.ch = NULL; ok = 0; } static void init_notify (void *cls, struct GNUNET_CORE_Handle *server, const struct GNUNET_PeerIdentity *my_identity) { struct PeerContext *p = cls; GNUNET_assert (server != NULL); GNUNET_assert (p->ch == server); if (cls == &p1) { /* connect p2 */ p2.ch = GNUNET_CORE_connect (p2.cfg, 1, &p2, &init_notify, &connect_notify, &disconnect_notify, &inbound_notify, GNUNET_YES, &outbound_notify, GNUNET_YES, handlers); } else { GNUNET_assert (cls == &p2); GNUNET_SCHEDULER_cancel (timeout_task_id); GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); } } static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE "-L", "DEBUG", #endif "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); } static void timeout_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { FPRINTF (stderr, "%s", "Timeout.\n"); if (p1.ch != NULL) { GNUNET_CORE_disconnect (p1.ch); p1.ch = NULL; } if (p2.ch != NULL) { GNUNET_CORE_disconnect (p2.ch); p2.ch = NULL; } ok = 42; } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { GNUNET_assert (ok == 1); OKPP; setup_peer (&p1, "test_core_api_peer1.conf"); setup_peer (&p2, "test_core_api_peer2.conf"); timeout_task_id = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, TIMEOUT), &timeout_task, NULL); p1.ch = GNUNET_CORE_connect (p1.cfg, 1, &p1, &init_notify, &connect_notify, &disconnect_notify, &inbound_notify, GNUNET_YES, &outbound_notify, GNUNET_YES, handlers); } static void stop_arm (struct PeerContext *p) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peer\n"); #if START_ARM if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; #endif GNUNET_CONFIGURATION_destroy (p->cfg); } static int check () { char *const argv[] = { "test-core-api-start-only", "-c", "test_core_api_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-1"); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-2"); ok = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-core-api-start-only", "nohelp", options, &run, &ok); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test finished\n"); stop_arm (&p1); stop_arm (&p2); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-core-api-start-only", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-1"); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-2"); return ret; } /* end of test_core_api_start_only.c */ gnunet-0.9.3/src/core/gnunet-service-core.c0000644000175000017500000000612111760502550015514 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file core/gnunet-service-core.c * @brief high-level P2P messaging * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet-service-core.h" #include "gnunet-service-core_clients.h" #include "gnunet-service-core_kx.h" #include "gnunet-service-core_neighbours.h" #include "gnunet-service-core_sessions.h" #include "gnunet-service-core_typemap.h" /** * Our identity. */ struct GNUNET_PeerIdentity GSC_my_identity; /** * Our configuration. */ const struct GNUNET_CONFIGURATION_Handle *GSC_cfg; /** * For creating statistics. */ struct GNUNET_STATISTICS_Handle *GSC_stats; /** * Last task run during shutdown. Disconnects us from * the transport. */ static void cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service shutting down.\n"); GSC_CLIENTS_done (); GSC_NEIGHBOURS_done (); GSC_SESSIONS_done (); GSC_KX_done (); GSC_TYPEMAP_done (); if (GSC_stats != NULL) { GNUNET_STATISTICS_destroy (GSC_stats, GNUNET_NO); GSC_stats = NULL; } GSC_cfg = NULL; } /** * Initiate core service. * * @param cls closure * @param server the initialized server * @param c configuration to use */ static void run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *c) { GSC_cfg = c; GSC_stats = GNUNET_STATISTICS_create ("core", GSC_cfg); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleaning_task, NULL); GSC_TYPEMAP_init (); if ((GNUNET_OK != GSC_KX_init ()) || (GNUNET_OK != GSC_NEIGHBOURS_init ())) { GNUNET_SCHEDULER_shutdown (); return; } GSC_SESSIONS_init (); GSC_CLIENTS_init (server); GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Core service of `%4s' ready.\n"), GNUNET_i2s (&GSC_my_identity)); } /** * The main function for the transport service. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { return (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "core", GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; } /* end of gnunet-service-core.c */ gnunet-0.9.3/src/core/test_core_quota_asymmetric_send_limit_peer1.conf0000644000175000017500000000151711723125435023301 00000000000000@INLINE@ test_core_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-core-quota-asym-send-lim-peer-1/ DEFAULTCONFIG = test_core_quota_asymmetric_send_limit_peer1.conf [transport-tcp] PORT = 12488 [arm] PORT = 12486 UNIXPATH = /tmp/gnunet-core-asym-send-p1-service-arm.sock [statistics] PORT = 12487 UNIXPATH = /tmp/gnunet-core-asym-send-p1-service-statistics.sock [resolver] PORT = 12484 UNIXPATH = /tmp/gnunet-core-asym-send-1-service-resolver.sock [peerinfo] PORT = 12489 UNIXPATH = /tmp/gnunet-core-asym-send-p1-service-peerinfo.sock [transport] PORT = 12485 UNIXPATH = /tmp/gnunet-core-asym-send-p1-service-transport.sock [ats] WAN_QUOTA_IN = 10240 WAN_QUOTA_OUT = 10240 PORT = 12491 UNIXPATH = /tmp/gnunet-core-asym-send-p1-service-ats.sock [core] PORT = 12490 UNIXPATH = /tmp/gnunet-core-asym-send-p1-service-core.sock DEBUG = NO gnunet-0.9.3/src/core/test_core_api_peer2.conf0000644000175000017500000000130211751071052016242 00000000000000@INLINE@ test_core_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-core-peer-2/ DEFAULTCONFIG = test_core_api_peer2.conf [arm] PORT = 22460 UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 22461 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 22462 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 22463 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 22464 UNIXPATH = /tmp/gnunet-p2-service-transport.sock [core] PORT = 22475 UNIXPATH = /tmp/gnunet-p2-service-core.sock [ats] PORT = 22476 UNIXPATH = /tmp/gnunet-p2-service-ats.sock [transport-tcp] PORT = 22467 [transport-unix] PORT = 22468 [transport-http] PORT = 22469gnunet-0.9.3/src/core/gnunet-service-core_typemap.c0000644000175000017500000001567511760502550017271 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file core/gnunet-service-core_typemap.c * @brief management of map that specifies which message types this peer supports * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_transport_service.h" #include "gnunet-service-core.h" #include "gnunet-service-core_sessions.h" #include "gnunet-service-core_typemap.h" #include /** * A type map describing which messages a given neighbour is able * to process. */ struct GSC_TypeMap { uint32_t bits[(UINT16_MAX + 1) / 32]; }; /** * Bitmap of message types this peer is able to handle. */ static struct GSC_TypeMap my_type_map; /** * Counters for message types this peer is able to handle. */ static uint8_t map_counters[UINT16_MAX + 1]; /** * Compute a type map message for this peer. * * @return this peers current type map message. */ struct GNUNET_MessageHeader * GSC_TYPEMAP_compute_type_map_message () { char *tmp; uLongf dlen; struct GNUNET_MessageHeader *hdr; #ifdef compressBound dlen = compressBound (sizeof (my_type_map)); #else dlen = sizeof (my_type_map) + (sizeof (my_type_map) / 100) + 20; /* documentation says 100.1% oldSize + 12 bytes, but we * should be able to overshoot by more to be safe */ #endif hdr = GNUNET_malloc (dlen + sizeof (struct GNUNET_MessageHeader)); tmp = (char *) &hdr[1]; if ((Z_OK != compress2 ((Bytef *) tmp, &dlen, (const Bytef *) &my_type_map, sizeof (my_type_map), 9)) || (dlen >= sizeof (my_type_map))) { dlen = sizeof (my_type_map); memcpy (tmp, &my_type_map, sizeof (my_type_map)); hdr->type = htons (GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP); } else { hdr->type = htons (GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP); } hdr->size = htons ((uint16_t) dlen + sizeof (struct GNUNET_MessageHeader)); return hdr; } /** * Extract a type map from a TYPE_MAP message. * * @param msg a type map message * @return NULL on error */ struct GSC_TypeMap * GSC_TYPEMAP_get_from_message (const struct GNUNET_MessageHeader *msg) { struct GSC_TypeMap *ret; uint16_t size; uLongf dlen; size = ntohs (msg->size); switch (ntohs (msg->type)) { case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP: GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# type maps received"), 1, GNUNET_NO); if (size != sizeof (struct GSC_TypeMap)) { GNUNET_break_op (0); return NULL; } ret = GNUNET_malloc (sizeof (struct GSC_TypeMap)); memcpy (ret, &msg[1], sizeof (struct GSC_TypeMap)); return ret; case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP: GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# type maps received"), 1, GNUNET_NO); ret = GNUNET_malloc (sizeof (struct GSC_TypeMap)); dlen = sizeof (struct GSC_TypeMap); if ((Z_OK != uncompress ((Bytef *) ret, &dlen, (const Bytef *) &msg[1], (uLong) size)) || (dlen != sizeof (struct GSC_TypeMap))) { GNUNET_break_op (0); GNUNET_free (ret); return NULL; } return ret; default: GNUNET_break (0); return NULL; } } /** * Send my type map to all connected peers (it got changed). */ static void broadcast_my_type_map () { struct GNUNET_MessageHeader *hdr; hdr = GSC_TYPEMAP_compute_type_map_message (); GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# updates to my type map"), 1, GNUNET_NO); GSC_SESSIONS_broadcast (hdr); GNUNET_free (hdr); } /** * Add a set of types to our type map. */ void GSC_TYPEMAP_add (const uint16_t * types, unsigned int tlen) { unsigned int i; int changed; changed = GNUNET_NO; for (i = 0; i < tlen; i++) { if (0 == map_counters[types[i]]++) { my_type_map.bits[types[i] / 32] |= (1 << (types[i] % 32)); changed = GNUNET_YES; } } if (GNUNET_YES == changed) broadcast_my_type_map (); } /** * Remove a set of types from our type map. */ void GSC_TYPEMAP_remove (const uint16_t * types, unsigned int tlen) { unsigned int i; int changed; changed = GNUNET_NO; for (i = 0; i < tlen; i++) { if (0 == --map_counters[types[i]]) { my_type_map.bits[types[i] / 32] &= ~(1 << (types[i] % 32)); changed = GNUNET_YES; } } if (GNUNET_YES == changed) broadcast_my_type_map (); } /** * Test if any of the types from the types array is in the * given type map. * * @param tmap map to test * @param types array of types * @param tcnt number of entries in types * @return GNUNET_YES if a type is in the map, GNUNET_NO if not */ int GSC_TYPEMAP_test_match (const struct GSC_TypeMap *tmap, const uint16_t * types, unsigned int tcnt) { unsigned int i; if (NULL == tmap) return GNUNET_NO; if (0 == tcnt) return GNUNET_YES; /* matches all */ for (i = 0; i < tcnt; i++) if (0 != (tmap->bits[types[i] / 32] & (1 << (types[i] % 32)))) return GNUNET_YES; return GNUNET_NO; } /** * Add additional types to a given typemap. * * @param tmap map to extend (not changed) * @param types array of types to add * @param tcnt number of entries in types * @return updated type map (fresh copy) */ struct GSC_TypeMap * GSC_TYPEMAP_extend (const struct GSC_TypeMap *tmap, const uint16_t * types, unsigned int tcnt) { struct GSC_TypeMap *ret; unsigned int i; ret = GNUNET_malloc (sizeof (struct GSC_TypeMap)); if (NULL != tmap) memcpy (ret, tmap, sizeof (struct GSC_TypeMap)); for (i = 0; i < tcnt; i++) ret->bits[types[i] / 32] |= (1 << (types[i] % 32)); return ret; } /** * Create an empty type map. * * @return an empty type map */ struct GSC_TypeMap * GSC_TYPEMAP_create () { return GNUNET_malloc (sizeof (struct GSC_TypeMap)); } /** * Free the given type map. * * @param tmap a type map */ void GSC_TYPEMAP_destroy (struct GSC_TypeMap *tmap) { GNUNET_free (tmap); } /** * Initialize typemap subsystem. */ void GSC_TYPEMAP_init () { /* nothing to do */ } /** * Shutdown typemap subsystem. */ void GSC_TYPEMAP_done () { /* nothing to do */ } /* end of gnunet-service-core_typemap.c */ gnunet-0.9.3/src/core/test_core_quota_asymmetric_send_limit_peer2.conf0000644000175000017500000000161311751071052023273 00000000000000@INLINE@ test_core_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-core-quota-asym-send-lim-peer-2/ DEFAULTCONFIG = test_core_quota_asymmetric_send_limit_peer2.conf [arm] PORT = 22486 UNIXPATH = /tmp/gnunet-core-asym-send-p2-service-arm.sock [statistics] PORT = 22487 UNIXPATH = /tmp/gnunet-core-asym-send-p2-service-statistics.sock [resolver] PORT = 22484 UNIXPATH = /tmp/gnunet-core-asym-send-p2-service-resolver.sock [peerinfo] PORT = 22489 UNIXPATH = /tmp/gnunet-core-asym-send-p2-service-peerinfo.sock [transport] PORT = 22485 UNIXPATH = /tmp/gnunet-core-asym-send-p2-service-transport.sock [core] PORT = 22490 UNIXPATH = /tmp/gnunet-core-asym-send-p2-service-core.sock DEBUG = NO [ats] PORT = 22491 UNIXPATH = /tmp/gnunet-core-asym-send-p2-service-ats.sock WAN_QUOTA_IN = 1 MB WAN_QUOTA_OUT = 1 MB [transport-tcp] PORT = 22467 [transport-unix] PORT = 22468 [transport-http] PORT = 22469gnunet-0.9.3/src/core/test_core_quota_compliance.c0000644000175000017500000005747411760502550017243 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file core/test_core_quota_compliance.c * @brief testcase for core_api.c focusing quota compliance on core level */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_constants.h" #include "gnunet_arm_service.h" #include "gnunet_core_service.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_transport_service.h" #include "gnunet_statistics_service.h" #define SYMMETRIC 0 #define ASYMMETRIC_SEND_LIMITED 1 #define ASYMMETRIC_RECV_LIMITED 2 #define START_ARM GNUNET_YES /** * Note that this value must not significantly exceed * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise * messages may be dropped even for a reliable transport. */ #define TOTAL_MSGS (60000 * 10) /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) /** * What delay do we request from the core service for transmission? */ #define FAST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 150) #define MTYPE 12345 #define MESSAGESIZE 1024 #define MEASUREMENT_LENGTH GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) static unsigned long long total_bytes_sent; static unsigned long long total_bytes_recv; static struct GNUNET_TIME_Absolute start_time; static GNUNET_SCHEDULER_TaskIdentifier err_task; static GNUNET_SCHEDULER_TaskIdentifier measure_task; static GNUNET_SCHEDULER_TaskIdentifier connect_task; struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_CORE_Handle *ch; struct GNUNET_CORE_TransmitHandle *nth; struct GNUNET_PeerIdentity id; struct GNUNET_TRANSPORT_Handle *th; struct GNUNET_MessageHeader *hello; struct GNUNET_STATISTICS_Handle *stats; struct GNUNET_TRANSPORT_GetHelloHandle *ghh; int connect_status; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static struct PeerContext p1; static struct PeerContext p2; static unsigned long long current_quota_p1_in; static unsigned long long current_quota_p1_out; static unsigned long long current_quota_p2_in; static unsigned long long current_quota_p2_out; static int ok; static int test; static int32_t tr_n; static int running; #if VERBOSE #define OKPP do { ok++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) #else #define OKPP do { ok++; } while (0) #endif struct TestMessage { struct GNUNET_MessageHeader header; uint32_t num; }; static void process_hello (void *cls, const struct GNUNET_MessageHeader *message); static void terminate_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CORE_Handle *ch; err_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_STATISTICS_destroy (p1.stats, GNUNET_NO); GNUNET_STATISTICS_destroy (p2.stats, GNUNET_NO); GNUNET_TRANSPORT_get_hello_cancel (p2.ghh); GNUNET_TRANSPORT_get_hello_cancel (p1.ghh); if (p1.nth != NULL) { GNUNET_CORE_notify_transmit_ready_cancel (p1.nth); p1.nth = NULL; } if (connect_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (connect_task); ch = p1.ch; p1.ch = NULL; GNUNET_CORE_disconnect (ch); ch = p2.ch; p2.ch = NULL; GNUNET_CORE_disconnect (ch); GNUNET_TRANSPORT_disconnect (p1.th); p1.th = NULL; GNUNET_TRANSPORT_disconnect (p2.th); p2.th = NULL; } static void terminate_task_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { err_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Testcase failed!\n"); //GNUNET_break (0); if (p1.nth != NULL) { GNUNET_CORE_notify_transmit_ready_cancel (p1.nth); p1.nth = NULL; } if (measure_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (measure_task); if (connect_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (connect_task); GNUNET_TRANSPORT_get_hello_cancel (p1.ghh); GNUNET_TRANSPORT_get_hello_cancel (p2.ghh); if (NULL != p1.ch) GNUNET_CORE_disconnect (p1.ch); p1.ch = NULL; if (NULL != p2.ch) GNUNET_CORE_disconnect (p2.ch); p2.ch = NULL; if (NULL != p1.th) GNUNET_TRANSPORT_disconnect (p1.th); p1.th = NULL; if (NULL != p2.th) GNUNET_TRANSPORT_disconnect (p2.th); p2.th = NULL; ok = 42; } static void try_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { connect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &try_connect, NULL); GNUNET_TRANSPORT_try_connect (p1.th, &p2.id); GNUNET_TRANSPORT_try_connect (p2.th, &p1.id); } /** * Callback function to process statistic values. * * @param cls closure * @param subsystem name of subsystem that created the statistic * @param name the name of the datum * @param value the current value * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration */ static int print_stat (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent) { if (cls == &p1) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer1 %50s = %12llu\n", name, (unsigned long long) value); if (cls == &p2) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer2 %50s = %12llu\n", name, (unsigned long long) value); return GNUNET_OK; } static void measurement_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { unsigned long long delta; unsigned long long throughput_out; unsigned long long throughput_in; unsigned long long max_quota_in; unsigned long long max_quota_out; unsigned long long quota_delta; enum GNUNET_ErrorType kind = GNUNET_ERROR_TYPE_DEBUG; measure_task = GNUNET_SCHEDULER_NO_TASK; FPRINTF (stdout, "%s", "\n"); running = GNUNET_NO; delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value; throughput_out = total_bytes_sent * 1000 / delta; /* convert to bytes/s */ throughput_in = total_bytes_recv * 1000 / delta; /* convert to bytes/s */ max_quota_in = GNUNET_MIN (current_quota_p1_in, current_quota_p2_in); max_quota_out = GNUNET_MIN (current_quota_p1_out, current_quota_p2_out); if (max_quota_out < max_quota_in) quota_delta = max_quota_in / 3; else quota_delta = max_quota_out / 3; if ((throughput_out > (max_quota_out + quota_delta)) || (throughput_in > (max_quota_in + quota_delta))) ok = 1; /* fail */ else ok = 0; /* pass */ GNUNET_STATISTICS_get (p1.stats, "core", "# discarded CORE_SEND requests", GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, &p1); GNUNET_STATISTICS_get (p1.stats, "core", "# discarded CORE_SEND request bytes", GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, &p1); GNUNET_STATISTICS_get (p1.stats, "core", "# discarded lower priority CORE_SEND requests", GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, NULL); GNUNET_STATISTICS_get (p1.stats, "core", "# discarded lower priority CORE_SEND request bytes", GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, &p1); GNUNET_STATISTICS_get (p2.stats, "core", "# discarded CORE_SEND requests", GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, &p2); GNUNET_STATISTICS_get (p2.stats, "core", "# discarded CORE_SEND request bytes", GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, &p2); GNUNET_STATISTICS_get (p2.stats, "core", "# discarded lower priority CORE_SEND requests", GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, &p2); GNUNET_STATISTICS_get (p2.stats, "core", "# discarded lower priority CORE_SEND request bytes", GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, &p2); if (ok != 0) kind = GNUNET_ERROR_TYPE_ERROR; switch (test) { case SYMMETRIC: GNUNET_log (kind, "Core quota compliance test with symmetric quotas: %s\n", (0 == ok) ? "PASSED" : "FAILED"); break; case ASYMMETRIC_SEND_LIMITED: GNUNET_log (kind, "Core quota compliance test with limited sender quota: %s\n", (0 == ok) ? "PASSED" : "FAILED"); break; case ASYMMETRIC_RECV_LIMITED: GNUNET_log (kind, "Core quota compliance test with limited receiver quota: %s\n", (0 == ok) ? "PASSED" : "FAILED"); break; }; GNUNET_log (kind, "Peer 1 send rate: %llu b/s (%llu bytes in %llu ms)\n", throughput_out, total_bytes_sent, delta); GNUNET_log (kind, "Peer 1 send quota: %llu b/s\n", current_quota_p1_out); GNUNET_log (kind, "Peer 2 receive rate: %llu b/s (%llu bytes in %llu ms)\n", throughput_in, total_bytes_recv, delta); GNUNET_log (kind, "Peer 2 receive quota: %llu b/s\n", current_quota_p2_in); /* GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Max. inbound quota allowed: %llu b/s\n",max_quota_in ); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Max. outbound quota allowed: %llu b/s\n",max_quota_out); */ GNUNET_SCHEDULER_cancel (err_task); err_task = GNUNET_SCHEDULER_add_now (&terminate_task, NULL); } static size_t transmit_ready (void *cls, size_t size, void *buf) { char *cbuf = buf; struct TestMessage hdr; unsigned int ret; p1.nth = NULL; GNUNET_assert (size <= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE); if (buf == NULL) { if ((p1.ch != NULL) && (p1.connect_status == 1)) GNUNET_break (NULL != (p1.nth = GNUNET_CORE_notify_transmit_ready (p1.ch, GNUNET_NO, 0, FAST_TIMEOUT, &p2.id, MESSAGESIZE, &transmit_ready, &p1))); return 0; } GNUNET_assert (tr_n < TOTAL_MSGS); ret = 0; GNUNET_assert (size >= MESSAGESIZE); GNUNET_assert (buf != NULL); cbuf = buf; do { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message %u of size %u at offset %u\n", tr_n, MESSAGESIZE, ret); hdr.header.size = htons (MESSAGESIZE); hdr.header.type = htons (MTYPE); hdr.num = htonl (tr_n); memcpy (&cbuf[ret], &hdr, sizeof (struct TestMessage)); ret += sizeof (struct TestMessage); memset (&cbuf[ret], tr_n, MESSAGESIZE - sizeof (struct TestMessage)); ret += MESSAGESIZE - sizeof (struct TestMessage); tr_n++; if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16)) break; /* sometimes pack buffer full, sometimes not */ } while (size - ret >= MESSAGESIZE); GNUNET_SCHEDULER_cancel (err_task); err_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &terminate_task_error, NULL); total_bytes_sent += ret; return ret; } static void connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct PeerContext *pc = cls; if (0 == memcmp (&pc->id, peer, sizeof (struct GNUNET_PeerIdentity))) return; /* loopback */ GNUNET_assert (pc->connect_status == 0); pc->connect_status = 1; if (pc == &p1) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypted connection established to peer `%4s'\n", GNUNET_i2s (peer)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking core (1) for transmission to peer `%4s'\n", GNUNET_i2s (&p2.id)); if (err_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (err_task); err_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &terminate_task_error, NULL); start_time = GNUNET_TIME_absolute_get (); running = GNUNET_YES; measure_task = GNUNET_SCHEDULER_add_delayed (MEASUREMENT_LENGTH, &measurement_stop, NULL); GNUNET_break (NULL != (p1.nth = GNUNET_CORE_notify_transmit_ready (p1.ch, GNUNET_NO, 0, TIMEOUT, &p2.id, MESSAGESIZE, &transmit_ready, &p1))); } } static void disconnect_notify (void *cls, const struct GNUNET_PeerIdentity *peer) { struct PeerContext *pc = cls; if (0 == memcmp (&pc->id, peer, sizeof (struct GNUNET_PeerIdentity))) return; /* loopback */ pc->connect_status = 0; if (GNUNET_SCHEDULER_NO_TASK != measure_task) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Measurement aborted due to disconnect!\n"); GNUNET_SCHEDULER_cancel (measure_task); measure_task = GNUNET_SCHEDULER_NO_TASK; } if (pc->nth != NULL) { GNUNET_CORE_notify_transmit_ready_cancel (pc->nth); pc->nth = NULL; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypted connection to `%4s' cut\n", GNUNET_i2s (peer)); } static int inbound_notify (void *cls, const struct GNUNET_PeerIdentity *other, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core provides inbound data from `%4s' %llu.\n", GNUNET_i2s (other), ntohs (message->size)); total_bytes_recv += ntohs (message->size); return GNUNET_OK; } static int outbound_notify (void *cls, const struct GNUNET_PeerIdentity *other, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core notifies about outbound data for `%4s'.\n", GNUNET_i2s (other)); return GNUNET_OK; } static size_t transmit_ready (void *cls, size_t size, void *buf); static int process_mtype (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { static int n; const struct TestMessage *hdr; hdr = (const struct TestMessage *) message; if (MTYPE != ntohs (message->type)) return GNUNET_SYSERR; if (ntohs (message->size) != MESSAGESIZE) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected message %u of size %u, got %u bytes of message %u\n", n, MESSAGESIZE, ntohs (message->size), ntohl (hdr->num)); GNUNET_SCHEDULER_cancel (err_task); err_task = GNUNET_SCHEDULER_add_now (&terminate_task_error, NULL); return GNUNET_SYSERR; } if (ntohl (hdr->num) != n) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected message %u of size %u, got %u bytes of message %u\n", n, MESSAGESIZE, ntohs (message->size), ntohl (hdr->num)); GNUNET_SCHEDULER_cancel (err_task); err_task = GNUNET_SCHEDULER_add_now (&terminate_task_error, NULL); return GNUNET_SYSERR; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got message %u of size %u\n", ntohl (hdr->num), ntohs (message->size)); n++; if (0 == (n % 10)) FPRINTF (stderr, "%s", "."); if (running == GNUNET_YES) GNUNET_break (NULL != GNUNET_CORE_notify_transmit_ready (p1.ch, GNUNET_NO, 0, FAST_TIMEOUT, &p2.id, MESSAGESIZE, &transmit_ready, &p1)); return GNUNET_OK; } static struct GNUNET_CORE_MessageHandler handlers[] = { {&process_mtype, MTYPE, 0}, {NULL, 0, 0} }; static void init_notify (void *cls, struct GNUNET_CORE_Handle *server, const struct GNUNET_PeerIdentity *my_identity) { struct PeerContext *p = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection to CORE service of `%4s' established\n", GNUNET_i2s (my_identity)); GNUNET_assert (server != NULL); p->id = *my_identity; GNUNET_assert (p->ch == server); if (cls == &p1) { GNUNET_assert (ok == 2); OKPP; /* connect p2 */ p2.ch = GNUNET_CORE_connect (p2.cfg, 1, &p2, &init_notify, &connect_notify, &disconnect_notify, &inbound_notify, GNUNET_YES, &outbound_notify, GNUNET_YES, handlers); } else { GNUNET_assert (ok == 3); OKPP; GNUNET_assert (cls == &p2); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking core (1) to connect to peer `%4s'\n", GNUNET_i2s (&p2.id)); connect_task = GNUNET_SCHEDULER_add_now (&try_connect, NULL); } } static void process_hello (void *cls, const struct GNUNET_MessageHeader *message) { struct PeerContext *p = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received (my) `%s' from transport service\n", "HELLO"); GNUNET_assert (message != NULL); p->hello = GNUNET_malloc (ntohs (message->size)); memcpy (p->hello, message, ntohs (message->size)); if ((p == &p1) && (p2.th != NULL)) GNUNET_TRANSPORT_offer_hello (p2.th, message, NULL, NULL); if ((p == &p2) && (p1.th != NULL)) GNUNET_TRANSPORT_offer_hello (p1.th, message, NULL, NULL); if ((p == &p1) && (p2.hello != NULL)) GNUNET_TRANSPORT_offer_hello (p1.th, p2.hello, NULL, NULL); if ((p == &p2) && (p1.hello != NULL)) GNUNET_TRANSPORT_offer_hello (p2.th, p1.hello, NULL, NULL); } static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); p->stats = GNUNET_STATISTICS_create ("core", p->cfg); GNUNET_assert (p->stats != NULL); p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p, NULL, NULL, NULL); GNUNET_assert (p->th != NULL); p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &process_hello, p); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { GNUNET_assert (ok == 1); OKPP; err_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &terminate_task_error, NULL); if (test == SYMMETRIC) { setup_peer (&p1, "test_core_quota_peer1.conf"); setup_peer (&p2, "test_core_quota_peer2.conf"); } else if (test == ASYMMETRIC_SEND_LIMITED) { setup_peer (&p1, "test_core_quota_asymmetric_send_limit_peer1.conf"); setup_peer (&p2, "test_core_quota_asymmetric_send_limit_peer2.conf"); } else if (test == ASYMMETRIC_RECV_LIMITED) { setup_peer (&p1, "test_core_quota_asymmetric_recv_limited_peer1.conf"); setup_peer (&p2, "test_core_quota_asymmetric_recv_limited_peer2.conf"); } GNUNET_assert (test != -1); GNUNET_assert (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_size (p1.cfg, "ATS", "WAN_QUOTA_IN", ¤t_quota_p1_in)); GNUNET_assert (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_size (p2.cfg, "ATS", "WAN_QUOTA_IN", ¤t_quota_p2_in)); GNUNET_assert (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_size (p1.cfg, "ATS", "WAN_QUOTA_OUT", ¤t_quota_p1_out)); GNUNET_assert (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_size (p2.cfg, "ATS", "WAN_QUOTA_OUT", ¤t_quota_p2_out)); p1.ch = GNUNET_CORE_connect (p1.cfg, 1, &p1, &init_notify, &connect_notify, &disconnect_notify, &inbound_notify, GNUNET_YES, &outbound_notify, GNUNET_YES, handlers); } static void stop_arm (struct PeerContext *p) { #if START_ARM if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; #endif GNUNET_CONFIGURATION_destroy (p->cfg); } static int check () { char *const argv[] = { "test-core-quota-compliance", "-c", "test_core_api_data.conf", NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; ok = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-core-quota-compliance", "nohelp", options, &run, &ok); stop_arm (&p1); stop_arm (&p2); return ok; } int main (int argc, char *argv[]) { int ret; test = -1; if (strstr (argv[0], "_symmetric") != NULL) { test = SYMMETRIC; } else if (strstr (argv[0], "_asymmetric_send") != NULL) { test = ASYMMETRIC_SEND_LIMITED; } else if (strstr (argv[0], "_asymmetric_recv") != NULL) { test = ASYMMETRIC_RECV_LIMITED; } GNUNET_assert (test != -1); if (test == SYMMETRIC) { GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-quota-sym-peer-1/"); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-quota-sym-peer-2/"); } else if (test == ASYMMETRIC_SEND_LIMITED) { GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-quota-asym-send-lim-peer-1/"); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-quota-asym-send-lim-peer-2/"); } else if (test == ASYMMETRIC_RECV_LIMITED) { GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-quota-asym-recv-lim-peer-1/"); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-quota-asym-recv-lim-peer-2/"); } GNUNET_log_setup ("test-core-quota-compliance", "WARNING", NULL); ret = check (); if (test == SYMMETRIC) { GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-quota-sym-peer-1/"); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-quota-sym-peer-2/"); } else if (test == ASYMMETRIC_SEND_LIMITED) { GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-quota-asym-send-lim-peer-1/"); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-quota-asym-send-lim-peer-2/"); } else if (test == ASYMMETRIC_RECV_LIMITED) { GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-quota-asym-recv-lim-peer-1/"); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-quota-asym-recv-lim-peer-2/"); } return ret; } /* end of test_core_quota_compliance.c */ gnunet-0.9.3/src/core/test_core_api.c0000644000175000017500000002636411760502550014463 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file core/test_core_api.c * @brief testcase for core_api.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_arm_service.h" #include "gnunet_core_service.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_transport_service.h" #define VERBOSE GNUNET_NO #define START_ARM GNUNET_YES #define MTYPE 12345 struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_CORE_Handle *ch; struct GNUNET_PeerIdentity id; struct GNUNET_TRANSPORT_Handle *th; struct GNUNET_TRANSPORT_GetHelloHandle *ghh; struct GNUNET_MessageHeader *hello; int connect_status; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static struct PeerContext p1; static struct PeerContext p2; static GNUNET_SCHEDULER_TaskIdentifier err_task; static GNUNET_SCHEDULER_TaskIdentifier con_task; static int ok; #if VERBOSE #define OKPP do { ok++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) #else #define OKPP do { ok++; } while (0) #endif static void process_hello (void *cls, const struct GNUNET_MessageHeader *message) { struct PeerContext *p = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received (my) `%s' from transport service\n", "HELLO"); GNUNET_assert (message != NULL); if ((p == &p1) && (p2.th != NULL)) GNUNET_TRANSPORT_offer_hello (p2.th, message, NULL, NULL); if ((p == &p2) && (p1.th != NULL)) GNUNET_TRANSPORT_offer_hello (p1.th, message, NULL, NULL); } static void terminate_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_assert (ok == 6); GNUNET_CORE_disconnect (p1.ch); p1.ch = NULL; GNUNET_CORE_disconnect (p2.ch); p2.ch = NULL; GNUNET_TRANSPORT_get_hello_cancel (p1.ghh); p1.ghh = NULL; GNUNET_TRANSPORT_get_hello_cancel (p2.ghh); p2.ghh = NULL; GNUNET_TRANSPORT_disconnect (p1.th); p1.th = NULL; GNUNET_TRANSPORT_disconnect (p2.th); p2.th = NULL; if (GNUNET_SCHEDULER_NO_TASK != con_task) { GNUNET_SCHEDULER_cancel (con_task); con_task = GNUNET_SCHEDULER_NO_TASK; } ok = 0; } static void terminate_task_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { #if VERBOSE FPRINTF (stderr, "ENDING ANGRILY %u\n", ok); #endif GNUNET_break (0); if (NULL != p1.ch) { GNUNET_CORE_disconnect (p1.ch); p1.ch = NULL; } if (NULL != p2.ch) { GNUNET_CORE_disconnect (p2.ch); p2.ch = NULL; } if (p1.th != NULL) { GNUNET_TRANSPORT_get_hello_cancel (p1.ghh); GNUNET_TRANSPORT_disconnect (p1.th); p1.th = NULL; } if (p2.th != NULL) { GNUNET_TRANSPORT_get_hello_cancel (p2.ghh); GNUNET_TRANSPORT_disconnect (p2.th); p2.th = NULL; } if (GNUNET_SCHEDULER_NO_TASK != con_task) { GNUNET_SCHEDULER_cancel (con_task); con_task = GNUNET_SCHEDULER_NO_TASK; } ok = 42; } static size_t transmit_ready (void *cls, size_t size, void *buf) { struct PeerContext *p = cls; struct GNUNET_MessageHeader *m; GNUNET_assert (ok == 4); OKPP; GNUNET_assert (p == &p1); GNUNET_assert (buf != NULL); m = (struct GNUNET_MessageHeader *) buf; m->type = htons (MTYPE); m->size = htons (sizeof (struct GNUNET_MessageHeader)); return sizeof (struct GNUNET_MessageHeader); } static void connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct PeerContext *pc = cls; if (0 == memcmp (&pc->id, peer, sizeof (struct GNUNET_PeerIdentity))) return; GNUNET_assert (pc->connect_status == 0); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypted connection established to peer `%4s'\n", GNUNET_i2s (peer)); if (GNUNET_SCHEDULER_NO_TASK != con_task) { GNUNET_SCHEDULER_cancel (con_task); con_task = GNUNET_SCHEDULER_NO_TASK; } pc->connect_status = 1; if (pc == &p1) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking core (1) for transmission to peer `%4s'\n", GNUNET_i2s (&p2.id)); if (NULL == GNUNET_CORE_notify_transmit_ready (p1.ch, GNUNET_YES, 0, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 145), &p2.id, sizeof (struct GNUNET_MessageHeader), &transmit_ready, &p1)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n", GNUNET_i2s (&p2.id)); } } } static void disconnect_notify (void *cls, const struct GNUNET_PeerIdentity *peer) { struct PeerContext *pc = cls; if (0 == memcmp (&pc->id, peer, sizeof (struct GNUNET_PeerIdentity))) return; pc->connect_status = 0; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypted connection to `%4s' cut\n", GNUNET_i2s (peer)); } static int inbound_notify (void *cls, const struct GNUNET_PeerIdentity *other, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core provides inbound data from `%4s'.\n", GNUNET_i2s (other)); return GNUNET_OK; } static int outbound_notify (void *cls, const struct GNUNET_PeerIdentity *other, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core notifies about outbound data for `%4s'.\n", GNUNET_i2s (other)); return GNUNET_OK; } static int process_mtype (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving message from `%4s'.\n", GNUNET_i2s (peer)); GNUNET_assert (ok == 5); OKPP; GNUNET_SCHEDULER_cancel (err_task); err_task = GNUNET_SCHEDULER_add_now (&terminate_task, NULL); return GNUNET_OK; } static struct GNUNET_CORE_MessageHandler handlers[] = { {&process_mtype, MTYPE, sizeof (struct GNUNET_MessageHeader)}, {NULL, 0, 0} }; static void connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) { con_task = GNUNET_SCHEDULER_NO_TASK; return; } con_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &connect_task, NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking transport (1) to connect to peer `%4s'\n", GNUNET_i2s (&p2.id)); GNUNET_TRANSPORT_try_connect (p1.th, &p2.id); } static void init_notify (void *cls, struct GNUNET_CORE_Handle *server, const struct GNUNET_PeerIdentity *my_identity) { struct PeerContext *p = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core connection to `%4s' established\n", GNUNET_i2s (my_identity)); GNUNET_assert (server != NULL); p->id = *my_identity; p->ch = server; if (cls == &p1) { GNUNET_assert (ok == 2); OKPP; /* connect p2 */ p2.ch = GNUNET_CORE_connect (p2.cfg, 1, &p2, &init_notify, &connect_notify, &disconnect_notify, &inbound_notify, GNUNET_YES, &outbound_notify, GNUNET_YES, handlers); } else { GNUNET_assert (ok == 3); OKPP; GNUNET_assert (cls == &p2); con_task = GNUNET_SCHEDULER_add_now (&connect_task, NULL); } } static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE "-L", "DEBUG", #endif "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p, NULL, NULL, NULL); GNUNET_assert (p->th != NULL); p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &process_hello, p); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { GNUNET_assert (ok == 1); OKPP; setup_peer (&p1, "test_core_api_peer1.conf"); setup_peer (&p2, "test_core_api_peer2.conf"); err_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300), &terminate_task_error, NULL); p1.ch = GNUNET_CORE_connect (p1.cfg, 1, &p1, &init_notify, &connect_notify, &disconnect_notify, &inbound_notify, GNUNET_YES, &outbound_notify, GNUNET_YES, handlers); } static void stop_arm (struct PeerContext *p) { #if START_ARM if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; #endif GNUNET_CONFIGURATION_destroy (p->cfg); } static int check () { char *const argv[] = { "test-core-api", "-c", "test_core_api_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; ok = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-core-api", "nohelp", options, &run, &ok); stop_arm (&p1); stop_arm (&p2); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-core-api", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-1"); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-2"); return ret; } /* end of test_core_api.c */ gnunet-0.9.3/src/core/gnunet-service-core_typemap.h0000644000175000017500000000572611760502551017273 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file core/gnunet-service-core_typemap.h * @brief management of map that specifies which message types this peer supports * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_CORE_TYPEMAP_H #define GNUNET_SERVICE_CORE_TYPEMAP_H #include "gnunet_util_lib.h" #include "gnunet_transport_service.h" /** * Map specifying which message types a peer supports. */ struct GSC_TypeMap; /** * Add a set of types to our type map. */ void GSC_TYPEMAP_add (const uint16_t * types, unsigned int tlen); /** * Remove a set of types from our type map. */ void GSC_TYPEMAP_remove (const uint16_t * types, unsigned int tlen); /** * Compute a type map message for this peer. * * @return this peers current type map message. */ struct GNUNET_MessageHeader * GSC_TYPEMAP_compute_type_map_message (void); /** * Extract a type map from a TYPE_MAP message. * * @param msg a type map message * @return NULL on error */ struct GSC_TypeMap * GSC_TYPEMAP_get_from_message (const struct GNUNET_MessageHeader *msg); /** * Test if any of the types from the types array is in the * given type map. * * @param tmap map to test * @param types array of types * @param tcnt number of entries in types * @return GNUNET_YES if a type is in the map, GNUNET_NO if not */ int GSC_TYPEMAP_test_match (const struct GSC_TypeMap *tmap, const uint16_t * types, unsigned int tcnt); /** * Add additional types to a given typemap. * * @param tmap map to extend (not changed) * @param types array of types to add * @param tcnt number of entries in types * @return updated type map (fresh copy) */ struct GSC_TypeMap * GSC_TYPEMAP_extend (const struct GSC_TypeMap *tmap, const uint16_t * types, unsigned int tcnt); /** * Create an empty type map. * * @return an empty type map */ struct GSC_TypeMap * GSC_TYPEMAP_create (void); /** * Free the given type map. * * @param tmap a type map */ void GSC_TYPEMAP_destroy (struct GSC_TypeMap *tmap); /** * Initialize typemap subsystem. */ void GSC_TYPEMAP_init (void); /** * Shutdown typemap subsystem. */ void GSC_TYPEMAP_done (void); #endif /* end of gnunet-service-core_typemap.h */ gnunet-0.9.3/src/core/gnunet-core.c0000644000175000017500000000574511760502550014071 00000000000000/* This file is part of GNUnet. (C) 2011, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file core/gnunet-core.c * @brief Print information about other known _connected_ peers. * @author Nathan Evans */ #include "platform.h" #include "gnunet_crypto_lib.h" #include "gnunet_configuration_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_peerinfo_service.h" #include "gnunet_transport_service.h" #include "gnunet_core_service.h" #include "gnunet_program_lib.h" /** * Callback for retrieving a list of connected peers. * * @param cls closure (unused) * @param peer peer identity this notification is about * @param atsi performance data for the connection * @param atsi_count number of records in 'atsi' */ static void connected_peer_callback (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct GNUNET_CRYPTO_HashAsciiEncoded enc; if (NULL == peer) return; GNUNET_CRYPTO_hash_to_enc (&peer->hashPubKey, &enc); printf (_("Peer `%s'\n"), (const char *) &enc); } /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param cfg configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { if (args[0] != NULL) { FPRINTF (stderr, _("Invalid command line argument `%s'\n"), args[0]); return; } GNUNET_CORE_iterate_peers (cfg, &connected_peer_callback, NULL); } /** * The main function to obtain peer information. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-core", gettext_noop ("Print information about connected peers."), options, &run, NULL)) ? 0 : 1; } /* end of gnunet-core.c */ gnunet-0.9.3/src/core/core_api_iterate_peers.c0000644000175000017500000001421211760515711016327 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file core/core_api_iterate_peers.c * @brief implementation of the peer_iterate function * @author Christian Grothoff * @author Nathan Evans */ #include "platform.h" #include "gnunet_core_service.h" #include "core.h" struct GNUNET_CORE_RequestContext { /** * Our connection to the service. */ struct GNUNET_CLIENT_Connection *client; /** * Handle for transmitting a request. */ struct GNUNET_CLIENT_TransmitHandle *th; /** * Function called with the peer. */ GNUNET_CORE_ConnectEventHandler peer_cb; /** * Peer to check for. */ struct GNUNET_PeerIdentity *peer; /** * Closure for peer_cb. */ void *cb_cls; }; /** * Receive reply from core service with information about a peer. * * @param cls our 'struct GNUNET_CORE_RequestContext *' * @param msg NULL on error or last entry */ static void receive_info (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_CORE_RequestContext *request_context = cls; const struct ConnectNotifyMessage *connect_message; uint32_t ats_count; uint16_t msize; /* Handle last message or error case, disconnect and clean up */ if ((msg == NULL) || ((ntohs (msg->type) == GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END) && (ntohs (msg->size) == sizeof (struct GNUNET_MessageHeader)))) { if (request_context->peer_cb != NULL) request_context->peer_cb (request_context->cb_cls, NULL, NULL, 0); GNUNET_CLIENT_disconnect (request_context->client); GNUNET_free (request_context); return; } msize = ntohs (msg->size); /* Handle incorrect message type or size, disconnect and clean up */ if ((ntohs (msg->type) != GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT) || (msize < sizeof (struct ConnectNotifyMessage))) { GNUNET_break (0); if (request_context->peer_cb != NULL) request_context->peer_cb (request_context->cb_cls, NULL, NULL, 0); GNUNET_CLIENT_disconnect (request_context->client); GNUNET_free (request_context); return; } connect_message = (const struct ConnectNotifyMessage *) msg; ats_count = ntohl (connect_message->ats_count); if (msize != sizeof (struct ConnectNotifyMessage) + ats_count * sizeof (struct GNUNET_ATS_Information)) { GNUNET_break (0); if (request_context->peer_cb != NULL) request_context->peer_cb (request_context->cb_cls, NULL, NULL, 0); GNUNET_CLIENT_disconnect (request_context->client); GNUNET_free (request_context); return; } /* Normal case */ if (request_context->peer_cb != NULL) request_context->peer_cb (request_context->cb_cls, &connect_message->peer, (const struct GNUNET_ATS_Information *) &connect_message[1], ats_count); GNUNET_CLIENT_receive (request_context->client, &receive_info, request_context, GNUNET_TIME_UNIT_FOREVER_REL); } /** * Function called to notify a client about the socket * begin ready to queue more data. "buf" will be * NULL and "size" zero if the socket was closed for * writing in the meantime. * * @param cls closure * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_request (void *cls, size_t size, void *buf) { struct GNUNET_MessageHeader *msg; struct GNUNET_PeerIdentity *peer = cls; int msize; if (peer == NULL) msize = sizeof (struct GNUNET_MessageHeader); else msize = sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_PeerIdentity); if ((size < msize) || (buf == NULL)) return 0; msg = (struct GNUNET_MessageHeader *) buf; msg->size = htons (msize); if (peer != NULL) { msg->type = htons (GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED); memcpy (&msg[1], peer, sizeof (struct GNUNET_PeerIdentity)); } else msg->type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS); return msize; } /** * Iterate over all currently connected peers. * Calls peer_cb with each connected peer, and then * once with NULL to indicate that all peers have * been handled. * * @param cfg configuration to use * @param peer_cb function to call with the peer information * @param cb_cls closure for peer_cb * * @return GNUNET_OK if iterating, GNUNET_SYSERR on error */ int GNUNET_CORE_iterate_peers (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_CORE_ConnectEventHandler peer_cb, void *cb_cls) { struct GNUNET_CORE_RequestContext *request_context; struct GNUNET_CLIENT_Connection *client; client = GNUNET_CLIENT_connect ("core", cfg); if (client == NULL) return GNUNET_SYSERR; request_context = GNUNET_malloc (sizeof (struct GNUNET_CORE_RequestContext)); request_context->client = client; request_context->peer_cb = peer_cb; request_context->cb_cls = cb_cls; request_context->th = GNUNET_CLIENT_notify_transmit_ready (client, sizeof (struct GNUNET_MessageHeader), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &transmit_request, NULL); GNUNET_CLIENT_receive (client, &receive_info, request_context, GNUNET_TIME_UNIT_FOREVER_REL); return GNUNET_OK; } /* end of core_api_iterate_peers.c */ gnunet-0.9.3/src/core/gnunet-service-core_neighbours.c0000644000175000017500000003416711760502550017754 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file core/gnunet-service-core_neighbours.c * @brief code for managing low-level 'plaintext' connections with transport (key exchange may or may not be done yet) * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" #include "gnunet-service-core.h" #include "gnunet-service-core_neighbours.h" #include "gnunet-service-core_kx.h" #include "gnunet-service-core_sessions.h" #include "gnunet_constants.h" /** * Message ready for transmission via transport service. This struct * is followed by the actual content of the message. */ struct NeighbourMessageEntry { /** * We keep messages in a doubly linked list. */ struct NeighbourMessageEntry *next; /** * We keep messages in a doubly linked list. */ struct NeighbourMessageEntry *prev; /** * By when are we supposed to transmit this message? */ struct GNUNET_TIME_Absolute deadline; /** * How long is the message? (number of bytes following the "struct * MessageEntry", but not including the size of "struct * MessageEntry" itself!) */ size_t size; }; /** * Data kept per transport-connected peer. */ struct Neighbour { /** * Head of the batched message queue (already ordered, transmit * starting with the head). */ struct NeighbourMessageEntry *message_head; /** * Tail of the batched message queue (already ordered, append new * messages to tail). */ struct NeighbourMessageEntry *message_tail; /** * Handle for pending requests for transmission to this peer * with the transport service. NULL if no request is pending. */ struct GNUNET_TRANSPORT_TransmitHandle *th; /** * Information about the key exchange with the other peer. */ struct GSC_KeyExchangeInfo *kxinfo; /** * Identity of the other peer. */ struct GNUNET_PeerIdentity peer; /** * ID of task used for re-trying plaintext scheduling. */ GNUNET_SCHEDULER_TaskIdentifier retry_plaintext_task; }; /** * Map of peer identities to 'struct Neighbour'. */ static struct GNUNET_CONTAINER_MultiHashMap *neighbours; /** * Transport service. */ static struct GNUNET_TRANSPORT_Handle *transport; /** * Find the entry for the given neighbour. * * @param peer identity of the neighbour * @return NULL if we are not connected, otherwise the * neighbour's entry. */ static struct Neighbour * find_neighbour (const struct GNUNET_PeerIdentity *peer) { if (NULL == neighbours) return NULL; return GNUNET_CONTAINER_multihashmap_get (neighbours, &peer->hashPubKey); } /** * Free the given entry for the neighbour. * * @param n neighbour to free */ static void free_neighbour (struct Neighbour *n) { struct NeighbourMessageEntry *m; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Destroying neighbour entry for peer `%4s'\n", GNUNET_i2s (&n->peer)); while (NULL != (m = n->message_head)) { GNUNET_CONTAINER_DLL_remove (n->message_head, n->message_tail, m); GNUNET_free (m); } if (NULL != n->th) { GNUNET_TRANSPORT_notify_transmit_ready_cancel (n->th); n->th = NULL; } GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# sessions terminated by transport disconnect"), 1, GNUNET_NO); GSC_SESSIONS_end (&n->peer); if (NULL != n->kxinfo) { GSC_KX_stop (n->kxinfo); n->kxinfo = NULL; } if (n->retry_plaintext_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (n->retry_plaintext_task); n->retry_plaintext_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (neighbours, &n->peer.hashPubKey, n)); GNUNET_STATISTICS_set (GSC_stats, gettext_noop ("# neighbour entries allocated"), GNUNET_CONTAINER_multihashmap_size (neighbours), GNUNET_NO); GNUNET_free (n); } /** * Check if we have encrypted messages for the specified neighbour * pending, and if so, check with the transport about sending them * out. * * @param n neighbour to check. */ static void process_queue (struct Neighbour *n); /** * Function called when the transport service is ready to receive a * message for the respective peer * * @param cls neighbour to use message from * @param size number of bytes we can transmit * @param buf where to copy the message * @return number of bytes transmitted */ static size_t transmit_ready (void *cls, size_t size, void *buf) { struct Neighbour *n = cls; struct NeighbourMessageEntry *m; size_t ret; char *cbuf; n->th = NULL; m = n->message_head; if (m == NULL) { GNUNET_break (0); return 0; } GNUNET_CONTAINER_DLL_remove (n->message_head, n->message_tail, m); if (buf == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission of message of type %u and size %u failed\n", (unsigned int) ntohs (((struct GNUNET_MessageHeader *) &m[1])->type), (unsigned int) m->size); GNUNET_free (m); process_queue (n); return 0; } cbuf = buf; GNUNET_assert (size >= m->size); memcpy (cbuf, &m[1], m->size); ret = m->size; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Copied message of type %u and size %u into transport buffer for `%4s'\n", (unsigned int) ntohs (((struct GNUNET_MessageHeader *) &m[1])->type), (unsigned int) ret, GNUNET_i2s (&n->peer)); GNUNET_free (m); process_queue (n); GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# encrypted bytes given to transport"), ret, GNUNET_NO); return ret; } /** * Check if we have messages for the specified neighbour pending, and * if so, check with the transport about sending them out. * * @param n neighbour to check. */ static void process_queue (struct Neighbour *n) { struct NeighbourMessageEntry *m; if (n->th != NULL) return; /* request already pending */ m = n->message_head; if (m == NULL) { /* notify sessions that the queue is empty and more messages * could thus be queued now */ GSC_SESSIONS_solicit (&n->peer); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking transport for transmission of %u bytes to `%4s' in next %llu ms\n", (unsigned int) m->size, GNUNET_i2s (&n->peer), (unsigned long long) GNUNET_TIME_absolute_get_remaining (m->deadline).rel_value); n->th = GNUNET_TRANSPORT_notify_transmit_ready (transport, &n->peer, m->size, 0, GNUNET_TIME_absolute_get_remaining (m->deadline), &transmit_ready, n); if (n->th != NULL) return; /* message request too large or duplicate request */ GNUNET_break (0); /* discard encrypted message */ GNUNET_CONTAINER_DLL_remove (n->message_head, n->message_tail, m); GNUNET_free (m); process_queue (n); } /** * Function called by transport to notify us that * a peer connected to us (on the network level). * * @param cls closure * @param peer the peer that connected * @param atsi performance data * @param atsi_count number of entries in ats (excluding 0-termination) */ static void handle_transport_notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, uint32_t atsi_count) { struct Neighbour *n; if (0 == memcmp (peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity))) { GNUNET_break (0); return; } n = find_neighbour (peer); if (n != NULL) { /* duplicate connect notification!? */ GNUNET_break (0); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received connection from `%4s'.\n", GNUNET_i2s (peer)); n = GNUNET_malloc (sizeof (struct Neighbour)); n->peer = *peer; GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (neighbours, &n->peer.hashPubKey, n, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); GNUNET_STATISTICS_set (GSC_stats, gettext_noop ("# neighbour entries allocated"), GNUNET_CONTAINER_multihashmap_size (neighbours), GNUNET_NO); n->kxinfo = GSC_KX_start (peer); } /** * Function called by transport telling us that a peer * disconnected. * * @param cls closure * @param peer the peer that disconnected */ static void handle_transport_notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { struct Neighbour *n; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' disconnected from us; received notification from transport.\n", GNUNET_i2s (peer)); n = find_neighbour (peer); if (n == NULL) { GNUNET_break (0); return; } free_neighbour (n); } /** * Function called by the transport for each received message. * * @param cls closure * @param peer (claimed) identity of the other peer * @param message the message * @param atsi performance data * @param atsi_count number of entries in ats (excluding 0-termination) */ static void handle_transport_receive (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, uint32_t atsi_count) { struct Neighbour *n; uint16_t type; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received message of type %u from `%4s', demultiplexing.\n", (unsigned int) ntohs (message->type), GNUNET_i2s (peer)); if (0 == memcmp (peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity))) { GNUNET_break (0); return; } n = find_neighbour (peer); if (n == NULL) { /* received message from peer that is not connected!? */ GNUNET_break (0); return; } type = ntohs (message->type); switch (type) { case GNUNET_MESSAGE_TYPE_CORE_SET_KEY: GSC_KX_handle_set_key (n->kxinfo, message); break; case GNUNET_MESSAGE_TYPE_CORE_PING: GSC_KX_handle_ping (n->kxinfo, message); break; case GNUNET_MESSAGE_TYPE_CORE_PONG: GSC_KX_handle_pong (n->kxinfo, message); break; case GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE: GSC_KX_handle_encrypted_message (n->kxinfo, message, atsi, atsi_count); break; default: GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Unsupported message of type %u (%u bytes) received from peer `%s'\n"), (unsigned int) type, (unsigned int) ntohs (message->size), GNUNET_i2s (peer)); return; } } /** * Transmit the given message to the given target. * * @param target peer that should receive the message (must be connected) * @param msg message to transmit * @param timeout by when should the transmission be done? */ void GSC_NEIGHBOURS_transmit (const struct GNUNET_PeerIdentity *target, const struct GNUNET_MessageHeader *msg, struct GNUNET_TIME_Relative timeout) { struct NeighbourMessageEntry *me; struct Neighbour *n; size_t msize; n = find_neighbour (target); if (NULL == n) { GNUNET_break (0); return; } msize = ntohs (msg->size); me = GNUNET_malloc (sizeof (struct NeighbourMessageEntry) + msize); me->deadline = GNUNET_TIME_relative_to_absolute (timeout); me->size = msize; memcpy (&me[1], msg, msize); GNUNET_CONTAINER_DLL_insert_tail (n->message_head, n->message_tail, me); process_queue (n); } /** * Initialize neighbours subsystem. */ int GSC_NEIGHBOURS_init () { neighbours = GNUNET_CONTAINER_multihashmap_create (128); transport = GNUNET_TRANSPORT_connect (GSC_cfg, &GSC_my_identity, NULL, &handle_transport_receive, &handle_transport_notify_connect, &handle_transport_notify_disconnect); if (NULL == transport) { GNUNET_CONTAINER_multihashmap_destroy (neighbours); neighbours = NULL; return GNUNET_SYSERR; } return GNUNET_OK; } /** * Wrapper around 'free_neighbour'. * * @param cls unused * @param key peer identity * @param value the 'struct Neighbour' to free * @return GNUNET_OK (continue to iterate) */ static int free_neighbour_helper (void *cls, const GNUNET_HashCode * key, void *value) { struct Neighbour *n = value; /* transport should have 'disconnected' all neighbours... */ GNUNET_break (0); free_neighbour (n); return GNUNET_OK; } /** * Shutdown neighbours subsystem. */ void GSC_NEIGHBOURS_done () { if (NULL == transport) return; GNUNET_TRANSPORT_disconnect (transport); transport = NULL; GNUNET_CONTAINER_multihashmap_iterate (neighbours, &free_neighbour_helper, NULL); GNUNET_CONTAINER_multihashmap_destroy (neighbours); neighbours = NULL; } /* end of gnunet-service-core_neighbours.c */ gnunet-0.9.3/src/core/test_core_quota_peer2.conf0000644000175000017500000000150511751071052016627 00000000000000@INLINE@ test_core_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-core-quota-sym-peer-2/ DEFAULTCONFIG = test_core_quota_peer2.conf [arm] PORT = 22476 UNIXPATH = /tmp/gnunet-core-sym-p2-service-arm.sock [statistics] PORT = 22477 UNIXPATH = /tmp/gnunet-core-sym-p2-service-statistics.sock [resolver] PORT = 22474 UNIXPATH = /tmp/gnunet-core-sym-p2-service-resolver.sock [peerinfo] PORT = 22479 UNIXPATH = /tmp/gnunet-core-sym-p2-service-peerinfo.sock [transport] PORT = 22475 UNIXPATH = /tmp/gnunet-core-sym-p2-service-transport.sock [core] PORT = 22480 UNIXPATH = /tmp/gnunet-core-sym-p2-service-core.sock DEBUG = NO [ats] PORT = 22482 UNIXPATH = /tmp/gnunet-core-sym-p2-service-ats.sock WAN_QUOTA_IN = 10 kiB WAN_QUOTA_OUT = 10 kiB [transport-tcp] PORT = 22467 [transport-unix] PORT = 22468 [transport-http] PORT = 22469gnunet-0.9.3/src/core/test_core_api_reliability.c0000644000175000017500000003526511760502550017054 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file core/test_core_api_reliability.c * @brief testcase for core_api.c focusing on reliable transmission (with TCP) */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_constants.h" #include "gnunet_arm_service.h" #include "gnunet_core_service.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_transport_service.h" #include #define START_ARM GNUNET_YES /** * Note that this value must not significantly exceed * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise * messages may be dropped even for a reliable transport. */ #define TOTAL_MSGS (600 * 10) /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 6000) /** * What delay do we request from the core service for transmission? */ #define FAST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) #define MTYPE 12345 static unsigned long long total_bytes; static struct GNUNET_TIME_Absolute start_time; static GNUNET_SCHEDULER_TaskIdentifier err_task; static GNUNET_SCHEDULER_TaskIdentifier connect_task; struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_CORE_Handle *ch; struct GNUNET_PeerIdentity id; struct GNUNET_TRANSPORT_Handle *th; struct GNUNET_MessageHeader *hello; struct GNUNET_TRANSPORT_GetHelloHandle *ghh; int connect_status; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static struct PeerContext p1; static struct PeerContext p2; static int ok; static int32_t tr_n; #define OKPP do { ok++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) struct TestMessage { struct GNUNET_MessageHeader header; uint32_t num; }; static unsigned int get_size (unsigned int iter) { unsigned int ret; if (iter < 60000) return iter + sizeof (struct TestMessage); ret = (iter * iter * iter); return sizeof (struct TestMessage) + (ret % 60000); } static void process_hello (void *cls, const struct GNUNET_MessageHeader *message); static void terminate_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { unsigned long long delta; GNUNET_TRANSPORT_get_hello_cancel (p1.ghh); GNUNET_TRANSPORT_get_hello_cancel (p2.ghh); GNUNET_CORE_disconnect (p1.ch); p1.ch = NULL; GNUNET_CORE_disconnect (p2.ch); p2.ch = NULL; if (connect_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (connect_task); GNUNET_TRANSPORT_disconnect (p1.th); p1.th = NULL; GNUNET_TRANSPORT_disconnect (p2.th); p2.th = NULL; delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value; FPRINTF (stderr, "\nThroughput was %llu kb/s\n", total_bytes * 1000 / 1024 / delta); GAUGER ("CORE", "Core throughput/s", total_bytes * 1000 / 1024 / delta, "kb/s"); ok = 0; } static void terminate_task_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_break (0); if (p1.ch != NULL) { GNUNET_CORE_disconnect (p1.ch); p1.ch = NULL; } if (p2.ch != NULL) { GNUNET_CORE_disconnect (p2.ch); p2.ch = NULL; } if (connect_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (connect_task); if (p1.th != NULL) { GNUNET_TRANSPORT_get_hello_cancel (p1.ghh); GNUNET_TRANSPORT_disconnect (p1.th); p1.th = NULL; } if (p2.th != NULL) { GNUNET_TRANSPORT_get_hello_cancel (p2.ghh); GNUNET_TRANSPORT_disconnect (p2.th); p2.th = NULL; } ok = 42; } static void try_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { connect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &try_connect, NULL); GNUNET_TRANSPORT_try_connect (p1.th, &p2.id); } static size_t transmit_ready (void *cls, size_t size, void *buf) { char *cbuf = buf; struct TestMessage hdr; unsigned int s; unsigned int ret; GNUNET_assert (size <= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE); if (buf == NULL) { if (p1.ch != NULL) GNUNET_break (NULL != GNUNET_CORE_notify_transmit_ready (p1.ch, GNUNET_NO, 0, FAST_TIMEOUT, &p2.id, get_size (tr_n), &transmit_ready, &p1)); return 0; } GNUNET_assert (tr_n < TOTAL_MSGS); ret = 0; s = get_size (tr_n); GNUNET_assert (size >= s); GNUNET_assert (buf != NULL); cbuf = buf; do { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message %u of size %u at offset %u\n", tr_n, s, ret); hdr.header.size = htons (s); hdr.header.type = htons (MTYPE); hdr.num = htonl (tr_n); memcpy (&cbuf[ret], &hdr, sizeof (struct TestMessage)); ret += sizeof (struct TestMessage); memset (&cbuf[ret], tr_n, s - sizeof (struct TestMessage)); ret += s - sizeof (struct TestMessage); tr_n++; s = get_size (tr_n); if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16)) break; /* sometimes pack buffer full, sometimes not */ } while (size - ret >= s); GNUNET_SCHEDULER_cancel (err_task); err_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &terminate_task_error, NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Returning total message block of size %u\n", ret); total_bytes += ret; return ret; } static void connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct PeerContext *pc = cls; if (0 == memcmp (&pc->id, peer, sizeof (struct GNUNET_PeerIdentity))) return; GNUNET_assert (pc->connect_status == 0); pc->connect_status = 1; if (pc == &p1) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypted connection established to peer `%4s'\n", GNUNET_i2s (peer)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking core (1) for transmission to peer `%4s'\n", GNUNET_i2s (&p2.id)); GNUNET_SCHEDULER_cancel (err_task); err_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &terminate_task_error, NULL); start_time = GNUNET_TIME_absolute_get (); GNUNET_break (NULL != GNUNET_CORE_notify_transmit_ready (p1.ch, GNUNET_NO, 0, TIMEOUT, &p2.id, get_size (0), &transmit_ready, &p1)); } } static void disconnect_notify (void *cls, const struct GNUNET_PeerIdentity *peer) { struct PeerContext *pc = cls; if (0 == memcmp (&pc->id, peer, sizeof (struct GNUNET_PeerIdentity))) return; pc->connect_status = 0; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypted connection to `%4s' cut\n", GNUNET_i2s (peer)); } static int inbound_notify (void *cls, const struct GNUNET_PeerIdentity *other, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core provides inbound data from `%4s'.\n", GNUNET_i2s (other)); return GNUNET_OK; } static int outbound_notify (void *cls, const struct GNUNET_PeerIdentity *other, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core notifies about outbound data for `%4s'.\n", GNUNET_i2s (other)); return GNUNET_OK; } static size_t transmit_ready (void *cls, size_t size, void *buf); static int process_mtype (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { static int n; unsigned int s; const struct TestMessage *hdr; hdr = (const struct TestMessage *) message; s = get_size (n); if (MTYPE != ntohs (message->type)) return GNUNET_SYSERR; if (ntohs (message->size) != s) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected message %u of size %u, got %u bytes of message %u\n", n, s, ntohs (message->size), ntohl (hdr->num)); GNUNET_SCHEDULER_cancel (err_task); err_task = GNUNET_SCHEDULER_add_now (&terminate_task_error, NULL); return GNUNET_SYSERR; } if (ntohl (hdr->num) != n) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected message %u of size %u, got %u bytes of message %u\n", n, s, ntohs (message->size), ntohl (hdr->num)); GNUNET_SCHEDULER_cancel (err_task); err_task = GNUNET_SCHEDULER_add_now (&terminate_task_error, NULL); return GNUNET_SYSERR; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got message %u of size %u\n", ntohl (hdr->num), ntohs (message->size)); n++; if (0 == (n % (TOTAL_MSGS / 100))) FPRINTF (stderr, "%s", "."); if (n == TOTAL_MSGS) { GNUNET_SCHEDULER_cancel (err_task); GNUNET_SCHEDULER_add_now (&terminate_task, NULL); } else { if (n == tr_n) GNUNET_break (NULL != GNUNET_CORE_notify_transmit_ready (p1.ch, GNUNET_NO, 0, FAST_TIMEOUT, &p2.id, get_size (tr_n), &transmit_ready, &p1)); } return GNUNET_OK; } static struct GNUNET_CORE_MessageHandler handlers[] = { {&process_mtype, MTYPE, 0}, {NULL, 0, 0} }; static void init_notify (void *cls, struct GNUNET_CORE_Handle *server, const struct GNUNET_PeerIdentity *my_identity) { struct PeerContext *p = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection to CORE service of `%4s' established\n", GNUNET_i2s (my_identity)); GNUNET_assert (server != NULL); p->id = *my_identity; p->ch = server; if (cls == &p1) { GNUNET_assert (ok == 2); OKPP; /* connect p2 */ GNUNET_CORE_connect (p2.cfg, 1, &p2, &init_notify, &connect_notify, &disconnect_notify, &inbound_notify, GNUNET_YES, &outbound_notify, GNUNET_YES, handlers); } else { GNUNET_assert (ok == 3); OKPP; GNUNET_assert (cls == &p2); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking transport (1) to connect to peer `%4s'\n", GNUNET_i2s (&p2.id)); connect_task = GNUNET_SCHEDULER_add_now (&try_connect, NULL); } } static void process_hello (void *cls, const struct GNUNET_MessageHeader *message) { struct PeerContext *p = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received (my) `%s' from transport service\n", "HELLO"); GNUNET_assert (message != NULL); p->hello = GNUNET_malloc (ntohs (message->size)); memcpy (p->hello, message, ntohs (message->size)); if ((p == &p1) && (p2.th != NULL)) GNUNET_TRANSPORT_offer_hello (p2.th, message, NULL, NULL); if ((p == &p2) && (p1.th != NULL)) GNUNET_TRANSPORT_offer_hello (p1.th, message, NULL, NULL); if ((p == &p1) && (p2.hello != NULL)) GNUNET_TRANSPORT_offer_hello (p1.th, p2.hello, NULL, NULL); if ((p == &p2) && (p1.hello != NULL)) GNUNET_TRANSPORT_offer_hello (p2.th, p1.hello, NULL, NULL); } static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p, NULL, NULL, NULL); GNUNET_assert (p->th != NULL); p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &process_hello, p); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { GNUNET_assert (ok == 1); OKPP; setup_peer (&p1, "test_core_api_peer1.conf"); setup_peer (&p2, "test_core_api_peer2.conf"); err_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &terminate_task_error, NULL); GNUNET_CORE_connect (p1.cfg, 1, &p1, &init_notify, &connect_notify, &disconnect_notify, &inbound_notify, GNUNET_YES, &outbound_notify, GNUNET_YES, handlers); } static void stop_arm (struct PeerContext *p) { #if START_ARM if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; #endif GNUNET_CONFIGURATION_destroy (p->cfg); } static int check () { char *const argv[] = { "test-core-api-reliability", "-c", "test_core_api_data.conf", NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; ok = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-core-api-reliability", "nohelp", options, &run, &ok); stop_arm (&p1); stop_arm (&p2); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-core-api", "WARNING", NULL); ret = check (); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-1"); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-2"); return ret; } /* end of test_core_api_reliability.c */ gnunet-0.9.3/src/core/test_core_defaults.conf0000644000175000017500000000132011760504301016201 00000000000000[PATHS] SERVICEHOME = /tmp/test-gnunet-core/ DEFAULTCONFIG = test_core_defaults.conf [arm] DEFAULTSERVICES = [nat] DISABLEV6 = YES ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 USE_LOCALADDR = NO [ats] WAN_QUOTA_IN = 1 GB WAN_QUOTA_OUT = 1 GB [core] PORT = 12470 UNIXPATH = /tmp/gnunet-p1-service-core.sock [transport-tcp] BINDTO = 127.0.0.1 [testing] WEAKRANDOM = YES [fs] AUTOSTART = NO [datastore] AUTOSTART = NO [dht] AUTOSTART = NO [mesh] AUTOSTART = NO [dns] AUTOSTART = NO [nse] AUTOSTART = NO [dv] AUTOSTART = NO [chat] AUTOSTART = NO [gns] AUTOSTART = NO [vpn] AUTOSTART = NO [namestore] AUTOSTART = NO [lockmanager] AUTOSTART = NO gnunet-0.9.3/src/core/core_api_is_connected.c0000644000175000017500000001501011760515724016132 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file core/core_api_is_connected.c * @brief implementation of the 'GNUNET_CORE_is_peer_connected function * @author Christian Grothoff * @author Nathan Evans * * TODO: * - define nice structs for the IPC messages in core.h * - consider NOT always sending the 'END' message -- it is redundant! */ #include "platform.h" #include "gnunet_core_service.h" #include "core.h" /** * Closure for 'transmit_is_connected_request" */ struct GNUNET_CORE_ConnectTestHandle { /** * Our connection to the service. */ struct GNUNET_CLIENT_Connection *client; /** * Handle for transmitting a request. */ struct GNUNET_CLIENT_TransmitHandle *th; /** * Function called with the peer. */ GNUNET_CORE_ConnectEventHandler peer_cb; /** * Peer to check for. */ struct GNUNET_PeerIdentity peer; /** * Closure for peer_cb. */ void *cb_cls; }; /** * Receive reply from core service with information about a peer. * * @param cls our 'struct GNUNET_CORE_RequestContext *' * @param msg NULL on error or last entry */ static void receive_connect_info (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_CORE_ConnectTestHandle *cth = cls; const struct ConnectNotifyMessage *connect_message; uint32_t ats_count; uint16_t msize; if (NULL == msg) { /* core died, failure */ cth->peer_cb (cth->cb_cls, NULL, NULL, 0); GNUNET_CORE_is_peer_connected_cancel (cth); return; } if ((ntohs (msg->type) == GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END) && (ntohs (msg->size) == sizeof (struct GNUNET_MessageHeader))) { /* end of transmissions */ cth->peer_cb (cth->cb_cls, NULL, NULL, 0); GNUNET_CORE_is_peer_connected_cancel (cth); return; } msize = ntohs (msg->size); /* Handle incorrect message type or size, disconnect and clean up */ if ((ntohs (msg->type) != GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT) || (msize < sizeof (struct ConnectNotifyMessage))) { GNUNET_break (0); cth->peer_cb (cth->cb_cls, NULL, NULL, 0); GNUNET_CORE_is_peer_connected_cancel (cth); return; } connect_message = (const struct ConnectNotifyMessage *) msg; ats_count = ntohl (connect_message->ats_count); if (msize != sizeof (struct ConnectNotifyMessage) + ats_count * sizeof (struct GNUNET_ATS_Information)) { GNUNET_break (0); cth->peer_cb (cth->cb_cls, NULL, NULL, 0); GNUNET_CORE_is_peer_connected_cancel (cth); return; } /* Normal case */ cth->peer_cb (cth->cb_cls, &connect_message->peer, (const struct GNUNET_ATS_Information *) &connect_message[1], ats_count); GNUNET_CLIENT_receive (cth->client, &receive_connect_info, cth, GNUNET_TIME_UNIT_FOREVER_REL); } /** * Function called to notify a client about the socket * begin ready to queue more data. "buf" will be * NULL and "size" zero if the socket was closed for * writing in the meantime. * * @param cls closure * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_is_connected_request (void *cls, size_t size, void *buf) { struct GNUNET_CORE_ConnectTestHandle *cth = cls; struct GNUNET_MessageHeader *msg; unsigned int msize; cth->th = NULL; msize = sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_PeerIdentity); if ( (NULL == buf) || (0 == size) ) { cth->peer_cb (cth->cb_cls, NULL, NULL, 0); GNUNET_CLIENT_disconnect (cth->client); GNUNET_free (cth); return 0; } GNUNET_assert (size >= msize); msg = (struct GNUNET_MessageHeader *) buf; msg->size = htons (msize); msg->type = htons (GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED); memcpy (&msg[1], &cth->peer, sizeof (struct GNUNET_PeerIdentity)); GNUNET_CLIENT_receive (cth->client, &receive_connect_info, cth, GNUNET_TIME_UNIT_FOREVER_REL); return msize; } /** * Iterate over all currently connected peers. * Calls peer_cb with each connected peer, and then * once with NULL to indicate that all peers have * been handled. * * @param cfg configuration to use * @param peer the specific peer to check for * @param peer_cb function to call with the peer information * @param cb_cls closure for peer_cb * * @return GNUNET_OK if iterating, GNUNET_SYSERR on error */ struct GNUNET_CORE_ConnectTestHandle * GNUNET_CORE_is_peer_connected (const struct GNUNET_CONFIGURATION_Handle *cfg, const struct GNUNET_PeerIdentity *peer, GNUNET_CORE_ConnectEventHandler peer_cb, void *cb_cls) { struct GNUNET_CORE_ConnectTestHandle *cth; struct GNUNET_CLIENT_Connection *client; GNUNET_assert (NULL != peer); GNUNET_assert (NULL != peer_cb); client = GNUNET_CLIENT_connect ("core", cfg); if (NULL == client) return NULL; cth = GNUNET_malloc (sizeof (struct GNUNET_CORE_ConnectTestHandle)); cth->peer = *peer; cth->client = client; cth->peer_cb = peer_cb; cth->cb_cls = cb_cls; cth->th = GNUNET_CLIENT_notify_transmit_ready (client, sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_PeerIdentity), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &transmit_is_connected_request, cth); GNUNET_assert (NULL != cth->th); return cth; } /** * Abort 'is_connected' test operation. * * @param cth handle for operation to cancel */ void GNUNET_CORE_is_peer_connected_cancel (struct GNUNET_CORE_ConnectTestHandle *cth) { if (NULL != cth->th) { GNUNET_CLIENT_notify_transmit_ready_cancel (cth->th); cth->th = NULL; } GNUNET_CLIENT_disconnect (cth->client); GNUNET_free (cth); } /* end of core_api_is_connected.c */ gnunet-0.9.3/src/core/gnunet-service-core_kx.h0000644000175000017500000000723411760502551016232 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file core/gnunet-service-core_kx.h * @brief code for managing the key exchange (SET_KEY, PING, PONG) with other peers * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_CORE_KX_H #define GNUNET_SERVICE_CORE_KX_H #include "gnunet_util_lib.h" #include "gnunet_transport_service.h" /** * Information about the status of a key exchange with another peer. */ struct GSC_KeyExchangeInfo; /** * We received a SET_KEY message. Validate and update * our key material and status. * * @param kx key exchange status for the corresponding peer * @param msg the set key message we received */ void GSC_KX_handle_set_key (struct GSC_KeyExchangeInfo *kx, const struct GNUNET_MessageHeader *msg); /** * We received a PING message. Validate and transmit * a PONG message. * * @param kx key exchange status for the corresponding peer * @param msg the encrypted PING message itself */ void GSC_KX_handle_ping (struct GSC_KeyExchangeInfo *kx, const struct GNUNET_MessageHeader *msg); /** * We received a PONG message. Validate and update our status. * * @param kx key exchange status for the corresponding peer * @param msg the encrypted PONG message itself */ void GSC_KX_handle_pong (struct GSC_KeyExchangeInfo *kx, const struct GNUNET_MessageHeader *msg); /** * Encrypt and transmit a message with the given payload. * * @param kx key exchange context * @param payload payload of the message * @param payload_size number of bytes in 'payload' */ void GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx, const void *payload, size_t payload_size); /** * We received an encrypted message. Decrypt, validate and * pass on to the appropriate clients. * * @param kx key exchange information context * @param msg encrypted message * @param atsi performance data * @param atsi_count number of entries in ats (excluding 0-termination) */ void GSC_KX_handle_encrypted_message (struct GSC_KeyExchangeInfo *kx, const struct GNUNET_MessageHeader *msg, const struct GNUNET_ATS_Information *atsi, uint32_t atsi_count); /** * Start the key exchange with the given peer. * * @param pid identity of the peer to do a key exchange with * @return key exchange information context */ struct GSC_KeyExchangeInfo * GSC_KX_start (const struct GNUNET_PeerIdentity *pid); /** * Stop key exchange with the given peer. Clean up key material. * * @param kx key exchange to stop */ void GSC_KX_stop (struct GSC_KeyExchangeInfo *kx); /** * Initialize KX subsystem. * * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int GSC_KX_init (void); /** * Shutdown KX subsystem. */ void GSC_KX_done (void); #endif /* end of gnunet-service-core_kx.h */ gnunet-0.9.3/src/core/test_core_api_peer1.conf0000644000175000017500000000102211723125510016236 00000000000000@INLINE@ test_core_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-core-peer-1/ DEFAULTCONFIG = test_core_api_peer1.conf [transport-tcp] PORT = 12468 [arm] PORT = 12466 UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12467 [resolver] PORT = 12464 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12469 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12465 UNIXPATH = /tmp/gnunet-p1-service-transport.sock [ats] PORT = 12471 UNIXPATH = /tmp/gnunet-p1-service-ats.sock gnunet-0.9.3/src/core/Makefile.in0000644000175000017500000011437211762217210013537 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-service-core$(EXEEXT) gnunet-core$(EXEEXT) check_PROGRAMS = test_core_api_start_only$(EXEEXT) \ test_core_api$(EXEEXT) test_core_api_reliability$(EXEEXT) \ test_core_quota_compliance_symmetric$(EXEEXT) \ test_core_quota_compliance_asymmetric_send_limited$(EXEEXT) \ test_core_quota_compliance_asymmetric_recv_limited$(EXEEXT) \ test_core_api_send_to_self$(EXEEXT) subdir = src/core DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/core.conf.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = core.conf CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libgnunetcore_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am_libgnunetcore_la_OBJECTS = core_api.lo core_api_iterate_peers.lo \ core_api_is_connected.lo libgnunetcore_la_OBJECTS = $(am_libgnunetcore_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunetcore_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetcore_la_LDFLAGS) $(LDFLAGS) \ -o $@ PROGRAMS = $(bin_PROGRAMS) am_gnunet_core_OBJECTS = gnunet-core.$(OBJEXT) gnunet_core_OBJECTS = $(am_gnunet_core_OBJECTS) am_gnunet_service_core_OBJECTS = gnunet-service-core.$(OBJEXT) \ gnunet-service-core_clients.$(OBJEXT) \ gnunet-service-core_neighbours.$(OBJEXT) \ gnunet-service-core_kx.$(OBJEXT) \ gnunet-service-core_sessions.$(OBJEXT) \ gnunet-service-core_typemap.$(OBJEXT) gnunet_service_core_OBJECTS = $(am_gnunet_service_core_OBJECTS) gnunet_service_core_DEPENDENCIES = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_test_core_api_OBJECTS = test_core_api.$(OBJEXT) test_core_api_OBJECTS = $(am_test_core_api_OBJECTS) test_core_api_DEPENDENCIES = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_core_api_reliability_OBJECTS = \ test_core_api_reliability.$(OBJEXT) test_core_api_reliability_OBJECTS = \ $(am_test_core_api_reliability_OBJECTS) test_core_api_reliability_DEPENDENCIES = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_core_api_send_to_self_OBJECTS = \ test_core_api_send_to_self.$(OBJEXT) test_core_api_send_to_self_OBJECTS = \ $(am_test_core_api_send_to_self_OBJECTS) test_core_api_send_to_self_DEPENDENCIES = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_core_api_start_only_OBJECTS = \ test_core_api_start_only.$(OBJEXT) test_core_api_start_only_OBJECTS = \ $(am_test_core_api_start_only_OBJECTS) test_core_api_start_only_DEPENDENCIES = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_core_quota_compliance_asymmetric_recv_limited_OBJECTS = \ test_core_quota_compliance.$(OBJEXT) test_core_quota_compliance_asymmetric_recv_limited_OBJECTS = $(am_test_core_quota_compliance_asymmetric_recv_limited_OBJECTS) test_core_quota_compliance_asymmetric_recv_limited_DEPENDENCIES = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la am_test_core_quota_compliance_asymmetric_send_limited_OBJECTS = \ test_core_quota_compliance.$(OBJEXT) test_core_quota_compliance_asymmetric_send_limited_OBJECTS = $(am_test_core_quota_compliance_asymmetric_send_limited_OBJECTS) test_core_quota_compliance_asymmetric_send_limited_DEPENDENCIES = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la am_test_core_quota_compliance_symmetric_OBJECTS = \ test_core_quota_compliance.$(OBJEXT) test_core_quota_compliance_symmetric_OBJECTS = \ $(am_test_core_quota_compliance_symmetric_OBJECTS) test_core_quota_compliance_symmetric_DEPENDENCIES = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunetcore_la_SOURCES) $(gnunet_core_SOURCES) \ $(gnunet_service_core_SOURCES) $(test_core_api_SOURCES) \ $(test_core_api_reliability_SOURCES) \ $(test_core_api_send_to_self_SOURCES) \ $(test_core_api_start_only_SOURCES) \ $(test_core_quota_compliance_asymmetric_recv_limited_SOURCES) \ $(test_core_quota_compliance_asymmetric_send_limited_SOURCES) \ $(test_core_quota_compliance_symmetric_SOURCES) DIST_SOURCES = $(libgnunetcore_la_SOURCES) $(gnunet_core_SOURCES) \ $(gnunet_service_core_SOURCES) $(test_core_api_SOURCES) \ $(test_core_api_reliability_SOURCES) \ $(test_core_api_send_to_self_SOURCES) \ $(test_core_api_start_only_SOURCES) \ $(test_core_quota_compliance_asymmetric_recv_limited_SOURCES) \ $(test_core_quota_compliance_asymmetric_send_limited_SOURCES) \ $(test_core_quota_compliance_symmetric_SOURCES) DATA = $(pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include pkgcfgdir = $(pkgdatadir)/config.d/ pkgcfg_DATA = \ core.conf @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @USE_COVERAGE_TRUE@XLIB = -lgcov lib_LTLIBRARIES = \ libgnunetcore.la libgnunetcore_la_SOURCES = \ core_api.c core.h \ core_api_iterate_peers.c \ core_api_is_connected.c libgnunetcore_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) $(XLIB) libgnunetcore_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 0:0:0 gnunet_service_core_SOURCES = \ gnunet-service-core.c gnunet-service-core.h \ gnunet-service-core_clients.c gnunet-service-core_clients.h \ gnunet-service-core_neighbours.c gnunet-service-core_neighbours.h \ gnunet-service-core_kx.c gnunet-service-core_kx.h \ gnunet-service-core_sessions.c gnunet-service-core_sessions.h \ gnunet-service-core_typemap.c gnunet-service-core_typemap.h gnunet_service_core_LDADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) -lz gnunet_core_SOURCES = \ gnunet-core.c gnunet_core_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la gnunet_core_DEPENDENCIES = \ libgnunetcore.la @ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) test_core_api_SOURCES = \ test_core_api.c test_core_api_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la test_core_api_reliability_SOURCES = \ test_core_api_reliability.c test_core_api_reliability_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la test_core_api_send_to_self_SOURCES = \ test_core_api_send_to_self.c test_core_api_send_to_self_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la test_core_api_start_only_SOURCES = \ test_core_api_start_only.c test_core_api_start_only_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_core_quota_compliance_symmetric_SOURCES = \ test_core_quota_compliance.c test_core_quota_compliance_symmetric_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la test_core_quota_compliance_asymmetric_send_limited_SOURCES = \ test_core_quota_compliance.c test_core_quota_compliance_asymmetric_send_limited_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la test_core_quota_compliance_asymmetric_recv_limited_SOURCES = \ test_core_quota_compliance.c test_core_quota_compliance_asymmetric_recv_limited_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la EXTRA_DIST = \ test_core_defaults.conf \ test_core_api_data.conf \ test_core_api_peer1.conf \ test_core_api_peer2.conf \ test_core_api_send_to_self.conf \ test_core_quota_asymmetric_recv_limited_peer1.conf \ test_core_quota_asymmetric_recv_limited_peer2.conf \ test_core_quota_asymmetric_send_limit_peer1.conf \ test_core_quota_asymmetric_send_limit_peer2.conf \ test_core_quota_peer1.conf \ test_core_quota_peer2.conf all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/core/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/core/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): core.conf: $(top_builddir)/config.status $(srcdir)/core.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunetcore.la: $(libgnunetcore_la_OBJECTS) $(libgnunetcore_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetcore_la_LINK) -rpath $(libdir) $(libgnunetcore_la_OBJECTS) $(libgnunetcore_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-core$(EXEEXT): $(gnunet_core_OBJECTS) $(gnunet_core_DEPENDENCIES) @rm -f gnunet-core$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_core_OBJECTS) $(gnunet_core_LDADD) $(LIBS) gnunet-service-core$(EXEEXT): $(gnunet_service_core_OBJECTS) $(gnunet_service_core_DEPENDENCIES) @rm -f gnunet-service-core$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_service_core_OBJECTS) $(gnunet_service_core_LDADD) $(LIBS) test_core_api$(EXEEXT): $(test_core_api_OBJECTS) $(test_core_api_DEPENDENCIES) @rm -f test_core_api$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_core_api_OBJECTS) $(test_core_api_LDADD) $(LIBS) test_core_api_reliability$(EXEEXT): $(test_core_api_reliability_OBJECTS) $(test_core_api_reliability_DEPENDENCIES) @rm -f test_core_api_reliability$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_core_api_reliability_OBJECTS) $(test_core_api_reliability_LDADD) $(LIBS) test_core_api_send_to_self$(EXEEXT): $(test_core_api_send_to_self_OBJECTS) $(test_core_api_send_to_self_DEPENDENCIES) @rm -f test_core_api_send_to_self$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_core_api_send_to_self_OBJECTS) $(test_core_api_send_to_self_LDADD) $(LIBS) test_core_api_start_only$(EXEEXT): $(test_core_api_start_only_OBJECTS) $(test_core_api_start_only_DEPENDENCIES) @rm -f test_core_api_start_only$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_core_api_start_only_OBJECTS) $(test_core_api_start_only_LDADD) $(LIBS) test_core_quota_compliance_asymmetric_recv_limited$(EXEEXT): $(test_core_quota_compliance_asymmetric_recv_limited_OBJECTS) $(test_core_quota_compliance_asymmetric_recv_limited_DEPENDENCIES) @rm -f test_core_quota_compliance_asymmetric_recv_limited$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_core_quota_compliance_asymmetric_recv_limited_OBJECTS) $(test_core_quota_compliance_asymmetric_recv_limited_LDADD) $(LIBS) test_core_quota_compliance_asymmetric_send_limited$(EXEEXT): $(test_core_quota_compliance_asymmetric_send_limited_OBJECTS) $(test_core_quota_compliance_asymmetric_send_limited_DEPENDENCIES) @rm -f test_core_quota_compliance_asymmetric_send_limited$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_core_quota_compliance_asymmetric_send_limited_OBJECTS) $(test_core_quota_compliance_asymmetric_send_limited_LDADD) $(LIBS) test_core_quota_compliance_symmetric$(EXEEXT): $(test_core_quota_compliance_symmetric_OBJECTS) $(test_core_quota_compliance_symmetric_DEPENDENCIES) @rm -f test_core_quota_compliance_symmetric$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_core_quota_compliance_symmetric_OBJECTS) $(test_core_quota_compliance_symmetric_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/core_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/core_api_is_connected.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/core_api_iterate_peers.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-core.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-core.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-core_clients.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-core_kx.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-core_neighbours.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-core_sessions.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-core_typemap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_core_api.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_core_api_reliability.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_core_api_send_to_self.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_core_api_start_only.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_core_quota_compliance.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgcfgDATA: $(pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgcfgDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-binPROGRAMS install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-pkgcfgDATA install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/core/gnunet-service-core.h0000644000175000017500000000470111760502551015524 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file core/gnunet-service-core.h * @brief Globals for gnunet-service-core * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_CORE_H #define GNUNET_SERVICE_CORE_H #include "gnunet_statistics_service.h" #include "core.h" /** * Opaque handle to a client. */ struct GSC_Client; /** * Record kept for each request for transmission issued by a * client that is still pending. (This struct is used by * both the 'CLIENTS' and 'SESSIONS' subsystems.) */ struct GSC_ClientActiveRequest { /** * Active requests are kept in a doubly-linked list of * the respective target peer. */ struct GSC_ClientActiveRequest *next; /** * Active requests are kept in a doubly-linked list of * the respective target peer. */ struct GSC_ClientActiveRequest *prev; /** * Which peer is the message going to be for? */ struct GNUNET_PeerIdentity target; /** * Handle to the client. */ struct GSC_Client *client_handle; /** * By what time would the client want to see this message out? */ struct GNUNET_TIME_Absolute deadline; /** * How important is this request. */ uint32_t priority; /** * Has this request been solicited yet? */ int was_solicited; /** * How many bytes does the client intend to send? */ uint16_t msize; /** * Unique request ID (in big endian). */ uint16_t smr_id; }; /** * Our configuration. */ extern const struct GNUNET_CONFIGURATION_Handle *GSC_cfg; /** * For creating statistics. */ extern struct GNUNET_STATISTICS_Handle *GSC_stats; /** * Our identity. */ extern struct GNUNET_PeerIdentity GSC_my_identity; #endif gnunet-0.9.3/src/core/gnunet-service-core_kx.c0000644000175000017500000015100311760502550016216 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file core/gnunet-service-core_kx.c * @brief code for managing the key exchange (SET_KEY, PING, PONG) with other peers * @author Christian Grothoff */ #include "platform.h" #include "gnunet-service-core_kx.h" #include "gnunet-service-core.h" #include "gnunet-service-core_clients.h" #include "gnunet-service-core_neighbours.h" #include "gnunet-service-core_sessions.h" #include "gnunet_statistics_service.h" #include "gnunet_peerinfo_service.h" #include "gnunet_hello_lib.h" #include "gnunet_constants.h" #include "gnunet_signatures.h" #include "gnunet_protocols.h" #include "core.h" /** * Set to GNUNET_YES to perform some slightly expensive internal invariant checks. */ #define EXTRA_CHECKS GNUNET_YES /** * How long do we wait for SET_KEY confirmation initially? */ #define INITIAL_SET_KEY_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (MAX_SET_KEY_DELAY, 1) /** * What is the minimum frequency for a PING message? */ #define MIN_PING_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) /** * How often do we rekey? */ #define REKEY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 90) /** * What is the maximum age of a message for us to consider processing * it? Note that this looks at the timestamp used by the other peer, * so clock skew between machines does come into play here. So this * should be picked high enough so that a little bit of clock skew * does not prevent peers from connecting to us. */ #define MAX_MESSAGE_AGE GNUNET_TIME_UNIT_DAYS /** * What is the maximum delay for a SET_KEY message? */ #define MAX_SET_KEY_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) GNUNET_NETWORK_STRUCT_BEGIN /** * We're sending an (encrypted) PING to the other peer to check if he * can decrypt. The other peer should respond with a PONG with the * same content, except this time encrypted with the receiver's key. */ struct PingMessage { /** * Message type is CORE_PING. */ struct GNUNET_MessageHeader header; /** * Seed for the IV */ uint32_t iv_seed GNUNET_PACKED; /** * Intended target of the PING, used primarily to check * that decryption actually worked. */ struct GNUNET_PeerIdentity target; /** * Random number chosen to make reply harder. */ uint32_t challenge GNUNET_PACKED; }; /** * Response to a PING. Includes data from the original PING. */ struct PongMessage { /** * Message type is CORE_PONG. */ struct GNUNET_MessageHeader header; /** * Seed for the IV */ uint32_t iv_seed GNUNET_PACKED; /** * Random number to make faking the reply harder. Must be * first field after header (this is where we start to encrypt!). */ uint32_t challenge GNUNET_PACKED; /** * Reserved, always 'GNUNET_BANDWIDTH_VALUE_MAX'. */ struct GNUNET_BANDWIDTH_Value32NBO reserved; /** * Intended target of the PING, used primarily to check * that decryption actually worked. */ struct GNUNET_PeerIdentity target; }; /** * Message transmitted to set (or update) a session key. */ struct SetKeyMessage { /** * Message type is either CORE_SET_KEY. */ struct GNUNET_MessageHeader header; /** * Status of the sender (should be in "enum PeerStateMachine"), nbo. */ int32_t sender_status GNUNET_PACKED; /** * Purpose of the signature, will be * GNUNET_SIGNATURE_PURPOSE_SET_KEY. */ struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; /** * At what time was this key created? */ struct GNUNET_TIME_AbsoluteNBO creation_time; /** * The encrypted session key. */ struct GNUNET_CRYPTO_RsaEncryptedData encrypted_key; /** * Who is the intended recipient? */ struct GNUNET_PeerIdentity target; /** * Signature of the stuff above (starting at purpose). */ struct GNUNET_CRYPTO_RsaSignature signature; }; /** * Encapsulation for encrypted messages exchanged between * peers. Followed by the actual encrypted data. */ struct EncryptedMessage { /** * Message type is either CORE_ENCRYPTED_MESSAGE. */ struct GNUNET_MessageHeader header; /** * Random value used for IV generation. */ uint32_t iv_seed GNUNET_PACKED; /** * MAC of the encrypted message (starting at 'sequence_number'), * used to verify message integrity. Everything after this value * (excluding this value itself) will be encrypted and authenticated. * ENCRYPTED_HEADER_SIZE must be set to the offset of the *next* field. */ GNUNET_HashCode hmac; /** * Sequence number, in network byte order. This field * must be the first encrypted/decrypted field */ uint32_t sequence_number GNUNET_PACKED; /** * Reserved, always 'GNUNET_BANDWIDTH_VALUE_MAX'. */ struct GNUNET_BANDWIDTH_Value32NBO reserved; /** * Timestamp. Used to prevent reply of ancient messages * (recent messages are caught with the sequence number). */ struct GNUNET_TIME_AbsoluteNBO timestamp; }; GNUNET_NETWORK_STRUCT_END /** * Number of bytes (at the beginning) of "struct EncryptedMessage" * that are NOT encrypted. */ #define ENCRYPTED_HEADER_SIZE (offsetof(struct EncryptedMessage, sequence_number)) /** * State machine for our P2P encryption handshake. Everyone starts in * "DOWN", if we receive the other peer's key (other peer initiated) * we start in state RECEIVED (since we will immediately send our * own); otherwise we start in SENT. If we get back a PONG from * within either state, we move up to CONFIRMED (the PONG will always * be sent back encrypted with the key we sent to the other peer). */ enum KxStateMachine { /** * No handshake yet. */ KX_STATE_DOWN, /** * We've sent our session key. */ KX_STATE_KEY_SENT, /** * We've received the other peers session key. */ KX_STATE_KEY_RECEIVED, /** * The other peer has confirmed our session key with a message * encrypted with his session key (which we got). Key exchange * is done. */ KX_STATE_UP, /** * We're rekeying, so we have received the other peer's session * key, but he didn't get ours yet. */ KX_STATE_REKEY, /** * We're rekeying but have not yet received confirmation for our new * key from the other peer. */ KX_STATE_REKEY_SENT }; /** * Information about the status of a key exchange with another peer. */ struct GSC_KeyExchangeInfo { /** * Identity of the peer. */ struct GNUNET_PeerIdentity peer; /** * SetKeyMessage to transmit (initialized the first * time our status goes past 'KX_STATE_KEY_SENT'). */ struct SetKeyMessage skm; /** * PING message we transmit to the other peer. */ struct PingMessage ping; /** * SetKeyMessage we received and did not process yet. */ struct SetKeyMessage *skm_received; /** * PING message we received from the other peer and * did not process yet (or NULL). */ struct PingMessage *ping_received; /** * PONG message we received from the other peer and * did not process yet (or NULL). */ struct PongMessage *pong_received; /** * Encrypted message we received from the other peer and * did not process yet (or NULL). */ struct EncryptedMessage *emsg_received; /** * Non-NULL if we are currently looking up HELLOs for this peer. * for this peer. */ struct GNUNET_PEERINFO_IteratorContext *pitr; /** * Public key of the neighbour, NULL if we don't have it yet. */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key; /** * We received a PONG message before we got the "public_key" * (or the SET_KEY). We keep it here until we have a key * to decrypt it. NULL if no PONG is pending. */ struct PongMessage *pending_pong; /** * Key we use to encrypt our messages for the other peer * (initialized by us when we do the handshake). */ struct GNUNET_CRYPTO_AesSessionKey encrypt_key; /** * Key we use to decrypt messages from the other peer * (given to us by the other peer during the handshake). */ struct GNUNET_CRYPTO_AesSessionKey decrypt_key; /** * At what time did we generate our encryption key? */ struct GNUNET_TIME_Absolute encrypt_key_created; /** * At what time did the other peer generate the decryption key? */ struct GNUNET_TIME_Absolute decrypt_key_created; /** * When should the session time out (if there are no PONGs)? */ struct GNUNET_TIME_Absolute timeout; /** * At what frequency are we currently re-trying SET_KEY messages? */ struct GNUNET_TIME_Relative set_key_retry_frequency; /** * ID of task used for re-trying SET_KEY and PING message. */ GNUNET_SCHEDULER_TaskIdentifier retry_set_key_task; /** * ID of task used for sending keep-alive pings. */ GNUNET_SCHEDULER_TaskIdentifier keep_alive_task; /** * Bit map indicating which of the 32 sequence numbers before the last * were received (good for accepting out-of-order packets and * estimating reliability of the connection) */ unsigned int last_packets_bitmap; /** * last sequence number received on this connection (highest) */ uint32_t last_sequence_number_received; /** * last sequence number transmitted */ uint32_t last_sequence_number_sent; /** * What was our PING challenge number (for this peer)? */ uint32_t ping_challenge; /** * What is our connection status? */ enum KxStateMachine status; }; /** * Handle to peerinfo service. */ static struct GNUNET_PEERINFO_Handle *peerinfo; /** * Our private key. */ static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; /** * Our public key. */ static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; /** * Our message stream tokenizer (for encrypted payload). */ static struct GNUNET_SERVER_MessageStreamTokenizer *mst; #if EXTRA_CHECKS /** * Check internal invariants of the given KX record. * * @param kx record to check * @param file filename for error reporting * @param line line number for error reporting */ static void check_kx_record (struct GSC_KeyExchangeInfo *kx, const char *file, int line) { struct GNUNET_HashCode hc; if (NULL == kx->public_key) return; GNUNET_CRYPTO_hash (kx->public_key, sizeof (*kx->public_key), &hc); GNUNET_assert_at (0 == memcmp (&hc, &kx->peer, sizeof (struct GNUNET_HashCode)), file, line); } /** * Check internal invariants of the given KX record. * * @param kx record to check */ #define CHECK_KX(kx) check_kx_record(kx, __FILE__, __LINE__) #else #define CHECK_KX(kx) #endif /** * Derive an authentication key from "set key" information * * @param akey authentication key to derive * @param skey session key to use * @param seed seed to use * @param creation_time creation time to use */ static void derive_auth_key (struct GNUNET_CRYPTO_AuthKey *akey, const struct GNUNET_CRYPTO_AesSessionKey *skey, uint32_t seed, struct GNUNET_TIME_Absolute creation_time) { static const char ctx[] = "authentication key"; struct GNUNET_TIME_AbsoluteNBO ctbe; ctbe = GNUNET_TIME_absolute_hton (creation_time); GNUNET_CRYPTO_hmac_derive_key (akey, skey, &seed, sizeof (seed), &skey->key, sizeof (skey->key), &ctbe, sizeof (ctbe), ctx, sizeof (ctx), NULL); } /** * Derive an IV from packet information * * @param iv initialization vector to initialize * @param skey session key to use * @param seed seed to use * @param identity identity of the other peer to use */ static void derive_iv (struct GNUNET_CRYPTO_AesInitializationVector *iv, const struct GNUNET_CRYPTO_AesSessionKey *skey, uint32_t seed, const struct GNUNET_PeerIdentity *identity) { static const char ctx[] = "initialization vector"; GNUNET_CRYPTO_aes_derive_iv (iv, skey, &seed, sizeof (seed), &identity->hashPubKey.bits, sizeof (identity->hashPubKey.bits), ctx, sizeof (ctx), NULL); } /** * Derive an IV from pong packet information * * @param iv initialization vector to initialize * @param skey session key to use * @param seed seed to use * @param challenge nonce to use * @param identity identity of the other peer to use */ static void derive_pong_iv (struct GNUNET_CRYPTO_AesInitializationVector *iv, const struct GNUNET_CRYPTO_AesSessionKey *skey, uint32_t seed, uint32_t challenge, const struct GNUNET_PeerIdentity *identity) { static const char ctx[] = "pong initialization vector"; GNUNET_CRYPTO_aes_derive_iv (iv, skey, &seed, sizeof (seed), &identity->hashPubKey.bits, sizeof (identity->hashPubKey.bits), &challenge, sizeof (challenge), ctx, sizeof (ctx), NULL); } /** * Encrypt size bytes from in and write the result to out. Use the * key for outbound traffic of the given neighbour. * * @param kx key information context * @param iv initialization vector to use * @param in ciphertext * @param out plaintext * @param size size of in/out * @return GNUNET_OK on success */ static int do_encrypt (struct GSC_KeyExchangeInfo *kx, const struct GNUNET_CRYPTO_AesInitializationVector *iv, const void *in, void *out, size_t size) { if (size != (uint16_t) size) { GNUNET_break (0); return GNUNET_NO; } GNUNET_assert (size == GNUNET_CRYPTO_aes_encrypt (in, (uint16_t) size, &kx->encrypt_key, iv, out)); GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# bytes encrypted"), size, GNUNET_NO); /* the following is too sensitive to write to log files by accident, so we require manual intervention to get this one... */ #if 0 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypted %u bytes for `%4s' using key %u, IV %u\n", (unsigned int) size, GNUNET_i2s (&kx->peer), (unsigned int) kx->encrypt_key.crc32, GNUNET_CRYPTO_crc32_n (iv, sizeof (iv))); #endif return GNUNET_OK; } /** * Decrypt size bytes from in and write the result to out. Use the * key for inbound traffic of the given neighbour. This function does * NOT do any integrity-checks on the result. * * @param kx key information context * @param iv initialization vector to use * @param in ciphertext * @param out plaintext * @param size size of in/out * @return GNUNET_OK on success */ static int do_decrypt (struct GSC_KeyExchangeInfo *kx, const struct GNUNET_CRYPTO_AesInitializationVector *iv, const void *in, void *out, size_t size) { if (size != (uint16_t) size) { GNUNET_break (0); return GNUNET_NO; } if ( (kx->status != KX_STATE_KEY_RECEIVED) && (kx->status != KX_STATE_UP) && (kx->status != KX_STATE_REKEY_SENT) && (kx->status != KX_STATE_REKEY) ) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (size != GNUNET_CRYPTO_aes_decrypt (in, (uint16_t) size, &kx->decrypt_key, iv, out)) { GNUNET_break (0); return GNUNET_SYSERR; } GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# bytes decrypted"), size, GNUNET_NO); /* the following is too sensitive to write to log files by accident, so we require manual intervention to get this one... */ #if 0 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Decrypted %u bytes from `%4s' using key %u, IV %u\n", (unsigned int) size, GNUNET_i2s (&kx->peer), (unsigned int) kx->decrypt_key.crc32, GNUNET_CRYPTO_crc32_n (iv, sizeof (*iv))); #endif return GNUNET_OK; } /** * Send our key (and encrypted PING) to the other peer. * * @param kx key exchange context */ static void send_key (struct GSC_KeyExchangeInfo *kx); /** * Task that will retry "send_key" if our previous attempt failed. * * @param cls our 'struct GSC_KeyExchangeInfo' * @param tc scheduler context */ static void set_key_retry_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GSC_KeyExchangeInfo *kx = cls; kx->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK; kx->set_key_retry_frequency = GNUNET_TIME_relative_multiply (kx->set_key_retry_frequency, 2); send_key (kx); } /** * PEERINFO is giving us a HELLO for a peer. Add the public key to * the neighbour's struct and continue with the key exchange. Or, if * we did not get a HELLO, just do nothing. * * @param cls the 'struct GSC_KeyExchangeInfo' to retry sending the key for * @param peer the peer for which this is the HELLO * @param hello HELLO message of that peer * @param err_msg NULL if successful, otherwise contains error message */ static void process_hello (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Message *hello, const char *err_msg) { struct GSC_KeyExchangeInfo *kx = cls; struct SetKeyMessage *skm; CHECK_KX (kx); if (NULL != err_msg) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Error in communication with PEERINFO service\n")); kx->pitr = NULL; if (GNUNET_SCHEDULER_NO_TASK != kx->retry_set_key_task) GNUNET_SCHEDULER_cancel (kx->retry_set_key_task); kx->retry_set_key_task = GNUNET_SCHEDULER_add_delayed (kx->set_key_retry_frequency, &set_key_retry_task, kx); return; } if (NULL == peer) { kx->pitr = NULL; if (NULL != kx->public_key) return; /* done here */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to obtain public key for peer `%4s', delaying processing of SET_KEY\n", GNUNET_i2s (&kx->peer)); GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# Delayed connecting due to lack of public key"), 1, GNUNET_NO); if (GNUNET_SCHEDULER_NO_TASK != kx->retry_set_key_task) GNUNET_SCHEDULER_cancel (kx->retry_set_key_task); kx->retry_set_key_task = GNUNET_SCHEDULER_add_delayed (kx->set_key_retry_frequency, &set_key_retry_task, kx); return; } GNUNET_break (0 == memcmp (peer, &kx->peer, sizeof (struct GNUNET_PeerIdentity))); if (NULL != kx->public_key) { /* already have public key, why are we here? */ GNUNET_break (0); return; } GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == kx->retry_set_key_task); kx->public_key = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); if (GNUNET_OK != GNUNET_HELLO_get_key (hello, kx->public_key)) { GNUNET_break (0); GNUNET_free (kx->public_key); kx->public_key = NULL; CHECK_KX (kx); return; } CHECK_KX (kx); send_key (kx); if (NULL != kx->skm_received) { skm = kx->skm_received; kx->skm_received = NULL; GSC_KX_handle_set_key (kx, &skm->header); GNUNET_free (skm); } } /** * Start the key exchange with the given peer. * * @param pid identity of the peer to do a key exchange with * @return key exchange information context */ struct GSC_KeyExchangeInfo * GSC_KX_start (const struct GNUNET_PeerIdentity *pid) { struct GSC_KeyExchangeInfo *kx; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Initiating key exchange with `%s'\n", GNUNET_i2s (pid)); GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# key exchanges initiated"), 1, GNUNET_NO); kx = GNUNET_malloc (sizeof (struct GSC_KeyExchangeInfo)); kx->peer = *pid; kx->set_key_retry_frequency = INITIAL_SET_KEY_RETRY_FREQUENCY; kx->pitr = GNUNET_PEERINFO_iterate (peerinfo, pid, GNUNET_TIME_UNIT_FOREVER_REL /* timeout? */ , &process_hello, kx); CHECK_KX (kx); return kx; } /** * Stop key exchange with the given peer. Clean up key material. * * @param kx key exchange to stop */ void GSC_KX_stop (struct GSC_KeyExchangeInfo *kx) { GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# key exchanges stopped"), 1, GNUNET_NO); if (NULL != kx->pitr) { GNUNET_PEERINFO_iterate_cancel (kx->pitr); kx->pitr = NULL; } if (kx->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (kx->retry_set_key_task); kx->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK; } if (kx->keep_alive_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (kx->keep_alive_task); kx->keep_alive_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_free_non_null (kx->skm_received); GNUNET_free_non_null (kx->ping_received); GNUNET_free_non_null (kx->pong_received); GNUNET_free_non_null (kx->emsg_received); GNUNET_free_non_null (kx->public_key); GNUNET_free (kx); } /** * We received a SET_KEY message. Validate and update * our key material and status. * * @param kx key exchange status for the corresponding peer * @param msg the set key message we received */ void GSC_KX_handle_set_key (struct GSC_KeyExchangeInfo *kx, const struct GNUNET_MessageHeader *msg) { const struct SetKeyMessage *m; struct GNUNET_TIME_Absolute t; struct GNUNET_CRYPTO_AesSessionKey k; struct PingMessage *ping; struct PongMessage *pong; enum KxStateMachine sender_status; uint16_t size; CHECK_KX (kx); size = ntohs (msg->size); if (size != sizeof (struct SetKeyMessage)) { GNUNET_break_op (0); return; } m = (const struct SetKeyMessage *) msg; GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# session keys received"), 1, GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service receives `%s' request from `%4s'.\n", "SET_KEY", GNUNET_i2s (&kx->peer)); if (NULL == kx->public_key) { GNUNET_free_non_null (kx->skm_received); kx->skm_received = (struct SetKeyMessage *) GNUNET_copy_message (msg); return; } if (0 != memcmp (&m->target, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("`%s' is for `%s', not for me. Ignoring.\n"), "SET_KEY", GNUNET_i2s (&m->target)); return; } if ((ntohl (m->purpose.size) != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + sizeof (struct GNUNET_CRYPTO_RsaEncryptedData) + sizeof (struct GNUNET_PeerIdentity)) || (GNUNET_OK != GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_SET_KEY, &m->purpose, &m->signature, kx->public_key))) { /* invalid signature */ CHECK_KX (kx); GNUNET_break_op (0); return; } t = GNUNET_TIME_absolute_ntoh (m->creation_time); if (((kx->status == KX_STATE_KEY_RECEIVED) || (kx->status == KX_STATE_UP)) && (t.abs_value < kx->decrypt_key_created.abs_value)) { /* this could rarely happen due to massive re-ordering of * messages on the network level, but is most likely either * a bug or some adversary messing with us. Report. */ GNUNET_break_op (0); return; } if ((GNUNET_CRYPTO_rsa_decrypt (my_private_key, &m->encrypted_key, &k, sizeof (struct GNUNET_CRYPTO_AesSessionKey)) != sizeof (struct GNUNET_CRYPTO_AesSessionKey)) || (GNUNET_OK != GNUNET_CRYPTO_aes_check_session_key (&k))) { /* failed to decrypt !? */ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid key %x decrypted by %s from message %u (origin: %s)\n", (unsigned int) GNUNET_CRYPTO_crc32_n (&k, sizeof (struct GNUNET_CRYPTO_AesSessionKey)), GNUNET_i2s (&GSC_my_identity), (unsigned int) GNUNET_CRYPTO_crc32_n (&m->encrypted_key, sizeof (struct GNUNET_CRYPTO_RsaEncryptedData)), GNUNET_h2s (&kx->peer.hashPubKey)); GNUNET_break_op (0); return; } GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# SET_KEY messages decrypted"), 1, GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received SET_KEY from `%s'\n", GNUNET_i2s (&kx->peer)); kx->decrypt_key = k; if (kx->decrypt_key_created.abs_value != t.abs_value) { /* fresh key, reset sequence numbers */ kx->last_sequence_number_received = 0; kx->last_packets_bitmap = 0; kx->decrypt_key_created = t; } sender_status = (enum KxStateMachine) ntohl (m->sender_status); switch (kx->status) { case KX_STATE_DOWN: kx->status = KX_STATE_KEY_RECEIVED; /* we're not up, so we are already doing 'send_key' */ break; case KX_STATE_KEY_SENT: kx->status = KX_STATE_KEY_RECEIVED; /* we're not up, so we are already doing 'send_key' */ break; case KX_STATE_KEY_RECEIVED: /* we're not up, so we are already doing 'send_key' */ break; case KX_STATE_UP: if ((sender_status == KX_STATE_DOWN) || (sender_status == KX_STATE_KEY_SENT)) send_key (kx); /* we are up, but other peer is not! */ break; case KX_STATE_REKEY: if ((sender_status == KX_STATE_DOWN) || (sender_status == KX_STATE_KEY_SENT)) send_key (kx); /* we are up, but other peer is not! */ break; case KX_STATE_REKEY_SENT: if ((sender_status == KX_STATE_DOWN) || (sender_status == KX_STATE_KEY_SENT)) send_key (kx); /* we are up, but other peer is not! */ break; default: GNUNET_break (0); break; } if (NULL != kx->ping_received) { ping = kx->ping_received; kx->ping_received = NULL; GSC_KX_handle_ping (kx, &ping->header); GNUNET_free (ping); } if (NULL != kx->pong_received) { pong = kx->pong_received; kx->pong_received = NULL; GSC_KX_handle_pong (kx, &pong->header); GNUNET_free (pong); } } /** * We received a PING message. Validate and transmit * a PONG message. * * @param kx key exchange status for the corresponding peer * @param msg the encrypted PING message itself */ void GSC_KX_handle_ping (struct GSC_KeyExchangeInfo *kx, const struct GNUNET_MessageHeader *msg) { const struct PingMessage *m; struct PingMessage t; struct PongMessage tx; struct PongMessage tp; struct GNUNET_CRYPTO_AesInitializationVector iv; uint16_t msize; msize = ntohs (msg->size); if (msize != sizeof (struct PingMessage)) { GNUNET_break_op (0); return; } GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# PING messages received"), 1, GNUNET_NO); if ((kx->status != KX_STATE_KEY_RECEIVED) && (kx->status != KX_STATE_UP) && (kx->status != KX_STATE_REKEY_SENT)) { /* defer */ GNUNET_free_non_null (kx->ping_received); kx->ping_received = (struct PingMessage *) GNUNET_copy_message (msg); return; } m = (const struct PingMessage *) msg; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service receives `%s' request from `%4s'.\n", "PING", GNUNET_i2s (&kx->peer)); derive_iv (&iv, &kx->decrypt_key, m->iv_seed, &GSC_my_identity); if (GNUNET_OK != do_decrypt (kx, &iv, &m->target, &t.target, sizeof (struct PingMessage) - ((void *) &m->target - (void *) m))) { GNUNET_break_op (0); return; } if (0 != memcmp (&t.target, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity))) { char sender[9]; char peer[9]; GNUNET_snprintf (sender, sizeof (sender), "%8s", GNUNET_i2s (&kx->peer)); GNUNET_snprintf (peer, sizeof (peer), "%8s", GNUNET_i2s (&t.target)); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Received PING from `%s' for different identity: I am `%s', PONG identity: `%s'\n"), sender, GNUNET_i2s (&GSC_my_identity), peer); GNUNET_break_op (0); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received PING from `%s'\n", GNUNET_i2s (&kx->peer)); /* construct PONG */ tx.reserved = GNUNET_BANDWIDTH_VALUE_MAX; tx.challenge = t.challenge; tx.target = t.target; tp.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PONG); tp.header.size = htons (sizeof (struct PongMessage)); tp.iv_seed = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); derive_pong_iv (&iv, &kx->encrypt_key, tp.iv_seed, t.challenge, &kx->peer); do_encrypt (kx, &iv, &tx.challenge, &tp.challenge, sizeof (struct PongMessage) - ((void *) &tp.challenge - (void *) &tp)); GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# PONG messages created"), 1, GNUNET_NO); GSC_NEIGHBOURS_transmit (&kx->peer, &tp.header, GNUNET_TIME_UNIT_FOREVER_REL /* FIXME: timeout */ ); } /** * Create a fresh SET KEY message for transmission to the other peer. * Also creates a new key. * * @param kx key exchange context to create SET KEY message for */ static void setup_fresh_setkey (struct GSC_KeyExchangeInfo *kx) { struct SetKeyMessage *skm; GNUNET_CRYPTO_aes_create_session_key (&kx->encrypt_key); kx->encrypt_key_created = GNUNET_TIME_absolute_get (); skm = &kx->skm; skm->header.size = htons (sizeof (struct SetKeyMessage)); skm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SET_KEY); skm->purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + sizeof (struct GNUNET_CRYPTO_RsaEncryptedData) + sizeof (struct GNUNET_PeerIdentity)); skm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SET_KEY); skm->creation_time = GNUNET_TIME_absolute_hton (kx->encrypt_key_created); skm->target = kx->peer; CHECK_KX (kx); GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_rsa_encrypt (&kx->encrypt_key, sizeof (struct GNUNET_CRYPTO_AesSessionKey), kx->public_key, &skm->encrypted_key)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting key %x for %s resulting in message %u (origin: %s)\n", (unsigned int) GNUNET_CRYPTO_crc32_n (&kx->encrypt_key, sizeof (struct GNUNET_CRYPTO_AesSessionKey)), GNUNET_i2s (&kx->peer), (unsigned int) GNUNET_CRYPTO_crc32_n (&skm->encrypted_key, sizeof (struct GNUNET_CRYPTO_RsaEncryptedData)), GNUNET_h2s (&GSC_my_identity.hashPubKey)); GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_rsa_sign (my_private_key, &skm->purpose, &skm->signature)); } /** * Create a fresh PING message for transmission to the other peer. * * @param kx key exchange context to create PING for */ static void setup_fresh_ping (struct GSC_KeyExchangeInfo *kx) { struct PingMessage pp; struct PingMessage *pm; struct GNUNET_CRYPTO_AesInitializationVector iv; pm = &kx->ping; pm->header.size = htons (sizeof (struct PingMessage)); pm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PING); pm->iv_seed = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); derive_iv (&iv, &kx->encrypt_key, pm->iv_seed, &kx->peer); pp.challenge = kx->ping_challenge; pp.target = kx->peer; do_encrypt (kx, &iv, &pp.target, &pm->target, sizeof (struct PingMessage) - ((void *) &pm->target - (void *) pm)); } /** * Task triggered when a neighbour entry is about to time out * (and we should prevent this by sending a PING). * * @param cls the 'struct GSC_KeyExchangeInfo' * @param tc scheduler context (not used) */ static void send_keep_alive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GSC_KeyExchangeInfo *kx = cls; struct GNUNET_TIME_Relative retry; struct GNUNET_TIME_Relative left; kx->keep_alive_task = GNUNET_SCHEDULER_NO_TASK; left = GNUNET_TIME_absolute_get_remaining (kx->timeout); if (0 == left.rel_value) { GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# sessions terminated by timeout"), 1, GNUNET_NO); GSC_SESSIONS_end (&kx->peer); kx->status = KX_STATE_DOWN; send_key (kx); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending KEEPALIVE to `%s'\n", GNUNET_i2s (&kx->peer)); GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# keepalive messages sent"), 1, GNUNET_NO); setup_fresh_ping (kx); GSC_NEIGHBOURS_transmit (&kx->peer, &kx->ping.header, kx->set_key_retry_frequency); retry = GNUNET_TIME_relative_max (GNUNET_TIME_relative_divide (left, 2), MIN_PING_FREQUENCY); kx->keep_alive_task = GNUNET_SCHEDULER_add_delayed (retry, &send_keep_alive, kx); } /** * We've seen a valid message from the other peer. * Update the time when the session would time out * and delay sending our keep alive message further. * * @param kx key exchange where we saw activity */ static void update_timeout (struct GSC_KeyExchangeInfo *kx) { kx->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); if (kx->keep_alive_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (kx->keep_alive_task); kx->keep_alive_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 2), &send_keep_alive, kx); } /** * Trigger rekeying event. * * @param cls the 'struct GSC_KeyExchangeInfo' * @param tc schedule context (unused) */ static void trigger_rekey (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GSC_KeyExchangeInfo *kx = cls; GNUNET_break (KX_STATE_UP == kx->status); kx->status = KX_STATE_REKEY; kx->set_key_retry_frequency = INITIAL_SET_KEY_RETRY_FREQUENCY; kx->retry_set_key_task = GNUNET_SCHEDULER_add_delayed (kx->set_key_retry_frequency, &set_key_retry_task, kx); } /** * Schedule rekey operation. * * @param kx key exchange to schedule rekey for */ static void schedule_rekey (struct GSC_KeyExchangeInfo *kx) { struct GNUNET_TIME_Relative rdelay; if (GNUNET_SCHEDULER_NO_TASK != kx->retry_set_key_task) GNUNET_SCHEDULER_cancel (kx->retry_set_key_task); rdelay = REKEY_FREQUENCY; /* randomize rekey frequency by one minute to avoid synchronization */ rdelay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 60 * 1000); kx->retry_set_key_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY, &trigger_rekey, kx); } /** * We received a PONG message. Validate and update our status. * * @param kx key exchange context for the the PONG * @param msg the encrypted PONG message itself */ void GSC_KX_handle_pong (struct GSC_KeyExchangeInfo *kx, const struct GNUNET_MessageHeader *msg) { const struct PongMessage *m; struct PongMessage t; struct EncryptedMessage *emsg; struct GNUNET_CRYPTO_AesInitializationVector iv; uint16_t msize; msize = ntohs (msg->size); if (sizeof (struct PongMessage) != msize) { GNUNET_break_op (0); return; } GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# PONG messages received"), 1, GNUNET_NO); switch (kx->status) { case KX_STATE_DOWN: return; case KX_STATE_KEY_SENT: GNUNET_free_non_null (kx->pong_received); kx->pong_received = (struct PongMessage *) GNUNET_copy_message (msg); return; case KX_STATE_KEY_RECEIVED: break; case KX_STATE_UP: break; case KX_STATE_REKEY: break; case KX_STATE_REKEY_SENT: break; default: GNUNET_break (0); return; } m = (const struct PongMessage *) msg; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service receives `%s' response from `%4s'.\n", "PONG", GNUNET_i2s (&kx->peer)); /* mark as garbage, just to be sure */ memset (&t, 255, sizeof (t)); derive_pong_iv (&iv, &kx->decrypt_key, m->iv_seed, kx->ping_challenge, &GSC_my_identity); if (GNUNET_OK != do_decrypt (kx, &iv, &m->challenge, &t.challenge, sizeof (struct PongMessage) - ((void *) &m->challenge - (void *) m))) { GNUNET_break_op (0); return; } GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# PONG messages decrypted"), 1, GNUNET_NO); if ((0 != memcmp (&t.target, &kx->peer, sizeof (struct GNUNET_PeerIdentity))) || (kx->ping_challenge != t.challenge)) { /* PONG malformed */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received malformed `%s' wanted sender `%4s' with challenge %u\n", "PONG", GNUNET_i2s (&kx->peer), (unsigned int) kx->ping_challenge); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received malformed `%s' received from `%4s' with challenge %u\n", "PONG", GNUNET_i2s (&t.target), (unsigned int) t.challenge); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received PONG from `%s'\n", GNUNET_i2s (&kx->peer)); switch (kx->status) { case KX_STATE_DOWN: GNUNET_break (0); /* should be impossible */ return; case KX_STATE_KEY_SENT: GNUNET_break (0); /* should be impossible */ return; case KX_STATE_KEY_RECEIVED: GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# session keys confirmed via PONG"), 1, GNUNET_NO); kx->status = KX_STATE_UP; GSC_SESSIONS_create (&kx->peer, kx); CHECK_KX (kx); schedule_rekey (kx); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == kx->keep_alive_task); if (NULL != kx->emsg_received) { emsg = kx->emsg_received; kx->emsg_received = NULL; GSC_KX_handle_encrypted_message (kx, &emsg->header, NULL, 0 /* FIXME: ATSI */ ); GNUNET_free (emsg); } update_timeout (kx); break; case KX_STATE_UP: update_timeout (kx); break; case KX_STATE_REKEY: update_timeout (kx); break; case KX_STATE_REKEY_SENT: GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# rekey operations confirmed via PONG"), 1, GNUNET_NO); kx->status = KX_STATE_UP; schedule_rekey (kx); update_timeout (kx); break; default: GNUNET_break (0); break; } } /** * Send our key (and encrypted PING) to the other peer. * * @param kx key exchange context */ static void send_key (struct GSC_KeyExchangeInfo *kx) { CHECK_KX (kx); if (GNUNET_SCHEDULER_NO_TASK != kx->retry_set_key_task) { GNUNET_SCHEDULER_cancel (kx->retry_set_key_task); kx->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK; } if (KX_STATE_UP == kx->status) return; /* nothing to do */ if (NULL == kx->public_key) { /* lookup public key, then try again */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to obtain public key for `%s'\n", GNUNET_i2s (&kx->peer)); kx->pitr = GNUNET_PEERINFO_iterate (peerinfo, &kx->peer, GNUNET_TIME_UNIT_FOREVER_REL /* timeout? */ , &process_hello, kx); return; } /* update status */ switch (kx->status) { case KX_STATE_DOWN: kx->status = KX_STATE_KEY_SENT; /* setup SET KEY message */ setup_fresh_setkey (kx); setup_fresh_ping (kx); GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# SET_KEY and PING messages created"), 1, GNUNET_NO); break; case KX_STATE_KEY_SENT: break; case KX_STATE_KEY_RECEIVED: break; case KX_STATE_UP: GNUNET_break (0); return; case KX_STATE_REKEY: kx->status = KX_STATE_REKEY_SENT; /* setup fresh SET KEY message */ setup_fresh_setkey (kx); setup_fresh_ping (kx); GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# SET_KEY and PING messages created"), 1, GNUNET_NO); GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# REKEY operations performed"), 1, GNUNET_NO); break; case KX_STATE_REKEY_SENT: break; default: GNUNET_break (0); return; } /* always update sender status in SET KEY message */ /* Not sending rekey sent state to be compatible with GNUnet 0.9.2 */ kx->skm.sender_status = htonl ((int32_t) ((kx->status == KX_STATE_REKEY_SENT) ? KX_STATE_KEY_RECEIVED : kx->status)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SET_KEY and PING to `%s'\n", GNUNET_i2s (&kx->peer)); GSC_NEIGHBOURS_transmit (&kx->peer, &kx->skm.header, kx->set_key_retry_frequency); GSC_NEIGHBOURS_transmit (&kx->peer, &kx->ping.header, kx->set_key_retry_frequency); kx->retry_set_key_task = GNUNET_SCHEDULER_add_delayed (kx->set_key_retry_frequency, &set_key_retry_task, kx); } /** * Encrypt and transmit a message with the given payload. * * @param kx key exchange context * @param payload payload of the message * @param payload_size number of bytes in 'payload' */ void GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx, const void *payload, size_t payload_size) { size_t used = payload_size + sizeof (struct EncryptedMessage); char pbuf[used]; /* plaintext */ char cbuf[used]; /* ciphertext */ struct EncryptedMessage *em; /* encrypted message */ struct EncryptedMessage *ph; /* plaintext header */ struct GNUNET_CRYPTO_AesInitializationVector iv; struct GNUNET_CRYPTO_AuthKey auth_key; ph = (struct EncryptedMessage *) pbuf; ph->iv_seed = htonl (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX)); ph->sequence_number = htonl (++kx->last_sequence_number_sent); ph->reserved = GNUNET_BANDWIDTH_VALUE_MAX; ph->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); memcpy (&ph[1], payload, payload_size); em = (struct EncryptedMessage *) cbuf; em->header.size = htons (used); em->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE); em->iv_seed = ph->iv_seed; derive_iv (&iv, &kx->encrypt_key, ph->iv_seed, &kx->peer); GNUNET_assert (GNUNET_OK == do_encrypt (kx, &iv, &ph->sequence_number, &em->sequence_number, used - ENCRYPTED_HEADER_SIZE)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypted %u bytes for %s\n", used - ENCRYPTED_HEADER_SIZE, GNUNET_i2s (&kx->peer)); derive_auth_key (&auth_key, &kx->encrypt_key, ph->iv_seed, kx->encrypt_key_created); GNUNET_CRYPTO_hmac (&auth_key, &em->sequence_number, used - ENCRYPTED_HEADER_SIZE, &em->hmac); GSC_NEIGHBOURS_transmit (&kx->peer, &em->header, GNUNET_TIME_UNIT_FOREVER_REL); } /** * Closure for 'deliver_message' */ struct DeliverMessageContext { /** * Performance information for the connection. */ const struct GNUNET_ATS_Information *atsi; /** * Sender of the message. */ const struct GNUNET_PeerIdentity *peer; /** * Number of entries in 'atsi' array. */ uint32_t atsi_count; }; /** * We received an encrypted message. Decrypt, validate and * pass on to the appropriate clients. * * @param kx key exchange context for encrypting the message * @param msg encrypted message * @param atsi performance data * @param atsi_count number of entries in ats (excluding 0-termination) */ void GSC_KX_handle_encrypted_message (struct GSC_KeyExchangeInfo *kx, const struct GNUNET_MessageHeader *msg, const struct GNUNET_ATS_Information *atsi, uint32_t atsi_count) { const struct EncryptedMessage *m; struct EncryptedMessage *pt; /* plaintext */ GNUNET_HashCode ph; uint32_t snum; struct GNUNET_TIME_Absolute t; struct GNUNET_CRYPTO_AesInitializationVector iv; struct GNUNET_CRYPTO_AuthKey auth_key; struct DeliverMessageContext dmc; uint16_t size = ntohs (msg->size); char buf[size] GNUNET_ALIGN; if (size < sizeof (struct EncryptedMessage) + sizeof (struct GNUNET_MessageHeader)) { GNUNET_break_op (0); return; } m = (const struct EncryptedMessage *) msg; if ((kx->status != KX_STATE_KEY_RECEIVED) && (kx->status != KX_STATE_UP) && (kx->status != KX_STATE_REKEY_SENT) ) { GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# failed to decrypt message (no session key)"), 1, GNUNET_NO); return; } if (KX_STATE_KEY_RECEIVED == kx->status) { /* defer */ GNUNET_free_non_null (kx->emsg_received); kx->emsg_received = (struct EncryptedMessage *) GNUNET_copy_message (msg); return; } /* validate hash */ derive_auth_key (&auth_key, &kx->decrypt_key, m->iv_seed, kx->decrypt_key_created); GNUNET_CRYPTO_hmac (&auth_key, &m->sequence_number, size - ENCRYPTED_HEADER_SIZE, &ph); if (0 != memcmp (&ph, &m->hmac, sizeof (GNUNET_HashCode))) { /* checksum failed */ GNUNET_break_op (0); return; } derive_iv (&iv, &kx->decrypt_key, m->iv_seed, &GSC_my_identity); /* decrypt */ if (GNUNET_OK != do_decrypt (kx, &iv, &m->sequence_number, &buf[ENCRYPTED_HEADER_SIZE], size - ENCRYPTED_HEADER_SIZE)) return; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Decrypted %u bytes from %s\n", size - ENCRYPTED_HEADER_SIZE, GNUNET_i2s (&kx->peer)); pt = (struct EncryptedMessage *) buf; /* validate sequence number */ snum = ntohl (pt->sequence_number); if (kx->last_sequence_number_received == snum) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received duplicate message, ignoring.\n"); /* duplicate, ignore */ GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# bytes dropped (duplicates)"), size, GNUNET_NO); return; } if ((kx->last_sequence_number_received > snum) && (kx->last_sequence_number_received - snum > 32)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received ancient out of sequence message, ignoring.\n"); /* ancient out of sequence, ignore */ GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# bytes dropped (out of sequence)"), size, GNUNET_NO); return; } if (kx->last_sequence_number_received > snum) { unsigned int rotbit = 1 << (kx->last_sequence_number_received - snum - 1); if ((kx->last_packets_bitmap & rotbit) != 0) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received duplicate message, ignoring.\n"); GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# bytes dropped (duplicates)"), size, GNUNET_NO); /* duplicate, ignore */ return; } kx->last_packets_bitmap |= rotbit; } if (kx->last_sequence_number_received < snum) { unsigned int shift = (snum - kx->last_sequence_number_received); if (shift >= 8 * sizeof (kx->last_packets_bitmap)) kx->last_packets_bitmap = 0; else kx->last_packets_bitmap <<= shift; kx->last_sequence_number_received = snum; } /* check timestamp */ t = GNUNET_TIME_absolute_ntoh (pt->timestamp); if (GNUNET_TIME_absolute_get_duration (t).rel_value > MAX_MESSAGE_AGE.rel_value) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Message received far too old (%llu ms). Content ignored.\n"), GNUNET_TIME_absolute_get_duration (t).rel_value); GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# bytes dropped (ancient message)"), size, GNUNET_NO); return; } /* process decrypted message(s) */ update_timeout (kx); GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# bytes of payload decrypted"), size - sizeof (struct EncryptedMessage), GNUNET_NO); dmc.atsi = atsi; dmc.atsi_count = atsi_count; dmc.peer = &kx->peer; if (GNUNET_OK != GNUNET_SERVER_mst_receive (mst, &dmc, &buf[sizeof (struct EncryptedMessage)], size - sizeof (struct EncryptedMessage), GNUNET_YES, GNUNET_NO)) GNUNET_break_op (0); } /** * Deliver P2P message to interested clients. * Invokes send twice, once for clients that want the full message, and once * for clients that only want the header * * @param cls always NULL * @param client who sent us the message (struct GSC_KeyExchangeInfo) * @param m the message */ static int deliver_message (void *cls, void *client, const struct GNUNET_MessageHeader *m) { struct DeliverMessageContext *dmc = client; switch (ntohs (m->type)) { case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP: case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP: GSC_SESSIONS_set_typemap (dmc->peer, m); return GNUNET_OK; default: GSC_CLIENTS_deliver_message (dmc->peer, dmc->atsi, dmc->atsi_count, m, ntohs (m->size), GNUNET_CORE_OPTION_SEND_FULL_INBOUND); GSC_CLIENTS_deliver_message (dmc->peer, dmc->atsi, dmc->atsi_count, m, sizeof (struct GNUNET_MessageHeader), GNUNET_CORE_OPTION_SEND_HDR_INBOUND); } return GNUNET_OK; } /** * Initialize KX subsystem. * * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int GSC_KX_init () { char *keyfile; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (GSC_cfg, "GNUNETD", "HOSTKEY", &keyfile)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Core service is lacking HOSTKEY configuration setting. Exiting.\n")); return GNUNET_SYSERR; } my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); GNUNET_free (keyfile); if (NULL == my_private_key) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Core service could not access hostkey. Exiting.\n")); return GNUNET_SYSERR; } GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key); GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key), &GSC_my_identity.hashPubKey); peerinfo = GNUNET_PEERINFO_connect (GSC_cfg); if (NULL == peerinfo) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not access PEERINFO service. Exiting.\n")); GNUNET_CRYPTO_rsa_key_free (my_private_key); my_private_key = NULL; return GNUNET_SYSERR; } mst = GNUNET_SERVER_mst_create (&deliver_message, NULL); return GNUNET_OK; } /** * Shutdown KX subsystem. */ void GSC_KX_done () { if (NULL != my_private_key) { GNUNET_CRYPTO_rsa_key_free (my_private_key); my_private_key = NULL; } if (NULL != peerinfo) { GNUNET_PEERINFO_disconnect (peerinfo); peerinfo = NULL; } if (NULL != mst) { GNUNET_SERVER_mst_destroy (mst); mst = NULL; } } /* end of gnunet-service-core_kx.c */ gnunet-0.9.3/src/core/core_api.c0000644000175000017500000012460411760502550013420 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file core/core_api.c * @brief core service; this is the main API for encrypted P2P * communications * @author Christian Grothoff */ #include "platform.h" #include "gnunet_constants.h" #include "gnunet_core_service.h" #include "core.h" #define LOG(kind,...) GNUNET_log_from (kind, "core-api",__VA_ARGS__) /** * Information we track for each peer. */ struct PeerRecord { /** * We generally do NOT keep peer records in a DLL; this * DLL is only used IF this peer's 'pending_head' message * is ready for transmission. */ struct PeerRecord *prev; /** * We generally do NOT keep peer records in a DLL; this * DLL is only used IF this peer's 'pending_head' message * is ready for transmission. */ struct PeerRecord *next; /** * Peer the record is about. */ struct GNUNET_PeerIdentity peer; /** * Corresponding core handle. */ struct GNUNET_CORE_Handle *ch; /** * Head of doubly-linked list of pending requests. * Requests are sorted by deadline *except* for HEAD, * which is only modified upon transmission to core. */ struct GNUNET_CORE_TransmitHandle *pending_head; /** * Tail of doubly-linked list of pending requests. */ struct GNUNET_CORE_TransmitHandle *pending_tail; /** * ID of timeout task for the 'pending_head' handle * which is the one with the smallest timeout. */ GNUNET_SCHEDULER_TaskIdentifier timeout_task; /** * ID of task to run 'next_request_transmission'. */ GNUNET_SCHEDULER_TaskIdentifier ntr_task; /** * Current size of the queue of pending requests. */ unsigned int queue_size; /** * SendMessageRequest ID generator for this peer. */ uint16_t smr_id_gen; }; /** * Type of function called upon completion. * * @param cls closure * @param success GNUNET_OK on success (which for request_connect * ONLY means that we transmitted the connect request to CORE, * it does not mean that we are actually now connected!); * GNUNET_NO on timeout, * GNUNET_SYSERR if core was shut down */ typedef void (*GNUNET_CORE_ControlContinuation) (void *cls, int success); /** * Entry in a doubly-linked list of control messages to be transmitted * to the core service. Control messages include traffic allocation, * connection requests and of course our initial 'init' request. * * The actual message is allocated at the end of this struct. */ struct ControlMessage { /** * This is a doubly-linked list. */ struct ControlMessage *next; /** * This is a doubly-linked list. */ struct ControlMessage *prev; /** * Function to run after transmission failed/succeeded. */ GNUNET_CORE_ControlContinuation cont; /** * Closure for 'cont'. */ void *cont_cls; /** * Transmit handle (if one is associated with this ControlMessage), or NULL. */ struct GNUNET_CORE_TransmitHandle *th; }; /** * Context for the core service connection. */ struct GNUNET_CORE_Handle { /** * Configuration we're using. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Closure for the various callbacks. */ void *cls; /** * Function to call once we've handshaked with the core service. */ GNUNET_CORE_StartupCallback init; /** * Function to call whenever we're notified about a peer connecting. */ GNUNET_CORE_ConnectEventHandler connects; /** * Function to call whenever we're notified about a peer disconnecting. */ GNUNET_CORE_DisconnectEventHandler disconnects; /** * Function to call whenever we receive an inbound message. */ GNUNET_CORE_MessageCallback inbound_notify; /** * Function to call whenever we receive an outbound message. */ GNUNET_CORE_MessageCallback outbound_notify; /** * Function handlers for messages of particular type. */ const struct GNUNET_CORE_MessageHandler *handlers; /** * Our connection to the service. */ struct GNUNET_CLIENT_Connection *client; /** * Handle for our current transmission request. */ struct GNUNET_CLIENT_TransmitHandle *cth; /** * Head of doubly-linked list of pending requests. */ struct ControlMessage *control_pending_head; /** * Tail of doubly-linked list of pending requests. */ struct ControlMessage *control_pending_tail; /** * Head of doubly-linked list of peers that are core-approved * to send their next message. */ struct PeerRecord *ready_peer_head; /** * Tail of doubly-linked list of peers that are core-approved * to send their next message. */ struct PeerRecord *ready_peer_tail; /** * Hash map listing all of the peers that we are currently * connected to. */ struct GNUNET_CONTAINER_MultiHashMap *peers; /** * Identity of this peer. */ struct GNUNET_PeerIdentity me; /** * ID of reconnect task (if any). */ GNUNET_SCHEDULER_TaskIdentifier reconnect_task; /** * Current delay we use for re-trying to connect to core. */ struct GNUNET_TIME_Relative retry_backoff; /** * Number of messages we are allowed to queue per target. */ unsigned int queue_size; /** * Number of entries in the handlers array. */ unsigned int hcnt; /** * For inbound notifications without a specific handler, do * we expect to only receive headers? */ int inbound_hdr_only; /** * For outbound notifications without a specific handler, do * we expect to only receive headers? */ int outbound_hdr_only; /** * Are we currently disconnected and hence unable to forward * requests? */ int currently_down; }; /** * Handle for a transmission request. */ struct GNUNET_CORE_TransmitHandle { /** * We keep active transmit handles in a doubly-linked list. */ struct GNUNET_CORE_TransmitHandle *next; /** * We keep active transmit handles in a doubly-linked list. */ struct GNUNET_CORE_TransmitHandle *prev; /** * Corresponding peer record. */ struct PeerRecord *peer; /** * Corresponding SEND_REQUEST message. Only non-NULL * while SEND_REQUEST message is pending. */ struct ControlMessage *cm; /** * Function that will be called to get the actual request * (once we are ready to transmit this request to the core). * The function will be called with a NULL buffer to signal * timeout. */ GNUNET_CONNECTION_TransmitReadyNotify get_message; /** * Closure for get_message. */ void *get_message_cls; /** * Timeout for this handle. */ struct GNUNET_TIME_Absolute timeout; /** * How important is this message? */ uint32_t priority; /** * Size of this request. */ uint16_t msize; /** * Send message request ID for this request. */ uint16_t smr_id; /** * Is corking allowed? */ int cork; }; /** * Our current client connection went down. Clean it up * and try to reconnect! * * @param h our handle to the core service */ static void reconnect (struct GNUNET_CORE_Handle *h); /** * Task schedule to try to re-connect to core. * * @param cls the 'struct GNUNET_CORE_Handle' * @param tc task context */ static void reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CORE_Handle *h = cls; h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CORE service after delay\n"); reconnect (h); } /** * Notify clients about disconnect and free * the entry for connected peer. * * @param cls the 'struct GNUNET_CORE_Handle*' * @param key the peer identity (not used) * @param value the 'struct PeerRecord' to free. * @return GNUNET_YES (continue) */ static int disconnect_and_free_peer_entry (void *cls, const GNUNET_HashCode * key, void *value) { struct GNUNET_CORE_Handle *h = cls; struct GNUNET_CORE_TransmitHandle *th; struct PeerRecord *pr = value; if (pr->timeout_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (pr->timeout_task); pr->timeout_task = GNUNET_SCHEDULER_NO_TASK; } if (pr->ntr_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (pr->ntr_task); pr->ntr_task = GNUNET_SCHEDULER_NO_TASK; } if ((pr->prev != NULL) || (pr->next != NULL) || (h->ready_peer_head == pr)) GNUNET_CONTAINER_DLL_remove (h->ready_peer_head, h->ready_peer_tail, pr); if (h->disconnects != NULL) h->disconnects (h->cls, &pr->peer); /* all requests should have been cancelled, clean up anyway, just in case */ GNUNET_break (pr->queue_size == 0); while (NULL != (th = pr->pending_head)) { GNUNET_break (0); GNUNET_CONTAINER_DLL_remove (pr->pending_head, pr->pending_tail, th); pr->queue_size--; if (th->cm != NULL) th->cm->th = NULL; GNUNET_free (th); } /* done with 'voluntary' cleanups, now on to normal freeing */ GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (h->peers, key, pr)); GNUNET_assert (pr->pending_head == NULL); GNUNET_assert (pr->pending_tail == NULL); GNUNET_assert (pr->ch == h); GNUNET_assert (pr->queue_size == 0); GNUNET_assert (pr->timeout_task == GNUNET_SCHEDULER_NO_TASK); GNUNET_assert (pr->ntr_task == GNUNET_SCHEDULER_NO_TASK); GNUNET_free (pr); return GNUNET_YES; } /** * Close down any existing connection to the CORE service and * try re-establishing it later. * * @param h our handle */ static void reconnect_later (struct GNUNET_CORE_Handle *h) { struct ControlMessage *cm; struct PeerRecord *pr; GNUNET_assert (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK); if (NULL != h->cth) { GNUNET_CLIENT_notify_transmit_ready_cancel (h->cth); h->cth = NULL; } if (h->client != NULL) { GNUNET_CLIENT_disconnect (h->client); h->client = NULL; } h->currently_down = GNUNET_YES; GNUNET_assert (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK); h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->retry_backoff, &reconnect_task, h); while (NULL != (cm = h->control_pending_head)) { GNUNET_CONTAINER_DLL_remove (h->control_pending_head, h->control_pending_tail, cm); if (cm->th != NULL) cm->th->cm = NULL; if (cm->cont != NULL) cm->cont (cm->cont_cls, GNUNET_NO); GNUNET_free (cm); } GNUNET_CONTAINER_multihashmap_iterate (h->peers, &disconnect_and_free_peer_entry, h); while (NULL != (pr = h->ready_peer_head)) GNUNET_CONTAINER_DLL_remove (h->ready_peer_head, h->ready_peer_tail, pr); GNUNET_assert (h->control_pending_head == NULL); h->retry_backoff = GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS, h->retry_backoff); h->retry_backoff = GNUNET_TIME_relative_multiply (h->retry_backoff, 2); } /** * Check the list of pending requests, send the next * one to the core. * * @param h core handle * @param ignore_currently_down transmit message even if not initialized? */ static void trigger_next_request (struct GNUNET_CORE_Handle *h, int ignore_currently_down); /** * The given request hit its timeout. Remove from the * doubly-linked list and call the respective continuation. * * @param cls the transmit handle of the request that timed out * @param tc context, can be NULL (!) */ static void transmission_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Send a control message to the peer asking for transmission * of the message in the given peer record. * * @param pr peer to request transmission to */ static void request_next_transmission (struct PeerRecord *pr) { struct GNUNET_CORE_Handle *h = pr->ch; struct ControlMessage *cm; struct SendMessageRequest *smr; struct GNUNET_CORE_TransmitHandle *th; if (pr->timeout_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (pr->timeout_task); pr->timeout_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL == (th = pr->pending_head)) { trigger_next_request (h, GNUNET_NO); return; } if (th->cm != NULL) return; /* already done */ GNUNET_assert (pr->prev == NULL); GNUNET_assert (pr->next == NULL); pr->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (th->timeout), &transmission_timeout, pr); cm = GNUNET_malloc (sizeof (struct ControlMessage) + sizeof (struct SendMessageRequest)); th->cm = cm; cm->th = th; smr = (struct SendMessageRequest *) &cm[1]; smr->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST); smr->header.size = htons (sizeof (struct SendMessageRequest)); smr->priority = htonl (th->priority); smr->deadline = GNUNET_TIME_absolute_hton (th->timeout); smr->peer = pr->peer; smr->queue_size = htonl (pr->queue_size); smr->size = htons (th->msize); smr->smr_id = htons (th->smr_id = pr->smr_id_gen++); GNUNET_CONTAINER_DLL_insert_tail (h->control_pending_head, h->control_pending_tail, cm); LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding SEND REQUEST for peer `%s' to message queue\n", GNUNET_i2s (&pr->peer)); trigger_next_request (h, GNUNET_NO); } /** * The given request hit its timeout. Remove from the * doubly-linked list and call the respective continuation. * * @param cls the transmit handle of the request that timed out * @param tc context, can be NULL (!) */ static void transmission_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerRecord *pr = cls; struct GNUNET_CORE_Handle *h = pr->ch; struct GNUNET_CORE_TransmitHandle *th; pr->timeout_task = GNUNET_SCHEDULER_NO_TASK; th = pr->pending_head; GNUNET_CONTAINER_DLL_remove (pr->pending_head, pr->pending_tail, th); pr->queue_size--; if ((pr->prev != NULL) || (pr->next != NULL) || (pr == h->ready_peer_head)) { /* the request that was 'approved' by core was * canceled before it could be transmitted; remove * us from the 'ready' list */ GNUNET_CONTAINER_DLL_remove (h->ready_peer_head, h->ready_peer_tail, pr); } if (NULL != th->cm) { /* we're currently in the control queue, remove */ GNUNET_CONTAINER_DLL_remove (h->control_pending_head, h->control_pending_tail, th->cm); GNUNET_free (th->cm); } LOG (GNUNET_ERROR_TYPE_DEBUG, "Signalling timeout of request for transmission to CORE service\n"); request_next_transmission (pr); GNUNET_assert (0 == th->get_message (th->get_message_cls, 0, NULL)); GNUNET_free (th); } /** * Transmit the next message to the core service. * * @param cls closure with the 'struct GNUNET_CORE_Handle' * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_message (void *cls, size_t size, void *buf) { struct GNUNET_CORE_Handle *h = cls; struct ControlMessage *cm; struct GNUNET_CORE_TransmitHandle *th; struct PeerRecord *pr; struct SendMessage *sm; const struct GNUNET_MessageHeader *hdr; uint16_t msize; size_t ret; GNUNET_assert (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK); h->cth = NULL; if (buf == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission failed, initiating reconnect\n"); reconnect_later (h); return 0; } /* first check for control messages */ if (NULL != (cm = h->control_pending_head)) { hdr = (const struct GNUNET_MessageHeader *) &cm[1]; msize = ntohs (hdr->size); if (size < msize) { trigger_next_request (h, GNUNET_NO); return 0; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting control message with %u bytes of type %u to core.\n", (unsigned int) msize, (unsigned int) ntohs (hdr->type)); memcpy (buf, hdr, msize); GNUNET_CONTAINER_DLL_remove (h->control_pending_head, h->control_pending_tail, cm); if (cm->th != NULL) cm->th->cm = NULL; if (NULL != cm->cont) cm->cont (cm->cont_cls, GNUNET_OK); GNUNET_free (cm); trigger_next_request (h, GNUNET_NO); return msize; } /* now check for 'ready' P2P messages */ if (NULL != (pr = h->ready_peer_head)) { GNUNET_assert (pr->pending_head != NULL); th = pr->pending_head; if (size < th->msize + sizeof (struct SendMessage)) { trigger_next_request (h, GNUNET_NO); return 0; } GNUNET_CONTAINER_DLL_remove (h->ready_peer_head, h->ready_peer_tail, pr); GNUNET_CONTAINER_DLL_remove (pr->pending_head, pr->pending_tail, th); pr->queue_size--; if (pr->timeout_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (pr->timeout_task); pr->timeout_task = GNUNET_SCHEDULER_NO_TASK; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting SEND request to `%s' with %u bytes.\n", GNUNET_i2s (&pr->peer), (unsigned int) th->msize); sm = (struct SendMessage *) buf; sm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND); sm->priority = htonl (th->priority); sm->deadline = GNUNET_TIME_absolute_hton (th->timeout); sm->peer = pr->peer; sm->cork = htonl ((uint32_t) th->cork); sm->reserved = htonl (0); ret = th->get_message (th->get_message_cls, size - sizeof (struct SendMessage), &sm[1]); LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting SEND request to `%s' yielded %u bytes.\n", GNUNET_i2s (&pr->peer), ret); GNUNET_free (th); if (0 == ret) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Size of clients message to peer %s is 0!\n", GNUNET_i2s (&pr->peer)); /* client decided to send nothing! */ request_next_transmission (pr); return 0; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Produced SEND message to core with %u bytes payload\n", (unsigned int) ret); GNUNET_assert (ret >= sizeof (struct GNUNET_MessageHeader)); if (ret + sizeof (struct SendMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); request_next_transmission (pr); return 0; } ret += sizeof (struct SendMessage); sm->header.size = htons (ret); GNUNET_assert (ret <= size); request_next_transmission (pr); return ret; } return 0; } /** * Check the list of pending requests, send the next * one to the core. * * @param h core handle * @param ignore_currently_down transmit message even if not initialized? */ static void trigger_next_request (struct GNUNET_CORE_Handle *h, int ignore_currently_down) { uint16_t msize; if ((GNUNET_YES == h->currently_down) && (ignore_currently_down == GNUNET_NO)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Core connection down, not processing queue\n"); return; } if (NULL != h->cth) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Request pending, not processing queue\n"); return; } if (h->control_pending_head != NULL) msize = ntohs (((struct GNUNET_MessageHeader *) &h-> control_pending_head[1])->size); else if (h->ready_peer_head != NULL) msize = h->ready_peer_head->pending_head->msize + sizeof (struct SendMessage); else { LOG (GNUNET_ERROR_TYPE_DEBUG, "Request queue empty, not processing queue\n"); return; /* no pending message */ } h->cth = GNUNET_CLIENT_notify_transmit_ready (h->client, msize, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_NO, &transmit_message, h); } /** * Handler for notification messages received from the core. * * @param cls our "struct GNUNET_CORE_Handle" * @param msg the message received from the core service */ static void main_notify_handler (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_CORE_Handle *h = cls; const struct InitReplyMessage *m; const struct ConnectNotifyMessage *cnm; const struct DisconnectNotifyMessage *dnm; const struct NotifyTrafficMessage *ntm; const struct GNUNET_MessageHeader *em; const struct SendMessageReady *smr; const struct GNUNET_CORE_MessageHandler *mh; const struct GNUNET_ATS_Information *ats; GNUNET_CORE_StartupCallback init; struct PeerRecord *pr; struct GNUNET_CORE_TransmitHandle *th; unsigned int hpos; int trigger; uint16_t msize; uint16_t et; uint32_t ats_count; if (NULL == msg) { LOG (GNUNET_ERROR_TYPE_INFO, _ ("Client was disconnected from core service, trying to reconnect.\n")); reconnect_later (h); return; } msize = ntohs (msg->size); LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing message of type %u and size %u from core service\n", ntohs (msg->type), msize); switch (ntohs (msg->type)) { case GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY: if (ntohs (msg->size) != sizeof (struct InitReplyMessage)) { GNUNET_break (0); reconnect_later (h); return; } m = (const struct InitReplyMessage *) msg; GNUNET_break (0 == ntohl (m->reserved)); /* start our message processing loop */ if (GNUNET_YES == h->currently_down) { h->currently_down = GNUNET_NO; trigger_next_request (h, GNUNET_NO); } h->retry_backoff = GNUNET_TIME_UNIT_MILLISECONDS; h->me = m->my_identity; if (NULL != (init = h->init)) { /* mark so we don't call init on reconnect */ h->init = NULL; LOG (GNUNET_ERROR_TYPE_DEBUG, "Connected to core service of peer `%s'.\n", GNUNET_i2s (&h->me)); init (h->cls, h, &h->me); } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "Successfully reconnected to core service.\n"); } /* fake 'connect to self' */ pr = GNUNET_CONTAINER_multihashmap_get (h->peers, &h->me.hashPubKey); GNUNET_assert (NULL == pr); pr = GNUNET_malloc (sizeof (struct PeerRecord)); pr->peer = h->me; pr->ch = h; GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_put (h->peers, &h->me.hashPubKey, pr, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); if (NULL != h->connects) h->connects (h->cls, &h->me, NULL, 0); break; case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT: if (msize < sizeof (struct ConnectNotifyMessage)) { GNUNET_break (0); reconnect_later (h); return; } cnm = (const struct ConnectNotifyMessage *) msg; ats_count = ntohl (cnm->ats_count); if (msize != sizeof (struct ConnectNotifyMessage) + ats_count * sizeof (struct GNUNET_ATS_Information)) { GNUNET_break (0); reconnect_later (h); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Received notification about connection from `%s'.\n", GNUNET_i2s (&cnm->peer)); if (0 == memcmp (&h->me, &cnm->peer, sizeof (struct GNUNET_PeerIdentity))) { /* connect to self!? */ GNUNET_break (0); return; } pr = GNUNET_CONTAINER_multihashmap_get (h->peers, &cnm->peer.hashPubKey); if (NULL != pr) { GNUNET_break (0); reconnect_later (h); return; } pr = GNUNET_malloc (sizeof (struct PeerRecord)); pr->peer = cnm->peer; pr->ch = h; GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_put (h->peers, &cnm->peer.hashPubKey, pr, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); ats = (const struct GNUNET_ATS_Information *) &cnm[1]; if (NULL != h->connects) h->connects (h->cls, &cnm->peer, ats, ats_count); break; case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT: if (msize != sizeof (struct DisconnectNotifyMessage)) { GNUNET_break (0); reconnect_later (h); return; } dnm = (const struct DisconnectNotifyMessage *) msg; if (0 == memcmp (&h->me, &dnm->peer, sizeof (struct GNUNET_PeerIdentity))) { /* connection to self!? */ GNUNET_break (0); return; } GNUNET_break (0 == ntohl (dnm->reserved)); LOG (GNUNET_ERROR_TYPE_DEBUG, "Received notification about disconnect from `%s'.\n", GNUNET_i2s (&dnm->peer)); pr = GNUNET_CONTAINER_multihashmap_get (h->peers, &dnm->peer.hashPubKey); if (NULL == pr) { GNUNET_break (0); reconnect_later (h); return; } trigger = ((pr->prev != NULL) || (pr->next != NULL) || (h->ready_peer_head == pr)); disconnect_and_free_peer_entry (h, &dnm->peer.hashPubKey, pr); if (trigger) trigger_next_request (h, GNUNET_NO); break; case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND: if (msize < sizeof (struct NotifyTrafficMessage)) { GNUNET_break (0); reconnect_later (h); return; } ntm = (const struct NotifyTrafficMessage *) msg; ats_count = ntohl (ntm->ats_count); if ((msize < sizeof (struct NotifyTrafficMessage) + ats_count * sizeof (struct GNUNET_ATS_Information) + sizeof (struct GNUNET_MessageHeader)) ) { GNUNET_break (0); reconnect_later (h); return; } ats = (const struct GNUNET_ATS_Information*) &ntm[1]; em = (const struct GNUNET_MessageHeader *) &ats[ats_count]; LOG (GNUNET_ERROR_TYPE_DEBUG, "Received message of type %u and size %u from peer `%4s'\n", ntohs (em->type), ntohs (em->size), GNUNET_i2s (&ntm->peer)); if ((GNUNET_NO == h->inbound_hdr_only) && (msize != ntohs (em->size) + sizeof (struct NotifyTrafficMessage) + +ats_count * sizeof (struct GNUNET_ATS_Information))) { GNUNET_break (0); reconnect_later (h); return; } et = ntohs (em->type); for (hpos = 0; hpos < h->hcnt; hpos++) { mh = &h->handlers[hpos]; if (mh->type != et) continue; if ((mh->expected_size != ntohs (em->size)) && (mh->expected_size != 0)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected message size %u for message of type %u from peer `%4s'\n", htons (em->size), mh->type, GNUNET_i2s (&ntm->peer)); GNUNET_break_op (0); continue; } pr = GNUNET_CONTAINER_multihashmap_get (h->peers, &ntm->peer.hashPubKey); if (NULL == pr) { GNUNET_break (0); reconnect_later (h); return; } if (GNUNET_OK != h->handlers[hpos].callback (h->cls, &ntm->peer, em, ats, ats_count)) { /* error in processing, do not process other messages! */ break; } } if (NULL != h->inbound_notify) h->inbound_notify (h->cls, &ntm->peer, em, ats, ats_count); break; case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND: if (msize < sizeof (struct NotifyTrafficMessage)) { GNUNET_break (0); reconnect_later (h); return; } ntm = (const struct NotifyTrafficMessage *) msg; ats_count = ntohl (ntm->ats_count); if ((msize < sizeof (struct NotifyTrafficMessage) + ats_count * sizeof (struct GNUNET_ATS_Information) + sizeof (struct GNUNET_MessageHeader)) ) { GNUNET_break (0); reconnect_later (h); return; } ats = (const struct GNUNET_ATS_Information*) &ntm[1]; em = (const struct GNUNET_MessageHeader *) &ats[ats_count]; LOG (GNUNET_ERROR_TYPE_DEBUG, "Received notification about transmission to `%s'.\n", GNUNET_i2s (&ntm->peer)); if ((GNUNET_NO == h->outbound_hdr_only) && (msize != ntohs (em->size) + sizeof (struct NotifyTrafficMessage) + ats_count * sizeof (struct GNUNET_ATS_Information))) { GNUNET_break (0); reconnect_later (h); return; } if (NULL == h->outbound_notify) { GNUNET_break (0); break; } h->outbound_notify (h->cls, &ntm->peer, em, ats, ats_count); break; case GNUNET_MESSAGE_TYPE_CORE_SEND_READY: if (msize != sizeof (struct SendMessageReady)) { GNUNET_break (0); reconnect_later (h); return; } smr = (const struct SendMessageReady *) msg; pr = GNUNET_CONTAINER_multihashmap_get (h->peers, &smr->peer.hashPubKey); if (NULL == pr) { GNUNET_break (0); reconnect_later (h); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Received notification about transmission readiness to `%s'.\n", GNUNET_i2s (&smr->peer)); if (NULL == pr->pending_head) { /* request must have been cancelled between the original request * and the response from core, ignore core's readiness */ break; } th = pr->pending_head; if (ntohs (smr->smr_id) != th->smr_id) { /* READY message is for expired or cancelled message, * ignore! (we should have already sent another request) */ break; } if ((NULL != pr->prev) || (NULL != pr->next) || (h->ready_peer_head == pr)) { /* we should not already be on the ready list... */ GNUNET_break (0); reconnect_later (h); return; } GNUNET_CONTAINER_DLL_insert (h->ready_peer_head, h->ready_peer_tail, pr); trigger_next_request (h, GNUNET_NO); break; default: reconnect_later (h); return; } GNUNET_CLIENT_receive (h->client, &main_notify_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); } /** * Task executed once we are done transmitting the INIT message. * Starts our 'receive' loop. * * @param cls the 'struct GNUNET_CORE_Handle' * @param success were we successful */ static void init_done_task (void *cls, int success) { struct GNUNET_CORE_Handle *h = cls; if (GNUNET_SYSERR == success) return; /* shutdown */ if (GNUNET_NO == success) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to exchange INIT with core, retrying\n"); if (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK) reconnect_later (h); return; } GNUNET_CLIENT_receive (h->client, &main_notify_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); } /** * Our current client connection went down. Clean it up * and try to reconnect! * * @param h our handle to the core service */ static void reconnect (struct GNUNET_CORE_Handle *h) { struct ControlMessage *cm; struct InitMessage *init; uint32_t opt; uint16_t msize; uint16_t *ts; unsigned int hpos; GNUNET_assert (NULL == h->client); GNUNET_assert (h->currently_down == GNUNET_YES); h->client = GNUNET_CLIENT_connect ("core", h->cfg); if (NULL == h->client) { reconnect_later (h); return; } msize = h->hcnt * sizeof (uint16_t) + sizeof (struct InitMessage); cm = GNUNET_malloc (sizeof (struct ControlMessage) + msize); cm->cont = &init_done_task; cm->cont_cls = h; init = (struct InitMessage *) &cm[1]; init->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT); init->header.size = htons (msize); opt = 0; if (h->inbound_notify != NULL) { if (h->inbound_hdr_only) opt |= GNUNET_CORE_OPTION_SEND_HDR_INBOUND; else opt |= GNUNET_CORE_OPTION_SEND_FULL_INBOUND; } if (h->outbound_notify != NULL) { if (h->outbound_hdr_only) opt |= GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND; else opt |= GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND; } LOG (GNUNET_ERROR_TYPE_INFO, "(Re)connecting to CORE service, monitoring messages of type %u\n", opt); init->options = htonl (opt); ts = (uint16_t *) & init[1]; for (hpos = 0; hpos < h->hcnt; hpos++) ts[hpos] = htons (h->handlers[hpos].type); GNUNET_CONTAINER_DLL_insert (h->control_pending_head, h->control_pending_tail, cm); trigger_next_request (h, GNUNET_YES); } /** * Connect to the core service. Note that the connection may * complete (or fail) asynchronously. * * @param cfg configuration to use * @param queue_size size of the per-peer message queue * @param cls closure for the various callbacks that follow (including handlers in the handlers array) * @param init callback to call once we have successfully * connected to the core service * @param connects function to call on peer connect, can be NULL * @param disconnects function to call on peer disconnect / timeout, can be NULL * @param inbound_notify function to call for all inbound messages, can be NULL * @param inbound_hdr_only set to GNUNET_YES if inbound_notify will only read the * GNUNET_MessageHeader and hence we do not need to give it the full message; * can be used to improve efficiency, ignored if inbound_notify is NULLL * @param outbound_notify function to call for all outbound messages, can be NULL * @param outbound_hdr_only set to GNUNET_YES if outbound_notify will only read the * GNUNET_MessageHeader and hence we do not need to give it the full message * can be used to improve efficiency, ignored if outbound_notify is NULLL * @param handlers callbacks for messages we care about, NULL-terminated * @return handle to the core service (only useful for disconnect until 'init' is called); * NULL on error (in this case, init is never called) */ struct GNUNET_CORE_Handle * GNUNET_CORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned int queue_size, void *cls, GNUNET_CORE_StartupCallback init, GNUNET_CORE_ConnectEventHandler connects, GNUNET_CORE_DisconnectEventHandler disconnects, GNUNET_CORE_MessageCallback inbound_notify, int inbound_hdr_only, GNUNET_CORE_MessageCallback outbound_notify, int outbound_hdr_only, const struct GNUNET_CORE_MessageHandler *handlers) { struct GNUNET_CORE_Handle *h; h = GNUNET_malloc (sizeof (struct GNUNET_CORE_Handle)); h->cfg = cfg; h->queue_size = queue_size; h->cls = cls; h->init = init; h->connects = connects; h->disconnects = disconnects; h->inbound_notify = inbound_notify; h->outbound_notify = outbound_notify; h->inbound_hdr_only = inbound_hdr_only; h->outbound_hdr_only = outbound_hdr_only; h->handlers = handlers; h->hcnt = 0; h->currently_down = GNUNET_YES; h->peers = GNUNET_CONTAINER_multihashmap_create (128); h->retry_backoff = GNUNET_TIME_UNIT_MILLISECONDS; if (NULL != handlers) while (handlers[h->hcnt].callback != NULL) h->hcnt++; GNUNET_assert (h->hcnt < (GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct InitMessage)) / sizeof (uint16_t)); LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CORE service\n"); reconnect (h); return h; } /** * Disconnect from the core service. This function can only * be called *after* all pending 'GNUNET_CORE_notify_transmit_ready' * requests have been explicitly canceled. * * @param handle connection to core to disconnect */ void GNUNET_CORE_disconnect (struct GNUNET_CORE_Handle *handle) { struct ControlMessage *cm; LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from CORE service\n"); if (NULL != handle->cth) { GNUNET_CLIENT_notify_transmit_ready_cancel (handle->cth); handle->cth = NULL; } while (NULL != (cm = handle->control_pending_head)) { GNUNET_CONTAINER_DLL_remove (handle->control_pending_head, handle->control_pending_tail, cm); if (NULL != cm->th) cm->th->cm = NULL; if (NULL != cm->cont) cm->cont (cm->cont_cls, GNUNET_SYSERR); GNUNET_free (cm); } if (NULL != handle->client) { GNUNET_CLIENT_disconnect (handle->client); handle->client = NULL; } GNUNET_CONTAINER_multihashmap_iterate (handle->peers, &disconnect_and_free_peer_entry, handle); if (handle->reconnect_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (handle->reconnect_task); handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_CONTAINER_multihashmap_destroy (handle->peers); handle->peers = NULL; GNUNET_break (handle->ready_peer_head == NULL); GNUNET_free (handle); } /** * Task that calls 'request_next_transmission'. * * @param cls the 'struct PeerRecord*' * @param tc scheduler context */ static void run_request_next_transmission (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerRecord *pr = cls; pr->ntr_task = GNUNET_SCHEDULER_NO_TASK; request_next_transmission (pr); } /** * Ask the core to call "notify" once it is ready to transmit the * given number of bytes to the specified "target". Must only be * called after a connection to the respective peer has been * established (and the client has been informed about this). * * @param handle connection to core service * @param cork is corking allowed for this transmission? * @param priority how important is the message? * @param maxdelay how long can the message wait? * @param target who should receive the message, never NULL (can be this peer's identity for loopback) * @param notify_size how many bytes of buffer space does notify want? * @param notify function to call when buffer space is available * @param notify_cls closure for notify * @return non-NULL if the notify callback was queued, * NULL if we can not even queue the request (insufficient * memory); if NULL is returned, "notify" will NOT be called. */ struct GNUNET_CORE_TransmitHandle * GNUNET_CORE_notify_transmit_ready (struct GNUNET_CORE_Handle *handle, int cork, uint32_t priority, struct GNUNET_TIME_Relative maxdelay, const struct GNUNET_PeerIdentity *target, size_t notify_size, GNUNET_CONNECTION_TransmitReadyNotify notify, void *notify_cls) { struct PeerRecord *pr; struct GNUNET_CORE_TransmitHandle *th; struct GNUNET_CORE_TransmitHandle *pos; struct GNUNET_CORE_TransmitHandle *prev; struct GNUNET_CORE_TransmitHandle *minp; pr = GNUNET_CONTAINER_multihashmap_get (handle->peers, &target->hashPubKey); if (NULL == pr) { /* attempt to send to peer that is not connected */ LOG (GNUNET_ERROR_TYPE_WARNING, "Attempting to send to peer `%s' from peer `%s', but not connected!\n", GNUNET_i2s (target), GNUNET_h2s (&handle->me.hashPubKey)); GNUNET_break (0); return NULL; } GNUNET_assert (notify_size + sizeof (struct SendMessage) < GNUNET_SERVER_MAX_MESSAGE_SIZE); th = GNUNET_malloc (sizeof (struct GNUNET_CORE_TransmitHandle)); th->peer = pr; GNUNET_assert (NULL != notify); th->get_message = notify; th->get_message_cls = notify_cls; th->timeout = GNUNET_TIME_relative_to_absolute (maxdelay); th->priority = priority; th->msize = notify_size; th->cork = cork; /* bound queue size */ if (pr->queue_size == handle->queue_size) { /* find lowest-priority entry, but skip the head of the list */ minp = pr->pending_head->next; prev = minp; while (prev != NULL) { if (prev->priority < minp->priority) minp = prev; prev = prev->next; } if (minp == NULL) { GNUNET_break (handle->queue_size != 0); GNUNET_break (pr->queue_size == 1); GNUNET_free (th); LOG (GNUNET_ERROR_TYPE_DEBUG, "Dropping transmission request: cannot drop queue head and limit is one\n"); return NULL; } if (priority <= minp->priority) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Dropping transmission request: priority too low\n"); GNUNET_free (th); return NULL; /* priority too low */ } GNUNET_CONTAINER_DLL_remove (pr->pending_head, pr->pending_tail, minp); pr->queue_size--; GNUNET_assert (0 == minp->get_message (minp->get_message_cls, 0, NULL)); GNUNET_free (minp); } /* Order entries by deadline, but SKIP 'HEAD' (as we may have transmitted * that request already or might even already be approved to transmit that * message to core) */ pos = pr->pending_head; if (pos != NULL) pos = pos->next; /* skip head */ /* insertion sort */ prev = pos; while ((NULL != pos) && (pos->timeout.abs_value < th->timeout.abs_value)) { prev = pos; pos = pos->next; } GNUNET_CONTAINER_DLL_insert_after (pr->pending_head, pr->pending_tail, prev, th); pr->queue_size++; /* was the request queue previously empty? */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission request added to queue\n"); if ((pr->pending_head == th) && (pr->ntr_task == GNUNET_SCHEDULER_NO_TASK) && (pr->next == NULL) && (pr->prev == NULL) && (handle->ready_peer_head != pr)) pr->ntr_task = GNUNET_SCHEDULER_add_now (&run_request_next_transmission, pr); return th; } /** * Cancel the specified transmission-ready notification. * * @param th handle that was returned by "notify_transmit_ready". */ void GNUNET_CORE_notify_transmit_ready_cancel (struct GNUNET_CORE_TransmitHandle *th) { struct PeerRecord *pr = th->peer; struct GNUNET_CORE_Handle *h = pr->ch; int was_head; was_head = (pr->pending_head == th); GNUNET_CONTAINER_DLL_remove (pr->pending_head, pr->pending_tail, th); pr->queue_size--; if (NULL != th->cm) { /* we're currently in the control queue, remove */ GNUNET_CONTAINER_DLL_remove (h->control_pending_head, h->control_pending_tail, th->cm); GNUNET_free (th->cm); } GNUNET_free (th); if (was_head) { if ((NULL != pr->prev) || (NULL != pr->next) || (pr == h->ready_peer_head)) { /* the request that was 'approved' by core was * canceled before it could be transmitted; remove * us from the 'ready' list */ GNUNET_CONTAINER_DLL_remove (h->ready_peer_head, h->ready_peer_tail, pr); } if (NULL != h->client) request_next_transmission (pr); } } /* end of core_api.c */ gnunet-0.9.3/src/core/core.h0000644000175000017500000001722411760502551012574 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file core/core.h * @brief common internal definitions for core service * @author Christian Grothoff */ #ifndef CORE_H #define CORE_H #include "gnunet_bandwidth_lib.h" #include "gnunet_transport_service.h" #include "gnunet_crypto_lib.h" #include "gnunet_time_lib.h" /** * General core debugging. */ #define DEBUG_CORE GNUNET_EXTRA_LOGGING /** * Definition of bits in the InitMessage's options field that specify * which events this client cares about. Note that inbound messages * for handlers that were specifically registered are always * transmitted to the client. */ #define GNUNET_CORE_OPTION_NOTHING 0 #define GNUNET_CORE_OPTION_SEND_STATUS_CHANGE 4 #define GNUNET_CORE_OPTION_SEND_FULL_INBOUND 8 #define GNUNET_CORE_OPTION_SEND_HDR_INBOUND 16 #define GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND 32 #define GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND 64 GNUNET_NETWORK_STRUCT_BEGIN /** * Message transmitted core clients to gnunet-service-core * to start the interaction. This header is followed by * uint16_t type values specifying which messages this * client is interested in. */ struct InitMessage { /** * Header with type GNUNET_MESSAGE_TYPE_CORE_INIT. */ struct GNUNET_MessageHeader header; /** * Options, see GNUNET_CORE_OPTION_ values. */ uint32_t options GNUNET_PACKED; }; /** * Message transmitted by the gnunet-service-core process * to its clients in response to an INIT message. */ struct InitReplyMessage { /** * Header with type GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY */ struct GNUNET_MessageHeader header; /** * Always zero. */ uint32_t reserved GNUNET_PACKED; /** * Public key of the local peer. */ struct GNUNET_PeerIdentity my_identity; }; /** * Message sent by the service to clients to notify them * about a peer connecting. */ struct ConnectNotifyMessage { /** * Header with type GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT */ struct GNUNET_MessageHeader header; /** * Number of ATS key-value pairs that follow this struct */ uint32_t ats_count GNUNET_PACKED; /** * Identity of the connecting peer. */ struct GNUNET_PeerIdentity peer; }; /** * Message sent by the service to clients to notify them * about a peer changing status. */ struct PeerStatusNotifyMessage { /** * Header with type GNUNET_MESSAGE_TYPE_CORE_NOTIFY_PEER_STATUS */ struct GNUNET_MessageHeader header; /** * Number of ATS key-value pairs that follow this struct * (excluding the 0-terminator). */ uint32_t ats_count GNUNET_PACKED; /** * When the peer would time out (unless we see activity) */ struct GNUNET_TIME_AbsoluteNBO timeout; /** * Available bandwidth from the peer. */ struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in; /** * Available bandwidth to the peer. */ struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out; /** * Identity of the peer. */ struct GNUNET_PeerIdentity peer; /** * First of the ATS information blocks (we must have at least * one due to the 0-termination requirement). */ struct GNUNET_ATS_Information ats; }; /** * Message sent by the service to clients to notify them * about a peer disconnecting. */ struct DisconnectNotifyMessage { /** * Header with type GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT. */ struct GNUNET_MessageHeader header; /** * Always zero. */ uint32_t reserved GNUNET_PACKED; /** * Identity of the connecting peer. */ struct GNUNET_PeerIdentity peer; }; /** * Message sent by the service to clients to notify them about * messages being received or transmitted. This overall message is * followed by the real message, or just the header of the real * message (depending on the client's preferences). The receiver can * tell if he got the full message or only a partial message by * looking at the size field in the header of NotifyTrafficMessage and * checking it with the size field in the message that follows. */ struct NotifyTrafficMessage { /** * Header with type GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND * or GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND. */ struct GNUNET_MessageHeader header; /** * Number of ATS key-value pairs that follow this struct * (excluding the 0-terminator). */ uint32_t ats_count GNUNET_PACKED; /** * Identity of the receiver or sender. */ struct GNUNET_PeerIdentity peer; /* Followed by ATS information blocks: * struct GNUNET_ATS_Information ats[ats_count] */ /* Followed by payload (message or just header), variable size */ }; /** * Client notifying core about the maximum-priority * message it has in the queue for a particular target. */ struct SendMessageRequest { /** * Header with type GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST */ struct GNUNET_MessageHeader header; /** * How important is this message? */ uint32_t priority GNUNET_PACKED; /** * By what time would the sender really like to see this * message transmitted? */ struct GNUNET_TIME_AbsoluteNBO deadline; /** * Identity of the intended target. */ struct GNUNET_PeerIdentity peer; /** * How large is the client's message queue for this peer? */ uint32_t queue_size GNUNET_PACKED; /** * How large is the message? */ uint16_t size GNUNET_PACKED; /** * Counter for this peer to match SMRs to replies. */ uint16_t smr_id GNUNET_PACKED; }; /** * Core notifying client that it is allowed to now * transmit a message to the given target * (response to GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST). */ struct SendMessageReady { /** * Header with type GNUNET_MESSAGE_TYPE_CORE_SEND_READY */ struct GNUNET_MessageHeader header; /** * How many bytes are allowed for transmission? * Guaranteed to be at least as big as the requested size, * or ZERO if the request is rejected (will timeout, * peer disconnected, queue full, etc.). */ uint16_t size GNUNET_PACKED; /** * smr_id from the request. */ uint16_t smr_id GNUNET_PACKED; /** * Identity of the intended target. */ struct GNUNET_PeerIdentity peer; }; /** * Client asking core to transmit a particular message to a particular * target (response to GNUNET_MESSAGE_TYPE_CORE_SEND_READY). */ struct SendMessage { /** * Header with type GNUNET_MESSAGE_TYPE_CORE_SEND */ struct GNUNET_MessageHeader header; /** * How important is this message? */ uint32_t priority GNUNET_PACKED; /** * By what time would the sender really like to see this * message transmitted? */ struct GNUNET_TIME_AbsoluteNBO deadline; /** * Identity of the intended receiver. */ struct GNUNET_PeerIdentity peer; /** * GNUNET_YES if corking is allowed, GNUNET_NO if not. */ uint32_t cork GNUNET_PACKED; /** * Always 0. */ uint64_t reserved GNUNET_PACKED; }; GNUNET_NETWORK_STRUCT_END #endif /* end of core.h */ gnunet-0.9.3/src/core/gnunet-service-core_sessions.h0000644000175000017500000001263111760502551017453 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file core/gnunet-service-core_neighbours.h * @brief code for managing of 'encrypted' sessions (key exchange done) * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_CORE_SESSIONS_H #define GNUNET_SERVICE_CORE_SESSIONS_H #include "gnunet-service-core.h" #include "gnunet-service-core_kx.h" /** * Create a session, a key exchange was just completed. * * @param peer peer that is now connected * @param kx key exchange that completed */ void GSC_SESSIONS_create (const struct GNUNET_PeerIdentity *peer, struct GSC_KeyExchangeInfo *kx); /** * End the session with the given peer (we are no longer * connected). * * @param pid identity of peer to kill session with */ void GSC_SESSIONS_end (const struct GNUNET_PeerIdentity *pid); /** * Traffic is being solicited for the given peer. This means that the * message queue on the transport-level (NEIGHBOURS subsystem) is now * empty and it is now OK to transmit another (non-control) message. * * @param pid identity of peer ready to receive data */ void GSC_SESSIONS_solicit (const struct GNUNET_PeerIdentity *pid); /** * Queue a request from a client for transmission to a particular peer. * * @param car request to queue; this handle is then shared between * the caller (CLIENTS subsystem) and SESSIONS and must not * be released by either until either 'GNUNET_SESSIONS_dequeue', * or 'GNUNET_CLIENTS_failed' * have been invoked on it */ void GSC_SESSIONS_queue_request (struct GSC_ClientActiveRequest *car); /** * Dequeue a request from a client from transmission to a particular peer. * * @param car request to dequeue; this handle will then be 'owned' by * the caller (CLIENTS sysbsystem) */ void GSC_SESSIONS_dequeue_request (struct GSC_ClientActiveRequest *car); /** * Transmit a message to a particular peer. * * @param car original request that was queued and then solicited, * ownership does not change (dequeue will be called soon). * @param msg message to transmit * @param cork is corking allowed? */ void GSC_SESSIONS_transmit (struct GSC_ClientActiveRequest *car, const struct GNUNET_MessageHeader *msg, int cork); /** * Broadcast a message to all neighbours. * * @param msg message to transmit */ void GSC_SESSIONS_broadcast (const struct GNUNET_MessageHeader *msg); /** * We have a new client, notify it about all current sessions. * * @param client the new client */ void GSC_SESSIONS_notify_client_about_sessions (struct GSC_Client *client); /** * We've received a typemap message from a peer, update ours. * Notifies clients about the session. * * @param peer peer this is about * @param msg typemap update message */ void GSC_SESSIONS_set_typemap (const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *msg); /** * The given peer send a message of the specified type. Make sure the * respective bit is set in its type-map and that clients are notified * about the session. * * @param peer peer this is about * @param type type of the message */ void GSC_SESSIONS_add_to_typemap (const struct GNUNET_PeerIdentity *peer, uint16_t type); /** * Handle CORE_ITERATE_PEERS request. For this request type, the client * does not have to have transmitted an INIT request. All current peers * are returned, regardless of which message types they accept. * * @param cls unused * @param client client sending the iteration request * @param message iteration request message */ void GSC_SESSIONS_handle_client_iterate_peers (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message); /** * Handle CORE_PEER_CONNECTED request. Notify client about connection * to the given neighbour. For this request type, the client does not * have to have transmitted an INIT request. All current peers are * returned, regardless of which message types they accept. * * @param cls unused * @param client client sending the iteration request * @param message iteration request message */ void GSC_SESSIONS_handle_client_have_peer (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message); /** * Initialize sessions subsystem. */ void GSC_SESSIONS_init (void); /** * Shutdown sessions subsystem. */ void GSC_SESSIONS_done (void); #endif gnunet-0.9.3/src/core/gnunet-service-core_neighbours.h0000644000175000017500000000403111760502551017745 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file core/gnunet-service-core_neighbours.h * @brief code for managing low-level 'plaintext' connections with transport (key exchange may or may not be done yet) * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_CORE_NEIGHBOURS_H #define GNUNET_SERVICE_CORE_NEIGHBOURS_H #include "gnunet_util_lib.h" /** * Transmit the given message to the given target. Note that a * non-control messages should only be transmitted after a * 'GSC_SESSION_solicit' call was made (that call is always invoked * when the message queue is empty). Outbound quotas and memory * bounds will then be enfoced (as GSC_SESSION_solicit is only called * if sufficient banwdith is available). * * @param target peer that should receive the message (must be connected) * @param msg message to transmit * @param timeout by when should the transmission be done? */ void GSC_NEIGHBOURS_transmit (const struct GNUNET_PeerIdentity *target, const struct GNUNET_MessageHeader *msg, struct GNUNET_TIME_Relative timeout); /** * Initialize neighbours subsystem. */ int GSC_NEIGHBOURS_init (void); /** * Shutdown neighbours subsystem. */ void GSC_NEIGHBOURS_done (void); #endif gnunet-0.9.3/src/Makefile.am0000644000175000017500000000134111760460615012574 00000000000000#if WANT_FRAMEWORK # INTLEMU_SUBDIRS = intlemu #endif if HAVE_EXPERIMENTAL EXP_DIR = chat dv stream regex endif if LINUX # All of these currently only work on GNU/Linux LINUX_DIR = dns gns exit vpn pt endif if HAVE_MYSQL MYSQL_DIR = mysql endif if HAVE_POSTGRES POSTGRES_DIR = postgres endif SUBDIRS = \ include $(INTLEMU_SUBDIRS) \ util \ hello \ tun \ block \ statistics \ arm \ peerinfo \ $(MYSQL_DIR) \ $(POSTGRES_DIR) \ datacache \ datastore \ namestore \ template \ ats \ nat \ fragmentation \ transport \ peerinfo-tool \ core \ testing \ testbed \ nse \ dht \ hostlist \ topology \ fs \ mesh \ lockmanager \ $(LINUX_DIR) \ integration-tests \ $(EXP_DIR) gnunet-0.9.3/src/vpn/0000755000175000017500000000000011763406750011427 500000000000000gnunet-0.9.3/src/vpn/gnunet-vpn.c0000644000175000017500000001752011760502550013611 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/vpn/gnunet-vpn.c * @brief Tool to manually request VPN tunnels to be created * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_vpn_service.h" /** * Handle to vpn service. */ static struct GNUNET_VPN_Handle *handle; /** * Opaque redirection request handle. */ static struct GNUNET_VPN_RedirectionRequest *request; /** * Option -p: destination peer identity for service */ static char *peer_id; /** * Option -s: service name (hash to get service descriptor) */ static char *service_name; /** * Option -i: target IP */ static char *target_ip; /** * Option -4: IPv4 requested. */ static int ipv4; /** * Option -6: IPv6 requested. */ static int ipv6; /** * Option -t: TCP requested. */ static int tcp; /** * Option -u: UDP requested. */ static int udp; /** * Selected level of verbosity. */ static int verbosity; /** * Option '-a': Notify only once the tunnel is connected? */ static int nac; /** * Global return value. */ static int ret; /** * Option '-d': duration of the mapping */ static unsigned long long duration = 5 * 60; /** * Shutdown. */ static void do_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (NULL != request) { GNUNET_VPN_cancel_request (request); request = NULL; } if (NULL != handle) { GNUNET_VPN_disconnect (handle); handle = NULL; } GNUNET_free_non_null (peer_id); GNUNET_free_non_null (service_name); GNUNET_free_non_null (target_ip); } /** * Callback invoked from the VPN service once a redirection is * available. Provides the IP address that can now be used to * reach the requested destination. * * @param cls closure * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error; * will match 'result_af' from the request * @param address IP address (struct in_addr or struct in_addr6, depending on 'af') * that the VPN allocated for the redirection; * traffic to this IP will now be redirected to the * specified target peer; NULL on error */ static void allocation_cb (void *cls, int af, const void *address) { char buf[INET6_ADDRSTRLEN]; request = NULL; switch (af) { case AF_INET6: case AF_INET: FPRINTF (stdout, "%s\n", inet_ntop (af, address, buf, sizeof (buf))); break; case AF_UNSPEC: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Error creating tunnel\n")); ret = 1; break; default: break; } GNUNET_SCHEDULER_shutdown (); } /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param cfg configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { int dst_af; int req_af; struct GNUNET_PeerIdentity peer; GNUNET_HashCode sd; const void *addr; struct in_addr v4; struct in6_addr v6; uint8_t protocol; struct GNUNET_TIME_Absolute etime; etime = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, (unsigned int) duration)); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &do_disconnect, NULL); handle = GNUNET_VPN_connect (cfg); if (NULL == handle) goto error; req_af = AF_UNSPEC; if (ipv4) { if (ipv6) { FPRINTF (stderr, _("Option `%s' makes no sense with option `%s'.\n"), "-4", "-6"); goto error; } req_af = AF_INET; } if (ipv6) req_af = AF_INET6; if (NULL == target_ip) { if (NULL == service_name) { FPRINTF (stderr, _("Option `%s' or `%s' is required.\n"), "-i", "-s"); goto error; } if (NULL == peer_id) { FPRINTF (stderr, _("Option `%s' is required when using option `%s'.\n"), "-p", "-s"); goto error; } if (! (tcp | udp) ) { FPRINTF (stderr, _("Option `%s' or `%s' is required when using option `%s'.\n"), "-t", "-u", "-s"); goto error; } if (tcp & udp) { FPRINTF (stderr, _("Option `%s' makes no sense with option `%s'.\n"), "-t", "-u"); goto error; } if (tcp) protocol = IPPROTO_TCP; if (udp) protocol = IPPROTO_UDP; if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (peer_id, &peer.hashPubKey)) { FPRINTF (stderr, _("`%s' is not a valid peer identifier.\n"), peer_id); goto error; } GNUNET_CRYPTO_hash (service_name, strlen (service_name), &sd); request = GNUNET_VPN_redirect_to_peer (handle, req_af, protocol, &peer, &sd, nac, etime, &allocation_cb, NULL); } else { if (1 != inet_pton (AF_INET6, target_ip, &v6)) { if (1 != inet_pton (AF_INET, target_ip, &v4)) { FPRINTF (stderr, _("`%s' is not a valid IP address.\n"), target_ip); goto error; } else { dst_af = AF_INET; addr = &v4; } } else { dst_af = AF_INET6; addr = &v6; } request = GNUNET_VPN_redirect_to_ip (handle, req_af, dst_af, addr, nac, etime, &allocation_cb, NULL); } return; error: GNUNET_SCHEDULER_shutdown (); ret = 1; } int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { {'4', "ipv4", NULL, gettext_noop ("request that result should be an IPv4 address"), 0, &GNUNET_GETOPT_set_one, &ipv4}, {'6', "ipv6", NULL, gettext_noop ("request that result should be an IPv6 address"), 0, &GNUNET_GETOPT_set_one, &ipv6}, {'a', "after-connect", NULL, gettext_noop ("print IP address only after mesh tunnel has been created"), 0, &GNUNET_GETOPT_set_one, &ipv6}, {'d', "duration", "SECONDS", gettext_noop ("how long should the mapping be valid for new tunnels?"), 1, &GNUNET_GETOPT_set_ulong, &duration}, {'i', "ip", "IP", gettext_noop ("destination IP for the tunnel"), 1, &GNUNET_GETOPT_set_string, &target_ip}, {'p', "peer", "PEERID", gettext_noop ("peer offering the service we would like to access"), 1, &GNUNET_GETOPT_set_string, &peer_id}, {'s', "service", "NAME", gettext_noop ("name of the service we would like to access"), 1, &GNUNET_GETOPT_set_string, &service_name}, {'t', "tcp", NULL, gettext_noop ("service is offered via TCP"), 0, &GNUNET_GETOPT_set_one, &tcp}, {'u', "udp", NULL, gettext_noop ("service is offered via UDP"), 0, &GNUNET_GETOPT_set_one, &udp}, GNUNET_GETOPT_OPTION_VERBOSE (&verbosity), GNUNET_GETOPT_OPTION_END }; return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-vpn", gettext_noop ("Setup tunnels via VPN."), options, &run, NULL)) ? ret : 1; } /* end of gnunet-vpn.c */ gnunet-0.9.3/src/vpn/vpn_api.c0000644000175000017500000003637511760502550013155 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file vpn/vpn_api.c * @brief library to access the VPN service and tell it how to redirect traffic * @author Christian Grothoff */ #include "platform.h" #include "gnunet_vpn_service.h" #include "vpn.h" /** * Opaque VPN handle */ struct GNUNET_VPN_Handle { /** * Configuration we use. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Connection to VPN service. */ struct GNUNET_CLIENT_Connection *client; /** * Active transmission request. */ struct GNUNET_CLIENT_TransmitHandle *th; /** * Head of list of active redirection requests. */ struct GNUNET_VPN_RedirectionRequest *rr_head; /** * Tail of list of active redirection requests. */ struct GNUNET_VPN_RedirectionRequest *rr_tail; /** * Identifier of a reconnect task. */ GNUNET_SCHEDULER_TaskIdentifier rt; /** * How long do we wait until we try to reconnect? */ struct GNUNET_TIME_Relative backoff; /** * ID of the last request that was submitted to the service. */ uint64_t request_id_gen; }; /** * Opaque redirection request handle. */ struct GNUNET_VPN_RedirectionRequest { /** * Element in DLL. */ struct GNUNET_VPN_RedirectionRequest *next; /** * Element in DLL. */ struct GNUNET_VPN_RedirectionRequest *prev; /** * Pointer to the VPN struct. */ struct GNUNET_VPN_Handle *vh; /** * Target IP address for the redirection, or NULL for * redirection to service. Allocated after this struct. */ const void *addr; /** * Function to call with the designated IP address. */ GNUNET_VPN_AllocationCallback cb; /** * Closure for 'cb'. */ void *cb_cls; /** * For service redirection, identity of the peer offering the service. */ struct GNUNET_PeerIdentity peer; /** * For service redirection, service descriptor. */ GNUNET_HashCode serv; /** * At what time should the created service mapping expire? */ struct GNUNET_TIME_Absolute expiration_time; /** * non-zero if this request has been sent to the service. */ uint64_t request_id; /** * Desired address family for the result. */ int result_af; /** * Address family of 'addr'. AF_INET or AF_INET6. */ int addr_af; /** * GNUNET_YES if we are to call the callback only after successful * mesh tunnel creation. */ int nac; /** * For service redirection, IPPROT_UDP or IPPROTO_TCP. */ uint8_t protocol; }; /** * Disconnect from the service (communication error) and reconnect later. * * @param vh handle to reconnect. */ static void reconnect (struct GNUNET_VPN_Handle *vh); /** * Function called when we receive a message from the VPN service. * * @param cls the 'struct GNUNET_VPN_Handle' * @param msg message received, NULL on timeout or fatal error */ static void receive_response (void *cls, const struct GNUNET_MessageHeader* msg) { struct GNUNET_VPN_Handle *vh = cls; const struct RedirectToIpResponseMessage *rm; struct GNUNET_VPN_RedirectionRequest *rr; size_t msize; size_t alen; int af; if (NULL == msg) { reconnect (vh); return; } if ( (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP) || (sizeof (struct RedirectToIpResponseMessage) > (msize = ntohs (msg->size))) ) { GNUNET_break (0); reconnect (vh); return; } rm = (const struct RedirectToIpResponseMessage *) msg; af = (int) ntohl (rm->result_af); switch (af) { case AF_UNSPEC: alen = 0; break; case AF_INET: alen = sizeof (struct in_addr); break; case AF_INET6: alen = sizeof (struct in6_addr); break; default: GNUNET_break (0); reconnect (vh); return; } if ( (msize != alen + sizeof (struct RedirectToIpResponseMessage)) || (0 == rm->request_id) ) { GNUNET_break (0); reconnect (vh); return; } GNUNET_CLIENT_receive (vh->client, &receive_response, vh, GNUNET_TIME_UNIT_FOREVER_REL); for (rr = vh->rr_head; NULL != rr; rr = rr->next) { if (rr->request_id == rm->request_id) { GNUNET_CONTAINER_DLL_remove (vh->rr_head, vh->rr_tail, rr); rr->cb (rr->cb_cls, af, (af == AF_UNSPEC) ? NULL : &rm[1]); GNUNET_free (rr); break; } } } /** * We're ready to transmit a request to the VPN service. Do it. * * @param cls the 'struct GNUNET_VPN_Handle*' * @param size number of bytes available in buf * @param buf where to copy the request * @return number of bytes copied to 'buf' */ static size_t transmit_request (void *cls, size_t size, void *buf) { struct GNUNET_VPN_Handle *vh = cls; struct GNUNET_VPN_RedirectionRequest *rr; struct RedirectToIpRequestMessage rip; struct RedirectToServiceRequestMessage rs; char *cbuf; size_t alen; size_t ret; vh->th = NULL; /* find a pending request */ rr = vh->rr_head; while ( (NULL != rr) && (0 != rr->request_id) ) rr = rr->next; if (NULL == rr) return 0; if (0 == size) { reconnect (vh); return 0; } /* if first request, start receive loop */ if (0 == vh->request_id_gen) GNUNET_CLIENT_receive (vh->client, &receive_response, vh, GNUNET_TIME_UNIT_FOREVER_REL); if (NULL == rr->addr) { ret = sizeof (struct RedirectToServiceRequestMessage); GNUNET_assert (ret <= size); rs.header.size = htons ((uint16_t) ret); rs.header.type = htons (GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE); rs.nac = htonl (rr->nac); rs.expiration_time = GNUNET_TIME_absolute_hton (rr->expiration_time); rs.protocol = htonl (rr->protocol); rs.result_af = htonl (rr->result_af); rs.target = rr->peer; rs.service_descriptor = rr->serv; rs.request_id = rr->request_id = ++vh->request_id_gen; memcpy (buf, &rs, sizeof (struct RedirectToServiceRequestMessage)); } else { switch (rr->addr_af) { case AF_INET: alen = sizeof (struct in_addr); break; case AF_INET6: alen = sizeof (struct in6_addr); break; default: GNUNET_assert (0); return 0; } ret = alen + sizeof (struct RedirectToIpRequestMessage); GNUNET_assert (ret <= size); rip.header.size = htons ((uint16_t) ret); rip.header.type = htons (GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP); rip.nac = htonl (rr->nac); rip.expiration_time = GNUNET_TIME_absolute_hton (rr->expiration_time); rip.result_af = htonl (rr->result_af); rip.addr_af = htonl (rr->addr_af); rip.request_id = rr->request_id = ++vh->request_id_gen; cbuf = buf; memcpy (cbuf, &rip, sizeof (struct RedirectToIpRequestMessage)); memcpy (&cbuf[sizeof (struct RedirectToIpRequestMessage)], rr->addr, alen); } /* test if there are more pending requests */ while ( (NULL != rr) && (0 != rr->request_id) ) rr = rr->next; if (NULL != rr) vh->th = GNUNET_CLIENT_notify_transmit_ready (vh->client, sizeof (struct RedirectToServiceRequestMessage), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_NO, &transmit_request, vh); return ret; } /** * Add a request to our request queue and transmit it. * * @param rr request to queue and transmit. */ static void queue_request (struct GNUNET_VPN_RedirectionRequest *rr) { struct GNUNET_VPN_Handle *vh; vh = rr->vh; GNUNET_CONTAINER_DLL_insert_tail (vh->rr_head, vh->rr_tail, rr); if ( (NULL == vh->th) && (NULL != vh->client) ) vh->th = GNUNET_CLIENT_notify_transmit_ready (vh->client, sizeof (struct RedirectToServiceRequestMessage), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_NO, &transmit_request, vh); } /** * Connect to the VPN service and start again to transmit our requests. * * @param cls the 'struct GNUNET_VPN_Handle *' * @param tc scheduler context */ static void connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_VPN_Handle *vh = cls; vh->rt = GNUNET_SCHEDULER_NO_TASK; vh->client = GNUNET_CLIENT_connect ("vpn", vh->cfg); GNUNET_assert (NULL != vh->client); GNUNET_assert (NULL == vh->th); if (NULL != vh->rr_head) vh->th = GNUNET_CLIENT_notify_transmit_ready (vh->client, sizeof (struct RedirectToServiceRequestMessage), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_NO, &transmit_request, vh); } /** * Disconnect from the service (communication error) and reconnect later. * * @param vh handle to reconnect. */ static void reconnect (struct GNUNET_VPN_Handle *vh) { struct GNUNET_VPN_RedirectionRequest *rr; if (NULL != vh->th) { GNUNET_CLIENT_notify_transmit_ready_cancel (vh->th); vh->th = NULL; } GNUNET_CLIENT_disconnect (vh->client); vh->client = NULL; vh->request_id_gen = 0; for (rr = vh->rr_head; NULL != rr; rr = rr->next) rr->request_id = 0; vh->backoff = GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_MILLISECONDS, GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply (vh->backoff, 2), GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30))); vh->rt = GNUNET_SCHEDULER_add_delayed (vh->backoff, &connect_task, vh); } /** * Cancel redirection request with the service. * * @param rr request to cancel */ void GNUNET_VPN_cancel_request (struct GNUNET_VPN_RedirectionRequest *rr) { struct GNUNET_VPN_Handle *vh; vh = rr->vh; GNUNET_CONTAINER_DLL_remove (vh->rr_head, vh->rr_tail, rr); GNUNET_free (rr); } /** * Tell the VPN that a forwarding to a particular peer offering a * particular service is requested. The VPN is to reserve a * particular IP for the redirection and return it. The VPN will * begin the redirection as soon as possible and maintain it as long * as it is actively used and keeping it is feasible. Given resource * limitations, the longest inactive mappings will be destroyed. * * @param vh VPN handle * @param result_af desired address family for the returned allocation * can also be AF_UNSPEC * @param protocol protocol, IPPROTO_UDP or IPPROTO_TCP * @param peer target peer for the redirection * @param serv service descriptor to give to the peer * @param nac GNUNET_YES to notify via callback only after completion of * the MESH-level connection, * GNUNET_NO to notify as soon as the IP has been reserved * @param expiration_time at what time should the redirection expire? * (this should not impact connections that are active at that time) * @param cb function to call with the IP * @param cb_cls closure for cb * @return handle to cancel the request (means the callback won't be * invoked anymore; the mapping may or may not be established * anyway) */ struct GNUNET_VPN_RedirectionRequest * GNUNET_VPN_redirect_to_peer (struct GNUNET_VPN_Handle *vh, int result_af, uint8_t protocol, const struct GNUNET_PeerIdentity *peer, const GNUNET_HashCode *serv, int nac, struct GNUNET_TIME_Absolute expiration_time, GNUNET_VPN_AllocationCallback cb, void *cb_cls) { struct GNUNET_VPN_RedirectionRequest *rr; rr = GNUNET_malloc (sizeof (struct GNUNET_VPN_RedirectionRequest)); rr->vh = vh; rr->cb = cb; rr->cb_cls = cb_cls; rr->peer = *peer; rr->serv = *serv; rr->expiration_time = expiration_time; rr->result_af = result_af; rr->nac = nac; rr->protocol = protocol; queue_request (rr); return rr; } /** * Tell the VPN that forwarding to the Internet via some exit node is * requested. Note that both UDP and TCP traffic will be forwarded, * but possibly to different exit nodes. The VPN is to reserve a * particular IP for the redirection and return it. The VPN will * begin the redirection as soon as possible and maintain it as long * as it is actively used and keeping it is feasible. Given resource * limitations, the longest inactive mappings will be destroyed. * * @param vh VPN handle * @param result_af desired address family for the returned allocation * @param addr_af address family for 'addr', AF_INET or AF_INET6 * @param addr destination IP address on the Internet; destination * port is to be taken from the VPN packet itself * @param nac GNUNET_YES to notify via callback only after completion of * the MESH-level connection, * GNUNET_NO to notify as soon as the IP has been reserved * @param expiration_time at what time should the redirection expire? * (this should not impact connections that are active at that time) * @param cb function to call with the IP * @param cb_cls closure for cb * @return handle to cancel the request (means the callback won't be * invoked anymore; the mapping may or may not be established * anyway) */ struct GNUNET_VPN_RedirectionRequest * GNUNET_VPN_redirect_to_ip (struct GNUNET_VPN_Handle *vh, int result_af, int addr_af, const void *addr, int nac, struct GNUNET_TIME_Absolute expiration_time, GNUNET_VPN_AllocationCallback cb, void *cb_cls) { struct GNUNET_VPN_RedirectionRequest *rr; size_t alen; switch (addr_af) { case AF_INET: alen = sizeof (struct in_addr); break; case AF_INET6: alen = sizeof (struct in6_addr); break; default: GNUNET_break (0); return NULL; } rr = GNUNET_malloc (sizeof (struct GNUNET_VPN_RedirectionRequest) + alen); rr->vh = vh; rr->addr = &rr[1]; rr->cb = cb; rr->cb_cls = cb_cls; rr->expiration_time = expiration_time; rr->result_af = result_af; rr->addr_af = addr_af; rr->nac = nac; memcpy (&rr[1], addr, alen); queue_request (rr); return rr; } /** * Connect to the VPN service * * @param cfg configuration to use * @return VPN handle */ struct GNUNET_VPN_Handle * GNUNET_VPN_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_VPN_Handle *vh; vh = GNUNET_malloc (sizeof (struct GNUNET_VPN_Handle)); vh->cfg = cfg; vh->client = GNUNET_CLIENT_connect ("vpn", cfg); if (NULL == vh->client) { GNUNET_free (vh); return NULL; } return vh; } /** * Disconnect from the VPN service. * * @param vh VPN handle */ void GNUNET_VPN_disconnect (struct GNUNET_VPN_Handle *vh) { GNUNET_assert (NULL == vh->rr_head); if (NULL != vh->th) { GNUNET_CLIENT_notify_transmit_ready_cancel (vh->th); vh->th = NULL; } if (NULL != vh->client) { GNUNET_CLIENT_disconnect (vh->client); vh->client = NULL; } if (GNUNET_SCHEDULER_NO_TASK != vh->rt) { GNUNET_SCHEDULER_cancel (vh->rt); vh->rt = GNUNET_SCHEDULER_NO_TASK; } GNUNET_free (vh); } /* end of vpn_api.c */ gnunet-0.9.3/src/vpn/Makefile.am0000644000175000017500000000504111723123714013373 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 endif pkgcfgdir= $(pkgdatadir)/config.d/ plugindir = $(libdir)/gnunet pkgcfg_DATA = \ vpn.conf if LINUX VPNBIN = gnunet-helper-vpn install-exec-hook: $(SUDO_BINARY) chown root:root $(bindir)/gnunet-helper-vpn || true $(SUDO_BINARY) chmod u+s $(bindir)/gnunet-helper-vpn || true if HAVE_MHD VPN_TEST = \ test_gnunet_vpn-4_to_6 \ test_gnunet_vpn-6_to_4 \ test_gnunet_vpn-6_over \ test_gnunet_vpn-4_over endif else install-exec-hook: endif lib_LTLIBRARIES = \ libgnunetvpn.la bin_PROGRAMS = \ $(VPNBIN) gnunet-service-vpn gnunet-vpn check_PROGRAMS = $(VPN_TEST) if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) endif EXTRA_DIST = \ test_gnunet_vpn.conf gnunet_helper_vpn_SOURCES = \ gnunet-helper-vpn.c gnunet_service_vpn_SOURCES = \ gnunet-service-vpn.c gnunet_service_vpn_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/tun/libgnunettun.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(GN_LIBINTL) gnunet_service_vpn_CFLAGS = \ -I$(top_srcdir)/src/exit $(CFLAGS) gnunet_vpn_SOURCES = \ gnunet-vpn.c gnunet_vpn_LDADD = \ $(top_builddir)/src/vpn/libgnunetvpn.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_vpn_DEPENDENCIES = \ libgnunetvpn.la libgnunetvpn_la_SOURCES = \ vpn_api.c vpn.h libgnunetvpn_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la $(XLIB) libgnunetvpn_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) test_gnunet_vpn_4_over_SOURCES = \ test_gnunet_vpn.c test_gnunet_vpn_4_over_LDADD = -lmicrohttpd @LIBCURL@ \ $(top_builddir)/src/vpn/libgnunetvpn.la \ $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la test_gnunet_vpn_6_over_SOURCES = \ test_gnunet_vpn.c test_gnunet_vpn_6_over_LDADD = -lmicrohttpd @LIBCURL@ \ $(top_builddir)/src/vpn/libgnunetvpn.la \ $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la test_gnunet_vpn_4_to_6_SOURCES = \ test_gnunet_vpn.c test_gnunet_vpn_4_to_6_LDADD = -lmicrohttpd @LIBCURL@ \ $(top_builddir)/src/vpn/libgnunetvpn.la \ $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la test_gnunet_vpn_6_to_4_SOURCES = \ test_gnunet_vpn.c test_gnunet_vpn_6_to_4_LDADD = -lmicrohttpd @LIBCURL@ \ $(top_builddir)/src/vpn/libgnunetvpn.la \ $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la gnunet-0.9.3/src/vpn/vpn.conf.in0000644000175000017500000000062511760502552013423 00000000000000[vpn] AUTOSTART = YES @UNIXONLY@ PORT = 0 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-vpn ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-vpn.sock UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES IPV6ADDR = 1234::1 IPV6PREFIX = 32 IPV4ADDR = 10.11.10.1 IPV4MASK = 255.255.0.0 VIRTDNS = 10.11.10.2 VIRTDNS6 = 1234::17 IFNAME = vpn-gnunet gnunet-0.9.3/src/vpn/test_gnunet_vpn.c0000644000175000017500000003371111760502550014732 00000000000000/* This file is part of GNUnet (C) 2007, 2009, 2011, 2012 Christian Grothoff GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file test_gnunet_vpn.c * @brief testcase for tunneling HTTP over the GNUnet VPN * @author Christian Grothoff */ #include "platform.h" #include #include #include "gnunet_vpn_service.h" #include "gnunet_arm_service.h" #define PORT 48080 #define START_ARM GNUNET_YES #define VERBOSE GNUNET_NO #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_PeerIdentity id; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static struct PeerContext p1; /** * Return value for 'main'. */ static int global_ret; static struct GNUNET_VPN_Handle *vpn; static struct MHD_Daemon *mhd; static GNUNET_SCHEDULER_TaskIdentifier mhd_task_id; static GNUNET_SCHEDULER_TaskIdentifier curl_task_id; static GNUNET_SCHEDULER_TaskIdentifier ctrl_c_task_id; static struct GNUNET_VPN_RedirectionRequest *rr; static CURL *curl; static CURLM *multi; static char *url; /** * IP address of the ultimate destination. */ static const char *dest_ip; /** * Address family of the dest_ip. */ static int dest_af; /** * Address family to use by the curl client. */ static int src_af; struct CBC { char buf[1024]; size_t pos; }; static struct CBC cbc; static size_t copy_buffer (void *ptr, size_t size, size_t nmemb, void *ctx) { struct CBC *cbc = ctx; if (cbc->pos + size * nmemb > sizeof(cbc->buf)) return 0; /* overflow */ memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); cbc->pos += size * nmemb; return size * nmemb; } static int mhd_ahc (void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **unused) { static int ptr; struct MHD_Response *response; int ret; if (0 != strcmp ("GET", method)) return MHD_NO; /* unexpected method */ if (&ptr != *unused) { *unused = &ptr; return MHD_YES; } *unused = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MHD sends respose for request to URL `%s'\n", url); response = MHD_create_response_from_buffer (strlen (url), (void *) url, MHD_RESPMEM_MUST_COPY); ret = MHD_queue_response (connection, MHD_HTTP_OK, response); MHD_destroy_response (response); if (ret == MHD_NO) abort (); return ret; } static void do_shutdown () { if (mhd_task_id != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (mhd_task_id); mhd_task_id = GNUNET_SCHEDULER_NO_TASK; } if (curl_task_id != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (curl_task_id); curl_task_id = GNUNET_SCHEDULER_NO_TASK; } if (ctrl_c_task_id != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (ctrl_c_task_id); ctrl_c_task_id = GNUNET_SCHEDULER_NO_TASK; } if (NULL != mhd) { MHD_stop_daemon (mhd); mhd = NULL; } if (NULL != rr) { GNUNET_VPN_cancel_request (rr); rr = NULL; } if (NULL != vpn) { GNUNET_VPN_disconnect (vpn); vpn = NULL; } GNUNET_free_non_null (url); url = NULL; } /** * Function to run the HTTP client. */ static void curl_main (void); static void curl_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { curl_task_id = GNUNET_SCHEDULER_NO_TASK; curl_main (); } static void curl_main () { fd_set rs; fd_set ws; fd_set es; int max; struct GNUNET_NETWORK_FDSet nrs; struct GNUNET_NETWORK_FDSet nws; struct GNUNET_TIME_Relative delay; long timeout; int running; struct CURLMsg *msg; max = 0; FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es); curl_multi_perform (multi, &running); if (running == 0) { GNUNET_assert (NULL != (msg = curl_multi_info_read (multi, &running))); if (msg->msg == CURLMSG_DONE) { if (msg->data.result != CURLE_OK) { fprintf (stderr, "%s failed at %s:%d: `%s'\n", "curl_multi_perform", __FILE__, __LINE__, curl_easy_strerror (msg->data.result)); global_ret = 1; } } curl_multi_remove_handle (multi, curl); curl_multi_cleanup (multi); curl_easy_cleanup (curl); curl = NULL; multi = NULL; if (cbc.pos != strlen ("/hello_world")) { GNUNET_break (0); global_ret = 2; } if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) { GNUNET_break (0); global_ret = 3; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download complete, shutting down!\n"); do_shutdown (); return; } GNUNET_assert (CURLM_OK == curl_multi_fdset (multi, &rs, &ws, &es, &max)); if ( (CURLM_OK != curl_multi_timeout (multi, &timeout)) || (-1 == timeout) ) delay = GNUNET_TIME_UNIT_SECONDS; else delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, (unsigned int) timeout); GNUNET_NETWORK_fdset_copy_native (&nrs, &rs, max + 1); GNUNET_NETWORK_fdset_copy_native (&nws, &ws, max + 1); curl_task_id = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, delay, &nrs, &nws, &curl_task, NULL); } /** * Callback invoked from the VPN service once a redirection is * available. Provides the IP address that can now be used to * reach the requested destination (in our case, the MHD server) * * @param cls closure * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error; * will match 'result_af' from the request * @param address IP address (struct in_addr or struct in_addr6, depending on 'af') * that the VPN allocated for the redirection; * traffic to this IP will now be redirected to the * specified target peer; NULL on error */ static void allocation_cb (void *cls, int af, const void *address) { char ips[INET6_ADDRSTRLEN]; rr = NULL; if (src_af != af) { fprintf (stderr, "VPN failed to allocate appropriate address\n"); GNUNET_SCHEDULER_shutdown (); return; } GNUNET_asprintf (&url, "http://%s:%u/hello_world", inet_ntop (af, address, ips, sizeof (ips)), (unsigned int) PORT); curl = curl_easy_init (); curl_easy_setopt (curl, CURLOPT_URL, url); curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ©_buffer); curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbc); curl_easy_setopt (curl, CURLOPT_FAILONERROR, 1); curl_easy_setopt (curl, CURLOPT_TIMEOUT, 150L); curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT, 15L); curl_easy_setopt (curl, CURLOPT_NOSIGNAL, 1); multi = curl_multi_init (); GNUNET_assert (multi != NULL); GNUNET_assert (CURLM_OK == curl_multi_add_handle (multi, curl)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Beginning HTTP download from `%s'\n", url); curl_main (); } /** * Function to keep the HTTP server running. */ static void mhd_main (void); static void mhd_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { mhd_task_id = GNUNET_SCHEDULER_NO_TASK; MHD_run (mhd); mhd_main (); } static void ctrl_c_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { ctrl_c_task_id = GNUNET_SCHEDULER_NO_TASK; do_shutdown (); GNUNET_break (0); global_ret = 1; } static void mhd_main () { struct GNUNET_NETWORK_FDSet nrs; struct GNUNET_NETWORK_FDSet nws; fd_set rs; fd_set ws; fd_set es; int max_fd; unsigned MHD_LONG_LONG timeout; struct GNUNET_TIME_Relative delay; GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == mhd_task_id); FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es); max_fd = -1; GNUNET_assert (MHD_YES == MHD_get_fdset (mhd, &rs, &ws, &es, &max_fd)); if (MHD_YES == MHD_get_timeout (mhd, &timeout)) delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, (unsigned int) timeout); else delay = GNUNET_TIME_UNIT_FOREVER_REL; GNUNET_NETWORK_fdset_copy_native (&nrs, &rs, max_fd + 1); GNUNET_NETWORK_fdset_copy_native (&nws, &ws, max_fd + 1); mhd_task_id = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, delay, &nrs, &nws, &mhd_task, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct in_addr v4; struct in6_addr v6; void *addr; enum MHD_FLAG flags; vpn = GNUNET_VPN_connect (cfg); GNUNET_assert (NULL != vpn); flags = MHD_USE_DEBUG; if (AF_INET6 == dest_af) flags |= MHD_USE_IPv6; mhd = MHD_start_daemon (flags, PORT, NULL, NULL, &mhd_ahc, NULL, MHD_OPTION_END); GNUNET_assert (NULL != mhd); mhd_main (); addr = NULL; switch (dest_af) { case AF_INET: GNUNET_assert (1 == inet_pton (dest_af, dest_ip, &v4)); addr = &v4; break; case AF_INET6: GNUNET_assert (1 == inet_pton (dest_af, dest_ip, &v6)); addr = &v6; break; default: GNUNET_assert (0); } rr = GNUNET_VPN_redirect_to_ip (vpn, src_af, dest_af, addr, GNUNET_YES, GNUNET_TIME_UNIT_FOREVER_ABS, &allocation_cb, NULL); ctrl_c_task_id = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &ctrl_c_shutdown, NULL); } static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, NULL); #endif GNUNET_assert (NULL != p->arm_proc); GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); } static void stop_peer (struct PeerContext *p) { #if START_ARM if (NULL != p->arm_proc) { if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; } #endif GNUNET_CONFIGURATION_destroy (p->cfg); } /** * Test if the given AF is supported by this system. * * @param af to test * @return GNUNET_OK if the AF is supported */ static int test_af (int af) { int s; s = socket (af, SOCK_STREAM, 0); if (-1 == s) { if (EAFNOSUPPORT == errno) return GNUNET_NO; fprintf (stderr, "Failed to create test socket: %s\n", STRERROR (errno)); return GNUNET_SYSERR; } close (s); return GNUNET_OK; } int main (int argc, char *const *argv) { const char *type; const char *bin; char *const argvx[] = { "test_gnunet_vpn", "-c", "test_gnunet_vpn.conf", NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; if (0 != ACCESS ("/dev/net/tun", R_OK)) { GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "access", "/dev/net/tun"); fprintf (stderr, "WARNING: System unable to run test, skipping.\n"); return 0; } if ( (GNUNET_YES != GNUNET_OS_check_helper_binary ("gnunet-helper-vpn")) || (GNUNET_YES != GNUNET_OS_check_helper_binary ("gnunet-helper-exit")) ) { fprintf (stderr, "WARNING: gnunet-helper-{exit,vpn} binaries in $PATH are not SUID, refusing to run test (as it would have to fail).\n"); fprintf (stderr, "Change $PATH ('.' in $PATH before $GNUNET_PREFIX/bin is problematic) or permissions (run 'make install' as root) to fix this!\n"); return 0; } GNUNET_CRYPTO_setup_hostkey ("test_gnunet_vpn.conf"); bin = argv[0]; if (NULL != strstr (bin, "lt-")) bin = strstr (bin, "lt-") + 4; type = strstr (bin, "-"); if (NULL == type) { fprintf (stderr, "invalid binary name\n"); return 1; } type++; if (0 == strcmp (type, "4_to_6")) { dest_ip = "FC5A:04E1:C2BA::1"; dest_af = AF_INET6; src_af = AF_INET; } else if (0 == strcmp (type, "6_to_4")) { dest_ip = "169.254.86.1"; dest_af = AF_INET; src_af = AF_INET6; } else if (0 == strcmp (type, "4_over")) { dest_ip = "169.254.86.1"; dest_af = AF_INET; src_af = AF_INET; } else if (0 == strcmp (type, "6_over")) { dest_ip = "FC5A:04E1:C2BA::1"; dest_af = AF_INET6; src_af = AF_INET6; } else { fprintf (stderr, "invalid binary suffix `%s'\n", type); return 1; } if ( (GNUNET_OK != test_af (src_af)) || (GNUNET_OK != test_af (dest_af)) ) { fprintf (stderr, "Required address families not supported by this system, skipping test.\n"); return 0; } if (0 != curl_global_init (CURL_GLOBAL_WIN32)) { fprintf (stderr, "failed to initialize curl\n"); return 2; } setup_peer (&p1, "test_gnunet_vpn.conf"); GNUNET_log_setup ("test_gnunet_vpn", "WARNING", NULL); GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "test_gnunet_vpn", "nohelp", options, &run, NULL); stop_peer (&p1); GNUNET_DISK_directory_remove ("/tmp/gnunet-test-vpn"); return global_ret; } /* end of test_gnunet_vpn.c */ gnunet-0.9.3/src/vpn/gnunet-helper-vpn.c0000644000175000017500000003464411760502550015074 00000000000000/* This file is part of GNUnet. (C) 2010, 2012 Christian Grothoff GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file vpn/gnunet-helper-vpn.c * @brief the helper for the VPN service. Opens a virtual network-interface, * sends data received on the if to stdout, sends data received on stdin to the * interface * @author Philipp Tölke * @author Christian Grothoff * * The following list of people have reviewed this code and considered * it safe since the last modification (if you reviewed it, please * have your name added to the list): * * - Philipp Tölke */ #include "platform.h" #include /** * Need 'struct GNUNET_MessageHeader'. */ #include "gnunet_common.h" /** * Need VPN message types. */ #include "gnunet_protocols.h" /** * Should we print (interesting|debug) messages that can happen during * normal operation? */ #define DEBUG GNUNET_NO /** * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE) */ #define MAX_SIZE 65536 #ifndef _LINUX_IN6_H /** * This is in linux/include/net/ipv6.h, but not always exported... */ struct in6_ifreq { struct in6_addr ifr6_addr; uint32_t ifr6_prefixlen; unsigned int ifr6_ifindex; }; #endif /** * Creates a tun-interface called dev; * * @param dev is asumed to point to a char[IFNAMSIZ] * if *dev == '\\0', uses the name supplied by the kernel; * @return the fd to the tun or -1 on error */ static int init_tun (char *dev) { struct ifreq ifr; int fd; if (NULL == dev) { errno = EINVAL; return -1; } if (-1 == (fd = open ("/dev/net/tun", O_RDWR))) { fprintf (stderr, "Error opening `%s': %s\n", "/dev/net/tun", strerror (errno)); return -1; } if (fd >= FD_SETSIZE) { fprintf (stderr, "File descriptor to large: %d", fd); (void) close (fd); return -1; } memset (&ifr, 0, sizeof (ifr)); ifr.ifr_flags = IFF_TUN; if ('\0' != *dev) strncpy (ifr.ifr_name, dev, IFNAMSIZ); if (-1 == ioctl (fd, TUNSETIFF, (void *) &ifr)) { fprintf (stderr, "Error with ioctl on `%s': %s\n", "/dev/net/tun", strerror (errno)); (void) close (fd); return -1; } strcpy (dev, ifr.ifr_name); return fd; } /** * @brief Sets the IPv6-Address given in address on the interface dev * * @param dev the interface to configure * @param address the IPv6-Address * @param prefix_len the length of the network-prefix */ static void set_address6 (const char *dev, const char *address, unsigned long prefix_len) { struct ifreq ifr; struct in6_ifreq ifr6; struct sockaddr_in6 sa6; int fd; /* * parse the new address */ memset (&sa6, 0, sizeof (struct sockaddr_in6)); sa6.sin6_family = AF_INET6; if (1 != inet_pton (AF_INET6, address, sa6.sin6_addr.s6_addr)) { fprintf (stderr, "Failed to parse address `%s': %s\n", address, strerror (errno)); exit (1); } if (-1 == (fd = socket (PF_INET6, SOCK_DGRAM, 0))) { fprintf (stderr, "Error creating socket: %s\n", strerror (errno)); exit (1); } memset (&ifr, 0, sizeof (struct ifreq)); /* * Get the index of the if */ strncpy (ifr.ifr_name, dev, IFNAMSIZ); if (-1 == ioctl (fd, SIOGIFINDEX, &ifr)) { fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } memset (&ifr6, 0, sizeof (struct in6_ifreq)); ifr6.ifr6_addr = sa6.sin6_addr; ifr6.ifr6_ifindex = ifr.ifr_ifindex; ifr6.ifr6_prefixlen = prefix_len; /* * Set the address */ if (-1 == ioctl (fd, SIOCSIFADDR, &ifr6)) { fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } /* * Get the flags */ if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr)) { fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } /* * Add the UP and RUNNING flags */ ifr.ifr_flags |= IFF_UP | IFF_RUNNING; if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr)) { fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } if (0 != close (fd)) { fprintf (stderr, "close failed: %s\n", strerror (errno)); exit (1); } } /** * @brief Sets the IPv4-Address given in address on the interface dev * * @param dev the interface to configure * @param address the IPv4-Address * @param mask the netmask */ static void set_address4 (const char *dev, const char *address, const char *mask) { int fd; struct sockaddr_in *addr; struct ifreq ifr; memset (&ifr, 0, sizeof (struct ifreq)); addr = (struct sockaddr_in *) &(ifr.ifr_addr); addr->sin_family = AF_INET; /* * Parse the address */ if (1 != inet_pton (AF_INET, address, &addr->sin_addr.s_addr)) { fprintf (stderr, "Failed to parse address `%s': %s\n", address, strerror (errno)); exit (1); } if (-1 == (fd = socket (PF_INET, SOCK_DGRAM, 0))) { fprintf (stderr, "Error creating socket: %s\n", strerror (errno)); exit (1); } strncpy (ifr.ifr_name, dev, IFNAMSIZ); /* * Set the address */ if (-1 == ioctl (fd, SIOCSIFADDR, &ifr)) { fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } /* * Parse the netmask */ addr = (struct sockaddr_in *) &(ifr.ifr_netmask); if (1 != inet_pton (AF_INET, mask, &addr->sin_addr.s_addr)) { fprintf (stderr, "Failed to parse address `%s': %s\n", mask, strerror (errno)); (void) close (fd); exit (1); } /* * Set the netmask */ if (-1 == ioctl (fd, SIOCSIFNETMASK, &ifr)) { fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } /* * Get the flags */ if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr)) { fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } /* * Add the UP and RUNNING flags */ ifr.ifr_flags |= IFF_UP | IFF_RUNNING; if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr)) { fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } if (0 != close (fd)) { fprintf (stderr, "close failed: %s\n", strerror (errno)); (void) close (fd); exit (1); } } /** * Start forwarding to and from the tunnel. * * @param fd_tun tunnel FD */ static void run (int fd_tun) { /* * The buffer filled by reading from fd_tun */ unsigned char buftun[MAX_SIZE]; ssize_t buftun_size = 0; unsigned char *buftun_read = NULL; /* * The buffer filled by reading from stdin */ unsigned char bufin[MAX_SIZE]; ssize_t bufin_size = 0; size_t bufin_rpos = 0; unsigned char *bufin_read = NULL; fd_set fds_w; fd_set fds_r; /* read refers to reading from fd_tun, writing to stdout */ int read_open = 1; /* write refers to reading from stdin, writing to fd_tun */ int write_open = 1; while ((1 == read_open) || (1 == write_open)) { FD_ZERO (&fds_w); FD_ZERO (&fds_r); /* * We are supposed to read and the buffer is empty * -> select on read from tun */ if (read_open && (0 == buftun_size)) FD_SET (fd_tun, &fds_r); /* * We are supposed to read and the buffer is not empty * -> select on write to stdout */ if (read_open && (0 != buftun_size)) FD_SET (1, &fds_w); /* * We are supposed to write and the buffer is empty * -> select on read from stdin */ if (write_open && (NULL == bufin_read)) FD_SET (0, &fds_r); /* * We are supposed to write and the buffer is not empty * -> select on write to tun */ if (write_open && (NULL != bufin_read)) FD_SET (fd_tun, &fds_w); int r = select (fd_tun + 1, &fds_r, &fds_w, NULL, NULL); if (-1 == r) { if (EINTR == errno) continue; fprintf (stderr, "select failed: %s\n", strerror (errno)); exit (1); } if (r > 0) { if (FD_ISSET (fd_tun, &fds_r)) { buftun_size = read (fd_tun, buftun + sizeof (struct GNUNET_MessageHeader), MAX_SIZE - sizeof (struct GNUNET_MessageHeader)); if (-1 == buftun_size) { fprintf (stderr, "read-error: %s\n", strerror (errno)); shutdown (fd_tun, SHUT_RD); shutdown (1, SHUT_WR); read_open = 0; buftun_size = 0; } else if (0 == buftun_size) { fprintf (stderr, "EOF on tun\n"); shutdown (fd_tun, SHUT_RD); shutdown (1, SHUT_WR); read_open = 0; buftun_size = 0; } else { buftun_read = buftun; struct GNUNET_MessageHeader *hdr = (struct GNUNET_MessageHeader *) buftun; buftun_size += sizeof (struct GNUNET_MessageHeader); hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); hdr->size = htons (buftun_size); } } else if (FD_ISSET (1, &fds_w)) { ssize_t written = write (1, buftun_read, buftun_size); if (-1 == written) { #if !DEBUG if (errno != EPIPE) #endif fprintf (stderr, "write-error to stdout: %s\n", strerror (errno)); shutdown (fd_tun, SHUT_RD); shutdown (1, SHUT_WR); read_open = 0; buftun_size = 0; } else if (0 == written) { fprintf (stderr, "write returned 0!?\n"); exit (1); } else { buftun_size -= written; buftun_read += written; } } if (FD_ISSET (0, &fds_r)) { bufin_size = read (0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos); if (-1 == bufin_size) { fprintf (stderr, "read-error: %s\n", strerror (errno)); shutdown (0, SHUT_RD); shutdown (fd_tun, SHUT_WR); write_open = 0; bufin_size = 0; } else if (0 == bufin_size) { #if DEBUG fprintf (stderr, "EOF on stdin\n"); #endif shutdown (0, SHUT_RD); shutdown (fd_tun, SHUT_WR); write_open = 0; bufin_size = 0; } else { struct GNUNET_MessageHeader *hdr; PROCESS_BUFFER: bufin_rpos += bufin_size; if (bufin_rpos < sizeof (struct GNUNET_MessageHeader)) continue; hdr = (struct GNUNET_MessageHeader *) bufin; if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) { fprintf (stderr, "protocol violation!\n"); exit (1); } if (ntohs (hdr->size) > bufin_rpos) continue; bufin_read = bufin + sizeof (struct GNUNET_MessageHeader); bufin_size = ntohs (hdr->size) - sizeof (struct GNUNET_MessageHeader); bufin_rpos -= bufin_size + sizeof (struct GNUNET_MessageHeader); } } else if (FD_ISSET (fd_tun, &fds_w)) { ssize_t written = write (fd_tun, bufin_read, bufin_size); if (-1 == written) { fprintf (stderr, "write-error to tun: %s\n", strerror (errno)); shutdown (0, SHUT_RD); shutdown (fd_tun, SHUT_WR); write_open = 0; bufin_size = 0; } else if (0 == written) { fprintf (stderr, "write returned 0!?\n"); exit (1); } else { bufin_size -= written; bufin_read += written; if (0 == bufin_size) { memmove (bufin, bufin_read, bufin_rpos); bufin_read = NULL; /* start reading again */ bufin_size = 0; goto PROCESS_BUFFER; } } } } } } /** * Open VPN tunnel interface. * * @param argc must be 6 * @param argv 0: binary name (gnunet-helper-vpn) * 1: tunnel interface name (gnunet-vpn) * 2: IPv6 address (::1), "-" to disable * 3: IPv6 netmask length in bits (64), ignored if #2 is "-" * 4: IPv4 address (1.2.3.4), "-" to disable * 5: IPv4 netmask (255.255.0.0), ignored if #4 is "-" */ int main (int argc, char **argv) { char dev[IFNAMSIZ]; int fd_tun; int global_ret; if (6 != argc) { fprintf (stderr, "Fatal: must supply 5 arguments!\n"); return 1; } strncpy (dev, argv[1], IFNAMSIZ); dev[IFNAMSIZ - 1] = '\0'; if (-1 == (fd_tun = init_tun (dev))) { fprintf (stderr, "Fatal: could not initialize tun-interface `%s' with IPv6 %s/%s and IPv4 %s/%s\n", dev, argv[2], argv[3], argv[4], argv[5]); return 1; } if (0 != strcmp (argv[2], "-")) { const char *address = argv[2]; long prefix_len = atol (argv[3]); if ((prefix_len < 1) || (prefix_len > 127)) { fprintf (stderr, "Fatal: prefix_len out of range\n"); return 1; } set_address6 (dev, address, prefix_len); } if (0 != strcmp (argv[4], "-")) { const char *address = argv[4]; const char *mask = argv[5]; set_address4 (dev, address, mask); } uid_t uid = getuid (); #ifdef HAVE_SETRESUID if (0 != setresuid (uid, uid, uid)) { fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno)); global_ret = 2; goto cleanup; } #else if (0 != (setuid (uid) | seteuid (uid))) { fprintf (stderr, "Failed to setuid: %s\n", strerror (errno)); global_ret = 2; goto cleanup; } #endif if (SIG_ERR == signal (SIGPIPE, SIG_IGN)) { fprintf (stderr, "Failed to protect against SIGPIPE: %s\n", strerror (errno)); /* no exit, we might as well die with SIGPIPE should it ever happen */ } run (fd_tun); global_ret = 0; cleanup: close (fd_tun); return global_ret; } gnunet-0.9.3/src/vpn/test_gnunet_vpn.conf0000644000175000017500000000135511752320517015436 00000000000000[PATHS] SERVICEHOME = /tmp/gnunet-test-vpn/ DEFAULTCONFIG = test_gnunet_vpn.conf [transport] PLUGINS = tcp [arm] DEFAULTSERVICES = statistics exit vpn PORT = 0 ALLOW_SHUTDOWN = YES [exit] EXIT_IPV4 = YES EXIT_IPV6 = YES # FIXME: can we use 'lo'? EXIT_IFNAME = eth1 [testing] WEAKRANDOM = YES HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat [nse] WORKBITS = 1 # repeating some values from the default configurations # here as the respective network addresses are also # hard-wired in the tests and the MUST match (!) [vpn] IPV6ADDR = FC2D:FDAA:6A26::1 IPV6PREFIX = 64 IPV4ADDR = 169.254.20.1 IPV4MASK = 255.255.255.0 [exit] IPV6ADDR = FC5A:04E1:C2BA::1 IPV6PREFIX = 96 IPV4ADDR = 169.254.86.1 IPV4MASK = 255.255.255.0 [gns] AUTOSTART = NO gnunet-0.9.3/src/vpn/Makefile.in0000644000175000017500000010761611762217214013421 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = $(am__EXEEXT_1) gnunet-service-vpn$(EXEEXT) \ gnunet-vpn$(EXEEXT) check_PROGRAMS = $(am__EXEEXT_2) subdir = src/vpn DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/vpn.conf.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = vpn.conf CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) libgnunetvpn_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_libgnunetvpn_la_OBJECTS = vpn_api.lo libgnunetvpn_la_OBJECTS = $(am_libgnunetvpn_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunetvpn_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetvpn_la_LDFLAGS) $(LDFLAGS) \ -o $@ @LINUX_TRUE@am__EXEEXT_1 = gnunet-helper-vpn$(EXEEXT) @HAVE_MHD_TRUE@@LINUX_TRUE@am__EXEEXT_2 = \ @HAVE_MHD_TRUE@@LINUX_TRUE@ test_gnunet_vpn-4_to_6$(EXEEXT) \ @HAVE_MHD_TRUE@@LINUX_TRUE@ test_gnunet_vpn-6_to_4$(EXEEXT) \ @HAVE_MHD_TRUE@@LINUX_TRUE@ test_gnunet_vpn-6_over$(EXEEXT) \ @HAVE_MHD_TRUE@@LINUX_TRUE@ test_gnunet_vpn-4_over$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) am_gnunet_helper_vpn_OBJECTS = gnunet-helper-vpn.$(OBJEXT) gnunet_helper_vpn_OBJECTS = $(am_gnunet_helper_vpn_OBJECTS) gnunet_helper_vpn_LDADD = $(LDADD) am_gnunet_service_vpn_OBJECTS = \ gnunet_service_vpn-gnunet-service-vpn.$(OBJEXT) gnunet_service_vpn_OBJECTS = $(am_gnunet_service_vpn_OBJECTS) am__DEPENDENCIES_1 = gnunet_service_vpn_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/tun/libgnunettun.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(am__DEPENDENCIES_1) gnunet_service_vpn_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(gnunet_service_vpn_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_gnunet_vpn_OBJECTS = gnunet-vpn.$(OBJEXT) gnunet_vpn_OBJECTS = $(am_gnunet_vpn_OBJECTS) am_test_gnunet_vpn_4_over_OBJECTS = test_gnunet_vpn.$(OBJEXT) test_gnunet_vpn_4_over_OBJECTS = $(am_test_gnunet_vpn_4_over_OBJECTS) test_gnunet_vpn_4_over_DEPENDENCIES = \ $(top_builddir)/src/vpn/libgnunetvpn.la \ $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_gnunet_vpn_4_to_6_OBJECTS = test_gnunet_vpn.$(OBJEXT) test_gnunet_vpn_4_to_6_OBJECTS = $(am_test_gnunet_vpn_4_to_6_OBJECTS) test_gnunet_vpn_4_to_6_DEPENDENCIES = \ $(top_builddir)/src/vpn/libgnunetvpn.la \ $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_gnunet_vpn_6_over_OBJECTS = test_gnunet_vpn.$(OBJEXT) test_gnunet_vpn_6_over_OBJECTS = $(am_test_gnunet_vpn_6_over_OBJECTS) test_gnunet_vpn_6_over_DEPENDENCIES = \ $(top_builddir)/src/vpn/libgnunetvpn.la \ $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_gnunet_vpn_6_to_4_OBJECTS = test_gnunet_vpn.$(OBJEXT) test_gnunet_vpn_6_to_4_OBJECTS = $(am_test_gnunet_vpn_6_to_4_OBJECTS) test_gnunet_vpn_6_to_4_DEPENDENCIES = \ $(top_builddir)/src/vpn/libgnunetvpn.la \ $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunetvpn_la_SOURCES) $(gnunet_helper_vpn_SOURCES) \ $(gnunet_service_vpn_SOURCES) $(gnunet_vpn_SOURCES) \ $(test_gnunet_vpn_4_over_SOURCES) \ $(test_gnunet_vpn_4_to_6_SOURCES) \ $(test_gnunet_vpn_6_over_SOURCES) \ $(test_gnunet_vpn_6_to_4_SOURCES) DIST_SOURCES = $(libgnunetvpn_la_SOURCES) $(gnunet_helper_vpn_SOURCES) \ $(gnunet_service_vpn_SOURCES) $(gnunet_vpn_SOURCES) \ $(test_gnunet_vpn_4_over_SOURCES) \ $(test_gnunet_vpn_4_to_6_SOURCES) \ $(test_gnunet_vpn_6_over_SOURCES) \ $(test_gnunet_vpn_6_to_4_SOURCES) DATA = $(pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 pkgcfgdir = $(pkgdatadir)/config.d/ plugindir = $(libdir)/gnunet pkgcfg_DATA = \ vpn.conf @LINUX_TRUE@VPNBIN = gnunet-helper-vpn @HAVE_MHD_TRUE@@LINUX_TRUE@VPN_TEST = \ @HAVE_MHD_TRUE@@LINUX_TRUE@ test_gnunet_vpn-4_to_6 \ @HAVE_MHD_TRUE@@LINUX_TRUE@ test_gnunet_vpn-6_to_4 \ @HAVE_MHD_TRUE@@LINUX_TRUE@ test_gnunet_vpn-6_over \ @HAVE_MHD_TRUE@@LINUX_TRUE@ test_gnunet_vpn-4_over lib_LTLIBRARIES = \ libgnunetvpn.la @ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) EXTRA_DIST = \ test_gnunet_vpn.conf gnunet_helper_vpn_SOURCES = \ gnunet-helper-vpn.c gnunet_service_vpn_SOURCES = \ gnunet-service-vpn.c gnunet_service_vpn_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/tun/libgnunettun.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(GN_LIBINTL) gnunet_service_vpn_CFLAGS = \ -I$(top_srcdir)/src/exit $(CFLAGS) gnunet_vpn_SOURCES = \ gnunet-vpn.c gnunet_vpn_LDADD = \ $(top_builddir)/src/vpn/libgnunetvpn.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_vpn_DEPENDENCIES = \ libgnunetvpn.la libgnunetvpn_la_SOURCES = \ vpn_api.c vpn.h libgnunetvpn_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la $(XLIB) libgnunetvpn_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) test_gnunet_vpn_4_over_SOURCES = \ test_gnunet_vpn.c test_gnunet_vpn_4_over_LDADD = -lmicrohttpd @LIBCURL@ \ $(top_builddir)/src/vpn/libgnunetvpn.la \ $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la test_gnunet_vpn_6_over_SOURCES = \ test_gnunet_vpn.c test_gnunet_vpn_6_over_LDADD = -lmicrohttpd @LIBCURL@ \ $(top_builddir)/src/vpn/libgnunetvpn.la \ $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la test_gnunet_vpn_4_to_6_SOURCES = \ test_gnunet_vpn.c test_gnunet_vpn_4_to_6_LDADD = -lmicrohttpd @LIBCURL@ \ $(top_builddir)/src/vpn/libgnunetvpn.la \ $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la test_gnunet_vpn_6_to_4_SOURCES = \ test_gnunet_vpn.c test_gnunet_vpn_6_to_4_LDADD = -lmicrohttpd @LIBCURL@ \ $(top_builddir)/src/vpn/libgnunetvpn.la \ $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/vpn/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/vpn/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): vpn.conf: $(top_builddir)/config.status $(srcdir)/vpn.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunetvpn.la: $(libgnunetvpn_la_OBJECTS) $(libgnunetvpn_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetvpn_la_LINK) -rpath $(libdir) $(libgnunetvpn_la_OBJECTS) $(libgnunetvpn_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-helper-vpn$(EXEEXT): $(gnunet_helper_vpn_OBJECTS) $(gnunet_helper_vpn_DEPENDENCIES) @rm -f gnunet-helper-vpn$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_helper_vpn_OBJECTS) $(gnunet_helper_vpn_LDADD) $(LIBS) gnunet-service-vpn$(EXEEXT): $(gnunet_service_vpn_OBJECTS) $(gnunet_service_vpn_DEPENDENCIES) @rm -f gnunet-service-vpn$(EXEEXT) $(AM_V_CCLD)$(gnunet_service_vpn_LINK) $(gnunet_service_vpn_OBJECTS) $(gnunet_service_vpn_LDADD) $(LIBS) gnunet-vpn$(EXEEXT): $(gnunet_vpn_OBJECTS) $(gnunet_vpn_DEPENDENCIES) @rm -f gnunet-vpn$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_vpn_OBJECTS) $(gnunet_vpn_LDADD) $(LIBS) test_gnunet_vpn-4_over$(EXEEXT): $(test_gnunet_vpn_4_over_OBJECTS) $(test_gnunet_vpn_4_over_DEPENDENCIES) @rm -f test_gnunet_vpn-4_over$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gnunet_vpn_4_over_OBJECTS) $(test_gnunet_vpn_4_over_LDADD) $(LIBS) test_gnunet_vpn-4_to_6$(EXEEXT): $(test_gnunet_vpn_4_to_6_OBJECTS) $(test_gnunet_vpn_4_to_6_DEPENDENCIES) @rm -f test_gnunet_vpn-4_to_6$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gnunet_vpn_4_to_6_OBJECTS) $(test_gnunet_vpn_4_to_6_LDADD) $(LIBS) test_gnunet_vpn-6_over$(EXEEXT): $(test_gnunet_vpn_6_over_OBJECTS) $(test_gnunet_vpn_6_over_DEPENDENCIES) @rm -f test_gnunet_vpn-6_over$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gnunet_vpn_6_over_OBJECTS) $(test_gnunet_vpn_6_over_LDADD) $(LIBS) test_gnunet_vpn-6_to_4$(EXEEXT): $(test_gnunet_vpn_6_to_4_OBJECTS) $(test_gnunet_vpn_6_to_4_DEPENDENCIES) @rm -f test_gnunet_vpn-6_to_4$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gnunet_vpn_6_to_4_OBJECTS) $(test_gnunet_vpn_6_to_4_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-vpn.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-vpn.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet_service_vpn-gnunet-service-vpn.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gnunet_vpn.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vpn_api.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< gnunet_service_vpn-gnunet-service-vpn.o: gnunet-service-vpn.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gnunet_service_vpn_CFLAGS) $(CFLAGS) -MT gnunet_service_vpn-gnunet-service-vpn.o -MD -MP -MF $(DEPDIR)/gnunet_service_vpn-gnunet-service-vpn.Tpo -c -o gnunet_service_vpn-gnunet-service-vpn.o `test -f 'gnunet-service-vpn.c' || echo '$(srcdir)/'`gnunet-service-vpn.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnunet_service_vpn-gnunet-service-vpn.Tpo $(DEPDIR)/gnunet_service_vpn-gnunet-service-vpn.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gnunet-service-vpn.c' object='gnunet_service_vpn-gnunet-service-vpn.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gnunet_service_vpn_CFLAGS) $(CFLAGS) -c -o gnunet_service_vpn-gnunet-service-vpn.o `test -f 'gnunet-service-vpn.c' || echo '$(srcdir)/'`gnunet-service-vpn.c gnunet_service_vpn-gnunet-service-vpn.obj: gnunet-service-vpn.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gnunet_service_vpn_CFLAGS) $(CFLAGS) -MT gnunet_service_vpn-gnunet-service-vpn.obj -MD -MP -MF $(DEPDIR)/gnunet_service_vpn-gnunet-service-vpn.Tpo -c -o gnunet_service_vpn-gnunet-service-vpn.obj `if test -f 'gnunet-service-vpn.c'; then $(CYGPATH_W) 'gnunet-service-vpn.c'; else $(CYGPATH_W) '$(srcdir)/gnunet-service-vpn.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnunet_service_vpn-gnunet-service-vpn.Tpo $(DEPDIR)/gnunet_service_vpn-gnunet-service-vpn.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gnunet-service-vpn.c' object='gnunet_service_vpn-gnunet-service-vpn.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gnunet_service_vpn_CFLAGS) $(CFLAGS) -c -o gnunet_service_vpn-gnunet-service-vpn.obj `if test -f 'gnunet-service-vpn.c'; then $(CYGPATH_W) 'gnunet-service-vpn.c'; else $(CYGPATH_W) '$(srcdir)/gnunet-service-vpn.c'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgcfgDATA: $(pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgcfgDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-exec-hook install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA .MAKE: check-am install-am install-exec-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-binPROGRAMS install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-exec-hook install-html install-html-am \ install-info install-info-am install-libLTLIBRARIES \ install-man install-pdf install-pdf-am install-pkgcfgDATA \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-libLTLIBRARIES uninstall-pkgcfgDATA @LINUX_TRUE@install-exec-hook: @LINUX_TRUE@ $(SUDO_BINARY) chown root:root $(bindir)/gnunet-helper-vpn || true @LINUX_TRUE@ $(SUDO_BINARY) chmod u+s $(bindir)/gnunet-helper-vpn || true @LINUX_FALSE@install-exec-hook: # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/vpn/vpn.h0000644000175000017500000000763511760502551012327 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file vpn/vpn.h * @brief IPC messages between VPN library and VPN service * @author Christian Grothoff */ #ifndef VPN_H #define VPN_H #include "gnunet_util_lib.h" GNUNET_NETWORK_STRUCT_BEGIN /** * Message send by the VPN client to the VPN service requesting * the setup of a redirection from some IP via an exit node to * some global Internet address. */ struct RedirectToIpRequestMessage { /** * Type is GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP */ struct GNUNET_MessageHeader header; /** * GNUNET_YES to notify only after completion of the mesh-level connection, * GNUNET_NO to notify as soon as an address was allocated (in nbo). */ int32_t nac GNUNET_PACKED; /** * How long should the redirection be maintained at most? */ struct GNUNET_TIME_AbsoluteNBO expiration_time; /** * Address family desired for the result (AF_INET or AF_INET6 or AF_UNSPEC, in nbo) */ int32_t result_af GNUNET_PACKED; /** * Address family used for the destination address (AF_INET or AF_INET6, in nbo) */ int32_t addr_af GNUNET_PACKED; /** * Unique ID to match a future response to this request. * Picked by the client. */ uint64_t request_id GNUNET_PACKED; /* followed by destination address ('struct in_addr' or 'struct in6_addr') */ }; /** * Message send by the VPN client to the VPN service requesting * the setup of a redirection from some IP to a service running * at a particular peer. */ struct RedirectToServiceRequestMessage { /** * Type is GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP */ struct GNUNET_MessageHeader header; /** * GNUNET_YES to notify only after completion of the mesh-level connection, * GNUNET_NO to notify as soon as an address was allocated (in nbo). */ int32_t nac GNUNET_PACKED; /** * How long should the redirection be maintained at most? */ struct GNUNET_TIME_AbsoluteNBO expiration_time; /** * Desired protocol (IPPROTO_UDP or IPPROTO_TCP) */ int32_t protocol GNUNET_PACKED; /** * Address family desired for the result (AF_INET or AF_INET6 or AF_UNSPEC, in nbo) */ int32_t result_af GNUNET_PACKED; /** * Target peer offering the service. */ struct GNUNET_PeerIdentity target; /** * Service descriptor identifying the service. */ GNUNET_HashCode service_descriptor; /** * Unique ID to match a future response to this request. * Picked by the client. */ uint64_t request_id GNUNET_PACKED; }; /** * Response from the VPN service to a VPN client informing about * the IP that was assigned for the requested redirection. */ struct RedirectToIpResponseMessage { /** * Type is GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP */ struct GNUNET_MessageHeader header; /** * Address family of the allocated address that follows; will match * "result_af" from the request, of be "AF_UNSPEC" on errors. */ int32_t result_af GNUNET_PACKED; /** * Unique ID to match the response to a request. */ uint64_t request_id GNUNET_PACKED; /* followed by destination address ('struct in_addr' or 'struct in6_addr') */ }; GNUNET_NETWORK_STRUCT_END #endif gnunet-0.9.3/src/vpn/gnunet-service-vpn.c0000644000175000017500000026170611760502550015256 00000000000000/* This file is part of GNUnet. (C) 2010, 2011, 2012 Christian Grothoff GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file vpn/gnunet-service-vpn.c * @brief service that opens a virtual interface and allows its clients * to allocate IPs on the virtual interface and to then redirect * IP traffic received on those IPs via the GNUnet mesh * @author Philipp Toelke * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_common.h" #include "gnunet_protocols.h" #include "gnunet_applications.h" #include "gnunet_mesh_service.h" #include "gnunet_statistics_service.h" #include "gnunet_constants.h" #include "gnunet_tun_lib.h" #include "vpn.h" #include "exit.h" /** * Maximum number of messages we allow in the queue for mesh. */ #define MAX_MESSAGE_QUEUE_SIZE 4 /** * State we keep for each of our tunnels. */ struct TunnelState; /** * Information we track for each IP address to determine which tunnel * to send the traffic over to the destination. */ struct DestinationEntry { /** * Key under which this entry is in the 'destination_map' (only valid * if 'heap_node != NULL'). */ GNUNET_HashCode key; /** * Pre-allocated tunnel for this destination, or NULL for none. */ struct TunnelState *ts; /** * Entry for this entry in the destination_heap. */ struct GNUNET_CONTAINER_HeapNode *heap_node; /** * GNUNET_NO if this is a tunnel to an Internet-exit, * GNUNET_YES if this tunnel is to a service. */ int is_service; /** * Details about the connection (depending on is_service). */ union { struct { /** * The description of the service (only used for service tunnels). */ GNUNET_HashCode service_descriptor; /** * Peer offering the service. */ struct GNUNET_PeerIdentity target; } service_destination; struct { /** * Address family used (AF_INET or AF_INET6). */ int af; /** * IP address of the ultimate destination (only used for exit tunnels). */ union { /** * Address if af is AF_INET. */ struct in_addr v4; /** * Address if af is AF_INET6. */ struct in6_addr v6; } ip; } exit_destination; } details; }; /** * A messages we have in queue for a particular tunnel. */ struct TunnelMessageQueueEntry { /** * This is a doubly-linked list. */ struct TunnelMessageQueueEntry *next; /** * This is a doubly-linked list. */ struct TunnelMessageQueueEntry *prev; /** * Number of bytes in 'msg'. */ size_t len; /** * Message to transmit, allocated at the end of this struct. */ const void *msg; }; /** * State we keep for each of our tunnels. */ struct TunnelState { /** * Information about the tunnel to use, NULL if no tunnel * is available right now. */ struct GNUNET_MESH_Tunnel *tunnel; /** * Active transmission handle, NULL for none. */ struct GNUNET_MESH_TransmitHandle *th; /** * Entry for this entry in the tunnel_heap, NULL as long as this * tunnel state is not fully bound. */ struct GNUNET_CONTAINER_HeapNode *heap_node; /** * Head of list of messages scheduled for transmission. */ struct TunnelMessageQueueEntry *tmq_head; /** * Tail of list of messages scheduled for transmission. */ struct TunnelMessageQueueEntry *tmq_tail; /** * Client that needs to be notified about the tunnel being * up as soon as a peer is connected; NULL for none. */ struct GNUNET_SERVER_Client *client; /** * Destination entry that has a pointer to this tunnel state; * NULL if this tunnel state is in the tunnel map. */ struct DestinationEntry *destination_container; /** * ID of the client request that caused us to setup this entry. */ uint64_t request_id; /** * Destination to which this tunnel leads. Note that * this struct is NOT in the destination_map (but a * local copy) and that the 'heap_node' should always * be NULL. */ struct DestinationEntry destination; /** * Task scheduled to destroy the tunnel (or NO_TASK). */ GNUNET_SCHEDULER_TaskIdentifier destroy_task; /** * Addess family used for this tunnel on the local TUN interface. */ int af; /** * Length of the doubly linked 'tmq_head/tmq_tail' list. */ unsigned int tmq_length; /** * IPPROTO_TCP or IPPROTO_UDP once bound. */ uint8_t protocol; /** * IP address of the source on our end, initially uninitialized. */ union { /** * Address if af is AF_INET. */ struct in_addr v4; /** * Address if af is AF_INET6. */ struct in6_addr v6; } source_ip; /** * Destination IP address used by the source on our end (this is the IP * that we pick freely within the VPN's tunnel IP range). */ union { /** * Address if af is AF_INET. */ struct in_addr v4; /** * Address if af is AF_INET6. */ struct in6_addr v6; } destination_ip; /** * Source port used by the sender on our end; 0 for uninitialized. */ uint16_t source_port; /** * Destination port used by the sender on our end; 0 for uninitialized. */ uint16_t destination_port; }; /** * Return value from 'main'. */ static int global_ret; /** * Configuration we use. */ static const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Handle to the mesh service. */ static struct GNUNET_MESH_Handle *mesh_handle; /** * Map from IP address to destination information (possibly with a * MESH tunnel handle for fast setup). */ static struct GNUNET_CONTAINER_MultiHashMap *destination_map; /** * Min-Heap sorted by activity time to expire old mappings. */ static struct GNUNET_CONTAINER_Heap *destination_heap; /** * Map from source and destination address (IP+port) to connection * information (mostly with the respective MESH tunnel handle). */ static struct GNUNET_CONTAINER_MultiHashMap *tunnel_map; /** * Min-Heap sorted by activity time to expire old mappings; values are * of type 'struct TunnelState'. */ static struct GNUNET_CONTAINER_Heap *tunnel_heap; /** * Statistics. */ static struct GNUNET_STATISTICS_Handle *stats; /** * The handle to the VPN helper process "gnunet-helper-vpn". */ static struct GNUNET_HELPER_Handle *helper_handle; /** * Arguments to the vpn helper. */ static char *vpn_argv[7]; /** * Length of the prefix of the VPN's IPv6 network. */ static unsigned long long ipv6prefix; /** * Notification context for sending replies to clients. */ static struct GNUNET_SERVER_NotificationContext *nc; /** * If there are more than this number of address-mappings, old ones * will be removed */ static unsigned long long max_destination_mappings; /** * If there are more than this number of open tunnels, old ones * will be removed */ static unsigned long long max_tunnel_mappings; /** * Compute the key under which we would store an entry in the * destination_map for the given IP address. * * @param af address family (AF_INET or AF_INET6) * @param address IP address, struct in_addr or struct in6_addr * @param key where to store the key */ static void get_destination_key_from_ip (int af, const void *address, GNUNET_HashCode *key) { switch (af) { case AF_INET: GNUNET_CRYPTO_hash (address, sizeof (struct in_addr), key); break; case AF_INET6: GNUNET_CRYPTO_hash (address, sizeof (struct in6_addr), key); break; default: GNUNET_assert (0); break; } } /** * Compute the key under which we would store an entry in the * tunnel_map for the given socket address pair. * * @param af address family (AF_INET or AF_INET6) * @param protocol IPPROTO_TCP or IPPROTO_UDP * @param source_ip sender's source IP, struct in_addr or struct in6_addr * @param source_port sender's source port * @param destination_ip sender's destination IP, struct in_addr or struct in6_addr * @param destination_port sender's destination port * @param key where to store the key */ static void get_tunnel_key_from_ips (int af, uint8_t protocol, const void *source_ip, uint16_t source_port, const void *destination_ip, uint16_t destination_port, GNUNET_HashCode *key) { char *off; memset (key, 0, sizeof (GNUNET_HashCode)); /* the GNUnet hashmap only uses the first sizeof(unsigned int) of the hash, so we put the ports in there (and hope for few collisions) */ off = (char*) key; memcpy (off, &source_port, sizeof (uint16_t)); off += sizeof (uint16_t); memcpy (off, &destination_port, sizeof (uint16_t)); off += sizeof (uint16_t); switch (af) { case AF_INET: memcpy (off, source_ip, sizeof (struct in_addr)); off += sizeof (struct in_addr); memcpy (off, destination_ip, sizeof (struct in_addr)); off += sizeof (struct in_addr); break; case AF_INET6: memcpy (off, source_ip, sizeof (struct in6_addr)); off += sizeof (struct in6_addr); memcpy (off, destination_ip, sizeof (struct in6_addr)); off += sizeof (struct in6_addr); break; default: GNUNET_assert (0); break; } memcpy (off, &protocol, sizeof (uint8_t)); off += sizeof (uint8_t); } /** * Notify the client about the result of its request. * * @param client client to notify * @param request_id original request ID to include in response * @param result_af resulting address family * @param addr resulting IP address */ static void send_client_reply (struct GNUNET_SERVER_Client *client, uint64_t request_id, int result_af, const void *addr) { char buf[sizeof (struct RedirectToIpResponseMessage) + sizeof (struct in6_addr)] GNUNET_ALIGN; struct RedirectToIpResponseMessage *res; size_t rlen; switch (result_af) { case AF_INET: rlen = sizeof (struct in_addr); break; case AF_INET6: rlen = sizeof (struct in6_addr); break; case AF_UNSPEC: rlen = 0; break; default: GNUNET_assert (0); return; } res = (struct RedirectToIpResponseMessage *) buf; res->header.size = htons (sizeof (struct RedirectToIpResponseMessage) + rlen); res->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP); res->result_af = htonl (result_af); res->request_id = request_id; memcpy (&res[1], addr, rlen); GNUNET_SERVER_notification_context_add (nc, client); GNUNET_SERVER_notification_context_unicast (nc, client, &res->header, GNUNET_NO); } /** * Free resources associated with a tunnel state. * * @param ts state to free */ static void free_tunnel_state (struct TunnelState *ts) { GNUNET_HashCode key; struct TunnelMessageQueueEntry *tnq; struct GNUNET_MESH_Tunnel *tunnel; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up tunnel state\n"); GNUNET_STATISTICS_update (stats, gettext_noop ("# Active tunnels"), -1, GNUNET_NO); while (NULL != (tnq = ts->tmq_head)) { GNUNET_CONTAINER_DLL_remove (ts->tmq_head, ts->tmq_tail, tnq); ts->tmq_length--; GNUNET_free (tnq); } GNUNET_assert (0 == ts->tmq_length); if (NULL != ts->client) { GNUNET_SERVER_client_drop (ts->client); ts->client = NULL; } if (NULL != ts->th) { GNUNET_MESH_notify_transmit_ready_cancel (ts->th); ts->th = NULL; } GNUNET_assert (NULL == ts->destination.heap_node); if (NULL != (tunnel = ts->tunnel)) { ts->tunnel = NULL; GNUNET_MESH_tunnel_destroy (tunnel); } if (GNUNET_SCHEDULER_NO_TASK != ts->destroy_task) { GNUNET_SCHEDULER_cancel (ts->destroy_task); ts->destroy_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != ts->heap_node) { GNUNET_CONTAINER_heap_remove_node (ts->heap_node); ts->heap_node = NULL; get_tunnel_key_from_ips (ts->af, ts->protocol, &ts->source_ip, ts->source_port, &ts->destination_ip, ts->destination_port, &key); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (tunnel_map, &key, ts)); } if (NULL != ts->destination_container) { GNUNET_assert (ts == ts->destination_container->ts); ts->destination_container->ts = NULL; ts->destination_container = NULL; } GNUNET_free (ts); } /** * Destroy the mesh tunnel. * * @param cls the 'struct TunnelState' with the tunnel to destroy * @param tc scheduler context */ static void destroy_tunnel_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct TunnelState *ts = cls; struct GNUNET_MESH_Tunnel *tunnel; ts->destroy_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_assert (NULL != ts->tunnel); tunnel = ts->tunnel; ts->tunnel = NULL; GNUNET_MESH_tunnel_destroy (tunnel); free_tunnel_state (ts); } /** * Method called whenever a peer has disconnected from the tunnel. * * @param cls closure * @param peer peer identity the tunnel stopped working with */ static void tunnel_peer_disconnect_handler (void *cls, const struct GNUNET_PeerIdentity * peer) { struct TunnelState *ts = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %s disconnected from tunnel.\n", GNUNET_i2s (peer)); GNUNET_STATISTICS_update (stats, gettext_noop ("# peers connected to mesh tunnels"), -1, GNUNET_NO); if (NULL != ts->th) { GNUNET_MESH_notify_transmit_ready_cancel (ts->th); ts->th = NULL; } if (ts->destination.is_service) return; /* hope for reconnect eventually */ /* as we are most likely going to change the exit node now, we should just destroy the tunnel entirely... */ if (GNUNET_SCHEDULER_NO_TASK == ts->destroy_task) ts->destroy_task = GNUNET_SCHEDULER_add_now (&destroy_tunnel_task, ts); } /** * Method called whenever a peer has connected to the tunnel. Notifies * the waiting client that the tunnel is now up. * * @param cls closure * @param peer peer identity the tunnel was created to, NULL on timeout * @param atsi performance data for the connection */ static void tunnel_peer_connect_handler (void *cls, const struct GNUNET_PeerIdentity * peer, const struct GNUNET_ATS_Information * atsi) { struct TunnelState *ts = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %s connected to tunnel.\n", GNUNET_i2s (peer)); GNUNET_STATISTICS_update (stats, gettext_noop ("# peers connected to mesh tunnels"), 1, GNUNET_NO); if (NULL == ts->client) return; /* nothing to do */ send_client_reply (ts->client, ts->request_id, ts->af, &ts->destination_ip); GNUNET_SERVER_client_drop (ts->client); ts->client = NULL; } /** * Send a message from the message queue via mesh. * * @param cls the 'struct TunnelState' with the message queue * @param size number of bytes available in buf * @param buf where to copy the message * @return number of bytes copied to buf */ static size_t send_to_peer_notify_callback (void *cls, size_t size, void *buf) { struct TunnelState *ts = cls; struct TunnelMessageQueueEntry *tnq; size_t ret; ts->th = NULL; if (NULL == buf) return 0; tnq = ts->tmq_head; GNUNET_assert (NULL != tnq); GNUNET_assert (size >= tnq->len); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending %u bytes via mesh tunnel\n", tnq->len); GNUNET_CONTAINER_DLL_remove (ts->tmq_head, ts->tmq_tail, tnq); ts->tmq_length--; memcpy (buf, tnq->msg, tnq->len); ret = tnq->len; GNUNET_free (tnq); if (NULL != (tnq = ts->tmq_head)) ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel, GNUNET_NO /* cork */, 42 /* priority */, GNUNET_TIME_UNIT_FOREVER_REL, NULL, tnq->len, &send_to_peer_notify_callback, ts); GNUNET_STATISTICS_update (stats, gettext_noop ("# Bytes given to mesh for transmission"), ret, GNUNET_NO); return ret; } /** * Add the given message to the given tunnel and trigger the * transmission process. * * @param tnq message to queue * @param ts tunnel to queue the message for */ static void send_to_tunnel (struct TunnelMessageQueueEntry *tnq, struct TunnelState *ts) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Queueing %u bytes for transmission via mesh tunnel\n", tnq->len); GNUNET_assert (NULL != ts->tunnel); GNUNET_CONTAINER_DLL_insert_tail (ts->tmq_head, ts->tmq_tail, tnq); ts->tmq_length++; if (ts->tmq_length > MAX_MESSAGE_QUEUE_SIZE) { struct TunnelMessageQueueEntry *dq; dq = ts->tmq_head; GNUNET_assert (dq != tnq); GNUNET_CONTAINER_DLL_remove (ts->tmq_head, ts->tmq_tail, dq); ts->tmq_length--; GNUNET_MESH_notify_transmit_ready_cancel (ts->th); ts->th = NULL; GNUNET_STATISTICS_update (stats, gettext_noop ("# Bytes dropped in mesh queue (overflow)"), dq->len, GNUNET_NO); GNUNET_free (dq); } if (NULL == ts->th) ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel, GNUNET_NO /* cork */, 42 /* priority */, GNUNET_TIME_UNIT_FOREVER_REL, NULL, tnq->len, &send_to_peer_notify_callback, ts); } /** * Initialize the given destination entry's mesh tunnel. * * @param de destination entry for which we need to setup a tunnel * @param client client to notify on successful tunnel setup, or NULL for none * @param client_af address family of the address returned to the client * @param request_id request ID to send in client notification (unused if client is NULL) * @return tunnel state of the tunnel that was created */ static struct TunnelState * create_tunnel_to_destination (struct DestinationEntry *de, struct GNUNET_SERVER_Client *client, int client_af, uint64_t request_id) { struct TunnelState *ts; GNUNET_STATISTICS_update (stats, gettext_noop ("# Mesh tunnels created"), 1, GNUNET_NO); GNUNET_assert (NULL == de->ts); ts = GNUNET_malloc (sizeof (struct TunnelState)); ts->af = client_af; if (NULL != client) { ts->request_id = request_id; ts->client = client; GNUNET_SERVER_client_keep (client); } ts->destination = *de; ts->destination.heap_node = NULL; /* copy is NOT in destination heap */ de->ts = ts; ts->destination_container = de; /* we are referenced from de */ ts->tunnel = GNUNET_MESH_tunnel_create (mesh_handle, ts, &tunnel_peer_connect_handler, &tunnel_peer_disconnect_handler, ts); if (NULL == ts->tunnel) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to setup mesh tunnel!\n")); if (NULL != client) GNUNET_SERVER_client_drop (client); GNUNET_free (ts); return NULL; } if (de->is_service) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating tunnel to peer %s offering service %s\n", GNUNET_i2s (&de->details.service_destination.target), GNUNET_h2s (&de->details.service_destination.service_descriptor)); GNUNET_MESH_peer_request_connect_add (ts->tunnel, &de->details.service_destination.target); } else { switch (de->details.exit_destination.af) { case AF_INET: GNUNET_MESH_peer_request_connect_by_type (ts->tunnel, GNUNET_APPLICATION_TYPE_IPV4_GATEWAY); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating tunnel to exit peer for %s\n", "IPv4"); break; case AF_INET6: GNUNET_MESH_peer_request_connect_by_type (ts->tunnel, GNUNET_APPLICATION_TYPE_IPV6_GATEWAY); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating tunnel to exit peer for %s\n", "IPv6"); break; default: GNUNET_assert (0); break; } } return ts; } /** * We have too many active tunnels. Clean up the oldest tunnel. * * @param except tunnel that must NOT be cleaned up, even if it is the oldest */ static void expire_tunnel (struct TunnelState *except) { struct TunnelState *ts; ts = GNUNET_CONTAINER_heap_peek (tunnel_heap); GNUNET_assert (NULL != ts); if (except == ts) return; /* can't do this */ free_tunnel_state (ts); } /** * Route a packet via mesh to the given destination. * * @param destination description of the destination * @param af address family on this end (AF_INET or AF_INET6) * @param protocol IPPROTO_TCP or IPPROTO_UDP or IPPROTO_ICMP or IPPROTO_ICMPV6 * @param source_ip source IP used by the sender (struct in_addr or struct in6_addr) * @param destination_ip destination IP used by the sender (struct in_addr or struct in6_addr) * @param payload payload of the packet after the IP header * @param payload_length number of bytes in payload */ static void route_packet (struct DestinationEntry *destination, int af, uint8_t protocol, const void *source_ip, const void *destination_ip, const void *payload, size_t payload_length) { GNUNET_HashCode key; struct TunnelState *ts; struct TunnelMessageQueueEntry *tnq; size_t alen; size_t mlen; int is_new; const struct GNUNET_TUN_UdpHeader *udp; const struct GNUNET_TUN_TcpHeader *tcp; const struct GNUNET_TUN_IcmpHeader *icmp; uint16_t source_port; uint16_t destination_port; switch (protocol) { case IPPROTO_UDP: { if (payload_length < sizeof (struct GNUNET_TUN_UdpHeader)) { /* blame kernel? */ GNUNET_break (0); return; } tcp = NULL; /* make compiler happy */ icmp = NULL; /* make compiler happy */ udp = payload; if (udp->len < sizeof (struct GNUNET_TUN_UdpHeader)) { GNUNET_break_op (0); return; } source_port = ntohs (udp->source_port); destination_port = ntohs (udp->destination_port); get_tunnel_key_from_ips (af, IPPROTO_UDP, source_ip, source_port, destination_ip, destination_port, &key); } break; case IPPROTO_TCP: { if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader)) { /* blame kernel? */ GNUNET_break (0); return; } udp = NULL; /* make compiler happy */ icmp = NULL; /* make compiler happy */ tcp = payload; if (tcp->off * 4 < sizeof (struct GNUNET_TUN_TcpHeader)) { GNUNET_break_op (0); return; } source_port = ntohs (tcp->source_port); destination_port = ntohs (tcp->destination_port); get_tunnel_key_from_ips (af, IPPROTO_TCP, source_ip, source_port, destination_ip, destination_port, &key); } break; case IPPROTO_ICMP: case IPPROTO_ICMPV6: { if ( (AF_INET == af) ^ (protocol == IPPROTO_ICMP) ) { GNUNET_break (0); return; } if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader)) { /* blame kernel? */ GNUNET_break (0); return; } tcp = NULL; /* make compiler happy */ udp = NULL; /* make compiler happy */ icmp = payload; source_port = 0; destination_port = 0; get_tunnel_key_from_ips (af, protocol, source_ip, 0, destination_ip, 0, &key); } break; default: GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Protocol %u not supported, dropping\n"), (unsigned int) protocol); return; } if (! destination->is_service) { switch (destination->details.exit_destination.af) { case AF_INET: alen = sizeof (struct in_addr); break; case AF_INET6: alen = sizeof (struct in6_addr); break; default: alen = 0; GNUNET_assert (0); } { char sbuf[INET6_ADDRSTRLEN]; char dbuf[INET6_ADDRSTRLEN]; char xbuf[INET6_ADDRSTRLEN]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Routing %s packet from %s:%u -> %s:%u to destination %s:%u\n", (protocol == IPPROTO_TCP) ? "TCP" : "UDP", inet_ntop (af, source_ip, sbuf, sizeof (sbuf)), source_port, inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)), destination_port, inet_ntop (destination->details.exit_destination.af, &destination->details.exit_destination.ip, xbuf, sizeof (xbuf)), destination_port); } } else { /* make compiler happy */ alen = 0; { char sbuf[INET6_ADDRSTRLEN]; char dbuf[INET6_ADDRSTRLEN]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Routing %s packet from %s:%u -> %s:%u to service %s at peer %s\n", (protocol == IPPROTO_TCP) ? "TCP" : "UDP", inet_ntop (af, source_ip, sbuf, sizeof (sbuf)), source_port, inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)), destination_port, GNUNET_h2s (&destination->details.service_destination.service_descriptor), GNUNET_i2s (&destination->details.service_destination.target)); } } /* see if we have an existing tunnel for this destination */ ts = GNUNET_CONTAINER_multihashmap_get (tunnel_map, &key); if (NULL == ts) { /* need to either use the existing tunnel from the destination (if still available) or create a fresh one */ is_new = GNUNET_YES; if (NULL == destination->ts) ts = create_tunnel_to_destination (destination, NULL, af, 0); else ts = destination->ts; if (NULL == ts) return; destination->ts = NULL; ts->destination_container = NULL; /* no longer 'contained' */ /* now bind existing "unbound" tunnel to our IP/port tuple */ ts->protocol = protocol; ts->af = af; if (af == AF_INET) { ts->source_ip.v4 = * (const struct in_addr *) source_ip; ts->destination_ip.v4 = * (const struct in_addr *) destination_ip; } else { ts->source_ip.v6 = * (const struct in6_addr *) source_ip; ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip; } ts->source_port = source_port; ts->destination_port = destination_port; ts->heap_node = GNUNET_CONTAINER_heap_insert (tunnel_heap, ts, GNUNET_TIME_absolute_get ().abs_value); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_put (tunnel_map, &key, ts, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); GNUNET_STATISTICS_update (stats, gettext_noop ("# Active tunnels"), 1, GNUNET_NO); while (GNUNET_CONTAINER_multihashmap_size (tunnel_map) > max_tunnel_mappings) expire_tunnel (ts); } else { is_new = GNUNET_NO; GNUNET_CONTAINER_heap_update_cost (tunnel_heap, ts->heap_node, GNUNET_TIME_absolute_get ().abs_value); } GNUNET_assert (NULL != ts->tunnel); /* send via tunnel */ switch (protocol) { case IPPROTO_UDP: if (destination->is_service) { struct GNUNET_EXIT_UdpServiceMessage *usm; mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) + payload_length - sizeof (struct GNUNET_TUN_UdpHeader); if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); return; } tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen); tnq->len = mlen; tnq->msg = &tnq[1]; usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1]; usm->header.size = htons ((uint16_t) mlen); usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE); /* if the source port is below 32000, we assume it has a special meaning; if not, we pick a random port (this is a heuristic) */ usm->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0; usm->destination_port = udp->destination_port; usm->service_descriptor = destination->details.service_destination.service_descriptor; memcpy (&usm[1], &udp[1], payload_length - sizeof (struct GNUNET_TUN_UdpHeader)); } else { struct GNUNET_EXIT_UdpInternetMessage *uim; struct in_addr *ip4dst; struct in6_addr *ip6dst; void *payload; mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) + alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader); if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); return; } tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen); tnq->len = mlen; tnq->msg = &tnq[1]; uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1]; uim->header.size = htons ((uint16_t) mlen); uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET); uim->af = htonl (destination->details.exit_destination.af); uim->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0; uim->destination_port = udp->destination_port; switch (destination->details.exit_destination.af) { case AF_INET: ip4dst = (struct in_addr *) &uim[1]; *ip4dst = destination->details.exit_destination.ip.v4; payload = &ip4dst[1]; break; case AF_INET6: ip6dst = (struct in6_addr *) &uim[1]; *ip6dst = destination->details.exit_destination.ip.v6; payload = &ip6dst[1]; break; default: GNUNET_assert (0); } memcpy (payload, &udp[1], payload_length - sizeof (struct GNUNET_TUN_UdpHeader)); } break; case IPPROTO_TCP: if (is_new) { if (destination->is_service) { struct GNUNET_EXIT_TcpServiceStartMessage *tsm; mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) + payload_length - sizeof (struct GNUNET_TUN_TcpHeader); if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); return; } tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen); tnq->len = mlen; tnq->msg = &tnq[1]; tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1]; tsm->header.size = htons ((uint16_t) mlen); tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START); tsm->reserved = htonl (0); tsm->service_descriptor = destination->details.service_destination.service_descriptor; tsm->tcp_header = *tcp; memcpy (&tsm[1], &tcp[1], payload_length - sizeof (struct GNUNET_TUN_TcpHeader)); } else { struct GNUNET_EXIT_TcpInternetStartMessage *tim; struct in_addr *ip4dst; struct in6_addr *ip6dst; void *payload; mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) + alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader); if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); return; } tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen); tnq->len = mlen; tnq->msg = &tnq[1]; tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1]; tim->header.size = htons ((uint16_t) mlen); tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START); tim->af = htonl (destination->details.exit_destination.af); tim->tcp_header = *tcp; switch (destination->details.exit_destination.af) { case AF_INET: ip4dst = (struct in_addr *) &tim[1]; *ip4dst = destination->details.exit_destination.ip.v4; payload = &ip4dst[1]; break; case AF_INET6: ip6dst = (struct in6_addr *) &tim[1]; *ip6dst = destination->details.exit_destination.ip.v6; payload = &ip6dst[1]; break; default: GNUNET_assert (0); } memcpy (payload, &tcp[1], payload_length - sizeof (struct GNUNET_TUN_TcpHeader)); } } else { struct GNUNET_EXIT_TcpDataMessage *tdm; mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) + payload_length - sizeof (struct GNUNET_TUN_TcpHeader); if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); return; } tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen); tnq->len = mlen; tnq->msg = &tnq[1]; tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1]; tdm->header.size = htons ((uint16_t) mlen); tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT); tdm->reserved = htonl (0); tdm->tcp_header = *tcp; memcpy (&tdm[1], &tcp[1], payload_length - sizeof (struct GNUNET_TUN_TcpHeader)); } break; case IPPROTO_ICMP: case IPPROTO_ICMPV6: if (destination->is_service) { struct GNUNET_EXIT_IcmpServiceMessage *ism; mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader); if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); return; } tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen); tnq->msg = &tnq[1]; ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1]; ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE); ism->af = htonl (af); /* need to tell destination ICMP protocol family! */ ism->service_descriptor = destination->details.service_destination.service_descriptor; ism->icmp_header = *icmp; /* ICMP protocol translation will be done by the receiver (as we don't know the target AF); however, we still need to possibly discard the payload depending on the ICMP type */ switch (af) { case AF_INET: switch (icmp->type) { case GNUNET_TUN_ICMPTYPE_ECHO_REPLY: case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST: break; case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE: case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH: case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED: /* throw away ICMP payload, won't be useful for the other side anyway */ payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); break; default: GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv4 packets dropped (not allowed)"), 1, GNUNET_NO); return; } /* end of AF_INET */ break; case AF_INET6: switch (icmp->type) { case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE: case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG: case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED: case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM: /* throw away ICMP payload, won't be useful for the other side anyway */ payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); break; case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST: case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY: break; default: GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv6 packets dropped (not allowed)"), 1, GNUNET_NO); return; } /* end of AF_INET6 */ break; default: GNUNET_assert (0); break; } /* update length calculations, as payload_length may have changed */ mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) + alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader); tnq->len = mlen; ism->header.size = htons ((uint16_t) mlen); /* finally, copy payload (if there is any left...) */ memcpy (&ism[1], &icmp[1], payload_length - sizeof (struct GNUNET_TUN_IcmpHeader)); } else { struct GNUNET_EXIT_IcmpInternetMessage *iim; struct in_addr *ip4dst; struct in6_addr *ip6dst; void *payload; mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) + alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader); if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); return; } tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueueEntry) + mlen); tnq->msg = &tnq[1]; iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1]; iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET); iim->icmp_header = *icmp; /* Perform ICMP protocol-translation (depending on destination AF and source AF) and throw away ICMP payload depending on ICMP message type */ switch (af) { case AF_INET: switch (icmp->type) { case GNUNET_TUN_ICMPTYPE_ECHO_REPLY: if (destination->details.exit_destination.af == AF_INET6) iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY; break; case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST: if (destination->details.exit_destination.af == AF_INET6) iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST; break; case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE: if (destination->details.exit_destination.af == AF_INET6) iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE; /* throw away IP-payload, exit will have to make it up anyway */ payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); break; case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED: if (destination->details.exit_destination.af == AF_INET6) iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED; /* throw away IP-payload, exit will have to make it up anyway */ payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); break; case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH: if (destination->details.exit_destination.af == AF_INET6) { GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"), 1, GNUNET_NO); GNUNET_free (tnq); return; } /* throw away IP-payload, exit will have to make it up anyway */ payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); break; default: GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv4 packets dropped (type not allowed)"), 1, GNUNET_NO); GNUNET_free (tnq); return; } /* end of AF_INET */ break; case AF_INET6: switch (icmp->type) { case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE: if (destination->details.exit_destination.af == AF_INET6) iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE; /* throw away IP-payload, exit will have to make it up anyway */ payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); break; case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED: if (destination->details.exit_destination.af == AF_INET) iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED; /* throw away IP-payload, exit will have to make it up anyway */ payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); break; case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG: if (destination->details.exit_destination.af == AF_INET) { GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"), 1, GNUNET_NO); GNUNET_free (tnq); return; } /* throw away IP-payload, exit will have to make it up anyway */ payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); break; case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM: if (destination->details.exit_destination.af == AF_INET) { GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"), 1, GNUNET_NO); GNUNET_free (tnq); return; } /* throw away IP-payload, exit will have to make it up anyway */ payload_length = sizeof (struct GNUNET_TUN_IcmpHeader); break; case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST: if (destination->details.exit_destination.af == AF_INET) iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST; break; case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY: if (destination->details.exit_destination.af == AF_INET) iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY; break; default: GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv6 packets dropped (type not allowed)"), 1, GNUNET_NO); GNUNET_free (tnq); return; } /* end of AF_INET6 */ break; default: GNUNET_assert (0); } /* update length calculations, as payload_length may have changed */ mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) + alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader); tnq->len = mlen; iim->header.size = htons ((uint16_t) mlen); /* need to tell destination ICMP protocol family! */ iim->af = htonl (destination->details.exit_destination.af); switch (destination->details.exit_destination.af) { case AF_INET: ip4dst = (struct in_addr *) &iim[1]; *ip4dst = destination->details.exit_destination.ip.v4; payload = &ip4dst[1]; break; case AF_INET6: ip6dst = (struct in6_addr *) &iim[1]; *ip6dst = destination->details.exit_destination.ip.v6; payload = &ip6dst[1]; break; default: GNUNET_assert (0); } memcpy (payload, &icmp[1], payload_length - sizeof (struct GNUNET_TUN_IcmpHeader)); } break; default: /* not supported above, how can we get here !? */ GNUNET_assert (0); break; } send_to_tunnel (tnq, ts); } /** * Receive packets from the helper-process (someone send to the local * virtual tunnel interface). Find the destination mapping, and if it * exists, identify the correct MESH tunnel (or possibly create it) * and forward the packet. * * @param cls closure, NULL * @param client NULL * @param message message we got from the client (VPN tunnel interface) */ static int message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED, const struct GNUNET_MessageHeader *message) { const struct GNUNET_TUN_Layer2PacketHeader *tun; size_t mlen; GNUNET_HashCode key; struct DestinationEntry *de; GNUNET_STATISTICS_update (stats, gettext_noop ("# Packets received from TUN interface"), 1, GNUNET_NO); mlen = ntohs (message->size); if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) || (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) ) { GNUNET_break (0); return GNUNET_OK; } tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1]; mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)); switch (ntohs (tun->proto)) { case ETH_P_IPV6: { const struct GNUNET_TUN_IPv6Header *pkt6; if (mlen < sizeof (struct GNUNET_TUN_IPv6Header)) { /* blame kernel */ GNUNET_break (0); return GNUNET_OK; } pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1]; get_destination_key_from_ip (AF_INET6, &pkt6->destination_address, &key); de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key); /* FIXME: do we need to guard against hash collision? (if so, we need to also store the local destination IP in the destination entry and then compare here; however, the risk of collision seems minimal AND the impact is unlikely to be super-problematic as well... */ if (NULL == de) { char buf[INET6_ADDRSTRLEN]; GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Packet received for unmapped destination `%s' (dropping it)\n"), inet_ntop (AF_INET6, &pkt6->destination_address, buf, sizeof (buf))); return GNUNET_OK; } route_packet (de, AF_INET6, pkt6->next_header, &pkt6->source_address, &pkt6->destination_address, &pkt6[1], mlen - sizeof (struct GNUNET_TUN_IPv6Header)); } break; case ETH_P_IPV4: { struct GNUNET_TUN_IPv4Header *pkt4; if (mlen < sizeof (struct GNUNET_TUN_IPv4Header)) { /* blame kernel */ GNUNET_break (0); return GNUNET_OK; } pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1]; get_destination_key_from_ip (AF_INET, &pkt4->destination_address, &key); de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key); /* FIXME: do we need to guard against hash collision? (if so, we need to also store the local destination IP in the destination entry and then compare here; however, the risk of collision seems minimal AND the impact is unlikely to be super-problematic as well... */ if (NULL == de) { char buf[INET_ADDRSTRLEN]; GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Packet received for unmapped destination `%s' (dropping it)\n"), inet_ntop (AF_INET, &pkt4->destination_address, buf, sizeof (buf))); return GNUNET_OK; } if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Received IPv4 packet with options (dropping it)\n")); return GNUNET_OK; } route_packet (de, AF_INET, pkt4->protocol, &pkt4->source_address, &pkt4->destination_address, &pkt4[1], mlen - sizeof (struct GNUNET_TUN_IPv4Header)); } break; default: GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Received packet of unknown protocol %d from TUN (dropping it)\n"), (unsigned int) ntohs (tun->proto)); break; } return GNUNET_OK; } /** * Synthesize a plausible ICMP payload for an ICMP error * response on the given tunnel. * * @param ts tunnel information * @param ipp IPv4 header to fill in (ICMP payload) * @param udp "UDP" header to fill in (ICMP payload); might actually * also be the first 8 bytes of the TCP header */ static void make_up_icmpv4_payload (struct TunnelState *ts, struct GNUNET_TUN_IPv4Header *ipp, struct GNUNET_TUN_UdpHeader *udp) { GNUNET_TUN_initialize_ipv4_header (ipp, ts->protocol, sizeof (struct GNUNET_TUN_TcpHeader), &ts->source_ip.v4, &ts->destination_ip.v4); udp->source_port = htons (ts->source_port); udp->destination_port = htons (ts->destination_port); udp->len = htons (0); udp->crc = htons (0); } /** * Synthesize a plausible ICMP payload for an ICMP error * response on the given tunnel. * * @param ts tunnel information * @param ipp IPv6 header to fill in (ICMP payload) * @param udp "UDP" header to fill in (ICMP payload); might actually * also be the first 8 bytes of the TCP header */ static void make_up_icmpv6_payload (struct TunnelState *ts, struct GNUNET_TUN_IPv6Header *ipp, struct GNUNET_TUN_UdpHeader *udp) { GNUNET_TUN_initialize_ipv6_header (ipp, ts->protocol, sizeof (struct GNUNET_TUN_TcpHeader), &ts->source_ip.v6, &ts->destination_ip.v6); udp->source_port = htons (ts->source_port); udp->destination_port = htons (ts->destination_port); udp->len = htons (0); udp->crc = htons (0); } /** * We got an ICMP packet back from the MESH tunnel. Pass it on to the * local virtual interface via the helper. * * @param cls closure, NULL * @param tunnel connection to the other end * @param tunnel_ctx pointer to our 'struct TunnelState *' * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int receive_icmp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) { struct TunnelState *ts = *tunnel_ctx; const struct GNUNET_EXIT_IcmpToVPNMessage *i2v; size_t mlen; GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMP packets received from mesh"), 1, GNUNET_NO); mlen = ntohs (message->size); if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage)) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (NULL == ts->heap_node) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (AF_UNSPEC == ts->af) { GNUNET_break_op (0); return GNUNET_SYSERR; } i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message; mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage); { char sbuf[INET6_ADDRSTRLEN]; char dbuf[INET6_ADDRSTRLEN]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ICMP packet from mesh, sending %u bytes from %s -> %s via TUN\n", (unsigned int) mlen, inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)), inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf))); } switch (ts->af) { case AF_INET: { size_t size = sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_IcmpHeader) + sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + mlen; { /* reserve some extra space in case we have an ICMP type here where we will need to make up the payload ourselves */ char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8] GNUNET_ALIGN; struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf; struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1]; struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1]; struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1]; msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); tun->flags = htons (0); tun->proto = htons (ETH_P_IPV4); GNUNET_TUN_initialize_ipv4_header (ipv4, IPPROTO_ICMP, sizeof (struct GNUNET_TUN_IcmpHeader) + mlen, &ts->destination_ip.v4, &ts->source_ip.v4); *icmp = i2v->icmp_header; memcpy (&icmp[1], &i2v[1], mlen); /* For some ICMP types, we need to adjust (make up) the payload here. Also, depending on the AF used on the other side, we have to do ICMP PT (translate ICMP types) */ switch (ntohl (i2v->af)) { case AF_INET: switch (icmp->type) { case GNUNET_TUN_ICMPTYPE_ECHO_REPLY: case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST: break; case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE: case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH: case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED: { struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1]; struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1]; if (mlen != 0) { /* sender did not strip ICMP payload? */ GNUNET_break_op (0); return GNUNET_SYSERR; } size += sizeof (struct GNUNET_TUN_IPv4Header) + 8; GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); make_up_icmpv4_payload (ts, ipp, udp); } break; default: GNUNET_break_op (0); GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv4 packets dropped (type not allowed)"), 1, GNUNET_NO); return GNUNET_SYSERR; } /* end AF_INET */ break; case AF_INET6: /* ICMP PT 6-to-4 and possibly making up payloads */ switch (icmp->type) { case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE: icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE; { struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1]; struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1]; if (mlen != 0) { /* sender did not strip ICMP payload? */ GNUNET_break_op (0); return GNUNET_SYSERR; } size += sizeof (struct GNUNET_TUN_IPv4Header) + 8; GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); make_up_icmpv4_payload (ts, ipp, udp); } break; case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED: icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED; { struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1]; struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1]; if (mlen != 0) { /* sender did not strip ICMP payload? */ GNUNET_break_op (0); return GNUNET_SYSERR; } size += sizeof (struct GNUNET_TUN_IPv4Header) + 8; GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); make_up_icmpv4_payload (ts, ipp, udp); } break; case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG: case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM: GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"), 1, GNUNET_NO); return GNUNET_OK; case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST: icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST; break; case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY: icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY; break; default: GNUNET_break_op (0); GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv6 packets dropped (type not allowed)"), 1, GNUNET_NO); return GNUNET_SYSERR; } /* end AF_INET6 */ break; default: GNUNET_break_op (0); return GNUNET_SYSERR; } msg->size = htons (size); GNUNET_TUN_calculate_icmp_checksum (icmp, &i2v[1], mlen); (void) GNUNET_HELPER_send (helper_handle, msg, GNUNET_YES, NULL, NULL); } } break; case AF_INET6: { size_t size = sizeof (struct GNUNET_TUN_IPv6Header) + sizeof (struct GNUNET_TUN_IcmpHeader) + sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + mlen; { char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN; struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf; struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1]; struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1]; struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1]; msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); tun->flags = htons (0); tun->proto = htons (ETH_P_IPV6); GNUNET_TUN_initialize_ipv6_header (ipv6, IPPROTO_ICMPV6, sizeof (struct GNUNET_TUN_IcmpHeader) + mlen, &ts->destination_ip.v6, &ts->source_ip.v6); *icmp = i2v->icmp_header; memcpy (&icmp[1], &i2v[1], mlen); /* For some ICMP types, we need to adjust (make up) the payload here. Also, depending on the AF used on the other side, we have to do ICMP PT (translate ICMP types) */ switch (ntohl (i2v->af)) { case AF_INET: /* ICMP PT 4-to-6 and possibly making up payloads */ switch (icmp->type) { case GNUNET_TUN_ICMPTYPE_ECHO_REPLY: icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY; break; case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST: icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST; break; case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE: icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE; { struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1]; struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1]; if (mlen != 0) { /* sender did not strip ICMP payload? */ GNUNET_break_op (0); return GNUNET_SYSERR; } size += sizeof (struct GNUNET_TUN_IPv6Header) + 8; GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); make_up_icmpv6_payload (ts, ipp, udp); } break; case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED: icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED; { struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1]; struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1]; if (mlen != 0) { /* sender did not strip ICMP payload? */ GNUNET_break_op (0); return GNUNET_SYSERR; } size += sizeof (struct GNUNET_TUN_IPv6Header) + 8; GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); make_up_icmpv6_payload (ts, ipp, udp); } break; case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH: GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"), 1, GNUNET_NO); return GNUNET_OK; default: GNUNET_break_op (0); GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv4 packets dropped (type not allowed)"), 1, GNUNET_NO); return GNUNET_SYSERR; } /* end AF_INET */ break; case AF_INET6: switch (icmp->type) { case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE: case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED: case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG: case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM: { struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1]; struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1]; if (mlen != 0) { /* sender did not strip ICMP payload? */ GNUNET_break_op (0); return GNUNET_SYSERR; } size += sizeof (struct GNUNET_TUN_IPv6Header) + 8; GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); make_up_icmpv6_payload (ts, ipp, udp); } break; case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST: break; default: GNUNET_break_op (0); GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv6 packets dropped (type not allowed)"), 1, GNUNET_NO); return GNUNET_SYSERR; } /* end AF_INET6 */ break; default: GNUNET_break_op (0); return GNUNET_SYSERR; } msg->size = htons (size); GNUNET_TUN_calculate_icmp_checksum (icmp, &i2v[1], mlen); (void) GNUNET_HELPER_send (helper_handle, msg, GNUNET_YES, NULL, NULL); } } break; default: GNUNET_assert (0); } GNUNET_CONTAINER_heap_update_cost (tunnel_heap, ts->heap_node, GNUNET_TIME_absolute_get ().abs_value); return GNUNET_OK; } /** * We got a UDP packet back from the MESH tunnel. Pass it on to the * local virtual interface via the helper. * * @param cls closure, NULL * @param tunnel connection to the other end * @param tunnel_ctx pointer to our 'struct TunnelState *' * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) { struct TunnelState *ts = *tunnel_ctx; const struct GNUNET_EXIT_UdpReplyMessage *reply; size_t mlen; GNUNET_STATISTICS_update (stats, gettext_noop ("# UDP packets received from mesh"), 1, GNUNET_NO); mlen = ntohs (message->size); if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage)) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (NULL == ts->heap_node) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (AF_UNSPEC == ts->af) { GNUNET_break_op (0); return GNUNET_SYSERR; } reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message; mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage); { char sbuf[INET6_ADDRSTRLEN]; char dbuf[INET6_ADDRSTRLEN]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received UDP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n", (unsigned int) mlen, inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)), ts->destination_port, inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)), ts->source_port); } switch (ts->af) { case AF_INET: { size_t size = sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_UdpHeader) + sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + mlen; { char buf[size] GNUNET_ALIGN; struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf; struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1]; struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1]; struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1]; msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); msg->size = htons (size); tun->flags = htons (0); tun->proto = htons (ETH_P_IPV4); GNUNET_TUN_initialize_ipv4_header (ipv4, IPPROTO_UDP, sizeof (struct GNUNET_TUN_UdpHeader) + mlen, &ts->destination_ip.v4, &ts->source_ip.v4); if (0 == ntohs (reply->source_port)) udp->source_port = htons (ts->destination_port); else udp->source_port = reply->source_port; if (0 == ntohs (reply->destination_port)) udp->destination_port = htons (ts->source_port); else udp->destination_port = reply->destination_port; udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader)); GNUNET_TUN_calculate_udp4_checksum (ipv4, udp, &reply[1], mlen); memcpy (&udp[1], &reply[1], mlen); (void) GNUNET_HELPER_send (helper_handle, msg, GNUNET_YES, NULL, NULL); } } break; case AF_INET6: { size_t size = sizeof (struct GNUNET_TUN_IPv6Header) + sizeof (struct GNUNET_TUN_UdpHeader) + sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + mlen; { char buf[size] GNUNET_ALIGN; struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf; struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1]; struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1]; struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1]; msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); msg->size = htons (size); tun->flags = htons (0); tun->proto = htons (ETH_P_IPV6); GNUNET_TUN_initialize_ipv6_header (ipv6, IPPROTO_UDP, sizeof (struct GNUNET_TUN_UdpHeader) + mlen, &ts->destination_ip.v6, &ts->source_ip.v6); if (0 == ntohs (reply->source_port)) udp->source_port = htons (ts->destination_port); else udp->source_port = reply->source_port; if (0 == ntohs (reply->destination_port)) udp->destination_port = htons (ts->source_port); else udp->destination_port = reply->destination_port; udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader)); GNUNET_TUN_calculate_udp6_checksum (ipv6, udp, &reply[1], mlen); memcpy (&udp[1], &reply[1], mlen); (void) GNUNET_HELPER_send (helper_handle, msg, GNUNET_YES, NULL, NULL); } } break; default: GNUNET_assert (0); } GNUNET_CONTAINER_heap_update_cost (tunnel_heap, ts->heap_node, GNUNET_TIME_absolute_get ().abs_value); return GNUNET_OK; } /** * We got a TCP packet back from the MESH tunnel. Pass it on to the * local virtual interface via the helper. * * @param cls closure, NULL * @param tunnel connection to the other end * @param tunnel_ctx pointer to our 'struct TunnelState *' * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) { struct TunnelState *ts = *tunnel_ctx; const struct GNUNET_EXIT_TcpDataMessage *data; size_t mlen; GNUNET_STATISTICS_update (stats, gettext_noop ("# TCP packets received from mesh"), 1, GNUNET_NO); mlen = ntohs (message->size); if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage)) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (NULL == ts->heap_node) { GNUNET_break_op (0); return GNUNET_SYSERR; } data = (const struct GNUNET_EXIT_TcpDataMessage *) message; mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage); { char sbuf[INET6_ADDRSTRLEN]; char dbuf[INET6_ADDRSTRLEN]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received TCP reply from mesh, sending %u bytes from %s:%u -> %s:%u via TUN\n", (unsigned int) mlen, inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)), ts->destination_port, inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)), ts->source_port); } if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader)) { GNUNET_break_op (0); return GNUNET_SYSERR; } switch (ts->af) { case AF_INET: { size_t size = sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_TcpHeader) + sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + mlen; { char buf[size] GNUNET_ALIGN; struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf; struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1]; struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1]; struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1]; msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); msg->size = htons (size); tun->flags = htons (0); tun->proto = htons (ETH_P_IPV4); GNUNET_TUN_initialize_ipv4_header (ipv4, IPPROTO_TCP, sizeof (struct GNUNET_TUN_TcpHeader) + mlen, &ts->destination_ip.v4, &ts->source_ip.v4); *tcp = data->tcp_header; tcp->source_port = htons (ts->destination_port); tcp->destination_port = htons (ts->source_port); GNUNET_TUN_calculate_tcp4_checksum (ipv4, tcp, &data[1], mlen); memcpy (&tcp[1], &data[1], mlen); (void) GNUNET_HELPER_send (helper_handle, msg, GNUNET_YES, NULL, NULL); } } break; case AF_INET6: { size_t size = sizeof (struct GNUNET_TUN_IPv6Header) + sizeof (struct GNUNET_TUN_TcpHeader) + sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + mlen; { char buf[size] GNUNET_ALIGN; struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf; struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1]; struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1]; struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1]; msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); msg->size = htons (size); tun->flags = htons (0); tun->proto = htons (ETH_P_IPV6); GNUNET_TUN_initialize_ipv6_header (ipv6, IPPROTO_TCP, sizeof (struct GNUNET_TUN_TcpHeader) + mlen, &ts->destination_ip.v6, &ts->source_ip.v6); *tcp = data->tcp_header; tcp->source_port = htons (ts->destination_port); tcp->destination_port = htons (ts->source_port); GNUNET_TUN_calculate_tcp6_checksum (ipv6, tcp, &data[1], mlen); memcpy (&tcp[1], &data[1], mlen); (void) GNUNET_HELPER_send (helper_handle, msg, GNUNET_YES, NULL, NULL); } } break; } GNUNET_CONTAINER_heap_update_cost (tunnel_heap, ts->heap_node, GNUNET_TIME_absolute_get ().abs_value); return GNUNET_OK; } /** * Allocate an IPv4 address from the range of the tunnel * for a new redirection. * * @param v4 where to store the address * @return GNUNET_OK on success, * GNUNET_SYSERR on error */ static int allocate_v4_address (struct in_addr *v4) { const char *ipv4addr = vpn_argv[4]; const char *ipv4mask = vpn_argv[5]; struct in_addr addr; struct in_addr mask; struct in_addr rnd; GNUNET_HashCode key; unsigned int tries; GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &addr)); GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &mask)); /* Given 192.168.0.1/255.255.0.0, we want a mask of '192.168.255.255', thus: */ mask.s_addr = addr.s_addr | ~mask.s_addr; tries = 0; do { tries++; if (tries > 16) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to find unallocated IPv4 address in VPN's range\n")); return GNUNET_SYSERR; } /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */ rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX); v4->s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr; get_destination_key_from_ip (AF_INET, v4, &key); } while ( (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (destination_map, &key)) || (v4->s_addr == addr.s_addr) || (v4->s_addr == mask.s_addr) ); return GNUNET_OK; } /** * Allocate an IPv6 address from the range of the tunnel * for a new redirection. * * @param v6 where to store the address * @return GNUNET_OK on success, * GNUNET_SYSERR on error */ static int allocate_v6_address (struct in6_addr *v6) { const char *ipv6addr = vpn_argv[2]; struct in6_addr addr; struct in6_addr mask; struct in6_addr rnd; int i; GNUNET_HashCode key; unsigned int tries; GNUNET_assert (1 == inet_pton (AF_INET6, ipv6addr, &addr)); GNUNET_assert (ipv6prefix < 128); /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF, thus: */ mask = addr; for (i=127;i>=ipv6prefix;i--) mask.s6_addr[i / 8] |= (1 << (i % 8)); /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */ tries = 0; do { tries++; if (tries > 16) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to find unallocated IPv6 address in VPN's range\n")); return GNUNET_SYSERR; } for (i=0;i<16;i++) { rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); v6->s6_addr[i] = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i]; } get_destination_key_from_ip (AF_INET6, v6, &key); } while ( (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (destination_map, &key)) || (0 == memcmp (v6, &addr, sizeof (struct in6_addr))) || (0 == memcmp (v6, &mask, sizeof (struct in6_addr))) ); return GNUNET_OK; } /** * Free resources occupied by a destination entry. * * @param de entry to free */ static void free_destination_entry (struct DestinationEntry *de) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up destination entry\n"); GNUNET_STATISTICS_update (stats, gettext_noop ("# Active destinations"), -1, GNUNET_NO); if (NULL != de->ts) { free_tunnel_state (de->ts); GNUNET_assert (NULL == de->ts); } if (NULL != de->heap_node) { GNUNET_CONTAINER_heap_remove_node (de->heap_node); de->heap_node = NULL; GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (destination_map, &de->key, de)); } GNUNET_free (de); } /** * We have too many active destinations. Clean up the oldest destination. * * @param except destination that must NOT be cleaned up, even if it is the oldest */ static void expire_destination (struct DestinationEntry *except) { struct DestinationEntry *de; de = GNUNET_CONTAINER_heap_peek (destination_heap); GNUNET_assert (NULL != de); if (except == de) return; /* can't do this */ free_destination_entry (de); } /** * Allocate an IP address for the response. * * @param result_af desired address family; set to the actual * address family; can initially be AF_UNSPEC if there * is no preference; will be set to AF_UNSPEC if the * allocation failed * @param addr set to either v4 or v6 depending on which * storage location was used; set to NULL if allocation failed * @param v4 storage space for an IPv4 address * @param v6 storage space for an IPv6 address * @return GNUNET_OK normally, GNUNET_SYSERR if '*result_af' was * an unsupported address family (not AF_INET, AF_INET6 or AF_UNSPEC) */ static int allocate_response_ip (int *result_af, void **addr, struct in_addr *v4, struct in6_addr *v6) { *addr = NULL; switch (*result_af) { case AF_INET: if (GNUNET_OK != allocate_v4_address (v4)) *result_af = AF_UNSPEC; else *addr = v4; break; case AF_INET6: if (GNUNET_OK != allocate_v6_address (v6)) *result_af = AF_UNSPEC; else *addr = v6; break; case AF_UNSPEC: if (GNUNET_OK == allocate_v4_address (v4)) { *addr = v4; *result_af = AF_INET; } else if (GNUNET_OK == allocate_v6_address (v6)) { *addr = v6; *result_af = AF_INET6; } break; default: GNUNET_break (0); return GNUNET_SYSERR; } return GNUNET_OK; } /** * A client asks us to setup a redirection via some exit * node to a particular IP. Setup the redirection and * give the client the allocated IP. * * @param cls unused * @param client requesting client * @param message redirection request (a 'struct RedirectToIpRequestMessage') */ static void service_redirect_to_ip (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { size_t mlen; size_t alen; const struct RedirectToIpRequestMessage *msg; int addr_af; int result_af; struct in_addr v4; struct in6_addr v6; void *addr; struct DestinationEntry *de; GNUNET_HashCode key; struct TunnelState *ts; /* validate and parse request */ mlen = ntohs (message->size); if (mlen < sizeof (struct RedirectToIpRequestMessage)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } alen = mlen - sizeof (struct RedirectToIpRequestMessage); msg = (const struct RedirectToIpRequestMessage *) message; addr_af = (int) htonl (msg->addr_af); switch (addr_af) { case AF_INET: if (alen != sizeof (struct in_addr)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } break; case AF_INET6: if (alen != sizeof (struct in6_addr)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } break; default: GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } /* allocate response IP */ result_af = (int) htonl (msg->result_af); if (GNUNET_OK != allocate_response_ip (&result_af, &addr, &v4, &v6)) { GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } if ( (result_af == AF_UNSPEC) || (GNUNET_NO == ntohl (msg->nac)) ) { /* send reply "instantly" */ send_client_reply (client, msg->request_id, result_af, addr); } if (result_af == AF_UNSPEC) { /* failure, we're done */ GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } { char sbuf[INET6_ADDRSTRLEN]; char dbuf[INET6_ADDRSTRLEN]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Allocated address %s for redirection via exit to %s\n", inet_ntop (result_af, addr, sbuf, sizeof (sbuf)), inet_ntop (addr_af, &msg[1], dbuf, sizeof (dbuf))); } /* setup destination record */ de = GNUNET_malloc (sizeof (struct DestinationEntry)); de->is_service = GNUNET_NO; de->details.exit_destination.af = addr_af; memcpy (&de->details.exit_destination.ip, &msg[1], alen); get_destination_key_from_ip (result_af, addr, &key); de->key = key; GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (destination_map, &key, de, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap, de, GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value); GNUNET_STATISTICS_update (stats, gettext_noop ("# Active destinations"), 1, GNUNET_NO); while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings) expire_destination (de); /* setup tunnel to destination */ ts = create_tunnel_to_destination (de, (GNUNET_NO == ntohl (msg->nac)) ? NULL : client, result_af, msg->request_id); switch (result_af) { case AF_INET: ts->destination_ip.v4 = v4; break; case AF_INET6: ts->destination_ip.v6 = v6; break; default: GNUNET_assert (0); } /* we're done */ GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * A client asks us to setup a redirection to a particular peer * offering a service. Setup the redirection and give the client the * allocated IP. * * @param cls unused * @param client requesting client * @param message redirection request (a 'struct RedirectToPeerRequestMessage') */ static void service_redirect_to_service (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct RedirectToServiceRequestMessage *msg; int result_af; struct in_addr v4; struct in6_addr v6; void *addr; struct DestinationEntry *de; GNUNET_HashCode key; struct TunnelState *ts; /* parse request */ msg = (const struct RedirectToServiceRequestMessage *) message; /* allocate response IP */ result_af = (int) htonl (msg->result_af); if (GNUNET_OK != allocate_response_ip (&result_af, &addr, &v4, &v6)) { GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } if ( (result_af == AF_UNSPEC) || (GNUNET_NO == ntohl (msg->nac)) ) { /* send reply "instantly" */ send_client_reply (client, msg->request_id, result_af, addr); } if (result_af == AF_UNSPEC) { /* failure, we're done */ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to allocate IP address for new destination\n")); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } { char sbuf[INET6_ADDRSTRLEN]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Allocated address %s for redirection to service %s on peer %s\n", inet_ntop (result_af, addr, sbuf, sizeof (sbuf)), GNUNET_h2s (&msg->service_descriptor), GNUNET_i2s (&msg->target)); } /* setup destination record */ de = GNUNET_malloc (sizeof (struct DestinationEntry)); de->is_service = GNUNET_YES; de->details.service_destination.service_descriptor = msg->service_descriptor; de->details.service_destination.target = msg->target; get_destination_key_from_ip (result_af, addr, &key); de->key = key; GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (destination_map, &key, de, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap, de, GNUNET_TIME_absolute_ntoh (msg->expiration_time).abs_value); while (GNUNET_CONTAINER_multihashmap_size (destination_map) > max_destination_mappings) expire_destination (de); ts = create_tunnel_to_destination (de, (GNUNET_NO == ntohl (msg->nac)) ? NULL : client, result_af, msg->request_id); switch (result_af) { case AF_INET: ts->destination_ip.v4 = v4; break; case AF_INET6: ts->destination_ip.v6 = v6; break; default: GNUNET_assert (0); } /* we're done */ GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Function called for inbound tunnels. As we don't offer * any mesh services, this function should never be called. * * @param cls closure * @param tunnel new handle to the tunnel * @param initiator peer that started the tunnel * @param atsi performance information for the tunnel * @return initial tunnel context for the tunnel * (can be NULL -- that's not an error) */ static void * inbound_tunnel_cb (void *cls, struct GNUNET_MESH_Tunnel *tunnel, const struct GNUNET_PeerIdentity *initiator, const struct GNUNET_ATS_Information *atsi) { /* How can and why should anyone open an inbound tunnel to vpn? */ GNUNET_break (0); return NULL; } /** * Function called whenever an inbound tunnel is destroyed. Should clean up * any associated state. * * @param cls closure (set from GNUNET_MESH_connect) * @param tunnel connection to the other end (henceforth invalid) * @param tunnel_ctx place where local state associated * with the tunnel is stored (our 'struct TunnelState') */ static void tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx) { /* we don't have inbound tunnels, so this function should never be called */ GNUNET_break (0); } /** * Free memory occupied by an entry in the destination map. * * @param cls unused * @param key unused * @param value a 'struct DestinationEntry *' * @return GNUNET_OK (continue to iterate) */ static int cleanup_destination (void *cls, const GNUNET_HashCode *key, void *value) { struct DestinationEntry *de = value; free_destination_entry (de); return GNUNET_OK; } /** * Free memory occupied by an entry in the tunnel map. * * @param cls unused * @param key unused * @param value a 'struct TunnelState *' * @return GNUNET_OK (continue to iterate) */ static int cleanup_tunnel (void *cls, const GNUNET_HashCode *key, void *value) { struct TunnelState *ts = value; free_tunnel_state (ts); return GNUNET_OK; } /** * Function scheduled as very last function, cleans up after us * * @param cls unused * @param tc unused */ static void cleanup (void *cls GNUNET_UNUSED, const struct GNUNET_SCHEDULER_TaskContext *tc) { unsigned int i; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "VPN is shutting down\n"); if (NULL != destination_map) { GNUNET_CONTAINER_multihashmap_iterate (destination_map, &cleanup_destination, NULL); GNUNET_CONTAINER_multihashmap_destroy (destination_map); destination_map = NULL; } if (NULL != destination_heap) { GNUNET_CONTAINER_heap_destroy (destination_heap); destination_heap = NULL; } if (NULL != tunnel_map) { GNUNET_CONTAINER_multihashmap_iterate (tunnel_map, &cleanup_tunnel, NULL); GNUNET_CONTAINER_multihashmap_destroy (tunnel_map); tunnel_map = NULL; } if (NULL != tunnel_heap) { GNUNET_CONTAINER_heap_destroy (tunnel_heap); tunnel_heap = NULL; } if (NULL != mesh_handle) { GNUNET_MESH_disconnect (mesh_handle); mesh_handle = NULL; } if (NULL != helper_handle) { GNUNET_HELPER_stop (helper_handle); helper_handle = NULL; } if (NULL != nc) { GNUNET_SERVER_notification_context_destroy (nc); nc = NULL; } if (stats != NULL) { GNUNET_STATISTICS_destroy (stats, GNUNET_NO); stats = NULL; } for (i=0;i<5;i++) GNUNET_free_non_null (vpn_argv[i]); } /** * A client disconnected, clean up all references to it. * * @param cls the client that disconnected * @param key unused * @param value a 'struct TunnelState *' * @return GNUNET_OK (continue to iterate) */ static int cleanup_tunnel_client (void *cls, const GNUNET_HashCode *key, void *value) { struct GNUNET_SERVER_Client *client = cls; struct TunnelState *ts = value; if (client == ts->client) { GNUNET_SERVER_client_drop (ts->client); ts->client = NULL; } return GNUNET_OK; } /** * A client disconnected, clean up all references to it. * * @param cls the client that disconnected * @param key unused * @param value a 'struct DestinationEntry *' * @return GNUNET_OK (continue to iterate) */ static int cleanup_destination_client (void *cls, const GNUNET_HashCode *key, void *value) { struct GNUNET_SERVER_Client *client = cls; struct DestinationEntry *de = value; struct TunnelState *ts; if (NULL == (ts = de->ts)) return GNUNET_OK; if (client == ts->client) { GNUNET_SERVER_client_drop (ts->client); ts->client = NULL; } return GNUNET_OK; } /** * A client has disconnected from us. If we are currently building * a tunnel for it, cancel the operation. * * @param cls unused * @param client handle to the client that disconnected */ static void client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) { if (NULL != tunnel_map) GNUNET_CONTAINER_multihashmap_iterate (tunnel_map, &cleanup_tunnel_client, client); if (NULL != destination_map) GNUNET_CONTAINER_multihashmap_iterate (destination_map, &cleanup_destination_client, client); } /** * Test if the given AF is supported by this system. * * @param af to test * @return GNUNET_OK if the AF is supported */ static int test_af (int af) { int s; s = socket (af, SOCK_STREAM, 0); if (-1 == s) { if (EAFNOSUPPORT == errno) return GNUNET_NO; GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket"); return GNUNET_SYSERR; } close (s); return GNUNET_OK; } /** * Main function that will be run by the scheduler. * * @param cls closure * @param server the initialized server * @param cfg_ configuration */ static void run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *cfg_) { static const struct GNUNET_SERVER_MessageHandler service_handlers[] = { /* callback, cls, type, size */ { &service_redirect_to_ip, NULL, GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP, 0}, { &service_redirect_to_service, NULL, GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE, sizeof (struct RedirectToServiceRequestMessage) }, {NULL, NULL, 0, 0} }; static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = { { &receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY, 0}, { &receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN, 0}, { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0}, {NULL, 0, 0} }; static const GNUNET_MESH_ApplicationType types[] = { GNUNET_APPLICATION_TYPE_END }; char *ifname; char *ipv6addr; char *ipv6prefix_s; char *ipv4addr; char *ipv4mask; struct in_addr v4; struct in6_addr v6; if (GNUNET_YES != GNUNET_OS_check_helper_binary ("gnunet-helper-vpn")) { fprintf (stderr, "`%s' is not SUID, refusing to run.\n", "gnunet-helper-vpn"); global_ret = 1; return; } cfg = cfg_; stats = GNUNET_STATISTICS_create ("vpn", cfg); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPING", &max_destination_mappings)) max_destination_mappings = 200; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_TUNNELS", &max_tunnel_mappings)) max_tunnel_mappings = 200; destination_map = GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2); destination_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); tunnel_map = GNUNET_CONTAINER_multihashmap_create (max_tunnel_mappings * 2); tunnel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); vpn_argv[0] = GNUNET_strdup ("vpn-gnunet"); if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IFNAME", &ifname)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No entry 'IFNAME' in configuration!\n"); GNUNET_SCHEDULER_shutdown (); return; } vpn_argv[1] = ifname; if (GNUNET_OK == test_af (AF_INET6)) { if ( (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR", &ipv6addr) || (1 != inet_pton (AF_INET6, ipv6addr, &v6))) ) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No valid entry 'IPV6ADDR' in configuration!\n"); GNUNET_SCHEDULER_shutdown (); return; } vpn_argv[2] = ipv6addr; if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6PREFIX", &ipv6prefix_s)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No entry 'IPV6PREFIX' in configuration!\n"); GNUNET_SCHEDULER_shutdown (); return; } vpn_argv[3] = ipv6prefix_s; if ( (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "IPV6PREFIX", &ipv6prefix)) || (ipv6prefix >= 127) ) { GNUNET_SCHEDULER_shutdown (); return; } } else { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("IPv6 support disabled as this system does not support IPv6\n")); vpn_argv[2] = GNUNET_strdup ("-"); vpn_argv[3] = GNUNET_strdup ("-"); } if (GNUNET_OK == test_af (AF_INET)) { if ( (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR", &ipv4addr) || (1 != inet_pton (AF_INET, ipv4addr, &v4))) ) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No valid entry for 'IPV4ADDR' in configuration!\n"); GNUNET_SCHEDULER_shutdown (); return; } vpn_argv[4] = ipv4addr; if ( (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK", &ipv4mask) || (1 != inet_pton (AF_INET, ipv4mask, &v4))) ) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No valid entry 'IPV4MASK' in configuration!\n"); GNUNET_SCHEDULER_shutdown (); return; } vpn_argv[5] = ipv4mask; } else { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("IPv4 support disabled as this system does not support IPv4\n")); vpn_argv[4] = GNUNET_strdup ("-"); vpn_argv[5] = GNUNET_strdup ("-"); } vpn_argv[6] = NULL; mesh_handle = GNUNET_MESH_connect (cfg_, 42 /* queue length */, NULL, &inbound_tunnel_cb, &tunnel_cleaner, mesh_handlers, types); helper_handle = GNUNET_HELPER_start ("gnunet-helper-vpn", vpn_argv, &message_token, NULL); nc = GNUNET_SERVER_notification_context_create (server, 1); GNUNET_SERVER_add_handlers (server, service_handlers); GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls); } /** * The main function of the VPN service. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { return (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "vpn", GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? global_ret : 1; } /* end of gnunet-service-vpn.c */ gnunet-0.9.3/src/util/0000755000175000017500000000000011763406747011607 500000000000000gnunet-0.9.3/src/util/getopt_helpers.c0000644000175000017500000002102011760502550014674 00000000000000/* This file is part of GNUnet (C) 2006, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/util/getopt_helpers.c * @brief implements command line that sets option * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_getopt_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) /** * Print out program version (implements --version). * * @param ctx command line processing context * @param scls additional closure (points to version string) * @param option name of the option * @param value not used (NULL) * @return GNUNET_SYSERR (do not continue) */ int GNUNET_GETOPT_print_version_ (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, const char *value) { const char *version = scls; printf ("%s v%s\n", ctx->binaryName, version); return GNUNET_SYSERR; } #define BORDER 29 /** * Print out details on command line options (implements --help). * * @param ctx command line processing context * @param scls additional closure (points to about text) * @param option name of the option * @param value not used (NULL) * @return GNUNET_SYSERR (do not continue) */ int GNUNET_GETOPT_format_help_ (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, const char *value) { const char *about = scls; size_t slen; unsigned int i; int j; size_t ml; size_t p; char *scp; const char *trans; const struct GNUNET_GETOPT_CommandLineOption *opt; if (NULL != about) { printf ("%s\n%s\n", ctx->binaryOptions, gettext (about)); printf (_ ("Arguments mandatory for long options are also mandatory for short options.\n")); } i = 0; opt = ctx->allOptions; while (opt[i].description != NULL) { if (opt[i].shortName == '\0') printf (" "); else printf (" -%c, ", opt[i].shortName); printf ("--%s", opt[i].name); slen = 8 + strlen (opt[i].name); if (opt[i].argumentHelp != NULL) { printf ("=%s", opt[i].argumentHelp); slen += 1 + strlen (opt[i].argumentHelp); } if (slen > BORDER) { printf ("\n%*s", BORDER, ""); slen = BORDER; } if (slen < BORDER) { printf ("%*s", (int) (BORDER - slen), ""); slen = BORDER; } if (0 < strlen (opt[i].description)) trans = gettext (opt[i].description); else trans = ""; ml = strlen (trans); p = 0; OUTER: while (ml - p > 78 - slen) { for (j = p + 78 - slen; j > p; j--) { if (isspace ((unsigned char) trans[j])) { scp = GNUNET_malloc (j - p + 1); memcpy (scp, &trans[p], j - p); scp[j - p] = '\0'; printf ("%s\n%*s", scp, BORDER + 2, ""); GNUNET_free (scp); p = j + 1; slen = BORDER + 2; goto OUTER; } } /* could not find space to break line */ scp = GNUNET_malloc (78 - slen + 1); memcpy (scp, &trans[p], 78 - slen); scp[78 - slen] = '\0'; printf ("%s\n%*s", scp, BORDER + 2, ""); GNUNET_free (scp); slen = BORDER + 2; p = p + 78 - slen; } /* print rest */ if (p < ml) printf ("%s\n", &trans[p]); if (strlen (trans) == 0) printf ("\n"); i++; } printf ("Report bugs to gnunet-developers@gnu.org.\n" "GNUnet home page: http://www.gnu.org/software/gnunet/\n" "General help using GNU software: http://www.gnu.org/gethelp/\n"); return GNUNET_SYSERR; } /** * Set an option of type 'unsigned int' from the command line. Each * time the option flag is given, the value is incremented by one. * A pointer to this function should be passed as part of the * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options * of this type. It should be followed by a pointer to a value of * type 'int'. * * @param ctx command line processing context * @param scls additional closure (will point to the 'int') * @param option name of the option * @param value not used (NULL) * @return GNUNET_OK */ int GNUNET_GETOPT_increment_value (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, const char *value) { int *val = scls; (*val)++; return GNUNET_OK; } /** * Set an option of type 'int' from the command line to 1 if the * given option is present. * A pointer to this function should be passed as part of the * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options * of this type. It should be followed by a pointer to a value of * type 'int'. * * @param ctx command line processing context * @param scls additional closure (will point to the 'int') * @param option name of the option * @param value not used (NULL) * @return GNUNET_OK */ int GNUNET_GETOPT_set_one (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, const char *value) { int *val = scls; *val = 1; return GNUNET_OK; } /** * Set an option of type 'char *' from the command line. * A pointer to this function should be passed as part of the * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options * of this type. It should be followed by a pointer to a value of * type 'char *'. * * @param ctx command line processing context * @param scls additional closure (will point to the 'char *', * which will be allocated) * @param option name of the option * @param value actual value of the option (a string) * @return GNUNET_OK */ int GNUNET_GETOPT_set_string (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, const char *value) { char **val = scls; GNUNET_assert (value != NULL); GNUNET_free_non_null (*val); *val = GNUNET_strdup (value); return GNUNET_OK; } /** * Set an option of type 'unsigned long long' from the command line. * A pointer to this function should be passed as part of the * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options * of this type. It should be followed by a pointer to a value of * type 'unsigned long long'. * * @param ctx command line processing context * @param scls additional closure (will point to the 'unsigned long long') * @param option name of the option * @param value actual value of the option as a string. * @return GNUNET_OK if parsing the value worked */ int GNUNET_GETOPT_set_ulong (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, const char *value) { unsigned long long *val = scls; if (1 != SSCANF (value, "%llu", val)) { FPRINTF (stderr, _("You must pass a number to the `%s' option.\n"), option); return GNUNET_SYSERR; } return GNUNET_OK; } /** * Set an option of type 'unsigned int' from the command line. * A pointer to this function should be passed as part of the * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options * of this type. It should be followed by a pointer to a value of * type 'unsigned int'. * * @param ctx command line processing context * @param scls additional closure (will point to the 'unsigned int') * @param option name of the option * @param value actual value of the option as a string. * @return GNUNET_OK if parsing the value worked */ int GNUNET_GETOPT_set_uint (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, const char *value) { unsigned int *val = scls; if (1 != SSCANF (value, "%u", val)) { FPRINTF (stderr, _("You must pass a number to the `%s' option.\n"), option); return GNUNET_SYSERR; } return GNUNET_OK; } /* end of getopt_helpers.c */ gnunet-0.9.3/src/util/common_logging.c0000644000175000017500000006345211760502550014665 00000000000000/* This file is part of GNUnet. (C) 2006, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/common_logging.c * @brief error handling API * * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_crypto_lib.h" #include "gnunet_strings_lib.h" #include "gnunet_time_lib.h" #include /** * After how many milliseconds do we always print * that "message X was repeated N times"? Use 12h. */ #define BULK_DELAY_THRESHOLD (12 * 60 * 60 * 1000) /** * After how many repetitions do we always print * that "message X was repeated N times"? (even if * we have not yet reached the delay threshold) */ #define BULK_REPEAT_THRESHOLD 1000 /** * How many characters do we use for matching of * bulk messages? */ #define BULK_TRACK_SIZE 256 /** * How many characters do we use for matching of * bulk components? */ #define COMP_TRACK_SIZE 32 /** * How many characters can a date/time string * be at most? */ #define DATE_STR_SIZE 64 /** * Linked list of active loggers. */ struct CustomLogger { /** * This is a linked list. */ struct CustomLogger *next; /** * Log function. */ GNUNET_Logger logger; /** * Closure for logger. */ void *logger_cls; }; /** * The last "bulk" error message that we have been logging. * Note that this message maybe truncated to the first BULK_TRACK_SIZE * characters, in which case it is NOT 0-terminated! */ static char last_bulk[BULK_TRACK_SIZE]; /** * Type of the last bulk message. */ static enum GNUNET_ErrorType last_bulk_kind; /** * Time of the last bulk error message (0 for none) */ static struct GNUNET_TIME_Absolute last_bulk_time; /** * Number of times that bulk message has been repeated since. */ static unsigned int last_bulk_repeat; /** * Component when the last bulk was logged. Will be 0-terminated. */ static char last_bulk_comp[COMP_TRACK_SIZE + 1]; /** * Running component. */ static char *component; /** * Running component (without pid). */ static char *component_nopid; /** * Minimum log level. */ static enum GNUNET_ErrorType min_level; /** * Linked list of our custom loggres. */ static struct CustomLogger *loggers; /** * Number of log calls to ignore. */ unsigned int skip_log; /** * File descriptor to use for "stderr", or NULL for none. */ static FILE *GNUNET_stderr; /** * Represents a single logging definition */ struct LogDef { /** * Component name regex */ regex_t component_regex; /** * File name regex */ regex_t file_regex; /** * Function name regex */ regex_t function_regex; /** * Lowest line at which this definition matches. * Defaults to 0. Must be <= to_line. */ int from_line; /** * Highest line at which this definition matches. * Defaults to INT_MAX. Must be >= from_line. */ int to_line; /** * Maximal log level allowed for calls that match this definition. * Calls with higher log level will be disabled. * Must be >= 0 */ int level; /** * 1 if this definition comes from GNUNET_FORCE_LOG, which means that it * overrides any configuration options. 0 otherwise. */ int force; }; /** * Dynamic array of logging definitions */ struct LogDef *logdefs = NULL; /** * Allocated size of logdefs array (in units) */ int logdefs_size = 0; /** * The number of units used in logdefs array. */ int logdefs_len = 0; /** * GNUNET_YES if GNUNET_LOG environment variable is already parsed. */ int gnunet_log_parsed = GNUNET_NO; /** * GNUNET_YES if GNUNET_FORCE_LOG environment variable is already parsed. */ int gnunet_force_log_parsed = GNUNET_NO; /** * GNUNET_YES if at least one definition with forced == 1 is available. */ int gnunet_force_log_present = GNUNET_NO; #ifdef WINDOWS /** * Contains the number of performance counts per second. */ LARGE_INTEGER performance_frequency; #endif /** * Convert a textual description of a loglevel * to the respective GNUNET_GE_KIND. * * @param log loglevel to parse * @return GNUNET_GE_INVALID if log does not parse */ static enum GNUNET_ErrorType get_type (const char *log) { if (log == NULL) return GNUNET_ERROR_TYPE_UNSPECIFIED; if (0 == strcasecmp (log, _("DEBUG"))) return GNUNET_ERROR_TYPE_DEBUG; if (0 == strcasecmp (log, _("INFO"))) return GNUNET_ERROR_TYPE_INFO; if (0 == strcasecmp (log, _("WARNING"))) return GNUNET_ERROR_TYPE_WARNING; if (0 == strcasecmp (log, _("ERROR"))) return GNUNET_ERROR_TYPE_ERROR; if (0 == strcasecmp (log, _("NONE"))) return GNUNET_ERROR_TYPE_NONE; return GNUNET_ERROR_TYPE_INVALID; } #if !defined(GNUNET_CULL_LOGGING) /** * Utility function - reallocates logdefs array to be twice as large. */ static void resize_logdefs () { logdefs_size = (logdefs_size + 1) * 2; logdefs = GNUNET_realloc (logdefs, logdefs_size * sizeof (struct LogDef)); } /** * Abort the process, generate a core dump if possible. */ void GNUNET_abort () { #if WINDOWS DebugBreak (); #endif abort (); } /** * Utility function - adds a parsed definition to logdefs array. * * @param component see struct LogDef, can't be NULL * @param file see struct LogDef, can't be NULL * @param function see struct LogDef, can't be NULL * @param from_line see struct LogDef * @param to_line see struct LogDef * @param level see struct LogDef, must be >= 0 * @param force see struct LogDef * @return 0 on success, regex-specific error otherwise */ static int add_definition (char *component, char *file, char *function, int from_line, int to_line, int level, int force) { struct LogDef n; int r; if (logdefs_size == logdefs_len) resize_logdefs (); memset (&n, 0, sizeof (n)); if (strlen (component) == 0) component = (char *) ".*"; r = regcomp (&n.component_regex, (const char *) component, REG_NOSUB); if (r != 0) { return r; } if (strlen (file) == 0) file = (char *) ".*"; r = regcomp (&n.file_regex, (const char *) file, REG_NOSUB); if (r != 0) { regfree (&n.component_regex); return r; } if ((NULL == function) || (strlen (function) == 0)) function = (char *) ".*"; r = regcomp (&n.function_regex, (const char *) function, REG_NOSUB); if (r != 0) { regfree (&n.component_regex); regfree (&n.file_regex); return r; } n.from_line = from_line; n.to_line = to_line; n.level = level; n.force = force; logdefs[logdefs_len++] = n; return 0; } /** * Decides whether a particular logging call should or should not be allowed * to be made. Used internally by GNUNET_log*() * * @param caller_level loglevel the caller wants to use * @param comp component name the caller uses (NULL means that global * component name is used) * @param file file name containing the logging call, usually __FILE__ * @param function function which tries to make a logging call, * usually __FUNCTION__ * @param line line at which the call is made, usually __LINE__ * @return 0 to disallow the call, 1 to allow it */ int GNUNET_get_log_call_status (int caller_level, const char *comp, const char *file, const char *function, int line) { struct LogDef *ld; int i; int force_only; if (comp == NULL) /* Use default component */ comp = component_nopid; /* We have no definitions to override globally configured log level, * so just use it right away. */ if (min_level >= 0 && gnunet_force_log_present == GNUNET_NO) return caller_level <= min_level; /* Only look for forced definitions? */ force_only = min_level >= 0; for (i = 0; i < logdefs_len; i++) { ld = &logdefs[i]; if ((!force_only || ld->force) && (line >= ld->from_line && line <= ld->to_line) && (regexec (&ld->component_regex, comp, 0, NULL, 0) == 0) && (regexec (&ld->file_regex, file, 0, NULL, 0) == 0) && (regexec (&ld->function_regex, function, 0, NULL, 0) == 0)) { /* We're finished */ return caller_level <= ld->level; } } /* No matches - use global level, if defined */ if (min_level >= 0) return caller_level <= min_level; /* All programs/services previously defaulted to WARNING. * Now WE default to WARNING, and THEY default to NULL. */ return caller_level <= GNUNET_ERROR_TYPE_WARNING; } /** * Utility function - parses a definition * * Definition format: * component;file;function;from_line-to_line;level[/component...] * All entries are mandatory, but may be empty. * Empty entries for component, file and function are treated as * "matches anything". * Empty line entry is treated as "from 0 to INT_MAX" * Line entry with only one line is treated as "this line only" * Entry for level MUST NOT be empty. * Entries for component, file and function that consist of a * single character "*" are treated (at the moment) the same way * empty entries are treated (wildcard matching is not implemented (yet?)). * file entry is matched to the end of __FILE__. That is, it might be * a base name, or a base name with leading directory names (some compilers * define __FILE__ to absolute file path). * * @param constname name of the environment variable from which to get the * string to be parsed * @param force 1 if definitions found in constname are to be forced * @return number of added definitions */ static int parse_definitions (const char *constname, int force) { char *def; const char *tmp; char *comp = NULL; char *file = NULL; char *function = NULL; char *p; char *start; char *t; short state; int level; int from_line, to_line; int counter = 0; int keep_looking = 1; tmp = getenv (constname); if (tmp == NULL) return 0; def = GNUNET_strdup (tmp); from_line = 0; to_line = INT_MAX; for (p = def, state = 0, start = def; keep_looking; p++) { switch (p[0]) { case ';': /* found a field separator */ p[0] = '\0'; switch (state) { case 0: /* within a component name */ comp = start; break; case 1: /* within a file name */ file = start; break; case 2: /* within a function name */ /* after a file name there must be a function name */ function = start; break; case 3: /* within a from-to line range */ if (strlen (start) > 0) { errno = 0; from_line = strtol (start, &t, 10); if (errno != 0 || from_line < 0) { GNUNET_free (def); return counter; } if (t < p && t[0] == '-') { errno = 0; start = t + 1; to_line = strtol (start, &t, 10); if (errno != 0 || to_line < 0 || t != p) { GNUNET_free (def); return counter; } } else /* one number means "match this line only" */ to_line = from_line; } else /* default to 0-max */ { from_line = 0; to_line = INT_MAX; } break; } start = p + 1; state += 1; break; case '\0': /* found EOL */ keep_looking = 0; /* fall through to '/' */ case '/': /* found a definition separator */ switch (state) { case 4: /* within a log level */ p[0] = '\0'; state = 0; level = get_type ((const char *) start); if (level == GNUNET_ERROR_TYPE_INVALID || level == GNUNET_ERROR_TYPE_UNSPECIFIED || 0 != add_definition (comp, file, function, from_line, to_line, level, force)) { GNUNET_free (def); return counter; } counter += 1; start = p + 1; break; default: break; } default: break; } } GNUNET_free (def); return counter; } /** * Utility function - parses GNUNET_LOG and GNUNET_FORCE_LOG. */ static void parse_all_definitions () { if (gnunet_log_parsed == GNUNET_NO) parse_definitions ("GNUNET_LOG", 0); gnunet_log_parsed = GNUNET_YES; if (gnunet_force_log_parsed == GNUNET_NO) gnunet_force_log_present = parse_definitions ("GNUNET_FORCE_LOG", 1) > 0 ? GNUNET_YES : GNUNET_NO; gnunet_force_log_parsed = GNUNET_YES; } #endif /** * Setup logging. * * @param comp default component to use * @param loglevel what types of messages should be logged * @param logfile which file to write log messages to (can be NULL) * @return GNUNET_OK on success */ int GNUNET_log_setup (const char *comp, const char *loglevel, const char *logfile) { FILE *altlog; int dirwarn; char *fn; const char *env_logfile = NULL; int altlog_fd; min_level = get_type (loglevel); #if !defined(GNUNET_CULL_LOGGING) parse_all_definitions (); #endif #ifdef WINDOWS QueryPerformanceFrequency (&performance_frequency); #endif GNUNET_free_non_null (component); GNUNET_asprintf (&component, "%s-%d", comp, getpid ()); GNUNET_free_non_null (component_nopid); component_nopid = GNUNET_strdup (comp); env_logfile = getenv ("GNUNET_FORCE_LOGFILE"); if ((env_logfile != NULL) && (strlen (env_logfile) > 0)) logfile = env_logfile; if (logfile == NULL) return GNUNET_OK; fn = GNUNET_STRINGS_filename_expand (logfile); if (NULL == fn) return GNUNET_SYSERR; dirwarn = (GNUNET_OK != GNUNET_DISK_directory_create_for_file (fn)); #if WINDOWS altlog_fd = OPEN (fn, O_APPEND | O_BINARY | O_WRONLY | O_CREAT, _S_IREAD | _S_IWRITE); #else altlog_fd = OPEN (fn, O_APPEND | O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); #endif if (altlog_fd != -1) { int dup_return; if (GNUNET_stderr != NULL) fclose (GNUNET_stderr); dup_return = dup2 (altlog_fd, 2); (void) close (altlog_fd); if (dup_return != -1) { altlog = fdopen (2, "ab"); if (altlog == NULL) { (void) close (2); altlog_fd = -1; } } else { altlog_fd = -1; } } if (altlog_fd == -1) { GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", fn); if (dirwarn) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to create or access directory for log file `%s'\n"), fn); GNUNET_free (fn); return GNUNET_SYSERR; } GNUNET_free (fn); GNUNET_stderr = altlog; return GNUNET_OK; } /** * Add a custom logger. * * @param logger log function * @param logger_cls closure for logger */ void GNUNET_logger_add (GNUNET_Logger logger, void *logger_cls) { struct CustomLogger *entry; entry = GNUNET_malloc (sizeof (struct CustomLogger)); entry->logger = logger; entry->logger_cls = logger_cls; entry->next = loggers; loggers = entry; } /** * Remove a custom logger. * * @param logger log function * @param logger_cls closure for logger */ void GNUNET_logger_remove (GNUNET_Logger logger, void *logger_cls) { struct CustomLogger *pos; struct CustomLogger *prev; prev = NULL; pos = loggers; while ((pos != NULL) && ((pos->logger != logger) || (pos->logger_cls != logger_cls))) { prev = pos; pos = pos->next; } GNUNET_assert (pos != NULL); if (prev == NULL) loggers = pos->next; else prev->next = pos->next; GNUNET_free (pos); } /** * Actually output the log message. * * @param kind how severe was the issue * @param comp component responsible * @param datestr current date/time * @param msg the actual message */ static void output_message (enum GNUNET_ErrorType kind, const char *comp, const char *datestr, const char *msg) { struct CustomLogger *pos; if (GNUNET_stderr != NULL) { FPRINTF (GNUNET_stderr, "%s %s %s %s", datestr, comp, GNUNET_error_type_to_string (kind), msg); fflush (GNUNET_stderr); } pos = loggers; while (pos != NULL) { pos->logger (pos->logger_cls, kind, comp, datestr, msg); pos = pos->next; } } /** * Flush an existing bulk report to the output. * * @param datestr our current timestamp */ static void flush_bulk (const char *datestr) { char msg[DATE_STR_SIZE + BULK_TRACK_SIZE + 256]; int rev; char *last; char *ft; if ((last_bulk_time.abs_value == 0) || (last_bulk_repeat == 0)) return; rev = 0; last = memchr (last_bulk, '\0', BULK_TRACK_SIZE); if (last == NULL) last = &last_bulk[BULK_TRACK_SIZE - 1]; else if (last != last_bulk) last--; if (last[0] == '\n') { rev = 1; last[0] = '\0'; } ft = GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (last_bulk_time)); snprintf (msg, sizeof (msg), _("Message `%.*s' repeated %u times in the last %s\n"), BULK_TRACK_SIZE, last_bulk, last_bulk_repeat, ft); GNUNET_free (ft); if (rev == 1) last[0] = '\n'; output_message (last_bulk_kind, last_bulk_comp, datestr, msg); last_bulk_time = GNUNET_TIME_absolute_get (); last_bulk_repeat = 0; } /** * Ignore the next n calls to the log function. * * @param n number of log calls to ignore * @param check_reset GNUNET_YES to assert that the log skip counter is currently zero */ void GNUNET_log_skip (unsigned int n, int check_reset) { if (n == 0) { int ok; ok = (0 == skip_log); skip_log = 0; if (check_reset) GNUNET_assert (ok); } else skip_log += n; } /** * Output a log message using the default mechanism. * * @param kind how severe was the issue * @param comp component responsible * @param message the actual message * @param va arguments to the format string "message" */ static void mylog (enum GNUNET_ErrorType kind, const char *comp, const char *message, va_list va) { char date[DATE_STR_SIZE]; char date2[DATE_STR_SIZE]; time_t timetmp; struct timeval timeofday; struct tm *tmptr; size_t size; va_list vacp; va_copy (vacp, va); size = VSNPRINTF (NULL, 0, message, vacp) + 1; GNUNET_assert (0 != size); va_end (vacp); { char buf[size]; VSNPRINTF (buf, size, message, va); time (&timetmp); memset (date, 0, DATE_STR_SIZE); tmptr = localtime (&timetmp); gettimeofday (&timeofday, NULL); if (NULL != tmptr) { #ifdef WINDOWS LARGE_INTEGER pc; pc.QuadPart = 0; QueryPerformanceCounter (&pc); strftime (date2, DATE_STR_SIZE, "%b %d %H:%M:%S-%%020llu", tmptr); snprintf (date, sizeof (date), date2, (long long) (pc.QuadPart / (performance_frequency.QuadPart / 1000))); #else strftime (date2, DATE_STR_SIZE, "%b %d %H:%M:%S-%%06u", tmptr); snprintf (date, sizeof (date), date2, timeofday.tv_usec); #endif } else strcpy (date, "localtime error"); if ((0 != (kind & GNUNET_ERROR_TYPE_BULK)) && (last_bulk_time.abs_value != 0) && (0 == strncmp (buf, last_bulk, sizeof (last_bulk)))) { last_bulk_repeat++; if ((GNUNET_TIME_absolute_get_duration (last_bulk_time).rel_value > BULK_DELAY_THRESHOLD) || (last_bulk_repeat > BULK_REPEAT_THRESHOLD)) flush_bulk (date); return; } flush_bulk (date); strncpy (last_bulk, buf, sizeof (last_bulk)); last_bulk_repeat = 0; last_bulk_kind = kind; last_bulk_time = GNUNET_TIME_absolute_get (); strncpy (last_bulk_comp, comp, COMP_TRACK_SIZE); output_message (kind, comp, date, buf); } } /** * Main log function. * * @param kind how serious is the error? * @param message what is the message (format string) * @param ... arguments for format string */ void GNUNET_log_nocheck (enum GNUNET_ErrorType kind, const char *message, ...) { va_list va; va_start (va, message); mylog (kind, component, message, va); va_end (va); } /** * Log function that specifies an alternative component. * This function should be used by plugins. * * @param kind how serious is the error? * @param comp component responsible for generating the message * @param message what is the message (format string) * @param ... arguments for format string */ void GNUNET_log_from_nocheck (enum GNUNET_ErrorType kind, const char *comp, const char *message, ...) { va_list va; char comp_w_pid[128]; if (comp == NULL) comp = component_nopid; va_start (va, message); GNUNET_snprintf (comp_w_pid, sizeof (comp_w_pid), "%s-%d", comp, getpid ()); mylog (kind, comp_w_pid, message, va); va_end (va); } /** * Convert error type to string. * * @param kind type to convert * @return string corresponding to the type */ const char * GNUNET_error_type_to_string (enum GNUNET_ErrorType kind) { if ((kind & GNUNET_ERROR_TYPE_ERROR) > 0) return _("ERROR"); if ((kind & GNUNET_ERROR_TYPE_WARNING) > 0) return _("WARNING"); if ((kind & GNUNET_ERROR_TYPE_INFO) > 0) return _("INFO"); if ((kind & GNUNET_ERROR_TYPE_DEBUG) > 0) return _("DEBUG"); if ((kind & ~GNUNET_ERROR_TYPE_BULK) == 0) return _("NONE"); return _("INVALID"); } /** * Convert a hash to a string (for printing debug messages). * This is one of the very few calls in the entire API that is * NOT reentrant! * * @param hc the hash code * @return string form; will be overwritten by next call to GNUNET_h2s. */ const char * GNUNET_h2s (const GNUNET_HashCode * hc) { static struct GNUNET_CRYPTO_HashAsciiEncoded ret; GNUNET_CRYPTO_hash_to_enc (hc, &ret); ret.encoding[8] = '\0'; return (const char *) ret.encoding; } /** * Convert a hash to a string (for printing debug messages). * This is one of the very few calls in the entire API that is * NOT reentrant! * * @param hc the hash code * @return string form; will be overwritten by next call to GNUNET_h2s_full. */ const char * GNUNET_h2s_full (const GNUNET_HashCode * hc) { static struct GNUNET_CRYPTO_HashAsciiEncoded ret; GNUNET_CRYPTO_hash_to_enc (hc, &ret); ret.encoding[sizeof (ret) - 1] = '\0'; return (const char *) ret.encoding; } /** * Convert a peer identity to a string (for printing debug messages). * This is one of the very few calls in the entire API that is * NOT reentrant! * * @param pid the peer identity * @return string form of the pid; will be overwritten by next * call to GNUNET_i2s. */ const char * GNUNET_i2s (const struct GNUNET_PeerIdentity *pid) { static struct GNUNET_CRYPTO_HashAsciiEncoded ret; GNUNET_CRYPTO_hash_to_enc (&pid->hashPubKey, &ret); ret.encoding[4] = '\0'; return (const char *) ret.encoding; } /** * Convert a peer identity to a string (for printing debug messages). * This is one of the very few calls in the entire API that is * NOT reentrant! * * @param pid the peer identity * @return string form of the pid; will be overwritten by next * call to GNUNET_i2s. */ const char * GNUNET_i2s_full (const struct GNUNET_PeerIdentity *pid) { static struct GNUNET_CRYPTO_HashAsciiEncoded ret; GNUNET_CRYPTO_hash_to_enc (&pid->hashPubKey, &ret); return (const char *) ret.encoding; } /** * Convert a "struct sockaddr*" (IPv4 or IPv6 address) to a string * (for printing debug messages). This is one of the very few calls * in the entire API that is NOT reentrant! * * @param addr the address * @param addrlen the length of the address * @return nicely formatted string for the address * will be overwritten by next call to GNUNET_a2s. */ const char * GNUNET_a2s (const struct sockaddr *addr, socklen_t addrlen) { static char buf[INET6_ADDRSTRLEN + 8]; static char b2[6]; const struct sockaddr_in *v4; const struct sockaddr_un *un; const struct sockaddr_in6 *v6; unsigned int off; if (addr == NULL) return _("unknown address"); switch (addr->sa_family) { case AF_INET: if (addrlen != sizeof (struct sockaddr_in)) return ""; v4 = (const struct sockaddr_in *) addr; inet_ntop (AF_INET, &v4->sin_addr, buf, INET_ADDRSTRLEN); if (0 == ntohs (v4->sin_port)) return buf; strcat (buf, ":"); GNUNET_snprintf (b2, sizeof (b2), "%u", ntohs (v4->sin_port)); strcat (buf, b2); return buf; case AF_INET6: if (addrlen != sizeof (struct sockaddr_in6)) return ""; v6 = (const struct sockaddr_in6 *) addr; buf[0] = '['; inet_ntop (AF_INET6, &v6->sin6_addr, &buf[1], INET6_ADDRSTRLEN); if (0 == ntohs (v6->sin6_port)) return &buf[1]; strcat (buf, "]:"); GNUNET_snprintf (b2, sizeof (b2), "%u", ntohs (v6->sin6_port)); strcat (buf, b2); return buf; case AF_UNIX: if (addrlen <= sizeof (sa_family_t)) return ""; un = (const struct sockaddr_un *) addr; off = 0; if (un->sun_path[0] == '\0') off++; snprintf (buf, sizeof (buf), "%s%.*s", (off == 1) ? "@" : "", (int) (addrlen - sizeof (sa_family_t) - 1 - off), &un->sun_path[off]); return buf; default: return _("invalid address"); } } /** * Initializer */ void __attribute__ ((constructor)) GNUNET_util_cl_init () { GNUNET_stderr = stderr; #ifdef MINGW GNInitWinEnv (NULL); #endif } /** * Destructor */ void __attribute__ ((destructor)) GNUNET_util_cl_fini () { #ifdef MINGW GNShutdownWinEnv (); #endif } /* end of common_logging.c */ gnunet-0.9.3/src/util/gnunet-config-diff.c0000644000175000017500000000113011760502550015321 00000000000000#include "platform.h" #include int main (int argc, char **argv) { struct GNUNET_CONFIGURATION_Handle *i1; struct GNUNET_CONFIGURATION_Handle *i2; if (argc != 3) { fprintf (stderr, "Invoke using `%s DEFAULTS-IN DIFFS'\n", argv[0]); return 1; } i1 = GNUNET_CONFIGURATION_create (); i2 = GNUNET_CONFIGURATION_create (); if ((GNUNET_OK != GNUNET_CONFIGURATION_load (i1, argv[1])) || (GNUNET_OK != GNUNET_CONFIGURATION_load (i2, argv[2]))) return 1; if (GNUNET_OK != GNUNET_CONFIGURATION_write_diffs (i1, i2, argv[2])) return 2; return 0; } gnunet-0.9.3/src/util/plugin.c0000644000175000017500000002022311760502550013152 00000000000000/* This file is part of GNUnet (C) 2002, 2003, 2004, 2005, 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/plugin.c * @brief Methods to access plugins * @author Christian Grothoff */ #include "platform.h" #include #include "gnunet_common.h" #include "gnunet_os_lib.h" #include "gnunet_plugin_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) /** * Linked list of active plugins. */ struct PluginList { /** * This is a linked list. */ struct PluginList *next; /** * Name of the library. */ char *name; /** * System handle. */ void *handle; }; /** * Have we been initialized? */ static int initialized; /** * Libtool search path before we started. */ static char *old_dlsearchpath; /** * List of plugins we have loaded. */ static struct PluginList *plugins; /** * Setup libtool paths. */ static void plugin_init () { int err; const char *opath; char *path; char *cpath; err = lt_dlinit (); if (err > 0) { FPRINTF (stderr, _("Initialization of plugin mechanism failed: %s!\n"), lt_dlerror ()); return; } opath = lt_dlgetsearchpath (); if (opath != NULL) old_dlsearchpath = GNUNET_strdup (opath); path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR); if (path != NULL) { if (opath != NULL) { GNUNET_asprintf (&cpath, "%s:%s", opath, path); lt_dlsetsearchpath (cpath); GNUNET_free (path); GNUNET_free (cpath); } else { lt_dlsetsearchpath (path); GNUNET_free (path); } } } /** * Shutdown libtool. */ static void plugin_fini () { lt_dlsetsearchpath (old_dlsearchpath); if (old_dlsearchpath != NULL) { GNUNET_free (old_dlsearchpath); old_dlsearchpath = NULL; } lt_dlexit (); } /** * Lookup a function in the plugin. */ static GNUNET_PLUGIN_Callback resolve_function (struct PluginList *plug, const char *name) { char *initName; void *mptr; GNUNET_asprintf (&initName, "_%s_%s", plug->name, name); mptr = lt_dlsym (plug->handle, &initName[1]); if (mptr == NULL) mptr = lt_dlsym (plug->handle, initName); if (mptr == NULL) LOG (GNUNET_ERROR_TYPE_ERROR, _("`%s' failed to resolve method '%s' with error: %s\n"), "lt_dlsym", &initName[1], lt_dlerror ()); GNUNET_free (initName); return mptr; } /** * Test if a plugin exists. * * Note that the library must export a symbol called * "library_name_init" for the test to succeed. * * @param library_name name of the plugin to test if it is installed * @return GNUNET_YES if the plugin exists, GNUNET_NO if not */ int GNUNET_PLUGIN_test (const char *library_name) { void *libhandle; GNUNET_PLUGIN_Callback init; struct PluginList plug; if (!initialized) { initialized = GNUNET_YES; plugin_init (); } libhandle = lt_dlopenext (library_name); if (libhandle == NULL) return GNUNET_NO; plug.handle = libhandle; plug.name = (char *) library_name; init = resolve_function (&plug, "init"); if (init == NULL) { GNUNET_break (0); lt_dlclose (libhandle); return GNUNET_NO; } lt_dlclose (libhandle); return GNUNET_YES; } /** * Setup plugin (runs the "init" callback and returns whatever "init" * returned). If "init" returns NULL, the plugin is unloaded. * * Note that the library must export symbols called * "library_name_init" and "library_name_done". These will be called * when the library is loaded and unloaded respectively. * * @param library_name name of the plugin to load * @param arg argument to the plugin initialization function * @return whatever the initialization function returned */ void * GNUNET_PLUGIN_load (const char *library_name, void *arg) { void *libhandle; struct PluginList *plug; GNUNET_PLUGIN_Callback init; void *ret; if (!initialized) { initialized = GNUNET_YES; plugin_init (); } libhandle = lt_dlopenext (library_name); if (libhandle == NULL) { LOG (GNUNET_ERROR_TYPE_ERROR, _("`%s' failed for library `%s' with error: %s\n"), "lt_dlopenext", library_name, lt_dlerror ()); return NULL; } plug = GNUNET_malloc (sizeof (struct PluginList)); plug->handle = libhandle; plug->name = GNUNET_strdup (library_name); plug->next = plugins; plugins = plug; init = resolve_function (plug, "init"); if ((init == NULL) || (NULL == (ret = init (arg)))) { lt_dlclose (libhandle); GNUNET_free (plug->name); plugins = plug->next; GNUNET_free (plug); return NULL; } return ret; } /** * Unload plugin (runs the "done" callback and returns whatever "done" * returned). The plugin is then unloaded. * * @param library_name name of the plugin to unload * @param arg argument to the plugin shutdown function * @return whatever the shutdown function returned */ void * GNUNET_PLUGIN_unload (const char *library_name, void *arg) { struct PluginList *pos; struct PluginList *prev; GNUNET_PLUGIN_Callback done; void *ret; prev = NULL; pos = plugins; while ((pos != NULL) && (0 != strcmp (pos->name, library_name))) { prev = pos; pos = pos->next; } if (pos == NULL) return NULL; done = resolve_function (pos, "done"); ret = NULL; if (done != NULL) ret = done (arg); if (prev == NULL) plugins = pos->next; else prev->next = pos->next; lt_dlclose (pos->handle); GNUNET_free (pos->name); GNUNET_free (pos); if (plugins == NULL) { plugin_fini (); initialized = GNUNET_NO; } return ret; } struct LoadAllContext { const char *basename; void *arg; GNUNET_PLUGIN_LoaderCallback cb; void *cb_cls; }; static int find_libraries (void *cls, const char *filename) { struct LoadAllContext *lac = cls; const char *slashpos; const char *libname; char *basename; char *dot; void *lib_ret; size_t n; libname = filename; while (NULL != (slashpos = strstr (libname, DIR_SEPARATOR_STR))) libname = slashpos + 1; n = strlen (libname); if (0 != strncmp (lac->basename, libname, strlen (lac->basename))) return GNUNET_OK; /* wrong name */ if ((n > 3) && (0 == strcmp (&libname[n - 3], ".la"))) return GNUNET_OK; /* .la file */ basename = GNUNET_strdup (libname); if (NULL != (dot = strstr (basename, "."))) *dot = '\0'; lib_ret = GNUNET_PLUGIN_load (basename, lac->arg); if (NULL != lib_ret) lac->cb (lac->cb_cls, basename, lib_ret); GNUNET_free (basename); return GNUNET_OK; } /** * Load all compatible plugins with the given base name. * * Note that the library must export symbols called * "basename_ANYTHING_init" and "basename_ANYTHING__done". These will * be called when the library is loaded and unloaded respectively. * * @param basename basename of the plugins to load * @param arg argument to the plugin initialization function * @param cb function to call for each plugin found * @param cb_cls closure for 'cb' */ void GNUNET_PLUGIN_load_all (const char *basename, void *arg, GNUNET_PLUGIN_LoaderCallback cb, void *cb_cls) { struct LoadAllContext lac; char *path; path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR); if (path == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not determine plugin installation path.\n")); return; } lac.basename = basename; lac.arg = arg; lac.cb = cb; lac.cb_cls = cb_cls; GNUNET_DISK_directory_scan (path, &find_libraries, &lac); GNUNET_free (path); } /* end of plugin.c */ gnunet-0.9.3/src/util/common_allocation.c0000644000175000017500000002301311760502550015351 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2005, 2006 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/common_allocation.c * @brief wrapper around malloc/free * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #define LOG(kind,...) GNUNET_log_from (kind, "util",__VA_ARGS__) #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) #ifndef INT_MAX #define INT_MAX 0x7FFFFFFF #endif #if 0 #define W32_MEM_LIMIT 200000000 #endif #ifdef W32_MEM_LIMIT static LONG mem_used = 0; #endif /** * Allocate memory. Checks the return value, aborts if no more * memory is available. * * @param size how many bytes of memory to allocate, do NOT use * this function (or GNUNET_malloc) to allocate more than several MB * of memory, if you are possibly needing a very large chunk use * GNUNET_xmalloc_unchecked_ instead. * @param filename where in the code was the call to GNUNET_malloc * @param linenumber where in the code was the call to GNUNET_malloc * @return pointer to size bytes of memory */ void * GNUNET_xmalloc_ (size_t size, const char *filename, int linenumber) { void *ret; /* As a security precaution, we generally do not allow very large * allocations using the default 'GNUNET_malloc' macro */ GNUNET_assert_at (size <= GNUNET_MAX_MALLOC_CHECKED, filename, linenumber); ret = GNUNET_xmalloc_unchecked_ (size, filename, linenumber); if (ret == NULL) { LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "malloc"); GNUNET_abort (); } return ret; } /** * Allocate and initialize memory. Checks the return value, aborts if no more * memory is available. Don't use GNUNET_xmemdup_ directly. Use the * GNUNET_memdup macro. * * @param buf buffer to initialize from (must contain size bytes) * @param size number of bytes to allocate * @param filename where is this call being made (for debugging) * @param linenumber line where this call is being made (for debugging) * @return allocated memory, never NULL */ void * GNUNET_xmemdup_ (const void *buf, size_t size, const char *filename, int linenumber) { void *ret; /* As a security precaution, we generally do not allow very large * allocations here */ GNUNET_assert_at (size <= GNUNET_MAX_MALLOC_CHECKED, filename, linenumber); #ifdef W32_MEM_LIMIT size += sizeof (size_t); if (mem_used + size > W32_MEM_LIMIT) return NULL; #endif GNUNET_assert_at (size < INT_MAX, filename, linenumber); ret = malloc (size); if (ret == NULL) { LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "malloc"); GNUNET_abort (); } #ifdef W32_MEM_LIMIT *((size_t *) ret) = size; ret = &((size_t *) ret)[1]; mem_used += size; #endif memcpy (ret, buf, size); return ret; } /** * Wrapper around malloc. Allocates size bytes of memory. * The memory will be zero'ed out. * * @param size the number of bytes to allocate * @param filename where in the code was the call to GNUNET_malloc_large * @param linenumber where in the code was the call to GNUNET_malloc_large * @return pointer to size bytes of memory, NULL if we do not have enough memory */ void * GNUNET_xmalloc_unchecked_ (size_t size, const char *filename, int linenumber) { void *result; #ifdef W32_MEM_LIMIT size += sizeof (size_t); if (mem_used + size > W32_MEM_LIMIT) return NULL; #endif result = malloc (size); if (result == NULL) return NULL; memset (result, 0, size); #ifdef W32_MEM_LIMIT *((size_t *) result) = size; result = &((size_t *) result)[1]; mem_used += size; #endif return result; } /** * Reallocate memory. Checks the return value, aborts if no more * memory is available. * * @param ptr the pointer to reallocate * @param n how many bytes of memory to allocate * @param filename where in the code was the call to GNUNET_realloc * @param linenumber where in the code was the call to GNUNET_realloc * @return pointer to size bytes of memory */ void * GNUNET_xrealloc_ (void *ptr, size_t n, const char *filename, int linenumber) { #ifdef W32_MEM_LIMIT n += sizeof (size_t); ptr = &((size_t *) ptr)[-1]; mem_used = mem_used - *((size_t *) ptr) + n; #endif ptr = realloc (ptr, n); if ((NULL == ptr) && (n > 0)) { LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "realloc"); GNUNET_abort (); } #ifdef W32_MEM_LIMIT ptr = &((size_t *) ptr)[1]; #endif return ptr; } /** * Free memory. Merely a wrapper for the case that we * want to keep track of allocations. * * @param ptr the pointer to free * @param filename where in the code was the call to GNUNET_array_grow * @param linenumber where in the code was the call to GNUNET_array_grow */ void GNUNET_xfree_ (void *ptr, const char *filename, int linenumber) { GNUNET_assert_at (ptr != NULL, filename, linenumber); #ifdef W32_MEM_LIMIT ptr = &((size_t *) ptr)[-1]; mem_used -= *((size_t *) ptr); #endif free (ptr); } /** * Dup a string (same semantics as strdup). * * @param str the string to dup * @param filename where in the code was the call to GNUNET_strdup * @param linenumber where in the code was the call to GNUNET_strdup * @return strdup(str) */ char * GNUNET_xstrdup_ (const char *str, const char *filename, int linenumber) { char *res; GNUNET_assert_at (str != NULL, filename, linenumber); res = GNUNET_xmalloc_ (strlen (str) + 1, filename, linenumber); memcpy (res, str, strlen (str) + 1); return res; } /** * Dup partially a string (same semantics as strndup). * * @param str the string to dup * @param len the length of the string to dup * @param filename where in the code was the call to GNUNET_strndup * @param linenumber where in the code was the call to GNUNET_strndup * @return strndup(str,len) */ char * GNUNET_xstrndup_ (const char *str, size_t len, const char *filename, int linenumber) { char *res; GNUNET_assert_at (str != NULL, filename, linenumber); len = GNUNET_MIN (len, strlen (str)); res = GNUNET_xmalloc_ (len + 1, filename, linenumber); memcpy (res, str, len); res[len] = '\0'; return res; } /** * Grow an array. Grows old by (*oldCount-newCount)*elementSize bytes * and sets *oldCount to newCount. * * @param old address of the pointer to the array * *old may be NULL * @param elementSize the size of the elements of the array * @param oldCount address of the number of elements in the *old array * @param newCount number of elements in the new array, may be 0 * @param filename where in the code was the call to GNUNET_array_grow * @param linenumber where in the code was the call to GNUNET_array_grow */ void GNUNET_xgrow_ (void **old, size_t elementSize, unsigned int *oldCount, unsigned int newCount, const char *filename, int linenumber) { void *tmp; size_t size; GNUNET_assert_at (INT_MAX / elementSize > newCount, filename, linenumber); size = newCount * elementSize; if (size == 0) { tmp = NULL; } else { tmp = GNUNET_xmalloc_ (size, filename, linenumber); memset (tmp, 0, size); /* client code should not rely on this, though... */ if (*oldCount > newCount) *oldCount = newCount; /* shrink is also allowed! */ memcpy (tmp, *old, elementSize * (*oldCount)); } if (*old != NULL) { GNUNET_xfree_ (*old, filename, linenumber); } *old = tmp; *oldCount = newCount; } /** * Like asprintf, just portable. * * @param buf set to a buffer of sufficient size (allocated, caller must free) * @param format format string (see printf, fprintf, etc.) * @param ... data for format string * @return number of bytes in "*buf" excluding 0-termination */ int GNUNET_asprintf (char **buf, const char *format, ...) { int ret; va_list args; va_start (args, format); ret = VSNPRINTF (NULL, 0, format, args); va_end (args); *buf = GNUNET_malloc (ret + 1); va_start (args, format); ret = VSPRINTF (*buf, format, args); va_end (args); return ret; } /** * Like snprintf, just aborts if the buffer is of insufficient size. * * @param buf pointer to buffer that is written to * @param size number of bytes in buf * @param format format strings * @param ... data for format string * @return number of bytes written to buf or negative value on error */ int GNUNET_snprintf (char *buf, size_t size, const char *format, ...) { int ret; va_list args; va_start (args, format); ret = VSNPRINTF (buf, size, format, args); va_end (args); GNUNET_assert (ret <= size); return ret; } /** * Create a copy of the given message. * * @param msg message to copy * @return duplicate of the message */ struct GNUNET_MessageHeader * GNUNET_copy_message (const struct GNUNET_MessageHeader *msg) { struct GNUNET_MessageHeader *ret; uint16_t msize; msize = ntohs (msg->size); GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader)); ret = GNUNET_malloc (msize); memcpy (ret, msg, msize); return ret; } /* end of common_allocation.c */ gnunet-0.9.3/src/util/container_multihashmap.c0000644000175000017500000002653711760502550016430 00000000000000/* This file is part of GNUnet. (C) 2008 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/container_multihashmap.c * @brief hash map where the same key may be present multiple times * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_container_lib.h" #include "gnunet_crypto_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) /** * An entry in the hash map. */ struct MapEntry { /** * Key for the entry. */ GNUNET_HashCode key; /** * Value of the entry. */ void *value; /** * If there is a hash collision, we create a linked list. */ struct MapEntry *next; }; /** * Internal representation of the hash map. */ struct GNUNET_CONTAINER_MultiHashMap { /** * All of our buckets. */ struct MapEntry **map; /** * Number of entries in the map. */ unsigned int size; /** * Length of the "map" array. */ unsigned int map_length; }; /** * Create a multi hash map. * * @param len initial size (map will grow as needed) * @return NULL on error */ struct GNUNET_CONTAINER_MultiHashMap * GNUNET_CONTAINER_multihashmap_create (unsigned int len) { struct GNUNET_CONTAINER_MultiHashMap *ret; GNUNET_assert (len > 0); ret = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_MultiHashMap)); ret->map = GNUNET_malloc (len * sizeof (struct MapEntry *)); ret->map_length = len; return ret; } /** * Destroy a hash map. Will not free any values * stored in the hash map! * * @param map the map */ void GNUNET_CONTAINER_multihashmap_destroy (struct GNUNET_CONTAINER_MultiHashMap *map) { unsigned int i; struct MapEntry *e; for (i = 0; i < map->map_length; i++) { while (NULL != (e = map->map[i])) { map->map[i] = e->next; GNUNET_free (e); } } GNUNET_free (map->map); GNUNET_free (map); } /** * Compute the index of the bucket for the given key. * * @param m hash map for which to compute the index * @param key what key should the index be computed for * @return offset into the "map" array of "m" */ static unsigned int idx_of (const struct GNUNET_CONTAINER_MultiHashMap *m, const GNUNET_HashCode * key) { GNUNET_assert (m != NULL); return (*(unsigned int *) key) % m->map_length; } /** * Get the number of key-value pairs in the map. * * @param map the map * @return the number of key value pairs */ unsigned int GNUNET_CONTAINER_multihashmap_size (const struct GNUNET_CONTAINER_MultiHashMap *map) { return map->size; } /** * Given a key find a value in the map matching the key. * * @param map the map * @param key what to look for * @return NULL if no value was found; note that * this is indistinguishable from values that just * happen to be NULL; use "contains" to test for * key-value pairs with value NULL */ void * GNUNET_CONTAINER_multihashmap_get (const struct GNUNET_CONTAINER_MultiHashMap *map, const GNUNET_HashCode * key) { struct MapEntry *e; e = map->map[idx_of (map, key)]; while (e != NULL) { if (0 == memcmp (key, &e->key, sizeof (GNUNET_HashCode))) return e->value; e = e->next; } return NULL; } /** * Iterate over all entries in the map. * * @param map the map * @param it function to call on each entry * @param it_cls extra argument to it * @return the number of key value pairs processed, * GNUNET_SYSERR if it aborted iteration */ int GNUNET_CONTAINER_multihashmap_iterate (const struct GNUNET_CONTAINER_MultiHashMap *map, GNUNET_CONTAINER_HashMapIterator it, void *it_cls) { int count; unsigned int i; struct MapEntry *e; struct MapEntry *n; GNUNET_HashCode kc; count = 0; GNUNET_assert (map != NULL); for (i = 0; i < map->map_length; i++) { n = map->map[i]; while (NULL != (e = n)) { n = e->next; if (NULL != it) { kc = e->key; if (GNUNET_OK != it (it_cls, &kc, e->value)) return GNUNET_SYSERR; } count++; } } return count; } /** * Remove the given key-value pair from the map. Note that if the * key-value pair is in the map multiple times, only one of the pairs * will be removed. * * @param map the map * @param key key of the key-value pair * @param value value of the key-value pair * @return GNUNET_YES on success, GNUNET_NO if the key-value pair * is not in the map */ int GNUNET_CONTAINER_multihashmap_remove (struct GNUNET_CONTAINER_MultiHashMap *map, const GNUNET_HashCode * key, void *value) { struct MapEntry *e; struct MapEntry *p; unsigned int i; i = idx_of (map, key); p = NULL; e = map->map[i]; while (e != NULL) { if ((0 == memcmp (key, &e->key, sizeof (GNUNET_HashCode))) && (value == e->value)) { if (p == NULL) map->map[i] = e->next; else p->next = e->next; GNUNET_free (e); map->size--; return GNUNET_YES; } p = e; e = e->next; } return GNUNET_NO; } /** * Remove all entries for the given key from the map. * Note that the values would not be "freed". * * @param map the map * @param key identifies values to be removed * @return number of values removed */ int GNUNET_CONTAINER_multihashmap_remove_all (struct GNUNET_CONTAINER_MultiHashMap *map, const GNUNET_HashCode * key) { struct MapEntry *e; struct MapEntry *p; unsigned int i; int ret; ret = 0; i = idx_of (map, key); p = NULL; e = map->map[i]; while (e != NULL) { if (0 == memcmp (key, &e->key, sizeof (GNUNET_HashCode))) { if (p == NULL) map->map[i] = e->next; else p->next = e->next; GNUNET_free (e); map->size--; if (p == NULL) e = map->map[i]; else e = p->next; ret++; } else { p = e; e = e->next; } } return ret; } /** * Check if the map contains any value under the given * key (including values that are NULL). * * @param map the map * @param key the key to test if a value exists for it * @return GNUNET_YES if such a value exists, * GNUNET_NO if not */ int GNUNET_CONTAINER_multihashmap_contains (const struct GNUNET_CONTAINER_MultiHashMap *map, const GNUNET_HashCode * key) { struct MapEntry *e; e = map->map[idx_of (map, key)]; while (e != NULL) { if (0 == memcmp (key, &e->key, sizeof (GNUNET_HashCode))) return GNUNET_YES; e = e->next; } return GNUNET_NO; } /** * Check if the map contains the given value under the given * key. * * @param map the map * @param key the key to test if a value exists for it * @param value value to test for * @return GNUNET_YES if such a value exists, * GNUNET_NO if not */ int GNUNET_CONTAINER_multihashmap_contains_value (const struct GNUNET_CONTAINER_MultiHashMap *map, const GNUNET_HashCode * key, const void *value) { struct MapEntry *e; e = map->map[idx_of (map, key)]; while (e != NULL) { if ((0 == memcmp (key, &e->key, sizeof (GNUNET_HashCode))) && (e->value == value)) return GNUNET_YES; e = e->next; } return GNUNET_NO; } /** * Grow the given map to a more appropriate size. * * @param map the hash map to grow */ static void grow (struct GNUNET_CONTAINER_MultiHashMap *map) { struct MapEntry **old_map; struct MapEntry **new_map; struct MapEntry *e; unsigned int old_len; unsigned int new_len; unsigned int idx; unsigned int i; old_map = map->map; old_len = map->map_length; new_len = old_len * 2; new_map = GNUNET_malloc (sizeof (struct MapEntry *) * new_len); map->map_length = new_len; map->map = new_map; for (i = 0; i < old_len; i++) { while (NULL != (e = old_map[i])) { old_map[i] = e->next; idx = idx_of (map, &e->key); e->next = new_map[idx]; new_map[idx] = e; } } GNUNET_free (old_map); } /** * Store a key-value pair in the map. * * @param map the map * @param key key to use * @param value value to use * @param opt options for put * @return GNUNET_OK on success, * GNUNET_NO if a value was replaced (with REPLACE) * GNUNET_SYSERR if UNIQUE_ONLY was the option and the * value already exists */ int GNUNET_CONTAINER_multihashmap_put (struct GNUNET_CONTAINER_MultiHashMap *map, const GNUNET_HashCode * key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt) { struct MapEntry *e; unsigned int i; i = idx_of (map, key); if ((opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE) && (opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) { e = map->map[i]; while (e != NULL) { if (0 == memcmp (key, &e->key, sizeof (GNUNET_HashCode))) { if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) return GNUNET_SYSERR; e->value = value; return GNUNET_NO; } e = e->next; } } if (map->size / 3 >= map->map_length / 4) { grow (map); i = idx_of (map, key); } e = GNUNET_malloc (sizeof (struct MapEntry)); e->key = *key; e->value = value; e->next = map->map[i]; map->map[i] = e; map->size++; return GNUNET_OK; } /** * Iterate over all entries in the map that match a particular key. * * @param map the map * @param key key that the entries must correspond to * @param it function to call on each entry * @param it_cls extra argument to it * @return the number of key value pairs processed, * GNUNET_SYSERR if it aborted iteration */ int GNUNET_CONTAINER_multihashmap_get_multiple (const struct GNUNET_CONTAINER_MultiHashMap *map, const GNUNET_HashCode * key, GNUNET_CONTAINER_HashMapIterator it, void *it_cls) { int count; struct MapEntry *e; struct MapEntry *n; count = 0; n = map->map[idx_of (map, key)]; while (NULL != (e = n)) { n = e->next; if (0 != memcmp (key, &e->key, sizeof (GNUNET_HashCode))) continue; if ((it != NULL) && (GNUNET_OK != it (it_cls, key, e->value))) return GNUNET_SYSERR; count++; } return count; } /* end of container_multihashmap.c */ gnunet-0.9.3/src/util/crypto_crc.c0000644000175000017500000001062511760502550014030 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2006 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. For the actual CRC-32 code: Copyright abandoned; this code is in the public domain. Provided to GNUnet by peter@horizon.com */ /** * @file util/crypto_crc.c * @brief implementation of CRC16 and CRC32 * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_crypto_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) /* Avoid wasting space on 8-byte longs. */ #if UINT_MAX >= 0xffffffff typedef unsigned int uLong; #elif ULONG_MAX >= 0xffffffff typedef unsigned long uLong; #else #error This compiler is not ANSI-compliant! #endif #define Z_NULL 0 #define POLYNOMIAL (uLong)0xedb88320 static uLong crc_table[256]; /* * This routine writes each crc_table entry exactly once, * with the ccorrect final value. Thus, it is safe to call * even on a table that someone else is using concurrently. */ static void crc_init () { static int once; unsigned int i, j; uLong h = 1; if (once) return; once = 1; crc_table[0] = 0; for (i = 128; i; i >>= 1) { h = (h >> 1) ^ ((h & 1) ? POLYNOMIAL : 0); /* h is now crc_table[i] */ for (j = 0; j < 256; j += 2 * i) crc_table[i + j] = crc_table[j] ^ h; } } /* * This computes the standard preset and inverted CRC, as used * by most networking standards. Start by passing in an initial * chaining value of 0, and then pass in the return value from the * previous crc32() call. The final return value is the CRC. * Note that this is a little-endian CRC, which is best used with * data transmitted lsbit-first, and it should, itself, be appended * to data in little-endian byte and bit order to preserve the * property of detecting all burst errors of length 32 bits or less. */ static uLong crc32 (uLong crc, const char *buf, size_t len) { crc_init (); GNUNET_assert (crc_table[255] != 0); crc ^= 0xffffffff; while (len--) crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; return crc ^ 0xffffffff; } /** * Compute the CRC32 checksum for the first len bytes of the buffer. * * @param buf the data over which we're taking the CRC * @param len the length of the buffer * @return the resulting CRC32 checksum */ int32_t GNUNET_CRYPTO_crc32_n (const void *buf, size_t len) { uLong crc; crc = crc32 (0L, Z_NULL, 0); crc = crc32 (crc, (char *) buf, len); return crc; } /** * Perform an incremental step in a CRC16 (for TCP/IP) calculation. * * @param sum current sum, initially 0 * @param buf buffer to calculate CRC over (must be 16-bit aligned) * @param len number of bytes in hdr, must be multiple of 2 * @return updated crc sum (must be subjected to GNUNET_CRYPTO_crc16_finish to get actual crc16) */ uint32_t GNUNET_CRYPTO_crc16_step (uint32_t sum, const void *buf, size_t len) { const uint16_t *hdr = buf; for (; len >= 2; len -= 2) sum += *(hdr++); if (len == 1) sum += (*hdr) & ntohs(0xFF00); return sum; } /** * Convert results from GNUNET_CRYPTO_crc16_step to final crc16. * * @param sum cummulative sum * @return crc16 value */ uint16_t GNUNET_CRYPTO_crc16_finish (uint32_t sum) { sum = (sum >> 16) + (sum & 0xFFFF); sum += (sum >> 16); return ~sum; } /** * Calculate the checksum of a buffer in one step. * * @param buf buffer to calculate CRC over (must be 16-bit aligned) * @param len number of bytes in hdr, must be multiple of 2 * @return crc16 value */ uint16_t GNUNET_CRYPTO_crc16_n (const void *buf, size_t len) { const uint16_t *hdr = buf; uint32_t sum = GNUNET_CRYPTO_crc16_step (0, hdr, len); return GNUNET_CRYPTO_crc16_finish (sum); } /* end of crypto_crc.c */ gnunet-0.9.3/src/util/test_plugin.c0000644000175000017500000000377411760502550014225 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_plugin.c * @brief testcase for plugin.c */ #include "platform.h" #include "gnunet_plugin_lib.h" #define VERBOSE GNUNET_NO static void test_cb (void *cls, const char *libname, void *lib_ret) { void *ret; GNUNET_assert (0 == strcmp (cls, "test")); GNUNET_assert (0 == strcmp (lib_ret, "Hello")); ret = GNUNET_PLUGIN_unload (libname, "out"); GNUNET_assert (NULL != ret); GNUNET_assert (0 == strcmp (ret, "World")); } static int check () { void *ret; GNUNET_log_skip (1, GNUNET_NO); ret = GNUNET_PLUGIN_load ("libgnunet_plugin_missing", NULL); GNUNET_log_skip (0, GNUNET_NO); if (ret != NULL) return 1; ret = GNUNET_PLUGIN_load ("libgnunet_plugin_test", "in"); if (ret == NULL) return 1; if (0 != strcmp (ret, "Hello")) return 2; ret = GNUNET_PLUGIN_unload ("libgnunet_plugin_test", "out"); if (ret == NULL) return 3; if (0 != strcmp (ret, "World")) return 4; free (ret); GNUNET_PLUGIN_load_all ("libgnunet_plugin_tes", "in", &test_cb, "test"); return 0; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-plugin", "WARNING", NULL); ret = check (); return ret; } /* end of test_plugin.c */ gnunet-0.9.3/src/util/test_program.c0000644000175000017500000000663411760502550014374 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_program.c * @brief tests for program.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" static int setme1, setme2; static struct GNUNET_GETOPT_CommandLineOption options1[] = { {'n', "name", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme1}, GNUNET_GETOPT_OPTION_END }; static struct GNUNET_GETOPT_CommandLineOption options2[] = { {'n', "name", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme1}, {'N', "number", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme2}, GNUNET_GETOPT_OPTION_END }; static struct GNUNET_GETOPT_CommandLineOption options3[] = { {'N', "number", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme1}, {'n', "name", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme2}, GNUNET_GETOPT_OPTION_END }; static struct GNUNET_GETOPT_CommandLineOption options4[] = { {'n', "name", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme1}, {'n', "number", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme2}, GNUNET_GETOPT_OPTION_END }; /** * Main function that will be run. */ static void runner (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { int *ok = cls; GNUNET_assert (setme1 == 1); GNUNET_assert (0 == strcmp (args[0], "extra")); GNUNET_assert (args[1] == NULL); GNUNET_assert (0 == strcmp (cfgfile, "test_program_data.conf")); *ok = 0; } /** * Main method, starts scheduler with task1, * checks that "ok" is correct at the end. */ static int check () { int ok = 1; char *const argv[] = { "test_program", "-c", "test_program_data.conf", "-L", "WARNING", "-n", "extra", NULL }; GNUNET_assert (GNUNET_OK == GNUNET_PROGRAM_run (7, argv, "test_program", "A test", options1, &runner, &ok)); GNUNET_assert (GNUNET_OK == GNUNET_PROGRAM_run (7, argv, "test_program", "A test", options2, &runner, &ok)); GNUNET_assert (GNUNET_OK == GNUNET_PROGRAM_run (7, argv, "test_program", "A test", options3, &runner, &ok)); GNUNET_assert (GNUNET_OK == GNUNET_PROGRAM_run (7, argv, "test_program", "A test", options4, &runner, &ok)); return ok; } int main (int argc, char *argv[]) { int ret = 0; GNUNET_log_setup ("test_program", "WARNING", NULL); ret += check (); return ret; } /* end of test_program.c */ gnunet-0.9.3/src/util/crypto_aes.c0000644000175000017500000001411311760502550014025 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/crypto_aes.c * @brief Symmetric encryption services. * @author Christian Grothoff * @author Ioana Patrascu */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_crypto_lib.h" #include #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) /** * Create a new SessionKey (for AES-256). * * @param key session key to initialize */ void GNUNET_CRYPTO_aes_create_session_key (struct GNUNET_CRYPTO_AesSessionKey *key) { gcry_randomize (&key->key[0], GNUNET_CRYPTO_AES_KEY_LENGTH, GCRY_STRONG_RANDOM); key->crc32 = htonl (GNUNET_CRYPTO_crc32_n (key, GNUNET_CRYPTO_AES_KEY_LENGTH)); } /** * Check that a new session key is well-formed. * * @return GNUNET_OK if the key is valid */ int GNUNET_CRYPTO_aes_check_session_key (const struct GNUNET_CRYPTO_AesSessionKey *key) { uint32_t crc; crc = GNUNET_CRYPTO_crc32_n (key, GNUNET_CRYPTO_AES_KEY_LENGTH); if (ntohl (key->crc32) != crc) { GNUNET_break_op (0); return GNUNET_SYSERR; } return GNUNET_OK; } /** * Initialize AES cipher. * * @param handle handle to initialize * @param sessionkey session key to use * @param iv initialization vector to use * @return GNUNET_OK on success, GNUNET_SYSERR on error */ static int setup_cipher (gcry_cipher_hd_t *handle, const struct GNUNET_CRYPTO_AesSessionKey * sessionkey, const struct GNUNET_CRYPTO_AesInitializationVector * iv) { int rc; if (GNUNET_OK != GNUNET_CRYPTO_aes_check_session_key (sessionkey)) { GNUNET_break (0); return GNUNET_SYSERR; } GNUNET_assert (0 == gcry_cipher_open (handle, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CFB, 0)); rc = gcry_cipher_setkey (*handle, sessionkey, GNUNET_CRYPTO_AES_KEY_LENGTH); GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY)); rc = gcry_cipher_setiv (*handle, iv, sizeof (struct GNUNET_CRYPTO_AesInitializationVector)); GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY)); return GNUNET_OK; } /** * Encrypt a block with the public key of another * host that uses the same cyper. * * @param block the block to encrypt * @param len the size of the block * @param sessionkey the key used to encrypt * @param iv the initialization vector to use, use INITVALUE * for streams. * @param result the output parameter in which to store the encrypted result * @returns the size of the encrypted block, -1 for errors */ ssize_t GNUNET_CRYPTO_aes_encrypt (const void *block, size_t len, const struct GNUNET_CRYPTO_AesSessionKey * sessionkey, const struct GNUNET_CRYPTO_AesInitializationVector * iv, void *result) { gcry_cipher_hd_t handle; if (GNUNET_OK != setup_cipher (&handle, sessionkey, iv)) return -1; GNUNET_assert (0 == gcry_cipher_encrypt (handle, result, len, block, len)); gcry_cipher_close (handle); return len; } /** * Decrypt a given block with the sessionkey. * * @param block the data to decrypt, encoded as returned by encrypt * @param size the size of the block to decrypt * @param sessionkey the key used to decrypt * @param iv the initialization vector to use, use INITVALUE * for streams. * @param result address to store the result at * @return -1 on failure, size of decrypted block on success */ ssize_t GNUNET_CRYPTO_aes_decrypt (const void *block, size_t size, const struct GNUNET_CRYPTO_AesSessionKey * sessionkey, const struct GNUNET_CRYPTO_AesInitializationVector * iv, void *result) { gcry_cipher_hd_t handle; if (GNUNET_OK != setup_cipher (&handle, sessionkey, iv)) return -1; GNUNET_assert (0 == gcry_cipher_decrypt (handle, result, size, block, size)); gcry_cipher_close (handle); return size; } /** * @brief Derive an IV * * @param iv initialization vector * @param skey session key * @param salt salt for the derivation * @param salt_len size of the salt * @param ... pairs of void * & size_t for context chunks, terminated by NULL */ void GNUNET_CRYPTO_aes_derive_iv (struct GNUNET_CRYPTO_AesInitializationVector *iv, const struct GNUNET_CRYPTO_AesSessionKey *skey, const void *salt, size_t salt_len, ...) { va_list argp; va_start (argp, salt_len); GNUNET_CRYPTO_aes_derive_iv_v (iv, skey, salt, salt_len, argp); va_end (argp); } /** * @brief Derive an IV * * @param iv initialization vector * @param skey session key * @param salt salt for the derivation * @param salt_len size of the salt * @param argp pairs of void * & size_t for context chunks, terminated by NULL */ void GNUNET_CRYPTO_aes_derive_iv_v (struct GNUNET_CRYPTO_AesInitializationVector *iv, const struct GNUNET_CRYPTO_AesSessionKey *skey, const void *salt, size_t salt_len, va_list argp) { GNUNET_CRYPTO_kdf_v (iv->iv, sizeof (iv->iv), salt, salt_len, skey->key, sizeof (skey->key), argp); } /* end of crypto_aes.c */ gnunet-0.9.3/src/util/test_server.c0000644000175000017500000001472011760502550014226 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_server.c * @brief tests for server.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_client_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_server_lib.h" #include "gnunet_time_lib.h" #define VERBOSE GNUNET_NO #define PORT 12435 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2) #define MY_TYPE 128 #define MY_TYPE2 129 static struct GNUNET_SERVER_Handle *server; static struct GNUNET_CLIENT_Connection *cc; static struct GNUNET_SERVER_Client *argclient; static struct GNUNET_CONFIGURATION_Handle *cfg; static int ok; static void finish_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_assert (ok == 6); ok = 0; GNUNET_SERVER_destroy (server); GNUNET_CLIENT_disconnect (cc); GNUNET_CONFIGURATION_destroy (cfg); } static void recv_fin_cb (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { GNUNET_assert (ok == 5); ok = 6; GNUNET_SERVER_receive_done (client, GNUNET_OK); GNUNET_SCHEDULER_add_now (&finish_up, NULL); } static void first_reply_handler (void *cls, const struct GNUNET_MessageHeader *msg) { GNUNET_assert (ok == 4); ok = 5; GNUNET_SERVER_receive_done (argclient, GNUNET_OK); GNUNET_SERVER_client_drop (argclient); argclient = NULL; } static size_t reply_msg (void *cls, size_t size, void *buf) { struct GNUNET_MessageHeader msg; GNUNET_assert (ok == 3); ok = 4; GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); msg.type = htons (MY_TYPE); msg.size = htons (sizeof (struct GNUNET_MessageHeader)); memcpy (buf, &msg, sizeof (struct GNUNET_MessageHeader)); return sizeof (struct GNUNET_MessageHeader); } static void recv_cb (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { GNUNET_assert (ok == 2); ok = 3; argclient = client; GNUNET_SERVER_client_keep (argclient); GNUNET_assert (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size)); GNUNET_assert (MY_TYPE == ntohs (message->type)); GNUNET_assert (NULL != GNUNET_SERVER_notify_transmit_ready (client, ntohs (message->size), TIMEOUT, &reply_msg, NULL)); } static struct GNUNET_SERVER_MessageHandler handlers[] = { {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)}, {&recv_fin_cb, NULL, MY_TYPE2, sizeof (struct GNUNET_MessageHeader)}, {NULL, NULL, 0, 0} }; static size_t transmit_second_message (void *cls, size_t size, void *buf) { struct GNUNET_MessageHeader msg; GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); msg.type = htons (MY_TYPE2); msg.size = htons (sizeof (struct GNUNET_MessageHeader)); memcpy (buf, &msg, sizeof (struct GNUNET_MessageHeader)); return sizeof (struct GNUNET_MessageHeader); } static size_t transmit_initial_message (void *cls, size_t size, void *buf) { struct GNUNET_MessageHeader msg; GNUNET_assert (ok == 1); ok = 2; GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); msg.type = htons (MY_TYPE); msg.size = htons (sizeof (struct GNUNET_MessageHeader)); memcpy (buf, &msg, sizeof (struct GNUNET_MessageHeader)); GNUNET_assert (NULL != GNUNET_CLIENT_notify_transmit_ready (cc, sizeof (struct GNUNET_MessageHeader), TIMEOUT, GNUNET_YES, &transmit_second_message, NULL)); GNUNET_CLIENT_receive (cc, &first_reply_handler, NULL, TIMEOUT); return sizeof (struct GNUNET_MessageHeader); } static void task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct sockaddr_in sa; struct sockaddr *sap[2]; socklen_t slens[2]; sap[0] = (struct sockaddr *) &sa; slens[0] = sizeof (sa); sap[1] = NULL; slens[1] = 0; memset (&sa, 0, sizeof (sa)); #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = sizeof (sa); #endif sa.sin_family = AF_INET; sa.sin_port = htons (PORT); server = GNUNET_SERVER_create (NULL, NULL, sap, slens, TIMEOUT, GNUNET_NO); GNUNET_assert (server != NULL); GNUNET_SERVER_add_handlers (server, handlers); cfg = GNUNET_CONFIGURATION_create (); GNUNET_CONFIGURATION_set_value_number (cfg, "test-server", "PORT", PORT); GNUNET_CONFIGURATION_set_value_string (cfg, "test-server", "HOSTNAME", "localhost"); GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", "localhost"); cc = GNUNET_CLIENT_connect ("test-server", cfg); GNUNET_assert (cc != NULL); GNUNET_assert (NULL != GNUNET_CLIENT_notify_transmit_ready (cc, sizeof (struct GNUNET_MessageHeader), TIMEOUT, GNUNET_YES, &transmit_initial_message, NULL)); } /** * Main method, starts scheduler with task1, * checks that "ok" is correct at the end. */ static int check () { ok = 1; GNUNET_SCHEDULER_run (&task, &ok); return ok; } int main (int argc, char *argv[]) { int ret = 0; GNUNET_log_setup ("test_server", "WARNING", NULL); ret += check (); return ret; } /* end of test_server.c */ gnunet-0.9.3/src/util/test_pseudonym.c0000644000175000017500000001635411760502550014750 00000000000000/* This file is part of GNUnet. (C) 2005, 2006, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_pseudonym.c * @brief testcase for pseudonym.c * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_container_lib.h" #include "gnunet_crypto_lib.h" #include "gnunet_disk_lib.h" #include "gnunet_pseudonym_lib.h" #define CHECK(a) do { if (!(a)) { ok = GNUNET_NO; GNUNET_break(0); goto FAILURE; } } while (0) static struct GNUNET_CONTAINER_MetaData *meta; static GNUNET_HashCode id1; static int iter (void *cls, const GNUNET_HashCode * pseudonym, const char *name, const char *unique_name, const struct GNUNET_CONTAINER_MetaData *md, int rating) { int *ok = cls; if ((0 == memcmp (pseudonym, &id1, sizeof (GNUNET_HashCode))) && (!GNUNET_CONTAINER_meta_data_test_equal (md, meta))) { *ok = GNUNET_NO; GNUNET_break (0); } return GNUNET_OK; } static int noti_callback (void *cls, const GNUNET_HashCode * pseudonym, const char *name, const char *unique_name, const struct GNUNET_CONTAINER_MetaData *md, int rating) { int *ret = cls; (*ret)++; return GNUNET_OK; } static int fake_noti_callback (void *cls, const GNUNET_HashCode * pseudonym, const char *name, const char *unique_name, const struct GNUNET_CONTAINER_MetaData *md, int rating) { int *ret = cls; (*ret)++; return GNUNET_OK; } static int false_callback (void *cls, const GNUNET_HashCode * pseudonym, const char *name, const char *unique_name, const struct GNUNET_CONTAINER_MetaData *md, int rating) { return GNUNET_OK; } int main (int argc, char *argv[]) { int ok; GNUNET_HashCode rid1; GNUNET_HashCode id2; GNUNET_HashCode rid2; GNUNET_HashCode fid; GNUNET_HashCode id3; int old; int newVal; struct GNUNET_CONFIGURATION_Handle *cfg; char *name1; char *name2; char *name3; char *name1_unique; char *name2_unique; char *noname; int noname_is_a_dup; int notiCount, fakenotiCount; int count; static char m[1024 * 1024 * 10]; memset (m, 'b', sizeof (m)); m[sizeof (m) - 1] = '\0'; GNUNET_log_setup ("test-pseudonym", "WARNING", NULL); ok = GNUNET_YES; GNUNET_CRYPTO_random_disable_entropy_gathering (); (void) GNUNET_DISK_directory_remove ("/tmp/gnunet-pseudonym-test"); cfg = GNUNET_CONFIGURATION_create (); if (-1 == GNUNET_CONFIGURATION_parse (cfg, "test_pseudonym_data.conf")) { GNUNET_CONFIGURATION_destroy (cfg); GNUNET_break (0); return -1; } notiCount = 0; fakenotiCount = 0; count = 0; GNUNET_PSEUDONYM_discovery_callback_register (cfg, &fake_noti_callback, &fakenotiCount); GNUNET_PSEUDONYM_discovery_callback_register (cfg, ¬i_callback, ¬iCount); GNUNET_PSEUDONYM_discovery_callback_unregister (&false_callback, &count); GNUNET_PSEUDONYM_discovery_callback_unregister (&fake_noti_callback, &fakenotiCount); /* ACTUAL TEST CODE */ old = GNUNET_PSEUDONYM_list_all (cfg, NULL, NULL); meta = GNUNET_CONTAINER_meta_data_create (); GNUNET_CONTAINER_meta_data_insert (meta, "", EXTRACTOR_METATYPE_TITLE, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "test", strlen ("test") + 1); GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &id1); GNUNET_PSEUDONYM_add (cfg, &id1, meta); CHECK (notiCount == 1); GNUNET_PSEUDONYM_add (cfg, &id1, meta); CHECK (notiCount == 2); newVal = GNUNET_PSEUDONYM_list_all (cfg, &iter, &ok); CHECK (old < newVal); old = newVal; GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &id2); GNUNET_PSEUDONYM_add (cfg, &id2, meta); CHECK (notiCount == 3); newVal = GNUNET_PSEUDONYM_list_all (cfg, &iter, &ok); CHECK (old < newVal); GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_meta_data_insert (meta, "", EXTRACTOR_METATYPE_COMMENT, EXTRACTOR_METAFORMAT_UTF8, "text/plain", m, strlen (m) + 1)); GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &id3); GNUNET_PSEUDONYM_add (cfg, &id3, meta); GNUNET_PSEUDONYM_get_info (cfg, &id3, NULL, NULL, &name3, NULL); CHECK (name3 != NULL); GNUNET_PSEUDONYM_get_info (cfg, &id2, NULL, NULL, &name2, NULL); CHECK (name2 != NULL); GNUNET_PSEUDONYM_get_info (cfg, &id1, NULL, NULL, &name1, NULL); CHECK (name1 != NULL); CHECK (0 == strcmp (name1, name2)); name1_unique = GNUNET_PSEUDONYM_name_uniquify (cfg, &id1, name1, NULL); name2_unique = GNUNET_PSEUDONYM_name_uniquify (cfg, &id2, name2, NULL); CHECK (0 != strcmp (name1_unique, name2_unique)); CHECK (GNUNET_SYSERR == GNUNET_PSEUDONYM_name_to_id (cfg, "fake", &rid2)); CHECK (GNUNET_SYSERR == GNUNET_PSEUDONYM_name_to_id (cfg, name2, &rid2)); CHECK (GNUNET_SYSERR == GNUNET_PSEUDONYM_name_to_id (cfg, name1, &rid1)); CHECK (GNUNET_OK == GNUNET_PSEUDONYM_name_to_id (cfg, name2_unique, &rid2)); CHECK (GNUNET_OK == GNUNET_PSEUDONYM_name_to_id (cfg, name1_unique, &rid1)); CHECK (0 == memcmp (&id1, &rid1, sizeof (GNUNET_HashCode))); CHECK (0 == memcmp (&id2, &rid2, sizeof (GNUNET_HashCode))); GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &fid); GNUNET_log_skip (1, GNUNET_NO); CHECK (0 == GNUNET_PSEUDONYM_rank (cfg, &fid, 0)); GNUNET_log_skip (0, GNUNET_YES); CHECK (GNUNET_OK == GNUNET_PSEUDONYM_get_info (cfg, &fid, NULL, NULL, &noname, &noname_is_a_dup)); CHECK (noname != NULL); CHECK (noname_is_a_dup == GNUNET_YES); CHECK (0 == GNUNET_PSEUDONYM_rank (cfg, &id1, 0)); CHECK (5 == GNUNET_PSEUDONYM_rank (cfg, &id1, 5)); CHECK (-5 == GNUNET_PSEUDONYM_rank (cfg, &id1, -10)); CHECK (0 == GNUNET_PSEUDONYM_rank (cfg, &id1, 5)); GNUNET_free (name1); GNUNET_free (name2); GNUNET_free (name1_unique); GNUNET_free (name2_unique); GNUNET_free (name3); GNUNET_free (noname); /* END OF TEST CODE */ FAILURE: GNUNET_PSEUDONYM_discovery_callback_unregister (¬i_callback, ¬iCount); GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_CONFIGURATION_destroy (cfg); GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove ("/tmp/gnunet-pseudonym-test")); return (ok == GNUNET_YES) ? 0 : 1; } /* end of test_pseudoynm.c */ gnunet-0.9.3/src/util/bandwidth.c0000644000175000017500000002403711760502550013627 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/bandwidth.c * @brief functions related to bandwidth (unit) * @author Christian Grothoff */ #include "platform.h" #include "gnunet_bandwidth_lib.h" #include "gnunet_server_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util-bandwidth", __VA_ARGS__) /** * Create a new bandwidth value. * * @param bytes_per_second value to create * @return the new bandwidth value */ struct GNUNET_BANDWIDTH_Value32NBO GNUNET_BANDWIDTH_value_init (uint32_t bytes_per_second) { struct GNUNET_BANDWIDTH_Value32NBO ret; LOG (GNUNET_ERROR_TYPE_DEBUG, "Initializing bandwidth of %u Bps\n", (unsigned int) bytes_per_second); ret.value__ = htonl (bytes_per_second); return ret; } /** * Compute the MIN of two bandwidth values. * * @param b1 first value * @param b2 second value * @return the min of b1 and b2 */ struct GNUNET_BANDWIDTH_Value32NBO GNUNET_BANDWIDTH_value_min (struct GNUNET_BANDWIDTH_Value32NBO b1, struct GNUNET_BANDWIDTH_Value32NBO b2) { return GNUNET_BANDWIDTH_value_init (GNUNET_MIN (ntohl (b1.value__), ntohl (b2.value__))); } /** * At the given bandwidth, calculate how much traffic will be * available until the given deadline. * * @param bps bandwidth * @param deadline when is the deadline * @return number of bytes available at bps until deadline */ uint64_t GNUNET_BANDWIDTH_value_get_available_until (struct GNUNET_BANDWIDTH_Value32NBO bps, struct GNUNET_TIME_Relative deadline) { uint64_t b; b = ntohl (bps.value__); LOG (GNUNET_ERROR_TYPE_DEBUG, "Bandwidth has %llu bytes available until deadline in %llums\n", (unsigned long long) ((b * deadline.rel_value + 500LL) / 1000LL), deadline.rel_value); return (b * deadline.rel_value + 500LL) / 1000LL; } /** * At the given bandwidth, calculate how long it would take for * 'size' bytes to be transmitted. * * @param bps bandwidth * @param size number of bytes we want to have available * @return how long it would take */ struct GNUNET_TIME_Relative GNUNET_BANDWIDTH_value_get_delay_for (struct GNUNET_BANDWIDTH_Value32NBO bps, uint64_t size) { uint64_t b; struct GNUNET_TIME_Relative ret; b = ntohl (bps.value__); if (b == 0) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Bandwidth suggests delay of infinity (zero bandwidth)\n"); return GNUNET_TIME_UNIT_FOREVER_REL; } ret.rel_value = size * 1000LL / b; LOG (GNUNET_ERROR_TYPE_DEBUG, "Bandwidth suggests delay of %llu ms for %llu bytes of traffic\n", (unsigned long long) ret.rel_value, (unsigned long long) size); return ret; } /** * Initialize bandwidth tracker. Note that in addition to the * 'max_carry_s' limit, we also always allow at least * GNUNET_SERVER_MAX_MESSAGE_SIZE to accumulate. So if the * bytes-per-second limit is so small that within 'max_carry_s' not * even GNUNET_SERVER_MAX_MESSAGE_SIZE is allowed to accumulate, it is * ignored and replaced by GNUNET_SERVER_MAX_MESSAGE_SIZE (which is in * bytes). * * @param av tracker to initialize * @param bytes_per_second_limit initial limit to assume * @param max_carry_s maximum number of seconds unused bandwidth * may accumulate before it expires */ void GNUNET_BANDWIDTH_tracker_init (struct GNUNET_BANDWIDTH_Tracker *av, struct GNUNET_BANDWIDTH_Value32NBO bytes_per_second_limit, uint32_t max_carry_s) { av->consumption_since_last_update__ = 0; av->last_update__ = GNUNET_TIME_absolute_get (); av->available_bytes_per_s__ = ntohl (bytes_per_second_limit.value__); av->max_carry_s__ = max_carry_s; LOG (GNUNET_ERROR_TYPE_DEBUG, "Tracker %p initialized with %u Bps and max carry %u\n", av, (unsigned int) av->available_bytes_per_s__, (unsigned int) max_carry_s); } /** * Update the tracker, looking at the current time and * bandwidth consumption data. * * @param av tracker to update */ static void update_tracker (struct GNUNET_BANDWIDTH_Tracker *av) { struct GNUNET_TIME_Absolute now; uint64_t delta_time; uint64_t delta_avail; uint64_t left_bytes; uint64_t max_carry; now = GNUNET_TIME_absolute_get (); delta_time = now.abs_value - av->last_update__.abs_value; delta_avail = (delta_time * ((unsigned long long) av->available_bytes_per_s__) + 500LL) / 1000LL; av->consumption_since_last_update__ -= delta_avail; av->last_update__ = now; if (av->consumption_since_last_update__ < 0) { left_bytes = -av->consumption_since_last_update__; max_carry = av->available_bytes_per_s__ * av->max_carry_s__; if (max_carry < GNUNET_SERVER_MAX_MESSAGE_SIZE) max_carry = GNUNET_SERVER_MAX_MESSAGE_SIZE; if (max_carry > left_bytes) av->consumption_since_last_update__ = -left_bytes; else av->consumption_since_last_update__ = -max_carry; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Tracker %p updated, have %u Bps, last update was %llu ms ago\n", av, (unsigned int) av->available_bytes_per_s__, (unsigned long long) delta_time); } /** * Notify the tracker that a certain number of bytes of bandwidth have * been consumed. Note that it is legal to consume bytes even if not * enough bandwidth is available (in that case, * GNUNET_BANDWIDTH_tracker_get_delay may return non-zero delay values * even for a size of zero for a while). * * @param av tracker to update * @param size number of bytes consumed * @return GNUNET_YES if this consumption is above the limit */ int GNUNET_BANDWIDTH_tracker_consume (struct GNUNET_BANDWIDTH_Tracker *av, ssize_t size) { int64_t nc; LOG (GNUNET_ERROR_TYPE_DEBUG, "Tracker %p consumes %d bytes\n", av, (int) size); if (size > 0) { nc = av->consumption_since_last_update__ + size; if (nc < av->consumption_since_last_update__) { GNUNET_break (0); return GNUNET_SYSERR; } av->consumption_since_last_update__ = nc; update_tracker (av); if (av->consumption_since_last_update__ > 0) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Tracker %p consumption %llu bytes above limit\n", av, (unsigned long long) av->consumption_since_last_update__); return GNUNET_YES; } } else { av->consumption_since_last_update__ += size; } return GNUNET_NO; } /** * Compute how long we should wait until consuming 'size' * bytes of bandwidth in order to stay within the given * quota. * * @param av tracker to query * @param size number of bytes we would like to consume * @return time in ms to wait for consumption to be OK */ struct GNUNET_TIME_Relative GNUNET_BANDWIDTH_tracker_get_delay (struct GNUNET_BANDWIDTH_Tracker *av, size_t size) { struct GNUNET_TIME_Relative ret; int64_t bytes_needed; if (av->available_bytes_per_s__ == 0) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Tracker %p delay is infinity\n", av); return GNUNET_TIME_UNIT_FOREVER_REL; } update_tracker (av); bytes_needed = size + av->consumption_since_last_update__; if (bytes_needed <= 0) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Tracker %p delay for %u bytes is zero\n", av, (unsigned int) size); return GNUNET_TIME_UNIT_ZERO; } ret.rel_value = (1000LL * bytes_needed) / (unsigned long long) av->available_bytes_per_s__; LOG (GNUNET_ERROR_TYPE_DEBUG, "Tracker %p delay for %u bytes is %llu ms\n", av, (unsigned int) size, (unsigned long long) ret.rel_value); return ret; } /** * Compute how many bytes are available for consumption right now. * quota. * * @param av tracker to query * @return number of bytes available for consumption right now */ int64_t GNUNET_BANDWIDTH_tracker_get_available (struct GNUNET_BANDWIDTH_Tracker * av) { struct GNUNET_BANDWIDTH_Value32NBO bps; uint64_t avail; int64_t used; update_tracker (av); bps = GNUNET_BANDWIDTH_value_init (av->available_bytes_per_s__); avail = GNUNET_BANDWIDTH_value_get_available_until (bps, GNUNET_TIME_absolute_get_duration (av->last_update__)); used = av->consumption_since_last_update__; LOG (GNUNET_ERROR_TYPE_DEBUG, "Tracker %p available bandwidth is %lld bytes\n", av, (long long) (int64_t) (avail - used)); return (int64_t) (avail - used); } /** * Update quota of bandwidth tracker. * * @param av tracker to initialize * @param bytes_per_second_limit new limit to assume */ void GNUNET_BANDWIDTH_tracker_update_quota (struct GNUNET_BANDWIDTH_Tracker *av, struct GNUNET_BANDWIDTH_Value32NBO bytes_per_second_limit) { uint32_t old_limit; uint32_t new_limit; new_limit = ntohl (bytes_per_second_limit.value__); LOG (GNUNET_ERROR_TYPE_DEBUG, "Tracker %p bandwidth changed to %u Bps\n", av, (unsigned int) new_limit); update_tracker (av); old_limit = av->available_bytes_per_s__; av->available_bytes_per_s__ = new_limit; if (old_limit > new_limit) update_tracker (av); /* maximum excess might be less now */ } /* end of bandwidth.c */ gnunet-0.9.3/src/util/test_container_meta_data.c0000644000175000017500000002633011760502550016701 00000000000000/* This file is part of GNUnet. (C) 2003, 2004, 2006, 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_container_meta_data.c * @brief Test for container_meta_data.c * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_container_lib.h" #define ABORT(m) { fprintf(stderr, "Error at %s:%d\n", __FILE__, __LINE__); if (m != NULL) GNUNET_CONTAINER_meta_data_destroy(m); return 1; } static int testMeta (int i) { struct GNUNET_CONTAINER_MetaData *m; char val[256]; char *sval; int j; unsigned int size; m = GNUNET_CONTAINER_meta_data_create (); if (GNUNET_OK != GNUNET_CONTAINER_meta_data_insert (m, "", EXTRACTOR_METATYPE_TITLE, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "TestTitle", strlen ("TestTitle") + 1)) ABORT (m); if (GNUNET_OK != GNUNET_CONTAINER_meta_data_insert (m, "", EXTRACTOR_METATYPE_AUTHOR_NAME, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "TestTitle", strlen ("TestTitle") + 1)) ABORT (m); if (GNUNET_OK == GNUNET_CONTAINER_meta_data_insert (m, "", EXTRACTOR_METATYPE_TITLE, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "TestTitle", strlen ("TestTitle") + 1)) /* dup! */ ABORT (m); if (GNUNET_OK == GNUNET_CONTAINER_meta_data_insert (m, "", EXTRACTOR_METATYPE_AUTHOR_NAME, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "TestTitle", strlen ("TestTitle") + 1)) /* dup! */ ABORT (m); if (2 != GNUNET_CONTAINER_meta_data_iterate (m, NULL, NULL)) ABORT (m); if (GNUNET_OK != GNUNET_CONTAINER_meta_data_delete (m, EXTRACTOR_METATYPE_AUTHOR_NAME, "TestTitle", strlen ("TestTitle") + 1)) ABORT (m); if (GNUNET_OK == GNUNET_CONTAINER_meta_data_delete (m, EXTRACTOR_METATYPE_AUTHOR_NAME, "TestTitle", strlen ("TestTitle") + 1)) /* already gone */ ABORT (m); if (1 != GNUNET_CONTAINER_meta_data_iterate (m, NULL, NULL)) ABORT (m); if (GNUNET_OK != GNUNET_CONTAINER_meta_data_delete (m, EXTRACTOR_METATYPE_TITLE, "TestTitle", strlen ("TestTitle") + 1)) ABORT (m); if (GNUNET_OK == GNUNET_CONTAINER_meta_data_delete (m, EXTRACTOR_METATYPE_TITLE, "TestTitle", strlen ("TestTitle") + 1)) /* already gone */ ABORT (m); if (0 != GNUNET_CONTAINER_meta_data_iterate (m, NULL, NULL)) ABORT (m); for (j = 0; j < i; j++) { GNUNET_snprintf (val, sizeof (val), "%s.%d", "A teststring that should compress well.", j); if (GNUNET_OK != GNUNET_CONTAINER_meta_data_insert (m, "", EXTRACTOR_METATYPE_UNKNOWN, EXTRACTOR_METAFORMAT_UTF8, "text/plain", val, strlen (val) + 1)) ABORT (m); } if (i != GNUNET_CONTAINER_meta_data_iterate (m, NULL, NULL)) ABORT (m); size = GNUNET_CONTAINER_meta_data_get_serialized_size (m); sval = NULL; if (size != GNUNET_CONTAINER_meta_data_serialize (m, &sval, size, GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL)) { GNUNET_free_non_null (sval); ABORT (m); } GNUNET_CONTAINER_meta_data_destroy (m); m = GNUNET_CONTAINER_meta_data_deserialize (sval, size); GNUNET_free (sval); if (m == NULL) ABORT (m); for (j = 0; j < i; j++) { GNUNET_snprintf (val, sizeof (val), "%s.%d", "A teststring that should compress well.", j); if (GNUNET_OK != GNUNET_CONTAINER_meta_data_delete (m, EXTRACTOR_METATYPE_UNKNOWN, val, strlen (val) + 1)) { ABORT (m); } } if (0 != GNUNET_CONTAINER_meta_data_iterate (m, NULL, NULL)) ABORT (m); GNUNET_CONTAINER_meta_data_destroy (m); return 0; } int testMetaMore (int i) { struct GNUNET_CONTAINER_MetaData *meta; int q; char txt[128]; char *data; unsigned long long size; meta = GNUNET_CONTAINER_meta_data_create (); for (q = 0; q <= i; q++) { GNUNET_snprintf (txt, 128, "%u -- %u\n", i, q); GNUNET_CONTAINER_meta_data_insert (meta, "", q % EXTRACTOR_metatype_get_max (), EXTRACTOR_METAFORMAT_UTF8, "text/plain", txt, strlen (txt) + 1); } size = GNUNET_CONTAINER_meta_data_get_serialized_size (meta); data = GNUNET_malloc (size * 4); if (size != GNUNET_CONTAINER_meta_data_serialize (meta, &data, size * 4, GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL)) { GNUNET_free (data); ABORT (meta); } GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_free (data); return 0; } static int testMetaLink () { struct GNUNET_CONTAINER_MetaData *m; char *val; unsigned int size; m = GNUNET_CONTAINER_meta_data_create (); if (GNUNET_OK != GNUNET_CONTAINER_meta_data_insert (m, "", EXTRACTOR_METATYPE_UNKNOWN, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "link", strlen ("link") + 1)) ABORT (m); if (GNUNET_OK != GNUNET_CONTAINER_meta_data_insert (m, "", EXTRACTOR_METATYPE_FILENAME, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "lib-link.m4", strlen ("lib-link.m4") + 1)) ABORT (m); val = NULL; size = GNUNET_CONTAINER_meta_data_serialize (m, &val, (size_t) - 1, GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL); GNUNET_CONTAINER_meta_data_destroy (m); m = GNUNET_CONTAINER_meta_data_deserialize (val, size); GNUNET_free (val); if (m == NULL) ABORT (m); GNUNET_CONTAINER_meta_data_destroy (m); return 0; } int check () { struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_CONTAINER_MetaData *meta2; int q; int i = 100; char txt[128]; char *str; unsigned char *thumb; meta = GNUNET_CONTAINER_meta_data_create (); meta2 = GNUNET_CONTAINER_meta_data_create (); for (q = 0; q <= i; q++) { GNUNET_snprintf (txt, 128, "%u -- %u\n", i, q); GNUNET_CONTAINER_meta_data_insert (meta, "", EXTRACTOR_METATYPE_UNKNOWN, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "TestTitle", strlen ("TestTitle") + 1); GNUNET_CONTAINER_meta_data_insert (meta2, "", EXTRACTOR_METATYPE_UNKNOWN, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "TestTitle", strlen ("TestTitle") + 1); } //check meta_data_test_equal if (GNUNET_YES != GNUNET_CONTAINER_meta_data_test_equal (meta, meta2)) { GNUNET_CONTAINER_meta_data_destroy (meta2); ABORT (meta); } //check meta_data_clear GNUNET_CONTAINER_meta_data_clear (meta2); if (0 != GNUNET_CONTAINER_meta_data_iterate (meta2, NULL, NULL)) { GNUNET_CONTAINER_meta_data_destroy (meta2); ABORT (meta); } // check equal branch in meta_data_test_equal if (GNUNET_YES != GNUNET_CONTAINER_meta_data_test_equal (meta, meta)) { GNUNET_CONTAINER_meta_data_destroy (meta2); ABORT (meta); } // check "count" branch in meta_data_test_equal if (GNUNET_NO != GNUNET_CONTAINER_meta_data_test_equal (meta, meta2)) { GNUNET_CONTAINER_meta_data_destroy (meta2); ABORT (meta); } // check meta_data_add_publication_date GNUNET_CONTAINER_meta_data_add_publication_date (meta2); // check meta_data_merge GNUNET_CONTAINER_meta_data_clear (meta2); GNUNET_CONTAINER_meta_data_merge (meta2, meta); if (100 == GNUNET_CONTAINER_meta_data_iterate (meta2, NULL, NULL)) { GNUNET_CONTAINER_meta_data_destroy (meta2); ABORT (meta); } // check meta_data_get_by_type GNUNET_CONTAINER_meta_data_clear (meta2); if (NULL != (str = GNUNET_CONTAINER_meta_data_get_by_type (meta2, EXTRACTOR_METATYPE_UNKNOWN))) { GNUNET_CONTAINER_meta_data_destroy (meta2); GNUNET_free (str); ABORT (meta); } str = GNUNET_CONTAINER_meta_data_get_by_type (meta, EXTRACTOR_METATYPE_UNKNOWN); GNUNET_assert (NULL != str); if (str[0] != 'T') { GNUNET_CONTAINER_meta_data_destroy (meta2); GNUNET_free (str); ABORT (meta); } GNUNET_free (str); // check branch if (NULL != (str = GNUNET_CONTAINER_meta_data_get_by_type (meta, EXTRACTOR_METATYPE_PUBLICATION_DATE))) { GNUNET_free (str); GNUNET_CONTAINER_meta_data_destroy (meta2); ABORT (meta); } //check meta_data_get_first_by_types str = GNUNET_CONTAINER_meta_data_get_first_by_types (meta, EXTRACTOR_METATYPE_UNKNOWN, -1); GNUNET_assert (NULL != str); if (str[0] != 'T') { GNUNET_CONTAINER_meta_data_destroy (meta2); GNUNET_free (str); ABORT (meta); } GNUNET_free (str); //check meta_data_get_thumbnail if (GNUNET_CONTAINER_meta_data_get_thumbnail (meta, &thumb) != 0) { GNUNET_free (thumb); GNUNET_CONTAINER_meta_data_destroy (meta2); ABORT (meta); } GNUNET_CONTAINER_meta_data_destroy (meta2); //check meta_data_duplicate meta2 = GNUNET_CONTAINER_meta_data_duplicate (meta); if (200 == GNUNET_CONTAINER_meta_data_iterate (meta2, NULL, NULL)) { GNUNET_CONTAINER_meta_data_destroy (meta2); ABORT (meta); } GNUNET_CONTAINER_meta_data_destroy (meta2); GNUNET_CONTAINER_meta_data_destroy (meta); return 0; } int main (int argc, char *argv[]) { int failureCount = 0; int i; GNUNET_log_setup ("test-container-meta-data", "WARNING", NULL); for (i = 0; i < 255; i++) failureCount += testMeta (i); for (i = 1; i < 255; i++) failureCount += testMetaMore (i); failureCount += testMetaLink (); int ret = check (); if (ret == 1) return 1; if (failureCount != 0) return 1; return 0; } /* end of test_container_meta_data.c */ gnunet-0.9.3/src/util/crypto_hkdf.c0000644000175000017500000001672611760502550014205 00000000000000/* Copyright (c) 2010 Nils Durner Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** * @file src/util/crypto_hkdf.c * @brief Hash-based KDF as defined in RFC 5869 * @see http://www.rfc-editor.org/rfc/rfc5869.txt * @todo remove GNUNET references * @author Nils Durner * * The following list of people have reviewed this code and considered * it correct on the date given (if you reviewed it, please * have your name added to the list): * * - Christian Grothoff (08.10.2010) * - Nathan Evans (08.10.2010) * - Matthias Wachs (08.10.2010) */ #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) /** * Set this to 0 if you compile this code outside of GNUnet. */ #define GNUNET_BUILD 1 /** * Enable debugging. */ #define DEBUG_HKDF 0 #if GNUNET_BUILD #include "platform.h" #include "gnunet_crypto_lib.h" #else #define GNUNET_NO 0 #define GNUNET_YES 1 #define GNUNET_SYSERR -1 #include #endif #include /** * @brief Compute the HMAC * @todo use chunked buffers * @param mac gcrypt MAC handle * @param key HMAC key * @param key_len length of key * @param buf message to be processed * @param buf_len length of buf * @return HMAC, freed by caller via gcry_md_close/_reset */ static const void * doHMAC (gcry_md_hd_t mac, const void *key, size_t key_len, const void *buf, size_t buf_len) { gcry_md_setkey (mac, key, key_len); gcry_md_write (mac, buf, buf_len); return (const void *) gcry_md_read (mac, 0); } /** * @brief Generate pseudo-random key * @param mac gcrypt HMAC handle * @param xts salt * @param xts_len length of the salt * @param skm source key material * @param skm_len length of skm * @param prk result buffer (allocated by caller; at least gcry_md_dlen() bytes) * @return GNUNET_YES on success */ static int getPRK (gcry_md_hd_t mac, const void *xts, size_t xts_len, const void *skm, size_t skm_len, void *prk) { const void *ret; ret = doHMAC (mac, xts, xts_len, skm, skm_len); if (ret == NULL) return GNUNET_SYSERR; memcpy (prk, ret, gcry_md_get_algo_dlen (gcry_md_get_algo (mac))); return GNUNET_YES; } #if DEBUG_HKDF static void dump (const char *src, const void *p, unsigned int l) { unsigned int i; printf ("\n%s: ", src); for (i = 0; i < l; i++) { printf ("%2x", (int) ((const unsigned char *) p)[i]); } printf ("\n"); } #endif /** * @brief Derive key * @param result buffer for the derived key, allocated by caller * @param out_len desired length of the derived key * @param xtr_algo hash algorithm for the extraction phase, GCRY_MD_... * @param prf_algo hash algorithm for the expansion phase, GCRY_MD_... * @param xts salt * @param xts_len length of xts * @param skm source key material * @param skm_len length of skm * @param argp va_list of void * & size_t pairs for context chunks * @return GNUNET_YES on success */ int GNUNET_CRYPTO_hkdf_v (void *result, size_t out_len, int xtr_algo, int prf_algo, const void *xts, size_t xts_len, const void *skm, size_t skm_len, va_list argp) { const void *hc; unsigned long i, t, d; unsigned int k = gcry_md_get_algo_dlen (prf_algo); unsigned int xtr_len = gcry_md_get_algo_dlen (xtr_algo); char prk[xtr_len]; int ret; gcry_md_hd_t xtr, prf; size_t ctx_len; va_list args; if (k == 0) return GNUNET_SYSERR; if (gcry_md_open (&xtr, xtr_algo, GCRY_MD_FLAG_HMAC) != GPG_ERR_NO_ERROR) return GNUNET_SYSERR; if (gcry_md_open (&prf, prf_algo, GCRY_MD_FLAG_HMAC) != GPG_ERR_NO_ERROR) { gcry_md_close (xtr); return GNUNET_SYSERR; } va_copy (args, argp); ctx_len = 0; while (NULL != va_arg (args, void *)) ctx_len += va_arg (args, size_t); va_end (args); memset (result, 0, out_len); if (getPRK (xtr, xts, xts_len, skm, skm_len, prk) != GNUNET_YES) goto hkdf_error; #if DEBUG_HKDF dump ("PRK", prk, xtr_len); #endif t = out_len / k; d = out_len % k; /* K(1) */ { size_t plain_len = k + ctx_len + 1; char plain[plain_len]; const void *ctx; char *dst; dst = plain + k; va_copy (args, argp); while ((ctx = va_arg (args, void *))) { size_t len; len = va_arg (args, size_t); memcpy (dst, ctx, len); dst += len; } va_end (args); if (t > 0) { memset (plain + k + ctx_len, 1, 1); #if DEBUG_HKDF dump ("K(1)", plain, plain_len); #endif hc = doHMAC (prf, prk, xtr_len, &plain[k], ctx_len + 1); if (hc == NULL) goto hkdf_error; memcpy (result, hc, k); result += k; } /* K(i+1) */ for (i = 1; i < t; i++) { memcpy (plain, result - k, k); memset (plain + k + ctx_len, i + 1, 1); gcry_md_reset (prf); #if DEBUG_HKDF dump ("K(i+1)", plain, plain_len); #endif hc = doHMAC (prf, prk, xtr_len, plain, plain_len); if (hc == NULL) goto hkdf_error; memcpy (result, hc, k); result += k; } /* K(t):d */ if (d > 0) { if (t > 0) { memcpy (plain, result - k, k); i++; } memset (plain + k + ctx_len, i, 1); gcry_md_reset (prf); #if DEBUG_HKDF dump ("K(t):d", plain, plain_len); #endif if (t > 0) hc = doHMAC (prf, prk, xtr_len, plain, plain_len); else hc = doHMAC (prf, prk, xtr_len, plain + k, plain_len - k); if (hc == NULL) goto hkdf_error; memcpy (result, hc, d); } #if DEBUG_HKDF dump ("result", result - k, out_len); #endif ret = GNUNET_YES; goto hkdf_ok; } hkdf_error: ret = GNUNET_SYSERR; hkdf_ok: gcry_md_close (prf); gcry_md_close (xtr); return ret; } /** * @brief Derive key * @param result buffer for the derived key, allocated by caller * @param out_len desired length of the derived key * @param xtr_algo hash algorithm for the extraction phase, GCRY_MD_... * @param prf_algo hash algorithm for the expansion phase, GCRY_MD_... * @param xts salt * @param xts_len length of xts * @param skm source key material * @param skm_len length of skm * @return GNUNET_YES on success */ int GNUNET_CRYPTO_hkdf (void *result, size_t out_len, int xtr_algo, int prf_algo, const void *xts, size_t xts_len, const void *skm, size_t skm_len, ...) { va_list argp; int ret; va_start (argp, skm_len); ret = GNUNET_CRYPTO_hkdf_v (result, out_len, xtr_algo, prf_algo, xts, xts_len, skm, skm_len, argp); va_end (argp); return ret; } /* end of crypto_hkdf.c */ gnunet-0.9.3/src/util/configuration.c0000644000175000017500000010140211760502550014522 00000000000000/* This file is part of GNUnet. (C) 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/util/configuration.c * @brief configuration management * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_util_lib.h" #include "gnunet_crypto_lib.h" #include "gnunet_strings_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) /** * @brief configuration entry */ struct ConfigEntry { /** * This is a linked list. */ struct ConfigEntry *next; /** * key for this entry */ char *key; /** * current, commited value */ char *val; }; /** * @brief configuration section */ struct ConfigSection { /** * This is a linked list. */ struct ConfigSection *next; /** * entries in the section */ struct ConfigEntry *entries; /** * name of the section */ char *name; }; /** * @brief configuration data */ struct GNUNET_CONFIGURATION_Handle { /** * Configuration sections. */ struct ConfigSection *sections; /** * Modification indication since last save * GNUNET_NO if clean, GNUNET_YES if dirty, * GNUNET_SYSERR on error (i.e. last save failed) */ int dirty; }; /** * Used for diffing a configuration object against * the default one */ struct DiffHandle { const struct GNUNET_CONFIGURATION_Handle *cfgDefault; struct GNUNET_CONFIGURATION_Handle *cfgDiff; }; /** * Create a GNUNET_CONFIGURATION_Handle. * * @return fresh configuration object */ struct GNUNET_CONFIGURATION_Handle * GNUNET_CONFIGURATION_create () { return GNUNET_malloc (sizeof (struct GNUNET_CONFIGURATION_Handle)); } /** * Destroy configuration object. * * @param cfg configuration to destroy */ void GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg) { struct ConfigSection *sec; while (NULL != (sec = cfg->sections)) GNUNET_CONFIGURATION_remove_section (cfg, sec->name); GNUNET_free (cfg); } /** * Parse a configuration file, add all of the options in the * file to the configuration environment. * * @param cfg configuration to update * @param filename name of the configuration file * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg, const char *filename) { int dirty; char line[256]; char tag[64]; char value[192]; FILE *fp; unsigned int nr; int i; int emptyline; int ret; char *section; char *fn; fn = GNUNET_STRINGS_filename_expand (filename); if (fn == NULL) return GNUNET_SYSERR; dirty = cfg->dirty; /* back up value! */ if (NULL == (fp = FOPEN (fn, "r"))) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fopen", fn); GNUNET_free (fn); return GNUNET_SYSERR; } GNUNET_free (fn); ret = GNUNET_OK; section = GNUNET_strdup (""); memset (line, 0, 256); nr = 0; while (NULL != fgets (line, 255, fp)) { nr++; for (i = 0; i < 255; i++) if (line[i] == '\t') line[i] = ' '; if (line[0] == '\n' || line[0] == '#' || line[0] == '%' || line[0] == '\r') continue; emptyline = 1; for (i = 0; (i < 255 && line[i] != 0); i++) if (line[i] != ' ' && line[i] != '\n' && line[i] != '\r') emptyline = 0; if (emptyline == 1) continue; /* remove tailing whitespace */ for (i = strlen (line) - 1; (i >= 0) && (isspace ((unsigned char) line[i])); i--) line[i] = '\0'; if (1 == SSCANF (line, "@INLINE@ %191[^\n]", value)) { /* @INLINE@ value */ if (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, value)) ret = GNUNET_SYSERR; /* failed to parse included config */ } else if (1 == SSCANF (line, "[%99[^]]]", value)) { /* [value] */ GNUNET_free (section); section = GNUNET_strdup (value); } else if (2 == SSCANF (line, " %63[^= ] = %191[^\n]", tag, value)) { /* tag = value */ /* Strip LF */ i = strlen (value) - 1; while ((i >= 0) && (isspace ((unsigned char) value[i]))) value[i--] = '\0'; /* remove quotes */ i = 0; if (value[0] == '"') { i = 1; while ((value[i] != '\0') && (value[i] != '"')) i++; if (value[i] == '"') { value[i] = '\0'; i = 1; } else i = 0; } GNUNET_CONFIGURATION_set_value_string (cfg, section, tag, &value[i]); } else if (1 == SSCANF (line, " %63[^= ] =[^\n]", tag)) { /* tag = */ GNUNET_CONFIGURATION_set_value_string (cfg, section, tag, ""); } else { /* parse error */ LOG (GNUNET_ERROR_TYPE_WARNING, _("Syntax error in configuration file `%s' at line %u.\n"), filename, nr); ret = GNUNET_SYSERR; break; } } GNUNET_assert (0 == FCLOSE (fp)); /* restore dirty flag - anything we set in the meantime * came from disk */ cfg->dirty = dirty; GNUNET_free (section); return ret; } /** * Test if there are configuration options that were * changed since the last save. * * @param cfg configuration to inspect * @return GNUNET_NO if clean, GNUNET_YES if dirty, GNUNET_SYSERR on error (i.e. last save failed) */ int GNUNET_CONFIGURATION_is_dirty (const struct GNUNET_CONFIGURATION_Handle *cfg) { return cfg->dirty; } /** * Write configuration file. * * @param cfg configuration to write * @param filename where to write the configuration * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *cfg, const char *filename) { struct ConfigSection *sec; struct ConfigEntry *ent; FILE *fp; int error; char *fn; char *val; char *pos; fn = GNUNET_STRINGS_filename_expand (filename); if (fn == NULL) return GNUNET_SYSERR; if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (fn)) { GNUNET_free (fn); return GNUNET_SYSERR; } if (NULL == (fp = FOPEN (fn, "w"))) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fopen", fn); GNUNET_free (fn); return GNUNET_SYSERR; } GNUNET_free (fn); error = 0; sec = cfg->sections; while (sec != NULL) { if (0 > FPRINTF (fp, "[%s]\n", sec->name)) { error = 1; break; } ent = sec->entries; while (ent != NULL) { if (ent->val != NULL) { val = GNUNET_malloc (strlen (ent->val) * 2 + 1); strcpy (val, ent->val); while (NULL != (pos = strstr (val, "\n"))) { memmove (&pos[2], &pos[1], strlen (&pos[1])); pos[0] = '\\'; pos[1] = 'n'; } if (0 > FPRINTF (fp, "%s = %s\n", ent->key, val)) { error = 1; GNUNET_free (val); break; } GNUNET_free (val); } ent = ent->next; } if (error != 0) break; if (0 > FPRINTF (fp, "%s\n", "")) { error = 1; break; } sec = sec->next; } if (error != 0) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", filename); GNUNET_assert (0 == FCLOSE (fp)); if (error != 0) { cfg->dirty = GNUNET_SYSERR; /* last write failed */ return GNUNET_SYSERR; } cfg->dirty = GNUNET_NO; /* last write succeeded */ return GNUNET_OK; } /** * Iterate over all options in the configuration. * * @param cfg configuration to inspect * @param iter function to call on each option * @param iter_cls closure for iter */ void GNUNET_CONFIGURATION_iterate (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_CONFIGURATION_Iterator iter, void *iter_cls) { struct ConfigSection *spos; struct ConfigEntry *epos; spos = cfg->sections; while (spos != NULL) { epos = spos->entries; while (epos != NULL) { iter (iter_cls, spos->name, epos->key, epos->val); epos = epos->next; } spos = spos->next; } } /** * Iterate over values of a section in the configuration. * * @param cfg configuration to inspect * @param section the section * @param iter function to call on each option * @param iter_cls closure for iter */ void GNUNET_CONFIGURATION_iterate_section_values (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, GNUNET_CONFIGURATION_Iterator iter, void *iter_cls) { struct ConfigSection *spos; struct ConfigEntry *epos; spos = cfg->sections; while ((spos != NULL) && (0 != strcasecmp (spos->name, section))) spos = spos->next; if (spos == NULL) return; epos = spos->entries; while (epos != NULL) { iter (iter_cls, spos->name, epos->key, epos->val); epos = epos->next; } } /** * Iterate over all sections in the configuration. * * @param cfg configuration to inspect * @param iter function to call on each section * @param iter_cls closure for iter */ void GNUNET_CONFIGURATION_iterate_sections (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_CONFIGURATION_Section_Iterator iter, void *iter_cls) { struct ConfigSection *spos; struct ConfigSection *next; next = cfg->sections; while (next != NULL) { spos = next; next = spos->next; iter (iter_cls, spos->name); } } /** * Remove the given section and all options in it. * * @param cfg configuration to inspect * @param section name of the section to remove */ void GNUNET_CONFIGURATION_remove_section (struct GNUNET_CONFIGURATION_Handle *cfg, const char *section) { struct ConfigSection *spos; struct ConfigSection *prev; struct ConfigEntry *ent; prev = NULL; spos = cfg->sections; while (spos != NULL) { if (0 == strcasecmp (section, spos->name)) { if (prev == NULL) cfg->sections = spos->next; else prev->next = spos->next; while (NULL != (ent = spos->entries)) { spos->entries = ent->next; GNUNET_free (ent->key); GNUNET_free_non_null (ent->val); GNUNET_free (ent); cfg->dirty = GNUNET_YES; } GNUNET_free (spos->name); GNUNET_free (spos); return; } prev = spos; spos = spos->next; } } /** * Copy a configuration value to the given target configuration. * Overwrites existing entries. * * @param cls the destination configuration (struct GNUNET_CONFIGURATION_Handle*) * @param section section for the value * @param option option name of the value * @param value value to copy */ static void copy_entry (void *cls, const char *section, const char *option, const char *value) { struct GNUNET_CONFIGURATION_Handle *dst = cls; GNUNET_CONFIGURATION_set_value_string (dst, section, option, value); } /** * Duplicate an existing configuration object. * * @param cfg configuration to duplicate * @return duplicate configuration */ struct GNUNET_CONFIGURATION_Handle * GNUNET_CONFIGURATION_dup (const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_CONFIGURATION_Handle *ret; ret = GNUNET_CONFIGURATION_create (); GNUNET_CONFIGURATION_iterate (cfg, ©_entry, ret); return ret; } /** * FIXME. * * @param cfg FIXME * @param section FIXME * @return matching entry, NULL if not found */ static struct ConfigSection * findSection (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section) { struct ConfigSection *pos; pos = cfg->sections; while ((pos != NULL) && (0 != strcasecmp (section, pos->name))) pos = pos->next; return pos; } /** * Find an entry from a configuration. * * @param cfg handle to the configuration * @param section section the option is in * @param key the option * @return matching entry, NULL if not found */ static struct ConfigEntry * findEntry (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *key) { struct ConfigSection *sec; struct ConfigEntry *pos; sec = findSection (cfg, section); if (sec == NULL) return NULL; pos = sec->entries; while ((pos != NULL) && (0 != strcasecmp (key, pos->key))) pos = pos->next; return pos; } /** * A callback function, compares entries from two configurations * (default against a new configuration) and write the diffs in a * diff-configuration object (the callback object). * * @param cls the diff configuration (struct DiffHandle*) * @param section section for the value (of the default conf.) * @param option option name of the value (of the default conf.) * @param value value to copy (of the default conf.) */ static void compareEntries (void *cls, const char *section, const char *option, const char *value) { struct DiffHandle *dh = cls; struct ConfigEntry *entNew; entNew = findEntry (dh->cfgDefault, section, option); if ((entNew != NULL) && (strcmp (entNew->val, value) == 0)) return; GNUNET_CONFIGURATION_set_value_string (dh->cfgDiff, section, option, value); } /** * Write only configuration entries that have been changed to configuration file * @param cfgDefault default configuration * @param cfgNew new configuration * @param filename where to write the configuration diff between default and new * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_write_diffs (const struct GNUNET_CONFIGURATION_Handle *cfgDefault, const struct GNUNET_CONFIGURATION_Handle *cfgNew, const char *filename) { int ret; struct DiffHandle diffHandle; diffHandle.cfgDiff = GNUNET_CONFIGURATION_create (); diffHandle.cfgDefault = cfgDefault; GNUNET_CONFIGURATION_iterate (cfgNew, compareEntries, &diffHandle); ret = GNUNET_CONFIGURATION_write (diffHandle.cfgDiff, filename); GNUNET_CONFIGURATION_destroy (diffHandle.cfgDiff); return ret; } /** * Set a configuration value that should be a string. * * @param cfg configuration to update * @param section section of interest * @param option option of interest * @param value value to set */ void GNUNET_CONFIGURATION_set_value_string (struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, const char *value) { struct ConfigSection *sec; struct ConfigEntry *e; e = findEntry (cfg, section, option); if (e != NULL) { GNUNET_free_non_null (e->val); e->val = GNUNET_strdup (value); return; } sec = findSection (cfg, section); if (sec == NULL) { sec = GNUNET_malloc (sizeof (struct ConfigSection)); sec->name = GNUNET_strdup (section); sec->next = cfg->sections; cfg->sections = sec; } e = GNUNET_malloc (sizeof (struct ConfigEntry)); e->key = GNUNET_strdup (option); e->val = GNUNET_strdup (value); e->next = sec->entries; sec->entries = e; } /** * Set a configuration value that should be a number. * * @param cfg configuration to update * @param section section of interest * @param option option of interest * @param number value to set */ void GNUNET_CONFIGURATION_set_value_number (struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, unsigned long long number) { char s[64]; GNUNET_snprintf (s, 64, "%llu", number); GNUNET_CONFIGURATION_set_value_string (cfg, section, option, s); } /** * Get a configuration value that should be a number. * * @param cfg configuration to inspect * @param section section of interest * @param option option of interest * @param number where to store the numeric value of the option * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_get_value_number (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, unsigned long long *number) { struct ConfigEntry *e; e = findEntry (cfg, section, option); if (e == NULL) return GNUNET_SYSERR; if (1 != SSCANF (e->val, "%llu", number)) return GNUNET_SYSERR; return GNUNET_OK; } /** * Get a configuration value that should be a relative time. * * @param cfg configuration to inspect * @param section section of interest * @param option option of interest * @param time set to the time value stored in the configuration * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_get_value_time (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, struct GNUNET_TIME_Relative *time) { struct ConfigEntry *e; e = findEntry (cfg, section, option); if (e == NULL) return GNUNET_SYSERR; return GNUNET_STRINGS_fancy_time_to_relative (e->val, time); } /** * Get a configuration value that should be a size in bytes. * * @param cfg configuration to inspect * @param section section of interest * @param option option of interest * @param size set to the size in bytes as stored in the configuration * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_get_value_size (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, unsigned long long *size) { struct ConfigEntry *e; e = findEntry (cfg, section, option); if (e == NULL) return GNUNET_SYSERR; return GNUNET_STRINGS_fancy_size_to_bytes (e->val, size); } /** * Get a configuration value that should be a string. * * @param cfg configuration to inspect * @param section section of interest * @param option option of interest * @param value will be set to a freshly allocated configuration * value, or NULL if option is not specified * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_get_value_string (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value) { struct ConfigEntry *e; e = findEntry (cfg, section, option); if ((e == NULL) || (e->val == NULL)) { *value = NULL; return GNUNET_SYSERR; } *value = GNUNET_strdup (e->val); return GNUNET_OK; } /** * Get a configuration value that should be in a set of * predefined strings * * @param cfg configuration to inspect * @param section section of interest * @param option option of interest * @param choices NULL-terminated list of legal values * @param value will be set to an entry in the legal list, * or NULL if option is not specified and no default given * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_get_value_choice (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, const char **choices, const char **value) { struct ConfigEntry *e; int i; e = findEntry (cfg, section, option); if (e == NULL) return GNUNET_SYSERR; i = 0; while (choices[i] != NULL) { if (0 == strcasecmp (choices[i], e->val)) break; i++; } if (choices[i] == NULL) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Configuration value '%s' for '%s'" " in section '%s' is not in set of legal choices\n"), e->val, option, section); return GNUNET_SYSERR; } *value = choices[i]; return GNUNET_OK; } /** * Test if we have a value for a particular option * @param cfg configuration to inspect * @param section section of interest * @param option option of interest * @return GNUNET_YES if so, GNUNET_NO if not. */ int GNUNET_CONFIGURATION_have_value (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option) { struct ConfigEntry *e; if ((NULL == (e = findEntry (cfg, section, option))) || (e->val == NULL)) return GNUNET_NO; return GNUNET_YES; } /** * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR" * where either in the "PATHS" section or the environtment * "FOO" is set to "DIRECTORY". * * @param cfg configuration to use for path expansion * @param orig string to $-expand (will be freed!) * @return $-expanded string */ char * GNUNET_CONFIGURATION_expand_dollar (const struct GNUNET_CONFIGURATION_Handle *cfg, char *orig) { int i; char *prefix; char *result; const char *post; const char *env; if (orig[0] != '$') return orig; i = 0; while ((orig[i] != '/') && (orig[i] != '\\') && (orig[i] != '\0')) i++; if (orig[i] == '\0') { post = ""; } else { orig[i] = '\0'; post = &orig[i + 1]; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "PATHS", &orig[1], &prefix)) { if (NULL == (env = getenv (&orig[1]))) { orig[i] = DIR_SEPARATOR; return orig; } prefix = GNUNET_strdup (env); } result = GNUNET_malloc (strlen (prefix) + strlen (post) + 2); strcpy (result, prefix); if ((strlen (prefix) == 0) || ((prefix[strlen (prefix) - 1] != DIR_SEPARATOR) && (strlen (post) > 0))) strcat (result, DIR_SEPARATOR_STR); strcat (result, post); GNUNET_free (prefix); GNUNET_free (orig); return result; } /** * Get a configuration value that should be a string. * * @param cfg configuration to inspect * @param section section of interest * @param option option of interest * @param value will be set to a freshly allocated configuration * value, or NULL if option is not specified * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_get_value_filename (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value) { char *tmp; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &tmp)) { *value = NULL; return GNUNET_SYSERR; } tmp = GNUNET_CONFIGURATION_expand_dollar (cfg, tmp); *value = GNUNET_STRINGS_filename_expand (tmp); GNUNET_free (tmp); if (*value == NULL) return GNUNET_SYSERR; return GNUNET_OK; } /** * Get a configuration value that should be in a set of * "GNUNET_YES" or "GNUNET_NO". * * @param cfg configuration to inspect * @param section section of interest * @param option option of interest * @return GNUNET_YES, GNUNET_NO or GNUNET_SYSERR */ int GNUNET_CONFIGURATION_get_value_yesno (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option) { static const char *yesno[] = { "YES", "NO", NULL }; const char *val; int ret; ret = GNUNET_CONFIGURATION_get_value_choice (cfg, section, option, yesno, &val); if (ret == GNUNET_SYSERR) return ret; if (val == yesno[0]) return GNUNET_YES; return GNUNET_NO; } /** * Iterate over the set of filenames stored in a configuration value. * * @param cfg configuration to inspect * @param section section of interest * @param option option of interest * @param cb function to call on each filename * @param cb_cls closure for cb * @return number of filenames iterated over, -1 on error */ int GNUNET_CONFIGURATION_iterate_value_filenames (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, GNUNET_FileNameCallback cb, void *cb_cls) { char *list; char *pos; char *end; char old; int ret; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list)) return 0; GNUNET_assert (list != NULL); ret = 0; pos = list; while (1) { while (pos[0] == ' ') pos++; if (strlen (pos) == 0) break; end = pos + 1; while ((end[0] != ' ') && (end[0] != '\0')) { if (end[0] == '\\') { switch (end[1]) { case '\\': case ' ': memmove (end, &end[1], strlen (&end[1]) + 1); case '\0': /* illegal, but just keep it */ break; default: /* illegal, but just ignore that there was a '/' */ break; } } end++; } old = end[0]; end[0] = '\0'; if (strlen (pos) > 0) { ret++; if ((cb != NULL) && (GNUNET_OK != cb (cb_cls, pos))) { ret = GNUNET_SYSERR; break; } } if (old == '\0') break; pos = end + 1; } GNUNET_free (list); return ret; } /** * FIXME. * * @param value FIXME * @return FIXME */ static char * escape_name (const char *value) { char *escaped; const char *rpos; char *wpos; escaped = GNUNET_malloc (strlen (value) * 2 + 1); memset (escaped, 0, strlen (value) * 2 + 1); rpos = value; wpos = escaped; while (rpos[0] != '\0') { switch (rpos[0]) { case '\\': case ' ': wpos[0] = '\\'; wpos[1] = rpos[0]; wpos += 2; break; default: wpos[0] = rpos[0]; wpos++; } rpos++; } return escaped; } /** * FIXME. * * @param cls string we compare with (const char*) * @param fn filename we are currently looking at * @return GNUNET_OK if the names do not match, GNUNET_SYSERR if they do */ static int test_match (void *cls, const char *fn) { const char *of = cls; return (0 == strcmp (of, fn)) ? GNUNET_SYSERR : GNUNET_OK; } /** * Append a filename to a configuration value that * represents a list of filenames * * @param cfg configuration to update * @param section section of interest * @param option option of interest * @param value filename to append * @return GNUNET_OK on success, * GNUNET_NO if the filename already in the list * GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_append_value_filename (struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, const char *value) { char *escaped; char *old; char *nw; if (GNUNET_SYSERR == GNUNET_CONFIGURATION_iterate_value_filenames (cfg, section, option, &test_match, (void *) value)) return GNUNET_NO; /* already exists */ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &old)) old = GNUNET_strdup (""); escaped = escape_name (value); nw = GNUNET_malloc (strlen (old) + strlen (escaped) + 2); strcpy (nw, old); if (strlen (old) > 0) strcat (nw, " "); strcat (nw, escaped); GNUNET_CONFIGURATION_set_value_string (cfg, section, option, nw); GNUNET_free (old); GNUNET_free (nw); GNUNET_free (escaped); return GNUNET_OK; } /** * Remove a filename from a configuration value that * represents a list of filenames * * @param cfg configuration to update * @param section section of interest * @param option option of interest * @param value filename to remove * @return GNUNET_OK on success, * GNUNET_NO if the filename is not in the list, * GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_remove_value_filename (struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, const char *value) { char *list; char *pos; char *end; char *match; char old; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list)) return GNUNET_NO; match = escape_name (value); pos = list; while (1) { while (pos[0] == ' ') pos++; if (strlen (pos) == 0) break; end = pos + 1; while ((end[0] != ' ') && (end[0] != '\0')) { if (end[0] == '\\') { switch (end[1]) { case '\\': case ' ': end++; break; case '\0': /* illegal, but just keep it */ break; default: /* illegal, but just ignore that there was a '/' */ break; } } end++; } old = end[0]; end[0] = '\0'; if (0 == strcmp (pos, match)) { if (old != '\0') memmove (pos, &end[1], strlen (&end[1]) + 1); else { if (pos != list) pos[-1] = '\0'; else pos[0] = '\0'; } GNUNET_CONFIGURATION_set_value_string (cfg, section, option, list); GNUNET_free (list); GNUNET_free (match); return GNUNET_OK; } if (old == '\0') break; end[0] = old; pos = end + 1; } GNUNET_free (list); GNUNET_free (match); return GNUNET_NO; } /** * Wrapper around GNUNET_CONFIGURATION_parse. * * @param cls the cfg * @param filename file to parse * @return GNUNET_OK on success */ static int parse_configuration_file (void *cls, const char *filename) { struct GNUNET_CONFIGURATION_Handle *cfg = cls; char * ext; int ret; /* Examine file extension */ ext = strrchr (filename, '.'); if ((NULL == ext) || (0 != strcmp (ext, ".conf"))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Skipping file `%s'\n", filename); return GNUNET_OK; } ret = GNUNET_CONFIGURATION_parse (cfg, filename); return ret; } /** * Load default configuration. This function will parse the * defaults from the given defaults_d directory. * * @param cfg configuration to update * @param defaults_d directory with the defaults * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_load_from (struct GNUNET_CONFIGURATION_Handle *cfg, const char *defaults_d) { if (GNUNET_SYSERR == GNUNET_DISK_directory_scan (defaults_d, &parse_configuration_file, cfg)) return GNUNET_SYSERR; /* no configuration at all found */ return GNUNET_OK; } /** * Load configuration (starts with defaults, then loads * system-specific configuration). * * @param cfg configuration to update * @param filename name of the configuration file, NULL to load defaults * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg, const char *filename) { char *baseconfig; char *ipath; ipath = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR); if (ipath == NULL) return GNUNET_SYSERR; baseconfig = NULL; GNUNET_asprintf (&baseconfig, "%s%s", ipath, "config.d"); GNUNET_free (ipath); if (GNUNET_SYSERR == GNUNET_DISK_directory_scan (baseconfig, &parse_configuration_file, cfg)) { GNUNET_free (baseconfig); return GNUNET_SYSERR; /* no configuration at all found */ } GNUNET_free (baseconfig); if ((filename != NULL) && (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, filename))) { /* specified configuration not found */ return GNUNET_SYSERR; } if (((GNUNET_YES != GNUNET_CONFIGURATION_have_value (cfg, "PATHS", "DEFAULTCONFIG"))) && (filename != NULL)) GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG", filename); if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg, "TESTING", "WEAKRANDOM")) && (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (cfg, "TESTING", "WEAKRANDOM"))) GNUNET_CRYPTO_random_disable_entropy_gathering (); return GNUNET_OK; } /* end of configuration.c */ gnunet-0.9.3/src/util/test_common_logging_runtime_loglevels.c0000644000175000017500000002407611760502550021542 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_common_logging_runtime_loglevels.c * @brief testcase for the logging module (runtime log level adjustment) * @author LRN */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_scheduler_lib.h" #include "gnunet_network_lib.h" #include "gnunet_disk_lib.h" #include "gnunet_os_lib.h" #define VERBOSE GNUNET_NO static int ok; static int phase = 0; static struct GNUNET_OS_Process *proc; /* Pipe to read from started processes stdout (on read end) */ static struct GNUNET_DISK_PipeHandle *pipe_stdout; static GNUNET_SCHEDULER_TaskIdentifier die_task; static void runone (void); static void end_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending phase %d, ok is %d\n", phase, ok); if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); } GNUNET_OS_process_wait (proc); GNUNET_OS_process_destroy (proc); proc = NULL; GNUNET_DISK_pipe_close (pipe_stdout); if (ok == 1) { if (phase < 9) { phase += 1; runone (); } else ok = 0; } else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "failing\n"); } static char * read_output_line (int phase_from1, int phase_to1, int phase_from2, int phase_to2, char c, char *expect_level, long delay_morethan, long delay_lessthan, int phase, char *p, int *len, long *delay, char level[8]) { char *r = p; char t[7]; int i, j, stop = 0; j = 0; int stage = 0; if (!(phase >= phase_from1 && phase <= phase_to1) && !(phase >= phase_from2 && phase <= phase_to2)) return p; #if 0 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to match '%c%s \\d\\r\\n' on %s\n", c, expect_level, p); #endif for (i = 0; i < *len && !stop; i++) { switch (stage) { case 0: /* read first char */ if (r[i] != c) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected '%c', but got '%c'\n", c, r[i]); GNUNET_break (0); return NULL; } stage += 1; break; case 1: /* read at most 7 char-long error level string, finished by ' ' */ if (r[i] == ' ') { level[j] = '\0'; stage += 1; j = 0; } else if (i == 8) { GNUNET_break (0); ok = 2; return NULL; } else level[j++] = r[i]; break; case 2: /* read the delay, finished by '\n' */ t[j++] = r[i]; #if WINDOWS if (r[i] == '\r' && r[i + 1] == '\n') { i += 1; t[j - 1] = '\0'; *delay = strtol (t, NULL, 10); stop = 1; } #else if (r[i] == '\n') { t[j - 1] = '\0'; *delay = strtol (t, NULL, 10); stop = 1; } #endif break; } } if (!stop || strcmp (expect_level, level) != 0 || *delay < 0 || *delay > 1000 || (!((*delay < delay_lessthan) || !(*delay > delay_morethan)) && c != '1' && c != '2')) return NULL; *len = *len - i; return &r[i]; } char buf[20 * 16]; char *buf_ptr; int bytes; static void read_call (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_DISK_FileHandle *stdout_read_handle = cls; char level[8]; long delay; long delays[8]; int rd; rd = GNUNET_DISK_file_read (stdout_read_handle, buf_ptr, sizeof (buf) - bytes); if (rd > 0) { buf_ptr += rd; bytes += rd; #if VERBOSE FPRINTF (stderr, "got %d bytes, reading more\n", rd); #endif GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, stdout_read_handle, &read_call, (void *) stdout_read_handle); return; } #if VERBOSE FPRINTF (stderr, "bytes is %d:%s\n", bytes, buf); #endif /* +------CHILD OUTPUT-- * | SOFT HARD * | E W I D E W I D * | 0E * * * * | 1W * * * * * P 2I * * * * * * H 3D * * * * * * * A * S 4E * * * E 5W * * * * * | 6I * * * * * * * | 7D * * * * * * * * * | 8 * * * * * | 9 * * * * */ char *p = buf; if (bytes == 20 * 16 || !(p = read_output_line (0, 3, 4, 9, 'L', "ERROR", -1, 1, phase, p, &bytes, &delay, level)) || !(p = read_output_line (0, 3, 4, 9, '1', "ERROR", 200, 400, phase, p, &bytes, &delays[0], level)) || !(p = read_output_line (1, 3, 5, 9, 'L', "WARNING", -1, 1, phase, p, &bytes, &delay, level)) || !(p = read_output_line (0, 3, 4, 9, '1', "WARNING", 200, 400, phase, p, &bytes, &delays[1], level)) || !(p = read_output_line (2, 3, 6, 7, 'L', "INFO", -1, 1, phase, p, &bytes, &delay, level)) || !(p = read_output_line (0, 3, 4, 9, '1', "INFO", 200, 400, phase, p, &bytes, &delays[2], level)) || !(p = read_output_line (3, 3, 7, 7, 'L', "DEBUG", -1, 1, phase, p, &bytes, &delay, level)) || !(p = read_output_line (0, 3, 4, 9, '1', "DEBUG", 200, 400, phase, p, &bytes, &delays[3], level)) || !(p = read_output_line (0, 3, 4, 9, 'L', "ERROR", -1, 1, phase, p, &bytes, &delay, level)) || !(p = read_output_line (0, 3, 4, 9, '2', "ERROR", 200, 400, phase, p, &bytes, &delays[4], level)) || !(p = read_output_line (0, 3, 5, 9, 'L', "WARNING", -1, 1, phase, p, &bytes, &delay, level)) || !(p = read_output_line (0, 3, 4, 9, '2', "WARNING", 200, 400, phase, p, &bytes, &delays[5], level)) || !(p = read_output_line (-1, -1, 6, 7, 'L', "INFO", -1, 1, phase, p, &bytes, &delay, level)) || !(p = read_output_line (0, 3, 4, 9, '2', "INFO", 200, 400, phase, p, &bytes, &delays[6], level)) || !(p = read_output_line (-1, -1, 7, 7, 'L', "DEBUG", -1, 1, phase, p, &bytes, &delay, level)) || !(p = read_output_line (0, 3, 4, 9, '2', "DEBUG", 200, 400, phase, p, &bytes, &delays[7], level))) { if (bytes == 20 * 16) FPRINTF (stderr, "%s", "Ran out of buffer space!\n"); GNUNET_break (0); ok = 2; GNUNET_SCHEDULER_cancel (die_task); GNUNET_SCHEDULER_add_now (&end_task, NULL); return; } GNUNET_SCHEDULER_cancel (die_task); GNUNET_SCHEDULER_add_now (&end_task, NULL); } static void runone () { const struct GNUNET_DISK_FileHandle *stdout_read_handle; pipe_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); if (pipe_stdout == NULL) { GNUNET_break (0); ok = 2; return; } putenv ("GNUNET_LOG="); putenv ("GNUNET_FORCE_LOG="); putenv ("GNUNET_FORCE_LOGFILE="); switch (phase) { case 0: putenv ("GNUNET_LOG=;;;;ERROR"); break; case 1: putenv ("GNUNET_LOG=;;;;WARNING"); break; case 2: putenv ("GNUNET_LOG=;;;;INFO"); break; case 3: putenv ("GNUNET_LOG=;;;;DEBUG"); break; case 4: putenv ("GNUNET_FORCE_LOG=;;;;ERROR"); break; case 5: putenv ("GNUNET_FORCE_LOG=;;;;WARNING"); break; case 6: putenv ("GNUNET_FORCE_LOG=;;;;INFO"); break; case 7: putenv ("GNUNET_FORCE_LOG=;;;;DEBUG"); break; case 8: putenv ("GNUNET_LOG=blah;;;;ERROR"); break; case 9: putenv ("GNUNET_FORCE_LOG=blah;;;;ERROR"); break; } proc = GNUNET_OS_start_process (GNUNET_NO, NULL, pipe_stdout, #if MINGW "test_common_logging_dummy", #else "./test_common_logging_dummy", #endif "test_common_logging_dummy", NULL); putenv ("GNUNET_FORCE_LOG="); putenv ("GNUNET_LOG="); /* Close the write end of the read pipe */ GNUNET_DISK_pipe_close_end (pipe_stdout, GNUNET_DISK_PIPE_END_WRITE); stdout_read_handle = GNUNET_DISK_pipe_handle (pipe_stdout, GNUNET_DISK_PIPE_END_READ); die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10), &end_task, NULL); bytes = 0; buf_ptr = buf; memset (&buf, 0, sizeof (buf)); GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, stdout_read_handle, &read_call, (void *) stdout_read_handle); } static void task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { phase = 0; runone (); } /** * Main method, starts scheduler with task1, * checks that "ok" is correct at the end. */ static int check () { ok = 1; GNUNET_SCHEDULER_run (&task, &ok); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-common-logging-runtime-loglevels", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); return ret; } /* end of test_common_logging_runtime_loglevels.c */ gnunet-0.9.3/src/util/test_os_priority.c0000644000175000017500000000435611760502550015306 00000000000000/* This file is part of GNUnet. (C) 2003, 2004, 2005, 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_os_priority.c * @brief testcase for util/os_priority.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_os_lib.h" #define VERBOSE 0 static int testprio () { if (GNUNET_OK != GNUNET_OS_set_process_priority (GNUNET_OS_process_current (), GNUNET_SCHEDULER_PRIORITY_DEFAULT)) return 1; if (GNUNET_OK != GNUNET_OS_set_process_priority (GNUNET_OS_process_current (), GNUNET_SCHEDULER_PRIORITY_UI)) return 1; if (GNUNET_OK != GNUNET_OS_set_process_priority (GNUNET_OS_process_current (), GNUNET_SCHEDULER_PRIORITY_IDLE)) return 1; if (GNUNET_OK != GNUNET_OS_set_process_priority (GNUNET_OS_process_current (), GNUNET_SCHEDULER_PRIORITY_BACKGROUND)) return 1; if (GNUNET_OK != GNUNET_OS_set_process_priority (GNUNET_OS_process_current (), GNUNET_SCHEDULER_PRIORITY_HIGH)) return 1; if (GNUNET_OK != GNUNET_OS_set_process_priority (GNUNET_OS_process_current (), GNUNET_SCHEDULER_PRIORITY_HIGH)) return 1; return 0; } int main (int argc, char *argv[]) { int errCnt = 0; GNUNET_log_setup ("test_os_priority", "WARNING", NULL); if (0 != testprio ()) errCnt++; return errCnt; } gnunet-0.9.3/src/util/Makefile.am0000644000175000017500000002456111762221256013560 00000000000000INCLUDES = -I$(top_srcdir)/src/include -I$(top_builddir)/src/include plugindir = $(libdir)/gnunet pkgcfgdir= $(pkgdatadir)/config.d/ dist_pkgcfg_DATA = \ util.conf pkgcfg_DATA = \ resolver.conf if MINGW noinst_LTLIBRARIES = \ libgnunetutilwin.la libgnunetutilwin_la_SOURCES = \ win.cc \ winproc.c libgnunetutilwin_la_LDFLAGS = \ -no-undefined -Wl,--export-all-symbols libgnunetutilwin_la_LIBADD = \ -lshell32 -liconv -lstdc++ \ -lcomdlg32 -lgdi32 -liphlpapi WINLIB = libgnunetutilwin.la endif if !MINGW SERVER_CLIENT_UNIX = test_server_with_client_unix endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIB = -lgcov endif noinst_PROGRAMS = \ gnunet-config-diff \ test_common_logging_dummy gnunet_config_diff_SOURCES = \ gnunet-config-diff.c gnunet_config_diff_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la gnunet_config_diff_DEPENDENCIES = \ libgnunetutil.la test_common_logging_dummy_SOURCES = \ test_common_logging_dummy.c test_common_logging_dummy_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_common_logging_dummy_DEPENDENCIES = \ libgnunetutil.la lib_LTLIBRARIES = libgnunetutil.la libgnunetutil_la_SOURCES = \ bandwidth.c \ bio.c \ client.c \ common_allocation.c \ common_endian.c \ common_logging.c \ configuration.c \ connection.c \ container_bloomfilter.c \ container_heap.c \ container_meta_data.c \ container_multihashmap.c \ container_slist.c \ crypto_aes.c \ crypto_crc.c \ crypto_hash.c \ crypto_hkdf.c \ crypto_kdf.c \ crypto_ksk.c \ crypto_random.c \ crypto_rsa.c \ disk.c \ disk.h \ getopt.c \ getopt_helpers.c \ helper.c \ load.c \ network.c \ os_installation.c \ os_network.c \ os_priority.c \ peer.c \ plugin.c \ program.c \ pseudonym.c \ resolver_api.c resolver.h \ scheduler.c \ server.c \ server_mst.c \ server_nc.c \ server_tc.c \ service.c \ signal.c \ strings.c \ time.c \ speedup.c libgnunetutil_la_LIBADD = \ $(GCLIBADD) $(WINLIB) \ $(LIBGCRYPT_LIBS) \ $(LTLIBICONV) \ -lltdl -lz -lunistring $(XLIB) libgnunetutil_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 8:0:0 bin_PROGRAMS = \ gnunet-service-resolver \ gnunet-resolver \ gnunet-rsa gnunet_service_resolver_SOURCES = \ gnunet-service-resolver.c gnunet_service_resolver_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_service_resolver_DEPENDENCIES = \ libgnunetutil.la gnunet_resolver_SOURCES = \ gnunet-resolver.c gnunet_resolver_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_resolver_DEPENDENCIES = \ libgnunetutil.la gnunet_rsa_SOURCES = \ gnunet-rsa.c gnunet_rsa_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_rsa_DEPENDENCIES = \ libgnunetutil.la plugin_LTLIBRARIES = \ libgnunet_plugin_test.la libgnunet_plugin_test_la_SOURCES = \ test_plugin_plug.c libgnunet_plugin_test_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) if HAVE_BENCHMARKS BENCHMARKS = \ perf_crypto_hash endif check_PROGRAMS = \ test_bio \ test_client \ test_common_allocation \ test_common_endian \ test_common_logging \ test_configuration \ test_container_bloomfilter \ test_container_meta_data \ test_container_multihashmap \ test_container_heap \ test_container_slist \ test_crypto_aes \ test_crypto_aes_weak \ test_crypto_crc \ test_crypto_hash \ test_crypto_hkdf \ test_crypto_ksk \ test_crypto_random \ test_crypto_rsa \ test_disk \ test_getopt \ test_connection \ test_connection_addressing \ test_connection_receive_cancel \ test_connection_timeout \ test_connection_timeout_no_connect \ test_connection_transmit_cancel \ test_os_network \ test_os_priority \ test_peer \ test_plugin \ test_program \ test_pseudonym \ test_resolver_api \ test_scheduler \ test_scheduler_delay \ test_server_mst_interrupt \ test_server \ test_server_disconnect \ test_server_with_client \ $(SERVER_CLIENT_UNIX) \ test_service \ test_strings \ test_time \ test_speedup \ $(BENCHMARKS) \ test_os_start_process \ test_common_logging_runtime_loglevels if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) endif test_bio_SOURCES = \ test_bio.c test_bio_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_os_start_process_SOURCES = \ test_os_start_process.c test_os_start_process_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_client_SOURCES = \ test_client.c test_client_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_common_allocation_SOURCES = \ test_common_allocation.c test_common_allocation_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_common_endian_SOURCES = \ test_common_endian.c test_common_endian_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_common_logging_SOURCES = \ test_common_logging.c test_common_logging_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_common_logging_runtime_loglevels_SOURCES = \ test_common_logging_runtime_loglevels.c test_common_logging_runtime_loglevels_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_configuration_SOURCES = \ test_configuration.c test_configuration_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_container_bloomfilter_SOURCES = \ test_container_bloomfilter.c test_container_bloomfilter_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_container_meta_data_SOURCES = \ test_container_meta_data.c test_container_meta_data_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la -lextractor test_container_multihashmap_SOURCES = \ test_container_multihashmap.c test_container_multihashmap_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_container_heap_SOURCES = \ test_container_heap.c test_container_heap_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_container_slist_SOURCES = \ test_container_slist.c test_container_slist_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_crypto_aes_SOURCES = \ test_crypto_aes.c test_crypto_aes_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_crypto_aes_weak_SOURCES = \ test_crypto_aes_weak.c test_crypto_aes_weak_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(LIBGCRYPT_LIBS) test_crypto_crc_SOURCES = \ test_crypto_crc.c test_crypto_crc_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_crypto_hash_SOURCES = \ test_crypto_hash.c test_crypto_hash_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_crypto_hkdf_SOURCES = \ test_crypto_hkdf.c test_crypto_hkdf_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_crypto_ksk_SOURCES = \ test_crypto_ksk.c test_crypto_ksk_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_crypto_random_SOURCES = \ test_crypto_random.c test_crypto_random_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_crypto_rsa_SOURCES = \ test_crypto_rsa.c test_crypto_rsa_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_disk_SOURCES = \ test_disk.c test_disk_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_getopt_SOURCES = \ test_getopt.c test_getopt_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_connection_SOURCES = \ test_connection.c test_connection_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_connection_addressing_SOURCES = \ test_connection_addressing.c test_connection_addressing_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_connection_receive_cancel_SOURCES = \ test_connection_receive_cancel.c test_connection_receive_cancel_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_connection_timeout_SOURCES = \ test_connection_timeout.c test_connection_timeout_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_connection_timeout_no_connect_SOURCES = \ test_connection_timeout_no_connect.c test_connection_timeout_no_connect_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_connection_transmit_cancel_SOURCES = \ test_connection_transmit_cancel.c test_connection_transmit_cancel_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_os_network_SOURCES = \ test_os_network.c test_os_network_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_os_priority_SOURCES = \ test_os_priority.c test_os_priority_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_peer_SOURCES = \ test_peer.c test_peer_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_plugin_SOURCES = \ test_plugin.c test_plugin_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_program_SOURCES = \ test_program.c test_program_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_pseudonym_SOURCES = \ test_pseudonym.c test_pseudonym_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_resolver_api_SOURCES = \ test_resolver_api.c test_resolver_api_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_scheduler_SOURCES = \ test_scheduler.c test_scheduler_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_scheduler_delay_SOURCES = \ test_scheduler_delay.c test_scheduler_delay_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_server_mst_interrupt_SOURCES = \ test_server_mst_interrupt.c test_server_mst_interrupt_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_server_SOURCES = \ test_server.c test_server_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_server_disconnect_SOURCES = \ test_server_disconnect.c test_server_disconnect_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_server_with_client_SOURCES = \ test_server_with_client.c test_server_with_client_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_server_with_client_unix_SOURCES = \ test_server_with_client_unix.c test_server_with_client_unix_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_service_SOURCES = \ test_service.c test_service_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_strings_SOURCES = \ test_strings.c test_strings_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_time_SOURCES = \ test_time.c test_time_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_speedup_SOURCES = \ test_speedup.c test_speedup_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la perf_crypto_hash_SOURCES = \ perf_crypto_hash.c perf_crypto_hash_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ test_configuration_data.conf \ test_program_data.conf \ test_pseudonym_data.conf \ test_resolver_api_data.conf \ test_service_data.conf \ test_speedup_data.conf gnunet-0.9.3/src/util/test_connection_transmit_cancel.c0000644000175000017500000000507411760502550020307 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_connection_transmit_cancel.c * @brief tests for connection.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_connection_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" #define VERBOSE GNUNET_NO #define PORT 12435 static struct GNUNET_CONFIGURATION_Handle *cfg; static size_t not_run (void *cls, size_t size, void *buf) { GNUNET_assert (0); return 0; } static void task_transmit_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { int *ok = cls; struct GNUNET_CONNECTION_TransmitHandle *th; struct GNUNET_CONNECTION_Handle *csock; csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT); GNUNET_assert (csock != NULL); th = GNUNET_CONNECTION_notify_transmit_ready (csock, 12, GNUNET_TIME_UNIT_MINUTES, ¬_run, cls); GNUNET_assert (NULL != th); GNUNET_CONNECTION_notify_transmit_ready_cancel (th); GNUNET_CONNECTION_destroy (csock); *ok = 0; } /** * Main method, starts scheduler with task_timeout. */ static int check_transmit_cancel () { int ok; ok = 1; cfg = GNUNET_CONFIGURATION_create (); GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", "localhost"); GNUNET_SCHEDULER_run (&task_transmit_cancel, &ok); GNUNET_CONFIGURATION_destroy (cfg); return ok; } int main (int argc, char *argv[]) { int ret = 0; GNUNET_log_setup ("test_connection_transmit_cancel", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret += check_transmit_cancel (); return ret; } /* end of test_connection_transmit_cancel.c */ gnunet-0.9.3/src/util/test_resolver_api.c0000644000175000017500000002615011760502550015412 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file resolver/test_resolver_api.c * @brief testcase for resolver_api.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_resolver_service.h" #include "resolver.h" #define VERBOSE GNUNET_NO /** * Using DNS root servers to check gnunet's resolver service * a.root-servers.net <-> 198.41.0.4 is a fix 1:1 mapping that should not change over years * For more information have a look at IANA's website http://www.root-servers.org/ */ #define ROOTSERVER_NAME "a.root-servers.net" #define ROOTSERVER_IP "198.41.0.4" static void check_hostname (void *cls, const struct sockaddr *sa, socklen_t salen) { int *ok = cls; if (salen == 0) { (*ok) &= ~8; return; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Got IP address `%s' for our host.\n"), GNUNET_a2s (sa, salen)); } static void check_localhost_num (void *cls, const char *hostname) { int *ok = cls; if (hostname == NULL) return; if (0 == strcmp (hostname, "127.0.0.1")) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct hostname `%s'.\n", hostname); (*ok) &= ~4; } else { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Received invalid hostname `%s'.\n", hostname); GNUNET_break (0); } } static void check_localhost (void *cls, const char *hostname) { int *ok = cls; if (hostname == NULL) return; if (0 == strcmp (hostname, "localhost")) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct hostname `%s'.\n", hostname); (*ok) &= ~2; } else { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Received unexpected hostname `%s', expected `localhost' (this could be OK).\n", hostname); } } static void check_127 (void *cls, const struct sockaddr *sa, socklen_t salen) { int *ok = cls; const struct sockaddr_in *sai = (const struct sockaddr_in *) sa; if (sa == NULL) return; GNUNET_assert (sizeof (struct sockaddr_in) == salen); if (sai->sin_addr.s_addr == htonl (INADDR_LOOPBACK)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct address.\n"); (*ok) &= ~1; } else { char buf[INET_ADDRSTRLEN]; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Received incorrect address`%s'.\n", inet_ntop (AF_INET, &sai->sin_addr, buf, sizeof (buf))); GNUNET_break (0); } } static void check_local_fqdn (void *cls, const char *gnunet_fqdn) { int result = 0; struct hostent *host; char hostname[GNUNET_OS_get_hostname_max_length () + 1]; if (0 != gethostname (hostname, sizeof (hostname) - 1)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "gethostname"); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Resolving our FQDN `%s'\n"), hostname); host = gethostbyname (hostname); if (NULL == host) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not resolve our FQDN: %s %u\n"), hstrerror (h_errno), h_errno); return; } GNUNET_assert (0 != host); result = strcmp (host->h_name, gnunet_fqdn); if (0 != result) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Local resolved and resolver resolved fqdns are not equal\n"); } GNUNET_assert (0 == result); } static void check_rootserver_ip (void *cls, const struct sockaddr *sa, socklen_t salen) { int *ok = cls; const struct sockaddr_in *sai = (const struct sockaddr_in *) sa; if (sa == NULL) return; GNUNET_assert (sizeof (struct sockaddr_in) == salen); if (0 == strcmp (inet_ntoa (sai->sin_addr), ROOTSERVER_IP)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct rootserver ip address.\n"); (*ok) &= ~1; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received incorrect rootserver ip address.\n"); GNUNET_break (0); } } static void check_rootserver_name (void *cls, const char *hostname) { int *ok = cls; if (hostname == NULL) return; if (0 == strcmp (hostname, ROOTSERVER_NAME)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct rootserver hostname `%s'.\n", hostname); (*ok) &= ~2; } else { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Received invalid rootserver hostname `%s'.\n", hostname); GNUNET_break (0); } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { int *ok = cls; struct sockaddr_in sa; struct GNUNET_TIME_Relative timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30); int count_ips = 0; char *own_fqdn; memset (&sa, 0, sizeof (sa)); sa.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = (u_char) sizeof (sa); #endif sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK); /* * Looking up our own fqdn */ own_fqdn = GNUNET_RESOLVER_local_fqdn_get (); check_local_fqdn (NULL, own_fqdn); GNUNET_free_non_null (own_fqdn); /* * Testing non-local DNS resolution * DNS rootserver to test: a.root-servers.net - 198.41.0.4 */ const char *rootserver_name = ROOTSERVER_NAME; struct hostent *rootserver; rootserver = gethostbyname (rootserver_name); if (rootserver == NULL) { /* Error: resolving ip addresses does not work */ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("gethostbyname() could not lookup IP address: %s\n"), hstrerror (h_errno)); FPRINTF (stderr, "%s", "System seems to be off-line, will not run all DNS tests\n"); *ok = 0; /* mark test as passing anyway */ return; } /* Counting returned IP addresses */ while (rootserver->h_addr_list[count_ips] != NULL) count_ips++; if (count_ips > 1) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "IP received range for root name server, but a root name server has only 1 IP\n"); GNUNET_break (0); } /* Comparing to resolved address to the address the root name server should have */ if (strcmp (inet_ntoa (*(struct in_addr *) rootserver->h_addr_list[0]), ROOTSERVER_IP) != 0) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "IP received and IP for root name server differ\n"); GNUNET_break (0); } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "System's own forward name resolution is working\n"); /* Resolve the same using GNUNET */ GNUNET_RESOLVER_ip_get (ROOTSERVER_NAME, AF_INET, timeout, &check_rootserver_ip, cls); /* * Success: forward lookups work as expected * Next step: reverse lookups */ struct in_addr rootserver_addr; rootserver->h_name = ""; if (1 != inet_pton (AF_INET, ROOTSERVER_IP, &rootserver_addr)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not transform root name server IP address\n"); GNUNET_break (0); } rootserver = gethostbyaddr (&rootserver_addr, sizeof (rootserver_addr), AF_INET); if (rootserver == NULL) { /* Error: resolving IP addresses does not work */ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("gethostbyaddr() could not lookup hostname: %s\n"), hstrerror (h_errno)); GNUNET_break (0); } else { if (0 != strcmp (rootserver->h_name, ROOTSERVER_NAME)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received hostname and hostname for root name server differ\n"); GNUNET_break (0); } } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "System's own reverse name resolution is working\n"); /* Resolve the same using GNUNET */ memset (&sa, 0, sizeof (sa)); sa.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = (u_char) sizeof (sa); #endif #ifndef MINGW inet_aton (ROOTSERVER_IP, &sa.sin_addr); #else sa.sin_addr.S_un.S_addr = inet_addr (ROOTSERVER_IP); #endif GNUNET_RESOLVER_hostname_get ((const struct sockaddr *) &sa, sizeof (struct sockaddr), GNUNET_YES, timeout, &check_rootserver_name, cls); memset (&sa, 0, sizeof (sa)); sa.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = (u_char) sizeof (sa); #endif sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK); GNUNET_RESOLVER_ip_get ("localhost", AF_INET, timeout, &check_127, cls); GNUNET_RESOLVER_hostname_get ((const struct sockaddr *) &sa, sizeof (struct sockaddr), GNUNET_YES, timeout, &check_localhost, cls); GNUNET_RESOLVER_hostname_get ((const struct sockaddr *) &sa, sizeof (struct sockaddr), GNUNET_NO, timeout, &check_localhost_num, cls); GNUNET_RESOLVER_hostname_resolve (AF_UNSPEC, timeout, &check_hostname, cls); } static int check () { int ok = 1 + 2 + 4 + 8; char *fn; char *pfx; struct GNUNET_OS_Process *proc; char *const argv[] = { "test-resolver-api", "-c", "test_resolver_api_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; pfx = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR); GNUNET_asprintf (&fn, "%s%cgnunet-service-resolver", pfx, DIR_SEPARATOR); GNUNET_free (pfx); proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, fn, "gnunet-service-resolver", #if VERBOSE "-L", "DEBUG", #endif "-c", "test_resolver_api_data.conf", NULL); GNUNET_assert (NULL != proc); GNUNET_free (fn); GNUNET_assert (GNUNET_OK == GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-resolver-api", "nohelp", options, &run, &ok)); if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); ok = 1; } GNUNET_OS_process_wait (proc); GNUNET_OS_process_destroy (proc); proc = NULL; if (ok != 0) FPRINTF (stderr, "Missed some resolutions: %u\n", ok); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-resolver-api", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); return ret; } /* end of test_resolver_api.c */ gnunet-0.9.3/src/util/container_slist.c0000644000175000017500000002300211760502550015052 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/container_slist.c * @brief Implementation of a singly-linked list * @author Nils Durner */ #include "platform.h" #include "gnunet_container_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) /** * Element in our linked list. */ struct GNUNET_CONTAINER_SList_Elem { /** * This is a linked list. */ struct GNUNET_CONTAINER_SList_Elem *next; /** * Application data stored at this element. */ void *elem; /** * Number of bytes stored in elem. */ size_t len; /** * Disposition of the element. */ enum GNUNET_CONTAINER_SListDisposition disp; }; /** * Handle to a singly linked list */ struct GNUNET_CONTAINER_SList { /** * Head of the linked list. */ struct GNUNET_CONTAINER_SList_Elem *head; /** * Tail of the linked list. */ struct GNUNET_CONTAINER_SList_Elem *tail; /** * Number of elements in the list. */ unsigned int length; }; /** * Create a new element that is to be inserted into the list * @internal * @param disp memory disposition * @param buf payload buffer * @param len length of the buffer * @return a new element */ static struct GNUNET_CONTAINER_SList_Elem * create_elem (enum GNUNET_CONTAINER_SListDisposition disp, const void *buf, size_t len) { struct GNUNET_CONTAINER_SList_Elem *e; if (disp == GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT) { e = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_SList_Elem) + len); memcpy (&e[1], buf, len); e->elem = (void *) &e[1]; } else { e = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_SList_Elem)); e->elem = (void *) buf; } e->disp = disp; e->len = len; return e; } /** * Add a new element to the list * @param l list * @param disp memory disposition * @param buf payload buffer * @param len length of the buffer */ void GNUNET_CONTAINER_slist_add (struct GNUNET_CONTAINER_SList *l, enum GNUNET_CONTAINER_SListDisposition disp, const void *buf, size_t len) { struct GNUNET_CONTAINER_SList_Elem *e; e = create_elem (disp, buf, len); e->next = l->head; l->head = e; if (l->tail == NULL) l->tail = e; l->length++; } /** * Add a new element to the end of the list * @param l list * @param disp memory disposition * @param buf payload buffer * @param len length of the buffer */ void GNUNET_CONTAINER_slist_add_end (struct GNUNET_CONTAINER_SList *l, enum GNUNET_CONTAINER_SListDisposition disp, const void *buf, size_t len) { struct GNUNET_CONTAINER_SList_Elem *e; e = create_elem (disp, buf, len); if (l->tail != NULL) l->tail->next = e; if (l->head == NULL) l->head = e; l->tail = e; l->length++; } /** * Append a singly linked list to another * @param dst list to append to * @param src source */ void GNUNET_CONTAINER_slist_append (struct GNUNET_CONTAINER_SList *dst, struct GNUNET_CONTAINER_SList *src) { struct GNUNET_CONTAINER_SList_Iterator i; for (i = GNUNET_CONTAINER_slist_begin (src); GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES; GNUNET_CONTAINER_slist_next (&i)) { GNUNET_CONTAINER_slist_add (dst, (i.elem->disp == GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC) ? GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC : GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, i.elem->elem, i.elem->len); } GNUNET_CONTAINER_slist_iter_destroy (&i); } /** * Create a new singly linked list * @return the new list */ struct GNUNET_CONTAINER_SList * GNUNET_CONTAINER_slist_create () { return GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_SList)); } /** * Destroy a singly linked list * @param l the list to be destroyed */ void GNUNET_CONTAINER_slist_destroy (struct GNUNET_CONTAINER_SList *l) { GNUNET_CONTAINER_slist_clear (l); GNUNET_free (l); } /** * Return the beginning of a list * @param l list * @return iterator pointing to the beginning */ struct GNUNET_CONTAINER_SList_Iterator GNUNET_CONTAINER_slist_begin (struct GNUNET_CONTAINER_SList *l) { struct GNUNET_CONTAINER_SList_Iterator ret; memset (&ret, 0, sizeof (ret)); ret.elem = l->head; ret.list = l; return ret; } /** * Clear a list * @param l list */ void GNUNET_CONTAINER_slist_clear (struct GNUNET_CONTAINER_SList *l) { struct GNUNET_CONTAINER_SList_Elem *e; struct GNUNET_CONTAINER_SList_Elem *n; e = l->head; while (e != NULL) { n = e->next; if (e->disp == GNUNET_CONTAINER_SLIST_DISPOSITION_DYNAMIC) GNUNET_free (e->elem); GNUNET_free (e); e = n; } l->head = NULL; l->tail = NULL; l->length = 0; } /** * Check if a list contains a certain element * @param l list * @param buf payload buffer to find * @param len length of the payload (number of bytes in buf) * * @return GNUNET_YES if found, GNUNET_NO otherwise */ int GNUNET_CONTAINER_slist_contains (const struct GNUNET_CONTAINER_SList *l, const void *buf, size_t len) { struct GNUNET_CONTAINER_SList_Elem *e; for (e = l->head; e != NULL; e = e->next) if ((e->len == len) && (memcmp (buf, e->elem, len) == 0)) return GNUNET_YES; return GNUNET_NO; } typedef int (*Comparator)(const void *, size_t, const void *, size_t); /** * Check if a list contains a certain element * * @param l list * @param buf payload buffer to find * @param len length of the payload (number of bytes in buf) * @param compare comparison function, should return 0 if compared elements match * * @return NULL if the 'buf' could not be found, pointer to the * list element, if found */ void * GNUNET_CONTAINER_slist_contains2 (const struct GNUNET_CONTAINER_SList *l, const void *buf, size_t len, Comparator compare) { struct GNUNET_CONTAINER_SList_Elem *e; for (e = l->head; e != NULL; e = e->next) if ((e->len == len) && (*compare)(buf, len, e->elem, e->len) == 0) return e->elem; return NULL; } /** * Count the elements of a list * @param l list * @return number of elements in the list */ int GNUNET_CONTAINER_slist_count (const struct GNUNET_CONTAINER_SList *l) { return l->length; } /** * Remove an element from the list * * @param i iterator that points to the element to be removed */ void GNUNET_CONTAINER_slist_erase (struct GNUNET_CONTAINER_SList_Iterator *i) { struct GNUNET_CONTAINER_SList_Elem *next; next = i->elem->next; if (i->last != NULL) i->last->next = next; else i->list->head = next; if (next == NULL) i->list->tail = i->last; if (i->elem->disp == GNUNET_CONTAINER_SLIST_DISPOSITION_DYNAMIC) GNUNET_free (i->elem->elem); GNUNET_free (i->elem); i->list->length--; i->elem = next; } /** * Insert an element into a list at a specific position * @param before where to insert the new element * @param disp memory disposition * @param buf payload buffer * @param len length of the payload */ void GNUNET_CONTAINER_slist_insert (struct GNUNET_CONTAINER_SList_Iterator *before, enum GNUNET_CONTAINER_SListDisposition disp, const void *buf, size_t len) { struct GNUNET_CONTAINER_SList_Elem *e; e = create_elem (disp, buf, len); e->next = before->elem; if (before->last != NULL) before->last->next = e; else before->list->head = e; if (e->next == NULL) before->list->tail = e; before->list->length++; } /** * Advance an iterator to the next element * @param i iterator * @return GNUNET_YES on success, GNUNET_NO if the end has been reached */ int GNUNET_CONTAINER_slist_next (struct GNUNET_CONTAINER_SList_Iterator *i) { i->last = i->elem; i->elem = i->elem->next; return (i->elem != NULL) ? GNUNET_YES : GNUNET_NO; } /** * Check if an iterator points beyond the end of a list * * @param i iterator * @return GNUNET_YES if the end has been reached, GNUNET_NO if the iterator * points to a valid element */ int GNUNET_CONTAINER_slist_end (struct GNUNET_CONTAINER_SList_Iterator *i) { return (i->elem == NULL) ? GNUNET_YES : GNUNET_NO; } /** * Retrieve the element at a specific position in a list * @param i iterator * @param len payload length * @return payload */ void * GNUNET_CONTAINER_slist_get (const struct GNUNET_CONTAINER_SList_Iterator *i, size_t * len) { if (len) *len = i->elem->len; return i->elem->elem; } /** * Release an iterator * @param i iterator */ void GNUNET_CONTAINER_slist_iter_destroy (struct GNUNET_CONTAINER_SList_Iterator *i) { } /* end of container_slist.c */ gnunet-0.9.3/src/util/getopt.c0000644000175000017500000010044611760502551013165 00000000000000/* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu before changing it! Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc. NOTE: The canonical source of this file is maintained with the GNU C Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. This code was heavily modified for GNUnet. Copyright (C) 2006 Christian Grothoff */ /** * @file util/getopt.c * @brief GNU style option parsing * * TODO: get rid of statics (make reentrant) and * replace main GNU getopt parser with one that * actually fits our API. */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_getopt_lib.h" #ifdef VMS #include #if HAVE_STRING_H - 0 #include #endif #endif #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) #if defined (WIN32) && !defined (__CYGWIN32__) /* It's not Unix, really. See? Capital letters. */ #include #define getpid() GetCurrentProcessId() #endif #ifndef _ /* This is for other GNU distributions with internationalized messages. When compiling libc, the _ macro is predefined. */ #ifdef HAVE_LIBINTL_H #include #define _(msgid) gettext (msgid) #else #define _(msgid) (msgid) #endif #endif /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct GNoption' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `GNoptarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct GNoption { const char *name; /* has_arg can't be an enum because some compilers complain about * type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ static char *GNoptarg = NULL; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `GNoptind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* 1003.2 says this must be 1 before any call. */ static int GNoptind = 1; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We GNUNET_CRYPTO_random_permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect GNoptions and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return -1 with `GNoptind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; /* Value of POSIXLY_CORRECT environment variable. */ static char *posixly_correct; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ #include #define my_index strchr #else /* Avoid depending on library functions or files whose names are inconsistent. */ char * getenv (); static char * my_index (const char *str, int chr) { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } /* If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare it. */ #ifdef __GNUC__ /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that was here before. */ #if !defined (__STDC__) || !__STDC__ /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ extern int strlen (const char *); #endif /* not __STDC__ */ #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; #ifdef _LIBC /* Bash 2.0 gives us an environment variable containing flags indicating ARGV elements that should not be considered arguments. */ /* Defined in getopt_init.c */ extern char *__getopt_nonoption_flags; static int nonoption_flags_max_len; static int nonoption_flags_len; static int original_argc; static char *const *original_argv; extern pid_t __libc_pid; /* Make sure the environment variable bash 2.0 puts in the environment is valid for the getopt call we must make sure that the ARGV passed to getopt is that one passed to the process. */ static void GNUNET_UNUSED store_args_and_env (int argc, char *const *argv) { /* XXX This is no good solution. We should rather copy the args so * that we can compare them later. But we must not use malloc(3). */ original_argc = argc; original_argv = argv; } text_set_element (__libc_subinit, store_args_and_env); #define SWAP_FLAGS(ch1, ch2) \ if (nonoption_flags_len > 0) \ { \ char __tmp = __getopt_nonoption_flags[ch1]; \ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ __getopt_nonoption_flags[ch2] = __tmp; \ } #else /* !_LIBC */ #define SWAP_FLAGS(ch1, ch2) #endif /* _LIBC */ /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,GNoptind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ #if defined (__STDC__) && __STDC__ static void exchange (char **); #endif static void exchange (char **argv) { int bottom = first_nonopt; int middle = last_nonopt; int top = GNoptind; char *tem; /* Exchange the shorter segment with the far end of the longer segment. * That puts the shorter segment into the right place. * It leaves the longer segment in the right place overall, * but it consists of two parts that need to be swapped next. */ #ifdef _LIBC /* First make sure the handling of the `__getopt_nonoption_flags' * string can work normally. Our top argument must be in the range * of the string. */ if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) { /* We must extend the array. The user plays games with us and * presents new arguments. */ char *new_str = malloc (top + 1); if (new_str == NULL) nonoption_flags_len = nonoption_flags_max_len = 0; else { memcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len); memset (&new_str[nonoption_flags_max_len], '\0', top + 1 - nonoption_flags_max_len); nonoption_flags_max_len = top + 1; __getopt_nonoption_flags = new_str; } } #endif while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; SWAP_FLAGS (bottom + i, middle + i); } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ first_nonopt += (GNoptind - last_nonopt); last_nonopt = GNoptind; } /* Initialize the internal data when the first call is made. */ #if defined (__STDC__) && __STDC__ static const char * _getopt_initialize (int, char *const *, const char *); #endif static const char * _getopt_initialize (int argc, char *const *argv, const char *optstring) { /* Start processing options with ARGV-element 1 (since ARGV-element 0 * is the program name); the sequence of previously skipped * non-option ARGV-elements is empty. */ first_nonopt = last_nonopt = GNoptind; nextchar = NULL; posixly_correct = getenv ("POSIXLY_CORRECT"); /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else if (posixly_correct != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; #ifdef _LIBC if (posixly_correct == NULL && argc == original_argc && argv == original_argv) { if (nonoption_flags_max_len == 0) { if (__getopt_nonoption_flags == NULL || __getopt_nonoption_flags[0] == '\0') nonoption_flags_max_len = -1; else { const char *orig_str = __getopt_nonoption_flags; int len = nonoption_flags_max_len = strlen (orig_str); if (nonoption_flags_max_len < argc) nonoption_flags_max_len = argc; __getopt_nonoption_flags = (char *) malloc (nonoption_flags_max_len); if (__getopt_nonoption_flags == NULL) nonoption_flags_max_len = -1; else { memcpy (__getopt_nonoption_flags, orig_str, len); memset (&__getopt_nonoption_flags[len], '\0', nonoption_flags_max_len - len); } } } nonoption_flags_len = nonoption_flags_max_len; } else nonoption_flags_len = 0; #endif return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `GNoptind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns -1. Then `GNoptind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `GNopterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `GNoptarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `GNoptarg', otherwise `GNoptarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we GNUNET_CRYPTO_random_permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct GNoption' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ static int GN_getopt_internal (int argc, char *const *argv, const char *optstring, const struct GNoption *longopts, int *longind, int long_only) { static int __getopt_initialized = 0; static int GNopterr = 1; GNoptarg = NULL; if (GNoptind == 0 || !__getopt_initialized) { if (GNoptind == 0) GNoptind = 1; /* Don't scan ARGV[0], the program name. */ optstring = _getopt_initialize (argc, argv, optstring); __getopt_initialized = 1; } /* Test whether ARGV[GNoptind] points to a non-option argument. * Either it does not have option syntax, or there is an environment flag * from the shell indicating it is not an option. The later information * is only used when the used in the GNU libc. */ #ifdef _LIBC #define NONOPTION_P (argv[GNoptind][0] != '-' || argv[GNoptind][1] == '\0' \ || (GNoptind < nonoption_flags_len \ && __getopt_nonoption_flags[GNoptind] == '1')) #else #define NONOPTION_P (argv[GNoptind][0] != '-' || argv[GNoptind][1] == '\0') #endif if (nextchar == NULL || *nextchar == '\0') { /* Advance to the next ARGV-element. */ /* Give FIRST_NONOPT & LAST_NONOPT rational values if GNoptind has been * moved back by the user (who may also have changed the arguments). */ if (last_nonopt > GNoptind) last_nonopt = GNoptind; if (first_nonopt > GNoptind) first_nonopt = GNoptind; if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, * exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != GNoptind) exchange ((char **) argv); else if (last_nonopt != GNoptind) first_nonopt = GNoptind; /* Skip any additional non-options * and extend the range of non-options previously skipped. */ while (GNoptind < argc && NONOPTION_P) GNoptind++; last_nonopt = GNoptind; } /* The special ARGV-element `--' means premature end of options. * Skip it like a null option, * then exchange with previous non-options as if it were an option, * then skip everything else like a non-option. */ if (GNoptind != argc && !strcmp (argv[GNoptind], "--")) { GNoptind++; if (first_nonopt != last_nonopt && last_nonopt != GNoptind) exchange ((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = GNoptind; last_nonopt = argc; GNoptind = argc; } /* If we have done all the ARGV-elements, stop the scan * and back over any non-options that we skipped and permuted. */ if (GNoptind == argc) { /* Set the next-arg-index to point at the non-options * that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) GNoptind = first_nonopt; return -1; } /* If we have come to a non-option and did not permute it, * either stop the scan or describe it to the caller and pass it by. */ if (NONOPTION_P) { if (ordering == REQUIRE_ORDER) return -1; GNoptarg = argv[GNoptind++]; return 1; } /* We have found another option-ARGV-element. * Skip the initial punctuation. */ nextchar = (argv[GNoptind] + 1 + (longopts != NULL && argv[GNoptind][1] == '-')); } /* Decode the current option-ARGV-element. */ /* Check whether the ARGV-element is a long option. * * If long_only and the ARGV-element has the form "-f", where f is * a valid short option, don't consider it an abbreviated form of * a long option that starts with f. Otherwise there would be no * way to give the -f short option. * * On the other hand, if there's a long option "fubar" and * the ARGV-element is "-fu", do consider that an abbreviation of * the long option, just like "--fu", and not "-f" with arg "u". * * This distinction seems to be the most useful approach. */ if (longopts != NULL && (argv[GNoptind][1] == '-' || (long_only && (argv[GNoptind][2] || !my_index (optstring, argv[GNoptind][1]))))) { char *nameend; const struct GNoption *p; const struct GNoption *pfound = NULL; int exact = 0; int ambig = 0; int indfound = -1; int option_index; for (nameend = nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match * or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == (unsigned int) strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (GNopterr) FPRINTF (stderr, _("%s: option `%s' is ambiguous\n"), argv[0], argv[GNoptind]); nextchar += strlen (nextchar); GNoptind++; return '?'; } if (pfound != NULL) { option_index = indfound; GNoptind++; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't * allow it to be used on enums. */ if (pfound->has_arg) GNoptarg = nameend + 1; else { if (GNopterr) { if (argv[GNoptind - 1][1] == '-') /* --option */ FPRINTF (stderr, _("%s: option `--%s' does not allow an argument\n"), argv[0], pfound->name); else /* +option or -option */ FPRINTF (stderr, _("%s: option `%c%s' does not allow an argument\n"), argv[0], argv[GNoptind - 1][0], pfound->name); } nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (GNoptind < argc) { GNoptarg = argv[GNoptind++]; } else { if (GNopterr) { FPRINTF (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[GNoptind - 1]); } nextchar += strlen (nextchar); return (optstring[0] == ':') ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, * or the option starts with '--' or is not a valid short * option, then it's an error. * Otherwise interpret it as a short option. */ if (!long_only || argv[GNoptind][1] == '-' || my_index (optstring, *nextchar) == NULL) { if (GNopterr) { if (argv[GNoptind][1] == '-') /* --option */ FPRINTF (stderr, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); else /* +option or -option */ FPRINTF (stderr, _("%s: unrecognized option `%c%s'\n"), argv[0], argv[GNoptind][0], nextchar); } nextchar = (char *) ""; GNoptind++; return '?'; } } /* Look at and handle the next short option-character. */ { char c = *nextchar++; char *temp = my_index (optstring, c); /* Increment `GNoptind' when we start to process its last character. */ if (*nextchar == '\0') ++GNoptind; if (temp == NULL || c == ':') { if (GNopterr) { if (posixly_correct) /* 1003.2 specifies the format of this message. */ FPRINTF (stderr, _("%s: illegal option -- %c\n"), argv[0], c); else FPRINTF (stderr, _("%s: invalid option -- %c\n"), argv[0], c); } return '?'; } /* Convenience. Treat POSIX -W foo same as long option --foo */ if (temp[0] == 'W' && temp[1] == ';') { char *nameend; const struct GNoption *p; const struct GNoption *pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; int option_index; /* This is an option that requires an argument. */ if (*nextchar != '\0') { GNoptarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, * we must advance to the next element now. */ GNoptind++; } else if (GNoptind == argc) { if (GNopterr) { /* 1003.2 specifies the format of this message. */ FPRINTF (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } if (optstring[0] == ':') c = ':'; else c = '?'; return c; } else /* We already incremented `GNoptind' once; * increment it again when taking next ARGV-elt as argument. */ GNoptarg = argv[GNoptind++]; /* GNoptarg is now the argument, see if it's in the * table of longopts. */ for (nextchar = nameend = GNoptarg; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match * or abbreviated matches. */ if (longopts != NULL) for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (GNopterr) FPRINTF (stderr, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[GNoptind]); nextchar += strlen (nextchar); GNoptind++; return '?'; } if (pfound != NULL) { option_index = indfound; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't * allow it to be used on enums. */ if (pfound->has_arg) GNoptarg = nameend + 1; else { if (GNopterr) FPRINTF (stderr, _("\ %s: option `-W %s' does not allow an argument\n"), argv[0], pfound->name); nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (GNoptind < argc) GNoptarg = argv[GNoptind++]; else { if (GNopterr) FPRINTF (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[GNoptind - 1]); nextchar += strlen (nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } nextchar = NULL; return 'W'; /* Let the application handle it. */ } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { GNoptarg = nextchar; GNoptind++; } else GNoptarg = NULL; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { GNoptarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, * we must advance to the next element now. */ GNoptind++; } else if (GNoptind == argc) { if (GNopterr) { /* 1003.2 specifies the format of this message. */ FPRINTF (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `GNoptind' once; * increment it again when taking next ARGV-elt as argument. */ GNoptarg = argv[GNoptind++]; nextchar = NULL; } } return c; } } static int GNgetopt_long (int argc, char *const *argv, const char *options, const struct GNoption *long_options, int *opt_index) { return GN_getopt_internal (argc, argv, options, long_options, opt_index, 0); } /* ******************** now the GNUnet specific modifications... ********************* */ /** * Parse the command line. * * @param binaryOptions Name of application with option summary * @param allOptions defined options and handlers * @param argc number of arguments * @param argv actual arguments * @return index into argv with first non-option * argument, or -1 on error */ int GNUNET_GETOPT_run (const char *binaryOptions, const struct GNUNET_GETOPT_CommandLineOption *allOptions, unsigned int argc, char *const *argv) { struct GNoption *long_options; struct GNUNET_GETOPT_CommandLineProcessorContext clpc; int count; int i; char *shorts; int spos; int cont; int c; GNUNET_assert (argc > 0); GNoptind = 0; clpc.binaryName = argv[0]; clpc.binaryOptions = binaryOptions; clpc.allOptions = allOptions; clpc.argv = argv; clpc.argc = argc; count = 0; while (allOptions[count].name != NULL) count++; long_options = GNUNET_malloc (sizeof (struct GNoption) * (count + 1)); shorts = GNUNET_malloc (count * 2 + 1); spos = 0; for (i = 0; i < count; i++) { long_options[i].name = allOptions[i].name; long_options[i].has_arg = allOptions[i].require_argument; long_options[i].flag = NULL; long_options[i].val = allOptions[i].shortName; shorts[spos++] = allOptions[i].shortName; if (allOptions[i].require_argument != 0) shorts[spos++] = ':'; } long_options[count].name = NULL; long_options[count].has_arg = 0; long_options[count].flag = NULL; long_options[count].val = '\0'; shorts[spos] = '\0'; cont = GNUNET_OK; /* main getopt loop */ while (cont == GNUNET_OK) { int option_index = 0; c = GNgetopt_long (argc, argv, shorts, long_options, &option_index); if (c == GNUNET_SYSERR) break; /* No more flags to process */ for (i = 0; i < count; i++) { clpc.currentArgument = GNoptind - 1; if ((char) c == allOptions[i].shortName) { cont = allOptions[i].processor (&clpc, allOptions[i].scls, allOptions[i].name, GNoptarg); break; } } if (i == count) { FPRINTF (stderr, _("Use %s to get a list of options.\n"), "--help"); cont = GNUNET_SYSERR; } } GNUNET_free (shorts); GNUNET_free (long_options); if (cont == GNUNET_SYSERR) return GNUNET_SYSERR; return GNoptind; } /* end of getopt.c */ gnunet-0.9.3/src/util/test_container_slist.c0000644000175000017500000001202111760502551016111 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_container_slist.c * @brief Testcases for singly linked lists * @author Nils Durner */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_container_lib.h" int main (int argc, char *argv[]) { struct GNUNET_CONTAINER_SList *l; struct GNUNET_CONTAINER_SList_Iterator it; unsigned int i; int *ip; unsigned int j; size_t s; const void *p; GNUNET_log_setup ("test-container-slist", "WARNING", NULL); l = GNUNET_CONTAINER_slist_create (); GNUNET_assert (l != NULL); GNUNET_assert (GNUNET_CONTAINER_slist_count (l) == 0); for (i = 0; i < 100; i++) GNUNET_CONTAINER_slist_add (l, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, &i, sizeof (i)); GNUNET_assert (GNUNET_CONTAINER_slist_count (l) == 100); for (it = GNUNET_CONTAINER_slist_begin (l), i = 99; GNUNET_CONTAINER_slist_end (&it) != GNUNET_YES; GNUNET_CONTAINER_slist_next (&it), i--) { p = GNUNET_CONTAINER_slist_get (&it, &s); if ((p == NULL) || (i != (j = *(int *) p)) || (s != sizeof (i))) { GNUNET_CONTAINER_slist_iter_destroy (&it); GNUNET_assert (0); } j *= 2; GNUNET_CONTAINER_slist_insert (&it, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, &j, sizeof (j)); } GNUNET_assert (GNUNET_CONTAINER_slist_count (l) == 200); i = 198; GNUNET_assert (GNUNET_CONTAINER_slist_contains (l, &i, sizeof (i))); for (it = GNUNET_CONTAINER_slist_begin (l); GNUNET_CONTAINER_slist_end (&it) != GNUNET_YES;) { p = GNUNET_CONTAINER_slist_get (&it, &s); GNUNET_assert (p != NULL); GNUNET_assert (s == sizeof (i)); i = *(int *) p; GNUNET_assert (GNUNET_CONTAINER_slist_next (&it) == GNUNET_YES); GNUNET_assert (GNUNET_CONTAINER_slist_end (&it) != GNUNET_YES); p = GNUNET_CONTAINER_slist_get (&it, &s); GNUNET_assert (p != NULL); GNUNET_assert (s == sizeof (j)); j = *(int *) p; GNUNET_assert (j * 2 == i); GNUNET_CONTAINER_slist_erase (&it); } GNUNET_assert (GNUNET_CONTAINER_slist_count (l) == 100); i = 99; GNUNET_assert (GNUNET_CONTAINER_slist_contains (l, &i, sizeof (i)) == GNUNET_NO); i = 198; GNUNET_assert (GNUNET_CONTAINER_slist_contains (l, &i, sizeof (i)) == GNUNET_YES); GNUNET_CONTAINER_slist_clear (l); GNUNET_assert (GNUNET_CONTAINER_slist_count (l) == 0); for (i = 0; i < 100; i++) GNUNET_CONTAINER_slist_add (l, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, &i, sizeof (i)); /*check slist_append */ GNUNET_CONTAINER_slist_append (l, l); GNUNET_assert (GNUNET_CONTAINER_slist_count (l) == 200); GNUNET_CONTAINER_slist_destroy (l); /*check slist_add_end */ l = GNUNET_CONTAINER_slist_create (); for (i = 0; i < 100; i++) GNUNET_CONTAINER_slist_add_end (l, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, &i, sizeof (i)); GNUNET_assert (GNUNET_CONTAINER_slist_count (l) == 100); for (it = GNUNET_CONTAINER_slist_begin (l), i = 0; GNUNET_CONTAINER_slist_end (&it) != GNUNET_YES; GNUNET_CONTAINER_slist_next (&it), i++) { p = GNUNET_CONTAINER_slist_get (&it, &s); if ((p == NULL) || (i != *(int *) p) || (s != sizeof (i))) { GNUNET_assert (0); } } GNUNET_CONTAINER_slist_destroy (l); /*check if disp = GNUNET_CONTAINER_SLIST_DISPOSITION_DYNAMIC */ l = GNUNET_CONTAINER_slist_create (); for (i = 0; i < 100; i++) { ip = GNUNET_malloc (sizeof (int)); *ip = i; GNUNET_CONTAINER_slist_add (l, GNUNET_CONTAINER_SLIST_DISPOSITION_DYNAMIC, ip, sizeof (int)); } //creat_add it = GNUNET_CONTAINER_slist_begin (l); p = GNUNET_CONTAINER_slist_get (&it, &s); GNUNET_assert (p != NULL); //slist_erase GNUNET_assert (GNUNET_CONTAINER_slist_next (&it) == GNUNET_YES); GNUNET_CONTAINER_slist_erase (&it); GNUNET_CONTAINER_slist_iter_destroy (&it); GNUNET_assert (GNUNET_CONTAINER_slist_count (l) == 99); //slist_clear GNUNET_CONTAINER_slist_clear (l); GNUNET_assert (GNUNET_CONTAINER_slist_count (l) == 0); GNUNET_CONTAINER_slist_destroy (l); return 0; } gnunet-0.9.3/src/util/crypto_ksk.c0000644000175000017500000004573711760502551014066 00000000000000/* This file is part of GNUnet. Copyright (C) 1994, 1996, 1998, 2001, 2002, 2003 Free Software Foundation, Inc. Copyright (C) 2004, 2005, 2006 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Note: This code is based on code from libgcrypt The code was adapted for GNUnet to support RSA-key generation based on weak, pseudo-random keys. Do NOT use to generate ordinary RSA keys! */ /** * @file util/crypto_ksk.c * @brief implementation of RSA-Key generation for KBlocks * (do NOT use for pseudonyms or hostkeys!) * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_crypto_lib.h" #include "gnunet_os_lib.h" #include #include #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) /** * Log an error message at log-level 'level' that indicates * a failure of the command 'cmd' with the message given * by gcry_strerror(rc). */ #define LOG_GCRY(level, cmd, rc) do { LOG(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, gcry_strerror(rc)); } while(0); typedef struct { gcry_mpi_t n; /* public modulus */ gcry_mpi_t e; /* public exponent */ gcry_mpi_t d; /* exponent */ gcry_mpi_t p; /* prime p. */ gcry_mpi_t q; /* prime q. */ gcry_mpi_t u; /* inverse of p mod q. */ } KBlock_secret_key; /** * The private information of an RSA key pair. * NOTE: this must match the definition in crypto_rsa.c */ struct GNUNET_CRYPTO_RsaPrivateKey { gcry_sexp_t sexp; }; static void mpz_randomize (gcry_mpi_t n, unsigned int nbits, GNUNET_HashCode * rnd) { GNUNET_HashCode hc; GNUNET_HashCode tmp; int bits_per_hc = sizeof (GNUNET_HashCode) * 8; int cnt; int i; GNUNET_assert (nbits > 0); cnt = (nbits + bits_per_hc - 1) / bits_per_hc; gcry_mpi_set_ui (n, 0); tmp = *rnd; for (i = 0; i < cnt; i++) { int j; if (i > 0) GNUNET_CRYPTO_hash (&hc, sizeof (GNUNET_HashCode), &tmp); for (j = 0; j < sizeof (GNUNET_HashCode) / sizeof (uint32_t); j++) { #if HAVE_GCRY_MPI_LSHIFT gcry_mpi_lshift (n, n, sizeof (uint32_t) * 8); #else gcry_mpi_mul_ui (n, n, 1 << (sizeof (uint32_t) * 4)); gcry_mpi_mul_ui (n, n, 1 << (sizeof (uint32_t) * 4)); #endif gcry_mpi_add_ui (n, n, ntohl (((uint32_t *) & tmp)[j])); } hc = tmp; } GNUNET_CRYPTO_hash (&hc, sizeof (GNUNET_HashCode), rnd); i = gcry_mpi_get_nbits (n); while (i > nbits) gcry_mpi_clear_bit (n, --i); } static unsigned long mpz_trailing_zeroes (gcry_mpi_t n) { unsigned int idx, cnt; cnt = gcry_mpi_get_nbits (n); for (idx = 0; idx < cnt; idx++) { if (gcry_mpi_test_bit (n, idx) == 0) return idx; } return ULONG_MAX; } static void mpz_tdiv_q_2exp (gcry_mpi_t q, gcry_mpi_t n, unsigned int b) { gcry_mpi_t u, d; u = gcry_mpi_set_ui (NULL, 1); d = gcry_mpi_new (0); gcry_mpi_mul_2exp (d, u, b); gcry_mpi_div (q, NULL, n, d, 0); } /** * Return true if n is probably a prime */ static int is_prime (gcry_mpi_t n, int steps, GNUNET_HashCode * hc) { gcry_mpi_t x; gcry_mpi_t y; gcry_mpi_t z; gcry_mpi_t nminus1; gcry_mpi_t a2; gcry_mpi_t q; unsigned int i, j, k; int rc = 0; unsigned int nbits; x = gcry_mpi_new (0); y = gcry_mpi_new (0); z = gcry_mpi_new (0); nminus1 = gcry_mpi_new (0); a2 = gcry_mpi_set_ui (NULL, 2); nbits = gcry_mpi_get_nbits (n); gcry_mpi_sub_ui (nminus1, n, 1); /* Find q and k, so that n = 1 + 2^k * q . */ q = gcry_mpi_set (NULL, nminus1); k = mpz_trailing_zeroes (q); mpz_tdiv_q_2exp (q, q, k); for (i = 0; i < steps; i++) { if (!i) { gcry_mpi_set_ui (x, 2); } else { mpz_randomize (x, nbits - 1, hc); GNUNET_assert (gcry_mpi_cmp (x, nminus1) < 0); GNUNET_assert (gcry_mpi_cmp_ui (x, 1) > 0); } gcry_mpi_powm (y, x, q, n); if (gcry_mpi_cmp_ui (y, 1) && gcry_mpi_cmp (y, nminus1)) { for (j = 1; j < k && gcry_mpi_cmp (y, nminus1); j++) { gcry_mpi_powm (y, y, a2, n); if (!gcry_mpi_cmp_ui (y, 1)) goto leave; /* Not a prime. */ } if (gcry_mpi_cmp (y, nminus1)) goto leave; /* Not a prime. */ } } rc = 1; /* May be a prime. */ leave: gcry_mpi_release (x); gcry_mpi_release (y); gcry_mpi_release (z); gcry_mpi_release (nminus1); gcry_mpi_release (q); gcry_mpi_release (a2); return rc; } /** * If target != size, move target bytes to the * end of the size-sized buffer and zero out the * first target-size bytes. */ static void adjust (unsigned char *buf, size_t size, size_t target) { if (size < target) { memmove (&buf[target - size], buf, size); memset (buf, 0, target - size); } } static void gen_prime (gcry_mpi_t * ptest, unsigned int nbits, GNUNET_HashCode * hc) { /* Note: 2 is not included because it can be tested more easily by * looking at bit 0. The last entry in this list is marked by a zero */ static const uint16_t small_prime_numbers[] = { 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 0 }; #define DIM(v) (sizeof(v)/sizeof((v)[0])) static int no_of_small_prime_numbers = DIM (small_prime_numbers) - 1; gcry_mpi_t prime, pminus1, val_2, val_3, result; unsigned int i; unsigned int step; unsigned int mods[no_of_small_prime_numbers]; gcry_mpi_t tmp; gcry_mpi_t sp; GNUNET_assert (nbits >= 16); /* Make nbits fit into mpz_t implementation. */ val_2 = gcry_mpi_set_ui (NULL, 2); val_3 = gcry_mpi_set_ui (NULL, 3); prime = gcry_mpi_snew (0); result = gcry_mpi_new (0); pminus1 = gcry_mpi_new (0); *ptest = gcry_mpi_new (0); tmp = gcry_mpi_new (0); sp = gcry_mpi_new (0); while (1) { /* generate a random number */ mpz_randomize (prime, nbits, hc); /* Set high order bit to 1, set low order bit to 1. If we are * generating a secret prime we are most probably doing that * for RSA, to make sure that the modulus does have the * requested key size we set the 2 high order bits. */ gcry_mpi_set_bit (prime, nbits - 1); gcry_mpi_set_bit (prime, nbits - 2); gcry_mpi_set_bit (prime, 0); /* Calculate all remainders. */ for (i = 0; i < no_of_small_prime_numbers; i++) { size_t written; gcry_mpi_set_ui (sp, small_prime_numbers[i]); gcry_mpi_div (NULL, tmp, prime, sp, -1); mods[i] = 0; written = sizeof (unsigned int); GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG, (unsigned char *) &mods[i], written, &written, tmp)); adjust ((unsigned char *) &mods[i], written, sizeof (unsigned int)); mods[i] = ntohl (mods[i]); } /* Now try some primes starting with prime. */ for (step = 0; step < 20000; step += 2) { /* Check against all the small primes we have in mods. */ for (i = 0; i < no_of_small_prime_numbers; i++) { uint16_t x = small_prime_numbers[i]; while (mods[i] + step >= x) mods[i] -= x; if (!(mods[i] + step)) break; } if (i < no_of_small_prime_numbers) continue; /* Found a multiple of an already known prime. */ gcry_mpi_add_ui (*ptest, prime, step); if (!gcry_mpi_test_bit (*ptest, nbits - 2)) break; /* Do a fast Fermat test now. */ gcry_mpi_sub_ui (pminus1, *ptest, 1); gcry_mpi_powm (result, val_2, pminus1, *ptest); if ((!gcry_mpi_cmp_ui (result, 1)) && (is_prime (*ptest, 5, hc))) { /* Got it. */ gcry_mpi_release (sp); gcry_mpi_release (tmp); gcry_mpi_release (val_2); gcry_mpi_release (val_3); gcry_mpi_release (result); gcry_mpi_release (pminus1); gcry_mpi_release (prime); return; } } } } /** * Generate a key pair with a key of size NBITS. * @param sk where to store the key * @param nbits the number of bits to use * @param hc the HC to use for PRNG (modified!) */ static void generate_kblock_key (KBlock_secret_key *sk, unsigned int nbits, GNUNET_HashCode * hc) { gcry_mpi_t t1, t2; gcry_mpi_t phi; /* helper: (p-1)(q-1) */ gcry_mpi_t g; gcry_mpi_t f; /* make sure that nbits is even so that we generate p, q of equal size */ if ((nbits & 1)) nbits++; sk->e = gcry_mpi_set_ui (NULL, 257); sk->n = gcry_mpi_new (0); sk->p = gcry_mpi_new (0); sk->q = gcry_mpi_new (0); sk->d = gcry_mpi_new (0); sk->u = gcry_mpi_new (0); t1 = gcry_mpi_new (0); t2 = gcry_mpi_new (0); phi = gcry_mpi_new (0); g = gcry_mpi_new (0); f = gcry_mpi_new (0); do { do { gcry_mpi_release (sk->p); gcry_mpi_release (sk->q); gen_prime (&sk->p, nbits / 2, hc); gen_prime (&sk->q, nbits / 2, hc); if (gcry_mpi_cmp (sk->p, sk->q) > 0) /* p shall be smaller than q (for calc of u) */ gcry_mpi_swap (sk->p, sk->q); /* calculate the modulus */ gcry_mpi_mul (sk->n, sk->p, sk->q); } while (gcry_mpi_get_nbits (sk->n) != nbits); /* calculate Euler totient: phi = (p-1)(q-1) */ gcry_mpi_sub_ui (t1, sk->p, 1); gcry_mpi_sub_ui (t2, sk->q, 1); gcry_mpi_mul (phi, t1, t2); gcry_mpi_gcd (g, t1, t2); gcry_mpi_div (f, NULL, phi, g, 0); while (0 == gcry_mpi_gcd (t1, sk->e, phi)) { /* (while gcd is not 1) */ gcry_mpi_add_ui (sk->e, sk->e, 2); } /* calculate the secret key d = e^1 mod phi */ } while ((0 == gcry_mpi_invm (sk->d, sk->e, f)) || (0 == gcry_mpi_invm (sk->u, sk->p, sk->q))); gcry_mpi_release (t1); gcry_mpi_release (t2); gcry_mpi_release (phi); gcry_mpi_release (f); gcry_mpi_release (g); } GNUNET_NETWORK_STRUCT_BEGIN /** * Internal representation of the private key. */ struct KskRsaPrivateKeyBinaryEncoded { /** * Total size of the structure, in bytes, in big-endian! */ uint16_t len GNUNET_PACKED; uint16_t sizen GNUNET_PACKED; /* in big-endian! */ uint16_t sizee GNUNET_PACKED; /* in big-endian! */ uint16_t sized GNUNET_PACKED; /* in big-endian! */ uint16_t sizep GNUNET_PACKED; /* in big-endian! */ uint16_t sizeq GNUNET_PACKED; /* in big-endian! */ uint16_t sizedmp1 GNUNET_PACKED; /* in big-endian! */ uint16_t sizedmq1 GNUNET_PACKED; /* in big-endian! */ /* followed by the actual values */ }; GNUNET_NETWORK_STRUCT_END /** * Deterministically (!) create a hostkey using only the * given HashCode as input to the PRNG. */ static struct KskRsaPrivateKeyBinaryEncoded * makeKblockKeyInternal (const GNUNET_HashCode * hc) { KBlock_secret_key sk; GNUNET_HashCode hx; unsigned char *pbu[6]; gcry_mpi_t *pkv[6]; size_t sizes[6]; struct KskRsaPrivateKeyBinaryEncoded *retval; int i; size_t size; hx = *hc; generate_kblock_key (&sk, 1024, /* at least 10x as fast than 2048 bits * -- we simply cannot afford 2048 bits * even on modern hardware, and especially * not since clearly a dictionary attack * will still be much cheaper * than breaking a 1024 bit RSA key. * If an adversary can spend the time to * break a 1024 bit RSA key just to forge * a signature -- SO BE IT. [ CG, 6/2005 ] */ &hx); pkv[0] = &sk.n; pkv[1] = &sk.e; pkv[2] = &sk.d; pkv[3] = &sk.p; pkv[4] = &sk.q; pkv[5] = &sk.u; size = sizeof (struct KskRsaPrivateKeyBinaryEncoded); for (i = 0; i < 6; i++) { gcry_mpi_aprint (GCRYMPI_FMT_STD, &pbu[i], &sizes[i], *pkv[i]); size += sizes[i]; } GNUNET_assert (size < 65536); retval = GNUNET_malloc (size); retval->len = htons (size); i = 0; retval->sizen = htons (sizes[0]); memcpy (&((char *) &retval[1])[i], pbu[0], sizes[0]); i += sizes[0]; retval->sizee = htons (sizes[1]); memcpy (&((char *) &retval[1])[i], pbu[1], sizes[1]); i += sizes[1]; retval->sized = htons (sizes[2]); memcpy (&((char *) &retval[1])[i], pbu[2], sizes[2]); i += sizes[2]; /* swap p and q! */ retval->sizep = htons (sizes[4]); memcpy (&((char *) &retval[1])[i], pbu[4], sizes[4]); i += sizes[4]; retval->sizeq = htons (sizes[3]); memcpy (&((char *) &retval[1])[i], pbu[3], sizes[3]); i += sizes[3]; retval->sizedmp1 = htons (0); retval->sizedmq1 = htons (0); memcpy (&((char *) &retval[1])[i], pbu[5], sizes[5]); for (i = 0; i < 6; i++) { gcry_mpi_release (*pkv[i]); free (pbu[i]); } return retval; } /** * Entry in the KSK cache. */ struct KBlockKeyCacheLine { /** * Hash from which the key was generated. */ GNUNET_HashCode hc; /** * The encoded key. */ struct KskRsaPrivateKeyBinaryEncoded *pke; }; /** * Cached KSK keys so that we don't have to recompute them * all the time. */ static struct KBlockKeyCacheLine **cache; /** * Size of the 'cache' array. */ static unsigned int cacheSize; /** * Deterministically (!) create a hostkey using only the * given HashCode as input to the PRNG. * * @param hc hash code to generate the key from * @return corresponding private key; must not be freed! */ struct GNUNET_CRYPTO_RsaPrivateKey * GNUNET_CRYPTO_rsa_key_create_from_hash (const GNUNET_HashCode * hc) { struct KBlockKeyCacheLine *line; unsigned int i; for (i = 0; i < cacheSize; i++) if (0 == memcmp (hc, &cache[i]->hc, sizeof (GNUNET_HashCode))) return GNUNET_CRYPTO_rsa_decode_key ((const char*) cache[i]->pke, ntohs (cache[i]->pke->len)); line = GNUNET_malloc (sizeof (struct KBlockKeyCacheLine)); line->hc = *hc; line->pke = makeKblockKeyInternal (hc); GNUNET_array_grow (cache, cacheSize, cacheSize + 1); cache[cacheSize - 1] = line; return GNUNET_CRYPTO_rsa_decode_key ((const char*) line->pke, ntohs (line->pke->len)); } /** * Destructor that frees the KSK cache. */ void __attribute__ ((destructor)) GNUNET_CRYPTO_ksk_fini () { unsigned int i; for (i = 0; i < cacheSize; i++) { GNUNET_free (cache[i]->pke); GNUNET_free (cache[i]); } GNUNET_array_grow (cache, cacheSize, 0); } /* end of crypto_ksk.c */ gnunet-0.9.3/src/util/scheduler.c0000644000175000017500000013325611760676452013662 00000000000000/* This file is part of GNUnet (C) 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/scheduler.c * @brief schedule computations using continuation passing style * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_os_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_signal_lib.h" #include "gnunet_time_lib.h" #include "disk.h" #define LOG(kind,...) GNUNET_log_from (kind, "util-scheduler", __VA_ARGS__) #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-scheduler", syscall) #ifdef LINUX #include "execinfo.h" /** * Use lsof to generate file descriptor reports on select error? * (turn off for stable releases). */ #define USE_LSOF GNUNET_NO /** * Obtain trace information for all scheduler calls that schedule tasks. */ #define EXECINFO GNUNET_NO /** * Check each file descriptor before adding */ #define DEBUG_FDS GNUNET_NO /** * Depth of the traces collected via EXECINFO. */ #define MAX_TRACE_DEPTH 50 #endif /** * Should we figure out which tasks are delayed for a while * before they are run? (Consider using in combination with EXECINFO). */ #define PROFILE_DELAYS GNUNET_NO /** * Task that were in the queue for longer than this are reported if * PROFILE_DELAYS is active. */ #define DELAY_THRESHOLD GNUNET_TIME_UNIT_SECONDS /** * Linked list of pending tasks. */ struct Task { /** * This is a linked list. */ struct Task *next; /** * Function to run when ready. */ GNUNET_SCHEDULER_Task callback; /** * Closure for the callback. */ void *callback_cls; /** * Set of file descriptors this task is waiting * for for reading. Once ready, this is updated * to reflect the set of file descriptors ready * for operation. */ struct GNUNET_NETWORK_FDSet *read_set; /** * Set of file descriptors this task is waiting for for writing. * Once ready, this is updated to reflect the set of file * descriptors ready for operation. */ struct GNUNET_NETWORK_FDSet *write_set; /** * Unique task identifier. */ GNUNET_SCHEDULER_TaskIdentifier id; /** * Absolute timeout value for the task, or * GNUNET_TIME_UNIT_FOREVER_ABS for "no timeout". */ struct GNUNET_TIME_Absolute timeout; #if PROFILE_DELAYS /** * When was the task scheduled? */ struct GNUNET_TIME_Absolute start_time; #endif /** * Why is the task ready? Set after task is added to ready queue. * Initially set to zero. All reasons that have already been * satisfied (i.e. read or write ready) will be set over time. */ enum GNUNET_SCHEDULER_Reason reason; /** * Task priority. */ enum GNUNET_SCHEDULER_Priority priority; /** * Set if we only wait for reading from a single FD, otherwise -1. */ int read_fd; /** * Set if we only wait for writing to a single FD, otherwise -1. */ int write_fd; /** * Should the existence of this task in the queue be counted as * reason to not shutdown the scheduler? */ int lifeness; #if EXECINFO /** * Array of strings which make up a backtrace from the point when this * task was scheduled (essentially, who scheduled the task?) */ char **backtrace_strings; /** * Size of the backtrace_strings array */ int num_backtrace_strings; #endif }; /** * List of tasks waiting for an event. */ static struct Task *pending; /** * List of tasks waiting ONLY for a timeout event. * Sorted by timeout (earliest first). Used so that * we do not traverse the list of these tasks when * building select sets (we just look at the head * to determine the respective timeout ONCE). */ static struct Task *pending_timeout; /** * Last inserted task waiting ONLY for a timeout event. * Used to (heuristically) speed up insertion. */ static struct Task *pending_timeout_last; /** * ID of the task that is running right now. */ static struct Task *active_task; /** * List of tasks ready to run right now, * grouped by importance. */ static struct Task *ready[GNUNET_SCHEDULER_PRIORITY_COUNT]; /** * Identity of the last task queued. Incremented for each task to * generate a unique task ID (it is virtually impossible to start * more than 2^64 tasks during the lifetime of a process). */ static GNUNET_SCHEDULER_TaskIdentifier last_id; /** * Number of tasks on the ready list. */ static unsigned int ready_count; /** * How many tasks have we run so far? */ static unsigned long long tasks_run; /** * Priority of the task running right now. Only * valid while a task is running. */ static enum GNUNET_SCHEDULER_Priority current_priority; /** * Priority of the highest task added in the current select * iteration. */ static enum GNUNET_SCHEDULER_Priority max_priority_added; /** * Value of the 'lifeness' flag for the current task. */ static int current_lifeness; /** * Function to use as a select() in the scheduler. * If NULL, we use GNUNET_NETWORK_socket_select (). */ static GNUNET_SCHEDULER_select scheduler_select; /** * Closure for 'scheduler_select'. */ static void *scheduler_select_cls; /** * Sets the select function to use in the scheduler (scheduler_select). * * @param new_select new select function to use * @param new_select_cls closure for 'new_select' * @return previously used select function, NULL for default */ void GNUNET_SCHEDULER_set_select (GNUNET_SCHEDULER_select new_select, void *new_select_cls) { scheduler_select = new_select; scheduler_select_cls = new_select_cls; } /** * Check that the given priority is legal (and return it). * * @param p priority value to check * @return p on success, 0 on error */ static enum GNUNET_SCHEDULER_Priority check_priority (enum GNUNET_SCHEDULER_Priority p) { if ((p >= 0) && (p < GNUNET_SCHEDULER_PRIORITY_COUNT)) return p; GNUNET_assert (0); return 0; /* make compiler happy */ } /** * Update all sets and timeout for select. * * @param rs read-set, set to all FDs we would like to read (updated) * @param ws write-set, set to all FDs we would like to write (updated) * @param timeout next timeout (updated) */ static void update_sets (struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws, struct GNUNET_TIME_Relative *timeout) { struct Task *pos; struct GNUNET_TIME_Absolute now; struct GNUNET_TIME_Relative to; now = GNUNET_TIME_absolute_get (); pos = pending_timeout; if (pos != NULL) { to = GNUNET_TIME_absolute_get_difference (now, pos->timeout); if (timeout->rel_value > to.rel_value) *timeout = to; if (pos->reason != 0) *timeout = GNUNET_TIME_UNIT_ZERO; } pos = pending; while (pos != NULL) { if (pos->timeout.abs_value != GNUNET_TIME_UNIT_FOREVER_ABS.abs_value) { to = GNUNET_TIME_absolute_get_difference (now, pos->timeout); if (timeout->rel_value > to.rel_value) *timeout = to; } if (pos->read_fd != -1) GNUNET_NETWORK_fdset_set_native (rs, pos->read_fd); if (pos->write_fd != -1) GNUNET_NETWORK_fdset_set_native (ws, pos->write_fd); if (pos->read_set != NULL) GNUNET_NETWORK_fdset_add (rs, pos->read_set); if (pos->write_set != NULL) GNUNET_NETWORK_fdset_add (ws, pos->write_set); if (pos->reason != 0) *timeout = GNUNET_TIME_UNIT_ZERO; pos = pos->next; } } /** * Check if the ready set overlaps with the set we want to have ready. * If so, update the want set (set all FDs that are ready). If not, * return GNUNET_NO. * * @param ready set that is ready * @param want set that we want to be ready * @return GNUNET_YES if there was some overlap */ static int set_overlaps (const struct GNUNET_NETWORK_FDSet *ready, struct GNUNET_NETWORK_FDSet *want) { if ((NULL == want) || (NULL == ready)) return GNUNET_NO; if (GNUNET_NETWORK_fdset_overlap (ready, want)) { /* copy all over (yes, there maybe unrelated bits, * but this should not hurt well-written clients) */ GNUNET_NETWORK_fdset_copy (want, ready); return GNUNET_YES; } return GNUNET_NO; } /** * Check if the given task is eligible to run now. * Also set the reason why it is eligible. * * @param task task to check if it is ready * @param now the current time * @param rs set of FDs ready for reading * @param ws set of FDs ready for writing * @return GNUNET_YES if we can run it, GNUNET_NO if not. */ static int is_ready (struct Task *task, struct GNUNET_TIME_Absolute now, const struct GNUNET_NETWORK_FDSet *rs, const struct GNUNET_NETWORK_FDSet *ws) { enum GNUNET_SCHEDULER_Reason reason; reason = task->reason; if (now.abs_value >= task->timeout.abs_value) reason |= GNUNET_SCHEDULER_REASON_TIMEOUT; if ((0 == (reason & GNUNET_SCHEDULER_REASON_READ_READY)) && (((task->read_fd != -1) && (GNUNET_YES == GNUNET_NETWORK_fdset_test_native (rs, task->read_fd))) || (set_overlaps (rs, task->read_set)))) reason |= GNUNET_SCHEDULER_REASON_READ_READY; if ((0 == (reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) && (((task->write_fd != -1) && (GNUNET_YES == GNUNET_NETWORK_fdset_test_native (ws, task->write_fd))) || (set_overlaps (ws, task->write_set)))) reason |= GNUNET_SCHEDULER_REASON_WRITE_READY; if (reason == 0) return GNUNET_NO; /* not ready */ reason |= GNUNET_SCHEDULER_REASON_PREREQ_DONE; task->reason = reason; return GNUNET_YES; } /** * Put a task that is ready for execution into the ready queue. * * @param task task ready for execution */ static void queue_ready_task (struct Task *task) { enum GNUNET_SCHEDULER_Priority p = task->priority; if (0 != (task->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) p = GNUNET_SCHEDULER_PRIORITY_SHUTDOWN; task->next = ready[check_priority (p)]; ready[check_priority (p)] = task; ready_count++; } /** * Check which tasks are ready and move them * to the respective ready queue. * * @param rs FDs ready for reading * @param ws FDs ready for writing */ static void check_ready (const struct GNUNET_NETWORK_FDSet *rs, const struct GNUNET_NETWORK_FDSet *ws) { struct Task *pos; struct Task *prev; struct Task *next; struct GNUNET_TIME_Absolute now; now = GNUNET_TIME_absolute_get (); prev = NULL; pos = pending_timeout; while (pos != NULL) { next = pos->next; if (now.abs_value >= pos->timeout.abs_value) pos->reason |= GNUNET_SCHEDULER_REASON_TIMEOUT; if (0 == pos->reason) break; pending_timeout = next; if (pending_timeout_last == pos) pending_timeout_last = NULL; queue_ready_task (pos); pos = next; } pos = pending; while (pos != NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking readiness of task: %llu / %p\n", pos->id, pos->callback_cls); next = pos->next; if (GNUNET_YES == is_ready (pos, now, rs, ws)) { if (prev == NULL) pending = next; else prev->next = next; queue_ready_task (pos); pos = next; continue; } prev = pos; pos = next; } } /** * Request the shutdown of a scheduler. Marks all currently * pending tasks as ready because of shutdown. This will * cause all tasks to run (as soon as possible, respecting * priorities and prerequisite tasks). Note that tasks * scheduled AFTER this call may still be delayed arbitrarily. */ void GNUNET_SCHEDULER_shutdown () { struct Task *pos; int i; pos = pending_timeout; while (pos != NULL) { pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN; /* we don't move the task into the ready queue yet; check_ready * will do that later, possibly adding additional * readiness-factors */ pos = pos->next; } pos = pending; while (pos != NULL) { pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN; /* we don't move the task into the ready queue yet; check_ready * will do that later, possibly adding additional * readiness-factors */ pos = pos->next; } for (i = 0; i < GNUNET_SCHEDULER_PRIORITY_COUNT; i++) { pos = ready[i]; while (pos != NULL) { pos->reason |= GNUNET_SCHEDULER_REASON_SHUTDOWN; /* we don't move the task into the ready queue yet; check_ready * will do that later, possibly adding additional * readiness-factors */ pos = pos->next; } } } /** * Destroy a task (release associated resources) * * @param t task to destroy */ static void destroy_task (struct Task *t) { if (NULL != t->read_set) GNUNET_NETWORK_fdset_destroy (t->read_set); if (NULL != t->write_set) GNUNET_NETWORK_fdset_destroy (t->write_set); #if EXECINFO GNUNET_free (t->backtrace_strings); #endif GNUNET_free (t); } /** * Run at least one task in the highest-priority queue that is not * empty. Keep running tasks until we are either no longer running * "URGENT" tasks or until we have at least one "pending" task (which * may become ready, hence we should select on it). Naturally, if * there are no more ready tasks, we also return. * * @param rs FDs ready for reading * @param ws FDs ready for writing */ static void run_ready (struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws) { enum GNUNET_SCHEDULER_Priority p; struct Task *pos; struct GNUNET_SCHEDULER_TaskContext tc; max_priority_added = GNUNET_SCHEDULER_PRIORITY_KEEP; do { if (ready_count == 0) return; GNUNET_assert (ready[GNUNET_SCHEDULER_PRIORITY_KEEP] == NULL); /* yes, p>0 is correct, 0 is "KEEP" which should * always be an empty queue (see assertion)! */ for (p = GNUNET_SCHEDULER_PRIORITY_COUNT - 1; p > 0; p--) { pos = ready[p]; if (pos != NULL) break; } GNUNET_assert (pos != NULL); /* ready_count wrong? */ ready[p] = pos->next; ready_count--; if (current_priority != pos->priority) { current_priority = pos->priority; (void) GNUNET_OS_set_process_priority (GNUNET_OS_process_current (), pos->priority); } current_lifeness = pos->lifeness; active_task = pos; #if PROFILE_DELAYS if (GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value > DELAY_THRESHOLD.rel_value) { LOG (GNUNET_ERROR_TYPE_ERROR, "Task %llu took %llums to be scheduled\n", pos->id, (unsigned long long) GNUNET_TIME_absolute_get_duration (pos->start_time).rel_value); } #endif tc.reason = pos->reason; tc.read_ready = (pos->read_set == NULL) ? rs : pos->read_set; if ((pos->read_fd != -1) && (0 != (pos->reason & GNUNET_SCHEDULER_REASON_READ_READY))) GNUNET_NETWORK_fdset_set_native (rs, pos->read_fd); tc.write_ready = (pos->write_set == NULL) ? ws : pos->write_set; if ((pos->write_fd != -1) && (0 != (pos->reason & GNUNET_SCHEDULER_REASON_WRITE_READY))) GNUNET_NETWORK_fdset_set_native (ws, pos->write_fd); if (((tc.reason & GNUNET_SCHEDULER_REASON_WRITE_READY) != 0) && (pos->write_fd != -1) && (!GNUNET_NETWORK_fdset_test_native (ws, pos->write_fd))) GNUNET_abort (); // added to ready in previous select loop! LOG (GNUNET_ERROR_TYPE_DEBUG, "Running task: %llu / %p\n", pos->id, pos->callback_cls); pos->callback (pos->callback_cls, &tc); #if EXECINFO int i; for (i = 0; i < pos->num_backtrace_strings; i++) LOG (GNUNET_ERROR_TYPE_ERROR, "Task %llu trace %d: %s\n", pos->id, i, pos->backtrace_strings[i]); #endif active_task = NULL; destroy_task (pos); tasks_run++; } while ((pending == NULL) || (p >= max_priority_added)); } /** * Pipe used to communicate shutdown via signal. */ static struct GNUNET_DISK_PipeHandle *shutdown_pipe_handle; /** * Process ID of this process at the time we installed the various * signal handlers. */ static pid_t my_pid; /** * Signal handler called for SIGPIPE. */ #ifndef MINGW static void sighandler_pipe () { return; } #endif /** * Signal handler called for signals that should cause us to shutdown. */ static void sighandler_shutdown () { static char c; int old_errno = errno; /* backup errno */ if (getpid () != my_pid) exit (1); /* we have fork'ed since the signal handler was created, * ignore the signal, see https://gnunet.org/vfork discussion */ GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (shutdown_pipe_handle, GNUNET_DISK_PIPE_END_WRITE), &c, sizeof (c)); errno = old_errno; } /** * Check if the system is still life. Trigger shutdown if we * have tasks, but none of them give us lifeness. * * @return GNUNET_OK to continue the main loop, * GNUNET_NO to exit */ static int check_lifeness () { struct Task *t; if (ready_count > 0) return GNUNET_OK; for (t = pending; NULL != t; t = t->next) if (t->lifeness == GNUNET_YES) return GNUNET_OK; for (t = pending_timeout; NULL != t; t = t->next) if (t->lifeness == GNUNET_YES) return GNUNET_OK; if ((NULL != pending) || (NULL != pending_timeout)) { GNUNET_SCHEDULER_shutdown (); return GNUNET_OK; } return GNUNET_NO; } /** * Initialize and run scheduler. This function will return when all * tasks have completed. On systems with signals, receiving a SIGTERM * (and other similar signals) will cause "GNUNET_SCHEDULER_shutdown" * to be run after the active task is complete. As a result, SIGTERM * causes all active tasks to be scheduled with reason * "GNUNET_SCHEDULER_REASON_SHUTDOWN". (However, tasks added * afterwards will execute normally!). Note that any particular signal * will only shut down one scheduler; applications should always only * create a single scheduler. * * @param task task to run immediately * @param task_cls closure of task */ void GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls) { struct GNUNET_NETWORK_FDSet *rs; struct GNUNET_NETWORK_FDSet *ws; struct GNUNET_TIME_Relative timeout; int ret; struct GNUNET_SIGNAL_Context *shc_int; struct GNUNET_SIGNAL_Context *shc_term; #ifndef MINGW struct GNUNET_SIGNAL_Context *shc_quit; struct GNUNET_SIGNAL_Context *shc_hup; struct GNUNET_SIGNAL_Context *shc_pipe; #endif unsigned long long last_tr; unsigned int busy_wait_warning; const struct GNUNET_DISK_FileHandle *pr; char c; GNUNET_assert (active_task == NULL); rs = GNUNET_NETWORK_fdset_create (); ws = GNUNET_NETWORK_fdset_create (); GNUNET_assert (shutdown_pipe_handle == NULL); shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO); GNUNET_assert (shutdown_pipe_handle != NULL); pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle, GNUNET_DISK_PIPE_END_READ); GNUNET_assert (pr != NULL); my_pid = getpid (); shc_int = GNUNET_SIGNAL_handler_install (SIGINT, &sighandler_shutdown); shc_term = GNUNET_SIGNAL_handler_install (SIGTERM, &sighandler_shutdown); #ifndef MINGW shc_pipe = GNUNET_SIGNAL_handler_install (SIGPIPE, &sighandler_pipe); shc_quit = GNUNET_SIGNAL_handler_install (SIGQUIT, &sighandler_shutdown); shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP, &sighandler_shutdown); #endif current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT; current_lifeness = GNUNET_YES; GNUNET_SCHEDULER_add_continuation (task, task_cls, GNUNET_SCHEDULER_REASON_STARTUP); active_task = (void *) (long) -1; /* force passing of sanity check */ GNUNET_SCHEDULER_add_now_with_lifeness (GNUNET_NO, &GNUNET_OS_install_parent_control_handler, NULL); active_task = NULL; last_tr = 0; busy_wait_warning = 0; while (GNUNET_OK == check_lifeness ()) { GNUNET_NETWORK_fdset_zero (rs); GNUNET_NETWORK_fdset_zero (ws); timeout = GNUNET_TIME_UNIT_FOREVER_REL; update_sets (rs, ws, &timeout); GNUNET_NETWORK_fdset_handle_set (rs, pr); if (ready_count > 0) { /* no blocking, more work already ready! */ timeout = GNUNET_TIME_UNIT_ZERO; } if (NULL == scheduler_select) ret = GNUNET_NETWORK_socket_select (rs, ws, NULL, timeout); else ret = scheduler_select (scheduler_select_cls, rs, ws, NULL, timeout); if (ret == GNUNET_SYSERR) { if (errno == EINTR) continue; LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "select"); #ifndef MINGW #if USE_LSOF char lsof[512]; snprintf (lsof, sizeof (lsof), "lsof -p %d", getpid ()); (void) close (1); (void) dup2 (2, 1); if (0 != system (lsof)) LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "system"); #endif #endif GNUNET_abort (); break; } if ((ret == 0) && (timeout.rel_value == 0) && (busy_wait_warning > 16)) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Looks like we're busy waiting...\n")); sleep (1); /* mitigate */ } check_ready (rs, ws); run_ready (rs, ws); if (GNUNET_NETWORK_fdset_handle_isset (rs, pr)) { /* consume the signal */ GNUNET_DISK_file_read (pr, &c, sizeof (c)); /* mark all active tasks as ready due to shutdown */ GNUNET_SCHEDULER_shutdown (); } if (last_tr == tasks_run) { busy_wait_warning++; } else { last_tr = tasks_run; busy_wait_warning = 0; } } GNUNET_SIGNAL_handler_uninstall (shc_int); GNUNET_SIGNAL_handler_uninstall (shc_term); #ifndef MINGW GNUNET_SIGNAL_handler_uninstall (shc_pipe); GNUNET_SIGNAL_handler_uninstall (shc_quit); GNUNET_SIGNAL_handler_uninstall (shc_hup); #endif GNUNET_DISK_pipe_close (shutdown_pipe_handle); shutdown_pipe_handle = NULL; GNUNET_NETWORK_fdset_destroy (rs); GNUNET_NETWORK_fdset_destroy (ws); } /** * Obtain the reason code for why the current task was * started. Will return the same value as * the GNUNET_SCHEDULER_TaskContext's reason field. * * @return reason(s) why the current task is run */ enum GNUNET_SCHEDULER_Reason GNUNET_SCHEDULER_get_reason () { GNUNET_assert (active_task != NULL); return active_task->reason; } /** * Get information about the current load of this scheduler. Use this * function to determine if an elective task should be added or simply * dropped (if the decision should be made based on the number of * tasks ready to run). * * @param p priority level to look at * @return number of tasks pending right now */ unsigned int GNUNET_SCHEDULER_get_load (enum GNUNET_SCHEDULER_Priority p) { struct Task *pos; unsigned int ret; GNUNET_assert (active_task != NULL); if (p == GNUNET_SCHEDULER_PRIORITY_COUNT) return ready_count; if (p == GNUNET_SCHEDULER_PRIORITY_KEEP) p = current_priority; ret = 0; pos = ready[check_priority (p)]; while (pos != NULL) { pos = pos->next; ret++; } return ret; } /** * Cancel the task with the specified identifier. * The task must not yet have run. * * @param task id of the task to cancel * @return original closure of the task */ void * GNUNET_SCHEDULER_cancel (GNUNET_SCHEDULER_TaskIdentifier task) { struct Task *t; struct Task *prev; enum GNUNET_SCHEDULER_Priority p; int to; void *ret; GNUNET_assert (active_task != NULL); to = 0; prev = NULL; t = pending; while (t != NULL) { if (t->id == task) break; prev = t; t = t->next; } if (t == NULL) { prev = NULL; to = 1; t = pending_timeout; while (t != NULL) { if (t->id == task) break; prev = t; t = t->next; } if (pending_timeout_last == t) pending_timeout_last = NULL; } p = 0; while (t == NULL) { p++; if (p >= GNUNET_SCHEDULER_PRIORITY_COUNT) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Attempt to cancel dead task %llu!\n"), (unsigned long long) task); GNUNET_assert (0); } prev = NULL; t = ready[p]; while (t != NULL) { if (t->id == task) { ready_count--; break; } prev = t; t = t->next; } } if (prev == NULL) { if (p == 0) { if (to == 0) { pending = t->next; } else { pending_timeout = t->next; } } else { ready[p] = t->next; } } else { prev->next = t->next; } ret = t->callback_cls; LOG (GNUNET_ERROR_TYPE_DEBUG, "Canceling task: %llu / %p\n", task, t->callback_cls); destroy_task (t); return ret; } /** * Continue the current execution with the given function. This is * similar to the other "add" functions except that there is no delay * and the reason code can be specified. * * @param task main function of the task * @param task_cls closure for 'main' * @param reason reason for task invocation * @param priority priority to use for the task */ void GNUNET_SCHEDULER_add_continuation_with_priority (GNUNET_SCHEDULER_Task task, void *task_cls, enum GNUNET_SCHEDULER_Reason reason, enum GNUNET_SCHEDULER_Priority priority) { struct Task *t; #if EXECINFO void *backtrace_array[50]; #endif GNUNET_assert (NULL != task); GNUNET_assert ((active_task != NULL) || (reason == GNUNET_SCHEDULER_REASON_STARTUP)); t = GNUNET_malloc (sizeof (struct Task)); #if EXECINFO t->num_backtrace_strings = backtrace (backtrace_array, 50); t->backtrace_strings = backtrace_symbols (backtrace_array, t->num_backtrace_strings); #endif t->read_fd = -1; t->write_fd = -1; t->callback = task; t->callback_cls = task_cls; t->id = ++last_id; #if PROFILE_DELAYS t->start_time = GNUNET_TIME_absolute_get (); #endif t->reason = reason; t->priority = priority; t->lifeness = current_lifeness; LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding continuation task: %llu / %p\n", t->id, t->callback_cls); queue_ready_task (t); } /** * Continue the current execution with the given function. This is * similar to the other "add" functions except that there is no delay * and the reason code can be specified. * * @param task main function of the task * @param task_cls closure for 'main' * @param reason reason for task invocation */ void GNUNET_SCHEDULER_add_continuation (GNUNET_SCHEDULER_Task task, void *task_cls, enum GNUNET_SCHEDULER_Reason reason) { GNUNET_SCHEDULER_add_continuation_with_priority (task, task_cls, reason, GNUNET_SCHEDULER_PRIORITY_DEFAULT); } /** * Schedule a new task to be run with a specified priority. * * @param prio how important is the new task? * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_with_priority (enum GNUNET_SCHEDULER_Priority prio, GNUNET_SCHEDULER_Task task, void *task_cls) { return GNUNET_SCHEDULER_add_select (prio, GNUNET_TIME_UNIT_ZERO, NULL, NULL, task, task_cls); } /** * Schedule a new task to be run with a specified delay. The task * will be scheduled for execution once the delay has expired. * * @param delay when should this operation time out? Use * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" * @param priority priority to use for the task * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_delayed_with_priority (struct GNUNET_TIME_Relative delay, enum GNUNET_SCHEDULER_Priority priority, GNUNET_SCHEDULER_Task task, void *task_cls) { struct Task *t; struct Task *pos; struct Task *prev; #if EXECINFO void *backtrace_array[MAX_TRACE_DEPTH]; #endif GNUNET_assert (active_task != NULL); GNUNET_assert (NULL != task); t = GNUNET_malloc (sizeof (struct Task)); t->callback = task; t->callback_cls = task_cls; #if EXECINFO t->num_backtrace_strings = backtrace (backtrace_array, MAX_TRACE_DEPTH); t->backtrace_strings = backtrace_symbols (backtrace_array, t->num_backtrace_strings); #endif t->read_fd = -1; t->write_fd = -1; t->id = ++last_id; #if PROFILE_DELAYS t->start_time = GNUNET_TIME_absolute_get (); #endif t->timeout = GNUNET_TIME_relative_to_absolute (delay); t->priority = priority; t->lifeness = current_lifeness; /* try tail first (optimization in case we are * appending to a long list of tasks with timeouts) */ prev = pending_timeout_last; if (prev != NULL) { if (prev->timeout.abs_value > t->timeout.abs_value) prev = NULL; else pos = prev->next; /* heuristic success! */ } if (prev == NULL) { /* heuristic failed, do traversal of timeout list */ pos = pending_timeout; } while ((pos != NULL) && ((pos->timeout.abs_value <= t->timeout.abs_value) || (pos->reason != 0))) { prev = pos; pos = pos->next; } if (prev == NULL) pending_timeout = t; else prev->next = t; t->next = pos; /* hyper-optimization... */ pending_timeout_last = t; LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding task: %llu / %p\n", t->id, t->callback_cls); #if EXECINFO int i; for (i = 0; i < t->num_backtrace_strings; i++) LOG (GNUNET_ERROR_TYPE_DEBUG, "Task %llu trace %d: %s\n", t->id, i, t->backtrace_strings[i]); #endif return t->id; } /** * Schedule a new task to be run with a specified delay. The task * will be scheduled for execution once the delay has expired. It * will be run with the DEFAULT priority. * * @param delay when should this operation time out? Use * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_Task task, void *task_cls) { return GNUNET_SCHEDULER_add_delayed_with_priority (delay, GNUNET_SCHEDULER_PRIORITY_DEFAULT, task, task_cls); } /** * Schedule a new task to be run as soon as possible. The task * will be run with the DEFAULT priority. * * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_Task task, void *task_cls) { return GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_ZERO, task, task_cls); } /** * Schedule a new task to be run as soon as possible with the * (transitive) ignore-shutdown flag either explicitly set or * explicitly enabled. This task (and all tasks created from it, * other than by another call to this function) will either count or * not count for the 'lifeness' of the process. This API is only * useful in a few special cases. * * @param lifeness GNUNET_YES if the task counts for lifeness, GNUNET_NO if not. * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness, GNUNET_SCHEDULER_Task task, void *task_cls) { GNUNET_SCHEDULER_TaskIdentifier ret; ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_TIME_UNIT_ZERO, NULL, NULL, task, task_cls); GNUNET_assert (pending->id == ret); pending->lifeness = lifeness; return ret; } /** * Schedule a new task to be run with a specified delay or when any of * the specified file descriptor sets is ready. The delay can be used * as a timeout on the socket(s) being ready. The task will be * scheduled for execution once either the delay has expired or any of * the socket operations is ready. This is the most general * function of the "add" family. Note that the "prerequisite_task" * must be satisfied in addition to any of the other conditions. In * other words, the task will be started when * * (prerequisite-run) * && (delay-ready * || any-rs-ready * || any-ws-ready * || shutdown-active ) * * * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever", * which means that the task will only be run after we receive SIGTERM * @param priority priority to use * @param rfd file descriptor we want to read (can be -1) * @param wfd file descriptors we want to write (can be -1) * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ #ifndef MINGW static GNUNET_SCHEDULER_TaskIdentifier add_without_sets (struct GNUNET_TIME_Relative delay, enum GNUNET_SCHEDULER_Priority priority, int rfd, int wfd, GNUNET_SCHEDULER_Task task, void *task_cls) { struct Task *t; #if EXECINFO void *backtrace_array[MAX_TRACE_DEPTH]; #endif GNUNET_assert (active_task != NULL); GNUNET_assert (NULL != task); t = GNUNET_malloc (sizeof (struct Task)); t->callback = task; t->callback_cls = task_cls; #if EXECINFO t->num_backtrace_strings = backtrace (backtrace_array, MAX_TRACE_DEPTH); t->backtrace_strings = backtrace_symbols (backtrace_array, t->num_backtrace_strings); #endif #if DEBUG_FDS if (-1 != rfd) { int flags = fcntl (rfd, F_GETFD); if ((flags == -1) && (errno == EBADF)) { LOG (GNUNET_ERROR_TYPE_ERROR, "Got invalid file descriptor %d!\n", rfd); #if EXECINFO int i; for (i = 0; i < t->num_backtrace_strings; i++) LOG (GNUNET_ERROR_TYPE_DEBUG, "Trace: %s\n", t->backtrace_strings[i]); #endif GNUNET_assert (0); } } if (-1 != wfd) { int flags = fcntl (wfd, F_GETFD); if (flags == -1 && errno == EBADF) { LOG (GNUNET_ERROR_TYPE_ERROR, "Got invalid file descriptor %d!\n", wfd); #if EXECINFO int i; for (i = 0; i < t->num_backtrace_strings; i++) LOG (GNUNET_ERROR_TYPE_DEBUG, "Trace: %s\n", t->backtrace_strings[i]); #endif GNUNET_assert (0); } } #endif t->read_fd = rfd; GNUNET_assert (wfd >= -1); t->write_fd = wfd; t->id = ++last_id; #if PROFILE_DELAYS t->start_time = GNUNET_TIME_absolute_get (); #endif t->timeout = GNUNET_TIME_relative_to_absolute (delay); t->priority = check_priority ((priority == GNUNET_SCHEDULER_PRIORITY_KEEP) ? current_priority : priority); t->lifeness = current_lifeness; t->next = pending; pending = t; max_priority_added = GNUNET_MAX (max_priority_added, t->priority); LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding task: %llu / %p\n", t->id, t->callback_cls); #if EXECINFO int i; for (i = 0; i < t->num_backtrace_strings; i++) LOG (GNUNET_ERROR_TYPE_DEBUG, "Task %llu trace %d: %s\n", t->id, i, t->backtrace_strings[i]); #endif return t->id; } #endif /** * Schedule a new task to be run with a specified delay or when the * specified file descriptor is ready for reading. The delay can be * used as a timeout on the socket being ready. The task will be * scheduled for execution once either the delay has expired or the * socket operation is ready. It will be run with the DEFAULT priority. * * @param delay when should this operation time out? Use * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" * @param rfd read file-descriptor * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *rfd, GNUNET_SCHEDULER_Task task, void *task_cls) { return GNUNET_SCHEDULER_add_read_net_with_priority (delay, GNUNET_SCHEDULER_PRIORITY_DEFAULT, rfd, task, task_cls); } /** * Schedule a new task to be run with a specified priority and to be * run after the specified delay or when the specified file descriptor * is ready for reading. The delay can be used as a timeout on the * socket being ready. The task will be scheduled for execution once * either the delay has expired or the socket operation is ready. It * will be run with the DEFAULT priority. * * @param delay when should this operation time out? Use * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" * @param priority priority to use for the task * @param rfd read file-descriptor * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_read_net_with_priority (struct GNUNET_TIME_Relative delay, enum GNUNET_SCHEDULER_Priority priority, struct GNUNET_NETWORK_Handle *rfd, GNUNET_SCHEDULER_Task task, void *task_cls) { #if MINGW struct GNUNET_NETWORK_FDSet *rs; GNUNET_SCHEDULER_TaskIdentifier ret; GNUNET_assert (rfd != NULL); rs = GNUNET_NETWORK_fdset_create (); GNUNET_NETWORK_fdset_set (rs, rfd); ret = GNUNET_SCHEDULER_add_select (priority, delay, rs, NULL, task, task_cls); GNUNET_NETWORK_fdset_destroy (rs); return ret; #else return add_without_sets (delay, priority, GNUNET_NETWORK_get_fd (rfd), -1, task, task_cls); #endif } /** * Schedule a new task to be run with a specified delay or when the * specified file descriptor is ready for writing. The delay can be * used as a timeout on the socket being ready. The task will be * scheduled for execution once either the delay has expired or the * socket operation is ready. It will be run with the priority of * the calling task. * * @param delay when should this operation time out? Use * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" * @param wfd write file-descriptor * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *wfd, GNUNET_SCHEDULER_Task task, void *task_cls) { #if MINGW struct GNUNET_NETWORK_FDSet *ws; GNUNET_SCHEDULER_TaskIdentifier ret; GNUNET_assert (wfd != NULL); ws = GNUNET_NETWORK_fdset_create (); GNUNET_NETWORK_fdset_set (ws, wfd); ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, delay, NULL, ws, task, task_cls); GNUNET_NETWORK_fdset_destroy (ws); return ret; #else GNUNET_assert (GNUNET_NETWORK_get_fd (wfd) >= 0); return add_without_sets (delay, GNUNET_SCHEDULER_PRIORITY_DEFAULT, -1, GNUNET_NETWORK_get_fd (wfd), task, task_cls); #endif } /** * Schedule a new task to be run with a specified delay or when the * specified file descriptor is ready for reading. The delay can be * used as a timeout on the socket being ready. The task will be * scheduled for execution once either the delay has expired or the * socket operation is ready. It will be run with the DEFAULT priority. * * @param delay when should this operation time out? Use * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" * @param rfd read file-descriptor * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay, const struct GNUNET_DISK_FileHandle *rfd, GNUNET_SCHEDULER_Task task, void *task_cls) { #if MINGW struct GNUNET_NETWORK_FDSet *rs; GNUNET_SCHEDULER_TaskIdentifier ret; GNUNET_assert (rfd != NULL); rs = GNUNET_NETWORK_fdset_create (); GNUNET_NETWORK_fdset_handle_set (rs, rfd); ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, delay, rs, NULL, task, task_cls); GNUNET_NETWORK_fdset_destroy (rs); return ret; #else int fd; GNUNET_DISK_internal_file_handle_ (rfd, &fd, sizeof (int)); return add_without_sets (delay, GNUNET_SCHEDULER_PRIORITY_DEFAULT, fd, -1, task, task_cls); #endif } /** * Schedule a new task to be run with a specified delay or when the * specified file descriptor is ready for writing. The delay can be * used as a timeout on the socket being ready. The task will be * scheduled for execution once either the delay has expired or the * socket operation is ready. It will be run with the DEFAULT priority. * * @param delay when should this operation time out? Use * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" * @param wfd write file-descriptor * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay, const struct GNUNET_DISK_FileHandle *wfd, GNUNET_SCHEDULER_Task task, void *task_cls) { #if MINGW struct GNUNET_NETWORK_FDSet *ws; GNUNET_SCHEDULER_TaskIdentifier ret; GNUNET_assert (wfd != NULL); ws = GNUNET_NETWORK_fdset_create (); GNUNET_NETWORK_fdset_handle_set (ws, wfd); ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, delay, NULL, ws, task, task_cls); GNUNET_NETWORK_fdset_destroy (ws); return ret; #else int fd; GNUNET_DISK_internal_file_handle_ (wfd, &fd, sizeof (int)); GNUNET_assert (fd >= 0); return add_without_sets (delay, GNUNET_SCHEDULER_PRIORITY_DEFAULT, -1, fd, task, task_cls); #endif } /** * Schedule a new task to be run with a specified delay or when any of * the specified file descriptor sets is ready. The delay can be used * as a timeout on the socket(s) being ready. The task will be * scheduled for execution once either the delay has expired or any of * the socket operations is ready. This is the most general * function of the "add" family. Note that the "prerequisite_task" * must be satisfied in addition to any of the other conditions. In * other words, the task will be started when * * (prerequisite-run) * && (delay-ready * || any-rs-ready * || any-ws-ready * || (shutdown-active && run-on-shutdown) ) * * * @param prio how important is this task? * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever", * which means that the task will only be run after we receive SIGTERM * @param rs set of file descriptors we want to read (can be NULL) * @param ws set of file descriptors we want to write (can be NULL) * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio, struct GNUNET_TIME_Relative delay, const struct GNUNET_NETWORK_FDSet *rs, const struct GNUNET_NETWORK_FDSet *ws, GNUNET_SCHEDULER_Task task, void *task_cls) { struct Task *t; #if EXECINFO void *backtrace_array[MAX_TRACE_DEPTH]; #endif GNUNET_assert (active_task != NULL); GNUNET_assert (NULL != task); t = GNUNET_malloc (sizeof (struct Task)); t->callback = task; t->callback_cls = task_cls; #if EXECINFO t->num_backtrace_strings = backtrace (backtrace_array, MAX_TRACE_DEPTH); t->backtrace_strings = backtrace_symbols (backtrace_array, t->num_backtrace_strings); #endif t->read_fd = -1; t->write_fd = -1; if (rs != NULL) { t->read_set = GNUNET_NETWORK_fdset_create (); GNUNET_NETWORK_fdset_copy (t->read_set, rs); } if (ws != NULL) { t->write_set = GNUNET_NETWORK_fdset_create (); GNUNET_NETWORK_fdset_copy (t->write_set, ws); } t->id = ++last_id; #if PROFILE_DELAYS t->start_time = GNUNET_TIME_absolute_get (); #endif t->timeout = GNUNET_TIME_relative_to_absolute (delay); t->priority = check_priority ((prio == GNUNET_SCHEDULER_PRIORITY_KEEP) ? current_priority : prio); t->lifeness = current_lifeness; t->next = pending; pending = t; max_priority_added = GNUNET_MAX (max_priority_added, t->priority); LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding task: %llu / %p\n", t->id, t->callback_cls); #if EXECINFO int i; for (i = 0; i < t->num_backtrace_strings; i++) LOG (GNUNET_ERROR_TYPE_DEBUG, "Task %llu trace %d: %s\n", t->id, i, t->backtrace_strings[i]); #endif return t->id; } /* end of scheduler.c */ gnunet-0.9.3/src/util/common_endian.c0000644000175000017500000000422611760502551014470 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2006, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/common_endian.c * @brief endian conversion helpers * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #define LOG(kind,...) GNUNET_log_from (kind, "util",__VA_ARGS__) uint64_t GNUNET_ntohll (uint64_t n) { #if __BYTE_ORDER == __BIG_ENDIAN return n; #elif __BYTE_ORDER == __LITTLE_ENDIAN return (((uint64_t) ntohl (n)) << 32) + ntohl (n >> 32); #else #error byteorder undefined #endif } uint64_t GNUNET_htonll (uint64_t n) { #if __BYTE_ORDER == __BIG_ENDIAN return n; #elif __BYTE_ORDER == __LITTLE_ENDIAN return (((uint64_t) htonl (n)) << 32) + htonl (n >> 32); #else #error byteorder undefined #endif } /** * Convert double to network-byte-order. * @param d the value in network byte order * @return the same value in host byte order */ double GNUNET_hton_double (double d) { double res; uint64_t *in = (uint64_t *) &d; uint64_t *out = (uint64_t *) &res; out[0] = GNUNET_htonll(in[0]); return res; } /** * Convert double to host-byte-order * @param d the value in network byte order * @return the same value in host byte order */ double GNUNET_ntoh_double (double d) { double res; uint64_t *in = (uint64_t *) &d; uint64_t *out = (uint64_t *) &res; out[0] = GNUNET_ntohll(in[0]); return res; } /* end of common_endian.c */ gnunet-0.9.3/src/util/test_crypto_random.c0000644000175000017500000000360011760502551015574 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_crypto_random.c * @brief testcase for crypto_random.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_crypto_lib.h" static int test (enum GNUNET_CRYPTO_Quality mode) { int buf[1024]; unsigned int *b2; int i; unsigned long long n; for (i = 0; i < 1024; i++) GNUNET_break (1024 > (buf[i] = GNUNET_CRYPTO_random_u32 (mode, 1024))); for (i = 0; i < 10; i++) { b2 = GNUNET_CRYPTO_random_permute (mode, 1024); if (0 == memcmp (b2, buf, sizeof (buf))) { FPRINTF (stderr, "%s", "!"); GNUNET_free (b2); continue; } GNUNET_free (b2); break; } if (i == 10) return 1; /* virtually impossible... */ for (n = 10; n < 1024LL * 1024LL * 1024LL; n *= 10) GNUNET_break (n > GNUNET_CRYPTO_random_u64 (mode, n)); return 0; } int main (int argc, char *argv[]) { GNUNET_log_setup ("test-crypto-random", "WARNING", NULL); if (0 != test (GNUNET_CRYPTO_QUALITY_WEAK)) return 1; if (0 != test (GNUNET_CRYPTO_QUALITY_STRONG)) return 1; return 0; } gnunet-0.9.3/src/util/test_resolver_api_data.conf0000644000175000017500000000015711667453373017123 00000000000000[PATHS] SERVICEHOME = /tmp/test-gnunetd-statistics/ [resolver] PORT = 22354 HOSTNAME = localhost DEBUG = YES gnunet-0.9.3/src/util/connection.c0000644000175000017500000013253111760502551014022 00000000000000/* This file is part of GNUnet. (C) 2009, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/connection.c * @brief TCP connection management * @author Christian Grothoff * * This code is rather complex. Only modify it if you * 1) Have a NEW testcase showing that the new code * is needed and correct * 2) All EXISTING testcases pass with the new code * These rules should apply in general, but for this * module they are VERY, VERY important. */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_connection_lib.h" #include "gnunet_container_lib.h" #include "gnunet_resolver_service.h" #include "gnunet_scheduler_lib.h" #include "gnunet_server_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) /** * Transmission handle. There can only be one for each connection. */ struct GNUNET_CONNECTION_TransmitHandle { /** * Function to call if the send buffer has notify_size * bytes available. */ GNUNET_CONNECTION_TransmitReadyNotify notify_ready; /** * Closure for notify_ready. */ void *notify_ready_cls; /** * Our connection handle. */ struct GNUNET_CONNECTION_Handle *connection; /** * Timeout for receiving (in absolute time). */ struct GNUNET_TIME_Absolute transmit_timeout; /** * Task called on timeout. */ GNUNET_SCHEDULER_TaskIdentifier timeout_task; /** * At what number of bytes available in the * write buffer should the notify method be called? */ size_t notify_size; }; /** * During connect, we try multiple possible IP addresses * to find out which one might work. */ struct AddressProbe { /** * This is a linked list. */ struct AddressProbe *next; /** * This is a doubly-linked list. */ struct AddressProbe *prev; /** * The address; do not free (allocated at the end of this struct). */ const struct sockaddr *addr; /** * Underlying OS's socket. */ struct GNUNET_NETWORK_Handle *sock; /** * Connection for which we are probing. */ struct GNUNET_CONNECTION_Handle *connection; /** * Lenth of addr. */ socklen_t addrlen; /** * Task waiting for the connection to finish connecting. */ GNUNET_SCHEDULER_TaskIdentifier task; }; /** * @brief handle for a network connection */ struct GNUNET_CONNECTION_Handle { /** * Configuration to use. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Linked list of sockets we are currently trying out * (during connect). */ struct AddressProbe *ap_head; /** * Linked list of sockets we are currently trying out * (during connect). */ struct AddressProbe *ap_tail; /** * Network address of the other end-point, may be NULL. */ struct sockaddr *addr; /** * Pointer to the hostname if connection was * created using DNS lookup, otherwise NULL. */ char *hostname; /** * Underlying OS's socket, set to NULL after fatal errors. */ struct GNUNET_NETWORK_Handle *sock; /** * Function to call on data received, NULL if no receive is pending. */ GNUNET_CONNECTION_Receiver receiver; /** * Closure for receiver. */ void *receiver_cls; /** * Pointer to our write buffer. */ char *write_buffer; /** * Current size of our write buffer. */ size_t write_buffer_size; /** * Current write-offset in write buffer (where * would we write next). */ size_t write_buffer_off; /** * Current read-offset in write buffer (how many * bytes have already been sent). */ size_t write_buffer_pos; /** * Length of addr. */ socklen_t addrlen; /** * Read task that we may need to wait for. */ GNUNET_SCHEDULER_TaskIdentifier read_task; /** * Write task that we may need to wait for. */ GNUNET_SCHEDULER_TaskIdentifier write_task; /** * Handle to a pending DNS lookup request. */ struct GNUNET_RESOLVER_RequestHandle *dns_active; /** * The handle we return for GNUNET_CONNECTION_notify_transmit_ready. */ struct GNUNET_CONNECTION_TransmitHandle nth; /** * Timeout for receiving (in absolute time). */ struct GNUNET_TIME_Absolute receive_timeout; /** * Maximum number of bytes to read (for receiving). */ size_t max; /** * Port to connect to. */ uint16_t port; /** * When shutdown, do not ever actually close the socket, but * free resources. Only should ever be set if using program * termination as a signal (because only then will the leaked * socket be freed!) */ int16_t persist; }; /** * Set the persist option on this connection handle. Indicates * that the underlying socket or fd should never really be closed. * Used for indicating process death. * * @param connection the connection to set persistent */ void GNUNET_CONNECTION_persist_ (struct GNUNET_CONNECTION_Handle *connection) { connection->persist = GNUNET_YES; } /** * Disable the "CORK" feature for communication with the given connection, * forcing the OS to immediately flush the buffer on transmission * instead of potentially buffering multiple messages. Essentially * reduces the OS send buffers to zero. * Used to make sure that the last messages sent through the connection * reach the other side before the process is terminated. * * @param connection the connection to make flushing and blocking * @return GNUNET_OK on success */ int GNUNET_CONNECTION_disable_corking (struct GNUNET_CONNECTION_Handle *connection) { return GNUNET_NETWORK_socket_disable_corking (connection->sock); } /** * Create a connection handle by boxing an existing OS socket. The OS * socket should henceforth be no longer used directly. * GNUNET_connection_destroy will close it. * * @param osSocket existing socket to box * @return the boxed connection handle */ struct GNUNET_CONNECTION_Handle * GNUNET_CONNECTION_create_from_existing (struct GNUNET_NETWORK_Handle *osSocket) { struct GNUNET_CONNECTION_Handle *connection; connection = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle)); connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; connection->write_buffer = GNUNET_malloc (connection->write_buffer_size); connection->sock = osSocket; return connection; } /** * Create a connection handle by accepting on a listen socket. This * function may block if the listen socket has no connection ready. * * @param access function to use to check if access is allowed * @param access_cls closure for access * @param lsock listen socket * @return the connection handle, NULL on error */ struct GNUNET_CONNECTION_Handle * GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access, void *access_cls, struct GNUNET_NETWORK_Handle *lsock) { struct GNUNET_CONNECTION_Handle *connection; char addr[128]; socklen_t addrlen; struct GNUNET_NETWORK_Handle *sock; int aret; struct sockaddr_in *v4; struct sockaddr_in6 *v6; struct sockaddr *sa; void *uaddr; struct GNUNET_CONNECTION_Credentials *gcp; struct GNUNET_CONNECTION_Credentials gc; #ifdef SO_PEERCRED struct ucred uc; socklen_t olen; #endif addrlen = sizeof (addr); sock = GNUNET_NETWORK_socket_accept (lsock, (struct sockaddr *) &addr, &addrlen); if (NULL == sock) { LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "accept"); return NULL; } if ((addrlen > sizeof (addr)) || (addrlen < sizeof (sa_family_t))) { GNUNET_break (0); GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); return NULL; } sa = (struct sockaddr *) addr; v6 = (struct sockaddr_in6 *) addr; if ((AF_INET6 == sa->sa_family) && (IN6_IS_ADDR_V4MAPPED (&v6->sin6_addr))) { /* convert to V4 address */ v4 = GNUNET_malloc (sizeof (struct sockaddr_in)); memset (v4, 0, sizeof (struct sockaddr_in)); v4->sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN v4->sin_len = (u_char) sizeof (struct sockaddr_in); #endif memcpy (&v4->sin_addr, &((char *) &v6->sin6_addr)[sizeof (struct in6_addr) - sizeof (struct in_addr)], sizeof (struct in_addr)); v4->sin_port = v6->sin6_port; uaddr = v4; addrlen = sizeof (struct sockaddr_in); } else { uaddr = GNUNET_malloc (addrlen); memcpy (uaddr, addr, addrlen); } gcp = NULL; gc.uid = 0; gc.gid = 0; if (AF_UNIX == sa->sa_family) { #if HAVE_GETPEEREID /* most BSDs */ if (0 == getpeereid (GNUNET_NETWORK_get_fd (sock), &gc.uid, &gc.gid)) gcp = &gc; #else #ifdef SO_PEERCRED /* largely traditional GNU/Linux */ olen = sizeof (uc); if ((0 == getsockopt (GNUNET_NETWORK_get_fd (sock), SOL_SOCKET, SO_PEERCRED, &uc, &olen)) && (olen == sizeof (uc))) { gc.uid = uc.uid; gc.gid = uc.gid; gcp = &gc; } #else #if HAVE_GETPEERUCRED /* this is for Solaris 10 */ ucred_t *uc; uc = NULL; if (0 == getpeerucred (GNUNET_NETWORK_get_fd (sock), &uc)) { gc.uid = ucred_geteuid (uc); gc.gid = ucred_getegid (uc); gcp = &gc; } ucred_free (uc); #endif #endif #endif } if ((NULL != access) && (GNUNET_YES != (aret = access (access_cls, gcp, uaddr, addrlen)))) { if (GNUNET_NO == aret) LOG (GNUNET_ERROR_TYPE_INFO, _("Access denied to `%s'\n"), GNUNET_a2s (uaddr, addrlen)); GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_shutdown (sock, SHUT_RDWR)); GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); GNUNET_free (uaddr); return NULL; } connection = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle)); connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; connection->write_buffer = GNUNET_malloc (connection->write_buffer_size); connection->addr = uaddr; connection->addrlen = addrlen; connection->sock = sock; LOG (GNUNET_ERROR_TYPE_INFO, _("Accepting connection from `%s': %p\n"), GNUNET_a2s (uaddr, addrlen), connection); return connection; } /** * Obtain the network address of the other party. * * @param connection the client to get the address for * @param addr where to store the address * @param addrlen where to store the length of the address * @return GNUNET_OK on success */ int GNUNET_CONNECTION_get_address (struct GNUNET_CONNECTION_Handle *connection, void **addr, size_t * addrlen) { if ((NULL == connection->addr) || (0 == connection->addrlen)) return GNUNET_NO; *addr = GNUNET_malloc (connection->addrlen); memcpy (*addr, connection->addr, connection->addrlen); *addrlen = connection->addrlen; return GNUNET_OK; } /** * Tell the receiver callback that we had an IO error. * * @param connection connection to signal error * @param errcode error code to send */ static void signal_receive_error (struct GNUNET_CONNECTION_Handle *connection, int errcode) { GNUNET_CONNECTION_Receiver receiver; LOG (GNUNET_ERROR_TYPE_DEBUG, "Receive encounters error (%s), connection closed (%p)\n", STRERROR (errcode), connection); GNUNET_assert (NULL != (receiver = connection->receiver)); connection->receiver = NULL; receiver (connection->receiver_cls, NULL, 0, connection->addr, connection->addrlen, errcode); } /** * Tell the receiver callback that a timeout was reached. * * @param connection connection to signal for */ static void signal_receive_timeout (struct GNUNET_CONNECTION_Handle *connection) { GNUNET_CONNECTION_Receiver receiver; LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection signals timeout to receiver (%p)!\n", connection); GNUNET_assert (NULL != (receiver = connection->receiver)); connection->receiver = NULL; receiver (connection->receiver_cls, NULL, 0, NULL, 0, 0); } /** * We failed to transmit data to the service, signal the error. * * @param connection handle that had trouble * @param ecode error code (errno) */ static void signal_transmit_error (struct GNUNET_CONNECTION_Handle *connection, int ecode) { GNUNET_CONNECTION_TransmitReadyNotify notify; LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission encounterd error (%s), connection closed (%p)\n", STRERROR (ecode), connection); if (NULL != connection->sock) { GNUNET_NETWORK_socket_shutdown (connection->sock, SHUT_RDWR); GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (connection->sock)); connection->sock = NULL; GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->write_task); } if (GNUNET_SCHEDULER_NO_TASK != connection->read_task) { /* send errors trigger read errors... */ GNUNET_SCHEDULER_cancel (connection->read_task); connection->read_task = GNUNET_SCHEDULER_NO_TASK; signal_receive_timeout (connection); return; } if (NULL == connection->nth.notify_ready) return; /* nobody to tell about it */ notify = connection->nth.notify_ready; connection->nth.notify_ready = NULL; notify (connection->nth.notify_ready_cls, 0, NULL); } /** * We've failed for good to establish a connection (timeout or * no more addresses to try). * * @param connection the connection we tried to establish */ static void connect_fail_continuation (struct GNUNET_CONNECTION_Handle *connection) { LOG (GNUNET_ERROR_TYPE_INFO, _("Failed to establish TCP connection to `%s:%u', no further addresses to try.\n"), connection->hostname, connection->port); GNUNET_break (NULL == connection->ap_head); GNUNET_break (NULL == connection->ap_tail); GNUNET_break (GNUNET_NO == connection->dns_active); GNUNET_break (NULL == connection->sock); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->write_task); /* signal errors for jobs that used to wait on the connection */ if (NULL != connection->receiver) signal_receive_error (connection, ECONNREFUSED); if (NULL != connection->nth.notify_ready) { GNUNET_assert (connection->nth.timeout_task != GNUNET_SCHEDULER_NO_TASK); GNUNET_SCHEDULER_cancel (connection->nth.timeout_task); connection->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK; signal_transmit_error (connection, ECONNREFUSED); } } /** * We are ready to transmit (or got a timeout). * * @param cls our connection handle * @param tc task context describing why we are here */ static void transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * This function is called once we either timeout or have data ready * to read. * * @param cls connection to read from * @param tc scheduler context */ static void receive_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * We've succeeded in establishing a connection. * * @param connection the connection we tried to establish */ static void connect_success_continuation (struct GNUNET_CONNECTION_Handle *connection) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection to `%s' succeeded! (%p)\n", GNUNET_a2s (connection->addr, connection->addrlen), connection); /* trigger jobs that waited for the connection */ if (NULL != connection->receiver) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection succeeded, starting with receiving data (%p)\n", connection); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->read_task); connection->read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining (connection->receive_timeout), connection->sock, &receive_ready, connection); } if (NULL != connection->nth.notify_ready) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection succeeded, starting with sending data (%p)\n", connection); GNUNET_assert (connection->nth.timeout_task != GNUNET_SCHEDULER_NO_TASK); GNUNET_SCHEDULER_cancel (connection->nth.timeout_task); connection->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_assert (connection->write_task == GNUNET_SCHEDULER_NO_TASK); connection->write_task = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining (connection->nth.transmit_timeout), connection->sock, &transmit_ready, connection); } } /** * Scheduler let us know that we're either ready to write on the * socket OR connect timed out. Do the right thing. * * @param cls the "struct AddressProbe*" with the address that we are probing * @param tc success or failure info about the connect attempt. */ static void connect_probe_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct AddressProbe *ap = cls; struct GNUNET_CONNECTION_Handle *connection = ap->connection; struct AddressProbe *pos; int error; socklen_t len; GNUNET_assert (NULL != ap->sock); GNUNET_CONTAINER_DLL_remove (connection->ap_head, connection->ap_tail, ap); len = sizeof (error); errno = 0; error = 0; if ((0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) || (GNUNET_OK != GNUNET_NETWORK_socket_getsockopt (ap->sock, SOL_SOCKET, SO_ERROR, &error, &len)) || (0 != error)) { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock)); GNUNET_free (ap); if ((NULL == connection->ap_head) && (GNUNET_NO == connection->dns_active)) connect_fail_continuation (connection); return; } GNUNET_assert (NULL == connection->sock); connection->sock = ap->sock; GNUNET_assert (NULL == connection->addr); connection->addr = GNUNET_malloc (ap->addrlen); memcpy (connection->addr, ap->addr, ap->addrlen); connection->addrlen = ap->addrlen; GNUNET_free (ap); /* cancel all other attempts */ while (NULL != (pos = connection->ap_head)) { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock)); GNUNET_SCHEDULER_cancel (pos->task); GNUNET_CONTAINER_DLL_remove (connection->ap_head, connection->ap_tail, pos); GNUNET_free (pos); } connect_success_continuation (connection); } /** * Try to establish a connection given the specified address. * This function is called by the resolver once we have a DNS reply. * * @param cls our "struct GNUNET_CONNECTION_Handle *" * @param addr address to try, NULL for "last call" * @param addrlen length of addr */ static void try_connect_using_address (void *cls, const struct sockaddr *addr, socklen_t addrlen) { struct GNUNET_CONNECTION_Handle *connection = cls; struct AddressProbe *ap; struct GNUNET_TIME_Relative delay; if (NULL == addr) { connection->dns_active = NULL; if ((NULL == connection->ap_head) && (NULL == connection->sock)) connect_fail_continuation (connection); return; } if (NULL != connection->sock) return; /* already connected */ GNUNET_assert (NULL == connection->addr); /* try to connect */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Trying to connect using address `%s:%u/%s:%u'\n", connection->hostname, connection->port, GNUNET_a2s (addr, addrlen), connection->port); ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen); ap->addr = (const struct sockaddr *) &ap[1]; memcpy (&ap[1], addr, addrlen); ap->addrlen = addrlen; ap->connection = connection; switch (ap->addr->sa_family) { case AF_INET: ((struct sockaddr_in *) ap->addr)->sin_port = htons (connection->port); break; case AF_INET6: ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (connection->port); break; default: GNUNET_break (0); GNUNET_free (ap); return; /* not supported by us */ } ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family, SOCK_STREAM, 0); if (NULL == ap->sock) { GNUNET_free (ap); return; /* not supported by OS */ } LOG (GNUNET_ERROR_TYPE_INFO, _("Trying to connect to `%s' (%p)\n"), GNUNET_a2s (ap->addr, ap->addrlen), connection); if ((GNUNET_OK != GNUNET_NETWORK_socket_connect (ap->sock, ap->addr, ap->addrlen)) && (EINPROGRESS != errno)) { /* maybe refused / unsupported address, try next */ LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect"); #if 0 LOG (GNUNET_ERROR_TYPE_INFO, _("Failed to connect to `%s' (%p)\n"), GNUNET_a2s (ap->addr, ap->addrlen), connection); #endif GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock)); GNUNET_free (ap); return; } GNUNET_CONTAINER_DLL_insert (connection->ap_head, connection->ap_tail, ap); delay = GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT; if (NULL != connection->nth.notify_ready) delay = GNUNET_TIME_relative_min (delay, GNUNET_TIME_absolute_get_remaining (connection-> nth.transmit_timeout)); if (NULL != connection->receiver) delay = GNUNET_TIME_relative_min (delay, GNUNET_TIME_absolute_get_remaining (connection->receive_timeout)); ap->task = GNUNET_SCHEDULER_add_write_net (delay, ap->sock, &connect_probe_continuation, ap); } /** * Create a connection handle by (asynchronously) connecting to a host. * This function returns immediately, even if the connection has not * yet been established. This function only creates TCP connections. * * @param cfg configuration to use * @param hostname name of the host to connect to * @param port port to connect to * @return the connection handle */ struct GNUNET_CONNECTION_Handle * GNUNET_CONNECTION_create_from_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *hostname, uint16_t port) { struct GNUNET_CONNECTION_Handle *connection; GNUNET_assert (0 < strlen (hostname)); /* sanity check */ connection = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle)); connection->cfg = cfg; connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; connection->write_buffer = GNUNET_malloc (connection->write_buffer_size); connection->port = port; connection->hostname = GNUNET_strdup (hostname); connection->dns_active = GNUNET_RESOLVER_ip_get (connection->hostname, AF_UNSPEC, GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT, &try_connect_using_address, connection); return connection; } /** * Create a connection handle by connecting to a UNIX domain service. * This function returns immediately, even if the connection has not * yet been established. This function only creates UNIX connections. * * @param cfg configuration to use * @param unixpath path to connect to * @return the connection handle, NULL on systems without UNIX support */ struct GNUNET_CONNECTION_Handle * GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *unixpath) { #ifdef AF_UNIX struct GNUNET_CONNECTION_Handle *connection; struct sockaddr_un *un; size_t slen; GNUNET_assert (0 < strlen (unixpath)); /* sanity check */ un = GNUNET_malloc (sizeof (struct sockaddr_un)); un->sun_family = AF_UNIX; slen = strlen (unixpath); if (slen >= sizeof (un->sun_path)) slen = sizeof (un->sun_path) - 1; memcpy (un->sun_path, unixpath, slen); un->sun_path[slen] = '\0'; slen = sizeof (struct sockaddr_un); #if HAVE_SOCKADDR_IN_SIN_LEN un->sun_len = (u_char) slen; #endif #if LINUX un->sun_path[0] = '\0'; #endif connection = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle)); connection->cfg = cfg; connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; connection->write_buffer = GNUNET_malloc (connection->write_buffer_size); connection->port = 0; connection->hostname = NULL; connection->addr = (struct sockaddr *) un; connection->addrlen = slen; connection->sock = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0); if (NULL == connection->sock) { GNUNET_free (connection->addr); GNUNET_free (connection->write_buffer); GNUNET_free (connection); return NULL; } if (GNUNET_OK != GNUNET_NETWORK_socket_connect (connection->sock, connection->addr, connection->addrlen)) { /* Just return; we expect everything to work eventually so don't fail HARD */ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (connection->sock)); connection->sock = NULL; return connection; } connect_success_continuation (connection); return connection; #else return NULL; #endif } /** * Create a connection handle by (asynchronously) connecting to a host. * This function returns immediately, even if the connection has not * yet been established. This function only creates TCP connections. * * @param af_family address family to use * @param serv_addr server address * @param addrlen length of server address * @return the connection handle */ struct GNUNET_CONNECTION_Handle * GNUNET_CONNECTION_create_from_sockaddr (int af_family, const struct sockaddr *serv_addr, socklen_t addrlen) { struct GNUNET_NETWORK_Handle *s; struct GNUNET_CONNECTION_Handle *connection; s = GNUNET_NETWORK_socket_create (af_family, SOCK_STREAM, 0); if (NULL == s) { LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "socket"); return NULL; } if ((GNUNET_OK != GNUNET_NETWORK_socket_connect (s, serv_addr, addrlen)) && (EINPROGRESS != errno)) { /* maybe refused / unsupported address, try next */ LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect"); LOG (GNUNET_ERROR_TYPE_INFO, _("Attempt to connect to `%s' failed\n"), GNUNET_a2s (serv_addr, addrlen)); GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s)); return NULL; } connection = GNUNET_CONNECTION_create_from_existing (s); connection->addr = GNUNET_malloc (addrlen); memcpy (connection->addr, serv_addr, addrlen); connection->addrlen = addrlen; LOG (GNUNET_ERROR_TYPE_INFO, _("Trying to connect to `%s' (%p)\n"), GNUNET_a2s (serv_addr, addrlen), connection); return connection; } /** * Check if connection is valid (no fatal errors have happened so far). * Note that a connection that is still trying to connect is considered * valid. * * @param connection connection to check * @return GNUNET_YES if valid, GNUNET_NO otherwise */ int GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *connection) { if ((NULL != connection->ap_head) || (NULL != connection->dns_active)) return GNUNET_YES; /* still trying to connect */ return (NULL == connection->sock) ? GNUNET_NO : GNUNET_YES; } /** * Close the connection and free associated resources. There must * not be any pending requests for reading or writing to the * connection at this time. * * @param connection connection to destroy */ void GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection) { struct AddressProbe *pos; LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down connection (%p)\n", connection); GNUNET_assert (NULL == connection->nth.notify_ready); GNUNET_assert (NULL == connection->receiver); if (GNUNET_SCHEDULER_NO_TASK != connection->write_task) { GNUNET_SCHEDULER_cancel (connection->write_task); connection->write_task = GNUNET_SCHEDULER_NO_TASK; connection->write_buffer_off = 0; } if (GNUNET_SCHEDULER_NO_TASK != connection->read_task) { GNUNET_SCHEDULER_cancel (connection->read_task); connection->read_task = GNUNET_SCHEDULER_NO_TASK; } if (GNUNET_SCHEDULER_NO_TASK != connection->nth.timeout_task) { GNUNET_SCHEDULER_cancel (connection->nth.timeout_task); connection->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK; } connection->nth.notify_ready = NULL; if (NULL != connection->dns_active) { GNUNET_RESOLVER_request_cancel (connection->dns_active); connection->dns_active = NULL; } while (NULL != (pos = connection->ap_head)) { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock)); GNUNET_SCHEDULER_cancel (pos->task); GNUNET_CONTAINER_DLL_remove (connection->ap_head, connection->ap_tail, pos); GNUNET_free (pos); } if ( (NULL != connection->sock) && (GNUNET_YES != connection->persist) ) { if ((GNUNET_YES != GNUNET_NETWORK_socket_shutdown (connection->sock, SHUT_RDWR)) && (ENOTCONN != errno) && (ECONNRESET != errno) ) LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "shutdown"); } if (NULL != connection->sock) { if (GNUNET_YES != connection->persist) GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (connection->sock)); else GNUNET_free (connection->sock); /* at least no memory leak (we deliberately * leak the socket in this special case) ... */ } GNUNET_free_non_null (connection->addr); GNUNET_free_non_null (connection->hostname); GNUNET_free (connection->write_buffer); GNUNET_free (connection); } /** * This function is called once we either timeout * or have data ready to read. * * @param cls connection to read from * @param tc scheduler context */ static void receive_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CONNECTION_Handle *connection = cls; char buffer[connection->max]; ssize_t ret; GNUNET_CONNECTION_Receiver receiver; connection->read_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) { /* ignore shutdown request, go again immediately */ connection->read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining (connection->receive_timeout), connection->sock, &receive_ready, connection); return; } if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Receive from `%s' encounters error: timeout (%p)\n", GNUNET_a2s (connection->addr, connection->addrlen), GNUNET_TIME_absolute_get_duration (connection->receive_timeout).rel_value, connection); signal_receive_timeout (connection); return; } if (NULL == connection->sock) { /* connect failed for good */ signal_receive_error (connection, ECONNREFUSED); return; } GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready, connection->sock)); RETRY: ret = GNUNET_NETWORK_socket_recv (connection->sock, buffer, connection->max); if (-1 == ret) { if (EINTR == errno) goto RETRY; signal_receive_error (connection, errno); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "receive_ready read %u/%u bytes from `%s' (%p)!\n", (unsigned int) ret, connection->max, GNUNET_a2s (connection->addr, connection->addrlen), connection); GNUNET_assert (NULL != (receiver = connection->receiver)); connection->receiver = NULL; receiver (connection->receiver_cls, buffer, ret, connection->addr, connection->addrlen, 0); } /** * Receive data from the given connection. Note that this function will * call "receiver" asynchronously using the scheduler. It will * "immediately" return. Note that there MUST only be one active * receive call per connection at any given point in time (so do not * call receive again until the receiver callback has been invoked). * * @param connection connection handle * @param max maximum number of bytes to read * @param timeout maximum amount of time to wait * @param receiver function to call with received data * @param receiver_cls closure for receiver */ void GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *connection, size_t max, struct GNUNET_TIME_Relative timeout, GNUNET_CONNECTION_Receiver receiver, void *receiver_cls) { GNUNET_assert ((GNUNET_SCHEDULER_NO_TASK == connection->read_task) && (NULL == connection->receiver)); GNUNET_assert (NULL != receiver); connection->receiver = receiver; connection->receiver_cls = receiver_cls; connection->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout); connection->max = max; if (NULL != connection->sock) { connection->read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining (connection->receive_timeout), connection->sock, &receive_ready, connection); return; } if ((NULL == connection->dns_active) && (NULL == connection->ap_head)) { connection->receiver = NULL; receiver (receiver_cls, NULL, 0, NULL, 0, ETIMEDOUT); return; } } /** * Cancel receive job on the given connection. Note that the * receiver callback must not have been called yet in order * for the cancellation to be valid. * * @param connection connection handle * @return closure of the original receiver callback closure */ void * GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *connection) { if (GNUNET_SCHEDULER_NO_TASK != connection->read_task) { GNUNET_assert (connection == GNUNET_SCHEDULER_cancel (connection->read_task)); connection->read_task = GNUNET_SCHEDULER_NO_TASK; } connection->receiver = NULL; return connection->receiver_cls; } /** * Try to call the transmit notify method (check if we do * have enough space available first)! * * @param connection connection for which we should do this processing * @return GNUNET_YES if we were able to call notify */ static int process_notify (struct GNUNET_CONNECTION_Handle *connection) { size_t used; size_t avail; size_t size; GNUNET_CONNECTION_TransmitReadyNotify notify; GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->write_task); if (NULL == (notify = connection->nth.notify_ready)) return GNUNET_NO; used = connection->write_buffer_off - connection->write_buffer_pos; avail = connection->write_buffer_size - used; size = connection->nth.notify_size; if (size > avail) return GNUNET_NO; connection->nth.notify_ready = NULL; if (connection->write_buffer_size - connection->write_buffer_off < size) { /* need to compact */ memmove (connection->write_buffer, &connection->write_buffer[connection->write_buffer_pos], used); connection->write_buffer_off -= connection->write_buffer_pos; connection->write_buffer_pos = 0; } avail = connection->write_buffer_size - connection->write_buffer_off; GNUNET_assert (avail >= size); size = notify (connection->nth.notify_ready_cls, avail, &connection->write_buffer[connection->write_buffer_off]); GNUNET_assert (size <= avail); if (0 != size) connection->write_buffer_off += size; return GNUNET_YES; } /** * Task invoked by the scheduler when a call to transmit * is timing out (we never got enough buffer space to call * the callback function before the specified timeout * expired). * * This task notifies the client about the timeout. * * @param cls the 'struct GNUNET_CONNECTION_Handle' * @param tc scheduler context */ static void transmit_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CONNECTION_Handle *connection = cls; GNUNET_CONNECTION_TransmitReadyNotify notify; connection->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK; LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmit to `%s:%u/%s' fails, time out reached (%p).\n", connection->hostname, connection->port, GNUNET_a2s (connection->addr, connection->addrlen), connection); notify = connection->nth.notify_ready; GNUNET_assert (NULL != notify); connection->nth.notify_ready = NULL; notify (connection->nth.notify_ready_cls, 0, NULL); } /** * Task invoked by the scheduler when we failed to connect * at the time of being asked to transmit. * * This task notifies the client about the error. * * @param cls the 'struct GNUNET_CONNECTION_Handle' * @param tc scheduler context */ static void connect_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CONNECTION_Handle *connection = cls; GNUNET_CONNECTION_TransmitReadyNotify notify; LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission request of size %u fails (%s/%u), connection failed (%p).\n", connection->nth.notify_size, connection->hostname, connection->port, connection); connection->write_task = GNUNET_SCHEDULER_NO_TASK; notify = connection->nth.notify_ready; connection->nth.notify_ready = NULL; notify (connection->nth.notify_ready_cls, 0, NULL); } /** * We are ready to transmit (or got a timeout). * * @param cls our connection handle * @param tc task context describing why we are here */ static void transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CONNECTION_Handle *connection = cls; GNUNET_CONNECTION_TransmitReadyNotify notify; ssize_t ret; size_t have; LOG (GNUNET_ERROR_TYPE_DEBUG, "transmit_ready running (%p).\n", connection); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != connection->write_task); connection->write_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->nth.timeout_task); if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) { if (NULL != connection->sock) goto SCHEDULE_WRITE; /* ignore shutdown, go again immediately */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmit to `%s' fails, shutdown happened (%p).\n", GNUNET_a2s (connection->addr, connection->addrlen), connection); notify = connection->nth.notify_ready; if (NULL != notify) { connection->nth.notify_ready = NULL; notify (connection->nth.notify_ready_cls, 0, NULL); } return; } if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmit to `%s' fails, time out reached (%p).\n", GNUNET_a2s (connection->addr, connection->addrlen), connection); notify = connection->nth.notify_ready; GNUNET_assert (NULL != notify); connection->nth.notify_ready = NULL; notify (connection->nth.notify_ready_cls, 0, NULL); return; } GNUNET_assert (NULL != connection->sock); if (NULL == tc->write_ready) { /* special circumstances (in particular, PREREQ_DONE after * connect): not yet ready to write, but no "fatal" error either. * Hence retry. */ goto SCHEDULE_WRITE; } if (!GNUNET_NETWORK_fdset_isset (tc->write_ready, connection->sock)) { GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->write_task); /* special circumstances (in particular, shutdown): not yet ready * to write, but no "fatal" error either. Hence retry. */ goto SCHEDULE_WRITE; } GNUNET_assert (connection->write_buffer_off >= connection->write_buffer_pos); if ((NULL != connection->nth.notify_ready) && (connection->write_buffer_size < connection->nth.notify_size)) { connection->write_buffer = GNUNET_realloc (connection->write_buffer, connection->nth.notify_size); connection->write_buffer_size = connection->nth.notify_size; } process_notify (connection); have = connection->write_buffer_off - connection->write_buffer_pos; if (0 == have) { /* no data ready for writing, terminate write loop */ return; } GNUNET_assert (have <= connection->write_buffer_size); GNUNET_assert (have + connection->write_buffer_pos <= connection->write_buffer_size); GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size); RETRY: ret = GNUNET_NETWORK_socket_send (connection->sock, &connection->write_buffer[connection->write_buffer_pos], have); if (-1 == ret) { if (EINTR == errno) goto RETRY; if (GNUNET_SCHEDULER_NO_TASK != connection->write_task) { GNUNET_SCHEDULER_cancel (connection->write_task); connection->write_task = GNUNET_SCHEDULER_NO_TASK; } signal_transmit_error (connection, errno); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection transmitted %u/%u bytes to `%s' (%p)\n", (unsigned int) ret, have, GNUNET_a2s (connection->addr, connection->addrlen), connection); connection->write_buffer_pos += ret; if (connection->write_buffer_pos == connection->write_buffer_off) { /* transmitted all pending data */ connection->write_buffer_pos = 0; connection->write_buffer_off = 0; } if ((0 == connection->write_buffer_off) && (NULL == connection->nth.notify_ready)) return; /* all data sent! */ /* not done writing, schedule more */ SCHEDULE_WRITE: LOG (GNUNET_ERROR_TYPE_DEBUG, "Re-scheduling transmit_ready (more to do) (%p).\n", connection); have = connection->write_buffer_off - connection->write_buffer_pos; GNUNET_assert ((NULL != connection->nth.notify_ready) || (have > 0)); if (GNUNET_SCHEDULER_NO_TASK == connection->write_task) connection->write_task = GNUNET_SCHEDULER_add_write_net ((connection->nth.notify_ready == NULL) ? GNUNET_TIME_UNIT_FOREVER_REL : GNUNET_TIME_absolute_get_remaining (connection->nth.transmit_timeout), connection->sock, &transmit_ready, connection); } /** * Ask the connection to call us once the specified number of bytes * are free in the transmission buffer. May call the notify * method immediately if enough space is available. * * @param connection connection * @param size number of bytes to send * @param timeout after how long should we give up (and call * notify with buf NULL and size 0)? * @param notify function to call * @param notify_cls closure for notify * @return non-NULL if the notify callback was queued, * NULL if we are already going to notify someone else (busy) */ struct GNUNET_CONNECTION_TransmitHandle * GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle *connection, size_t size, struct GNUNET_TIME_Relative timeout, GNUNET_CONNECTION_TransmitReadyNotify notify, void *notify_cls) { if (NULL != connection->nth.notify_ready) { GNUNET_assert (0); return NULL; } GNUNET_assert (NULL != notify); GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE); GNUNET_assert (connection->write_buffer_off <= connection->write_buffer_size); GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size); GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_off); connection->nth.notify_ready = notify; connection->nth.notify_ready_cls = notify_cls; connection->nth.connection = connection; connection->nth.notify_size = size; connection->nth.transmit_timeout = GNUNET_TIME_relative_to_absolute (timeout); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->nth.timeout_task); if ((NULL == connection->sock) && (NULL == connection->ap_head) && (NULL == connection->dns_active)) { if (GNUNET_SCHEDULER_NO_TASK != connection->write_task) GNUNET_SCHEDULER_cancel (connection->write_task); connection->write_task = GNUNET_SCHEDULER_add_now (&connect_error, connection); return &connection->nth; } if (GNUNET_SCHEDULER_NO_TASK != connection->write_task) return &connection->nth; /* previous transmission still in progress */ if (NULL != connection->sock) { /* connected, try to transmit now */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Scheduling transmission (%p).\n", connection); connection->write_task = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining (connection->nth.transmit_timeout), connection->sock, &transmit_ready, connection); return &connection->nth; } /* not yet connected, wait for connection */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Need to wait to schedule transmission for connection, adding timeout task (%p).\n", connection); connection->nth.timeout_task = GNUNET_SCHEDULER_add_delayed (timeout, &transmit_timeout, connection); return &connection->nth; } /** * Cancel the specified transmission-ready notification. * * @param th notification to cancel */ void GNUNET_CONNECTION_notify_transmit_ready_cancel (struct GNUNET_CONNECTION_TransmitHandle *th) { GNUNET_assert (NULL != th->notify_ready); th->notify_ready = NULL; if (GNUNET_SCHEDULER_NO_TASK != th->timeout_task) { GNUNET_SCHEDULER_cancel (th->timeout_task); th->timeout_task = GNUNET_SCHEDULER_NO_TASK; } if (GNUNET_SCHEDULER_NO_TASK != th->connection->write_task) { GNUNET_SCHEDULER_cancel (th->connection->write_task); th->connection->write_task = GNUNET_SCHEDULER_NO_TASK; } } /* end of connection.c */ gnunet-0.9.3/src/util/test_peer.c0000644000175000017500000000677611760502551013670 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_peer.c * @brief testcase for peer.c * @author Safey Mohammed */ #include "platform.h" #include "gnunet_crypto_lib.h" #include "gnunet_peer_lib.h" #define NUMBER_OF_PEERS 10 #define VERBOSE GNUNET_NO /** * A list of Peer ID's to play with */ static struct GNUNET_PeerIdentity pidArr[NUMBER_OF_PEERS]; static void generatePeerIdList () { int i; for (i = 0; i < NUMBER_OF_PEERS; i++) { GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &pidArr[i].hashPubKey); #if VERBOSE printf ("Peer %d: %s\n", i, GNUNET_i2s (&pidArr[i])); #endif } } static int check () { int i; GNUNET_PEER_Id pid; struct GNUNET_PeerIdentity res; struct GNUNET_PeerIdentity zero; GNUNET_PEER_Id ids[] = { 1, 2, 3 }; GNUNET_assert (0 == GNUNET_PEER_intern (NULL)); /* Insert Peers into PeerEntry table and hashmap */ for (i = 0; i < NUMBER_OF_PEERS; i++) { pid = GNUNET_PEER_intern (&pidArr[i]); if (pid != (i + 1)) { FPRINTF (stderr, "%s", "Unexpected Peer ID returned by intern function\n"); return 1; } } /* Referencing the first 3 peers once again */ for (i = 0; i < 3; i++) { pid = GNUNET_PEER_intern (&pidArr[i]); if (pid != (i + 1)) { FPRINTF (stderr, "%s", "Unexpected Peer ID returned by intern function\n"); return 1; } } /* Dereferencing the first 3 peers once [decrementing their reference count] */ GNUNET_PEER_decrement_rcs (ids, 3); /* re-referencing the first 3 peers using the change_rc function */ for (i = 1; i <= 3; i++) GNUNET_PEER_change_rc (i, 1); /* Removing the second Peer from the PeerEntry hash map */ GNUNET_PEER_change_rc (2, -2); /* convert the pid of the first PeerEntry into that of the third */ GNUNET_PEER_resolve (1, &res); GNUNET_assert (0 == memcmp (&res, &pidArr[0], sizeof (res))); /* * Attempt to convert pid = 0 (which is reserved) * into a peer identity object, the peer identity memory * is expected to be set to zero */ memset (&zero, 0, sizeof (struct GNUNET_PeerIdentity)); GNUNET_log_skip (1, GNUNET_YES); GNUNET_PEER_resolve (0, &res); GNUNET_assert (0 == memcmp (&res, &zero, sizeof (res))); /* Removing peer entries 1 and 3 from table using the list decrement function */ /* If count = 0, nothing should be done whatsoever */ GNUNET_PEER_decrement_rcs (ids, 0); ids[1] = 3; GNUNET_PEER_decrement_rcs (ids, 2); GNUNET_PEER_decrement_rcs (ids, 2); return 0; } int main () { int i; GNUNET_log_setup ("test-peer", "ERROR", NULL); for (i = 0; i < 1; i++) { generatePeerIdList (); if (0 != check ()) return 1; } return 0; } /* end of test_peer.c */ gnunet-0.9.3/src/util/test_configuration_data.conf0000644000175000017500000000042611667453373017277 00000000000000[PATHS] SUBST=/hello [GNUNET] SUBST=hello GNUNET_HOME=/tmp [test] a=a b=b five=5 [more] c=c five=42 [last] test = $SUBST/world boom = "1 2 3 testing" trailing = YES size = 512 KiB [FILENAMES] test = "/Hello /File\ Name /World" [TESTING] WEAKRANDOM = YES gnunet-0.9.3/src/util/test_os_start_process.c0000644000175000017500000001572011760502551016316 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_os_start_process.c * @brief testcase for os start process code * * This testcase simply calls the os start process code * giving a file descriptor to write stdout to. If the * correct data "HELLO" is read then all is well. */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "disk.h" #define VERBOSE GNUNET_NO static char *test_phrase = "HELLO WORLD"; static int ok; static struct GNUNET_OS_Process *proc; /* Pipe to write to started processes stdin (on write end) */ static struct GNUNET_DISK_PipeHandle *hello_pipe_stdin; /* Pipe to read from started processes stdout (on read end) */ static struct GNUNET_DISK_PipeHandle *hello_pipe_stdout; static GNUNET_SCHEDULER_TaskIdentifier die_task; static void end_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); } GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (proc)); GNUNET_OS_process_destroy (proc); proc = NULL; GNUNET_DISK_pipe_close (hello_pipe_stdout); GNUNET_DISK_pipe_close (hello_pipe_stdin); } static void read_call (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_DISK_FileHandle *stdout_read_handle = cls; char buf[16]; memset (&buf, 0, sizeof (buf)); int bytes; bytes = GNUNET_DISK_file_read (stdout_read_handle, &buf, sizeof (buf)); #if VERBOSE FPRINTF (stderr, "bytes is %d\n", bytes); #endif if (bytes < 1) { GNUNET_break (0); ok = 1; GNUNET_SCHEDULER_cancel (die_task); GNUNET_SCHEDULER_add_now (&end_task, NULL); return; } ok = strncmp (&buf[0], test_phrase, strlen (test_phrase)); #if VERBOSE FPRINTF (stderr, "read %s\n", &buf[0]); #endif if (ok == 0) { GNUNET_SCHEDULER_cancel (die_task); GNUNET_SCHEDULER_add_now (&end_task, NULL); return; } GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, stdout_read_handle, &read_call, stdout_read_handle); } static void run_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { char *fn; const struct GNUNET_DISK_FileHandle *stdout_read_handle; const struct GNUNET_DISK_FileHandle *wh; GNUNET_asprintf (&fn, "cat"); hello_pipe_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO); hello_pipe_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); if ((hello_pipe_stdout == NULL) || (hello_pipe_stdin == NULL)) { GNUNET_break (0); ok = 1; GNUNET_free (fn); return; } proc = GNUNET_OS_start_process (GNUNET_NO, hello_pipe_stdin, hello_pipe_stdout, fn, "test_gnunet_echo_hello", "-", NULL); GNUNET_free (fn); /* Close the write end of the read pipe */ GNUNET_DISK_pipe_close_end (hello_pipe_stdout, GNUNET_DISK_PIPE_END_WRITE); /* Close the read end of the write pipe */ GNUNET_DISK_pipe_close_end (hello_pipe_stdin, GNUNET_DISK_PIPE_END_READ); wh = GNUNET_DISK_pipe_handle (hello_pipe_stdin, GNUNET_DISK_PIPE_END_WRITE); /* Write the test_phrase to the cat process */ if (GNUNET_DISK_file_write (wh, test_phrase, strlen (test_phrase) + 1) != strlen (test_phrase) + 1) { GNUNET_break (0); ok = 1; return; } /* Close the write end to end the cycle! */ GNUNET_DISK_pipe_close_end (hello_pipe_stdin, GNUNET_DISK_PIPE_END_WRITE); stdout_read_handle = GNUNET_DISK_pipe_handle (hello_pipe_stdout, GNUNET_DISK_PIPE_END_READ); die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1), &end_task, NULL); GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, stdout_read_handle, &read_call, (void *) stdout_read_handle); } /** * Main method, starts scheduler with task1, * checks that "ok" is correct at the end. */ static int check_run () { ok = 1; GNUNET_SCHEDULER_run (&run_task, &ok); return ok; } /** * Test killing via pipe. */ static int check_kill () { hello_pipe_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO); hello_pipe_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); if ((hello_pipe_stdout == NULL) || (hello_pipe_stdin == NULL)) { return 1; } proc = GNUNET_OS_start_process (GNUNET_YES, hello_pipe_stdin, hello_pipe_stdout, "cat", "gnunet-service-resolver", "-", NULL); sleep (1); /* give process time to start and open pipe */ if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); } GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (proc)); GNUNET_OS_process_destroy (proc); proc = NULL; GNUNET_DISK_pipe_close (hello_pipe_stdout); GNUNET_DISK_pipe_close (hello_pipe_stdin); return 0; } /** * Test killing via pipe. */ static int check_instant_kill () { hello_pipe_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO); hello_pipe_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); if ((hello_pipe_stdout == NULL) || (hello_pipe_stdin == NULL)) { return 1; } proc = GNUNET_OS_start_process (GNUNET_YES, hello_pipe_stdin, hello_pipe_stdout, "cat", "gnunet-service-resolver", "-", NULL); if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); } GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (proc)); GNUNET_OS_process_destroy (proc); proc = NULL; GNUNET_DISK_pipe_close (hello_pipe_stdout); GNUNET_DISK_pipe_close (hello_pipe_stdin); return 0; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-os-start-process", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = 0; ret |= check_run (); ret |= check_kill (); ret |= check_instant_kill (); return ret; } gnunet-0.9.3/src/util/signal.c0000644000175000017500000000460211760502551013135 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2006 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/signal.c * @brief code for installing and uninstalling signal handlers * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_signal_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) struct GNUNET_SIGNAL_Context { int sig; GNUNET_SIGNAL_Handler method; #ifndef MINGW struct sigaction oldsig; #endif }; #ifdef WINDOWS GNUNET_SIGNAL_Handler w32_sigchld_handler = NULL; #endif struct GNUNET_SIGNAL_Context * GNUNET_SIGNAL_handler_install (int signum, GNUNET_SIGNAL_Handler handler) { struct GNUNET_SIGNAL_Context *ret; #ifndef MINGW struct sigaction sig; #endif ret = GNUNET_malloc (sizeof (struct GNUNET_SIGNAL_Context)); ret->sig = signum; ret->method = handler; #ifndef MINGW memset (&sig, 0, sizeof (sig)); sig.sa_handler = (void *) handler; sigemptyset (&sig.sa_mask); #ifdef SA_INTERRUPT sig.sa_flags = SA_INTERRUPT; /* SunOS */ #else sig.sa_flags = SA_RESTART; #endif sigaction (signum, &sig, &ret->oldsig); #else if (signum == GNUNET_SIGCHLD) w32_sigchld_handler = handler; else { __p_sig_fn_t sigret = signal (signum, (__p_sig_fn_t) handler); if (sigret == SIG_ERR) { LOG (GNUNET_ERROR_TYPE_WARNING, _("signal (%d, %p) returned %d.\n"), signum, handler, sigret); } } #endif return ret; } void GNUNET_SIGNAL_handler_uninstall (struct GNUNET_SIGNAL_Context *ctx) { #ifndef MINGW struct sigaction sig; sigemptyset (&sig.sa_mask); sigaction (ctx->sig, &ctx->oldsig, &sig); #endif GNUNET_free (ctx); } gnunet-0.9.3/src/util/test_crypto_hkdf.c0000644000175000017500000003437511760502551015245 00000000000000/* Copyright (c) 2010 Nils Durner Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** * @file src/util/test_crypt_hkdf.c * @brief Testcases for HKDF * @todo: test for out_len < hash_len * @author Nils Durner */ #include #include "platform.h" #include "gnunet_crypto_lib.h" void tc1 () { unsigned char ikm[22] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b }; unsigned char salt[13] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c }; unsigned char info[10] = { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9 }; unsigned char okm[42] = { 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c, 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf, 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, 0x58, 0x65 }; unsigned char result[44]; int l = 42; memset (result, 0, sizeof (result)); GNUNET_assert (GNUNET_CRYPTO_hkdf (result, l, GCRY_MD_SHA256, GCRY_MD_SHA256, salt, sizeof (salt), ikm, sizeof (ikm), info, sizeof (info), NULL) == GNUNET_YES); GNUNET_assert (memcmp (result, okm, l) == 0); GNUNET_assert (memcmp (result + l, "\0", 2) == 0); } void tc2 () { unsigned char ikm[80] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f }; unsigned char salt[80] = { 0x60, 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, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf }; unsigned char info[80] = { 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; unsigned char okm[82] = { 0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1, 0xc8, 0xe7, 0xf7, 0x8c, 0x59, 0x6a, 0x49, 0x34, 0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, 0xfa, 0xd8, 0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, 0xa9, 0x7c, 0x59, 0x04, 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72, 0x71, 0xcb, 0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09, 0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8, 0x36, 0x77, 0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71, 0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec, 0x3e, 0x87, 0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f, 0x1d, 0x87 }; char result[84]; int l = 82; memset (result, 0, sizeof (result)); GNUNET_assert (GNUNET_CRYPTO_hkdf (result, l, GCRY_MD_SHA256, GCRY_MD_SHA256, salt, sizeof (salt), ikm, sizeof (ikm), info, sizeof (info), NULL) == GNUNET_YES); GNUNET_assert (memcmp (result, okm, l) == 0); GNUNET_assert (memcmp (result + l, "\0", 2) == 0); } void tc3 () { unsigned char ikm[22] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b }; unsigned char okm[42] = { 0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f, 0x71, 0x5f, 0x80, 0x2a, 0x06, 0x3c, 0x5a, 0x31, 0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, 0x87, 0x9e, 0xc3, 0x45, 0x4e, 0x5f, 0x3c, 0x73, 0x8d, 0x2d, 0x9d, 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a, 0x96, 0xc8 }; unsigned char result[44]; int l = 42; memset (result, 0, sizeof (result)); GNUNET_assert (GNUNET_CRYPTO_hkdf (result, l, GCRY_MD_SHA256, GCRY_MD_SHA256, NULL, 0, ikm, sizeof (ikm), NULL, 0, NULL) == GNUNET_YES); GNUNET_assert (memcmp (result, okm, l) == 0); GNUNET_assert (memcmp (result + l, "\0", 2) == 0); } void tc4 () { unsigned char ikm[11] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b }; unsigned char salt[13] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c }; unsigned char info[10] = { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9 }; unsigned char okm[42] = { 0x08, 0x5a, 0x01, 0xea, 0x1b, 0x10, 0xf3, 0x69, 0x33, 0x06, 0x8b, 0x56, 0xef, 0xa5, 0xad, 0x81, 0xa4, 0xf1, 0x4b, 0x82, 0x2f, 0x5b, 0x09, 0x15, 0x68, 0xa9, 0xcd, 0xd4, 0xf1, 0x55, 0xfd, 0xa2, 0xc2, 0x2e, 0x42, 0x24, 0x78, 0xd3, 0x05, 0xf3, 0xf8, 0x96 }; char result[84]; int l = 42; memset (result, 0, sizeof (result)); GNUNET_assert (GNUNET_CRYPTO_hkdf (result, l, GCRY_MD_SHA1, GCRY_MD_SHA1, salt, sizeof (salt), ikm, sizeof (ikm), info, sizeof (info), NULL) == GNUNET_YES); GNUNET_assert (memcmp (result, okm, l) == 0); GNUNET_assert (memcmp (result + l, "\0", 2) == 0); } void tc5 () { unsigned char ikm[80] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f }; unsigned char salt[80] = { 0x60, 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, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf }; unsigned char info[80] = { 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; unsigned char okm[82] = { 0x0b, 0xd7, 0x70, 0xa7, 0x4d, 0x11, 0x60, 0xf7, 0xc9, 0xf1, 0x2c, 0xd5, 0x91, 0x2a, 0x06, 0xeb, 0xff, 0x6a, 0xdc, 0xae, 0x89, 0x9d, 0x92, 0x19, 0x1f, 0xe4, 0x30, 0x56, 0x73, 0xba, 0x2f, 0xfe, 0x8f, 0xa3, 0xf1, 0xa4, 0xe5, 0xad, 0x79, 0xf3, 0xf3, 0x34, 0xb3, 0xb2, 0x02, 0xb2, 0x17, 0x3c, 0x48, 0x6e, 0xa3, 0x7c, 0xe3, 0xd3, 0x97, 0xed, 0x03, 0x4c, 0x7f, 0x9d, 0xfe, 0xb1, 0x5c, 0x5e, 0x92, 0x73, 0x36, 0xd0, 0x44, 0x1f, 0x4c, 0x43, 0x00, 0xe2, 0xcf, 0xf0, 0xd0, 0x90, 0x0b, 0x52, 0xd3, 0xb4 }; char result[84]; int l = 82; memset (result, 0, sizeof (result)); GNUNET_assert (GNUNET_CRYPTO_hkdf (result, l, GCRY_MD_SHA1, GCRY_MD_SHA1, salt, sizeof (salt), ikm, sizeof (ikm), info, sizeof (info), NULL) == GNUNET_YES); GNUNET_assert (memcmp (result, okm, l) == 0); GNUNET_assert (memcmp (result + l, "\0", 2) == 0); } void tc6 () { unsigned char ikm[22] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b }; unsigned char okm[42] = { 0x0a, 0xc1, 0xaf, 0x70, 0x02, 0xb3, 0xd7, 0x61, 0xd1, 0xe5, 0x52, 0x98, 0xda, 0x9d, 0x05, 0x06, 0xb9, 0xae, 0x52, 0x05, 0x72, 0x20, 0xa3, 0x06, 0xe0, 0x7b, 0x6b, 0x87, 0xe8, 0xdf, 0x21, 0xd0, 0xea, 0x00, 0x03, 0x3d, 0xe0, 0x39, 0x84, 0xd3, 0x49, 0x18 }; char result[44]; int l = 42; memset (result, 0, sizeof (result)); GNUNET_assert (GNUNET_CRYPTO_hkdf (result, l, GCRY_MD_SHA1, GCRY_MD_SHA1, NULL, 0, ikm, sizeof (ikm), NULL, 0, NULL) == GNUNET_YES); GNUNET_assert (memcmp (result, okm, l) == 0); GNUNET_assert (memcmp (result + l, "\0", 2) == 0); } void tc7 () { unsigned char ikm[80] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f }; unsigned char salt[80] = { 0x60, 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, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf }; unsigned char info1[34] = { 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1 }; unsigned char info2[46] = { 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; unsigned char okm[82] = { 0x0b, 0xd7, 0x70, 0xa7, 0x4d, 0x11, 0x60, 0xf7, 0xc9, 0xf1, 0x2c, 0xd5, 0x91, 0x2a, 0x06, 0xeb, 0xff, 0x6a, 0xdc, 0xae, 0x89, 0x9d, 0x92, 0x19, 0x1f, 0xe4, 0x30, 0x56, 0x73, 0xba, 0x2f, 0xfe, 0x8f, 0xa3, 0xf1, 0xa4, 0xe5, 0xad, 0x79, 0xf3, 0xf3, 0x34, 0xb3, 0xb2, 0x02, 0xb2, 0x17, 0x3c, 0x48, 0x6e, 0xa3, 0x7c, 0xe3, 0xd3, 0x97, 0xed, 0x03, 0x4c, 0x7f, 0x9d, 0xfe, 0xb1, 0x5c, 0x5e, 0x92, 0x73, 0x36, 0xd0, 0x44, 0x1f, 0x4c, 0x43, 0x00, 0xe2, 0xcf, 0xf0, 0xd0, 0x90, 0x0b, 0x52, 0xd3, 0xb4 }; char result[84]; int l = 82; memset (result, 0, sizeof (result)); GNUNET_assert (GNUNET_CRYPTO_hkdf (result, l, GCRY_MD_SHA1, GCRY_MD_SHA1, salt, sizeof (salt), ikm, sizeof (ikm), info1, sizeof (info1), info2, sizeof (info2), NULL) == GNUNET_YES); GNUNET_assert (memcmp (result, okm, l) == 0); GNUNET_assert (memcmp (result + l, "\0", 2) == 0); } void tc8 () { unsigned char ikm[32] = { 0xbf, 0x16, 0x6e, 0x46, 0x3a, 0x6c, 0xf3, 0x93, 0xa7, 0x72, 0x11, 0xa1, 0xdc, 0x0b, 0x07, 0xdb, 0x1a, 0x5e, 0xd9, 0xb9, 0x81, 0xbe, 0xea, 0xe4, 0x31, 0x5f, 0x24, 0xff, 0xfe, 0x50, 0x8a, 0xde }; unsigned char salt[4] = { 0xfc, 0x62, 0x76, 0x35 }; unsigned char info[86] = { 0x8c, 0x0d, 0xcf, 0xb3, 0x25, 0x6e, 0x88, 0x0d, 0xc1, 0x0b, 0x1d, 0x33, 0x15, 0x3e, 0x52, 0x0b, 0xb0, 0x77, 0xff, 0x7d, 0xc3, 0xc7, 0xef, 0xe5, 0x8e, 0x3c, 0xc4, 0x4e, 0x8b, 0x41, 0x46, 0x1f, 0x02, 0x94, 0x82, 0x35, 0xc5, 0xa6, 0x5e, 0x91, 0xd8, 0xa2, 0x90, 0xfd, 0x6f, 0xb4, 0x07, 0xc9, 0xed, 0x6b, 0x18, 0x90, 0x31, 0xab, 0x0f, 0xb5, 0x6b, 0xec, 0x9e, 0x45, 0xa2, 0x83, 0x65, 0x41, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x00 }; unsigned char okm[16] = { 0xd6, 0x90, 0xec, 0x9e, 0x62, 0xdf, 0xb9, 0x41, 0xff, 0x92, 0x4f, 0xd2, 0xf6, 0x1d, 0x67, 0xe0 }; char result[18]; int l = 16; memset (result, 0, sizeof (result)); GNUNET_assert (GNUNET_CRYPTO_hkdf (result, l, GCRY_MD_SHA512, GCRY_MD_SHA256, salt, sizeof (salt), ikm, sizeof (ikm), info, sizeof (info), NULL) == GNUNET_YES); GNUNET_assert (memcmp (result, okm, l) == 0); GNUNET_assert (memcmp (result + l, "\0", 2) == 0); } int main () { GNUNET_log_setup ("test-crypto-hkdf", "WARNING", NULL); /* Official test vectors */ tc1 (); tc2 (); tc3 (); tc4 (); tc5 (); tc6 (); /* Additional tests */ tc7 (); tc8 (); return 0; } gnunet-0.9.3/src/util/time.c0000644000175000017500000003301311760514727012624 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/time.c * @author Christian Grothoff * @brief functions for handling time and time arithmetic */ #include "platform.h" #include "gnunet_time_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) /** * Variable used to simulate clock skew. Used for testing, never in production. */ static long long timestamp_offset; /** * Set the timestamp offset for this instance. * * @param offset the offset to skew the locale time by */ void GNUNET_TIME_set_offset (long long offset) { timestamp_offset = offset; } /** * Get the current time (works just as "time", just that we use the * unit of time that the cron-jobs use (and is 64 bit)). * * @return the current time */ struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get () { struct GNUNET_TIME_Absolute ret; struct timeval tv; GETTIMEOFDAY (&tv, NULL); ret.abs_value = (uint64_t) (((uint64_t) tv.tv_sec * 1000LL) + ((uint64_t) tv.tv_usec / 1000LL)) + timestamp_offset; return ret; } /** * Return relative time of 0ms. */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_get_zero_ () { static struct GNUNET_TIME_Relative zero; return zero; } /** * Return absolute time of 0ms. */ struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get_zero_ () { static struct GNUNET_TIME_Absolute zero; return zero; } /** * Return relative time of 1ms. */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_get_unit_ () { static struct GNUNET_TIME_Relative one = { 1 }; return one; } /** * Return relative time of 1s. */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_get_second_ () { static struct GNUNET_TIME_Relative one = { 1000 }; return one; } /** * Return relative time of 1 minute. */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_get_minute_ () { static struct GNUNET_TIME_Relative one = { 60 * 1000 }; return one; } /** * Return relative time of 1 hour. */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_get_hour_ () { static struct GNUNET_TIME_Relative one = { 60 * 60 * 1000 }; return one; } /** * Return "forever". */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_get_forever_ () { static struct GNUNET_TIME_Relative forever = { UINT64_MAX }; return forever; } /** * Return "forever". */ struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get_forever_ () { static struct GNUNET_TIME_Absolute forever = { UINT64_MAX }; return forever; } /** * Convert relative time to an absolute time in the * future. * * @return timestamp that is "rel" in the future, or FOREVER if rel==FOREVER (or if we would overflow) */ struct GNUNET_TIME_Absolute GNUNET_TIME_relative_to_absolute (struct GNUNET_TIME_Relative rel) { struct GNUNET_TIME_Absolute ret; if (rel.rel_value == UINT64_MAX) return GNUNET_TIME_UNIT_FOREVER_ABS; struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); if (rel.rel_value + now.abs_value < rel.rel_value) { GNUNET_break (0); /* overflow... */ return GNUNET_TIME_UNIT_FOREVER_ABS; } ret.abs_value = rel.rel_value + now.abs_value; return ret; } /** * Return the minimum of two relative time values. * * @param t1 first timestamp * @param t2 other timestamp * @return timestamp that is smaller */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_min (struct GNUNET_TIME_Relative t1, struct GNUNET_TIME_Relative t2) { return (t1.rel_value < t2.rel_value) ? t1 : t2; } /** * Return the maximum of two relative time values. * * @param t1 first timestamp * @param t2 other timestamp * @return timestamp that is larger */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_max (struct GNUNET_TIME_Relative t1, struct GNUNET_TIME_Relative t2) { return (t1.rel_value > t2.rel_value) ? t1 : t2; } /** * Return the minimum of two relative time values. * * @param t1 first timestamp * @param t2 other timestamp * @return timestamp that is smaller */ struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_min (struct GNUNET_TIME_Absolute t1, struct GNUNET_TIME_Absolute t2) { return (t1.abs_value < t2.abs_value) ? t1 : t2; } /** * Return the maximum of two relative time values. * * @param t1 first timestamp * @param t2 other timestamp * @return timestamp that is bigger */ struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_max (struct GNUNET_TIME_Absolute t1, struct GNUNET_TIME_Absolute t2) { return (t1.abs_value > t2.abs_value) ? t1 : t2; } /** * Given a timestamp in the future, how much time * remains until then? * * @return future - now, or 0 if now >= future, or FOREVER if future==FOREVER. */ struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_remaining (struct GNUNET_TIME_Absolute future) { struct GNUNET_TIME_Relative ret; if (future.abs_value == UINT64_MAX) return GNUNET_TIME_UNIT_FOREVER_REL; struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); if (now.abs_value > future.abs_value) return GNUNET_TIME_UNIT_ZERO; ret.rel_value = future.abs_value - now.abs_value; return ret; } /** * Compute the time difference between the given start and end times. * Use this function instead of actual subtraction to ensure that * "FOREVER" and overflows are handled correctly. * * @return 0 if start >= end; FOREVER if end==FOREVER; otherwise end - start */ struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_difference (struct GNUNET_TIME_Absolute start, struct GNUNET_TIME_Absolute end) { struct GNUNET_TIME_Relative ret; if (end.abs_value == UINT64_MAX) return GNUNET_TIME_UNIT_FOREVER_REL; if (end.abs_value < start.abs_value) return GNUNET_TIME_UNIT_ZERO; ret.rel_value = end.abs_value - start.abs_value; return ret; } /** * Get the duration of an operation as the * difference of the current time and the given start time "whence". * * @return aborts if whence==FOREVER, 0 if whence > now, otherwise now-whence. */ struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_duration (struct GNUNET_TIME_Absolute whence) { struct GNUNET_TIME_Absolute now; struct GNUNET_TIME_Relative ret; now = GNUNET_TIME_absolute_get (); GNUNET_assert (whence.abs_value != UINT64_MAX); if (whence.abs_value > now.abs_value) return GNUNET_TIME_UNIT_ZERO; ret.rel_value = now.abs_value - whence.abs_value; return ret; } /** * Add a given relative duration to the * given start time. * * @return FOREVER if either argument is FOREVER or on overflow; start+duration otherwise */ struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_add (struct GNUNET_TIME_Absolute start, struct GNUNET_TIME_Relative duration) { struct GNUNET_TIME_Absolute ret; if ((start.abs_value == UINT64_MAX) || (duration.rel_value == UINT64_MAX)) return GNUNET_TIME_UNIT_FOREVER_ABS; if (start.abs_value + duration.rel_value < start.abs_value) { GNUNET_break (0); return GNUNET_TIME_UNIT_FOREVER_ABS; } ret.abs_value = start.abs_value + duration.rel_value; return ret; } /** * Subtract a given relative duration from the * given start time. * * @param start some absolute time * @param duration some relative time to subtract * @return ZERO if start <= duration, or FOREVER if start time is FOREVER; start-duration otherwise */ struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_subtract (struct GNUNET_TIME_Absolute start, struct GNUNET_TIME_Relative duration) { struct GNUNET_TIME_Absolute ret; if (start.abs_value <= duration.rel_value) return GNUNET_TIME_UNIT_ZERO_ABS; if (start.abs_value == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value) return GNUNET_TIME_UNIT_FOREVER_ABS; ret.abs_value = start.abs_value - duration.rel_value; return ret; } /** * Multiply relative time by a given factor. * * @return FOREVER if rel=FOREVER or on overflow; otherwise rel*factor */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_multiply (struct GNUNET_TIME_Relative rel, unsigned int factor) { struct GNUNET_TIME_Relative ret; if (factor == 0) return GNUNET_TIME_UNIT_ZERO; ret.rel_value = rel.rel_value * (unsigned long long) factor; if (ret.rel_value / factor != rel.rel_value) { GNUNET_break (0); return GNUNET_TIME_UNIT_FOREVER_REL; } return ret; } /** * Divide relative time by a given factor. * * @param rel some duration * @param factor integer to divide by * @return FOREVER if rel=FOREVER or factor==0; otherwise rel/factor */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_divide (struct GNUNET_TIME_Relative rel, unsigned int factor) { struct GNUNET_TIME_Relative ret; if ((factor == 0) || (rel.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)) return GNUNET_TIME_UNIT_FOREVER_REL; ret.rel_value = rel.rel_value / (unsigned long long) factor; return ret; } /** * Calculate the estimate time of arrival/completion * for an operation. * * @param start when did the operation start? * @param finished how much has been done? * @param total how much must be done overall (same unit as for "finished") * @return remaining duration for the operation, * assuming it continues at the same speed */ struct GNUNET_TIME_Relative GNUNET_TIME_calculate_eta (struct GNUNET_TIME_Absolute start, uint64_t finished, uint64_t total) { struct GNUNET_TIME_Relative dur; double exp; struct GNUNET_TIME_Relative ret; GNUNET_break (finished <= total); if (finished >= total) return GNUNET_TIME_UNIT_ZERO; if (finished == 0) return GNUNET_TIME_UNIT_FOREVER_REL; dur = GNUNET_TIME_absolute_get_duration (start); exp = ((double) dur.rel_value) * ((double) total) / ((double) finished); ret.rel_value = ((uint64_t) exp) - dur.rel_value; return ret; } /** * Add relative times together. * * @param a1 first timestamp * @param a2 second timestamp * @return FOREVER if either argument is FOREVER or on overflow; a1+a2 otherwise */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_add (struct GNUNET_TIME_Relative a1, struct GNUNET_TIME_Relative a2) { struct GNUNET_TIME_Relative ret; if ((a1.rel_value == UINT64_MAX) || (a2.rel_value == UINT64_MAX)) return GNUNET_TIME_UNIT_FOREVER_REL; if (a1.rel_value + a2.rel_value < a1.rel_value) { GNUNET_break (0); return GNUNET_TIME_UNIT_FOREVER_REL; } ret.rel_value = a1.rel_value + a2.rel_value; return ret; } /** * Subtract relative timestamp from the other. * * @param a1 first timestamp * @param a2 second timestamp * @return ZERO if a2>=a1 (including both FOREVER), FOREVER if a1 is FOREVER, a1-a2 otherwise */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_subtract (struct GNUNET_TIME_Relative a1, struct GNUNET_TIME_Relative a2) { struct GNUNET_TIME_Relative ret; if (a2.rel_value >= a1.rel_value) return GNUNET_TIME_UNIT_ZERO; if (a1.rel_value == UINT64_MAX) return GNUNET_TIME_UNIT_FOREVER_REL; ret.rel_value = a1.rel_value - a2.rel_value; return ret; } /** * Convert relative time to network byte order. * * @param a time to convert * @return time in network byte order */ struct GNUNET_TIME_RelativeNBO GNUNET_TIME_relative_hton (struct GNUNET_TIME_Relative a) { struct GNUNET_TIME_RelativeNBO ret; ret.rel_value__ = GNUNET_htonll (a.rel_value); return ret; } /** * Convert relative time from network byte order. * * @param a time to convert * @return time in host byte order */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_ntoh (struct GNUNET_TIME_RelativeNBO a) { struct GNUNET_TIME_Relative ret; ret.rel_value = GNUNET_ntohll (a.rel_value__); return ret; } /** * Convert absolute time to network byte order. * * @param a time to convert * @return time in network byte order */ struct GNUNET_TIME_AbsoluteNBO GNUNET_TIME_absolute_hton (struct GNUNET_TIME_Absolute a) { struct GNUNET_TIME_AbsoluteNBO ret; ret.abs_value__ = GNUNET_htonll (a.abs_value); return ret; } /** * Convert absolute time from network byte order. * * @param a time to convert * @return time in host byte order */ struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_ntoh (struct GNUNET_TIME_AbsoluteNBO a) { struct GNUNET_TIME_Absolute ret; ret.abs_value = GNUNET_ntohll (a.abs_value__); return ret; } /** * Convert a relative time to a string. * This is one of the very few calls in the entire API that is * NOT reentrant! * * @param time the time to print * * @return string form of the time (as milliseconds) */ const char * GNUNET_TIME_relative_to_string (struct GNUNET_TIME_Relative time) { static char time_string[21]; memset (time_string, 0, sizeof (time_string)); sprintf (time_string, "%llu", (unsigned long long) time.rel_value); return (const char *) time_string; } /* end of time.c */ gnunet-0.9.3/src/util/network.c0000644000175000017500000012503711762171530013360 00000000000000/* This file is part of GNUnet. (C) 2009, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/network.c * @brief basic, low-level networking interface * @author Nils Durner */ #include "platform.h" #include "gnunet_disk_lib.h" #include "disk.h" #include "gnunet_container_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) #define DEBUG_NETWORK GNUNET_EXTRA_LOGGING #ifndef INVALID_SOCKET #define INVALID_SOCKET -1 #endif struct GNUNET_NETWORK_Handle { #ifndef MINGW int fd; #else SOCKET fd; #endif /** * Address family / domain. */ int af; /** * Number of bytes in addr. */ socklen_t addrlen; /** * Address we were bound to, or NULL. */ struct sockaddr *addr; }; #ifndef FD_COPY #define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set))) #endif /** * Set if a socket should use blocking or non-blocking IO. * @param fd socket * @param doBlock blocking mode * @return GNUNET_OK on success, GNUNET_SYSERR on error */ static int socket_set_blocking (struct GNUNET_NETWORK_Handle *fd, int doBlock) { #if MINGW u_long mode; mode = !doBlock; if (ioctlsocket (fd->fd, FIONBIO, &mode) == SOCKET_ERROR) { SetErrnoFromWinsockError (WSAGetLastError ()); LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "ioctlsocket"); return GNUNET_SYSERR; } return GNUNET_OK; #else /* not MINGW */ int flags = fcntl (fd->fd, F_GETFL); if (flags == -1) { LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "fcntl"); return GNUNET_SYSERR; } if (doBlock) flags &= ~O_NONBLOCK; else flags |= O_NONBLOCK; if (0 != fcntl (fd->fd, F_SETFL, flags)) { LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "fcntl"); return GNUNET_SYSERR; } return GNUNET_OK; #endif } #ifndef MINGW /** * Make a socket non-inheritable to child processes * * @param h the socket to make non-inheritable * @return GNUNET_OK on success, GNUNET_SYSERR otherwise * @warning Not implemented on Windows */ static int socket_set_inheritable (const struct GNUNET_NETWORK_Handle *h) { int i; i = fcntl (h->fd, F_GETFD); if (i < 0) return GNUNET_SYSERR; if (i == (i | FD_CLOEXEC)) return GNUNET_OK; i |= FD_CLOEXEC; if (fcntl (h->fd, F_SETFD, i) < 0) return GNUNET_SYSERR; return GNUNET_OK; } #endif #ifdef DARWIN /** * The MSG_NOSIGNAL equivalent on Mac OS X * * @param h the socket to make non-delaying */ static void socket_set_nosigpipe (const struct GNUNET_NETWORK_Handle *h) { int abs_value = 1; if (0 != setsockopt (h->fd, SOL_SOCKET, SO_NOSIGPIPE, &abs_value, sizeof (abs_value))) LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt"); } #endif /** * Disable delays when sending data via the socket. * (GNUnet makes sure that messages are as big as * possible already). * * @param h the socket to make non-delaying */ static void socket_set_nodelay (const struct GNUNET_NETWORK_Handle *h) { #ifndef WINDOWS int value = 1; if (0 != setsockopt (h->fd, IPPROTO_TCP, TCP_NODELAY, &value, sizeof (value))) LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt"); #else const char *abs_value = "1"; if (0 != setsockopt (h->fd, IPPROTO_TCP, TCP_NODELAY, abs_value, sizeof (abs_value))) LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt"); #endif } /** * Perform proper canonical initialization for a network handle. * Set it to non-blocking, make it non-inheritable to child * processes, disable SIGPIPE, enable "nodelay" (if non-UNIX * stream socket) and check that it is smaller than FS_SETSIZE. * * @param h socket to initialize * @param af address family of the socket * @param type socket type * @return GNUNET_OK on success, GNUNET_SYSERR if initialization * failed and the handle was destroyed */ static int initialize_network_handle (struct GNUNET_NETWORK_Handle *h, int af, int type) { h->af = af; if (h->fd == INVALID_SOCKET) { #ifdef MINGW SetErrnoFromWinsockError (WSAGetLastError ()); #endif GNUNET_free (h); return GNUNET_SYSERR; } #ifndef MINGW if (h->fd >= FD_SETSIZE) { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (h)); errno = EMFILE; return GNUNET_SYSERR; } if (GNUNET_OK != socket_set_inheritable (h)) LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "socket_set_inheritable"); #endif if (GNUNET_SYSERR == socket_set_blocking (h, GNUNET_NO)) { GNUNET_break (0); GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (h)); return GNUNET_SYSERR; } #ifdef DARWIN socket_set_nosigpipe (h); #endif if ( (type == SOCK_STREAM) #ifdef AF_UNIX && (af != AF_UNIX) #endif ) socket_set_nodelay (h); return GNUNET_OK; } /** * accept a new connection on a socket * * @param desc bound socket * @param address address of the connecting peer, may be NULL * @param address_len length of address * @return client socket */ struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Handle *desc, struct sockaddr *address, socklen_t * address_len) { struct GNUNET_NETWORK_Handle *ret; ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle)); #if DEBUG_NETWORK { struct sockaddr name; socklen_t namelen = sizeof (name); int gsn = getsockname (desc->fd, &name, &namelen); if (gsn == 0) LOG (GNUNET_ERROR_TYPE_DEBUG, "Accepting connection on `%s'\n", GNUNET_a2s (&name, namelen)); } #endif ret->fd = accept (desc->fd, address, address_len); if (GNUNET_OK != initialize_network_handle (ret, (NULL != address) ? address->sa_family : desc->af, SOCK_STREAM)) return NULL; return ret; } /** * Bind to a connected socket * @param desc socket * @param address address to be bound * @param address_len length of address * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc, const struct sockaddr *address, socklen_t address_len) { int ret; #ifdef IPV6_V6ONLY #ifdef IPPROTO_IPV6 const int on = 1; if (desc->af == AF_INET6) if (0 != setsockopt (desc->fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on))) LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG, "setsockopt"); #endif #endif #ifndef WINDOWS /* This is required, and required here, but only on UNIX */ if (0 != setsockopt (desc->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on))) LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG, "setsockopt"); #endif #ifndef LINUX #ifndef MINGW if (address->sa_family == AF_UNIX) { const struct sockaddr_un *un = (const struct sockaddr_un *) address; (void) unlink (un->sun_path); } #endif #endif ret = bind (desc->fd, address, address_len); #ifdef MINGW if (SOCKET_ERROR == ret) SetErrnoFromWinsockError (WSAGetLastError ()); #endif if (ret != 0) return GNUNET_SYSERR; #ifndef MINGW #ifndef LINUX desc->addr = GNUNET_malloc (address_len); memcpy (desc->addr, address, address_len); desc->addrlen = address_len; #endif #endif return GNUNET_OK; } /** * Close a socket * @param desc socket * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Handle *desc) { int ret; #ifdef MINGW DWORD error = 0; SetLastError (0); ret = closesocket (desc->fd); error = WSAGetLastError (); SetErrnoFromWinsockError (error); LOG (GNUNET_ERROR_TYPE_DEBUG, "Closed 0x%x, closesocket() returned %d, GLE is %u\n", desc->fd, ret, error); #else ret = close (desc->fd); #endif #ifndef LINUX #ifndef MINGW if ((desc->af == AF_UNIX) && (NULL != desc->addr)) { const struct sockaddr_un *un = (const struct sockaddr_un *) desc->addr; if (0 != unlink (un->sun_path)) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", un->sun_path); } #endif #endif GNUNET_free_non_null (desc->addr); GNUNET_free (desc); return (ret == 0) ? GNUNET_OK : GNUNET_SYSERR; } /** * Box a native socket (and check that it is a socket). * * @param fd socket to box * @return NULL on error (including not supported on target platform) */ struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_box_native (SOCKTYPE fd) { struct GNUNET_NETWORK_Handle *ret; #if MINGW unsigned long i; DWORD d; /* FIXME: Find a better call to check that FD is valid */ if (WSAIoctl (fd, FIONBIO, (void *) &i, sizeof (i), NULL, 0, &d, NULL, NULL) != 0) return NULL; /* invalid FD */ ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle)); ret->fd = fd; ret->af = AF_UNSPEC; return ret; #else if (fcntl (fd, F_GETFD) < 0) return NULL; /* invalid FD */ ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle)); ret->fd = fd; ret->af = AF_UNSPEC; return ret; #endif } /** * Connect a socket * @param desc socket * @param address peer address * @param address_len length of address * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_NETWORK_socket_connect (const struct GNUNET_NETWORK_Handle *desc, const struct sockaddr *address, socklen_t address_len) { int ret; ret = connect (desc->fd, address, address_len); #ifdef MINGW if (SOCKET_ERROR == ret) { SetErrnoFromWinsockError (WSAGetLastError ()); if (errno == EWOULDBLOCK) errno = EINPROGRESS; } #endif return ret == 0 ? GNUNET_OK : GNUNET_SYSERR; } /** * Get socket options * * @param desc socket * @param level protocol level of the option * @param optname identifier of the option * @param optval options * @param optlen length of optval * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_NETWORK_socket_getsockopt (const struct GNUNET_NETWORK_Handle *desc, int level, int optname, void *optval, socklen_t * optlen) { int ret; ret = getsockopt (desc->fd, level, optname, optval, optlen); #ifdef MINGW if (ret == 0 && level == SOL_SOCKET && optname == SO_ERROR) *((int *) optval) = GetErrnoFromWinsockError (*((int *) optval)); else if (SOCKET_ERROR == ret) SetErrnoFromWinsockError (WSAGetLastError ()); #endif return ret == 0 ? GNUNET_OK : GNUNET_SYSERR; } /** * Listen on a socket * @param desc socket * @param backlog length of the listen queue * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Handle *desc, int backlog) { int ret; ret = listen (desc->fd, backlog); #ifdef MINGW if (SOCKET_ERROR == ret) SetErrnoFromWinsockError (WSAGetLastError ()); #endif return ret == 0 ? GNUNET_OK : GNUNET_SYSERR; } /** * How much data is available to be read on this descriptor? * * Returns GNUNET_NO if no data is available, or on error! * @param desc socket */ ssize_t GNUNET_NETWORK_socket_recvfrom_amount (const struct GNUNET_NETWORK_Handle * desc) { int error; /* How much is there to be read? */ #ifndef WINDOWS int pending; error = ioctl (desc->fd, FIONREAD, &pending); if (error == 0) return (ssize_t) pending; return GNUNET_NO; #else u_long pending; error = ioctlsocket (desc->fd, FIONREAD, &pending); if (error != SOCKET_ERROR) return (ssize_t) pending; return GNUNET_NO; #endif } /** * Read data from a connected socket (always non-blocking). * @param desc socket * @param buffer buffer * @param length length of buffer * @param src_addr either the source to recv from, or all zeroes * to be filled in by recvfrom * @param addrlen length of the addr */ ssize_t GNUNET_NETWORK_socket_recvfrom (const struct GNUNET_NETWORK_Handle * desc, void *buffer, size_t length, struct sockaddr * src_addr, socklen_t * addrlen) { int ret; int flags; flags = 0; #ifdef MSG_DONTWAIT flags |= MSG_DONTWAIT; #endif ret = recvfrom (desc->fd, buffer, length, flags, src_addr, addrlen); #ifdef MINGW if (SOCKET_ERROR == ret) SetErrnoFromWinsockError (WSAGetLastError ()); #endif return ret; } /** * Read data from a connected socket (always non-blocking). * @param desc socket * @param buffer buffer * @param length length of buffer */ ssize_t GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Handle * desc, void *buffer, size_t length) { int ret; int flags; flags = 0; #ifdef MSG_DONTWAIT flags |= MSG_DONTWAIT; #endif ret = recv (desc->fd, buffer, length, flags); #ifdef MINGW if (SOCKET_ERROR == ret) SetErrnoFromWinsockError (WSAGetLastError ()); #endif return ret; } /** * Send data (always non-blocking). * * @param desc socket * @param buffer data to send * @param length size of the buffer * @return number of bytes sent, GNUNET_SYSERR on error */ ssize_t GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Handle * desc, const void *buffer, size_t length) { int ret; int flags; flags = 0; #ifdef MSG_DONTWAIT flags |= MSG_DONTWAIT; #endif #ifdef MSG_NOSIGNAL flags |= MSG_NOSIGNAL; #endif ret = send (desc->fd, buffer, length, flags); #ifdef MINGW if (SOCKET_ERROR == ret) SetErrnoFromWinsockError (WSAGetLastError ()); #endif return ret; } /** * Send data to a particular destination (always non-blocking). * This function only works for UDP sockets. * * @param desc socket * @param message data to send * @param length size of the data * @param dest_addr destination address * @param dest_len length of address * @return number of bytes sent, GNUNET_SYSERR on error */ ssize_t GNUNET_NETWORK_socket_sendto (const struct GNUNET_NETWORK_Handle * desc, const void *message, size_t length, const struct sockaddr * dest_addr, socklen_t dest_len) { int ret; int flags; flags = 0; #ifdef MSG_DONTWAIT flags |= MSG_DONTWAIT; #endif #ifdef MSG_NOSIGNAL flags |= MSG_NOSIGNAL; #endif ret = sendto (desc->fd, message, length, flags, dest_addr, dest_len); #ifdef MINGW if (SOCKET_ERROR == ret) SetErrnoFromWinsockError (WSAGetLastError ()); #endif return ret; } /** * Set socket option * @param fd socket * @param level protocol level of the option * @param option_name option identifier * @param option_value value to set * @param option_len size of option_value * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_NETWORK_socket_setsockopt (struct GNUNET_NETWORK_Handle *fd, int level, int option_name, const void *option_value, socklen_t option_len) { int ret; ret = setsockopt (fd->fd, level, option_name, option_value, option_len); #ifdef MINGW if (SOCKET_ERROR == ret) SetErrnoFromWinsockError (WSAGetLastError ()); #endif return ret == 0 ? GNUNET_OK : GNUNET_SYSERR; } /** * Create a new socket. Configure it for non-blocking IO and * mark it as non-inheritable to child processes (set the * close-on-exec flag). * * @param domain domain of the socket * @param type socket type * @param protocol network protocol * @return new socket, NULL on error */ struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_create (int domain, int type, int protocol) { struct GNUNET_NETWORK_Handle *ret; ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle)); ret->fd = socket (domain, type, protocol); if (GNUNET_OK != initialize_network_handle (ret, domain, type)) return NULL; return ret; } /** * Shut down socket operations * @param desc socket * @param how type of shutdown * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Handle *desc, int how) { int ret; ret = shutdown (desc->fd, how); #ifdef MINGW if (ret != 0) SetErrnoFromWinsockError (WSAGetLastError ()); #endif return ret == 0 ? GNUNET_OK : GNUNET_SYSERR; } /** * Disable the "CORK" feature for communication with the given socket, * forcing the OS to immediately flush the buffer on transmission * instead of potentially buffering multiple messages. Essentially * reduces the OS send buffers to zero. * * @param desc socket * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_NETWORK_socket_disable_corking (struct GNUNET_NETWORK_Handle *desc) { int ret = 0; #if WINDOWS int value = 0; if (0 != (ret = setsockopt (desc->fd, SOL_SOCKET, SO_SNDBUF, (char *) &value, sizeof (value)))) LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt"); if (0 != (ret = setsockopt (desc->fd, SOL_SOCKET, SO_RCVBUF, (char *) &value, sizeof (value)))) LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt"); #elif LINUX int value = 0; if (0 != (ret = setsockopt (desc->fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof (value)))) LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt"); if (0 != (ret = setsockopt (desc->fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof (value)))) LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt"); #endif return ret == 0 ? GNUNET_OK : GNUNET_SYSERR; } /** * Reset FD set * @param fds fd set */ void GNUNET_NETWORK_fdset_zero (struct GNUNET_NETWORK_FDSet *fds) { FD_ZERO (&fds->sds); fds->nsds = 0; #ifdef MINGW GNUNET_CONTAINER_slist_clear (fds->handles); #endif } /** * Add a socket to the FD set * @param fds fd set * @param desc socket to add */ void GNUNET_NETWORK_fdset_set (struct GNUNET_NETWORK_FDSet *fds, const struct GNUNET_NETWORK_Handle *desc) { FD_SET (desc->fd, &fds->sds); if (desc->fd + 1 > fds->nsds) fds->nsds = desc->fd + 1; } /** * Check whether a socket is part of the fd set * @param fds fd set * @param desc socket * @return 0 if the FD is not set */ int GNUNET_NETWORK_fdset_isset (const struct GNUNET_NETWORK_FDSet *fds, const struct GNUNET_NETWORK_Handle *desc) { return FD_ISSET (desc->fd, &fds->sds); } /** * Add one fd set to another * @param dst the fd set to add to * @param src the fd set to add from */ void GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst, const struct GNUNET_NETWORK_FDSet *src) { int nfds; for (nfds = src->nsds; nfds > 0; nfds--) if (FD_ISSET (nfds, &src->sds)) { FD_SET (nfds, &dst->sds); if (nfds + 1 > dst->nsds) dst->nsds = nfds + 1; } #ifdef MINGW GNUNET_CONTAINER_slist_append (dst->handles, src->handles); #endif } /** * Copy one fd set to another * * @param to destination * @param from source */ void GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to, const struct GNUNET_NETWORK_FDSet *from) { FD_COPY (&from->sds, &to->sds); to->nsds = from->nsds; #ifdef MINGW GNUNET_CONTAINER_slist_clear (to->handles); GNUNET_CONTAINER_slist_append (to->handles, from->handles); #endif } /** * Return file descriptor for this network handle * * @param desc wrapper to process * @return POSIX file descriptor */ int GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc) { return desc->fd; } /** * Return sockaddr for this network handle * * @param desc wrapper to process * @return sockaddr */ struct sockaddr* GNUNET_NETWORK_get_addr (struct GNUNET_NETWORK_Handle *desc) { return desc->addr; } /** * Return sockaddr length for this network handle * * @param desc wrapper to process * @return socklen_t for sockaddr */ socklen_t GNUNET_NETWORK_get_addrlen (struct GNUNET_NETWORK_Handle *desc) { return desc->addrlen; } /** * Copy a native fd set * * @param to destination * @param from native source set * @param nfds the biggest socket number in from + 1 */ void GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to, const fd_set * from, int nfds) { FD_COPY (from, &to->sds); to->nsds = nfds; } /** * Set a native fd in a set * * @param to destination * @param nfd native FD to set */ void GNUNET_NETWORK_fdset_set_native (struct GNUNET_NETWORK_FDSet *to, int nfd) { GNUNET_assert ((nfd >= 0) && (nfd < FD_SETSIZE)); FD_SET (nfd, &to->sds); to->nsds = GNUNET_MAX (nfd + 1, to->nsds); } /** * Test native fd in a set * * @param to set to test, NULL for empty set * @param nfd native FD to test, or -1 for none * @return GNUNET_YES if FD is set in the set */ int GNUNET_NETWORK_fdset_test_native (const struct GNUNET_NETWORK_FDSet *to, int nfd) { if ((nfd == -1) || (to == NULL)) return GNUNET_NO; return FD_ISSET (nfd, &to->sds) ? GNUNET_YES : GNUNET_NO; } /** * Add a file handle to the fd set * @param fds fd set * @param h the file handle to add */ void GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds, const struct GNUNET_DISK_FileHandle *h) { #ifdef MINGW GNUNET_CONTAINER_slist_add (fds->handles, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, h, sizeof (struct GNUNET_DISK_FileHandle)); #else int fd; GNUNET_DISK_internal_file_handle_ (h, &fd, sizeof (int)); FD_SET (fd, &fds->sds); if (fd + 1 > fds->nsds) fds->nsds = fd + 1; #endif } /** * Check if a file handle is part of an fd set * @param fds fd set * @param h file handle * @return GNUNET_YES if the file handle is part of the set */ int GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds, const struct GNUNET_DISK_FileHandle *h) { #ifdef MINGW return GNUNET_CONTAINER_slist_contains (fds->handles, h, sizeof (struct GNUNET_DISK_FileHandle)); #else return FD_ISSET (h->fd, &fds->sds); #endif } /** * Checks if two fd sets overlap * @param fds1 first fd set * @param fds2 second fd set * @return GNUNET_YES if they do overlap, GNUNET_NO otherwise */ int GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1, const struct GNUNET_NETWORK_FDSet *fds2) { #ifndef MINGW int nfds; nfds = fds1->nsds; if (nfds > fds2->nsds) nfds = fds2->nsds; while (nfds > 0) { nfds--; if (FD_ISSET (nfds, &fds1->sds) && FD_ISSET (nfds, &fds2->sds)) return GNUNET_YES; } #else struct GNUNET_CONTAINER_SList_Iterator it; struct GNUNET_DISK_FileHandle *h; int i; int j; /*This code is somewhat hacky, we are not supposed to know what's * inside of fd_set; also the O(n^2) is really bad... */ for (i = 0; i < fds1->sds.fd_count; i++) { for (j = 0; j < fds2->sds.fd_count; j++) { if (fds1->sds.fd_array[i] == fds2->sds.fd_array[j]) return GNUNET_YES; } } it = GNUNET_CONTAINER_slist_begin (fds1->handles); while (GNUNET_CONTAINER_slist_end (&it) != GNUNET_YES) { #if DEBUG_NETWORK struct GNUNET_CONTAINER_SList_Iterator t; #endif h = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&it, NULL); #if DEBUG_NETWORK LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking that FD 0x%x is in another set:\n", h->h); for (t = GNUNET_CONTAINER_slist_begin (fds2->handles); GNUNET_CONTAINER_slist_end (&t) != GNUNET_YES; GNUNET_CONTAINER_slist_next (&t)) { struct GNUNET_DISK_FileHandle *fh; fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&t, NULL); LOG (GNUNET_ERROR_TYPE_DEBUG, "0x%x\n", fh->h); } #endif if (GNUNET_CONTAINER_slist_contains (fds2->handles, h, sizeof (struct GNUNET_DISK_FileHandle))) { return GNUNET_YES; } GNUNET_CONTAINER_slist_next (&it); } #endif return GNUNET_NO; } /** * Creates an fd set * @return a new fd set */ struct GNUNET_NETWORK_FDSet * GNUNET_NETWORK_fdset_create () { struct GNUNET_NETWORK_FDSet *fds; fds = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_FDSet)); #ifdef MINGW fds->handles = GNUNET_CONTAINER_slist_create (); #endif GNUNET_NETWORK_fdset_zero (fds); return fds; } /** * Releases the associated memory of an fd set * @param fds fd set */ void GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds) { #ifdef MINGW GNUNET_CONTAINER_slist_destroy (fds->handles); #endif GNUNET_free (fds); } /** * Check if sockets meet certain conditions * @param rfds set of sockets to be checked for readability * @param wfds set of sockets to be checked for writability * @param efds set of sockets to be checked for exceptions * @param timeout relative value when to return * @return number of selected sockets, GNUNET_SYSERR on error */ int GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, struct GNUNET_NETWORK_FDSet *wfds, struct GNUNET_NETWORK_FDSet *efds, const struct GNUNET_TIME_Relative timeout) { int nfds = 0; #ifdef MINGW int handles = 0; int ex_handles = 0; int read_handles = 0; int write_handles = 0; int i = 0; int retcode = 0; DWORD ms_total = 0; int nsock = 0; int nhandles = 0; int nSockEvents = 0; static HANDLE hEventRead = 0; static HANDLE hEventWrite = 0; static HANDLE hEventException = 0; static HANDLE hEventPipeWrite = 0; static HANDLE hEventReadReady = 0; int readPipes = 0; int writePipePos = 0; HANDLE handle_array[FD_SETSIZE + 2]; int returncode = -1; DWORD newretcode = 0; int returnedpos = 0; struct GNUNET_CONTAINER_SList *handles_read; struct GNUNET_CONTAINER_SList *handles_write; struct GNUNET_CONTAINER_SList *handles_except; fd_set aread; fd_set awrite; fd_set aexcept; #if DEBUG_NETWORK fd_set bread; fd_set bwrite; fd_set bexcept; #endif /* TODO: Make this growable */ struct GNUNET_DISK_FileHandle *readArray[50]; #else struct timeval tv; #endif if (NULL != rfds) { nfds = rfds->nsds; #ifdef MINGW handles += read_handles = GNUNET_CONTAINER_slist_count (rfds->handles); #if DEBUG_NETWORK { struct GNUNET_CONTAINER_SList_Iterator t; for (t = GNUNET_CONTAINER_slist_begin (rfds->handles); GNUNET_CONTAINER_slist_end (&t) != GNUNET_YES; GNUNET_CONTAINER_slist_next (&t)) { struct GNUNET_DISK_FileHandle *fh; fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&t, NULL); LOG (GNUNET_ERROR_TYPE_DEBUG, "FD 0x%x (0x%x) is SET in rfds\n", fh->h, fh); } } #endif #endif } if (NULL != wfds) { nfds = GNUNET_MAX (nfds, wfds->nsds); #ifdef MINGW handles += write_handles = GNUNET_CONTAINER_slist_count (wfds->handles); #endif } if (NULL != efds) { nfds = GNUNET_MAX (nfds, efds->nsds); #ifdef MINGW handles += ex_handles = GNUNET_CONTAINER_slist_count (efds->handles); #endif } if ((nfds == 0) && (timeout.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value) #ifdef MINGW && handles == 0 #endif ) { LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n"), "select"); GNUNET_break (0); } #ifndef MINGW tv.tv_sec = timeout.rel_value / GNUNET_TIME_UNIT_SECONDS.rel_value; tv.tv_usec = 1000 * (timeout.rel_value - (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.rel_value)); return select (nfds, (rfds != NULL) ? &rfds->sds : NULL, (wfds != NULL) ? &wfds->sds : NULL, (efds != NULL) ? &efds->sds : NULL, (timeout.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value) ? NULL : &tv); #else #define SAFE_FD_ISSET(fd, set) (set != NULL && FD_ISSET(fd, set)) /* calculate how long we need to wait in milliseconds */ if (timeout.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value) ms_total = INFINITE; else ms_total = timeout.rel_value / GNUNET_TIME_UNIT_MILLISECONDS.rel_value; /* select() may be used as a portable way to sleep */ if (!(rfds || wfds || efds)) { Sleep (ms_total); return 0; } /* Events for sockets */ if (!hEventRead) hEventRead = CreateEvent (NULL, TRUE, FALSE, NULL); else ResetEvent (hEventRead); if (!hEventReadReady) hEventReadReady = CreateEvent (NULL, TRUE, TRUE, NULL); if (!hEventWrite) hEventWrite = CreateEvent (NULL, TRUE, FALSE, NULL); else ResetEvent (hEventWrite); if (!hEventException) hEventException = CreateEvent (NULL, TRUE, FALSE, NULL); else ResetEvent (hEventException); /* Event for pipes */ if (!hEventPipeWrite) hEventPipeWrite = CreateEvent (NULL, TRUE, TRUE, NULL); readPipes = 0; writePipePos = -1; handles_read = GNUNET_CONTAINER_slist_create (); handles_write = GNUNET_CONTAINER_slist_create (); handles_except = GNUNET_CONTAINER_slist_create (); FD_ZERO (&aread); FD_ZERO (&awrite); FD_ZERO (&aexcept); #if DEBUG_NETWORK FD_ZERO (&bread); FD_ZERO (&bwrite); FD_ZERO (&bexcept); #endif if (rfds) { FD_COPY (&rfds->sds, &aread); #if DEBUG_NETWORK FD_COPY (&rfds->sds, &bread); #endif } if (wfds) { FD_COPY (&wfds->sds, &awrite); #if DEBUG_NETWORK FD_COPY (&wfds->sds, &bwrite); #endif } if (efds) { FD_COPY (&efds->sds, &aexcept); #if DEBUG_NETWORK FD_COPY (&efds->sds, &bexcept); #endif } /* We will first Add the PIPES to the events */ /* Read Pipes */ if (rfds && read_handles) { struct GNUNET_CONTAINER_SList_Iterator i; for (i = GNUNET_CONTAINER_slist_begin (rfds->handles); GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES; GNUNET_CONTAINER_slist_next (&i)) { struct GNUNET_DISK_FileHandle *fh; fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&i, NULL); if (fh->type == GNUNET_PIPE) { /* Read zero bytes to check the status of the pipe */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Reading 0 bytes from the pipe 0x%x\n", fh->h); if (!ReadFile (fh->h, NULL, 0, NULL, fh->oOverlapRead)) { DWORD error_code = GetLastError (); if (error_code == ERROR_IO_PENDING) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding the pipe's 0x%x overlapped event to the array as %d\n", fh->h, nhandles); handle_array[nhandles++] = fh->oOverlapRead->hEvent; readArray[readPipes++] = fh; } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "Read failed, adding the read ready event to the array as %d\n", nhandles); handle_array[nhandles++] = hEventReadReady; readArray[readPipes++] = fh; } } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding the read ready event to the array as %d\n", nhandles); handle_array[nhandles++] = hEventReadReady; readArray[readPipes++] = fh; } } else { GNUNET_CONTAINER_slist_add (handles_read, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, fh, sizeof (struct GNUNET_DISK_FileHandle)); } } } if (wfds && write_handles) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding the write ready event to the array as %d\n", nhandles); handle_array[nhandles++] = hEventPipeWrite; writePipePos = nhandles; } if (efds && ex_handles) { struct GNUNET_CONTAINER_SList_Iterator i; for (i = GNUNET_CONTAINER_slist_begin (efds->handles); GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES; GNUNET_CONTAINER_slist_next (&i)) { struct GNUNET_DISK_FileHandle *fh; DWORD dwBytes; fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&i, NULL); if (fh->type == GNUNET_PIPE) { if (!PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL)) { GNUNET_CONTAINER_slist_add (handles_except, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, fh, sizeof (struct GNUNET_DISK_FileHandle)); newretcode++; } } } } if (nfds > 0) { if (rfds) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding the socket read event to the array as %d\n", nhandles); handle_array[nhandles++] = hEventRead; nSockEvents++; for (i = 0; i < rfds->sds.fd_count; i++) { WSAEventSelect (rfds->sds.fd_array[i], hEventRead, FD_ACCEPT | FD_READ | FD_CLOSE); nsock++; } } if (wfds) { int wakeup = 0; LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding the socket write event to the array as %d\n", nhandles); handle_array[nhandles++] = hEventWrite; nSockEvents++; for (i = 0; i < wfds->sds.fd_count; i++) { DWORD error; int status; status = send (wfds->sds.fd_array[i], NULL, 0, 0); error = GetLastError (); LOG (GNUNET_ERROR_TYPE_DEBUG, "pre-send to the socket %d returned %d (%u)\n", i, status, error); if (status == 0 || (error != WSAEWOULDBLOCK && error != WSAENOTCONN)) wakeup = 1; WSAEventSelect (wfds->sds.fd_array[i], hEventWrite, FD_WRITE | FD_CONNECT | FD_CLOSE); nsock++; } if (wakeup) SetEvent (hEventWrite); } if (efds) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding the socket error event to the array as %d\n", nhandles); handle_array[nhandles++] = hEventException; nSockEvents++; for (i = 0; i < efds->sds.fd_count; i++) { WSAEventSelect (efds->sds.fd_array[i], hEventException, FD_OOB | FD_CLOSE); nsock++; } } } handle_array[nhandles] = NULL; LOG (GNUNET_ERROR_TYPE_DEBUG, "Number nfds: %d, handles: %d, return code: %u will wait: %d ms\n", nfds, nhandles, newretcode, ms_total); if (nhandles) returncode = WaitForMultipleObjects (nhandles, handle_array, FALSE, ms_total); LOG (GNUNET_ERROR_TYPE_DEBUG, "WaitForMultipleObjects Returned : %d\n", returncode); returnedpos = returncode - WAIT_OBJECT_0; LOG (GNUNET_ERROR_TYPE_DEBUG, "return pos is : %d\n", returnedpos); /* FIXME: THIS LINE IS WRONG !! We should add to handles only handles that fired the events, not all ! */ /* * if(rfds) * GNUNET_CONTAINER_slist_append (handles_read, rfds->handles); */ if (nhandles && (returnedpos < nhandles)) { DWORD waitstatus; /* Do the select */ if (nfds) { struct timeval tvslice; tvslice.tv_sec = 0; tvslice.tv_usec = 0; retcode = select (nfds, &aread, &awrite, &aexcept, &tvslice); if (retcode == -1) retcode = 0; LOG (GNUNET_ERROR_TYPE_DEBUG, "Select retcode : %d\n", retcode); } /* FIXME: <= writePipePos? Really? */ if ((writePipePos != -1) && (returnedpos <= writePipePos)) { GNUNET_CONTAINER_slist_append (handles_write, wfds->handles); retcode += write_handles; LOG (GNUNET_ERROR_TYPE_DEBUG, "Added write pipe\n"); } LOG (GNUNET_ERROR_TYPE_DEBUG, "ReadPipes is : %d\n", readPipes); /* We have some pipes ready for read. */ /* FIXME: it is supposed to work !! Only choose the Pipes who fired the event, but it is not working */ if (returnedpos < readPipes) { /* * for (i = 0; i < readPipes; i++) * { * waitstatus = WaitForSingleObject (handle_array[i], 0); * LOG (GNUNET_ERROR_TYPE_DEBUG, "Read pipe %d wait status is : %d\n", i, waitstatus); * if (waitstatus != WAIT_OBJECT_0) * continue; * GNUNET_CONTAINER_slist_add (handles_read, * GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, * readArray[i], sizeof (struct GNUNET_DISK_FileHandle)); * retcode++; * LOG (GNUNET_ERROR_TYPE_DEBUG, "Added read Pipe\n"); * } */ for (i = 0; i < readPipes; i++) { DWORD error; BOOL bret; SetLastError (0); waitstatus = 0; bret = PeekNamedPipe (readArray[i]->h, NULL, 0, NULL, &waitstatus, NULL); error = GetLastError (); LOG (GNUNET_ERROR_TYPE_DEBUG, "Peek at read pipe %d (0x%x) returned %d (%d bytes available) GLE %u\n", i, readArray[i]->h, bret, waitstatus, error); if (bret == 0) { if (error != ERROR_BROKEN_PIPE) continue; } else if (waitstatus <= 0) continue; GNUNET_CONTAINER_slist_add (handles_read, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, readArray[i], sizeof (struct GNUNET_DISK_FileHandle)); retcode++; LOG (GNUNET_ERROR_TYPE_DEBUG, "Added read Pipe 0x%x (0x%x)\n", readArray[i], readArray[i]->h); } } waitstatus = WaitForSingleObject (hEventWrite, 0); LOG (GNUNET_ERROR_TYPE_DEBUG, "Wait for the write event returned %d\n", waitstatus); if (waitstatus == WAIT_OBJECT_0) { for (i = 0; i < wfds->sds.fd_count; i++) { DWORD error; int status; int so_error = 0; int sizeof_so_error = sizeof (so_error); int gso_result = getsockopt (wfds->sds.fd_array[i], SOL_SOCKET, SO_ERROR, (char *) &so_error, &sizeof_so_error); status = send (wfds->sds.fd_array[i], NULL, 0, 0); error = GetLastError (); LOG (GNUNET_ERROR_TYPE_DEBUG, "send to the socket %d returned %d (%u)\n", i, status, error); if (status == 0 || (error != WSAEWOULDBLOCK && error != WSAENOTCONN) || (status == -1 && gso_result == 0 && error == WSAENOTCONN && so_error == WSAECONNREFUSED)) { FD_SET (wfds->sds.fd_array[i], &awrite); retcode += 1; } } } } if (!nhandles || (returnedpos >= nhandles)) LOG (GNUNET_ERROR_TYPE_DEBUG, "Returning from _select() with nothing!\n"); if (rfds) { struct GNUNET_CONTAINER_SList_Iterator t; for (i = 0; i < rfds->sds.fd_count; i++) { WSAEventSelect (rfds->sds.fd_array[i], hEventRead, 0); nsock++; } for (t = GNUNET_CONTAINER_slist_begin (rfds->handles); GNUNET_CONTAINER_slist_end (&t) != GNUNET_YES; GNUNET_CONTAINER_slist_next (&t)) { struct GNUNET_DISK_FileHandle *fh; fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&t, NULL); if (fh->type == GNUNET_PIPE) { CancelIo (fh->h); } } LOG (GNUNET_ERROR_TYPE_DEBUG, "Zeroing rfds\n"); GNUNET_NETWORK_fdset_zero (rfds); if (retcode != -1 && nhandles && (returnedpos < nhandles)) GNUNET_NETWORK_fdset_copy_native (rfds, &aread, retcode); GNUNET_CONTAINER_slist_append (rfds->handles, handles_read); } if (wfds) { for (i = 0; i < wfds->sds.fd_count; i++) { WSAEventSelect (wfds->sds.fd_array[i], hEventWrite, 0); nsock++; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Zeroing wfds\n"); GNUNET_NETWORK_fdset_zero (wfds); if (retcode != -1 && nhandles && (returnedpos < nhandles)) GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, retcode); GNUNET_CONTAINER_slist_append (wfds->handles, handles_write); } if (efds) { for (i = 0; i < efds->sds.fd_count; i++) { WSAEventSelect (efds->sds.fd_array[i], hEventException, 0); nsock++; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Zeroing efds\n"); GNUNET_NETWORK_fdset_zero (efds); if (retcode != -1 && nhandles && (returnedpos < nhandles)) GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, retcode); GNUNET_CONTAINER_slist_append (efds->handles, handles_except); } GNUNET_CONTAINER_slist_destroy (handles_read); GNUNET_CONTAINER_slist_destroy (handles_write); GNUNET_CONTAINER_slist_destroy (handles_except); #if DEBUG_NETWORK if (rfds) { struct GNUNET_CONTAINER_SList_Iterator t; for (i = 0; i < bread.fd_count; i++) { if (bread.fd_array[i] != 0) LOG (GNUNET_ERROR_TYPE_DEBUG, "FD 0x%x is %s in rfds\n", bread.fd_array[i], (SAFE_FD_ISSET (bread.fd_array[i], rfds)) ? "SET" : "NOT SET"); } for (t = GNUNET_CONTAINER_slist_begin (rfds->handles); GNUNET_CONTAINER_slist_end (&t) != GNUNET_YES; GNUNET_CONTAINER_slist_next (&t)) { struct GNUNET_DISK_FileHandle *fh; fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&t, NULL); LOG (GNUNET_ERROR_TYPE_DEBUG, "FD 0x%x is SET in rfds\n", fh->h); } } if (wfds) { for (i = 0; i < bwrite.fd_count; i++) { if (bwrite.fd_array[i] != 0) LOG (GNUNET_ERROR_TYPE_DEBUG, "FD 0x%x is %s in wfds\n", bwrite.fd_array[i], (SAFE_FD_ISSET (bwrite.fd_array[i], rfds)) ? "SET" : "NOT SET"); } } if (efds) { for (i = 0; i < bexcept.fd_count; i++) { if (bexcept.fd_array[i] != 0) LOG (GNUNET_ERROR_TYPE_DEBUG, "FD 0x%x is %s in efds\n", bexcept.fd_array[i], (SAFE_FD_ISSET (bexcept.fd_array[i], rfds)) ? "SET" : "NOT SET"); } } LOG (GNUNET_ERROR_TYPE_DEBUG, "Returning %d or 0\n", retcode); #endif if (nhandles && (returnedpos < nhandles)) return retcode; else #endif return 0; } /* end of network.c */ gnunet-0.9.3/src/util/container_heap.c0000644000175000017500000003203611760502551014641 00000000000000/* This file is part of GNUnet. (C) 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/container_heap.c * @brief Implementation of a heap * @author Nathan Evans * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) #define EXTRA_CHECKS 0 /** * Node in the heap. */ struct GNUNET_CONTAINER_HeapNode { /** * Heap this node belongs to. */ struct GNUNET_CONTAINER_Heap *heap; /** * Parent node. */ struct GNUNET_CONTAINER_HeapNode *parent; /** * Left child. */ struct GNUNET_CONTAINER_HeapNode *left_child; /** * Right child. */ struct GNUNET_CONTAINER_HeapNode *right_child; /** * Our element. */ void *element; /** * Cost for this element. */ GNUNET_CONTAINER_HeapCostType cost; /** * Number of elements below this node in the heap * (excluding this node itself). */ unsigned int tree_size; }; /** * Handle to a node in a heap. */ struct GNUNET_CONTAINER_Heap { /** * Root of the heap. */ struct GNUNET_CONTAINER_HeapNode *root; /** * Current position of our random walk. */ struct GNUNET_CONTAINER_HeapNode *walk_pos; /** * Number of elements in the heap. */ unsigned int size; /** * How is the heap sorted? */ enum GNUNET_CONTAINER_HeapOrder order; }; #if EXTRA_CHECKS /** * Check if internal invariants hold for the given node. * * @param node subtree to check */ static void check (const struct GNUNET_CONTAINER_HeapNode *node) { if (NULL == node) return; GNUNET_assert (node->tree_size == ((node->left_child == NULL) ? 0 : 1 + node->left_child->tree_size) + ((node->right_child == NULL) ? 0 : 1 + node->right_child->tree_size)); check (node->left_child); check (node->right_child); } #define CHECK(n) check(n) #else #define CHECK(n) do {} while (0) #endif /** * Create a new heap. * * @param order how should the heap be sorted? * @return handle to the heap */ struct GNUNET_CONTAINER_Heap * GNUNET_CONTAINER_heap_create (enum GNUNET_CONTAINER_HeapOrder order) { struct GNUNET_CONTAINER_Heap *heap; heap = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_Heap)); heap->order = order; return heap; } /** * Destroys the heap. Only call on a heap that * is already empty. * * @param heap heap to destroy */ void GNUNET_CONTAINER_heap_destroy (struct GNUNET_CONTAINER_Heap *heap) { GNUNET_break (heap->size == 0); GNUNET_free (heap); } /** * Get element stored at root of heap. * * @param heap heap to inspect * @return NULL if heap is empty */ void * GNUNET_CONTAINER_heap_peek (const struct GNUNET_CONTAINER_Heap *heap) { if (heap->root == NULL) return NULL; return heap->root->element; } /** * Get the current size of the heap * * @param heap the heap to get the size of * @return number of elements stored */ unsigned int GNUNET_CONTAINER_heap_get_size (const struct GNUNET_CONTAINER_Heap *heap) { return heap->size; } /** * Get the current cost of the node * * @param node the node to get the cost of * @return cost of the node */ GNUNET_CONTAINER_HeapCostType GNUNET_CONTAINER_heap_node_get_cost (const struct GNUNET_CONTAINER_HeapNode *node) { return node->cost; } /** * Iterate over the children of the given node. * * @param heap argument to give to iterator * @param node node to iterate over * @param iterator function to call on each node * @param iterator_cls closure for iterator * @return GNUNET_YES to continue to iterate */ static int node_iterator (const struct GNUNET_CONTAINER_Heap *heap, struct GNUNET_CONTAINER_HeapNode *node, GNUNET_CONTAINER_HeapIterator iterator, void *iterator_cls) { if (node == NULL) return GNUNET_YES; if (GNUNET_YES != node_iterator (heap, node->left_child, iterator, iterator_cls)) return GNUNET_NO; if (GNUNET_YES != node_iterator (heap, node->right_child, iterator, iterator_cls)) return GNUNET_NO; return iterator (iterator_cls, node, node->element, node->cost); } /** * Iterate over all entries in the heap. * * @param heap the heap * @param iterator function to call on each entry * @param iterator_cls closure for iterator */ void GNUNET_CONTAINER_heap_iterate (const struct GNUNET_CONTAINER_Heap *heap, GNUNET_CONTAINER_HeapIterator iterator, void *iterator_cls) { (void) node_iterator (heap, heap->root, iterator, iterator_cls); } /** * Perform a random walk of the tree. The walk is biased * towards elements closer to the root of the tree (since * each walk starts at the root and ends at a random leaf). * The heap internally tracks the current position of the * walk. * * @param heap heap to walk * @return data stored at the next random node in the walk; * NULL if the tree is empty. */ void * GNUNET_CONTAINER_heap_walk_get_next (struct GNUNET_CONTAINER_Heap *heap) { struct GNUNET_CONTAINER_HeapNode *pos; void *element; if (heap->root == NULL) return NULL; pos = heap->walk_pos; if (pos == NULL) pos = heap->root; element = pos->element; heap->walk_pos = (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2)) ? pos->right_child : pos->left_child; return element; } /** * Insert the given node 'node' into the subtree starting * at 'pos' (while keeping the tree somewhat balanced). * * @param heap heap to modify * @param pos existing tree * @param node node to insert (which may be a subtree itself) */ static void insert_node (struct GNUNET_CONTAINER_Heap *heap, struct GNUNET_CONTAINER_HeapNode *pos, struct GNUNET_CONTAINER_HeapNode *node) { struct GNUNET_CONTAINER_HeapNode *parent; GNUNET_assert (node->parent == NULL); while ((heap->order == GNUNET_CONTAINER_HEAP_ORDER_MAX) ? (pos->cost >= node->cost) : (pos->cost <= node->cost)) { /* node is descendent of pos */ pos->tree_size += (1 + node->tree_size); if (pos->left_child == NULL) { pos->left_child = node; node->parent = pos; return; } if (pos->right_child == NULL) { pos->right_child = node; node->parent = pos; return; } /* keep it balanced by descending into smaller subtree */ if (pos->left_child->tree_size < pos->right_child->tree_size) pos = pos->left_child; else pos = pos->right_child; } /* make 'node' parent of 'pos' */ parent = pos->parent; pos->parent = NULL; node->parent = parent; if (NULL == parent) { heap->root = node; } else { if (parent->left_child == pos) parent->left_child = node; else parent->right_child = node; } /* insert 'pos' below 'node' */ insert_node (heap, node, pos); CHECK (pos); } /** * Inserts a new element into the heap. * * @param heap heap to modify * @param element element to insert * @param cost cost for the element * @return node for the new element */ struct GNUNET_CONTAINER_HeapNode * GNUNET_CONTAINER_heap_insert (struct GNUNET_CONTAINER_Heap *heap, void *element, GNUNET_CONTAINER_HeapCostType cost) { struct GNUNET_CONTAINER_HeapNode *node; node = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_HeapNode)); node->heap = heap; node->element = element; node->cost = cost; heap->size++; if (NULL == heap->root) heap->root = node; else insert_node (heap, heap->root, node); GNUNET_assert (heap->size == heap->root->tree_size + 1); CHECK (heap->root); return node; } /** * Remove root of the heap. * * @param heap heap to modify * @return element data stored at the root node, NULL if heap is empty */ void * GNUNET_CONTAINER_heap_remove_root (struct GNUNET_CONTAINER_Heap *heap) { void *ret; struct GNUNET_CONTAINER_HeapNode *root; if (NULL == (root = heap->root)) return NULL; heap->size--; ret = root->element; if (root->left_child == NULL) { heap->root = root->right_child; if (root->right_child != NULL) root->right_child->parent = NULL; } else if (root->right_child == NULL) { heap->root = root->left_child; root->left_child->parent = NULL; } else { root->left_child->parent = NULL; root->right_child->parent = NULL; heap->root = root->left_child; insert_node (heap, heap->root, root->right_child); } GNUNET_free (root); #if EXTRA_CHECKS GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) || (heap->size == heap->root->tree_size + 1)); CHECK (heap->root); #endif return ret; } /** * Remove the given node 'node' from the tree and update * the 'tree_size' fields accordingly. Preserves the * children of 'node' and does NOT change the overall * 'size' field of the tree. */ static void remove_node (struct GNUNET_CONTAINER_HeapNode *node) { struct GNUNET_CONTAINER_HeapNode *ancestor; struct GNUNET_CONTAINER_Heap *heap = node->heap; /* update 'size' of the ancestors */ ancestor = node; while (NULL != (ancestor = ancestor->parent)) ancestor->tree_size--; /* update 'size' of node itself */ if (node->left_child != NULL) node->tree_size -= (1 + node->left_child->tree_size); if (node->right_child != NULL) node->tree_size -= (1 + node->right_child->tree_size); /* unlink 'node' itself and insert children in its place */ if (node->parent == NULL) { if (node->left_child != NULL) { heap->root = node->left_child; node->left_child->parent = NULL; if (node->right_child != NULL) { node->right_child->parent = NULL; insert_node (heap, heap->root, node->right_child); } } else { heap->root = node->right_child; if (node->right_child != NULL) node->right_child->parent = NULL; } } else { if (node->parent->left_child == node) node->parent->left_child = NULL; else node->parent->right_child = NULL; if (node->left_child != NULL) { node->left_child->parent = NULL; node->parent->tree_size -= (1 + node->left_child->tree_size); insert_node (heap, node->parent, node->left_child); } if (node->right_child != NULL) { node->right_child->parent = NULL; node->parent->tree_size -= (1 + node->right_child->tree_size); insert_node (heap, node->parent, node->right_child); } } node->parent = NULL; node->left_child = NULL; node->right_child = NULL; GNUNET_assert (node->tree_size == 0); CHECK (heap->root); } /** * Removes a node from the heap. * * @param node node to remove * @return element data stored at the node */ void * GNUNET_CONTAINER_heap_remove_node (struct GNUNET_CONTAINER_HeapNode *node) { void *ret; struct GNUNET_CONTAINER_Heap *heap; heap = node->heap; CHECK (heap->root); if (heap->walk_pos == node) (void) GNUNET_CONTAINER_heap_walk_get_next (heap); remove_node (node); heap->size--; ret = node->element; if (heap->walk_pos == node) heap->walk_pos = NULL; GNUNET_free (node); #if EXTRA_CHECKS CHECK (heap->root); GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) || (heap->size == heap->root->tree_size + 1)); #endif return ret; } /** * Updates the cost of any node in the tree * * @param heap heap to modify * @param node node for which the cost is to be changed * @param new_cost new cost for the node */ void GNUNET_CONTAINER_heap_update_cost (struct GNUNET_CONTAINER_Heap *heap, struct GNUNET_CONTAINER_HeapNode *node, GNUNET_CONTAINER_HeapCostType new_cost) { #if EXTRA_CHECKS GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) || (heap->size == heap->root->tree_size + 1)); CHECK (heap->root); #endif remove_node (node); #if EXTRA_CHECKS CHECK (heap->root); GNUNET_assert (((heap->size == 1) && (heap->root == NULL)) || (heap->size == heap->root->tree_size + 2)); #endif node->cost = new_cost; if (heap->root == NULL) heap->root = node; else insert_node (heap, heap->root, node); #if EXTRA_CHECKS CHECK (heap->root); GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) || (heap->size == heap->root->tree_size + 1)); #endif } /* end of heap.c */ gnunet-0.9.3/src/util/os_installation.c0000644000175000017500000003017511760502551015066 00000000000000/* This file is part of GNUnet. (C) 2006 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/util/os_installation.c * @brief get paths used by the program * @author Milan */ #include #include #include #include #include "platform.h" #include "gnunet_common.h" #include "gnunet_configuration_lib.h" #include "gnunet_disk_lib.h" #include "gnunet_os_lib.h" #if DARWIN #include #include #endif #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) #if LINUX /** * Try to determine path by reading /proc/PID/exe */ static char * get_path_from_proc_maps () { char fn[64]; char line[1024]; char dir[1024]; FILE *f; char *lgu; GNUNET_snprintf (fn, sizeof (fn), "/proc/%u/maps", getpid ()); f = FOPEN (fn, "r"); if (f == NULL) return NULL; while (NULL != fgets (line, sizeof (line), f)) { if ((1 == SSCANF (line, "%*x-%*x %*c%*c%*c%*c %*x %*2u:%*2u %*u%*[ ]%s", dir)) && (NULL != (lgu = strstr (dir, "libgnunetutil")))) { lgu[0] = '\0'; FCLOSE (f); return GNUNET_strdup (dir); } } FCLOSE (f); return NULL; } /** * Try to determine path by reading /proc/PID/exe */ static char * get_path_from_proc_exe () { char fn[64]; char lnk[1024]; ssize_t size; GNUNET_snprintf (fn, sizeof (fn), "/proc/%u/exe", getpid ()); size = readlink (fn, lnk, sizeof (lnk) - 1); if (size <= 0) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "readlink", fn); return NULL; } GNUNET_assert (size < sizeof (lnk)); lnk[size] = '\0'; while ((lnk[size] != '/') && (size > 0)) size--; if ((size < 4) || (lnk[size - 4] != '/')) { /* not installed in "/bin/" -- binary path probably useless */ return NULL; } lnk[size] = '\0'; return GNUNET_strdup (lnk); } #endif #if WINDOWS /** * Try to determine path with win32-specific function */ static char * get_path_from_module_filename () { wchar_t path[4097]; char upath[4097]; wchar_t *idx; GetModuleFileNameW (NULL, path, sizeof (path) - 1); idx = path + wcslen (path); while ((idx > path) && (*idx != L'\\') && (*idx != L'/')) idx--; *idx = L'\0'; upath[0] = '\0'; WideCharToMultiByte (CP_UTF8, 0, path, -1, upath, 4097, NULL, NULL); return GNUNET_strdup (upath); } #endif #if DARWIN typedef int (*MyNSGetExecutablePathProto) (char *buf, size_t * bufsize); static char * get_path_from_NSGetExecutablePath () { static char zero = '\0'; char *path; size_t len; MyNSGetExecutablePathProto func; int ret; path = NULL; func = (MyNSGetExecutablePathProto) dlsym (RTLD_DEFAULT, "_NSGetExecutablePath"); if (!func) return NULL; path = &zero; len = 0; /* get the path len, including the trailing \0 */ func (path, &len); if (len == 0) return NULL; path = GNUNET_malloc (len); ret = func (path, &len); if (ret != 0) { GNUNET_free (path); return NULL; } len = strlen (path); while ((path[len] != '/') && (len > 0)) len--; path[len] = '\0'; return path; } static char * get_path_from_dyld_image () { const char *path; char *p, *s; int i; int c; p = NULL; c = _dyld_image_count (); for (i = 0; i < c; i++) { if (_dyld_get_image_header (i) == &_mh_dylib_header) { path = _dyld_get_image_name (i); if (path != NULL && strlen (path) > 0) { p = GNUNET_strdup (path); s = p + strlen (p); while ((s > p) && (*s != '/')) s--; s++; *s = '\0'; } break; } } return p; } #endif /** * Return the actual path to a file found in the current * PATH environment variable. * * @param binary the name of the file to find * @return path to binary, NULL if not found */ static char * get_path_from_PATH (const char *binary) { char *path; char *pos; char *end; char *buf; const char *p; p = getenv ("PATH"); if (p == NULL) return NULL; path = GNUNET_strdup (p); /* because we write on it */ buf = GNUNET_malloc (strlen (path) + 20); pos = path; while (NULL != (end = strchr (pos, PATH_SEPARATOR))) { *end = '\0'; sprintf (buf, "%s/%s", pos, binary); if (GNUNET_DISK_file_test (buf) == GNUNET_YES) { pos = GNUNET_strdup (pos); GNUNET_free (buf); GNUNET_free (path); return pos; } pos = end + 1; } sprintf (buf, "%s/%s", pos, binary); if (GNUNET_DISK_file_test (buf) == GNUNET_YES) { pos = GNUNET_strdup (pos); GNUNET_free (buf); GNUNET_free (path); return pos; } GNUNET_free (buf); GNUNET_free (path); return NULL; } static char * get_path_from_GNUNET_PREFIX () { const char *p; p = getenv ("GNUNET_PREFIX"); if (p != NULL) return GNUNET_strdup (p); return NULL; } /** * @brief get the path to GNUnet bin/ or lib/, prefering the lib/ path * @author Milan * * @return a pointer to the executable path, or NULL on error */ static char * os_get_gnunet_path () { char *ret; ret = get_path_from_GNUNET_PREFIX (); if (ret != NULL) return ret; #if LINUX ret = get_path_from_proc_maps (); if (ret != NULL) return ret; ret = get_path_from_proc_exe (); if (ret != NULL) return ret; #endif #if WINDOWS ret = get_path_from_module_filename (); if (ret != NULL) return ret; #endif #if DARWIN ret = get_path_from_dyld_image (); if (ret != NULL) return ret; ret = get_path_from_NSGetExecutablePath (); if (ret != NULL) return ret; #endif ret = get_path_from_PATH ("gnunet-arm"); if (ret != NULL) return ret; /* other attempts here */ LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Could not determine installation path for %s. Set `%s' environment variable.\n"), "GNUnet", "GNUNET_PREFIX"); return NULL; } /* * @brief get the path to current app's bin/ * @author Milan * * @return a pointer to the executable path, or NULL on error */ static char * os_get_exec_path () { char *ret; ret = NULL; #if LINUX ret = get_path_from_proc_exe (); if (ret != NULL) return ret; #endif #if WINDOWS ret = get_path_from_module_filename (); if (ret != NULL) return ret; #endif #if DARWIN ret = get_path_from_NSGetExecutablePath (); if (ret != NULL) return ret; #endif /* other attempts here */ return ret; } /** * @brief get the path to a specific GNUnet installation directory or, * with GNUNET_IPK_SELF_PREFIX, the current running apps installation directory * @author Milan * @return a pointer to the dir path (to be freed by the caller) */ char * GNUNET_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind) { size_t n; const char *dirname; char *execpath = NULL; char *tmp; int isbasedir; /* if wanted, try to get the current app's bin/ */ if (dirkind == GNUNET_OS_IPK_SELF_PREFIX) execpath = os_get_exec_path (); /* try to get GNUnet's bin/ or lib/, or if previous was unsuccessful some * guess for the current app */ if (execpath == NULL) execpath = os_get_gnunet_path (); if (execpath == NULL) return NULL; n = strlen (execpath); if (n == 0) { /* should never happen, but better safe than sorry */ GNUNET_free (execpath); return NULL; } /* remove filename itself */ while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR)) execpath[--n] = '\0'; isbasedir = 1; if ((n > 5) && ((0 == strcasecmp (&execpath[n - 5], "lib32")) || (0 == strcasecmp (&execpath[n - 5], "lib64")))) { if (dirkind != GNUNET_OS_IPK_LIBDIR) { /* strip '/lib32' or '/lib64' */ execpath[n - 5] = '\0'; n -= 5; } else isbasedir = 0; } else if ((n > 3) && ((0 == strcasecmp (&execpath[n - 3], "bin")) || (0 == strcasecmp (&execpath[n - 3], "lib")))) { /* strip '/bin' or '/lib' */ execpath[n - 3] = '\0'; n -= 3; } /* in case this was a directory named foo-bin, remove "foo-" */ while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR)) execpath[--n] = '\0'; switch (dirkind) { case GNUNET_OS_IPK_PREFIX: case GNUNET_OS_IPK_SELF_PREFIX: dirname = DIR_SEPARATOR_STR; break; case GNUNET_OS_IPK_BINDIR: dirname = DIR_SEPARATOR_STR "bin" DIR_SEPARATOR_STR; break; case GNUNET_OS_IPK_LIBDIR: if (isbasedir) dirname = DIR_SEPARATOR_STR "lib" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR; else dirname = DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR; break; case GNUNET_OS_IPK_DATADIR: dirname = DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "gnunet" DIR_SEPARATOR_STR; break; case GNUNET_OS_IPK_LOCALEDIR: dirname = DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "locale" DIR_SEPARATOR_STR; break; case GNUNET_OS_IPK_ICONDIR: dirname = DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "icons" DIR_SEPARATOR_STR; break; case GNUNET_OS_IPK_DOCDIR: dirname = DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "doc" DIR_SEPARATOR_STR \ "gnunet" DIR_SEPARATOR_STR; break; default: GNUNET_free (execpath); return NULL; } tmp = GNUNET_malloc (strlen (execpath) + strlen (dirname) + 1); sprintf (tmp, "%s%s", execpath, dirname); GNUNET_free (execpath); return tmp; } /** * Check whether an executable exists and possibly * if the suid bit is set on the file. * Attempts to find the file using the current * PATH environment variable as a search path. * * @param binary the name of the file to check * @return GNUNET_YES if the file is SUID, * GNUNET_NO if not SUID (but binary exists) * GNUNET_SYSERR on error (no such binary or not executable) */ int GNUNET_OS_check_helper_binary (const char *binary) { struct stat statbuf; char *p; char *pf; #ifdef MINGW SOCKET rawsock; char *binaryexe; GNUNET_asprintf (&binaryexe, "%s.exe", binary); p = get_path_from_PATH (binaryexe); if (p != NULL) { GNUNET_asprintf (&pf, "%s/%s", p, binaryexe); GNUNET_free (p); p = pf; } GNUNET_free (binaryexe); #else p = get_path_from_PATH (binary); if (p != NULL) { GNUNET_asprintf (&pf, "%s/%s", p, binary); GNUNET_free (p); p = pf; } #endif if (p == NULL) { LOG (GNUNET_ERROR_TYPE_INFO, _("Could not find binary `%s' in PATH!\n"), binary); return GNUNET_SYSERR; } if (0 != ACCESS (p, X_OK)) { LOG (GNUNET_ERROR_TYPE_WARNING, _("access (%s, X_OK) failed: %s\n"), p, STRERROR (errno)); GNUNET_free (p); return GNUNET_SYSERR; } #ifndef MINGW if (0 == getuid ()) { /* as we run as root, we don't insist on SUID */ GNUNET_free (p); return GNUNET_OK; } #endif if (0 != STAT (p, &statbuf)) { LOG (GNUNET_ERROR_TYPE_WARNING, _("stat (%s) failed: %s\n"), p, STRERROR (errno)); GNUNET_free (p); return GNUNET_SYSERR; } #ifndef MINGW if ((0 != (statbuf.st_mode & S_ISUID)) && (statbuf.st_uid == 0)) { GNUNET_free (p); return GNUNET_YES; } /* binary exists, but not SUID */ GNUNET_free (p); return GNUNET_NO; #else GNUNET_free (p); rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); if (INVALID_SOCKET == rawsock) { DWORD err = GetLastError (); LOG (GNUNET_ERROR_TYPE_INFO, "socket (AF_INET, SOCK_RAW, IPPROTO_ICMP) failed! GLE = %d\n", err); return GNUNET_NO; /* not running as administrator */ } closesocket (rawsock); return GNUNET_YES; #endif } /* end of os_installation.c */ gnunet-0.9.3/src/util/strings.c0000644000175000017500000007114511760502551013357 00000000000000/* This file is part of GNUnet. (C) 2005, 2006 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/strings.c * @brief string functions * @author Nils Durner * @author Christian Grothoff */ #include "platform.h" #if HAVE_ICONV #include #endif #include "gnunet_common.h" #include "gnunet_strings_lib.h" #include #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) /** * Fill a buffer of the given size with * count 0-terminated strings (given as varargs). * If "buffer" is NULL, only compute the amount of * space required (sum of "strlen(arg)+1"). * * Unlike using "snprintf" with "%s", this function * will add 0-terminators after each string. The * "GNUNET_string_buffer_tokenize" function can be * used to parse the buffer back into individual * strings. * * @param buffer the buffer to fill with strings, can * be NULL in which case only the necessary * amount of space will be calculated * @param size number of bytes available in buffer * @param count number of strings that follow * @param ... count 0-terminated strings to copy to buffer * @return number of bytes written to the buffer * (or number of bytes that would have been written) */ size_t GNUNET_STRINGS_buffer_fill (char *buffer, size_t size, unsigned int count, ...) { size_t needed; size_t slen; const char *s; va_list ap; needed = 0; va_start (ap, count); while (count > 0) { s = va_arg (ap, const char *); slen = strlen (s) + 1; if (buffer != NULL) { GNUNET_assert (needed + slen <= size); memcpy (&buffer[needed], s, slen); } needed += slen; count--; } va_end (ap); return needed; } /** * Given a buffer of a given size, find "count" * 0-terminated strings in the buffer and assign * the count (varargs) of type "const char**" to the * locations of the respective strings in the * buffer. * * @param buffer the buffer to parse * @param size size of the buffer * @param count number of strings to locate * @return offset of the character after the last 0-termination * in the buffer, or 0 on error. */ unsigned int GNUNET_STRINGS_buffer_tokenize (const char *buffer, size_t size, unsigned int count, ...) { unsigned int start; unsigned int needed; const char **r; va_list ap; needed = 0; va_start (ap, count); while (count > 0) { r = va_arg (ap, const char **); start = needed; while ((needed < size) && (buffer[needed] != '\0')) needed++; if (needed == size) { va_end (ap); return 0; /* error */ } *r = &buffer[start]; needed++; /* skip 0-termination */ count--; } va_end (ap); return needed; } /** * Convert a given filesize into a fancy human-readable format. * * @param size number of bytes * @return fancy representation of the size (possibly rounded) for humans */ char * GNUNET_STRINGS_byte_size_fancy (unsigned long long size) { const char *unit = _( /* size unit */ "b"); char *ret; if (size > 5 * 1024) { size = size / 1024; unit = "KiB"; if (size > 5 * 1024) { size = size / 1024; unit = "MiB"; if (size > 5 * 1024) { size = size / 1024; unit = "GiB"; if (size > 5 * 1024) { size = size / 1024; unit = "TiB"; } } } } ret = GNUNET_malloc (32); GNUNET_snprintf (ret, 32, "%llu %s", size, unit); return ret; } /** * Unit conversion table entry for 'convert_with_table'. */ struct ConversionTable { /** * Name of the unit (or NULL for end of table). */ const char *name; /** * Factor to apply for this unit. */ unsigned long long value; }; /** * Convert a string of the form "4 X 5 Y" into a numeric value * by interpreting "X" and "Y" as units and then multiplying * the numbers with the values associated with the respective * unit from the conversion table. * * @param input input string to parse * @param table table with the conversion of unit names to numbers * @param output where to store the result * @return GNUNET_OK on success, GNUNET_SYSERR on error */ static int convert_with_table (const char *input, const struct ConversionTable *table, unsigned long long *output) { unsigned long long ret; char *in; const char *tok; unsigned long long last; unsigned int i; ret = 0; last = 0; in = GNUNET_strdup (input); for (tok = strtok (in, " "); tok != NULL; tok = strtok (NULL, " ")) { i = 0; while ((table[i].name != NULL) && (0 != strcasecmp (table[i].name, tok))) i++; if (table[i].name != NULL) last *= table[i].value; else { ret += last; last = 0; if (1 != SSCANF (tok, "%llu", &last)) { GNUNET_free (in); return GNUNET_SYSERR; /* expected number */ } } } ret += last; *output = ret; GNUNET_free (in); return GNUNET_OK; } /** * Convert a given fancy human-readable size to bytes. * * @param fancy_size human readable string (i.e. 1 MB) * @param size set to the size in bytes * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_STRINGS_fancy_size_to_bytes (const char *fancy_size, unsigned long long *size) { static const struct ConversionTable table[] = { { "B", 1}, { "KiB", 1024}, { "kB", 1000}, { "MiB", 1024 * 1024}, { "MB", 1000 * 1000}, { "GiB", 1024 * 1024 * 1024}, { "GB", 1000 * 1000 * 1000}, { "TiB", 1024LL * 1024LL * 1024LL * 1024LL}, { "TB", 1000LL * 1000LL * 1000LL * 1024LL}, { "PiB", 1024LL * 1024LL * 1024LL * 1024LL * 1024LL}, { "PB", 1000LL * 1000LL * 1000LL * 1024LL * 1000LL}, { "EiB", 1024LL * 1024LL * 1024LL * 1024LL * 1024LL * 1024LL}, { "EB", 1000LL * 1000LL * 1000LL * 1024LL * 1000LL * 1000LL}, { NULL, 0} }; return convert_with_table (fancy_size, table, size); } /** * Convert a given fancy human-readable time to our internal * representation. * * @param fancy_time human readable string (i.e. 1 minute) * @param rtime set to the relative time * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_STRINGS_fancy_time_to_relative (const char *fancy_time, struct GNUNET_TIME_Relative *rtime) { static const struct ConversionTable table[] = { { "ms", 1}, { "s", 1000}, { "\"", 1000}, { "min", 60 * 1000}, { "minutes", 60 * 1000}, { "'", 60 * 1000}, { "h", 60 * 60 * 1000}, { "d", 24 * 60 * 60 * 1000}, { "a", 31536000000LL /* year */ }, { NULL, 0} }; int ret; unsigned long long val; ret = convert_with_table (fancy_time, table, &val); rtime->rel_value = (uint64_t) val; return ret; } /** * Convert the len characters long character sequence * given in input that is in the given input charset * to a string in given output charset. * @return the converted string (0-terminated), * if conversion fails, a copy of the orignal * string is returned. */ char * GNUNET_STRINGS_conv (const char *input, size_t len, const char *input_charset, const char *output_charset) { char *ret; #if ENABLE_NLS && HAVE_ICONV size_t tmpSize; size_t finSize; char *tmp; char *itmp; iconv_t cd; cd = iconv_open (output_charset, input_charset); if (cd == (iconv_t) - 1) { LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "iconv_open"); LOG (GNUNET_ERROR_TYPE_WARNING, _("Character sets requested were `%s'->`%s'\n"), input_charset, output_charset); ret = GNUNET_malloc (len + 1); memcpy (ret, input, len); ret[len] = '\0'; return ret; } tmpSize = 3 * len + 4; tmp = GNUNET_malloc (tmpSize); itmp = tmp; finSize = tmpSize; if (iconv (cd, #if FREEBSD || DARWIN || WINDOWS (const char **) &input, #else (char **) &input, #endif &len, &itmp, &finSize) == SIZE_MAX) { LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "iconv"); iconv_close (cd); GNUNET_free (tmp); ret = GNUNET_malloc (len + 1); memcpy (ret, input, len); ret[len] = '\0'; return ret; } ret = GNUNET_malloc (tmpSize - finSize + 1); memcpy (ret, tmp, tmpSize - finSize); ret[tmpSize - finSize] = '\0'; GNUNET_free (tmp); if (0 != iconv_close (cd)) LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "iconv_close"); return ret; #else ret = GNUNET_malloc (len + 1); memcpy (ret, input, len); ret[len] = '\0'; return ret; #endif } /** * Convert the len characters long character sequence * given in input that is in the given charset * to UTF-8. * @return the converted string (0-terminated), * if conversion fails, a copy of the orignal * string is returned. */ char * GNUNET_STRINGS_to_utf8 (const char *input, size_t len, const char *charset) { return GNUNET_STRINGS_conv (input, len, charset, "UTF-8"); } /** * Convert the len bytes-long UTF-8 string * given in input to the given charset. * @return the converted string (0-terminated), * if conversion fails, a copy of the orignal * string is returned. */ char * GNUNET_STRINGS_from_utf8 (const char *input, size_t len, const char *charset) { return GNUNET_STRINGS_conv (input, len, "UTF-8", charset); } /** * Convert the utf-8 input string to lowercase * Output needs to be allocated appropriately * * @param input input string * @param output output buffer */ void GNUNET_STRINGS_utf8_tolower(const char* input, char** output) { uint8_t *tmp_in; size_t len; tmp_in = u8_tolower ((uint8_t*)input, strlen ((char *) input), NULL, UNINORM_NFD, NULL, &len); memcpy(*output, tmp_in, len); (*output)[len] = '\0'; free(tmp_in); } /** * Convert the utf-8 input string to uppercase * Output needs to be allocated appropriately * * @param input input string * @param output output buffer */ void GNUNET_STRINGS_utf8_toupper(const char* input, char** output) { uint8_t *tmp_in; size_t len; tmp_in = u8_toupper ((uint8_t*)input, strlen ((char *) input), NULL, UNINORM_NFD, NULL, &len); memcpy(*output, tmp_in, len); (*output)[len] = '\0'; free(tmp_in); } /** * Complete filename (a la shell) from abbrevition. * @param fil the name of the file, may contain ~/ or * be relative to the current directory * @returns the full file name, * NULL is returned on error */ char * GNUNET_STRINGS_filename_expand (const char *fil) { char *buffer; #ifndef MINGW size_t len; size_t n; char *fm; const char *fil_ptr; #else char *fn; long lRet; #endif if (fil == NULL) return NULL; #ifndef MINGW if (fil[0] == DIR_SEPARATOR) /* absolute path, just copy */ return GNUNET_strdup (fil); if (fil[0] == '~') { fm = getenv ("HOME"); if (fm == NULL) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Failed to expand `$HOME': environment variable `HOME' not set")); return NULL; } fm = GNUNET_strdup (fm); /* do not copy '~' */ fil_ptr = fil + 1; /* skip over dir seperator to be consistent */ if (fil_ptr[0] == DIR_SEPARATOR) fil_ptr++; } else { /* relative path */ fil_ptr = fil; len = 512; fm = NULL; while (1) { buffer = GNUNET_malloc (len); if (getcwd (buffer, len) != NULL) { fm = buffer; break; } if ((errno == ERANGE) && (len < 1024 * 1024 * 4)) { len *= 2; GNUNET_free (buffer); continue; } GNUNET_free (buffer); break; } if (fm == NULL) { LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "getcwd"); buffer = getenv ("PWD"); /* alternative */ if (buffer != NULL) fm = GNUNET_strdup (buffer); } if (fm == NULL) fm = GNUNET_strdup ("./"); /* give up */ } n = strlen (fm) + 1 + strlen (fil_ptr) + 1; buffer = GNUNET_malloc (n); GNUNET_snprintf (buffer, n, "%s%s%s", fm, (fm[strlen (fm) - 1] == DIR_SEPARATOR) ? "" : DIR_SEPARATOR_STR, fil_ptr); GNUNET_free (fm); return buffer; #else fn = GNUNET_malloc (MAX_PATH + 1); if ((lRet = plibc_conv_to_win_path (fil, fn)) != ERROR_SUCCESS) { SetErrnoFromWinError (lRet); LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "plibc_conv_to_win_path"); return NULL; } /* is the path relative? */ if ((strncmp (fn + 1, ":\\", 2) != 0) && (strncmp (fn, "\\\\", 2) != 0)) { char szCurDir[MAX_PATH + 1]; lRet = GetCurrentDirectory (MAX_PATH + 1, szCurDir); if (lRet + strlen (fn) + 1 > (MAX_PATH + 1)) { SetErrnoFromWinError (ERROR_BUFFER_OVERFLOW); LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "GetCurrentDirectory"); return NULL; } buffer = GNUNET_malloc (MAX_PATH + 1); GNUNET_snprintf (buffer, MAX_PATH + 1, "%s\\%s", szCurDir, fn); GNUNET_free (fn); fn = buffer; } return fn; #endif } /** * Give relative time in human-readable fancy format. * * @param delta time in milli seconds * @return time as human-readable string */ char * GNUNET_STRINGS_relative_time_to_string (struct GNUNET_TIME_Relative delta) { const char *unit = _( /* time unit */ "ms"); char *ret; uint64_t dval = delta.rel_value; if (delta.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value) return GNUNET_strdup (_("eternity")); if (dval > 5 * 1000) { dval = dval / 1000; unit = _( /* time unit */ "s"); if (dval > 5 * 60) { dval = dval / 60; unit = _( /* time unit */ "m"); if (dval > 5 * 60) { dval = dval / 60; unit = _( /* time unit */ "h"); if (dval > 5 * 24) { dval = dval / 24; unit = _( /* time unit */ " days"); } } } } GNUNET_asprintf (&ret, "%llu %s", dval, unit); return ret; } /** * "man ctime_r", except for GNUnet time; also, unlike ctime, the * return value does not include the newline character. * * @param t time to convert * @return absolute time in human-readable format */ char * GNUNET_STRINGS_absolute_time_to_string (struct GNUNET_TIME_Absolute t) { time_t tt; char *ret; if (t.abs_value == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value) return GNUNET_strdup (_("end of time")); tt = t.abs_value / 1000; #ifdef ctime_r ret = ctime_r (&tt, GNUNET_malloc (32)); #else ret = GNUNET_strdup (ctime (&tt)); #endif ret[strlen (ret) - 1] = '\0'; return ret; } /** * "man basename" * Returns a pointer to a part of filename (allocates nothing)! * * @param filename filename to extract basename from * @return short (base) name of the file (that is, everything following the * last directory separator in filename. If filename ends with a * directory separator, the result will be a zero-length string. * If filename has no directory separators, the result is filename * itself. */ const char * GNUNET_STRINGS_get_short_name (const char *filename) { const char *short_fn = filename; const char *ss; while (NULL != (ss = strstr (short_fn, DIR_SEPARATOR_STR)) && (ss[1] != '\0')) short_fn = 1 + ss; return short_fn; } /** * Get the numeric value corresponding to a character. * * @param a a character * @return corresponding numeric value */ static unsigned int getValue__ (unsigned char a) { if ((a >= '0') && (a <= '9')) return a - '0'; if ((a >= 'A') && (a <= 'V')) return (a - 'A' + 10); return -1; } /** * Convert binary data to ASCII encoding. The ASCII encoding is rather * GNUnet specific. It was chosen such that it only uses characters * in [0-9A-V], can be produced without complex arithmetics and uses a * small number of characters. * Does not append 0-terminator, but returns a pointer to the place where * it should be placed, if needed. * * @param data data to encode * @param size size of data (in bytes) * @param out buffer to fill * @param out_size size of the buffer. Must be large enough to hold * ((size*8) + (((size*8) % 5) > 0 ? 5 - ((size*8) % 5) : 0)) / 5 bytes * @return pointer to the next byte in 'out' or NULL on error. */ char * GNUNET_STRINGS_data_to_string (const unsigned char *data, size_t size, char *out, size_t out_size) { /** * 32 characters for encoding */ static char *encTable__ = "0123456789ABCDEFGHIJKLMNOPQRSTUV"; unsigned int wpos; unsigned int rpos; unsigned int bits; unsigned int vbit; GNUNET_assert (data != NULL); GNUNET_assert (out != NULL); if (out_size < (((size*8) + ((size*8) % 5)) % 5)) { GNUNET_break (0); return NULL; } vbit = 0; wpos = 0; rpos = 0; bits = 0; while ((rpos < size) || (vbit > 0)) { if ((rpos < size) && (vbit < 5)) { bits = (bits << 8) | data[rpos++]; /* eat 8 more bits */ vbit += 8; } if (vbit < 5) { bits <<= (5 - vbit); /* zero-padding */ GNUNET_assert (vbit == ((size * 8) % 5)); vbit = 5; } if (wpos >= out_size) { GNUNET_break (0); return NULL; } out[wpos++] = encTable__[(bits >> (vbit - 5)) & 31]; vbit -= 5; } if (wpos != out_size) { GNUNET_break (0); return NULL; } GNUNET_assert (vbit == 0); return &out[wpos]; } /** * Convert ASCII encoding back to data * out_size must match exactly the size of the data before it was encoded. * * @param enc the encoding * @param enclen number of characters in 'enc' (without 0-terminator, which can be missing) * @param out location where to store the decoded data * @param out_size sizeof the output buffer * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding */ int GNUNET_STRINGS_string_to_data (const char *enc, size_t enclen, unsigned char *out, size_t out_size) { unsigned int rpos; unsigned int wpos; unsigned int bits; unsigned int vbit; int ret; int shift; int encoded_len = out_size * 8; if (encoded_len % 5 > 0) { vbit = encoded_len % 5; /* padding! */ shift = 5 - vbit; } else { vbit = 0; shift = 0; } if ((encoded_len + shift) / 5 != enclen) return GNUNET_SYSERR; wpos = out_size; rpos = enclen; bits = (ret = getValue__ (enc[--rpos])) >> (5 - encoded_len % 5); if (-1 == ret) return GNUNET_SYSERR; while (wpos > 0) { GNUNET_assert (rpos > 0); bits = ((ret = getValue__ (enc[--rpos])) << vbit) | bits; if (-1 == ret) return GNUNET_SYSERR; vbit += 5; if (vbit >= 8) { out[--wpos] = (unsigned char) bits; bits >>= 8; vbit -= 8; } } GNUNET_assert (rpos == 0); GNUNET_assert (vbit == 0); return GNUNET_OK; } /** * Parse a path that might be an URI. * * @param path path to parse. Must be NULL-terminated. * @param scheme_part a pointer to 'char *' where a pointer to a string that * represents the URI scheme will be stored. Can be NULL. The string is * allocated by the function, and should be freed by GNUNET_free() when * it is no longer needed. * @param path_part a pointer to 'const char *' where a pointer to the path * part of the URI will be stored. Can be NULL. Points to the same block * of memory as 'path', and thus must not be freed. Might point to '\0', * if path part is zero-length. * @return GNUNET_YES if it's an URI, GNUNET_NO otherwise. If 'path' is not * an URI, '* scheme_part' and '*path_part' will remain unchanged * (if they weren't NULL). */ int GNUNET_STRINGS_parse_uri (const char *path, char **scheme_part, const char **path_part) { size_t len; int i, end; int pp_state = 0; const char *post_scheme_part = NULL; len = strlen (path); for (end = 0, i = 0; !end && i < len; i++) { switch (pp_state) { case 0: if (path[i] == ':' && i > 0) { pp_state += 1; continue; } if (!((path[i] >= 'A' && path[i] <= 'Z') || (path[i] >= 'a' && path[i] <= 'z') || (path[i] >= '0' && path[i] <= '9') || path[i] == '+' || path[i] == '-' || (path[i] == '.'))) end = 1; break; case 1: case 2: if (path[i] == '/') { pp_state += 1; continue; } end = 1; break; case 3: post_scheme_part = &path[i]; end = 1; break; default: end = 1; } } if (post_scheme_part == NULL) return GNUNET_NO; if (scheme_part) { *scheme_part = GNUNET_malloc (post_scheme_part - path + 1); memcpy (*scheme_part, path, post_scheme_part - path); (*scheme_part)[post_scheme_part - path] = '\0'; } if (path_part) *path_part = post_scheme_part; return GNUNET_YES; } /** * Check whether 'filename' is absolute or not, and if it's an URI * * @param filename filename to check * @param can_be_uri GNUNET_YES to check for being URI, GNUNET_NO - to * assume it's not URI * @param r_is_uri a pointer to an int that is set to GNUNET_YES if 'filename' * is URI and to GNUNET_NO otherwise. Can be NULL. If 'can_be_uri' is * not GNUNET_YES, *r_is_uri is set to GNUNET_NO. * @param r_uri_scheme a pointer to a char * that is set to a pointer to URI scheme. * The string is allocated by the function, and should be freed with * GNUNET_free (). Can be NULL. * @return GNUNET_YES if 'filename' is absolute, GNUNET_NO otherwise. */ int GNUNET_STRINGS_path_is_absolute (const char *filename, int can_be_uri, int *r_is_uri, char **r_uri_scheme) { #if WINDOWS size_t len; #endif const char *post_scheme_path; int is_uri; char * uri; /* consider POSIX paths to be absolute too, even on W32, * as plibc expansion will fix them for us. */ if (filename[0] == '/') return GNUNET_YES; if (can_be_uri) { is_uri = GNUNET_STRINGS_parse_uri (filename, &uri, &post_scheme_path); if (r_is_uri) *r_is_uri = is_uri; if (is_uri) { if (r_uri_scheme) *r_uri_scheme = uri; else GNUNET_free_non_null (uri); #if WINDOWS len = strlen(post_scheme_path); /* Special check for file:///c:/blah * We want to parse 'c:/', not '/c:/' */ if (post_scheme_path[0] == '/' && len >= 3 && post_scheme_path[2] == ':') post_scheme_path = &post_scheme_path[1]; #endif return GNUNET_STRINGS_path_is_absolute (post_scheme_path, GNUNET_NO, NULL, NULL); } } else { is_uri = GNUNET_NO; if (r_is_uri) *r_is_uri = GNUNET_NO; } #if WINDOWS len = strlen (filename); if (len >= 3 && ((filename[0] >= 'A' && filename[0] <= 'Z') || (filename[0] >= 'a' && filename[0] <= 'z')) && filename[1] == ':' && (filename[2] == '/' || filename[2] == '\\')) return GNUNET_YES; #endif return GNUNET_NO; } #if MINGW #define _IFMT 0170000 /* type of file */ #define _IFLNK 0120000 /* symbolic link */ #define S_ISLNK(m) (((m)&_IFMT) == _IFLNK) #endif /** * Perform 'checks' on 'filename' * * @param filename file to check * @param checks checks to perform * @return GNUNET_YES if all checks pass, GNUNET_NO if at least one of them * fails, GNUNET_SYSERR when a check can't be performed */ int GNUNET_STRINGS_check_filename (const char *filename, enum GNUNET_STRINGS_FilenameCheck checks) { struct stat st; if ( (NULL == filename) || (filename[0] == '\0') ) return GNUNET_SYSERR; if (0 != (checks & GNUNET_STRINGS_CHECK_IS_ABSOLUTE)) if (!GNUNET_STRINGS_path_is_absolute (filename, GNUNET_NO, NULL, NULL)) return GNUNET_NO; if (0 != (checks & (GNUNET_STRINGS_CHECK_EXISTS | GNUNET_STRINGS_CHECK_IS_DIRECTORY | GNUNET_STRINGS_CHECK_IS_LINK))) { if (0 != STAT (filename, &st)) { if (0 != (checks & GNUNET_STRINGS_CHECK_EXISTS)) return GNUNET_NO; else return GNUNET_SYSERR; } } if (0 != (checks & GNUNET_STRINGS_CHECK_IS_DIRECTORY)) if (!S_ISDIR (st.st_mode)) return GNUNET_NO; if (0 != (checks & GNUNET_STRINGS_CHECK_IS_LINK)) if (!S_ISLNK (st.st_mode)) return GNUNET_NO; return GNUNET_YES; } /** * Tries to convert 'zt_addr' string to an IPv6 address. * The string is expected to have the format "[ABCD::01]:80". * * @param zt_addr 0-terminated string. May be mangled by the function. * @param addrlen length of zt_addr (not counting 0-terminator). * @param r_buf a buffer to fill. Initially gets filled with zeroes, * then its sin6_port, sin6_family and sin6_addr are set appropriately. * @return GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which * case the contents of r_buf are undefined. */ int GNUNET_STRINGS_to_address_ipv6 (const char *zt_addr, uint16_t addrlen, struct sockaddr_in6 *r_buf) { char zbuf[addrlen + 1]; int ret; char *port_colon; unsigned int port; if (addrlen < 6) return GNUNET_SYSERR; memcpy (zbuf, zt_addr, addrlen); if ('[' != zbuf[0]) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("IPv6 address did not start with `['\n")); return GNUNET_SYSERR; } zbuf[addrlen] = '\0'; port_colon = strrchr (zbuf, ':'); if (NULL == port_colon) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("IPv6 address did contain ':' to separate port number\n")); return GNUNET_SYSERR; } if (']' != *(port_colon - 1)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("IPv6 address did contain ']' before ':' to separate port number\n")); return GNUNET_SYSERR; } ret = SSCANF (port_colon, ":%u", &port); if ( (1 != ret) || (port > 65535) ) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("IPv6 address did contain a valid port number after the last ':'\n")); return GNUNET_SYSERR; } *(port_colon-1) = '\0'; memset (r_buf, 0, sizeof (struct sockaddr_in6)); ret = inet_pton (AF_INET6, &zbuf[1], &r_buf->sin6_addr); if (ret <= 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Invalid IPv6 address `%s': %s\n"), &zbuf[1], STRERROR (errno)); return GNUNET_SYSERR; } r_buf->sin6_port = htons (port); r_buf->sin6_family = AF_INET6; #if HAVE_SOCKADDR_IN_SIN_LEN r_buf->sin6_len = (u_char) sizeof (struct sockaddr_in6); #endif return GNUNET_OK; } /** * Tries to convert 'zt_addr' string to an IPv4 address. * The string is expected to have the format "1.2.3.4:80". * * @param zt_addr 0-terminated string. May be mangled by the function. * @param addrlen length of zt_addr (not counting 0-terminator). * @param r_buf a buffer to fill. * @return GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which case * the contents of r_buf are undefined. */ int GNUNET_STRINGS_to_address_ipv4 (const char *zt_addr, uint16_t addrlen, struct sockaddr_in *r_buf) { unsigned int temps[4]; unsigned int port; unsigned int cnt; if (addrlen < 9) return GNUNET_SYSERR; cnt = SSCANF (zt_addr, "%u.%u.%u.%u:%u", &temps[0], &temps[1], &temps[2], &temps[3], &port); if (5 != cnt) return GNUNET_SYSERR; for (cnt = 0; cnt < 4; cnt++) if (temps[cnt] > 0xFF) return GNUNET_SYSERR; if (port > 65535) return GNUNET_SYSERR; r_buf->sin_family = AF_INET; r_buf->sin_port = htons (port); r_buf->sin_addr.s_addr = htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) + temps[3]); #if HAVE_SOCKADDR_IN_SIN_LEN r_buf->sin_len = (u_char) sizeof (struct sockaddr_in); #endif return GNUNET_OK; } /** * Tries to convert 'addr' string to an IP (v4 or v6) address. * Will automatically decide whether to treat 'addr' as v4 or v6 address. * * @param addr a string, may not be 0-terminated. * @param addrlen number of bytes in addr (if addr is 0-terminated, * 0-terminator should not be counted towards addrlen). * @param r_buf a buffer to fill. * @return GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which * case the contents of r_buf are undefined. */ int GNUNET_STRINGS_to_address_ip (const char *addr, uint16_t addrlen, struct sockaddr_storage *r_buf) { if (addr[0] == '[') return GNUNET_STRINGS_to_address_ipv6 (addr, addrlen, (struct sockaddr_in6 *) r_buf); return GNUNET_STRINGS_to_address_ipv4 (addr, addrlen, (struct sockaddr_in *) r_buf); } /* end of strings.c */ gnunet-0.9.3/src/util/program.c0000644000175000017500000002073311761753145013342 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/program.c * @brief standard code for GNUnet startup and shutdown * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_configuration_lib.h" #include "gnunet_crypto_lib.h" #include "gnunet_directories.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_resolver_service.h" #include "gnunet_scheduler_lib.h" #include #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) /** * Context for the command. */ struct CommandContext { /** * Argv argument. */ char *const *args; /** * Name of the configuration file used, can be NULL! */ char *cfgfile; /** * Main function to run. */ GNUNET_PROGRAM_Main task; /** * Closure for task. */ void *task_cls; /** * Configuration to use. */ const struct GNUNET_CONFIGURATION_Handle *cfg; }; int GNUNET_SPEEDUP_start_ (const struct GNUNET_CONFIGURATION_Handle *cfg); int GNUNET_SPEEDUP_stop_ (void); /** * Initial task called by the scheduler for each * program. Runs the program-specific main task. */ static void program_main (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct CommandContext *cc = cls; GNUNET_SPEEDUP_start_(cc->cfg); GNUNET_RESOLVER_connect (cc->cfg); cc->task (cc->task_cls, cc->args, cc->cfgfile, cc->cfg); } /** * Compare function for 'qsort' to sort command-line arguments by the * short option. * * @param a1 first command line option * @param a2 second command line option */ static int cmd_sorter (const void *a1, const void *a2) { const struct GNUNET_GETOPT_CommandLineOption *c1 = a1; const struct GNUNET_GETOPT_CommandLineOption *c2 = a2; if (toupper ((unsigned char) c1->shortName) > toupper ((unsigned char) c2->shortName)) return 1; if (toupper ((unsigned char) c1->shortName) < toupper ((unsigned char) c2->shortName)) return -1; if (c1->shortName > c2->shortName) return 1; if (c1->shortName < c2->shortName) return -1; return 0; } /** * Run a standard GNUnet command startup sequence (initialize loggers * and configuration, parse options). * * @param argc number of command line arguments * @param argv command line arguments * @param binaryName our expected name * @param binaryHelp help text for the program * @param options command line options * @param task main function to run * @param task_cls closure for task * @param run_without_scheduler GNUNET_NO start the scheduler, GNUNET_YES do not * start the scheduler just run the main task * @return GNUNET_SYSERR on error, GNUNET_OK on success */ int GNUNET_PROGRAM_run2 (int argc, char *const *argv, const char *binaryName, const char *binaryHelp, const struct GNUNET_GETOPT_CommandLineOption *options, GNUNET_PROGRAM_Main task, void *task_cls, int run_without_scheduler) { struct CommandContext cc; char *path; char *loglev; char *logfile; int ret; unsigned int cnt; unsigned long long skew_offset; unsigned long long skew_variance; long long clock_offset; struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_GETOPT_CommandLineOption defoptions[] = { GNUNET_GETOPT_OPTION_CFG_FILE (&cc.cfgfile), GNUNET_GETOPT_OPTION_HELP (binaryHelp), GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev), GNUNET_GETOPT_OPTION_LOGFILE (&logfile), GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION) }; struct GNUNET_GETOPT_CommandLineOption *allopts; const char *gargs; char *lpfx; char *spc; logfile = NULL; gargs = getenv ("GNUNET_ARGS"); if (gargs != NULL) { char **gargv; unsigned int gargc; int i; char *tok; char *cargs; gargv = NULL; gargc = 0; for (i = 0; i < argc; i++) GNUNET_array_append (gargv, gargc, GNUNET_strdup (argv[i])); cargs = GNUNET_strdup (gargs); tok = strtok (cargs, " "); while (NULL != tok) { GNUNET_array_append (gargv, gargc, GNUNET_strdup (tok)); tok = strtok (NULL, " "); } GNUNET_free (cargs); GNUNET_array_append (gargv, gargc, NULL); argv = (char *const *) gargv; argc = gargc - 1; } memset (&cc, 0, sizeof (cc)); loglev = NULL; cc.task = task; cc.task_cls = task_cls; cc.cfg = cfg = GNUNET_CONFIGURATION_create (); /* prepare */ #if ENABLE_NLS setlocale (LC_ALL, ""); path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR); if (path != NULL) { BINDTEXTDOMAIN ("GNUnet", path); GNUNET_free (path); } textdomain ("GNUnet"); #endif cnt = 0; while (options[cnt].name != NULL) cnt++; allopts = GNUNET_malloc ((cnt + 1) * sizeof (struct GNUNET_GETOPT_CommandLineOption) + sizeof (defoptions)); memcpy (allopts, defoptions, sizeof (defoptions)); memcpy (&allopts [sizeof (defoptions) / sizeof (struct GNUNET_GETOPT_CommandLineOption)], options, (cnt + 1) * sizeof (struct GNUNET_GETOPT_CommandLineOption)); cnt += sizeof (defoptions) / sizeof (struct GNUNET_GETOPT_CommandLineOption); qsort (allopts, cnt, sizeof (struct GNUNET_GETOPT_CommandLineOption), &cmd_sorter); loglev = NULL; cc.cfgfile = GNUNET_strdup (GNUNET_DEFAULT_USER_CONFIG_FILE); lpfx = GNUNET_strdup (binaryName); if (NULL != (spc = strstr (lpfx, " "))) *spc = '\0'; if ((-1 == (ret = GNUNET_GETOPT_run (binaryName, allopts, (unsigned int) argc, argv))) || (GNUNET_OK != GNUNET_log_setup (lpfx, loglev, logfile))) { GNUNET_CONFIGURATION_destroy (cfg); GNUNET_free_non_null (cc.cfgfile); GNUNET_free_non_null (loglev); GNUNET_free_non_null (logfile); GNUNET_free (allopts); GNUNET_free (lpfx); return GNUNET_SYSERR; } (void) GNUNET_CONFIGURATION_load (cfg, cc.cfgfile); GNUNET_free (allopts); GNUNET_free (lpfx); if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cc.cfg, "testing", "skew_offset", &skew_offset) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cc.cfg, "testing", "skew_variance", &skew_variance))) { clock_offset = skew_offset - skew_variance; GNUNET_TIME_set_offset (clock_offset); } /* run */ cc.args = &argv[ret]; if (GNUNET_NO == run_without_scheduler) { GNUNET_SCHEDULER_run (&program_main, &cc); } else { GNUNET_RESOLVER_connect (cc.cfg); cc.task (cc.task_cls, cc.args, cc.cfgfile, cc.cfg); } /* clean up */ GNUNET_SPEEDUP_stop_ (); GNUNET_CONFIGURATION_destroy (cfg); GNUNET_free_non_null (cc.cfgfile); GNUNET_free_non_null (loglev); GNUNET_free_non_null (logfile); return GNUNET_OK; } /** * Run a standard GNUnet command startup sequence (initialize loggers * and configuration, parse options). * * @param argc number of command line arguments * @param argv command line arguments * @param binaryName our expected name * @param binaryHelp help text for the program * @param options command line options * @param task main function to run * @param task_cls closure for task * @return GNUNET_SYSERR on error, GNUNET_OK on success */ int GNUNET_PROGRAM_run (int argc, char *const *argv, const char *binaryName, const char *binaryHelp, const struct GNUNET_GETOPT_CommandLineOption *options, GNUNET_PROGRAM_Main task, void *task_cls) { return GNUNET_PROGRAM_run2 (argc, argv, binaryName, binaryHelp, options, task, task_cls, GNUNET_NO); } /* end of program.c */ gnunet-0.9.3/src/util/test_server_with_client.c0000644000175000017500000001327511760502551016624 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_server_with_client.c * @brief tests for server.c and client.c, * specifically disconnect_notify, * client_get_address and receive_done (resume processing) */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_scheduler_lib.h" #include "gnunet_client_lib.h" #include "gnunet_server_lib.h" #include "gnunet_time_lib.h" #define VERBOSE GNUNET_NO #define PORT 22335 #define MY_TYPE 128 static struct GNUNET_SERVER_Handle *server; static struct GNUNET_CLIENT_Connection *client; static struct GNUNET_CONFIGURATION_Handle *cfg; static int ok; static void send_done (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_SERVER_Client *argclient = cls; GNUNET_assert (ok == 3); ok++; GNUNET_SERVER_receive_done (argclient, GNUNET_OK); } static void recv_cb (void *cls, struct GNUNET_SERVER_Client *argclient, const struct GNUNET_MessageHeader *message) { void *addr; size_t addrlen; struct sockaddr_in sa; struct sockaddr_in *have; GNUNET_assert (GNUNET_OK == GNUNET_SERVER_client_get_address (argclient, &addr, &addrlen)); GNUNET_assert (addrlen == sizeof (struct sockaddr_in)); have = addr; memset (&sa, 0, sizeof (sa)); #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = sizeof (sa); #endif sa.sin_family = AF_INET; sa.sin_port = have->sin_port; sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK); GNUNET_assert (0 == memcmp (&sa, addr, addrlen)); GNUNET_free (addr); switch (ok) { case 2: ok++; GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 50), &send_done, argclient); break; case 4: ok++; GNUNET_CLIENT_disconnect (client); GNUNET_SERVER_receive_done (argclient, GNUNET_OK); break; default: GNUNET_assert (0); } } static void clean_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_SERVER_destroy (server); server = NULL; GNUNET_CONFIGURATION_destroy (cfg); cfg = NULL; } /** * Functions with this signature are called whenever a client * is disconnected on the network level. * * @param cls closure * @param client identification of the client */ static void notify_disconnect (void *cls, struct GNUNET_SERVER_Client *client) { if (client == NULL) return; GNUNET_assert (ok == 5); ok = 0; GNUNET_SCHEDULER_add_now (&clean_up, NULL); } static size_t notify_ready (void *cls, size_t size, void *buf) { struct GNUNET_MessageHeader *msg; GNUNET_assert (size >= 256); GNUNET_assert (1 == ok); ok++; msg = buf; msg->type = htons (MY_TYPE); msg->size = htons (sizeof (struct GNUNET_MessageHeader)); msg++; msg->type = htons (MY_TYPE); msg->size = htons (sizeof (struct GNUNET_MessageHeader)); return 2 * sizeof (struct GNUNET_MessageHeader); } static struct GNUNET_SERVER_MessageHandler handlers[] = { {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)}, {NULL, NULL, 0, 0} }; static void task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct sockaddr_in sa; struct sockaddr *sap[2]; socklen_t slens[2]; sap[0] = (struct sockaddr *) &sa; slens[0] = sizeof (sa); sap[1] = NULL; slens[1] = 0; memset (&sa, 0, sizeof (sa)); #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = sizeof (sa); #endif sa.sin_family = AF_INET; sa.sin_port = htons (PORT); server = GNUNET_SERVER_create (NULL, NULL, sap, slens, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250), GNUNET_NO); GNUNET_assert (server != NULL); handlers[0].callback_cls = cls; GNUNET_SERVER_add_handlers (server, handlers); GNUNET_SERVER_disconnect_notify (server, ¬ify_disconnect, cls); cfg = GNUNET_CONFIGURATION_create (); GNUNET_CONFIGURATION_set_value_number (cfg, "test", "PORT", PORT); GNUNET_CONFIGURATION_set_value_string (cfg, "test", "HOSTNAME", "localhost"); GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", "localhost"); client = GNUNET_CLIENT_connect ("test", cfg); GNUNET_assert (client != NULL); GNUNET_CLIENT_notify_transmit_ready (client, 256, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250), GNUNET_NO, ¬ify_ready, NULL); } /** * Main method, starts scheduler with task1, * checks that "ok" is correct at the end. */ static int check () { ok = 1; GNUNET_SCHEDULER_run (&task, NULL); return ok; } int main (int argc, char *argv[]) { int ret = 0; GNUNET_log_setup ("test_server_with_client", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret += check (); return ret; } /* end of test_server_with_client.c */ gnunet-0.9.3/src/util/test_time.c0000644000175000017500000002146011760516473013666 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_time.c * @brief testcase for time.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_time_lib.h" #define VERBOSE GNUNET_NO static int check () { struct GNUNET_TIME_Absolute now; struct GNUNET_TIME_AbsoluteNBO nown; struct GNUNET_TIME_Absolute future; struct GNUNET_TIME_Absolute past; struct GNUNET_TIME_Absolute last; struct GNUNET_TIME_Absolute forever; struct GNUNET_TIME_Absolute zero; struct GNUNET_TIME_Relative rel; struct GNUNET_TIME_Relative relForever; struct GNUNET_TIME_Relative relUnit; struct GNUNET_TIME_RelativeNBO reln; unsigned int i; forever = GNUNET_TIME_UNIT_FOREVER_ABS; relForever = GNUNET_TIME_UNIT_FOREVER_REL; relUnit = GNUNET_TIME_UNIT_MILLISECONDS; zero.abs_value = 0; last = now = GNUNET_TIME_absolute_get (); while (now.abs_value == last.abs_value) now = GNUNET_TIME_absolute_get (); GNUNET_assert (now.abs_value > last.abs_value); /* test overflow checking in multiply */ rel = GNUNET_TIME_UNIT_SECONDS; GNUNET_log_skip (1, GNUNET_NO); for (i = 0; i < 55; i++) rel = GNUNET_TIME_relative_multiply (rel, 2); GNUNET_log_skip (0, GNUNET_NO); GNUNET_assert (rel.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value); /*check zero */ rel.rel_value = (UINT64_MAX) - 1024; GNUNET_assert (GNUNET_TIME_UNIT_ZERO.rel_value == GNUNET_TIME_relative_multiply (rel, 0).rel_value); /* test infinity-check for relative to absolute */ GNUNET_log_skip (1, GNUNET_NO); last = GNUNET_TIME_relative_to_absolute (rel); GNUNET_assert (last.abs_value == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value); GNUNET_log_skip (0, GNUNET_YES); /*check relative to absolute */ rel.rel_value = 0; GNUNET_assert (GNUNET_TIME_absolute_get ().abs_value == GNUNET_TIME_relative_to_absolute (rel).abs_value); /*check forever */ rel.rel_value = UINT64_MAX; GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value == GNUNET_TIME_relative_to_absolute (rel).abs_value); /* check overflow for r2a */ rel.rel_value = (UINT64_MAX) - 1024; GNUNET_log_skip (1, GNUNET_NO); last = GNUNET_TIME_relative_to_absolute (rel); GNUNET_log_skip (0, GNUNET_NO); GNUNET_assert (last.abs_value == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value); /* check overflow for relative add */ GNUNET_log_skip (1, GNUNET_NO); rel = GNUNET_TIME_relative_add (rel, rel); GNUNET_log_skip (0, GNUNET_NO); GNUNET_assert (rel.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value); GNUNET_log_skip (1, GNUNET_NO); rel = GNUNET_TIME_relative_add (relForever, relForever); GNUNET_log_skip (0, GNUNET_NO); GNUNET_assert (rel.rel_value == relForever.rel_value); GNUNET_log_skip (1, GNUNET_NO); rel = GNUNET_TIME_relative_add (relUnit, relUnit); GNUNET_assert (rel.rel_value == 2 * relUnit.rel_value); /* check relation check in get_duration */ future.abs_value = now.abs_value + 1000000; GNUNET_assert (GNUNET_TIME_absolute_get_difference (now, future).rel_value == 1000000); GNUNET_assert (GNUNET_TIME_absolute_get_difference (future, now).rel_value == 0); GNUNET_assert (GNUNET_TIME_absolute_get_difference (zero, forever).rel_value == forever.abs_value); past.abs_value = now.abs_value - 1000000; rel = GNUNET_TIME_absolute_get_duration (future); GNUNET_assert (rel.rel_value == 0); rel = GNUNET_TIME_absolute_get_duration (past); GNUNET_assert (rel.rel_value >= 1000000); /* check get remaining */ rel = GNUNET_TIME_absolute_get_remaining (now); GNUNET_assert (rel.rel_value == 0); rel = GNUNET_TIME_absolute_get_remaining (past); GNUNET_assert (rel.rel_value == 0); rel = GNUNET_TIME_absolute_get_remaining (future); GNUNET_assert (rel.rel_value > 0); GNUNET_assert (rel.rel_value <= 1000000); forever = GNUNET_TIME_UNIT_FOREVER_ABS; GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value == GNUNET_TIME_absolute_get_remaining (forever).rel_value); /* check endianess */ reln = GNUNET_TIME_relative_hton (rel); GNUNET_assert (rel.rel_value == GNUNET_TIME_relative_ntoh (reln).rel_value); nown = GNUNET_TIME_absolute_hton (now); GNUNET_assert (now.abs_value == GNUNET_TIME_absolute_ntoh (nown).abs_value); /* check absolute addition */ future = GNUNET_TIME_absolute_add (now, GNUNET_TIME_UNIT_SECONDS); GNUNET_assert (future.abs_value == now.abs_value + 1000); future = GNUNET_TIME_absolute_add (forever, GNUNET_TIME_UNIT_ZERO); GNUNET_assert (future.abs_value == forever.abs_value); rel.rel_value = (UINT64_MAX) - 1024; now.abs_value = rel.rel_value; future = GNUNET_TIME_absolute_add (now, rel); GNUNET_assert (future.abs_value == forever.abs_value); /* check zero */ future = GNUNET_TIME_absolute_add (now, GNUNET_TIME_UNIT_ZERO); GNUNET_assert (future.abs_value == now.abs_value); GNUNET_assert (forever.abs_value == GNUNET_TIME_absolute_subtract (forever, GNUNET_TIME_UNIT_MINUTES).abs_value); /*check absolute subtract */ now.abs_value = 50000; rel.rel_value = 100000; GNUNET_assert (GNUNET_TIME_UNIT_ZERO_ABS.abs_value == (GNUNET_TIME_absolute_subtract (now, rel)).abs_value); rel.rel_value = 10000; GNUNET_assert (40000 == (GNUNET_TIME_absolute_subtract (now, rel)).abs_value); /*check relative divide */ GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value == (GNUNET_TIME_relative_divide (rel, 0)).rel_value); rel = GNUNET_TIME_UNIT_FOREVER_REL; GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value == (GNUNET_TIME_relative_divide (rel, 2)).rel_value); rel = GNUNET_TIME_relative_divide (relUnit, 2); GNUNET_assert (rel.rel_value == relUnit.rel_value / 2); /* check Return absolute time of 0ms */ zero = GNUNET_TIME_UNIT_ZERO_ABS; /* check GNUNET_TIME_calculate_eta */ last.abs_value = GNUNET_TIME_absolute_get ().abs_value - 1024; forever = GNUNET_TIME_UNIT_FOREVER_ABS; forever.abs_value = forever.abs_value - 1024; GNUNET_assert (GNUNET_TIME_UNIT_ZERO_ABS.abs_value == GNUNET_TIME_calculate_eta (forever, 50000, 100000).rel_value); /* check zero */ GNUNET_log_skip (1, GNUNET_NO); GNUNET_assert (GNUNET_TIME_UNIT_ZERO.rel_value == (GNUNET_TIME_calculate_eta (last, 60000, 50000)).rel_value); GNUNET_log_skip (0, GNUNET_YES); /*check forever */ GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value == (GNUNET_TIME_calculate_eta (last, 0, 50000)).rel_value); /*check relative subtract */ now = GNUNET_TIME_absolute_get (); rel.rel_value = now.abs_value; relForever.rel_value = rel.rel_value + 1024; GNUNET_assert (1024 == GNUNET_TIME_relative_subtract (relForever, rel).rel_value); /*check zero */ GNUNET_assert (GNUNET_TIME_UNIT_ZERO.rel_value == GNUNET_TIME_relative_subtract (rel, relForever).rel_value); /*check forever */ rel.rel_value = UINT64_MAX; GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value == GNUNET_TIME_relative_subtract (rel, relForever).rel_value); /*check GNUNET_TIME_relative_min */ now = GNUNET_TIME_absolute_get (); rel.rel_value = now.abs_value; relForever.rel_value = rel.rel_value - 1024; GNUNET_assert (relForever.rel_value == GNUNET_TIME_relative_min (rel, relForever).rel_value); /*check GNUNET_TIME_relative_max */ GNUNET_assert (rel.rel_value == GNUNET_TIME_relative_max (rel, relForever).rel_value); /*check GNUNET_TIME_absolute_min */ now = GNUNET_TIME_absolute_get (); last.abs_value = now.abs_value - 1024; GNUNET_assert (last.abs_value == GNUNET_TIME_absolute_min (now, last).abs_value); /*check GNUNET_TIME_absolute_max */ GNUNET_assert (now.abs_value == GNUNET_TIME_absolute_max (now, last).abs_value); return 0; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-time", "WARNING", NULL); ret = check (); return ret; } /* end of test_time.c */ gnunet-0.9.3/src/util/server.c0000644000175000017500000013364111762516573013207 00000000000000/* This file is part of GNUnet. (C) 2009, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/server.c * @brief library for building GNUnet network servers * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_util_lib.h" #include "gnunet_protocols.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) /** * List of arrays of message handlers. */ struct HandlerList { /** * This is a linked list. */ struct HandlerList *next; /** * NULL-terminated array of handlers. */ const struct GNUNET_SERVER_MessageHandler *handlers; }; /** * List of arrays of message handlers. */ struct NotifyList { /** * This is a doubly linked list. */ struct NotifyList *next; /** * This is a doubly linked list. */ struct NotifyList *prev; /** * Function to call. */ GNUNET_SERVER_DisconnectCallback callback; /** * Closure for callback. */ void *callback_cls; }; /** * @brief handle for a server */ struct GNUNET_SERVER_Handle { /** * List of handlers for incoming messages. */ struct HandlerList *handlers; /** * Head of list of our current clients. */ struct GNUNET_SERVER_Client *clients_head; /** * Head of list of our current clients. */ struct GNUNET_SERVER_Client *clients_tail; /** * Head of linked list of functions to call on disconnects by clients. */ struct NotifyList *disconnect_notify_list_head; /** * Tail of linked list of functions to call on disconnects by clients. */ struct NotifyList *disconnect_notify_list_tail; /** * Function to call for access control. */ GNUNET_CONNECTION_AccessCheck access; /** * Closure for access. */ void *access_cls; /** * NULL-terminated array of sockets used to listen for new * connections. */ struct GNUNET_NETWORK_Handle **listen_sockets; /** * After how long should an idle connection time * out (on write). */ struct GNUNET_TIME_Relative idle_timeout; /** * Task scheduled to do the listening. */ GNUNET_SCHEDULER_TaskIdentifier listen_task; /** * Alternative function to create a MST instance. */ GNUNET_SERVER_MstCreateCallback mst_create; /** * Alternative function to destroy a MST instance. */ GNUNET_SERVER_MstDestroyCallback mst_destroy; /** * Alternative function to give data to a MST instance. */ GNUNET_SERVER_MstReceiveCallback mst_receive; /** * Closure for 'mst_'-callbacks. */ void *mst_cls; /** * Do we ignore messages of types that we do not understand or do we * require that a handler is found (and if not kill the connection)? */ int require_found; /** * Set to GNUNET_YES once we are in 'soft' shutdown where we wait for * all non-monitor clients to disconnect before we call * GNUNET_SERVER_destroy. See 'test_monitor_clients'. Set to * GNUNET_SYSERR once the final destroy task has been scheduled * (we cannot run it in the same task). */ int in_soft_shutdown; }; /** * Handle server returns for aborting transmission to a client. */ struct GNUNET_SERVER_TransmitHandle { /** * Function to call to get the message. */ GNUNET_CONNECTION_TransmitReadyNotify callback; /** * Closure for 'callback' */ void *callback_cls; /** * Active connection transmission handle. */ struct GNUNET_CONNECTION_TransmitHandle *cth; }; /** * @brief handle for a client of the server */ struct GNUNET_SERVER_Client { /** * This is a doubly linked list. */ struct GNUNET_SERVER_Client *next; /** * This is a doubly linked list. */ struct GNUNET_SERVER_Client *prev; /** * Processing of incoming data. */ void *mst; /** * Server that this client belongs to. */ struct GNUNET_SERVER_Handle *server; /** * Client closure for callbacks. */ struct GNUNET_CONNECTION_Handle *connection; /** * ID of task used to restart processing. */ GNUNET_SCHEDULER_TaskIdentifier restart_task; /** * Task that warns about missing calls to 'GNUNET_SERVER_receive_done'. */ GNUNET_SCHEDULER_TaskIdentifier warn_task; /** * Time when the warn task was started. */ struct GNUNET_TIME_Absolute warn_start; /** * Last activity on this socket (used to time it out * if reference_count == 0). */ struct GNUNET_TIME_Absolute last_activity; /** * Transmission handle we return for this client from * GNUNET_SERVER_notify_transmit_ready. */ struct GNUNET_SERVER_TransmitHandle th; /** * After how long should an idle connection time * out (on write). */ struct GNUNET_TIME_Relative idle_timeout; /** * Number of external entities with a reference to * this client object. */ unsigned int reference_count; /** * Was processing if incoming messages suspended while * we were still processing data already received? * This is a counter saying how often processing was * suspended (once per handler invoked). */ unsigned int suspended; /** * Are we currently in the "process_client_buffer" function (and * will hence restart the receive job on exit if suspended == 0 once * we are done?). If this is set, then "receive_done" will * essentially only decrement suspended; if this is not set, then * "receive_done" may need to restart the receive process (either * from the side-buffer or via select/recv). */ int in_process_client_buffer; /** * We're about to close down this client. */ int shutdown_now; /** * Are we currently trying to receive? (YES if we are, NO if we are not, * SYSERR if data is already available in MST). */ int receive_pending; /** * Finish pending write when disconnecting? */ int finish_pending_write; /** * Persist the file handle for this client no matter what happens, * force the OS to close once the process actually dies. Should only * be used in special cases! */ int persist; /** * Is this client a 'monitor' client that should not be counted * when deciding on destroying the server during soft shutdown? * (see also GNUNET_SERVICE_start) */ int is_monitor; /** * Type of last message processed (for warn_no_receive_done). */ uint16_t warn_type; }; /** * Scheduler says our listen socket is ready. Process it! * * @param cls handle to our server for which we are processing the listen * socket * @param tc reason why we are running right now */ static void process_listen_socket (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Add a listen task with the scheduler for this server. * * @param server handle to our server for which we are adding the listen * socket */ static void schedule_listen_task (struct GNUNET_SERVER_Handle *server) { struct GNUNET_NETWORK_FDSet *r; unsigned int i; if (NULL == server->listen_sockets[0]) return; /* nothing to do, no listen sockets! */ if (NULL == server->listen_sockets[1]) { /* simplified method: no fd set needed; this is then much simpler and much more efficient */ server->listen_task = GNUNET_SCHEDULER_add_read_net_with_priority (GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_SCHEDULER_PRIORITY_HIGH, server->listen_sockets[0], &process_listen_socket, server); return; } r = GNUNET_NETWORK_fdset_create (); i = 0; while (NULL != server->listen_sockets[i]) GNUNET_NETWORK_fdset_set (r, server->listen_sockets[i++]); server->listen_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, GNUNET_TIME_UNIT_FOREVER_REL, r, NULL, &process_listen_socket, server); GNUNET_NETWORK_fdset_destroy (r); } /** * Scheduler says our listen socket is ready. Process it! * * @param cls handle to our server for which we are processing the listen * socket * @param tc reason why we are running right now */ static void process_listen_socket (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_SERVER_Handle *server = cls; struct GNUNET_CONNECTION_Handle *sock; struct GNUNET_SERVER_Client *client; unsigned int i; server->listen_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) { /* ignore shutdown, someone else will take care of it! */ schedule_listen_task (server); return; } i = 0; while (NULL != server->listen_sockets[i]) { if (GNUNET_NETWORK_fdset_isset (tc->read_ready, server->listen_sockets[i])) { sock = GNUNET_CONNECTION_create_from_accept (server->access, server->access_cls, server->listen_sockets[i]); if (NULL != sock) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Server accepted incoming connection.\n"); client = GNUNET_SERVER_connect_socket (server, sock); /* decrement reference count, we don't keep "client" alive */ GNUNET_SERVER_client_drop (client); } } i++; } /* listen for more! */ schedule_listen_task (server); } /** * Create and initialize a listen socket for the server. * * @param serverAddr address to listen on * @param socklen length of address * @return NULL on error, otherwise the listen socket */ static struct GNUNET_NETWORK_Handle * open_listen_socket (const struct sockaddr *serverAddr, socklen_t socklen) { static int on = 1; struct GNUNET_NETWORK_Handle *sock; uint16_t port; int eno; switch (serverAddr->sa_family) { case AF_INET: port = ntohs (((const struct sockaddr_in *) serverAddr)->sin_port); break; case AF_INET6: port = ntohs (((const struct sockaddr_in6 *) serverAddr)->sin6_port); break; case AF_UNIX: port = 0; break; default: GNUNET_break (0); port = 0; break; } sock = GNUNET_NETWORK_socket_create (serverAddr->sa_family, SOCK_STREAM, 0); if (NULL == sock) { LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket"); errno = 0; return NULL; } if (0 != port) { if (GNUNET_NETWORK_socket_setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); #ifdef IPV6_V6ONLY if ((AF_INET6 == serverAddr->sa_family) && (GNUNET_NETWORK_socket_setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK)) LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); #endif } /* bind the socket */ if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, serverAddr, socklen)) { eno = errno; if (EADDRINUSE != errno) { /* we don't log 'EADDRINUSE' here since an IPv4 bind may * fail if we already took the port on IPv6; if both IPv4 and * IPv6 binds fail, then our caller will log using the * errno preserved in 'eno' */ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "bind"); if (0 != port) LOG (GNUNET_ERROR_TYPE_ERROR, _("`%s' failed for port %d (%s).\n"), "bind", port, (AF_INET == serverAddr->sa_family) ? "IPv4" : "IPv6"); eno = 0; } else { if (0 != port) LOG (GNUNET_ERROR_TYPE_WARNING, _("`%s' failed for port %d (%s): address already in use\n"), "bind", port, (AF_INET == serverAddr->sa_family) ? "IPv4" : "IPv6"); else if (AF_UNIX == serverAddr->sa_family) LOG (GNUNET_ERROR_TYPE_WARNING, _("`%s' failed for `%s': address already in use\n"), "bind", ((const struct sockaddr_un *) serverAddr)->sun_path); } GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); errno = eno; return NULL; } if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5)) { LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "listen"); GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); errno = 0; return NULL; } if (0 != port) LOG (GNUNET_ERROR_TYPE_DEBUG, "Server starts to listen on port %u.\n", port); return sock; } /** * Create a new server. * * @param access function for access control * @param access_cls closure for access * @param lsocks NULL-terminated array of listen sockets * @param idle_timeout after how long should we timeout idle connections? * @param require_found if YES, connections sending messages of unknown type * will be closed * @return handle for the new server, NULL on error * (typically, "port" already in use) */ struct GNUNET_SERVER_Handle * GNUNET_SERVER_create_with_sockets (GNUNET_CONNECTION_AccessCheck access, void *access_cls, struct GNUNET_NETWORK_Handle **lsocks, struct GNUNET_TIME_Relative idle_timeout, int require_found) { struct GNUNET_SERVER_Handle *server; server = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Handle)); server->idle_timeout = idle_timeout; server->listen_sockets = lsocks; server->access = access; server->access_cls = access_cls; server->require_found = require_found; if (NULL != lsocks) schedule_listen_task (server); return server; } /** * Create a new server. * * @param access function for access control * @param access_cls closure for access * @param serverAddr address to listen on (including port), NULL terminated array * @param socklen length of serverAddr * @param idle_timeout after how long should we timeout idle connections? * @param require_found if YES, connections sending messages of unknown type * will be closed * @return handle for the new server, NULL on error * (typically, "port" already in use) */ struct GNUNET_SERVER_Handle * GNUNET_SERVER_create (GNUNET_CONNECTION_AccessCheck access, void *access_cls, struct sockaddr *const *serverAddr, const socklen_t * socklen, struct GNUNET_TIME_Relative idle_timeout, int require_found) { struct GNUNET_NETWORK_Handle **lsocks; unsigned int i; unsigned int j; unsigned int k; int seen; i = 0; while (NULL != serverAddr[i]) i++; if (i > 0) { lsocks = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (i + 1)); i = 0; j = 0; while (NULL != serverAddr[i]) { seen = 0; for (k=0;kis_monitor = GNUNET_YES; } /** * Helper function for 'test_monitor_clients' to trigger * 'GNUNET_SERVER_destroy' after the stack has unwound. * * @param cls the 'struct GNUNET_SERVER_Handle' to destroy * @param tc unused */ static void do_destroy (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_SERVER_Handle *server = cls; GNUNET_SERVER_destroy (server); } /** * Check if only 'monitor' clients are left. If so, destroy the * server completely. * * @param server server to test for full shutdown */ static void test_monitor_clients (struct GNUNET_SERVER_Handle *server) { struct GNUNET_SERVER_Client *client; if (GNUNET_YES != server->in_soft_shutdown) return; for (client = server->clients_head; NULL != client; client = client->next) if (GNUNET_NO == client->is_monitor) return; /* not done yet */ server->in_soft_shutdown = GNUNET_SYSERR; GNUNET_SCHEDULER_add_continuation (&do_destroy, server, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } /** * Stop the listen socket and get ready to shutdown the server * once only 'monitor' clients are left. * * @param server server to stop listening on */ void GNUNET_SERVER_stop_listening (struct GNUNET_SERVER_Handle *server) { unsigned int i; LOG (GNUNET_ERROR_TYPE_DEBUG, "Server in soft shutdown\n"); if (GNUNET_SCHEDULER_NO_TASK != server->listen_task) { GNUNET_SCHEDULER_cancel (server->listen_task); server->listen_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != server->listen_sockets) { i = 0; while (NULL != server->listen_sockets[i]) GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (server->listen_sockets[i++])); GNUNET_free (server->listen_sockets); server->listen_sockets = NULL; } if (GNUNET_NO == server->in_soft_shutdown) server->in_soft_shutdown = GNUNET_YES; test_monitor_clients (server); } /** * Free resources held by this server. * * @param server server to destroy */ void GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server) { struct HandlerList *hpos; struct NotifyList *npos; unsigned int i; LOG (GNUNET_ERROR_TYPE_DEBUG, "Server shutting down.\n"); if (GNUNET_SCHEDULER_NO_TASK != server->listen_task) { GNUNET_SCHEDULER_cancel (server->listen_task); server->listen_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != server->listen_sockets) { i = 0; while (NULL != server->listen_sockets[i]) GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (server->listen_sockets[i++])); GNUNET_free (server->listen_sockets); server->listen_sockets = NULL; } while (NULL != server->clients_head) GNUNET_SERVER_client_disconnect (server->clients_head); while (NULL != (hpos = server->handlers)) { server->handlers = hpos->next; GNUNET_free (hpos); } while (NULL != (npos = server->disconnect_notify_list_head)) { npos->callback (npos->callback_cls, NULL); GNUNET_CONTAINER_DLL_remove (server->disconnect_notify_list_head, server->disconnect_notify_list_tail, npos); GNUNET_free (npos); } GNUNET_free (server); } /** * Add additional handlers to an existing server. * * @param server the server to add handlers to * @param handlers array of message handlers for * incoming messages; the last entry must * have "NULL" for the "callback"; multiple * entries for the same type are allowed, * they will be called in order of occurence. * These handlers can be removed later; * the handlers array must exist until removed * (or server is destroyed). */ void GNUNET_SERVER_add_handlers (struct GNUNET_SERVER_Handle *server, const struct GNUNET_SERVER_MessageHandler *handlers) { struct HandlerList *p; p = GNUNET_malloc (sizeof (struct HandlerList)); p->handlers = handlers; p->next = server->handlers; server->handlers = p; } /** * Change functions used by the server to tokenize the message stream. * (very rarely used). * * @param server server to modify * @param create new tokenizer initialization function * @param destroy new tokenizer destruction function * @param receive new tokenizer receive function * @param cls closure for 'create', 'receive', 'destroy' */ void GNUNET_SERVER_set_callbacks (struct GNUNET_SERVER_Handle *server, GNUNET_SERVER_MstCreateCallback create, GNUNET_SERVER_MstDestroyCallback destroy, GNUNET_SERVER_MstReceiveCallback receive, void *cls) { server->mst_create = create; server->mst_destroy = destroy; server->mst_receive = receive; server->mst_cls = cls; } /** * Task run to warn about missing calls to 'GNUNET_SERVER_receive_done'. * * @param cls our 'struct GNUNET_SERVER_Client*' to process more requests from * @param tc scheduler context (unused) */ static void warn_no_receive_done (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_SERVER_Client *client = cls; GNUNET_break (0 != client->warn_type); /* type should never be 0 here, as we don't use 0 */ client->warn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &warn_no_receive_done, client); if (0 == (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) LOG (GNUNET_ERROR_TYPE_WARNING, _ ("Processing code for message of type %u did not call GNUNET_SERVER_receive_done after %llums\n"), (unsigned int) client->warn_type, (unsigned long long) GNUNET_TIME_absolute_get_duration (client->warn_start).rel_value); } /** * Disable the warning the server issues if a message is not acknowledged * in a timely fashion. Use this call if a client is intentionally delayed * for a while. Only applies to the current message. * * @param client client for which to disable the warning */ void GNUNET_SERVER_disable_receive_done_warning (struct GNUNET_SERVER_Client *client) { if (GNUNET_SCHEDULER_NO_TASK != client->warn_task) { GNUNET_SCHEDULER_cancel (client->warn_task); client->warn_task = GNUNET_SCHEDULER_NO_TASK; } } /** * Inject a message into the server, pretend it came * from the specified client. Delivery of the message * will happen instantly (if a handler is installed; * otherwise the call does nothing). * * @param server the server receiving the message * @param sender the "pretended" sender of the message * can be NULL! * @param message message to transmit * @return GNUNET_OK if the message was OK and the * connection can stay open * GNUNET_SYSERR if the connection to the * client should be shut down */ int GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server, struct GNUNET_SERVER_Client *sender, const struct GNUNET_MessageHeader *message) { struct HandlerList *pos; const struct GNUNET_SERVER_MessageHandler *mh; unsigned int i; uint16_t type; uint16_t size; int found; type = ntohs (message->type); size = ntohs (message->size); LOG (GNUNET_ERROR_TYPE_DEBUG, "Server schedules transmission of %u-byte message of type %u to client.\n", size, type); found = GNUNET_NO; for (pos = server->handlers; NULL != pos; pos = pos->next) { i = 0; while (pos->handlers[i].callback != NULL) { mh = &pos->handlers[i]; if ((mh->type == type) || (mh->type == GNUNET_MESSAGE_TYPE_ALL)) { if ((0 != mh->expected_size) && (mh->expected_size != size)) { #if GNUNET8_NETWORK_IS_DEAD LOG (GNUNET_ERROR_TYPE_WARNING, "Expected %u bytes for message of type %u, got %u\n", mh->expected_size, mh->type, size); GNUNET_break_op (0); #endif return GNUNET_SYSERR; } if (NULL != sender) { if ( (0 == sender->suspended) && (GNUNET_SCHEDULER_NO_TASK == sender->warn_task) ) { GNUNET_break (0 != type); /* type should never be 0 here, as we don't use 0 */ sender->warn_start = GNUNET_TIME_absolute_get (); sender->warn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &warn_no_receive_done, sender); sender->warn_type = type; } sender->suspended++; } mh->callback (mh->callback_cls, sender, message); found = GNUNET_YES; } i++; } } if (GNUNET_NO == found) { LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "Received message of unknown type %d\n", type); if (GNUNET_YES == server->require_found) return GNUNET_SYSERR; } return GNUNET_OK; } /** * We are receiving an incoming message. Process it. * * @param cls our closure (handle for the client) * @param buf buffer with data received from network * @param available number of bytes available in buf * @param addr address of the sender * @param addrlen length of addr * @param errCode code indicating errors receiving, 0 for success */ static void process_incoming (void *cls, const void *buf, size_t available, const struct sockaddr *addr, socklen_t addrlen, int errCode); /** * Process messages from the client's message tokenizer until either * the tokenizer is empty (and then schedule receiving more), or * until some handler is not immediately done (then wait for restart_processing) * or shutdown. * * @param client the client to process, RC must have already been increased * using GNUNET_SERVER_client_keep and will be decreased by one in this * function * @param ret GNUNET_NO to start processing from the buffer, * GNUNET_OK if the mst buffer is drained and we should instantly go back to receiving * GNUNET_SYSERR if we should instantly abort due to error in a previous step */ static void process_mst (struct GNUNET_SERVER_Client *client, int ret) { while ((GNUNET_SYSERR != ret) && (NULL != client->server) && (GNUNET_YES != client->shutdown_now) && (0 == client->suspended)) { if (GNUNET_OK == ret) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Server re-enters receive loop, timeout: %llu.\n", client->idle_timeout.rel_value); client->receive_pending = GNUNET_YES; GNUNET_CONNECTION_receive (client->connection, GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, client->idle_timeout, &process_incoming, client); break; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Server processes additional messages instantly.\n"); if (NULL != client->server->mst_receive) ret = client->server->mst_receive (client->server->mst_cls, client->mst, client, NULL, 0, GNUNET_NO, GNUNET_YES); else ret = GNUNET_SERVER_mst_receive (client->mst, client, NULL, 0, GNUNET_NO, GNUNET_YES); } LOG (GNUNET_ERROR_TYPE_DEBUG, "Server leaves instant processing loop: ret = %d, server = %p, shutdown = %d, suspended = %u\n", ret, client->server, client->shutdown_now, client->suspended); if (GNUNET_NO == ret) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Server has more data pending but is suspended.\n"); client->receive_pending = GNUNET_SYSERR; /* data pending */ } if ((GNUNET_SYSERR == ret) || (GNUNET_YES == client->shutdown_now)) GNUNET_SERVER_client_disconnect (client); } /** * We are receiving an incoming message. Process it. * * @param cls our closure (handle for the client) * @param buf buffer with data received from network * @param available number of bytes available in buf * @param addr address of the sender * @param addrlen length of addr * @param errCode code indicating errors receiving, 0 for success */ static void process_incoming (void *cls, const void *buf, size_t available, const struct sockaddr *addr, socklen_t addrlen, int errCode) { struct GNUNET_SERVER_Client *client = cls; struct GNUNET_SERVER_Handle *server = client->server; struct GNUNET_TIME_Absolute end; struct GNUNET_TIME_Absolute now; int ret; GNUNET_assert (GNUNET_YES == client->receive_pending); client->receive_pending = GNUNET_NO; now = GNUNET_TIME_absolute_get (); end = GNUNET_TIME_absolute_add (client->last_activity, client->idle_timeout); if ((NULL == buf) && (0 == available) && (NULL == addr) && (0 == errCode) && (GNUNET_YES != client->shutdown_now) && (NULL != server) && (GNUNET_YES == GNUNET_CONNECTION_check (client->connection)) && (end.abs_value > now.abs_value)) { /* wait longer, timeout changed (i.e. due to us sending) */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Receive time out, but no disconnect due to sending (%p)\n", GNUNET_a2s (addr, addrlen)); client->receive_pending = GNUNET_YES; GNUNET_CONNECTION_receive (client->connection, GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, GNUNET_TIME_absolute_get_remaining (end), &process_incoming, client); return; } if ((NULL == buf) || (0 == available) || (0 != errCode) || (NULL == server) || (GNUNET_YES == client->shutdown_now) || (GNUNET_YES != GNUNET_CONNECTION_check (client->connection))) { /* other side closed connection, error connecting, etc. */ GNUNET_SERVER_client_disconnect (client); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Server receives %u bytes from `%s'.\n", (unsigned int) available, GNUNET_a2s (addr, addrlen)); GNUNET_SERVER_client_keep (client); client->last_activity = now; if (NULL != server->mst_receive) ret = client->server->mst_receive (client->server->mst_cls, client->mst, client, buf, available, GNUNET_NO, GNUNET_YES); else if (NULL != client->mst) { ret = GNUNET_SERVER_mst_receive (client->mst, client, buf, available, GNUNET_NO, GNUNET_YES); } else { GNUNET_break (0); return; } process_mst (client, ret); GNUNET_SERVER_client_drop (client); } /** * Task run to start again receiving from the network * and process requests. * * @param cls our 'struct GNUNET_SERVER_Client*' to process more requests from * @param tc scheduler context (unused) */ static void restart_processing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_SERVER_Client *client = cls; GNUNET_assert (GNUNET_YES != client->shutdown_now); client->restart_task = GNUNET_SCHEDULER_NO_TASK; if (GNUNET_NO == client->receive_pending) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Server begins to read again from client.\n"); client->receive_pending = GNUNET_YES; GNUNET_CONNECTION_receive (client->connection, GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, client->idle_timeout, &process_incoming, client); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Server continues processing messages still in the buffer.\n"); GNUNET_SERVER_client_keep (client); client->receive_pending = GNUNET_NO; process_mst (client, GNUNET_NO); GNUNET_SERVER_client_drop (client); } /** * This function is called whenever our inbound message tokenizer has * received a complete message. * * @param cls closure (struct GNUNET_SERVER_Handle) * @param client identification of the client (struct GNUNET_SERVER_Client*) * @param message the actual message * * @return GNUNET_OK on success, GNUNET_SYSERR to stop further processing */ static int client_message_tokenizer_callback (void *cls, void *client, const struct GNUNET_MessageHeader *message) { struct GNUNET_SERVER_Handle *server = cls; struct GNUNET_SERVER_Client *sender = client; int ret; LOG (GNUNET_ERROR_TYPE_DEBUG, "Tokenizer gives server message of type %u from client\n", ntohs (message->type)); sender->in_process_client_buffer = GNUNET_YES; ret = GNUNET_SERVER_inject (server, sender, message); sender->in_process_client_buffer = GNUNET_NO; if ( (GNUNET_OK != ret) || (GNUNET_YES == sender->shutdown_now) ) { GNUNET_SERVER_client_disconnect (sender); return GNUNET_SYSERR; } return GNUNET_OK; } /** * Add a TCP socket-based connection to the set of handles managed by * this server. Use this function for outgoing (P2P) connections that * we initiated (and where this server should process incoming * messages). * * @param server the server to use * @param connection the connection to manage (client must * stop using this connection from now on) * @return the client handle (client should call * "client_drop" on the return value eventually) */ struct GNUNET_SERVER_Client * GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server, struct GNUNET_CONNECTION_Handle *connection) { struct GNUNET_SERVER_Client *client; client = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Client)); client->connection = connection; client->reference_count = 1; client->server = server; client->last_activity = GNUNET_TIME_absolute_get (); client->idle_timeout = server->idle_timeout; GNUNET_CONTAINER_DLL_insert (server->clients_head, server->clients_tail, client); if (NULL != server->mst_create) client->mst = server->mst_create (server->mst_cls, client); else client->mst = GNUNET_SERVER_mst_create (&client_message_tokenizer_callback, server); GNUNET_assert (NULL != client->mst); client->receive_pending = GNUNET_YES; GNUNET_CONNECTION_receive (client->connection, GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, client->idle_timeout, &process_incoming, client); return client; } /** * Change the timeout for a particular client. Decreasing the timeout * may not go into effect immediately (only after the previous timeout * times out or activity happens on the socket). * * @param client the client to update * @param timeout new timeout for activities on the socket */ void GNUNET_SERVER_client_set_timeout (struct GNUNET_SERVER_Client *client, struct GNUNET_TIME_Relative timeout) { client->idle_timeout = timeout; } /** * Notify the server that the given client handle should * be kept (keeps the connection up if possible, increments * the internal reference counter). * * @param client the client to keep */ void GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client) { client->reference_count++; } /** * Notify the server that the given client handle is no * longer required. Decrements the reference counter. If * that counter reaches zero an inactive connection maybe * closed. * * @param client the client to drop */ void GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client) { GNUNET_assert (client->reference_count > 0); client->reference_count--; if ((GNUNET_YES == client->shutdown_now) && (0 == client->reference_count)) GNUNET_SERVER_client_disconnect (client); } /** * Obtain the network address of the other party. * * @param client the client to get the address for * @param addr where to store the address * @param addrlen where to store the length of the address * @return GNUNET_OK on success */ int GNUNET_SERVER_client_get_address (struct GNUNET_SERVER_Client *client, void **addr, size_t * addrlen) { return GNUNET_CONNECTION_get_address (client->connection, addr, addrlen); } /** * Ask the server to notify us whenever a client disconnects. * This function is called whenever the actual network connection * is closed; the reference count may be zero or larger than zero * at this point. * * @param server the server manageing the clients * @param callback function to call on disconnect * @param callback_cls closure for callback */ void GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server, GNUNET_SERVER_DisconnectCallback callback, void *callback_cls) { struct NotifyList *n; n = GNUNET_malloc (sizeof (struct NotifyList)); n->callback = callback; n->callback_cls = callback_cls; GNUNET_CONTAINER_DLL_insert (server->disconnect_notify_list_head, server->disconnect_notify_list_tail, n); } /** * Ask the server to stop notifying us whenever a client disconnects. * * @param server the server manageing the clients * @param callback function to call on disconnect * @param callback_cls closure for callback */ void GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server, GNUNET_SERVER_DisconnectCallback callback, void *callback_cls) { struct NotifyList *pos; for (pos = server->disconnect_notify_list_head; NULL != pos; pos = pos->next) if ((pos->callback == callback) && (pos->callback_cls == callback_cls)) break; if (NULL == pos) { GNUNET_break (0); return; } GNUNET_CONTAINER_DLL_remove (server->disconnect_notify_list_head, server->disconnect_notify_list_tail, pos); GNUNET_free (pos); } /** * Destroy the connection that is passed in via 'cls'. Used * as calling 'GNUNET_CONNECTION_destroy' from within a function * that was itself called from within 'process_notify' of * 'connection.c' is not allowed (see #2329). * * @param cls connection to destroy * @param tc scheduler context (unused) */ static void destroy_connection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CONNECTION_Handle *connection = cls; GNUNET_CONNECTION_destroy (connection); } /** * Ask the server to disconnect from the given client. * This is the same as returning GNUNET_SYSERR from a message * handler, except that it allows dropping of a client even * when not handling a message from that client. * * @param client the client to disconnect from */ void GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client) { struct GNUNET_SERVER_Handle *server = client->server; struct NotifyList *n; LOG (GNUNET_ERROR_TYPE_DEBUG, "Client is being disconnected from the server.\n"); if (GNUNET_SCHEDULER_NO_TASK != client->restart_task) { GNUNET_SCHEDULER_cancel (client->restart_task); client->restart_task = GNUNET_SCHEDULER_NO_TASK; } if (GNUNET_SCHEDULER_NO_TASK != client->warn_task) { GNUNET_SCHEDULER_cancel (client->warn_task); client->warn_task = GNUNET_SCHEDULER_NO_TASK; } if (GNUNET_YES == client->receive_pending) { GNUNET_CONNECTION_receive_cancel (client->connection); client->receive_pending = GNUNET_NO; } client->shutdown_now = GNUNET_YES; client->reference_count++; /* make sure nobody else clean up client... */ if ( (NULL != client->mst) && (NULL != server) ) { GNUNET_CONTAINER_DLL_remove (server->clients_head, server->clients_tail, client); if (NULL != server->mst_destroy) server->mst_destroy (server->mst_cls, client->mst); else GNUNET_SERVER_mst_destroy (client->mst); client->mst = NULL; for (n = server->disconnect_notify_list_head; NULL != n; n = n->next) n->callback (n->callback_cls, client); } client->reference_count--; if (client->reference_count > 0) { LOG (GNUNET_ERROR_TYPE_DEBUG, "RC still positive, not destroying everything.\n"); client->server = NULL; return; } if (GNUNET_YES == client->in_process_client_buffer) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Still processing inputs, not destroying everything.\n"); return; } if (GNUNET_YES == client->persist) GNUNET_CONNECTION_persist_ (client->connection); if (NULL != client->th.cth) GNUNET_SERVER_notify_transmit_ready_cancel (&client->th); (void) GNUNET_SCHEDULER_add_now (&destroy_connection, client->connection); /* need to cancel again, as it might have been re-added in the meantime (i.e. during callbacks) */ if (GNUNET_SCHEDULER_NO_TASK != client->warn_task) { GNUNET_SCHEDULER_cancel (client->warn_task); client->warn_task = GNUNET_SCHEDULER_NO_TASK; } if (GNUNET_YES == client->receive_pending) { GNUNET_CONNECTION_receive_cancel (client->connection); client->receive_pending = GNUNET_NO; } GNUNET_free (client); /* we might be in soft-shutdown, test if we're done */ if (NULL != server) test_monitor_clients (server); } /** * Disable the "CORK" feature for communication with the given client, * forcing the OS to immediately flush the buffer on transmission * instead of potentially buffering multiple messages. * * @param client handle to the client * @return GNUNET_OK on success */ int GNUNET_SERVER_client_disable_corking (struct GNUNET_SERVER_Client *client) { return GNUNET_CONNECTION_disable_corking (client->connection); } /** * Wrapper for transmission notification that calls the original * callback and update the last activity time for our connection. * * @param cls the 'struct GNUNET_SERVER_Client' * @param size number of bytes we can transmit * @param buf where to copy the message * @return number of bytes actually transmitted */ static size_t transmit_ready_callback_wrapper (void *cls, size_t size, void *buf) { struct GNUNET_SERVER_Client *client = cls; GNUNET_CONNECTION_TransmitReadyNotify callback; client->th.cth = NULL; callback = client->th.callback; client->th.callback = NULL; client->last_activity = GNUNET_TIME_absolute_get (); return callback (client->th.callback_cls, size, buf); } /** * Notify us when the server has enough space to transmit * a message of the given size to the given client. * * @param client client to transmit message to * @param size requested amount of buffer space * @param timeout after how long should we give up (and call * notify with buf NULL and size 0)? * @param callback function to call when space is available * @param callback_cls closure for callback * @return non-NULL if the notify callback was queued; can be used * to cancel the request using * GNUNET_SERVER_notify_transmit_ready_cancel. * NULL if we are already going to notify someone else (busy) */ struct GNUNET_SERVER_TransmitHandle * GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client, size_t size, struct GNUNET_TIME_Relative timeout, GNUNET_CONNECTION_TransmitReadyNotify callback, void *callback_cls) { if (NULL != client->th.callback) return NULL; client->th.callback_cls = callback_cls; client->th.callback = callback; client->th.cth = GNUNET_CONNECTION_notify_transmit_ready (client->connection, size, timeout, &transmit_ready_callback_wrapper, client); return &client->th; } /** * Abort transmission request. * * @param th request to abort */ void GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th) { GNUNET_CONNECTION_notify_transmit_ready_cancel (th->cth); th->cth = NULL; th->callback = NULL; } /** * Set the persistent flag on this client, used to setup client connection * to only be killed when the service it's connected to is actually dead. * * @param client the client to set the persistent flag on */ void GNUNET_SERVER_client_persist_ (struct GNUNET_SERVER_Client *client) { client->persist = GNUNET_YES; } /** * Resume receiving from this client, we are done processing the * current request. This function must be called from within each * GNUNET_SERVER_MessageCallback (or its respective continuations). * * @param client client we were processing a message of * @param success GNUNET_OK to keep the connection open and * continue to receive * GNUNET_NO to close the connection (normal behavior) * GNUNET_SYSERR to close the connection (signal * serious error) */ void GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client, int success) { if (NULL == client) return; GNUNET_assert (client->suspended > 0); client->suspended--; if (GNUNET_OK != success) { LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_SERVER_receive_done called with failure indication\n"); if ( (client->reference_count > 0) || (client->suspended > 0) ) client->shutdown_now = GNUNET_YES; else GNUNET_SERVER_client_disconnect (client); return; } if (client->suspended > 0) { LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_SERVER_receive_done called, but more clients pending\n"); return; } if (GNUNET_SCHEDULER_NO_TASK != client->warn_task) { GNUNET_SCHEDULER_cancel (client->warn_task); client->warn_task = GNUNET_SCHEDULER_NO_TASK; } if (GNUNET_YES == client->in_process_client_buffer) { LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_SERVER_receive_done called while still in processing loop\n"); return; } if ((NULL == client->server) || (GNUNET_YES == client->shutdown_now)) { GNUNET_SERVER_client_disconnect (client); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_SERVER_receive_done causes restart in reading from the socket\n"); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == client->restart_task); client->restart_task = GNUNET_SCHEDULER_add_now (&restart_processing, client); } /* end of server.c */ gnunet-0.9.3/src/util/test_scheduler.c0000644000175000017500000001267711760502551014710 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_scheduler.c * @brief tests for the scheduler */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" #include "gnunet_disk_lib.h" #define VERBOSE GNUNET_NO static void task2 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { int *ok = cls; /* t3 should be ready (albeit with lower priority) */ GNUNET_assert (1 == GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_COUNT)); GNUNET_assert (2 == *ok); (*ok) = 3; } static void task3 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { int *ok = cls; GNUNET_assert (3 == *ok); (*ok) = 4; } struct GNUNET_DISK_PipeHandle *p; static const struct GNUNET_DISK_FileHandle *fds[2]; static void taskWrt (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { static char c; int *ok = cls; GNUNET_assert (6 == *ok); GNUNET_assert (GNUNET_NETWORK_fdset_handle_isset (tc->write_ready, fds[1])); (*ok) = 7; GNUNET_assert (1 == GNUNET_DISK_file_write (fds[1], &c, 1)); } static void taskNeverRun (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_assert (0); } static void taskLast (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { int *ok = cls; /* t4 should be ready (albeit with lower priority) */ GNUNET_assert (8 == *ok); (*ok) = 0; } static void taskRd (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { static char c; int *ok = cls; GNUNET_assert (7 == *ok); GNUNET_assert (GNUNET_NETWORK_fdset_handle_isset (tc->read_ready, fds[0])); GNUNET_assert (1 == GNUNET_DISK_file_read (fds[0], &c, 1)); (*ok) = 8; GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, &taskLast, cls); GNUNET_SCHEDULER_shutdown (); } static void task4 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { int *ok = cls; GNUNET_assert (4 == *ok); (*ok) = 6; p = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO); GNUNET_assert (NULL != p); fds[0] = GNUNET_DISK_pipe_handle (p, GNUNET_DISK_PIPE_END_READ); fds[1] = GNUNET_DISK_pipe_handle (p, GNUNET_DISK_PIPE_END_WRITE); GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, fds[0], &taskRd, cls); GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, fds[1], &taskWrt, cls); } static void task1 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { int *ok = cls; GNUNET_assert (1 == *ok); (*ok) = 2; GNUNET_SCHEDULER_add_now (&task3, cls); GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_UI, &task2, cls); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &task4, cls); } /** * Main method, starts scheduler with task1, * checks that "ok" is correct at the end. */ static int check () { int ok; ok = 1; GNUNET_SCHEDULER_run (&task1, &ok); return ok; } static void taskShutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { int *ok = cls; GNUNET_assert (1 == *ok); *ok = 8; GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &taskLast, cls); GNUNET_SCHEDULER_shutdown (); } /** * Main method, starts scheduler with task1, * checks that "ok" is correct at the end. */ static int checkShutdown () { int ok; ok = 1; GNUNET_SCHEDULER_run (&taskShutdown, &ok); return ok; } static void taskSig (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { int *ok = cls; GNUNET_assert (1 == *ok); *ok = 8; GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &taskLast, cls); GNUNET_break (0 == PLIBC_KILL (getpid (), SIGTERM)); } /** * Main method, starts scheduler with task1, * checks that "ok" is correct at the end. */ static int checkSignal () { int ok; ok = 1; GNUNET_SCHEDULER_run (&taskSig, &ok); return ok; } static void taskCancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { int *ok = cls; GNUNET_assert (1 == *ok); *ok = 0; GNUNET_SCHEDULER_cancel (GNUNET_SCHEDULER_add_now (&taskNeverRun, NULL)); } /** * Main method, starts scheduler with task1, * checks that "ok" is correct at the end. */ static int checkCancel () { int ok; ok = 1; GNUNET_SCHEDULER_run (&taskCancel, &ok); return ok; } int main (int argc, char *argv[]) { int ret = 0; GNUNET_log_setup ("test_scheduler", "WARNING", NULL); ret += check (); #ifndef MINGW ret += checkSignal (); #endif ret += checkShutdown (); ret += checkCancel (); GNUNET_DISK_pipe_close (p); return ret; } /* end of test_scheduler.c */ gnunet-0.9.3/src/util/crypto_random.c0000644000175000017500000001764111760502551014547 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/crypto_random.c * @brief functions to gather random numbers * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_crypto_lib.h" #include "gnunet_os_lib.h" #include #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) /* TODO: ndurner, move this to plibc? */ /* The code is derived from glibc, obviously */ #if MINGW #ifdef RANDOM #undef RANDOM #endif #ifdef SRANDOM #undef SRANDOM #endif #define RANDOM() glibc_weak_rand32() #define SRANDOM(s) glibc_weak_srand32(s) static int32_t glibc_weak_rand32_state = 1; void glibc_weak_srand32 (int32_t s) { glibc_weak_rand32_state = s; } int32_t glibc_weak_rand32 () { int32_t val = glibc_weak_rand32_state; val = ((glibc_weak_rand32_state * 1103515245) + 12345) & 0x7fffffff; glibc_weak_rand32_state = val; return val; } #endif /** * Create a cryptographically weak pseudo-random number in the interval of 0 to 1. * * @return number between 0 and 1. */ static double weak_random () { return ((double) RANDOM () / RAND_MAX); } /** * Seed a weak random generator. Only GNUNET_CRYPTO_QUALITY_WEAK-mode generator * can be seeded. * * @param seed the seed to use */ void GNUNET_CRYPTO_seed_weak_random (int32_t seed) { SRANDOM (seed); } /** * Produce a random value. * * @param mode desired quality of the random number * @param i the upper limit (exclusive) for the random number * @return a random value in the interval [0,i[. */ uint32_t GNUNET_CRYPTO_random_u32 (enum GNUNET_CRYPTO_Quality mode, uint32_t i) { #ifdef gcry_fast_random_poll static unsigned int invokeCount; #endif uint32_t ret; uint32_t ul; GNUNET_assert (i > 0); switch (mode) { case GNUNET_CRYPTO_QUALITY_STRONG: /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */ #ifdef gcry_fast_random_poll if ((invokeCount++ % 256) == 0) gcry_fast_random_poll (); #endif ul = UINT32_MAX - (UINT32_MAX % i); do { gcry_randomize ((unsigned char *) &ret, sizeof (uint32_t), GCRY_STRONG_RANDOM); } while (ret >= ul); return ret % i; case GNUNET_CRYPTO_QUALITY_NONCE: ul = UINT32_MAX - (UINT32_MAX % i); do { gcry_create_nonce (&ret, sizeof (ret)); } while (ret >= ul); return ret % i; case GNUNET_CRYPTO_QUALITY_WEAK: ret = i * weak_random (); if (ret >= i) ret = i - 1; return ret; default: GNUNET_assert (0); } return 0; } /** * Get an array with a random permutation of the * numbers 0...n-1. * @param mode GNUNET_RANDOM_QUALITY_STRONG if the strong (but expensive) * PRNG should be used, GNUNET_RANDOM_QUALITY_WEAK otherwise * @param n the size of the array * @return the permutation array (allocated from heap) */ unsigned int * GNUNET_CRYPTO_random_permute (enum GNUNET_CRYPTO_Quality mode, unsigned int n) { unsigned int *ret; unsigned int i; unsigned int tmp; uint32_t x; GNUNET_assert (n > 0); ret = GNUNET_malloc (n * sizeof (unsigned int)); for (i = 0; i < n; i++) ret[i] = i; for (i = n - 1; i > 0; i--) { x = GNUNET_CRYPTO_random_u32 (mode, i + 1); tmp = ret[x]; ret[x] = ret[i]; ret[i] = tmp; } return ret; } /** * Random on unsigned 64-bit values. * * * @param mode desired quality of the random number * @param max value returned will be in range [0,max) (exclusive) * @return random 64-bit number */ uint64_t GNUNET_CRYPTO_random_u64 (enum GNUNET_CRYPTO_Quality mode, uint64_t max) { uint64_t ret; uint64_t ul; GNUNET_assert (max > 0); switch (mode) { case GNUNET_CRYPTO_QUALITY_STRONG: ul = UINT64_MAX - (UINT64_MAX % max); do { gcry_randomize ((unsigned char *) &ret, sizeof (uint64_t), GCRY_STRONG_RANDOM); } while (ret >= ul); return ret % max; case GNUNET_CRYPTO_QUALITY_NONCE: ul = UINT64_MAX - (UINT64_MAX % max); do { gcry_create_nonce (&ret, sizeof (ret)); } while (ret >= ul); return ret % max; case GNUNET_CRYPTO_QUALITY_WEAK: ret = max * weak_random (); if (ret >= max) ret = max - 1; return ret; default: GNUNET_assert (0); } return 0; } /** * This function should only be called in testcases * where strong entropy gathering is not desired * (for example, for hostkey generation). */ void GNUNET_CRYPTO_random_disable_entropy_gathering () { gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); } /** * Process ID of the "find" process that we use for * entropy gathering. */ static struct GNUNET_OS_Process *genproc; /** * Function called by libgcrypt whenever we are * blocked gathering entropy. */ static void entropy_generator (void *cls, const char *what, int printchar, int current, int total) { unsigned long code; enum GNUNET_OS_ProcessStatusType type; int ret; if (0 != strcmp (what, "need_entropy")) return; if (current == total) { if (genproc != NULL) { if (0 != GNUNET_OS_process_kill (genproc, SIGTERM)) LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "kill"); GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (genproc)); GNUNET_OS_process_destroy (genproc); genproc = NULL; } return; } if (genproc != NULL) { ret = GNUNET_OS_process_status (genproc, &type, &code); if (ret == GNUNET_NO) return; /* still running */ if (ret == GNUNET_SYSERR) { GNUNET_break (0); return; } if (0 != GNUNET_OS_process_kill (genproc, SIGTERM)) LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "kill"); GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (genproc)); GNUNET_OS_process_destroy (genproc); genproc = NULL; } LOG (GNUNET_ERROR_TYPE_INFO, _("Starting `%s' process to generate entropy\n"), "find"); genproc = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "sh", "sh", "-c", "exec find / -mount -type f -exec cp {} /dev/null \\; 2>/dev/null", NULL); } static void killfind () { if (genproc != NULL) { GNUNET_OS_process_kill (genproc, SIGKILL); GNUNET_OS_process_destroy (genproc); genproc = NULL; } } void __attribute__ ((constructor)) GNUNET_CRYPTO_random_init () { gcry_control (GCRYCTL_DISABLE_SECMEM, 0); if (!gcry_check_version (GCRYPT_VERSION)) { FPRINTF (stderr, _ ("libgcrypt has not the expected version (version %s is required).\n"), GCRYPT_VERSION); GNUNET_abort (); } #ifdef GCRYCTL_INITIALIZATION_FINISHED gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); #endif #ifdef gcry_fast_random_poll gcry_fast_random_poll (); #endif gcry_set_progress_handler (&entropy_generator, NULL); atexit (&killfind); GNUNET_CRYPTO_seed_weak_random (time (NULL) ^ GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX)); } void __attribute__ ((destructor)) GNUNET_CRYPTO_random_fini () { gcry_set_progress_handler (NULL, NULL); } /* end of crypto_random.c */ gnunet-0.9.3/src/util/test_crypto_aes_weak.c0000644000175000017500000001226711760502551016104 00000000000000/* This file is part of GNUnet. (C) 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @author Krista Bennett * @author Christian Grothoff * @file util/test_crypto_aes_weak.c * @brief AES weak key test. */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_crypto_lib.h" #include #define MAX_WEAK_KEY_TRIALS 100000 #define GENERATE_WEAK_KEYS GNUNET_NO #define WEAK_KEY_TESTSTRING "I hate weak keys." static void printWeakKey (struct GNUNET_CRYPTO_AesSessionKey *key) { int i; for (i = 0; i < GNUNET_CRYPTO_AES_KEY_LENGTH; i++) { printf ("%x ", (int) (key->key[i])); } } static int testWeakKey () { char result[100]; char res[100]; int size; struct GNUNET_CRYPTO_AesSessionKey weak_key; struct GNUNET_CRYPTO_AesInitializationVector INITVALUE; memset (&INITVALUE, 42, sizeof (struct GNUNET_CRYPTO_AesInitializationVector)); /* sorry, this is not a weak key -- I don't have * any at the moment! */ weak_key.key[0] = (char) (0x4c); weak_key.key[1] = (char) (0x31); weak_key.key[2] = (char) (0xc6); weak_key.key[3] = (char) (0x2b); weak_key.key[4] = (char) (0xc1); weak_key.key[5] = (char) (0x5f); weak_key.key[6] = (char) (0x4d); weak_key.key[7] = (char) (0x1f); weak_key.key[8] = (char) (0x31); weak_key.key[9] = (char) (0xaa); weak_key.key[10] = (char) (0x12); weak_key.key[11] = (char) (0x2e); weak_key.key[12] = (char) (0xb7); weak_key.key[13] = (char) (0x82); weak_key.key[14] = (char) (0xc0); weak_key.key[15] = (char) (0xb6); weak_key.key[16] = (char) (0x4d); weak_key.key[17] = (char) (0x1f); weak_key.key[18] = (char) (0x31); weak_key.key[19] = (char) (0xaa); weak_key.key[20] = (char) (0x4c); weak_key.key[21] = (char) (0x31); weak_key.key[22] = (char) (0xc6); weak_key.key[23] = (char) (0x2b); weak_key.key[24] = (char) (0xc1); weak_key.key[25] = (char) (0x5f); weak_key.key[26] = (char) (0x4d); weak_key.key[27] = (char) (0x1f); weak_key.key[28] = (char) (0x31); weak_key.key[29] = (char) (0xaa); weak_key.key[30] = (char) (0xaa); weak_key.key[31] = (char) (0xaa); /* memset(&weak_key, 0, 32); */ weak_key.crc32 = htonl (GNUNET_CRYPTO_crc32_n (&weak_key, GNUNET_CRYPTO_AES_KEY_LENGTH)); size = GNUNET_CRYPTO_aes_encrypt (WEAK_KEY_TESTSTRING, strlen (WEAK_KEY_TESTSTRING) + 1, &weak_key, &INITVALUE, result); if (size == -1) { GNUNET_break (0); return 1; } size = GNUNET_CRYPTO_aes_decrypt (result, size, &weak_key, &INITVALUE, res); if ((strlen (WEAK_KEY_TESTSTRING) + 1) != size) { GNUNET_break (0); return 1; } if (0 != strcmp (res, WEAK_KEY_TESTSTRING)) { GNUNET_break (0); return 1; } else return 0; } static int getWeakKeys () { struct GNUNET_CRYPTO_AesSessionKey sessionkey; int number_of_weak_keys = 0; int number_of_runs; gcry_cipher_hd_t handle; int rc; for (number_of_runs = 0; number_of_runs < MAX_WEAK_KEY_TRIALS; number_of_runs++) { if (number_of_runs % 1000 == 0) FPRINTF (stderr, "%s", "."); /*printf("Got to run number %d.\n", number_of_runs); */ GNUNET_CRYPTO_aes_create_session_key (&sessionkey); rc = gcry_cipher_open (&handle, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CFB, 0); if (rc) { printf ("testweakkey: gcry_cipher_open failed on trial %d. %s\n", number_of_runs, gcry_strerror (rc)); continue; } rc = gcry_cipher_setkey (handle, &sessionkey, GNUNET_CRYPTO_AES_KEY_LENGTH); if ((char) rc == GPG_ERR_WEAK_KEY) { printf ("\nWeak key (in hex): "); printWeakKey (&sessionkey); printf ("\n"); number_of_weak_keys++; } else if (rc) { printf ("\nUnexpected error generating keys. Error is %s\n", gcry_strerror (rc)); } gcry_cipher_close (handle); } return number_of_weak_keys; } int main (int argc, char *argv[]) { int weak_keys; GNUNET_log_setup ("test-crypto-aes-weak", "WARNING", NULL); GNUNET_CRYPTO_random_disable_entropy_gathering (); if (GENERATE_WEAK_KEYS) { weak_keys = getWeakKeys (); if (weak_keys == 0) { printf ("\nNo weak keys found in %d runs.\n", MAX_WEAK_KEY_TRIALS); } else { printf ("\n%d weak keys found in %d runs.\n", weak_keys, MAX_WEAK_KEY_TRIALS); } } if (testWeakKey () != 0) return -1; return 0; } /* end of weakkeytest.c */ gnunet-0.9.3/src/util/test_common_logging_dummy.c0000644000175000017500000000621711760502551017134 00000000000000/* This file is part of GNUnet. (C) 2008 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_common_logging_dummy.c * @brief dummy labrat for the testcase for the logging module (runtime * log level adjustment) * @author LRN */ #include "platform.h" #undef GNUNET_EXTRA_LOGGING #define GNUNET_EXTRA_LOGGING GNUNET_YES #include "gnunet_common.h" #include "gnunet_time_lib.h" #include "gnunet_network_lib.h" /** * Delay introduced between operations, useful for debugging. */ #define OUTPUT_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 0) static void my_log (void *ctx, enum GNUNET_ErrorType kind, const char *component, const char *date, const char *msg) { if (strncmp ("test-common-logging-dummy", component, 25) != 0) return; FPRINTF (stdout, "%s", msg); fflush (stdout); } static int expensive_func () { return GNUNET_NETWORK_socket_select (NULL, NULL, NULL, OUTPUT_DELAY); } #define pr(kind,lvl) {\ struct GNUNET_TIME_Absolute t1, t2;\ t1 = GNUNET_TIME_absolute_get ();\ GNUNET_log (kind, "L%s %d\n", lvl, expensive_func());\ t2 = GNUNET_TIME_absolute_get ();\ printf ("1%s %llu\n", lvl,\ (unsigned long long) GNUNET_TIME_absolute_get_difference (t1, t2).rel_value); \ } #define pr2(kind,lvl) {\ struct GNUNET_TIME_Absolute t1, t2;\ t1 = GNUNET_TIME_absolute_get ();\ GNUNET_log (kind, "L%s %d\n", lvl, expensive_func());\ t2 = GNUNET_TIME_absolute_get ();\ printf ("2%s %llu\n", lvl,\ (unsigned long long) GNUNET_TIME_absolute_get_difference (t1, t2).rel_value); \ } int main (int argc, char *argv[]) { /* We set up logging with NULL level - will be overrided by * GNUNET_LOG or GNUNET_FORCE_LOG at runtime. */ GNUNET_log_setup ("test-common-logging-dummy", NULL, "/dev/null"); GNUNET_logger_add (&my_log, NULL); pr (GNUNET_ERROR_TYPE_ERROR, "ERROR"); pr (GNUNET_ERROR_TYPE_WARNING, "WARNING"); pr (GNUNET_ERROR_TYPE_INFO, "INFO"); pr (GNUNET_ERROR_TYPE_DEBUG, "DEBUG"); /* We set up logging with WARNING level - will onle be overrided by * GNUNET_FORCE_LOG at runtime. */ GNUNET_log_setup ("test-common-logging-dummy", "WARNING", "/dev/null"); pr2 (GNUNET_ERROR_TYPE_ERROR, "ERROR"); pr2 (GNUNET_ERROR_TYPE_WARNING, "WARNING"); pr2 (GNUNET_ERROR_TYPE_INFO, "INFO"); pr2 (GNUNET_ERROR_TYPE_DEBUG, "DEBUG"); return 0; } /* end of main */ /* end of test_common_logging_dummy.c */ gnunet-0.9.3/src/util/test_scheduler_delay.c0000644000175000017500000000565511760502551016064 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2006 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_scheduler_delay.c * @brief testcase for delay of scheduler, measures how * precise the timers are. Expect values between 10 and 20 ms on * modern machines. */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" #define VERBOSE GNUNET_NO static struct GNUNET_TIME_Absolute target; static int i; static unsigned long long cumDelta; #define INCR 47 #define MAXV 1500 /** * Signature of the main function of a task. * * @param cls closure * @param tc context */ static void test_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TIME_Absolute now; now = GNUNET_TIME_absolute_get (); if (now.abs_value > target.abs_value) cumDelta += (now.abs_value - target.abs_value); else cumDelta += (target.abs_value - now.abs_value); target = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, i)); FPRINTF (stderr, "%s", "."); if (i > MAXV) { FPRINTF (stderr, "%s", "\n"); return; } GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, i), &test_task, NULL); i += INCR; } static int check () { target = GNUNET_TIME_absolute_get (); GNUNET_SCHEDULER_run (&test_task, NULL); FPRINTF (stdout, "Sleep precision: %llu ms. ", cumDelta / 1000 / (MAXV / INCR)); if (cumDelta <= 10 * MAXV / INCR) FPRINTF (stdout, "%s", "Timer precision is excellent.\n"); else if (cumDelta <= 50 * MAXV / INCR) /* 50 ms average deviation */ FPRINTF (stdout, "%s", "Timer precision is good.\n"); else if (cumDelta > 250 * MAXV / INCR) FPRINTF (stdout, "%s", "Timer precision is awful.\n"); else FPRINTF (stdout, "%s", "Timer precision is acceptable.\n"); return 0; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-scheduler-delay", "WARNING", NULL); ret = check (); return ret; } /* end of test_scheduler_delay.c */ gnunet-0.9.3/src/util/test_common_logging.c0000644000175000017500000000636111760502551015721 00000000000000/* This file is part of GNUnet. (C) 2008 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_common_logging.c * @brief testcase for the logging module * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" static void my_log (void *ctx, enum GNUNET_ErrorType kind, const char *component, const char *date, const char *msg) { unsigned int *c = ctx; (*c)++; } int main (int argc, char *argv[]) { unsigned int failureCount = 0; unsigned int logs = 0; if (0 != putenv ("GNUNET_FORCE_LOG=")) FPRINTF (stderr, "Failed to putenv: %s\n", strerror (errno)); GNUNET_log_setup ("test-common-logging", "DEBUG", "/dev/null"); GNUNET_logger_add (&my_log, &logs); GNUNET_logger_add (&my_log, &logs); GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Testing...\n"); GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Testing...\n"); GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Testing...\n"); GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Testing...\n"); GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Testing...\n"); GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Testing...\n"); GNUNET_logger_remove (&my_log, &logs); GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Flusher...\n"); /* the last 6 calls should be merged (repated bulk messages!) */ GNUNET_logger_remove (&my_log, &logs); if (logs != 4) { FPRINTF (stdout, "Expected 4 log calls, got %u\n", logs); failureCount++; } GNUNET_break (0 == strcmp (_("ERROR"), GNUNET_error_type_to_string (GNUNET_ERROR_TYPE_ERROR))); GNUNET_break (0 == strcmp (_("WARNING"), GNUNET_error_type_to_string (GNUNET_ERROR_TYPE_WARNING))); GNUNET_break (0 == strcmp (_("INFO"), GNUNET_error_type_to_string (GNUNET_ERROR_TYPE_INFO))); GNUNET_break (0 == strcmp (_("DEBUG"), GNUNET_error_type_to_string (GNUNET_ERROR_TYPE_DEBUG))); GNUNET_log_setup ("test_common_logging", "WARNING", "/dev/null"); logs = 0; GNUNET_logger_add (&my_log, &logs); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Checker...\n"); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Drop me...\n"); GNUNET_logger_remove (&my_log, &logs); if (logs != 1) { FPRINTF (stdout, "Expected 1 log call, got %u\n", logs); failureCount++; } if (failureCount != 0) { FPRINTF (stdout, "%u TESTS FAILED!\n", failureCount); return -1; } return 0; } /* end of main */ /* end of test_common_logging.c */ gnunet-0.9.3/src/util/test_connection.c0000644000175000017500000001343211760502551015057 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_connection.c * @brief tests for connection.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_connection_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" #define VERBOSE GNUNET_NO #define PORT 12435 static struct GNUNET_CONNECTION_Handle *csock; static struct GNUNET_CONNECTION_Handle *asock; static struct GNUNET_CONNECTION_Handle *lsock; static size_t sofar; static struct GNUNET_NETWORK_Handle *ls; static struct GNUNET_CONFIGURATION_Handle *cfg; /** * Create and initialize a listen socket for the server. * * @return -1 on error, otherwise the listen socket */ static struct GNUNET_NETWORK_Handle * open_listen_socket () { const static int on = 1; struct sockaddr_in sa; struct GNUNET_NETWORK_Handle *desc; memset (&sa, 0, sizeof (sa)); #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = sizeof (sa); #endif sa.sin_port = htons (PORT); sa.sin_family = AF_INET; desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); GNUNET_assert (desc != NULL); if (GNUNET_NETWORK_socket_setsockopt (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); GNUNET_assert (GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa, sizeof (sa)) == GNUNET_OK); GNUNET_NETWORK_socket_listen (desc, 5); return desc; } static void receive_check (void *cls, const void *buf, size_t available, const struct sockaddr *addr, socklen_t addrlen, int errCode) { int *ok = cls; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receive validates incoming data\n"); #endif GNUNET_assert (buf != NULL); /* no timeout */ if (0 == memcmp (&"Hello World"[sofar], buf, available)) sofar += available; if (sofar < 12) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receive needs more data\n"); #endif GNUNET_CONNECTION_receive (asock, 1024, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check, cls); } else { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receive closes accepted socket\n"); #endif *ok = 0; GNUNET_CONNECTION_destroy (asock); GNUNET_CONNECTION_destroy (csock); } } static void run_accept (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test accepts connection\n"); #endif asock = GNUNET_CONNECTION_create_from_accept (NULL, NULL, ls); GNUNET_assert (asock != NULL); GNUNET_assert (GNUNET_YES == GNUNET_CONNECTION_check (asock)); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test destroys listen socket\n"); #endif GNUNET_CONNECTION_destroy (lsock); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test asks to receive on accepted socket\n"); #endif GNUNET_CONNECTION_receive (asock, 1024, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check, cls); } static size_t make_hello (void *cls, size_t size, void *buf) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test prepares to transmit on connect socket\n"); #endif GNUNET_assert (size >= 12); strcpy ((char *) buf, "Hello World"); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test destroys client socket\n"); #endif return 12; } static void task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { ls = open_listen_socket (); lsock = GNUNET_CONNECTION_create_from_existing (ls); GNUNET_assert (lsock != NULL); csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT); GNUNET_assert (csock != NULL); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test asks for write notification\n"); #endif GNUNET_assert (NULL != GNUNET_CONNECTION_notify_transmit_ready (csock, 12, GNUNET_TIME_UNIT_SECONDS, &make_hello, NULL)); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test prepares to accept\n"); #endif GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, ls, &run_accept, cls); } /** * Main method, starts scheduler with task , * checks that "ok" is correct at the end. */ static int check () { int ok; ok = 1; cfg = GNUNET_CONFIGURATION_create (); GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", "localhost"); GNUNET_SCHEDULER_run (&task, &ok); GNUNET_CONFIGURATION_destroy (cfg); return ok; } int main (int argc, char *argv[]) { int ret = 0; GNUNET_log_setup ("test_connection", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret += check (); return ret; } /* end of test_connection.c */ gnunet-0.9.3/src/util/test_pseudonym_data.conf0000644000175000017500000000013511667453373016450 00000000000000# General settings [client] HOME = "/tmp/gnunet-pseudonym-test" [TESTING] WEAKRANDOM = YES gnunet-0.9.3/src/util/test_connection_timeout.c0000644000175000017500000001020111760502551016614 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_connection_timeout.c * @brief tests for connection.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_connection_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" #define VERBOSE GNUNET_NO #define PORT 12435 static struct GNUNET_CONNECTION_Handle *csock; static struct GNUNET_CONNECTION_Handle *lsock; static struct GNUNET_NETWORK_Handle *ls; static struct GNUNET_CONFIGURATION_Handle *cfg; /** * Create and initialize a listen socket for the server. * * @return NULL on error, otherwise the listen socket */ static struct GNUNET_NETWORK_Handle * open_listen_socket () { const static int on = 1; struct sockaddr_in sa; struct GNUNET_NETWORK_Handle *desc; memset (&sa, 0, sizeof (sa)); #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = sizeof (sa); #endif sa.sin_family = AF_INET; sa.sin_port = htons (PORT); desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); GNUNET_assert (desc != NULL); if (GNUNET_NETWORK_socket_setsockopt (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); GNUNET_assert (GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa, sizeof (sa)) == GNUNET_OK); GNUNET_NETWORK_socket_listen (desc, 5); return desc; } static size_t send_kilo (void *cls, size_t size, void *buf) { int *ok = cls; if (size == 0) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got the desired timeout!\n"); #endif GNUNET_assert (buf == NULL); *ok = 0; GNUNET_CONNECTION_destroy (lsock); GNUNET_CONNECTION_destroy (csock); return 0; } #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending kilo to fill buffer.\n"); #endif GNUNET_assert (size >= 1024); memset (buf, 42, 1024); GNUNET_assert (NULL != GNUNET_CONNECTION_notify_transmit_ready (csock, 1024, GNUNET_TIME_UNIT_SECONDS, &send_kilo, cls)); return 1024; } static void task_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { ls = open_listen_socket (); lsock = GNUNET_CONNECTION_create_from_existing (ls); GNUNET_assert (lsock != NULL); csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT); GNUNET_assert (csock != NULL); GNUNET_assert (NULL != GNUNET_CONNECTION_notify_transmit_ready (csock, 1024, GNUNET_TIME_UNIT_SECONDS, &send_kilo, cls)); } /** * Main method, starts scheduler with task_timeout. */ static int check_timeout () { int ok; ok = 1; cfg = GNUNET_CONFIGURATION_create (); GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", "localhost"); GNUNET_SCHEDULER_run (&task_timeout, &ok); GNUNET_CONFIGURATION_destroy (cfg); return ok; } int main (int argc, char *argv[]) { int ret = 0; GNUNET_log_setup ("test_connection_timeout", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret += check_timeout (); return ret; } /* end of test_connection_timeout.c */ gnunet-0.9.3/src/util/crypto_hash.c0000644000175000017500000004544111760502551014211 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. SHA-512 code by Jean-Luc Cooke Copyright (c) Jean-Luc Cooke Copyright (c) Andrew McDonald Copyright (c) 2003 Kyle McMartin */ /** * @file util/crypto_hash.c * @brief SHA-512 GNUNET_CRYPTO_hash related functions * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_crypto_lib.h" #include "gnunet_disk_lib.h" #include "gnunet_strings_lib.h" #include #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) /** * Hash block of given size. * * @param block the data to GNUNET_CRYPTO_hash, length is given as a second argument * @param size the length of the data to GNUNET_CRYPTO_hash * @param ret pointer to where to write the hashcode */ void GNUNET_CRYPTO_hash (const void *block, size_t size, GNUNET_HashCode * ret) { gcry_md_hash_buffer (GCRY_MD_SHA512, ret, block, size); } /** * Compute short (256-bit) hash of a given block. * * @param block the data to GNUNET_CRYPTO_hash, length is given as a second argument * @param size the length of the data to GNUNET_CRYPTO_hash * @param ret pointer to where to write the hashcode */ void GNUNET_CRYPTO_short_hash (const void *block, size_t size, struct GNUNET_CRYPTO_ShortHashCode * ret) { gcry_md_hash_buffer (GCRY_MD_SHA256, ret, block, size); } /** * Context used when hashing a file. */ struct GNUNET_CRYPTO_FileHashContext { /** * Function to call upon completion. */ GNUNET_CRYPTO_HashCompletedCallback callback; /** * Closure for callback. */ void *callback_cls; /** * IO buffer. */ unsigned char *buffer; /** * Name of the file we are hashing. */ char *filename; /** * File descriptor. */ struct GNUNET_DISK_FileHandle *fh; /** * Cummulated hash. */ gcry_md_hd_t md; /** * Size of the file. */ uint64_t fsize; /** * Current offset. */ uint64_t offset; /** * Current task for hashing. */ GNUNET_SCHEDULER_TaskIdentifier task; /** * Priority we use. */ enum GNUNET_SCHEDULER_Priority priority; /** * Blocksize. */ size_t bsize; }; /** * Report result of hash computation to callback * and free associated resources. */ static void file_hash_finish (struct GNUNET_CRYPTO_FileHashContext *fhc, const GNUNET_HashCode * res) { fhc->callback (fhc->callback_cls, res); GNUNET_free (fhc->filename); if (!GNUNET_DISK_handle_invalid (fhc->fh)) GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fhc->fh)); gcry_md_close (fhc->md); GNUNET_free (fhc); /* also frees fhc->buffer */ } /** * File hashing task. * * @param cls closure * @param tc context */ static void file_hash_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CRYPTO_FileHashContext *fhc = cls; GNUNET_HashCode *res; size_t delta; fhc->task = GNUNET_SCHEDULER_NO_TASK; GNUNET_assert (fhc->offset <= fhc->fsize); delta = fhc->bsize; if (fhc->fsize - fhc->offset < delta) delta = fhc->fsize - fhc->offset; if (delta != GNUNET_DISK_file_read (fhc->fh, fhc->buffer, delta)) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "read", fhc->filename); file_hash_finish (fhc, NULL); return; } gcry_md_write (fhc->md, fhc->buffer, delta); fhc->offset += delta; if (fhc->offset == fhc->fsize) { res = (GNUNET_HashCode *) gcry_md_read (fhc->md, GCRY_MD_SHA512); file_hash_finish (fhc, res); return; } fhc->task = GNUNET_SCHEDULER_add_with_priority (fhc->priority, &file_hash_task, fhc); } /** * Compute the hash of an entire file. * * @param priority scheduling priority to use * @param filename name of file to hash * @param blocksize number of bytes to process in one task * @param callback function to call upon completion * @param callback_cls closure for callback * @return NULL on (immediate) errror */ struct GNUNET_CRYPTO_FileHashContext * GNUNET_CRYPTO_hash_file (enum GNUNET_SCHEDULER_Priority priority, const char *filename, size_t blocksize, GNUNET_CRYPTO_HashCompletedCallback callback, void *callback_cls) { struct GNUNET_CRYPTO_FileHashContext *fhc; GNUNET_assert (blocksize > 0); fhc = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_FileHashContext) + blocksize); fhc->callback = callback; fhc->callback_cls = callback_cls; fhc->buffer = (unsigned char *) &fhc[1]; fhc->filename = GNUNET_strdup (filename); if (GPG_ERR_NO_ERROR != gcry_md_open (&fhc->md, GCRY_MD_SHA512, 0)) { GNUNET_break (0); GNUNET_free (fhc); return NULL; } fhc->bsize = blocksize; if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fhc->fsize, GNUNET_NO, GNUNET_YES)) { GNUNET_free (fhc->filename); GNUNET_free (fhc); return NULL; } fhc->fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); if (!fhc->fh) { GNUNET_free (fhc->filename); GNUNET_free (fhc); return NULL; } fhc->priority = priority; fhc->task = GNUNET_SCHEDULER_add_with_priority (priority, &file_hash_task, fhc); return fhc; } /** * Cancel a file hashing operation. * * @param fhc operation to cancel (callback must not yet have been invoked) */ void GNUNET_CRYPTO_hash_file_cancel (struct GNUNET_CRYPTO_FileHashContext *fhc) { GNUNET_SCHEDULER_cancel (fhc->task); GNUNET_free (fhc->filename); GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fhc->fh)); GNUNET_free (fhc); } /* ***************** binary-ASCII encoding *************** */ /** * Convert GNUNET_CRYPTO_hash to ASCII encoding. The ASCII encoding is rather * GNUnet specific. It was chosen such that it only uses characters * in [0-9A-V], can be produced without complex arithmetics and uses a * small number of characters. The GNUnet encoding uses 103 * characters plus a null terminator. * * @param block the hash code * @param result where to store the encoding (struct GNUNET_CRYPTO_HashAsciiEncoded can be * safely cast to char*, a '\\0' termination is set). */ void GNUNET_CRYPTO_hash_to_enc (const GNUNET_HashCode * block, struct GNUNET_CRYPTO_HashAsciiEncoded *result) { char *np; np = GNUNET_STRINGS_data_to_string ((const unsigned char *) block, sizeof (struct GNUNET_HashCode), (char*) result, sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1); GNUNET_assert (NULL != np); *np = '\0'; } /** * Convert ASCII encoding back to hash code. * * @param enc the encoding * @param enclen number of characters in 'enc' (without 0-terminator, which can be missing) * @param result where to store the hash code * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding */ int GNUNET_CRYPTO_hash_from_string2 (const char *enc, size_t enclen, GNUNET_HashCode * result) { char upper_enc[enclen]; char* up_ptr = upper_enc; GNUNET_STRINGS_utf8_toupper(enc, &up_ptr); return GNUNET_STRINGS_string_to_data (upper_enc, enclen, (unsigned char*) result, sizeof (struct GNUNET_HashCode)); } /** * Compute the distance between 2 hashcodes. The computation must be * fast, not involve bits[0] or bits[4] (they're used elsewhere), and be * somewhat consistent. And of course, the result should be a positive * number. * * @param a some hash code * @param b some hash code * @return a positive number which is a measure for * hashcode proximity. */ unsigned int GNUNET_CRYPTO_hash_distance_u32 (const GNUNET_HashCode * a, const GNUNET_HashCode * b) { unsigned int x1 = (a->bits[1] - b->bits[1]) >> 16; unsigned int x2 = (b->bits[1] - a->bits[1]) >> 16; return (x1 * x2); } /** * Create a random hash code. * * @param mode desired quality level * @param result hash code that is randomized */ void GNUNET_CRYPTO_hash_create_random (enum GNUNET_CRYPTO_Quality mode, GNUNET_HashCode * result) { int i; for (i = (sizeof (GNUNET_HashCode) / sizeof (uint32_t)) - 1; i >= 0; i--) result->bits[i] = GNUNET_CRYPTO_random_u32 (mode, UINT32_MAX); } /** * compute result(delta) = b - a * * @param a some hash code * @param b some hash code * @param result set to b - a */ void GNUNET_CRYPTO_hash_difference (const GNUNET_HashCode * a, const GNUNET_HashCode * b, GNUNET_HashCode * result) { int i; for (i = (sizeof (GNUNET_HashCode) / sizeof (unsigned int)) - 1; i >= 0; i--) result->bits[i] = b->bits[i] - a->bits[i]; } /** * compute result(b) = a + delta * * @param a some hash code * @param delta some hash code * @param result set to a + delta */ void GNUNET_CRYPTO_hash_sum (const GNUNET_HashCode * a, const GNUNET_HashCode * delta, GNUNET_HashCode * result) { int i; for (i = (sizeof (GNUNET_HashCode) / sizeof (unsigned int)) - 1; i >= 0; i--) result->bits[i] = delta->bits[i] + a->bits[i]; } /** * compute result = a ^ b * * @param a some hash code * @param b some hash code * @param result set to a ^ b */ void GNUNET_CRYPTO_hash_xor (const GNUNET_HashCode * a, const GNUNET_HashCode * b, GNUNET_HashCode * result) { int i; for (i = (sizeof (GNUNET_HashCode) / sizeof (unsigned int)) - 1; i >= 0; i--) result->bits[i] = a->bits[i] ^ b->bits[i]; } /** * Convert a hashcode into a key. * * @param hc hash code that serves to generate the key * @param skey set to a valid session key * @param iv set to a valid initialization vector */ void GNUNET_CRYPTO_hash_to_aes_key (const GNUNET_HashCode * hc, struct GNUNET_CRYPTO_AesSessionKey *skey, struct GNUNET_CRYPTO_AesInitializationVector *iv) { GNUNET_assert (sizeof (GNUNET_HashCode) >= GNUNET_CRYPTO_AES_KEY_LENGTH + sizeof (struct GNUNET_CRYPTO_AesInitializationVector)); memcpy (skey, hc, GNUNET_CRYPTO_AES_KEY_LENGTH); skey->crc32 = htonl (GNUNET_CRYPTO_crc32_n (skey, GNUNET_CRYPTO_AES_KEY_LENGTH)); memcpy (iv, &((char *) hc)[GNUNET_CRYPTO_AES_KEY_LENGTH], sizeof (struct GNUNET_CRYPTO_AesInitializationVector)); } /** * Obtain a bit from a hashcode. * @param code the GNUNET_CRYPTO_hash to index bit-wise * @param bit index into the hashcode, [0...511] * @return Bit \a bit from hashcode \a code, -1 for invalid index */ int GNUNET_CRYPTO_hash_get_bit (const GNUNET_HashCode * code, unsigned int bit) { GNUNET_assert (bit < 8 * sizeof (GNUNET_HashCode)); return (((unsigned char *) code)[bit >> 3] & (1 << (bit & 7))) > 0; } /** * Determine how many low order bits match in two * GNUNET_HashCodes. i.e. - 010011 and 011111 share * the first two lowest order bits, and therefore the * return value is two (NOT XOR distance, nor how many * bits match absolutely!). * * @param first the first hashcode * @param second the hashcode to compare first to * * @return the number of bits that match */ unsigned int GNUNET_CRYPTO_hash_matching_bits (const GNUNET_HashCode * first, const GNUNET_HashCode * second) { unsigned int i; for (i = 0; i < sizeof (GNUNET_HashCode) * 8; i++) if (GNUNET_CRYPTO_hash_get_bit (first, i) != GNUNET_CRYPTO_hash_get_bit (second, i)) return i; return sizeof (GNUNET_HashCode) * 8; } /** * Compare function for HashCodes, producing a total ordering * of all hashcodes. * * @param h1 some hash code * @param h2 some hash code * @return 1 if h1 > h2, -1 if h1 < h2 and 0 if h1 == h2. */ int GNUNET_CRYPTO_hash_cmp (const GNUNET_HashCode * h1, const GNUNET_HashCode * h2) { unsigned int *i1; unsigned int *i2; int i; i1 = (unsigned int *) h1; i2 = (unsigned int *) h2; for (i = (sizeof (GNUNET_HashCode) / sizeof (unsigned int)) - 1; i >= 0; i--) { if (i1[i] > i2[i]) return 1; if (i1[i] < i2[i]) return -1; } return 0; } /** * Find out which of the two GNUNET_CRYPTO_hash codes is closer to target * in the XOR metric (Kademlia). * * @param h1 some hash code * @param h2 some hash code * @param target some hash code * @return -1 if h1 is closer, 1 if h2 is closer and 0 if h1==h2. */ int GNUNET_CRYPTO_hash_xorcmp (const GNUNET_HashCode * h1, const GNUNET_HashCode * h2, const GNUNET_HashCode * target) { int i; unsigned int d1; unsigned int d2; for (i = sizeof (GNUNET_HashCode) / sizeof (unsigned int) - 1; i >= 0; i--) { d1 = ((unsigned int *) h1)[i] ^ ((unsigned int *) target)[i]; d2 = ((unsigned int *) h2)[i] ^ ((unsigned int *) target)[i]; if (d1 > d2) return 1; else if (d1 < d2) return -1; } return 0; } /** * @brief Derive an authentication key * @param key authentication key * @param rkey root key * @param salt salt * @param salt_len size of the salt * @param ... pair of void * & size_t for context chunks, terminated by NULL */ void GNUNET_CRYPTO_hmac_derive_key (struct GNUNET_CRYPTO_AuthKey *key, const struct GNUNET_CRYPTO_AesSessionKey *rkey, const void *salt, size_t salt_len, ...) { va_list argp; va_start (argp, salt_len); GNUNET_CRYPTO_hmac_derive_key_v (key, rkey, salt, salt_len, argp); va_end (argp); } /** * @brief Derive an authentication key * @param key authentication key * @param rkey root key * @param salt salt * @param salt_len size of the salt * @param argp pair of void * & size_t for context chunks, terminated by NULL */ void GNUNET_CRYPTO_hmac_derive_key_v (struct GNUNET_CRYPTO_AuthKey *key, const struct GNUNET_CRYPTO_AesSessionKey *rkey, const void *salt, size_t salt_len, va_list argp) { GNUNET_CRYPTO_kdf_v (key->key, sizeof (key->key), salt, salt_len, rkey->key, sizeof (rkey->key), argp); } /** * Calculate HMAC of a message (RFC 2104) * * @param key secret key * @param plaintext input plaintext * @param plaintext_len length of plaintext * @param hmac where to store the hmac */ void GNUNET_CRYPTO_hmac (const struct GNUNET_CRYPTO_AuthKey *key, const void *plaintext, size_t plaintext_len, GNUNET_HashCode * hmac) { gcry_md_hd_t md; const unsigned char *mc; GNUNET_assert (GPG_ERR_NO_ERROR == gcry_md_open (&md, GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC)); gcry_md_setkey (md, key->key, sizeof (key->key)); gcry_md_write (md, plaintext, plaintext_len); mc = gcry_md_read (md, GCRY_MD_SHA512); if (mc != NULL) memcpy (hmac->bits, mc, sizeof (hmac->bits)); gcry_md_close (md); } /** * Double short (256-bit) hash to create a long hash. * * @param sh short hash to double * @param dh where to store the (doubled) long hash (not really a hash) */ void GNUNET_CRYPTO_short_hash_double (const struct GNUNET_CRYPTO_ShortHashCode *sh, struct GNUNET_HashCode *dh) { char *ptr; ptr = (char*) dh; memcpy (ptr, sh, sizeof (struct GNUNET_CRYPTO_ShortHashCode)); memcpy (&ptr[sizeof (struct GNUNET_CRYPTO_ShortHashCode)], sh, sizeof (struct GNUNET_CRYPTO_ShortHashCode)); } /** * Truncate doubled short hash back to a short hash. * * @param dh doubled short hash to reduce again * @param sh where to store the short hash * @return GNUNET_OK on success, GNUNET_SYSERR if this was not a * doubled short hash */ int GNUNET_CRYPTO_short_hash_from_truncation (const struct GNUNET_HashCode *dh, struct GNUNET_CRYPTO_ShortHashCode *sh) { const struct GNUNET_CRYPTO_ShortHashCode *s; s = (const struct GNUNET_CRYPTO_ShortHashCode *) dh; if (0 != memcmp (&s[0], &s[1], sizeof (struct GNUNET_CRYPTO_ShortHashCode))) return GNUNET_SYSERR; *sh = *s; return GNUNET_OK; } /** * Convert ASCII encoding back to a 'struct GNUNET_CRYPTO_ShortHash' * * @param enc the encoding * @param enclen number of characters in 'enc' (without 0-terminator, which can be missing) * @param result where to store the GNUNET_CRYPTO_hash code * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding */ int GNUNET_CRYPTO_short_hash_from_string2 (const char *enc, size_t enclen, struct GNUNET_CRYPTO_ShortHashCode * result) { char upper_enc[enclen]; char* up_ptr = upper_enc; GNUNET_STRINGS_utf8_toupper(enc, &up_ptr); return GNUNET_STRINGS_string_to_data (upper_enc, enclen, (unsigned char*) result, sizeof (struct GNUNET_CRYPTO_ShortHashCode)); } /** * Convert short hash to ASCII encoding. * * @param block the hash code * @param result where to store the encoding (struct GNUNET_CRYPTO_ShortHashAsciiEncoded can be * safely cast to char*, a '\\0' termination is set). */ void GNUNET_CRYPTO_short_hash_to_enc (const struct GNUNET_CRYPTO_ShortHashCode * block, struct GNUNET_CRYPTO_ShortHashAsciiEncoded *result) { char *np; np = GNUNET_STRINGS_data_to_string ((const unsigned char *) block, sizeof (struct GNUNET_CRYPTO_ShortHashCode), (char*) result, sizeof (struct GNUNET_CRYPTO_ShortHashAsciiEncoded) - 1); GNUNET_assert (NULL != np); *np = '\0'; } /** * Compare function for ShortHashCodes, producing a total ordering * of all hashcodes. * * @param h1 some hash code * @param h2 some hash code * @return 1 if h1 > h2, -1 if h1 < h2 and 0 if h1 == h2. */ int GNUNET_CRYPTO_short_hash_cmp (const struct GNUNET_CRYPTO_ShortHashCode * h1, const struct GNUNET_CRYPTO_ShortHashCode * h2) { unsigned int *i1; unsigned int *i2; int i; i1 = (unsigned int *) h1; i2 = (unsigned int *) h2; for (i = (sizeof (struct GNUNET_CRYPTO_ShortHashCode) / sizeof (unsigned int)) - 1; i >= 0; i--) { if (i1[i] > i2[i]) return 1; if (i1[i] < i2[i]) return -1; } return 0; } /* end of crypto_hash.c */ gnunet-0.9.3/src/util/winproc.c0000644000175000017500000002415711762422575013361 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/winproc.c * @brief Functions for MS Windows * @author Nils Durner */ #include "platform.h" #include "gnunet_common.h" #ifdef MINGW static HINSTANCE hNTDLL, hIphlpapi, hAdvapi, hNetapi; #ifdef W32_VEH static void *GNWinVEH_handle = NULL; #endif TNtQuerySystemInformation GNNtQuerySystemInformation; TGetIfEntry GNGetIfEntry; TGetIpAddrTable GNGetIpAddrTable; TGetIfTable GNGetIfTable; TOpenSCManager GNOpenSCManager; TCreateService GNCreateService; TCloseServiceHandle GNCloseServiceHandle; TDeleteService GNDeleteService; TRegisterServiceCtrlHandler GNRegisterServiceCtrlHandler; TSetServiceStatus GNSetServiceStatus; TStartServiceCtrlDispatcher GNStartServiceCtrlDispatcher; TControlService GNControlService; TOpenService GNOpenService; TGetBestInterfaceEx GNGetBestInterfaceEx; TGetAdaptersInfo GNGetAdaptersInfo; TNetUserAdd GNNetUserAdd; TNetUserSetInfo GNNetUserSetInfo; TLsaOpenPolicy GNLsaOpenPolicy; TLsaAddAccountRights GNLsaAddAccountRights; TLsaRemoveAccountRights GNLsaRemoveAccountRights; TLsaClose GNLsaClose; TLookupAccountName GNLookupAccountName; TGetFileSecurity GNGetFileSecurity; TInitializeSecurityDescriptor GNInitializeSecurityDescriptor; TGetSecurityDescriptorDacl GNGetSecurityDescriptorDacl; TGetAclInformation GNGetAclInformation; TInitializeAcl GNInitializeAcl; TGetAce GNGetAce; TEqualSid GNEqualSid; TAddAce GNAddAce; TAddAccessAllowedAce GNAddAccessAllowedAce; TSetNamedSecurityInfo GNSetNamedSecurityInfo; #define LOG(kind,...) GNUNET_log_from (kind, "winproc", __VA_ARGS__) /** * Log (panic) messages from PlibC */ void plibc_panic (int err, char *msg) { LOG (((err == INT_MAX) ? GNUNET_ERROR_TYPE_DEBUG : GNUNET_ERROR_TYPE_ERROR), "%s", msg); } #ifdef W32_VEH /** * Handles exceptions (useful for debugging). * Issues a DebugBreak() call if the process is being debugged (not really * useful - if the process is being debugged, this handler won't be invoked * anyway). If it is not, runs a debugger from GNUNET_DEBUGGER env var, * substituting first %u in it for PID, and the second one for the event, * that should be set once the debugger attaches itself (otherwise the * only way out of WaitForSingleObject() is to time out after 1 minute). */ LONG __stdcall GNWinVEH (PEXCEPTION_POINTERS ExceptionInfo) { char debugger[MAX_PATH + 1]; char *debugger_env = NULL; if (IsDebuggerPresent ()) { DebugBreak (); return EXCEPTION_CONTINUE_EXECUTION; } debugger_env = getenv ("GNUNET_DEBUGGER"); if (debugger_env != NULL) { STARTUPINFO si; PROCESS_INFORMATION pi; HANDLE event; SECURITY_ATTRIBUTES sa; memset (&si, 0, sizeof (si)); si.cb = sizeof (si); memset (&pi, 0, sizeof (pi)); memset (&sa, 0, sizeof (sa)); sa.nLength = sizeof (sa); sa.bInheritHandle = TRUE; event = CreateEvent (&sa, FALSE, FALSE, NULL); snprintf (debugger, MAX_PATH + 1, debugger_env, GetCurrentProcessId (), (uintptr_t) event); debugger[MAX_PATH] = '\0'; if (0 != CreateProcessA (NULL, debugger, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) { CloseHandle (pi.hProcess); CloseHandle (pi.hThread); WaitForSingleObject (event, 60000); CloseHandle (event); if (IsDebuggerPresent ()) { return EXCEPTION_CONTINUE_EXECUTION; } } else CloseHandle (event); } return EXCEPTION_CONTINUE_SEARCH; } #endif /** * @brief Initialize PlibC and set up Windows environment * @param logging context, NULL means stderr * @return Error code from winerror.h, ERROR_SUCCESS on success */ int GNInitWinEnv () { int ret; plibc_initialized (); plibc_set_panic_proc (plibc_panic); ret = plibc_init_utf8 ("GNU", PACKAGE, 1); /* don't load other DLLs twice */ if (hNTDLL) return ret; #ifdef W32_VEH if (GNWinVEH_handle == NULL) { GNWinVEH_handle = AddVectoredExceptionHandler (1, &GNWinVEH); if (GNWinVEH_handle == NULL) { /* This is bad, but what can we do? */ printf ("Failed to set up an exception handler!\n"); } } #endif hNTDLL = LoadLibrary ("ntdll.dll"); /* Function to get CPU usage under Win NT */ if (hNTDLL) { GNNtQuerySystemInformation = (TNtQuerySystemInformation) GetProcAddress (hNTDLL, "NtQuerySystemInformation"); } else { GNNtQuerySystemInformation = NULL; } /* Functions to get information about a network adapter */ hIphlpapi = LoadLibrary ("iphlpapi.dll"); if (hIphlpapi) { GNGetIfEntry = (TGetIfEntry) GetProcAddress (hIphlpapi, "GetIfEntry"); GNGetIpAddrTable = (TGetIpAddrTable) GetProcAddress (hIphlpapi, "GetIpAddrTable"); GNGetIfTable = (TGetIfTable) GetProcAddress (hIphlpapi, "GetIfTable"); GNGetBestInterfaceEx = (TGetBestInterfaceEx) GetProcAddress (hIphlpapi, "GetBestInterfaceEx"); GNGetAdaptersInfo = (TGetAdaptersInfo) GetProcAddress (hIphlpapi, "GetAdaptersInfo"); } else { GNGetIfEntry = NULL; GNGetIpAddrTable = NULL; GNGetIfTable = NULL; GNGetBestInterfaceEx = NULL; GNGetAdaptersInfo = NULL; } /* Service & Account functions */ hAdvapi = LoadLibrary ("advapi32.dll"); if (hAdvapi) { GNOpenSCManager = (TOpenSCManager) GetProcAddress (hAdvapi, "OpenSCManagerA"); GNCreateService = (TCreateService) GetProcAddress (hAdvapi, "CreateServiceA"); GNCloseServiceHandle = (TCloseServiceHandle) GetProcAddress (hAdvapi, "CloseServiceHandle"); GNDeleteService = (TDeleteService) GetProcAddress (hAdvapi, "DeleteService"); GNRegisterServiceCtrlHandler = (TRegisterServiceCtrlHandler) GetProcAddress (hAdvapi, "RegisterServiceCtrlHandlerA"); GNSetServiceStatus = (TSetServiceStatus) GetProcAddress (hAdvapi, "SetServiceStatus"); GNStartServiceCtrlDispatcher = (TStartServiceCtrlDispatcher) GetProcAddress (hAdvapi, "StartServiceCtrlDispatcherA"); GNControlService = (TControlService) GetProcAddress (hAdvapi, "ControlService"); GNOpenService = (TOpenService) GetProcAddress (hAdvapi, "OpenServiceA"); GNLsaOpenPolicy = (TLsaOpenPolicy) GetProcAddress (hAdvapi, "LsaOpenPolicy"); GNLsaAddAccountRights = (TLsaAddAccountRights) GetProcAddress (hAdvapi, "LsaAddAccountRights"); GNLsaRemoveAccountRights = (TLsaRemoveAccountRights) GetProcAddress (hAdvapi, "LsaRemoveAccountRights"); GNLsaClose = (TLsaClose) GetProcAddress (hAdvapi, "LsaClose"); GNLookupAccountName = (TLookupAccountName) GetProcAddress (hAdvapi, "LookupAccountNameA"); GNGetFileSecurity = (TGetFileSecurity) GetProcAddress (hAdvapi, "GetFileSecurityA"); GNInitializeSecurityDescriptor = (TInitializeSecurityDescriptor) GetProcAddress (hAdvapi, "InitializeSecurityDescriptor"); GNGetSecurityDescriptorDacl = (TGetSecurityDescriptorDacl) GetProcAddress (hAdvapi, "GetSecurityDescriptorDacl"); GNGetAclInformation = (TGetAclInformation) GetProcAddress (hAdvapi, "GetAclInformation"); GNInitializeAcl = (TInitializeAcl) GetProcAddress (hAdvapi, "InitializeAcl"); GNGetAce = (TGetAce) GetProcAddress (hAdvapi, "GetAce"); GNEqualSid = (TEqualSid) GetProcAddress (hAdvapi, "EqualSid"); GNAddAce = (TAddAce) GetProcAddress (hAdvapi, "AddAce"); GNAddAccessAllowedAce = (TAddAccessAllowedAce) GetProcAddress (hAdvapi, "AddAccessAllowedAce"); GNSetNamedSecurityInfo = (TSetNamedSecurityInfo) GetProcAddress (hAdvapi, "SetNamedSecurityInfoA"); } else { GNOpenSCManager = NULL; GNCreateService = NULL; GNCloseServiceHandle = NULL; GNDeleteService = NULL; GNRegisterServiceCtrlHandler = NULL; GNSetServiceStatus = NULL; GNStartServiceCtrlDispatcher = NULL; GNControlService = NULL; GNOpenService = NULL; GNLsaOpenPolicy = NULL; GNLsaAddAccountRights = NULL; GNLsaRemoveAccountRights = NULL; GNLsaClose = NULL; GNLookupAccountName = NULL; GNGetFileSecurity = NULL; GNInitializeSecurityDescriptor = NULL; GNGetSecurityDescriptorDacl = NULL; GNGetAclInformation = NULL; GNInitializeAcl = NULL; GNGetAce = NULL; GNEqualSid = NULL; GNAddAce = NULL; GNAddAccessAllowedAce = NULL; GNSetNamedSecurityInfo = NULL; } /* Account function */ hNetapi = LoadLibrary ("netapi32.dll"); if (hNetapi) { GNNetUserAdd = (TNetUserAdd) GetProcAddress (hNetapi, "NetUserAdd"); GNNetUserSetInfo = (TNetUserSetInfo) GetProcAddress (hNetapi, "NetUserSetInfo"); } else { GNNetUserAdd = NULL; GNNetUserSetInfo = NULL; } return ret; } /** * Clean up Windows environment */ void GNShutdownWinEnv () { plibc_shutdown (); #ifdef W32_VEH if (GNWinVEH_handle != NULL) { RemoveVectoredExceptionHandler (GNWinVEH_handle); GNWinVEH_handle = NULL; } #endif FreeLibrary (hNTDLL); FreeLibrary (hIphlpapi); FreeLibrary (hAdvapi); FreeLibrary (hNetapi); CoUninitialize (); } #endif /* MINGW */ #if !HAVE_ATOLL long long atoll (const char *nptr) { return atol (nptr); } #endif gnunet-0.9.3/src/util/disk.c0000644000175000017500000017244111760502551012621 00000000000000/* This file is part of GNUnet. (C) 2001--2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/disk.c * @brief disk IO convenience methods * @author Christian Grothoff * @author Nils Durner */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_directories.h" #include "gnunet_disk_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_strings_lib.h" #include "gnunet_crypto_lib.h" #include "disk.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) /** * Block size for IO for copying files. */ #define COPY_BLK_SIZE 65536 #if defined(LINUX) || defined(CYGWIN) #include #else #if defined(SOMEBSD) || defined(DARWIN) #include #include #else #ifdef SOLARIS #include #include #else #ifdef MINGW #ifndef PIPE_BUF #define PIPE_BUF 512 ULONG PipeSerialNumber; #endif #define _IFMT 0170000 /* type of file */ #define _IFLNK 0120000 /* symbolic link */ #define S_ISLNK(m) (((m)&_IFMT) == _IFLNK) #else #error PORT-ME: need to port statfs (how much space is left on the drive?) #endif #endif #endif #endif #if !defined(SOMEBSD) && !defined(DARWIN) && !defined(WINDOWS) #include #endif #if LINUX #include #endif /** * Handle used to manage a pipe. */ struct GNUNET_DISK_PipeHandle { /** * File descriptors for the pipe. */ struct GNUNET_DISK_FileHandle *fd[2]; }; /** * Closure for the recursion to determine the file size * of a directory. */ struct GetFileSizeData { /** * Set to the total file size. */ uint64_t total; /** * GNUNET_YES if symbolic links should be included. */ int include_sym_links; /** * GNUNET_YES if mode is file-only (return total == -1 for directories). */ int single_file_mode; }; #ifndef MINGW /** * Translate GNUnet-internal permission bitmap to UNIX file * access permission bitmap. * * @param perm file permissions, GNUnet style * @return file permissions, UNIX style */ static int translate_unix_perms (enum GNUNET_DISK_AccessPermissions perm) { int mode; mode = 0; if (perm & GNUNET_DISK_PERM_USER_READ) mode |= S_IRUSR; if (perm & GNUNET_DISK_PERM_USER_WRITE) mode |= S_IWUSR; if (perm & GNUNET_DISK_PERM_USER_EXEC) mode |= S_IXUSR; if (perm & GNUNET_DISK_PERM_GROUP_READ) mode |= S_IRGRP; if (perm & GNUNET_DISK_PERM_GROUP_WRITE) mode |= S_IWGRP; if (perm & GNUNET_DISK_PERM_GROUP_EXEC) mode |= S_IXGRP; if (perm & GNUNET_DISK_PERM_OTHER_READ) mode |= S_IROTH; if (perm & GNUNET_DISK_PERM_OTHER_WRITE) mode |= S_IWOTH; if (perm & GNUNET_DISK_PERM_OTHER_EXEC) mode |= S_IXOTH; return mode; } #endif /** * Iterate over all files in the given directory and * accumulate their size. * * @param cls closure of type "struct GetFileSizeData" * @param fn current filename we are looking at * @return GNUNET_SYSERR on serious errors, otherwise GNUNET_OK */ static int getSizeRec (void *cls, const char *fn) { struct GetFileSizeData *gfsd = cls; #ifdef HAVE_STAT64 struct stat64 buf; #else struct stat buf; #endif #ifdef HAVE_STAT64 if (0 != STAT64 (fn, &buf)) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "stat64", fn); return GNUNET_SYSERR; } #else if (0 != STAT (fn, &buf)) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "stat", fn); return GNUNET_SYSERR; } #endif if ((S_ISDIR (buf.st_mode)) && (gfsd->single_file_mode == GNUNET_YES)) { errno = EISDIR; return GNUNET_SYSERR; } if ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES)) gfsd->total += buf.st_size; if ((S_ISDIR (buf.st_mode)) && (0 == ACCESS (fn, X_OK)) && ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES))) { if (GNUNET_SYSERR == GNUNET_DISK_directory_scan (fn, &getSizeRec, gfsd)) return GNUNET_SYSERR; } return GNUNET_OK; } /** * Checks whether a handle is invalid * * @param h handle to check * @return GNUNET_YES if invalid, GNUNET_NO if valid */ int GNUNET_DISK_handle_invalid (const struct GNUNET_DISK_FileHandle *h) { #ifdef MINGW return ((!h) || (h->h == INVALID_HANDLE_VALUE)) ? GNUNET_YES : GNUNET_NO; #else return ((!h) || (h->fd == -1)) ? GNUNET_YES : GNUNET_NO; #endif } /** * Get the size of an open file. * * @param fh open file handle * @param size where to write size of the file * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_DISK_file_handle_size (struct GNUNET_DISK_FileHandle *fh, OFF_T *size) { #if WINDOWS BOOL b; LARGE_INTEGER li; b = GetFileSizeEx (fh->h, &li); if (!b) { SetErrnoFromWinError (GetLastError ()); return GNUNET_SYSERR; } *size = (OFF_T) li.QuadPart; #else struct stat sbuf; if (0 != FSTAT (fh->fd, &sbuf)) return GNUNET_SYSERR; *size = sbuf.st_size; #endif return GNUNET_OK; } /** * Move the read/write pointer in a file * * @param h handle of an open file * @param offset position to move to * @param whence specification to which position the offset parameter relates to * @return the new position on success, GNUNET_SYSERR otherwise */ OFF_T GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle * h, OFF_T offset, enum GNUNET_DISK_Seek whence) { if (h == NULL) { errno = EINVAL; return GNUNET_SYSERR; } #ifdef MINGW LARGE_INTEGER li; LARGE_INTEGER new_pos; BOOL b; static DWORD t[] = {[GNUNET_DISK_SEEK_SET] = FILE_BEGIN, [GNUNET_DISK_SEEK_CUR] = FILE_CURRENT,[GNUNET_DISK_SEEK_END] = FILE_END }; li.QuadPart = offset; b = SetFilePointerEx (h->h, li, &new_pos, t[whence]); if (b == 0) { SetErrnoFromWinError (GetLastError ()); return GNUNET_SYSERR; } return (OFF_T) new_pos.QuadPart; #else static int t[] = {[GNUNET_DISK_SEEK_SET] = SEEK_SET, [GNUNET_DISK_SEEK_CUR] = SEEK_CUR,[GNUNET_DISK_SEEK_END] = SEEK_END }; return lseek (h->fd, offset, t[whence]); #endif } /** * Get the size of the file (or directory) of the given file (in * bytes). * * @param filename name of the file or directory * @param size set to the size of the file (or, * in the case of directories, the sum * of all sizes of files in the directory) * @param includeSymLinks should symbolic links be * included? * @param singleFileMode GNUNET_YES to only get size of one file * and return GNUNET_SYSERR for directories. * @return GNUNET_SYSERR on error, GNUNET_OK on success */ int GNUNET_DISK_file_size (const char *filename, uint64_t * size, int includeSymLinks, int singleFileMode) { struct GetFileSizeData gfsd; int ret; GNUNET_assert (size != NULL); gfsd.total = 0; gfsd.include_sym_links = includeSymLinks; gfsd.single_file_mode = singleFileMode; ret = getSizeRec (&gfsd, filename); *size = gfsd.total; return ret; } /** * Obtain some unique identifiers for the given file * that can be used to identify it in the local system. * This function is used between GNUnet processes to * quickly check if two files with the same absolute path * are actually identical. The two processes represent * the same peer but may communicate over the network * (and the file may be on an NFS volume). This function * may not be supported on all operating systems. * * @param filename name of the file * @param dev set to the device ID * @param ino set to the inode ID * @return GNUNET_OK on success */ int GNUNET_DISK_file_get_identifiers (const char *filename, uint64_t * dev, uint64_t * ino) { #if LINUX struct stat sbuf; struct statvfs fbuf; if ((0 == stat (filename, &sbuf)) && (0 == statvfs (filename, &fbuf))) { *dev = (uint64_t) fbuf.f_fsid; *ino = (uint64_t) sbuf.st_ino; return GNUNET_OK; } #elif SOMEBSD struct stat sbuf; struct statfs fbuf; if ((0 == stat (filename, &sbuf)) && (0 == statfs (filename, &fbuf))) { *dev = ((uint64_t) fbuf.f_fsid.val[0]) << 32 || ((uint64_t) fbuf.f_fsid.val[1]); *ino = (uint64_t) sbuf.st_ino; return GNUNET_OK; } #elif WINDOWS // FIXME NILS: test this struct GNUNET_DISK_FileHandle *fh; BY_HANDLE_FILE_INFORMATION info; int succ; fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, 0); if (fh == NULL) return GNUNET_SYSERR; succ = GetFileInformationByHandle (fh->h, &info); GNUNET_DISK_file_close (fh); if (succ) { *dev = info.dwVolumeSerialNumber; *ino = ((((uint64_t) info.nFileIndexHigh) << (sizeof (DWORD) * 8)) | info.nFileIndexLow); return GNUNET_OK; } else return GNUNET_SYSERR; #endif return GNUNET_SYSERR; } /** * Create an (empty) temporary file on disk. If the given name is not * an absolute path, the current 'TMPDIR' will be prepended. In any case, * 6 random characters will be appended to the name to create a unique * filename. * * @param t component to use for the name; * does NOT contain "XXXXXX" or "/tmp/". * @return NULL on error, otherwise name of fresh * file on disk in directory for temporary files */ char * GNUNET_DISK_mktemp (const char *t) { const char *tmpdir; int fd; char *tmpl; char *fn; if ((t[0] != '/') && (t[0] != '\\') #if WINDOWS && !(isalpha ((int) t[0]) && (t[0] != '\0') && (t[1] == ':')) #endif ) { /* FIXME: This uses system codepage on W32, not UTF-8 */ tmpdir = getenv ("TMPDIR"); tmpdir = tmpdir ? tmpdir : "/tmp"; GNUNET_asprintf (&tmpl, "%s/%s%s", tmpdir, t, "XXXXXX"); } else { GNUNET_asprintf (&tmpl, "%s%s", t, "XXXXXX"); } #ifdef MINGW fn = (char *) GNUNET_malloc (MAX_PATH + 1); if (ERROR_SUCCESS != plibc_conv_to_win_path (tmpl, fn)) { GNUNET_free (fn); GNUNET_free (tmpl); return NULL; } GNUNET_free (tmpl); #else fn = tmpl; #endif /* FIXME: why is this not MKSTEMP()? This function is implemented in plibc. * CG: really? If I put MKSTEMP here, I get a compilation error... * It will assume that fn is UTF-8-encoded, if compiled with UTF-8 support. */ fd = mkstemp (fn); if (fd == -1) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkstemp", fn); GNUNET_free (fn); return NULL; } if (0 != CLOSE (fd)) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "close", fn); return fn; } /** * Get the number of blocks that are left on the partition that * contains the given file (for normal users). * * @param part a file on the partition to check * @return -1 on errors, otherwise the number of free blocks */ long GNUNET_DISK_get_blocks_available (const char *part) { #ifdef SOLARIS struct statvfs buf; if (0 != statvfs (part, &buf)) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "statfs", part); return -1; } return buf.f_bavail; #elif MINGW DWORD dwDummy; DWORD dwBlocks; wchar_t szDrive[4]; wchar_t wpath[MAX_PATH + 1]; char *path; path = GNUNET_STRINGS_filename_expand (part); if (path == NULL) return -1; /* "part" was in UTF-8, and so is "path" */ if (ERROR_SUCCESS != plibc_conv_to_win_pathwconv(path, wpath)) { GNUNET_free (path); return -1; } GNUNET_free (path); wcsncpy (szDrive, wpath, 3); szDrive[3] = 0; if (!GetDiskFreeSpaceW (szDrive, &dwDummy, &dwDummy, &dwBlocks, &dwDummy)) { LOG (GNUNET_ERROR_TYPE_WARNING, _("`%s' failed for drive `%S': %u\n"), "GetDiskFreeSpace", szDrive, GetLastError ()); return -1; } return dwBlocks; #else struct statfs s; if (0 != statfs (part, &s)) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "statfs", part); return -1; } return s.f_bavail; #endif } /** * Test if "fil" is a directory. * Will not print an error message if the directory * does not exist. Will log errors if GNUNET_SYSERR is * returned (i.e., a file exists with the same name). * * @param fil filename to test * @return GNUNET_YES if yes, GNUNET_NO if not, GNUNET_SYSERR if it * does not exist */ int GNUNET_DISK_directory_test (const char *fil) { struct stat filestat; int ret; ret = STAT (fil, &filestat); if (ret != 0) { if (errno != ENOENT) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", fil); return GNUNET_SYSERR; } return GNUNET_NO; } if (!S_ISDIR (filestat.st_mode)) return GNUNET_NO; if (ACCESS (fil, R_OK | X_OK) < 0) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", fil); return GNUNET_SYSERR; } return GNUNET_YES; } /** * Check that fil corresponds to a filename * (of a file that exists and that is not a directory). * * @param fil filename to check * @return GNUNET_YES if yes, GNUNET_NO if not a file, GNUNET_SYSERR if something * else (will print an error message in that case, too). */ int GNUNET_DISK_file_test (const char *fil) { struct stat filestat; int ret; char *rdir; rdir = GNUNET_STRINGS_filename_expand (fil); if (rdir == NULL) return GNUNET_SYSERR; ret = STAT (rdir, &filestat); if (ret != 0) { if (errno != ENOENT) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", rdir); GNUNET_free (rdir); return GNUNET_SYSERR; } GNUNET_free (rdir); return GNUNET_NO; } if (!S_ISREG (filestat.st_mode)) { GNUNET_free (rdir); return GNUNET_NO; } if (ACCESS (rdir, R_OK) < 0) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", rdir); GNUNET_free (rdir); return GNUNET_SYSERR; } GNUNET_free (rdir); return GNUNET_YES; } /** * Implementation of "mkdir -p" * @param dir the directory to create * @returns GNUNET_OK on success, GNUNET_SYSERR on failure */ int GNUNET_DISK_directory_create (const char *dir) { char *rdir; int len; int pos; int ret = GNUNET_OK; rdir = GNUNET_STRINGS_filename_expand (dir); if (rdir == NULL) return GNUNET_SYSERR; len = strlen (rdir); #ifndef MINGW pos = 1; /* skip heading '/' */ #else /* Local or Network path? */ if (strncmp (rdir, "\\\\", 2) == 0) { pos = 2; while (rdir[pos]) { if (rdir[pos] == '\\') { pos++; break; } pos++; } } else { pos = 3; /* strlen("C:\\") */ } #endif while (pos <= len) { if ((rdir[pos] == DIR_SEPARATOR) || (pos == len)) { rdir[pos] = '\0'; ret = GNUNET_DISK_directory_test (rdir); if (ret == GNUNET_SYSERR) { GNUNET_free (rdir); return GNUNET_SYSERR; } if (ret == GNUNET_NO) { #ifndef MINGW ret = mkdir (rdir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); /* 755 */ #else wchar_t wrdir[MAX_PATH + 1]; if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(rdir, wrdir)) ret = !CreateDirectoryW (wrdir, NULL); else ret = 1; #endif if ((ret != 0) && (errno != EEXIST)) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkdir", rdir); GNUNET_free (rdir); return GNUNET_SYSERR; } } rdir[pos] = DIR_SEPARATOR; } pos++; } GNUNET_free (rdir); return GNUNET_OK; } /** * Create the directory structure for storing * a file. * * @param filename name of a file in the directory * @returns GNUNET_OK on success, * GNUNET_SYSERR on failure, * GNUNET_NO if the directory * exists but is not writeable for us */ int GNUNET_DISK_directory_create_for_file (const char *filename) { char *rdir; int len; int ret; rdir = GNUNET_STRINGS_filename_expand (filename); if (rdir == NULL) return GNUNET_SYSERR; len = strlen (rdir); while ((len > 0) && (rdir[len] != DIR_SEPARATOR)) len--; rdir[len] = '\0'; ret = GNUNET_DISK_directory_create (rdir); if ((ret == GNUNET_OK) && (0 != ACCESS (rdir, W_OK))) ret = GNUNET_NO; GNUNET_free (rdir); return ret; } /** * Read the contents of a binary file into a buffer. * @param h handle to an open file * @param result the buffer to write the result to * @param len the maximum number of bytes to read * @return the number of bytes read on success, GNUNET_SYSERR on failure */ ssize_t GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle * h, void *result, size_t len) { if (h == NULL) { errno = EINVAL; return GNUNET_SYSERR; } #ifdef MINGW DWORD bytesRead; if (h->type != GNUNET_PIPE) { if (!ReadFile (h->h, result, len, &bytesRead, NULL)) { SetErrnoFromWinError (GetLastError ()); return GNUNET_SYSERR; } } else { if (!ReadFile (h->h, result, len, &bytesRead, h->oOverlapRead)) { if (GetLastError () != ERROR_IO_PENDING) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ()); SetErrnoFromWinError (GetLastError ()); return GNUNET_SYSERR; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n"); GetOverlappedResult (h->h, h->oOverlapRead, &bytesRead, TRUE); } LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes from pipe\n", bytesRead); } return bytesRead; #else return read (h->fd, result, len); #endif } /** * Read the contents of a binary file into a buffer. * Guarantees not to block (returns GNUNET_SYSERR and sets errno to EAGAIN * when no data can be read). * * @param h handle to an open file * @param result the buffer to write the result to * @param len the maximum number of bytes to read * @return the number of bytes read on success, GNUNET_SYSERR on failure */ ssize_t GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle * h, void *result, size_t len) { if (h == NULL) { errno = EINVAL; return GNUNET_SYSERR; } #ifdef MINGW DWORD bytesRead; if (h->type != GNUNET_PIPE) { if (!ReadFile (h->h, result, len, &bytesRead, NULL)) { SetErrnoFromWinError (GetLastError ()); return GNUNET_SYSERR; } } else { if (!ReadFile (h->h, result, len, &bytesRead, h->oOverlapRead)) { if (GetLastError () != ERROR_IO_PENDING) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ()); SetErrnoFromWinError (GetLastError ()); return GNUNET_SYSERR; } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "ReadFile() queued a read, cancelling\n"); CancelIo (h->h); errno = EAGAIN; return GNUNET_SYSERR; } } LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes\n", bytesRead); } return bytesRead; #else int flags; ssize_t ret; /* set to non-blocking, read, then set back */ flags = fcntl (h->fd, F_GETFL); if (0 == (flags & O_NONBLOCK)) fcntl (h->fd, F_SETFL, flags | O_NONBLOCK); ret = read (h->fd, result, len); if (0 == (flags & O_NONBLOCK)) fcntl (h->fd, F_SETFL, flags); return ret; #endif } /** * Read the contents of a binary file into a buffer. * * @param fn file name * @param result the buffer to write the result to * @param len the maximum number of bytes to read * @return number of bytes read, GNUNET_SYSERR on failure */ ssize_t GNUNET_DISK_fn_read (const char *fn, void *result, size_t len) { struct GNUNET_DISK_FileHandle *fh; ssize_t ret; fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); if (!fh) return GNUNET_SYSERR; ret = GNUNET_DISK_file_read (fh, result, len); GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); return ret; } /** * Write a buffer to a file. * @param h handle to open file * @param buffer the data to write * @param n number of bytes to write * @return number of bytes written on success, GNUNET_SYSERR on error */ ssize_t GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle * h, const void *buffer, size_t n) { if (h == NULL) { errno = EINVAL; return GNUNET_SYSERR; } #ifdef MINGW DWORD bytesWritten; if (h->type != GNUNET_PIPE) { if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL)) { SetErrnoFromWinError (GetLastError ()); return GNUNET_SYSERR; } } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "It is a pipe trying to write %u bytes\n", n); if (!WriteFile (h->h, buffer, n, &bytesWritten, h->oOverlapWrite)) { if (GetLastError () != ERROR_IO_PENDING) { SetErrnoFromWinError (GetLastError ()); LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n", GetLastError ()); return GNUNET_SYSERR; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n"); if (!GetOverlappedResult (h->h, h->oOverlapWrite, &bytesWritten, TRUE)) { SetErrnoFromWinError (GetLastError ()); LOG (GNUNET_ERROR_TYPE_DEBUG, "Error getting overlapped result while writing to pipe: %u\n", GetLastError ()); return GNUNET_SYSERR; } } else { DWORD ovr; if (!GetOverlappedResult (h->h, h->oOverlapWrite, &ovr, TRUE)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Error getting control overlapped result while writing to pipe: %u\n", GetLastError ()); } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes (ovr says %u), picking the greatest\n", bytesWritten, ovr); } } if (bytesWritten == 0) { if (n > 0) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes, returning -1 with EAGAIN\n", bytesWritten); errno = EAGAIN; return GNUNET_SYSERR; } } LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten); } return bytesWritten; #else return write (h->fd, buffer, n); #endif } /** * Write a buffer to a file, blocking, if necessary. * @param h handle to open file * @param buffer the data to write * @param n number of bytes to write * @return number of bytes written on success, GNUNET_SYSERR on error */ ssize_t GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle * h, const void *buffer, size_t n) { if (h == NULL) { errno = EINVAL; return GNUNET_SYSERR; } #ifdef MINGW DWORD bytesWritten; /* We do a non-overlapped write, which is as blocking as it gets */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing %u bytes\n", n); if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL)) { SetErrnoFromWinError (GetLastError ()); LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n", GetLastError ()); return GNUNET_SYSERR; } if (bytesWritten == 0 && n > 0) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for pipe to clean\n"); WaitForSingleObject (h->h, INFINITE); if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL)) { SetErrnoFromWinError (GetLastError ()); LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n", GetLastError ()); return GNUNET_SYSERR; } } LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten); return bytesWritten; #else int flags; ssize_t ret; /* set to blocking, write, then set back */ flags = fcntl (h->fd, F_GETFL); if (0 != (flags & O_NONBLOCK)) fcntl (h->fd, F_SETFL, flags - O_NONBLOCK); ret = write (h->fd, buffer, n); if (0 == (flags & O_NONBLOCK)) fcntl (h->fd, F_SETFL, flags); return ret; #endif } /** * Write a buffer to a file. If the file is longer than the * number of bytes that will be written, it will be truncated. * * @param fn file name * @param buffer the data to write * @param n number of bytes to write * @param mode file permissions * @return number of bytes written on success, GNUNET_SYSERR on error */ ssize_t GNUNET_DISK_fn_write (const char *fn, const void *buffer, size_t n, enum GNUNET_DISK_AccessPermissions mode) { struct GNUNET_DISK_FileHandle *fh; ssize_t ret; fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE | GNUNET_DISK_OPEN_CREATE, mode); if (!fh) return GNUNET_SYSERR; ret = GNUNET_DISK_file_write (fh, buffer, n); GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); return ret; } /** * Scan a directory for files. * * @param dirName the name of the directory * @param callback the method to call for each file, * can be NULL, in that case, we only count * @param callback_cls closure for callback * @return the number of files found, GNUNET_SYSERR on error or * ieration aborted by callback returning GNUNET_SYSERR */ int GNUNET_DISK_directory_scan (const char *dirName, GNUNET_FileNameCallback callback, void *callback_cls) { DIR *dinfo; struct dirent *finfo; struct stat istat; int count = 0; char *name; char *dname; unsigned int name_len; unsigned int n_size; GNUNET_assert (dirName != NULL); dname = GNUNET_STRINGS_filename_expand (dirName); if (dname == NULL) return GNUNET_SYSERR; while ((strlen (dname) > 0) && (dname[strlen (dname) - 1] == DIR_SEPARATOR)) dname[strlen (dname) - 1] = '\0'; if (0 != STAT (dname, &istat)) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", dname); GNUNET_free (dname); return GNUNET_SYSERR; } if (!S_ISDIR (istat.st_mode)) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Expected `%s' to be a directory!\n"), dirName); GNUNET_free (dname); return GNUNET_SYSERR; } errno = 0; dinfo = OPENDIR (dname); if ((errno == EACCES) || (dinfo == NULL)) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "opendir", dname); if (dinfo != NULL) CLOSEDIR (dinfo); GNUNET_free (dname); return GNUNET_SYSERR; } name_len = 256; n_size = strlen (dname) + name_len + 2; name = GNUNET_malloc (n_size); while ((finfo = READDIR (dinfo)) != NULL) { if ((0 == strcmp (finfo->d_name, ".")) || (0 == strcmp (finfo->d_name, ".."))) continue; if (callback != NULL) { if (name_len < strlen (finfo->d_name)) { GNUNET_free (name); name_len = strlen (finfo->d_name); n_size = strlen (dname) + name_len + 2; name = GNUNET_malloc (n_size); } /* dname can end in "/" only if dname == "/"; * if dname does not end in "/", we need to add * a "/" (otherwise, we must not!) */ GNUNET_snprintf (name, n_size, "%s%s%s", dname, (strcmp (dname, DIR_SEPARATOR_STR) == 0) ? "" : DIR_SEPARATOR_STR, finfo->d_name); if (GNUNET_OK != callback (callback_cls, name)) { CLOSEDIR (dinfo); GNUNET_free (name); GNUNET_free (dname); return GNUNET_SYSERR; } } count++; } CLOSEDIR (dinfo); GNUNET_free (name); GNUNET_free (dname); return count; } /** * Opaque handle used for iterating over a directory. */ struct GNUNET_DISK_DirectoryIterator { /** * Function to call on directory entries. */ GNUNET_DISK_DirectoryIteratorCallback callback; /** * Closure for callback. */ void *callback_cls; /** * Reference to directory. */ DIR *directory; /** * Directory name. */ char *dirname; /** * Next filename to process. */ char *next_name; /** * Our priority. */ enum GNUNET_SCHEDULER_Priority priority; }; /** * Task used by the directory iterator. */ static void directory_iterator_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_DISK_DirectoryIterator *iter = cls; char *name; name = iter->next_name; GNUNET_assert (name != NULL); iter->next_name = NULL; iter->callback (iter->callback_cls, iter, name, iter->dirname); GNUNET_free (name); } /** * This function must be called during the DiskIteratorCallback * (exactly once) to schedule the task to process the next * filename in the directory (if there is one). * * @param iter opaque handle for the iterator * @param can set to GNUNET_YES to terminate the iteration early * @return GNUNET_YES if iteration will continue, * GNUNET_NO if this was the last entry (and iteration is complete), * GNUNET_SYSERR if abort was YES */ int GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator *iter, int can) { struct dirent *finfo; GNUNET_assert (iter->next_name == NULL); if (can == GNUNET_YES) { CLOSEDIR (iter->directory); GNUNET_free (iter->dirname); GNUNET_free (iter); return GNUNET_SYSERR; } while (NULL != (finfo = READDIR (iter->directory))) { if ((0 == strcmp (finfo->d_name, ".")) || (0 == strcmp (finfo->d_name, ".."))) continue; GNUNET_asprintf (&iter->next_name, "%s%s%s", iter->dirname, DIR_SEPARATOR_STR, finfo->d_name); break; } if (finfo == NULL) { GNUNET_DISK_directory_iterator_next (iter, GNUNET_YES); return GNUNET_NO; } GNUNET_SCHEDULER_add_with_priority (iter->priority, &directory_iterator_task, iter); return GNUNET_YES; } /** * Scan a directory for files using the scheduler to run a task for * each entry. The name of the directory must be expanded first (!). * If a scheduler does not need to be used, GNUNET_DISK_directory_scan * may provide a simpler API. * * @param prio priority to use * @param dirName the name of the directory * @param callback the method to call for each file * @param callback_cls closure for callback * @return GNUNET_YES if directory is not empty and 'callback' * will be called later, GNUNET_NO otherwise, GNUNET_SYSERR on error. */ int GNUNET_DISK_directory_iterator_start (enum GNUNET_SCHEDULER_Priority prio, const char *dirName, GNUNET_DISK_DirectoryIteratorCallback callback, void *callback_cls) { struct GNUNET_DISK_DirectoryIterator *di; di = GNUNET_malloc (sizeof (struct GNUNET_DISK_DirectoryIterator)); di->callback = callback; di->callback_cls = callback_cls; di->directory = OPENDIR (dirName); if (di->directory == NULL) { GNUNET_free (di); callback (callback_cls, NULL, NULL, NULL); return GNUNET_SYSERR; } di->dirname = GNUNET_strdup (dirName); di->priority = prio; return GNUNET_DISK_directory_iterator_next (di, GNUNET_NO); } /** * Function that removes the given directory by calling * "GNUNET_DISK_directory_remove". * * @param unused not used * @param fn directory to remove * @return GNUNET_OK */ static int remove_helper (void *unused, const char *fn) { (void) GNUNET_DISK_directory_remove (fn); return GNUNET_OK; } /** * Remove all files in a directory (rm -rf). Call with * caution. * * * @param fileName the file to remove * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_DISK_directory_remove (const char *fileName) { struct stat istat; if (0 != LSTAT (fileName, &istat)) return GNUNET_NO; /* file may not exist... */ CHMOD (fileName, S_IWUSR | S_IRUSR | S_IXUSR); if (UNLINK (fileName) == 0) return GNUNET_OK; if ((errno != EISDIR) && /* EISDIR is not sufficient in all cases, e.g. * sticky /tmp directory may result in EPERM on BSD. * So we also explicitly check "isDirectory" */ (GNUNET_YES != GNUNET_DISK_directory_test (fileName))) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", fileName); return GNUNET_SYSERR; } if (GNUNET_SYSERR == GNUNET_DISK_directory_scan (fileName, &remove_helper, NULL)) return GNUNET_SYSERR; if (0 != RMDIR (fileName)) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", fileName); return GNUNET_SYSERR; } return GNUNET_OK; } /** * Copy a file. * * @param src file to copy * @param dst destination file name * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_DISK_file_copy (const char *src, const char *dst) { char *buf; uint64_t pos; uint64_t size; size_t len; struct GNUNET_DISK_FileHandle *in; struct GNUNET_DISK_FileHandle *out; if (GNUNET_OK != GNUNET_DISK_file_size (src, &size, GNUNET_YES, GNUNET_YES)) return GNUNET_SYSERR; pos = 0; in = GNUNET_DISK_file_open (src, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); if (!in) return GNUNET_SYSERR; out = GNUNET_DISK_file_open (dst, GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_FAILIFEXISTS, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_GROUP_READ | GNUNET_DISK_PERM_GROUP_WRITE); if (!out) { GNUNET_DISK_file_close (in); return GNUNET_SYSERR; } buf = GNUNET_malloc (COPY_BLK_SIZE); while (pos < size) { len = COPY_BLK_SIZE; if (len > size - pos) len = size - pos; if (len != GNUNET_DISK_file_read (in, buf, len)) goto FAIL; if (len != GNUNET_DISK_file_write (out, buf, len)) goto FAIL; pos += len; } GNUNET_free (buf); GNUNET_DISK_file_close (in); GNUNET_DISK_file_close (out); return GNUNET_OK; FAIL: GNUNET_free (buf); GNUNET_DISK_file_close (in); GNUNET_DISK_file_close (out); return GNUNET_SYSERR; } /** * @brief Removes special characters as ':' from a filename. * @param fn the filename to canonicalize */ void GNUNET_DISK_filename_canonicalize (char *fn) { char *idx; char c; idx = fn; while (*idx) { c = *idx; if (c == '/' || c == '\\' || c == ':' || c == '*' || c == '?' || c == '"' || c == '<' || c == '>' || c == '|') { *idx = '_'; } idx++; } } /** * @brief Change owner of a file * * @param filename name of file to change the owner of * @param user name of the new owner * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int GNUNET_DISK_file_change_owner (const char *filename, const char *user) { #ifndef MINGW struct passwd *pws; pws = getpwnam (user); if (pws == NULL) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot obtain information about user `%s': %s\n"), user, STRERROR (errno)); return GNUNET_SYSERR; } if (0 != chown (filename, pws->pw_uid, pws->pw_gid)) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "chown", filename); #endif return GNUNET_OK; } /** * Lock a part of a file * @param fh file handle * @param lockStart absolute position from where to lock * @param lockEnd absolute position until where to lock * @param excl GNUNET_YES for an exclusive lock * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, OFF_T lockStart, OFF_T lockEnd, int excl) { if (fh == NULL) { errno = EINVAL; return GNUNET_SYSERR; } #ifndef MINGW struct flock fl; memset (&fl, 0, sizeof (struct flock)); fl.l_type = excl ? F_WRLCK : F_RDLCK; fl.l_whence = SEEK_SET; fl.l_start = lockStart; fl.l_len = lockEnd; return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK; #else OVERLAPPED o; OFF_T diff = lockEnd - lockStart; DWORD diff_low, diff_high; diff_low = (DWORD) (diff & 0xFFFFFFFF); diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF); memset (&o, 0, sizeof (OVERLAPPED)); o.Offset = (DWORD) (lockStart & 0xFFFFFFFF);; o.OffsetHigh = (DWORD) (((lockStart & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF); if (!LockFileEx (fh->h, (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0) | LOCKFILE_FAIL_IMMEDIATELY, 0, diff_low, diff_high, &o)) { SetErrnoFromWinError (GetLastError ()); return GNUNET_SYSERR; } return GNUNET_OK; #endif } /** * Unlock a part of a file * @param fh file handle * @param unlockStart absolute position from where to unlock * @param unlockEnd absolute position until where to unlock * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, OFF_T unlockStart, OFF_T unlockEnd) { if (fh == NULL) { errno = EINVAL; return GNUNET_SYSERR; } #ifndef MINGW struct flock fl; memset (&fl, 0, sizeof (struct flock)); fl.l_type = F_UNLCK; fl.l_whence = SEEK_SET; fl.l_start = unlockStart; fl.l_len = unlockEnd; return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK; #else OVERLAPPED o; OFF_T diff = unlockEnd - unlockStart; DWORD diff_low, diff_high; diff_low = (DWORD) (diff & 0xFFFFFFFF); diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF); memset (&o, 0, sizeof (OVERLAPPED)); o.Offset = (DWORD) (unlockStart & 0xFFFFFFFF);; o.OffsetHigh = (DWORD) (((unlockStart & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF); if (!UnlockFileEx (fh->h, 0, diff_low, diff_high, &o)) { SetErrnoFromWinError (GetLastError ()); return GNUNET_SYSERR; } return GNUNET_OK; #endif } /** * Open a file. Note that the access permissions will only be * used if a new file is created and if the underlying operating * system supports the given permissions. * * @param fn file name to be opened * @param flags opening flags, a combination of GNUNET_DISK_OPEN_xxx bit flags * @param perm permissions for the newly created file, use * GNUNET_DISK_PERM_USER_NONE if a file could not be created by this * call (because of flags) * @return IO handle on success, NULL on error */ struct GNUNET_DISK_FileHandle * GNUNET_DISK_file_open (const char *fn, enum GNUNET_DISK_OpenFlags flags, enum GNUNET_DISK_AccessPermissions perm) { char *expfn; struct GNUNET_DISK_FileHandle *ret; #ifdef MINGW DWORD access; DWORD disp; HANDLE h; wchar_t wexpfn[MAX_PATH + 1]; #else int oflags; int mode; int fd; #endif expfn = GNUNET_STRINGS_filename_expand (fn); if (NULL == expfn) return NULL; #ifndef MINGW mode = 0; if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE)) oflags = O_RDWR; /* note: O_RDWR is NOT always O_RDONLY | O_WRONLY */ else if (flags & GNUNET_DISK_OPEN_READ) oflags = O_RDONLY; else if (flags & GNUNET_DISK_OPEN_WRITE) oflags = O_WRONLY; else { GNUNET_break (0); GNUNET_free (expfn); return NULL; } if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS) oflags |= (O_CREAT | O_EXCL); if (flags & GNUNET_DISK_OPEN_TRUNCATE) oflags |= O_TRUNC; if (flags & GNUNET_DISK_OPEN_APPEND) oflags |= O_APPEND; if (flags & GNUNET_DISK_OPEN_CREATE) { (void) GNUNET_DISK_directory_create_for_file (expfn); oflags |= O_CREAT; mode = translate_unix_perms (perm); } fd = open (expfn, oflags | O_LARGEFILE, mode); if (fd == -1) { if (0 == (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", expfn); else LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "open", expfn); GNUNET_free (expfn); return NULL; } #else access = 0; disp = OPEN_ALWAYS; if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE)) access = FILE_READ_DATA | FILE_WRITE_DATA; else if (flags & GNUNET_DISK_OPEN_READ) access = FILE_READ_DATA; else if (flags & GNUNET_DISK_OPEN_WRITE) access = FILE_WRITE_DATA; if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS) { disp = CREATE_NEW; } else if (flags & GNUNET_DISK_OPEN_CREATE) { (void) GNUNET_DISK_directory_create_for_file (expfn); if (flags & GNUNET_DISK_OPEN_TRUNCATE) disp = CREATE_ALWAYS; else disp = OPEN_ALWAYS; } else if (flags & GNUNET_DISK_OPEN_TRUNCATE) { disp = TRUNCATE_EXISTING; } else { disp = OPEN_EXISTING; } if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(expfn, wexpfn)) h = CreateFileW (wexpfn, access, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, disp, FILE_ATTRIBUTE_NORMAL, NULL); else h = INVALID_HANDLE_VALUE; if (h == INVALID_HANDLE_VALUE) { SetErrnoFromWinError (GetLastError ()); LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", expfn); GNUNET_free (expfn); return NULL; } if (flags & GNUNET_DISK_OPEN_APPEND) if (SetFilePointer (h, 0, 0, FILE_END) == INVALID_SET_FILE_POINTER) { SetErrnoFromWinError (GetLastError ()); LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "SetFilePointer", expfn); CloseHandle (h); GNUNET_free (expfn); return NULL; } #endif ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle)); #ifdef MINGW ret->h = h; ret->type = GNUNET_DISK_FILE; #else ret->fd = fd; #endif GNUNET_free (expfn); return ret; } /** * Close an open file * @param h file handle * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h) { if (h == NULL) { errno = EINVAL; return GNUNET_SYSERR; } #if MINGW if (!CloseHandle (h->h)) { SetErrnoFromWinError (GetLastError ()); LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close"); GNUNET_free (h->oOverlapRead); GNUNET_free (h->oOverlapWrite); GNUNET_free (h); return GNUNET_SYSERR; } #else if (close (h->fd) != 0) { LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close"); GNUNET_free (h); return GNUNET_SYSERR; } #endif GNUNET_free (h); return GNUNET_OK; } /** * Construct full path to a file inside of the private * directory used by GNUnet. Also creates the corresponding * directory. If the resulting name is supposed to be * a directory, end the last argument in '/' (or pass * DIR_SEPARATOR_STR as the last argument before NULL). * * @param cfg configuration to use (determines HOME) * @param serviceName name of the service * @param ... is NULL-terminated list of * path components to append to the * private directory name. * @return the constructed filename */ char * GNUNET_DISK_get_home_filename (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *serviceName, ...) { const char *c; char *pfx; char *ret; va_list ap; unsigned int needed; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, serviceName, "HOME", &pfx)) return NULL; if (pfx == NULL) { LOG (GNUNET_ERROR_TYPE_WARNING, _("No `%s' specified for service `%s' in configuration.\n"), "HOME", serviceName); return NULL; } needed = strlen (pfx) + 2; if ((pfx[strlen (pfx) - 1] != '/') && (pfx[strlen (pfx) - 1] != '\\')) needed++; va_start (ap, serviceName); while (1) { c = va_arg (ap, const char *); if (c == NULL) break; needed += strlen (c); if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\')) needed++; } va_end (ap); ret = GNUNET_malloc (needed); strcpy (ret, pfx); GNUNET_free (pfx); va_start (ap, serviceName); while (1) { c = va_arg (ap, const char *); if (c == NULL) break; if ((c[strlen (c) - 1] != '/') && (c[strlen (c) - 1] != '\\')) strcat (ret, DIR_SEPARATOR_STR); strcat (ret, c); } va_end (ap); if ((ret[strlen (ret) - 1] != '/') && (ret[strlen (ret) - 1] != '\\')) (void) GNUNET_DISK_directory_create_for_file (ret); else (void) GNUNET_DISK_directory_create (ret); return ret; } /** * Handle for a memory-mapping operation. */ struct GNUNET_DISK_MapHandle { /** * Address where the map is in memory. */ void *addr; #ifdef MINGW /** * Underlying OS handle. */ HANDLE h; #else /** * Number of bytes mapped. */ size_t len; #endif }; #ifndef MAP_FAILED #define MAP_FAILED ((void *) -1) #endif /** * Map a file into memory * * @param h open file handle * @param m handle to the new mapping * @param access access specification, GNUNET_DISK_MAP_TYPE_xxx * @param len size of the mapping * @return pointer to the mapped memory region, NULL on failure */ void * GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h, struct GNUNET_DISK_MapHandle **m, enum GNUNET_DISK_MapType access, size_t len) { if (h == NULL) { errno = EINVAL; return NULL; } #ifdef MINGW DWORD mapAccess, protect; if ((access & GNUNET_DISK_MAP_TYPE_READ) && (access & GNUNET_DISK_MAP_TYPE_WRITE)) { protect = PAGE_READWRITE; mapAccess = FILE_MAP_ALL_ACCESS; } else if (access & GNUNET_DISK_MAP_TYPE_READ) { protect = PAGE_READONLY; mapAccess = FILE_MAP_READ; } else if (access & GNUNET_DISK_MAP_TYPE_WRITE) { protect = PAGE_READWRITE; mapAccess = FILE_MAP_WRITE; } else { GNUNET_break (0); return NULL; } *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle)); (*m)->h = CreateFileMapping (h->h, NULL, protect, 0, 0, NULL); if ((*m)->h == INVALID_HANDLE_VALUE) { SetErrnoFromWinError (GetLastError ()); GNUNET_free (*m); return NULL; } (*m)->addr = MapViewOfFile ((*m)->h, mapAccess, 0, 0, len); if (!(*m)->addr) { SetErrnoFromWinError (GetLastError ()); CloseHandle ((*m)->h); GNUNET_free (*m); } return (*m)->addr; #else int prot; prot = 0; if (access & GNUNET_DISK_MAP_TYPE_READ) prot = PROT_READ; if (access & GNUNET_DISK_MAP_TYPE_WRITE) prot |= PROT_WRITE; *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle)); (*m)->addr = mmap (NULL, len, prot, MAP_SHARED, h->fd, 0); GNUNET_assert (NULL != (*m)->addr); if (MAP_FAILED == (*m)->addr) { GNUNET_free (*m); return NULL; } (*m)->len = len; return (*m)->addr; #endif } /** * Unmap a file * @param h mapping handle * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h) { int ret; if (h == NULL) { errno = EINVAL; return GNUNET_SYSERR; } #ifdef MINGW ret = UnmapViewOfFile (h->addr) ? GNUNET_OK : GNUNET_SYSERR; if (ret != GNUNET_OK) SetErrnoFromWinError (GetLastError ()); if (!CloseHandle (h->h) && (ret == GNUNET_OK)) { ret = GNUNET_SYSERR; SetErrnoFromWinError (GetLastError ()); } #else ret = munmap (h->addr, h->len) != -1 ? GNUNET_OK : GNUNET_SYSERR; #endif GNUNET_free (h); return ret; } /** * Write file changes to disk * @param h handle to an open file * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h) { if (h == NULL) { errno = EINVAL; return GNUNET_SYSERR; } #ifdef MINGW int ret; ret = FlushFileBuffers (h->h) ? GNUNET_OK : GNUNET_SYSERR; if (ret != GNUNET_OK) SetErrnoFromWinError (GetLastError ()); return ret; #elif defined(FREEBSD) || defined(OPENBSD) || defined(DARWIN) return fsync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK; #else return fdatasync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK; #endif } #if WINDOWS /* Copyright Bob Byrnes curl.com> http://permalink.gmane.org/gmane.os.cygwin.patches/2121 */ /* Create a pipe, and return handles to the read and write ends, just like CreatePipe, but ensure that the write end permits FILE_READ_ATTRIBUTES access, on later versions of win32 where this is supported. This access is needed by NtQueryInformationFile, which is used to implement select and nonblocking writes. Note that the return value is either NO_ERROR or GetLastError, unlike CreatePipe, which returns a bool for success or failure. */ static int create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr, LPSECURITY_ATTRIBUTES sa_ptr, DWORD psize, DWORD dwReadMode, DWORD dwWriteMode) { /* Default to error. */ *read_pipe_ptr = *write_pipe_ptr = INVALID_HANDLE_VALUE; HANDLE read_pipe = INVALID_HANDLE_VALUE, write_pipe = INVALID_HANDLE_VALUE; /* Ensure that there is enough pipe buffer space for atomic writes. */ if (psize < PIPE_BUF) psize = PIPE_BUF; char pipename[MAX_PATH]; /* Retry CreateNamedPipe as long as the pipe name is in use. * Retrying will probably never be necessary, but we want * to be as robust as possible. */ while (1) { static volatile LONG pipe_unique_id; snprintf (pipename, sizeof pipename, "\\\\.\\pipe\\gnunet-%d-%ld", getpid (), InterlockedIncrement ((LONG *) & pipe_unique_id)); LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateNamedPipe: name = %s, size = %lu\n", pipename, psize); /* Use CreateNamedPipe instead of CreatePipe, because the latter * returns a write handle that does not permit FILE_READ_ATTRIBUTES * access, on versions of win32 earlier than WinXP SP2. * CreatePipe also stupidly creates a full duplex pipe, which is * a waste, since only a single direction is actually used. * It's important to only allow a single instance, to ensure that * the pipe was not created earlier by some other process, even if * the pid has been reused. We avoid FILE_FLAG_FIRST_PIPE_INSTANCE * because that is only available for Win2k SP2 and WinXP. */ read_pipe = CreateNamedPipeA (pipename, PIPE_ACCESS_INBOUND | dwReadMode, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, /* max instances */ psize, /* output buffer size */ psize, /* input buffer size */ NMPWAIT_USE_DEFAULT_WAIT, sa_ptr); if (read_pipe != INVALID_HANDLE_VALUE) { LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p\n", read_pipe); break; } DWORD err = GetLastError (); switch (err) { case ERROR_PIPE_BUSY: /* The pipe is already open with compatible parameters. * Pick a new name and retry. */ LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe busy, retrying\n"); continue; case ERROR_ACCESS_DENIED: /* The pipe is already open with incompatible parameters. * Pick a new name and retry. */ LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe access denied, retrying\n"); continue; case ERROR_CALL_NOT_IMPLEMENTED: /* We are on an older Win9x platform without named pipes. * Return an anonymous pipe as the best approximation. */ LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateNamedPipe not implemented, resorting to " "CreatePipe: size = %lu\n", psize); if (CreatePipe (read_pipe_ptr, write_pipe_ptr, sa_ptr, psize)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p, write handle = %p\n", *read_pipe_ptr, *write_pipe_ptr); return GNUNET_OK; } err = GetLastError (); LOG (GNUNET_ERROR_TYPE_ERROR, "CreatePipe failed: %d\n", err); return err; default: LOG (GNUNET_ERROR_TYPE_ERROR, "CreateNamedPipe failed: %d\n", err); return err; } /* NOTREACHED */ } LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile: name = %s\n", pipename); /* Open the named pipe for writing. * Be sure to permit FILE_READ_ATTRIBUTES access. */ write_pipe = CreateFileA (pipename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, /* share mode */ sa_ptr, OPEN_EXISTING, dwWriteMode, /* flags and attributes */ 0); /* handle to template file */ if (write_pipe == INVALID_HANDLE_VALUE) { /* Failure. */ DWORD err = GetLastError (); LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile failed: %d\n", err); CloseHandle (read_pipe); return err; } LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe write handle = %p\n", write_pipe); /* Success. */ *read_pipe_ptr = read_pipe; *write_pipe_ptr = write_pipe; return GNUNET_OK; } #endif /** * Creates an interprocess channel * * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO * @param inherit_read inherit the parent processes stdin (only for windows) * @param inherit_write inherit the parent processes stdout (only for windows) * @return handle to the new pipe, NULL on error */ struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int inherit_write) { #ifndef MINGW int fd[2]; int ret; int eno; ret = pipe (fd); if (ret == -1) { eno = errno; LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe"); errno = eno; return NULL; } return GNUNET_DISK_pipe_from_fd (blocking_read, blocking_write, fd); #else struct GNUNET_DISK_PipeHandle *p; struct GNUNET_DISK_FileHandle *fds; BOOL ret; HANDLE tmp_handle; p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) + 2 * sizeof (struct GNUNET_DISK_FileHandle)); fds = (struct GNUNET_DISK_FileHandle *) &p[1]; p->fd[0] = &fds[0]; p->fd[1] = &fds[1]; /* All pipes are overlapped. If you want them to block - just * call WriteFile() and ReadFile() with NULL overlapped pointer. */ ret = create_selectable_pipe (&p->fd[0]->h, &p->fd[1]->h, NULL, 0, FILE_FLAG_OVERLAPPED, FILE_FLAG_OVERLAPPED); if (!ret) { GNUNET_free (p); SetErrnoFromWinError (GetLastError ()); return NULL; } if (!DuplicateHandle (GetCurrentProcess (), p->fd[0]->h, GetCurrentProcess (), &tmp_handle, 0, inherit_read == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS)) { SetErrnoFromWinError (GetLastError ()); CloseHandle (p->fd[0]->h); CloseHandle (p->fd[1]->h); GNUNET_free (p); return NULL; } CloseHandle (p->fd[0]->h); p->fd[0]->h = tmp_handle; if (!DuplicateHandle (GetCurrentProcess (), p->fd[1]->h, GetCurrentProcess (), &tmp_handle, 0, inherit_write == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS)) { SetErrnoFromWinError (GetLastError ()); CloseHandle (p->fd[0]->h); CloseHandle (p->fd[1]->h); GNUNET_free (p); return NULL; } CloseHandle (p->fd[1]->h); p->fd[1]->h = tmp_handle; p->fd[0]->type = GNUNET_PIPE; p->fd[1]->type = GNUNET_PIPE; p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED)); p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED)); p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED)); p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED)); p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); return p; #endif } /** * Creates a pipe object from a couple of file descriptors. * Useful for wrapping existing pipe FDs. * * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO * @param fd an array of two fd values. One of them may be -1 for read-only or write-only pipes * * @return handle to the new pipe, NULL on error */ struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2]) { struct GNUNET_DISK_PipeHandle *p; struct GNUNET_DISK_FileHandle *fds; p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) + 2 * sizeof (struct GNUNET_DISK_FileHandle)); fds = (struct GNUNET_DISK_FileHandle *) &p[1]; p->fd[0] = &fds[0]; p->fd[1] = &fds[1]; #ifndef MINGW int ret; int flags; int eno = 0; /* make gcc happy */ p->fd[0]->fd = fd[0]; p->fd[1]->fd = fd[1]; ret = 0; if (fd[0] >= 0) { if (!blocking_read) { flags = fcntl (fd[0], F_GETFL); flags |= O_NONBLOCK; if (0 > fcntl (fd[0], F_SETFL, flags)) { ret = -1; eno = errno; } } flags = fcntl (fd[0], F_GETFD); flags |= FD_CLOEXEC; if (0 > fcntl (fd[0], F_SETFD, flags)) { ret = -1; eno = errno; } } if (fd[1] >= 0) { if (!blocking_write) { flags = fcntl (fd[1], F_GETFL); flags |= O_NONBLOCK; if (0 > fcntl (fd[1], F_SETFL, flags)) { ret = -1; eno = errno; } } flags = fcntl (fd[1], F_GETFD); flags |= FD_CLOEXEC; if (0 > fcntl (fd[1], F_SETFD, flags)) { ret = -1; eno = errno; } } if (ret == -1) { errno = eno; LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fcntl"); if (p->fd[0]->fd >= 0) GNUNET_break (0 == close (p->fd[0]->fd)); if (p->fd[1]->fd >= 0) GNUNET_break (0 == close (p->fd[1]->fd)); GNUNET_free (p); errno = eno; return NULL; } #else if (fd[0] >= 0) p->fd[0]->h = _get_osfhandle (fd[0]); else p->fd[0]->h = INVALID_HANDLE_VALUE; if (fd[1] >= 0) p->fd[1]->h = _get_osfhandle (fd[1]); else p->fd[1]->h = INVALID_HANDLE_VALUE; if (p->fd[0]->h != INVALID_HANDLE_VALUE) { p->fd[0]->type = GNUNET_PIPE; p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED)); p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED)); p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); } if (p->fd[1]->h != INVALID_HANDLE_VALUE) { p->fd[1]->type = GNUNET_PIPE; p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED)); p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED)); p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); } #endif return p; } /** * Closes an interprocess channel * * @param p pipe to close * @param end which end of the pipe to close * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd end) { int ret = GNUNET_OK; int save; #ifdef MINGW if (end == GNUNET_DISK_PIPE_END_READ) { if (p->fd[0]->h != INVALID_HANDLE_VALUE) { if (!CloseHandle (p->fd[0]->h)) { SetErrnoFromWinError (GetLastError ()); ret = GNUNET_SYSERR; } GNUNET_free (p->fd[0]->oOverlapRead); GNUNET_free (p->fd[0]->oOverlapWrite); p->fd[0]->h = INVALID_HANDLE_VALUE; } } else if (end == GNUNET_DISK_PIPE_END_WRITE) { if (p->fd[0]->h != INVALID_HANDLE_VALUE) { if (!CloseHandle (p->fd[1]->h)) { SetErrnoFromWinError (GetLastError ()); ret = GNUNET_SYSERR; } GNUNET_free (p->fd[1]->oOverlapRead); GNUNET_free (p->fd[1]->oOverlapWrite); p->fd[1]->h = INVALID_HANDLE_VALUE; } } save = errno; #else save = 0; if (end == GNUNET_DISK_PIPE_END_READ) { if (0 != close (p->fd[0]->fd)) { ret = GNUNET_SYSERR; save = errno; } p->fd[0]->fd = -1; } else if (end == GNUNET_DISK_PIPE_END_WRITE) { if (0 != close (p->fd[1]->fd)) { ret = GNUNET_SYSERR; save = errno; } p->fd[1]->fd = -1; } #endif errno = save; return ret; } /** * Closes an interprocess channel * * @param p pipe to close * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p) { int ret = GNUNET_OK; int save; #ifdef MINGW if (p->fd[0]->h != INVALID_HANDLE_VALUE) { if (!CloseHandle (p->fd[0]->h)) { SetErrnoFromWinError (GetLastError ()); ret = GNUNET_SYSERR; } GNUNET_free (p->fd[0]->oOverlapRead); GNUNET_free (p->fd[0]->oOverlapWrite); } if (p->fd[1]->h != INVALID_HANDLE_VALUE) { if (!CloseHandle (p->fd[1]->h)) { SetErrnoFromWinError (GetLastError ()); ret = GNUNET_SYSERR; } GNUNET_free (p->fd[1]->oOverlapRead); GNUNET_free (p->fd[1]->oOverlapWrite); } save = errno; #else save = 0; if (p->fd[0]->fd != -1) { if (0 != close (p->fd[0]->fd)) { ret = GNUNET_SYSERR; save = errno; } } if (p->fd[1]->fd != -1) { if (0 != close (p->fd[1]->fd)) { ret = GNUNET_SYSERR; save = errno; } } #endif GNUNET_free (p); errno = save; return ret; } /** * Get the handle to a particular pipe end * * @param p pipe * @param n end to access * @return handle for the respective end */ const struct GNUNET_DISK_FileHandle * GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd n) { switch (n) { case GNUNET_DISK_PIPE_END_READ: case GNUNET_DISK_PIPE_END_WRITE: return p->fd[n]; default: GNUNET_break (0); return NULL; } } /** * Retrieve OS file handle * @internal * @param fh GNUnet file descriptor * @param dst destination buffer * @param dst_len length of dst * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh, void *dst, size_t dst_len) { #ifdef MINGW if (dst_len < sizeof (HANDLE)) return GNUNET_SYSERR; *((HANDLE *) dst) = fh->h; #else if (dst_len < sizeof (int)) return GNUNET_SYSERR; *((int *) dst) = fh->fd; #endif return GNUNET_OK; } /* end of disk.c */ gnunet-0.9.3/src/util/perf_crypto_hash.c0000644000175000017500000000401111760502551015211 00000000000000/* This file is part of GNUnet. (C) 2002, 2003, 2004, 2006 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @author Christian Grothoff * @file util/perf_crypto_hash.c * @brief measure performance of hash function */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_crypto_lib.h" #include "gnunet_time_lib.h" #include static void perfHash () { GNUNET_HashCode hc1; GNUNET_HashCode hc2; GNUNET_HashCode hc3; int i; char *buf; buf = GNUNET_malloc (1024 * 64); memset (buf, 1, 1024 * 64); GNUNET_CRYPTO_hash ("foo", 3, &hc1); for (i = 0; i < 1024; i++) { GNUNET_CRYPTO_hash (&hc1, sizeof (GNUNET_HashCode), &hc2); GNUNET_CRYPTO_hash (&hc2, sizeof (GNUNET_HashCode), &hc1); GNUNET_CRYPTO_hash (buf, 1024 * 64, &hc3); } GNUNET_free (buf); } int main (int argc, char *argv[]) { struct GNUNET_TIME_Absolute start; start = GNUNET_TIME_absolute_get (); perfHash (); printf ("Hash perf took %llu ms\n", (unsigned long long) GNUNET_TIME_absolute_get_duration (start).rel_value); GAUGER ("UTIL", "Cryptographic hashing", 1024 * 64 * 1024 / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value), "kb/s"); return 0; } /* end of hashperf.c */ gnunet-0.9.3/src/util/server_tc.c0000644000175000017500000001552011760502551013655 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/server_tc.c * @brief convenience functions for transmission of * complex responses as a server * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_connection_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_server_lib.h" #include "gnunet_time_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) /** * How much buffer space do we want to have at least * before transmitting another increment? */ #define MIN_BLOCK_SIZE 128 struct GNUNET_SERVER_TransmitContext { /** * Which client are we transmitting to? */ struct GNUNET_SERVER_Client *client; /** * Transmission buffer. (current offset for writing). */ char *buf; /** * Number of bytes in buf. */ size_t total; /** * Offset for writing in buf. */ size_t off; /** * Timeout for this request. */ struct GNUNET_TIME_Absolute timeout; }; /** * Helper function for incremental transmission of the response. */ static size_t transmit_response (void *cls, size_t size, void *buf) { struct GNUNET_SERVER_TransmitContext *tc = cls; size_t msize; if (NULL == buf) { GNUNET_SERVER_transmit_context_destroy (tc, GNUNET_SYSERR); return 0; } if (tc->total - tc->off > size) msize = size; else msize = tc->total - tc->off; memcpy (buf, &tc->buf[tc->off], msize); tc->off += msize; if (tc->total == tc->off) { GNUNET_SERVER_receive_done (tc->client, GNUNET_OK); GNUNET_SERVER_client_drop (tc->client); GNUNET_free_non_null (tc->buf); GNUNET_free (tc); } else { if (NULL == GNUNET_SERVER_notify_transmit_ready (tc->client, GNUNET_MIN (MIN_BLOCK_SIZE, tc->total - tc->off), GNUNET_TIME_absolute_get_remaining (tc->timeout), &transmit_response, tc)) { GNUNET_break (0); GNUNET_SERVER_transmit_context_destroy (tc, GNUNET_SYSERR); } } return msize; } /** * Create a new transmission context for the * given client. * * @param client client to create the context for. * @return NULL on error */ struct GNUNET_SERVER_TransmitContext * GNUNET_SERVER_transmit_context_create (struct GNUNET_SERVER_Client *client) { struct GNUNET_SERVER_TransmitContext *tc; GNUNET_assert (NULL != client); tc = GNUNET_malloc (sizeof (struct GNUNET_SERVER_TransmitContext)); GNUNET_SERVER_client_keep (client); tc->client = client; return tc; } /** * Append a message to the transmission context. * All messages in the context will be sent by * the transmit_context_run method. * * @param tc context to use * @param data what to append to the result message * @param length length of data * @param type type of the message */ void GNUNET_SERVER_transmit_context_append_data (struct GNUNET_SERVER_TransmitContext *tc, const void *data, size_t length, uint16_t type) { struct GNUNET_MessageHeader *msg; size_t size; GNUNET_assert (length < GNUNET_SERVER_MAX_MESSAGE_SIZE); size = length + sizeof (struct GNUNET_MessageHeader); GNUNET_assert (size > length); tc->buf = GNUNET_realloc (tc->buf, tc->total + size); msg = (struct GNUNET_MessageHeader *) &tc->buf[tc->total]; tc->total += size; msg->size = htons (size); msg->type = htons (type); memcpy (&msg[1], data, length); } /** * Append a message to the transmission context. * All messages in the context will be sent by * the transmit_context_run method. * * @param tc context to use * @param msg message to append */ void GNUNET_SERVER_transmit_context_append_message (struct GNUNET_SERVER_TransmitContext *tc, const struct GNUNET_MessageHeader *msg) { struct GNUNET_MessageHeader *m; uint16_t size; size = ntohs (msg->size); tc->buf = GNUNET_realloc (tc->buf, tc->total + size); m = (struct GNUNET_MessageHeader *) &tc->buf[tc->total]; tc->total += size; memcpy (m, msg, size); } /** * Execute a transmission context. If there is * an error in the transmission, the receive_done * method will be called with an error code (GNUNET_SYSERR), * otherwise with GNUNET_OK. * * @param tc transmission context to use * @param timeout when to time out and abort the transmission */ void GNUNET_SERVER_transmit_context_run (struct GNUNET_SERVER_TransmitContext *tc, struct GNUNET_TIME_Relative timeout) { tc->timeout = GNUNET_TIME_relative_to_absolute (timeout); if (NULL == GNUNET_SERVER_notify_transmit_ready (tc->client, GNUNET_MIN (MIN_BLOCK_SIZE, tc->total), timeout, &transmit_response, tc)) { GNUNET_break (0); GNUNET_SERVER_transmit_context_destroy (tc, GNUNET_SYSERR); } } /** * Destroy a transmission context. This function must not be called * after 'GNUNET_SERVER_transmit_context_run'. * * @param tc transmission context to destroy * @param success code to give to 'GNUNET_SERVER_receive_done' for * the client: GNUNET_OK to keep the connection open and * continue to receive * GNUNET_NO to close the connection (normal behavior) * GNUNET_SYSERR to close the connection (signal * serious error) */ void GNUNET_SERVER_transmit_context_destroy (struct GNUNET_SERVER_TransmitContext *tc, int success) { GNUNET_SERVER_receive_done (tc->client, success); GNUNET_SERVER_client_drop (tc->client); GNUNET_free_non_null (tc->buf); GNUNET_free (tc); } /* end of server_tc.c */ gnunet-0.9.3/src/util/gnunet-rsa.c0000644000175000017500000000745311760502551013752 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/gnunet-rsa.c * @brief tool to manipulate RSA key files * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" /** * Flag for printing public key. */ static int print_public_key; /** * Flag for printing hash of public key. */ static int print_peer_identity; /** * Flag for printing short hash of public key. */ static int print_short_identity; /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param cfg configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_CRYPTO_RsaPrivateKey *pk; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub; struct GNUNET_PeerIdentity pid; if (NULL == args[0]) { fprintf (stderr, _("No hostkey file specified on command line\n")); return; } pk = GNUNET_CRYPTO_rsa_key_create_from_file (args[0]); if (print_public_key) { char *s; GNUNET_CRYPTO_rsa_key_get_public (pk, &pub); s = GNUNET_CRYPTO_rsa_public_key_to_string (&pub); fprintf (stdout, "%s\n", s); GNUNET_free (s); } if (print_peer_identity) { struct GNUNET_CRYPTO_HashAsciiEncoded enc; GNUNET_CRYPTO_rsa_key_get_public (pk, &pub); GNUNET_CRYPTO_hash (&pub, sizeof (pub), &pid.hashPubKey); GNUNET_CRYPTO_hash_to_enc (&pid.hashPubKey, &enc); fprintf (stdout, "%s\n", enc.encoding); } if (print_short_identity) { struct GNUNET_CRYPTO_ShortHashAsciiEncoded enc; struct GNUNET_CRYPTO_ShortHashCode sh; GNUNET_CRYPTO_rsa_key_get_public (pk, &pub); GNUNET_CRYPTO_short_hash (&pub, sizeof (pub), &sh); GNUNET_CRYPTO_short_hash_to_enc (&sh, &enc); fprintf (stdout, "%s\n", enc.short_encoding); } GNUNET_CRYPTO_rsa_key_free (pk); } /** * The main function to obtain statistics in GNUnet. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { { 'p', "print-public-key", NULL, gettext_noop ("print the public key in ASCII format"), 0, &GNUNET_GETOPT_set_one, &print_public_key }, { 'P', "print-peer-identity", NULL, gettext_noop ("print the hash of the public key in ASCII format"), 0, &GNUNET_GETOPT_set_one, &print_peer_identity }, { 's', "print-short-identity", NULL, gettext_noop ("print the short hash of the public key in ASCII format"), 0, &GNUNET_GETOPT_set_one, &print_short_identity }, GNUNET_GETOPT_OPTION_END }; return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-rsa [OPTIONS] keyfile", gettext_noop ("Manipulate GNUnet private RSA key files"), options, &run, NULL)) ? 0 : 1; } /* end of gnunet-rsa.c */ gnunet-0.9.3/src/util/test_crypto_aes.c0000644000175000017500000001152011760502551015064 00000000000000/* This file is part of GNUnet. (C) 2002, 2003, 2004, 2006 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @author Christian Grothoff * @file util/test_crypto_aes.c * @brief test for AES ciphers */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_crypto_lib.h" #define TESTSTRING "Hello World!" #define INITVALUE "InitializationVectorValue" static int testSymcipher () { struct GNUNET_CRYPTO_AesSessionKey key; char result[100]; int size; char res[100]; GNUNET_CRYPTO_aes_create_session_key (&key); size = GNUNET_CRYPTO_aes_encrypt (TESTSTRING, strlen (TESTSTRING) + 1, &key, (const struct GNUNET_CRYPTO_AesInitializationVector *) INITVALUE, result); if (size == -1) { printf ("symciphertest failed: encryptBlock returned %d\n", size); return 1; } size = GNUNET_CRYPTO_aes_decrypt (result, size, &key, (const struct GNUNET_CRYPTO_AesInitializationVector *) INITVALUE, res); if (strlen (TESTSTRING) + 1 != size) { printf ("symciphertest failed: decryptBlock returned %d\n", size); return 1; } if (0 != strcmp (res, TESTSTRING)) { printf ("symciphertest failed: %s != %s\n", res, TESTSTRING); return 1; } else return 0; } int verifyCrypto () { struct GNUNET_CRYPTO_AesSessionKey key; char result[GNUNET_CRYPTO_AES_KEY_LENGTH]; char *res; int ret; unsigned char plain[] = { 29, 128, 192, 253, 74, 171, 38, 187, 84, 219, 76, 76, 209, 118, 33, 249, 172, 124, 96, 9, 157, 110, 8, 215, 200, 63, 69, 230, 157, 104, 247, 164 }; unsigned char raw_key[] = { 106, 74, 209, 88, 145, 55, 189, 135, 125, 180, 225, 108, 183, 54, 25, 169, 129, 188, 131, 75, 227, 245, 105, 10, 225, 15, 115, 159, 148, 184, 34, 191 }; unsigned char encrresult[] = { 167, 102, 230, 233, 127, 195, 176, 107, 17, 91, 199, 127, 96, 113, 75, 195, 245, 217, 61, 236, 159, 165, 103, 121, 203, 99, 202, 41, 23, 222, 25, 102 }; res = NULL; ret = 0; memcpy (key.key, raw_key, GNUNET_CRYPTO_AES_KEY_LENGTH); key.crc32 = htonl (GNUNET_CRYPTO_crc32_n (&key, GNUNET_CRYPTO_AES_KEY_LENGTH)); if (ntohl (key.crc32) != (unsigned int) 38125195LL) { printf ("Static key has different CRC: %u - %u\n", ntohl (key.crc32), key.crc32); ret = 1; goto error; } if (GNUNET_CRYPTO_AES_KEY_LENGTH != GNUNET_CRYPTO_aes_encrypt (plain, GNUNET_CRYPTO_AES_KEY_LENGTH, &key, (const struct GNUNET_CRYPTO_AesInitializationVector *) "testtesttesttest", result)) { printf ("Wrong return value from encrypt block.\n"); ret = 1; goto error; } if (memcmp (encrresult, result, GNUNET_CRYPTO_AES_KEY_LENGTH) != 0) { printf ("Encrypted result wrong.\n"); ret = 1; goto error; } res = GNUNET_malloc (GNUNET_CRYPTO_AES_KEY_LENGTH); if (GNUNET_CRYPTO_AES_KEY_LENGTH != GNUNET_CRYPTO_aes_decrypt (result, GNUNET_CRYPTO_AES_KEY_LENGTH, &key, (const struct GNUNET_CRYPTO_AesInitializationVector *) "testtesttesttest", res)) { printf ("Wrong return value from decrypt block.\n"); ret = 1; goto error; } if (memcmp (res, plain, GNUNET_CRYPTO_AES_KEY_LENGTH) != 0) { printf ("Decrypted result does not match input.\n"); ret = 1; } error: GNUNET_free_non_null (res); return ret; } int main (int argc, char *argv[]) { int failureCount = 0; GNUNET_log_setup ("test-crypto-aes", "WARNING", NULL); GNUNET_CRYPTO_random_disable_entropy_gathering (); GNUNET_assert (strlen (INITVALUE) > sizeof (struct GNUNET_CRYPTO_AesInitializationVector)); failureCount += testSymcipher (); failureCount += verifyCrypto (); if (failureCount != 0) { printf ("%d TESTS FAILED!\n", failureCount); return -1; } return 0; } /* end of test_crypto_aes.c */ gnunet-0.9.3/src/util/test_service_data.conf0000644000175000017500000000104211667453373016063 00000000000000[test_service] PORT=12435 BINDTO=localhost PIDFILE=/tmp/test-service.pid TIMEOUT=30 s MAXBUF=1024 DISABLEV6=NO ACCEPT_FROM=127.0.0.1; REJECT_FROM=1.2.3.0/15;4.5.0.0/8;6.7.8.9/255.255.255.0; ACCEPT_FROM6=::1; REJECT_FROM6=AB:CD:EF::00;AB:CD::00/40; HOSTNAME=localhost [test_service6] PORT=12435 PIDFILE=/tmp/test-service.pid TIMEOUT=30 s MAXBUF=1024 DISABLEV6=NO ACCEPT_FROM=127.0.0.1; REJECT_FROM=1.2.3.0/15;4.5.0.0/8;6.7.8.9/255.255.255.0; ACCEPT_FROM6=::1; REJECT_FROM6=AB:CD:EF::00;AB:CD::00/40; HOSTNAME=::1 [resolver] HOSTNAME=localhost gnunet-0.9.3/src/util/test_connection_timeout_no_connect.c0000644000175000017500000000524611760502551021036 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_connection_timeout_no_connect.c * @brief tests for connection.c, doing timeout which connect failure */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_connection_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" #define VERBOSE GNUNET_NO #define PORT 13425 static struct GNUNET_CONNECTION_Handle *csock; static struct GNUNET_CONFIGURATION_Handle *cfg; static size_t handle_timeout (void *cls, size_t size, void *buf) { int *ok = cls; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received timeout signal.\n"); #endif GNUNET_assert (size == 0); GNUNET_assert (buf == NULL); *ok = 0; return 0; } static void task_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT); GNUNET_assert (csock != NULL); GNUNET_assert (NULL != GNUNET_CONNECTION_notify_transmit_ready (csock, 1024, GNUNET_TIME_UNIT_SECONDS, &handle_timeout, cls)); } /** * Main method, starts scheduler with task_timeout. */ static int check_timeout () { int ok; ok = 1; cfg = GNUNET_CONFIGURATION_create (); GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", "localhost"); GNUNET_SCHEDULER_run (&task_timeout, &ok); GNUNET_CONFIGURATION_destroy (cfg); return ok; } int main (int argc, char *argv[]) { int ret = 0; GNUNET_log_setup ("test_connection_timeout_no_connect", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret += check_timeout (); return ret; } /* end of test_connection_timeout_no_connect.c */ gnunet-0.9.3/src/util/test_server_disconnect.c0000644000175000017500000001172311760502551016440 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_server_disconnect.c * @brief tests for server.c, specifically GNUNET_SERVER_client_disconnect */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_client_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_server_lib.h" #include "gnunet_time_lib.h" #define VERBOSE GNUNET_NO #define PORT 12435 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250) #define MY_TYPE 128 static struct GNUNET_SERVER_Handle *server; static struct GNUNET_CLIENT_Connection *cc; static struct GNUNET_CONFIGURATION_Handle *cfg; static int ok; static void finish_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_assert (ok == 5); ok = 0; GNUNET_SERVER_destroy (server); GNUNET_CLIENT_disconnect (cc); GNUNET_CONFIGURATION_destroy (cfg); } static void notify_disconnect (void *cls, struct GNUNET_SERVER_Client *clientarg) { if (clientarg == NULL) return; GNUNET_assert (ok == 4); ok = 5; GNUNET_SCHEDULER_add_now (&finish_up, NULL); } static void server_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_SERVER_Client *argclient = cls; GNUNET_assert (ok == 3); ok = 4; GNUNET_SERVER_client_disconnect (argclient); GNUNET_SERVER_client_drop (argclient); } static void recv_cb (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { GNUNET_assert (ok == 2); ok = 3; GNUNET_SERVER_client_keep (client); GNUNET_SCHEDULER_add_now (&server_disconnect, client); GNUNET_assert (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size)); GNUNET_assert (MY_TYPE == ntohs (message->type)); GNUNET_SERVER_receive_done (client, GNUNET_OK); } static struct GNUNET_SERVER_MessageHandler handlers[] = { {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)}, {NULL, NULL, 0, 0} }; static size_t transmit_initial_message (void *cls, size_t size, void *buf) { struct GNUNET_MessageHeader msg; GNUNET_assert (ok == 1); ok = 2; GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); msg.type = htons (MY_TYPE); msg.size = htons (sizeof (struct GNUNET_MessageHeader)); memcpy (buf, &msg, sizeof (struct GNUNET_MessageHeader)); return sizeof (struct GNUNET_MessageHeader); } static void task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct sockaddr_in sa; struct sockaddr *sap[2]; socklen_t slens[2]; sap[0] = (struct sockaddr *) &sa; slens[0] = sizeof (sa); sap[1] = NULL; slens[1] = 0; memset (&sa, 0, sizeof (sa)); #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = sizeof (sa); #endif sa.sin_family = AF_INET; sa.sin_port = htons (PORT); server = GNUNET_SERVER_create (NULL, NULL, sap, slens, TIMEOUT, GNUNET_NO); GNUNET_assert (server != NULL); GNUNET_SERVER_add_handlers (server, handlers); GNUNET_SERVER_disconnect_notify (server, ¬ify_disconnect, NULL); cfg = GNUNET_CONFIGURATION_create (); GNUNET_CONFIGURATION_set_value_number (cfg, "test-server", "PORT", PORT); GNUNET_CONFIGURATION_set_value_string (cfg, "test-server", "HOSTNAME", "localhost"); GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", "localhost"); cc = GNUNET_CLIENT_connect ("test-server", cfg); GNUNET_assert (cc != NULL); GNUNET_assert (NULL != GNUNET_CLIENT_notify_transmit_ready (cc, sizeof (struct GNUNET_MessageHeader), TIMEOUT, GNUNET_YES, &transmit_initial_message, NULL)); } /** * Main method, starts scheduler with task1, * checks that "ok" is correct at the end. */ static int check () { ok = 1; GNUNET_SCHEDULER_run (&task, &ok); return ok; } int main (int argc, char *argv[]) { int ret = 0; GNUNET_log_setup ("test_server_disconnect", "WARNING", NULL); ret += check (); return ret; } /* end of test_server_disconnect.c */ gnunet-0.9.3/src/util/test_bio.c0000644000175000017500000003162411760502551013474 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_bio.c * @brief testcase for the buffered IO module * @author Ji Lu */ #include "platform.h" #include "gnunet_util_lib.h" #define TESTSTRING "testString" #define TESTNUMBER64 ((int64_t)100000L) static int test_normal_rw () { char *msg; int64_t testNum; char *readResultString; char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); struct GNUNET_BIO_WriteHandle *fileW; struct GNUNET_BIO_ReadHandle *fileR; struct GNUNET_CONTAINER_MetaData *metaDataW; struct GNUNET_CONTAINER_MetaData *metaDataR; metaDataW = GNUNET_CONTAINER_meta_data_create (); metaDataR = NULL; GNUNET_CONTAINER_meta_data_add_publication_date (metaDataW); fileW = GNUNET_BIO_write_open (fileName); GNUNET_assert (NULL != fileW); GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_string (fileW, TESTSTRING)); GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_meta_data (fileW, metaDataW)); GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int64 (fileW, TESTNUMBER64)); GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); fileR = GNUNET_BIO_read_open (fileName); GNUNET_assert (NULL != fileR); readResultString = NULL; GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_string (fileR, "Read string error", &readResultString, 200)); GNUNET_assert (NULL != readResultString); GNUNET_assert (0 == strcmp (TESTSTRING, readResultString)); GNUNET_free (readResultString); GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_meta_data (fileR, "Read meta error", &metaDataR)); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_meta_data_test_equal (metaDataR, metaDataW)); GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_int64 (fileR, &testNum)); GNUNET_BIO_read_close (fileR, &msg); GNUNET_CONTAINER_meta_data_destroy (metaDataW); GNUNET_CONTAINER_meta_data_destroy (metaDataR); GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); GNUNET_free (fileName); return 0; } static int test_nullstring_rw () { char *msg; char *readResultString = (char *) "not null"; struct GNUNET_BIO_WriteHandle *fileW; struct GNUNET_BIO_ReadHandle *fileR; char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); fileW = GNUNET_BIO_write_open (fileName); GNUNET_assert (NULL != fileW); GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_string (fileW, NULL)); GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); fileR = GNUNET_BIO_read_open (fileName); GNUNET_assert (NULL != fileR); GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_string (fileR, "Read string error", &readResultString, 200)); GNUNET_assert (NULL == readResultString); GNUNET_BIO_read_close (fileR, &msg); GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); GNUNET_free (fileName); return 0; } static int test_emptystring_rw () { char *msg; char *readResultString; struct GNUNET_BIO_WriteHandle *fileW; struct GNUNET_BIO_ReadHandle *fileR; char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); fileW = GNUNET_BIO_write_open (fileName); GNUNET_assert (NULL != fileW); GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_string (fileW, "")); GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); fileR = GNUNET_BIO_read_open (fileName); GNUNET_assert (NULL != fileR); readResultString = NULL; GNUNET_assert (GNUNET_OK == GNUNET_BIO_read_string (fileR, "Read string error", &readResultString, 200)); GNUNET_free (readResultString); GNUNET_BIO_read_close (fileR, &msg); GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); GNUNET_free (fileName); return 0; } static int test_bigstring_rw () { char *msg; char *readResultString; struct GNUNET_BIO_WriteHandle *fileW; struct GNUNET_BIO_ReadHandle *fileR; char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); fileW = GNUNET_BIO_write_open (fileName); GNUNET_assert (NULL != fileW); GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_string (fileW, TESTSTRING)); GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); fileR = GNUNET_BIO_read_open (fileName); GNUNET_assert (NULL != fileR); readResultString = NULL; GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_string (fileR, "Read string error", &readResultString, 1)); GNUNET_assert (NULL == readResultString); msg = NULL; GNUNET_BIO_read_close (fileR, &msg); GNUNET_free (msg); GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); GNUNET_free (fileName); return 0; } static int test_bigmeta_rw () { char *msg; static char meta[1024 * 1024 * 10]; struct GNUNET_BIO_WriteHandle *fileW; struct GNUNET_BIO_ReadHandle *fileR; char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); struct GNUNET_CONTAINER_MetaData *metaDataR; memset (meta, 'b', sizeof (meta)); meta[sizeof (meta) - 1] = '\0'; fileW = GNUNET_BIO_write_open (fileName); GNUNET_assert (NULL != fileW); GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int32 (fileW, sizeof (meta))); GNUNET_assert (GNUNET_OK == GNUNET_BIO_write (fileW, meta, sizeof (meta))); GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); fileR = GNUNET_BIO_read_open (fileName); GNUNET_assert (NULL != fileR); metaDataR = NULL; GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_meta_data (fileR, "Read meta error", &metaDataR)); msg = NULL; GNUNET_BIO_read_close (fileR, &msg); GNUNET_free (msg); GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); GNUNET_assert (NULL == metaDataR); GNUNET_free (fileName); return 0; } static int test_directory_r () { #if LINUX char *msg; char readResult[200]; struct GNUNET_BIO_ReadHandle *fileR; fileR = GNUNET_BIO_read_open ("/dev"); GNUNET_assert (NULL != fileR); GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read (fileR, "Read error", readResult, sizeof (readResult))); msg = NULL; GNUNET_BIO_read_close (fileR, &msg); GNUNET_free (msg); #endif return 0; } static int test_nullfile_rw () { static char fileNameNO[102401]; struct GNUNET_BIO_WriteHandle *fileWNO; struct GNUNET_BIO_ReadHandle *fileRNO; memset (fileNameNO, 'a', sizeof (fileNameNO)); fileNameNO[sizeof (fileNameNO) - 1] = '\0'; GNUNET_log_skip (1, GNUNET_NO); fileWNO = GNUNET_BIO_write_open (fileNameNO); GNUNET_log_skip (0, GNUNET_YES); GNUNET_assert (NULL == fileWNO); GNUNET_log_skip (1, GNUNET_NO); fileRNO = GNUNET_BIO_read_open (fileNameNO); GNUNET_log_skip (0, GNUNET_YES); GNUNET_assert (NULL == fileRNO); return 0; } static int test_fullfile_rw () { #ifdef LINUX /* /dev/full only seems to exist on Linux */ char *msg; int64_t testNum; char *readResultString; char readResult[200]; struct GNUNET_BIO_WriteHandle *fileW; struct GNUNET_BIO_ReadHandle *fileR; struct GNUNET_CONTAINER_MetaData *metaDataW; struct GNUNET_CONTAINER_MetaData *metaDataR; metaDataW = GNUNET_CONTAINER_meta_data_create (); GNUNET_CONTAINER_meta_data_add_publication_date (metaDataW); fileW = GNUNET_BIO_write_open ("/dev/full"); GNUNET_assert (NULL != fileW); (void) GNUNET_BIO_write (fileW, TESTSTRING, strlen (TESTSTRING)); (void) GNUNET_BIO_write_string (fileW, TESTSTRING); (void) GNUNET_BIO_write_meta_data (fileW, metaDataW); GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_write_close (fileW)); GNUNET_CONTAINER_meta_data_destroy (metaDataW); fileW = GNUNET_BIO_write_open ("/dev/full"); GNUNET_assert (NULL != fileW); GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_write_close (fileW)); fileR = GNUNET_BIO_read_open ("/dev/null"); GNUNET_assert (NULL != fileR); GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read (fileR, "Read error", readResult, sizeof (readResult))); readResultString = NULL; GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_string (fileR, "Read string error", &readResultString, 200)); GNUNET_assert (NULL == readResultString); GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_int64 (fileR, &testNum)); metaDataR = NULL; GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_meta_data (fileR, "Read meta error", &metaDataR)); msg = NULL; GNUNET_BIO_read_close (fileR, &msg); GNUNET_free (msg); GNUNET_assert (NULL == metaDataR); #endif return 0; } static int test_fakestring_rw () { char *msg; int32_t tmpInt = 2; char *readResult; struct GNUNET_BIO_WriteHandle *fileW; struct GNUNET_BIO_ReadHandle *fileR; char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); fileW = GNUNET_BIO_write_open (fileName); GNUNET_assert (NULL != fileW); GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int32 (fileW, tmpInt)); GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); fileR = GNUNET_BIO_read_open (fileName); GNUNET_assert (NULL != fileR); GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_string (fileR, "Read string error", &readResult, 200)); msg = NULL; GNUNET_BIO_read_close (fileR, &msg); GNUNET_free (msg); GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); GNUNET_free (fileName); return 0; } static int test_fakemeta_rw () { char *msg; int32_t tmpInt = 2; struct GNUNET_BIO_WriteHandle *fileW; struct GNUNET_BIO_ReadHandle *fileR; char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); struct GNUNET_CONTAINER_MetaData *metaDataR; fileW = GNUNET_BIO_write_open (fileName); GNUNET_assert (NULL != fileW); GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int32 (fileW, tmpInt)); GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); fileR = GNUNET_BIO_read_open (fileName); GNUNET_assert (NULL != fileR); metaDataR = NULL; GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_meta_data (fileR, "Read meta error", &metaDataR)); GNUNET_assert (NULL == metaDataR); msg = NULL; GNUNET_BIO_read_close (fileR, &msg); GNUNET_free (msg); GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); GNUNET_free (fileName); return 0; } static int test_fakebigmeta_rw () { char *msg; int32_t tmpInt = 1024 * 1024 * 10; struct GNUNET_BIO_WriteHandle *fileW; struct GNUNET_BIO_ReadHandle *fileR; char *fileName = GNUNET_DISK_mktemp ("gnunet_bio"); struct GNUNET_CONTAINER_MetaData *metaDataR; fileW = GNUNET_BIO_write_open (fileName); GNUNET_assert (NULL != fileW); GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_int32 (fileW, tmpInt)); GNUNET_assert (GNUNET_OK == GNUNET_BIO_write_close (fileW)); fileR = GNUNET_BIO_read_open (fileName); GNUNET_assert (NULL != fileR); metaDataR = NULL; GNUNET_assert (GNUNET_SYSERR == GNUNET_BIO_read_meta_data (fileR, "Read meta error", &metaDataR)); msg = NULL; GNUNET_BIO_read_close (fileR, &msg); GNUNET_free (msg); GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (fileName)); GNUNET_assert (NULL == metaDataR); GNUNET_free (fileName); return 0; } static int check_string_rw () { GNUNET_assert (0 == test_nullstring_rw ()); GNUNET_assert (0 == test_emptystring_rw ()); GNUNET_assert (0 == test_bigstring_rw ()); GNUNET_assert (0 == test_fakestring_rw ()); return 0; } static int check_metadata_rw () { GNUNET_assert (0 == test_fakebigmeta_rw ()); GNUNET_assert (0 == test_fakemeta_rw ()); GNUNET_assert (0 == test_bigmeta_rw ()); return 0; } static int check_file_rw () { GNUNET_assert (0 == test_normal_rw ()); GNUNET_assert (0 == test_nullfile_rw ()); GNUNET_assert (0 == test_fullfile_rw ()); GNUNET_assert (0 == test_directory_r ()); return 0; } int main (int argc, char *argv[]) { GNUNET_log_setup ("test-bio", "WARNING", NULL); GNUNET_assert (0 == check_file_rw ()); GNUNET_assert (0 == check_metadata_rw ()); GNUNET_assert (0 == check_string_rw ()); return 0; } /* end of test_bio.c */ gnunet-0.9.3/src/util/helper.c0000644000175000017500000003324511760502551013144 00000000000000/* This file is part of GNUnet. (C) 2011, 2012 Christian Grothoff GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/helper.c * @brief API for dealing with (SUID) helper processes that communicate via GNUNET_MessageHeaders on stdin/stdout * @author Philipp Toelke * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" /** * Entry in the queue of messages we need to transmit to the helper. */ struct GNUNET_HELPER_SendHandle { /** * This is an entry in a DLL. */ struct GNUNET_HELPER_SendHandle *next; /** * This is an entry in a DLL. */ struct GNUNET_HELPER_SendHandle *prev; /** * Message to transmit (allocated at the end of this struct) */ const struct GNUNET_MessageHeader *msg; /** * The handle to a helper process. */ struct GNUNET_HELPER_Handle *h; /** * Function to call upon completion. */ GNUNET_HELPER_Continuation cont; /** * Closure to 'cont'. */ void *cont_cls; /** * Current write position. */ unsigned int wpos; }; /** * The handle to a helper process. */ struct GNUNET_HELPER_Handle { /** * PipeHandle to receive data from the helper */ struct GNUNET_DISK_PipeHandle *helper_in; /** * PipeHandle to send data to the helper */ struct GNUNET_DISK_PipeHandle *helper_out; /** * FileHandle to receive data from the helper */ const struct GNUNET_DISK_FileHandle *fh_from_helper; /** * FileHandle to send data to the helper */ const struct GNUNET_DISK_FileHandle *fh_to_helper; /** * The process id of the helper */ struct GNUNET_OS_Process *helper_proc; /** * The Message-Tokenizer that tokenizes the messages comming from the helper */ struct GNUNET_SERVER_MessageStreamTokenizer *mst; /** * First message queued for transmission to helper. */ struct GNUNET_HELPER_SendHandle *sh_head; /** * Last message queued for transmission to helper. */ struct GNUNET_HELPER_SendHandle *sh_tail; /** * Binary to run. */ const char *binary_name; /** * NULL-terminated list of command-line arguments. */ char *const *binary_argv; /** * Task to read from the helper. */ GNUNET_SCHEDULER_TaskIdentifier read_task; /** * Task to read from the helper. */ GNUNET_SCHEDULER_TaskIdentifier write_task; /** * Restart task. */ GNUNET_SCHEDULER_TaskIdentifier restart_task; }; /** * Stop the helper process, we're closing down or had an error. * * @param h handle to the helper process */ static void stop_helper (struct GNUNET_HELPER_Handle *h) { struct GNUNET_HELPER_SendHandle *sh; if (NULL != h->helper_proc) { GNUNET_break (0 == GNUNET_OS_process_kill (h->helper_proc, SIGTERM)); GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (h->helper_proc)); GNUNET_OS_process_destroy (h->helper_proc); h->helper_proc = NULL; } if (GNUNET_SCHEDULER_NO_TASK != h->restart_task) { GNUNET_SCHEDULER_cancel (h->restart_task); h->restart_task = GNUNET_SCHEDULER_NO_TASK; } if (GNUNET_SCHEDULER_NO_TASK != h->read_task) { GNUNET_SCHEDULER_cancel (h->read_task); h->read_task = GNUNET_SCHEDULER_NO_TASK; } if (GNUNET_SCHEDULER_NO_TASK != h->write_task) { GNUNET_SCHEDULER_cancel (h->write_task); h->write_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != h->helper_in) { GNUNET_DISK_pipe_close (h->helper_in); h->helper_in = NULL; h->fh_to_helper = NULL; } if (NULL != h->helper_out) { GNUNET_DISK_pipe_close (h->helper_out); h->helper_out = NULL; h->fh_from_helper = NULL; } while (NULL != (sh = h->sh_head)) { GNUNET_CONTAINER_DLL_remove (h->sh_head, h->sh_tail, sh); if (NULL != sh->cont) sh->cont (sh->cont_cls, GNUNET_NO); GNUNET_free (sh); } /* purge MST buffer */ (void) GNUNET_SERVER_mst_receive (h->mst, NULL, NULL, 0, GNUNET_YES, GNUNET_NO); } /** * Restart the helper process. * * @param cls handle to the helper process * @param tc scheduler context */ static void restart_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Read from the helper-process * * @param cls handle to the helper process * @param tc scheduler context */ static void helper_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_HELPER_Handle *h = cls; char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE] GNUNET_ALIGN; ssize_t t; h->read_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) { /* try again */ h->read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, h->fh_from_helper, &helper_read, h); return; } t = GNUNET_DISK_file_read (h->fh_from_helper, &buf, sizeof (buf)); if (t < 0) { /* On read-error, restart the helper */ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Error reading from `%s': %s\n"), h->binary_name, STRERROR (errno)); stop_helper (h); /* Restart the helper */ h->restart_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &restart_task, h); return; } if (0 == t) { /* this happens if the helper is shut down via a signal, so it is not a "hard" error */ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Got 0 bytes from helper `%s' (EOF)\n"), h->binary_name); stop_helper (h); /* Restart the helper */ h->restart_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &restart_task, h); return; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Got %u bytes from helper `%s'\n"), (unsigned int) t, h->binary_name); h->read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, h->fh_from_helper, &helper_read, h); if (GNUNET_SYSERR == GNUNET_SERVER_mst_receive (h->mst, NULL, buf, t, GNUNET_NO, GNUNET_NO)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to parse inbound message from helper `%s'\n"), h->binary_name); stop_helper (h); /* Restart the helper */ h->restart_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &restart_task, h); return; } } /** * Start the helper process. * * @param h handle to the helper process */ static void start_helper (struct GNUNET_HELPER_Handle *h) { h->helper_in = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO); h->helper_out = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); if ( (h->helper_in == NULL) || (h->helper_out == NULL)) { /* out of file descriptors? try again later... */ stop_helper (h); h->restart_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &restart_task, h); return; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting HELPER process `%s'\n"), h->binary_name); h->fh_from_helper = GNUNET_DISK_pipe_handle (h->helper_out, GNUNET_DISK_PIPE_END_READ); h->fh_to_helper = GNUNET_DISK_pipe_handle (h->helper_in, GNUNET_DISK_PIPE_END_WRITE); h->helper_proc = GNUNET_OS_start_process_vap (GNUNET_NO, h->helper_in, h->helper_out, h->binary_name, h->binary_argv); if (NULL == h->helper_proc) { /* failed to start process? try again later... */ stop_helper (h); h->restart_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &restart_task, h); return; } GNUNET_DISK_pipe_close_end (h->helper_out, GNUNET_DISK_PIPE_END_WRITE); GNUNET_DISK_pipe_close_end (h->helper_in, GNUNET_DISK_PIPE_END_READ); h->read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, h->fh_from_helper, &helper_read, h); } /** * Restart the helper process. * * @param cls handle to the helper process * @param tc scheduler context */ static void restart_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_HELPER_Handle*h = cls; h->restart_task = GNUNET_SCHEDULER_NO_TASK; start_helper (h); } /** * @brief Starts a helper and begins reading from it * * @param binary_name name of the binary to run * @param binary_argv NULL-terminated list of arguments to give when starting the binary (this * argument must not be modified by the client for * the lifetime of the helper h) * @param cb function to call if we get messages from the helper * @param cb_cls Closure for the callback * @return the new H, NULL on error */ struct GNUNET_HELPER_Handle* GNUNET_HELPER_start (const char *binary_name, char *const binary_argv[], GNUNET_SERVER_MessageTokenizerCallback cb, void *cb_cls) { struct GNUNET_HELPER_Handle*h; h = GNUNET_malloc (sizeof (struct GNUNET_HELPER_Handle)); h->binary_name = binary_name; h->binary_argv = binary_argv; h->mst = GNUNET_SERVER_mst_create (cb, cb_cls); start_helper (h); return h; } /** * @brief Kills the helper, closes the pipe and frees the h * * @param h h to helper to stop */ void GNUNET_HELPER_stop (struct GNUNET_HELPER_Handle *h) { struct GNUNET_HELPER_SendHandle *sh; /* signal pending writes that we were stopped */ while (NULL != (sh = h->sh_head)) { GNUNET_CONTAINER_DLL_remove (h->sh_head, h->sh_tail, sh); if (NULL != sh->cont) sh->cont (sh->cont_cls, GNUNET_SYSERR); GNUNET_free (sh); } stop_helper (h); GNUNET_SERVER_mst_destroy (h->mst); GNUNET_free (h); } /** * Write to the helper-process * * @param cls handle to the helper process * @param tc scheduler context */ static void helper_write (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_HELPER_Handle *h = cls; struct GNUNET_HELPER_SendHandle *sh; const char *buf; ssize_t t; h->write_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) { /* try again */ h->write_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, h->fh_to_helper, &helper_write, h); return; } if (NULL == (sh = h->sh_head)) return; /* how did this happen? */ buf = (const char*) sh->msg; t = GNUNET_DISK_file_write (h->fh_to_helper, &buf[sh->wpos], ntohs (sh->msg->size) - sh->wpos); if (t <= 0) { /* On write-error, restart the helper */ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Error writing to `%s': %s\n"), h->binary_name, STRERROR (errno)); stop_helper (h); /* Restart the helper */ h->restart_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &restart_task, h); return; } sh->wpos += t; if (sh->wpos == ntohs (sh->msg->size)) { GNUNET_CONTAINER_DLL_remove (h->sh_head, h->sh_tail, sh); if (NULL != sh->cont) sh->cont (sh->cont_cls, GNUNET_YES); GNUNET_free (sh); } if (NULL != h->sh_head) h->write_task = GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, h->fh_to_helper, &helper_write, h); } /** * Send an message to the helper. * * @param h helper to send message to * @param msg message to send * @param can_drop can the message be dropped if there is already one in the queue? * @param cont continuation to run once the message is out (PREREQ_DONE on succees, CANCEL * if the helper process died, NULL during GNUNET_HELPER_stop). * @param cont_cls closure for 'cont' * @return NULL if the message was dropped, * otherwise handle to cancel *cont* (actual transmission may * not be abortable) */ struct GNUNET_HELPER_SendHandle * GNUNET_HELPER_send (struct GNUNET_HELPER_Handle *h, const struct GNUNET_MessageHeader *msg, int can_drop, GNUNET_HELPER_Continuation cont, void *cont_cls) { struct GNUNET_HELPER_SendHandle *sh; uint16_t mlen; if (NULL == h->fh_to_helper) return NULL; if ( (GNUNET_YES == can_drop) && (NULL != h->sh_head) ) return NULL; mlen = ntohs (msg->size); sh = GNUNET_malloc (sizeof (struct GNUNET_HELPER_SendHandle) + mlen); sh->msg = (const struct GNUNET_MessageHeader*) &sh[1]; memcpy (&sh[1], msg, mlen); sh->h = h; sh->cont = cont; sh->cont_cls = cont_cls; GNUNET_CONTAINER_DLL_insert_tail (h->sh_head, h->sh_tail, sh); if (GNUNET_SCHEDULER_NO_TASK == h->write_task) h->write_task = GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, h->fh_to_helper, &helper_write, h); return sh; } /** * Cancel a 'send' operation. If possible, transmitting the * message is also aborted, but at least 'cont' won't be * called. * * @param sh operation to cancel */ void GNUNET_HELPER_send_cancel (struct GNUNET_HELPER_SendHandle *sh) { struct GNUNET_HELPER_Handle *h = sh->h; sh->cont = NULL; sh->cont_cls = NULL; if (0 == sh->wpos) { GNUNET_CONTAINER_DLL_remove (h->sh_head, h->sh_tail, sh); if (NULL == h->sh_head) { GNUNET_SCHEDULER_cancel (h->write_task); h->write_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_free (sh); } } /* end of helper.c */ gnunet-0.9.3/src/util/test_strings.c0000644000175000017500000000770511760502551014417 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_strings.c * @brief testcase for strings.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_strings_lib.h" #define VERBOSE GNUNET_NO #define WANT(a,b) if (0 != strcmp(a,b)) { fprintf(stderr, "Got `%s', wanted `%s'\n", b, a); GNUNET_free(b); GNUNET_break(0); return 1;} else { GNUNET_free (b); } #define WANTB(a,b,l) if (0 != memcmp(a,b,l)) { GNUNET_break(0); return 1;} else { } static int check () { char buf[128]; char *r; char *b; struct GNUNET_TIME_Absolute at; const char *hdir; sprintf (buf, "4 %s", _( /* size unit */ "b")); b = GNUNET_STRINGS_byte_size_fancy (4); WANT (buf, b); sprintf (buf, "10 %s", _( /* size unit */ "KiB")); b = GNUNET_STRINGS_byte_size_fancy (10240); WANT (buf, b); sprintf (buf, "10 %s", _( /* size unit */ "TiB")); b = GNUNET_STRINGS_byte_size_fancy (10240LL * 1024LL * 1024LL * 1024LL); WANT (buf, b); sprintf (buf, "4 %s", _( /* time unit */ "ms")); b = GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 4)); WANT (buf, b); sprintf (buf, "7 %s", _( /* time unit */ "s")); b = GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 7 * 1000)); WANT (buf, b); sprintf (buf, "7 %s", _( /* time unit */ "h")); b = GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 7 * 60 * 60 * 1000)); WANT (buf, b); #ifndef MINGW hdir = getenv ("HOME"); #else hdir = getenv ("USERPROFILE"); #endif GNUNET_snprintf (buf, sizeof (buf), "%s%s", hdir, DIR_SEPARATOR_STR); b = GNUNET_STRINGS_filename_expand ("~"); GNUNET_assert (b != NULL); WANT (buf, b); GNUNET_STRINGS_buffer_fill (buf, sizeof (buf), 3, "a", "btx", "c"); WANTB ("a\0btx\0c", buf, 8); if (6 != GNUNET_STRINGS_buffer_tokenize (buf, sizeof (buf), 2, &r, &b)) return 1; r = GNUNET_strdup (r); WANT ("a", r); b = GNUNET_strdup (b); WANT ("btx", b); if (0 != GNUNET_STRINGS_buffer_tokenize (buf, 2, 2, &r, &b)) return 1; at.abs_value = 5000; r = GNUNET_STRINGS_absolute_time_to_string (at); /* r should be something like "Wed Dec 31 17:00:05 1969" * where the details of the day and hour depend on the timezone; * however, the "0:05 19" should always be there; hence: */ if (NULL == strstr (r, "0:05 19")) { FPRINTF (stderr, "Got %s\n", r); GNUNET_break (0); GNUNET_free (r); return 1; } GNUNET_free (r); b = GNUNET_STRINGS_to_utf8 ("TEST", 4, "ASCII"); WANT ("TEST", b); #if ENABLE_NLS && HAVE_ICONV GNUNET_log_skip (2, GNUNET_NO); b = GNUNET_STRINGS_to_utf8 ("TEST", 4, "unknown"); GNUNET_log_skip (0, GNUNET_YES); WANT ("TEST", b); #endif return 0; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test_strings", "ERROR", NULL); ret = check (); return ret; } /* end of test_strings.c */ gnunet-0.9.3/src/util/service.c0000644000175000017500000015211511761753145013333 00000000000000/* This file is part of GNUnet. (C) 2009, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/service.c * @brief functions related to starting services * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_configuration_lib.h" #include "gnunet_crypto_lib.h" #include "gnunet_directories.h" #include "gnunet_disk_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_protocols.h" #include "gnunet_resolver_service.h" #include "gnunet_server_lib.h" #include "gnunet_service_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) /* ******************* access control ******************** */ /** * @brief IPV4 network in CIDR notation. */ struct IPv4NetworkSet { /** * IPv4 address. */ struct in_addr network; /** * IPv4 netmask. */ struct in_addr netmask; }; /** * @brief network in CIDR notation for IPV6. */ struct IPv6NetworkSet { /** * IPv6 address. */ struct in6_addr network; /** * IPv6 netmask. */ struct in6_addr netmask; }; int GNUNET_SPEEDUP_start_ (const struct GNUNET_CONFIGURATION_Handle *cfg); int GNUNET_SPEEDUP_stop_ (void); /** * Parse a network specification. The argument specifies * a list of networks. The format is * [network/netmask;]* (no whitespace, must be terminated * with a semicolon). The network must be given in dotted-decimal * notation. The netmask can be given in CIDR notation (/16) or * in dotted-decimal (/255.255.0.0). * * @param routeList a string specifying the forbidden networks * @return the converted list, NULL if the synatx is flawed */ static struct IPv4NetworkSet * parse_ipv4_specification (const char *routeList) { unsigned int count; unsigned int i; unsigned int j; unsigned int len; int cnt; unsigned int pos; unsigned int temps[8]; int slash; struct IPv4NetworkSet *result; if (NULL == routeList) return NULL; len = strlen (routeList); if (0 == len) return NULL; count = 0; for (i = 0; i < len; i++) if (routeList[i] == ';') count++; result = GNUNET_malloc (sizeof (struct IPv4NetworkSet) * (count + 1)); i = 0; pos = 0; while (i < count) { cnt = SSCANF (&routeList[pos], "%u.%u.%u.%u/%u.%u.%u.%u;", &temps[0], &temps[1], &temps[2], &temps[3], &temps[4], &temps[5], &temps[6], &temps[7]); if (8 == cnt) { for (j = 0; j < 8; j++) if (temps[j] > 0xFF) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"), &routeList[pos]); GNUNET_free (result); return NULL; } result[i].network.s_addr = htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) + temps[3]); result[i].netmask.s_addr = htonl ((temps[4] << 24) + (temps[5] << 16) + (temps[6] << 8) + temps[7]); while (routeList[pos] != ';') pos++; pos++; i++; continue; } /* try second notation */ cnt = SSCANF (&routeList[pos], "%u.%u.%u.%u/%u;", &temps[0], &temps[1], &temps[2], &temps[3], &slash); if (5 == cnt) { for (j = 0; j < 4; j++) if (temps[j] > 0xFF) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"), &routeList[pos]); GNUNET_free (result); return NULL; } result[i].network.s_addr = htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) + temps[3]); if ((slash <= 32) && (slash >= 0)) { result[i].netmask.s_addr = 0; while (slash > 0) { result[i].netmask.s_addr = (result[i].netmask.s_addr >> 1) + 0x80000000; slash--; } result[i].netmask.s_addr = htonl (result[i].netmask.s_addr); while (';' != routeList[pos]) pos++; pos++; i++; continue; } else { LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid network notation ('/%d' is not legal in IPv4 CIDR)."), slash); GNUNET_free (result); return NULL; /* error */ } } /* try third notation */ slash = 32; cnt = SSCANF (&routeList[pos], "%u.%u.%u.%u;", &temps[0], &temps[1], &temps[2], &temps[3]); if (4 == cnt) { for (j = 0; j < 4; j++) if (temps[j] > 0xFF) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"), &routeList[pos]); GNUNET_free (result); return NULL; } result[i].network.s_addr = htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) + temps[3]); result[i].netmask.s_addr = 0; while (slash > 0) { result[i].netmask.s_addr = (result[i].netmask.s_addr >> 1) + 0x80000000; slash--; } result[i].netmask.s_addr = htonl (result[i].netmask.s_addr); while (routeList[pos] != ';') pos++; pos++; i++; continue; } LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"), &routeList[pos]); GNUNET_free (result); return NULL; /* error */ } if (pos < strlen (routeList)) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"), &routeList[pos]); GNUNET_free (result); return NULL; /* oops */ } return result; /* ok */ } /** * Parse a network specification. The argument specifies * a list of networks. The format is * [network/netmask;]* (no whitespace, must be terminated * with a semicolon). The network must be given in colon-hex * notation. The netmask must be given in CIDR notation (/16) or * can be omitted to specify a single host. * * @param routeListX a string specifying the forbidden networks * @return the converted list, NULL if the synatx is flawed */ static struct IPv6NetworkSet * parse_ipv6_specification (const char *routeListX) { unsigned int count; unsigned int i; unsigned int len; unsigned int pos; int start; int slash; int ret; char *routeList; struct IPv6NetworkSet *result; unsigned int bits; unsigned int off; int save; if (NULL == routeListX) return NULL; len = strlen (routeListX); if (0 == len) return NULL; routeList = GNUNET_strdup (routeListX); count = 0; for (i = 0; i < len; i++) if (';' == routeList[i]) count++; if (';' != routeList[len - 1]) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid network notation (does not end with ';': `%s')\n"), routeList); GNUNET_free (routeList); return NULL; } result = GNUNET_malloc (sizeof (struct IPv6NetworkSet) * (count + 1)); i = 0; pos = 0; while (i < count) { start = pos; while (';' != routeList[pos]) pos++; slash = pos; while ((slash >= start) && (routeList[slash] != '/')) slash--; if (slash < start) { memset (&result[i].netmask, 0xFF, sizeof (struct in6_addr)); slash = pos; } else { routeList[pos] = '\0'; ret = inet_pton (AF_INET6, &routeList[slash + 1], &result[i].netmask); if (ret <= 0) { save = errno; if ((1 != SSCANF (&routeList[slash + 1], "%u", &bits)) || (bits >= 128)) { if (0 == ret) LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong format `%s' for netmask\n"), &routeList[slash + 1]); else { errno = save; LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "inet_pton"); } GNUNET_free (result); GNUNET_free (routeList); return NULL; } off = 0; while (bits > 8) { result[i].netmask.s6_addr[off++] = 0xFF; bits -= 8; } while (bits > 0) { result[i].netmask.s6_addr[off] = (result[i].netmask.s6_addr[off] >> 1) + 0x80; bits--; } } } routeList[slash] = '\0'; ret = inet_pton (AF_INET6, &routeList[start], &result[i].network); if (ret <= 0) { if (0 == ret) LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong format `%s' for network\n"), &routeList[slash + 1]); else LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "inet_pton"); GNUNET_free (result); GNUNET_free (routeList); return NULL; } pos++; i++; } GNUNET_free (routeList); return result; } /** * Check if the given IP address is in the list of IP addresses. * * @param list a list of networks * @param add the IP to check (in network byte order) * @return GNUNET_NO if the IP is not in the list, GNUNET_YES if it it is */ static int check_ipv4_listed (const struct IPv4NetworkSet *list, const struct in_addr *add) { unsigned int i; if (NULL == list) return GNUNET_NO; i = 0; while ((list[i].network.s_addr != 0) || (list[i].netmask.s_addr != 0)) { if ((add->s_addr & list[i].netmask.s_addr) == (list[i].network.s_addr & list[i].netmask.s_addr)) return GNUNET_YES; i++; } return GNUNET_NO; } /** * Check if the given IP address is in the list of IP addresses. * * @param list a list of networks * @param ip the IP to check (in network byte order) * @return GNUNET_NO if the IP is not in the list, GNUNET_YES if it it is */ static int check_ipv6_listed (const struct IPv6NetworkSet *list, const struct in6_addr *ip) { unsigned int i; unsigned int j; struct in6_addr zero; if (NULL == list) return GNUNET_NO; memset (&zero, 0, sizeof (struct in6_addr)); i = 0; NEXT: while (0 != memcmp (&zero, &list[i].network, sizeof (struct in6_addr))) { for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++) if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) != (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j])) { i++; goto NEXT; } return GNUNET_YES; } return GNUNET_NO; } /* ****************** service struct ****************** */ /** * Context for "service_task". */ struct GNUNET_SERVICE_Context { /** * Our configuration. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Handle for the server. */ struct GNUNET_SERVER_Handle *server; /** * NULL-terminated array of addresses to bind to, NULL if we got pre-bound * listen sockets. */ struct sockaddr **addrs; /** * Name of our service. */ const char *service_name; /** * Main service-specific task to run. */ GNUNET_SERVICE_Main task; /** * Closure for task. */ void *task_cls; /** * IPv4 addresses that are not allowed to connect. */ struct IPv4NetworkSet *v4_denied; /** * IPv6 addresses that are not allowed to connect. */ struct IPv6NetworkSet *v6_denied; /** * IPv4 addresses that are allowed to connect (if not * set, all are allowed). */ struct IPv4NetworkSet *v4_allowed; /** * IPv6 addresses that are allowed to connect (if not * set, all are allowed). */ struct IPv6NetworkSet *v6_allowed; /** * My (default) message handlers. Adjusted copy * of "defhandlers". */ struct GNUNET_SERVER_MessageHandler *my_handlers; /** * Array of the lengths of the entries in addrs. */ socklen_t *addrlens; /** * NULL-terminated array of listen sockets we should take over. */ struct GNUNET_NETWORK_Handle **lsocks; /** * Task ID of the shutdown task. */ GNUNET_SCHEDULER_TaskIdentifier shutdown_task; /** * Idle timeout for server. */ struct GNUNET_TIME_Relative timeout; /** * Overall success/failure of the service start. */ int ret; /** * If we are daemonizing, this FD is set to the * pipe to the parent. Send '.' if we started * ok, '!' if not. -1 if we are not daemonizing. */ int ready_confirm_fd; /** * Do we close connections if we receive messages * for which we have no handler? */ int require_found; /** * Do we require a matching UID for UNIX domain socket connections? * GNUNET_NO means that the UID does not have to match (however, * "match_gid" may still impose other access control checks). */ int match_uid; /** * Do we require a matching GID for UNIX domain socket connections? * Ignored if "match_uid" is GNUNET_YES. Note that this is about * checking that the client's UID is in our group OR that the * client's GID is our GID. If both "match_gid" and "match_uid" are * "GNUNET_NO", all users on the local system have access. */ int match_gid; /** * Our options. */ enum GNUNET_SERVICE_Options options; }; /* ****************** message handlers ****************** */ /** * Send a 'TEST' message back to the client. * * @param cls the 'struct GNUNET_SERVER_Client' to send TEST to * @param size number of bytes available in 'buf' * @param buf where to copy the message * @return number of bytes written to 'buf' */ static size_t write_test (void *cls, size_t size, void *buf) { struct GNUNET_SERVER_Client *client = cls; struct GNUNET_MessageHeader *msg; if (size < sizeof (struct GNUNET_MessageHeader)) { GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return 0; /* client disconnected */ } msg = (struct GNUNET_MessageHeader *) buf; msg->type = htons (GNUNET_MESSAGE_TYPE_TEST); msg->size = htons (sizeof (struct GNUNET_MessageHeader)); GNUNET_SERVER_receive_done (client, GNUNET_OK); return sizeof (struct GNUNET_MessageHeader); } /** * Handler for TEST message. * * @param cls closure (refers to service) * @param client identification of the client * @param message the actual message */ static void handle_test (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { /* simply bounce message back to acknowledge */ if (NULL == GNUNET_SERVER_notify_transmit_ready (client, sizeof (struct GNUNET_MessageHeader), GNUNET_TIME_UNIT_FOREVER_REL, &write_test, client)) GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); } /** * Default handlers for all services. Will be copied and the * "callback_cls" fields will be replaced with the specific service * struct. */ static const struct GNUNET_SERVER_MessageHandler defhandlers[] = { {&handle_test, NULL, GNUNET_MESSAGE_TYPE_TEST, sizeof (struct GNUNET_MessageHeader)}, {NULL, NULL, 0, 0} }; /* ****************** service core routines ************** */ /** * Check if access to the service is allowed from the given address. * * @param cls closure * @param uc credentials, if available, otherwise NULL * @param addr address * @param addrlen length of address * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR * for unknown address family (will be denied). */ static int check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc, const struct sockaddr *addr, socklen_t addrlen) { struct GNUNET_SERVICE_Context *sctx = cls; const struct sockaddr_in *i4; const struct sockaddr_in6 *i6; int ret; switch (addr->sa_family) { case AF_INET: GNUNET_assert (addrlen == sizeof (struct sockaddr_in)); i4 = (const struct sockaddr_in *) addr; ret = ((NULL == sctx->v4_allowed) || (check_ipv4_listed (sctx->v4_allowed, &i4->sin_addr))) && ((NULL == sctx->v4_denied) || (!check_ipv4_listed (sctx->v4_denied, &i4->sin_addr))); break; case AF_INET6: GNUNET_assert (addrlen == sizeof (struct sockaddr_in6)); i6 = (const struct sockaddr_in6 *) addr; ret = ((NULL == sctx->v6_allowed) || (check_ipv6_listed (sctx->v6_allowed, &i6->sin6_addr))) && ((NULL == sctx->v6_denied) || (!check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr))); break; #ifndef WINDOWS case AF_UNIX: ret = GNUNET_OK; /* always OK for now */ if (GNUNET_YES == sctx->match_uid) { /* UID match required */ ret = (NULL != uc) && (uc->uid == geteuid ()); } else if ( (GNUNET_YES == sctx->match_gid) && ( (NULL == uc) || (uc->uid != geteuid ()) ) ) { /* group match required and UID does not match */ if (NULL == uc) { /* no credentials, group match not possible */ ret = GNUNET_NO; } else { struct group *grp; unsigned int i; if (uc->gid != getegid()) { /* default group did not match, but maybe the user is in our group, let's check */ grp = getgrgid (getegid ()); if (NULL == grp) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "getgrgid"); return GNUNET_NO; } ret = GNUNET_NO; for (i=0; NULL != grp->gr_mem[i]; i++) { struct passwd *nam = getpwnam (grp->gr_mem[i]); if (NULL == nam) continue; /* name in group that is not in user DB !? */ if (nam->pw_uid == uc->uid) { /* yes, uid is in our group, allow! */ ret = GNUNET_YES; break; } } } } } if (GNUNET_NO == ret) LOG (GNUNET_ERROR_TYPE_WARNING, _("Access denied to UID %d / GID %d\n"), (NULL == uc) ? -1 : uc->uid, (NULL == uc) ? -1 : uc->gid); break; #endif default: LOG (GNUNET_ERROR_TYPE_WARNING, _("Unknown address family %d\n"), addr->sa_family); return GNUNET_SYSERR; } if (GNUNET_OK != ret) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Access from `%s' denied to service `%s'\n"), GNUNET_a2s (addr, addrlen), sctx->service_name); } return ret; } /** * Get the name of the file where we will * write the PID of the service. * * @param sctx service context * @return name of the file for the process ID */ static char * get_pid_file_name (struct GNUNET_SERVICE_Context *sctx) { char *pif; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name, "PIDFILE", &pif)) return NULL; return pif; } /** * Parse an IPv4 access control list. * * @param ret location where to write the ACL (set) * @param sctx service context to use to get the configuration * @param option name of the ACL option to parse * @return GNUNET_SYSERR on parse error, GNUNET_OK on success (including * no ACL configured) */ static int process_acl4 (struct IPv4NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx, const char *option) { char *opt; if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option)) { *ret = NULL; return GNUNET_OK; } GNUNET_break (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (sctx->cfg, sctx->service_name, option, &opt)); if (NULL == (*ret = parse_ipv4_specification (opt))) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"), opt, sctx->service_name, option); GNUNET_free (opt); return GNUNET_SYSERR; } GNUNET_free (opt); return GNUNET_OK; } /** * Parse an IPv6 access control list. * * @param ret location where to write the ACL (set) * @param sctx service context to use to get the configuration * @param option name of the ACL option to parse * @return GNUNET_SYSERR on parse error, GNUNET_OK on success (including * no ACL configured) */ static int process_acl6 (struct IPv6NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx, const char *option) { char *opt; if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option)) { *ret = NULL; return GNUNET_OK; } GNUNET_break (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (sctx->cfg, sctx->service_name, option, &opt)); if (NULL == (*ret = parse_ipv6_specification (opt))) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"), opt, sctx->service_name, option); GNUNET_free (opt); return GNUNET_SYSERR; } GNUNET_free (opt); return GNUNET_OK; } /** * Add the given UNIX domain path as an address to the * list (as the first entry). * * @param saddrs array to update * @param saddrlens where to store the address length * @param unixpath path to add */ static void add_unixpath (struct sockaddr **saddrs, socklen_t * saddrlens, const char *unixpath) { #ifdef AF_UNIX struct sockaddr_un *un; size_t slen; un = GNUNET_malloc (sizeof (struct sockaddr_un)); un->sun_family = AF_UNIX; slen = strlen (unixpath) + 1; if (slen >= sizeof (un->sun_path)) slen = sizeof (un->sun_path) - 1; memcpy (un->sun_path, unixpath, slen); un->sun_path[slen] = '\0'; slen = sizeof (struct sockaddr_un); #if LINUX un->sun_path[0] = '\0'; #endif #if HAVE_SOCKADDR_IN_SIN_LEN un->sun_len = (u_char) slen; #endif *saddrs = (struct sockaddr *) un; *saddrlens = slen; #else /* this function should never be called * unless AF_UNIX is defined! */ GNUNET_assert (0); #endif } /** * Get the list of addresses that a server for the given service * should bind to. * * @param service_name name of the service * @param cfg configuration (which specifies the addresses) * @param addrs set (call by reference) to an array of pointers to the * addresses the server should bind to and listen on; the * array will be NULL-terminated (on success) * @param addr_lens set (call by reference) to an array of the lengths * of the respective 'struct sockaddr' struct in the 'addrs' * array (on success) * @return number of addresses found on success, * GNUNET_SYSERR if the configuration * did not specify reasonable finding information or * if it specified a hostname that could not be resolved; * GNUNET_NO if the number of addresses configured is * zero (in this case, '*addrs' and '*addr_lens' will be * set to NULL). */ int GNUNET_SERVICE_get_server_addresses (const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg, struct sockaddr ***addrs, socklen_t ** addr_lens) { int disablev6; struct GNUNET_NETWORK_Handle *desc; unsigned long long port; char *unixpath; struct addrinfo hints; struct addrinfo *res; struct addrinfo *pos; struct addrinfo *next; unsigned int i; int resi; int ret; struct sockaddr **saddrs; socklen_t *saddrlens; char *hostname; *addrs = NULL; *addr_lens = NULL; desc = NULL; if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6")) { if (GNUNET_SYSERR == (disablev6 = GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6"))) return GNUNET_SYSERR; } else disablev6 = GNUNET_NO; if (!disablev6) { /* probe IPv6 support */ desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); if (NULL == desc) { if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) || (EACCES == errno)) { LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket"); return GNUNET_SYSERR; } LOG (GNUNET_ERROR_TYPE_INFO, _ ("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"), service_name, STRERROR (errno)); disablev6 = GNUNET_YES; } else { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc)); desc = NULL; } } port = 0; if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT")) { GNUNET_break (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "PORT", &port)); if (port > 65535) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Require valid port number for service `%s' in configuration!\n"), service_name); return GNUNET_SYSERR; } } if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO")) { GNUNET_break (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "BINDTO", &hostname)); } else hostname = NULL; unixpath = NULL; #ifdef AF_UNIX if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "UNIXPATH", &unixpath)) && (0 < strlen (unixpath))) { /* probe UNIX support */ struct sockaddr_un s_un; if (strlen (unixpath) >= sizeof (s_un.sun_path)) { LOG (GNUNET_ERROR_TYPE_WARNING, _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath, sizeof (s_un.sun_path)); GNUNET_free_non_null (hostname); GNUNET_free (unixpath); return GNUNET_SYSERR; } desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0); if (NULL == desc) { if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) || (EACCES == errno)) { LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket"); GNUNET_free_non_null (hostname); GNUNET_free (unixpath); return GNUNET_SYSERR; } LOG (GNUNET_ERROR_TYPE_INFO, _ ("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"), service_name, STRERROR (errno)); GNUNET_free (unixpath); unixpath = NULL; } else { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc)); desc = NULL; } } #endif if ((0 == port) && (NULL == unixpath)) { LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"), service_name); GNUNET_free_non_null (hostname); return GNUNET_SYSERR; } if (0 == port) { saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *)); saddrlens = GNUNET_malloc (2 * sizeof (socklen_t)); add_unixpath (saddrs, saddrlens, unixpath); GNUNET_free_non_null (unixpath); GNUNET_free_non_null (hostname); *addrs = saddrs; *addr_lens = saddrlens; return 1; } if (NULL != hostname) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Resolving `%s' since that is where `%s' will bind to.\n", hostname, service_name); memset (&hints, 0, sizeof (struct addrinfo)); if (disablev6) hints.ai_family = AF_INET; hints.ai_protocol = IPPROTO_TCP; if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) || (res == NULL)) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to resolve `%s': %s\n"), hostname, gai_strerror (ret)); GNUNET_free (hostname); GNUNET_free_non_null (unixpath); return GNUNET_SYSERR; } next = res; i = 0; while (NULL != (pos = next)) { next = pos->ai_next; if ((disablev6) && (pos->ai_family == AF_INET6)) continue; i++; } if (0 == i) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to find %saddress for `%s'.\n"), disablev6 ? "IPv4 " : "", hostname); freeaddrinfo (res); GNUNET_free (hostname); GNUNET_free_non_null (unixpath); return GNUNET_SYSERR; } resi = i; if (NULL != unixpath) resi++; saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); i = 0; if (NULL != unixpath) { add_unixpath (saddrs, saddrlens, unixpath); i++; } next = res; while (NULL != (pos = next)) { next = pos->ai_next; if ((disablev6) && (AF_INET6 == pos->ai_family)) continue; if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol)) continue; /* not TCP */ if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype)) continue; /* huh? */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n", service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen)); if (AF_INET == pos->ai_family) { GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen); saddrlens[i] = pos->ai_addrlen; saddrs[i] = GNUNET_malloc (saddrlens[i]); memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); } else { GNUNET_assert (AF_INET6 == pos->ai_family); GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen); saddrlens[i] = pos->ai_addrlen; saddrs[i] = GNUNET_malloc (saddrlens[i]); memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); } i++; } GNUNET_free (hostname); freeaddrinfo (res); resi = i; } else { /* will bind against everything, just set port */ if (disablev6) { /* V4-only */ resi = 1; if (NULL != unixpath) resi++; i = 0; saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); if (NULL != unixpath) { add_unixpath (saddrs, saddrlens, unixpath); i++; } saddrlens[i] = sizeof (struct sockaddr_in); saddrs[i] = GNUNET_malloc (saddrlens[i]); #if HAVE_SOCKADDR_IN_SIN_LEN ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i]; #endif ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET; ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); } else { /* dual stack */ resi = 2; if (NULL != unixpath) resi++; saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); i = 0; if (NULL != unixpath) { add_unixpath (saddrs, saddrlens, unixpath); i++; } saddrlens[i] = sizeof (struct sockaddr_in6); saddrs[i] = GNUNET_malloc (saddrlens[i]); #if HAVE_SOCKADDR_IN_SIN_LEN ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0]; #endif ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6; ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); i++; saddrlens[i] = sizeof (struct sockaddr_in); saddrs[i] = GNUNET_malloc (saddrlens[i]); #if HAVE_SOCKADDR_IN_SIN_LEN ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1]; #endif ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET; ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); } } GNUNET_free_non_null (unixpath); *addrs = saddrs; *addr_lens = saddrlens; return resi; } #ifdef MINGW /** * Read listen sockets from the parent process (ARM). * * @param sctx service context to initialize * @return GNUNET_YES if ok, GNUNET_NO if not ok (must bind yourself), * and GNUNET_SYSERR on error. */ static int receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx) { const char *env_buf; int fail; uint64_t count; uint64_t i; HANDLE lsocks_pipe; env_buf = getenv ("GNUNET_OS_READ_LSOCKS"); if ((NULL == env_buf) || (strlen (env_buf) <= 0)) return GNUNET_NO; /* Using W32 API directly here, because this pipe will * never be used outside of this function, and it's just too much of a bother * to create a GNUnet API that boxes a HANDLE (the way it is done with socks) */ lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10); if ( (0 == lsocks_pipe) || (INVALID_HANDLE_VALUE == lsocks_pipe)) return GNUNET_NO; fail = 1; do { int ret; int fail2; DWORD rd; ret = ReadFile (lsocks_pipe, &count, sizeof (count), &rd, NULL); if ((0 == ret) || (sizeof (count) != rd) || (0 == count)) break; sctx->lsocks = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (count + 1)); fail2 = 1; for (i = 0; i < count; i++) { WSAPROTOCOL_INFOA pi; uint64_t size; SOCKET s; ret = ReadFile (lsocks_pipe, &size, sizeof (size), &rd, NULL); if ( (0 == ret) || (sizeof (size) != rd) || (sizeof (pi) != size) ) break; ret = ReadFile (lsocks_pipe, &pi, sizeof (pi), &rd, NULL); if ( (0 == ret) || (sizeof (pi) != rd)) break; s = WSASocketA (pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0, WSA_FLAG_OVERLAPPED); sctx->lsocks[i] = GNUNET_NETWORK_socket_box_native (s); if (NULL == sctx->lsocks[i]) break; else if (i == count - 1) fail2 = 0; } if (fail2) break; sctx->lsocks[count] = NULL; fail = 0; } while (fail); CloseHandle (lsocks_pipe); if (fail) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Could not access a pre-bound socket, will try to bind myself\n")); for (i = 0; (i < count) && (NULL != sctx->lsocks[i]); i++) GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[i])); GNUNET_free_non_null (sctx->lsocks); sctx->lsocks = NULL; return GNUNET_NO; } return GNUNET_YES; } #endif /** * Setup addr, addrlen, idle_timeout * based on configuration! * * Configuration may specify: * - PORT (where to bind to for TCP) * - UNIXPATH (where to bind to for UNIX domain sockets) * - TIMEOUT (after how many ms does an inactive service timeout); * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack) * - BINDTO (hostname or IP address to bind to, otherwise we take everything) * - ACCEPT_FROM (only allow connections from specified IPv4 subnets) * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets) * - REJECT_FROM (disallow allow connections from specified IPv4 subnets) * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets) * * @param sctx service context to initialize * @return GNUNET_OK if configuration succeeded */ static int setup_service (struct GNUNET_SERVICE_Context *sctx) { struct GNUNET_TIME_Relative idleout; int tolerant; #ifndef MINGW const char *lpid; unsigned int pid; const char *nfds; unsigned int cnt; int flags; #endif if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, "TIMEOUT")) { if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (sctx->cfg, sctx->service_name, "TIMEOUT", &idleout)) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Specified value for `%s' of service `%s' is invalid\n"), "TIMEOUT", sctx->service_name); return GNUNET_SYSERR; } sctx->timeout = idleout; } else sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL; if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, "TOLERANT")) { if (GNUNET_SYSERR == (tolerant = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name, "TOLERANT"))) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Specified value for `%s' of service `%s' is invalid\n"), "TOLERANT", sctx->service_name); return GNUNET_SYSERR; } } else tolerant = GNUNET_NO; #ifndef MINGW errno = 0; if ((NULL != (lpid = getenv ("LISTEN_PID"))) && (1 == SSCANF (lpid, "%u", &pid)) && (getpid () == (pid_t) pid) && (NULL != (nfds = getenv ("LISTEN_FDS"))) && (1 == SSCANF (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) && (cnt + 4 < FD_SETSIZE)) { sctx->lsocks = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (cnt + 1)); while (0 < cnt--) { flags = fcntl (3 + cnt, F_GETFD); if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) || (NULL == (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt)))) { LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Could not access pre-bound socket %u, will try to bind myself\n"), (unsigned int) 3 + cnt); cnt++; while (sctx->lsocks[cnt] != NULL) GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[cnt++])); GNUNET_free (sctx->lsocks); sctx->lsocks = NULL; break; } } unsetenv ("LISTEN_PID"); unsetenv ("LISTEN_FDS"); } #else if (getenv ("GNUNET_OS_READ_LSOCKS") != NULL) { receive_sockets_from_parent (sctx); putenv ("GNUNET_OS_READ_LSOCKS="); } #endif if ((NULL == sctx->lsocks) && (GNUNET_SYSERR == GNUNET_SERVICE_get_server_addresses (sctx->service_name, sctx->cfg, &sctx->addrs, &sctx->addrlens))) return GNUNET_SYSERR; sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES; sctx->match_uid = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name, "UNIX_MATCH_UID"); sctx->match_gid = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name, "UNIX_MATCH_GID"); process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM"); process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM"); process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6"); process_acl6 (&sctx->v6_allowed, sctx, "ACCEPT_FROM6"); return GNUNET_OK; } /** * Get the name of the user that'll be used * to provide the service. * * @param sctx service context * @return value of the 'USERNAME' option */ static char * get_user_name (struct GNUNET_SERVICE_Context *sctx) { char *un; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name, "USERNAME", &un)) return NULL; return un; } /** * Write PID file. * * @param sctx service context * @param pid PID to write (should be equal to 'getpid()' * @return GNUNET_OK on success (including no work to be done) */ static int write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid) { FILE *pidfd; char *pif; char *user; char *rdir; int len; if (NULL == (pif = get_pid_file_name (sctx))) return GNUNET_OK; /* no file desired */ user = get_user_name (sctx); rdir = GNUNET_strdup (pif); len = strlen (rdir); while ((len > 0) && (rdir[len] != DIR_SEPARATOR)) len--; rdir[len] = '\0'; if (0 != ACCESS (rdir, F_OK)) { /* we get to create a directory -- and claim it * as ours! */ GNUNET_DISK_directory_create (rdir); if ((NULL != user) && (0 < strlen (user))) GNUNET_DISK_file_change_owner (rdir, user); } if (0 != ACCESS (rdir, W_OK | X_OK)) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", rdir); GNUNET_free (rdir); GNUNET_free_non_null (user); GNUNET_free (pif); return GNUNET_SYSERR; } GNUNET_free (rdir); pidfd = FOPEN (pif, "w"); if (NULL == pidfd) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif); GNUNET_free (pif); GNUNET_free_non_null (user); return GNUNET_SYSERR; } if (0 > FPRINTF (pidfd, "%u", pid)) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif); GNUNET_break (0 == FCLOSE (pidfd)); if ((NULL != user) && (0 < strlen (user))) GNUNET_DISK_file_change_owner (pif, user); GNUNET_free_non_null (user); GNUNET_free (pif); return GNUNET_OK; } /** * Task run during shutdown. Stops the server/service. * * @param cls the 'struct GNUNET_SERVICE_Context' * @param tc unused */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_SERVICE_Context *service = cls; struct GNUNET_SERVER_Handle *server = service->server; service->shutdown_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (service->options & GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN)) GNUNET_SERVER_stop_listening (server); else GNUNET_SERVER_destroy (server); } /** * Initial task for the service. * * @param cls service context * @param tc unused */ static void service_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_SERVICE_Context *sctx = cls; unsigned int i; GNUNET_RESOLVER_connect (sctx->cfg); if (NULL != sctx->lsocks) sctx->server = GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks, sctx->timeout, sctx->require_found); else sctx->server = GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens, sctx->timeout, sctx->require_found); if (NULL == sctx->server) { if (NULL != sctx->addrs) { i = 0; while (NULL != sctx->addrs[i]) { LOG (GNUNET_ERROR_TYPE_INFO, _("Failed to start `%s' at `%s'\n"), sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i])); i++; } } sctx->ret = GNUNET_SYSERR; return; } if (0 == (sctx->options & GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN)) { /* install a task that will kill the server * process if the scheduler ever gets a shutdown signal */ sctx->shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, sctx); } sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers)); memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers)); i = 0; while (NULL != sctx->my_handlers[i].callback) sctx->my_handlers[i++].callback_cls = sctx; GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers); if (-1 != sctx->ready_confirm_fd) { GNUNET_break (1 == WRITE (sctx->ready_confirm_fd, ".", 1)); GNUNET_break (0 == CLOSE (sctx->ready_confirm_fd)); sctx->ready_confirm_fd = -1; write_pid_file (sctx, getpid ()); } if (NULL != sctx->addrs) { i = 0; while (NULL != sctx->addrs[i]) { LOG (GNUNET_ERROR_TYPE_INFO, _("Service `%s' runs at %s\n"), sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i])); i++; } } sctx->task (sctx->task_cls, sctx->server, sctx->cfg); } /** * Detach from terminal. * * @param sctx service context * @return GNUNET_OK on success, GNUNET_SYSERR on error */ static int detach_terminal (struct GNUNET_SERVICE_Context *sctx) { #ifndef MINGW pid_t pid; int nullfd; int filedes[2]; if (0 != PIPE (filedes)) { LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe"); return GNUNET_SYSERR; } pid = fork (); if (pid < 0) { LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork"); return GNUNET_SYSERR; } if (0 != pid) { /* Parent */ char c; GNUNET_break (0 == CLOSE (filedes[1])); c = 'X'; if (1 != READ (filedes[0], &c, sizeof (char))) LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read"); fflush (stdout); switch (c) { case '.': exit (0); case 'I': LOG (GNUNET_ERROR_TYPE_INFO, _("Service process failed to initialize\n")); break; case 'S': LOG (GNUNET_ERROR_TYPE_INFO, _("Service process could not initialize server function\n")); break; case 'X': LOG (GNUNET_ERROR_TYPE_INFO, _("Service process failed to report status\n")); break; } exit (1); /* child reported error */ } GNUNET_break (0 == CLOSE (0)); GNUNET_break (0 == CLOSE (1)); GNUNET_break (0 == CLOSE (filedes[0])); nullfd = OPEN ("/dev/null", O_RDWR | O_APPEND); if (nullfd < 0) return GNUNET_SYSERR; /* set stdin/stdout to /dev/null */ if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0)) { LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2"); (void) CLOSE (nullfd); return GNUNET_SYSERR; } (void) CLOSE (nullfd); /* Detach from controlling terminal */ pid = setsid (); if (-1 == pid) LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid"); sctx->ready_confirm_fd = filedes[1]; #else /* FIXME: we probably need to do something else * elsewhere in order to fork the process itself... */ FreeConsole (); #endif return GNUNET_OK; } /** * Set user ID. * * @param sctx service context * @return GNUNET_OK on success, GNUNET_SYSERR on error */ static int set_user_id (struct GNUNET_SERVICE_Context *sctx) { char *user; if (NULL == (user = get_user_name (sctx))) return GNUNET_OK; /* keep */ #ifndef MINGW struct passwd *pws; errno = 0; pws = getpwnam (user); if (NULL == pws) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot obtain information about user `%s': %s\n"), user, errno == 0 ? _("No such user") : STRERROR (errno)); GNUNET_free (user); return GNUNET_SYSERR; } if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) || #if HAVE_INITGROUPS (0 != initgroups (user, pws->pw_gid)) || #endif (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid))) { if ((0 != setregid (pws->pw_gid, pws->pw_gid)) || (0 != setreuid (pws->pw_uid, pws->pw_uid))) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot change user/group to `%s': %s\n"), user, STRERROR (errno)); GNUNET_free (user); return GNUNET_SYSERR; } } #endif GNUNET_free (user); return GNUNET_OK; } /** * Delete the PID file that was created by our parent. * * @param sctx service context */ static void pid_file_delete (struct GNUNET_SERVICE_Context *sctx) { char *pif = get_pid_file_name (sctx); if (NULL == pif) return; /* no PID file */ if (0 != UNLINK (pif)) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif); GNUNET_free (pif); } /** * Run a standard GNUnet service startup sequence (initialize loggers * and configuration, parse options). * * @param argc number of command line arguments * @param argv command line arguments * @param service_name our service name * @param options service options * @param task main task of the service * @param task_cls closure for task * @return GNUNET_SYSERR on error, GNUNET_OK * if we shutdown nicely */ int GNUNET_SERVICE_run (int argc, char *const *argv, const char *service_name, enum GNUNET_SERVICE_Options options, GNUNET_SERVICE_Main task, void *task_cls) { #define HANDLE_ERROR do { GNUNET_break (0); goto shutdown; } while (0) int err; char *cfg_fn; char *loglev; char *logfile; int do_daemonize; unsigned int i; unsigned long long skew_offset; unsigned long long skew_variance; long long clock_offset; struct GNUNET_SERVICE_Context sctx; struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_GETOPT_CommandLineOption service_options[] = { GNUNET_GETOPT_OPTION_CFG_FILE (&cfg_fn), {'d', "daemonize", NULL, gettext_noop ("do daemonize (detach from terminal)"), 0, GNUNET_GETOPT_set_one, &do_daemonize}, GNUNET_GETOPT_OPTION_HELP (NULL), GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev), GNUNET_GETOPT_OPTION_LOGFILE (&logfile), GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION), GNUNET_GETOPT_OPTION_END }; err = 1; do_daemonize = 0; logfile = NULL; loglev = NULL; cfg_fn = GNUNET_strdup (GNUNET_DEFAULT_USER_CONFIG_FILE); memset (&sctx, 0, sizeof (sctx)); sctx.options = options; sctx.ready_confirm_fd = -1; sctx.ret = GNUNET_OK; sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL; sctx.task = task; sctx.task_cls = task_cls; sctx.service_name = service_name; sctx.cfg = cfg = GNUNET_CONFIGURATION_create (); /* setup subsystems */ if (GNUNET_SYSERR == GNUNET_GETOPT_run (service_name, service_options, argc, argv)) goto shutdown; if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile)) HANDLE_ERROR; if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfg_fn)) goto shutdown; if (GNUNET_OK != setup_service (&sctx)) goto shutdown; if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sctx))) HANDLE_ERROR; if (GNUNET_OK != set_user_id (&sctx)) goto shutdown; LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' runs with configuration from `%s'\n", service_name, cfg_fn); if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING", "SKEW_OFFSET", &skew_offset)) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING", "SKEW_VARIANCE", &skew_variance))) { clock_offset = skew_offset - skew_variance; GNUNET_TIME_set_offset (clock_offset); LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll ms\n", clock_offset); } /* actually run service */ err = 0; GNUNET_SCHEDULER_run (&service_task, &sctx); GNUNET_SPEEDUP_start_ (cfg); /* shutdown */ if ((1 == do_daemonize) && (NULL != sctx.server)) pid_file_delete (&sctx); GNUNET_free_non_null (sctx.my_handlers); shutdown: if (-1 != sctx.ready_confirm_fd) { if (1 != WRITE (sctx.ready_confirm_fd, err ? "I" : "S", 1)) LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write"); GNUNET_break (0 == CLOSE (sctx.ready_confirm_fd)); } GNUNET_SPEEDUP_stop_ (); GNUNET_CONFIGURATION_destroy (cfg); i = 0; if (NULL != sctx.addrs) while (NULL != sctx.addrs[i]) GNUNET_free (sctx.addrs[i++]); GNUNET_free_non_null (sctx.addrs); GNUNET_free_non_null (sctx.addrlens); GNUNET_free_non_null (logfile); GNUNET_free_non_null (loglev); GNUNET_free (cfg_fn); GNUNET_free_non_null (sctx.v4_denied); GNUNET_free_non_null (sctx.v6_denied); GNUNET_free_non_null (sctx.v4_allowed); GNUNET_free_non_null (sctx.v6_allowed); return err ? GNUNET_SYSERR : sctx.ret; } /** * Run a service startup sequence within an existing * initialized system. * * @param service_name our service name * @param cfg configuration to use * @param options service options * @return NULL on error, service handle */ struct GNUNET_SERVICE_Context * GNUNET_SERVICE_start (const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg, enum GNUNET_SERVICE_Options options) { int i; struct GNUNET_SERVICE_Context *sctx; sctx = GNUNET_malloc (sizeof (struct GNUNET_SERVICE_Context)); sctx->ready_confirm_fd = -1; /* no daemonizing */ sctx->ret = GNUNET_OK; sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL; sctx->service_name = service_name; sctx->cfg = cfg; sctx->options = options; /* setup subsystems */ if (GNUNET_OK != setup_service (sctx)) { GNUNET_SERVICE_stop (sctx); return NULL; } if (NULL != sctx->lsocks) sctx->server = GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks, sctx->timeout, sctx->require_found); else sctx->server = GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens, sctx->timeout, sctx->require_found); if (NULL == sctx->server) { GNUNET_SERVICE_stop (sctx); return NULL; } sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers)); memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers)); i = 0; while ((sctx->my_handlers[i].callback != NULL)) sctx->my_handlers[i++].callback_cls = sctx; GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers); return sctx; } /** * Obtain the server used by a service. Note that the server must NOT * be destroyed by the caller. * * @param ctx the service context returned from the start function * @return handle to the server for this service, NULL if there is none */ struct GNUNET_SERVER_Handle * GNUNET_SERVICE_get_server (struct GNUNET_SERVICE_Context *ctx) { return ctx->server; } /** * Stop a service that was started with "GNUNET_SERVICE_start". * * @param sctx the service context returned from the start function */ void GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Context *sctx) { unsigned int i; if (GNUNET_SCHEDULER_NO_TASK != sctx->shutdown_task) { GNUNET_SCHEDULER_cancel (sctx->shutdown_task); sctx->shutdown_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != sctx->server) GNUNET_SERVER_destroy (sctx->server); GNUNET_free_non_null (sctx->my_handlers); if (NULL != sctx->addrs) { i = 0; while (NULL != sctx->addrs[i]) GNUNET_free (sctx->addrs[i++]); GNUNET_free (sctx->addrs); } GNUNET_free_non_null (sctx->addrlens); GNUNET_free_non_null (sctx->v4_denied); GNUNET_free_non_null (sctx->v6_denied); GNUNET_free_non_null (sctx->v4_allowed); GNUNET_free_non_null (sctx->v6_allowed); GNUNET_free (sctx); } /* end of service.c */ gnunet-0.9.3/src/util/test_common_endian.c0000644000175000017500000000251311760502551015524 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_common_endian.c * @brief testcase for common_endian.c */ #include "platform.h" #include "gnunet_common.h" #define CHECK(n) if (n != GNUNET_htonll(GNUNET_ntohll(n))) return 1; int main (int argc, char *argv[]) { GNUNET_log_setup ("test-common-endian", "WARNING", NULL); CHECK (1); CHECK (0x12345678); CHECK (123456789012345LL); if ((0x1234567890ABCDEFLL != GNUNET_htonll (0xEFCDAB9078563412LL)) && 42 != htonl (42)) return 1; return 0; } /* end of test_common_endian.c */ gnunet-0.9.3/src/util/gnunet-resolver.c0000644000175000017500000000765311760502551015030 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/gnunet-resolver.c * @brief tool to test resolver * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_resolver_service.h" #define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) /** * Flag for reverse lookup. */ static int reverse; /** * Prints each hostname obtained from DNS. * * @param cls closure (unused) * @param hostname one of the names for the host, NULL * on the last call to the callback */ static void print_hostname (void *cls, const char *hostname) { if (NULL == hostname) return; FPRINTF (stdout, "%s\n", hostname); } /** * Callback function to display address. * * @param cls closure (unused) * @param addr one of the addresses of the host, NULL for the last address * @param addrlen length of the address */ static void print_sockaddr (void *cls, const struct sockaddr *addr, socklen_t addrlen) { if (NULL == addr) return; FPRINTF (stdout, "%s\n", GNUNET_a2s (addr, addrlen)); } /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param cfg configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { const struct sockaddr *sa; socklen_t salen; struct sockaddr_in v4; struct sockaddr_in6 v6; if (args[0] == NULL) return; if (! reverse) { GNUNET_RESOLVER_ip_get (args[0], AF_UNSPEC, GET_TIMEOUT, &print_sockaddr, NULL); return; } sa = NULL; memset (&v4, 0, sizeof (v4)); v4.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN v4.sin_len = sizeof (v4); #endif if (1 == inet_pton (AF_INET, args[0], &v4.sin_addr)) { sa = (struct sockaddr *) &v4; salen = sizeof (v4); } memset (&v6, 0, sizeof (v6)); v6.sin6_family = AF_INET6; #if HAVE_SOCKADDR_IN_SIN_LEN v6.sin6_len = sizeof (v6); #endif if (1 == inet_pton (AF_INET6, args[0], &v6.sin6_addr)) { sa = (struct sockaddr *) &v6; salen = sizeof (v6); } if (NULL == sa) { fprintf (stderr, "`%s' is not a valid IP: %s\n", args[0], strerror (errno)); return; } GNUNET_RESOLVER_hostname_get (sa, salen, GNUNET_YES, GET_TIMEOUT, &print_hostname, NULL); } /** * The main function to obtain statistics in GNUnet. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { { 'r', "reverse", NULL, gettext_noop ("perform a reverse lookup"), 0, &GNUNET_GETOPT_set_one, &reverse }, GNUNET_GETOPT_OPTION_END }; return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-resolver [hostname]", gettext_noop ("Use build-in GNUnet stub resolver"), options, &run, NULL)) ? 0 : 1; } /* end of gnunet-resolver.c */ gnunet-0.9.3/src/util/test_service.c0000644000175000017500000001731611760502551014365 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_service.c * @brief tests for service.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_client_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_program_lib.h" #include "gnunet_service_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" #define VERBOSE GNUNET_NO #define PORT 12435 #define MY_TYPE 256 static struct GNUNET_SERVICE_Context *sctx; static int ok = 1; static struct GNUNET_CLIENT_Connection *client; static void do_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (NULL != client) { GNUNET_CLIENT_disconnect (client); client = NULL; } if (NULL != sctx) { GNUNET_SERVICE_stop (sctx); sctx = NULL; } else { GNUNET_SCHEDULER_shutdown (); } } static size_t build_msg (void *cls, size_t size, void *buf) { struct GNUNET_MessageHeader *msg = buf; if (size < sizeof (struct GNUNET_MessageHeader)) { /* timeout */ GNUNET_break (0); GNUNET_SCHEDULER_add_now (&do_stop, NULL); ok = 1; return 0; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client connected, transmitting\n"); GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); msg->type = htons (MY_TYPE); msg->size = htons (sizeof (struct GNUNET_MessageHeader)); return sizeof (struct GNUNET_MessageHeader); } static void ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { const struct GNUNET_CONFIGURATION_Handle *cfg = cls; GNUNET_assert (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service confirmed running\n"); client = GNUNET_CLIENT_connect ("test_service", cfg); GNUNET_assert (client != NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client connecting, waiting to transmit\n"); GNUNET_CLIENT_notify_transmit_ready (client, sizeof (struct GNUNET_MessageHeader), GNUNET_TIME_UNIT_SECONDS, GNUNET_NO, &build_msg, NULL); } static void recv_cb (void *cls, struct GNUNET_SERVER_Client *sc, const struct GNUNET_MessageHeader *message) { if (NULL == message) return; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving client message...\n"); GNUNET_SERVER_receive_done (sc, GNUNET_OK); GNUNET_SCHEDULER_add_now (&do_stop, NULL); ok = 0; } static struct GNUNET_SERVER_MessageHandler myhandlers[] = { {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)}, {NULL, NULL, 0, 0} }; static void runner (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *cfg) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service initializing\n"); GNUNET_SERVER_add_handlers (server, myhandlers); GNUNET_CLIENT_service_test ("test_service", cfg, GNUNET_TIME_UNIT_SECONDS, &ready, (void *) cfg); } /** * Main method, starts scheduler with task1, * checks that "ok" is correct at the end. */ static int check () { ok = 1; char *const argv[] = { "test_service", "-c", "test_service_data.conf", "-L", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL }; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting service\n"); GNUNET_assert (GNUNET_OK == GNUNET_SERVICE_run (5, argv, "test_service", GNUNET_SERVICE_OPTION_NONE, &runner, &ok)); GNUNET_assert (0 == ok); return ok; } static void ready6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { const struct GNUNET_CONFIGURATION_Handle *cfg = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "V6 ready\n"); GNUNET_assert (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)); client = GNUNET_CLIENT_connect ("test_service6", cfg); GNUNET_assert (client != NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "V6 client connected\n"); GNUNET_CLIENT_notify_transmit_ready (client, sizeof (struct GNUNET_MessageHeader), GNUNET_TIME_UNIT_SECONDS, GNUNET_NO, &build_msg, NULL); } static void runner6 (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *cfg) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Initializing v6 service\n"); GNUNET_SERVER_add_handlers (server, myhandlers); GNUNET_CLIENT_service_test ("test_service6", cfg, GNUNET_TIME_UNIT_SECONDS, &ready6, (void *) cfg); } /** * Main method, starts scheduler with task1, * checks that "ok" is correct at the end. */ static int check6 () { char *const argv[] = { "test_service6", "-c", "test_service_data.conf", "-L", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL }; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting v6 service\n"); GNUNET_assert (GNUNET_OK == GNUNET_SERVICE_run (5, argv, "test_service6", GNUNET_SERVICE_OPTION_NONE, &runner6, &ok)); GNUNET_assert (0 == ok); return ok; } static void start_stop_main (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { int *ret = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting service using start method\n"); sctx = GNUNET_SERVICE_start ("test_service", cfg, GNUNET_SERVICE_OPTION_NONE); GNUNET_assert (NULL != sctx); runner (cls, GNUNET_SERVICE_get_server (sctx), cfg); *ret = 0; } static int check_start_stop () { char *const argv[] = { "test-service-program", "-c", "test_service_data.conf", "-L", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL }; const struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; int ret = 1; GNUNET_assert (GNUNET_OK == GNUNET_PROGRAM_run (5, argv, "test-service-program", "no help", options, &start_stop_main, &ret)); GNUNET_break (0 == ret); return ret; } int main (int argc, char *argv[]) { int ret = 0; struct GNUNET_NETWORK_Handle *s = NULL; GNUNET_log_setup ("test-service", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret += check (); ret += check (); // FIXME #ifndef MINGW s = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); #endif if (NULL == s) { if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) || (errno == EACCES)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket"); return 1; } FPRINTF (stderr, "IPv6 support seems to not be available (%s), not testing it!\n", strerror (errno)); } else { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s)); ret += check6 (); } ret += check_start_stop (); return ret; } /* end of test_service.c */ gnunet-0.9.3/src/util/util.conf0000644000175000017500000000060011761753145013342 00000000000000[PATHS] SERVICEHOME = ~/.gnunet/ # SERVICEHOME = /var/lib/gnunet/ # DEFAULTCONFIG = /etc/gnunet.conf # If 'DEFAULTCONFIG' is not defined, the current # configuration file is assumed to be the default, # which is what we want by default... [gnunetd] HOSTKEY = $SERVICEHOME/.hostkey [client] HOME = $SERVICEHOME [TESTING] WEAKRANDOM = NO SPEEDUP_INTERVAL = 0 ms SPEEDUP_DELTA = 0 ms gnunet-0.9.3/src/util/test_connection_addressing.c0000644000175000017500000001314311760502551017261 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_connection_addressing.c * @brief tests for connection.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_connection_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" #define VERBOSE GNUNET_NO #define PORT 12435 static struct GNUNET_CONNECTION_Handle *csock; static struct GNUNET_CONNECTION_Handle *asock; static struct GNUNET_CONNECTION_Handle *lsock; static size_t sofar; static struct GNUNET_NETWORK_Handle *ls; /** * Create and initialize a listen socket for the server. * * @return NULL on error, otherwise the listen socket */ static struct GNUNET_NETWORK_Handle * open_listen_socket () { const static int on = 1; struct sockaddr_in sa; struct GNUNET_NETWORK_Handle *desc; memset (&sa, 0, sizeof (sa)); #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = sizeof (sa); #endif sa.sin_family = AF_INET; sa.sin_port = htons (PORT); desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); GNUNET_assert (desc != 0); if (GNUNET_NETWORK_socket_setsockopt (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); if (GNUNET_OK != GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa, sizeof (sa))) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "bind"); GNUNET_assert (0); } GNUNET_NETWORK_socket_listen (desc, 5); return desc; } static void receive_check (void *cls, const void *buf, size_t available, const struct sockaddr *addr, socklen_t addrlen, int errCode) { int *ok = cls; GNUNET_assert (buf != NULL); /* no timeout */ if (0 == memcmp (&"Hello World"[sofar], buf, available)) sofar += available; if (sofar < 12) { GNUNET_CONNECTION_receive (asock, 1024, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check, cls); } else { *ok = 0; GNUNET_CONNECTION_destroy (csock); GNUNET_CONNECTION_destroy (asock); } } static void run_accept (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { void *addr; size_t alen; struct sockaddr_in *v4; struct sockaddr_in expect; asock = GNUNET_CONNECTION_create_from_accept (NULL, NULL, ls); GNUNET_assert (asock != NULL); GNUNET_assert (GNUNET_YES == GNUNET_CONNECTION_check (asock)); GNUNET_assert (GNUNET_OK == GNUNET_CONNECTION_get_address (asock, &addr, &alen)); GNUNET_assert (alen == sizeof (struct sockaddr_in)); v4 = addr; memset (&expect, 0, sizeof (expect)); #if HAVE_SOCKADDR_IN_SIN_LEN expect.sin_len = sizeof (expect); #endif expect.sin_family = AF_INET; expect.sin_port = v4->sin_port; expect.sin_addr.s_addr = htonl (INADDR_LOOPBACK); GNUNET_assert (0 == memcmp (&expect, v4, alen)); GNUNET_free (addr); GNUNET_CONNECTION_destroy (lsock); GNUNET_CONNECTION_receive (asock, 1024, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check, cls); } static size_t make_hello (void *cls, size_t size, void *buf) { GNUNET_assert (size >= 12); strcpy ((char *) buf, "Hello World"); return 12; } static void task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct sockaddr_in v4; ls = open_listen_socket (); lsock = GNUNET_CONNECTION_create_from_existing (ls); GNUNET_assert (lsock != NULL); #if HAVE_SOCKADDR_IN_SIN_LEN v4.sin_len = sizeof (v4); #endif v4.sin_family = AF_INET; v4.sin_port = htons (PORT); v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK); csock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET, (const struct sockaddr *) &v4, sizeof (v4)); GNUNET_assert (csock != NULL); GNUNET_assert (NULL != GNUNET_CONNECTION_notify_transmit_ready (csock, 12, GNUNET_TIME_UNIT_SECONDS, &make_hello, NULL)); GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, ls, &run_accept, cls); } /** * Main method, starts scheduler with task , * checks that "ok" is correct at the end. */ static int check () { int ok; ok = 1; GNUNET_SCHEDULER_run (&task, &ok); return ok; } int main (int argc, char *argv[]) { int ret = 0; GNUNET_log_setup ("test_connection_addressing", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret += check (); return ret; } /* end of test_connection_addressing.c */ gnunet-0.9.3/src/util/load.c0000644000175000017500000001471411760502551012604 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/load.c * @brief functions related to load calculations * @author Christian Grothoff */ #include "platform.h" #include "gnunet_load_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) /** * Values we track for load calculations. */ struct GNUNET_LOAD_Value { /** * How fast should the load decline if no values are added? */ struct GNUNET_TIME_Relative autodecline; /** * Last time this load value was updated by an event. */ struct GNUNET_TIME_Absolute last_update; /** * Sum of all datastore delays ever observed (in ms). Note that * delays above 64k ms are excluded (to avoid overflow within * first 4 billion requests). */ uint64_t cummulative_delay; /** * Sum of squares of all datastore delays ever observed (in ms). Note that * delays above 64k ms are excluded (to avoid overflow within * first 4 billion requests). */ uint64_t cummulative_squared_delay; /** * Total number of requests included in the cummulative datastore delay values. */ uint64_t cummulative_request_count; /** * Current running average datastore delay. Its relation to the * average datastore delay and it std. dev. (as calcualted from the * cummulative values) tells us our current load. */ double runavg_delay; /** * How high is the load? 0 for below average, otherwise * the number of std. devs we are above average, or 100 if the * load is so high that we currently cannot calculate it. */ double load; }; static void internal_update (struct GNUNET_LOAD_Value *load) { struct GNUNET_TIME_Relative delta; unsigned int n; if (load->autodecline.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value) return; delta = GNUNET_TIME_absolute_get_duration (load->last_update); if (delta.rel_value < load->autodecline.rel_value) return; if (load->autodecline.rel_value == 0) { load->runavg_delay = 0.0; load->load = 0; return; } n = delta.rel_value / load->autodecline.rel_value; if (n > 16) { load->runavg_delay = 0.0; load->load = 0; return; } while (n > 0) { n--; load->runavg_delay = (load->runavg_delay * 7.0) / 8.0; } } /** * Create a new load value. * * @param autodecline speed at which this value should automatically * decline in the absence of external events; at the given * frequency, 0-load values will be added to the load * @return the new load value */ struct GNUNET_LOAD_Value * GNUNET_LOAD_value_init (struct GNUNET_TIME_Relative autodecline) { struct GNUNET_LOAD_Value *ret; ret = GNUNET_malloc (sizeof (struct GNUNET_LOAD_Value)); ret->autodecline = autodecline; ret->last_update = GNUNET_TIME_absolute_get (); return ret; } /** * Change the value by which the load automatically declines. * * @param load load to update * @param autodecline frequency of load decline */ void GNUNET_LOAD_value_set_decline (struct GNUNET_LOAD_Value *load, struct GNUNET_TIME_Relative autodecline) { internal_update (load); load->autodecline = autodecline; } /** * Recalculate our load value. * * @param load load to update */ static void calculate_load (struct GNUNET_LOAD_Value *load) { double stddev; double avgdel; double sum_val_i; double n; double nm1; if (load->cummulative_request_count <= 1) return; /* calcuate std dev of latency; we have for n values of "i" that: * * avg = (sum val_i) / n * stddev = (sum (val_i - avg)^2) / (n-1) * = (sum (val_i^2 - 2 avg val_i + avg^2) / (n-1) * = (sum (val_i^2) - 2 avg sum (val_i) + n * avg^2) / (n-1) */ sum_val_i = (double) load->cummulative_delay; n = ((double) load->cummulative_request_count); nm1 = n - 1.0; avgdel = sum_val_i / n; stddev = (((double) load->cummulative_squared_delay) - 2.0 * avgdel * sum_val_i + n * avgdel * avgdel) / nm1; if (stddev <= 0) stddev = 0.01; /* must have been rounding error or zero; prevent division by zero */ /* now calculate load based on how far out we are from * std dev; or if we are below average, simply assume load zero */ if (load->runavg_delay < avgdel) load->load = 0.0; else load->load = (load->runavg_delay - avgdel) / stddev; } /** * Get the current load. * * @param load load handle * @return zero for below-average load, otherwise * number of std. devs we are above average; * 100 if the latest updates were so large * that we could not do proper calculations */ double GNUNET_LOAD_get_load (struct GNUNET_LOAD_Value *load) { internal_update (load); calculate_load (load); return load->load; } /** * Get the average value given to update so far. * * @param load load handle * @return zero if update was never called */ double GNUNET_LOAD_get_average (struct GNUNET_LOAD_Value *load) { double n; double sum_val_i; internal_update (load); if (load->cummulative_request_count == 0) return 0.0; n = ((double) load->cummulative_request_count); sum_val_i = (double) load->cummulative_delay; return sum_val_i / n; } /** * Update the current load. * * @param load to update * @param data latest measurement value (for example, delay) */ void GNUNET_LOAD_update (struct GNUNET_LOAD_Value *load, uint64_t data) { uint32_t dv; internal_update (load); load->last_update = GNUNET_TIME_absolute_get (); if (data > 64 * 1024) { /* very large */ load->load = 100.0; return; } dv = (uint32_t) data; load->cummulative_delay += dv; load->cummulative_squared_delay += dv * dv; load->cummulative_request_count++; load->runavg_delay = ((load->runavg_delay * 7.0) + dv) / 8.0; } /* end of load.c */ gnunet-0.9.3/src/util/test_speedup.c0000644000175000017500000000636011761753145014377 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_speedup.c * @brief testcase for speedup.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_program_lib.h" #include "gnunet_time_lib.h" #include "gnunet_strings_lib.h" /** * Start time of the testcase */ static struct GNUNET_TIME_Absolute start; /** * End-time of the testcase (affected by speed-up) */ static struct GNUNET_TIME_Absolute end; /** * Number of cycles we have spent in 'run'. */ static unsigned int cycles; /** * Main task that is scheduled with the speed-up. * * @param cls NULL * @param tc scheduler context, unused */ static void run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { cycles++; fprintf (stderr, "..%u", cycles); if (cycles <= 5) { GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &run, NULL); return; } end = GNUNET_TIME_absolute_get(); fprintf (stderr, "\n"); fflush(stdout); } /** * */ static void check (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle * cfg) { fprintf (stderr, "0"); fflush(stdout); GNUNET_SCHEDULER_add_now(&run, NULL); } int main (int argc, char *argv[]) { static char *const argvn[] = { "test-speedup", "-c", "test_speedup_data.conf", NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; time_t start_real; time_t end_real; struct GNUNET_TIME_Relative delta; start_real = time (NULL); start = GNUNET_TIME_absolute_get(); GNUNET_PROGRAM_run ((sizeof (argvn) / sizeof (char *)) - 1, argvn, "test-speedup", "nohelp", options, &check, NULL); end_real = time (NULL); delta = GNUNET_TIME_absolute_get_difference(start, end); if (delta.rel_value > ((end_real - start_real) * 1500LL)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Execution time in GNUnet time: %llu ms\n", (unsigned long long) delta.rel_value); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Execution time in system time: %llu ms\n", (unsigned long long) ((end_real - start_real) * 1000LL)); return 0; } GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Execution time in GNUnet time: %llu ms\n", (unsigned long long) delta.rel_value); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Execution time in system time: %llu ms\n", (unsigned long long) ((end_real - start_real) * 1000LL)); return 1; } /* end of test_speedup.c */ gnunet-0.9.3/src/util/container_bloomfilter.c0000644000175000017500000005326611760502551016252 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2006, 2008, 2011, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/container_bloomfilter.c * @brief data structure used to reduce disk accesses. * * The idea basically: Create a signature for each element in the * database. Add those signatures to a bit array. When doing a lookup, * check if the bit array matches the signature of the requested * element. If yes, address the disk, otherwise return 'not found'. * * A property of the bloom filter is that sometimes we will have * a match even if the element is not on the disk (then we do * an unnecessary disk access), but what's most important is that * we never get a single "false negative". * * To be able to delete entries from the bloom filter, we maintain * a 4 bit counter in the file on the drive (we still use only one * bit in memory). * * @author Igor Wronsky * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_container_lib.h" #include "gnunet_disk_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) struct GNUNET_CONTAINER_BloomFilter { /** * The actual bloomfilter bit array */ char *bitArray; /** * Filename of the filter */ char *filename; /** * The bit counter file on disk */ struct GNUNET_DISK_FileHandle *fh; /** * How many bits we set for each stored element */ unsigned int addressesPerElement; /** * Size of bitArray in bytes */ size_t bitArraySize; }; /** * Get size of the bloom filter. * * @param bf the filter * @return number of bytes used for the data of the bloom filter */ size_t GNUNET_CONTAINER_bloomfilter_get_size (const struct GNUNET_CONTAINER_BloomFilter *bf) { if (bf == NULL) return 0; return bf->bitArraySize; } /** * Copy an existing memory. Any association with a file * on-disk will be lost in the process. * @param bf the filter to copy * @return copy of the bf */ struct GNUNET_CONTAINER_BloomFilter * GNUNET_CONTAINER_bloomfilter_copy (const struct GNUNET_CONTAINER_BloomFilter *bf) { return GNUNET_CONTAINER_bloomfilter_init (bf->bitArray, bf->bitArraySize, bf->addressesPerElement); } /** * Sets a bit active in the bitArray. Increment bit-specific * usage counter on disk only if below 4bit max (==15). * * @param bitArray memory area to set the bit in * @param bitIdx which bit to set */ static void setBit (char *bitArray, unsigned int bitIdx) { size_t arraySlot; unsigned int targetBit; arraySlot = bitIdx / 8; targetBit = (1L << (bitIdx % 8)); bitArray[arraySlot] |= targetBit; } /** * Clears a bit from bitArray. Bit is cleared from the array * only if the respective usage counter on the disk hits/is zero. * * @param bitArray memory area to set the bit in * @param bitIdx which bit to unset */ static void clearBit (char *bitArray, unsigned int bitIdx) { size_t slot; unsigned int targetBit; slot = bitIdx / 8; targetBit = (1L << (bitIdx % 8)); bitArray[slot] = bitArray[slot] & (~targetBit); } /** * Checks if a bit is active in the bitArray * * @param bitArray memory area to set the bit in * @param bitIdx which bit to test * @return GNUNET_YES if the bit is set, GNUNET_NO if not. */ static int testBit (char *bitArray, unsigned int bitIdx) { size_t slot; unsigned int targetBit; slot = bitIdx / 8; targetBit = (1L << (bitIdx % 8)); if (bitArray[slot] & targetBit) return GNUNET_YES; else return GNUNET_NO; } /** * Sets a bit active in the bitArray and increments * bit-specific usage counter on disk (but only if * the counter was below 4 bit max (==15)). * * @param bitArray memory area to set the bit in * @param bitIdx which bit to test * @param fh A file to keep the 4 bit address usage counters in */ static void incrementBit (char *bitArray, unsigned int bitIdx, const struct GNUNET_DISK_FileHandle *fh) { OFF_T fileSlot; unsigned char value; unsigned int high; unsigned int low; unsigned int targetLoc; setBit (bitArray, bitIdx); if (GNUNET_DISK_handle_invalid (fh)) return; /* Update the counter file on disk */ fileSlot = bitIdx / 2; targetLoc = bitIdx % 2; GNUNET_assert (fileSlot == GNUNET_DISK_file_seek (fh, fileSlot, GNUNET_DISK_SEEK_SET)); if (1 != GNUNET_DISK_file_read (fh, &value, 1)) value = 0; low = value & 0xF; high = (value & (~0xF)) >> 4; if (targetLoc == 0) { if (low < 0xF) low++; } else { if (high < 0xF) high++; } value = ((high << 4) | low); GNUNET_assert (fileSlot == GNUNET_DISK_file_seek (fh, fileSlot, GNUNET_DISK_SEEK_SET)); GNUNET_assert (1 == GNUNET_DISK_file_write (fh, &value, 1)); } /** * Clears a bit from bitArray if the respective usage * counter on the disk hits/is zero. * * @param bitArray memory area to set the bit in * @param bitIdx which bit to test * @param fh A file to keep the 4bit address usage counters in */ static void decrementBit (char *bitArray, unsigned int bitIdx, const struct GNUNET_DISK_FileHandle *fh) { OFF_T fileSlot; unsigned char value; unsigned int high; unsigned int low; unsigned int targetLoc; if (GNUNET_DISK_handle_invalid (fh)) return; /* cannot decrement! */ /* Each char slot in the counter file holds two 4 bit counters */ fileSlot = bitIdx / 2; targetLoc = bitIdx % 2; GNUNET_DISK_file_seek (fh, fileSlot, GNUNET_DISK_SEEK_SET); if (1 != GNUNET_DISK_file_read (fh, &value, 1)) value = 0; low = value & 0xF; high = (value & 0xF0) >> 4; /* decrement, but once we have reached the max, never go back! */ if (targetLoc == 0) { if ((low > 0) && (low < 0xF)) low--; if (low == 0) { clearBit (bitArray, bitIdx); } } else { if ((high > 0) && (high < 0xF)) high--; if (high == 0) { clearBit (bitArray, bitIdx); } } value = ((high << 4) | low); GNUNET_DISK_file_seek (fh, fileSlot, GNUNET_DISK_SEEK_SET); GNUNET_assert (1 == GNUNET_DISK_file_write (fh, &value, 1)); } #define BUFFSIZE 65536 /** * Creates a file filled with zeroes * * @param fh the file handle * @param size the size of the file * @return GNUNET_OK if created ok, GNUNET_SYSERR otherwise */ static int make_empty_file (const struct GNUNET_DISK_FileHandle *fh, size_t size) { char buffer[BUFFSIZE]; size_t bytesleft = size; int res = 0; if (GNUNET_DISK_handle_invalid (fh)) return GNUNET_SYSERR; memset (buffer, 0, sizeof (buffer)); GNUNET_DISK_file_seek (fh, 0, GNUNET_DISK_SEEK_SET); while (bytesleft > 0) { if (bytesleft > sizeof (buffer)) { res = GNUNET_DISK_file_write (fh, buffer, sizeof (buffer)); if (res >= 0) bytesleft -= res; } else { res = GNUNET_DISK_file_write (fh, buffer, bytesleft); if (res >= 0) bytesleft -= res; } if (GNUNET_SYSERR == res) return GNUNET_SYSERR; } return GNUNET_OK; } /* ************** GNUNET_CONTAINER_BloomFilter iterator ********* */ /** * Iterator (callback) method to be called by the * bloomfilter iterator on each bit that is to be * set or tested for the key. * * @param cls closure * @param bf the filter to manipulate * @param bit the current bit * @return GNUNET_YES to continue, GNUNET_NO to stop early */ typedef int (*BitIterator) (void *cls, const struct GNUNET_CONTAINER_BloomFilter * bf, unsigned int bit); /** * Call an iterator for each bit that the bloomfilter * must test or set for this element. * * @param bf the filter * @param callback the method to call * @param arg extra argument to callback * @param key the key for which we iterate over the BF bits */ static void iterateBits (const struct GNUNET_CONTAINER_BloomFilter *bf, BitIterator callback, void *arg, const GNUNET_HashCode * key) { GNUNET_HashCode tmp[2]; int bitCount; unsigned int round; unsigned int slot = 0; bitCount = bf->addressesPerElement; tmp[0] = *key; round = 0; GNUNET_assert (bf->bitArraySize > 0); GNUNET_assert (bf->bitArraySize * 8LL > bf->bitArraySize); while (bitCount > 0) { while (slot < (sizeof (GNUNET_HashCode) / sizeof (uint32_t))) { if (GNUNET_YES != callback (arg, bf, (((uint32_t *) & tmp[round & 1])[slot]) % ((bf->bitArraySize * 8LL)))) return; slot++; bitCount--; if (bitCount == 0) break; } if (bitCount > 0) { GNUNET_CRYPTO_hash (&tmp[round & 1], sizeof (GNUNET_HashCode), &tmp[(round + 1) & 1]); round++; slot = 0; } } } /** * Callback: increment bit * * @param cls pointer to writeable form of bf * @param bf the filter to manipulate * @param bit the bit to increment * @return GNUNET_YES */ static int incrementBitCallback (void *cls, const struct GNUNET_CONTAINER_BloomFilter *bf, unsigned int bit) { struct GNUNET_CONTAINER_BloomFilter *b = cls; incrementBit (b->bitArray, bit, bf->fh); return GNUNET_YES; } /** * Callback: decrement bit * * @param cls pointer to writeable form of bf * @param bf the filter to manipulate * @param bit the bit to decrement * @return GNUNET_YES */ static int decrementBitCallback (void *cls, const struct GNUNET_CONTAINER_BloomFilter *bf, unsigned int bit) { struct GNUNET_CONTAINER_BloomFilter *b = cls; decrementBit (b->bitArray, bit, bf->fh); return GNUNET_YES; } /** * Callback: test if all bits are set * * @param cls pointer set to GNUNET_NO if bit is not set * @param bf the filter * @param bit the bit to test * @return YES if the bit is set, NO if not */ static int testBitCallback (void *cls, const struct GNUNET_CONTAINER_BloomFilter *bf, unsigned int bit) { int *arg = cls; if (GNUNET_NO == testBit (bf->bitArray, bit)) { *arg = GNUNET_NO; return GNUNET_NO; } return GNUNET_YES; } /* *********************** INTERFACE **************** */ /** * Load a bloom-filter from a file. * * @param filename the name of the file (or the prefix) * @param size the size of the bloom-filter (number of * bytes of storage space to use); will be rounded up * to next power of 2 * @param k the number of GNUNET_CRYPTO_hash-functions to apply per * element (number of bits set per element in the set) * @return the bloomfilter */ struct GNUNET_CONTAINER_BloomFilter * GNUNET_CONTAINER_bloomfilter_load (const char *filename, size_t size, unsigned int k) { struct GNUNET_CONTAINER_BloomFilter *bf; char *rbuff; OFF_T pos; int i; size_t ui; OFF_T fsize; int must_read; GNUNET_assert (NULL != filename); if ((k == 0) || (size == 0)) return NULL; if (size < BUFFSIZE) size = BUFFSIZE; ui = 1; while ( (ui < size) && (ui * 2 > ui) ) ui *= 2; size = ui; /* make sure it's a power of 2 */ bf = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_BloomFilter)); /* Try to open a bloomfilter file */ if (GNUNET_YES == GNUNET_DISK_file_test (filename)) bf->fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READWRITE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (NULL != bf->fh) { /* file existed, try to read it! */ must_read = GNUNET_YES; if (GNUNET_OK != GNUNET_DISK_file_handle_size (bf->fh, &fsize)) { GNUNET_DISK_file_close (bf->fh); GNUNET_free (bf); return NULL; } if (fsize == 0) { /* found existing empty file, just overwrite */ if (GNUNET_OK != make_empty_file (bf->fh, size * 4LL)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write"); GNUNET_DISK_file_close (bf->fh); GNUNET_free (bf); return NULL; } } else if (fsize != size * 4LL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Size of file on disk is incorrect for this Bloom filter (want %llu, have %llu)\n"), (unsigned long long) (size * 4LL), (unsigned long long) fsize); GNUNET_DISK_file_close (bf->fh); GNUNET_free (bf); return NULL; } } else { /* file did not exist, don't read, just create */ must_read = GNUNET_NO; bf->fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_READWRITE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (NULL == bf->fh) { GNUNET_free (bf); return NULL; } if (GNUNET_OK != make_empty_file (bf->fh, size * 4LL)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write"); GNUNET_DISK_file_close (bf->fh); GNUNET_free (bf); return NULL; } } bf->filename = GNUNET_strdup (filename); /* Alloc block */ bf->bitArray = GNUNET_malloc_large (size); if (bf->bitArray == NULL) { if (bf->fh != NULL) GNUNET_DISK_file_close (bf->fh); GNUNET_free (bf->filename); GNUNET_free (bf); return NULL; } bf->bitArraySize = size; bf->addressesPerElement = k; if (GNUNET_YES != must_read) return bf; /* already done! */ /* Read from the file what bits we can */ rbuff = GNUNET_malloc (BUFFSIZE); pos = 0; while (pos < size * 8LL) { int res; res = GNUNET_DISK_file_read (bf->fh, rbuff, BUFFSIZE); if (res == -1) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "read", bf->filename); GNUNET_free (rbuff); GNUNET_free (bf->filename); GNUNET_DISK_file_close (bf->fh); GNUNET_free (bf); return NULL; } if (res == 0) break; /* is ok! we just did not use that many bits yet */ for (i = 0; i < res; i++) { if ((rbuff[i] & 0x0F) != 0) setBit (bf->bitArray, pos + i * 2); if ((rbuff[i] & 0xF0) != 0) setBit (bf->bitArray, pos + i * 2 + 1); } if (res < BUFFSIZE) break; pos += BUFFSIZE * 2; /* 2 bits per byte in the buffer */ } GNUNET_free (rbuff); return bf; } /** * Create a bloom filter from raw bits. * * @param data the raw bits in memory (maybe NULL, * in which case all bits should be considered * to be zero). * @param size the size of the bloom-filter (number of * bytes of storage space to use); also size of data * -- unless data is NULL * @param k the number of GNUNET_CRYPTO_hash-functions to apply per * element (number of bits set per element in the set) * @return the bloomfilter */ struct GNUNET_CONTAINER_BloomFilter * GNUNET_CONTAINER_bloomfilter_init (const char *data, size_t size, unsigned int k) { struct GNUNET_CONTAINER_BloomFilter *bf; if ((0 == k) || (0 == size)) return NULL; bf = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_BloomFilter)); bf->filename = NULL; bf->fh = NULL; bf->bitArray = GNUNET_malloc_large (size); if (NULL == bf->bitArray) { GNUNET_free (bf); return NULL; } bf->bitArraySize = size; bf->addressesPerElement = k; if (NULL != data) memcpy (bf->bitArray, data, size); return bf; } /** * Copy the raw data of this bloomfilter into * the given data array. * * @param bf bloomfilter to take the raw data from * @param data where to write the data * @param size the size of the given data array * @return GNUNET_SYSERR if the data array is not big enough */ int GNUNET_CONTAINER_bloomfilter_get_raw_data (const struct GNUNET_CONTAINER_BloomFilter *bf, char *data, size_t size) { if (NULL == bf) return GNUNET_SYSERR; if (bf->bitArraySize != size) return GNUNET_SYSERR; memcpy (data, bf->bitArray, size); return GNUNET_OK; } /** * Free the space associated with a filter * in memory, flush to drive if needed (do not * free the space on the drive) * * @param bf the filter */ void GNUNET_CONTAINER_bloomfilter_free (struct GNUNET_CONTAINER_BloomFilter *bf) { if (NULL == bf) return; if (bf->fh != NULL) GNUNET_DISK_file_close (bf->fh); GNUNET_free_non_null (bf->filename); GNUNET_free (bf->bitArray); GNUNET_free (bf); } /** * Reset a bloom filter to empty. Clears the file on disk. * * @param bf the filter */ void GNUNET_CONTAINER_bloomfilter_clear (struct GNUNET_CONTAINER_BloomFilter *bf) { if (NULL == bf) return; memset (bf->bitArray, 0, bf->bitArraySize); if (bf->filename != NULL) make_empty_file (bf->fh, bf->bitArraySize * 4LL); } /** * Test if an element is in the filter. * * @param e the element * @param bf the filter * @return GNUNET_YES if the element is in the filter, GNUNET_NO if not */ int GNUNET_CONTAINER_bloomfilter_test (const struct GNUNET_CONTAINER_BloomFilter *bf, const GNUNET_HashCode * e) { int res; if (NULL == bf) return GNUNET_YES; res = GNUNET_YES; iterateBits (bf, &testBitCallback, &res, e); return res; } /** * Add an element to the filter * * @param bf the filter * @param e the element */ void GNUNET_CONTAINER_bloomfilter_add (struct GNUNET_CONTAINER_BloomFilter *bf, const GNUNET_HashCode * e) { if (NULL == bf) return; iterateBits (bf, &incrementBitCallback, bf, e); } /** * Or the entries of the given raw data array with the * data of the given bloom filter. Assumes that * the size of the data array and the current filter * match. * * @param bf the filter * @param data the data to or-in * @param size number of bytes in data */ int GNUNET_CONTAINER_bloomfilter_or (struct GNUNET_CONTAINER_BloomFilter *bf, const char *data, size_t size) { unsigned int i; unsigned int n; unsigned long long *fc; const unsigned long long *dc; if (NULL == bf) return GNUNET_YES; if (bf->bitArraySize != size) return GNUNET_SYSERR; fc = (unsigned long long *) bf->bitArray; dc = (const unsigned long long *) data; n = size / sizeof (unsigned long long); for (i = 0; i < n; i++) fc[i] |= dc[i]; for (i = n * sizeof (unsigned long long); i < size; i++) bf->bitArray[i] |= data[i]; return GNUNET_OK; } /** * Or the entries of the given raw data array with the * data of the given bloom filter. Assumes that * the size of the data array and the current filter * match. * * @param bf the filter * @param to_or the bloomfilter to or-in * @param size number of bytes in data */ int GNUNET_CONTAINER_bloomfilter_or2 (struct GNUNET_CONTAINER_BloomFilter *bf, const struct GNUNET_CONTAINER_BloomFilter *to_or, size_t size) { unsigned int i; unsigned int n; unsigned long long *fc; const unsigned long long *dc; if (NULL == bf) return GNUNET_YES; if (bf->bitArraySize != size) return GNUNET_SYSERR; fc = (unsigned long long *) bf->bitArray; dc = (const unsigned long long *) to_or->bitArray; n = size / sizeof (unsigned long long); for (i = 0; i < n; i++) fc[i] |= dc[i]; for (i = n * sizeof (unsigned long long); i < size; i++) bf->bitArray[i] |= to_or->bitArray[i]; return GNUNET_OK; } /** * Remove an element from the filter. * * @param bf the filter * @param e the element to remove */ void GNUNET_CONTAINER_bloomfilter_remove (struct GNUNET_CONTAINER_BloomFilter *bf, const GNUNET_HashCode * e) { if (NULL == bf) return; if (bf->filename == NULL) return; iterateBits (bf, &decrementBitCallback, bf, e); } /** * Resize a bloom filter. Note that this operation * is pretty costly. Essentially, the bloom filter * needs to be completely re-build. * * @param bf the filter * @param iterator an iterator over all elements stored in the BF * @param iterator_cls argument to the iterator function * @param size the new size for the filter * @param k the new number of GNUNET_CRYPTO_hash-function to apply per element */ void GNUNET_CONTAINER_bloomfilter_resize (struct GNUNET_CONTAINER_BloomFilter *bf, GNUNET_HashCodeIterator iterator, void *iterator_cls, size_t size, unsigned int k) { GNUNET_HashCode hc; unsigned int i; GNUNET_free (bf->bitArray); i = 1; while (i < size) i *= 2; size = i; /* make sure it's a power of 2 */ bf->bitArraySize = size; bf->bitArray = GNUNET_malloc (size); if (bf->filename != NULL) make_empty_file (bf->fh, bf->bitArraySize * 4LL); while (GNUNET_YES == iterator (iterator_cls, &hc)) GNUNET_CONTAINER_bloomfilter_add (bf, &hc); } /* end of container_bloomfilter.c */ gnunet-0.9.3/src/util/test_speedup_data.conf0000644000175000017500000000007311761753145016066 00000000000000[testing] SPEEDUP_INTERVAL = 100 ms SPEEDUP_DELTA = 100 ms gnunet-0.9.3/src/util/test_os_network.c0000644000175000017500000000501611760502551015111 00000000000000/* This file is part of GNUnet. (C) 2003, 2004, 2005, 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_os_network.c * @brief testcase for util/os_network.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_configuration_lib.h" #include "gnunet_os_lib.h" #define VERBOSE 1 /** * Check if the address we got is IPv4 or IPv6 loopback (which should * be present on all systems at all times); if so, set ok to 0 * (success). */ static int proc (void *cls, const char *name, int isDefault, const struct sockaddr *addr, const struct sockaddr *broadcast_addr, const struct sockaddr *netmask, socklen_t addrlen) { int *ok = cls; char buf[INET6_ADDRSTRLEN]; if (NULL == addr) return GNUNET_OK; #if VERBOSE const char * protocol; if (addrlen == sizeof (struct sockaddr_in)) protocol = "IPv4"; else protocol = "IPv6"; printf ("%s Address `%s'\n", protocol, GNUNET_a2s ((const struct sockaddr *) addr,addrlen) ); printf (" Netmask `%s'\n", GNUNET_a2s ((const struct sockaddr *) netmask, addrlen) ); printf (" Broadcast `%s'\n", GNUNET_a2s ((const struct sockaddr *) broadcast_addr,addrlen) ); #endif inet_ntop (addr->sa_family, (addr->sa_family == AF_INET) ? (void *) &((struct sockaddr_in *) addr)->sin_addr : (void *) &((struct sockaddr_in6 *) addr)->sin6_addr, buf, sizeof (buf)); if ((0 == strcmp ("::1", buf)) || (0 == strcmp ("127.0.0.1", buf))) *ok = 0; return GNUNET_OK; } static int testifcs () { int ret; ret = 1; GNUNET_OS_network_interfaces_list (&proc, &ret); return ret; } int main (int argc, char *argv[]) { int errCnt = 0; GNUNET_log_setup ("test-os-network", "WARNING", NULL); if (0 != testifcs ()) errCnt++; return errCnt; } gnunet-0.9.3/src/util/os_priority.c0000644000175000017500000014424511761753145014262 00000000000000/* This file is part of GNUnet (C) 2002, 2003, 2004, 2005, 2006, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/os_priority.c * @brief Methods to set process priority * @author Nils Durner */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_os_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_strings_lib.h" #include "gnunet_crypto_lib.h" #include "disk.h" #include #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) #define GNUNET_OS_CONTROL_PIPE "GNUNET_OS_CONTROL_PIPE" struct GNUNET_OS_Process { /** * PID of the process. */ pid_t pid; #if WINDOWS /** * Process handle. */ HANDLE handle; #endif /** * Pipe we use to signal the process (if used). */ struct GNUNET_DISK_FileHandle *control_pipe; /** * Name of the pipe, NULL for none. */ char *childpipename; }; /** * Handle for 'this' process. */ static struct GNUNET_OS_Process current_process; /* MinGW version of named pipe API */ #ifdef MINGW /** * Creates a named pipe/FIFO and opens it * * @param fn pointer to the name of the named pipe or to NULL * @param flags open flags * @param perm access permissions * @return pipe handle on success, NULL on error */ static struct GNUNET_DISK_FileHandle * npipe_create (char **fn, enum GNUNET_DISK_OpenFlags flags, enum GNUNET_DISK_AccessPermissions perm) { struct GNUNET_DISK_FileHandle *ret; HANDLE h = NULL; DWORD openMode; char *name; openMode = 0; if (flags & GNUNET_DISK_OPEN_READWRITE) openMode = PIPE_ACCESS_DUPLEX; else if (flags & GNUNET_DISK_OPEN_READ) openMode = PIPE_ACCESS_INBOUND; else if (flags & GNUNET_DISK_OPEN_WRITE) openMode = PIPE_ACCESS_OUTBOUND; if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS) openMode |= FILE_FLAG_FIRST_PIPE_INSTANCE; while (h == NULL) { DWORD error_code; name = NULL; if (*fn != NULL) { GNUNET_asprintf (&name, "\\\\.\\pipe\\%.246s", fn); LOG (GNUNET_ERROR_TYPE_DEBUG, "Trying to create an instance of named pipe `%s'\n", name); /* 1) This might work just fine with UTF-8 strings as it is. * 2) This is only used by GNUnet itself, and only with latin names. */ h = CreateNamedPipe (name, openMode | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 2, 1, 1, 0, NULL); } else { GNUNET_asprintf (fn, "\\\\.\\pipe\\gnunet-%llu", GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX)); LOG (GNUNET_ERROR_TYPE_DEBUG, "Trying to create unique named pipe `%s'\n", *fn); h = CreateNamedPipe (*fn, openMode | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 2, 1, 1, 0, NULL); } error_code = GetLastError (); if (name) GNUNET_free (name); /* don't re-set name to NULL yet */ if (h == INVALID_HANDLE_VALUE) { SetErrnoFromWinError (error_code); LOG (GNUNET_ERROR_TYPE_DEBUG, "Pipe creation have failed because of %d, errno is %d\n", error_code, errno); if (name == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Pipe was to be unique, considering re-creation\n"); GNUNET_free (*fn); *fn = NULL; if (error_code != ERROR_ACCESS_DENIED && error_code != ERROR_PIPE_BUSY) { return NULL; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Pipe name was not unique, trying again\n"); h = NULL; } else return NULL; } } errno = 0; ret = GNUNET_malloc (sizeof (*ret)); ret->h = h; ret->type = GNUNET_PIPE; ret->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED)); ret->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED)); ret->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); ret->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); return ret; } /** * Opens already existing named pipe/FIFO * * @param fn name of an existing named pipe * @param flags open flags * @return pipe handle on success, NULL on error */ static struct GNUNET_DISK_FileHandle * npipe_open (const char *fn, enum GNUNET_DISK_OpenFlags flags) { struct GNUNET_DISK_FileHandle *ret; HANDLE h; DWORD openMode; openMode = 0; if (flags & GNUNET_DISK_OPEN_READWRITE) openMode = GENERIC_WRITE | GENERIC_READ; else if (flags & GNUNET_DISK_OPEN_READ) openMode = GENERIC_READ; else if (flags & GNUNET_DISK_OPEN_WRITE) openMode = GENERIC_WRITE; h = CreateFile (fn, openMode, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_READ_ATTRIBUTES, NULL); if (h == INVALID_HANDLE_VALUE) { SetErrnoFromWinError (GetLastError ()); return NULL; } ret = GNUNET_malloc (sizeof (*ret)); ret->h = h; ret->type = GNUNET_PIPE; ret->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED)); ret->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED)); ret->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); ret->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); return ret; } #else /* UNIX version of named-pipe API */ /** * Clean up a named pipe and the directory it was placed in. * * @param fn name of the pipe */ static void cleanup_npipe (const char *fn) { char *dn; char *dp; if (0 != unlink (fn)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn); dn = GNUNET_strdup (fn); dp = dirname (dn); if (0 != rmdir (dp)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "rmdir", dp); GNUNET_free (dn); } /** * Setup a named pipe. * * @param fn where to store the name of the new pipe, * if *fn is non-null, the name of the pipe to setup * @return GNUNET_OK on success */ static int npipe_setup (char **fn) { if (NULL == *fn) { /* FIXME: hardwired '/tmp' path... is bad */ char dir[] = "/tmp/gnunet-pipe-XXXXXX"; if (NULL == mkdtemp (dir)) { LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "mkdtemp"); return GNUNET_SYSERR; } GNUNET_asprintf (fn, "%s/child-control", dir); } if (-1 == mkfifo (*fn, S_IRUSR | S_IWUSR)) return GNUNET_SYSERR; return GNUNET_OK; } /** * Open an existing named pipe. * * @param fn name of the file * @param flags flags to use * @return NULL on error */ static struct GNUNET_DISK_FileHandle * npipe_open (const char *fn, enum GNUNET_DISK_OpenFlags flags) { struct GNUNET_DISK_FileHandle *ret; int fd; struct timespec req; int i; /* 200 * 5ms = 1s at most */ for (i=0;i<200;i++) { fd = open (fn, O_NONBLOCK | ((flags == GNUNET_DISK_OPEN_READ) ? O_RDONLY : O_WRONLY)); if ( (-1 != fd) || (9 == i) || (flags == GNUNET_DISK_OPEN_READ)) break; /* as this is for killing a child process via pipe and it is conceivable that the child process simply didn't finish starting yet, we do some sleeping (which is obviously usually not allowed). We can't select on the FD as 'open' fails, and we probably shouldn't just "ignore" the error, so wait and retry a few times is likely the best method; our process API doesn't support continuations, so we need to sleep directly... */ req.tv_sec = 0; req.tv_nsec = 5000000; /* 5ms */ (void) nanosleep (&req, NULL); } if (-1 == fd) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, (flags == GNUNET_DISK_OPEN_READ) ? _("Failed to open named pipe `%s' for reading: %s\n") : _("Failed to open named pipe `%s' for writing: %s\n"), fn, STRERROR (errno)); return NULL; } ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle)); ret->fd = fd; return ret; } #endif /** * This handler is called when there are control data to be read on the pipe * * @param cls the 'struct GNUNET_DISK_FileHandle' of the control pipe * @param tc scheduler context */ static void parent_control_handler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_DISK_FileHandle *control_pipe = cls; char sig; ssize_t ret; LOG (GNUNET_ERROR_TYPE_DEBUG, "`%s' invoked because of %d\n", __FUNCTION__, tc->reason); if (0 != (tc->reason & (GNUNET_SCHEDULER_REASON_SHUTDOWN | GNUNET_SCHEDULER_REASON_TIMEOUT))) { GNUNET_DISK_file_close (control_pipe); control_pipe = NULL; return; } ret = GNUNET_DISK_file_read (control_pipe, &sig, sizeof (sig)); if (sizeof (sig) != ret) { if (-1 == ret) LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "GNUNET_DISK_file_read"); GNUNET_DISK_file_close (control_pipe); control_pipe = NULL; return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Got control code %d from parent\n", sig); GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, control_pipe, &parent_control_handler, control_pipe); raise ((int) sig); } /** * Task that connects this process to its parent via pipe; * essentially, the parent control handler will read signal numbers * from the 'GNUNET_OS_CONTROL_PIPE' (as given in an environment * variable) and raise those signals. * * @param cls closure (unused) * @param tc scheduler context (unused) */ void GNUNET_OS_install_parent_control_handler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { const char *env_buf; struct GNUNET_DISK_FileHandle *control_pipe; env_buf = getenv (GNUNET_OS_CONTROL_PIPE); if ( (env_buf == NULL) || (strlen (env_buf) <= 0) ) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Not installing a handler because $%s is empty\n", GNUNET_OS_CONTROL_PIPE); putenv ("GNUNET_OS_CONTROL_PIPE="); return; } control_pipe = npipe_open (env_buf, GNUNET_DISK_OPEN_READ); if (NULL == control_pipe) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", env_buf); putenv ("GNUNET_OS_CONTROL_PIPE="); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding parent control handler pipe `%s' to the scheduler\n", env_buf); GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, control_pipe, &parent_control_handler, control_pipe); putenv ("GNUNET_OS_CONTROL_PIPE="); } /** * Get process structure for current process * * The pointer it returns points to static memory location and must not be * deallocated/closed * * @return pointer to the process sturcutre for this process */ struct GNUNET_OS_Process * GNUNET_OS_process_current () { #if WINDOWS current_process.pid = GetCurrentProcessId (); current_process.handle = GetCurrentProcess (); #else current_process.pid = 0; #endif return ¤t_process; } /** * Sends a signal to the process * * @param proc pointer to process structure * @param sig signal * @return 0 on success, -1 on error */ int GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig) { int ret; char csig; csig = (char) sig; #if !WINDOWS if ( (NULL == proc->control_pipe) && (NULL != proc->childpipename) ) proc->control_pipe = npipe_open (proc->childpipename, GNUNET_DISK_OPEN_WRITE); #endif if (NULL != proc->control_pipe) { ret = GNUNET_DISK_file_write (proc->control_pipe, &csig, sizeof (csig)); if (ret == sizeof (csig)) return 0; } /* pipe failed or non-existent, try other methods */ switch (sig) { #if !WINDOWS case SIGHUP: #endif case SIGINT: case SIGKILL: case SIGTERM: #if WINDOWS && !defined(__CYGWIN__) if (0 == TerminateProcess (proc->handle, 0)) { /* FIXME: set 'errno' */ return -1; } return 0; #else return PLIBC_KILL (proc->pid, sig); #endif default: #if WINDOWS errno = EINVAL; return -1; #else return PLIBC_KILL (proc->pid, sig); #endif } } /** * Get the pid of the process in question * * @param proc the process to get the pid of * * @return the current process id */ pid_t GNUNET_OS_process_get_pid (struct GNUNET_OS_Process * proc) { return proc->pid; } /** * Cleans up process structure contents (OS-dependent) and deallocates it * * @param proc pointer to process structure */ void GNUNET_OS_process_destroy (struct GNUNET_OS_Process *proc) { if (NULL != proc->control_pipe) GNUNET_DISK_file_close (proc->control_pipe); // FIXME NILS #ifdef WINDOWS if (proc->handle != NULL) CloseHandle (proc->handle); #endif if (NULL != proc->childpipename) { #if !WINDOWS cleanup_npipe (proc->childpipename); #endif GNUNET_free (proc->childpipename); } GNUNET_free (proc); } // FIXME NILS #if WINDOWS #include "gnunet_signal_lib.h" extern GNUNET_SIGNAL_Handler w32_sigchld_handler; /** * Make seaspider happy. */ #define DWORD_WINAPI DWORD WINAPI /** * @brief Waits for a process to terminate and invokes the SIGCHLD handler * @param proc pointer to process structure */ static DWORD_WINAPI child_wait_thread (void *arg) { struct GNUNET_OS_Process *proc = (struct GNUNET_OS_Process *) arg; WaitForSingleObject (proc->handle, INFINITE); if (w32_sigchld_handler) w32_sigchld_handler (); return 0; } #endif /** * Set process priority * * @param proc pointer to process structure * @param prio priority value * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc, enum GNUNET_SCHEDULER_Priority prio) { int rprio; GNUNET_assert (prio < GNUNET_SCHEDULER_PRIORITY_COUNT); if (prio == GNUNET_SCHEDULER_PRIORITY_KEEP) return GNUNET_OK; /* convert to MINGW/Unix values */ switch (prio) { case GNUNET_SCHEDULER_PRIORITY_UI: case GNUNET_SCHEDULER_PRIORITY_URGENT: #ifdef MINGW rprio = HIGH_PRIORITY_CLASS; #else rprio = 0; #endif break; case GNUNET_SCHEDULER_PRIORITY_HIGH: #ifdef MINGW rprio = ABOVE_NORMAL_PRIORITY_CLASS; #else rprio = 5; #endif break; case GNUNET_SCHEDULER_PRIORITY_DEFAULT: #ifdef MINGW rprio = NORMAL_PRIORITY_CLASS; #else rprio = 7; #endif break; case GNUNET_SCHEDULER_PRIORITY_BACKGROUND: #ifdef MINGW rprio = BELOW_NORMAL_PRIORITY_CLASS; #else rprio = 10; #endif break; case GNUNET_SCHEDULER_PRIORITY_IDLE: #ifdef MINGW rprio = IDLE_PRIORITY_CLASS; #else rprio = 19; #endif break; default: GNUNET_assert (0); return GNUNET_SYSERR; } /* Set process priority */ #ifdef MINGW { HANDLE h = proc->handle; GNUNET_assert (h != NULL); SetPriorityClass (h, rprio); } #elif LINUX pid_t pid; pid = proc->pid; if ((0 == pid) || (pid == getpid ())) { int have = nice (0); int delta = rprio - have; errno = 0; if ((delta != 0) && (rprio == nice (delta)) && (errno != 0)) { LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "nice"); return GNUNET_SYSERR; } } else { if (0 != setpriority (PRIO_PROCESS, pid, rprio)) { LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "setpriority"); return GNUNET_SYSERR; } } #else LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "Priority management not availabe for this platform\n"); #endif return GNUNET_OK; } #if MINGW static char * CreateCustomEnvTable (char **vars) { char *win32_env_table; char *ptr; char **var_ptr; char *result; char *result_ptr; size_t tablesize = 0; size_t items_count = 0; size_t n_found = 0; size_t n_var; char *index = NULL; size_t c; size_t var_len; char *var; char *val; win32_env_table = GetEnvironmentStringsA (); if (win32_env_table == NULL) return NULL; for (c = 0, var_ptr = vars; *var_ptr; var_ptr += 2, c++) ; n_var = c; index = GNUNET_malloc (sizeof (char *) * n_var); for (c = 0; c < n_var; c++) index[c] = 0; for (items_count = 0, ptr = win32_env_table; ptr[0] != 0; items_count++) { size_t len = strlen (ptr); int found = 0; for (var_ptr = vars; *var_ptr; var_ptr++) { var = *var_ptr++; val = *var_ptr; var_len = strlen (var); if (strncmp (var, ptr, var_len) == 0) { found = 1; index[c] = 1; tablesize += var_len + strlen (val) + 1; break; } } if (!found) tablesize += len + 1; ptr += len + 1; } for (n_found = 0, c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++) { var = *var_ptr++; val = *var_ptr; if (index[c] != 1) n_found += strlen (var) + strlen (val) + 1; } result = GNUNET_malloc (tablesize + n_found + 1); for (result_ptr = result, ptr = win32_env_table; ptr[0] != 0;) { size_t len = strlen (ptr); int found = 0; for (c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++) { var = *var_ptr++; val = *var_ptr; var_len = strlen (var); if (strncmp (var, ptr, var_len) == 0) { found = 1; break; } } if (!found) { strcpy (result_ptr, ptr); result_ptr += len + 1; } else { strcpy (result_ptr, var); result_ptr += var_len; strcpy (result_ptr, val); result_ptr += strlen (val) + 1; } ptr += len + 1; } for (c = 0, var_ptr = vars; *var_ptr; var_ptr++, c++) { var = *var_ptr++; val = *var_ptr; var_len = strlen (var); if (index[c] != 1) { strcpy (result_ptr, var); result_ptr += var_len; strcpy (result_ptr, val); result_ptr += strlen (val) + 1; } } FreeEnvironmentStrings (win32_env_table); GNUNET_free (index); *result_ptr = 0; return result; } #endif /** * Start a process. * * @param pipe_control should a pipe be used to send signals to the child? * @param pipe_stdin pipe to use to send input to child process (or NULL) * @param pipe_stdout pipe to use to get output from child process (or NULL) * @param filename name of the binary * @param argv NULL-terminated array of arguments to the process * @return pointer to process structure of the new process, NULL on error */ struct GNUNET_OS_Process * GNUNET_OS_start_process_vap (int pipe_control, struct GNUNET_DISK_PipeHandle *pipe_stdin, struct GNUNET_DISK_PipeHandle *pipe_stdout, const char *filename, char *const argv[]) { #ifndef MINGW char *childpipename = NULL; struct GNUNET_OS_Process *gnunet_proc = NULL; pid_t ret; int fd_stdout_write; int fd_stdout_read; int fd_stdin_read; int fd_stdin_write; if ( (GNUNET_YES == pipe_control) && (GNUNET_OK != npipe_setup (&childpipename)) ) return NULL; if (pipe_stdout != NULL) { GNUNET_assert (GNUNET_OK == GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (pipe_stdout, GNUNET_DISK_PIPE_END_WRITE), &fd_stdout_write, sizeof (int))); GNUNET_assert (GNUNET_OK == GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (pipe_stdout, GNUNET_DISK_PIPE_END_READ), &fd_stdout_read, sizeof (int))); } if (pipe_stdin != NULL) { GNUNET_assert (GNUNET_OK == GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (pipe_stdin, GNUNET_DISK_PIPE_END_READ), &fd_stdin_read, sizeof (int))); GNUNET_assert (GNUNET_OK == GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (pipe_stdin, GNUNET_DISK_PIPE_END_WRITE), &fd_stdin_write, sizeof (int))); } ret = fork (); if (-1 == ret) { int eno = errno; LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork"); GNUNET_free_non_null (childpipename); errno = eno; return NULL; } if (0 != ret) { gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process)); gnunet_proc->pid = ret; gnunet_proc->childpipename = childpipename; return gnunet_proc; } if (NULL != childpipename) { setenv (GNUNET_OS_CONTROL_PIPE, childpipename, 1); GNUNET_free (childpipename); } if (pipe_stdout != NULL) { GNUNET_break (0 == close (fd_stdout_read)); if (-1 == dup2 (fd_stdout_write, 1)) LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2"); GNUNET_break (0 == close (fd_stdout_write)); } if (pipe_stdin != NULL) { GNUNET_break (0 == close (fd_stdin_write)); if (-1 == dup2 (fd_stdin_read, 0)) LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2"); GNUNET_break (0 == close (fd_stdin_read)); } execvp (filename, argv); LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename); _exit (1); #else char *childpipename = NULL; struct GNUNET_OS_Process *gnunet_proc = NULL; char *arg; unsigned int cmdlen; char *cmd, *idx; STARTUPINFOW start; PROCESS_INFORMATION proc; int argc, arg_count; HANDLE stdin_handle; HANDLE stdout_handle; struct GNUNET_DISK_FileHandle *control_pipe; char path[MAX_PATH + 1]; char *our_env[3] = { NULL, NULL, NULL }; char *env_block = NULL; char *pathbuf; DWORD pathbuf_len, alloc_len; char *self_prefix; char *bindir; char *libdir; char *ptr; char *non_const_filename; char win_path[MAX_PATH + 1]; wchar_t *wpath, *wcmd; size_t wpath_len, wcmd_len; long lRet; /* Search in prefix dir (hopefully - the directory from which * the current module was loaded), bindir and libdir, then in PATH */ self_prefix = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_SELF_PREFIX); bindir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR); libdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR); pathbuf_len = GetEnvironmentVariableA ("PATH", (char *) &pathbuf, 0); alloc_len = pathbuf_len + 1 + strlen (self_prefix) + 1 + strlen (bindir) + 1 + strlen (libdir); pathbuf = GNUNET_malloc (alloc_len * sizeof (char)); ptr = pathbuf; ptr += sprintf (pathbuf, "%s;%s;%s;", self_prefix, bindir, libdir); GNUNET_free (self_prefix); GNUNET_free (bindir); GNUNET_free (libdir); alloc_len = GetEnvironmentVariableA ("PATH", ptr, pathbuf_len); GNUNET_assert (alloc_len == (pathbuf_len - 1)); cmdlen = strlen (filename); if (cmdlen < 5 || strcmp (&filename[cmdlen - 4], ".exe") != 0) GNUNET_asprintf (&non_const_filename, "%s.exe", filename); else GNUNET_asprintf (&non_const_filename, "%s", filename); /* It could be in POSIX form, convert it to a DOS path early on */ if (ERROR_SUCCESS != (lRet = plibc_conv_to_win_path (non_const_filename, win_path))) { SetErrnoFromWinError (lRet); LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "plibc_conv_to_win_path", non_const_filename); GNUNET_free (non_const_filename); GNUNET_free (pathbuf); return NULL; } GNUNET_free (non_const_filename); non_const_filename = GNUNET_strdup (win_path); /* Check that this is the full path. If it isn't, search. */ /* FIXME: convert it to wchar_t and use SearchPathW? * Remember: arguments to _start_process() are technically in UTF-8... */ if (non_const_filename[1] == ':') snprintf (path, sizeof (path) / sizeof (char), "%s", non_const_filename); else if (!SearchPathA (pathbuf, non_const_filename, NULL, sizeof (path) / sizeof (char), path, NULL)) { SetErrnoFromWinError (GetLastError ()); LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "SearchPath", non_const_filename); GNUNET_free (non_const_filename); GNUNET_free (pathbuf); return NULL; } GNUNET_free (pathbuf); GNUNET_free (non_const_filename); cmdlen = 0; argc = 0; while (NULL != (arg = argv[argc++])) { if (cmdlen == 0) cmdlen = cmdlen + strlen (path) + 4; else cmdlen = cmdlen + strlen (arg) + 4; } arg_count = argc; cmd = idx = GNUNET_malloc (sizeof (char) * (cmdlen + 1)); argc = 0; while (NULL != (arg = argv[argc++])) { /* This is to escape trailing slash */ char arg_lastchar = arg[strlen (arg) - 1]; if (idx == cmd) idx += sprintf (idx, "\"%s%s\"%s", path, arg_lastchar == '\\' ? "\\" : "", argc + 1 == arg_count ? "" : " "); else idx += sprintf (idx, "\"%s%s\"%s", arg, arg_lastchar == '\\' ? "\\" : "", argc + 1 == arg_count ? "" : " "); } memset (&start, 0, sizeof (start)); start.cb = sizeof (start); if ((pipe_stdin != NULL) || (pipe_stdout != NULL)) start.dwFlags |= STARTF_USESTDHANDLES; if (pipe_stdin != NULL) { GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (pipe_stdin, GNUNET_DISK_PIPE_END_READ), &stdin_handle, sizeof (HANDLE)); start.hStdInput = stdin_handle; } if (pipe_stdout != NULL) { GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (pipe_stdout, GNUNET_DISK_PIPE_END_WRITE), &stdout_handle, sizeof (HANDLE)); start.hStdOutput = stdout_handle; } if (GNUNET_YES == pipe_control) { control_pipe = npipe_create (&childpipename, GNUNET_DISK_OPEN_WRITE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (control_pipe == NULL) { GNUNET_free (cmd); GNUNET_free (path); return NULL; } } else control_pipe = NULL; if (NULL != childpipename) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Opened the parent end of the pipe `%s'\n", childpipename); GNUNET_asprintf (&our_env[0], "%s=", GNUNET_OS_CONTROL_PIPE); GNUNET_asprintf (&our_env[1], "%s", childpipename); our_env[2] = NULL; } else { our_env[0] = NULL; } env_block = CreateCustomEnvTable (our_env); GNUNET_free_non_null (our_env[0]); GNUNET_free_non_null (our_env[1]); wpath_len = 0; if (NULL == (wpath = u8_to_u16 ((uint8_t *) path, 1 + strlen (path), NULL, &wpath_len))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to convert `%s' from UTF-8 to UTF-16: %d\n", path, errno); GNUNET_free (env_block); GNUNET_free (cmd); return NULL; } wcmd_len = 0; if (NULL == (wcmd = u8_to_u16 ((uint8_t *) cmd, 1 + strlen (cmd), NULL, &wcmd_len))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to convert `%s' from UTF-8 to UTF-16: %d\n", cmd, errno); GNUNET_free (env_block); GNUNET_free (cmd); free (wpath); return NULL; } if (!CreateProcessW (wpath, wcmd, NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_SUSPENDED, env_block, NULL, &start, &proc)) { SetErrnoFromWinError (GetLastError ()); LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "CreateProcess", path); GNUNET_free (env_block); GNUNET_free (cmd); free (wpath); free (wcmd); return NULL; } GNUNET_free (env_block); gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process)); gnunet_proc->pid = proc.dwProcessId; gnunet_proc->handle = proc.hProcess; gnunet_proc->control_pipe = control_pipe; CreateThread (NULL, 64000, &child_wait_thread, (void *) gnunet_proc, 0, NULL); ResumeThread (proc.hThread); CloseHandle (proc.hThread); GNUNET_free (cmd); free (wpath); free (wcmd); return gnunet_proc; #endif } /** * Start a process. * * @param pipe_control should a pipe be used to send signals to the child? * @param pipe_stdin pipe to use to send input to child process (or NULL) * @param pipe_stdout pipe to use to get output from child process (or NULL) * @param filename name of the binary * @param va NULL-terminated list of arguments to the process * @return pointer to process structure of the new process, NULL on error */ struct GNUNET_OS_Process * GNUNET_OS_start_process_va (int pipe_control, struct GNUNET_DISK_PipeHandle *pipe_stdin, struct GNUNET_DISK_PipeHandle *pipe_stdout, const char *filename, va_list va) { struct GNUNET_OS_Process *ret; va_list ap; char **argv; int argc; argc = 0; va_copy (ap, va); while (NULL != va_arg (ap, char *)) argc++; va_end (ap); argv = GNUNET_malloc (sizeof (char *) * (argc + 1)); argc = 0; va_copy (ap, va); while (NULL != (argv[argc] = va_arg (ap, char *))) argc++; va_end (ap); ret = GNUNET_OS_start_process_vap (pipe_control, pipe_stdin, pipe_stdout, filename, argv); GNUNET_free (argv); return ret; } /** * Start a process. * * @param pipe_control should a pipe be used to send signals to the child? * @param pipe_stdin pipe to use to send input to child process (or NULL) * @param pipe_stdout pipe to use to get output from child process (or NULL) * @param filename name of the binary * @param ... NULL-terminated list of arguments to the process * * @return pointer to process structure of the new process, NULL on error * */ struct GNUNET_OS_Process * GNUNET_OS_start_process (int pipe_control, struct GNUNET_DISK_PipeHandle *pipe_stdin, struct GNUNET_DISK_PipeHandle *pipe_stdout, const char *filename, ...) { struct GNUNET_OS_Process *ret; va_list ap; va_start (ap, filename); ret = GNUNET_OS_start_process_va (pipe_control, pipe_stdin, pipe_stdout, filename, ap); va_end (ap); return ret; } /** * Start a process. * * @param pipe_control should a pipe be used to send signals to the child? * @param lsocks array of listen sockets to dup systemd-style (or NULL); * must be NULL on platforms where dup is not supported * @param filename name of the binary * @param argv NULL-terminated list of arguments to the process * @return process ID of the new process, -1 on error */ struct GNUNET_OS_Process * GNUNET_OS_start_process_v (int pipe_control, const SOCKTYPE *lsocks, const char *filename, char *const argv[]) { #ifndef MINGW pid_t ret; char lpid[16]; char fds[16]; struct GNUNET_OS_Process *gnunet_proc = NULL; char *childpipename = NULL; int i; int j; int k; int tgt; int flags; int *lscp; unsigned int ls; if ( (GNUNET_YES == pipe_control) && (GNUNET_OK != npipe_setup (&childpipename)) ) return NULL; lscp = NULL; ls = 0; if (lsocks != NULL) { i = 0; while (-1 != (k = lsocks[i++])) GNUNET_array_append (lscp, ls, k); GNUNET_array_append (lscp, ls, -1); } ret = fork (); if (-1 == ret) { int eno = errno; LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork"); GNUNET_free_non_null (childpipename); GNUNET_array_grow (lscp, ls, 0); errno = eno; return NULL; } if (0 != ret) { gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process)); gnunet_proc->pid = ret; gnunet_proc->childpipename = childpipename; GNUNET_array_grow (lscp, ls, 0); return gnunet_proc; } if (NULL != childpipename) { setenv (GNUNET_OS_CONTROL_PIPE, childpipename, 1); GNUNET_free (childpipename); } if (lscp != NULL) { /* read systemd documentation... */ GNUNET_snprintf (lpid, sizeof (lpid), "%u", getpid ()); setenv ("LISTEN_PID", lpid, 1); i = 0; tgt = 3; while (-1 != lscp[i]) { j = i + 1; while (-1 != lscp[j]) { if (lscp[j] == tgt) { /* dup away */ k = dup (lscp[j]); GNUNET_assert (-1 != k); GNUNET_assert (0 == close (lscp[j])); lscp[j] = k; break; } j++; } if (lscp[i] != tgt) { /* Bury any existing FD, no matter what; they should all be closed * on exec anyway and the important onces have been dup'ed away */ (void) close (tgt); GNUNET_assert (-1 != dup2 (lscp[i], tgt)); } /* unset close-on-exec flag */ flags = fcntl (tgt, F_GETFD); GNUNET_assert (flags >= 0); flags &= ~FD_CLOEXEC; fflush (stderr); (void) fcntl (tgt, F_SETFD, flags); tgt++; i++; } GNUNET_snprintf (fds, sizeof (fds), "%u", i); setenv ("LISTEN_FDS", fds, 1); } GNUNET_array_grow (lscp, ls, 0); execvp (filename, argv); LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename); _exit (1); #else struct GNUNET_DISK_FileHandle *control_pipe = NULL; char *childpipename = NULL; char **arg, **non_const_argv; unsigned int cmdlen; char *cmd, *idx; STARTUPINFOW start; PROCESS_INFORMATION proc; int argcount = 0; struct GNUNET_OS_Process *gnunet_proc = NULL; char path[MAX_PATH + 1]; char *our_env[5] = { NULL, NULL, NULL, NULL, NULL }; char *env_block = NULL; char *pathbuf; DWORD pathbuf_len, alloc_len; char *self_prefix; char *bindir; char *libdir; char *ptr; char *non_const_filename; char win_path[MAX_PATH + 1]; struct GNUNET_DISK_PipeHandle *lsocks_pipe; const struct GNUNET_DISK_FileHandle *lsocks_write_fd; HANDLE lsocks_read; HANDLE lsocks_write; wchar_t *wpath, *wcmd; size_t wpath_len, wcmd_len; int env_off; int fail; long lRet; /* Search in prefix dir (hopefully - the directory from which * the current module was loaded), bindir and libdir, then in PATH */ self_prefix = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_SELF_PREFIX); bindir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR); libdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR); pathbuf_len = GetEnvironmentVariableA ("PATH", (char *) &pathbuf, 0); alloc_len = pathbuf_len + 1 + strlen (self_prefix) + 1 + strlen (bindir) + 1 + strlen (libdir); pathbuf = GNUNET_malloc (alloc_len * sizeof (char)); ptr = pathbuf; ptr += sprintf (pathbuf, "%s;%s;%s;", self_prefix, bindir, libdir); GNUNET_free (self_prefix); GNUNET_free (bindir); GNUNET_free (libdir); alloc_len = GetEnvironmentVariableA ("PATH", ptr, pathbuf_len); if (alloc_len != pathbuf_len - 1) { GNUNET_free (pathbuf); errno = ENOSYS; /* PATH changed on the fly. What kind of error is that? */ return NULL; } cmdlen = strlen (filename); if (cmdlen < 5 || strcmp (&filename[cmdlen - 4], ".exe") != 0) GNUNET_asprintf (&non_const_filename, "%s.exe", filename); else GNUNET_asprintf (&non_const_filename, "%s", filename); /* It could be in POSIX form, convert it to a DOS path early on */ if (ERROR_SUCCESS != (lRet = plibc_conv_to_win_path (non_const_filename, win_path))) { SetErrnoFromWinError (lRet); LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "plibc_conv_to_win_path", non_const_filename); GNUNET_free (non_const_filename); GNUNET_free (pathbuf); return NULL; } GNUNET_free (non_const_filename); non_const_filename = GNUNET_strdup (win_path); /* Check that this is the full path. If it isn't, search. */ /* FIXME: convert it to wchar_t and use SearchPathW? * Remember: arguments to _start_process() are technically in UTF-8... */ if (non_const_filename[1] == ':') snprintf (path, sizeof (path) / sizeof (char), "%s", non_const_filename); else if (!SearchPathA (pathbuf, non_const_filename, NULL, sizeof (path) / sizeof (char), path, NULL)) { SetErrnoFromWinError (GetLastError ()); LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "SearchPath", non_const_filename); GNUNET_free (non_const_filename); GNUNET_free (pathbuf); return NULL; } GNUNET_free (pathbuf); GNUNET_free (non_const_filename); /* Count the number of arguments */ arg = (char **) argv; while (*arg) { arg++; argcount++; } /* Allocate a copy argv */ non_const_argv = GNUNET_malloc (sizeof (char *) * (argcount + 1)); /* Copy all argv strings */ argcount = 0; arg = (char **) argv; while (*arg) { if (arg == argv) non_const_argv[argcount] = GNUNET_strdup (path); else non_const_argv[argcount] = GNUNET_strdup (*arg); arg++; argcount++; } non_const_argv[argcount] = NULL; /* Count cmd len */ cmdlen = 1; arg = non_const_argv; while (*arg) { cmdlen = cmdlen + strlen (*arg) + 4; arg++; } /* Allocate and create cmd */ cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen); arg = non_const_argv; while (*arg) { char arg_last_char = (*arg)[strlen (*arg) - 1]; idx += sprintf (idx, "\"%s%s\"%s", *arg, arg_last_char == '\\' ? "\\" : "", *(arg + 1) ? " " : ""); arg++; } while (argcount > 0) GNUNET_free (non_const_argv[--argcount]); GNUNET_free (non_const_argv); memset (&start, 0, sizeof (start)); start.cb = sizeof (start); if (GNUNET_YES == pipe_control) { control_pipe = npipe_create (&childpipename, GNUNET_DISK_OPEN_WRITE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (control_pipe == NULL) { GNUNET_free (cmd); GNUNET_free (path); return NULL; } } else control_pipe = NULL; if (lsocks != NULL && lsocks[0] != INVALID_SOCKET) { lsocks_pipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO); if (lsocks_pipe == NULL) { GNUNET_free (cmd); GNUNET_free (path); GNUNET_DISK_pipe_close (lsocks_pipe); return NULL; } lsocks_write_fd = GNUNET_DISK_pipe_handle (lsocks_pipe, GNUNET_DISK_PIPE_END_WRITE); GNUNET_DISK_internal_file_handle_ (lsocks_write_fd, &lsocks_write, sizeof (HANDLE)); GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (lsocks_pipe, GNUNET_DISK_PIPE_END_READ), &lsocks_read, sizeof (HANDLE)); } env_off = 0; if (NULL != childpipename) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Opened the parent end of the pipe `%s'\n", childpipename); GNUNET_asprintf (&our_env[env_off++], "%s=", GNUNET_OS_CONTROL_PIPE); GNUNET_asprintf (&our_env[env_off++], "%s", childpipename); GNUNET_free (childpipename); } if ( (lsocks != NULL) && (lsocks[0] != INVALID_SOCKET)) { /*This will tell the child that we're going to send lsocks over the pipe*/ GNUNET_asprintf (&our_env[env_off++], "%s=", "GNUNET_OS_READ_LSOCKS"); GNUNET_asprintf (&our_env[env_off++], "%lu", lsocks_read); } our_env[env_off++] = NULL; env_block = CreateCustomEnvTable (our_env); while (0 > env_off) GNUNET_free_non_null (our_env[--env_off]); wpath_len = 0; if (NULL == (wpath = u8_to_u16 ((uint8_t *) path, 1 + strlen (path), NULL, &wpath_len))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to convert `%s' from UTF-8 to UTF-16: %d\n", path, errno); GNUNET_free (env_block); GNUNET_free (cmd); return NULL; } wcmd_len = 0; if (NULL == (wcmd = u8_to_u16 ((uint8_t *) cmd, 1 + strlen (cmd), NULL, &wcmd_len))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to convert `%s' from UTF-8 to UTF-16: %d\n", cmd, errno); GNUNET_free (env_block); GNUNET_free (cmd); free (wpath); return NULL; } if (!CreateProcessW (wpath, wcmd, NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_SUSPENDED, env_block, NULL, &start, &proc)) { SetErrnoFromWinError (GetLastError ()); LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "CreateProcess"); if (NULL != control_pipe) GNUNET_DISK_file_close (control_pipe); if (NULL != lsocks) GNUNET_DISK_pipe_close (lsocks_pipe); GNUNET_free (env_block); GNUNET_free (cmd); free (wpath); free (wcmd); return NULL; } GNUNET_free (env_block); gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process)); gnunet_proc->pid = proc.dwProcessId; gnunet_proc->handle = proc.hProcess; gnunet_proc->control_pipe = control_pipe; CreateThread (NULL, 64000, &child_wait_thread, (void *) gnunet_proc, 0, NULL); ResumeThread (proc.hThread); CloseHandle (proc.hThread); GNUNET_free (cmd); free (wpath); free (wcmd); if (lsocks == NULL || lsocks[0] == INVALID_SOCKET) return gnunet_proc; GNUNET_DISK_pipe_close_end (lsocks_pipe, GNUNET_DISK_PIPE_END_READ); /* This is a replacement for "goto error" that doesn't use goto */ fail = 1; do { int wrote; uint64_t size, count, i; /* Tell the number of sockets */ for (count = 0; lsocks && lsocks[count] != INVALID_SOCKET; count++); wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count)); if (wrote != sizeof (count)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write %u count bytes to the child: %u\n", sizeof (count), GetLastError ()); break; } for (i = 0; lsocks && lsocks[i] != INVALID_SOCKET; i++) { WSAPROTOCOL_INFOA pi; /* Get a socket duplication info */ if (SOCKET_ERROR == WSADuplicateSocketA (lsocks[i], gnunet_proc->pid, &pi)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to duplicate an socket[%llu]: %u\n", i, GetLastError ()); LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "CreateProcess"); break; } /* Synchronous I/O is not nice, but we can't schedule this: * lsocks will be closed/freed by the caller soon, and until * the child creates a duplicate, closing a socket here will * close it for good. */ /* Send the size of the structure * (the child might be built with different headers...) */ size = sizeof (pi); wrote = GNUNET_DISK_file_write (lsocks_write_fd, &size, sizeof (size)); if (wrote != sizeof (size)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write %u size[%llu] bytes to the child: %u\n", sizeof (size), i, GetLastError ()); break; } /* Finally! Send the data */ wrote = GNUNET_DISK_file_write (lsocks_write_fd, &pi, sizeof (pi)); if (wrote != sizeof (pi)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write %u socket[%llu] bytes to the child: %u\n", sizeof (pi), i, GetLastError ()); break; } } /* This will block us until the child makes a final read or closes * the pipe (hence no 'wrote' check), since we have to wait for it * to duplicate the last socket, before we return and start closing * our own copies) */ wrote = GNUNET_DISK_file_write (lsocks_write_fd, &count, sizeof (count)); fail = 0; } while (fail); GNUNET_DISK_file_sync (lsocks_write_fd); GNUNET_DISK_pipe_close (lsocks_pipe); if (fail) { /* If we can't pass on the socket(s), the child will block forever, * better put it out of its misery. */ TerminateProcess (gnunet_proc->handle, 0); CloseHandle (gnunet_proc->handle); if (NULL != gnunet_proc->control_pipe) GNUNET_DISK_file_close (gnunet_proc->control_pipe); GNUNET_free (gnunet_proc); return NULL; } return gnunet_proc; #endif } /** * Retrieve the status of a process, waiting on him if dead. * Nonblocking version. * * @param proc process ID * @param type status type * @param code return code/signal number * @return GNUNET_OK on success, GNUNET_NO if the process is still running, GNUNET_SYSERR otherwise */ int GNUNET_OS_process_status (struct GNUNET_OS_Process *proc, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code) { #ifndef MINGW int status; int ret; GNUNET_assert (0 != proc); ret = waitpid (proc->pid, &status, WNOHANG); if (ret < 0) { LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid"); return GNUNET_SYSERR; } if (0 == ret) { *type = GNUNET_OS_PROCESS_RUNNING; *code = 0; return GNUNET_NO; } if (proc->pid != ret) { LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid"); return GNUNET_SYSERR; } if (WIFEXITED (status)) { *type = GNUNET_OS_PROCESS_EXITED; *code = WEXITSTATUS (status); } else if (WIFSIGNALED (status)) { *type = GNUNET_OS_PROCESS_SIGNALED; *code = WTERMSIG (status); } else if (WIFSTOPPED (status)) { *type = GNUNET_OS_PROCESS_SIGNALED; *code = WSTOPSIG (status); } #ifdef WIFCONTINUED else if (WIFCONTINUED (status)) { *type = GNUNET_OS_PROCESS_RUNNING; *code = 0; } #endif else { *type = GNUNET_OS_PROCESS_UNKNOWN; *code = 0; } #else HANDLE h; DWORD c, error_code, ret; h = proc->handle; ret = proc->pid; if (h == NULL || ret == 0) { LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n", ret, h); return GNUNET_SYSERR; } if (h == NULL) h = GetCurrentProcess (); SetLastError (0); ret = GetExitCodeProcess (h, &c); error_code = GetLastError (); if (ret == 0 || error_code != NO_ERROR) { SetErrnoFromWinError (error_code); LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "GetExitCodeProcess"); return GNUNET_SYSERR; } if (STILL_ACTIVE == c) { *type = GNUNET_OS_PROCESS_RUNNING; *code = 0; return GNUNET_NO; } *type = GNUNET_OS_PROCESS_EXITED; *code = c; #endif return GNUNET_OK; } /** * Wait for a process * @param proc pointer to process structure * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc) { #ifndef MINGW pid_t pid = proc->pid; pid_t ret; while ( (pid != (ret = waitpid (pid, NULL, 0))) && (EINTR == errno) ) ; if (pid != ret) { LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid"); return GNUNET_SYSERR; } return GNUNET_OK; #else HANDLE h; int ret; h = proc->handle; if (NULL == h) { LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n", proc->pid, h); return GNUNET_SYSERR; } if (h == NULL) h = GetCurrentProcess (); if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE)) { SetErrnoFromWinError (GetLastError ()); ret = GNUNET_SYSERR; } else ret = GNUNET_OK; return ret; #endif } /** * Handle to a command. */ struct GNUNET_OS_CommandHandle { /** * Process handle. */ struct GNUNET_OS_Process *eip; /** * Handle to the output pipe. */ struct GNUNET_DISK_PipeHandle *opipe; /** * Read-end of output pipe. */ const struct GNUNET_DISK_FileHandle *r; /** * Function to call on each line of output. */ GNUNET_OS_LineProcessor proc; /** * Closure for 'proc'. */ void *proc_cls; /** * Buffer for the output. */ char buf[1024]; /** * Task reading from pipe. */ GNUNET_SCHEDULER_TaskIdentifier rtask; /** * When to time out. */ struct GNUNET_TIME_Absolute timeout; /** * Current read offset in buf. */ size_t off; }; /** * Stop/kill a command. Must ONLY be called either from * the callback after 'NULL' was passed for 'line' *OR* * from an independent task (not within the line processor). * * @param cmd handle to the process */ void GNUNET_OS_command_stop (struct GNUNET_OS_CommandHandle *cmd) { if (cmd->proc != NULL) { GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != cmd->rtask); GNUNET_SCHEDULER_cancel (cmd->rtask); } (void) GNUNET_OS_process_kill (cmd->eip, SIGKILL); GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (cmd->eip)); GNUNET_OS_process_destroy (cmd->eip); GNUNET_DISK_pipe_close (cmd->opipe); GNUNET_free (cmd); } /** * Read from the process and call the line processor. * * @param cls the 'struct GNUNET_OS_CommandHandle' * @param tc scheduler context */ static void cmd_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_OS_CommandHandle *cmd = cls; GNUNET_OS_LineProcessor proc; char *end; ssize_t ret; cmd->rtask = GNUNET_SCHEDULER_NO_TASK; if (GNUNET_YES != GNUNET_NETWORK_fdset_handle_isset (tc->read_ready, cmd->r)) { /* timeout, shutdown, etc. */ proc = cmd->proc; cmd->proc = NULL; proc (cmd->proc_cls, NULL); return; } ret = GNUNET_DISK_file_read (cmd->r, &cmd->buf[cmd->off], sizeof (cmd->buf) - cmd->off); if (ret <= 0) { if ((cmd->off > 0) && (cmd->off < sizeof (cmd->buf))) { cmd->buf[cmd->off] = '\0'; cmd->proc (cmd->proc_cls, cmd->buf); } proc = cmd->proc; cmd->proc = NULL; proc (cmd->proc_cls, NULL); return; } end = memchr (&cmd->buf[cmd->off], '\n', ret); cmd->off += ret; while (end != NULL) { *end = '\0'; cmd->proc (cmd->proc_cls, cmd->buf); memmove (cmd->buf, end + 1, cmd->off - (end + 1 - cmd->buf)); cmd->off -= (end + 1 - cmd->buf); end = memchr (cmd->buf, '\n', cmd->off); } cmd->rtask = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining (cmd->timeout), cmd->r, &cmd_read, cmd); } /** * Run the given command line and call the given function * for each line of the output. * * @param proc function to call for each line of the output * @param proc_cls closure for proc * @param timeout when to time out * @param binary command to run * @param ... arguments to command * @return NULL on error */ struct GNUNET_OS_CommandHandle * GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls, struct GNUNET_TIME_Relative timeout, const char *binary, ...) { struct GNUNET_OS_CommandHandle *cmd; struct GNUNET_OS_Process *eip; struct GNUNET_DISK_PipeHandle *opipe; va_list ap; opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); if (NULL == opipe) return NULL; va_start (ap, binary); eip = GNUNET_OS_start_process_va (GNUNET_NO, NULL, opipe, binary, ap); va_end (ap); if (NULL == eip) { GNUNET_DISK_pipe_close (opipe); return NULL; } GNUNET_DISK_pipe_close_end (opipe, GNUNET_DISK_PIPE_END_WRITE); cmd = GNUNET_malloc (sizeof (struct GNUNET_OS_CommandHandle)); cmd->timeout = GNUNET_TIME_relative_to_absolute (timeout); cmd->eip = eip; cmd->opipe = opipe; cmd->proc = proc; cmd->proc_cls = proc_cls; cmd->r = GNUNET_DISK_pipe_handle (opipe, GNUNET_DISK_PIPE_END_READ); cmd->rtask = GNUNET_SCHEDULER_add_read_file (timeout, cmd->r, &cmd_read, cmd); return cmd; } /* end of os_priority.c */ gnunet-0.9.3/src/util/win.cc0000644000175000017500000011317611707326360012632 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/win.cc * @brief Helper functions for MS Windows in C++ * @author Nils Durner */ #ifndef _WIN_CC #define _WIN_CC #include "winproc.h" #include "platform.h" #include "gnunet_common.h" #include "gnunet_connection_lib.h" #include using namespace std; #include #ifndef INHERITED_ACE #define INHERITED_ACE 0x10 #endif extern "C" { int plibc_conv_to_win_path(const char *pszUnix, char *pszWindows); #define _IP_ADAPTER_UNICAST_ADDRESS_HEAD \ union { \ struct { \ ULONG Length; \ DWORD Flags; \ }; \ }; \ #define _IP_ADAPTER_UNICAST_ADDRESS_BASE \ SOCKET_ADDRESS Address; \ IP_PREFIX_ORIGIN PrefixOrigin; \ IP_SUFFIX_ORIGIN SuffixOrigin; \ IP_DAD_STATE DadState; \ ULONG ValidLifetime; \ ULONG PreferredLifetime; \ ULONG LeaseLifetime; #define _IP_ADAPTER_UNICAST_ADDRESS_ADD_VISTA \ UINT8 OnLinkPrefixLength; #define _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(suffix,addition) \ typedef struct _IP_ADAPTER_UNICAST_ADDRESS##suffix { \ _IP_ADAPTER_UNICAST_ADDRESS_HEAD \ struct _IP_ADAPTER_UNICAST_ADDRESS##suffix *Next; \ _IP_ADAPTER_UNICAST_ADDRESS_BASE \ addition \ } IP_ADAPTER_UNICAST_ADDRESS##suffix, *PIP_ADAPTER_UNICAST_ADDRESS##suffix; /* _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(,) defined in w32api headers */ _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(_VISTA,_IP_ADAPTER_UNICAST_ADDRESS_ADD_VISTA) typedef struct _IP_ADAPTER_WINS_SERVER_ADDRESS { union { ULONGLONG Alignment; struct { ULONG Length; DWORD Reserved; }; }; struct _IP_ADAPTER_WINS_SERVER_ADDRESS *Next; SOCKET_ADDRESS Address; } IP_ADAPTER_WINS_SERVER_ADDRESS, *PIP_ADAPTER_WINS_SERVER_ADDRESS, *PIP_ADAPTER_WINS_SERVER_ADDRESS_LH; typedef struct _IP_ADAPTER_GATEWAY_ADDRESS { union { ULONGLONG Alignment; struct { ULONG Length; DWORD Reserved; }; }; struct _IP_ADAPTER_GATEWAY_ADDRESS *Next; SOCKET_ADDRESS Address; } IP_ADAPTER_GATEWAY_ADDRESS, *PIP_ADAPTER_GATEWAY_ADDRESS, *PIP_ADAPTER_GATEWAY_ADDRESS_LH; typedef UINT32 NET_IF_COMPARTMENT_ID; typedef GUID NET_IF_NETWORK_GUID; typedef enum _NET_IF_CONNECTION_TYPE { NET_IF_CONNECTION_DEDICATED = 1, NET_IF_CONNECTION_PASSIVE, NET_IF_CONNECTION_DEMAND, NET_IF_CONNECTION_MAXIMUM } NET_IF_CONNECTION_TYPE, *PNET_IF_CONNECTION_TYPE; typedef enum { TUNNEL_TYPE_NONE = 0, TUNNEL_TYPE_OTHER, TUNNEL_TYPE_DIRECT, TUNNEL_TYPE_6TO4, TUNNEL_TYPE_ISATAP, TUNNEL_TYPE_TEREDO, TUNNEL_TYPE_IPHTTPS } TUNNEL_TYPE, *PTUNNEL_TYPE; /* A DUID consists of a two-octet type code represented in network byte order, followed by a variable number of octets that make up the actual identifier. A DUID can be no more than 128 octets long (not including the type code). */ #define MAX_DHCPV6_DUID_LENGTH 130 typedef union _NET_LUID { ULONG64 Value; struct { ULONG64 Reserved :24; ULONG64 NetLuidIndex :24; ULONG64 IfType :16; } Info; } NET_LUID, *PNET_LUID, IF_LUID; #define MAX_DNS_SUFFIX_STRING_LENGTH 246 typedef struct _IP_ADAPTER_DNS_SUFFIX { struct _IP_ADAPTER_DNS_SUFFIX *Next; WCHAR String[MAX_DNS_SUFFIX_STRING_LENGTH]; } IP_ADAPTER_DNS_SUFFIX, *PIP_ADAPTER_DNS_SUFFIX; #define _IP_ADAPTER_ADDRESSES_HEAD \ union { \ ULONGLONG Alignment; \ struct { \ ULONG Length; \ DWORD IfIndex; \ }; \ }; #define _IP_ADAPTER_ADDRESSES_BASE \ PCHAR AdapterName; \ PIP_ADAPTER_UNICAST_ADDRESS FirstUnicastAddress; \ PIP_ADAPTER_ANYCAST_ADDRESS FirstAnycastAddress; \ PIP_ADAPTER_MULTICAST_ADDRESS FirstMulticastAddress; \ PIP_ADAPTER_DNS_SERVER_ADDRESS FirstDnsServerAddress; \ PWCHAR DnsSuffix; \ PWCHAR Description; \ PWCHAR FriendlyName; \ BYTE PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH]; \ DWORD PhysicalAddressLength; \ DWORD Flags; \ DWORD Mtu; \ DWORD IfType; \ IF_OPER_STATUS OperStatus; #define _IP_ADAPTER_ADDRESSES_ADD_XPSP1 \ DWORD Ipv6IfIndex; \ DWORD ZoneIndices[16]; \ PIP_ADAPTER_PREFIX FirstPrefix; \ #define _IP_ADAPTER_ADDRESSES_ADD_VISTA \ _IP_ADAPTER_ADDRESSES_ADD_XPSP1 \ ULONG64 TransmitLinkSpeed; \ ULONG64 ReceiveLinkSpeed; \ PIP_ADAPTER_WINS_SERVER_ADDRESS_LH FirstWinsServerAddress; \ PIP_ADAPTER_GATEWAY_ADDRESS_LH FirstGatewayAddress; \ ULONG Ipv4Metric; \ ULONG Ipv6Metric; \ IF_LUID Luid; \ SOCKET_ADDRESS Dhcpv4Server; \ NET_IF_COMPARTMENT_ID CompartmentId; \ NET_IF_NETWORK_GUID NetworkGuid; \ NET_IF_CONNECTION_TYPE ConnectionType; \ TUNNEL_TYPE TunnelType; \ SOCKET_ADDRESS Dhcpv6Server; \ BYTE Dhcpv6ClientDuid[MAX_DHCPV6_DUID_LENGTH]; \ ULONG Dhcpv6ClientDuidLength; \ ULONG Dhcpv6Iaid; #define _IP_ADAPTER_ADDRESSES_ADD_2008_OR_VISTASP1 \ _IP_ADAPTER_ADDRESSES_ADD_VISTA \ PIP_ADAPTER_DNS_SUFFIX FirstDnsSuffix; #define _IP_ADAPTER_ADDRESSES_DEFINE(suffix,addition) \ typedef struct _IP_ADAPTER_ADDRESSES##suffix { \ _IP_ADAPTER_ADDRESSES_HEAD \ struct _IP_ADAPTER_ADDRESSES##suffix *Next; \ _IP_ADAPTER_ADDRESSES_BASE \ addition \ } IP_ADAPTER_ADDRESSES##suffix, *PIP_ADAPTER_ADDRESSES##suffix; /* _IP_ADAPTER_ADDRESSES_DEFINE(,) defined in w32api headers */ _IP_ADAPTER_ADDRESSES_DEFINE(_XPSP1,_IP_ADAPTER_ADDRESSES_ADD_XPSP1) _IP_ADAPTER_ADDRESSES_DEFINE(_VISTA,_IP_ADAPTER_ADDRESSES_ADD_VISTA) _IP_ADAPTER_ADDRESSES_DEFINE(_2008_OR_VISTASP1,_IP_ADAPTER_ADDRESSES_ADD_2008_OR_VISTASP1) static int EnumNICs_IPv6_get_ifs_count (SOCKET s) { DWORD dwret = 0, err; int iret; iret = WSAIoctl (s, SIO_ADDRESS_LIST_QUERY, NULL, 0, NULL, 0, &dwret, NULL, NULL); err = GetLastError (); if (iret == SOCKET_ERROR && err == WSAEFAULT) return dwret; else if (iret == 0) return 0; return GNUNET_SYSERR; } static int EnumNICs_IPv6_get_ifs (SOCKET s, SOCKET_ADDRESS_LIST *inf, int size) { int iret; DWORD dwret = 0; iret = WSAIoctl (s, SIO_ADDRESS_LIST_QUERY, NULL, 0, inf, size, &dwret, NULL, NULL); if (iret != 0 || dwret != size) { /* It's supposed to succeed! And size should be the same */ return GNUNET_SYSERR; } return GNUNET_OK; } #undef GNUNET_malloc #define GNUNET_malloc(a) HeapAlloc(GetProcessHeap (), HEAP_ZERO_MEMORY | \ HEAP_GENERATE_EXCEPTIONS, a) #undef GNUNET_free #define GNUNET_free(a) HeapFree(GetProcessHeap (), 0, a) #undef GNUNET_free_non_null #define GNUNET_free_non_null(a) do { if ((a) != NULL) GNUNET_free(a); } while (0) static int EnumNICs_IPv4_get_ifs (SOCKET s, INTERFACE_INFO **inf, int *size) { int iret; DWORD dwret = 0; DWORD error; INTERFACE_INFO *ii = NULL; DWORD ii_size = sizeof (INTERFACE_INFO) * 15; while (TRUE) { if (ii_size >= sizeof (INTERFACE_INFO) * 1000) return GNUNET_SYSERR; ii = (INTERFACE_INFO *) GNUNET_malloc (ii_size); dwret = 0; iret = WSAIoctl (s, SIO_GET_INTERFACE_LIST, NULL, 0, ii, ii_size, &dwret, NULL, NULL); error = GetLastError (); if (iret == SOCKET_ERROR) { if (error == WSAEFAULT) { GNUNET_free (ii); ii_size *= 2; continue; } GNUNET_free (ii); return GNUNET_SYSERR; } else { *inf = ii; *size = dwret; return GNUNET_OK; } } return GNUNET_SYSERR; } int EnumNICs2 (INTERFACE_INFO **ifs4, int *ifs4_len, SOCKET_ADDRESS_LIST **ifs6) { int result = 0; SOCKET s4 = INVALID_SOCKET, s6 = INVALID_SOCKET; DWORD dwret1 = 0, dwret2; DWORD err1, err2; int ifs4len = 0, ifs6len = 0; INTERFACE_INFO *interfaces4 = NULL; SOCKET_ADDRESS_LIST *interfaces6 = NULL; SetLastError (0); s4 = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); err1 = GetLastError (); SetLastError (0); s6 = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP); err2 = GetLastError (); if (s6 != INVALID_SOCKET) { ifs6len = EnumNICs_IPv6_get_ifs_count (s6); if (ifs6len > 0) { interfaces6 = (SOCKET_ADDRESS_LIST *) GNUNET_malloc (ifs6len); result = EnumNICs_IPv6_get_ifs (s6, interfaces6, ifs6len) || result; } closesocket (s6); s6 = INVALID_SOCKET; } if (s4 != INVALID_SOCKET) { result = EnumNICs_IPv4_get_ifs (s4, &interfaces4, &ifs4len) || result; closesocket (s4); s4 = INVALID_SOCKET; } if (ifs6len + ifs4len == 0) goto error; if (!result) { *ifs4 = interfaces4; *ifs4_len = ifs4len; *ifs6 = interfaces6; return GNUNET_OK; } error: if (interfaces4 != NULL) GNUNET_free (interfaces4); if (interfaces6 != NULL) GNUNET_free (interfaces6); if (s4 != INVALID_SOCKET) closesocket (s4); if (s6 != INVALID_SOCKET) closesocket (s6); return GNUNET_SYSERR; } /** * Returns GNUNET_OK on OK, GNUNET_SYSERR on error */ int EnumNICs3 (struct EnumNICs3_results **results, int *results_count) { DWORD dwRetVal = 0; int count = 0; ULONG flags = /*GAA_FLAG_INCLUDE_PREFIX |*/ GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER; struct sockaddr_in6 examplecom6; IPAddr examplecom; DWORD best_interface = 0; DWORD best_interface6 = 0; int use_enum2 = 0; INTERFACE_INFO *interfaces4 = NULL; int interfaces4_len = 0; SOCKET_ADDRESS_LIST *interfaces6 = NULL; unsigned long outBufLen = sizeof (IP_ADAPTER_ADDRESSES); IP_ADAPTER_ADDRESSES *pCurrentAddress = NULL; IP_ADAPTER_ADDRESSES *pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen); if (GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW) { GNUNET_free (pAddresses); pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen); } dwRetVal = GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen); if (dwRetVal != NO_ERROR) { GNUNET_free (pAddresses); return GNUNET_SYSERR; } if (pAddresses->Length < sizeof (IP_ADAPTER_ADDRESSES_VISTA)) { use_enum2 = 1; /* Enumerate NICs using WSAIoctl() */ if (GNUNET_OK != EnumNICs2 (&interfaces4, &interfaces4_len, &interfaces6)) { GNUNET_free (pAddresses); return GNUNET_SYSERR; } } examplecom = inet_addr("192.0.34.166"); /* www.example.com */ if (GetBestInterface (examplecom, &best_interface) != NO_ERROR) best_interface = 0; if (GNGetBestInterfaceEx != NULL) { examplecom6.sin6_family = AF_INET6; examplecom6.sin6_port = 0; examplecom6.sin6_flowinfo = 0; examplecom6.sin6_scope_id = 0; inet_pton (AF_INET6, "2001:500:88:200:0:0:0:10", (struct sockaddr *) &examplecom6.sin6_addr); dwRetVal = GNGetBestInterfaceEx ((struct sockaddr *) &examplecom6, &best_interface6); if (dwRetVal != NO_ERROR) best_interface6 = 0; } /* Give IPv6 a priority */ if (best_interface6 != 0) best_interface = best_interface6; count = 0; for (pCurrentAddress = pAddresses; pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next) { if (pCurrentAddress->OperStatus == IfOperStatusUp) { IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL; for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL; unicast = unicast->Next) { if ((unicast->Address.lpSockaddr->sa_family == AF_INET || unicast->Address.lpSockaddr->sa_family == AF_INET6) && (unicast->DadState == IpDadStateDeprecated || unicast->DadState == IpDadStatePreferred)) count += 1; } } } if (count == 0) { *results = NULL; *results_count = 0; GNUNET_free (pAddresses); GNUNET_free_non_null (interfaces4); GNUNET_free_non_null (interfaces6); return GNUNET_OK; } *results = (struct EnumNICs3_results *) GNUNET_malloc ( sizeof (struct EnumNICs3_results) * count); *results_count = count; count = 0; for (pCurrentAddress = pAddresses; pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next) { struct EnumNICs3_results *r; IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL; if (pCurrentAddress->OperStatus != IfOperStatusUp) continue; for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL; unicast = unicast->Next) { int i, j; int mask_length = -1; char dst[INET6_ADDRSTRLEN + 1]; if ((unicast->Address.lpSockaddr->sa_family != AF_INET && unicast->Address.lpSockaddr->sa_family != AF_INET6) || (unicast->DadState != IpDadStateDeprecated && unicast->DadState != IpDadStatePreferred)) continue; r = &(*results)[count]; r->flags = 0; if (pCurrentAddress->IfIndex > 0 && pCurrentAddress->IfIndex == best_interface && unicast->Address.lpSockaddr->sa_family == AF_INET) r->is_default = 1; else if (pCurrentAddress->Ipv6IfIndex > 0 && pCurrentAddress->Ipv6IfIndex == best_interface6 && unicast->Address.lpSockaddr->sa_family == AF_INET6) r->is_default = 1; else r->is_default = 0; /* Don't choose default interface twice */ if (r->is_default) best_interface = best_interface6 = 0; if (!use_enum2) { memcpy (&r->address, unicast->Address.lpSockaddr, unicast->Address.iSockaddrLength); memset (&r->mask, 0, sizeof (struct sockaddr)); mask_length = ((IP_ADAPTER_UNICAST_ADDRESS_VISTA *) unicast)-> OnLinkPrefixLength; /* OnLinkPrefixLength is the number of leading 1s in the mask. * OnLinkPrefixLength is available on Vista and later (hence use_enum2). */ if (unicast->Address.lpSockaddr->sa_family == AF_INET) { struct sockaddr_in *m = (struct sockaddr_in *) &r->mask; for (i = 0; i < mask_length; i++) ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8); } else if (unicast->Address.lpSockaddr->sa_family == AF_INET6) { struct sockaddr_in6 *m = (struct sockaddr_in6 *) &r->mask; struct sockaddr_in6 *b = (struct sockaddr_in6 *) &r->broadcast; for (i = 0; i < mask_length; i++) ((unsigned char *) &m->sin6_addr)[i / 8] |= 0x80 >> (i % 8); memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength); for (i = mask_length; i < 128; i++) ((unsigned char *) &b->sin6_addr)[i / 8] |= 0x80 >> (i % 8); } r->flags |= ENUMNICS3_MASK_OK; } else { int found = 0; if (unicast->Address.lpSockaddr->sa_family == AF_INET) { for (i = 0; !found && i < interfaces4_len / sizeof (INTERFACE_INFO); i++) { struct sockaddr_in *m = (struct sockaddr_in *) &r->mask; if (memcpy (&interfaces4[i].iiAddress.Address, unicast->Address.lpSockaddr, unicast->Address.iSockaddrLength) != 0) continue; found = 1; memcpy (&r->address, &interfaces4[i].iiAddress.Address, sizeof (struct sockaddr_in)); memcpy (&r->mask, &interfaces4[i].iiNetmask.Address, sizeof (struct sockaddr_in)); for (mask_length = 0; ((unsigned char *) &m->sin_addr)[mask_length / 8] & 0x80 >> (mask_length % 8); mask_length++) { } r->flags |= ENUMNICS3_MASK_OK; } } else if (unicast->Address.lpSockaddr->sa_family == AF_INET6) { for (i = 0; interfaces6 != NULL && !found && i < interfaces6->iAddressCount; i++) { if (memcpy (interfaces6->Address[i].lpSockaddr, unicast->Address.lpSockaddr, unicast->Address.iSockaddrLength) != 0) continue; found = 1; memcpy (&r->address, interfaces6->Address[i].lpSockaddr, sizeof (struct sockaddr_in6)); /* TODO: Find a way to reliably get network mask for IPv6 on XP */ memset (&r->mask, 0, sizeof (struct sockaddr)); r->flags &= ~ENUMNICS3_MASK_OK; } } if (!found) { DebugBreak (); } } if (unicast->Address.lpSockaddr->sa_family == AF_INET) { struct sockaddr_in *m = (struct sockaddr_in *) &r->mask; struct sockaddr_in *a = (struct sockaddr_in *) &r->address; /* copy address to broadcast, then flip all the trailing bits not * falling under netmask to 1, * so we get, 192.168.0.255 from, say, 192.168.0.43 with mask == 24. */ memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength); for (i = mask_length; i < 32; i++) ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8); r->flags |= ENUMNICS3_BCAST_OK; r->addr_size = sizeof (struct sockaddr_in); inet_ntop (AF_INET, &a->sin_addr, dst, INET_ADDRSTRLEN); } else if (unicast->Address.lpSockaddr->sa_family == AF_INET6) { struct sockaddr_in6 *a = (struct sockaddr_in6 *) &r->address; /* for IPv6 broadcast is not defined, zero it down */ memset (&r->broadcast, 0, sizeof (struct sockaddr)); r->flags &= ~ENUMNICS3_BCAST_OK; r->addr_size = sizeof (struct sockaddr_in6); inet_ntop (AF_INET6, &a->sin6_addr, dst, INET6_ADDRSTRLEN); } i = 0; i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0, "%S (%s", pCurrentAddress->FriendlyName, dst); for (j = 0; j < pCurrentAddress->PhysicalAddressLength; j++) i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0, "%s%02X",j > 0 ? ":" : " - ", pCurrentAddress->PhysicalAddress[j]); i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0, ")"); r->pretty_name[1000] = '\0'; count += 1; } } if (use_enum2) { GNUNET_free_non_null (interfaces4); GNUNET_free_non_null (interfaces6); } GNUNET_free (pAddresses); return GNUNET_OK; } void EnumNICs3_free (struct EnumNICs3_results *r) { GNUNET_free_non_null (r); } /** * Lists all network interfaces in a combo box * Used by the basic GTK configurator * * @param callback function to call for each NIC * @param callback_cls closure for callback */ int ListNICs (void (*callback) (void *, const char *, int), void * callback_cls) { int r; int i; struct EnumNICs3_results *results = NULL; int results_count; r = EnumNICs3 (&results, &results_count); if (r != GNUNET_OK) return GNUNET_NO; for (i = 0; i < results_count; i++) callback (callback_cls, results[i].pretty_name, results[i].is_default); GNUNET_free_non_null (results); return GNUNET_YES; } /** * @brief Installs the Windows service * @param servicename name of the service as diplayed by the SCM * @param application path to the application binary * @param username the name of the service's user account * @returns 0 on success * 1 if the Windows version doesn't support services * 2 if the SCM could not be opened * 3 if the service could not be created */ int InstallAsService(char *servicename, char *application, char *username) { SC_HANDLE hManager, hService; char szEXE[_MAX_PATH + 17] = "\""; char *user = NULL; if (! GNOpenSCManager) return 1; plibc_conv_to_win_path(application, szEXE + 1); strcat(szEXE, "\" --win-service"); hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE); if (! hManager) return 2; if (username) { user = (char *) malloc(strlen(username) + 3); sprintf(user, ".\\%s", username); } hService = GNCreateService(hManager, (LPCTSTR) servicename, (LPCTSTR) servicename, 0, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, (LPCTSTR) szEXE, NULL, NULL, NULL, (LPCTSTR) user, (LPCTSTR) username); if (user) free(user); if (! hService) return 3; GNCloseServiceHandle(hService); return 0; } /** * @brief Uninstall Windows service * @param servicename name of the service to delete * @returns 0 on success * 1 if the Windows version doesn't support services * 2 if the SCM could not be openend * 3 if the service cannot be accessed * 4 if the service cannot be deleted */ int UninstallService(char *servicename) { SC_HANDLE hManager, hService; if (! GNOpenSCManager) return 1; hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); if (! hManager) return 2; if (! (hService = GNOpenService(hManager, (LPCTSTR) servicename, DELETE))) if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST) return 3; else goto closeSCM; if (! GNDeleteService(hService)) if (GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE) return 4; closeSCM: GNCloseServiceHandle(hService); return 0; } /** * @author Scott Field, Microsoft * @see http://support.microsoft.com/?scid=kb;en-us;132958 * @date 12-Jul-95 */ void _InitLsaString(PLSA_UNICODE_STRING LsaString, LPWSTR String) { DWORD StringLength; if(String == NULL) { LsaString->Buffer = NULL; LsaString->Length = 0; LsaString->MaximumLength = 0; return; } StringLength = wcslen(String); LsaString->Buffer = String; LsaString->Length = (USHORT) StringLength *sizeof(WCHAR); LsaString->MaximumLength = (USHORT) (StringLength + 1) * sizeof(WCHAR); } /** * @author Scott Field, Microsoft * @see http://support.microsoft.com/?scid=kb;en-us;132958 * @date 12-Jul-95 */ NTSTATUS _OpenPolicy(LPWSTR ServerName, DWORD DesiredAccess, PLSA_HANDLE PolicyHandle) { LSA_OBJECT_ATTRIBUTES ObjectAttributes; LSA_UNICODE_STRING ServerString; PLSA_UNICODE_STRING Server = NULL; /* Always initialize the object attributes to all zeroes. */ ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes)); if(ServerName != NULL) { /* Make a LSA_UNICODE_STRING out of the LPWSTR passed in */ _InitLsaString(&ServerString, ServerName); Server = &ServerString; } /* Attempt to open the policy. */ return GNLsaOpenPolicy(Server, &ObjectAttributes, DesiredAccess, PolicyHandle); } /** * @brief Obtain a SID representing the supplied account on the supplied system * @return TRUE on success, FALSE on failure * @author Scott Field, Microsoft * @date 12-Jul-95 * @remarks A buffer is allocated which contains the SID representing the * supplied account. This buffer should be freed when it is no longer * needed by calling\n * HeapFree(GetProcessHeap(), 0, buffer) * @remarks Call GetLastError() to obtain extended error information. * @see http://support.microsoft.com/?scid=kb;en-us;132958 */ BOOL _GetAccountSid(LPCTSTR SystemName, LPCTSTR AccountName, PSID * Sid) { LPTSTR ReferencedDomain = NULL; DWORD cbSid = 128; /* initial allocation attempt */ DWORD cchReferencedDomain = 16; /* initial allocation size */ SID_NAME_USE peUse; BOOL bSuccess = FALSE; /* assume this function will fail */ /* initial memory allocations */ if ((*Sid = HeapAlloc (GetProcessHeap (), 0, cbSid)) == NULL) return FALSE; if ((ReferencedDomain = (LPTSTR) HeapAlloc (GetProcessHeap (), 0, cchReferencedDomain * sizeof (TCHAR))) == NULL) return FALSE; /* Obtain the SID of the specified account on the specified system. */ while (!GNLookupAccountName(SystemName, /* machine to lookup account on */ AccountName, /* account to lookup */ *Sid, /* SID of interest */ &cbSid, /* size of SID */ ReferencedDomain, /* domain account was found on */ &cchReferencedDomain, &peUse)) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { /* reallocate memory */ if ((*Sid = HeapReAlloc (GetProcessHeap (), 0, *Sid, cbSid)) == NULL) return FALSE; if ((ReferencedDomain = (LPTSTR) HeapReAlloc (GetProcessHeap (), 0, ReferencedDomain, cchReferencedDomain * sizeof (TCHAR))) == NULL) return FALSE; } else goto end; } /* Indicate success. */ bSuccess = TRUE; end: /* Cleanup and indicate failure, if appropriate. */ HeapFree (GetProcessHeap (), 0, ReferencedDomain); if (!bSuccess) { if (*Sid != NULL) { HeapFree (GetProcessHeap (), 0, *Sid); *Sid = NULL; } } return bSuccess; } /** * @author Scott Field, Microsoft * @see http://support.microsoft.com/?scid=kb;en-us;132958 * @date 12-Jul-95 */ NTSTATUS _SetPrivilegeOnAccount(LSA_HANDLE PolicyHandle,/* open policy handle */ PSID AccountSid, /* SID to grant privilege to */ LPWSTR PrivilegeName, /* privilege to grant (Unicode) */ BOOL bEnable /* enable or disable */ ) { LSA_UNICODE_STRING PrivilegeString; /* Create a LSA_UNICODE_STRING for the privilege name. */ _InitLsaString(&PrivilegeString, PrivilegeName); /* grant or revoke the privilege, accordingly */ if(bEnable) { NTSTATUS i; i = GNLsaAddAccountRights(PolicyHandle, /* open policy handle */ AccountSid, /* target SID */ &PrivilegeString, /* privileges */ 1 /* privilege count */ ); } else { return GNLsaRemoveAccountRights(PolicyHandle, /* open policy handle */ AccountSid, /* target SID */ FALSE, /* do not disable all rights */ &PrivilegeString, /* privileges */ 1 /* privilege count */ ); } } /** * @brief Create a Windows service account * @return 0 on success, > 0 otherwise * @param pszName the name of the account * @param pszDesc description of the account */ int CreateServiceAccount(const char *pszName, const char *pszDesc) { USER_INFO_1 ui; USER_INFO_1008 ui2; NET_API_STATUS nStatus; wchar_t wszName[MAX_NAME_LENGTH], wszDesc[MAX_NAME_LENGTH]; DWORD dwErr; LSA_HANDLE hPolicy; PSID pSID; if (! GNNetUserAdd) return 1; mbstowcs(wszName, pszName, strlen(pszName) + 1); mbstowcs(wszDesc, pszDesc, strlen(pszDesc) + 1); memset(&ui, 0, sizeof(ui)); ui.usri1_name = wszName; ui.usri1_password = wszName; /* account is locked anyway */ ui.usri1_priv = USER_PRIV_USER; ui.usri1_comment = wszDesc; ui.usri1_flags = UF_SCRIPT; nStatus = GNNetUserAdd(NULL, 1, (LPBYTE)&ui, NULL); if (nStatus != NERR_Success && nStatus != NERR_UserExists) return 2; ui2.usri1008_flags = UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD; GNNetUserSetInfo(NULL, wszName, 1008, (LPBYTE)&ui2, NULL); if (_OpenPolicy(NULL, POLICY_ALL_ACCESS, &hPolicy) != STATUS_SUCCESS) return 3; _GetAccountSid(NULL, (LPCTSTR) pszName, &pSID); if (_SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeServiceLogonRight", TRUE) != STATUS_SUCCESS) return 4; _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyInteractiveLogonRight", TRUE); _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyBatchLogonRight", TRUE); _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyNetworkLogonRight", TRUE); GNLsaClose(hPolicy); return 0; } /** * @brief Grant permission to a file * @param lpszFileName the name of the file or directory * @param lpszAccountName the user account * @param dwAccessMask the desired access (e.g. GENERIC_ALL) * @return TRUE on success * @remark based on http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q102102& */ BOOL AddPathAccessRights(char *lpszFileName, char *lpszAccountName, DWORD dwAccessMask) { /* SID variables. */ SID_NAME_USE snuType; TCHAR * szDomain = NULL; DWORD cbDomain = 0; LPVOID pUserSID = NULL; DWORD cbUserSID = 0; /* File SD variables. */ PSECURITY_DESCRIPTOR pFileSD = NULL; DWORD cbFileSD = 0; /* New SD variables. */ SECURITY_DESCRIPTOR newSD; /* ACL variables. */ PACL pACL = NULL; BOOL fDaclPresent; BOOL fDaclDefaulted; ACL_SIZE_INFORMATION AclInfo; /* New ACL variables. */ PACL pNewACL = NULL; DWORD cbNewACL = 0; /* Temporary ACE. */ LPVOID pTempAce = NULL; UINT CurrentAceIndex = 0; UINT newAceIndex = 0; /* Assume function will fail. */ BOOL fResult = FALSE; BOOL fAPISuccess; SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION; /** * STEP 1: Get SID of the account name specified. */ fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName, pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType); /* API should have failed with insufficient buffer. */ if (fAPISuccess) goto end; else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { goto end; } pUserSID = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbUserSID); if (!pUserSID) { goto end; } szDomain = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDomain * sizeof(TCHAR)); if (!szDomain) { goto end; } fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName, pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType); if (!fAPISuccess) { goto end; } /** * STEP 2: Get security descriptor (SD) of the file specified. */ fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName, secInfo, pFileSD, 0, &cbFileSD); /* API should have failed with insufficient buffer. */ if (fAPISuccess) goto end; else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { goto end; } pFileSD = (PSECURITY_DESCRIPTOR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbFileSD); if (!pFileSD) { goto end; } fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName, secInfo, pFileSD, cbFileSD, &cbFileSD); if (!fAPISuccess) { goto end; } /** * STEP 3: Initialize new SD. */ if (!GNInitializeSecurityDescriptor(&newSD, SECURITY_DESCRIPTOR_REVISION)) { goto end; } /** * STEP 4: Get DACL from the old SD. */ if (!GNGetSecurityDescriptorDacl(pFileSD, &fDaclPresent, &pACL, &fDaclDefaulted)) { goto end; } /** * STEP 5: Get size information for DACL. */ AclInfo.AceCount = 0; // Assume NULL DACL. AclInfo.AclBytesFree = 0; AclInfo.AclBytesInUse = sizeof(ACL); if (pACL == NULL) fDaclPresent = FALSE; /* If not NULL DACL, gather size information from DACL. */ if (fDaclPresent) { if (!GNGetAclInformation(pACL, &AclInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) { goto end; } } /** * STEP 6: Compute size needed for the new ACL. */ cbNewACL = AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pUserSID) - sizeof(DWORD); /** * STEP 7: Allocate memory for new ACL. */ pNewACL = (PACL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNewACL); if (!pNewACL) { goto end; } /** * STEP 8: Initialize the new ACL. */ if (!GNInitializeAcl(pNewACL, cbNewACL, ACL_REVISION2)) { goto end; } /** * STEP 9 If DACL is present, copy all the ACEs from the old DACL * to the new DACL. * * The following code assumes that the old DACL is * already in Windows 2000 preferred order. To conform * to the new Windows 2000 preferred order, first we will * copy all non-inherited ACEs from the old DACL to the * new DACL, irrespective of the ACE type. */ newAceIndex = 0; if (fDaclPresent && AclInfo.AceCount) { for (CurrentAceIndex = 0; CurrentAceIndex < AclInfo.AceCount; CurrentAceIndex++) { /** * TEP 10: Get an ACE. */ if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) { goto end; } /** * STEP 11: Check if it is a non-inherited ACE. * If it is an inherited ACE, break from the loop so * that the new access allowed non-inherited ACE can * be added in the correct position, immediately after * all non-inherited ACEs. */ if (((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags & INHERITED_ACE) break; /** * STEP 12: Skip adding the ACE, if the SID matches * with the account specified, as we are going to * add an access allowed ACE with a different access * mask. */ if (GNEqualSid(pUserSID, &(((ACCESS_ALLOWED_ACE *)pTempAce)->SidStart))) continue; /** * STEP 13: Add the ACE to the new ACL. */ if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce, ((PACE_HEADER) pTempAce)->AceSize)) { goto end; } newAceIndex++; } } /** * STEP 14: Add the access-allowed ACE to the new DACL. * The new ACE added here will be in the correct position, * immediately after all existing non-inherited ACEs. */ if (!GNAddAccessAllowedAce(pNewACL, ACL_REVISION2, dwAccessMask, pUserSID)) { goto end; } /** * STEP 14.5: Make new ACE inheritable */ if (!GetAce(pNewACL, newAceIndex, &pTempAce)) goto end; ((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags |= (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE); /** * STEP 15: To conform to the new Windows 2000 preferred order, * we will now copy the rest of inherited ACEs from the * old DACL to the new DACL. */ if (fDaclPresent && AclInfo.AceCount) { for (; CurrentAceIndex < AclInfo.AceCount; CurrentAceIndex++) { /** * STEP 16: Get an ACE. */ if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) { goto end; } /** * STEP 17: Add the ACE to the new ACL. */ if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce, ((PACE_HEADER) pTempAce)->AceSize)) { goto end; } } } /** * STEP 18: Set permissions */ if (GNSetNamedSecurityInfo((LPTSTR) lpszFileName, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, pNewACL, NULL) != ERROR_SUCCESS) { goto end; } fResult = TRUE; end: /** * STEP 19: Free allocated memory */ if (pUserSID) HeapFree(GetProcessHeap(), 0, pUserSID); if (szDomain) HeapFree(GetProcessHeap(), 0, szDomain); if (pFileSD) HeapFree(GetProcessHeap(), 0, pFileSD); if (pNewACL) HeapFree(GetProcessHeap(), 0, pNewACL); return fResult; } char *winErrorStr(const char *prefix, int dwErr) { char *err, *ret; int mem; if (! FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, (DWORD) dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &err, 0, NULL )) { err = (char *) LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT, 1); } mem = strlen(err) + strlen(prefix) + 20; ret = (char *) malloc(mem); snprintf(ret, mem, "%s: %s (#%u)", prefix, err, dwErr); LocalFree(err); return ret; } } /* extern "C" */ #endif gnunet-0.9.3/src/util/test_crypto_crc.c0000644000175000017500000003343311760502551015072 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2006 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. For the actual CRC code: Copyright abandoned; this code is in the public domain. Provided to GNUnet by peter@horizon.com */ /** * @file util/test_crypto_crc.c * @brief testcase for crypto_crc.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_crypto_lib.h" static int expected[] = { -1223996378, 929797997, -1048047323, 1791081351, -425765913, 2138425902, 82584863, 1939615314, 1806463044, -1505003452, 1878277636, -997353517, 201238705, 1723258694, -1107452366, -344562561, -1102247383, 1973035265, 715213337, -1886586005, 2021214515, -1387332962, 593019378, -571088044, 1412577760, 412164558, -1626111170, 1556494863, -289796528, -850404775, 2066714587, -911838105, -1426027382, 499684507, -835420055, 1817119454, -1221795958, 1516966784, -1038806877, -2115880691, 532627620, 1984437415, -396341583, -1345366324, -590766745, -1801923449, 1752427988, -386896390, 453906317, 1552589433, -858925718, 1160445643, -740188079, -486609040, 1102529269, -515846212, -1614217202, 1572162207, 943558923, -467330358, -1870764193, 1477005328, -793029208, -888983175, -696956020, 842706021, 1642390067, -805889494, 1284862057, 1562545388, 2091626273, 1852404553, -2076508101, 370903003, 1186422975, 1936085227, 769358463, 180401058, 2032612572, -105461719, -1119935472, 617249831, 1169304728, 1771205256, -2042554284, 653270859, -918610713, 336081663, -913685370, 1962213744, -505406126, -838622649, -1141518710, 893143582, -1330296611, 122119483, 1111564496, 688811976, 1016241049, -1803438473, 359630107, 1034798954, -581359286, 1590946527, -389997034, 2020318460, 1695967527, -464069727, -862641495, -1405012109, -771244841, 738226150, -1035328134, -933945474, 1254965774, 1661863830, -884127998, 1800460481, 814702567, -1214068102, -541120421, 1898656429, -236825530, 1505866267, 1252462132, -981007520, 1502096471, -2134644056, 483221797, 1276403836, 541133290, -1234093967, 350748780, 257941070, 1030457090, 434988890, -1098135432, -1000556640, -577128022, 644806294, -787536281, -1288346343, 998079404, 1259353935, 955771631, -958377466, 1746756252, 451579658, 1913409243, -952026299, -1556035958, -830279881, 834744289, -1878491428, 700000962, -1027245802, 1393574384, -1260409147, -841420884, 892132797, 1494730226, -1649181766, 1651097838, -1041807403, -1916675721, -1324525963, 157405899, -655788033, -1943555237, -79747022, 339721623, -138341083, 1111902411, -435322914, -533294200, -190220608, -1718346014, -1631301894, 1706265243, 745533899, 1351941230, 1803009594, -1218191958, 1467751062, 84368433, -711251880, 1699423788, -768792716, 846639904, 2103267723, -2095288070, -440571408, -362144485, 2020468971, 352105963, -849211036, -1272592429, 1743440467, 2020667861, -1649992312, 172682343, 816705364, -1990206923, 902689869, -298510060, 164207498, 190378213, 242531543, 113383268, 304810777, -1081099373, 819221134, -1100982926, -855941239, 1091308887, -934548124, 520508733, -1381763773, -491593287, -2143492665, 700894653, -2049034808, -160942046, -2009323577, 1464245054, 1584746011, -768646852, -993282698, 1265838699, -1873820824, 575704373, -986682955, 1270688416, 88587481, -1723991633, -409928242, 866669946, -483811323, -181759253, -963525431, -1686612238, -1663460076, -1128449775, -1368922329, 122318131, 795862385, 528576131, -19927090, 1369299478, 1285665642, -738964611, 1328292127, 552041252, -1431494354, -1205275362, 42768297, -1329537238, -449177266, 943925221, 987016465, -945138414, -270064876, 1650366626, -369252552, 582030210, -1229235374, 147901387, -517510506, -1609742888, -1086838308, 1391998445, -313975512, -613392078, 855706229, 1475706341, -1112105406, 2032001400, 1565777625, 2030937777, 435522421, 1823527907, -691390605, -827253664, 1057171580, -314146639, -630099999, -1347514552, 478716232, -1533658804, -1425371979, 761987780, 1560243817, -1945893959, 1205759225, -959343783, -576742354, -154125407, -1158108776, 1183788580, 1354198127, -1534207721, -823991517, -170534462, -912524170, 1858513573, 467072185, 2091040157, -1765027018, -1659401643, -1173890143, -1912754057, -84568053, 2010781784, -921970156, 944508352, -922040609, 1055102010, 1018688871, -1186761311, -2012263648, 1311654161, 277659086, 2029602288, 1127061510, 1029452642, 285677123, -188521091, -641039012, 653836416, -805916340, -1644860596, 1352872213, 691634876, -1477113308, -748430369, 1030697363, -2007864449, -1196662616, 1313997192, 177342476, -566676450, -1118618118, 1697953104, 344671484, -1489783116, -889507873, 1259591310, -716567168, 2116447062, 324368527, 1789366816, 1558930442, 1950250221, -785460151, 1174714258, -430047304, -859487565, -580633932, 607732845, -1128150220, 1544355315, 1460298016, -1771194297, 1215703690, 277231808, -416020628, -418936577, -1724839216, 404731389, 1058730508, -1508366681, 229883053, -572310243, 1883189553, 931286849, 1659300867, -94236383, -241524462, 548020458, -302406981, 579986475, 73468197, -984957614, 1554382245, 2084807492, -1456802798, -1105192593, 629440327, -16313961, -2102585261, 1873675206, 161035128, 1497033351, 1990150811, -499405222, 304019482, 41935663, -805987182, -571699268, 1748462913, 2096239823, -116359807, -1871127553, -1074832534, -1558866192, 231353861, 2122854560, -2102323721, -281462361, -343403210, -673268171, 1776058383, 1581561150, 2059580579, 768848632, 1347190372, -1701705879, 245282007, -563267886, -592558289, 1662399958, 1390406821, -1522485580, -706446863, 2069516289, -301855859, -778346387, -1454093198, 1249083752, -1760506745, 262193320, 630751125, -1495939124, -29980580, -1989626563, 659039376, -329477132, -1003507166, -1322549020, 358606508, -2052572059, 1848014133, 1826958586, -1004948862, -1775370541, 2134177912, -1739214473, 1892700918, 926629675, -1042761322, 2020075900, 606370962, -1256609305, 117577265, -586848924, 191368285, 1653535275, -1329269701, -375879127, -1089901406, 1206489978, 534223924, -1042752982, -1178316881, -445594741, -1501682065, -1598136839, -467688289, 750784023, 1781080461, 1729380226, 16906088, 862168532, -2037752683, 1455274138, -1491220107, 1058323960, 1711530558, 1355062750, 227640096, 396568027, -173579098, -408975801, -993618329, -1470751562, 371076647, 209563718, 2015405719, -723460281, -1423934420, -2089643958, 353260489, 2084264341, -792676687, 701391030, -1440658244, 1479321011, 1907822880, 1232524257, -256712289, 401077577, 621808069, 868263613, 1244930119, 2020996902, 117483907, 1341376744, -1936988014, -445200547, -843751811, -435291191, 1041695743, 476132726, -1226874735, -1436046747, -297047422, 1739645396, 1948680937, -718144374, 1141983978, 1673650568, -197244350, 1604464002, 1424069853, -485626505, 1708710014, -849136541, 1573778103, 530360999, 1777767203, 1376958336, -1088364352, 1826167753, 742735448, -1386211659, -1991323164, -444115655, -443055378, -1586901006, -1741686587, 1925818034, -2118916824, 803890920, -1481793154, 992278937, 1302616410, 444517030, 1393144770, -2025632978, 1902300505, -1683582981, 800654133, 873850324, -619580878, -2002070410, -2024936385, 1978986634, 2012024264, 675768872, 389435615, -867217540, 231209167, -303917385, 1445676969, -1385982721, 1310476490, 580273453, -160600202, -1330895874, 487110497, 1124384798, 227637416, -1829783306, 1014818058, -1336870683, -1042199518, -468525587, -1186267363, -472843891, 1215617600, -2056648329, -873216891, 156780951, -1883246047, -842549253, -717684332, 760531638, 1074787431, 786267513, 814031289, -561255343, -110302255, -1837376592, 989669060, -81350614, 546038730, 222899882, 1298746805, 1791615733, 1565630269, 1516024174, 421691479, 1860326051, -1973359550, 1854393443, -1401468528, -158562295, 1509929255, -124024738, -462937489, 259890715, -1515121317, -289511197, -913738664, 698079062, -1631229382, -507275144, 1897739663, -1118192766, -1687033399, 61405556, -1913606579, -473308896, -259107170, -576944609, -1689355510, 322156799, 545090192, 127425176, -1815211748, -2070235628, -1172529316, 599259550, -910906653, 1797380363, -938649427, 142991392, 504559631, 1208867355, -807699247, -616021271, -254935281, -57151221, -1095534993, 1998380318, 1772459584, 713271407, -1197898266, 808881935, -308133481, -1314455137, 284321772, -743117625, -1622364240, -1667535152, 118713606, 1053615347, -2072876023, -178189072, -828319551, 2047304928, -1311435786, -1970672907, -747972100, 86806159, -436088421, 1464645587, 735840899, 32600466, -190473426, -735703440, 482872155, 475662392, -713681085, 1424078728, -150668609, -1137197868, -1682762563, -48035649, 1143959866, -1542015129, 284920371, -1587695586, -625236551, -753893357, -433976266, -1329796037, -1636712478, 1686783454, 27839146, 1748631474, -879528256, 2057796026, 773734654, 112269667, -2011541314, 1517797297, -1943171794, 268166111, -1037010413, -1945824504, -1672323792, 306260758, -692968628, -701704965, -462980996, 939188824, 553289792, 1790245000, 2093793129, -658085781, -186055037, -2130433650, -1013235433, 1190870089, -2126586963, -1509655742, -1291895256, -1427857845, 309538950, 388316741, 259659733, -1895092434, 110126220, -170175575, -419430224, -696234084, -832170948, -353431720, -797675726, -1644136054, 715163272, -1305904349, -145786463, -99586244, -695450446, -871327102, -725496060, 952863853, -688441983, -1729929460, -103732092, 1059054528, 568873585, -982665223, -128672783, 2099418320, 1508239336, -2089480835, -390935727, 664306522, -1607364342, -163246802, -1121295140, -128375779, -615694409, -2079391797, 760542037, 677761593, -750117849, -1060525080, 2128437080, 525250908, 1987657172, 2032530557, -2011247936, 1942775263, 1681562788, 688229491, -803856505, 684707948, 1308988965, 1455480037, 790659611, 1557968784, -383203149, -361510986, -742575828, 558837193, -1214977424, 1253274105, -119513513, -993964385, -33438767, -177452803, 1186928041, -2073533871, 1188528559, 1896514695, 1200128512, 1930588755, -1914141443, 1534656032, -1192989829, -1848274656, -220848455, 1001806509, 1298797392, 1533031884, -1912322446, 1705583815, 1568094347, -1397640627, 807828512, -1852996497, -1529733505, -1575634185, -1280270160, -1567624159, -1861904922, 1276738579, 1163432999, 626879833, 316942006, -1871138342, 1341039701, 1595907877, 1950911580, 1634717748, 1071476055, -809354290, -1161553341, -2081621710, -2085557943, 19360224, 322135580, -698485151, 1267663094, -233890834, -126361189, -1426257522, 1094007921, 500179855, -283548002, -1678987343, 1946999943, 1489410849, 2089571262, 1430799093, 1961848046, -99462663, -552833264, 1168700661, -1783882181, 2089196401, 1092839657, 914488673, 80263859, -2140947098, -726384741, -1022448237, 2113887675, 1485770846, -112922517, 1995461466, 774613726, 944068011, 1521975359, 289086919, -386920759, -1960513175, 358460021, -238698524, -1913640563, -1000324864, 1731755224, -1271586254, -1917469655, 2134162829, -828097534, -1089292503, -1514835999, 1682931514, -482307169, 2110243841, 115744834, -2038340170, 65889188, -539445712, -1713206408, -1842396726, -1659545588, -909558923, 860164922, 1328713040, 1044007120, -2103807103, -1073990344, -1312783785, -884980824, -705318011, -1263408788, -2032228692, -1732844111, -1813827156, 1462566279, 1179250845, 1732421772, 604429013, -92284336, -1192166516, 304654351, 1998552034, -1802461575, -1802704071, -1704833934, -976264396, 1005840702, 2108843914, 1363909309, 843040834, -1039625241, 1285007226, 91610001, 418426329, 678422358, -945360697, -440008081, -1053091357, 425719777, -1372778676, 591912153, 1229089037, -56663158, 2140251400, 830257037, 763914157, 175610373, -2105655963, -1040826150, 1174443038, 339290593, 346618443, -180504100, -1363190515, 210620018, 1028894425, 573529714, 698460117, 136999397, 1015621712, -1401813739, -297990684, -1820934845, -1299093313, 1299361369, -366522415, 91527707, 1113466178, -956229484, 22204763, -1394374195, -1912666711, -1453789804, 1613408399, -169509567, 1350520309, 540761213, -2086682848, 1095131491, -812787911, 1860108594, -1121378737, -1667252487, -486084366, 166519760, 1609891237, 728218405, 291075010, 646168382, 108462277, -1616661910, 1016600360, 2099958568, 27934736, 183821196, 13660496, -805589719, 936068730, -439037934, 1414622584, 215845485, -1352304469, -1817427526, -1318710977, -110207199, 228524335, 1704746590, 998293651, -1521016702, -641956531, -2089808167, 2094404052, -1446381065, -662186492, 1670154584, 9637833, 493925511, 660047318, 1197537103, 1696017374, -204994399, -1104145601, -852330465, -1936369658, -829716674, -1255255217, 1264013799, 1642611772, -652520861, 777247164, 2028895987, -1424241853, -54367829, -1940161761, -1802831079, -449405299, 838242661, -323055438, 794295411, -136989378, -446686673, -421252799, -16777216, }; int main (int argc, char *argv[]) { char buf[1024]; int i; GNUNET_log_setup ("test-crypto-crc", "WARNING", NULL); for (i = 0; i < 1024; i++) buf[i] = (char) i; for (i = 0; i < 1024; i++) if (expected[i] != GNUNET_CRYPTO_crc32_n (&buf[i], 1024 - i)) return 1; return 0; } gnunet-0.9.3/src/util/test_plugin_plug.c0000644000175000017500000000226311760502551015245 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_plugin_plug.c * @brief plugin for testing */ #include "platform.h" void * libgnunet_plugin_test_init (void *arg) { if (0 == strcmp (arg, "in")) return "Hello"; return NULL; } void * libgnunet_plugin_test_done (void *arg) { if (0 == strcmp (arg, "out")) return strdup ("World"); return NULL; } /* end of test_plugin_plug.c */ gnunet-0.9.3/src/util/test_server_with_client_unix.c0000644000175000017500000001236611760502551017667 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_server_with_client_unix.c * @brief tests for server.c and client.c, * specifically disconnect_notify, * client_get_address and receive_done (resume processing) */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_scheduler_lib.h" #include "gnunet_client_lib.h" #include "gnunet_server_lib.h" #include "gnunet_time_lib.h" #define VERBOSE GNUNET_NO #define MY_TYPE 128 static struct GNUNET_SERVER_Handle *server; static struct GNUNET_CLIENT_Connection *client; static struct GNUNET_CONFIGURATION_Handle *cfg; static int ok; static void send_done (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_SERVER_Client *argclient = cls; GNUNET_assert (ok == 3); ok++; GNUNET_SERVER_receive_done (argclient, GNUNET_OK); } static void recv_cb (void *cls, struct GNUNET_SERVER_Client *argclient, const struct GNUNET_MessageHeader *message) { switch (ok) { case 2: ok++; GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 50), &send_done, argclient); break; case 4: ok++; GNUNET_CLIENT_disconnect (client); GNUNET_SERVER_receive_done (argclient, GNUNET_OK); break; default: GNUNET_assert (0); } } static void clean_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_SERVER_destroy (server); server = NULL; GNUNET_CONFIGURATION_destroy (cfg); cfg = NULL; } /** * Functions with this signature are called whenever a client * is disconnected on the network level. * * @param cls closure * @param client identification of the client */ static void notify_disconnect (void *cls, struct GNUNET_SERVER_Client *client) { if (client == NULL) return; GNUNET_assert (ok == 5); ok = 0; GNUNET_SCHEDULER_add_now (&clean_up, NULL); } static size_t notify_ready (void *cls, size_t size, void *buf) { struct GNUNET_MessageHeader *msg; GNUNET_assert (size >= 256); GNUNET_assert (1 == ok); ok++; msg = buf; msg->type = htons (MY_TYPE); msg->size = htons (sizeof (struct GNUNET_MessageHeader)); msg++; msg->type = htons (MY_TYPE); msg->size = htons (sizeof (struct GNUNET_MessageHeader)); return 2 * sizeof (struct GNUNET_MessageHeader); } static struct GNUNET_SERVER_MessageHandler handlers[] = { {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)}, {NULL, NULL, 0, 0} }; static void task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct sockaddr_un un; const char *unixpath = "/tmp/testsock"; size_t slen = strlen (unixpath); struct sockaddr *sap[2]; socklen_t slens[2]; memset (&un, 0, sizeof (un)); un.sun_family = AF_UNIX; memcpy (un.sun_path, unixpath, slen); un.sun_path[slen] = '\0'; #if HAVE_SOCKADDR_IN_SIN_LEN un.sun_len = (u_char) sizeof (un); #endif #if LINUX un.sun_path[0] = '\0'; #endif sap[0] = (struct sockaddr *) &un; slens[0] = sizeof (un); sap[1] = NULL; slens[1] = 0; server = GNUNET_SERVER_create (NULL, NULL, sap, slens, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250), GNUNET_NO); GNUNET_assert (server != NULL); handlers[0].callback_cls = cls; GNUNET_SERVER_add_handlers (server, handlers); GNUNET_SERVER_disconnect_notify (server, ¬ify_disconnect, cls); cfg = GNUNET_CONFIGURATION_create (); GNUNET_CONFIGURATION_set_value_string (cfg, "test", "UNIXPATH", unixpath); GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", "localhost"); client = GNUNET_CLIENT_connect ("test", cfg); GNUNET_assert (client != NULL); GNUNET_CLIENT_notify_transmit_ready (client, 256, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250), GNUNET_NO, ¬ify_ready, NULL); } /** * Main method, starts scheduler with task1, * checks that "ok" is correct at the end. */ static int check () { ok = 1; GNUNET_SCHEDULER_run (&task, NULL); return ok; } int main (int argc, char *argv[]) { int ret = 0; GNUNET_log_setup ("test_server_with_client_unix", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret += check (); return ret; } /* end of test_server_with_client_unix.c */ gnunet-0.9.3/src/util/resolver_api.c0000644000175000017500000006153711760502551014364 00000000000000/* This file is part of GNUnet. (C) 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/resolver_api.c * @brief resolver for writing a tool * @author Christian Grothoff */ #include "platform.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_client_lib.h" #include "gnunet_container_lib.h" #include "gnunet_protocols.h" #include "gnunet_resolver_service.h" #include "gnunet_server_lib.h" #include "resolver.h" #define LOG(kind,...) GNUNET_log_from (kind, "resolver-api", __VA_ARGS__) #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "resolver-api", syscall) /** * Maximum supported length for a hostname */ #define MAX_HOSTNAME 1024 /** * Possible hostnames for "loopback". */ static const char *loopback[] = { "localhost", "ip6-localnet", NULL }; /** * Configuration. */ static const struct GNUNET_CONFIGURATION_Handle *resolver_cfg; /** * Our connection to the resolver service, created on-demand, but then * persists until error or shutdown. */ static struct GNUNET_CLIENT_Connection *client; /** * Head of DLL of requests. */ static struct GNUNET_RESOLVER_RequestHandle *req_head; /** * Tail of DLL of requests. */ static struct GNUNET_RESOLVER_RequestHandle *req_tail; /** * How long should we wait to reconnect? */ static struct GNUNET_TIME_Relative backoff; /** * Task for reconnecting. */ static GNUNET_SCHEDULER_TaskIdentifier r_task; /** * Task ID of shutdown task; only present while we have a * connection to the resolver service. */ static GNUNET_SCHEDULER_TaskIdentifier s_task; /** * Handle to a request given to the resolver. Can be used to cancel * the request prior to the timeout or successful execution. Also * used to track our internal state for the request. */ struct GNUNET_RESOLVER_RequestHandle { /** * Next entry in DLL of requests. */ struct GNUNET_RESOLVER_RequestHandle *next; /** * Previous entry in DLL of requests. */ struct GNUNET_RESOLVER_RequestHandle *prev; /** * Callback if this is an name resolution request, * otherwise NULL. */ GNUNET_RESOLVER_AddressCallback addr_callback; /** * Callback if this is a reverse lookup request, * otherwise NULL. */ GNUNET_RESOLVER_HostnameCallback name_callback; /** * Closure for the respective "callback". */ void *cls; /** * When should this request time out? */ struct GNUNET_TIME_Absolute timeout; /** * Task handle for numeric lookups. */ GNUNET_SCHEDULER_TaskIdentifier task; /** * Desired address family. */ int af; /** * Has this request been transmitted to the service? * GNUNET_YES if transmitted * GNUNET_YES if not transmitted * GNUNET_SYSERR when request was canceled */ int was_transmitted; /** * Did we add this request to the queue? */ int was_queued; /** * Desired direction (IP to name or name to IP) */ int direction; /** * GNUNET_YES if a response was received */ int received_response; /** * Length of the data that follows this struct. */ size_t data_len; }; /** * Check that the resolver service runs on localhost * (or equivalent). */ static void check_config () { char *hostname; unsigned int i; struct sockaddr_in v4; struct sockaddr_in6 v6; memset (&v4, 0, sizeof (v4)); v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK); v4.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN v4.sin_len = sizeof (v4); #endif memset (&v6, 0, sizeof (v6)); v6.sin6_family = AF_INET6; #if HAVE_SOCKADDR_IN_SIN_LEN v6.sin6_len = sizeof (v6); #endif if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (resolver_cfg, "resolver", "HOSTNAME", &hostname)) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Must specify `%s' for `%s' in configuration!\n"), "HOSTNAME", "resolver"); GNUNET_assert (0); } if ((1 != inet_pton (AF_INET, hostname, &v4)) || (1 != inet_pton (AF_INET6, hostname, &v6))) { GNUNET_free (hostname); return; } i = 0; while (loopback[i] != NULL) if (0 == strcasecmp (loopback[i++], hostname)) { GNUNET_free (hostname); return; } LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Must specify `%s' or numeric IP address for `%s' of `%s' in configuration!\n"), "localhost", "HOSTNAME", "resolver"); GNUNET_free (hostname); GNUNET_assert (0); } /** * Create the connection to the resolver service. * * @param cfg configuration to use */ void GNUNET_RESOLVER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) { GNUNET_assert (NULL != cfg); backoff = GNUNET_TIME_UNIT_MILLISECONDS; resolver_cfg = cfg; check_config (); } /** * Destroy the connection to the resolver service. */ void GNUNET_RESOLVER_disconnect () { GNUNET_assert (NULL == req_head); GNUNET_assert (NULL == req_tail); if (NULL != client) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from DNS service\n"); GNUNET_CLIENT_disconnect (client); client = NULL; } if (r_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (r_task); r_task = GNUNET_SCHEDULER_NO_TASK; } if (s_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (s_task); s_task = GNUNET_SCHEDULER_NO_TASK; } } /** * Convert IP address to string without DNS resolution. * * @param af address family * @param ip the address * @param ip_len number of bytes in ip * @return address as a string, NULL on error */ static char * no_resolve (int af, const void *ip, socklen_t ip_len) { char buf[INET6_ADDRSTRLEN]; switch (af) { case AF_INET: if (ip_len != sizeof (struct in_addr)) return NULL; if (NULL == inet_ntop (AF_INET, ip, buf, sizeof (buf))) { LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "inet_ntop"); return NULL; } break; case AF_INET6: if (ip_len != sizeof (struct in6_addr)) return NULL; if (NULL == inet_ntop (AF_INET6, ip, buf, sizeof (buf))) { LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "inet_ntop"); return NULL; } break; default: GNUNET_break (0); return NULL; } return GNUNET_strdup (buf); } /** * Adjust exponential back-off and reconnect to the service. */ static void reconnect (); /** * Process pending requests to the resolver. */ static void process_requests (); /** * Process response with a hostname for a DNS lookup. * * @param cls our "struct GNUNET_RESOLVER_RequestHandle" context * @param msg message with the hostname, NULL on error */ static void handle_response (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_RESOLVER_RequestHandle *rh = cls; uint16_t size; LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving response from DNS service\n"); if (msg == NULL) { char buf[INET6_ADDRSTRLEN]; if (NULL != rh->name_callback) LOG (GNUNET_ERROR_TYPE_INFO, _("Timeout trying to resolve IP address `%s'.\n"), inet_ntop (rh->af, (const void *) &rh[1], buf, sizeof(buf))); else LOG (GNUNET_ERROR_TYPE_INFO, _("Timeout trying to resolve hostname `%s'.\n"), (const char *) &rh[1]); /* check if request was canceled */ if (rh->was_transmitted != GNUNET_SYSERR) { if (NULL != rh->name_callback) { /* no reverse lookup was successful, return ip as string */ if (rh->received_response == GNUNET_NO) rh->name_callback (rh->cls, no_resolve (rh->af, &rh[1], rh->data_len)); /* at least one reverse lookup was successful */ else rh->name_callback (rh->cls, NULL); } if (NULL != rh->addr_callback) rh->addr_callback (rh->cls, NULL, 0); } GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh); GNUNET_free (rh); GNUNET_CLIENT_disconnect (client); client = NULL; reconnect (); return; } if (GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE != ntohs (msg->type)) { GNUNET_break (0); GNUNET_CLIENT_disconnect (client); client = NULL; reconnect (); return; } size = ntohs (msg->size); /* message contains not data, just header */ if (size == sizeof (struct GNUNET_MessageHeader)) { /* check if request was canceled */ if (rh->was_transmitted != GNUNET_SYSERR) { if (NULL != rh->name_callback) rh->name_callback (rh->cls, NULL); if (NULL != rh->addr_callback) rh->addr_callback (rh->cls, NULL, 0); } GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh); GNUNET_free (rh); process_requests (); return; } /* return reverse lookup results to caller */ if (NULL != rh->name_callback) { const char *hostname; hostname = (const char *) &msg[1]; if (hostname[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0') { GNUNET_break (0); if (rh->was_transmitted != GNUNET_SYSERR) rh->name_callback (rh->cls, NULL); GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh); GNUNET_free (rh); GNUNET_CLIENT_disconnect (client); client = NULL; reconnect (); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Resolver returns `%s' for IP `%s'.\n", hostname, GNUNET_a2s ((const void *) &rh[1], rh->data_len)); if (rh->was_transmitted != GNUNET_SYSERR) rh->name_callback (rh->cls, hostname); rh->received_response = GNUNET_YES; GNUNET_CLIENT_receive (client, &handle_response, rh, GNUNET_TIME_absolute_get_remaining (rh->timeout)); } /* return lookup results to caller */ if (NULL != rh->addr_callback) { struct sockaddr_in v4; struct sockaddr_in6 v6; const struct sockaddr *sa; socklen_t salen; const void *ip; size_t ip_len; ip = &msg[1]; ip_len = size - sizeof (struct GNUNET_MessageHeader); if (ip_len == sizeof (struct in_addr)) { memset (&v4, 0, sizeof (v4)); v4.sin_family = AF_INET; v4.sin_addr = *(struct in_addr*) ip; #if HAVE_SOCKADDR_IN_SIN_LEN v4.sin_len = sizeof (v4); #endif salen = sizeof (v4); sa = (const struct sockaddr *) &v4; } else if (ip_len == sizeof (struct in6_addr)) { memset (&v6, 0, sizeof (v6)); v6.sin6_family = AF_INET6; v6.sin6_addr = *(struct in6_addr*) ip; #if HAVE_SOCKADDR_IN_SIN_LEN v6.sin6_len = sizeof (v6); #endif salen = sizeof (v6); sa = (const struct sockaddr *) &v6; } else { GNUNET_break (0); if (rh->was_transmitted != GNUNET_SYSERR) rh->addr_callback (rh->cls, NULL, 0); GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh); GNUNET_free (rh); GNUNET_CLIENT_disconnect (client); client = NULL; reconnect (); return; } rh->addr_callback (rh->cls, sa, salen); GNUNET_CLIENT_receive (client, &handle_response, rh, GNUNET_TIME_absolute_get_remaining (rh->timeout)); } } /** * We've been asked to lookup the address for a hostname and were * given a valid numeric string. Perform the callbacks for the * numeric addresses. * * @param cls struct GNUNET_RESOLVER_RequestHandle for the request * @param tc unused scheduler context */ static void numeric_resolution (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_RESOLVER_RequestHandle *rh = cls; struct sockaddr_in v4; struct sockaddr_in6 v6; const char *hostname; memset (&v4, 0, sizeof (v4)); v4.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN v4.sin_len = sizeof (v4); #endif memset (&v6, 0, sizeof (v6)); v6.sin6_family = AF_INET6; #if HAVE_SOCKADDR_IN_SIN_LEN v6.sin6_len = sizeof (v6); #endif hostname = (const char *) &rh[1]; if (((rh->af == AF_UNSPEC) || (rh->af == AF_INET)) && (1 == inet_pton (AF_INET, hostname, &v4.sin_addr))) { rh->addr_callback (rh->cls, (const struct sockaddr *) &v4, sizeof (v4)); if ((rh->af == AF_UNSPEC) && (1 == inet_pton (AF_INET6, hostname, &v6.sin6_addr))) { /* this can happen on some systems IF "hostname" is "localhost" */ rh->addr_callback (rh->cls, (const struct sockaddr *) &v6, sizeof (v6)); } rh->addr_callback (rh->cls, NULL, 0); GNUNET_free (rh); return; } if (((rh->af == AF_UNSPEC) || (rh->af == AF_INET6)) && (1 == inet_pton (AF_INET6, hostname, &v6.sin6_addr))) { rh->addr_callback (rh->cls, (const struct sockaddr *) &v6, sizeof (v6)); rh->addr_callback (rh->cls, NULL, 0); GNUNET_free (rh); return; } /* why are we here? this task should not have been scheduled! */ GNUNET_assert (0); GNUNET_free (rh); } /** * We've been asked to lookup the address for a hostname and were * given a variant of "loopback". Perform the callbacks for the * respective loopback numeric addresses. * * @param cls struct GNUNET_RESOLVER_RequestHandle for the request * @param tc unused scheduler context */ static void loopback_resolution (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_RESOLVER_RequestHandle *rh = cls; struct sockaddr_in v4; struct sockaddr_in6 v6; memset (&v4, 0, sizeof (v4)); v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK); v4.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN v4.sin_len = sizeof (v4); #endif memset (&v6, 0, sizeof (v6)); v6.sin6_family = AF_INET6; #if HAVE_SOCKADDR_IN_SIN_LEN v6.sin6_len = sizeof (v6); #endif v6.sin6_addr = in6addr_loopback; switch (rh->af) { case AF_INET: rh->addr_callback (rh->cls, (const struct sockaddr *) &v4, sizeof (v4)); break; case AF_INET6: rh->addr_callback (rh->cls, (const struct sockaddr *) &v6, sizeof (v6)); break; case AF_UNSPEC: rh->addr_callback (rh->cls, (const struct sockaddr *) &v6, sizeof (v6)); rh->addr_callback (rh->cls, (const struct sockaddr *) &v4, sizeof (v4)); break; default: GNUNET_break (0); break; } rh->addr_callback (rh->cls, NULL, 0); GNUNET_free (rh); } /** * Task executed on system shutdown. */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { s_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_RESOLVER_disconnect (); } /** * Process pending requests to the resolver. */ static void process_requests () { struct GNUNET_RESOLVER_GetMessage *msg; char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN; struct GNUNET_RESOLVER_RequestHandle *rh; if (NULL == client) { reconnect (); return; } rh = req_head; if (NULL == rh) { /* nothing to do, release socket really soon if there is nothing * else happening... */ s_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, &shutdown_task, NULL); return; } if (GNUNET_YES == rh->was_transmitted) return; /* waiting for reply */ msg = (struct GNUNET_RESOLVER_GetMessage *) buf; msg->header.size = htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + rh->data_len); msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST); msg->direction = htonl (rh->direction); msg->af = htonl (rh->af); memcpy (&msg[1], &rh[1], rh->data_len); LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting DNS resolution request to DNS service\n"); if (GNUNET_OK != GNUNET_CLIENT_transmit_and_get_response (client, &msg->header, GNUNET_TIME_absolute_get_remaining (rh->timeout), GNUNET_YES, &handle_response, rh)) { GNUNET_CLIENT_disconnect (client); client = NULL; reconnect (); return; } rh->was_transmitted = GNUNET_YES; } /** * Now try to reconnect to the resolver service. * * @param cls NULL * @param tc scheduler context */ static void reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { r_task = GNUNET_SCHEDULER_NO_TASK; if (NULL == req_head) return; /* no work pending */ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; LOG (GNUNET_ERROR_TYPE_DEBUG, "Trying to connect to DNS service\n"); client = GNUNET_CLIENT_connect ("resolver", resolver_cfg); if (NULL == client) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect, will try again later\n"); reconnect (); return; } process_requests (); } /** * Adjust exponential back-off and reconnect to the service. */ static void reconnect () { struct GNUNET_RESOLVER_RequestHandle *rh; if (GNUNET_SCHEDULER_NO_TASK != r_task) return; GNUNET_assert (NULL == client); if (NULL != (rh = req_head)) { switch (rh->was_transmitted) { case GNUNET_NO: /* nothing more to do */ break; case GNUNET_YES: /* disconnected, transmit again! */ rh->was_transmitted = GNUNET_NO; break; case GNUNET_SYSERR: /* request was cancelled, remove entirely */ GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh); GNUNET_free (rh); break; default: GNUNET_assert (0); break; } } LOG (GNUNET_ERROR_TYPE_DEBUG, "Will try to connect to DNS service in %llu ms\n", (unsigned long long) backoff.rel_value); GNUNET_assert (NULL != resolver_cfg); r_task = GNUNET_SCHEDULER_add_delayed (backoff, &reconnect_task, NULL); backoff = GNUNET_TIME_relative_multiply (backoff, 2); } /** * Convert a string to one or more IP addresses. * * @param hostname the hostname to resolve * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any" * @param callback function to call with addresses * @param callback_cls closure for callback * @param timeout how long to try resolving * @return handle that can be used to cancel the request, NULL on error */ struct GNUNET_RESOLVER_RequestHandle * GNUNET_RESOLVER_ip_get (const char *hostname, int af, struct GNUNET_TIME_Relative timeout, GNUNET_RESOLVER_AddressCallback callback, void *callback_cls) { struct GNUNET_RESOLVER_RequestHandle *rh; size_t slen; unsigned int i; struct in_addr v4; struct in6_addr v6; slen = strlen (hostname) + 1; if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); return NULL; } rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + slen); rh->af = af; rh->addr_callback = callback; rh->cls = callback_cls; memcpy (&rh[1], hostname, slen); rh->data_len = slen; rh->timeout = GNUNET_TIME_relative_to_absolute (timeout); rh->direction = GNUNET_NO; /* first, check if this is a numeric address */ if (((1 == inet_pton (AF_INET, hostname, &v4)) && ((af == AF_INET) || (af == AF_UNSPEC))) || ((1 == inet_pton (AF_INET6, hostname, &v6)) && ((af == AF_INET6) || (af == AF_UNSPEC)))) { rh->task = GNUNET_SCHEDULER_add_now (&numeric_resolution, rh); return rh; } /* then, check if this is a loopback address */ i = 0; while (loopback[i] != NULL) if (0 == strcasecmp (loopback[i++], hostname)) { rh->task = GNUNET_SCHEDULER_add_now (&loopback_resolution, rh); return rh; } GNUNET_CONTAINER_DLL_insert_tail (req_head, req_tail, rh); rh->was_queued = GNUNET_YES; if (s_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (s_task); s_task = GNUNET_SCHEDULER_NO_TASK; } process_requests (); return rh; } /** * We've been asked to convert an address to a string without * a reverse lookup. Do it. * * @param cls struct GNUNET_RESOLVER_RequestHandle for the request * @param tc unused scheduler context */ static void numeric_reverse (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_RESOLVER_RequestHandle *rh = cls; char *result; result = no_resolve (rh->af, &rh[1], rh->data_len); LOG (GNUNET_ERROR_TYPE_DEBUG, "Resolver returns `%s'.\n", result); if (result != NULL) { rh->name_callback (rh->cls, result); GNUNET_free (result); } rh->name_callback (rh->cls, NULL); GNUNET_free (rh); } /** * Get an IP address as a string. * * @param sa host address * @param salen length of host address * @param do_resolve use GNUNET_NO to return numeric hostname * @param timeout how long to try resolving * @param callback function to call with hostnames * last callback is NULL when finished * @param cls closure for callback * @return handle that can be used to cancel the request */ struct GNUNET_RESOLVER_RequestHandle * GNUNET_RESOLVER_hostname_get (const struct sockaddr *sa, socklen_t salen, int do_resolve, struct GNUNET_TIME_Relative timeout, GNUNET_RESOLVER_HostnameCallback callback, void *cls) { struct GNUNET_RESOLVER_RequestHandle *rh; size_t ip_len; const void *ip; check_config (); switch (sa->sa_family) { case AF_INET: ip_len = sizeof (struct in_addr); ip = &((const struct sockaddr_in*)sa)->sin_addr; break; case AF_INET6: ip_len = sizeof (struct in6_addr); ip = &((const struct sockaddr_in6*)sa)->sin6_addr; break; default: GNUNET_break (0); return NULL; } rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + salen); rh->name_callback = callback; rh->cls = cls; rh->af = sa->sa_family; rh->timeout = GNUNET_TIME_relative_to_absolute (timeout); memcpy (&rh[1], ip, ip_len); rh->data_len = ip_len; rh->direction = GNUNET_YES; rh->received_response = GNUNET_NO; if (GNUNET_NO == do_resolve) { rh->task = GNUNET_SCHEDULER_add_now (&numeric_reverse, rh); return rh; } GNUNET_CONTAINER_DLL_insert_tail (req_head, req_tail, rh); rh->was_queued = GNUNET_YES; if (s_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (s_task); s_task = GNUNET_SCHEDULER_NO_TASK; } process_requests (); return rh; } /** * Get local fully qualified af name * * @return fqdn */ char * GNUNET_RESOLVER_local_fqdn_get () { struct hostent *host; char hostname[GNUNET_OS_get_hostname_max_length () + 1]; if (0 != gethostname (hostname, sizeof (hostname) - 1)) { LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "gethostname"); return NULL; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Resolving our FQDN `%s'\n", hostname); host = gethostbyname (hostname); if (NULL == host) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Could not resolve our FQDN : %s\n"), hstrerror (h_errno)); return NULL; } return GNUNET_strdup (host->h_name); } /** * Looking our own hostname. * * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any" * @param callback function to call with addresses * @param cls closure for callback * @param timeout how long to try resolving * @return handle that can be used to cancel the request, NULL on error */ struct GNUNET_RESOLVER_RequestHandle * GNUNET_RESOLVER_hostname_resolve (int af, struct GNUNET_TIME_Relative timeout, GNUNET_RESOLVER_AddressCallback callback, void *cls) { char hostname[GNUNET_OS_get_hostname_max_length () + 1]; if (0 != gethostname (hostname, sizeof (hostname) - 1)) { LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "gethostname"); return NULL; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Resolving our hostname `%s'\n", hostname); return GNUNET_RESOLVER_ip_get (hostname, af, timeout, callback, cls); } /** * Cancel a request that is still pending with the resolver. * Note that a client MUST NOT cancel a request that has * been completed (i.e, the callback has been called to * signal timeout or the final result). * * @param rh handle of request to cancel */ void GNUNET_RESOLVER_request_cancel (struct GNUNET_RESOLVER_RequestHandle *rh) { if (rh->task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (rh->task); rh->task = GNUNET_SCHEDULER_NO_TASK; } if (rh->was_transmitted == GNUNET_NO) { if (rh->was_queued == GNUNET_YES) GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh); GNUNET_free (rh); return; } GNUNET_assert (rh->was_transmitted == GNUNET_YES); rh->was_transmitted = GNUNET_SYSERR; /* mark as cancelled */ } /* end of resolver_api.c */ gnunet-0.9.3/src/util/test_connection_receive_cancel.c0000644000175000017500000001040011760502551020056 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_connection_receive_cancel.c * @brief tests for connection.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_connection_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" #define VERBOSE GNUNET_NO #define PORT 12435 static struct GNUNET_CONNECTION_Handle *csock; static struct GNUNET_CONNECTION_Handle *asock; static struct GNUNET_CONNECTION_Handle *lsock; static struct GNUNET_NETWORK_Handle *ls; static struct GNUNET_CONFIGURATION_Handle *cfg; /** * Create and initialize a listen socket for the server. * * @return NULL on error, otherwise the listen socket */ static struct GNUNET_NETWORK_Handle * open_listen_socket () { const static int on = 1; struct sockaddr_in sa; struct GNUNET_NETWORK_Handle *desc; memset (&sa, 0, sizeof (sa)); #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = sizeof (sa); #endif sa.sin_family = AF_INET; sa.sin_port = htons (PORT); desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); GNUNET_assert (desc != NULL); if (GNUNET_NETWORK_socket_setsockopt (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); GNUNET_assert (GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa, sizeof (sa)) == GNUNET_OK); GNUNET_NETWORK_socket_listen (desc, 5); return desc; } static void dead_receive (void *cls, const void *buf, size_t available, const struct sockaddr *addr, socklen_t addrlen, int errCode) { GNUNET_assert (0); } static void run_accept_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { asock = GNUNET_CONNECTION_create_from_accept (NULL, NULL, ls); GNUNET_assert (asock != NULL); GNUNET_assert (GNUNET_YES == GNUNET_CONNECTION_check (asock)); GNUNET_CONNECTION_destroy (lsock); GNUNET_CONNECTION_receive (asock, 1024, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), &dead_receive, cls); } static void receive_cancel_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { int *ok = cls; GNUNET_CONNECTION_receive_cancel (asock); GNUNET_CONNECTION_destroy (csock); GNUNET_CONNECTION_destroy (asock); *ok = 0; } static void task_receive_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { ls = open_listen_socket (); lsock = GNUNET_CONNECTION_create_from_existing (ls); GNUNET_assert (lsock != NULL); csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT); GNUNET_assert (csock != NULL); GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, ls, &run_accept_cancel, cls); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &receive_cancel_task, cls); } /** * Main method, starts scheduler with task_timeout. */ static int check_receive_cancel () { int ok; ok = 1; cfg = GNUNET_CONFIGURATION_create (); GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", "localhost"); GNUNET_SCHEDULER_run (&task_receive_cancel, &ok); GNUNET_CONFIGURATION_destroy (cfg); return ok; } int main (int argc, char *argv[]) { int ret = 0; GNUNET_log_setup ("test_connection_receive_cancel", "WARNING", NULL); ret += check_receive_cancel (); return ret; } /* end of test_connection_receive_cancel.c */ gnunet-0.9.3/src/util/speedup.c0000644000175000017500000000534111761753145013336 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/speedup.c * @author Matthias Wachs * @brief functions to speedup peer execution by manipulation system time */ #include "platform.h" #include "gnunet_time_lib.h" #include "gnunet_scheduler_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) static struct GNUNET_TIME_Relative interval; static struct GNUNET_TIME_Relative delta; static GNUNET_SCHEDULER_TaskIdentifier speedup_task; static void do_speedup (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { static long long current_offset; speedup_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) return; current_offset += delta.rel_value; GNUNET_TIME_set_offset (current_offset); LOG (GNUNET_ERROR_TYPE_DEBUG, "Speeding up execution time by %llu ms\n", delta.rel_value); speedup_task = GNUNET_SCHEDULER_add_delayed (interval, &do_speedup, NULL); } int GNUNET_SPEEDUP_start_ (const struct GNUNET_CONFIGURATION_Handle *cfg) { if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "SPEEDUP_INTERVAL", &interval)) return GNUNET_SYSERR; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "SPEEDUP_DELTA", &delta)) return GNUNET_SYSERR; if ((0 == interval.rel_value) || (0 == delta.rel_value)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Speed up disabled\n"); return GNUNET_OK; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Speed up execution time %llu ms every %llu ms\n", delta.rel_value, interval.rel_value); speedup_task = GNUNET_SCHEDULER_add_now_with_lifeness (GNUNET_NO, &do_speedup, NULL); return GNUNET_OK; } void GNUNET_SPEEDUP_stop_ ( ) { if (GNUNET_SCHEDULER_NO_TASK != speedup_task) { GNUNET_SCHEDULER_cancel (speedup_task); speedup_task = GNUNET_SCHEDULER_NO_TASK; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Stopped execution speed up\n"); } /* end of speedup.c */ gnunet-0.9.3/src/util/pseudonym.c0000644000175000017500000005047511760502551013714 00000000000000/* This file is part of GNUnet (C) 2003, 2004, 2005, 2006, 2007, 2008 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/pseudonym.c * @brief helper functions * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_container_lib.h" #include "gnunet_disk_lib.h" #include "gnunet_pseudonym_lib.h" #include "gnunet_bio_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) /** * Name of the directory which stores meta data for pseudonym */ #define PS_METADATA_DIR DIR_SEPARATOR_STR "data" DIR_SEPARATOR_STR "pseudonyms" DIR_SEPARATOR_STR "metadata" DIR_SEPARATOR_STR /** * Name of the directory which stores names for pseudonyms */ #define PS_NAMES_DIR DIR_SEPARATOR_STR "data" DIR_SEPARATOR_STR "pseudonyms" DIR_SEPARATOR_STR "names" DIR_SEPARATOR_STR /** * Configuration section we use. */ #define GNUNET_CLIENT_SERVICE_NAME "client" /** * Registered callbacks for discovery of pseudonyms. */ struct DiscoveryCallback { /** * This is a linked list. */ struct DiscoveryCallback *next; /** * Function to call each time a pseudonym is discovered. */ GNUNET_PSEUDONYM_Iterator callback; /** * Closure for callback. */ void *closure; }; /** * Head of the linked list of functions to call when * new pseudonyms are added. */ static struct DiscoveryCallback *head; /** * Internal notification about new tracked URI. * @param id a point to the hash code of pseudonym * @param md meta data to be written * @param rating rating of pseudonym */ static void internal_notify (const GNUNET_HashCode * id, const struct GNUNET_CONTAINER_MetaData *md, int rating) { struct DiscoveryCallback *pos; pos = head; while (pos != NULL) { pos->callback (pos->closure, id, NULL, NULL, md, rating); pos = pos->next; } } /** * Register callback to be invoked whenever we discover * a new pseudonym. * Will immediately call provided iterator callback for all * already discovered pseudonyms. * * @param cfg configuration to use * @param iterator iterator over pseudonym * @param closure point to a closure */ int GNUNET_PSEUDONYM_discovery_callback_register (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_PSEUDONYM_Iterator iterator, void *closure) { struct DiscoveryCallback *list; list = GNUNET_malloc (sizeof (struct DiscoveryCallback)); list->callback = iterator; list->closure = closure; list->next = head; head = list; GNUNET_PSEUDONYM_list_all (cfg, iterator, closure); return GNUNET_OK; } /** * Unregister pseudonym discovery callback. * @param iterator iterator over pseudonym * @param closure point to a closure */ int GNUNET_PSEUDONYM_discovery_callback_unregister (GNUNET_PSEUDONYM_Iterator iterator, void *closure) { struct DiscoveryCallback *prev; struct DiscoveryCallback *pos; prev = NULL; pos = head; while ((pos != NULL) && ((pos->callback != iterator) || (pos->closure != closure))) { prev = pos; pos = pos->next; } if (pos == NULL) return GNUNET_SYSERR; if (prev == NULL) head = pos->next; else prev->next = pos->next; GNUNET_free (pos); return GNUNET_OK; } /** * Get the filename (or directory name) for the given * pseudonym identifier and directory prefix. * @param cfg configuration to use * @param prefix path components to append to the private directory name * @param psid hash code of pseudonym, can be NULL * @return filename of the pseudonym (if psid != NULL) or directory with the data (if psid == NULL) */ static char * get_data_filename (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *prefix, const GNUNET_HashCode * psid) { struct GNUNET_CRYPTO_HashAsciiEncoded enc; if (psid != NULL) GNUNET_CRYPTO_hash_to_enc (psid, &enc); return GNUNET_DISK_get_home_filename (cfg, GNUNET_CLIENT_SERVICE_NAME, prefix, (psid == NULL) ? NULL : (const char *) &enc, NULL); } /** * Write the pseudonym infomation into a file * @param cfg configuration to use * @param nsid hash code of a pseudonym * @param meta meta data to be written into a file * @param ranking ranking of a pseudonym * @param ns_name non-unique name of a pseudonym */ static void write_pseudonym_info (const struct GNUNET_CONFIGURATION_Handle *cfg, const GNUNET_HashCode * nsid, const struct GNUNET_CONTAINER_MetaData *meta, int32_t ranking, const char *ns_name) { char *fn; struct GNUNET_BIO_WriteHandle *fileW; fn = get_data_filename (cfg, PS_METADATA_DIR, nsid); GNUNET_assert (fn != NULL); fileW = GNUNET_BIO_write_open (fn); if (NULL != fileW) { if ((GNUNET_OK != GNUNET_BIO_write_int32 (fileW, ranking)) || (GNUNET_OK != GNUNET_BIO_write_string (fileW, ns_name)) || (GNUNET_OK != GNUNET_BIO_write_meta_data (fileW, meta))) { (void) GNUNET_BIO_write_close (fileW); GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn)); GNUNET_free (fn); return; } if (GNUNET_OK != GNUNET_BIO_write_close (fileW)) { GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn)); GNUNET_free (fn); return; } } GNUNET_free (fn); /* create entry for pseudonym name in names */ if (ns_name != NULL) GNUNET_free_non_null (GNUNET_PSEUDONYM_name_uniquify (cfg, nsid, ns_name, NULL)); } /** * read the pseudonym infomation from a file * @param cfg configuration to use * @param nsid hash code of a pseudonym * @param meta meta data to be read from a file * @param ranking ranking of a pseudonym * @param ns_name name of a pseudonym */ static int read_info (const struct GNUNET_CONFIGURATION_Handle *cfg, const GNUNET_HashCode * nsid, struct GNUNET_CONTAINER_MetaData **meta, int32_t * ranking, char **ns_name) { char *fn; char *emsg; struct GNUNET_BIO_ReadHandle *fileR; fn = get_data_filename (cfg, PS_METADATA_DIR, nsid); GNUNET_assert (fn != NULL); fileR = GNUNET_BIO_read_open (fn); if (fileR == NULL) { GNUNET_free (fn); return GNUNET_SYSERR; } emsg = NULL; *ns_name = NULL; if ((GNUNET_OK != GNUNET_BIO_read_int32 (fileR, ranking)) || (GNUNET_OK != GNUNET_BIO_read_string (fileR, "Read string error!", ns_name, 200)) || (GNUNET_OK != GNUNET_BIO_read_meta_data (fileR, "Read meta data error!", meta))) { (void) GNUNET_BIO_read_close (fileR, &emsg); GNUNET_free_non_null (emsg); GNUNET_free_non_null (*ns_name); *ns_name = NULL; GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn)); GNUNET_free (fn); return GNUNET_SYSERR; } if (GNUNET_OK != GNUNET_BIO_read_close (fileR, &emsg)) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Failed to parse metadata about pseudonym from file `%s': %s\n"), fn, emsg); GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn)); GNUNET_CONTAINER_meta_data_destroy (*meta); *meta = NULL; GNUNET_free_non_null (*ns_name); *ns_name = NULL; GNUNET_free_non_null (emsg); GNUNET_free (fn); return GNUNET_SYSERR; } GNUNET_free (fn); return GNUNET_OK; } /** * Return unique variant of the namespace name. * Use it after GNUNET_PSEUDONYM_get_info() to make sure * that name is unique. * * @param cfg configuration * @param nsid cryptographic ID of the namespace * @param name name to uniquify * @param suffix if not NULL, filled with the suffix value * @return NULL on failure (should never happen), name on success. * Free the name with GNUNET_free(). */ char * GNUNET_PSEUDONYM_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg, const GNUNET_HashCode * nsid, const char *name, unsigned int *suffix) { GNUNET_HashCode nh; uint64_t len; char *fn; struct GNUNET_DISK_FileHandle *fh; unsigned int i; unsigned int idx; char *ret; struct stat sbuf; GNUNET_CRYPTO_hash (name, strlen (name), &nh); fn = get_data_filename (cfg, PS_NAMES_DIR, &nh); GNUNET_assert (fn != NULL); len = 0; if (0 == STAT (fn, &sbuf)) GNUNET_break (GNUNET_OK == GNUNET_DISK_file_size (fn, &len, GNUNET_YES, GNUNET_YES)); fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_READWRITE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); i = 0; idx = -1; while ((len >= sizeof (GNUNET_HashCode)) && (sizeof (GNUNET_HashCode) == GNUNET_DISK_file_read (fh, &nh, sizeof (GNUNET_HashCode)))) { if (0 == memcmp (&nh, nsid, sizeof (GNUNET_HashCode))) { idx = i; break; } i++; len -= sizeof (GNUNET_HashCode); } if (idx == -1) { idx = i; if (sizeof (GNUNET_HashCode) != GNUNET_DISK_file_write (fh, nsid, sizeof (GNUNET_HashCode))) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "write", fn); } GNUNET_DISK_file_close (fh); ret = GNUNET_malloc (strlen (name) + 32); GNUNET_snprintf (ret, strlen (name) + 32, "%s-%u", name, idx); if (suffix != NULL) *suffix = idx; GNUNET_free (fn); return ret; } /** * Get namespace name, metadata and rank * This is a wrapper around internal read_info() call, and ensures that * returned data is not invalid (not NULL). * * @param cfg configuration * @param nsid cryptographic ID of the namespace * @param ret_meta a location to store metadata pointer. NULL, if metadata * is not needed. Destroy with GNUNET_CONTAINER_meta_data_destroy(). * @param ret_rank a location to store rank. NULL, if rank not needed. * @param ret_name a location to store human-readable name. Name is not unique. * NULL, if name is not needed. Free with GNUNET_free(). * @param name_is_a_dup is set to GNUNET_YES, if ret_name was filled with * a duplicate of a "no-name" placeholder * @return GNUNET_OK on success. GNUENT_SYSERR if the data was * unobtainable (in that case ret_* are filled with placeholders - * empty metadata container, rank -1 and a "no-name" name). */ int GNUNET_PSEUDONYM_get_info (const struct GNUNET_CONFIGURATION_Handle *cfg, const GNUNET_HashCode * nsid, struct GNUNET_CONTAINER_MetaData **ret_meta, int32_t *ret_rank, char **ret_name, int *name_is_a_dup) { struct GNUNET_CONTAINER_MetaData *meta; char *name; int32_t rank = -1; meta = NULL; name = NULL; if (GNUNET_OK == read_info (cfg, nsid, &meta, &rank, &name)) { if ((meta != NULL) && (name == NULL)) name = GNUNET_CONTAINER_meta_data_get_first_by_types (meta, EXTRACTOR_METATYPE_TITLE, EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, EXTRACTOR_METATYPE_FILENAME, EXTRACTOR_METATYPE_DESCRIPTION, EXTRACTOR_METATYPE_SUBJECT, EXTRACTOR_METATYPE_PUBLISHER, EXTRACTOR_METATYPE_AUTHOR_NAME, EXTRACTOR_METATYPE_COMMENT, EXTRACTOR_METATYPE_SUMMARY, -1); if (ret_name != NULL) { if (name == NULL) { name = GNUNET_strdup (_("no-name")); if (name_is_a_dup != NULL) *name_is_a_dup = GNUNET_YES; } else if (name_is_a_dup != NULL) *name_is_a_dup = GNUNET_NO; *ret_name = name; } else if (name != NULL) GNUNET_free (name); if (ret_meta != NULL) { if (meta == NULL) meta = GNUNET_CONTAINER_meta_data_create (); *ret_meta = meta; } else if (meta != NULL) GNUNET_CONTAINER_meta_data_destroy (meta); if (ret_rank != NULL) *ret_rank = rank; return GNUNET_OK; } if (ret_name != NULL) *ret_name = GNUNET_strdup (_("no-name")); if (ret_meta != NULL) *ret_meta = GNUNET_CONTAINER_meta_data_create (); if (ret_rank != NULL) *ret_rank = -1; if (name_is_a_dup != NULL) *name_is_a_dup = GNUNET_YES; return GNUNET_SYSERR; } /** * Get the namespace ID belonging to the given namespace name. * * @param cfg configuration to use * @param ns_uname unique (!) human-readable name for the namespace * @param nsid set to namespace ID based on 'ns_uname' * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int GNUNET_PSEUDONYM_name_to_id (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *ns_uname, GNUNET_HashCode * nsid) { size_t slen; uint64_t len; unsigned int idx; char *name; GNUNET_HashCode nh; char *fn; struct GNUNET_DISK_FileHandle *fh; idx = -1; slen = strlen (ns_uname); while ((slen > 0) && (1 != SSCANF (&ns_uname[slen - 1], "-%u", &idx))) slen--; if (slen == 0) return GNUNET_SYSERR; name = GNUNET_strdup (ns_uname); name[slen - 1] = '\0'; GNUNET_CRYPTO_hash (name, strlen (name), &nh); GNUNET_free (name); fn = get_data_filename (cfg, PS_NAMES_DIR, &nh); GNUNET_assert (fn != NULL); if ((GNUNET_OK != GNUNET_DISK_file_test (fn) || (GNUNET_OK != GNUNET_DISK_file_size (fn, &len, GNUNET_YES, GNUNET_YES))) || ((idx + 1) * sizeof (GNUNET_HashCode) > len)) { GNUNET_free (fn); return GNUNET_SYSERR; } fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_READWRITE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); GNUNET_free (fn); GNUNET_DISK_file_seek (fh, idx * sizeof (GNUNET_HashCode), GNUNET_DISK_SEEK_SET); if (sizeof (GNUNET_HashCode) != GNUNET_DISK_file_read (fh, nsid, sizeof (GNUNET_HashCode))) { GNUNET_DISK_file_close (fh); return GNUNET_SYSERR; } GNUNET_DISK_file_close (fh); return GNUNET_OK; } /** * struct used to list the pseudonym */ struct ListPseudonymClosure { /** * iterator over pseudonym */ GNUNET_PSEUDONYM_Iterator iterator; /** * Closure for iterator. */ void *closure; /** * Configuration to use. */ const struct GNUNET_CONFIGURATION_Handle *cfg; }; /** * the help function to list all available pseudonyms * @param cls point to a struct ListPseudonymClosure * @param fullname name of pseudonym */ static int list_pseudonym_helper (void *cls, const char *fullname) { struct ListPseudonymClosure *c = cls; int ret; GNUNET_HashCode id; int32_t rating; struct GNUNET_CONTAINER_MetaData *meta; const char *fn; char *str; char *name_unique; if (strlen (fullname) < sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) return GNUNET_OK; fn = &fullname[strlen (fullname) + 1 - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]; if (fn[-1] != DIR_SEPARATOR) return GNUNET_OK; ret = GNUNET_OK; if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (fn, &id)) return GNUNET_OK; /* invalid name */ str = NULL; if (GNUNET_OK != GNUNET_PSEUDONYM_get_info (c->cfg, &id, &meta, &rating, &str, NULL)) { /* ignore entry. FIXME: Why? Lack of data about a pseudonym is not a reason * to ignore it... So yeah, it will have placeholders instead of name, * empty metadata container and a default rank == -1, so what? We know * its nsid - that's all we really need. Right? */ GNUNET_free (str); GNUNET_CONTAINER_meta_data_destroy (meta); return GNUNET_OK; } name_unique = GNUNET_PSEUDONYM_name_uniquify (c->cfg, &id, str, NULL); if (c->iterator != NULL) ret = c->iterator (c->closure, &id, str, name_unique, meta, rating); GNUNET_free_non_null (str); GNUNET_free_non_null (name_unique); GNUNET_CONTAINER_meta_data_destroy (meta); return ret; } /** * List all available pseudonyms. * * @param cfg overall configuration * @param iterator function to call for each pseudonym * @param closure closure for iterator * @return number of pseudonyms found */ int GNUNET_PSEUDONYM_list_all (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_PSEUDONYM_Iterator iterator, void *closure) { struct ListPseudonymClosure cls; char *fn; int ret; cls.iterator = iterator; cls.closure = closure; cls.cfg = cfg; fn = get_data_filename (cfg, PS_METADATA_DIR, NULL); GNUNET_assert (fn != NULL); GNUNET_DISK_directory_create (fn); ret = GNUNET_DISK_directory_scan (fn, &list_pseudonym_helper, &cls); GNUNET_free (fn); return ret; } /** * Change the ranking of a pseudonym. * * @param cfg overall configuration * @param nsid id of the pseudonym * @param delta by how much should the rating be * changed? * @return new rating of the pseudonym */ int GNUNET_PSEUDONYM_rank (const struct GNUNET_CONFIGURATION_Handle *cfg, const GNUNET_HashCode * nsid, int delta) { struct GNUNET_CONTAINER_MetaData *meta; int ret; int32_t ranking; char *name; name = NULL; ret = read_info (cfg, nsid, &meta, &ranking, &name); if (ret == GNUNET_SYSERR) { ranking = 0; meta = GNUNET_CONTAINER_meta_data_create (); } ranking += delta; write_pseudonym_info (cfg, nsid, meta, ranking, name); GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_free_non_null (name); return ranking; } /** * Set the pseudonym metadata, rank and name. * * @param cfg overall configuration * @param nsid id of the pseudonym * @param name name to set. Must be the non-unique version of it. * May be NULL, in which case it erases pseudonym's name! * @param md metadata to set * May be NULL, in which case it erases pseudonym's metadata! * @param rank rank to assign * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int GNUNET_PSEUDONYM_set_info (const struct GNUNET_CONFIGURATION_Handle *cfg, const GNUNET_HashCode * nsid, const char *name, const struct GNUNET_CONTAINER_MetaData *md, int rank) { GNUNET_assert (cfg != NULL); GNUNET_assert (nsid != NULL); write_pseudonym_info (cfg, nsid, md, rank, name); return GNUNET_OK; } /** * Add a pseudonym to the set of known pseudonyms. * For all pseudonym advertisements that we discover * FS should automatically call this function. * * @param cfg overall configuration * @param id the pseudonym identifier * @param meta metadata for the pseudonym */ void GNUNET_PSEUDONYM_add (const struct GNUNET_CONFIGURATION_Handle *cfg, const GNUNET_HashCode * id, const struct GNUNET_CONTAINER_MetaData *meta) { char *name; int32_t ranking; struct GNUNET_CONTAINER_MetaData *old; char *fn; struct stat sbuf; ranking = 0; fn = get_data_filename (cfg, PS_METADATA_DIR, id); GNUNET_assert (fn != NULL); if ((0 == STAT (fn, &sbuf)) && (GNUNET_OK == read_info (cfg, id, &old, &ranking, &name))) { GNUNET_CONTAINER_meta_data_merge (old, meta); write_pseudonym_info (cfg, id, old, ranking, name); GNUNET_CONTAINER_meta_data_destroy (old); GNUNET_free_non_null (name); } else { write_pseudonym_info (cfg, id, meta, ranking, NULL); } GNUNET_free (fn); internal_notify (id, meta, ranking); } /* end of pseudonym.c */ gnunet-0.9.3/src/util/gnunet-service-resolver.c0000644000175000017500000003423111760502551016456 00000000000000/* This file is part of GNUnet. (C) 2007, 2008, 2009, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/gnunet-service-resolver.c * @brief code to do DNS resolution * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_protocols.h" #include "gnunet_statistics_service.h" #include "resolver.h" /** * A cached DNS lookup result. */ struct IPCache { /** * This is a doubly linked list. */ struct IPCache *next; /** * This is a doubly linked list. */ struct IPCache *prev; /** * Hostname in human-readable form. */ char *addr; /** * Binary IP address, allocated at the end of this struct. */ const void *ip; /** * Last time this entry was updated. */ struct GNUNET_TIME_Absolute last_refresh; /** * Last time this entry was requested. */ struct GNUNET_TIME_Absolute last_request; /** * Number of bytes in ip. */ size_t ip_len; /** * Address family of the IP. */ int af; }; /** * Start of the linked list of cached DNS lookup results. */ static struct IPCache *cache_head; /** * Tail of the linked list of cached DNS lookup results. */ static struct IPCache *cache_tail; #if HAVE_GETNAMEINFO /** * Resolve the given request using getnameinfo * * @param cache the request to resolve (and where to store the result) */ static void getnameinfo_resolve (struct IPCache *cache) { char hostname[256]; const struct sockaddr *sa; struct sockaddr_in v4; struct sockaddr_in6 v6; size_t salen; switch (cache->af) { case AF_INET: GNUNET_assert (cache->ip_len == sizeof (struct in_addr)); sa = (const struct sockaddr*) &v4; memset (&v4, 0, sizeof (v4)); v4.sin_addr = * (const struct in_addr*) cache->ip; v4.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN v4.sin_len = sizeof (v4); #endif salen = sizeof (v4); break; case AF_INET6: GNUNET_assert (cache->ip_len == sizeof (struct in6_addr)); sa = (const struct sockaddr*) &v6; memset (&v6, 0, sizeof (v6)); v6.sin6_addr = * (const struct in6_addr*) cache->ip; v6.sin6_family = AF_INET6; #if HAVE_SOCKADDR_IN_SIN_LEN v6.sin6_len = sizeof (v6); #endif salen = sizeof (v6); break; default: GNUNET_assert (0); } if (0 == getnameinfo (sa, salen, hostname, sizeof (hostname), NULL, 0, 0)) cache->addr = GNUNET_strdup (hostname); } #endif #if HAVE_GETHOSTBYADDR /** * Resolve the given request using gethostbyaddr * * @param cache the request to resolve (and where to store the result) */ static void gethostbyaddr_resolve (struct IPCache *cache) { struct hostent *ent; ent = gethostbyaddr (cache->ip, cache->ip_len, cache->af); if (ent != NULL) cache->addr = GNUNET_strdup (ent->h_name); } #endif /** * Resolve the given request using the available methods. * * @param cache the request to resolve (and where to store the result) */ static void cache_resolve (struct IPCache *cache) { #if HAVE_GETNAMEINFO if (cache->addr == NULL) getnameinfo_resolve (cache); #endif #if HAVE_GETHOSTBYADDR if (cache->addr == NULL) gethostbyaddr_resolve (cache); #endif } /** * Get an IP address as a string (works for both IPv4 and IPv6). Note * that the resolution happens asynchronously and that the first call * may not immediately result in the FQN (but instead in a * human-readable IP address). * * @param client handle to the client making the request (for sending the reply) * @param af AF_INET or AF_INET6 * @param ip 'struct in_addr' or 'struct in6_addr' */ static void get_ip_as_string (struct GNUNET_SERVER_Client *client, int af, const void *ip) { struct IPCache *pos; struct IPCache *next; struct GNUNET_TIME_Absolute now; struct GNUNET_SERVER_TransmitContext *tc; size_t ip_len; switch (af) { case AF_INET: ip_len = sizeof (struct in_addr); break; case AF_INET6: ip_len = sizeof (struct in6_addr); break; default: GNUNET_assert (0); } now = GNUNET_TIME_absolute_get (); next = cache_head; while ( (NULL != (pos = next)) && ( (pos->af != af) || (pos->ip_len != ip_len) || (0 != memcmp (pos->ip, ip, ip_len))) ) { next = pos->next; if (GNUNET_TIME_absolute_get_duration (pos->last_request).rel_value < 60 * 60 * 1000) { GNUNET_CONTAINER_DLL_remove (cache_head, cache_tail, pos); GNUNET_free_non_null (pos->addr); GNUNET_free (pos); continue; } } if (pos != NULL) { pos->last_request = now; if (GNUNET_TIME_absolute_get_duration (pos->last_request).rel_value < 60 * 60 * 1000) { GNUNET_free_non_null (pos->addr); pos->addr = NULL; cache_resolve (pos); } } else { pos = GNUNET_malloc (sizeof (struct IPCache) + ip_len); pos->ip = &pos[1]; memcpy (&pos[1], ip, ip_len); pos->last_request = now; pos->last_refresh = now; pos->ip_len = ip_len; pos->af = af; GNUNET_CONTAINER_DLL_insert (cache_head, cache_tail, pos); cache_resolve (pos); } tc = GNUNET_SERVER_transmit_context_create (client); if (pos->addr != NULL) GNUNET_SERVER_transmit_context_append_data (tc, pos->addr, strlen (pos->addr) + 1, GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); } #if HAVE_GETADDRINFO static int getaddrinfo_resolve (struct GNUNET_SERVER_TransmitContext *tc, const char *hostname, int af) { int s; struct addrinfo hints; struct addrinfo *result; struct addrinfo *pos; memset (&hints, 0, sizeof (struct addrinfo)); // FIXME in PlibC #ifndef MINGW hints.ai_family = af; #else hints.ai_family = AF_INET; #endif hints.ai_socktype = SOCK_STREAM; /* go for TCP */ if (0 != (s = getaddrinfo (hostname, NULL, &hints, &result))) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Could not resolve `%s' (%s): %s\n"), hostname, (af == AF_INET) ? "IPv4" : ((af == AF_INET6) ? "IPv6" : "any"), gai_strerror (s)); if ((s == EAI_BADFLAGS) || (s == EAI_MEMORY) #ifndef MINGW || (s == EAI_SYSTEM) #else // FIXME NILS || 1 #endif ) return GNUNET_NO; /* other function may still succeed */ return GNUNET_SYSERR; } if (result == NULL) return GNUNET_SYSERR; pos = result; while (pos != NULL) { switch (pos->ai_family) { case AF_INET: GNUNET_SERVER_transmit_context_append_data (tc, &((struct sockaddr_in*) pos->ai_addr)->sin_addr, sizeof (struct in_addr), GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); break; case AF_INET6: GNUNET_SERVER_transmit_context_append_data (tc, &((struct sockaddr_in6*) pos->ai_addr)->sin6_addr, sizeof (struct in6_addr), GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); break; default: /* unsupported, skip */ break; } pos = pos->ai_next; } freeaddrinfo (result); return GNUNET_OK; } #endif #if HAVE_GETHOSTBYNAME2 static int gethostbyname2_resolve (struct GNUNET_SERVER_TransmitContext *tc, const char *hostname, int af) { struct hostent *hp; int ret1; int ret2; if (af == AF_UNSPEC) { ret1 = gethostbyname2_resolve (tc, hostname, AF_INET); ret2 = gethostbyname2_resolve (tc, hostname, AF_INET6); if ((ret1 == GNUNET_OK) || (ret2 == GNUNET_OK)) return GNUNET_OK; if ((ret1 == GNUNET_SYSERR) || (ret2 == GNUNET_SYSERR)) return GNUNET_SYSERR; return GNUNET_NO; } hp = gethostbyname2 (hostname, af); if (hp == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Could not find IP of host `%s': %s\n"), hostname, hstrerror (h_errno)); return GNUNET_SYSERR; } GNUNET_assert (hp->h_addrtype == af); switch (af) { case AF_INET: GNUNET_assert (hp->h_length == sizeof (struct in_addr)); GNUNET_SERVER_transmit_context_append_data (tc, hp->h_addr_list[0], hp->h_length, GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); break; case AF_INET6: GNUNET_assert (hp->h_length == sizeof (struct in6_addr)); GNUNET_SERVER_transmit_context_append_data (tc, hp->h_addr_list[0], hp->h_length, GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); break; default: GNUNET_break (0); return GNUNET_SYSERR; } return GNUNET_OK; } #endif #if HAVE_GETHOSTBYNAME static int gethostbyname_resolve (struct GNUNET_SERVER_TransmitContext *tc, const char *hostname) { struct hostent *hp; hp = GETHOSTBYNAME (hostname); if (hp == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Could not find IP of host `%s': %s\n"), hostname, hstrerror (h_errno)); return GNUNET_SYSERR; } if (hp->h_addrtype != AF_INET) { GNUNET_break (0); return GNUNET_SYSERR; } GNUNET_assert (hp->h_length == sizeof (struct in_addr)); GNUNET_SERVER_transmit_context_append_data (tc, hp->h_addr_list[0], hp->h_length, GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); return GNUNET_OK; } #endif /** * Convert a string to an IP address. * * @param client where to send the IP address * @param hostname the hostname to resolve * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any" */ static void get_ip_from_hostname (struct GNUNET_SERVER_Client *client, const char *hostname, int af) { int ret; struct GNUNET_SERVER_TransmitContext *tc; tc = GNUNET_SERVER_transmit_context_create (client); ret = GNUNET_NO; #if HAVE_GETADDRINFO if (ret == GNUNET_NO) ret = getaddrinfo_resolve (tc, hostname, af); #endif #if HAVE_GETHOSTBYNAME2 if (ret == GNUNET_NO) ret = gethostbyname2_resolve (tc, hostname, af); #endif #if HAVE_GETHOSTBYNAME if ((ret == GNUNET_NO) && ((af == AF_UNSPEC) || (af == PF_INET))) gethostbyname_resolve (tc, hostname); #endif GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); } /** * Handle GET-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_get (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { uint16_t msize; const struct GNUNET_RESOLVER_GetMessage *msg; const void *ip; uint16_t size; int direction; int af; msize = ntohs (message->size); if (msize < sizeof (struct GNUNET_RESOLVER_GetMessage)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } msg = (const struct GNUNET_RESOLVER_GetMessage *) message; size = msize - sizeof (struct GNUNET_RESOLVER_GetMessage); direction = ntohl (msg->direction); af = ntohl (msg->af); if (direction == GNUNET_NO) { /* IP from hostname */ const char *hostname; hostname = (const char *) &msg[1]; if (hostname[size - 1] != '\0') { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Resolver asked to look up `%s'.\n", hostname); get_ip_from_hostname (client, hostname, af); return; } ip = &msg[1]; switch (af) { case AF_INET: if (size != sizeof (struct in_addr)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } break; case AF_INET6: if (size != sizeof (struct in6_addr)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } break; default: GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } { char buf[INET6_ADDRSTRLEN]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Resolver asked to look up IP address `%s'.\n", inet_ntop (af, ip, buf, sizeof (buf))); } get_ip_as_string (client, af, ip); } /** * Process resolver requests. * * @param cls closure * @param server the initialized server * @param cfg configuration to use */ static void run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *cfg) { static const struct GNUNET_SERVER_MessageHandler handlers[] = { {&handle_get, NULL, GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST, 0}, {NULL, NULL, 0, 0} }; GNUNET_SERVER_add_handlers (server, handlers); } /** * The main function for the resolver service. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { struct IPCache *pos; int ret; ret = (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "resolver", GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; while (NULL != (pos = cache_head)) { GNUNET_CONTAINER_DLL_remove (cache_head, cache_tail, pos); GNUNET_free_non_null (pos->addr); GNUNET_free (pos); } return ret; } /* end of gnunet-service-resolver.c */ gnunet-0.9.3/src/util/test_crypto_rsa.c0000644000175000017500000002330111760502551015101 00000000000000/* This file is part of GNUnet. (C) 2002, 2003, 2004, 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_crypto_rsa.c * @brief testcase for RSA public key crypto * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_crypto_lib.h" #include "gnunet_signatures.h" #include "gnunet_time_lib.h" #define TESTSTRING "Hello World\0" #define MAX_TESTVAL sizeof(struct GNUNET_CRYPTO_AesSessionKey) #define ITER 25 #define KEYFILE "/tmp/test-gnunet-crypto-rsa.key" #define PERF GNUNET_YES static int testEncryptDecrypt () { struct GNUNET_CRYPTO_RsaPrivateKey *hostkey; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; struct GNUNET_CRYPTO_RsaEncryptedData target; char result[MAX_TESTVAL]; int i; struct GNUNET_TIME_Absolute start; int ok; FPRINTF (stderr, "%s", "W"); hostkey = GNUNET_CRYPTO_rsa_key_create (); GNUNET_CRYPTO_rsa_key_get_public (hostkey, &pkey); ok = 0; start = GNUNET_TIME_absolute_get (); for (i = 0; i < ITER; i++) { FPRINTF (stderr, "%s", "."); if (GNUNET_SYSERR == GNUNET_CRYPTO_rsa_encrypt (TESTSTRING, strlen (TESTSTRING) + 1, &pkey, &target)) { FPRINTF (stderr, "%s", "GNUNET_CRYPTO_rsa_encrypt returned SYSERR\n"); ok++; continue; } if (-1 == GNUNET_CRYPTO_rsa_decrypt (hostkey, &target, result, strlen (TESTSTRING) + 1)) { FPRINTF (stderr, "%s", "GNUNET_CRYPTO_rsa_decrypt returned SYSERR\n"); ok++; continue; } if (strncmp (TESTSTRING, result, strlen (TESTSTRING)) != 0) { printf ("%s != %.*s - testEncryptDecrypt failed!\n", TESTSTRING, (int) MAX_TESTVAL, result); ok++; continue; } } printf ("%d RSA encrypt/decrypt operations %llums (%d failures)\n", ITER, (unsigned long long) GNUNET_TIME_absolute_get_duration (start).rel_value, ok); GNUNET_CRYPTO_rsa_key_free (hostkey); if (ok == 0) return GNUNET_OK; else return GNUNET_SYSERR; } #if PERF static int testEncryptPerformance () { struct GNUNET_CRYPTO_RsaPrivateKey *hostkey; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; struct GNUNET_CRYPTO_RsaEncryptedData target; int i; struct GNUNET_TIME_Absolute start; int ok; FPRINTF (stderr, "%s", "W"); hostkey = GNUNET_CRYPTO_rsa_key_create (); GNUNET_CRYPTO_rsa_key_get_public (hostkey, &pkey); ok = 0; start = GNUNET_TIME_absolute_get (); for (i = 0; i < ITER; i++) { FPRINTF (stderr, "%s", "."); if (GNUNET_SYSERR == GNUNET_CRYPTO_rsa_encrypt (TESTSTRING, strlen (TESTSTRING) + 1, &pkey, &target)) { FPRINTF (stderr, "%s", "GNUNET_CRYPTO_rsa_encrypt returned SYSERR\n"); ok++; continue; } } printf ("%d RSA encrypt operations %llu ms (%d failures)\n", ITER, (unsigned long long) GNUNET_TIME_absolute_get_duration (start).rel_value, ok); GNUNET_CRYPTO_rsa_key_free (hostkey); if (ok != 0) return GNUNET_SYSERR; return GNUNET_OK; } #endif static int testEncryptDecryptSK () { struct GNUNET_CRYPTO_RsaPrivateKey *hostkey; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; struct GNUNET_CRYPTO_RsaEncryptedData target; struct GNUNET_CRYPTO_AesSessionKey insk; struct GNUNET_CRYPTO_AesSessionKey outsk; int i; struct GNUNET_TIME_Absolute start; int ok; FPRINTF (stderr, "%s", "W"); hostkey = GNUNET_CRYPTO_rsa_key_create (); GNUNET_CRYPTO_rsa_key_get_public (hostkey, &pkey); ok = 0; start = GNUNET_TIME_absolute_get (); for (i = 0; i < ITER; i++) { FPRINTF (stderr, "%s", "."); GNUNET_CRYPTO_aes_create_session_key (&insk); if (GNUNET_SYSERR == GNUNET_CRYPTO_rsa_encrypt (&insk, sizeof (struct GNUNET_CRYPTO_AesSessionKey), &pkey, &target)) { FPRINTF (stderr, "%s", "GNUNET_CRYPTO_rsa_encrypt returned SYSERR\n"); ok++; continue; } if (-1 == GNUNET_CRYPTO_rsa_decrypt (hostkey, &target, &outsk, sizeof (struct GNUNET_CRYPTO_AesSessionKey))) { FPRINTF (stderr, "%s", "GNUNET_CRYPTO_rsa_decrypt returned SYSERR\n"); ok++; continue; } if (0 != memcmp (&insk, &outsk, sizeof (struct GNUNET_CRYPTO_AesSessionKey))) { printf ("testEncryptDecryptSK failed!\n"); ok++; continue; } } printf ("%d RSA encrypt/decrypt SK operations %llums (%d failures)\n", ITER, (unsigned long long) GNUNET_TIME_absolute_get_duration (start).rel_value, ok); GNUNET_CRYPTO_rsa_key_free (hostkey); if (ok != 0) return GNUNET_SYSERR; return GNUNET_OK; } static int testSignVerify () { struct GNUNET_CRYPTO_RsaPrivateKey *hostkey; struct GNUNET_CRYPTO_RsaSignature sig; struct GNUNET_CRYPTO_RsaSignaturePurpose purp; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; int i; struct GNUNET_TIME_Absolute start; int ok = GNUNET_OK; FPRINTF (stderr, "%s", "W"); hostkey = GNUNET_CRYPTO_rsa_key_create (); GNUNET_CRYPTO_rsa_key_get_public (hostkey, &pkey); start = GNUNET_TIME_absolute_get (); purp.size = htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose)); purp.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST); for (i = 0; i < ITER; i++) { FPRINTF (stderr, "%s", "."); if (GNUNET_SYSERR == GNUNET_CRYPTO_rsa_sign (hostkey, &purp, &sig)) { FPRINTF (stderr, "%s", "GNUNET_CRYPTO_rsa_sign returned SYSERR\n"); ok = GNUNET_SYSERR; continue; } if (GNUNET_SYSERR == GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TEST, &purp, &sig, &pkey)) { printf ("GNUNET_CRYPTO_rsa_verify failed!\n"); ok = GNUNET_SYSERR; continue; } if (GNUNET_SYSERR != GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN, &purp, &sig, &pkey)) { printf ("GNUNET_CRYPTO_rsa_verify failed to fail!\n"); ok = GNUNET_SYSERR; continue; } } printf ("%d RSA sign/verify operations %llums\n", ITER, (unsigned long long) GNUNET_TIME_absolute_get_duration (start).rel_value); GNUNET_CRYPTO_rsa_key_free (hostkey); return ok; } #if PERF static int testSignPerformance () { struct GNUNET_CRYPTO_RsaPrivateKey *hostkey; struct GNUNET_CRYPTO_RsaSignaturePurpose purp; struct GNUNET_CRYPTO_RsaSignature sig; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; int i; struct GNUNET_TIME_Absolute start; int ok = GNUNET_OK; purp.size = htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose)); purp.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST); FPRINTF (stderr, "%s", "W"); hostkey = GNUNET_CRYPTO_rsa_key_create (); GNUNET_CRYPTO_rsa_key_get_public (hostkey, &pkey); start = GNUNET_TIME_absolute_get (); for (i = 0; i < ITER; i++) { FPRINTF (stderr, "%s", "."); if (GNUNET_SYSERR == GNUNET_CRYPTO_rsa_sign (hostkey, &purp, &sig)) { FPRINTF (stderr, "%s", "GNUNET_CRYPTO_rsa_sign returned SYSERR\n"); ok = GNUNET_SYSERR; continue; } } printf ("%d RSA sign operations %llu ms\n", ITER, (unsigned long long) GNUNET_TIME_absolute_get_duration (start).rel_value); GNUNET_CRYPTO_rsa_key_free (hostkey); return ok; } #endif static int testCreateFromFile () { struct GNUNET_CRYPTO_RsaPrivateKey *key; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded p1; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded p2; key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE); GNUNET_assert (NULL != key); GNUNET_CRYPTO_rsa_key_get_public (key, &p1); GNUNET_CRYPTO_rsa_key_free (key); key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE); GNUNET_assert (NULL != key); GNUNET_CRYPTO_rsa_key_get_public (key, &p2); GNUNET_assert (0 == memcmp (&p1, &p2, sizeof (p1))); GNUNET_CRYPTO_rsa_key_free (key); GNUNET_assert (0 == UNLINK (KEYFILE)); key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE); GNUNET_assert (NULL != key); GNUNET_CRYPTO_rsa_key_get_public (key, &p2); GNUNET_assert (0 != memcmp (&p1, &p2, sizeof (p1))); GNUNET_CRYPTO_rsa_key_free (key); GNUNET_assert (0 == UNLINK (KEYFILE)); return GNUNET_OK; } int main (int argc, char *argv[]) { int failureCount = 0; GNUNET_log_setup ("test-crypto-rsa", "WARNING", NULL); GNUNET_CRYPTO_random_disable_entropy_gathering (); if (GNUNET_OK != testCreateFromFile ()) failureCount++; #if PERF if (GNUNET_OK != testEncryptPerformance ()) failureCount++; if (GNUNET_OK != testSignPerformance ()) failureCount++; #endif if (GNUNET_OK != testEncryptDecryptSK ()) failureCount++; if (GNUNET_OK != testEncryptDecrypt ()) failureCount++; if (GNUNET_OK != testSignVerify ()) failureCount++; if (failureCount != 0) { printf ("\n\n%d TESTS FAILED!\n\n", failureCount); return -1; } return 0; } /* end of main */ gnunet-0.9.3/src/util/test_container_bloomfilter.c0000644000175000017500000001431211760502551017276 00000000000000/* This file is part of GNUnet. (C) 2004, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_container_bloomfilter.c * @brief Testcase for the bloomfilter. * @author Christian Grothoff * @author Igor Wronsky */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_container_lib.h" #define K 4 #define SIZE 65536 #define TESTFILE "/tmp/bloomtest.dat" /** * Generate a random hashcode. */ static void nextHC (GNUNET_HashCode * hc) { GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, hc); } static int add_iterator (void *cls, GNUNET_HashCode * next) { int *ret = cls; GNUNET_HashCode pos; if (0 == (*ret)--) return GNUNET_NO; nextHC (&pos); *next = pos; return GNUNET_YES; } int main (int argc, char *argv[]) { struct GNUNET_CONTAINER_BloomFilter *bf; struct GNUNET_CONTAINER_BloomFilter *bfi; GNUNET_HashCode tmp; int i; int ok1; int ok2; int falseok; char buf[SIZE]; struct stat sbuf; GNUNET_log_setup ("test-container-bloomfilter", "WARNING", NULL); GNUNET_CRYPTO_seed_weak_random (1); if (0 == STAT (TESTFILE, &sbuf)) if (0 != UNLINK (TESTFILE)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "unlink", TESTFILE); bf = GNUNET_CONTAINER_bloomfilter_load (TESTFILE, SIZE, K); for (i = 0; i < 200; i++) { nextHC (&tmp); GNUNET_CONTAINER_bloomfilter_add (bf, &tmp); } GNUNET_CRYPTO_seed_weak_random (1); ok1 = 0; for (i = 0; i < 200; i++) { nextHC (&tmp); if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES) ok1++; } if (ok1 != 200) { printf ("Got %d elements out of" "200 expected after insertion.\n", ok1); GNUNET_CONTAINER_bloomfilter_free (bf); return -1; } if (GNUNET_OK != GNUNET_CONTAINER_bloomfilter_get_raw_data (bf, buf, SIZE)) { GNUNET_CONTAINER_bloomfilter_free (bf); return -1; } GNUNET_CONTAINER_bloomfilter_free (bf); bf = GNUNET_CONTAINER_bloomfilter_load (TESTFILE, SIZE, K); GNUNET_assert (bf != NULL); bfi = GNUNET_CONTAINER_bloomfilter_init (buf, SIZE, K); GNUNET_assert (bfi != NULL); GNUNET_CRYPTO_seed_weak_random (1); ok1 = 0; ok2 = 0; for (i = 0; i < 200; i++) { nextHC (&tmp); if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES) ok1++; if (GNUNET_CONTAINER_bloomfilter_test (bfi, &tmp) == GNUNET_YES) ok2++; } if (ok1 != 200) { printf ("Got %d elements out of 200 " "expected after reloading.\n", ok1); GNUNET_CONTAINER_bloomfilter_free (bf); GNUNET_CONTAINER_bloomfilter_free (bfi); return -1; } if (ok2 != 200) { printf ("Got %d elements out of 200 " "expected after initialization.\n", ok2); GNUNET_CONTAINER_bloomfilter_free (bf); GNUNET_CONTAINER_bloomfilter_free (bfi); return -1; } GNUNET_CRYPTO_seed_weak_random (1); for (i = 0; i < 100; i++) { nextHC (&tmp); GNUNET_CONTAINER_bloomfilter_remove (bf, &tmp); GNUNET_CONTAINER_bloomfilter_remove (bfi, &tmp); } GNUNET_CRYPTO_seed_weak_random (1); ok1 = 0; ok2 = 0; for (i = 0; i < 200; i++) { nextHC (&tmp); if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES) ok1++; if (GNUNET_CONTAINER_bloomfilter_test (bfi, &tmp) == GNUNET_YES) ok2++; } if (ok1 != 100) { printf ("Expected 100 elements in loaded filter" " after adding 200 and deleting 100, got %d\n", ok1); GNUNET_CONTAINER_bloomfilter_free (bf); GNUNET_CONTAINER_bloomfilter_free (bfi); return -1; } if (ok2 != 200) { printf ("Expected 200 elements in initialized filter" " after adding 200 and deleting 100 " "(which should do nothing for a filter not backed by a file), got %d\n", ok2); GNUNET_CONTAINER_bloomfilter_free (bf); GNUNET_CONTAINER_bloomfilter_free (bfi); return -1; } GNUNET_CRYPTO_seed_weak_random (3); GNUNET_CONTAINER_bloomfilter_clear (bf); falseok = 0; for (i = 0; i < 1000; i++) { nextHC (&tmp); if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES) falseok++; } if (falseok > 0) { GNUNET_CONTAINER_bloomfilter_free (bf); GNUNET_CONTAINER_bloomfilter_free (bfi); return -1; } if (GNUNET_OK != GNUNET_CONTAINER_bloomfilter_or (bf, buf, SIZE)) { GNUNET_CONTAINER_bloomfilter_free (bf); GNUNET_CONTAINER_bloomfilter_free (bfi); return -1; } GNUNET_CRYPTO_seed_weak_random (2); i = 20; GNUNET_CONTAINER_bloomfilter_resize (bfi, &add_iterator, &i, SIZE * 2, K); GNUNET_CRYPTO_seed_weak_random (2); i = 20; GNUNET_CONTAINER_bloomfilter_resize (bf, &add_iterator, &i, SIZE * 2, K); GNUNET_CRYPTO_seed_weak_random (2); ok1 = 0; ok2 = 0; for (i = 0; i < 20; i++) { nextHC (&tmp); if (GNUNET_CONTAINER_bloomfilter_test (bf, &tmp) == GNUNET_YES) ok1++; if (GNUNET_CONTAINER_bloomfilter_test (bfi, &tmp) == GNUNET_YES) ok2++; } if (ok1 != 20) { printf ("Expected 20 elements in resized file-backed filter" " after adding 20, got %d\n", ok1); GNUNET_CONTAINER_bloomfilter_free (bf); GNUNET_CONTAINER_bloomfilter_free (bfi); return -1; } if (ok2 != 20) { printf ("Expected 20 elements in resized filter" " after adding 20, got %d\n", ok2); GNUNET_CONTAINER_bloomfilter_free (bf); GNUNET_CONTAINER_bloomfilter_free (bfi); return -1; } GNUNET_CONTAINER_bloomfilter_free (bf); GNUNET_CONTAINER_bloomfilter_free (bfi); GNUNET_break (0 == UNLINK (TESTFILE)); return 0; } gnunet-0.9.3/src/util/test_common_allocation.c0000644000175000017500000000531511760502551016416 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2005, 2006 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_common_allocation.c * @brief testcase for common_allocation.c */ #include "platform.h" #include "gnunet_common.h" static int check () { #define MAX_TESTVAL 1024 char *ptrs[MAX_TESTVAL]; int i; int j; int k; unsigned int ui; /* GNUNET_malloc/GNUNET_free test */ k = 352; /* random start value */ for (i = 1; i < MAX_TESTVAL; i++) { ptrs[i] = GNUNET_malloc (i); for (j = 0; j < i; j++) ptrs[i][j] = k++; } for (i = MAX_TESTVAL - 1; i >= 1; i--) { for (j = i - 1; j >= 0; j--) if (ptrs[i][j] != (char) --k) return 1; GNUNET_free (ptrs[i]); } /* GNUNET_free_non_null test */ GNUNET_free_non_null (NULL); GNUNET_free_non_null (GNUNET_malloc (4)); /* GNUNET_strdup tests */ ptrs[0] = GNUNET_strdup ("bar"); if (0 != strcmp (ptrs[0], "bar")) return 3; /* now realloc */ ptrs[0] = GNUNET_realloc (ptrs[0], 12); strcpy (ptrs[0], "Hello World"); GNUNET_free (ptrs[0]); GNUNET_asprintf (&ptrs[0], "%s %s", "Hello", "World"); GNUNET_assert (strlen (ptrs[0]) == 11); GNUNET_free (ptrs[0]); /* GNUNET_array_grow tests */ ptrs[0] = NULL; ui = 0; GNUNET_array_grow (ptrs[0], ui, 42); if (ui != 42) return 4; GNUNET_array_grow (ptrs[0], ui, 22); if (ui != 22) return 5; for (j = 0; j < 22; j++) ptrs[0][j] = j; GNUNET_array_grow (ptrs[0], ui, 32); for (j = 0; j < 22; j++) if (ptrs[0][j] != j) return 6; for (j = 22; j < 32; j++) if (ptrs[0][j] != 0) return 7; GNUNET_array_grow (ptrs[0], ui, 0); if (i != 0) return 8; if (ptrs[0] != NULL) return 9; return 0; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-common-allocation", "WARNING", NULL); ret = check (); if (ret != 0) FPRINTF (stderr, "ERROR %d.\n", ret); return ret; } /* end of test_common_allocation.c */ gnunet-0.9.3/src/util/os_network.c0000644000175000017500000001733711760502551014063 00000000000000/* This file is part of GNUnet. (C) 2004, 2005, 2006 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/os_network.c * @brief function to determine available network interfaces * @author Nils Durner * @author Heikki Lindholm * @author Jake Dust * @author LRN */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_os_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) /** * @brief Enumerate all network interfaces * * @param proc the callback function * @param proc_cls closure for proc */ void GNUNET_OS_network_interfaces_list (GNUNET_OS_NetworkInterfaceProcessor proc, void *proc_cls) { #ifdef MINGW int r; int i; struct EnumNICs3_results *results = NULL; int results_count; r = EnumNICs3 (&results, &results_count); if (r != GNUNET_OK) return; for (i = 0; i < results_count; i++) { if (GNUNET_OK != proc (proc_cls, results[i].pretty_name, results[i].is_default, (const struct sockaddr *) &results[i].address, results[i]. flags & ENUMNICS3_BCAST_OK ? (const struct sockaddr *) &results[i].broadcast : NULL, results[i].flags & ENUMNICS3_MASK_OK ? (const struct sockaddr *) &results[i].mask : NULL, results[i].addr_size)) break; } EnumNICs3_free (results); return; #elif HAVE_GETIFADDRS && HAVE_FREEIFADDRS struct ifaddrs *ifa_first; struct ifaddrs *ifa_ptr; socklen_t alen; if (getifaddrs (&ifa_first) == 0) { for (ifa_ptr = ifa_first; ifa_ptr != NULL; ifa_ptr = ifa_ptr->ifa_next) { if (ifa_ptr->ifa_name != NULL && ifa_ptr->ifa_addr != NULL && (ifa_ptr->ifa_flags & IFF_UP) != 0) { if ((ifa_ptr->ifa_addr->sa_family != AF_INET) && (ifa_ptr->ifa_addr->sa_family != AF_INET6)) continue; if (ifa_ptr->ifa_addr->sa_family == AF_INET) alen = sizeof (struct sockaddr_in); else alen = sizeof (struct sockaddr_in6); if (GNUNET_OK != proc (proc_cls, ifa_ptr->ifa_name, 0 == strcmp (ifa_ptr->ifa_name, GNUNET_DEFAULT_INTERFACE), ifa_ptr->ifa_addr, ifa_ptr->ifa_broadaddr, ifa_ptr->ifa_netmask, alen)) break; } } freeifaddrs (ifa_first); } #else int i; char line[1024]; char *replace; const char *start; char ifc[12]; char addrstr[128]; char bcstr[128]; char netmaskstr[128]; FILE *f; int have_ifc; struct sockaddr_in a4; struct sockaddr_in6 a6; struct in_addr v4; struct in6_addr v6; struct sockaddr_in bcaddr; struct sockaddr_in netmask; struct sockaddr_in6 netmask6; struct sockaddr *pass_bcaddr; struct sockaddr *pass_netmask; int prefixlen; if (system ("ifconfig -a > /dev/null 2> /dev/null")) if (system ("/sbin/ifconfig -a > /dev/null 2> /dev/null") == 0) f = popen ("/sbin/ifconfig -a 2> /dev/null", "r"); else f = NULL; else f = popen ("ifconfig -a 2> /dev/null", "r"); if (!f) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "popen", "ifconfig"); return; } have_ifc = GNUNET_NO; ifc[11] = '\0'; while (NULL != fgets (line, sizeof (line), f)) { if (strlen (line) == 0) { have_ifc = GNUNET_NO; continue; } if (!isspace (line[0])) { have_ifc = (1 == SSCANF (line, "%11s", ifc)) ? GNUNET_YES : GNUNET_NO; /* would end with ':' on OSX, fix it! */ if (ifc[strlen (ifc) - 1] == ':') ifc[strlen (ifc) - 1] = '\0'; continue; } if (!have_ifc) continue; /* strange input, hope for the best */ /* make parsing of ipv6 addresses easier */ for (replace = line; *replace != '\0'; replace++) { if (*replace == '/') *replace = ' '; } prefixlen = -1; start = line; while (('\0' != *start) && (isspace (*start))) start++; /* Zero-out stack allocated values */ memset (addrstr, 0, 128); memset (netmaskstr, 0, 128); memset (bcstr, 0, 128); prefixlen = 0; if ( /* Linux */ (3 == SSCANF (start, "inet addr:%127s Bcast:%127s Mask:%127s", addrstr, bcstr, netmaskstr)) || (2 == SSCANF (start, "inet addr:%127s Mask:%127s", addrstr, netmaskstr)) || (2 == SSCANF (start, "inet6 addr:%127s %d", addrstr, &prefixlen)) || /* Solaris, OS X */ (1 == SSCANF (start, "inet %127s", addrstr)) || (1 == SSCANF (start, "inet6 %127s", addrstr))) { /* IPv4 */ if (1 == inet_pton (AF_INET, addrstr, &v4)) { memset (&a4, 0, sizeof (a4)); a4.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN a4.sin_len = (u_char) sizeof (struct sockaddr_in); #endif a4.sin_addr = v4; pass_bcaddr = NULL; pass_netmask = NULL; if (1 == inet_pton (AF_INET, bcstr, &v4)) { memset (&bcaddr, 0, sizeof (bcaddr)); bcaddr.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN bcaddr.sin_len = (u_char) sizeof (struct sockaddr_in); #endif bcaddr.sin_addr = v4; pass_bcaddr = (struct sockaddr *) &bcaddr; } if (1 == inet_pton (AF_INET, netmaskstr, &v4)) { memset (&netmask, 0, sizeof (netmask)); netmask.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN netmask.sin_len = (u_char) sizeof (struct sockaddr_in); #endif netmask.sin_addr = v4; pass_netmask = (struct sockaddr *) &netmask; } if (GNUNET_OK != proc (proc_cls, ifc, 0 == strcmp (ifc, GNUNET_DEFAULT_INTERFACE), (const struct sockaddr *) &a4, pass_bcaddr, pass_netmask, sizeof (a4))) break; continue; } /* IPv6 */ if (1 == inet_pton (AF_INET6, addrstr, &v6)) { memset (&a6, 0, sizeof (a6)); a6.sin6_family = AF_INET6; #if HAVE_SOCKADDR_IN_SIN_LEN a6.sin6_len = (u_char) sizeof (struct sockaddr_in6); #endif a6.sin6_addr = v6; pass_netmask = NULL; if (prefixlen != -1) { memset (v6.s6_addr, 0, sizeof (v6.s6_addr)); for (i = 0; i < prefixlen; i++) { v6.s6_addr[i >> 3] |= 1 << (i & 7); } memset (&netmask6, 0, sizeof (netmask6)); netmask6.sin6_family = AF_INET6; #if HAVE_SOCKADDR_IN_SIN_LEN netmask6.sin6_len = (u_char) sizeof (struct sockaddr_in6); #endif netmask6.sin6_addr = v6; pass_netmask = (struct sockaddr *) &netmask6; } if (GNUNET_OK != proc (proc_cls, ifc, 0 == strcmp (ifc, GNUNET_DEFAULT_INTERFACE), (const struct sockaddr *) &a6, NULL, pass_netmask, sizeof (a6))) break; continue; } } } pclose (f); #endif } /* end of os_network.c */ gnunet-0.9.3/src/util/bio.c0000644000175000017500000003063011760502551012431 00000000000000/* This file is part of GNUnet. (C) 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/bio.c * @brief functions for buffering IO * @author Christian Grothoff */ #include "platform.h" #include "gnunet_bio_lib.h" #include "gnunet_disk_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util",__VA_ARGS__) #define BIO_BUFFER_SIZE 65536 #define MAX_META_DATA (1024 * 1024) /** * Handle for buffered reading. */ struct GNUNET_BIO_ReadHandle { struct GNUNET_DISK_FileHandle *fd; char *emsg; char *buffer; size_t have; size_t size; off_t pos; }; /** * Open a file for reading. * * @param fn file name to be opened * @return IO handle on success, NULL on error */ struct GNUNET_BIO_ReadHandle * GNUNET_BIO_read_open (const char *fn) { struct GNUNET_DISK_FileHandle *fd; struct GNUNET_BIO_ReadHandle *h; fd = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); if (NULL == fd) return NULL; h = GNUNET_malloc (sizeof (struct GNUNET_BIO_ReadHandle) + BIO_BUFFER_SIZE); h->buffer = (char *) &h[1]; h->size = BIO_BUFFER_SIZE; h->fd = fd; return h; } /** * Close an open file. Reports if any errors reading * from the file were encountered. * * @param h file handle * @param emsg set to the error message * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_BIO_read_close (struct GNUNET_BIO_ReadHandle *h, char **emsg) { int err; err = (NULL == h->emsg) ? GNUNET_OK : GNUNET_SYSERR; if (emsg != NULL) *emsg = h->emsg; else GNUNET_free_non_null (h->emsg); GNUNET_DISK_file_close (h->fd); GNUNET_free (h); return err; } /** * Read the contents of a binary file into a buffer. * * @param h handle to an open file * @param what describes what is being read (for error message creation) * @param result the buffer to write the result to * @param len the number of bytes to read * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int GNUNET_BIO_read (struct GNUNET_BIO_ReadHandle *h, const char *what, void *result, size_t len) { char *dst = result; size_t min; size_t pos; ssize_t ret; if (h->emsg != NULL) return GNUNET_SYSERR; pos = 0; do { /* first, use buffer */ min = h->have - h->pos; if (min > 0) { if (min > len - pos) min = len - pos; memcpy (&dst[pos], &h->buffer[h->pos], min); h->pos += min; pos += min; } if (pos == len) return GNUNET_OK; /* done! */ GNUNET_assert (h->have == h->pos); /* fill buffer */ ret = GNUNET_DISK_file_read (h->fd, h->buffer, h->size); if (ret == -1) { GNUNET_asprintf (&h->emsg, _("Error reading `%s': %s"), what, STRERROR (errno)); return GNUNET_SYSERR; } if (ret == 0) { GNUNET_asprintf (&h->emsg, _("Error reading `%s': %s"), what, _("End of file")); return GNUNET_SYSERR; } h->pos = 0; h->have = ret; } while (pos < len); /* should always be true */ return GNUNET_OK; } /** * Read the contents of a binary file into a buffer. * * @param h handle to an open file * @param file name of the source file * @param line line number in the source file * @param result the buffer to write the result to * @param len the number of bytes to read * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int GNUNET_BIO_read_fn (struct GNUNET_BIO_ReadHandle *h, const char *file, int line, void *result, size_t len) { char what[1024]; GNUNET_snprintf (what, sizeof (what), "%s:%d", file, line); return GNUNET_BIO_read (h, what, result, len); } /** * Read 0-terminated string from a file. * * @param h handle to an open file * @param what describes what is being read (for error message creation) * @param result the buffer to store a pointer to the (allocated) string to * (note that *result could be set to NULL as well) * @param maxLen maximum allowed length for the string * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int GNUNET_BIO_read_string (struct GNUNET_BIO_ReadHandle *h, const char *what, char **result, size_t maxLen) { char *buf; uint32_t big; if (GNUNET_OK != GNUNET_BIO_read_int32 (h, &big)) { GNUNET_free_non_null (h->emsg); GNUNET_asprintf (&h->emsg, _("Error reading length of string `%s'"), what); return GNUNET_SYSERR; } if (big == 0) { *result = NULL; return GNUNET_OK; } if (big > maxLen) { GNUNET_asprintf (&h->emsg, _("String `%s' longer than allowed (%u > %u)"), what, big, maxLen); return GNUNET_SYSERR; } buf = GNUNET_malloc (big); *result = buf; buf[--big] = '\0'; if (big == 0) return GNUNET_OK; if (GNUNET_OK != GNUNET_BIO_read (h, what, buf, big)) { GNUNET_free (buf); *result = NULL; return GNUNET_SYSERR; } return GNUNET_OK; } /** * Read metadata container from a file. * * @param h handle to an open file * @param what describes what is being read (for error message creation) * @param result the buffer to store a pointer to the (allocated) metadata * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int GNUNET_BIO_read_meta_data (struct GNUNET_BIO_ReadHandle *h, const char *what, struct GNUNET_CONTAINER_MetaData **result) { uint32_t size; char *buf; struct GNUNET_CONTAINER_MetaData *meta; if (GNUNET_BIO_read_int32 (h, (int32_t *) & size) != GNUNET_OK) return GNUNET_SYSERR; if (size == 0) { *result = NULL; return GNUNET_OK; } if (size > MAX_META_DATA) { GNUNET_asprintf (&h->emsg, _("Serialized metadata `%s' larger than allowed (%u>%u)"), what, size, MAX_META_DATA); return GNUNET_SYSERR; } buf = GNUNET_malloc (size); if (GNUNET_OK != GNUNET_BIO_read (h, what, buf, size)) { GNUNET_free (buf); return GNUNET_SYSERR; } meta = GNUNET_CONTAINER_meta_data_deserialize (buf, size); if (meta == NULL) { GNUNET_free (buf); GNUNET_asprintf (&h->emsg, _("Metadata `%s' failed to deserialize"), what); return GNUNET_SYSERR; } GNUNET_free (buf); *result = meta; return GNUNET_OK; } /** * Read an (u)int32_t. * * @param h hande to open file * @param file name of the source file * @param line line number in the source file * @param i address of 32-bit integer to read * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_BIO_read_int32__ (struct GNUNET_BIO_ReadHandle *h, const char *file, int line, int32_t * i) { int32_t big; if (GNUNET_OK != GNUNET_BIO_read_fn (h, file, line, &big, sizeof (int32_t))) return GNUNET_SYSERR; *i = ntohl (big); return GNUNET_OK; } /** * Read an (u)int64_t. * * @param h hande to open file * @param file name of the source file * @param line line number in the source file * @param i address of 64-bit integer to read * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_BIO_read_int64__ (struct GNUNET_BIO_ReadHandle *h, const char *file, int line, int64_t * i) { int64_t big; if (GNUNET_OK != GNUNET_BIO_read_fn (h, file, line, &big, sizeof (int64_t))) return GNUNET_SYSERR; *i = GNUNET_ntohll (big); return GNUNET_OK; } /** * Handle for buffered writing. */ struct GNUNET_BIO_WriteHandle { struct GNUNET_DISK_FileHandle *fd; char *buffer; size_t have; size_t size; }; /** * Open a file for writing. * * @param fn file name to be opened * @return IO handle on success, NULL on error */ struct GNUNET_BIO_WriteHandle * GNUNET_BIO_write_open (const char *fn) { struct GNUNET_DISK_FileHandle *fd; struct GNUNET_BIO_WriteHandle *h; fd = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE | GNUNET_DISK_OPEN_CREATE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (NULL == fd) return NULL; h = GNUNET_malloc (sizeof (struct GNUNET_BIO_WriteHandle) + BIO_BUFFER_SIZE); h->buffer = (char *) &h[1]; h->size = BIO_BUFFER_SIZE; h->fd = fd; return h; } /** * Close an open file for writing. * * @param h file handle * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_BIO_write_close (struct GNUNET_BIO_WriteHandle *h) { ssize_t wrt; int ret; if (NULL == h->fd) { ret = GNUNET_SYSERR; } else { wrt = GNUNET_DISK_file_write (h->fd, h->buffer, h->have); if (wrt == h->have) ret = GNUNET_OK; else ret = GNUNET_SYSERR; GNUNET_DISK_file_close (h->fd); } GNUNET_free (h); return ret; } /** * Write a buffer to a file. * * @param h handle to open file * @param buffer the data to write * @param n number of bytes to write * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_BIO_write (struct GNUNET_BIO_WriteHandle *h, const void *buffer, size_t n) { const char *src = buffer; size_t min; size_t pos; ssize_t ret; if (NULL == h->fd) return GNUNET_SYSERR; pos = 0; do { /* first, just use buffer */ min = h->size - h->have; if (min > n - pos) min = n - pos; memcpy (&h->buffer[h->have], &src[pos], min); pos += min; h->have += min; if (pos == n) return GNUNET_OK; /* done */ GNUNET_assert (h->have == h->size); ret = GNUNET_DISK_file_write (h->fd, h->buffer, h->size); if (ret != h->size) { GNUNET_DISK_file_close (h->fd); h->fd = NULL; return GNUNET_SYSERR; /* error */ } h->have = 0; } while (pos < n); /* should always be true */ GNUNET_break (0); return GNUNET_OK; } /** * Write a string to a file. * * @param h handle to open file * @param s string to write (can be NULL) * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_BIO_write_string (struct GNUNET_BIO_WriteHandle *h, const char *s) { uint32_t slen; slen = (uint32_t) ((s == NULL) ? 0 : strlen (s) + 1); if (GNUNET_OK != GNUNET_BIO_write_int32 (h, slen)) return GNUNET_SYSERR; if (0 != slen) return GNUNET_BIO_write (h, s, slen - 1); return GNUNET_OK; } /** * Write metadata container to a file. * * @param h handle to open file * @param m metadata to write * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_BIO_write_meta_data (struct GNUNET_BIO_WriteHandle *h, const struct GNUNET_CONTAINER_MetaData *m) { ssize_t size; char *buf; if (m == NULL) return GNUNET_BIO_write_int32 (h, 0); buf = NULL; size = GNUNET_CONTAINER_meta_data_serialize (m, &buf, MAX_META_DATA, GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); if (size == -1) { GNUNET_free (buf); return GNUNET_SYSERR; } if ((GNUNET_OK != GNUNET_BIO_write_int32 (h, (uint32_t) size)) || (GNUNET_OK != GNUNET_BIO_write (h, buf, size))) { GNUNET_free (buf); return GNUNET_SYSERR; } GNUNET_free (buf); return GNUNET_OK; } /** * Write an (u)int32_t. * * @param h hande to open file * @param i 32-bit integer to write * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_BIO_write_int32 (struct GNUNET_BIO_WriteHandle *h, int32_t i) { int32_t big; big = htonl (i); return GNUNET_BIO_write (h, &big, sizeof (int32_t)); } /** * Write an (u)int64_t. * * @param h hande to open file * @param i 64-bit integer to write * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_BIO_write_int64 (struct GNUNET_BIO_WriteHandle *h, int64_t i) { int64_t big; big = GNUNET_htonll (i); return GNUNET_BIO_write (h, &big, sizeof (int64_t)); } /* end of bio.c */ gnunet-0.9.3/src/util/test_program_data.conf0000644000175000017500000000000011667453373016063 00000000000000gnunet-0.9.3/src/util/server_nc.c0000644000175000017500000003027711760502551013655 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/server_nc.c * @brief convenience functions for transmission of * a notification stream * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_connection_lib.h" #include "gnunet_container_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_server_lib.h" #include "gnunet_time_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) /** * Entry in list of messages pending to be transmitted. */ struct PendingMessageList { /** * This is a doubly-linked list. */ struct PendingMessageList *next; /** * This is a doubly-linked list. */ struct PendingMessageList *prev; /** * Message to transmit (allocated at the end of this * struct, do not free) */ const struct GNUNET_MessageHeader *msg; /** * Can this message be dropped? */ int can_drop; }; /** * Lists of clients we manage for notifications. */ struct ClientList { /** * This is a doubly linked list. */ struct ClientList *next; /** * This is a doubly linked list. */ struct ClientList *prev; /** * Overall context this client belongs to. */ struct GNUNET_SERVER_NotificationContext *nc; /** * Handle to the client. */ struct GNUNET_SERVER_Client *client; /** * Handle for pending transmission request to the client (or NULL). */ struct GNUNET_SERVER_TransmitHandle *th; /** * Head of linked list of requests queued for transmission. */ struct PendingMessageList *pending_head; /** * Tail of linked list of requests queued for transmission. */ struct PendingMessageList *pending_tail; /** * Number of messages currently in the list. */ unsigned int num_pending; }; /** * The notification context is the key datastructure for a convenience * API used for transmission of notifications to the client until the * client disconnects (or the notification context is destroyed, in * which case we disconnect these clients). Essentially, all * (notification) messages are queued up until the client is able to * read them. */ struct GNUNET_SERVER_NotificationContext { /** * Server we do notifications for. */ struct GNUNET_SERVER_Handle *server; /** * Head of list of clients receiving notifications. */ struct ClientList *clients_head; /** * Tail of list of clients receiving notifications. */ struct ClientList *clients_tail; /** * Maximum number of optional messages to queue per client. */ unsigned int queue_length; }; /** * Client has disconnected, clean up. * * @param cls our 'struct GNUNET_SERVER_NotificationContext *' * @param client handle of client that disconnected */ static void handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) { struct GNUNET_SERVER_NotificationContext *nc = cls; struct ClientList *pos; struct PendingMessageList *pml; if (NULL == client) { nc->server = NULL; return; } for (pos = nc->clients_head; NULL != pos; pos = pos->next) if (pos->client == client) break; if (NULL == pos) return; LOG (GNUNET_ERROR_TYPE_DEBUG, "Client disconnected, cleaning up %u messages in NC queue\n", pos->num_pending); GNUNET_CONTAINER_DLL_remove (nc->clients_head, nc->clients_tail, pos); while (NULL != (pml = pos->pending_head)) { GNUNET_CONTAINER_DLL_remove (pos->pending_head, pos->pending_tail, pml); GNUNET_free (pml); pos->num_pending--; } if (NULL != pos->th) { GNUNET_SERVER_notify_transmit_ready_cancel (pos->th); pos->th = NULL; } GNUNET_SERVER_client_drop (client); GNUNET_assert (0 == pos->num_pending); GNUNET_free (pos); } /** * Create a new notification context. * * @param server server for which this function creates the context * @param queue_length maximum number of messages to keep in * the notification queue; optional messages are dropped * it the queue gets longer than this number of messages * @return handle to the notification context */ struct GNUNET_SERVER_NotificationContext * GNUNET_SERVER_notification_context_create (struct GNUNET_SERVER_Handle *server, unsigned int queue_length) { struct GNUNET_SERVER_NotificationContext *ret; ret = GNUNET_malloc (sizeof (struct GNUNET_SERVER_NotificationContext)); ret->server = server; ret->queue_length = queue_length; GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, ret); return ret; } /** * Destroy the context, force disconnect for all clients. * * @param nc context to destroy. */ void GNUNET_SERVER_notification_context_destroy (struct GNUNET_SERVER_NotificationContext *nc) { struct ClientList *pos; struct PendingMessageList *pml; while (NULL != (pos = nc->clients_head)) { GNUNET_CONTAINER_DLL_remove (nc->clients_head, nc->clients_tail, pos); if (NULL != pos->th) { GNUNET_SERVER_notify_transmit_ready_cancel(pos->th); pos->th = NULL; } GNUNET_SERVER_client_drop (pos->client); while (NULL != (pml = pos->pending_head)) { GNUNET_CONTAINER_DLL_remove (pos->pending_head, pos->pending_tail, pml); GNUNET_free (pml); pos->num_pending--; } GNUNET_assert (0 == pos->num_pending); GNUNET_free (pos); } if (NULL != nc->server) GNUNET_SERVER_disconnect_notify_cancel (nc->server, &handle_client_disconnect, nc); GNUNET_free (nc); } /** * Add a client to the notification context. * * @param nc context to modify * @param client client to add */ void GNUNET_SERVER_notification_context_add (struct GNUNET_SERVER_NotificationContext *nc, struct GNUNET_SERVER_Client *client) { struct ClientList *cl; for (cl = nc->clients_head; NULL != cl; cl = cl->next) if (cl->client == client) return; /* already present */ cl = GNUNET_malloc (sizeof (struct ClientList)); GNUNET_CONTAINER_DLL_insert (nc->clients_head, nc->clients_tail, cl); cl->nc = nc; cl->client = client; GNUNET_SERVER_client_keep (client); } /** * Function called to notify a client about the socket begin ready to * queue more data. "buf" will be NULL and "size" zero if the socket * was closed for writing in the meantime. * * @param cls the 'struct ClientList *' * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_message (void *cls, size_t size, void *buf) { struct ClientList *cl = cls; char *cbuf = buf; struct PendingMessageList *pml; uint16_t msize; size_t ret; cl->th = NULL; if (NULL == buf) { /* 'cl' should be freed via disconnect notification shortly */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to transmit message from NC queue to client\n"); return 0; } ret = 0; while (NULL != (pml = cl->pending_head)) { msize = ntohs (pml->msg->size); if (size < msize) break; GNUNET_CONTAINER_DLL_remove (cl->pending_head, cl->pending_tail, pml); LOG (GNUNET_ERROR_TYPE_DEBUG, "Copying message of type %u and size %u from pending queue to transmission buffer\n", ntohs (pml->msg->type), msize); memcpy (&cbuf[ret], pml->msg, msize); ret += msize; size -= msize; GNUNET_free (pml); cl->num_pending--; } if (NULL != pml) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Have %u messages left in NC queue, will try transmission again\n", cl->num_pending); cl->th = GNUNET_SERVER_notify_transmit_ready (cl->client, ntohs (pml->msg->size), GNUNET_TIME_UNIT_FOREVER_REL, &transmit_message, cl); } else { GNUNET_assert (0 == cl->num_pending); } return ret; } /** * Send a message to a particular client. * * @param nc context to modify * @param client client to transmit to * @param msg message to send * @param can_drop can this message be dropped due to queue length limitations */ static void do_unicast (struct GNUNET_SERVER_NotificationContext *nc, struct ClientList *client, const struct GNUNET_MessageHeader *msg, int can_drop) { struct PendingMessageList *pml; uint16_t size; if ((client->num_pending > nc->queue_length) && (GNUNET_YES == can_drop)) { LOG (GNUNET_ERROR_TYPE_INFO, "Dropping message of type %u and size %u due to full queue (%u entries)\n", ntohs (msg->type), ntohs (msg->size), (unsigned int) nc->queue_length); return; /* drop! */ } if (client->num_pending > nc->queue_length) { /* FIXME: consider checking for other messages in the * queue that are 'droppable' */ } client->num_pending++; size = ntohs (msg->size); pml = GNUNET_malloc (sizeof (struct PendingMessageList) + size); pml->msg = (const struct GNUNET_MessageHeader *) &pml[1]; pml->can_drop = can_drop; LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding message of type %u and size %u to pending queue (which has %u entries)\n", ntohs (msg->type), ntohs (msg->size), (unsigned int) nc->queue_length); memcpy (&pml[1], msg, size); /* append */ GNUNET_CONTAINER_DLL_insert_tail (client->pending_head, client->pending_tail, pml); if (client->th == NULL) client->th = GNUNET_SERVER_notify_transmit_ready (client->client, ntohs (client->pending_head-> msg->size), GNUNET_TIME_UNIT_FOREVER_REL, &transmit_message, client); } /** * Send a message to a particular client; must have * already been added to the notification context. * * @param nc context to modify * @param client client to transmit to * @param msg message to send * @param can_drop can this message be dropped due to queue length limitations */ void GNUNET_SERVER_notification_context_unicast (struct GNUNET_SERVER_NotificationContext *nc, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *msg, int can_drop) { struct ClientList *pos; for (pos = nc->clients_head; NULL != pos; pos = pos->next) if (pos->client == client) break; GNUNET_assert (NULL != pos); do_unicast (nc, pos, msg, can_drop); } /** * Send a message to all clients of this context. * * @param nc context to modify * @param msg message to send * @param can_drop can this message be dropped due to queue length limitations */ void GNUNET_SERVER_notification_context_broadcast (struct GNUNET_SERVER_NotificationContext *nc, const struct GNUNET_MessageHeader *msg, int can_drop) { struct ClientList *pos; for (pos = nc->clients_head; NULL != pos; pos = pos->next) do_unicast (nc, pos, msg, can_drop); } /* end of server_nc.c */ gnunet-0.9.3/src/util/test_crypto_hash.c0000644000175000017500000001053611760502551015245 00000000000000/* This file is part of GNUnet. (C) 2002, 2003, 2004, 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @author Christian Grothoff * @file util/test_crypto_hash.c * @brief Test for crypto_hash.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_crypto_lib.h" #include "gnunet_scheduler_lib.h" static char block[65536]; #define FILENAME "testblock.dat" static int test (int number) { GNUNET_HashCode h1; GNUNET_HashCode h2; struct GNUNET_CRYPTO_HashAsciiEncoded enc; memset (&h1, number, sizeof (GNUNET_HashCode)); GNUNET_CRYPTO_hash_to_enc (&h1, &enc); if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &h2)) { printf ("enc2hash failed!\n"); return 1; } if (0 != memcmp (&h1, &h2, sizeof (GNUNET_HashCode))) return 1; return 0; } static int testEncoding () { int i; for (i = 0; i < 255; i++) if (0 != test (i)) return 1; return 0; } static int testArithmetic () { static struct GNUNET_CRYPTO_AesSessionKey zskey; static struct GNUNET_CRYPTO_AesInitializationVector ziv; GNUNET_HashCode h1; GNUNET_HashCode h2; GNUNET_HashCode d; GNUNET_HashCode s; struct GNUNET_CRYPTO_AesSessionKey skey; struct GNUNET_CRYPTO_AesInitializationVector iv; GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &h1); GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &h2); if (GNUNET_CRYPTO_hash_distance_u32 (&h1, &h2) != GNUNET_CRYPTO_hash_distance_u32 (&h2, &h1)) return 1; GNUNET_CRYPTO_hash_difference (&h1, &h2, &d); GNUNET_CRYPTO_hash_sum (&h1, &d, &s); if (0 != GNUNET_CRYPTO_hash_cmp (&s, &h2)) return 1; GNUNET_CRYPTO_hash_xor (&h1, &h2, &d); GNUNET_CRYPTO_hash_xor (&h1, &d, &s); if (0 != GNUNET_CRYPTO_hash_cmp (&s, &h2)) return 1; if (0 != GNUNET_CRYPTO_hash_xorcmp (&s, &h2, &h1)) return 1; if (-1 != GNUNET_CRYPTO_hash_xorcmp (&h1, &h2, &h1)) return 1; if (1 != GNUNET_CRYPTO_hash_xorcmp (&h1, &h2, &h2)) return 1; memset (&d, 0xF0, sizeof (d)); if (0 != GNUNET_CRYPTO_hash_get_bit (&d, 3)) return 1; if (1 != GNUNET_CRYPTO_hash_get_bit (&d, 6)) return 1; memset (&d, 0, sizeof (d)); GNUNET_CRYPTO_hash_to_aes_key (&d, &skey, &iv); if ((0 != memcmp (&skey, &zskey, sizeof (skey) - sizeof (unsigned int))) || (0 != memcmp (&iv, &ziv, sizeof (iv)))) return 1; return 0; } static void finished_task (void *cls, const GNUNET_HashCode * res) { int *ret = cls; GNUNET_HashCode want; GNUNET_CRYPTO_hash (block, sizeof (block), &want); if (0 != memcmp (res, &want, sizeof (want))) *ret = 2; else *ret = 0; } static void file_hasher (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_assert (NULL != GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_DEFAULT, FILENAME, 1024, &finished_task, cls)); } static int testFileHash () { int ret; FILE *f; memset (block, 42, sizeof (block) / 2); memset (&block[sizeof (block) / 2], 43, sizeof (block) / 2); GNUNET_assert (NULL != (f = FOPEN (FILENAME, "w+"))); GNUNET_break (sizeof (block) == fwrite (block, 1, sizeof (block), f)); GNUNET_break (0 == FCLOSE (f)); ret = 1; GNUNET_SCHEDULER_run (&file_hasher, &ret); GNUNET_break (0 == UNLINK (FILENAME)); return ret; } int main (int argc, char *argv[]) { int failureCount = 0; int i; GNUNET_log_setup ("test-crypto-hash", "WARNING", NULL); for (i = 0; i < 10; i++) failureCount += testEncoding (); failureCount += testArithmetic (); failureCount += testFileHash (); if (failureCount != 0) return 1; return 0; } /* end of hashingtest.c */ gnunet-0.9.3/src/util/server_mst.c0000644000175000017500000002066711760502551014062 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/server_mst.c * @brief convenience functions for handling inbound message buffers * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_connection_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_server_lib.h" #include "gnunet_time_lib.h" #if HAVE_UNALIGNED_64_ACCESS #define ALIGN_FACTOR 4 #else #define ALIGN_FACTOR 8 #endif #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) /** * Handle to a message stream tokenizer. */ struct GNUNET_SERVER_MessageStreamTokenizer { /** * Function to call on completed messages. */ GNUNET_SERVER_MessageTokenizerCallback cb; /** * Closure for cb. */ void *cb_cls; /** * Size of the buffer (starting at 'hdr'). */ size_t curr_buf; /** * How many bytes in buffer have we already processed? */ size_t off; /** * How many bytes in buffer are valid right now? */ size_t pos; /** * Beginning of the buffer. Typed like this to force alignment. */ struct GNUNET_MessageHeader *hdr; }; /** * Create a message stream tokenizer. * * @param cb function to call on completed messages * @param cb_cls closure for cb * @return handle to tokenizer */ struct GNUNET_SERVER_MessageStreamTokenizer * GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb, void *cb_cls) { struct GNUNET_SERVER_MessageStreamTokenizer *ret; ret = GNUNET_malloc (sizeof (struct GNUNET_SERVER_MessageStreamTokenizer)); ret->hdr = GNUNET_malloc (GNUNET_SERVER_MIN_BUFFER_SIZE); ret->curr_buf = GNUNET_SERVER_MIN_BUFFER_SIZE; ret->cb = cb; ret->cb_cls = cb_cls; return ret; } /** * Add incoming data to the receive buffer and call the * callback for all complete messages. * * @param mst tokenizer to use * @param client_identity ID of client for which this is a buffer * @param buf input data to add * @param size number of bytes in buf * @param purge should any excess bytes in the buffer be discarded * (i.e. for packet-based services like UDP) * @param one_shot only call callback once, keep rest of message in buffer * @return GNUNET_OK if we are done processing (need more data) * GNUNET_NO if one_shot was set and we have another message ready * GNUNET_SYSERR if the data stream is corrupt */ int GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst, void *client_identity, const char *buf, size_t size, int purge, int one_shot) { const struct GNUNET_MessageHeader *hdr; size_t delta; uint16_t want; char *ibuf; int need_align; unsigned long offset; int ret; GNUNET_assert (mst->off <= mst->pos); GNUNET_assert (mst->pos <= mst->curr_buf); LOG (GNUNET_ERROR_TYPE_DEBUG, "Server-mst receives %u bytes with %u bytes already in private buffer\n", (unsigned int) size, (unsigned int) (mst->pos - mst->off)); ret = GNUNET_OK; ibuf = (char *) mst->hdr; while (mst->pos > 0) { do_align: GNUNET_assert (mst->pos >= mst->off); if ((mst->curr_buf - mst->off < sizeof (struct GNUNET_MessageHeader)) || (0 != (mst->off % ALIGN_FACTOR))) { /* need to align or need more space */ mst->pos -= mst->off; memmove (ibuf, &ibuf[mst->off], mst->pos); mst->off = 0; } if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader)) { delta = GNUNET_MIN (sizeof (struct GNUNET_MessageHeader) - (mst->pos - mst->off), size); memcpy (&ibuf[mst->pos], buf, delta); mst->pos += delta; buf += delta; size -= delta; } if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader)) { if (purge) { mst->off = 0; mst->pos = 0; } return GNUNET_OK; } hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off]; want = ntohs (hdr->size); if (want < sizeof (struct GNUNET_MessageHeader)) { GNUNET_break_op (0); return GNUNET_SYSERR; } if ( (mst->curr_buf - mst->off < want) && (mst->off > 0) ) { /* can get more space by moving */ mst->pos -= mst->off; memmove (ibuf, &ibuf[mst->off], mst->pos); mst->off = 0; } if (mst->curr_buf < want) { /* need to get more space by growing buffer */ GNUNET_assert (0 == mst->off); mst->hdr = GNUNET_realloc (mst->hdr, want); ibuf = (char *) mst->hdr; mst->curr_buf = want; } hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off]; if (mst->pos - mst->off < want) { delta = GNUNET_MIN (want - (mst->pos - mst->off), size); GNUNET_assert (mst->pos + delta <= mst->curr_buf); memcpy (&ibuf[mst->pos], buf, delta); mst->pos += delta; buf += delta; size -= delta; } if (mst->pos - mst->off < want) { if (purge) { mst->off = 0; mst->pos = 0; } return GNUNET_OK; } if (one_shot == GNUNET_SYSERR) { /* cannot call callback again, but return value saying that * we have another full message in the buffer */ ret = GNUNET_NO; goto copy; } if (one_shot == GNUNET_YES) one_shot = GNUNET_SYSERR; mst->off += want; if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr)) return GNUNET_SYSERR; if (mst->off == mst->pos) { /* reset to beginning of buffer, it's free right now! */ mst->off = 0; mst->pos = 0; } } GNUNET_assert (0 == mst->pos); while (size > 0) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Server-mst has %u bytes left in inbound buffer\n", (unsigned int) size); if (size < sizeof (struct GNUNET_MessageHeader)) break; offset = (unsigned long) buf; need_align = (0 != (offset % ALIGN_FACTOR)) ? GNUNET_YES : GNUNET_NO; if (GNUNET_NO == need_align) { /* can try to do zero-copy and process directly from original buffer */ hdr = (const struct GNUNET_MessageHeader *) buf; want = ntohs (hdr->size); if (want < sizeof (struct GNUNET_MessageHeader)) { GNUNET_break_op (0); mst->off = 0; return GNUNET_SYSERR; } if (size < want) break; /* or not: buffer incomplete, so copy to private buffer... */ if (one_shot == GNUNET_SYSERR) { /* cannot call callback again, but return value saying that * we have another full message in the buffer */ ret = GNUNET_NO; goto copy; } if (one_shot == GNUNET_YES) one_shot = GNUNET_SYSERR; if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr)) return GNUNET_SYSERR; buf += want; size -= want; } else { /* need to copy to private buffer to align; * yes, we go a bit more spagetti than usual here */ goto do_align; } } copy: if ((size > 0) && (!purge)) { if (size + mst->pos > mst->curr_buf) { mst->hdr = GNUNET_realloc (mst->hdr, size + mst->pos); ibuf = (char *) mst->hdr; mst->curr_buf = size + mst->pos; } GNUNET_assert (size + mst->pos <= mst->curr_buf); memcpy (&ibuf[mst->pos], buf, size); mst->pos += size; } if (purge) { mst->off = 0; mst->pos = 0; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Server-mst leaves %u bytes in private buffer\n", (unsigned int) (mst->pos - mst->off)); return ret; } /** * Destroys a tokenizer. * * @param mst tokenizer to destroy */ void GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst) { GNUNET_free (mst->hdr); GNUNET_free (mst); } /* end of server_mst.c */ gnunet-0.9.3/src/util/Makefile.in0000644000175000017500000023246311762223550013572 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ noinst_PROGRAMS = gnunet-config-diff$(EXEEXT) \ test_common_logging_dummy$(EXEEXT) bin_PROGRAMS = gnunet-service-resolver$(EXEEXT) \ gnunet-resolver$(EXEEXT) gnunet-rsa$(EXEEXT) check_PROGRAMS = test_bio$(EXEEXT) test_client$(EXEEXT) \ test_common_allocation$(EXEEXT) test_common_endian$(EXEEXT) \ test_common_logging$(EXEEXT) test_configuration$(EXEEXT) \ test_container_bloomfilter$(EXEEXT) \ test_container_meta_data$(EXEEXT) \ test_container_multihashmap$(EXEEXT) \ test_container_heap$(EXEEXT) test_container_slist$(EXEEXT) \ test_crypto_aes$(EXEEXT) test_crypto_aes_weak$(EXEEXT) \ test_crypto_crc$(EXEEXT) test_crypto_hash$(EXEEXT) \ test_crypto_hkdf$(EXEEXT) test_crypto_ksk$(EXEEXT) \ test_crypto_random$(EXEEXT) test_crypto_rsa$(EXEEXT) \ test_disk$(EXEEXT) test_getopt$(EXEEXT) \ test_connection$(EXEEXT) test_connection_addressing$(EXEEXT) \ test_connection_receive_cancel$(EXEEXT) \ test_connection_timeout$(EXEEXT) \ test_connection_timeout_no_connect$(EXEEXT) \ test_connection_transmit_cancel$(EXEEXT) \ test_os_network$(EXEEXT) test_os_priority$(EXEEXT) \ test_peer$(EXEEXT) test_plugin$(EXEEXT) test_program$(EXEEXT) \ test_pseudonym$(EXEEXT) test_resolver_api$(EXEEXT) \ test_scheduler$(EXEEXT) test_scheduler_delay$(EXEEXT) \ test_server_mst_interrupt$(EXEEXT) test_server$(EXEEXT) \ test_server_disconnect$(EXEEXT) \ test_server_with_client$(EXEEXT) $(am__EXEEXT_1) \ test_service$(EXEEXT) test_strings$(EXEEXT) test_time$(EXEEXT) \ test_speedup$(EXEEXT) $(am__EXEEXT_2) \ test_os_start_process$(EXEEXT) \ test_common_logging_runtime_loglevels$(EXEEXT) subdir = src/util DIST_COMMON = $(dist_pkgcfg_DATA) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/resolver.conf.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = resolver.conf CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \ "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" \ "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) \ $(plugin_LTLIBRARIES) libgnunet_plugin_test_la_LIBADD = am_libgnunet_plugin_test_la_OBJECTS = test_plugin_plug.lo libgnunet_plugin_test_la_OBJECTS = \ $(am_libgnunet_plugin_test_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunet_plugin_test_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunet_plugin_test_la_LDFLAGS) \ $(LDFLAGS) -o $@ am__DEPENDENCIES_1 = libgnunetutil_la_DEPENDENCIES = $(WINLIB) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am_libgnunetutil_la_OBJECTS = bandwidth.lo bio.lo client.lo \ common_allocation.lo common_endian.lo common_logging.lo \ configuration.lo connection.lo container_bloomfilter.lo \ container_heap.lo container_meta_data.lo \ container_multihashmap.lo container_slist.lo crypto_aes.lo \ crypto_crc.lo crypto_hash.lo crypto_hkdf.lo crypto_kdf.lo \ crypto_ksk.lo crypto_random.lo crypto_rsa.lo disk.lo getopt.lo \ getopt_helpers.lo helper.lo load.lo network.lo \ os_installation.lo os_network.lo os_priority.lo peer.lo \ plugin.lo program.lo pseudonym.lo resolver_api.lo scheduler.lo \ server.lo server_mst.lo server_nc.lo server_tc.lo service.lo \ signal.lo strings.lo time.lo speedup.lo libgnunetutil_la_OBJECTS = $(am_libgnunetutil_la_OBJECTS) libgnunetutil_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetutil_la_LDFLAGS) $(LDFLAGS) \ -o $@ libgnunetutilwin_la_DEPENDENCIES = am__libgnunetutilwin_la_SOURCES_DIST = win.cc winproc.c @MINGW_TRUE@am_libgnunetutilwin_la_OBJECTS = win.lo winproc.lo libgnunetutilwin_la_OBJECTS = $(am_libgnunetutilwin_la_OBJECTS) libgnunetutilwin_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(libgnunetutilwin_la_LDFLAGS) \ $(LDFLAGS) -o $@ @MINGW_TRUE@am_libgnunetutilwin_la_rpath = @MINGW_FALSE@am__EXEEXT_1 = test_server_with_client_unix$(EXEEXT) @HAVE_BENCHMARKS_TRUE@am__EXEEXT_2 = perf_crypto_hash$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) am_gnunet_config_diff_OBJECTS = gnunet-config-diff.$(OBJEXT) gnunet_config_diff_OBJECTS = $(am_gnunet_config_diff_OBJECTS) am_gnunet_resolver_OBJECTS = gnunet-resolver.$(OBJEXT) gnunet_resolver_OBJECTS = $(am_gnunet_resolver_OBJECTS) am_gnunet_rsa_OBJECTS = gnunet-rsa.$(OBJEXT) gnunet_rsa_OBJECTS = $(am_gnunet_rsa_OBJECTS) am_gnunet_service_resolver_OBJECTS = \ gnunet-service-resolver.$(OBJEXT) gnunet_service_resolver_OBJECTS = \ $(am_gnunet_service_resolver_OBJECTS) am_perf_crypto_hash_OBJECTS = perf_crypto_hash.$(OBJEXT) perf_crypto_hash_OBJECTS = $(am_perf_crypto_hash_OBJECTS) perf_crypto_hash_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_bio_OBJECTS = test_bio.$(OBJEXT) test_bio_OBJECTS = $(am_test_bio_OBJECTS) test_bio_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la am_test_client_OBJECTS = test_client.$(OBJEXT) test_client_OBJECTS = $(am_test_client_OBJECTS) test_client_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la am_test_common_allocation_OBJECTS = test_common_allocation.$(OBJEXT) test_common_allocation_OBJECTS = $(am_test_common_allocation_OBJECTS) test_common_allocation_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_common_endian_OBJECTS = test_common_endian.$(OBJEXT) test_common_endian_OBJECTS = $(am_test_common_endian_OBJECTS) test_common_endian_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_common_logging_OBJECTS = test_common_logging.$(OBJEXT) test_common_logging_OBJECTS = $(am_test_common_logging_OBJECTS) test_common_logging_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_common_logging_dummy_OBJECTS = \ test_common_logging_dummy.$(OBJEXT) test_common_logging_dummy_OBJECTS = \ $(am_test_common_logging_dummy_OBJECTS) am_test_common_logging_runtime_loglevels_OBJECTS = \ test_common_logging_runtime_loglevels.$(OBJEXT) test_common_logging_runtime_loglevels_OBJECTS = \ $(am_test_common_logging_runtime_loglevels_OBJECTS) test_common_logging_runtime_loglevels_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_configuration_OBJECTS = test_configuration.$(OBJEXT) test_configuration_OBJECTS = $(am_test_configuration_OBJECTS) test_configuration_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_connection_OBJECTS = test_connection.$(OBJEXT) test_connection_OBJECTS = $(am_test_connection_OBJECTS) test_connection_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_connection_addressing_OBJECTS = \ test_connection_addressing.$(OBJEXT) test_connection_addressing_OBJECTS = \ $(am_test_connection_addressing_OBJECTS) test_connection_addressing_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_connection_receive_cancel_OBJECTS = \ test_connection_receive_cancel.$(OBJEXT) test_connection_receive_cancel_OBJECTS = \ $(am_test_connection_receive_cancel_OBJECTS) test_connection_receive_cancel_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_connection_timeout_OBJECTS = \ test_connection_timeout.$(OBJEXT) test_connection_timeout_OBJECTS = \ $(am_test_connection_timeout_OBJECTS) test_connection_timeout_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_connection_timeout_no_connect_OBJECTS = \ test_connection_timeout_no_connect.$(OBJEXT) test_connection_timeout_no_connect_OBJECTS = \ $(am_test_connection_timeout_no_connect_OBJECTS) test_connection_timeout_no_connect_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_connection_transmit_cancel_OBJECTS = \ test_connection_transmit_cancel.$(OBJEXT) test_connection_transmit_cancel_OBJECTS = \ $(am_test_connection_transmit_cancel_OBJECTS) test_connection_transmit_cancel_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_container_bloomfilter_OBJECTS = \ test_container_bloomfilter.$(OBJEXT) test_container_bloomfilter_OBJECTS = \ $(am_test_container_bloomfilter_OBJECTS) test_container_bloomfilter_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_container_heap_OBJECTS = test_container_heap.$(OBJEXT) test_container_heap_OBJECTS = $(am_test_container_heap_OBJECTS) test_container_heap_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_container_meta_data_OBJECTS = \ test_container_meta_data.$(OBJEXT) test_container_meta_data_OBJECTS = \ $(am_test_container_meta_data_OBJECTS) test_container_meta_data_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_container_multihashmap_OBJECTS = \ test_container_multihashmap.$(OBJEXT) test_container_multihashmap_OBJECTS = \ $(am_test_container_multihashmap_OBJECTS) test_container_multihashmap_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_container_slist_OBJECTS = test_container_slist.$(OBJEXT) test_container_slist_OBJECTS = $(am_test_container_slist_OBJECTS) test_container_slist_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_crypto_aes_OBJECTS = test_crypto_aes.$(OBJEXT) test_crypto_aes_OBJECTS = $(am_test_crypto_aes_OBJECTS) test_crypto_aes_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_crypto_aes_weak_OBJECTS = test_crypto_aes_weak.$(OBJEXT) test_crypto_aes_weak_OBJECTS = $(am_test_crypto_aes_weak_OBJECTS) test_crypto_aes_weak_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_test_crypto_crc_OBJECTS = test_crypto_crc.$(OBJEXT) test_crypto_crc_OBJECTS = $(am_test_crypto_crc_OBJECTS) test_crypto_crc_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_crypto_hash_OBJECTS = test_crypto_hash.$(OBJEXT) test_crypto_hash_OBJECTS = $(am_test_crypto_hash_OBJECTS) test_crypto_hash_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_crypto_hkdf_OBJECTS = test_crypto_hkdf.$(OBJEXT) test_crypto_hkdf_OBJECTS = $(am_test_crypto_hkdf_OBJECTS) test_crypto_hkdf_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_crypto_ksk_OBJECTS = test_crypto_ksk.$(OBJEXT) test_crypto_ksk_OBJECTS = $(am_test_crypto_ksk_OBJECTS) test_crypto_ksk_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_crypto_random_OBJECTS = test_crypto_random.$(OBJEXT) test_crypto_random_OBJECTS = $(am_test_crypto_random_OBJECTS) test_crypto_random_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_crypto_rsa_OBJECTS = test_crypto_rsa.$(OBJEXT) test_crypto_rsa_OBJECTS = $(am_test_crypto_rsa_OBJECTS) test_crypto_rsa_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_disk_OBJECTS = test_disk.$(OBJEXT) test_disk_OBJECTS = $(am_test_disk_OBJECTS) test_disk_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la am_test_getopt_OBJECTS = test_getopt.$(OBJEXT) test_getopt_OBJECTS = $(am_test_getopt_OBJECTS) test_getopt_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la am_test_os_network_OBJECTS = test_os_network.$(OBJEXT) test_os_network_OBJECTS = $(am_test_os_network_OBJECTS) test_os_network_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_os_priority_OBJECTS = test_os_priority.$(OBJEXT) test_os_priority_OBJECTS = $(am_test_os_priority_OBJECTS) test_os_priority_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_os_start_process_OBJECTS = test_os_start_process.$(OBJEXT) test_os_start_process_OBJECTS = $(am_test_os_start_process_OBJECTS) test_os_start_process_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_peer_OBJECTS = test_peer.$(OBJEXT) test_peer_OBJECTS = $(am_test_peer_OBJECTS) test_peer_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la am_test_plugin_OBJECTS = test_plugin.$(OBJEXT) test_plugin_OBJECTS = $(am_test_plugin_OBJECTS) test_plugin_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la am_test_program_OBJECTS = test_program.$(OBJEXT) test_program_OBJECTS = $(am_test_program_OBJECTS) test_program_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la am_test_pseudonym_OBJECTS = test_pseudonym.$(OBJEXT) test_pseudonym_OBJECTS = $(am_test_pseudonym_OBJECTS) test_pseudonym_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_resolver_api_OBJECTS = test_resolver_api.$(OBJEXT) test_resolver_api_OBJECTS = $(am_test_resolver_api_OBJECTS) test_resolver_api_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_scheduler_OBJECTS = test_scheduler.$(OBJEXT) test_scheduler_OBJECTS = $(am_test_scheduler_OBJECTS) test_scheduler_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_scheduler_delay_OBJECTS = test_scheduler_delay.$(OBJEXT) test_scheduler_delay_OBJECTS = $(am_test_scheduler_delay_OBJECTS) test_scheduler_delay_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_server_OBJECTS = test_server.$(OBJEXT) test_server_OBJECTS = $(am_test_server_OBJECTS) test_server_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la am_test_server_disconnect_OBJECTS = test_server_disconnect.$(OBJEXT) test_server_disconnect_OBJECTS = $(am_test_server_disconnect_OBJECTS) test_server_disconnect_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_server_mst_interrupt_OBJECTS = \ test_server_mst_interrupt.$(OBJEXT) test_server_mst_interrupt_OBJECTS = \ $(am_test_server_mst_interrupt_OBJECTS) test_server_mst_interrupt_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_server_with_client_OBJECTS = \ test_server_with_client.$(OBJEXT) test_server_with_client_OBJECTS = \ $(am_test_server_with_client_OBJECTS) test_server_with_client_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_server_with_client_unix_OBJECTS = \ test_server_with_client_unix.$(OBJEXT) test_server_with_client_unix_OBJECTS = \ $(am_test_server_with_client_unix_OBJECTS) test_server_with_client_unix_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_service_OBJECTS = test_service.$(OBJEXT) test_service_OBJECTS = $(am_test_service_OBJECTS) test_service_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la am_test_speedup_OBJECTS = test_speedup.$(OBJEXT) test_speedup_OBJECTS = $(am_test_speedup_OBJECTS) test_speedup_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la am_test_strings_OBJECTS = test_strings.$(OBJEXT) test_strings_OBJECTS = $(am_test_strings_OBJECTS) test_strings_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la am_test_time_OBJECTS = test_time.$(OBJEXT) test_time_OBJECTS = $(am_test_time_OBJECTS) test_time_DEPENDENCIES = $(top_builddir)/src/util/libgnunetutil.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_$(V)) am__v_CXX_ = $(am__v_CXX_$(AM_DEFAULT_VERBOSITY)) am__v_CXX_0 = @echo " CXX " $@; CXXLD = $(CXX) CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CXXLD = $(am__v_CXXLD_$(V)) am__v_CXXLD_ = $(am__v_CXXLD_$(AM_DEFAULT_VERBOSITY)) am__v_CXXLD_0 = @echo " CXXLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunet_plugin_test_la_SOURCES) \ $(libgnunetutil_la_SOURCES) $(libgnunetutilwin_la_SOURCES) \ $(gnunet_config_diff_SOURCES) $(gnunet_resolver_SOURCES) \ $(gnunet_rsa_SOURCES) $(gnunet_service_resolver_SOURCES) \ $(perf_crypto_hash_SOURCES) $(test_bio_SOURCES) \ $(test_client_SOURCES) $(test_common_allocation_SOURCES) \ $(test_common_endian_SOURCES) $(test_common_logging_SOURCES) \ $(test_common_logging_dummy_SOURCES) \ $(test_common_logging_runtime_loglevels_SOURCES) \ $(test_configuration_SOURCES) $(test_connection_SOURCES) \ $(test_connection_addressing_SOURCES) \ $(test_connection_receive_cancel_SOURCES) \ $(test_connection_timeout_SOURCES) \ $(test_connection_timeout_no_connect_SOURCES) \ $(test_connection_transmit_cancel_SOURCES) \ $(test_container_bloomfilter_SOURCES) \ $(test_container_heap_SOURCES) \ $(test_container_meta_data_SOURCES) \ $(test_container_multihashmap_SOURCES) \ $(test_container_slist_SOURCES) $(test_crypto_aes_SOURCES) \ $(test_crypto_aes_weak_SOURCES) $(test_crypto_crc_SOURCES) \ $(test_crypto_hash_SOURCES) $(test_crypto_hkdf_SOURCES) \ $(test_crypto_ksk_SOURCES) $(test_crypto_random_SOURCES) \ $(test_crypto_rsa_SOURCES) $(test_disk_SOURCES) \ $(test_getopt_SOURCES) $(test_os_network_SOURCES) \ $(test_os_priority_SOURCES) $(test_os_start_process_SOURCES) \ $(test_peer_SOURCES) $(test_plugin_SOURCES) \ $(test_program_SOURCES) $(test_pseudonym_SOURCES) \ $(test_resolver_api_SOURCES) $(test_scheduler_SOURCES) \ $(test_scheduler_delay_SOURCES) $(test_server_SOURCES) \ $(test_server_disconnect_SOURCES) \ $(test_server_mst_interrupt_SOURCES) \ $(test_server_with_client_SOURCES) \ $(test_server_with_client_unix_SOURCES) \ $(test_service_SOURCES) $(test_speedup_SOURCES) \ $(test_strings_SOURCES) $(test_time_SOURCES) DIST_SOURCES = $(libgnunet_plugin_test_la_SOURCES) \ $(libgnunetutil_la_SOURCES) \ $(am__libgnunetutilwin_la_SOURCES_DIST) \ $(gnunet_config_diff_SOURCES) $(gnunet_resolver_SOURCES) \ $(gnunet_rsa_SOURCES) $(gnunet_service_resolver_SOURCES) \ $(perf_crypto_hash_SOURCES) $(test_bio_SOURCES) \ $(test_client_SOURCES) $(test_common_allocation_SOURCES) \ $(test_common_endian_SOURCES) $(test_common_logging_SOURCES) \ $(test_common_logging_dummy_SOURCES) \ $(test_common_logging_runtime_loglevels_SOURCES) \ $(test_configuration_SOURCES) $(test_connection_SOURCES) \ $(test_connection_addressing_SOURCES) \ $(test_connection_receive_cancel_SOURCES) \ $(test_connection_timeout_SOURCES) \ $(test_connection_timeout_no_connect_SOURCES) \ $(test_connection_transmit_cancel_SOURCES) \ $(test_container_bloomfilter_SOURCES) \ $(test_container_heap_SOURCES) \ $(test_container_meta_data_SOURCES) \ $(test_container_multihashmap_SOURCES) \ $(test_container_slist_SOURCES) $(test_crypto_aes_SOURCES) \ $(test_crypto_aes_weak_SOURCES) $(test_crypto_crc_SOURCES) \ $(test_crypto_hash_SOURCES) $(test_crypto_hkdf_SOURCES) \ $(test_crypto_ksk_SOURCES) $(test_crypto_random_SOURCES) \ $(test_crypto_rsa_SOURCES) $(test_disk_SOURCES) \ $(test_getopt_SOURCES) $(test_os_network_SOURCES) \ $(test_os_priority_SOURCES) $(test_os_start_process_SOURCES) \ $(test_peer_SOURCES) $(test_plugin_SOURCES) \ $(test_program_SOURCES) $(test_pseudonym_SOURCES) \ $(test_resolver_api_SOURCES) $(test_scheduler_SOURCES) \ $(test_scheduler_delay_SOURCES) $(test_server_SOURCES) \ $(test_server_disconnect_SOURCES) \ $(test_server_mst_interrupt_SOURCES) \ $(test_server_with_client_SOURCES) \ $(test_server_with_client_unix_SOURCES) \ $(test_service_SOURCES) $(test_speedup_SOURCES) \ $(test_strings_SOURCES) $(test_time_SOURCES) DATA = $(dist_pkgcfg_DATA) $(pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include -I$(top_builddir)/src/include plugindir = $(libdir)/gnunet pkgcfgdir = $(pkgdatadir)/config.d/ dist_pkgcfg_DATA = \ util.conf pkgcfg_DATA = \ resolver.conf @MINGW_TRUE@noinst_LTLIBRARIES = \ @MINGW_TRUE@ libgnunetutilwin.la @MINGW_TRUE@libgnunetutilwin_la_SOURCES = \ @MINGW_TRUE@ win.cc \ @MINGW_TRUE@ winproc.c @MINGW_TRUE@libgnunetutilwin_la_LDFLAGS = \ @MINGW_TRUE@ -no-undefined -Wl,--export-all-symbols @MINGW_TRUE@libgnunetutilwin_la_LIBADD = \ @MINGW_TRUE@ -lshell32 -liconv -lstdc++ \ @MINGW_TRUE@ -lcomdlg32 -lgdi32 -liphlpapi @MINGW_TRUE@WINLIB = libgnunetutilwin.la @MINGW_FALSE@SERVER_CLIENT_UNIX = test_server_with_client_unix @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @USE_COVERAGE_TRUE@XLIB = -lgcov gnunet_config_diff_SOURCES = \ gnunet-config-diff.c gnunet_config_diff_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la gnunet_config_diff_DEPENDENCIES = \ libgnunetutil.la test_common_logging_dummy_SOURCES = \ test_common_logging_dummy.c test_common_logging_dummy_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_common_logging_dummy_DEPENDENCIES = \ libgnunetutil.la lib_LTLIBRARIES = libgnunetutil.la libgnunetutil_la_SOURCES = \ bandwidth.c \ bio.c \ client.c \ common_allocation.c \ common_endian.c \ common_logging.c \ configuration.c \ connection.c \ container_bloomfilter.c \ container_heap.c \ container_meta_data.c \ container_multihashmap.c \ container_slist.c \ crypto_aes.c \ crypto_crc.c \ crypto_hash.c \ crypto_hkdf.c \ crypto_kdf.c \ crypto_ksk.c \ crypto_random.c \ crypto_rsa.c \ disk.c \ disk.h \ getopt.c \ getopt_helpers.c \ helper.c \ load.c \ network.c \ os_installation.c \ os_network.c \ os_priority.c \ peer.c \ plugin.c \ program.c \ pseudonym.c \ resolver_api.c resolver.h \ scheduler.c \ server.c \ server_mst.c \ server_nc.c \ server_tc.c \ service.c \ signal.c \ strings.c \ time.c \ speedup.c libgnunetutil_la_LIBADD = \ $(GCLIBADD) $(WINLIB) \ $(LIBGCRYPT_LIBS) \ $(LTLIBICONV) \ -lltdl -lz -lunistring $(XLIB) libgnunetutil_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 8:0:0 gnunet_service_resolver_SOURCES = \ gnunet-service-resolver.c gnunet_service_resolver_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_service_resolver_DEPENDENCIES = \ libgnunetutil.la gnunet_resolver_SOURCES = \ gnunet-resolver.c gnunet_resolver_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_resolver_DEPENDENCIES = \ libgnunetutil.la gnunet_rsa_SOURCES = \ gnunet-rsa.c gnunet_rsa_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_rsa_DEPENDENCIES = \ libgnunetutil.la plugin_LTLIBRARIES = \ libgnunet_plugin_test.la libgnunet_plugin_test_la_SOURCES = \ test_plugin_plug.c libgnunet_plugin_test_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) @HAVE_BENCHMARKS_TRUE@BENCHMARKS = \ @HAVE_BENCHMARKS_TRUE@ perf_crypto_hash @ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) test_bio_SOURCES = \ test_bio.c test_bio_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_os_start_process_SOURCES = \ test_os_start_process.c test_os_start_process_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_client_SOURCES = \ test_client.c test_client_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_common_allocation_SOURCES = \ test_common_allocation.c test_common_allocation_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_common_endian_SOURCES = \ test_common_endian.c test_common_endian_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_common_logging_SOURCES = \ test_common_logging.c test_common_logging_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_common_logging_runtime_loglevels_SOURCES = \ test_common_logging_runtime_loglevels.c test_common_logging_runtime_loglevels_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_configuration_SOURCES = \ test_configuration.c test_configuration_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_container_bloomfilter_SOURCES = \ test_container_bloomfilter.c test_container_bloomfilter_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_container_meta_data_SOURCES = \ test_container_meta_data.c test_container_meta_data_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la -lextractor test_container_multihashmap_SOURCES = \ test_container_multihashmap.c test_container_multihashmap_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_container_heap_SOURCES = \ test_container_heap.c test_container_heap_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_container_slist_SOURCES = \ test_container_slist.c test_container_slist_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_crypto_aes_SOURCES = \ test_crypto_aes.c test_crypto_aes_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_crypto_aes_weak_SOURCES = \ test_crypto_aes_weak.c test_crypto_aes_weak_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(LIBGCRYPT_LIBS) test_crypto_crc_SOURCES = \ test_crypto_crc.c test_crypto_crc_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_crypto_hash_SOURCES = \ test_crypto_hash.c test_crypto_hash_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_crypto_hkdf_SOURCES = \ test_crypto_hkdf.c test_crypto_hkdf_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_crypto_ksk_SOURCES = \ test_crypto_ksk.c test_crypto_ksk_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_crypto_random_SOURCES = \ test_crypto_random.c test_crypto_random_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_crypto_rsa_SOURCES = \ test_crypto_rsa.c test_crypto_rsa_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_disk_SOURCES = \ test_disk.c test_disk_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_getopt_SOURCES = \ test_getopt.c test_getopt_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_connection_SOURCES = \ test_connection.c test_connection_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_connection_addressing_SOURCES = \ test_connection_addressing.c test_connection_addressing_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_connection_receive_cancel_SOURCES = \ test_connection_receive_cancel.c test_connection_receive_cancel_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_connection_timeout_SOURCES = \ test_connection_timeout.c test_connection_timeout_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_connection_timeout_no_connect_SOURCES = \ test_connection_timeout_no_connect.c test_connection_timeout_no_connect_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_connection_transmit_cancel_SOURCES = \ test_connection_transmit_cancel.c test_connection_transmit_cancel_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_os_network_SOURCES = \ test_os_network.c test_os_network_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_os_priority_SOURCES = \ test_os_priority.c test_os_priority_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_peer_SOURCES = \ test_peer.c test_peer_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_plugin_SOURCES = \ test_plugin.c test_plugin_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_program_SOURCES = \ test_program.c test_program_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_pseudonym_SOURCES = \ test_pseudonym.c test_pseudonym_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_resolver_api_SOURCES = \ test_resolver_api.c test_resolver_api_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_scheduler_SOURCES = \ test_scheduler.c test_scheduler_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_scheduler_delay_SOURCES = \ test_scheduler_delay.c test_scheduler_delay_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_server_mst_interrupt_SOURCES = \ test_server_mst_interrupt.c test_server_mst_interrupt_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_server_SOURCES = \ test_server.c test_server_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_server_disconnect_SOURCES = \ test_server_disconnect.c test_server_disconnect_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_server_with_client_SOURCES = \ test_server_with_client.c test_server_with_client_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_server_with_client_unix_SOURCES = \ test_server_with_client_unix.c test_server_with_client_unix_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_service_SOURCES = \ test_service.c test_service_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_strings_SOURCES = \ test_strings.c test_strings_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_time_SOURCES = \ test_time.c test_time_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la test_speedup_SOURCES = \ test_speedup.c test_speedup_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la perf_crypto_hash_SOURCES = \ perf_crypto_hash.c perf_crypto_hash_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ test_configuration_data.conf \ test_program_data.conf \ test_pseudonym_data.conf \ test_resolver_api_data.conf \ test_service_data.conf \ test_speedup_data.conf all: all-am .SUFFIXES: .SUFFIXES: .c .cc .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/util/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/util/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): resolver.conf: $(top_builddir)/config.status $(srcdir)/resolver.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ } uninstall-pluginLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ done clean-pluginLTLIBRARIES: -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunet_plugin_test.la: $(libgnunet_plugin_test_la_OBJECTS) $(libgnunet_plugin_test_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_test_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_test_la_OBJECTS) $(libgnunet_plugin_test_la_LIBADD) $(LIBS) libgnunetutil.la: $(libgnunetutil_la_OBJECTS) $(libgnunetutil_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetutil_la_LINK) -rpath $(libdir) $(libgnunetutil_la_OBJECTS) $(libgnunetutil_la_LIBADD) $(LIBS) libgnunetutilwin.la: $(libgnunetutilwin_la_OBJECTS) $(libgnunetutilwin_la_DEPENDENCIES) $(AM_V_CXXLD)$(libgnunetutilwin_la_LINK) $(am_libgnunetutilwin_la_rpath) $(libgnunetutilwin_la_OBJECTS) $(libgnunetutilwin_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-config-diff$(EXEEXT): $(gnunet_config_diff_OBJECTS) $(gnunet_config_diff_DEPENDENCIES) @rm -f gnunet-config-diff$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_config_diff_OBJECTS) $(gnunet_config_diff_LDADD) $(LIBS) gnunet-resolver$(EXEEXT): $(gnunet_resolver_OBJECTS) $(gnunet_resolver_DEPENDENCIES) @rm -f gnunet-resolver$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_resolver_OBJECTS) $(gnunet_resolver_LDADD) $(LIBS) gnunet-rsa$(EXEEXT): $(gnunet_rsa_OBJECTS) $(gnunet_rsa_DEPENDENCIES) @rm -f gnunet-rsa$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_rsa_OBJECTS) $(gnunet_rsa_LDADD) $(LIBS) gnunet-service-resolver$(EXEEXT): $(gnunet_service_resolver_OBJECTS) $(gnunet_service_resolver_DEPENDENCIES) @rm -f gnunet-service-resolver$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_service_resolver_OBJECTS) $(gnunet_service_resolver_LDADD) $(LIBS) perf_crypto_hash$(EXEEXT): $(perf_crypto_hash_OBJECTS) $(perf_crypto_hash_DEPENDENCIES) @rm -f perf_crypto_hash$(EXEEXT) $(AM_V_CCLD)$(LINK) $(perf_crypto_hash_OBJECTS) $(perf_crypto_hash_LDADD) $(LIBS) test_bio$(EXEEXT): $(test_bio_OBJECTS) $(test_bio_DEPENDENCIES) @rm -f test_bio$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_bio_OBJECTS) $(test_bio_LDADD) $(LIBS) test_client$(EXEEXT): $(test_client_OBJECTS) $(test_client_DEPENDENCIES) @rm -f test_client$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_client_OBJECTS) $(test_client_LDADD) $(LIBS) test_common_allocation$(EXEEXT): $(test_common_allocation_OBJECTS) $(test_common_allocation_DEPENDENCIES) @rm -f test_common_allocation$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_common_allocation_OBJECTS) $(test_common_allocation_LDADD) $(LIBS) test_common_endian$(EXEEXT): $(test_common_endian_OBJECTS) $(test_common_endian_DEPENDENCIES) @rm -f test_common_endian$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_common_endian_OBJECTS) $(test_common_endian_LDADD) $(LIBS) test_common_logging$(EXEEXT): $(test_common_logging_OBJECTS) $(test_common_logging_DEPENDENCIES) @rm -f test_common_logging$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_common_logging_OBJECTS) $(test_common_logging_LDADD) $(LIBS) test_common_logging_dummy$(EXEEXT): $(test_common_logging_dummy_OBJECTS) $(test_common_logging_dummy_DEPENDENCIES) @rm -f test_common_logging_dummy$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_common_logging_dummy_OBJECTS) $(test_common_logging_dummy_LDADD) $(LIBS) test_common_logging_runtime_loglevels$(EXEEXT): $(test_common_logging_runtime_loglevels_OBJECTS) $(test_common_logging_runtime_loglevels_DEPENDENCIES) @rm -f test_common_logging_runtime_loglevels$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_common_logging_runtime_loglevels_OBJECTS) $(test_common_logging_runtime_loglevels_LDADD) $(LIBS) test_configuration$(EXEEXT): $(test_configuration_OBJECTS) $(test_configuration_DEPENDENCIES) @rm -f test_configuration$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_configuration_OBJECTS) $(test_configuration_LDADD) $(LIBS) test_connection$(EXEEXT): $(test_connection_OBJECTS) $(test_connection_DEPENDENCIES) @rm -f test_connection$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_connection_OBJECTS) $(test_connection_LDADD) $(LIBS) test_connection_addressing$(EXEEXT): $(test_connection_addressing_OBJECTS) $(test_connection_addressing_DEPENDENCIES) @rm -f test_connection_addressing$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_connection_addressing_OBJECTS) $(test_connection_addressing_LDADD) $(LIBS) test_connection_receive_cancel$(EXEEXT): $(test_connection_receive_cancel_OBJECTS) $(test_connection_receive_cancel_DEPENDENCIES) @rm -f test_connection_receive_cancel$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_connection_receive_cancel_OBJECTS) $(test_connection_receive_cancel_LDADD) $(LIBS) test_connection_timeout$(EXEEXT): $(test_connection_timeout_OBJECTS) $(test_connection_timeout_DEPENDENCIES) @rm -f test_connection_timeout$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_connection_timeout_OBJECTS) $(test_connection_timeout_LDADD) $(LIBS) test_connection_timeout_no_connect$(EXEEXT): $(test_connection_timeout_no_connect_OBJECTS) $(test_connection_timeout_no_connect_DEPENDENCIES) @rm -f test_connection_timeout_no_connect$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_connection_timeout_no_connect_OBJECTS) $(test_connection_timeout_no_connect_LDADD) $(LIBS) test_connection_transmit_cancel$(EXEEXT): $(test_connection_transmit_cancel_OBJECTS) $(test_connection_transmit_cancel_DEPENDENCIES) @rm -f test_connection_transmit_cancel$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_connection_transmit_cancel_OBJECTS) $(test_connection_transmit_cancel_LDADD) $(LIBS) test_container_bloomfilter$(EXEEXT): $(test_container_bloomfilter_OBJECTS) $(test_container_bloomfilter_DEPENDENCIES) @rm -f test_container_bloomfilter$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_container_bloomfilter_OBJECTS) $(test_container_bloomfilter_LDADD) $(LIBS) test_container_heap$(EXEEXT): $(test_container_heap_OBJECTS) $(test_container_heap_DEPENDENCIES) @rm -f test_container_heap$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_container_heap_OBJECTS) $(test_container_heap_LDADD) $(LIBS) test_container_meta_data$(EXEEXT): $(test_container_meta_data_OBJECTS) $(test_container_meta_data_DEPENDENCIES) @rm -f test_container_meta_data$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_container_meta_data_OBJECTS) $(test_container_meta_data_LDADD) $(LIBS) test_container_multihashmap$(EXEEXT): $(test_container_multihashmap_OBJECTS) $(test_container_multihashmap_DEPENDENCIES) @rm -f test_container_multihashmap$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_container_multihashmap_OBJECTS) $(test_container_multihashmap_LDADD) $(LIBS) test_container_slist$(EXEEXT): $(test_container_slist_OBJECTS) $(test_container_slist_DEPENDENCIES) @rm -f test_container_slist$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_container_slist_OBJECTS) $(test_container_slist_LDADD) $(LIBS) test_crypto_aes$(EXEEXT): $(test_crypto_aes_OBJECTS) $(test_crypto_aes_DEPENDENCIES) @rm -f test_crypto_aes$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_crypto_aes_OBJECTS) $(test_crypto_aes_LDADD) $(LIBS) test_crypto_aes_weak$(EXEEXT): $(test_crypto_aes_weak_OBJECTS) $(test_crypto_aes_weak_DEPENDENCIES) @rm -f test_crypto_aes_weak$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_crypto_aes_weak_OBJECTS) $(test_crypto_aes_weak_LDADD) $(LIBS) test_crypto_crc$(EXEEXT): $(test_crypto_crc_OBJECTS) $(test_crypto_crc_DEPENDENCIES) @rm -f test_crypto_crc$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_crypto_crc_OBJECTS) $(test_crypto_crc_LDADD) $(LIBS) test_crypto_hash$(EXEEXT): $(test_crypto_hash_OBJECTS) $(test_crypto_hash_DEPENDENCIES) @rm -f test_crypto_hash$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_crypto_hash_OBJECTS) $(test_crypto_hash_LDADD) $(LIBS) test_crypto_hkdf$(EXEEXT): $(test_crypto_hkdf_OBJECTS) $(test_crypto_hkdf_DEPENDENCIES) @rm -f test_crypto_hkdf$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_crypto_hkdf_OBJECTS) $(test_crypto_hkdf_LDADD) $(LIBS) test_crypto_ksk$(EXEEXT): $(test_crypto_ksk_OBJECTS) $(test_crypto_ksk_DEPENDENCIES) @rm -f test_crypto_ksk$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_crypto_ksk_OBJECTS) $(test_crypto_ksk_LDADD) $(LIBS) test_crypto_random$(EXEEXT): $(test_crypto_random_OBJECTS) $(test_crypto_random_DEPENDENCIES) @rm -f test_crypto_random$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_crypto_random_OBJECTS) $(test_crypto_random_LDADD) $(LIBS) test_crypto_rsa$(EXEEXT): $(test_crypto_rsa_OBJECTS) $(test_crypto_rsa_DEPENDENCIES) @rm -f test_crypto_rsa$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_crypto_rsa_OBJECTS) $(test_crypto_rsa_LDADD) $(LIBS) test_disk$(EXEEXT): $(test_disk_OBJECTS) $(test_disk_DEPENDENCIES) @rm -f test_disk$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_disk_OBJECTS) $(test_disk_LDADD) $(LIBS) test_getopt$(EXEEXT): $(test_getopt_OBJECTS) $(test_getopt_DEPENDENCIES) @rm -f test_getopt$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_getopt_OBJECTS) $(test_getopt_LDADD) $(LIBS) test_os_network$(EXEEXT): $(test_os_network_OBJECTS) $(test_os_network_DEPENDENCIES) @rm -f test_os_network$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_os_network_OBJECTS) $(test_os_network_LDADD) $(LIBS) test_os_priority$(EXEEXT): $(test_os_priority_OBJECTS) $(test_os_priority_DEPENDENCIES) @rm -f test_os_priority$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_os_priority_OBJECTS) $(test_os_priority_LDADD) $(LIBS) test_os_start_process$(EXEEXT): $(test_os_start_process_OBJECTS) $(test_os_start_process_DEPENDENCIES) @rm -f test_os_start_process$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_os_start_process_OBJECTS) $(test_os_start_process_LDADD) $(LIBS) test_peer$(EXEEXT): $(test_peer_OBJECTS) $(test_peer_DEPENDENCIES) @rm -f test_peer$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_peer_OBJECTS) $(test_peer_LDADD) $(LIBS) test_plugin$(EXEEXT): $(test_plugin_OBJECTS) $(test_plugin_DEPENDENCIES) @rm -f test_plugin$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_plugin_OBJECTS) $(test_plugin_LDADD) $(LIBS) test_program$(EXEEXT): $(test_program_OBJECTS) $(test_program_DEPENDENCIES) @rm -f test_program$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_program_OBJECTS) $(test_program_LDADD) $(LIBS) test_pseudonym$(EXEEXT): $(test_pseudonym_OBJECTS) $(test_pseudonym_DEPENDENCIES) @rm -f test_pseudonym$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_pseudonym_OBJECTS) $(test_pseudonym_LDADD) $(LIBS) test_resolver_api$(EXEEXT): $(test_resolver_api_OBJECTS) $(test_resolver_api_DEPENDENCIES) @rm -f test_resolver_api$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_resolver_api_OBJECTS) $(test_resolver_api_LDADD) $(LIBS) test_scheduler$(EXEEXT): $(test_scheduler_OBJECTS) $(test_scheduler_DEPENDENCIES) @rm -f test_scheduler$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_scheduler_OBJECTS) $(test_scheduler_LDADD) $(LIBS) test_scheduler_delay$(EXEEXT): $(test_scheduler_delay_OBJECTS) $(test_scheduler_delay_DEPENDENCIES) @rm -f test_scheduler_delay$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_scheduler_delay_OBJECTS) $(test_scheduler_delay_LDADD) $(LIBS) test_server$(EXEEXT): $(test_server_OBJECTS) $(test_server_DEPENDENCIES) @rm -f test_server$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_server_OBJECTS) $(test_server_LDADD) $(LIBS) test_server_disconnect$(EXEEXT): $(test_server_disconnect_OBJECTS) $(test_server_disconnect_DEPENDENCIES) @rm -f test_server_disconnect$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_server_disconnect_OBJECTS) $(test_server_disconnect_LDADD) $(LIBS) test_server_mst_interrupt$(EXEEXT): $(test_server_mst_interrupt_OBJECTS) $(test_server_mst_interrupt_DEPENDENCIES) @rm -f test_server_mst_interrupt$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_server_mst_interrupt_OBJECTS) $(test_server_mst_interrupt_LDADD) $(LIBS) test_server_with_client$(EXEEXT): $(test_server_with_client_OBJECTS) $(test_server_with_client_DEPENDENCIES) @rm -f test_server_with_client$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_server_with_client_OBJECTS) $(test_server_with_client_LDADD) $(LIBS) test_server_with_client_unix$(EXEEXT): $(test_server_with_client_unix_OBJECTS) $(test_server_with_client_unix_DEPENDENCIES) @rm -f test_server_with_client_unix$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_server_with_client_unix_OBJECTS) $(test_server_with_client_unix_LDADD) $(LIBS) test_service$(EXEEXT): $(test_service_OBJECTS) $(test_service_DEPENDENCIES) @rm -f test_service$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_service_OBJECTS) $(test_service_LDADD) $(LIBS) test_speedup$(EXEEXT): $(test_speedup_OBJECTS) $(test_speedup_DEPENDENCIES) @rm -f test_speedup$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_speedup_OBJECTS) $(test_speedup_LDADD) $(LIBS) test_strings$(EXEEXT): $(test_strings_OBJECTS) $(test_strings_DEPENDENCIES) @rm -f test_strings$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_strings_OBJECTS) $(test_strings_LDADD) $(LIBS) test_time$(EXEEXT): $(test_time_OBJECTS) $(test_time_DEPENDENCIES) @rm -f test_time$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_time_OBJECTS) $(test_time_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bandwidth.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bio.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common_allocation.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common_endian.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common_logging.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/configuration.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connection.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/container_bloomfilter.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/container_heap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/container_meta_data.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/container_multihashmap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/container_slist.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto_aes.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto_crc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto_hash.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto_hkdf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto_kdf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto_ksk.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto_random.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto_rsa.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/disk.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt_helpers.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-config-diff.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-resolver.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-rsa.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-resolver.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/helper.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/network.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os_installation.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os_network.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os_priority.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/peer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perf_crypto_hash.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/program.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pseudonym.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resolver_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scheduler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server_mst.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server_nc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server_tc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/service.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signal.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/speedup.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strings.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_bio.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_common_allocation.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_common_endian.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_common_logging.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_common_logging_dummy.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_common_logging_runtime_loglevels.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_configuration.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_connection.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_connection_addressing.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_connection_receive_cancel.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_connection_timeout.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_connection_timeout_no_connect.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_connection_transmit_cancel.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_container_bloomfilter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_container_heap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_container_meta_data.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_container_multihashmap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_container_slist.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_crypto_aes.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_crypto_aes_weak.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_crypto_crc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_crypto_hash.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_crypto_hkdf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_crypto_ksk.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_crypto_random.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_crypto_rsa.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_disk.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_getopt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_os_network.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_os_priority.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_os_start_process.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_peer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_plugin.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_plugin_plug.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_program.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_pseudonym.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_resolver_api.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_scheduler.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_scheduler_delay.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_server.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_server_disconnect.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_server_mst_interrupt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_server_with_client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_server_with_client_unix.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_service.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_speedup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_strings.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_time.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/time.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/win.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/winproc.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< .cc.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cc.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cc.lo: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_pkgcfgDATA: $(dist_pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-dist_pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files install-pkgcfgDATA: $(pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool clean-noinstLTLIBRARIES \ clean-noinstPROGRAMS clean-pluginLTLIBRARIES mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_pkgcfgDATA install-pkgcfgDATA \ install-pluginLTLIBRARIES install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-dist_pkgcfgDATA \ uninstall-libLTLIBRARIES uninstall-pkgcfgDATA \ uninstall-pluginLTLIBRARIES .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool clean-noinstLTLIBRARIES \ clean-noinstPROGRAMS clean-pluginLTLIBRARIES ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-binPROGRAMS install-data \ install-data-am install-dist_pkgcfgDATA install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libLTLIBRARIES install-man install-pdf install-pdf-am \ install-pkgcfgDATA install-pluginLTLIBRARIES install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ uninstall-am uninstall-binPROGRAMS uninstall-dist_pkgcfgDATA \ uninstall-libLTLIBRARIES uninstall-pkgcfgDATA \ uninstall-pluginLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/util/test_server_mst_interrupt.c0000644000175000017500000000421611760502551017225 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_server_mst_interrupt.c * @brief test for interrupt message processing in server_mst.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_protocols.h" #include "gnunet_client_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_server_lib.h" #include "gnunet_time_lib.h" static struct GNUNET_SERVER_MessageStreamTokenizer * mst; static int ret; /* Callback destroying mst with data in buffer */ static int mst_cb (void *cls, void *client, const struct GNUNET_MessageHeader * message) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MST gave me message, destroying\n"); GNUNET_SERVER_mst_destroy (mst); return GNUNET_SYSERR; } /** * Main method */ static int check () { struct GNUNET_PeerIdentity id; struct GNUNET_MessageHeader msg[2]; /* Prepare */ memset (&id, sizeof (id), '\0'); msg[0].size = htons (sizeof (msg)); msg[0].type = htons (sizeof (GNUNET_MESSAGE_TYPE_DUMMY)); mst = GNUNET_SERVER_mst_create(mst_cb, NULL); GNUNET_SERVER_mst_receive(mst, &id, (const char *) &msg, 2 * sizeof (msg), GNUNET_NO, GNUNET_NO); /* If we reach this line, it did not crash */ ret = 0; return ret; } int main (int argc, char *argv[]) { ret = 1; GNUNET_log_setup ("test_server", "WARNING", NULL); check (); return ret; } /* end of test_server_mst_interrupt.c */ gnunet-0.9.3/src/util/test_configuration.c0000644000175000017500000003217011760502551015567 00000000000000/* This file is part of GNUnet. (C) 2003, 2004, 2005, 2006, 2007 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_configuration.c * @brief Test that the configuration module works. * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_configuration_lib.h" #include "gnunet_disk_lib.h" /* Test Configuration Diffs Options */ enum { EDIT_NOTHING, EDIT_SECTION, EDIT_ALL, ADD_NEW_SECTION, ADD_NEW_ENTRY, REMOVE_SECTION, REMOVE_ENTRY, COMPARE, PRINT }; static struct GNUNET_CONFIGURATION_Handle *cfg; static struct GNUNET_CONFIGURATION_Handle *cfgDefault; struct DiffsCBData { struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_CONFIGURATION_Handle *cfgDiffs; const char *section; int callBackOption; int status; }; static void initDiffsCBData (struct DiffsCBData *cbData) { cbData->section = NULL; cbData->cfg = NULL; cbData->cfgDiffs = NULL; cbData->callBackOption = -1; cbData->status = 0; } /** * callback function for modifying * and comparing configuration */ static void diffsCallBack (void *cls, const char *section, const char *option, const char *value) { struct DiffsCBData *cbData = cls; int cbOption = cbData->callBackOption; switch (cbOption) { case EDIT_SECTION: if (NULL == cbData->section) cbData->section = section; if (strcmp (cbData->section, section) == 0) { GNUNET_CONFIGURATION_set_value_string (cbData->cfg, section, option, "new-value"); GNUNET_CONFIGURATION_set_value_string (cbData->cfgDiffs, section, option, "new-value"); } break; case EDIT_ALL: GNUNET_CONFIGURATION_set_value_string (cbData->cfg, section, option, "new-value"); GNUNET_CONFIGURATION_set_value_string (cbData->cfgDiffs, section, option, "new-value"); break; case ADD_NEW_ENTRY: { static int hit = 0; if (hit == 0) { hit = 1; GNUNET_CONFIGURATION_set_value_string (cbData->cfg, section, "new-key", "new-value"); GNUNET_CONFIGURATION_set_value_string (cbData->cfgDiffs, section, "new-key", "new-value"); } break; } case COMPARE: { int ret; char *diffValue; diffValue = NULL; ret = GNUNET_CONFIGURATION_get_value_string (cbData->cfgDiffs, section, option, &diffValue); if (NULL != diffValue) { if (ret == GNUNET_SYSERR || strcmp (diffValue, value) != 0) cbData->status = 1; } else cbData->status = 1; GNUNET_free_non_null (diffValue); break; } #if 0 case PRINT: if (NULL == cbData->section) { cbData->section = section; printf ("\nSection: %s\n", section); } else if (strcmp (cbData->section, section) != 0) { cbData->section = section; printf ("\nSection: %s\n", section); } printf ("%s = %s\n", option, value); #endif default: break; } } static struct GNUNET_CONFIGURATION_Handle * editConfiguration (struct GNUNET_CONFIGURATION_Handle *cfg, int option) { struct DiffsCBData diffsCB; initDiffsCBData (&diffsCB); diffsCB.cfgDiffs = GNUNET_CONFIGURATION_create (); switch (option) { case EDIT_SECTION: case EDIT_ALL: case ADD_NEW_ENTRY: diffsCB.callBackOption = option; diffsCB.cfg = cfg; GNUNET_CONFIGURATION_iterate (cfg, diffsCallBack, &diffsCB); break; case EDIT_NOTHING: /* Do nothing */ break; case ADD_NEW_SECTION: { int i; char *key; for (i = 0; i < 5; i++) { GNUNET_asprintf (&key, "key%d", i); GNUNET_CONFIGURATION_set_value_string (cfg, "new-section", key, "new-value"); GNUNET_CONFIGURATION_set_value_string (diffsCB.cfgDiffs, "new-section", key, "new-value"); GNUNET_free (key); } break; } case REMOVE_SECTION: break; case REMOVE_ENTRY: break; default: break; } return diffsCB.cfgDiffs; } /** * Checking configuration diffs */ static int checkDiffs (struct GNUNET_CONFIGURATION_Handle *cfgDefault, int option) { struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_CONFIGURATION_Handle *cfgDiffs; struct DiffsCBData cbData; int ret; char *diffsFileName; initDiffsCBData (&cbData); cfg = GNUNET_CONFIGURATION_create (); /* load defaults */ GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (cfg, NULL)); /* Modify configuration and save it */ cfgDiffs = editConfiguration (cfg, option); diffsFileName = GNUNET_DISK_mktemp ("gnunet-test-configurations-diffs.conf"); if (diffsFileName == NULL) { GNUNET_break (0); GNUNET_CONFIGURATION_destroy (cfg); GNUNET_CONFIGURATION_destroy (cfgDiffs); return 1; } GNUNET_CONFIGURATION_write_diffs (cfgDefault, cfg, diffsFileName); GNUNET_CONFIGURATION_destroy (cfg); /* Compare the dumped configuration with modifications done */ cfg = GNUNET_CONFIGURATION_create (); GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_parse (cfg, diffsFileName)); remove (diffsFileName); cbData.callBackOption = COMPARE; cbData.cfgDiffs = cfgDiffs; GNUNET_CONFIGURATION_iterate (cfg, diffsCallBack, &cbData); if (1 == (ret = cbData.status)) { FPRINTF (stderr, "%s", "Incorrect Configuration Diffs: Diffs may contain data not actually edited\n"); goto housekeeping; } cbData.cfgDiffs = cfg; GNUNET_CONFIGURATION_iterate (cfgDiffs, diffsCallBack, &cbData); if ((ret = cbData.status) == 1) FPRINTF (stderr, "%s", "Incorrect Configuration Diffs: Data may be missing in diffs\n"); housekeeping: #if 0 cbData.section = NULL; cbData.callBackOption = PRINT; printf ("\nExpected Diffs:\n"); GNUNET_CONFIGURATION_iterate (cfgDiffs, diffsCallBack, &cbData); cbData.section = NULL; printf ("\nActual Diffs:\n"); GNUNET_CONFIGURATION_iterate (cfg, diffsCallBack, &cbData); #endif GNUNET_CONFIGURATION_destroy (cfg); GNUNET_CONFIGURATION_destroy (cfgDiffs); GNUNET_free (diffsFileName); return ret; } static int testConfig () { char *c; unsigned long long l; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "test", "b", &c)) return 1; if (0 != strcmp ("b", c)) { FPRINTF (stderr, "Got `%s'\n", c); GNUNET_free (c); return 2; } GNUNET_free (c); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "test", "five", &l)) { GNUNET_break (0); return 3; } if (5 != l) { GNUNET_break (0); return 4; } GNUNET_CONFIGURATION_set_value_string (cfg, "more", "c", "YES"); if (GNUNET_NO == GNUNET_CONFIGURATION_get_value_yesno (cfg, "more", "c")) { GNUNET_break (0); return 5; } GNUNET_CONFIGURATION_set_value_number (cfg, "NUMBERS", "TEN", 10); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "NUMBERS", "TEN", &c)) { GNUNET_break (0); return 6; } if (0 != strcmp (c, "10")) { GNUNET_free (c); GNUNET_break (0); return 7; } GNUNET_free (c); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "last", "test", &c)) { GNUNET_break (0); return 8; } #ifndef MINGW if (0 != strcmp (c, "/hello/world")) #else #define HI "\\hello\\world" if (strstr (c, HI) != c + strlen (c) - strlen (HI)) #endif { GNUNET_break (0); GNUNET_free (c); return 9; } GNUNET_free (c); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_size (cfg, "last", "size", &l)) { GNUNET_break (0); return 10; } if (l != 512 * 1024) { GNUNET_break (0); return 11; } return 0; } static const char *want[] = { "/Hello", "/File Name", "/World", NULL, NULL, }; static int check (void *data, const char *fn) { int *idx = data; if (0 == strcmp (want[*idx], fn)) { (*idx)++; return GNUNET_OK; } GNUNET_break (0); return GNUNET_SYSERR; } static int testConfigFilenames () { int idx; idx = 0; if (3 != GNUNET_CONFIGURATION_iterate_value_filenames (cfg, "FILENAMES", "test", &check, &idx)) { GNUNET_break (0); return 8; } if (idx != 3) return 16; if (GNUNET_OK != GNUNET_CONFIGURATION_remove_value_filename (cfg, "FILENAMES", "test", "/File Name")) { GNUNET_break (0); return 24; } if (GNUNET_NO != GNUNET_CONFIGURATION_remove_value_filename (cfg, "FILENAMES", "test", "/File Name")) { GNUNET_break (0); return 32; } if (GNUNET_NO != GNUNET_CONFIGURATION_remove_value_filename (cfg, "FILENAMES", "test", "Stuff")) { GNUNET_break (0); return 40; } if (GNUNET_NO != GNUNET_CONFIGURATION_append_value_filename (cfg, "FILENAMES", "test", "/Hello")) { GNUNET_break (0); return 48; } if (GNUNET_NO != GNUNET_CONFIGURATION_append_value_filename (cfg, "FILENAMES", "test", "/World")) { GNUNET_break (0); return 56; } if (GNUNET_YES != GNUNET_CONFIGURATION_append_value_filename (cfg, "FILENAMES", "test", "/File 1")) { GNUNET_break (0); return 64; } if (GNUNET_YES != GNUNET_CONFIGURATION_append_value_filename (cfg, "FILENAMES", "test", "/File 2")) { GNUNET_break (0); return 72; } idx = 0; want[1] = "/World"; want[2] = "/File 1"; want[3] = "/File 2"; if (4 != GNUNET_CONFIGURATION_iterate_value_filenames (cfg, "FILENAMES", "test", &check, &idx)) { GNUNET_break (0); return 80; } if (idx != 4) { GNUNET_break (0); return 88; } return 0; } int main (int argc, char *argv[]) { int failureCount = 0; char *c; GNUNET_log_setup ("test_configuration", "WARNING", NULL); cfg = GNUNET_CONFIGURATION_create (); GNUNET_assert (cfg != NULL); if (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, "test_configuration_data.conf")) { FPRINTF (stderr, "%s", "Failed to parse configuration file\n"); GNUNET_CONFIGURATION_destroy (cfg); return 1; } failureCount += testConfig (); if (failureCount > 0) goto error; failureCount = testConfigFilenames (); if (failureCount > 0) goto error; if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, "/tmp/gnunet-test.conf")) { FPRINTF (stderr, "%s", "Failed to write configuration file\n"); GNUNET_CONFIGURATION_destroy (cfg); return 1; } GNUNET_CONFIGURATION_destroy (cfg); GNUNET_assert (0 == UNLINK ("/tmp/gnunet-test.conf")); cfg = GNUNET_CONFIGURATION_create (); if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, "test_configuration_data.conf")) { GNUNET_break (0); GNUNET_CONFIGURATION_destroy (cfg); return 1; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "TESTING", "WEAKRANDOM", &c)) { GNUNET_break (0); GNUNET_CONFIGURATION_destroy (cfg); return 1; } if (0 != strcmp (c, "YES")) { GNUNET_break (0); GNUNET_free (c); GNUNET_CONFIGURATION_destroy (cfg); return 1; } GNUNET_free (c); GNUNET_CONFIGURATION_destroy (cfg); /* Testing configuration diffs */ cfgDefault = GNUNET_CONFIGURATION_create (); if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfgDefault, NULL)) { GNUNET_break (0); GNUNET_CONFIGURATION_destroy (cfgDefault); return 1; } /* Nothing changed in the new configuration */ failureCount += checkDiffs (cfgDefault, EDIT_NOTHING); /* Modify all entries of the last section */ failureCount += checkDiffs (cfgDefault, EDIT_SECTION); /* Add a new section */ failureCount += checkDiffs (cfgDefault, ADD_NEW_SECTION); /* Add a new entry to the last section */ failureCount += checkDiffs (cfgDefault, ADD_NEW_ENTRY); /* Modify all entries in the configuration */ failureCount += checkDiffs (cfgDefault, EDIT_ALL); GNUNET_CONFIGURATION_destroy (cfgDefault); error: if (failureCount != 0) { FPRINTF (stderr, "Test failed: %u\n", failureCount); return 1; } return 0; } gnunet-0.9.3/src/util/client.c0000644000175000017500000010760011760502551013140 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2006, 2008, 2009, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/client.c * @brief code for access to services * @author Christian Grothoff * * Generic TCP code for reliable, record-oriented TCP * connections between clients and service providers. */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_client_lib.h" #include "gnunet_protocols.h" #include "gnunet_server_lib.h" #include "gnunet_scheduler_lib.h" /** * How often do we re-try tranmsitting requests before giving up? * Note that if we succeeded transmitting a request but failed to read * a response, we do NOT re-try. */ #define MAX_ATTEMPTS 50 #define LOG(kind,...) GNUNET_log_from (kind, "util",__VA_ARGS__) /** * Handle for a transmission request. */ struct GNUNET_CLIENT_TransmitHandle { /** * Connection state. */ struct GNUNET_CLIENT_Connection *client; /** * Function to call to get the data for transmission. */ GNUNET_CONNECTION_TransmitReadyNotify notify; /** * Closure for notify. */ void *notify_cls; /** * Handle to the transmission with the underlying * connection. */ struct GNUNET_CONNECTION_TransmitHandle *th; /** * If we are re-trying and are delaying to do so, * handle to the scheduled task managing the delay. */ GNUNET_SCHEDULER_TaskIdentifier reconnect_task; /** * Timeout for the operation overall. */ struct GNUNET_TIME_Absolute timeout; /** * Number of bytes requested. */ size_t size; /** * Are we allowed to re-try to connect without telling * the user (of this API) about the connection troubles? */ int auto_retry; /** * Number of attempts left for transmitting the request. We may * fail the first time (say because the service is not yet up), in * which case (if auto_retry is set) we wait a bit and re-try * (timeout permitting). */ unsigned int attempts_left; }; /** * Context for processing * "GNUNET_CLIENT_transmit_and_get_response" requests. */ struct TransmitGetResponseContext { /** * Client handle. */ struct GNUNET_CLIENT_Connection *client; /** * Message to transmit; do not free, allocated * right after this struct. */ const struct GNUNET_MessageHeader *hdr; /** * Timeout to use. */ struct GNUNET_TIME_Absolute timeout; /** * Function to call when done. */ GNUNET_CLIENT_MessageHandler rn; /** * Closure for "rn". */ void *rn_cls; }; /** * Struct to refer to a GNUnet TCP connection. * This is more than just a socket because if the server * drops the connection, the client automatically tries * to reconnect (and for that needs connection information). */ struct GNUNET_CLIENT_Connection { /** * The connection handle, NULL if not live */ struct GNUNET_CONNECTION_Handle *connection; /** * Our configuration. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Name of the service we interact with. */ char *service_name; /** * Context of a transmit_and_get_response operation, NULL * if no such operation is pending. */ struct TransmitGetResponseContext *tag; /** * Handler for current receiver task. */ GNUNET_CLIENT_MessageHandler receiver_handler; /** * Closure for receiver_handler. */ void *receiver_handler_cls; /** * Handle for a pending transmission request, NULL if there is * none pending. */ struct GNUNET_CLIENT_TransmitHandle *th; /** * Handler for service test completion (NULL unless in service_test) */ GNUNET_SCHEDULER_Task test_cb; /** * Deadline for calling 'test_cb'. */ struct GNUNET_TIME_Absolute test_deadline; /** * If we are re-trying and are delaying to do so, * handle to the scheduled task managing the delay. */ GNUNET_SCHEDULER_TaskIdentifier receive_task; /** * Closure for test_cb (NULL unless in service_test) */ void *test_cb_cls; /** * Buffer for received message. */ char *received_buf; /** * Timeout for receiving a response (absolute time). */ struct GNUNET_TIME_Absolute receive_timeout; /** * Current value for our incremental back-off (for * connect re-tries). */ struct GNUNET_TIME_Relative back_off; /** * Number of bytes in received_buf that are valid. */ size_t received_pos; /** * Size of received_buf. */ unsigned int received_size; /** * Do we have a complete response in received_buf? */ int msg_complete; /** * Are we currently busy doing receive-processing? * GNUNET_YES if so, GNUNET_NO if not. */ int in_receive; /** * How often have we tried to connect? */ unsigned int attempts; }; /** * Try connecting to the server using UNIX domain sockets. * * @param service_name name of service to connect to * @param cfg configuration to use * @return NULL on error, connection to UNIX otherwise */ static struct GNUNET_CONNECTION_Handle * try_unixpath (const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg) { #if AF_UNIX struct GNUNET_CONNECTION_Handle *connection; char *unixpath; unixpath = NULL; if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "UNIXPATH", &unixpath)) && (0 < strlen (unixpath))) { /* We have a non-NULL unixpath, need to validate it */ connection = GNUNET_CONNECTION_create_from_connect_to_unixpath (cfg, unixpath); if (NULL != connection) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Connected to unixpath `%s'!\n", unixpath); GNUNET_free (unixpath); return connection; } } GNUNET_free_non_null (unixpath); #endif return NULL; } /** * Try connecting to the server using UNIX domain sockets. * * @param service_name name of service to connect to * @param cfg configuration to use * @return GNUNET_OK if the configuration is valid, GNUNET_SYSERR if not */ static int test_service_configuration (const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg) { int ret = GNUNET_SYSERR; char *hostname = NULL; unsigned long long port; #if AF_UNIX char *unixpath = NULL; if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "UNIXPATH", &unixpath)) && (0 < strlen (unixpath))) ret = GNUNET_OK; GNUNET_free_non_null (unixpath); #endif if ( (GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT")) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "PORT", &port)) && (port <= 65535) && (0 != port) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "HOSTNAME", &hostname)) && (0 != strlen (hostname)) ) ret = GNUNET_OK; GNUNET_free_non_null (hostname); return ret; } /** * Try to connect to the service. * * @param service_name name of service to connect to * @param cfg configuration to use * @param attempt counter used to alternate between IP and UNIX domain sockets * @return NULL on error */ static struct GNUNET_CONNECTION_Handle * do_connect (const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned int attempt) { struct GNUNET_CONNECTION_Handle *connection; char *hostname; unsigned long long port; connection = NULL; if (0 == (attempt % 2)) { /* on even rounds, try UNIX first */ connection = try_unixpath (service_name, cfg); if (NULL != connection) return connection; } if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT")) { if ((GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "PORT", &port)) || (port > 65535) || (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "HOSTNAME", &hostname))) { LOG (GNUNET_ERROR_TYPE_WARNING, _ ("Could not determine valid hostname and port for service `%s' from configuration.\n"), service_name); return NULL; } if (0 == strlen (hostname)) { GNUNET_free (hostname); LOG (GNUNET_ERROR_TYPE_WARNING, _("Need a non-empty hostname for service `%s'.\n"), service_name); return NULL; } } else { /* unspecified means 0 (disabled) */ port = 0; hostname = NULL; } if (0 == port) { /* if port is 0, try UNIX */ connection = try_unixpath (service_name, cfg); if (NULL != connection) return connection; LOG (GNUNET_ERROR_TYPE_DEBUG, "Port is 0 for service `%s', UNIXPATH did not work, returning NULL!\n", service_name); GNUNET_free_non_null (hostname); return NULL; } connection = GNUNET_CONNECTION_create_from_connect (cfg, hostname, port); GNUNET_free (hostname); return connection; } /** * Get a connection with a service. * * @param service_name name of the service * @param cfg configuration to use * @return NULL on error (service unknown to configuration) */ struct GNUNET_CLIENT_Connection * GNUNET_CLIENT_connect (const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_CLIENT_Connection *client; struct GNUNET_CONNECTION_Handle *connection; if (GNUNET_OK != test_service_configuration (service_name, cfg)) return NULL; connection = do_connect (service_name, cfg, 0); client = GNUNET_malloc (sizeof (struct GNUNET_CLIENT_Connection)); client->attempts = 1; client->connection = connection; client->service_name = GNUNET_strdup (service_name); client->cfg = cfg; client->back_off = GNUNET_TIME_UNIT_MILLISECONDS; return client; } /** * Destroy connection with the service. This will automatically * cancel any pending "receive" request (however, the handler will * *NOT* be called, not even with a NULL message). Any pending * transmission request will also be cancelled UNLESS the callback for * the transmission request has already been called, in which case the * transmission 'finish_pending_write' argument determines whether or * not the write is guaranteed to complete before the socket is fully * destroyed (unless, of course, there is an error with the server in * which case the message may still be lost). * * @param client handle to the service connection */ void GNUNET_CLIENT_disconnect (struct GNUNET_CLIENT_Connection *client) { if (GNUNET_YES == client->in_receive) { GNUNET_CONNECTION_receive_cancel (client->connection); client->in_receive = GNUNET_NO; } if (NULL != client->th) { GNUNET_CLIENT_notify_transmit_ready_cancel (client->th); client->th = NULL; } if (NULL != client->connection) { GNUNET_CONNECTION_destroy (client->connection); client->connection = NULL; } if (GNUNET_SCHEDULER_NO_TASK != client->receive_task) { GNUNET_SCHEDULER_cancel (client->receive_task); client->receive_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != client->tag) { GNUNET_free (client->tag); client->tag = NULL; } client->receiver_handler = NULL; GNUNET_array_grow (client->received_buf, client->received_size, 0); GNUNET_free (client->service_name); GNUNET_free (client); } /** * Check if message is complete. Sets the "msg_complete" member * in the client struct. * * @param client connection with the buffer to check */ static void check_complete (struct GNUNET_CLIENT_Connection *client) { if ((client->received_pos >= sizeof (struct GNUNET_MessageHeader)) && (client->received_pos >= ntohs (((const struct GNUNET_MessageHeader *) client->received_buf)-> size))) client->msg_complete = GNUNET_YES; } /** * Callback function for data received from the network. Note that * both "available" and "errCode" would be 0 if the read simply timed out. * * @param cls closure * @param buf pointer to received data * @param available number of bytes availabe in "buf", * possibly 0 (on errors) * @param addr address of the sender * @param addrlen size of addr * @param errCode value of errno (on errors receiving) */ static void receive_helper (void *cls, const void *buf, size_t available, const struct sockaddr *addr, socklen_t addrlen, int errCode) { struct GNUNET_CLIENT_Connection *client = cls; struct GNUNET_TIME_Relative remaining; GNUNET_CLIENT_MessageHandler receive_handler; void *receive_handler_cls; GNUNET_assert (GNUNET_NO == client->msg_complete); GNUNET_assert (GNUNET_YES == client->in_receive); client->in_receive = GNUNET_NO; if ((0 == available) || (NULL == client->connection) || (0 != errCode)) { /* signal timeout! */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Timeout in receive_helper, available %u, client->connection %s, errCode `%s'\n", (unsigned int) available, NULL == client->connection ? "NULL" : "non-NULL", STRERROR (errCode)); if (NULL != (receive_handler = client->receiver_handler)) { receive_handler_cls = client->receiver_handler_cls; client->receiver_handler = NULL; receive_handler (receive_handler_cls, NULL); } return; } /* FIXME: optimize for common fast case where buf contains the * entire message and we need no copying... */ /* slow path: append to array */ if (client->received_size < client->received_pos + available) GNUNET_array_grow (client->received_buf, client->received_size, client->received_pos + available); memcpy (&client->received_buf[client->received_pos], buf, available); client->received_pos += available; check_complete (client); /* check for timeout */ remaining = GNUNET_TIME_absolute_get_remaining (client->receive_timeout); if (0 == remaining.rel_value) { /* signal timeout! */ if (NULL != client->receiver_handler) client->receiver_handler (client->receiver_handler_cls, NULL); return; } /* back to receive -- either for more data or to call callback! */ GNUNET_CLIENT_receive (client, client->receiver_handler, client->receiver_handler_cls, remaining); } /** * Continuation to call the receive callback. * * @param cls our handle to the client connection * @param tc scheduler context */ static void receive_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CLIENT_Connection *client = cls; GNUNET_CLIENT_MessageHandler handler = client->receiver_handler; const struct GNUNET_MessageHeader *cmsg = (const struct GNUNET_MessageHeader *) client->received_buf; void *handler_cls = client->receiver_handler_cls; uint16_t msize = ntohs (cmsg->size); char mbuf[msize]; struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) mbuf; LOG (GNUNET_ERROR_TYPE_DEBUG, "Received message of type %u and size %u\n", ntohs (cmsg->type), msize); client->receive_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_assert (GNUNET_YES == client->msg_complete); GNUNET_assert (client->received_pos >= msize); memcpy (msg, cmsg, msize); memmove (client->received_buf, &client->received_buf[msize], client->received_pos - msize); client->received_pos -= msize; client->msg_complete = GNUNET_NO; client->receiver_handler = NULL; check_complete (client); if (NULL != handler) handler (handler_cls, msg); } /** * Read from the service. * * @param client the service * @param handler function to call with the message * @param handler_cls closure for handler * @param timeout how long to wait until timing out */ void GNUNET_CLIENT_receive (struct GNUNET_CLIENT_Connection *client, GNUNET_CLIENT_MessageHandler handler, void *handler_cls, struct GNUNET_TIME_Relative timeout) { if (NULL == client->connection) { /* already disconnected, fail instantly! */ GNUNET_break (0); /* this should not happen in well-written code! */ if (NULL != handler) handler (handler_cls, NULL); return; } client->receiver_handler = handler; client->receiver_handler_cls = handler_cls; client->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout); if (GNUNET_YES == client->msg_complete) { GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == client->receive_task); client->receive_task = GNUNET_SCHEDULER_add_now (&receive_task, client); } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "calling GNUNET_CONNECTION_receive\n"); GNUNET_assert (GNUNET_NO == client->in_receive); client->in_receive = GNUNET_YES; GNUNET_CONNECTION_receive (client->connection, GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, timeout, &receive_helper, client); } } /** * Report service unavailable. */ static void service_test_error (GNUNET_SCHEDULER_Task task, void *task_cls) { GNUNET_SCHEDULER_add_continuation (task, task_cls, GNUNET_SCHEDULER_REASON_TIMEOUT); } /** * Receive confirmation from test, service is up. * * @param cls closure * @param msg message received, NULL on timeout or fatal error */ static void confirm_handler (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_CLIENT_Connection *client = cls; /* We may want to consider looking at the reply in more * detail in the future, for example, is this the * correct service? FIXME! */ if (NULL != msg) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Received confirmation that service is running.\n"); GNUNET_SCHEDULER_add_continuation (client->test_cb, client->test_cb_cls, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } else { service_test_error (client->test_cb, client->test_cb_cls); } GNUNET_CLIENT_disconnect (client); } /** * Send the 'TEST' message to the service. If successful, prepare to * receive the reply. * * @param cls the 'struct GNUNET_CLIENT_Connection' of the connection to test * @param size number of bytes available in buf * @param buf where to write the message * @return number of bytes written to buf */ static size_t write_test (void *cls, size_t size, void *buf) { struct GNUNET_CLIENT_Connection *client = cls; struct GNUNET_MessageHeader *msg; if (size < sizeof (struct GNUNET_MessageHeader)) { LOG (GNUNET_ERROR_TYPE_DEBUG, _("Failure to transmit TEST request.\n")); service_test_error (client->test_cb, client->test_cb_cls); GNUNET_CLIENT_disconnect (client); return 0; /* client disconnected */ } LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' request.\n", "TEST"); msg = (struct GNUNET_MessageHeader *) buf; msg->type = htons (GNUNET_MESSAGE_TYPE_TEST); msg->size = htons (sizeof (struct GNUNET_MessageHeader)); GNUNET_CLIENT_receive (client, &confirm_handler, client, GNUNET_TIME_absolute_get_remaining (client->test_deadline)); return sizeof (struct GNUNET_MessageHeader); } /** * Test if the service is running. If we are given a UNIXPATH or a local address, * we do this NOT by trying to connect to the service, but by trying to BIND to * the same port. If the BIND fails, we know the service is running. * * @param service name of the service to wait for * @param cfg configuration to use * @param timeout how long to wait at most * @param task task to run if service is running * (reason will be "PREREQ_DONE" (service running) * or "TIMEOUT" (service not known to be running)) * @param task_cls closure for task */ void GNUNET_CLIENT_service_test (const char *service, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TIME_Relative timeout, GNUNET_SCHEDULER_Task task, void *task_cls) { char *hostname; unsigned long long port; struct GNUNET_NETWORK_Handle *sock; struct GNUNET_CLIENT_Connection *client; LOG (GNUNET_ERROR_TYPE_DEBUG, "Testing if service `%s' is running.\n", service); #ifdef AF_UNIX { /* probe UNIX support */ struct sockaddr_un s_un; size_t slen; char *unixpath; unixpath = NULL; if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, service, "UNIXPATH", &unixpath)) && (0 < strlen (unixpath))) /* We have a non-NULL unixpath, does that mean it's valid? */ { if (strlen (unixpath) >= sizeof (s_un.sun_path)) { LOG (GNUNET_ERROR_TYPE_WARNING, _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath, sizeof (s_un.sun_path)); } else { sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0); if (NULL != sock) { memset (&s_un, 0, sizeof (s_un)); s_un.sun_family = AF_UNIX; slen = strlen (unixpath) + 1; if (slen >= sizeof (s_un.sun_path)) slen = sizeof (s_un.sun_path) - 1; memcpy (s_un.sun_path, unixpath, slen); s_un.sun_path[slen] = '\0'; slen = sizeof (struct sockaddr_un); #if LINUX s_un.sun_path[0] = '\0'; #endif #if HAVE_SOCKADDR_IN_SIN_LEN s_un.sun_len = (u_char) slen; #endif if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_un, slen)) { /* failed to bind => service must be running */ GNUNET_free (unixpath); (void) GNUNET_NETWORK_socket_close (sock); GNUNET_SCHEDULER_add_continuation (task, task_cls, GNUNET_SCHEDULER_REASON_PREREQ_DONE); return; } (void) GNUNET_NETWORK_socket_close (sock); } /* let's try IP */ } } GNUNET_free_non_null (unixpath); } #endif hostname = NULL; if ((GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, service, "PORT", &port)) || (port > 65535) || (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, service, "HOSTNAME", &hostname))) { /* UNIXPATH failed (if possible) AND IP failed => error */ service_test_error (task, task_cls); return; } if (0 == strcmp ("localhost", hostname) #if !LINUX && 0 #endif ) { /* can test using 'bind' */ struct sockaddr_in s_in; memset (&s_in, 0, sizeof (s_in)); #if HAVE_SOCKADDR_IN_SIN_LEN s_in.sin_len = sizeof (struct sockaddr_in); #endif s_in.sin_family = AF_INET; s_in.sin_port = htons (port); sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); if (NULL != sock) { if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_in, sizeof (s_in))) { /* failed to bind => service must be running */ GNUNET_free (hostname); (void) GNUNET_NETWORK_socket_close (sock); GNUNET_SCHEDULER_add_continuation (task, task_cls, GNUNET_SCHEDULER_REASON_PREREQ_DONE); return; } (void) GNUNET_NETWORK_socket_close (sock); } } if (0 == strcmp ("ip6-localhost", hostname) #if !LINUX && 0 #endif ) { /* can test using 'bind' */ struct sockaddr_in6 s_in6; memset (&s_in6, 0, sizeof (s_in6)); #if HAVE_SOCKADDR_IN_SIN_LEN s_in6.sin6_len = sizeof (struct sockaddr_in6); #endif s_in6.sin6_family = AF_INET6; s_in6.sin6_port = htons (port); sock = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_STREAM, 0); if (NULL != sock) { if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_in6, sizeof (s_in6))) { /* failed to bind => service must be running */ GNUNET_free (hostname); (void) GNUNET_NETWORK_socket_close (sock); GNUNET_SCHEDULER_add_continuation (task, task_cls, GNUNET_SCHEDULER_REASON_PREREQ_DONE); return; } (void) GNUNET_NETWORK_socket_close (sock); } } if (((0 == strcmp ("localhost", hostname)) || (0 == strcmp ("ip6-localhost", hostname))) #if !LINUX && 0 #endif ) { /* all binds succeeded => claim service not running right now */ GNUNET_free_non_null (hostname); service_test_error (task, task_cls); return; } GNUNET_free_non_null (hostname); /* non-localhost, try 'connect' method */ client = GNUNET_CLIENT_connect (service, cfg); if (NULL == client) { LOG (GNUNET_ERROR_TYPE_INFO, _("Could not connect to service `%s', must not be running.\n"), service); service_test_error (task, task_cls); return; } client->test_cb = task; client->test_cb_cls = task_cls; client->test_deadline = GNUNET_TIME_relative_to_absolute (timeout); if (NULL == GNUNET_CLIENT_notify_transmit_ready (client, sizeof (struct GNUNET_MessageHeader), timeout, GNUNET_YES, &write_test, client)) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Failure to transmit request to service `%s'\n"), service); service_test_error (task, task_cls); GNUNET_CLIENT_disconnect (client); return; } } /** * Connection notifies us about failure or success of * a transmission request. Either pass it on to our * user or, if possible, retry. * * @param cls our "struct GNUNET_CLIENT_TransmissionHandle" * @param size number of bytes available for transmission * @param buf where to write them * @return number of bytes written to buf */ static size_t client_notify (void *cls, size_t size, void *buf); /** * This task is run if we should re-try connection to the * service after a while. * * @param cls our "struct GNUNET_CLIENT_TransmitHandle" of the request * @param tc unused */ static void client_delayed_retry (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CLIENT_TransmitHandle *th = cls; struct GNUNET_TIME_Relative delay; th->reconnect_task = GNUNET_SCHEDULER_NO_TASK; th->client->connection = do_connect (th->client->service_name, th->client->cfg, th->client->attempts++); if (NULL == th->client->connection) { /* could happen if we're out of sockets */ delay = GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (th->timeout), th->client->back_off); th->client->back_off = GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply (th->client->back_off, 2), GNUNET_TIME_UNIT_SECONDS); LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission failed %u times, trying again in %llums.\n", MAX_ATTEMPTS - th->attempts_left, (unsigned long long) delay.rel_value); th->reconnect_task = GNUNET_SCHEDULER_add_delayed (delay, &client_delayed_retry, th); return; } th->th = GNUNET_CONNECTION_notify_transmit_ready (th->client->connection, th->size, GNUNET_TIME_absolute_get_remaining (th->timeout), &client_notify, th); if (NULL == th->th) { GNUNET_break (0); th->client->th = NULL; th->notify (th->notify_cls, 0, NULL); GNUNET_free (th); return; } } /** * Connection notifies us about failure or success of a transmission * request. Either pass it on to our user or, if possible, retry. * * @param cls our "struct GNUNET_CLIENT_TransmissionHandle" * @param size number of bytes available for transmission * @param buf where to write them * @return number of bytes written to buf */ static size_t client_notify (void *cls, size_t size, void *buf) { struct GNUNET_CLIENT_TransmitHandle *th = cls; struct GNUNET_CLIENT_Connection *client = th->client; size_t ret; struct GNUNET_TIME_Relative delay; th->th = NULL; client->th = NULL; if (NULL == buf) { delay = GNUNET_TIME_absolute_get_remaining (th->timeout); delay.rel_value /= 2; if ((GNUNET_YES != th->auto_retry) || (0 == --th->attempts_left) || (delay.rel_value < 1)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission failed %u times, giving up.\n", MAX_ATTEMPTS - th->attempts_left); GNUNET_break (0 == th->notify (th->notify_cls, 0, NULL)); GNUNET_free (th); return 0; } /* auto-retry */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect to `%s', automatically trying again.\n", client->service_name); if (GNUNET_YES == client->in_receive) { GNUNET_CONNECTION_receive_cancel (client->connection); client->in_receive = GNUNET_NO; } GNUNET_CONNECTION_destroy (client->connection); client->connection = NULL; delay = GNUNET_TIME_relative_min (delay, client->back_off); client->back_off = GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply (client->back_off, 2), GNUNET_TIME_UNIT_SECONDS); LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission failed %u times, trying again in %llums.\n", MAX_ATTEMPTS - th->attempts_left, (unsigned long long) delay.rel_value); client->th = th; th->reconnect_task = GNUNET_SCHEDULER_add_delayed (delay, &client_delayed_retry, th); return 0; } GNUNET_assert (size >= th->size); ret = th->notify (th->notify_cls, size, buf); GNUNET_free (th); return ret; } /** * Ask the client to call us once the specified number of bytes * are free in the transmission buffer. May call the notify * method immediately if enough space is available. * * @param client connection to the service * @param size number of bytes to send * @param timeout after how long should we give up (and call * notify with buf NULL and size 0)? * @param auto_retry if the connection to the service dies, should we * automatically re-connect and retry (within the timeout period) * or should we immediately fail in this case? Pass GNUNET_YES * if the caller does not care about temporary connection errors, * for example because the protocol is stateless * @param notify function to call * @param notify_cls closure for notify * @return NULL if our buffer will never hold size bytes, * a handle if the notify callback was queued (can be used to cancel) */ struct GNUNET_CLIENT_TransmitHandle * GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *client, size_t size, struct GNUNET_TIME_Relative timeout, int auto_retry, GNUNET_CONNECTION_TransmitReadyNotify notify, void *notify_cls) { struct GNUNET_CLIENT_TransmitHandle *th; if (NULL != client->th) { /* If this breaks, you most likley called this function twice without waiting * for completion or canceling the request */ GNUNET_break (0); return NULL; } th = GNUNET_malloc (sizeof (struct GNUNET_CLIENT_TransmitHandle)); th->client = client; th->size = size; th->timeout = GNUNET_TIME_relative_to_absolute (timeout); th->auto_retry = auto_retry; th->notify = notify; th->notify_cls = notify_cls; th->attempts_left = MAX_ATTEMPTS; client->th = th; if (NULL == client->connection) { th->reconnect_task = GNUNET_SCHEDULER_add_delayed (client->back_off, &client_delayed_retry, th); } else { th->th = GNUNET_CONNECTION_notify_transmit_ready (client->connection, size, timeout, &client_notify, th); if (NULL == th->th) { GNUNET_break (0); GNUNET_free (th); client->th = NULL; return NULL; } } return th; } /** * Cancel a request for notification. * * @param th handle from the original request. */ void GNUNET_CLIENT_notify_transmit_ready_cancel (struct GNUNET_CLIENT_TransmitHandle *th) { if (GNUNET_SCHEDULER_NO_TASK != th->reconnect_task) { GNUNET_assert (NULL == th->th); GNUNET_SCHEDULER_cancel (th->reconnect_task); th->reconnect_task = GNUNET_SCHEDULER_NO_TASK; } else { GNUNET_assert (NULL != th->th); GNUNET_CONNECTION_notify_transmit_ready_cancel (th->th); } th->client->th = NULL; GNUNET_free (th); } /** * Function called to notify a client about the socket * begin ready to queue the message. "buf" will be * NULL and "size" zero if the socket was closed for * writing in the meantime. * * @param cls closure of type "struct TransmitGetResponseContext*" * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_for_response (void *cls, size_t size, void *buf) { struct TransmitGetResponseContext *tc = cls; uint16_t msize; tc->client->tag = NULL; msize = ntohs (tc->hdr->size); if (NULL == buf) { LOG (GNUNET_ERROR_TYPE_DEBUG, _("Could not submit request, not expecting to receive a response.\n")); if (NULL != tc->rn) tc->rn (tc->rn_cls, NULL); GNUNET_free (tc); return 0; } GNUNET_assert (size >= msize); memcpy (buf, tc->hdr, msize); GNUNET_CLIENT_receive (tc->client, tc->rn, tc->rn_cls, GNUNET_TIME_absolute_get_remaining (tc->timeout)); GNUNET_free (tc); return msize; } /** * Convenience API that combines sending a request * to the service and waiting for a response. * If either operation times out, the callback * will be called with a "NULL" response (in which * case the connection should probably be destroyed). * * @param client connection to use * @param hdr message to transmit * @param timeout when to give up (for both transmission * and for waiting for a response) * @param auto_retry if the connection to the service dies, should we * automatically re-connect and retry (within the timeout period) * or should we immediately fail in this case? Pass GNUNET_YES * if the caller does not care about temporary connection errors, * for example because the protocol is stateless * @param rn function to call with the response * @param rn_cls closure for rn * @return GNUNET_OK on success, GNUNET_SYSERR if a request * is already pending */ int GNUNET_CLIENT_transmit_and_get_response (struct GNUNET_CLIENT_Connection *client, const struct GNUNET_MessageHeader *hdr, struct GNUNET_TIME_Relative timeout, int auto_retry, GNUNET_CLIENT_MessageHandler rn, void *rn_cls) { struct TransmitGetResponseContext *tc; uint16_t msize; if (NULL != client->th) return GNUNET_SYSERR; GNUNET_assert (NULL == client->tag); msize = ntohs (hdr->size); tc = GNUNET_malloc (sizeof (struct TransmitGetResponseContext) + msize); tc->client = client; tc->hdr = (const struct GNUNET_MessageHeader *) &tc[1]; memcpy (&tc[1], hdr, msize); tc->timeout = GNUNET_TIME_relative_to_absolute (timeout); tc->rn = rn; tc->rn_cls = rn_cls; if (NULL == GNUNET_CLIENT_notify_transmit_ready (client, msize, timeout, auto_retry, &transmit_for_response, tc)) { GNUNET_break (0); GNUNET_free (tc); return GNUNET_SYSERR; } client->tag = tc; return GNUNET_OK; } /* end of client.c */ gnunet-0.9.3/src/util/resolver.conf.in0000644000175000017500000000064111762215674014641 00000000000000[resolver] AUTOSTART = YES @JAVAPORT@PORT = 2089 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-resolver ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-resolver.sock UNIX_MATCH_UID = NO UNIX_MATCH_GID = NO # DISABLE_SOCKET_FORWARDING = NO # USERNAME = # MAXBUF = # TIMEOUT = # DISABLEV6 = # BINDTO = # REJECT_FROM = # REJECT_FROM6 = # PREFIX = gnunet-0.9.3/src/util/resolver.h0000644000175000017500000000367511760502551013537 00000000000000/* This file is part of GNUnet. (C) 2009, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @author Christian Grothoff * @file util/resolver.h */ #ifndef RESOLVER_H #define RESOLVER_H #include "gnunet_common.h" GNUNET_NETWORK_STRUCT_BEGIN /** * Request for the resolver. Followed by either the "struct sockaddr" * or the 0-terminated hostname. * * The response will be one or more messages of type * RESOLVER_RESPONSE, each with the message header immediately * followed by the requested data (0-terminated hostname or struct * in[6]_addr, depending on direction). The last RESOLVER_RESPONSE * will just be a header without any data (used to indicate the end of * the list). */ struct GNUNET_RESOLVER_GetMessage { /** * Type: GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST */ struct GNUNET_MessageHeader header; /** * GNUNET_YES to get hostname from IP, * GNUNET_NO to get IP from hostname. */ int32_t direction GNUNET_PACKED; /** * Address family to use (AF_INET, AF_INET6 or AF_UNSPEC). */ int32_t af GNUNET_PACKED; /* followed by 0-terminated string for A/AAAA-lookup or by 'struct in_addr' / 'struct in6_addr' for reverse lookup */ }; GNUNET_NETWORK_STRUCT_END #endif gnunet-0.9.3/src/util/test_container_heap.c0000644000175000017500000002520111760502551015674 00000000000000/* This file is part of GNUnet. (C) 2008 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @author Nathan Evans * @file util/test_container_heap.c * @brief Test of heap operations */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_container_lib.h" static int iterator_callback (void *cls, struct GNUNET_CONTAINER_HeapNode *node, void *element, GNUNET_CONTAINER_HeapCostType cost) { return GNUNET_OK; } static int nstrcmp (const char *a, const char *b) { GNUNET_assert (a != NULL); GNUNET_assert (b != NULL); return strcmp (a, b); } static int check () { struct GNUNET_CONTAINER_Heap *myHeap; struct GNUNET_CONTAINER_HeapNode *n1; struct GNUNET_CONTAINER_HeapNode *n2; struct GNUNET_CONTAINER_HeapNode *n3; struct GNUNET_CONTAINER_HeapNode *n4; struct GNUNET_CONTAINER_HeapNode *n5; struct GNUNET_CONTAINER_HeapNode *n6; struct GNUNET_CONTAINER_HeapNode *n7; struct GNUNET_CONTAINER_HeapNode *n8; const char *r; myHeap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); // GNUNET_CONTAINER_heap_remove_root heap empty, taking if-branch n1 = GNUNET_CONTAINER_heap_remove_root (myHeap); GNUNET_assert (NULL == n1); // GNUNET_CONTAINER_heap_peek heap empty, taking if-branch n1 = GNUNET_CONTAINER_heap_peek (myHeap); GNUNET_assert (NULL == n1); // GNUNET_CONTAINER_heap_walk_get_next: heap empty, taking if-branch n1 = GNUNET_CONTAINER_heap_walk_get_next (myHeap); GNUNET_assert (NULL == n1); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "11", 11); GNUNET_assert (NULL != n1); // GNUNET_CONTAINER_heap_peek not empty, taking if-branch n2 = NULL; n2 = GNUNET_CONTAINER_heap_peek (myHeap); GNUNET_assert (NULL != n2); // GNUNET_CONTAINER_heap_walk_get_next: 1 element n1 = NULL; n1 = GNUNET_CONTAINER_heap_walk_get_next (myHeap); GNUNET_assert (NULL != n1); GNUNET_CONTAINER_heap_iterate (myHeap, &iterator_callback, NULL); GNUNET_assert (1 == GNUNET_CONTAINER_heap_get_size (myHeap)); n2 = GNUNET_CONTAINER_heap_insert (myHeap, "78", 78); GNUNET_assert (2 == GNUNET_CONTAINER_heap_get_size (myHeap)); GNUNET_assert (0 == strcmp ("78", GNUNET_CONTAINER_heap_remove_node (n2))); GNUNET_assert (1 == GNUNET_CONTAINER_heap_get_size (myHeap)); GNUNET_CONTAINER_heap_iterate (myHeap, &iterator_callback, NULL); n3 = GNUNET_CONTAINER_heap_insert (myHeap, "15", 5); GNUNET_CONTAINER_heap_update_cost (myHeap, n3, 15); GNUNET_assert (2 == GNUNET_CONTAINER_heap_get_size (myHeap)); GNUNET_CONTAINER_heap_iterate (myHeap, &iterator_callback, NULL); n4 = GNUNET_CONTAINER_heap_insert (myHeap, "50", 50); GNUNET_CONTAINER_heap_update_cost (myHeap, n4, 50); GNUNET_assert (3 == GNUNET_CONTAINER_heap_get_size (myHeap)); GNUNET_CONTAINER_heap_iterate (myHeap, &iterator_callback, NULL); n5 = GNUNET_CONTAINER_heap_insert (myHeap, "100", 100); n6 = GNUNET_CONTAINER_heap_insert (myHeap, "30/200", 30); GNUNET_assert (5 == GNUNET_CONTAINER_heap_get_size (myHeap)); GNUNET_CONTAINER_heap_remove_node (n5); r = GNUNET_CONTAINER_heap_remove_root (myHeap); /* n1 */ GNUNET_assert (NULL != r); GNUNET_assert (0 == strcmp ("11", r)); GNUNET_CONTAINER_heap_update_cost (myHeap, n6, 200); GNUNET_CONTAINER_heap_remove_node (n3); r = GNUNET_CONTAINER_heap_remove_root (myHeap); /* n4 */ GNUNET_assert (NULL != r); GNUNET_assert (0 == strcmp ("50", r)); r = GNUNET_CONTAINER_heap_remove_root (myHeap); /* n6 */ GNUNET_assert (NULL != r); GNUNET_assert (0 == strcmp ("30/200", r)); GNUNET_assert (0 == GNUNET_CONTAINER_heap_get_size (myHeap)); GNUNET_CONTAINER_heap_destroy (myHeap); // My additions to a complete testcase // Testing a GNUNET_CONTAINER_HEAP_ORDER_MIN // Testing remove_node myHeap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); GNUNET_CONTAINER_heap_update_cost (myHeap, n1, 15); r = GNUNET_CONTAINER_heap_remove_node (n1); GNUNET_assert (NULL != r); GNUNET_assert (0 == strcmp ("10", r)); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10); GNUNET_CONTAINER_heap_walk_get_next (myHeap); r = GNUNET_CONTAINER_heap_remove_node (n2); GNUNET_assert (NULL != r); GNUNET_assert (0 == strcmp ("20", r)); r = GNUNET_CONTAINER_heap_remove_node (n1); GNUNET_assert (NULL != r); GNUNET_assert (0 == strcmp ("10", r)); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10); n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 10); GNUNET_CONTAINER_heap_remove_node (n2); GNUNET_CONTAINER_heap_remove_node (n1); r = GNUNET_CONTAINER_heap_remove_root (myHeap); GNUNET_assert (NULL != r); GNUNET_assert (0 == strcmp ("30", r)); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10); n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 10); GNUNET_CONTAINER_heap_remove_node (n2); GNUNET_CONTAINER_heap_remove_node (n1); r = GNUNET_CONTAINER_heap_remove_node (n3); GNUNET_assert (NULL != r); GNUNET_assert (0 == strcmp ("30", r)); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 20); n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 30); GNUNET_assert (0 == nstrcmp ("20", GNUNET_CONTAINER_heap_remove_node (n2))); GNUNET_assert (0 == nstrcmp ("10", GNUNET_CONTAINER_heap_remove_root (myHeap))); GNUNET_assert (0 == nstrcmp ("30", GNUNET_CONTAINER_heap_remove_root (myHeap))); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 20); n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 30); n4 = GNUNET_CONTAINER_heap_insert (myHeap, "40", 40); n5 = GNUNET_CONTAINER_heap_insert (myHeap, "50", 50); n6 = GNUNET_CONTAINER_heap_insert (myHeap, "60", 60); // Inserting nodes deeper in the tree with lower costs n7 = GNUNET_CONTAINER_heap_insert (myHeap, "70", 10); n8 = GNUNET_CONTAINER_heap_insert (myHeap, "80", 10); GNUNET_assert (0 == nstrcmp ("30", GNUNET_CONTAINER_heap_remove_node (n3))); // Cleaning up... GNUNET_assert (0 == nstrcmp ("60", GNUNET_CONTAINER_heap_remove_node (n6))); GNUNET_assert (0 == nstrcmp ("50", GNUNET_CONTAINER_heap_remove_node (n5))); // Testing heap_walk_get_next GNUNET_CONTAINER_heap_walk_get_next (myHeap); GNUNET_CONTAINER_heap_walk_get_next (myHeap); GNUNET_CONTAINER_heap_walk_get_next (myHeap);; GNUNET_CONTAINER_heap_walk_get_next (myHeap); GNUNET_CONTAINER_heap_walk_get_next (myHeap); GNUNET_assert (0 == nstrcmp ("10", GNUNET_CONTAINER_heap_remove_node (n1))); GNUNET_assert (0 == nstrcmp ("20", GNUNET_CONTAINER_heap_remove_node (n2))); GNUNET_assert (0 == nstrcmp ("40", GNUNET_CONTAINER_heap_remove_node (n4))); GNUNET_assert (0 == nstrcmp ("70", GNUNET_CONTAINER_heap_remove_node (n7))); GNUNET_assert (0 == nstrcmp ("80", GNUNET_CONTAINER_heap_remove_node (n8))); // End Testing remove_node // Testing a GNUNET_CONTAINER_HEAP_ORDER_MAX GNUNET_CONTAINER_heap_destroy (myHeap); myHeap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); GNUNET_CONTAINER_heap_update_cost (myHeap, n1, 15); GNUNET_assert (0 == nstrcmp ("10", GNUNET_CONTAINER_heap_remove_node (n1))); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10); GNUNET_CONTAINER_heap_walk_get_next (myHeap); GNUNET_assert (0 == nstrcmp ("20", GNUNET_CONTAINER_heap_remove_node (n2))); GNUNET_assert (0 == nstrcmp ("10", GNUNET_CONTAINER_heap_remove_node (n1))); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10); n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 10); GNUNET_CONTAINER_heap_remove_node (n2); GNUNET_CONTAINER_heap_remove_node (n1); GNUNET_assert (0 == nstrcmp ("30", GNUNET_CONTAINER_heap_remove_root (myHeap))); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10); n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 10); GNUNET_CONTAINER_heap_remove_node (n2); GNUNET_CONTAINER_heap_remove_node (n1); GNUNET_assert (0 == nstrcmp ("30", GNUNET_CONTAINER_heap_remove_node (n3))); n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10); n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 20); n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 30); n4 = GNUNET_CONTAINER_heap_insert (myHeap, "40", 40); n5 = GNUNET_CONTAINER_heap_insert (myHeap, "50", 50); n6 = GNUNET_CONTAINER_heap_insert (myHeap, "60", 60); // Inserting nodes deeper in the tree with lower costs n7 = GNUNET_CONTAINER_heap_insert (myHeap, "70", 10); n8 = GNUNET_CONTAINER_heap_insert (myHeap, "80", 10); GNUNET_assert (0 == nstrcmp ("30", GNUNET_CONTAINER_heap_remove_node (n3))); // Cleaning up... GNUNET_assert (0 == nstrcmp ("60", GNUNET_CONTAINER_heap_remove_node (n6))); GNUNET_assert (0 == nstrcmp ("50", GNUNET_CONTAINER_heap_remove_node (n5))); // Testing heap_walk_get_next GNUNET_CONTAINER_heap_walk_get_next (myHeap); GNUNET_CONTAINER_heap_walk_get_next (myHeap); GNUNET_CONTAINER_heap_walk_get_next (myHeap);; GNUNET_CONTAINER_heap_walk_get_next (myHeap); GNUNET_CONTAINER_heap_walk_get_next (myHeap); GNUNET_assert (0 == nstrcmp ("10", GNUNET_CONTAINER_heap_remove_node (n1))); GNUNET_assert (0 == nstrcmp ("20", GNUNET_CONTAINER_heap_remove_node (n2))); GNUNET_assert (0 == nstrcmp ("40", GNUNET_CONTAINER_heap_remove_node (n4))); GNUNET_assert (0 == nstrcmp ("70", GNUNET_CONTAINER_heap_remove_node (n7))); GNUNET_assert (0 == nstrcmp ("80", GNUNET_CONTAINER_heap_remove_node (n8))); // End Testing remove_node GNUNET_CONTAINER_heap_destroy (myHeap); return 0; } int main (int argc, char **argv) { GNUNET_log_setup ("test-container-heap", "WARNING", NULL); return check (); } /* end of test_container_heap.c */ gnunet-0.9.3/src/util/crypto_kdf.c0000644000175000017500000000577411760502551014037 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/util/crypto_kdf.c * @brief Key derivation * @author Nils Durner */ #include #include "platform.h" #include "gnunet_crypto_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) /** * @brief Derive key * @param result buffer for the derived key, allocated by caller * @param out_len desired length of the derived key * @param xts salt * @param xts_len length of xts * @param skm source key material * @param skm_len length of skm * @param argp va_list of void * & size_t pairs for context chunks * @return GNUNET_YES on success */ int GNUNET_CRYPTO_kdf_v (void *result, size_t out_len, const void *xts, size_t xts_len, const void *skm, size_t skm_len, va_list argp) { /* * "Finally, we point out to a particularly advantageous instantiation using * HMAC-SHA512 as XTR and HMAC-SHA256 in PRF* (in which case the output from SHA-512 is * truncated to 256 bits). This makes sense in two ways: First, the extraction part is where we need a * stronger hash function due to the unconventional demand from the hash function in the extraction * setting. Second, as shown in Section 6, using HMAC with a truncated output as an extractor * allows to prove the security of HKDF under considerably weaker assumptions on the underlying * hash function." * * http://eprint.iacr.org/2010/264 */ return GNUNET_CRYPTO_hkdf_v (result, out_len, GCRY_MD_SHA512, GCRY_MD_SHA256, xts, xts_len, skm, skm_len, argp); } /** * @brief Derive key * @param result buffer for the derived key, allocated by caller * @param out_len desired length of the derived key * @param xts salt * @param xts_len length of xts * @param skm source key material * @param skm_len length of skm * @param ... void * & size_t pairs for context chunks * @return GNUNET_YES on success */ int GNUNET_CRYPTO_kdf (void *result, size_t out_len, const void *xts, size_t xts_len, const void *skm, size_t skm_len, ...) { va_list argp; int ret; va_start (argp, skm_len); ret = GNUNET_CRYPTO_kdf_v (result, out_len, xts, xts_len, skm, skm_len, argp); va_end (argp); return ret; } gnunet-0.9.3/src/util/test_getopt.c0000644000175000017500000001101111760502551014211 00000000000000/* This file is part of GNUnet. (C) 2003, 2004, 2005, 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_getopt.c * @brief testcase for util/getopt.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_configuration_lib.h" #include "gnunet_getopt_lib.h" #define VERBOSE 0 static int testMinimal () { char *const emptyargv[] = { "test", NULL }; const struct GNUNET_GETOPT_CommandLineOption emptyoptionlist[] = { GNUNET_GETOPT_OPTION_END }; if (1 != GNUNET_GETOPT_run ("test", emptyoptionlist, 1, emptyargv)) return 1; return 0; } static int testVerbose () { char *const myargv[] = { "test", "-V", "-V", "more", NULL }; unsigned int vflags = 0; const struct GNUNET_GETOPT_CommandLineOption verboseoptionlist[] = { GNUNET_GETOPT_OPTION_VERBOSE (&vflags), GNUNET_GETOPT_OPTION_END }; if (3 != GNUNET_GETOPT_run ("test", verboseoptionlist, 4, myargv)) { GNUNET_break (0); return 1; } if (vflags != 2) { GNUNET_break (0); return 1; } return 0; } static int testVersion () { char *const myargv[] = { "test_getopt", "-v", NULL }; const struct GNUNET_GETOPT_CommandLineOption versionoptionlist[] = { GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION), GNUNET_GETOPT_OPTION_END }; if (-1 != GNUNET_GETOPT_run ("test_getopt", versionoptionlist, 2, myargv)) { GNUNET_break (0); return 1; } return 0; } static int testAbout () { char *const myargv[] = { "test_getopt", "-h", NULL }; const struct GNUNET_GETOPT_CommandLineOption aboutoptionlist[] = { GNUNET_GETOPT_OPTION_HELP ("Testing"), GNUNET_GETOPT_OPTION_END }; if (-1 != GNUNET_GETOPT_run ("test_getopt", aboutoptionlist, 2, myargv)) { GNUNET_break (0); return 1; } return 0; } static int testLogOpts () { char *const myargv[] = { "test_getopt", "-l", "filename", "-L", "WARNING", NULL }; char *level = GNUNET_strdup ("stuff"); char *fn = NULL; const struct GNUNET_GETOPT_CommandLineOption logoptionlist[] = { GNUNET_GETOPT_OPTION_LOGFILE (&fn), GNUNET_GETOPT_OPTION_LOGLEVEL (&level), GNUNET_GETOPT_OPTION_END }; if (5 != GNUNET_GETOPT_run ("test_getopt", logoptionlist, 5, myargv)) { GNUNET_break (0); return 1; } GNUNET_assert (fn != NULL); if ((0 != strcmp (level, "WARNING")) || (0 != strcmp (fn, "filename"))) { GNUNET_break (0); GNUNET_free (level); GNUNET_free (fn); return 1; } GNUNET_free (level); GNUNET_free (fn); return 0; } static int testFlagNum () { char *const myargv[] = { "test_getopt", "-f", "-n", "42", "-N", "42", NULL }; int flag = 0; unsigned int num = 0; unsigned long long lnum = 0; const struct GNUNET_GETOPT_CommandLineOption logoptionlist[] = { {'f', "--flag", NULL, "helptext", 0, &GNUNET_GETOPT_set_one, (void *) &flag}, {'n', "--num", "ARG", "helptext", 1, &GNUNET_GETOPT_set_uint, (void *) &num}, {'N', "--lnum", "ARG", "helptext", 1, &GNUNET_GETOPT_set_ulong, (void *) &lnum}, GNUNET_GETOPT_OPTION_END }; if (6 != GNUNET_GETOPT_run ("test_getopt", logoptionlist, 6, myargv)) { GNUNET_break (0); return 1; } if ((1 != flag) || (42 != num) || (42 != lnum)) { GNUNET_break (0); return 1; } return 0; } int main (int argc, char *argv[]) { int errCnt = 0; GNUNET_log_setup ("test_getopt", "WARNING", NULL); /* suppress output from -h, -v options */ #ifndef MINGW GNUNET_break (0 == CLOSE (1)); #endif if (0 != testMinimal ()) errCnt++; if (0 != testVerbose ()) errCnt++; if (0 != testVersion ()) errCnt++; if (0 != testAbout ()) errCnt++; if (0 != testLogOpts ()) errCnt++; if (0 != testFlagNum ()) errCnt++; return errCnt; } gnunet-0.9.3/src/util/crypto_rsa.c0000644000175000017500000007664511760502551014065 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/crypto_rsa.c * @brief public key cryptography (RSA) with libgcrypt * @author Christian Grothoff * * Note that the code locks often needlessly on the gcrypt-locking api. * One would think that simple MPI operations should not require locking * (since only global operations on the random pool must be locked, * strictly speaking). But libgcrypt does sometimes require locking in * unexpected places, so the safe solution is to always lock even if it * is not required. The performance impact is minimal anyway. */ #include "platform.h" #include #include "gnunet_common.h" #include "gnunet_crypto_lib.h" #include "gnunet_disk_lib.h" #include "gnunet_strings_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) /** * The private information of an RSA key pair. * NOTE: this must match the definition in crypto_ksk.c */ struct GNUNET_CRYPTO_RsaPrivateKey { gcry_sexp_t sexp; }; #define HOSTKEY_LEN 2048 #define EXTRA_CHECKS ALLOW_EXTRA_CHECKS /** * Log an error message at log-level 'level' that indicates * a failure of the command 'cmd' with the message given * by gcry_strerror(rc). */ #define LOG_GCRY(level, cmd, rc) do { LOG(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, gcry_strerror(rc)); } while(0); /** * If target != size, move target bytes to the * end of the size-sized buffer and zero out the * first target-size bytes. */ static void adjust (unsigned char *buf, size_t size, size_t target) { if (size < target) { memmove (&buf[target - size], buf, size); memset (buf, 0, target - size); } } /** * Create a new private key. Caller must free return value. * * @return fresh private key */ struct GNUNET_CRYPTO_RsaPrivateKey * GNUNET_CRYPTO_rsa_key_create () { struct GNUNET_CRYPTO_RsaPrivateKey *ret; gcry_sexp_t s_key; gcry_sexp_t s_keyparam; GNUNET_assert (0 == gcry_sexp_build (&s_keyparam, NULL, "(genkey(rsa(nbits %d)(rsa-use-e 3:257)))", HOSTKEY_LEN)); GNUNET_assert (0 == gcry_pk_genkey (&s_key, s_keyparam)); gcry_sexp_release (s_keyparam); #if EXTRA_CHECKS GNUNET_assert (0 == gcry_pk_testkey (s_key)); #endif ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPrivateKey)); ret->sexp = s_key; return ret; } /** * Free memory occupied by hostkey * @param hostkey pointer to the memory to free */ void GNUNET_CRYPTO_rsa_key_free (struct GNUNET_CRYPTO_RsaPrivateKey *hostkey) { gcry_sexp_release (hostkey->sexp); GNUNET_free (hostkey); } static int key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname, const char *elems) { gcry_sexp_t list, l2; const char *s; int i, idx; list = gcry_sexp_find_token (sexp, topname, 0); if (!list) { return 1; } l2 = gcry_sexp_cadr (list); gcry_sexp_release (list); list = l2; if (!list) { return 2; } idx = 0; for (s = elems; *s; s++, idx++) { l2 = gcry_sexp_find_token (list, s, 1); if (!l2) { for (i = 0; i < idx; i++) { gcry_free (array[i]); array[i] = NULL; } gcry_sexp_release (list); return 3; /* required parameter not found */ } array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); gcry_sexp_release (l2); if (!array[idx]) { for (i = 0; i < idx; i++) { gcry_free (array[i]); array[i] = NULL; } gcry_sexp_release (list); return 4; /* required parameter is invalid */ } } gcry_sexp_release (list); return 0; } /** * Extract the public key of the host. * @param priv the private key * @param pub where to write the public key */ void GNUNET_CRYPTO_rsa_key_get_public (const struct GNUNET_CRYPTO_RsaPrivateKey *priv, struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pub) { gcry_mpi_t skey[2]; size_t size; int rc; rc = key_from_sexp (skey, priv->sexp, "public-key", "ne"); if (rc) rc = key_from_sexp (skey, priv->sexp, "private-key", "ne"); if (rc) rc = key_from_sexp (skey, priv->sexp, "rsa", "ne"); GNUNET_assert (0 == rc); pub->len = htons (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) - sizeof (pub->padding)); pub->sizen = htons (GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH); pub->padding = 0; size = GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH; GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG, &pub->key[0], size, &size, skey[0])); adjust (&pub->key[0], size, GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH); size = GNUNET_CRYPTO_RSA_KEY_LENGTH - GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH; GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG, &pub->key [GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH], size, &size, skey[1])); adjust (&pub->key[GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH], size, GNUNET_CRYPTO_RSA_KEY_LENGTH - GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH); gcry_mpi_release (skey[0]); gcry_mpi_release (skey[1]); } /** * Convert a public key to a string. * * @param pub key to convert * @return string representing 'pub' */ char * GNUNET_CRYPTO_rsa_public_key_to_string (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pub) { char *pubkeybuf; size_t keylen = (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)) * 8; char *end; if (keylen % 5 > 0) keylen += 5 - keylen % 5; keylen /= 5; pubkeybuf = GNUNET_malloc (keylen + 1); end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), pubkeybuf, keylen); if (NULL == end) { GNUNET_free (pubkeybuf); return NULL; } *end = '\0'; return pubkeybuf; } /** * Convert a string representing a public key to a public key. * * @param enc encoded public key * @param enclen number of bytes in enc (without 0-terminator) * @param pub where to store the public key * @return GNUNET_OK on success */ int GNUNET_CRYPTO_rsa_public_key_from_string (const char *enc, size_t enclen, struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pub) { size_t keylen = (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)) * 8; if (keylen % 5 > 0) keylen += 5 - keylen % 5; keylen /= 5; if (enclen != keylen) return GNUNET_SYSERR; if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen, (unsigned char*) pub, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded))) return GNUNET_SYSERR; if ( (ntohs (pub->len) != sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)) || (ntohs (pub->padding) != 0) || (ntohs (pub->sizen) != GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH) ) return GNUNET_SYSERR; return GNUNET_OK; } /** * Internal: publicKey => RSA-Key. * * Note that the return type is not actually a private * key but rather an sexpression for the public key! */ static struct GNUNET_CRYPTO_RsaPrivateKey * public2PrivateKey (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey) { struct GNUNET_CRYPTO_RsaPrivateKey *ret; gcry_sexp_t result; gcry_mpi_t n; gcry_mpi_t e; size_t size; size_t erroff; int rc; if ((ntohs (publicKey->sizen) != GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH) || (ntohs (publicKey->len) != sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) - sizeof (publicKey->padding))) { GNUNET_break (0); return NULL; } size = GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH; rc = gcry_mpi_scan (&n, GCRYMPI_FMT_USG, &publicKey->key[0], size, &size); if (rc) { LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); return NULL; } size = GNUNET_CRYPTO_RSA_KEY_LENGTH - GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH; rc = gcry_mpi_scan (&e, GCRYMPI_FMT_USG, &publicKey->key[GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH], size, &size); if (rc) { LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); gcry_mpi_release (n); return NULL; } rc = gcry_sexp_build (&result, &erroff, "(public-key(rsa(n %m)(e %m)))", n, e); gcry_mpi_release (n); gcry_mpi_release (e); if (rc) { LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); /* erroff gives more info */ return NULL; } ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPrivateKey)); ret->sexp = result; return ret; } /** * Encode the private key in a format suitable for * storing it into a file. * @returns encoding of the private key. * The first 4 bytes give the size of the array, as usual. */ struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded * GNUNET_CRYPTO_rsa_encode_key (const struct GNUNET_CRYPTO_RsaPrivateKey *hostkey) { struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *retval; gcry_mpi_t pkv[6]; void *pbu[6]; size_t sizes[6]; int rc; int i; int size; #if EXTRA_CHECKS if (gcry_pk_testkey (hostkey->sexp)) { GNUNET_break (0); return NULL; } #endif memset (pkv, 0, sizeof (gcry_mpi_t) * 6); rc = key_from_sexp (pkv, hostkey->sexp, "private-key", "nedpqu"); if (rc) rc = key_from_sexp (pkv, hostkey->sexp, "rsa", "nedpqu"); if (rc) rc = key_from_sexp (pkv, hostkey->sexp, "private-key", "nedpq"); if (rc) rc = key_from_sexp (pkv, hostkey->sexp, "rsa", "nedpq"); if (rc) rc = key_from_sexp (pkv, hostkey->sexp, "private-key", "ned"); if (rc) rc = key_from_sexp (pkv, hostkey->sexp, "rsa", "ned"); GNUNET_assert (0 == rc); size = sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded); for (i = 0; i < 6; i++) { if (pkv[i] != NULL) { GNUNET_assert (0 == gcry_mpi_aprint (GCRYMPI_FMT_USG, (unsigned char **) &pbu[i], &sizes[i], pkv[i])); size += sizes[i]; } else { pbu[i] = NULL; sizes[i] = 0; } } GNUNET_assert (size < 65536); retval = GNUNET_malloc (size); retval->len = htons (size); i = 0; retval->sizen = htons (sizes[0]); memcpy (&((char *) (&retval[1]))[i], pbu[0], sizes[0]); i += sizes[0]; retval->sizee = htons (sizes[1]); memcpy (&((char *) (&retval[1]))[i], pbu[1], sizes[1]); i += sizes[1]; retval->sized = htons (sizes[2]); memcpy (&((char *) (&retval[1]))[i], pbu[2], sizes[2]); i += sizes[2]; /* swap p and q! */ retval->sizep = htons (sizes[4]); memcpy (&((char *) (&retval[1]))[i], pbu[4], sizes[4]); i += sizes[4]; retval->sizeq = htons (sizes[3]); memcpy (&((char *) (&retval[1]))[i], pbu[3], sizes[3]); i += sizes[3]; retval->sizedmp1 = htons (0); retval->sizedmq1 = htons (0); memcpy (&((char *) (&retval[1]))[i], pbu[5], sizes[5]); for (i = 0; i < 6; i++) { if (pkv[i] != NULL) gcry_mpi_release (pkv[i]); if (pbu[i] != NULL) free (pbu[i]); } return retval; } /** * Decode the private key from the file-format back * to the "normal", internal format. * * @param buf the buffer where the private key data is stored * @param len the length of the data in 'buffer' */ struct GNUNET_CRYPTO_RsaPrivateKey * GNUNET_CRYPTO_rsa_decode_key (const char *buf, uint16_t len) { struct GNUNET_CRYPTO_RsaPrivateKey *ret; const struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *encoding = (const struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *) buf; gcry_sexp_t res; gcry_mpi_t n, e, d, p, q, u; int rc; size_t size; int pos; uint16_t enc_len; enc_len = ntohs (encoding->len); if (len != enc_len) return NULL; pos = 0; size = ntohs (encoding->sizen); rc = gcry_mpi_scan (&n, GCRYMPI_FMT_USG, &((const unsigned char *) (&encoding[1]))[pos], size, &size); pos += ntohs (encoding->sizen); if (rc) { LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); return NULL; } size = ntohs (encoding->sizee); rc = gcry_mpi_scan (&e, GCRYMPI_FMT_USG, &((const unsigned char *) (&encoding[1]))[pos], size, &size); pos += ntohs (encoding->sizee); if (rc) { LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); gcry_mpi_release (n); return NULL; } size = ntohs (encoding->sized); rc = gcry_mpi_scan (&d, GCRYMPI_FMT_USG, &((const unsigned char *) (&encoding[1]))[pos], size, &size); pos += ntohs (encoding->sized); if (rc) { LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); gcry_mpi_release (n); gcry_mpi_release (e); return NULL; } /* swap p and q! */ size = ntohs (encoding->sizep); if (size > 0) { rc = gcry_mpi_scan (&q, GCRYMPI_FMT_USG, &((const unsigned char *) (&encoding[1]))[pos], size, &size); pos += ntohs (encoding->sizep); if (rc) { LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); gcry_mpi_release (n); gcry_mpi_release (e); gcry_mpi_release (d); return NULL; } } else q = NULL; size = ntohs (encoding->sizeq); if (size > 0) { rc = gcry_mpi_scan (&p, GCRYMPI_FMT_USG, &((const unsigned char *) (&encoding[1]))[pos], size, &size); pos += ntohs (encoding->sizeq); if (rc) { LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); gcry_mpi_release (n); gcry_mpi_release (e); gcry_mpi_release (d); if (q != NULL) gcry_mpi_release (q); return NULL; } } else p = NULL; pos += ntohs (encoding->sizedmp1); pos += ntohs (encoding->sizedmq1); size = ntohs (encoding->len) - sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded) - pos; if (size > 0) { rc = gcry_mpi_scan (&u, GCRYMPI_FMT_USG, &((const unsigned char *) (&encoding[1]))[pos], size, &size); if (rc) { LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); gcry_mpi_release (n); gcry_mpi_release (e); gcry_mpi_release (d); if (p != NULL) gcry_mpi_release (p); if (q != NULL) gcry_mpi_release (q); return NULL; } } else u = NULL; if ((p != NULL) && (q != NULL) && (u != NULL)) { rc = gcry_sexp_build (&res, &size, /* erroff */ "(private-key(rsa(n %m)(e %m)(d %m)(p %m)(q %m)(u %m)))", n, e, d, p, q, u); } else { if ((p != NULL) && (q != NULL)) { rc = gcry_sexp_build (&res, &size, /* erroff */ "(private-key(rsa(n %m)(e %m)(d %m)(p %m)(q %m)))", n, e, d, p, q); } else { rc = gcry_sexp_build (&res, &size, /* erroff */ "(private-key(rsa(n %m)(e %m)(d %m)))", n, e, d); } } gcry_mpi_release (n); gcry_mpi_release (e); gcry_mpi_release (d); if (p != NULL) gcry_mpi_release (p); if (q != NULL) gcry_mpi_release (q); if (u != NULL) gcry_mpi_release (u); if (rc) LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); #if EXTRA_CHECKS if (gcry_pk_testkey (res)) { LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc); return NULL; } #endif ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPrivateKey)); ret->sexp = res; return ret; } /** * Create a new private key by reading it from a file. If the * files does not exist, create a new key and write it to the * file. Caller must free return value. Note that this function * can not guarantee that another process might not be trying * the same operation on the same file at the same time. * If the contents of the file * are invalid the old file is deleted and a fresh key is * created. * * @return new private key, NULL on error (for example, * permission denied) */ struct GNUNET_CRYPTO_RsaPrivateKey * GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename) { struct GNUNET_CRYPTO_RsaPrivateKey *ret; struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *enc; uint16_t len; struct GNUNET_DISK_FileHandle *fd; unsigned int cnt; int ec; uint64_t fs; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub; struct GNUNET_PeerIdentity pid; if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename)) return NULL; while (GNUNET_YES != GNUNET_DISK_file_test (filename)) { fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_FAILIFEXISTS, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (NULL == fd) { if (errno == EEXIST) { if (GNUNET_YES != GNUNET_DISK_file_test (filename)) { /* must exist but not be accessible, fail for good! */ if (0 != ACCESS (filename, R_OK)) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", filename); else GNUNET_break (0); /* what is going on!? */ return NULL; } continue; } LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename); return NULL; } cnt = 0; while (GNUNET_YES != GNUNET_DISK_file_lock (fd, 0, sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded), GNUNET_YES)) { sleep (1); if (0 == ++cnt % 10) { ec = errno; LOG (GNUNET_ERROR_TYPE_ERROR, _("Could not aquire lock on file `%s': %s...\n"), filename, STRERROR (ec)); } } LOG (GNUNET_ERROR_TYPE_INFO, _("Creating a new private key. This may take a while.\n")); ret = GNUNET_CRYPTO_rsa_key_create (); GNUNET_assert (ret != NULL); enc = GNUNET_CRYPTO_rsa_encode_key (ret); GNUNET_assert (enc != NULL); GNUNET_assert (ntohs (enc->len) == GNUNET_DISK_file_write (fd, enc, ntohs (enc->len))); GNUNET_free (enc); GNUNET_DISK_file_sync (fd); if (GNUNET_YES != GNUNET_DISK_file_unlock (fd, 0, sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded))) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd)); GNUNET_CRYPTO_rsa_key_get_public (ret, &pub); GNUNET_CRYPTO_hash (&pub, sizeof (pub), &pid.hashPubKey); LOG (GNUNET_ERROR_TYPE_INFO, _("I am host `%s'. Stored new private key in `%s'.\n"), GNUNET_i2s (&pid), filename); return ret; } /* hostkey file exists already, read it! */ fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); if (NULL == fd) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename); return NULL; } cnt = 0; while (1) { if (GNUNET_YES != GNUNET_DISK_file_lock (fd, 0, sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded), GNUNET_NO)) { if (0 == ++cnt % 60) { ec = errno; LOG (GNUNET_ERROR_TYPE_ERROR, _("Could not aquire lock on file `%s': %s...\n"), filename, STRERROR (ec)); LOG (GNUNET_ERROR_TYPE_ERROR, _ ("This may be ok if someone is currently generating a hostkey.\n")); } sleep (1); continue; } if (GNUNET_YES != GNUNET_DISK_file_test (filename)) { /* eh, what!? File we opened is now gone!? */ LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename); if (GNUNET_YES != GNUNET_DISK_file_unlock (fd, 0, sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded))) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); return NULL; } if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES)) fs = 0; if (fs < sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded)) { /* maybe we got the read lock before the hostkey generating * process had a chance to get the write lock; give it up! */ if (GNUNET_YES != GNUNET_DISK_file_unlock (fd, 0, sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded))) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); if (0 == ++cnt % 10) { LOG (GNUNET_ERROR_TYPE_ERROR, _ ("When trying to read hostkey file `%s' I found %u bytes but I need at least %u.\n"), filename, (unsigned int) fs, (unsigned int) sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded)); LOG (GNUNET_ERROR_TYPE_ERROR, _ ("This may be ok if someone is currently generating a hostkey.\n")); } sleep (2); /* wait a bit longer! */ continue; } break; } enc = GNUNET_malloc (fs); GNUNET_assert (fs == GNUNET_DISK_file_read (fd, enc, fs)); len = ntohs (enc->len); ret = NULL; if ((len != fs) || (NULL == (ret = GNUNET_CRYPTO_rsa_decode_key ((char *) enc, len)))) { LOG (GNUNET_ERROR_TYPE_ERROR, _("File `%s' does not contain a valid private key. Deleting it.\n"), filename); if (0 != UNLINK (filename)) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", filename); } } GNUNET_free (enc); if (GNUNET_YES != GNUNET_DISK_file_unlock (fd, 0, sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded))) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd)); if (ret != NULL) { GNUNET_CRYPTO_rsa_key_get_public (ret, &pub); GNUNET_CRYPTO_hash (&pub, sizeof (pub), &pid.hashPubKey); LOG (GNUNET_ERROR_TYPE_INFO, _("I am host `%s'. Read private key from `%s'.\n"), GNUNET_i2s (&pid), filename); } return ret; } /** * Setup a hostkey file for a peer given the name of the * configuration file (!). This function is used so that * at a later point code can be certain that reading a * hostkey is fast (for example in time-dependent testcases). * * @param cfg_name name of the configuration file to use */ void GNUNET_CRYPTO_setup_hostkey (const char *cfg_name) { struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_CRYPTO_RsaPrivateKey *pk; char *fn; cfg = GNUNET_CONFIGURATION_create (); (void) GNUNET_CONFIGURATION_load (cfg, cfg_name); if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY", &fn)) { pk = GNUNET_CRYPTO_rsa_key_create_from_file (fn); if (NULL != pk) GNUNET_CRYPTO_rsa_key_free (pk); GNUNET_free (fn); } GNUNET_CONFIGURATION_destroy (cfg); } /** * Encrypt a block with the public key of another host that uses the * same cipher. * * @param block the block to encrypt * @param size the size of block * @param publicKey the encoded public key used to encrypt * @param target where to store the encrypted block * @returns GNUNET_SYSERR on error, GNUNET_OK if ok */ int GNUNET_CRYPTO_rsa_encrypt (const void *block, size_t size, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey, struct GNUNET_CRYPTO_RsaEncryptedData *target) { gcry_sexp_t result; gcry_sexp_t data; struct GNUNET_CRYPTO_RsaPrivateKey *pubkey; gcry_mpi_t val; gcry_mpi_t rval; size_t isize; size_t erroff; GNUNET_assert (size <= sizeof (GNUNET_HashCode)); pubkey = public2PrivateKey (publicKey); if (pubkey == NULL) return GNUNET_SYSERR; isize = size; GNUNET_assert (0 == gcry_mpi_scan (&val, GCRYMPI_FMT_USG, block, isize, &isize)); GNUNET_assert (0 == gcry_sexp_build (&data, &erroff, "(data (flags pkcs1)(value %m))", val)); gcry_mpi_release (val); GNUNET_assert (0 == gcry_pk_encrypt (&result, data, pubkey->sexp)); gcry_sexp_release (data); GNUNET_CRYPTO_rsa_key_free (pubkey); GNUNET_assert (0 == key_from_sexp (&rval, result, "rsa", "a")); gcry_sexp_release (result); isize = sizeof (struct GNUNET_CRYPTO_RsaEncryptedData); GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG, (unsigned char *) target, isize, &isize, rval)); gcry_mpi_release (rval); adjust (&target->encoding[0], isize, sizeof (struct GNUNET_CRYPTO_RsaEncryptedData)); return GNUNET_OK; } /** * Decrypt a given block with the hostkey. * * @param key the key with which to decrypt this block * @param block the data to decrypt, encoded as returned by encrypt * @param result pointer to a location where the result can be stored * @param max the maximum number of bits to store for the result, if * the decrypted block is bigger, an error is returned * @return the size of the decrypted block, -1 on error */ ssize_t GNUNET_CRYPTO_rsa_decrypt (const struct GNUNET_CRYPTO_RsaPrivateKey * key, const struct GNUNET_CRYPTO_RsaEncryptedData * block, void *result, size_t max) { gcry_sexp_t resultsexp; gcry_sexp_t data; size_t erroff; size_t size; gcry_mpi_t val; unsigned char *endp; unsigned char *tmp; #if EXTRA_CHECKS GNUNET_assert (0 == gcry_pk_testkey (key->sexp)); #endif size = sizeof (struct GNUNET_CRYPTO_RsaEncryptedData); GNUNET_assert (0 == gcry_mpi_scan (&val, GCRYMPI_FMT_USG, &block->encoding[0], size, &size)); GNUNET_assert (0 == gcry_sexp_build (&data, &erroff, "(enc-val(flags)(rsa(a %m)))", val)); gcry_mpi_release (val); GNUNET_assert (0 == gcry_pk_decrypt (&resultsexp, data, key->sexp)); gcry_sexp_release (data); /* resultsexp has format "(value %m)" */ GNUNET_assert (NULL != (val = gcry_sexp_nth_mpi (resultsexp, 1, GCRYMPI_FMT_USG))); gcry_sexp_release (resultsexp); tmp = GNUNET_malloc (max + HOSTKEY_LEN / 8); size = max + HOSTKEY_LEN / 8; GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG, tmp, size, &size, val)); gcry_mpi_release (val); endp = tmp; endp += (size - max); size = max; memcpy (result, endp, size); GNUNET_free (tmp); return size; } /** * Sign a given block. * * @param key private key to use for the signing * @param purpose what to sign (size, purpose) * @param sig where to write the signature * @return GNUNET_SYSERR on error, GNUNET_OK on success */ int GNUNET_CRYPTO_rsa_sign (const struct GNUNET_CRYPTO_RsaPrivateKey *key, const struct GNUNET_CRYPTO_RsaSignaturePurpose *purpose, struct GNUNET_CRYPTO_RsaSignature *sig) { gcry_sexp_t result; gcry_sexp_t data; size_t ssize; gcry_mpi_t rval; GNUNET_HashCode hc; char *buff; int bufSize; GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc); #define FORMATSTRING "(4:data(5:flags5:pkcs1)(4:hash6:sha51264:0123456789012345678901234567890123456789012345678901234567890123))" bufSize = strlen (FORMATSTRING) + 1; buff = GNUNET_malloc (bufSize); memcpy (buff, FORMATSTRING, bufSize); memcpy (&buff [bufSize - strlen ("0123456789012345678901234567890123456789012345678901234567890123))") - 1], &hc, sizeof (GNUNET_HashCode)); GNUNET_assert (0 == gcry_sexp_new (&data, buff, bufSize, 0)); GNUNET_free (buff); GNUNET_assert (0 == gcry_pk_sign (&result, data, key->sexp)); gcry_sexp_release (data); GNUNET_assert (0 == key_from_sexp (&rval, result, "rsa", "s")); gcry_sexp_release (result); ssize = sizeof (struct GNUNET_CRYPTO_RsaSignature); GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG, (unsigned char *) sig, ssize, &ssize, rval)); gcry_mpi_release (rval); adjust (sig->sig, ssize, sizeof (struct GNUNET_CRYPTO_RsaSignature)); return GNUNET_OK; } /** * Verify signature. * * @param purpose what is the purpose that the signature should have? * @param validate block to validate (size, purpose, data) * @param sig signature that is being validated * @param publicKey public key of the signer * @returns GNUNET_OK if ok, GNUNET_SYSERR if invalid */ int GNUNET_CRYPTO_rsa_verify (uint32_t purpose, const struct GNUNET_CRYPTO_RsaSignaturePurpose *validate, const struct GNUNET_CRYPTO_RsaSignature *sig, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey) { gcry_sexp_t data; gcry_sexp_t sigdata; size_t size; gcry_mpi_t val; struct GNUNET_CRYPTO_RsaPrivateKey *hostkey; GNUNET_HashCode hc; char *buff; int bufSize; size_t erroff; int rc; if (purpose != ntohl (validate->purpose)) return GNUNET_SYSERR; /* purpose mismatch */ GNUNET_CRYPTO_hash (validate, ntohl (validate->size), &hc); size = sizeof (struct GNUNET_CRYPTO_RsaSignature); GNUNET_assert (0 == gcry_mpi_scan (&val, GCRYMPI_FMT_USG, (const unsigned char *) sig, size, &size)); GNUNET_assert (0 == gcry_sexp_build (&sigdata, &erroff, "(sig-val(rsa(s %m)))", val)); gcry_mpi_release (val); bufSize = strlen (FORMATSTRING) + 1; buff = GNUNET_malloc (bufSize); memcpy (buff, FORMATSTRING, bufSize); memcpy (&buff [strlen (FORMATSTRING) - strlen ("0123456789012345678901234567890123456789012345678901234567890123))")], &hc, sizeof (GNUNET_HashCode)); GNUNET_assert (0 == gcry_sexp_new (&data, buff, bufSize, 0)); GNUNET_free (buff); hostkey = public2PrivateKey (publicKey); if (hostkey == NULL) { gcry_sexp_release (data); gcry_sexp_release (sigdata); return GNUNET_SYSERR; } rc = gcry_pk_verify (sigdata, data, hostkey->sexp); GNUNET_CRYPTO_rsa_key_free (hostkey); gcry_sexp_release (data); gcry_sexp_release (sigdata); if (rc) { LOG (GNUNET_ERROR_TYPE_WARNING, _("RSA signature verification failed at %s:%d: %s\n"), __FILE__, __LINE__, gcry_strerror (rc)); return GNUNET_SYSERR; } return GNUNET_OK; } /* end of crypto_rsa.c */ gnunet-0.9.3/src/util/test_client.c0000644000175000017500000001450411760502551014177 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_client.c * @brief tests for client.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_client_lib.h" #include "gnunet_configuration_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_server_lib.h" #include "gnunet_time_lib.h" #define VERBOSE GNUNET_NO #define PORT 14325 #define MYNAME "test_client" static struct GNUNET_CLIENT_Connection *client; static struct GNUNET_SERVER_Handle *server; static struct GNUNET_CONFIGURATION_Handle *cfg; #define MY_TYPE 130 struct CopyContext { struct GNUNET_SERVER_Client *client; struct GNUNET_MessageHeader *cpy; }; static size_t copy_msg (void *cls, size_t size, void *buf) { struct CopyContext *ctx = cls; struct GNUNET_MessageHeader *cpy = ctx->cpy; GNUNET_assert (sizeof (struct GNUNET_MessageHeader) == ntohs (cpy->size)); GNUNET_assert (size >= ntohs (cpy->size)); memcpy (buf, cpy, ntohs (cpy->size)); GNUNET_SERVER_receive_done (ctx->client, GNUNET_OK); GNUNET_free (cpy); GNUNET_free (ctx); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message bounced back to client\n"); return sizeof (struct GNUNET_MessageHeader); } /** * Callback that just bounces the message back to the sender. */ static void echo_cb (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct CopyContext *cc; struct GNUNET_MessageHeader *cpy; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving message from client, bouncing back\n"); GNUNET_assert (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size)); cc = GNUNET_malloc (sizeof (struct CopyContext)); cc->client = client; cpy = GNUNET_malloc (ntohs (message->size)); memcpy (cpy, message, ntohs (message->size)); cc->cpy = cpy; GNUNET_assert (NULL != GNUNET_SERVER_notify_transmit_ready (client, ntohs (message->size), GNUNET_TIME_UNIT_SECONDS, ©_msg, cc)); } static struct GNUNET_SERVER_MessageHandler handlers[] = { {&echo_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)}, {NULL, NULL, 0, 0} }; static void recv_bounce (void *cls, const struct GNUNET_MessageHeader *got) { int *ok = cls; struct GNUNET_MessageHeader msg; GNUNET_assert (got != NULL); /* timeout */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving bounce, checking content\n"); msg.type = htons (MY_TYPE); msg.size = htons (sizeof (struct GNUNET_MessageHeader)); GNUNET_assert (0 == memcmp (got, &msg, sizeof (struct GNUNET_MessageHeader))); GNUNET_CLIENT_disconnect (client); client = NULL; GNUNET_SERVER_destroy (server); server = NULL; *ok = 0; } static size_t make_msg (void *cls, size_t size, void *buf) { struct GNUNET_MessageHeader *msg = buf; GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); msg->type = htons (MY_TYPE); msg->size = htons (sizeof (struct GNUNET_MessageHeader)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating message for transmission\n"); return sizeof (struct GNUNET_MessageHeader); } static void task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct sockaddr_in sa; struct sockaddr *sap[2]; socklen_t slens[2]; /* test that ill-configured client fails instantly */ GNUNET_assert (NULL == GNUNET_CLIENT_connect ("invalid-service", cfg)); /* test IPC between client and server */ sap[0] = (struct sockaddr *) &sa; slens[0] = sizeof (sa); sap[1] = NULL; slens[1] = 0; memset (&sa, 0, sizeof (sa)); #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = sizeof (sa); #endif sa.sin_family = AF_INET; sa.sin_port = htons (PORT); server = GNUNET_SERVER_create (NULL, NULL, sap, slens, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 10000), GNUNET_NO); GNUNET_assert (server != NULL); handlers[0].callback_cls = cls; handlers[1].callback_cls = cls; GNUNET_SERVER_add_handlers (server, handlers); client = GNUNET_CLIENT_connect (MYNAME, cfg); GNUNET_assert (client != NULL); GNUNET_assert (NULL != GNUNET_CLIENT_notify_transmit_ready (client, sizeof (struct GNUNET_MessageHeader), GNUNET_TIME_UNIT_SECONDS, GNUNET_NO, &make_msg, NULL)); GNUNET_CLIENT_receive (client, &recv_bounce, cls, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 10000)); } /** * Main method, starts scheduler with task1, * checks that "ok" is correct at the end. */ static int check () { int ok; cfg = GNUNET_CONFIGURATION_create (); GNUNET_CONFIGURATION_set_value_number (cfg, MYNAME, "PORT", PORT); GNUNET_CONFIGURATION_set_value_string (cfg, MYNAME, "HOSTNAME", "localhost"); GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", "localhost"); ok = 1; GNUNET_SCHEDULER_run (&task, &ok); GNUNET_CONFIGURATION_destroy (cfg); return ok; } int main (int argc, char *argv[]) { int ret = 0; GNUNET_log_setup ("test_client", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret += check (); return ret; } /* end of test_client.c */ gnunet-0.9.3/src/util/disk.h0000644000175000017500000000256211760502551012622 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/disk.h * @brief Internal DISK related helper functions * @author Nils Durner */ #ifndef GNUNET_DISK_H_ #define GNUNET_DISK_H_ #include "gnunet_disk_lib.h" /** * Retrieve OS file handle * * @internal * @param fh GNUnet file descriptor * @param dst destination buffer * @param dst_len length of dst * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh, void *dst, size_t dst_len); #endif /* GNUNET_DISK_H_ */ gnunet-0.9.3/src/util/test_crypto_ksk.c0000644000175000017500000001764411760502551015121 00000000000000/* This file is part of GNUnet. Copyright (C) 2004, 2005, 2006 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_crypto_ksk.c * @brief testcase for util/crypto_ksk.c * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_crypto_lib.h" #include "gnunet_signatures.h" #include "gnunet_time_lib.h" #define TESTSTRING "Hello World\0" #define MAX_TESTVAL 20 #define UNIQUE_ITER 6 #define ITER 25 static int testCorrectKey () { const char *want = "010601000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b73c215f7a5e6b09bec55713c901786c09324a150980e014bdb0d04426934929c3b4971a9711af5455536cd6eeb8bfa004ee904972a737455f53c752987d8c82b755bc02882b44950c4acdc1672ba74c3b94d81a4c1ea3d74e7700ae5594c3a4f3c559e4bff2df6844fac302e4b66175e14dc8bad3ce44281d2fec1a1abef06301010000"; GNUNET_HashCode in; struct GNUNET_CRYPTO_RsaPrivateKey *hostkey; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; int i; char out[3]; FPRINTF (stderr, "%s", "Testing KBlock key correctness"); GNUNET_CRYPTO_hash ("X", strlen ("X"), &in); hostkey = GNUNET_CRYPTO_rsa_key_create_from_hash (&in); if (hostkey == NULL) { GNUNET_break (0); return GNUNET_SYSERR; } GNUNET_CRYPTO_rsa_key_get_public (hostkey, &pkey); GNUNET_CRYPTO_rsa_key_free (hostkey); #if 0 for (i = 0; i < sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded); i++) printf ("%02x", ((unsigned char *) &pkey)[i]); printf ("\n"); #endif for (i = 0; i < sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded); i++) { snprintf (out, sizeof (out), "%02x", ((unsigned char *) &pkey)[i]); if (0 != strncmp (out, &want[i * 2], 2)) { FPRINTF (stderr, " Failed! Wanted %.2s but got %2s at %d\n", &want[i * 2], out, i); return GNUNET_SYSERR; } } FPRINTF (stderr, "%s", " OK\n"); return GNUNET_OK; } static int testMultiKey (const char *word) { GNUNET_HashCode in; struct GNUNET_CRYPTO_RsaPrivateKey *hostkey; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey1; int i; FPRINTF (stderr, "Testing KBlock key uniqueness (%s) ", word); GNUNET_CRYPTO_hash (word, strlen (word), &in); hostkey = GNUNET_CRYPTO_rsa_key_create_from_hash (&in); if (hostkey == NULL) { GNUNET_break (0); return GNUNET_SYSERR; } GNUNET_CRYPTO_rsa_key_get_public (hostkey, &pkey); /* * for (i=0;i<|cd*ef:/g\""); GNUNET_DISK_filename_canonicalize (fn); if (0 != strcmp (fn, "ab____cd_ef__g_")) { GNUNET_free (fn); return 1; } GNUNET_free (fn); return 0; } static int testChangeOwner () { GNUNET_log_skip (1, GNUNET_NO); if (GNUNET_OK == GNUNET_DISK_file_change_owner ("/dev/null", "unknownuser")) return 1; return 0; } static int testDirMani () { if (GNUNET_OK != GNUNET_DISK_directory_create_for_file ("test/ing")) return 1; if (GNUNET_NO != GNUNET_DISK_file_test ("test")) return 1; if (GNUNET_NO != GNUNET_DISK_file_test ("test/ing")) return 1; if (GNUNET_OK != GNUNET_DISK_directory_remove ("test")) return 1; if (GNUNET_OK != GNUNET_DISK_directory_create ("test")) return 1; if (GNUNET_YES != GNUNET_DISK_directory_test ("test")) return 1; if (GNUNET_OK != GNUNET_DISK_directory_remove ("test")) return 1; return 0; } int main (int argc, char *argv[]) { unsigned int failureCount = 0; GNUNET_log_setup ("test-disk", "WARNING", NULL); failureCount += testReadWrite (); failureCount += testOpenClose (); failureCount += testDirScan (); failureCount += testDirIter (); failureCount += testGetHome (); failureCount += testCanonicalize (); failureCount += testChangeOwner (); failureCount += testDirMani (); if (failureCount != 0) { FPRINTF (stderr, "\n%u TESTS FAILED!\n", failureCount); return -1; } return 0; } /* end of main */ gnunet-0.9.3/src/util/container_meta_data.c0000644000175000017500000007302211760502551015643 00000000000000/* This file is part of GNUnet. (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/container_meta_data.c * @brief Storing of meta data * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_container_lib.h" #include "gnunet_strings_lib.h" #include "gnunet_time_lib.h" #include #include #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) /** * Meta data item. */ struct MetaItem { /** * This is a linked list. */ struct MetaItem *next; /** * Name of the extracting plugin. */ char *plugin_name; /** * Mime-type of data. */ char *mime_type; /** * The actual meta data. */ char *data; /** * Number of bytes in 'data'. */ size_t data_size; /** * Type of the meta data. */ enum EXTRACTOR_MetaType type; /** * Format of the meta data. */ enum EXTRACTOR_MetaFormat format; }; /** * Meta data to associate with a file, directory or namespace. */ struct GNUNET_CONTAINER_MetaData { /** * Linked list of the meta data items. */ struct MetaItem *items; /** * Complete serialized and compressed buffer of the items. * NULL if we have not computed that buffer yet. */ char *sbuf; /** * Number of bytes in 'sbuf'. 0 if the buffer is stale. */ size_t sbuf_size; /** * Number of items in the linked list. */ unsigned int item_count; }; /** * Create a fresh struct CONTAINER_MetaData token. * * @return empty meta-data container */ struct GNUNET_CONTAINER_MetaData * GNUNET_CONTAINER_meta_data_create () { return GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_MetaData)); } /** * Free meta data item. * * @param item item to free */ static void meta_item_free (struct MetaItem *item) { GNUNET_free_non_null (item->plugin_name); GNUNET_free_non_null (item->mime_type); GNUNET_free_non_null (item->data); GNUNET_free (item); } /** * The meta data has changed, invalidate its serialization * buffer. * * @param md meta data that changed */ static void invalidate_sbuf (struct GNUNET_CONTAINER_MetaData *md) { if (md->sbuf == NULL) return; GNUNET_free (md->sbuf); md->sbuf = NULL; md->sbuf_size = 0; } /** * Free meta data. * * @param md what to free */ void GNUNET_CONTAINER_meta_data_destroy (struct GNUNET_CONTAINER_MetaData *md) { struct MetaItem *item; if (md == NULL) return; while (NULL != (item = md->items)) { md->items = item->next; meta_item_free (item); } GNUNET_free_non_null (md->sbuf); GNUNET_free (md); } /** * Remove all items in the container. * * @param md metadata to manipulate */ void GNUNET_CONTAINER_meta_data_clear (struct GNUNET_CONTAINER_MetaData *md) { struct MetaItem *item; if (md == NULL) return; while (NULL != (item = md->items)) { md->items = item->next; meta_item_free (item); } GNUNET_free_non_null (md->sbuf); memset (md, 0, sizeof (struct GNUNET_CONTAINER_MetaData)); } /** * Test if two MDs are equal. We consider them equal if * the meta types, formats and content match (we do not * include the mime types and plugins names in this * consideration). * * @param md1 first value to check * @param md2 other value to check * @return GNUNET_YES if they are equal */ int GNUNET_CONTAINER_meta_data_test_equal (const struct GNUNET_CONTAINER_MetaData *md1, const struct GNUNET_CONTAINER_MetaData *md2) { struct MetaItem *i; struct MetaItem *j; int found; if (md1 == md2) return GNUNET_YES; if (md1->item_count != md2->item_count) return GNUNET_NO; i = md1->items; while (NULL != i) { found = GNUNET_NO; j = md2->items; while (NULL != j) { if ((i->type == j->type) && (i->format == j->format) && (i->data_size == j->data_size) && (0 == memcmp (i->data, j->data, i->data_size))) { found = GNUNET_YES; break; } j = j->next; } if (found == GNUNET_NO) return GNUNET_NO; i = i->next; } return GNUNET_YES; } /** * Extend metadata. Note that the list of meta data items is * sorted by size (largest first). * * @param md metadata to extend * @param plugin_name name of the plugin that produced this value; * special values can be used (i.e. '<zlib>' for zlib being * used in the main libextractor library and yielding * meta data). * @param type libextractor-type describing the meta data * @param format basic format information about data * @param data_mime_type mime-type of data (not of the original file); * can be NULL (if mime-type is not known) * @param data actual meta-data found * @param data_len number of bytes in data * @return GNUNET_OK on success, GNUNET_SYSERR if this entry already exists * data_mime_type and plugin_name are not considered for "exists" checks */ int GNUNET_CONTAINER_meta_data_insert (struct GNUNET_CONTAINER_MetaData *md, const char *plugin_name, enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat format, const char *data_mime_type, const char *data, size_t data_len) { struct MetaItem *prev; struct MetaItem *pos; struct MetaItem *i; char *p; prev = NULL; pos = md->items; while (NULL != pos) { if (pos->data_size < data_len) break; if ((pos->type == type) && (pos->data_size == data_len) && (0 == memcmp (pos->data, data, data_len))) { if ((pos->mime_type == NULL) && (data_mime_type != NULL)) { pos->mime_type = GNUNET_strdup (data_mime_type); invalidate_sbuf (md); } if ((pos->format == EXTRACTOR_METAFORMAT_C_STRING) && (format == EXTRACTOR_METAFORMAT_UTF8)) { pos->format = EXTRACTOR_METAFORMAT_UTF8; invalidate_sbuf (md); } return GNUNET_SYSERR; } prev = pos; pos = pos->next; } md->item_count++; i = GNUNET_malloc (sizeof (struct MetaItem)); i->type = type; i->format = format; i->data_size = data_len; i->next = pos; if (prev == NULL) md->items = i; else prev->next = i; i->mime_type = (data_mime_type == NULL) ? NULL : GNUNET_strdup (data_mime_type); i->plugin_name = (plugin_name == NULL) ? NULL : GNUNET_strdup (plugin_name); i->data = GNUNET_malloc (data_len); memcpy (i->data, data, data_len); /* change OS native dir separators to unix '/' and others to '_' */ if ( (type == EXTRACTOR_METATYPE_FILENAME) || (type == EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME) ) { p = i->data; while ((*p != '\0') && (p < i->data + data_len)) { if (*p == DIR_SEPARATOR) *p = '/'; else if (*p == '\\') *p = '_'; p++; } } invalidate_sbuf (md); return GNUNET_OK; } /** * Merge given meta data. * * @param cls the 'struct GNUNET_CONTAINER_MetaData' to merge into * @param plugin_name name of the plugin that produced this value; * special values can be used (i.e. '<zlib>' for zlib being * used in the main libextractor library and yielding * meta data). * @param type libextractor-type describing the meta data * @param format basic format information about data * @param data_mime_type mime-type of data (not of the original file); * can be NULL (if mime-type is not known) * @param data actual meta-data found * @param data_len number of bytes in data * @return 0 (to continue) */ static int merge_helper (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat format, const char *data_mime_type, const char *data, size_t data_len) { struct GNUNET_CONTAINER_MetaData *md = cls; (void) GNUNET_CONTAINER_meta_data_insert (md, plugin_name, type, format, data_mime_type, data, data_len); return 0; } /** * Extend metadata. Merges the meta data from the second argument * into the first, discarding duplicate key-value pairs. * * @param md metadata to extend * @param in metadata to merge */ void GNUNET_CONTAINER_meta_data_merge (struct GNUNET_CONTAINER_MetaData *md, const struct GNUNET_CONTAINER_MetaData *in) { GNUNET_CONTAINER_meta_data_iterate (in, &merge_helper, md); } /** * Remove an item. * * @param md metadata to manipulate * @param type type of the item to remove * @param data specific value to remove, NULL to remove all * entries of the given type * @param data_len number of bytes in data * @return GNUNET_OK on success, GNUNET_SYSERR if the item does not exist in md */ int GNUNET_CONTAINER_meta_data_delete (struct GNUNET_CONTAINER_MetaData *md, enum EXTRACTOR_MetaType type, const char *data, size_t data_len) { struct MetaItem *pos; struct MetaItem *prev; prev = NULL; pos = md->items; while (NULL != pos) { if ((pos->type == type) && ((data == NULL) || ((pos->data_size == data_len) && (0 == memcmp (pos->data, data, data_len))))) { if (prev == NULL) md->items = pos->next; else prev->next = pos->next; meta_item_free (pos); md->item_count--; invalidate_sbuf (md); return GNUNET_OK; } prev = pos; pos = pos->next; } return GNUNET_SYSERR; } /** * Add the current time as the publication date * to the meta-data. * * @param md metadata to modify */ void GNUNET_CONTAINER_meta_data_add_publication_date (struct GNUNET_CONTAINER_MetaData *md) { char *dat; struct GNUNET_TIME_Absolute t; t = GNUNET_TIME_absolute_get (); GNUNET_CONTAINER_meta_data_delete (md, EXTRACTOR_METATYPE_PUBLICATION_DATE, NULL, 0); dat = GNUNET_STRINGS_absolute_time_to_string (t); GNUNET_CONTAINER_meta_data_insert (md, "", EXTRACTOR_METATYPE_PUBLICATION_DATE, EXTRACTOR_METAFORMAT_UTF8, "text/plain", dat, strlen (dat) + 1); GNUNET_free (dat); } /** * Iterate over MD entries. * * @param md metadata to inspect * @param iter function to call on each entry * @param iter_cls closure for iterator * @return number of entries */ int GNUNET_CONTAINER_meta_data_iterate (const struct GNUNET_CONTAINER_MetaData *md, EXTRACTOR_MetaDataProcessor iter, void *iter_cls) { struct MetaItem *pos; if (md == NULL) return 0; if (iter == NULL) return md->item_count; pos = md->items; while (NULL != pos) { if (0 != iter (iter_cls, pos->plugin_name, pos->type, pos->format, pos->mime_type, pos->data, pos->data_size)) return md->item_count; pos = pos->next; } return md->item_count; } /** * Get the first MD entry of the given type. Caller * is responsible for freeing the return value. * Also, only meta data items that are strings (0-terminated) * are returned by this function. * * @param md metadata to inspect * @param type type to look for * @return NULL if no entry was found */ char * GNUNET_CONTAINER_meta_data_get_by_type (const struct GNUNET_CONTAINER_MetaData *md, enum EXTRACTOR_MetaType type) { struct MetaItem *pos; if (md == NULL) return NULL; pos = md->items; while (NULL != pos) { if ((type == pos->type) && ((pos->format == EXTRACTOR_METAFORMAT_UTF8) || (pos->format == EXTRACTOR_METAFORMAT_C_STRING))) return GNUNET_strdup (pos->data); pos = pos->next; } return NULL; } /** * Get the first matching MD entry of the given types. Caller is * responsible for freeing the return value. Also, only meta data * items that are strings (0-terminated) are returned by this * function. * * @param md metadata to inspect * @param ... -1-terminated list of types * @return NULL if we do not have any such entry, * otherwise client is responsible for freeing the value! */ char * GNUNET_CONTAINER_meta_data_get_first_by_types (const struct GNUNET_CONTAINER_MetaData *md, ...) { char *ret; va_list args; enum EXTRACTOR_MetaType type; if (md == NULL) return NULL; ret = NULL; va_start (args, md); while (1) { type = va_arg (args, enum EXTRACTOR_MetaType); if (type == -1) break; ret = GNUNET_CONTAINER_meta_data_get_by_type (md, type); if (ret != NULL) break; } va_end (args); return ret; } /** * Get a thumbnail from the meta-data (if present). * * @param md metadata to get the thumbnail from * @param thumb will be set to the thumbnail data. Must be * freed by the caller! * @return number of bytes in thumbnail, 0 if not available */ size_t GNUNET_CONTAINER_meta_data_get_thumbnail (const struct GNUNET_CONTAINER_MetaData * md, unsigned char **thumb) { struct MetaItem *pos; struct MetaItem *match; if (md == NULL) return 0; match = NULL; pos = md->items; while (NULL != pos) { if ((NULL != pos->mime_type) && (0 == strncasecmp ("image/", pos->mime_type, strlen ("image/"))) && (pos->format == EXTRACTOR_METAFORMAT_BINARY)) { if (match == NULL) match = pos; else if ((match->type != EXTRACTOR_METATYPE_THUMBNAIL) && (pos->type == EXTRACTOR_METATYPE_THUMBNAIL)) match = pos; } pos = pos->next; } if ((match == NULL) || (match->data_size == 0)) return 0; *thumb = GNUNET_malloc (match->data_size); memcpy (*thumb, match->data, match->data_size); return match->data_size; } /** * Duplicate struct GNUNET_CONTAINER_MetaData. * * @param md what to duplicate * @return duplicate meta-data container */ struct GNUNET_CONTAINER_MetaData * GNUNET_CONTAINER_meta_data_duplicate (const struct GNUNET_CONTAINER_MetaData *md) { struct GNUNET_CONTAINER_MetaData *ret; struct MetaItem *pos; if (md == NULL) return NULL; ret = GNUNET_CONTAINER_meta_data_create (); pos = md->items; while (NULL != pos) { GNUNET_CONTAINER_meta_data_insert (ret, pos->plugin_name, pos->type, pos->format, pos->mime_type, pos->data, pos->data_size); pos = pos->next; } return ret; } /** * Try to compress the given block of data. * * @param data block to compress; if compression * resulted in a smaller block, the first * bytes of data are updated to the compressed * data * @param oldSize number of bytes in data * @param result set to the compressed data * @param newSize set to size of result * @return GNUNET_YES if compression reduce the size, * GNUNET_NO if compression did not help */ static int try_compression (const char *data, size_t oldSize, char **result, size_t * newSize) { char *tmp; uLongf dlen; #ifdef compressBound dlen = compressBound (oldSize); #else dlen = oldSize + (oldSize / 100) + 20; /* documentation says 100.1% oldSize + 12 bytes, but we * should be able to overshoot by more to be safe */ #endif tmp = GNUNET_malloc (dlen); if (Z_OK == compress2 ((Bytef *) tmp, &dlen, (const Bytef *) data, oldSize, 9)) { if (dlen < oldSize) { *result = tmp; *newSize = dlen; return GNUNET_YES; } } GNUNET_free (tmp); return GNUNET_NO; } /** * Flag in 'version' that indicates compressed meta-data. */ #define HEADER_COMPRESSED 0x80000000 /** * Bits in 'version' that give the version number. */ #define HEADER_VERSION_MASK 0x7FFFFFFF /** * Header for serialized meta data. */ struct MetaDataHeader { /** * The version of the MD serialization. The highest bit is used to * indicate compression. * * Version 0 is traditional (pre-0.9) meta data (unsupported) * Version is 1 for a NULL pointer * Version 2 is for 0.9.x (and possibly higher) * Other version numbers are not yet defined. */ uint32_t version; /** * How many MD entries are there? */ uint32_t entries; /** * Size of the decompressed meta data. */ uint32_t size; /** * This is followed by 'entries' values of type 'struct MetaDataEntry' * and then by 'entry' plugin names, mime-types and data blocks * as specified in those meta data entries. */ }; /** * Entry of serialized meta data. */ struct MetaDataEntry { /** * Meta data type. Corresponds to an 'enum EXTRACTOR_MetaType' */ uint32_t type; /** * Meta data format. Corresponds to an 'enum EXTRACTOR_MetaFormat' */ uint32_t format; /** * Number of bytes of meta data. */ uint32_t data_size; /** * Number of bytes in the plugin name including 0-terminator. 0 for NULL. */ uint32_t plugin_name_len; /** * Number of bytes in the mime type including 0-terminator. 0 for NULL. */ uint32_t mime_type_len; }; /** * Serialize meta-data to target. * * @param md metadata to serialize * @param target where to write the serialized metadata; * *target can be NULL, in which case memory is allocated * @param max maximum number of bytes available in target * @param opt is it ok to just write SOME of the * meta-data to match the size constraint, * possibly discarding some data? * @return number of bytes written on success, * GNUNET_SYSERR on error (typically: not enough * space) */ ssize_t GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData *md, char **target, size_t max, enum GNUNET_CONTAINER_MetaDataSerializationOptions opt) { struct GNUNET_CONTAINER_MetaData *vmd; struct MetaItem *pos; struct MetaDataHeader ihdr; struct MetaDataHeader *hdr; struct MetaDataEntry *ent; char *dst; unsigned int i; uint64_t msize; size_t off; char *mdata; char *cdata; size_t mlen; size_t plen; size_t size; size_t left; size_t clen; size_t rlen; int comp; if (max < sizeof (struct MetaDataHeader)) return GNUNET_SYSERR; /* far too small */ if (md == NULL) return 0; if (md->sbuf != NULL) { /* try to use serialization cache */ if (md->sbuf_size <= max) { if (NULL == *target) *target = GNUNET_malloc (md->sbuf_size); memcpy (*target, md->sbuf, md->sbuf_size); return md->sbuf_size; } if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_PART)) return GNUNET_SYSERR; /* can say that this will fail */ /* need to compute a partial serialization, sbuf useless ... */ } dst = NULL; msize = 0; pos = md->items; while (NULL != pos) { msize += sizeof (struct MetaDataEntry); msize += pos->data_size; if (pos->plugin_name != NULL) msize += strlen (pos->plugin_name) + 1; if (pos->mime_type != NULL) msize += strlen (pos->mime_type) + 1; pos = pos->next; } size = (size_t) msize; if (size != msize) { GNUNET_break (0); /* integer overflow */ return GNUNET_SYSERR; } if (size >= GNUNET_MAX_MALLOC_CHECKED) { /* too large to be processed */ return GNUNET_SYSERR; } ent = GNUNET_malloc (size); mdata = (char *) &ent[md->item_count]; off = size - (md->item_count * sizeof (struct MetaDataEntry)); i = 0; pos = md->items; while (NULL != pos) { ent[i].type = htonl ((uint32_t) pos->type); ent[i].format = htonl ((uint32_t) pos->format); ent[i].data_size = htonl ((uint32_t) pos->data_size); if (pos->plugin_name == NULL) plen = 0; else plen = strlen (pos->plugin_name) + 1; ent[i].plugin_name_len = htonl ((uint32_t) plen); if (pos->mime_type == NULL) mlen = 0; else mlen = strlen (pos->mime_type) + 1; ent[i].mime_type_len = htonl ((uint32_t) mlen); off -= pos->data_size; memcpy (&mdata[off], pos->data, pos->data_size); off -= plen; if (pos->plugin_name != NULL) memcpy (&mdata[off], pos->plugin_name, plen); off -= mlen; if (pos->mime_type != NULL) memcpy (&mdata[off], pos->mime_type, mlen); i++; pos = pos->next; } GNUNET_assert (off == 0); clen = 0; cdata = NULL; left = size; i = 0; pos = md->items; while (pos != NULL) { comp = GNUNET_NO; if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_NO_COMPRESS)) comp = try_compression ((const char *) &ent[i], left, &cdata, &clen); if ((md->sbuf == NULL) && (i == 0)) { /* fill 'sbuf'; this "modifies" md, but since this is only * an internal cache we will cast away the 'const' instead * of making the API look strange. */ vmd = (struct GNUNET_CONTAINER_MetaData *) md; hdr = GNUNET_malloc (left + sizeof (struct MetaDataHeader)); hdr->size = htonl (left); hdr->entries = htonl (md->item_count); if (GNUNET_YES == comp) { GNUNET_assert (clen < left); hdr->version = htonl (2 | HEADER_COMPRESSED); memcpy (&hdr[1], cdata, clen); vmd->sbuf_size = clen + sizeof (struct MetaDataHeader); } else { hdr->version = htonl (2); memcpy (&hdr[1], &ent[0], left); vmd->sbuf_size = left + sizeof (struct MetaDataHeader); } vmd->sbuf = (char *) hdr; } if (((left + sizeof (struct MetaDataHeader)) <= max) || ((comp == GNUNET_YES) && (clen <= max))) { /* success, this now fits! */ if (GNUNET_YES == comp) { if (dst == NULL) dst = GNUNET_malloc (clen + sizeof (struct MetaDataHeader)); hdr = (struct MetaDataHeader *) dst; hdr->version = htonl (2 | HEADER_COMPRESSED); hdr->size = htonl (left); hdr->entries = htonl (md->item_count - i); memcpy (&dst[sizeof (struct MetaDataHeader)], cdata, clen); GNUNET_free (cdata); GNUNET_free (ent); rlen = clen + sizeof (struct MetaDataHeader); } else { if (dst == NULL) dst = GNUNET_malloc (left + sizeof (struct MetaDataHeader)); hdr = (struct MetaDataHeader *) dst; hdr->version = htonl (2); hdr->entries = htonl (md->item_count - i); hdr->size = htonl (left); memcpy (&dst[sizeof (struct MetaDataHeader)], &ent[i], left); GNUNET_free (ent); rlen = left + sizeof (struct MetaDataHeader); } if (NULL != *target) { memcpy (*target, dst, clen + sizeof (struct MetaDataHeader)); GNUNET_free (dst); } else { *target = dst; } return rlen; } if (0 == (opt & GNUNET_CONTAINER_META_DATA_SERIALIZE_PART)) { /* does not fit! */ GNUNET_free (ent); return GNUNET_SYSERR; } /* next iteration: ignore the corresponding meta data at the * end and try again without it */ left -= sizeof (struct MetaDataEntry); left -= pos->data_size; if (pos->plugin_name != NULL) left -= strlen (pos->plugin_name) + 1; if (pos->mime_type != NULL) left -= strlen (pos->mime_type) + 1; pos = pos->next; i++; } GNUNET_free (ent); /* nothing fit, only write header! */ ihdr.version = htonl (2); ihdr.entries = htonl (0); ihdr.size = htonl (0); if (*target == NULL) *target = GNUNET_malloc (sizeof (struct MetaDataHeader)); memcpy (*target, &ihdr, sizeof (struct MetaDataHeader)); return sizeof (struct MetaDataHeader); } /** * Get the size of the full meta-data in serialized form. * * @param md metadata to inspect * @return number of bytes needed for serialization, -1 on error */ ssize_t GNUNET_CONTAINER_meta_data_get_serialized_size (const struct GNUNET_CONTAINER_MetaData *md) { ssize_t ret; char *ptr; if (md->sbuf != NULL) return md->sbuf_size; ptr = NULL; ret = GNUNET_CONTAINER_meta_data_serialize (md, &ptr, GNUNET_MAX_MALLOC_CHECKED, GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL); if (ret != -1) GNUNET_free (ptr); return ret; } /** * Decompress input, return the decompressed data * as output, set outputSize to the number of bytes * that were found. * * @param input compressed data * @param inputSize number of bytes in input * @param outputSize expected size of the output * @return NULL on error */ static char * decompress (const char *input, size_t inputSize, size_t outputSize) { char *output; uLongf olen; olen = outputSize; output = GNUNET_malloc (olen); if (Z_OK == uncompress ((Bytef *) output, &olen, (const Bytef *) input, inputSize)) { return output; } else { GNUNET_free (output); return NULL; } } /** * Deserialize meta-data. Initializes md. * * @param input buffer with the serialized metadata * @param size number of bytes available in input * @return MD on success, NULL on error (i.e. * bad format) */ struct GNUNET_CONTAINER_MetaData * GNUNET_CONTAINER_meta_data_deserialize (const char *input, size_t size) { struct GNUNET_CONTAINER_MetaData *md; struct MetaDataHeader hdr; struct MetaDataEntry ent; uint32_t ic; uint32_t i; char *data; const char *cdata; uint32_t version; uint32_t dataSize; int compressed; size_t left; uint32_t mlen; uint32_t plen; uint32_t dlen; const char *mdata; const char *meta_data; const char *plugin_name; const char *mime_type; enum EXTRACTOR_MetaFormat format; if (size < sizeof (struct MetaDataHeader)) return NULL; memcpy (&hdr, input, sizeof (struct MetaDataHeader)); version = ntohl (hdr.version) & HEADER_VERSION_MASK; compressed = (ntohl (hdr.version) & HEADER_COMPRESSED) != 0; if (version == 1) return NULL; /* null pointer */ if (version != 2) { GNUNET_break_op (0); /* unsupported version */ return NULL; } ic = ntohl (hdr.entries); dataSize = ntohl (hdr.size); if ((sizeof (struct MetaDataEntry) * ic) > dataSize) { GNUNET_break_op (0); return NULL; } if (compressed) { if (dataSize >= GNUNET_MAX_MALLOC_CHECKED) { /* make sure we don't blow our memory limit because of a mal-formed * message... */ GNUNET_break_op (0); return NULL; } data = decompress ((const char *) &input[sizeof (struct MetaDataHeader)], size - sizeof (struct MetaDataHeader), dataSize); if (data == NULL) { GNUNET_break_op (0); return NULL; } cdata = data; } else { data = NULL; cdata = (const char *) &input[sizeof (struct MetaDataHeader)]; if (dataSize != size - sizeof (struct MetaDataHeader)) { GNUNET_break_op (0); return NULL; } } md = GNUNET_CONTAINER_meta_data_create (); left = dataSize - ic * sizeof (struct MetaDataEntry); mdata = &cdata[ic * sizeof (struct MetaDataEntry)]; for (i = 0; i < ic; i++) { memcpy (&ent, &cdata[i * sizeof (struct MetaDataEntry)], sizeof (struct MetaDataEntry)); format = (enum EXTRACTOR_MetaFormat) ntohl (ent.format); if ((format != EXTRACTOR_METAFORMAT_UTF8) && (format != EXTRACTOR_METAFORMAT_C_STRING) && (format != EXTRACTOR_METAFORMAT_BINARY)) { GNUNET_break_op (0); break; } dlen = ntohl (ent.data_size); plen = ntohl (ent.plugin_name_len); mlen = ntohl (ent.mime_type_len); if (dlen > left) { GNUNET_break_op (0); break; } left -= dlen; meta_data = &mdata[left]; if ((format == EXTRACTOR_METAFORMAT_UTF8) || (format == EXTRACTOR_METAFORMAT_C_STRING)) { if ((dlen == 0) || (mdata[left + dlen - 1] != '\0')) { GNUNET_break_op (0); break; } } if (plen > left) { GNUNET_break_op (0); break; } left -= plen; if ((plen > 0) && (mdata[left + plen - 1] != '\0')) { GNUNET_break_op (0); break; } if (plen == 0) plugin_name = NULL; else plugin_name = &mdata[left]; if (mlen > left) { GNUNET_break_op (0); break; } left -= mlen; if ((mlen > 0) && (mdata[left + mlen - 1] != '\0')) { GNUNET_break_op (0); break; } if (mlen == 0) mime_type = NULL; else mime_type = &mdata[left]; GNUNET_CONTAINER_meta_data_insert (md, plugin_name, (enum EXTRACTOR_MetaType) ntohl (ent.type), format, mime_type, meta_data, dlen); } GNUNET_free_non_null (data); return md; } /* end of container_meta_data.c */ gnunet-0.9.3/src/util/test_container_multihashmap.c0000644000175000017500000001032011760502551017447 00000000000000/* This file is part of GNUnet. (C) 2008 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file util/test_container_multihashmap.c * @brief Test for container_multihashmap.c * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_container_lib.h" #define ABORT() { fprintf(stderr, "Error at %s:%d\n", __FILE__, __LINE__); if (m != NULL) GNUNET_CONTAINER_multihashmap_destroy(m); return 1; } #define CHECK(c) { if (! (c)) ABORT(); } static int testMap (int i) { struct GNUNET_CONTAINER_MultiHashMap *m; GNUNET_HashCode k1; GNUNET_HashCode k2; const char *ret; int j; CHECK (NULL != (m = GNUNET_CONTAINER_multihashmap_create (i))); memset (&k1, 0, sizeof (k1)); memset (&k2, 1, sizeof (k2)); CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (m, &k1)); CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (m, &k2)); CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_remove (m, &k1, NULL)); CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_remove (m, &k2, NULL)); CHECK (NULL == GNUNET_CONTAINER_multihashmap_get (m, &k1)); CHECK (NULL == GNUNET_CONTAINER_multihashmap_get (m, &k2)); CHECK (0 == GNUNET_CONTAINER_multihashmap_remove_all (m, &k1)); CHECK (0 == GNUNET_CONTAINER_multihashmap_size (m)); CHECK (0 == GNUNET_CONTAINER_multihashmap_iterate (m, NULL, NULL)); CHECK (0 == GNUNET_CONTAINER_multihashmap_get_multiple (m, &k1, NULL, NULL)); CHECK (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (m, &k1, "v1", GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE)); CHECK (1 == GNUNET_CONTAINER_multihashmap_size (m)); ret = GNUNET_CONTAINER_multihashmap_get (m, &k1); GNUNET_assert (ret != NULL); CHECK (0 == strcmp ("v1", ret)); CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_put (m, &k1, "v1", GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE)); CHECK (1 == GNUNET_CONTAINER_multihashmap_size (m)); CHECK (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (m, &k1, "v2", GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); CHECK (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (m, &k1, "v3", GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); CHECK (3 == GNUNET_CONTAINER_multihashmap_size (m)); CHECK (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (m, &k1, "v3")); CHECK (2 == GNUNET_CONTAINER_multihashmap_size (m)); CHECK (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (m, &k1)); CHECK (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (m, &k2)); CHECK (2 == GNUNET_CONTAINER_multihashmap_get_multiple (m, &k1, NULL, NULL)); CHECK (0 == GNUNET_CONTAINER_multihashmap_get_multiple (m, &k2, NULL, NULL)); CHECK (2 == GNUNET_CONTAINER_multihashmap_iterate (m, NULL, NULL)); CHECK (2 == GNUNET_CONTAINER_multihashmap_remove_all (m, &k1)); for (j = 0; j < 1024; j++) CHECK (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (m, &k1, "v2", GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); GNUNET_CONTAINER_multihashmap_destroy (m); return 0; } int main (int argc, char *argv[]) { int failureCount = 0; int i; GNUNET_log_setup ("test-container-multihashmap", "WARNING", NULL); for (i = 1; i < 255; i++) failureCount += testMap (i); if (failureCount != 0) return 1; return 0; } /* end of test_container_multihashmap.c */ gnunet-0.9.3/src/util/peer.c0000644000175000017500000001355211760502551012617 00000000000000/* This file is part of GNUnet (C) 2006, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * @file util/peer.c * @brief peer-ID table that assigns integer IDs to peer-IDs to save memory * @author Christian Grothoff */ #include "platform.h" #include "gnunet_peer_lib.h" #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) struct PeerEntry { /** * The identifier itself */ struct GNUNET_PeerIdentity id; /** * Short version of the identifier; if the RC==0, then index of next * free slot in table, otherwise equal to this slot in the table. */ GNUNET_PEER_Id pid; /** * Reference counter, 0 if this slot is not used. */ unsigned int rc; }; /** * Table with our interned peer IDs. */ static struct PeerEntry *table; /** * Hashmap of PeerIdentities to "struct PeerEntry" * (for fast lookup). NULL until the library * is actually being used. */ static struct GNUNET_CONTAINER_MultiHashMap *map; /** * Size of the "table". */ static unsigned int size; /** * Index of the beginning of the free list in the table; set to "size" * if no slots are free in the table. */ static unsigned int free_list_start; /** * Search for a peer identity. The reference counter is not changed. * * @param pid identity to find * @return the interned identity or 0. */ GNUNET_PEER_Id GNUNET_PEER_search (const struct GNUNET_PeerIdentity *pid) { struct PeerEntry *e; long off; if (pid == NULL) return 0; if (NULL == map) return 0; off = (long) GNUNET_CONTAINER_multihashmap_get (map, &pid->hashPubKey); e = (off == 0) ? NULL : &table[off]; if (e == NULL) return 0; GNUNET_assert (e->rc > 0); return e->pid; } /** * Intern an peer identity. If the identity is already known, its * reference counter will be increased by one. * * @param pid identity to intern * @return the interned identity. */ GNUNET_PEER_Id GNUNET_PEER_intern (const struct GNUNET_PeerIdentity *pid) { GNUNET_PEER_Id ret; struct PeerEntry *e; unsigned int i; long off; if (pid == NULL) return 0; if (NULL == map) map = GNUNET_CONTAINER_multihashmap_create (32); off = (long) GNUNET_CONTAINER_multihashmap_get (map, &pid->hashPubKey); e = (off == 0) ? NULL : &table[off]; if (e != NULL) { GNUNET_assert (e->rc > 0); e->rc++; return e->pid; } ret = free_list_start; if (ret == size) { GNUNET_array_grow (table, size, size + 16); for (i = ret; i < size; i++) table[i].pid = i + 1; } if (ret == 0) { table[0].pid = 0; table[0].rc = 1; ret = 1; } GNUNET_assert (ret < size); GNUNET_assert (table[ret].rc == 0); free_list_start = table[ret].pid; table[ret].id = *pid; table[ret].rc = 1; table[ret].pid = ret; GNUNET_break (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (map, &pid->hashPubKey, (void *) (long) ret, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); return ret; } /** * Decrement multiple RCs of peer identities by one. * * @param ids array of PIDs to decrement the RCs of * @param count size of the ids array */ void GNUNET_PEER_decrement_rcs (const GNUNET_PEER_Id *ids, unsigned int count) { int i; GNUNET_PEER_Id id; if (count == 0) return; for (i = count - 1; i >= 0; i--) { id = ids[i]; if (id == 0) continue; GNUNET_assert (id < size); GNUNET_assert (table[id].rc > 0); table[id].rc--; if (table[id].rc == 0) { GNUNET_break (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (map, &table[id]. id.hashPubKey, (void *) (long) id)); table[id].pid = free_list_start; free_list_start = id; } } } /** * Change the reference counter of an interned PID. * * @param id identity to change the RC of * @param delta how much to change the RC */ void GNUNET_PEER_change_rc (GNUNET_PEER_Id id, int delta) { if (id == 0) return; GNUNET_assert (id < size); GNUNET_assert (table[id].rc > 0); GNUNET_assert ((delta >= 0) || (table[id].rc >= -delta)); table[id].rc += delta; if (table[id].rc == 0) { GNUNET_break (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (map, &table[id]. id.hashPubKey, (void *) (long) id)); table[id].pid = free_list_start; free_list_start = id; } } /** * Convert an interned PID to a normal peer identity. * * @param id interned PID to convert * @param pid where to write the normal peer identity */ void GNUNET_PEER_resolve (GNUNET_PEER_Id id, struct GNUNET_PeerIdentity *pid) { if (id == 0) { memset (pid, 0, sizeof (struct GNUNET_PeerIdentity)); GNUNET_break (0); return; } GNUNET_assert (id < size); GNUNET_assert (table[id].rc > 0); *pid = table[id].id; } /* end of peer.c */ gnunet-0.9.3/src/testbed/0000755000175000017500000000000011763406750012256 500000000000000gnunet-0.9.3/src/testbed/testbed_api_topology.c0000644000175000017500000001035211760502551016553 00000000000000/* This file is part of GNUnet (C) 2008--2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testbed/testbed_api_topology.c * @brief topology-generation functions * @author Christian Grothoff */ #include "platform.h" #include "gnunet_testbed_service.h" /** * Configure overall network topology to have a particular shape. * * @param op_cls closure argument to give with the operation event * @param num_peers number of peers in 'peers' * @param peers array of 'num_peers' with the peers to configure * @param topo desired underlay topology to use * @param ap topology-specific options * @return handle to the operation, NULL if configuring the topology * is not allowed at this time */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_underlay_configure_topology_va (void *op_cls, unsigned int num_peers, struct GNUNET_TESTBED_Peer **peers, enum GNUNET_TESTBED_TopologyOption topo, va_list ap) { GNUNET_break (0); return NULL; } /** * Configure overall network topology to have a particular shape. * * @param op_cls closure argument to give with the operation event * @param num_peers number of peers in 'peers' * @param peers array of 'num_peers' with the peers to configure * @param topo desired underlay topology to use * @param ... topology-specific options * @return handle to the operation, NULL if configuring the topology * is not allowed at this time */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_underlay_configure_topology (void *op_cls, unsigned int num_peers, struct GNUNET_TESTBED_Peer **peers, enum GNUNET_TESTBED_TopologyOption topo, ...) { GNUNET_break (0); return NULL; } /** * All peers must have been started before calling this function. * This function then connects the given peers in the P2P overlay * using the given topology. * * @param op_cls closure argument to give with the operation event * @param num_peers number of peers in 'peers' * @param peers array of 'num_peers' with the peers to configure * @param topo desired underlay topology to use * @param va topology-specific options * @return handle to the operation, NULL if connecting these * peers is fundamentally not possible at this time (peers * not running or underlay disallows) */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_overlay_configure_topology_va (void *op_cls, unsigned int num_peers, struct GNUNET_TESTBED_Peer *peers, enum GNUNET_TESTBED_TopologyOption topo, va_list va) { GNUNET_break (0); return NULL; } /** * All peers must have been started before calling this function. * This function then connects the given peers in the P2P overlay * using the given topology. * * @param op_cls closure argument to give with the operation event * @param num_peers number of peers in 'peers' * @param peers array of 'num_peers' with the peers to configure * @param topo desired underlay topology to use * @param ... topology-specific options * @return handle to the operation, NULL if connecting these * peers is fundamentally not possible at this time (peers * not running or underlay disallows) */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_overlay_configure_topology (void *op_cls, unsigned int num_peers, struct GNUNET_TESTBED_Peer *peers, enum GNUNET_TESTBED_TopologyOption topo, ...) { GNUNET_break (0); return NULL; } /* end of testbed_api_topology.c */ gnunet-0.9.3/src/testbed/Makefile.am0000644000175000017500000000171111751245053014224 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIB = -lgcov endif pkgcfgdir= $(pkgdatadir)/config.d/ dist_pkgcfg_DATA = \ testbed.conf lib_LTLIBRARIES = \ libgnunettestbed.la libgnunettestbed_la_SOURCES = \ testbed_api.c testbed.h \ testbed_api_hosts.c testbed_api_hosts.h \ testbed_api_operations.c testbed_api_operations.h \ testbed_api_peers.c testbed_api_peers.h \ testbed_api_services.c \ testbed_api_testbed.c \ testbed_api_test.c \ testbed_api_topology.c libgnunettestbed_la_LIBADD = $(XLIB) \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ -lm \ $(top_builddir)/src/util/libgnunetutil.la libgnunettestbed_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:0:0 gnunet-0.9.3/src/testbed/testbed_api.c0000644000175000017500000001234711760502551014625 00000000000000/* This file is part of GNUnet (C) 2008--2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testbed/testbed_api.c * @brief API for accessing the GNUnet testing service. * This library is supposed to make it easier to write * testcases and script large-scale benchmarks. * @author Christian Grothoff */ #include "platform.h" #include "gnunet_testbed_service.h" #include "gnunet_core_service.h" #include "gnunet_constants.h" #include "gnunet_transport_service.h" #include "gnunet_hello_lib.h" /** * Start a controller process using the given configuration at the * given host. * * @param cfg configuration to use * @param host host to run the controller on, NULL for 'localhost' * @param event_mask bit mask with set of events to call 'cc' for; * or-ed values of "1LL" shifted by the * respective 'enum GNUNET_TESTBED_EventType' * (i.e. "(1LL << GNUNET_TESTBED_ET_CONNECT) | ...") * @param cc controller callback to invoke on events * @param cc_cls closure for cc * @return handle to the controller */ struct GNUNET_TESTBED_Controller * GNUNET_TESTBED_controller_start (const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTBED_Host *host, uint64_t event_mask, GNUNET_TESTBED_ControllerCallback cc, void *cc_cls) { GNUNET_break (0); return NULL; } /** * Configure shared services at a controller. Using this function, * you can specify that certain services (such as "resolver") * should not be run for each peer but instead be shared * across N peers on the specified host. This function * must be called before any peers are created at the host. * * @param controller controller to configure * @param service_name name of the service to share * @param num_peers number of peers that should share one instance * of the specified service (1 for no sharing is the default), * use 0 to disable the service */ void GNUNET_TESTBED_controller_configure_sharing (struct GNUNET_TESTBED_Controller *controller, const char *service_name, uint32_t num_peers) { GNUNET_break (0); } /** * Stop the given controller (also will terminate all peers and * controllers dependent on this controller). This function * blocks until the testbed has been fully terminated (!). * * @param controller handle to controller to stop */ void GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_Controller *controller) { GNUNET_break (0); } /** * Create a link from a 'master' controller to a slave controller. * Whenever the master controller is asked to start a peer at the * given 'delegated_host', it will delegate the request to the * specified slave controller. Note that the slave controller runs at * the 'slave_host', which may or may not be the same host as the * 'delegated_host' (for hierarchical delegations). The configuration * of the slave controller is given and to be used to either create * the slave controller or to connect to an existing slave controller * process. 'is_subordinate' specifies if the given slave controller * should be started and managed by the master controller, or if the * slave already has a master and this is just a secondary master that * is also allowed to use the existing slave. * * @param master handle to the master controller who creates the association * @param delegated_host requests to which host should be delegated * @param slave_host which host is used to run the slave controller * @param slave_cfg configuration to use for the slave controller * @param is_subordinate GNUNET_YES if the slave should be started (and stopped) * by the master controller; GNUNET_NO if we are just * allowed to use the slave via TCP/IP */ void GNUNET_TESTBED_controller_link (struct GNUNET_TESTBED_Controller *master, struct GNUNET_TESTBED_Host *delegated_host, struct GNUNET_TESTBED_Host *slave_host, const struct GNUNET_CONFIGURATION_Handle *slave_cfg, int is_subordinate) { GNUNET_break (0); } /** * Ask the testbed controller to write the current overlay topology to * a file. Naturally, the file will only contain a snapshot as the * topology may evolve all the time. * * @param controller overlay controller to inspect * @param filename name of the file the topology should * be written to. */ void GNUNET_TESTBED_overlay_write_topology_to_file (struct GNUNET_TESTBED_Controller *controller, const char *filename) { } /* end of testbed_api.c */ gnunet-0.9.3/src/testbed/testbed_api_hosts.c0000644000175000017500000001261711760502551016045 00000000000000/* This file is part of GNUnet (C) 2008--2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testbed/testbed_api_hosts.c * @brief API for manipulating 'hosts' controlled by the GNUnet testing service; * allows parsing hosts files, starting, stopping and communicating (via * SSH/stdin/stdout) with the remote (or local) processes * @author Christian Grothoff */ #include "platform.h" #include "gnunet_testbed_service.h" #include "gnunet_core_service.h" #include "gnunet_constants.h" #include "gnunet_transport_service.h" #include "gnunet_hello_lib.h" /** * Opaque handle to a host running experiments managed by the testing framework. * The master process must be able to SSH to this host without password (via * ssh-agent). */ struct GNUNET_TESTBED_Host { const char *hostname; const char *username; /** * Global ID we use to refer to a host on the network */ uint32_t unique_id; uint16_t port; }; /** * Lookup a host by ID. * * @param id global host ID assigned to the host; 0 is * reserved to always mean 'localhost' * @return handle to the host, NULL on error */ struct GNUNET_TESTBED_Host * GNUNET_TESTBED_host_lookup_by_id_ (uint32_t id) { GNUNET_break (0); return NULL; } /** * Create a host by ID; given this host handle, we could not * run peers at the host, but we can talk about the host * internally. * * @param id global host ID assigned to the host; 0 is * reserved to always mean 'localhost' * @return handle to the host, NULL on error */ struct GNUNET_TESTBED_Host * GNUNET_TESTBED_host_create_by_id_ (uint32_t id) { return NULL; } /** * Obtain a host's unique global ID. * * @param host handle to the host, NULL means 'localhost' * @return id global host ID assigned to the host (0 is * 'localhost', but then obviously not globally unique) */ uint32_t GNUNET_TESTBED_host_get_id_ (struct GNUNET_TESTBED_Host *host) { GNUNET_break (0); return 0; } /** * Create a host to run peers and controllers on. * * @param id global host ID assigned to the host; 0 is * reserved to always mean 'localhost' * @param hostname name of the host, use "NULL" for localhost * @param username username to use for the login; may be NULL * @param port port number to use for ssh; use 0 to let ssh decide * @return handle to the host, NULL on error */ struct GNUNET_TESTBED_Host * GNUNET_TESTBED_host_create_with_id_ (uint32_t id, const char *hostname, const char *username, uint16_t port) { GNUNET_break (0); return NULL; } /** * Create a host to run peers and controllers on. * * @param hostname name of the host, use "NULL" for localhost * @param username username to use for the login; may be NULL * @param port port number to use for ssh; use 0 to let ssh decide * @return handle to the host, NULL on error */ struct GNUNET_TESTBED_Host * GNUNET_TESTBED_host_create (const char *hostname, const char *username, uint16_t port) { static uint32_t uid_generator; return GNUNET_TESTBED_host_create_with_id_ (++uid_generator, hostname, username, port); } /** * Load a set of hosts from a configuration file. * * @param filename file with the host specification * @param hosts set to the hosts found in the file * @return number of hosts returned in 'hosts', 0 on error */ unsigned int GNUNET_TESTBED_hosts_load_from_file (const char *filename, struct GNUNET_TESTBED_Host **hosts) { GNUNET_break (0); return 0; } /** * Destroy a host handle. Must only be called once everything * running on that host has been stopped. * * @param host handle to destroy */ void GNUNET_TESTBED_host_destroy (struct GNUNET_TESTBED_Host *host) { GNUNET_break (0); } /** * Run a given helper process at the given host. Communication * with the helper will be via GNUnet messages on stdin/stdout. * Runs the process via 'ssh' at the specified host, or locally. * Essentially an SSH-wrapper around the 'gnunet_helper_lib.h' API. * * @param host host to use, use "NULL" for localhost * @param binary_argv binary name and command-line arguments to give to the binary * @param cb function to call for messages received from the binary * @param cb_cls closure for cb * @return handle to terminate the command, NULL on error */ struct GNUNET_HELPER_Handle * GNUNET_TESTBED_host_run_ (struct GNUNET_TESTBED_Host *host, char *const binary_argv[], GNUNET_SERVER_MessageTokenizerCallback cb, void *cb_cls) { /* FIXME: decide on the SSH command line, prepend it and run GNUNET_HELPER_start with the modified binary_name and binary_argv! */ GNUNET_break (0); return NULL; } /* end of testbed_api_hosts.c */ gnunet-0.9.3/src/testbed/testbed_api_peers.c0000644000175000017500000002117711760502551016024 00000000000000/* This file is part of GNUnet (C) 2008--2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testbed/testbed_api_peers.c * @brief management of the knowledge about peers in this library * (we know the peer ID, its host, pending operations, etc.) * @author Christian Grothoff */ #include "platform.h" #include "testbed_api_peers.h" /** * Details about a peer; kept in a separate struct to avoid bloating * memory consumption everywhere... */ struct PeerDetails { /** * Configuration of the peer; NULL if we are not sure what the peer's correct * configuration actually is; non-NULL if this peer is controlled by this * process. */ struct GNUNET_CONFIGURATION_Handle *cfg; /** * If this process has started this peer's ARM process, this is the handle * to the 'gnunet-service-arm' process of the peer. */ struct GNUNET_OS_Process *arm; // ... }; /** * A peer controlled by the testing framework. A peer runs * at a particular host. */ struct GNUNET_TESTBED_Peer { /** * Our controller context (not necessarily the controller * that is responsible for starting/running the peer!). */ struct GNUNET_TESTBED_Controller *controller; /** * Which host does this peer run on? */ struct GNUENT_TESTING_Host *host; /** * Globally unique ID of the peer. */ uint32_t unique_id; /** * Internals of the peer for the controlling process; NULL if * this process is not controlling this peer. */ struct PeerDetails *details; }; /** * Lookup a peer by ID. * * @param id global peer ID assigned to the peer * @return handle to the host, NULL on error */ struct GNUNET_TESTBED_Peer * GNUNET_TESTBED_peer_lookup_by_id_ (uint32_t id) { GNUNET_break (0); return NULL; } /** * Create the given peer at the specified host using the given * controller. If the given controller is not running on the target * host, it should find or create a controller at the target host and * delegate creating the peer. Explicit delegation paths can be setup * using 'GNUNET_TESTBED_controller_link'. If no explicit delegation * path exists, a direct link with a subordinate controller is setup * for the first delegated peer to a particular host; the subordinate * controller is then destroyed once the last peer that was delegated * to the remote host is stopped. This function is used in particular * if some other controller has already assigned a unique ID to the * peer. * * Creating the peer only creates the handle to manipulate and further * configure the peer; use "GNUNET_TESTBED_peer_start" and * "GNUNET_TESTBED_peer_stop" to actually start/stop the peer's * processes. * * Note that the given configuration will be adjusted by the * controller to avoid port/path conflicts with other peers. * The "final" configuration can be obtained using * 'GNUNET_TESTBED_peer_get_information'. * * @param unique_id unique ID for this peer * @param controller controller process to use * @param host host to run the peer on * @param cfg configuration to use for the peer * @return handle to the peer (actual startup will happen asynchronously) */ struct GNUNET_TESTBED_Peer * GNUNET_TESTBED_peer_create_with_id_ (uint32_t unique_id, struct GNUNET_TESTBED_Controller *controller, struct GNUNET_TESTBED_Host *host, const struct GNUNET_CONFIGURATION_Handle *cfg) { // FIXME: create locally or delegate... GNUNET_break (0); return NULL; } /** * Create the given peer at the specified host using the given * controller. If the given controller is not running on the target * host, it should find or create a controller at the target host and * delegate creating the peer. Explicit delegation paths can be setup * using 'GNUNET_TESTBED_controller_link'. If no explicit delegation * path exists, a direct link with a subordinate controller is setup * for the first delegated peer to a particular host; the subordinate * controller is then destroyed once the last peer that was delegated * to the remote host is stopped. * * Creating the peer only creates the handle to manipulate and further * configure the peer; use "GNUNET_TESTBED_peer_start" and * "GNUNET_TESTBED_peer_stop" to actually start/stop the peer's * processes. * * Note that the given configuration will be adjusted by the * controller to avoid port/path conflicts with other peers. * The "final" configuration can be obtained using * 'GNUNET_TESTBED_peer_get_information'. * * @param controller controller process to use * @param host host to run the peer on * @param cfg configuration to use for the peer * @return handle to the peer (actual startup will happen asynchronously) */ struct GNUNET_TESTBED_Peer * GNUNET_TESTBED_peer_create (struct GNUNET_TESTBED_Controller *controller, struct GNUNET_TESTBED_Host *host, const struct GNUNET_CONFIGURATION_Handle *cfg) { static uint32_t id_gen; return GNUNET_TESTBED_peer_create_with_id_ (++id_gen, controller, host, cfg); } /** * Start the given peer. * * @param peer peer to start * @return handle to the operation */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_peer_start (struct GNUNET_TESTBED_Peer *peer) { // FIXME: start locally or delegate... GNUNET_break (0); return NULL; } /** * Stop the given peer. The handle remains valid (use * "GNUNET_TESTBED_peer_destroy" to fully clean up the * state of the peer). * * @param peer peer to stop * @return handle to the operation */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_peer_stop (struct GNUNET_TESTBED_Peer *peer) { // FIXME: stop locally or delegate... GNUNET_break (0); return NULL; } /** * Request information about a peer. * * @param peer peer to request information about * @param pit desired information * @return handle to the operation */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_peer_get_information (struct GNUNET_TESTBED_Peer *peer, enum GNUNET_TESTBED_PeerInformationType pit) { // FIXME: handle locally or delegate... GNUNET_break (0); return NULL; } /** * Change peer configuration. Must only be called while the * peer is stopped. Ports and paths cannot be changed this * way. * * @param peer peer to change configuration for * @param cfg new configuration (differences to existing * configuration only) * @return handle to the operation */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_peer_update_configuration (struct GNUNET_TESTBED_Peer *peer, const struct GNUNET_CONFIGURATION_Handle *cfg) { // FIXME: handle locally or delegate... GNUNET_break (0); return NULL; } /** * Manipulate the P2P underlay topology by configuring a link * between two peers. * * @param op_cls closure argument to give with the operation event * @param p1 first peer * @param p2 second peer * @param co option to change * @param ... option-specific values * @return handle to the operation, NULL if configuring the link at this * time is not allowed */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_underlay_configure_link (void *op_cls, struct GNUNET_TESTBED_Peer *p1, struct GNUNET_TESTBED_Peer *p2, enum GNUNET_TESTBED_ConnectOption co, ...) { GNUNET_break (0); return NULL; } /** * Both peers must have been started before calling this function. * This function then obtains a HELLO from 'p1', gives it to 'p2' * and asks 'p2' to connect to 'p1'. * * @param op_cls closure argument to give with the operation event * @param p1 first peer * @param p2 second peer * @return handle to the operation, NULL if connecting these two * peers is fundamentally not possible at this time (peers * not running or underlay disallows) */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_overlay_connect (void *op_cls, struct GNUNET_TESTBED_Peer *p1, struct GNUNET_TESTBED_Peer *p2) { GNUNET_break (0); return NULL; } /* end of testbed_api_peers.c */ gnunet-0.9.3/src/testbed/testbed_api_hosts.h0000644000175000017500000000677511760502551016062 00000000000000/* This file is part of GNUnet (C) 2008--2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testbed/testbed_api_hosts.h * @brief internal API to access the 'hosts' subsystem * @author Christian Grothoff */ #ifndef NEW_TESTING_API_HOSTS_H #define NEW_TESTING_API_HOSTS_H #include "gnunet_testbed_service.h" #include "gnunet_helper_lib.h" /** * Lookup a host by ID. * * @param id global host ID assigned to the host; 0 is * reserved to always mean 'localhost' * @return handle to the host, NULL on error */ struct GNUNET_TESTBED_Host * GNUNET_TESTBED_host_lookup_by_id_ (uint32_t id); /** * Create a host by ID; given this host handle, we could not * run peers at the host, but we can talk about the host * internally. * * @param id global host ID assigned to the host; 0 is * reserved to always mean 'localhost' * @return handle to the host, NULL on error */ struct GNUNET_TESTBED_Host * GNUNET_TESTBED_host_create_by_id_ (uint32_t id); /** * Create a host to run peers and controllers on. This function is used * if a peer learns about a host via IPC between controllers (and thus * some higher-level controller has already determined the unique IDs). * * @param id global host ID assigned to the host; 0 is * reserved to always mean 'localhost' * @param hostname name of the host, use "NULL" for localhost * @param username username to use for the login; may be NULL * @param port port number to use for ssh; use 0 to let ssh decide * @return handle to the host, NULL on error */ struct GNUNET_TESTBED_Host * GNUNET_TESTBED_host_create_with_id_ (uint32_t id, const char *hostname, const char *username, uint16_t port); /** * Obtain a host's unique global ID. * * @param host handle to the host, NULL means 'localhost' * @return id global host ID assigned to the host (0 is * 'localhost', but then obviously not globally unique) */ uint32_t GNUNET_TESTBED_host_get_id_ (struct GNUNET_TESTBED_Host *host); /** * Run a given helper process at the given host. Communication * with the helper will be via GNUnet messages on stdin/stdout. * Runs the process via 'ssh' at the specified host, or locally. * Essentially an SSH-wrapper around the 'gnunet_helper_lib.h' API. * * @param host host to use, use "NULL" for localhost * @param binary_argv binary name and command-line arguments to give to the binary * @param cb function to call for messages received from the binary * @param cb_cls closure for cb * @return handle to terminate the command, NULL on error */ struct GNUNET_HELPER_Handle * GNUNET_TESTBED_host_run_ (struct GNUNET_TESTBED_Host *host, char *const binary_argv[], GNUNET_SERVER_MessageTokenizerCallback cb, void *cb_cls); #endif /* end of testbed_api_hosts.h */ gnunet-0.9.3/src/testbed/testbed_api_operations.c0000644000175000017500000001165411760502551017070 00000000000000/* This file is part of GNUnet (C) 2008--2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testbed/testbed_api_operations.c * @brief functions to manage operation queues * @author Christian Grothoff */ #include "platform.h" #include "testbed_api_operations.h" /** * Opaque handle to an abstract operation to be executed by the testing framework. */ struct GNUNET_TESTBED_Operation { /** * Function to call when we have the resources to begin the operation. */ OperationStart start; /** * Function to call to clean up after the operation (which may or may * not have been started yet). */ OperationRelease release; /** * Closure for callbacks. */ void *cb_cls; // FIXME! }; /** * Queue of operations where we can only support a certain * number of concurrent operations of a particular type. */ struct OperationQueue { /** * Maximum number of operationst that can be concurrently * active in this queue. */ unsigned int max_active; // FIXME! }; /** * Create an operation queue. * * @param max_active maximum number of operations in this * queue that can be active in parallel at the same time * @return handle to the queue */ struct OperationQueue * GNUNET_TESTBED_operation_queue_create_ (unsigned int max_active) { struct OperationQueue *queue; queue = GNUNET_malloc (sizeof (struct OperationQueue)); queue->max_active = max_active; return queue; } /** * Destroy an operation queue. The queue MUST be empty * at this time. * * @param queue queue to destroy */ void GNUNET_TESTBED_operation_queue_destroy_ (struct OperationQueue *queue) { GNUNET_break (0); GNUNET_free (queue); } /** * Add an operation to a queue. An operation can be in multiple * queues at once. Once all queues permit the operation to become * active, the operation will be activated. The actual activation * will occur in a separate task (thus allowing multiple queue * insertions to be made without having the first one instantly * trigger the operation if the first queue has sufficient * resources). * * @param queue queue to add the operation to * @param operation operation to add to the queue */ void GNUNET_TESTBED_operation_queue_insert_ (struct OperationQueue *queue, struct GNUNET_TESTBED_Operation *operation) { GNUNET_break (0); } /** * Remove an operation from a queue. This can be because the * oeration was active and has completed (and the resources have * been released), or because the operation was cancelled and * thus scheduling the operation is no longer required. * * @param queue queue to add the operation to * @param operation operation to add to the queue */ void GNUNET_TESTBED_operation_queue_remove_ (struct OperationQueue *queue, struct GNUNET_TESTBED_Operation *operation) { GNUNET_break (0); } /** * An operation is 'done' (was cancelled or finished); remove * it from the queues and release associated resources. * * @param operation operation that finished */ static void operation_release (struct GNUNET_TESTBED_Operation *operation) { // call operation->release, remove from queues GNUNET_break (0); } /** * Cancel a pending operation. Releases all resources * of the operation and will ensure that no event * is generated for the operation. Does NOT guarantee * that the operation will be fully undone (or that * nothing ever happened). * * @param operation operation to cancel */ void GNUNET_TESTBED_operation_cancel (struct GNUNET_TESTBED_Operation *operation) { // test that operation had not yet generated an event GNUNET_break (0); operation_release (operation); } /** * Signal that the information from an operation has been fully * processed. This function MUST be called for each event * of type 'operation_finished' to fully remove the operation * from the operation queue. After calling this function, the * 'op_result' becomes invalid (!). * * @param operation operation to signal completion for */ void GNUNET_TESTBED_operation_done (struct GNUNET_TESTBED_Operation *operation) { // test that operation was started and had generated an event GNUNET_break (0); operation_release (operation); } /* end of testbed_api_operations.c */ gnunet-0.9.3/src/testbed/testbed_api_test.c0000644000175000017500000000436511760502551015665 00000000000000/* This file is part of GNUnet (C) 2008--2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testbed/testbed_api_test.c * @brief high-level test function * @author Christian Grothoff */ #include "platform.h" #include "gnunet_testbed_service.h" /** * Convenience method for running a "simple" test on the local system * with a single call from 'main'. Underlay and overlay topology are * configured using the "UNDERLAY" and "OVERLAY" options in the * "[testbed]" section of the configuration (with possible options * given in "UNDERLAY_XXX" and/or "OVERLAY_XXX"). * * The test is to be terminated using a call to * "GNUNET_SCHEDULER_shutdown". If starting the test fails, * the program is stopped without 'master' ever being run. * * NOTE: this function should be called from 'main', NOT from * within a GNUNET_SCHEDULER-loop. This function will initialze * the scheduler loop, the testbed and then pass control to * 'master'. * * @param testname name of the testcase (to configure logging, etc.) * @param cfg_filename configuration filename to use * (for testbed, controller and peers) * @param num_peers number of peers to start * @param test_master task to run once the test is ready * @param test_master_cls closure for 'task'. */ void GNUNET_TESTBED_test_run (const char *testname, const char *cfg_filename, unsigned int num_peers, GNUNET_TESTBED_TestMaster test_master, void *test_master_cls) { GNUNET_break (0); } /* end of testbed_api_test.c */ gnunet-0.9.3/src/testbed/testbed_api_services.c0000644000175000017500000000436611760502551016532 00000000000000/* This file is part of GNUnet (C) 2008--2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testbed/testbed_api_services.c * @brief convenience functions for accessing services * @author Christian Grothoff */ #include "platform.h" #include "testbed_api_peers.h" /** * Connect to a service offered by the given peer. Will ensure that * the request is queued to not overwhelm our ability to create and * maintain connections with other systems. The actual service * handle is then returned via the 'op_result' member in the event * callback. The 'ca' callback is used to create the connection * when the time is right; the 'da' callback will be used to * destroy the connection (upon 'GNUNET_TESTBED_operation_done'). * 'GNUNET_TESTBED_operation_cancel' can be used to abort this * operation until the event callback has been called. * * @param op_cls closure to pass in operation event * @param peer peer that runs the service * @param service_name name of the service to connect to * @param ca helper function to establish the connection * @param da helper function to close the connection * @param cada_cls closure for ca and da * @return handle for the operation */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_service_connect (void *op_cls, struct GNUNET_TESTBED_Peer *peer, const char *service_name, GNUNET_TESTBED_ConnectAdapter ca, GNUNET_TESTBED_DisconnectAdapter da, void *cada_cls) { GNUNET_break (0); return NULL; } /* end of testbed_api_services.c */ gnunet-0.9.3/src/testbed/testbed.h0000644000175000017500000002340511760502551013776 00000000000000/* This file is part of GNUnet (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testbed/testbed.h * @brief IPC messages between testing API and service ("controller") * @author Christian Grothoff */ #ifndef NEW_TESTING_H #define NEW_TESTING_H #include "gnunet_util_lib.h" /** * Initial message from a client to a testing control service. */ struct GNUNET_TESTBED_Message { /** * Type is */ struct GNUNET_MessageHeader header; /** * Host ID that the controller is either given * (if this is the dominating client communicating * via stdin) or assumed to have (for peer-connections * between controllers). */ uint32_t host_id GNUNET_PACKED; /** * Event mask that specifies which events this client * is interested in. In NBO. */ uint64_t event_mask GNUNET_PACKED; }; /** * Notify the service about a host that we intend to use. */ struct GNUNET_TESTBED_AddHostMessage { /** * Type is */ struct GNUNET_MessageHeader header; /** * Unique ID for the host (in NBO). */ uint32_t host_id GNUNET_PACKED; /** * SSH port to use, 0 for default (in NBO). */ uint16_t ssh_port GNUNET_PACKED; /** * Number of bytes in the user name that follows; * 0 to use no user name; otherwise 'strlen (username)', * excluding 0-termination! */ uint16_t user_name_length GNUNET_PACKED; /* followed by 0-terminated user name */ /* followed by 0-terminated host name */ }; /** * Confirmation from the service that adding a host * worked (or failed). */ struct GNUNET_TESTBED_HostConfirmedMessage { /** * Type is */ struct GNUNET_MessageHeader header; /** * Unique ID for the host (in NBO). */ uint32_t host_id GNUNET_PACKED; /* followed by the 0-terminated error message (on failure) (typical errors include failure to login and host-id already in use) */ }; /** * Message to testing service: configure service sharing * at a host. */ struct GNUNET_TESTBED_ConfigureSharedServiceMessage { /** * Type is */ struct GNUNET_MessageHeader header; /** * Host that is being configured. */ uint32_t host_id GNUNET_PACKED; /** * Number of peers that should share a service instance; * 1 for no sharing, 0 to forcefully disable the service. */ uint32_t num_peers GNUNET_PACKED; /* followed by 0-terminated name of the service */ }; /** * Client notifies controller that it should delegate * requests for a particular client to a particular * sub-controller. */ struct GNUNET_TESTBED_ControllerLinkMessage { /** * Type is */ struct GNUNET_MessageHeader header; /** * For which host should requests be delegated? NBO. */ uint32_t delegated_host_id GNUNET_PACKED; /** * Which host is responsible for managing the delegation? NBO */ uint32_t slave_host_id GNUNET_PACKED; /** * Is the receiving controller the master controller for * the slave host (and thus responsible for starting it?). NBO. */ int32_t is_subordinate GNUNET_PACKED; /* followed by serialized slave configuration; gzip'ed configuration file in INI format */ }; /** * Message sent from client to testing service to * create (configure, but not start) a peer. */ struct GNUNET_TESTBED_PeerCreateMessage { /** * Type is */ struct GNUNET_MessageHeader header; /** * On which host should the peer be started? */ uint32_t host_id GNUNET_PACKED; /** * Unique ID for the peer. */ uint32_t peer_id GNUNET_PACKED; /* followed by serialized peer configuration; gzip'ed configuration file in INI format */ }; /** * Message sent from client to testing service to * reconfigure a (stopped) a peer. */ struct GNUNET_TESTBED_PeerReconfigureMessage { /** * Type is */ struct GNUNET_MessageHeader header; /** * Unique ID for the peer. */ uint32_t peer_id GNUNET_PACKED; /** * Operation ID that is used to identify this operation. */ uint64_t operation_id GNUNET_PACKED; /* followed by serialized peer configuration; gzip'ed configuration file in INI format */ }; /** * Message sent from client to testing service to * start a peer. */ struct GNUNET_TESTBED_PeerStartMessage { /** * Type is */ struct GNUNET_MessageHeader header; /** * Unique ID for the peer. */ uint32_t peer_id GNUNET_PACKED; /** * Operation ID that is used to identify this operation. */ uint64_t operation_id GNUNET_PACKED; }; /** * Message sent from client to testing service to * stop a peer. */ struct GNUNET_TESTBED_PeerStopMessage { /** * Type is */ struct GNUNET_MessageHeader header; /** * Unique ID for the peer. */ uint32_t peer_id GNUNET_PACKED; /** * Operation ID that is used to identify this operation. */ uint64_t operation_id GNUNET_PACKED; }; /** * Message sent from client to testing service to * destroy a (stopped) peer. */ struct GNUNET_TESTBED_PeerDestroyMessage { /** * Type is */ struct GNUNET_MessageHeader header; /** * Unique ID for the peer. */ uint32_t peer_id GNUNET_PACKED; /** * Operation ID that is used to identify this operation. */ uint64_t operation_id GNUNET_PACKED; }; /** * Message sent from client to testing service to * (re)configure a "physical" link between two peers. */ struct GNUNET_TESTBED_ConfigureUnderlayLinkMessage { /** * Type is */ struct GNUNET_MessageHeader header; /** * 'enum GNUNET_TESTBED_ConnectOption' of the option to change */ int32_t connect_option GNUNET_PACKED; /** * Unique ID for the first peer. */ uint32_t peer1 GNUNET_PACKED; /** * Unique ID for the second peer. */ uint32_t peer2 GNUNET_PACKED; /** * Operation ID that is used to identify this operation. */ uint64_t operation_id GNUNET_PACKED; /* followed by option-dependent variable-size values */ }; /** * Message sent from client to testing service to * connect two peers. */ struct GNUNET_TESTBED_OverlayConnectMessage { /** * Type is */ struct GNUNET_MessageHeader header; /** * Unique ID for the first peer. */ uint32_t peer1 GNUNET_PACKED; /** * Operation ID that is used to identify this operation. */ uint64_t operation_id GNUNET_PACKED; /** * Unique ID for the second peer. */ uint32_t peer2 GNUNET_PACKED; }; /** * Event notification from a controller to a client. */ struct GNUNET_TESTBED_PeerEventMessage { /** * Type is */ struct GNUNET_MessageHeader header; /** * 'enum GNUNET_TESTBED_EventType' (in NBO); * either GNUNET_TESTBED_ET_PEER_START or GNUNET_TESTBED_ET_PEER_STOP. */ int32_t event_type GNUNET_PACKED; /** * Host where the peer is running. */ uint32_t host_id GNUNET_PACKED; /** * Peer that was started or stopped. */ uint32_t peer_id GNUNET_PACKED; /** * Operation ID that is used to identify this operation. */ uint64_t operation_id GNUNET_PACKED; }; /** * Event notification from a controller to a client. */ struct GNUNET_TESTBED_ConnectionEventMessage { /** * Type is */ struct GNUNET_MessageHeader header; /** * 'enum GNUNET_TESTBED_EventType' (in NBO); * either GNUNET_TESTBED_ET_PEER_CONNECT or GNUNET_TESTBED_ET_PEER_DISCONNECT. */ int32_t event_type GNUNET_PACKED; /** * First peer. */ uint32_t peer1 GNUNET_PACKED; /** * Second peer. */ uint32_t peer2 GNUNET_PACKED; /** * Operation ID that is used to identify this operation. */ uint64_t operation_id GNUNET_PACKED; }; /** * Event notification from a controller to a client. */ struct GNUNET_TESTBED_OperationFailureEventMessage { /** * Type is */ struct GNUNET_MessageHeader header; /** * 'enum GNUNET_TESTBED_EventType' (in NBO); * GNUNET_TESTBED_ET_OPERATION_FINISHED. */ int32_t event_type GNUNET_PACKED; /** * Operation ID of the operation that created this event. */ uint64_t operation_id GNUNET_PACKED; /* followed by 0-terminated error message */ }; /** * Event notification from a controller to a client. */ struct GNUNET_TESTBED_PeerCreateSuccessEventMessage { /** * Type is */ struct GNUNET_MessageHeader header; /** * Peer identity of the peer that was created. */ uint32_t peer_id GNUNET_PACKED; /** * Operation ID of the operation that created this event. */ uint64_t operation_id GNUNET_PACKED; /** * Identity of the peer. */ struct GNUNET_PeerIdentity peer_id; /* followed by gzip-compressed configuration of the peer */ }; /** * Event notification from a controller to a client for * a generic operational success where the operation does * not return any data. */ struct GNUNET_TESTBED_GenericOperationSuccessEventMessage { /** * Type is */ struct GNUNET_MessageHeader header; /** * 'enum GNUNET_TESTBED_EventType' (in NBO); * GNUNET_TESTBED_ET_OPERATION_FINISHED. */ int32_t event_type GNUNET_PACKED; /** * Operation ID of the operation that created this event. */ uint64_t operation_id GNUNET_PACKED; }; #endif gnunet-0.9.3/src/testbed/testbed_api_testbed.c0000644000175000017500000001156711760502551016342 00000000000000/* This file is part of GNUnet (C) 2008--2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testbed/testbed_api_testbed.c * @brief high-level testbed management * @author Christian Grothoff */ #include "platform.h" #include "gnunet_testbed_service.h" /** * Opaque handle to an abstract operation to be executed by the testing framework. */ struct GNUNET_TESTBED_Testbed { // FIXME! }; /** * Configure and run a testbed using the given * master controller on 'num_hosts' starting * 'num_peers' using the given peer configuration. * * @param controller master controller for the testbed * (must not be destroyed until after the * testbed is destroyed). * @param num_hosts number of hosts in 'hosts', 0 to only * use 'localhost' * @param hosts list of hosts to use for the testbed * @param num_peers number of peers to start * @param peer_cfg peer configuration template to use * @param underlay_topology underlay topology to create * @param va topology-specific options * @return handle to the testbed */ struct GNUNET_TESTBED_Testbed * GNUNET_TESTBED_create_va (struct GNUNET_TESTBED_Controller *controller, unsigned int num_hosts, struct GNUNET_TESTBED_Host **hosts, unsigned int num_peers, const struct GNUNET_CONFIGURATION_Handle *peer_cfg, enum GNUNET_TESTBED_TopologyOption underlay_topology, va_list va) { GNUNET_break (0); return NULL; } /** * Configure and run a testbed using the given * master controller on 'num_hosts' starting * 'num_peers' using the given peer configuration. * * @param controller master controller for the testbed * (must not be destroyed until after the * testbed is destroyed). * @param num_hosts number of hosts in 'hosts', 0 to only * use 'localhost' * @param hosts list of hosts to use for the testbed * @param num_peers number of peers to start * @param peer_cfg peer configuration template to use * @param underlay_topology underlay topology to create * @param ... topology-specific options */ struct GNUNET_TESTBED_Testbed * GNUNET_TESTBED_create (struct GNUNET_TESTBED_Controller *controller, unsigned int num_hosts, struct GNUNET_TESTBED_Host **hosts, unsigned int num_peers, const struct GNUNET_CONFIGURATION_Handle *peer_cfg, enum GNUNET_TESTBED_TopologyOption underlay_topology, ...) { GNUNET_break (0); return NULL; } /** * Destroy a testbed. Stops all running peers and then * destroys all peers. Does NOT destroy the master controller. * * @param testbed testbed to destroy */ void GNUNET_TESTBED_destroy (struct GNUNET_TESTBED_Testbed *testbed) { GNUNET_break (0); } /** * Convenience method for running a testbed with * a single call. Underlay and overlay topology * are configured using the "UNDERLAY" and "OVERLAY" * options in the "[testbed]" section of the configuration\ * (with possible options given in "UNDERLAY_XXX" and/or * "OVERLAY_XXX"). * * The testbed is to be terminated using a call to * "GNUNET_SCHEDULER_shutdown". * * @param host_filename name of the file with the 'hosts', NULL * to run everything on 'localhost' * @param cfg configuration to use (for testbed, controller and peers) * @param num_peers number of peers to start; FIXME: maybe put that ALSO into cfg? * @param event_mask bit mask with set of events to call 'cc' for; * or-ed values of "1LL" shifted by the * respective 'enum GNUNET_TESTBED_EventType' * (i.e. "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...") * @param cc controller callback to invoke on events * @param cc_cls closure for cc * @param master task to run once the testbed is ready * @param master_cls closure for 'task'. */ void GNUNET_TESTBED_run (const char *host_filename, const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned int num_peers, uint64_t event_mask, GNUNET_TESTBED_ControllerCallback cc, void *cc_cls, GNUNET_SCHEDULER_Task master, void *master_cls) { GNUNET_break (0); } /* end of testbed_api_testbed.c */ gnunet-0.9.3/src/testbed/Makefile.in0000644000175000017500000005552711762217213014252 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = src/testbed DIST_COMMON = $(dist_pkgcfg_DATA) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libgnunettestbed_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la am_libgnunettestbed_la_OBJECTS = testbed_api.lo testbed_api_hosts.lo \ testbed_api_operations.lo testbed_api_peers.lo \ testbed_api_services.lo testbed_api_testbed.lo \ testbed_api_test.lo testbed_api_topology.lo libgnunettestbed_la_OBJECTS = $(am_libgnunettestbed_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunettestbed_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunettestbed_la_LDFLAGS) \ $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunettestbed_la_SOURCES) DIST_SOURCES = $(libgnunettestbed_la_SOURCES) DATA = $(dist_pkgcfg_DATA) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @USE_COVERAGE_TRUE@XLIB = -lgcov pkgcfgdir = $(pkgdatadir)/config.d/ dist_pkgcfg_DATA = \ testbed.conf lib_LTLIBRARIES = \ libgnunettestbed.la libgnunettestbed_la_SOURCES = \ testbed_api.c testbed.h \ testbed_api_hosts.c testbed_api_hosts.h \ testbed_api_operations.c testbed_api_operations.h \ testbed_api_peers.c testbed_api_peers.h \ testbed_api_services.c \ testbed_api_testbed.c \ testbed_api_test.c \ testbed_api_topology.c libgnunettestbed_la_LIBADD = $(XLIB) \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ -lm \ $(top_builddir)/src/util/libgnunetutil.la libgnunettestbed_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:0:0 all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/testbed/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/testbed/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunettestbed.la: $(libgnunettestbed_la_OBJECTS) $(libgnunettestbed_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunettestbed_la_LINK) -rpath $(libdir) $(libgnunettestbed_la_OBJECTS) $(libgnunettestbed_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testbed_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testbed_api_hosts.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testbed_api_operations.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testbed_api_peers.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testbed_api_services.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testbed_api_test.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testbed_api_testbed.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testbed_api_topology.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_pkgcfgDATA: $(dist_pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-dist_pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(DATA) installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_pkgcfgDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_pkgcfgDATA uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-dist_pkgcfgDATA install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-libLTLIBRARIES \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ uninstall-am uninstall-dist_pkgcfgDATA \ uninstall-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/testbed/testbed.conf0000644000175000017500000000000011751245443014462 00000000000000gnunet-0.9.3/src/testbed/testbed_api_peers.h0000644000175000017500000000536411760502551016031 00000000000000/* This file is part of GNUnet (C) 2008--2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testbed/testbed_api_peers.h * @brief internal API to access the 'peers' subsystem * @author Christian Grothoff */ #ifndef NEW_TESTING_API_PEERS_H #define NEW_TESTING_API_PEERS_H #include "gnunet_testbed_service.h" #include "gnunet_helper_lib.h" /** * Create the given peer at the specified host using the given * controller. If the given controller is not running on the target * host, it should find or create a controller at the target host and * delegate creating the peer. Explicit delegation paths can be setup * using 'GNUNET_TESTBED_controller_link'. If no explicit delegation * path exists, a direct link with a subordinate controller is setup * for the first delegated peer to a particular host; the subordinate * controller is then destroyed once the last peer that was delegated * to the remote host is stopped. This function is used in particular * if some other controller has already assigned a unique ID to the * peer. * * Creating the peer only creates the handle to manipulate and further * configure the peer; use "GNUNET_TESTBED_peer_start" and * "GNUNET_TESTBED_peer_stop" to actually start/stop the peer's * processes. * * Note that the given configuration will be adjusted by the * controller to avoid port/path conflicts with other peers. * The "final" configuration can be obtained using * 'GNUNET_TESTBED_peer_get_information'. * * @param unique_id unique ID for this peer * @param controller controller process to use * @param host host to run the peer on * @param cfg configuration to use for the peer * @return handle to the peer (actual startup will happen asynchronously) */ struct GNUNET_TESTBED_Peer * GNUNET_TESTBED_peer_create_with_id_ (uint32_t unique_id, struct GNUNET_TESTBED_Controller *controller, struct GNUNET_TESTBED_Host *host, const struct GNUNET_CONFIGURATION_Handle *cfg); #endif /* end of testbed_api_peers.h */ gnunet-0.9.3/src/testbed/testbed_api_operations.h0000644000175000017500000001006611760502551017071 00000000000000/* This file is part of GNUnet (C) 2008--2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testbed/testbed_api_operations.h * @brief internal API to access the 'operations' subsystem * @author Christian Grothoff */ #ifndef NEW_TESTING_API_OPERATIONS_H #define NEW_TESTING_API_OPERATIONS_H #include "gnunet_testbed_service.h" #include "gnunet_helper_lib.h" /** * Queue of operations where we can only support a certain * number of concurrent operations of a particular type. */ struct OperationQueue; /** * Create an operation queue. * * @param max_active maximum number of operations in this * queue that can be active in parallel at the same time * @return handle to the queue */ struct OperationQueue * GNUNET_TESTBED_operation_queue_create_ (unsigned int max_active); /** * Destroy an operation queue. The queue MUST be empty * at this time. * * @param queue queue to destroy */ void GNUNET_TESTBED_operation_queue_destroy_ (struct OperationQueue *queue); /** * Add an operation to a queue. An operation can be in multiple * queues at once. Once all queues permit the operation to become * active, the operation will be activated. The actual activation * will occur in a separate task (thus allowing multiple queue * insertions to be made without having the first one instantly * trigger the operation if the first queue has sufficient * resources). * * @param queue queue to add the operation to * @param operation operation to add to the queue */ void GNUNET_TESTBED_operation_queue_insert_ (struct OperationQueue *queue, struct GNUNET_TESTBED_Operation *operation); /** * Remove an operation from a queue. This can be because the * oeration was active and has completed (and the resources have * been released), or because the operation was cancelled and * thus scheduling the operation is no longer required. * * @param queue queue to add the operation to * @param operation operation to add to the queue */ void GNUNET_TESTBED_operation_queue_remove_ (struct OperationQueue *queue, struct GNUNET_TESTBED_Operation *operation); /** * Function to call to start an operation once all * queues the operation is part of declare that the * operation can be activated. */ typedef void (*OperationStart)(void *cls); /** * Function to call to cancel an operation (release all associated * resources). This can be because of a call to * "GNUNET_TESTBED_operation_cancel" (before the operation generated * an event) or AFTER the operation generated an event due to a call * to "GNUNET_TESTBED_operation_done". Thus it is not guaranteed that * a callback to the 'OperationStart' preceeds the call to * 'OperationRelease'. Implementations of this function are expected * to clean up whatever state is in 'cls' and release all resources * associated with the operation. */ typedef void (*OperationRelease)(void *cls); /** * Create an 'operation' to be performed. * * @param cls closure for the callbacks * @param start function to call to start the operation * @param release function to call to close down the operation * @param ... FIXME * @return handle to the operation */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_operation_create_ (void *cls, OperationStart start, OperationRelease release, ...); #endif /* end of testbed_api_operations.h */ gnunet-0.9.3/src/nse/0000755000175000017500000000000011763406750011411 500000000000000gnunet-0.9.3/src/nse/test_nse_api.c0000644000175000017500000001111111760502551014136 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file nse/test_nse_api.c * @brief testcase for nse_api.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_nse_service.h" #define START_ARM GNUNET_YES static struct GNUNET_NSE_Handle *h; static GNUNET_SCHEDULER_TaskIdentifier die_task; struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static struct PeerContext p1; static void stop_arm (struct PeerContext *p) { #if START_ARM if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); GNUNET_OS_process_wait (p->arm_proc); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; #endif GNUNET_CONFIGURATION_destroy (p->cfg); } /** * Signature of the main function of a task. * * @param cls closure * @param tc context information (why was this task triggered now) */ static void end_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (h != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from NSE service.\n"); GNUNET_NSE_disconnect (h); } } /** * Callback to call when network size estimate is updated. * * @param cls unused * @param timestamp time when the estimate was received from the server (or created by the server) * @param estimate the value of the current network size estimate * @param std_dev standard deviation (rounded down to nearest integer) * of the size estimation values seen * */ static void check_nse_message (void *cls, struct GNUNET_TIME_Absolute timestamp, double estimate, double std_dev) { int *ok = cls; FPRINTF (stderr, "Received NSE message, estimate %f, standard deviation %f.\n", estimate, std_dev); /* Fantastic check below. Expect NaN, the only thing not equal to itself. */ (*ok) = 0; if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_test, NULL); } static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE_ARM "-L", "DEBUG", #endif "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1), &end_test, NULL); setup_peer (&p1, cfgfile); h = GNUNET_NSE_connect (cfg, &check_nse_message, cls); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to NSE service.\n"); GNUNET_assert (h != NULL); } static int check () { int ok = 1; char *const argv[] = { "test-nse-api", "-c", "test_nse.conf", "-L", "WARNING", NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_PROGRAM_run (5, argv, "test-nse-api", "nohelp", options, &run, &ok); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping arm.\n"); stop_arm (&p1); if (0 != ok) FPRINTF (stderr, "%s", "No information received from NSE service!\n"); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test_nse_api", "WARNING", NULL); ret = check (); return ret; } /* end of test_nse_api.c */ gnunet-0.9.3/src/nse/nse_profiler_test.conf0000644000175000017500000000526011760506121015717 00000000000000[PATHS] SERVICEHOME = /tmp/nse-profiler/ DEFAULTCONFIG = nse_profiler_test.conf [nse] PORT = 0 UNIXPATH = /tmp/test-nse-service-nse.unix BINARY = gnunet-service-nse #BINARY = /home/mrwiggles/documents/research/gnunet/gnunet-ng/src/nse/.libs/gnunet-service-nse #PREFIX = valgrind --leak-check=full --log-file=valgrind_nse.%p AUTOSTART = NO DEBUG = YES CONFIG = $DEFAULTCONFIG # Overriding network settings for faster testing (do NOT use # these values in production just because they are here) WORKDELAY = 60 s INTERVAL = 30 s WORKBITS = 0 PROOFFILE = $SERVICEHOME/nse.proof [arm] PORT = 0 DEFAULTSERVICES = core UNIXPATH = /tmp/test-nse-service-arm.unix #DEBUG = YES [statistics] AUTOSTART = YES PORT=0 [fs] AUTOSTART = NO PORT=0 [datastore] AUTOSTART = NO PORT = 0 [dht] AUTOSTART = NO PORT = 0 [nat] DISABLEV6 = YES BINDTO = 127.0.0.1 ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 [transport] PORT = 0 plugins = unix [transport-unix] PORT = 1 [transport-tcp] PORT = 0 [transport-udp] PORT = 0 [transport-http] PORT = 0 [transport-https] PORT = 0 [core] AUTOSTART = YES PORT = 0 [peerinfo] AUTOSTART = YES PORT = 0 [dns] AUTOSTART = NO [topology] AUTOSTART = NO [dv] AUTOSTART = NO [resolver] PORT = 0 [ats] PORT = 0 [mesh] AUTOSTART = NO [chat] AUTOSTART = NO [gns] AUTOSTART = NO [vpn] AUTOSTART = NO [testing] NUM_PEERS = 2000 WEAKRANDOM = YES TOPOLOGY = NONE #CONNECT_TOPOLOGY = SMALL_WORLD_RING CONNECT_TOPOLOGY = ERDOS_RENYI CONNECT_TOPOLOGY_OPTION = CONNECT_MINIMUM CONNECT_TOPOLOGY_OPTION_MODIFIER = 5 # PERCENTAGE = 3 PROBABILITY = .1 F2F = NO CONNECT_TIMEOUT = 360 s CONNECT_ATTEMPTS = 3 DEBUG = YES #HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat HOSTKEYSFILE = hostkeys.dat MAX_CONCURRENT_SSH = 20 USE_PROGRESSBARS = YES PEERGROUP_TIMEOUT = 1000 s TOPOLOGY_OUTPUT_FILE = nse_topo_2000_peers_initial MAX_OUTSTANDING_CONNECTIONS = 100 #SINGLE_PEERINFO_PER_HOST = YES #NUM_PEERINFO_PER_HOST = 10 #SINGLE_STATISTICS_PER_HOST = YES #NUM_STATISTICS_PER_HOST = 10 DELETE_FILES = NO #SKEW_VARIANCE = 30000 [nse-profiler] OUTPUT_FILE = nse_output_2000_peers.dat TOPOLOGY_OUTPUT_FILE = nse_topo_2000_peers DATA_OUTPUT_FILE = nse_stats_2000_peers ROUND0 = 1000 #ROUND1 = 2000 ROUND2 = 2000 ROUND3 = 2000 ROUND4 = 2000 ROUND5 = 2000 ROUND6 = 2000 ROUND7 = 2000 ROUND8 = 2000 ROUND9 = 2000 ROUND10 = 2000 ROUND11 = 1000 ROUND12 = 1000 ROUND13 = 1000 ROUND14 = 1000 ROUND15 = 1000 ROUND16 = 1000 ROUND17 = 1000 ROUND18 = 1000 ROUND19 = 1000 ROUND20 = 1000 ROUND21 = 2000 ROUND22 = 2000 ROUND23 = 2000 ROUND24 = 2000 ROUND25 = 2000 ROUND26 = 2000 ROUND27 = 2000 ROUND28 = 2000 ROUND29 = 2000 ROUND30 = 2000 WAIT_TIME = 1920 s CONNECTION_LIMIT = 10 gnunet-0.9.3/src/nse/Makefile.am0000644000175000017500000000364211704315747013372 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIB = -lgcov endif pkgcfgdir= $(pkgdatadir)/config.d/ pkgcfg_DATA = \ nse.conf lib_LTLIBRARIES = libgnunetnse.la libgnunetnse_la_SOURCES = \ nse_api.c nse.h libgnunetnse_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) $(XLIB) libgnunetnse_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 0:0:0 bin_PROGRAMS = \ gnunet-service-nse noinst_PROGRAMS = \ gnunet-nse-profiler gnunet_nse_profiler_SOURCES = \ gnunet-nse-profiler.c gnunet_nse_profiler_LDADD = -lm \ $(top_builddir)/src/nse/libgnunetnse.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(GN_LIBINTL) gnunet_nse_profiler_DEPENDENCIES = \ libgnunetnse.la gnunet_service_nse_SOURCES = \ gnunet-service-nse.c gnunet_service_nse_LDADD = \ $(top_builddir)/src/nse/libgnunetnse.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ -lm \ $(GN_LIBINTL) gnunet_service_nse_DEPENDENCIES = \ libgnunetnse.la if HAVE_BENCHMARKS MULTIPEER_TEST = test_nse_multipeer endif check_PROGRAMS = \ test_nse_api \ $(MULTIPEER_TEST) if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) endif test_nse_api_SOURCES = \ test_nse_api.c test_nse_api_LDADD = \ $(top_builddir)/src/nse/libgnunetnse.la \ $(top_builddir)/src/util/libgnunetutil.la test_nse_multipeer_SOURCES = \ test_nse_multipeer.c test_nse_multipeer_LDADD = \ $(top_builddir)/src/nse/libgnunetnse.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la \ -lm EXTRA_DIST = \ test_nse.conf \ nse_profiler_test.conf gnunet-0.9.3/src/nse/gnunet-nse-profiler.c0000644000175000017500000006520611760515777015420 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file nse/gnunet-nse-profiler.c * * @brief Profiling driver for the network size estimation service. * Generally, the profiler starts a given number of peers, * then churns some off, waits a certain amount of time, then * churns again, and repeats. */ #include "platform.h" #include "gnunet_testing_lib.h" #include "gnunet_nse_service.h" #define VERBOSE 3 struct NSEPeer { struct NSEPeer *prev; struct NSEPeer *next; struct GNUNET_TESTING_Daemon *daemon; struct GNUNET_NSE_Handle *nse_handle; struct GNUNET_STATISTICS_Handle *stats; GNUNET_SCHEDULER_TaskIdentifier stats_task; }; struct StatsContext { /** * Whether or not shoutdown after finishing. */ int shutdown; /** * How many messages have peers received during the test. */ unsigned long long total_nse_received_messages; /** * How many messages have peers send during the test (should be == received). */ unsigned long long total_nse_transmitted_messages; /** * How many messages have travelled an edge in both directions. */ unsigned long long total_nse_cross; /** * How many extra messages per edge (corrections) have been received. */ unsigned long long total_nse_extra; /** * How many messages have been discarded. */ unsigned long long total_discarded; }; static struct NSEPeer *peer_head; static struct NSEPeer *peer_tail; /** * How long until we give up on connecting the peers? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500) static int ok; /** * Be verbose */ static int verbose; /** * Total number of peers in the test. */ static unsigned long long num_peers; /** * Global configuration file */ static struct GNUNET_CONFIGURATION_Handle *testing_cfg; /** * Total number of currently running peers. */ static unsigned long long peers_running; /** * Current round we are in. */ static unsigned long long current_round; /** * Peers desired in the next round. */ static unsigned long long peers_next_round; /** * Maximum number of connections to NSE services. */ static unsigned long long connection_limit; /** * Total number of connections in the whole network. */ static unsigned int total_connections; /** * The currently running peer group. */ static struct GNUNET_TESTING_PeerGroup *pg; /** * File to report results to. */ static struct GNUNET_DISK_FileHandle *output_file; /** * File to log connection info, statistics to. */ static struct GNUNET_DISK_FileHandle *data_file; /** * How many data points to capture before triggering next round? */ static struct GNUNET_TIME_Relative wait_time; /** * NSE interval. */ static struct GNUNET_TIME_Relative interval; /** * Task called to disconnect peers. */ static GNUNET_SCHEDULER_TaskIdentifier disconnect_task; /** * Task called to shutdown test. */ static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle; /** * Task used to churn the network. */ static GNUNET_SCHEDULER_TaskIdentifier churn_task; static char *topology_file; /** * Check whether peers successfully shut down. */ static void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); #endif if (ok == 0) ok = 666; } else { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); #endif ok = 0; } } static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct NSEPeer *pos; #if VERBOSE FPRINTF (stderr, "%s", "Ending test.\n"); #endif if (disconnect_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (disconnect_task); disconnect_task = GNUNET_SCHEDULER_NO_TASK; } while (NULL != (pos = peer_head)) { if (pos->nse_handle != NULL) GNUNET_NSE_disconnect (pos->nse_handle); GNUNET_CONTAINER_DLL_remove (peer_head, peer_tail, pos); if (GNUNET_SCHEDULER_NO_TASK != pos->stats_task) { GNUNET_SCHEDULER_cancel (pos->stats_task); if (NULL != pos->stats) GNUNET_STATISTICS_destroy(pos->stats, GNUNET_NO); } GNUNET_free (pos); } if (data_file != NULL) GNUNET_DISK_file_close (data_file); GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); } /** * Callback to call when network size estimate is updated. * * @param cls closure * @param timestamp server timestamp * @param estimate the value of the current network size estimate * @param std_dev standard deviation (rounded down to nearest integer) * of the size estimation values seen * */ static void handle_estimate (void *cls, struct GNUNET_TIME_Absolute timestamp, double estimate, double std_dev) { struct NSEPeer *peer = cls; char *output_buffer; size_t size; if (output_file != NULL) { size = GNUNET_asprintf (&output_buffer, "%s %llu %llu %f %f %f\n", GNUNET_i2s (&peer->daemon->id), peers_running, timestamp.abs_value, GNUNET_NSE_log_estimate_to_n (estimate), estimate, std_dev); if (size != GNUNET_DISK_file_write (output_file, output_buffer, size)) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to write to file!\n"); GNUNET_free (output_buffer); } else FPRINTF (stderr, "Received network size estimate from peer %s. Size: %f std.dev. %f\n", GNUNET_i2s (&peer->daemon->id), estimate, std_dev); } /** * Process core statistic values. * * @param cls closure * @param subsystem name of subsystem that created the statistic * @param name the name of the datum * @param value the current value * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration */ static int core_stats_iterator (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent) { struct NSEPeer *peer = cls; char *output_buffer; size_t size; if (output_file != NULL) { size = GNUNET_asprintf (&output_buffer, "%s [%s] %s %llu\n", GNUNET_i2s (&peer->daemon->id), subsystem, name, value); if (size != GNUNET_DISK_file_write (output_file, output_buffer, size)) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to write to file!\n"); GNUNET_free (output_buffer); } else GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%s -> %s [%s]: %llu\n", GNUNET_i2s (&peer->daemon->id), subsystem, name, value); return GNUNET_OK; } /** * Continuation called by "get_stats" function. * * @param cls closure * @param success GNUNET_OK if statistics were * successfully obtained, GNUNET_SYSERR if not. */ static void core_stats_cont (void *cls, int success); static void core_get_stats (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct NSEPeer *peer = cls; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) { GNUNET_STATISTICS_destroy(peer->stats, GNUNET_NO); peer->stats = NULL; return; } else { GNUNET_STATISTICS_get(peer->stats, "core", NULL, GNUNET_TIME_UNIT_FOREVER_REL, &core_stats_cont, &core_stats_iterator, peer); GNUNET_STATISTICS_get(peer->stats, "transport", NULL, GNUNET_TIME_UNIT_FOREVER_REL, NULL, &core_stats_iterator, peer); GNUNET_STATISTICS_get(peer->stats, "nse", NULL, GNUNET_TIME_UNIT_FOREVER_REL, NULL, &core_stats_iterator, peer); } peer->stats_task = GNUNET_SCHEDULER_NO_TASK; } /** * Continuation called by "get_stats" function. * * @param cls closure * @param success GNUNET_OK if statistics were * successfully obtained, GNUNET_SYSERR if not. */ static void core_stats_cont (void *cls, int success) { struct NSEPeer *peer = cls; peer->stats_task = GNUNET_SCHEDULER_add_delayed (interval, &core_get_stats, peer); } /** * */ static void connect_nse_service (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct NSEPeer *current_peer; unsigned int i; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to nse service of peers\n"); #endif for (i = 0; i < num_peers; i++) { if ((connection_limit > 0) && (num_peers > connection_limit) && (i % (num_peers / connection_limit) != 0)) continue; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "nse-profiler: connecting to nse service of peer %d\n", i); #endif current_peer = GNUNET_malloc (sizeof (struct NSEPeer)); current_peer->daemon = GNUNET_TESTING_daemon_get (pg, i); if (GNUNET_YES == GNUNET_TESTING_test_daemon_running (GNUNET_TESTING_daemon_get (pg, i))) { current_peer->nse_handle = GNUNET_NSE_connect (current_peer->daemon->cfg, &handle_estimate, current_peer); GNUNET_assert (current_peer->nse_handle != NULL); } current_peer->stats = GNUNET_STATISTICS_create("profiler", current_peer->daemon->cfg); GNUNET_STATISTICS_get(current_peer->stats, "core", NULL, GNUNET_TIME_UNIT_FOREVER_REL, &core_stats_cont, &core_stats_iterator, current_peer); GNUNET_STATISTICS_get(current_peer->stats, "transport", NULL, GNUNET_TIME_UNIT_FOREVER_REL, NULL, &core_stats_iterator, current_peer); GNUNET_STATISTICS_get(current_peer->stats, "nse", NULL, GNUNET_TIME_UNIT_FOREVER_REL, NULL, &core_stats_iterator, current_peer); GNUNET_CONTAINER_DLL_insert (peer_head, peer_tail, current_peer); } } static void churn_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Continuation called by the "get_all" and "get" functions. * * @param cls struct StatsContext * @param success GNUNET_OK if statistics were * successfully obtained, GNUNET_SYSERR if not. */ static void stats_finished_callback (void *cls, int success) { struct StatsContext *stats_context = cls; char *buf; int buf_len; if ((GNUNET_OK == success) && (data_file != NULL)) { /* Stats lookup successful, write out data */ buf = NULL; buf_len = GNUNET_asprintf (&buf, "TOTAL_NSE_RECEIVED_MESSAGES_%d: %u \n", stats_context->shutdown, stats_context->total_nse_received_messages); if (buf_len > 0) { GNUNET_DISK_file_write (data_file, buf, buf_len); } GNUNET_free_non_null (buf); buf = NULL; buf_len = GNUNET_asprintf (&buf, "TOTAL_NSE_TRANSMITTED_MESSAGES_%d: %u\n", stats_context->shutdown, stats_context->total_nse_transmitted_messages); if (buf_len > 0) { GNUNET_DISK_file_write (data_file, buf, buf_len); } GNUNET_free_non_null (buf); buf = NULL; buf_len = GNUNET_asprintf (&buf, "TOTAL_NSE_CROSS_%d: %u \n", stats_context->shutdown, stats_context->total_nse_cross); if (buf_len > 0) { GNUNET_DISK_file_write (data_file, buf, buf_len); } GNUNET_free_non_null (buf); buf = NULL; buf_len = GNUNET_asprintf (&buf, "TOTAL_NSE_EXTRA_%d: %u \n", stats_context->shutdown, stats_context->total_nse_extra); if (buf_len > 0) { GNUNET_DISK_file_write (data_file, buf, buf_len); } GNUNET_free_non_null (buf); buf = NULL; buf_len = GNUNET_asprintf (&buf, "TOTAL_NSE_DISCARDED_%d: %u \n", stats_context->shutdown, stats_context->total_discarded); if (buf_len > 0) { GNUNET_DISK_file_write (data_file, buf, buf_len); } GNUNET_free_non_null (buf); } if (GNUNET_YES == stats_context->shutdown) { GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == shutdown_handle); shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); } else { GNUNET_assert (churn_task == GNUNET_SCHEDULER_NO_TASK); churn_task = GNUNET_SCHEDULER_add_now (&churn_peers, NULL); } GNUNET_free (stats_context); } /** * Callback function to process statistic values. * * @param cls struct StatsContext * @param peer the peer the statistics belong to * @param subsystem name of subsystem that created the statistic * @param name the name of the datum * @param value the current value * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration */ static int statistics_iterator (void *cls, const struct GNUNET_PeerIdentity *peer, const char *subsystem, const char *name, uint64_t value, int is_persistent) { struct StatsContext *stats_context = cls; if (0 == strcmp (subsystem, "nse")) { if (0 == strcmp (name, "# flood messages received")) { stats_context->total_nse_received_messages += value; #if VERBOSE if (data_file != NULL) { char *buf; int buf_len; buf = NULL; buf_len = GNUNET_asprintf (&buf, "%s %u RECEIVED\n", GNUNET_i2s(peer), value); if (buf_len > 0) { GNUNET_DISK_file_write (data_file, buf, buf_len); } GNUNET_free_non_null (buf); } #endif } if (0 == strcmp (name, "# flood messages transmitted")) { stats_context->total_nse_transmitted_messages += value; #if VERBOSE if (data_file != NULL) { char *buf; int buf_len; buf = NULL; buf_len = GNUNET_asprintf (&buf, "%s %u TRANSMITTED\n", GNUNET_i2s(peer), value); if (buf_len > 0) { GNUNET_DISK_file_write (data_file, buf, buf_len); } GNUNET_free_non_null (buf); } #endif } if (0 == strcmp (name, "# cross messages")) { stats_context->total_nse_cross += value; } if (0 == strcmp (name, "# extra messages")) { stats_context->total_nse_extra += value; } if (0 == strcmp (name, "# flood messages discarded (clock skew too large)")) { stats_context->total_discarded += value; } } return GNUNET_OK; } static void disconnect_nse_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct NSEPeer *pos; char *buf; struct StatsContext *stats_context; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnecting nse service of peers\n"); disconnect_task = GNUNET_SCHEDULER_NO_TASK; while (NULL != (pos = peer_head)) { if (pos->nse_handle != NULL) { GNUNET_NSE_disconnect (pos->nse_handle); pos->nse_handle = NULL; } GNUNET_CONTAINER_DLL_remove (peer_head, peer_tail, pos); if (NULL != pos->stats) GNUNET_STATISTICS_destroy(pos->stats, GNUNET_NO); if (GNUNET_SCHEDULER_NO_TASK != pos->stats_task) GNUNET_SCHEDULER_cancel (pos->stats_task); GNUNET_free (pos); } GNUNET_asprintf (&buf, "round%llu", current_round); if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (testing_cfg, "nse-profiler", buf, &peers_next_round)) { current_round++; if (current_round == 1) { stats_context = GNUNET_malloc (sizeof (struct StatsContext)); stats_context->shutdown = GNUNET_NO; GNUNET_TESTING_get_statistics (pg, &stats_finished_callback, &statistics_iterator, stats_context); } else { GNUNET_assert (churn_task == GNUNET_SCHEDULER_NO_TASK); churn_task = GNUNET_SCHEDULER_add_now (&churn_peers, NULL); } } else /* No more rounds, let's shut it down! */ { stats_context = GNUNET_malloc (sizeof (struct StatsContext)); stats_context->shutdown = GNUNET_YES; GNUNET_SCHEDULER_cancel (shutdown_handle); shutdown_handle = GNUNET_SCHEDULER_NO_TASK; GNUNET_TESTING_get_statistics (pg, &stats_finished_callback, &statistics_iterator, stats_context); } GNUNET_free (buf); } /** * FIXME. * * @param cls unused * @param emsg NULL on success */ static void topology_output_callback (void *cls, const char *emsg) { disconnect_task = GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_nse_peers, NULL); GNUNET_SCHEDULER_add_now (&connect_nse_service, NULL); } /** * FIXME. * * @param cls closure * @param emsg NULL on success */ static void churn_callback (void *cls, const char *emsg) { char *temp_output_file; if (emsg == NULL) /* Everything is okay! */ { peers_running = peers_next_round; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Round %llu, churn finished successfully.\n", current_round); GNUNET_assert (disconnect_task == GNUNET_SCHEDULER_NO_TASK); GNUNET_asprintf (&temp_output_file, "%s_%llu.dot", topology_file, current_round); GNUNET_TESTING_peergroup_topology_to_file (pg, temp_output_file, &topology_output_callback, NULL); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Writing topology to file %s\n", temp_output_file); GNUNET_free (temp_output_file); } else { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Round %llu, churn FAILED!!\n", current_round); GNUNET_SCHEDULER_cancel (shutdown_handle); shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); } } static void churn_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { /* peers_running = GNUNET_TESTING_daemons_running(pg); */ churn_task = GNUNET_SCHEDULER_NO_TASK; if (peers_next_round == peers_running) { /* Nothing to do... */ GNUNET_SCHEDULER_add_now (&connect_nse_service, NULL); GNUNET_assert (disconnect_task == GNUNET_SCHEDULER_NO_TASK); disconnect_task = GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_nse_peers, NULL); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Round %lu, doing nothing!\n", current_round); } else { if (peers_next_round > num_peers) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Asked to turn on more peers than we have!!\n"); GNUNET_SCHEDULER_cancel (shutdown_handle); GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); } GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Round %llu, turning off %llu peers, turning on %llu peers!\n", current_round, (peers_running > peers_next_round) ? peers_running - peers_next_round : 0, (peers_next_round > peers_running) ? peers_next_round - peers_running : 0); GNUNET_TESTING_daemons_churn (pg, "nse", (peers_running > peers_next_round) ? peers_running - peers_next_round : 0, (peers_next_round > peers_running) ? peers_next_round - peers_running : 0, wait_time, &churn_callback, NULL); } } static void nse_started_cb (void *cls, const char *emsg) { GNUNET_SCHEDULER_add_now (&connect_nse_service, NULL); disconnect_task = GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_nse_peers, NULL); } static void my_cb (void *cls, const char *emsg) { char *buf; int buf_len; if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peergroup callback called with error, aborting test!\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n"); ok = 1; GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); return; } #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer Group started successfully, connecting to NSE service for each peer!\n"); #endif GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Have %u connections\n", total_connections); if (data_file != NULL) { buf = NULL; buf_len = GNUNET_asprintf (&buf, "CONNECTIONS_0: %u\n", total_connections); if (buf_len > 0) GNUNET_DISK_file_write (data_file, buf, buf_len); GNUNET_free (buf); } peers_running = GNUNET_TESTING_daemons_running (pg); GNUNET_TESTING_daemons_start_service (pg, "nse", wait_time, &nse_started_cb, NULL); } /** * Function that will be called whenever two daemons are connected by * the testing library. * * @param cls closure * @param first peer id for first daemon * @param second peer id for the second daemon * @param distance distance between the connected peers * @param first_cfg config for the first daemon * @param second_cfg config for the second daemon * @param first_daemon handle for the first daemon * @param second_daemon handle for the second daemon * @param emsg error message (NULL on success) */ static void connect_cb (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, uint32_t distance, const struct GNUNET_CONFIGURATION_Handle *first_cfg, const struct GNUNET_CONFIGURATION_Handle *second_cfg, struct GNUNET_TESTING_Daemon *first_daemon, struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) { if (emsg == NULL) total_connections++; } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { char *temp_str; struct GNUNET_TESTING_Host *hosts; char *data_filename; ok = 1; //testing_cfg = GNUNET_CONFIGURATION_create (); testing_cfg = GNUNET_CONFIGURATION_dup (cfg); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", "use_progressbars", "YES"); #endif if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing", "num_peers", &num_peers)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Option TESTING:NUM_PEERS is required!\n"); return; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (testing_cfg, "nse-profiler", "WAIT_TIME", &wait_time)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Option nse-profiler:wait_time is required!\n"); return; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (testing_cfg, "nse", "INTERVAL", &interval)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Option nse:interval is required!\n"); return; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (testing_cfg, "nse-profiler", "connection_limit", &connection_limit)) { connection_limit = 0; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (testing_cfg, "nse-profiler", "topology_output_file", &topology_file)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Option nse-profiler:topology_output_file is required!\n"); return; } if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (testing_cfg, "nse-profiler", "data_output_file", &data_filename)) { data_file = GNUNET_DISK_file_open (data_filename, GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_TRUNCATE | GNUNET_DISK_OPEN_CREATE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (data_file == NULL) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n", data_filename); GNUNET_free (data_filename); } if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "nse-profiler", "output_file", &temp_str)) { output_file = GNUNET_DISK_file_open (temp_str, GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_CREATE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (output_file == NULL) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n", temp_str); } GNUNET_free_non_null (temp_str); hosts = GNUNET_TESTING_hosts_load (testing_cfg); pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT, &connect_cb, &my_cb, NULL, hosts); GNUNET_assert (pg != NULL); shutdown_handle = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); } /** * nse-profiler command line options */ static struct GNUNET_GETOPT_CommandLineOption options[] = { {'V', "verbose", NULL, gettext_noop ("be verbose (print progress information)"), 0, &GNUNET_GETOPT_set_one, &verbose}, GNUNET_GETOPT_OPTION_END }; int main (int argc, char *argv[]) { GNUNET_log_setup ("nse-profiler", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_PROGRAM_run (argc, argv, "nse-profiler", gettext_noop ("Measure quality and performance of the NSE service."), options, &run, NULL); #if REMOVE_DIR GNUNET_DISK_directory_remove ("/tmp/nse-profiler"); #endif return ok; } /* end of nse-profiler.c */ gnunet-0.9.3/src/nse/test_nse.conf0000644000175000017500000000252211661530124014013 00000000000000[PATHS] SERVICEHOME = /tmp/test-nse-multipeer/ DEFAULTCONFIG = test_nse.conf [nse] PORT = 22353 UNIXPATH = /tmp/test-nse-service-nse.unix BINARY = gnunet-service-nse #BINARY = /home/mrwiggles/documents/research/gnunet/gnunet-ng/src/nse/.libs/gnunet-service-nse #PREFIX = valgrind --leak-check=full --log-file=valgrind_nse.%p AUTOSTART = YES DEBUG = NO CONFIG = $DEFAULTCONFIG PROOFFILE = $SERVICEHOME/proof.nse # Overriding network settings for faster testing (do NOT use # these values in production just because they are here) WORKDELAY = 1 ms INTERVAL = 60 s WORKBITS = 1 HISTOGRAM = $SERVICEHOME/nse-histogram [arm] PORT = 22354 DEFAULTSERVICES = nse core UNIXPATH = /tmp/test-nse-service-arm.unix #DEBUG = YES [fs] AUTOSTART = NO [datastore] AUTOSTART = NO [dht] AUTOSTART = NO [transport] AUTOSTART = YES [core] AUTOSTART = YES [peerinfo] AUTOSTART = YES [nat] DISABLEV6 = YES BINDTO = 127.0.0.1 ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 [dns] AUTOSTART = NO [testing] NUM_PEERS = 10 WEAKRANDOM = YES TOPOLOGY = NONE CONNECT_TOPOLOGY = SMALL_WORLD_RING PERCENTAGE = 3 F2F = NO CONNECT_TIMEOUT = 60 s CONNECT_ATTEMPTS = 3 #DEBUG = YES HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat MAX_CONCURRENT_SSH = 20 USE_PROGRESSBARS = YES PEERGROUP_TIMEOUT = 1000 s DELETE_FILES = NO gnunet-0.9.3/src/nse/test_nse_multipeer.c0000644000175000017500000001656111760502551015411 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file nse/test_nse_multipeer.c * * @brief Testcase for the network size estimation service. Starts * a peergroup with a given number of peers, then waits to * receive size estimates from each peer. Expects to wait * for one message from each peer. */ #include "platform.h" #include "gnunet_testing_lib.h" #include "gnunet_nse_service.h" #define VERBOSE GNUNET_NO #define NUM_PEERS 4 struct NSEPeer { struct NSEPeer *prev; struct NSEPeer *next; struct GNUNET_TESTING_Daemon *daemon; struct GNUNET_NSE_Handle *nse_handle; }; struct NSEPeer *peer_head; struct NSEPeer *peer_tail; /** * How long do we run the test? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) static int ok; static int peers_left; static unsigned int num_peers; static unsigned int total_connections; static struct GNUNET_TESTING_PeerGroup *pg; /** * Check whether peers successfully shut down. */ static void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed: %s!\n", emsg); #endif if (ok == 0) ok = 666; } else { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); #endif ok = 0; } } static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct NSEPeer *pos; #if VERBOSE FPRINTF (stderr, "%s", "Ending test.\n"); #endif while (NULL != (pos = peer_head)) { GNUNET_NSE_disconnect (pos->nse_handle); GNUNET_CONTAINER_DLL_remove (peer_head, peer_tail, pos); GNUNET_free (pos); } GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); } /** * Callback to call when network size estimate is updated. * * @param cls closure * @param timestamp server timestamp * @param estimate the value of the current network size estimate * @param std_dev standard deviation (rounded down to nearest integer) * of the size estimation values seen * */ static void handle_estimate (void *cls, struct GNUNET_TIME_Absolute timestamp, double estimate, double std_dev) { struct NSEPeer *peer = cls; FPRINTF (stderr, "Received network size estimate from peer %s. logSize: %f std.dev. %f (%f/%u)\n", GNUNET_i2s (&peer->daemon->id), estimate, std_dev, GNUNET_NSE_log_estimate_to_n (estimate), num_peers); } static void connect_nse_service (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct NSEPeer *current_peer; unsigned int i; #if VERBOSE FPRINTF (stderr, "%s", "TEST_NSE_MULTIPEER: connecting to nse service of peers\n"); #endif for (i = 0; i < num_peers; i++) { current_peer = GNUNET_malloc (sizeof (struct NSEPeer)); current_peer->daemon = GNUNET_TESTING_daemon_get (pg, i); current_peer->nse_handle = GNUNET_NSE_connect (current_peer->daemon->cfg, &handle_estimate, current_peer); GNUNET_assert (current_peer->nse_handle != NULL); GNUNET_CONTAINER_DLL_insert (peer_head, peer_tail, current_peer); } } static void my_cb (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peergroup callback called with error, aborting test!\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n"); ok = 1; GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); return; } #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer Group started successfully, connecting to NSE service for each peer!\n"); #endif GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Have %u connections\n", total_connections); GNUNET_SCHEDULER_add_now (&connect_nse_service, NULL); } /** * Function that will be called whenever * two daemons are connected by the testing library. * * @param cls closure * @param first peer id for first daemon * @param second peer id for the second daemon * @param distance distance between the connected peers * @param first_cfg config for the first daemon * @param second_cfg config for the second daemon * @param first_daemon handle for the first daemon * @param second_daemon handle for the second daemon * @param emsg error message (NULL on success) */ static void connect_cb (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, uint32_t distance, const struct GNUNET_CONFIGURATION_Handle *first_cfg, const struct GNUNET_CONFIGURATION_Handle *second_cfg, struct GNUNET_TESTING_Daemon *first_daemon, struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) { if (emsg == NULL) { //fprintf(stderr, "Connected %s -> %s\n", GNUNET_i2s(first), second_id); total_connections++; } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_CONFIGURATION_Handle *testing_cfg; unsigned long long total_peers; ok = 1; testing_cfg = GNUNET_CONFIGURATION_create (); GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (testing_cfg, cfgfile)); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", "use_progressbars", "YES"); #endif if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing", "num_peers", &total_peers)) total_peers = NUM_PEERS; peers_left = total_peers; num_peers = peers_left; pg = GNUNET_TESTING_peergroup_start (testing_cfg, peers_left, TIMEOUT, &connect_cb, &my_cb, NULL, NULL); GNUNET_assert (pg != NULL); GNUNET_SCHEDULER_add_delayed (TIMEOUT, &shutdown_task, NULL); } static int check () { char *const argv[] = { "test-nse-multipeer", "-c", "test_nse.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-nse-multipeer", "nohelp", options, &run, &ok); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-nse-multipeer", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); // GNUNET_DISK_directory_remove ("/tmp/test-nse-multipeer"); return ret; } /* end of test_nse_multipeer.c */ gnunet-0.9.3/src/nse/nse_api.c0000644000175000017500000001712211760502551013107 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file nse/nse_api.c * @brief api to get information from the network size estimation service * @author Nathan Evans */ #include "platform.h" #include "gnunet_client_lib.h" #include "gnunet_constants.h" #include "gnunet_container_lib.h" #include "gnunet_arm_service.h" #include "gnunet_hello_lib.h" #include "gnunet_protocols.h" #include "gnunet_server_lib.h" #include "gnunet_time_lib.h" #include "gnunet_nse_service.h" #include "nse.h" #define LOG(kind,...) GNUNET_log_from (kind, "nse-api",__VA_ARGS__) /** * Handle for the service. */ struct GNUNET_NSE_Handle { /** * Configuration to use. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Socket (if available). */ struct GNUNET_CLIENT_Connection *client; /** * Currently pending transmission request. */ struct GNUNET_CLIENT_TransmitHandle *th; /** * Task doing exponential back-off trying to reconnect. */ GNUNET_SCHEDULER_TaskIdentifier reconnect_task; /** * Time for next connect retry. */ struct GNUNET_TIME_Relative reconnect_delay; /** * Callback function to call when message is received. */ GNUNET_NSE_Callback recv_cb; /** * Closure to pass to callback. */ void *recv_cb_cls; }; /** * Try again to connect to network size estimation service. * * @param cls the handle to the transport service * @param tc scheduler context */ static void reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Type of a function to call when we receive a message * from the service. * * @param cls closure * @param msg message received, NULL on timeout or fatal error */ static void message_handler (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_NSE_Handle *h = cls; const struct GNUNET_NSE_ClientMessage *client_msg; if (msg == NULL) { /* Error, timeout, death */ GNUNET_CLIENT_disconnect (h->client); h->client = NULL; h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h); return; } if ((ntohs (msg->size) != sizeof (struct GNUNET_NSE_ClientMessage)) || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_NSE_ESTIMATE)) { GNUNET_break (0); return; } client_msg = (const struct GNUNET_NSE_ClientMessage *) msg; h->recv_cb (h->recv_cb_cls, GNUNET_TIME_absolute_ntoh (client_msg->timestamp), GNUNET_ntoh_double (client_msg->size_estimate), GNUNET_ntoh_double (client_msg->std_deviation)); GNUNET_CLIENT_receive (h->client, &message_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); } /** * Reschedule a connect attempt to the service. * * @param h transport service to reconnect */ static void reschedule_connect (struct GNUNET_NSE_Handle *h) { GNUNET_assert (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK); if (NULL != h->th) { GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); h->th = NULL; } if (NULL != h->client) { GNUNET_CLIENT_disconnect (h->client); h->client = NULL; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Scheduling task to reconnect to nse service in %llu ms.\n", h->reconnect_delay.rel_value); h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h); if (h->reconnect_delay.rel_value == 0) { h->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; } else { h->reconnect_delay = GNUNET_TIME_relative_multiply (h->reconnect_delay, 2); h->reconnect_delay = GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS, h->reconnect_delay); } } /** * Transmit START message to service. * * @param cls unused * @param size number of bytes available in buf * @param buf where to copy the message * @return number of bytes copied to buf */ static size_t send_start (void *cls, size_t size, void *buf) { struct GNUNET_NSE_Handle *h = cls; struct GNUNET_MessageHeader *msg; h->th = NULL; if (buf == NULL) { /* Connect error... */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutdown while trying to transmit `%s' request.\n", "START"); reschedule_connect (h); return 0; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' request.\n", "START"); GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); msg = (struct GNUNET_MessageHeader *) buf; msg->size = htons (sizeof (struct GNUNET_MessageHeader)); msg->type = htons (GNUNET_MESSAGE_TYPE_NSE_START); GNUNET_CLIENT_receive (h->client, &message_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); return sizeof (struct GNUNET_MessageHeader); } /** * Try again to connect to network size estimation service. * * @param cls the handle to the transport service * @param tc scheduler context */ static void reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_NSE_Handle *h = cls; h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) { /* shutdown, just give up */ return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to network size estimation service.\n"); GNUNET_assert (h->client == NULL); h->client = GNUNET_CLIENT_connect ("nse", h->cfg); GNUNET_assert (h->client != NULL); h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, sizeof (struct GNUNET_MessageHeader), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_NO, &send_start, h); GNUNET_assert (h->th != NULL); } /** * Connect to the network size estimation service. * * @param cfg the configuration to use * @param func funtion to call with network size estimate * @param func_cls closure to pass for network size estimate callback * * @return handle to use */ struct GNUNET_NSE_Handle * GNUNET_NSE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_NSE_Callback func, void *func_cls) { struct GNUNET_NSE_Handle *ret; GNUNET_assert (func != NULL); ret = GNUNET_malloc (sizeof (struct GNUNET_NSE_Handle)); ret->cfg = cfg; ret->recv_cb = func; ret->recv_cb_cls = func_cls; ret->reconnect_delay = GNUNET_TIME_UNIT_ZERO; ret->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, ret); return ret; } /** * Disconnect from network size estimation service * * @param h handle to destroy */ void GNUNET_NSE_disconnect (struct GNUNET_NSE_Handle *h) { GNUNET_assert (h != NULL); if (h->reconnect_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (h->reconnect_task); h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; } if (h->th != NULL) { GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); h->th = NULL; } if (h->client != NULL) { GNUNET_CLIENT_disconnect (h->client); h->client = NULL; } GNUNET_free (h); } /* end of nse_api.c */ gnunet-0.9.3/src/nse/nse.h0000644000175000017500000000362711760502551012270 00000000000000/* This file is part of GNUnet. (C) 2001-2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @author Nathan Evans * @file nse/nse.h * * @brief Common type definitions for the network size estimation * service and API. */ #ifndef NSE_H #define NSE_H #include "gnunet_common.h" /** * Generate debug-level log messages? */ #define DEBUG_NSE GNUNET_EXTRA_LOGGING GNUNET_NETWORK_STRUCT_BEGIN /** * Network size estimate sent from the service * to clients. Contains the current size estimate * (or 0 if none has been calculated) and the * standard deviation of known estimates. * */ struct GNUNET_NSE_ClientMessage { /** * Type: GNUNET_MESSAGE_TYPE_NSE_ESTIMATE */ struct GNUNET_MessageHeader header; /** * For alignment. */ uint32_t reserved GNUNET_PACKED; /** * Timestamp at which the server received the message. */ struct GNUNET_TIME_AbsoluteNBO timestamp; /** * The current estimated network size. */ double size_estimate GNUNET_PACKED; /** * The standard deviation (rounded down * to the nearest integer) of size * estimations. */ double std_deviation GNUNET_PACKED; }; GNUNET_NETWORK_STRUCT_END #endif gnunet-0.9.3/src/nse/gnunet-service-nse.c0000644000175000017500000012754711760502551015227 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file nse/gnunet-service-nse.c * @brief network size estimation service * @author Nathan Evans * @author Christian Grothoff * * The purpose of this service is to estimate the size of the network. * Given a specified interval, each peer hashes the most recent * timestamp which is evenly divisible by that interval. This hash is * compared in distance to the peer identity to choose an offset. The * closer the peer identity to the hashed timestamp, the earlier the * peer sends out a "nearest peer" message. The closest peer's * message should thus be received before any others, which stops * those peer from sending their messages at a later duration. So * every peer should receive the same nearest peer message, and from * this can calculate the expected number of peers in the network. */ #include "platform.h" #include #include "gnunet_util_lib.h" #include "gnunet_constants.h" #include "gnunet_protocols.h" #include "gnunet_signatures.h" #include "gnunet_statistics_service.h" #include "gnunet_core_service.h" #include "gnunet_nse_service.h" #include "nse.h" /** * Should messages be delayed randomly? This option should be set to * GNUNET_NO only for experiments, not in production. It should also * be removed once the initial experiments have been completed. */ #define USE_RANDOM_DELAYS GNUNET_YES /** * Should we generate a histogram with the time stamps of when we received * NSE messages to disk? (for performance evaluation only, not useful in * production). The associated code should also probably be removed * once we're done with experiments. */ #define ENABLE_HISTOGRAM GNUNET_NO /** * Over how many values do we calculate the weighted average? */ #define HISTORY_SIZE 64 /** * Message priority to use. */ #define NSE_PRIORITY 5 #if FREEBSD #define log2(a) (log(a)/log(2)) #endif /** * Amount of work required (W-bit collisions) for NSE proofs, in collision-bits. */ static unsigned long long nse_work_required; /** * Interval for sending network size estimation flood requests. */ static struct GNUNET_TIME_Relative gnunet_nse_interval; /** * Interval between proof find runs. */ static struct GNUNET_TIME_Relative proof_find_delay; #if ENABLE_HISTOGRAM /** * Handle for writing when we received messages to disk. */ static struct GNUNET_BIO_WriteHandle *wh; #endif /** * Per-peer information. */ struct NSEPeerEntry { /** * Core handle for sending messages to this peer. */ struct GNUNET_CORE_TransmitHandle *th; /** * What is the identity of the peer? */ struct GNUNET_PeerIdentity id; /** * Task scheduled to send message to this peer. */ GNUNET_SCHEDULER_TaskIdentifier transmit_task; /** * Did we receive or send a message about the previous round * to this peer yet? GNUNET_YES if the previous round has * been taken care of. */ int previous_round; #if ENABLE_HISTOGRAM /** * Amount of messages received from this peer on this round. */ unsigned int received_messages; /** * Amount of messages transmitted to this peer on this round. */ unsigned int transmitted_messages; /** * Which size did we tell the peer the network is? */ unsigned int last_transmitted_size; #endif }; GNUNET_NETWORK_STRUCT_BEGIN /** * Network size estimate reply; sent when "this" * peer's timer has run out before receiving a * valid reply from another peer. */ struct GNUNET_NSE_FloodMessage { /** * Type: GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD */ struct GNUNET_MessageHeader header; /** * Number of hops this message has taken so far. */ uint32_t hop_count GNUNET_PACKED; /** * Purpose. */ struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; /** * The current timestamp value (which all * peers should agree on). */ struct GNUNET_TIME_AbsoluteNBO timestamp; /** * Number of matching bits between the hash * of timestamp and the initiator's public * key. */ uint32_t matching_bits GNUNET_PACKED; /** * Public key of the originator. */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; /** * Proof of work, causing leading zeros when hashed with pkey. */ uint64_t proof_of_work GNUNET_PACKED; /** * Signature (over range specified in purpose). */ struct GNUNET_CRYPTO_RsaSignature signature; }; GNUNET_NETWORK_STRUCT_END /** * Handle to our current configuration. */ static const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Handle to the statistics service. */ static struct GNUNET_STATISTICS_Handle *stats; /** * Handle to the core service. */ static struct GNUNET_CORE_Handle *coreAPI; /** * Map of all connected peers. */ static struct GNUNET_CONTAINER_MultiHashMap *peers; /** * The current network size estimate. Number of bits matching on * average thus far. */ static double current_size_estimate; /** * The standard deviation of the last HISTORY_SIZE network * size estimates. */ static double current_std_dev = NAN; /** * Current hop counter estimate (estimate for network diameter). */ static uint32_t hop_count_max; /** * Message for the next round, if we got any. */ static struct GNUNET_NSE_FloodMessage next_message; /** * Array of recent size estimate messages. */ static struct GNUNET_NSE_FloodMessage size_estimate_messages[HISTORY_SIZE]; /** * Index of most recent estimate. */ static unsigned int estimate_index; /** * Number of valid entries in the history. */ static unsigned int estimate_count; /** * Task scheduled to update our flood message for the next round. */ static GNUNET_SCHEDULER_TaskIdentifier flood_task; /** * Task scheduled to compute our proof. */ static GNUNET_SCHEDULER_TaskIdentifier proof_task; /** * Notification context, simplifies client broadcasts. */ static struct GNUNET_SERVER_NotificationContext *nc; /** * The next major time. */ static struct GNUNET_TIME_Absolute next_timestamp; /** * The current major time. */ static struct GNUNET_TIME_Absolute current_timestamp; /** * The public key of this peer. */ static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; /** * The private key of this peer. */ static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; /** * The peer identity of this peer. */ static struct GNUNET_PeerIdentity my_identity; /** * Proof of work for this peer. */ static uint64_t my_proof; /** * Initialize a message to clients with the current network * size estimate. * * @param em message to fill in */ static void setup_estimate_message (struct GNUNET_NSE_ClientMessage *em) { unsigned int i; unsigned int j; double mean; double sum; double std_dev; double variance; double val; double nsize; #define WEST 1 /* Weighted incremental algorithm for stddev according to West (1979) */ #if WEST double sumweight; double weight; double q; double r; double temp; mean = 0.0; sum = 0.0; sumweight = 0.0; variance = 0.0; for (i = 0; i < estimate_count; i++) { j = (estimate_index - i + HISTORY_SIZE) % HISTORY_SIZE; val = htonl (size_estimate_messages[j].matching_bits); weight = estimate_count + 1 - i; temp = weight + sumweight; q = val - mean; r = q * weight / temp; mean += r; sum += sumweight * q * r; sumweight = temp; } if (estimate_count > 0) variance = (sum / sumweight) * estimate_count / (estimate_count - 1.0); #else /* trivial version for debugging */ double vsq; /* non-weighted trivial version */ sum = 0.0; vsq = 0.0; variance = 0.0; mean = 0.0; for (i = 0; i < estimate_count; i++) { j = (estimate_index - i + HISTORY_SIZE) % HISTORY_SIZE; val = htonl (size_estimate_messages[j].matching_bits); sum += val; vsq += val * val; } if (0 != estimate_count) { mean = sum / estimate_count; variance = (vsq - mean * sum) / (estimate_count - 1.0); // terrible for numerical stability... } #endif if (variance >= 0) std_dev = sqrt (variance); else std_dev = variance; /* must be infinity due to estimate_count == 0 */ current_std_dev = std_dev; current_size_estimate = mean; em->header.size = htons (sizeof (struct GNUNET_NSE_ClientMessage)); em->header.type = htons (GNUNET_MESSAGE_TYPE_NSE_ESTIMATE); em->reserved = htonl (0); em->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); double se = mean - 0.332747; nsize = log2 (GNUNET_CONTAINER_multihashmap_size (peers) + 1); em->size_estimate = GNUNET_hton_double (GNUNET_MAX (se, nsize)); em->std_deviation = GNUNET_hton_double (std_dev); GNUNET_STATISTICS_set (stats, "# nodes in the network (estimate)", (uint64_t) pow (2, mean - 1.0 / 3.0), GNUNET_NO); } /** * Handler for START message from client, triggers an * immediate current network estimate notification. * Also, we remember the client for updates upon future * estimate measurements. * * @param cls unused * @param client who sent the message * @param message the message received */ static void handle_start_message (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct GNUNET_NSE_ClientMessage em; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received START message from client\n"); GNUNET_SERVER_notification_context_add (nc, client); setup_estimate_message (&em); GNUNET_SERVER_notification_context_unicast (nc, client, &em.header, GNUNET_YES); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * How long should we delay a message to go the given number of * matching bits? * * @param matching_bits number of matching bits to consider */ static double get_matching_bits_delay (uint32_t matching_bits) { /* Calculated as: S + f/2 - (f / pi) * (atan(x - p')) */ // S is next_timestamp (ignored in return value) // f is frequency (gnunet_nse_interval) // x is matching_bits // p' is current_size_estimate return ((double) gnunet_nse_interval.rel_value / (double) 2.0) - ((gnunet_nse_interval.rel_value / M_PI) * atan (matching_bits - current_size_estimate)); } /** * What delay randomization should we apply for a given number of matching bits? * * @param matching_bits number of matching bits * @return random delay to apply */ static struct GNUNET_TIME_Relative get_delay_randomization (uint32_t matching_bits) { #if USE_RANDOM_DELAYS struct GNUNET_TIME_Relative ret; uint32_t i; double d; d = get_matching_bits_delay (matching_bits); i = (uint32_t) (d / (double) (hop_count_max + 1)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Randomizing flood using latencies up to %u ms\n", (unsigned int) i); ret.rel_value = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, i + 1); return ret; #else return GNUNET_TIME_UNIT_ZERO; #endif } /** * Get the number of matching bits that the given timestamp has to the given peer ID. * * @param timestamp time to generate key * @param id peer identity to compare with * @return number of matching bits */ static uint32_t get_matching_bits (struct GNUNET_TIME_Absolute timestamp, const struct GNUNET_PeerIdentity *id) { GNUNET_HashCode timestamp_hash; GNUNET_CRYPTO_hash (×tamp.abs_value, sizeof (timestamp.abs_value), ×tamp_hash); return GNUNET_CRYPTO_hash_matching_bits (×tamp_hash, &id->hashPubKey); } /** * Get the transmission delay that should be applied for a * particular round. * * @param round_offset -1 for the previous round (random delay between 0 and 50ms) * 0 for the current round (based on our proximity to time key) * @return delay that should be applied */ static struct GNUNET_TIME_Relative get_transmit_delay (int round_offset) { struct GNUNET_TIME_Relative ret; struct GNUNET_TIME_Absolute tgt; double dist_delay; uint32_t matching_bits; switch (round_offset) { case -1: /* previous round is randomized between 0 and 50 ms */ #if USE_RANDOM_DELAYS ret.rel_value = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, 50); #else ret = GNUNET_TIME_UNIT_ZERO; #endif GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting previous round behind schedule in %llu ms\n", (unsigned long long) ret.rel_value); return ret; case 0: /* current round is based on best-known matching_bits */ matching_bits = ntohl (size_estimate_messages[estimate_index].matching_bits); dist_delay = get_matching_bits_delay (matching_bits); dist_delay += get_delay_randomization (matching_bits).rel_value; ret.rel_value = (uint64_t) dist_delay; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "For round %llu, delay for %u matching bits is %llu ms\n", (unsigned long long) current_timestamp.abs_value, (unsigned int) matching_bits, (unsigned long long) ret.rel_value); /* now consider round start time and add delay to it */ tgt = GNUNET_TIME_absolute_add (current_timestamp, ret); return GNUNET_TIME_absolute_get_remaining (tgt); } GNUNET_break (0); return GNUNET_TIME_UNIT_FOREVER_REL; } /** * Task that triggers a NSE P2P transmission. * * @param cls the 'struct NSEPeerEntry' * @param tc scheduler context */ static void transmit_task_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Called when core is ready to send a message we asked for * out to the destination. * * @param cls closure (NULL) * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_ready (void *cls, size_t size, void *buf) { struct NSEPeerEntry *peer_entry = cls; unsigned int idx; peer_entry->th = NULL; if (NULL == buf) { /* client disconnected */ return 0; } GNUNET_assert (size >= sizeof (struct GNUNET_NSE_FloodMessage)); idx = estimate_index; if (GNUNET_NO == peer_entry->previous_round) { idx = (idx + HISTORY_SIZE - 1) % HISTORY_SIZE; peer_entry->previous_round = GNUNET_YES; peer_entry->transmit_task = GNUNET_SCHEDULER_add_delayed (get_transmit_delay (0), &transmit_task_cb, peer_entry); } if ((ntohl (size_estimate_messages[idx].hop_count) == 0) && (GNUNET_SCHEDULER_NO_TASK != proof_task)) { GNUNET_STATISTICS_update (stats, "# flood messages not generated (no proof yet)", 1, GNUNET_NO); return 0; } if (ntohs (size_estimate_messages[idx].header.size) == 0) { GNUNET_STATISTICS_update (stats, "# flood messages not generated (lack of history)", 1, GNUNET_NO); return 0; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "In round %llu, sending to `%s' estimate with %u bits\n", (unsigned long long) GNUNET_TIME_absolute_ntoh (size_estimate_messages[idx]. timestamp).abs_value, GNUNET_i2s (&peer_entry->id), (unsigned int) ntohl (size_estimate_messages[idx].matching_bits)); if (ntohl (size_estimate_messages[idx].hop_count) == 0) GNUNET_STATISTICS_update (stats, "# flood messages started", 1, GNUNET_NO); GNUNET_STATISTICS_update (stats, "# flood messages transmitted", 1, GNUNET_NO); #if ENABLE_HISTOGRAM peer_entry->transmitted_messages++; peer_entry->last_transmitted_size = ntohl(size_estimate_messages[idx].matching_bits); #endif memcpy (buf, &size_estimate_messages[idx], sizeof (struct GNUNET_NSE_FloodMessage)); return sizeof (struct GNUNET_NSE_FloodMessage); } /** * Task that triggers a NSE P2P transmission. * * @param cls the 'struct NSEPeerEntry' * @param tc scheduler context */ static void transmit_task_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct NSEPeerEntry *peer_entry = cls; peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_assert (NULL == peer_entry->th); peer_entry->th = GNUNET_CORE_notify_transmit_ready (coreAPI, GNUNET_NO, NSE_PRIORITY, GNUNET_TIME_UNIT_FOREVER_REL, &peer_entry->id, sizeof (struct GNUNET_NSE_FloodMessage), &transmit_ready, peer_entry); } /** * We've sent on our flood message or one that we received which was * validated and closer than ours. Update the global list of recent * messages and the average. Also re-broadcast the message to any * clients. */ static void update_network_size_estimate () { struct GNUNET_NSE_ClientMessage em; setup_estimate_message (&em); GNUNET_SERVER_notification_context_broadcast (nc, &em.header, GNUNET_YES); } /** * Setup a flood message in our history array at the given * slot offset for the given timestamp. * * @param slot index to use * @param ts timestamp to use */ static void setup_flood_message (unsigned int slot, struct GNUNET_TIME_Absolute ts) { struct GNUNET_NSE_FloodMessage *fm; uint32_t matching_bits; matching_bits = get_matching_bits (ts, &my_identity); fm = &size_estimate_messages[slot]; fm->header.size = htons (sizeof (struct GNUNET_NSE_FloodMessage)); fm->header.type = htons (GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD); fm->hop_count = htonl (0); fm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_NSE_SEND); fm->purpose.size = htonl (sizeof (struct GNUNET_NSE_FloodMessage) - sizeof (struct GNUNET_MessageHeader) - sizeof (uint32_t) - sizeof (struct GNUNET_CRYPTO_RsaSignature)); fm->matching_bits = htonl (matching_bits); fm->timestamp = GNUNET_TIME_absolute_hton (ts); fm->pkey = my_public_key; fm->proof_of_work = my_proof; if (nse_work_required > 0) GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_rsa_sign (my_private_key, &fm->purpose, &fm->signature)); else memset (&fm->signature, 0, sizeof (fm->signature)); } /** * Schedule transmission for the given peer for the current round based * on what we know about the desired delay. * * @param cls unused * @param key hash of peer identity * @param value the 'struct NSEPeerEntry' * @return GNUNET_OK (continue to iterate) */ static int schedule_current_round (void *cls, const GNUNET_HashCode * key, void *value) { struct NSEPeerEntry *peer_entry = value; struct GNUNET_TIME_Relative delay; if (NULL != peer_entry->th) { peer_entry->previous_round = GNUNET_NO; return GNUNET_OK; } if (GNUNET_SCHEDULER_NO_TASK != peer_entry->transmit_task) { GNUNET_SCHEDULER_cancel (peer_entry->transmit_task); peer_entry->previous_round = GNUNET_NO; } #if ENABLE_HISTOGRAM if (peer_entry->received_messages > 1) GNUNET_STATISTICS_update(stats, "# extra messages", peer_entry->received_messages - 1, GNUNET_NO); peer_entry->transmitted_messages = 0; peer_entry->last_transmitted_size = 0; peer_entry->received_messages = 0; #endif delay = get_transmit_delay ((peer_entry->previous_round == GNUNET_NO) ? -1 : 0); peer_entry->transmit_task = GNUNET_SCHEDULER_add_delayed (delay, &transmit_task_cb, peer_entry); return GNUNET_OK; } /** * Update our flood message to be sent (and our timestamps). * * @param cls unused * @param tc context for this message */ static void update_flood_message (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TIME_Relative offset; unsigned int i; flood_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; offset = GNUNET_TIME_absolute_get_remaining (next_timestamp); if (0 != offset.rel_value) { /* somehow run early, delay more */ flood_task = GNUNET_SCHEDULER_add_delayed (offset, &update_flood_message, NULL); return; } estimate_index = (estimate_index + 1) % HISTORY_SIZE; if (estimate_count < HISTORY_SIZE) estimate_count++; current_timestamp = next_timestamp; next_timestamp = GNUNET_TIME_absolute_add (current_timestamp, gnunet_nse_interval); if ((current_timestamp.abs_value == GNUNET_TIME_absolute_ntoh (next_message.timestamp).abs_value) && (get_matching_bits (current_timestamp, &my_identity) < ntohl(next_message.matching_bits))) { /* we received a message for this round way early, use it! */ size_estimate_messages[estimate_index] = next_message; size_estimate_messages[estimate_index].hop_count = htonl (1 + ntohl (next_message.hop_count)); } else setup_flood_message (estimate_index, current_timestamp); next_message.matching_bits = htonl (0); /* reset for 'next' round */ hop_count_max = 0; for (i = 0; i < HISTORY_SIZE; i++) hop_count_max = GNUNET_MAX (ntohl (size_estimate_messages[i].hop_count), hop_count_max); GNUNET_CONTAINER_multihashmap_iterate (peers, &schedule_current_round, NULL); flood_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (next_timestamp), &update_flood_message, NULL); } /** * Count the leading zeroes in hash. * * @param hash * @return the number of leading zero bits. */ static unsigned int count_leading_zeroes (const GNUNET_HashCode * hash) { unsigned int hash_count; hash_count = 0; while ((0 == GNUNET_CRYPTO_hash_get_bit (hash, hash_count))) hash_count++; return hash_count; } /** * Check whether the given public key * and integer are a valid proof of work. * * @param pkey the public key * @param val the integer * * @return GNUNET_YES if valid, GNUNET_NO if not */ static int check_proof_of_work (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey, uint64_t val) { char buf[sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sizeof (val)] GNUNET_ALIGN; GNUNET_HashCode result; memcpy (buf, &val, sizeof (val)); memcpy (&buf[sizeof (val)], pkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); GNUNET_CRYPTO_hash (buf, sizeof (buf), &result); return (count_leading_zeroes (&result) >= nse_work_required) ? GNUNET_YES : GNUNET_NO; } /** * Write our current proof to disk. */ static void write_proof () { char *proof; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof)) return; if (sizeof (my_proof) != GNUNET_DISK_fn_write (proof, &my_proof, sizeof (my_proof), GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", proof); GNUNET_free (proof); } /** * Find our proof of work. * * @param cls closure (unused) * @param tc task context */ static void find_proof (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { #define ROUND_SIZE 10 uint64_t counter; char buf[sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sizeof (uint64_t)] GNUNET_ALIGN; GNUNET_HashCode result; unsigned int i; proof_task = GNUNET_SCHEDULER_NO_TASK; memcpy (&buf[sizeof (uint64_t)], &my_public_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); i = 0; counter = my_proof; while ((counter != UINT64_MAX) && (i < ROUND_SIZE)) { memcpy (buf, &counter, sizeof (uint64_t)); GNUNET_CRYPTO_hash (buf, sizeof (buf), &result); if (nse_work_required <= count_leading_zeroes (&result)) { my_proof = counter; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Proof of work found: %llu!\n", (unsigned long long) GNUNET_ntohll (counter)); write_proof (); setup_flood_message (estimate_index, current_timestamp); return; } counter++; i++; } if (my_proof / (100 * ROUND_SIZE) < counter / (100 * ROUND_SIZE)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing proofs currently at %llu\n", (unsigned long long) counter); /* remember progress every 100 rounds */ my_proof = counter; write_proof (); } else { my_proof = counter; } proof_task = GNUNET_SCHEDULER_add_delayed_with_priority (proof_find_delay, GNUNET_SCHEDULER_PRIORITY_IDLE, &find_proof, NULL); } /** * An incoming flood message has been received which claims * to have more bits matching than any we know in this time * period. Verify the signature and/or proof of work. * * @param incoming_flood the message to verify * * @return GNUNET_YES if the message is verified * GNUNET_NO if the key/signature don't verify */ static int verify_message_crypto (const struct GNUNET_NSE_FloodMessage *incoming_flood) { if (GNUNET_YES != check_proof_of_work (&incoming_flood->pkey, incoming_flood->proof_of_work)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Proof of work invalid: %llu!\n"), (unsigned long long) GNUNET_ntohll (incoming_flood->proof_of_work)); GNUNET_break_op (0); return GNUNET_NO; } if ((nse_work_required > 0) && (GNUNET_OK != GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_NSE_SEND, &incoming_flood->purpose, &incoming_flood->signature, &incoming_flood->pkey))) { GNUNET_break_op (0); return GNUNET_NO; } return GNUNET_YES; } /** * Update transmissions for the given peer for the current round based * on updated proximity information. * * @param cls peer entry to exclude from updates * @param key hash of peer identity * @param value the 'struct NSEPeerEntry' * @return GNUNET_OK (continue to iterate) */ static int update_flood_times (void *cls, const GNUNET_HashCode * key, void *value) { struct NSEPeerEntry *exclude = cls; struct NSEPeerEntry *peer_entry = value; struct GNUNET_TIME_Relative delay; if (peer_entry->th != NULL) return GNUNET_OK; /* already active */ if (peer_entry == exclude) return GNUNET_OK; /* trigger of the update */ if (peer_entry->previous_round == GNUNET_NO) { /* still stuck in previous round, no point to update, check that * we are active here though... */ if (GNUNET_SCHEDULER_NO_TASK == peer_entry->transmit_task && NULL == peer_entry->th) { GNUNET_break (0); } return GNUNET_OK; } if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (peer_entry->transmit_task); peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK; } delay = get_transmit_delay (0); peer_entry->transmit_task = GNUNET_SCHEDULER_add_delayed (delay, &transmit_task_cb, peer_entry); return GNUNET_OK; } /** * Core handler for size estimate flooding messages. * * @param cls closure unused * @param message message * @param peer peer identity this message is from (ignored) * @param atsi performance data (ignored) * @param atsi_count number of records in 'atsi' */ static int handle_p2p_size_estimate (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { const struct GNUNET_NSE_FloodMessage *incoming_flood; struct GNUNET_TIME_Absolute ts; struct NSEPeerEntry *peer_entry; uint32_t matching_bits; unsigned int idx; #if ENABLE_HISTOGRAM if (NULL != wh) GNUNET_break (GNUNET_OK == GNUNET_BIO_write_int64 (wh, GNUNET_TIME_absolute_get ().abs_value)); #endif incoming_flood = (const struct GNUNET_NSE_FloodMessage *) message; GNUNET_STATISTICS_update (stats, "# flood messages received", 1, GNUNET_NO); matching_bits = ntohl (incoming_flood->matching_bits); #if DEBUG_NSE { char origin[5]; char pred[5]; struct GNUNET_PeerIdentity os; GNUNET_CRYPTO_hash (&incoming_flood->pkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &os.hashPubKey); GNUNET_snprintf (origin, sizeof (origin), "%s", GNUNET_i2s (&os)); GNUNET_snprintf (pred, sizeof (pred), "%s", GNUNET_i2s (peer)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Flood at %llu from `%s' via `%s' at `%s' with bits %u\n", (unsigned long long) GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp).abs_value, origin, pred, GNUNET_i2s (&my_identity), (unsigned int) matching_bits); } #endif peer_entry = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); if (NULL == peer_entry) { GNUNET_break (0); return GNUNET_OK; } #if ENABLE_HISTOGRAM peer_entry->received_messages++; if (peer_entry->transmitted_messages > 0 && peer_entry->last_transmitted_size >= matching_bits) GNUNET_STATISTICS_update(stats, "# cross messages", 1, GNUNET_NO); #endif ts = GNUNET_TIME_absolute_ntoh (incoming_flood->timestamp); if (ts.abs_value == current_timestamp.abs_value) idx = estimate_index; else if (ts.abs_value == current_timestamp.abs_value - gnunet_nse_interval.rel_value) idx = (estimate_index + HISTORY_SIZE - 1) % HISTORY_SIZE; else if (ts.abs_value == next_timestamp.abs_value) { if (matching_bits <= ntohl (next_message.matching_bits)) return GNUNET_OK; /* ignore, simply too early/late */ if (GNUNET_YES != verify_message_crypto (incoming_flood)) { GNUNET_break_op (0); return GNUNET_OK; } next_message = *incoming_flood; return GNUNET_OK; } else { GNUNET_STATISTICS_update (stats, "# flood messages discarded (clock skew too large)", 1, GNUNET_NO); return GNUNET_OK; } if (0 == (memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))) { /* send to self, update our own estimate IF this also comes from us! */ if (0 == memcmp (&incoming_flood->pkey, &my_public_key, sizeof (my_public_key))) update_network_size_estimate (); return GNUNET_OK; } if (matching_bits == ntohl (size_estimate_messages[idx].matching_bits)) { /* Cancel transmission in the other direction, as this peer clearly has up-to-date information already. Even if we didn't talk to this peer in the previous round, we should no longer send it stale information as it told us about the current round! */ peer_entry->previous_round = GNUNET_YES; if (idx != estimate_index) { /* do not transmit information for the previous round to this peer anymore (but allow current round) */ return GNUNET_OK; } /* got up-to-date information for current round, cancel transmission to * this peer altogether */ if (GNUNET_SCHEDULER_NO_TASK != peer_entry->transmit_task) { GNUNET_SCHEDULER_cancel (peer_entry->transmit_task); peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK; } if (peer_entry->th != NULL) { GNUNET_CORE_notify_transmit_ready_cancel (peer_entry->th); peer_entry->th = NULL; } return GNUNET_OK; } if (matching_bits < ntohl (size_estimate_messages[idx].matching_bits)) { if ((idx < estimate_index) && (peer_entry->previous_round == GNUNET_YES)) { peer_entry->previous_round = GNUNET_NO; } /* push back our result now, that peer is spreading bad information... */ if (NULL == peer_entry->th) { if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (peer_entry->transmit_task); peer_entry->transmit_task = GNUNET_SCHEDULER_add_now (&transmit_task_cb, peer_entry); } /* Not closer than our most recent message, no need to do work here */ GNUNET_STATISTICS_update (stats, "# flood messages ignored (had closer already)", 1, GNUNET_NO); return GNUNET_OK; } if (GNUNET_YES != verify_message_crypto (incoming_flood)) { GNUNET_break_op (0); return GNUNET_OK; } GNUNET_assert (matching_bits > ntohl (size_estimate_messages[idx].matching_bits)); /* Cancel transmission in the other direction, as this peer clearly has * up-to-date information already. */ peer_entry->previous_round = GNUNET_YES; if (idx == estimate_index) { /* cancel any activity for current round */ if (peer_entry->transmit_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (peer_entry->transmit_task); peer_entry->transmit_task = GNUNET_SCHEDULER_NO_TASK; } if (peer_entry->th != NULL) { GNUNET_CORE_notify_transmit_ready_cancel (peer_entry->th); peer_entry->th = NULL; } } size_estimate_messages[idx] = *incoming_flood; size_estimate_messages[idx].hop_count = htonl (ntohl (incoming_flood->hop_count) + 1); hop_count_max = GNUNET_MAX (ntohl (incoming_flood->hop_count) + 1, hop_count_max); GNUNET_STATISTICS_set (stats, "# estimated network diameter", hop_count_max, GNUNET_NO); /* have a new, better size estimate, inform clients */ update_network_size_estimate (); /* flood to rest */ GNUNET_CONTAINER_multihashmap_iterate (peers, &update_flood_times, peer_entry); return GNUNET_OK; } /** * Method called whenever a peer connects. Sets up the PeerEntry and * schedules the initial size info transmission to this peer. * * @param cls closure * @param peer peer identity this notification is about * @param atsi performance data * @param atsi_count number of records in 'atsi' */ static void handle_core_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct NSEPeerEntry *peer_entry; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' connected to us\n", GNUNET_i2s (peer)); peer_entry = GNUNET_malloc (sizeof (struct NSEPeerEntry)); peer_entry->id = *peer; GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (peers, &peer->hashPubKey, peer_entry, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); peer_entry->transmit_task = GNUNET_SCHEDULER_add_delayed (get_transmit_delay (-1), &transmit_task_cb, peer_entry); GNUNET_STATISTICS_update (stats, "# peers connected", 1, GNUNET_NO); } /** * Method called whenever a peer disconnects. Deletes the PeerEntry and cancels * any pending transmission requests to that peer. * * @param cls closure * @param peer peer identity this notification is about */ static void handle_core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { struct NSEPeerEntry *pos; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' disconnected from us\n", GNUNET_i2s (peer)); pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); if (NULL == pos) { GNUNET_break (0); return; } GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (peers, &peer->hashPubKey, pos)); if (pos->transmit_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (pos->transmit_task); pos->transmit_task = GNUNET_SCHEDULER_NO_TASK; } if (pos->th != NULL) { GNUNET_CORE_notify_transmit_ready_cancel (pos->th); pos->th = NULL; } GNUNET_free (pos); GNUNET_STATISTICS_update (stats, "# peers connected", -1, GNUNET_NO); } /** * Task run during shutdown. * * @param cls unused * @param tc unused */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (flood_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (flood_task); flood_task = GNUNET_SCHEDULER_NO_TASK; } if (proof_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (proof_task); proof_task = GNUNET_SCHEDULER_NO_TASK; write_proof (); /* remember progress */ } if (nc != NULL) { GNUNET_SERVER_notification_context_destroy (nc); nc = NULL; } if (coreAPI != NULL) { GNUNET_CORE_disconnect (coreAPI); coreAPI = NULL; } if (stats != NULL) { GNUNET_STATISTICS_destroy (stats, GNUNET_NO); stats = NULL; } if (peers != NULL) { GNUNET_CONTAINER_multihashmap_destroy (peers); peers = NULL; } if (my_private_key != NULL) { GNUNET_CRYPTO_rsa_key_free (my_private_key); my_private_key = NULL; } #if ENABLE_HISTOGRAM if (wh != NULL) { GNUNET_break (GNUNET_OK == GNUNET_BIO_write_close (wh)); wh = NULL; } #endif } /** * Called on core init/fail. * * @param cls service closure * @param server handle to the server for this service * @param identity the public identity of this peer */ static void core_init (void *cls, struct GNUNET_CORE_Handle *server, const struct GNUNET_PeerIdentity *identity) { struct GNUNET_TIME_Absolute now; struct GNUNET_TIME_Absolute prev_time; if (NULL == server) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Connection to core FAILED!\n"); GNUNET_SCHEDULER_shutdown (); return; } GNUNET_assert (0 == memcmp (&my_identity, identity, sizeof (struct GNUNET_PeerIdentity))); now = GNUNET_TIME_absolute_get (); current_timestamp.abs_value = (now.abs_value / gnunet_nse_interval.rel_value) * gnunet_nse_interval.rel_value; next_timestamp = GNUNET_TIME_absolute_add (current_timestamp, gnunet_nse_interval); estimate_index = HISTORY_SIZE - 1; estimate_count = 0; if (GNUNET_YES == check_proof_of_work (&my_public_key, my_proof)) { int idx = (estimate_index + HISTORY_SIZE - 1) % HISTORY_SIZE; prev_time.abs_value = current_timestamp.abs_value - gnunet_nse_interval.rel_value; setup_flood_message (idx, prev_time); setup_flood_message (estimate_index, current_timestamp); estimate_count++; } flood_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (next_timestamp), &update_flood_message, NULL); } /** * Handle network size estimate clients. * * @param cls closure * @param server the initialized server * @param c configuration to use */ static void run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *c) { char *keyfile; char *proof; static const struct GNUNET_SERVER_MessageHandler handlers[] = { {&handle_start_message, NULL, GNUNET_MESSAGE_TYPE_NSE_START, sizeof (struct GNUNET_MessageHeader)}, {NULL, NULL, 0, 0} }; static const struct GNUNET_CORE_MessageHandler core_handlers[] = { {&handle_p2p_size_estimate, GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD, sizeof (struct GNUNET_NSE_FloodMessage)}, {NULL, 0, 0} }; cfg = c; if ((GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "NSE", "INTERVAL", &gnunet_nse_interval)) || (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "NSE", "WORKDELAY", &proof_find_delay)) || (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "NSE", "WORKBITS", &nse_work_required))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("NSE service is lacking key configuration settings. Exiting.\n")); GNUNET_SCHEDULER_shutdown (); return; } if (nse_work_required >= sizeof (GNUNET_HashCode) * 8) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Invalid work requirement for NSE service. Exiting.\n")); GNUNET_SCHEDULER_shutdown (); return; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY", &keyfile)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("NSE service is lacking key configuration settings. Exiting.\n")); GNUNET_SCHEDULER_shutdown (); return; } my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); GNUNET_free (keyfile); if (my_private_key == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("NSE service could not access hostkey. Exiting.\n")); GNUNET_SCHEDULER_shutdown (); return; } GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key); GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key), &my_identity.hashPubKey); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "PROOFFILE", &proof)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("NSE service is lacking key configuration settings. Exiting.\n")); if (my_private_key != NULL) { GNUNET_CRYPTO_rsa_key_free (my_private_key); my_private_key = NULL; } GNUNET_SCHEDULER_shutdown (); return; } if ((GNUNET_YES != GNUNET_DISK_file_test (proof)) || (sizeof (my_proof) != GNUNET_DISK_fn_read (proof, &my_proof, sizeof (my_proof)))) my_proof = 0; GNUNET_free (proof); proof_task = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, &find_proof, NULL); peers = GNUNET_CONTAINER_multihashmap_create (128); GNUNET_SERVER_add_handlers (server, handlers); nc = GNUNET_SERVER_notification_context_create (server, 1); /* Connect to core service and register core handlers */ coreAPI = GNUNET_CORE_connect (cfg, /* Main configuration */ 1, NULL, /* Closure passed to functions */ &core_init, /* Call core_init once connected */ &handle_core_connect, /* Handle connects */ &handle_core_disconnect, /* Handle disconnects */ NULL, /* Don't want notified about all incoming messages */ GNUNET_NO, /* For header only inbound notification */ NULL, /* Don't want notified about all outbound messages */ GNUNET_NO, /* For header only outbound notification */ core_handlers); /* Register these handlers */ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); #if ENABLE_HISTOGRAM if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, "NSE", "HISTOGRAM", &proof)) { wh = GNUNET_BIO_write_open (proof); GNUNET_free (proof); } #endif if (coreAPI == NULL) { GNUNET_SCHEDULER_shutdown (); return; } stats = GNUNET_STATISTICS_create ("nse", cfg); } /** * The main function for the statistics service. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { return (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "nse", GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; } /* end of gnunet-service-nse.c */ gnunet-0.9.3/src/nse/Makefile.in0000644000175000017500000007516411762217212013403 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-service-nse$(EXEEXT) noinst_PROGRAMS = gnunet-nse-profiler$(EXEEXT) check_PROGRAMS = test_nse_api$(EXEEXT) $(am__EXEEXT_1) subdir = src/nse DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/nse.conf.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = nse.conf CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libgnunetnse_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am_libgnunetnse_la_OBJECTS = nse_api.lo libgnunetnse_la_OBJECTS = $(am_libgnunetnse_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunetnse_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetnse_la_LDFLAGS) $(LDFLAGS) \ -o $@ @HAVE_BENCHMARKS_TRUE@am__EXEEXT_1 = test_nse_multipeer$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) am_gnunet_nse_profiler_OBJECTS = gnunet-nse-profiler.$(OBJEXT) gnunet_nse_profiler_OBJECTS = $(am_gnunet_nse_profiler_OBJECTS) am_gnunet_service_nse_OBJECTS = gnunet-service-nse.$(OBJEXT) gnunet_service_nse_OBJECTS = $(am_gnunet_service_nse_OBJECTS) am_test_nse_api_OBJECTS = test_nse_api.$(OBJEXT) test_nse_api_OBJECTS = $(am_test_nse_api_OBJECTS) test_nse_api_DEPENDENCIES = $(top_builddir)/src/nse/libgnunetnse.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_nse_multipeer_OBJECTS = test_nse_multipeer.$(OBJEXT) test_nse_multipeer_OBJECTS = $(am_test_nse_multipeer_OBJECTS) test_nse_multipeer_DEPENDENCIES = \ $(top_builddir)/src/nse/libgnunetnse.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunetnse_la_SOURCES) $(gnunet_nse_profiler_SOURCES) \ $(gnunet_service_nse_SOURCES) $(test_nse_api_SOURCES) \ $(test_nse_multipeer_SOURCES) DIST_SOURCES = $(libgnunetnse_la_SOURCES) \ $(gnunet_nse_profiler_SOURCES) $(gnunet_service_nse_SOURCES) \ $(test_nse_api_SOURCES) $(test_nse_multipeer_SOURCES) DATA = $(pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @USE_COVERAGE_TRUE@XLIB = -lgcov pkgcfgdir = $(pkgdatadir)/config.d/ pkgcfg_DATA = \ nse.conf lib_LTLIBRARIES = libgnunetnse.la libgnunetnse_la_SOURCES = \ nse_api.c nse.h libgnunetnse_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) $(XLIB) libgnunetnse_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 0:0:0 gnunet_nse_profiler_SOURCES = \ gnunet-nse-profiler.c gnunet_nse_profiler_LDADD = -lm \ $(top_builddir)/src/nse/libgnunetnse.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(GN_LIBINTL) gnunet_nse_profiler_DEPENDENCIES = \ libgnunetnse.la gnunet_service_nse_SOURCES = \ gnunet-service-nse.c gnunet_service_nse_LDADD = \ $(top_builddir)/src/nse/libgnunetnse.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ -lm \ $(GN_LIBINTL) gnunet_service_nse_DEPENDENCIES = \ libgnunetnse.la @HAVE_BENCHMARKS_TRUE@MULTIPEER_TEST = test_nse_multipeer @ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) test_nse_api_SOURCES = \ test_nse_api.c test_nse_api_LDADD = \ $(top_builddir)/src/nse/libgnunetnse.la \ $(top_builddir)/src/util/libgnunetutil.la test_nse_multipeer_SOURCES = \ test_nse_multipeer.c test_nse_multipeer_LDADD = \ $(top_builddir)/src/nse/libgnunetnse.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la \ -lm EXTRA_DIST = \ test_nse.conf \ nse_profiler_test.conf all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/nse/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/nse/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): nse.conf: $(top_builddir)/config.status $(srcdir)/nse.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunetnse.la: $(libgnunetnse_la_OBJECTS) $(libgnunetnse_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetnse_la_LINK) -rpath $(libdir) $(libgnunetnse_la_OBJECTS) $(libgnunetnse_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-nse-profiler$(EXEEXT): $(gnunet_nse_profiler_OBJECTS) $(gnunet_nse_profiler_DEPENDENCIES) @rm -f gnunet-nse-profiler$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_nse_profiler_OBJECTS) $(gnunet_nse_profiler_LDADD) $(LIBS) gnunet-service-nse$(EXEEXT): $(gnunet_service_nse_OBJECTS) $(gnunet_service_nse_DEPENDENCIES) @rm -f gnunet-service-nse$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_service_nse_OBJECTS) $(gnunet_service_nse_LDADD) $(LIBS) test_nse_api$(EXEEXT): $(test_nse_api_OBJECTS) $(test_nse_api_DEPENDENCIES) @rm -f test_nse_api$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_nse_api_OBJECTS) $(test_nse_api_LDADD) $(LIBS) test_nse_multipeer$(EXEEXT): $(test_nse_multipeer_OBJECTS) $(test_nse_multipeer_DEPENDENCIES) @rm -f test_nse_multipeer$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_nse_multipeer_OBJECTS) $(test_nse_multipeer_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-nse-profiler.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-nse.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nse_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_nse_api.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_nse_multipeer.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgcfgDATA: $(pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool clean-noinstPROGRAMS \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgcfgDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool clean-noinstPROGRAMS ctags \ distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-libLTLIBRARIES \ install-man install-pdf install-pdf-am install-pkgcfgDATA \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-libLTLIBRARIES uninstall-pkgcfgDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/nse/nse.conf.in0000644000175000017500000000123111760502552013361 00000000000000[nse] AUTOSTART = YES @JAVAPORT@PORT = 2097 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-nse ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-nse-service-nse.unix UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES PROOFFILE = $SERVICEHOME/.nse-proof HISTOGRAM = $SERVICEHOME/nse-history.log # How 'slowly' should the proof-of-work be constructed (delay # between rounds); sane values between 0 and ~1000. WORKDELAY = 5 ms # Note: changing any of the values below will make this peer # completely incompatible with other peers! INTERVAL = 1 h # 26 is about 10 minutes on a modern i7 (single-core) WORKBITS = 26 gnunet-0.9.3/src/peerinfo/0000755000175000017500000000000011763406747012441 500000000000000gnunet-0.9.3/src/peerinfo/gnunet-service-peerinfo.c0000644000175000017500000005225411760502551017263 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2004, 2005, 2007, 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file peerinfo/gnunet-service-peerinfo.c * @brief maintains list of known peers * * Code to maintain the list of currently known hosts (in memory * structure of data/hosts/). * * @author Christian Grothoff * * TODO: * - HostEntries are never 'free'd (add expiration, upper bound?) */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_hello_lib.h" #include "gnunet_protocols.h" #include "gnunet_statistics_service.h" #include "peerinfo.h" /** * How often do we scan the HOST_DIR for new entries? */ #define DATA_HOST_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) /** * How often do we discard old entries in data/hosts/? */ #define DATA_HOST_CLEAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 60) /** * In-memory cache of known hosts. */ struct HostEntry { /** * Identity of the peer. */ struct GNUNET_PeerIdentity identity; /** * Hello for the peer (can be NULL) */ struct GNUNET_HELLO_Message *hello; }; /** * The in-memory list of known hosts, mapping of * host IDs to 'struct HostEntry*' values. */ static struct GNUNET_CONTAINER_MultiHashMap *hostmap; /** * Clients to immediately notify about all changes. */ static struct GNUNET_SERVER_NotificationContext *notify_list; /** * Directory where the hellos are stored in (data/hosts) */ static char *networkIdDirectory; /** * Handle for reporting statistics. */ static struct GNUNET_STATISTICS_Handle *stats; /** * Notify all clients in the notify list about the * given host entry changing. * * @param he entry of the host for which we generate a notification * @return generated notification message */ static struct InfoMessage * make_info_message (const struct HostEntry *he) { struct InfoMessage *im; size_t hs; hs = (he->hello == NULL) ? 0 : GNUNET_HELLO_size (he->hello); im = GNUNET_malloc (sizeof (struct InfoMessage) + hs); im->header.size = htons (hs + sizeof (struct InfoMessage)); im->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_INFO); im->peer = he->identity; if (he->hello != NULL) memcpy (&im[1], he->hello, hs); return im; } /** * Address iterator that causes expired entries to be discarded. * * @param cls pointer to the current time * @param address the address * @param expiration expiration time for the address * @return GNUNET_NO if expiration smaller than the current time */ static int discard_expired (void *cls, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration) { const struct GNUNET_TIME_Absolute *now = cls; if (now->abs_value > expiration.abs_value) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Removing expired address of transport `%s'\n"), address->transport_name); return GNUNET_NO; } return GNUNET_OK; } /** * Get the filename under which we would store the GNUNET_HELLO_Message * for the given host and protocol. * * @param id peer for which we need the filename for the HELLO * @return filename of the form DIRECTORY/HOSTID */ static char * get_host_filename (const struct GNUNET_PeerIdentity *id) { struct GNUNET_CRYPTO_HashAsciiEncoded fil; char *fn; GNUNET_CRYPTO_hash_to_enc (&id->hashPubKey, &fil); GNUNET_asprintf (&fn, "%s%s%s", networkIdDirectory, DIR_SEPARATOR_STR, &fil); return fn; } /** * Broadcast information about the given entry to all * clients that care. * * @param entry entry to broadcast about */ static void notify_all (struct HostEntry *entry) { struct InfoMessage *msg; msg = make_info_message (entry); GNUNET_SERVER_notification_context_broadcast (notify_list, &msg->header, GNUNET_NO); GNUNET_free (msg); } /** * Try to read the HELLO in the given filename and discard expired addresses. * * @param fn name of the file * @return HELLO of the file, NULL on error */ static struct GNUNET_HELLO_Message * read_host_file (const char *fn) { char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN; const struct GNUNET_HELLO_Message *hello; struct GNUNET_HELLO_Message *hello_clean; int size; struct GNUNET_TIME_Absolute now; if (GNUNET_YES != GNUNET_DISK_file_test (fn)) return NULL; size = GNUNET_DISK_fn_read (fn, buffer, sizeof (buffer)); hello = (const struct GNUNET_HELLO_Message *) buffer; if ((size < sizeof (struct GNUNET_MessageHeader)) || (size != ntohs ((((const struct GNUNET_MessageHeader *) hello)->size))) || (size != GNUNET_HELLO_size (hello))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to parse HELLO in file `%s'\n"), fn); return NULL; } now = GNUNET_TIME_absolute_get (); hello_clean = GNUNET_HELLO_iterate_addresses (hello, GNUNET_YES, &discard_expired, &now); return hello_clean; } /** * Add a host to the list. * * @param identity the identity of the host */ static void add_host_to_known_hosts (const struct GNUNET_PeerIdentity *identity) { struct HostEntry *entry; char *fn; entry = GNUNET_CONTAINER_multihashmap_get (hostmap, &identity->hashPubKey); if (entry != NULL) return; GNUNET_STATISTICS_update (stats, gettext_noop ("# peers known"), 1, GNUNET_NO); entry = GNUNET_malloc (sizeof (struct HostEntry)); entry->identity = *identity; GNUNET_CONTAINER_multihashmap_put (hostmap, &identity->hashPubKey, entry, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); fn = get_host_filename (identity); entry->hello = read_host_file (fn); GNUNET_free (fn); notify_all (entry); } /** * Remove a file that should not be there. LOG * success or failure. * * @param fullname name of the file to remove */ static void remove_garbage (const char *fullname) { if (0 == UNLINK (fullname)) GNUNET_log (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, _ ("File `%s' in directory `%s' does not match naming convention. " "Removed.\n"), fullname, networkIdDirectory); else GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "unlink", fullname); } /** * Function that is called on each HELLO file in a particular directory. * Try to parse the file and add the HELLO to our list. * * @param cls pointer to 'unsigned int' to increment for each file, or NULL * if the file is from a read-only, read-once resource directory * @param fullname name of the file to parse * @return GNUNET_OK (continue iteration) */ static int hosts_directory_scan_callback (void *cls, const char *fullname) { unsigned int *matched = cls; struct GNUNET_PeerIdentity identity; const char *filename; struct HostEntry *entry; struct GNUNET_HELLO_Message *hello; if (GNUNET_DISK_file_test (fullname) != GNUNET_YES) return GNUNET_OK; /* ignore non-files */ if (strlen (fullname) < sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) { if (NULL != matched) remove_garbage (fullname); return GNUNET_OK; } filename = &fullname[strlen (fullname) - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1]; if (filename[-1] != DIR_SEPARATOR) { if (NULL != matched) remove_garbage (fullname); return GNUNET_OK; } if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (filename, &identity.hashPubKey)) { if (NULL != (hello = read_host_file (filename))) { entry = GNUNET_malloc (sizeof (struct HostEntry)); if (GNUNET_OK == GNUNET_HELLO_get_id (hello, &entry->identity)) { GNUNET_CONTAINER_multihashmap_put (hostmap, &entry->identity.hashPubKey, entry, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); entry->hello = hello; notify_all (entry); return GNUNET_OK; } GNUNET_free (entry); } if (NULL != matched) remove_garbage (fullname); return GNUNET_OK; } if (NULL != matched) (*matched)++; add_host_to_known_hosts (&identity); return GNUNET_OK; } /** * Call this method periodically to scan data/hosts for new hosts. * * @param cls unused * @param tc scheduler context, aborted if reason is shutdown */ static void cron_scan_directory_data_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { static unsigned int retries; unsigned int count; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; count = 0; if (GNUNET_SYSERR == GNUNET_DISK_directory_create (networkIdDirectory)) { GNUNET_SCHEDULER_add_delayed_with_priority (DATA_HOST_FREQ, GNUNET_SCHEDULER_PRIORITY_IDLE, &cron_scan_directory_data_hosts, NULL); return; } GNUNET_DISK_directory_scan (networkIdDirectory, &hosts_directory_scan_callback, &count); if ((0 == count) && (0 == (++retries & 31))) GNUNET_log (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, _("Still no peers found in `%s'!\n"), networkIdDirectory); GNUNET_SCHEDULER_add_delayed_with_priority (DATA_HOST_FREQ, GNUNET_SCHEDULER_PRIORITY_IDLE, &cron_scan_directory_data_hosts, NULL); } /** * Bind a host address (hello) to a hostId. * * @param peer the peer for which this is a hello * @param hello the verified (!) hello message */ static void bind_address (const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Message *hello) { char *fn; struct HostEntry *host; struct GNUNET_HELLO_Message *mrg; struct GNUNET_TIME_Absolute delta; add_host_to_known_hosts (peer); host = GNUNET_CONTAINER_multihashmap_get (hostmap, &peer->hashPubKey); GNUNET_assert (host != NULL); if (host->hello == NULL) { host->hello = GNUNET_malloc (GNUNET_HELLO_size (hello)); memcpy (host->hello, hello, GNUNET_HELLO_size (hello)); } else { mrg = GNUNET_HELLO_merge (host->hello, hello); delta = GNUNET_HELLO_equals (mrg, host->hello, GNUNET_TIME_absolute_get ()); if (delta.abs_value == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value) { GNUNET_free (mrg); return; } GNUNET_free (host->hello); host->hello = mrg; } fn = get_host_filename (peer); if (GNUNET_OK == GNUNET_DISK_directory_create_for_file (fn)) { if (GNUNET_SYSERR == GNUNET_DISK_fn_write (fn, host->hello, GNUNET_HELLO_size (host->hello), GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_GROUP_READ | GNUNET_DISK_PERM_OTHER_READ)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", fn); } GNUNET_free (fn); notify_all (host); } /** * Do transmit info about peer to given host. * * @param cls NULL to hit all hosts, otherwise specifies a particular target * @param key hostID * @param value information to transmit * @return GNUNET_YES (continue to iterate) */ static int add_to_tc (void *cls, const GNUNET_HashCode * key, void *value) { struct GNUNET_SERVER_TransmitContext *tc = cls; struct HostEntry *pos = value; struct InfoMessage *im; uint16_t hs; char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN; hs = 0; im = (struct InfoMessage *) buf; if (pos->hello != NULL) { hs = GNUNET_HELLO_size (pos->hello); GNUNET_assert (hs < GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct InfoMessage)); memcpy (&im[1], pos->hello, hs); } im->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_INFO); im->header.size = htons (sizeof (struct InfoMessage) + hs); im->reserved = htonl (0); im->peer = pos->identity; GNUNET_SERVER_transmit_context_append_message (tc, &im->header); return GNUNET_YES; } /** * @brief delete expired HELLO entries in data/hosts/ * * @param cls pointer to current time (struct GNUNET_TIME_Absolute) * @param fn filename to test to see if the HELLO expired * @return GNUNET_OK (continue iteration) */ static int discard_hosts_helper (void *cls, const char *fn) { struct GNUNET_TIME_Absolute *now = cls; char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN; const struct GNUNET_HELLO_Message *hello; struct GNUNET_HELLO_Message *new_hello; int size; size = GNUNET_DISK_fn_read (fn, buffer, sizeof (buffer)); if (size < sizeof (struct GNUNET_MessageHeader)) { if (0 != UNLINK (fn)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "unlink", fn); return GNUNET_OK; } hello = (const struct GNUNET_HELLO_Message *) buffer; new_hello = GNUNET_HELLO_iterate_addresses (hello, GNUNET_YES, &discard_expired, now); if (new_hello != NULL) { GNUNET_DISK_fn_write (fn, new_hello, GNUNET_HELLO_size (new_hello), GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_GROUP_READ | GNUNET_DISK_PERM_OTHER_READ); GNUNET_free (new_hello); } else { if (0 != UNLINK (fn)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "unlink", fn); } return GNUNET_OK; } /** * Call this method periodically to scan data/hosts for ancient * HELLOs to expire. * * @param cls unused * @param tc scheduler context, aborted if reason is shutdown */ static void cron_clean_data_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TIME_Absolute now; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; now = GNUNET_TIME_absolute_get (); GNUNET_DISK_directory_scan (networkIdDirectory, &discard_hosts_helper, &now); GNUNET_SCHEDULER_add_delayed (DATA_HOST_CLEAN_FREQ, &cron_clean_data_hosts, NULL); } /** * Handle HELLO-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_hello (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct GNUNET_HELLO_Message *hello; struct GNUNET_PeerIdentity pid; hello = (const struct GNUNET_HELLO_Message *) message; if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' message received for peer `%4s'\n", "HELLO", GNUNET_i2s (&pid)); bind_address (&pid, hello); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Handle GET-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_get (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct ListPeerMessage *lpm; struct GNUNET_SERVER_TransmitContext *tc; lpm = (const struct ListPeerMessage *) message; GNUNET_break (0 == ntohl (lpm->reserved)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' message received for peer `%4s'\n", "GET", GNUNET_i2s (&lpm->peer)); tc = GNUNET_SERVER_transmit_context_create (client); GNUNET_CONTAINER_multihashmap_get_multiple (hostmap, &lpm->peer.hashPubKey, &add_to_tc, tc); GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END); GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); } /** * Handle GET-ALL-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_get_all (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct GNUNET_SERVER_TransmitContext *tc; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' message received\n", "GET_ALL"); tc = GNUNET_SERVER_transmit_context_create (client); GNUNET_CONTAINER_multihashmap_iterate (hostmap, &add_to_tc, tc); GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END); GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); } /** * FIXME. */ static int do_notify_entry (void *cls, const GNUNET_HashCode * key, void *value) { struct GNUNET_SERVER_Client *client = cls; struct HostEntry *he = value; struct InfoMessage *msg; msg = make_info_message (he); GNUNET_SERVER_notification_context_unicast (notify_list, client, &msg->header, GNUNET_NO); GNUNET_free (msg); return GNUNET_YES; } /** * Handle NOTIFY-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_notify (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' message received\n", "NOTIFY"); GNUNET_SERVER_client_mark_monitor (client); GNUNET_SERVER_notification_context_add (notify_list, client); GNUNET_CONTAINER_multihashmap_iterate (hostmap, &do_notify_entry, client); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * FIXME. */ static int free_host_entry (void *cls, const GNUNET_HashCode * key, void *value) { struct HostEntry *he = value; GNUNET_free_non_null (he->hello); GNUNET_free (he); return GNUNET_YES; } /** * Clean up our state. Called during shutdown. * * @param cls unused * @param tc scheduler task context, unused */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_SERVER_notification_context_destroy (notify_list); notify_list = NULL; GNUNET_CONTAINER_multihashmap_iterate (hostmap, &free_host_entry, NULL); GNUNET_CONTAINER_multihashmap_destroy (hostmap); if (stats != NULL) { GNUNET_STATISTICS_destroy (stats, GNUNET_NO); stats = NULL; } } /** * Start up peerinfo service. * * @param cls closure * @param server the initialized server * @param cfg configuration to use */ static void run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *cfg) { static const struct GNUNET_SERVER_MessageHandler handlers[] = { {&handle_hello, NULL, GNUNET_MESSAGE_TYPE_HELLO, 0}, {&handle_get, NULL, GNUNET_MESSAGE_TYPE_PEERINFO_GET, sizeof (struct ListPeerMessage)}, {&handle_get_all, NULL, GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL, sizeof (struct GNUNET_MessageHeader)}, {&handle_notify, NULL, GNUNET_MESSAGE_TYPE_PEERINFO_NOTIFY, sizeof (struct GNUNET_MessageHeader)}, {NULL, NULL, 0, 0} }; char *peerdir; char *ip; hostmap = GNUNET_CONTAINER_multihashmap_create (1024); stats = GNUNET_STATISTICS_create ("peerinfo", cfg); notify_list = GNUNET_SERVER_notification_context_create (server, 0); GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, "peerinfo", "HOSTS", &networkIdDirectory)); GNUNET_DISK_directory_create (networkIdDirectory); GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, &cron_scan_directory_data_hosts, NULL); GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, &cron_clean_data_hosts, NULL); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); GNUNET_SERVER_add_handlers (server, handlers); ip = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR); GNUNET_asprintf (&peerdir, "%shellos", ip); GNUNET_free (ip); GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Importing HELLOs from `%s'\n"), peerdir); GNUNET_DISK_directory_scan (peerdir, &hosts_directory_scan_callback, NULL); GNUNET_free (peerdir); } /** * The main function for the peerinfo service. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { int ret; ret = (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "peerinfo", GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; GNUNET_free_non_null (networkIdDirectory); return ret; } /* end of gnunet-service-peerinfo.c */ gnunet-0.9.3/src/peerinfo/Makefile.am0000644000175000017500000000315211704315746014407 00000000000000INCLUDES = -I$(top_srcdir)/src/include pkgcfgdir= $(pkgdatadir)/config.d/ pkgcfg_DATA = \ peerinfo.conf if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -lole32 -lshell32 -liconv -lstdc++ -lcomdlg32 -lgdi32 endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIB = -lgcov endif lib_LTLIBRARIES = libgnunetpeerinfo.la libgnunetpeerinfo_la_SOURCES = \ peerinfo_api.c peerinfo.h \ peerinfo_api_notify.c libgnunetpeerinfo_la_LIBADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(XLIB) libgnunetpeerinfo_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 0:0:0 bin_PROGRAMS = \ gnunet-service-peerinfo gnunet_service_peerinfo_SOURCES = \ gnunet-service-peerinfo.c gnunet_service_peerinfo_LDADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la if HAVE_BENCHMARKS PEERINFO_BENCHMARKS = \ perf_peerinfo_api endif check_PROGRAMS = \ test_peerinfo_api \ $(PEERINFO_BENCHMARKS) if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) endif test_peerinfo_api_SOURCES = \ test_peerinfo_api.c test_peerinfo_api_LDADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/util/libgnunetutil.la perf_peerinfo_api_SOURCES = \ perf_peerinfo_api.c perf_peerinfo_api_LDADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ test_peerinfo_api_data.conf gnunet-0.9.3/src/peerinfo/test_peerinfo_api_data.conf0000644000175000017500000000020511611077627017706 00000000000000[PATHS] SERVICEHOME = /tmp/test-gnunet-peerinfo/ [peerinfo] PORT = 22354 DEBUG = NO [dns] AUTOSTART = NO [nse] AUTOSTART = NO gnunet-0.9.3/src/peerinfo/test_peerinfo_api.c0000644000175000017500000001267511760502551016222 00000000000000/* This file is part of GNUnet. (C) 2004, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file peerinfo/test_peerinfo_api.c * @brief testcase for peerinfo_api.c * @author Christian Grothoff * * TODO: * - test merging of HELLOs (add same peer twice...) */ #include "platform.h" #include "gnunet_hello_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_peerinfo_service.h" #include "gnunet_program_lib.h" #include "gnunet_time_lib.h" #include "peerinfo.h" static const struct GNUNET_CONFIGURATION_Handle *cfg; static struct GNUNET_PEERINFO_IteratorContext *ic; static struct GNUNET_PEERINFO_Handle *h; static unsigned int retries; static int check_it (void *cls, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration) { unsigned int *agc = cls; if (address != NULL) { GNUNET_assert (0 == strcmp ("peerinfotest", address->transport_name)); GNUNET_assert (0 == strncmp ("Address", address->address, address->address_length)); (*agc) -= (1 << (address->address_length - 1)); } return GNUNET_OK; } static size_t address_generator (void *cls, size_t max, void *buf) { size_t *agc = cls; size_t ret; struct GNUNET_HELLO_Address address; if (0 == *agc) return 0; memset (&address.peer, 0, sizeof (struct GNUNET_PeerIdentity)); address.address = "Address"; address.transport_name = "peerinfotest"; address.address_length = *agc; ret = GNUNET_HELLO_add_address (&address, GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS), buf, max); (*agc)--; return ret; } static void add_peer () { struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; struct GNUNET_PeerIdentity pid; struct GNUNET_HELLO_Message *h2; size_t agc; agc = 2; memset (&pkey, 32, sizeof (pkey)); GNUNET_CRYPTO_hash (&pkey, sizeof (pkey), &pid.hashPubKey); h2 = GNUNET_HELLO_create (&pkey, &address_generator, &agc); GNUNET_PEERINFO_add_peer (h, h2, NULL, NULL); GNUNET_free (h2); } static void process (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Message *hello, const char *err_msg) { int *ok = cls; unsigned int agc; if (err_msg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Error in communication with PEERINFO service\n")); } if (peer == NULL) { ic = NULL; if ((3 == *ok) && (retries < 50)) { /* try again */ retries++; add_peer (); ic = GNUNET_PEERINFO_iterate (h, NULL, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15), &process, cls); return; } GNUNET_assert (peer == NULL); GNUNET_assert (2 == *ok); GNUNET_PEERINFO_disconnect (h); h = NULL; *ok = 0; return; } if (hello != NULL) { GNUNET_assert (3 == *ok); agc = 3; GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &check_it, &agc); GNUNET_assert (agc == 0); *ok = 2; } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { cfg = c; h = GNUNET_PEERINFO_connect (cfg); GNUNET_assert (h != NULL); add_peer (); ic = GNUNET_PEERINFO_iterate (h, NULL, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15), &process, cls); } static int check () { int ok = 3; struct GNUNET_OS_Process *proc; char *const argv[] = { "test-peerinfo-api", "-c", "test_peerinfo_api_data.conf", NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-peerinfo", "gnunet-service-peerinfo", "-c", "test_peerinfo_api_data.conf", NULL); GNUNET_assert (NULL != proc); GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-peerinfo-api", "nohelp", options, &run, &ok); if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); ok = 1; } GNUNET_OS_process_wait (proc); GNUNET_OS_process_destroy (proc); proc = NULL; return ok; } int main (int argc, char *argv[]) { int ret = 0; GNUNET_DISK_directory_remove ("/tmp/test-gnunet-peerinfo"); GNUNET_log_setup ("test_peerinfo_api", "WARNING", NULL); ret = check (); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-peerinfo"); return ret; } /* end of test_peerinfo_api.c */ gnunet-0.9.3/src/peerinfo/peerinfo.h0000644000175000017500000000410111760502551014320 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file peerinfo/peerinfo.h * @brief common internal definitions for peerinfo service * @author Christian Grothoff */ #include "gnunet_crypto_lib.h" #include "gnunet_time_lib.h" #include "gnunet_peerinfo_service.h" GNUNET_NETWORK_STRUCT_BEGIN /** * Message requesting a listing of all known peers, * possibly restricted to the specified peer identity. */ struct ListPeerMessage { /** * Type will be GNUNET_MESSAGE_TYPE_PEERINFO_GET */ struct GNUNET_MessageHeader header; /** * Always zero. */ uint32_t reserved GNUNET_PACKED; /** * Restrict to peers with this identity (optional * field, check header.size!). */ struct GNUNET_PeerIdentity peer; }; /** * Message used to inform the client about * a particular peer; this message is optionally followed * by a HELLO message for the respective peer (if available). * Check the header.size field to see if a HELLO is * present. */ struct InfoMessage { /** * Type will be GNUNET_MESSAGE_TYPE_PEERINFO_INFO */ struct GNUNET_MessageHeader header; /** * Always zero. */ uint32_t reserved GNUNET_PACKED; /** * About which peer are we talking here? */ struct GNUNET_PeerIdentity peer; }; GNUNET_NETWORK_STRUCT_END /* end of peerinfo.h */ gnunet-0.9.3/src/peerinfo/perf_peerinfo_api.c0000644000175000017500000001156311760502551016172 00000000000000/* This file is part of GNUnet. (C) 2004, 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file peerinfo/test_peerinfo_hammer.c * @brief testcase for peerinfo_api.c, hopefully hammer the peerinfo service * @author Nathan Evans */ #include "platform.h" #include "gnunet_hello_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_peerinfo_service.h" #include "gnunet_program_lib.h" #include "gnunet_time_lib.h" #include "peerinfo.h" #include #define START_SERVICE 1 #define NUM_REQUESTS 5000 static const struct GNUNET_CONFIGURATION_Handle *cfg; static struct GNUNET_PEERINFO_IteratorContext *ic[NUM_REQUESTS]; static struct GNUNET_PEERINFO_Handle *h; static unsigned int numpeers; static struct GNUNET_PeerIdentity pid; static int check_it (void *cls, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration) { return GNUNET_OK; } static size_t address_generator (void *cls, size_t max, void *buf) { size_t *agc = cls; size_t ret; char *caddress; struct GNUNET_HELLO_Address address; if (*agc == 0) return 0; GNUNET_asprintf (&caddress, "Address%d", *agc); address.peer = pid; address.address_length = strlen (caddress) + 1; address.address = caddress; address.transport_name = "peerinfotest"; ret = GNUNET_HELLO_add_address (&address, GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS), buf, max); GNUNET_free (caddress); *agc = 0; return ret; } static void add_peer (size_t i) { struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; struct GNUNET_HELLO_Message *h2; memset (&pkey, i, sizeof (pkey)); GNUNET_CRYPTO_hash (&pkey, sizeof (pkey), &pid.hashPubKey); h2 = GNUNET_HELLO_create (&pkey, &address_generator, &i); GNUNET_PEERINFO_add_peer (h, h2, NULL, NULL); GNUNET_free (h2); } static void process (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Message *hello, const char *err_msg) { if (NULL != peer) { numpeers++; if (0 && (hello != NULL)) GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &check_it, NULL); } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { size_t i; cfg = c; h = GNUNET_PEERINFO_connect (cfg); GNUNET_assert (h != NULL); for (i = 0; i < NUM_REQUESTS; i++) { add_peer (i); ic[i] = GNUNET_PEERINFO_iterate (h, NULL, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30), &process, cls); } } static int check () { int ok = 0; char *const argv[] = { "perf-peerinfo-api", "-c", "test_peerinfo_api_data.conf", "-L", "ERROR", NULL }; #if START_SERVICE struct GNUNET_OS_Process *proc; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-peerinfo", "gnunet-service-peerinfo", "-L", "ERROR", "-c", "test_peerinfo_api_data.conf", NULL); #endif GNUNET_assert (NULL != proc); GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "perf-peerinfo-api", "nohelp", options, &run, &ok); FPRINTF (stderr, "Received %u/%u calls before timeout\n", numpeers, NUM_REQUESTS * NUM_REQUESTS / 2); GAUGER ("PEERINFO", "Peerinfo lookups", numpeers / 30, "peers/s"); #if START_SERVICE if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); ok = 1; } GNUNET_OS_process_wait (proc); GNUNET_OS_process_destroy (proc); proc = NULL; #endif return ok; } int main (int argc, char *argv[]) { int ret = 0; GNUNET_DISK_directory_remove ("/tmp/test-gnunet-peerinfo"); GNUNET_log_setup ("perf_peerinfo_api", "ERROR", NULL); ret = check (); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-peerinfo"); return ret; } /* end of perf_peerinfo_api.c */ gnunet-0.9.3/src/peerinfo/peerinfo_api_notify.c0000644000175000017500000001721011760502551016541 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2004, 2005, 2007, 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file peerinfo/peerinfo_api_notify.c * @brief notify API to access peerinfo service * @author Christian Grothoff */ #include "platform.h" #include "gnunet_client_lib.h" #include "gnunet_peerinfo_service.h" #include "gnunet_protocols.h" #include "gnunet_time_lib.h" #include "peerinfo.h" #define LOG(kind,...) GNUNET_log_from (kind, "nse-api",__VA_ARGS__) /** * Context for the info handler. */ struct GNUNET_PEERINFO_NotifyContext { /** * Our connection to the PEERINFO service. */ struct GNUNET_CLIENT_Connection *client; /** * Function to call with information. */ GNUNET_PEERINFO_Processor callback; /** * Closure for callback. */ void *callback_cls; /** * Handle to our initial request for message transmission to * the peerinfo service. */ struct GNUNET_CLIENT_TransmitHandle *init; /** * Configuration. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Tasked used for delayed re-connection attempt. */ GNUNET_SCHEDULER_TaskIdentifier task; }; /** * Send a request to the peerinfo service to start being * notified about all changes to peer information. * * @param nc our context */ static void request_notifications (struct GNUNET_PEERINFO_NotifyContext *nc); /** * Read notifications from the client handle and pass them * to the callback. * * @param nc our context */ static void receive_notifications (struct GNUNET_PEERINFO_NotifyContext *nc); /** * Task to re-try connecting to peerinfo. * * @param cls the 'struct GNUNET_PEERINFO_NotifyContext' * @param tc scheduler context */ static void reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_PEERINFO_NotifyContext *nc = cls; nc->task = GNUNET_SCHEDULER_NO_TASK; nc->client = GNUNET_CLIENT_connect ("peerinfo", nc->cfg); if (NULL == nc->client) { /* ugh */ nc->task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect, nc); return; } request_notifications (nc); } /** * Receive a peerinfo information message, process it and * go for more. * * @param cls closure * @param msg message received, NULL on timeout or fatal error */ static void process_notification (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_PEERINFO_NotifyContext *nc = cls; const struct InfoMessage *im; const struct GNUNET_HELLO_Message *hello; uint16_t ms; if (msg == NULL) { GNUNET_CLIENT_disconnect (nc->client); reconnect (nc, NULL); return; } ms = ntohs (msg->size); if ((ms < sizeof (struct InfoMessage)) || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_PEERINFO_INFO)) { GNUNET_break (0); GNUNET_CLIENT_disconnect (nc->client); nc->client = GNUNET_CLIENT_connect ("peerinfo", nc->cfg); request_notifications (nc); return; } im = (const struct InfoMessage *) msg; hello = NULL; if (ms > sizeof (struct InfoMessage) + sizeof (struct GNUNET_MessageHeader)) { hello = (const struct GNUNET_HELLO_Message *) &im[1]; if (ms != sizeof (struct InfoMessage) + GNUNET_HELLO_size (hello)) { GNUNET_break (0); GNUNET_CLIENT_disconnect (nc->client); nc->client = GNUNET_CLIENT_connect ("peerinfo", nc->cfg); request_notifications (nc); return; } } LOG (GNUNET_ERROR_TYPE_DEBUG, "Received information about peer `%s' from peerinfo database\n", GNUNET_i2s (&im->peer)); nc->callback (nc->callback_cls, &im->peer, hello, NULL); receive_notifications (nc); } /** * Read notifications from the client handle and pass them * to the callback. * * @param nc our context */ static void receive_notifications (struct GNUNET_PEERINFO_NotifyContext *nc) { GNUNET_CLIENT_receive (nc->client, &process_notification, nc, GNUNET_TIME_UNIT_FOREVER_REL); } /** * Transmit our init-notify request, start receiving. * * @param cls closure (our 'struct GNUNET_PEERINFO_NotifyContext') * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_notify_request (void *cls, size_t size, void *buf) { struct GNUNET_PEERINFO_NotifyContext *nc = cls; struct GNUNET_MessageHeader hdr; nc->init = NULL; if (buf == NULL) { GNUNET_CLIENT_disconnect (nc->client); nc->client = GNUNET_CLIENT_connect ("peerinfo", nc->cfg); request_notifications (nc); return 0; } GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); hdr.size = htons (sizeof (struct GNUNET_MessageHeader)); hdr.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_NOTIFY); memcpy (buf, &hdr, sizeof (struct GNUNET_MessageHeader)); receive_notifications (nc); return sizeof (struct GNUNET_MessageHeader); } /** * Send a request to the peerinfo service to start being * notified about all changes to peer information. * * @param nc our context */ static void request_notifications (struct GNUNET_PEERINFO_NotifyContext *nc) { GNUNET_assert (NULL == nc->init); nc->init = GNUNET_CLIENT_notify_transmit_ready (nc->client, sizeof (struct GNUNET_MessageHeader), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &transmit_notify_request, nc); } /** * Call a method whenever our known information about peers * changes. Initially calls the given function for all known * peers and then only signals changes. * * @param cfg configuration to use * @param callback the method to call for each peer * @param callback_cls closure for callback * @return NULL on error */ struct GNUNET_PEERINFO_NotifyContext * GNUNET_PEERINFO_notify (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_PEERINFO_Processor callback, void *callback_cls) { struct GNUNET_PEERINFO_NotifyContext *nc; struct GNUNET_CLIENT_Connection *client; client = GNUNET_CLIENT_connect ("peerinfo", cfg); if (client == NULL) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Could not connect to `%s' service.\n"), "peerinfo"); return NULL; } nc = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_NotifyContext)); nc->cfg = cfg; nc->client = client; nc->callback = callback; nc->callback_cls = callback_cls; request_notifications (nc); return nc; } /** * Stop notifying about changes. * * @param nc context to stop notifying */ void GNUNET_PEERINFO_notify_cancel (struct GNUNET_PEERINFO_NotifyContext *nc) { if (NULL != nc->init) { GNUNET_CLIENT_notify_transmit_ready_cancel (nc->init); nc->init = NULL; } if (NULL != nc->client) GNUNET_CLIENT_disconnect (nc->client); if (GNUNET_SCHEDULER_NO_TASK != nc->task) GNUNET_SCHEDULER_cancel (nc->task); GNUNET_free (nc); } /* end of peerinfo_api_notify.c */ gnunet-0.9.3/src/peerinfo/peerinfo.conf.in0000644000175000017500000000070611760502552015433 00000000000000[peerinfo] AUTOSTART = YES @UNIXONLY@ PORT = 2090 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-peerinfo ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-peerinfo.sock UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES # DISABLE_SOCKET_FORWARDING = NO # USERNAME = # MAXBUF = # TIMEOUT = # DISABLEV6 = # BINDTO = # REJECT_FROM = # REJECT_FROM6 = # PREFIX = HOSTS = $SERVICEHOME/data/hosts/ gnunet-0.9.3/src/peerinfo/Makefile.in0000644000175000017500000007417411762217212014425 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-service-peerinfo$(EXEEXT) check_PROGRAMS = test_peerinfo_api$(EXEEXT) $(am__EXEEXT_1) subdir = src/peerinfo DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/peerinfo.conf.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = peerinfo.conf CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libgnunetpeerinfo_la_DEPENDENCIES = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_libgnunetpeerinfo_la_OBJECTS = peerinfo_api.lo \ peerinfo_api_notify.lo libgnunetpeerinfo_la_OBJECTS = $(am_libgnunetpeerinfo_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunetpeerinfo_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetpeerinfo_la_LDFLAGS) \ $(LDFLAGS) -o $@ @HAVE_BENCHMARKS_TRUE@am__EXEEXT_1 = perf_peerinfo_api$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) am_gnunet_service_peerinfo_OBJECTS = \ gnunet-service-peerinfo.$(OBJEXT) gnunet_service_peerinfo_OBJECTS = \ $(am_gnunet_service_peerinfo_OBJECTS) gnunet_service_peerinfo_DEPENDENCIES = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la am_perf_peerinfo_api_OBJECTS = perf_peerinfo_api.$(OBJEXT) perf_peerinfo_api_OBJECTS = $(am_perf_peerinfo_api_OBJECTS) perf_peerinfo_api_DEPENDENCIES = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_peerinfo_api_OBJECTS = test_peerinfo_api.$(OBJEXT) test_peerinfo_api_OBJECTS = $(am_test_peerinfo_api_OBJECTS) test_peerinfo_api_DEPENDENCIES = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/util/libgnunetutil.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunetpeerinfo_la_SOURCES) \ $(gnunet_service_peerinfo_SOURCES) \ $(perf_peerinfo_api_SOURCES) $(test_peerinfo_api_SOURCES) DIST_SOURCES = $(libgnunetpeerinfo_la_SOURCES) \ $(gnunet_service_peerinfo_SOURCES) \ $(perf_peerinfo_api_SOURCES) $(test_peerinfo_api_SOURCES) DATA = $(pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include pkgcfgdir = $(pkgdatadir)/config.d/ pkgcfg_DATA = \ peerinfo.conf @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -lole32 -lshell32 -liconv -lstdc++ -lcomdlg32 -lgdi32 @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @USE_COVERAGE_TRUE@XLIB = -lgcov lib_LTLIBRARIES = libgnunetpeerinfo.la libgnunetpeerinfo_la_SOURCES = \ peerinfo_api.c peerinfo.h \ peerinfo_api_notify.c libgnunetpeerinfo_la_LIBADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(XLIB) libgnunetpeerinfo_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 0:0:0 gnunet_service_peerinfo_SOURCES = \ gnunet-service-peerinfo.c gnunet_service_peerinfo_LDADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la @HAVE_BENCHMARKS_TRUE@PEERINFO_BENCHMARKS = \ @HAVE_BENCHMARKS_TRUE@ perf_peerinfo_api @ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) test_peerinfo_api_SOURCES = \ test_peerinfo_api.c test_peerinfo_api_LDADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/util/libgnunetutil.la perf_peerinfo_api_SOURCES = \ perf_peerinfo_api.c perf_peerinfo_api_LDADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ test_peerinfo_api_data.conf all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/peerinfo/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/peerinfo/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): peerinfo.conf: $(top_builddir)/config.status $(srcdir)/peerinfo.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunetpeerinfo.la: $(libgnunetpeerinfo_la_OBJECTS) $(libgnunetpeerinfo_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetpeerinfo_la_LINK) -rpath $(libdir) $(libgnunetpeerinfo_la_OBJECTS) $(libgnunetpeerinfo_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-service-peerinfo$(EXEEXT): $(gnunet_service_peerinfo_OBJECTS) $(gnunet_service_peerinfo_DEPENDENCIES) @rm -f gnunet-service-peerinfo$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_service_peerinfo_OBJECTS) $(gnunet_service_peerinfo_LDADD) $(LIBS) perf_peerinfo_api$(EXEEXT): $(perf_peerinfo_api_OBJECTS) $(perf_peerinfo_api_DEPENDENCIES) @rm -f perf_peerinfo_api$(EXEEXT) $(AM_V_CCLD)$(LINK) $(perf_peerinfo_api_OBJECTS) $(perf_peerinfo_api_LDADD) $(LIBS) test_peerinfo_api$(EXEEXT): $(test_peerinfo_api_OBJECTS) $(test_peerinfo_api_DEPENDENCIES) @rm -f test_peerinfo_api$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_peerinfo_api_OBJECTS) $(test_peerinfo_api_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-peerinfo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/peerinfo_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/peerinfo_api_notify.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perf_peerinfo_api.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_peerinfo_api.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgcfgDATA: $(pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgcfgDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-binPROGRAMS install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-pkgcfgDATA install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/peerinfo/peerinfo_api.c0000644000175000017500000005105011760502551015151 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2004, 2005, 2007, 2009, 2010, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file peerinfo/peerinfo_api.c * @brief API to access peerinfo service * @author Christian Grothoff */ #include "platform.h" #include "gnunet_client_lib.h" #include "gnunet_container_lib.h" #include "gnunet_peerinfo_service.h" #include "gnunet_protocols.h" #include "gnunet_time_lib.h" #include "peerinfo.h" #define LOG(kind,...) GNUNET_log_from (kind, "peerinfo-api",__VA_ARGS__) /** * Entry in the transmission queue to PEERINFO service. We use * the same structure for queueing 'iteration' requests and * actual 'add' messages. */ struct GNUNET_PEERINFO_AddContext { /** * This is a linked list. */ struct GNUNET_PEERINFO_AddContext *next; /** * This is a linked list. */ struct GNUNET_PEERINFO_AddContext *prev; /** * Handle to the PEERINFO service. */ struct GNUNET_PEERINFO_Handle *h; /** * Function to call after request has been transmitted, or NULL. */ GNUNET_PEERINFO_Continuation cont; /** * Closure for 'cont'. */ void *cont_cls; /** * Number of bytes of the request message (follows after this struct). */ size_t size; }; /** * Context for an iteration request. */ struct GNUNET_PEERINFO_IteratorContext { /** * Kept in a DLL. */ struct GNUNET_PEERINFO_IteratorContext *next; /** * Kept in a DLL. */ struct GNUNET_PEERINFO_IteratorContext *prev; /** * Handle to the PEERINFO service. */ struct GNUNET_PEERINFO_Handle *h; /** * Function to call with the results. */ GNUNET_PEERINFO_Processor callback; /** * Closure for 'callback'. */ void *callback_cls; /** * Our entry in the transmission queue. */ struct GNUNET_PEERINFO_AddContext *ac; /** * Task responsible for timeout. */ GNUNET_SCHEDULER_TaskIdentifier timeout_task; /** * Timeout for the operation. */ struct GNUNET_TIME_Absolute timeout; /** * Peer we are interested in (only valid if iteration was restricted to one peer). */ struct GNUNET_PeerIdentity peer; /** * Is 'peer' set? */ int have_peer; /** * Are we now receiving? */ int in_receive; }; /** * Handle to the peerinfo service. */ struct GNUNET_PEERINFO_Handle { /** * Our configuration. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Connection to the service. */ struct GNUNET_CLIENT_Connection *client; /** * Head of transmission queue. */ struct GNUNET_PEERINFO_AddContext *ac_head; /** * Tail of transmission queue. */ struct GNUNET_PEERINFO_AddContext *ac_tail; /** * Handle for the current transmission request, or NULL if none is pending. */ struct GNUNET_CLIENT_TransmitHandle *th; /** * Head of iterator DLL. */ struct GNUNET_PEERINFO_IteratorContext *ic_head; /** * Tail of iterator DLL. */ struct GNUNET_PEERINFO_IteratorContext *ic_tail; /** * ID for a reconnect task. */ GNUNET_SCHEDULER_TaskIdentifier r_task; /** * Set to GNUNET_YES if we are currently receiving replies from the * service. */ int in_receive; }; /** * Connect to the peerinfo service. * * @param cfg configuration to use * @return NULL on error (configuration related, actual connection * establishment may happen asynchronously). */ struct GNUNET_PEERINFO_Handle * GNUNET_PEERINFO_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_PEERINFO_Handle *h; h = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_Handle)); h->client = GNUNET_CLIENT_connect ("peerinfo", cfg); h->cfg = cfg; return h; } /** * Disconnect from the peerinfo service. Note that all iterators must * have completed or have been cancelled by the time this function is * called (otherwise, calling this function is a serious error). * Furthermore, if 'GNUNET_PEERINFO_add_peer' operations are still * pending, they will be cancelled silently on disconnect. * * @param h handle to disconnect */ void GNUNET_PEERINFO_disconnect (struct GNUNET_PEERINFO_Handle *h) { struct GNUNET_PEERINFO_AddContext *ac; struct GNUNET_PEERINFO_IteratorContext *ic; while (NULL != (ic = h->ic_head)) { GNUNET_break (GNUNET_YES == ic->in_receive); ic->in_receive = GNUNET_NO; GNUNET_PEERINFO_iterate_cancel (ic); } while (NULL != (ac = h->ac_head)) { GNUNET_CONTAINER_DLL_remove (h->ac_head, h->ac_tail, ac); if (NULL != ac->cont) ac->cont (ac->cont_cls, _("aborted due to explicit disconnect request")); GNUNET_free (ac); } if (NULL != h->th) { GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); h->th = NULL; } if (NULL != h->client) { GNUNET_CLIENT_disconnect (h->client); h->client = NULL; } if (GNUNET_SCHEDULER_NO_TASK != h->r_task) { GNUNET_SCHEDULER_cancel (h->r_task); h->r_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_free (h); } /** * Check if we have a request pending in the transmission queue and are * able to transmit it right now. If so, schedule transmission. * * @param h handle to the service */ static void trigger_transmit (struct GNUNET_PEERINFO_Handle *h); /** * Close the existing connection to PEERINFO and reconnect. * * @param h handle to the service */ static void reconnect (struct GNUNET_PEERINFO_Handle *h); /** * Task scheduled to re-try connecting to the peerinfo service. * * @param cls the 'struct GNUNET_PEERINFO_Handle' * @param tc scheduler context */ static void reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_PEERINFO_Handle *h = cls; h->r_task = GNUNET_SCHEDULER_NO_TASK; reconnect (h); } /** * Close the existing connection to PEERINFO and reconnect. * * @param h handle to the service */ static void reconnect (struct GNUNET_PEERINFO_Handle *h) { if (GNUNET_SCHEDULER_NO_TASK != h->r_task) { GNUNET_SCHEDULER_cancel (h->r_task); h->r_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != h->th) { GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); h->th = NULL; } if (NULL != h->client) { GNUNET_CLIENT_disconnect (h->client); h->client = NULL; } h->in_receive = GNUNET_NO; h->client = GNUNET_CLIENT_connect ("peerinfo", h->cfg); if (NULL == h->client) { h->r_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task, h); return; } trigger_transmit (h); } /** * Transmit the request at the head of the transmission queue * and trigger continuation (if any). * * @param cls the 'struct GNUNET_PEERINFO_Handle' (with the queue) * @param size size of the buffer (0 on error) * @param buf where to copy the message * @return number of bytes copied to buf */ static size_t do_transmit (void *cls, size_t size, void *buf) { struct GNUNET_PEERINFO_Handle *h = cls; struct GNUNET_PEERINFO_AddContext *ac = h->ac_head; size_t ret; h->th = NULL; if (NULL == ac) return 0; /* request was cancelled in the meantime */ if (NULL == buf) { /* peerinfo service died */ LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "Failed to transmit message to `%s' service.\n", "PEERINFO"); GNUNET_CONTAINER_DLL_remove (h->ac_head, h->ac_tail, ac); reconnect (h); if (NULL != ac->cont) ac->cont (ac->cont_cls, _("failed to transmit request (service down?)")); GNUNET_free (ac); return 0; } ret = ac->size; if (size < ret) { /* change in head of queue (i.e. cancel + add), try again */ trigger_transmit (h); return 0; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting request of size %u to `%s' service.\n", ret, "PEERINFO"); memcpy (buf, &ac[1], ret); GNUNET_CONTAINER_DLL_remove (h->ac_head, h->ac_tail, ac); trigger_transmit (h); if (NULL != ac->cont) ac->cont (ac->cont_cls, NULL); GNUNET_free (ac); return ret; } /** * Check if we have a request pending in the transmission queue and are * able to transmit it right now. If so, schedule transmission. * * @param h handle to the service */ static void trigger_transmit (struct GNUNET_PEERINFO_Handle *h) { struct GNUNET_PEERINFO_AddContext *ac; if (NULL == (ac = h->ac_head)) return; /* no requests queued */ if (NULL != h->th) return; /* request already pending */ if (GNUNET_YES == h->in_receive) return; /* still reading replies from last request */ if (NULL == h->client) { /* disconnected, try to reconnect */ reconnect (h); return; } h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, ac->size, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &do_transmit, h); } /** * Add a host to the persistent list. This method operates in * semi-reliable mode: if the transmission is not completed by * the time 'GNUNET_PEERINFO_disconnect' is called, it will be * aborted. Furthermore, if a second HELLO is added for the * same peer before the first one was transmitted, PEERINFO may * merge the two HELLOs prior to transmission to the service. * * @param h handle to the peerinfo service * @param hello the verified (!) HELLO message * @param cont continuation to call when done, NULL is allowed * @param cont_cls closure for 'cont' * @return handle to cancel add operation; all pending * 'add' operations will be cancelled automatically * on disconnect, so it is not necessary to keep this * handle (unless 'cont' is NULL and at some point * calling 'cont' must be prevented) */ struct GNUNET_PEERINFO_AddContext * GNUNET_PEERINFO_add_peer (struct GNUNET_PEERINFO_Handle *h, const struct GNUNET_HELLO_Message *hello, GNUNET_PEERINFO_Continuation cont, void *cont_cls) { uint16_t hs = GNUNET_HELLO_size (hello); struct GNUNET_PEERINFO_AddContext *ac; struct GNUNET_PeerIdentity peer; GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (hello, &peer)); LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding peer `%s' to PEERINFO database (%u bytes of `%s')\n", GNUNET_i2s (&peer), hs, "HELLO"); ac = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_AddContext) + hs); ac->h = h; ac->size = hs; ac->cont = cont; ac->cont_cls = cont_cls; memcpy (&ac[1], hello, hs); GNUNET_CONTAINER_DLL_insert_tail (h->ac_head, h->ac_tail, ac); trigger_transmit (h); return ac; } /** * Cancel pending 'add' operation. Must only be called before * either 'cont' or 'GNUNET_PEERINFO_disconnect' are invoked. * * @param ac handle for the add operation to cancel */ void GNUNET_PEERINFO_add_peer_cancel (struct GNUNET_PEERINFO_AddContext *ac) { struct GNUNET_PEERINFO_Handle *h = ac->h; GNUNET_CONTAINER_DLL_remove (h->ac_head, h->ac_tail, ac); GNUNET_free (ac); } /** * Type of a function to call when we receive a message from the * service. Call the iterator with the result and (if applicable) * continue to receive more messages or trigger processing the next * event (if applicable). * * @param cls closure * @param msg message received, NULL on timeout or fatal error */ static void peerinfo_handler (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_PEERINFO_Handle *h = cls; struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head; const struct InfoMessage *im; const struct GNUNET_HELLO_Message *hello; GNUNET_PEERINFO_Processor cb; struct GNUNET_PeerIdentity id; void *cb_cls; uint16_t ms; GNUNET_assert (NULL != ic); h->in_receive = GNUNET_NO; ic->in_receive = GNUNET_NO; cb = ic->callback; cb_cls = ic->callback_cls; if (NULL == msg) { /* peerinfo service died, signal error */ GNUNET_PEERINFO_iterate_cancel (ic); reconnect (h); if (NULL != cb) cb (cb_cls, NULL, NULL, _("Failed to receive response from `PEERINFO' service.")); return; } if (GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END == ntohs (msg->type)) { /* normal end of list of peers, signal end, process next pending request */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Received end of list of peers from `%s' service\n", "PEERINFO"); GNUNET_PEERINFO_iterate_cancel (ic); trigger_transmit (h); if (NULL != cb) cb (cb_cls, NULL, NULL, NULL); return; } ms = ntohs (msg->size); if ((ms < sizeof (struct InfoMessage)) || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_PEERINFO_INFO)) { /* malformed message */ GNUNET_break (0); GNUNET_PEERINFO_iterate_cancel (ic); reconnect (h); if (NULL != cb) cb (cb_cls, NULL, NULL, _("Received invalid message from `PEERINFO' service.")); return; } im = (const struct InfoMessage *) msg; GNUNET_break (0 == ntohl (im->reserved)); if ( (GNUNET_YES == ic->have_peer) && (0 != memcmp (&ic->peer, &im->peer, sizeof (struct GNUNET_PeerIdentity))) ) { /* bogus message (from a different iteration call?); out of sequence! */ LOG (GNUNET_ERROR_TYPE_ERROR, "Received HELLO for peer `%s', expected peer `%s'\n", GNUNET_h2s (&im->peer.hashPubKey), GNUNET_i2s (&ic->peer)); GNUNET_break (0); GNUNET_PEERINFO_iterate_cancel (ic); reconnect (h); if (NULL != cb) cb (cb_cls, NULL, NULL, _("Received invalid message from `PEERINFO' service.")); return; } hello = NULL; if (ms > sizeof (struct InfoMessage) + sizeof (struct GNUNET_MessageHeader)) { hello = (const struct GNUNET_HELLO_Message *) &im[1]; if (ms != sizeof (struct InfoMessage) + GNUNET_HELLO_size (hello)) { /* malformed message */ GNUNET_break (0); GNUNET_PEERINFO_iterate_cancel (ic); reconnect (h); if (NULL != cb) cb (cb_cls, NULL, NULL, _("Received invalid message from `PEERINFO' service.")); return; } if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &id)) { /* malformed message */ GNUNET_break (0); GNUNET_PEERINFO_iterate_cancel (ic); reconnect (h); if (NULL != cb) cb (cb_cls, NULL, NULL, _("Received invalid message from `PEERINFO' service.")); return; } if (0 != memcmp (&im->peer, &id, sizeof (struct GNUNET_PeerIdentity))) { /* malformed message */ GNUNET_break (0); GNUNET_PEERINFO_iterate_cancel (ic); reconnect (h); if (NULL != cb) cb (cb_cls, NULL, NULL, _("Received invalid message from `PEERINFO' service.")); return; } } /* normal data message */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Received %u bytes of `%s' information about peer `%s' from `%s' service\n", (hello == NULL) ? 0 : (unsigned int) GNUNET_HELLO_size (hello), "HELLO", GNUNET_i2s (&im->peer), "PEERINFO"); h->in_receive = GNUNET_YES; ic->in_receive = GNUNET_YES; GNUNET_CLIENT_receive (h->client, &peerinfo_handler, h, GNUNET_TIME_absolute_get_remaining (ic->timeout)); if (NULL != cb) cb (cb_cls, &im->peer, hello, NULL); } /** * We've transmitted the iteration request. Now get ready to process * the results (or handle transmission error). * * @param cls the 'struct GNUNET_PEERINFO_IteratorContext' * @param emsg error message, NULL if transmission worked */ static void iterator_start_receive (void *cls, const char *emsg) { struct GNUNET_PEERINFO_IteratorContext *ic = cls; struct GNUNET_PEERINFO_Handle *h = ic->h; GNUNET_PEERINFO_Processor cb; void *cb_cls; ic->ac = NULL; if (NULL != emsg) { cb = ic->callback; cb_cls = ic->callback_cls; GNUNET_PEERINFO_iterate_cancel (ic); reconnect (h); if (NULL != cb) cb (cb_cls, NULL, NULL, emsg); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for response from `%s' service.\n", "PEERINFO"); ic->in_receive = GNUNET_YES; if (GNUNET_NO == h->in_receive) { h->in_receive = GNUNET_YES; GNUNET_CLIENT_receive (h->client, &peerinfo_handler, h, GNUNET_TIME_absolute_get_remaining (ic->timeout)); } } /** * Peerinfo iteration request has timed out. * * @param cls the 'struct GNUNET_PEERINFO_IteratorContext*' * @param tc scheduler context */ static void signal_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_PEERINFO_IteratorContext *ic = cls; GNUNET_PEERINFO_Processor cb; void *cb_cls; ic->timeout_task = GNUNET_SCHEDULER_NO_TASK; cb = ic->callback; cb_cls = ic->callback_cls; GNUNET_PEERINFO_iterate_cancel (ic); if (NULL != cb) cb (cb_cls, NULL, NULL, _("Timeout transmitting iteration request to `PEERINFO' service.")); } /** * Call a method for each known matching host and change its trust * value. The callback method will be invoked once for each matching * host and then finally once with a NULL pointer. After that final * invocation, the iterator context must no longer be used. * * Instead of calling this function with 'peer == NULL' it is often * better to use 'GNUNET_PEERINFO_notify'. * * @param h handle to the peerinfo service * @param peer restrict iteration to this peer only (can be NULL) * @param timeout how long to wait until timing out * @param callback the method to call for each peer * @param callback_cls closure for callback * @return iterator context */ struct GNUNET_PEERINFO_IteratorContext * GNUNET_PEERINFO_iterate (struct GNUNET_PEERINFO_Handle *h, const struct GNUNET_PeerIdentity *peer, struct GNUNET_TIME_Relative timeout, GNUNET_PEERINFO_Processor callback, void *callback_cls) { struct GNUNET_MessageHeader *lapm; struct ListPeerMessage *lpm; struct GNUNET_PEERINFO_IteratorContext *ic; struct GNUNET_PEERINFO_AddContext *ac; ic = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_IteratorContext)); if (NULL == peer) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Requesting list of peers from PEERINFO service\n"); ac = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_AddContext) + sizeof (struct GNUNET_MessageHeader)); ac->size = sizeof (struct GNUNET_MessageHeader); lapm = (struct GNUNET_MessageHeader *) &ac[1]; lapm->size = htons (sizeof (struct GNUNET_MessageHeader)); lapm->type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL); } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "Requesting information on peer `%4s' from PEERINFO service\n", GNUNET_i2s (peer)); ac = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_AddContext) + sizeof (struct ListPeerMessage)); ac->size = sizeof (struct ListPeerMessage); lpm = (struct ListPeerMessage *) &ac[1]; lpm->header.size = htons (sizeof (struct ListPeerMessage)); lpm->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_GET); memcpy (&lpm->peer, peer, sizeof (struct GNUNET_PeerIdentity)); ic->have_peer = GNUNET_YES; ic->peer = *peer; } ic->h = h; ic->ac = ac; ic->callback = callback; ic->callback_cls = callback_cls; ic->timeout = GNUNET_TIME_relative_to_absolute (timeout); ic->timeout_task = GNUNET_SCHEDULER_add_delayed (timeout, &signal_timeout, ic); ac->cont = &iterator_start_receive; ac->cont_cls = ic; GNUNET_CONTAINER_DLL_insert_tail (h->ac_head, h->ac_tail, ac); GNUNET_CONTAINER_DLL_insert_tail (h->ic_head, h->ic_tail, ic); trigger_transmit (h); return ic; } /** * Cancel an iteration over peer information. * * @param ic context of the iterator to cancel */ void GNUNET_PEERINFO_iterate_cancel (struct GNUNET_PEERINFO_IteratorContext *ic) { struct GNUNET_PEERINFO_Handle *h; h = ic->h; if (GNUNET_SCHEDULER_NO_TASK != ic->timeout_task) { GNUNET_SCHEDULER_cancel (ic->timeout_task); ic->timeout_task = GNUNET_SCHEDULER_NO_TASK; } ic->callback = NULL; if (GNUNET_YES == ic->in_receive) return; /* need to finish processing */ GNUNET_CONTAINER_DLL_remove (h->ic_head, h->ic_tail, ic); if (NULL != ic->ac) { GNUNET_CONTAINER_DLL_remove (h->ac_head, h->ac_tail, ic->ac); GNUNET_free (ic->ac); } GNUNET_free (ic); } /* end of peerinfo_api.c */ gnunet-0.9.3/src/template/0000755000175000017500000000000011763406747012445 500000000000000gnunet-0.9.3/src/template/gnunet-service-template.c0000644000175000017500000000431411760502551017265 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file template/gnunet-service-template.c * @brief program that tracks template * @author Christian Grothoff */ #include "platform.h" #include "gnunet_getopt_lib.h" #include "gnunet_service_lib.h" /** * Task run during shutdown. * * @param cls unused * @param tc unused */ static void cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { /* FIXME: do clean up here */ } /** * Process template requests. * * @param cls closure * @param server the initialized server * @param cfg configuration to use */ static void run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *cfg) { static const struct GNUNET_SERVER_MessageHandler handlers[] = { /* FIXME: add handlers here! */ {NULL, NULL, 0, 0} }; /* FIXME: do setup here */ GNUNET_SERVER_add_handlers (server, handlers); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, NULL); } /** * The main function for the template service. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { return (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "template", GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; } /* end of gnunet-service-template.c */ gnunet-0.9.3/src/template/Makefile.am0000644000175000017500000000152111654545774014423 00000000000000INCLUDES = -I$(top_srcdir)/src/include pkgcfgdir= $(pkgdatadir)/config.d/ dist_pkgcfg_DATA = \ template.conf if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = -fprofile-arcs -ftest-coverage endif bin_PROGRAMS = \ gnunet-template \ gnunet-service-template gnunet_template_SOURCES = \ gnunet-template.c gnunet_template_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_service_template_SOURCES = \ gnunet-service-template.c gnunet_service_template_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) check_PROGRAMS = \ test_template_api if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) endif test_template_api_SOURCES = \ test_template_api.c test_template_api_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la gnunet-0.9.3/src/template/template.conf0000644000175000017500000000062711654545774015057 00000000000000[template] AUTOSTART = NO PORT = 9999 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-template ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-template.sock UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES # DISABLE_SOCKET_FORWARDING = NO # USERNAME = # MAXBUF = # TIMEOUT = # DISABLEV6 = # BINDTO = # REJECT_FROM = # REJECT_FROM6 = # PREFIX = gnunet-0.9.3/src/template/test_template_api.c0000644000175000017500000000216111760502551016217 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file template/test_template.c * @brief testcase for template.c */ #include "platform.h" #include "gnunet_common.h" #define VERBOSE GNUNET_NO static int check () { return 0; } int main (int argc, char *argv[]) { int ret; ret = check (); return ret; } /* end of test_template.c */ gnunet-0.9.3/src/template/gnunet-template.c0000644000175000017500000000411211760502551015623 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file template/gnunet-template.c * @brief template for writing a tool * @author Christian Grothoff */ #include "platform.h" #include "gnunet_getopt_lib.h" #include "gnunet_program_lib.h" /* #include "gnunet_template_service.h" */ /** * Final status code. */ static int ret; /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param cfg configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { /* main code here */ } /** * The main function. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { /* FIMXE: add options here */ GNUNET_GETOPT_OPTION_END }; return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-template", gettext_noop ("help text"), options, &run, NULL)) ? ret : 1; } /* end of gnunet-template.c */ gnunet-0.9.3/src/template/Makefile.in0000644000175000017500000006472511762217213014433 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-template$(EXEEXT) \ gnunet-service-template$(EXEEXT) check_PROGRAMS = test_template_api$(EXEEXT) subdir = src/template DIST_COMMON = $(dist_pkgcfg_DATA) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" PROGRAMS = $(bin_PROGRAMS) am_gnunet_service_template_OBJECTS = \ gnunet-service-template.$(OBJEXT) gnunet_service_template_OBJECTS = \ $(am_gnunet_service_template_OBJECTS) am__DEPENDENCIES_1 = gnunet_service_template_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent am_gnunet_template_OBJECTS = gnunet-template.$(OBJEXT) gnunet_template_OBJECTS = $(am_gnunet_template_OBJECTS) gnunet_template_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_test_template_api_OBJECTS = test_template_api.$(OBJEXT) test_template_api_OBJECTS = $(am_test_template_api_OBJECTS) test_template_api_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(gnunet_service_template_SOURCES) \ $(gnunet_template_SOURCES) $(test_template_api_SOURCES) DIST_SOURCES = $(gnunet_service_template_SOURCES) \ $(gnunet_template_SOURCES) $(test_template_api_SOURCES) am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' DATA = $(dist_pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include pkgcfgdir = $(pkgdatadir)/config.d/ dist_pkgcfg_DATA = \ template.conf @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = -fprofile-arcs -ftest-coverage gnunet_template_SOURCES = \ gnunet-template.c gnunet_template_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_service_template_SOURCES = \ gnunet-service-template.c gnunet_service_template_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) @ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) test_template_api_SOURCES = \ test_template_api.c test_template_api_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/template/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/template/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-service-template$(EXEEXT): $(gnunet_service_template_OBJECTS) $(gnunet_service_template_DEPENDENCIES) @rm -f gnunet-service-template$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_service_template_OBJECTS) $(gnunet_service_template_LDADD) $(LIBS) gnunet-template$(EXEEXT): $(gnunet_template_OBJECTS) $(gnunet_template_DEPENDENCIES) @rm -f gnunet-template$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_template_OBJECTS) $(gnunet_template_LDADD) $(LIBS) test_template_api$(EXEEXT): $(test_template_api_OBJECTS) $(test_template_api_DEPENDENCIES) @rm -f test_template_api$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_template_api_OBJECTS) $(test_template_api_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-template.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-template.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_template_api.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_pkgcfgDATA: $(dist_pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-dist_pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(PROGRAMS) $(DATA) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_pkgcfgDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-dist_pkgcfgDATA .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libtool ctags distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-binPROGRAMS install-data install-data-am \ install-dist_pkgcfgDATA install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-dist_pkgcfgDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/datacache/0000755000175000017500000000000011763406747012527 500000000000000gnunet-0.9.3/src/datacache/datacache.conf0000644000175000017500000000026611662766715015221 00000000000000[datacache-mysql] DATABASE = gnunet CONFIG = ~/.my.cnf # USER = gnunet # PASSWORD = # HOST = localhost # PORT = 3306 [datacache-postgres] CONFIG = connect_timeout=10; dbname=gnunet gnunet-0.9.3/src/datacache/test_datacache_data_mysql.conf0000644000175000017500000000022511654602262020454 00000000000000[testcache] QUOTA = 1 MB DATABASE = mysql [datacache-mysql] DATABASE = gnunetcheck # CONFIG = ~/.my.cnf # USER = # PASSWORD = # HOST = # PORT = gnunet-0.9.3/src/datacache/Makefile.am0000644000175000017500000001215411733356070014474 00000000000000INCLUDES = -I$(top_srcdir)/src/include plugindir = $(libdir)/gnunet pkgcfgdir= $(pkgdatadir)/config.d/ dist_pkgcfg_DATA = \ datacache.conf if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIBS = -lgcov endif if HAVE_SQLITE SQLITE_PLUGIN = libgnunet_plugin_datacache_sqlite.la endif if HAVE_MYSQL MYSQL_PLUGIN = libgnunet_plugin_datacache_mysql.la endif if HAVE_POSTGRES POSTGRES_PLUGIN = libgnunet_plugin_datacache_postgres.la endif lib_LTLIBRARIES = \ libgnunetdatacache.la libgnunetdatacache_la_SOURCES = \ datacache.c libgnunetdatacache_la_LIBADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) libgnunetdatacache_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 0:1:0 plugin_LTLIBRARIES = \ $(SQLITE_PLUGIN) \ $(MYSQL_PLUGIN) \ $(POSTGRES_PLUGIN) \ libgnunet_plugin_datacache_template.la libgnunet_plugin_datacache_sqlite_la_SOURCES = \ plugin_datacache_sqlite.c libgnunet_plugin_datacache_sqlite_la_LIBADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 libgnunet_plugin_datacache_sqlite_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_datacache_mysql_la_SOURCES = \ plugin_datacache_mysql.c libgnunet_plugin_datacache_mysql_la_LIBADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/mysql/libgnunetmysql.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_PLUGIN_LDFLAGS) $(MYSQL_LDFLAGS) -lmysqlclient libgnunet_plugin_datacache_mysql_la_CPPFLAGS = \ $(MYSQL_CPPFLAGS) libgnunet_plugin_datacache_mysql_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) $(MYSQL_LDFLAGS) -lmysqlclient libgnunet_plugin_datacache_postgres_la_SOURCES = \ plugin_datacache_postgres.c libgnunet_plugin_datacache_postgres_la_LIBADD = \ $(top_builddir)/src/postgres/libgnunetpostgres.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_PLUGIN_LDFLAGS) $(POSTGRES_LDFLAGS) -lpq libgnunet_plugin_datacache_postgres_la_CPPFLAGS = \ $(POSTGRES_CPPFLAGS) libgnunet_plugin_datacache_postgres_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) $(POSTGRES_LDFLAGS) -lpq libgnunet_plugin_datacache_template_la_SOURCES = \ plugin_datacache_template.c libgnunet_plugin_datacache_template_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) libgnunet_plugin_datacache_template_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) if HAVE_SQLITE if HAVE_BENCHMARKS SQLITE_BENCHMARKS = \ perf_datacache_sqlite endif SQLITE_TESTS = \ test_datacache_sqlite \ test_datacache_quota_sqlite \ $(SQLITE_BENCHMARKS) endif if HAVE_MYSQL if HAVE_BENCHMARKS MYSQL_BENCHMARKS = \ perf_datacache_mysql endif MYSQL_TESTS = \ test_datacache_mysql \ test_datacache_quota_mysql \ $(MYSQL_BENCHMARKS) endif if HAVE_POSTGRES if HAVE_BENCHMARKS POSTGRES_BENCHMARKS = \ perf_datacache_postgres endif POSTGRES_TESTS = \ test_datacache_postgres \ test_datacache_quota_postgres \ $(POSTGRES_BENCHMARKS) endif check_PROGRAMS = \ $(SQLITE_TESTS) \ $(MYSQL_TESTS) \ $(POSTGRES_TESTS) if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) endif test_datacache_sqlite_SOURCES = \ test_datacache.c test_datacache_sqlite_LDADD = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la test_datacache_quota_sqlite_SOURCES = \ test_datacache_quota.c test_datacache_quota_sqlite_LDADD = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la perf_datacache_sqlite_SOURCES = \ perf_datacache.c perf_datacache_sqlite_LDADD = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la test_datacache_mysql_SOURCES = \ test_datacache.c test_datacache_mysql_LDADD = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la test_datacache_quota_mysql_SOURCES = \ test_datacache_quota.c test_datacache_quota_mysql_LDADD = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la perf_datacache_mysql_SOURCES = \ perf_datacache.c perf_datacache_mysql_LDADD = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la test_datacache_postgres_SOURCES = \ test_datacache.c test_datacache_postgres_LDADD = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la test_datacache_quota_postgres_SOURCES = \ test_datacache_quota.c test_datacache_quota_postgres_LDADD = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la perf_datacache_postgres_SOURCES = \ perf_datacache.c perf_datacache_postgres_LDADD = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ test_datacache_data_sqlite.conf \ perf_datacache_data_sqlite.conf \ test_datacache_data_mysql.conf \ perf_datacache_data_mysql.conf \ test_datacache_data_postgres.conf \ perf_datacache_data_postgres.conf gnunet-0.9.3/src/datacache/perf_datacache_data_sqlite.conf0000644000175000017500000000005611654602345020571 00000000000000[perfcache] QUOTA = 500 KB DATABASE = sqlite gnunet-0.9.3/src/datacache/test_datacache_data_postgres.conf0000644000175000017500000000016511654602305021156 00000000000000 [testcache] QUOTA = 1 MB DATABASE = postgres [datacache-postgres] CONFIG = connect_timeout=10; dbname=gnunetcheck gnunet-0.9.3/src/datacache/perf_datacache_data_mysql.conf0000644000175000017500000000022711654602333020432 00000000000000[perfcache] QUOTA = 500 KB DATABASE = mysql [datacache-mysql] DATABASE = gnunetcheck # CONFIG = ~/.my.cnf # USER = # PASSWORD = # HOST = # PORT = gnunet-0.9.3/src/datacache/perf_datacache.c0000644000175000017500000001177711760502551015524 00000000000000/* This file is part of GNUnet. (C) 2006, 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * @file datacache/perf_datacache.c * @brief Performance evaluation for the datacache implementations. * @author Nils Durner */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_datacache_lib.h" #include #define VERBOSE GNUNET_NO #define ASSERT(x) do { if (! (x)) { printf("Error at %s:%d\n", __FILE__, __LINE__); goto FAILURE;} } while (0) #define ITERATIONS 10000 static int ok; static unsigned int found; /** * Name of plugin under test. */ static const char *plugin_name; static int checkIt (void *cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, size_t size, const char *data, enum GNUNET_BLOCK_Type type) { if ((size == sizeof (GNUNET_HashCode)) && (0 == memcmp (data, cls, size))) found++; return GNUNET_OK; } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_DATACACHE_Handle *h; GNUNET_HashCode k; GNUNET_HashCode n; struct GNUNET_TIME_Absolute exp; struct GNUNET_TIME_Absolute start; unsigned int i; char gstr[128]; ok = 0; h = GNUNET_DATACACHE_create (cfg, "perfcache"); if (h == NULL) { FPRINTF (stderr, "%s", "Failed to initialize datacache. Database likely not setup, skipping test.\n"); return; } exp = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS); start = GNUNET_TIME_absolute_get (); memset (&k, 0, sizeof (GNUNET_HashCode)); for (i = 0; i < ITERATIONS; i++) { if (0 == i % (ITERATIONS / 80)) FPRINTF (stderr, "%s", "."); GNUNET_CRYPTO_hash (&k, sizeof (GNUNET_HashCode), &n); ASSERT (GNUNET_OK == GNUNET_DATACACHE_put (h, &k, sizeof (GNUNET_HashCode), (const char *) &n, 1 + i % 16, exp)); k = n; } FPRINTF (stderr, "%s", "\n"); FPRINTF (stdout, "Stored %u items in %llums\n", ITERATIONS, (unsigned long long) GNUNET_TIME_absolute_get_duration (start).rel_value); GNUNET_snprintf (gstr, sizeof (gstr), "DATACACHE-%s", plugin_name); GAUGER (gstr, "Time to PUT item in datacache", GNUNET_TIME_absolute_get_duration (start).rel_value / ITERATIONS, "ms/item"); start = GNUNET_TIME_absolute_get (); memset (&k, 0, sizeof (GNUNET_HashCode)); for (i = 0; i < ITERATIONS; i++) { if (0 == i % (ITERATIONS / 80)) FPRINTF (stderr, "%s", "."); GNUNET_CRYPTO_hash (&k, sizeof (GNUNET_HashCode), &n); GNUNET_DATACACHE_get (h, &k, 1 + i % 16, &checkIt, &n); k = n; } FPRINTF (stderr, "%s", "\n"); FPRINTF (stdout, "Found %u/%u items in %llums (%u were deleted during storage processing)\n", found, ITERATIONS, (unsigned long long) GNUNET_TIME_absolute_get_duration (start).rel_value, ITERATIONS - found); if (found > 0) GAUGER (gstr, "Time to GET item from datacache", GNUNET_TIME_absolute_get_duration (start).rel_value / found, "ms/item"); GNUNET_DATACACHE_destroy (h); ASSERT (ok == 0); return; FAILURE: if (h != NULL) GNUNET_DATACACHE_destroy (h); ok = GNUNET_SYSERR; } int main (int argc, char *argv[]) { char *pos; char cfg_name[128]; char *const xargv[] = { "perf-datacache", "-c", cfg_name, #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("perf-datacache", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); /* determine name of plugin to use */ plugin_name = argv[0]; while (NULL != (pos = strstr (plugin_name, "_"))) plugin_name = pos + 1; if (NULL != (pos = strstr (plugin_name, "."))) pos[0] = 0; else pos = (char *) plugin_name; GNUNET_snprintf (cfg_name, sizeof (cfg_name), "perf_datacache_data_%s.conf", plugin_name); if (pos != plugin_name) pos[0] = '.'; GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1, xargv, "perf-datacache", "nohelp", options, &run, NULL); if (ok != 0) FPRINTF (stderr, "Missed some perfcases: %d\n", ok); return ok; } /* end of perf_datacache.c */ gnunet-0.9.3/src/datacache/test_datacache_quota.c0000644000175000017500000001024711760502551016747 00000000000000/* This file is part of GNUnet. (C) 2006, 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * @file datacache/test_datacache_quota.c * @brief Test for the quota code of the datacache implementations. * @author Nils Durner */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_datacache_lib.h" #define VERBOSE GNUNET_NO #define ASSERT(x) do { if (! (x)) { printf("Error at %s:%d\n", __FILE__, __LINE__); goto FAILURE;} } while (0) static int ok; /** * Name of plugin under test. */ static const char *plugin_name; /** * Quota is 1 MB. Each iteration of the test puts in about 1 MB of * data. We do 10 iterations. Afterwards we check that the data from * the first 5 iterations has all been discarded and that at least * some of the data from the last iteration is still there. */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_DATACACHE_Handle *h; GNUNET_HashCode k; GNUNET_HashCode n; unsigned int i; unsigned int j; char buf[3200]; struct GNUNET_TIME_Absolute exp; ok = 0; h = GNUNET_DATACACHE_create (cfg, "testcache"); if (h == NULL) { FPRINTF (stderr, "%s", "Failed to initialize datacache. Database likely not setup, skipping test.\n"); return; } exp = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS); memset (buf, 1, sizeof (buf)); memset (&k, 0, sizeof (GNUNET_HashCode)); for (i = 0; i < 10; i++) { FPRINTF (stderr, "%s", "."); GNUNET_CRYPTO_hash (&k, sizeof (GNUNET_HashCode), &n); for (j = i; j < sizeof (buf); j += 10) { exp.abs_value++; buf[j] = i; ASSERT (GNUNET_OK == GNUNET_DATACACHE_put (h, &k, j, buf, 1 + i, exp)); ASSERT (0 < GNUNET_DATACACHE_get (h, &k, 1 + i, NULL, NULL)); } k = n; } FPRINTF (stderr, "%s", "\n"); memset (&k, 0, sizeof (GNUNET_HashCode)); for (i = 0; i < 10; i++) { FPRINTF (stderr, "%s", "."); GNUNET_CRYPTO_hash (&k, sizeof (GNUNET_HashCode), &n); if (i < 2) ASSERT (0 == GNUNET_DATACACHE_get (h, &k, 1 + i, NULL, NULL)); if (i == 9) ASSERT (0 < GNUNET_DATACACHE_get (h, &k, 1 + i, NULL, NULL)); k = n; } FPRINTF (stderr, "%s", "\n"); GNUNET_DATACACHE_destroy (h); return; FAILURE: if (h != NULL) GNUNET_DATACACHE_destroy (h); ok = GNUNET_SYSERR; } int main (int argc, char *argv[]) { char *pos; char cfg_name[128]; char *const xargv[] = { "test-datacache-quota", "-c", cfg_name, #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("test-datacache-quota", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); /* determine name of plugin to use */ plugin_name = argv[0]; while (NULL != (pos = strstr (plugin_name, "_"))) plugin_name = pos + 1; if (NULL != (pos = strstr (plugin_name, "."))) pos[0] = 0; else pos = (char *) plugin_name; GNUNET_snprintf (cfg_name, sizeof (cfg_name), "test_datacache_data_%s.conf", plugin_name); if (pos != plugin_name) pos[0] = '.'; GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1, xargv, "test-datacache-quota", "nohelp", options, &run, NULL); if (ok != 0) FPRINTF (stderr, "Missed some testcases: %d\n", ok); return ok; } /* end of test_datacache_quota.c */ gnunet-0.9.3/src/datacache/test_datacache_data_sqlite.conf0000644000175000017500000000005511654602272020612 00000000000000[testcache] QUOTA = 1 MB DATABASE = sqlite gnunet-0.9.3/src/datacache/plugin_datacache_sqlite.c0000644000175000017500000003457511760502551017450 00000000000000/* This file is part of GNUnet (C) 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file datacache/plugin_datacache_sqlite.c * @brief sqlite for an implementation of a database backend for the datacache * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_datacache_plugin.h" #include #define LOG(kind,...) GNUNET_log_from (kind, "datacache-sqlite", __VA_ARGS__) #define LOG_STRERROR_FILE(kind,op,fn) GNUNET_log_from_strerror_file (kind, "datacache-sqlite", op, fn) /** * How much overhead do we assume per entry in the * datacache? */ #define OVERHEAD (sizeof(GNUNET_HashCode) + 32) /** * Context for all functions in this plugin. */ struct Plugin { /** * Our execution environment. */ struct GNUNET_DATACACHE_PluginEnvironment *env; /** * Handle to the sqlite database. */ sqlite3 *dbh; /** * Filename used for the DB. */ char *fn; }; /** * Log an error message at log-level 'level' that indicates * a failure of the command 'cmd' on file 'filename' * with the message given by strerror(errno). */ #define LOG_SQLITE(db, level, cmd) do { LOG (level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db)); } while(0) #define SQLITE3_EXEC(db, cmd) do { emsg = NULL; if (SQLITE_OK != sqlite3_exec(db, cmd, NULL, NULL, &emsg)) { LOG (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, _("`%s' failed at %s:%d with error: %s\n"), "sqlite3_exec", __FILE__, __LINE__, emsg); sqlite3_free(emsg); } } while(0) /** * @brief Prepare a SQL statement */ static int sq_prepare (sqlite3 * dbh, const char *zSql, /* SQL statement, UTF-8 encoded */ sqlite3_stmt ** ppStmt) { /* OUT: Statement handle */ char *dummy; return sqlite3_prepare (dbh, zSql, strlen (zSql), ppStmt, (const char **) &dummy); } /** * Store an item in the datastore. * * @param cls closure (our "struct Plugin") * @param key key to store data under * @param size number of bytes in data * @param data data to store * @param type type of the value * @param discard_time when to discard the value in any case * @return 0 on error, number of bytes used otherwise */ static size_t sqlite_plugin_put (void *cls, const GNUNET_HashCode * key, size_t size, const char *data, enum GNUNET_BLOCK_Type type, struct GNUNET_TIME_Absolute discard_time) { struct Plugin *plugin = cls; sqlite3_stmt *stmt; int64_t dval; LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' of %u bytes with key `%4s' and expiration %llums\n", "PUT", (unsigned int) size, GNUNET_h2s (key), (unsigned long long) GNUNET_TIME_absolute_get_remaining (discard_time).rel_value); dval = (int64_t) discard_time.abs_value; if (dval < 0) dval = INT64_MAX; if (sq_prepare (plugin->dbh, "INSERT INTO ds090 (type, expire, key, value) VALUES (?, ?, ?, ?)", &stmt) != SQLITE_OK) { LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sq_prepare"); return 0; } if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, type)) || (SQLITE_OK != sqlite3_bind_int64 (stmt, 2, dval)) || (SQLITE_OK != sqlite3_bind_blob (stmt, 3, key, sizeof (GNUNET_HashCode), SQLITE_TRANSIENT)) || (SQLITE_OK != sqlite3_bind_blob (stmt, 4, data, size, SQLITE_TRANSIENT))) { LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_xxx"); sqlite3_finalize (stmt); return 0; } if (SQLITE_DONE != sqlite3_step (stmt)) { LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); sqlite3_finalize (stmt); return 0; } if (SQLITE_OK != sqlite3_finalize (stmt)) LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_finalize"); return size + OVERHEAD; } /** * Iterate over the results for a particular key * in the datastore. * * @param cls closure (our "struct Plugin") * @param key * @param type entries of which type are relevant? * @param iter maybe NULL (to just count) * @param iter_cls closure for iter * @return the number of results found */ static unsigned int sqlite_plugin_get (void *cls, const GNUNET_HashCode * key, enum GNUNET_BLOCK_Type type, GNUNET_DATACACHE_Iterator iter, void *iter_cls) { struct Plugin *plugin = cls; sqlite3_stmt *stmt; struct GNUNET_TIME_Absolute now; struct GNUNET_TIME_Absolute exp; unsigned int size; const char *dat; unsigned int cnt; unsigned int off; unsigned int total; char scratch[256]; int64_t ntime; now = GNUNET_TIME_absolute_get (); LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s' for key `%4s'\n", "GET", GNUNET_h2s (key)); if (sq_prepare (plugin->dbh, "SELECT count(*) FROM ds090 WHERE key=? AND type=? AND expire >= ?", &stmt) != SQLITE_OK) { LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sq_prepare"); return 0; } ntime = (int64_t) now.abs_value; GNUNET_assert (ntime >= 0); if ((SQLITE_OK != sqlite3_bind_blob (stmt, 1, key, sizeof (GNUNET_HashCode), SQLITE_TRANSIENT)) || (SQLITE_OK != sqlite3_bind_int (stmt, 2, type)) || (SQLITE_OK != sqlite3_bind_int64 (stmt, 3, now.abs_value))) { LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_xxx"); sqlite3_finalize (stmt); return 0; } if (SQLITE_ROW != sqlite3_step (stmt)) { LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite_step"); sqlite3_finalize (stmt); LOG (GNUNET_ERROR_TYPE_DEBUG, "No content found when processing `%s' for key `%4s'\n", "GET", GNUNET_h2s (key)); return 0; } total = sqlite3_column_int (stmt, 0); sqlite3_finalize (stmt); if ((total == 0) || (iter == NULL)) { if (0 == total) LOG (GNUNET_ERROR_TYPE_DEBUG, "No content found when processing `%s' for key `%4s'\n", "GET", GNUNET_h2s (key)); return total; } cnt = 0; off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total); while (cnt < total) { off = (off + 1) % total; GNUNET_snprintf (scratch, sizeof (scratch), "SELECT value,expire FROM ds090 WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET %u", off); if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK) { LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sq_prepare"); return cnt; } if ((SQLITE_OK != sqlite3_bind_blob (stmt, 1, key, sizeof (GNUNET_HashCode), SQLITE_TRANSIENT)) || (SQLITE_OK != sqlite3_bind_int (stmt, 2, type)) || (SQLITE_OK != sqlite3_bind_int64 (stmt, 3, now.abs_value))) { LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_xxx"); sqlite3_finalize (stmt); return cnt; } if (sqlite3_step (stmt) != SQLITE_ROW) break; size = sqlite3_column_bytes (stmt, 0); dat = sqlite3_column_blob (stmt, 0); exp.abs_value = sqlite3_column_int64 (stmt, 1); ntime = (int64_t) exp.abs_value; if (ntime == INT64_MAX) exp = GNUNET_TIME_UNIT_FOREVER_ABS; cnt++; LOG (GNUNET_ERROR_TYPE_DEBUG, "Found %u-byte result when processing `%s' for key `%4s'\n", (unsigned int) size, "GET", GNUNET_h2s (key)); if (GNUNET_OK != iter (iter_cls, exp, key, size, dat, type)) { sqlite3_finalize (stmt); break; } sqlite3_finalize (stmt); } return cnt; } /** * Delete the entry with the lowest expiration value * from the datacache right now. * * @param cls closure (our "struct Plugin") * @return GNUNET_OK on success, GNUNET_SYSERR on error */ static int sqlite_plugin_del (void *cls) { struct Plugin *plugin = cls; unsigned long long rowid; unsigned int dsize; sqlite3_stmt *stmt; sqlite3_stmt *dstmt; GNUNET_HashCode hc; LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing `%s'\n", "DEL"); stmt = NULL; dstmt = NULL; if (sq_prepare (plugin->dbh, "SELECT _ROWID_,key,value FROM ds090 ORDER BY expire ASC LIMIT 1", &stmt) != SQLITE_OK) { LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sq_prepare"); if (stmt != NULL) (void) sqlite3_finalize (stmt); return GNUNET_SYSERR; } if (SQLITE_ROW != sqlite3_step (stmt)) { LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); (void) sqlite3_finalize (stmt); return GNUNET_SYSERR; } rowid = sqlite3_column_int64 (stmt, 0); GNUNET_assert (sqlite3_column_bytes (stmt, 1) == sizeof (GNUNET_HashCode)); memcpy (&hc, sqlite3_column_blob (stmt, 1), sizeof (GNUNET_HashCode)); dsize = sqlite3_column_bytes (stmt, 2); if (SQLITE_OK != sqlite3_finalize (stmt)) LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); if (sq_prepare (plugin->dbh, "DELETE FROM ds090 WHERE _ROWID_=?", &dstmt) != SQLITE_OK) { LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sq_prepare"); if (stmt != NULL) (void) sqlite3_finalize (stmt); return GNUNET_SYSERR; } if (SQLITE_OK != sqlite3_bind_int64 (dstmt, 1, rowid)) { LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind"); (void) sqlite3_finalize (dstmt); return GNUNET_SYSERR; } if (sqlite3_step (dstmt) != SQLITE_DONE) { LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); (void) sqlite3_finalize (dstmt); return GNUNET_SYSERR; } plugin->env->delete_notify (plugin->env->cls, &hc, dsize + OVERHEAD); if (SQLITE_OK != sqlite3_finalize (dstmt)) LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_finalize"); return GNUNET_OK; } /** * Entry point for the plugin. * * @param cls closure (the "struct GNUNET_DATACACHE_PluginEnvironmnet") * @return the plugin's closure (our "struct Plugin") */ void * libgnunet_plugin_datacache_sqlite_init (void *cls) { struct GNUNET_DATACACHE_PluginEnvironment *env = cls; struct GNUNET_DATACACHE_PluginFunctions *api; struct Plugin *plugin; char *fn; char *fn_utf8; sqlite3 *dbh; char *emsg; fn = GNUNET_DISK_mktemp ("gnunet-datacache"); if (fn == NULL) { GNUNET_break (0); return NULL; } #ifdef ENABLE_NLS fn_utf8 = GNUNET_STRINGS_to_utf8 (fn, strlen (fn), nl_langinfo (CODESET)); #else /* good luck */ fn_utf8 = GNUNET_STRINGS_to_utf8 (fn, strlen (fn), "UTF-8"); #endif if (SQLITE_OK != sqlite3_open (fn_utf8, &dbh)) { GNUNET_free (fn); GNUNET_free (fn_utf8); return NULL; } GNUNET_free (fn); SQLITE3_EXEC (dbh, "PRAGMA temp_store=MEMORY"); SQLITE3_EXEC (dbh, "PRAGMA locking_mode=EXCLUSIVE"); SQLITE3_EXEC (dbh, "PRAGMA journal_mode=OFF"); SQLITE3_EXEC (dbh, "PRAGMA synchronous=OFF"); SQLITE3_EXEC (dbh, "PRAGMA count_changes=OFF"); SQLITE3_EXEC (dbh, "PRAGMA page_size=4092"); SQLITE3_EXEC (dbh, "CREATE TABLE ds090 (" " type INTEGER NOT NULL DEFAULT 0," " expire INTEGER NOT NULL DEFAULT 0," " key BLOB NOT NULL DEFAULT ''," " value BLOB NOT NULL DEFAULT '')"); SQLITE3_EXEC (dbh, "CREATE INDEX idx_hashidx ON ds090 (key,type,expire)"); SQLITE3_EXEC (dbh, "CREATE INDEX idx_expire ON ds090 (expire)"); plugin = GNUNET_malloc (sizeof (struct Plugin)); plugin->env = env; plugin->dbh = dbh; plugin->fn = fn_utf8; api = GNUNET_malloc (sizeof (struct GNUNET_DATACACHE_PluginFunctions)); api->cls = plugin; api->get = &sqlite_plugin_get; api->put = &sqlite_plugin_put; api->del = &sqlite_plugin_del; LOG (GNUNET_ERROR_TYPE_INFO, _("Sqlite datacache running\n")); return api; } /** * Exit point from the plugin. * * @param cls closure (our "struct Plugin") * @return NULL */ void * libgnunet_plugin_datacache_sqlite_done (void *cls) { struct GNUNET_DATACACHE_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; int result; #if SQLITE_VERSION_NUMBER >= 3007000 sqlite3_stmt *stmt; #endif #if !WINDOWS || defined(__CYGWIN__) if (0 != UNLINK (plugin->fn)) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", plugin->fn); GNUNET_free (plugin->fn); #endif result = sqlite3_close (plugin->dbh); #if SQLITE_VERSION_NUMBER >= 3007000 if (result == SQLITE_BUSY) { LOG (GNUNET_ERROR_TYPE_WARNING, _ ("Tried to close sqlite without finalizing all prepared statements.\n")); stmt = sqlite3_next_stmt (plugin->dbh, NULL); while (stmt != NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Closing statement %p\n", stmt); result = sqlite3_finalize (stmt); if (result != SQLITE_OK) LOG (GNUNET_ERROR_TYPE_WARNING, _("Failed to close statement %p: %d\n"), stmt, result); stmt = sqlite3_next_stmt (plugin->dbh, NULL); } result = sqlite3_close (plugin->dbh); } #endif if (SQLITE_OK != result) LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close"); #if WINDOWS && !defined(__CYGWIN__) if (0 != UNLINK (plugin->fn)) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", plugin->fn); GNUNET_free (plugin->fn); #endif GNUNET_free (plugin); GNUNET_free (api); return NULL; } /* end of plugin_datacache_sqlite.c */ gnunet-0.9.3/src/datacache/Makefile.in0000644000175000017500000013263411762217211014506 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ check_PROGRAMS = $(am__EXEEXT_2) $(am__EXEEXT_4) $(am__EXEEXT_6) subdir = src/datacache DIST_COMMON = $(dist_pkgcfg_DATA) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \ "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) $(plugin_LTLIBRARIES) am__DEPENDENCIES_1 = libgnunet_plugin_datacache_mysql_la_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/mysql/libgnunetmysql.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am_libgnunet_plugin_datacache_mysql_la_OBJECTS = \ libgnunet_plugin_datacache_mysql_la-plugin_datacache_mysql.lo libgnunet_plugin_datacache_mysql_la_OBJECTS = \ $(am_libgnunet_plugin_datacache_mysql_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunet_plugin_datacache_mysql_la_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libgnunet_plugin_datacache_mysql_la_LDFLAGS) $(LDFLAGS) -o \ $@ @HAVE_MYSQL_TRUE@am_libgnunet_plugin_datacache_mysql_la_rpath = \ @HAVE_MYSQL_TRUE@ -rpath $(plugindir) libgnunet_plugin_datacache_postgres_la_DEPENDENCIES = \ $(top_builddir)/src/postgres/libgnunetpostgres.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am_libgnunet_plugin_datacache_postgres_la_OBJECTS = libgnunet_plugin_datacache_postgres_la-plugin_datacache_postgres.lo libgnunet_plugin_datacache_postgres_la_OBJECTS = \ $(am_libgnunet_plugin_datacache_postgres_la_OBJECTS) libgnunet_plugin_datacache_postgres_la_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libgnunet_plugin_datacache_postgres_la_LDFLAGS) $(LDFLAGS) \ -o $@ @HAVE_POSTGRES_TRUE@am_libgnunet_plugin_datacache_postgres_la_rpath = \ @HAVE_POSTGRES_TRUE@ -rpath $(plugindir) libgnunet_plugin_datacache_sqlite_la_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_libgnunet_plugin_datacache_sqlite_la_OBJECTS = \ plugin_datacache_sqlite.lo libgnunet_plugin_datacache_sqlite_la_OBJECTS = \ $(am_libgnunet_plugin_datacache_sqlite_la_OBJECTS) libgnunet_plugin_datacache_sqlite_la_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libgnunet_plugin_datacache_sqlite_la_LDFLAGS) $(LDFLAGS) -o \ $@ @HAVE_SQLITE_TRUE@am_libgnunet_plugin_datacache_sqlite_la_rpath = \ @HAVE_SQLITE_TRUE@ -rpath $(plugindir) libgnunet_plugin_datacache_template_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_libgnunet_plugin_datacache_template_la_OBJECTS = \ plugin_datacache_template.lo libgnunet_plugin_datacache_template_la_OBJECTS = \ $(am_libgnunet_plugin_datacache_template_la_OBJECTS) libgnunet_plugin_datacache_template_la_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libgnunet_plugin_datacache_template_la_LDFLAGS) $(LDFLAGS) \ -o $@ libgnunetdatacache_la_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_libgnunetdatacache_la_OBJECTS = datacache.lo libgnunetdatacache_la_OBJECTS = $(am_libgnunetdatacache_la_OBJECTS) libgnunetdatacache_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetdatacache_la_LDFLAGS) \ $(LDFLAGS) -o $@ @HAVE_BENCHMARKS_TRUE@@HAVE_SQLITE_TRUE@am__EXEEXT_1 = perf_datacache_sqlite$(EXEEXT) @HAVE_SQLITE_TRUE@am__EXEEXT_2 = test_datacache_sqlite$(EXEEXT) \ @HAVE_SQLITE_TRUE@ test_datacache_quota_sqlite$(EXEEXT) \ @HAVE_SQLITE_TRUE@ $(am__EXEEXT_1) @HAVE_BENCHMARKS_TRUE@@HAVE_MYSQL_TRUE@am__EXEEXT_3 = perf_datacache_mysql$(EXEEXT) @HAVE_MYSQL_TRUE@am__EXEEXT_4 = test_datacache_mysql$(EXEEXT) \ @HAVE_MYSQL_TRUE@ test_datacache_quota_mysql$(EXEEXT) \ @HAVE_MYSQL_TRUE@ $(am__EXEEXT_3) @HAVE_BENCHMARKS_TRUE@@HAVE_POSTGRES_TRUE@am__EXEEXT_5 = perf_datacache_postgres$(EXEEXT) @HAVE_POSTGRES_TRUE@am__EXEEXT_6 = test_datacache_postgres$(EXEEXT) \ @HAVE_POSTGRES_TRUE@ test_datacache_quota_postgres$(EXEEXT) \ @HAVE_POSTGRES_TRUE@ $(am__EXEEXT_5) am_perf_datacache_mysql_OBJECTS = perf_datacache.$(OBJEXT) perf_datacache_mysql_OBJECTS = $(am_perf_datacache_mysql_OBJECTS) perf_datacache_mysql_DEPENDENCIES = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la am_perf_datacache_postgres_OBJECTS = perf_datacache.$(OBJEXT) perf_datacache_postgres_OBJECTS = \ $(am_perf_datacache_postgres_OBJECTS) perf_datacache_postgres_DEPENDENCIES = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la am_perf_datacache_sqlite_OBJECTS = perf_datacache.$(OBJEXT) perf_datacache_sqlite_OBJECTS = $(am_perf_datacache_sqlite_OBJECTS) perf_datacache_sqlite_DEPENDENCIES = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_datacache_mysql_OBJECTS = test_datacache.$(OBJEXT) test_datacache_mysql_OBJECTS = $(am_test_datacache_mysql_OBJECTS) test_datacache_mysql_DEPENDENCIES = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_datacache_postgres_OBJECTS = test_datacache.$(OBJEXT) test_datacache_postgres_OBJECTS = \ $(am_test_datacache_postgres_OBJECTS) test_datacache_postgres_DEPENDENCIES = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_datacache_quota_mysql_OBJECTS = \ test_datacache_quota.$(OBJEXT) test_datacache_quota_mysql_OBJECTS = \ $(am_test_datacache_quota_mysql_OBJECTS) test_datacache_quota_mysql_DEPENDENCIES = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_datacache_quota_postgres_OBJECTS = \ test_datacache_quota.$(OBJEXT) test_datacache_quota_postgres_OBJECTS = \ $(am_test_datacache_quota_postgres_OBJECTS) test_datacache_quota_postgres_DEPENDENCIES = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_datacache_quota_sqlite_OBJECTS = \ test_datacache_quota.$(OBJEXT) test_datacache_quota_sqlite_OBJECTS = \ $(am_test_datacache_quota_sqlite_OBJECTS) test_datacache_quota_sqlite_DEPENDENCIES = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_datacache_sqlite_OBJECTS = test_datacache.$(OBJEXT) test_datacache_sqlite_OBJECTS = $(am_test_datacache_sqlite_OBJECTS) test_datacache_sqlite_DEPENDENCIES = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunet_plugin_datacache_mysql_la_SOURCES) \ $(libgnunet_plugin_datacache_postgres_la_SOURCES) \ $(libgnunet_plugin_datacache_sqlite_la_SOURCES) \ $(libgnunet_plugin_datacache_template_la_SOURCES) \ $(libgnunetdatacache_la_SOURCES) \ $(perf_datacache_mysql_SOURCES) \ $(perf_datacache_postgres_SOURCES) \ $(perf_datacache_sqlite_SOURCES) \ $(test_datacache_mysql_SOURCES) \ $(test_datacache_postgres_SOURCES) \ $(test_datacache_quota_mysql_SOURCES) \ $(test_datacache_quota_postgres_SOURCES) \ $(test_datacache_quota_sqlite_SOURCES) \ $(test_datacache_sqlite_SOURCES) DIST_SOURCES = $(libgnunet_plugin_datacache_mysql_la_SOURCES) \ $(libgnunet_plugin_datacache_postgres_la_SOURCES) \ $(libgnunet_plugin_datacache_sqlite_la_SOURCES) \ $(libgnunet_plugin_datacache_template_la_SOURCES) \ $(libgnunetdatacache_la_SOURCES) \ $(perf_datacache_mysql_SOURCES) \ $(perf_datacache_postgres_SOURCES) \ $(perf_datacache_sqlite_SOURCES) \ $(test_datacache_mysql_SOURCES) \ $(test_datacache_postgres_SOURCES) \ $(test_datacache_quota_mysql_SOURCES) \ $(test_datacache_quota_postgres_SOURCES) \ $(test_datacache_quota_sqlite_SOURCES) \ $(test_datacache_sqlite_SOURCES) DATA = $(dist_pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include plugindir = $(libdir)/gnunet pkgcfgdir = $(pkgdatadir)/config.d/ dist_pkgcfg_DATA = \ datacache.conf @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @USE_COVERAGE_TRUE@XLIBS = -lgcov @HAVE_SQLITE_TRUE@SQLITE_PLUGIN = libgnunet_plugin_datacache_sqlite.la @HAVE_MYSQL_TRUE@MYSQL_PLUGIN = libgnunet_plugin_datacache_mysql.la @HAVE_POSTGRES_TRUE@POSTGRES_PLUGIN = libgnunet_plugin_datacache_postgres.la lib_LTLIBRARIES = \ libgnunetdatacache.la libgnunetdatacache_la_SOURCES = \ datacache.c libgnunetdatacache_la_LIBADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) libgnunetdatacache_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 0:1:0 plugin_LTLIBRARIES = \ $(SQLITE_PLUGIN) \ $(MYSQL_PLUGIN) \ $(POSTGRES_PLUGIN) \ libgnunet_plugin_datacache_template.la libgnunet_plugin_datacache_sqlite_la_SOURCES = \ plugin_datacache_sqlite.c libgnunet_plugin_datacache_sqlite_la_LIBADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 libgnunet_plugin_datacache_sqlite_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_datacache_mysql_la_SOURCES = \ plugin_datacache_mysql.c libgnunet_plugin_datacache_mysql_la_LIBADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/mysql/libgnunetmysql.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_PLUGIN_LDFLAGS) $(MYSQL_LDFLAGS) -lmysqlclient libgnunet_plugin_datacache_mysql_la_CPPFLAGS = \ $(MYSQL_CPPFLAGS) libgnunet_plugin_datacache_mysql_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) $(MYSQL_LDFLAGS) -lmysqlclient libgnunet_plugin_datacache_postgres_la_SOURCES = \ plugin_datacache_postgres.c libgnunet_plugin_datacache_postgres_la_LIBADD = \ $(top_builddir)/src/postgres/libgnunetpostgres.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_PLUGIN_LDFLAGS) $(POSTGRES_LDFLAGS) -lpq libgnunet_plugin_datacache_postgres_la_CPPFLAGS = \ $(POSTGRES_CPPFLAGS) libgnunet_plugin_datacache_postgres_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) $(POSTGRES_LDFLAGS) -lpq libgnunet_plugin_datacache_template_la_SOURCES = \ plugin_datacache_template.c libgnunet_plugin_datacache_template_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) libgnunet_plugin_datacache_template_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) @HAVE_BENCHMARKS_TRUE@@HAVE_SQLITE_TRUE@SQLITE_BENCHMARKS = \ @HAVE_BENCHMARKS_TRUE@@HAVE_SQLITE_TRUE@ perf_datacache_sqlite @HAVE_SQLITE_TRUE@SQLITE_TESTS = \ @HAVE_SQLITE_TRUE@ test_datacache_sqlite \ @HAVE_SQLITE_TRUE@ test_datacache_quota_sqlite \ @HAVE_SQLITE_TRUE@ $(SQLITE_BENCHMARKS) @HAVE_BENCHMARKS_TRUE@@HAVE_MYSQL_TRUE@MYSQL_BENCHMARKS = \ @HAVE_BENCHMARKS_TRUE@@HAVE_MYSQL_TRUE@ perf_datacache_mysql @HAVE_MYSQL_TRUE@MYSQL_TESTS = \ @HAVE_MYSQL_TRUE@ test_datacache_mysql \ @HAVE_MYSQL_TRUE@ test_datacache_quota_mysql \ @HAVE_MYSQL_TRUE@ $(MYSQL_BENCHMARKS) @HAVE_BENCHMARKS_TRUE@@HAVE_POSTGRES_TRUE@POSTGRES_BENCHMARKS = \ @HAVE_BENCHMARKS_TRUE@@HAVE_POSTGRES_TRUE@ perf_datacache_postgres @HAVE_POSTGRES_TRUE@POSTGRES_TESTS = \ @HAVE_POSTGRES_TRUE@ test_datacache_postgres \ @HAVE_POSTGRES_TRUE@ test_datacache_quota_postgres \ @HAVE_POSTGRES_TRUE@ $(POSTGRES_BENCHMARKS) @ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) test_datacache_sqlite_SOURCES = \ test_datacache.c test_datacache_sqlite_LDADD = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la test_datacache_quota_sqlite_SOURCES = \ test_datacache_quota.c test_datacache_quota_sqlite_LDADD = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la perf_datacache_sqlite_SOURCES = \ perf_datacache.c perf_datacache_sqlite_LDADD = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la test_datacache_mysql_SOURCES = \ test_datacache.c test_datacache_mysql_LDADD = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la test_datacache_quota_mysql_SOURCES = \ test_datacache_quota.c test_datacache_quota_mysql_LDADD = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la perf_datacache_mysql_SOURCES = \ perf_datacache.c perf_datacache_mysql_LDADD = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la test_datacache_postgres_SOURCES = \ test_datacache.c test_datacache_postgres_LDADD = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la test_datacache_quota_postgres_SOURCES = \ test_datacache_quota.c test_datacache_quota_postgres_LDADD = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la perf_datacache_postgres_SOURCES = \ perf_datacache.c perf_datacache_postgres_LDADD = \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ test_datacache_data_sqlite.conf \ perf_datacache_data_sqlite.conf \ test_datacache_data_mysql.conf \ perf_datacache_data_mysql.conf \ test_datacache_data_postgres.conf \ perf_datacache_data_postgres.conf all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/datacache/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/datacache/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ } uninstall-pluginLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ done clean-pluginLTLIBRARIES: -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunet_plugin_datacache_mysql.la: $(libgnunet_plugin_datacache_mysql_la_OBJECTS) $(libgnunet_plugin_datacache_mysql_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_datacache_mysql_la_LINK) $(am_libgnunet_plugin_datacache_mysql_la_rpath) $(libgnunet_plugin_datacache_mysql_la_OBJECTS) $(libgnunet_plugin_datacache_mysql_la_LIBADD) $(LIBS) libgnunet_plugin_datacache_postgres.la: $(libgnunet_plugin_datacache_postgres_la_OBJECTS) $(libgnunet_plugin_datacache_postgres_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_datacache_postgres_la_LINK) $(am_libgnunet_plugin_datacache_postgres_la_rpath) $(libgnunet_plugin_datacache_postgres_la_OBJECTS) $(libgnunet_plugin_datacache_postgres_la_LIBADD) $(LIBS) libgnunet_plugin_datacache_sqlite.la: $(libgnunet_plugin_datacache_sqlite_la_OBJECTS) $(libgnunet_plugin_datacache_sqlite_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_datacache_sqlite_la_LINK) $(am_libgnunet_plugin_datacache_sqlite_la_rpath) $(libgnunet_plugin_datacache_sqlite_la_OBJECTS) $(libgnunet_plugin_datacache_sqlite_la_LIBADD) $(LIBS) libgnunet_plugin_datacache_template.la: $(libgnunet_plugin_datacache_template_la_OBJECTS) $(libgnunet_plugin_datacache_template_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_datacache_template_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_datacache_template_la_OBJECTS) $(libgnunet_plugin_datacache_template_la_LIBADD) $(LIBS) libgnunetdatacache.la: $(libgnunetdatacache_la_OBJECTS) $(libgnunetdatacache_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetdatacache_la_LINK) -rpath $(libdir) $(libgnunetdatacache_la_OBJECTS) $(libgnunetdatacache_la_LIBADD) $(LIBS) clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list perf_datacache_mysql$(EXEEXT): $(perf_datacache_mysql_OBJECTS) $(perf_datacache_mysql_DEPENDENCIES) @rm -f perf_datacache_mysql$(EXEEXT) $(AM_V_CCLD)$(LINK) $(perf_datacache_mysql_OBJECTS) $(perf_datacache_mysql_LDADD) $(LIBS) perf_datacache_postgres$(EXEEXT): $(perf_datacache_postgres_OBJECTS) $(perf_datacache_postgres_DEPENDENCIES) @rm -f perf_datacache_postgres$(EXEEXT) $(AM_V_CCLD)$(LINK) $(perf_datacache_postgres_OBJECTS) $(perf_datacache_postgres_LDADD) $(LIBS) perf_datacache_sqlite$(EXEEXT): $(perf_datacache_sqlite_OBJECTS) $(perf_datacache_sqlite_DEPENDENCIES) @rm -f perf_datacache_sqlite$(EXEEXT) $(AM_V_CCLD)$(LINK) $(perf_datacache_sqlite_OBJECTS) $(perf_datacache_sqlite_LDADD) $(LIBS) test_datacache_mysql$(EXEEXT): $(test_datacache_mysql_OBJECTS) $(test_datacache_mysql_DEPENDENCIES) @rm -f test_datacache_mysql$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_datacache_mysql_OBJECTS) $(test_datacache_mysql_LDADD) $(LIBS) test_datacache_postgres$(EXEEXT): $(test_datacache_postgres_OBJECTS) $(test_datacache_postgres_DEPENDENCIES) @rm -f test_datacache_postgres$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_datacache_postgres_OBJECTS) $(test_datacache_postgres_LDADD) $(LIBS) test_datacache_quota_mysql$(EXEEXT): $(test_datacache_quota_mysql_OBJECTS) $(test_datacache_quota_mysql_DEPENDENCIES) @rm -f test_datacache_quota_mysql$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_datacache_quota_mysql_OBJECTS) $(test_datacache_quota_mysql_LDADD) $(LIBS) test_datacache_quota_postgres$(EXEEXT): $(test_datacache_quota_postgres_OBJECTS) $(test_datacache_quota_postgres_DEPENDENCIES) @rm -f test_datacache_quota_postgres$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_datacache_quota_postgres_OBJECTS) $(test_datacache_quota_postgres_LDADD) $(LIBS) test_datacache_quota_sqlite$(EXEEXT): $(test_datacache_quota_sqlite_OBJECTS) $(test_datacache_quota_sqlite_DEPENDENCIES) @rm -f test_datacache_quota_sqlite$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_datacache_quota_sqlite_OBJECTS) $(test_datacache_quota_sqlite_LDADD) $(LIBS) test_datacache_sqlite$(EXEEXT): $(test_datacache_sqlite_OBJECTS) $(test_datacache_sqlite_DEPENDENCIES) @rm -f test_datacache_sqlite$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_datacache_sqlite_OBJECTS) $(test_datacache_sqlite_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/datacache.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_datacache_mysql_la-plugin_datacache_mysql.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_datacache_postgres_la-plugin_datacache_postgres.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perf_datacache.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_datacache_sqlite.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_datacache_template.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_datacache.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_datacache_quota.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< libgnunet_plugin_datacache_mysql_la-plugin_datacache_mysql.lo: plugin_datacache_mysql.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_datacache_mysql_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_datacache_mysql_la-plugin_datacache_mysql.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_datacache_mysql_la-plugin_datacache_mysql.Tpo -c -o libgnunet_plugin_datacache_mysql_la-plugin_datacache_mysql.lo `test -f 'plugin_datacache_mysql.c' || echo '$(srcdir)/'`plugin_datacache_mysql.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_datacache_mysql_la-plugin_datacache_mysql.Tpo $(DEPDIR)/libgnunet_plugin_datacache_mysql_la-plugin_datacache_mysql.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_datacache_mysql.c' object='libgnunet_plugin_datacache_mysql_la-plugin_datacache_mysql.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_datacache_mysql_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_datacache_mysql_la-plugin_datacache_mysql.lo `test -f 'plugin_datacache_mysql.c' || echo '$(srcdir)/'`plugin_datacache_mysql.c libgnunet_plugin_datacache_postgres_la-plugin_datacache_postgres.lo: plugin_datacache_postgres.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_datacache_postgres_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_datacache_postgres_la-plugin_datacache_postgres.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_datacache_postgres_la-plugin_datacache_postgres.Tpo -c -o libgnunet_plugin_datacache_postgres_la-plugin_datacache_postgres.lo `test -f 'plugin_datacache_postgres.c' || echo '$(srcdir)/'`plugin_datacache_postgres.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_datacache_postgres_la-plugin_datacache_postgres.Tpo $(DEPDIR)/libgnunet_plugin_datacache_postgres_la-plugin_datacache_postgres.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_datacache_postgres.c' object='libgnunet_plugin_datacache_postgres_la-plugin_datacache_postgres.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_datacache_postgres_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_datacache_postgres_la-plugin_datacache_postgres.lo `test -f 'plugin_datacache_postgres.c' || echo '$(srcdir)/'`plugin_datacache_postgres.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_pkgcfgDATA: $(dist_pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-dist_pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(DATA) installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool clean-pluginLTLIBRARIES mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_pkgcfgDATA install-pluginLTLIBRARIES install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_pkgcfgDATA uninstall-libLTLIBRARIES \ uninstall-pluginLTLIBRARIES .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool clean-pluginLTLIBRARIES ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-dist_pkgcfgDATA install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-libLTLIBRARIES \ install-man install-pdf install-pdf-am \ install-pluginLTLIBRARIES install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-dist_pkgcfgDATA uninstall-libLTLIBRARIES \ uninstall-pluginLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/datacache/datacache.c0000644000175000017500000002102011760502551014466 00000000000000/* This file is part of GNUnet (C) 2004, 2005, 2006, 2007, 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file datacache/datacache.c * @brief datacache API implementation * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_datacache_lib.h" #include "gnunet_statistics_service.h" #include "gnunet_datacache_plugin.h" #define LOG(kind,...) GNUNET_log_from (kind, "datacache", __VA_ARGS__) #define LOG_STRERROR_FILE(kind,op,fn) GNUNET_log_from_strerror_file (kind, "datacache", op, fn) /** * Internal state of the datacache library. */ struct GNUNET_DATACACHE_Handle { /** * Bloomfilter to quickly tell if we don't have the content. */ struct GNUNET_CONTAINER_BloomFilter *filter; /** * Our configuration. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Opaque handle for the statistics service. */ struct GNUNET_STATISTICS_Handle *stats; /** * Configuration section to use. */ char *section; /** * API of the transport as returned by the plugin's * initialization function. */ struct GNUNET_DATACACHE_PluginFunctions *api; /** * Short name for the plugin (i.e. "sqlite"). */ char *short_name; /** * Name of the library (i.e. "gnunet_plugin_datacache_sqlite"). */ char *lib_name; /** * Name for the bloom filter file. */ char *bloom_name; /** * Environment provided to our plugin. */ struct GNUNET_DATACACHE_PluginEnvironment env; /** * How much space is in use right now? */ unsigned long long utilization; }; /** * Function called by plugins to notify the datacache * about content deletions. * * @param cls closure * @param key key of the content that was deleted * @param size number of bytes that were made available */ static void env_delete_notify (void *cls, const GNUNET_HashCode * key, size_t size) { struct GNUNET_DATACACHE_Handle *h = cls; LOG (GNUNET_ERROR_TYPE_DEBUG, "Content under key `%s' discarded\n", GNUNET_h2s (key)); GNUNET_assert (h->utilization >= size); h->utilization -= size; GNUNET_CONTAINER_bloomfilter_remove (h->filter, key); GNUNET_STATISTICS_update (h->stats, gettext_noop ("# bytes stored"), -size, GNUNET_NO); } /** * Create a data cache. * * @param cfg configuration to use * @param section section in the configuration that contains our options * @return handle to use to access the service */ struct GNUNET_DATACACHE_Handle * GNUNET_DATACACHE_create (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section) { unsigned int bf_size; unsigned long long quota; struct GNUNET_DATACACHE_Handle *ret; char *libname; char *name; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_size (cfg, section, "QUOTA", "a)) { LOG (GNUNET_ERROR_TYPE_ERROR, _("No `%s' specified for `%s' in configuration!\n"), "QUOTA", section); return NULL; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, section, "DATABASE", &name)) { LOG (GNUNET_ERROR_TYPE_ERROR, _("No `%s' specified for `%s' in configuration!\n"), "DATABASE", section); return NULL; } bf_size = quota / 32; /* 8 bit per entry, 1 bit per 32 kb in DB */ ret = GNUNET_malloc (sizeof (struct GNUNET_DATACACHE_Handle)); ret->bloom_name = GNUNET_DISK_mktemp ("gnunet-datacachebloom"); if (NULL != ret->bloom_name) { ret->filter = GNUNET_CONTAINER_bloomfilter_load (ret->bloom_name, quota / 1024, /* 8 bit per entry in DB, expect 1k entries */ 5); } if (NULL == ret->filter) { ret->filter = GNUNET_CONTAINER_bloomfilter_init (NULL, bf_size, 5); /* approx. 3% false positives at max use */ } if (NULL == ret->filter) { GNUNET_free (name); GNUNET_free (ret->bloom_name); GNUNET_free (ret); return NULL; } ret->stats = GNUNET_STATISTICS_create ("datacache", cfg); ret->section = GNUNET_strdup (section); ret->env.cfg = cfg; ret->env.delete_notify = &env_delete_notify; ret->env.section = ret->section; ret->env.cls = ret; ret->env.delete_notify = &env_delete_notify; ret->env.quota = quota; LOG (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' datacache plugin\n"), name); GNUNET_asprintf (&libname, "libgnunet_plugin_datacache_%s", name); ret->short_name = name; ret->lib_name = libname; ret->api = GNUNET_PLUGIN_load (libname, &ret->env); if (ret->api == NULL) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to load datacache plugin for `%s'\n"), name); GNUNET_DATACACHE_destroy (ret); return NULL; } return ret; } /** * Destroy a data cache (and free associated resources). * * @param h handle to the datastore */ void GNUNET_DATACACHE_destroy (struct GNUNET_DATACACHE_Handle *h) { if (h->filter != NULL) GNUNET_CONTAINER_bloomfilter_free (h->filter); if (h->api != NULL) GNUNET_break (NULL == GNUNET_PLUGIN_unload (h->lib_name, h->api)); GNUNET_free (h->lib_name); GNUNET_free (h->short_name); GNUNET_free (h->section); if (h->bloom_name != NULL) { if (0 != UNLINK (h->bloom_name)) GNUNET_log_from_strerror_file (GNUNET_ERROR_TYPE_WARNING, "datacache", "unlink", h->bloom_name); GNUNET_free (h->bloom_name); } GNUNET_STATISTICS_destroy (h->stats, GNUNET_NO); GNUNET_free (h); } /** * Store an item in the datastore. * * @param h handle to the datacache * @param key key to store data under * @param size number of bytes in data * @param data data to store * @param type type of the value * @param discard_time when to discard the value in any case * @return GNUNET_OK on success, GNUNET_SYSERR on error (full, etc.) */ int GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h, const GNUNET_HashCode * key, size_t size, const char *data, enum GNUNET_BLOCK_Type type, struct GNUNET_TIME_Absolute discard_time) { uint32_t used; used = h->api->put (h->api->cls, key, size, data, type, discard_time); if (used == 0) { GNUNET_break (0); return GNUNET_SYSERR; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Stored data under key `%s' in cache\n", GNUNET_h2s (key)); GNUNET_STATISTICS_update (h->stats, gettext_noop ("# bytes stored"), size, GNUNET_NO); GNUNET_CONTAINER_bloomfilter_add (h->filter, key); while (h->utilization + used > h->env.quota) GNUNET_assert (GNUNET_OK == h->api->del (h->api->cls)); h->utilization += used; return GNUNET_OK; } /** * Iterate over the results for a particular key * in the datacache. * * @param h handle to the datacache * @param key what to look up * @param type entries of which type are relevant? * @param iter maybe NULL (to just count) * @param iter_cls closure for iter * @return the number of results found */ unsigned int GNUNET_DATACACHE_get (struct GNUNET_DATACACHE_Handle *h, const GNUNET_HashCode * key, enum GNUNET_BLOCK_Type type, GNUNET_DATACACHE_Iterator iter, void *iter_cls) { GNUNET_STATISTICS_update (h->stats, gettext_noop ("# requests received"), 1, GNUNET_NO); LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing request for key `%s'\n", GNUNET_h2s (key)); if (GNUNET_OK != GNUNET_CONTAINER_bloomfilter_test (h->filter, key)) { GNUNET_STATISTICS_update (h->stats, gettext_noop ("# requests filtered by bloom filter"), 1, GNUNET_NO); LOG (GNUNET_ERROR_TYPE_DEBUG, "Bloomfilter filters request for key `%s'\n", GNUNET_h2s (key)); return 0; /* can not be present */ } return h->api->get (h->api->cls, key, type, iter, iter_cls); } /* end of datacache_api.c */ gnunet-0.9.3/src/datacache/plugin_datacache_postgres.c0000644000175000017500000002605111760502551020003 00000000000000/* This file is part of GNUnet (C) 2006, 2009, 2010, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file datacache/plugin_datacache_postgres.c * @brief postgres for an implementation of a database backend for the datacache * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_postgres_lib.h" #include "gnunet_datacache_plugin.h" #include #define LOG(kind,...) GNUNET_log_from (kind, "datacache-postgres", __VA_ARGS__) /** * Per-entry overhead estimate */ #define OVERHEAD (sizeof(GNUNET_HashCode) + 24) /** * Context for all functions in this plugin. */ struct Plugin { /** * Our execution environment. */ struct GNUNET_DATACACHE_PluginEnvironment *env; /** * Native Postgres database handle. */ PGconn *dbh; }; /** * @brief Get a database handle * * @param plugin global context * @return GNUNET_OK on success, GNUNET_SYSERR on error */ static int init_connection (struct Plugin *plugin) { PGresult *ret; plugin->dbh = GNUNET_POSTGRES_connect (plugin->env->cfg, "datacache-postgres"); if (NULL == plugin->dbh) return GNUNET_SYSERR; ret = PQexec (plugin->dbh, "CREATE TEMPORARY TABLE gn090dc (" " type INTEGER NOT NULL DEFAULT 0," " discard_time BIGINT NOT NULL DEFAULT 0," " key BYTEA NOT NULL DEFAULT ''," " value BYTEA NOT NULL DEFAULT '')" "WITH OIDS"); if ((ret == NULL) || ((PQresultStatus (ret) != PGRES_COMMAND_OK) && (0 != strcmp ("42P07", /* duplicate table */ PQresultErrorField (ret, PG_DIAG_SQLSTATE))))) { (void) GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_COMMAND_OK, "CREATE TABLE", "gn090dc"); PQfinish (plugin->dbh); plugin->dbh = NULL; return GNUNET_SYSERR; } if (PQresultStatus (ret) == PGRES_COMMAND_OK) { if ((GNUNET_OK != GNUNET_POSTGRES_exec (plugin->dbh, "CREATE INDEX idx_key ON gn090dc (key)")) || (GNUNET_OK != GNUNET_POSTGRES_exec (plugin->dbh, "CREATE INDEX idx_dt ON gn090dc (discard_time)"))) { PQclear (ret); PQfinish (plugin->dbh); plugin->dbh = NULL; return GNUNET_SYSERR; } } PQclear (ret); ret = PQexec (plugin->dbh, "ALTER TABLE gn090dc ALTER value SET STORAGE EXTERNAL"); if (GNUNET_OK != GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_COMMAND_OK, "ALTER TABLE", "gn090dc")) { PQfinish (plugin->dbh); plugin->dbh = NULL; return GNUNET_SYSERR; } PQclear (ret); ret = PQexec (plugin->dbh, "ALTER TABLE gn090dc ALTER key SET STORAGE PLAIN"); if (GNUNET_OK != GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_COMMAND_OK, "ALTER TABLE", "gn090dc")) { PQfinish (plugin->dbh); plugin->dbh = NULL; return GNUNET_SYSERR; } PQclear (ret); if ((GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, "getkt", "SELECT discard_time,type,value FROM gn090dc " "WHERE key=$1 AND type=$2 ", 2)) || (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, "getk", "SELECT discard_time,type,value FROM gn090dc " "WHERE key=$1", 1)) || (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, "getm", "SELECT length(value),oid,key FROM gn090dc " "ORDER BY discard_time ASC LIMIT 1", 0)) || (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, "delrow", "DELETE FROM gn090dc WHERE oid=$1", 1)) || (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, "put", "INSERT INTO gn090dc (type, discard_time, key, value) " "VALUES ($1, $2, $3, $4)", 4))) { PQfinish (plugin->dbh); plugin->dbh = NULL; return GNUNET_SYSERR; } return GNUNET_OK; } /** * Store an item in the datastore. * * @param cls closure (our "struct Plugin") * @param key key to store data under * @param size number of bytes in data * @param data data to store * @param type type of the value * @param discard_time when to discard the value in any case * @return 0 on error, number of bytes used otherwise */ static size_t postgres_plugin_put (void *cls, const GNUNET_HashCode * key, size_t size, const char *data, enum GNUNET_BLOCK_Type type, struct GNUNET_TIME_Absolute discard_time) { struct Plugin *plugin = cls; PGresult *ret; uint32_t btype = htonl (type); uint64_t bexpi = GNUNET_TIME_absolute_hton (discard_time).abs_value__; const char *paramValues[] = { (const char *) &btype, (const char *) &bexpi, (const char *) key, (const char *) data }; int paramLengths[] = { sizeof (btype), sizeof (bexpi), sizeof (GNUNET_HashCode), size }; const int paramFormats[] = { 1, 1, 1, 1 }; ret = PQexecPrepared (plugin->dbh, "put", 4, paramValues, paramLengths, paramFormats, 1); if (GNUNET_OK != GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_COMMAND_OK, "PQexecPrepared", "put")) return GNUNET_SYSERR; PQclear (ret); return size + OVERHEAD; } /** * Iterate over the results for a particular key * in the datastore. * * @param cls closure (our "struct Plugin") * @param key * @param type entries of which type are relevant? * @param iter maybe NULL (to just count) * @param iter_cls closure for iter * @return the number of results found */ static unsigned int postgres_plugin_get (void *cls, const GNUNET_HashCode * key, enum GNUNET_BLOCK_Type type, GNUNET_DATACACHE_Iterator iter, void *iter_cls) { struct Plugin *plugin = cls; uint32_t btype = htonl (type); const char *paramValues[] = { (const char *) key, (const char *) &btype, }; int paramLengths[] = { sizeof (GNUNET_HashCode), sizeof (btype), }; const int paramFormats[] = { 1, 1 }; struct GNUNET_TIME_Absolute expiration_time; uint32_t size; unsigned int cnt; unsigned int i; PGresult *res; res = PQexecPrepared (plugin->dbh, (type == 0) ? "getk" : "getkt", (type == 0) ? 1 : 2, paramValues, paramLengths, paramFormats, 1); if (GNUNET_OK != GNUNET_POSTGRES_check_result (plugin->dbh, res, PGRES_TUPLES_OK, "PQexecPrepared", (type == 0) ? "getk" : "getkt")) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Ending iteration (postgres error)\n"); return 0; } if (0 == (cnt = PQntuples (res))) { /* no result */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Ending iteration (no more results)\n"); PQclear (res); return 0; } if (iter == NULL) { PQclear (res); return cnt; } if ((3 != PQnfields (res)) || (sizeof (uint64_t) != PQfsize (res, 0)) || (sizeof (uint32_t) != PQfsize (res, 1))) { GNUNET_break (0); PQclear (res); return 0; } for (i = 0; i < cnt; i++) { expiration_time.abs_value = GNUNET_ntohll (*(uint64_t *) PQgetvalue (res, i, 0)); type = ntohl (*(uint32_t *) PQgetvalue (res, i, 1)); size = PQgetlength (res, i, 2); LOG (GNUNET_ERROR_TYPE_DEBUG, "Found result of size %u bytes and type %u in database\n", (unsigned int) size, (unsigned int) type); if (GNUNET_SYSERR == iter (iter_cls, expiration_time, key, size, PQgetvalue (res, i, 2), (enum GNUNET_BLOCK_Type) type)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Ending iteration (client error)\n"); PQclear (res); return cnt; } } PQclear (res); return cnt; } /** * Delete the entry with the lowest expiration value * from the datacache right now. * * @param cls closure (our "struct Plugin") * @return GNUNET_OK on success, GNUNET_SYSERR on error */ static int postgres_plugin_del (void *cls) { struct Plugin *plugin = cls; uint32_t size; uint32_t oid; GNUNET_HashCode key; PGresult *res; res = PQexecPrepared (plugin->dbh, "getm", 0, NULL, NULL, NULL, 1); if (GNUNET_OK != GNUNET_POSTGRES_check_result (plugin->dbh, res, PGRES_TUPLES_OK, "PQexecPrepared", "getm")) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Ending iteration (postgres error)\n"); return 0; } if (0 == PQntuples (res)) { /* no result */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Ending iteration (no more results)\n"); PQclear (res); return GNUNET_SYSERR; } if ((3 != PQnfields (res)) || (sizeof (size) != PQfsize (res, 0)) || (sizeof (oid) != PQfsize (res, 1)) || (sizeof (GNUNET_HashCode) != PQgetlength (res, 0, 2))) { GNUNET_break (0); PQclear (res); return 0; } size = ntohl (*(uint32_t *) PQgetvalue (res, 0, 0)); oid = ntohl (*(uint32_t *) PQgetvalue (res, 0, 1)); memcpy (&key, PQgetvalue (res, 0, 2), sizeof (GNUNET_HashCode)); PQclear (res); if (GNUNET_OK != GNUNET_POSTGRES_delete_by_rowid (plugin->dbh, "delrow", oid)) return GNUNET_SYSERR; plugin->env->delete_notify (plugin->env->cls, &key, size + OVERHEAD); return GNUNET_OK; } /** * Entry point for the plugin. * * @param cls closure (the "struct GNUNET_DATACACHE_PluginEnvironmnet") * @return the plugin's closure (our "struct Plugin") */ void * libgnunet_plugin_datacache_postgres_init (void *cls) { struct GNUNET_DATACACHE_PluginEnvironment *env = cls; struct GNUNET_DATACACHE_PluginFunctions *api; struct Plugin *plugin; plugin = GNUNET_malloc (sizeof (struct Plugin)); plugin->env = env; if (GNUNET_OK != init_connection (plugin)) { GNUNET_free (plugin); return NULL; } api = GNUNET_malloc (sizeof (struct GNUNET_DATACACHE_PluginFunctions)); api->cls = plugin; api->get = &postgres_plugin_get; api->put = &postgres_plugin_put; api->del = &postgres_plugin_del; LOG (GNUNET_ERROR_TYPE_INFO, _("Postgres datacache running\n")); return api; } /** * Exit point from the plugin. * * @param cls closure (our "struct Plugin") * @return NULL */ void * libgnunet_plugin_datacache_postgres_done (void *cls) { struct GNUNET_DATACACHE_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; PQfinish (plugin->dbh); GNUNET_free (plugin); GNUNET_free (api); return NULL; } /* end of plugin_datacache_postgres.c */ gnunet-0.9.3/src/datacache/plugin_datacache_template.c0000644000175000017500000000735511760502551017756 00000000000000/* This file is part of GNUnet (C) 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file datacache/plugin_datacache_template.c * @brief template for an implementation of a database backend for the datacache * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_datacache_plugin.h" /** * Context for all functions in this plugin. */ struct Plugin { /** * Our execution environment. */ struct GNUNET_DATACACHE_PluginEnvironment *env; }; /** * Store an item in the datastore. * * @param cls closure (our "struct Plugin") * @param key key to store data under * @param size number of bytes in data * @param data data to store * @param type type of the value * @param discard_time when to discard the value in any case * @return 0 on error, number of bytes used otherwise */ static size_t template_plugin_put (void *cls, const GNUNET_HashCode * key, size_t size, const char *data, enum GNUNET_BLOCK_Type type, struct GNUNET_TIME_Absolute discard_time) { GNUNET_break (0); return 0; } /** * Iterate over the results for a particular key * in the datastore. * * @param cls closure (our "struct Plugin") * @param key * @param type entries of which type are relevant? * @param iter maybe NULL (to just count) * @param iter_cls closure for iter * @return the number of results found */ static unsigned int template_plugin_get (void *cls, const GNUNET_HashCode * key, enum GNUNET_BLOCK_Type type, GNUNET_DATACACHE_Iterator iter, void *iter_cls) { GNUNET_break (0); return 0; } /** * Delete the entry with the lowest expiration value * from the datacache right now. * * @param cls closure (our "struct Plugin") * @return GNUNET_OK on success, GNUNET_SYSERR on error */ static int template_plugin_del (void *cls) { GNUNET_break (0); return GNUNET_SYSERR; } /** * Entry point for the plugin. * * @param cls closure (the "struct GNUNET_DATACACHE_PluginEnvironmnet") * @return the plugin's closure (our "struct Plugin") */ void * libgnunet_plugin_datacache_template_init (void *cls) { struct GNUNET_DATACACHE_PluginEnvironment *env = cls; struct GNUNET_DATACACHE_PluginFunctions *api; struct Plugin *plugin; plugin = GNUNET_malloc (sizeof (struct Plugin)); plugin->env = env; api = GNUNET_malloc (sizeof (struct GNUNET_DATACACHE_PluginFunctions)); api->cls = plugin; api->get = &template_plugin_get; api->put = &template_plugin_put; api->del = &template_plugin_del; GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "template", _("Template datacache running\n")); return api; } /** * Exit point from the plugin. * * @param cls closure (our "struct Plugin") * @return NULL */ void * libgnunet_plugin_datacache_template_done (void *cls) { struct GNUNET_DATACACHE_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; GNUNET_free (plugin); GNUNET_free (api); return NULL; } /* end of plugin_datacache_template.c */ gnunet-0.9.3/src/datacache/plugin_datacache_mysql.c0000644000175000017500000003743411760502551017311 00000000000000/* This file is part of GNUnet (C) 2006, 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file datacache/plugin_datacache_mysql.c * @brief mysql for an implementation of a database backend for the datacache * @author Christian Grothoff * * SETUP INSTRUCTIONS: * * 1) Access mysql as root, *

     *
     *    $ mysql -u root -p
     *
     *    
    * and do the following. [You should replace $USER with the username * that will be running the gnunetd process]. * @verbatim CREATE DATABASE gnunet; GRANT select,insert,update,delete,create,alter,drop,create temporary tables ON gnunet.* TO $USER@localhost; SET PASSWORD FOR $USER@localhost=PASSWORD('$the_password_you_like'); FLUSH PRIVILEGES; @endverbatim * 2) In the $HOME directory of $USER, create a ".my.cnf" file * with the following lines * @verbatim [client] user=$USER password=$the_password_you_like @endverbatim * * Thats it -- now you can configure your datastores in GNUnet to * use MySQL. Note that .my.cnf file is a security risk unless its on * a safe partition etc. The $HOME/.my.cnf can of course be a symbolic * link. Even greater security risk can be achieved by setting no * password for $USER. Luckily $USER has only priviledges to mess * up GNUnet's tables, nothing else (unless you give him more, * of course).

    * * 3) Still, perhaps you should briefly try if the DB connection * works. First, login as $USER. Then use, * @verbatim $ mysql -u $USER -p $the_password_you_like mysql> use gnunet; @endverbatim * * If you get the message "Database changed" it probably works. * * [If you get "ERROR 2002: Can't connect to local MySQL server * through socket '/tmp/mysql.sock' (2)" it may be resolvable by * "ln -s /var/run/mysqld/mysqld.sock /tmp/mysql.sock" * so there may be some additional trouble depending on your mysql setup.] * * PROBLEMS? * * If you have problems related to the mysql module, your best * friend is probably the mysql manual. The first thing to check * is that mysql is basically operational, that you can connect * to it, create tables, issue queries etc. */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_datacache_plugin.h" #include "gnunet_mysql_lib.h" #include /** * Estimate of the per-entry overhead (including indices). */ #define OVERHEAD ((4*2+4*2+8*2+8*2+sizeof(GNUNET_HashCode)*5+8)) /** * Die with an error message that indicates * a failure of the command 'cmd' with the message given * by strerror(errno). */ #define DIE_MYSQL(cmd, dbh) do { GNUNET_log(GNUNET_ERROR_TYPE__ERROR, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, mysql_error((dbh)->dbf)); GNUNET_abort(); } while(0); /** * Log an error message at log-level 'level' that indicates * a failure of the command 'cmd' on file 'filename' * with the message given by strerror(errno). */ #define LOG_MYSQL(level, cmd, dbh) do { GNUNET_log(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, mysql_error((dbh)->dbf)); } while(0); /** * Context for all functions in this plugin. */ struct Plugin { /** * Our execution environment. */ struct GNUNET_DATACACHE_PluginEnvironment *env; /** * Handle to the mysql database. */ struct GNUNET_MYSQL_Context *mc; #define SELECT_VALUE_STMT "SELECT value,expire FROM gn080dstore FORCE INDEX (hashidx) WHERE hash=? AND type=? AND expire >= ? LIMIT 1 OFFSET ?" struct GNUNET_MYSQL_StatementHandle *select_value; #define COUNT_VALUE_STMT "SELECT count(*) FROM gn080dstore FORCE INDEX (hashidx) WHERE hash=? AND type=? AND expire >= ?" struct GNUNET_MYSQL_StatementHandle *count_value; #define SELECT_OLD_VALUE_STMT "SELECT hash, vhash, type, value FROM gn080dstore FORCE INDEX (expireidx) ORDER BY puttime ASC LIMIT 1" struct GNUNET_MYSQL_StatementHandle *select_old_value; #define DELETE_VALUE_STMT "DELETE FROM gn080dstore WHERE hash = ? AND vhash = ? AND type = ? AND value = ?" struct GNUNET_MYSQL_StatementHandle *delete_value; #define INSERT_VALUE_STMT "INSERT INTO gn080dstore (type, puttime, expire, hash, vhash, value) "\ "VALUES (?, ?, ?, ?, ?, ?)" struct GNUNET_MYSQL_StatementHandle *insert_value; #define UPDATE_VALUE_STMT "UPDATE gn080dstore FORCE INDEX (allidx) SET puttime=?, expire=? "\ "WHERE hash=? AND vhash=? AND type=?" struct GNUNET_MYSQL_StatementHandle *update_value; }; /** * Create temporary table and prepare statements. * * @param plugin plugin context * @return GNUNET_OK on success */ static int itable (struct Plugin *plugin) { #define MRUNS(a) (GNUNET_OK != GNUNET_MYSQL_statement_run (plugin->mc, a) ) if (MRUNS ("CREATE TEMPORARY TABLE gn080dstore (" " type INT(11) UNSIGNED NOT NULL DEFAULT 0," " puttime BIGINT UNSIGNED NOT NULL DEFAULT 0," " expire BIGINT UNSIGNED NOT NULL DEFAULT 0," " hash BINARY(64) NOT NULL DEFAULT ''," " vhash BINARY(64) NOT NULL DEFAULT ''," " value BLOB NOT NULL DEFAULT ''," " INDEX hashidx (hash(64),type,expire)," " INDEX allidx (hash(64),vhash(64),type)," " INDEX expireidx (puttime)" ") ENGINE=InnoDB") || MRUNS ("SET AUTOCOMMIT = 1")) return GNUNET_SYSERR; #undef MRUNS #define PINIT(a,b) (NULL == (a = GNUNET_MYSQL_statement_prepare (plugin->mc, b))) if (PINIT (plugin->select_value, SELECT_VALUE_STMT) || PINIT (plugin->count_value, COUNT_VALUE_STMT) || PINIT (plugin->select_old_value, SELECT_OLD_VALUE_STMT) || PINIT (plugin->delete_value, DELETE_VALUE_STMT) || PINIT (plugin->insert_value, INSERT_VALUE_STMT) || PINIT (plugin->update_value, UPDATE_VALUE_STMT)) return GNUNET_SYSERR; #undef PINIT return GNUNET_OK; } /** * Store an item in the datastore. * * @param cls closure (our "struct Plugin") * @param key key to store data under * @param size number of bytes in data * @param data data to store * @param type type of the value * @param discard_time when to discard the value in any case * @return 0 on error, number of bytes used otherwise */ static size_t mysql_plugin_put (void *cls, const GNUNET_HashCode * key, size_t size, const char *data, enum GNUNET_BLOCK_Type type, struct GNUNET_TIME_Absolute discard_time) { struct Plugin *plugin = cls; struct GNUNET_TIME_Absolute now; unsigned long k_length; unsigned long h_length; unsigned long v_length; unsigned long long v_now; unsigned long long v_discard_time; unsigned int v_type; GNUNET_HashCode vhash; int ret; if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE) return GNUNET_SYSERR; GNUNET_CRYPTO_hash (data, size, &vhash); now = GNUNET_TIME_absolute_get (); /* first try UPDATE */ h_length = sizeof (GNUNET_HashCode); k_length = sizeof (GNUNET_HashCode); v_length = size; v_type = type; v_now = (unsigned long long) now.abs_value; v_discard_time = (unsigned long long) discard_time.abs_value; if (GNUNET_OK == GNUNET_MYSQL_statement_run_prepared (plugin->mc, plugin->update_value, NULL, MYSQL_TYPE_LONGLONG, &v_now, GNUNET_YES, MYSQL_TYPE_LONGLONG, &v_discard_time, GNUNET_YES, MYSQL_TYPE_BLOB, key, sizeof (GNUNET_HashCode), &k_length, MYSQL_TYPE_BLOB, &vhash, sizeof (GNUNET_HashCode), &h_length, MYSQL_TYPE_LONG, &v_type, GNUNET_YES, -1)) return GNUNET_OK; /* now try INSERT */ h_length = sizeof (GNUNET_HashCode); k_length = sizeof (GNUNET_HashCode); v_length = size; if (GNUNET_OK != (ret = GNUNET_MYSQL_statement_run_prepared (plugin->mc, plugin->insert_value, NULL, MYSQL_TYPE_LONG, &type, GNUNET_YES, MYSQL_TYPE_LONGLONG, &v_now, GNUNET_YES, MYSQL_TYPE_LONGLONG, &v_discard_time, GNUNET_YES, MYSQL_TYPE_BLOB, key, sizeof (GNUNET_HashCode), &k_length, MYSQL_TYPE_BLOB, &vhash, sizeof (GNUNET_HashCode), &h_length, MYSQL_TYPE_BLOB, data, (unsigned long) size, &v_length, -1))) { if (ret == GNUNET_SYSERR) itable (plugin); return GNUNET_SYSERR; } return size + OVERHEAD; } static int return_ok (void *cls, unsigned int num_values, MYSQL_BIND * values) { return GNUNET_OK; } /** * Iterate over the results for a particular key * in the datastore. * * @param cls closure (our "struct Plugin") * @param key * @param type entries of which type are relevant? * @param iter maybe NULL (to just count) * @param iter_cls closure for iter * @return the number of results found */ static unsigned int mysql_plugin_get (void *cls, const GNUNET_HashCode * key, enum GNUNET_BLOCK_Type type, GNUNET_DATACACHE_Iterator iter, void *iter_cls) { struct Plugin *plugin = cls; MYSQL_BIND rbind[3]; unsigned long h_length; unsigned long v_length; unsigned long long v_expire; struct GNUNET_TIME_Absolute now; struct GNUNET_TIME_Absolute expire; unsigned int cnt; unsigned long long total; unsigned long long v_now; unsigned int off; unsigned int v_type; int ret; char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE]; now = GNUNET_TIME_absolute_get (); h_length = sizeof (GNUNET_HashCode); v_length = sizeof (buffer); total = -1; memset (rbind, 0, sizeof (rbind)); rbind[0].buffer_type = MYSQL_TYPE_LONGLONG; rbind[0].buffer = &total; rbind[0].is_unsigned = GNUNET_YES; v_type = type; v_now = (unsigned long long) now.abs_value; if ((GNUNET_OK != (ret = GNUNET_MYSQL_statement_run_prepared_select (plugin->mc, plugin->count_value, 1, rbind, return_ok, NULL, MYSQL_TYPE_BLOB, key, sizeof (GNUNET_HashCode), &h_length, MYSQL_TYPE_LONG, &v_type, GNUNET_YES, MYSQL_TYPE_LONGLONG, &v_now, GNUNET_YES, -1))) || (-1 == total)) { if (ret == GNUNET_SYSERR) itable (plugin); return GNUNET_SYSERR; } if ((iter == NULL) || (total == 0)) return (int) total; off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total); cnt = 0; while (cnt < total) { memset (rbind, 0, sizeof (rbind)); rbind[0].buffer_type = MYSQL_TYPE_BLOB; rbind[0].buffer_length = sizeof (buffer); rbind[0].length = &v_length; rbind[0].buffer = buffer; rbind[1].buffer_type = MYSQL_TYPE_LONGLONG; rbind[1].is_unsigned = 1; rbind[1].buffer = &v_expire; off = (off + 1) % total; if (GNUNET_OK != (ret = GNUNET_MYSQL_statement_run_prepared_select (plugin->mc, plugin->select_value, 2, rbind, return_ok, NULL, MYSQL_TYPE_BLOB, key, sizeof (GNUNET_HashCode), &h_length, MYSQL_TYPE_LONG, &v_type, GNUNET_YES, MYSQL_TYPE_LONGLONG, &v_now, GNUNET_YES, MYSQL_TYPE_LONG, &off, GNUNET_YES, -1))) { if (ret == GNUNET_SYSERR) itable (plugin); return GNUNET_SYSERR; } cnt++; expire.abs_value = v_expire; if (GNUNET_OK != iter (iter_cls, expire, key, v_length, buffer, type)) break; } return cnt; } /** * Delete the entry with the lowest expiration value * from the datacache right now. * * @param cls closure (our "struct Plugin") * @return GNUNET_OK on success, GNUNET_SYSERR on error */ static int mysql_plugin_del (void *cls) { struct Plugin *plugin = cls; MYSQL_BIND rbind[5]; unsigned int v_type; GNUNET_HashCode v_key; GNUNET_HashCode vhash; unsigned long k_length; unsigned long h_length; unsigned long v_length; int ret; char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE]; k_length = sizeof (GNUNET_HashCode); h_length = sizeof (GNUNET_HashCode); v_length = sizeof (buffer); memset (rbind, 0, sizeof (rbind)); rbind[0].buffer_type = MYSQL_TYPE_BLOB; rbind[0].buffer_length = sizeof (GNUNET_HashCode); rbind[0].length = &k_length; rbind[0].buffer = &v_key; rbind[1].buffer_type = MYSQL_TYPE_BLOB; rbind[1].buffer_length = sizeof (GNUNET_HashCode); rbind[1].length = &h_length; rbind[1].buffer = &vhash; rbind[2].buffer_type = MYSQL_TYPE_LONG; rbind[2].is_unsigned = 1; rbind[2].buffer = &v_type; rbind[3].buffer_type = MYSQL_TYPE_BLOB; rbind[3].buffer_length = sizeof (buffer); rbind[3].length = &v_length; rbind[3].buffer = buffer; if ((GNUNET_OK != (ret = GNUNET_MYSQL_statement_run_prepared_select (plugin->mc, plugin->select_old_value, 4, rbind, return_ok, NULL, -1))) || (GNUNET_OK != (ret = GNUNET_MYSQL_statement_run_prepared (plugin->mc, plugin->delete_value, NULL, MYSQL_TYPE_BLOB, &v_key, sizeof (GNUNET_HashCode), &k_length, MYSQL_TYPE_BLOB, &vhash, sizeof (GNUNET_HashCode), &h_length, MYSQL_TYPE_LONG, &v_type, GNUNET_YES, MYSQL_TYPE_BLOB, buffer, (unsigned long) sizeof (buffer), &v_length, -1)))) { if (ret == GNUNET_SYSERR) itable (plugin); return GNUNET_SYSERR; } plugin->env->delete_notify (plugin->env->cls, &v_key, v_length + OVERHEAD); return GNUNET_OK; } /** * Entry point for the plugin. * * @param cls closure (the "struct GNUNET_DATACACHE_PluginEnvironmnet") * @return the plugin's closure (our "struct Plugin") */ void * libgnunet_plugin_datacache_mysql_init (void *cls) { struct GNUNET_DATACACHE_PluginEnvironment *env = cls; struct GNUNET_DATACACHE_PluginFunctions *api; struct Plugin *plugin; plugin = GNUNET_malloc (sizeof (struct Plugin)); plugin->env = env; plugin->mc = GNUNET_MYSQL_context_create (env->cfg, "datacache-mysql"); if ( (NULL == plugin->mc) || (GNUNET_OK != itable (plugin)) ) { if (NULL != plugin->mc) GNUNET_MYSQL_context_destroy (plugin->mc); GNUNET_free (plugin); return NULL; } api = GNUNET_malloc (sizeof (struct GNUNET_DATACACHE_PluginFunctions)); api->cls = plugin; api->get = &mysql_plugin_get; api->put = &mysql_plugin_put; api->del = &mysql_plugin_del; GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "mysql", _("MySQL datacache running\n")); return api; } /** * Exit point from the plugin. * * @param cls closure (our "struct Plugin") * @return NULL */ void * libgnunet_plugin_datacache_mysql_done (void *cls) { struct GNUNET_DATACACHE_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; GNUNET_MYSQL_context_destroy (plugin->mc); GNUNET_free (plugin); GNUNET_free (api); return NULL; } /* end of plugin_datacache_mysql.c */ gnunet-0.9.3/src/datacache/test_datacache.c0000644000175000017500000001043311760502551015533 00000000000000/* This file is part of GNUnet. (C) 2006, 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * @file datacache/test_datacache.c * @brief Test for the datacache implementations. * @author Nils Durner */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_datacache_lib.h" #define VERBOSE GNUNET_NO #define ASSERT(x) do { if (! (x)) { printf("Error at %s:%d\n", __FILE__, __LINE__); goto FAILURE;} } while (0) static int ok; /** * Name of plugin under test. */ static const char *plugin_name; static int checkIt (void *cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, size_t size, const char *data, enum GNUNET_BLOCK_Type type) { if (size != sizeof (GNUNET_HashCode)) { printf ("ERROR: Invalid size\n"); ok = 2; } if (0 != memcmp (data, cls, size)) { printf ("ERROR: Invalid data\n"); ok = 3; } return GNUNET_OK; } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_DATACACHE_Handle *h; GNUNET_HashCode k; GNUNET_HashCode n; struct GNUNET_TIME_Absolute exp; unsigned int i; ok = 0; h = GNUNET_DATACACHE_create (cfg, "testcache"); if (h == NULL) { FPRINTF (stderr, "%s", "Failed to initialize datacache. Database likely not setup, skipping test.\n"); return; } exp = GNUNET_TIME_absolute_get (); exp.abs_value += 5 * 60 * 1000; memset (&k, 0, sizeof (GNUNET_HashCode)); for (i = 0; i < 100; i++) { GNUNET_CRYPTO_hash (&k, sizeof (GNUNET_HashCode), &n); ASSERT (GNUNET_OK == GNUNET_DATACACHE_put (h, &k, sizeof (GNUNET_HashCode), (const char *) &n, 1 + i % 16, exp)); k = n; } memset (&k, 0, sizeof (GNUNET_HashCode)); for (i = 0; i < 100; i++) { GNUNET_CRYPTO_hash (&k, sizeof (GNUNET_HashCode), &n); ASSERT (1 == GNUNET_DATACACHE_get (h, &k, 1 + i % 16, &checkIt, &n)); k = n; } memset (&k, 42, sizeof (GNUNET_HashCode)); GNUNET_CRYPTO_hash (&k, sizeof (GNUNET_HashCode), &n); ASSERT (GNUNET_OK == GNUNET_DATACACHE_put (h, &k, sizeof (GNUNET_HashCode), (const char *) &n, 792, GNUNET_TIME_UNIT_FOREVER_ABS)); ASSERT (0 != GNUNET_DATACACHE_get (h, &k, 792, &checkIt, &n)); GNUNET_DATACACHE_destroy (h); ASSERT (ok == 0); return; FAILURE: if (h != NULL) GNUNET_DATACACHE_destroy (h); ok = GNUNET_SYSERR; } int main (int argc, char *argv[]) { char *pos; char cfg_name[128]; char *const xargv[] = { "test-datacache", "-c", cfg_name, #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("test-datacache", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); /* determine name of plugin to use */ plugin_name = argv[0]; while (NULL != (pos = strstr (plugin_name, "_"))) plugin_name = pos + 1; if (NULL != (pos = strstr (plugin_name, "."))) pos[0] = 0; else pos = (char *) plugin_name; GNUNET_snprintf (cfg_name, sizeof (cfg_name), "test_datacache_data_%s.conf", plugin_name); if (pos != plugin_name) pos[0] = '.'; GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1, xargv, "test-datacache", "nohelp", options, &run, NULL); if (ok != 0) FPRINTF (stderr, "Missed some testcases: %d\n", ok); return ok; } /* end of test_datacache.c */ gnunet-0.9.3/src/datacache/perf_datacache_data_postgres.conf0000644000175000017500000000016711654602354021141 00000000000000[perfcache] QUOTA = 500 KB DATABASE = postgres [datacache-postgres] CONFIG = connect_timeout=10; dbname=gnunetcheck gnunet-0.9.3/src/dht/0000755000175000017500000000000011763406750011403 500000000000000gnunet-0.9.3/src/dht/gnunet-service-dht_clients.h0000644000175000017500000001267011760502551016727 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/gnunet-service-dht_clients.h * @brief GNUnet DHT service's client management code * @author Christian Grothoff * @author Nathan Evans */ #ifndef GNUNET_SERVICE_DHT_CLIENT_H #define GNUNET_SERVICE_DHT_CLIENT_H #include "gnunet_util_lib.h" #include "gnunet_block_lib.h" /** * Handle a reply we've received from another peer. If the reply * matches any of our pending queries, forward it to the respective * client(s). * * @param expiration when will the reply expire * @param key the query this reply is for * @param get_path_length number of peers in 'get_path' * @param get_path path the reply took on get * @param put_path_length number of peers in 'put_path' * @param put_path path the reply took on put * @param type type of the reply * @param data_size number of bytes in 'data' * @param data application payload data */ void GDS_CLIENTS_handle_reply (struct GNUNET_TIME_Absolute expiration, const GNUNET_HashCode * key, unsigned int get_path_length, const struct GNUNET_PeerIdentity *get_path, unsigned int put_path_length, const struct GNUNET_PeerIdentity *put_path, enum GNUNET_BLOCK_Type type, size_t data_size, const void *data); /** * Check if some client is monitoring GET messages and notify * them in that case. * * @param options Options, for instance RecordRoute, DemultiplexEverywhere. * @param type The type of data in the request. * @param hop_count Hop count so far. * @param path_length number of entries in path (or 0 if not recorded). * @param path peers on the GET path (or NULL if not recorded). * @param desired_replication_level Desired replication level. * @param key Key of the requested data. */ void GDS_CLIENTS_process_get (uint32_t options, enum GNUNET_BLOCK_Type type, uint32_t hop_count, uint32_t desired_replication_level, unsigned int path_length, const struct GNUNET_PeerIdentity *path, const GNUNET_HashCode * key); /** * Check if some client is monitoring GET RESP messages and notify * them in that case. * * @param type The type of data in the result. * @param get_path Peers on GET path (or NULL if not recorded). * @param get_path_length number of entries in get_path. * @param put_path peers on the PUT path (or NULL if not recorded). * @param put_path_length number of entries in get_path. * @param exp Expiration time of the data. * @param key Key of the data. * @param data Pointer to the result data. * @param size Number of bytes in data. */ void GDS_CLIENTS_process_get_resp (enum GNUNET_BLOCK_Type type, const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int put_path_length, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const void *data, size_t size); /** * Check if some client is monitoring PUT messages and notify * them in that case. * * @param options Options, for instance RecordRoute, DemultiplexEverywhere. * @param type The type of data in the request. * @param hop_count Hop count so far. * @param path_length number of entries in path (or 0 if not recorded). * @param path peers on the PUT path (or NULL if not recorded). * @param desired_replication_level Desired replication level. * @param exp Expiration time of the data. * @param key Key under which data is to be stored. * @param data Pointer to the data carried. * @param size Number of bytes in data. */ void GDS_CLIENTS_process_put (uint32_t options, enum GNUNET_BLOCK_Type type, uint32_t hop_count, uint32_t desired_replication_level, unsigned int path_length, const struct GNUNET_PeerIdentity *path, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const void *data, size_t size); /** * Initialize client subsystem. * * @param server the initialized server */ void GDS_CLIENTS_init (struct GNUNET_SERVER_Handle *server); /** * Shutdown client subsystem. */ void GDS_CLIENTS_done (void); #endif gnunet-0.9.3/src/dht/gnunet-service-dht_datacache.h0000644000175000017500000000537711760502551017171 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/gnunet-service-dht_datacache.h * @brief GNUnet DHT service's datacache integration * @author Christian Grothoff * @author Nathan Evans */ #ifndef GNUNET_SERVICE_DHT_DATACACHE_H #define GNUNET_SERVICE_DHT_DATACACHE_H #include "gnunet_util_lib.h" #include "gnunet_block_lib.h" /** * Handle a datum we've received from another peer. Cache if * possible. * * @param expiration when will the reply expire * @param key the query this reply is for * @param put_path_length number of peers in 'put_path' * @param put_path path the reply took on put * @param type type of the reply * @param data_size number of bytes in 'data' * @param data application payload data */ void GDS_DATACACHE_handle_put (struct GNUNET_TIME_Absolute expiration, const GNUNET_HashCode * key, unsigned int put_path_length, const struct GNUNET_PeerIdentity *put_path, enum GNUNET_BLOCK_Type type, size_t data_size, const void *data); /** * Handle a GET request we've received from another peer. * * @param key the query * @param type requested data type * @param xquery extended query * @param xquery_size number of bytes in xquery * @param reply_bf where the reply bf is (to be) stored, possibly updated!, can be NULL * @param reply_bf_mutator mutation value for reply_bf * @return evaluation result for the local replies */ enum GNUNET_BLOCK_EvaluationResult GDS_DATACACHE_handle_get (const GNUNET_HashCode * key, enum GNUNET_BLOCK_Type type, const void *xquery, size_t xquery_size, struct GNUNET_CONTAINER_BloomFilter **reply_bf, uint32_t reply_bf_mutator); /** * Initialize datacache subsystem. */ void GDS_DATACACHE_init (void); /** * Shutdown datacache subsystem. */ void GDS_DATACACHE_done (void); #endif gnunet-0.9.3/src/dht/gnunet-service-dht_neighbours.c0000644000175000017500000017701111760502551017427 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/gnunet-service-dht_neighbours.c * @brief GNUnet DHT service's bucket and neighbour management code * @author Christian Grothoff * @author Nathan Evans */ #include "platform.h" #include "gnunet_block_lib.h" #include "gnunet_util_lib.h" #include "gnunet_hello_lib.h" #include "gnunet_constants.h" #include "gnunet_protocols.h" #include "gnunet_nse_service.h" #include "gnunet_ats_service.h" #include "gnunet_core_service.h" #include "gnunet_datacache_lib.h" #include "gnunet_transport_service.h" #include "gnunet_hello_lib.h" #include "gnunet_dht_service.h" #include "gnunet_statistics_service.h" #include "gnunet-service-dht.h" #include "gnunet-service-dht_clients.h" #include "gnunet-service-dht_datacache.h" #include "gnunet-service-dht_hello.h" #include "gnunet-service-dht_neighbours.h" #include "gnunet-service-dht_nse.h" #include "gnunet-service-dht_routing.h" #include #include "dht.h" /** * How many buckets will we allow total. */ #define MAX_BUCKETS sizeof (GNUNET_HashCode) * 8 /** * What is the maximum number of peers in a given bucket. */ #define DEFAULT_BUCKET_SIZE 8 /** * Desired replication level for FIND PEER requests */ #define FIND_PEER_REPLICATION_LEVEL 4 /** * Maximum allowed replication level for all requests. */ #define MAXIMUM_REPLICATION_LEVEL 16 /** * How often to update our preference levels for peers in our routing tables. */ #define DHT_DEFAULT_PREFERENCE_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2) /** * How long at least to wait before sending another find peer request. */ #define DHT_MINIMUM_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30) /** * How long at most to wait before sending another find peer request. */ #define DHT_MAXIMUM_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 10) /** * How long at most to wait for transmission of a GET request to another peer? */ #define GET_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2) GNUNET_NETWORK_STRUCT_BEGIN /** * P2P PUT message */ struct PeerPutMessage { /** * Type: GNUNET_MESSAGE_TYPE_DHT_P2P_PUT */ struct GNUNET_MessageHeader header; /** * Processing options */ uint32_t options GNUNET_PACKED; /** * Content type. */ uint32_t type GNUNET_PACKED; /** * Hop count */ uint32_t hop_count GNUNET_PACKED; /** * Replication level for this message */ uint32_t desired_replication_level GNUNET_PACKED; /** * Length of the PUT path that follows (if tracked). */ uint32_t put_path_length GNUNET_PACKED; /** * When does the content expire? */ struct GNUNET_TIME_AbsoluteNBO expiration_time; /** * Bloomfilter (for peer identities) to stop circular routes */ char bloomfilter[DHT_BLOOM_SIZE]; /** * The key we are storing under. */ GNUNET_HashCode key; /* put path (if tracked) */ /* Payload */ }; /** * P2P Result message */ struct PeerResultMessage { /** * Type: GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT */ struct GNUNET_MessageHeader header; /** * Content type. */ uint32_t type GNUNET_PACKED; /** * Length of the PUT path that follows (if tracked). */ uint32_t put_path_length GNUNET_PACKED; /** * Length of the GET path that follows (if tracked). */ uint32_t get_path_length GNUNET_PACKED; /** * When does the content expire? */ struct GNUNET_TIME_AbsoluteNBO expiration_time; /** * The key of the corresponding GET request. */ GNUNET_HashCode key; /* put path (if tracked) */ /* get path (if tracked) */ /* Payload */ }; /** * P2P GET message */ struct PeerGetMessage { /** * Type: GNUNET_MESSAGE_TYPE_DHT_P2P_GET */ struct GNUNET_MessageHeader header; /** * Processing options */ uint32_t options GNUNET_PACKED; /** * Desired content type. */ uint32_t type GNUNET_PACKED; /** * Hop count */ uint32_t hop_count GNUNET_PACKED; /** * Desired replication level for this request. */ uint32_t desired_replication_level GNUNET_PACKED; /** * Size of the extended query. */ uint32_t xquery_size; /** * Bloomfilter mutator. */ uint32_t bf_mutator; /** * Bloomfilter (for peer identities) to stop circular routes */ char bloomfilter[DHT_BLOOM_SIZE]; /** * The key we are looking for. */ GNUNET_HashCode key; /* xquery */ /* result bloomfilter */ }; GNUNET_NETWORK_STRUCT_END /** * Linked list of messages to send to a particular other peer. */ struct P2PPendingMessage { /** * Pointer to next item in the list */ struct P2PPendingMessage *next; /** * Pointer to previous item in the list */ struct P2PPendingMessage *prev; /** * Message importance level. FIXME: used? useful? */ unsigned int importance; /** * When does this message time out? */ struct GNUNET_TIME_Absolute timeout; /** * Actual message to be sent, allocated at the end of the struct: * // msg = (cast) &pm[1]; * // memcpy (&pm[1], data, len); */ const struct GNUNET_MessageHeader *msg; }; /** * Entry for a peer in a bucket. */ struct PeerInfo { /** * Next peer entry (DLL) */ struct PeerInfo *next; /** * Prev peer entry (DLL) */ struct PeerInfo *prev; /** * Count of outstanding messages for peer. FIXME: NEEDED? * FIXME: bound queue size!? */ unsigned int pending_count; /** * Head of pending messages to be sent to this peer. */ struct P2PPendingMessage *head; /** * Tail of pending messages to be sent to this peer. */ struct P2PPendingMessage *tail; /** * Core handle for sending messages to this peer. */ struct GNUNET_CORE_TransmitHandle *th; /** * Task for scheduling preference updates */ GNUNET_SCHEDULER_TaskIdentifier preference_task; /** * What is the identity of the peer? */ struct GNUNET_PeerIdentity id; #if 0 /** * What is the average latency for replies received? */ struct GNUNET_TIME_Relative latency; /** * Transport level distance to peer. */ unsigned int distance; #endif }; /** * Peers are grouped into buckets. */ struct PeerBucket { /** * Head of DLL */ struct PeerInfo *head; /** * Tail of DLL */ struct PeerInfo *tail; /** * Number of peers in the bucket. */ unsigned int peers_size; }; /** * The lowest currently used bucket, initially 0 (for 0-bits matching bucket). */ static unsigned int closest_bucket; /** * How many peers have we added since we sent out our last * find peer request? */ static unsigned int newly_found_peers; /** * The buckets. Array of size MAX_BUCKET_SIZE. Offset 0 means 0 bits matching. */ static struct PeerBucket k_buckets[MAX_BUCKETS]; /** * Hash map of all known peers, for easy removal from k_buckets on disconnect. */ static struct GNUNET_CONTAINER_MultiHashMap *all_known_peers; /** * Maximum size for each bucket. */ static unsigned int bucket_size = DEFAULT_BUCKET_SIZE; /** * Task that sends FIND PEER requests. */ static GNUNET_SCHEDULER_TaskIdentifier find_peer_task; /** * Identity of this peer. */ static struct GNUNET_PeerIdentity my_identity; /** * Handle to CORE. */ static struct GNUNET_CORE_Handle *coreAPI; /** * Handle to ATS. */ static struct GNUNET_ATS_PerformanceHandle *atsAPI; /** * Find the optimal bucket for this key. * * @param hc the hashcode to compare our identity to * @return the proper bucket index, or GNUNET_SYSERR * on error (same hashcode) */ static int find_bucket (const GNUNET_HashCode * hc) { unsigned int bits; bits = GNUNET_CRYPTO_hash_matching_bits (&my_identity.hashPubKey, hc); if (bits == MAX_BUCKETS) { /* How can all bits match? Got my own ID? */ GNUNET_break (0); return GNUNET_SYSERR; } return MAX_BUCKETS - bits - 1; } /** * Let GNUnet core know that we like the given peer. * * @param cls the 'struct PeerInfo' of the peer * @param tc scheduler context. */ static void update_core_preference (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerInfo *peer = cls; uint64_t preference; unsigned int matching; int bucket; peer->preference_task = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; matching = GNUNET_CRYPTO_hash_matching_bits (&my_identity.hashPubKey, &peer->id.hashPubKey); if (matching >= 64) matching = 63; bucket = find_bucket (&peer->id.hashPubKey); if (bucket == GNUNET_SYSERR) preference = 0; else { GNUNET_assert (k_buckets[bucket].peers_size != 0); preference = (1LL << matching) / k_buckets[bucket].peers_size; } if (preference == 0) { peer->preference_task = GNUNET_SCHEDULER_add_delayed (DHT_DEFAULT_PREFERENCE_INTERVAL, &update_core_preference, peer); return; } GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Preference updates given to core"), 1, GNUNET_NO); GNUNET_ATS_change_preference (atsAPI, &peer->id, GNUNET_ATS_PREFERENCE_BANDWIDTH, (double) preference, GNUNET_ATS_PREFERENCE_END); peer->preference_task = GNUNET_SCHEDULER_add_delayed (DHT_DEFAULT_PREFERENCE_INTERVAL, &update_core_preference, peer); } /** * Closure for 'add_known_to_bloom'. */ struct BloomConstructorContext { /** * Bloom filter under construction. */ struct GNUNET_CONTAINER_BloomFilter *bloom; /** * Mutator to use. */ uint32_t bf_mutator; }; /** * Add each of the peers we already know to the bloom filter of * the request so that we don't get duplicate HELLOs. * * @param cls the 'struct BloomConstructorContext'. * @param key peer identity to add to the bloom filter * @param value value the peer information (unused) * @return GNUNET_YES (we should continue to iterate) */ static int add_known_to_bloom (void *cls, const GNUNET_HashCode * key, void *value) { struct BloomConstructorContext *ctx = cls; GNUNET_HashCode mh; GNUNET_BLOCK_mingle_hash (key, ctx->bf_mutator, &mh); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding known peer (%s) to bloomfilter for FIND PEER with mutation %u\n", GNUNET_h2s (key), ctx->bf_mutator); GNUNET_CONTAINER_bloomfilter_add (ctx->bloom, &mh); return GNUNET_YES; } /** * Task to send a find peer message for our own peer identifier * so that we can find the closest peers in the network to ourselves * and attempt to connect to them. * * @param cls closure for this task * @param tc the context under which the task is running */ static void send_find_peer_message (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TIME_Relative next_send_time; struct BloomConstructorContext bcc; struct GNUNET_CONTAINER_BloomFilter *peer_bf; find_peer_task = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; if (newly_found_peers > bucket_size) { /* If we are finding many peers already, no need to send out our request right now! */ find_peer_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &send_find_peer_message, NULL); newly_found_peers = 0; return; } bcc.bf_mutator = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX); bcc.bloom = GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE, GNUNET_CONSTANTS_BLOOMFILTER_K); GNUNET_CONTAINER_multihashmap_iterate (all_known_peers, &add_known_to_bloom, &bcc); GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# FIND PEER messages initiated"), 1, GNUNET_NO); peer_bf = GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE, GNUNET_CONSTANTS_BLOOMFILTER_K); // FIXME: pass priority!? GDS_NEIGHBOURS_handle_get (GNUNET_BLOCK_TYPE_DHT_HELLO, GNUNET_DHT_RO_FIND_PEER, FIND_PEER_REPLICATION_LEVEL, 0, &my_identity.hashPubKey, NULL, 0, bcc.bloom, bcc.bf_mutator, peer_bf); GNUNET_CONTAINER_bloomfilter_free (peer_bf); GNUNET_CONTAINER_bloomfilter_free (bcc.bloom); /* schedule next round */ next_send_time.rel_value = DHT_MINIMUM_FIND_PEER_INTERVAL.rel_value + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, DHT_MAXIMUM_FIND_PEER_INTERVAL.rel_value / (newly_found_peers + 1)); newly_found_peers = 0; find_peer_task = GNUNET_SCHEDULER_add_delayed (next_send_time, &send_find_peer_message, NULL); } /** * Method called whenever a peer connects. * * @param cls closure * @param peer peer identity this notification is about * @param atsi performance data * @param atsi_count number of records in 'atsi' */ static void handle_core_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct PeerInfo *ret; int peer_bucket; /* Check for connect to self message */ if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity))) return; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected %s to %s\n", GNUNET_i2s (&my_identity), GNUNET_h2s (&peer->hashPubKey)); if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (all_known_peers, &peer->hashPubKey)) { GNUNET_break (0); return; } GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# peers connected"), 1, GNUNET_NO); peer_bucket = find_bucket (&peer->hashPubKey); GNUNET_assert ((peer_bucket >= 0) && (peer_bucket < MAX_BUCKETS)); ret = GNUNET_malloc (sizeof (struct PeerInfo)); #if 0 ret->latency = latency; ret->distance = distance; #endif ret->id = *peer; GNUNET_CONTAINER_DLL_insert_tail (k_buckets[peer_bucket].head, k_buckets[peer_bucket].tail, ret); k_buckets[peer_bucket].peers_size++; closest_bucket = GNUNET_MAX (closest_bucket, peer_bucket); if ((peer_bucket > 0) && (k_buckets[peer_bucket].peers_size <= bucket_size)) { ret->preference_task = GNUNET_SCHEDULER_add_now (&update_core_preference, ret); newly_found_peers++; } GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (all_known_peers, &peer->hashPubKey, ret, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); if (1 == GNUNET_CONTAINER_multihashmap_size (all_known_peers)) { /* got a first connection, good time to start with FIND PEER requests... */ find_peer_task = GNUNET_SCHEDULER_add_now (&send_find_peer_message, NULL); } } /** * Method called whenever a peer disconnects. * * @param cls closure * @param peer peer identity this notification is about */ static void handle_core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { struct PeerInfo *to_remove; int current_bucket; struct P2PPendingMessage *pos; unsigned int discarded; /* Check for disconnect from self message */ if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity))) return; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnected %s from %s\n", GNUNET_i2s (&my_identity), GNUNET_h2s (&peer->hashPubKey)); to_remove = GNUNET_CONTAINER_multihashmap_get (all_known_peers, &peer->hashPubKey); if (NULL == to_remove) { GNUNET_break (0); return; } GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# peers connected"), -1, GNUNET_NO); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (all_known_peers, &peer->hashPubKey, to_remove)); if (GNUNET_SCHEDULER_NO_TASK != to_remove->preference_task) { GNUNET_SCHEDULER_cancel (to_remove->preference_task); to_remove->preference_task = GNUNET_SCHEDULER_NO_TASK; } current_bucket = find_bucket (&to_remove->id.hashPubKey); GNUNET_assert (current_bucket >= 0); GNUNET_CONTAINER_DLL_remove (k_buckets[current_bucket].head, k_buckets[current_bucket].tail, to_remove); GNUNET_assert (k_buckets[current_bucket].peers_size > 0); k_buckets[current_bucket].peers_size--; while ((closest_bucket > 0) && (k_buckets[closest_bucket].peers_size == 0)) closest_bucket--; if (to_remove->th != NULL) { GNUNET_CORE_notify_transmit_ready_cancel (to_remove->th); to_remove->th = NULL; } discarded = 0; while (NULL != (pos = to_remove->head)) { GNUNET_CONTAINER_DLL_remove (to_remove->head, to_remove->tail, pos); discarded++; GNUNET_free (pos); } GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Queued messages discarded (peer disconnected)"), discarded, GNUNET_NO); GNUNET_free (to_remove); } /** * Called when core is ready to send a message we asked for * out to the destination. * * @param cls the 'struct PeerInfo' of the target peer * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t core_transmit_notify (void *cls, size_t size, void *buf) { struct PeerInfo *peer = cls; char *cbuf = buf; struct P2PPendingMessage *pending; size_t off; size_t msize; peer->th = NULL; while ((NULL != (pending = peer->head)) && (GNUNET_TIME_absolute_get_remaining (pending->timeout).rel_value == 0)) { peer->pending_count--; GNUNET_CONTAINER_DLL_remove (peer->head, peer->tail, pending); GNUNET_free (pending); } if (pending == NULL) { /* no messages pending */ return 0; } if (buf == NULL) { peer->th = GNUNET_CORE_notify_transmit_ready (coreAPI, GNUNET_YES, pending->importance, GNUNET_TIME_absolute_get_remaining (pending->timeout), &peer->id, ntohs (pending->msg->size), &core_transmit_notify, peer); GNUNET_break (NULL != peer->th); return 0; } off = 0; while ((NULL != (pending = peer->head)) && (size - off >= (msize = ntohs (pending->msg->size)))) { GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Bytes transmitted to other peers"), msize, GNUNET_NO); memcpy (&cbuf[off], pending->msg, msize); off += msize; peer->pending_count--; GNUNET_CONTAINER_DLL_remove (peer->head, peer->tail, pending); GNUNET_free (pending); } if (peer->head != NULL) { peer->th = GNUNET_CORE_notify_transmit_ready (coreAPI, GNUNET_YES, pending->importance, GNUNET_TIME_absolute_get_remaining (pending->timeout), &peer->id, msize, &core_transmit_notify, peer); GNUNET_break (NULL != peer->th); } return off; } /** * Transmit all messages in the peer's message queue. * * @param peer message queue to process */ static void process_peer_queue (struct PeerInfo *peer) { struct P2PPendingMessage *pending; if (NULL == (pending = peer->head)) return; if (NULL != peer->th) return; GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Bytes of bandwdith requested from core"), ntohs (pending->msg->size), GNUNET_NO); peer->th = GNUNET_CORE_notify_transmit_ready (coreAPI, GNUNET_YES, pending->importance, GNUNET_TIME_absolute_get_remaining (pending->timeout), &peer->id, ntohs (pending->msg->size), &core_transmit_notify, peer); GNUNET_break (NULL != peer->th); } /** * To how many peers should we (on average) forward the request to * obtain the desired target_replication count (on average). * * @param hop_count number of hops the message has traversed * @param target_replication the number of total paths desired * @return Some number of peers to forward the message to */ static unsigned int get_forward_count (uint32_t hop_count, uint32_t target_replication) { uint32_t random_value; uint32_t forward_count; float target_value; if (hop_count > GDS_NSE_get () * 6.0) { /* forcefully terminate */ return 0; } if (hop_count > GDS_NSE_get () * 4.0) { /* Once we have reached our ideal number of hops, only forward to 1 peer */ return 1; } /* bound by system-wide maximum */ target_replication = GNUNET_MIN (MAXIMUM_REPLICATION_LEVEL, target_replication); target_value = 1 + (target_replication - 1.0) / (GDS_NSE_get () + ((float) (target_replication - 1.0) * hop_count)); /* Set forward count to floor of target_value */ forward_count = (uint32_t) target_value; /* Subtract forward_count (floor) from target_value (yields value between 0 and 1) */ target_value = target_value - forward_count; random_value = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX); if (random_value < (target_value * UINT32_MAX)) forward_count++; return forward_count; } /** * Compute the distance between have and target as a 32-bit value. * Differences in the lower bits must count stronger than differences * in the higher bits. * * @return 0 if have==target, otherwise a number * that is larger as the distance between * the two hash codes increases */ static unsigned int get_distance (const GNUNET_HashCode * target, const GNUNET_HashCode * have) { unsigned int bucket; unsigned int msb; unsigned int lsb; unsigned int i; /* We have to represent the distance between two 2^9 (=512)-bit * numbers as a 2^5 (=32)-bit number with "0" being used for the * two numbers being identical; furthermore, we need to * guarantee that a difference in the number of matching * bits is always represented in the result. * * We use 2^32/2^9 numerical values to distinguish between * hash codes that have the same LSB bit distance and * use the highest 2^9 bits of the result to signify the * number of (mis)matching LSB bits; if we have 0 matching * and hence 512 mismatching LSB bits we return -1 (since * 512 itself cannot be represented with 9 bits) */ /* first, calculate the most significant 9 bits of our * result, aka the number of LSBs */ bucket = GNUNET_CRYPTO_hash_matching_bits (target, have); /* bucket is now a value between 0 and 512 */ if (bucket == 512) return 0; /* perfect match */ if (bucket == 0) return (unsigned int) -1; /* LSB differs; use max (if we did the bit-shifting * below, we'd end up with max+1 (overflow)) */ /* calculate the most significant bits of the final result */ msb = (512 - bucket) << (32 - 9); /* calculate the 32-9 least significant bits of the final result by * looking at the differences in the 32-9 bits following the * mismatching bit at 'bucket' */ lsb = 0; for (i = bucket + 1; (i < sizeof (GNUNET_HashCode) * 8) && (i < bucket + 1 + 32 - 9); i++) { if (GNUNET_CRYPTO_hash_get_bit (target, i) != GNUNET_CRYPTO_hash_get_bit (have, i)) lsb |= (1 << (bucket + 32 - 9 - i)); /* first bit set will be 10, * last bit set will be 31 -- if * i does not reach 512 first... */ } return msb | lsb; } /** * Check whether my identity is closer than any known peers. If a * non-null bloomfilter is given, check if this is the closest peer * that hasn't already been routed to. * * @param key hash code to check closeness to * @param bloom bloomfilter, exclude these entries from the decision * @return GNUNET_YES if node location is closest, * GNUNET_NO otherwise. */ static int am_closest_peer (const GNUNET_HashCode * key, const struct GNUNET_CONTAINER_BloomFilter *bloom) { int bits; int other_bits; int bucket_num; int count; struct PeerInfo *pos; if (0 == memcmp (&my_identity.hashPubKey, key, sizeof (GNUNET_HashCode))) return GNUNET_YES; bucket_num = find_bucket (key); GNUNET_assert (bucket_num >= 0); bits = GNUNET_CRYPTO_hash_matching_bits (&my_identity.hashPubKey, key); pos = k_buckets[bucket_num].head; count = 0; while ((pos != NULL) && (count < bucket_size)) { if ((bloom != NULL) && (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey))) { pos = pos->next; continue; /* Skip already checked entries */ } other_bits = GNUNET_CRYPTO_hash_matching_bits (&pos->id.hashPubKey, key); if (other_bits > bits) return GNUNET_NO; if (other_bits == bits) /* We match the same number of bits */ return GNUNET_YES; pos = pos->next; } /* No peers closer, we are the closest! */ return GNUNET_YES; } /** * Select a peer from the routing table that would be a good routing * destination for sending a message for "key". The resulting peer * must not be in the set of blocked peers.

    * * Note that we should not ALWAYS select the closest peer to the * target, peers further away from the target should be chosen with * exponentially declining probability. * * FIXME: double-check that this is fine * * * @param key the key we are selecting a peer to route to * @param bloom a bloomfilter containing entries this request has seen already * @param hops how many hops has this message traversed thus far * @return Peer to route to, or NULL on error */ static struct PeerInfo * select_peer (const GNUNET_HashCode * key, const struct GNUNET_CONTAINER_BloomFilter *bloom, uint32_t hops) { unsigned int bc; unsigned int count; unsigned int selected; struct PeerInfo *pos; unsigned int dist; unsigned int smallest_distance; struct PeerInfo *chosen; if (hops >= GDS_NSE_get ()) { /* greedy selection (closest peer that is not in bloomfilter) */ smallest_distance = UINT_MAX; chosen = NULL; for (bc = 0; bc <= closest_bucket; bc++) { pos = k_buckets[bc].head; count = 0; while ((pos != NULL) && (count < bucket_size)) { if ((bloom == NULL) || (GNUNET_NO == GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey))) { dist = get_distance (key, &pos->id.hashPubKey); if (dist < smallest_distance) { chosen = pos; smallest_distance = dist; } } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Excluded peer `%s' due to BF match in greedy routing for %s\n", GNUNET_i2s (&pos->id), GNUNET_h2s (key)); GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Peers excluded from routing due to Bloomfilter"), 1, GNUNET_NO); } count++; pos = pos->next; } } if (NULL == chosen) GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Peer selection failed"), 1, GNUNET_NO); return chosen; } /* select "random" peer */ /* count number of peers that are available and not filtered */ count = 0; for (bc = 0; bc <= closest_bucket; bc++) { pos = k_buckets[bc].head; while ((pos != NULL) && (count < bucket_size)) { if ((bloom != NULL) && (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey))) { GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Peers excluded from routing due to Bloomfilter"), 1, GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Excluded peer `%s' due to BF match in random routing for %s\n", GNUNET_i2s (&pos->id), GNUNET_h2s (key)); pos = pos->next; continue; /* Ignore bloomfiltered peers */ } count++; pos = pos->next; } } if (count == 0) /* No peers to select from! */ { GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Peer selection failed"), 1, GNUNET_NO); return NULL; } /* Now actually choose a peer */ selected = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, count); count = 0; for (bc = 0; bc <= closest_bucket; bc++) { pos = k_buckets[bc].head; while ((pos != NULL) && (count < bucket_size)) { if ((bloom != NULL) && (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey))) { pos = pos->next; continue; /* Ignore bloomfiltered peers */ } if (0 == selected--) return pos; pos = pos->next; } } GNUNET_break (0); return NULL; } /** * Compute the set of peers that the given request should be * forwarded to. * * @param key routing key * @param bloom bloom filter excluding peers as targets, all selected * peers will be added to the bloom filter * @param hop_count number of hops the request has traversed so far * @param target_replication desired number of replicas * @param targets where to store an array of target peers (to be * free'd by the caller) * @return number of peers returned in 'targets'. */ static unsigned int get_target_peers (const GNUNET_HashCode * key, struct GNUNET_CONTAINER_BloomFilter *bloom, uint32_t hop_count, uint32_t target_replication, struct PeerInfo ***targets) { unsigned int ret; unsigned int off; struct PeerInfo **rtargets; struct PeerInfo *nxt; GNUNET_assert (NULL != bloom); ret = get_forward_count (hop_count, target_replication); if (ret == 0) { *targets = NULL; return 0; } rtargets = GNUNET_malloc (sizeof (struct PeerInfo *) * ret); for (off = 0; off < ret; off++) { nxt = select_peer (key, bloom, hop_count); if (nxt == NULL) break; rtargets[off] = nxt; GNUNET_break (GNUNET_NO == GNUNET_CONTAINER_bloomfilter_test (bloom, &nxt->id.hashPubKey)); GNUNET_CONTAINER_bloomfilter_add (bloom, &rtargets[off]->id.hashPubKey); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Selected %u/%u peers at hop %u for %s (target was %u)\n", off, GNUNET_CONTAINER_multihashmap_size (all_known_peers), (unsigned int) hop_count, GNUNET_h2s (key), ret); if (0 == off) { GNUNET_free (rtargets); *targets = NULL; return 0; } *targets = rtargets; return off; } /** * Perform a PUT operation. Forwards the given request to other * peers. Does not store the data locally. Does not give the * data to local clients. May do nothing if this is the only * peer in the network (or if we are the closest peer in the * network). * * @param type type of the block * @param options routing options * @param desired_replication_level desired replication count * @param expiration_time when does the content expire * @param hop_count how many hops has this message traversed so far * @param bf Bloom filter of peers this PUT has already traversed * @param key key for the content * @param put_path_length number of entries in put_path * @param put_path peers this request has traversed so far (if tracked) * @param data payload to store * @param data_size number of bytes in data */ void GDS_NEIGHBOURS_handle_put (enum GNUNET_BLOCK_Type type, enum GNUNET_DHT_RouteOption options, uint32_t desired_replication_level, struct GNUNET_TIME_Absolute expiration_time, uint32_t hop_count, struct GNUNET_CONTAINER_BloomFilter *bf, const GNUNET_HashCode * key, unsigned int put_path_length, struct GNUNET_PeerIdentity *put_path, const void *data, size_t data_size) { unsigned int target_count; unsigned int i; struct PeerInfo **targets; struct PeerInfo *target; struct P2PPendingMessage *pending; size_t msize; struct PeerPutMessage *ppm; struct GNUNET_PeerIdentity *pp; GNUNET_assert (NULL != bf); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding myself (%s) to PUT bloomfilter for %s\n", GNUNET_i2s (&my_identity), GNUNET_h2s (key)); GNUNET_CONTAINER_bloomfilter_add (bf, &my_identity.hashPubKey); GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# PUT requests routed"), 1, GNUNET_NO); target_count = get_target_peers (key, bf, hop_count, desired_replication_level, &targets); if (0 == target_count) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Routing PUT for %s terminates after %u hops at %s\n", GNUNET_h2s (key), (unsigned int) hop_count, GNUNET_i2s (&my_identity)); return; } msize = put_path_length * sizeof (struct GNUNET_PeerIdentity) + data_size + sizeof (struct PeerPutMessage); if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { put_path_length = 0; msize = data_size + sizeof (struct PeerPutMessage); } if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); GNUNET_free (targets); return; } GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# PUT messages queued for transmission"), target_count, GNUNET_NO); for (i = 0; i < target_count; i++) { target = targets[i]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Routing PUT for %s after %u hops to %s\n", GNUNET_h2s (key), (unsigned int) hop_count, GNUNET_i2s (&target->id)); pending = GNUNET_malloc (sizeof (struct P2PPendingMessage) + msize); pending->importance = 0; /* FIXME */ pending->timeout = expiration_time; ppm = (struct PeerPutMessage *) &pending[1]; pending->msg = &ppm->header; ppm->header.size = htons (msize); ppm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_PUT); ppm->options = htonl (options); ppm->type = htonl (type); ppm->hop_count = htonl (hop_count + 1); ppm->desired_replication_level = htonl (desired_replication_level); ppm->put_path_length = htonl (put_path_length); ppm->expiration_time = GNUNET_TIME_absolute_hton (expiration_time); GNUNET_break (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (bf, &target->id.hashPubKey)); GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_bloomfilter_get_raw_data (bf, ppm->bloomfilter, DHT_BLOOM_SIZE)); ppm->key = *key; pp = (struct GNUNET_PeerIdentity *) &ppm[1]; memcpy (pp, put_path, sizeof (struct GNUNET_PeerIdentity) * put_path_length); memcpy (&pp[put_path_length], data, data_size); GNUNET_CONTAINER_DLL_insert_tail (target->head, target->tail, pending); target->pending_count++; process_peer_queue (target); } GNUNET_free (targets); } /** * Perform a GET operation. Forwards the given request to other * peers. Does not lookup the key locally. May do nothing if this is * the only peer in the network (or if we are the closest peer in the * network). * * @param type type of the block * @param options routing options * @param desired_replication_level desired replication count * @param hop_count how many hops did this request traverse so far? * @param key key for the content * @param xquery extended query * @param xquery_size number of bytes in xquery * @param reply_bf bloomfilter to filter duplicates * @param reply_bf_mutator mutator for reply_bf * @param peer_bf filter for peers not to select (again) */ void GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type, enum GNUNET_DHT_RouteOption options, uint32_t desired_replication_level, uint32_t hop_count, const GNUNET_HashCode * key, const void *xquery, size_t xquery_size, const struct GNUNET_CONTAINER_BloomFilter *reply_bf, uint32_t reply_bf_mutator, struct GNUNET_CONTAINER_BloomFilter *peer_bf) { unsigned int target_count; unsigned int i; struct PeerInfo **targets; struct PeerInfo *target; struct P2PPendingMessage *pending; size_t msize; struct PeerGetMessage *pgm; char *xq; size_t reply_bf_size; GNUNET_assert (NULL != peer_bf); GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# GET requests routed"), 1, GNUNET_NO); target_count = get_target_peers (key, peer_bf, hop_count, desired_replication_level, &targets); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding myself (%s) to GET bloomfilter for %s\n", GNUNET_i2s (&my_identity), GNUNET_h2s (key)); GNUNET_CONTAINER_bloomfilter_add (peer_bf, &my_identity.hashPubKey); if (0 == target_count) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Routing GET for %s terminates after %u hops at %s\n", GNUNET_h2s (key), (unsigned int) hop_count, GNUNET_i2s (&my_identity)); return; } reply_bf_size = GNUNET_CONTAINER_bloomfilter_get_size (reply_bf); msize = xquery_size + sizeof (struct PeerGetMessage) + reply_bf_size; if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); GNUNET_free (targets); return; } GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# GET messages queued for transmission"), target_count, GNUNET_NO); /* forward request */ for (i = 0; i < target_count; i++) { target = targets[i]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Routing GET for %s after %u hops to %s\n", GNUNET_h2s (key), (unsigned int) hop_count, GNUNET_i2s (&target->id)); pending = GNUNET_malloc (sizeof (struct P2PPendingMessage) + msize); pending->importance = 0; /* FIXME */ pending->timeout = GNUNET_TIME_relative_to_absolute (GET_TIMEOUT); pgm = (struct PeerGetMessage *) &pending[1]; pending->msg = &pgm->header; pgm->header.size = htons (msize); pgm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_GET); pgm->options = htonl (options); pgm->type = htonl (type); pgm->hop_count = htonl (hop_count + 1); pgm->desired_replication_level = htonl (desired_replication_level); pgm->xquery_size = htonl (xquery_size); pgm->bf_mutator = reply_bf_mutator; GNUNET_break (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (peer_bf, &target->id.hashPubKey)); GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_bloomfilter_get_raw_data (peer_bf, pgm->bloomfilter, DHT_BLOOM_SIZE)); pgm->key = *key; xq = (char *) &pgm[1]; memcpy (xq, xquery, xquery_size); if (NULL != reply_bf) GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_bloomfilter_get_raw_data (reply_bf, &xq [xquery_size], reply_bf_size)); GNUNET_CONTAINER_DLL_insert_tail (target->head, target->tail, pending); target->pending_count++; process_peer_queue (target); } GNUNET_free (targets); } /** * Handle a reply (route to origin). Only forwards the reply back to * the given peer. Does not do local caching or forwarding to local * clients. * * @param target neighbour that should receive the block (if still connected) * @param type type of the block * @param expiration_time when does the content expire * @param key key for the content * @param put_path_length number of entries in put_path * @param put_path peers the original PUT traversed (if tracked) * @param get_path_length number of entries in put_path * @param get_path peers this reply has traversed so far (if tracked) * @param data payload of the reply * @param data_size number of bytes in data */ void GDS_NEIGHBOURS_handle_reply (const struct GNUNET_PeerIdentity *target, enum GNUNET_BLOCK_Type type, struct GNUNET_TIME_Absolute expiration_time, const GNUNET_HashCode * key, unsigned int put_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *get_path, const void *data, size_t data_size) { struct PeerInfo *pi; struct P2PPendingMessage *pending; size_t msize; struct PeerResultMessage *prm; struct GNUNET_PeerIdentity *paths; msize = data_size + sizeof (struct PeerResultMessage) + (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity); if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || (get_path_length > GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) || (put_path_length > GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) || (data_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)) { GNUNET_break (0); return; } pi = GNUNET_CONTAINER_multihashmap_get (all_known_peers, &target->hashPubKey); if (NULL == pi) { /* peer disconnected in the meantime, drop reply */ return; } GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# RESULT messages queued for transmission"), 1, GNUNET_NO); pending = GNUNET_malloc (sizeof (struct P2PPendingMessage) + msize); pending->importance = 0; /* FIXME */ pending->timeout = expiration_time; prm = (struct PeerResultMessage *) &pending[1]; pending->msg = &prm->header; prm->header.size = htons (msize); prm->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT); prm->type = htonl (type); prm->put_path_length = htonl (put_path_length); prm->get_path_length = htonl (get_path_length); prm->expiration_time = GNUNET_TIME_absolute_hton (expiration_time); prm->key = *key; paths = (struct GNUNET_PeerIdentity *) &prm[1]; memcpy (paths, put_path, put_path_length * sizeof (struct GNUNET_PeerIdentity)); memcpy (&paths[put_path_length], get_path, get_path_length * sizeof (struct GNUNET_PeerIdentity)); memcpy (&paths[put_path_length + get_path_length], data, data_size); GNUNET_CONTAINER_DLL_insert (pi->head, pi->tail, pending); pi->pending_count++; process_peer_queue (pi); } /** * To be called on core init/fail. * * @param cls service closure * @param server handle to the server for this service * @param identity the public identity of this peer */ static void core_init (void *cls, struct GNUNET_CORE_Handle *server, const struct GNUNET_PeerIdentity *identity) { GNUNET_assert (server != NULL); my_identity = *identity; } /** * Core handler for p2p put requests. * * @param cls closure * @param peer sender of the request * @param message message * @param peer peer identity this notification is about * @param atsi performance data * @param atsi_count number of records in 'atsi' * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_dht_p2p_put (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { const struct PeerPutMessage *put; const struct GNUNET_PeerIdentity *put_path; const void *payload; uint32_t putlen; uint16_t msize; size_t payload_size; enum GNUNET_DHT_RouteOption options; struct GNUNET_CONTAINER_BloomFilter *bf; GNUNET_HashCode test_key; msize = ntohs (message->size); if (msize < sizeof (struct PeerPutMessage)) { GNUNET_break_op (0); return GNUNET_YES; } put = (const struct PeerPutMessage *) message; putlen = ntohl (put->put_path_length); if ((msize < sizeof (struct PeerPutMessage) + putlen * sizeof (struct GNUNET_PeerIdentity)) || (putlen > GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity))) { GNUNET_break_op (0); return GNUNET_YES; } GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# P2P PUT requests received"), 1, GNUNET_NO); put_path = (const struct GNUNET_PeerIdentity *) &put[1]; payload = &put_path[putlen]; options = ntohl (put->options); payload_size = msize - (sizeof (struct PeerPutMessage) + putlen * sizeof (struct GNUNET_PeerIdentity)); switch (GNUNET_BLOCK_get_key (GDS_block_context, ntohl (put->type), payload, payload_size, &test_key)) { case GNUNET_YES: if (0 != memcmp (&test_key, &put->key, sizeof (GNUNET_HashCode))) { GNUNET_break_op (0); return GNUNET_YES; } break; case GNUNET_NO: GNUNET_break_op (0); return GNUNET_YES; case GNUNET_SYSERR: /* cannot verify, good luck */ break; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "PUT for `%s' from %s\n", GNUNET_h2s (&put->key), GNUNET_i2s (peer)); bf = GNUNET_CONTAINER_bloomfilter_init (put->bloomfilter, DHT_BLOOM_SIZE, GNUNET_CONSTANTS_BLOOMFILTER_K); GNUNET_break_op (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (bf, &peer->hashPubKey)); { struct GNUNET_PeerIdentity pp[putlen + 1]; /* extend 'put path' by sender */ if (0 != (options & GNUNET_DHT_RO_RECORD_ROUTE)) { memcpy (pp, put_path, putlen * sizeof (struct GNUNET_PeerIdentity)); pp[putlen] = *peer; putlen++; } else putlen = 0; /* give to local clients */ GDS_CLIENTS_handle_reply (GNUNET_TIME_absolute_ntoh (put->expiration_time), &put->key, 0, NULL, putlen, pp, ntohl (put->type), payload_size, payload); /* store locally */ if ((0 != (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) || (am_closest_peer (&put->key, bf))) GDS_DATACACHE_handle_put (GNUNET_TIME_absolute_ntoh (put->expiration_time), &put->key, putlen, pp, ntohl (put->type), payload_size, payload); /* route to other peers */ GDS_NEIGHBOURS_handle_put (ntohl (put->type), options, ntohl (put->desired_replication_level), GNUNET_TIME_absolute_ntoh (put->expiration_time), ntohl (put->hop_count), bf, &put->key, putlen, pp, payload, payload_size); } GNUNET_CONTAINER_bloomfilter_free (bf); GDS_CLIENTS_process_put (options, ntohl (put->type), ntohl (put->hop_count), ntohl (put->desired_replication_level), putlen, put_path, GNUNET_TIME_absolute_ntoh (put->expiration_time), &put->key, payload, payload_size); return GNUNET_YES; } /** * We have received a FIND PEER request. Send matching * HELLOs back. * * @param sender sender of the FIND PEER request * @param key peers close to this key are desired * @param bf peers matching this bf are excluded * @param bf_mutator mutator for bf */ static void handle_find_peer (const struct GNUNET_PeerIdentity *sender, const GNUNET_HashCode * key, struct GNUNET_CONTAINER_BloomFilter *bf, uint32_t bf_mutator) { int bucket_idx; struct PeerBucket *bucket; struct PeerInfo *peer; unsigned int choice; GNUNET_HashCode mhash; const struct GNUNET_HELLO_Message *hello; /* first, check about our own HELLO */ if (NULL != GDS_my_hello) { GNUNET_BLOCK_mingle_hash (&my_identity.hashPubKey, bf_mutator, &mhash); if ((NULL == bf) || (GNUNET_YES != GNUNET_CONTAINER_bloomfilter_test (bf, &mhash))) { GDS_NEIGHBOURS_handle_reply (sender, GNUNET_BLOCK_TYPE_DHT_HELLO, GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION), key, 0, NULL, 0, NULL, GDS_my_hello, GNUNET_HELLO_size ((const struct GNUNET_HELLO_Message *) GDS_my_hello)); } else { GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# FIND PEER requests ignored due to Bloomfilter"), 1, GNUNET_NO); } } else { GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# FIND PEER requests ignored due to lack of HELLO"), 1, GNUNET_NO); } /* then, also consider sending a random HELLO from the closest bucket */ if (0 == memcmp (&my_identity.hashPubKey, key, sizeof (GNUNET_HashCode))) bucket_idx = closest_bucket; else bucket_idx = GNUNET_MIN (closest_bucket, find_bucket (key)); if (bucket_idx == GNUNET_SYSERR) return; bucket = &k_buckets[bucket_idx]; if (bucket->peers_size == 0) return; choice = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, bucket->peers_size); peer = bucket->head; while (choice > 0) { GNUNET_assert (peer != NULL); peer = peer->next; choice--; } choice = bucket->peers_size; do { peer = peer->next; if (choice-- == 0) return; /* no non-masked peer available */ if (peer == NULL) peer = bucket->head; GNUNET_BLOCK_mingle_hash (&peer->id.hashPubKey, bf_mutator, &mhash); hello = GDS_HELLO_get (&peer->id); } while ((hello == NULL) || (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (bf, &mhash))); GDS_NEIGHBOURS_handle_reply (sender, GNUNET_BLOCK_TYPE_DHT_HELLO, GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION), key, 0, NULL, 0, NULL, hello, GNUNET_HELLO_size (hello)); } /** * Core handler for p2p get requests. * * @param cls closure * @param peer sender of the request * @param message message * @param peer peer identity this notification is about * @param atsi performance data * @param atsi_count number of records in 'atsi' * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_dht_p2p_get (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct PeerGetMessage *get; uint32_t xquery_size; size_t reply_bf_size; uint16_t msize; enum GNUNET_BLOCK_Type type; enum GNUNET_DHT_RouteOption options; enum GNUNET_BLOCK_EvaluationResult eval; struct GNUNET_CONTAINER_BloomFilter *reply_bf; struct GNUNET_CONTAINER_BloomFilter *peer_bf; const char *xquery; GNUNET_break (0 != memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity))); /* parse and validate message */ msize = ntohs (message->size); if (msize < sizeof (struct PeerGetMessage)) { GNUNET_break_op (0); return GNUNET_YES; } get = (struct PeerGetMessage *) message; xquery_size = ntohl (get->xquery_size); if (msize < sizeof (struct PeerGetMessage) + xquery_size) { GNUNET_break_op (0); return GNUNET_YES; } GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# P2P GET requests received"), 1, GNUNET_NO); reply_bf_size = msize - (sizeof (struct PeerGetMessage) + xquery_size); type = ntohl (get->type); options = ntohl (get->options); xquery = (const char *) &get[1]; reply_bf = NULL; if (reply_bf_size > 0) reply_bf = GNUNET_CONTAINER_bloomfilter_init (&xquery[xquery_size], reply_bf_size, GNUNET_CONSTANTS_BLOOMFILTER_K); eval = GNUNET_BLOCK_evaluate (GDS_block_context, type, &get->key, &reply_bf, get->bf_mutator, xquery, xquery_size, NULL, 0); if (eval != GNUNET_BLOCK_EVALUATION_REQUEST_VALID) { /* request invalid or block type not supported */ GNUNET_break_op (eval == GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED); if (NULL != reply_bf) GNUNET_CONTAINER_bloomfilter_free (reply_bf); return GNUNET_YES; } peer_bf = GNUNET_CONTAINER_bloomfilter_init (get->bloomfilter, DHT_BLOOM_SIZE, GNUNET_CONSTANTS_BLOOMFILTER_K); GNUNET_break_op (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (peer_bf, &peer->hashPubKey)); /* remember request for routing replies */ GDS_ROUTING_add (peer, type, options, &get->key, xquery, xquery_size, reply_bf, get->bf_mutator); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GET for %s at %s after %u hops\n", GNUNET_h2s (&get->key), GNUNET_i2s (&my_identity), (unsigned int) ntohl (get->hop_count)); /* local lookup (this may update the reply_bf) */ if ((0 != (options & GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) || (am_closest_peer (&get->key, peer_bf))) { if ((0 != (options & GNUNET_DHT_RO_FIND_PEER))) { GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# P2P FIND PEER requests processed"), 1, GNUNET_NO); handle_find_peer (peer, &get->key, reply_bf, get->bf_mutator); } else { eval = GDS_DATACACHE_handle_get (&get->key, type, xquery, xquery_size, &reply_bf, get->bf_mutator); } } else { GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# P2P GET requests ONLY routed"), 1, GNUNET_NO); } /* FIXME Path */ GDS_CLIENTS_process_get (options, type, ntohl(get->hop_count), ntohl(get->desired_replication_level), 0, NULL, &get->key); /* P2P forwarding */ if (eval != GNUNET_BLOCK_EVALUATION_OK_LAST) GDS_NEIGHBOURS_handle_get (type, options, ntohl (get->desired_replication_level), ntohl (get->hop_count), &get->key, xquery, xquery_size, reply_bf, get->bf_mutator, peer_bf); /* clean up */ if (NULL != reply_bf) GNUNET_CONTAINER_bloomfilter_free (reply_bf); GNUNET_CONTAINER_bloomfilter_free (peer_bf); return GNUNET_YES; } /** * Core handler for p2p result messages. * * @param cls closure * @param message message * @param peer peer identity this notification is about * @param atsi performance data * @param atsi_count number of records in 'atsi' * @return GNUNET_YES (do not cut p2p connection) */ static int handle_dht_p2p_result (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { const struct PeerResultMessage *prm; const struct GNUNET_PeerIdentity *put_path; const struct GNUNET_PeerIdentity *get_path; const void *data; uint32_t get_path_length; uint32_t put_path_length; uint16_t msize; size_t data_size; enum GNUNET_BLOCK_Type type; /* parse and validate message */ msize = ntohs (message->size); if (msize < sizeof (struct PeerResultMessage)) { GNUNET_break_op (0); return GNUNET_YES; } prm = (struct PeerResultMessage *) message; put_path_length = ntohl (prm->put_path_length); get_path_length = ntohl (prm->get_path_length); if ((msize < sizeof (struct PeerResultMessage) + (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity)) || (get_path_length > GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) || (put_path_length > GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity))) { GNUNET_break_op (0); return GNUNET_YES; } GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# P2P RESULTS received"), 1, GNUNET_NO); put_path = (const struct GNUNET_PeerIdentity *) &prm[1]; get_path = &put_path[put_path_length]; type = ntohl (prm->type); data = (const void *) &get_path[get_path_length]; data_size = msize - (sizeof (struct PeerResultMessage) + (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity)); /* if we got a HELLO, consider it for our own routing table */ if (type == GNUNET_BLOCK_TYPE_DHT_HELLO) { const struct GNUNET_MessageHeader *h; struct GNUNET_PeerIdentity pid; int bucket; /* Should be a HELLO, validate and consider using it! */ if (data_size < sizeof (struct GNUNET_MessageHeader)) { GNUNET_break_op (0); return GNUNET_YES; } h = data; if (data_size != ntohs (h->size)) { GNUNET_break_op (0); return GNUNET_YES; } if (GNUNET_OK != GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) h, &pid)) { GNUNET_break_op (0); return GNUNET_YES; } if (0 != memcmp (&my_identity, &pid, sizeof (struct GNUNET_PeerIdentity))) { bucket = find_bucket (&pid.hashPubKey); if ((bucket >= 0) && (k_buckets[bucket].peers_size < bucket_size)) { if (NULL != GDS_transport_handle) { GNUNET_TRANSPORT_offer_hello (GDS_transport_handle, h, NULL, NULL); GNUNET_TRANSPORT_try_connect (GDS_transport_handle, &pid); } } } } /* append 'peer' to 'get_path' */ { struct GNUNET_PeerIdentity xget_path[get_path_length + 1]; memcpy (xget_path, get_path, get_path_length * sizeof (struct GNUNET_PeerIdentity)); xget_path[get_path_length] = *peer; get_path_length++; /* forward to local clients */ GDS_CLIENTS_handle_reply (GNUNET_TIME_absolute_ntoh (prm->expiration_time), &prm->key, get_path_length, xget_path, put_path_length, put_path, type, data_size, data); /* forward to other peers */ GDS_ROUTING_process (type, GNUNET_TIME_absolute_ntoh (prm->expiration_time), &prm->key, put_path_length, put_path, get_path_length, xget_path, data, data_size); } GDS_CLIENTS_process_get_resp (type, get_path, get_path_length, put_path, put_path_length, GNUNET_TIME_absolute_ntoh ( prm->expiration_time), &prm->key, data, data_size); return GNUNET_YES; } /** * Initialize neighbours subsystem. * * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GDS_NEIGHBOURS_init () { static struct GNUNET_CORE_MessageHandler core_handlers[] = { {&handle_dht_p2p_get, GNUNET_MESSAGE_TYPE_DHT_P2P_GET, 0}, {&handle_dht_p2p_put, GNUNET_MESSAGE_TYPE_DHT_P2P_PUT, 0}, {&handle_dht_p2p_result, GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT, 0}, {NULL, 0, 0} }; unsigned long long temp_config_num; if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (GDS_cfg, "DHT", "bucket_size", &temp_config_num)) bucket_size = (unsigned int) temp_config_num; atsAPI = GNUNET_ATS_performance_init (GDS_cfg, NULL, NULL); coreAPI = GNUNET_CORE_connect (GDS_cfg, 1, NULL, &core_init, &handle_core_connect, &handle_core_disconnect, NULL, GNUNET_NO, NULL, GNUNET_NO, core_handlers); if (coreAPI == NULL) return GNUNET_SYSERR; all_known_peers = GNUNET_CONTAINER_multihashmap_create (256); return GNUNET_OK; } /** * Shutdown neighbours subsystem. */ void GDS_NEIGHBOURS_done () { if (coreAPI == NULL) return; GNUNET_CORE_disconnect (coreAPI); coreAPI = NULL; GNUNET_ATS_performance_done (atsAPI); atsAPI = NULL; GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (all_known_peers)); GNUNET_CONTAINER_multihashmap_destroy (all_known_peers); all_known_peers = NULL; if (GNUNET_SCHEDULER_NO_TASK != find_peer_task) { GNUNET_SCHEDULER_cancel (find_peer_task); find_peer_task = GNUNET_SCHEDULER_NO_TASK; } } /** * Get the ID of the local node. * * @return identity of the local node */ struct GNUNET_PeerIdentity * GDS_NEIGHBOURS_get_id () { return &my_identity; } /* end of gnunet-service-dht_neighbours.c */ gnunet-0.9.3/src/dht/gnunet-service-dht_routing.h0000644000175000017500000000625211760502551016754 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/gnunet-service-dht_routing.h * @brief GNUnet DHT tracking of requests for routing replies * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_DHT_ROUTING_H #define GNUNET_SERVICE_DHT_ROUTING_H #include "gnunet_util_lib.h" #include "gnunet_block_lib.h" #include "gnunet_dht_service.h" /** * Handle a reply (route to origin). Only forwards the reply back to * other peers waiting for it. Does not do local caching or * forwarding to local clients. Essentially calls * GDS_NEIGHBOURS_handle_reply for all peers that sent us a matching * request recently. * * @param type type of the block * @param expiration_time when does the content expire * @param key key for the content * @param put_path_length number of entries in put_path * @param put_path peers the original PUT traversed (if tracked) * @param get_path_length number of entries in put_path * @param get_path peers this reply has traversed so far (if tracked) * @param data payload of the reply * @param data_size number of bytes in data */ void GDS_ROUTING_process (enum GNUNET_BLOCK_Type type, struct GNUNET_TIME_Absolute expiration_time, const GNUNET_HashCode * key, unsigned int put_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *get_path, const void *data, size_t data_size); /** * Add a new entry to our routing table. * * @param sender peer that originated the request * @param type type of the block * @param options options for processing * @param key key for the content * @param xquery extended query * @param xquery_size number of bytes in xquery * @param reply_bf bloomfilter to filter duplicates * @param reply_bf_mutator mutator for reply_bf */ void GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender, enum GNUNET_BLOCK_Type type, enum GNUNET_DHT_RouteOption options, const GNUNET_HashCode * key, const void *xquery, size_t xquery_size, const struct GNUNET_CONTAINER_BloomFilter *reply_bf, uint32_t reply_bf_mutator); /** * Initialize routing subsystem. */ void GDS_ROUTING_init (void); /** * Shutdown routing subsystem. */ void GDS_ROUTING_done (void); #endif gnunet-0.9.3/src/dht/dht_api.c0000644000175000017500000011617111760504775013111 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/dht_api.c * @brief library to access the DHT service * @author Christian Grothoff * @author Nathan Evans */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_constants.h" #include "gnunet_arm_service.h" #include "gnunet_hello_lib.h" #include "gnunet_protocols.h" #include "gnunet_dht_service.h" #include "dht.h" #define LOG(kind,...) GNUNET_log_from (kind, "dht-api",__VA_ARGS__) /** * Entry in our list of messages to be (re-)transmitted. */ struct PendingMessage { /** * This is a doubly-linked list. */ struct PendingMessage *prev; /** * This is a doubly-linked list. */ struct PendingMessage *next; /** * Message that is pending, allocated at the end * of this struct. */ const struct GNUNET_MessageHeader *msg; /** * Handle to the DHT API context. */ struct GNUNET_DHT_Handle *handle; /** * Continuation to call when the request has been * transmitted (for the first time) to the service; can be NULL. */ GNUNET_SCHEDULER_Task cont; /** * Closure for 'cont'. */ void *cont_cls; /** * Unique ID for this request */ uint64_t unique_id; /** * Free the saved message once sent, set to GNUNET_YES for messages * that do not receive responses; GNUNET_NO if this pending message * is aliased from a 'struct GNUNET_DHT_RouteHandle' and will be freed * from there. */ int free_on_send; /** * GNUNET_YES if this message is in our pending queue right now. */ int in_pending_queue; }; /** * Handle to a PUT request. */ struct GNUNET_DHT_PutHandle { /** * Kept in a DLL. */ struct GNUNET_DHT_PutHandle *next; /** * Kept in a DLL. */ struct GNUNET_DHT_PutHandle *prev; /** * Continuation to call when done. */ GNUNET_DHT_PutContinuation cont; /** * Pending message associated with this PUT operation, * NULL after the message has been transmitted to the service. */ struct PendingMessage *pending; /** * Main handle to this DHT api */ struct GNUNET_DHT_Handle *dht_handle; /** * Closure for 'cont'. */ void *cont_cls; /** * Timeout task for this operation. */ GNUNET_SCHEDULER_TaskIdentifier timeout_task; /** * Unique ID for the PUT operation. */ uint64_t unique_id; }; /** * Handle to a GET request */ struct GNUNET_DHT_GetHandle { /** * Iterator to call on data receipt */ GNUNET_DHT_GetIterator iter; /** * Closure for the iterator callback */ void *iter_cls; /** * Main handle to this DHT api */ struct GNUNET_DHT_Handle *dht_handle; /** * The actual message sent for this request, * used for retransmitting requests on service * failure/reconnect. Freed on route_stop. */ struct PendingMessage *message; /** * Key that this get request is for */ GNUNET_HashCode key; /** * Unique identifier for this request (for key collisions). */ uint64_t unique_id; }; /** * Handle to a monitoring request. */ struct GNUNET_DHT_MonitorHandle { /** * DLL. */ struct GNUNET_DHT_MonitorHandle *next; /** * DLL. */ struct GNUNET_DHT_MonitorHandle *prev; /** * Main handle to this DHT api. */ struct GNUNET_DHT_Handle *dht_handle; /** * Type of block looked for. */ enum GNUNET_BLOCK_Type type; /** * Key being looked for, NULL == all. */ GNUNET_HashCode *key; /** * Callback for each received message of type get. */ GNUNET_DHT_MonitorGetCB get_cb; /** * Callback for each received message of type get response. */ GNUNET_DHT_MonitorGetRespCB get_resp_cb; /** * Callback for each received message of type put. */ GNUNET_DHT_MonitorPutCB put_cb; /** * Closure for cb. */ void *cb_cls; }; /** * Connection to the DHT service. */ struct GNUNET_DHT_Handle { /** * Configuration to use. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Socket (if available). */ struct GNUNET_CLIENT_Connection *client; /** * Currently pending transmission request (or NULL). */ struct GNUNET_CLIENT_TransmitHandle *th; /** * Head of linked list of messages we would like to transmit. */ struct PendingMessage *pending_head; /** * Tail of linked list of messages we would like to transmit. */ struct PendingMessage *pending_tail; /** * Head of linked list of messages we would like to monitor. */ struct GNUNET_DHT_MonitorHandle *monitor_head; /** * Tail of linked list of messages we would like to monitor. */ struct GNUNET_DHT_MonitorHandle *monitor_tail; /** * Head of active PUT requests. */ struct GNUNET_DHT_PutHandle *put_head; /** * Tail of active PUT requests. */ struct GNUNET_DHT_PutHandle *put_tail; /** * Hash map containing the current outstanding unique GET requests * (values are of type 'struct GNUNET_DHT_GetHandle'). */ struct GNUNET_CONTAINER_MultiHashMap *active_requests; /** * Task for trying to reconnect. */ GNUNET_SCHEDULER_TaskIdentifier reconnect_task; /** * How quickly should we retry? Used for exponential back-off on * connect-errors. */ struct GNUNET_TIME_Relative retry_time; /** * Generator for unique ids. */ uint64_t uid_gen; /** * Did we start our receive loop yet? */ int in_receive; }; /** * Handler for messages received from the DHT service * a demultiplexer which handles numerous message types * * @param cls the 'struct GNUNET_DHT_Handle' * @param msg the incoming message */ static void service_message_handler (void *cls, const struct GNUNET_MessageHeader *msg); /** * Try to (re)connect to the DHT service. * * @param handle DHT handle to reconnect * @return GNUNET_YES on success, GNUNET_NO on failure. */ static int try_connect (struct GNUNET_DHT_Handle *handle) { if (NULL != handle->client) return GNUNET_OK; handle->in_receive = GNUNET_NO; handle->client = GNUNET_CLIENT_connect ("dht", handle->cfg); if (NULL == handle->client) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Failed to connect to the DHT service!\n")); return GNUNET_NO; } return GNUNET_YES; } /** * Add the request corresponding to the given route handle * to the pending queue (if it is not already in there). * * @param cls the 'struct GNUNET_DHT_Handle*' * @param key key for the request (not used) * @param value the 'struct GNUNET_DHT_GetHandle*' * @return GNUNET_YES (always) */ static int add_request_to_pending (void *cls, const GNUNET_HashCode * key, void *value) { struct GNUNET_DHT_Handle *handle = cls; struct GNUNET_DHT_GetHandle *rh = value; if (GNUNET_NO == rh->message->in_pending_queue) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Retransmitting request related to %s to DHT %p\n", GNUNET_h2s (key), handle); GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail, rh->message); rh->message->in_pending_queue = GNUNET_YES; } return GNUNET_YES; } /** * Try to send messages from list of messages to send * * @param handle DHT_Handle */ static void process_pending_messages (struct GNUNET_DHT_Handle *handle); /** * Try reconnecting to the dht service. * * @param cls GNUNET_DHT_Handle * @param tc scheduler context */ static void try_reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_DHT_Handle *handle = cls; LOG (GNUNET_ERROR_TYPE_DEBUG, "Reconnecting with DHT %p\n", handle); handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; if (handle->retry_time.rel_value < GNUNET_CONSTANTS_SERVICE_RETRY.rel_value) handle->retry_time = GNUNET_CONSTANTS_SERVICE_RETRY; else handle->retry_time = GNUNET_TIME_relative_multiply (handle->retry_time, 2); if (handle->retry_time.rel_value > GNUNET_CONSTANTS_SERVICE_TIMEOUT.rel_value) handle->retry_time = GNUNET_CONSTANTS_SERVICE_TIMEOUT; handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; if (GNUNET_YES != try_connect (handle)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "dht reconnect failed(!)\n"); return; } GNUNET_CONTAINER_multihashmap_iterate (handle->active_requests, &add_request_to_pending, handle); process_pending_messages (handle); } /** * Try reconnecting to the DHT service. * * @param handle handle to dht to (possibly) disconnect and reconnect */ static void do_disconnect (struct GNUNET_DHT_Handle *handle) { struct GNUNET_DHT_PutHandle *ph; struct GNUNET_DHT_PutHandle *next; if (NULL == handle->client) return; GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == handle->reconnect_task); if (NULL != handle->th) GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th); handle->th = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from DHT service, will try to reconnect in %llu ms\n", (unsigned long long) handle->retry_time.rel_value); GNUNET_CLIENT_disconnect (handle->client); handle->client = NULL; /* signal disconnect to all PUT requests that were transmitted but waiting for the put confirmation */ next = handle->put_head; while (NULL != (ph = next)) { next = ph->next; if (NULL == ph->pending) { if (NULL != ph->cont) ph->cont (ph->cont_cls, GNUNET_SYSERR); GNUNET_DHT_put_cancel (ph); } } handle->reconnect_task = GNUNET_SCHEDULER_add_delayed (handle->retry_time, &try_reconnect, handle); } /** * Transmit the next pending message, called by notify_transmit_ready * * @param cls the DHT handle * @param size number of bytes available in 'buf' for transmission * @param buf where to copy messages for the service * @return number of bytes written to 'buf' */ static size_t transmit_pending (void *cls, size_t size, void *buf); /** * Try to send messages from list of messages to send * * @param handle handle to DHT */ static void process_pending_messages (struct GNUNET_DHT_Handle *handle) { struct PendingMessage *head; if (NULL == handle->client) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "process_pending_messages called, but client is NULL, reconnecting\n"); do_disconnect (handle); return; } if (NULL != handle->th) return; if (NULL == (head = handle->pending_head)) return; handle->th = GNUNET_CLIENT_notify_transmit_ready (handle->client, ntohs (head->msg->size), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &transmit_pending, handle); if (NULL != handle->th) return; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "notify_transmit_ready returned NULL, reconnecting\n"); do_disconnect (handle); } /** * Transmit the next pending message, called by notify_transmit_ready * * @param cls the DHT handle * @param size number of bytes available in 'buf' for transmission * @param buf where to copy messages for the service * @return number of bytes written to 'buf' */ static size_t transmit_pending (void *cls, size_t size, void *buf) { struct GNUNET_DHT_Handle *handle = cls; struct PendingMessage *head; size_t tsize; handle->th = NULL; if (NULL == buf) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission to DHT service failed! Reconnecting!\n"); do_disconnect (handle); return 0; } if (NULL == (head = handle->pending_head)) return 0; tsize = ntohs (head->msg->size); if (size < tsize) { process_pending_messages (handle); return 0; } memcpy (buf, head->msg, tsize); GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail, head); head->in_pending_queue = GNUNET_NO; if (NULL != head->cont) { head->cont (head->cont_cls, NULL); head->cont = NULL; head->cont_cls = NULL; } if (GNUNET_YES == head->free_on_send) GNUNET_free (head); process_pending_messages (handle); LOG (GNUNET_ERROR_TYPE_DEBUG, "Forwarded request of %u bytes to DHT service\n", (unsigned int) tsize); if (GNUNET_NO == handle->in_receive) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting to process replies from DHT\n"); handle->in_receive = GNUNET_YES; GNUNET_CLIENT_receive (handle->client, &service_message_handler, handle, GNUNET_TIME_UNIT_FOREVER_REL); } return tsize; } /** * Process a given reply that might match the given * request. * * @param cls the 'struct GNUNET_DHT_ClientResultMessage' * @param key query of the request * @param value the 'struct GNUNET_DHT_RouteHandle' of a request matching the same key * @return GNUNET_YES to continue to iterate over all results, * GNUNET_NO if the reply is malformed */ static int process_reply (void *cls, const GNUNET_HashCode * key, void *value) { const struct GNUNET_DHT_ClientResultMessage *dht_msg = cls; struct GNUNET_DHT_GetHandle *get_handle = value; const struct GNUNET_PeerIdentity *put_path; const struct GNUNET_PeerIdentity *get_path; uint32_t put_path_length; uint32_t get_path_length; size_t data_length; size_t msize; size_t meta_length; const void *data; if (dht_msg->unique_id != get_handle->unique_id) { /* UID mismatch */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Ignoring reply for %s: UID mismatch: %llu/%llu\n", GNUNET_h2s (key), dht_msg->unique_id, get_handle->unique_id); return GNUNET_YES; } msize = ntohs (dht_msg->header.size); put_path_length = ntohl (dht_msg->put_path_length); get_path_length = ntohl (dht_msg->get_path_length); meta_length = sizeof (struct GNUNET_DHT_ClientResultMessage) + sizeof (struct GNUNET_PeerIdentity) * (get_path_length + put_path_length); if ((msize < meta_length) || (get_path_length > GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) || (put_path_length > GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity))) { GNUNET_break (0); return GNUNET_NO; } data_length = msize - meta_length; LOG (GNUNET_ERROR_TYPE_DEBUG, "Giving %u byte reply for %s to application\n", (unsigned int) data_length, GNUNET_h2s (key)); put_path = (const struct GNUNET_PeerIdentity *) &dht_msg[1]; get_path = &put_path[put_path_length]; data = &get_path[get_path_length]; get_handle->iter (get_handle->iter_cls, GNUNET_TIME_absolute_ntoh (dht_msg->expiration), key, get_path, get_path_length, put_path, put_path_length, ntohl (dht_msg->type), data_length, data); return GNUNET_YES; } /** * Process a get monitor message from the service. * * @param handle The DHT handle. * @param msg Monitor get message from the service. * * @return GNUNET_OK if everything went fine, * GNUNET_SYSERR if the message is malformed. */ static int process_monitor_get_message (struct GNUNET_DHT_Handle *handle, const struct GNUNET_DHT_MonitorGetMessage *msg) { struct GNUNET_DHT_MonitorHandle *h; for (h = handle->monitor_head; NULL != h; h = h->next) { int type_ok; int key_ok; type_ok = (GNUNET_BLOCK_TYPE_ANY == h->type) || (h->type == ntohl(msg->type)); key_ok = (NULL == h->key) || (0 == memcmp (h->key, &msg->key, sizeof (GNUNET_HashCode))); if (type_ok && key_ok && (NULL != h->get_cb)) h->get_cb (h->cb_cls, ntohl (msg->options), (enum GNUNET_BLOCK_Type) ntohl(msg->type), ntohl (msg->hop_count), ntohl (msg->desired_replication_level), ntohl (msg->get_path_length), (struct GNUNET_PeerIdentity *) &msg[1], &msg->key); } return GNUNET_OK; } /** * Process a get response monitor message from the service. * * @param handle The DHT handle. * @param msg monitor get response message from the service * @return GNUNET_OK if everything went fine, * GNUNET_SYSERR if the message is malformed. */ static int process_monitor_get_resp_message (struct GNUNET_DHT_Handle *handle, const struct GNUNET_DHT_MonitorGetRespMessage *msg) { struct GNUNET_DHT_MonitorHandle *h; struct GNUNET_PeerIdentity *path; uint32_t getl; uint32_t putl; size_t msize; msize = ntohs (msg->header.size); path = (struct GNUNET_PeerIdentity *) &msg[1]; getl = ntohl (msg->get_path_length); putl = ntohl (msg->put_path_length); if ( (getl + putl < getl) || ( ((msize - sizeof (struct GNUNET_DHT_MonitorGetRespMessage)) / sizeof (struct GNUNET_PeerIdentity)) < getl + putl) ) { GNUNET_break (0); return GNUNET_SYSERR; } for (h = handle->monitor_head; NULL != h; h = h->next) { int type_ok; int key_ok; type_ok = (GNUNET_BLOCK_TYPE_ANY == h->type) || (h->type == ntohl(msg->type)); key_ok = (NULL == h->key) || (0 == memcmp (h->key, &msg->key, sizeof (GNUNET_HashCode))); if (type_ok && key_ok && (NULL != h->get_resp_cb)) h->get_resp_cb (h->cb_cls, (enum GNUNET_BLOCK_Type) ntohl(msg->type), path, getl, &path[getl], putl, GNUNET_TIME_absolute_ntoh(msg->expiration_time), &msg->key, (void *) &path[getl + putl], msize - sizeof (struct GNUNET_DHT_MonitorGetRespMessage) - sizeof (struct GNUNET_PeerIdentity) * (putl + getl)); } return GNUNET_OK; } /** * Process a put monitor message from the service. * * @param handle The DHT handle. * @param msg Monitor put message from the service. * * @return GNUNET_OK if everything went fine, * GNUNET_SYSERR if the message is malformed. */ static int process_monitor_put_message (struct GNUNET_DHT_Handle *handle, const struct GNUNET_DHT_MonitorPutMessage *msg) { struct GNUNET_DHT_MonitorHandle *h; size_t msize; struct GNUNET_PeerIdentity *path; uint32_t putl; msize = ntohs (msg->header.size); path = (struct GNUNET_PeerIdentity *) &msg[1]; putl = ntohl (msg->put_path_length); if (((msize - sizeof (struct GNUNET_DHT_MonitorGetRespMessage)) / sizeof (struct GNUNET_PeerIdentity)) < putl) { GNUNET_break (0); return GNUNET_SYSERR; } for (h = handle->monitor_head; NULL != h; h = h->next) { int type_ok; int key_ok; type_ok = (GNUNET_BLOCK_TYPE_ANY == h->type) || (h->type == ntohl(msg->type)); key_ok = (NULL == h->key) || (0 == memcmp (h->key, &msg->key, sizeof (GNUNET_HashCode))); if (type_ok && key_ok && (NULL != h->put_cb)) h->put_cb (h->cb_cls, ntohl (msg->options), (enum GNUNET_BLOCK_Type) ntohl(msg->type), ntohl (msg->hop_count), ntohl (msg->desired_replication_level), putl, path, GNUNET_TIME_absolute_ntoh(msg->expiration_time), &msg->key, (void *) &path[putl], msize - sizeof (struct GNUNET_DHT_MonitorPutMessage) - sizeof (struct GNUNET_PeerIdentity) * putl); } return GNUNET_OK; } /** * Process a put confirmation message from the service. * * @param handle The DHT handle. * @param msg confirmation message from the service. * @return GNUNET_OK if everything went fine, * GNUNET_SYSERR if the message is malformed. */ static int process_put_confirmation_message (struct GNUNET_DHT_Handle *handle, const struct GNUNET_DHT_ClientPutConfirmationMessage *msg) { struct GNUNET_DHT_PutHandle *ph; GNUNET_DHT_PutContinuation cont; void *cont_cls; for (ph = handle->put_head; NULL != ph; ph = ph->next) if (ph->unique_id == msg->unique_id) break; if (NULL == ph) return GNUNET_OK; cont = ph->cont; cont_cls = ph->cont_cls; GNUNET_DHT_put_cancel (ph); if (NULL != cont) cont (cont_cls, GNUNET_OK); return GNUNET_OK; } /** * Handler for messages received from the DHT service * a demultiplexer which handles numerous message types * * @param cls the 'struct GNUNET_DHT_Handle' * @param msg the incoming message */ static void service_message_handler (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_DHT_Handle *handle = cls; const struct GNUNET_DHT_ClientResultMessage *dht_msg; uint16_t msize; int ret; if (NULL == msg) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Error receiving data from DHT service, reconnecting\n"); do_disconnect (handle); return; } ret = GNUNET_SYSERR; msize = ntohs (msg->size); switch (ntohs (msg->type)) { case GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET: if (msize < sizeof (struct GNUNET_DHT_MonitorGetMessage)) { GNUNET_break (0); break; } ret = process_monitor_get_message(handle, (const struct GNUNET_DHT_MonitorGetMessage *) msg); break; case GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET_RESP: if (msize < sizeof (struct GNUNET_DHT_MonitorGetRespMessage)) { GNUNET_break (0); break; } ret = process_monitor_get_resp_message(handle, (const struct GNUNET_DHT_MonitorGetRespMessage *) msg); break; case GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT: if (msize < sizeof (struct GNUNET_DHT_MonitorPutMessage)) { GNUNET_break (0); break; } ret = process_monitor_put_message(handle, (const struct GNUNET_DHT_MonitorPutMessage *) msg); break; case GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT_RESP: /* Not implemented yet */ GNUNET_break(0); break; case GNUNET_MESSAGE_TYPE_DHT_CLIENT_RESULT: if (ntohs (msg->size) < sizeof (struct GNUNET_DHT_ClientResultMessage)) { GNUNET_break (0); break; } ret = GNUNET_OK; dht_msg = (const struct GNUNET_DHT_ClientResultMessage *) msg; LOG (GNUNET_ERROR_TYPE_DEBUG, "Received reply for `%s' from DHT service %p\n", GNUNET_h2s (&dht_msg->key), handle); GNUNET_CONTAINER_multihashmap_get_multiple (handle->active_requests, &dht_msg->key, &process_reply, (void *) dht_msg); break; case GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT_OK: if (ntohs (msg->size) != sizeof (struct GNUNET_DHT_ClientPutConfirmationMessage)) { GNUNET_break (0); break; } ret = process_put_confirmation_message (handle, (const struct GNUNET_DHT_ClientPutConfirmationMessage*) msg); break; default: GNUNET_break(0); break; } if (GNUNET_OK != ret) { GNUNET_break (0); do_disconnect (handle); return; } GNUNET_CLIENT_receive (handle->client, &service_message_handler, handle, GNUNET_TIME_UNIT_FOREVER_REL); } /** * Initialize the connection with the DHT service. * * @param cfg configuration to use * @param ht_len size of the internal hash table to use for * processing multiple GET/FIND requests in parallel * * @return handle to the DHT service, or NULL on error */ struct GNUNET_DHT_Handle * GNUNET_DHT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned int ht_len) { struct GNUNET_DHT_Handle *handle; handle = GNUNET_malloc (sizeof (struct GNUNET_DHT_Handle)); handle->cfg = cfg; handle->uid_gen = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); handle->active_requests = GNUNET_CONTAINER_multihashmap_create (ht_len); if (GNUNET_NO == try_connect (handle)) { GNUNET_DHT_disconnect (handle); return NULL; } return handle; } /** * Shutdown connection with the DHT service. * * @param handle handle of the DHT connection to stop */ void GNUNET_DHT_disconnect (struct GNUNET_DHT_Handle *handle) { struct PendingMessage *pm; struct GNUNET_DHT_PutHandle *ph; GNUNET_assert (NULL != handle); GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (handle->active_requests)); if (NULL != handle->th) { GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th); handle->th = NULL; } while (NULL != (pm = handle->pending_head)) { GNUNET_assert (GNUNET_YES == pm->in_pending_queue); GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail, pm); pm->in_pending_queue = GNUNET_NO; GNUNET_assert (GNUNET_YES == pm->free_on_send); if (NULL != pm->cont) pm->cont (pm->cont_cls, NULL); GNUNET_free (pm); } while (NULL != (ph = handle->put_head)) { GNUNET_break (NULL == ph->pending); if (NULL != ph->cont) ph->cont (ph->cont_cls, GNUNET_SYSERR); GNUNET_DHT_put_cancel (ph); } if (NULL != handle->client) { GNUNET_CLIENT_disconnect (handle->client); handle->client = NULL; } if (GNUNET_SCHEDULER_NO_TASK != handle->reconnect_task) GNUNET_SCHEDULER_cancel (handle->reconnect_task); GNUNET_CONTAINER_multihashmap_destroy (handle->active_requests); GNUNET_free (handle); } /** * Timeout for the transmission of a fire&forget-request. Clean it up. * * @param cls the 'struct PendingMessage' * @param tc scheduler context */ static void timeout_put_request (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_DHT_PutHandle *ph = cls; struct GNUNET_DHT_Handle *handle = ph->dht_handle; ph->timeout_task = GNUNET_SCHEDULER_NO_TASK; if (NULL != ph->pending) { GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail, ph->pending); ph->pending->in_pending_queue = GNUNET_NO; GNUNET_free (ph->pending); } if (NULL != ph->cont) ph->cont (ph->cont_cls, GNUNET_NO); GNUNET_CONTAINER_DLL_remove (handle->put_head, handle->put_tail, ph); GNUNET_free (ph); } /** * Function called whenever the PUT message leaves the queue. Sets * the message pointer in the put handle to NULL. * * @param cls the 'struct GNUNET_DHT_PutHandle' * @param tc unused */ static void mark_put_message_gone (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_DHT_PutHandle *ph = cls; ph->pending = NULL; } /** * Perform a PUT operation storing data in the DHT. FIXME: we should * change the protocol to get a confirmation for the PUT from the DHT * and call 'cont' only after getting the confirmation; otherwise, the * client has no good way of telling if the 'PUT' message actually got * to the DHT service! * * @param handle handle to DHT service * @param key the key to store under * @param desired_replication_level estimate of how many * nearest peers this request should reach * @param options routing options for this message * @param type type of the value * @param size number of bytes in data; must be less than 64k * @param data the data to store * @param exp desired expiration time for the value * @param timeout how long to wait for transmission of this request * @param cont continuation to call when done (transmitting request to service) * You must not call GNUNET_DHT_DISCONNECT in this continuation * @param cont_cls closure for cont */ struct GNUNET_DHT_PutHandle * GNUNET_DHT_put (struct GNUNET_DHT_Handle *handle, const GNUNET_HashCode * key, uint32_t desired_replication_level, enum GNUNET_DHT_RouteOption options, enum GNUNET_BLOCK_Type type, size_t size, const char *data, struct GNUNET_TIME_Absolute exp, struct GNUNET_TIME_Relative timeout, GNUNET_DHT_PutContinuation cont, void *cont_cls) { struct GNUNET_DHT_ClientPutMessage *put_msg; size_t msize; struct PendingMessage *pending; struct GNUNET_DHT_PutHandle *ph; msize = sizeof (struct GNUNET_DHT_ClientPutMessage) + size; if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)) { GNUNET_break (0); return NULL; } ph = GNUNET_malloc (sizeof (struct GNUNET_DHT_PutHandle)); ph->dht_handle = handle; ph->timeout_task = GNUNET_SCHEDULER_add_delayed (timeout, &timeout_put_request, ph); ph->cont = cont; ph->cont_cls = cont_cls; ph->unique_id = ++handle->uid_gen; pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize); ph->pending = pending; put_msg = (struct GNUNET_DHT_ClientPutMessage *) &pending[1]; pending->msg = &put_msg->header; pending->handle = handle; pending->cont = &mark_put_message_gone; pending->cont_cls = ph; pending->free_on_send = GNUNET_YES; put_msg->header.size = htons (msize); put_msg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT); put_msg->type = htonl (type); put_msg->options = htonl ((uint32_t) options); put_msg->desired_replication_level = htonl (desired_replication_level); put_msg->unique_id = ph->unique_id; put_msg->expiration = GNUNET_TIME_absolute_hton (exp); put_msg->key = *key; memcpy (&put_msg[1], data, size); GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail, pending); pending->in_pending_queue = GNUNET_YES; GNUNET_CONTAINER_DLL_insert_tail (handle->put_head, handle->put_tail, ph); process_pending_messages (handle); return ph; } /** * Cancels a DHT PUT operation. Note that the PUT request may still * go out over the network (we can't stop that); However, if the PUT * has not yet been sent to the service, cancelling the PUT will stop * this from happening (but there is no way for the user of this API * to tell if that is the case). The only use for this API is to * prevent a later call to 'cont' from "GNUNET_DHT_put" (i.e. because * the system is shutting down). * * @param ph put operation to cancel ('cont' will no longer be called) */ void GNUNET_DHT_put_cancel (struct GNUNET_DHT_PutHandle *ph) { struct GNUNET_DHT_Handle *handle = ph->dht_handle; if (NULL != ph->pending) { GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail, ph->pending); GNUNET_free (ph->pending); ph->pending = NULL; } if (ph->timeout_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (ph->timeout_task); ph->timeout_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_CONTAINER_DLL_remove (handle->put_head, handle->put_tail, ph); GNUNET_free (ph); } /** * Perform an asynchronous GET operation on the DHT identified. See * also "GNUNET_BLOCK_evaluate". * * @param handle handle to the DHT service * @param type expected type of the response object * @param key the key to look up * @param desired_replication_level estimate of how many nearest peers this request should reach * @param options routing options for this message * @param xquery extended query data (can be NULL, depending on type) * @param xquery_size number of bytes in xquery * @param iter function to call on each result * @param iter_cls closure for iter * @return handle to stop the async get */ struct GNUNET_DHT_GetHandle * GNUNET_DHT_get_start (struct GNUNET_DHT_Handle *handle, enum GNUNET_BLOCK_Type type, const GNUNET_HashCode * key, uint32_t desired_replication_level, enum GNUNET_DHT_RouteOption options, const void *xquery, size_t xquery_size, GNUNET_DHT_GetIterator iter, void *iter_cls) { struct GNUNET_DHT_ClientGetMessage *get_msg; struct GNUNET_DHT_GetHandle *get_handle; size_t msize; struct PendingMessage *pending; msize = sizeof (struct GNUNET_DHT_ClientGetMessage) + xquery_size; if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || (xquery_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)) { GNUNET_break (0); return NULL; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending query for %s to DHT %p\n", GNUNET_h2s (key), handle); pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize); get_msg = (struct GNUNET_DHT_ClientGetMessage *) &pending[1]; pending->msg = &get_msg->header; pending->handle = handle; pending->free_on_send = GNUNET_NO; get_msg->header.size = htons (msize); get_msg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET); get_msg->options = htonl ((uint32_t) options); get_msg->desired_replication_level = htonl (desired_replication_level); get_msg->type = htonl (type); get_msg->key = *key; get_msg->unique_id = ++handle->uid_gen; memcpy (&get_msg[1], xquery, xquery_size); GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail, pending); pending->in_pending_queue = GNUNET_YES; get_handle = GNUNET_malloc (sizeof (struct GNUNET_DHT_GetHandle)); get_handle->iter = iter; get_handle->iter_cls = iter_cls; get_handle->message = pending; get_handle->unique_id = get_msg->unique_id; GNUNET_CONTAINER_multihashmap_put (handle->active_requests, key, get_handle, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); process_pending_messages (handle); return get_handle; } /** * Stop async DHT-get. * * @param get_handle handle to the GET operation to stop */ void GNUNET_DHT_get_stop (struct GNUNET_DHT_GetHandle *get_handle) { struct GNUNET_DHT_Handle *handle; const struct GNUNET_DHT_ClientGetMessage *get_msg; struct GNUNET_DHT_ClientGetStopMessage *stop_msg; struct PendingMessage *pending; handle = get_handle->message->handle; get_msg = (const struct GNUNET_DHT_ClientGetMessage *) get_handle->message->msg; LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending STOP for %s to DHT via %p\n", GNUNET_h2s (&get_msg->key), handle); /* generate STOP */ pending = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (struct GNUNET_DHT_ClientGetStopMessage)); stop_msg = (struct GNUNET_DHT_ClientGetStopMessage *) &pending[1]; pending->msg = &stop_msg->header; pending->handle = handle; pending->free_on_send = GNUNET_YES; stop_msg->header.size = htons (sizeof (struct GNUNET_DHT_ClientGetStopMessage)); stop_msg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_STOP); stop_msg->reserved = htonl (0); stop_msg->unique_id = get_msg->unique_id; stop_msg->key = get_msg->key; GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail, pending); pending->in_pending_queue = GNUNET_YES; /* remove 'GET' from active status */ GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (handle->active_requests, &get_msg->key, get_handle)); if (GNUNET_YES == get_handle->message->in_pending_queue) { GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail, get_handle->message); get_handle->message->in_pending_queue = GNUNET_NO; } GNUNET_free (get_handle->message); GNUNET_free (get_handle); process_pending_messages (handle); } /** * Start monitoring the local DHT service. * * @param handle Handle to the DHT service. * @param type Type of blocks that are of interest. * @param key Key of data of interest, NULL for all. * @param get_cb Callback to process monitored get messages. * @param get_resp_cb Callback to process monitored get response messages. * @param put_cb Callback to process monitored put messages. * @param cb_cls Closure for cb. * * @return Handle to stop monitoring. */ struct GNUNET_DHT_MonitorHandle * GNUNET_DHT_monitor_start (struct GNUNET_DHT_Handle *handle, enum GNUNET_BLOCK_Type type, const GNUNET_HashCode *key, GNUNET_DHT_MonitorGetCB get_cb, GNUNET_DHT_MonitorGetRespCB get_resp_cb, GNUNET_DHT_MonitorPutCB put_cb, void *cb_cls) { struct GNUNET_DHT_MonitorHandle *h; struct GNUNET_DHT_MonitorStartStopMessage *m; struct PendingMessage *pending; h = GNUNET_malloc (sizeof (struct GNUNET_DHT_MonitorHandle)); GNUNET_CONTAINER_DLL_insert(handle->monitor_head, handle->monitor_tail, h); h->get_cb = get_cb; h->get_resp_cb = get_resp_cb; h->put_cb = put_cb; h->cb_cls = cb_cls; h->type = type; h->dht_handle = handle; if (NULL != key) { h->key = GNUNET_malloc (sizeof(GNUNET_HashCode)); memcpy (h->key, key, sizeof(GNUNET_HashCode)); } pending = GNUNET_malloc (sizeof (struct GNUNET_DHT_MonitorStartStopMessage) + sizeof (struct PendingMessage)); m = (struct GNUNET_DHT_MonitorStartStopMessage *) &pending[1]; pending->msg = &m->header; pending->handle = handle; pending->free_on_send = GNUNET_YES; m->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_MONITOR_START); m->header.size = htons (sizeof (struct GNUNET_DHT_MonitorStartStopMessage)); m->type = htonl(type); m->get = htons(NULL != get_cb); m->get_resp = htons(NULL != get_resp_cb); m->put = htons(NULL != put_cb); if (NULL != key) { m->filter_key = htons(1); memcpy (&m->key, key, sizeof(GNUNET_HashCode)); } GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail, pending); pending->in_pending_queue = GNUNET_YES; process_pending_messages (handle); return h; } /** * Stop monitoring. * * @param handle The handle to the monitor request returned by monitor_start. * * On return get_handle will no longer be valid, caller must not use again!!! */ void GNUNET_DHT_monitor_stop (struct GNUNET_DHT_MonitorHandle *handle) { struct GNUNET_DHT_MonitorStartStopMessage *m; struct PendingMessage *pending; GNUNET_CONTAINER_DLL_remove (handle->dht_handle->monitor_head, handle->dht_handle->monitor_tail, handle); pending = GNUNET_malloc (sizeof (struct GNUNET_DHT_MonitorStartStopMessage) + sizeof (struct PendingMessage)); m = (struct GNUNET_DHT_MonitorStartStopMessage *) &pending[1]; pending->msg = &m->header; pending->handle = handle->dht_handle; pending->free_on_send = GNUNET_YES; m->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_MONITOR_STOP); m->header.size = htons (sizeof (struct GNUNET_DHT_MonitorStartStopMessage)); m->type = htonl(handle->type); m->get = htons(NULL != handle->get_cb); m->get_resp = htons(NULL != handle->get_resp_cb); m->put = htons(NULL != handle->put_cb); if (NULL != handle->key) { m->filter_key = htons(1); memcpy (&m->key, handle->key, sizeof(GNUNET_HashCode)); } GNUNET_CONTAINER_DLL_insert (handle->dht_handle->pending_head, handle->dht_handle->pending_tail, pending); pending->in_pending_queue = GNUNET_YES; process_pending_messages (handle->dht_handle); GNUNET_free_non_null (handle->key); GNUNET_free (handle); } /* end of dht_api.c */ gnunet-0.9.3/src/dht/test_dht_topo.c0000644000175000017500000004357611761765304014366 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/test_dht_topo.c * * @brief Test for the dht service: store and retrieve in various topologies. * Each peer stores it own ID in the DHT and then a different peer tries to * retrieve that key from it. The GET starts after a first round of PUTS has * been made. Periodically, each peer stores its ID into the DHT. If after * a timeout no result has been returned, the test fails. */ #include "platform.h" #include "gnunet_testing_lib.h" #include "gnunet_dht_service.h" #define REMOVE_DIR GNUNET_YES /** * DIFFERENT TESTS TO RUN */ #define LINE 0 #define TORUS 1 /** * How long until we give up on connecting the peers? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500) #define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) #define PUT_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) /** * Result of the test. */ static int ok; /** * Total number of peers in the test. */ static unsigned long long num_peers; /** * Global configuration file */ static struct GNUNET_CONFIGURATION_Handle *testing_cfg; /** * Total number of currently running peers. */ static unsigned long long peers_running; /** * Total number of connections in the whole network. */ static unsigned int total_connections; /** * The currently running peer group. */ static struct GNUNET_TESTING_PeerGroup *pg; /** * File to report results to. */ static struct GNUNET_DISK_FileHandle *output_file; /** * File to log connection info, statistics to. */ static struct GNUNET_DISK_FileHandle *data_file; /** * Task called to disconnect peers. */ static GNUNET_SCHEDULER_TaskIdentifier disconnect_task; /** * Task To perform tests */ static GNUNET_SCHEDULER_TaskIdentifier test_task; /** * Task to do DHT_puts */ static GNUNET_SCHEDULER_TaskIdentifier put_task; /** * Task called to shutdown test. */ static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle; static char *topology_file; static struct GNUNET_DHT_Handle **hs; static struct GNUNET_DHT_GetHandle *get_h; static struct GNUNET_DHT_GetHandle *get_h_2; static struct GNUNET_DHT_GetHandle *get_h_far; static int found_1; static int found_2; static int found_far; /** * Which topology are we to run */ static int test_topology; /** * Check whether peers successfully shut down. */ static void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Shutdown of peers failed!\n"); ok++; } else { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "All peers successfully shut down!\n"); } GNUNET_CONFIGURATION_destroy (testing_cfg); } static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Ending test.\n"); if (disconnect_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (disconnect_task); disconnect_task = GNUNET_SCHEDULER_NO_TASK; } if (data_file != NULL) GNUNET_DISK_file_close (data_file); GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); } static void disconnect_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { unsigned int i; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "disconnecting peers\n"); disconnect_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_SCHEDULER_cancel (put_task); if (NULL != get_h) GNUNET_DHT_get_stop (get_h); if (NULL != get_h_2) GNUNET_DHT_get_stop (get_h_2); if (NULL != get_h_far) GNUNET_DHT_get_stop (get_h_far); for (i = 0; i < num_peers; i++) { GNUNET_DHT_disconnect (hs[i]); } GNUNET_SCHEDULER_cancel (shutdown_handle); shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); } static void dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int put_path_length, enum GNUNET_BLOCK_Type type, size_t size, const void *data) { int i; if (sizeof (GNUNET_HashCode) == size) { const GNUNET_HashCode *h = data; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Contents: %s\n", GNUNET_h2s_full (h)); } else { GNUNET_break(0); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "PATH: (get %u, put %u)\n", get_path_length, put_path_length); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " LOCAL\n"); for (i = get_path_length - 1; i >= 0; i--) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %s\n", GNUNET_i2s (&get_path[i])); } for (i = put_path_length - 1; i >= 0; i--) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %s\n", GNUNET_i2s (&put_path[i])); } switch ((long)cls) { case 1: found_1++; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "FOUND 1!\n"); break; case 2: found_2++; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "FOUND 2!\n"); break; case 3: found_far++; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "FOUND FAR!\n"); break; default: GNUNET_break(0); } if ( (TORUS == test_topology) && ( (found_1 == 0) || (found_2 == 0) || (found_far == 0)) ) return; ok = 0; GNUNET_SCHEDULER_cancel (disconnect_task); disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL); } static void do_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TESTING_Daemon *d; struct GNUNET_TESTING_Daemon *d2; struct GNUNET_TESTING_Daemon *d_far; struct GNUNET_TESTING_Daemon *o; struct GNUNET_TESTING_Daemon *aux; const char *id_aux; const char *id_origin = "FC74"; const char *id_near = "9P6V"; const char *id_near2 = "2GDS"; const char *id_far = "KPST"; unsigned int i; d = d2 = d_far = o = NULL; found_1 = found_2 = found_far = 0; if (LINE == test_topology) { o = GNUNET_TESTING_daemon_get (pg, 0); d = GNUNET_TESTING_daemon_get (pg, 4); } else if (TORUS == test_topology) { for (i = 0; i < num_peers; i++) { aux = GNUNET_TESTING_daemon_get (pg, i); id_aux = GNUNET_i2s (&aux->id); if (strcmp (id_aux, id_origin) == 0) o = aux; if (strcmp (id_aux, id_far) == 0) d_far = aux; if (strcmp (id_aux, id_near) == 0) d = aux; if (strcmp (id_aux, id_near2) == 0) d2 = aux; } if ((NULL == o) || (NULL == d) || (NULL == d2) || (NULL == d_far)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers not found (hostkey file changed?)\n"); GNUNET_SCHEDULER_cancel (disconnect_task); disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL); return; } } else { GNUNET_assert (0); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test_task\nfrom %s\n", GNUNET_h2s_full (&o->id.hashPubKey)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " looking for %s\n", GNUNET_h2s_full (&d->id.hashPubKey)); get_h = GNUNET_DHT_get_start (hs[0], GNUNET_BLOCK_TYPE_TEST, /* type */ &d->id.hashPubKey, /*key to search */ 4U, /* replication level */ GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, NULL, /* xquery */ 0, /* xquery bits */ &dht_get_id_handler, (void *)1); if (TORUS == test_topology) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " looking for %s\n", GNUNET_h2s_full (&d2->id.hashPubKey)); get_h_2 = GNUNET_DHT_get_start (hs[0], GNUNET_BLOCK_TYPE_TEST, /* type */ &d2->id.hashPubKey, /*key to search */ 4U, /* replication level */ GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, NULL, /* xquery */ 0, /* xquery bits */ &dht_get_id_handler, (void *)2); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " looking for %s\n", GNUNET_h2s_full (&d_far->id.hashPubKey)); get_h_far = GNUNET_DHT_get_start (hs[0], GNUNET_BLOCK_TYPE_TEST, /* type */ &d_far->id.hashPubKey, /*key to search */ 4U, /* replication level */ GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, NULL, /* xquery */ 0, /* xquery bits */ &dht_get_id_handler, (void *)3); } GNUNET_SCHEDULER_cancel (disconnect_task); disconnect_task = GNUNET_SCHEDULER_add_delayed (GET_TIMEOUT, &disconnect_peers, NULL); } /** * Task to put the id of each peer into teh DHT. * * @param cls Closure (unused) * @param tc Task context * */ static void put_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TESTING_Daemon *d; unsigned int i; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "putting id's in DHT\n"); for (i = 0; i < num_peers; i++) { d = GNUNET_TESTING_daemon_get (pg, i); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " putting into DHT: %s\n", GNUNET_h2s_full (&d->id.hashPubKey)); GNUNET_DHT_put (hs[i], &d->id.hashPubKey, 10U, GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, GNUNET_BLOCK_TYPE_TEST, sizeof (struct GNUNET_PeerIdentity), (const char *) &d->id, GNUNET_TIME_UNIT_FOREVER_ABS, GNUNET_TIME_UNIT_FOREVER_REL, NULL, NULL); } put_task = GNUNET_SCHEDULER_add_delayed (PUT_FREQUENCY, &put_id, NULL); if (GNUNET_SCHEDULER_NO_TASK == test_task) test_task = GNUNET_SCHEDULER_add_now (&do_test, NULL); } /** * peergroup_ready: start test when all peers are connected * * @param cls closure * @param emsg error message * */ static void peergroup_ready (void *cls, const char *emsg) { struct GNUNET_TESTING_Daemon *d; char *buf; int buf_len; unsigned int i; if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peergroup callback called with error, aborting test!\n"); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error from testing: `%s'\n", emsg); ok++; GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer Group started successfully with %u connections\n", total_connections); if (data_file != NULL) { buf = NULL; buf_len = GNUNET_asprintf (&buf, "CONNECTIONS_0: %u\n", total_connections); if (buf_len > 0) GNUNET_DISK_file_write (data_file, buf, buf_len); GNUNET_free (buf); } peers_running = GNUNET_TESTING_daemons_running (pg); GNUNET_assert (peers_running == num_peers); hs = GNUNET_malloc (num_peers * sizeof (struct GNUNET_DHT_Handle *)); for (i = 0; i < num_peers; i++) { d = GNUNET_TESTING_daemon_get (pg, i); hs[i] = GNUNET_DHT_connect (d->cfg, 32); } test_task = GNUNET_SCHEDULER_NO_TASK; put_task = GNUNET_SCHEDULER_add_now (&put_id, NULL); disconnect_task = GNUNET_SCHEDULER_add_delayed (GET_TIMEOUT, &disconnect_peers, NULL); } /** * Function that will be called whenever two daemons are connected by * the testing library. * * @param cls closure * @param first peer id for first daemon * @param second peer id for the second daemon * @param distance distance between the connected peers * @param first_cfg config for the first daemon * @param second_cfg config for the second daemon * @param first_daemon handle for the first daemon * @param second_daemon handle for the second daemon * @param emsg error message (NULL on success) */ static void connect_cb (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, uint32_t distance, const struct GNUNET_CONFIGURATION_Handle *first_cfg, const struct GNUNET_CONFIGURATION_Handle *second_cfg, struct GNUNET_TESTING_Daemon *first_daemon, struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) { if (emsg == NULL) { total_connections++; GNUNET_PEER_intern (first); GNUNET_PEER_intern (second); } else { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Problem with new connection (%s)\n", emsg); } } /** * run: load configuration options and schedule test to run (start peergroup) * @param cls closure * @param args argv * @param cfgfile configuration file name (can be NULL) * @param cfg configuration handle */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { char *temp_str; struct GNUNET_TESTING_Host *hosts; char *data_filename; ok = 1; testing_cfg = GNUNET_CONFIGURATION_dup (cfg); GNUNET_log_setup ("test_dht_topo", "WARNING", NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", "use_progressbars", "YES"); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing", "num_peers", &num_peers)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Option TESTING:NUM_PEERS is required!\n"); return; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (testing_cfg, "testing", "topology_output_file", &topology_file)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Option test_dht_topo:topology_output_file is required!\n"); return; } if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (testing_cfg, "test_dht_topo", "data_output_file", &data_filename)) { data_file = GNUNET_DISK_file_open (data_filename, GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_CREATE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (data_file == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n", data_filename); GNUNET_free (data_filename); } } if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "test_dht_topo", "output_file", &temp_str)) { output_file = GNUNET_DISK_file_open (temp_str, GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_CREATE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (output_file == NULL) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n", temp_str); } GNUNET_free_non_null (temp_str); hosts = GNUNET_TESTING_hosts_load (testing_cfg); pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT, &connect_cb, &peergroup_ready, NULL, hosts); GNUNET_assert (pg != NULL); shutdown_handle = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); } /** * Main: start test */ int main (int xargc, char *xargv[]) { static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; static char *const argv_torus[] = { "test-dht-2dtorus", "-c", "test_dht_2dtorus.conf", NULL }; static char *const argv_line[] = { "test-dht-line", "-c", "test_dht_line.conf", NULL }; char *const *argv; int argc; if (strstr (xargv[0], "test_dht_2dtorus") != NULL) { argv = argv_torus; argc = sizeof (argv_torus) / sizeof (char *); test_topology = TORUS; } else if (strstr (xargv[0], "test_dht_line") != NULL) { argv = argv_line; argc = sizeof (argv_line) / sizeof (char *); test_topology = LINE; } else { GNUNET_break (0); return 1; } GNUNET_PROGRAM_run (argc - 1, argv, xargv[0], gettext_noop ("Test dht in different topologies."), options, &run, NULL); #if REMOVE_DIR GNUNET_DISK_directory_remove ("/tmp/test_dht_topo"); #endif if (0 == found_1) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "ID 1 not found!\n"); } if (TORUS == test_topology) { if (0 == found_2) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "ID 2 not found!\n"); } if (0 == found_far) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "ID far not found!\n"); } } return ok; } /* end of test_dht_topo.c */ gnunet-0.9.3/src/dht/test_dht_twopeer_get_put.c0000644000175000017500000004542511760505260016604 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/test_dht_twopeer_get_put.c * @brief base testcase for testing DHT service with * two running peers. * * This testcase starts peers using the GNUNET_TESTING_daemons_start * function call. On peer start, connects to the peers DHT service * by calling GNUNET_DHT_connected. Once notified about all peers * being started (by the peers_started_callback function), calls * GNUNET_TESTING_connect_topology, which connects the peers in a * "straight line" topology. On notification that all peers have * been properly connected, calls the do_get function which initiates * a GNUNET_DHT_get from the *second* peer. Once the GNUNET_DHT_get * function starts, runs the do_put function to insert data at the first peer. * If the GET is successful, schedules finish_testing * to stop the test and shut down peers. If GET is unsuccessful * after GET_TIMEOUT seconds, prints an error message and shuts down * the peers. */ #include "platform.h" #include "gnunet_testing_lib.h" #include "gnunet_core_service.h" #include "gnunet_dht_service.h" #include "block_dns.h" #include "gnunet_signatures.h" /* DEFINES */ #define VERBOSE GNUNET_NO /* Timeout for entire testcase */ #define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 40) /* Timeout for waiting for replies to get requests */ #define GET_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30) /* If number of peers not in config file, use this number */ #define DEFAULT_NUM_PEERS 2 #define DNS GNUNET_NO /* Globals */ /** * Directory to store temp data in, defined in config file */ static char *test_directory; /** * Variable used to store the number of connections we should wait for. */ static unsigned int expected_connections; /** * Variable used to keep track of how many peers aren't yet started. */ static unsigned long long peers_left; /** * Handle to the set of all peers run for this test. */ static struct GNUNET_TESTING_PeerGroup *pg; /** * Global handle we will use for GET requests. */ struct GNUNET_DHT_GetHandle *global_get_handle; /** * Total number of peers to run, set based on config file. */ static unsigned long long num_peers; /** * Global used to count how many connections we have currently * been notified about (how many times has topology_callback been called * with success?) */ static unsigned int total_connections; /** * Global used to count how many failed connections we have * been notified about (how many times has topology_callback * been called with failure?) */ static unsigned int failed_connections; /* Task handle to use to schedule test failure */ GNUNET_SCHEDULER_TaskIdentifier die_task; /* Global return value (0 for success, anything else for failure) */ static int ok; #if DNS struct GNUNET_DNS_Record data; #endif /** * Peer identity of the first peer started. */ static struct GNUNET_PeerIdentity peer1id; /** * Peer identity of the second peer started. */ static struct GNUNET_PeerIdentity peer2id; /** * Handle to the first peers DHT service (via the API) */ static struct GNUNET_DHT_Handle *peer1dht; /** * Handle to the second peers DHT service (via the API) */ static struct GNUNET_DHT_Handle *peer2dht; static void do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Check whether peers successfully shut down. */ void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { if (ok == 0) ok = 2; } } /** * Function scheduled to be run on the successful completion of this * testcase. Specifically, called when our get request completes. */ static void finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_assert (pg != NULL); GNUNET_assert (peer1dht != NULL); GNUNET_assert (peer2dht != NULL); GNUNET_DHT_disconnect (peer1dht); GNUNET_DHT_disconnect (peer2dht); GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); ok = 0; } /** * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut * down the peers without freeing memory associated with GET request. */ static void end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (peer1dht != NULL) GNUNET_DHT_disconnect (peer1dht); if (peer2dht != NULL) GNUNET_DHT_disconnect (peer2dht); if (pg != NULL) GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); } /** * Check if the get_handle is being used, if so stop the request. Either * way, schedule the end_badly_cont function which actually shuts down the * test. */ static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failing test with error: `%s'!\n", (char *) cls); if (global_get_handle != NULL) { GNUNET_DHT_get_stop (global_get_handle); global_get_handle = NULL; } GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL); ok = 1; } /** * Iterator called if the GET request initiated returns a response. * * @param cls closure * @param exp when will this value expire * @param key key of the result * @param type type of the result * @param size number of bytes in data * @param data pointer to the result data */ void get_result_iterator (void *cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_size, const struct GNUNET_PeerIdentity *put_path, unsigned int put_path_size, enum GNUNET_BLOCK_Type type, size_t size, const void *result_data) { GNUNET_HashCode original_key; /* Key data was stored data under */ char original_data[4]; /* Made up data that was stored */ memset (&original_key, 42, sizeof (GNUNET_HashCode)); /* Set the key to what it was set to previously */ memset (original_data, 43, sizeof (original_data)); #if DNS if ((sizeof (original_data) != size) || (0 != memcmp (&data.service_descriptor, key, sizeof (GNUNET_HashCode))) || (0 != memcmp ((char *) &data, result_data, sizeof (original_data)))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Key or data is not the same as was inserted!\n"); GNUNET_SCHEDULER_cancel (die_task); GNUNET_SCHEDULER_add_now (&end_badly, "key or data mismatch in get response!\n"); return; } #else if ((sizeof (original_data) != size) || (0 != memcmp (&original_key, key, sizeof (GNUNET_HashCode))) || (0 != memcmp (original_data, result_data, sizeof (original_data)))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Key or data is not the same as was inserted!\n"); GNUNET_SCHEDULER_cancel (die_task); GNUNET_SCHEDULER_add_now (&end_badly, "key or data mismatch in get response!\n"); return; } #endif GNUNET_SCHEDULER_cancel (die_task); GNUNET_DHT_get_stop (global_get_handle); GNUNET_SCHEDULER_add_now (&finish_testing, NULL); } /** * Start the GET request for the same key/data that was inserted. */ static void do_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_HashCode key; /* Key for data lookup */ #if DNS memcpy (&key, &data.service_descriptor, sizeof (GNUNET_HashCode)); #else memset (&key, 42, sizeof (GNUNET_HashCode)); /* Set the key to the same thing as when data was inserted */ #endif global_get_handle = GNUNET_DHT_get_start (peer2dht, #if DNS GNUNET_BLOCK_TYPE_DNS, #else GNUNET_BLOCK_TYPE_TEST, #endif &key, 1, GNUNET_DHT_RO_NONE, NULL, 0, &get_result_iterator, NULL); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10), &do_put, NULL); } /** * Called when the PUT request has been transmitted to the DHT service. * Schedule the GET request for some time in the future. */ static void put_finished (void *cls, int success) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_delayed (GET_TIMEOUT, &end_badly, "waiting for get response (data not found)"); } #if !DNS /** * Set up some data, and call API PUT function */ static void do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_HashCode key; /* Made up key to store data under */ char data[4]; /* Made up data to store */ memset (&key, 42, sizeof (GNUNET_HashCode)); /* Set the key to something simple so we can issue GET request */ memset (data, 43, sizeof (data)); /* Insert the data at the first peer */ GNUNET_DHT_put (peer1dht, &key, 1, GNUNET_DHT_RO_NONE, GNUNET_BLOCK_TYPE_TEST, sizeof (data), data, GNUNET_TIME_UNIT_FOREVER_ABS, GNUNET_TIME_UNIT_FOREVER_REL, &put_finished, NULL); } #else /** * Set up some data, and call API PUT function */ static void do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { char *name = "philipptoelke.gnunet."; size_t size = sizeof (struct GNUNET_DNS_Record); memset (&data, 0, size); data.purpose.size = htonl (size - sizeof (struct GNUNET_CRYPTO_RsaSignature)); data.purpose.purpose = GNUNET_SIGNATURE_PURPOSE_DNS_RECORD; GNUNET_CRYPTO_hash (name, strlen (name) + 1, &data.service_descriptor); data.service_type = htonl (GNUNET_DNS_SERVICE_TYPE_UDP); data.ports = htons (69); char *keyfile; GNUNET_asprintf (&keyfile, "/tmp/test_dns_data_key"); struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); GNUNET_free (keyfile); GNUNET_assert (my_private_key != NULL); GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &data.peer); data.expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS); /* Sign the block */ if (GNUNET_OK != GNUNET_CRYPTO_rsa_sign (my_private_key, &data.purpose, &data.signature)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not sign DNS_Record\n"); return; } GNUNET_CRYPTO_rsa_key_free (my_private_key); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Putting with key %08x\n", *((unsigned int *) &data.service_descriptor)); GNUNET_DHT_put (peer1dht, &data.service_descriptor, DEFAULT_PUT_REPLICATION, GNUNET_DHT_RO_NONE, GNUNET_BLOCK_TYPE_DNS, size, (char *) &data, GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS), GNUNET_TIME_UNIT_MINUTES, &put_finished, NULL); } #endif /** * This function is called whenever a connection attempt is finished between two of * the started peers (started with GNUNET_TESTING_daemons_start). The total * number of times this function is called should equal the number returned * from the GNUNET_TESTING_connect_topology call. * * The emsg variable is NULL on success (peers connected), and non-NULL on * failure (peers failed to connect). */ void topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, uint32_t distance, const struct GNUNET_CONFIGURATION_Handle *first_cfg, const struct GNUNET_CONFIGURATION_Handle *second_cfg, struct GNUNET_TESTING_Daemon *first_daemon, struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) { if (emsg == NULL) { total_connections++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s, distance %u\n", first_daemon->shortname, second_daemon->shortname, distance); } else { failed_connections++; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to connect peer %s to peer %s with error :\n%s\n", first_daemon->shortname, second_daemon->shortname, emsg); } if (total_connections == expected_connections) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created %d total connections, which is our target number! Starting next phase of testing.\n", total_connections); GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "from test gets"); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2), &do_get, NULL); } else if (total_connections + failed_connections == expected_connections) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from topology_callback (too many failed connections)"); } } /** * Callback which is called whenever a peer is started (as a result of the * GNUNET_TESTING_daemons_start call. * * @param cls closure argument given to GNUNET_TESTING_daemons_start * @param id the GNUNET_PeerIdentity of the started peer * @param cfg the configuration for this specific peer (needed to connect * to the DHT) * @param d the handle to the daemon started * @param emsg NULL if peer started, non-NULL on error */ static void peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to start daemon with error: `%s'\n", emsg); return; } GNUNET_assert (id != NULL); /* This is the first peer started */ if (peers_left == num_peers) { memcpy (&peer1id, id, sizeof (struct GNUNET_PeerIdentity)); /* Save the peer id */ peer1dht = GNUNET_DHT_connect (cfg, 100); /* Connect to the first peers DHT service */ if (peer1dht == NULL) /* If DHT connect failed */ { GNUNET_SCHEDULER_cancel (die_task); GNUNET_SCHEDULER_add_now (&end_badly, "Failed to get dht handle!\n"); } } else /* This is the second peer started */ { memcpy (&peer2id, id, sizeof (struct GNUNET_PeerIdentity)); /* Same as for first peer... */ peer2dht = GNUNET_DHT_connect (cfg, 100); if (peer2dht == NULL) { GNUNET_SCHEDULER_cancel (die_task); GNUNET_SCHEDULER_add_now (&end_badly, "Failed to get dht handle!\n"); } } /* Decrement number of peers left to start */ peers_left--; if (peers_left == 0) /* Indicates all peers started */ { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All %d daemons started, now connecting peers!\n", num_peers); expected_connections = -1; if ((pg != NULL)) /* Sanity check */ { /* Connect peers in a "straight line" topology, return the number of expected connections */ expected_connections = GNUNET_TESTING_connect_topology (pg, GNUNET_TESTING_TOPOLOGY_LINE, GNUNET_TESTING_TOPOLOGY_OPTION_ALL, 0.0, TIMEOUT, 12, NULL, NULL); } /* Cancel current timeout fail task */ GNUNET_SCHEDULER_cancel (die_task); if (expected_connections == GNUNET_SYSERR) /* Some error happened */ die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from connect topology (bad return)"); /* Schedule timeout on failure task */ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "from connect topology (timeout)"); ok = 0; } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { /* Get path from configuration file */ if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", &test_directory)) { ok = 404; return; } /* Get number of peers to start from configuration (should be two) */ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", &num_peers)) num_peers = DEFAULT_NUM_PEERS; /* Set peers_left so we know when all peers started */ peers_left = num_peers; /* Set up a task to end testing if peer start fails */ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "didn't start all daemons in reasonable amount of time!!!"); /* Start num_peers peers, call peers_started_callback on peer start, topology_callback on peer connect */ /* Read the API documentation for other parameters! */ pg = GNUNET_TESTING_daemons_start (cfg, num_peers, 2, 2, TIMEOUT, NULL, NULL, &peers_started_callback, NULL, &topology_callback, NULL, NULL); } static int check () { int ret; /* Arguments for GNUNET_PROGRAM_run */ char *const argv[] = { "test-dht-twopeer-get-put", /* Name to give running binary */ "-c", "test_dht_twopeer_data.conf", /* Config file to use */ NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; /* Run the run function as a new program */ ret = GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-dht-twopeer-get-put", "nohelp", options, &run, &ok); if (ret != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "`test-dht-twopeer': Failed with error code %d\n", ret); } return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-dht-twopeer", "WARNING", NULL); ret = check (); /** * Need to remove base directory, subdirectories taken care * of by the testing framework. */ if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to remove testing directory %s\n", test_directory); } return ret; } /* end of test_dht_twopeer_get_put.c */ gnunet-0.9.3/src/dht/dht.h0000644000175000017500000001755511760502551012261 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @author Christian Grothoff * @author Nathan Evans * @file dht/dht.h */ #ifndef DHT_H #define DHT_H /** * Size of the bloom filter the DHT uses to filter peers. */ #define DHT_BLOOM_SIZE 128 GNUNET_NETWORK_STRUCT_BEGIN /** * Message which indicates the DHT should cancel outstanding * requests and discard any state. */ struct GNUNET_DHT_ClientGetStopMessage { /** * Type: GNUNET_MESSAGE_TYPE_DHT_GET_STOP */ struct GNUNET_MessageHeader header; /** * Always zero. */ uint32_t reserved GNUNET_PACKED; /** * Unique ID identifying this request */ uint64_t unique_id GNUNET_PACKED; /** * Key of this request */ GNUNET_HashCode key; }; /** * DHT GET message sent from clients to service. Indicates that a GET * request should be issued. */ struct GNUNET_DHT_ClientGetMessage { /** * Type: GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET */ struct GNUNET_MessageHeader header; /** * Message options, actually an 'enum GNUNET_DHT_RouteOption' value. */ uint32_t options GNUNET_PACKED; /** * Replication level for this message */ uint32_t desired_replication_level GNUNET_PACKED; /** * The type for the data for the GET request; actually an 'enum * GNUNET_BLOCK_Type'. */ uint32_t type; /** * The key to search for */ GNUNET_HashCode key; /** * Unique ID identifying this request, if 0 then * the client will not expect a response */ uint64_t unique_id GNUNET_PACKED; /* Possibly followed by xquery, copied to end of this dealy do */ }; /** * Reply to a GET send from the service to a client. */ struct GNUNET_DHT_ClientResultMessage { /** * Type: GNUNET_MESSAGE_TYPE_DHT_CLIENT_RESULT */ struct GNUNET_MessageHeader header; /** * The type for the data. */ uint32_t type; /** * Number of peers recorded in the outgoing path from source to the * storgage location of this message. */ uint32_t put_path_length GNUNET_PACKED; /** * The number of peer identities recorded from the storage location * to this peer. */ uint32_t get_path_length GNUNET_PACKED; /** * Unique ID of the matching GET request. */ uint64_t unique_id GNUNET_PACKED; /** * When does this entry expire? */ struct GNUNET_TIME_AbsoluteNBO expiration; /** * The key that was searched for */ GNUNET_HashCode key; /* put path, get path and actual data are copied to end of this dealy do */ }; /** * Message to insert data into the DHT, sent from clients to DHT service. */ struct GNUNET_DHT_ClientPutMessage { /** * Type: GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT */ struct GNUNET_MessageHeader header; /** * The type of data to insert. */ uint32_t type GNUNET_PACKED; /** * Message options, actually an 'enum GNUNET_DHT_RouteOption' value. */ uint32_t options GNUNET_PACKED; /** * Replication level for this message */ uint32_t desired_replication_level GNUNET_PACKED; /** * Unique ID for the PUT message. */ uint64_t unique_id GNUNET_PACKED; /** * How long should this data persist? */ struct GNUNET_TIME_AbsoluteNBO expiration; /** * The key to store the value under. */ GNUNET_HashCode key; /* DATA copied to end of this message */ }; /** * Message to confirming receipt of PUT, sent from DHT service to clients. */ struct GNUNET_DHT_ClientPutConfirmationMessage { /** * Type: GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT_OK */ struct GNUNET_MessageHeader header; /** * Always zero. */ uint32_t reserved GNUNET_PACKED; /** * Unique ID from the PUT message that is being confirmed. */ uint64_t unique_id GNUNET_PACKED; }; /** * Message to monitor put requests going through peer, DHT service -> clients. */ struct GNUNET_DHT_MonitorPutMessage { /** * Type: GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT */ struct GNUNET_MessageHeader header; /** * Message options, actually an 'enum GNUNET_DHT_RouteOption' value. */ uint32_t options GNUNET_PACKED; /** * The type of data in the request. */ uint32_t type GNUNET_PACKED; /** * Hop count so far. */ uint32_t hop_count GNUNET_PACKED; /** * Replication level for this message */ uint32_t desired_replication_level GNUNET_PACKED; /** * Number of peers recorded in the outgoing path from source to the * storage location of this message. */ uint32_t put_path_length GNUNET_PACKED; /** * How long should this data persist? */ struct GNUNET_TIME_AbsoluteNBO expiration_time; /** * The key to store the value under. */ GNUNET_HashCode key; /* put path (if tracked) */ /* Payload */ }; /** * Message to request monitoring messages, clients -> DHT service. */ struct GNUNET_DHT_MonitorStartStopMessage { /** * Type: GNUNET_MESSAGE_TYPE_DHT_MONITOR_(START|STOP) */ struct GNUNET_MessageHeader header; /** * The type of data desired, GNUNET_BLOCK_TYPE_ANY for all. */ uint32_t type GNUNET_PACKED; /** * Flag whether to notify about GET messages. */ int16_t get GNUNET_PACKED; /** * Flag whether to notify about GET_REPONSE messages. */ int16_t get_resp GNUNET_PACKED; /** * Flag whether to notify about PUT messages. */ int16_t put GNUNET_PACKED; /** * Flag whether to use the provided key to filter messages. */ int16_t filter_key GNUNET_PACKED; /** * The key to filter messages by. */ GNUNET_HashCode key; }; /** * Message to monitor get requests going through peer, DHT service -> clients. */ struct GNUNET_DHT_MonitorGetMessage { /** * Type: GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT */ struct GNUNET_MessageHeader header; /** * Message options, actually an 'enum GNUNET_DHT_RouteOption' value. */ uint32_t options GNUNET_PACKED; /** * The type of data in the request. */ uint32_t type GNUNET_PACKED; /** * Hop count */ uint32_t hop_count GNUNET_PACKED; /** * Replication level for this message */ uint32_t desired_replication_level GNUNET_PACKED; /** * Number of peers recorded in the outgoing path from source to the * storage location of this message. */ uint32_t get_path_length GNUNET_PACKED; /** * The key to store the value under. */ GNUNET_HashCode key; /* get path (if tracked) */ }; /** * Message to monitor get results going through peer, DHT service -> clients. */ struct GNUNET_DHT_MonitorGetRespMessage { /** * Type: GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT */ struct GNUNET_MessageHeader header; /** * Content type. */ uint32_t type GNUNET_PACKED; /** * Length of the PUT path that follows (if tracked). */ uint32_t put_path_length GNUNET_PACKED; /** * Length of the GET path that follows (if tracked). */ uint32_t get_path_length GNUNET_PACKED; /** * When does the content expire? */ struct GNUNET_TIME_AbsoluteNBO expiration_time; /** * The key of the corresponding GET request. */ GNUNET_HashCode key; /* put path (if tracked) */ /* get path (if tracked) */ /* Payload */ }; GNUNET_NETWORK_STRUCT_END #endif gnunet-0.9.3/src/dht/test_dht_api.c0000644000175000017500000002123411760505267014140 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/test_dht_api.c * @brief base test case for dht api * * This test case tests DHT api to DUMMY DHT service communication. * */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_hello_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_dht_service.h" #include "gnunet_hello_lib.h" #define VERBOSE GNUNET_NO #define VERBOSE_ARM GNUNET_NO #define START_ARM GNUNET_YES /** * How long until we really give up on a particular testcase portion? */ #define TOTAL_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600) /** * How long until we give up on any particular operation (and retry)? */ #define BASE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3) #define MTYPE 12345 struct RetryContext { /** * When to really abort the operation. */ struct GNUNET_TIME_Absolute real_timeout; /** * What timeout to set for the current attempt (increases) */ struct GNUNET_TIME_Relative next_timeout; /** * The context of the peer we are dealing with. */ struct PeerContext *peer_ctx; /** * The task identifier of the retry task, so it can be cancelled. */ GNUNET_SCHEDULER_TaskIdentifier retry_task; }; struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_DHT_Handle *dht_handle; struct GNUNET_PeerIdentity id; struct GNUNET_DHT_GetHandle *get_handle; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static struct PeerContext p1; struct RetryContext retry_context; static int ok; static GNUNET_SCHEDULER_TaskIdentifier die_task; #if VERBOSE #define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) #else #define OKPP do { ok++; } while (0) #endif static void end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_DHT_disconnect (p1.dht_handle); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "DHT disconnected, returning success!\n"); ok = 0; } static void stop_arm (struct PeerContext *p) { #if START_ARM if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); GNUNET_OS_process_wait (p->arm_proc); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; #endif GNUNET_CONFIGURATION_destroy (p->cfg); } static void end_badly () { /* do work here */ #if VERBOSE FPRINTF (stderr, "%s", "Ending on an unhappy note.\n"); #endif if ((retry_context.peer_ctx != NULL) && (retry_context.peer_ctx->get_handle != NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping get request!\n"); GNUNET_DHT_get_stop (retry_context.peer_ctx->get_handle); } if (retry_context.retry_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (retry_context.retry_task); GNUNET_DHT_disconnect (p1.dht_handle); ok = 1; } /** * Signature of the main function of a task. * * @param cls closure * @param tc context information (why was this task triggered now) */ static void test_get_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerContext *peer = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called test_get_stop!\n"); if ((tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT) != 0) { GNUNET_break (0); GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } GNUNET_assert (peer->dht_handle != NULL); GNUNET_DHT_get_stop (peer->get_handle); peer->get_handle = NULL; GNUNET_SCHEDULER_add_now (&end, &p1); } static void test_get_iterator (void *cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int put_path_length, enum GNUNET_BLOCK_Type type, size_t size, const void *data) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test_get_iterator called (we got a result), stopping get request!\n"); GNUNET_SCHEDULER_add_continuation (&test_get_stop, &p1, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } /** * Signature of the main function of a task. * * @param cls closure * @param success result of PUT */ static void test_get (void *cls, int success) { struct PeerContext *peer = cls; GNUNET_HashCode hash; memset (&hash, 42, sizeof (GNUNET_HashCode)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called test_get!\n"); GNUNET_assert (peer->dht_handle != NULL); retry_context.real_timeout = GNUNET_TIME_relative_to_absolute (TOTAL_TIMEOUT); retry_context.next_timeout = BASE_TIMEOUT; peer->get_handle = GNUNET_DHT_get_start (peer->dht_handle, GNUNET_BLOCK_TYPE_TEST, &hash, 1, GNUNET_DHT_RO_NONE, NULL, 0, &test_get_iterator, NULL); if (peer->get_handle == NULL) { GNUNET_break (0); GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, &p1); return; } retry_context.peer_ctx = peer; } /** * Signature of the main function of a task. * * @param cls closure * @param tc context information (why was this task triggered now) */ static void test_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerContext *peer = cls; GNUNET_HashCode hash; char *data; size_t data_size = 42; memset (&hash, 42, sizeof (GNUNET_HashCode)); data = GNUNET_malloc (data_size); memset (data, 43, data_size); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called test_put!\n"); peer->dht_handle = GNUNET_DHT_connect (peer->cfg, 100); GNUNET_assert (peer->dht_handle != NULL); GNUNET_DHT_put (peer->dht_handle, &hash, 1, GNUNET_DHT_RO_NONE, GNUNET_BLOCK_TYPE_TEST, data_size, data, GNUNET_TIME_relative_to_absolute (TOTAL_TIMEOUT), TOTAL_TIMEOUT, &test_get, &p1); GNUNET_free (data); } static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE_ARM "-L", "DEBUG", #endif "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { GNUNET_assert (ok == 1); OKPP; die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1), &end_badly, NULL); setup_peer (&p1, "test_dht_api_peer1.conf"); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1), &test_put, &p1); } static int check () { char *const argv[] = { "test-dht-api", "-c", "test_dht_api_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; ok = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-dht-api", "nohelp", options, &run, &ok); stop_arm (&p1); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-dht-api", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-dht-peer-1"); return ret; } /* end of test_dht_api.c */ gnunet-0.9.3/src/dht/test_dht_twopeer_data.conf0000644000175000017500000000173411761764656016565 00000000000000[PATHS] DEFAULTCONFIG = test_dht_twopeer_data.conf SERVICEHOME = /tmp/test-dht-twopeer/ [resolver] AUTOSTART = YES [dht] DEBUG = NO AUTOSTART = YES #PREFIX = xterm -T dht -e gdb --args PORT = 12100 BINARY = gnunet-service-dht [block] plugins = test dht dns [dhtcache] QUOTA = 1 MB DATABASE = sqlite [transport] PLUGINS = tcp DEBUG = NO NEIGHBOUR_LIMIT = 50 PORT = 12365 [ats] WAN_QUOTA_IN = 1 GB WAN_QUOTA_OUT = 1 GB [core] HOSTNAME = localhost PORT = 12092 [arm] DEFAULTSERVICES = core dht PORT = 12366 DEBUG = NO [transport-tcp] TIMEOUT = 300 s PORT = 12368 BINDTO = 127.0.0.1 [TESTING] WEAKRANDOM = YES NUM_PEERS = 2 HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat [gnunetd] HOSTKEY = $SERVICEHOME/.hostkey [nat] DISABLEV6 = YES ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 USE_LOCALADDR = YES [dns] AUTOSTART = NO [mesh] AUTOSTART = NO [nse] AUTOSTART = NO [fs] AUTOSTART = NO [namestore] AUTOSTART = NO gnunet-0.9.3/src/dht/plugin_block_dht.c0000644000175000017500000001350611760502551014774 00000000000000/* This file is part of GNUnet (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/plugin_block_dht.c * @brief block plugin for DHT internals (right now, find-peer requests only); * other plugins should be used to store "useful" data in the * DHT (see fs block plugin) * @author Christian Grothoff */ #include "platform.h" #include "gnunet_constants.h" #include "gnunet_hello_lib.h" #include "gnunet_block_plugin.h" #define DEBUG_DHT GNUNET_EXTRA_LOGGING /** * Function called to validate a reply or a request. For * request evaluation, simply pass "NULL" for the reply_block. * * @param cls closure * @param type block type * @param query original query (hash) * @param bf pointer to bloom filter associated with query; possibly updated (!) * @param bf_mutator mutation value for bf * @param xquery extended query data (can be NULL, depending on type) * @param xquery_size number of bytes in xquery * @param reply_block response to validate * @param reply_block_size number of bytes in reply block * @return characterization of result */ static enum GNUNET_BLOCK_EvaluationResult block_plugin_dht_evaluate (void *cls, enum GNUNET_BLOCK_Type type, const GNUNET_HashCode * query, struct GNUNET_CONTAINER_BloomFilter **bf, int32_t bf_mutator, const void *xquery, size_t xquery_size, const void *reply_block, size_t reply_block_size) { GNUNET_HashCode mhash; const struct GNUNET_HELLO_Message *hello; struct GNUNET_PeerIdentity pid; const struct GNUNET_MessageHeader *msg; if (type != GNUNET_BLOCK_TYPE_DHT_HELLO) return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; if (xquery_size != 0) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; } if (NULL == reply_block) return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; if (reply_block_size < sizeof (struct GNUNET_MessageHeader)) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } msg = reply_block; if (reply_block_size != ntohs (msg->size)) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } hello = reply_block; if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid)) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } if (NULL != bf) { GNUNET_BLOCK_mingle_hash (&pid.hashPubKey, bf_mutator, &mhash); if (NULL != *bf) { if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash)) return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE; } else { *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, GNUNET_CONSTANTS_BLOOMFILTER_K); } GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash); } return GNUNET_BLOCK_EVALUATION_OK_MORE; } /** * Function called to obtain the key for a block. * * @param cls closure * @param type block type * @param block block to get the key for * @param block_size number of bytes in block * @param key set to the key (query) for the given block * @return GNUNET_OK on success, GNUNET_SYSERR if type not supported * (or if extracting a key from a block of this type does not work) */ static int block_plugin_dht_get_key (void *cls, enum GNUNET_BLOCK_Type type, const void *block, size_t block_size, GNUNET_HashCode * key) { const struct GNUNET_MessageHeader *msg; const struct GNUNET_HELLO_Message *hello; struct GNUNET_PeerIdentity *pid; if (type != GNUNET_BLOCK_TYPE_DHT_HELLO) return GNUNET_SYSERR; if (block_size < sizeof (struct GNUNET_MessageHeader)) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "block-dht", _("Block not of type %u\n"), GNUNET_BLOCK_TYPE_DHT_HELLO); return GNUNET_NO; } msg = block; if (block_size != ntohs (msg->size)) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "block-dht", _("Size mismatch for block\n"), GNUNET_BLOCK_TYPE_DHT_HELLO); return GNUNET_NO; } hello = block; pid = (struct GNUNET_PeerIdentity *) key; if (GNUNET_OK != GNUNET_HELLO_get_id (hello, pid)) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "block-dht", _("Block of type %u is malformed\n"), GNUNET_BLOCK_TYPE_DHT_HELLO); return GNUNET_NO; } return GNUNET_OK; } /** * Entry point for the plugin. */ void * libgnunet_plugin_block_dht_init (void *cls) { static enum GNUNET_BLOCK_Type types[] = { GNUNET_BLOCK_TYPE_DHT_HELLO, GNUNET_BLOCK_TYPE_ANY /* end of list */ }; struct GNUNET_BLOCK_PluginFunctions *api; api = GNUNET_malloc (sizeof (struct GNUNET_BLOCK_PluginFunctions)); api->evaluate = &block_plugin_dht_evaluate; api->get_key = &block_plugin_dht_get_key; api->types = types; return api; } /** * Exit point from the plugin. */ void * libgnunet_plugin_block_dht_done (void *cls) { struct GNUNET_TRANSPORT_PluginFunctions *api = cls; GNUNET_free (api); return NULL; } /* end of plugin_block_dht.c */ gnunet-0.9.3/src/dht/Makefile.am0000644000175000017500000001375411744051775013373 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -lole32 -lshell32 -liconv -lstdc++ -lcomdlg32 -lgdi32 endif plugindir = $(libdir)/gnunet pkgcfgdir= $(pkgdatadir)/config.d/ pkgcfg_DATA = \ dht.conf if HAVE_ZLIB ZLIB_LNK = -lz endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIB = -lgcov endif lib_LTLIBRARIES = \ libgnunetdht.la libgnunetdht_la_SOURCES = \ dht_api.c dht.h libgnunetdht_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(XLIB) libgnunetdht_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 1:0:1 plugin_LTLIBRARIES = \ libgnunet_plugin_block_dht.la libgnunet_plugin_block_dht_la_SOURCES = \ plugin_block_dht.c libgnunet_plugin_block_dht_la_LIBADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/block/libgnunetblock.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_block_dht_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_block_dht_la_DEPENDENCIES = \ $(top_builddir)/src/block/libgnunetblock.la bin_PROGRAMS = \ gnunet-service-dht \ gnunet-dht-monitor \ gnunet-dht-get \ gnunet-dht-put gnunet_service_dht_SOURCES = \ gnunet-service-dht.c gnunet-service-dht.h \ gnunet-service-dht_clients.c gnunet-service-dht_clients.h \ gnunet-service-dht_datacache.c gnunet-service-dht_datacache.h \ gnunet-service-dht_hello.c gnunet-service-dht_hello.h \ gnunet-service-dht_nse.c gnunet-service-dht_nse.h \ gnunet-service-dht_neighbours.c gnunet-service-dht_neighbours.h \ gnunet-service-dht_routing.c gnunet-service-dht_routing.h gnunet_service_dht_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/nse/libgnunetnse.la \ $(top_builddir)/src/ats/libgnunetats.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/block/libgnunetblock.la \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la \ -lm gnunet_dht_get_SOURCES = \ gnunet-dht-get.c gnunet_dht_get_LDADD = \ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la gnunet_dht_get_DEPENDENCIES = \ libgnunetdht.la gnunet_dht_put_SOURCES = \ gnunet-dht-put.c gnunet_dht_put_LDADD = \ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la gnunet_dht_put_DEPENDENCIES = \ libgnunetdht.la gnunet_dht_monitor_SOURCES = \ gnunet-dht-monitor.c gnunet_dht_monitor_LDADD = \ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la gnunet_dht_monitor_DEPENDENCIES = \ libgnunetdht.la check_PROGRAMS = \ test_dht_api \ test_dht_twopeer \ test_dht_twopeer_put_get \ test_dht_twopeer_get_put \ test_dht_twopeer_path_tracking \ test_dht_multipeer \ test_dht_line \ test_dht_2dtorus \ test_dht_monitor if ENABLE_TEST_RUN TESTS = test_dht_api $(check_SCRIPTS) \ test_dht_twopeer \ test_dht_twopeer_put_get \ test_dht_twopeer_get_put \ test_dht_twopeer_path_tracking \ test_dht_multipeer \ test_dht_line \ test_dht_2dtorus \ test_dht_monitor endif test_dht_api_SOURCES = \ test_dht_api.c test_dht_api_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_api_DEPENDENCIES = \ libgnunetdht.la test_dht_twopeer_SOURCES = \ test_dht_twopeer.c test_dht_twopeer_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_twopeer_DEPENDENCIES = \ libgnunetdht.la test_dht_twopeer_put_get_SOURCES = \ test_dht_twopeer_put_get.c test_dht_twopeer_put_get_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_twopeer_get_put_SOURCES = \ test_dht_twopeer_get_put.c test_dht_twopeer_get_put_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_twopeer_path_tracking_SOURCES = \ test_dht_twopeer_path_tracking.c test_dht_twopeer_path_tracking_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_multipeer_SOURCES = \ test_dht_multipeer.c test_dht_multipeer_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_multipeer_DEPENDENCIES = \ libgnunetdht.la test_dht_2dtorus_SOURCES = \ test_dht_topo.c test_dht_2dtorus_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_2dtorus_DEPENDENCIES = \ libgnunetdht.la test_dht_line_SOURCES = \ test_dht_topo.c test_dht_line_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_line_DEPENDENCIES = \ libgnunetdht.la test_dht_monitor_SOURCES = test_dht_monitor.c test_dht_monitor_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_monitor_DEPENDENCIES = \ libgnunetdht.la EXTRA_DIST = \ $(check_SCRIPTS) \ test_dht_api_data.conf \ test_dht_api_peer1.conf \ test_dht_twopeer_data.conf \ test_dht_multipeer_data.conf \ test_dht_2dtorus.conf \ test_dht_line.conf \ multipeer_topo.dat check_SCRIPTS = \ test_dht_tools.sh gnunet-0.9.3/src/dht/test_dht_twopeer.c0000644000175000017500000003452611761753145015065 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/test_dht_twopeer.c * @brief base testcase for testing DHT service with * two running peers */ #include "platform.h" #include "gnunet_testing_lib.h" #include "gnunet_core_service.h" #include "gnunet_dht_service.h" /* DEFINES */ #define MAX_GET_ATTEMPTS 10 #define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5) #define DEFAULT_NUM_PEERS 2 /* Structs */ struct PeerGetContext { struct GNUNET_PeerIdentity *peer; struct GNUNET_DHT_Handle *dht_handle; struct GNUNET_DHT_GetHandle *get_handle; unsigned int get_attempts; GNUNET_SCHEDULER_TaskIdentifier retry_task; }; /* Globals */ static char *test_directory; static struct PeerGetContext curr_get_ctx; static unsigned int expected_connections; static unsigned long long peers_left; static struct GNUNET_TESTING_PeerGroup *pg; static unsigned long long num_peers; static unsigned int total_gets; static unsigned int gets_succeeded; static unsigned int total_connections; static unsigned int failed_connections; static GNUNET_SCHEDULER_TaskIdentifier die_task; static int ok; static struct GNUNET_PeerIdentity peer1id; static struct GNUNET_PeerIdentity peer2id; static struct GNUNET_DHT_Handle *peer1dht; static struct GNUNET_DHT_Handle *peer2dht; /** * Check whether peers successfully shut down. */ static void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { if (ok == 0) ok = 2; } } static void finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_assert (pg != NULL); GNUNET_assert (peer1dht != NULL); GNUNET_assert (peer2dht != NULL); GNUNET_DHT_disconnect (peer1dht); GNUNET_DHT_disconnect (peer2dht); GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); pg = NULL; ok = 0; } static void end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (peer1dht != NULL) GNUNET_DHT_disconnect (peer1dht); if (peer2dht != NULL) GNUNET_DHT_disconnect (peer2dht); if (pg != NULL) { GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); pg = NULL; } if (curr_get_ctx.retry_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (curr_get_ctx.retry_task); curr_get_ctx.retry_task = GNUNET_SCHEDULER_NO_TASK; } } static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { const char *emsg = cls; FPRINTF (stderr, "Error: %s\n", emsg); if (curr_get_ctx.retry_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (curr_get_ctx.retry_task); curr_get_ctx.retry_task = GNUNET_SCHEDULER_NO_TASK; } if (curr_get_ctx.get_handle != NULL) { GNUNET_DHT_get_stop (curr_get_ctx.get_handle); } GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL); ok = 1; } /* Forward declaration */ static void do_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Iterator called on each result obtained for a DHT * operation that expects a reply * * @param cls closure * @param exp when will this value expire * @param key key of the result * @param type type of the result * @param size number of bytes in data * @param data pointer to the result data */ static void get_result_iterator (void *cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int put_path_length, enum GNUNET_BLOCK_Type type, size_t size, const void *data) { struct PeerGetContext *get_context = cls; if (0 != memcmp (&get_context->peer->hashPubKey, key, sizeof (GNUNET_HashCode))) { FPRINTF (stderr, "%s", "??\n"); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Key returned is not the same key as was searched for!\n"); GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, "key mismatch in get response!\n"); return; } if (get_context->retry_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (get_context->retry_task); get_context->retry_task = GNUNET_SCHEDULER_NO_TASK; } if (get_context->peer == &peer2id) { get_context->peer = &peer1id; get_context->dht_handle = peer2dht; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received first correct GET request response!\n"); GNUNET_DHT_get_stop (get_context->get_handle); GNUNET_SCHEDULER_add_now (&do_get, get_context); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received second correct GET request response!\n"); GNUNET_SCHEDULER_cancel (die_task); GNUNET_DHT_get_stop (get_context->get_handle); die_task = GNUNET_SCHEDULER_add_now (&finish_testing, NULL); } } static void stop_retry_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); static void get_stop_finished (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerGetContext *get_context = cls; if (get_context->get_attempts >= MAX_GET_ATTEMPTS) { FPRINTF (stderr, "%s", "?\n"); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Too many attempts failed, ending test!\n", get_context->get_attempts); GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, "GET attempt failed, ending test!\n"); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Get attempt %u failed, retrying request!\n", get_context->get_attempts); FPRINTF (stderr, "%s", "."); get_context->get_attempts++; get_context->retry_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60), &stop_retry_get, get_context); get_context->get_handle = GNUNET_DHT_get_start (get_context->dht_handle, GNUNET_BLOCK_TYPE_DHT_HELLO, &get_context->peer->hashPubKey, 1, GNUNET_DHT_RO_NONE, NULL, 0, &get_result_iterator, get_context); } static void stop_retry_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerGetContext *get_context = cls; get_context->retry_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Get attempt %u failed, canceling request!\n", get_context->get_attempts); GNUNET_DHT_get_stop (get_context->get_handle); get_context->get_handle = NULL; GNUNET_SCHEDULER_add_now (&get_stop_finished, get_context); } static void do_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerGetContext *get_context = cls; get_context->retry_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10), &stop_retry_get, get_context); get_context->get_handle = GNUNET_DHT_get_start (get_context->dht_handle, GNUNET_BLOCK_TYPE_DHT_HELLO, &get_context->peer->hashPubKey, 1, GNUNET_DHT_RO_FIND_PEER, NULL, 0, &get_result_iterator, get_context); } static void topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, uint32_t distance, const struct GNUNET_CONFIGURATION_Handle *first_cfg, const struct GNUNET_CONFIGURATION_Handle *second_cfg, struct GNUNET_TESTING_Daemon *first_daemon, struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) { if (emsg == NULL) { total_connections++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s, distance %u\n", first_daemon->shortname, second_daemon->shortname, distance); } else { failed_connections++; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to connect peer %s to peer %s with error :\n%s\n", first_daemon->shortname, second_daemon->shortname, emsg); } if (total_connections == expected_connections) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created %d total connections, which is our target number! Starting next phase of testing.\n", total_connections); GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "Timeout trying to GET"); curr_get_ctx.dht_handle = peer1dht; curr_get_ctx.peer = &peer2id; GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2), &do_get, &curr_get_ctx); } else if (total_connections + failed_connections == expected_connections) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from topology_callback (too many failed connections)"); } } static void connect_topology (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { expected_connections = -1; if ((pg != NULL) && (peers_left == 0)) expected_connections = GNUNET_TESTING_connect_topology (pg, GNUNET_TESTING_TOPOLOGY_CLIQUE, GNUNET_TESTING_TOPOLOGY_OPTION_ALL, 0.0, TIMEOUT, 12, NULL, NULL); GNUNET_SCHEDULER_cancel (die_task); if (expected_connections == GNUNET_SYSERR) die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from connect topology (bad return)"); else die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "from connect topology (timeout)"); } static void peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { if (emsg != NULL) { FPRINTF (stderr, "Failed to start daemon: `%s'\n", emsg); return; } GNUNET_assert (id != NULL); if (peers_left == num_peers) { memcpy (&peer1id, id, sizeof (struct GNUNET_PeerIdentity)); peer1dht = GNUNET_DHT_connect (cfg, 100); if (peer1dht == NULL) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, "Failed to get dht handle!\n"); } } else { memcpy (&peer2id, id, sizeof (struct GNUNET_PeerIdentity)); peer2dht = GNUNET_DHT_connect (cfg, 100); if (peer2dht == NULL) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, "Failed to get dht handle!\n"); } } peers_left--; if (peers_left == 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All %d daemons started, now connecting peers!\n", num_peers); GNUNET_SCHEDULER_cancel (die_task); /* Set up task in case topology creation doesn't finish * within a reasonable amount of time */ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "from peers_started_callback"); GNUNET_SCHEDULER_add_now (&connect_topology, NULL); ok = 0; } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", &test_directory)) { ok = 404; return; } if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", &num_peers)) num_peers = DEFAULT_NUM_PEERS; peers_left = num_peers; total_gets = num_peers; gets_succeeded = 0; /* Set up a task to end testing if peer start fails */ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "didn't start all daemons in reasonable amount of time!!!"); pg = GNUNET_TESTING_daemons_start (cfg, num_peers, 10, num_peers, TIMEOUT, NULL, NULL, &peers_started_callback, NULL, &topology_callback, NULL, NULL); } static int check () { int ret; char *const argv[] = { "test-dht-twopeer", "-c", "test_dht_twopeer_data.conf", NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; ret = GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-dht-twopeer", "nohelp", options, &run, &ok); if (ret != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "`test-dht-twopeer': Failed with error code %d\n", ret); } return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-dht-twopeer", "WARNING", NULL); ret = check (); /** * Need to remove base directory, subdirectories taken care * of by the testing framework. */ if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to remove testing directory %s\n", test_directory); } return ret; } /* end of test_dht_twopeer.c */ gnunet-0.9.3/src/dht/gnunet-dht-monitor.c0000644000175000017500000002216111760502551015224 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/gnunet-dht-monitor.c * @brief search for data in DHT * @author Christian Grothoff * @author Bartlomiej Polot */ #include "platform.h" #include "gnunet_dht_service.h" /** * The type of the query */ static unsigned int block_type; /** * The key to be monitored */ static char *query_key; /** * User supplied timeout value (in seconds) */ static unsigned long long timeout_request = 5; /** * Be verbose */ static int verbose; /** * Handle to the DHT */ static struct GNUNET_DHT_Handle *dht_handle; /** * Global handle of the configuration */ static const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Handle for the get request */ static struct GNUNET_DHT_MonitorHandle *monitor_handle; /** * Count of messages received */ static unsigned int result_count; /** * Global status value */ static int ret; /** * Function called on shutdown, disconnects from DHT if necessary. * * @param cls closure (unused) * @param tc Task Context */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (verbose) FPRINTF (stderr, "%s", "Shutting down!\n"); if (dht_handle != NULL) { GNUNET_DHT_disconnect (dht_handle); dht_handle = NULL; } } /** * Stop monitoring request and start shutdown * * @param cls closure (unused) * @param tc Task Context */ static void cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (verbose) FPRINTF (stderr, "%s", "Cleaning up!\n"); if (monitor_handle != NULL) { GNUNET_DHT_monitor_stop (monitor_handle); monitor_handle = NULL; } GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); } /** * Callback called on each GET request going through the DHT. * * @param cls Closure. * @param options Options, for instance RecordRoute, DemultiplexEverywhere. * @param type The type of data in the request. * @param hop_count Hop count so far. * @param path_length number of entries in path (or 0 if not recorded). * @param path peers on the GET path (or NULL if not recorded). * @param desired_replication_level Desired replication level. * @param key Key of the requested data. */ void get_callback (void *cls, enum GNUNET_DHT_RouteOption options, enum GNUNET_BLOCK_Type type, uint32_t hop_count, uint32_t desired_replication_level, unsigned int path_length, const struct GNUNET_PeerIdentity *path, const GNUNET_HashCode * key) { FPRINTF (stdout, "Result %d, operation: %s, type %d\n Key: %s", result_count, "GET", type, GNUNET_h2s_full(key)); result_count++; } /** * Callback called on each GET reply going through the DHT. * * @param cls Closure. * @param type The type of data in the result. * @param get_path Peers on GET path (or NULL if not recorded). * @param get_path_length number of entries in get_path. * @param put_path peers on the PUT path (or NULL if not recorded). * @param put_path_length number of entries in get_path. * @param exp Expiration time of the data. * @param key Key of the data. * @param data Pointer to the result data. * @param size Number of bytes in data. */ void get_resp_callback (void *cls, enum GNUNET_BLOCK_Type type, const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int put_path_length, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const void *data, size_t size) { FPRINTF (stdout, "Result %d, operation: %s, type %d:\n Key: %s\n %.*s\n", result_count, "GET_RESP", type, GNUNET_h2s_full(key), (unsigned int) size, (char *) data); result_count++; } /** * Callback called on each PUT request going through the DHT. * * @param cls Closure. * @param options Options, for instance RecordRoute, DemultiplexEverywhere. * @param type The type of data in the request. * @param hop_count Hop count so far. * @param path_length number of entries in path (or 0 if not recorded). * @param path peers on the PUT path (or NULL if not recorded). * @param desired_replication_level Desired replication level. * @param exp Expiration time of the data. * @param key Key under which data is to be stored. * @param data Pointer to the data carried. * @param size Number of bytes in data. */ void put_callback (void *cls, enum GNUNET_DHT_RouteOption options, enum GNUNET_BLOCK_Type type, uint32_t hop_count, uint32_t desired_replication_level, unsigned int path_length, const struct GNUNET_PeerIdentity *path, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const void *data, size_t size) { FPRINTF (stdout, "Result %d, operation: %s, type %d:\n Key: %s\n %.*s\n", result_count, "PUT", type, GNUNET_h2s_full(key), (unsigned int) size, (char *) data); result_count++; } /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param c configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { struct GNUNET_TIME_Relative timeout; GNUNET_HashCode *key; cfg = c; dht_handle = GNUNET_DHT_connect (cfg, 1); if (dht_handle == NULL) { if (verbose) FPRINTF (stderr, "%s", "Couldn't connect to DHT service!\n"); ret = 1; return; } else if (verbose) FPRINTF (stderr, "%s", "Connected to DHT service!\n"); if (block_type == GNUNET_BLOCK_TYPE_ANY) /* Type of data not set */ block_type = GNUNET_BLOCK_TYPE_TEST; if (query_key != NULL) { key = GNUNET_malloc (sizeof(GNUNET_HashCode)); GNUNET_CRYPTO_hash (query_key, strlen (query_key), key); } else key = NULL; if (0 != timeout_request) { timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, timeout_request); if (verbose) FPRINTF (stderr, "Monitoring for %llus\n", timeout_request); } else { timeout = GNUNET_TIME_UNIT_FOREVER_REL; if (verbose) FPRINTF (stderr, "%s", "Monitoring indefinitely (close with Ctrl+C)\n"); } GNUNET_SCHEDULER_add_delayed (timeout, &cleanup_task, NULL); if (verbose) FPRINTF (stderr, "Issuing MONITOR request for %s!\n", query_key); monitor_handle = GNUNET_DHT_monitor_start (dht_handle, block_type, key, &get_callback, &get_resp_callback, &put_callback, NULL); if (verbose) FPRINTF (stderr, "%s", "MONITOR started!\n"); GNUNET_free_non_null (key); } /** * gnunet-dht-get command line options */ static struct GNUNET_GETOPT_CommandLineOption options[] = { {'k', "key", "KEY", gettext_noop ("the query key"), 1, &GNUNET_GETOPT_set_string, &query_key}, {'t', "type", "TYPE", gettext_noop ("the type of data to look for"), 1, &GNUNET_GETOPT_set_uint, &block_type}, {'T', "timeout", "TIMEOUT", gettext_noop ("how long to execute? 0 = forever"), 1, &GNUNET_GETOPT_set_ulong, &timeout_request}, {'V', "verbose", NULL, gettext_noop ("be verbose (print progress information)"), 0, &GNUNET_GETOPT_set_one, &verbose}, GNUNET_GETOPT_OPTION_END }; /** * Entry point for gnunet-dht-monitor * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-dht-get", gettext_noop ("Prints all packets that go through the DHT."), options, &run, NULL)) ? ret : 1; } /* end of gnunet-dht-monitor.c */ gnunet-0.9.3/src/dht/dht.conf.in0000644000175000017500000000124511760502552013352 00000000000000[dht] AUTOSTART = YES @JAVAPORT@PORT = 2095 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dht ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; BUCKET_SIZE = 4 UNIXPATH = /tmp/gnunet-service-dht.sock # This could be relaxed... UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES # DISABLE_SOCKET_FORWARDING = NO # DEBUG = YES # USERNAME = # MAXBUF = # TIMEOUT = # DISABLEV6 = # BINDTO = # REJECT_FROM = # REJECT_FROM6 = # PREFIX = # DO_FIND_PEER = # STRICT_KADEMLIA = # USE_MAX_HOPS = # MAX_HOPS = # REPUBLISH = YES # REPLICATION_FREQUENCY = 60 # STOP_ON_CLOSEST = # STOP_FOUND = # CONVERGE_MODIFIER = [dhtcache] DATABASE = sqlite QUOTA = 1 MB gnunet-0.9.3/src/dht/gnunet-service-dht_neighbours.h0000644000175000017500000001262011760502551017426 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/gnunet-service-dht_neighbours.h * @brief GNUnet DHT routing code * @author Christian Grothoff * @author Nathan Evans */ #ifndef GNUNET_SERVICE_DHT_NEIGHBOURS_H #define GNUNET_SERVICE_DHT_NEIGHBOURS_H #include "gnunet_util_lib.h" #include "gnunet_block_lib.h" #include "gnunet_dht_service.h" /** * Perform a PUT operation. Forwards the given request to other * peers. Does not store the data locally. Does not give the * data to local clients. May do nothing if this is the only * peer in the network (or if we are the closest peer in the * network). * * @param type type of the block * @param options routing options * @param desired_replication_level desired replication level * @param expiration_time when does the content expire * @param hop_count how many hops has this message traversed so far * @param bf Bloom filter of peers this PUT has already traversed * @param key key for the content * @param put_path_length number of entries in put_path * @param put_path peers this request has traversed so far (if tracked) * @param data payload to store * @param data_size number of bytes in data */ void GDS_NEIGHBOURS_handle_put (enum GNUNET_BLOCK_Type type, enum GNUNET_DHT_RouteOption options, uint32_t desired_replication_level, struct GNUNET_TIME_Absolute expiration_time, uint32_t hop_count, struct GNUNET_CONTAINER_BloomFilter *bf, const GNUNET_HashCode * key, unsigned int put_path_length, struct GNUNET_PeerIdentity *put_path, const void *data, size_t data_size); /** * Perform a GET operation. Forwards the given request to other * peers. Does not lookup the key locally. May do nothing if this is * the only peer in the network (or if we are the closest peer in the * network). * * @param type type of the block * @param options routing options * @param desired_replication_level desired replication count * @param hop_count how many hops did this request traverse so far? * @param key key for the content * @param xquery extended query * @param xquery_size number of bytes in xquery * @param reply_bf bloomfilter to filter duplicates * @param reply_bf_mutator mutator for reply_bf * @param peer_bf filter for peers not to select (again, updated) */ void GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type, enum GNUNET_DHT_RouteOption options, uint32_t desired_replication_level, uint32_t hop_count, const GNUNET_HashCode * key, const void *xquery, size_t xquery_size, const struct GNUNET_CONTAINER_BloomFilter *reply_bf, uint32_t reply_bf_mutator, struct GNUNET_CONTAINER_BloomFilter *peer_bf); /** * Handle a reply (route to origin). Only forwards the reply back to * other peers waiting for it. Does not do local caching or * forwarding to local clients. * * @param target neighbour that should receive the block (if still connected) * @param type type of the block * @param expiration_time when does the content expire * @param key key for the content * @param put_path_length number of entries in put_path * @param put_path peers the original PUT traversed (if tracked) * @param get_path_length number of entries in put_path * @param get_path peers this reply has traversed so far (if tracked) * @param data payload of the reply * @param data_size number of bytes in data */ void GDS_NEIGHBOURS_handle_reply (const struct GNUNET_PeerIdentity *target, enum GNUNET_BLOCK_Type type, struct GNUNET_TIME_Absolute expiration_time, const GNUNET_HashCode * key, unsigned int put_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *get_path, const void *data, size_t data_size); /** * Initialize neighbours subsystem. * * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GDS_NEIGHBOURS_init (void); /** * Shutdown neighbours subsystem. */ void GDS_NEIGHBOURS_done (void); /** * Get the ID of the local node. * * @return identity of the local node */ struct GNUNET_PeerIdentity * GDS_NEIGHBOURS_get_id (); #endif gnunet-0.9.3/src/dht/gnunet-service-dht.c0000644000175000017500000001127211760502551015176 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/gnunet-service-dht.c * @brief GNUnet DHT service * @author Christian Grothoff * @author Nathan Evans */ #include "platform.h" #include "gnunet_block_lib.h" #include "gnunet_util_lib.h" #include "gnunet_transport_service.h" #include "gnunet_hello_lib.h" #include "gnunet_dht_service.h" #include "gnunet_statistics_service.h" #include "gnunet-service-dht.h" #include "gnunet-service-dht_clients.h" #include "gnunet-service-dht_datacache.h" #include "gnunet-service-dht_hello.h" #include "gnunet-service-dht_neighbours.h" #include "gnunet-service-dht_nse.h" #include "gnunet-service-dht_routing.h" /** * Handle for the statistics service. */ struct GNUNET_STATISTICS_Handle *GDS_stats; /** * Our handle to the BLOCK library. */ struct GNUNET_BLOCK_Context *GDS_block_context; /** * The configuration the DHT service is running with */ const struct GNUNET_CONFIGURATION_Handle *GDS_cfg; /** * Our HELLO */ struct GNUNET_MessageHeader *GDS_my_hello; /** * Handle to the transport service, for getting our hello */ struct GNUNET_TRANSPORT_Handle *GDS_transport_handle; /** * Handle to get our current HELLO. */ static struct GNUNET_TRANSPORT_GetHelloHandle *ghh; /** * Receive the HELLO from transport service, free current and replace * if necessary. * * @param cls NULL * @param message HELLO message of peer */ static void process_hello (void *cls, const struct GNUNET_MessageHeader *message) { GNUNET_assert (message != NULL); GNUNET_free_non_null (GDS_my_hello); GDS_my_hello = GNUNET_malloc (ntohs (message->size)); memcpy (GDS_my_hello, message, ntohs (message->size)); } /** * Task run during shutdown. * * @param cls unused * @param tc unused */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (NULL != ghh) { GNUNET_TRANSPORT_get_hello_cancel (ghh); ghh = NULL; } if (GDS_transport_handle != NULL) { GNUNET_TRANSPORT_disconnect (GDS_transport_handle); GDS_transport_handle = NULL; } GDS_NEIGHBOURS_done (); GDS_DATACACHE_done (); GDS_ROUTING_done (); GDS_HELLO_done (); GDS_NSE_done (); if (GDS_block_context != NULL) { GNUNET_BLOCK_context_destroy (GDS_block_context); GDS_block_context = NULL; } if (GDS_stats != NULL) { GNUNET_STATISTICS_destroy (GDS_stats, GNUNET_YES); GDS_stats = NULL; } GNUNET_free_non_null (GDS_my_hello); GDS_my_hello = NULL; } /** * Process dht requests. * * @param cls closure * @param server the initialized server * @param c configuration to use */ static void run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *c) { GDS_cfg = c; GDS_block_context = GNUNET_BLOCK_context_create (GDS_cfg); GDS_stats = GNUNET_STATISTICS_create ("dht", GDS_cfg); GDS_ROUTING_init (); GDS_NSE_init (); GDS_DATACACHE_init (); GDS_HELLO_init (); GDS_CLIENTS_init (server); if (GNUNET_OK != GDS_NEIGHBOURS_init ()) { shutdown_task (NULL, NULL); return; } GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); GDS_transport_handle = GNUNET_TRANSPORT_connect (GDS_cfg, NULL, NULL, NULL, NULL, NULL); if (GDS_transport_handle == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to connect to transport service!\n")); return; } ghh = GNUNET_TRANSPORT_get_hello (GDS_transport_handle, &process_hello, NULL); } /** * The main function for the dht service. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { int ret; ret = (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "dht", GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; GDS_CLIENTS_done (); return ret; } /* end of gnunet-service-dht.c */ gnunet-0.9.3/src/dht/test_dht_2dtorus.conf0000644000175000017500000000270311724074662015474 00000000000000[PATHS] SERVICEHOME = /tmp/test_dht_topo/ DEFAULTCONFIG = test_dht_2dtours.conf [arm] PORT = 10010 DEFAULTSERVICES = core dht #DEBUG = YES [statistics] AUTOSTART = YES PORT = 10000 [dht] DEBUG = NO AUTOSTART = YES ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; HOSTNAME = localhost PORT = 10001 [dns] AUTOSTART = NO PORT = 10011 [transport] PORT = 10002 AUTOSTART = YES [nat] DISABLEV6 = YES BINDTO = 127.0.0.1 ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 [ats] WAN_QUOTA_IN = 1 GB WAN_QUOTA_OUT = 1 GB [core] AUTOSTART = YES PORT = 10003 [peerinfo] AUTOSTART = YES PORT = 10004 [testing] NUM_PEERS = 16 WEAKRANDOM = YES TOPOLOGY = NONE CONNECT_TOPOLOGY = 2D_TORUS BLACKLIST_TOPOLOGY = 2D_TORUS #TOPOLOGY_FILE = small.dat #CONNECT_TOPOLOGY = ERDOS_RENYI #CONNECT_TOPOLOGY_OPTION = CONNECT_MINIMUM #CONNECT_TOPOLOGY_OPTION_MODIFIER = 25 #PERCENTAGE = 3 #PROBABILITY = .1 F2F = NO CONNECT_TIMEOUT = 60 s CONNECT_ATTEMPTS = 3 DEBUG = YES HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat MAX_CONCURRENT_SSH = 20 USE_PROGRESSBARS = YES PEERGROUP_TIMEOUT = 2400 s TOPOLOGY_OUTPUT_FILE = 2dtorus_topo_initial MAX_OUTSTANDING_CONNECTIONS = 75 #SINGLE_PEERINFO_PER_HOST = YES #NUM_PEERINFO_PER_HOST = 10 #SINGLE_STATISTICS_PER_HOST = YES #NUM_STATISTICS_PER_HOST = 10 DELETE_FILES = YES [test_dht_topo] CONNECTION_LIMIT = 20 #DATA_OUTPUT_FILE=data_output [nse] WORKDELAY = 500 ms INTERVAL = 60 s WORKBITS = 0 gnunet-0.9.3/src/dht/test_dht_tools.sh0000755000175000017500000000270211615607751014721 00000000000000#!/bin/sh out=`mktemp /tmp/test-gnunet-dht-logXXXXXXXX` tempcfg=`mktemp /tmp/test_dht_api_peer1.XXXXXXXX` checkout="check.out" armexe="gnunet-arm -c $tempcfg " putexe="gnunet-dht-put -c $tempcfg " getexe="gnunet-dht-get -c $tempcfg " peerinfo="gnunet-peerinfo -c $tempcfg -sq" stop_arm() { if ! $armexe $DEBUG -e -d > $out ; then echo "FAIL: error running $armexe" echo "Command output was:" cat $out rm -f $out $tempcfg exit 1 fi rm -f $out $tempcfg } cp test_dht_api_peer1.conf $tempcfg echo -n "TEST: Generating hostkey..." if ! $peerinfo > $out ; then echo "FAIL: error running $peerinfo" echo "Command output was:" cat $out exit 1 fi echo "PASS" echo -n "TEST: Starting ARM..." if ! $armexe $DEBUG -s > $out ; then echo "FAIL: error running $armexe" echo "Command output was:" cat $out stop_arm exit 1 fi echo "PASS" sleep 1 echo -n "TEST: Testing put..." if ! $putexe -k testkey -d testdata -t 8 > $out ; then echo "FAIL: error running $putexe" echo "Command output was:" cat $out stop_arm exit 1 fi echo "PASS" sleep 1 echo -n "TEST: Testing get..." echo "Result 0, type 8:" > $checkout echo "testdata" >> $checkout if ! $getexe -k testkey -T 5 -t 8 > $out ; then echo "FAIL: error running $putexe" echo "Command output was:" cat $out stop_arm exit 1 fi if ! diff --strip-trailing-cr -q $out $checkout ; then echo "FAIL: $out and $checkout differ" stop_arm exit 1 fi echo "PASS" stop_arm gnunet-0.9.3/src/dht/gnunet-dht-get.c0000644000175000017500000001431111760505033014310 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/gnunet-dht-get.c * @brief search for data in DHT * @author Christian Grothoff * @author Nathan Evans */ #include "platform.h" #include "gnunet_dht_service.h" /** * The type of the query */ static unsigned int query_type; /** * Desired replication level */ static unsigned int replication = 5; /** * The key for the query */ static char *query_key; /** * User supplied timeout value (in seconds) */ static unsigned long long timeout_request = 5; /** * When this request should really die */ struct GNUNET_TIME_Absolute absolute_timeout; /** * Be verbose */ static int verbose; /** * Handle to the DHT */ static struct GNUNET_DHT_Handle *dht_handle; /** * Global handle of the configuration */ static const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Handle for the get request */ static struct GNUNET_DHT_GetHandle *get_handle; /** * Count of results found */ static unsigned int result_count; /** * Global status value */ static int ret; static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (dht_handle != NULL) { GNUNET_DHT_disconnect (dht_handle); dht_handle = NULL; } } static void cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (get_handle != NULL) { GNUNET_DHT_get_stop (get_handle); get_handle = NULL; } GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); } /** * Iterator called on each result obtained for a DHT * operation that expects a reply * * @param cls closure * @param exp when will this value expire * @param key key of the result * @param get_path peers on reply path (or NULL if not recorded) * @param get_path_length number of entries in get_path * @param put_path peers on the PUT path (or NULL if not recorded) * @param put_path_length number of entries in get_path * @param type type of the result * @param size number of bytes in data * @param data pointer to the result data */ static void get_result_iterator (void *cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int put_path_length, enum GNUNET_BLOCK_Type type, size_t size, const void *data) { FPRINTF (stdout, "Result %d, type %d:\n%.*s\n", result_count, type, (unsigned int) size, (char *) data); result_count++; } /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param c configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { struct GNUNET_TIME_Relative timeout; GNUNET_HashCode key; cfg = c; if (query_key == NULL) { if (verbose) FPRINTF (stderr, "%s", "Must provide key for DHT GET!\n"); ret = 1; return; } dht_handle = GNUNET_DHT_connect (cfg, 1); if (dht_handle == NULL) { if (verbose) FPRINTF (stderr, "%s", "Couldn't connect to DHT service!\n"); ret = 1; return; } else if (verbose) FPRINTF (stderr, "%s", "Connected to DHT service!\n"); if (query_type == GNUNET_BLOCK_TYPE_ANY) /* Type of data not set */ query_type = GNUNET_BLOCK_TYPE_TEST; GNUNET_CRYPTO_hash (query_key, strlen (query_key), &key); timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, timeout_request); absolute_timeout = GNUNET_TIME_relative_to_absolute (timeout); if (verbose) FPRINTF (stderr, "Issuing GET request for %s!\n", query_key); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (absolute_timeout), &cleanup_task, NULL); get_handle = GNUNET_DHT_get_start (dht_handle, query_type, &key, replication, GNUNET_DHT_RO_NONE, NULL, 0, &get_result_iterator, NULL); } /** * gnunet-dht-get command line options */ static struct GNUNET_GETOPT_CommandLineOption options[] = { {'k', "key", "KEY", gettext_noop ("the query key"), 1, &GNUNET_GETOPT_set_string, &query_key}, {'r', "replication", "LEVEL", gettext_noop ("how many parallel requests (replicas) to create"), 1, &GNUNET_GETOPT_set_uint, &replication}, {'t', "type", "TYPE", gettext_noop ("the type of data to look for"), 1, &GNUNET_GETOPT_set_uint, &query_type}, {'T', "timeout", "TIMEOUT", gettext_noop ("how long to execute this query before giving up?"), 1, &GNUNET_GETOPT_set_ulong, &timeout_request}, {'V', "verbose", NULL, gettext_noop ("be verbose (print progress information)"), 0, &GNUNET_GETOPT_set_one, &verbose}, GNUNET_GETOPT_OPTION_END }; /** * Entry point for gnunet-dht-get * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-dht-get", gettext_noop ("Issue a GET request to the GNUnet DHT, prints results."), options, &run, NULL)) ? ret : 1; } /* end of gnunet-dht-get.c */ gnunet-0.9.3/src/dht/gnunet-service-dht.h0000644000175000017500000000314711760502551015205 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/gnunet-service-dht.h * @brief GNUnet DHT globals * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_DHT_H #define GNUNET_SERVICE_DHT_H #include "gnunet_util_lib.h" #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" #define DEBUG_DHT GNUNET_EXTRA_LOGGING /** * Configuration we use. */ extern const struct GNUNET_CONFIGURATION_Handle *GDS_cfg; /** * Our handle to the BLOCK library. */ extern struct GNUNET_BLOCK_Context *GDS_block_context; /** * Handle for the statistics service. */ extern struct GNUNET_STATISTICS_Handle *GDS_stats; /** * Our HELLO */ extern struct GNUNET_MessageHeader *GDS_my_hello; /** * Handle to the transport service, for getting our hello */ extern struct GNUNET_TRANSPORT_Handle *GDS_transport_handle; #endif gnunet-0.9.3/src/dht/gnunet-service-dht_clients.c0000644000175000017500000012714511760502551016726 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/gnunet-service-dht_clients.c * @brief GNUnet DHT service's client management code * @author Christian Grothoff * @author Nathan Evans */ #include "platform.h" #include "gnunet_constants.h" #include "gnunet_protocols.h" #include "gnunet_statistics_service.h" #include "gnunet-service-dht.h" #include "gnunet-service-dht_clients.h" #include "gnunet-service-dht_datacache.h" #include "gnunet-service-dht_neighbours.h" #include "dht.h" /** * Linked list of messages to send to clients. */ struct PendingMessage { /** * Pointer to next item in the list */ struct PendingMessage *next; /** * Pointer to previous item in the list */ struct PendingMessage *prev; /** * Actual message to be sent, allocated at the end of the struct: * // msg = (cast) &pm[1]; * // memcpy (&pm[1], data, len); */ const struct GNUNET_MessageHeader *msg; }; /** * Struct containing information about a client, * handle to connect to it, and any pending messages * that need to be sent to it. */ struct ClientList { /** * Linked list of active clients */ struct ClientList *next; /** * Linked list of active clients */ struct ClientList *prev; /** * The handle to this client */ struct GNUNET_SERVER_Client *client_handle; /** * Handle to the current transmission request, NULL * if none pending. */ struct GNUNET_SERVER_TransmitHandle *transmit_handle; /** * Linked list of pending messages for this client */ struct PendingMessage *pending_head; /** * Tail of linked list of pending messages for this client */ struct PendingMessage *pending_tail; }; /** * Entry in the DHT routing table for a client's GET request. */ struct ClientQueryRecord { /** * The key this request was about */ GNUNET_HashCode key; /** * Client responsible for the request. */ struct ClientList *client; /** * Extended query (see gnunet_block_lib.h), allocated at the end of this struct. */ const void *xquery; /** * Replies we have already seen for this request. */ GNUNET_HashCode *seen_replies; /** * Pointer to this nodes heap location in the retry-heap (for fast removal) */ struct GNUNET_CONTAINER_HeapNode *hnode; /** * What's the delay between re-try operations that we currently use for this * request? */ struct GNUNET_TIME_Relative retry_frequency; /** * What's the next time we should re-try this request? */ struct GNUNET_TIME_Absolute retry_time; /** * The unique identifier of this request */ uint64_t unique_id; /** * Number of bytes in xquery. */ size_t xquery_size; /** * Number of entries in 'seen_replies'. */ unsigned int seen_replies_count; /** * Desired replication level */ uint32_t replication; /** * Any message options for this request */ uint32_t msg_options; /** * The type for the data for the GET request. */ enum GNUNET_BLOCK_Type type; }; /** * Struct containing paremeters of monitoring requests. */ struct ClientMonitorRecord { /** * Next element in DLL. */ struct ClientMonitorRecord *next; /** * Previous element in DLL. */ struct ClientMonitorRecord *prev; /** * Type of blocks that are of interest */ enum GNUNET_BLOCK_Type type; /** * Key of data of interest, NULL for all. */ GNUNET_HashCode *key; /** * Flag whether to notify about GET messages. */ int16_t get; /** * Flag whether to notify about GET_REPONSE messages. */ int16_t get_resp; /** * Flag whether to notify about PUT messages. */ uint16_t put; /** * Client to notify of these requests. */ struct ClientList *client; }; /** * List of active clients. */ static struct ClientList *client_head; /** * List of active clients. */ static struct ClientList *client_tail; /** * List of active monitoring requests. */ static struct ClientMonitorRecord *monitor_head; /** * List of active monitoring requests. */ static struct ClientMonitorRecord *monitor_tail; /** * Hashmap for fast key based lookup, maps keys to 'struct ClientQueryRecord' entries. */ static struct GNUNET_CONTAINER_MultiHashMap *forward_map; /** * Heap with all of our client's request, sorted by retry time (earliest on top). */ static struct GNUNET_CONTAINER_Heap *retry_heap; /** * Task that re-transmits requests (using retry_heap). */ static GNUNET_SCHEDULER_TaskIdentifier retry_task; /** * Task run to check for messages that need to be sent to a client. * * @param client a ClientList, containing the client and any messages to be sent to it */ static void process_pending_messages (struct ClientList *client); /** * Add a PendingMessage to the clients list of messages to be sent * * @param client the active client to send the message to * @param pending_message the actual message to send */ static void add_pending_message (struct ClientList *client, struct PendingMessage *pending_message) { GNUNET_CONTAINER_DLL_insert_tail (client->pending_head, client->pending_tail, pending_message); process_pending_messages (client); } /** * Find a client if it exists, add it otherwise. * * @param client the server handle to the client * * @return the client if found, a new client otherwise */ static struct ClientList * find_active_client (struct GNUNET_SERVER_Client *client) { struct ClientList *pos = client_head; struct ClientList *ret; while (pos != NULL) { if (pos->client_handle == client) return pos; pos = pos->next; } ret = GNUNET_malloc (sizeof (struct ClientList)); ret->client_handle = client; GNUNET_CONTAINER_DLL_insert (client_head, client_tail, ret); return ret; } /** * Iterator over hash map entries that frees all entries * associated with the given client. * * @param cls client to search for in source routes * @param key current key code (ignored) * @param value value in the hash map, a ClientQueryRecord * @return GNUNET_YES (we should continue to iterate) */ static int remove_client_records (void *cls, const GNUNET_HashCode * key, void *value) { struct ClientList *client = cls; struct ClientQueryRecord *record = value; if (record->client != client) return GNUNET_YES; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing client %p's record for key %s\n", client, GNUNET_h2s (key)); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (forward_map, key, record)); if (NULL != record->hnode) GNUNET_CONTAINER_heap_remove_node (record->hnode); GNUNET_array_grow (record->seen_replies, record->seen_replies_count, 0); GNUNET_free (record); return GNUNET_YES; } /** * Functions with this signature are called whenever a client * is disconnected on the network level. * * @param cls closure (NULL for dht) * @param client identification of the client; NULL * for the last call when the server is destroyed */ static void handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) { struct ClientList *pos; struct PendingMessage *reply; struct ClientMonitorRecord *monitor; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Local client %p disconnects\n", client); pos = find_active_client (client); GNUNET_CONTAINER_DLL_remove (client_head, client_tail, pos); if (pos->transmit_handle != NULL) GNUNET_SERVER_notify_transmit_ready_cancel (pos->transmit_handle); while (NULL != (reply = pos->pending_head)) { GNUNET_CONTAINER_DLL_remove (pos->pending_head, pos->pending_tail, reply); GNUNET_free (reply); } monitor = monitor_head; while (NULL != monitor) { if (monitor->client == pos) { struct ClientMonitorRecord *next; GNUNET_free_non_null (monitor->key); next = monitor->next; GNUNET_CONTAINER_DLL_remove (monitor_head, monitor_tail, monitor); GNUNET_free (monitor); monitor = next; } else monitor = monitor->next; } GNUNET_CONTAINER_multihashmap_iterate (forward_map, &remove_client_records, pos); GNUNET_free (pos); } /** * Route the given request via the DHT. This includes updating * the bloom filter and retransmission times, building the P2P * message and initiating the routing operation. */ static void transmit_request (struct ClientQueryRecord *cqr) { int32_t reply_bf_mutator; struct GNUNET_CONTAINER_BloomFilter *reply_bf; struct GNUNET_CONTAINER_BloomFilter *peer_bf; GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# GET requests from clients injected"), 1, GNUNET_NO); reply_bf_mutator = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX); reply_bf = GNUNET_BLOCK_construct_bloomfilter (reply_bf_mutator, cqr->seen_replies, cqr->seen_replies_count); peer_bf = GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE, GNUNET_CONSTANTS_BLOOMFILTER_K); GDS_NEIGHBOURS_handle_get (cqr->type, cqr->msg_options, cqr->replication, 0 /* hop count */ , &cqr->key, cqr->xquery, cqr->xquery_size, reply_bf, reply_bf_mutator, peer_bf); GNUNET_CONTAINER_bloomfilter_free (reply_bf); GNUNET_CONTAINER_bloomfilter_free (peer_bf); /* exponential back-off for retries, max 1h */ cqr->retry_frequency = GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_HOURS, GNUNET_TIME_relative_multiply (cqr->retry_frequency, 2)); cqr->retry_time = GNUNET_TIME_relative_to_absolute (cqr->retry_frequency); } /** * Task that looks at the 'retry_heap' and transmits all of the requests * on the heap that are ready for transmission. Then re-schedules * itself (unless the heap is empty). * * @param cls unused * @param tc scheduler context */ static void transmit_next_request_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ClientQueryRecord *cqr; struct GNUNET_TIME_Relative delay; retry_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; while (NULL != (cqr = GNUNET_CONTAINER_heap_remove_root (retry_heap))) { cqr->hnode = NULL; delay = GNUNET_TIME_absolute_get_remaining (cqr->retry_time); if (delay.rel_value > 0) { cqr->hnode = GNUNET_CONTAINER_heap_insert (retry_heap, cqr, cqr->retry_time.abs_value); retry_task = GNUNET_SCHEDULER_add_delayed (delay, &transmit_next_request_task, NULL); return; } transmit_request (cqr); cqr->hnode = GNUNET_CONTAINER_heap_insert (retry_heap, cqr, cqr->retry_time.abs_value); } } /** * Handler for PUT messages. * * @param cls closure for the service * @param client the client we received this message from * @param message the actual message received */ static void handle_dht_local_put (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct GNUNET_DHT_ClientPutMessage *dht_msg; struct GNUNET_CONTAINER_BloomFilter *peer_bf; uint16_t size; struct PendingMessage *pm; struct GNUNET_DHT_ClientPutConfirmationMessage *conf; size = ntohs (message->size); if (size < sizeof (struct GNUNET_DHT_ClientPutMessage)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# PUT requests received from clients"), 1, GNUNET_NO); dht_msg = (const struct GNUNET_DHT_ClientPutMessage *) message; /* give to local clients */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Handling local PUT of %u-bytes for query %s\n", size - sizeof (struct GNUNET_DHT_ClientPutMessage), GNUNET_h2s (&dht_msg->key)); GDS_CLIENTS_handle_reply (GNUNET_TIME_absolute_ntoh (dht_msg->expiration), &dht_msg->key, 0, NULL, 0, NULL, ntohl (dht_msg->type), size - sizeof (struct GNUNET_DHT_ClientPutMessage), &dht_msg[1]); /* store locally */ GDS_DATACACHE_handle_put (GNUNET_TIME_absolute_ntoh (dht_msg->expiration), &dht_msg->key, 0, NULL, ntohl (dht_msg->type), size - sizeof (struct GNUNET_DHT_ClientPutMessage), &dht_msg[1]); /* route to other peers */ peer_bf = GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE, GNUNET_CONSTANTS_BLOOMFILTER_K); GDS_NEIGHBOURS_handle_put (ntohl (dht_msg->type), ntohl (dht_msg->options), ntohl (dht_msg->desired_replication_level), GNUNET_TIME_absolute_ntoh (dht_msg->expiration), 0 /* hop count */ , peer_bf, &dht_msg->key, 0, NULL, &dht_msg[1], size - sizeof (struct GNUNET_DHT_ClientPutMessage)); GDS_CLIENTS_process_put (ntohl (dht_msg->options), ntohl (dht_msg->type), 0, ntohl (dht_msg->desired_replication_level), 1, GDS_NEIGHBOURS_get_id(), GNUNET_TIME_absolute_ntoh (dht_msg->expiration), &dht_msg->key, &dht_msg[1], size - sizeof (struct GNUNET_DHT_ClientPutMessage)); GNUNET_CONTAINER_bloomfilter_free (peer_bf); pm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (struct GNUNET_DHT_ClientPutConfirmationMessage)); conf = (struct GNUNET_DHT_ClientPutConfirmationMessage *) &pm[1]; conf->header.size = htons (sizeof (struct GNUNET_DHT_ClientPutConfirmationMessage)); conf->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT_OK); conf->reserved = htonl (0); conf->unique_id = dht_msg->unique_id; pm->msg = &conf->header; add_pending_message (find_active_client (client), pm); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Handler for any generic DHT messages, calls the appropriate handler * depending on message type, sends confirmation if responses aren't otherwise * expected. * * @param cls closure for the service * @param client the client we received this message from * @param message the actual message received */ static void handle_dht_local_get (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct GNUNET_DHT_ClientGetMessage *get; struct ClientQueryRecord *cqr; size_t xquery_size; const char *xquery; uint16_t size; size = ntohs (message->size); if (size < sizeof (struct GNUNET_DHT_ClientGetMessage)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } xquery_size = size - sizeof (struct GNUNET_DHT_ClientGetMessage); get = (const struct GNUNET_DHT_ClientGetMessage *) message; xquery = (const char *) &get[1]; GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# GET requests received from clients"), 1, GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received request for %s from local client %p\n", GNUNET_h2s (&get->key), client); cqr = GNUNET_malloc (sizeof (struct ClientQueryRecord) + xquery_size); cqr->key = get->key; cqr->client = find_active_client (client); cqr->xquery = (void *) &cqr[1]; memcpy (&cqr[1], xquery, xquery_size); cqr->hnode = GNUNET_CONTAINER_heap_insert (retry_heap, cqr, 0); cqr->retry_frequency = GNUNET_TIME_UNIT_MILLISECONDS; cqr->retry_time = GNUNET_TIME_absolute_get (); cqr->unique_id = get->unique_id; cqr->xquery_size = xquery_size; cqr->replication = ntohl (get->desired_replication_level); cqr->msg_options = ntohl (get->options); cqr->type = ntohl (get->type); GNUNET_CONTAINER_multihashmap_put (forward_map, &get->key, cqr, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); GDS_CLIENTS_process_get (ntohl (get->options), ntohl (get->type), 0, ntohl (get->desired_replication_level), 1, GDS_NEIGHBOURS_get_id(), &get->key); /* start remote requests */ if (GNUNET_SCHEDULER_NO_TASK != retry_task) GNUNET_SCHEDULER_cancel (retry_task); retry_task = GNUNET_SCHEDULER_add_now (&transmit_next_request_task, NULL); /* perform local lookup */ GDS_DATACACHE_handle_get (&get->key, cqr->type, cqr->xquery, xquery_size, NULL, 0); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Closure for 'remove_by_unique_id'. */ struct RemoveByUniqueIdContext { /** * Client that issued the removal request. */ struct ClientList *client; /** * Unique ID of the request. */ uint64_t unique_id; }; /** * Iterator over hash map entries that frees all entries * that match the given client and unique ID. * * @param cls unique ID and client to search for in source routes * @param key current key code * @param value value in the hash map, a ClientQueryRecord * @return GNUNET_YES (we should continue to iterate) */ static int remove_by_unique_id (void *cls, const GNUNET_HashCode * key, void *value) { const struct RemoveByUniqueIdContext *ctx = cls; struct ClientQueryRecord *record = value; if (record->unique_id != ctx->unique_id) return GNUNET_YES; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing client %p's record for key %s (by unique id)\n", ctx->client->client_handle, GNUNET_h2s (key)); return remove_client_records (ctx->client, key, record); } /** * Handler for any generic DHT stop messages, calls the appropriate handler * depending on message type (if processed locally) * * @param cls closure for the service * @param client the client we received this message from * @param message the actual message received * */ static void handle_dht_local_get_stop (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct GNUNET_DHT_ClientGetStopMessage *dht_stop_msg = (const struct GNUNET_DHT_ClientGetStopMessage *) message; struct RemoveByUniqueIdContext ctx; GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# GET STOP requests received from clients"), 1, GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p stopped request for key %s\n", client, GNUNET_h2s (&dht_stop_msg->key)); ctx.client = find_active_client (client); ctx.unique_id = dht_stop_msg->unique_id; GNUNET_CONTAINER_multihashmap_get_multiple (forward_map, &dht_stop_msg->key, &remove_by_unique_id, &ctx); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Handler for monitor start messages * * @param cls closure for the service * @param client the client we received this message from * @param message the actual message received * */ static void handle_dht_local_monitor (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct ClientMonitorRecord *r; const struct GNUNET_DHT_MonitorStartStopMessage *msg; msg = (struct GNUNET_DHT_MonitorStartStopMessage *) message; r = GNUNET_malloc (sizeof(struct ClientMonitorRecord)); r->client = find_active_client(client); r->type = ntohl(msg->type); r->get = ntohs(msg->get); r->get_resp = ntohs(msg->get_resp); r->put = ntohs(msg->put); if (0 == ntohs(msg->filter_key)) r->key = NULL; else { r->key = GNUNET_malloc (sizeof (GNUNET_HashCode)); memcpy (r->key, &msg->key, sizeof (GNUNET_HashCode)); } GNUNET_CONTAINER_DLL_insert (monitor_head, monitor_tail, r); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Handler for monitor stop messages * * @param cls closure for the service * @param client the client we received this message from * @param message the actual message received * */ static void handle_dht_local_monitor_stop (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct ClientMonitorRecord *r; const struct GNUNET_DHT_MonitorStartStopMessage *msg; int keys_match; msg = (struct GNUNET_DHT_MonitorStartStopMessage *) message; r = monitor_head; while (NULL != r) { if (NULL == r->key) keys_match = (0 == ntohs(msg->filter_key)); else { keys_match = (0 != ntohs(msg->filter_key) && !memcmp(r->key, &msg->key, sizeof(GNUNET_HashCode))); } if (find_active_client(client) == r->client && ntohl(msg->type) == r->type && r->get == msg->get && r->get_resp == msg->get_resp && r->put == msg->put && keys_match ) { GNUNET_CONTAINER_DLL_remove (monitor_head, monitor_tail, r); GNUNET_free_non_null (r->key); GNUNET_free (r); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; /* Delete only ONE entry */ } r = r->next; } GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Callback called as a result of issuing a GNUNET_SERVER_notify_transmit_ready * request. A ClientList is passed as closure, take the head of the list * and copy it into buf, which has the result of sending the message to the * client. * * @param cls closure to this call * @param size maximum number of bytes available to send * @param buf where to copy the actual message to * * @return the number of bytes actually copied, 0 indicates failure */ static size_t send_reply_to_client (void *cls, size_t size, void *buf) { struct ClientList *client = cls; char *cbuf = buf; struct PendingMessage *reply; size_t off; size_t msize; client->transmit_handle = NULL; if (buf == NULL) { /* client disconnected */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected, pending messages will be discarded\n", client->client_handle); return 0; } off = 0; while ((NULL != (reply = client->pending_head)) && (size >= off + (msize = ntohs (reply->msg->size)))) { GNUNET_CONTAINER_DLL_remove (client->pending_head, client->pending_tail, reply); memcpy (&cbuf[off], reply->msg, msize); GNUNET_free (reply); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting %u bytes to client %p\n", msize, client->client_handle); off += msize; } process_pending_messages (client); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitted %u/%u bytes to client %p\n", (unsigned int) off, (unsigned int) size, client->client_handle); return off; } /** * Task run to check for messages that need to be sent to a client. * * @param client a ClientList, containing the client and any messages to be sent to it */ static void process_pending_messages (struct ClientList *client) { if ((client->pending_head == NULL) || (client->transmit_handle != NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not asking for transmission to %p now: %s\n", client->client_handle, client->pending_head == NULL ? "no more messages" : "request already pending"); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking for transmission of %u bytes to client %p\n", ntohs (client->pending_head->msg->size), client->client_handle); client->transmit_handle = GNUNET_SERVER_notify_transmit_ready (client->client_handle, ntohs (client->pending_head-> msg->size), GNUNET_TIME_UNIT_FOREVER_REL, &send_reply_to_client, client); } /** * Closure for 'forward_reply' */ struct ForwardReplyContext { /** * Actual message to send to matching clients. */ struct PendingMessage *pm; /** * Embedded payload. */ const void *data; /** * Type of the data. */ enum GNUNET_BLOCK_Type type; /** * Number of bytes in data. */ size_t data_size; /** * Do we need to copy 'pm' because it was already used? */ int do_copy; }; /** * Iterator over hash map entries that send a given reply to * each of the matching clients. With some tricky recycling * of the buffer. * * @param cls the 'struct ForwardReplyContext' * @param key current key * @param value value in the hash map, a ClientQueryRecord * @return GNUNET_YES (we should continue to iterate), * if the result is mal-formed, GNUNET_NO */ static int forward_reply (void *cls, const GNUNET_HashCode * key, void *value) { struct ForwardReplyContext *frc = cls; struct ClientQueryRecord *record = value; struct PendingMessage *pm; struct GNUNET_DHT_ClientResultMessage *reply; enum GNUNET_BLOCK_EvaluationResult eval; int do_free; GNUNET_HashCode ch; unsigned int i; if ((record->type != GNUNET_BLOCK_TYPE_ANY) && (record->type != frc->type)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record type missmatch, not passing request for key %s to local client\n", GNUNET_h2s (key)); GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Key match, type mismatches in REPLY to CLIENT"), 1, GNUNET_NO); return GNUNET_YES; /* type mismatch */ } GNUNET_CRYPTO_hash (frc->data, frc->data_size, &ch); for (i = 0; i < record->seen_replies_count; i++) if (0 == memcmp (&record->seen_replies[i], &ch, sizeof (GNUNET_HashCode))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Duplicate reply, not passing request for key %s to local client\n", GNUNET_h2s (key)); GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Duplicate REPLIES to CLIENT request dropped"), 1, GNUNET_NO); return GNUNET_YES; /* duplicate */ } eval = GNUNET_BLOCK_evaluate (GDS_block_context, record->type, key, NULL, 0, record->xquery, record->xquery_size, frc->data, frc->data_size); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Evaluation result is %d for key %s for local client's query\n", (int) eval, GNUNET_h2s (key)); switch (eval) { case GNUNET_BLOCK_EVALUATION_OK_LAST: do_free = GNUNET_YES; break; case GNUNET_BLOCK_EVALUATION_OK_MORE: GNUNET_array_append (record->seen_replies, record->seen_replies_count, ch); do_free = GNUNET_NO; break; case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE: /* should be impossible to encounter here */ GNUNET_break (0); return GNUNET_YES; case GNUNET_BLOCK_EVALUATION_RESULT_INVALID: GNUNET_break_op (0); return GNUNET_NO; case GNUNET_BLOCK_EVALUATION_REQUEST_VALID: GNUNET_break (0); return GNUNET_NO; case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID: GNUNET_break (0); return GNUNET_NO; case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED: GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Unsupported block type (%u) in request!\n"), record->type); return GNUNET_NO; default: GNUNET_break (0); return GNUNET_NO; } if (GNUNET_NO == frc->do_copy) { /* first time, we can use the original data */ pm = frc->pm; frc->do_copy = GNUNET_YES; } else { /* two clients waiting for same reply, must copy for queueing */ pm = GNUNET_malloc (sizeof (struct PendingMessage) + ntohs (frc->pm->msg->size)); memcpy (pm, frc->pm, sizeof (struct PendingMessage) + ntohs (frc->pm->msg->size)); pm->next = pm->prev = NULL; } GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# RESULTS queued for clients"), 1, GNUNET_NO); reply = (struct GNUNET_DHT_ClientResultMessage *) &pm[1]; reply->unique_id = record->unique_id; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Queueing reply to query %s for client %p\n", GNUNET_h2s (key), record->client->client_handle); add_pending_message (record->client, pm); if (GNUNET_YES == do_free) remove_client_records (record->client, key, record); return GNUNET_YES; } /** * Handle a reply we've received from another peer. If the reply * matches any of our pending queries, forward it to the respective * client(s). * * @param expiration when will the reply expire * @param key the query this reply is for * @param get_path_length number of peers in 'get_path' * @param get_path path the reply took on get * @param put_path_length number of peers in 'put_path' * @param put_path path the reply took on put * @param type type of the reply * @param data_size number of bytes in 'data' * @param data application payload data */ void GDS_CLIENTS_handle_reply (struct GNUNET_TIME_Absolute expiration, const GNUNET_HashCode * key, unsigned int get_path_length, const struct GNUNET_PeerIdentity *get_path, unsigned int put_path_length, const struct GNUNET_PeerIdentity *put_path, enum GNUNET_BLOCK_Type type, size_t data_size, const void *data) { struct ForwardReplyContext frc; struct PendingMessage *pm; struct GNUNET_DHT_ClientResultMessage *reply; struct GNUNET_PeerIdentity *paths; size_t msize; if (NULL == GNUNET_CONTAINER_multihashmap_get (forward_map, key)) { GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# REPLIES ignored for CLIENTS (no match)"), 1, GNUNET_NO); return; /* no matching request, fast exit! */ } msize = sizeof (struct GNUNET_DHT_ClientResultMessage) + data_size + (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity); if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Could not pass reply to client, message too big!\n")); return; } pm = (struct PendingMessage *) GNUNET_malloc (msize + sizeof (struct PendingMessage)); reply = (struct GNUNET_DHT_ClientResultMessage *) &pm[1]; pm->msg = &reply->header; reply->header.size = htons ((uint16_t) msize); reply->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_CLIENT_RESULT); reply->type = htonl (type); reply->get_path_length = htonl (get_path_length); reply->put_path_length = htonl (put_path_length); reply->unique_id = 0; /* filled in later */ reply->expiration = GNUNET_TIME_absolute_hton (expiration); reply->key = *key; paths = (struct GNUNET_PeerIdentity *) &reply[1]; memcpy (paths, put_path, sizeof (struct GNUNET_PeerIdentity) * put_path_length); memcpy (&paths[put_path_length], get_path, sizeof (struct GNUNET_PeerIdentity) * get_path_length); memcpy (&paths[get_path_length + put_path_length], data, data_size); frc.do_copy = GNUNET_NO; frc.pm = pm; frc.data = data; frc.data_size = data_size; frc.type = type; GNUNET_CONTAINER_multihashmap_get_multiple (forward_map, key, &forward_reply, &frc); if (GNUNET_NO == frc.do_copy) { /* did not match any of the requests, free! */ GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# REPLIES ignored for CLIENTS (no match)"), 1, GNUNET_NO); GNUNET_free (pm); } } /** * Check if some client is monitoring GET messages and notify * them in that case. * * @param options Options, for instance RecordRoute, DemultiplexEverywhere. * @param type The type of data in the request. * @param hop_count Hop count so far. * @param path_length number of entries in path (or 0 if not recorded). * @param path peers on the GET path (or NULL if not recorded). * @param desired_replication_level Desired replication level. * @param key Key of the requested data. */ void GDS_CLIENTS_process_get (uint32_t options, enum GNUNET_BLOCK_Type type, uint32_t hop_count, uint32_t desired_replication_level, unsigned int path_length, const struct GNUNET_PeerIdentity *path, const GNUNET_HashCode * key) { struct ClientMonitorRecord *m; struct ClientList **cl; unsigned int cl_size; cl = NULL; cl_size = 0; for (m = monitor_head; NULL != m; m = m->next) { if ((GNUNET_BLOCK_TYPE_ANY == m->type || m->type == type) && (NULL == m->key || memcmp (key, m->key, sizeof(GNUNET_HashCode)) == 0)) { struct PendingMessage *pm; struct GNUNET_DHT_MonitorGetMessage *mmsg; struct GNUNET_PeerIdentity *msg_path; size_t msize; unsigned int i; /* Don't send duplicates */ for (i = 0; i < cl_size; i++) if (cl[i] == m->client) break; if (i < cl_size) continue; GNUNET_array_append (cl, cl_size, m->client); msize = path_length * sizeof (struct GNUNET_PeerIdentity); msize += sizeof (struct GNUNET_DHT_MonitorGetMessage); msize += sizeof (struct PendingMessage); pm = (struct PendingMessage *) GNUNET_malloc (msize); mmsg = (struct GNUNET_DHT_MonitorGetMessage *) &pm[1]; pm->msg = &mmsg->header; mmsg->header.size = htons (msize - sizeof (struct PendingMessage)); mmsg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET); mmsg->options = htonl(options); mmsg->type = htonl(type); mmsg->hop_count = htonl(hop_count); mmsg->desired_replication_level = htonl(desired_replication_level); mmsg->get_path_length = htonl(path_length); memcpy (&mmsg->key, key, sizeof (GNUNET_HashCode)); msg_path = (struct GNUNET_PeerIdentity *) &mmsg[1]; if (path_length > 0) memcpy (msg_path, path, path_length * sizeof (struct GNUNET_PeerIdentity)); add_pending_message (m->client, pm); } } GNUNET_free_non_null (cl); } /** * Check if some client is monitoring GET RESP messages and notify * them in that case. * * @param type The type of data in the result. * @param get_path Peers on GET path (or NULL if not recorded). * @param get_path_length number of entries in get_path. * @param put_path peers on the PUT path (or NULL if not recorded). * @param put_path_length number of entries in get_path. * @param exp Expiration time of the data. * @param key Key of the data. * @param data Pointer to the result data. * @param size Number of bytes in data. */ void GDS_CLIENTS_process_get_resp (enum GNUNET_BLOCK_Type type, const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int put_path_length, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const void *data, size_t size) { struct ClientMonitorRecord *m; struct ClientList **cl; unsigned int cl_size; cl = NULL; cl_size = 0; for (m = monitor_head; NULL != m; m = m->next) { if ((GNUNET_BLOCK_TYPE_ANY == m->type || m->type == type) && (NULL == m->key || memcmp (key, m->key, sizeof(GNUNET_HashCode)) == 0)) { struct PendingMessage *pm; struct GNUNET_DHT_MonitorGetRespMessage *mmsg; struct GNUNET_PeerIdentity *path; size_t msize; unsigned int i; /* Don't send duplicates */ for (i = 0; i < cl_size; i++) if (cl[i] == m->client) break; if (i < cl_size) continue; GNUNET_array_append (cl, cl_size, m->client); msize = size; msize += (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity); msize += sizeof (struct GNUNET_DHT_MonitorGetRespMessage); msize += sizeof (struct PendingMessage); pm = (struct PendingMessage *) GNUNET_malloc (msize); mmsg = (struct GNUNET_DHT_MonitorGetRespMessage *) &pm[1]; pm->msg = (struct GNUNET_MessageHeader *) mmsg; mmsg->header.size = htons (msize - sizeof (struct PendingMessage)); mmsg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET_RESP); mmsg->type = htonl(type); mmsg->put_path_length = htonl(put_path_length); mmsg->get_path_length = htonl(get_path_length); path = (struct GNUNET_PeerIdentity *) &mmsg[1]; if (put_path_length > 0) { memcpy (path, put_path, put_path_length * sizeof (struct GNUNET_PeerIdentity)); path = &path[put_path_length]; } if (get_path_length > 0) memcpy (path, get_path, get_path_length * sizeof (struct GNUNET_PeerIdentity)); mmsg->expiration_time = GNUNET_TIME_absolute_hton(exp); memcpy (&mmsg->key, key, sizeof (GNUNET_HashCode)); if (size > 0) memcpy (&path[get_path_length], data, size); add_pending_message (m->client, pm); } } GNUNET_free_non_null (cl); } /** * Check if some client is monitoring PUT messages and notify * them in that case. * * @param options Options, for instance RecordRoute, DemultiplexEverywhere. * @param type The type of data in the request. * @param hop_count Hop count so far. * @param path_length number of entries in path (or 0 if not recorded). * @param path peers on the PUT path (or NULL if not recorded). * @param desired_replication_level Desired replication level. * @param exp Expiration time of the data. * @param key Key under which data is to be stored. * @param data Pointer to the data carried. * @param size Number of bytes in data. */ void GDS_CLIENTS_process_put (uint32_t options, enum GNUNET_BLOCK_Type type, uint32_t hop_count, uint32_t desired_replication_level, unsigned int path_length, const struct GNUNET_PeerIdentity *path, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const void *data, size_t size) { struct ClientMonitorRecord *m; struct ClientList **cl; unsigned int cl_size; cl = NULL; cl_size = 0; for (m = monitor_head; NULL != m; m = m->next) { if ((GNUNET_BLOCK_TYPE_ANY == m->type || m->type == type) && (NULL == m->key || memcmp (key, m->key, sizeof(GNUNET_HashCode)) == 0)) { struct PendingMessage *pm; struct GNUNET_DHT_MonitorPutMessage *mmsg; struct GNUNET_PeerIdentity *msg_path; size_t msize; unsigned int i; /* Don't send duplicates */ for (i = 0; i < cl_size; i++) if (cl[i] == m->client) break; if (i < cl_size) continue; GNUNET_array_append (cl, cl_size, m->client); msize = size; msize += path_length * sizeof (struct GNUNET_PeerIdentity); msize += sizeof (struct GNUNET_DHT_MonitorPutMessage); msize += sizeof (struct PendingMessage); pm = (struct PendingMessage *) GNUNET_malloc (msize); mmsg = (struct GNUNET_DHT_MonitorPutMessage *) &pm[1]; pm->msg = (struct GNUNET_MessageHeader *) mmsg; mmsg->header.size = htons (msize - sizeof (struct PendingMessage)); mmsg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT); mmsg->options = htonl(options); mmsg->type = htonl(type); mmsg->hop_count = htonl(hop_count); mmsg->desired_replication_level = htonl(desired_replication_level); mmsg->put_path_length = htonl(path_length); msg_path = (struct GNUNET_PeerIdentity *) &mmsg[1]; if (path_length > 0) { memcpy (msg_path, path, path_length * sizeof (struct GNUNET_PeerIdentity)); } mmsg->expiration_time = GNUNET_TIME_absolute_hton(exp); memcpy (&mmsg->key, key, sizeof (GNUNET_HashCode)); if (size > 0) memcpy (&msg_path[path_length], data, size); add_pending_message (m->client, pm); } } GNUNET_free_non_null (cl); } /** * Initialize client subsystem. * * @param server the initialized server */ void GDS_CLIENTS_init (struct GNUNET_SERVER_Handle *server) { static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = { {&handle_dht_local_put, NULL, GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT, 0}, {&handle_dht_local_get, NULL, GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET, 0}, {&handle_dht_local_get_stop, NULL, GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_STOP, sizeof (struct GNUNET_DHT_ClientGetStopMessage)}, {&handle_dht_local_monitor, NULL, GNUNET_MESSAGE_TYPE_DHT_MONITOR_START, sizeof (struct GNUNET_DHT_MonitorStartStopMessage)}, {&handle_dht_local_monitor_stop, NULL, GNUNET_MESSAGE_TYPE_DHT_MONITOR_STOP, sizeof (struct GNUNET_DHT_MonitorStartStopMessage)}, {NULL, NULL, 0, 0} }; forward_map = GNUNET_CONTAINER_multihashmap_create (1024); retry_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); GNUNET_SERVER_add_handlers (server, plugin_handlers); GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); } /** * Shutdown client subsystem. */ void GDS_CLIENTS_done () { GNUNET_assert (client_head == NULL); GNUNET_assert (client_tail == NULL); if (GNUNET_SCHEDULER_NO_TASK != retry_task) { GNUNET_SCHEDULER_cancel (retry_task); retry_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != retry_heap) { GNUNET_assert (0 == GNUNET_CONTAINER_heap_get_size (retry_heap)); GNUNET_CONTAINER_heap_destroy (retry_heap); retry_heap = NULL; } if (NULL != forward_map) { GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (forward_map)); GNUNET_CONTAINER_multihashmap_destroy (forward_map); forward_map = NULL; } } /* end of gnunet-service-dht_clients.c */ gnunet-0.9.3/src/dht/test_dht_monitor.c0000644000175000017500000005012011760505334015045 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/test_dht_monitor.c * * @brief Test for the dht service: store, retrieve and monitor in a line. * TODO: update this description * Each peer stores it own ID in the DHT and then a different peer tries to * retrieve that key from it. The GET starts after a first round of PUTS has * been made. Periodically, each peer stores its ID into the DHT. If after * a timeout no result has been returned, the test fails. */ #include "platform.h" #include "gnunet_testing_lib.h" #include "gnunet_dht_service.h" #define REMOVE_DIR GNUNET_YES /** * How long until we give up on connecting the peers? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500) #define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) #define PUT_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) static int ok; /** * Be verbose */ static int verbose; /** * Total number of peers in the test. */ static unsigned long long num_peers; /** * Global configuration file */ static struct GNUNET_CONFIGURATION_Handle *testing_cfg; /** * Total number of currently running peers. */ static unsigned long long peers_running; /** * Total number of connections in the whole network. */ static unsigned int total_connections; /** * The currently running peer group. */ static struct GNUNET_TESTING_PeerGroup *pg; /** * File to report results to. */ static struct GNUNET_DISK_FileHandle *output_file; /** * File to log connection info, statistics to. */ static struct GNUNET_DISK_FileHandle *data_file; /** * Task called to disconnect peers. */ static GNUNET_SCHEDULER_TaskIdentifier disconnect_task; /** * Task To perform tests */ static GNUNET_SCHEDULER_TaskIdentifier test_task; /** * Task to do DHT_puts */ static GNUNET_SCHEDULER_TaskIdentifier put_task; /** * Task called to shutdown test. */ static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle; static char *topology_file; struct GNUNET_TESTING_Daemon *d1; struct GNUNET_TESTING_Daemon *d2; struct GNUNET_DHT_Handle **hs; struct GNUNET_DHT_MonitorHandle **mhs; struct GNUNET_DHT_GetHandle *get_h_far; const char *id_origin = "FC74"; const char *id_far = "2UVH"; struct GNUNET_TESTING_Daemon *d_far; struct GNUNET_TESTING_Daemon *o; unsigned int monitor_counter; int in_test; /** * Check whether peers successfully shut down. */ static void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: Shutdown of peers failed: %s\n", emsg); ok++; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: All peers successfully shut down!\n"); } GNUNET_CONFIGURATION_destroy (testing_cfg); } static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Ending test.\n"); if (disconnect_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (disconnect_task); disconnect_task = GNUNET_SCHEDULER_NO_TASK; } if (data_file != NULL) GNUNET_DISK_file_close (data_file); GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); } static void disconnect_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { unsigned int i; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: disconnecting peers\n"); disconnect_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_SCHEDULER_cancel (put_task); if (NULL != get_h_far) GNUNET_DHT_get_stop (get_h_far); for (i = 0; i < num_peers; i++) { GNUNET_DHT_monitor_stop(mhs[i]); GNUNET_DHT_disconnect (hs[i]); } GNUNET_SCHEDULER_cancel (shutdown_handle); shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); } static void dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int put_path_length, enum GNUNET_BLOCK_Type type, size_t size, const void *data) { int i; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: ************* FOUND!!! ***********\n"); if (sizeof (GNUNET_HashCode) == size) { const GNUNET_HashCode *h = data; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Contents: %s\n", GNUNET_h2s_full (h)); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: PATH: (get %u, put %u)\n", get_path_length, put_path_length); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: LOCAL\n"); for (i = get_path_length - 1; i >= 0; i--) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: %s\n", GNUNET_i2s (&get_path[i])); } for (i = put_path_length - 1; i >= 0; i--) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: %s\n", GNUNET_i2s (&put_path[i])); } if (monitor_counter >= get_path_length + put_path_length) { ok = 0; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "expected at least %u hops, got %u\n", get_path_length + put_path_length, monitor_counter); } else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "expected at least %u hops, got %u\n", get_path_length + put_path_length, monitor_counter); GNUNET_SCHEDULER_cancel (disconnect_task); disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL); } /** * Start test: start GET request from the first node in the line looking for * the ID of the last node in the line. * * @param cls Closure (not used). * @param tc Task context. */ static void do_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) { return; } in_test = GNUNET_YES; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: test_task\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: looking for %s\n", GNUNET_h2s_full (&d_far->id.hashPubKey)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: from %s\n", GNUNET_h2s_full (&o->id.hashPubKey)); get_h_far = GNUNET_DHT_get_start (hs[0], GNUNET_BLOCK_TYPE_TEST, /* type */ &d_far->id.hashPubKey, /*key to search */ 4U, /* replication level */ GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, NULL, /* xquery */ 0, /* xquery bits */ &dht_get_id_handler, NULL); GNUNET_SCHEDULER_cancel (disconnect_task); disconnect_task = GNUNET_SCHEDULER_add_delayed (GET_TIMEOUT, &disconnect_peers, NULL); } /** * Periodic function used to put the ID of the far peer in the DHT. * * @param cls Closure (not used). * @param tc Task context. */ static void put_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TESTING_Daemon *d; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) { put_task = GNUNET_SCHEDULER_NO_TASK; return; } d = GNUNET_TESTING_daemon_get (pg, 4); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: putting into DHT: %s\n", GNUNET_h2s_full (&d->id.hashPubKey)); GNUNET_DHT_put (hs[4], &d->id.hashPubKey, 10U, GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, GNUNET_BLOCK_TYPE_TEST, sizeof (struct GNUNET_PeerIdentity), (const char *) &d->id, GNUNET_TIME_UNIT_FOREVER_ABS, GNUNET_TIME_UNIT_FOREVER_REL, NULL, NULL); put_task = GNUNET_SCHEDULER_add_delayed (PUT_FREQUENCY, &put_id, NULL); } /** * Callback called on each GET request going through the DHT. * Prints the info about the intercepted packet and increments a counter. * * @param cls Closure. * @param options Options, for instance RecordRoute, DemultiplexEverywhere. * @param type The type of data in the request. * @param hop_count Hop count so far. * @param path_length number of entries in path (or 0 if not recorded). * @param path peers on the GET path (or NULL if not recorded). * @param desired_replication_level Desired replication level. * @param key Key of the requested data. */ void monitor_get_cb (void *cls, enum GNUNET_DHT_RouteOption options, enum GNUNET_BLOCK_Type type, uint32_t hop_count, uint32_t desired_replication_level, unsigned int path_length, const struct GNUNET_PeerIdentity *path, const GNUNET_HashCode * key) { const char *s_key; unsigned int i; i = (unsigned int) (long) cls; s_key = GNUNET_h2s(key); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u got a GET message for key %s\n", i, s_key); if (strncmp (s_key, id_far, 4) == 0 && in_test == GNUNET_YES) monitor_counter++; } /** * Callback called on each PUT request going through the DHT. * Prints the info about the intercepted packet and increments a counter. * * @param cls Closure. * @param options Options, for instance RecordRoute, DemultiplexEverywhere. * @param type The type of data in the request. * @param hop_count Hop count so far. * @param path_length number of entries in path (or 0 if not recorded). * @param path peers on the PUT path (or NULL if not recorded). * @param desired_replication_level Desired replication level. * @param exp Expiration time of the data. * @param key Key under which data is to be stored. * @param data Pointer to the data carried. * @param size Number of bytes in data. */ void monitor_put_cb (void *cls, enum GNUNET_DHT_RouteOption options, enum GNUNET_BLOCK_Type type, uint32_t hop_count, uint32_t desired_replication_level, unsigned int path_length, const struct GNUNET_PeerIdentity *path, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const void *data, size_t size) { const char *s_key; unsigned int i; i = (unsigned int) (long) cls; s_key = GNUNET_h2s(key); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u got a PUT message for key %s with %u bytes\n", i, s_key, size); if (strncmp (s_key, id_far, 4) == 0 && in_test == GNUNET_YES) monitor_counter++; } /** * Callback called on each GET reply going through the DHT. * Prints the info about the intercepted packet and increments a counter. * * @param cls Closure. * @param type The type of data in the result. * @param get_path Peers on GET path (or NULL if not recorded). * @param get_path_length number of entries in get_path. * @param put_path peers on the PUT path (or NULL if not recorded). * @param put_path_length number of entries in get_path. * @param exp Expiration time of the data. * @param key Key of the data. * @param data Pointer to the result data. * @param size Number of bytes in data. */ void monitor_res_cb (void *cls, enum GNUNET_BLOCK_Type type, const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int put_path_length, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const void *data, size_t size) { const char *s_key; unsigned int i; i = (unsigned int) (long) cls; s_key = GNUNET_h2s(key); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u got a REPLY message for key %s with %u bytes\n", i, s_key, size); if (strncmp (s_key, id_far, 4) == 0 && in_test == GNUNET_YES) monitor_counter++; } /** * peergroup_ready: start test when all peers are connected * * @param cls closure * @param emsg error message */ static void peergroup_ready (void *cls, const char *emsg) { struct GNUNET_TESTING_Daemon *d; char *buf; int buf_len; unsigned int i; if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Peergroup callback called with error, aborting test!\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Error from testing: `%s'\n", emsg); ok++; GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Peer Group started successfully with %u connections\n", total_connections); if (data_file != NULL) { buf = NULL; buf_len = GNUNET_asprintf (&buf, "CONNECTIONS_0: %u\n", total_connections); if (buf_len > 0) GNUNET_DISK_file_write (data_file, buf, buf_len); GNUNET_free (buf); } peers_running = GNUNET_TESTING_daemons_running (pg); GNUNET_assert (peers_running == num_peers); hs = GNUNET_malloc (num_peers * sizeof (struct GNUNET_DHT_Handle *)); mhs = GNUNET_malloc (num_peers * sizeof (struct GNUNET_DHT_MonitorHandle *)); d_far = o = NULL; o = GNUNET_TESTING_daemon_get (pg, 0); d_far = GNUNET_TESTING_daemon_get (pg, 4); for (i = 0; i < num_peers; i++) { d = GNUNET_TESTING_daemon_get (pg, i); hs[i] = GNUNET_DHT_connect (d->cfg, 32); mhs[i] = GNUNET_DHT_monitor_start(hs[i], GNUNET_BLOCK_TYPE_ANY, NULL, &monitor_get_cb, &monitor_res_cb, &monitor_put_cb, (void *)(long)i); } if ((NULL == o) || (NULL == d_far)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: Error getting daemons from pg\n"); GNUNET_SCHEDULER_cancel (disconnect_task); disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL); return; } monitor_counter = 0; put_task = GNUNET_SCHEDULER_add_now (&put_id, NULL); test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2), &do_test, NULL); disconnect_task = GNUNET_SCHEDULER_add_delayed (GET_TIMEOUT, &disconnect_peers, NULL); } /** * Function that will be called whenever two daemons are connected by * the testing library. * * @param cls closure * @param first peer id for first daemon * @param second peer id for the second daemon * @param distance distance between the connected peers * @param first_cfg config for the first daemon * @param second_cfg config for the second daemon * @param first_daemon handle for the first daemon * @param second_daemon handle for the second daemon * @param emsg error message (NULL on success) */ static void connect_cb (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, uint32_t distance, const struct GNUNET_CONFIGURATION_Handle *first_cfg, const struct GNUNET_CONFIGURATION_Handle *second_cfg, struct GNUNET_TESTING_Daemon *first_daemon, struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) { if (emsg == NULL) { total_connections++; GNUNET_PEER_intern (first); GNUNET_PEER_intern (second); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Problem with new connection (%s)\n", emsg); } } /** * run: load configuration options and schedule test to run (start peergroup) * @param cls closure * @param args argv * @param cfgfile configuration file name (can be NULL) * @param cfg configuration handle */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { char *temp_str; struct GNUNET_TESTING_Host *hosts; char *data_filename; ok = 1; testing_cfg = GNUNET_CONFIGURATION_dup (cfg); GNUNET_log_setup ("test_dht_monitor", "WARNING", NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Starting daemons.\n"); GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", "use_progressbars", "YES"); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing", "num_peers", &num_peers)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Option TESTING:NUM_PEERS is required!\n"); return; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (testing_cfg, "testing", "topology_output_file", &topology_file)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Option test_dht_monitor:topology_output_file is required!\n"); return; } if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (testing_cfg, "test_dht_topo", "data_output_file", &data_filename)) { data_file = GNUNET_DISK_file_open (data_filename, GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_CREATE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (data_file == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n", data_filename); GNUNET_free (data_filename); } } if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "test_dht_topo", "output_file", &temp_str)) { output_file = GNUNET_DISK_file_open (temp_str, GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_CREATE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (output_file == NULL) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n", temp_str); } GNUNET_free_non_null (temp_str); hosts = GNUNET_TESTING_hosts_load (testing_cfg); pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT, &connect_cb, &peergroup_ready, NULL, hosts); GNUNET_assert (pg != NULL); shutdown_handle = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); } /** * test_dht_monitor command line options */ static struct GNUNET_GETOPT_CommandLineOption options[] = { {'V', "verbose", NULL, gettext_noop ("be verbose (print progress information)"), 0, &GNUNET_GETOPT_set_one, &verbose}, GNUNET_GETOPT_OPTION_END }; /** * Main: start test */ int main (int xargc, char *xargv[]) { char *const argv[] = { "test-dht-monitor", "-c", "test_dht_line.conf", NULL }; in_test = GNUNET_NO; GNUNET_PROGRAM_run (sizeof (argv) / sizeof (char *) - 1, argv, "test_dht_monitor", gettext_noop ("Test dht monitoring in a line."), options, &run, NULL); #if REMOVE_DIR GNUNET_DISK_directory_remove ("/tmp/test_dht_monitor"); #endif if (0 != ok) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: FAILED!\n"); } return ok; } /* end of test_dht_monitor.c */ gnunet-0.9.3/src/dht/gnunet-service-dht_nse.c0000644000175000017500000000516511760502551016047 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/gnunet-service-dht_nse.c * @brief GNUnet DHT integration with NSE * @author Christian Grothoff */ #include "platform.h" #include "gnunet_nse_service.h" #include "gnunet-service-dht.h" #include "gnunet-service-dht_nse.h" /** * log of the current network size estimate, used as the point where * we switch between random and deterministic routing. Default * value of 4.0 is used if NSE module is not available (i.e. not * configured). */ static double log_of_network_size_estimate = 4.0; /** * Network size estimation handle. */ static struct GNUNET_NSE_Handle *nse; /** * Callback that is called when network size estimate is updated. * * @param cls closure * @param timestamp time when the estimate was received from the server (or created by the server) * @param logestimate the log(Base 2) value of the current network size estimate * @param std_dev standard deviation for the estimate * */ static void update_network_size_estimate (void *cls, struct GNUNET_TIME_Absolute timestamp, double logestimate, double std_dev) { GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Network size estimates received"), 1, GNUNET_NO); /* do not allow estimates < 0.5 */ log_of_network_size_estimate = GNUNET_MAX (0.5, logestimate); } /** * Return the log of the current network size estimate. * * @return log of NSE */ double GDS_NSE_get () { return log_of_network_size_estimate; } /** * Initialize NSE subsystem. */ void GDS_NSE_init () { nse = GNUNET_NSE_connect (GDS_cfg, &update_network_size_estimate, NULL); } /** * Shutdown NSE subsystem. */ void GDS_NSE_done () { if (NULL != nse) { GNUNET_NSE_disconnect (nse); nse = NULL; } } /* end of gnunet-service-dht_nse.c */ gnunet-0.9.3/src/dht/test_dht_twopeer_path_tracking.c0000644000175000017500000004033611760505404017747 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/test_dht_twopeer_path_tracking.c * @brief testcase for testing DHT service with * two running peers, logging the path of the dht requests. */ #include "platform.h" #include "gnunet_testing_lib.h" #include "gnunet_core_service.h" #include "gnunet_dht_service.h" /* DEFINES */ #define VERBOSE GNUNET_NO /* Timeout for entire testcase */ #define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5) /* Timeout for waiting for replies to get requests */ #define GET_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30) /* If number of peers not in config file, use this number */ #define DEFAULT_NUM_PEERS 2 /* Globals */ /** * Directory to store temp data in, defined in config file */ static char *test_directory; /** * Variable used to store the number of connections we should wait for. */ static unsigned int expected_connections; /** * Variable used to keep track of how many peers aren't yet started. */ static unsigned long long peers_left; /** * Handle to the set of all peers run for this test. */ static struct GNUNET_TESTING_PeerGroup *pg; /** * Global handle we will use for GET requests. */ struct GNUNET_DHT_GetHandle *global_get_handle; /** * Total number of peers to run, set based on config file. */ static unsigned long long num_peers; /** * Global used to count how many connections we have currently * been notified about (how many times has topology_callback been called * with success?) */ static unsigned int total_connections; /** * Global used to count how many failed connections we have * been notified about (how many times has topology_callback * been called with failure?) */ static unsigned int failed_connections; /** * Task handle to use to schedule test failure */ GNUNET_SCHEDULER_TaskIdentifier die_task; /** * Global return value (0 for success, anything else for failure) */ static int ok; /** * Peer identity of the first peer started. */ static struct GNUNET_PeerIdentity peer1id; /** * Peer identity of the second peer started. */ static struct GNUNET_PeerIdentity peer2id; /** * Handle to the first peers DHT service (via the API) */ static struct GNUNET_DHT_Handle *peer1dht; /** * Handle to the second peers DHT service (via the API) */ static struct GNUNET_DHT_Handle *peer2dht; /** * Check whether peers successfully shut down. */ void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { if (ok == 0) ok = 2; } } /** * Function scheduled to be run on the successful completion of this * testcase. Specifically, called when our get request completes. */ static void finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_assert (pg != NULL); GNUNET_assert (peer1dht != NULL); GNUNET_assert (peer2dht != NULL); GNUNET_DHT_disconnect (peer1dht); GNUNET_DHT_disconnect (peer2dht); GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); ok = 0; } /** * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut * down the peers without freeing memory associated with GET request. */ static void end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (peer1dht != NULL) GNUNET_DHT_disconnect (peer1dht); if (peer2dht != NULL) GNUNET_DHT_disconnect (peer2dht); if (pg != NULL) GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); } /** * Check if the get_handle is being used, if so stop the request. Either * way, schedule the end_badly_cont function which actually shuts down the * test. */ static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failing test with error: `%s'!\n", (char *) cls); if (global_get_handle != NULL) { GNUNET_DHT_get_stop (global_get_handle); global_get_handle = NULL; } GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL); ok = 1; } /** * Iterator called if the GET request initiated returns a response. * * @param cls closure * @param exp when will this value expire * @param key key of the result * @param type type of the result * @param size number of bytes in data * @param data pointer to the result data */ static void get_result_iterator (void *cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int put_path_length, enum GNUNET_BLOCK_Type type, size_t size, const void *data) { GNUNET_HashCode original_key; /* Key data was stored data under */ char original_data[4]; /* Made up data that was stored */ memset (&original_key, 42, sizeof (GNUNET_HashCode)); /* Set the key to what it was set to previously */ memset (original_data, 43, sizeof (original_data)); #if VERBOSE unsigned int i; #endif if ((0 != memcmp (&original_key, key, sizeof (GNUNET_HashCode))) || (0 != memcmp (original_data, data, sizeof (original_data)))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Key or data is not the same as was inserted!\n"); GNUNET_SCHEDULER_cancel (die_task); GNUNET_SCHEDULER_add_now (&end_badly, "key or data mismatch in get response!\n"); return; } #if VERBOSE if (put_path != NULL) { FPRINTF (stderr, "%s", "PUT Path: "); for (i = 0; i < put_path_length; i++) FPRINTF (stderr, "%s%s", i == 0 ? "" : "->", GNUNET_i2s (&put_path[i])); FPRINTF (stderr, "%s", "\n"); } if (get_path != NULL) { FPRINTF (stderr, "%s", "GET Path: "); for (i = 0; i < get_path_length; i++) FPRINTF (stderr, "%s%s", i == 0 ? "" : "->", GNUNET_i2s (&get_path[i])); FPRINTF (stderr, "%s", "\n"); } #endif GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct GET response!\n"); GNUNET_SCHEDULER_cancel (die_task); GNUNET_DHT_get_stop (global_get_handle); GNUNET_SCHEDULER_add_now (&finish_testing, NULL); } /** * Called when the PUT request has been transmitted to the DHT service. * Schedule the GET request for some time in the future. */ static void put_finished (void *cls, int success) { GNUNET_HashCode key; /* Key for data lookup */ GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_delayed (GET_TIMEOUT, &end_badly, "waiting for get response (data not found)"); memset (&key, 42, sizeof (GNUNET_HashCode)); /* Set the key to the same thing as when data was inserted */ global_get_handle = GNUNET_DHT_get_start (peer2dht, GNUNET_BLOCK_TYPE_TEST, &key, 1, GNUNET_DHT_RO_RECORD_ROUTE, NULL, 0, &get_result_iterator, NULL); } /** * Set up some data, and call API PUT function */ static void do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_HashCode key; /* Made up key to store data under */ char data[4]; /* Made up data to store */ memset (&key, 42, sizeof (GNUNET_HashCode)); /* Set the key to something simple so we can issue GET request */ memset (data, 43, sizeof (data)); /* Insert the data at the first peer */ GNUNET_DHT_put (peer1dht, &key, 1, GNUNET_DHT_RO_RECORD_ROUTE, GNUNET_BLOCK_TYPE_TEST, sizeof (data), data, GNUNET_TIME_UNIT_FOREVER_ABS, GNUNET_TIME_UNIT_FOREVER_REL, &put_finished, NULL); } /** * This function is called whenever a connection attempt is finished between two of * the started peers (started with GNUNET_TESTING_daemons_start). The total * number of times this function is called should equal the number returned * from the GNUNET_TESTING_connect_topology call. * * The emsg variable is NULL on success (peers connected), and non-NULL on * failure (peers failed to connect). */ static void topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, uint32_t distance, const struct GNUNET_CONFIGURATION_Handle *first_cfg, const struct GNUNET_CONFIGURATION_Handle *second_cfg, struct GNUNET_TESTING_Daemon *first_daemon, struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) { if (emsg == NULL) { total_connections++; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s, distance %u\n", first_daemon->shortname, second_daemon->shortname, distance); #endif } #if VERBOSE else { failed_connections++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect peer %s to peer %s with error :\n%s\n", first_daemon->shortname, second_daemon->shortname, emsg); } #endif if (total_connections == expected_connections) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created %d total connections, which is our target number! Starting next phase of testing.\n", total_connections); #endif GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "from test gets"); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2), &do_put, NULL); } else if (total_connections + failed_connections == expected_connections) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from topology_callback (too many failed connections)"); } } /** * Callback which is called whenever a peer is started (as a result of the * GNUNET_TESTING_daemons_start call. * * @param cls closure argument given to GNUNET_TESTING_daemons_start * @param id the GNUNET_PeerIdentity of the started peer * @param cfg the configuration for this specific peer (needed to connect * to the DHT) * @param d the handle to the daemon started * @param emsg NULL if peer started, non-NULL on error */ static void peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to start daemon with error: `%s'\n", emsg); return; } GNUNET_assert (id != NULL); /* This is the first peer started */ if (peers_left == num_peers) { memcpy (&peer1id, id, sizeof (struct GNUNET_PeerIdentity)); /* Save the peer id */ peer1dht = GNUNET_DHT_connect (cfg, 100); /* Connect to the first peers DHT service */ if (peer1dht == NULL) /* If DHT connect failed */ { GNUNET_SCHEDULER_cancel (die_task); GNUNET_SCHEDULER_add_now (&end_badly, "Failed to get dht handle!\n"); } } else /* This is the second peer started */ { memcpy (&peer2id, id, sizeof (struct GNUNET_PeerIdentity)); /* Same as for first peer... */ peer2dht = GNUNET_DHT_connect (cfg, 100); if (peer2dht == NULL) { GNUNET_SCHEDULER_cancel (die_task); GNUNET_SCHEDULER_add_now (&end_badly, "Failed to get dht handle!\n"); } } /* Decrement number of peers left to start */ peers_left--; if (peers_left == 0) /* Indicates all peers started */ { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All %d daemons started, now connecting peers!\n", num_peers); #endif expected_connections = -1; if ((pg != NULL)) /* Sanity check */ { /* Connect peers in a "straight line" topology, return the number of expected connections */ expected_connections = GNUNET_TESTING_connect_topology (pg, GNUNET_TESTING_TOPOLOGY_LINE, GNUNET_TESTING_TOPOLOGY_OPTION_ALL, 0.0, TIMEOUT, 2, NULL, NULL); } /* Cancel current timeout fail task */ GNUNET_SCHEDULER_cancel (die_task); if (expected_connections == GNUNET_SYSERR) /* Some error happened */ die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from connect topology (bad return)"); /* Schedule timeout on failure task */ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "from connect topology (timeout)"); ok = 0; } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { /* Get path from configuration file */ if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", &test_directory)) { ok = 404; return; } /* Get number of peers to start from configuration (should be two) */ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", &num_peers)) num_peers = DEFAULT_NUM_PEERS; /* Set peers_left so we know when all peers started */ peers_left = num_peers; /* Set up a task to end testing if peer start fails */ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "didn't start all daemons in reasonable amount of time!!!"); /* Start num_peers peers, call peers_started_callback on peer start, topology_callback on peer connect */ /* Read the API documentation for other parameters! */ pg = GNUNET_TESTING_daemons_start (cfg, peers_left, /* Total number of peers */ peers_left, /* Number of outstanding connections */ peers_left, /* Number of parallel ssh connections, or peers being started at once */ TIMEOUT, NULL, NULL, &peers_started_callback, NULL, &topology_callback, NULL, NULL); } static int check () { int ret; /* Arguments for GNUNET_PROGRAM_run */ char *const argv[] = { "test-dht-twopeer-put-get", /* Name to give running binary */ "-c", "test_dht_twopeer_data.conf", /* Config file to use */ #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; /* Run the run function as a new program */ ret = GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-dht-twopeer-put-get", "nohelp", options, &run, &ok); if (ret != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "`test-dht-twopeer': Failed with error code %d\n", ret); } return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-dht-twopeer", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); /** * Need to remove base directory, subdirectories taken care * of by the testing framework. */ if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to remove testing directory %s\n", test_directory); } return ret; } /* end of test_dht_twopeer_put_get.c */ gnunet-0.9.3/src/dht/gnunet-dht-put.c0000644000175000017500000001367211760502551014354 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/gnunet-dht-put.c * @brief search for data in DHT * @author Christian Grothoff * @author Nathan Evans */ #include "platform.h" #include "gnunet_dht_service.h" /** * The type of the query */ static unsigned int query_type; /** * The key for the query */ static char *query_key; /** * User supplied timeout value */ static unsigned long long timeout_request = 5; /** * User supplied expiration value */ static unsigned long long expiration_seconds = 3600; /** * Desired replication level. */ static unsigned int replication = 5; /** * Be verbose */ static int verbose; /** * Handle to the DHT */ static struct GNUNET_DHT_Handle *dht_handle; /** * Global handle of the configuration */ static const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Global status value */ static int ret; /** * The data to insert into the dht */ static char *data; static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (NULL != dht_handle) { GNUNET_DHT_disconnect (dht_handle); dht_handle = NULL; } } /** * Signature of the main function of a task. * * @param cls closure * @param success GNUNET_OK if the PUT was transmitted, * GNUNET_NO on timeout, * GNUNET_SYSERR on disconnect from service * after the PUT message was transmitted * (so we don't know if it was received or not) */ static void message_sent_cont (void *cls, int success) { if (verbose) { switch (success) { case GNUNET_OK: FPRINTF (stderr, "%s", _("PUT request sent!\n")); break; case GNUNET_NO: FPRINTF (stderr, "%s", _("Timeout sending PUT request!\n")); break; case GNUNET_SYSERR: FPRINTF (stderr, "%s", _("PUT request not confirmed!\n")); break; default: GNUNET_break (0); break; } } GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); } /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param c configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { struct GNUNET_TIME_Relative timeout; struct GNUNET_TIME_Absolute expiration; GNUNET_HashCode key; cfg = c; if ((query_key == NULL) || (data == NULL)) { FPRINTF (stderr, "%s", _("Must provide KEY and DATA for DHT put!\n")); ret = 1; return; } dht_handle = GNUNET_DHT_connect (cfg, 1); if (dht_handle == NULL) { FPRINTF (stderr, _("Could not connect to %s service!\n"), "DHT"); ret = 1; return; } else if (verbose) FPRINTF (stderr, _("Connected to %s service!\n"), "DHT"); if (query_type == GNUNET_BLOCK_TYPE_ANY) /* Type of data not set */ query_type = GNUNET_BLOCK_TYPE_TEST; GNUNET_CRYPTO_hash (query_key, strlen (query_key), &key); timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, timeout_request); expiration = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, expiration_seconds)); if (verbose) FPRINTF (stderr, _("Issuing put request for `%s' with data `%s'!\n"), query_key, data); GNUNET_DHT_put (dht_handle, &key, replication, GNUNET_DHT_RO_NONE, query_type, strlen (data), data, expiration, timeout, &message_sent_cont, NULL); } /** * gnunet-dht-put command line options */ static struct GNUNET_GETOPT_CommandLineOption options[] = { {'d', "data", "DATA", gettext_noop ("the data to insert under the key"), 1, &GNUNET_GETOPT_set_string, &data}, {'e', "expiration", "EXPIRATION", gettext_noop ("how long to store this entry in the dht (in seconds)"), 1, &GNUNET_GETOPT_set_ulong, &expiration_seconds}, {'k', "key", "KEY", gettext_noop ("the query key"), 1, &GNUNET_GETOPT_set_string, &query_key}, {'r', "replication", "LEVEL", gettext_noop ("how many replicas to create"), 1, &GNUNET_GETOPT_set_uint, &replication}, {'t', "type", "TYPE", gettext_noop ("the type to insert data as"), 1, &GNUNET_GETOPT_set_uint, &query_type}, {'T', "timeout", "TIMEOUT", gettext_noop ("how long to execute this query before giving up?"), 1, &GNUNET_GETOPT_set_ulong, &timeout_request}, {'V', "verbose", NULL, gettext_noop ("be verbose (print progress information)"), 0, &GNUNET_GETOPT_set_one, &verbose}, GNUNET_GETOPT_OPTION_END }; /** * Entry point for gnunet-dht-put * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-dht-put", gettext_noop ("Issue a PUT request to the GNUnet DHT insert DATA under KEY."), options, &run, NULL)) ? ret : 1; } /* end of gnunet-dht-put.c */ gnunet-0.9.3/src/dht/gnunet-service-dht_routing.c0000644000175000017500000002644411760502551016754 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/gnunet-service-dht_routing.c * @brief GNUnet DHT tracking of requests for routing replies * @author Christian Grothoff */ #include "platform.h" #include "gnunet-service-dht_neighbours.h" #include "gnunet-service-dht_routing.h" #include "gnunet-service-dht.h" /** * Number of requests we track at most (for routing replies). */ #define DHT_MAX_RECENT (1024 * 16) /** * Information we keep about all recent GET requests * so that we can route replies. */ struct RecentRequest { /** * The peer this request was received from. */ struct GNUNET_PeerIdentity peer; /** * Key of this request. */ GNUNET_HashCode key; /** * Position of this node in the min heap. */ struct GNUNET_CONTAINER_HeapNode *heap_node; /** * Bloomfilter for replies to drop. */ struct GNUNET_CONTAINER_BloomFilter *reply_bf; /** * Type of the requested block. */ enum GNUNET_BLOCK_Type type; /** * extended query (see gnunet_block_lib.h). Allocated at the * end of this struct. */ const void *xquery; /** * Number of bytes in xquery. */ size_t xquery_size; /** * Mutator value for the reply_bf, see gnunet_block_lib.h */ uint32_t reply_bf_mutator; /** * Request options. */ enum GNUNET_DHT_RouteOption options; }; /** * Recent requests by time inserted. */ static struct GNUNET_CONTAINER_Heap *recent_heap; /** * Recently seen requests by key. */ static struct GNUNET_CONTAINER_MultiHashMap *recent_map; /** * Closure for the 'process' function. */ struct ProcessContext { /** * Path of the original PUT */ const struct GNUNET_PeerIdentity *put_path; /** * Path of the reply. */ const struct GNUNET_PeerIdentity *get_path; /** * Payload of the reply. */ const void *data; /** * Expiration time of the result. */ struct GNUNET_TIME_Absolute expiration_time; /** * Number of entries in 'put_path'. */ unsigned int put_path_length; /** * Number of entries in 'get_path'. */ unsigned int get_path_length; /** * Number of bytes in 'data'. */ size_t data_size; /** * Type of the reply. */ enum GNUNET_BLOCK_Type type; }; /** * Forward the result to the given peer if it matches the request. * * @param cls the 'struct ProcessContext' with the result * @param key the query * @param value the 'struct RecentRequest' with the request * @return GNUNET_OK (continue to iterate), * GNUNET_SYSERR if the result is malformed or type unsupported */ static int process (void *cls, const GNUNET_HashCode * key, void *value) { struct ProcessContext *pc = cls; struct RecentRequest *rr = value; enum GNUNET_BLOCK_EvaluationResult eval; unsigned int gpl; unsigned int ppl; GNUNET_HashCode hc; const GNUNET_HashCode *eval_key; if ((rr->type != GNUNET_BLOCK_TYPE_ANY) && (rr->type != pc->type)) return GNUNET_OK; /* type missmatch */ if (0 != (rr->options & GNUNET_DHT_RO_RECORD_ROUTE)) { gpl = pc->get_path_length; ppl = pc->put_path_length; } else { gpl = 0; ppl = 0; } if ((0 != (rr->options & GNUNET_DHT_RO_FIND_PEER)) && (pc->type == GNUNET_BLOCK_TYPE_DHT_HELLO)) { /* key may not match HELLO, which is OK since * the search is approximate. Still, the evaluation * would fail since the match is not exact. So * we fake it by changing the key to the actual PID ... */ GNUNET_BLOCK_get_key (GDS_block_context, GNUNET_BLOCK_TYPE_DHT_HELLO, pc->data, pc->data_size, &hc); eval_key = &hc; } else { eval_key = key; } eval = GNUNET_BLOCK_evaluate (GDS_block_context, pc->type, eval_key, &rr->reply_bf, rr->reply_bf_mutator, rr->xquery, rr->xquery_size, pc->data, pc->data_size); switch (eval) { case GNUNET_BLOCK_EVALUATION_OK_MORE: case GNUNET_BLOCK_EVALUATION_OK_LAST: GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Good REPLIES matched against routing table"), 1, GNUNET_NO); GDS_NEIGHBOURS_handle_reply (&rr->peer, pc->type, pc->expiration_time, key, ppl, pc->put_path, gpl, pc->get_path, pc->data, pc->data_size); break; case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE: GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Duplicate REPLIES matched against routing table"), 1, GNUNET_NO); return GNUNET_OK; case GNUNET_BLOCK_EVALUATION_RESULT_INVALID: GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Invalid REPLIES matched against routing table"), 1, GNUNET_NO); return GNUNET_SYSERR; case GNUNET_BLOCK_EVALUATION_REQUEST_VALID: GNUNET_break (0); return GNUNET_OK; case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID: GNUNET_break (0); return GNUNET_OK; case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED: GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Unsupported REPLIES matched against routing table"), 1, GNUNET_NO); return GNUNET_SYSERR; default: GNUNET_break (0); return GNUNET_SYSERR; } return GNUNET_OK; } /** * Handle a reply (route to origin). Only forwards the reply back to * other peers waiting for it. Does not do local caching or * forwarding to local clients. Essentially calls * GDS_NEIGHBOURS_handle_reply for all peers that sent us a matching * request recently. * * @param type type of the block * @param expiration_time when does the content expire * @param key key for the content * @param put_path_length number of entries in put_path * @param put_path peers the original PUT traversed (if tracked) * @param get_path_length number of entries in put_path * @param get_path peers this reply has traversed so far (if tracked) * @param data payload of the reply * @param data_size number of bytes in data */ void GDS_ROUTING_process (enum GNUNET_BLOCK_Type type, struct GNUNET_TIME_Absolute expiration_time, const GNUNET_HashCode * key, unsigned int put_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *get_path, const void *data, size_t data_size) { struct ProcessContext pc; pc.type = type; pc.expiration_time = expiration_time; pc.put_path_length = put_path_length; pc.put_path = put_path; pc.get_path_length = get_path_length; pc.get_path = get_path; pc.data = data; pc.data_size = data_size; if (NULL == data) { /* Some apps might have an 'empty' reply as a valid reply; however, 'process' will call GNUNET_BLOCK_evaluate' which treats a 'NULL' reply as request-validation (but we need response-validation). So we set 'data' to a 0-byte non-NULL value just to be sure */ GNUNET_break (0 == data_size); data_size = 0; pc.data = ""; /* something not null */ } GNUNET_CONTAINER_multihashmap_get_multiple (recent_map, key, &process, &pc); } /** * Remove the oldest entry from the DHT routing table. Must only * be called if it is known that there is at least one entry * in the heap and hashmap. */ static void expire_oldest_entry () { struct RecentRequest *recent_req; GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Entries removed from routing table"), 1, GNUNET_NO); recent_req = GNUNET_CONTAINER_heap_peek (recent_heap); GNUNET_assert (recent_req != NULL); GNUNET_CONTAINER_heap_remove_node (recent_req->heap_node); GNUNET_CONTAINER_bloomfilter_free (recent_req->reply_bf); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (recent_map, &recent_req->key, recent_req)); GNUNET_free (recent_req); } /** * Add a new entry to our routing table. * * @param sender peer that originated the request * @param type type of the block * @param options options for processing * @param key key for the content * @param xquery extended query * @param xquery_size number of bytes in xquery * @param reply_bf bloomfilter to filter duplicates * @param reply_bf_mutator mutator for reply_bf */ void GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender, enum GNUNET_BLOCK_Type type, enum GNUNET_DHT_RouteOption options, const GNUNET_HashCode * key, const void *xquery, size_t xquery_size, const struct GNUNET_CONTAINER_BloomFilter *reply_bf, uint32_t reply_bf_mutator) { struct RecentRequest *recent_req; while (GNUNET_CONTAINER_heap_get_size (recent_heap) >= DHT_MAX_RECENT) expire_oldest_entry (); GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Entries added to routing table"), 1, GNUNET_NO); recent_req = GNUNET_malloc (sizeof (struct RecentRequest) + xquery_size); recent_req->peer = *sender; recent_req->key = *key; recent_req->heap_node = GNUNET_CONTAINER_heap_insert (recent_heap, recent_req, GNUNET_TIME_absolute_get ().abs_value); recent_req->reply_bf = GNUNET_CONTAINER_bloomfilter_copy (reply_bf); recent_req->type = type; recent_req->options = options; recent_req->xquery = &recent_req[1]; recent_req->xquery_size = xquery_size; recent_req->reply_bf_mutator = reply_bf_mutator; GNUNET_CONTAINER_multihashmap_put (recent_map, key, recent_req, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); } /** * Initialize routing subsystem. */ void GDS_ROUTING_init () { recent_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); recent_map = GNUNET_CONTAINER_multihashmap_create (DHT_MAX_RECENT * 4 / 3); } /** * Shutdown routing subsystem. */ void GDS_ROUTING_done () { while (GNUNET_CONTAINER_heap_get_size (recent_heap) > 0) expire_oldest_entry (); GNUNET_assert (0 == GNUNET_CONTAINER_heap_get_size (recent_heap)); GNUNET_CONTAINER_heap_destroy (recent_heap); recent_heap = NULL; GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (recent_map)); GNUNET_CONTAINER_multihashmap_destroy (recent_map); recent_map = NULL; } /* end of gnunet-service-dht_routing.c */ gnunet-0.9.3/src/dht/test_dht_api_peer1.conf0000644000175000017500000000163511761764404015743 00000000000000[fs] AUTOSTART = NO [resolver] AUTOSTART = NO [dht] DEBUG = NO AUTOSTART = YES ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; HOSTNAME = localhost PORT = 12100 BINARY = gnunet-service-dht [block] plugins = dht test [dhtcache] QUOTA = 1 MB DATABASE = sqlite [transport] PLUGINS = tcp DEBUG = NO ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; NEIGHBOUR_LIMIT = 50 PORT = 12365 [ats] WAN_QUOTA_IN = 1 GB WAN_QUOTA_OUT = 1 GB [core] PORT = 12092 [arm] DEFAULTSERVICES = core PORT = 12366 DEBUG = NO [transport-tcp] TIMEOUT = 300 s PORT = 12368 BINDTO = 127.0.0.1 [TESTING] WEAKRANDOM = YES [gnunetd] HOSTKEY = $SERVICEHOME/.hostkey [PATHS] DEFAULTCONFIG = test_dht_api_peer1.conf SERVICEHOME = /tmp/test-gnunetd-dht-peer-1/ [nat] DISABLEV6 = YES ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 USE_LOCALADDR = NO [dns] AUTOSTART = NO [nse] AUTOSTART = NO gnunet-0.9.3/src/dht/test_dht_multipeer.c0000644000175000017500000005760411760505351015401 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/test_dht_multipeer.c * @brief testcase for testing DHT service with * multiple peers. */ #include "platform.h" #include "gnunet_testing_lib.h" #include "gnunet_core_service.h" #include "gnunet_dht_service.h" /* Timeout for entire testcase */ #define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 30) /* Timeout for waiting for replies to get requests */ #define GET_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 300) /* */ #define START_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30) /* Timeout for waiting for gets to complete */ #define GET_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 50) /* Timeout for waiting for puts to complete */ #define PUT_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 50) /* If number of peers not in config file, use this number */ #define DEFAULT_NUM_PEERS 10 #define TEST_DATA_SIZE 8 #define MAX_OUTSTANDING_PUTS 100 #define MAX_OUTSTANDING_GETS 100 #define PATH_TRACKING GNUNET_NO struct TestPutContext { /** * This is a linked list */ struct TestPutContext *next; /** * This is a linked list */ struct TestPutContext *prev; /** * Handle to the first peers DHT service (via the API) */ struct GNUNET_DHT_Handle *dht_handle; /** * Handle to the PUT peer daemon */ struct GNUNET_TESTING_Daemon *daemon; /** * Identifier for this PUT */ uint32_t uid; /** * Task handle for processing of the put. */ GNUNET_SCHEDULER_TaskIdentifier task; }; struct TestGetContext { /** * This is a linked list */ struct TestGetContext *next; /** * This is a linked list */ struct TestGetContext *prev; /** * Handle to the first peers DHT service (via the API) */ struct GNUNET_DHT_Handle *dht_handle; /** * Handle for the DHT get request */ struct GNUNET_DHT_GetHandle *get_handle; /** * Handle to the GET peer daemon */ struct GNUNET_TESTING_Daemon *daemon; /** * Identifier for this GET */ uint32_t uid; /** * Task for disconnecting DHT handles (and stopping GET) */ GNUNET_SCHEDULER_TaskIdentifier task; /** * Whether or not this request has been fulfilled already. */ int succeeded; }; /** * List of GETS to perform */ static struct TestGetContext *all_gets_head; /** * List of GETS to perform */ static struct TestGetContext *all_gets_tail; /** * List of PUTS to perform */ static struct TestPutContext *all_puts_head; /** * List of PUTS to perform */ static struct TestPutContext *all_puts_tail; /** * Handle to the set of all peers run for this test. */ static struct GNUNET_TESTING_PeerGroup *pg; /** * Total number of peers to run, set based on config file. */ static unsigned long long num_peers; /** * How many puts do we currently have in flight? */ static unsigned long long outstanding_puts; /** * How many puts are done? */ static unsigned long long puts_completed; /** * How many puts do we currently have in flight? */ static unsigned long long outstanding_gets; /** * How many gets are done? */ static unsigned long long gets_completed; /** * How many gets failed? */ static unsigned long long gets_failed; /** * Directory to remove on shutdown. */ static char *test_directory; /** * Option to use when routing. */ static enum GNUNET_DHT_RouteOption route_option; /** * Task handle to use to schedule test failure / success. */ static GNUNET_SCHEDULER_TaskIdentifier die_task; /** * Task handle to use to schedule test shutdown */ GNUNET_SCHEDULER_TaskIdentifier shutdown_task; /** * Global return value (0 for success, anything else for failure) */ static int ok; /** * Check whether peers successfully shut down. */ static void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { FPRINTF (stderr, "Failed to shutdown testing topology: %s\n", emsg); if (ok == 0) ok = 2; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown callback completed.\n"); } static void do_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) == 0) { if (GNUNET_SCHEDULER_NO_TASK != shutdown_task) { GNUNET_SCHEDULER_cancel(shutdown_task); shutdown_task = GNUNET_SCHEDULER_NO_TASK; } } else { shutdown_task = GNUNET_SCHEDULER_NO_TASK ; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown requested.\n"); if (NULL != pg) GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); pg = NULL; } /** * Master context for 'stat_run'. */ struct StatMaster { struct GNUNET_STATISTICS_Handle *stat; unsigned int daemon; unsigned int value; }; struct StatValues { const char *subsystem; const char *name; unsigned long long total; }; /** * Statistics we print out. */ static struct StatValues stats[] = { {"core", "# bytes decrypted", 0}, {"core", "# bytes encrypted", 0}, {"core", "# type maps received", 0}, {"core", "# session keys confirmed via PONG", 0}, {"core", "# peers connected", 0}, {"core", "# key exchanges initiated", 0}, {"core", "# send requests dropped (disconnected)", 0}, {"core", "# transmissions delayed due to corking", 0}, {"core", "# messages discarded (expired prior to transmission)", 0}, {"core", "# messages discarded (disconnected)", 0}, {"core", "# discarded CORE_SEND requests", 0}, {"core", "# discarded lower priority CORE_SEND requests", 0}, {"transport", "# bytes received via TCP", 0}, {"transport", "# bytes transmitted via TCP", 0}, {"dht", "# PUT messages queued for transmission", 0}, {"dht", "# P2P PUT requests received", 0}, {"dht", "# GET messages queued for transmission", 0}, {"dht", "# P2P GET requests received", 0}, {"dht", "# RESULT messages queued for transmission", 0}, {"dht", "# P2P RESULTS received", 0}, {"dht", "# Queued messages discarded (peer disconnected)", 0}, {"dht", "# Peers excluded from routing due to Bloomfilter", 0}, {"dht", "# Peer selection failed", 0}, {"dht", "# FIND PEER requests ignored due to Bloomfilter", 0}, {"dht", "# FIND PEER requests ignored due to lack of HELLO", 0}, {"dht", "# P2P FIND PEER requests processed", 0}, {"dht", "# P2P GET requests ONLY routed", 0}, {"dht", "# Preference updates given to core", 0}, {"dht", "# REPLIES ignored for CLIENTS (no match)", 0}, {"dht", "# GET requests from clients injected", 0}, {"dht", "# GET requests received from clients", 0}, {"dht", "# GET STOP requests received from clients", 0}, {"dht", "# ITEMS stored in datacache", 0}, {"dht", "# Good RESULTS found in datacache", 0}, {"dht", "# GET requests given to datacache", 0}, {NULL, NULL, 0} }; /** * Callback function to process statistic values. * * @param cls closure * @param subsystem name of subsystem that created the statistic * @param name the name of the datum * @param value the current value * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration */ static int print_stat (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent) { struct StatMaster *sm = cls; stats[sm->value].total += value; FPRINTF (stderr, "Peer %2u: %12s/%50s = %12llu\n", sm->daemon, subsystem, name, (unsigned long long) value); return GNUNET_OK; } /** * Function that gathers stats from all daemons. */ static void stat_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Function called when GET operation on stats is done. */ static void get_done (void *cls, int success) { struct StatMaster *sm = cls; GNUNET_break (GNUNET_OK == success); sm->value++; GNUNET_SCHEDULER_add_now (&stat_run, sm); } /** * Function that gathers stats from all daemons. */ static void stat_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct StatMaster *sm = cls; unsigned int i; die_task = GNUNET_SCHEDULER_NO_TASK; if (stats[sm->value].name != NULL) { GNUNET_STATISTICS_get (sm->stat, #if 0 NULL, NULL, #else stats[sm->value].subsystem, stats[sm->value].name, #endif GNUNET_TIME_UNIT_FOREVER_REL, &get_done, &print_stat, sm); return; } GNUNET_STATISTICS_destroy (sm->stat, GNUNET_NO); sm->value = 0; sm->daemon++; if (sm->daemon == num_peers) { GNUNET_free (sm); i = 0; while (stats[i].name != NULL) { FPRINTF (stderr, "Total : %12s/%50s = %12llu\n", stats[i].subsystem, stats[i].name, (unsigned long long) stats[i].total); i++; } die_task = GNUNET_SCHEDULER_add_now (&do_stop, NULL); return; } sm->stat = GNUNET_STATISTICS_create ("", GNUNET_TESTING_daemon_get (pg, sm->daemon)->cfg); die_task = GNUNET_SCHEDULER_add_now (&stat_run, sm); } /** * Function scheduled to be run on the successful completion of this * testcase. */ static void finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct TestPutContext *test_put; struct TestGetContext *test_get; struct StatMaster *sm; die_task = GNUNET_SCHEDULER_NO_TASK; while (NULL != (test_put = all_puts_head)) { if (test_put->task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (test_put->task); if (test_put->dht_handle != NULL) GNUNET_DHT_disconnect (test_put->dht_handle); GNUNET_CONTAINER_DLL_remove (all_puts_head, all_puts_tail, test_put); GNUNET_free (test_put); } while (NULL != (test_get = all_gets_head)) { if (test_get->task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (test_get->task); if (test_get->get_handle != NULL) GNUNET_DHT_get_stop (test_get->get_handle); if (test_get->dht_handle != NULL) GNUNET_DHT_disconnect (test_get->dht_handle); GNUNET_CONTAINER_DLL_remove (all_gets_head, all_gets_tail, test_get); GNUNET_free (test_get); } sm = GNUNET_malloc (sizeof (struct StatMaster)); sm->stat = GNUNET_STATISTICS_create ("", GNUNET_TESTING_daemon_get (pg, sm->daemon)->cfg); die_task = GNUNET_SCHEDULER_add_now (&stat_run, sm); } /** * Check if the get_handle is being used, if so stop the request. Either * way, schedule the end_badly_cont function which actually shuts down the * test. */ static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { const char *emsg = cls; struct TestPutContext *test_put; struct TestGetContext *test_get; die_task = GNUNET_SCHEDULER_NO_TASK; FPRINTF (stderr, "Failing test with error: `%s'!\n", emsg); while (NULL != (test_put = all_puts_head)) { if (test_put->task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (test_put->task); if (test_put->dht_handle != NULL) GNUNET_DHT_disconnect (test_put->dht_handle); GNUNET_CONTAINER_DLL_remove (all_puts_head, all_puts_tail, test_put); GNUNET_free (test_put); } while (NULL != (test_get = all_gets_head)) { if (test_get->task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (test_get->task); if (test_get->get_handle != NULL) GNUNET_DHT_get_stop (test_get->get_handle); if (test_get->dht_handle != NULL) GNUNET_DHT_disconnect (test_get->dht_handle); GNUNET_CONTAINER_DLL_remove (all_gets_head, all_gets_tail, test_get); GNUNET_free (test_get); } ok = 1; /* testing_peergroup will do that in its own end_badly() handler */ /*GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); */ pg = NULL; } /** * Task to release get handle. */ static void get_stop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct TestGetContext *test_get = cls; GNUNET_HashCode search_key; /* Key stored under */ char original_data[TEST_DATA_SIZE]; /* Made up data to store */ test_get->task = GNUNET_SCHEDULER_NO_TASK; memset (original_data, test_get->uid, sizeof (original_data)); GNUNET_CRYPTO_hash (original_data, TEST_DATA_SIZE, &search_key); if (test_get->succeeded != GNUNET_YES) { gets_failed++; FPRINTF (stderr, "Get from peer %s for key %s failed!\n", GNUNET_i2s (&test_get->daemon->id), GNUNET_h2s (&search_key)); } GNUNET_assert (test_get->get_handle != NULL); GNUNET_DHT_get_stop (test_get->get_handle); test_get->get_handle = NULL; outstanding_gets--; /* GET is really finished */ GNUNET_DHT_disconnect (test_get->dht_handle); test_get->dht_handle = NULL; GNUNET_CONTAINER_DLL_remove (all_gets_head, all_gets_tail, test_get); GNUNET_free (test_get); if ((gets_failed > 10) && (outstanding_gets == 0)) { /* Had more than 10% failures */ FPRINTF (stderr, "%llu gets succeeded, %llu gets failed!\n", gets_completed, gets_failed); GNUNET_SCHEDULER_cancel (die_task); ok = 1; die_task = GNUNET_SCHEDULER_add_now (&finish_testing, "not all gets succeeded"); return; } if ((gets_completed + gets_failed == num_peers * num_peers) && (outstanding_gets == 0)) /* All gets successful */ { FPRINTF (stderr, "%llu gets succeeded, %llu gets failed!\n", gets_completed, gets_failed); GNUNET_SCHEDULER_cancel (die_task); ok = 0; die_task = GNUNET_SCHEDULER_add_now (&finish_testing, NULL); } } /** * Iterator called if the GET request initiated returns a response. * * @param cls closure * @param exp when will this value expire * @param key key of the result * @param type type of the result * @param size number of bytes in data * @param data pointer to the result data */ static void get_result_iterator (void *cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int put_path_length, enum GNUNET_BLOCK_Type type, size_t size, const void *data) { struct TestGetContext *test_get = cls; GNUNET_HashCode search_key; /* Key stored under */ char original_data[TEST_DATA_SIZE]; /* Made up data to store */ memset (original_data, test_get->uid, sizeof (original_data)); GNUNET_CRYPTO_hash (original_data, TEST_DATA_SIZE, &search_key); if (test_get->succeeded == GNUNET_YES) return; /* Get has already been successful, probably ending now */ #if PATH_TRACKING if (put_path != NULL) { unsigned int i; FPRINTF (stderr, "PUT (%u) Path: ", test_get->uid); for (i = 0; i < put_path_length; i++) FPRINTF (stderr, "%s%s", i == 0 ? "" : "->", GNUNET_i2s (&put_path[i])); FPRINTF (stderr, "%s", "\n"); } if (get_path != NULL) { unsigned int i; FPRINTF (stderr, "GET (%u) Path: ", test_get->uid); for (i = 0; i < get_path_length; i++) FPRINTF (stderr, "%s%s", i == 0 ? "" : "->", GNUNET_i2s (&get_path[i])); FPRINTF (stderr, "%s%s\n", get_path_length > 0 ? "->" : "", GNUNET_i2s (&test_get->daemon->id)); } #endif if ((0 != memcmp (&search_key, key, sizeof (GNUNET_HashCode))) || (0 != memcmp (original_data, data, sizeof (original_data)))) { FPRINTF (stderr, "%s", "Key or data is not the same as was inserted!\n"); return; } gets_completed++; test_get->succeeded = GNUNET_YES; GNUNET_SCHEDULER_cancel (test_get->task); test_get->task = GNUNET_SCHEDULER_add_now (&get_stop_task, test_get); } /** * Set up some data, and call API PUT function */ static void do_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct TestGetContext *test_get = cls; GNUNET_HashCode key; /* Made up key to store data under */ char data[TEST_DATA_SIZE]; /* Made up data to store */ if (outstanding_gets > MAX_OUTSTANDING_GETS) { test_get->task = GNUNET_SCHEDULER_add_delayed (GET_DELAY, &do_get, test_get); return; } memset (data, test_get->uid, sizeof (data)); GNUNET_CRYPTO_hash (data, TEST_DATA_SIZE, &key); test_get->dht_handle = GNUNET_DHT_connect (test_get->daemon->cfg, 10); GNUNET_assert (test_get->dht_handle != NULL); outstanding_gets++; test_get->get_handle = GNUNET_DHT_get_start (test_get->dht_handle, GNUNET_BLOCK_TYPE_TEST, &key, 1, route_option, NULL, 0, &get_result_iterator, test_get); test_get->task = GNUNET_SCHEDULER_add_delayed (GET_TIMEOUT, &get_stop_task, test_get); } /** * Task to release DHT handles for PUT */ static void put_disconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct TestPutContext *test_put = cls; test_put->task = GNUNET_SCHEDULER_NO_TASK; GNUNET_DHT_disconnect (test_put->dht_handle); test_put->dht_handle = NULL; GNUNET_CONTAINER_DLL_remove (all_puts_head, all_puts_tail, test_put); GNUNET_free (test_put); } /** * Schedule the GET requests */ static void start_gets (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { unsigned long long i; unsigned long long j; struct TestGetContext *test_get; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Issuing %llu GETs\n", (unsigned long long) (num_peers * num_peers)); for (i = 0; i < num_peers; i++) for (j = 0; j < num_peers; j++) { test_get = GNUNET_malloc (sizeof (struct TestGetContext)); test_get->uid = i + j * num_peers; test_get->daemon = GNUNET_TESTING_daemon_get (pg, j); GNUNET_CONTAINER_DLL_insert (all_gets_head, all_gets_tail, test_get); test_get->task = GNUNET_SCHEDULER_add_now (&do_get, test_get); } } /** * Called when the PUT request has been transmitted to the DHT service. */ static void put_finished (void *cls, int success) { struct TestPutContext *test_put = cls; outstanding_puts--; puts_completed++; if (GNUNET_SCHEDULER_NO_TASK != test_put->task) { GNUNET_SCHEDULER_cancel (test_put->task); } test_put->task = GNUNET_SCHEDULER_add_now (&put_disconnect_task, test_put); if (puts_completed != num_peers * num_peers) return; GNUNET_assert (outstanding_puts == 0); GNUNET_SCHEDULER_add_delayed (START_DELAY, &start_gets, NULL); } /** * Set up some data, and call API PUT function */ static void do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct TestPutContext *test_put = cls; GNUNET_HashCode key; /* Made up key to store data under */ char data[TEST_DATA_SIZE]; /* Made up data to store */ test_put->task = GNUNET_SCHEDULER_NO_TASK; if (outstanding_puts > MAX_OUTSTANDING_PUTS) { test_put->task = GNUNET_SCHEDULER_add_delayed (PUT_DELAY, &do_put, test_put); return; } memset (data, test_put->uid, sizeof (data)); GNUNET_CRYPTO_hash (data, TEST_DATA_SIZE, &key); test_put->dht_handle = GNUNET_DHT_connect (test_put->daemon->cfg, 10); GNUNET_assert (test_put->dht_handle != NULL); outstanding_puts++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "PUT %u at `%s'\n", test_put->uid, GNUNET_i2s (&test_put->daemon->id)); GNUNET_DHT_put (test_put->dht_handle, &key, 1, route_option, GNUNET_BLOCK_TYPE_TEST, sizeof (data), data, GNUNET_TIME_UNIT_FOREVER_ABS, GNUNET_TIME_UNIT_FOREVER_REL, &put_finished, test_put); test_put->task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &put_disconnect_task, test_put); } static void run_dht_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { unsigned long long i; struct TestPutContext *test_put; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) { ok = 1; return; } #if PATH_TRACKING route_option = GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE; #else route_option = GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE; #endif die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "from setup puts/gets"); FPRINTF (stderr, "Issuing %llu PUTs (one per peer)\n", (unsigned long long) (num_peers * num_peers)); for (i = 0; i < num_peers * num_peers; i++) { test_put = GNUNET_malloc (sizeof (struct TestPutContext)); test_put->uid = i; test_put->daemon = GNUNET_TESTING_daemon_get (pg, i % num_peers); test_put->task = GNUNET_SCHEDULER_add_now (&do_put, test_put); GNUNET_CONTAINER_DLL_insert (all_puts_head, all_puts_tail, test_put); } } /** * This function is called once testing has finished setting up the topology. * * @param cls unused * @param emsg variable is NULL on success (peers connected), and non-NULL on * failure (peers failed to connect). */ static void startup_done (void *cls, const char *emsg) { if (emsg != NULL) { FPRINTF (stderr, "Failed to setup topology: %s\n", emsg); die_task = GNUNET_SCHEDULER_add_now (&end_badly, "topology setup failed"); return; } die_task = GNUNET_SCHEDULER_add_delayed (START_DELAY, &run_dht_test, "from setup puts/gets"); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { /* Get path from configuration file */ if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", &test_directory)) { GNUNET_break (0); ok = 404; return; } if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", &num_peers)) num_peers = DEFAULT_NUM_PEERS; pg = GNUNET_TESTING_peergroup_start (cfg, num_peers, TIMEOUT, NULL, &startup_done, NULL, NULL); GNUNET_assert (NULL != pg); shutdown_task = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_FOREVER_REL, &do_stop, NULL); } static int check () { int ret; /* Arguments for GNUNET_PROGRAM_run */ char *const argv[] = { "test-dht-multipeer", /* Name to give running binary */ "-c", "test_dht_multipeer_data.conf", /* Config file to use */ NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; /* Run the run function as a new program */ ret = GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-dht-multipeer", "nohelp", options, &run, &ok); if (ret != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "`test-dht-multipeer': Failed with error code %d\n", ret); } return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-dht-multipeer", "WARNING", NULL); ret = check (); /** * Need to remove base directory, subdirectories taken care * of by the testing framework. */ if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to remove testing directory %s\n", test_directory); } return ret; } /* end of test_dht_multipeer.c */ gnunet-0.9.3/src/dht/gnunet-service-dht_datacache.c0000644000175000017500000002205511760502551017154 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/gnunet-service-dht_datacache.c * @brief GNUnet DHT service's datacache integration * @author Christian Grothoff * @author Nathan Evans */ #include "platform.h" #include "gnunet_datacache_lib.h" #include "gnunet-service-dht_clients.h" #include "gnunet-service-dht_datacache.h" #include "gnunet-service-dht_routing.h" #include "gnunet-service-dht.h" /** * Handle to the datacache service (for inserting/retrieving data) */ static struct GNUNET_DATACACHE_Handle *datacache; /** * Entry for inserting data into datacache from the DHT. */ struct DHTPutEntry { /** * Size of data. */ uint16_t data_size; /** * Length of recorded path. */ uint16_t path_length; /* PATH ENTRIES */ /* PUT DATA */ }; /** * Handle a datum we've received from another peer. Cache if * possible. * * @param expiration when will the reply expire * @param key the query this reply is for * @param put_path_length number of peers in 'put_path' * @param put_path path the reply took on put * @param type type of the reply * @param data_size number of bytes in 'data' * @param data application payload data */ void GDS_DATACACHE_handle_put (struct GNUNET_TIME_Absolute expiration, const GNUNET_HashCode * key, unsigned int put_path_length, const struct GNUNET_PeerIdentity *put_path, enum GNUNET_BLOCK_Type type, size_t data_size, const void *data) { size_t plen = data_size + put_path_length * sizeof (struct GNUNET_PeerIdentity) + sizeof (struct DHTPutEntry); char buf[plen]; struct DHTPutEntry *pe; struct GNUNET_PeerIdentity *pp; if (datacache == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("%s request received, but have no datacache!\n"), "PUT"); return; } if (data_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); return; } /* Put size is actual data size plus struct overhead plus path length (if any) */ GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# ITEMS stored in datacache"), 1, GNUNET_NO); pe = (struct DHTPutEntry *) buf; pe->data_size = htons (data_size); pe->path_length = htons ((uint16_t) put_path_length); pp = (struct GNUNET_PeerIdentity *) &pe[1]; memcpy (pp, put_path, put_path_length * sizeof (struct GNUNET_PeerIdentity)); memcpy (&pp[put_path_length], data, data_size); (void) GNUNET_DATACACHE_put (datacache, key, plen, (const char *) pe, type, expiration); } /** * Context containing information about a GET request. */ struct GetRequestContext { /** * extended query (see gnunet_block_lib.h). */ const void *xquery; /** * Bloomfilter to filter out duplicate replies (updated) */ struct GNUNET_CONTAINER_BloomFilter **reply_bf; /** * The key this request was about */ GNUNET_HashCode key; /** * Number of bytes in xquery. */ size_t xquery_size; /** * Mutator value for the reply_bf, see gnunet_block_lib.h */ uint32_t reply_bf_mutator; /** * Return value to give back. */ enum GNUNET_BLOCK_EvaluationResult eval; }; /** * Iterator for local get request results, * * @param cls closure for iterator, a DatacacheGetContext * @param exp when does this value expire? * @param key the key this data is stored under * @param size the size of the data identified by key * @param data the actual data * @param type the type of the data * * @return GNUNET_OK to continue iteration, anything else * to stop iteration. */ static int datacache_get_iterator (void *cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, size_t size, const char *data, enum GNUNET_BLOCK_Type type) { struct GetRequestContext *ctx = cls; const struct DHTPutEntry *pe; const struct GNUNET_PeerIdentity *pp; const char *rdata; size_t rdata_size; uint16_t put_path_length; enum GNUNET_BLOCK_EvaluationResult eval; pe = (const struct DHTPutEntry *) data; put_path_length = ntohs (pe->path_length); rdata_size = ntohs (pe->data_size); if (size != sizeof (struct DHTPutEntry) + rdata_size + (put_path_length * sizeof (struct GNUNET_PeerIdentity))) { GNUNET_break (0); return GNUNET_OK; } pp = (const struct GNUNET_PeerIdentity *) &pe[1]; rdata = (const char *) &pp[put_path_length]; eval = GNUNET_BLOCK_evaluate (GDS_block_context, type, key, ctx->reply_bf, ctx->reply_bf_mutator, ctx->xquery, ctx->xquery_size, rdata, rdata_size); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found reply for query %s in datacache, evaluation result is %d\n", GNUNET_h2s (key), (int) eval); ctx->eval = eval; switch (eval) { case GNUNET_BLOCK_EVALUATION_OK_LAST: case GNUNET_BLOCK_EVALUATION_OK_MORE: /* forward to local clients */ GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Good RESULTS found in datacache"), 1, GNUNET_NO); GDS_CLIENTS_handle_reply (exp, key, 0, NULL, put_path_length, pp, type, rdata_size, rdata); /* forward to other peers */ GDS_ROUTING_process (type, exp, key, put_path_length, pp, 0, NULL, rdata, rdata_size); break; case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE: GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Duplicate RESULTS found in datacache"), 1, GNUNET_NO); break; case GNUNET_BLOCK_EVALUATION_RESULT_INVALID: GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Invalid RESULTS found in datacache"), 1, GNUNET_NO); break; case GNUNET_BLOCK_EVALUATION_REQUEST_VALID: GNUNET_break (0); break; case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID: GNUNET_break_op (0); return GNUNET_SYSERR; case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED: GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Unsupported RESULTS found in datacache"), 1, GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Unsupported block type (%u) in local response!\n"), type); break; } return (eval == GNUNET_BLOCK_EVALUATION_OK_LAST) ? GNUNET_NO : GNUNET_OK; } /** * Handle a GET request we've received from another peer. * * @param key the query * @param type requested data type * @param xquery extended query * @param xquery_size number of bytes in xquery * @param reply_bf where the reply bf is (to be) stored, possibly updated, can be NULL * @param reply_bf_mutator mutation value for reply_bf * @return evaluation result for the local replies */ enum GNUNET_BLOCK_EvaluationResult GDS_DATACACHE_handle_get (const GNUNET_HashCode * key, enum GNUNET_BLOCK_Type type, const void *xquery, size_t xquery_size, struct GNUNET_CONTAINER_BloomFilter **reply_bf, uint32_t reply_bf_mutator) { struct GetRequestContext ctx; if (datacache == NULL) return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# GET requests given to datacache"), 1, GNUNET_NO); ctx.eval = GNUNET_BLOCK_EVALUATION_REQUEST_VALID; ctx.key = *key; ctx.xquery = xquery; ctx.xquery_size = xquery_size; ctx.reply_bf = reply_bf; ctx.reply_bf_mutator = reply_bf_mutator; (void) GNUNET_DATACACHE_get (datacache, key, type, &datacache_get_iterator, &ctx); return ctx.eval; } /** * Initialize datacache subsystem. */ void GDS_DATACACHE_init () { datacache = GNUNET_DATACACHE_create (GDS_cfg, "dhtcache"); } /** * Shutdown datacache subsystem. */ void GDS_DATACACHE_done () { if (datacache != NULL) { GNUNET_DATACACHE_destroy (datacache); datacache = NULL; } } /* end of gnunet-service-dht_datacache.c */ gnunet-0.9.3/src/dht/test_dht_twopeer_put_get.c0000644000175000017500000004022711760505363016603 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/test_dht_twopeer_put_get.c * @brief base testcase for testing DHT service with * two running peers. * * This testcase starts peers using the GNUNET_TESTING_daemons_start * function call. On peer start, connects to the peers DHT service * by calling GNUNET_DHT_connected. Once notified about all peers * being started (by the peers_started_callback function), calls * GNUNET_TESTING_connect_topology, which connects the peers in a * "straight line" topology. On notification that all peers have * been properly connected, runs the do_put function to insert data * at the first peer. Once the GNUNET_DHT_put function completes, * calls the do_get function which initiates a GNUNET_DHT_get from * the *second* peer. If the GET is successful, schedules finish_testing * to stop the test and shut down peers. If GET is unsuccessful * after GET_TIMEOUT seconds, prints an error message and shuts down * the peers. */ #include "platform.h" #include "gnunet_testing_lib.h" #include "gnunet_core_service.h" #include "gnunet_dht_service.h" #include "block_dns.h" #include "gnunet_signatures.h" /* DEFINES */ #define VERBOSE GNUNET_NO /* Timeout for entire testcase */ #define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5) /* Timeout for waiting for replies to get requests */ #define GET_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30) /* If number of peers not in config file, use this number */ #define DEFAULT_NUM_PEERS 2 /* Globals */ /** * Directory to store temp data in, defined in config file */ static char *test_directory; /** * Variable used to store the number of connections we should wait for. */ static unsigned int expected_connections; /** * Variable used to keep track of how many peers aren't yet started. */ static unsigned long long peers_left; /** * Handle to the set of all peers run for this test. */ static struct GNUNET_TESTING_PeerGroup *pg; /** * Global handle we will use for GET requests. */ struct GNUNET_DHT_GetHandle *global_get_handle; /** * Total number of peers to run, set based on config file. */ static unsigned long long num_peers; /** * Global used to count how many connections we have currently * been notified about (how many times has topology_callback been called * with success?) */ static unsigned int total_connections; /** * Global used to count how many failed connections we have * been notified about (how many times has topology_callback * been called with failure?) */ static unsigned int failed_connections; /* Task handle to use to schedule test failure */ static GNUNET_SCHEDULER_TaskIdentifier die_task; /* Global return value (0 for success, anything else for failure) */ static int ok; /** * Peer identity of the first peer started. */ static struct GNUNET_PeerIdentity peer1id; /** * Peer identity of the second peer started. */ static struct GNUNET_PeerIdentity peer2id; /** * Handle to the first peers DHT service (via the API) */ static struct GNUNET_DHT_Handle *peer1dht; /** * Handle to the second peers DHT service (via the API) */ static struct GNUNET_DHT_Handle *peer2dht; /** * Handle for our PUT operation. */ static struct GNUNET_DHT_PutHandle *put_op; /** * Check whether peers successfully shut down. */ static void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { if (ok == 0) ok = 2; } } /** * Function scheduled to be run on the successful completion of this * testcase. Specifically, called when our get request completes. */ static void finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_assert (pg != NULL); GNUNET_assert (peer1dht != NULL); GNUNET_assert (peer2dht != NULL); GNUNET_DHT_disconnect (peer1dht); GNUNET_DHT_disconnect (peer2dht); GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); ok = 0; } /** * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut * down the peers without freeing memory associated with GET request. */ static void end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (NULL != put_op) { GNUNET_DHT_put_cancel (put_op); put_op = NULL; } if (peer1dht != NULL) GNUNET_DHT_disconnect (peer1dht); if (peer2dht != NULL) GNUNET_DHT_disconnect (peer2dht); if (pg != NULL) GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); } /** * Check if the get_handle is being used, if so stop the request. Either * way, schedule the end_badly_cont function which actually shuts down the * test. */ static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failing test with error: `%s'!\n", (char *) cls); if (global_get_handle != NULL) { GNUNET_DHT_get_stop (global_get_handle); global_get_handle = NULL; } GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL); ok = 1; } /** * Iterator called if the GET request initiated returns a response. * * @param cls closure * @param exp when will this value expire * @param key key of the result * @param type type of the result * @param size number of bytes in data * @param data pointer to the result data */ static void get_result_iterator (void *cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_size, const struct GNUNET_PeerIdentity *put_path, unsigned int put_path_size, enum GNUNET_BLOCK_Type type, size_t size, const void *result_data) { GNUNET_HashCode original_key; /* Key data was stored data under */ char original_data[4]; /* Made up data that was stored */ memset (&original_key, 42, sizeof (GNUNET_HashCode)); /* Set the key to what it was set to previously */ memset (original_data, 43, sizeof (original_data)); if ((sizeof (original_data) != size) || (0 != memcmp (&original_key, key, sizeof (GNUNET_HashCode))) || (0 != memcmp (original_data, result_data, sizeof (original_data)))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Key or data is not the same as was inserted!\n"); GNUNET_SCHEDULER_cancel (die_task); GNUNET_SCHEDULER_add_now (&end_badly, "key or data mismatch in get response!\n"); return; } GNUNET_SCHEDULER_cancel (die_task); GNUNET_DHT_get_stop (global_get_handle); global_get_handle = NULL; GNUNET_SCHEDULER_add_now (&finish_testing, NULL); } /** * Called when the PUT request has been transmitted to the DHT service. * Schedule the GET request for some time in the future. */ static void put_finished (void *cls, int success) { GNUNET_HashCode key; /* Key for data lookup */ put_op = NULL; GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_delayed (GET_TIMEOUT, &end_badly, "waiting for get response (data not found)"); memset (&key, 42, sizeof (GNUNET_HashCode)); /* Set the key to the same thing as when data was inserted */ global_get_handle = GNUNET_DHT_get_start (peer2dht, GNUNET_BLOCK_TYPE_TEST, &key, 1, GNUNET_DHT_RO_NONE, NULL, 0, &get_result_iterator, NULL); } /** * Set up some data, and call API PUT function */ static void do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_HashCode key; /* Made up key to store data under */ char data[4]; /* Made up data to store */ memset (&key, 42, sizeof (GNUNET_HashCode)); /* Set the key to something simple so we can issue GET request */ memset (data, 43, sizeof (data)); /* Insert the data at the first peer */ put_op = GNUNET_DHT_put (peer1dht, &key, 1, GNUNET_DHT_RO_NONE, GNUNET_BLOCK_TYPE_TEST, sizeof (data), data, GNUNET_TIME_UNIT_FOREVER_ABS, GNUNET_TIME_UNIT_FOREVER_REL, &put_finished, NULL); } /** * This function is called whenever a connection attempt is finished between two of * the started peers (started with GNUNET_TESTING_daemons_start). The total * number of times this function is called should equal the number returned * from the GNUNET_TESTING_connect_topology call. * * The emsg variable is NULL on success (peers connected), and non-NULL on * failure (peers failed to connect). */ static void topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, uint32_t distance, const struct GNUNET_CONFIGURATION_Handle *first_cfg, const struct GNUNET_CONFIGURATION_Handle *second_cfg, struct GNUNET_TESTING_Daemon *first_daemon, struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) { if (emsg == NULL) { total_connections++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s, distance %u\n", first_daemon->shortname, second_daemon->shortname, distance); } else { failed_connections++; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to connect peer %s to peer %s with error :\n%s\n", first_daemon->shortname, second_daemon->shortname, emsg); } if (total_connections == expected_connections) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created %d total connections, which is our target number! Starting next phase of testing.\n", total_connections); GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "from test gets"); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_put, NULL); } else if (total_connections + failed_connections == expected_connections) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from topology_callback (too many failed connections)"); } } /** * Callback which is called whenever a peer is started (as a result of the * GNUNET_TESTING_daemons_start call. * * @param cls closure argument given to GNUNET_TESTING_daemons_start * @param id the GNUNET_PeerIdentity of the started peer * @param cfg the configuration for this specific peer (needed to connect * to the DHT) * @param d the handle to the daemon started * @param emsg NULL if peer started, non-NULL on error */ static void peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to start daemon with error: `%s'\n", emsg); return; } GNUNET_assert (id != NULL); /* This is the first peer started */ if (peers_left == num_peers) { memcpy (&peer1id, id, sizeof (struct GNUNET_PeerIdentity)); /* Save the peer id */ peer1dht = GNUNET_DHT_connect (cfg, 100); /* Connect to the first peers DHT service */ if (peer1dht == NULL) /* If DHT connect failed */ { GNUNET_SCHEDULER_cancel (die_task); GNUNET_SCHEDULER_add_now (&end_badly, "Failed to get dht handle!\n"); } } else /* This is the second peer started */ { memcpy (&peer2id, id, sizeof (struct GNUNET_PeerIdentity)); /* Same as for first peer... */ peer2dht = GNUNET_DHT_connect (cfg, 100); if (peer2dht == NULL) { GNUNET_SCHEDULER_cancel (die_task); GNUNET_SCHEDULER_add_now (&end_badly, "Failed to get dht handle!\n"); } } /* Decrement number of peers left to start */ peers_left--; if (peers_left == 0) /* Indicates all peers started */ { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All %d daemons started, now connecting peers!\n", num_peers); expected_connections = -1; if ((pg != NULL)) /* Sanity check */ { /* Connect peers in a "straight line" topology, return the number of expected connections */ expected_connections = GNUNET_TESTING_connect_topology (pg, GNUNET_TESTING_TOPOLOGY_LINE, GNUNET_TESTING_TOPOLOGY_OPTION_ALL, 0.0, TIMEOUT, 12, NULL, NULL); } /* Cancel current timeout fail task */ GNUNET_SCHEDULER_cancel (die_task); if (expected_connections == GNUNET_SYSERR) /* Some error happened */ die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from connect topology (bad return)"); /* Schedule timeout on failure task */ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "from connect topology (timeout)"); ok = 0; } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { /* Get path from configuration file */ if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", &test_directory)) { ok = 404; return; } /* Get number of peers to start from configuration (should be two) */ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", &num_peers)) num_peers = DEFAULT_NUM_PEERS; /* Set peers_left so we know when all peers started */ peers_left = num_peers; /* Set up a task to end testing if peer start fails */ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "didn't start all daemons in reasonable amount of time!!!"); /* Start num_peers peers, call peers_started_callback on peer start, topology_callback on peer connect */ /* Read the API documentation for other parameters! */ pg = GNUNET_TESTING_daemons_start (cfg, num_peers, 2, 2, TIMEOUT, NULL, NULL, &peers_started_callback, NULL, &topology_callback, NULL, NULL); } static int check () { int ret; /* Arguments for GNUNET_PROGRAM_run */ char *const argv[] = { "test-dht-twopeer-put-get", /* Name to give running binary */ "-c", "test_dht_twopeer_data.conf", /* Config file to use */ NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; /* Run the run function as a new program */ ret = GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-dht-twopeer-put-get", "nohelp", options, &run, &ok); if (ret != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "`test-dht-twopeer': Failed with error code %d\n", ret); } return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-dht-twopeer", "WARNING", NULL); ret = check (); /** * Need to remove base directory, subdirectories taken care * of by the testing framework. */ if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to remove testing directory %s\n", test_directory); } return ret; } /* end of test_dht_twopeer_put_get.c */ gnunet-0.9.3/src/dht/test_dht_line.conf0000644000175000017500000000271511725220503015010 00000000000000[PATHS] SERVICEHOME = /tmp/test_dht_topo/ DEFAULTCONFIG = test_dht_line.conf [arm] PORT = 10010 DEFAULTSERVICES = core dht #DEBUG = YES [statistics] AUTOSTART = YES PORT = 10000 [dht] DEBUG = NO AUTOSTART = YES ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; HOSTNAME = localhost PORT = 10001 [dns] AUTOSTART = NO PORT = 10011 [transport] PORT = 10002 AUTOSTART = YES [nat] DISABLEV6 = YES BINDTO = 127.0.0.1 ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 [ats] WAN_QUOTA_IN = 1 GB WAN_QUOTA_OUT = 1 GB [core] AUTOSTART = YES PORT = 10003 [peerinfo] AUTOSTART = YES PORT = 10004 [testing] NUM_PEERS = 5 WEAKRANDOM = YES TOPOLOGY = NONE CONNECT_TOPOLOGY = LINE BLACKLIST_TOPOLOGY = LINE #TOPOLOGY_FILE = small.dat #CONNECT_TOPOLOGY = ERDOS_RENYI #CONNECT_TOPOLOGY_OPTION = CONNECT_MINIMUM #CONNECT_TOPOLOGY_OPTION_MODIFIER = 25 #PERCENTAGE = 3 #PROBABILITY = .1 F2F = NO CONNECT_TIMEOUT = 60 s CONNECT_ATTEMPTS = 3 DEBUG = YES HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat MAX_CONCURRENT_SSH = 10 USE_PROGRESSBARS = YES PEERGROUP_TIMEOUT = 2400 s TOPOLOGY_OUTPUT_FILE = line_topo_initial MAX_OUTSTANDING_CONNECTIONS = 75 #SINGLE_PEERINFO_PER_HOST = YES #NUM_PEERINFO_PER_HOST = 10 #SINGLE_STATISTICS_PER_HOST = YES #NUM_STATISTICS_PER_HOST = 10 DELETE_FILES = YES [test_dht_topo] CONNECTION_LIMIT = 5 #DATA_OUTPUT_FILE=data_output [namestore] AUTOSTART = NO [nse] WORKDELAY = 500 ms INTERVAL = 60 s WORKBITS = 0 gnunet-0.9.3/src/dht/Makefile.in0000644000175000017500000012536211762217211013370 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-service-dht$(EXEEXT) gnunet-dht-monitor$(EXEEXT) \ gnunet-dht-get$(EXEEXT) gnunet-dht-put$(EXEEXT) check_PROGRAMS = test_dht_api$(EXEEXT) test_dht_twopeer$(EXEEXT) \ test_dht_twopeer_put_get$(EXEEXT) \ test_dht_twopeer_get_put$(EXEEXT) \ test_dht_twopeer_path_tracking$(EXEEXT) \ test_dht_multipeer$(EXEEXT) test_dht_line$(EXEEXT) \ test_dht_2dtorus$(EXEEXT) test_dht_monitor$(EXEEXT) @ENABLE_TEST_RUN_TRUE@TESTS = test_dht_api$(EXEEXT) $(check_SCRIPTS) \ @ENABLE_TEST_RUN_TRUE@ test_dht_twopeer$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_dht_twopeer_put_get$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_dht_twopeer_get_put$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_dht_twopeer_path_tracking$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_dht_multipeer$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_dht_line$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_dht_2dtorus$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_dht_monitor$(EXEEXT) subdir = src/dht DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/dht.conf.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = dht.conf CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \ "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) $(plugin_LTLIBRARIES) am_libgnunet_plugin_block_dht_la_OBJECTS = plugin_block_dht.lo libgnunet_plugin_block_dht_la_OBJECTS = \ $(am_libgnunet_plugin_block_dht_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunet_plugin_block_dht_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) \ $(libgnunet_plugin_block_dht_la_LDFLAGS) $(LDFLAGS) -o $@ am__DEPENDENCIES_1 = libgnunetdht_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_libgnunetdht_la_OBJECTS = dht_api.lo libgnunetdht_la_OBJECTS = $(am_libgnunetdht_la_OBJECTS) libgnunetdht_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetdht_la_LDFLAGS) $(LDFLAGS) \ -o $@ PROGRAMS = $(bin_PROGRAMS) am_gnunet_dht_get_OBJECTS = gnunet-dht-get.$(OBJEXT) gnunet_dht_get_OBJECTS = $(am_gnunet_dht_get_OBJECTS) am_gnunet_dht_monitor_OBJECTS = gnunet-dht-monitor.$(OBJEXT) gnunet_dht_monitor_OBJECTS = $(am_gnunet_dht_monitor_OBJECTS) am_gnunet_dht_put_OBJECTS = gnunet-dht-put.$(OBJEXT) gnunet_dht_put_OBJECTS = $(am_gnunet_dht_put_OBJECTS) am_gnunet_service_dht_OBJECTS = gnunet-service-dht.$(OBJEXT) \ gnunet-service-dht_clients.$(OBJEXT) \ gnunet-service-dht_datacache.$(OBJEXT) \ gnunet-service-dht_hello.$(OBJEXT) \ gnunet-service-dht_nse.$(OBJEXT) \ gnunet-service-dht_neighbours.$(OBJEXT) \ gnunet-service-dht_routing.$(OBJEXT) gnunet_service_dht_OBJECTS = $(am_gnunet_service_dht_OBJECTS) gnunet_service_dht_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/nse/libgnunetnse.la \ $(top_builddir)/src/ats/libgnunetats.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/block/libgnunetblock.la \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_dht_2dtorus_OBJECTS = test_dht_topo.$(OBJEXT) test_dht_2dtorus_OBJECTS = $(am_test_dht_2dtorus_OBJECTS) am_test_dht_api_OBJECTS = test_dht_api.$(OBJEXT) test_dht_api_OBJECTS = $(am_test_dht_api_OBJECTS) am_test_dht_line_OBJECTS = test_dht_topo.$(OBJEXT) test_dht_line_OBJECTS = $(am_test_dht_line_OBJECTS) am_test_dht_monitor_OBJECTS = test_dht_monitor.$(OBJEXT) test_dht_monitor_OBJECTS = $(am_test_dht_monitor_OBJECTS) am_test_dht_multipeer_OBJECTS = test_dht_multipeer.$(OBJEXT) test_dht_multipeer_OBJECTS = $(am_test_dht_multipeer_OBJECTS) am_test_dht_twopeer_OBJECTS = test_dht_twopeer.$(OBJEXT) test_dht_twopeer_OBJECTS = $(am_test_dht_twopeer_OBJECTS) am_test_dht_twopeer_get_put_OBJECTS = \ test_dht_twopeer_get_put.$(OBJEXT) test_dht_twopeer_get_put_OBJECTS = \ $(am_test_dht_twopeer_get_put_OBJECTS) test_dht_twopeer_get_put_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/dht/libgnunetdht.la am_test_dht_twopeer_path_tracking_OBJECTS = \ test_dht_twopeer_path_tracking.$(OBJEXT) test_dht_twopeer_path_tracking_OBJECTS = \ $(am_test_dht_twopeer_path_tracking_OBJECTS) test_dht_twopeer_path_tracking_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/dht/libgnunetdht.la am_test_dht_twopeer_put_get_OBJECTS = \ test_dht_twopeer_put_get.$(OBJEXT) test_dht_twopeer_put_get_OBJECTS = \ $(am_test_dht_twopeer_put_get_OBJECTS) test_dht_twopeer_put_get_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/dht/libgnunetdht.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunet_plugin_block_dht_la_SOURCES) \ $(libgnunetdht_la_SOURCES) $(gnunet_dht_get_SOURCES) \ $(gnunet_dht_monitor_SOURCES) $(gnunet_dht_put_SOURCES) \ $(gnunet_service_dht_SOURCES) $(test_dht_2dtorus_SOURCES) \ $(test_dht_api_SOURCES) $(test_dht_line_SOURCES) \ $(test_dht_monitor_SOURCES) $(test_dht_multipeer_SOURCES) \ $(test_dht_twopeer_SOURCES) \ $(test_dht_twopeer_get_put_SOURCES) \ $(test_dht_twopeer_path_tracking_SOURCES) \ $(test_dht_twopeer_put_get_SOURCES) DIST_SOURCES = $(libgnunet_plugin_block_dht_la_SOURCES) \ $(libgnunetdht_la_SOURCES) $(gnunet_dht_get_SOURCES) \ $(gnunet_dht_monitor_SOURCES) $(gnunet_dht_put_SOURCES) \ $(gnunet_service_dht_SOURCES) $(test_dht_2dtorus_SOURCES) \ $(test_dht_api_SOURCES) $(test_dht_line_SOURCES) \ $(test_dht_monitor_SOURCES) $(test_dht_multipeer_SOURCES) \ $(test_dht_twopeer_SOURCES) \ $(test_dht_twopeer_get_put_SOURCES) \ $(test_dht_twopeer_path_tracking_SOURCES) \ $(test_dht_twopeer_put_get_SOURCES) DATA = $(pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -lole32 -lshell32 -liconv -lstdc++ -lcomdlg32 -lgdi32 plugindir = $(libdir)/gnunet pkgcfgdir = $(pkgdatadir)/config.d/ pkgcfg_DATA = \ dht.conf @HAVE_ZLIB_TRUE@ZLIB_LNK = -lz @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @USE_COVERAGE_TRUE@XLIB = -lgcov lib_LTLIBRARIES = \ libgnunetdht.la libgnunetdht_la_SOURCES = \ dht_api.c dht.h libgnunetdht_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(XLIB) libgnunetdht_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 1:0:1 plugin_LTLIBRARIES = \ libgnunet_plugin_block_dht.la libgnunet_plugin_block_dht_la_SOURCES = \ plugin_block_dht.c libgnunet_plugin_block_dht_la_LIBADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/block/libgnunetblock.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_block_dht_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_block_dht_la_DEPENDENCIES = \ $(top_builddir)/src/block/libgnunetblock.la gnunet_service_dht_SOURCES = \ gnunet-service-dht.c gnunet-service-dht.h \ gnunet-service-dht_clients.c gnunet-service-dht_clients.h \ gnunet-service-dht_datacache.c gnunet-service-dht_datacache.h \ gnunet-service-dht_hello.c gnunet-service-dht_hello.h \ gnunet-service-dht_nse.c gnunet-service-dht_nse.h \ gnunet-service-dht_neighbours.c gnunet-service-dht_neighbours.h \ gnunet-service-dht_routing.c gnunet-service-dht_routing.h gnunet_service_dht_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/nse/libgnunetnse.la \ $(top_builddir)/src/ats/libgnunetats.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/block/libgnunetblock.la \ $(top_builddir)/src/datacache/libgnunetdatacache.la \ $(top_builddir)/src/util/libgnunetutil.la \ -lm gnunet_dht_get_SOURCES = \ gnunet-dht-get.c gnunet_dht_get_LDADD = \ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la gnunet_dht_get_DEPENDENCIES = \ libgnunetdht.la gnunet_dht_put_SOURCES = \ gnunet-dht-put.c gnunet_dht_put_LDADD = \ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la gnunet_dht_put_DEPENDENCIES = \ libgnunetdht.la gnunet_dht_monitor_SOURCES = \ gnunet-dht-monitor.c gnunet_dht_monitor_LDADD = \ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la gnunet_dht_monitor_DEPENDENCIES = \ libgnunetdht.la test_dht_api_SOURCES = \ test_dht_api.c test_dht_api_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_api_DEPENDENCIES = \ libgnunetdht.la test_dht_twopeer_SOURCES = \ test_dht_twopeer.c test_dht_twopeer_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_twopeer_DEPENDENCIES = \ libgnunetdht.la test_dht_twopeer_put_get_SOURCES = \ test_dht_twopeer_put_get.c test_dht_twopeer_put_get_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_twopeer_get_put_SOURCES = \ test_dht_twopeer_get_put.c test_dht_twopeer_get_put_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_twopeer_path_tracking_SOURCES = \ test_dht_twopeer_path_tracking.c test_dht_twopeer_path_tracking_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_multipeer_SOURCES = \ test_dht_multipeer.c test_dht_multipeer_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_multipeer_DEPENDENCIES = \ libgnunetdht.la test_dht_2dtorus_SOURCES = \ test_dht_topo.c test_dht_2dtorus_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_2dtorus_DEPENDENCIES = \ libgnunetdht.la test_dht_line_SOURCES = \ test_dht_topo.c test_dht_line_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_line_DEPENDENCIES = \ libgnunetdht.la test_dht_monitor_SOURCES = test_dht_monitor.c test_dht_monitor_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_monitor_DEPENDENCIES = \ libgnunetdht.la EXTRA_DIST = \ $(check_SCRIPTS) \ test_dht_api_data.conf \ test_dht_api_peer1.conf \ test_dht_twopeer_data.conf \ test_dht_multipeer_data.conf \ test_dht_2dtorus.conf \ test_dht_line.conf \ multipeer_topo.dat check_SCRIPTS = \ test_dht_tools.sh all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/dht/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/dht/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): dht.conf: $(top_builddir)/config.status $(srcdir)/dht.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ } uninstall-pluginLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ done clean-pluginLTLIBRARIES: -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunet_plugin_block_dht.la: $(libgnunet_plugin_block_dht_la_OBJECTS) $(libgnunet_plugin_block_dht_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_block_dht_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_block_dht_la_OBJECTS) $(libgnunet_plugin_block_dht_la_LIBADD) $(LIBS) libgnunetdht.la: $(libgnunetdht_la_OBJECTS) $(libgnunetdht_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetdht_la_LINK) -rpath $(libdir) $(libgnunetdht_la_OBJECTS) $(libgnunetdht_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-dht-get$(EXEEXT): $(gnunet_dht_get_OBJECTS) $(gnunet_dht_get_DEPENDENCIES) @rm -f gnunet-dht-get$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_dht_get_OBJECTS) $(gnunet_dht_get_LDADD) $(LIBS) gnunet-dht-monitor$(EXEEXT): $(gnunet_dht_monitor_OBJECTS) $(gnunet_dht_monitor_DEPENDENCIES) @rm -f gnunet-dht-monitor$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_dht_monitor_OBJECTS) $(gnunet_dht_monitor_LDADD) $(LIBS) gnunet-dht-put$(EXEEXT): $(gnunet_dht_put_OBJECTS) $(gnunet_dht_put_DEPENDENCIES) @rm -f gnunet-dht-put$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_dht_put_OBJECTS) $(gnunet_dht_put_LDADD) $(LIBS) gnunet-service-dht$(EXEEXT): $(gnunet_service_dht_OBJECTS) $(gnunet_service_dht_DEPENDENCIES) @rm -f gnunet-service-dht$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_service_dht_OBJECTS) $(gnunet_service_dht_LDADD) $(LIBS) test_dht_2dtorus$(EXEEXT): $(test_dht_2dtorus_OBJECTS) $(test_dht_2dtorus_DEPENDENCIES) @rm -f test_dht_2dtorus$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_dht_2dtorus_OBJECTS) $(test_dht_2dtorus_LDADD) $(LIBS) test_dht_api$(EXEEXT): $(test_dht_api_OBJECTS) $(test_dht_api_DEPENDENCIES) @rm -f test_dht_api$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_dht_api_OBJECTS) $(test_dht_api_LDADD) $(LIBS) test_dht_line$(EXEEXT): $(test_dht_line_OBJECTS) $(test_dht_line_DEPENDENCIES) @rm -f test_dht_line$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_dht_line_OBJECTS) $(test_dht_line_LDADD) $(LIBS) test_dht_monitor$(EXEEXT): $(test_dht_monitor_OBJECTS) $(test_dht_monitor_DEPENDENCIES) @rm -f test_dht_monitor$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_dht_monitor_OBJECTS) $(test_dht_monitor_LDADD) $(LIBS) test_dht_multipeer$(EXEEXT): $(test_dht_multipeer_OBJECTS) $(test_dht_multipeer_DEPENDENCIES) @rm -f test_dht_multipeer$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_dht_multipeer_OBJECTS) $(test_dht_multipeer_LDADD) $(LIBS) test_dht_twopeer$(EXEEXT): $(test_dht_twopeer_OBJECTS) $(test_dht_twopeer_DEPENDENCIES) @rm -f test_dht_twopeer$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_dht_twopeer_OBJECTS) $(test_dht_twopeer_LDADD) $(LIBS) test_dht_twopeer_get_put$(EXEEXT): $(test_dht_twopeer_get_put_OBJECTS) $(test_dht_twopeer_get_put_DEPENDENCIES) @rm -f test_dht_twopeer_get_put$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_dht_twopeer_get_put_OBJECTS) $(test_dht_twopeer_get_put_LDADD) $(LIBS) test_dht_twopeer_path_tracking$(EXEEXT): $(test_dht_twopeer_path_tracking_OBJECTS) $(test_dht_twopeer_path_tracking_DEPENDENCIES) @rm -f test_dht_twopeer_path_tracking$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_dht_twopeer_path_tracking_OBJECTS) $(test_dht_twopeer_path_tracking_LDADD) $(LIBS) test_dht_twopeer_put_get$(EXEEXT): $(test_dht_twopeer_put_get_OBJECTS) $(test_dht_twopeer_put_get_DEPENDENCIES) @rm -f test_dht_twopeer_put_get$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_dht_twopeer_put_get_OBJECTS) $(test_dht_twopeer_put_get_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dht_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-dht-get.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-dht-monitor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-dht-put.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-dht.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-dht_clients.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-dht_datacache.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-dht_hello.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-dht_neighbours.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-dht_nse.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-dht_routing.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_block_dht.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_dht_api.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_dht_monitor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_dht_multipeer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_dht_topo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_dht_twopeer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_dht_twopeer_get_put.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_dht_twopeer_path_tracking.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_dht_twopeer_put_get.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgcfgDATA: $(pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(check_SCRIPTS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool clean-pluginLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgcfgDATA install-pluginLTLIBRARIES install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool clean-pluginLTLIBRARIES \ ctags distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-libLTLIBRARIES \ install-man install-pdf install-pdf-am install-pkgcfgDATA \ install-pluginLTLIBRARIES install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/dht/test_dht_multipeer_data.conf0000644000175000017500000000425711761764656017111 00000000000000[fs] AUTOSTART = NO [resolver] AUTOSTART = NO [dht] DEBUG = NO STOP_ON_CLOSEST = YES AUTOSTART = YES ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; #BINARY = /home/mrwiggles/documents/research/gnunet/gnunet-ng/src/dht/.libs/gnunet-service-dht #PREFIX = xterm -T dht -e gdb --args #PREFIX = valgrind --log-file=dht_%p CONFIG = $DEFAULTCONFIG HOME = $SERVICEHOME HOSTNAME = localhost PORT = 12100 STOP_FOUND = YES USE_MAX_HOPS = YES MAX_HOPS = 16 CONVERGE_BINARY = YES CONVERGE_MODIFIER = 4 [block] plugins = test dht [dhtcache] QUOTA = 1 MB DATABASE = sqlite [transport] PLUGINS = tcp DEBUG = NO ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; NEIGHBOUR_LIMIT = 50 BINARY = gnunet-service-transport CONFIG = $DEFAULTCONFIG HOME = $SERVICEHOME HOSTNAME = localhost PORT = 12365 [DHTLOG] PLUGIN = mysql_dump [ats] WAN_QUOTA_IN = 1 GB WAN_QUOTA_OUT = 1 GB [core] ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; BINARY = gnunet-service-core CONFIG = $DEFAULTCONFIG HOME = $SERVICEHOME HOSTNAME = localhost PORT = 12092 DEBUG = NO [arm] DEFAULTSERVICES = dht core ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; BINARY = gnunet-service-arm CONFIG = $DEFAULTCONFIG HOME = $SERVICEHOME HOSTNAME = localhost PORT = 12366 DEBUG = NO [transport-tcp] TIMEOUT = 300 s PORT = 12368 BINDTO = 127.0.0.1 [DHT_TESTING] MYSQL_LOGGING_EXTENDED = NO MYSQL_LOGGING = NO NUM_GETS = 5 NUM_PUTS = 5 [TESTING] TOPOLOGY = FROM_FILE # file contains a ring CONNECT_TOPOLOGY = NONE # None == use all allowed connections # BLACKLIST_TOPOLOGY = X # No additional restrictions... TOPOLOGY_FILE = multipeer_topo.dat MAX_CONCURRENT_SSH = 1 PEERGROUP_TIMEOUT = 2400 s USE_PROGRESSBARS = YES #CONNECT_TOPOLOGY_OPTION = CONNECT_RANDOM_SUBSET #CONNECT_TOPOLOGY_OPTION_MODIFIER = 2 #LOGNMODIFIER = .65 #PERCENTAGE = .75 WEAKRANDOM = YES NUM_PEERS = 10 HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat [gnunetd] HOSTKEY = $SERVICEHOME/.hostkey [PATHS] DEFAULTCONFIG = test_dht_multipeer_data.conf SERVICEHOME = /tmp/test-dht-multipeer/ [nat] DISABLEV6 = YES ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 USE_LOCALADDR = YES [dns] AUTOSTART = NO [namestore] AUTOSTART = NO [nse] AUTOSTART = NO gnunet-0.9.3/src/dht/test_dht_api_data.conf0000644000175000017500000000176711725220530015631 00000000000000[PATHS] SERVICEHOME = /tmp/test-dht-api/ DEFAULTCONFIG = test_dht_api_data.conf [fs] AUTOSTART = NO [resolver] AUTOSTART = NO [datastore-sqlite] FILENAME = $SERVICEHOME/datastore/sqlite.db [datastore] AUTOSTART = NO [topology] TARGET-CONNECTION-COUNT = 16 AUTOCONNECT = YES FRIENDS-ONLY = NO MINIMUM-FRIENDS = 0 [ats] WAN_QUOTA_IN = 1 GB WAN_QUOTA_OUT = 1 GB [core] PORT = 2092 [dht] DEBUG = NO PORT = 12370 [block] plugins = dht test [transport] plugins = tcp DEBUG = NO NEIGHBOUR_LIMIT = 50 PORT = 2091 [peerinfo] PORT = 2090 [resolver] PORT = 2089 [statistics] PORT = 2088 [arm] DEFAULTSERVICES = PORT = 2087 [transport-tcp] TIMEOUT = 300 s PORT = 2094 [TESTING] WEAKRANDOM = NO HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat [gnunetd] HOSTKEY = $SERVICEHOME/.hostkey [nat] DISABLEV6 = YES BINDTO = 127.0.0.1 ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 [dns] AUTOSTART = NO [namestore] AUTOSTART = NO [nse] AUTOSTART = NO gnunet-0.9.3/src/dht/gnunet-service-dht_hello.c0000644000175000017500000000716611760502551016370 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/gnunet-service-dht_hello.c * @brief GNUnet DHT integration with peerinfo * @author Christian Grothoff * * TODO: * - consider adding mechanism to remove expired HELLOs */ #include "platform.h" #include "gnunet-service-dht.h" #include "gnunet-service-dht_hello.h" #include "gnunet_peerinfo_service.h" /** * Handle for peerinfo notifications. */ static struct GNUNET_PEERINFO_NotifyContext *pnc; /** * Hash map of peers to HELLOs. */ static struct GNUNET_CONTAINER_MultiHashMap *peer_to_hello; /** * Obtain a peer's HELLO if available * * @param peer peer to look for a HELLO from * @return HELLO for the given peer */ const struct GNUNET_HELLO_Message * GDS_HELLO_get (const struct GNUNET_PeerIdentity *peer) { if (NULL == peer_to_hello) return NULL; return GNUNET_CONTAINER_multihashmap_get (peer_to_hello, &peer->hashPubKey); } /** * Function called for each HELLO known to PEERINFO. * * @param cls closure * @param peer id of the peer, NULL for last call * @param hello hello message for the peer (can be NULL) * @param err_msg error message (not used) */ static void process_hello (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Message *hello, const char *err_msg) { struct GNUNET_TIME_Absolute ex; struct GNUNET_HELLO_Message *hm; if (hello == NULL) return; ex = GNUNET_HELLO_get_last_expiration (hello); if (GNUNET_TIME_absolute_get_remaining (ex).rel_value == 0) return; GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# HELLOs obtained from peerinfo"), 1, GNUNET_NO); hm = GNUNET_CONTAINER_multihashmap_get (peer_to_hello, &peer->hashPubKey); GNUNET_free_non_null (hm); hm = GNUNET_malloc (GNUNET_HELLO_size (hello)); memcpy (hm, hello, GNUNET_HELLO_size (hello)); GNUNET_assert (GNUNET_SYSERR != GNUNET_CONTAINER_multihashmap_put (peer_to_hello, &peer->hashPubKey, hm, GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE)); } /** * Initialize HELLO subsystem. */ void GDS_HELLO_init () { pnc = GNUNET_PEERINFO_notify (GDS_cfg, &process_hello, NULL); peer_to_hello = GNUNET_CONTAINER_multihashmap_create (256); } /** * Free memory occopied by the HELLO. */ static int free_hello (void *cls, const GNUNET_HashCode * key, void *hello) { GNUNET_free (hello); return GNUNET_OK; } /** * Shutdown HELLO subsystem. */ void GDS_HELLO_done () { if (NULL != pnc) { GNUNET_PEERINFO_notify_cancel (pnc); pnc = NULL; } if (NULL != peer_to_hello) { GNUNET_CONTAINER_multihashmap_iterate (peer_to_hello, &free_hello, NULL); GNUNET_CONTAINER_multihashmap_destroy (peer_to_hello); } } /* end of gnunet-service-dht_hello.c */ gnunet-0.9.3/src/dht/multipeer_topo.dat0000644000175000017500000000020111641421314015041 0000000000000010 1:2 2:3 3:4 4:5 5:6 6:7 7:8 8:9 9:10 10:1 4:2 5:3 6:4 7:5 8:6 9:7 10:8 1:9 2:10 3:1 6:2 7:3 8:4 9:5 10:6 1:7 2:8 3:9 4:10 5:1 gnunet-0.9.3/src/dht/gnunet-service-dht_hello.h0000644000175000017500000000266111760502551016370 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/gnunet-service-dht_hello.h * @brief GNUnet DHT integration with peerinfo * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_DHT_HELLO_H #define GNUNET_SERVICE_DHT_HELLO_H #include "gnunet_util_lib.h" #include "gnunet_hello_lib.h" /** * Obtain a peer's HELLO if available * * @param peer peer to look for a HELLO from * @return HELLO for the given peer */ const struct GNUNET_HELLO_Message * GDS_HELLO_get (const struct GNUNET_PeerIdentity *peer); /** * Initialize HELLO subsystem. */ void GDS_HELLO_init (void); /** * Shutdown HELLO subsystem. */ void GDS_HELLO_done (void); #endif gnunet-0.9.3/src/dht/gnunet-service-dht_nse.h0000644000175000017500000000237111760502551016050 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dht/gnunet-service-dht_nse.h * @brief GNUnet DHT integration with NSE * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_DHT_NSE_H #define GNUNET_SERVICE_DHT_NSE_H /** * Return the log of the current network size estimate. * * @return log of NSE */ double GDS_NSE_get (void); /** * Initialize NSE subsystem. */ void GDS_NSE_init (void); /** * Shutdown NSE subsystem. */ void GDS_NSE_done (void); #endif gnunet-0.9.3/src/stream/0000755000175000017500000000000011763406751012120 500000000000000gnunet-0.9.3/src/stream/README0000644000175000017500000000110411734113251012700 00000000000000Stream library provides stream connections between peers in GNUnet. This is a convenience library which hides the complexity of dividing data stream into packets, transmitting them and retransmitting them in case of communication errors. This library's API are similar to unix PIPE API. The user is expected to open a stream to a listening target peer. Once the stream is established, the user can use it as a pipe. Any data written into the stream at one peer will be readable by the other peer and vice versa. This library uses mesh API for establishing tunnels between peers.gnunet-0.9.3/src/stream/stream_api.c0000644000175000017500000031332611760502551014330 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* TODO: * * Checks for matching the sender and socket->other_peer in server * message handlers * * Add code for write io timeout * * Include retransmission for control messages **/ /** * @file stream/stream_api.c * @brief Implementation of the stream library * @author Sree Harsha Totakura */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_crypto_lib.h" #include "gnunet_stream_lib.h" #include "stream_protocol.h" #define LOG(kind,...) \ GNUNET_log_from (kind, "stream-api", __VA_ARGS__) /** * The maximum packet size of a stream packet */ #define MAX_PACKET_SIZE 64000 /** * Receive buffer */ #define RECEIVE_BUFFER_SIZE 4096000 /** * The maximum payload a data message packet can carry */ static size_t max_payload_size = MAX_PACKET_SIZE - sizeof (struct GNUNET_STREAM_DataMessage); /** * states in the Protocol */ enum State { /** * Client initialization state */ STATE_INIT, /** * Listener initialization state */ STATE_LISTEN, /** * Pre-connection establishment state */ STATE_HELLO_WAIT, /** * State where a connection has been established */ STATE_ESTABLISHED, /** * State where the socket is closed on our side and waiting to be ACK'ed */ STATE_RECEIVE_CLOSE_WAIT, /** * State where the socket is closed for reading */ STATE_RECEIVE_CLOSED, /** * State where the socket is closed on our side and waiting to be ACK'ed */ STATE_TRANSMIT_CLOSE_WAIT, /** * State where the socket is closed for writing */ STATE_TRANSMIT_CLOSED, /** * State where the socket is closed on our side and waiting to be ACK'ed */ STATE_CLOSE_WAIT, /** * State where the socket is closed */ STATE_CLOSED }; /** * Functions of this type are called when a message is written * * @param cls the closure from queue_message * @param socket the socket the written message was bound to */ typedef void (*SendFinishCallback) (void *cls, struct GNUNET_STREAM_Socket *socket); /** * The send message queue */ struct MessageQueue { /** * The message */ struct GNUNET_STREAM_MessageHeader *message; /** * Callback to be called when the message is sent */ SendFinishCallback finish_cb; /** * The closure for finish_cb */ void *finish_cb_cls; /** * The next message in queue. Should be NULL in the last message */ struct MessageQueue *next; /** * The next message in queue. Should be NULL in the first message */ struct MessageQueue *prev; }; /** * The STREAM Socket Handler */ struct GNUNET_STREAM_Socket { /** * Retransmission timeout */ struct GNUNET_TIME_Relative retransmit_timeout; /** * The Acknowledgement Bitmap */ GNUNET_STREAM_AckBitmap ack_bitmap; /** * Time when the Acknowledgement was queued */ struct GNUNET_TIME_Absolute ack_time_registered; /** * Queued Acknowledgement deadline */ struct GNUNET_TIME_Relative ack_time_deadline; /** * The mesh handle */ struct GNUNET_MESH_Handle *mesh; /** * The mesh tunnel handle */ struct GNUNET_MESH_Tunnel *tunnel; /** * Stream open closure */ void *open_cls; /** * Stream open callback */ GNUNET_STREAM_OpenCallback open_cb; /** * The current transmit handle (if a pending transmit request exists) */ struct GNUNET_MESH_TransmitHandle *transmit_handle; /** * The current act transmit handle (if a pending ack transmit request exists) */ struct GNUNET_MESH_TransmitHandle *ack_transmit_handle; /** * Pointer to the current ack message using in ack_task */ struct GNUNET_STREAM_AckMessage *ack_msg; /** * The current message associated with the transmit handle */ struct MessageQueue *queue_head; /** * The queue tail, should always point to the last message in queue */ struct MessageQueue *queue_tail; /** * The write IO_handle associated with this socket */ struct GNUNET_STREAM_IOWriteHandle *write_handle; /** * The read IO_handle associated with this socket */ struct GNUNET_STREAM_IOReadHandle *read_handle; /** * The shutdown handle associated with this socket */ struct GNUNET_STREAM_ShutdownHandle *shutdown_handle; /** * Buffer for storing received messages */ void *receive_buffer; /** * The listen socket from which this socket is derived. Should be NULL if it * is not a derived socket */ struct GNUNET_STREAM_ListenSocket *lsocket; /** * The peer identity of the peer at the other end of the stream */ struct GNUNET_PeerIdentity other_peer; /** * Task identifier for the read io timeout task */ GNUNET_SCHEDULER_TaskIdentifier read_io_timeout_task_id; /** * Task identifier for retransmission task after timeout */ GNUNET_SCHEDULER_TaskIdentifier retransmission_timeout_task_id; /** * The task for sending timely Acks */ GNUNET_SCHEDULER_TaskIdentifier ack_task_id; /** * Task scheduled to continue a read operation. */ GNUNET_SCHEDULER_TaskIdentifier read_task_id; /** * The state of the protocol associated with this socket */ enum State state; /** * The status of the socket */ enum GNUNET_STREAM_Status status; /** * The number of previous timeouts; FIXME: currently not used */ unsigned int retries; /** * The application port number (type: uint32_t) */ GNUNET_MESH_ApplicationType app_port; /** * The session id associated with this stream connection * FIXME: Not used currently, may be removed */ uint32_t session_id; /** * Write sequence number. Set to random when sending HELLO(client) and * HELLO_ACK(server) */ uint32_t write_sequence_number; /** * Read sequence number. This number's value is determined during handshake */ uint32_t read_sequence_number; /** * The receiver buffer size */ uint32_t receive_buffer_size; /** * The receiver buffer boundaries */ uint32_t receive_buffer_boundaries[GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH]; /** * receiver's available buffer after the last acknowledged packet */ uint32_t receiver_window_available; /** * The offset pointer used during write operation */ uint32_t write_offset; /** * The offset after which we are expecting data */ uint32_t read_offset; /** * The offset upto which user has read from the received buffer */ uint32_t copy_offset; }; /** * A socket for listening */ struct GNUNET_STREAM_ListenSocket { /** * The mesh handle */ struct GNUNET_MESH_Handle *mesh; /** * The callback function which is called after successful opening socket */ GNUNET_STREAM_ListenCallback listen_cb; /** * The call back closure */ void *listen_cb_cls; /** * The service port * FIXME: Remove if not required! */ GNUNET_MESH_ApplicationType port; }; /** * The IO Write Handle */ struct GNUNET_STREAM_IOWriteHandle { /** * The socket to which this write handle is associated */ struct GNUNET_STREAM_Socket *socket; /** * The packet_buffers associated with this Handle */ struct GNUNET_STREAM_DataMessage *messages[GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH]; /** * The write continuation callback */ GNUNET_STREAM_CompletionContinuation write_cont; /** * Write continuation closure */ void *write_cont_cls; /** * The bitmap of this IOHandle; Corresponding bit for a message is set when * it has been acknowledged by the receiver */ GNUNET_STREAM_AckBitmap ack_bitmap; /** * Number of bytes in this write handle */ size_t size; }; /** * The IO Read Handle */ struct GNUNET_STREAM_IOReadHandle { /** * Callback for the read processor */ GNUNET_STREAM_DataProcessor proc; /** * The closure pointer for the read processor callback */ void *proc_cls; }; /** * Handle for Shutdown */ struct GNUNET_STREAM_ShutdownHandle { /** * The socket associated with this shutdown handle */ struct GNUNET_STREAM_Socket *socket; /** * Shutdown completion callback */ GNUNET_STREAM_ShutdownCompletion completion_cb; /** * Closure for completion callback */ void *completion_cls; /** * Close message retransmission task id */ GNUNET_SCHEDULER_TaskIdentifier close_msg_retransmission_task_id; /** * Which operation to shutdown? SHUT_RD, SHUT_WR or SHUT_RDWR */ int operation; }; /** * Default value in seconds for various timeouts */ static unsigned int default_timeout = 10; /** * Callback function for sending queued message * * @param cls closure the socket * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t send_message_notify (void *cls, size_t size, void *buf) { struct GNUNET_STREAM_Socket *socket = cls; struct MessageQueue *head; size_t ret; socket->transmit_handle = NULL; /* Remove the transmit handle */ head = socket->queue_head; if (NULL == head) return 0; /* just to be safe */ if (0 == size) /* request timed out */ { socket->retries++; LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Message sending timed out. Retry %d \n", GNUNET_i2s (&socket->other_peer), socket->retries); socket->transmit_handle = GNUNET_MESH_notify_transmit_ready (socket->tunnel, 0, /* Corking */ 1, /* Priority */ /* FIXME: exponential backoff */ socket->retransmit_timeout, &socket->other_peer, ntohs (head->message->header.size), &send_message_notify, socket); return 0; } ret = ntohs (head->message->header.size); GNUNET_assert (size >= ret); memcpy (buf, head->message, ret); if (NULL != head->finish_cb) { head->finish_cb (head->finish_cb_cls, socket); } GNUNET_CONTAINER_DLL_remove (socket->queue_head, socket->queue_tail, head); GNUNET_free (head->message); GNUNET_free (head); head = socket->queue_head; if (NULL != head) /* more pending messages to send */ { socket->retries = 0; socket->transmit_handle = GNUNET_MESH_notify_transmit_ready (socket->tunnel, 0, /* Corking */ 1, /* Priority */ /* FIXME: exponential backoff */ socket->retransmit_timeout, &socket->other_peer, ntohs (head->message->header.size), &send_message_notify, socket); } return ret; } /** * Queues a message for sending using the mesh connection of a socket * * @param socket the socket whose mesh connection is used * @param message the message to be sent * @param finish_cb the callback to be called when the message is sent * @param finish_cb_cls the closure for the callback */ static void queue_message (struct GNUNET_STREAM_Socket *socket, struct GNUNET_STREAM_MessageHeader *message, SendFinishCallback finish_cb, void *finish_cb_cls) { struct MessageQueue *queue_entity; GNUNET_assert ((ntohs (message->header.type) >= GNUNET_MESSAGE_TYPE_STREAM_DATA) && (ntohs (message->header.type) <= GNUNET_MESSAGE_TYPE_STREAM_CLOSE_ACK)); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Queueing message of type %d and size %d\n", GNUNET_i2s (&socket->other_peer), ntohs (message->header.type), ntohs (message->header.size)); GNUNET_assert (NULL != message); queue_entity = GNUNET_malloc (sizeof (struct MessageQueue)); queue_entity->message = message; queue_entity->finish_cb = finish_cb; queue_entity->finish_cb_cls = finish_cb_cls; GNUNET_CONTAINER_DLL_insert_tail (socket->queue_head, socket->queue_tail, queue_entity); if (NULL == socket->transmit_handle) { socket->retries = 0; socket->transmit_handle = GNUNET_MESH_notify_transmit_ready (socket->tunnel, 0, /* Corking */ 1, /* Priority */ socket->retransmit_timeout, &socket->other_peer, ntohs (message->header.size), &send_message_notify, socket); } } /** * Copies a message and queues it for sending using the mesh connection of * given socket * * @param socket the socket whose mesh connection is used * @param message the message to be sent * @param finish_cb the callback to be called when the message is sent * @param finish_cb_cls the closure for the callback */ static void copy_and_queue_message (struct GNUNET_STREAM_Socket *socket, const struct GNUNET_STREAM_MessageHeader *message, SendFinishCallback finish_cb, void *finish_cb_cls) { struct GNUNET_STREAM_MessageHeader *msg_copy; uint16_t size; size = ntohs (message->header.size); msg_copy = GNUNET_malloc (size); memcpy (msg_copy, message, size); queue_message (socket, msg_copy, finish_cb, finish_cb_cls); } /** * Callback function for sending ack message * * @param cls closure the ACK message created in ack_task * @param size number of bytes available in buffer * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t send_ack_notify (void *cls, size_t size, void *buf) { struct GNUNET_STREAM_Socket *socket = cls; if (0 == size) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s called with size 0\n", __func__); return 0; } GNUNET_assert (ntohs (socket->ack_msg->header.header.size) <= size); size = ntohs (socket->ack_msg->header.header.size); memcpy (buf, socket->ack_msg, size); GNUNET_free (socket->ack_msg); socket->ack_msg = NULL; socket->ack_transmit_handle = NULL; return size; } /** * Writes data using the given socket. The amount of data written is limited by * the receiver_window_size * * @param socket the socket to use */ static void write_data (struct GNUNET_STREAM_Socket *socket); /** * Task for retransmitting data messages if they aren't ACK before their ack * deadline * * @param cls the socket * @param tc the Task context */ static void retransmission_timeout_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_STREAM_Socket *socket = cls; if (GNUNET_SCHEDULER_REASON_SHUTDOWN == tc->reason) return; LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Retransmitting DATA...\n", GNUNET_i2s (&socket->other_peer)); socket->retransmission_timeout_task_id = GNUNET_SCHEDULER_NO_TASK; write_data (socket); } /** * Task for sending ACK message * * @param cls the socket * @param tc the Task context */ static void ack_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_STREAM_Socket *socket = cls; struct GNUNET_STREAM_AckMessage *ack_msg; if (GNUNET_SCHEDULER_REASON_SHUTDOWN == tc->reason) { return; } socket->ack_task_id = GNUNET_SCHEDULER_NO_TASK; /* Create the ACK Message */ ack_msg = GNUNET_malloc (sizeof (struct GNUNET_STREAM_AckMessage)); ack_msg->header.header.size = htons (sizeof (struct GNUNET_STREAM_AckMessage)); ack_msg->header.header.type = htons (GNUNET_MESSAGE_TYPE_STREAM_ACK); ack_msg->bitmap = GNUNET_htonll (socket->ack_bitmap); ack_msg->base_sequence_number = htonl (socket->read_sequence_number); ack_msg->receive_window_remaining = htonl (RECEIVE_BUFFER_SIZE - socket->receive_buffer_size); socket->ack_msg = ack_msg; /* Request MESH for sending ACK */ socket->ack_transmit_handle = GNUNET_MESH_notify_transmit_ready (socket->tunnel, 0, /* Corking */ 1, /* Priority */ socket->retransmit_timeout, &socket->other_peer, ntohs (ack_msg->header.header.size), &send_ack_notify, socket); } /** * Retransmission task for shutdown messages * * @param cls the shutdown handle * @param tc the Task Context */ static void close_msg_retransmission_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_STREAM_ShutdownHandle *shutdown_handle = cls; struct GNUNET_STREAM_MessageHeader *msg; struct GNUNET_STREAM_Socket *socket; GNUNET_assert (NULL != shutdown_handle); socket = shutdown_handle->socket; msg = GNUNET_malloc (sizeof (struct GNUNET_STREAM_MessageHeader)); msg->header.size = htons (sizeof (struct GNUNET_STREAM_MessageHeader)); switch (shutdown_handle->operation) { case SHUT_RDWR: msg->header.type = htons (GNUNET_MESSAGE_TYPE_STREAM_CLOSE); break; case SHUT_RD: msg->header.type = htons (GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE); break; case SHUT_WR: msg->header.type = htons (GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE); break; default: GNUNET_free (msg); shutdown_handle->close_msg_retransmission_task_id = GNUNET_SCHEDULER_NO_TASK; return; } queue_message (socket, msg, NULL, NULL); shutdown_handle->close_msg_retransmission_task_id = GNUNET_SCHEDULER_add_delayed (socket->retransmit_timeout, &close_msg_retransmission_task, shutdown_handle); } /** * Function to modify a bit in GNUNET_STREAM_AckBitmap * * @param bitmap the bitmap to modify * @param bit the bit number to modify * @param value GNUNET_YES to on, GNUNET_NO to off */ static void ackbitmap_modify_bit (GNUNET_STREAM_AckBitmap *bitmap, unsigned int bit, int value) { GNUNET_assert (bit < GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH); if (GNUNET_YES == value) *bitmap |= (1LL << bit); else *bitmap &= ~(1LL << bit); } /** * Function to check if a bit is set in the GNUNET_STREAM_AckBitmap * * @param bitmap address of the bitmap that has to be checked * @param bit the bit number to check * @return GNUNET_YES if the bit is set; GNUNET_NO if not */ static uint8_t ackbitmap_is_bit_set (const GNUNET_STREAM_AckBitmap *bitmap, unsigned int bit) { GNUNET_assert (bit < GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH); return 0 != (*bitmap & (1LL << bit)); } /** * Writes data using the given socket. The amount of data written is limited by * the receiver_window_size * * @param socket the socket to use */ static void write_data (struct GNUNET_STREAM_Socket *socket) { struct GNUNET_STREAM_IOWriteHandle *io_handle = socket->write_handle; int packet; /* Although an int, should never be negative */ int ack_packet; ack_packet = -1; /* Find the last acknowledged packet */ for (packet=0; packet < GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH; packet++) { if (GNUNET_YES == ackbitmap_is_bit_set (&io_handle->ack_bitmap, packet)) ack_packet = packet; else if (NULL == io_handle->messages[packet]) break; } /* Resend packets which weren't ack'ed */ for (packet=0; packet < ack_packet; packet++) { if (GNUNET_NO == ackbitmap_is_bit_set (&io_handle->ack_bitmap, packet)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Placing DATA message with sequence %u in send queue\n", GNUNET_i2s (&socket->other_peer), ntohl (io_handle->messages[packet]->sequence_number)); copy_and_queue_message (socket, &io_handle->messages[packet]->header, NULL, NULL); } } packet = ack_packet + 1; /* Now send new packets if there is enough buffer space */ while ( (NULL != io_handle->messages[packet]) && (socket->receiver_window_available >= ntohs (io_handle->messages[packet]->header.header.size)) ) { socket->receiver_window_available -= ntohs (io_handle->messages[packet]->header.header.size); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Placing DATA message with sequence %u in send queue\n", GNUNET_i2s (&socket->other_peer), ntohl (io_handle->messages[packet]->sequence_number)); copy_and_queue_message (socket, &io_handle->messages[packet]->header, NULL, NULL); packet++; } if (GNUNET_SCHEDULER_NO_TASK == socket->retransmission_timeout_task_id) socket->retransmission_timeout_task_id = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 8), &retransmission_timeout_task, socket); } /** * Task for calling the read processor * * @param cls the socket * @param tc the task context */ static void call_read_processor (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_STREAM_Socket *socket = cls; size_t read_size; size_t valid_read_size; unsigned int packet; uint32_t sequence_increase; uint32_t offset_increase; socket->read_task_id = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; if (NULL == socket->receive_buffer) return; GNUNET_assert (NULL != socket->read_handle); GNUNET_assert (NULL != socket->read_handle->proc); /* Check the bitmap for any holes */ for (packet=0; packet < GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH; packet++) { if (GNUNET_NO == ackbitmap_is_bit_set (&socket->ack_bitmap, packet)) break; } /* We only call read processor if we have the first packet */ GNUNET_assert (0 < packet); valid_read_size = socket->receive_buffer_boundaries[packet-1] - socket->copy_offset; GNUNET_assert (0 != valid_read_size); /* Cancel the read_io_timeout_task */ GNUNET_SCHEDULER_cancel (socket->read_io_timeout_task_id); socket->read_io_timeout_task_id = GNUNET_SCHEDULER_NO_TASK; /* Call the data processor */ LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Calling read processor\n", GNUNET_i2s (&socket->other_peer)); read_size = socket->read_handle->proc (socket->read_handle->proc_cls, socket->status, socket->receive_buffer + socket->copy_offset, valid_read_size); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Read processor read %d bytes\n", GNUNET_i2s (&socket->other_peer), read_size); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Read processor completed successfully\n", GNUNET_i2s (&socket->other_peer)); /* Free the read handle */ GNUNET_free (socket->read_handle); socket->read_handle = NULL; GNUNET_assert (read_size <= valid_read_size); socket->copy_offset += read_size; /* Determine upto which packet we can remove from the buffer */ for (packet = 0; packet < GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH; packet++) { if (socket->copy_offset == socket->receive_buffer_boundaries[packet]) { packet++; break; } if (socket->copy_offset < socket->receive_buffer_boundaries[packet]) break; } /* If no packets can be removed we can't move the buffer */ if (0 == packet) return; sequence_increase = packet; LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Sequence increase after read processor completion: %u\n", GNUNET_i2s (&socket->other_peer), sequence_increase); /* Shift the data in the receive buffer */ memmove (socket->receive_buffer, socket->receive_buffer + socket->receive_buffer_boundaries[sequence_increase-1], socket->receive_buffer_size - socket->receive_buffer_boundaries[sequence_increase-1]); /* Shift the bitmap */ socket->ack_bitmap = socket->ack_bitmap >> sequence_increase; /* Set read_sequence_number */ socket->read_sequence_number += sequence_increase; /* Set read_offset */ offset_increase = socket->receive_buffer_boundaries[sequence_increase-1]; socket->read_offset += offset_increase; /* Fix copy_offset */ GNUNET_assert (offset_increase <= socket->copy_offset); socket->copy_offset -= offset_increase; /* Fix relative boundaries */ for (packet=0; packet < GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH; packet++) { if (packet < GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH - sequence_increase) { socket->receive_buffer_boundaries[packet] = socket->receive_buffer_boundaries[packet + sequence_increase] - offset_increase; } else socket->receive_buffer_boundaries[packet] = 0; } } /** * Cancels the existing read io handle * * @param cls the closure from the SCHEDULER call * @param tc the task context */ static void read_io_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_STREAM_Socket *socket = cls; GNUNET_STREAM_DataProcessor proc; void *proc_cls; socket->read_io_timeout_task_id = GNUNET_SCHEDULER_NO_TASK; if (socket->read_task_id != GNUNET_SCHEDULER_NO_TASK) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Read task timedout - Cancelling it\n", GNUNET_i2s (&socket->other_peer)); GNUNET_SCHEDULER_cancel (socket->read_task_id); socket->read_task_id = GNUNET_SCHEDULER_NO_TASK; } GNUNET_assert (NULL != socket->read_handle); proc = socket->read_handle->proc; proc_cls = socket->read_handle->proc_cls; GNUNET_free (socket->read_handle); socket->read_handle = NULL; /* Call the read processor to signal timeout */ proc (proc_cls, GNUNET_STREAM_TIMEOUT, NULL, 0); } /** * Handler for DATA messages; Same for both client and server * * @param socket the socket through which the ack was received * @param tunnel connection to the other end * @param sender who sent the message * @param msg the data message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_data (struct GNUNET_STREAM_Socket *socket, struct GNUNET_MESH_Tunnel *tunnel, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_STREAM_DataMessage *msg, const struct GNUNET_ATS_Information*atsi) { const void *payload; uint32_t bytes_needed; uint32_t relative_offset; uint32_t relative_sequence_number; uint16_t size; size = htons (msg->header.header.size); if (size < sizeof (struct GNUNET_STREAM_DataMessage)) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (0 != memcmp (sender, &socket->other_peer, sizeof (struct GNUNET_PeerIdentity))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received DATA from non-confirming peer\n", GNUNET_i2s (&socket->other_peer)); return GNUNET_YES; } switch (socket->state) { case STATE_ESTABLISHED: case STATE_TRANSMIT_CLOSED: case STATE_TRANSMIT_CLOSE_WAIT: /* check if the message's sequence number is in the range we are expecting */ relative_sequence_number = ntohl (msg->sequence_number) - socket->read_sequence_number; if ( relative_sequence_number > GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Ignoring received message with sequence number %u\n", GNUNET_i2s (&socket->other_peer), ntohl (msg->sequence_number)); /* Start ACK sending task if one is not already present */ if (GNUNET_SCHEDULER_NO_TASK == socket->ack_task_id) { socket->ack_task_id = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_ntoh (msg->ack_deadline), &ack_task, socket); } return GNUNET_YES; } /* Check if we have already seen this message */ if (GNUNET_YES == ackbitmap_is_bit_set (&socket->ack_bitmap, relative_sequence_number)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Ignoring already received message with sequence number %u\n", GNUNET_i2s (&socket->other_peer), ntohl (msg->sequence_number)); /* Start ACK sending task if one is not already present */ if (GNUNET_SCHEDULER_NO_TASK == socket->ack_task_id) { socket->ack_task_id = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_ntoh (msg->ack_deadline), &ack_task, socket); } return GNUNET_YES; } LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Receiving DATA with sequence number: %u and size: %d from %s\n", GNUNET_i2s (&socket->other_peer), ntohl (msg->sequence_number), ntohs (msg->header.header.size), GNUNET_i2s (&socket->other_peer)); /* Check if we have to allocate the buffer */ size -= sizeof (struct GNUNET_STREAM_DataMessage); relative_offset = ntohl (msg->offset) - socket->read_offset; bytes_needed = relative_offset + size; if (bytes_needed > socket->receive_buffer_size) { if (bytes_needed <= RECEIVE_BUFFER_SIZE) { socket->receive_buffer = GNUNET_realloc (socket->receive_buffer, bytes_needed); socket->receive_buffer_size = bytes_needed; } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Cannot accommodate packet %d as buffer is full\n", GNUNET_i2s (&socket->other_peer), ntohl (msg->sequence_number)); return GNUNET_YES; } } /* Copy Data to buffer */ payload = &msg[1]; GNUNET_assert (relative_offset + size <= socket->receive_buffer_size); memcpy (socket->receive_buffer + relative_offset, payload, size); socket->receive_buffer_boundaries[relative_sequence_number] = relative_offset + size; /* Modify the ACK bitmap */ ackbitmap_modify_bit (&socket->ack_bitmap, relative_sequence_number, GNUNET_YES); /* Start ACK sending task if one is not already present */ if (GNUNET_SCHEDULER_NO_TASK == socket->ack_task_id) { socket->ack_task_id = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_ntoh (msg->ack_deadline), &ack_task, socket); } if ((NULL != socket->read_handle) /* A read handle is waiting */ /* There is no current read task */ && (GNUNET_SCHEDULER_NO_TASK == socket->read_task_id) /* We have the first packet */ && (GNUNET_YES == ackbitmap_is_bit_set(&socket->ack_bitmap, 0))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Scheduling read processor\n", GNUNET_i2s (&socket->other_peer)); socket->read_task_id = GNUNET_SCHEDULER_add_now (&call_read_processor, socket); } break; default: LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received data message when it cannot be handled\n", GNUNET_i2s (&socket->other_peer)); break; } return GNUNET_YES; } /** * Client's message Handler for GNUNET_MESSAGE_TYPE_STREAM_DATA * * @param cls the socket (set from GNUNET_MESH_connect) * @param tunnel connection to the other end * @param tunnel_ctx place to store local state associated with the tunnel * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int client_handle_data (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information*atsi) { struct GNUNET_STREAM_Socket *socket = cls; return handle_data (socket, tunnel, sender, (const struct GNUNET_STREAM_DataMessage *) message, atsi); } /** * Callback to set state to ESTABLISHED * * @param cls the closure from queue_message FIXME: document * @param socket the socket to requiring state change */ static void set_state_established (void *cls, struct GNUNET_STREAM_Socket *socket) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Attaining ESTABLISHED state\n", GNUNET_i2s (&socket->other_peer)); socket->write_offset = 0; socket->read_offset = 0; socket->state = STATE_ESTABLISHED; /* FIXME: What if listen_cb is NULL */ if (NULL != socket->lsocket) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Calling listen callback\n", GNUNET_i2s (&socket->other_peer)); if (GNUNET_SYSERR == socket->lsocket->listen_cb (socket->lsocket->listen_cb_cls, socket, &socket->other_peer)) { socket->state = STATE_CLOSED; /* FIXME: We should close in a decent way */ GNUNET_MESH_tunnel_destroy (socket->tunnel); /* Destroy the tunnel */ GNUNET_free (socket); } } else if (socket->open_cb) socket->open_cb (socket->open_cls, socket); } /** * Callback to set state to HELLO_WAIT * * @param cls the closure from queue_message * @param socket the socket to requiring state change */ static void set_state_hello_wait (void *cls, struct GNUNET_STREAM_Socket *socket) { GNUNET_assert (STATE_INIT == socket->state); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Attaining HELLO_WAIT state\n", GNUNET_i2s (&socket->other_peer)); socket->state = STATE_HELLO_WAIT; } /** * Callback to set state to CLOSE_WAIT * * @param cls the closure from queue_message * @param socket the socket requiring state change */ static void set_state_close_wait (void *cls, struct GNUNET_STREAM_Socket *socket) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Attaing CLOSE_WAIT state\n", GNUNET_i2s (&socket->other_peer)); socket->state = STATE_CLOSE_WAIT; GNUNET_free_non_null (socket->receive_buffer); /* Free the receive buffer */ socket->receive_buffer = NULL; socket->receive_buffer_size = 0; } /** * Callback to set state to RECEIVE_CLOSE_WAIT * * @param cls the closure from queue_message * @param socket the socket requiring state change */ static void set_state_receive_close_wait (void *cls, struct GNUNET_STREAM_Socket *socket) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Attaing RECEIVE_CLOSE_WAIT state\n", GNUNET_i2s (&socket->other_peer)); socket->state = STATE_RECEIVE_CLOSE_WAIT; GNUNET_free_non_null (socket->receive_buffer); /* Free the receive buffer */ socket->receive_buffer = NULL; socket->receive_buffer_size = 0; } /** * Callback to set state to TRANSMIT_CLOSE_WAIT * * @param cls the closure from queue_message * @param socket the socket requiring state change */ static void set_state_transmit_close_wait (void *cls, struct GNUNET_STREAM_Socket *socket) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Attaing TRANSMIT_CLOSE_WAIT state\n", GNUNET_i2s (&socket->other_peer)); socket->state = STATE_TRANSMIT_CLOSE_WAIT; } /** * Callback to set state to CLOSED * * @param cls the closure from queue_message * @param socket the socket requiring state change */ static void set_state_closed (void *cls, struct GNUNET_STREAM_Socket *socket) { socket->state = STATE_CLOSED; } /** * Returns a new HelloAckMessage. Also sets the write sequence number for the * socket * * @param socket the socket for which this HelloAckMessage has to be generated * @return the HelloAckMessage */ static struct GNUNET_STREAM_HelloAckMessage * generate_hello_ack_msg (struct GNUNET_STREAM_Socket *socket) { struct GNUNET_STREAM_HelloAckMessage *msg; /* Get the random sequence number */ socket->write_sequence_number = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Generated write sequence number %u\n", GNUNET_i2s (&socket->other_peer), (unsigned int) socket->write_sequence_number); msg = GNUNET_malloc (sizeof (struct GNUNET_STREAM_HelloAckMessage)); msg->header.header.size = htons (sizeof (struct GNUNET_STREAM_HelloAckMessage)); msg->header.header.type = htons (GNUNET_MESSAGE_TYPE_STREAM_HELLO_ACK); msg->sequence_number = htonl (socket->write_sequence_number); msg->receiver_window_size = htonl (RECEIVE_BUFFER_SIZE); return msg; } /** * Client's message handler for GNUNET_MESSAGE_TYPE_STREAM_HELLO_ACK * * @param cls the socket (set from GNUNET_MESH_connect) * @param tunnel connection to the other end * @param tunnel_ctx this is NULL * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int client_handle_hello_ack (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information*atsi) { struct GNUNET_STREAM_Socket *socket = cls; const struct GNUNET_STREAM_HelloAckMessage *ack_msg; struct GNUNET_STREAM_HelloAckMessage *reply; if (0 != memcmp (sender, &socket->other_peer, sizeof (struct GNUNET_PeerIdentity))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received HELLO_ACK from non-confirming peer\n", GNUNET_i2s (&socket->other_peer)); return GNUNET_YES; } ack_msg = (const struct GNUNET_STREAM_HelloAckMessage *) message; LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received HELLO_ACK from %s\n", GNUNET_i2s (&socket->other_peer), GNUNET_i2s (&socket->other_peer)); GNUNET_assert (socket->tunnel == tunnel); switch (socket->state) { case STATE_HELLO_WAIT: socket->read_sequence_number = ntohl (ack_msg->sequence_number); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Read sequence number %u\n", GNUNET_i2s (&socket->other_peer), (unsigned int) socket->read_sequence_number); socket->receiver_window_available = ntohl (ack_msg->receiver_window_size); reply = generate_hello_ack_msg (socket); queue_message (socket, &reply->header, &set_state_established, NULL); return GNUNET_OK; case STATE_ESTABLISHED: case STATE_RECEIVE_CLOSE_WAIT: // call statistics (# ACKs ignored++) return GNUNET_OK; case STATE_INIT: default: LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Server %s sent HELLO_ACK when in state %d\n", GNUNET_i2s (&socket->other_peer), GNUNET_i2s (&socket->other_peer), socket->state); socket->state = STATE_CLOSED; // introduce STATE_ERROR? return GNUNET_SYSERR; } } /** * Client's message handler for GNUNET_MESSAGE_TYPE_STREAM_RESET * * @param cls the socket (set from GNUNET_MESH_connect) * @param tunnel connection to the other end * @param tunnel_ctx this is NULL * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int client_handle_reset (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information*atsi) { // struct GNUNET_STREAM_Socket *socket = cls; return GNUNET_OK; } /** * Common message handler for handling TRANSMIT_CLOSE messages * * @param socket the socket through which the ack was received * @param tunnel connection to the other end * @param sender who sent the message * @param msg the transmit close message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_transmit_close (struct GNUNET_STREAM_Socket *socket, struct GNUNET_MESH_Tunnel *tunnel, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_STREAM_MessageHeader *msg, const struct GNUNET_ATS_Information*atsi) { struct GNUNET_STREAM_MessageHeader *reply; switch (socket->state) { case STATE_ESTABLISHED: socket->state = STATE_RECEIVE_CLOSED; /* Send TRANSMIT_CLOSE_ACK */ reply = GNUNET_malloc (sizeof (struct GNUNET_STREAM_MessageHeader)); reply->header.type = htons (GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE_ACK); reply->header.size = htons (sizeof (struct GNUNET_STREAM_MessageHeader)); queue_message (socket, reply, NULL, NULL); break; default: /* FIXME: Call statistics? */ break; } return GNUNET_YES; } /** * Client's message handler for GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE * * @param cls the socket (set from GNUNET_MESH_connect) * @param tunnel connection to the other end * @param tunnel_ctx this is NULL * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int client_handle_transmit_close (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information*atsi) { struct GNUNET_STREAM_Socket *socket = cls; return handle_transmit_close (socket, tunnel, sender, (struct GNUNET_STREAM_MessageHeader *)message, atsi); } /** * Generic handler for GNUNET_MESSAGE_TYPE_STREAM_*_CLOSE_ACK messages * * @param socket the socket * @param tunnel connection to the other end * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @param operation the close operation which is being ACK'ed * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_generic_close_ack (struct GNUNET_STREAM_Socket *socket, struct GNUNET_MESH_Tunnel *tunnel, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_STREAM_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, int operation) { struct GNUNET_STREAM_ShutdownHandle *shutdown_handle; shutdown_handle = socket->shutdown_handle; if (NULL == shutdown_handle) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received CLOSE_ACK when shutdown handle is NULL\n", GNUNET_i2s (&socket->other_peer)); return GNUNET_OK; } switch (operation) { case SHUT_RDWR: switch (socket->state) { case STATE_CLOSE_WAIT: if (SHUT_RDWR != shutdown_handle->operation) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received CLOSE_ACK when shutdown handle is not for " "SHUT_RDWR\n", GNUNET_i2s (&socket->other_peer)); return GNUNET_OK; } LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received CLOSE_ACK from %s\n", GNUNET_i2s (&socket->other_peer), GNUNET_i2s (&socket->other_peer)); socket->state = STATE_CLOSED; break; default: LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received CLOSE_ACK when in it not expected\n", GNUNET_i2s (&socket->other_peer)); return GNUNET_OK; } break; case SHUT_RD: switch (socket->state) { case STATE_RECEIVE_CLOSE_WAIT: if (SHUT_RD != shutdown_handle->operation) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received RECEIVE_CLOSE_ACK when shutdown handle " "is not for SHUT_RD\n", GNUNET_i2s (&socket->other_peer)); return GNUNET_OK; } LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received RECEIVE_CLOSE_ACK from %s\n", GNUNET_i2s (&socket->other_peer), GNUNET_i2s (&socket->other_peer)); socket->state = STATE_RECEIVE_CLOSED; break; default: LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received RECEIVE_CLOSE_ACK when in it not expected\n", GNUNET_i2s (&socket->other_peer)); return GNUNET_OK; } break; case SHUT_WR: switch (socket->state) { case STATE_TRANSMIT_CLOSE_WAIT: if (SHUT_WR != shutdown_handle->operation) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received TRANSMIT_CLOSE_ACK when shutdown handle " "is not for SHUT_WR\n", GNUNET_i2s (&socket->other_peer)); return GNUNET_OK; } LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received TRANSMIT_CLOSE_ACK from %s\n", GNUNET_i2s (&socket->other_peer), GNUNET_i2s (&socket->other_peer)); socket->state = STATE_TRANSMIT_CLOSED; break; default: LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received TRANSMIT_CLOSE_ACK when in it not expected\n", GNUNET_i2s (&socket->other_peer)); return GNUNET_OK; } break; default: GNUNET_assert (0); } if (NULL != shutdown_handle->completion_cb) /* Shutdown completion */ shutdown_handle->completion_cb(shutdown_handle->completion_cls, operation); GNUNET_free (shutdown_handle); /* Free shutdown handle */ socket->shutdown_handle = NULL; if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle->close_msg_retransmission_task_id) { GNUNET_SCHEDULER_cancel (shutdown_handle->close_msg_retransmission_task_id); shutdown_handle->close_msg_retransmission_task_id = GNUNET_SCHEDULER_NO_TASK; } return GNUNET_OK; } /** * Client's message handler for GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE_ACK * * @param cls the socket (set from GNUNET_MESH_connect) * @param tunnel connection to the other end * @param tunnel_ctx this is NULL * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int client_handle_transmit_close_ack (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information*atsi) { struct GNUNET_STREAM_Socket *socket = cls; return handle_generic_close_ack (socket, tunnel, sender, (const struct GNUNET_STREAM_MessageHeader *) message, atsi, SHUT_WR); } /** * Generic handler for GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE * * @param socket the socket * @param tunnel connection to the other end * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_receive_close (struct GNUNET_STREAM_Socket *socket, struct GNUNET_MESH_Tunnel *tunnel, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_STREAM_MessageHeader *message, const struct GNUNET_ATS_Information *atsi) { struct GNUNET_STREAM_MessageHeader *receive_close_ack; switch (socket->state) { case STATE_INIT: case STATE_LISTEN: case STATE_HELLO_WAIT: LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Ignoring RECEIVE_CLOSE as it cannot be handled now\n", GNUNET_i2s (&socket->other_peer)); return GNUNET_OK; default: break; } LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received RECEIVE_CLOSE from %s\n", GNUNET_i2s (&socket->other_peer), GNUNET_i2s (&socket->other_peer)); receive_close_ack = GNUNET_malloc (sizeof (struct GNUNET_STREAM_MessageHeader)); receive_close_ack->header.size = htons (sizeof (struct GNUNET_STREAM_MessageHeader)); receive_close_ack->header.type = htons (GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE_ACK); queue_message (socket, receive_close_ack, &set_state_closed, NULL); /* FIXME: Handle the case where write handle is present; the write operation should be deemed as finised and the write continuation callback has to be called with the stream status GNUNET_STREAM_SHUTDOWN */ return GNUNET_OK; } /** * Client's message handler for GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE * * @param cls the socket (set from GNUNET_MESH_connect) * @param tunnel connection to the other end * @param tunnel_ctx this is NULL * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int client_handle_receive_close (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information*atsi) { struct GNUNET_STREAM_Socket *socket = cls; return handle_receive_close (socket, tunnel, sender, (const struct GNUNET_STREAM_MessageHeader *) message, atsi); } /** * Client's message handler for GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE_ACK * * @param cls the socket (set from GNUNET_MESH_connect) * @param tunnel connection to the other end * @param tunnel_ctx this is NULL * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int client_handle_receive_close_ack (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information*atsi) { struct GNUNET_STREAM_Socket *socket = cls; return handle_generic_close_ack (socket, tunnel, sender, (const struct GNUNET_STREAM_MessageHeader *) message, atsi, SHUT_RD); } /** * Generic handler for GNUNET_MESSAGE_TYPE_STREAM_CLOSE * * @param socket the socket * @param tunnel connection to the other end * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_close (struct GNUNET_STREAM_Socket *socket, struct GNUNET_MESH_Tunnel *tunnel, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_STREAM_MessageHeader *message, const struct GNUNET_ATS_Information*atsi) { struct GNUNET_STREAM_MessageHeader *close_ack; switch (socket->state) { case STATE_INIT: case STATE_LISTEN: case STATE_HELLO_WAIT: LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Ignoring RECEIVE_CLOSE as it cannot be handled now\n", GNUNET_i2s (&socket->other_peer)); return GNUNET_OK; default: break; } LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received CLOSE from %s\n", GNUNET_i2s (&socket->other_peer), GNUNET_i2s (&socket->other_peer)); close_ack = GNUNET_malloc (sizeof (struct GNUNET_STREAM_MessageHeader)); close_ack->header.size = htons (sizeof (struct GNUNET_STREAM_MessageHeader)); close_ack->header.type = htons (GNUNET_MESSAGE_TYPE_STREAM_CLOSE_ACK); queue_message (socket, close_ack, &set_state_closed, NULL); if (socket->state == STATE_CLOSED) return GNUNET_OK; GNUNET_free_non_null (socket->receive_buffer); /* Free the receive buffer */ socket->receive_buffer = NULL; socket->receive_buffer_size = 0; return GNUNET_OK; } /** * Client's message handler for GNUNET_MESSAGE_TYPE_STREAM_CLOSE * * @param cls the socket (set from GNUNET_MESH_connect) * @param tunnel connection to the other end * @param tunnel_ctx this is NULL * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int client_handle_close (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information*atsi) { struct GNUNET_STREAM_Socket *socket = cls; return handle_close (socket, tunnel, sender, (const struct GNUNET_STREAM_MessageHeader *) message, atsi); } /** * Client's message handler for GNUNET_MESSAGE_TYPE_STREAM_CLOSE_ACK * * @param cls the socket (set from GNUNET_MESH_connect) * @param tunnel connection to the other end * @param tunnel_ctx this is NULL * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int client_handle_close_ack (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi) { struct GNUNET_STREAM_Socket *socket = cls; return handle_generic_close_ack (socket, tunnel, sender, (const struct GNUNET_STREAM_MessageHeader *) message, atsi, SHUT_RDWR); } /*****************************/ /* Server's Message Handlers */ /*****************************/ /** * Server's message Handler for GNUNET_MESSAGE_TYPE_STREAM_DATA * * @param cls the closure * @param tunnel connection to the other end * @param tunnel_ctx the socket * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int server_handle_data (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information*atsi) { struct GNUNET_STREAM_Socket *socket = *tunnel_ctx; return handle_data (socket, tunnel, sender, (const struct GNUNET_STREAM_DataMessage *)message, atsi); } /** * Server's message handler for GNUNET_MESSAGE_TYPE_STREAM_HELLO * * @param cls the closure * @param tunnel connection to the other end * @param tunnel_ctx the socket * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int server_handle_hello (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information*atsi) { struct GNUNET_STREAM_Socket *socket = *tunnel_ctx; struct GNUNET_STREAM_HelloAckMessage *reply; if (0 != memcmp (sender, &socket->other_peer, sizeof (struct GNUNET_PeerIdentity))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received HELLO from non-confirming peer\n", GNUNET_i2s (&socket->other_peer)); return GNUNET_YES; } GNUNET_assert (GNUNET_MESSAGE_TYPE_STREAM_HELLO == ntohs (message->type)); GNUNET_assert (socket->tunnel == tunnel); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received HELLO from %s\n", GNUNET_i2s (&socket->other_peer), GNUNET_i2s (&socket->other_peer)); if (STATE_INIT == socket->state) { reply = generate_hello_ack_msg (socket); queue_message (socket, &reply->header, &set_state_hello_wait, NULL); } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "Client sent HELLO when in state %d\n", socket->state); /* FIXME: Send RESET? */ } return GNUNET_OK; } /** * Server's message handler for GNUNET_MESSAGE_TYPE_STREAM_HELLO_ACK * * @param cls the closure * @param tunnel connection to the other end * @param tunnel_ctx the socket * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int server_handle_hello_ack (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information*atsi) { struct GNUNET_STREAM_Socket *socket = *tunnel_ctx; const struct GNUNET_STREAM_HelloAckMessage *ack_message; GNUNET_assert (GNUNET_MESSAGE_TYPE_STREAM_HELLO_ACK == ntohs (message->type)); GNUNET_assert (socket->tunnel == tunnel); ack_message = (struct GNUNET_STREAM_HelloAckMessage *) message; if (STATE_HELLO_WAIT == socket->state) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received HELLO_ACK from %s\n", GNUNET_i2s (&socket->other_peer), GNUNET_i2s (&socket->other_peer)); socket->read_sequence_number = ntohl (ack_message->sequence_number); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Read sequence number %u\n", GNUNET_i2s (&socket->other_peer), (unsigned int) socket->read_sequence_number); socket->receiver_window_available = ntohl (ack_message->receiver_window_size); /* Attain ESTABLISHED state */ set_state_established (NULL, socket); } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "Client sent HELLO_ACK when in state %d\n", socket->state); /* FIXME: Send RESET? */ } return GNUNET_OK; } /** * Server's message handler for GNUNET_MESSAGE_TYPE_STREAM_RESET * * @param cls the closure * @param tunnel connection to the other end * @param tunnel_ctx the socket * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int server_handle_reset (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information*atsi) { // struct GNUNET_STREAM_Socket *socket = *tunnel_ctx; return GNUNET_OK; } /** * Server's message handler for GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE * * @param cls the closure * @param tunnel connection to the other end * @param tunnel_ctx the socket * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int server_handle_transmit_close (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information*atsi) { struct GNUNET_STREAM_Socket *socket = *tunnel_ctx; return handle_transmit_close (socket, tunnel, sender, (struct GNUNET_STREAM_MessageHeader *)message, atsi); } /** * Server's message handler for GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE_ACK * * @param cls the closure * @param tunnel connection to the other end * @param tunnel_ctx the socket * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int server_handle_transmit_close_ack (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information*atsi) { struct GNUNET_STREAM_Socket *socket = *tunnel_ctx; return handle_generic_close_ack (socket, tunnel, sender, (const struct GNUNET_STREAM_MessageHeader *) message, atsi, SHUT_WR); } /** * Server's message handler for GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE * * @param cls the closure * @param tunnel connection to the other end * @param tunnel_ctx the socket * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int server_handle_receive_close (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information*atsi) { struct GNUNET_STREAM_Socket *socket = *tunnel_ctx; return handle_receive_close (socket, tunnel, sender, (const struct GNUNET_STREAM_MessageHeader *) message, atsi); } /** * Server's message handler for GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE_ACK * * @param cls the closure * @param tunnel connection to the other end * @param tunnel_ctx the socket * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int server_handle_receive_close_ack (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information*atsi) { struct GNUNET_STREAM_Socket *socket = *tunnel_ctx; return handle_generic_close_ack (socket, tunnel, sender, (const struct GNUNET_STREAM_MessageHeader *) message, atsi, SHUT_RD); } /** * Server's message handler for GNUNET_MESSAGE_TYPE_STREAM_CLOSE * * @param cls the listen socket (from GNUNET_MESH_connect in * GNUNET_STREAM_listen) * @param tunnel connection to the other end * @param tunnel_ctx the socket * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int server_handle_close (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information*atsi) { struct GNUNET_STREAM_Socket *socket = *tunnel_ctx; return handle_close (socket, tunnel, sender, (const struct GNUNET_STREAM_MessageHeader *) message, atsi); } /** * Server's message handler for GNUNET_MESSAGE_TYPE_STREAM_CLOSE_ACK * * @param cls the closure * @param tunnel connection to the other end * @param tunnel_ctx the socket * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int server_handle_close_ack (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information*atsi) { struct GNUNET_STREAM_Socket *socket = *tunnel_ctx; return handle_generic_close_ack (socket, tunnel, sender, (const struct GNUNET_STREAM_MessageHeader *) message, atsi, SHUT_RDWR); } /** * Handler for DATA_ACK messages * * @param socket the socket through which the ack was received * @param tunnel connection to the other end * @param sender who sent the message * @param ack the acknowledgment message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_ack (struct GNUNET_STREAM_Socket *socket, struct GNUNET_MESH_Tunnel *tunnel, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_STREAM_AckMessage *ack, const struct GNUNET_ATS_Information*atsi) { unsigned int packet; int need_retransmission; if (0 != memcmp (sender, &socket->other_peer, sizeof (struct GNUNET_PeerIdentity))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received ACK from non-confirming peer\n", GNUNET_i2s (&socket->other_peer)); return GNUNET_YES; } switch (socket->state) { case (STATE_ESTABLISHED): case (STATE_RECEIVE_CLOSED): case (STATE_RECEIVE_CLOSE_WAIT): if (NULL == socket->write_handle) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received DATA_ACK when write_handle is NULL\n", GNUNET_i2s (&socket->other_peer)); return GNUNET_OK; } /* FIXME: increment in the base sequence number is breaking current flow */ if (!((socket->write_sequence_number - ntohl (ack->base_sequence_number)) < GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received DATA_ACK with unexpected base sequence number\n", GNUNET_i2s (&socket->other_peer)); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Current write sequence: %u; Ack's base sequence: %u\n", GNUNET_i2s (&socket->other_peer), socket->write_sequence_number, ntohl (ack->base_sequence_number)); return GNUNET_OK; } /* FIXME: include the case when write_handle is cancelled - ignore the acks */ LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Received DATA_ACK from %s\n", GNUNET_i2s (&socket->other_peer), GNUNET_i2s (&socket->other_peer)); /* Cancel the retransmission task */ if (GNUNET_SCHEDULER_NO_TASK != socket->retransmission_timeout_task_id) { GNUNET_SCHEDULER_cancel (socket->retransmission_timeout_task_id); socket->retransmission_timeout_task_id = GNUNET_SCHEDULER_NO_TASK; } for (packet=0; packet < GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH; packet++) { if (NULL == socket->write_handle->messages[packet]) break; if (ntohl (ack->base_sequence_number) >= ntohl (socket->write_handle->messages[packet]->sequence_number)) ackbitmap_modify_bit (&socket->write_handle->ack_bitmap, packet, GNUNET_YES); else if (GNUNET_YES == ackbitmap_is_bit_set (&socket->write_handle->ack_bitmap, ntohl (socket->write_handle->messages[packet]->sequence_number) - ntohl (ack->base_sequence_number))) ackbitmap_modify_bit (&socket->write_handle->ack_bitmap, packet, GNUNET_YES); } /* Update the receive window remaining FIXME : Should update with the value from a data ack with greater sequence number */ socket->receiver_window_available = ntohl (ack->receive_window_remaining); /* Check if we have received all acknowledgements */ need_retransmission = GNUNET_NO; for (packet=0; packet < GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH; packet++) { if (NULL == socket->write_handle->messages[packet]) break; if (GNUNET_YES != ackbitmap_is_bit_set (&socket->write_handle->ack_bitmap,packet)) { need_retransmission = GNUNET_YES; break; } } if (GNUNET_YES == need_retransmission) { write_data (socket); } else /* We have to call the write continuation callback now */ { /* Free the packets */ for (packet=0; packet < GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH; packet++) { GNUNET_free_non_null (socket->write_handle->messages[packet]); } if (NULL != socket->write_handle->write_cont) socket->write_handle->write_cont (socket->write_handle->write_cont_cls, socket->status, socket->write_handle->size); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Write completion callback completed\n", GNUNET_i2s (&socket->other_peer)); /* We are done with the write handle - Freeing it */ GNUNET_free (socket->write_handle); socket->write_handle = NULL; } break; default: break; } return GNUNET_OK; } /** * Handler for DATA_ACK messages * * @param cls the 'struct GNUNET_STREAM_Socket' * @param tunnel connection to the other end * @param tunnel_ctx unused * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int client_handle_ack (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information*atsi) { struct GNUNET_STREAM_Socket *socket = cls; const struct GNUNET_STREAM_AckMessage *ack = (const struct GNUNET_STREAM_AckMessage *) message; return handle_ack (socket, tunnel, sender, ack, atsi); } /** * Handler for DATA_ACK messages * * @param cls the server's listen socket * @param tunnel connection to the other end * @param tunnel_ctx pointer to the 'struct GNUNET_STREAM_Socket*' * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int server_handle_ack (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information*atsi) { struct GNUNET_STREAM_Socket *socket = *tunnel_ctx; const struct GNUNET_STREAM_AckMessage *ack = (const struct GNUNET_STREAM_AckMessage *) message; return handle_ack (socket, tunnel, sender, ack, atsi); } /** * For client message handlers, the stream socket is in the * closure argument. */ static struct GNUNET_MESH_MessageHandler client_message_handlers[] = { {&client_handle_data, GNUNET_MESSAGE_TYPE_STREAM_DATA, 0}, {&client_handle_ack, GNUNET_MESSAGE_TYPE_STREAM_ACK, sizeof (struct GNUNET_STREAM_AckMessage) }, {&client_handle_hello_ack, GNUNET_MESSAGE_TYPE_STREAM_HELLO_ACK, sizeof (struct GNUNET_STREAM_HelloAckMessage)}, {&client_handle_reset, GNUNET_MESSAGE_TYPE_STREAM_RESET, sizeof (struct GNUNET_STREAM_MessageHeader)}, {&client_handle_transmit_close, GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE, sizeof (struct GNUNET_STREAM_MessageHeader)}, {&client_handle_transmit_close_ack, GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE_ACK, sizeof (struct GNUNET_STREAM_MessageHeader)}, {&client_handle_receive_close, GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE, sizeof (struct GNUNET_STREAM_MessageHeader)}, {&client_handle_receive_close_ack, GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE_ACK, sizeof (struct GNUNET_STREAM_MessageHeader)}, {&client_handle_close, GNUNET_MESSAGE_TYPE_STREAM_CLOSE, sizeof (struct GNUNET_STREAM_MessageHeader)}, {&client_handle_close_ack, GNUNET_MESSAGE_TYPE_STREAM_CLOSE_ACK, sizeof (struct GNUNET_STREAM_MessageHeader)}, {NULL, 0, 0} }; /** * For server message handlers, the stream socket is in the * tunnel context, and the listen socket in the closure argument. */ static struct GNUNET_MESH_MessageHandler server_message_handlers[] = { {&server_handle_data, GNUNET_MESSAGE_TYPE_STREAM_DATA, 0}, {&server_handle_ack, GNUNET_MESSAGE_TYPE_STREAM_ACK, sizeof (struct GNUNET_STREAM_AckMessage) }, {&server_handle_hello, GNUNET_MESSAGE_TYPE_STREAM_HELLO, sizeof (struct GNUNET_STREAM_MessageHeader)}, {&server_handle_hello_ack, GNUNET_MESSAGE_TYPE_STREAM_HELLO_ACK, sizeof (struct GNUNET_STREAM_HelloAckMessage)}, {&server_handle_reset, GNUNET_MESSAGE_TYPE_STREAM_RESET, sizeof (struct GNUNET_STREAM_MessageHeader)}, {&server_handle_transmit_close, GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE, sizeof (struct GNUNET_STREAM_MessageHeader)}, {&server_handle_transmit_close_ack, GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE_ACK, sizeof (struct GNUNET_STREAM_MessageHeader)}, {&server_handle_receive_close, GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE, sizeof (struct GNUNET_STREAM_MessageHeader)}, {&server_handle_receive_close_ack, GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE_ACK, sizeof (struct GNUNET_STREAM_MessageHeader)}, {&server_handle_close, GNUNET_MESSAGE_TYPE_STREAM_CLOSE, sizeof (struct GNUNET_STREAM_MessageHeader)}, {&server_handle_close_ack, GNUNET_MESSAGE_TYPE_STREAM_CLOSE_ACK, sizeof (struct GNUNET_STREAM_MessageHeader)}, {NULL, 0, 0} }; /** * Function called when our target peer is connected to our tunnel * * @param cls the socket for which this tunnel is created * @param peer the peer identity of the target * @param atsi performance data for the connection */ static void mesh_peer_connect_callback (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information * atsi) { struct GNUNET_STREAM_Socket *socket = cls; struct GNUNET_STREAM_MessageHeader *message; if (0 != memcmp (peer, &socket->other_peer, sizeof (struct GNUNET_PeerIdentity))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: A peer which is not our target has connected to our tunnel\n", GNUNET_i2s(peer)); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Target peer %s connected\n", GNUNET_i2s (&socket->other_peer), GNUNET_i2s (&socket->other_peer)); /* Set state to INIT */ socket->state = STATE_INIT; /* Send HELLO message */ message = GNUNET_malloc (sizeof (struct GNUNET_STREAM_MessageHeader)); message->header.type = htons (GNUNET_MESSAGE_TYPE_STREAM_HELLO); message->header.size = htons (sizeof (struct GNUNET_STREAM_MessageHeader)); queue_message (socket, message, &set_state_hello_wait, NULL); /* Call open callback */ if (NULL == socket->open_cb) { LOG (GNUNET_ERROR_TYPE_DEBUG, "STREAM_open callback is NULL\n"); } } /** * Function called when our target peer is disconnected from our tunnel * * @param cls the socket associated which this tunnel * @param peer the peer identity of the target */ static void mesh_peer_disconnect_callback (void *cls, const struct GNUNET_PeerIdentity *peer) { struct GNUNET_STREAM_Socket *socket=cls; /* If the state is SHUTDOWN its ok; else set the state of the socket to SYSERR */ LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Other peer %s disconnected \n", GNUNET_i2s (&socket->other_peer), GNUNET_i2s (&socket->other_peer)); } /** * Method called whenever a peer creates a tunnel to us * * @param cls closure * @param tunnel new handle to the tunnel * @param initiator peer that started the tunnel * @param atsi performance information for the tunnel * @return initial tunnel context for the tunnel * (can be NULL -- that's not an error) */ static void * new_tunnel_notify (void *cls, struct GNUNET_MESH_Tunnel *tunnel, const struct GNUNET_PeerIdentity *initiator, const struct GNUNET_ATS_Information *atsi) { struct GNUNET_STREAM_ListenSocket *lsocket = cls; struct GNUNET_STREAM_Socket *socket; /* FIXME: If a tunnel is already created, we should not accept new tunnels from the same peer again until the socket is closed */ socket = GNUNET_malloc (sizeof (struct GNUNET_STREAM_Socket)); socket->other_peer = *initiator; socket->tunnel = tunnel; socket->session_id = 0; /* FIXME */ socket->state = STATE_INIT; socket->lsocket = lsocket; LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Peer %s initiated tunnel to us\n", GNUNET_i2s (&socket->other_peer), GNUNET_i2s (&socket->other_peer)); /* FIXME: Copy MESH handle from lsocket to socket */ return socket; } /** * Function called whenever an inbound tunnel is destroyed. Should clean up * any associated state. This function is NOT called if the client has * explicitly asked for the tunnel to be destroyed using * GNUNET_MESH_tunnel_destroy. It must NOT call GNUNET_MESH_tunnel_destroy on * the tunnel. * * @param cls closure (set from GNUNET_MESH_connect) * @param tunnel connection to the other end (henceforth invalid) * @param tunnel_ctx place where local state associated * with the tunnel is stored */ static void tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx) { struct GNUNET_STREAM_Socket *socket = tunnel_ctx; if (tunnel != socket->tunnel) return; GNUNET_break_op(0); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: Peer %s has terminated connection abruptly\n", GNUNET_i2s (&socket->other_peer), GNUNET_i2s (&socket->other_peer)); socket->status = GNUNET_STREAM_SHUTDOWN; /* Clear Transmit handles */ if (NULL != socket->transmit_handle) { GNUNET_MESH_notify_transmit_ready_cancel (socket->transmit_handle); socket->transmit_handle = NULL; } if (NULL != socket->ack_transmit_handle) { GNUNET_MESH_notify_transmit_ready_cancel (socket->ack_transmit_handle); GNUNET_free (socket->ack_msg); socket->ack_msg = NULL; socket->ack_transmit_handle = NULL; } /* Stop Tasks using socket->tunnel */ if (GNUNET_SCHEDULER_NO_TASK != socket->ack_task_id) { GNUNET_SCHEDULER_cancel (socket->ack_task_id); socket->ack_task_id = GNUNET_SCHEDULER_NO_TASK; } if (GNUNET_SCHEDULER_NO_TASK != socket->retransmission_timeout_task_id) { GNUNET_SCHEDULER_cancel (socket->retransmission_timeout_task_id); socket->retransmission_timeout_task_id = GNUNET_SCHEDULER_NO_TASK; } /* FIXME: Cancel all other tasks using socket->tunnel */ socket->tunnel = NULL; } /*****************/ /* API functions */ /*****************/ /** * Tries to open a stream to the target peer * * @param cfg configuration to use * @param target the target peer to which the stream has to be opened * @param app_port the application port number which uniquely identifies this * stream * @param open_cb this function will be called after stream has be established * @param open_cb_cls the closure for open_cb * @param ... options to the stream, terminated by GNUNET_STREAM_OPTION_END * @return if successful it returns the stream socket; NULL if stream cannot be * opened */ struct GNUNET_STREAM_Socket * GNUNET_STREAM_open (const struct GNUNET_CONFIGURATION_Handle *cfg, const struct GNUNET_PeerIdentity *target, GNUNET_MESH_ApplicationType app_port, GNUNET_STREAM_OpenCallback open_cb, void *open_cb_cls, ...) { struct GNUNET_STREAM_Socket *socket; enum GNUNET_STREAM_Option option; GNUNET_MESH_ApplicationType ports[] = {app_port, 0}; va_list vargs; /* Variable arguments */ LOG (GNUNET_ERROR_TYPE_DEBUG, "%s\n", __func__); socket = GNUNET_malloc (sizeof (struct GNUNET_STREAM_Socket)); socket->other_peer = *target; socket->open_cb = open_cb; socket->open_cls = open_cb_cls; /* Set defaults */ socket->retransmit_timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, default_timeout); va_start (vargs, open_cb_cls); /* Parse variable args */ do { option = va_arg (vargs, enum GNUNET_STREAM_Option); switch (option) { case GNUNET_STREAM_OPTION_INITIAL_RETRANSMIT_TIMEOUT: /* Expect struct GNUNET_TIME_Relative */ socket->retransmit_timeout = va_arg (vargs, struct GNUNET_TIME_Relative); break; case GNUNET_STREAM_OPTION_END: break; } } while (GNUNET_STREAM_OPTION_END != option); va_end (vargs); /* End of variable args parsing */ socket->mesh = GNUNET_MESH_connect (cfg, /* the configuration handle */ 10, /* QUEUE size as parameter? */ socket, /* cls */ NULL, /* No inbound tunnel handler */ NULL, /* No in-tunnel cleaner */ client_message_handlers, ports); /* We don't get inbound tunnels */ if (NULL == socket->mesh) /* Fail if we cannot connect to mesh */ { GNUNET_free (socket); return NULL; } /* Now create the mesh tunnel to target */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating MESH Tunnel\n"); socket->tunnel = GNUNET_MESH_tunnel_create (socket->mesh, NULL, /* Tunnel context */ &mesh_peer_connect_callback, &mesh_peer_disconnect_callback, socket); GNUNET_assert (NULL != socket->tunnel); GNUNET_MESH_peer_request_connect_add (socket->tunnel, &socket->other_peer); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__); return socket; } /** * Shutdown the stream for reading or writing (similar to man 2 shutdown). * * @param socket the stream socket * @param operation SHUT_RD, SHUT_WR or SHUT_RDWR * @param completion_cb the callback that will be called upon successful * shutdown of given operation * @param completion_cls the closure for the completion callback * @return the shutdown handle */ struct GNUNET_STREAM_ShutdownHandle * GNUNET_STREAM_shutdown (struct GNUNET_STREAM_Socket *socket, int operation, GNUNET_STREAM_ShutdownCompletion completion_cb, void *completion_cls) { struct GNUNET_STREAM_ShutdownHandle *handle; struct GNUNET_STREAM_MessageHeader *msg; GNUNET_assert (NULL == socket->shutdown_handle); handle = GNUNET_malloc (sizeof (struct GNUNET_STREAM_ShutdownHandle)); handle->socket = socket; handle->completion_cb = completion_cb; handle->completion_cls = completion_cls; socket->shutdown_handle = handle; msg = GNUNET_malloc (sizeof (struct GNUNET_STREAM_MessageHeader)); msg->header.size = htons (sizeof (struct GNUNET_STREAM_MessageHeader)); switch (operation) { case SHUT_RD: handle->operation = SHUT_RD; if (NULL != socket->read_handle) LOG (GNUNET_ERROR_TYPE_WARNING, "Existing read handle should be cancelled before shutting" " down reading\n"); msg->header.type = htons (GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE); queue_message (socket, msg, &set_state_receive_close_wait, NULL); break; case SHUT_WR: handle->operation = SHUT_WR; if (NULL != socket->write_handle) LOG (GNUNET_ERROR_TYPE_WARNING, "Existing write handle should be cancelled before shutting" " down writing\n"); msg->header.type = htons (GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE); queue_message (socket, msg, &set_state_transmit_close_wait, NULL); break; case SHUT_RDWR: handle->operation = SHUT_RDWR; if (NULL != socket->write_handle) LOG (GNUNET_ERROR_TYPE_WARNING, "Existing write handle should be cancelled before shutting" " down writing\n"); if (NULL != socket->read_handle) LOG (GNUNET_ERROR_TYPE_WARNING, "Existing read handle should be cancelled before shutting" " down reading\n"); msg->header.type = htons (GNUNET_MESSAGE_TYPE_STREAM_CLOSE); queue_message (socket, msg, &set_state_close_wait, NULL); break; default: LOG (GNUNET_ERROR_TYPE_WARNING, "GNUNET_STREAM_shutdown called with invalid value for " "parameter operation -- Ignoring\n"); GNUNET_free (msg); GNUNET_free (handle); return NULL; } handle->close_msg_retransmission_task_id = GNUNET_SCHEDULER_add_delayed (socket->retransmit_timeout, &close_msg_retransmission_task, handle); return handle; } /** * Cancels a pending shutdown * * @param handle the shutdown handle returned from GNUNET_STREAM_shutdown */ void GNUNET_STREAM_shutdown_cancel (struct GNUNET_STREAM_ShutdownHandle *handle) { if (GNUNET_SCHEDULER_NO_TASK != handle->close_msg_retransmission_task_id) GNUNET_SCHEDULER_cancel (handle->close_msg_retransmission_task_id); GNUNET_free (handle); return; } /** * Closes the stream * * @param socket the stream socket */ void GNUNET_STREAM_close (struct GNUNET_STREAM_Socket *socket) { struct MessageQueue *head; if (NULL != socket->read_handle) { LOG (GNUNET_ERROR_TYPE_WARNING, "Closing STREAM socket when a read handle is pending\n"); } if (NULL != socket->write_handle) { LOG (GNUNET_ERROR_TYPE_WARNING, "Closing STREAM socket when a write handle is pending\n"); } if (socket->read_task_id != GNUNET_SCHEDULER_NO_TASK) { /* socket closed with read task pending!? */ GNUNET_break (0); GNUNET_SCHEDULER_cancel (socket->read_task_id); socket->read_task_id = GNUNET_SCHEDULER_NO_TASK; } /* Terminate the ack'ing tasks if they are still present */ if (socket->ack_task_id != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (socket->ack_task_id); socket->ack_task_id = GNUNET_SCHEDULER_NO_TASK; } /* Clear Transmit handles */ if (NULL != socket->transmit_handle) { GNUNET_MESH_notify_transmit_ready_cancel (socket->transmit_handle); socket->transmit_handle = NULL; } if (NULL != socket->ack_transmit_handle) { GNUNET_MESH_notify_transmit_ready_cancel (socket->ack_transmit_handle); GNUNET_free (socket->ack_msg); socket->ack_msg = NULL; socket->ack_transmit_handle = NULL; } /* Clear existing message queue */ while (NULL != (head = socket->queue_head)) { GNUNET_CONTAINER_DLL_remove (socket->queue_head, socket->queue_tail, head); GNUNET_free (head->message); GNUNET_free (head); } /* Close associated tunnel */ if (NULL != socket->tunnel) { GNUNET_MESH_tunnel_destroy (socket->tunnel); socket->tunnel = NULL; } /* Close mesh connection */ if (NULL != socket->mesh && NULL == socket->lsocket) { GNUNET_MESH_disconnect (socket->mesh); socket->mesh = NULL; } /* Release receive buffer */ if (NULL != socket->receive_buffer) { GNUNET_free (socket->receive_buffer); } GNUNET_free (socket); } /** * Listens for stream connections for a specific application ports * * @param cfg the configuration to use * @param app_port the application port for which new streams will be accepted * @param listen_cb this function will be called when a peer tries to establish * a stream with us * @param listen_cb_cls closure for listen_cb * @return listen socket, NULL for any error */ struct GNUNET_STREAM_ListenSocket * GNUNET_STREAM_listen (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_MESH_ApplicationType app_port, GNUNET_STREAM_ListenCallback listen_cb, void *listen_cb_cls) { /* FIXME: Add variable args for passing configration options? */ struct GNUNET_STREAM_ListenSocket *lsocket; GNUNET_MESH_ApplicationType ports[] = {app_port, 0}; lsocket = GNUNET_malloc (sizeof (struct GNUNET_STREAM_ListenSocket)); lsocket->port = app_port; lsocket->listen_cb = listen_cb; lsocket->listen_cb_cls = listen_cb_cls; lsocket->mesh = GNUNET_MESH_connect (cfg, 10, /* FIXME: QUEUE size as parameter? */ lsocket, /* Closure */ &new_tunnel_notify, &tunnel_cleaner, server_message_handlers, ports); GNUNET_assert (NULL != lsocket->mesh); return lsocket; } /** * Closes the listen socket * * @param lsocket the listen socket */ void GNUNET_STREAM_listen_close (struct GNUNET_STREAM_ListenSocket *lsocket) { /* Close MESH connection */ GNUNET_assert (NULL != lsocket->mesh); GNUNET_MESH_disconnect (lsocket->mesh); GNUNET_free (lsocket); } /** * Tries to write the given data to the stream. The maximum size of data that * can be written as part of a write operation is (64 * (64000 - sizeof (struct * GNUNET_STREAM_DataMessage))). If size is greater than this it is not an API * violation, however only the said number of maximum bytes will be written. * * @param socket the socket representing a stream * @param data the data buffer from where the data is written into the stream * @param size the number of bytes to be written from the data buffer * @param timeout the timeout period * @param write_cont the function to call upon writing some bytes into the * stream * @param write_cont_cls the closure * * @return handle to cancel the operation; if a previous write is pending or * the stream has been shutdown for this operation then write_cont is * immediately called and NULL is returned. */ struct GNUNET_STREAM_IOWriteHandle * GNUNET_STREAM_write (struct GNUNET_STREAM_Socket *socket, const void *data, size_t size, struct GNUNET_TIME_Relative timeout, GNUNET_STREAM_CompletionContinuation write_cont, void *write_cont_cls) { unsigned int num_needed_packets; unsigned int packet; struct GNUNET_STREAM_IOWriteHandle *io_handle; uint32_t packet_size; uint32_t payload_size; struct GNUNET_STREAM_DataMessage *data_msg; const void *sweep; struct GNUNET_TIME_Relative ack_deadline; LOG (GNUNET_ERROR_TYPE_DEBUG, "%s\n", __func__); /* Return NULL if there is already a write request pending */ if (NULL != socket->write_handle) { GNUNET_break (0); return NULL; } switch (socket->state) { case STATE_TRANSMIT_CLOSED: case STATE_TRANSMIT_CLOSE_WAIT: case STATE_CLOSED: case STATE_CLOSE_WAIT: if (NULL != write_cont) write_cont (write_cont_cls, GNUNET_STREAM_SHUTDOWN, 0); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__); return NULL; case STATE_INIT: case STATE_LISTEN: case STATE_HELLO_WAIT: if (NULL != write_cont) /* FIXME: GNUNET_STREAM_SYSERR?? */ write_cont (write_cont_cls, GNUNET_STREAM_SYSERR, 0); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__); return NULL; case STATE_ESTABLISHED: case STATE_RECEIVE_CLOSED: case STATE_RECEIVE_CLOSE_WAIT: break; } if (GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH * max_payload_size < size) size = GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH * max_payload_size; num_needed_packets = (size + (max_payload_size - 1)) / max_payload_size; io_handle = GNUNET_malloc (sizeof (struct GNUNET_STREAM_IOWriteHandle)); io_handle->socket = socket; io_handle->write_cont = write_cont; io_handle->write_cont_cls = write_cont_cls; io_handle->size = size; sweep = data; /* FIXME: Remove the fixed delay for ack deadline; Set it to the value determined from RTT */ ack_deadline = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5); /* Divide the given buffer into packets for sending */ for (packet=0; packet < num_needed_packets; packet++) { if ((packet + 1) * max_payload_size < size) { payload_size = max_payload_size; packet_size = MAX_PACKET_SIZE; } else { payload_size = size - packet * max_payload_size; packet_size = payload_size + sizeof (struct GNUNET_STREAM_DataMessage); } io_handle->messages[packet] = GNUNET_malloc (packet_size); io_handle->messages[packet]->header.header.size = htons (packet_size); io_handle->messages[packet]->header.header.type = htons (GNUNET_MESSAGE_TYPE_STREAM_DATA); io_handle->messages[packet]->sequence_number = htonl (socket->write_sequence_number++); io_handle->messages[packet]->offset = htonl (socket->write_offset); /* FIXME: Remove the fixed delay for ack deadline; Set it to the value determined from RTT */ io_handle->messages[packet]->ack_deadline = GNUNET_TIME_relative_hton (ack_deadline); data_msg = io_handle->messages[packet]; /* Copy data from given buffer to the packet */ memcpy (&data_msg[1], sweep, payload_size); sweep += payload_size; socket->write_offset += payload_size; } socket->write_handle = io_handle; write_data (socket); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__); return io_handle; } /** * Tries to read data from the stream. * * @param socket the socket representing a stream * @param timeout the timeout period * @param proc function to call with data (once only) * @param proc_cls the closure for proc * * @return handle to cancel the operation; if the stream has been shutdown for * this type of opeartion then the DataProcessor is immediately * called with GNUNET_STREAM_SHUTDOWN as status and NULL if returned */ struct GNUNET_STREAM_IOReadHandle * GNUNET_STREAM_read (struct GNUNET_STREAM_Socket *socket, struct GNUNET_TIME_Relative timeout, GNUNET_STREAM_DataProcessor proc, void *proc_cls) { struct GNUNET_STREAM_IOReadHandle *read_handle; LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: %s()\n", GNUNET_i2s (&socket->other_peer), __func__); /* Return NULL if there is already a read handle; the user has to cancel that first before continuing or has to wait until it is completed */ if (NULL != socket->read_handle) return NULL; GNUNET_assert (NULL != proc); switch (socket->state) { case STATE_RECEIVE_CLOSED: case STATE_RECEIVE_CLOSE_WAIT: case STATE_CLOSED: case STATE_CLOSE_WAIT: proc (proc_cls, GNUNET_STREAM_SHUTDOWN, NULL, 0); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: %s() END\n", GNUNET_i2s (&socket->other_peer), __func__); return NULL; default: break; } read_handle = GNUNET_malloc (sizeof (struct GNUNET_STREAM_IOReadHandle)); read_handle->proc = proc; read_handle->proc_cls = proc_cls; socket->read_handle = read_handle; /* Check if we have a packet at bitmap 0 */ if (GNUNET_YES == ackbitmap_is_bit_set (&socket->ack_bitmap, 0)) { socket->read_task_id = GNUNET_SCHEDULER_add_now (&call_read_processor, socket); } /* Setup the read timeout task */ socket->read_io_timeout_task_id = GNUNET_SCHEDULER_add_delayed (timeout, &read_io_timeout, socket); LOG (GNUNET_ERROR_TYPE_DEBUG, "%s: %s() END\n", GNUNET_i2s (&socket->other_peer), __func__); return read_handle; } /** * Cancel pending write operation. * * @param ioh handle to operation to cancel */ void GNUNET_STREAM_io_write_cancel (struct GNUNET_STREAM_IOWriteHandle *ioh) { struct GNUNET_STREAM_Socket *socket = ioh->socket; unsigned int packet; GNUNET_assert (NULL != socket->write_handle); GNUNET_assert (socket->write_handle == ioh); if (GNUNET_SCHEDULER_NO_TASK != socket->retransmission_timeout_task_id) { GNUNET_SCHEDULER_cancel (socket->retransmission_timeout_task_id); socket->retransmission_timeout_task_id = GNUNET_SCHEDULER_NO_TASK; } for (packet=0; packet < GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH; packet++) { if (NULL == ioh->messages[packet]) break; GNUNET_free (ioh->messages[packet]); } GNUNET_free (socket->write_handle); socket->write_handle = NULL; return; } /** * Cancel pending read operation. * * @param ioh handle to operation to cancel */ void GNUNET_STREAM_io_read_cancel (struct GNUNET_STREAM_IOReadHandle *ioh) { return; } gnunet-0.9.3/src/stream/test_stream_local.c0000644000175000017500000003165111760502551015706 00000000000000/* This file is part of GNUnet. (C) 2011, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file stream/test_stream_local.c * @brief Stream API testing between local peers * @author Sree Harsha Totakura */ #include #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_mesh_service.h" #include "gnunet_stream_lib.h" #include "gnunet_testing_lib.h" #define VERBOSE 1 /** * Structure for holding peer's sockets and IO Handles */ struct PeerData { /** * Peer's stream socket */ struct GNUNET_STREAM_Socket *socket; /** * Peer's io write handle */ struct GNUNET_STREAM_IOWriteHandle *io_write_handle; /** * Peer's io read handle */ struct GNUNET_STREAM_IOReadHandle *io_read_handle; /** * Bytes the peer has written */ unsigned int bytes_wrote; /** * Byte the peer has read */ unsigned int bytes_read; }; static struct GNUNET_OS_Process *arm_pid; static struct PeerData peer1; static struct PeerData peer2; static struct GNUNET_STREAM_ListenSocket *peer2_listen_socket; static struct GNUNET_CONFIGURATION_Handle *config_peer1; static struct GNUNET_CONFIGURATION_Handle *config_peer2; static GNUNET_SCHEDULER_TaskIdentifier abort_task; static GNUNET_SCHEDULER_TaskIdentifier test_task; static char *data = "ABCD"; static int result; static int writing_success; static int reading_success; /** * Input processor * * @param cls the closure from GNUNET_STREAM_write/read * @param status the status of the stream at the time this function is called * @param data traffic from the other side * @param size the number of bytes available in data read * @return number of bytes of processed from 'data' (any data remaining should be * given to the next time the read processor is called). */ static size_t input_processor (void *cls, enum GNUNET_STREAM_Status status, const void *input_data, size_t size); /** * Task for calling STREAM_read * * @param cls the peer data entity * @param tc the task context */ static void stream_read_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerData *peer = cls; peer->io_read_handle = GNUNET_STREAM_read (peer->socket, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), &input_processor, peer); GNUNET_assert (NULL != peer->io_read_handle); } /** * The write completion function; called upon writing some data to stream or * upon error * * @param cls the closure from GNUNET_STREAM_write/read * @param status the status of the stream at the time this function is called * @param size the number of bytes read or written */ static void write_completion (void *cls, enum GNUNET_STREAM_Status status, size_t size); /** * Task for calling STREAM_write * * @param cls the peer data entity * @param tc the task context */ static void stream_write_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerData *peer = cls; peer->io_write_handle = GNUNET_STREAM_write (peer->socket, (void *) data, strlen(data) - peer->bytes_wrote, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), &write_completion, peer); GNUNET_assert (NULL != peer->io_write_handle); } /** * Shutdown nicely */ static void do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_STREAM_close (peer1.socket); if (NULL != peer2.socket) GNUNET_STREAM_close (peer2.socket); if (NULL != peer2_listen_socket) GNUNET_STREAM_listen_close (peer2_listen_socket); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: shutdown\n"); if (0 != abort_task) { GNUNET_SCHEDULER_cancel (abort_task); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: arm\n"); if (0 != GNUNET_OS_process_kill (arm_pid, SIGTERM)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Wait\n"); /* Free the duplicated configuration */ GNUNET_CONFIGURATION_destroy (config_peer1); GNUNET_CONFIGURATION_destroy (config_peer2); GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (arm_pid)); GNUNET_OS_process_destroy (arm_pid); } /** * Something went wrong and timed out. Kill everything and set error flag */ static void do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: ABORT\n"); if (0 != test_task) { GNUNET_SCHEDULER_cancel (test_task); } result = GNUNET_SYSERR; abort_task = 0; do_shutdown (cls, tc); } /** * The write completion function; called upon writing some data to stream or * upon error * * @param cls the closure from GNUNET_STREAM_write/read * @param status the status of the stream at the time this function is called * @param size the number of bytes read or written */ static void write_completion (void *cls, enum GNUNET_STREAM_Status status, size_t size) { struct PeerData *peer=cls; GNUNET_assert (GNUNET_STREAM_OK == status); GNUNET_assert (size <= strlen (data)); peer->bytes_wrote += size; if (peer->bytes_wrote < strlen(data)) /* Have more data to send */ { GNUNET_SCHEDULER_add_now (&stream_write_task, peer); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Writing completed\n"); if (&peer1 == peer) /* Peer1 has finished writing; should read now */ { peer->bytes_read = 0; GNUNET_SCHEDULER_add_now (&stream_read_task, peer); } else { writing_success = GNUNET_YES; if (GNUNET_YES == reading_success) GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); } } } /** * Function executed after stream has been established * * @param cls the closure from GNUNET_STREAM_open * @param socket socket to use to communicate with the other side (read/write) */ static void stream_open_cb (void *cls, struct GNUNET_STREAM_Socket *socket) { struct PeerData *peer=cls; GNUNET_assert (&peer1 == peer); GNUNET_assert (socket == peer1.socket); GNUNET_assert (socket == peer->socket); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stream established from peer1\n"); peer->bytes_wrote = 0; GNUNET_SCHEDULER_add_now (&stream_write_task, peer); } /** * Input processor * * @param cls the closure from GNUNET_STREAM_write/read * @param status the status of the stream at the time this function is called * @param data traffic from the other side * @param size the number of bytes available in data read * @return number of bytes of processed from 'data' (any data remaining should be * given to the next time the read processor is called). */ static size_t input_processor (void *cls, enum GNUNET_STREAM_Status status, const void *input_data, size_t size) { struct PeerData *peer = cls; GNUNET_assert (GNUNET_STREAM_OK == status); GNUNET_assert (size <= strlen (data)); GNUNET_assert (0 == strncmp ((const char *) data + peer->bytes_read, (const char *) input_data, size)); peer->bytes_read += size; if (peer->bytes_read < strlen (data)) { GNUNET_SCHEDULER_add_now (&stream_read_task, peer); } else { if (&peer2 == peer) /* Peer2 has completed reading; should write */ { peer->bytes_wrote = 0; GNUNET_SCHEDULER_add_now (&stream_write_task, peer); } else /* Peer1 has completed reading. End of tests */ { reading_success = GNUNET_YES; if (GNUNET_YES == writing_success) GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); } } return size; } /** * Functions of this type are called upon new stream connection from other peers * * @param cls the PeerData of peer2 * @param socket the socket representing the stream * @param initiator the identity of the peer who wants to establish a stream * with us * @return GNUNET_OK to keep the socket open, GNUNET_SYSERR to close the * stream (the socket will be invalid after the call) */ static int stream_listen_cb (void *cls, struct GNUNET_STREAM_Socket *socket, const struct GNUNET_PeerIdentity *initiator) { struct PeerData *peer=cls; struct GNUNET_PeerIdentity self; GNUNET_assert (NULL != socket); GNUNET_assert (socket != peer1.socket); GNUNET_assert (&peer2 == peer); /* Get our identity */ GNUNET_assert (GNUNET_OK == GNUNET_TESTING_get_peer_identity (config_peer1, &self)); GNUNET_assert (0 == memcmp (&self, initiator, sizeof (struct GNUNET_PeerIdentity))); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer connected: %s\n", GNUNET_i2s(initiator)); peer->socket = socket; peer->bytes_read = 0; GNUNET_SCHEDULER_add_now (&stream_read_task, &peer2); return GNUNET_OK; } /** * Testing function * * @param cls NULL * @param tc the task context */ static void test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_PeerIdentity self; test_task = GNUNET_SCHEDULER_NO_TASK; /* Get our identity */ GNUNET_assert (GNUNET_OK == GNUNET_TESTING_get_peer_identity (config_peer1, &self)); peer2_listen_socket = GNUNET_STREAM_listen (config_peer2, 10, /* App port */ &stream_listen_cb, &peer2); GNUNET_assert (NULL != peer2_listen_socket); /* Connect to stream library */ peer1.socket = GNUNET_STREAM_open (config_peer1, &self, /* Null for local peer? */ 10, /* App port */ &stream_open_cb, &peer1, GNUNET_STREAM_OPTION_END); GNUNET_assert (NULL != peer1.socket); } /** * Initialize framework and start test */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { GNUNET_log_setup ("test_stream_local", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); /* Duplicate the configuration */ config_peer1 = GNUNET_CONFIGURATION_dup (cfg); config_peer2 = GNUNET_CONFIGURATION_dup (cfg); arm_pid = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE_ARM "-L", "DEBUG", #endif "-c", "test_stream_local.conf", NULL); abort_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60), &do_abort, NULL); test_task = GNUNET_SCHEDULER_add_now (&test, NULL); } /** * Main function */ int main (int argc, char **argv) { int ret; char *const argv2[] = { "test-stream-local", "-c", "test_stream_local.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; ret = GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, "test-stream-local", "nohelp", options, &run, NULL); if (GNUNET_OK != ret) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "run failed with error code %d\n", ret); return 1; } if (GNUNET_SYSERR == result) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test failed\n"); return 1; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "test ok\n"); return 0; } gnunet-0.9.3/src/stream/Makefile.am0000644000175000017500000000250211746441621014067 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIB = -lgcov endif lib_LTLIBRARIES = libgnunetstream.la libgnunetstream_la_SOURCES = \ stream_api.c stream_protocol.h libgnunetstream_la_LIBADD = \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/util/libgnunetutil.la $(XLIB) libgnunetstream_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) check_PROGRAMS = \ test-stream-2peers \ test-stream-2peers_halfclose \ test-stream-local EXTRA_DIST = test_stream_local.conf if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) endif test_stream_2peers_SOURCES = \ test_stream_2peers.c test_stream_2peers_LDADD = \ $(top_builddir)/src/stream/libgnunetstream.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la test_stream_2peers_halfclose_SOURCES = \ test_stream_2peers_halfclose.c test_stream_2peers_halfclose_LDADD = \ $(top_builddir)/src/stream/libgnunetstream.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la test_stream_local_SOURCES = \ test_stream_local.c test_stream_local_LDADD = \ $(top_builddir)/src/stream/libgnunetstream.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.lagnunet-0.9.3/src/stream/test_stream_2peers.c0000644000175000017500000003613511760502551016016 00000000000000/* This file is part of GNUnet. (C) 2011, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file stream/test_stream_2peers.c * @brief Stream API testing between 2 peers using testing API * @author Sree Harsha Totakura */ #include #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_mesh_service.h" #include "gnunet_stream_lib.h" #include "gnunet_testing_lib.h" #define VERBOSE 1 /** * Number of peers */ #define NUM_PEERS 2 /** * Structure for holding peer's sockets and IO Handles */ struct PeerData { /** * Peer's stream socket */ struct GNUNET_STREAM_Socket *socket; /** * Peer's io write handle */ struct GNUNET_STREAM_IOWriteHandle *io_write_handle; /** * Peer's io read handle */ struct GNUNET_STREAM_IOReadHandle *io_read_handle; /** * Peer's shutdown handle */ struct GNUNET_STREAM_ShutdownHandle *shutdown_handle; /** * Our Peer id */ struct GNUNET_PeerIdentity our_id; /** * Bytes the peer has written */ unsigned int bytes_wrote; /** * Byte the peer has read */ unsigned int bytes_read; }; /** * The current peer group */ static struct GNUNET_TESTING_PeerGroup *pg; /** * Peer 1 daemon */ static struct GNUNET_TESTING_Daemon *d1; /** * Peer 2 daemon */ static struct GNUNET_TESTING_Daemon *d2; static struct PeerData peer1; static struct PeerData peer2; static struct GNUNET_STREAM_ListenSocket *peer2_listen_socket; static struct GNUNET_CONFIGURATION_Handle *config; static GNUNET_SCHEDULER_TaskIdentifier abort_task; static char *data = "ABCD"; static int result; static int writing_success; static int reading_success; /** * Input processor * * @param cls the closure from GNUNET_STREAM_write/read * @param status the status of the stream at the time this function is called * @param data traffic from the other side * @param size the number of bytes available in data read * @return number of bytes of processed from 'data' (any data remaining should be * given to the next time the read processor is called). */ static size_t input_processor (void *cls, enum GNUNET_STREAM_Status status, const void *input_data, size_t size); /** * Task for calling STREAM_read * * @param cls the peer data entity * @param tc the task context */ static void stream_read_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerData *peer = cls; peer->io_read_handle = GNUNET_STREAM_read (peer->socket, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), &input_processor, peer); GNUNET_assert (NULL != peer->io_read_handle); } /** * The write completion function; called upon writing some data to stream or * upon error * * @param cls the closure from GNUNET_STREAM_write/read * @param status the status of the stream at the time this function is called * @param size the number of bytes read or written */ static void write_completion (void *cls, enum GNUNET_STREAM_Status status, size_t size); /** * Task for calling STREAM_write * * @param cls the peer data entity * @param tc the task context */ static void stream_write_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerData *peer = cls; peer->io_write_handle = GNUNET_STREAM_write (peer->socket, (void *) data, strlen(data) - peer->bytes_wrote, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), &write_completion, peer); GNUNET_assert (NULL != peer->io_write_handle); } /** * Check whether peers successfully shut down. */ static void peergroup_shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Shutdown of peers failed!\n"); } else { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "All peers successfully shut down!\n"); } GNUNET_CONFIGURATION_destroy (config); } /** * Close sockets and stop testing deamons nicely */ static void do_close (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (NULL != peer1.socket) GNUNET_STREAM_close (peer1.socket); if (NULL != peer2.socket) GNUNET_STREAM_close (peer2.socket); if (NULL != peer2_listen_socket) GNUNET_STREAM_listen_close (peer2_listen_socket); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: shutdown\n"); if (0 != abort_task) { GNUNET_SCHEDULER_cancel (abort_task); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Wait\n"); GNUNET_TESTING_daemons_stop (pg, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), &peergroup_shutdown_callback, NULL); } /** * Completion callback for shutdown * * @param cls the closure from GNUNET_STREAM_shutdown call * @param operation the operation that was shutdown (SHUT_RD, SHUT_WR, * SHUT_RDWR) */ static void shutdown_completion (void *cls, int operation) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "STREAM shutdown successful\n"); GNUNET_SCHEDULER_add_now (&do_close, cls); } /** * Shutdown sockets gracefully */ static void do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { peer1.shutdown_handle = GNUNET_STREAM_shutdown (peer1.socket, SHUT_RDWR, &shutdown_completion, cls); } /** * Something went wrong and timed out. Kill everything and set error flag */ static void do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: ABORT\n"); result = GNUNET_SYSERR; abort_task = 0; do_close (cls, tc); } /** * The write completion function; called upon writing some data to stream or * upon error * * @param cls the closure from GNUNET_STREAM_write/read * @param status the status of the stream at the time this function is called * @param size the number of bytes read or written */ static void write_completion (void *cls, enum GNUNET_STREAM_Status status, size_t size) { struct PeerData *peer=cls; GNUNET_assert (GNUNET_STREAM_OK == status); GNUNET_assert (size <= strlen (data)); peer->bytes_wrote += size; if (peer->bytes_wrote < strlen(data)) /* Have more data to send */ { GNUNET_SCHEDULER_add_now (&stream_write_task, peer); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Writing completed\n"); if (&peer1 == peer) /* Peer1 has finished writing; should read now */ { peer->bytes_read = 0; GNUNET_SCHEDULER_add_now (&stream_read_task, peer); } else { writing_success = GNUNET_YES; if (GNUNET_YES == reading_success) GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); } } } /** * Function executed after stream has been established * * @param cls the closure from GNUNET_STREAM_open * @param socket socket to use to communicate with the other side (read/write) */ static void stream_open_cb (void *cls, struct GNUNET_STREAM_Socket *socket) { struct PeerData *peer=cls; GNUNET_assert (&peer1 == peer); GNUNET_assert (socket == peer1.socket); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Stream established from peer1\n", GNUNET_i2s (&peer1.our_id)); peer->bytes_wrote = 0; GNUNET_SCHEDULER_add_now (&stream_write_task, peer); } /** * Input processor * * @param cls the closure from GNUNET_STREAM_write/read * @param status the status of the stream at the time this function is called * @param data traffic from the other side * @param size the number of bytes available in data read * @return number of bytes of processed from 'data' (any data remaining should be * given to the next time the read processor is called). */ static size_t input_processor (void *cls, enum GNUNET_STREAM_Status status, const void *input_data, size_t size) { struct PeerData *peer; peer = (struct PeerData *) cls; if (GNUNET_STREAM_TIMEOUT == status) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read operation timedout - reading again!\n"); GNUNET_assert (0 == size); GNUNET_SCHEDULER_add_now (&stream_read_task, peer); return 0; } GNUNET_assert (GNUNET_STREAM_OK == status); GNUNET_assert (size <= strlen (data)); GNUNET_assert (0 == strncmp ((const char *) data + peer->bytes_read, (const char *) input_data, size)); peer->bytes_read += size; if (peer->bytes_read < strlen (data)) { GNUNET_SCHEDULER_add_now (&stream_read_task, peer); } else { if (&peer2 == peer) /* Peer2 has completed reading; should write */ { peer->bytes_wrote = 0; GNUNET_SCHEDULER_add_now (&stream_write_task, peer); } else /* Peer1 has completed reading. End of tests */ { reading_success = GNUNET_YES; if (GNUNET_YES == writing_success) GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); } } return size; } /** * Functions of this type are called upon new stream connection from other peers * * @param cls the closure from GNUNET_STREAM_listen * @param socket the socket representing the stream * @param initiator the identity of the peer who wants to establish a stream * with us * @return GNUNET_OK to keep the socket open, GNUNET_SYSERR to close the * stream (the socket will be invalid after the call) */ static int stream_listen_cb (void *cls, struct GNUNET_STREAM_Socket *socket, const struct GNUNET_PeerIdentity *initiator) { GNUNET_assert (NULL != socket); GNUNET_assert (NULL != initiator); GNUNET_assert (socket != peer1.socket); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Peer connected: %s\n", GNUNET_i2s (&peer2.our_id), GNUNET_i2s(initiator)); peer2.socket = socket; peer2.bytes_read = 0; GNUNET_SCHEDULER_add_now (&stream_read_task, &peer2); return GNUNET_OK; } /** * Callback to be called when testing peer group is ready * * @param cls NULL * @param emsg NULL on success */ void peergroup_ready (void *cls, const char *emsg) { if (NULL != emsg) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Starting peer group failed: %s\n", emsg); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer group is now ready\n"); GNUNET_assert (2 == GNUNET_TESTING_daemons_running (pg)); d1 = GNUNET_TESTING_daemon_get (pg, 0); GNUNET_assert (NULL != d1); d2 = GNUNET_TESTING_daemon_get (pg, 1); GNUNET_assert (NULL != d2); GNUNET_TESTING_get_peer_identity (d1->cfg, &peer1.our_id); GNUNET_TESTING_get_peer_identity (d2->cfg, &peer2.our_id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s : %s\n", GNUNET_i2s (&peer1.our_id), GNUNET_i2s (&d1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s : %s\n", GNUNET_i2s (&peer2.our_id), GNUNET_i2s (&d2->id)); peer2_listen_socket = GNUNET_STREAM_listen (d2->cfg, 10, /* App port */ &stream_listen_cb, NULL); GNUNET_assert (NULL != peer2_listen_socket); /* Connect to stream library */ peer1.socket = GNUNET_STREAM_open (d1->cfg, &d2->id, /* Null for local peer? */ 10, /* App port */ &stream_open_cb, &peer1, GNUNET_STREAM_OPTION_END); GNUNET_assert (NULL != peer1.socket); } /** * Initialize framework and start test */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_TESTING_Host *hosts; /* FIXME: free hosts (DLL) */ GNUNET_log_setup ("test_stream_2peers", "DEBUG", NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting test\n"); /* Duplicate the configuration */ config = GNUNET_CONFIGURATION_dup (cfg); hosts = GNUNET_TESTING_hosts_load (config); pg = GNUNET_TESTING_peergroup_start (config, 2, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3), NULL, &peergroup_ready, NULL, hosts); GNUNET_assert (NULL != pg); abort_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 40), &do_abort, NULL); } /** * Main function */ int main (int argc, char **argv) { int ret; char *argv2[] = { "test-stream-2peers", "-L", "DEBUG", "-c", "test_stream_local.conf", NULL}; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; ret = GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, "test-stream-2peers", "nohelp", options, &run, NULL); if (GNUNET_OK != ret) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "run failed with error code %d\n", ret); return 1; } if (GNUNET_SYSERR == result) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test failed\n"); return 1; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "test ok\n"); return 0; } gnunet-0.9.3/src/stream/stream_protocol.h0000644000175000017500000001102511760502551015414 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file stream/stream_protocol.h * @brief P2P protocol for the stream connections * @author Sree Harsha Totakura */ #ifndef STREAM_PROTOCOL_H #define STREAM_PROTOCOL_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_util_lib.h" GNUNET_NETWORK_STRUCT_BEGIN /** * The stream message header * All messages of STREAM should commonly have this as header */ struct GNUNET_STREAM_MessageHeader { /** * The GNUNET message header, types are from GNUNET_MESSAGE_TYPE_STREAM_*-range. */ struct GNUNET_MessageHeader header; /** * A number which identifies a session between the two peers. FIXME: not needed */ uint32_t session_id GNUNET_PACKED; }; /** * The Data message, should be prefixed with stream header with its type set to * GNUNET_STREAM_Data */ struct GNUNET_STREAM_DataMessage { /** * Type is GNUNET_MESSAGE_TYPE_STREAM_DATA */ struct GNUNET_STREAM_MessageHeader header; /** * Sequence number; starts with a random value. (Just in case * someone breaks mesh and is able to try to do a Sequence * Prediction Attack on us.) */ uint32_t sequence_number GNUNET_PACKED; /** * number of milliseconds to the soft deadline for sending acknowledgement * measured from the time this message is received. It is optimal for the * communication to send the ack within the soft deadline */ struct GNUNET_TIME_RelativeNBO ack_deadline; /** * Offset of the packet in the overall stream, modulo 2^32; allows * the receiver to calculate where in the destination buffer the * message should be placed. In network byte order. */ uint32_t offset GNUNET_PACKED; /** * The data should be appended here */ }; /** * Number of bits in GNUNET_STREAM_AckBitmap */ #define GNUNET_STREAM_ACK_BITMAP_BIT_LENGTH 64 /** * The Selective Acknowledgement Bitmap */ typedef uint64_t GNUNET_STREAM_AckBitmap; /** * The Acknowledgment Message to confirm receipt of DATA. */ struct GNUNET_STREAM_AckMessage { /** * Type is GNUNET_MESSAGE_TYPE_STREAM_ACK */ struct GNUNET_STREAM_MessageHeader header; /** * The Selective Acknowledgement Bitmap. Computed relative to the base_seq * (bit n corresponds to the Data message with sequence number base_seq+n) */ GNUNET_STREAM_AckBitmap bitmap GNUNET_PACKED; /** * The sequence number of the next Data Message receiver is * anticipating. Data messages less than this number are received by receiver */ uint32_t base_sequence_number GNUNET_PACKED; /** * Available buffer space past the last acknowledged buffer (for flow control), * in bytes. */ uint32_t receive_window_remaining GNUNET_PACKED; }; /** * Message for Acknowledging HELLO */ struct GNUNET_STREAM_HelloAckMessage { /** * The stream message header */ struct GNUNET_STREAM_MessageHeader header; /** * The selected sequence number. Following data tranmissions from the sender * start with this sequence */ uint32_t sequence_number; /** * The size(in bytes) of the receive window on the peer sending this message * * FIXME: Remove if not needed */ uint32_t receiver_window_size; }; /** * The Transmit close message(used to signal transmission is closed) */ struct GNUNET_STREAM_TransmitCloseMessage { /** * The stream message header */ struct GNUNET_STREAM_MessageHeader header; /** * The last sequence number of the packet after which the transmission has * ended */ uint32_t final_sequence_number GNUNET_PACKED; }; GNUNET_NETWORK_STRUCT_END #if 0 /** keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif #endif /* STREAM_PROTOCOL_H */ gnunet-0.9.3/src/stream/test_stream_2peers_halfclose.c0000644000175000017500000005274311760502551020041 00000000000000/* This file is part of GNUnet. (C) 2011, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file stream/test_stream_2peers_halfclose.c * @brief Testcases for Stream API halfclosed connections between 2 peers * @author Sree Harsha Totakura */ #include #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_mesh_service.h" #include "gnunet_stream_lib.h" #include "gnunet_testing_lib.h" #include "gnunet_scheduler_lib.h" #define VERBOSE 1 /** * Number of peers */ #define NUM_PEERS 2 /** * Structure for holding peer's sockets and IO Handles */ struct PeerData { /** * Peer's stream socket */ struct GNUNET_STREAM_Socket *socket; /** * Peer's io write handle */ struct GNUNET_STREAM_IOWriteHandle *io_write_handle; /** * Peer's io read handle */ struct GNUNET_STREAM_IOReadHandle *io_read_handle; /** * Peer's shutdown handle */ struct GNUNET_STREAM_ShutdownHandle *shutdown_handle; /** * Our Peer id */ struct GNUNET_PeerIdentity our_id; /** * Bytes the peer has written */ unsigned int bytes_wrote; /** * Byte the peer has read */ unsigned int bytes_read; /** * GNUNET_YES if the peer has successfully completed the current test */ unsigned int test_ok; /** * The shutdown operation that has to be used by the stream_shutdown_task */ int shutdown_operation; }; /** * The current peer group */ static struct GNUNET_TESTING_PeerGroup *pg; /** * Peer 1 daemon */ static struct GNUNET_TESTING_Daemon *d1; /** * Peer 2 daemon */ static struct GNUNET_TESTING_Daemon *d2; /** * Peer1 writes first and then calls for SHUT_WR * Peer2 reads first and then calls for SHUT_RD * Attempt to write again by Peer1 should be rejected * Attempt to read again by Peer2 should be rejected * Peer1 then reads from Peer2 which writes */ static struct PeerData peer1; static struct PeerData peer2; static struct GNUNET_STREAM_ListenSocket *peer2_listen_socket; static struct GNUNET_CONFIGURATION_Handle *config; static GNUNET_SCHEDULER_TaskIdentifier abort_task; static GNUNET_SCHEDULER_TaskIdentifier read_task; static char *data = "ABCD"; static int result; /** * Enumeration for various tests that are to be passed in the same order as * below */ enum Test { /** * Peer1 writing; Peer2 reading */ PEER1_WRITE, /** * Peer1 write shutdown; Peer2 should get an error when it tries to read; */ PEER1_WRITE_SHUTDOWN, /** * Peer1 reads; Peer2 writes (connection is halfclosed) */ PEER1_HALFCLOSE_READ, /** * Peer1 attempts to write; Should fail with stream already shutdown error */ PEER1_HALFCLOSE_WRITE_FAIL, /** * Peer1 read shutdown; Peer2 should get stream shutdown error during write */ PEER1_READ_SHUTDOWN, /** * All tests successfully finished */ SUCCESS }; /** * Current running test */ enum Test current_test; /** * Input processor * * @param cls the closure from GNUNET_STREAM_write/read * @param status the status of the stream at the time this function is called * @param data traffic from the other side * @param size the number of bytes available in data read * @return number of bytes of processed from 'data' (any data remaining should be * given to the next time the read processor is called). */ static size_t input_processor (void *cls, enum GNUNET_STREAM_Status status, const void *input_data, size_t size); /** * The transition function; responsible for the transitions among tests */ static void transition(); /** * Task for calling STREAM_read * * @param cls the peer data entity * @param tc the task context */ static void stream_read_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerData *peer = cls; peer->io_read_handle = GNUNET_STREAM_read (peer->socket, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), &input_processor, cls); switch (current_test) { case PEER1_WRITE_SHUTDOWN: GNUNET_assert (&peer2 == peer); GNUNET_assert (NULL == peer->io_read_handle); transition (); /* to PEER1_HALFCLOSE_READ */ break; default: GNUNET_assert (NULL != peer->io_read_handle); } } /** * The write completion function; called upon writing some data to stream or * upon error * * @param cls the closure from GNUNET_STREAM_write/read * @param status the status of the stream at the time this function is called * @param size the number of bytes read or written */ static void write_completion (void *cls, enum GNUNET_STREAM_Status status, size_t size); /** * Task for calling STREAM_write * * @param cls the peer data entity * @param tc the task context */ static void stream_write_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerData *peer = cls; peer->io_write_handle = GNUNET_STREAM_write (peer->socket, (void *) data, strlen(data) - peer->bytes_wrote, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), &write_completion, peer); switch (current_test) { case PEER1_HALFCLOSE_WRITE_FAIL: GNUNET_assert (&peer1 == peer); GNUNET_assert (NULL == peer->io_write_handle); transition(); /* To PEER1_READ_SHUTDOWN */ break; case PEER1_READ_SHUTDOWN: GNUNET_assert (&peer2 == peer); GNUNET_assert (NULL == peer->io_write_handle); transition (); /* To SUCCESS */ break; default: GNUNET_assert (NULL != peer->io_write_handle); } } /** * Check whether peers successfully shut down. */ static void peergroup_shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Shutdown of peers failed!\n"); } else { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "All peers successfully shut down!\n"); } GNUNET_CONFIGURATION_destroy (config); } /** * Close sockets and stop testing deamons nicely */ static void do_close (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (NULL != peer1.socket) GNUNET_STREAM_close (peer1.socket); if (NULL != peer2.socket) GNUNET_STREAM_close (peer2.socket); if (NULL != peer2_listen_socket) GNUNET_STREAM_listen_close (peer2_listen_socket); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: shutdown\n"); if (0 != abort_task) { GNUNET_SCHEDULER_cancel (abort_task); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Wait\n"); GNUNET_TESTING_daemons_stop (pg, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), &peergroup_shutdown_callback, NULL); } /** * Completion callback for shutdown * * @param cls the closure from GNUNET_STREAM_shutdown call * @param operation the operation that was shutdown (SHUT_RD, SHUT_WR, * SHUT_RDWR) */ void shutdown_completion (void *cls, int operation) { switch (current_test) { case PEER1_WRITE: GNUNET_assert (0); case PEER1_WRITE_SHUTDOWN: GNUNET_assert (cls == &peer1); GNUNET_assert (SHUT_WR == operation); peer1.test_ok = GNUNET_YES; /* Peer2 should read with error */ peer2.bytes_read = 0; GNUNET_SCHEDULER_add_now (&stream_read_task, &peer2); break; case PEER1_READ_SHUTDOWN: peer1.test_ok = GNUNET_YES; peer2.bytes_wrote = 0; GNUNET_SCHEDULER_add_now (&stream_write_task, &peer2); break; case PEER1_HALFCLOSE_READ: case PEER1_HALFCLOSE_WRITE_FAIL: case SUCCESS: GNUNET_assert (0); /* We shouldn't reach here */ } } /** * Task for calling STREAM_shutdown * * @param cls the peer entity * @param tc the TaskContext */ static void stream_shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerData *peer = cls; peer->shutdown_handle = GNUNET_STREAM_shutdown (peer->socket, peer->shutdown_operation, &shutdown_completion, peer); GNUNET_assert (NULL != peer->shutdown_handle); } /** * Something went wrong and timed out. Kill everything and set error flag */ static void do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: ABORT\n"); if (0 != read_task) { GNUNET_SCHEDULER_cancel (read_task); } result = GNUNET_SYSERR; abort_task = 0; do_close (cls, tc); } /** * The transition function; responsible for the transitions among tests */ static void transition() { if ((GNUNET_YES == peer1.test_ok) && (GNUNET_YES == peer2.test_ok)) { peer1.test_ok = GNUNET_NO; peer2.test_ok = GNUNET_NO; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TEST %d SUCCESSFULL\n", current_test); switch (current_test) { case PEER1_WRITE: current_test = PEER1_WRITE_SHUTDOWN; /* Peer1 should shutdown writing */ peer1.shutdown_operation = SHUT_WR; GNUNET_SCHEDULER_add_now (&stream_shutdown_task, &peer1); break; case PEER1_WRITE_SHUTDOWN: current_test = PEER1_HALFCLOSE_READ; /* Peer2 should be able to write successfully */ peer2.bytes_wrote = 0; GNUNET_SCHEDULER_add_now (&stream_write_task, &peer2); /* Peer1 should be able to read successfully */ peer1.bytes_read = 0; GNUNET_SCHEDULER_add_now (&stream_read_task, &peer1); break; case PEER1_HALFCLOSE_READ: current_test = PEER1_HALFCLOSE_WRITE_FAIL; peer1.bytes_wrote = 0; peer2.bytes_read = 0; peer2.test_ok = GNUNET_YES; GNUNET_SCHEDULER_add_now (&stream_write_task, &peer1); break; case PEER1_HALFCLOSE_WRITE_FAIL: current_test = PEER1_READ_SHUTDOWN; peer1.shutdown_operation = SHUT_RD; GNUNET_SCHEDULER_add_now (&stream_shutdown_task, &peer1); break; case PEER1_READ_SHUTDOWN: current_test = SUCCESS; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All tests successful\n"); GNUNET_SCHEDULER_add_now (&do_close, NULL); break; case SUCCESS: GNUNET_assert (0); /* We shouldn't reach here */ } } } /** * The write completion function; called upon writing some data to stream or * upon error * * @param cls the closure from GNUNET_STREAM_write/read * @param status the status of the stream at the time this function is called * @param size the number of bytes read or written */ static void write_completion (void *cls, enum GNUNET_STREAM_Status status, size_t size) { struct PeerData *peer = cls; switch (current_test) { case PEER1_WRITE: case PEER1_HALFCLOSE_READ: GNUNET_assert (GNUNET_STREAM_OK == status); GNUNET_assert (size <= strlen (data)); peer->bytes_wrote += size; if (peer->bytes_wrote < strlen(data)) /* Have more data to send */ { GNUNET_SCHEDULER_add_now (&stream_write_task, peer); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Writing completed\n"); if (&peer1 == peer) { peer1.test_ok = GNUNET_YES; transition (); /* to PEER1_WRITE_SHUTDOWN */ } else /* This will happen during PEER1_HALFCLOSE_READ */ { peer2.test_ok = GNUNET_YES; transition (); /* to PEER1_HALFCLOSE_WRITE_FAIL */ } } break; case PEER1_HALFCLOSE_WRITE_FAIL: GNUNET_assert (peer == &peer1); GNUNET_assert (GNUNET_STREAM_SHUTDOWN == status); GNUNET_assert (0 == size); peer1.test_ok = GNUNET_YES; break; case PEER1_READ_SHUTDOWN: GNUNET_assert (peer == &peer2); GNUNET_assert (GNUNET_STREAM_SHUTDOWN == status); GNUNET_assert (0 == size); peer2.test_ok = GNUNET_YES; break; case PEER1_WRITE_SHUTDOWN: case SUCCESS: GNUNET_assert (0); /* We shouldn't reach here */ } } /** * Function executed after stream has been established * * @param cls the closure from GNUNET_STREAM_open * @param socket socket to use to communicate with the other side (read/write) */ static void stream_open_cb (void *cls, struct GNUNET_STREAM_Socket *socket) { struct PeerData *peer; GNUNET_assert (socket == peer1.socket); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Stream established from peer1\n", GNUNET_i2s (&peer1.our_id)); peer = (struct PeerData *) cls; peer->bytes_wrote = 0; GNUNET_assert (socket == peer1.socket); GNUNET_assert (socket == peer->socket); peer1.test_ok = GNUNET_NO; peer2.test_ok = GNUNET_NO; current_test = PEER1_WRITE; GNUNET_SCHEDULER_add_now (&stream_write_task, peer); } /** * Input processor * * @param cls the closure from GNUNET_STREAM_write/read * @param status the status of the stream at the time this function is called * @param data traffic from the other side * @param size the number of bytes available in data read * @return number of bytes of processed from 'data' (any data remaining should be * given to the next time the read processor is called). */ static size_t input_processor (void *cls, enum GNUNET_STREAM_Status status, const void *input_data, size_t size) { struct PeerData *peer; peer = (struct PeerData *) cls; switch (current_test) { case PEER1_WRITE: case PEER1_HALFCLOSE_READ: if (GNUNET_STREAM_TIMEOUT == status) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read operation timedout - reading again!\n"); GNUNET_assert (0 == size); GNUNET_SCHEDULER_add_now (&stream_read_task, peer); return 0; } GNUNET_assert (GNUNET_STREAM_OK == status); GNUNET_assert (size <= strlen (data)); GNUNET_assert (0 == strncmp ((const char *) data + peer->bytes_read, (const char *) input_data, size)); peer->bytes_read += size; if (peer->bytes_read < strlen (data)) { GNUNET_SCHEDULER_add_now (&stream_read_task, peer); } else { if (&peer2 == peer) /* Peer2 has completed reading; should write */ { peer2.test_ok = GNUNET_YES; transition (); /* Transition to PEER1_WRITE_SHUTDOWN */ } else /* Peer1 has completed reading. End of tests */ { peer1.test_ok = GNUNET_YES; transition (); /* to PEER1_HALFCLOSE_WRITE_FAIL */ } } break; case PEER1_WRITE_SHUTDOWN: GNUNET_assert (GNUNET_STREAM_SHUTDOWN == status); peer2.test_ok = GNUNET_YES; break; case PEER1_HALFCLOSE_WRITE_FAIL: case PEER1_READ_SHUTDOWN: case SUCCESS: GNUNET_assert (0); /* We shouldn't reach here */ } return size; } /** * Scheduler call back; to be executed when a new stream is connected * Called from listen connect for peer2 */ static void stream_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { read_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_assert (NULL != cls); peer2.bytes_read = 0; GNUNET_SCHEDULER_add_now (&stream_read_task, &peer2); } /** * Functions of this type are called upon new stream connection from other peers * * @param cls the closure from GNUNET_STREAM_listen * @param socket the socket representing the stream * @param initiator the identity of the peer who wants to establish a stream * with us * @return GNUNET_OK to keep the socket open, GNUNET_SYSERR to close the * stream (the socket will be invalid after the call) */ static int stream_listen_cb (void *cls, struct GNUNET_STREAM_Socket *socket, const struct GNUNET_PeerIdentity *initiator) { GNUNET_assert (NULL != socket); GNUNET_assert (NULL != initiator); GNUNET_assert (socket != peer1.socket); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Peer connected: %s\n", GNUNET_i2s (&peer2.our_id), GNUNET_i2s(initiator)); peer2.socket = socket; /* FIXME: reading should be done right now instead of a scheduled call */ read_task = GNUNET_SCHEDULER_add_now (&stream_read, (void *) socket); return GNUNET_OK; } /** * Callback to be called when testing peer group is ready * * @param cls NULL * @param emsg NULL on success */ void peergroup_ready (void *cls, const char *emsg) { if (NULL != emsg) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Starting peer group failed: %s\n", emsg); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer group is now ready\n"); GNUNET_assert (2 == GNUNET_TESTING_daemons_running (pg)); d1 = GNUNET_TESTING_daemon_get (pg, 0); GNUNET_assert (NULL != d1); d2 = GNUNET_TESTING_daemon_get (pg, 1); GNUNET_assert (NULL != d2); GNUNET_TESTING_get_peer_identity (d1->cfg, &peer1.our_id); GNUNET_TESTING_get_peer_identity (d2->cfg, &peer2.our_id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s : %s\n", GNUNET_i2s (&peer1.our_id), GNUNET_i2s (&d1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s : %s\n", GNUNET_i2s (&peer2.our_id), GNUNET_i2s (&d2->id)); peer2_listen_socket = GNUNET_STREAM_listen (d2->cfg, 10, /* App port */ &stream_listen_cb, NULL); GNUNET_assert (NULL != peer2_listen_socket); /* Connect to stream library */ peer1.socket = GNUNET_STREAM_open (d1->cfg, &d2->id, /* Null for local peer? */ 10, /* App port */ &stream_open_cb, &peer1, GNUNET_STREAM_OPTION_END); GNUNET_assert (NULL != peer1.socket); } /** * Initialize framework and start test */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_TESTING_Host *hosts; /* FIXME: free hosts (DLL) */ /* GNUNET_log_setup ("test_stream_local", */ /* "DEBUG", */ /* NULL); */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting test\n"); /* Duplicate the configuration */ config = GNUNET_CONFIGURATION_dup (cfg); hosts = GNUNET_TESTING_hosts_load (config); pg = GNUNET_TESTING_peergroup_start (config, 2, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3), NULL, &peergroup_ready, NULL, hosts); GNUNET_assert (NULL != pg); abort_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 40), &do_abort, NULL); } /** * Main function */ int main (int argc, char **argv) { int ret; char *argv2[] = { "test-stream-2peers-halfclose", "-L", "DEBUG", "-c", "test_stream_local.conf", NULL}; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; ret = GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, "test-stream-2peers-halfclose", "nohelp", options, &run, NULL); if (GNUNET_OK != ret) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "run failed with error code %d\n", ret); return 1; } if (GNUNET_SYSERR == result) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test failed\n"); return 1; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "test ok\n"); return 0; } gnunet-0.9.3/src/stream/test_stream_local.conf0000644000175000017500000000204211761764506016414 00000000000000[fs] AUTOSTART = NO [resolver] AUTOSTART = NO [mesh] DEBUG = YES AUTOSTART = YES ACCEPT_FROM = 127.0.0.1; HOSTNAME = localhost PORT = 10700 # PREFIX = valgrind --leak-check=full # PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args [dht] DEBUG = NO AUTOSTART = YES ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; HOSTNAME = localhost PORT = 12100 [block] plugins = dht test [dhtcache] QUOTA = 1 MB DATABASE = sqlite [transport] PLUGINS = tcp DEBUG = NO ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; NEIGHBOUR_LIMIT = 50 PORT = 12365 [ats] WAN_QUOTA_OUT = 3932160 WAN_QUOTA_IN = 3932160 [core] PORT = 12092 [arm] DEFAULTSERVICES = core PORT = 12366 DEBUG = NO [transport-tcp] TIMEOUT = 300 s PORT = 12368 [TESTING] NUM_PEERS = 5 WEAKRANDOM = YES DEBUG = YES HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat MAX_CONCURRENT_SSH = 10 USE_PROGRESSBARS = YES PEERGROUP_TIMEOUT = 2400 s [gnunetd] HOSTKEY = $SERVICEHOME/.hostkey [PATHS] DEFAULTCONFIG = test_stream_local.conf SERVICEHOME = /tmp/test-stream/ [dns] AUTOSTART = NO [nse] AUTOSTART = NO gnunet-0.9.3/src/stream/Makefile.in0000644000175000017500000006506511762217213014111 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ check_PROGRAMS = test-stream-2peers$(EXEEXT) \ test-stream-2peers_halfclose$(EXEEXT) \ test-stream-local$(EXEEXT) subdir = src/stream DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libgnunetstream_la_DEPENDENCIES = \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_libgnunetstream_la_OBJECTS = stream_api.lo libgnunetstream_la_OBJECTS = $(am_libgnunetstream_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunetstream_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetstream_la_LDFLAGS) \ $(LDFLAGS) -o $@ am_test_stream_2peers_OBJECTS = test_stream_2peers.$(OBJEXT) test_stream_2peers_OBJECTS = $(am_test_stream_2peers_OBJECTS) test_stream_2peers_DEPENDENCIES = \ $(top_builddir)/src/stream/libgnunetstream.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la am_test_stream_2peers_halfclose_OBJECTS = \ test_stream_2peers_halfclose.$(OBJEXT) test_stream_2peers_halfclose_OBJECTS = \ $(am_test_stream_2peers_halfclose_OBJECTS) test_stream_2peers_halfclose_DEPENDENCIES = \ $(top_builddir)/src/stream/libgnunetstream.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la am_test_stream_local_OBJECTS = test_stream_local.$(OBJEXT) test_stream_local_OBJECTS = $(am_test_stream_local_OBJECTS) test_stream_local_DEPENDENCIES = \ $(top_builddir)/src/stream/libgnunetstream.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunetstream_la_SOURCES) $(test_stream_2peers_SOURCES) \ $(test_stream_2peers_halfclose_SOURCES) \ $(test_stream_local_SOURCES) DIST_SOURCES = $(libgnunetstream_la_SOURCES) \ $(test_stream_2peers_SOURCES) \ $(test_stream_2peers_halfclose_SOURCES) \ $(test_stream_local_SOURCES) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @USE_COVERAGE_TRUE@XLIB = -lgcov lib_LTLIBRARIES = libgnunetstream.la libgnunetstream_la_SOURCES = \ stream_api.c stream_protocol.h libgnunetstream_la_LIBADD = \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/util/libgnunetutil.la $(XLIB) libgnunetstream_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) EXTRA_DIST = test_stream_local.conf @ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) test_stream_2peers_SOURCES = \ test_stream_2peers.c test_stream_2peers_LDADD = \ $(top_builddir)/src/stream/libgnunetstream.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la test_stream_2peers_halfclose_SOURCES = \ test_stream_2peers_halfclose.c test_stream_2peers_halfclose_LDADD = \ $(top_builddir)/src/stream/libgnunetstream.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la test_stream_local_SOURCES = \ test_stream_local.c test_stream_local_LDADD = \ $(top_builddir)/src/stream/libgnunetstream.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/stream/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/stream/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunetstream.la: $(libgnunetstream_la_OBJECTS) $(libgnunetstream_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetstream_la_LINK) -rpath $(libdir) $(libgnunetstream_la_OBJECTS) $(libgnunetstream_la_LIBADD) $(LIBS) clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list test-stream-2peers$(EXEEXT): $(test_stream_2peers_OBJECTS) $(test_stream_2peers_DEPENDENCIES) @rm -f test-stream-2peers$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_stream_2peers_OBJECTS) $(test_stream_2peers_LDADD) $(LIBS) test-stream-2peers_halfclose$(EXEEXT): $(test_stream_2peers_halfclose_OBJECTS) $(test_stream_2peers_halfclose_DEPENDENCIES) @rm -f test-stream-2peers_halfclose$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_stream_2peers_halfclose_OBJECTS) $(test_stream_2peers_halfclose_LDADD) $(LIBS) test-stream-local$(EXEEXT): $(test_stream_local_OBJECTS) $(test_stream_local_DEPENDENCIES) @rm -f test-stream-local$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_stream_local_OBJECTS) $(test_stream_local_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_stream_2peers.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_stream_2peers_halfclose.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_stream_local.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool ctags distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-libLTLIBRARIES \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ uninstall-am uninstall-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/arm/0000755000175000017500000000000011763406747011411 500000000000000gnunet-0.9.3/src/arm/test_gnunet_arm.sh0000755000175000017500000000254411671106247015061 00000000000000#!/bin/sh exe="./gnunet-arm -c test_arm_api_data.conf" out=`mktemp /tmp/test-gnunet-arm-logXXXXXXXX` #DEBUG="-L DEBUG" # ---------------------------------------------------------------------------------- echo -n "TEST: Bad argument checking... " if $exe -x 2> /dev/null; then echo "FAIL: error running $exe" exit 1 fi echo "PASS" # ---------------------------------------------------------------------------------- echo -n "TEST: Start ARM..." if ! $exe $DEBUG -s > $out ; then echo "FAIL: error running $exe" echo "Command output was:" cat $out exit 1 fi echo "PASS" sleep 1 # ---------------------------------------------------------------------------------- echo -n "TEST: Start another service... " if ! $exe $DEBUG -i resolver > $out ; then echo "FAIL: error running $exe" echo "Command output was:" cat $out kill %% exit 1 fi sleep 1 echo "PASS" # ---------------------------------------------------------------------------------- echo -n "TEST: Stop a service... " if ! $exe $DEBUG -k resolver > $out; then echo "FAIL: error running $exe" $exe -e exit 1 fi sleep 1 echo "PASS" # ---------------------------------------------------------------------------------- echo -n "TEST: Stop ARM... " if ! $exe $DEBUG -e > $out; then echo "FAIL: error running $exe" exit 1 fi sleep 1 echo "PASS" rm -rf /tmp/test-gnunetd-arm/ rm -f $out gnunet-0.9.3/src/arm/arm.conf.in0000644000175000017500000000072411762111032013342 00000000000000 [arm] @UNIXONLY@ PORT = 2087 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-arm ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DEFAULTSERVICES = topology hostlist dht nse mesh fs UNIXPATH = /tmp/gnunet-service-arm.sock UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES # GLOBAL_POSTFIX = -l $SERVICEHOME/{}-logs # GLOBAL_PREFIX = # USERNAME = # MAXBUF = # TIMEOUT = # DISABLEV6 = # BINDTO = # REJECT_FROM = # REJECT_FROM6 = # PREFIX = gnunet-0.9.3/src/arm/gnunet-arm.c0000644000175000017500000002727311760502551013550 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file arm/gnunet-arm.c * @brief arm for writing a tool * @author Christian Grothoff */ #include "platform.h" #include "gnunet_arm_service.h" #include "gnunet_client_lib.h" #include "gnunet_constants.h" #include "gnunet_getopt_lib.h" #include "gnunet_program_lib.h" #include "gnunet_time_lib.h" /** * Timeout for stopping services. Long to give some services a real chance. */ #define STOP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1) /** * Timeout for stopping ARM. Extra-long since ARM needs to stop everyone else. */ #define STOP_TIMEOUT_ARM GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2) /** * Timeout for starting services, very short because of the strange way start works * (by checking if running before starting, so really this time is always waited on * startup (annoying)). */ #define START_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) /** * Timeout for listing all running services. */ #define LIST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2) /** * Set if we are to shutdown all services (including ARM). */ static int end; /** * Set if we are to start default services (including ARM). */ static int start; /** * Set if we are to stop/start default services (including ARM). */ static int restart; /** * Set if we should delete configuration and temp directory on exit. */ static int delete; /** * Set if we should not print status messages. */ static int quiet; /** * Set if we should print a list of currently running services. */ static int list; /** * Set to the name of a service to start. */ static char *init; /** * Set to the name of a service to kill. */ static char *term; /** * Set to the name of the config file used. */ static const char *config_file; /** * Set to the directory where runtime files are stored. */ static char *dir; /** * Final status code. */ static int ret; /** * Connection with ARM. */ static struct GNUNET_ARM_Handle *h; /** * Our configuration. */ static const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Processing stage that we are in. Simple counter. */ static unsigned int phase; /** * User defined timestamp for completing operations. */ static struct GNUNET_TIME_Relative timeout; /** * Main continuation-passing-style loop. Runs the various * jobs that we've been asked to do in order. * * @param cls closure, unused * @param tc context, unused */ static void cps_loop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Callback invoked with the status of the last operation. Reports to the * user and then runs the next phase in the FSM. * * @param cls pointer to "const char*" identifying service that was manipulated * @param result result of the operation */ static void confirm_cb (void *cls, enum GNUNET_ARM_ProcessStatus result) { const char *service = cls; switch (result) { case GNUNET_ARM_PROCESS_UNKNOWN: FPRINTF (stderr, _("Service `%s' is unknown to ARM.\n"), service); ret = 1; break; case GNUNET_ARM_PROCESS_DOWN: if (quiet != GNUNET_YES) FPRINTF (stdout, _("Service `%s' has been stopped.\n"), service); break; case GNUNET_ARM_PROCESS_ALREADY_RUNNING: FPRINTF (stderr, _("Service `%s' was already running.\n"), service); ret = 1; break; case GNUNET_ARM_PROCESS_STARTING: if (quiet != GNUNET_YES) FPRINTF (stdout, _("Service `%s' has been started.\n"), service); break; case GNUNET_ARM_PROCESS_ALREADY_STOPPING: FPRINTF (stderr, _("Service `%s' was already being stopped.\n"), service); ret = 1; break; case GNUNET_ARM_PROCESS_ALREADY_DOWN: FPRINTF (stderr, _("Service `%s' was already not running.\n"), service); ret = 1; break; case GNUNET_ARM_PROCESS_SHUTDOWN: FPRINTF (stderr, "%s", _("Request ignored as ARM is shutting down.\n")); ret = 1; break; case GNUNET_ARM_PROCESS_COMMUNICATION_ERROR: FPRINTF (stderr, "%s", _("Error communicating with ARM service.\n")); ret = 1; break; case GNUNET_ARM_PROCESS_COMMUNICATION_TIMEOUT: FPRINTF (stderr, "%s", _("Timeout communicating with ARM service.\n")); ret = 1; break; case GNUNET_ARM_PROCESS_FAILURE: FPRINTF (stderr, "%s", _("Operation failed.\n")); ret = 1; break; default: FPRINTF (stderr, "%s", _("Unknown response code from ARM.\n")); break; } GNUNET_SCHEDULER_add_continuation (&cps_loop, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } /** * Callback invoked with the list of running services. * Reports to the user and then runs the next phase in the FSM. * * @param cls currently not used * @param result result of the operation * @param count number of running services * @param list copy of the list of running services */ static void list_cb (void *cls, int result, unsigned int count, const char *const*list) { unsigned int i; if ( (result != GNUNET_YES) || (NULL == list) ) { FPRINTF (stderr, "%s", _("Error communicating with ARM. ARM not running?\n")); return; } FPRINTF (stdout, "%s", _("Running services:\n")); for (i=0; i 0) timeout.rel_value = temp_timeout_ms; if (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-arm", gettext_noop ("Control services and the Automated Restart Manager (ARM)"), options, &run, NULL)) { return ret; } return 1; } /* end of gnunet-arm.c */ gnunet-0.9.3/src/arm/arm.h0000644000175000017500000000354111760502551012247 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @author Christian Grothoff * @file arm/arm.h */ #ifndef ARM_H #define ARM_H #include "gnunet_common.h" /** * This option will turn on the DEBUG loglevel for * all processes controlled by this ARM! */ #define DEBUG_ARM GNUNET_EXTRA_LOGGING GNUNET_NETWORK_STRUCT_BEGIN /** * Reply from ARM to client. */ struct GNUNET_ARM_ResultMessage { /** * Reply to client, of type is GNUNET_MESSAGE_TYPE_ARM_RESULT. */ struct GNUNET_MessageHeader header; /** * Status from the 'enum GNUNET_ARM_ProcessStatus' */ uint32_t status; }; /** * Reply from ARM to client for the * GNUNET_MESSAGE_TYPE_ARM_LIST request followed by count * '\0' terminated strings. header->size contains the * total size (including all strings). */ struct GNUNET_ARM_ListResultMessage { /** * Reply to client is of type GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT */ struct GNUNET_MessageHeader header; /** * Number of '\0' terminated strings that follow * this message. */ uint16_t count; }; GNUNET_NETWORK_STRUCT_END #endif gnunet-0.9.3/src/arm/Makefile.am0000644000175000017500000000365311704315743013362 00000000000000INCLUDES = -I$(top_srcdir)/src/include pkgcfgdir= $(pkgdatadir)/config.d/ pkgcfg_DATA = \ arm.conf if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIB = -lgcov endif lib_LTLIBRARIES = libgnunetarm.la libgnunetarm_la_SOURCES = \ arm_api.c arm.h libgnunetarm_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) $(XLIB) libgnunetarm_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 1:1:0 bin_PROGRAMS = \ gnunet-arm \ gnunet-service-arm \ mockup-service gnunet_arm_SOURCES = \ gnunet-arm.c gnunet_arm_LDADD = \ $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_arm_DEPENDENCIES = \ libgnunetarm.la gnunet_service_arm_SOURCES = \ gnunet-service-arm.c gnunet_service_arm_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_service_arm_DEPENDENCIES = \ libgnunetarm.la mockup_service_SOURCES = \ mockup-service.c mockup_service_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la check_PROGRAMS = \ test_arm_api \ test_exponential_backoff \ test_gnunet_service_manager check_SCRIPTS = \ test_gnunet_arm.sh if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) $(check_SCRIPTS) endif test_arm_api_SOURCES = \ test_arm_api.c test_arm_api_LDADD = \ $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la test_exponential_backoff_SOURCES = \ test_exponential_backoff.c test_exponential_backoff_LDADD = \ $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la test_gnunet_service_manager_SOURCES = \ test_gnunet_service_manager.c test_gnunet_service_manager_LDADD = \ $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ test_arm_api_data.conf \ do_start_process.c \ $(check_SCRIPTS) gnunet-0.9.3/src/arm/test_arm_api.c0000644000175000017500000000757011760502551014140 00000000000000/* This file is part of GNUnet. (C) 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file arm/test_arm_api.c * @brief testcase for arm_api.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_arm_service.h" #include "gnunet_client_lib.h" #include "gnunet_configuration_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_program_lib.h" #include "gnunet_resolver_service.h" #define VERBOSE GNUNET_NO #define START_ARM GNUNET_YES #define START_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 1500) #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) static const struct GNUNET_CONFIGURATION_Handle *cfg; static struct GNUNET_ARM_Handle *arm; static int ok = 1; static void arm_stopped (void *cls, enum GNUNET_ARM_ProcessStatus success) { GNUNET_break (success == GNUNET_ARM_PROCESS_DOWN); if (success != GNUNET_ARM_PROCESS_DOWN) ok = 3; else if (ok == 1) ok = 0; } static void arm_notify_stop (void *cls, enum GNUNET_ARM_ProcessStatus success) { GNUNET_break (success == GNUNET_ARM_PROCESS_DOWN); #if START_ARM GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); #endif } static void dns_notify (void *cls, const struct sockaddr *addr, socklen_t addrlen) { if (addr == NULL) { if (ok != 0) { GNUNET_break (0); ok = 2; } GNUNET_ARM_stop_service (arm, "resolver", TIMEOUT, &arm_notify_stop, NULL); return; } GNUNET_break (addr != NULL); ok = 0; } static void resolver_notify (void *cls, enum GNUNET_ARM_ProcessStatus success) { if (success != GNUNET_ARM_PROCESS_STARTING) { GNUNET_break (0); ok = 2; #if START_ARM GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); #endif return; } GNUNET_RESOLVER_ip_get ("localhost", AF_INET, TIMEOUT, &dns_notify, NULL); } static void arm_notify (void *cls, enum GNUNET_ARM_ProcessStatus success) { if (success != GNUNET_ARM_PROCESS_STARTING) { GNUNET_break (0); ok = 2; #if START_ARM GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); #endif } GNUNET_ARM_start_service (arm, "resolver", START_TIMEOUT, &resolver_notify, NULL); } static void task (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { cfg = c; arm = GNUNET_ARM_connect (cfg, NULL); #if START_ARM GNUNET_ARM_start_service (arm, "arm", START_TIMEOUT, &arm_notify, NULL); #else arm_notify (NULL, GNUNET_YES); #endif } static int check () { char *const argv[] = { "test-arm-api", "-c", "test_arm_api_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_assert (GNUNET_OK == GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-arm-api", "nohelp", options, &task, NULL)); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-arm-api", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); return ret; } /* end of test_arm_api.c */ gnunet-0.9.3/src/arm/mockup-service.c0000644000175000017500000000427511760502551014424 00000000000000/* This file is part of GNUnet. (C) 2007, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "platform.h" #include "gnunet_disk_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_protocols.h" #include "gnunet_service_lib.h" #include "gnunet_statistics_service.h" #include "gnunet_strings_lib.h" #include "gnunet_time_lib.h" /** * Handler for SHUTDOWN message. * * @param cls closure (refers to service) * @param client identification of the client * @param message the actual message */ static void handle_shutdown (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Initiating shutdown as requested by client.\n")); GNUNET_SERVER_client_persist_ (client); GNUNET_SCHEDULER_shutdown (); } static void run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *cfg) { static const struct GNUNET_SERVER_MessageHandler handlers[] = { {&handle_shutdown, NULL, GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN, sizeof (struct GNUNET_MessageHeader)}, {NULL, NULL, 0, 0} }; /* process client requests */ GNUNET_SERVER_add_handlers (server, handlers); } int main (int argc, char *const *argv) { int ret; ret = (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "do-nothing", GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; return ret; } gnunet-0.9.3/src/arm/test_arm_api_data.conf0000644000175000017500000000127611611077627015637 00000000000000[PATHS] SERVICEHOME = /tmp/test-gnunetd-arm/ DEFAULTCONFIG = test_arm_api_data.conf [arm] PORT = 23354 DEFAULTSERVICES = BINARY = gnunet-service-arm OPTIONS = -L ERROR # DEBUG = YES #PREFIX = valgrind --tool=memcheck --leak-check=yes [resolver] # DEBUG = YES PORT = 23355 # PREFIX = valgrind [do-nothing] #DEBUG = YES AUTOSTART = NO PORT = 2223 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = mockup-service ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; [fs] AUTOSTART = NO [datastore] AUTOSTART = NO [core] AUTOSTART = NO [transport] AUTOSTART = NO [peerinfo] AUTOSTART = NO [statistics] AUTOSTART = YES # DEBUG = NO [dns] AUTOSTART = NO [nse] AUTOSTART = NO gnunet-0.9.3/src/arm/test_exponential_backoff.c0000644000175000017500000002650411760502551016527 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file arm/test_exponential_backoff.c * @brief testcase for gnunet-service-arm.c */ #include "platform.h" #include "gnunet_arm_service.h" #include "gnunet_client_lib.h" #include "gnunet_configuration_lib.h" #include "gnunet_program_lib.h" #include "gnunet_protocols.h" #define VERBOSE GNUNET_NO #define START_ARM GNUNET_YES #define LOG_BACKOFF GNUNET_NO #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) #define SERVICE_TEST_TIMEOUT GNUNET_TIME_UNIT_FOREVER_REL #define FIVE_MILLISECONDS GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 5) static const struct GNUNET_CONFIGURATION_Handle *cfg; static struct GNUNET_ARM_Handle *arm; static int ok = 1; static int trialCount; static struct GNUNET_TIME_Absolute startedWaitingAt; struct GNUNET_TIME_Relative waitedFor; #if LOG_BACKOFF static FILE *killLogFilePtr; static char *killLogFileName; #endif /** * Context for handling the shutdown of a service. */ struct ShutdownContext { /** * Connection to the service that is being shutdown. */ struct GNUNET_CLIENT_Connection *sock; /** * Time allowed for shutdown to happen. */ struct GNUNET_TIME_Absolute timeout; /** * Task set up to cancel the shutdown request on timeout. */ GNUNET_SCHEDULER_TaskIdentifier cancel_task; /** * Task to call once shutdown complete */ GNUNET_CLIENT_ShutdownTask cont; /** * Closure for shutdown continuation */ void *cont_cls; /** * We received a confirmation that the service will shut down. */ int confirmed; }; /** * Handler receiving response to service shutdown requests. * First call with NULL: service misbehaving, or something. * First call with GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN: * - service will shutdown * Second call with NULL: * - service has now really shut down. * * @param cls closure * @param msg NULL, indicating socket closure. */ static void service_shutdown_handler (void *cls, const struct GNUNET_MessageHeader *msg) { struct ShutdownContext *shutdown_ctx = cls; if (msg == NULL) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service shutdown complete.\n"); #endif if (shutdown_ctx->cont != NULL) shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_NO); GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task); GNUNET_CLIENT_disconnect (shutdown_ctx->sock); GNUNET_free (shutdown_ctx); return; } GNUNET_assert (ntohs (msg->size) == sizeof (struct GNUNET_MessageHeader)); switch (ntohs (msg->type)) { case GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN: #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received confirmation for service shutdown.\n"); #endif shutdown_ctx->confirmed = GNUNET_YES; GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler, shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL); break; default: /* Fall through */ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Service shutdown refused!\n"); if (shutdown_ctx->cont != NULL) shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_YES); GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task); GNUNET_CLIENT_disconnect (shutdown_ctx->sock); GNUNET_free (shutdown_ctx); break; } } /** * Shutting down took too long, cancel receive and return error. * * @param cls closure * @param tc context information (why was this task triggered now) */ void service_shutdown_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ShutdownContext *shutdown_ctx = cls; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "service_shutdown_cancel called!\n"); shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_SYSERR); GNUNET_CLIENT_disconnect (shutdown_ctx->sock); GNUNET_free (shutdown_ctx); } /** * If possible, write a shutdown message to the target * buffer and destroy the client connection. * * @param cls the "struct GNUNET_CLIENT_Connection" to destroy * @param size number of bytes available in buf * @param buf NULL on error, otherwise target buffer * @return number of bytes written to buf */ static size_t write_shutdown (void *cls, size_t size, void *buf) { struct GNUNET_MessageHeader *msg; struct ShutdownContext *shutdown_ctx = cls; if (size < sizeof (struct GNUNET_MessageHeader)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Failed to transmit shutdown request to client.\n")); shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_SYSERR); GNUNET_CLIENT_disconnect (shutdown_ctx->sock); GNUNET_free (shutdown_ctx); return 0; /* client disconnected */ } GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler, shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL); shutdown_ctx->cancel_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (shutdown_ctx->timeout), &service_shutdown_cancel, shutdown_ctx); msg = (struct GNUNET_MessageHeader *) buf; msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN); msg->size = htons (sizeof (struct GNUNET_MessageHeader)); return sizeof (struct GNUNET_MessageHeader); } /** * Request that the service should shutdown. * Afterwards, the connection will automatically be * disconnected. Hence the "sock" should not * be used by the caller after this call * (calling this function frees "sock" after a while). * * @param sock the socket connected to the service * @param timeout how long to wait before giving up on transmission * @param cont continuation to call once the service is really down * @param cont_cls closure for continuation * */ static void arm_service_shutdown (struct GNUNET_CLIENT_Connection *sock, struct GNUNET_TIME_Relative timeout, GNUNET_CLIENT_ShutdownTask cont, void *cont_cls) { struct ShutdownContext *shutdown_ctx; shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext)); shutdown_ctx->cont = cont; shutdown_ctx->cont_cls = cont_cls; shutdown_ctx->sock = sock; shutdown_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); GNUNET_CLIENT_notify_transmit_ready (sock, sizeof (struct GNUNET_MessageHeader), timeout, GNUNET_NO, &write_shutdown, shutdown_ctx); } static void arm_notify_stop (void *cls, enum GNUNET_ARM_ProcessStatus status) { GNUNET_assert ( (status == GNUNET_ARM_PROCESS_DOWN) || (status == GNUNET_ARM_PROCESS_ALREADY_DOWN) ); #if START_ARM GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, NULL, NULL); #endif } static void kill_task (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc); static void do_nothing_notify (void *cls, enum GNUNET_ARM_ProcessStatus status) { GNUNET_assert (status == GNUNET_ARM_PROCESS_STARTING); ok = 1; GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &kill_task, NULL); } static void arm_notify (void *cls, enum GNUNET_ARM_ProcessStatus status) { GNUNET_assert (status == GNUNET_ARM_PROCESS_STARTING); GNUNET_ARM_start_service (arm, "do-nothing", TIMEOUT, &do_nothing_notify, NULL); } static void kill_task (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc); static void do_nothing_restarted_notify_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { static char a; trialCount++; #if LOG_BACKOFF if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) { FPRINTF (killLogFilePtr, "%d.Reason is shutdown!\n", trialCount); } else if ((tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT) != 0) { FPRINTF (killLogFilePtr, "%d.Reason is timeout!\n", trialCount); } else if ((tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE) != 0) { FPRINTF (killLogFilePtr, "%d.Service is running!\n", trialCount); } #endif GNUNET_SCHEDULER_add_now (&kill_task, &a); } static void do_test (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_CLIENT_service_test ("do-nothing", cfg, TIMEOUT, &do_nothing_restarted_notify_task, NULL); } static void shutdown_cont (void *cls, int reason) { trialCount++; startedWaitingAt = GNUNET_TIME_absolute_get (); GNUNET_SCHEDULER_add_delayed (waitedFor, &do_test, NULL); } static void kill_task (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc) { static struct GNUNET_CLIENT_Connection *doNothingConnection = NULL; if (NULL != cbData) { waitedFor = GNUNET_TIME_absolute_get_duration (startedWaitingAt); #if LOG_BACKOFF FPRINTF (killLogFilePtr, "Waited for: %llu ms\n", (unsigned long long) waitedFor.rel_value); #endif } else { waitedFor.rel_value = 0; } /* Connect to the doNothing task */ doNothingConnection = GNUNET_CLIENT_connect ("do-nothing", cfg); GNUNET_assert (doNothingConnection != NULL); if (trialCount == 12) { GNUNET_CLIENT_disconnect (doNothingConnection); GNUNET_ARM_stop_service (arm, "do-nothing", TIMEOUT, &arm_notify_stop, NULL); ok = 0; return; } /* Use the created connection to kill the doNothingTask */ arm_service_shutdown (doNothingConnection, TIMEOUT, &shutdown_cont, NULL); } static void task (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { cfg = c; arm = GNUNET_ARM_connect (cfg, NULL); #if START_ARM GNUNET_ARM_start_service (arm, "arm", GNUNET_TIME_UNIT_ZERO, &arm_notify, NULL); #else arm_do_nothing (NULL, GNUNET_YES); #endif } static int check () { char *const argv[] = { "test-exponential-backoff", "-c", "test_arm_api_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; /* Running ARM and running the do_nothing task */ GNUNET_assert (GNUNET_OK == GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-exponential-backoff", "nohelp", options, &task, NULL)); return ok; } static int init () { #if LOG_BACKOFF killLogFileName = GNUNET_DISK_mktemp ("exponential-backoff-waiting.log"); if (NULL == (killLogFilePtr = FOPEN (killLogFileName, "w"))) { GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "fopen", killLogFileName); GNUNET_free (killLogFileName); return GNUNET_SYSERR; } #endif return GNUNET_OK; } static void houseKeep () { #if LOG_BACKOFF GNUNET_assert (0 == fclose (killLogFilePtr)); GNUNET_free (killLogFileName); #endif } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-exponential-backoff", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); init (); ret = check (); houseKeep (); return ret; } /* end of test_exponential_backoff.c */ gnunet-0.9.3/src/arm/gnunet-service-arm.c0000644000175000017500000010437111760502551015201 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file arm/gnunet-service-arm.c * @brief the automated restart manager service * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_arm_service.h" #include "gnunet_protocols.h" #include "arm.h" /** * Threshold after which exponential backoff shouldn't increase (in ms); 30m */ #define EXPONENTIAL_BACKOFF_THRESHOLD GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30) /** * List of our services. */ struct ServiceList; /** * Record with information about a listen socket we have open. */ struct ServiceListeningInfo { /** * This is a linked list. */ struct ServiceListeningInfo *next; /** * This is a linked list. */ struct ServiceListeningInfo *prev; /** * Address this socket is listening on. */ struct sockaddr *service_addr; /** * Service this listen socket is for. */ struct ServiceList *sl; /** * Number of bytes in 'service_addr' */ socklen_t service_addr_len; /** * Our listening socket. */ struct GNUNET_NETWORK_Handle *listen_socket; /** * Task doing the accepting. */ GNUNET_SCHEDULER_TaskIdentifier accept_task; }; /** * List of our services. */ struct ServiceList { /** * This is a doubly-linked list. */ struct ServiceList *next; /** * This is a doubly-linked list. */ struct ServiceList *prev; /** * Linked list of listen sockets associated with this service. */ struct ServiceListeningInfo *listen_head; /** * Linked list of listen sockets associated with this service. */ struct ServiceListeningInfo *listen_tail; /** * Name of the service. */ char *name; /** * Name of the binary used. */ char *binary; /** * Name of the configuration file used. */ char *config; /** * Client to notify upon kill completion (waitpid), NULL * if we should simply restart the process. */ struct GNUNET_SERVER_Client *killing_client; /** * Process structure pointer of the child. */ struct GNUNET_OS_Process *proc; /** * Process exponential backoff time */ struct GNUNET_TIME_Relative backoff; /** * Absolute time at which the process is scheduled to restart in case of death */ struct GNUNET_TIME_Absolute restart_at; /** * Time we asked the service to shut down (used to calculate time it took * the service to terminate). */ struct GNUNET_TIME_Absolute killed_at; /** * Is this service to be started by default (or did a client tell us explicitly * to start it)? GNUNET_NO if the service is started only upon 'accept' on a * listen socket or possibly explicitly by a client changing the value. */ int is_default; /** * Should we use pipes to signal this process? (YES for Java binaries and if we * are on Windoze). */ int pipe_control; }; /** * List of running services. */ static struct ServiceList *running_head; /** * List of running services. */ static struct ServiceList *running_tail; /** * Our configuration */ static const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Command to prepend to each actual command. */ static char *prefix_command; /** * Option to append to each actual command. */ static char *final_option; /** * ID of task called whenever we get a SIGCHILD. */ static GNUNET_SCHEDULER_TaskIdentifier child_death_task; /** * ID of task called whenever the timeout for restarting a child * expires. */ static GNUNET_SCHEDULER_TaskIdentifier child_restart_task; /** * Pipe used to communicate shutdown via signal. */ static struct GNUNET_DISK_PipeHandle *sigpipe; /** * Are we in shutdown mode? */ static int in_shutdown; /** * Handle to our server instance. Our server is a bit special in that * its service is not immediately stopped once we get a shutdown * request (since we need to continue service until all of our child * processes are dead). This handle is used to shut down the server * (and thus trigger process termination) once all child processes are * also dead. A special option in the ARM configuration modifies the * behaviour of the service implementation to not do the shutdown * immediately. */ static struct GNUNET_SERVER_Handle *server; #include "do_start_process.c" /** * Actually start the process for the given service. * * @param sl identifies service to start */ static void start_process (struct ServiceList *sl) { char *loprefix; char *options; char *optpos; char *optend; const char *next; int use_debug; char b; char *val; struct ServiceListeningInfo *sli; SOCKTYPE *lsocks; unsigned int ls; /* calculate listen socket list */ lsocks = NULL; ls = 0; for (sli = sl->listen_head; NULL != sli; sli = sli->next) { GNUNET_array_append (lsocks, ls, GNUNET_NETWORK_get_fd (sli->listen_socket)); if (sli->accept_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (sli->accept_task); sli->accept_task = GNUNET_SCHEDULER_NO_TASK; } } #if WINDOWS GNUNET_array_append (lsocks, ls, INVALID_SOCKET); #else GNUNET_array_append (lsocks, ls, -1); #endif /* obtain configuration */ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "PREFIX", &loprefix)) loprefix = GNUNET_strdup (prefix_command); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "OPTIONS", &options)) { options = GNUNET_strdup (final_option); if (NULL == strstr (options, "%")) { /* replace '{}' with service name */ while (NULL != (optpos = strstr (options, "{}"))) { optpos[0] = '%'; optpos[1] = 's'; GNUNET_asprintf (&optpos, options, sl->name); GNUNET_free (options); options = optpos; } /* replace '$PATH' with value associated with "PATH" */ while (NULL != (optpos = strstr (options, "$"))) { optend = optpos + 1; while (isupper ((unsigned char) *optend)) optend++; b = *optend; if ('\0' == b) next = ""; else next = optend + 1; *optend = '\0'; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", optpos + 1, &val)) val = GNUNET_strdup (""); *optpos = '\0'; GNUNET_asprintf (&optpos, "%s%s%c%s", options, val, b, next); GNUNET_free (options); GNUNET_free (val); options = optpos; } } } use_debug = GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name, "DEBUG"); /* actually start process */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting service `%s' using binary `%s' and configuration `%s'\n", sl->name, sl->binary, sl->config); GNUNET_assert (NULL == sl->proc); if (GNUNET_YES == use_debug) sl->proc = do_start_process (sl->pipe_control, lsocks, loprefix, sl->binary, "-c", sl->config, "-L", "DEBUG", options, NULL); else sl->proc = do_start_process (sl->pipe_control, lsocks, loprefix, sl->binary, "-c", sl->config, options, NULL); if (sl->proc == NULL) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to start service `%s'\n"), sl->name); else GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting service `%s'\n"), sl->name); /* clean up */ GNUNET_free (loprefix); GNUNET_free (options); GNUNET_array_grow (lsocks, ls, 0); } /** * Transmit a status result message. * * @param cls pointer to "unit16_t*" with message type * @param size number of bytes available in buf * @param buf where to copy the message, NULL on error * @return number of bytes copied to buf */ static size_t write_result (void *cls, size_t size, void *buf) { enum GNUNET_ARM_ProcessStatus *res = cls; struct GNUNET_ARM_ResultMessage *msg; if (buf == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Could not send status result to client\n")); return 0; /* error, not much we can do */ } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending status response %u to client\n", (unsigned int) *res); GNUNET_assert (size >= sizeof (struct GNUNET_ARM_ResultMessage)); msg = buf; msg->header.size = htons (sizeof (struct GNUNET_ARM_ResultMessage)); msg->header.type = htons (GNUNET_MESSAGE_TYPE_ARM_RESULT); msg->status = htonl ((uint32_t) (*res)); GNUNET_free (res); return sizeof (struct GNUNET_ARM_ResultMessage); } /** * Transmit the list of running services. * * @param cls pointer to struct GNUNET_ARM_ListResultMessage with the message * @param size number of bytes available in buf * @param buf where to copy the message, NULL on error * @return number of bytes copied to buf */ static size_t write_list_result (void *cls, size_t size, void *buf) { struct GNUNET_ARM_ListResultMessage *msg = cls; struct GNUNET_ARM_ListResultMessage *rslt; size_t rslt_size; if (buf == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Could not send list result to client\n")); return 0; /* error, not much we can do */ } GNUNET_assert (size >= msg->header.size); rslt = buf; rslt->header.size = htons (msg->header.size); rslt->header.type = htons (msg->header.type); rslt->count = htons (msg->count); size_t list_size = msg->header.size - sizeof (struct GNUNET_ARM_ListResultMessage); memcpy (&rslt[1], &msg[1], list_size); rslt_size = msg->header.size; GNUNET_free (msg); return rslt_size; } /** * Signal our client that we will start or stop the * service. * * @param client who is being signalled * @param name name of the service * @param result message type to send * @return NULL if it was not found */ static void signal_result (struct GNUNET_SERVER_Client *client, const char *name, enum GNUNET_ARM_ProcessStatus result) { enum GNUNET_ARM_ProcessStatus *res; if (NULL == client) return; /* FIXME: this is not super-clean yet... */ res = GNUNET_malloc (sizeof (enum GNUNET_ARM_ProcessStatus)); *res = result; GNUNET_SERVER_notify_transmit_ready (client, sizeof (struct GNUNET_ARM_ResultMessage), GNUNET_TIME_UNIT_FOREVER_REL, &write_result, res); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Find the process with the given service * name in the given list and return it. * * @param name which service entry to look up * @return NULL if it was not found */ static struct ServiceList * find_service (const char *name) { struct ServiceList *sl; sl = running_head; while (sl != NULL) { if (0 == strcasecmp (sl->name, name)) return sl; sl = sl->next; } return NULL; } /** * First connection has come to the listening socket associated with the service, * create the service in order to relay the incoming connection to it * * @param cls callback data, struct ServiceListeningInfo describing a listen socket * @param tc context */ static void accept_connection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ServiceListeningInfo *sli = cls; struct ServiceList *sl = sli->sl; sli->accept_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) return; start_process (sl); } /** * Creating a listening socket for each of the service's addresses and * wait for the first incoming connection to it * * @param sa address associated with the service * @param addr_len length of sa * @param sl service entry for the service in question */ static void create_listen_socket (struct sockaddr *sa, socklen_t addr_len, struct ServiceList *sl) { static int on = 1; struct GNUNET_NETWORK_Handle *sock; struct ServiceListeningInfo *sli; switch (sa->sa_family) { case AF_INET: sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0); break; case AF_INET6: sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); break; case AF_UNIX: if (strcmp (GNUNET_a2s (sa, addr_len), "@") == 0) /* Do not bind to blank UNIX path! */ return; sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0); break; default: GNUNET_break (0); sock = NULL; errno = EAFNOSUPPORT; break; } if (NULL == sock) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unable to create socket for service `%s': %s\n"), sl->name, STRERROR (errno)); GNUNET_free (sa); return; } if (GNUNET_NETWORK_socket_setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); #ifdef IPV6_V6ONLY if ((sa->sa_family == AF_INET6) && (GNUNET_NETWORK_socket_setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); #endif if (GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) sa, addr_len) != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Unable to bind listening socket for service `%s' to address `%s': %s\n"), sl->name, GNUNET_a2s (sa, addr_len), STRERROR (errno)); GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); GNUNET_free (sa); return; } if (GNUNET_NETWORK_socket_listen (sock, 5) != GNUNET_OK) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen"); GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); GNUNET_free (sa); return; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("ARM now monitors connections to service `%s' at `%s'\n"), sl->name, GNUNET_a2s (sa, addr_len)); sli = GNUNET_malloc (sizeof (struct ServiceListeningInfo)); sli->service_addr = sa; sli->service_addr_len = addr_len; sli->listen_socket = sock; sli->sl = sl; sli->accept_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sock, &accept_connection, sli); GNUNET_CONTAINER_DLL_insert (sl->listen_head, sl->listen_tail, sli); } /** * Remove and free an entry in the service list. Listen sockets * must have already been cleaned up. Only to be called during shutdown. * * @param sl entry to free */ static void free_service (struct ServiceList *sl) { GNUNET_assert (GNUNET_YES == in_shutdown); GNUNET_CONTAINER_DLL_remove (running_head, running_tail, sl); GNUNET_assert (NULL == sl->listen_head); GNUNET_free_non_null (sl->config); GNUNET_free_non_null (sl->binary); GNUNET_free (sl->name); GNUNET_free (sl); } /** * Handle START-message. * * @param cls closure (always NULL) * @param client identification of the client * @param message the actual message * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static void handle_start (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const char *servicename; struct ServiceList *sl; uint16_t size; size = ntohs (message->size); size -= sizeof (struct GNUNET_MessageHeader); servicename = (const char *) &message[1]; if ((size == 0) || (servicename[size - 1] != '\0')) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } if (GNUNET_YES == in_shutdown) { signal_result (client, servicename, GNUNET_ARM_PROCESS_SHUTDOWN); return; } sl = find_service (servicename); if (NULL == sl) { signal_result (client, servicename, GNUNET_ARM_PROCESS_UNKNOWN); return; } sl->is_default = GNUNET_YES; if (sl->proc != NULL) { signal_result (client, servicename, GNUNET_ARM_PROCESS_ALREADY_RUNNING); return; } start_process (sl); signal_result (client, servicename, GNUNET_ARM_PROCESS_STARTING); } /** * Handle STOP-message. * * @param cls closure (always NULL) * @param client identification of the client * @param message the actual message * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static void handle_stop (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct ServiceList *sl; const char *servicename; uint16_t size; size = ntohs (message->size); size -= sizeof (struct GNUNET_MessageHeader); servicename = (const char *) &message[1]; if ((size == 0) || (servicename[size - 1] != '\0')) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Preparing to stop `%s'\n"), servicename); sl = find_service (servicename); if (sl == NULL) { signal_result (client, servicename, GNUNET_ARM_PROCESS_UNKNOWN); return; } sl->is_default = GNUNET_NO; if (GNUNET_YES == in_shutdown) { /* shutdown in progress */ signal_result (client, servicename, GNUNET_ARM_PROCESS_SHUTDOWN); return; } if (sl->killing_client != NULL) { /* killing already in progress */ signal_result (client, servicename, GNUNET_ARM_PROCESS_ALREADY_STOPPING); return; } if (sl->proc == NULL) { /* process is down */ signal_result (client, servicename, GNUNET_ARM_PROCESS_ALREADY_DOWN); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending kill signal to service `%s', waiting for process to die.\n", servicename); sl->killed_at = GNUNET_TIME_absolute_get (); if (0 != GNUNET_OS_process_kill (sl->proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); sl->killing_client = client; GNUNET_SERVER_client_keep (client); } /** * Handle LIST-message. * * @param cls closure (always NULL) * @param client identification of the client * @param message the actual message */ static void handle_list (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct GNUNET_ARM_ListResultMessage *msg; size_t string_list_size; size_t total_size; struct ServiceList *sl; uint16_t count; if (NULL == client) return; count = 0; string_list_size = 0; /* first count the running processes get their name's size */ for (sl = running_head; sl != NULL; sl = sl->next) { if (sl->proc != NULL) { string_list_size += strlen (sl->name); string_list_size += strlen (sl->binary); string_list_size += 4; count++; } } total_size = sizeof (struct GNUNET_ARM_ListResultMessage) + string_list_size; msg = GNUNET_malloc (total_size); msg->header.size = total_size; msg->header.type = GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT; msg->count = count; char *pos = (char *)&msg[1]; for (sl = running_head; sl != NULL; sl = sl->next) { if (sl->proc != NULL) { size_t s = strlen (sl->name) + strlen (sl->binary) + 4; GNUNET_snprintf(pos, s, "%s (%s)", sl->name, sl->binary); pos += s; } } GNUNET_SERVER_notify_transmit_ready (client, msg->header.size, GNUNET_TIME_UNIT_FOREVER_REL, &write_list_result, msg); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * We are done with everything. Stop remaining * tasks, signal handler and the server. */ static void do_shutdown () { if (NULL != server) { GNUNET_SERVER_destroy (server); server = NULL; } if (GNUNET_SCHEDULER_NO_TASK != child_death_task) { GNUNET_SCHEDULER_cancel (child_death_task); child_death_task = GNUNET_SCHEDULER_NO_TASK; } } /** * Task run for shutdown. * * @param cls closure, NULL if we need to self-restart * @param tc context */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ServiceList *pos; struct ServiceList *nxt; struct ServiceListeningInfo *sli; if (GNUNET_SCHEDULER_NO_TASK != child_restart_task) { GNUNET_SCHEDULER_cancel (child_restart_task); child_restart_task = GNUNET_SCHEDULER_NO_TASK; } in_shutdown = GNUNET_YES; /* first, stop listening */ for (pos = running_head; NULL != pos; pos = pos->next) { while (NULL != (sli = pos->listen_head)) { GNUNET_CONTAINER_DLL_remove (pos->listen_head, pos->listen_tail, sli); if (sli->accept_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (sli->accept_task); sli->accept_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sli->listen_socket)); GNUNET_free (sli->service_addr); GNUNET_free (sli); } } /* then, shutdown all existing service processes */ nxt = running_head; while (NULL != (pos = nxt)) { nxt = pos->next; if (pos->proc != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stopping service `%s'\n", pos->name); pos->killed_at = GNUNET_TIME_absolute_get (); if (0 != GNUNET_OS_process_kill (pos->proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); } else { free_service (pos); } } /* finally, should all service processes be already gone, terminate for real */ if (running_head == NULL) do_shutdown (); } /** * Task run whenever it is time to restart a child that died. * * @param cls closure, always NULL * @param tc context */ static void delayed_restart_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ServiceList *sl; struct GNUNET_TIME_Relative lowestRestartDelay; struct ServiceListeningInfo *sli; child_restart_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; GNUNET_assert (GNUNET_NO == in_shutdown); lowestRestartDelay = GNUNET_TIME_UNIT_FOREVER_REL; /* check for services that need to be restarted due to * configuration changes or because the last restart failed */ for (sl = running_head; NULL != sl; sl = sl->next) { if (NULL != sl->proc) continue; /* service is currently not running */ if (GNUNET_TIME_absolute_get_remaining (sl->restart_at).rel_value == 0) { /* restart is now allowed */ if (sl->is_default) { /* process should run by default, start immediately */ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Restarting service `%s'.\n"), sl->name); start_process (sl); } else { /* process is run on-demand, ensure it is re-started if there is demand */ for (sli = sl->listen_head; NULL != sli; sli = sli->next) if (GNUNET_SCHEDULER_NO_TASK == sli->accept_task) { /* accept was actually paused, so start it again */ sli->accept_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sli->listen_socket, &accept_connection, sli); } } } else { /* update calculation for earliest time to reactivate a service */ lowestRestartDelay = GNUNET_TIME_relative_min (lowestRestartDelay, GNUNET_TIME_absolute_get_remaining (sl->restart_at)); } } if (lowestRestartDelay.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Will restart process in %llums\n", (unsigned long long) lowestRestartDelay.rel_value); child_restart_task = GNUNET_SCHEDULER_add_delayed_with_priority (lowestRestartDelay, GNUNET_SCHEDULER_PRIORITY_IDLE, &delayed_restart_task, NULL); } } /** * Task triggered whenever we receive a SIGCHLD (child * process died). * * @param cls closure, NULL if we need to self-restart * @param tc context */ static void maint_child_death (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ServiceList *pos; struct ServiceList *next; struct ServiceListeningInfo *sli; const char *statstr; int statcode; int ret; char c[16]; enum GNUNET_OS_ProcessStatusType statusType; unsigned long statusCode; const struct GNUNET_DISK_FileHandle *pr; pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ); child_death_task = GNUNET_SCHEDULER_NO_TASK; if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) { /* shutdown scheduled us, ignore! */ child_death_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, pr, &maint_child_death, NULL); return; } /* consume the signal */ GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c))); /* check for services that died (WAITPID) */ next = running_head; while (NULL != (pos = next)) { next = pos->next; if (pos->proc == NULL) { if (GNUNET_YES == in_shutdown) free_service (pos); continue; } if ((GNUNET_SYSERR == (ret = GNUNET_OS_process_status (pos->proc, &statusType, &statusCode))) || ((ret == GNUNET_NO) || (statusType == GNUNET_OS_PROCESS_STOPPED) || (statusType == GNUNET_OS_PROCESS_RUNNING))) continue; if (statusType == GNUNET_OS_PROCESS_EXITED) { statstr = _( /* process termination method */ "exit"); statcode = statusCode; } else if (statusType == GNUNET_OS_PROCESS_SIGNALED) { statstr = _( /* process termination method */ "signal"); statcode = statusCode; } else { statstr = _( /* process termination method */ "unknown"); statcode = 0; } if (0 != pos->killed_at.abs_value) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Service `%s' took %llu ms to terminate\n"), pos->name, GNUNET_TIME_absolute_get_duration (pos->killed_at).rel_value); } GNUNET_OS_process_destroy (pos->proc); pos->proc = NULL; if (NULL != pos->killing_client) { signal_result (pos->killing_client, pos->name, GNUNET_ARM_PROCESS_DOWN); GNUNET_SERVER_client_drop (pos->killing_client); pos->killing_client = NULL; /* process can still be re-started on-demand, ensure it is re-started if there is demand */ for (sli = pos->listen_head; NULL != sli; sli = sli->next) { GNUNET_break (GNUNET_SCHEDULER_NO_TASK == sli->accept_task); sli->accept_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sli->listen_socket, &accept_connection, sli); } continue; } if (GNUNET_YES != in_shutdown) { if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0)) { /* process terminated normally, allow restart at any time */ pos->restart_at.abs_value = 0; } else { if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Service `%s' terminated with status %s/%d, will restart in %llu ms\n"), pos->name, statstr, statcode, pos->backoff.rel_value); /* schedule restart */ pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff); pos->backoff = GNUNET_TIME_relative_min (EXPONENTIAL_BACKOFF_THRESHOLD, GNUNET_TIME_relative_multiply (pos->backoff, 2)); } if (GNUNET_SCHEDULER_NO_TASK != child_restart_task) GNUNET_SCHEDULER_cancel (child_restart_task); child_restart_task = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, &delayed_restart_task, NULL); } else { free_service (pos); } } child_death_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, pr, &maint_child_death, NULL); if ((NULL == running_head) && (GNUNET_YES == in_shutdown)) do_shutdown (); } /** * Handler for SHUTDOWN message. * * @param cls closure (refers to service) * @param client identification of the client * @param message the actual message */ static void handle_shutdown (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { GNUNET_SCHEDULER_shutdown (); GNUNET_SERVER_client_persist_ (client); } /** * Signal handler called for SIGCHLD. Triggers the * respective handler by writing to the trigger pipe. */ static void sighandler_child_death () { static char c; int old_errno = errno; /* back-up errno */ GNUNET_break (1 == GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_WRITE), &c, sizeof (c))); errno = old_errno; /* restore errno */ } /** * Setup our service record for the given section in the configuration file * (assuming the section is for a service). * * @param cls unused * @param section a section in the configuration file * @return GNUNET_OK (continue) */ static void setup_service (void *cls, const char *section) { struct ServiceList *sl; char *binary; char *config; struct stat sbuf; struct sockaddr **addrs; socklen_t *addr_lens; int ret; unsigned int i; if (strcasecmp (section, "arm") == 0) return; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, section, "BINARY", &binary)) { /* not a service section */ return; } sl = find_service (section); if (NULL != sl) { /* got the same section twice!? */ GNUNET_break (0); return; } config = NULL; if ((GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, section, "CONFIG", &config)) || (0 != STAT (config, &sbuf))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Configuration file `%s' for service `%s' not valid: %s\n"), config, section, (config == NULL) ? _("option missing") : STRERROR (errno)); GNUNET_free (binary); GNUNET_free_non_null (config); return; } sl = GNUNET_malloc (sizeof (struct ServiceList)); sl->name = GNUNET_strdup (section); sl->binary = binary; sl->config = config; sl->backoff = GNUNET_TIME_UNIT_MILLISECONDS; sl->restart_at = GNUNET_TIME_UNIT_FOREVER_ABS; #if WINDOWS sl->pipe_control = GNUNET_YES; #else if (GNUNET_CONFIGURATION_have_value (cfg, section, "PIPECONTROL")) sl->pipe_control = GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "PIPECONTROL"); #endif GNUNET_CONTAINER_DLL_insert (running_head, running_tail, sl); if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_yesno (cfg, section, "AUTOSTART")) return; if (0 >= (ret = GNUNET_SERVICE_get_server_addresses (section, cfg, &addrs, &addr_lens))) return; /* this will free (or capture) addrs[i] */ for (i = 0; i < ret; i++) create_listen_socket (addrs[i], addr_lens[i], sl); GNUNET_free (addrs); GNUNET_free (addr_lens); } /** * Process arm requests. * * @param cls closure * @param serv the initialized server * @param c configuration to use */ static void run (void *cls, struct GNUNET_SERVER_Handle *serv, const struct GNUNET_CONFIGURATION_Handle *c) { static const struct GNUNET_SERVER_MessageHandler handlers[] = { {&handle_start, NULL, GNUNET_MESSAGE_TYPE_ARM_START, 0}, {&handle_stop, NULL, GNUNET_MESSAGE_TYPE_ARM_STOP, 0}, {&handle_shutdown, NULL, GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN, sizeof (struct GNUNET_MessageHeader)}, {&handle_list, NULL, GNUNET_MESSAGE_TYPE_ARM_LIST, sizeof (struct GNUNET_MessageHeader)}, {NULL, NULL, 0, 0} }; char *defaultservices; const char *pos; struct ServiceList *sl; cfg = c; server = serv; GNUNET_assert (serv != NULL); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); child_death_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ), &maint_child_death, NULL); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "GLOBAL_PREFIX", &prefix_command)) prefix_command = GNUNET_strdup (""); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "GLOBAL_POSTFIX", &final_option)) final_option = GNUNET_strdup (""); GNUNET_CONFIGURATION_iterate_sections (cfg, &setup_service, NULL); /* start default services... */ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, "ARM", "DEFAULTSERVICES", &defaultservices)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting default services `%s'\n"), defaultservices); if (0 < strlen (defaultservices)) { for (pos = strtok (defaultservices, " "); NULL != pos; pos = strtok (NULL, " ")) { sl = find_service (pos); if (NULL == sl) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Default service `%s' not configured correctly!\n"), pos); continue; } sl->is_default = GNUNET_YES; start_process (sl); } } GNUNET_free (defaultservices); } else { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("No default services configured, GNUnet will not really start right now.\n")); } /* process client requests */ GNUNET_SERVER_add_handlers (server, handlers); } /** * The main function for the arm service. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { int ret; struct GNUNET_SIGNAL_Context *shc_chld; sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO); GNUNET_assert (sigpipe != NULL); shc_chld = GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death); ret = (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "arm", GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN, &run, NULL)) ? 0 : 1; GNUNET_SIGNAL_handler_uninstall (shc_chld); shc_chld = NULL; GNUNET_DISK_pipe_close (sigpipe); sigpipe = NULL; return ret; } #ifdef LINUX #include /** * MINIMIZE heap size (way below 128k) since this process doesn't need much. */ void __attribute__ ((constructor)) GNUNET_ARM_memory_init () { mallopt (M_TRIM_THRESHOLD, 4 * 1024); mallopt (M_TOP_PAD, 1 * 1024); malloc_trim (0); } #endif /* end of gnunet-service-arm.c */ gnunet-0.9.3/src/arm/test_gnunet_service_manager.c0000644000175000017500000001107611760502551017236 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file arm/test_gnunet_service_manager.c (A mockup testcase, not functionally complete) * @brief testcase for gnunet-service-manager.c */ #include "platform.h" #include "gnunet_arm_service.h" #include "gnunet_resolver_service.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" /** * Timeout for starting services, very short because of the strange way start works * (by checking if running before starting, so really this time is always waited on * startup (annoying)). */ #define START_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 50) #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) #define START_ARM GNUNET_YES #define VERBOSE GNUNET_NO static int ret = 1; static const struct GNUNET_CONFIGURATION_Handle *cfg; #if START_ARM static struct GNUNET_ARM_Handle *arm; #endif static void arm_stopped (void *cls, enum GNUNET_ARM_ProcessStatus success) { if (success != GNUNET_ARM_PROCESS_DOWN) { GNUNET_break (0); ret = 4; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM stopped\n"); } #if START_ARM GNUNET_ARM_disconnect (arm); arm = NULL; #endif } static void hostNameResolveCB (void *cls, const struct sockaddr *addr, socklen_t addrlen) { if ((ret == 0) || (ret == 4)) return; if (NULL == addr) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Name not resolved!\n"); #if START_ARM GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); #endif ret = 3; return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Resolved hostname, now stopping ARM\n"); ret = 0; #if START_ARM GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); #endif } static void arm_notify (void *cls, enum GNUNET_ARM_ProcessStatus success) { if (success != GNUNET_ARM_PROCESS_STARTING) { GNUNET_break (0); ret = 1; return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to resolve our own hostname!\n"); /* connect to the resolver service */ if (NULL == GNUNET_RESOLVER_hostname_resolve (AF_UNSPEC, TIMEOUT, &hostNameResolveCB, NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable initiate connection to resolver service\n"); ret = 2; #if START_ARM GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); #endif } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { cfg = c; #if START_ARM arm = GNUNET_ARM_connect (cfg, NULL); GNUNET_ARM_start_service (arm, "arm", START_TIMEOUT, &arm_notify, NULL); #else arm_notify (NULL, GNUNET_YES); #endif } static void check () { char *const argv[] = { "test-gnunet-service-manager", "-c", "test_arm_api_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_assert (GNUNET_OK == GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-gnunet-service-manager", "nohelp", options, &run, NULL)); } int main (int argc, char *argv[]) { char hostname[GNUNET_OS_get_hostname_max_length () + 1]; if (0 != gethostname (hostname, sizeof (hostname) - 1)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "gethostname"); FPRINTF (stderr, "%s", "Failed to determine my own hostname, testcase not run.\n"); return 0; } if (NULL == gethostbyname (hostname)) { FPRINTF (stderr, "Failed to resolve my hostname `%s', testcase not run.\n", hostname); return 0; } GNUNET_log_setup ("test-gnunet-service-manager", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); check (); return ret; } gnunet-0.9.3/src/arm/arm_api.c0000644000175000017500000005401311760502551013073 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file arm/arm_api.c * @brief API for accessing the ARM service * @author Christian Grothoff */ #include "platform.h" #include "gnunet_arm_service.h" #include "gnunet_client_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_protocols.h" #include "gnunet_server_lib.h" #include "arm.h" #define LOG(kind,...) GNUNET_log_from (kind, "arm-api",__VA_ARGS__) /** * Handle for interacting with ARM. */ struct GNUNET_ARM_Handle { /** * Our connection to the ARM service. */ struct GNUNET_CLIENT_Connection *client; /** * The configuration that we are using. */ struct GNUNET_CONFIGURATION_Handle *cfg; }; /** * Context for handling the shutdown of a service. */ struct ShutdownContext { /** * Connection to the service that is being shutdown. */ struct GNUNET_CLIENT_Connection *sock; /** * Time allowed for shutdown to happen. */ struct GNUNET_TIME_Absolute timeout; /** * Task set up to cancel the shutdown request on timeout. */ GNUNET_SCHEDULER_TaskIdentifier cancel_task; /** * Task to call once shutdown complete */ GNUNET_CLIENT_ShutdownTask cont; /** * Closure for shutdown continuation */ void *cont_cls; /** * Handle for transmission request. */ struct GNUNET_CLIENT_TransmitHandle *th; }; /** * Handler receiving response to service shutdown requests. * First call with NULL: service misbehaving, or something. * First call with GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN_ACK: * - service will shutdown * Second call with NULL: * - service has now really shut down. * * @param cls closure * @param msg NULL, indicating socket closure. */ static void service_shutdown_handler (void *cls, const struct GNUNET_MessageHeader *msg) { struct ShutdownContext *shutdown_ctx = cls; if (NULL != msg) { /* We just expected a disconnect! Report the error and be done with it... */ GNUNET_break (0); shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR); GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task); GNUNET_CLIENT_disconnect (shutdown_ctx->sock); GNUNET_free (shutdown_ctx); return; } if (NULL != shutdown_ctx->cont) /* shutdown is now complete, as we waited for the network disconnect... */ shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_ARM_PROCESS_DOWN); GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task); GNUNET_CLIENT_disconnect (shutdown_ctx->sock); GNUNET_free (shutdown_ctx); } /** * Shutting down took too long, cancel receive and return error. * * @param cls closure * @param tc context information (why was this task triggered now) */ static void service_shutdown_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ShutdownContext *shutdown_ctx = cls; shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_ARM_PROCESS_COMMUNICATION_TIMEOUT); GNUNET_CLIENT_disconnect (shutdown_ctx->sock); GNUNET_free (shutdown_ctx); } /** * If possible, write a shutdown message to the target * buffer and destroy the client connection. * * @param cls the "struct GNUNET_CLIENT_Connection" to destroy * @param size number of bytes available in buf * @param buf NULL on error, otherwise target buffer * @return number of bytes written to buf */ static size_t write_shutdown (void *cls, size_t size, void *buf) { struct ShutdownContext *shutdown_ctx = cls; struct GNUNET_MessageHeader *msg; shutdown_ctx->th = NULL; if (size < sizeof (struct GNUNET_MessageHeader)) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Failed to transmit shutdown request to client.\n")); shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR); GNUNET_CLIENT_disconnect (shutdown_ctx->sock); GNUNET_free (shutdown_ctx); return 0; /* client disconnected */ } GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler, shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL); shutdown_ctx->cancel_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (shutdown_ctx->timeout), &service_shutdown_cancel, shutdown_ctx); msg = (struct GNUNET_MessageHeader *) buf; msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN); msg->size = htons (sizeof (struct GNUNET_MessageHeader)); return sizeof (struct GNUNET_MessageHeader); } /** * Request that the service should shutdown. * Afterwards, the connection will automatically be * disconnected. Hence the "sock" should not * be used by the caller after this call * (calling this function frees "sock" after a while). * * @param sock the socket connected to the service * @param timeout how long to wait before giving up on transmission * @param cont continuation to call once the service is really down * @param cont_cls closure for continuation * */ static void arm_service_shutdown (struct GNUNET_CLIENT_Connection *sock, struct GNUNET_TIME_Relative timeout, GNUNET_CLIENT_ShutdownTask cont, void *cont_cls) { struct ShutdownContext *shutdown_ctx; shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext)); shutdown_ctx->cont = cont; shutdown_ctx->cont_cls = cont_cls; shutdown_ctx->sock = sock; shutdown_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); shutdown_ctx->th = GNUNET_CLIENT_notify_transmit_ready (sock, sizeof (struct GNUNET_MessageHeader), timeout, GNUNET_NO, &write_shutdown, shutdown_ctx); } /** * Setup a context for communicating with ARM. Note that this * can be done even if the ARM service is not yet running. * * @param cfg configuration to use (needed to contact ARM; * the ARM service may internally use a different * configuration to determine how to start the service). * @param service service that *this* process is implementing/providing, can be NULL * @return context to use for further ARM operations, NULL on error */ struct GNUNET_ARM_Handle * GNUNET_ARM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *service) { struct GNUNET_ARM_Handle *ret; ret = GNUNET_malloc (sizeof (struct GNUNET_ARM_Handle)); ret->cfg = GNUNET_CONFIGURATION_dup (cfg); return ret; } /** * Disconnect from the ARM service. * * @param h the handle that was being used */ void GNUNET_ARM_disconnect (struct GNUNET_ARM_Handle *h) { if (h->client != NULL) GNUNET_CLIENT_disconnect (h->client); GNUNET_CONFIGURATION_destroy (h->cfg); GNUNET_free (h); } struct ARM_ShutdownContext { /** * Callback to call once shutdown complete. */ GNUNET_ARM_Callback cb; /** * Closure for callback. */ void *cb_cls; }; /** * Internal state for a request with ARM. */ struct RequestContext { /** * Pointer to our handle with ARM. */ struct GNUNET_ARM_Handle *h; /** * Function to call with a status code for the requested operation. */ GNUNET_ARM_Callback callback; /** * Closure for "callback". */ void *cls; /** * Timeout for the operation. */ struct GNUNET_TIME_Absolute timeout; /** * Type of the request expressed as a message type (start or stop). */ uint16_t type; }; #include "do_start_process.c" /** * A client specifically requested starting of ARM itself. * This function is called with information about whether * or not ARM is running; if it is, report success. If * it is not, start the ARM process. * * @param cls the context for the request that we will report on (struct RequestContext*) * @param tc why were we called (reason says if ARM is running) */ static void arm_service_report (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct RequestContext *pos = cls; struct GNUNET_OS_Process *proc; char *binary; char *config; char *loprefix; char *lopostfix; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Looks like `%s' is already running.\n", "gnunet-service-arm"); /* arm is running! */ if (pos->callback != NULL) pos->callback (pos->cls, GNUNET_ARM_PROCESS_ALREADY_RUNNING); GNUNET_free (pos); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Looks like `%s' is not running, will start it.\n", "gnunet-service-arm"); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (pos->h->cfg, "arm", "PREFIX", &loprefix)) loprefix = GNUNET_strdup (""); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (pos->h->cfg, "arm", "OPTIONS", &lopostfix)) lopostfix = GNUNET_strdup (""); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (pos->h->cfg, "arm", "BINARY", &binary)) { LOG (GNUNET_ERROR_TYPE_WARNING, _ ("Configuration failes to specify option `%s' in section `%s'!\n"), "BINARY", "arm"); if (pos->callback != NULL) pos->callback (pos->cls, GNUNET_ARM_PROCESS_UNKNOWN); GNUNET_free (pos); GNUNET_free (loprefix); GNUNET_free (lopostfix); return; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (pos->h->cfg, "arm", "CONFIG", &config)) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Configuration fails to specify option `%s' in section `%s'!\n"), "CONFIG", "arm"); if (pos->callback != NULL) pos->callback (pos->cls, GNUNET_ARM_PROCESS_UNKNOWN); GNUNET_free (binary); GNUNET_free (pos); GNUNET_free (loprefix); GNUNET_free (lopostfix); return; } if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (pos->h->cfg, "TESTING", "WEAKRANDOM")) && (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (pos->h->cfg, "TESTING", "WEAKRANDOM")) && (GNUNET_NO == GNUNET_CONFIGURATION_have_value (pos->h->cfg, "TESTING", "HOSTFILE"))) { /* Means we are ONLY running locally */ /* we're clearly running a test, don't daemonize */ proc = do_start_process (GNUNET_NO, NULL, loprefix, binary, "-c", config, /* no daemonization! */ lopostfix, NULL); } else { proc = do_start_process (GNUNET_NO, NULL, loprefix, binary, "-c", config, "-d", lopostfix, NULL); } GNUNET_free (binary); GNUNET_free (config); GNUNET_free (loprefix); GNUNET_free (lopostfix); if (proc == NULL) { if (pos->callback != NULL) pos->callback (pos->cls, GNUNET_ARM_PROCESS_FAILURE); GNUNET_free (pos); return; } if (pos->callback != NULL) pos->callback (pos->cls, GNUNET_ARM_PROCESS_STARTING); GNUNET_free (proc); GNUNET_free (pos); } /** * Process a response from ARM to a request for a change in service * status. * * @param cls the request context * @param msg the response */ static void handle_response (void *cls, const struct GNUNET_MessageHeader *msg) { struct RequestContext *sc = cls; const struct GNUNET_ARM_ResultMessage *res; enum GNUNET_ARM_ProcessStatus status; if ((msg == NULL) || (ntohs (msg->size) != sizeof (struct GNUNET_ARM_ResultMessage))) { LOG (GNUNET_ERROR_TYPE_WARNING, _ ("Error receiving response to `%s' request from ARM for service `%s'\n"), (sc->type == GNUNET_MESSAGE_TYPE_ARM_START) ? "START" : "STOP", (const char *) &sc[1]); GNUNET_CLIENT_disconnect (sc->h->client); sc->h->client = GNUNET_CLIENT_connect ("arm", sc->h->cfg); GNUNET_assert (NULL != sc->h->client); if (sc->callback != NULL) sc->callback (sc->cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR); GNUNET_free (sc); return; } res = (const struct GNUNET_ARM_ResultMessage *) msg; LOG (GNUNET_ERROR_TYPE_DEBUG, "Received response from ARM for service `%s': %u\n", (const char *) &sc[1], ntohs (msg->type)); status = (enum GNUNET_ARM_ProcessStatus) ntohl (res->status); if (sc->callback != NULL) sc->callback (sc->cls, status); GNUNET_free (sc); } /** * Start or stop a service. * * @param h handle to ARM * @param service_name name of the service * @param timeout how long to wait before failing for good * @param cb callback to invoke when service is ready * @param cb_cls closure for callback * @param type type of the request */ static void change_service (struct GNUNET_ARM_Handle *h, const char *service_name, struct GNUNET_TIME_Relative timeout, GNUNET_ARM_Callback cb, void *cb_cls, uint16_t type) { struct RequestContext *sctx; size_t slen; struct GNUNET_MessageHeader *msg; slen = strlen (service_name) + 1; if (slen + sizeof (struct GNUNET_MessageHeader) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); if (cb != NULL) cb (cb_cls, GNUNET_NO); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, (type == GNUNET_MESSAGE_TYPE_ARM_START) ? _("Requesting start of service `%s'.\n") : _("Requesting termination of service `%s'.\n"), service_name); sctx = GNUNET_malloc (sizeof (struct RequestContext) + slen); sctx->h = h; sctx->callback = cb; sctx->cls = cb_cls; sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); sctx->type = type; memcpy (&sctx[1], service_name, slen); msg = GNUNET_malloc (sizeof (struct GNUNET_MessageHeader) + slen); msg->size = htons (sizeof (struct GNUNET_MessageHeader) + slen); msg->type = htons (sctx->type); memcpy (&msg[1], service_name, slen); if (GNUNET_OK != GNUNET_CLIENT_transmit_and_get_response (sctx->h->client, msg, GNUNET_TIME_absolute_get_remaining (sctx->timeout), GNUNET_YES, &handle_response, sctx)) { LOG (GNUNET_ERROR_TYPE_WARNING, (type == GNUNET_MESSAGE_TYPE_ARM_START) ? _("Error while trying to transmit request to start `%s' to ARM\n") : _("Error while trying to transmit request to stop `%s' to ARM\n"), (const char *) &service_name); if (cb != NULL) cb (cb_cls, GNUNET_SYSERR); GNUNET_free (sctx); GNUNET_free (msg); return; } GNUNET_free (msg); } /** * Start a service. * * @param h handle to ARM * @param service_name name of the service * @param timeout how long to wait before failing for good * @param cb callback to invoke when service is ready * @param cb_cls closure for callback */ void GNUNET_ARM_start_service (struct GNUNET_ARM_Handle *h, const char *service_name, struct GNUNET_TIME_Relative timeout, GNUNET_ARM_Callback cb, void *cb_cls) { struct RequestContext *sctx; struct GNUNET_CLIENT_Connection *client; size_t slen; LOG (GNUNET_ERROR_TYPE_DEBUG, _("Asked to start service `%s' within %llu ms\n"), service_name, (unsigned long long) timeout.rel_value); if (0 == strcasecmp ("arm", service_name)) { slen = strlen ("arm") + 1; sctx = GNUNET_malloc (sizeof (struct RequestContext) + slen); sctx->h = h; sctx->callback = cb; sctx->cls = cb_cls; sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); memcpy (&sctx[1], service_name, slen); GNUNET_CLIENT_service_test ("arm", h->cfg, timeout, &arm_service_report, sctx); return; } if (h->client == NULL) { client = GNUNET_CLIENT_connect ("arm", h->cfg); if (client == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "arm_api, GNUNET_CLIENT_connect returned NULL\n"); cb (cb_cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "arm_api, GNUNET_CLIENT_connect returned non-NULL\n"); h->client = client; } LOG (GNUNET_ERROR_TYPE_DEBUG, "arm_api, h->client non-NULL\n"); change_service (h, service_name, timeout, cb, cb_cls, GNUNET_MESSAGE_TYPE_ARM_START); } /** * Callback from the arm stop service call, indicates that the arm service * is well and truly dead, won't die, or an error occurred. * * @param cls closure for the callback * @param reason reason for callback */ static void arm_shutdown_callback (void *cls, enum GNUNET_ARM_ProcessStatus reason) { struct ARM_ShutdownContext *arm_shutdown_ctx = cls; if (arm_shutdown_ctx->cb != NULL) arm_shutdown_ctx->cb (arm_shutdown_ctx->cb_cls, reason); GNUNET_free (arm_shutdown_ctx); } /** * Stop a service. * * @param h handle to ARM * @param service_name name of the service * @param timeout how long to wait before failing for good * @param cb callback to invoke when service is ready * @param cb_cls closure for callback */ void GNUNET_ARM_stop_service (struct GNUNET_ARM_Handle *h, const char *service_name, struct GNUNET_TIME_Relative timeout, GNUNET_ARM_Callback cb, void *cb_cls) { struct ARM_ShutdownContext *arm_shutdown_ctx; struct GNUNET_CLIENT_Connection *client; LOG (GNUNET_ERROR_TYPE_INFO, _("Stopping service `%s' within %llu ms\n"), service_name, (unsigned long long) timeout.rel_value); if (h->client == NULL) { client = GNUNET_CLIENT_connect ("arm", h->cfg); if (client == NULL) { cb (cb_cls, GNUNET_SYSERR); return; } h->client = client; } if (0 == strcasecmp ("arm", service_name)) { arm_shutdown_ctx = GNUNET_malloc (sizeof (struct ARM_ShutdownContext)); arm_shutdown_ctx->cb = cb; arm_shutdown_ctx->cb_cls = cb_cls; arm_service_shutdown (h->client, timeout, &arm_shutdown_callback, arm_shutdown_ctx); h->client = NULL; return; } change_service (h, service_name, timeout, cb, cb_cls, GNUNET_MESSAGE_TYPE_ARM_STOP); } /** * Internal state for a list request with ARM. */ struct ListRequestContext { /** * Pointer to our handle with ARM. */ struct GNUNET_ARM_Handle *h; /** * Function to call with a status code for the requested operation. */ GNUNET_ARM_List_Callback callback; /** * Closure for "callback". */ void *cls; /** * Timeout for the operation. */ struct GNUNET_TIME_Absolute timeout; }; /** * Process a response from ARM for the list request. * * @param cls the list request context * @param msg the response */ static void handle_list_response (void *cls, const struct GNUNET_MessageHeader *msg) { struct ListRequestContext *sc = cls; const struct GNUNET_ARM_ListResultMessage *res; const char *pos; uint16_t size_check; uint16_t rcount; uint16_t msize; if (NULL == msg) { LOG (GNUNET_ERROR_TYPE_WARNING, "Error receiving response to LIST request from ARM\n"); GNUNET_CLIENT_disconnect (sc->h->client); sc->h->client = GNUNET_CLIENT_connect ("arm", sc->h->cfg); GNUNET_assert (NULL != sc->h->client); if (sc->callback != NULL) sc->callback (sc->cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR, 0, NULL); GNUNET_free (sc); return; } if (NULL == sc->callback) { GNUNET_break (0); GNUNET_free (sc); return; } msize = ntohs (msg->size); if ( (msize < sizeof ( struct GNUNET_ARM_ListResultMessage)) || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT) ) { GNUNET_break (0); sc->callback (sc->cls, GNUNET_NO, 0, NULL); GNUNET_free (sc); return; } size_check = 0; res = (const struct GNUNET_ARM_ListResultMessage *) msg; rcount = ntohs (res->count); { const char *list[rcount]; unsigned int i; pos = (const char *)&res[1]; for (i=0; icallback (sc->cls, GNUNET_NO, 0, NULL); GNUNET_free (sc); return; } list[i] = pos; size_check += (end - pos) + 1; pos = end + 1; } sc->callback (sc->cls, GNUNET_YES, rcount, list); } GNUNET_free (sc); } /** * List all running services. * * @param h handle to ARM * @param timeout how long to wait before failing for good * @param cb callback to invoke when service is ready * @param cb_cls closure for callback */ void GNUNET_ARM_list_running_services (struct GNUNET_ARM_Handle *h, struct GNUNET_TIME_Relative timeout, GNUNET_ARM_List_Callback cb, void *cb_cls) { struct ListRequestContext *sctx; struct GNUNET_MessageHeader msg; struct GNUNET_CLIENT_Connection *client; if (h->client == NULL) { client = GNUNET_CLIENT_connect ("arm", h->cfg); if (client == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "arm_api, GNUNET_CLIENT_connect returned NULL\n"); cb (cb_cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR, 0, NULL); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "arm_api, GNUNET_CLIENT_connect returned non-NULL\n"); h->client = client; } sctx = GNUNET_malloc (sizeof (struct RequestContext)); sctx->h = h; sctx->callback = cb; sctx->cls = cb_cls; sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); msg.size = htons (sizeof (struct GNUNET_MessageHeader)); msg.type = htons (GNUNET_MESSAGE_TYPE_ARM_LIST); LOG (GNUNET_ERROR_TYPE_DEBUG, "Requesting LIST from ARM service with timeout: %llu ms\n", (unsigned long long)timeout.rel_value); if (GNUNET_OK != GNUNET_CLIENT_transmit_and_get_response (sctx->h->client, &msg, GNUNET_TIME_absolute_get_remaining (sctx->timeout), GNUNET_YES, &handle_list_response, sctx)) { LOG (GNUNET_ERROR_TYPE_WARNING, "Error while trying to transmit request to list services to ARM\n"); if (cb != NULL) cb (cb_cls, GNUNET_SYSERR, 0, NULL); GNUNET_free (sctx); return; } } /* end of arm_api.c */ gnunet-0.9.3/src/arm/Makefile.in0000644000175000017500000007666611762217210013403 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-arm$(EXEEXT) gnunet-service-arm$(EXEEXT) \ mockup-service$(EXEEXT) check_PROGRAMS = test_arm_api$(EXEEXT) \ test_exponential_backoff$(EXEEXT) \ test_gnunet_service_manager$(EXEEXT) subdir = src/arm DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/arm.conf.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = arm.conf CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libgnunetarm_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am_libgnunetarm_la_OBJECTS = arm_api.lo libgnunetarm_la_OBJECTS = $(am_libgnunetarm_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunetarm_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetarm_la_LDFLAGS) $(LDFLAGS) \ -o $@ PROGRAMS = $(bin_PROGRAMS) am_gnunet_arm_OBJECTS = gnunet-arm.$(OBJEXT) gnunet_arm_OBJECTS = $(am_gnunet_arm_OBJECTS) am_gnunet_service_arm_OBJECTS = gnunet-service-arm.$(OBJEXT) gnunet_service_arm_OBJECTS = $(am_gnunet_service_arm_OBJECTS) am_mockup_service_OBJECTS = mockup-service.$(OBJEXT) mockup_service_OBJECTS = $(am_mockup_service_OBJECTS) mockup_service_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_arm_api_OBJECTS = test_arm_api.$(OBJEXT) test_arm_api_OBJECTS = $(am_test_arm_api_OBJECTS) test_arm_api_DEPENDENCIES = $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_exponential_backoff_OBJECTS = \ test_exponential_backoff.$(OBJEXT) test_exponential_backoff_OBJECTS = \ $(am_test_exponential_backoff_OBJECTS) test_exponential_backoff_DEPENDENCIES = \ $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_gnunet_service_manager_OBJECTS = \ test_gnunet_service_manager.$(OBJEXT) test_gnunet_service_manager_OBJECTS = \ $(am_test_gnunet_service_manager_OBJECTS) test_gnunet_service_manager_DEPENDENCIES = \ $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunetarm_la_SOURCES) $(gnunet_arm_SOURCES) \ $(gnunet_service_arm_SOURCES) $(mockup_service_SOURCES) \ $(test_arm_api_SOURCES) $(test_exponential_backoff_SOURCES) \ $(test_gnunet_service_manager_SOURCES) DIST_SOURCES = $(libgnunetarm_la_SOURCES) $(gnunet_arm_SOURCES) \ $(gnunet_service_arm_SOURCES) $(mockup_service_SOURCES) \ $(test_arm_api_SOURCES) $(test_exponential_backoff_SOURCES) \ $(test_gnunet_service_manager_SOURCES) DATA = $(pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include pkgcfgdir = $(pkgdatadir)/config.d/ pkgcfg_DATA = \ arm.conf @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @USE_COVERAGE_TRUE@XLIB = -lgcov lib_LTLIBRARIES = libgnunetarm.la libgnunetarm_la_SOURCES = \ arm_api.c arm.h libgnunetarm_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) $(XLIB) libgnunetarm_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 1:1:0 gnunet_arm_SOURCES = \ gnunet-arm.c gnunet_arm_LDADD = \ $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_arm_DEPENDENCIES = \ libgnunetarm.la gnunet_service_arm_SOURCES = \ gnunet-service-arm.c gnunet_service_arm_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_service_arm_DEPENDENCIES = \ libgnunetarm.la mockup_service_SOURCES = \ mockup-service.c mockup_service_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la check_SCRIPTS = \ test_gnunet_arm.sh @ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) $(check_SCRIPTS) test_arm_api_SOURCES = \ test_arm_api.c test_arm_api_LDADD = \ $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la test_exponential_backoff_SOURCES = \ test_exponential_backoff.c test_exponential_backoff_LDADD = \ $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la test_gnunet_service_manager_SOURCES = \ test_gnunet_service_manager.c test_gnunet_service_manager_LDADD = \ $(top_builddir)/src/arm/libgnunetarm.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ test_arm_api_data.conf \ do_start_process.c \ $(check_SCRIPTS) all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/arm/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/arm/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): arm.conf: $(top_builddir)/config.status $(srcdir)/arm.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunetarm.la: $(libgnunetarm_la_OBJECTS) $(libgnunetarm_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetarm_la_LINK) -rpath $(libdir) $(libgnunetarm_la_OBJECTS) $(libgnunetarm_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-arm$(EXEEXT): $(gnunet_arm_OBJECTS) $(gnunet_arm_DEPENDENCIES) @rm -f gnunet-arm$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_arm_OBJECTS) $(gnunet_arm_LDADD) $(LIBS) gnunet-service-arm$(EXEEXT): $(gnunet_service_arm_OBJECTS) $(gnunet_service_arm_DEPENDENCIES) @rm -f gnunet-service-arm$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_service_arm_OBJECTS) $(gnunet_service_arm_LDADD) $(LIBS) mockup-service$(EXEEXT): $(mockup_service_OBJECTS) $(mockup_service_DEPENDENCIES) @rm -f mockup-service$(EXEEXT) $(AM_V_CCLD)$(LINK) $(mockup_service_OBJECTS) $(mockup_service_LDADD) $(LIBS) test_arm_api$(EXEEXT): $(test_arm_api_OBJECTS) $(test_arm_api_DEPENDENCIES) @rm -f test_arm_api$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_arm_api_OBJECTS) $(test_arm_api_LDADD) $(LIBS) test_exponential_backoff$(EXEEXT): $(test_exponential_backoff_OBJECTS) $(test_exponential_backoff_DEPENDENCIES) @rm -f test_exponential_backoff$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_exponential_backoff_OBJECTS) $(test_exponential_backoff_LDADD) $(LIBS) test_gnunet_service_manager$(EXEEXT): $(test_gnunet_service_manager_OBJECTS) $(test_gnunet_service_manager_DEPENDENCIES) @rm -f test_gnunet_service_manager$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gnunet_service_manager_OBJECTS) $(test_gnunet_service_manager_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-arm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-arm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mockup-service.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_arm_api.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_exponential_backoff.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gnunet_service_manager.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgcfgDATA: $(pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(check_SCRIPTS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgcfgDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-binPROGRAMS install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-pkgcfgDATA install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/arm/do_start_process.c0000644000175000017500000000501111760502551015032 00000000000000/** * Actually start a process. All of the arguments given to this * function are strings that are used for the "argv" array. However, * if those strings contain spaces, the given argument is split into * multiple argv entries without spaces. Similarly, if an argument is * the empty string, it is skipped. This function has the inherent * limitation that it does NOT allow passing command line arguments * with spaces to the new process. * * @param pipe_control should a pipe be used to send signals to the child? * @param lsocks array of listen sockets to dup starting at fd3 (systemd-style), or NULL * @param first_arg first argument for argv (may be an empty string) * @param ... more arguments, NULL terminated * @return handle of the started process, NULL on error */ static struct GNUNET_OS_Process * do_start_process (int pipe_control, const SOCKTYPE * lsocks, const char *first_arg, ...) { va_list ap; char **argv; unsigned int argv_size; const char *arg; const char *rpos; char *pos; char *cp; const char *last; struct GNUNET_OS_Process *proc; argv_size = 1; va_start (ap, first_arg); arg = first_arg; last = NULL; /* *INDENT-OFF* */ do { /* *INDENT-ON* */ rpos = arg; while ('\0' != *rpos) { if (' ' == *rpos) { if (last != NULL) argv_size++; last = NULL; while (' ' == *rpos) rpos++; } if ((last == NULL) && (*rpos != '\0')) last = rpos; if (*rpos != '\0') rpos++; } if (last != NULL) argv_size++; /* *INDENT-OFF* */ } while (NULL != (arg = (va_arg (ap, const char*)))); /* *INDENT-ON* */ va_end (ap); argv = GNUNET_malloc (argv_size * sizeof (char *)); argv_size = 0; va_start (ap, first_arg); arg = first_arg; last = NULL; /* *INDENT-OFF* */ do { /* *INDENT-ON* */ cp = GNUNET_strdup (arg); pos = cp; while ('\0' != *pos) { if (' ' == *pos) { *pos = '\0'; if (last != NULL) argv[argv_size++] = GNUNET_strdup (last); last = NULL; pos++; while (' ' == *pos) pos++; } if ((last == NULL) && (*pos != '\0')) last = pos; if (*pos != '\0') pos++; } if (last != NULL) argv[argv_size++] = GNUNET_strdup (last); last = NULL; GNUNET_free (cp); /* *INDENT-OFF* */ } while (NULL != (arg = (va_arg (ap, const char*)))); /* *INDENT-ON* */ va_end (ap); argv[argv_size] = NULL; proc = GNUNET_OS_start_process_v (pipe_control, lsocks, argv[0], argv); while (argv_size > 0) GNUNET_free (argv[--argv_size]); GNUNET_free (argv); return proc; } gnunet-0.9.3/src/ats/0000755000175000017500000000000011763406750011413 500000000000000gnunet-0.9.3/src/ats/test_ats_api.conf0000644000175000017500000000167211744051776014672 00000000000000[PATHS] SERVICEHOME = /tmp/test-ats-api-scheduling/ [arm] PORT = 12001 DEFAULTSERVICES = ats UNIXPATH = /tmp/test-ats-scheduling-arm.sock [ats] #DEBUG = YES #PREFIX = valgrind --leak-check=full AUTOSTART = YES PORT = 12002 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-ats ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/test-ats-scheduling-ats.sock UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES # Enable MLP mode (default: NO) MLP = NO # Network specific inbound/outbound quotas # LOOPBACK LOOPBACK_QUOTA_IN = unlimited LOOPBACK_QUOTA_OUT = unlimited # LAN LAN_QUOTA_IN = unlimited LAN_QUOTA_OUT = unlimited # WAN WAN_QUOTA_IN = 64 KiB WAN_QUOTA_OUT = 64 KiB # WLAN WLAN_QUOTA_IN = 1 MiB WLAN_QUOTA_OUT = 1 MiB # ATS extended options DUMP_MLP = NO DUMP_SOLUTION = NO DUMP_OVERWRITE = NO DUMP_MIN_PEERS = 0 DUMP_MIN_ADDRS = 0 DUMP_OVERWRITE = NO ATS_MIN_INTERVAL = 15000 ATS_EXEC_INTERVAL = 30000 gnunet-0.9.3/src/ats/gnunet-service-ats_reservations.c0000644000175000017500000001135111760502551020020 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file ats/gnunet-service-ats_reservations.c * @brief ats service, inbound bandwidth reservation management * @author Christian Grothoff */ #include "platform.h" #include "gnunet-service-ats_reservations.h" /** * Number of seconds that available bandwidth carries over * (can accumulate). */ #define MAX_BANDWIDTH_CARRY_S 5 /** * Map of peer identities to 'struct GNUNET_BANDWIDTH_Tracker *'s */ static struct GNUNET_CONTAINER_MultiHashMap *trackers; /** * Reserve the given amount of incoming bandwidth (in bytes) from the * given peer. If a reservation is not possible right now, return how * long the client should wait before trying again. * * @param peer peer to reserve bandwidth from * @param amount number of bytes to reserve * @return 0 if the reservation was successful, FOREVER if the * peer is not connected, otherwise the time to wait * until the reservation might succeed */ struct GNUNET_TIME_Relative GAS_reservations_reserve (const struct GNUNET_PeerIdentity *peer, int32_t amount) { struct GNUNET_BANDWIDTH_Tracker *tracker; struct GNUNET_TIME_Relative ret; tracker = GNUNET_CONTAINER_multihashmap_get (trackers, &peer->hashPubKey); if (NULL == tracker) return GNUNET_TIME_UNIT_ZERO; /* not connected, satisfy now */ if (amount >= 0) { ret = GNUNET_BANDWIDTH_tracker_get_delay (tracker, amount); if (ret.rel_value > 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Delay to satisfy reservation for %d bytes is %llu ms\n", (int) amount, (unsigned long long) ret.rel_value); return ret; } } (void) GNUNET_BANDWIDTH_tracker_consume (tracker, amount); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Reserved %d bytes\n", (int) amount); return GNUNET_TIME_UNIT_ZERO; } /** * Set the amount of bandwidth the other peer could currently transmit * to us (as far as we know) to the given value. * * @param peer identity of the peer * @param bandwidth_in currently available bandwidth from that peer to * this peer (estimate) */ void GAS_reservations_set_bandwidth (const struct GNUNET_PeerIdentity *peer, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in) { struct GNUNET_BANDWIDTH_Tracker *tracker; tracker = GNUNET_CONTAINER_multihashmap_get (trackers, &peer->hashPubKey); if (0 == ntohl (bandwidth_in.value__)) { if (NULL == tracker) return; GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (trackers, &peer->hashPubKey, tracker)); GNUNET_free (tracker); return; } if (NULL == tracker) { tracker = GNUNET_malloc (sizeof (struct GNUNET_BANDWIDTH_Tracker)); GNUNET_BANDWIDTH_tracker_init (tracker, bandwidth_in, MAX_BANDWIDTH_CARRY_S); GNUNET_CONTAINER_multihashmap_put (trackers, &peer->hashPubKey, tracker, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); return; } GNUNET_BANDWIDTH_tracker_update_quota (tracker, bandwidth_in); } /** * Initialize reservations subsystem. */ void GAS_reservations_init () { trackers = GNUNET_CONTAINER_multihashmap_create (128); } /** * Free memory of bandwidth tracker. * * @param cls NULL * @param key peer identity (unused) * @param value the 'struct GNUNET_BANDWIDTH_Tracker' to free * @return GNUNET_OK (continue to iterate) */ static int free_tracker (void *cls, const GNUNET_HashCode * key, void *value) { struct GNUNET_BANDWIDTH_Tracker *tracker = value; GNUNET_free (tracker); return GNUNET_OK; } /** * Shutdown reservations subsystem. */ void GAS_reservations_done () { GNUNET_CONTAINER_multihashmap_iterate (trackers, &free_tracker, NULL); GNUNET_CONTAINER_multihashmap_destroy (trackers); } /* end of gnunet-service-ats_reservations.c */ gnunet-0.9.3/src/ats/gnunet-service-ats_performance.h0000644000175000017500000000733211760502551017606 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file ats/gnunet-service-ats_performance.h * @brief ats service, interaction with 'performance' API * @author Matthias Wachs * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_ATS_PERFORMANCE_H #define GNUNET_SERVICE_ATS_PERFORMANCE_H #include "gnunet_util_lib.h" #include "gnunet_ats_service.h" #include "ats.h" /** * Register a new performance client. * * @param client handle of the new client * @param flag flag specifying the type of the client */ void GAS_performance_add_client (struct GNUNET_SERVER_Client *client, enum StartFlag flag); /** * Unregister a client (which may have been a performance client, * but this is not assured). * * @param client handle of the (now dead) client */ void GAS_performance_remove_client (struct GNUNET_SERVER_Client *client); /** * Transmit the given performance information to all performance * clients. * * @param peer peer for which this is an address suggestion * @param plugin_name 0-termintated string specifying the transport plugin * @param plugin_addr binary address for the plugin to use * @param plugin_addr_len number of bytes in plugin_addr * @param atsi performance data for the address * @param atsi_count number of performance records in 'ats' * @param bandwidth_out assigned outbound bandwidth * @param bandwidth_in assigned inbound bandwidth */ void GAS_performance_notify_clients (const struct GNUNET_PeerIdentity *peer, const char *plugin_name, const void *plugin_addr, size_t plugin_addr_len, const struct GNUNET_ATS_Information *atsi, uint32_t atsi_count, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in); /** * Handle 'reservation request' messages from clients. * * @param cls unused, NULL * @param client client that sent the request * @param message the request message */ void GAS_handle_reservation_request (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message); /** * Handle 'preference change' messages from clients. * * @param cls unused, NULL * @param client client that sent the request * @param message the request message */ void GAS_handle_preference_change (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message); /** * Initialize performance subsystem. * * @param server handle to our server */ void GAS_performance_init (struct GNUNET_SERVER_Handle *server); /** * Shutdown performance subsystem. */ void GAS_performance_done (void); /* FIXME: add API to broadcast performance updates! */ #endif /* end of gnunet-service-ats_performance.h */ gnunet-0.9.3/src/ats/Makefile.am0000644000175000017500000000634611762221660013372 00000000000000INCLUDES = -I$(top_srcdir)/src/include pkgcfgdir= $(pkgdatadir)/config.d/ pkgcfg_DATA = \ ats.conf if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = -fprofile-arcs -ftest-coverage endif if HAVE_LIBGLPK GN_LIBGLPK = -lglpk GN_MLP_SRC = gnunet-service-ats_addresses_mlp.c gnunet-service-ats_addresses_mlp.h GN_MLP_TEST = test_ats_mlp GN_MLP_TEST_AVG = test_ats_mlp_averaging GN_MLP_PERF = perf_ats_mlp endif lib_LTLIBRARIES = libgnunetats.la libgnunetats_la_SOURCES = \ ats_api_scheduling.c \ ats_api_performance.c libgnunetats_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la libgnunetats_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 2:0:2 bin_PROGRAMS = \ gnunet-service-ats gnunet_service_ats_SOURCES = \ gnunet-service-ats.c gnunet-service-ats.h\ gnunet-service-ats_addresses.c gnunet-service-ats_addresses.h \ $(GN_MLP_SRC) \ gnunet-service-ats_performance.c gnunet-service-ats_performance.h \ gnunet-service-ats_scheduling.c gnunet-service-ats_scheduling.h \ gnunet-service-ats_reservations.c gnunet-service-ats_reservations.h gnunet_service_ats_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBGLPK) \ $(GN_LIBINTL) check_PROGRAMS = \ test_ats_api_scheduling \ test_ats_api_reset_backoff \ $(GN_MLP_TEST) \ $(GN_MLP_TEST_AVG) \ $(GN_MLP_PERF) # test_ats_api_scheduling_get_type # test_ats_api_bandwidth_consumption if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) endif if HAVE_LIBGLPK test_ats_mlp_SOURCES = \ $(GN_MLP_SRC) \ test_ats_mlp.c test_ats_mlp_LDADD = \ $(GN_LIBGLPK) \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la test_ats_mlp_averaging_SOURCES = \ $(GN_MLP_SRC) \ test_ats_mlp_averaging.c test_ats_mlp_averaging_LDADD = \ $(GN_LIBGLPK) \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la perf_ats_mlp_SOURCES = \ $(GN_MLP_SRC) \ perf_ats_mlp.c perf_ats_mlp_LDADD = \ $(GN_LIBGLPK) \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la endif test_ats_api_scheduling_SOURCES = \ test_ats_api_scheduling.c test_ats_api_scheduling_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/ats/libgnunetats.la test_ats_api_reset_backoff_SOURCES = \ test_ats_api_reset_backoff.c test_ats_api_reset_backoff_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/ats/libgnunetats.la #test_ats_api_scheduling_get_type_SOURCES = \ # test_ats_api_scheduling_get_type.c #test_ats_api_scheduling_get_type_LDADD = \ # $(top_builddir)/src/util/libgnunetutil.la \ # $(top_builddir)/src/ats/libgnunetats.la #test_ats_api_bandwidth_consumption_SOURCES = \ # test_ats_api_bandwidth_consumption.c #test_ats_api_bandwidth_consumption_LDADD = \ # $(top_builddir)/src/util/libgnunetutil.la \ # $(top_builddir)/src/ats/libgnunetats.la #test_ats_api_update_address_SOURCES = \ # test_ats_api_update_address.c #test_ats_api_update_address_LDADD = \ # $(top_builddir)/src/util/libgnunetutil.la \ # $(top_builddir)/src/ats/libgnunetats.la EXTRA_DIST = \ ats.h \ test_ats_api.conf gnunet-0.9.3/src/ats/gnunet-service-ats_addresses_mlp.c0000644000175000017500000014213311760515512020125 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file ats/gnunet-service-ats_addresses_mlp.c * @brief ats mlp problem solver * @author Matthias Wachs * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet-service-ats_addresses.h" #include "gnunet-service-ats_addresses_mlp.h" #include "gnunet_statistics_service.h" #include "glpk.h" #define WRITE_MLP GNUNET_NO #define DEBUG_ATS GNUNET_NO #define VERBOSE_GLPK GNUNET_NO #define ENABLE_C8 GNUNET_YES #define ENABLE_C9 GNUNET_YES /** * Translate glpk solver error codes to text * @param retcode return code * @return string with result */ const char * mlp_solve_to_string (int retcode) { switch (retcode) { case 0: return "ok"; break; case GLP_EBADB: return "invalid basis"; break; case GLP_ESING: return "singular matrix"; break; case GLP_ECOND: return "ill-conditioned matrix"; break; case GLP_EBOUND: return "invalid bounds"; break; case GLP_EFAIL: return "solver failed"; break; case GLP_EOBJLL: return "objective lower limit reached"; break; case GLP_EOBJUL: return "objective upper limit reached"; break; case GLP_EITLIM: return "iteration limit exceeded"; break; case GLP_ETMLIM: return "time limit exceeded"; break; case GLP_ENOPFS: return "no primal feasible solution"; break; case GLP_EROOT: return "root LP optimum not provided"; break; case GLP_ESTOP: return "search terminated by application"; break; case GLP_EMIPGAP: return "relative mip gap tolerance reached"; break; case GLP_ENOFEAS: return "no dual feasible solution"; break; case GLP_ENOCVG: return "no convergence"; break; case GLP_EINSTAB: return "numerical instability"; break; case GLP_EDATA: return "invalid data"; break; case GLP_ERANGE: return "result out of range"; break; default: GNUNET_break (0); return "unknown error"; break; } GNUNET_break (0); return "unknown error"; } /** * Translate glpk status error codes to text * @param retcode return code * @return string with result */ const char * mlp_status_to_string (int retcode) { switch (retcode) { case GLP_UNDEF: return "solution is undefined"; break; case GLP_FEAS: return "solution is feasible"; break; case GLP_INFEAS: return "solution is infeasible"; break; case GLP_NOFEAS: return "no feasible solution exists"; break; case GLP_OPT: return "solution is optimal"; break; case GLP_UNBND: return "solution is unbounded"; break; default: GNUNET_break (0); return "unknown error"; break; } GNUNET_break (0); return "unknown error"; } /** * Translate ATS properties to text * Just intended for debugging * * @param ats_index the ATS index * @return string with result */ const char * mlp_ats_to_string (int ats_index) { switch (ats_index) { case GNUNET_ATS_ARRAY_TERMINATOR: return "GNUNET_ATS_ARRAY_TERMINATOR"; break; case GNUNET_ATS_UTILIZATION_UP: return "GNUNET_ATS_UTILIZATION_UP"; break; case GNUNET_ATS_UTILIZATION_DOWN: return "GNUNET_ATS_UTILIZATION_DOWN"; break; case GNUNET_ATS_COST_LAN: return "GNUNET_ATS_COST_LAN"; break; case GNUNET_ATS_COST_WAN: return "GNUNET_ATS_COST_LAN"; break; case GNUNET_ATS_COST_WLAN: return "GNUNET_ATS_COST_WLAN"; break; case GNUNET_ATS_NETWORK_TYPE: return "GNUNET_ATS_NETWORK_TYPE"; break; case GNUNET_ATS_QUALITY_NET_DELAY: return "GNUNET_ATS_QUALITY_NET_DELAY"; break; case GNUNET_ATS_QUALITY_NET_DISTANCE: return "GNUNET_ATS_QUALITY_NET_DISTANCE"; break; default: return "unknown"; break; } GNUNET_break (0); return "unknown error"; } /** * Find a peer in the DLL * * @param mlp the mlp handle * @param peer the peer to find * @return the peer struct */ static struct ATS_Peer * mlp_find_peer (struct GAS_MLP_Handle *mlp, const struct GNUNET_PeerIdentity *peer) { struct ATS_Peer *res = mlp->peer_head; while (res != NULL) { if (0 == memcmp (peer, &res->id, sizeof (struct GNUNET_PeerIdentity))) break; res = res->next; } return res; } /** * Intercept GLPK terminal output * @param info the mlp handle * @param s the string to print * @return 0: glpk prints output on terminal, 0 != surpress output */ static int mlp_term_hook (void *info, const char *s) { /* Not needed atm struct MLP_information *mlp = info; */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s", s); return 1; } /** * Delete the MLP problem and free the constrain matrix * * @param mlp the MLP handle */ static void mlp_delete_problem (struct GAS_MLP_Handle *mlp) { if (mlp != NULL) { if (mlp->prob != NULL) glp_delete_prob(mlp->prob); /* delete row index */ if (mlp->ia != NULL) { GNUNET_free (mlp->ia); mlp->ia = NULL; } /* delete column index */ if (mlp->ja != NULL) { GNUNET_free (mlp->ja); mlp->ja = NULL; } /* delete coefficients */ if (mlp->ar != NULL) { GNUNET_free (mlp->ar); mlp->ar = NULL; } mlp->ci = 0; mlp->prob = NULL; } } /** * Add constraints that are iterating over "forall addresses" * and collects all existing peers for "forall peers" constraints * * @param cls GAS_MLP_Handle * @param key Hashcode * @param value ATS_Address * * @return GNUNET_OK to continue */ static int create_constraint_it (void *cls, const GNUNET_HashCode * key, void *value) { struct GAS_MLP_Handle *mlp = cls; struct ATS_Address *address = value; struct MLP_information *mlpi; unsigned int row_index; char *name; GNUNET_assert (address->mlp_information != NULL); mlpi = (struct MLP_information *) address->mlp_information; /* c 1) bandwidth capping * b_t + (-M) * n_t <= 0 */ row_index = glp_add_rows (mlp->prob, 1); mlpi->r_c1 = row_index; /* set row name */ GNUNET_asprintf(&name, "c1_%s_%s", GNUNET_i2s(&address->peer), address->plugin); glp_set_row_name (mlp->prob, row_index, name); GNUNET_free (name); /* set row bounds: <= 0 */ glp_set_row_bnds (mlp->prob, row_index, GLP_UP, 0.0, 0.0); mlp->ia[mlp->ci] = row_index; mlp->ja[mlp->ci] = mlpi->c_b; mlp->ar[mlp->ci] = 1; mlp->ci++; mlp->ia[mlp->ci] = row_index; mlp->ja[mlp->ci] = mlpi->c_n; mlp->ar[mlp->ci] = -mlp->BIG_M; mlp->ci++; /* c 3) minimum bandwidth * b_t + (-n_t * b_min) >= 0 */ row_index = glp_add_rows (mlp->prob, 1); /* set row name */ GNUNET_asprintf(&name, "c3_%s_%s", GNUNET_i2s(&address->peer), address->plugin); glp_set_row_name (mlp->prob, row_index, name); GNUNET_free (name); mlpi->r_c3 = row_index; /* set row bounds: >= 0 */ glp_set_row_bnds (mlp->prob, row_index, GLP_LO, 0.0, 0.0); mlp->ia[mlp->ci] = row_index; mlp->ja[mlp->ci] = mlpi->c_b; mlp->ar[mlp->ci] = 1; mlp->ci++; mlp->ia[mlp->ci] = row_index; mlp->ja[mlp->ci] = mlpi->c_n; mlp->ar[mlp->ci] = - (double) mlp->b_min; mlp->ci++; /* c 4) minimum connections * (1)*n_1 + ... + (1)*n_m >= n_min */ mlp->ia[mlp->ci] = mlp->r_c4; mlp->ja[mlp->ci] = mlpi->c_n; mlp->ar[mlp->ci] = 1; mlp->ci++; /* c 6) maximize diversity * (1)*n_1 + ... + (1)*n_m - d == 0 */ mlp->ia[mlp->ci] = mlp->r_c6; mlp->ja[mlp->ci] = mlpi->c_n; mlp->ar[mlp->ci] = 1; mlp->ci++; /* c 10) obey network specific quotas * (1)*b_1 + ... + (1)*b_m <= quota_n */ int cur_row = 0; int c; for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++) { if (mlp->quota_index[c] == address->atsp_network_type) { cur_row = mlp->r_quota[c]; break; } } if (cur_row != 0) { mlp->ia[mlp->ci] = cur_row; mlp->ja[mlp->ci] = mlpi->c_b; mlp->ar[mlp->ci] = 1; mlp->ci++; } else { GNUNET_break (0); } return GNUNET_OK; } /** * Find the required ATS information for an address * * @param addr the address * @param ats_index the desired ATS index * * @return the index on success, otherwise GNUNET_SYSERR */ static int mlp_lookup_ats (struct ATS_Address *addr, int ats_index) { struct GNUNET_ATS_Information * ats = addr->ats; int c = 0; int found = GNUNET_NO; for (c = 0; c < addr->ats_count; c++) { if (ats[c].type == ats_index) { found = GNUNET_YES; break; } } if (found == GNUNET_YES) return c; else return GNUNET_SYSERR; } /** * Adds the problem constraints for all addresses * Required for problem recreation after address deletion * * @param mlp the mlp handle * @param addresses all addresses */ static void mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses) { unsigned int n_addresses; int c; char *name; /* Problem matrix*/ n_addresses = GNUNET_CONTAINER_multihashmap_size(addresses); /* Required indices in the constrain matrix * * feasibility constraints: * * c 1) bandwidth capping * #rows: |n_addresses| * #indices: 2 * |n_addresses| * * c 2) one active address per peer * #rows: |peers| * #indices: |n_addresses| * * c 3) minium bandwidth assigned * #rows: |n_addresses| * #indices: 2 * |n_addresses| * * c 4) minimum number of active connections * #rows: 1 * #indices: |n_addresses| * * c 5) maximum ressource consumption * #rows: |ressources| * #indices: |n_addresses| * * c 10) obey network specific quota * #rows: |network types * #indices: |n_addresses| * * Sum for feasibility constraints: * #rows: 3 * |n_addresses| + |ressources| + |peers| + 1 * #indices: 7 * |n_addresses| * * optimality constraints: * * c 6) diversity * #rows: 1 * #indices: |n_addresses| + 1 * * c 7) quality * #rows: |quality properties| * #indices: |n_addresses| + |quality properties| * * c 8) utilization * #rows: 1 * #indices: |n_addresses| + 1 * * c 9) relativity * #rows: |peers| * #indices: |n_addresses| + |peers| * */ /* last +1 caused by glpk index starting with one: [1..pi]*/ int pi = ((7 * n_addresses) + (5 * n_addresses + mlp->m_q + mlp->c_p + 2) + 1); mlp->cm_size = pi; mlp->ci = 1; /* row index */ int *ia = GNUNET_malloc (pi * sizeof (int)); mlp->ia = ia; /* column index */ int *ja = GNUNET_malloc (pi * sizeof (int)); mlp->ja = ja; /* coefficient */ double *ar= GNUNET_malloc (pi * sizeof (double)); mlp->ar = ar; /* Adding constraint rows * This constraints are kind of "for all addresses" * Feasibility constraints: * * c 1) bandwidth capping * c 3) minimum bandwidth * c 4) minimum number of connections * c 6) maximize diversity * c 10) obey network specific quota */ /* Row for c4) minimum connection */ int min = mlp->n_min; /* Number of minimum connections is min(|Peers|, n_min) */ if (mlp->n_min > mlp->c_p) min = mlp->c_p; mlp->r_c4 = glp_add_rows (mlp->prob, 1); glp_set_row_name (mlp->prob, mlp->r_c4, "c4"); glp_set_row_bnds (mlp->prob, mlp->r_c4, GLP_LO, min, min); /* Add row for c6) */ mlp->r_c6 = glp_add_rows (mlp->prob, 1); /* Set type type to fix */ glp_set_row_bnds (mlp->prob, mlp->r_c6, GLP_FX, 0.0, 0.0); /* Setting -D */ ia[mlp->ci] = mlp->r_c6 ; ja[mlp->ci] = mlp->c_d; ar[mlp->ci] = -1; mlp->ci++; /* Add rows for c 10) */ for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++) { mlp->r_quota[c] = glp_add_rows (mlp->prob, 1); char * text; GNUNET_asprintf(&text, "quota_ats_%i", mlp->quota_index[c]); glp_set_row_name (mlp->prob, mlp->r_quota[c], text); GNUNET_free (text); /* Set bounds to 0 <= x <= quota_out */ glp_set_row_bnds (mlp->prob, mlp->r_quota[c], GLP_UP, 0.0, mlp->quota_out[c]); } GNUNET_CONTAINER_multihashmap_iterate (addresses, create_constraint_it, mlp); /* Adding constraint rows * This constraints are kind of "for all peers" * Feasibility constraints: * * c 2) 1 address per peer * sum (n_p1_1 + ... + n_p1_n) = 1 * * c 8) utilization * sum (f_p * b_p1_1 + ... + f_p * b_p1_n) - u = 0 * * c 9) relativity * V p : sum (bt_1 + ... +bt_n) - f_p * r = 0 * */ /* Adding rows for c 8) */ mlp->r_c8 = glp_add_rows (mlp->prob, mlp->c_p); glp_set_row_name (mlp->prob, mlp->r_c8, "c8"); /* Set row bound == 0 */ glp_set_row_bnds (mlp->prob, mlp->r_c8, GLP_FX, 0.0, 0.0); /* -u */ ia[mlp->ci] = mlp->r_c8; ja[mlp->ci] = mlp->c_u; ar[mlp->ci] = -1; mlp->ci++; struct ATS_Peer * peer = mlp->peer_head; /* For all peers */ while (peer != NULL) { struct ATS_Address *addr = peer->head; struct MLP_information *mlpi = NULL; /* Adding rows for c 2) */ peer->r_c2 = glp_add_rows (mlp->prob, 1); GNUNET_asprintf(&name, "c2_%s", GNUNET_i2s(&peer->id)); glp_set_row_name (mlp->prob, peer->r_c2, name); GNUNET_free (name); /* Set row bound == 1 */ glp_set_row_bnds (mlp->prob, peer->r_c2, GLP_FX, 1.0, 1.0); /* Adding rows for c 9) */ #if ENABLE_C9 peer->r_c9 = glp_add_rows (mlp->prob, 1); GNUNET_asprintf(&name, "c9_%s", GNUNET_i2s(&peer->id)); glp_set_row_name (mlp->prob, peer->r_c9, name); GNUNET_free (name); /* Set row bound == 0 */ glp_set_row_bnds (mlp->prob, peer->r_c9, GLP_LO, 0.0, 0.0); /* Set -r */ ia[mlp->ci] = peer->r_c9; ja[mlp->ci] = mlp->c_r; ar[mlp->ci] = -peer->f; mlp->ci++; #endif /* For all addresses of this peer */ while (addr != NULL) { mlpi = (struct MLP_information *) addr->mlp_information; /* coefficient for c 2) */ ia[mlp->ci] = peer->r_c2; ja[mlp->ci] = mlpi->c_n; ar[mlp->ci] = 1; mlp->ci++; /* coefficient for c 8) */ ia[mlp->ci] = mlp->r_c8; ja[mlp->ci] = mlpi->c_b; ar[mlp->ci] = peer->f; mlp->ci++; #if ENABLE_C9 /* coefficient for c 9) */ ia[mlp->ci] = peer->r_c9; ja[mlp->ci] = mlpi->c_b; ar[mlp->ci] = 1; mlp->ci++; #endif addr = addr->next; } peer = peer->next; } /* c 7) For all quality metrics */ for (c = 0; c < mlp->m_q; c++) { struct ATS_Peer *tp; struct ATS_Address *ta; struct MLP_information * mlpi; double value = 1.0; /* Adding rows for c 7) */ mlp->r_q[c] = glp_add_rows (mlp->prob, 1); GNUNET_asprintf(&name, "c7_q%i_%s", c, mlp_ats_to_string(mlp->q[c])); glp_set_row_name (mlp->prob, mlp->r_q[c], name); GNUNET_free (name); /* Set row bound == 0 */ glp_set_row_bnds (mlp->prob, mlp->r_q[c], GLP_FX, 0.0, 0.0); ia[mlp->ci] = mlp->r_q[c]; ja[mlp->ci] = mlp->c_q[c]; ar[mlp->ci] = -1; mlp->ci++; for (tp = mlp->peer_head; tp != NULL; tp = tp->next) for (ta = tp->head; ta != NULL; ta = ta->next) { mlpi = ta->mlp_information; value = mlpi->q_averaged[c]; mlpi->r_q[c] = mlp->r_q[c]; ia[mlp->ci] = mlp->r_q[c]; ja[mlp->ci] = mlpi->c_b; ar[mlp->ci] = tp->f_q[c] * value; mlp->ci++; } } } /** * Add columns for all addresses * * @param cls GAS_MLP_Handle * @param key Hashcode * @param value ATS_Address * * @return GNUNET_OK to continue */ static int create_columns_it (void *cls, const GNUNET_HashCode * key, void *value) { struct GAS_MLP_Handle *mlp = cls; struct ATS_Address *address = value; struct MLP_information *mlpi; unsigned int col; char *name; GNUNET_assert (address->mlp_information != NULL); mlpi = address->mlp_information; /* Add bandwidth column */ col = glp_add_cols (mlp->prob, 2); mlpi->c_b = col; mlpi->c_n = col + 1; GNUNET_asprintf (&name, "b_%s_%s", GNUNET_i2s (&address->peer), address->plugin); glp_set_col_name (mlp->prob, mlpi->c_b , name); GNUNET_free (name); /* Lower bound == 0 */ glp_set_col_bnds (mlp->prob, mlpi->c_b , GLP_LO, 0.0, 0.0); /* Continuous value*/ glp_set_col_kind (mlp->prob, mlpi->c_b , GLP_CV); /* Objective function coefficient == 0 */ glp_set_obj_coef (mlp->prob, mlpi->c_b , 0); /* Add usage column */ GNUNET_asprintf (&name, "n_%s_%s", GNUNET_i2s (&address->peer), address->plugin); glp_set_col_name (mlp->prob, mlpi->c_n, name); GNUNET_free (name); /* Limit value : 0 <= value <= 1 */ glp_set_col_bnds (mlp->prob, mlpi->c_n, GLP_DB, 0.0, 1.0); /* Integer value*/ glp_set_col_kind (mlp->prob, mlpi->c_n, GLP_IV); /* Objective function coefficient == 0 */ glp_set_obj_coef (mlp->prob, mlpi->c_n, 0); return GNUNET_OK; } /** * Create the MLP problem * * @param mlp the MLP handle * @param addresses the hashmap containing all adresses * @return GNUNET_OK or GNUNET_SYSERR */ static int mlp_create_problem (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses) { int res = GNUNET_OK; int col; int c; char *name; GNUNET_assert (mlp->prob == NULL); /* create the glpk problem */ mlp->prob = glp_create_prob (); /* Set a problem name */ glp_set_prob_name (mlp->prob, "gnunet ats bandwidth distribution"); /* Set optimization direction to maximize */ glp_set_obj_dir (mlp->prob, GLP_MAX); /* Adding invariant columns */ /* Diversity d column */ col = glp_add_cols (mlp->prob, 1); mlp->c_d = col; /* Column name */ glp_set_col_name (mlp->prob, col, "d"); /* Column objective function coefficient */ glp_set_obj_coef (mlp->prob, col, mlp->co_D); /* Column lower bound = 0.0 */ glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0); /* Utilization u column */ col = glp_add_cols (mlp->prob, 1); mlp->c_u = col; /* Column name */ glp_set_col_name (mlp->prob, col, "u"); /* Column objective function coefficient */ glp_set_obj_coef (mlp->prob, col, mlp->co_U); /* Column lower bound = 0.0 */ glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0); #if ENABLE_C9 /* Relativity r column */ col = glp_add_cols (mlp->prob, 1); mlp->c_r = col; /* Column name */ glp_set_col_name (mlp->prob, col, "r"); /* Column objective function coefficient */ glp_set_obj_coef (mlp->prob, col, mlp->co_R); /* Column lower bound = 0.0 */ glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0); #endif /* Quality metric columns */ col = glp_add_cols(mlp->prob, mlp->m_q); for (c = 0; c < mlp->m_q; c++) { mlp->c_q[c] = col + c; GNUNET_asprintf (&name, "q_%u", mlp->q[c]); glp_set_col_name (mlp->prob, col + c, name); /* Column lower bound = 0.0 */ glp_set_col_bnds (mlp->prob, col + c, GLP_LO, 0.0, 0.0); GNUNET_free (name); /* Coefficient == Qm */ glp_set_obj_coef (mlp->prob, col + c, mlp->co_Q[c]); } /* Add columns for addresses */ GNUNET_CONTAINER_multihashmap_iterate (addresses, create_columns_it, mlp); /* Add constraints */ mlp_add_constraints_all_addresses (mlp, addresses); /* Load the matrix */ glp_load_matrix(mlp->prob, (mlp->ci-1), mlp->ia, mlp->ja, mlp->ar); return res; } /** * Solves the LP problem * * @param mlp the MLP Handle * @param s_ctx context to return results * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure */ static int mlp_solve_lp_problem (struct GAS_MLP_Handle *mlp, struct GAS_MLP_SolutionContext *s_ctx) { int res; struct GNUNET_TIME_Relative duration; struct GNUNET_TIME_Absolute end; struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get(); /* LP presolver? * Presolver is required if the problem was modified and an existing * valid basis is now invalid */ if (mlp->presolver_required == GNUNET_YES) mlp->control_param_lp.presolve = GLP_ON; else mlp->control_param_lp.presolve = GLP_OFF; /* Solve LP problem to have initial valid solution */ lp_solv: res = glp_simplex(mlp->prob, &mlp->control_param_lp); if (res == 0) { /* The LP problem instance has been successfully solved. */ } else if (res == GLP_EITLIM) { /* simplex iteration limit has been exceeded. */ // TODO Increase iteration limit? } else if (res == GLP_ETMLIM) { /* Time limit has been exceeded. */ // TODO Increase time limit? } else { /* Problem was ill-defined, retry with presolver */ if (mlp->presolver_required == GNUNET_NO) { mlp->presolver_required = GNUNET_YES; goto lp_solv; } else { /* Problem was ill-defined, no way to handle that */ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-mlp", "Solving LP problem failed: %i %s\n", res, mlp_solve_to_string(res)); return GNUNET_SYSERR; } } end = GNUNET_TIME_absolute_get (); duration = GNUNET_TIME_absolute_get_difference (start, end); mlp->lp_solved++; mlp->lp_total_duration =+ duration.rel_value; s_ctx->lp_duration = duration; GNUNET_STATISTICS_update (mlp->stats,"# LP problem solved", 1, GNUNET_NO); GNUNET_STATISTICS_set (mlp->stats,"# LP execution time (ms)", duration.rel_value, GNUNET_NO); GNUNET_STATISTICS_set (mlp->stats,"# LP execution time average (ms)", mlp->lp_total_duration / mlp->lp_solved, GNUNET_NO); /* Analyze problem status */ res = glp_get_status (mlp->prob); switch (res) { /* solution is optimal */ case GLP_OPT: /* solution is feasible */ case GLP_FEAS: break; /* Problem was ill-defined, no way to handle that */ default: GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-mlp", "Solving LP problem failed, no solution: %s\n", mlp_status_to_string(res)); return GNUNET_SYSERR; break; } /* solved sucessfully, no presolver required next time */ mlp->presolver_required = GNUNET_NO; return GNUNET_OK; } /** * Solves the MLP problem * * @param mlp the MLP Handle * @param s_ctx context to return results * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure */ int mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp, struct GAS_MLP_SolutionContext *s_ctx) { int res; struct GNUNET_TIME_Relative duration; struct GNUNET_TIME_Absolute end; struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get(); /* solve MLP problem */ res = glp_intopt(mlp->prob, &mlp->control_param_mlp); if (res == 0) { /* The MLP problem instance has been successfully solved. */ } else if (res == GLP_EITLIM) { /* simplex iteration limit has been exceeded. */ // TODO Increase iteration limit? } else if (res == GLP_ETMLIM) { /* Time limit has been exceeded. */ // TODO Increase time limit? } else { /* Problem was ill-defined, no way to handle that */ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-mlp", "Solving MLP problem failed: %s\n", mlp_solve_to_string(res)); return GNUNET_SYSERR; } end = GNUNET_TIME_absolute_get (); duration = GNUNET_TIME_absolute_get_difference (start, end); mlp->mlp_solved++; mlp->mlp_total_duration =+ duration.rel_value; s_ctx->mlp_duration = duration; GNUNET_STATISTICS_update (mlp->stats,"# MLP problem solved", 1, GNUNET_NO); GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time (ms)", duration.rel_value, GNUNET_NO); GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time average (ms)", mlp->mlp_total_duration / mlp->mlp_solved, GNUNET_NO); /* Analyze problem status */ res = glp_mip_status(mlp->prob); switch (res) { /* solution is optimal */ case GLP_OPT: /* solution is feasible */ case GLP_FEAS: break; /* Problem was ill-defined, no way to handle that */ default: GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-mlp", "Solving MLP problem failed, %s\n\n", mlp_status_to_string(res)); return GNUNET_SYSERR; break; } return GNUNET_OK; } int GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp, struct GAS_MLP_SolutionContext *ctx); static void mlp_scheduler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GAS_MLP_Handle *mlp = cls; struct GAS_MLP_SolutionContext ctx; mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scheduled problem solving\n"); if (mlp->addr_in_problem != 0) GAS_mlp_solve_problem(mlp, &ctx); } /** * Solves the MLP problem * * @param mlp the MLP Handle * @param ctx solution context * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure */ int GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp, struct GAS_MLP_SolutionContext *ctx) { int res; /* Check if solving is already running */ if (GNUNET_YES == mlp->semaphore) { if (mlp->mlp_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel(mlp->mlp_task); mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK; } mlp->mlp_task = GNUNET_SCHEDULER_add_delayed (mlp->exec_interval, &mlp_scheduler, mlp); return GNUNET_SYSERR; } mlp->semaphore = GNUNET_YES; mlp->last_execution = GNUNET_TIME_absolute_get (); ctx->lp_result = GNUNET_SYSERR; ctx->mlp_result = GNUNET_SYSERR; ctx->lp_duration = GNUNET_TIME_UNIT_FOREVER_REL; ctx->mlp_duration = GNUNET_TIME_UNIT_FOREVER_REL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Solve LP problem\n"); #if WRITE_MLP char * name; static int i; i++; GNUNET_asprintf(&name, "problem_%i", i); glp_write_lp (mlp->prob, 0, name); GNUNET_free (name); # endif res = mlp_solve_lp_problem (mlp, ctx); ctx->lp_result = res; if (res != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "LP Problem solving failed\n"); mlp->semaphore = GNUNET_NO; return GNUNET_SYSERR; } #if WRITE_MLP GNUNET_asprintf(&name, "problem_%i_lp_solution", i); glp_print_sol (mlp->prob, name); GNUNET_free (name); # endif GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Solve MLP problem\n"); res = mlp_solve_mlp_problem (mlp, ctx); ctx->mlp_result = res; if (res != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP Problem solving failed\n"); mlp->semaphore = GNUNET_NO; return GNUNET_SYSERR; } #if WRITE_MLP GNUNET_asprintf(&name, "problem_%i_mlp_solution", i); glp_print_mip (mlp->prob, name); GNUNET_free (name); # endif GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem solved %s (LP duration %llu / MLP duration %llu)\n", (GNUNET_OK == res) ? "successfully" : "failed", ctx->lp_duration.rel_value, ctx->mlp_duration.rel_value); /* Process result */ struct ATS_Peer *p = NULL; struct ATS_Address *a = NULL; struct MLP_information *mlpi = NULL; for (p = mlp->peer_head; p != NULL; p = p->next) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s'\n", GNUNET_i2s (&p->id)); for (a = p->head; a != NULL; a = a->next) { double b = 0.0; double n = 0.0; mlpi = a->mlp_information; b = glp_mip_col_val(mlp->prob, mlpi->c_b); mlpi->b = b; n = glp_mip_col_val(mlp->prob, mlpi->c_n); if (n == 1.0) mlpi->n = GNUNET_YES; else mlpi->n = GNUNET_NO; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\tAddress %s %f\n", (n == 1.0) ? "[x]" : "[ ]", b); } } if (mlp->mlp_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel(mlp->mlp_task); mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK; } mlp->mlp_task = GNUNET_SCHEDULER_add_delayed (mlp->exec_interval, &mlp_scheduler, mlp); mlp->semaphore = GNUNET_NO; return res; } /** * Init the MLP problem solving component * * @param cfg the GNUNET_CONFIGURATION_Handle handle * @param stats the GNUNET_STATISTICS handle * @param max_duration maximum numbers of iterations for the LP/MLP Solver * @param max_iterations maximum time limit for the LP/MLP Solver * @return struct GAS_MLP_Handle * on success, NULL on fail */ struct GAS_MLP_Handle * GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg, const struct GNUNET_STATISTICS_Handle *stats, struct GNUNET_TIME_Relative max_duration, unsigned int max_iterations) { struct GAS_MLP_Handle * mlp = GNUNET_malloc (sizeof (struct GAS_MLP_Handle)); double D; double R; double U; unsigned long long tmp; unsigned int b_min; unsigned int n_min; struct GNUNET_TIME_Relative i_exec; int c; char * quota_out_str; char * quota_in_str; /* Init GLPK environment */ int res = glp_init_env(); switch (res) { case 0: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n", "initialization successful"); break; case 1: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n", "environment is already initialized"); break; case 2: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n", "initialization failed (insufficient memory)"); GNUNET_free(mlp); return NULL; break; case 3: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n", "initialization failed (unsupported programming model)"); GNUNET_free(mlp); return NULL; break; default: break; } /* Create initial MLP problem */ mlp->prob = glp_create_prob(); GNUNET_assert (mlp->prob != NULL); mlp->BIG_M = (double) BIG_M_VALUE; /* Get diversity coefficient from configuration */ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", "COEFFICIENT_D", &tmp)) D = (double) tmp / 100; else D = 1.0; /* Get proportionality coefficient from configuration */ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", "COEFFICIENT_R", &tmp)) R = (double) tmp / 100; else R = 1.0; /* Get utilization coefficient from configuration */ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", "COEFFICIENT_U", &tmp)) U = (double) tmp / 100; else U = 1.0; /* Get quality metric coefficients from configuration */ int i_delay = -1; int i_distance = -1; int q[GNUNET_ATS_QualityPropertiesCount] = GNUNET_ATS_QualityProperties; for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++) { /* initialize quality coefficients with default value 1.0 */ mlp->co_Q[c] = 1.0; mlp->q[c] = q[c]; if (q[c] == GNUNET_ATS_QUALITY_NET_DELAY) i_delay = c; if (q[c] == GNUNET_ATS_QUALITY_NET_DISTANCE) i_distance = c; } if ((i_delay != -1) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", "COEFFICIENT_QUALITY_DELAY", &tmp))) mlp->co_Q[i_delay] = (double) tmp / 100; else mlp->co_Q[i_delay] = 1.0; if ((i_distance != -1) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", "COEFFICIENT_QUALITY_DISTANCE", &tmp))) mlp->co_Q[i_distance] = (double) tmp / 100; else mlp->co_Q[i_distance] = 1.0; /* Get minimum bandwidth per used address from configuration */ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", "MIN_BANDWIDTH", &tmp)) b_min = tmp; else { b_min = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__); } /* Get minimum number of connections from configuration */ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats", "MIN_CONNECTIONS", &tmp)) n_min = tmp; else n_min = 4; /* Init network quotas */ int quotas[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType; for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++) { mlp->quota_index[c] = quotas[c]; static char * entry_in = NULL; static char * entry_out = NULL; unsigned long long quota_in = 0; unsigned long long quota_out = 0; switch (quotas[c]) { case GNUNET_ATS_NET_UNSPECIFIED: entry_out = "UNSPECIFIED_QUOTA_OUT"; entry_in = "UNSPECIFIED_QUOTA_IN"; break; case GNUNET_ATS_NET_LOOPBACK: entry_out = "LOOPBACK_QUOTA_OUT"; entry_in = "LOOPBACK_QUOTA_IN"; break; case GNUNET_ATS_NET_LAN: entry_out = "LAN_QUOTA_OUT"; entry_in = "LAN_QUOTA_IN"; break; case GNUNET_ATS_NET_WAN: entry_out = "WAN_QUOTA_OUT"; entry_in = "WAN_QUOTA_IN"; break; case GNUNET_ATS_NET_WLAN: entry_out = "WLAN_QUOTA_OUT"; entry_in = "WLAN_QUOTA_IN"; break; default: break; } if ((entry_in == NULL) || (entry_out == NULL)) continue; if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", entry_out, "a_out_str)) { if (0 == strcmp(quota_out_str, BIG_M_STRING) || (GNUNET_SYSERR == GNUNET_STRINGS_fancy_size_to_bytes (quota_out_str, "a_out))) quota_out = mlp->BIG_M; GNUNET_free (quota_out_str); quota_out_str = NULL; } else if (GNUNET_ATS_NET_UNSPECIFIED == quotas[c]) { quota_out = mlp->BIG_M; } else { quota_out = mlp->BIG_M; } if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", entry_in, "a_in_str)) { if (0 == strcmp(quota_in_str, BIG_M_STRING) || (GNUNET_SYSERR == GNUNET_STRINGS_fancy_size_to_bytes (quota_in_str, "a_in))) quota_in = mlp->BIG_M; GNUNET_free (quota_in_str); quota_in_str = NULL; } else if (GNUNET_ATS_NET_UNSPECIFIED == quotas[c]) { quota_in = mlp->BIG_M; } else { quota_in = mlp->BIG_M; } /* Check if defined quota could make problem unsolvable */ if (((n_min * b_min) > quota_out) && (GNUNET_ATS_NET_UNSPECIFIED != quotas[c])) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Inconsistent quota configuration value `%s': " "outbound quota (%u Bps) too small for combination of minimum connections and minimum bandwidth per peer (%u * %u Bps = %u)\n", entry_out, quota_out, n_min, b_min, n_min * b_min); GAS_mlp_done(mlp); mlp = NULL; return NULL; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found `%s' quota %llu and `%s' quota %llu\n", entry_out, quota_out, entry_in, quota_in); GNUNET_STATISTICS_update ((struct GNUNET_STATISTICS_Handle *) stats, entry_out, quota_out, GNUNET_NO); GNUNET_STATISTICS_update ((struct GNUNET_STATISTICS_Handle *) stats, entry_in, quota_in, GNUNET_NO); mlp->quota_out[c] = quota_out; mlp->quota_in[c] = quota_in; } /* Get minimum number of connections from configuration */ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_time (cfg, "ats", "ATS_EXEC_INTERVAL", &i_exec)) mlp->exec_interval = i_exec; else mlp->exec_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30); mlp->stats = (struct GNUNET_STATISTICS_Handle *) stats; mlp->max_iterations = max_iterations; mlp->max_exec_duration = max_duration; mlp->auto_solve = GNUNET_YES; /* Redirect GLPK output to GNUnet logging */ glp_error_hook((void *) mlp, &mlp_term_hook); /* Init LP solving parameters */ glp_init_smcp(&mlp->control_param_lp); mlp->control_param_lp.msg_lev = GLP_MSG_OFF; #if VERBOSE_GLPK mlp->control_param_lp.msg_lev = GLP_MSG_ALL; #endif mlp->control_param_lp.it_lim = max_iterations; mlp->control_param_lp.tm_lim = max_duration.rel_value; /* Init MLP solving parameters */ glp_init_iocp(&mlp->control_param_mlp); mlp->control_param_mlp.msg_lev = GLP_MSG_OFF; #if VERBOSE_GLPK mlp->control_param_mlp.msg_lev = GLP_MSG_ALL; #endif mlp->control_param_mlp.tm_lim = max_duration.rel_value; mlp->last_execution = GNUNET_TIME_UNIT_FOREVER_ABS; mlp->co_D = D; mlp->co_R = R; mlp->co_U = U; mlp->b_min = b_min; mlp->n_min = n_min; mlp->m_q = GNUNET_ATS_QualityPropertiesCount; mlp->semaphore = GNUNET_NO; return mlp; } static void update_quality (struct GAS_MLP_Handle *mlp, struct ATS_Address * address) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating quality metrics for peer `%s'\n", GNUNET_i2s (&address->peer)); GNUNET_assert (NULL != address); GNUNET_assert (NULL != address->mlp_information); GNUNET_assert (NULL != address->ats); struct MLP_information *mlpi = address->mlp_information; struct GNUNET_ATS_Information *ats = address->ats; GNUNET_assert (mlpi != NULL); int c; for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++) { int index = mlp_lookup_ats(address, mlp->q[c]); if (index == GNUNET_SYSERR) continue; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating address for peer `%s' value `%s': %f\n", GNUNET_i2s (&address->peer), mlp_ats_to_string(mlp->q[c]), (double) ats[index].value); int i = mlpi->q_avg_i[c]; double * qp = mlpi->q[c]; qp[i] = (double) ats[index].value; int t; for (t = 0; t < MLP_AVERAGING_QUEUE_LENGTH; t++) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s': `%s' queue[%u]: %f\n", GNUNET_i2s (&address->peer), mlp_ats_to_string(mlp->q[c]), t, qp[t]); } if (mlpi->q_avg_i[c] + 1 < (MLP_AVERAGING_QUEUE_LENGTH)) mlpi->q_avg_i[c] ++; else mlpi->q_avg_i[c] = 0; int c2; int c3; double avg = 0.0; switch (mlp->q[c]) { case GNUNET_ATS_QUALITY_NET_DELAY: c3 = 0; for (c2 = 0; c2 < MLP_AVERAGING_QUEUE_LENGTH; c2++) { if (mlpi->q[c][c2] != -1) { double * t2 = mlpi->q[c] ; avg += t2[c2]; c3 ++; } } if ((c3 > 0) && (avg > 0)) /* avg = 1 / ((q[0] + ... + q[l]) /c3) => c3 / avg*/ mlpi->q_averaged[c] = (double) c3 / avg; else mlpi->q_averaged[c] = 0.0; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s': `%s' average sum: %f, average: %f, weight: %f\n", GNUNET_i2s (&address->peer), mlp_ats_to_string(mlp->q[c]), avg, avg / (double) c3, mlpi->q_averaged[c]); break; case GNUNET_ATS_QUALITY_NET_DISTANCE: c3 = 0; for (c2 = 0; c2 < MLP_AVERAGING_QUEUE_LENGTH; c2++) { if (mlpi->q[c][c2] != -1) { double * t2 = mlpi->q[c] ; avg += t2[c2]; c3 ++; } } if ((c3 > 0) && (avg > 0)) /* avg = 1 / ((q[0] + ... + q[l]) /c3) => c3 / avg*/ mlpi->q_averaged[c] = (double) c3 / avg; else mlpi->q_averaged[c] = 0.0; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s': `%s' average sum: %f, average: %f, weight: %f\n", GNUNET_i2s (&address->peer), mlp_ats_to_string(mlp->q[c]), avg, avg / (double) c3, mlpi->q_averaged[c]); break; default: break; } if ((mlpi->c_b != 0) && (mlpi->r_q[c] != 0)) { /* Get current number of columns */ int found = GNUNET_NO; int cols = glp_get_num_cols(mlp->prob); int *ind = GNUNET_malloc (cols * sizeof (int) + 1); double *val = GNUNET_malloc (cols * sizeof (double) + 1); /* Get the matrix row of quality */ int length = glp_get_mat_row(mlp->prob, mlp->r_q[c], ind, val); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "cols %i, length %i c_b %i\n", cols, length, mlpi->c_b); int c4; /* Get the index if matrix row of quality */ for (c4 = 1; c4 <= length; c4++ ) { if (mlpi->c_b == ind[c4]) { /* Update the value */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating quality `%s' column `%s' row `%s' : %f -> %f\n", mlp_ats_to_string(mlp->q[c]), glp_get_col_name (mlp->prob, ind[c4]), glp_get_row_name (mlp->prob, mlp->r_q[c]), val[c4], mlpi->q_averaged[c]); val[c4] = mlpi->q_averaged[c]; found = GNUNET_YES; break; } } if (found == GNUNET_NO) { ind[length+1] = mlpi->c_b; val[length+1] = mlpi->q_averaged[c]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%i ind[%i] val[%i]: %i %f\n", length+1, length+1, length+1, mlpi->c_b, mlpi->q_averaged[c]); glp_set_mat_row (mlp->prob, mlpi->r_q[c], length+1, ind, val); } else { /* Get the index if matrix row of quality */ glp_set_mat_row (mlp->prob, mlpi->r_q[c], length, ind, val); } GNUNET_free (ind); GNUNET_free (val); } } } /** * Updates a single address in the MLP problem * * If the address did not exist before in the problem: * The MLP problem has to be recreated and the problem has to be resolved * * Otherwise the addresses' values can be updated and the existing base can * be reused * * @param mlp the MLP Handle * @param addresses the address hashmap * the address has to be already removed from the hashmap * @param address the address to update */ void GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address) { int new; struct MLP_information *mlpi; struct GAS_MLP_SolutionContext ctx; GNUNET_STATISTICS_update (mlp->stats, "# MLP address updates", 1, GNUNET_NO); /* We add a new address */ if (address->mlp_information == NULL) new = GNUNET_YES; else new = GNUNET_NO; /* Do the update */ if (new == GNUNET_YES) { mlpi = GNUNET_malloc (sizeof (struct MLP_information)); int c; for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++) { int c2; mlpi->r_q[c] = 0; for (c2 = 0; c2 < MLP_AVERAGING_QUEUE_LENGTH; c2++) mlpi->q[c][c2] = -1.0; /* -1.0: invalid value */ mlpi->q_avg_i[c] = 0; mlpi->q_averaged[c] = 0.0; } address->mlp_information = mlpi; mlp->addr_in_problem ++; GNUNET_STATISTICS_update (mlp->stats, "# addresses in MLP", 1, GNUNET_NO); /* Check for and add peer */ struct ATS_Peer *peer = mlp_find_peer (mlp, &address->peer); if (peer == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding new peer `%s'\n", GNUNET_i2s (&address->peer)); peer = GNUNET_malloc (sizeof (struct ATS_Peer)); peer->head = NULL; peer->tail = NULL; int c; for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++) { peer->f_q[c] = 1.0; } peer->f = 1.0; memcpy (&peer->id, &address->peer, sizeof (struct GNUNET_PeerIdentity)); GNUNET_assert(address->prev == NULL); GNUNET_assert(address->next == NULL); GNUNET_CONTAINER_DLL_insert (peer->head, peer->tail, address); GNUNET_CONTAINER_DLL_insert (mlp->peer_head, mlp->peer_tail, peer); mlp->c_p ++; GNUNET_STATISTICS_update (mlp->stats, "# peers in MLP", 1, GNUNET_NO); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding address to peer `%s'\n", GNUNET_i2s (&address->peer)); GNUNET_CONTAINER_DLL_insert (peer->head, peer->tail, address); } update_quality (mlp, address); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating existing address to peer `%s'\n", GNUNET_i2s (&address->peer)); update_quality (mlp, address); } /* Recalculate */ if (new == GNUNET_YES) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Recreating problem: new address\n"); mlp_delete_problem (mlp); mlp_create_problem (mlp, addresses); mlp->presolver_required = GNUNET_YES; } if (mlp->auto_solve == GNUNET_YES) GAS_mlp_solve_problem (mlp, &ctx); } /** * Deletes a single address in the MLP problem * * The MLP problem has to be recreated and the problem has to be resolved * * @param mlp the MLP Handle * @param addresses the address hashmap * the address has to be already removed from the hashmap * @param address the address to delete */ void GAS_mlp_address_delete (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address) { GNUNET_STATISTICS_update (mlp->stats,"# LP address deletions", 1, GNUNET_NO); struct GAS_MLP_SolutionContext ctx; /* Free resources */ if (address->mlp_information != NULL) { GNUNET_free (address->mlp_information); address->mlp_information = NULL; mlp->addr_in_problem --; GNUNET_STATISTICS_update (mlp->stats, "# addresses in MLP", -1, GNUNET_NO); } /* Remove from peer list */ struct ATS_Peer *head = mlp_find_peer (mlp, &address->peer); GNUNET_assert (head != NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting address for `%s'\n", GNUNET_i2s (&address->peer)); GNUNET_CONTAINER_DLL_remove (head->head, head->tail, address); if ((head->head == NULL) && (head->tail == NULL)) { /* No address for peer left, remove peer */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting peer `%s'\n", GNUNET_i2s (&address->peer)); GNUNET_CONTAINER_DLL_remove (mlp->peer_head, mlp->peer_tail, head); GNUNET_free (head); mlp->c_p --; GNUNET_STATISTICS_update (mlp->stats, "# peers in MLP", -1, GNUNET_NO); } /* Update problem */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Recreating problem: new address\n"); mlp_delete_problem (mlp); if ((GNUNET_CONTAINER_multihashmap_size (addresses) > 0) && (mlp->c_p > 0)) { mlp_create_problem (mlp, addresses); /* Recalculate */ mlp->presolver_required = GNUNET_YES; if (mlp->auto_solve == GNUNET_YES) GAS_mlp_solve_problem (mlp, &ctx); } } static int mlp_get_preferred_address_it (void *cls, const GNUNET_HashCode * key, void *value) { struct ATS_PreferedAddress *aa = (struct ATS_PreferedAddress *) cls; struct ATS_Address *addr = value; struct MLP_information *mlpi = addr->mlp_information; if (mlpi == NULL) return GNUNET_YES; if (mlpi->n == GNUNET_YES) { aa->address = addr; if (mlpi->b > (double) UINT32_MAX) aa->bandwidth_out = UINT32_MAX; else aa->bandwidth_out = (uint32_t) mlpi->b; aa->bandwidth_in = 0; return GNUNET_NO; } return GNUNET_YES; } /** * Get the preferred address for a specific peer * * @param mlp the MLP Handle * @param addresses address hashmap * @param peer the peer * @return suggested address */ struct ATS_PreferedAddress * GAS_mlp_get_preferred_address (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, const struct GNUNET_PeerIdentity *peer) { struct ATS_PreferedAddress * aa = GNUNET_malloc (sizeof (struct ATS_PreferedAddress)); aa->address = NULL; aa->bandwidth_in = 0; aa->bandwidth_out = 0; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting preferred address for `%s'\n", GNUNET_i2s (peer)); GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey, mlp_get_preferred_address_it, aa); return aa; } /** * Changes the preferences for a peer in the MLP problem * * @param mlp the MLP Handle * @param peer the peer * @param kind the kind to change the preference * @param score the score */ void GAS_mlp_address_change_preference (struct GAS_MLP_Handle *mlp, const struct GNUNET_PeerIdentity *peer, enum GNUNET_ATS_PreferenceKind kind, float score) { GNUNET_STATISTICS_update (mlp->stats,"# LP address preference changes", 1, GNUNET_NO); struct ATS_Peer *p = mlp_find_peer (mlp, peer); p = p; /* Here we have to do the matching */ } /** * Shutdown the MLP problem solving component * @param mlp the MLP handle */ void GAS_mlp_done (struct GAS_MLP_Handle *mlp) { struct ATS_Peer * peer; struct ATS_Address *addr; GNUNET_assert (mlp != NULL); if (mlp->mlp_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel(mlp->mlp_task); mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK; } /* clean up peer list */ peer = mlp->peer_head; while (peer != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up peer `%s'\n", GNUNET_i2s (&peer->id)); GNUNET_CONTAINER_DLL_remove(mlp->peer_head, mlp->peer_tail, peer); for (addr = peer->head; NULL != addr; addr = peer->head) { GNUNET_CONTAINER_DLL_remove(peer->head, peer->tail, addr); GNUNET_free (addr->mlp_information); addr->mlp_information = NULL; } GNUNET_free (peer); peer = mlp->peer_head; } mlp_delete_problem (mlp); /* Clean up GLPK environment */ glp_free_env(); GNUNET_free (mlp); } /* end of gnunet-service-ats_addresses_mlp.c */ gnunet-0.9.3/src/ats/ats_api_scheduling.c0000644000175000017500000010347211760502551015324 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file ats/ats_api_scheduling.c * @brief automatic transport selection and outbound bandwidth determination * @author Christian Grothoff * @author Matthias Wachs */ #include "platform.h" #include "gnunet_ats_service.h" #include "ats.h" #define INTERFACE_PROCESSING_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) /** * Message in linked list we should send to the ATS service. The * actual binary message follows this struct. */ struct PendingMessage { /** * Kept in a DLL. */ struct PendingMessage *next; /** * Kept in a DLL. */ struct PendingMessage *prev; /** * Size of the message. */ size_t size; /** * Is this the 'ATS_START' message? */ int is_init; }; /** * Information we track per session. */ struct SessionRecord { /** * Identity of the peer (just needed for error checking). */ struct GNUNET_PeerIdentity peer; /** * Session handle. */ struct Session *session; /** * Set to GNUNET_YES if the slot is used. */ int slot_used; }; struct ATS_Network { struct ATS_Network * next; struct ATS_Network * prev; struct sockaddr *network; struct sockaddr *netmask; socklen_t length; }; /** * Handle to the ATS subsystem for bandwidth/transport scheduling information. */ struct GNUNET_ATS_SchedulingHandle { /** * Our configuration. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Callback to invoke on suggestions. */ GNUNET_ATS_AddressSuggestionCallback suggest_cb; /** * Closure for 'suggest_cb'. */ void *suggest_cb_cls; /** * Connection to ATS service. */ struct GNUNET_CLIENT_Connection *client; /** * Head of list of messages for the ATS service. */ struct PendingMessage *pending_head; /** * Tail of list of messages for the ATS service */ struct PendingMessage *pending_tail; /** * Current request for transmission to ATS. */ struct GNUNET_CLIENT_TransmitHandle *th; /** * Head of network list */ struct ATS_Network * net_head; /** * Tail of network list */ struct ATS_Network * net_tail; /** * Array of session objects (we need to translate them to numbers and back * for the protocol; the offset in the array is the session number on the * network). Index 0 is always NULL and reserved to represent the NULL pointer. * Unused entries are also NULL. */ struct SessionRecord *session_array; /** * Task to trigger reconnect. */ GNUNET_SCHEDULER_TaskIdentifier task; /** * Task retrieving interfaces from the system */ GNUNET_SCHEDULER_TaskIdentifier interface_task; /** * Size of the session array. */ unsigned int session_array_size; /** * Should we reconnect to ATS due to some serious error? */ int reconnect; }; /** * Re-establish the connection to the ATS service. * * @param sh handle to use to re-connect. */ static void reconnect (struct GNUNET_ATS_SchedulingHandle *sh); /** * Re-establish the connection to the ATS service. * * @param cls handle to use to re-connect. * @param tc scheduler context */ static void reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_ATS_SchedulingHandle *sh = cls; sh->task = GNUNET_SCHEDULER_NO_TASK; reconnect (sh); } /** * Disconnect from ATS and then reconnect. * * @param sh our handle */ static void force_reconnect (struct GNUNET_ATS_SchedulingHandle *sh) { sh->reconnect = GNUNET_NO; GNUNET_CLIENT_disconnect (sh->client); sh->client = NULL; sh->task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task, sh); } /** * Transmit messages from the message queue to the service * (if there are any, and if we are not already trying). * * @param sh handle to use */ static void do_transmit (struct GNUNET_ATS_SchedulingHandle *sh); /** * Type of a function to call when we receive a message * from the service. * * @param cls the 'struct GNUNET_ATS_SchedulingHandle' * @param msg message received, NULL on timeout or fatal error */ static void process_ats_message (void *cls, const struct GNUNET_MessageHeader *msg); /** * We can now transmit a message to ATS. Do it. * * @param cls the 'struct GNUNET_ATS_SchedulingHandle' * @param size number of bytes we can transmit to ATS * @param buf where to copy the messages * @return number of bytes copied into buf */ static size_t transmit_message_to_ats (void *cls, size_t size, void *buf) { struct GNUNET_ATS_SchedulingHandle *sh = cls; struct PendingMessage *p; size_t ret; char *cbuf; sh->th = NULL; if ((size == 0) || (buf == NULL)) { force_reconnect (sh); return 0; } ret = 0; cbuf = buf; while ((NULL != (p = sh->pending_head)) && (p->size <= size)) { memcpy (&cbuf[ret], &p[1], p->size); ret += p->size; size -= p->size; GNUNET_CONTAINER_DLL_remove (sh->pending_head, sh->pending_tail, p); if (GNUNET_YES == p->is_init) GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh, GNUNET_TIME_UNIT_FOREVER_REL); GNUNET_free (p); } do_transmit (sh); return ret; } /** * Transmit messages from the message queue to the service * (if there are any, and if we are not already trying). * * @param sh handle to use */ static void do_transmit (struct GNUNET_ATS_SchedulingHandle *sh) { struct PendingMessage *p; if (NULL != sh->th) return; if (NULL == (p = sh->pending_head)) return; if (NULL == sh->client) return; /* currently reconnecting */ sh->th = GNUNET_CLIENT_notify_transmit_ready (sh->client, p->size, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_NO, &transmit_message_to_ats, sh); } /** * Find the session object corresponding to the given session ID. * * @param sh our handle * @param session_id current session ID * @param peer peer the session belongs to * @return the session object (or NULL) */ static struct Session * find_session (struct GNUNET_ATS_SchedulingHandle *sh, uint32_t session_id, const struct GNUNET_PeerIdentity *peer) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-scheduling-api", "Find session %u from peer %s in %p\n", (unsigned int) session_id, GNUNET_i2s (peer), sh); if (session_id >= sh->session_array_size) { GNUNET_break (0); return NULL; } if (0 == session_id) return NULL; if (sh->session_array[session_id].session == NULL) { GNUNET_break (0 == memcmp (peer, &sh->session_array[session_id].peer, sizeof (struct GNUNET_PeerIdentity))); return NULL; } if (0 != memcmp (peer, &sh->session_array[session_id].peer, sizeof (struct GNUNET_PeerIdentity))) { GNUNET_break (0); sh->reconnect = GNUNET_YES; return NULL; } return sh->session_array[session_id].session; } /** * Get the ID for the given session object. If we do not have an ID for * the given session object, allocate one. * * @param sh our handle * @param session session object * @param peer peer the session belongs to * @return the session id */ static uint32_t get_session_id (struct GNUNET_ATS_SchedulingHandle *sh, struct Session *session, const struct GNUNET_PeerIdentity *peer) { unsigned int i; unsigned int f; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-scheduling-api", "Get session ID for session %p from peer %s in %p\n", session, GNUNET_i2s (peer), sh); if (NULL == session) return 0; f = 0; for (i = 1; i < sh->session_array_size; i++) { if (session == sh->session_array[i].session) { GNUNET_assert (0 == memcmp (peer, &sh->session_array[i].peer, sizeof (struct GNUNET_PeerIdentity))); return i; } if ((f == 0) && (sh->session_array[i].slot_used == GNUNET_NO)) f = i; } if (f == 0) { f = sh->session_array_size; GNUNET_array_grow (sh->session_array, sh->session_array_size, sh->session_array_size * 2); } GNUNET_assert (f > 0); sh->session_array[f].session = session; sh->session_array[f].peer = *peer; sh->session_array[f].slot_used = GNUNET_YES; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-scheduling-api", "Assigning session ID %u for session %p of peer %s in %p\n", f, session, GNUNET_i2s (peer), sh); return f; } /** * Remove the session of the given session ID from the session * table (it is no longer valid). * * @param sh our handle * @param session_id identifies session that is no longer valid * @param peer peer the session belongs to */ static void remove_session (struct GNUNET_ATS_SchedulingHandle *sh, uint32_t session_id, const struct GNUNET_PeerIdentity *peer) { GNUNET_assert (peer != NULL); GNUNET_assert (sh != NULL); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-scheduling-api", "Release sessionID %u from peer %s in %p\n", (unsigned int) session_id, GNUNET_i2s (peer), sh); if (0 == session_id) return; GNUNET_assert (session_id < sh->session_array_size); GNUNET_assert (GNUNET_YES == sh->session_array[session_id].slot_used); GNUNET_assert (0 == memcmp (peer, &sh->session_array[session_id].peer, sizeof (struct GNUNET_PeerIdentity))); sh->session_array[session_id].session = NULL; } /** * Release the session slot from the session table (ATS service is * also done using it). * * @param sh our handle * @param session_id identifies session that is no longer valid * @param peer peer the session belongs to */ static void release_session (struct GNUNET_ATS_SchedulingHandle *sh, uint32_t session_id, const struct GNUNET_PeerIdentity *peer) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-scheduling-api", "Release sessionID %u from peer %s in %p\n", (unsigned int) session_id, GNUNET_i2s (peer), sh); if (session_id >= sh->session_array_size) { GNUNET_break (0); sh->reconnect = GNUNET_YES; return; } /* this slot should have been removed from remove_session before */ GNUNET_assert (sh->session_array[session_id].session == NULL); if (0 != memcmp (peer, &sh->session_array[session_id].peer, sizeof (struct GNUNET_PeerIdentity))) { GNUNET_break (0); sh->reconnect = GNUNET_YES; return; } sh->session_array[session_id].slot_used = GNUNET_NO; memset (&sh->session_array[session_id].peer, 0, sizeof (struct GNUNET_PeerIdentity)); } static void process_release_message (struct GNUNET_ATS_SchedulingHandle *sh, const struct SessionReleaseMessage *srm) { release_session (sh, ntohl (srm->session_id), &srm->peer); } /** * Type of a function to call when we receive a message * from the service. * * @param cls the 'struct GNUNET_ATS_SchedulingHandle' * @param msg message received, NULL on timeout or fatal error */ static void process_ats_message (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_ATS_SchedulingHandle *sh = cls; const struct AddressSuggestionMessage *m; const struct GNUNET_ATS_Information *atsi; const char *plugin_address; const char *plugin_name; uint16_t plugin_address_length; uint16_t plugin_name_length; uint32_t ats_count; struct GNUNET_HELLO_Address address; struct Session *s; if (NULL == msg) { force_reconnect (sh); return; } if ((ntohs (msg->type) == GNUNET_MESSAGE_TYPE_ATS_SESSION_RELEASE) && (ntohs (msg->size) == sizeof (struct SessionReleaseMessage))) { process_release_message (sh, (const struct SessionReleaseMessage *) msg); GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh, GNUNET_TIME_UNIT_FOREVER_REL); if (GNUNET_YES == sh->reconnect) force_reconnect (sh); return; } if ((ntohs (msg->type) != GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION) || (ntohs (msg->size) <= sizeof (struct AddressSuggestionMessage))) { GNUNET_break (0); force_reconnect (sh); return; } m = (const struct AddressSuggestionMessage *) msg; ats_count = ntohl (m->ats_count); plugin_address_length = ntohs (m->address_length); atsi = (const struct GNUNET_ATS_Information *) &m[1]; plugin_address = (const char *) &atsi[ats_count]; plugin_name = &plugin_address[plugin_address_length]; plugin_name_length = ntohs (m->plugin_name_length); if ((plugin_address_length + plugin_name_length + ats_count * sizeof (struct GNUNET_ATS_Information) + sizeof (struct AddressSuggestionMessage) != ntohs (msg->size)) || (ats_count > GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information)) || (plugin_name[plugin_name_length - 1] != '\0')) { GNUNET_break (0); force_reconnect (sh); return; } uint32_t session_id = ntohl (m->session_id); if (session_id == 0) s = NULL; else { s = find_session (sh, session_id, &m->peer); if (s == NULL) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-scheduling-api", "ATS tries to use outdated session `%s'\n", GNUNET_i2s (&m->peer)); GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh, GNUNET_TIME_UNIT_FOREVER_REL); return; } } address.peer = m->peer; address.address = plugin_address; address.address_length = plugin_address_length; address.transport_name = plugin_name; if ((s == NULL) && (0 == address.address_length)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ATS returned invalid address for peer `%s' transport `%s' address length %i, session_id %i\n", GNUNET_i2s (&address.peer), address.transport_name, plugin_address_length, session_id); GNUNET_break_op (0); GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh, GNUNET_TIME_UNIT_FOREVER_REL); return; } sh->suggest_cb (sh->suggest_cb_cls, &address, s, m->bandwidth_out, m->bandwidth_in, atsi, ats_count); GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh, GNUNET_TIME_UNIT_FOREVER_REL); if (GNUNET_YES == sh->reconnect) force_reconnect (sh); } /** * Re-establish the connection to the ATS service. * * @param sh handle to use to re-connect. */ static void reconnect (struct GNUNET_ATS_SchedulingHandle *sh) { struct PendingMessage *p; struct ClientStartMessage *init; GNUNET_assert (NULL == sh->client); sh->client = GNUNET_CLIENT_connect ("ats", sh->cfg); GNUNET_assert (NULL != sh->client); if ((NULL == (p = sh->pending_head)) || (GNUNET_YES != p->is_init)) { p = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (struct ClientStartMessage)); p->size = sizeof (struct ClientStartMessage); p->is_init = GNUNET_YES; init = (struct ClientStartMessage *) &p[1]; init->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_START); init->header.size = htons (sizeof (struct ClientStartMessage)); init->start_flag = htonl (START_FLAG_SCHEDULING); GNUNET_CONTAINER_DLL_insert (sh->pending_head, sh->pending_tail, p); } do_transmit (sh); } /** * delete the current network list */ static void delete_networks (struct GNUNET_ATS_SchedulingHandle *sh) { struct ATS_Network * cur = sh->net_head; while (cur != NULL) { GNUNET_CONTAINER_DLL_remove(sh->net_head, sh->net_tail, cur); GNUNET_free (cur); cur = sh->net_head; } } static int interface_proc (void *cls, const char *name, int isDefault, const struct sockaddr * addr, const struct sockaddr * broadcast_addr, const struct sockaddr * netmask, socklen_t addrlen) { struct GNUNET_ATS_SchedulingHandle * sh = cls; /* Calculate network */ struct ATS_Network *net = NULL; /* Skipping IPv4 loopback addresses since we have special check */ if (addr->sa_family == AF_INET) { struct sockaddr_in * a4 = (struct sockaddr_in *) addr; if ((a4->sin_addr.s_addr & htonl(0xff000000)) == htonl (0x7f000000)) return GNUNET_OK; } /* Skipping IPv6 loopback addresses since we have special check */ if (addr->sa_family == AF_INET6) { struct sockaddr_in6 * a6 = (struct sockaddr_in6 *) addr; if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr)) return GNUNET_OK; } if (addr->sa_family == AF_INET) { struct sockaddr_in *addr4 = (struct sockaddr_in *) addr; struct sockaddr_in *netmask4 = (struct sockaddr_in *) netmask; struct sockaddr_in *tmp = NULL; struct sockaddr_in network4; net = GNUNET_malloc(sizeof (struct ATS_Network) + 2 * sizeof (struct sockaddr_in)); tmp = (struct sockaddr_in *) &net[1]; net->network = (struct sockaddr *) &tmp[0]; net->netmask = (struct sockaddr *) &tmp[1]; net->length = addrlen; memset (&network4, 0, sizeof (network4)); network4.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN network4.sin_len = sizeof (network4); #endif network4.sin_addr.s_addr = (addr4->sin_addr.s_addr & netmask4->sin_addr.s_addr); memcpy (net->netmask, netmask4, sizeof (struct sockaddr_in)); memcpy (net->network, &network4, sizeof (struct sockaddr_in)); } if (addr->sa_family == AF_INET6) { struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr; struct sockaddr_in6 *netmask6 = (struct sockaddr_in6 *) netmask; struct sockaddr_in6 * tmp = NULL; struct sockaddr_in6 network6; net = GNUNET_malloc(sizeof (struct ATS_Network) + 2 * sizeof (struct sockaddr_in6)); tmp = (struct sockaddr_in6 *) &net[1]; net->network = (struct sockaddr *) &tmp[0]; net->netmask = (struct sockaddr *) &tmp[1]; net->length = addrlen; memset (&network6, 0, sizeof (network6)); network6.sin6_family = AF_INET6; #if HAVE_SOCKADDR_IN_SIN_LEN network6.sin6_len = sizeof (network6); #endif int c = 0; uint32_t *addr_elem = (uint32_t *) &addr6->sin6_addr; uint32_t *mask_elem = (uint32_t *) &netmask6->sin6_addr; uint32_t *net_elem = (uint32_t *) &network6.sin6_addr; for (c = 0; c < 4; c++) net_elem[c] = addr_elem[c] & mask_elem[c]; memcpy (net->netmask, netmask6, sizeof (struct sockaddr_in6)); memcpy (net->network, &network6, sizeof (struct sockaddr_in6)); } /* Store in list */ if (net != NULL) { #if VERBOSE_ATS char * netmask = GNUNET_strdup (GNUNET_a2s((struct sockaddr *) net->netmask, addrlen)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding network `%s', netmask `%s'\n", GNUNET_a2s((struct sockaddr *) net->network, addrlen), netmask); GNUNET_free (netmask); # endif GNUNET_CONTAINER_DLL_insert(sh->net_head, sh->net_tail, net); } return GNUNET_OK; } /** * Periodically get list of addresses * @param cls closure * @param tc Task context */ static void get_addresses (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_ATS_SchedulingHandle * sh = cls; sh->interface_task = GNUNET_SCHEDULER_NO_TASK; delete_networks (sh); GNUNET_OS_network_interfaces_list(interface_proc, sh); sh->interface_task = GNUNET_SCHEDULER_add_delayed (INTERFACE_PROCESSING_INTERVALL, get_addresses, sh); } /** * Returns where the address is located: LAN or WAN or ... * * @param sh the scheduling handle * @param addr address * @param addrlen address length * @return location as GNUNET_ATS_Information */ struct GNUNET_ATS_Information GNUNET_ATS_address_get_type (struct GNUNET_ATS_SchedulingHandle * sh, const struct sockaddr * addr, socklen_t addrlen) { GNUNET_assert (sh != NULL); struct GNUNET_ATS_Information ats; struct ATS_Network * cur = sh->net_head; int type = GNUNET_ATS_NET_UNSPECIFIED; if (addr->sa_family == AF_UNIX) { type = GNUNET_ATS_NET_LOOPBACK; } /* IPv4 loopback check */ if (addr->sa_family == AF_INET) { struct sockaddr_in * a4 = (struct sockaddr_in *) addr; if ((a4->sin_addr.s_addr & htonl(0xff000000)) == htonl (0x7f000000)) type = GNUNET_ATS_NET_LOOPBACK; } /* IPv6 loopback check */ if (addr->sa_family == AF_INET6) { struct sockaddr_in6 * a6 = (struct sockaddr_in6 *) addr; if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr)) type = GNUNET_ATS_NET_LOOPBACK; } /* Check local networks */ while ((cur != NULL) && (type == GNUNET_ATS_NET_UNSPECIFIED)) { if (addrlen != cur->length) { cur = cur->next; continue; } if (addr->sa_family == AF_INET) { struct sockaddr_in * a4 = (struct sockaddr_in *) addr; struct sockaddr_in * net4 = (struct sockaddr_in *) cur->network; struct sockaddr_in * mask4 = (struct sockaddr_in *) cur->netmask; if (((a4->sin_addr.s_addr & mask4->sin_addr.s_addr)) == net4->sin_addr.s_addr) { char * net = GNUNET_strdup (GNUNET_a2s ((const struct sockaddr *) net4, addrlen)); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-scheduling-api", "`%s' is in network `%s'\n", GNUNET_a2s ((const struct sockaddr *)a4, addrlen), net); GNUNET_free (net); type = GNUNET_ATS_NET_LAN; } } if (addr->sa_family == AF_INET6) { struct sockaddr_in6 * a6 = (struct sockaddr_in6 *) addr; struct sockaddr_in6 * net6 = (struct sockaddr_in6 *) cur->network; struct sockaddr_in6 * mask6 = (struct sockaddr_in6 *) cur->netmask; int res = GNUNET_YES; int c = 0; uint32_t *addr_elem = (uint32_t *) &a6->sin6_addr; uint32_t *mask_elem = (uint32_t *) &mask6->sin6_addr; uint32_t *net_elem = (uint32_t *) &net6->sin6_addr; for (c = 0; c < 4; c++) if ((addr_elem[c] & mask_elem[c]) != net_elem[c]) res = GNUNET_NO; if (res == GNUNET_YES) { char * net = GNUNET_strdup (GNUNET_a2s ((const struct sockaddr *) net6, addrlen)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' is in network `%s'\n", GNUNET_a2s ((const struct sockaddr *) a6, addrlen), net); GNUNET_free (net); type = GNUNET_ATS_NET_LAN; } } cur = cur->next; } /* no local network found for this address, default: WAN */ if (type == GNUNET_ATS_NET_UNSPECIFIED) type = GNUNET_ATS_NET_WAN; ats.type = htonl (GNUNET_ATS_NETWORK_TYPE); ats.value = htonl (type); return (const struct GNUNET_ATS_Information) ats; } /** * Initialize the ATS subsystem. * * @param cfg configuration to use * @param suggest_cb notification to call whenever the suggestation changed * @param suggest_cb_cls closure for 'suggest_cb' * @return ats context */ struct GNUNET_ATS_SchedulingHandle * GNUNET_ATS_scheduling_init (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_ATS_AddressSuggestionCallback suggest_cb, void *suggest_cb_cls) { struct GNUNET_ATS_SchedulingHandle *sh; sh = GNUNET_malloc (sizeof (struct GNUNET_ATS_SchedulingHandle)); sh->cfg = cfg; sh->suggest_cb = suggest_cb; sh->suggest_cb_cls = suggest_cb_cls; GNUNET_array_grow (sh->session_array, sh->session_array_size, 4); GNUNET_OS_network_interfaces_list(interface_proc, sh); sh->interface_task = GNUNET_SCHEDULER_add_delayed (INTERFACE_PROCESSING_INTERVALL, get_addresses, sh); reconnect (sh); return sh; } /** * Client is done with ATS scheduling, release resources. * * @param sh handle to release */ void GNUNET_ATS_scheduling_done (struct GNUNET_ATS_SchedulingHandle *sh) { struct PendingMessage *p; while (NULL != (p = sh->pending_head)) { GNUNET_CONTAINER_DLL_remove (sh->pending_head, sh->pending_tail, p); GNUNET_free (p); } if (NULL != sh->client) { GNUNET_CLIENT_disconnect (sh->client); sh->client = NULL; } if (GNUNET_SCHEDULER_NO_TASK != sh->task) { GNUNET_SCHEDULER_cancel (sh->task); sh->task = GNUNET_SCHEDULER_NO_TASK; } delete_networks (sh); if (sh->interface_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel(sh->interface_task); sh->interface_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_array_grow (sh->session_array, sh->session_array_size, 0); GNUNET_free (sh); sh = NULL; } /** * We would like to reset the address suggestion block time for this * peer * * @param sh handle * @param peer identity of the peer we want to reset */ void GNUNET_ATS_reset_backoff (struct GNUNET_ATS_SchedulingHandle *sh, const struct GNUNET_PeerIdentity *peer) { struct PendingMessage *p; struct ResetBackoffMessage *m; p = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (struct ResetBackoffMessage)); p->size = sizeof (struct ResetBackoffMessage); p->is_init = GNUNET_NO; m = (struct ResetBackoffMessage *) &p[1]; m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_RESET_BACKOFF); m->header.size = htons (sizeof (struct ResetBackoffMessage)); m->reserved = htonl (0); m->peer = *peer; GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p); do_transmit (sh); } /** * We would like to establish a new connection with a peer. ATS * should suggest a good address to begin with. * * @param sh handle * @param peer identity of the peer we need an address for */ void GNUNET_ATS_suggest_address (struct GNUNET_ATS_SchedulingHandle *sh, const struct GNUNET_PeerIdentity *peer) { struct PendingMessage *p; struct RequestAddressMessage *m; // FIXME: ATS needs to remember this in case of // a disconnect! p = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (struct RequestAddressMessage)); p->size = sizeof (struct RequestAddressMessage); p->is_init = GNUNET_NO; m = (struct RequestAddressMessage *) &p[1]; m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS); m->header.size = htons (sizeof (struct RequestAddressMessage)); m->reserved = htonl (0); m->peer = *peer; GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p); do_transmit (sh); } /** * We would like to stop receiving address updates for this peer * * @param sh handle * @param peer identity of the peer */ void GNUNET_ATS_suggest_address_cancel (struct GNUNET_ATS_SchedulingHandle *sh, const struct GNUNET_PeerIdentity *peer) { struct PendingMessage *p; struct RequestAddressMessage *m; p = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (struct RequestAddressMessage)); p->size = sizeof (struct RequestAddressMessage); p->is_init = GNUNET_NO; m = (struct RequestAddressMessage *) &p[1]; m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS_CANCEL); m->header.size = htons (sizeof (struct RequestAddressMessage)); m->reserved = htonl (0); m->peer = *peer; GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p); do_transmit (sh); } /** * We have updated performance statistics for a given address. Note * that this function can be called for addresses that are currently * in use as well as addresses that are valid but not actively in use. * Furthermore, the peer may not even be connected to us right now (in * which case the call may be ignored or the information may be stored * for later use). Update bandwidth assignments. * * @param sh handle * @param address the address * @param session session handle (if available) * @param ats performance data for the address * @param ats_count number of performance records in 'ats' */ void GNUNET_ATS_address_update (struct GNUNET_ATS_SchedulingHandle *sh, const struct GNUNET_HELLO_Address *address, struct Session *session, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { struct PendingMessage *p; struct AddressUpdateMessage *m; struct GNUNET_ATS_Information *am; char *pm; size_t namelen; size_t msize; if (address == NULL) { GNUNET_break (0); return; } if ((address == NULL) && (session == NULL)) { GNUNET_break (0); return; } namelen = (address->transport_name == NULL) ? 0 : strlen (address->transport_name) + 1; msize = sizeof (struct AddressUpdateMessage) + address->address_length + ats_count * sizeof (struct GNUNET_ATS_Information) + namelen; if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || (ats_count >= GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information))) { GNUNET_break (0); return; } p = GNUNET_malloc (sizeof (struct PendingMessage) + msize); p->size = msize; p->is_init = GNUNET_NO; m = (struct AddressUpdateMessage *) &p[1]; m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_UPDATE); m->header.size = htons (msize); m->ats_count = htonl (ats_count); m->peer = address->peer; m->address_length = htons (address->address_length); m->plugin_name_length = htons (namelen); m->session_id = htonl (get_session_id (sh, session, &address->peer)); am = (struct GNUNET_ATS_Information *) &m[1]; memcpy (am, ats, ats_count * sizeof (struct GNUNET_ATS_Information)); pm = (char *) &am[ats_count]; memcpy (pm, address->address, address->address_length); memcpy (&pm[address->address_length], address->transport_name, namelen); GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p); do_transmit (sh); } /** * An address is now in use or not used any more. * * @param sh handle * @param address the address * @param session session handle * @param in_use GNUNET_YES if this address is now used, GNUNET_NO * if address is not used any more */ void GNUNET_ATS_address_in_use (struct GNUNET_ATS_SchedulingHandle *sh, const struct GNUNET_HELLO_Address *address, struct Session *session, int in_use) { struct PendingMessage *p; struct AddressUseMessage *m; char *pm; size_t namelen; size_t msize; GNUNET_assert (NULL != address); namelen = (address->transport_name == NULL) ? 0 : strlen (address->transport_name) + 1; msize = sizeof (struct AddressUseMessage) + address->address_length + namelen; if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)) { GNUNET_break (0); return; } p = GNUNET_malloc (sizeof (struct PendingMessage) + msize); p->size = msize; p->is_init = GNUNET_NO; m = (struct AddressUseMessage *) &p[1]; m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_IN_USE); m->header.size = htons (msize); m->peer = address->peer; m->in_use = htons (in_use); m->address_length = htons (address->address_length); m->plugin_name_length = htons (namelen); m->session_id = htonl (get_session_id (sh, session, &address->peer)); pm = (char *) &m[1]; memcpy (pm, address->address, address->address_length); memcpy (&pm[address->address_length], address->transport_name, namelen); GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p); do_transmit (sh); } /** * A session got destroyed, stop including it as a valid address. * * @param sh handle * @param address the address * @param session session handle that is no longer valid */ void GNUNET_ATS_address_destroyed (struct GNUNET_ATS_SchedulingHandle *sh, const struct GNUNET_HELLO_Address *address, struct Session *session) { struct PendingMessage *p; struct AddressDestroyedMessage *m; char *pm; size_t namelen; size_t msize; uint32_t session_id; GNUNET_assert (address->transport_name != NULL); namelen = strlen (address->transport_name) + 1; GNUNET_assert (namelen > 1); msize = sizeof (struct AddressDestroyedMessage) + address->address_length + namelen; if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)) { GNUNET_break (0); return; } p = GNUNET_malloc (sizeof (struct PendingMessage) + msize); p->size = msize; p->is_init = GNUNET_NO; m = (struct AddressDestroyedMessage *) &p[1]; m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_DESTROYED); m->header.size = htons (msize); m->reserved = htonl (0); m->peer = address->peer; m->address_length = htons (address->address_length); m->plugin_name_length = htons (namelen); session_id = get_session_id (sh, session, &address->peer); m->session_id = htonl (session_id); pm = (char *) &m[1]; memcpy (pm, address->address, address->address_length); memcpy (&pm[address->address_length], address->transport_name, namelen); GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p); do_transmit (sh); remove_session (sh, session_id, &address->peer); } /* end of ats_api_scheduling.c */ gnunet-0.9.3/src/ats/gnunet-service-ats.c0000644000175000017500000001276211760502551015223 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file ats/gnunet-service-ats.c * @brief ats service * @author Matthias Wachs * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_ats_service.h" #include "gnunet-service-ats.h" #include "gnunet-service-ats_addresses.h" #include "gnunet-service-ats_performance.h" #include "gnunet-service-ats_scheduling.h" #include "gnunet-service-ats_reservations.h" #include "ats.h" /** * Handle for statistics. */ struct GNUNET_STATISTICS_Handle *GSA_stats; static struct GNUNET_SERVER_Handle *GSA_server; /** * We have received a 'ClientStartMessage' from a client. Find out which * type of client it is and notify the respective subsystem. * * @param cls closure, unused * @param client handle to the client * @param message the start message */ static void handle_ats_start (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct ClientStartMessage *msg = (const struct ClientStartMessage *) message; enum StartFlag flag; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ATS_START"); flag = ntohl (msg->start_flag); switch (flag) { case START_FLAG_SCHEDULING: if (GNUNET_OK != GAS_scheduling_add_client (client)) { GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } break; case START_FLAG_PERFORMANCE_WITH_PIC: GAS_performance_add_client (client, flag); break; case START_FLAG_PERFORMANCE_NO_PIC: GAS_performance_add_client (client, flag); break; default: GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * A client disconnected from us. Tear down the local client * record. * * @param cls unused * @param client handle of the client */ static void client_disconnect_handler (void *cls, struct GNUNET_SERVER_Client *client) { if (NULL == client) return; GAS_scheduling_remove_client (client); GAS_performance_remove_client (client); } /** * Task run during shutdown. * * @param cls unused * @param tc unused */ static void cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GAS_addresses_done (); GAS_scheduling_done (); GAS_performance_done (); GAS_reservations_done (); GNUNET_SERVER_disconnect_notify_cancel (GSA_server, &client_disconnect_handler, NULL); if (NULL != GSA_stats) { GNUNET_STATISTICS_destroy (GSA_stats, GNUNET_NO); GSA_stats = NULL; } } /** * Process template requests. * * @param cls closure * @param server the initialized server * @param cfg configuration to use */ static void run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *cfg) { static const struct GNUNET_SERVER_MessageHandler handlers[] = { {&handle_ats_start, NULL, GNUNET_MESSAGE_TYPE_ATS_START, sizeof (struct ClientStartMessage)}, {&GAS_handle_request_address, NULL, GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS, sizeof (struct RequestAddressMessage)}, {&GAS_handle_request_address_cancel, NULL, GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS_CANCEL, sizeof (struct RequestAddressMessage)}, {&GAS_handle_address_update, NULL, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_UPDATE, 0}, {&GAS_handle_address_in_use, NULL, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_IN_USE, 0}, {&GAS_handle_address_destroyed, NULL, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_DESTROYED, 0}, {&GAS_handle_reservation_request, NULL, GNUNET_MESSAGE_TYPE_ATS_RESERVATION_REQUEST, sizeof (struct ReservationRequestMessage)}, {&GAS_handle_preference_change, NULL, GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_CHANGE, 0}, {&GAS_handle_reset_backoff, NULL, GNUNET_MESSAGE_TYPE_ATS_RESET_BACKOFF, sizeof (struct ResetBackoffMessage)}, {NULL, NULL, 0, 0} }; GSA_server = server; GSA_stats = GNUNET_STATISTICS_create ("ats", cfg); GAS_reservations_init (); GAS_performance_init (server); GAS_scheduling_init (server); GAS_addresses_init (cfg, GSA_stats); GNUNET_SERVER_disconnect_notify (server, &client_disconnect_handler, NULL); GNUNET_SERVER_add_handlers (server, handlers); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, NULL); } /** * The main function for the ats service. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { return (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "ats", GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; } /* end of gnunet-service-ats.c */ gnunet-0.9.3/src/ats/gnunet-service-ats.h0000644000175000017500000000217411760502551015224 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file ats/gnunet-service-ats.h * @brief ats service * @author Matthias Wachs * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_ATS_H #define GNUNET_SERVICE_ATS_H #include "gnunet_statistics_service.h" /** * Handle for statistics. */ extern struct GNUNET_STATISTICS_Handle *GSA_stats; #endif gnunet-0.9.3/src/ats/test_ats_api_reset_backoff.c0000644000175000017500000001710111760502551017024 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file ats/test_ats_api_reset_backoff.c * @brief test case for block reset api * @author Christian Grothoff * @author Matthias Wachs */ #include "platform.h" #include "gnunet_ats_service.h" #include "ats.h" #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) #define ATS_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 90) static GNUNET_SCHEDULER_TaskIdentifier die_task; static GNUNET_SCHEDULER_TaskIdentifier suggest_timeout_task; static struct GNUNET_ATS_SchedulingHandle *ats; struct GNUNET_OS_Process *arm_proc; static int ret; struct Address { char *plugin; size_t plugin_len; void *addr; size_t addr_len; struct GNUNET_ATS_Information *ats; int ats_count; void *session; }; struct PeerContext { struct GNUNET_PeerIdentity id; struct Address *addr; }; struct GNUNET_HELLO_Address hello_addr; struct Address address; struct PeerContext peer; struct GNUNET_ATS_Information atsi[2]; static void stop_arm () { if (0 != GNUNET_OS_process_kill (arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); GNUNET_OS_process_wait (arm_proc); GNUNET_OS_process_destroy (arm_proc); arm_proc = NULL; } static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { die_task = GNUNET_SCHEDULER_NO_TASK; if (suggest_timeout_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (suggest_timeout_task); suggest_timeout_task = GNUNET_SCHEDULER_NO_TASK; } if (ats != NULL) { GNUNET_ATS_scheduling_done (ats); ats = NULL; } ret = GNUNET_SYSERR; stop_arm (); } static void end () { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutting down\n"); if (die_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; } if (suggest_timeout_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (suggest_timeout_task); suggest_timeout_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_ATS_scheduling_done (ats); ret = 0; stop_arm (); } static void suggest_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { suggest_timeout_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Requesting address for peer timed out\n"); if (die_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; } die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); } static void address_suggest_cb (void *cls, const struct GNUNET_HELLO_Address *a, struct Session *session, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, const struct GNUNET_ATS_Information *atsi, uint32_t ats_count) { static int suggestions; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS suggests address `%s'\n", GNUNET_i2s (&a->peer)); if (0 != memcmp (&a->peer, &peer.id, sizeof (struct GNUNET_PeerIdentity))) { GNUNET_break (0); if (die_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } if (0 != strcmp (a->transport_name, address.plugin)) { GNUNET_break (0); if (die_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } if (a->address_length != address.addr_len) { GNUNET_break (0); if (die_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } if (0 != memcmp (a->address, address.addr, a->address_length)) { GNUNET_break (0); if (die_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } if (session != address.session) { GNUNET_break (0); if (die_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } suggestions ++; if (2 == suggestions) { GNUNET_SCHEDULER_add_now(&end, NULL); return; } if (suggest_timeout_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (suggest_timeout_task); suggest_timeout_task = GNUNET_SCHEDULER_NO_TASK; } suggest_timeout_task = GNUNET_SCHEDULER_add_delayed(ATS_TIMEOUT, &suggest_timeout, NULL); } void start_arm (const char *cfgname) { arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, NULL); } static void check (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { ret = GNUNET_SYSERR; die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); start_arm (cfgfile); ats = GNUNET_ATS_scheduling_init (cfg, &address_suggest_cb, NULL); if (ats == NULL) { ret = GNUNET_SYSERR; end (); return; } /* set up peer */ GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &peer.id.hashPubKey); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created peer `%s'\n", GNUNET_i2s (&peer.id)); address.plugin = "test"; address.session = NULL; address.addr = GNUNET_strdup ("test"); address.addr_len = 4; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding address\n"); hello_addr.peer = peer.id; hello_addr.transport_name = address.plugin; hello_addr.address = address.addr; hello_addr.address_length = address.addr_len; GNUNET_ATS_address_update (ats, &hello_addr, address.session, NULL, 0); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Requesting address for peer `%s'\n", GNUNET_i2s (&peer.id)); /* Increase block timout far beyond ATS_TIMEOUT */ GNUNET_ATS_suggest_address (ats, &peer.id); GNUNET_ATS_reset_backoff(ats, &peer.id); GNUNET_ATS_suggest_address (ats, &peer.id); } int main (int argc, char *argv[]) { static char *const argv2[] = { "test_ats_api_scheduling", "-c", "test_ats_api.conf", "-L", "WARNING", NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, "test_ats_api_scheduling", "nohelp", options, &check, NULL); return ret; } /* end of file test_ats_api_reset_backoff.c */ gnunet-0.9.3/src/ats/gnunet-service-ats_addresses.c0000644000175000017500000006431611762202310017252 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file ats/gnunet-service-ats_addresses.c * @brief ats service address management * @author Matthias Wachs * @author Christian Grothoff */ #include "platform.h" #include "gnunet_ats_service.h" #include "gnunet-service-ats.h" #include "gnunet-service-ats_addresses.h" #include "gnunet-service-ats_performance.h" #include "gnunet-service-ats_scheduling.h" #include "gnunet-service-ats_reservations.h" #if HAVE_LIBGLPK #include "gnunet-service-ats_addresses_mlp.h" #endif #define VERBOSE GNUNET_NO #define ATS_BLOCKING_DELTA GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100) enum ATS_Mode { /* * Assign each peer an equal amount of bandwidth (bw) * * bw_per_peer = bw_total / #active addresses */ SIMPLE, /* * Use MLP solver to assign bandwidth */ MLP }; static struct GNUNET_CONTAINER_MultiHashMap *addresses; #if HAVE_LIBGLPK static struct GAS_MLP_Handle *mlp; #endif static unsigned long long wan_quota_in; static unsigned long long wan_quota_out; static unsigned int active_addr_count; static int ats_mode; static int running; static void send_bw_notification (struct ATS_Address *aa) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New bandwidth for peer %s is %u/%u\n", GNUNET_i2s (&aa->peer), ntohl (aa->assigned_bw_in.value__), ntohl (aa->assigned_bw_out.value__)); GAS_scheduling_transmit_address_suggestion (&aa->peer, aa->plugin, aa->addr, aa->addr_len, aa->session_id, aa->ats, aa->ats_count, aa->assigned_bw_out, aa->assigned_bw_in); GAS_reservations_set_bandwidth (&aa->peer, aa->assigned_bw_in); GAS_performance_notify_clients (&aa->peer, aa->plugin, aa->addr, aa->addr_len, aa->ats, aa->ats_count, aa->assigned_bw_out, aa->assigned_bw_in); } /** * Update a bandwidth assignment for a peer. This trivial method currently * simply assigns the same share to all active connections. * * @param cls unused * @param key unused * @param value the 'struct ATS_Address' * @return GNUNET_OK (continue to iterate) */ static int update_bw_simple_it (void *cls, const GNUNET_HashCode * key, void *value) { struct ATS_Address *aa = value; if (GNUNET_YES != aa->active) return GNUNET_OK; GNUNET_assert (active_addr_count > 0); /* Simple method */ aa->assigned_bw_in.value__ = htonl (wan_quota_in / active_addr_count); aa->assigned_bw_out.value__ = htonl (wan_quota_out / active_addr_count); send_bw_notification (aa); return GNUNET_OK; } /** * Some (significant) input changed, recalculate bandwidth assignment * for all peers. */ static void recalculate_assigned_bw () { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Recalculating bandwidth for all active connections\n"); GNUNET_STATISTICS_update (GSA_stats, "# bandwidth recalculations performed", 1, GNUNET_NO); GNUNET_STATISTICS_set (GSA_stats, "# active addresses", active_addr_count, GNUNET_NO); GNUNET_CONTAINER_multihashmap_iterate (addresses, &update_bw_simple_it, NULL); } /** * Free the given address * @param addr address to destroy */ static void free_address (struct ATS_Address *addr) { GNUNET_free_non_null (addr->ats); GNUNET_free (addr->plugin); GNUNET_free (addr); } /** * Create a ATS_address with the given information * @param peer peer * @param plugin_name plugin * @param plugin_addr address * @param plugin_addr_len address length * @param session_id session * @return the ATS_Address */ static struct ATS_Address * create_address (const struct GNUNET_PeerIdentity *peer, const char *plugin_name, const void *plugin_addr, size_t plugin_addr_len, uint32_t session_id) { struct ATS_Address *aa = NULL; aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len); aa->peer = *peer; aa->addr_len = plugin_addr_len; aa->addr = &aa[1]; memcpy (&aa[1], plugin_addr, plugin_addr_len); aa->plugin = GNUNET_strdup (plugin_name); aa->session_id = session_id; return aa; } /** * Destroy the given address. * * @param addr address to destroy * @return GNUNET_YES if bandwidth allocations should be recalcualted */ static int destroy_address (struct ATS_Address *addr) { int ret; ret = GNUNET_NO; GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (addresses, &addr->peer.hashPubKey, addr)); #if HAVE_LIBGLPK if (ats_mode == MLP) GAS_mlp_address_delete (mlp, addresses, addr); #endif if (GNUNET_YES == addr->active) { active_addr_count--; addr->active = GNUNET_NO; ret = GNUNET_YES; } free_address (addr); return ret; } struct CompareAddressContext { const struct ATS_Address *search; /* exact_address != NULL if address and session is equal */ struct ATS_Address *exact_address; /* exact_address != NULL if address and session is 0 */ struct ATS_Address *base_address; }; static int compare_address_it (void *cls, const GNUNET_HashCode * key, void *value) { struct CompareAddressContext *cac = cls; struct ATS_Address *aa = value; /* GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Comparing to: %s %s %u session %u\n", GNUNET_i2s (&aa->peer), aa->plugin, aa->addr_len, aa->session_id); */ /* find an exact matching address: aa->addr == cac->search->addr && aa->session == cac->search->session */ if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin))) { if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == cac->search->session_id)) { cac->exact_address = aa; } } /* find an matching address: aa->addr == cac->search->addr && aa->session == 0 */ /* this address can be used to be updated */ if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin))) { if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == 0)) { cac->base_address = aa; } } if (cac->exact_address == NULL) return GNUNET_YES; else return GNUNET_NO; } /** * Find an existing equivalent address record. * Compares by peer identity and network address OR by session ID * (one of the two must match). * * @param peer peer to lookup addresses for * @param addr existing address record * @return existing address record, NULL for none */ struct ATS_Address * find_address (const struct GNUNET_PeerIdentity *peer, const struct ATS_Address *addr) { struct CompareAddressContext cac; cac.exact_address = NULL; cac.base_address = NULL; cac.search = addr; GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey, &compare_address_it, &cac); /* GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "exact address: %s base address: %s\n", (cac.exact_address != NULL) ? "YES" : "NO", (cac.base_address != NULL) ? "YES" : "NO"); */ if (cac.exact_address == NULL) return cac.base_address; return cac.exact_address; } static int compare_address_session_it (void *cls, const GNUNET_HashCode * key, void *value) { struct CompareAddressContext *cac = cls; struct ATS_Address *aa = value; if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin))) { if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == cac->search->session_id)) { cac->exact_address = aa; return GNUNET_NO; } } return GNUNET_YES; } /** * Find an existing equivalent address record. * Compares by peer identity and network address AND by session ID * (one of the two must match). * * @param peer peer to lookup addresses for * @param addr existing address record * @return existing address record, NULL for none */ struct ATS_Address * find_exact_address (const struct GNUNET_PeerIdentity *peer, const struct ATS_Address *addr) { struct CompareAddressContext cac; cac.exact_address = NULL; cac.search = addr; GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey, &compare_address_session_it, &cac); return cac.exact_address; } void GAS_addresses_update (const struct GNUNET_PeerIdentity *peer, const char *plugin_name, const void *plugin_addr, size_t plugin_addr_len, uint32_t session_id, const struct GNUNET_ATS_Information *atsi, uint32_t atsi_count) { struct ATS_Address *aa; struct ATS_Address *old; uint32_t i; if (GNUNET_NO == running) return; GNUNET_assert (NULL != addresses); aa = create_address (peer, plugin_name, plugin_addr, plugin_addr_len, session_id); aa->mlp_information = NULL; aa->ats = GNUNET_malloc (atsi_count * sizeof (struct GNUNET_ATS_Information)); aa->ats_count = atsi_count; memcpy (aa->ats, atsi, atsi_count * sizeof (struct GNUNET_ATS_Information)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating address for peer `%s' %u\n", GNUNET_i2s (peer), session_id); /* Get existing address or address with session == 0 */ old = find_address (peer, aa); if (old == NULL) { GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (addresses, &peer->hashPubKey, aa, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); #if DEBUG_ATS GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added new address for peer `%s' %X\n", GNUNET_i2s (peer), aa); #endif old = aa; } else { #if DEBUG_ATS GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updated existing address for peer `%s' %p old session %u new session %u\n", GNUNET_i2s (peer), old, old->session_id, session_id); #endif GNUNET_free_non_null (old->ats); old->session_id = session_id; old->ats = NULL; old->ats_count = 0; old->ats = aa->ats; old->ats_count = aa->ats_count; GNUNET_free (aa->plugin); GNUNET_free (aa); } for (i = 0; i < atsi_count; i++) switch (ntohl (atsi[i].type)) { case GNUNET_ATS_UTILIZATION_UP: old->atsp_utilization_out.value__ = atsi[i].value; break; case GNUNET_ATS_UTILIZATION_DOWN: old->atsp_utilization_in.value__ = atsi[i].value; break; case GNUNET_ATS_QUALITY_NET_DELAY: old->atsp_latency.rel_value = ntohl (atsi[i].value); break; case GNUNET_ATS_QUALITY_NET_DISTANCE: old->atsp_distance = ntohl (atsi[i].value); break; case GNUNET_ATS_COST_WAN: old->atsp_cost_wan = ntohl (atsi[i].value); break; case GNUNET_ATS_COST_LAN: old->atsp_cost_lan = ntohl (atsi[i].value); break; case GNUNET_ATS_COST_WLAN: old->atsp_cost_wlan = ntohl (atsi[i].value); break; case GNUNET_ATS_NETWORK_TYPE: old->atsp_network_type = ntohl (atsi[i].value); break; default: GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Received unsupported ATS type %u\n", ntohl (atsi[i].type)); GNUNET_break (0); break; } #if HAVE_LIBGLPK if (ats_mode == MLP) GAS_mlp_address_update (mlp, addresses, old); #endif } /** * Delete an address * * If session != 0, just the session is deleted, the address itself still exists * If session == 0, remove full address * If session == 0 and addrlen == 0, destroy inbound address * * @param cls unused * @param key unused * @param value the 'struct ATS_Address' * @return GNUNET_OK (continue to iterate) */ static int destroy_by_session_id (void *cls, const GNUNET_HashCode * key, void *value) { const struct ATS_Address *info = cls; struct ATS_Address *aa = value; GNUNET_assert (0 == memcmp (&aa->peer, &info->peer, sizeof (struct GNUNET_PeerIdentity))); /* session == 0, remove full address */ if ((info->session_id == 0) && (0 == strcmp (info->plugin, aa->plugin)) && (aa->addr_len == info->addr_len) && (0 == memcmp (info->addr, aa->addr, aa->addr_len))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting address for peer `%s': `%s' %u\n", GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id); if (GNUNET_YES == destroy_address (aa)) recalculate_assigned_bw (); return GNUNET_OK; } /* session != 0, just remove session */ if (aa->session_id != info->session_id) return GNUNET_OK; /* irrelevant */ if (aa->session_id != 0) GNUNET_break (0 == strcmp (info->plugin, aa->plugin)); /* session died */ #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting session for peer `%s': `%s' %u\n", GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id); #endif aa->session_id = 0; if (GNUNET_YES == aa->active) { aa->active = GNUNET_NO; active_addr_count--; recalculate_assigned_bw (); } /* session == 0 and addrlen == 0 : destroy address */ if (aa->addr_len == 0) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting session and address for peer `%s': `%s' %u\n", GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id); #endif (void) destroy_address (aa); } else { /* session was set to 0, update address */ #if HAVE_LIBGLPK if (ats_mode == MLP) GAS_mlp_address_update (mlp, addresses, aa); #endif } return GNUNET_OK; } void GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer, const char *plugin_name, const void *plugin_addr, size_t plugin_addr_len, uint32_t session_id) { struct ATS_Address *aa; if (GNUNET_NO == running) return; GNUNET_break (0 < strlen (plugin_name)); aa = create_address (peer, plugin_name, plugin_addr, plugin_addr_len, session_id); GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey, &destroy_by_session_id, aa); free_address (aa); } /** * Find a "good" address to use for a peer. If we already have an existing * address, we stick to it. Otherwise, we pick by lowest distance and then * by lowest latency. * * @param cls the 'struct ATS_Address**' where we store the result * @param key unused * @param value another 'struct ATS_Address*' to consider using * @return GNUNET_OK (continue to iterate) */ static int find_address_it (void *cls, const GNUNET_HashCode * key, void *value) { struct ATS_Address **ap = cls; struct ATS_Address *aa = (struct ATS_Address *) value; struct ATS_Address *ab = *ap; struct GNUNET_TIME_Absolute now; now = GNUNET_TIME_absolute_get(); if (aa->blocked_until.abs_value == GNUNET_TIME_absolute_max (now, aa->blocked_until).abs_value) { /* This address is blocked for suggestion */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Address %p blocked for suggestion for %llu ms \n", aa, GNUNET_TIME_absolute_get_difference(now, aa->blocked_until).rel_value); return GNUNET_OK; } aa->block_interval = GNUNET_TIME_relative_add (aa->block_interval, ATS_BLOCKING_DELTA); aa->blocked_until = GNUNET_TIME_absolute_add (now, aa->block_interval); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Address %p ready for suggestion, block interval now %llu \n", aa, aa->block_interval); /* FIXME this is a hack */ if (NULL != ab) { if ((0 == strcmp (ab->plugin, "tcp")) && (0 == strcmp (aa->plugin, "tcp"))) { if ((0 != ab->addr_len) && (0 == aa->addr_len)) { /* saved address was an outbound address, but we have an inbound address */ *ap = aa; return GNUNET_OK; } if (0 == ab->addr_len) { /* saved address was an inbound address, so do not overwrite */ return GNUNET_OK; } } } /* FIXME end of hack */ if (NULL == ab) { *ap = aa; return GNUNET_OK; } if ((ntohl (ab->assigned_bw_in.value__) == 0) && (ntohl (aa->assigned_bw_in.value__) > 0)) { /* stick to existing connection */ *ap = aa; return GNUNET_OK; } if (ab->atsp_distance > aa->atsp_distance) { /* user shorter distance */ *ap = aa; return GNUNET_OK; } if (ab->atsp_latency.rel_value > aa->atsp_latency.rel_value) { /* user lower latency */ *ap = aa; return GNUNET_OK; } /* don't care */ return GNUNET_OK; } int GAS_addresses_in_use (const struct GNUNET_PeerIdentity *peer, const char *plugin_name, const void *plugin_addr, size_t plugin_addr_len, uint32_t session_id, int in_use) { #if DEBUG_ATS GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message for peer `%s': %i\n", "ADDRESS_IN_USE", GNUNET_i2s (peer), in_use); #endif struct ATS_Address *aa; struct ATS_Address *old; if (GNUNET_NO == running) return GNUNET_SYSERR; aa = create_address (peer, plugin_name, plugin_addr, plugin_addr_len, session_id); old = find_exact_address (peer, aa); free_address (aa); if (NULL == old) { GNUNET_break (0); return GNUNET_SYSERR; } if (old->used == in_use) { GNUNET_break (0); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Address in use called multiple times for peer `%s': %s -> %s \n", GNUNET_i2s (peer), (GNUNET_NO == old->used) ? "NO" : "YES", (GNUNET_NO == in_use) ? "NO" : "YES"); return GNUNET_SYSERR; } old->used = in_use; #if HAVE_LIBGLPK if (ats_mode == MLP) GAS_mlp_address_update (mlp, addresses, old); #endif return GNUNET_OK; } void request_address_mlp (const struct GNUNET_PeerIdentity *peer) { struct ATS_Address *aa; aa = NULL; #if HAVE_GLPK /* Get preferred address from MLP */ struct ATS_PreferedAddress * paddr = NULL; paddr = GAS_mlp_get_preferred_address (mlp, addresses, peer); aa = paddr->address; aa->assigned_bw_out = GNUNET_BANDWIDTH_value_init(paddr->bandwidth_out); /* FIXME use bw in value */ paddr->bandwidth_in = paddr->bandwidth_out; aa->assigned_bw_in = GNUNET_BANDWIDTH_value_init (paddr->bandwidth_in); GNUNET_free (paddr); #endif if (aa == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer)); return; } if (aa->active == GNUNET_NO) { aa->active = GNUNET_YES; active_addr_count++; send_bw_notification (aa); } else { /* just to be sure... */ GAS_scheduling_transmit_address_suggestion (peer, aa->plugin, aa->addr, aa->addr_len, aa->session_id, aa->ats, aa->ats_count, aa->assigned_bw_out, aa->assigned_bw_in); } } void request_address_simple (const struct GNUNET_PeerIdentity *peer) { struct ATS_Address *aa; aa = NULL; /* Get address with: stick to current address, lower distance, lower latency */ GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey, &find_address_it, &aa); if (aa == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer)); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "Suggesting address %p for peer `%s'\n", aa, GNUNET_i2s (peer)); if (aa->active == GNUNET_NO) { aa->active = GNUNET_YES; active_addr_count++; if (ats_mode == SIMPLE) { recalculate_assigned_bw (); } } else { /* just to be sure... */ GAS_scheduling_transmit_address_suggestion (peer, aa->plugin, aa->addr, aa->addr_len, aa->session_id, aa->ats, aa->ats_count, aa->assigned_bw_out, aa->assigned_bw_in); } } void GAS_addresses_request_address (const struct GNUNET_PeerIdentity *peer) { if (GNUNET_NO == running) return; if (ats_mode == SIMPLE) { request_address_simple (peer); } if (ats_mode == MLP) { request_address_mlp(peer); } } static int reset_address_it (void *cls, const GNUNET_HashCode * key, void *value) { struct ATS_Address *aa = value; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Resetting interval for peer `%s' address %p from %llu to 0\n", GNUNET_i2s (&aa->peer), aa, aa->block_interval); aa->blocked_until = GNUNET_TIME_UNIT_ZERO_ABS; aa->block_interval = GNUNET_TIME_UNIT_ZERO; return GNUNET_OK; } void GAS_addresses_handle_backoff_reset (const struct GNUNET_PeerIdentity *peer) { GNUNET_break (GNUNET_SYSERR != GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey, &reset_address_it, NULL)); } // FIXME: this function should likely end up in the LP-subsystem and // not with 'addresses' in the future... void GAS_addresses_change_preference (const struct GNUNET_PeerIdentity *peer, enum GNUNET_ATS_PreferenceKind kind, float score) { if (GNUNET_NO == running) return; #if HAVE_LIBGLPK if (ats_mode == MLP) GAS_mlp_address_change_preference (mlp, peer, kind, score); #endif } /** * Initialize address subsystem. * * @param cfg configuration to use * @param stats the statistics handle to use */ void GAS_addresses_init (const struct GNUNET_CONFIGURATION_Handle *cfg, const struct GNUNET_STATISTICS_Handle *stats) { int mode; char *quota_wan_in_str; char *quota_wan_out_str; running = GNUNET_NO; addresses = GNUNET_CONTAINER_multihashmap_create (128); GNUNET_assert (NULL != addresses); if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", "WAN_QUOTA_IN", "a_wan_in_str)) { if (0 == strcmp(quota_wan_in_str, "unlimited") || (GNUNET_SYSERR == GNUNET_STRINGS_fancy_size_to_bytes (quota_wan_in_str, &wan_quota_in))) wan_quota_in = (UINT32_MAX) /10; GNUNET_free (quota_wan_in_str); quota_wan_in_str = NULL; } else { wan_quota_in = (UINT32_MAX) /10; } if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", "WAN_QUOTA_OUT", "a_wan_out_str)) { if (0 == strcmp(quota_wan_out_str, "unlimited") || (GNUNET_SYSERR == GNUNET_STRINGS_fancy_size_to_bytes (quota_wan_out_str, &wan_quota_out))) wan_quota_out = (UINT32_MAX) /10; GNUNET_free (quota_wan_out_str); quota_wan_out_str = NULL; } else { wan_quota_out = (UINT32_MAX) /10; } mode = GNUNET_CONFIGURATION_get_value_yesno (cfg, "ats", "MLP"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MLP mode %u", mode); switch (mode) { /* MLP = YES */ case GNUNET_YES: #if HAVE_LIBGLPK ats_mode = MLP; /* Init the MLP solver with default values */ mlp = GAS_mlp_init (cfg, stats, MLP_MAX_EXEC_DURATION, MLP_MAX_ITERATIONS); if (NULL == mlp) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP mode was configured, but libglpk is not installed, switching to simple mode\n"); GNUNET_STATISTICS_update (GSA_stats, "MLP mode enabled", 0, GNUNET_NO); break; } else { GNUNET_STATISTICS_update (GSA_stats, "MLP enabled", 1, GNUNET_NO); break; } #else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP mode was configured, but libglpk is not installed, switching to simple mode"); GNUNET_STATISTICS_update (GSA_stats, "MLP enabled", 0, GNUNET_NO); ats_mode = SIMPLE; break; #endif /* MLP = NO */ case GNUNET_NO: GNUNET_STATISTICS_update (GSA_stats, "MLP enabled", 0, GNUNET_NO); ats_mode = SIMPLE; break; /* No configuration value */ case GNUNET_SYSERR: GNUNET_STATISTICS_update (GSA_stats, "MLP enabled", 0, GNUNET_NO); ats_mode = SIMPLE; break; default: break; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS started with %s mode\n", (SIMPLE == ats_mode) ? "SIMPLE" : "MLP"); running = GNUNET_YES; } /** * Free memory of address. * * @param cls NULL * @param key peer identity (unused) * @param value the 'struct ATS_Address' to free * @return GNUNET_OK (continue to iterate) */ static int free_address_it (void *cls, const GNUNET_HashCode * key, void *value) { struct ATS_Address *aa = value; destroy_address (aa); return GNUNET_OK; } void GAS_addresses_destroy_all () { if (GNUNET_NO == running) return; if (addresses != NULL) GNUNET_CONTAINER_multihashmap_iterate (addresses, &free_address_it, NULL); GNUNET_assert (active_addr_count == 0); } /** * Shutdown address subsystem. */ void GAS_addresses_done () { GAS_addresses_destroy_all (); running = GNUNET_NO; GNUNET_CONTAINER_multihashmap_destroy (addresses); addresses = NULL; #if HAVE_LIBGLPK if (ats_mode == MLP) { GAS_mlp_done (mlp); } #endif } /* end of gnunet-service-ats_addresses.c */ gnunet-0.9.3/src/ats/ats.h0000644000175000017500000001156611760502551012275 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file ats/ats.h * @brief automatic transport selection messages * @author Christian Grothoff * @author Matthias Wachs */ #ifndef ATS_H #define ATS_H #include "gnunet_util_lib.h" enum StartFlag { START_FLAG_SCHEDULING = 0, START_FLAG_PERFORMANCE_WITH_PIC = 1, START_FLAG_PERFORMANCE_NO_PIC = 2 }; GNUNET_NETWORK_STRUCT_BEGIN struct ClientStartMessage { struct GNUNET_MessageHeader header; /** * NBO value of an 'enum StartFlag'. */ uint32_t start_flag GNUNET_PACKED; }; struct RequestAddressMessage { struct GNUNET_MessageHeader header; uint32_t reserved GNUNET_PACKED; struct GNUNET_PeerIdentity peer; }; struct ResetBackoffMessage { struct GNUNET_MessageHeader header; uint32_t reserved GNUNET_PACKED; struct GNUNET_PeerIdentity peer; }; struct AddressUpdateMessage { struct GNUNET_MessageHeader header; uint32_t ats_count GNUNET_PACKED; struct GNUNET_PeerIdentity peer; uint16_t address_length GNUNET_PACKED; uint16_t plugin_name_length GNUNET_PACKED; uint32_t session_id GNUNET_PACKED; /* followed by: * - struct GNUNET_ATS_Information [ats_count]; * - char address[address_length] * - char plugin_name[plugin_name_length] (including '\0'-termination). */ }; struct AddressUseMessage { struct GNUNET_MessageHeader header; struct GNUNET_PeerIdentity peer; uint16_t in_use GNUNET_PACKED; uint16_t address_length GNUNET_PACKED; uint16_t plugin_name_length GNUNET_PACKED; uint32_t session_id GNUNET_PACKED; /* followed by: * - char address[address_length] * - char plugin_name[plugin_name_length] (including '\0'-termination). */ }; struct AddressDestroyedMessage { struct GNUNET_MessageHeader header; uint32_t reserved GNUNET_PACKED; struct GNUNET_PeerIdentity peer; uint16_t address_length GNUNET_PACKED; uint16_t plugin_name_length GNUNET_PACKED; uint32_t session_id GNUNET_PACKED; /* followed by: * - char address[address_length] * - char plugin_name[plugin_name_length] (including '\0'-termination). */ }; struct AddressSuggestionMessage { struct GNUNET_MessageHeader header; uint32_t ats_count GNUNET_PACKED; struct GNUNET_PeerIdentity peer; uint16_t address_length GNUNET_PACKED; uint16_t plugin_name_length GNUNET_PACKED; uint32_t session_id GNUNET_PACKED; struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out; struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in; /* followed by: * - struct GNUNET_ATS_Information [ats_count]; * - char address[address_length] * - char plugin_name[plugin_name_length] (including '\0'-termination). */ }; struct PeerInformationMessage { struct GNUNET_MessageHeader header; uint32_t ats_count GNUNET_PACKED; struct GNUNET_PeerIdentity peer; uint16_t address_length GNUNET_PACKED; uint16_t plugin_name_length GNUNET_PACKED; struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out; struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in; /* followed by: * - struct GNUNET_ATS_Information [ats_count]; * - char address[address_length] * - char plugin_name[plugin_name_length] (including '\0'-termination). */ }; struct ReservationRequestMessage { struct GNUNET_MessageHeader header; int32_t amount GNUNET_PACKED; struct GNUNET_PeerIdentity peer; }; /** * Message sent by ATS service to client to confirm that it is done * using the given session ID. */ struct SessionReleaseMessage { struct GNUNET_MessageHeader header; uint32_t session_id GNUNET_PACKED; struct GNUNET_PeerIdentity peer; }; struct ReservationResultMessage { struct GNUNET_MessageHeader header; int32_t amount GNUNET_PACKED; struct GNUNET_PeerIdentity peer; struct GNUNET_TIME_RelativeNBO res_delay; }; struct PreferenceInformation { uint32_t preference_kind GNUNET_PACKED; float preference_value GNUNET_PACKED; }; struct ChangePreferenceMessage { struct GNUNET_MessageHeader header; uint32_t num_preferences GNUNET_PACKED; struct GNUNET_PeerIdentity peer; /* followed by 'num_preferences' * struct PreferenceInformation values */ }; GNUNET_NETWORK_STRUCT_END #endif gnunet-0.9.3/src/ats/gnunet-service-ats_addresses.h0000644000175000017500000001011511760502551017253 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file ats/gnunet-service-ats_addresses.h * @brief ats service address management * @author Matthias Wachs * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_ATS_ADDRESSES_H #define GNUNET_SERVICE_ATS_ADDRESSES_H #include "gnunet_util_lib.h" #include "gnunet_ats_service.h" #include "gnunet_statistics_service.h" #include "ats.h" struct ATS_Address { struct ATS_Address *next; struct ATS_Address *prev; struct GNUNET_PeerIdentity peer; size_t addr_len; uint32_t session_id; uint32_t ats_count; const void *addr; char *plugin; void *mlp_information; struct GNUNET_ATS_Information *ats; struct GNUNET_TIME_Relative atsp_latency; struct GNUNET_BANDWIDTH_Value32NBO atsp_utilization_in; struct GNUNET_BANDWIDTH_Value32NBO atsp_utilization_out; uint32_t atsp_distance; uint32_t atsp_cost_wan; uint32_t atsp_cost_lan; uint32_t atsp_cost_wlan; uint32_t atsp_network_type; struct GNUNET_BANDWIDTH_Value32NBO assigned_bw_in; struct GNUNET_BANDWIDTH_Value32NBO assigned_bw_out; /** * Blocking interval */ struct GNUNET_TIME_Relative block_interval; /** * Time when address can be suggested again */ struct GNUNET_TIME_Absolute blocked_until; /** * Is this the active address for this peer? */ int active; /** * Is this the address for this peer in use? */ int used; }; /** * Initialize address subsystem. * * @param cfg configuration to use * @param stats the statistics handle to use */ void GAS_addresses_init (const struct GNUNET_CONFIGURATION_Handle *cfg, const struct GNUNET_STATISTICS_Handle *stats); /** * Shutdown address subsystem. */ void GAS_addresses_done (void); void GAS_addresses_handle_backoff_reset (const struct GNUNET_PeerIdentity *peer); /** * This address is now used or not used anymore */ int GAS_addresses_in_use (const struct GNUNET_PeerIdentity *peer, const char *plugin_name, const void *plugin_addr, size_t plugin_addr_len, uint32_t session_id, int in_use); void GAS_addresses_update (const struct GNUNET_PeerIdentity *peer, const char *plugin_name, const void *plugin_addr, size_t plugin_addr_len, uint32_t session_id, const struct GNUNET_ATS_Information *atsi, uint32_t atsi_count); void GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer, const char *plugin_name, const void *plugin_addr, size_t plugin_addr_len, uint32_t session_id); void GAS_addresses_destroy_all (void); // FIXME: this function should likely end up in the LP-subsystem and // not with 'addresses' in the future... // Note: this call should trigger an address suggestion // (GAS_scheduling_transmit_address_suggestion) void GAS_addresses_request_address (const struct GNUNET_PeerIdentity *peer); // FIXME: this function should likely end up in the LP-subsystem and // not with 'addresses' in the future... void GAS_addresses_change_preference (const struct GNUNET_PeerIdentity *peer, enum GNUNET_ATS_PreferenceKind kind, float score); /* FIXME: add performance request API */ #endif /* end of gnunet-service-ats_addresses.h */ gnunet-0.9.3/src/ats/gnunet-service-ats_scheduling.h0000644000175000017500000001223211760502551017425 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file ats/gnunet-service-ats_scheduling.h * @brief ats service, interaction with 'scheduling' API * @author Matthias Wachs * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_ATS_SCHEDULING_H #define GNUNET_SERVICE_ATS_SCHEDULING_H #include "gnunet_util_lib.h" /** * Register a new scheduling client. * * @param client handle of the new client * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GAS_scheduling_add_client (struct GNUNET_SERVER_Client *client); /** * Unregister a client (which may have been a scheduling client, * but this is not assured). * * @param client handle of the (now dead) client */ void GAS_scheduling_remove_client (struct GNUNET_SERVER_Client *client); /** * Handle 'reset backoff' messages from clients. * * @param cls unused, NULL * @param client client that sent the request * @param message the request message */ void GAS_handle_reset_backoff (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message); /** * Transmit the given address suggestion and bandwidth update to all scheduling * clients. * * @param peer peer for which this is an address suggestion * @param plugin_name 0-termintated string specifying the transport plugin * @param plugin_addr binary address for the plugin to use * @param plugin_addr_len number of bytes in plugin_addr * @param session_id session ID to use * @param atsi performance data for the address * @param atsi_count number of performance records in 'ats' * @param bandwidth_out assigned outbound bandwidth * @param bandwidth_in assigned inbound bandwidth */ void GAS_scheduling_transmit_address_suggestion (const struct GNUNET_PeerIdentity *peer, const char *plugin_name, const void *plugin_addr, size_t plugin_addr_len, uint32_t session_id, const struct GNUNET_ATS_Information *atsi, uint32_t atsi_count, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in); /** * Handle 'request address' messages from clients. * * @param cls unused, NULL * @param client client that sent the request * @param message the request message */ void GAS_handle_request_address (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message); /** * Cancel 'request address' messages from clients. * * @param cls unused, NULL * @param client client that sent the request * @param message the request message */ void GAS_handle_request_address_cancel (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message); /** * Handle 'address update' messages from clients. * * @param cls unused, NULL * @param client client that sent the request * @param message the request message */ void GAS_handle_address_update (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message); /** * Handle 'address in use' messages from clients. * * @param cls unused, NULL * @param client client that sent the request * @param message the request message */ void GAS_handle_address_in_use (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message); /** * Handle 'address destroyed' messages from clients. * * @param cls unused, NULL * @param client client that sent the request * @param message the request message */ void GAS_handle_address_destroyed (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message); /** * Initialize scheduling subsystem. * * @param server handle to our server */ void GAS_scheduling_init (struct GNUNET_SERVER_Handle *server); /** * Shutdown scheduling subsystem. */ void GAS_scheduling_done (void); #endif /* end of gnunet-service-ats_scheduling.h */ gnunet-0.9.3/src/ats/gnunet-service-ats_performance.c0000644000175000017500000002265211760502551017603 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file ats/gnunet-service-ats_performance.c * @brief ats service, interaction with 'performance' API * @author Matthias Wachs * @author Christian Grothoff */ #include "platform.h" #include "gnunet-service-ats.h" #include "gnunet-service-ats_addresses.h" #include "gnunet-service-ats_performance.h" #include "gnunet-service-ats_reservations.h" #include "ats.h" /** * We keep clients that are interested in performance in a linked list. */ struct PerformanceClient { /** * Next in doubly-linked list. */ struct PerformanceClient *next; /** * Previous in doubly-linked list. */ struct PerformanceClient *prev; /** * Actual handle to the client. */ struct GNUNET_SERVER_Client *client; /** * Options for the client. */ enum StartFlag flag; }; /** * Head of linked list of all clients to this service. */ static struct PerformanceClient *pc_head; /** * Tail of linked list of all clients to this service. */ static struct PerformanceClient *pc_tail; /** * Context for sending messages to performance clients. */ static struct GNUNET_SERVER_NotificationContext *nc; /** * Find the performance client associated with the given handle. * * @param client server handle * @return internal handle */ static struct PerformanceClient * find_client (struct GNUNET_SERVER_Client *client) { struct PerformanceClient *pc; for (pc = pc_head; pc != NULL; pc = pc->next) if (pc->client == client) return pc; return NULL; } /** * Register a new performance client. * * @param client handle of the new client * @param flag flag specifying the type of the client */ void GAS_performance_add_client (struct GNUNET_SERVER_Client *client, enum StartFlag flag) { struct PerformanceClient *pc; GNUNET_break (NULL == find_client (client)); pc = GNUNET_malloc (sizeof (struct PerformanceClient)); pc->client = client; pc->flag = flag; GNUNET_SERVER_notification_context_add (nc, client); GNUNET_SERVER_client_keep (client); GNUNET_CONTAINER_DLL_insert (pc_head, pc_tail, pc); } /** * Unregister a client (which may have been a performance client, * but this is not assured). * * @param client handle of the (now dead) client */ void GAS_performance_remove_client (struct GNUNET_SERVER_Client *client) { struct PerformanceClient *pc; pc = find_client (client); if (NULL == pc) return; GNUNET_CONTAINER_DLL_remove (pc_head, pc_tail, pc); GNUNET_SERVER_client_drop (client); GNUNET_free (pc); } /** * Transmit the given performance information to all performance * clients. * * @param peer peer for which this is an address suggestion * @param plugin_name 0-termintated string specifying the transport plugin * @param plugin_addr binary address for the plugin to use * @param plugin_addr_len number of bytes in plugin_addr * @param atsi performance data for the address * @param atsi_count number of performance records in 'ats' * @param bandwidth_out assigned outbound bandwidth * @param bandwidth_in assigned inbound bandwidth */ void GAS_performance_notify_clients (const struct GNUNET_PeerIdentity *peer, const char *plugin_name, const void *plugin_addr, size_t plugin_addr_len, const struct GNUNET_ATS_Information *atsi, uint32_t atsi_count, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in) { struct PerformanceClient *pc; struct PeerInformationMessage *msg; size_t plugin_name_length = strlen (plugin_name) + 1; size_t msize = sizeof (struct PeerInformationMessage) + atsi_count * sizeof (struct GNUNET_ATS_Information) + plugin_addr_len + plugin_name_length; char buf[msize] GNUNET_ALIGN; struct GNUNET_ATS_Information *atsp; char *addrp; GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE); GNUNET_assert (atsi_count < GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information)); msg = (struct PeerInformationMessage *) buf; msg->header.size = htons (msize); msg->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_PEER_INFORMATION); msg->ats_count = htonl (atsi_count); msg->peer = *peer; msg->address_length = htons (plugin_addr_len); msg->plugin_name_length = htons (plugin_name_length); msg->bandwidth_out = bandwidth_out; msg->bandwidth_in = bandwidth_in; atsp = (struct GNUNET_ATS_Information *) &msg[1]; memcpy (atsp, atsi, sizeof (struct GNUNET_ATS_Information) * atsi_count); addrp = (char *) &atsp[atsi_count]; memcpy (addrp, plugin_addr, plugin_addr_len); strcpy (&addrp[plugin_addr_len], plugin_name); for (pc = pc_head; pc != NULL; pc = pc->next) if (pc->flag == START_FLAG_PERFORMANCE_WITH_PIC) { GNUNET_SERVER_notification_context_unicast (nc, pc->client, &msg->header, GNUNET_YES); GNUNET_STATISTICS_update (GSA_stats, "# performance updates given to clients", 1, GNUNET_NO); } } /** * Handle 'reservation request' messages from clients. * * @param cls unused, NULL * @param client client that sent the request * @param message the request message */ void GAS_handle_reservation_request (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct ReservationRequestMessage *msg = (const struct ReservationRequestMessage *) message; struct ReservationResultMessage result; int32_t amount; struct GNUNET_TIME_Relative res_delay; if (NULL == find_client (client)) { /* missing start message! */ GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "RESERVATION_REQUEST"); amount = (int32_t) ntohl (msg->amount); res_delay = GAS_reservations_reserve (&msg->peer, amount); if (res_delay.rel_value > 0) amount = 0; result.header.size = htons (sizeof (struct ReservationResultMessage)); result.header.type = htons (GNUNET_MESSAGE_TYPE_ATS_RESERVATION_RESULT); result.amount = htonl (amount); result.peer = msg->peer; result.res_delay = GNUNET_TIME_relative_hton (res_delay); GNUNET_STATISTICS_update (GSA_stats, "# reservation requests processed", 1, GNUNET_NO); GNUNET_SERVER_notification_context_unicast (nc, client, &result.header, GNUNET_NO); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Handle 'preference change' messages from clients. * * @param cls unused, NULL * @param client client that sent the request * @param message the request message */ void GAS_handle_preference_change (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct ChangePreferenceMessage *msg; const struct PreferenceInformation *pi; uint16_t msize; uint32_t nump; uint32_t i; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "PREFERENCE_CHANGE"); msize = ntohs (message->size); if (msize < sizeof (struct ChangePreferenceMessage)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } msg = (const struct ChangePreferenceMessage *) message; nump = ntohl (msg->num_preferences); if (msize != sizeof (struct ChangePreferenceMessage) + nump * sizeof (struct PreferenceInformation)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_STATISTICS_update (GSA_stats, "# preference change requests processed", 1, GNUNET_NO); pi = (const struct PreferenceInformation *) &msg[1]; for (i = 0; i < nump; i++) GAS_addresses_change_preference (&msg->peer, (enum GNUNET_ATS_PreferenceKind) ntohl (pi[i].preference_kind), pi[i].preference_value); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Initialize performance subsystem. * * @param server handle to our server */ void GAS_performance_init (struct GNUNET_SERVER_Handle *server) { nc = GNUNET_SERVER_notification_context_create (server, 128); } /** * Shutdown performance subsystem. */ void GAS_performance_done () { GNUNET_SERVER_notification_context_destroy (nc); nc = NULL; } /* end of gnunet-service-ats_performance.c */ gnunet-0.9.3/src/ats/test_ats_api_scheduling.c0000644000175000017500000001547511760502551016370 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file ats/test_ats_api_scheduling.c * @brief test automatic transport selection scheduling API * @author Christian Grothoff * @author Matthias Wachs * * TODO: * - write test case * - extend API to get performance data * - implement simplistic strategy based on say 'lowest latency' or strict ordering * - extend API to get peer preferences, implement proportional bandwidth assignment * - re-implement API against a real ATS service (!) */ #include "platform.h" #include "gnunet_ats_service.h" #include "ats.h" #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) static GNUNET_SCHEDULER_TaskIdentifier die_task; static struct GNUNET_ATS_SchedulingHandle *ats; struct GNUNET_OS_Process *arm_proc; static int ret; struct Address { char *plugin; size_t plugin_len; void *addr; size_t addr_len; struct GNUNET_ATS_Information *ats; int ats_count; void *session; }; struct PeerContext { struct GNUNET_PeerIdentity id; struct Address *addr; }; struct Address addr[2]; struct PeerContext p[2]; struct GNUNET_ATS_Information atsi[2]; static void stop_arm () { if (0 != GNUNET_OS_process_kill (arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); GNUNET_OS_process_wait (arm_proc); GNUNET_OS_process_destroy (arm_proc); arm_proc = NULL; } static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { die_task = GNUNET_SCHEDULER_NO_TASK; if (ats != NULL) GNUNET_ATS_scheduling_done (ats); ret = GNUNET_SYSERR; stop_arm (); } static void end () { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutting down\n"); if (die_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_ATS_scheduling_done (ats); ret = 0; stop_arm (); } static void address_suggest_cb (void *cls, const struct GNUNET_HELLO_Address *address, struct Session *session, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS suggests address `%s'\n", GNUNET_i2s (&address->peer)); GNUNET_assert (0 == memcmp (&address->peer, &p[0].id, sizeof (struct GNUNET_PeerIdentity))); GNUNET_assert (0 == strcmp (address->transport_name, addr[0].plugin)); GNUNET_assert (address->address_length == addr[0].addr_len); GNUNET_assert (0 == memcmp (address->address, addr[0].plugin, address->address_length)); GNUNET_assert (addr[0].session == session); /* TODO ats merge * GNUNET_assert (ats_count == 2); * GNUNET_assert (atsi[0].type == htons (1)); * GNUNET_assert (atsi[0].type == htons (2)); * GNUNET_assert (atsi[1].type == htons (2)); * GNUNET_assert (atsi[1].type == htons (2)); */ ret = 0; GNUNET_SCHEDULER_add_now (&end, NULL); } void start_arm (const char *cfgname) { arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, NULL); } static void check (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_HELLO_Address address0; ret = GNUNET_SYSERR; die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); start_arm (cfgfile); ats = GNUNET_ATS_scheduling_init (cfg, &address_suggest_cb, NULL); if (ats == NULL) { ret = GNUNET_SYSERR; end (); return; } /* set up peer */ GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &p[0].id.hashPubKey); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created peer `%s'\n", GNUNET_i2s (&p[0].id)); GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &p[1].id.hashPubKey); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created peer `%s'\n", GNUNET_i2s (&p[1].id)); addr[0].plugin = "test"; addr[0].session = NULL; addr[0].addr = GNUNET_strdup ("test"); addr[0].addr_len = 4; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing address creation\n"); address0.peer = p[0].id; address0.transport_name = addr[0].plugin; address0.address = addr[0].addr; address0.address_length = addr[0].addr_len; GNUNET_ATS_address_update (ats, &address0, addr[0].session, NULL, 0); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing ATS info creation\n"); atsi[0].type = htonl (GNUNET_ATS_UTILIZATION_UP); atsi[0].value = htonl (1024); GNUNET_ATS_address_update (ats, &address0, addr[0].session, atsi, 1); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing ATS info update\n"); atsi[0].type = htonl (GNUNET_ATS_UTILIZATION_UP); atsi[0].value = htonl (2048); atsi[1].type = htonl (GNUNET_ATS_UTILIZATION_DOWN); atsi[1].value = htonl (1024); GNUNET_ATS_address_update (ats, &address0, addr[0].session, atsi, 2); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing manual address deletion \n"); address0.peer = p[1].id; // FIXME: why? typo in old code? GNUNET_ATS_address_update (ats, &address0, addr[0].session, NULL, 0); GNUNET_ATS_address_destroyed (ats, &address0, addr[0].session); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Requesting peer `%s'\n", GNUNET_i2s (&p[0].id)); GNUNET_ATS_suggest_address (ats, &p[0].id); } int main (int argc, char *argv[]) { static char *const argv2[] = { "test_ats_api_scheduling", "-c", "test_ats_api.conf", "-L", "WARNING", NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, "test_ats_api_scheduling", "nohelp", options, &check, NULL); return ret; } /* end of file test_ats_api_scheduling.c */ gnunet-0.9.3/src/ats/test_ats_mlp_averaging.c0000644000175000017500000001233711760502551016217 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file ats/test_ats_mlp.c * @brief test for the MLP solver * @author Christian Grothoff * @author Matthias Wachs */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_statistics_service.h" #include "gnunet_ats_service.h" #include "gnunet-service-ats_addresses_mlp.h" #define MLP_MAX_EXEC_DURATION GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3) #define MLP_MAX_ITERATIONS INT_MAX static int ret; struct GNUNET_STATISTICS_Handle * stats; struct GNUNET_CONTAINER_MultiHashMap * addresses; struct GAS_MLP_Handle *mlp; static void create_address (struct ATS_Address *addr, char * plugin, int ats_count, struct GNUNET_ATS_Information *ats) { addr->mlp_information = NULL; addr->next = NULL; addr->prev = NULL; addr->plugin = GNUNET_strdup (plugin); addr->ats_count = ats_count; addr->ats = ats; } static void set_ats (struct GNUNET_ATS_Information *ats, uint32_t type, uint32_t value) { ats->type = type; ats->value = value; } static void check (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { #if !HAVE_LIBGLPK GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GLPK not installed!"); ret = 1; return; #endif struct ATS_Address addr[10]; struct ATS_PreferedAddress *res[10]; struct MLP_information *mlpi; struct GAS_MLP_SolutionContext ctx; stats = GNUNET_STATISTICS_create("ats", cfg); addresses = GNUNET_CONTAINER_multihashmap_create (10); mlp = GAS_mlp_init (cfg, NULL, MLP_MAX_EXEC_DURATION, MLP_MAX_ITERATIONS); mlp->auto_solve = GNUNET_NO; struct GNUNET_PeerIdentity p[10]; /* Creating peer 1 */ GNUNET_CRYPTO_hash_create_random(GNUNET_CRYPTO_QUALITY_WEAK, &p[0].hashPubKey); /* Creating peer 1 address 1 */ addr[0].peer.hashPubKey = p[0].hashPubKey; struct GNUNET_ATS_Information a1_ats[3]; set_ats (&a1_ats[0], GNUNET_ATS_QUALITY_NET_DISTANCE, 1); set_ats (&a1_ats[1], GNUNET_ATS_QUALITY_NET_DELAY, 0); set_ats (&a1_ats[2], GNUNET_ATS_ARRAY_TERMINATOR, 0); create_address (&addr[0], "dummy", 3, &a1_ats[0]); addr[0].atsp_network_type = GNUNET_ATS_NET_LAN; GNUNET_CONTAINER_multihashmap_put(addresses, &addr[0].peer.hashPubKey, &addr[0], GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); /* Add peer 1 address 1 */ GAS_mlp_address_update (mlp, addresses, &addr[0]); mlpi = addr[0].mlp_information; GNUNET_assert (mlp != NULL); GNUNET_assert (mlp->addr_in_problem == 1); /* Update an peer 1 address 1 */ set_ats (&a1_ats[1], GNUNET_ATS_QUALITY_NET_DELAY, 20); GAS_mlp_address_update (mlp, addresses, &addr[0]); GNUNET_assert (mlp->addr_in_problem == 1); /* Update an peer 1 address 1 */ set_ats (&a1_ats[1], GNUNET_ATS_QUALITY_NET_DELAY, 10); GAS_mlp_address_update (mlp, addresses, &addr[0]); GNUNET_assert (mlp->addr_in_problem == 1); /* Update an peer 1 address 1 */ set_ats (&a1_ats[1], GNUNET_ATS_QUALITY_NET_DELAY, 10); GAS_mlp_address_update (mlp, addresses, &addr[0]); GNUNET_assert (mlp->addr_in_problem == 1); /* Update an peer 1 address 1 */ set_ats (&a1_ats[1], GNUNET_ATS_QUALITY_NET_DELAY, 30); GAS_mlp_address_update (mlp, addresses, &addr[0]); GNUNET_assert (mlp->addr_in_problem == 1); GNUNET_assert (GNUNET_OK == GAS_mlp_solve_problem(mlp, &ctx)); GNUNET_assert (GNUNET_OK == ctx.lp_result); GNUNET_assert (GNUNET_OK == ctx.mlp_result); res[0] = GAS_mlp_get_preferred_address(mlp, addresses, &p[0]); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Preferred address `%s' outbound bandwidth: %u Bps\n",res[0]->address->plugin, res[0]->bandwidth_out); GNUNET_free (res[0]); /* Delete an address */ GNUNET_CONTAINER_multihashmap_remove (addresses, &addr[0].peer.hashPubKey, &addr[0]); GAS_mlp_address_delete (mlp, addresses, &addr[0]); GNUNET_assert (mlp->addr_in_problem == 0); GAS_mlp_done (mlp); GNUNET_free (addr[0].plugin); GNUNET_CONTAINER_multihashmap_destroy (addresses); GNUNET_STATISTICS_destroy(stats, GNUNET_NO); ret = 0; return; } int main (int argc, char *argv[]) { static char *const argv2[] = { "test_ats_mlp", "-c", "test_ats_api.conf", "-L", "WARNING", NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, "test_ats_mlp", "nohelp", options, &check, NULL); return ret; } /* end of file test_ats_api_bandwidth_consumption.c */ gnunet-0.9.3/src/ats/ats_api_performance.c0000644000175000017500000004142311760502551015475 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file ats/ats_api_performance.c * @brief automatic transport selection and outbound bandwidth determination * @author Christian Grothoff * @author Matthias Wachs */ #include "platform.h" #include "gnunet_ats_service.h" #include "ats.h" /** * Message in linked list we should send to the ATS service. The * actual binary message follows this struct. */ struct PendingMessage { /** * Kept in a DLL. */ struct PendingMessage *next; /** * Kept in a DLL. */ struct PendingMessage *prev; /** * Size of the message. */ size_t size; /** * Is this the 'ATS_START' message? */ int is_init; }; /** * Linked list of pending reservations. */ struct GNUNET_ATS_ReservationContext { /** * Kept in a DLL. */ struct GNUNET_ATS_ReservationContext *next; /** * Kept in a DLL. */ struct GNUNET_ATS_ReservationContext *prev; /** * Target peer. */ struct GNUNET_PeerIdentity peer; /** * Desired reservation */ int32_t size; /** * Function to call on result. */ GNUNET_ATS_ReservationCallback rcb; /** * Closure for 'rcb' */ void *rcb_cls; /** * Do we need to undo this reservation if it succeeded? Set to * GNUNET_YES if a reservation is cancelled. (at that point, 'info' * is also set to NULL; however, info will ALSO be NULL for the * reservation context that is created to undo the original request, * so 'info' being NULL cannot be used to check if undo is * required). */ int undo; }; /** * ATS Handle to obtain and/or modify performance information. */ struct GNUNET_ATS_PerformanceHandle { /** * Our configuration. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Callback to invoke on performance changes. */ GNUNET_ATS_PeerInformationCallback infocb; /** * Closure for 'infocb'. */ void *infocb_cls; /** * Connection to ATS service. */ struct GNUNET_CLIENT_Connection *client; /** * Head of list of messages for the ATS service. */ struct PendingMessage *pending_head; /** * Tail of list of messages for the ATS service */ struct PendingMessage *pending_tail; /** * Head of linked list of pending reservation requests. */ struct GNUNET_ATS_ReservationContext *reservation_head; /** * Tail of linked list of pending reservation requests. */ struct GNUNET_ATS_ReservationContext *reservation_tail; /** * Current request for transmission to ATS. */ struct GNUNET_CLIENT_TransmitHandle *th; /** * Task to trigger reconnect. */ GNUNET_SCHEDULER_TaskIdentifier task; }; /** * Re-establish the connection to the ATS service. * * @param ph handle to use to re-connect. */ static void reconnect (struct GNUNET_ATS_PerformanceHandle *ph); /** * Re-establish the connection to the ATS service. * * @param cls handle to use to re-connect. * @param tc scheduler context */ static void reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_ATS_PerformanceHandle *ph = cls; ph->task = GNUNET_SCHEDULER_NO_TASK; reconnect (ph); } /** * Transmit messages from the message queue to the service * (if there are any, and if we are not already trying). * * @param ph handle to use */ static void do_transmit (struct GNUNET_ATS_PerformanceHandle *ph); /** * We can now transmit a message to ATS. Do it. * * @param cls the 'struct GNUNET_ATS_SchedulingHandle' * @param size number of bytes we can transmit to ATS * @param buf where to copy the messages * @return number of bytes copied into buf */ static size_t transmit_message_to_ats (void *cls, size_t size, void *buf) { struct GNUNET_ATS_PerformanceHandle *ph = cls; struct PendingMessage *p; size_t ret; char *cbuf; ph->th = NULL; ret = 0; cbuf = buf; while ((NULL != (p = ph->pending_head)) && (p->size <= size)) { memcpy (&cbuf[ret], &p[1], p->size); ret += p->size; size -= p->size; GNUNET_CONTAINER_DLL_remove (ph->pending_head, ph->pending_tail, p); GNUNET_free (p); } do_transmit (ph); return ret; } /** * Transmit messages from the message queue to the service * (if there are any, and if we are not already trying). * * @param ph handle to use */ static void do_transmit (struct GNUNET_ATS_PerformanceHandle *ph) { struct PendingMessage *p; if (NULL != ph->th) return; if (NULL == (p = ph->pending_head)) return; if (NULL == ph->client) return; /* currently reconnecting */ ph->th = GNUNET_CLIENT_notify_transmit_ready (ph->client, p->size, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &transmit_message_to_ats, ph); } /** * We received a peer information message. Validate and process it. * * @param ph our context with the callback * @param msg the message * @return GNUNET_OK if the message was well-formed */ static int process_pi_message (struct GNUNET_ATS_PerformanceHandle *ph, const struct GNUNET_MessageHeader *msg) { const struct PeerInformationMessage *pi; const struct GNUNET_ATS_Information *atsi; const char *plugin_address; const char *plugin_name; struct GNUNET_HELLO_Address address; uint16_t plugin_address_length; uint16_t plugin_name_length; uint32_t ats_count; if (ph->infocb == NULL) { GNUNET_break (0); return GNUNET_SYSERR; } if (ntohs (msg->size) < sizeof (struct PeerInformationMessage)) { GNUNET_break (0); return GNUNET_SYSERR; } pi = (const struct PeerInformationMessage *) msg; ats_count = ntohl (pi->ats_count); plugin_address_length = ntohs (pi->address_length); plugin_name_length = ntohs (pi->plugin_name_length); atsi = (const struct GNUNET_ATS_Information *) &pi[1]; plugin_address = (const char *) &atsi[ats_count]; plugin_name = &plugin_address[plugin_address_length]; if ((plugin_address_length + plugin_name_length + ats_count * sizeof (struct GNUNET_ATS_Information) + sizeof (struct PeerInformationMessage) != ntohs (msg->size)) || (ats_count > GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information)) || (plugin_name[plugin_name_length - 1] != '\0')) { GNUNET_break (0); return GNUNET_SYSERR; } address.peer = pi->peer; address.address = plugin_address; address.address_length = plugin_address_length; address.transport_name = plugin_name; ph->infocb (ph->infocb_cls, &address, pi->bandwidth_out, pi->bandwidth_in, atsi, ats_count); return GNUNET_OK; } /** * We received a reservation result message. Validate and process it. * * @param ph our context with the callback * @param msg the message * @return GNUNET_OK if the message was well-formed */ static int process_rr_message (struct GNUNET_ATS_PerformanceHandle *ph, const struct GNUNET_MessageHeader *msg) { const struct ReservationResultMessage *rr; struct GNUNET_ATS_ReservationContext *rc; int32_t amount; if (ntohs (msg->size) < sizeof (struct ReservationResultMessage)) { GNUNET_break (0); return GNUNET_SYSERR; } rr = (const struct ReservationResultMessage *) msg; amount = ntohl (rr->amount); rc = ph->reservation_head; if (0 != memcmp (&rr->peer, &rc->peer, sizeof (struct GNUNET_PeerIdentity))) { GNUNET_break (0); return GNUNET_SYSERR; } GNUNET_CONTAINER_DLL_remove (ph->reservation_head, ph->reservation_tail, rc); if ((amount == 0) || (rc->rcb != NULL)) { /* tell client if not cancelled */ if (rc->rcb != NULL) rc->rcb (rc->rcb_cls, &rr->peer, amount, GNUNET_TIME_relative_ntoh (rr->res_delay)); GNUNET_free (rc); return GNUNET_OK; } /* amount non-zero, but client cancelled, consider undo! */ if (GNUNET_YES != rc->undo) { GNUNET_free (rc); return GNUNET_OK; /* do not try to undo failed undos or negative amounts */ } GNUNET_free (rc); (void) GNUNET_ATS_reserve_bandwidth (ph, &rr->peer, -amount, NULL, NULL); return GNUNET_OK; } /** * Type of a function to call when we receive a message * from the service. * * @param cls the 'struct GNUNET_ATS_SchedulingHandle' * @param msg message received, NULL on timeout or fatal error */ static void process_ats_message (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_ATS_PerformanceHandle *ph = cls; if (NULL == msg) goto reconnect; switch (ntohs (msg->type)) { case GNUNET_MESSAGE_TYPE_ATS_PEER_INFORMATION: if (GNUNET_OK != process_pi_message (ph, msg)) goto reconnect; break; case GNUNET_MESSAGE_TYPE_ATS_RESERVATION_RESULT: if (GNUNET_OK != process_rr_message (ph, msg)) goto reconnect; break; default: GNUNET_break (0); goto reconnect; } GNUNET_CLIENT_receive (ph->client, &process_ats_message, ph, GNUNET_TIME_UNIT_FOREVER_REL); return; reconnect: GNUNET_CLIENT_disconnect (ph->client); ph->client = NULL; ph->task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task, ph); } /** * Re-establish the connection to the ATS service. * * @param ph handle to use to re-connect. */ static void reconnect (struct GNUNET_ATS_PerformanceHandle *ph) { struct PendingMessage *p; struct ClientStartMessage *init; GNUNET_assert (NULL == ph->client); ph->client = GNUNET_CLIENT_connect ("ats", ph->cfg); GNUNET_assert (NULL != ph->client); GNUNET_CLIENT_receive (ph->client, &process_ats_message, ph, GNUNET_TIME_UNIT_FOREVER_REL); if ((NULL == (p = ph->pending_head)) || (GNUNET_YES != p->is_init)) { p = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (struct ClientStartMessage)); p->size = sizeof (struct ClientStartMessage); p->is_init = GNUNET_YES; init = (struct ClientStartMessage *) &p[1]; init->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_START); init->header.size = htons (sizeof (struct ClientStartMessage)); init->start_flag = htonl ((ph->infocb == NULL) ? START_FLAG_PERFORMANCE_NO_PIC : START_FLAG_PERFORMANCE_WITH_PIC); GNUNET_CONTAINER_DLL_insert (ph->pending_head, ph->pending_tail, p); } do_transmit (ph); } /** * Get handle to access performance API of the ATS subsystem. * * @param cfg configuration to use * @param infocb function to call on allocation changes, can be NULL * @param infocb_cls closure for infocb * @return ats performance context */ struct GNUNET_ATS_PerformanceHandle * GNUNET_ATS_performance_init (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_ATS_PeerInformationCallback infocb, void *infocb_cls) { struct GNUNET_ATS_PerformanceHandle *ph; ph = GNUNET_malloc (sizeof (struct GNUNET_ATS_PerformanceHandle)); ph->cfg = cfg; ph->infocb = infocb; ph->infocb_cls = infocb_cls; reconnect (ph); return ph; } /** * Client is done using the ATS performance subsystem, release resources. * * @param ph handle */ void GNUNET_ATS_performance_done (struct GNUNET_ATS_PerformanceHandle *ph) { struct PendingMessage *p; struct GNUNET_ATS_ReservationContext *rc; while (NULL != (p = ph->pending_head)) { GNUNET_CONTAINER_DLL_remove (ph->pending_head, ph->pending_tail, p); GNUNET_free (p); } while (NULL != (rc = ph->reservation_head)) { GNUNET_CONTAINER_DLL_remove (ph->reservation_head, ph->reservation_tail, rc); GNUNET_break (NULL == rc->rcb); GNUNET_free (rc); } if (GNUNET_SCHEDULER_NO_TASK != ph->task) { GNUNET_SCHEDULER_cancel (ph->task); ph->task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != ph->client) { GNUNET_CLIENT_disconnect (ph->client); ph->client = NULL; } GNUNET_free (ph); } /** * Reserve inbound bandwidth from the given peer. ATS will look at * the current amount of traffic we receive from the peer and ensure * that the peer could add 'amount' of data to its stream. * * @param ph performance handle * @param peer identifies the peer * @param amount reserve N bytes for receiving, negative * amounts can be used to undo a (recent) reservation; * @param rcb function to call with the resulting reservation information * @param rcb_cls closure for info * @return NULL on error * @deprecated will be replaced soon */ struct GNUNET_ATS_ReservationContext * GNUNET_ATS_reserve_bandwidth (struct GNUNET_ATS_PerformanceHandle *ph, const struct GNUNET_PeerIdentity *peer, int32_t amount, GNUNET_ATS_ReservationCallback rcb, void *rcb_cls) { struct GNUNET_ATS_ReservationContext *rc; struct PendingMessage *p; struct ReservationRequestMessage *m; rc = GNUNET_malloc (sizeof (struct GNUNET_ATS_ReservationContext)); rc->size = amount; rc->peer = *peer; rc->rcb = rcb; rc->rcb_cls = rcb_cls; if ((rcb != NULL) && (amount > 0)) rc->undo = GNUNET_YES; GNUNET_CONTAINER_DLL_insert_tail (ph->reservation_head, ph->reservation_tail, rc); p = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (struct ReservationRequestMessage)); p->size = sizeof (struct ReservationRequestMessage); p->is_init = GNUNET_NO; m = (struct ReservationRequestMessage *) &p[1]; m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_RESERVATION_REQUEST); m->header.size = htons (sizeof (struct ReservationRequestMessage)); m->amount = htonl (amount); m->peer = *peer; GNUNET_CONTAINER_DLL_insert_tail (ph->pending_head, ph->pending_tail, p); do_transmit (ph); return rc; } /** * Cancel request for reserving bandwidth. * * @param rc context returned by the original GNUNET_ATS_reserve_bandwidth call */ void GNUNET_ATS_reserve_bandwidth_cancel (struct GNUNET_ATS_ReservationContext *rc) { rc->rcb = NULL; } /** * Change preferences for the given peer. Preference changes are forgotten if peers * disconnect. * * @param ph performance handle * @param peer identifies the peer * @param ... 0-terminated specification of the desired changes */ void GNUNET_ATS_change_preference (struct GNUNET_ATS_PerformanceHandle *ph, const struct GNUNET_PeerIdentity *peer, ...) { struct PendingMessage *p; struct ChangePreferenceMessage *m; size_t msize; uint32_t count; struct PreferenceInformation *pi; va_list ap; enum GNUNET_ATS_PreferenceKind kind; count = 0; va_start (ap, peer); while (GNUNET_ATS_PREFERENCE_END != (kind = va_arg (ap, enum GNUNET_ATS_PreferenceKind))) { switch (kind) { case GNUNET_ATS_PREFERENCE_BANDWIDTH: count++; (void) va_arg (ap, double); break; case GNUNET_ATS_PREFERENCE_LATENCY: count++; (void) va_arg (ap, double); break; default: GNUNET_assert (0); } } va_end (ap); msize = count * sizeof (struct PreferenceInformation) + sizeof (struct ChangePreferenceMessage); p = GNUNET_malloc (sizeof (struct PendingMessage) + msize); p->size = msize; p->is_init = GNUNET_NO; m = (struct ChangePreferenceMessage *) &p[1]; m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_CHANGE); m->header.size = htons (msize); m->num_preferences = htonl (count); m->peer = *peer; pi = (struct PreferenceInformation *) &m[1]; count = 0; va_start (ap, peer); while (GNUNET_ATS_PREFERENCE_END != (kind = va_arg (ap, enum GNUNET_ATS_PreferenceKind))) { pi[count].preference_kind = htonl (kind); switch (kind) { case GNUNET_ATS_PREFERENCE_BANDWIDTH: pi[count].preference_value = (float) va_arg (ap, double); count++; break; case GNUNET_ATS_PREFERENCE_LATENCY: pi[count].preference_value = (float) va_arg (ap, double); count++; break; default: GNUNET_assert (0); } } va_end (ap); GNUNET_CONTAINER_DLL_insert_tail (ph->pending_head, ph->pending_tail, p); do_transmit (ph); } /* end of ats_api_performance.c */ gnunet-0.9.3/src/ats/perf_ats_mlp.c0000644000175000017500000002624311760502551014152 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file ats/perf_ats_mlp * @brief performance test for the MLP solver * @author Christian Grothoff * @author Matthias Wachs */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_statistics_service.h" #include "gnunet-service-ats_addresses_mlp.h" #define MLP_MAX_EXEC_DURATION GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3) #define MLP_MAX_ITERATIONS INT_MAX #define DEF_PEERS 10 #define DEF_ADDRESSES_PER_PEER 5 #define DEF_ATS_VALUES 2 #define DEF_ATS_MAX_DELAY 30 #define DEF_ATS_MAX_DISTANCE 3 static unsigned int peers; static unsigned int addresses; static unsigned int numeric; static unsigned int update_percentage; static int start; static int end; struct ATS_Peer *p; struct ATS_Address *a; static int ret; static struct GNUNET_CONTAINER_MultiHashMap * amap; static struct GAS_MLP_Handle *mlp; GNUNET_SCHEDULER_TaskIdentifier shutdown_task; struct PeerContext { struct GNUNET_PeerIdentity id; struct Address *addr; }; struct Address { char *plugin; size_t plugin_len; void *addr; size_t addr_len; struct GNUNET_ATS_Information *ats; int ats_count; void *session; }; void do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { unsigned int ca; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n"); if (NULL != mlp) { GAS_mlp_done (mlp); mlp = NULL; } if (NULL != a) { for (ca=0; ca < (peers * addresses); ca++) { GNUNET_free (a[ca].plugin); GNUNET_free (a[ca].ats); } } if (NULL != amap) GNUNET_CONTAINER_multihashmap_destroy(amap); GNUNET_free_non_null (a); GNUNET_free_non_null (p); } static void update_addresses (struct ATS_Address * a, unsigned int addrs, unsigned int percentage) { if (percentage == 0) return; unsigned int ua = (addrs) * ((float) percentage / 100); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Updating %u of %u addresses per peer\n", ua, addrs); unsigned int updated[addrs]; unsigned int u_types[DEF_ATS_VALUES]; unsigned int updates = 0; unsigned int u_type = 0; unsigned int u_val = 0; unsigned int cur = 0; u_types[0] = 0; u_types[1] = 0; for (cur = 0; cur < addrs; cur ++) { updated[cur] = 0; } cur = 0; while (updates < ua) { cur = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, addrs); if (0 == updated[cur]) { u_type = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, DEF_ATS_VALUES); switch (u_type) { case 0: do { u_val = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, DEF_ATS_MAX_DELAY); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating DELAY from %u to %u\n",a[cur].ats[u_type].value, u_val); } while (a[cur].ats[u_type].value == u_val); break; case 1: do { u_val = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, DEF_ATS_MAX_DISTANCE); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating DISTANCE from %u to %u\n",a[cur].ats[u_type].value, u_val); } while (a[cur].ats[u_type].value == u_val); break; default: GNUNET_break (0); break; } u_types[u_type]++; a[cur].ats[u_type].value = u_val; updated[cur] = 1; GAS_mlp_address_update(mlp, amap, &a[cur]); updates++; } } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Updated %u delay and %u distance values\n", u_types[0], u_types[1]); } static void check (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { unsigned int c = 0; unsigned int c2 = 0; unsigned int ca = 0; int update = GNUNET_NO; int range = GNUNET_NO; int res; #if !HAVE_LIBGLPK GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GLPK not installed!"); ret = 1; return; #endif GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Setting up %u peers with %u addresses per peer\n", peers, addresses); mlp = GAS_mlp_init (cfg, NULL, MLP_MAX_EXEC_DURATION, MLP_MAX_ITERATIONS); if (NULL == mlp) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to init MLP\n"); ret = 1; if (GNUNET_SCHEDULER_NO_TASK != shutdown_task) GNUNET_SCHEDULER_cancel(shutdown_task); shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); } if (peers == 0) peers = DEF_PEERS; if (addresses == 0) addresses = DEF_ADDRESSES_PER_PEER; p = GNUNET_malloc (peers * sizeof (struct ATS_Peer)); a = GNUNET_malloc (peers * addresses * sizeof (struct ATS_Address)); amap = GNUNET_CONTAINER_multihashmap_create(addresses * peers); mlp->auto_solve = GNUNET_NO; if (start == 0) start = 0; if (end == 0) end = -1; if ((start != -1) && (end != -1)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Solving problem starting from %u to %u\n", start , end); range = GNUNET_YES; } else GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Solving problem for %u peers\n", peers); if ((update_percentage >= 0) && (update_percentage <= 100)) { update = GNUNET_YES; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Benchmarking with existing presolution and %u%% updated addresses\n", update_percentage); } else if ((update_percentage > 100) && (update_percentage != UINT_MAX)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Invalid percentage: %u\n", update_percentage); ret = 1; return; } for (c=0; c < peers; c++) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Setting up peer %u\n", c); GNUNET_CRYPTO_hash_create_random(GNUNET_CRYPTO_QUALITY_NONCE, &p[c].id.hashPubKey); for (c2=0; c2 < addresses; c2++) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Setting up address %u for peer %u\n", c2, c); /* Setting required information */ a[ca].mlp_information = NULL; a[ca].prev = NULL; a[ca].next = NULL; /* Setting address */ a[ca].peer = p[c].id; a[ca].plugin = GNUNET_strdup("test"); a[ca].atsp_network_type = GNUNET_ATS_NET_LOOPBACK; a[ca].ats = GNUNET_malloc (DEF_ATS_VALUES * sizeof (struct GNUNET_ATS_Information)); a[ca].ats[0].type = GNUNET_ATS_QUALITY_NET_DELAY; a[ca].ats[0].value = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, DEF_ATS_MAX_DELAY); a[ca].ats[1].type = GNUNET_ATS_QUALITY_NET_DISTANCE; a[ca].ats[1].value = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, DEF_ATS_MAX_DISTANCE); a[ca].ats_count = 2; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Setting up address %u\n", ca); GNUNET_CONTAINER_multihashmap_put (amap, &a[ca].peer.hashPubKey, &a[ca], GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); GAS_mlp_address_update(mlp, amap, &a[ca]); ca++; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Problem contains %u peers and %u adresses\n", mlp->c_p, mlp->addr_in_problem); if (((GNUNET_YES == range) && (((start >= 0) && ((c+1) >= start)) && (c <= end))) || ((c+1) == peers)) { GNUNET_assert ((c+1) == mlp->c_p); GNUNET_assert ((c+1) * addresses == mlp->addr_in_problem); /* Solving the problem */ struct GAS_MLP_SolutionContext ctx; res = GAS_mlp_solve_problem(mlp, &ctx); if (GNUNET_NO == update) { if (GNUNET_OK == res) { GNUNET_assert (GNUNET_OK == ctx.lp_result); GNUNET_assert (GNUNET_OK == ctx.mlp_result); if (GNUNET_YES == numeric) printf ("%u;%u;%llu;%llu\n",mlp->c_p, mlp->addr_in_problem, (unsigned long long) ctx.lp_duration.rel_value, (unsigned long long) ctx.mlp_duration.rel_value); else GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Problem solved for %u peers with %u address successfully (LP: %llu ms / MLP: %llu ms)\n", mlp->c_p, mlp->addr_in_problem, ctx.lp_duration.rel_value, ctx.mlp_duration.rel_value); } else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Solving problem with %u peers and %u addresses failed\n", c, c2); } else { struct GAS_MLP_SolutionContext uctx; /* Update addresses */ update_addresses (a, (c+1) * c2, update_percentage); /* Solve again */ res = GAS_mlp_solve_problem(mlp, &uctx); if (GNUNET_OK == res) { GNUNET_assert (GNUNET_OK == uctx.lp_result); GNUNET_assert (GNUNET_OK == uctx.mlp_result); if (GNUNET_YES == numeric) printf ("%u;%u;%llu;%llu;%llu;%llu\n",mlp->c_p, mlp->addr_in_problem, (unsigned long long) ctx.lp_duration.rel_value, (unsigned long long) ctx.mlp_duration.rel_value, (unsigned long long) uctx.lp_duration.rel_value, (unsigned long long) uctx.mlp_duration.rel_value); else GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Updated problem solved for %u peers with %u address successfully (Initial: LP/MLP: %llu/%llu ms, Update: %llu/%llu ms)\n", mlp->c_p, mlp->addr_in_problem, (unsigned long long) ctx.lp_duration.rel_value, (unsigned long long) ctx.mlp_duration.rel_value, (unsigned long long) uctx.lp_duration.rel_value, (unsigned long long) uctx.mlp_duration.rel_value); } else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Solving updated problem with %u peers and %u addresses failed\n", c, c2); } } } if (GNUNET_SCHEDULER_NO_TASK != shutdown_task) GNUNET_SCHEDULER_cancel(shutdown_task); shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); } int main (int argc, char *argv[]) { /* Init invalid */ update_percentage = UINT_MAX; static struct GNUNET_GETOPT_CommandLineOption options[] = { {'a', "addresses", NULL, gettext_noop ("addresses per peer"), 1, &GNUNET_GETOPT_set_uint, &addresses}, {'p', "peers", NULL, gettext_noop ("peers"), 1, &GNUNET_GETOPT_set_uint, &peers}, {'n', "numeric", NULL, gettext_noop ("numeric output only"), 0, &GNUNET_GETOPT_set_one, &numeric}, {'e', "end", NULL, gettext_noop ("end solving problem"), 1, &GNUNET_GETOPT_set_uint, &end}, {'s', "start", NULL, gettext_noop ("start solving problem"), 1, &GNUNET_GETOPT_set_uint, &start}, {'u', "update", NULL, gettext_noop ("benchmark with existing solution (address updates)"), 1, &GNUNET_GETOPT_set_uint, &update_percentage}, GNUNET_GETOPT_OPTION_END }; GNUNET_PROGRAM_run (argc, argv, "perf_ats_mlp", "nohelp", options, &check, NULL); return ret; } /* end of file perf_ats_mlp.c */ gnunet-0.9.3/src/ats/ats.conf.in0000644000175000017500000000137011760502552013371 00000000000000[ats] AUTOSTART = YES @UNIXONLY@ PORT = 2098 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-ats ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-ats.sock UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES # Enable MLP mode (default: NO) MLP = NO # Network specific inbound/outbound quotas # LOOPBACK LOOPBACK_QUOTA_IN = unlimited LOOPBACK_QUOTA_OUT = unlimited # LAN LAN_QUOTA_IN = unlimited LAN_QUOTA_OUT = unlimited # WAN WAN_QUOTA_IN = 64 KiB WAN_QUOTA_OUT = 64 KiB # WLAN WLAN_QUOTA_IN = 1 MiB WLAN_QUOTA_OUT = 1 MiB # ATS options DUMP_MLP = NO DUMP_SOLUTION = NO DUMP_OVERWRITE = NO DUMP_MIN_PEERS = 0 DUMP_MIN_ADDRS = 0 DUMP_OVERWRITE = NO ATS_MIN_INTERVAL = 15000 ATS_EXEC_INTERVAL = 30000 gnunet-0.9.3/src/ats/Makefile.in0000644000175000017500000010760511762223646013411 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-service-ats$(EXEEXT) check_PROGRAMS = test_ats_api_scheduling$(EXEEXT) \ test_ats_api_reset_backoff$(EXEEXT) $(am__EXEEXT_1) \ $(am__EXEEXT_2) $(am__EXEEXT_3) subdir = src/ats DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/ats.conf.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = ats.conf CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) libgnunetats_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_libgnunetats_la_OBJECTS = ats_api_scheduling.lo \ ats_api_performance.lo libgnunetats_la_OBJECTS = $(am_libgnunetats_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunetats_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetats_la_LDFLAGS) $(LDFLAGS) \ -o $@ @HAVE_LIBGLPK_TRUE@am__EXEEXT_1 = test_ats_mlp$(EXEEXT) @HAVE_LIBGLPK_TRUE@am__EXEEXT_2 = test_ats_mlp_averaging$(EXEEXT) @HAVE_LIBGLPK_TRUE@am__EXEEXT_3 = perf_ats_mlp$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) am__gnunet_service_ats_SOURCES_DIST = gnunet-service-ats.c \ gnunet-service-ats.h gnunet-service-ats_addresses.c \ gnunet-service-ats_addresses.h \ gnunet-service-ats_addresses_mlp.c \ gnunet-service-ats_addresses_mlp.h \ gnunet-service-ats_performance.c \ gnunet-service-ats_performance.h \ gnunet-service-ats_scheduling.c \ gnunet-service-ats_scheduling.h \ gnunet-service-ats_reservations.c \ gnunet-service-ats_reservations.h @HAVE_LIBGLPK_TRUE@am__objects_1 = \ @HAVE_LIBGLPK_TRUE@ gnunet-service-ats_addresses_mlp.$(OBJEXT) am_gnunet_service_ats_OBJECTS = gnunet-service-ats.$(OBJEXT) \ gnunet-service-ats_addresses.$(OBJEXT) $(am__objects_1) \ gnunet-service-ats_performance.$(OBJEXT) \ gnunet-service-ats_scheduling.$(OBJEXT) \ gnunet-service-ats_reservations.$(OBJEXT) gnunet_service_ats_OBJECTS = $(am_gnunet_service_ats_OBJECTS) am__DEPENDENCIES_1 = gnunet_service_ats_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am__perf_ats_mlp_SOURCES_DIST = gnunet-service-ats_addresses_mlp.c \ gnunet-service-ats_addresses_mlp.h perf_ats_mlp.c @HAVE_LIBGLPK_TRUE@am_perf_ats_mlp_OBJECTS = $(am__objects_1) \ @HAVE_LIBGLPK_TRUE@ perf_ats_mlp.$(OBJEXT) perf_ats_mlp_OBJECTS = $(am_perf_ats_mlp_OBJECTS) @HAVE_LIBGLPK_TRUE@perf_ats_mlp_DEPENDENCIES = $(am__DEPENDENCIES_1) \ @HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \ @HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/statistics/libgnunetstatistics.la am_test_ats_api_reset_backoff_OBJECTS = \ test_ats_api_reset_backoff.$(OBJEXT) test_ats_api_reset_backoff_OBJECTS = \ $(am_test_ats_api_reset_backoff_OBJECTS) test_ats_api_reset_backoff_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/ats/libgnunetats.la am_test_ats_api_scheduling_OBJECTS = \ test_ats_api_scheduling.$(OBJEXT) test_ats_api_scheduling_OBJECTS = \ $(am_test_ats_api_scheduling_OBJECTS) test_ats_api_scheduling_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/ats/libgnunetats.la am__test_ats_mlp_SOURCES_DIST = gnunet-service-ats_addresses_mlp.c \ gnunet-service-ats_addresses_mlp.h test_ats_mlp.c @HAVE_LIBGLPK_TRUE@am_test_ats_mlp_OBJECTS = $(am__objects_1) \ @HAVE_LIBGLPK_TRUE@ test_ats_mlp.$(OBJEXT) test_ats_mlp_OBJECTS = $(am_test_ats_mlp_OBJECTS) @HAVE_LIBGLPK_TRUE@test_ats_mlp_DEPENDENCIES = $(am__DEPENDENCIES_1) \ @HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \ @HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/statistics/libgnunetstatistics.la am__test_ats_mlp_averaging_SOURCES_DIST = \ gnunet-service-ats_addresses_mlp.c \ gnunet-service-ats_addresses_mlp.h test_ats_mlp_averaging.c @HAVE_LIBGLPK_TRUE@am_test_ats_mlp_averaging_OBJECTS = \ @HAVE_LIBGLPK_TRUE@ $(am__objects_1) \ @HAVE_LIBGLPK_TRUE@ test_ats_mlp_averaging.$(OBJEXT) test_ats_mlp_averaging_OBJECTS = $(am_test_ats_mlp_averaging_OBJECTS) @HAVE_LIBGLPK_TRUE@test_ats_mlp_averaging_DEPENDENCIES = \ @HAVE_LIBGLPK_TRUE@ $(am__DEPENDENCIES_1) \ @HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \ @HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/statistics/libgnunetstatistics.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunetats_la_SOURCES) $(gnunet_service_ats_SOURCES) \ $(perf_ats_mlp_SOURCES) $(test_ats_api_reset_backoff_SOURCES) \ $(test_ats_api_scheduling_SOURCES) $(test_ats_mlp_SOURCES) \ $(test_ats_mlp_averaging_SOURCES) DIST_SOURCES = $(libgnunetats_la_SOURCES) \ $(am__gnunet_service_ats_SOURCES_DIST) \ $(am__perf_ats_mlp_SOURCES_DIST) \ $(test_ats_api_reset_backoff_SOURCES) \ $(test_ats_api_scheduling_SOURCES) \ $(am__test_ats_mlp_SOURCES_DIST) \ $(am__test_ats_mlp_averaging_SOURCES_DIST) DATA = $(pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include pkgcfgdir = $(pkgdatadir)/config.d/ pkgcfg_DATA = \ ats.conf @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = -fprofile-arcs -ftest-coverage @HAVE_LIBGLPK_TRUE@GN_LIBGLPK = -lglpk @HAVE_LIBGLPK_TRUE@GN_MLP_SRC = gnunet-service-ats_addresses_mlp.c gnunet-service-ats_addresses_mlp.h @HAVE_LIBGLPK_TRUE@GN_MLP_TEST = test_ats_mlp @HAVE_LIBGLPK_TRUE@GN_MLP_TEST_AVG = test_ats_mlp_averaging @HAVE_LIBGLPK_TRUE@GN_MLP_PERF = perf_ats_mlp lib_LTLIBRARIES = libgnunetats.la libgnunetats_la_SOURCES = \ ats_api_scheduling.c \ ats_api_performance.c libgnunetats_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la libgnunetats_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 2:0:2 gnunet_service_ats_SOURCES = \ gnunet-service-ats.c gnunet-service-ats.h\ gnunet-service-ats_addresses.c gnunet-service-ats_addresses.h \ $(GN_MLP_SRC) \ gnunet-service-ats_performance.c gnunet-service-ats_performance.h \ gnunet-service-ats_scheduling.c gnunet-service-ats_scheduling.h \ gnunet-service-ats_reservations.c gnunet-service-ats_reservations.h gnunet_service_ats_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBGLPK) \ $(GN_LIBINTL) # test_ats_api_scheduling_get_type # test_ats_api_bandwidth_consumption @ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) @HAVE_LIBGLPK_TRUE@test_ats_mlp_SOURCES = \ @HAVE_LIBGLPK_TRUE@ $(GN_MLP_SRC) \ @HAVE_LIBGLPK_TRUE@ test_ats_mlp.c @HAVE_LIBGLPK_TRUE@test_ats_mlp_LDADD = \ @HAVE_LIBGLPK_TRUE@ $(GN_LIBGLPK) \ @HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \ @HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/statistics/libgnunetstatistics.la @HAVE_LIBGLPK_TRUE@test_ats_mlp_averaging_SOURCES = \ @HAVE_LIBGLPK_TRUE@ $(GN_MLP_SRC) \ @HAVE_LIBGLPK_TRUE@ test_ats_mlp_averaging.c @HAVE_LIBGLPK_TRUE@test_ats_mlp_averaging_LDADD = \ @HAVE_LIBGLPK_TRUE@ $(GN_LIBGLPK) \ @HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \ @HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/statistics/libgnunetstatistics.la @HAVE_LIBGLPK_TRUE@perf_ats_mlp_SOURCES = \ @HAVE_LIBGLPK_TRUE@ $(GN_MLP_SRC) \ @HAVE_LIBGLPK_TRUE@ perf_ats_mlp.c @HAVE_LIBGLPK_TRUE@perf_ats_mlp_LDADD = \ @HAVE_LIBGLPK_TRUE@ $(GN_LIBGLPK) \ @HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \ @HAVE_LIBGLPK_TRUE@ $(top_builddir)/src/statistics/libgnunetstatistics.la test_ats_api_scheduling_SOURCES = \ test_ats_api_scheduling.c test_ats_api_scheduling_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/ats/libgnunetats.la test_ats_api_reset_backoff_SOURCES = \ test_ats_api_reset_backoff.c test_ats_api_reset_backoff_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/ats/libgnunetats.la #test_ats_api_scheduling_get_type_SOURCES = \ # test_ats_api_scheduling_get_type.c #test_ats_api_scheduling_get_type_LDADD = \ # $(top_builddir)/src/util/libgnunetutil.la \ # $(top_builddir)/src/ats/libgnunetats.la #test_ats_api_bandwidth_consumption_SOURCES = \ # test_ats_api_bandwidth_consumption.c #test_ats_api_bandwidth_consumption_LDADD = \ # $(top_builddir)/src/util/libgnunetutil.la \ # $(top_builddir)/src/ats/libgnunetats.la #test_ats_api_update_address_SOURCES = \ # test_ats_api_update_address.c #test_ats_api_update_address_LDADD = \ # $(top_builddir)/src/util/libgnunetutil.la \ # $(top_builddir)/src/ats/libgnunetats.la EXTRA_DIST = \ ats.h \ test_ats_api.conf all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/ats/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/ats/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): ats.conf: $(top_builddir)/config.status $(srcdir)/ats.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunetats.la: $(libgnunetats_la_OBJECTS) $(libgnunetats_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetats_la_LINK) -rpath $(libdir) $(libgnunetats_la_OBJECTS) $(libgnunetats_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-service-ats$(EXEEXT): $(gnunet_service_ats_OBJECTS) $(gnunet_service_ats_DEPENDENCIES) @rm -f gnunet-service-ats$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_service_ats_OBJECTS) $(gnunet_service_ats_LDADD) $(LIBS) perf_ats_mlp$(EXEEXT): $(perf_ats_mlp_OBJECTS) $(perf_ats_mlp_DEPENDENCIES) @rm -f perf_ats_mlp$(EXEEXT) $(AM_V_CCLD)$(LINK) $(perf_ats_mlp_OBJECTS) $(perf_ats_mlp_LDADD) $(LIBS) test_ats_api_reset_backoff$(EXEEXT): $(test_ats_api_reset_backoff_OBJECTS) $(test_ats_api_reset_backoff_DEPENDENCIES) @rm -f test_ats_api_reset_backoff$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_ats_api_reset_backoff_OBJECTS) $(test_ats_api_reset_backoff_LDADD) $(LIBS) test_ats_api_scheduling$(EXEEXT): $(test_ats_api_scheduling_OBJECTS) $(test_ats_api_scheduling_DEPENDENCIES) @rm -f test_ats_api_scheduling$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_ats_api_scheduling_OBJECTS) $(test_ats_api_scheduling_LDADD) $(LIBS) test_ats_mlp$(EXEEXT): $(test_ats_mlp_OBJECTS) $(test_ats_mlp_DEPENDENCIES) @rm -f test_ats_mlp$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_ats_mlp_OBJECTS) $(test_ats_mlp_LDADD) $(LIBS) test_ats_mlp_averaging$(EXEEXT): $(test_ats_mlp_averaging_OBJECTS) $(test_ats_mlp_averaging_DEPENDENCIES) @rm -f test_ats_mlp_averaging$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_ats_mlp_averaging_OBJECTS) $(test_ats_mlp_averaging_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ats_api_performance.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ats_api_scheduling.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-ats.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-ats_addresses.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-ats_addresses_mlp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-ats_performance.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-ats_reservations.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-ats_scheduling.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perf_ats_mlp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_ats_api_reset_backoff.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_ats_api_scheduling.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_ats_mlp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_ats_mlp_averaging.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgcfgDATA: $(pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgcfgDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-binPROGRAMS install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-pkgcfgDATA install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/ats/gnunet-service-ats_addresses_mlp.h0000644000175000017500000002324011760502551020126 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file ats/gnunet-service-ats_addresses_mlp.h * @brief ats mlp problem solver * @author Matthias Wachs * @author Christian Grothoff */ #include "platform.h" #include "gnunet_statistics_service.h" #include "gnunet-service-ats_addresses.h" #if HAVE_LIBGLPK #include "glpk.h" #endif #ifndef GNUNET_SERVICE_ATS_ADDRESSES_MLP_H #define GNUNET_SERVICE_ATS_ADDRESSES_MLP_H #define DEBUG_MLP GNUNET_EXTRA_LOGGING #define BIG_M_VALUE (UINT32_MAX) /10 #define BIG_M_STRING "unlimited" #define MLP_AVERAGING_QUEUE_LENGTH 3 #define MLP_MAX_EXEC_DURATION GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3) #define MLP_MAX_ITERATIONS INT_MAX struct ATS_Peer { struct ATS_Peer *next; struct ATS_Peer *prev; struct GNUNET_PeerIdentity id; /* Array of quality preferences */ double f_q[GNUNET_ATS_QualityPropertiesCount]; /* Legacy preference value */ double f; /* constraint 2: 1 address per peer*/ unsigned int r_c2; /* constraint 9: relativity */ unsigned int r_c9; struct ATS_Address *head; struct ATS_Address *tail; }; struct ATS_PreferedAddress { uint32_t bandwidth_out; uint32_t bandwidth_in; struct ATS_Address *address; }; struct GAS_MLP_SolutionContext { int lp_result; int mlp_result; struct GNUNET_TIME_Relative lp_duration; struct GNUNET_TIME_Relative mlp_duration; }; /** * MLP Handle */ struct GAS_MLP_Handle { /** * Statistics handle */ struct GNUNET_STATISTICS_Handle *stats; /** * GLPK (MLP) problem object */ #if HAVE_LIBGLPK glp_prob *prob; #else void *prob; #endif double BIG_M; /** * GLPK LP control parameter */ glp_smcp control_param_lp; /** * GLPK LP control parameter */ glp_iocp control_param_mlp; /** * Solves the task in an regular interval */ GNUNET_SCHEDULER_TaskIdentifier mlp_task; /** * Interval between scheduled problem solving */ struct GNUNET_TIME_Relative exec_interval; /** * Maximum execution time per problem solving */ struct GNUNET_TIME_Relative max_exec_duration; /** * Maximum number of LP iterations per problem solving */ unsigned int max_iterations; /** * Solve the problem automatically when updates occur? * Default: GNUNET_YES * Can be disabled for test and measurements */ int auto_solve; int semaphore; /* state information */ /** * Do we need to use the LP presolver? * * If the problem addresses were added or removed and the last basis was we * need to use the presolver. * presolver_required == GNUNET_YES * * If values were modified, we can reuse a valid basis * presolver_required == GNUNET_NO */ int presolver_required; /* statistics */ /** * Time of last execution */ struct GNUNET_TIME_Absolute last_execution; /** * How often was the LP problem solved */ unsigned int lp_solved; /** * total duration of all lp solver executions */ uint64_t lp_total_duration; /** * How often was the MLP problem solved */ unsigned int mlp_solved; /** * total duration of all mlp solver executions */ uint64_t mlp_total_duration; unsigned int addr_in_problem; /* Information about the problem */ struct ATS_Peer *peer_head; struct ATS_Peer *peer_tail; /* Number of peers */ unsigned int c_p; /* current problem matrix */ /* row index array */ int *ia; /* column index array */ int *ja; /* column index array */ double *ar; /* current size of the constraint matrix |indices| */ unsigned int cm_size; unsigned int ci; /* Row index constraint 2: */ unsigned int r_c2; /* Row index constraint 4: minimum connections */ unsigned int r_c4; /* Row index constraint 6: maximize diversity */ unsigned int r_c6; /* Row index constraint 8: utilization*/ unsigned int r_c8; /* Row index constraint 9: relativity*/ unsigned int r_c9; /* column index Diversity (D) column */ int c_d; double co_D; /* column index Utilization (U) column */ int c_u; double co_U; /* column index Proportionality (R) column */ int c_r; double co_R; /* ATS Quality metrics * * array with GNUNET_ATS_QualityPropertiesCount elements * contains mapping to GNUNET_ATS_Property*/ int q[GNUNET_ATS_QualityPropertiesCount]; /* column index quality metrics */ int c_q[GNUNET_ATS_QualityPropertiesCount]; /* column index quality metrics */ int r_q[GNUNET_ATS_QualityPropertiesCount]; /* quality metric coefficients*/ double co_Q[GNUNET_ATS_QualityPropertiesCount]; /* number of quality metrics */ int m_q; /* ATS network quotas */ int c_quota[GNUNET_ATS_NetworkTypeCount]; int r_quota[GNUNET_ATS_NetworkTypeCount]; int quota_index [GNUNET_ATS_NetworkTypeCount]; unsigned long long quota_out[GNUNET_ATS_NetworkTypeCount]; unsigned long long quota_in[GNUNET_ATS_NetworkTypeCount]; /* ATS ressource costs * * array with GNUNET_ATS_QualityPropertiesCount elements * contains mapping to GNUNET_ATS_Property*/ int rc[GNUNET_ATS_QualityPropertiesCount]; /* column index ressource costs */ int c_rc[GNUNET_ATS_QualityPropertiesCount]; /* ressource costs coefficients*/ double co_RC[GNUNET_ATS_QualityPropertiesCount]; /* number of quality metrics */ int m_rc; /* minimum bandwidth assigned to an address */ unsigned int b_min; /* minimum number of addresses with bandwidth assigned */ unsigned int n_min; }; /** * Address specific MLP information */ struct MLP_information { double b; int n; /* bandwidth column index */ signed int c_b; /* address usage column */ signed int c_n; /* row indexes */ /* constraint 1: bandwidth capping */ unsigned int r_c1; /* constraint 3: minimum bandwidth */ unsigned int r_c3; /* Quality information row indices */ unsigned int r_q[GNUNET_ATS_QualityPropertiesCount]; /* Quality information */ double q[GNUNET_ATS_QualityPropertiesCount][MLP_AVERAGING_QUEUE_LENGTH]; /* Quality information averaged */ double q_averaged[GNUNET_ATS_QualityPropertiesCount]; /* Averaging index */ int q_avg_i[GNUNET_ATS_QualityPropertiesCount]; }; /** * Init the MLP problem solving component * * @param cfg configuration handle * @param stats the GNUNET_STATISTICS handle * @param max_duration maximum numbers of iterations for the LP/MLP Solver * @param max_iterations maximum time limit for the LP/MLP Solver * @return struct GAS_MLP_Handle * on success, NULL on fail */ struct GAS_MLP_Handle * GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg, const struct GNUNET_STATISTICS_Handle *stats, struct GNUNET_TIME_Relative max_duration, unsigned int max_iterations); /** * Solves the MLP problem on demand * * @param mlp the MLP Handle * @param ctx solution context * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure */ int GAS_mlp_solve_problem (struct GAS_MLP_Handle *mlp, struct GAS_MLP_SolutionContext *ctx); /** * Updates a single address in the MLP problem * * If the address did not exist before in the problem: * The MLP problem has to be recreated and the problem has to be resolved * * Otherwise the addresses' values can be updated and the existing base can * be reused * * @param mlp the MLP Handle * @param addresses the address hashmap * the address has to be already added from the hashmap * @param address the address to update */ void GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address); /** * Deletes a single address in the MLP problem * * The MLP problem has to be recreated and the problem has to be resolved * * @param mlp the MLP Handle * @param addresses the address hashmap * the address has to be already removed from the hashmap * @param address the address to delete */ void GAS_mlp_address_delete (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address); /** * Changes the preferences for a peer in the MLP problem * * @param mlp the MLP Handle * @param peer the peer * @param kind the kind to change the preference * @param score the score */ void GAS_mlp_address_change_preference (struct GAS_MLP_Handle *mlp, const struct GNUNET_PeerIdentity *peer, enum GNUNET_ATS_PreferenceKind kind, float score); /** * Get the preferred address for a specific peer * * @param mlp the MLP Handle * @param addresses address hashmap * @param peer the peer * @return suggested address */ struct ATS_PreferedAddress * GAS_mlp_get_preferred_address (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, const struct GNUNET_PeerIdentity *peer); /** * Shutdown the MLP problem solving component */ void GAS_mlp_done (); #endif /* end of gnunet-service-ats_addresses_mlp.h */ gnunet-0.9.3/src/ats/test_ats_mlp.c0000644000175000017500000001472711760502551014201 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file ats/test_ats_mlp.c * @brief test for the MLP solver * @author Christian Grothoff * @author Matthias Wachs */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_statistics_service.h" #include "gnunet_ats_service.h" #include "gnunet-service-ats_addresses_mlp.h" #define MLP_MAX_EXEC_DURATION GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3) #define MLP_MAX_ITERATIONS INT_MAX static int ret; struct GNUNET_STATISTICS_Handle * stats; struct GNUNET_CONTAINER_MultiHashMap * addresses; struct GAS_MLP_Handle *mlp; static void create_address (struct ATS_Address *addr, char * plugin, int ats_count, struct GNUNET_ATS_Information *ats) { addr->mlp_information = NULL; addr->next = NULL; addr->prev = NULL; addr->plugin = GNUNET_strdup (plugin); addr->ats_count = ats_count; addr->ats = ats; } static void set_ats (struct GNUNET_ATS_Information *ats, uint32_t type, uint32_t value) { ats->type = type; ats->value = value; } static void check (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { #if !HAVE_LIBGLPK GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GLPK not installed!"); ret = 1; return; #endif struct ATS_Address addr[10]; struct ATS_PreferedAddress *res[10]; struct GAS_MLP_SolutionContext ctx; stats = GNUNET_STATISTICS_create("ats", cfg); addresses = GNUNET_CONTAINER_multihashmap_create (10); mlp = GAS_mlp_init (cfg, NULL, MLP_MAX_EXEC_DURATION, MLP_MAX_ITERATIONS); mlp->auto_solve = GNUNET_NO; struct GNUNET_PeerIdentity p[10]; /* Creating peer 1 */ GNUNET_CRYPTO_hash_create_random(GNUNET_CRYPTO_QUALITY_WEAK, &p[0].hashPubKey); /* Creating peer 2 */ GNUNET_CRYPTO_hash_create_random(GNUNET_CRYPTO_QUALITY_WEAK, &p[1].hashPubKey); /* Creating peer 1 address 1 */ addr[0].peer.hashPubKey = p[0].hashPubKey; struct GNUNET_ATS_Information a1_ats[3]; set_ats (&a1_ats[0], GNUNET_ATS_QUALITY_NET_DISTANCE, 1); set_ats (&a1_ats[1], GNUNET_ATS_QUALITY_NET_DELAY, 1); set_ats (&a1_ats[2], GNUNET_ATS_ARRAY_TERMINATOR, 0); create_address (&addr[0], "dummy", 3, &a1_ats[0]); addr[0].atsp_network_type = GNUNET_ATS_NET_WAN; /* Creating peer 1 address 2 */ addr[1].peer.hashPubKey = p[0].hashPubKey; struct GNUNET_ATS_Information a2_ats[3]; set_ats (&a2_ats[1], GNUNET_ATS_QUALITY_NET_DISTANCE, 1); set_ats (&a2_ats[0], GNUNET_ATS_QUALITY_NET_DELAY, 1); set_ats (&a2_ats[2], GNUNET_ATS_ARRAY_TERMINATOR, 0); create_address (&addr[1], "dummy2", 3, &a2_ats[0]); addr[1].atsp_network_type = GNUNET_ATS_NET_LAN; /* Creating peer 2 address 1 */ addr[2].peer.hashPubKey = p[1].hashPubKey; struct GNUNET_ATS_Information a3_ats[3]; set_ats (&a3_ats[1], GNUNET_ATS_QUALITY_NET_DISTANCE, 1); set_ats (&a3_ats[0], GNUNET_ATS_QUALITY_NET_DELAY, 1); set_ats (&a3_ats[2], GNUNET_ATS_ARRAY_TERMINATOR, 0); create_address (&addr[2], "dummy3", 3, &a3_ats[0]); addr[2].atsp_network_type = GNUNET_ATS_NET_LAN; GNUNET_CONTAINER_multihashmap_put(addresses, &addr[0].peer.hashPubKey, &addr[0], GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); /* Add peer 1 address 1 */ GAS_mlp_address_update (mlp, addresses, &addr[0]); GNUNET_assert (mlp != NULL); GNUNET_assert (mlp->addr_in_problem == 1); /* Update an peer 1 address 1 */ set_ats (&a1_ats[1], GNUNET_ATS_QUALITY_NET_DELAY, 1); GAS_mlp_address_update (mlp, addresses, &addr[0]); GNUNET_assert (mlp->addr_in_problem == 1); /* Add peer 1 address 2 */ GNUNET_CONTAINER_multihashmap_put(addresses, &addr[0].peer.hashPubKey, &addr[1], GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); GAS_mlp_address_update (mlp, addresses, &addr[1]); GNUNET_assert (mlp->addr_in_problem == 2); /* Add peer 2 address 1 */ GNUNET_CONTAINER_multihashmap_put(addresses, &addr[2].peer.hashPubKey, &addr[2], GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); GAS_mlp_address_update (mlp, addresses, &addr[2]); GNUNET_assert (mlp->addr_in_problem == 3); GNUNET_assert (GNUNET_OK == GAS_mlp_solve_problem(mlp, &ctx)); GNUNET_assert (GNUNET_OK == ctx.lp_result); GNUNET_assert (GNUNET_OK == ctx.mlp_result); res[0] = GAS_mlp_get_preferred_address(mlp, addresses, &p[0]); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Preferred address `%s' outbound bandwidth: %u Bps\n",res[0]->address->plugin, res[0]->bandwidth_out); res[1] = GAS_mlp_get_preferred_address(mlp, addresses, &p[1]); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Preferred address `%s' outbound bandwidth: %u Bps\n",res[1]->address->plugin, res[1]->bandwidth_out); /* Delete an address */ GNUNET_CONTAINER_multihashmap_remove (addresses, &addr[0].peer.hashPubKey, &addr[0]); GAS_mlp_address_delete (mlp, addresses, &addr[0]); GNUNET_CONTAINER_multihashmap_remove (addresses, &addr[1].peer.hashPubKey, &addr[1]); GAS_mlp_address_delete (mlp, addresses, &addr[1]); GNUNET_CONTAINER_multihashmap_remove (addresses, &addr[2].peer.hashPubKey, &addr[2]); GAS_mlp_address_delete (mlp, addresses, &addr[2]); GNUNET_assert (mlp->addr_in_problem == 0); GAS_mlp_done (mlp); GNUNET_free (addr[0].plugin); GNUNET_free (addr[1].plugin); GNUNET_CONTAINER_multihashmap_destroy (addresses); GNUNET_STATISTICS_destroy(stats, GNUNET_NO); ret = 0; return; } int main (int argc, char *argv[]) { static char *const argv2[] = { "test_ats_mlp", "-c", "test_ats_api.conf", "-L", "WARNING", NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, "test_ats_mlp", "nohelp", options, &check, NULL); return ret; } /* end of file test_ats_api_bandwidth_consumption.c */ gnunet-0.9.3/src/ats/gnunet-service-ats_reservations.h0000644000175000017500000000444011760502551020026 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file ats/gnunet-service-ats_reservations.h * @brief ats service, inbound bandwidth reservation management * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_ATS_RESERVATIONS_H #define GNUNET_SERVICE_ATS_RESERVATIONS_H #include "gnunet_util_lib.h" /** * Set the amount of bandwidth the other peer could currently transmit * to us (as far as we know) to the given value. * * @param peer identity of the peer * @param bandwidth_in currently available bandwidth from that peer to * this peer (estimate) */ void GAS_reservations_set_bandwidth (const struct GNUNET_PeerIdentity *peer, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in); /** * Reserve the given amount of incoming bandwidth (in bytes) from the * given peer. If a reservation is not possible right now, return how * long the client should wait before trying again. * * @param peer peer to reserve bandwidth from * @param amount number of bytes to reserve * @return 0 if the reservation was successful, FOREVER if the * peer is not connected, otherwise the time to wait * until the reservation might succeed */ struct GNUNET_TIME_Relative GAS_reservations_reserve (const struct GNUNET_PeerIdentity *peer, int32_t amount); /** * Initialize reservations subsystem. */ void GAS_reservations_init (void); /** * Shutdown reservations subsystem. */ void GAS_reservations_done (void); #endif gnunet-0.9.3/src/ats/gnunet-service-ats_scheduling.c0000644000175000017500000003357111760502551017431 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file ats/gnunet-service-ats_scheduling.c * @brief ats service, interaction with 'scheduling' API * @author Matthias Wachs * @author Christian Grothoff */ #include "platform.h" #include "gnunet-service-ats.h" #include "gnunet-service-ats_addresses.h" #include "gnunet-service-ats_scheduling.h" #include "ats.h" /** * Context for sending messages to clients. */ static struct GNUNET_SERVER_NotificationContext *nc; /** * Actual handle to the client. */ static struct GNUNET_SERVER_Client *my_client; /** * Register a new scheduling client. * * @param client handle of the new client * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GAS_scheduling_add_client (struct GNUNET_SERVER_Client *client) { if (my_client != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "This ATS already has a scheduling client, refusing new scheduling client for now.\n"); return GNUNET_SYSERR; } my_client = client; GNUNET_SERVER_notification_context_add (nc, client); return GNUNET_OK; } /** * Unregister a client (which may have been a scheduling client, * but this is not assured). * * @param client handle of the (now dead) client */ void GAS_scheduling_remove_client (struct GNUNET_SERVER_Client *client) { if (my_client != client) return; GAS_addresses_destroy_all (); my_client = NULL; } /** * Transmit the given address suggestion and bandwidth update to all scheduling * clients. * * @param peer peer for which this is an address suggestion * @param plugin_name 0-termintated string specifying the transport plugin * @param plugin_addr binary address for the plugin to use * @param plugin_addr_len number of bytes in plugin_addr * @param session_id session ID to use for the given client (other clients will see 0) * @param atsi performance data for the address * @param atsi_count number of performance records in 'ats' * @param bandwidth_out assigned outbound bandwidth * @param bandwidth_in assigned inbound bandwidth */ void GAS_scheduling_transmit_address_suggestion (const struct GNUNET_PeerIdentity *peer, const char *plugin_name, const void *plugin_addr, size_t plugin_addr_len, uint32_t session_id, const struct GNUNET_ATS_Information *atsi, uint32_t atsi_count, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in) { struct AddressSuggestionMessage *msg; size_t plugin_name_length = strlen (plugin_name) + 1; size_t msize = sizeof (struct AddressSuggestionMessage) + atsi_count * sizeof (struct GNUNET_ATS_Information) + plugin_addr_len + plugin_name_length; char buf[msize] GNUNET_ALIGN; struct GNUNET_ATS_Information *atsp; char *addrp; if (my_client == NULL) return; GNUNET_STATISTICS_update (GSA_stats, "# address suggestions made", 1, GNUNET_NO); GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE); GNUNET_assert (atsi_count < GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information)); msg = (struct AddressSuggestionMessage *) buf; msg->header.size = htons (msize); msg->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION); msg->ats_count = htonl (atsi_count); msg->peer = *peer; msg->address_length = htons (plugin_addr_len); msg->plugin_name_length = htons (plugin_name_length); msg->session_id = htonl (session_id); msg->bandwidth_out = bandwidth_out; msg->bandwidth_in = bandwidth_in; atsp = (struct GNUNET_ATS_Information *) &msg[1]; memcpy (atsp, atsi, sizeof (struct GNUNET_ATS_Information) * atsi_count); addrp = (char *) &atsp[atsi_count]; memcpy (addrp, plugin_addr, plugin_addr_len); strcpy (&addrp[plugin_addr_len], plugin_name); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS sends quota for peer `%s': (in/out) %u/%u\n", GNUNET_i2s (peer), ntohl (bandwidth_in.value__), ntohl (bandwidth_out.value__)); GNUNET_SERVER_notification_context_unicast (nc, my_client, &msg->header, GNUNET_YES); } /** * Handle 'request address' messages from clients. * * @param cls unused, NULL * @param client client that sent the request * @param message the request message */ void GAS_handle_request_address (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct RequestAddressMessage *msg = (const struct RequestAddressMessage *) message; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "REQUEST_ADDRESS"); GNUNET_STATISTICS_update (GSA_stats, "# address requests received", 1, GNUNET_NO); GNUNET_break (0 == ntohl (msg->reserved)); GAS_addresses_request_address (&msg->peer); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Handle 'request address' messages from clients. * * @param cls unused, NULL * @param client client that sent the request * @param message the request message */ void GAS_handle_request_address_cancel (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct RequestAddressMessage *msg = (const struct RequestAddressMessage *) message; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "REQUEST_ADDRESS_CANCEL"); GNUNET_break (0 == ntohl (msg->reserved)); /* TODO */ GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Handle 'reset backoff' messages from clients. * * @param cls unused, NULL * @param client client that sent the request * @param message the request message */ void GAS_handle_reset_backoff (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct ResetBackoffMessage *msg = (const struct ResetBackoffMessage *) message; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "RESET_BACKOFF"); GNUNET_STATISTICS_update (GSA_stats, "# backoff reset requests received", 1, GNUNET_NO); GNUNET_break (0 == ntohl (msg->reserved)); GAS_addresses_handle_backoff_reset (&msg->peer); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Handle 'address update' messages from clients. * * @param cls unused, NULL * @param client client that sent the request * @param message the request message */ void GAS_handle_address_update (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct AddressUpdateMessage *m; const struct GNUNET_ATS_Information *atsi; const char *address; const char *plugin_name; uint16_t address_length; uint16_t plugin_name_length; uint32_t ats_count; uint16_t size; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ADDRESS_UPDATE"); size = ntohs (message->size); if (size < sizeof (struct AddressUpdateMessage)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } m = (const struct AddressUpdateMessage *) message; ats_count = ntohl (m->ats_count); address_length = ntohs (m->address_length); plugin_name_length = ntohs (m->plugin_name_length); atsi = (const struct GNUNET_ATS_Information *) &m[1]; address = (const char *) &atsi[ats_count]; if (plugin_name_length != 0) plugin_name = &address[address_length]; else plugin_name = ""; if ((address_length + plugin_name_length + ats_count * sizeof (struct GNUNET_ATS_Information) + sizeof (struct AddressUpdateMessage) != ntohs (message->size)) || (ats_count > GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information)) || ((plugin_name_length > 0) && (plugin_name[plugin_name_length - 1] != '\0'))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_STATISTICS_update (GSA_stats, "# address updates received", 1, GNUNET_NO); GAS_addresses_update (&m->peer, plugin_name, address, address_length, ntohl (m->session_id), atsi, ats_count); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Handle 'address in use' messages from clients. * * @param cls unused, NULL * @param client client that sent the request * @param message the request message */ void GAS_handle_address_in_use (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct AddressUseMessage *m; const char *address; const char *plugin_name; int res; uint16_t address_length; uint16_t plugin_name_length; uint16_t size; uint16_t in_use; size = ntohs (message->size); if (size < sizeof (struct AddressUseMessage)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } m = (const struct AddressUseMessage *) message; address_length = ntohs (m->address_length); plugin_name_length = ntohs (m->plugin_name_length); address = (const char *) &m[1]; if (plugin_name_length != 0) plugin_name = &address[address_length]; else plugin_name = ""; if ((address_length + plugin_name_length + sizeof (struct AddressUseMessage) != ntohs (message->size)) || ((plugin_name_length > 0) && (plugin_name[plugin_name_length - 1] != '\0'))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } in_use = ntohs (m->in_use); res = GAS_addresses_in_use (&m->peer, plugin_name, address, address_length, ntohl (m->session_id), in_use); if (res == GNUNET_OK) GNUNET_SERVER_receive_done (client, GNUNET_OK); else { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); } } /** * Handle 'address destroyed' messages from clients. * * @param cls unused, NULL * @param client client that sent the request * @param message the request message */ void GAS_handle_address_destroyed (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct AddressDestroyedMessage *m; struct SessionReleaseMessage srm; const char *address; const char *plugin_name; uint16_t address_length; uint16_t plugin_name_length; uint16_t size; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message of size %u %u\n", "ADDRESS_DESTROYED", ntohs (message->size), sizeof (struct AddressDestroyedMessage)); size = ntohs (message->size); if ((size < sizeof (struct AddressDestroyedMessage)) || (client != my_client)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } m = (const struct AddressDestroyedMessage *) message; GNUNET_break (0 == ntohl (m->reserved)); address_length = ntohs (m->address_length); plugin_name_length = ntohs (m->plugin_name_length); address = (const char *) &m[1]; if (plugin_name_length != 0) plugin_name = &address[address_length]; else plugin_name = ""; if ((address_length + plugin_name_length + sizeof (struct AddressDestroyedMessage) != ntohs (message->size))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } if ((plugin_name_length == 0) || (plugin_name[plugin_name_length - 1] != '\0')) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_STATISTICS_update (GSA_stats, "# addresses destroyed", 1, GNUNET_NO); GAS_addresses_destroy (&m->peer, plugin_name, address, address_length, ntohl (m->session_id)); if (0 != ntohl (m->session_id)) { srm.header.type = ntohs (GNUNET_MESSAGE_TYPE_ATS_SESSION_RELEASE); srm.header.size = ntohs (sizeof (struct SessionReleaseMessage)); srm.session_id = m->session_id; srm.peer = m->peer; GNUNET_SERVER_notification_context_unicast (nc, client, &srm.header, GNUNET_NO); } GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Initialize scheduling subsystem. * * @param server handle to our server */ void GAS_scheduling_init (struct GNUNET_SERVER_Handle *server) { nc = GNUNET_SERVER_notification_context_create (server, 128); } /** * Shutdown scheduling subsystem. */ void GAS_scheduling_done () { if (NULL != my_client) { my_client = NULL; } GNUNET_SERVER_notification_context_destroy (nc); nc = NULL; } /* end of gnunet-service-ats_scheduling.c */ gnunet-0.9.3/src/exit/0000755000175000017500000000000011763406750011575 500000000000000gnunet-0.9.3/src/exit/exit.h0000644000175000017500000001737111760502551012641 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file exit/exit.h * @brief format for mesh messages exchanged between VPN service and exit daemon * @author Christian Grothoff */ #ifndef EXIT_H #define EXIT_H #include "gnunet_util_lib.h" GNUNET_NETWORK_STRUCT_BEGIN /** * Message send via mesh to an exit daemon to initiate forwarding of * TCP data to a local service. */ struct GNUNET_EXIT_TcpServiceStartMessage { /** * Type is GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START */ struct GNUNET_MessageHeader header; /** * Always 0. */ uint32_t reserved GNUNET_PACKED; /** * Identification for the desired service. */ GNUNET_HashCode service_descriptor; /** * Skeleton of the TCP header to send. Port numbers are to * be replaced and the checksum may be updated as necessary. */ struct GNUNET_TUN_TcpHeader tcp_header; /* followed by TCP payload */ }; /** * Message send via mesh to an exit daemon to initiate forwarding of * TCP data to the Internet. */ struct GNUNET_EXIT_TcpInternetStartMessage { /** * Type is GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START */ struct GNUNET_MessageHeader header; /** * Address family, AF_INET or AF_INET6, in network byte order. */ int32_t af GNUNET_PACKED; /** * Skeleton of the TCP header to send. Port numbers are to * be replaced and the checksum may be updated as necessary. */ struct GNUNET_TUN_TcpHeader tcp_header; /* followed by IP address of the destination; either 'struct in_addr' or 'struct in6_addr', depending on af */ /* followed by TCP payload */ }; /** * Message send via mesh between VPN and entry and an exit daemon to * transmit TCP data between the VPN entry and an exit session. This * format is used for both Internet-exits and service-exits and * in both directions (VPN to exit and exit to VPN). */ struct GNUNET_EXIT_TcpDataMessage { /** * Type is GNUNET_MESSAGE_TYPE_VPN_TCP_DATA */ struct GNUNET_MessageHeader header; /** * Always 0. */ uint32_t reserved GNUNET_PACKED; /** * Skeleton of the TCP header to send. Port numbers are to * be replaced and the checksum may be updated as necessary. (The destination port number should not be changed, as it contains the desired destination port.) */ struct GNUNET_TUN_TcpHeader tcp_header; /* followed by TCP payload */ }; /** * Message send via mesh to an exit daemon to send * UDP data to a local service. */ struct GNUNET_EXIT_UdpServiceMessage { /** * Type is GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE */ struct GNUNET_MessageHeader header; /** * Source port to use for the UDP request (0 to use a random port). In NBO. */ uint16_t source_port GNUNET_PACKED; /** * Destination port to use for the UDP request. In NBO. */ uint16_t destination_port GNUNET_PACKED; /** * Identification for the desired service. */ GNUNET_HashCode service_descriptor; /* followed by UDP payload */ }; /** * Message send via mesh to an exit daemon to forward * UDP data to the Internet. */ struct GNUNET_EXIT_UdpInternetMessage { /** * Type is GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET */ struct GNUNET_MessageHeader header; /** * Address family, AF_INET or AF_INET6, in network byte order. */ int32_t af GNUNET_PACKED; /** * Source port to use for the UDP request (0 to use a random port). In NBO. */ uint16_t source_port GNUNET_PACKED; /** * Destination port to use for the UDP request. In NBO. */ uint16_t destination_port GNUNET_PACKED; /* followed by IP address of the destination; either 'struct in_addr' or 'struct in6_addr', depending on af */ /* followed by UDP payload */ }; /** * Message send from exit daemon back to the UDP entry point * (used for both Internet and Service exit replies). */ struct GNUNET_EXIT_UdpReplyMessage { /** * Type is GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY */ struct GNUNET_MessageHeader header; /** * Source port to use for the UDP reply (0 to use the same * port as for the original request). In NBO. */ uint16_t source_port GNUNET_PACKED; /** * Destination port to use for the UDP reply (0 to use the same * port as for the original request). In NBO. */ uint16_t destination_port GNUNET_PACKED; /* followed by UDP payload */ }; /** * Message send via mesh to an exit daemon to send * ICMP data to a local service. */ struct GNUNET_EXIT_IcmpServiceMessage { /** * Type is GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE */ struct GNUNET_MessageHeader header; /** * Address family, AF_INET or AF_INET6, in network byte order. This * AF value determines if the 'icmp_header' is ICMPv4 or ICMPv6. * The receiver (exit) may still have to translate (PT) to the services' * ICMP version (if possible). */ int32_t af GNUNET_PACKED; /** * Identification for the desired service. */ GNUNET_HashCode service_descriptor; /** * ICMP header to use. */ struct GNUNET_TUN_IcmpHeader icmp_header; /* followed by ICMP payload; however, for certain ICMP message types where the payload is the original IP packet, the payload is omitted as it is useless for the receiver (who will need to create some fake payload manually) */ }; /** * Message send via mesh to an exit daemon to forward * ICMP data to the Internet. */ struct GNUNET_EXIT_IcmpInternetMessage { /** * Type is GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET */ struct GNUNET_MessageHeader header; /** * Address family, AF_INET or AF_INET6, in network byte order. * Determines both the ICMP version used in the 'icmp_header' and * the IP address format that is used for the target IP. If * PT is necessary, the sender has already done it. */ int32_t af GNUNET_PACKED; /** * ICMP header to use. Must match the target 'af' given * above. */ struct GNUNET_TUN_IcmpHeader icmp_header; /* followed by IP address of the destination; either 'struct in_addr' or 'struct in6_addr', depending on af */ /* followed by ICMP payload; however, for certain ICMP message types where the payload is the original IP packet, the payload is omitted as it is useless for the receiver (who will need to create some fake payload manually) */ }; /** * Message send via mesh to the vpn service to send * ICMP data to the VPN's TUN interface. */ struct GNUNET_EXIT_IcmpToVPNMessage { /** * Type is GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN */ struct GNUNET_MessageHeader header; /** * Address family, AF_INET or AF_INET6, in network byte order. * Useful to determine if this is an ICMPv4 or ICMPv6 header. */ int32_t af GNUNET_PACKED; /** * ICMP header to use. ICMPv4 or ICMPv6, depending on 'af'. */ struct GNUNET_TUN_IcmpHeader icmp_header; /* followed by ICMP payload; however, for certain ICMP message types where the payload is the original IP packet, the payload is omitted as it is useless for the receiver (who will need to create some fake payload manually) */ }; GNUNET_NETWORK_STRUCT_END #endif gnunet-0.9.3/src/exit/Makefile.am0000644000175000017500000000165211705345004013543 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 endif pkgcfgdir= $(pkgdatadir)/config.d/ plugindir = $(libdir)/gnunet dist_pkgcfg_DATA = \ exit.conf if LINUX EXITBIN = gnunet-helper-exit install-exec-hook: $(SUDO_BINARY) chown root:root $(bindir)/gnunet-helper-exit || true $(SUDO_BINARY) chmod u+s $(bindir)/gnunet-helper-exit || true else install-exec-hook: endif bin_PROGRAMS = \ gnunet-daemon-exit $(EXITBIN) gnunet_helper_exit_SOURCES = \ gnunet-helper-exit.c gnunet_daemon_exit_SOURCES = \ gnunet-daemon-exit.c exit.h gnunet_daemon_exit_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/tun/libgnunettun.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(GN_LIBINTL) gnunet-0.9.3/src/exit/exit.conf0000644000175000017500000000276311710067400013330 00000000000000[exit] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-exit # IPv6 address for the TUN interface (must be changed as this # must be within the global IPv6 range of your system!) IPV6ADDR = 2001:DB8::1 # Prefix for our IPv6 subnet on the TUN interface. IPV6PREFIX = 64 # IPv4 address to use on our TUN interface (may need to be # changed to avoid conflicts with existing addresses on your system). # Use RFC 3927-style link-local address IPV4ADDR = 169.254.86.1 # Netmask for the IPv4 subnet on the TUN interface. IPV4MASK = 255.255.255.0 # Name of the (virtual) tunnel interface the exit daemon will manage TUN_IFNAME = exit-gnunet # Name of the "real" interface that IPv4 traffic from this system will # leave from; this is the name of the interface where we need to # enable NAT on postrouting (typically something like 'eth0' or 'eth1' # or 'wlan0'). Not needed if EXIT_IPv4 is disabled AND if all # offered services run on 'localhost'. In this case, the value # of the option can instead be set to "%" (to not enable NAT on any # interface). EXIT_IFNAME = eth0 # Set this to YES to allow exiting this system via IPv4 to the Internet EXIT_IPV4 = NO # Set this to YES to allow exiting this system via IPv6 to the Internet EXIT_IPV6 = NO # For IPv4-services offered by this peer, we need to at least enable IPv4 ENABLE_IPV4 = YES # For IPv6-services offered by this peer, we need to at least enable IPv6 ENABLE_IPV6 = YES # Maximum number of concurrent connections this exit supports. MAX_CONNECTIONS = 256 gnunet-0.9.3/src/exit/gnunet-daemon-exit.c0000644000175000017500000026613411760502551015376 00000000000000/* This file is part of GNUnet. (C) 2010, 2012 Christian Grothoff GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file exit/gnunet-daemon-exit.c * @brief tool to allow IP traffic exit from the GNUnet mesh to the Internet * @author Philipp Toelke * @author Christian Grothoff * * TODO: * - test * * Design: * - which code should advertise services? the service model is right * now a bit odd, especially as this code DOES the exit and knows * the DNS "name", but OTOH this is clearly NOT the place to advertise * the service's existence; maybe the daemon should turn into a * service with an API to add local-exit services dynamically? */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_protocols.h" #include "gnunet_applications.h" #include "gnunet_mesh_service.h" #include "gnunet_statistics_service.h" #include "gnunet_constants.h" #include "gnunet_tun_lib.h" #include "exit.h" /** * Information about an address. */ struct SocketAddress { /** * AF_INET or AF_INET6. */ int af; /** * Remote address information. */ union { /** * Address, if af is AF_INET. */ struct in_addr ipv4; /** * Address, if af is AF_INET6. */ struct in6_addr ipv6; } address; /** * IPPROTO_TCP or IPPROTO_UDP; */ uint8_t proto; /** * Remote port, in host byte order! */ uint16_t port; }; /** * This struct is saved into the services-hashmap to represent * a service this peer is specifically offering an exit for * (for a specific domain name). */ struct LocalService { /** * Remote address to use for the service. */ struct SocketAddress address; /** * DNS name of the service. */ char *name; /** * Port I am listening on within GNUnet for this service, in host * byte order. (as we may redirect ports). */ uint16_t my_port; }; /** * Information we use to track a connection (the classical 6-tuple of * IP-version, protocol, source-IP, destination-IP, source-port and * destinatin-port. */ struct RedirectInformation { /** * Address information for the other party (equivalent of the * arguments one would give to "connect"). */ struct SocketAddress remote_address; /** * Address information we used locally (AF and proto must match * "remote_address"). Equivalent of the arguments one would give to * "bind". */ struct SocketAddress local_address; /* Note 1: additional information might be added here in the future to support protocols that require special handling, such as ftp/tftp Note 2: we might also sometimes not match on all components of the tuple, to support protocols where things do not always fully map. */ }; /** * Queue of messages to a tunnel. */ struct TunnelMessageQueue { /** * This is a doubly-linked list. */ struct TunnelMessageQueue *next; /** * This is a doubly-linked list. */ struct TunnelMessageQueue *prev; /** * Payload to send via the tunnel. */ const void *payload; /** * Number of bytes in 'payload'. */ size_t len; }; /** * This struct is saved into connections_map to allow finding the * right tunnel given an IP packet from TUN. It is also associated * with the tunnel's closure so we can find it again for the next * message from the tunnel. */ struct TunnelState { /** * Mesh tunnel that is used for this connection. */ struct GNUNET_MESH_Tunnel *tunnel; /** * Heap node for this state in the connections_heap. */ struct GNUNET_CONTAINER_HeapNode *heap_node; /** * Key this state has in the connections_map. */ GNUNET_HashCode state_key; /** * Associated service record, or NULL for no service. */ struct LocalService *serv; /** * Head of DLL of messages for this tunnel. */ struct TunnelMessageQueue *head; /** * Tail of DLL of messages for this tunnel. */ struct TunnelMessageQueue *tail; /** * Active tunnel transmission request (or NULL). */ struct GNUNET_MESH_TransmitHandle *th; /** * Primary redirection information for this connection. */ struct RedirectInformation ri; }; /** * Return value from 'main'. */ static int global_ret; /** * The handle to the configuration used throughout the process */ static const struct GNUNET_CONFIGURATION_Handle *cfg; /** * The handle to the helper */ static struct GNUNET_HELPER_Handle *helper_handle; /** * Arguments to the exit helper. */ static char *exit_argv[8]; /** * IPv6 address of our TUN interface. */ static struct in6_addr exit_ipv6addr; /** * IPv6 prefix (0..127) from configuration file. */ static unsigned long long ipv6prefix; /** * IPv4 address of our TUN interface. */ static struct in_addr exit_ipv4addr; /** * IPv4 netmask of our TUN interface. */ static struct in_addr exit_ipv4mask; /** * Statistics. */ static struct GNUNET_STATISTICS_Handle *stats; /** * The handle to mesh */ static struct GNUNET_MESH_Handle *mesh_handle; /** * This hashmaps contains the mapping from peer, service-descriptor, * source-port and destination-port to a struct TunnelState */ static struct GNUNET_CONTAINER_MultiHashMap *connections_map; /** * Heap so we can quickly find "old" connections. */ static struct GNUNET_CONTAINER_Heap *connections_heap; /** * If there are at least this many connections, old ones will be removed */ static unsigned long long max_connections; /** * This hashmaps saves interesting things about the configured UDP services */ static struct GNUNET_CONTAINER_MultiHashMap *udp_services; /** * This hashmaps saves interesting things about the configured TCP services */ static struct GNUNET_CONTAINER_MultiHashMap *tcp_services; /** * Are we an IPv4-exit? */ static int ipv4_exit; /** * Are we an IPv6-exit? */ static int ipv6_exit; /** * Do we support IPv4 at all on the TUN interface? */ static int ipv4_enabled; /** * Do we support IPv6 at all on the TUN interface? */ static int ipv6_enabled; /** * Given IP information about a connection, calculate the respective * hash we would use for the 'connections_map'. * * @param hash resulting hash * @param ri information about the connection */ static void hash_redirect_info (GNUNET_HashCode *hash, const struct RedirectInformation *ri) { char *off; memset (hash, 0, sizeof (GNUNET_HashCode)); /* the GNUnet hashmap only uses the first sizeof(unsigned int) of the hash, so we put the IP address in there (and hope for few collisions) */ off = (char*) hash; switch (ri->remote_address.af) { case AF_INET: memcpy (off, &ri->remote_address.address.ipv4, sizeof (struct in_addr)); off += sizeof (struct in_addr); break; case AF_INET6: memcpy (off, &ri->remote_address.address.ipv6, sizeof (struct in6_addr)); off += sizeof (struct in_addr); break; default: GNUNET_assert (0); } memcpy (off, &ri->remote_address.port, sizeof (uint16_t)); off += sizeof (uint16_t); switch (ri->local_address.af) { case AF_INET: memcpy (off, &ri->local_address.address.ipv4, sizeof (struct in_addr)); off += sizeof (struct in_addr); break; case AF_INET6: memcpy (off, &ri->local_address.address.ipv6, sizeof (struct in6_addr)); off += sizeof (struct in_addr); break; default: GNUNET_assert (0); } memcpy (off, &ri->local_address.port, sizeof (uint16_t)); off += sizeof (uint16_t); memcpy (off, &ri->remote_address.proto, sizeof (uint8_t)); off += sizeof (uint8_t); } /** * Get our connection tracking state. Warns if it does not exists, * refreshes the timestamp if it does exist. * * @param af address family * @param protocol IPPROTO_UDP or IPPROTO_TCP * @param destination_ip target IP * @param destination_port target port * @param local_ip local IP * @param local_port local port * @param state_key set to hash's state if non-NULL * @return NULL if we have no tracking information for this tuple */ static struct TunnelState * get_redirect_state (int af, int protocol, const void *destination_ip, uint16_t destination_port, const void *local_ip, uint16_t local_port, GNUNET_HashCode *state_key) { struct RedirectInformation ri; GNUNET_HashCode key; struct TunnelState *state; if ( ( (af == AF_INET) && (protocol == IPPROTO_ICMP) ) || ( (af == AF_INET6) && (protocol == IPPROTO_ICMPV6) ) ) { /* ignore ports */ destination_port = 0; local_port = 0; } ri.remote_address.af = af; if (af == AF_INET) ri.remote_address.address.ipv4 = *((struct in_addr*) destination_ip); else ri.remote_address.address.ipv6 = * ((struct in6_addr*) destination_ip); ri.remote_address.port = destination_port; ri.remote_address.proto = protocol; ri.local_address.af = af; if (af == AF_INET) ri.local_address.address.ipv4 = *((struct in_addr*) local_ip); else ri.local_address.address.ipv6 = * ((struct in6_addr*) local_ip); ri.local_address.port = local_port; ri.local_address.proto = protocol; hash_redirect_info (&key, &ri); if (NULL != state_key) *state_key = key; state = GNUNET_CONTAINER_multihashmap_get (connections_map, &key); if (NULL == state) return NULL; /* Mark this connection as freshly used */ if (NULL == state_key) GNUNET_CONTAINER_heap_update_cost (connections_heap, state->heap_node, GNUNET_TIME_absolute_get ().abs_value); return state; } /** * Given a service descriptor and a destination port, find the * respective service entry. * * @param service_map map of services (TCP or UDP) * @param desc service descriptor * @param destination_port destination port * @return NULL if we are not aware of such a service */ static struct LocalService * find_service (struct GNUNET_CONTAINER_MultiHashMap *service_map, const GNUNET_HashCode *desc, uint16_t destination_port) { char key[sizeof (GNUNET_HashCode) + sizeof (uint16_t)]; memcpy (&key[0], &destination_port, sizeof (uint16_t)); memcpy (&key[sizeof(uint16_t)], desc, sizeof (GNUNET_HashCode)); return GNUNET_CONTAINER_multihashmap_get (service_map, (GNUNET_HashCode *) key); } /** * Free memory associated with a service record. * * @param cls unused * @param key service descriptor * @param value service record to free * @return GNUNET_OK */ static int free_service_record (void *cls, const GNUNET_HashCode *key, void *value) { struct LocalService *service = value; GNUNET_free_non_null (service->name); GNUNET_free (service); return GNUNET_OK; } /** * Given a service descriptor and a destination port, find the * respective service entry. * * @param service_map map of services (TCP or UDP) * @param name name of the service * @param destination_port destination port * @param service service information record to store (service->name will be set). */ static void store_service (struct GNUNET_CONTAINER_MultiHashMap *service_map, const char *name, uint16_t destination_port, struct LocalService *service) { char key[sizeof (GNUNET_HashCode) + sizeof (uint16_t)]; GNUNET_HashCode desc; GNUNET_CRYPTO_hash (name, strlen (name) + 1, &desc); service->name = GNUNET_strdup (name); memcpy (&key[0], &destination_port, sizeof (uint16_t)); memcpy (&key[sizeof(uint16_t)], &desc, sizeof (GNUNET_HashCode)); if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (service_map, (GNUNET_HashCode *) key, service, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) { free_service_record (NULL, (GNUNET_HashCode *) key, service); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Got duplicate service records for `%s:%u'\n"), name, (unsigned int) destination_port); } } /** * MESH is ready to receive a message for the tunnel. Transmit it. * * @param cls the 'struct TunnelState'. * @param size number of bytes available in buf * @param buf where to copy the message * @return number of bytes copied to buf */ static size_t send_to_peer_notify_callback (void *cls, size_t size, void *buf) { struct TunnelState *s = cls; struct GNUNET_MESH_Tunnel *tunnel = s->tunnel; struct TunnelMessageQueue *tnq; s->th = NULL; tnq = s->head; if (NULL == tnq) return 0; if (0 == size) { s->th = GNUNET_MESH_notify_transmit_ready (tunnel, GNUNET_NO /* corking */, 0 /* priority */, GNUNET_TIME_UNIT_FOREVER_REL, NULL, tnq->len, &send_to_peer_notify_callback, s); return 0; } GNUNET_assert (size >= tnq->len); memcpy (buf, tnq->payload, tnq->len); size = tnq->len; GNUNET_CONTAINER_DLL_remove (s->head, s->tail, tnq); GNUNET_free (tnq); if (NULL != (tnq = s->head)) s->th = GNUNET_MESH_notify_transmit_ready (tunnel, GNUNET_NO /* corking */, 0 /* priority */, GNUNET_TIME_UNIT_FOREVER_REL, NULL, tnq->len, &send_to_peer_notify_callback, s); GNUNET_STATISTICS_update (stats, gettext_noop ("# Bytes transmitted via mesh tunnels"), size, GNUNET_NO); return size; } /** * Send the given packet via the mesh tunnel. * * @param mesh_tunnel destination * @param tnq message to queue */ static void send_packet_to_mesh_tunnel (struct GNUNET_MESH_Tunnel *mesh_tunnel, struct TunnelMessageQueue *tnq) { struct TunnelState *s; s = GNUNET_MESH_tunnel_get_data (mesh_tunnel); GNUNET_assert (NULL != s); GNUNET_CONTAINER_DLL_insert_tail (s->head, s->tail, tnq); if (NULL == s->th) s->th = GNUNET_MESH_notify_transmit_ready (mesh_tunnel, GNUNET_NO /* cork */, 0 /* priority */, GNUNET_TIME_UNIT_FOREVER_REL, NULL, tnq->len, &send_to_peer_notify_callback, s); } /** * @brief Handles an ICMP packet received from the helper. * * @param icmp A pointer to the Packet * @param pktlen number of bytes in 'icmp' * @param af address family (AFINET or AF_INET6) * @param destination_ip destination IP-address of the IP packet (should * be our local address) * @param source_ip original source IP-address of the IP packet (should * be the original destination address) */ static void icmp_from_helper (const struct GNUNET_TUN_IcmpHeader *icmp, size_t pktlen, int af, const void *destination_ip, const void *source_ip) { struct TunnelState *state; struct TunnelMessageQueue *tnq; struct GNUNET_EXIT_IcmpToVPNMessage *i2v; const struct GNUNET_TUN_IPv4Header *ipv4; const struct GNUNET_TUN_IPv6Header *ipv6; const struct GNUNET_TUN_UdpHeader *udp; size_t mlen; uint16_t source_port; uint16_t destination_port; uint8_t protocol; { char sbuf[INET6_ADDRSTRLEN]; char dbuf[INET6_ADDRSTRLEN]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ICMP packet going from %s to %s\n", inet_ntop (af, source_ip, sbuf, sizeof (sbuf)), inet_ntop (af, destination_ip, dbuf, sizeof (dbuf))); } if (pktlen < sizeof (struct GNUNET_TUN_IcmpHeader)) { /* blame kernel */ GNUNET_break (0); return; } /* Find out if this is an ICMP packet in response to an existing TCP/UDP packet and if so, figure out ports / protocol of the existing session from the IP data in the ICMP payload */ source_port = 0; destination_port = 0; switch (af) { case AF_INET: protocol = IPPROTO_ICMP; switch (icmp->type) { case GNUNET_TUN_ICMPTYPE_ECHO_REPLY: case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST: break; case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE: case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH: case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED: if (pktlen < sizeof (struct GNUNET_TUN_IcmpHeader) + sizeof (struct GNUNET_TUN_IPv4Header) + 8) { /* blame kernel */ GNUNET_break (0); return; } ipv4 = (const struct GNUNET_TUN_IPv4Header *) &icmp[1]; protocol = ipv4->protocol; /* could be TCP or UDP, but both have the ports in the right place, so that doesn't matter here */ udp = (const struct GNUNET_TUN_UdpHeader *) &ipv4[1]; /* swap ports, as they are from the original message */ destination_port = ntohs (udp->source_port); source_port = ntohs (udp->destination_port); /* throw away ICMP payload, won't be useful for the other side anyway */ pktlen = sizeof (struct GNUNET_TUN_IcmpHeader); break; default: GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv4 packets dropped (type not allowed)"), 1, GNUNET_NO); return; } break; case AF_INET6: protocol = IPPROTO_ICMPV6; switch (icmp->type) { case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE: case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG: case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED: case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM: if (pktlen < sizeof (struct GNUNET_TUN_IcmpHeader) + sizeof (struct GNUNET_TUN_IPv6Header) + 8) { /* blame kernel */ GNUNET_break (0); return; } ipv6 = (const struct GNUNET_TUN_IPv6Header *) &icmp[1]; protocol = ipv6->next_header; /* could be TCP or UDP, but both have the ports in the right place, so that doesn't matter here */ udp = (const struct GNUNET_TUN_UdpHeader *) &ipv6[1]; /* swap ports, as they are from the original message */ destination_port = ntohs (udp->source_port); source_port = ntohs (udp->destination_port); /* throw away ICMP payload, won't be useful for the other side anyway */ pktlen = sizeof (struct GNUNET_TUN_IcmpHeader); break; case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST: case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY: break; default: GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv6 packets dropped (type not allowed)"), 1, GNUNET_NO); return; } break; default: GNUNET_assert (0); } switch (protocol) { case IPPROTO_ICMP: state = get_redirect_state (af, IPPROTO_ICMP, source_ip, 0, destination_ip, 0, NULL); break; case IPPROTO_ICMPV6: state = get_redirect_state (af, IPPROTO_ICMPV6, source_ip, 0, destination_ip, 0, NULL); break; case IPPROTO_UDP: state = get_redirect_state (af, IPPROTO_UDP, source_ip, source_port, destination_ip, destination_port, NULL); break; case IPPROTO_TCP: state = get_redirect_state (af, IPPROTO_TCP, source_ip, source_port, destination_ip, destination_port, NULL); break; default: GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMP packets dropped (not allowed)"), 1, GNUNET_NO); return; } if (NULL == state) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("ICMP Packet dropped, have no matching connection information\n")); return; } mlen = sizeof (struct GNUNET_EXIT_IcmpToVPNMessage) + pktlen - sizeof (struct GNUNET_TUN_IcmpHeader); tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueue) + mlen); tnq->payload = &tnq[1]; tnq->len = mlen; i2v = (struct GNUNET_EXIT_IcmpToVPNMessage *) &tnq[1]; i2v->header.size = htons ((uint16_t) mlen); i2v->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN); i2v->af = htonl (af); memcpy (&i2v->icmp_header, icmp, pktlen); send_packet_to_mesh_tunnel (state->tunnel, tnq); } /** * @brief Handles an UDP packet received from the helper. * * @param udp A pointer to the Packet * @param pktlen number of bytes in 'udp' * @param af address family (AFINET or AF_INET6) * @param destination_ip destination IP-address of the IP packet (should * be our local address) * @param source_ip original source IP-address of the IP packet (should * be the original destination address) */ static void udp_from_helper (const struct GNUNET_TUN_UdpHeader *udp, size_t pktlen, int af, const void *destination_ip, const void *source_ip) { struct TunnelState *state; struct TunnelMessageQueue *tnq; struct GNUNET_EXIT_UdpReplyMessage *urm; size_t mlen; { char sbuf[INET6_ADDRSTRLEN]; char dbuf[INET6_ADDRSTRLEN]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received UDP packet going from %s:%u to %s:%u\n", inet_ntop (af, source_ip, sbuf, sizeof (sbuf)), (unsigned int) ntohs (udp->source_port), inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)), (unsigned int) ntohs (udp->destination_port)); } if (pktlen < sizeof (struct GNUNET_TUN_UdpHeader)) { /* blame kernel */ GNUNET_break (0); return; } if (pktlen != ntohs (udp->len)) { /* blame kernel */ GNUNET_break (0); return; } state = get_redirect_state (af, IPPROTO_UDP, source_ip, ntohs (udp->source_port), destination_ip, ntohs (udp->destination_port), NULL); if (NULL == state) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("UDP Packet dropped, have no matching connection information\n")); return; } mlen = sizeof (struct GNUNET_EXIT_UdpReplyMessage) + pktlen - sizeof (struct GNUNET_TUN_UdpHeader); tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueue) + mlen); tnq->payload = &tnq[1]; tnq->len = mlen; urm = (struct GNUNET_EXIT_UdpReplyMessage *) &tnq[1]; urm->header.size = htons ((uint16_t) mlen); urm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY); urm->source_port = htons (0); urm->destination_port = htons (0); memcpy (&urm[1], &udp[1], pktlen - sizeof (struct GNUNET_TUN_UdpHeader)); send_packet_to_mesh_tunnel (state->tunnel, tnq); } /** * @brief Handles a TCP packet received from the helper. * * @param tcp A pointer to the Packet * @param pktlen the length of the packet, including its TCP header * @param af address family (AFINET or AF_INET6) * @param destination_ip destination IP-address of the IP packet (should * be our local address) * @param source_ip original source IP-address of the IP packet (should * be the original destination address) */ static void tcp_from_helper (const struct GNUNET_TUN_TcpHeader *tcp, size_t pktlen, int af, const void *destination_ip, const void *source_ip) { struct TunnelState *state; char buf[pktlen] GNUNET_ALIGN; struct GNUNET_TUN_TcpHeader *mtcp; struct GNUNET_EXIT_TcpDataMessage *tdm; struct TunnelMessageQueue *tnq; size_t mlen; { char sbuf[INET6_ADDRSTRLEN]; char dbuf[INET6_ADDRSTRLEN]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received TCP packet with %u bytes going from %s:%u to %s:%u\n", pktlen - sizeof (struct GNUNET_TUN_TcpHeader), inet_ntop (af, source_ip, sbuf, sizeof (sbuf)), (unsigned int) ntohs (tcp->source_port), inet_ntop (af, destination_ip, dbuf, sizeof (dbuf)), (unsigned int) ntohs (tcp->destination_port)); } if (pktlen < sizeof (struct GNUNET_TUN_TcpHeader)) { /* blame kernel */ GNUNET_break (0); return; } state = get_redirect_state (af, IPPROTO_TCP, source_ip, ntohs (tcp->source_port), destination_ip, ntohs (tcp->destination_port), NULL); if (NULL == state) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("TCP Packet dropped, have no matching connection information\n")); return; } /* mug port numbers and crc to avoid information leakage; sender will need to lookup the correct values anyway */ memcpy (buf, tcp, pktlen); mtcp = (struct GNUNET_TUN_TcpHeader *) buf; mtcp->source_port = 0; mtcp->destination_port = 0; mtcp->crc = 0; mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) + (pktlen - sizeof (struct GNUNET_TUN_TcpHeader)); if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); return; } tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueue) + mlen); tnq->payload = &tnq[1]; tnq->len = mlen; tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1]; tdm->header.size = htons ((uint16_t) mlen); tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN); tdm->reserved = htonl (0); memcpy (&tdm->tcp_header, buf, pktlen); send_packet_to_mesh_tunnel (state->tunnel, tnq); } /** * Receive packets from the helper-process * * @param cls unused * @param client unsued * @param message message received from helper */ static int message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED, const struct GNUNET_MessageHeader *message) { const struct GNUNET_TUN_Layer2PacketHeader *pkt_tun; size_t size; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got %u-byte message of type %u from gnunet-helper-exit\n", ntohs (message->size), ntohs (message->type)); GNUNET_STATISTICS_update (stats, gettext_noop ("# Packets received from TUN"), 1, GNUNET_NO); if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) { GNUNET_break (0); return GNUNET_OK; } size = ntohs (message->size); if (size < sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_MessageHeader)) { GNUNET_break (0); return GNUNET_OK; } GNUNET_STATISTICS_update (stats, gettext_noop ("# Bytes received from TUN"), size, GNUNET_NO); pkt_tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1]; size -= sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_MessageHeader); switch (ntohs (pkt_tun->proto)) { case ETH_P_IPV4: { const struct GNUNET_TUN_IPv4Header *pkt4; if (size < sizeof (struct GNUNET_TUN_IPv4Header)) { /* Kernel to blame? */ GNUNET_break (0); return GNUNET_OK; } pkt4 = (const struct GNUNET_TUN_IPv4Header *) &pkt_tun[1]; if (size != ntohs (pkt4->total_length)) { /* Kernel to blame? */ GNUNET_break (0); return GNUNET_OK; } if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("IPv4 packet options received. Ignored.\n")); return GNUNET_OK; } size -= sizeof (struct GNUNET_TUN_IPv4Header); switch (pkt4->protocol) { case IPPROTO_UDP: udp_from_helper ((const struct GNUNET_TUN_UdpHeader *) &pkt4[1], size, AF_INET, &pkt4->destination_address, &pkt4->source_address); break; case IPPROTO_TCP: tcp_from_helper ((const struct GNUNET_TUN_TcpHeader *) &pkt4[1], size, AF_INET, &pkt4->destination_address, &pkt4->source_address); break; case IPPROTO_ICMP: icmp_from_helper ((const struct GNUNET_TUN_IcmpHeader *) &pkt4[1], size, AF_INET, &pkt4->destination_address, &pkt4->source_address); break; default: GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("IPv4 packet with unsupported next header %u received. Ignored.\n"), (int) pkt4->protocol); return GNUNET_OK; } } break; case ETH_P_IPV6: { const struct GNUNET_TUN_IPv6Header *pkt6; if (size < sizeof (struct GNUNET_TUN_IPv6Header)) { /* Kernel to blame? */ GNUNET_break (0); return GNUNET_OK; } pkt6 = (struct GNUNET_TUN_IPv6Header *) &pkt_tun[1]; if (size != ntohs (pkt6->payload_length) + sizeof (struct GNUNET_TUN_IPv6Header)) { /* Kernel to blame? */ GNUNET_break (0); return GNUNET_OK; } size -= sizeof (struct GNUNET_TUN_IPv6Header); switch (pkt6->next_header) { case IPPROTO_UDP: udp_from_helper ((const struct GNUNET_TUN_UdpHeader *) &pkt6[1], size, AF_INET6, &pkt6->destination_address, &pkt6->source_address); break; case IPPROTO_TCP: tcp_from_helper ((const struct GNUNET_TUN_TcpHeader *) &pkt6[1], size, AF_INET6, &pkt6->destination_address, &pkt6->source_address); break; case IPPROTO_ICMPV6: icmp_from_helper ((const struct GNUNET_TUN_IcmpHeader *) &pkt6[1], size, AF_INET6, &pkt6->destination_address, &pkt6->source_address); break; default: GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("IPv6 packet with unsupported next header %d received. Ignored.\n"), pkt6->next_header); return GNUNET_OK; } } break; default: GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Packet from unknown protocol %u received. Ignored.\n"), ntohs (pkt_tun->proto)); break; } return GNUNET_OK; } /** * We need to create a (unique) fresh local address (IP+port). * Fill one in. * * @param af desired address family * @param proto desired protocol (IPPROTO_UDP or IPPROTO_TCP) * @param local_address address to initialize */ static void setup_fresh_address (int af, uint8_t proto, struct SocketAddress *local_address) { local_address->af = af; local_address->proto = (uint8_t) proto; /* default "local" port range is often 32768--61000, so we pick a random value in that range */ if ( ( (af == AF_INET) && (proto == IPPROTO_ICMP) ) || ( (af == AF_INET6) && (proto == IPPROTO_ICMPV6) ) ) local_address->port = 0; else local_address->port = (uint16_t) 32768 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 28232); switch (af) { case AF_INET: { struct in_addr addr; struct in_addr mask; struct in_addr rnd; addr = exit_ipv4addr; mask = exit_ipv4mask; if (0 == ~mask.s_addr) { /* only one valid IP anyway */ local_address->address.ipv4 = addr; return; } /* Given 192.168.0.1/255.255.0.0, we want a mask of '192.168.255.255', thus: */ mask.s_addr = addr.s_addr | ~mask.s_addr; /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */ do { rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX); local_address->address.ipv4.s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr; } while ( (local_address->address.ipv4.s_addr == addr.s_addr) || (local_address->address.ipv4.s_addr == mask.s_addr) ); } break; case AF_INET6: { struct in6_addr addr; struct in6_addr mask; struct in6_addr rnd; int i; addr = exit_ipv6addr; GNUNET_assert (ipv6prefix < 128); if (ipv6prefix == 127) { /* only one valid IP anyway */ local_address->address.ipv6 = addr; return; } /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF, thus: */ mask = addr; for (i=127;i>=ipv6prefix;i--) mask.s6_addr[i / 8] |= (1 << (i % 8)); /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */ do { for (i=0;i<16;i++) { rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); local_address->address.ipv6.s6_addr[i] = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i]; } } while ( (0 == memcmp (&local_address->address.ipv6, &addr, sizeof (struct in6_addr))) || (0 == memcmp (&local_address->address.ipv6, &mask, sizeof (struct in6_addr))) ); } break; default: GNUNET_assert (0); } } /** * We are starting a fresh connection (TCP or UDP) and need * to pick a source port and IP address (within the correct * range and address family) to associate replies with the * connection / correct mesh tunnel. This function generates * a "fresh" source IP and source port number for a connection * After picking a good source address, this function sets up * the state in the 'connections_map' and 'connections_heap' * to allow finding the state when needed later. The function * also makes sure that we remain within memory limits by * cleaning up 'old' states. * * @param state skeleton state to setup a record for; should * 'state->ri.remote_address' filled in so that * this code can determine which AF/protocol is * going to be used (the 'tunnel' should also * already be set); after calling this function, * heap_node and the local_address will be * also initialized (heap_node != NULL can be * used to test if a state has been fully setup). */ static void setup_state_record (struct TunnelState *state) { GNUNET_HashCode key; struct TunnelState *s; /* generate fresh, unique address */ do { if (NULL == state->serv) setup_fresh_address (state->ri.remote_address.af, state->ri.remote_address.proto, &state->ri.local_address); else setup_fresh_address (state->serv->address.af, state->serv->address.proto, &state->ri.local_address); } while (NULL != get_redirect_state (state->ri.remote_address.af, state->ri.remote_address.proto, &state->ri.remote_address.address, state->ri.remote_address.port, &state->ri.local_address.address, state->ri.local_address.port, &key)); { char buf[INET6_ADDRSTRLEN]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Picked local address %s:%u for new connection\n", inet_ntop (state->ri.local_address.af, &state->ri.local_address.address, buf, sizeof (buf)), (unsigned int) state->ri.local_address.port); } state->state_key = key; GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (connections_map, &key, state, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); state->heap_node = GNUNET_CONTAINER_heap_insert (connections_heap, state, GNUNET_TIME_absolute_get ().abs_value); while (GNUNET_CONTAINER_heap_get_size (connections_heap) > max_connections) { s = GNUNET_CONTAINER_heap_remove_root (connections_heap); GNUNET_assert (state != s); s->heap_node = NULL; GNUNET_MESH_tunnel_destroy (s->tunnel); GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (connections_map, &s->state_key, s)); GNUNET_free (s); } } /** * Prepare an IPv4 packet for transmission via the TUN interface. * Initializes the IP header and calculates checksums (IP+UDP/TCP). * For UDP, the UDP header will be fully created, whereas for TCP * only the ports and checksum will be filled in. So for TCP, * a skeleton TCP header must be part of the provided payload. * * @param payload payload of the packet (starting with UDP payload or * TCP header, depending on protocol) * @param payload_length number of bytes in 'payload' * @param protocol IPPROTO_UDP or IPPROTO_TCP * @param tcp_header skeleton of the TCP header, NULL for UDP * @param src_address source address to use (IP and port) * @param dst_address destination address to use (IP and port) * @param pkt4 where to write the assembled packet; must * contain enough space for the IP header, UDP/TCP header * AND the payload */ static void prepare_ipv4_packet (const void *payload, size_t payload_length, int protocol, const struct GNUNET_TUN_TcpHeader *tcp_header, const struct SocketAddress *src_address, const struct SocketAddress *dst_address, struct GNUNET_TUN_IPv4Header *pkt4) { size_t len; len = payload_length; switch (protocol) { case IPPROTO_UDP: len += sizeof (struct GNUNET_TUN_UdpHeader); break; case IPPROTO_TCP: len += sizeof (struct GNUNET_TUN_TcpHeader); GNUNET_assert (NULL != tcp_header); break; default: GNUNET_break (0); return; } if (len + sizeof (struct GNUNET_TUN_IPv4Header) > UINT16_MAX) { GNUNET_break (0); return; } GNUNET_TUN_initialize_ipv4_header (pkt4, protocol, len, &src_address->address.ipv4, &dst_address->address.ipv4); switch (protocol) { case IPPROTO_UDP: { struct GNUNET_TUN_UdpHeader *pkt4_udp = (struct GNUNET_TUN_UdpHeader *) &pkt4[1]; pkt4_udp->source_port = htons (src_address->port); pkt4_udp->destination_port = htons (dst_address->port); pkt4_udp->len = htons ((uint16_t) payload_length); GNUNET_TUN_calculate_udp4_checksum (pkt4, pkt4_udp, payload, payload_length); memcpy (&pkt4_udp[1], payload, payload_length); } break; case IPPROTO_TCP: { struct GNUNET_TUN_TcpHeader *pkt4_tcp = (struct GNUNET_TUN_TcpHeader *) &pkt4[1]; *pkt4_tcp = *tcp_header; pkt4_tcp->source_port = htons (src_address->port); pkt4_tcp->destination_port = htons (dst_address->port); GNUNET_TUN_calculate_tcp4_checksum (pkt4, pkt4_tcp, payload, payload_length); memcpy (&pkt4_tcp[1], payload, payload_length); } break; default: GNUNET_assert (0); } } /** * Prepare an IPv6 packet for transmission via the TUN interface. * Initializes the IP header and calculates checksums (IP+UDP/TCP). * For UDP, the UDP header will be fully created, whereas for TCP * only the ports and checksum will be filled in. So for TCP, * a skeleton TCP header must be part of the provided payload. * * @param payload payload of the packet (starting with UDP payload or * TCP header, depending on protocol) * @param payload_length number of bytes in 'payload' * @param protocol IPPROTO_UDP or IPPROTO_TCP * @param tcp_header skeleton TCP header data to send, NULL for UDP * @param src_address source address to use (IP and port) * @param dst_address destination address to use (IP and port) * @param pkt6 where to write the assembled packet; must * contain enough space for the IP header, UDP/TCP header * AND the payload */ static void prepare_ipv6_packet (const void *payload, size_t payload_length, int protocol, const struct GNUNET_TUN_TcpHeader *tcp_header, const struct SocketAddress *src_address, const struct SocketAddress *dst_address, struct GNUNET_TUN_IPv6Header *pkt6) { size_t len; len = payload_length; switch (protocol) { case IPPROTO_UDP: len += sizeof (struct GNUNET_TUN_UdpHeader); break; case IPPROTO_TCP: len += sizeof (struct GNUNET_TUN_TcpHeader); break; default: GNUNET_break (0); return; } if (len > UINT16_MAX) { GNUNET_break (0); return; } GNUNET_TUN_initialize_ipv6_header (pkt6, protocol, len, &src_address->address.ipv6, &dst_address->address.ipv6); switch (protocol) { case IPPROTO_UDP: { struct GNUNET_TUN_UdpHeader *pkt6_udp = (struct GNUNET_TUN_UdpHeader *) &pkt6[1]; pkt6_udp->source_port = htons (src_address->port); pkt6_udp->destination_port = htons (dst_address->port); pkt6_udp->len = htons ((uint16_t) payload_length); GNUNET_TUN_calculate_udp6_checksum (pkt6, pkt6_udp, payload, payload_length); memcpy (&pkt6_udp[1], payload, payload_length); } break; case IPPROTO_TCP: { struct GNUNET_TUN_TcpHeader *pkt6_tcp = (struct GNUNET_TUN_TcpHeader *) &pkt6[1]; /* memcpy first here as some TCP header fields are initialized this way! */ *pkt6_tcp = *tcp_header; pkt6_tcp->source_port = htons (src_address->port); pkt6_tcp->destination_port = htons (dst_address->port); GNUNET_TUN_calculate_tcp6_checksum (pkt6, pkt6_tcp, payload, payload_length); memcpy (&pkt6_tcp[1], payload, payload_length); } break; default: GNUNET_assert (0); break; } } /** * Send a TCP packet via the TUN interface. * * @param destination_address IP and port to use for the TCP packet's destination * @param source_address IP and port to use for the TCP packet's source * @param tcp_header header template to use * @param payload payload of the TCP packet * @param payload_length number of bytes in 'payload' */ static void send_tcp_packet_via_tun (const struct SocketAddress *destination_address, const struct SocketAddress *source_address, const struct GNUNET_TUN_TcpHeader *tcp_header, const void *payload, size_t payload_length) { size_t len; GNUNET_STATISTICS_update (stats, gettext_noop ("# TCP packets sent via TUN"), 1, GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending packet with %u bytes TCP payload via TUN\n", (unsigned int) payload_length); len = sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader); switch (source_address->af) { case AF_INET: len += sizeof (struct GNUNET_TUN_IPv4Header); break; case AF_INET6: len += sizeof (struct GNUNET_TUN_IPv6Header); break; default: GNUNET_break (0); return; } len += sizeof (struct GNUNET_TUN_TcpHeader); len += payload_length; if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); return; } { char buf[len] GNUNET_ALIGN; struct GNUNET_MessageHeader *hdr; struct GNUNET_TUN_Layer2PacketHeader *tun; hdr = (struct GNUNET_MessageHeader *) buf; hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); hdr->size = htons (len); tun = (struct GNUNET_TUN_Layer2PacketHeader*) &hdr[1]; tun->flags = htons (0); switch (source_address->af) { case AF_INET: { struct GNUNET_TUN_IPv4Header * ipv4 = (struct GNUNET_TUN_IPv4Header*) &tun[1]; tun->proto = htons (ETH_P_IPV4); prepare_ipv4_packet (payload, payload_length, IPPROTO_TCP, tcp_header, source_address, destination_address, ipv4); } break; case AF_INET6: { struct GNUNET_TUN_IPv6Header * ipv6 = (struct GNUNET_TUN_IPv6Header*) &tun[1]; tun->proto = htons (ETH_P_IPV6); prepare_ipv6_packet (payload, payload_length, IPPROTO_TCP, tcp_header, source_address, destination_address, ipv6); } break; default: GNUNET_assert (0); break; } (void) GNUNET_HELPER_send (helper_handle, (const struct GNUNET_MessageHeader*) buf, GNUNET_YES, NULL, NULL); } } /** * Process a request via mesh to send a request to a TCP service * offered by this system. * * @param cls closure, NULL * @param tunnel connection to the other end * @param tunnel_ctx pointer to our 'struct TunnelState *' * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int receive_tcp_service (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx GNUNET_UNUSED, const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) { struct TunnelState *state = *tunnel_ctx; const struct GNUNET_EXIT_TcpServiceStartMessage *start; uint16_t pkt_len = ntohs (message->size); GNUNET_STATISTICS_update (stats, gettext_noop ("# TCP service creation requests received via mesh"), 1, GNUNET_NO); GNUNET_STATISTICS_update (stats, gettext_noop ("# Bytes received from MESH"), pkt_len, GNUNET_NO); /* check that we got at least a valid header */ if (pkt_len < sizeof (struct GNUNET_EXIT_TcpServiceStartMessage)) { GNUNET_break_op (0); return GNUNET_SYSERR; } start = (const struct GNUNET_EXIT_TcpServiceStartMessage*) message; pkt_len -= sizeof (struct GNUNET_EXIT_TcpServiceStartMessage); if ( (NULL == state) || (NULL != state->serv) || (NULL != state->heap_node) ) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (start->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader)) { GNUNET_break_op (0); return GNUNET_SYSERR; } GNUNET_break_op (ntohl (start->reserved) == 0); /* setup fresh connection */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received data from %s for forwarding to TCP service %s on port %u\n", GNUNET_i2s (sender), GNUNET_h2s (&start->service_descriptor), (unsigned int) ntohs (start->tcp_header.destination_port)); if (NULL == (state->serv = find_service (tcp_services, &start->service_descriptor, ntohs (start->tcp_header.destination_port)))) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("No service found for %s on port %d!\n"), "TCP", ntohs (start->tcp_header.destination_port)); GNUNET_STATISTICS_update (stats, gettext_noop ("# TCP requests dropped (no such service)"), 1, GNUNET_NO); return GNUNET_SYSERR; } state->ri.remote_address = state->serv->address; setup_state_record (state); send_tcp_packet_via_tun (&state->ri.remote_address, &state->ri.local_address, &start->tcp_header, &start[1], pkt_len); return GNUNET_YES; } /** * Process a request to forward TCP data to the Internet via this peer. * * @param cls closure, NULL * @param tunnel connection to the other end * @param tunnel_ctx pointer to our 'struct TunnelState *' * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int receive_tcp_remote (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx GNUNET_UNUSED, const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) { struct TunnelState *state = *tunnel_ctx; const struct GNUNET_EXIT_TcpInternetStartMessage *start; uint16_t pkt_len = ntohs (message->size); const struct in_addr *v4; const struct in6_addr *v6; const void *payload; int af; GNUNET_STATISTICS_update (stats, gettext_noop ("# Bytes received from MESH"), pkt_len, GNUNET_NO); GNUNET_STATISTICS_update (stats, gettext_noop ("# TCP IP-exit creation requests received via mesh"), 1, GNUNET_NO); if (pkt_len < sizeof (struct GNUNET_EXIT_TcpInternetStartMessage)) { GNUNET_break_op (0); return GNUNET_SYSERR; } start = (const struct GNUNET_EXIT_TcpInternetStartMessage*) message; pkt_len -= sizeof (struct GNUNET_EXIT_TcpInternetStartMessage); if ( (NULL == state) || (NULL != state->serv) || (NULL != state->heap_node) ) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (start->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader)) { GNUNET_break_op (0); return GNUNET_SYSERR; } af = (int) ntohl (start->af); state->ri.remote_address.af = af; switch (af) { case AF_INET: if (pkt_len < sizeof (struct in_addr)) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (! ipv4_exit) { GNUNET_break_op (0); return GNUNET_SYSERR; } v4 = (const struct in_addr*) &start[1]; payload = &v4[1]; pkt_len -= sizeof (struct in_addr); state->ri.remote_address.address.ipv4 = *v4; break; case AF_INET6: if (pkt_len < sizeof (struct in6_addr)) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (! ipv6_exit) { GNUNET_break_op (0); return GNUNET_SYSERR; } v6 = (const struct in6_addr*) &start[1]; payload = &v6[1]; pkt_len -= sizeof (struct in6_addr); state->ri.remote_address.address.ipv6 = *v6; break; default: GNUNET_break_op (0); return GNUNET_SYSERR; } { char buf[INET6_ADDRSTRLEN]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received data from %s for starting TCP stream to %s:%u\n", GNUNET_i2s (sender), inet_ntop (af, &state->ri.remote_address.address, buf, sizeof (buf)), (unsigned int) ntohs (start->tcp_header.destination_port)); } state->ri.remote_address.proto = IPPROTO_TCP; state->ri.remote_address.port = ntohs (start->tcp_header.destination_port); setup_state_record (state); send_tcp_packet_via_tun (&state->ri.remote_address, &state->ri.local_address, &start->tcp_header, payload, pkt_len); return GNUNET_YES; } /** * Process a request to forward TCP data on an established * connection via this peer. * * @param cls closure, NULL * @param tunnel connection to the other end * @param tunnel_ctx pointer to our 'struct TunnelState *' * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int receive_tcp_data (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx GNUNET_UNUSED, const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) { struct TunnelState *state = *tunnel_ctx; const struct GNUNET_EXIT_TcpDataMessage *data; uint16_t pkt_len = ntohs (message->size); GNUNET_STATISTICS_update (stats, gettext_noop ("# Bytes received from MESH"), pkt_len, GNUNET_NO); GNUNET_STATISTICS_update (stats, gettext_noop ("# TCP data requests received via mesh"), 1, GNUNET_NO); if (pkt_len < sizeof (struct GNUNET_EXIT_TcpDataMessage)) { GNUNET_break_op (0); return GNUNET_SYSERR; } data = (const struct GNUNET_EXIT_TcpDataMessage*) message; pkt_len -= sizeof (struct GNUNET_EXIT_TcpDataMessage); if ( (NULL == state) || (NULL == state->heap_node) ) { /* connection should have been up! */ GNUNET_STATISTICS_update (stats, gettext_noop ("# TCP DATA requests dropped (no session)"), 1, GNUNET_NO); return GNUNET_SYSERR; } if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader)) { GNUNET_break_op (0); return GNUNET_SYSERR; } GNUNET_break_op (ntohl (data->reserved) == 0); { char buf[INET6_ADDRSTRLEN]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received additional %u bytes of data from %s for TCP stream to %s:%u\n", pkt_len, GNUNET_i2s (sender), inet_ntop (state->ri.remote_address.af, &state->ri.remote_address.address, buf, sizeof (buf)), (unsigned int) state->ri.remote_address.port); } send_tcp_packet_via_tun (&state->ri.remote_address, &state->ri.local_address, &data->tcp_header, &data[1], pkt_len); return GNUNET_YES; } /** * Send an ICMP packet via the TUN interface. * * @param destination_address IP to use for the ICMP packet's destination * @param source_address IP to use for the ICMP packet's source * @param icmp_header ICMP header to send * @param payload payload of the ICMP packet (does NOT include ICMP header) * @param payload_length number of bytes of data in payload */ static void send_icmp_packet_via_tun (const struct SocketAddress *destination_address, const struct SocketAddress *source_address, const struct GNUNET_TUN_IcmpHeader *icmp_header, const void *payload, size_t payload_length) { size_t len; struct GNUNET_TUN_IcmpHeader *icmp; GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMP packets sent via TUN"), 1, GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending packet with %u bytes ICMP payload via TUN\n", (unsigned int) payload_length); len = sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader); switch (destination_address->af) { case AF_INET: len += sizeof (struct GNUNET_TUN_IPv4Header); break; case AF_INET6: len += sizeof (struct GNUNET_TUN_IPv6Header); break; default: GNUNET_break (0); return; } len += sizeof (struct GNUNET_TUN_IcmpHeader); len += payload_length; if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); return; } { char buf[len] GNUNET_ALIGN; struct GNUNET_MessageHeader *hdr; struct GNUNET_TUN_Layer2PacketHeader *tun; hdr= (struct GNUNET_MessageHeader *) buf; hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); hdr->size = htons (len); tun = (struct GNUNET_TUN_Layer2PacketHeader*) &hdr[1]; tun->flags = htons (0); switch (source_address->af) { case AF_INET: { struct GNUNET_TUN_IPv4Header * ipv4 = (struct GNUNET_TUN_IPv4Header*) &tun[1]; tun->proto = htons (ETH_P_IPV4); GNUNET_TUN_initialize_ipv4_header (ipv4, IPPROTO_ICMP, sizeof (struct GNUNET_TUN_IcmpHeader) + payload_length, &source_address->address.ipv4, &destination_address->address.ipv4); icmp = (struct GNUNET_TUN_IcmpHeader*) &ipv4[1]; } break; case AF_INET6: { struct GNUNET_TUN_IPv6Header * ipv6 = (struct GNUNET_TUN_IPv6Header*) &tun[1]; tun->proto = htons (ETH_P_IPV6); GNUNET_TUN_initialize_ipv6_header (ipv6, IPPROTO_ICMPV6, sizeof (struct GNUNET_TUN_IcmpHeader) + payload_length, &source_address->address.ipv6, &destination_address->address.ipv6); icmp = (struct GNUNET_TUN_IcmpHeader*) &ipv6[1]; } break; default: GNUNET_assert (0); break; } *icmp = *icmp_header; memcpy (&icmp[1], payload, payload_length); GNUNET_TUN_calculate_icmp_checksum (icmp, payload, payload_length); (void) GNUNET_HELPER_send (helper_handle, (const struct GNUNET_MessageHeader*) buf, GNUNET_YES, NULL, NULL); } } /** * Synthesize a plausible ICMP payload for an ICMPv4 error * response on the given tunnel. * * @param state tunnel information * @param ipp IPv6 header to fill in (ICMP payload) * @param udp "UDP" header to fill in (ICMP payload); might actually * also be the first 8 bytes of the TCP header */ static void make_up_icmpv4_payload (struct TunnelState *state, struct GNUNET_TUN_IPv4Header *ipp, struct GNUNET_TUN_UdpHeader *udp) { GNUNET_TUN_initialize_ipv4_header (ipp, state->ri.remote_address.proto, sizeof (struct GNUNET_TUN_TcpHeader), &state->ri.remote_address.address.ipv4, &state->ri.local_address.address.ipv4); udp->source_port = htons (state->ri.remote_address.port); udp->destination_port = htons (state->ri.local_address.port); udp->len = htons (0); udp->crc = htons (0); } /** * Synthesize a plausible ICMP payload for an ICMPv6 error * response on the given tunnel. * * @param state tunnel information * @param ipp IPv6 header to fill in (ICMP payload) * @param udp "UDP" header to fill in (ICMP payload); might actually * also be the first 8 bytes of the TCP header */ static void make_up_icmpv6_payload (struct TunnelState *state, struct GNUNET_TUN_IPv6Header *ipp, struct GNUNET_TUN_UdpHeader *udp) { GNUNET_TUN_initialize_ipv6_header (ipp, state->ri.remote_address.proto, sizeof (struct GNUNET_TUN_TcpHeader), &state->ri.remote_address.address.ipv6, &state->ri.local_address.address.ipv6); udp->source_port = htons (state->ri.remote_address.port); udp->destination_port = htons (state->ri.local_address.port); udp->len = htons (0); udp->crc = htons (0); } /** * Process a request to forward ICMP data to the Internet via this peer. * * @param cls closure, NULL * @param tunnel connection to the other end * @param tunnel_ctx pointer to our 'struct TunnelState *' * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int receive_icmp_remote (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx GNUNET_UNUSED, const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) { struct TunnelState *state = *tunnel_ctx; const struct GNUNET_EXIT_IcmpInternetMessage *msg; uint16_t pkt_len = ntohs (message->size); const struct in_addr *v4; const struct in6_addr *v6; const void *payload; char buf[sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN; int af; GNUNET_STATISTICS_update (stats, gettext_noop ("# Bytes received from MESH"), pkt_len, GNUNET_NO); GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMP IP-exit requests received via mesh"), 1, GNUNET_NO); if (pkt_len < sizeof (struct GNUNET_EXIT_IcmpInternetMessage)) { GNUNET_break_op (0); return GNUNET_SYSERR; } msg = (const struct GNUNET_EXIT_IcmpInternetMessage*) message; pkt_len -= sizeof (struct GNUNET_EXIT_IcmpInternetMessage); af = (int) ntohl (msg->af); if ( (NULL != state->heap_node) && (af != state->ri.remote_address.af) ) { /* other peer switched AF on this tunnel; not allowed */ GNUNET_break_op (0); return GNUNET_SYSERR; } switch (af) { case AF_INET: if (pkt_len < sizeof (struct in_addr)) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (! ipv4_exit) { GNUNET_break_op (0); return GNUNET_SYSERR; } v4 = (const struct in_addr*) &msg[1]; payload = &v4[1]; pkt_len -= sizeof (struct in_addr); state->ri.remote_address.address.ipv4 = *v4; if (NULL == state->heap_node) { state->ri.remote_address.af = af; state->ri.remote_address.proto = IPPROTO_ICMP; setup_state_record (state); } /* check that ICMP type is something we want to support and possibly make up payload! */ switch (msg->icmp_header.type) { case GNUNET_TUN_ICMPTYPE_ECHO_REPLY: case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST: break; case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE: case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH: case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED: if (0 != pkt_len) { GNUNET_break_op (0); return GNUNET_SYSERR; } /* make up payload */ { struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) buf; struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1]; GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); pkt_len = sizeof (struct GNUNET_TUN_IPv4Header) + 8; make_up_icmpv4_payload (state, ipp, udp); payload = ipp; } break; default: GNUNET_break_op (0); GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv4 packets dropped (type not allowed)"), 1, GNUNET_NO); return GNUNET_SYSERR; } /* end AF_INET */ break; case AF_INET6: if (pkt_len < sizeof (struct in6_addr)) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (! ipv6_exit) { GNUNET_break_op (0); return GNUNET_SYSERR; } v6 = (const struct in6_addr*) &msg[1]; payload = &v6[1]; pkt_len -= sizeof (struct in6_addr); state->ri.remote_address.address.ipv6 = *v6; if (NULL == state->heap_node) { state->ri.remote_address.af = af; state->ri.remote_address.proto = IPPROTO_ICMPV6; setup_state_record (state); } /* check that ICMP type is something we want to support and possibly make up payload! */ switch (msg->icmp_header.type) { case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY: case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST: break; case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE: case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG: case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED: case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM: if (0 != pkt_len) { GNUNET_break_op (0); return GNUNET_SYSERR; } /* make up payload */ { struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) buf; struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1]; GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); pkt_len = sizeof (struct GNUNET_TUN_IPv6Header) + 8; make_up_icmpv6_payload (state, ipp, udp); payload = ipp; } break; default: GNUNET_break_op (0); GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv6 packets dropped (type not allowed)"), 1, GNUNET_NO); return GNUNET_SYSERR; } /* end AF_INET6 */ break; default: /* bad AF */ GNUNET_break_op (0); return GNUNET_SYSERR; } { char buf[INET6_ADDRSTRLEN]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ICMP data from %s for forwarding to %s\n", GNUNET_i2s (sender), inet_ntop (af, &state->ri.remote_address.address, buf, sizeof (buf))); } send_icmp_packet_via_tun (&state->ri.remote_address, &state->ri.local_address, &msg->icmp_header, payload, pkt_len); return GNUNET_YES; } /** * Setup ICMP payload for ICMP error messages. Called * for both IPv4 and IPv6 addresses. * * @param state context for creating the IP Packet * @param buf where to create the payload, has at least * sizeof (struct GNUNET_TUN_IPv6Header) + 8 bytes * @return number of bytes of payload we created in buf */ static uint16_t make_up_icmp_service_payload (struct TunnelState *state, char *buf) { switch (state->serv->address.af) { case AF_INET: { struct GNUNET_TUN_IPv4Header *ipv4; struct GNUNET_TUN_UdpHeader *udp; ipv4 = (struct GNUNET_TUN_IPv4Header *)buf; udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1]; make_up_icmpv4_payload (state, ipv4, udp); GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); return sizeof (struct GNUNET_TUN_IPv4Header) + 8; } break; case AF_INET6: { struct GNUNET_TUN_IPv6Header *ipv6; struct GNUNET_TUN_UdpHeader *udp; ipv6 = (struct GNUNET_TUN_IPv6Header *)buf; udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1]; make_up_icmpv6_payload (state, ipv6, udp); GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); return sizeof (struct GNUNET_TUN_IPv6Header) + 8; } break; default: GNUNET_break (0); } return 0; } /** * Process a request via mesh to send ICMP data to a service * offered by this system. * * @param cls closure, NULL * @param tunnel connection to the other end * @param tunnel_ctx pointer to our 'struct TunnelState *' * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int receive_icmp_service (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) { struct TunnelState *state = *tunnel_ctx; const struct GNUNET_EXIT_IcmpServiceMessage *msg; uint16_t pkt_len = ntohs (message->size); struct GNUNET_TUN_IcmpHeader icmp; char buf[sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN; const void *payload; GNUNET_STATISTICS_update (stats, gettext_noop ("# Bytes received from MESH"), pkt_len, GNUNET_NO); GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMP service requests received via mesh"), 1, GNUNET_NO); /* check that we got at least a valid header */ if (pkt_len < sizeof (struct GNUNET_EXIT_IcmpServiceMessage)) { GNUNET_break_op (0); return GNUNET_SYSERR; } msg = (const struct GNUNET_EXIT_IcmpServiceMessage*) message; pkt_len -= sizeof (struct GNUNET_EXIT_IcmpServiceMessage); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received data from %s for forwarding to ICMP service %s\n", GNUNET_i2s (sender), GNUNET_h2s (&msg->service_descriptor)); if (NULL == state->serv) { /* first packet to service must not be ICMP (cannot determine service!) */ GNUNET_break_op (0); return GNUNET_SYSERR; } icmp = msg->icmp_header; payload = &msg[1]; state->ri.remote_address = state->serv->address; setup_state_record (state); /* check that ICMP type is something we want to support, perform ICMP PT if needed ans possibly make up payload */ switch (msg->af) { case AF_INET: switch (msg->icmp_header.type) { case GNUNET_TUN_ICMPTYPE_ECHO_REPLY: if (state->serv->address.af == AF_INET6) icmp.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY; break; case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST: if (state->serv->address.af == AF_INET6) icmp.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST; break; case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE: if (state->serv->address.af == AF_INET6) icmp.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE; if (0 != pkt_len) { GNUNET_break_op (0); return GNUNET_SYSERR; } payload = buf; pkt_len = make_up_icmp_service_payload (state, buf); break; case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED: if (state->serv->address.af == AF_INET6) icmp.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED; if (0 != pkt_len) { GNUNET_break_op (0); return GNUNET_SYSERR; } payload = buf; pkt_len = make_up_icmp_service_payload (state, buf); break; case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH: if (state->serv->address.af == AF_INET6) { GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"), 1, GNUNET_NO); return GNUNET_OK; } if (0 != pkt_len) { GNUNET_break_op (0); return GNUNET_SYSERR; } payload = buf; pkt_len = make_up_icmp_service_payload (state, buf); break; default: GNUNET_break_op (0); GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv4 packets dropped (type not allowed)"), 1, GNUNET_NO); return GNUNET_SYSERR; } /* end of AF_INET */ break; case AF_INET6: switch (msg->icmp_header.type) { case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY: if (state->serv->address.af == AF_INET) icmp.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY; break; case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST: if (state->serv->address.af == AF_INET) icmp.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST; break; case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE: if (state->serv->address.af == AF_INET) icmp.type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE; if (0 != pkt_len) { GNUNET_break_op (0); return GNUNET_SYSERR; } payload = buf; pkt_len = make_up_icmp_service_payload (state, buf); break; case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED: if (state->serv->address.af == AF_INET) icmp.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED; if (0 != pkt_len) { GNUNET_break_op (0); return GNUNET_SYSERR; } payload = buf; pkt_len = make_up_icmp_service_payload (state, buf); break; case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG: case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM: if (state->serv->address.af == AF_INET) { GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"), 1, GNUNET_NO); return GNUNET_OK; } if (0 != pkt_len) { GNUNET_break_op (0); return GNUNET_SYSERR; } payload = buf; pkt_len = make_up_icmp_service_payload (state, buf); break; default: GNUNET_break_op (0); GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv6 packets dropped (type not allowed)"), 1, GNUNET_NO); return GNUNET_SYSERR; } /* end of AF_INET6 */ break; default: GNUNET_break_op (0); return GNUNET_SYSERR; } send_icmp_packet_via_tun (&state->ri.remote_address, &state->ri.local_address, &icmp, payload, pkt_len); return GNUNET_YES; } /** * Send a UDP packet via the TUN interface. * * @param destination_address IP and port to use for the UDP packet's destination * @param source_address IP and port to use for the UDP packet's source * @param payload payload of the UDP packet (does NOT include UDP header) * @param payload_length number of bytes of data in payload */ static void send_udp_packet_via_tun (const struct SocketAddress *destination_address, const struct SocketAddress *source_address, const void *payload, size_t payload_length) { size_t len; GNUNET_STATISTICS_update (stats, gettext_noop ("# UDP packets sent via TUN"), 1, GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending packet with %u bytes UDP payload via TUN\n", (unsigned int) payload_length); len = sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader); switch (source_address->af) { case AF_INET: len += sizeof (struct GNUNET_TUN_IPv4Header); break; case AF_INET6: len += sizeof (struct GNUNET_TUN_IPv6Header); break; default: GNUNET_break (0); return; } len += sizeof (struct GNUNET_TUN_UdpHeader); len += payload_length; if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); return; } { char buf[len] GNUNET_ALIGN; struct GNUNET_MessageHeader *hdr; struct GNUNET_TUN_Layer2PacketHeader *tun; hdr= (struct GNUNET_MessageHeader *) buf; hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); hdr->size = htons (len); tun = (struct GNUNET_TUN_Layer2PacketHeader*) &hdr[1]; tun->flags = htons (0); switch (source_address->af) { case AF_INET: { struct GNUNET_TUN_IPv4Header * ipv4 = (struct GNUNET_TUN_IPv4Header*) &tun[1]; tun->proto = htons (ETH_P_IPV4); prepare_ipv4_packet (payload, payload_length, IPPROTO_UDP, NULL, source_address, destination_address, ipv4); } break; case AF_INET6: { struct GNUNET_TUN_IPv6Header * ipv6 = (struct GNUNET_TUN_IPv6Header*) &tun[1]; tun->proto = htons (ETH_P_IPV6); prepare_ipv6_packet (payload, payload_length, IPPROTO_UDP, NULL, source_address, destination_address, ipv6); } break; default: GNUNET_assert (0); break; } (void) GNUNET_HELPER_send (helper_handle, (const struct GNUNET_MessageHeader*) buf, GNUNET_YES, NULL, NULL); } } /** * Process a request to forward UDP data to the Internet via this peer. * * @param cls closure, NULL * @param tunnel connection to the other end * @param tunnel_ctx pointer to our 'struct TunnelState *' * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int receive_udp_remote (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx GNUNET_UNUSED, const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) { struct TunnelState *state = *tunnel_ctx; const struct GNUNET_EXIT_UdpInternetMessage *msg; uint16_t pkt_len = ntohs (message->size); const struct in_addr *v4; const struct in6_addr *v6; const void *payload; int af; GNUNET_STATISTICS_update (stats, gettext_noop ("# Bytes received from MESH"), pkt_len, GNUNET_NO); GNUNET_STATISTICS_update (stats, gettext_noop ("# UDP IP-exit requests received via mesh"), 1, GNUNET_NO); if (pkt_len < sizeof (struct GNUNET_EXIT_UdpInternetMessage)) { GNUNET_break_op (0); return GNUNET_SYSERR; } msg = (const struct GNUNET_EXIT_UdpInternetMessage*) message; pkt_len -= sizeof (struct GNUNET_EXIT_UdpInternetMessage); af = (int) ntohl (msg->af); state->ri.remote_address.af = af; switch (af) { case AF_INET: if (pkt_len < sizeof (struct in_addr)) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (! ipv4_exit) { GNUNET_break_op (0); return GNUNET_SYSERR; } v4 = (const struct in_addr*) &msg[1]; payload = &v4[1]; pkt_len -= sizeof (struct in_addr); state->ri.remote_address.address.ipv4 = *v4; break; case AF_INET6: if (pkt_len < sizeof (struct in6_addr)) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (! ipv6_exit) { GNUNET_break_op (0); return GNUNET_SYSERR; } v6 = (const struct in6_addr*) &msg[1]; payload = &v6[1]; pkt_len -= sizeof (struct in6_addr); state->ri.remote_address.address.ipv6 = *v6; break; default: GNUNET_break_op (0); return GNUNET_SYSERR; } { char buf[INET6_ADDRSTRLEN]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received data from %s for forwarding to UDP %s:%u\n", GNUNET_i2s (sender), inet_ntop (af, &state->ri.remote_address.address, buf, sizeof (buf)), (unsigned int) ntohs (msg->destination_port)); } state->ri.remote_address.proto = IPPROTO_UDP; state->ri.remote_address.port = msg->destination_port; if (NULL == state->heap_node) setup_state_record (state); if (0 != ntohs (msg->source_port)) state->ri.local_address.port = msg->source_port; send_udp_packet_via_tun (&state->ri.remote_address, &state->ri.local_address, payload, pkt_len); return GNUNET_YES; } /** * Process a request via mesh to send a request to a UDP service * offered by this system. * * @param cls closure, NULL * @param tunnel connection to the other end * @param tunnel_ctx pointer to our 'struct TunnelState *' * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int receive_udp_service (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) { struct TunnelState *state = *tunnel_ctx; const struct GNUNET_EXIT_UdpServiceMessage *msg; uint16_t pkt_len = ntohs (message->size); GNUNET_STATISTICS_update (stats, gettext_noop ("# Bytes received from MESH"), pkt_len, GNUNET_NO); GNUNET_STATISTICS_update (stats, gettext_noop ("# UDP service requests received via mesh"), 1, GNUNET_NO); /* check that we got at least a valid header */ if (pkt_len < sizeof (struct GNUNET_EXIT_UdpServiceMessage)) { GNUNET_break_op (0); return GNUNET_SYSERR; } msg = (const struct GNUNET_EXIT_UdpServiceMessage*) message; pkt_len -= sizeof (struct GNUNET_EXIT_UdpServiceMessage); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received data from %s for forwarding to UDP service %s on port %u\n", GNUNET_i2s (sender), GNUNET_h2s (&msg->service_descriptor), (unsigned int) ntohs (msg->destination_port)); if (NULL == (state->serv = find_service (udp_services, &msg->service_descriptor, ntohs (msg->destination_port)))) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("No service found for %s on port %d!\n"), "UDP", ntohs (msg->destination_port)); GNUNET_STATISTICS_update (stats, gettext_noop ("# UDP requests dropped (no such service)"), 1, GNUNET_NO); return GNUNET_SYSERR; } state->ri.remote_address = state->serv->address; setup_state_record (state); if (0 != ntohs (msg->source_port)) state->ri.local_address.port = msg->source_port; send_udp_packet_via_tun (&state->ri.remote_address, &state->ri.local_address, &msg[1], pkt_len); return GNUNET_YES; } /** * Callback from GNUNET_MESH for new tunnels. * * @param cls closure * @param tunnel new handle to the tunnel * @param initiator peer that started the tunnel * @param atsi performance information for the tunnel * @return initial tunnel context for the tunnel */ static void * new_tunnel (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, const struct GNUNET_PeerIdentity *initiator GNUNET_UNUSED, const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) { struct TunnelState *s = GNUNET_malloc (sizeof (struct TunnelState)); GNUNET_STATISTICS_update (stats, gettext_noop ("# Inbound MESH tunnels created"), 1, GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received inbound tunnel from `%s'\n", GNUNET_i2s (initiator)); s->tunnel = tunnel; return s; } /** * Function called by mesh whenever an inbound tunnel is destroyed. * Should clean up any associated state. * * @param cls closure (set from GNUNET_MESH_connect) * @param tunnel connection to the other end (henceforth invalid) * @param tunnel_ctx place where local state associated * with the tunnel is stored */ static void clean_tunnel (void *cls GNUNET_UNUSED, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx) { struct TunnelState *s = tunnel_ctx; struct TunnelMessageQueue *tnq; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Tunnel destroyed\n"); while (NULL != (tnq = s->head)) { GNUNET_CONTAINER_DLL_remove (s->head, s->tail, tnq); GNUNET_free (tnq); } if (s->heap_node != NULL) { GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (connections_map, &s->state_key, s)); GNUNET_CONTAINER_heap_remove_node (s->heap_node); s->heap_node = NULL; } if (NULL != s->th) { GNUNET_MESH_notify_transmit_ready_cancel (s->th); s->th = NULL; } GNUNET_free (s); } /** * Function that frees everything from a hashmap * * @param cls unused * @param hash key * @param value value to free */ static int free_iterate (void *cls GNUNET_UNUSED, const GNUNET_HashCode * hash GNUNET_UNUSED, void *value) { GNUNET_free (value); return GNUNET_YES; } /** * Function scheduled as very last function, cleans up after us */ static void cleanup (void *cls GNUNET_UNUSED, const struct GNUNET_SCHEDULER_TaskContext *tskctx) { unsigned int i; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Exit service is shutting down now\n"); if (helper_handle != NULL) { GNUNET_HELPER_stop (helper_handle); helper_handle = NULL; } if (mesh_handle != NULL) { GNUNET_MESH_disconnect (mesh_handle); mesh_handle = NULL; } if (NULL != connections_map) { GNUNET_CONTAINER_multihashmap_iterate (connections_map, &free_iterate, NULL); GNUNET_CONTAINER_multihashmap_destroy (connections_map); connections_map = NULL; } if (NULL != connections_heap) { GNUNET_CONTAINER_heap_destroy (connections_heap); connections_heap = NULL; } if (NULL != tcp_services) { GNUNET_CONTAINER_multihashmap_iterate (tcp_services, &free_service_record, NULL); GNUNET_CONTAINER_multihashmap_destroy (tcp_services); tcp_services = NULL; } if (NULL != udp_services) { GNUNET_CONTAINER_multihashmap_iterate (udp_services, &free_service_record, NULL); GNUNET_CONTAINER_multihashmap_destroy (udp_services); udp_services = NULL; } if (stats != NULL) { GNUNET_STATISTICS_destroy (stats, GNUNET_NO); stats = NULL; } for (i=0;i<8;i++) GNUNET_free_non_null (exit_argv[i]); } /** * Add services to the service map. * * @param proto IPPROTO_TCP or IPPROTO_UDP * @param cpy copy of the service descriptor (can be mutilated) * @param name DNS name of the service */ static void add_services (int proto, char *cpy, const char *name) { char *redirect; char *hostname; char *hostport; struct LocalService *serv; for (redirect = strtok (cpy, " "); redirect != NULL; redirect = strtok (NULL, " ")) { if (NULL == (hostname = strstr (redirect, ":"))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "option `%s' for domain `%s' is not formatted correctly!\n", redirect, name); continue; } hostname[0] = '\0'; hostname++; if (NULL == (hostport = strstr (hostname, ":"))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "option `%s' for domain `%s' is not formatted correctly!\n", redirect, name); continue; } hostport[0] = '\0'; hostport++; int local_port = atoi (redirect); int remote_port = atoi (hostport); if (!((local_port > 0) && (local_port < 65536))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "`%s' is not a valid port number (for domain `%s')!", redirect, name); continue; } if (!((remote_port > 0) && (remote_port < 65536))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "`%s' is not a valid port number (for domain `%s')!", hostport, name); continue; } serv = GNUNET_malloc (sizeof (struct LocalService)); serv->my_port = (uint16_t) local_port; serv->address.port = remote_port; if (0 == strcmp ("localhost4", hostname)) { const char *ip4addr = exit_argv[4]; serv->address.af = AF_INET; GNUNET_assert (1 != inet_pton (AF_INET, ip4addr, &serv->address.address.ipv4)); } else if (0 == strcmp ("localhost6", hostname)) { const char *ip6addr = exit_argv[2]; serv->address.af = AF_INET6; GNUNET_assert (1 == inet_pton (AF_INET6, ip6addr, &serv->address.address.ipv6)); } else { struct addrinfo *res; int ret; ret = getaddrinfo (hostname, NULL, NULL, &res); if ( (ret != 0) || (res == NULL) ) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("No addresses found for hostname `%s' of service `%s'!\n"), hostname, name); GNUNET_free (serv); continue; } serv->address.af = res->ai_family; switch (res->ai_family) { case AF_INET: if (! ipv4_enabled) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Service `%s' configured for IPv4, but IPv4 is disabled!\n"), name); freeaddrinfo (res); GNUNET_free (serv); continue; } serv->address.address.ipv4 = ((struct sockaddr_in *) res->ai_addr)->sin_addr; break; case AF_INET6: if (! ipv6_enabled) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Service `%s' configured for IPv4, but IPv4 is disabled!\n"), name); freeaddrinfo (res); GNUNET_free (serv); continue; } serv->address.address.ipv6 = ((struct sockaddr_in6 *) res->ai_addr)->sin6_addr; break; default: freeaddrinfo (res); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("No IP addresses found for hostname `%s' of service `%s'!\n"), hostname, name); GNUNET_free (serv); continue; } freeaddrinfo (res); } store_service ((IPPROTO_UDP == proto) ? udp_services : tcp_services, name, local_port, serv); } } /** * Reads the configuration servicecfg and populates udp_services * * @param cls unused * @param section name of section in config, equal to hostname */ static void read_service_conf (void *cls GNUNET_UNUSED, const char *section) { char *cpy; if ((strlen (section) < 8) || (0 != strcmp (".gnunet.", section + (strlen (section) - 8)))) return; if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, section, "UDP_REDIRECTS", &cpy)) { add_services (IPPROTO_UDP, cpy, section); GNUNET_free (cpy); } if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, section, "TCP_REDIRECTS", &cpy)) { add_services (IPPROTO_TCP, cpy, section); GNUNET_free (cpy); } } /** * Test if the given AF is supported by this system. * * @param af to test * @return GNUNET_OK if the AF is supported */ static int test_af (int af) { int s; s = socket (af, SOCK_STREAM, 0); if (-1 == s) { if (EAFNOSUPPORT == errno) return GNUNET_NO; GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket"); return GNUNET_SYSERR; } close (s); return GNUNET_OK; } /** * @brief Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param cfg_ configuration */ static void run (void *cls, char *const *args GNUNET_UNUSED, const char *cfgfile GNUNET_UNUSED, const struct GNUNET_CONFIGURATION_Handle *cfg_) { static struct GNUNET_MESH_MessageHandler handlers[] = { {&receive_icmp_service, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE, 0}, {&receive_icmp_remote, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET, 0}, {&receive_udp_service, GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE, 0}, {&receive_udp_remote, GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET, 0}, {&receive_tcp_service, GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START, 0}, {&receive_tcp_remote, GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START, 0}, {&receive_tcp_data, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT, 0}, {NULL, 0, 0} }; static GNUNET_MESH_ApplicationType apptypes[] = { GNUNET_APPLICATION_TYPE_END, GNUNET_APPLICATION_TYPE_END, GNUNET_APPLICATION_TYPE_END }; unsigned int app_idx; char *exit_ifname; char *tun_ifname; char *ipv6addr; char *ipv6prefix_s; char *ipv4addr; char *ipv4mask; if (GNUNET_YES != GNUNET_OS_check_helper_binary ("gnunet-helper-exit")) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("`%s' must be installed SUID, refusing to run\n"), "gnunet-helper-exit"); global_ret = 1; return; } cfg = cfg_; stats = GNUNET_STATISTICS_create ("exit", cfg); ipv4_exit = GNUNET_CONFIGURATION_get_value_yesno (cfg, "exit", "EXIT_IPV4"); ipv6_exit = GNUNET_CONFIGURATION_get_value_yesno (cfg, "exit", "EXIT_IPV6"); ipv4_enabled = GNUNET_CONFIGURATION_get_value_yesno (cfg, "exit", "ENABLE_IPV4"); ipv6_enabled = GNUNET_CONFIGURATION_get_value_yesno (cfg, "exit", "ENABLE_IPV6"); if ( (ipv4_exit || ipv4_enabled) && GNUNET_OK != test_af (AF_INET)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("This system does not support IPv4, will disable IPv4 functions despite them being enabled in the configuration\n")); ipv4_exit = GNUNET_NO; ipv4_enabled = GNUNET_NO; } if ( (ipv6_exit || ipv6_enabled) && GNUNET_OK != test_af (AF_INET6)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("This system does not support IPv6, will disable IPv6 functions despite them being enabled in the configuration\n")); ipv6_exit = GNUNET_NO; ipv6_enabled = GNUNET_NO; } if (ipv4_exit && (! ipv4_enabled)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot enable IPv4 exit but disable IPv4 on TUN interface, will use ENABLE_IPv4=YES\n")); ipv4_enabled = GNUNET_YES; } if (ipv6_exit && (! ipv6_enabled)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot enable IPv6 exit but disable IPv6 on TUN interface, will use ENABLE_IPv6=YES\n")); ipv6_enabled = GNUNET_YES; } if (! (ipv4_enabled || ipv6_enabled)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("No useful service enabled. Exiting.\n")); GNUNET_SCHEDULER_shutdown (); return; } app_idx = 0; if (GNUNET_YES == ipv4_exit) { apptypes[app_idx] = GNUNET_APPLICATION_TYPE_IPV4_GATEWAY; app_idx++; } if (GNUNET_YES == ipv6_exit) { apptypes[app_idx] = GNUNET_APPLICATION_TYPE_IPV6_GATEWAY; app_idx++; } GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "exit", "MAX_CONNECTIONS", &max_connections)) max_connections = 1024; exit_argv[0] = GNUNET_strdup ("exit-gnunet"); if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "TUN_IFNAME", &tun_ifname)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No entry 'TUN_IFNAME' in configuration!\n"); GNUNET_SCHEDULER_shutdown (); return; } exit_argv[1] = tun_ifname; if (ipv4_enabled) { if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "EXIT_IFNAME", &exit_ifname)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No entry 'EXIT_IFNAME' in configuration!\n"); GNUNET_SCHEDULER_shutdown (); return; } exit_argv[2] = exit_ifname; } else { exit_argv[2] = GNUNET_strdup ("%"); } if (GNUNET_YES == ipv6_enabled) { if ( (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV6ADDR", &ipv6addr) || (1 != inet_pton (AF_INET6, ipv6addr, &exit_ipv6addr))) ) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No valid entry 'IPV6ADDR' in configuration!\n"); GNUNET_SCHEDULER_shutdown (); return; } exit_argv[3] = ipv6addr; if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV6PREFIX", &ipv6prefix_s)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No entry 'IPV6PREFIX' in configuration!\n"); GNUNET_SCHEDULER_shutdown (); return; } exit_argv[4] = ipv6prefix_s; if ( (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "exit", "IPV6PREFIX", &ipv6prefix)) || (ipv6prefix >= 127) ) { GNUNET_SCHEDULER_shutdown (); return; } } else { /* IPv6 explicitly disabled */ exit_argv[3] = GNUNET_strdup ("-"); exit_argv[4] = GNUNET_strdup ("-"); } if (GNUNET_YES == ipv4_enabled) { if ( (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV4ADDR", &ipv4addr) || (1 != inet_pton (AF_INET, ipv4addr, &exit_ipv4addr))) ) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No valid entry for 'IPV4ADDR' in configuration!\n"); GNUNET_SCHEDULER_shutdown (); return; } exit_argv[5] = ipv4addr; if ( (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV4MASK", &ipv4mask) || (1 != inet_pton (AF_INET, ipv4mask, &exit_ipv4mask))) ) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No valid entry 'IPV4MASK' in configuration!\n"); GNUNET_SCHEDULER_shutdown (); return; } exit_argv[6] = ipv4mask; } else { /* IPv4 explicitly disabled */ exit_argv[5] = GNUNET_strdup ("-"); exit_argv[6] = GNUNET_strdup ("-"); } exit_argv[7] = NULL; udp_services = GNUNET_CONTAINER_multihashmap_create (65536); tcp_services = GNUNET_CONTAINER_multihashmap_create (65536); GNUNET_CONFIGURATION_iterate_sections (cfg, &read_service_conf, NULL); connections_map = GNUNET_CONTAINER_multihashmap_create (65536); connections_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); mesh_handle = GNUNET_MESH_connect (cfg, 42 /* queue size */, NULL, &new_tunnel, &clean_tunnel, handlers, apptypes); if (NULL == mesh_handle) { GNUNET_SCHEDULER_shutdown (); return; } helper_handle = GNUNET_HELPER_start ("gnunet-helper-exit", exit_argv, &message_token, NULL); } /** * The main function * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-daemon-exit", gettext_noop ("Daemon to run to provide an IP exit node for the VPN"), options, &run, NULL)) ? global_ret : 1; } /* end of gnunet-daemon-exit.c */ gnunet-0.9.3/src/exit/gnunet-helper-exit.c0000644000175000017500000004420211760502551015400 00000000000000/* This file is part of GNUnet. (C) 2010, 2011, 2012 Christian Grothoff GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file exit/gnunet-helper-exit.c * * @brief the helper for exit nodes. Opens a virtual * network-interface, sends data received on the if to stdout, sends * data received on stdin to the interface. The code also enables * IPv4/IPv6 forwarding and NAT on the current system (the latter on * an interface specified on the command-line); these changes to the * network configuration are NOT automatically undone when the program * is stopped (this is because we cannot be sure that some other * application didn't enable them before or after us; also, these * changes should be mostly harmless as it simply turns the system * into a router). * * @author Philipp Tölke * @author Christian Grothoff * * The following list of people have reviewed this code and considered * it safe since the last modification (if you reviewed it, please * have your name added to the list): * * - Philipp Tölke */ #include "platform.h" #include /** * Need 'struct GNUNET_MessageHeader'. */ #include "gnunet_common.h" /** * Need VPN message types. */ #include "gnunet_protocols.h" /** * Should we print (interesting|debug) messages that can happen during * normal operation? */ #define DEBUG GNUNET_NO /** * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE) */ #define MAX_SIZE 65536 /** * Path to 'sysctl' binary. */ static const char *sbin_sysctl; /** * Path to 'iptables' binary. */ static const char *sbin_iptables; #ifndef _LINUX_IN6_H /** * This is in linux/include/net/ipv6.h, but not always exported... */ struct in6_ifreq { struct in6_addr ifr6_addr; __u32 ifr6_prefixlen; int ifr6_ifindex; }; #endif /** * Run the given command and wait for it to complete. * * @param file name of the binary to run * @param cmd command line arguments (as given to 'execv') * @return 0 on success, 1 on any error */ static int fork_and_exec (const char *file, char *const cmd[]) { int status; pid_t pid; pid_t ret; pid = fork (); if (-1 == pid) { fprintf (stderr, "fork failed: %s\n", strerror (errno)); return 1; } if (0 == pid) { /* we are the child process */ /* close stdin/stdout to not cause interference with the helper's main protocol! */ (void) close (0); (void) close (1); (void) execv (file, cmd); /* can only get here on error */ fprintf (stderr, "exec `%s' failed: %s\n", file, strerror (errno)); _exit (1); } /* keep running waitpid as long as the only error we get is 'EINTR' */ while ( (-1 == (ret = waitpid (pid, &status, 0))) && (errno == EINTR) ); if (-1 == ret) { fprintf (stderr, "waitpid failed: %s\n", strerror (errno)); return 1; } if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)))) return 1; /* child process completed and returned success, we're happy */ return 0; } /** * Creates a tun-interface called dev; * * @param dev is asumed to point to a char[IFNAMSIZ] * if *dev == '\\0', uses the name supplied by the kernel; * @return the fd to the tun or -1 on error */ static int init_tun (char *dev) { struct ifreq ifr; int fd; if (NULL == dev) { errno = EINVAL; return -1; } if (-1 == (fd = open ("/dev/net/tun", O_RDWR))) { fprintf (stderr, "Error opening `%s': %s\n", "/dev/net/tun", strerror (errno)); return -1; } if (fd >= FD_SETSIZE) { fprintf (stderr, "File descriptor to large: %d", fd); (void) close (fd); return -1; } memset (&ifr, 0, sizeof (ifr)); ifr.ifr_flags = IFF_TUN; if ('\0' != *dev) strncpy (ifr.ifr_name, dev, IFNAMSIZ); if (-1 == ioctl (fd, TUNSETIFF, (void *) &ifr)) { fprintf (stderr, "Error with ioctl on `%s': %s\n", "/dev/net/tun", strerror (errno)); (void) close (fd); return -1; } strcpy (dev, ifr.ifr_name); return fd; } /** * @brief Sets the IPv6-Address given in address on the interface dev * * @param dev the interface to configure * @param address the IPv6-Address * @param prefix_len the length of the network-prefix */ static void set_address6 (const char *dev, const char *address, unsigned long prefix_len) { struct ifreq ifr; struct sockaddr_in6 sa6; int fd; struct in6_ifreq ifr6; /* * parse the new address */ memset (&sa6, 0, sizeof (struct sockaddr_in6)); sa6.sin6_family = AF_INET6; if (1 != inet_pton (AF_INET6, address, &sa6.sin6_addr)) { fprintf (stderr, "Failed to parse address `%s': %s\n", address, strerror (errno)); exit (1); } if (-1 == (fd = socket (PF_INET6, SOCK_DGRAM, 0))) { fprintf (stderr, "Error creating socket: %s\n", strerror (errno)); exit (1); } memset (&ifr, 0, sizeof (struct ifreq)); /* * Get the index of the if */ strncpy (ifr.ifr_name, dev, IFNAMSIZ); if (-1 == ioctl (fd, SIOGIFINDEX, &ifr)) { fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } memset (&ifr6, 0, sizeof (struct in6_ifreq)); ifr6.ifr6_addr = sa6.sin6_addr; ifr6.ifr6_ifindex = ifr.ifr_ifindex; ifr6.ifr6_prefixlen = prefix_len; /* * Set the address */ if (-1 == ioctl (fd, SIOCSIFADDR, &ifr6)) { fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } /* * Get the flags */ if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr)) { fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } /* * Add the UP and RUNNING flags */ ifr.ifr_flags |= IFF_UP | IFF_RUNNING; if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr)) { fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } if (0 != close (fd)) { fprintf (stderr, "close failed: %s\n", strerror (errno)); exit (1); } } /** * @brief Sets the IPv4-Address given in address on the interface dev * * @param dev the interface to configure * @param address the IPv4-Address * @param mask the netmask */ static void set_address4 (const char *dev, const char *address, const char *mask) { int fd; struct sockaddr_in *addr; struct ifreq ifr; memset (&ifr, 0, sizeof (struct ifreq)); addr = (struct sockaddr_in *) &(ifr.ifr_addr); addr->sin_family = AF_INET; /* * Parse the address */ if (1 != inet_pton (AF_INET, address, &addr->sin_addr.s_addr)) { fprintf (stderr, "Failed to parse address `%s': %s\n", address, strerror (errno)); exit (1); } if (-1 == (fd = socket (PF_INET, SOCK_DGRAM, 0))) { fprintf (stderr, "Error creating socket: %s\n", strerror (errno)); exit (1); } strncpy (ifr.ifr_name, dev, IFNAMSIZ); /* * Set the address */ if (-1 == ioctl (fd, SIOCSIFADDR, &ifr)) { fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } /* * Parse the netmask */ addr = (struct sockaddr_in *) &(ifr.ifr_netmask); if (1 != inet_pton (AF_INET, mask, &addr->sin_addr.s_addr)) { fprintf (stderr, "Failed to parse address `%s': %s\n", mask, strerror (errno)); (void) close (fd); exit (1); } /* * Set the netmask */ if (-1 == ioctl (fd, SIOCSIFNETMASK, &ifr)) { fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } /* * Get the flags */ if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr)) { fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } /* * Add the UP and RUNNING flags */ ifr.ifr_flags |= IFF_UP | IFF_RUNNING; if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr)) { fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } if (0 != close (fd)) { fprintf (stderr, "close failed: %s\n", strerror (errno)); (void) close (fd); exit (1); } } /** * Start forwarding to and from the tunnel. * * @param fd_tun tunnel FD */ static void run (int fd_tun) { /* * The buffer filled by reading from fd_tun */ unsigned char buftun[MAX_SIZE]; ssize_t buftun_size = 0; unsigned char *buftun_read = NULL; /* * The buffer filled by reading from stdin */ unsigned char bufin[MAX_SIZE]; ssize_t bufin_size = 0; size_t bufin_rpos = 0; unsigned char *bufin_read = NULL; fd_set fds_w; fd_set fds_r; /* read refers to reading from fd_tun, writing to stdout */ int read_open = 1; /* write refers to reading from stdin, writing to fd_tun */ int write_open = 1; while ((1 == read_open) || (1 == write_open)) { FD_ZERO (&fds_w); FD_ZERO (&fds_r); /* * We are supposed to read and the buffer is empty * -> select on read from tun */ if (read_open && (0 == buftun_size)) FD_SET (fd_tun, &fds_r); /* * We are supposed to read and the buffer is not empty * -> select on write to stdout */ if (read_open && (0 != buftun_size)) FD_SET (1, &fds_w); /* * We are supposed to write and the buffer is empty * -> select on read from stdin */ if (write_open && (NULL == bufin_read)) FD_SET (0, &fds_r); /* * We are supposed to write and the buffer is not empty * -> select on write to tun */ if (write_open && (NULL != bufin_read)) FD_SET (fd_tun, &fds_w); int r = select (fd_tun + 1, &fds_r, &fds_w, NULL, NULL); if (-1 == r) { if (EINTR == errno) continue; fprintf (stderr, "select failed: %s\n", strerror (errno)); exit (1); } if (r > 0) { if (FD_ISSET (fd_tun, &fds_r)) { buftun_size = read (fd_tun, buftun + sizeof (struct GNUNET_MessageHeader), MAX_SIZE - sizeof (struct GNUNET_MessageHeader)); if (-1 == buftun_size) { fprintf (stderr, "read-error: %s\n", strerror (errno)); shutdown (fd_tun, SHUT_RD); shutdown (1, SHUT_WR); read_open = 0; buftun_size = 0; } else if (0 == buftun_size) { #if DEBUG fprintf (stderr, "EOF on tun\n"); #endif shutdown (fd_tun, SHUT_RD); shutdown (1, SHUT_WR); read_open = 0; buftun_size = 0; } else { buftun_read = buftun; struct GNUNET_MessageHeader *hdr = (struct GNUNET_MessageHeader *) buftun; buftun_size += sizeof (struct GNUNET_MessageHeader); hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); hdr->size = htons (buftun_size); } } else if (FD_ISSET (1, &fds_w)) { ssize_t written = write (1, buftun_read, buftun_size); if (-1 == written) { #if !DEBUG if (errno != EPIPE) #endif fprintf (stderr, "write-error to stdout: %s\n", strerror (errno)); shutdown (fd_tun, SHUT_RD); shutdown (1, SHUT_WR); read_open = 0; buftun_size = 0; } else if (0 == written) { fprintf (stderr, "write returned 0!?\n"); exit (1); } else { buftun_size -= written; buftun_read += written; } } if (FD_ISSET (0, &fds_r)) { bufin_size = read (0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos); if (-1 == bufin_size) { fprintf (stderr, "read-error: %s\n", strerror (errno)); shutdown (0, SHUT_RD); shutdown (fd_tun, SHUT_WR); write_open = 0; bufin_size = 0; } else if (0 == bufin_size) { #if DEBUG fprintf (stderr, "EOF on stdin\n"); #endif shutdown (0, SHUT_RD); shutdown (fd_tun, SHUT_WR); write_open = 0; bufin_size = 0; } else { struct GNUNET_MessageHeader *hdr; PROCESS_BUFFER: bufin_rpos += bufin_size; if (bufin_rpos < sizeof (struct GNUNET_MessageHeader)) continue; hdr = (struct GNUNET_MessageHeader *) bufin; if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) { fprintf (stderr, "protocol violation!\n"); exit (1); } if (ntohs (hdr->size) > bufin_rpos) continue; bufin_read = bufin + sizeof (struct GNUNET_MessageHeader); bufin_size = ntohs (hdr->size) - sizeof (struct GNUNET_MessageHeader); bufin_rpos -= bufin_size + sizeof (struct GNUNET_MessageHeader); } } else if (FD_ISSET (fd_tun, &fds_w)) { ssize_t written = write (fd_tun, bufin_read, bufin_size); if (-1 == written) { fprintf (stderr, "write-error to tun: %s\n", strerror (errno)); shutdown (0, SHUT_RD); shutdown (fd_tun, SHUT_WR); write_open = 0; bufin_size = 0; } else if (0 == written) { fprintf (stderr, "write returned 0!?\n"); exit (1); } else { bufin_size -= written; bufin_read += written; if (0 == bufin_size) { memmove (bufin, bufin_read, bufin_rpos); bufin_read = NULL; /* start reading again */ bufin_size = 0; goto PROCESS_BUFFER; } } } } } } /** * Open VPN tunnel interface. * * @param argc must be 6 * @param argv 0: binary name ("gnunet-helper-exit") * 1: tunnel interface name ("gnunet-exit") * 2: IPv4 "physical" interface name ("eth0"), or "%" to not do IPv4 NAT * 3: IPv6 address ("::1"), or "-" to skip IPv6 * 4: IPv6 netmask length in bits ("64") [ignored if #4 is "-"] * 5: IPv4 address ("1.2.3.4"), or "-" to skip IPv4 * 6: IPv4 netmask ("255.255.0.0") [ignored if #4 is "-"] */ int main (int argc, char **argv) { char dev[IFNAMSIZ]; int fd_tun; int global_ret; if (7 != argc) { fprintf (stderr, "Fatal: must supply 6 arguments!\n"); return 1; } if ( (0 == strcmp (argv[3], "-")) && (0 == strcmp (argv[5], "-")) ) { fprintf (stderr, "Fatal: disabling both IPv4 and IPv6 makes no sense.\n"); return 1; } if (0 == access ("/sbin/iptables", X_OK)) sbin_iptables = "/sbin/iptables"; else if (0 == access ("/usr/sbin/iptables", X_OK)) sbin_iptables = "/usr/sbin/iptables"; else { fprintf (stderr, "Fatal: executable iptables not found in approved directories: %s\n", strerror (errno)); return 1; } if (0 == access ("/sbin/sysctl", X_OK)) sbin_sysctl = "/sbin/sysctl"; else if (0 == access ("/usr/sbin/sysctl", X_OK)) sbin_sysctl = "/usr/sbin/sysctl"; else { fprintf (stderr, "Fatal: executable sysctl not found in approved directories: %s\n", strerror (errno)); return 1; } strncpy (dev, argv[1], IFNAMSIZ); dev[IFNAMSIZ - 1] = '\0'; if (-1 == (fd_tun = init_tun (dev))) { fprintf (stderr, "Fatal: could not initialize tun-interface `%s' with IPv6 %s/%s and IPv4 %s/%s\n", dev, argv[3], argv[4], argv[5], argv[6]); return 1; } if (0 != strcmp (argv[3], "-")) { { const char *address = argv[3]; long prefix_len = atol (argv[4]); if ((prefix_len < 1) || (prefix_len > 127)) { fprintf (stderr, "Fatal: prefix_len out of range\n"); return 1; } set_address6 (dev, address, prefix_len); } { char *const sysctl_args[] = { "sysctl", "-w", "net.ipv6.conf.all.forwarding=1", NULL }; if (0 != fork_and_exec (sbin_sysctl, sysctl_args)) { fprintf (stderr, "Failed to enable IPv6 forwarding. Will continue anyway.\n"); } } } if (0 != strcmp (argv[5], "-")) { { const char *address = argv[5]; const char *mask = argv[6]; set_address4 (dev, address, mask); } { char *const sysctl_args[] = { "sysctl", "-w", "net.ipv4.ip_forward=1", NULL }; if (0 != fork_and_exec (sbin_sysctl, sysctl_args)) { fprintf (stderr, "Failed to enable IPv4 forwarding. Will continue anyway.\n"); } } if (0 != strcmp (argv[2], "%")) { char *const iptables_args[] = { "iptables", "-t", "nat", "-A", "POSTROUTING", "-o", argv[2], "-j", "MASQUERADE", NULL }; if (0 != fork_and_exec (sbin_iptables, iptables_args)) { fprintf (stderr, "Failed to enable IPv4 masquerading (NAT). Will continue anyway.\n"); } } } uid_t uid = getuid (); #ifdef HAVE_SETRESUID if (0 != setresuid (uid, uid, uid)) { fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno)); global_ret = 2; goto cleanup; } #else if (0 != (setuid (uid) | seteuid (uid))) { fprintf (stderr, "Failed to setuid: %s\n", strerror (errno)); global_ret = 2; goto cleanup; } #endif if (SIG_ERR == signal (SIGPIPE, SIG_IGN)) { fprintf (stderr, "Failed to protect against SIGPIPE: %s\n", strerror (errno)); /* no exit, we might as well die with SIGPIPE should it ever happen */ } run (fd_tun); global_ret = 0; cleanup: close (fd_tun); return global_ret; } /* end of gnunet-helper-exit.c */ gnunet-0.9.3/src/exit/Makefile.in0000644000175000017500000005616611762217211013567 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-daemon-exit$(EXEEXT) $(am__EXEEXT_1) subdir = src/exit DIST_COMMON = $(dist_pkgcfg_DATA) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @LINUX_TRUE@am__EXEEXT_1 = gnunet-helper-exit$(EXEEXT) am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" PROGRAMS = $(bin_PROGRAMS) am_gnunet_daemon_exit_OBJECTS = gnunet-daemon-exit.$(OBJEXT) gnunet_daemon_exit_OBJECTS = $(am_gnunet_daemon_exit_OBJECTS) am__DEPENDENCIES_1 = gnunet_daemon_exit_DEPENDENCIES = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/tun/libgnunettun.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(am__DEPENDENCIES_1) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent am_gnunet_helper_exit_OBJECTS = gnunet-helper-exit.$(OBJEXT) gnunet_helper_exit_OBJECTS = $(am_gnunet_helper_exit_OBJECTS) gnunet_helper_exit_LDADD = $(LDADD) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(gnunet_daemon_exit_SOURCES) $(gnunet_helper_exit_SOURCES) DIST_SOURCES = $(gnunet_daemon_exit_SOURCES) \ $(gnunet_helper_exit_SOURCES) am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' DATA = $(dist_pkgcfg_DATA) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 pkgcfgdir = $(pkgdatadir)/config.d/ plugindir = $(libdir)/gnunet dist_pkgcfg_DATA = \ exit.conf @LINUX_TRUE@EXITBIN = gnunet-helper-exit gnunet_helper_exit_SOURCES = \ gnunet-helper-exit.c gnunet_daemon_exit_SOURCES = \ gnunet-daemon-exit.c exit.h gnunet_daemon_exit_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/tun/libgnunettun.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(GN_LIBINTL) all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/exit/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/exit/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-daemon-exit$(EXEEXT): $(gnunet_daemon_exit_OBJECTS) $(gnunet_daemon_exit_DEPENDENCIES) @rm -f gnunet-daemon-exit$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_daemon_exit_OBJECTS) $(gnunet_daemon_exit_LDADD) $(LIBS) gnunet-helper-exit$(EXEEXT): $(gnunet_helper_exit_OBJECTS) $(gnunet_helper_exit_DEPENDENCIES) @rm -f gnunet-helper-exit$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_helper_exit_OBJECTS) $(gnunet_helper_exit_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-daemon-exit.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-exit.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_pkgcfgDATA: $(dist_pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-dist_pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(DATA) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_pkgcfgDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-exec-hook install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-dist_pkgcfgDATA .MAKE: install-am install-exec-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ clean-generic clean-libtool ctags distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-binPROGRAMS install-data install-data-am \ install-dist_pkgcfgDATA install-dvi install-dvi-am \ install-exec install-exec-am install-exec-hook install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-dist_pkgcfgDATA @LINUX_TRUE@install-exec-hook: @LINUX_TRUE@ $(SUDO_BINARY) chown root:root $(bindir)/gnunet-helper-exit || true @LINUX_TRUE@ $(SUDO_BINARY) chmod u+s $(bindir)/gnunet-helper-exit || true @LINUX_FALSE@install-exec-hook: # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/fragmentation/0000755000175000017500000000000011763406750013462 500000000000000gnunet-0.9.3/src/fragmentation/fragmentation.h0000644000175000017500000000371311760502551016406 00000000000000/* This file is part of GNUnet (C) 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/fragmentation/fragmentation.h * @brief library to help fragment messages * @author Christian Grothoff */ #ifndef FRAGMENTATION_H #define FRAGMENTATION_H #include "platform.h" #include "gnunet_fragmentation_lib.h" GNUNET_NETWORK_STRUCT_BEGIN /** * Header for a message fragment. Followed by the * original message. */ struct FragmentHeader { /** * Message header. */ struct GNUNET_MessageHeader header; /** * Unique fragment ID. */ uint32_t fragment_id; /** * Total message size of the original message. */ uint16_t total_size; /** * Absolute offset (in bytes) of this fragment in the original * message. Will be a multiple of the MTU. */ uint16_t offset; }; /** * Message fragment acknowledgement. */ struct FragmentAcknowledgement { /** * Message header. */ struct GNUNET_MessageHeader header; /** * Unique fragment ID. */ uint32_t fragment_id; /** * Bits that are being acknowledged, in big-endian. * (bits that are set correspond to fragments that * have not yet been received). */ uint64_t bits; }; GNUNET_NETWORK_STRUCT_END #endif gnunet-0.9.3/src/fragmentation/defragmentation.c0000644000175000017500000003454511760502551016721 00000000000000/* This file is part of GNUnet (C) 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/fragmentation/defragmentation.c * @brief library to help defragment messages * @author Christian Grothoff */ #include "platform.h" #include "gnunet_fragmentation_lib.h" #include "fragmentation.h" /** * Timestamps for fragments. */ struct FragTimes { /** * The time the fragment was received. */ struct GNUNET_TIME_Absolute time; /** * Number of the bit for the fragment (in [0,..,63]). */ unsigned int bit; }; /** * Information we keep for one message that is being assembled. Note * that we keep the context around even after the assembly is done to * handle 'stray' messages that are received 'late'. A message * context is ONLY discarded when the queue gets too big. */ struct MessageContext { /** * This is a DLL. */ struct MessageContext *next; /** * This is a DLL. */ struct MessageContext *prev; /** * Associated defragmentation context. */ struct GNUNET_DEFRAGMENT_Context *dc; /** * Pointer to the assembled message, allocated at the * end of this struct. */ const struct GNUNET_MessageHeader *msg; /** * Last time we received any update for this message * (least-recently updated message will be discarded * if we hit the queue size). */ struct GNUNET_TIME_Absolute last_update; /** * Task scheduled for transmitting the next ACK to the * other peer. */ GNUNET_SCHEDULER_TaskIdentifier ack_task; /** * When did we receive which fragment? Used to calculate * the time we should send the ACK. */ struct FragTimes frag_times[64]; /** * Which fragments have we gotten yet? bits that are 1 * indicate missing fragments. */ uint64_t bits; /** * Unique ID for this message. */ uint32_t fragment_id; /** * Which 'bit' did the last fragment we received correspond to? */ unsigned int last_bit; /** * For the current ACK round, which is the first relevant * offset in 'frag_times'? */ unsigned int frag_times_start_offset; /** * Which offset whould we write the next frag value into * in the 'frag_times' array? All smaller entries are valid. */ unsigned int frag_times_write_offset; /** * Total size of the message that we are assembling. */ uint16_t total_size; }; /** * Defragmentation context (one per connection). */ struct GNUNET_DEFRAGMENT_Context { /** * For statistics. */ struct GNUNET_STATISTICS_Handle *stats; /** * Head of list of messages we're defragmenting. */ struct MessageContext *head; /** * Tail of list of messages we're defragmenting. */ struct MessageContext *tail; /** * Closure for 'proc' and 'ackp'. */ void *cls; /** * Function to call with defragmented messages. */ GNUNET_FRAGMENT_MessageProcessor proc; /** * Function to call with acknowledgements. */ GNUNET_DEFRAGMENT_AckProcessor ackp; /** * Running average of the latency (delay between messages) for this * connection. */ struct GNUNET_TIME_Relative latency; /** * num_msgs how many fragmented messages * to we defragment at most at the same time? */ unsigned int num_msgs; /** * Current number of messages in the 'struct MessageContext' * DLL (smaller or equal to 'num_msgs'). */ unsigned int list_size; /** * Maximum message size for each fragment. */ uint16_t mtu; }; /** * Create a defragmentation context. * * @param stats statistics context * @param mtu the maximum message size for each fragment * @param num_msgs how many fragmented messages * to we defragment at most at the same time? * @param cls closure for proc and ackp * @param proc function to call with defragmented messages * @param ackp function to call with acknowledgements (to send * back to the other side) * @return the defragmentation context */ struct GNUNET_DEFRAGMENT_Context * GNUNET_DEFRAGMENT_context_create (struct GNUNET_STATISTICS_Handle *stats, uint16_t mtu, unsigned int num_msgs, void *cls, GNUNET_FRAGMENT_MessageProcessor proc, GNUNET_DEFRAGMENT_AckProcessor ackp) { struct GNUNET_DEFRAGMENT_Context *dc; dc = GNUNET_malloc (sizeof (struct GNUNET_DEFRAGMENT_Context)); dc->stats = stats; dc->cls = cls; dc->proc = proc; dc->ackp = ackp; dc->num_msgs = num_msgs; dc->mtu = mtu; dc->latency = GNUNET_TIME_UNIT_SECONDS; /* start with likely overestimate */ return dc; } /** * Destroy the given defragmentation context. * * @param dc defragmentation context */ void GNUNET_DEFRAGMENT_context_destroy (struct GNUNET_DEFRAGMENT_Context *dc) { struct MessageContext *mc; while (NULL != (mc = dc->head)) { GNUNET_CONTAINER_DLL_remove (dc->head, dc->tail, mc); dc->list_size--; if (GNUNET_SCHEDULER_NO_TASK != mc->ack_task) { GNUNET_SCHEDULER_cancel (mc->ack_task); mc->ack_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_free (mc); } GNUNET_assert (0 == dc->list_size); GNUNET_free (dc); } /** * Send acknowledgement to the other peer now. * * @param cls the message context * @param tc the scheduler context */ static void send_ack (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct MessageContext *mc = cls; struct GNUNET_DEFRAGMENT_Context *dc = mc->dc; struct FragmentAcknowledgement fa; mc->ack_task = GNUNET_SCHEDULER_NO_TASK; fa.header.size = htons (sizeof (struct FragmentAcknowledgement)); fa.header.type = htons (GNUNET_MESSAGE_TYPE_FRAGMENT_ACK); fa.fragment_id = htonl (mc->fragment_id); fa.bits = GNUNET_htonll (mc->bits); GNUNET_STATISTICS_update (mc->dc->stats, _("# acknowledgements sent for fragment"), 1, GNUNET_NO); dc->ackp (dc->cls, mc->fragment_id, &fa.header); } /** * This function is from the GNU Scientific Library, linear/fit.c, * (C) 2000 Brian Gough */ static void gsl_fit_mul (const double *x, const size_t xstride, const double *y, const size_t ystride, const size_t n, double *c1, double *cov_11, double *sumsq) { double m_x = 0, m_y = 0, m_dx2 = 0, m_dxdy = 0; size_t i; for (i = 0; i < n; i++) { m_x += (x[i * xstride] - m_x) / (i + 1.0); m_y += (y[i * ystride] - m_y) / (i + 1.0); } for (i = 0; i < n; i++) { const double dx = x[i * xstride] - m_x; const double dy = y[i * ystride] - m_y; m_dx2 += (dx * dx - m_dx2) / (i + 1.0); m_dxdy += (dx * dy - m_dxdy) / (i + 1.0); } /* In terms of y = b x */ { double s2 = 0, d2 = 0; double b = (m_x * m_y + m_dxdy) / (m_x * m_x + m_dx2); *c1 = b; /* Compute chi^2 = \sum (y_i - b * x_i)^2 */ for (i = 0; i < n; i++) { const double dx = x[i * xstride] - m_x; const double dy = y[i * ystride] - m_y; const double d = (m_y - b * m_x) + dy - b * dx; d2 += d * d; } s2 = d2 / (n - 1.0); /* chisq per degree of freedom */ *cov_11 = s2 * 1.0 / (n * (m_x * m_x + m_dx2)); *sumsq = d2; } } /** * Estimate the latency between messages based on the most recent * message time stamps. * * @param mc context with time stamps * @return average delay between time stamps (based on least-squares fit) */ static struct GNUNET_TIME_Relative estimate_latency (struct MessageContext *mc) { struct FragTimes *first; size_t total = mc->frag_times_write_offset - mc->frag_times_start_offset; double x[total]; double y[total]; size_t i; double c1; double cov11; double sumsq; struct GNUNET_TIME_Relative ret; first = &mc->frag_times[mc->frag_times_start_offset]; GNUNET_assert (total > 1); for (i = 0; i < total; i++) { x[i] = (double) i; y[i] = (double) (first[i].time.abs_value - first[0].time.abs_value); } gsl_fit_mul (x, 1, y, 1, total, &c1, &cov11, &sumsq); c1 += sqrt (sumsq); /* add 1 std dev */ ret.rel_value = (uint64_t) c1; if (ret.rel_value == 0) ret = GNUNET_TIME_UNIT_MILLISECONDS; /* always at least 1 */ return ret; } /** * Discard the message context that was inactive for the longest time. * * @param dc defragmentation context */ static void discard_oldest_mc (struct GNUNET_DEFRAGMENT_Context *dc) { struct MessageContext *old; struct MessageContext *pos; old = NULL; pos = dc->head; while (NULL != pos) { if ((old == NULL) || (old->last_update.abs_value > pos->last_update.abs_value)) old = pos; pos = pos->next; } GNUNET_assert (NULL != old); GNUNET_CONTAINER_DLL_remove (dc->head, dc->tail, old); dc->list_size--; if (GNUNET_SCHEDULER_NO_TASK != old->ack_task) { GNUNET_SCHEDULER_cancel (old->ack_task); old->ack_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_free (old); } /** * We have received a fragment. Process it. * * @param dc the context * @param msg the message that was received * @return GNUNET_OK on success, GNUNET_NO if this was a duplicate, GNUNET_SYSERR on error */ int GNUNET_DEFRAGMENT_process_fragment (struct GNUNET_DEFRAGMENT_Context *dc, const struct GNUNET_MessageHeader *msg) { struct MessageContext *mc; const struct FragmentHeader *fh; uint16_t msize; uint16_t foff; uint32_t fid; char *mbuf; unsigned int bit; struct GNUNET_TIME_Absolute now; struct GNUNET_TIME_Relative delay; unsigned int bc; unsigned int b; unsigned int n; unsigned int num_fragments; int duplicate; int last; if (ntohs (msg->size) < sizeof (struct FragmentHeader)) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (ntohs (msg->size) > dc->mtu) { GNUNET_break_op (0); return GNUNET_SYSERR; } fh = (const struct FragmentHeader *) msg; msize = ntohs (fh->total_size); if (msize < sizeof (struct GNUNET_MessageHeader)) { GNUNET_break_op (0); return GNUNET_SYSERR; } fid = ntohl (fh->fragment_id); foff = ntohs (fh->offset); if (foff >= msize) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (0 != (foff % (dc->mtu - sizeof (struct FragmentHeader)))) { GNUNET_break_op (0); return GNUNET_SYSERR; } GNUNET_STATISTICS_update (dc->stats, _("# fragments received"), 1, GNUNET_NO); num_fragments = (ntohs (msg->size) + dc->mtu - sizeof (struct FragmentHeader)-1) / (dc->mtu - sizeof (struct FragmentHeader)); last = 0; for (mc = dc->head; NULL != mc; mc = mc->next) if (mc->fragment_id > fid) last++; mc = dc->head; while ((NULL != mc) && (fid != mc->fragment_id)) mc = mc->next; bit = foff / (dc->mtu - sizeof (struct FragmentHeader)); if (bit * (dc->mtu - sizeof (struct FragmentHeader)) + ntohs (msg->size) - sizeof (struct FragmentHeader) > msize) { /* payload extends past total message size */ GNUNET_break_op (0); return GNUNET_SYSERR; } if ((NULL != mc) && (msize != mc->total_size)) { /* inconsistent message size */ GNUNET_break_op (0); return GNUNET_SYSERR; } now = GNUNET_TIME_absolute_get (); if (NULL == mc) { mc = GNUNET_malloc (sizeof (struct MessageContext) + msize); mc->msg = (const struct GNUNET_MessageHeader *) &mc[1]; mc->dc = dc; mc->total_size = msize; mc->fragment_id = fid; mc->last_update = now; n = (msize + dc->mtu - sizeof (struct FragmentHeader) - 1) / (dc->mtu - sizeof (struct FragmentHeader)); if (n == 64) mc->bits = UINT64_MAX; /* set all 64 bit */ else mc->bits = (1LL << n) - 1; /* set lowest 'bits' bit */ if (dc->list_size >= dc->num_msgs) discard_oldest_mc (dc); GNUNET_CONTAINER_DLL_insert (dc->head, dc->tail, mc); dc->list_size++; } /* copy data to 'mc' */ if (0 != (mc->bits & (1LL << bit))) { mc->bits -= 1LL << bit; mbuf = (char *) &mc[1]; memcpy (&mbuf[bit * (dc->mtu - sizeof (struct FragmentHeader))], &fh[1], ntohs (msg->size) - sizeof (struct FragmentHeader)); mc->last_update = now; if (bit < mc->last_bit) mc->frag_times_start_offset = mc->frag_times_write_offset; mc->last_bit = bit; mc->frag_times[mc->frag_times_write_offset].time = now; mc->frag_times[mc->frag_times_write_offset].bit = bit; mc->frag_times_write_offset++; duplicate = GNUNET_NO; } else { duplicate = GNUNET_YES; GNUNET_STATISTICS_update (dc->stats, _("# duplicate fragments received"), 1, GNUNET_NO); } /* count number of missing fragments */ bc = 0; for (b = 0; b < 64; b++) if (0 != (mc->bits & (1LL << b))) bc++; /* notify about complete message */ if ((duplicate == GNUNET_NO) && (0 == mc->bits)) { GNUNET_STATISTICS_update (dc->stats, _("# messages defragmented"), 1, GNUNET_NO); /* message complete, notify! */ dc->proc (dc->cls, mc->msg); } /* send ACK */ if (mc->frag_times_write_offset - mc->frag_times_start_offset > 1) { dc->latency = estimate_latency (mc); } delay = GNUNET_TIME_relative_multiply (dc->latency, bc + 1); if ( (last + fid == num_fragments) || (0 == mc->bits) || (GNUNET_YES == duplicate)) { /* message complete or duplicate or last missing fragment in linear sequence; ACK now! */ delay = GNUNET_TIME_UNIT_ZERO; } if (GNUNET_SCHEDULER_NO_TASK != mc->ack_task) GNUNET_SCHEDULER_cancel (mc->ack_task); mc->ack_task = GNUNET_SCHEDULER_add_delayed (delay, &send_ack, mc); if (duplicate == GNUNET_YES) return GNUNET_NO; return GNUNET_YES; } /* end of defragmentation.c */ gnunet-0.9.3/src/fragmentation/Makefile.am0000644000175000017500000000152211762221317015427 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage endif lib_LTLIBRARIES = libgnunetfragmentation.la libgnunetfragmentation_la_SOURCES = \ fragmentation.c fragmentation.h \ defragmentation.c libgnunetfragmentation_la_LIBADD = -lm \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunetfragmentation_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 1:0:1 check_PROGRAMS = \ test_fragmentation if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) endif test_fragmentation_SOURCES = \ test_fragmentation.c test_fragmentation_LDADD = \ $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = test_fragmentation_data.confgnunet-0.9.3/src/fragmentation/test_fragmentation_data.conf0000644000175000017500000000003011611077627021127 00000000000000 [nse] AUTOSTART = NO gnunet-0.9.3/src/fragmentation/test_fragmentation.c0000644000175000017500000001464011760502551017441 00000000000000/* This file is part of GNUnet (C) 2004, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fragmentation/test_fragmentation.c * @brief test for fragmentation.c * @author Christian Grothoff */ #include "platform.h" #include "gnunet_fragmentation_lib.h" #define VERBOSE GNUNET_NO #define DETAILS GNUNET_NO /** * Number of messages to transmit (note: each uses ~32k memory!) */ #define NUM_MSGS 5000 /** * MTU to force on fragmentation (must be > 1k + 12) */ #define MTU 1111 /** * Simulate dropping of 1 out of how many messages? (must be > 1) */ #define DROPRATE 10 static int ret = 1; static unsigned int dups; static unsigned int fragc; static unsigned int frag_drops; static unsigned int acks; static unsigned int ack_drops; static struct GNUNET_DEFRAGMENT_Context *defrag; static struct GNUNET_BANDWIDTH_Tracker trackers[NUM_MSGS]; static struct GNUNET_FRAGMENT_Context *frags[NUM_MSGS]; static GNUNET_SCHEDULER_TaskIdentifier shutdown_task; static void do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { unsigned int i; ret = 0; shutdown_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_DEFRAGMENT_context_destroy (defrag); defrag = NULL; for (i = 0; i < NUM_MSGS; i++) { if (frags[i] == NULL) continue; GNUNET_FRAGMENT_context_destroy (frags[i]); frags[i] = NULL; } } static void proc_msgs (void *cls, const struct GNUNET_MessageHeader *hdr) { static unsigned int total; unsigned int i; const char *buf; #if DETAILS FPRINTF (stderr, "%s", "!"); /* message complete, good! */ #endif buf = (const char *) hdr; for (i = sizeof (struct GNUNET_MessageHeader); i < ntohs (hdr->size); i++) GNUNET_assert (buf[i] == (char) i); total++; #if ! DETAILS if (0 == (total % (NUM_MSGS / 100))) FPRINTF (stderr, "%s", "."); #endif /* tolerate 10% loss, i.e. due to duplicate fragment IDs */ if ((total >= NUM_MSGS - (NUM_MSGS / 10)) && (ret != 0)) { if (GNUNET_SCHEDULER_NO_TASK == shutdown_task) shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); } } /** * Process ACK (by passing to fragmenter) */ static void proc_acks (void *cls, uint32_t msg_id, const struct GNUNET_MessageHeader *hdr) { unsigned int i; int ret; if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, DROPRATE)) { ack_drops++; return; /* random drop */ } for (i = 0; i < NUM_MSGS; i++) { if (frags[i] == NULL) continue; ret = GNUNET_FRAGMENT_process_ack (frags[i], hdr); if (ret == GNUNET_OK) { #if DETAILS FPRINTF (stderr, "%s", "@"); /* good ACK */ #endif GNUNET_FRAGMENT_context_destroy (frags[i]); frags[i] = NULL; acks++; return; } if (ret == GNUNET_NO) { #if DETAILS FPRINTF (stderr, "%s", "@"); /* good ACK */ #endif acks++; return; } } #if DETAILS FPRINTF (stderr, "%s", "_"); /* BAD: ack that nobody feels responsible for... */ #endif } /** * Process fragment (by passing to defrag). */ static void proc_frac (void *cls, const struct GNUNET_MessageHeader *hdr) { struct GNUNET_FRAGMENT_Context **fc = cls; int ret; GNUNET_FRAGMENT_context_transmission_done (*fc); if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, DROPRATE)) { frag_drops++; return; /* random drop */ } if (NULL == defrag) { FPRINTF (stderr, "%s", "E"); /* Error: frag after shutdown!? */ return; } ret = GNUNET_DEFRAGMENT_process_fragment (defrag, hdr); if (ret == GNUNET_NO) { #if DETAILS FPRINTF (stderr, "%s", "?"); /* duplicate fragment */ #endif dups++; } else if (ret == GNUNET_OK) { #if DETAILS FPRINTF (stderr, "%s", "."); /* good fragment */ #endif fragc++; } } /** * Main function run with scheduler. */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { unsigned int i; struct GNUNET_MessageHeader *msg; char buf[MTU + 32 * 1024]; defrag = GNUNET_DEFRAGMENT_context_create (NULL, MTU, NUM_MSGS /* enough space for all */ , NULL, &proc_msgs, &proc_acks); for (i = 0; i < sizeof (buf); i++) buf[i] = (char) i; msg = (struct GNUNET_MessageHeader *) buf; for (i = 0; i < NUM_MSGS; i++) { msg->type = htons ((uint16_t) i); msg->size = htons (sizeof (struct GNUNET_MessageHeader) + (17 * i) % (32 * 1024)); frags[i] = GNUNET_FRAGMENT_context_create (NULL /* no stats */ , MTU, &trackers[i], GNUNET_TIME_UNIT_SECONDS, msg, &proc_frac, &frags[i]); } } int main (int argc, char *argv[]) { struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; char *const argv_prog[] = { "test-fragmentation", "-c", "test_fragmentation_data.conf", "-L", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL }; unsigned int i; GNUNET_log_setup ("test-fragmentation", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); for (i = 0; i < NUM_MSGS; i++) GNUNET_BANDWIDTH_tracker_init (&trackers[i], GNUNET_BANDWIDTH_value_init ((i + 1) * 1024), 100); GNUNET_PROGRAM_run (5, argv_prog, "test-fragmentation", "nohelp", options, &run, NULL); FPRINTF (stderr, "\nHad %u good fragments, %u duplicate fragments, %u acks and %u simulated drops of acks\n", fragc, dups, acks, ack_drops); return ret; } gnunet-0.9.3/src/fragmentation/Makefile.in0000644000175000017500000006137411762223645015461 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ check_PROGRAMS = test_fragmentation$(EXEEXT) subdir = src/fragmentation DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) libgnunetfragmentation_la_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la am_libgnunetfragmentation_la_OBJECTS = fragmentation.lo \ defragmentation.lo libgnunetfragmentation_la_OBJECTS = \ $(am_libgnunetfragmentation_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunetfragmentation_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetfragmentation_la_LDFLAGS) \ $(LDFLAGS) -o $@ am_test_fragmentation_OBJECTS = test_fragmentation.$(OBJEXT) test_fragmentation_OBJECTS = $(am_test_fragmentation_OBJECTS) test_fragmentation_DEPENDENCIES = \ $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \ $(top_builddir)/src/util/libgnunetutil.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunetfragmentation_la_SOURCES) \ $(test_fragmentation_SOURCES) DIST_SOURCES = $(libgnunetfragmentation_la_SOURCES) \ $(test_fragmentation_SOURCES) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage lib_LTLIBRARIES = libgnunetfragmentation.la libgnunetfragmentation_la_SOURCES = \ fragmentation.c fragmentation.h \ defragmentation.c libgnunetfragmentation_la_LIBADD = -lm \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunetfragmentation_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 1:0:1 @ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) test_fragmentation_SOURCES = \ test_fragmentation.c test_fragmentation_LDADD = \ $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = test_fragmentation_data.conf all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/fragmentation/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/fragmentation/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunetfragmentation.la: $(libgnunetfragmentation_la_OBJECTS) $(libgnunetfragmentation_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetfragmentation_la_LINK) -rpath $(libdir) $(libgnunetfragmentation_la_OBJECTS) $(libgnunetfragmentation_la_LIBADD) $(LIBS) clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list test_fragmentation$(EXEEXT): $(test_fragmentation_OBJECTS) $(test_fragmentation_DEPENDENCIES) @rm -f test_fragmentation$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_fragmentation_OBJECTS) $(test_fragmentation_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defragmentation.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fragmentation.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fragmentation.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool ctags distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-libLTLIBRARIES \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ uninstall-am uninstall-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/fragmentation/fragmentation.c0000644000175000017500000003161011760502551016376 00000000000000/* This file is part of GNUnet (C) 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/fragmentation/fragmentation.c * @brief library to help fragment messages * @author Christian Grothoff */ #include "platform.h" #include "gnunet_fragmentation_lib.h" #include "gnunet_protocols.h" #include "fragmentation.h" /** * Absolute minimum delay we impose between sending and expecting ACK to arrive. */ #define MIN_ACK_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 1) /** * Fragmentation context. */ struct GNUNET_FRAGMENT_Context { /** * Statistics to use. */ struct GNUNET_STATISTICS_Handle *stats; /** * Tracker for flow control. */ struct GNUNET_BANDWIDTH_Tracker *tracker; /** * Current expected delay for ACKs. */ struct GNUNET_TIME_Relative delay; /** * Next allowed transmission time. */ struct GNUNET_TIME_Absolute delay_until; /** * Time we transmitted the last message of the last round. */ struct GNUNET_TIME_Absolute last_round; /** * Message to fragment (allocated at the end of this struct). */ const struct GNUNET_MessageHeader *msg; /** * Function to call for transmissions. */ GNUNET_FRAGMENT_MessageProcessor proc; /** * Closure for 'proc'. */ void *proc_cls; /** * Bitfield, set to 1 for each unacknowledged fragment. */ uint64_t acks; /** * Bitfield with all possible bits for 'acks' (used to mask the * ack we get back). */ uint64_t acks_mask; /** * Task performing work for the fragmenter. */ GNUNET_SCHEDULER_TaskIdentifier task; /** * Our fragmentation ID. (chosen at random) */ uint32_t fragment_id; /** * Round-robin selector for the next transmission. */ unsigned int next_transmission; /** * How many rounds of transmission have we completed so far? */ unsigned int num_rounds; /** * How many transmission have we completed in this round? */ unsigned int num_transmissions; /** * GNUNET_YES if we called 'proc' and are now waiting for 'GNUNET_FRAGMENT_transmission_done' */ int8_t proc_busy; /** * GNUNET_YES if we are waiting for an ACK. */ int8_t wack; /** * Target fragment size. */ uint16_t mtu; }; /** * Transmit the next fragment to the other peer. * * @param cls the 'struct GNUNET_FRAGMENT_Context' * @param tc scheduler context */ static void transmit_next (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FRAGMENT_Context *fc = cls; char msg[fc->mtu]; const char *mbuf; struct FragmentHeader *fh; struct GNUNET_TIME_Relative delay; unsigned int bit; size_t size; size_t fsize; int wrap; fc->task = GNUNET_SCHEDULER_NO_TASK; GNUNET_assert (GNUNET_NO == fc->proc_busy); if (0 == fc->acks) return; /* all done */ /* calculate delay */ wrap = 0; while (0 == (fc->acks & (1LL << fc->next_transmission))) { fc->next_transmission = (fc->next_transmission + 1) % 64; wrap |= (0 == fc->next_transmission); } bit = fc->next_transmission; size = ntohs (fc->msg->size); if (bit == size / (fc->mtu - sizeof (struct FragmentHeader))) fsize = (size % (fc->mtu - sizeof (struct FragmentHeader))) + sizeof (struct FragmentHeader); else fsize = fc->mtu; if (NULL != fc->tracker) delay = GNUNET_BANDWIDTH_tracker_get_delay (fc->tracker, fsize); else delay = GNUNET_TIME_UNIT_ZERO; if (delay.rel_value > 0) { fc->task = GNUNET_SCHEDULER_add_delayed (delay, &transmit_next, fc); return; } fc->next_transmission = (fc->next_transmission + 1) % 64; wrap |= (fc->next_transmission == 0); while (0 == (fc->acks & (1LL << fc->next_transmission))) { fc->next_transmission = (fc->next_transmission + 1) % 64; wrap |= (fc->next_transmission == 0); } /* assemble fragmentation message */ mbuf = (const char *) &fc[1]; fh = (struct FragmentHeader *) msg; fh->header.size = htons (fsize); fh->header.type = htons (GNUNET_MESSAGE_TYPE_FRAGMENT); fh->fragment_id = htonl (fc->fragment_id); fh->total_size = fc->msg->size; /* already in big-endian */ fh->offset = htons ((fc->mtu - sizeof (struct FragmentHeader)) * bit); memcpy (&fh[1], &mbuf[bit * (fc->mtu - sizeof (struct FragmentHeader))], fsize - sizeof (struct FragmentHeader)); if (NULL != fc->tracker) GNUNET_BANDWIDTH_tracker_consume (fc->tracker, fsize); GNUNET_STATISTICS_update (fc->stats, _("# fragments transmitted"), 1, GNUNET_NO); if (0 != fc->last_round.abs_value) GNUNET_STATISTICS_update (fc->stats, _("# fragments retransmitted"), 1, GNUNET_NO); /* select next message to calculate delay */ bit = fc->next_transmission; size = ntohs (fc->msg->size); if (bit == size / (fc->mtu - sizeof (struct FragmentHeader))) fsize = size % (fc->mtu - sizeof (struct FragmentHeader)); else fsize = fc->mtu; if (NULL != fc->tracker) delay = GNUNET_BANDWIDTH_tracker_get_delay (fc->tracker, fsize); else delay = GNUNET_TIME_UNIT_ZERO; if (wrap) { /* full round transmitted wait 2x delay for ACK before going again */ fc->num_rounds++; delay = GNUNET_TIME_relative_max (GNUNET_TIME_relative_multiply (delay, 2), GNUNET_TIME_relative_multiply (fc->delay, fc->num_rounds)); /* never use zero, need some time for ACK always */ delay = GNUNET_TIME_relative_max (MIN_ACK_DELAY, delay); fc->wack = GNUNET_YES; fc->last_round = GNUNET_TIME_absolute_get (); GNUNET_STATISTICS_update (fc->stats, _("# fragments wrap arounds"), 1, GNUNET_NO); } fc->proc_busy = GNUNET_YES; fc->delay_until = GNUNET_TIME_relative_to_absolute (delay); fc->num_transmissions++; fc->proc (fc->proc_cls, &fh->header); } /** * Create a fragmentation context for the given message. * Fragments the message into fragments of size "mtu" or * less. Calls 'proc' on each un-acknowledged fragment, * using both the expected 'delay' between messages and * acknowledgements and the given 'tracker' to guide the * frequency of calls to 'proc'. * * @param stats statistics context * @param mtu the maximum message size for each fragment * @param tracker bandwidth tracker to use for flow control (can be NULL) * @param delay expected delay between fragment transmission * and ACK based on previous messages * @param msg the message to fragment * @param proc function to call for each fragment to transmit * @param proc_cls closure for proc * @return the fragmentation context */ struct GNUNET_FRAGMENT_Context * GNUNET_FRAGMENT_context_create (struct GNUNET_STATISTICS_Handle *stats, uint16_t mtu, struct GNUNET_BANDWIDTH_Tracker *tracker, struct GNUNET_TIME_Relative delay, const struct GNUNET_MessageHeader *msg, GNUNET_FRAGMENT_MessageProcessor proc, void *proc_cls) { struct GNUNET_FRAGMENT_Context *fc; size_t size; uint64_t bits; GNUNET_STATISTICS_update (stats, _("# messages fragmented"), 1, GNUNET_NO); GNUNET_assert (mtu >= 1024 + sizeof (struct FragmentHeader)); size = ntohs (msg->size); GNUNET_STATISTICS_update (stats, _("# total size of fragmented messages"), size, GNUNET_NO); GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); fc = GNUNET_malloc (sizeof (struct GNUNET_FRAGMENT_Context) + size); fc->stats = stats; fc->mtu = mtu; fc->tracker = tracker; fc->delay = delay; fc->msg = (const struct GNUNET_MessageHeader *) &fc[1]; fc->proc = proc; fc->proc_cls = proc_cls; fc->fragment_id = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX); memcpy (&fc[1], msg, size); bits = (size + mtu - sizeof (struct FragmentHeader) - 1) / (mtu - sizeof (struct FragmentHeader)); GNUNET_assert (bits <= 64); if (bits == 64) fc->acks_mask = UINT64_MAX; /* set all 64 bit */ else fc->acks_mask = (1LL << bits) - 1; /* set lowest 'bits' bit */ fc->acks = fc->acks_mask; fc->task = GNUNET_SCHEDULER_add_now (&transmit_next, fc); return fc; } /** * Continuation to call from the 'proc' function after the fragment * has been transmitted (and hence the next fragment can now be * given to proc). * * @param fc fragmentation context */ void GNUNET_FRAGMENT_context_transmission_done (struct GNUNET_FRAGMENT_Context *fc) { GNUNET_assert (fc->proc_busy == GNUNET_YES); fc->proc_busy = GNUNET_NO; GNUNET_assert (fc->task == GNUNET_SCHEDULER_NO_TASK); fc->task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (fc->delay_until), &transmit_next, fc); } /** * Process an acknowledgement message we got from the other * side (to control re-transmits). * * @param fc fragmentation context * @param msg acknowledgement message we received * @return GNUNET_OK if this ack completes the work of the 'fc' * (all fragments have been received); * GNUNET_NO if more messages are pending * GNUNET_SYSERR if this ack is not valid for this fc */ int GNUNET_FRAGMENT_process_ack (struct GNUNET_FRAGMENT_Context *fc, const struct GNUNET_MessageHeader *msg) { const struct FragmentAcknowledgement *fa; uint64_t abits; struct GNUNET_TIME_Relative ndelay; if (sizeof (struct FragmentAcknowledgement) != ntohs (msg->size)) { GNUNET_break_op (0); return GNUNET_SYSERR; } fa = (const struct FragmentAcknowledgement *) msg; if (ntohl (fa->fragment_id) != fc->fragment_id) return GNUNET_SYSERR; /* not our ACK */ abits = GNUNET_ntohll (fa->bits); if ( (GNUNET_YES == fc->wack) && (0 != fc->num_transmissions) ) { /* normal ACK, can update running average of delay... */ fc->wack = GNUNET_NO; ndelay = GNUNET_TIME_absolute_get_duration (fc->last_round); fc->delay.rel_value = (ndelay.rel_value / fc->num_transmissions + 3 * fc->delay.rel_value) / 4; fc->num_transmissions = 0; } GNUNET_STATISTICS_update (fc->stats, _("# fragment acknowledgements received"), 1, GNUNET_NO); if (abits != (fc->acks & abits)) { /* ID collission or message reordering, count! This should be rare! */ GNUNET_STATISTICS_update (fc->stats, _("# bits removed from fragmentation ACKs"), 1, GNUNET_NO); } fc->acks = abits & fc->acks_mask; if (0 != fc->acks) { /* more to transmit, do so right now (if tracker permits...) */ if (fc->task != GNUNET_SCHEDULER_NO_TASK) { /* schedule next transmission now, no point in waiting... */ GNUNET_SCHEDULER_cancel (fc->task); fc->task = GNUNET_SCHEDULER_add_now (&transmit_next, fc); } else { /* only case where there is no task should be if we're waiting * for the right to transmit again (proc_busy set to YES) */ GNUNET_assert (GNUNET_YES == fc->proc_busy); } return GNUNET_NO; } /* all done */ GNUNET_STATISTICS_update (fc->stats, _("# fragmentation transmissions completed"), 1, GNUNET_NO); if (fc->task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (fc->task); fc->task = GNUNET_SCHEDULER_NO_TASK; } return GNUNET_OK; } /** * Destroy the given fragmentation context (stop calling 'proc', free * resources). * * @param fc fragmentation context * @return average delay between transmission and ACK for the * last message, FOREVER if the message was not fully transmitted */ struct GNUNET_TIME_Relative GNUNET_FRAGMENT_context_destroy (struct GNUNET_FRAGMENT_Context *fc) { struct GNUNET_TIME_Relative ret; if (fc->task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (fc->task); ret = fc->delay; GNUNET_free (fc); return ret; } /* end of fragmentation.c */ gnunet-0.9.3/src/pt/0000755000175000017500000000000011763406751011250 500000000000000gnunet-0.9.3/src/pt/Makefile.am0000644000175000017500000000134111705633646013224 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 endif pkgcfgdir= $(pkgdatadir)/config.d/ plugindir = $(libdir)/gnunet dist_pkgcfg_DATA = \ pt.conf bin_PROGRAMS = \ gnunet-daemon-pt $(PTBIN) gnunet_daemon_pt_SOURCES = \ gnunet-daemon-pt.c gnunet_daemon_pt_LDADD = \ $(top_builddir)/src/vpn/libgnunetvpn.la \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/dns/libgnunetdns.la \ $(top_builddir)/src/dns/libgnunetdnsparser.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(GN_LIBINTL) gnunet-0.9.3/src/pt/gnunet-daemon-pt.c0000644000175000017500000005724611760502551014524 00000000000000/* This file is part of GNUnet. (C) 2010, 2012 Christian Grothoff GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file pt/gnunet-daemon-pt.c * @brief tool to manipulate DNS and VPN services to perform protocol translation (IPvX over GNUnet) * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_dns_service.h" #include "gnunet_dnsparser_lib.h" #include "gnunet_mesh_service.h" #include "gnunet_tun_lib.h" #include "gnunet_vpn_service.h" #include "gnunet_statistics_service.h" #include "gnunet_applications.h" /** * After how long do we time out if we could not get an IP from VPN or MESH? */ #define TIMEOUT GNUNET_TIME_UNIT_MINUTES /** * How many bytes of payload do we allow at most for a DNS reply? * Given that this is pretty much limited to loopback, we can be * pretty high (Linux loopback defaults to 16k, most local UDP packets * should survive up to 9k (NFS), so 8k should be pretty safe in * general). */ #define MAX_DNS_SIZE (8 * 1024) /** * Which group of DNS records are we currently processing? */ enum RequestGroup { /** * DNS answers */ ANSWERS = 0, /** * DNS authority records */ AUTHORITY_RECORDS = 1, /** * DNS additional records */ ADDITIONAL_RECORDS = 2, /** * We're done processing. */ END = 3 }; /** * Information tracked per DNS reply that we are processing. */ struct ReplyContext { /** * Handle to submit the final result. */ struct GNUNET_DNS_RequestHandle *rh; /** * DNS packet that is being modified. */ struct GNUNET_DNSPARSER_Packet *dns; /** * Active redirection request with the VPN. */ struct GNUNET_VPN_RedirectionRequest *rr; /** * Record for which we have an active redirection request. */ struct GNUNET_DNSPARSER_Record *rec; /** * Offset in the current record group that is being modified. */ unsigned int offset; /** * Group that is being modified */ enum RequestGroup group; }; /** * State we keep for a request that is going out via MESH. */ struct RequestContext { /** * We keep these in a DLL. */ struct RequestContext *next; /** * We keep these in a DLL. */ struct RequestContext *prev; /** * Handle for interaction with DNS service. */ struct GNUNET_DNS_RequestHandle *rh; /** * Message we're sending out via MESH, allocated at the * end of this struct. */ const struct GNUNET_MessageHeader *mesh_message; /** * Task used to abort this operation with timeout. */ GNUNET_SCHEDULER_TaskIdentifier timeout_task; /** * ID of the original DNS request (used to match the reply). */ uint16_t dns_id; /** * GNUNET_NO if this request is still in the transmit_queue, * GNUNET_YES if we are in the receive_queue. */ int16_t was_transmitted; }; /** * The handle to the configuration used throughout the process */ static const struct GNUNET_CONFIGURATION_Handle *cfg; /** * The handle to the VPN */ static struct GNUNET_VPN_Handle *vpn_handle; /** * The handle to the MESH service */ static struct GNUNET_MESH_Handle *mesh_handle; /** * Tunnel we use for DNS requests over MESH. */ static struct GNUNET_MESH_Tunnel *mesh_tunnel; /** * Active transmission request with MESH (or NULL). */ static struct GNUNET_MESH_TransmitHandle *mesh_th; /** * Head of DLL of requests to be transmitted to mesh_tunnel. */ static struct RequestContext *transmit_queue_head; /** * Tail of DLL of requests to be transmitted to mesh_tunnel. */ static struct RequestContext *transmit_queue_tail; /** * Head of DLL of requests waiting for a response. */ static struct RequestContext *receive_queue_head; /** * Tail of DLL of requests waiting for a response. */ static struct RequestContext *receive_queue_tail; /** * Statistics. */ static struct GNUNET_STATISTICS_Handle *stats; /** * The handle to DNS post-resolution modifications. */ static struct GNUNET_DNS_Handle *dns_post_handle; /** * The handle to DNS pre-resolution modifications. */ static struct GNUNET_DNS_Handle *dns_pre_handle; /** * Are we doing IPv4-pt? */ static int ipv4_pt; /** * Are we doing IPv6-pt? */ static int ipv6_pt; /** * Are we tunneling DNS queries? */ static int dns_tunnel; /** * Number of DNS exit peers we currently have in the mesh tunnel. * Used to see if using the mesh tunnel makes any sense right now. */ static unsigned int dns_exit_available; /** * We're done modifying all records in the response. Submit the reply * and free the resources of the rc. * * @param rc context to process */ static void finish_request (struct ReplyContext *rc) { char *buf; size_t buf_len; if (GNUNET_SYSERR == GNUNET_DNSPARSER_pack (rc->dns, MAX_DNS_SIZE, &buf, &buf_len)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to pack DNS request. Dropping.\n")); GNUNET_DNS_request_drop (rc->rh); } else { GNUNET_STATISTICS_update (stats, gettext_noop ("# DNS requests mapped to VPN"), 1, GNUNET_NO); GNUNET_DNS_request_answer (rc->rh, buf_len, buf); GNUNET_free (buf); } GNUNET_DNSPARSER_free_packet (rc->dns); GNUNET_free (rc); } /** * Process the next record of the given request context. * When done, submit the reply and free the resources of * the rc. * * @param rc context to process */ static void submit_request (struct ReplyContext *rc); /** * Callback invoked from the VPN service once a redirection is * available. Provides the IP address that can now be used to * reach the requested destination. We substitute the active * record and then continue with 'submit_request' to look at * the other records. * * @param cls our 'struct ReplyContext' * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error; * will match 'result_af' from the request * @param address IP address (struct in_addr or struct in_addr6, depending on 'af') * that the VPN allocated for the redirection; * traffic to this IP will now be redirected to the * specified target peer; NULL on error */ static void vpn_allocation_callback (void *cls, int af, const void *address) { struct ReplyContext *rc = cls; rc->rr = NULL; if (af == AF_UNSPEC) { GNUNET_DNS_request_drop (rc->rh); GNUNET_DNSPARSER_free_packet (rc->dns); GNUNET_free (rc); return; } GNUNET_STATISTICS_update (stats, gettext_noop ("# DNS records modified"), 1, GNUNET_NO); switch (rc->rec->type) { case GNUNET_DNSPARSER_TYPE_A: GNUNET_assert (AF_INET == af); memcpy (rc->rec->data.raw.data, address, sizeof (struct in_addr)); break; case GNUNET_DNSPARSER_TYPE_AAAA: GNUNET_assert (AF_INET6 == af); memcpy (rc->rec->data.raw.data, address, sizeof (struct in6_addr)); break; default: GNUNET_assert (0); return; } rc->rec = NULL; submit_request (rc); } /** * Modify the given DNS record by asking VPN to create a tunnel * to the given address. When done, continue with submitting * other records from the request context ('submit_request' is * our continuation). * * @param rc context to process * @param rec record to modify */ static void modify_address (struct ReplyContext *rc, struct GNUNET_DNSPARSER_Record *rec) { int af; switch (rec->type) { case GNUNET_DNSPARSER_TYPE_A: af = AF_INET; GNUNET_assert (rec->data.raw.data_len == sizeof (struct in_addr)); break; case GNUNET_DNSPARSER_TYPE_AAAA: af = AF_INET6; GNUNET_assert (rec->data.raw.data_len == sizeof (struct in6_addr)); break; default: GNUNET_assert (0); return; } rc->rec = rec; rc->rr = GNUNET_VPN_redirect_to_ip (vpn_handle, af, af, rec->data.raw.data, GNUNET_NO /* nac */, GNUNET_TIME_relative_to_absolute (TIMEOUT), &vpn_allocation_callback, rc); } /** * Process the next record of the given request context. * When done, submit the reply and free the resources of * the rc. * * @param rc context to process */ static void submit_request (struct ReplyContext *rc) { struct GNUNET_DNSPARSER_Record *ra; unsigned int ra_len; unsigned int i; while (1) { switch (rc->group) { case ANSWERS: ra = rc->dns->answers; ra_len = rc->dns->num_answers; break; case AUTHORITY_RECORDS: ra = rc->dns->authority_records; ra_len = rc->dns->num_authority_records; break; case ADDITIONAL_RECORDS: ra = rc->dns->additional_records; ra_len = rc->dns->num_additional_records; break; case END: finish_request (rc); return; default: GNUNET_assert (0); } for (i=rc->offset;ioffset = i + 1; modify_address (rc, &ra[i]); return; } break; case GNUNET_DNSPARSER_TYPE_AAAA: if (ipv6_pt) { rc->offset = i + 1; modify_address (rc, &ra[i]); return; } break; } } rc->group++; } } /** * Test if any of the given records need protocol-translation work. * * @param ra array of records * @param ra_len number of entries in ra * @return GNUNET_YES if any of the given records require protocol-translation */ static int work_test (const struct GNUNET_DNSPARSER_Record *ra, unsigned int ra_len) { unsigned int i; for (i=0;ianswers, dns->num_answers); work |= work_test (dns->authority_records, dns->num_authority_records); work |= work_test (dns->additional_records, dns->num_additional_records); if (! work) { GNUNET_DNS_request_forward (rh); GNUNET_DNSPARSER_free_packet (dns); return; } rc = GNUNET_malloc (sizeof (struct ReplyContext)); rc->rh = rh; rc->dns = dns; rc->offset = 0; rc->group = ANSWERS; submit_request (rc); } /** * Transmit a DNS request via MESH and move the request * handle to the receive queue. * * @param cls NULL * @param size number of bytes available in buf * @param buf where to copy the message * @return number of bytes written to buf */ static size_t transmit_dns_request_to_mesh (void *cls, size_t size, void *buf) { struct RequestContext *rc; size_t mlen; mesh_th = NULL; if (NULL == (rc = transmit_queue_head)) return 0; mlen = ntohs (rc->mesh_message->size); if (mlen > size) { mesh_th = GNUNET_MESH_notify_transmit_ready (mesh_tunnel, GNUNET_NO, 0, TIMEOUT, NULL, mlen, &transmit_dns_request_to_mesh, NULL); return 0; } GNUNET_assert (GNUNET_NO == rc->was_transmitted); memcpy (buf, rc->mesh_message, mlen); GNUNET_CONTAINER_DLL_remove (transmit_queue_head, transmit_queue_tail, rc); rc->was_transmitted = GNUNET_YES; GNUNET_CONTAINER_DLL_insert (receive_queue_head, receive_queue_tail, rc); rc = transmit_queue_head; if (NULL != rc) mesh_th = GNUNET_MESH_notify_transmit_ready (mesh_tunnel, GNUNET_NO, 0, TIMEOUT, NULL, ntohs (rc->mesh_message->size), &transmit_dns_request_to_mesh, NULL); return mlen; } /** * Task run if the time to answer a DNS request via MESH is over. * * @param cls the 'struct RequestContext' to abort * @param tc scheduler context */ static void timeout_request (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct RequestContext *rc = cls; if (rc->was_transmitted) GNUNET_CONTAINER_DLL_remove (receive_queue_head, receive_queue_tail, rc); else GNUNET_CONTAINER_DLL_remove (transmit_queue_head, transmit_queue_tail, rc); GNUNET_STATISTICS_update (stats, gettext_noop ("# DNS requests dropped (timeout)"), 1, GNUNET_NO); GNUNET_DNS_request_drop (rc->rh); GNUNET_free (rc); } /** * This function is called *before* the DNS request has been * given to a "local" DNS resolver. Tunneling for DNS requests * was enabled, so we now need to send the request via some MESH * tunnel to a DNS EXIT for resolution. * * @param cls closure * @param rh request handle to user for reply * @param request_length number of bytes in request * @param request udp payload of the DNS request */ static void dns_pre_request_handler (void *cls, struct GNUNET_DNS_RequestHandle *rh, size_t request_length, const char *request) { struct RequestContext *rc; size_t mlen; struct GNUNET_MessageHeader hdr; struct GNUNET_TUN_DnsHeader dns; GNUNET_STATISTICS_update (stats, gettext_noop ("# DNS requests intercepted"), 1, GNUNET_NO); if (0 == dns_exit_available) { GNUNET_STATISTICS_update (stats, gettext_noop ("# DNS requests dropped (DNS mesh tunnel down)"), 1, GNUNET_NO); GNUNET_DNS_request_drop (rh); return; } if (request_length < sizeof (dns)) { GNUNET_STATISTICS_update (stats, gettext_noop ("# DNS requests dropped (malformed)"), 1, GNUNET_NO); GNUNET_DNS_request_drop (rh); return; } memcpy (&dns, request, sizeof (dns)); GNUNET_assert (NULL != mesh_tunnel); mlen = sizeof (struct GNUNET_MessageHeader) + request_length; rc = GNUNET_malloc (sizeof (struct RequestContext) + mlen); rc->rh = rh; rc->mesh_message = (const struct GNUNET_MessageHeader*) &rc[1]; rc->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_request, rc); rc->dns_id = dns.id; hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET); hdr.size = htons (mlen); memcpy (&rc[1], &hdr, sizeof (struct GNUNET_MessageHeader)); memcpy (&(((char*)&rc[1])[sizeof (struct GNUNET_MessageHeader)]), request, request_length); GNUNET_CONTAINER_DLL_insert_tail (transmit_queue_head, transmit_queue_tail, rc); if (NULL == mesh_th) mesh_th = GNUNET_MESH_notify_transmit_ready (mesh_tunnel, GNUNET_NO, 0, TIMEOUT, NULL, mlen, &transmit_dns_request_to_mesh, NULL); } /** * Process a request via mesh to perform a DNS query. * * @param cls closure, NULL * @param tunnel connection to the other end * @param tunnel_ctx pointer to our 'struct TunnelState *' * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int receive_dns_response (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) { struct GNUNET_TUN_DnsHeader dns; size_t mlen; struct RequestContext *rc; mlen = ntohs (message->size); mlen -= sizeof (struct GNUNET_MessageHeader); if (mlen < sizeof (struct GNUNET_TUN_DnsHeader)) { GNUNET_break_op (0); return GNUNET_SYSERR; } memcpy (&dns, &message[1], sizeof (dns)); for (rc = receive_queue_head; NULL != rc; rc = rc->next) { GNUNET_assert (GNUNET_YES == rc->was_transmitted); if (dns.id == rc->dns_id) { GNUNET_STATISTICS_update (stats, gettext_noop ("# DNS replies received"), 1, GNUNET_NO); GNUNET_DNS_request_answer (rc->rh, mlen, (const void*) &message[1]); GNUNET_CONTAINER_DLL_remove (receive_queue_head, receive_queue_tail, rc); GNUNET_SCHEDULER_cancel (rc->timeout_task); GNUNET_free (rc); return GNUNET_OK; } } GNUNET_STATISTICS_update (stats, gettext_noop ("# DNS replies dropped (too late?)"), 1, GNUNET_NO); return GNUNET_OK; } /** * The MESH DNS tunnel went down. Abort all pending DNS * requests (we're unlikely to get an answer in time). */ static void abort_all_requests () { struct RequestContext *rc; while (NULL != (rc = receive_queue_head)) { GNUNET_STATISTICS_update (stats, gettext_noop ("# DNS requests aborted (tunnel down)"), 1, GNUNET_NO); GNUNET_CONTAINER_DLL_remove (receive_queue_head, receive_queue_tail, rc); GNUNET_DNS_request_drop (rc->rh); GNUNET_SCHEDULER_cancel (rc->timeout_task); GNUNET_free (rc); } while (NULL != (rc = transmit_queue_head)) { GNUNET_STATISTICS_update (stats, gettext_noop ("# DNS requests aborted (tunnel down)"), 1, GNUNET_NO); GNUNET_CONTAINER_DLL_remove (transmit_queue_head, transmit_queue_tail, rc); GNUNET_DNS_request_drop (rc->rh); GNUNET_SCHEDULER_cancel (rc->timeout_task); GNUNET_free (rc); } } /** * Method called whenever a peer has disconnected from the tunnel. * * @param cls closure * @param peer peer identity the tunnel stopped working with */ static void mesh_disconnect_handler (void *cls, const struct GNUNET_PeerIdentity * peer) { GNUNET_assert (dns_exit_available > 0); dns_exit_available--; if (0 == dns_exit_available) { if (NULL != mesh_th) { GNUNET_MESH_notify_transmit_ready_cancel (mesh_th); mesh_th = NULL; } abort_all_requests (); } } /** * Method called whenever a peer has connected to the tunnel. * * @param cls closure * @param peer peer identity the tunnel was created to, NULL on timeout * @param atsi performance data for the connection */ static void mesh_connect_handler (void *cls, const struct GNUNET_PeerIdentity * peer, const struct GNUNET_ATS_Information * atsi) { dns_exit_available++; } /** * Function scheduled as very last function, cleans up after us */ static void cleanup (void *cls GNUNET_UNUSED, const struct GNUNET_SCHEDULER_TaskContext *tskctx) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Protocol translation daemon is shutting down now\n"); if (vpn_handle != NULL) { GNUNET_VPN_disconnect (vpn_handle); vpn_handle = NULL; } if (NULL != mesh_th) { GNUNET_MESH_notify_transmit_ready_cancel (mesh_th); mesh_th = NULL; } if (NULL != mesh_tunnel) { GNUNET_MESH_tunnel_destroy (mesh_tunnel); mesh_tunnel = NULL; } if (mesh_handle != NULL) { GNUNET_MESH_disconnect (mesh_handle); mesh_handle = NULL; } abort_all_requests (); if (dns_post_handle != NULL) { GNUNET_DNS_disconnect (dns_post_handle); dns_post_handle = NULL; } if (dns_pre_handle != NULL) { GNUNET_DNS_disconnect (dns_pre_handle); dns_pre_handle = NULL; } if (stats != NULL) { GNUNET_STATISTICS_destroy (stats, GNUNET_YES); stats = NULL; } } /** * @brief Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param cfg_ configuration */ static void run (void *cls, char *const *args GNUNET_UNUSED, const char *cfgfile GNUNET_UNUSED, const struct GNUNET_CONFIGURATION_Handle *cfg_) { cfg = cfg_; stats = GNUNET_STATISTICS_create ("pt", cfg); ipv4_pt = GNUNET_CONFIGURATION_get_value_yesno (cfg, "pt", "TUNNEL_IPV4"); ipv6_pt = GNUNET_CONFIGURATION_get_value_yesno (cfg, "pt", "TUNNEL_IPV6"); dns_tunnel = GNUNET_CONFIGURATION_get_value_yesno (cfg, "pt", "TUNNEL_DNS"); if (! (ipv4_pt || ipv6_pt || dns_tunnel)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("No useful service enabled. Exiting.\n")); GNUNET_SCHEDULER_shutdown (); return; } GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls); if (ipv4_pt || ipv6_pt) { dns_post_handle = GNUNET_DNS_connect (cfg, GNUNET_DNS_FLAG_POST_RESOLUTION, &dns_post_request_handler, NULL); if (NULL == dns_post_handle) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to connect to %s service. Exiting.\n"), "DNS"); GNUNET_SCHEDULER_shutdown (); return; } vpn_handle = GNUNET_VPN_connect (cfg); if (NULL == vpn_handle) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to connect to %s service. Exiting.\n"), "VPN"); GNUNET_SCHEDULER_shutdown (); return; } } if (dns_tunnel) { static struct GNUNET_MESH_MessageHandler mesh_handlers[] = { {&receive_dns_response, GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET, 0}, {NULL, 0, 0} }; static GNUNET_MESH_ApplicationType mesh_types[] = { GNUNET_APPLICATION_TYPE_END }; dns_pre_handle = GNUNET_DNS_connect (cfg, GNUNET_DNS_FLAG_PRE_RESOLUTION, &dns_pre_request_handler, NULL); if (NULL == dns_pre_handle) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to connect to %s service. Exiting.\n"), "DNS"); GNUNET_SCHEDULER_shutdown (); return; } mesh_handle = GNUNET_MESH_connect (cfg, 1, NULL, NULL, NULL, mesh_handlers, mesh_types); if (NULL == mesh_handle) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to connect to %s service. Exiting.\n"), "MESH"); GNUNET_SCHEDULER_shutdown (); return; } mesh_tunnel = GNUNET_MESH_tunnel_create (mesh_handle, NULL, &mesh_connect_handler, &mesh_disconnect_handler, NULL); GNUNET_MESH_peer_request_connect_by_type (mesh_tunnel, GNUNET_APPLICATION_TYPE_INTERNET_RESOLVER); } } /** * The main function * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-daemon-pt", gettext_noop ("Daemon to run to perform IP protocol translation to GNUnet"), options, &run, NULL)) ? 0 : 1; } /* end of gnunet-daemon-pt.c */ gnunet-0.9.3/src/pt/pt.conf0000644000175000017500000000041311705633747012463 00000000000000[pt] CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-pt # Set this to YES to tunnel IPv4 traffic over GNUnet TUNNEL_IPV4 = NO # Set this to YES to tunnel IPv6 traffic over GNUnet TUNNEL_IPV6 = NO # Set this to YES to tunnel DNS traffic over GNUnet TUNNEL_DNS = NO gnunet-0.9.3/src/pt/Makefile.in0000644000175000017500000005442211762217212013233 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-daemon-pt$(EXEEXT) subdir = src/pt DIST_COMMON = $(dist_pkgcfg_DATA) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" PROGRAMS = $(bin_PROGRAMS) am_gnunet_daemon_pt_OBJECTS = gnunet-daemon-pt.$(OBJEXT) gnunet_daemon_pt_OBJECTS = $(am_gnunet_daemon_pt_OBJECTS) am__DEPENDENCIES_1 = gnunet_daemon_pt_DEPENDENCIES = \ $(top_builddir)/src/vpn/libgnunetvpn.la \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/dns/libgnunetdns.la \ $(top_builddir)/src/dns/libgnunetdnsparser.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(am__DEPENDENCIES_1) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(gnunet_daemon_pt_SOURCES) DIST_SOURCES = $(gnunet_daemon_pt_SOURCES) am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' DATA = $(dist_pkgcfg_DATA) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 pkgcfgdir = $(pkgdatadir)/config.d/ plugindir = $(libdir)/gnunet dist_pkgcfg_DATA = \ pt.conf gnunet_daemon_pt_SOURCES = \ gnunet-daemon-pt.c gnunet_daemon_pt_LDADD = \ $(top_builddir)/src/vpn/libgnunetvpn.la \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/dns/libgnunetdns.la \ $(top_builddir)/src/dns/libgnunetdnsparser.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(GN_LIBINTL) all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/pt/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/pt/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-daemon-pt$(EXEEXT): $(gnunet_daemon_pt_OBJECTS) $(gnunet_daemon_pt_DEPENDENCIES) @rm -f gnunet-daemon-pt$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_daemon_pt_OBJECTS) $(gnunet_daemon_pt_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-daemon-pt.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_pkgcfgDATA: $(dist_pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-dist_pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(DATA) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_pkgcfgDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-dist_pkgcfgDATA .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ clean-generic clean-libtool ctags distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-binPROGRAMS install-data install-data-am \ install-dist_pkgcfgDATA install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-dist_pkgcfgDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/statistics/0000755000175000017500000000000011763406747013024 500000000000000gnunet-0.9.3/src/statistics/statistics.h0000644000175000017500000000624211760502551015276 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @author Christian Grothoff * @file statistics/statistics.h */ #ifndef STATISTICS_H #define STATISTICS_H #include "gnunet_common.h" GNUNET_NETWORK_STRUCT_BEGIN /** * Statistics message. Contains how long the system is up * and one value. * * The struct is be followed by the service name and * name of the statistic, both 0-terminated. */ struct GNUNET_STATISTICS_ReplyMessage { /** * Type: GNUNET_MESSAGE_TYPE_STATISTICS_VALUE */ struct GNUNET_MessageHeader header; /** * Unique numerical identifier for the value (will * not change during the same client-session). Highest * bit will be set for persistent values. */ uint32_t uid GNUNET_PACKED; /** * The value. */ uint64_t value GNUNET_PACKED; }; #define GNUNET_STATISTICS_PERSIST_BIT (1<<31) #define GNUNET_STATISTICS_SETFLAG_ABSOLUTE 0 #define GNUNET_STATISTICS_SETFLAG_RELATIVE 1 #define GNUNET_STATISTICS_SETFLAG_PERSISTENT 2 /** * Message to set a statistic. Followed * by the subsystem name and the name of * the statistic (each 0-terminated). */ struct GNUNET_STATISTICS_SetMessage { /** * Type: GNUNET_MESSAGE_TYPE_STATISTICS_SET */ struct GNUNET_MessageHeader header; /** * 0 for absolute value, 1 for relative value; 2 to make persistent * (see GNUNET_STATISTICS_SETFLAG_*). */ uint32_t flags GNUNET_PACKED; /** * Value. Note that if this is a relative value, it will * be signed even though the type given here is unsigned. */ uint64_t value GNUNET_PACKED; }; /** * Message transmitted if a watched value changes. */ struct GNUNET_STATISTICS_WatchValueMessage { /** * Type: GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE */ struct GNUNET_MessageHeader header; /** * 0 for absolute value, 1 for relative value; 2 to make persistent * (see GNUNET_STATISTICS_SETFLAG_*). */ uint32_t flags GNUNET_PACKED; /** * Unique watch identification number (watch * requests are enumerated in the order they * are received, the first request having * a wid of zero). */ uint32_t wid GNUNET_PACKED; /** * Reserved (always 0). */ uint32_t reserved GNUNET_PACKED; /** * Value. Note that if this is a relative value, it will * be signed even though the type given here is unsigned. */ uint64_t value GNUNET_PACKED; }; GNUNET_NETWORK_STRUCT_END #endif gnunet-0.9.3/src/statistics/Makefile.am0000644000175000017500000000450711762221711014767 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIB = -lgcov endif pkgcfgdir= $(pkgdatadir)/config.d/ pkgcfg_DATA = \ statistics.conf lib_LTLIBRARIES = libgnunetstatistics.la libgnunetstatistics_la_SOURCES = \ statistics_api.c statistics.h libgnunetstatistics_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) $(XLIB) libgnunetstatistics_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 1:1:1 bin_PROGRAMS = \ gnunet-statistics \ gnunet-service-statistics gnunet_statistics_SOURCES = \ gnunet-statistics.c gnunet_statistics_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_statistics_DEPENDENCIES = \ libgnunetstatistics.la gnunet_service_statistics_SOURCES = \ gnunet-service-statistics.c gnunet_service_statistics_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_service_statistics_DEPENDENCIES = \ libgnunetstatistics.la check_PROGRAMS = \ test_statistics_api \ test_statistics_api_loop \ test_statistics_api_watch \ test_statistics_api_watch_zero_value if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) $(check_SCRIPTS) endif test_statistics_api_SOURCES = \ test_statistics_api.c test_statistics_api_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la test_statistics_api_loop_SOURCES = \ test_statistics_api_loop.c test_statistics_api_loop_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la test_statistics_api_watch_SOURCES = \ test_statistics_api_watch.c test_statistics_api_watch_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la test_statistics_api_watch_zero_value_SOURCES = \ test_statistics_api_watch_zero_value.c test_statistics_api_watch_zero_value_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la check_SCRIPTS = \ test_gnunet_statistics.sh EXTRA_DIST = \ test_statistics_api_data.conf \ $(check_SCRIPTS) gnunet-0.9.3/src/statistics/test_statistics_api.c0000644000175000017500000001370011760502551017156 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file statistics/test_statistics_api.c * @brief testcase for statistics_api.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_statistics_service.h" #define START_SERVICE GNUNET_YES static int check_1 (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received value %llu for `%s:%s\n", (unsigned long long) value, subsystem, name); GNUNET_assert (0 == strcmp (name, "test-1")); GNUNET_assert (0 == strcmp (subsystem, "test-statistics-api")); GNUNET_assert (value == 1); GNUNET_assert (is_persistent == GNUNET_NO); return GNUNET_OK; } static int check_2 (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received value %llu for `%s:%s\n", (unsigned long long) value, subsystem, name); GNUNET_assert (0 == strcmp (name, "test-2")); GNUNET_assert (0 == strcmp (subsystem, "test-statistics-api")); GNUNET_assert (value == 2); GNUNET_assert (is_persistent == GNUNET_NO); return GNUNET_OK; } static int check_3 (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received value %llu for `%s:%s\n", (unsigned long long) value, subsystem, name); GNUNET_assert (0 == strcmp (name, "test-3")); GNUNET_assert (0 == strcmp (subsystem, "test-statistics-api")); GNUNET_assert (value == 3); GNUNET_assert (is_persistent == GNUNET_YES); return GNUNET_OK; } static struct GNUNET_STATISTICS_Handle *h; static void next_fin (void *cls, int success) { int *ok = cls; GNUNET_STATISTICS_destroy (h, GNUNET_NO); GNUNET_assert (success == GNUNET_OK); *ok = 0; } static void next (void *cls, int success) { GNUNET_assert (success == GNUNET_OK); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Issuing GET request\n"); GNUNET_break (NULL != GNUNET_STATISTICS_get (h, NULL, "test-2", GNUNET_TIME_UNIT_SECONDS, &next_fin, &check_2, cls)); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { h = GNUNET_STATISTICS_create ("test-statistics-api", cfg); GNUNET_STATISTICS_set (h, "test-1", 1, GNUNET_NO); GNUNET_STATISTICS_set (h, "test-2", 2, GNUNET_NO); GNUNET_STATISTICS_set (h, "test-3", 2, GNUNET_NO); GNUNET_STATISTICS_update (h, "test-3", 1, GNUNET_YES); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Issuing GET request\n"); GNUNET_break (NULL != GNUNET_STATISTICS_get (h, NULL, "test-1", GNUNET_TIME_UNIT_SECONDS, &next, &check_1, cls)); } static void run_more (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { h = GNUNET_STATISTICS_create ("test-statistics-api", cfg); GNUNET_break (NULL != GNUNET_STATISTICS_get (h, NULL, "test-3", GNUNET_TIME_UNIT_SECONDS, &next_fin, &check_3, cls)); } static int check () { int ok = 1; char *const argv[] = { "test-statistics-api", "-c", "test_statistics_api_data.conf", "-L", "WARNING", NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; #if START_SERVICE struct GNUNET_OS_Process *proc; proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-statistics", "gnunet-service-statistics", "-c", "test_statistics_api_data.conf", NULL); #endif GNUNET_assert (NULL != proc); GNUNET_PROGRAM_run (5, argv, "test-statistics-api", "nohelp", options, &run, &ok); #if START_SERVICE if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); ok = 1; } GNUNET_OS_process_wait (proc); GNUNET_OS_process_destroy (proc); proc = NULL; #endif if (ok != 0) return ok; ok = 1; #if START_SERVICE /* restart to check persistence! */ proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-statistics", "gnunet-service-statistics", "-c", "test_statistics_api_data.conf", NULL); #endif GNUNET_PROGRAM_run (5, argv, "test-statistics-api", "nohelp", options, &run_more, &ok); #if START_SERVICE if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); ok = 1; } GNUNET_OS_process_wait (proc); GNUNET_OS_process_destroy (proc); proc = NULL; #endif return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test_statistics_api", "WARNING", NULL); ret = check (); return ret; } /* end of test_statistics_api.c */ gnunet-0.9.3/src/statistics/test_statistics_api_data.conf0000644000175000017500000000114611762211152020647 00000000000000[PATHS] SERVICEHOME = /tmp/test-gnunetd-statistics/ DEFAULTCONFIG = test_statistics_api_data.conf [statistics] PORT = 22353 UNIXPATH = /tmp/test-statistics-service-statistics.unix #DEBUG = YES [arm] PORT = 22354 DEFAULTSERVICES = UNIXPATH = /tmp/test-statistics-service-arm.unix # DEBUG = YES [fs] AUTOSTART = NO [datastore] AUTOSTART = NO [dht] AUTOSTART = NO [transport] AUTOSTART = NO [core] AUTOSTART = NO [peerinfo] AUTOSTART = NO [dns] AUTOSTART = NO [nse] AUTOSTART = NO [lockmanager] AUTOSTART = NO [ats] AUTOSTART = NO [namestore] AUTOSTART = NO [gns] AUTOSTART = NO [vpn] AUTOSTART = NO gnunet-0.9.3/src/statistics/test_statistics_api_loop.c0000644000175000017500000000676111760502551020220 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file statistics/test_statistics_api_loop.c * @brief testcase for statistics_api.c */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_statistics_service.h" #define VERBOSE GNUNET_NO #define START_SERVICE GNUNET_YES #define ROUNDS (1024 * 1024) static int check_1 (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent) { GNUNET_assert (0 == strcmp (name, "test-0")); GNUNET_assert (0 == strcmp (subsystem, "test-statistics-api-loop")); GNUNET_assert (is_persistent == GNUNET_NO); return GNUNET_OK; } static struct GNUNET_STATISTICS_Handle *h; static void next (void *cls, int success) { int *ok = cls; GNUNET_STATISTICS_destroy (h, GNUNET_NO); GNUNET_assert (success == GNUNET_OK); *ok = 0; } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { int i; char name[128]; h = GNUNET_STATISTICS_create ("test-statistics-api-loop", cfg); for (i = 0; i < ROUNDS; i++) { GNUNET_snprintf (name, sizeof (name), "test-%d", i % 256); GNUNET_STATISTICS_set (h, name, i, GNUNET_NO); GNUNET_snprintf (name, sizeof (name), "test-%d", i % 128); GNUNET_STATISTICS_update (h, name, 1, GNUNET_NO); } i = 0; GNUNET_break (NULL != GNUNET_STATISTICS_get (h, NULL, "test-0", GNUNET_TIME_UNIT_MINUTES, &next, &check_1, cls)); } static int check () { int ok = 1; char *const argv[] = { "test-statistics-api", "-c", "test_statistics_api_data.conf", NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; #if START_SERVICE struct GNUNET_OS_Process *proc; proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-statistics", "gnunet-service-statistics", #if DEBUG_STATISTICS "-L", "DEBUG", #endif "-c", "test_statistics_api_data.conf", NULL); #endif GNUNET_assert (NULL != proc); GNUNET_PROGRAM_run (3, argv, "test-statistics-api", "nohelp", options, &run, &ok); #if START_SERVICE if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); ok = 1; } GNUNET_OS_process_wait (proc); GNUNET_OS_process_destroy (proc); proc = NULL; #endif return ok; } int main (int argc, char *argv[]) { int ret; ret = check (); return ret; } /* end of test_statistics_api_loop.c */ gnunet-0.9.3/src/statistics/test_statistics_api_watch_zero_value.c0000644000175000017500000001224611760502551022603 00000000000000/* This file is part of GNUnet. (C) 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file statistics/test_statistics_api_watch_zero_value.c * @brief testcase for statistics_api.c watch functions with initial 0 value */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_statistics_service.h" #define VERBOSE GNUNET_NO #define START_SERVICE GNUNET_YES static int ok; static int ok2; static struct GNUNET_STATISTICS_Handle *h; static struct GNUNET_STATISTICS_Handle *h2; static GNUNET_SCHEDULER_TaskIdentifier shutdown_task; static void force_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { fprintf (stderr, "Timeout, failed to receive notifications: %d\n", ok); GNUNET_STATISTICS_destroy (h, GNUNET_NO); GNUNET_STATISTICS_destroy (h2, GNUNET_NO); ok = 7; } static void normal_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_STATISTICS_destroy (h, GNUNET_NO); GNUNET_STATISTICS_destroy (h2, GNUNET_NO); } static int watch_1 (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received value `%s' `%s' %llu\n", subsystem, name, value); GNUNET_assert (0 == strcmp (name, "test-1")); if ((0 == value) && (3 == ok)) { ok--; GNUNET_STATISTICS_set (h, "test-1", 42, GNUNET_NO); } if ((42 == value) && (2 == ok)) { ok--; GNUNET_STATISTICS_set (h, "test-1", 0, GNUNET_NO); } if ((0 == value) && (1 == ok)) { ok--; } if ((0 == ok) && (0 == ok2)) { GNUNET_SCHEDULER_cancel (shutdown_task); GNUNET_SCHEDULER_add_now (&normal_shutdown, NULL); } return GNUNET_OK; } static int watch_2 (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received value `%s' `%s' %llu\n", subsystem, name, value); GNUNET_assert (0 == strcmp (name, "test-2")); if ((42 == value) && (1 == ok2)) { ok2 = 0; if (0 == ok) { GNUNET_SCHEDULER_cancel (shutdown_task); GNUNET_SCHEDULER_add_now (&normal_shutdown, NULL); } } else { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Received unexpected value %llu\n", value); GNUNET_break (0); GNUNET_SCHEDULER_cancel (shutdown_task); GNUNET_SCHEDULER_add_now (&normal_shutdown, NULL); } return GNUNET_OK; } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { h = GNUNET_STATISTICS_create ("dummy", cfg); h2 = GNUNET_STATISTICS_create ("dummy-2", cfg); GNUNET_assert (GNUNET_OK == GNUNET_STATISTICS_watch (h, "dummy", "test-1", &watch_1, NULL)); GNUNET_assert (GNUNET_OK == GNUNET_STATISTICS_watch (h2, "dummy-2", "test-2", &watch_2, NULL)); /* Set initial value to 0 */ GNUNET_STATISTICS_set (h, "test-1", 0, GNUNET_NO); GNUNET_STATISTICS_set (h2, "test-2", 42, GNUNET_NO); shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &force_shutdown, NULL); } static int check () { char *const argv[] = { "test-statistics-api", "-c", "test_statistics_api_data.conf", NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; #if START_SERVICE struct GNUNET_OS_Process *proc; proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-statistics", "gnunet-service-statistics", #if VERBOSE "-L", "DEBUG", #endif "-c", "test_statistics_api_data.conf", NULL); #endif GNUNET_assert (NULL != proc); ok = 3; ok2 = 1; GNUNET_PROGRAM_run (3, argv, "test-statistics-api", "nohelp", options, &run, NULL); #if START_SERVICE if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); ok = 1; } GNUNET_OS_process_wait (proc); GNUNET_OS_process_destroy (proc); proc = NULL; #endif if ((0 == ok) && (0 == ok2)) return 0; else return 1; } int main (int argc, char *argv[]) { int ret; ret = check (); return ret; } /* end of test_statistics_api_watch_zero_value.c */ gnunet-0.9.3/src/statistics/gnunet-service-statistics.c0000644000175000017500000005207711760502551020234 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file statistics/gnunet-service-statistics.c * @brief program that tracks statistics * @author Christian Grothoff */ #include "platform.h" #include "gnunet_bio_lib.h" #include "gnunet_container_lib.h" #include "gnunet_disk_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_protocols.h" #include "gnunet_service_lib.h" #include "gnunet_statistics_service.h" #include "gnunet_strings_lib.h" #include "gnunet_time_lib.h" #include "statistics.h" /** * Watch entry. */ struct WatchEntry { /** * Watch entries are kept in a linked list. */ struct WatchEntry *next; /** * Watch entries are kept in a linked list. */ struct WatchEntry *prev; /** * For which client is this watch entry? */ struct GNUNET_SERVER_Client *client; /** * Last value we communicated to the client for this watch entry. */ uint64_t last_value; /** * Unique watch number for this client and this watched value. */ uint32_t wid; /** * Is last_value valid * GNUNET_NO : last_value is n/a, GNUNET_YES: last_value is valid */ int last_value_set; }; /** * Client entry. */ struct ClientEntry { /** * Clients are kept in a linked list. */ struct ClientEntry *next; /** * Clients are kept in a linked list. */ struct ClientEntry *prev; /** * Corresponding server handle. */ struct GNUNET_SERVER_Client *client; /** * Maximum watch ID used by this client so far. */ uint32_t max_wid; }; /** * Entry in the statistics list. */ struct StatsEntry { /** * This is a linked list. */ struct StatsEntry *next; /** * Name of the service, points into the * middle of msg. */ const char *service; /** * Name for the value, points into * the middle of msg. */ const char *name; /** * Message that can be used to set this value, * stored at the end of the memory used by * this struct. */ struct GNUNET_STATISTICS_SetMessage *msg; /** * Watch context for changes to this * value, or NULL for none. */ struct WatchEntry *we_head; /** * Watch context for changes to this * value, or NULL for none. */ struct WatchEntry *we_tail; /** * Our value. */ uint64_t value; /** * Unique ID. */ uint32_t uid; /** * Is this value persistent? */ int persistent; /** * Is this value set? * GNUNET_NO : value is n/a, GNUNET_YES: value is valid */ int set; }; /** * Our configuration. */ static const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Linked list of our active statistics. */ static struct StatsEntry *start; /** * Head of linked list of connected clients. */ static struct ClientEntry *client_head; /** * Tail of linked list of connected clients. */ static struct ClientEntry *client_tail; /** * Handle to our server. */ static struct GNUNET_SERVER_Handle *srv; /** * Our notification context. */ static struct GNUNET_SERVER_NotificationContext *nc; /** * Counter used to generate unique values. */ static uint32_t uidgen; /** * Set to YES if we are shutting down as soon as possible. */ static int in_shutdown; /** * Inject a message to our server with a client of 'NULL'. * * @param cls the 'struct GNUNET_SERVER_Handle' * @param client unused * @param msg message to inject */ static int inject_message (void *cls, void *client, const struct GNUNET_MessageHeader *msg) { struct GNUNET_SERVER_Handle *server = cls; GNUNET_break (GNUNET_OK == GNUNET_SERVER_inject (server, NULL, msg)); return GNUNET_OK; } /** * Load persistent values from disk. Disk format is * exactly the same format that we also use for * setting the values over the network. * * @param server handle to the server context */ static void load (struct GNUNET_SERVER_Handle *server) { char *fn; struct GNUNET_BIO_ReadHandle *rh; uint64_t fsize; char *buf; struct GNUNET_SERVER_MessageStreamTokenizer *mst; char *emsg; fn = GNUNET_DISK_get_home_filename (cfg, "statistics", "statistics.data", NULL); if (fn == NULL) return; if ((GNUNET_OK != GNUNET_DISK_file_size (fn, &fsize, GNUNET_NO, GNUNET_YES)) || (fsize == 0)) { GNUNET_free (fn); return; } buf = GNUNET_malloc (fsize); rh = GNUNET_BIO_read_open (fn); if (!rh) { GNUNET_free (buf); GNUNET_free (fn); return; } if (GNUNET_OK != GNUNET_BIO_read (rh, fn, buf, fsize)) { GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "read", fn); GNUNET_break (GNUNET_OK == GNUNET_BIO_read_close (rh, &emsg)); GNUNET_free (buf); GNUNET_free_non_null (emsg); GNUNET_free (fn); return; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading %llu bytes of statistics from `%s'\n"), fsize, fn); mst = GNUNET_SERVER_mst_create (&inject_message, server); GNUNET_break (GNUNET_OK == GNUNET_SERVER_mst_receive (mst, NULL, buf, fsize, GNUNET_YES, GNUNET_NO)); GNUNET_SERVER_mst_destroy (mst); GNUNET_free (buf); GNUNET_break (GNUNET_OK == GNUNET_BIO_read_close (rh, &emsg)); GNUNET_free_non_null (emsg); GNUNET_free (fn); } /** * Write persistent statistics to disk. */ static void save () { struct StatsEntry *pos; char *fn; struct GNUNET_BIO_WriteHandle *wh; uint16_t size; unsigned long long total; wh = NULL; fn = GNUNET_DISK_get_home_filename (cfg, "statistics", "statistics.data", NULL); if (fn != NULL) wh = GNUNET_BIO_write_open (fn); total = 0; while (NULL != (pos = start)) { start = pos->next; if ((pos->persistent) && (NULL != wh)) { size = htons (pos->msg->header.size); if (GNUNET_OK != GNUNET_BIO_write (wh, pos->msg, size)) { GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", fn); if (GNUNET_OK != GNUNET_BIO_write_close (wh)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "close", fn); wh = NULL; } else total += size; } GNUNET_free (pos); } if (NULL != wh) { if (GNUNET_OK != GNUNET_BIO_write_close (wh)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "close", fn); if (total == 0) GNUNET_break (0 == UNLINK (fn)); else GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Wrote %llu bytes of statistics to `%s'\n"), total, fn); } GNUNET_free_non_null (fn); } /** * Transmit the given stats value. * * @param client receiver of the value * @param e value to transmit */ static void transmit (struct GNUNET_SERVER_Client *client, const struct StatsEntry *e) { struct GNUNET_STATISTICS_ReplyMessage *m; size_t size; size = sizeof (struct GNUNET_STATISTICS_ReplyMessage) + strlen (e->service) + 1 + strlen (e->name) + 1; GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE); m = GNUNET_malloc (size); m->header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_VALUE); m->header.size = htons (size); m->uid = htonl (e->uid); if (e->persistent) m->uid |= htonl (GNUNET_STATISTICS_PERSIST_BIT); m->value = GNUNET_htonll (e->value); size -= sizeof (struct GNUNET_STATISTICS_ReplyMessage); GNUNET_assert (size == GNUNET_STRINGS_buffer_fill ((char *) &m[1], size, 2, e->service, e->name)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting value for `%s:%s' (%d): %llu\n", e->service, e->name, e->persistent, e->value); GNUNET_SERVER_notification_context_unicast (nc, client, &m->header, GNUNET_NO); GNUNET_free (m); } /** * Does this entry match the request? * * @param e an entry * @param service name of service to match * @param name value to match * @return 1 if they match, 0 if not */ static int matches (const struct StatsEntry *e, const char *service, const char *name) { return ((0 == strlen (service)) || (0 == strcmp (service, e->service))) && ((0 == strlen (name)) || (0 == strcmp (name, e->name))); } /** * Find a client entry for the given client handle, or create one. * * @param client handle to match * @return corresponding client entry struct */ static struct ClientEntry * make_client_entry (struct GNUNET_SERVER_Client *client) { struct ClientEntry *ce; GNUNET_assert (client != NULL); ce = client_head; while (ce != NULL) { if (ce->client == client) return ce; ce = ce->next; } if (NULL == nc) { GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return NULL; } ce = GNUNET_malloc (sizeof (struct ClientEntry)); ce->client = client; GNUNET_SERVER_client_keep (client); GNUNET_CONTAINER_DLL_insert (client_head, client_tail, ce); GNUNET_SERVER_notification_context_add (nc, client); return ce; } /** * Handle GET-message. * * @param cls closure * @param client identification of the client * @param message the actual message * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static void handle_get (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct GNUNET_MessageHeader end; char *service; char *name; struct StatsEntry *pos; size_t size; if ( (NULL != client) && (NULL == make_client_entry (client)) ) return; /* new client during shutdown */ size = ntohs (message->size) - sizeof (struct GNUNET_MessageHeader); if (size != GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1], size, 2, &service, &name)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received request for statistics on `%s:%s'\n", strlen (service) ? service : "*", strlen (name) ? name : "*"); for (pos = start; NULL != pos; pos = pos->next) if (matches (pos, service, name)) transmit (client, pos); end.size = htons (sizeof (struct GNUNET_MessageHeader)); end.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_END); GNUNET_SERVER_notification_context_unicast (nc, client, &end, GNUNET_NO); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Notify all clients listening about a change to a value. * * @param se value that changed */ static void notify_change (struct StatsEntry *se) { struct GNUNET_STATISTICS_WatchValueMessage wvm; struct WatchEntry *pos; for (pos = se->we_head; NULL != pos; pos = pos->next) { if (GNUNET_YES == pos->last_value_set) { if (pos->last_value == se->value) continue; } else { pos->last_value_set = GNUNET_YES; } wvm.header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE); wvm.header.size = htons (sizeof (struct GNUNET_STATISTICS_WatchValueMessage)); wvm.flags = htonl (se->persistent ? GNUNET_STATISTICS_PERSIST_BIT : 0); wvm.wid = htonl (pos->wid); wvm.reserved = htonl (0); wvm.value = GNUNET_htonll (se->value); GNUNET_SERVER_notification_context_unicast (nc, pos->client, &wvm.header, GNUNET_NO); pos->last_value = se->value; } } /** * Handle SET-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_set (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { char *service; char *name; uint16_t msize; uint16_t size; const struct GNUNET_STATISTICS_SetMessage *msg; struct StatsEntry *pos; struct StatsEntry *prev; uint32_t flags; uint64_t value; int64_t delta; int changed; int initial_set; if ( (NULL != client) && (NULL == make_client_entry (client)) ) return; /* new client during shutdown */ msize = ntohs (message->size); if (msize < sizeof (struct GNUNET_STATISTICS_SetMessage)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } size = msize - sizeof (struct GNUNET_STATISTICS_SetMessage); msg = (const struct GNUNET_STATISTICS_SetMessage *) message; if (size != GNUNET_STRINGS_buffer_tokenize ((const char *) &msg[1], size, 2, &service, &name)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } flags = ntohl (msg->flags); value = GNUNET_ntohll (msg->value); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received request to update statistic on `%s:%s' (%u) to/by %llu\n", service, name, (unsigned int) flags, (unsigned long long) value); pos = start; prev = NULL; while (pos != NULL) { if (matches (pos, service, name)) { initial_set = 0; if ((flags & GNUNET_STATISTICS_SETFLAG_RELATIVE) == 0) { changed = (pos->value != value); pos->value = value; } else { delta = (int64_t) value; if ((delta < 0) && (pos->value < -delta)) { changed = (pos->value != 0); pos->value = 0; } else { changed = (delta != 0); GNUNET_break ((delta <= 0) || (pos->value + delta > pos->value)); pos->value += delta; } } if (GNUNET_NO == pos->set) { pos->set = GNUNET_YES; initial_set = 1; } pos->msg->value = GNUNET_htonll (pos->value); pos->msg->flags = msg->flags; pos->persistent = (0 != (flags & GNUNET_STATISTICS_SETFLAG_PERSISTENT)); if (prev != NULL) { /* move to front for faster setting next time! */ prev->next = pos->next; pos->next = start; start = pos; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Statistic `%s:%s' updated to value %llu.\n", service, name, pos->value); if ((changed) || (1 == initial_set)) notify_change (pos); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } prev = pos; pos = pos->next; } pos = GNUNET_malloc (sizeof (struct StatsEntry) + msize); pos->next = start; if (((flags & GNUNET_STATISTICS_SETFLAG_RELATIVE) == 0) || (0 < (int64_t) GNUNET_ntohll (msg->value))) { pos->value = GNUNET_ntohll (msg->value); pos->set = GNUNET_YES; } else { pos->set = GNUNET_NO; } pos->uid = uidgen++; pos->persistent = (0 != (flags & GNUNET_STATISTICS_SETFLAG_PERSISTENT)); pos->msg = (void *) &pos[1]; memcpy (pos->msg, message, ntohs (message->size)); pos->service = (const char *) &pos->msg[1]; pos->name = &pos->service[strlen (pos->service) + 1]; start = pos; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New statistic on `%s:%s' with value %llu created.\n", service, name, pos->value); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Handle WATCH-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_watch (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { char *service; char *name; uint16_t msize; uint16_t size; struct StatsEntry *pos; struct ClientEntry *ce; struct WatchEntry *we; size_t slen; if (NULL == nc) { GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_SERVER_client_mark_monitor (client); ce = make_client_entry (client); msize = ntohs (message->size); if (msize < sizeof (struct GNUNET_MessageHeader)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } size = msize - sizeof (struct GNUNET_MessageHeader); if (size != GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1], size, 2, &service, &name)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received request to watch statistic on `%s:%s'\n", service, name); pos = start; while (pos != NULL) { if (matches (pos, service, name)) break; pos = pos->next; } if (pos == NULL) { pos = GNUNET_malloc (sizeof (struct StatsEntry) + sizeof (struct GNUNET_STATISTICS_SetMessage) + size); pos->next = start; pos->uid = uidgen++; pos->set = GNUNET_NO; pos->msg = (void *) &pos[1]; pos->msg->header.size = htons (sizeof (struct GNUNET_STATISTICS_SetMessage) + size); pos->msg->header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_SET); pos->service = (const char *) &pos->msg[1]; slen = strlen (service) + 1; memcpy ((void *) pos->service, service, slen); pos->name = &pos->service[slen]; memcpy ((void *) pos->name, name, strlen (name) + 1); start = pos; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New statistic on `%s:%s' with value %llu created.\n", service, name, pos->value); } we = GNUNET_malloc (sizeof (struct WatchEntry)); we->client = client; we->last_value_set = GNUNET_NO; GNUNET_SERVER_client_keep (client); we->wid = ce->max_wid++; GNUNET_CONTAINER_DLL_insert (pos->we_head, pos->we_tail, we); if (pos->value != 0) notify_change (pos); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Actually perform the shutdown. */ static void do_shutdown () { struct WatchEntry *we; struct StatsEntry *se; if (NULL == nc) return; save (); GNUNET_SERVER_notification_context_destroy (nc); nc = NULL; GNUNET_assert (NULL == client_head); while (NULL != (se = start)) { start = se->next; while (NULL != (we = se->we_head)) { GNUNET_SERVER_client_drop (we->client); GNUNET_CONTAINER_DLL_remove (se->we_head, se->we_tail, we); GNUNET_free (we); } GNUNET_free (se); } } /** * Task run during shutdown. * * @param cls unused * @param tc unused */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { in_shutdown = GNUNET_YES; if (NULL != client_head) return; do_shutdown (); } /** * A client disconnected. Remove all of its data structure entries. * * @param cls closure, NULL * @param client identification of the client */ static void handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) { struct ClientEntry *ce; struct WatchEntry *we; struct WatchEntry *wen; struct StatsEntry *se; ce = client_head; while (NULL != ce) { if (ce->client == client) { GNUNET_SERVER_client_drop (ce->client); GNUNET_CONTAINER_DLL_remove (client_head, client_tail, ce); GNUNET_free (ce); break; } ce = ce->next; } se = start; while (NULL != se) { wen = se->we_head; while (NULL != (we = wen)) { wen = we->next; if (we->client != client) continue; GNUNET_SERVER_client_drop (we->client); GNUNET_CONTAINER_DLL_remove (se->we_head, se->we_tail, we); GNUNET_free (we); } se = se->next; } if ( (NULL == client_head) && (GNUNET_YES == in_shutdown) ) do_shutdown (); } /** * Process statistics requests. * * @param cls closure * @param server the initialized server * @param c configuration to use */ static void run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *c) { static const struct GNUNET_SERVER_MessageHandler handlers[] = { {&handle_set, NULL, GNUNET_MESSAGE_TYPE_STATISTICS_SET, 0}, {&handle_get, NULL, GNUNET_MESSAGE_TYPE_STATISTICS_GET, 0}, {&handle_watch, NULL, GNUNET_MESSAGE_TYPE_STATISTICS_WATCH, 0}, {NULL, NULL, 0, 0} }; cfg = c; srv = server; GNUNET_SERVER_add_handlers (server, handlers); nc = GNUNET_SERVER_notification_context_create (server, 16); GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); load (server); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); } /** * The main function for the statistics service. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { return (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "statistics", GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN, &run, NULL)) ? 0 : 1; } /* end of gnunet-service-statistics.c */ gnunet-0.9.3/src/statistics/statistics_api.c0000644000175000017500000010536011760502551016123 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file statistics/statistics_api.c * @brief API of the statistics service * @author Christian Grothoff */ #include "platform.h" #include "gnunet_client_lib.h" #include "gnunet_constants.h" #include "gnunet_container_lib.h" #include "gnunet_protocols.h" #include "gnunet_server_lib.h" #include "gnunet_statistics_service.h" #include "gnunet_strings_lib.h" #include "statistics.h" /** * How long do we wait until a statistics request for setting * a value times out? (The update will be lost if the * service does not react within this timeframe). */ #define SET_TRANSMIT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2) #define LOG(kind,...) GNUNET_log_from (kind, "statistics-api",__VA_ARGS__) /** * Types of actions. */ enum ActionType { /** * Get a value. */ ACTION_GET, /** * Set a value. */ ACTION_SET, /** * Update a value. */ ACTION_UPDATE, /** * Watch a value. */ ACTION_WATCH }; /** * Entry kept for each value we are watching. */ struct GNUNET_STATISTICS_WatchEntry { /** * What subsystem is this action about? (never NULL) */ char *subsystem; /** * What value is this action about? (never NULL) */ char *name; /** * Function to call */ GNUNET_STATISTICS_Iterator proc; /** * Closure for proc */ void *proc_cls; }; /** * Linked list of things we still need to do. */ struct GNUNET_STATISTICS_GetHandle { /** * This is a doubly linked list. */ struct GNUNET_STATISTICS_GetHandle *next; /** * This is a doubly linked list. */ struct GNUNET_STATISTICS_GetHandle *prev; /** * Main statistics handle. */ struct GNUNET_STATISTICS_Handle *sh; /** * What subsystem is this action about? (can be NULL) */ char *subsystem; /** * What value is this action about? (can be NULL) */ char *name; /** * Continuation to call once action is complete. */ GNUNET_STATISTICS_Callback cont; /** * Function to call (for GET actions only). */ GNUNET_STATISTICS_Iterator proc; /** * Closure for proc and cont. */ void *cls; /** * Timeout for this action. */ struct GNUNET_TIME_Absolute timeout; /** * Associated value. */ uint64_t value; /** * Flag for SET/UPDATE actions. */ int make_persistent; /** * Has the current iteration been aborted; for GET actions. */ int aborted; /** * Is this a GET, SET, UPDATE or WATCH? */ enum ActionType type; /** * Size of the message that we will be transmitting. */ uint16_t msize; }; /** * Handle for the service. */ struct GNUNET_STATISTICS_Handle { /** * Name of our subsystem. */ char *subsystem; /** * Configuration to use. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Socket (if available). */ struct GNUNET_CLIENT_Connection *client; /** * Currently pending transmission request. */ struct GNUNET_CLIENT_TransmitHandle *th; /** * Head of the linked list of pending actions (first action * to be performed). */ struct GNUNET_STATISTICS_GetHandle *action_head; /** * Tail of the linked list of actions (for fast append). */ struct GNUNET_STATISTICS_GetHandle *action_tail; /** * Action we are currently busy with (action request has been * transmitted, we're now receiving the response from the * service). */ struct GNUNET_STATISTICS_GetHandle *current; /** * Array of watch entries. */ struct GNUNET_STATISTICS_WatchEntry **watches; /** * Task doing exponential back-off trying to reconnect. */ GNUNET_SCHEDULER_TaskIdentifier backoff_task; /** * Time for next connect retry. */ struct GNUNET_TIME_Relative backoff; /** * Size of the 'watches' array. */ unsigned int watches_size; /** * Should this handle auto-destruct once all actions have * been processed? */ int do_destroy; /** * Are we currently receiving from the service? */ int receiving; }; /** * Schedule the next action to be performed. * * @param h statistics handle to reconnect */ static void schedule_action (struct GNUNET_STATISTICS_Handle *h); /** * Transmit request to service that we want to watch * the development of a particular value. * * @param h statistics handle * @param watch watch entry of the value to watch */ static void schedule_watch_request (struct GNUNET_STATISTICS_Handle *h, struct GNUNET_STATISTICS_WatchEntry *watch) { struct GNUNET_STATISTICS_GetHandle *ai; size_t slen; size_t nlen; size_t nsize; GNUNET_assert (NULL != h); GNUNET_assert (NULL != watch); slen = strlen (watch->subsystem) + 1; nlen = strlen (watch->name) + 1; nsize = sizeof (struct GNUNET_MessageHeader) + slen + nlen; if (nsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); return; } ai = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_GetHandle)); ai->sh = h; ai->subsystem = GNUNET_strdup (watch->subsystem); ai->name = GNUNET_strdup (watch->name); ai->timeout = GNUNET_TIME_UNIT_FOREVER_ABS; ai->msize = nsize; ai->type = ACTION_WATCH; ai->proc = watch->proc; ai->cls = watch->proc_cls; GNUNET_CONTAINER_DLL_insert_tail (h->action_head, h->action_tail, ai); schedule_action (h); } /** * Free memory associated with the given action item. * * @param gh action item to free */ static void free_action_item (struct GNUNET_STATISTICS_GetHandle *gh) { GNUNET_free_non_null (gh->subsystem); GNUNET_free_non_null (gh->name); GNUNET_free (gh); } /** * Disconnect from the statistics service. * * @param h statistics handle to disconnect from */ static void do_disconnect (struct GNUNET_STATISTICS_Handle *h) { struct GNUNET_STATISTICS_GetHandle *c; if (NULL != h->th) { GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); h->th = NULL; } if (NULL != h->client) { GNUNET_CLIENT_disconnect (h->client); h->client = NULL; } h->receiving = GNUNET_NO; if (NULL != (c = h->current)) { h->current = NULL; if (NULL != c->cont) c->cont (c->cls, GNUNET_SYSERR); free_action_item (c); } } /** * Try to (re)connect to the statistics service. * * @param h statistics handle to reconnect * @return GNUNET_YES on success, GNUNET_NO on failure. */ static int try_connect (struct GNUNET_STATISTICS_Handle *h) { struct GNUNET_STATISTICS_GetHandle *gh; struct GNUNET_STATISTICS_GetHandle *gn; unsigned int i; if (GNUNET_SCHEDULER_NO_TASK != h->backoff_task) return GNUNET_NO; if (NULL != h->client) return GNUNET_YES; h->client = GNUNET_CLIENT_connect ("statistics", h->cfg); if (NULL != h->client) { gn = h->action_head; while (NULL != (gh = gn)) { gn = gh->next; if (gh->type == ACTION_WATCH) { GNUNET_CONTAINER_DLL_remove (h->action_head, h->action_tail, gh); free_action_item (gh); } } for (i = 0; i < h->watches_size; i++) { if (NULL != h->watches[i]) schedule_watch_request (h, h->watches[i]); } return GNUNET_YES; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect to statistics service!\n"); return GNUNET_NO; } /** * We've waited long enough, reconnect now. * * @param cls the 'struct GNUNET_STATISTICS_Handle' to reconnect * @param tc scheduler context (unused) */ static void reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_STATISTICS_Handle *h = cls; h->backoff_task = GNUNET_SCHEDULER_NO_TASK; schedule_action (h); } /** * Task used by 'reconnect_later' to shutdown the handle * * @param cls the statistics handle * @param tc scheduler context */ static void do_destroy (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_STATISTICS_Handle *h = cls; GNUNET_STATISTICS_destroy (h, GNUNET_NO); } /** * Reconnect at a later time, respecting back-off. * * @param h statistics handle */ static void reconnect_later (struct GNUNET_STATISTICS_Handle *h) { int loss; struct GNUNET_STATISTICS_GetHandle *gh; GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->backoff_task); if (GNUNET_YES == h->do_destroy) { /* So we are shutting down and the service is not reachable. * Chances are that it's down for good and we are not going to connect to * it anymore. * Give up and don't sync the rest of the data. */ loss = GNUNET_NO; for (gh = h->action_head; NULL != gh; gh = gh->next) if ( (gh->make_persistent) && (ACTION_SET == gh->type) ) loss = GNUNET_YES; if (GNUNET_YES == loss) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Could not save some persistent statistics\n")); h->do_destroy = GNUNET_NO; GNUNET_SCHEDULER_add_continuation (&do_destroy, h, GNUNET_SCHEDULER_REASON_PREREQ_DONE); return; } h->backoff_task = GNUNET_SCHEDULER_add_delayed (h->backoff, &reconnect_task, h); h->backoff = GNUNET_TIME_relative_multiply (h->backoff, 2); h->backoff = GNUNET_TIME_relative_min (h->backoff, GNUNET_CONSTANTS_SERVICE_TIMEOUT); } /** * Process a 'GNUNET_MESSAGE_TYPE_STATISTICS_VALUE' message. * * @param h statistics handle * @param msg message received from the service, never NULL * @return GNUNET_OK if the message was well-formed */ static int process_statistics_value_message (struct GNUNET_STATISTICS_Handle *h, const struct GNUNET_MessageHeader *msg) { char *service; char *name; const struct GNUNET_STATISTICS_ReplyMessage *smsg; uint16_t size; if (h->current->aborted) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Iteration was aborted, ignoring VALUE\n"); return GNUNET_OK; /* don't bother */ } size = ntohs (msg->size); if (size < sizeof (struct GNUNET_STATISTICS_ReplyMessage)) { GNUNET_break (0); return GNUNET_SYSERR; } smsg = (const struct GNUNET_STATISTICS_ReplyMessage *) msg; size -= sizeof (struct GNUNET_STATISTICS_ReplyMessage); if (size != GNUNET_STRINGS_buffer_tokenize ((const char *) &smsg[1], size, 2, &service, &name)) { GNUNET_break (0); return GNUNET_SYSERR; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Received valid statistic on `%s:%s': %llu\n", service, name, GNUNET_ntohll (smsg->value)); if (GNUNET_OK != h->current->proc (h->current->cls, service, name, GNUNET_ntohll (smsg->value), 0 != (ntohl (smsg->uid) & GNUNET_STATISTICS_PERSIST_BIT))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing of remaining statistics aborted by client.\n"); h->current->aborted = GNUNET_YES; } LOG (GNUNET_ERROR_TYPE_DEBUG, "VALUE processed successfully\n"); return GNUNET_OK; } /** * We have received a watch value from the service. Process it. * * @param h statistics handle * @param msg the watch value message * @return GNUNET_OK if the message was well-formed, GNUNET_SYSERR if not, * GNUNET_NO if this watch has been cancelled */ static int process_watch_value (struct GNUNET_STATISTICS_Handle *h, const struct GNUNET_MessageHeader *msg) { const struct GNUNET_STATISTICS_WatchValueMessage *wvm; struct GNUNET_STATISTICS_WatchEntry *w; uint32_t wid; if (sizeof (struct GNUNET_STATISTICS_WatchValueMessage) != ntohs (msg->size)) { GNUNET_break (0); return GNUNET_SYSERR; } wvm = (const struct GNUNET_STATISTICS_WatchValueMessage *) msg; GNUNET_break (0 == ntohl (wvm->reserved)); wid = ntohl (wvm->wid); if (wid >= h->watches_size) { GNUNET_break (0); return GNUNET_SYSERR; } w = h->watches[wid]; if (NULL == w) return GNUNET_NO; (void) w->proc (w->proc_cls, w->subsystem, w->name, GNUNET_ntohll (wvm->value), 0 != (ntohl (wvm->flags) & GNUNET_STATISTICS_PERSIST_BIT)); return GNUNET_OK; } static void destroy_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_STATISTICS_Handle *h = cls; GNUNET_STATISTICS_destroy (h, GNUNET_NO); } /** * Function called with messages from stats service. * * @param cls closure * @param msg message received, NULL on timeout or fatal error */ static void receive_stats (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_STATISTICS_Handle *h = cls; struct GNUNET_STATISTICS_GetHandle *c; int ret; if (NULL == msg) { LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "Error receiving statistics from service, is the service running?\n"); do_disconnect (h); reconnect_later (h); return; } switch (ntohs (msg->type)) { case GNUNET_MESSAGE_TYPE_TEST: if (GNUNET_SYSERR != h->do_destroy) { /* not in shutdown, why do we get 'TEST'? */ GNUNET_break (0); do_disconnect (h); reconnect_later (h); return; } h->do_destroy = GNUNET_NO; GNUNET_SCHEDULER_add_continuation (&destroy_task, h, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_MESSAGE_TYPE_STATISTICS_END: LOG (GNUNET_ERROR_TYPE_DEBUG, "Received end of statistics marker\n"); if (NULL == (c = h->current)) { GNUNET_break (0); do_disconnect (h); reconnect_later (h); return; } h->backoff = GNUNET_TIME_UNIT_MILLISECONDS; if (h->watches_size > 0) { GNUNET_CLIENT_receive (h->client, &receive_stats, h, GNUNET_TIME_UNIT_FOREVER_REL); } else { h->receiving = GNUNET_NO; } h->current = NULL; schedule_action (h); if (NULL != c->cont) c->cont (c->cls, GNUNET_OK); free_action_item (c); return; case GNUNET_MESSAGE_TYPE_STATISTICS_VALUE: if (GNUNET_OK != process_statistics_value_message (h, msg)) { do_disconnect (h); reconnect_later (h); return; } /* finally, look for more! */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing VALUE done, now reading more\n"); GNUNET_CLIENT_receive (h->client, &receive_stats, h, GNUNET_TIME_absolute_get_remaining (h-> current->timeout)); h->backoff = GNUNET_TIME_UNIT_MILLISECONDS; return; case GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE: if (GNUNET_OK != (ret = process_watch_value (h, msg))) { do_disconnect (h); if (GNUNET_NO == ret) h->backoff = GNUNET_TIME_UNIT_MILLISECONDS; reconnect_later (h); return; } h->backoff = GNUNET_TIME_UNIT_MILLISECONDS; GNUNET_assert (h->watches_size > 0); GNUNET_CLIENT_receive (h->client, &receive_stats, h, GNUNET_TIME_UNIT_FOREVER_REL); return; default: GNUNET_break (0); do_disconnect (h); reconnect_later (h); return; } } /** * Transmit a GET request (and if successful, start to receive * the response). * * @param handle statistics handle * @param size how many bytes can we write to buf * @param buf where to write requests to the service * @return number of bytes written to buf */ static size_t transmit_get (struct GNUNET_STATISTICS_Handle *handle, size_t size, void *buf) { struct GNUNET_STATISTICS_GetHandle *c; struct GNUNET_MessageHeader *hdr; size_t slen1; size_t slen2; uint16_t msize; GNUNET_assert (NULL != (c = handle->current)); if (NULL == buf) { /* timeout / error */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission of request for statistics failed!\n"); do_disconnect (handle); reconnect_later (handle); return 0; } slen1 = strlen (c->subsystem) + 1; slen2 = strlen (c->name) + 1; msize = slen1 + slen2 + sizeof (struct GNUNET_MessageHeader); GNUNET_assert (msize <= size); hdr = (struct GNUNET_MessageHeader *) buf; hdr->size = htons (msize); hdr->type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_GET); GNUNET_assert (slen1 + slen2 == GNUNET_STRINGS_buffer_fill ((char *) &hdr[1], slen1 + slen2, 2, c->subsystem, c->name)); if (GNUNET_YES != handle->receiving) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission of GET done, now reading response\n"); handle->receiving = GNUNET_YES; GNUNET_CLIENT_receive (handle->client, &receive_stats, handle, GNUNET_TIME_absolute_get_remaining (c->timeout)); } return msize; } /** * Transmit a WATCH request (and if successful, start to receive * the response). * * @param handle statistics handle * @param size how many bytes can we write to buf * @param buf where to write requests to the service * @return number of bytes written to buf */ static size_t transmit_watch (struct GNUNET_STATISTICS_Handle *handle, size_t size, void *buf) { struct GNUNET_MessageHeader *hdr; size_t slen1; size_t slen2; uint16_t msize; if (NULL == buf) { /* timeout / error */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission of request for statistics failed!\n"); do_disconnect (handle); reconnect_later (handle); return 0; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting watch request for `%s'\n", handle->current->name); slen1 = strlen (handle->current->subsystem) + 1; slen2 = strlen (handle->current->name) + 1; msize = slen1 + slen2 + sizeof (struct GNUNET_MessageHeader); GNUNET_assert (msize <= size); hdr = (struct GNUNET_MessageHeader *) buf; hdr->size = htons (msize); hdr->type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_WATCH); GNUNET_assert (slen1 + slen2 == GNUNET_STRINGS_buffer_fill ((char *) &hdr[1], slen1 + slen2, 2, handle->current->subsystem, handle->current->name)); if (GNUNET_YES != handle->receiving) { handle->receiving = GNUNET_YES; GNUNET_CLIENT_receive (handle->client, &receive_stats, handle, GNUNET_TIME_UNIT_FOREVER_REL); } GNUNET_assert (NULL == handle->current->cont); free_action_item (handle->current); handle->current = NULL; return msize; } /** * Transmit a SET/UPDATE request. * * @param handle statistics handle * @param size how many bytes can we write to buf * @param buf where to write requests to the service * @return number of bytes written to buf */ static size_t transmit_set (struct GNUNET_STATISTICS_Handle *handle, size_t size, void *buf) { struct GNUNET_STATISTICS_SetMessage *r; size_t slen; size_t nlen; size_t nsize; if (NULL == buf) { do_disconnect (handle); reconnect_later (handle); return 0; } slen = strlen (handle->current->subsystem) + 1; nlen = strlen (handle->current->name) + 1; nsize = sizeof (struct GNUNET_STATISTICS_SetMessage) + slen + nlen; if (size < nsize) { GNUNET_break (0); do_disconnect (handle); reconnect_later (handle); return 0; } r = buf; r->header.size = htons (nsize); r->header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_SET); r->flags = 0; r->value = GNUNET_htonll (handle->current->value); if (handle->current->make_persistent) r->flags |= htonl (GNUNET_STATISTICS_SETFLAG_PERSISTENT); if (handle->current->type == ACTION_UPDATE) r->flags |= htonl (GNUNET_STATISTICS_SETFLAG_RELATIVE); GNUNET_assert (slen + nlen == GNUNET_STRINGS_buffer_fill ((char *) &r[1], slen + nlen, 2, handle->current->subsystem, handle->current->name)); GNUNET_assert (NULL == handle->current->cont); free_action_item (handle->current); handle->current = NULL; return nsize; } /** * Function called when we are ready to transmit a request to the service. * * @param cls the 'struct GNUNET_STATISTICS_Handle' * @param size how many bytes can we write to buf * @param buf where to write requests to the service * @return number of bytes written to buf */ static size_t transmit_action (void *cls, size_t size, void *buf) { struct GNUNET_STATISTICS_Handle *h = cls; size_t ret; h->th = NULL; ret = 0; if (NULL != h->current) switch (h->current->type) { case ACTION_GET: ret = transmit_get (h, size, buf); break; case ACTION_SET: case ACTION_UPDATE: ret = transmit_set (h, size, buf); break; case ACTION_WATCH: ret = transmit_watch (h, size, buf); break; default: GNUNET_assert (0); break; } schedule_action (h); return ret; } /** * Get handle for the statistics service. * * @param subsystem name of subsystem using the service * @param cfg services configuration in use * @return handle to use */ struct GNUNET_STATISTICS_Handle * GNUNET_STATISTICS_create (const char *subsystem, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_STATISTICS_Handle *ret; GNUNET_assert (NULL != subsystem); GNUNET_assert (NULL != cfg); ret = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_Handle)); ret->cfg = cfg; ret->subsystem = GNUNET_strdup (subsystem); ret->backoff = GNUNET_TIME_UNIT_MILLISECONDS; return ret; } /** * Destroy a handle (free all state associated with * it). * * @param h statistics handle to destroy * @param sync_first set to GNUNET_YES if pending SET requests should * be completed */ void GNUNET_STATISTICS_destroy (struct GNUNET_STATISTICS_Handle *h, int sync_first) { struct GNUNET_STATISTICS_GetHandle *pos; struct GNUNET_STATISTICS_GetHandle *next; struct GNUNET_TIME_Relative timeout; int i; if (NULL == h) return; GNUNET_assert (GNUNET_NO == h->do_destroy); // Don't call twice. if (GNUNET_SCHEDULER_NO_TASK != h->backoff_task) { GNUNET_SCHEDULER_cancel (h->backoff_task); h->backoff_task = GNUNET_SCHEDULER_NO_TASK; } if (sync_first) { if (NULL != h->current) { if (ACTION_GET == h->current->type) { GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); h->th = NULL; free_action_item (h->current); h->current = NULL; } } next = h->action_head; while (NULL != (pos = next)) { next = pos->next; if (ACTION_GET == pos->type) { GNUNET_CONTAINER_DLL_remove (h->action_head, h->action_tail, pos); free_action_item (pos); } } if ( (NULL == h->current) && (NULL != (h->current = h->action_head)) ) GNUNET_CONTAINER_DLL_remove (h->action_head, h->action_tail, h->current); h->do_destroy = GNUNET_YES; if ((NULL != h->current) && (NULL == h->th) && (NULL != h->client)) { timeout = GNUNET_TIME_absolute_get_remaining (h->current->timeout); h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, h->current->msize, timeout, GNUNET_YES, &transmit_action, h); GNUNET_assert (NULL != h->th); } if (NULL != h->th) return; /* do not finish destruction just yet */ } while (NULL != (pos = h->action_head)) { GNUNET_CONTAINER_DLL_remove (h->action_head, h->action_tail, pos); free_action_item (pos); } do_disconnect (h); for (i = 0; i < h->watches_size; i++) { if (NULL == h->watches[i]) continue; GNUNET_free (h->watches[i]->subsystem); GNUNET_free (h->watches[i]->name); GNUNET_free (h->watches[i]); } GNUNET_array_grow (h->watches, h->watches_size, 0); GNUNET_free (h->subsystem); GNUNET_free (h); } /** * Function called to transmit TEST message to service to * confirm that the service has received all of our 'SET' * messages (during statistics disconnect/shutdown). * * @param cls the 'struct GNUNET_STATISTICS_Handle' * @param size how many bytes can we write to buf * @param buf where to write requests to the service * @return number of bytes written to buf */ static size_t transmit_test_on_shutdown (void *cls, size_t size, void *buf) { struct GNUNET_STATISTICS_Handle *h = cls; struct GNUNET_MessageHeader hdr; h->th = NULL; if (NULL == buf) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to receive acknowledgement from statistics service, some statistics might have been lost!\n")); h->do_destroy = GNUNET_NO; GNUNET_SCHEDULER_add_continuation (&destroy_task, h, GNUNET_SCHEDULER_REASON_PREREQ_DONE); return 0; } hdr.type = htons (GNUNET_MESSAGE_TYPE_TEST); hdr.size = htons (sizeof (struct GNUNET_MessageHeader)); memcpy (buf, &hdr, sizeof (hdr)); if (GNUNET_YES != h->receiving) { h->receiving = GNUNET_YES; GNUNET_CLIENT_receive (h->client, &receive_stats, h, GNUNET_TIME_UNIT_FOREVER_REL); } return sizeof (struct GNUNET_MessageHeader); } /** * Schedule the next action to be performed. * * @param h statistics handle */ static void schedule_action (struct GNUNET_STATISTICS_Handle *h) { struct GNUNET_TIME_Relative timeout; if ( (NULL != h->th) || (GNUNET_SCHEDULER_NO_TASK != h->backoff_task) ) return; /* action already pending */ if (GNUNET_YES != try_connect (h)) { reconnect_later (h); return; } if (NULL != h->current) return; /* action already pending */ /* schedule next action */ h->current = h->action_head; if (NULL == h->current) { if (GNUNET_YES == h->do_destroy) { h->do_destroy = GNUNET_SYSERR; /* in 'TEST' mode */ h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, sizeof (struct GNUNET_MessageHeader), SET_TRANSMIT_TIMEOUT, GNUNET_NO, &transmit_test_on_shutdown, h); } return; } GNUNET_CONTAINER_DLL_remove (h->action_head, h->action_tail, h->current); timeout = GNUNET_TIME_absolute_get_remaining (h->current->timeout); if (NULL == (h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, h->current->msize, timeout, GNUNET_YES, &transmit_action, h))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to transmit request to statistics service.\n"); do_disconnect (h); reconnect_later (h); } } /** * Get statistic from the peer. * * @param handle identification of the statistics service * @param subsystem limit to the specified subsystem, NULL for our subsystem * @param name name of the statistic value, NULL for all values * @param timeout after how long should we give up (and call * cont with an error code)? * @param cont continuation to call when done (can be NULL) * This callback CANNOT destroy the statistics handle in the same call. * @param proc function to call on each value * @param cls closure for cont and proc * @return NULL on error */ struct GNUNET_STATISTICS_GetHandle * GNUNET_STATISTICS_get (struct GNUNET_STATISTICS_Handle *handle, const char *subsystem, const char *name, struct GNUNET_TIME_Relative timeout, GNUNET_STATISTICS_Callback cont, GNUNET_STATISTICS_Iterator proc, void *cls) { size_t slen1; size_t slen2; struct GNUNET_STATISTICS_GetHandle *ai; if (NULL == handle) return NULL; GNUNET_assert (NULL != proc); GNUNET_assert (GNUNET_NO == handle->do_destroy); if (NULL == subsystem) subsystem = ""; if (NULL == name) name = ""; slen1 = strlen (subsystem) + 1; slen2 = strlen (name) + 1; GNUNET_assert (slen1 + slen2 + sizeof (struct GNUNET_MessageHeader) < GNUNET_SERVER_MAX_MESSAGE_SIZE); ai = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_GetHandle)); ai->sh = handle; ai->subsystem = GNUNET_strdup (subsystem); ai->name = GNUNET_strdup (name); ai->cont = cont; ai->proc = proc; ai->cls = cls; ai->timeout = GNUNET_TIME_relative_to_absolute (timeout); ai->type = ACTION_GET; ai->msize = slen1 + slen2 + sizeof (struct GNUNET_MessageHeader); GNUNET_CONTAINER_DLL_insert_tail (handle->action_head, handle->action_tail, ai); schedule_action (handle); return ai; } /** * Cancel a 'get' request. Must be called before the 'cont' * function is called. * * @param gh handle of the request to cancel */ void GNUNET_STATISTICS_get_cancel (struct GNUNET_STATISTICS_GetHandle *gh) { if (NULL == gh) return; if (gh->sh->current == gh) { gh->aborted = GNUNET_YES; } else { GNUNET_CONTAINER_DLL_remove (gh->sh->action_head, gh->sh->action_tail, gh); GNUNET_free (gh->name); GNUNET_free (gh->subsystem); GNUNET_free (gh); } } /** * Watch statistics from the peer (be notified whenever they change). * * @param handle identification of the statistics service * @param subsystem limit to the specified subsystem, never NULL * @param name name of the statistic value, never NULL * @param proc function to call on each value * @param proc_cls closure for proc * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_STATISTICS_watch (struct GNUNET_STATISTICS_Handle *handle, const char *subsystem, const char *name, GNUNET_STATISTICS_Iterator proc, void *proc_cls) { struct GNUNET_STATISTICS_WatchEntry *w; if (NULL == handle) return GNUNET_SYSERR; w = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_WatchEntry)); w->subsystem = GNUNET_strdup (subsystem); w->name = GNUNET_strdup (name); w->proc = proc; w->proc_cls = proc_cls; GNUNET_array_append (handle->watches, handle->watches_size, w); schedule_watch_request (handle, w); return GNUNET_OK; } /** * Stop watching statistics from the peer. * * @param handle identification of the statistics service * @param subsystem limit to the specified subsystem, never NULL * @param name name of the statistic value, never NULL * @param proc function to call on each value * @param proc_cls closure for proc * @return GNUNET_OK on success, GNUNET_SYSERR on error (no such watch) */ int GNUNET_STATISTICS_watch_cancel (struct GNUNET_STATISTICS_Handle *handle, const char *subsystem, const char *name, GNUNET_STATISTICS_Iterator proc, void *proc_cls) { struct GNUNET_STATISTICS_WatchEntry *w; unsigned int i; if (NULL == handle) return GNUNET_SYSERR; for (i=0;iwatches_size;i++) { w = handle->watches[i]; if (NULL == w) continue; if ( (w->proc == proc) && (w->proc_cls == proc_cls) && (0 == strcmp (w->name, name)) && (0 == strcmp (w->subsystem, subsystem)) ) { GNUNET_free (w->name); GNUNET_free (w->subsystem); GNUNET_free (w); handle->watches[i] = NULL; return GNUNET_OK; } } return GNUNET_SYSERR; } /** * Queue a request to change a statistic. * * @param h statistics handle * @param name name of the value * @param make_persistent should the value be kept across restarts? * @param value new value or change * @param type type of the action (ACTION_SET or ACTION_UPDATE) */ static void add_setter_action (struct GNUNET_STATISTICS_Handle *h, const char *name, int make_persistent, uint64_t value, enum ActionType type) { struct GNUNET_STATISTICS_GetHandle *ai; size_t slen; size_t nlen; size_t nsize; int64_t delta; GNUNET_assert (NULL != h); GNUNET_assert (NULL != name); slen = strlen (h->subsystem) + 1; nlen = strlen (name) + 1; nsize = sizeof (struct GNUNET_STATISTICS_SetMessage) + slen + nlen; if (nsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); return; } for (ai = h->action_head; NULL != ai; ai = ai->next) { if (! ( (0 == strcmp (ai->subsystem, h->subsystem)) && (0 == strcmp (ai->name, name)) && ( (ACTION_UPDATE == ai->type) || (ACTION_SET == ai->type) ) ) ) continue; if (ACTION_SET == ai->type) { if (ACTION_UPDATE == type) { delta = (int64_t) value; if (delta > 0) { /* update old set by new delta */ ai->value += delta; } else { /* update old set by new delta, but never go negative */ if (ai->value < -delta) ai->value = 0; else ai->value += delta; } } else { /* new set overrides old set */ ai->value = value; } } else { if (ACTION_UPDATE == type) { /* make delta cummulative */ delta = (int64_t) value; ai->value += delta; } else { /* drop old 'update', use new 'set' instead */ ai->value = value; ai->type = type; } } ai->timeout = GNUNET_TIME_relative_to_absolute (SET_TRANSMIT_TIMEOUT); ai->make_persistent = make_persistent; return; } /* no existing entry matches, create a fresh one */ ai = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_GetHandle)); ai->sh = h; ai->subsystem = GNUNET_strdup (h->subsystem); ai->name = GNUNET_strdup (name); ai->timeout = GNUNET_TIME_relative_to_absolute (SET_TRANSMIT_TIMEOUT); ai->make_persistent = make_persistent; ai->msize = nsize; ai->value = value; ai->type = type; GNUNET_CONTAINER_DLL_insert_tail (h->action_head, h->action_tail, ai); schedule_action (h); } /** * Set statistic value for the peer. Will always use our * subsystem (the argument used when "handle" was created). * * @param handle identification of the statistics service * @param name name of the statistic value * @param value new value to set * @param make_persistent should the value be kept across restarts? */ void GNUNET_STATISTICS_set (struct GNUNET_STATISTICS_Handle *handle, const char *name, uint64_t value, int make_persistent) { if (NULL == handle) return; GNUNET_assert (GNUNET_NO == handle->do_destroy); add_setter_action (handle, name, make_persistent, value, ACTION_SET); } /** * Set statistic value for the peer. Will always use our * subsystem (the argument used when "handle" was created). * * @param handle identification of the statistics service * @param name name of the statistic value * @param delta change in value (added to existing value) * @param make_persistent should the value be kept across restarts? */ void GNUNET_STATISTICS_update (struct GNUNET_STATISTICS_Handle *handle, const char *name, int64_t delta, int make_persistent) { if (NULL == handle) return; if (0 == delta) return; GNUNET_assert (GNUNET_NO == handle->do_destroy); add_setter_action (handle, name, make_persistent, (uint64_t) delta, ACTION_UPDATE); } /* end of statistics_api.c */ gnunet-0.9.3/src/statistics/gnunet-statistics.c0000644000175000017500000001505411761753145016600 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file statistics/gnunet-statistics.c * @brief tool to obtain statistics * @author Christian Grothoff * @author Igor Wronsky */ #include "platform.h" #include "gnunet_getopt_lib.h" #include "gnunet_program_lib.h" #include "gnunet_util_lib.h" #include "gnunet_statistics_service.h" #include "statistics.h" #define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) /** * Final status code. */ static int ret; /** * Set to subsystem that we're going to get stats for (or NULL for all). */ static char *subsystem; /** * Set to the specific stat value that we are after (or NULL for all). */ static char *name; /** * Make the value that is being set persistent. */ static int persistent; /** * Watch value continuously */ static int watch; /** * Quiet mode */ static int quiet; /** * Callback function to process statistic values. * * @param cls closure * @param subsystem name of subsystem that created the statistic * @param name the name of the datum * @param value the current value * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration */ static int printer (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent) { struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get(); char * now_str; if (quiet == GNUNET_NO) { if (GNUNET_YES == watch) { now_str = GNUNET_STRINGS_absolute_time_to_string(now); FPRINTF (stdout, "%24s %s%12s %50s: %16llu \n", now_str, is_persistent ? "!" : " ", subsystem, _(name), (unsigned long long) value); GNUNET_free (now_str); } else { FPRINTF (stdout, "%s%12s %50s: %16llu \n", is_persistent ? "!" : " ", subsystem, _(name), (unsigned long long) value); } } else FPRINTF (stdout, "%llu\n", (unsigned long long) value); return GNUNET_OK; } /** * Function called last by the statistics code. * * @param cls closure * @param success GNUNET_OK if statistics were * successfully obtained, GNUNET_SYSERR if not. */ static void cleanup (void *cls, int success) { struct GNUNET_STATISTICS_Handle *h = cls; if (success != GNUNET_OK) { FPRINTF (stderr, "%s", _("Failed to obtain statistics.\n")); ret = 1; } if (NULL != h) { GNUNET_STATISTICS_destroy (h, GNUNET_NO); h = NULL; } } static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_STATISTICS_Handle *h = cls; GNUNET_STATISTICS_watch_cancel (h, subsystem, name, &printer, h); if (NULL != h) { GNUNET_STATISTICS_destroy (h, GNUNET_NO); h = NULL; } } /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param cfg configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_STATISTICS_Handle *h; unsigned long long val; if (args[0] != NULL) { if ((1 != SSCANF (args[0], "%llu", &val)) || (subsystem == NULL) || (name == NULL)) { FPRINTF (stderr, _("Invalid argument `%s'\n"), args[0]); ret = 1; return; } h = GNUNET_STATISTICS_create (subsystem, cfg); if (NULL == h) { ret = 1; return; } GNUNET_STATISTICS_set (h, name, (uint64_t) val, persistent); GNUNET_STATISTICS_destroy (h, GNUNET_YES); h = NULL; return; } h = GNUNET_STATISTICS_create ("gnunet-statistics", cfg); if (NULL == h) { ret = 1; return; } if (GNUNET_NO == watch) { if (NULL == GNUNET_STATISTICS_get (h, subsystem, name, GET_TIMEOUT, &cleanup, &printer, h)) cleanup (h, GNUNET_SYSERR); } else { if ((NULL == subsystem) || (NULL == name)) { printf (_("No subsystem or name given\n")); if (h != NULL) GNUNET_STATISTICS_destroy (h, GNUNET_NO); ret = 1; return; } if (GNUNET_OK != GNUNET_STATISTICS_watch (h, subsystem, name, &printer, h)) { fprintf (stderr, _("Failed to initialize watch routine\n")); GNUNET_SCHEDULER_add_now (&shutdown_task, h); return; } GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, h); } } /** * The main function to obtain statistics in GNUnet. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { {'n', "name", "NAME", gettext_noop ("limit output to statistics for the given NAME"), 1, &GNUNET_GETOPT_set_string, &name}, {'p', "persistent", NULL, gettext_noop ("make the value being set persistent"), 0, &GNUNET_GETOPT_set_one, &persistent}, {'s', "subsystem", "SUBSYSTEM", gettext_noop ("limit output to the given SUBSYSTEM"), 1, &GNUNET_GETOPT_set_string, &subsystem}, {'q', "quiet", NULL, gettext_noop ("just print the statistics value"), 0, &GNUNET_GETOPT_set_one, &quiet}, {'w', "watch", NULL, gettext_noop ("watch value continously"), 0, &GNUNET_GETOPT_set_one, &watch}, GNUNET_GETOPT_OPTION_END }; return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-statistics [options [value]]", gettext_noop ("Print statistics about GNUnet operations."), options, &run, NULL)) ? ret : 1; } /* end of gnunet-statistics.c */ gnunet-0.9.3/src/statistics/test_gnunet_statistics.sh0000755000175000017500000001037111504756301020101 00000000000000#!/bin/sh rm -rf /tmp/test-gnunetd-statistics/ exe="./gnunet-statistics -c test_statistics_api_data.conf" out=`mktemp /tmp/test-gnunet-statistics-logXXXXXXXX` arm="gnunet-arm -c test_statistics_api_data.conf $DEBUG" #DEBUG="-L DEBUG" # ----------------------------------- echo -n "Preparing: Starting service..." $arm -s > /dev/null sleep 1 $arm -i statistics > /dev/null sleep 1 echo "DONE" # ---------------------------------------------------------------------------------- echo -n "TEST: Bad argument checking..." if $exe -x 2> /dev/null; then echo "FAIL: error running $exe" $arm -e exit 1 fi echo "PASS" # ---------------------------------------------------------------------------------- echo -n "TEST: Set value..." if ! $exe $DEBUG -n test -s subsystem 42 ; then echo "FAIL: error running $exe" $arm -e exit 1 fi echo "PASS" # ---------------------------------------------------------------------------------- echo -n "TEST: Set another value..." if ! $exe $DEBUG -n other -s osystem 43 ; then echo "FAIL: error running $exe" $arm -e exit 1 fi echo "PASS" # ---------------------------------------------------------------------------------- echo -n "TEST: viewing all stats..." if ! $exe $DEBUG > $out; then echo "FAIL: error running $exe" $arm -e exit 1 fi LINES=`cat $out | wc -l` if test $LINES -ne 2; then echo "FAIL: unexpected output" $arm -e exit 1 fi echo "PASS" # ---------------------------------------------------------------------------------- echo -n "TEST: viewing stats by name..." if ! $exe $DEBUG -n other > $out; then echo "FAIL: error running $exe" $arm -e exit 1 fi LINES=`cat $out | grep 43 | wc -l` if test $LINES -ne 1; then echo "FAIL: unexpected output" $arm -e exit 1 fi echo "PASS" # ---------------------------------------------------------------------------------- echo -n "TEST: viewing stats by subsystem..." if ! $exe $DEBUG -s subsystem > $out; then echo "FAIL: error running $exe" $arm -e exit 1 fi LINES=`cat $out | grep 42 | wc -l` if test $LINES -ne 1; then echo "FAIL: unexpected output" $arm -e exit 1 fi echo "PASS" # ---------------------------------------------------------------------------------- echo -n "TEST: Set persistent value..." if ! $exe $DEBUG -n lasting -s subsystem 40 -p; then echo "FAIL: error running $exe" $arm -e exit 1 fi if ! $exe $DEBUG > $out; then echo "FAIL: error running $exe" $arm -e exit 1 fi LINES=`cat $out | grep 40 | wc -l` if test $LINES -ne 1; then echo "FAIL: unexpected output" cat $out $arm -e exit 1 fi echo "PASS" # ----------------------------------- echo -n "Restarting service..." $arm -k statistics > /dev/null sleep 1 $arm -i statistics > /dev/null sleep 1 echo "DONE" # ---------------------------------------------------------------------------------- echo -n "TEST: checking persistence..." if ! $exe $DEBUG > $out; then echo "FAIL: error running $exe" $arm -e exit 1 fi LINES=`cat $out | grep 40 | wc -l` if test $LINES -ne 1; then echo "FAIL: unexpected output" cat $out $arm -e exit 1 fi echo "PASS" # ---------------------------------------------------------------------------------- echo -n "TEST: Removing persistence..." if ! $exe $DEBUG -n lasting -s subsystem 40; then echo "FAIL: error running $exe" $arm -e exit 1 fi if ! $exe $DEBUG > $out; then echo "FAIL: error running $exe" $arm -e exit 1 fi LINES=`cat $out | grep \! | wc -l` if test $LINES -ne 0; then echo "FAIL: unexpected output" cat $out $arm -e exit 1 fi echo "PASS" # ----------------------------------- echo -n "Restarting service..." $arm -k statistics > /dev/null sleep 1 $arm -i statistics > /dev/null sleep 1 echo "DONE" # ---------------------------------------------------------------------------------- echo -n "TEST: checking removed persistence..." if ! $exe $DEBUG > $out; then echo "FAIL: error running $exe" $arm -e exit 1 fi LINES=`cat $out | grep 40 | wc -l` if test $LINES -ne 0; then echo "FAIL: unexpected output" cat $out $arm -e exit 1 fi echo "PASS" # ----------------------------------- echo -n "Stopping service..." $arm -e > /dev/null sleep 1 echo "DONE" rm -f $out rm -rf /tmp/test-gnunetd-statistics/ gnunet-0.9.3/src/statistics/test_statistics_api_watch.c0000644000175000017500000001061211760502551020343 00000000000000/* This file is part of GNUnet. (C) 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file statistics/test_statistics_api_watch.c * @brief testcase for statistics_api.c watch functions */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_statistics_service.h" #define VERBOSE GNUNET_NO #define START_SERVICE GNUNET_YES static int ok; static struct GNUNET_STATISTICS_Handle *h; static struct GNUNET_STATISTICS_Handle *h2; static GNUNET_SCHEDULER_TaskIdentifier shutdown_task; static void force_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { fprintf (stderr, "Timeout, failed to receive notifications: %d\n", ok); GNUNET_STATISTICS_destroy (h, GNUNET_NO); GNUNET_STATISTICS_destroy (h2, GNUNET_NO); ok = 7; } static void normal_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_STATISTICS_destroy (h, GNUNET_NO); GNUNET_STATISTICS_destroy (h2, GNUNET_NO); } static int watch_1 (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent) { GNUNET_assert (value == 42); GNUNET_assert (0 == strcmp (name, "test-1")); ok &= ~1; if (0 == ok) { GNUNET_SCHEDULER_cancel (shutdown_task); GNUNET_SCHEDULER_add_now (&normal_shutdown, NULL); } return GNUNET_OK; } static int watch_2 (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent) { GNUNET_assert (value == 43); GNUNET_assert (0 == strcmp (name, "test-2")); ok &= ~2; if (0 == ok) { GNUNET_SCHEDULER_cancel (shutdown_task); GNUNET_SCHEDULER_add_now (&normal_shutdown, NULL); } return GNUNET_OK; } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { h = GNUNET_STATISTICS_create ("dummy", cfg); GNUNET_assert (GNUNET_OK == GNUNET_STATISTICS_watch (h, "test-statistics-api-watch", "test-1", &watch_1, NULL)); GNUNET_assert (GNUNET_OK == GNUNET_STATISTICS_watch (h, "test-statistics-api-watch", "test-2", &watch_2, NULL)); h2 = GNUNET_STATISTICS_create ("test-statistics-api-watch", cfg); GNUNET_STATISTICS_set (h2, "test-1", 42, GNUNET_NO); GNUNET_STATISTICS_set (h2, "test-2", 43, GNUNET_NO); shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &force_shutdown, NULL); } static int check () { char *const argv[] = { "test-statistics-api", "-c", "test_statistics_api_data.conf", NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; #if START_SERVICE struct GNUNET_OS_Process *proc; proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-statistics", "gnunet-service-statistics", #if VERBOSE "-L", "DEBUG", #endif "-c", "test_statistics_api_data.conf", NULL); #endif GNUNET_assert (NULL != proc); ok = 3; GNUNET_PROGRAM_run (3, argv, "test-statistics-api", "nohelp", options, &run, NULL); #if START_SERVICE if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); ok = 1; } GNUNET_OS_process_wait (proc); GNUNET_OS_process_destroy (proc); proc = NULL; #endif return ok; } int main (int argc, char *argv[]) { int ret; ret = check (); return ret; } /* end of test_statistics_api_watch.c */ gnunet-0.9.3/src/statistics/Makefile.in0000644000175000017500000010125311762223647015006 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-statistics$(EXEEXT) \ gnunet-service-statistics$(EXEEXT) check_PROGRAMS = test_statistics_api$(EXEEXT) \ test_statistics_api_loop$(EXEEXT) \ test_statistics_api_watch$(EXEEXT) \ test_statistics_api_watch_zero_value$(EXEEXT) subdir = src/statistics DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/statistics.conf.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = statistics.conf CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libgnunetstatistics_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am_libgnunetstatistics_la_OBJECTS = statistics_api.lo libgnunetstatistics_la_OBJECTS = $(am_libgnunetstatistics_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunetstatistics_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetstatistics_la_LDFLAGS) \ $(LDFLAGS) -o $@ PROGRAMS = $(bin_PROGRAMS) am_gnunet_service_statistics_OBJECTS = \ gnunet-service-statistics.$(OBJEXT) gnunet_service_statistics_OBJECTS = \ $(am_gnunet_service_statistics_OBJECTS) am_gnunet_statistics_OBJECTS = gnunet-statistics.$(OBJEXT) gnunet_statistics_OBJECTS = $(am_gnunet_statistics_OBJECTS) am_test_statistics_api_OBJECTS = test_statistics_api.$(OBJEXT) test_statistics_api_OBJECTS = $(am_test_statistics_api_OBJECTS) test_statistics_api_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_statistics_api_loop_OBJECTS = \ test_statistics_api_loop.$(OBJEXT) test_statistics_api_loop_OBJECTS = \ $(am_test_statistics_api_loop_OBJECTS) test_statistics_api_loop_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_statistics_api_watch_OBJECTS = \ test_statistics_api_watch.$(OBJEXT) test_statistics_api_watch_OBJECTS = \ $(am_test_statistics_api_watch_OBJECTS) test_statistics_api_watch_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_statistics_api_watch_zero_value_OBJECTS = \ test_statistics_api_watch_zero_value.$(OBJEXT) test_statistics_api_watch_zero_value_OBJECTS = \ $(am_test_statistics_api_watch_zero_value_OBJECTS) test_statistics_api_watch_zero_value_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunetstatistics_la_SOURCES) \ $(gnunet_service_statistics_SOURCES) \ $(gnunet_statistics_SOURCES) $(test_statistics_api_SOURCES) \ $(test_statistics_api_loop_SOURCES) \ $(test_statistics_api_watch_SOURCES) \ $(test_statistics_api_watch_zero_value_SOURCES) DIST_SOURCES = $(libgnunetstatistics_la_SOURCES) \ $(gnunet_service_statistics_SOURCES) \ $(gnunet_statistics_SOURCES) $(test_statistics_api_SOURCES) \ $(test_statistics_api_loop_SOURCES) \ $(test_statistics_api_watch_SOURCES) \ $(test_statistics_api_watch_zero_value_SOURCES) DATA = $(pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @USE_COVERAGE_TRUE@XLIB = -lgcov pkgcfgdir = $(pkgdatadir)/config.d/ pkgcfg_DATA = \ statistics.conf lib_LTLIBRARIES = libgnunetstatistics.la libgnunetstatistics_la_SOURCES = \ statistics_api.c statistics.h libgnunetstatistics_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) $(XLIB) libgnunetstatistics_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 1:1:1 gnunet_statistics_SOURCES = \ gnunet-statistics.c gnunet_statistics_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_statistics_DEPENDENCIES = \ libgnunetstatistics.la gnunet_service_statistics_SOURCES = \ gnunet-service-statistics.c gnunet_service_statistics_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_service_statistics_DEPENDENCIES = \ libgnunetstatistics.la @ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) $(check_SCRIPTS) test_statistics_api_SOURCES = \ test_statistics_api.c test_statistics_api_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la test_statistics_api_loop_SOURCES = \ test_statistics_api_loop.c test_statistics_api_loop_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la test_statistics_api_watch_SOURCES = \ test_statistics_api_watch.c test_statistics_api_watch_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la test_statistics_api_watch_zero_value_SOURCES = \ test_statistics_api_watch_zero_value.c test_statistics_api_watch_zero_value_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la check_SCRIPTS = \ test_gnunet_statistics.sh EXTRA_DIST = \ test_statistics_api_data.conf \ $(check_SCRIPTS) all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/statistics/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/statistics/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): statistics.conf: $(top_builddir)/config.status $(srcdir)/statistics.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunetstatistics.la: $(libgnunetstatistics_la_OBJECTS) $(libgnunetstatistics_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetstatistics_la_LINK) -rpath $(libdir) $(libgnunetstatistics_la_OBJECTS) $(libgnunetstatistics_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-service-statistics$(EXEEXT): $(gnunet_service_statistics_OBJECTS) $(gnunet_service_statistics_DEPENDENCIES) @rm -f gnunet-service-statistics$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_service_statistics_OBJECTS) $(gnunet_service_statistics_LDADD) $(LIBS) gnunet-statistics$(EXEEXT): $(gnunet_statistics_OBJECTS) $(gnunet_statistics_DEPENDENCIES) @rm -f gnunet-statistics$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_statistics_OBJECTS) $(gnunet_statistics_LDADD) $(LIBS) test_statistics_api$(EXEEXT): $(test_statistics_api_OBJECTS) $(test_statistics_api_DEPENDENCIES) @rm -f test_statistics_api$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_statistics_api_OBJECTS) $(test_statistics_api_LDADD) $(LIBS) test_statistics_api_loop$(EXEEXT): $(test_statistics_api_loop_OBJECTS) $(test_statistics_api_loop_DEPENDENCIES) @rm -f test_statistics_api_loop$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_statistics_api_loop_OBJECTS) $(test_statistics_api_loop_LDADD) $(LIBS) test_statistics_api_watch$(EXEEXT): $(test_statistics_api_watch_OBJECTS) $(test_statistics_api_watch_DEPENDENCIES) @rm -f test_statistics_api_watch$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_statistics_api_watch_OBJECTS) $(test_statistics_api_watch_LDADD) $(LIBS) test_statistics_api_watch_zero_value$(EXEEXT): $(test_statistics_api_watch_zero_value_OBJECTS) $(test_statistics_api_watch_zero_value_DEPENDENCIES) @rm -f test_statistics_api_watch_zero_value$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_statistics_api_watch_zero_value_OBJECTS) $(test_statistics_api_watch_zero_value_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-statistics.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-statistics.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/statistics_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_statistics_api.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_statistics_api_loop.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_statistics_api_watch.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_statistics_api_watch_zero_value.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgcfgDATA: $(pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(check_SCRIPTS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgcfgDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-binPROGRAMS install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-pkgcfgDATA install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/statistics/statistics.conf.in0000644000175000017500000000065011760502552016377 00000000000000[statistics] AUTOSTART = YES @JAVAPORT@PORT = 2088 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-statistics ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-statistics.sock UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES # DISABLE_SOCKET_FORWARDING = NO # USERNAME = # MAXBUF = # TIMEOUT = # DISABLEV6 = # BINDTO = # REJECT_FROM = # REJECT_FROM6 = # PREFIX = gnunet-0.9.3/src/fs/0000755000175000017500000000000011763406750011234 500000000000000gnunet-0.9.3/src/fs/test_fs_unindex.c0000644000175000017500000002311111760502551014510 00000000000000/* This file is part of GNUnet. (C) 2004, 2005, 2006, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/test_fs_unindex.c * @brief simple testcase for simple publish + unindex operation * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_arm_service.h" #include "gnunet_fs_service.h" #define VERBOSE GNUNET_NO #define START_ARM GNUNET_YES /** * File-size we use for testing. */ #define FILESIZE (1024 * 1024 * 2) /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) /** * How long should our test-content live? */ #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static struct PeerContext p1; static struct GNUNET_TIME_Absolute start; static struct GNUNET_FS_Handle *fs; static struct GNUNET_FS_UnindexContext *unindex; static struct GNUNET_FS_PublishContext *publish; static char *fn; static void abort_publish_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_FS_publish_stop (publish); publish = NULL; } static void abort_unindex_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_FS_unindex_stop (unindex); unindex = NULL; GNUNET_DISK_directory_remove (fn); GNUNET_free (fn); fn = NULL; } static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) { switch (event->status) { case GNUNET_FS_STATUS_PUBLISH_PROGRESS: #if VERBOSE printf ("Publish is progressing (%llu/%llu at level %u off %llu)...\n", (unsigned long long) event->value.publish.completed, (unsigned long long) event->value.publish.size, event->value.publish.specifics.progress.depth, (unsigned long long) event->value.publish.specifics. progress.offset); #endif break; case GNUNET_FS_STATUS_PUBLISH_COMPLETED: printf ("Publishing complete, %llu kbps.\n", (unsigned long long) (FILESIZE * 1000 / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value) / 1024)); start = GNUNET_TIME_absolute_get (); unindex = GNUNET_FS_unindex_start (fs, fn, "unindex"); GNUNET_assert (unindex != NULL); break; case GNUNET_FS_STATUS_UNINDEX_COMPLETED: printf ("Unindex complete, %llu kbps.\n", (unsigned long long) (FILESIZE * 1000 / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value) / 1024)); GNUNET_SCHEDULER_add_continuation (&abort_unindex_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_UNINDEX_PROGRESS: GNUNET_assert (unindex == event->value.unindex.uc); #if VERBOSE printf ("Unindex is progressing (%llu/%llu at level %u off %llu)...\n", (unsigned long long) event->value.unindex.completed, (unsigned long long) event->value.unindex.size, event->value.unindex.specifics.progress.depth, (unsigned long long) event->value.unindex.specifics. progress.offset); #endif break; case GNUNET_FS_STATUS_PUBLISH_ERROR: FPRINTF (stderr, "Error publishing file: %s\n", event->value.publish.specifics.error.message); GNUNET_break (0); GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_UNINDEX_ERROR: FPRINTF (stderr, "Error unindexing file: %s\n", event->value.unindex.specifics.error.message); GNUNET_SCHEDULER_add_continuation (&abort_unindex_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_PUBLISH_START: GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); GNUNET_assert (NULL == event->value.publish.pctx); GNUNET_assert (FILESIZE == event->value.publish.size); GNUNET_assert (0 == event->value.publish.completed); GNUNET_assert (1 == event->value.publish.anonymity); break; case GNUNET_FS_STATUS_PUBLISH_STOPPED: GNUNET_assert (publish == event->value.publish.pc); GNUNET_assert (FILESIZE == event->value.publish.size); GNUNET_assert (1 == event->value.publish.anonymity); GNUNET_FS_stop (fs); fs = NULL; break; case GNUNET_FS_STATUS_UNINDEX_START: GNUNET_assert (unindex == NULL); GNUNET_assert (0 == strcmp ("unindex", event->value.unindex.cctx)); GNUNET_assert (0 == strcmp (fn, event->value.unindex.filename)); GNUNET_assert (FILESIZE == event->value.unindex.size); GNUNET_assert (0 == event->value.unindex.completed); break; case GNUNET_FS_STATUS_UNINDEX_STOPPED: GNUNET_assert (unindex == event->value.unindex.uc); GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; default: printf ("Unexpected event: %d\n", event->status); break; } return NULL; } static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE "-L", "DEBUG", #endif "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); } static void stop_arm (struct PeerContext *p) { #if START_ARM if (NULL != p->arm_proc) { if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; } #endif GNUNET_CONFIGURATION_destroy (p->cfg); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { const char *keywords[] = { "down_foo", "down_bar", }; char *buf; struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_FS_Uri *kuri; struct GNUNET_FS_FileInformation *fi; size_t i; struct GNUNET_FS_BlockOptions bo; setup_peer (&p1, "test_fs_unindex_data.conf"); fn = GNUNET_DISK_mktemp ("gnunet-unindex-test-dst"); fs = GNUNET_FS_start (cfg, "test-fs-unindex", &progress_cb, NULL, GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); GNUNET_assert (NULL != fs); buf = GNUNET_malloc (FILESIZE); for (i = 0; i < FILESIZE; i++) buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); GNUNET_assert (FILESIZE == GNUNET_DISK_fn_write (fn, buf, FILESIZE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)); GNUNET_free (buf); meta = GNUNET_CONTAINER_meta_data_create (); kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); bo.content_priority = 42; bo.anonymity_level = 1; bo.replication_level = 0; bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); fi = GNUNET_FS_file_information_create_from_file (fs, "publish-context", fn, kuri, meta, GNUNET_YES, &bo); GNUNET_FS_uri_destroy (kuri); GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_assert (NULL != fi); start = GNUNET_TIME_absolute_get (); publish = GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, GNUNET_FS_PUBLISH_OPTION_NONE); GNUNET_assert (publish != NULL); } int main (int argc, char *argv[]) { char *const argvx[] = { "test-fs-unindex", "-c", "test_fs_unindex_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("test_fs_unindex", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "test-fs-unindex", "nohelp", options, &run, NULL); stop_arm (&p1); GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-unindex/"); if (NULL != fn) { GNUNET_DISK_directory_remove (fn); GNUNET_free (fn); } return 0; } /* end of test_fs_unindex.c */ gnunet-0.9.3/src/fs/test_gnunet_fs_rec.py.in0000644000175000017500000001124011760502552016003 00000000000000#!@PYTHON@ # This file is part of GNUnet. # (C) 2010 Christian Grothoff (and other contributing authors) # # GNUnet is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2, or (at your # option) any later version. # # GNUnet is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNUnet; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # Testcase for file-sharing command-line tools (recursive publishing & download) import sys import os import subprocess import re import shutil srcdir = "../.." gnunet_pyexpect_dir = os.path.join (srcdir, "contrib") if gnunet_pyexpect_dir not in sys.path: sys.path.append (gnunet_pyexpect_dir) from gnunet_pyexpect import pexpect if os.name == 'posix': download = 'gnunet-download' gnunetarm = 'gnunet-arm' publish = 'gnunet-publish' unindex = 'gnunet-unindex' search = 'gnunet-search' directory = 'gnunet-directory' elif os.name == 'nt': download = 'gnunet-download.exe' gnunetarm = 'gnunet-arm.exe' publish = 'gnunet-publish.exe' unindex = 'gnunet-unindex.exe' search = 'gnunet-search.exe' directory = 'gnunet-directory.exe' if os.name == "nt": shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-rec"), True) else: shutil.rmtree ("/tmp/gnunet-test-fs-py-rec", True) arm = subprocess.Popen ([gnunetarm, '-sq', '-c', 'test_gnunet_fs_rec_data.conf']) arm.communicate () # pray that `tar' is in PATH os.system ('tar xfz test_gnunet_fs_rec_data.tgz') # first, basic publish-search-download run try: pub = pexpect () pub.spawn (None, [publish, '-c', 'test_gnunet_fs_rec_data.conf', '-d', '-k', 'testdir', 'dir/'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # Can't say much for publishing, except that the last one is the toplevel directory pub.expect ("stdout", re.compile (r"Publishing `.+' done\.\r?\n")) pub.expect ("stdout", re.compile (r"URI is `gnunet://fs/chk/[A-Z0-9]{103}\.[A-Z0-9]{103}\.\d+'\.\r?\n")) pub.expect ("stdout", re.compile (r"Publishing `.+' done\.\r?\n")) pub.expect ("stdout", re.compile (r"URI is `gnunet://fs/chk/[A-Z0-9]{103}\.[A-Z0-9]{103}\.\d+'\.\r?\n")) pub.expect ("stdout", re.compile (r"Publishing `.+' done\.\r?\n")) pub.expect ("stdout", re.compile (r"URI is `gnunet://fs/chk/[A-Z0-9]{103}\.[A-Z0-9]{103}\.\d+'\.\r?\n")) pub.expect ("stdout", re.compile (r"Publishing `.+' done\.\r?\n")) pub.expect ("stdout", re.compile (r"URI is `gnunet://fs/chk/[A-Z0-9]{103}\.[A-Z0-9]{103}\.\d+'\.\r?\n")) pub.expect ("stdout", re.compile (r"Publishing `.+' done\.\r?\n")) pub.expect ("stdout", re.compile (r"URI is `gnunet://fs/chk/[A-Z0-9]{103}\.[A-Z0-9]{103}\.\d+'\.\r?\n")) pub.expect ("stdout", re.compile (r"Publishing `.+' done\.\r?\n")) pub.expect ("stdout", re.compile (r"URI is `gnunet://fs/chk/[A-Z0-9]{103}\.[A-Z0-9]{103}\.\d+'\.\r?\n")) pub.expect ("stdout", re.compile (r"Publishing `.+[\\/]dir[\\/]' done\.\r?\n")) m = pub.expect ("stdout", re.compile (r".+\r?\n")) if not m: sys.exit (3) output = m.string url = output[output.find ("`")+1:output.find("'")] down = pexpect () down.spawn (None, [download, '-c', 'test_gnunet_fs_rec_data.conf', '-R', '-o', 'rdir.gnd', url], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) down.expect ("stdout", re.compile (r"Downloading `rdir.gnd' done (.*).\r?\n")) d = pexpect () d.spawn (None, [directory, '-c', 'test_gnunet_fs_rec_data.conf', 'rdir/a.gnd'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) d.expect ("stdout", re.compile (r"Directory `a/' meta data:\r?\n")) d.expect ("stdout", re.compile (r"Directory `a/' contents:\r?\n")) d.expect ("stdout", re.compile (r"COPYING (.*)\r?\n")) d.expect ("stdout", re.compile (r"INSTALL (.*)\r?\n")) os.remove ("rdir/b.gnd") os.remove ("rdir/a.gnd") if 0 != os.system ("diff -r dir rdir"): raise Exception ("Unexpected difference between source directory and downloaded result") finally: arm = subprocess.Popen ([gnunetarm, '-eq', '-c', 'test_gnunet_fs_rec_data.conf']) arm.communicate () if os.name == "nt": shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-rec"), True) else: shutil.rmtree ("/tmp/gnunet-test-fs-py-rec", True) shutil.rmtree ("dir", True) shutil.rmtree ("rdir", True) shutil.rmtree ("rdir.gnd", True) gnunet-0.9.3/src/fs/gnunet-service-fs_cp.h0000644000175000017500000002776611760502551015366 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-service-fs_cp.h * @brief API to handle 'connected peers' * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_FS_CP_H #define GNUNET_SERVICE_FS_CP_H #include "fs.h" #include "gnunet-service-fs.h" /** * Maximum number of outgoing messages we queue per peer. * * Performance measurements for 2 peer setup for 50 MB file * (with MAX_DATASTORE_QUEUE = 1 and RETRY_PROBABILITY_INV = 1): * * 2: 1700 kb/s, 1372 kb/s * 8: 2117 kb/s, 1284 kb/s, 1112 kb/s * 16: 3500 kb/s, 3200 kb/s, 3388 kb/s * 32: 3441 kb/s, 3163 kb/s, 3277 kb/s * 128: 1700 kb/s; 2010 kb/s, 3383 kb/s, 1156 kb/s * * Conclusion: 16 seems to be a pretty good value (stable * and high performance, no excessive memory use). */ #define MAX_QUEUE_PER_PEER 16 /** * Length of the P2P success tracker. Note that having a very long * list can also hurt performance. */ #define P2P_SUCCESS_LIST_SIZE 8 /** * Length of the CS-2-P success tracker. Note that * having a very long list can also hurt performance. */ #define CS2P_SUCCESS_LIST_SIZE 8 /** * Performance data kept for a peer. */ struct GSF_PeerPerformanceData { /** * Transport performance data. */ struct GNUNET_ATS_Information *atsi; /** * List of the last clients for which this peer successfully * answered a query. */ struct GSF_LocalClient *last_client_replies[CS2P_SUCCESS_LIST_SIZE]; /** * List of the last PIDs for which * this peer successfully answered a query; * We use 0 to indicate no successful reply. */ GNUNET_PEER_Id last_p2p_replies[P2P_SUCCESS_LIST_SIZE]; /** * Average delay between sending the peer a request and * getting a reply (only calculated over the requests for * which we actually got a reply). Calculated * as a moving average: new_delay = ((n-1)*last_delay+curr_delay) / n */ struct GNUNET_TIME_Relative avg_reply_delay; /** * If we get content we already have from this peer, for how * long do we block him? Adjusted based on the fraction of * redundant data we receive, between 1s and 1h. */ struct GNUNET_TIME_Relative migration_delay; /** * Point in time until which this peer does not want us to migrate content * to it. */ struct GNUNET_TIME_Absolute migration_blocked_until; /** * Transmission times for the last MAX_QUEUE_PER_PEER * requests for this peer. Used as a ring buffer, current * offset is stored in 'last_request_times_off'. If the * oldest entry is more recent than the 'avg_delay', we should * not send any more requests right now. */ struct GNUNET_TIME_Absolute last_request_times[MAX_QUEUE_PER_PEER]; /** * How long does it typically take for us to transmit a message * to this peer? (delay between the request being issued and * the callback being invoked). */ struct GNUNET_LOAD_Value *transmission_delay; /** * Average priority of successful replies. Calculated * as a moving average: new_avg = ((n-1)*last_avg+curr_prio) / n */ double avg_priority; /** * The peer's identity. */ GNUNET_PEER_Id pid; /** * Trust rating for this peer */ uint32_t trust; /** * Number of pending queries (replies are not counted) */ unsigned int pending_queries; /** * Number of pending replies (queries are not counted) */ unsigned int pending_replies; }; /** * Signature of function called on a connected peer. * * @param cls closure * @param peer identity of the peer * @param cp handle to the connected peer record * @param perf peer performance data */ typedef void (*GSF_ConnectedPeerIterator) (void *cls, const struct GNUNET_PeerIdentity * peer, struct GSF_ConnectedPeer * cp, const struct GSF_PeerPerformanceData * ppd); /** * Function called to get a message for transmission. * * @param cls closure * @param buf_size number of bytes available in buf * @param buf where to copy the message, NULL on error (peer disconnect) * @return number of bytes copied to 'buf', can be 0 (without indicating an error) */ typedef size_t (*GSF_GetMessageCallback) (void *cls, size_t buf_size, void *buf); /** * Signature of function called on a reservation success or failure. * * @param cls closure * @param cp handle to the connected peer record * @param success GNUNET_YES on success, GNUNET_NO on failure */ typedef void (*GSF_PeerReserveCallback) (void *cls, struct GSF_ConnectedPeer * cp, int success); /** * Handle to cancel a transmission request. */ struct GSF_PeerTransmitHandle; /** * A peer connected to us. Setup the connected peer * records. * * @param peer identity of peer that connected * @param atsi performance data for the connection * @param atsi_count number of records in 'atsi' * @return handle to connected peer entry */ struct GSF_ConnectedPeer * GSF_peer_connect_handler_ (const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count); /** * Get a handle for a connected peer. * * @param peer peer's identity * @return NULL if this peer is not currently connected */ struct GSF_ConnectedPeer * GSF_peer_get_ (const struct GNUNET_PeerIdentity *peer); /** * Transmit a message to the given peer as soon as possible. * If the peer disconnects before the transmission can happen, * the callback is invoked with a 'NULL' buffer. * * @param cp target peer * @param is_query is this a query (GNUNET_YES) or content (GNUNET_NO) * @param priority how important is this request? * @param timeout when does this request timeout (call gmc with error) * @param size number of bytes we would like to send to the peer * @param gmc function to call to get the message * @param gmc_cls closure for gmc * @return handle to cancel request */ struct GSF_PeerTransmitHandle * GSF_peer_transmit_ (struct GSF_ConnectedPeer *cp, int is_query, uint32_t priority, struct GNUNET_TIME_Relative timeout, size_t size, GSF_GetMessageCallback gmc, void *gmc_cls); /** * Cancel an earlier request for transmission. * * @param pth request to cancel */ void GSF_peer_transmit_cancel_ (struct GSF_PeerTransmitHandle *pth); /** * Report on receiving a reply; update the performance record of the given peer. * * @param cp responding peer (will be updated) * @param request_time time at which the original query was transmitted * @param request_priority priority of the original request */ void GSF_peer_update_performance_ (struct GSF_ConnectedPeer *cp, struct GNUNET_TIME_Absolute request_time, uint32_t request_priority); /** * Report on receiving a reply in response to an initiating client. * Remember that this peer is good for this client. * * @param cp responding peer (will be updated) * @param initiator_client local client on responsible for query */ void GSF_peer_update_responder_client_ (struct GSF_ConnectedPeer *cp, struct GSF_LocalClient *initiator_client); /** * Report on receiving a reply in response to an initiating peer. * Remember that this peer is good for this initiating peer. * * @param cp responding peer (will be updated) * @param initiator_peer other peer responsible for query */ void GSF_peer_update_responder_peer_ (struct GSF_ConnectedPeer *cp, const struct GSF_ConnectedPeer *initiator_peer); /** * Handle P2P "MIGRATION_STOP" message. * * @param cls closure, always NULL * @param other the other peer involved (sender or receiver, NULL * for loopback messages where we are both sender and receiver) * @param message the actual message * @param atsi performance information * @param atsi_count number of records in 'atsi' * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ int GSF_handle_p2p_migration_stop_ (void *cls, const struct GNUNET_PeerIdentity *other, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count); /** * Handle P2P "QUERY" message. Only responsible for creating the * request entry itself and setting up reply callback and cancellation * on peer disconnect. Does NOT execute the actual request strategy * (planning) or local database operations. * * @param other the other peer involved (sender or receiver, NULL * for loopback messages where we are both sender and receiver) * @param message the actual message * @return pending request handle, NULL on error */ struct GSF_PendingRequest * GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other, const struct GNUNET_MessageHeader *message); /** * Return the performance data record for the given peer * * @param cp peer to query * @return performance data record for the peer */ struct GSF_PeerPerformanceData * GSF_get_peer_performance_data_ (struct GSF_ConnectedPeer *cp); /** * Ask a peer to stop migrating data to us until the given point * in time. * * @param cp peer to ask * @param block_time until when to block */ void GSF_block_peer_migration_ (struct GSF_ConnectedPeer *cp, struct GNUNET_TIME_Absolute block_time); /** * A peer disconnected from us. Tear down the connected peer * record. * * @param cls unused * @param peer identity of peer that connected */ void GSF_peer_disconnect_handler_ (void *cls, const struct GNUNET_PeerIdentity *peer); /** * Notification that a local client disconnected. Clean up all of our * references to the given handle. * * @param lc handle to the local client (henceforth invalid) */ void GSF_handle_local_client_disconnect_ (const struct GSF_LocalClient *lc); /** * Notify core about a preference we have for the given peer * (to allocate more resources towards it). The change will * be communicated the next time we reserve bandwidth with * core (not instantly). * * @param cp peer to reserve bandwidth from * @param pref preference change */ void GSF_connected_peer_change_preference_ (struct GSF_ConnectedPeer *cp, uint64_t pref); /** * Obtain the identity of a connected peer. * * @param cp peer to reserve bandwidth from * @param id identity to set (written to) */ void GSF_connected_peer_get_identity_ (const struct GSF_ConnectedPeer *cp, struct GNUNET_PeerIdentity *id); /** * Iterate over all connected peers. * * @param it function to call for each peer * @param it_cls closure for it */ void GSF_iterate_connected_peers_ (GSF_ConnectedPeerIterator it, void *it_cls); /** * Initialize peer management subsystem. */ void GSF_connected_peer_init_ (void); /** * Shutdown peer management subsystem. */ void GSF_connected_peer_done_ (void); #endif /* end of gnunet-service-fs_cp.h */ gnunet-0.9.3/src/fs/gnunet-service-fs_indexing.h0000644000175000017500000000734511760502551016560 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-service-fs_indexing.h * @brief indexing for the file-sharing service * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_FS_INDEXING_H #define GNUNET_SERVICE_FS_INDEXING_H #include "gnunet_block_lib.h" #include "gnunet_core_service.h" #include "gnunet_datastore_service.h" #include "gnunet_peer_lib.h" #include "gnunet_protocols.h" #include "gnunet_signatures.h" #include "gnunet_util_lib.h" /** * We've received an on-demand encoded block from the datastore. * Attempt to do on-demand encoding and (if successful), call the * continuation with the resulting block. On error, clean up and ask * the datastore for more results. * * @param key key for the content * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param expiration expiration time for the content * @param uid unique identifier for the datum; * maybe 0 if no unique identifier is available * @param cont function to call with the actual block (at most once, on success) * @param cont_cls closure for cont * @return GNUNET_OK on success */ int GNUNET_FS_handle_on_demand_block (const GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid, GNUNET_DATASTORE_DatumProcessor cont, void *cont_cls); /** * Handle INDEX_START-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ void GNUNET_FS_handle_index_start (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message); /** * Handle INDEX_LIST_GET-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ void GNUNET_FS_handle_index_list_get (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message); /** * Handle UNINDEX-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ void GNUNET_FS_handle_unindex (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message); /** * Initialize the indexing submodule. * * @param c configuration to use * @param d datastore to use * @return GNUNET_OK on success */ int GNUNET_FS_indexing_init (const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_DATASTORE_Handle *d); /** * Shutdown the module. */ void GNUNET_FS_indexing_done (void); #endif gnunet-0.9.3/src/fs/test_fs_getopt.c0000644000175000017500000000242111760502551014341 00000000000000/* This file is part of GNUnet (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/test_fs_getopt.c * @brief test for fs_getopt.c * @author Christian Grothoff */ #include "platform.h" #include "gnunet_fs_service.h" int main (int argc, char *argv[]) { GNUNET_log_setup ("test_fs_directory", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); FPRINTF (stderr, "%s", "WARNING: testcase not yet written.\n"); return 0; /* testcase passed */ } gnunet-0.9.3/src/fs/test_fs_list_indexed_data.conf0000644000175000017500000000027211615567501017215 00000000000000@INLINE@ test_fs_defaults.conf [PATHS] SERVICEHOME = /tmp/gnunet-test-fs-list-indexed/ DEFAULTCONFIG = test_fs_list_indexed_data.conf [transport] PLUGINS = [fs] ACTIVEMIGRATION = NO gnunet-0.9.3/src/fs/test_fs_search.c0000644000175000017500000002031711760502551014310 00000000000000/* This file is part of GNUnet. (C) 2004, 2005, 2006, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/test_fs_search.c * @brief simple testcase for simple publish + search operation * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_arm_service.h" #include "gnunet_fs_service.h" #define VERBOSE GNUNET_NO #define START_ARM GNUNET_YES /** * File-size we use for testing. */ #define FILESIZE 1024 /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) /** * How long should our test-content live? */ #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_PeerIdentity id; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static struct PeerContext p1; static struct GNUNET_TIME_Absolute start; static struct GNUNET_FS_Handle *fs; static struct GNUNET_FS_SearchContext *search; static struct GNUNET_FS_PublishContext *publish; static void abort_publish_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_FS_publish_stop (publish); publish = NULL; } static void abort_search_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (search != NULL) GNUNET_FS_search_stop (search); search = NULL; } static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) { const char *keywords[] = { "down_foo" }; struct GNUNET_FS_Uri *kuri; switch (event->status) { case GNUNET_FS_STATUS_PUBLISH_PROGRESS: #if VERBOSE printf ("Publish is progressing (%llu/%llu at level %u off %llu)...\n", (unsigned long long) event->value.publish.completed, (unsigned long long) event->value.publish.size, event->value.publish.specifics.progress.depth, (unsigned long long) event->value.publish.specifics. progress.offset); #endif break; case GNUNET_FS_STATUS_PUBLISH_COMPLETED: kuri = GNUNET_FS_uri_ksk_create_from_args (1, keywords); start = GNUNET_TIME_absolute_get (); search = GNUNET_FS_search_start (fs, kuri, 1, GNUNET_FS_SEARCH_OPTION_NONE, "search"); GNUNET_FS_uri_destroy (kuri); GNUNET_assert (search != NULL); break; case GNUNET_FS_STATUS_SEARCH_RESULT: #if VERBOSE printf ("Search complete.\n"); #endif GNUNET_SCHEDULER_add_continuation (&abort_search_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_PUBLISH_ERROR: FPRINTF (stderr, "Error publishing file: %s\n", event->value.publish.specifics.error.message); GNUNET_break (0); GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_SEARCH_ERROR: FPRINTF (stderr, "Error searching file: %s\n", event->value.search.specifics.error.message); GNUNET_SCHEDULER_add_continuation (&abort_search_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_PUBLISH_START: GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); GNUNET_assert (NULL == event->value.publish.pctx); GNUNET_assert (FILESIZE == event->value.publish.size); GNUNET_assert (0 == event->value.publish.completed); GNUNET_assert (1 == event->value.publish.anonymity); break; case GNUNET_FS_STATUS_PUBLISH_STOPPED: GNUNET_assert (publish == event->value.publish.pc); GNUNET_assert (FILESIZE == event->value.publish.size); GNUNET_assert (1 == event->value.publish.anonymity); GNUNET_FS_stop (fs); fs = NULL; break; case GNUNET_FS_STATUS_SEARCH_START: GNUNET_assert (search == NULL); GNUNET_assert (0 == strcmp ("search", event->value.search.cctx)); GNUNET_assert (1 == event->value.search.anonymity); break; case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED: break; case GNUNET_FS_STATUS_SEARCH_STOPPED: GNUNET_assert (search == event->value.search.sc); GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; default: FPRINTF (stderr, "Unexpected event: %d\n", event->status); break; } return NULL; } static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); } static void stop_arm (struct PeerContext *p) { #if START_ARM if (NULL != p->arm_proc) { if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; } #endif GNUNET_CONFIGURATION_destroy (p->cfg); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { const char *keywords[] = { "down_foo", "down_bar" }; char *buf; struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_FS_Uri *kuri; struct GNUNET_FS_BlockOptions bo; struct GNUNET_FS_FileInformation *fi; size_t i; setup_peer (&p1, "test_fs_search_data.conf"); fs = GNUNET_FS_start (cfg, "test-fs-search", &progress_cb, NULL, GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); GNUNET_assert (NULL != fs); buf = GNUNET_malloc (FILESIZE); for (i = 0; i < FILESIZE; i++) buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); meta = GNUNET_CONTAINER_meta_data_create (); kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); bo.content_priority = 42; bo.anonymity_level = 1; bo.replication_level = 0; bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); fi = GNUNET_FS_file_information_create_from_data (fs, "publish-context", FILESIZE, buf, kuri, meta, GNUNET_NO, &bo); GNUNET_FS_uri_destroy (kuri); GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_assert (NULL != fi); start = GNUNET_TIME_absolute_get (); publish = GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, GNUNET_FS_PUBLISH_OPTION_NONE); GNUNET_assert (publish != NULL); } int main (int argc, char *argv[]) { char *const argvx[] = { "test-fs-search", "-c", "test_fs_search_data.conf", NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("test_fs_search", "WARNING", NULL); GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "test-fs-search", "nohelp", options, &run, NULL); stop_arm (&p1); GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-search/"); return 0; } /* end of test_fs_search.c */ gnunet-0.9.3/src/fs/gnunet-download-manager.scm0000755000175000017500000003203211704661367016402 00000000000000#!/bin/sh exec guile -e main -s "$0" "$@" !# ;;; gnunet-download-manager -- Manage GNUnet downloads. ;;; Copyright (C) 2004 Ludovic Courtès ;;; ;;; This program is free software; you can redistribute it and/or ;;; modify it under the terms of the GNU General Public License ;;; as published by the Free Software Foundation; either version 2 ;;; of the License, or (at your option) any later version. ;;; ;;; This program is distributed in the hope that it will be useful, ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;;; GNU General Public License for more details. ;;; ;;; You should have received a copy of the GNU General Public License ;;; along with this program; if not, write to the Free Software ;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ;;; Remember ongoing GNUnet downloads so as to be able to resume them ;;; later. Typical usage is to define the following alias in your ;;; favorite shell: ;;; ;;; alias gnunet-download='gnunet-download-manager.scm download' ;;; ;;; You may have a ~/.gnunet-download-manager.scm Scheme configuration ;;; file. In particular, if you would like to be notified of ;;; completed downloads, you may want to add the following line to ;;; your configuration file: ;;; ;;; (add-hook! *completed-download-hook* ;;; completed-download-notification-hook) ;;; ;;; This script works fine with GNU Guile 1.6.4, and doesn't run with ;;; Guile 1.4.x. ;;; ;;; Enjoy! ;;; Ludovic Courtès (use-modules (ice-9 format) (ice-9 optargs) (ice-9 regex) (ice-9 and-let-star) (ice-9 pretty-print) (ice-9 documentation)) ;; Overall user settings (define *debug?* #f) (define *rc-file* (string-append (getenv "HOME") "/.gnunet-download-manager.scm")) (define *status-directory* (string-append (getenv "HOME") "/" ".gnunet-download-manager")) (define *gnunet-download* "gnunet-download") ;; Helper macros (define-macro (gnunet-info fmt . args) `(format #t (string-append *program-name* ": " ,fmt "~%") ,@args)) (define-macro (gnunet-debug fmt . args) (if *debug?* (cons 'gnunet-info (cons fmt args)) #t)) (define-macro (gnunet-error fmt . args) `(and ,(cons 'gnunet-info (cons fmt args)) (exit 1))) (define (exception-string key args) "Describe an error, using the format from @var{args}, if available." (if (< (length args) 4) (format #f "Scheme exception: ~S" key) (string-append (if (string? (car args)) (string-append "In " (car args)) "Scheme exception") ": " (apply format `(#f ,(cadr args) ,@(caddr args)))))) ;; Regexps matching GNUnet URIs (define *uri-base* "([[:alnum:]]+)\.([[:alnum:]]+)\.([[:alnum:]]+)\.([0-9]+)") (define *uri-re* (make-regexp (string-append "^gnunet://afs/" *uri-base* "$") regexp/extended)) (define *uri-status-file-re* (make-regexp (string-append "^" *uri-base* "$") regexp/extended)) (define (uri-status-file-name directory uri) "Return the name of the status file for URI @var{uri}." (let ((match (regexp-exec *uri-re* uri))) (if (not match) (and (gnunet-info "~a: Invalid URI" uri) #f) (let ((start (match:start match 1)) (end (match:end match 4))) (string-append directory "/" (substring uri start end)))))) (define (uri-status directory uri) "Load the current status alist for URI @var{uri} from @var{directory}." (gnunet-debug "uri-status") (let ((filename (uri-status-file-name directory uri))) (catch 'system-error (lambda () (let* ((file (open-input-file filename)) (status (read file))) (begin (close-port file) status))) (lambda (key . args) (and (gnunet-debug (exception-string key args)) '()))))) (define (process-exists? pid) (false-if-exception (begin (kill pid 0) #t))) (define (fork-and-exec directory program . args) "Launch @var{program} and return its PID." (gnunet-debug "fork-and-exec: ~a ~a" program args) (let ((pid (primitive-fork))) (if (= 0 pid) (begin (if directory (chdir directory)) (apply execlp (cons program (cons program args)))) pid))) (define* (start-downloader downloader uri options #:key (directory #f)) "Start the GNUnet downloader for URI @var{uri} with options @var{options}. Return an alist describing the download status." (catch 'system-error (lambda () (let* ((pid (apply fork-and-exec `(,(if directory directory (getcwd)) ,downloader ,@options)))) (gnunet-info "Launched process ~a" pid) `((uri . ,uri) (working-directory . ,(if directory directory (getcwd))) (options . ,options) (pid . ,(getpid)) (downloader-pid . ,pid)))) (lambda (key . args) (gnunet-error (exception-string key args))))) (define (download-process-alive? uri-status) "Return true if the download whose status is that described by @var{uri-status} is still alive." (let ((pid (assoc-ref uri-status 'pid)) (downloader-pid (assoc-ref uri-status 'downloader-pid))) (and (process-exists? pid) (process-exists? downloader-pid)))) (define (start-file-download downloader status-dir uri options) "Dowload the file located at @var{uri}, with options @var{options} and return an updated status alist." (gnunet-debug "start-file-download") (let ((uri-status (uri-status status-dir uri))) (if (null? uri-status) (acons 'start-date (current-time) (start-downloader downloader uri options)) (if (download-process-alive? uri-status) (and (gnunet-info "~a already being downloaded by process ~a" uri (assoc-ref uri-status 'pid)) #f) (and (gnunet-info "Resuming download") (let ((start-date (assoc-ref uri-status 'start-date)) (dir (assoc-ref uri-status 'working-directory)) (options (assoc-ref uri-status 'options))) (acons 'start-date start-date (start-downloader downloader uri options #:directory dir)))))))) (define *completed-download-hook* (make-hook 1)) (define (download-file downloader status-dir uri options) "Start downloading file located at URI @var{uri}, with options @var{options}, resuming it if it's already started." (catch 'system-error (lambda () (and-let* ((status (start-file-download downloader status-dir uri options)) (pid (assoc-ref status 'downloader-pid)) (filename (uri-status-file-name status-dir uri)) (file (open-file filename "w"))) ;; Write down the status (pretty-print status file) (close-port file) ;; Wait for `gnunet-download' (gnunet-info "Waiting for process ~a" pid) (let* ((process-status (waitpid pid)) (exit-val (status:exit-val (cdr process-status))) (term-sig (status:term-sig (cdr process-status)))) ;; Terminate (delete-file filename) (gnunet-info "Download completed (PID ~a, exit code ~a)" pid exit-val) (let ((ret `((end-date . ,(current-time)) (exit-code . ,exit-val) (terminating-signal . ,term-sig) ,@status))) (run-hook *completed-download-hook* ret) ret)))) (lambda (key . args) (gnunet-error (exception-string key args))))) (define (uri-status-files directory) "Return the list of URI status files in @var{directory}." (catch 'system-error (lambda () (let ((dir (opendir directory))) (let loop ((filename (readdir dir)) (file-list '())) (if (eof-object? filename) file-list (if (regexp-exec *uri-status-file-re* filename) (loop (readdir dir) (cons filename file-list)) (loop (readdir dir) file-list)))))) (lambda (key . args) (gnunet-error (exception-string key args))))) (define (output-file-option option-list) "Return the output file specified in @var{option-list}, false if anavailable." (if (null? option-list) #f (let ((rest (cdr option-list)) (opt (car option-list))) (if (null? rest) #f (if (or (string=? opt "-o") (string=? opt "--output")) (car rest) (output-file-option rest)))))) (define (download-command . args) "Start downloading a file using the given `gnunet-download' arguments." (gnunet-debug "download-command") (let* ((argc (length args)) ;; FIXME: We're assuming the URI is the last argument (uri (car (list-tail args (- argc 1)))) (options args)) (download-file *gnunet-download* *status-directory* uri options))) (define (status-command . args) "Print status info about files being downloaded." (for-each (lambda (status) (format #t "~a: ~a~% ~a~% ~a~% ~a~%" (assoc-ref status 'uri) (if (download-process-alive? status) (string-append "running (PID " (number->string (assoc-ref status 'pid)) ")") "not running") (string-append "Started on " (strftime "%c" (localtime (assoc-ref status 'start-date)))) (string-append "Directory: " (assoc-ref status 'working-directory)) (string-append "Output file: " (or (output-file-option (assoc-ref status 'options)) "")))) (map (lambda (file) (uri-status *status-directory* (string-append "gnunet://afs/" file))) (uri-status-files *status-directory*)))) (define (resume-command . args) "Resume stopped downloads." (for-each (lambda (status) (if (not (download-process-alive? status)) (if (= 0 (primitive-fork)) (let* ((ret (download-file *gnunet-download* *status-directory* (assoc-ref status 'uri) (assoc-ref status 'options))) (code (assoc-ref ret 'exit-code))) (exit code))))) (map (lambda (file) (uri-status *status-directory* (string-append "gnunet://afs/" file))) (uri-status-files *status-directory*)))) (define (killall-command . args) "Stop all running downloads." (for-each (lambda (status) (if (download-process-alive? status) (let ((pid (assoc-ref status 'pid)) (dl-pid (assoc-ref status 'downloader-pid))) (and (gnunet-info "Stopping processes ~a and ~a" pid dl-pid) (kill pid 15) (kill dl-pid 15))))) (map (lambda (file) (uri-status *status-directory* (string-append "gnunet://afs/" file))) (uri-status-files *status-directory*)))) (define (help-command . args) "Show this help message." (format #t "Usage: ~a [options]~%" *program-name*) (format #t "Where may be one of the following:~%~%") (for-each (lambda (command) (if (not (eq? (cdr command) help-command)) (format #t (string-append " " (car command) ": " (object-documentation (cdr command)) "~%")))) *commands*) (format #t "~%")) (define (settings-command . args) "Dump the current settings." (format #t "Current settings:~%~%") (module-for-each (lambda (symbol variable) (if (string-match "^\\*.*\\*$" (symbol->string symbol)) (format #t " ~a: ~a~%" symbol (variable-ref variable)))) (current-module)) (format #t "~%")) (define (version-command . args) "Show version information." (format #t "~a ~a.~a (~a)~%" *program-name* *version-major* *version-minor* *version-date*)) ;; This hook may be added to *completed-download-hook*. (define (completed-download-notification-hook status) "Notifies of the completion of a file download." (let ((msg (string-append "GNUnet download of " (output-file-option (assoc-ref status 'options)) " in " (assoc-ref status 'working-directory) " complete!"))) (if (getenv "DISPLAY") (waitpid (fork-and-exec #f "xmessage" msg)) (waitpid (fork-and-exec #f "write" (cuserid) msg))))) ;; Available user commands (define *commands* `(("download" . ,download-command) ("status" . ,status-command) ("resume" . ,resume-command) ("killall" . ,killall-command) ("settings" . ,settings-command) ("version" . ,version-command) ("help" . ,help-command) ("--help" . ,help-command) ("-h" . ,help-command))) (define *program-name* "gnunet-download-manager") (define *version-major* 0) (define *version-minor* 1) (define *version-date* "april 2004") (define (main args) (set! *program-name* (basename (car args))) ;; Load the user's configuration file (if (file-exists? *rc-file*) (load *rc-file*)) ;; Check whether the status directory already exists (if (not (file-exists? *status-directory*)) (begin (gnunet-info "Creating status directory ~a..." *status-directory*) (catch 'system-error (lambda () (mkdir *status-directory*)) (lambda (key . args) (and (gnunet-error (exception-string key args)) (exit 1)))))) ;; Go ahead (if (< (length args) 2) (and (format #t "Usage: ~a [options]~%" *program-name*) (exit 1)) (let* ((command-name (cadr args)) (command (assoc-ref *commands* command-name))) (if command (apply command (cddr args)) (and (gnunet-info "~a command not found" command-name) (exit 1))))))gnunet-0.9.3/src/fs/test_fs_directory.c0000644000175000017500000001273211760502551015051 00000000000000/* This file is part of GNUnet. (C) 2005, 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/test_fs_directory.c * @brief Test for fs_directory.c * @author Christian Grothoff */ #include "platform.h" #include #include "gnunet_util_lib.h" #include "gnunet_fs_service.h" #include "fs_api.h" #define ABORT() { fprintf(stderr, "Error at %s:%d\n", __FILE__, __LINE__); return 1; } struct PCLS { struct GNUNET_FS_Uri **uri; struct GNUNET_CONTAINER_MetaData **md; unsigned int pos; unsigned int max; }; static void processor (void *cls, const char *filename, const struct GNUNET_FS_Uri *uri, const struct GNUNET_CONTAINER_MetaData *md, size_t length, const void *data) { struct PCLS *p = cls; int i; if (NULL == uri) return; /* ignore directory's meta data */ for (i = 0; i < p->max; i++) { if (GNUNET_CONTAINER_meta_data_test_equal (p->md[i], md) && GNUNET_FS_uri_test_equal (p->uri[i], uri)) { p->pos++; return; } } FPRINTF (stderr, "Error at %s:%d\n", __FILE__, __LINE__); } static int testDirectory (unsigned int i) { struct GNUNET_FS_DirectoryBuilder *db; char *data; size_t dlen; struct GNUNET_FS_Uri **uris; struct GNUNET_CONTAINER_MetaData **mds; struct GNUNET_CONTAINER_MetaData *meta; struct PCLS cls; char *emsg; int p; int q; char uri[512]; char txt[128]; int ret = 0; struct GNUNET_TIME_Absolute start; char *s; cls.max = i; uris = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri *) * i); mds = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_MetaData *) * i); meta = GNUNET_CONTAINER_meta_data_create (); GNUNET_CONTAINER_meta_data_insert (meta, "", EXTRACTOR_METATYPE_TITLE, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "A title", strlen ("A title") + 1); GNUNET_CONTAINER_meta_data_insert (meta, "", EXTRACTOR_METATYPE_AUTHOR_NAME, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "An author", strlen ("An author") + 1); for (p = 0; p < i; p++) { mds[p] = GNUNET_CONTAINER_meta_data_create (); for (q = 0; q <= p; q++) { GNUNET_snprintf (txt, sizeof (txt), "%u -- %u\n", p, q); GNUNET_CONTAINER_meta_data_insert (mds[p], "", q % EXTRACTOR_metatype_get_max (), EXTRACTOR_METAFORMAT_UTF8, "text/plain", txt, strlen (txt) + 1); } GNUNET_snprintf (uri, sizeof (uri), "gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.%u", p); emsg = NULL; uris[p] = GNUNET_FS_uri_parse (uri, &emsg); if (uris[p] == NULL) { GNUNET_CONTAINER_meta_data_destroy (mds[p]); while (--p > 0) { GNUNET_CONTAINER_meta_data_destroy (mds[p]); GNUNET_FS_uri_destroy (uris[p]); } GNUNET_free (mds); GNUNET_free (uris); GNUNET_free (emsg); GNUNET_CONTAINER_meta_data_destroy (meta); ABORT (); /* error in testcase */ } GNUNET_assert (emsg == NULL); } start = GNUNET_TIME_absolute_get (); db = GNUNET_FS_directory_builder_create (meta); for (p = 0; p < i; p++) GNUNET_FS_directory_builder_add (db, uris[p], mds[p], NULL); GNUNET_FS_directory_builder_finish (db, &dlen, (void **) &data); s = GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (start)); FPRINTF (stdout, "Creating directory with %u entires and total size %llu took %s\n", i, (unsigned long long) dlen, s); GNUNET_free (s); if (i < 100) { cls.pos = 0; cls.uri = uris; cls.md = mds; GNUNET_FS_directory_list_contents (dlen, data, 0, &processor, &cls); GNUNET_assert (cls.pos == i); } GNUNET_free (data); GNUNET_CONTAINER_meta_data_destroy (meta); for (p = 0; p < i; p++) { GNUNET_CONTAINER_meta_data_destroy (mds[p]); GNUNET_FS_uri_destroy (uris[p]); } GNUNET_free (uris); GNUNET_free (mds); return ret; } int main (int argc, char *argv[]) { int failureCount = 0; int i; GNUNET_log_setup ("test_fs_directory", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); for (i = 17; i < 1000; i *= 2) failureCount += testDirectory (i); if (failureCount != 0) return 1; return 0; } /* end of test_fs_directory.c */ gnunet-0.9.3/src/fs/fs.h0000644000175000017500000002044211760502551011730 00000000000000/* This file is part of GNUnet. (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs.h * @brief definitions for the entire fs module * @author Igor Wronsky, Christian Grothoff */ #ifndef FS_H #define FS_H #include "gnunet_constants.h" #include "gnunet_datastore_service.h" #include "gnunet_dht_service.h" #include "gnunet_fs_service.h" #include "gnunet_block_lib.h" #include "block_fs.h" /** * Size of the individual blocks used for file-sharing. */ #define DBLOCK_SIZE (32*1024) /** * Blocksize to use when hashing files for indexing (blocksize for IO, * not for the DBlocks). Larger blocksizes can be more efficient but * will be more disruptive as far as the scheduler is concerned. */ #define HASHING_BLOCKSIZE (1024 * 128) /** * @brief content hash key */ struct ContentHashKey { /** * Hash of the original content, used for encryption. */ GNUNET_HashCode key; /** * Hash of the encrypted content, used for querying. */ GNUNET_HashCode query; }; GNUNET_NETWORK_STRUCT_BEGIN /** * Message sent from a GNUnet (fs) publishing activity to the * gnunet-fs-service to initiate indexing of a file. The service is * supposed to check if the specified file is available and has the * same cryptographic hash. It should then respond with either a * confirmation or a denial. * * On OSes where this works, it is considered acceptable if the * service only checks that the path, device and inode match (it can * then be assumed that the hash will also match without actually * computing it; this is an optimization that should be safe given * that the client is not our adversary). */ struct IndexStartMessage { /** * Message type will be GNUNET_MESSAGE_TYPE_FS_INDEX_START. */ struct GNUNET_MessageHeader header; /** * For alignment. */ uint32_t reserved GNUNET_PACKED; /** * ID of device containing the file, as seen by the client. This * device ID is obtained using a call like "statvfs" (and converting * the "f_fsid" field to a 32-bit big-endian number). Use 0 if the * OS does not support this, in which case the service must do a * full hash recomputation. */ uint64_t device GNUNET_PACKED; /** * Inode of the file on the given device, as seen by the client * ("st_ino" field from "struct stat"). Use 0 if the OS does not * support this, in which case the service must do a full hash * recomputation. */ uint64_t inode GNUNET_PACKED; /** * Hash of the file that we would like to index. */ GNUNET_HashCode file_id; /* this is followed by a 0-terminated * filename of a file with the hash * "file_id" as seen by the client */ }; /** * Message send by FS service in response to a request * asking for a list of all indexed files. */ struct IndexInfoMessage { /** * Message type will be * GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_ENTRY. */ struct GNUNET_MessageHeader header; /** * Always zero. */ uint32_t reserved GNUNET_PACKED; /** * Hash of the indexed file. */ GNUNET_HashCode file_id; /* this is followed by a 0-terminated * filename of a file with the hash * "file_id" as seen by the client */ }; /** * Message sent from a GNUnet (fs) unindexing activity to the * gnunet-service-fs to indicate that a file will be unindexed. The * service is supposed to remove the file from the list of indexed * files and response with a confirmation message (even if the file * was already not on the list). */ struct UnindexMessage { /** * Message type will be * GNUNET_MESSAGE_TYPE_FS_UNINDEX. */ struct GNUNET_MessageHeader header; /** * Always zero. */ uint32_t reserved GNUNET_PACKED; /** * Hash of the file that we will unindex. */ GNUNET_HashCode file_id; }; /** * No options. */ #define SEARCH_MESSAGE_OPTION_NONE 0 /** * Only search the local datastore (no network) */ #define SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY 1 /** * Request is too large to fit in 64k format. The list of * already-known search results will be continued in another message * for the same type/query/target and additional already-known results * following this one). */ #define SEARCH_MESSAGE_OPTION_CONTINUED 2 /** * Message sent from a GNUnet (fs) search activity to the * gnunet-service-fs to start a search. */ struct SearchMessage { /** * Message type will be * GNUNET_MESSAGE_TYPE_FS_START_SEARCH. */ struct GNUNET_MessageHeader header; /** * Bitmask with options. Zero for no options, one for * loopback-only, two for 'to be continued' (with a second search * message for the same type/query/target and additional * already-known results following this one). See * SEARCH_MESSAGE_OPTION_ defines. * * Other bits are currently not defined. */ uint32_t options GNUNET_PACKED; /** * Type of the content that we're looking for. */ uint32_t type GNUNET_PACKED; /** * Desired anonymity level, big-endian. */ uint32_t anonymity_level GNUNET_PACKED; /** * If the request is for a DBLOCK or IBLOCK, this is the identity of * the peer that is known to have a response. Set to all-zeros if * such a target is not known (note that even if OUR anonymity * level is >0 we may happen to know the responder's identity; * nevertheless, we should probably not use it for a DHT-lookup * or similar blunt actions in order to avoid exposing ourselves). *

    * If the request is for an SBLOCK, this is the identity of the * pseudonym to which the SBLOCK belongs. *

    * If the request is for a KBLOCK, "target" must be all zeros. */ GNUNET_HashCode target; /** * Hash of the keyword (aka query) for KBLOCKs; Hash of * the CHK-encoded block for DBLOCKS and IBLOCKS (aka query) * and hash of the identifier XORed with the target for * SBLOCKS (aka query). */ GNUNET_HashCode query; /* this is followed by the hash codes of already-known * results (which should hence be excluded from what * the service returns); naturally, this only applies * to queries that can have multiple results, such as * those for KBLOCKS (KSK) and SBLOCKS (SKS) */ }; /** * Response from FS service with a result for a previous FS search. * Note that queries for DBLOCKS and IBLOCKS that have received a * single response are considered done. This message is transmitted * between peers. */ struct PutMessage { /** * Message type will be GNUNET_MESSAGE_TYPE_FS_PUT. */ struct GNUNET_MessageHeader header; /** * Type of the block (in big endian). Should never be zero. */ uint32_t type GNUNET_PACKED; /** * When does this result expire? */ struct GNUNET_TIME_AbsoluteNBO expiration; /* this is followed by the actual encrypted content */ }; /** * Response from FS service with a result for a previous FS search. * Note that queries for DBLOCKS and IBLOCKS that have received a * single response are considered done. This message is transmitted * between the service and a client. */ struct ClientPutMessage { /** * Message type will be GNUNET_MESSAGE_TYPE_FS_PUT. */ struct GNUNET_MessageHeader header; /** * Type of the block (in big endian). Should never be zero. */ uint32_t type GNUNET_PACKED; /** * When does this result expire? */ struct GNUNET_TIME_AbsoluteNBO expiration; /** * When was the last time we've tried to download this block? * (FOREVER if unknown/not relevant) */ struct GNUNET_TIME_AbsoluteNBO last_transmission; /* this is followed by the actual encrypted content */ }; GNUNET_NETWORK_STRUCT_END #endif /* end of fs.h */ gnunet-0.9.3/src/fs/test_fs_list_indexed.c0000644000175000017500000002472611760502551015526 00000000000000/* This file is part of GNUnet. (C) 2004, 2005, 2006, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/test_fs_list_indexed.c * @brief simple testcase for list_indexed operation (indexing, listing * indexed) * @author Christian Grothoff * * TODO: * - actually call list_indexed API! */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_arm_service.h" #include "gnunet_fs_service.h" #define VERBOSE GNUNET_NO #define START_ARM GNUNET_YES /** * File-size we use for testing. */ #define FILESIZE (1024 * 1024 * 2) /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) /** * How long should our test-content live? */ #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static struct PeerContext p1; static struct GNUNET_TIME_Absolute start; static struct GNUNET_FS_Handle *fs; static struct GNUNET_FS_PublishContext *publish; static char *fn1; static char *fn2; static int err; static void abort_publish_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_FS_publish_stop (publish); publish = NULL; GNUNET_DISK_directory_remove (fn1); GNUNET_free (fn1); fn1 = NULL; GNUNET_DISK_directory_remove (fn2); GNUNET_free (fn2); fn2 = NULL; } static void list_indexed_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) { void *ret; ret = NULL; switch (event->status) { case GNUNET_FS_STATUS_PUBLISH_COMPLETED: ret = event->value.publish.cctx; printf ("Publish complete, %llu kbps.\n", (unsigned long long) (FILESIZE * 1000 / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value) / 1024)); if (0 == strcmp ("list_indexed-context-dir", event->value.publish.cctx)) GNUNET_SCHEDULER_add_continuation (&list_indexed_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_PUBLISH_PROGRESS: ret = event->value.publish.cctx; GNUNET_assert (publish == event->value.publish.pc); #if VERBOSE printf ("Publish is progressing (%llu/%llu at level %u off %llu)...\n", (unsigned long long) event->value.publish.completed, (unsigned long long) event->value.publish.size, event->value.publish.specifics.progress.depth, (unsigned long long) event->value.publish.specifics. progress.offset); #endif break; case GNUNET_FS_STATUS_PUBLISH_ERROR: ret = event->value.publish.cctx; FPRINTF (stderr, "Error publishing file: %s\n", event->value.publish.specifics.error.message); err = 1; if (0 == strcmp ("list_indexed-context-dir", event->value.publish.cctx)) GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_PUBLISH_START: ret = event->value.publish.cctx; if (0 == strcmp ("list_indexed-context1", event->value.publish.cctx)) { GNUNET_assert (0 == strcmp ("list_indexed-context-dir", event->value.publish.pctx)); GNUNET_assert (FILESIZE == event->value.publish.size); GNUNET_assert (0 == event->value.publish.completed); GNUNET_assert (1 == event->value.publish.anonymity); } else if (0 == strcmp ("list_indexed-context2", event->value.publish.cctx)) { GNUNET_assert (0 == strcmp ("list_indexed-context-dir", event->value.publish.pctx)); GNUNET_assert (FILESIZE == event->value.publish.size); GNUNET_assert (0 == event->value.publish.completed); GNUNET_assert (2 == event->value.publish.anonymity); } else if (0 == strcmp ("list_indexed-context-dir", event->value.publish.cctx)) { GNUNET_assert (0 == event->value.publish.completed); GNUNET_assert (3 == event->value.publish.anonymity); } else GNUNET_assert (0); break; case GNUNET_FS_STATUS_PUBLISH_STOPPED: if (0 == strcmp ("list_indexed-context-dir", event->value.publish.cctx)) { GNUNET_assert (publish == event->value.publish.pc); publish = NULL; } break; default: printf ("Unexpected event: %d\n", event->status); break; } return ret; } static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE "-L", "DEBUG", #endif "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); } static void stop_arm (struct PeerContext *p) { #if START_ARM if (NULL != p->arm_proc) { if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; } #endif GNUNET_CONFIGURATION_destroy (p->cfg); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { const char *keywords[] = { "down_foo", "down_bar", }; char *buf; struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_FS_Uri *kuri; struct GNUNET_FS_FileInformation *fi1; struct GNUNET_FS_FileInformation *fi2; struct GNUNET_FS_FileInformation *fidir; size_t i; struct GNUNET_FS_BlockOptions bo; setup_peer (&p1, "test_fs_list_indexed_data.conf"); fs = GNUNET_FS_start (cfg, "test-fs-list_indexed", &progress_cb, NULL, GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); GNUNET_assert (NULL != fs); fn1 = GNUNET_DISK_mktemp ("gnunet-list_indexed-test-dst"); buf = GNUNET_malloc (FILESIZE); for (i = 0; i < FILESIZE; i++) buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); GNUNET_assert (FILESIZE == GNUNET_DISK_fn_write (fn1, buf, FILESIZE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)); GNUNET_free (buf); fn2 = GNUNET_DISK_mktemp ("gnunet-list_indexed-test-dst"); buf = GNUNET_malloc (FILESIZE); for (i = 0; i < FILESIZE; i++) buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); GNUNET_assert (FILESIZE == GNUNET_DISK_fn_write (fn2, buf, FILESIZE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)); GNUNET_free (buf); meta = GNUNET_CONTAINER_meta_data_create (); kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); bo.content_priority = 42; bo.anonymity_level = 1; bo.replication_level = 0; bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); fi1 = GNUNET_FS_file_information_create_from_file (fs, "list_indexed-context1", fn1, kuri, meta, GNUNET_YES, &bo); GNUNET_assert (NULL != fi1); bo.anonymity_level = 2; fi2 = GNUNET_FS_file_information_create_from_file (fs, "list_indexed-context2", fn2, kuri, meta, GNUNET_YES, &bo); GNUNET_assert (NULL != fi2); bo.anonymity_level = 3; fidir = GNUNET_FS_file_information_create_empty_directory (fs, "list_indexed-context-dir", kuri, meta, &bo, NULL); GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi1)); GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi2)); GNUNET_FS_uri_destroy (kuri); GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_assert (NULL != fidir); start = GNUNET_TIME_absolute_get (); publish = GNUNET_FS_publish_start (fs, fidir, NULL, NULL, NULL, GNUNET_FS_PUBLISH_OPTION_NONE); GNUNET_assert (publish != NULL); } int main (int argc, char *argv[]) { char *const argvx[] = { "test-fs-list_indexed", "-c", "test_fs_list_indexed_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("test_fs_list_indexed", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "test-fs-list_indexed", "nohelp", options, &run, NULL); stop_arm (&p1); GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-list-indexed/"); if (fn1 != NULL) { GNUNET_DISK_directory_remove (fn1); GNUNET_free (fn1); } if (fn2 != NULL) { GNUNET_DISK_directory_remove (fn2); GNUNET_free (fn2); } return err; } /* end of test_fs_list_indexed.c */ gnunet-0.9.3/src/fs/gnunet-service-fs_lc.h0000644000175000017500000000534111760502551015343 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-service-fs_lc.h * @brief API to handle 'local clients' * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_FS_LC_H #define GNUNET_SERVICE_FS_LC_H #include "gnunet-service-fs.h" /** * Look up a local client record or create one if it * doesn't exist yet. * * @param client handle of the client * @return handle to local client entry */ struct GSF_LocalClient * GSF_local_client_lookup_ (struct GNUNET_SERVER_Client *client); /** * Handle START_SEARCH-message (search request from local client). * Only responsible for creating the request entry itself and setting * up reply callback and cancellation on client disconnect. Does NOT * execute the actual request strategy (planning). * * @param client identification of the client * @param message the actual message * @param prptr where to store the pending request handle for the request * @return GNUNET_YES to start local processing, * GNUNET_NO to not (yet) start local processing, * GNUNET_SYSERR on error */ int GSF_local_client_start_search_handler_ (struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message, struct GSF_PendingRequest **prptr); /** * Transmit a message to the given local client as soon as possible. * If the client disconnects before transmission, the message is * simply discarded. * * @param lc recipient * @param msg message to transmit to client */ void GSF_local_client_transmit_ (struct GSF_LocalClient *lc, const struct GNUNET_MessageHeader *msg); /** * A client disconnected from us. Tear down the local client record. * * @param cls unused * @param client handle of the client */ void GSF_client_disconnect_handler_ (void *cls, struct GNUNET_SERVER_Client *client); #endif /* end of gnunet-service-fs_lc.h */ gnunet-0.9.3/src/fs/test_fs_namespace_list_updateable.c0000644000175000017500000001520611760502551020221 00000000000000/* This file is part of GNUnet. (C) 2005, 2006, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/test_fs_namespace_list_updateable.c * @brief Test for fs_namespace_list_updateable.c * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_arm_service.h" #include "gnunet_fs_service.h" #define VERBOSE GNUNET_NO #define START_ARM GNUNET_YES static struct PeerContext p1; static struct GNUNET_FS_Handle *fs; static int err; static struct GNUNET_FS_Namespace *ns; static struct GNUNET_CONTAINER_MetaData *meta; static struct GNUNET_FS_Uri *uri_this; static struct GNUNET_FS_Uri *uri_next; static struct GNUNET_FS_BlockOptions bo; struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) { return NULL; } static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE "-L", "DEBUG", #endif "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); } static void stop_arm (struct PeerContext *p) { #if START_ARM if (NULL != p->arm_proc) { if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; } #endif if (uri_this != NULL) GNUNET_FS_uri_destroy (uri_this); if (uri_next != NULL) GNUNET_FS_uri_destroy (uri_next); if (ns != NULL) GNUNET_FS_namespace_delete (ns, GNUNET_NO); if (meta != NULL) GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_CONFIGURATION_destroy (p->cfg); } static void check_next (void *cls, const char *last_id, const struct GNUNET_FS_Uri *last_uri, const struct GNUNET_CONTAINER_MetaData *last_meta, const char *next_id) { GNUNET_break (0 == strcmp (last_id, "next")); GNUNET_break (0 == strcmp (next_id, "future")); err -= 4; } static void check_this_next (void *cls, const char *last_id, const struct GNUNET_FS_Uri *last_uri, const struct GNUNET_CONTAINER_MetaData *last_meta, const char *next_id) { GNUNET_break (0 == strcmp (last_id, "this")); GNUNET_break (0 == strcmp (next_id, "next")); err -= 2; err += 4; GNUNET_FS_namespace_list_updateable (ns, next_id, &check_next, NULL); } static void sks_cont_next (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) { GNUNET_assert (NULL == emsg); err += 2; GNUNET_FS_namespace_list_updateable (ns, NULL, &check_this_next, NULL); } static void check_this (void *cls, const char *last_id, const struct GNUNET_FS_Uri *last_uri, const struct GNUNET_CONTAINER_MetaData *last_meta, const char *next_id) { GNUNET_break (0 == strcmp (last_id, "this")); GNUNET_break (0 == strcmp (next_id, "next")); err -= 1; } static void sks_cont_this (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) { GNUNET_assert (NULL == emsg); err = 1; GNUNET_FS_namespace_list_updateable (ns, NULL, &check_this, NULL); GNUNET_FS_publish_sks (fs, ns, "next", "future", meta, uri_next, &bo, GNUNET_FS_PUBLISH_OPTION_NONE, &sks_cont_next, NULL); } static void testNamespace () { ns = GNUNET_FS_namespace_create (fs, "testNamespace"); GNUNET_assert (NULL != ns); bo.content_priority = 1; bo.anonymity_level = 1; bo.replication_level = 0; bo.expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); meta = GNUNET_CONTAINER_meta_data_create (); uri_this = GNUNET_FS_uri_parse ("gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.42", NULL); uri_next = GNUNET_FS_uri_parse ("gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.43", NULL); GNUNET_FS_publish_sks (fs, ns, "this", "next", meta, uri_this, &bo, GNUNET_FS_PUBLISH_OPTION_NONE, &sks_cont_this, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { setup_peer (&p1, "test_fs_namespace_data.conf"); fs = GNUNET_FS_start (cfg, "test-fs-namespace", &progress_cb, NULL, GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); testNamespace (); } int main (int argc, char *argv[]) { char *const argvx[] = { "test-fs-namespace", "-c", "test_fs_namespace_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("test_fs_namespace_list_updateable", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "test-fs-namespace", "nohelp", options, &run, NULL); stop_arm (&p1); GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-namespace/"); return err; } /* end of test_fs_namespace_list_updateable.c */ gnunet-0.9.3/src/fs/test_fs_unindex_persistence.c0000644000175000017500000002625511760502551017130 00000000000000/* This file is part of GNUnet. (C) 2004, 2005, 2006, 2008, 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/test_fs_unindex_persistence.c * @brief simple testcase for simple publish + unindex operation * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_arm_service.h" #include "gnunet_fs_service.h" #define VERBOSE GNUNET_NO #define START_ARM GNUNET_YES /** * File-size we use for testing. */ #define FILESIZE (1024 * 1024 * 2) /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) /** * How long should our test-content live? */ #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static struct PeerContext p1; static struct GNUNET_TIME_Absolute start; static struct GNUNET_FS_Handle *fs; static struct GNUNET_FS_UnindexContext *unindex; static struct GNUNET_FS_PublishContext *publish; static char *fn; static const struct GNUNET_CONFIGURATION_Handle *cfg; static void abort_publish_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_FS_publish_stop (publish); publish = NULL; } static void abort_unindex_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (unindex != NULL) { GNUNET_FS_unindex_stop (unindex); unindex = NULL; } if (fn != NULL) { GNUNET_DISK_directory_remove (fn); GNUNET_free (fn); fn = NULL; } } static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event); static void restart_fs_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_FS_stop (fs); fs = GNUNET_FS_start (cfg, "test-fs-unindex-persistence", &progress_cb, NULL, GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); } /** * Consider scheduling the restart-task. * Only runs the restart task once per event * category. * * @param ev type of the event to consider */ static void consider_restart (int ev) { static int prev[32]; static int off; int i; for (i = 0; i < off; i++) if (prev[i] == ev) return; prev[off++] = ev; GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_URGENT, &restart_fs_task, NULL); } static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) { switch (event->status) { case GNUNET_FS_STATUS_PUBLISH_PROGRESS: #if VERBOSE printf ("Publish is progressing (%llu/%llu at level %u off %llu)...\n", (unsigned long long) event->value.publish.completed, (unsigned long long) event->value.publish.size, event->value.publish.specifics.progress.depth, (unsigned long long) event->value.publish.specifics. progress.offset); #endif break; case GNUNET_FS_STATUS_PUBLISH_COMPLETED: printf ("Publishing complete, %llu kbps.\n", (unsigned long long) (FILESIZE * 1000 / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value) / 1024)); start = GNUNET_TIME_absolute_get (); unindex = GNUNET_FS_unindex_start (fs, fn, "unindex"); GNUNET_assert (unindex != NULL); break; case GNUNET_FS_STATUS_UNINDEX_COMPLETED: printf ("Unindex complete, %llu kbps.\n", (unsigned long long) (FILESIZE * 1000 / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value) / 1024)); GNUNET_SCHEDULER_add_continuation (&abort_unindex_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_UNINDEX_PROGRESS: consider_restart (event->status); GNUNET_assert (unindex == event->value.unindex.uc); #if VERBOSE printf ("Unindex is progressing (%llu/%llu at level %u off %llu)...\n", (unsigned long long) event->value.unindex.completed, (unsigned long long) event->value.unindex.size, event->value.unindex.specifics.progress.depth, (unsigned long long) event->value.unindex.specifics. progress.offset); #endif break; case GNUNET_FS_STATUS_PUBLISH_SUSPEND: if (event->value.publish.pc == publish) publish = NULL; break; case GNUNET_FS_STATUS_PUBLISH_RESUME: if (NULL == publish) { publish = event->value.publish.pc; return "publish-context"; } break; case GNUNET_FS_STATUS_UNINDEX_SUSPEND: GNUNET_assert (event->value.unindex.uc == unindex); unindex = NULL; break; case GNUNET_FS_STATUS_UNINDEX_RESUME: GNUNET_assert (NULL == unindex); unindex = event->value.unindex.uc; return "unindex"; case GNUNET_FS_STATUS_PUBLISH_ERROR: FPRINTF (stderr, "Error publishing file: %s\n", event->value.publish.specifics.error.message); GNUNET_break (0); GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_UNINDEX_ERROR: FPRINTF (stderr, "Error unindexing file: %s\n", event->value.unindex.specifics.error.message); GNUNET_SCHEDULER_add_continuation (&abort_unindex_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_PUBLISH_START: GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); GNUNET_assert (NULL == event->value.publish.pctx); GNUNET_assert (FILESIZE == event->value.publish.size); GNUNET_assert (0 == event->value.publish.completed); GNUNET_assert (1 == event->value.publish.anonymity); break; case GNUNET_FS_STATUS_PUBLISH_STOPPED: GNUNET_assert (publish == event->value.publish.pc); GNUNET_assert (FILESIZE == event->value.publish.size); GNUNET_assert (1 == event->value.publish.anonymity); GNUNET_FS_stop (fs); fs = NULL; break; case GNUNET_FS_STATUS_UNINDEX_START: consider_restart (event->status); GNUNET_assert (unindex == NULL); GNUNET_assert (0 == strcmp ("unindex", event->value.unindex.cctx)); GNUNET_assert (0 == strcmp (fn, event->value.unindex.filename)); GNUNET_assert (FILESIZE == event->value.unindex.size); GNUNET_assert (0 == event->value.unindex.completed); break; case GNUNET_FS_STATUS_UNINDEX_STOPPED: GNUNET_assert (unindex == event->value.unindex.uc); GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; default: printf ("Unexpected event: %d\n", event->status); break; } return NULL; } static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE "-L", "DEBUG", #endif "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); } static void stop_arm (struct PeerContext *p) { #if START_ARM if (NULL != p->arm_proc) { if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; } #endif GNUNET_CONFIGURATION_destroy (p->cfg); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { const char *keywords[] = { "down_foo", "down_bar", }; char *buf; struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_FS_Uri *kuri; struct GNUNET_FS_FileInformation *fi; size_t i; struct GNUNET_FS_BlockOptions bo; cfg = c; setup_peer (&p1, "test_fs_unindex_data.conf"); fn = GNUNET_DISK_mktemp ("gnunet-unindex-test-dst"); fs = GNUNET_FS_start (cfg, "test-fs-unindex-persistence", &progress_cb, NULL, GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); GNUNET_assert (NULL != fs); buf = GNUNET_malloc (FILESIZE); for (i = 0; i < FILESIZE; i++) buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); GNUNET_assert (FILESIZE == GNUNET_DISK_fn_write (fn, buf, FILESIZE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)); GNUNET_free (buf); meta = GNUNET_CONTAINER_meta_data_create (); kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); bo.content_priority = 42; bo.anonymity_level = 1; bo.replication_level = 0; bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); fi = GNUNET_FS_file_information_create_from_file (fs, "publish-context", fn, kuri, meta, GNUNET_YES, &bo); GNUNET_FS_uri_destroy (kuri); GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_assert (NULL != fi); start = GNUNET_TIME_absolute_get (); publish = GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, GNUNET_FS_PUBLISH_OPTION_NONE); GNUNET_assert (publish != NULL); } int main (int argc, char *argv[]) { char *const argvx[] = { "test-fs-unindex", "-c", "test_fs_unindex_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("test_fs_unindex_persistence", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "test-fs-unindex", "nohelp", options, &run, NULL); stop_arm (&p1); GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-unindex/"); if (NULL != fn) { GNUNET_DISK_directory_remove (fn); GNUNET_free (fn); } return 0; } /* end of test_fs_unindex_persistence.c */ gnunet-0.9.3/src/fs/test_fs_publish.c0000644000175000017500000002403111760502551014506 00000000000000/* This file is part of GNUnet. (C) 2004, 2005, 2006, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/test_fs_publish.c * @brief simple testcase for publish operation (indexing, listing * indexed, directory structure) * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_arm_service.h" #include "gnunet_fs_service.h" #define VERBOSE GNUNET_NO #define START_ARM GNUNET_YES /** * File-size we use for testing. */ #define FILESIZE (1024 * 1024 * 2) /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) /** * How long should our test-content live? */ #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static struct PeerContext p1; static struct GNUNET_TIME_Absolute start; static struct GNUNET_FS_Handle *fs; static struct GNUNET_FS_PublishContext *publish; static char *fn1; static char *fn2; static int err; static void abort_publish_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_FS_publish_stop (publish); publish = NULL; GNUNET_DISK_directory_remove (fn1); GNUNET_free (fn1); fn1 = NULL; GNUNET_DISK_directory_remove (fn2); GNUNET_free (fn2); fn2 = NULL; } static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) { void *ret; ret = NULL; switch (event->status) { case GNUNET_FS_STATUS_PUBLISH_COMPLETED: ret = event->value.publish.cctx; printf ("Publish complete, %llu kbps.\n", (unsigned long long) (FILESIZE * 1000 / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value) / 1024)); if (0 == strcmp ("publish-context-dir", event->value.publish.cctx)) GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_PUBLISH_PROGRESS: ret = event->value.publish.cctx; GNUNET_assert (publish == event->value.publish.pc); #if VERBOSE printf ("Publish is progressing (%llu/%llu at level %u off %llu)...\n", (unsigned long long) event->value.publish.completed, (unsigned long long) event->value.publish.size, event->value.publish.specifics.progress.depth, (unsigned long long) event->value.publish.specifics. progress.offset); #endif break; case GNUNET_FS_STATUS_PUBLISH_ERROR: ret = event->value.publish.cctx; FPRINTF (stderr, "Error publishing file: %s\n", event->value.publish.specifics.error.message); err = 1; if (0 == strcmp ("publish-context-dir", event->value.publish.cctx)) { FPRINTF (stderr, "Scheduling abort task for error on `%s'\n", (const char *) event->value.publish.cctx); GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } break; case GNUNET_FS_STATUS_PUBLISH_START: ret = event->value.publish.cctx; if (0 == strcmp ("publish-context1", event->value.publish.cctx)) { GNUNET_assert (0 == strcmp ("publish-context-dir", event->value.publish.pctx)); GNUNET_assert (FILESIZE == event->value.publish.size); GNUNET_assert (0 == event->value.publish.completed); GNUNET_assert (1 == event->value.publish.anonymity); } else if (0 == strcmp ("publish-context2", event->value.publish.cctx)) { GNUNET_assert (0 == strcmp ("publish-context-dir", event->value.publish.pctx)); GNUNET_assert (FILESIZE == event->value.publish.size); GNUNET_assert (0 == event->value.publish.completed); GNUNET_assert (2 == event->value.publish.anonymity); } else if (0 == strcmp ("publish-context-dir", event->value.publish.cctx)) { GNUNET_assert (0 == event->value.publish.completed); GNUNET_assert (3 == event->value.publish.anonymity); } else GNUNET_assert (0); break; case GNUNET_FS_STATUS_PUBLISH_STOPPED: if (0 == strcmp ("publish-context-dir", event->value.publish.cctx)) GNUNET_assert (publish == event->value.publish.pc); break; default: printf ("Unexpected event: %d\n", event->status); break; } return ret; } static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE "-L", "DEBUG", #endif "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); } static void stop_arm (struct PeerContext *p) { #if START_ARM if (NULL != p->arm_proc) { if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; } #endif GNUNET_CONFIGURATION_destroy (p->cfg); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { const char *keywords[] = { "down_foo", "down_bar", }; char *buf; struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_FS_Uri *kuri; struct GNUNET_FS_FileInformation *fi1; struct GNUNET_FS_FileInformation *fi2; struct GNUNET_FS_FileInformation *fidir; size_t i; struct GNUNET_FS_BlockOptions bo; setup_peer (&p1, "test_fs_publish_data.conf"); fs = GNUNET_FS_start (cfg, "test-fs-publish", &progress_cb, NULL, GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); GNUNET_assert (NULL != fs); fn1 = GNUNET_DISK_mktemp ("gnunet-publish-test-dst"); buf = GNUNET_malloc (FILESIZE); for (i = 0; i < FILESIZE; i++) buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); GNUNET_assert (FILESIZE == GNUNET_DISK_fn_write (fn1, buf, FILESIZE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)); GNUNET_free (buf); fn2 = GNUNET_DISK_mktemp ("gnunet-publish-test-dst"); buf = GNUNET_malloc (FILESIZE); for (i = 0; i < FILESIZE; i++) buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); GNUNET_assert (FILESIZE == GNUNET_DISK_fn_write (fn2, buf, FILESIZE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)); GNUNET_free (buf); meta = GNUNET_CONTAINER_meta_data_create (); kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); bo.content_priority = 42; bo.anonymity_level = 1; bo.replication_level = 0; bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); fi1 = GNUNET_FS_file_information_create_from_file (fs, "publish-context1", fn1, kuri, meta, GNUNET_YES, &bo); GNUNET_assert (NULL != fi1); bo.anonymity_level = 2; fi2 = GNUNET_FS_file_information_create_from_file (fs, "publish-context2", fn2, kuri, meta, GNUNET_YES, &bo); GNUNET_assert (NULL != fi2); bo.anonymity_level = 3; fidir = GNUNET_FS_file_information_create_empty_directory (fs, "publish-context-dir", kuri, meta, &bo, NULL); GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi1)); GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi2)); GNUNET_FS_uri_destroy (kuri); GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_assert (NULL != fidir); start = GNUNET_TIME_absolute_get (); publish = GNUNET_FS_publish_start (fs, fidir, NULL, NULL, NULL, GNUNET_FS_PUBLISH_OPTION_NONE); GNUNET_assert (publish != NULL); } int main (int argc, char *argv[]) { char *const argvx[] = { "test-fs-publish", "-c", "test_fs_publish_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("test_fs_publish", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "test-fs-publish", "nohelp", options, &run, NULL); stop_arm (&p1); GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-publish/"); if (fn1 != NULL) { GNUNET_DISK_directory_remove (fn1); GNUNET_free (fn1); } if (fn2 != NULL) { GNUNET_DISK_directory_remove (fn2); GNUNET_free (fn2); } return err; } /* end of test_fs_publish.c */ gnunet-0.9.3/src/fs/test_gnunet_fs_psd.py.in0000644000175000017500000000736411760502552016034 00000000000000#!@PYTHON@ # This file is part of GNUnet. # (C) 2010 Christian Grothoff (and other contributing authors) # # GNUnet is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2, or (at your # option) any later version. # # GNUnet is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNUnet; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # Testcase for file-sharing command-line tools (publish, search, download) import sys import os import subprocess import re import shutil srcdir = "../.." gnunet_pyexpect_dir = os.path.join (srcdir, "contrib") if gnunet_pyexpect_dir not in sys.path: sys.path.append (gnunet_pyexpect_dir) from gnunet_pyexpect import pexpect if os.name == 'posix': download = 'gnunet-download' gnunetarm = 'gnunet-arm' publish = 'gnunet-publish' unindex = 'gnunet-unindex' search = 'gnunet-search' elif os.name == 'nt': download = 'gnunet-download.exe' gnunetarm = 'gnunet-arm.exe' publish = 'gnunet-publish.exe' unindex = 'gnunet-unindex.exe' search = 'gnunet-search.exe' if os.name == "nt": shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-psd"), True) else: shutil.rmtree ("/tmp/gnunet-test-fs-py-psd", True) arm = subprocess.Popen ([gnunetarm, '-sq', '-c', 'test_gnunet_fs_psd_data.conf']) arm.communicate () # first, basic publish-search-download run try: pub = pexpect () pub.spawn (None, [publish, '-c', 'test_gnunet_fs_psd_data.conf', '-n', '-m', "description:The GNU Public License", '-k', 'gpl', '../../COPYING'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pub.expect ("stdout", re.compile (r"Publishing `.+[\\/]..[\\/]..[\\/]COPYING' done\.\r?\n")) pub.expect ("stdout", re.compile (r"URI is `gnunet://fs/chk/PC0M19QMQC0BPSHR6BGA228PP6INER1D610MGEMOMEM87222FN8HVUO7PQGO0O9HD2GVLHF2N5IDHEQUNK6LKE428FPO96SKQEA486O\.PG7K85JGQ6N599MD5HEP3CHEVFPKQD9JB6NPSLVA3T1SKDS66CFI499VS6MGQ88B0QUAVT1282TCRD4GGFVUKDLGI8F0SPIANA3J2LG\.35147'\.\r?\n")) s = pexpect () s.spawn (None, [search, '-V', '-t', '1000', '-N', '1', '-c', 'test_gnunet_fs_psd_data.conf', 'gpl'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) s.expect ("stdout", re.compile (r'#0:\r?\n')) s.expect ("stdout", re.compile (r'gnunet-download -o "COPYING" gnunet://fs/chk/PC0M19QMQC0BPSHR6BGA228PP6INER1D610MGEMOMEM87222FN8HVUO7PQGO0O9HD2GVLHF2N5IDHEQUNK6LKE428FPO96SKQEA486O\.PG7K85JGQ6N599MD5HEP3CHEVFPKQD9JB6NPSLVA3T1SKDS66CFI499VS6MGQ88B0QUAVT1282TCRD4GGFVUKDLGI8F0SPIANA3J2LG\.35147\r?\n')) s.expect ("stdout", re.compile (r"\s*description: The GNU Public License\r?\n")) down = pexpect () down.spawn (None, [download, '-c', 'test_gnunet_fs_psd_data.conf', '-o', 'COPYING', 'gnunet://fs/chk/PC0M19QMQC0BPSHR6BGA228PP6INER1D610MGEMOMEM87222FN8HVUO7PQGO0O9HD2GVLHF2N5IDHEQUNK6LKE428FPO96SKQEA486O.PG7K85JGQ6N599MD5HEP3CHEVFPKQD9JB6NPSLVA3T1SKDS66CFI499VS6MGQ88B0QUAVT1282TCRD4GGFVUKDLGI8F0SPIANA3J2LG.35147'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) down.expect ("stdout", re.compile (r"Downloading `COPYING' done (.*).\r?\n")) os.remove ("COPYING") finally: arm = subprocess.Popen ([gnunetarm, '-eq', '-c', 'test_gnunet_fs_psd_data.conf']) arm.communicate () if os.name == "nt": shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-psd"), True) else: shutil.rmtree ("/tmp/gnunet-test-fs-py-psd", True) gnunet-0.9.3/src/fs/gnunet-unindex.c0000644000175000017500000001221611760502551014263 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-unindex.c * @brief unindex files published on GNUnet * @author Christian Grothoff * @author Krista Bennett * @author James Blackwell * @author Igor Wronsky */ #include "platform.h" #include "gnunet_fs_service.h" static int ret; static int verbose; static const struct GNUNET_CONFIGURATION_Handle *cfg; static struct GNUNET_FS_Handle *ctx; static struct GNUNET_FS_UnindexContext *uc; static void cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_FS_stop (ctx); ctx = NULL; } static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FS_UnindexContext *u; if (uc != NULL) { u = uc; uc = NULL; GNUNET_FS_unindex_stop (u); } } /** * Called by FS client to give information about the progress of an * operation. * * @param cls closure * @param info details about the event, specifying the event type * and various bits about the event * @return client-context (for the next progress call * for this operation; should be set to NULL for * SUSPEND and STOPPED events). The value returned * will be passed to future callbacks in the respective * field in the GNUNET_FS_ProgressInfo struct. */ static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info) { char *s; switch (info->status) { case GNUNET_FS_STATUS_UNINDEX_START: break; case GNUNET_FS_STATUS_UNINDEX_PROGRESS: if (verbose) { s = GNUNET_STRINGS_relative_time_to_string (info->value.unindex.eta); FPRINTF (stdout, _("Unindexing at %llu/%llu (%s remaining)\n"), (unsigned long long) info->value.unindex.completed, (unsigned long long) info->value.unindex.size, s); GNUNET_free (s); } break; case GNUNET_FS_STATUS_UNINDEX_ERROR: FPRINTF (stderr, _("Error unindexing: %s.\n"), info->value.unindex.specifics.error.message); GNUNET_SCHEDULER_shutdown (); break; case GNUNET_FS_STATUS_UNINDEX_COMPLETED: FPRINTF (stdout, "%s", _("Unindexing done.\n")); GNUNET_SCHEDULER_shutdown (); break; case GNUNET_FS_STATUS_UNINDEX_STOPPED: GNUNET_SCHEDULER_add_continuation (&cleanup_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; default: FPRINTF (stderr, _("Unexpected status: %d\n"), info->status); break; } return NULL; } /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param c configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { /* check arguments */ if ((args[0] == NULL) || (args[1] != NULL)) { printf (_("You must specify one and only one filename for unindexing.\n")); ret = -1; return; } cfg = c; ctx = GNUNET_FS_start (cfg, "gnunet-unindex", &progress_cb, NULL, GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); if (NULL == ctx) { FPRINTF (stderr, _("Could not initialize `%s' subsystem.\n"), "FS"); ret = 1; return; } uc = GNUNET_FS_unindex_start (ctx, args[0], NULL); if (NULL == uc) { FPRINTF (stderr, "%s", _("Could not start unindex operation.\n")); GNUNET_FS_stop (ctx); return; } GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); } /** * The main function to unindex content. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { {'V', "verbose", NULL, gettext_noop ("be verbose (print progress information)"), 0, &GNUNET_GETOPT_set_one, &verbose}, GNUNET_GETOPT_OPTION_END }; return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-unindex [OPTIONS] FILENAME", gettext_noop ("Unindex a file that was previously indexed with gnunet-publish."), options, &run, NULL)) ? ret : 1; } /* end of gnunet-unindex.c */ gnunet-0.9.3/src/fs/gnunet-service-fs_pr.h0000644000175000017500000002750211760502551015371 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-service-fs_pr.h * @brief API to handle pending requests * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_FS_PR_H #define GNUNET_SERVICE_FS_PR_H #include "gnunet-service-fs.h" /** * Options for pending requests (bits to be ORed). */ enum GSF_PendingRequestOptions { /** * No special options (P2P-default). */ GSF_PRO_DEFAULTS = 0, /** * Request must only be processed locally. */ GSF_PRO_LOCAL_ONLY = 1, /** * Request must only be forwarded (no routing) */ GSF_PRO_FORWARD_ONLY = 2, /** * Request persists indefinitely (no expiration). */ GSF_PRO_REQUEST_NEVER_EXPIRES = 4, /** * Request is allowed to refresh bloomfilter and change mingle value. */ GSF_PRO_BLOOMFILTER_FULL_REFRESH = 8, /** * Request priority is allowed to be exceeded. */ GSF_PRO_PRIORITY_UNLIMITED = 16, /** * Option mask for typical local requests. */ GSF_PRO_LOCAL_REQUEST = (GSF_PRO_BLOOMFILTER_FULL_REFRESH | GSF_PRO_PRIORITY_UNLIMITED | GSF_PRO_REQUEST_NEVER_EXPIRES) }; /** * Public data (in the sense of not encapsulated within * 'gnunet-service-fs_pr', not in the sense of network-wide * known) associated with each pending request. */ struct GSF_PendingRequestData { /** * Primary query hash for this request. */ GNUNET_HashCode query; /** * Namespace to query, only set if the type is SBLOCK. */ GNUNET_HashCode namespace; /** * Identity of a peer hosting the content, only set if * 'has_target' is GNUNET_YES. */ struct GNUNET_PeerIdentity target; /** * Fields for the plan module to track a DLL with the request. */ struct GSF_RequestPlanReference *rpr_head; /** * Fields for the plan module to track a DLL with the request. */ struct GSF_RequestPlanReference *rpr_tail; /** * Current TTL for the request. */ struct GNUNET_TIME_Absolute ttl; /** * When did we start with the request. */ struct GNUNET_TIME_Absolute start_time; /** * Desired anonymity level. */ uint32_t anonymity_level; /** * Priority that this request (still) has for us. */ uint32_t priority; /** * Priority that this request (originally) had for us. */ uint32_t original_priority; /** * Options for the request. */ enum GSF_PendingRequestOptions options; /** * Type of the requested block. */ enum GNUNET_BLOCK_Type type; /** * Number of results we have found for this request so far. */ unsigned int results_found; /** * Is the 'target' value set to a valid peer identity? */ int has_target; /** * Has this request been started yet (local/p2p operations)? Or are * we still constructing it? */ int has_started; }; /** * Handle a reply to a pending request. Also called if a request * expires (then with data == NULL). The handler may be called * many times (depending on the request type), but will not be * called during or after a call to GSF_pending_request_cancel * and will also not be called anymore after a call signalling * expiration. * * @param cls user-specified closure * @param eval evaluation of the result * @param pr handle to the original pending request * @param reply_anonymity_level anonymity level for the reply, UINT32_MAX for "unknown" * @param expiration when does 'data' expire? * @param last_transmission the last time we've tried to get this block (FOREVER if unknown) * @param type type of the block * @param data response data, NULL on request expiration * @param data_len number of bytes in data */ typedef void (*GSF_PendingRequestReplyHandler) (void *cls, enum GNUNET_BLOCK_EvaluationResult eval, struct GSF_PendingRequest * pr, uint32_t reply_anonymity_level, struct GNUNET_TIME_Absolute expiration, struct GNUNET_TIME_Absolute last_transmission, enum GNUNET_BLOCK_Type type, const void *data, size_t data_len); /** * Create a new pending request. * * @param options request options * @param type type of the block that is being requested * @param query key for the lookup * @param namespace namespace to lookup, NULL for no namespace * @param target preferred target for the request, NULL for none * @param bf_data raw data for bloom filter for known replies, can be NULL * @param bf_size number of bytes in bf_data * @param mingle mingle value for bf * @param anonymity_level desired anonymity level * @param priority maximum outgoing cummulative request priority to use * @param ttl current time-to-live for the request * @param sender_pid peer ID to use for the sender when forwarding, 0 for none; * reference counter is taken over by this function * @param origin_pid peer ID of origin of query (do not loop back) * @param replies_seen hash codes of known local replies * @param replies_seen_count size of the 'replies_seen' array * @param rh handle to call when we get a reply * @param rh_cls closure for rh * @return handle for the new pending request */ struct GSF_PendingRequest * GSF_pending_request_create_ (enum GSF_PendingRequestOptions options, enum GNUNET_BLOCK_Type type, const GNUNET_HashCode * query, const GNUNET_HashCode * namespace, const struct GNUNET_PeerIdentity *target, const char *bf_data, size_t bf_size, uint32_t mingle, uint32_t anonymity_level, uint32_t priority, int32_t ttl, GNUNET_PEER_Id sender_pid, GNUNET_PEER_Id origin_pid, const GNUNET_HashCode * replies_seen, unsigned int replies_seen_count, GSF_PendingRequestReplyHandler rh, void *rh_cls); /** * Update a given pending request with additional replies * that have been seen. * * @param pr request to update * @param replies_seen hash codes of replies that we've seen * @param replies_seen_count size of the replies_seen array */ void GSF_pending_request_update_ (struct GSF_PendingRequest *pr, const GNUNET_HashCode * replies_seen, unsigned int replies_seen_count); /** * Obtain the public data associated with a pending request * * @param pr pending request * @return associated public data */ struct GSF_PendingRequestData * GSF_pending_request_get_data_ (struct GSF_PendingRequest *pr); /** * Test if two pending requests are compatible (would generate * the same query modulo filters and should thus be processed * jointly). * * @param pra a pending request * @param prb another pending request * @return GNUNET_OK if the requests are compatible */ int GSF_pending_request_is_compatible_ (struct GSF_PendingRequest *pra, struct GSF_PendingRequest *prb); /** * Generate the message corresponding to the given pending request for * transmission to other peers (or at least determine its size). * * @param pr request to generate the message for * @param buf_size number of bytes available in buf * @param buf where to copy the message (can be NULL) * @return number of bytes needed (if buf_size too small) or used */ size_t GSF_pending_request_get_message_ (struct GSF_PendingRequest *pr, size_t buf_size, void *buf); /** * Explicitly cancel a pending request. * * @param pr request to cancel * @param full_cleanup fully purge the request */ void GSF_pending_request_cancel_ (struct GSF_PendingRequest *pr, int full_cleanup); /** * Signature of function called on each request. * (Note: 'subtype' of GNUNET_CONTAINER_HashMapIterator). * * @param cls closure * @param key query for the request * @param pr handle to the pending request * @return GNUNET_YES to continue to iterate */ typedef int (*GSF_PendingRequestIterator) (void *cls, const GNUNET_HashCode * key, struct GSF_PendingRequest * pr); /** * Iterate over all pending requests. * * @param it function to call for each request * @param cls closure for it */ void GSF_iterate_pending_requests_ (GSF_PendingRequestIterator it, void *cls); /** * Handle P2P "CONTENT" message. Checks that the message is * well-formed and then checks if there are any pending requests for * this content and possibly passes it on (to local clients or other * peers). Does NOT perform migration (content caching at this peer). * * @param cp the other peer involved (sender or receiver, NULL * for loopback messages where we are both sender and receiver) * @param message the actual message * @return GNUNET_OK if the message was well-formed, * GNUNET_SYSERR if the message was malformed (close connection, * do not cache under any circumstances) */ int GSF_handle_p2p_content_ (struct GSF_ConnectedPeer *cp, const struct GNUNET_MessageHeader *message); /** * Consider looking up the data in the DHT (anonymity-level permitting). * * @param pr the pending request to process */ void GSF_dht_lookup_ (struct GSF_PendingRequest *pr); /** * Function to be called after we're done processing * replies from the local lookup. * * @param cls closure * @param pr the pending request we were processing * @param result final datastore lookup result */ typedef void (*GSF_LocalLookupContinuation) (void *cls, struct GSF_PendingRequest * pr, enum GNUNET_BLOCK_EvaluationResult result); /** * Look up the request in the local datastore. * * @param pr the pending request to process * @param cont function to call at the end * @param cont_cls closure for cont */ void GSF_local_lookup_ (struct GSF_PendingRequest *pr, GSF_LocalLookupContinuation cont, void *cont_cls); /** * Is the given target a legitimate peer for forwarding the given request? * * @param pr request * @param target * @return GNUNET_YES if this request could be forwarded to the given peer */ int GSF_pending_request_test_target_ (struct GSF_PendingRequest *pr, const struct GNUNET_PeerIdentity *target); /** * Setup the subsystem. */ void GSF_pending_request_init_ (void); /** * Shutdown the subsystem. */ void GSF_pending_request_done_ (void); #endif /* end of gnunet-service-fs_pr.h */ gnunet-0.9.3/src/fs/test_gnunet_service_fs_p2p.c0000644000175000017500000001174011760502551016644 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/test_gnunet_service_fs_p2p.c * @brief test P2P routing using simple publish + download operation * @author Christian Grothoff */ #include "platform.h" #include "fs_test_lib.h" #define VERBOSE GNUNET_NO /** * File-size we use for testing. */ #define FILESIZE (1024 * 1024 * 1) /** * How long until we give up on the download? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) #define NUM_DAEMONS 2 #define SEED 42 static struct GNUNET_FS_TestDaemon *daemons[NUM_DAEMONS]; static int ok; static struct GNUNET_TIME_Absolute start_time; static struct GNUNET_FS_TEST_ConnectContext *cc; static void do_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TIME_Relative del; char *fancy; if (NULL != cc) { GNUNET_FS_TEST_daemons_connect_cancel (cc); cc = NULL; } GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons); if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) { del = GNUNET_TIME_absolute_get_duration (start_time); if (del.rel_value == 0) del.rel_value = 1; fancy = GNUNET_STRINGS_byte_size_fancy (((unsigned long long) FILESIZE) * 1000LL / del.rel_value); FPRINTF (stdout, "Download speed was %s/s\n", fancy); GNUNET_free (fancy); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished download, shutting down\n", (unsigned long long) FILESIZE); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout during download, shutting down with error\n"); ok = 1; } } static void do_download (void *cls, const struct GNUNET_FS_Uri *uri) { if (NULL == uri) { GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout during upload attempt, shutting down with error\n"); ok = 1; return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Downloading %llu bytes\n", (unsigned long long) FILESIZE); start_time = GNUNET_TIME_absolute_get (); GNUNET_FS_TEST_download (daemons[0], TIMEOUT, 1, SEED, uri, VERBOSE, &do_stop, NULL); } static void do_publish (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { cc = NULL; if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) { GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout during connect attempt, shutting down with error\n"); ok = 1; return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing %llu bytes\n", (unsigned long long) FILESIZE); GNUNET_FS_TEST_publish (daemons[1], TIMEOUT, 1, GNUNET_NO, FILESIZE, SEED, VERBOSE, &do_download, NULL); } static void do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_assert (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemons started, will now try to connect them\n"); cc = GNUNET_FS_TEST_daemons_connect (daemons[0], daemons[1], TIMEOUT, &do_publish, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { GNUNET_FS_TEST_daemons_start ("fs_test_lib_data.conf", TIMEOUT, NUM_DAEMONS, daemons, &do_connect, NULL); } int main (int argc, char *argv[]) { char *const argvx[] = { "test-gnunet-service-fs-p2p", "-c", "fs_test_lib_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/"); GNUNET_log_setup ("test_gnunet_service_fs_p2p", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "test-gnunet-service-fs-p2p", "nohelp", options, &run, NULL); GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/"); return ok; } /* end of test_gnunet_service_fs_p2p.c */ gnunet-0.9.3/src/fs/Makefile.am0000644000175000017500000003166111762221424013207 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIB = -lgcov endif pkgcfgdir= $(pkgdatadir)/config.d/ pkgcfg_DATA = \ fs.conf plugindir = $(libdir)/gnunet lib_LTLIBRARIES = libgnunetfs.la plugin_LTLIBRARIES = \ libgnunet_plugin_block_fs.la noinst_LIBRARIES = libgnunetfstest.a libgnunetfs_la_SOURCES = \ fs_api.c fs_api.h fs.h \ fs_directory.c \ fs_dirmetascan.c \ fs_download.c \ fs_file_information.c \ fs_getopt.c \ fs_list_indexed.c \ fs_publish.c \ fs_publish_ksk.c \ fs_misc.c \ fs_namespace.c \ fs_namespace_advertise.c \ fs_search.c \ fs_sharetree.c \ fs_tree.c fs_tree.h \ fs_unindex.c \ fs_uri.c libgnunetfs_la_LIBADD = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) $(XLIB) -lunistring -lextractor libgnunetfs_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 2:1:0 libgnunetfstest_a_SOURCES = \ fs_test_lib.c fs_test_lib.h libgnunetfstest_a_LIBADD = \ $(top_builddir)/src/testing/libgnunettesting.la bin_PROGRAMS = \ gnunet-directory \ gnunet-download \ gnunet-publish \ gnunet-helper-fs-publish \ gnunet-pseudonym \ gnunet-search \ gnunet-service-fs \ gnunet-fs \ gnunet-unindex bin_SCRIPTS = \ gnunet-download-manager.scm gnunet_directory_SOURCES = \ gnunet-directory.c gnunet_directory_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la \ -lextractor \ $(GN_LIBINTL) gnunet_directory_DEPENDENCIES = \ libgnunetfs.la gnunet_fs_SOURCES = \ gnunet-fs.c gnunet_fs_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la \ -lextractor \ $(GN_LIBINTL) gnunet_fs_DEPENDENCIES = \ libgnunetfs.la gnunet_download_SOURCES = \ gnunet-download.c gnunet_download_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_download_DEPENDENCIES = \ libgnunetfs.la gnunet_publish_SOURCES = \ gnunet-publish.c gnunet_publish_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la \ -lextractor \ $(GN_LIBINTL) gnunet_publish_DEPENDENCIES = \ libgnunetfs.la gnunet_helper_fs_publish_SOURCES = \ gnunet-helper-fs-publish.c gnunet_helper_fs_publish_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ -lextractor \ $(GN_LIBINTL) gnunet_helper_fs_publish_DEPENDENCIES = \ libgnunetfs.la gnunet_pseudonym_SOURCES = \ gnunet-pseudonym.c gnunet_pseudonym_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la \ -lextractor \ $(GN_LIBINTL) gnunet_pseudonym_DEPENDENCIES = \ libgnunetfs.la gnunet_search_SOURCES = \ gnunet-search.c gnunet_search_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la \ -lextractor \ $(GN_LIBINTL) gnunet_search_DEPENDENCIES = \ libgnunetfs.la gnunet_service_fs_SOURCES = \ gnunet-service-fs.c gnunet-service-fs.h \ gnunet-service-fs_cp.c gnunet-service-fs_cp.h \ gnunet-service-fs_indexing.c gnunet-service-fs_indexing.h \ gnunet-service-fs_lc.c gnunet-service-fs_lc.h \ gnunet-service-fs_pe.c gnunet-service-fs_pe.h \ gnunet-service-fs_pr.c gnunet-service-fs_pr.h \ gnunet-service-fs_push.c gnunet-service-fs_push.h \ gnunet-service-fs_put.c gnunet-service-fs_put.h gnunet_service_fs_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/block/libgnunetblock.la \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/ats/libgnunetats.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) -lm gnunet_service_fs_DEPENDENCIES = \ libgnunetfs.la gnunet_unindex_SOURCES = \ gnunet-unindex.c gnunet_unindex_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_unindex_DEPENDENCIES = \ libgnunetfs.la libgnunet_plugin_block_fs_la_SOURCES = \ plugin_block_fs.c libgnunet_plugin_block_fs_la_LIBADD = \ $(top_builddir)/src/block/libgnunetblock.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_block_fs_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_block_fs_la_DEPENDENCIES = \ $(top_builddir)/src/block/libgnunetblock.la if HAVE_BENCHMARKS FS_BENCHMARKS = \ perf_gnunet_service_fs_p2p \ perf_gnunet_service_fs_p2p_dht \ perf_gnunet_service_fs_p2p_index \ perf_gnunet_service_fs_p2p_trust endif check_PROGRAMS = \ test_fs_directory \ test_fs_download \ test_fs_download_indexed \ test_fs_download_persistence \ test_fs_file_information \ test_fs_getopt \ test_fs_list_indexed \ test_fs_namespace \ test_fs_namespace_list_updateable \ test_fs_publish \ test_fs_publish_persistence \ test_fs_search \ test_fs_search_probes \ test_fs_search_persistence \ test_fs_start_stop \ test_fs_test_lib \ test_fs_unindex \ test_fs_unindex_persistence \ test_fs_uri \ test_gnunet_service_fs_migration \ test_gnunet_service_fs_p2p \ $(FS_BENCHMARKS) if HAVE_PYTHON_PEXPECT check_SCRIPTS = \ test_gnunet_fs_psd.py \ test_gnunet_fs_rec.py \ test_gnunet_fs_idx.py \ test_gnunet_fs_ns.py endif if ENABLE_MONKEY TESTS_ENVIRONMENT = @MONKEYPREFIX@ AM_LDFLAGS = -no-install endif if ENABLE_TEST_RUN TESTS = \ test_fs_directory \ test_fs_download \ test_fs_download_indexed \ test_fs_download_persistence \ test_fs_file_information \ test_fs_list_indexed \ test_fs_namespace \ test_fs_namespace_list_updateable \ test_fs_publish \ test_fs_publish_persistence \ test_fs_search \ test_fs_search_probes \ test_fs_search_persistence \ test_fs_start_stop \ test_fs_unindex \ test_fs_unindex_persistence \ test_fs_uri \ test_fs_test_lib \ test_gnunet_service_fs_migration \ test_gnunet_service_fs_p2p \ perf_gnunet_service_fs_p2p \ perf_gnunet_service_fs_p2p_index \ perf_gnunet_service_fs_p2p_trust \ $(check_SCRIPTS) endif test_fs_directory_SOURCES = \ test_fs_directory.c test_fs_directory_LDADD = \ -lextractor \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_download_SOURCES = \ test_fs_download.c test_fs_download_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_download_indexed_SOURCES = \ test_fs_download_indexed.c test_fs_download_indexed_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_download_persistence_SOURCES = \ test_fs_download_persistence.c test_fs_download_persistence_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_file_information_SOURCES = \ test_fs_file_information.c test_fs_file_information_LDADD = \ -lextractor \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_getopt_SOURCES = \ test_fs_getopt.c test_fs_getopt_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_list_indexed_SOURCES = \ test_fs_list_indexed.c test_fs_list_indexed_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_namespace_SOURCES = \ test_fs_namespace.c test_fs_namespace_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_namespace_list_updateable_SOURCES = \ test_fs_namespace_list_updateable.c test_fs_namespace_list_updateable_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_publish_SOURCES = \ test_fs_publish.c test_fs_publish_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_publish_persistence_SOURCES = \ test_fs_publish_persistence.c test_fs_publish_persistence_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_search_SOURCES = \ test_fs_search.c test_fs_search_LDADD = $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_search_probes_SOURCES = \ test_fs_search_probes.c test_fs_search_probes_LDADD = $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_search_persistence_SOURCES = \ test_fs_search_persistence.c test_fs_search_persistence_LDADD = $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_start_stop_SOURCES = \ test_fs_start_stop.c test_fs_start_stop_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_unindex_SOURCES = \ test_fs_unindex.c test_fs_unindex_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_unindex_persistence_SOURCES = \ test_fs_unindex_persistence.c test_fs_unindex_persistence_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_uri_SOURCES = \ test_fs_uri.c test_fs_uri_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_test_lib_SOURCES = \ test_fs_test_lib.c test_fs_test_lib_LDADD = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_gnunet_service_fs_p2p_SOURCES = \ test_gnunet_service_fs_p2p.c test_gnunet_service_fs_p2p_LDADD = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_gnunet_service_fs_migration_SOURCES = \ test_gnunet_service_fs_migration.c test_gnunet_service_fs_migration_LDADD = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la perf_gnunet_service_fs_p2p_SOURCES = \ perf_gnunet_service_fs_p2p.c perf_gnunet_service_fs_p2p_LDADD = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la perf_gnunet_service_fs_p2p_index_SOURCES = \ perf_gnunet_service_fs_p2p.c perf_gnunet_service_fs_p2p_index_LDADD = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la perf_gnunet_service_fs_p2p_dht_SOURCES = \ perf_gnunet_service_fs_p2p.c perf_gnunet_service_fs_p2p_dht_LDADD = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la perf_gnunet_service_fs_p2p_trust_SOURCES = \ perf_gnunet_service_fs_p2p_trust.c perf_gnunet_service_fs_p2p_trust_LDADD = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' test_gnunet_fs_psd.py: test_gnunet_fs_psd.py.in Makefile $(do_subst) < $(srcdir)/test_gnunet_fs_psd.py.in > test_gnunet_fs_psd.py chmod +x test_gnunet_fs_psd.py test_gnunet_fs_rec.py: test_gnunet_fs_rec.py.in Makefile $(do_subst) < $(srcdir)/test_gnunet_fs_rec.py.in > test_gnunet_fs_rec.py chmod +x test_gnunet_fs_rec.py test_gnunet_fs_ns.py: test_gnunet_fs_ns.py.in Makefile $(do_subst) < $(srcdir)/test_gnunet_fs_ns.py.in > test_gnunet_fs_ns.py chmod +x test_gnunet_fs_ns.py test_gnunet_fs_idx.py: test_gnunet_fs_idx.py.in Makefile $(do_subst) < $(srcdir)/test_gnunet_fs_idx.py.in > test_gnunet_fs_idx.py chmod +x test_gnunet_fs_idx.py EXTRA_DIST = \ test_fs_defaults.conf \ fs_test_lib_data.conf \ test_fs_data.conf \ test_fs_download_data.conf \ test_fs_file_information_data.conf \ fs_test_lib_data.conf \ test_fs_list_indexed_data.conf \ test_fs_namespace_data.conf \ test_fs_publish_data.conf \ test_fs_search_data.conf \ test_fs_unindex_data.conf \ test_fs_uri_data.conf \ test_gnunet_service_fs_migration_data.conf \ test_gnunet_fs_idx_data.conf \ test_gnunet_fs_ns_data.conf \ test_gnunet_fs_psd_data.conf \ test_gnunet_fs_rec_data.conf \ test_gnunet_fs_rec_data.tgz \ test_gnunet_fs_psd.py.in \ test_gnunet_fs_rec.py.in \ test_gnunet_fs_ns.py.in \ test_gnunet_fs_idx.py.in \ $(bin_SCRIPTS) CLEANFILES = $(check_SCRIPTS) gnunet-0.9.3/src/fs/gnunet-pseudonym.c0000644000175000017500000002053411760502551014636 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-pseudonym.c * @brief manage GNUnet namespaces / pseudonyms * @author Christian Grothoff */ #include "platform.h" #include "gnunet_fs_service.h" /** * -C option */ static char *create_ns; /** * -D option */ static char *delete_ns; /** * -k option */ static struct GNUNET_FS_Uri *ksk_uri; /** * -l option. */ static int print_local_only; /** * -m option. */ static struct GNUNET_CONTAINER_MetaData *adv_metadata; /** * Our block options (-p, -r, -a). */ static struct GNUNET_FS_BlockOptions bo = { {0LL}, 1, 365, 1 }; /** * -q option given. */ static int no_remote_printing; /** * -r option. */ static char *root_identifier; /** * -s option. */ static char *rating_change; /** * Handle to fs service. */ static struct GNUNET_FS_Handle *h; /** * Namespace we are looking at. */ static struct GNUNET_FS_Namespace *ns; /** * Our configuration. */ static const struct GNUNET_CONFIGURATION_Handle *cfg; static int ret; static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info) { return NULL; } static void ns_printer (void *cls, const char *name, const GNUNET_HashCode * id) { struct GNUNET_CRYPTO_HashAsciiEncoded enc; GNUNET_CRYPTO_hash_to_enc (id, &enc); FPRINTF (stdout, "%s (%s)\n", name, (const char *) &enc); } static int pseudo_printer (void *cls, const GNUNET_HashCode * pseudonym, const char *name, const char *unique_name, const struct GNUNET_CONTAINER_MetaData *md, int rating) { char *id; char *unique_id; int getinfo_result; /* While we get a name from the caller, it might be NULL. * GNUNET_PSEUDONYM_get_info () never returns NULL. */ getinfo_result = GNUNET_PSEUDONYM_get_info (cfg, pseudonym, NULL, NULL, &id, NULL); if (getinfo_result != GNUNET_OK) { GNUNET_break (0); return GNUNET_OK; } unique_id = GNUNET_PSEUDONYM_name_uniquify (cfg, pseudonym, id, NULL); GNUNET_free (id); FPRINTF (stdout, "%s (%d):\n", unique_id, rating); GNUNET_CONTAINER_meta_data_iterate (md, &EXTRACTOR_meta_data_print, stdout); FPRINTF (stdout, "%s", "\n"); GNUNET_free (unique_id); return GNUNET_OK; } static void post_advertising (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) { GNUNET_HashCode nsid; char *set; int delta; if (emsg != NULL) { FPRINTF (stderr, "%s", emsg); ret = 1; } if (ns != NULL) { if (GNUNET_OK != GNUNET_FS_namespace_delete (ns, GNUNET_NO)) ret = 1; } if (NULL != rating_change) { set = rating_change; while ((*set != '\0') && (*set != ':')) set++; if (*set != ':') { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Invalid argument `%s'\n"), rating_change); } else { *set = '\0'; delta = strtol (&set[1], NULL, /* no error handling yet */ 10); if (GNUNET_OK == GNUNET_PSEUDONYM_name_to_id (cfg, rating_change, &nsid)) { (void) GNUNET_PSEUDONYM_rank (cfg, &nsid, delta); } else { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, ("Namespace `%s' unknown. Make sure you specify its numeric suffix, if any.\n"), rating_change); } } GNUNET_free (rating_change); rating_change = NULL; } if (0 != print_local_only) { GNUNET_FS_namespace_list (h, &ns_printer, NULL); } else if (0 == no_remote_printing) { GNUNET_PSEUDONYM_list_all (cfg, &pseudo_printer, NULL); } GNUNET_FS_stop (h); } /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param c configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { char *emsg; cfg = c; h = GNUNET_FS_start (cfg, "gnunet-pseudonym", &progress_cb, NULL, GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); if (NULL != delete_ns) { ns = GNUNET_FS_namespace_create (h, delete_ns); if (ns == NULL) { ret = 1; } else { if (GNUNET_OK != GNUNET_FS_namespace_delete (ns, GNUNET_YES)) ret = 1; ns = NULL; } } if (NULL != create_ns) { ns = GNUNET_FS_namespace_create (h, create_ns); if (ns == NULL) { ret = 1; } else { if (NULL != root_identifier) { if (ksk_uri == NULL) { emsg = NULL; ksk_uri = GNUNET_FS_uri_parse ("gnunet://fs/ksk/namespace", &emsg); GNUNET_assert (NULL == emsg); } GNUNET_FS_namespace_advertise (h, ksk_uri, ns, adv_metadata, &bo, root_identifier, &post_advertising, NULL); return; } else { if (ksk_uri != NULL) FPRINTF (stderr, _("Option `%s' ignored\n"), "-k"); } } } else { if (root_identifier != NULL) FPRINTF (stderr, _("Option `%s' ignored\n"), "-r"); if (ksk_uri != NULL) FPRINTF (stderr, _("Option `%s' ignored\n"), "-k"); } post_advertising (NULL, NULL, NULL); } /** * The main function to manipulate GNUnet pseudonyms (and publish * to namespaces). * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { {'a', "anonymity", "LEVEL", gettext_noop ("set the desired LEVEL of sender-anonymity"), 1, &GNUNET_GETOPT_set_uint, &bo.anonymity_level}, {'C', "create", "NAME", gettext_noop ("create or advertise namespace NAME"), 1, &GNUNET_GETOPT_set_string, &create_ns}, {'D', "delete", "NAME", gettext_noop ("delete namespace NAME "), 1, &GNUNET_GETOPT_set_string, &delete_ns}, {'k', "keyword", "VALUE", gettext_noop ("add an additional keyword for the advertisment" " (this option can be specified multiple times)"), 1, &GNUNET_FS_getopt_set_keywords, &ksk_uri}, {'m', "meta", "TYPE:VALUE", gettext_noop ("set the meta-data for the given TYPE to the given VALUE"), 1, &GNUNET_FS_getopt_set_metadata, &adv_metadata}, {'o', "only-local", NULL, gettext_noop ("print names of local namespaces"), 0, &GNUNET_GETOPT_set_one, &print_local_only}, {'p', "priority", "PRIORITY", gettext_noop ("use the given PRIORITY for the advertisments"), 1, &GNUNET_GETOPT_set_uint, &bo.content_priority}, {'q', "quiet", NULL, gettext_noop ("do not print names of remote namespaces"), 0, &GNUNET_GETOPT_set_one, &no_remote_printing}, {'r', "replication", "LEVEL", gettext_noop ("set the desired replication LEVEL"), 1, &GNUNET_GETOPT_set_uint, &bo.replication_level}, {'R', "root", "ID", gettext_noop ("specify ID of the root of the namespace"), 1, &GNUNET_GETOPT_set_string, &root_identifier}, {'s', "set-rating", "ID:VALUE", gettext_noop ("change rating of namespace ID by VALUE"), 1, &GNUNET_GETOPT_set_string, &rating_change}, GNUNET_GETOPT_OPTION_END }; bo.expiration_time = GNUNET_FS_year_to_time (GNUNET_FS_get_current_year () + 2); return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-pseudonym [OPTIONS]", gettext_noop ("Manage GNUnet pseudonyms."), options, &run, NULL)) ? ret : 1; } /* end of gnunet-pseudonym.c */ gnunet-0.9.3/src/fs/fs_api.h0000644000175000017500000013010411760502551012556 00000000000000/* This file is part of GNUnet. (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs_api.h * @brief shared definitions for the FS library * @author Igor Wronsky, Christian Grothoff */ #ifndef FS_API_H #define FS_API_H #include "gnunet_constants.h" #include "gnunet_datastore_service.h" #include "gnunet_dht_service.h" #include "gnunet_fs_service.h" #include "gnunet_block_lib.h" #include "block_fs.h" #include "fs.h" /** * Size of the individual blocks used for file-sharing. */ #define DBLOCK_SIZE (32*1024) /** * Pick a multiple of 2 here to achive 8-byte alignment! We also * probably want DBlocks to have (roughly) the same size as IBlocks. * With SHA-512, the optimal value is 32768 byte / 128 byte = 256 (128 * byte = 2 * 512 bits). DO NOT CHANGE! */ #define CHK_PER_INODE 256 /** * Maximum size for a file to be considered for inlining in a * directory. */ #define MAX_INLINE_SIZE 65536 /** * Name of the directory with top-level searches. */ #define GNUNET_FS_SYNC_PATH_MASTER_SEARCH "search" /** * Name of the directory with sub-searches (namespace-updates). */ #define GNUNET_FS_SYNC_PATH_CHILD_SEARCH "search-child" /** * Name of the directory with master downloads (not associated * with search or part of another download). */ #define GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD "download" /** * Name of the directory with downloads that are part of another * download or a search. */ #define GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD "download-child" /** * Name of the directory with publishing operations. */ #define GNUNET_FS_SYNC_PATH_MASTER_PUBLISH "publish" /** * Name of the directory with files that are being published */ #define GNUNET_FS_SYNC_PATH_FILE_INFO "publish-file" /** * Name of the directory with unindex operations. */ #define GNUNET_FS_SYNC_PATH_MASTER_UNINDEX "unindex" /** * @brief complete information needed * to download a file. */ struct FileIdentifier { /** * Total size of the file in bytes. (network byte order (!)) */ uint64_t file_length; /** * Query and key of the top GNUNET_EC_IBlock. */ struct ContentHashKey chk; }; /** * Information about a file and its location * (peer claiming to share the file). */ struct Location { /** * Information about the shared file. */ struct FileIdentifier fi; /** * Identity of the peer sharing the file. */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded peer; /** * Time when this location URI expires. */ struct GNUNET_TIME_Absolute expirationTime; /** * RSA signature over the GNUNET_EC_FileIdentifier, * GNUNET_hash of the peer and expiration time. */ struct GNUNET_CRYPTO_RsaSignature contentSignature; }; /** * Types of URIs. */ enum uri_types { /** * Content-hash-key (simple file). */ chk, /** * Signed key space (file in namespace). */ sks, /** * Keyword search key (query with keywords). */ ksk, /** * Location (chk with identity of hosting peer). */ loc }; /** * A Universal Resource Identifier (URI), opaque. */ struct GNUNET_FS_Uri { /** * Type of the URI. */ enum uri_types type; union { struct { /** * Keywords start with a '+' if they are * mandatory (in which case the '+' is NOT * part of the keyword) and with a * simple space if they are optional * (in which case the space is ALSO not * part of the actual keyword). * * Double-quotes to protect spaces and * %-encoding are NOT used internally * (only in URI-strings). */ char **keywords; /** * Size of the keywords array. */ unsigned int keywordCount; } ksk; struct { /** * Hash of the public key for the namespace. */ GNUNET_HashCode namespace; /** * Human-readable identifier chosen for this * entry in the namespace. */ char *identifier; } sks; /** * Information needed to retrieve a file (content-hash-key * plus file size). */ struct FileIdentifier chk; /** * Information needed to retrieve a file including signed * location (identity of a peer) of the content. */ struct Location loc; } data; }; /** * Information for a file or directory that is * about to be published. */ struct GNUNET_FS_FileInformation { /** * Files in a directory are kept as a linked list. */ struct GNUNET_FS_FileInformation *next; /** * If this is a file in a directory, "dir" refers to * the directory; otherwise NULL. */ struct GNUNET_FS_FileInformation *dir; /** * Handle to the master context. */ struct GNUNET_FS_Handle *h; /** * Pointer kept for the client. */ void *client_info; /** * Metadata to use for the file. */ struct GNUNET_CONTAINER_MetaData *meta; /** * Keywords to use for KBlocks. */ struct GNUNET_FS_Uri *keywords; /** * CHK for this file or directory. NULL if * we have not yet computed it. */ struct GNUNET_FS_Uri *chk_uri; /** * Block options for the file. */ struct GNUNET_FS_BlockOptions bo; /** * At what time did we start this upload? */ struct GNUNET_TIME_Absolute start_time; /** * Under what filename is this struct serialized * (for operational persistence). Should be determined * using 'mktemp'. */ char *serialization; /** * Encoder being used to publish this file. */ struct GNUNET_FS_TreeEncoder *te; /** * Error message (non-NULL if this operation failed). */ char *emsg; /** * Name of the file or directory (must be an absolute path). */ char *filename; /** * Data describing either the file or the directory. */ union { /** * Data for a file. */ struct { /** * Function that can be used to read the data for the file. */ GNUNET_FS_DataReader reader; /** * Closure for reader. */ void *reader_cls; /** * If this file is being indexed, this value is set to the hash * over the entire file (when the indexing process is started). * Otherwise this field is not used. */ GNUNET_HashCode file_id; /** * Size of the file (in bytes). */ uint64_t file_size; /** * Should the file be indexed or inserted? */ int do_index; /** * Is "file_id" already valid? Set to GNUNET_YES once the hash * has been calculated. */ int have_hash; /** * Has the service confirmed our INDEX_START request? * GNUNET_YES if this step has been completed. */ int index_start_confirmed; } file; /** * Data for a directory. */ struct { /** * Linked list of entries in the directory. */ struct GNUNET_FS_FileInformation *entries; /** * Size of the directory itself (in bytes); 0 if the * size has not yet been calculated. */ size_t dir_size; /** * Pointer to the data for the directory (or NULL if not * available). */ void *dir_data; } dir; } data; /** * Is this struct for a file or directory? */ int is_directory; /** * Are we done publishing this file? */ int is_published; }; /** * The job is now ready to run and should use the given client * handle to communicate with the FS service. * * @param cls closure * @param client handle to use for FS communication */ typedef void (*GNUNET_FS_QueueStart) (void *cls, struct GNUNET_CLIENT_Connection * client); /** * The job must now stop to run and should destry the client handle as * soon as possible (ideally prior to returning). */ typedef void (*GNUNET_FS_QueueStop) (void *cls); /** * Priorities for the queue. */ enum GNUNET_FS_QueuePriority { /** * This is a probe (low priority). */ GNUNET_FS_QUEUE_PRIORITY_PROBE, /** * Default priority. */ GNUNET_FS_QUEUE_PRIORITY_NORMAL }; /** * Entry in the job queue. */ struct GNUNET_FS_QueueEntry { /** * This is a linked list. */ struct GNUNET_FS_QueueEntry *next; /** * This is a linked list. */ struct GNUNET_FS_QueueEntry *prev; /** * Function to call when the job is started. */ GNUNET_FS_QueueStart start; /** * Function to call when the job needs to stop (or is done / dequeued). */ GNUNET_FS_QueueStop stop; /** * Closure for start and stop. */ void *cls; /** * Handle to FS primary context. */ struct GNUNET_FS_Handle *h; /** * Client handle, or NULL if job is not running. */ struct GNUNET_CLIENT_Connection *client; /** * Time the job was originally queued. */ struct GNUNET_TIME_Absolute queue_time; /** * Time the job was started last. */ struct GNUNET_TIME_Absolute start_time; /** * Total amount of time the job has been running (except for the * current run). */ struct GNUNET_TIME_Relative run_time; /** * How many blocks do the active downloads have? */ unsigned int blocks; /** * How important is this download? */ enum GNUNET_FS_QueuePriority priority; /** * How often have we (re)started this download? */ unsigned int start_times; }; /** * Information we store for each search result. */ struct GNUNET_FS_SearchResult { /** * Search context this result belongs to. */ struct GNUNET_FS_SearchContext *sc; /** * URI to which this search result refers to. */ struct GNUNET_FS_Uri *uri; /** * Metadata for the search result. */ struct GNUNET_CONTAINER_MetaData *meta; /** * Client info for this search result. */ void *client_info; /** * ID of a job that is currently probing this results' availability * (NULL if we are not currently probing). */ struct GNUNET_FS_DownloadContext *probe_ctx; /** * ID of an associated download based on this search result (or * NULL for none). */ struct GNUNET_FS_DownloadContext *download; /** * If this search result triggered an update search, this field * links to the update search. */ struct GNUNET_FS_SearchContext *update_search; /** * Name under which this search result is stored on disk. */ char *serialization; /** * Bitmap that specifies precisely which keywords have been matched already. */ uint8_t *keyword_bitmap; /** * Key for the search result */ GNUNET_HashCode key; /** * ID of the task that will clean up the probe_ctx should it not * complete on time (and that will need to be cancelled if we clean * up the search result before then). */ GNUNET_SCHEDULER_TaskIdentifier probe_cancel_task; /** * When did the current probe become active? */ struct GNUNET_TIME_Absolute probe_active_time; /** * How much longer should we run the current probe before giving up? */ struct GNUNET_TIME_Relative remaining_probe_time; /** * Number of mandatory keywords for which we have NOT yet found the * search result; when this value hits zero, the search result is * given to the callback. */ uint32_t mandatory_missing; /** * Number of optional keywords under which this result was also * found. */ uint32_t optional_support; /** * Number of availability tests that have succeeded for this result. */ uint32_t availability_success; /** * Number of availability trials that we have performed for this * search result. */ uint32_t availability_trials; }; /** * Add a job to the queue. * * @param h handle to the overall FS state * @param start function to call to begin the job * @param stop function to call to pause the job, or on dequeue (if the job was running) * @param cls closure for start and stop * @param blocks number of blocks this download has * @param priority how important is this download * @return queue handle */ struct GNUNET_FS_QueueEntry * GNUNET_FS_queue_ (struct GNUNET_FS_Handle *h, GNUNET_FS_QueueStart start, GNUNET_FS_QueueStop stop, void *cls, unsigned int blocks, enum GNUNET_FS_QueuePriority priority); /** * Dequeue a job from the queue. * @param qh handle for the job */ void GNUNET_FS_dequeue_ (struct GNUNET_FS_QueueEntry *qh); /** * Function that provides data by reading from a file. * * @param cls closure (points to the file information) * @param offset offset to read from; it is possible * that the caller might need to go backwards * a bit at times * @param max maximum number of bytes that should be * copied to buf; readers are not allowed * to provide less data unless there is an error; * a value of "0" will be used at the end to allow * the reader to clean up its internal state * @param buf where the reader should write the data * @param emsg location for the reader to store an error message * @return number of bytes written, usually "max", 0 on error */ size_t GNUNET_FS_data_reader_file_ (void *cls, uint64_t offset, size_t max, void *buf, char **emsg); /** * Create the closure for the 'GNUNET_FS_data_reader_file_' callback. * * @param filename file to read * @return closure to use */ void * GNUNET_FS_make_file_reader_context_ (const char *filename); /** * Function that provides data by copying from a buffer. * * @param cls closure (points to the buffer) * @param offset offset to read from; it is possible * that the caller might need to go backwards * a bit at times * @param max maximum number of bytes that should be * copied to buf; readers are not allowed * to provide less data unless there is an error; * a value of "0" will be used at the end to allow * the reader to clean up its internal state * @param buf where the reader should write the data * @param emsg location for the reader to store an error message * @return number of bytes written, usually "max", 0 on error */ size_t GNUNET_FS_data_reader_copy_ (void *cls, uint64_t offset, size_t max, void *buf, char **emsg); /** * Notification of FS that a search probe has made progress. * This function is used INSTEAD of the client's event handler * for downloads where the GNUNET_FS_DOWNLOAD_IS_PROBE flag is set. * * @param cls closure, always NULL (!), actual closure * is in the client-context of the info struct * @param info details about the event, specifying the event type * and various bits about the event * @return client-context (for the next progress call * for this operation; should be set to NULL for * SUSPEND and STOPPED events). The value returned * will be passed to future callbacks in the respective * field in the GNUNET_FS_ProgressInfo struct. */ void * GNUNET_FS_search_probe_progress_ (void *cls, const struct GNUNET_FS_ProgressInfo *info); /** * Main function that performs the upload. * * @param cls "struct GNUNET_FS_PublishContext" identifies the upload * @param tc task context */ void GNUNET_FS_publish_main_ (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Function called once the hash of the file * that is being unindexed has been computed. * * @param cls closure, unindex context * @param file_id computed hash, NULL on error */ void GNUNET_FS_unindex_process_hash_ (void *cls, const GNUNET_HashCode * file_id); /** * Extract the keywords for KBlock removal * * @param uc context for the unindex operation. */ void GNUNET_FS_unindex_do_extract_keywords_ (struct GNUNET_FS_UnindexContext *uc); /** * If necessary, connect to the datastore and remove the KBlocks. * * @param uc context for the unindex operation. */ void GNUNET_FS_unindex_do_remove_kblocks_ (struct GNUNET_FS_UnindexContext *uc); /** * Fill in all of the generic fields for a publish event and call the * callback. * * @param pi structure to fill in * @param pc overall publishing context * @param p file information for the file being published * @param offset where in the file are we so far * @return value returned from callback */ void * GNUNET_FS_publish_make_status_ (struct GNUNET_FS_ProgressInfo *pi, struct GNUNET_FS_PublishContext *pc, const struct GNUNET_FS_FileInformation *p, uint64_t offset); /** * Fill in all of the generic fields for a download event and call the * callback. * * @param pi structure to fill in * @param dc overall download context */ void GNUNET_FS_download_make_status_ (struct GNUNET_FS_ProgressInfo *pi, struct GNUNET_FS_DownloadContext *dc); /** * Task that creates the initial (top-level) download * request for the file. * * @param cls the 'struct GNUNET_FS_DownloadContext' * @param tc scheduler context */ void GNUNET_FS_download_start_task_ (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Fill in all of the generic fields for * an unindex event and call the callback. * * @param pi structure to fill in * @param uc overall unindex context * @param offset where we are in the file (for progress) */ void GNUNET_FS_unindex_make_status_ (struct GNUNET_FS_ProgressInfo *pi, struct GNUNET_FS_UnindexContext *uc, uint64_t offset); /** * Fill in all of the generic fields for a search event and * call the callback. * * @param pi structure to fill in * @param sc overall search context * @return value returned by the callback */ void * GNUNET_FS_search_make_status_ (struct GNUNET_FS_ProgressInfo *pi, struct GNUNET_FS_SearchContext *sc); /** * Connect to the datastore and remove the blocks. * * @param uc context for the unindex operation. */ void GNUNET_FS_unindex_do_remove_ (struct GNUNET_FS_UnindexContext *uc); /** * Build the request and actually initiate the search using the * GNUnet FS service. * * @param sc search context * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_FS_search_start_searching_ (struct GNUNET_FS_SearchContext *sc); /** * Start the downloading process (by entering the queue). * * @param dc our download context */ void GNUNET_FS_download_start_downloading_ (struct GNUNET_FS_DownloadContext *dc); /** * Start download probes for the given search result. * * @param sr the search result */ void GNUNET_FS_search_start_probe_ (struct GNUNET_FS_SearchResult *sr); /** * Remove serialization/deserialization file from disk. * * @param h master context * @param ext component of the path * @param ent entity identifier */ void GNUNET_FS_remove_sync_file_ (struct GNUNET_FS_Handle *h, const char *ext, const char *ent); /** * Remove serialization/deserialization directory from disk. * * @param h master context * @param ext component of the path * @param uni unique name of parent */ void GNUNET_FS_remove_sync_dir_ (struct GNUNET_FS_Handle *h, const char *ext, const char *uni); /** * Synchronize this file-information struct with its mirror * on disk. Note that all internal FS-operations that change * file information data should already call "sync" internally, * so this function is likely not useful for clients. * * @param fi the struct to sync */ void GNUNET_FS_file_information_sync_ (struct GNUNET_FS_FileInformation *f); /** * Synchronize this publishing struct with its mirror * on disk. Note that all internal FS-operations that change * publishing structs should already call "sync" internally, * so this function is likely not useful for clients. * * @param pc the struct to sync */ void GNUNET_FS_publish_sync_ (struct GNUNET_FS_PublishContext *pc); /** * Synchronize this unindex struct with its mirror * on disk. Note that all internal FS-operations that change * publishing structs should already call "sync" internally, * so this function is likely not useful for clients. * * @param uc the struct to sync */ void GNUNET_FS_unindex_sync_ (struct GNUNET_FS_UnindexContext *uc); /** * Synchronize this search struct with its mirror * on disk. Note that all internal FS-operations that change * publishing structs should already call "sync" internally, * so this function is likely not useful for clients. * * @param sc the struct to sync */ void GNUNET_FS_search_sync_ (struct GNUNET_FS_SearchContext *sc); /** * Synchronize this search result with its mirror * on disk. Note that all internal FS-operations that change * publishing structs should already call "sync" internally, * so this function is likely not useful for clients. * * @param sr the struct to sync */ void GNUNET_FS_search_result_sync_ (struct GNUNET_FS_SearchResult *sr); /** * Synchronize this download struct with its mirror * on disk. Note that all internal FS-operations that change * publishing structs should already call "sync" internally, * so this function is likely not useful for clients. * * @param dc the struct to sync */ void GNUNET_FS_download_sync_ (struct GNUNET_FS_DownloadContext *dc); /** * Create SUSPEND event for the given publish operation * and then clean up our state (without stop signal). * * @param cls the 'struct GNUNET_FS_PublishContext' to signal for */ void GNUNET_FS_publish_signal_suspend_ (void *cls); /** * Create SUSPEND event for the given search operation * and then clean up our state (without stop signal). * * @param cls the 'struct GNUNET_FS_SearchContext' to signal for */ void GNUNET_FS_search_signal_suspend_ (void *cls); /** * Create SUSPEND event for the given download operation * and then clean up our state (without stop signal). * * @param cls the 'struct GNUNET_FS_DownloadContext' to signal for */ void GNUNET_FS_download_signal_suspend_ (void *cls); /** * Create SUSPEND event for the given unindex operation * and then clean up our state (without stop signal). * * @param cls the 'struct GNUNET_FS_UnindexContext' to signal for */ void GNUNET_FS_unindex_signal_suspend_ (void *cls); /** * Function signature of the functions that can be called * to trigger suspend signals and clean-up for top-level * activities. * * @param cls closure */ typedef void (*SuspendSignalFunction) (void *cls); /** * We track all of the top-level activities of FS * so that we can signal 'suspend' on shutdown. */ struct TopLevelActivity { /** * This is a doubly-linked list. */ struct TopLevelActivity *next; /** * This is a doubly-linked list. */ struct TopLevelActivity *prev; /** * Function to call for suspend-signalling and clean up. */ SuspendSignalFunction ssf; /** * Closure for 'ssf' (some struct GNUNET_FS_XXXHandle*) */ void *ssf_cls; }; /** * Create a top-level activity entry. * * @param h global fs handle * @param ssf suspend signal function to use * @param ssf_cls closure for ssf * @return fresh top-level activity handle */ struct TopLevelActivity * GNUNET_FS_make_top (struct GNUNET_FS_Handle *h, SuspendSignalFunction ssf, void *ssf_cls); /** * Destroy a top-level activity entry. * * @param h global fs handle * @param top top level activity entry */ void GNUNET_FS_end_top (struct GNUNET_FS_Handle *h, struct TopLevelActivity *top); /** * Master context for most FS operations. */ struct GNUNET_FS_Handle { /** * Configuration to use. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Name of our client. */ char *client_name; /** * Function to call with updates on our progress. */ GNUNET_FS_ProgressCallback upcb; /** * Closure for upcb. */ void *upcb_cls; /** * Head of DLL of top-level activities. */ struct TopLevelActivity *top_head; /** * Tail of DLL of top-level activities. */ struct TopLevelActivity *top_tail; /** * Head of DLL of running jobs. */ struct GNUNET_FS_QueueEntry *running_head; /** * Tail of DLL of running jobs. */ struct GNUNET_FS_QueueEntry *running_tail; /** * Head of DLL of pending jobs. */ struct GNUNET_FS_QueueEntry *pending_head; /** * Tail of DLL of pending jobs. */ struct GNUNET_FS_QueueEntry *pending_tail; /** * Task that processes the jobs in the running and pending queues * (and moves jobs around as needed). */ GNUNET_SCHEDULER_TaskIdentifier queue_job; /** * Average time we take for a single request to be satisfied. * FIXME: not yet calcualted properly... */ struct GNUNET_TIME_Relative avg_block_latency; /** * How many actual downloads do we have running right now? */ unsigned int active_downloads; /** * How many blocks do the active downloads have? */ unsigned int active_blocks; /** * General flags. */ enum GNUNET_FS_Flags flags; /** * Maximum number of parallel downloads. */ unsigned int max_parallel_downloads; /** * Maximum number of parallel requests. */ unsigned int max_parallel_requests; }; /** * Handle for controlling a publication process. */ struct GNUNET_FS_PublishContext { /** * Handle to the global fs context. */ struct GNUNET_FS_Handle *h; /** * Our top-level activity entry (if we are top-level, otherwise NULL). */ struct TopLevelActivity *top; /** * File-structure that is being shared. */ struct GNUNET_FS_FileInformation *fi; /** * Namespace that we are publishing in, NULL if we have no namespace. */ struct GNUNET_FS_Namespace *namespace; /** * ID of the content in the namespace, NULL if we have no namespace. */ char *nid; /** * ID for future updates, NULL if we have no namespace or no updates. */ char *nuid; /** * Filename used for serializing information about this operation * (should be determined using 'mktemp'). */ char *serialization; /** * Our own client handle for the FS service; only briefly used when * we start to index a file, otherwise NULL. */ struct GNUNET_CLIENT_Connection *client; /** * Current position in the file-tree for the upload. */ struct GNUNET_FS_FileInformation *fi_pos; /** * Non-null if we are currently hashing a file. */ struct GNUNET_CRYPTO_FileHashContext *fhc; /** * Connection to the datastore service. */ struct GNUNET_DATASTORE_Handle *dsh; /** * Queue entry for reservation/unreservation. */ struct GNUNET_DATASTORE_QueueEntry *qre; /** * Context for SKS publishing operation that is part of this publishing operation * (NULL if not active). */ struct GNUNET_FS_PublishSksContext *sks_pc; /** * Context for KSK publishing operation that is part of this publishing operation * (NULL if not active). */ struct GNUNET_FS_PublishKskContext *ksk_pc; /** * ID of the task performing the upload. NO_TASK if the upload has * completed. */ GNUNET_SCHEDULER_TaskIdentifier upload_task; /** * Storage space to reserve for the operation. */ uint64_t reserve_space; /** * Overall number of entries to reserve for the * publish operation. */ uint32_t reserve_entries; /** * Options for publishing. */ enum GNUNET_FS_PublishOptions options; /** * Space reservation ID with datastore service * for this upload. */ int rid; /** * Set to GNUNET_YES if all processing has completed. */ int all_done; /** * Flag set to GNUNET_YES if the next callback from * GNUNET_FS_file_information_inspect should be skipped because it * is for the directory which was already processed with the parent. */ int skip_next_fi_callback; }; /** * Phases of unindex processing (state machine). */ enum UnindexState { /** * We're currently hashing the file. */ UNINDEX_STATE_HASHING = 0, /** * We're telling the datastore to delete * the respective DBlocks and IBlocks. */ UNINDEX_STATE_DS_REMOVE = 1, /** * Find out which keywords apply. */ UNINDEX_STATE_EXTRACT_KEYWORDS = 2, /** * We're telling the datastore to remove KBlocks. */ UNINDEX_STATE_DS_REMOVE_KBLOCKS = 3, /** * We're notifying the FS service about * the unindexing. */ UNINDEX_STATE_FS_NOTIFY = 4, /** * We're done. */ UNINDEX_STATE_COMPLETE = 5, /** * We've encountered a fatal error. */ UNINDEX_STATE_ERROR = 6 }; /** * Handle for controlling an unindexing operation. */ struct GNUNET_FS_UnindexContext { /** * The content hash key of the last block we processed, will in the * end be set to the CHK from the URI. Used to remove the KBlocks. */ struct ContentHashKey chk; /** * Global FS context. */ struct GNUNET_FS_Handle *h; /** * Our top-level activity entry. */ struct TopLevelActivity *top; /** * Directory scanner to find keywords (KBlock removal). */ struct GNUNET_FS_DirScanner *dscan; /** * Keywords found (telling us which KBlocks to remove). */ struct GNUNET_FS_Uri *ksk_uri; /** * Current offset in KSK removal. */ uint32_t ksk_offset; /** * Name of the file that we are unindexing. */ char *filename; /** * Short name under which we are serializing the state of this operation. */ char *serialization; /** * Connection to the FS service, only valid during the * UNINDEX_STATE_FS_NOTIFY phase. */ struct GNUNET_CLIENT_Connection *client; /** * Connection to the datastore service, only valid during the * UNINDEX_STATE_DS_NOTIFY phase. */ struct GNUNET_DATASTORE_Handle *dsh; /** * Pointer kept for the client. */ void *client_info; /** * Merkle-ish tree encoder context. */ struct GNUNET_FS_TreeEncoder *tc; /** * Handle used to read the file. */ struct GNUNET_DISK_FileHandle *fh; /** * Handle to datastore 'get_key' operation issued for * obtaining KBlocks. */ struct GNUNET_DATASTORE_QueueEntry *dqe; /** * Current key for decrypting KBLocks from 'get_key' operation. */ GNUNET_HashCode key; /** * Current query of 'get_key' operation. */ GNUNET_HashCode query; /** * First content UID, 0 for none. */ uint64_t first_uid; /** * Error message, NULL on success. */ char *emsg; /** * Context for hashing of the file. */ struct GNUNET_CRYPTO_FileHashContext *fhc; /** * Overall size of the file. */ uint64_t file_size; /** * Random offset given to 'GNUNET_DATASTORE_get_key'. */ uint64_t roff; /** * When did we start? */ struct GNUNET_TIME_Absolute start_time; /** * Hash of the file's contents (once computed). */ GNUNET_HashCode file_id; /** * Current operatinonal phase. */ enum UnindexState state; }; /** * Information we keep for each keyword in * a keyword search. */ struct SearchRequestEntry { /** * Hash of the original keyword, also known as the * key (for decrypting the KBlock). */ GNUNET_HashCode key; /** * Hash of the public key, also known as the query. */ GNUNET_HashCode query; /** * Map that contains a "struct GNUNET_FS_SearchResult" for each result that * was found under this keyword. Note that the entries will point * to the same locations as those in the master result map (in * "struct GNUNET_FS_SearchContext"), so they should not be freed. * The key for each entry is the XOR of the key and query in the CHK * URI (as a unique identifier for the search result). */ struct GNUNET_CONTAINER_MultiHashMap *results; /** * Is this keyword a mandatory keyword * (started with '+')? */ int mandatory; }; /** * Handle for controlling a search. */ struct GNUNET_FS_SearchContext { /** * Handle to the global FS context. */ struct GNUNET_FS_Handle *h; /** * Our top-level activity entry (if we are top-level, otherwise NULL). */ struct TopLevelActivity *top; /** * List of keywords that we're looking for. */ struct GNUNET_FS_Uri *uri; /** * For update-searches, link to the search result that triggered * the update search; otherwise NULL. */ struct GNUNET_FS_SearchResult *psearch_result; /** * Connection to the FS service. */ struct GNUNET_CLIENT_Connection *client; /** * Pointer we keep for the client. */ void *client_info; /** * Name of the file on disk we use for persistence. */ char *serialization; /** * Error message (non-NULL if this operation failed). */ char *emsg; /** * Map that contains a "struct GNUNET_FS_SearchResult" for each result that * was found in the search. The key for each entry is the XOR of * the key and query in the CHK URI (as a unique identifier for the * search result). */ struct GNUNET_CONTAINER_MultiHashMap *master_result_map; /** * Per-keyword information for a keyword search. This array will * have exactly as many entries as there were keywords. */ struct SearchRequestEntry *requests; /** * When did we start? */ struct GNUNET_TIME_Absolute start_time; /** * ID of a task that is using this struct and that must be cancelled * when the search is being stopped (if not * GNUNET_SCHEDULER_NO_TASK). Used for the task that adds some * artificial delay when trying to reconnect to the FS service. */ GNUNET_SCHEDULER_TaskIdentifier task; /** * How many of the entries in the search request * map have been passed to the service so far? */ unsigned int search_request_map_offset; /** * How many of the keywords in the KSK * map have been passed to the service so far? */ unsigned int keyword_offset; /** * Anonymity level for the search. */ uint32_t anonymity; /** * Number of mandatory keywords in this query. */ uint32_t mandatory_count; /** * Options for the search. */ enum GNUNET_FS_SearchOptions options; }; /** * FSM for possible states a block can go through. The typical * order of progression is linear through the states, alternatives * are documented in the comments. */ enum BlockRequestState { /** * Initial state, block has only been allocated (since it is * relevant to the overall download request). */ BRS_INIT = 0, /** * We've checked the block on the path down the tree, and the * content on disk did match the desired CHK, but not all * the way down, so at the bottom some blocks will still * need to be reconstructed). */ BRS_RECONSTRUCT_DOWN = 1, /** * We've calculated the CHK bottom-up based on the meta data. * This may work, but if it did we have to write the meta data to * disk at the end (and we still need to check against the * CHK set on top). */ BRS_RECONSTRUCT_META_UP = 2, /** * We've calculated the CHK bottom-up based on what we have on * disk, which may not be what the desired CHK is. If the * reconstructed CHKs match whatever comes from above, we're * done with the respective subtree. */ BRS_RECONSTRUCT_UP = 3, /** * We've determined the real, desired CHK for this block * (full tree reconstruction failed), request is now pending. * If the CHK that bubbled up through reconstruction did match * the top-level request, the state machine for the subtree * would have moved to BRS_DOWNLOAD_UP. */ BRS_CHK_SET = 4, /** * We've successfully downloaded this block, but the children * still need to be either downloaded or verified (download * request propagates down). If the download fails, the * state machine for this block may move to * BRS_DOWNLOAD_ERROR instead. */ BRS_DOWNLOAD_DOWN = 5, /** * This block and all of its children have been downloaded * successfully (full completion propagates up). */ BRS_DOWNLOAD_UP = 6, /** * We got a block back that matched the query but did not hash to * the key (malicious publisher or hash collision); this block * can never be downloaded (error propagates up). */ BRS_ERROR = 7 }; /** * Information about an active download request. */ struct DownloadRequest { /** * While pending, we keep all download requests in a doubly-linked list. */ struct DownloadRequest *next; /** * While pending, we keep all download requests in a doubly-linked list. */ struct DownloadRequest *prev; /** * Parent in the CHK-tree. */ struct DownloadRequest *parent; /** * Array (!) of child-requests, or NULL for the bottom of the tree. */ struct DownloadRequest **children; /** * CHK for the request for this block (set during reconstruction * to what we have on disk, later to what we want to have). */ struct ContentHashKey chk; /** * Offset of the corresponding block. Specifically, first (!) byte of * the first DBLOCK in the subtree induced by block represented by * this request. */ uint64_t offset; /** * Number of entries in 'children' array. */ unsigned int num_children; /** * Depth of the corresponding block in the tree. 0==DBLOCKs. */ unsigned int depth; /** * Offset of the CHK for this block in the parent block */ unsigned int chk_idx; /** * State in the FSM. */ enum BlockRequestState state; /** * GNUNET_YES if this entry is in the pending list. */ int is_pending; }; /** * (recursively) free download request structure * * @param dr request to free */ void GNUNET_FS_free_download_request_ (struct DownloadRequest *dr); /** * Context for controlling a download. */ struct GNUNET_FS_DownloadContext { /** * Global FS context. */ struct GNUNET_FS_Handle *h; /** * Our top-level activity entry (if we are top-level, otherwise NULL). */ struct TopLevelActivity *top; /** * Connection to the FS service. */ struct GNUNET_CLIENT_Connection *client; /** * Parent download (used when downloading files * in directories). */ struct GNUNET_FS_DownloadContext *parent; /** * Associated search (used when downloading files * based on search results), or NULL for none. */ struct GNUNET_FS_SearchResult *search; /** * Head of list of child downloads. */ struct GNUNET_FS_DownloadContext *child_head; /** * Tail of list of child downloads. */ struct GNUNET_FS_DownloadContext *child_tail; /** * Previous download belonging to the same parent. */ struct GNUNET_FS_DownloadContext *prev; /** * Next download belonging to the same parent. */ struct GNUNET_FS_DownloadContext *next; /** * Context kept for the client. */ void *client_info; /** * URI that identifies the file that we are downloading. */ struct GNUNET_FS_Uri *uri; /** * Known meta-data for the file (can be NULL). */ struct GNUNET_CONTAINER_MetaData *meta; /** * Error message, NULL if we're doing OK. */ char *emsg; /** * Random portion of filename we use for syncing state of this * download. */ char *serialization; /** * Where are we writing the data (name of the * file, can be NULL!). */ char *filename; /** * Where are we writing the data temporarily (name of the * file, can be NULL!); used if we do not have a permanent * name and we are a directory and we do a recursive download. */ char *temp_filename; /** * Our entry in the job queue. */ struct GNUNET_FS_QueueEntry *job_queue; /** * Non-NULL if we are currently having a request for * transmission pending with the client handle. */ struct GNUNET_CLIENT_TransmitHandle *th; /** * Tree encoder used for the reconstruction. */ struct GNUNET_FS_TreeEncoder *te; /** * File handle for reading data from an existing file * (to pass to tree encoder). */ struct GNUNET_DISK_FileHandle *rfh; /** * Map of active requests (those waiting for a response). The key * is the hash of the encryped block (aka query). */ struct GNUNET_CONTAINER_MultiHashMap *active; /** * Head of linked list of pending requests. */ struct DownloadRequest *pending_head; /** * Head of linked list of pending requests. */ struct DownloadRequest *pending_tail; /** * Top-level download request. */ struct DownloadRequest *top_request; /** * Identity of the peer having the content, or all-zeros * if we don't know of such a peer. */ struct GNUNET_PeerIdentity target; /** * ID of a task that is using this struct and that must be cancelled * when the download is being stopped (if not * GNUNET_SCHEDULER_NO_TASK). Used for the task that adds some * artificial delay when trying to reconnect to the FS service or * the task processing incrementally the data on disk, or the * task requesting blocks, etc. */ GNUNET_SCHEDULER_TaskIdentifier task; /** * What is the first offset that we're interested * in? */ uint64_t offset; /** * How many bytes starting from offset are desired? * This is NOT the overall length of the file! */ uint64_t length; /** * How many bytes have we already received within * the specified range (DBlocks only). */ uint64_t completed; /** * What was the size of the file on disk that we're downloading * before we started? Used to detect if there is a point in * checking an existing block on disk for matching the desired * content. 0 if the file did not exist already. */ uint64_t old_file_size; /** * Time download was started. */ struct GNUNET_TIME_Absolute start_time; /** * Desired level of anonymity. */ uint32_t anonymity; /** * The depth of the file-tree. */ unsigned int treedepth; /** * Options for the download. */ enum GNUNET_FS_DownloadOptions options; /** * Flag set upon transitive completion (includes child downloads). * This flag is only set to GNUNET_YES for directories where all * child-downloads have also completed (and signalled completion). */ int has_finished; /** * Have we started the receive continuation yet? */ int in_receive; /** * Are we ready to issue requests (reconstructions are finished)? */ int issue_requests; }; /** * Information about an (updateable) node in the * namespace. */ struct NamespaceUpdateNode { /** * Identifier for this node. */ char *id; /** * Identifier of children of this node. */ char *update; /** * Metadata for this entry. */ struct GNUNET_CONTAINER_MetaData *md; /** * URI of this entry in the namespace. */ struct GNUNET_FS_Uri *uri; /** * Namespace update generation ID. Used to ensure * freshness of the tree_id. */ unsigned int nug; /** * TREE this entry belongs to (if nug is current). */ unsigned int tree_id; }; struct GNUNET_FS_Namespace { /** * Handle to the FS service context. */ struct GNUNET_FS_Handle *h; /** * Array with information about nodes in the namespace. */ struct NamespaceUpdateNode **update_nodes; /** * Private key for the namespace. */ struct GNUNET_CRYPTO_RsaPrivateKey *key; /** * Hash map mapping identifiers of update nodes * to the update nodes (initialized on-demand). */ struct GNUNET_CONTAINER_MultiHashMap *update_map; /** * Name of the file with the private key. */ char *filename; /** * Name of the namespace. */ char *name; /** * Size of the update nodes array. */ unsigned int update_node_count; /** * Reference counter. */ unsigned int rc; /** * Generator for unique nug numbers. */ unsigned int nug_gen; }; #endif /* end of fs_api.h */ gnunet-0.9.3/src/fs/test_gnunet_fs_rec_data.conf0000644000175000017500000000022711615567501016673 00000000000000@INLINE@ test_fs_defaults.conf [PATHS] SERVICEHOME = /tmp/gnunet-test-fs-py-rec/ DEFAULTCONFIG = test_gnunet_fs_rec_data.conf [transport] PLUGINS = gnunet-0.9.3/src/fs/test_fs_download.c0000644000175000017500000002632411760502551014656 00000000000000/* This file is part of GNUnet. (C) 2004, 2005, 2006, 2008, 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/test_fs_download.c * @brief simple testcase for simple publish + download operation * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_arm_service.h" #include "gnunet_fs_service.h" #include #define VERBOSE GNUNET_NO #define START_ARM GNUNET_YES /** * File-size we use for testing. */ #define FILESIZE (1024 * 1024 * 2) /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) /** * How long should our test-content live? */ #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static struct PeerContext p1; static struct GNUNET_TIME_Absolute start; static struct GNUNET_FS_Handle *fs; static struct GNUNET_FS_DownloadContext *download; static struct GNUNET_FS_PublishContext *publish; static GNUNET_SCHEDULER_TaskIdentifier timeout_kill; static char *fn; static int err; static void timeout_kill_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (download != NULL) { GNUNET_FS_download_stop (download, GNUNET_YES); download = NULL; } else if (publish != NULL) { GNUNET_FS_publish_stop (publish); publish = NULL; } GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout downloading file\n"); timeout_kill = GNUNET_SCHEDULER_NO_TASK; err = 1; } static void abort_publish_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (publish != NULL) { GNUNET_FS_publish_stop (publish); publish = NULL; } } static void stop_fs_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_FS_stop (fs); fs = NULL; } static void abort_download_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { uint64_t size; if (download != NULL) { GNUNET_FS_download_stop (download, GNUNET_YES); download = NULL; } GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_size (fn, &size, GNUNET_YES, GNUNET_NO)); GNUNET_assert (size == FILESIZE); GNUNET_DISK_directory_remove (fn); GNUNET_free (fn); fn = NULL; GNUNET_SCHEDULER_cancel (timeout_kill); timeout_kill = GNUNET_SCHEDULER_NO_TASK; } static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) { switch (event->status) { case GNUNET_FS_STATUS_PUBLISH_PROGRESS: #if VERBOSE printf ("Publish is progressing (%llu/%llu at level %u off %llu)...\n", (unsigned long long) event->value.publish.completed, (unsigned long long) event->value.publish.size, event->value.publish.specifics.progress.depth, (unsigned long long) event->value.publish.specifics. progress.offset); #endif break; case GNUNET_FS_STATUS_PUBLISH_COMPLETED: printf ("Publishing complete, %llu kb/s.\n", (unsigned long long) (FILESIZE * 1000LL / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value) / 1024LL)); GAUGER ("FS", "Publishing speed (insertion)", (unsigned long long) (FILESIZE * 1000LL / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value) / 1024LL), "kb/s"); fn = GNUNET_DISK_mktemp ("gnunet-download-test-dst"); start = GNUNET_TIME_absolute_get (); download = GNUNET_FS_download_start (fs, event->value.publish.specifics. completed.chk_uri, NULL, fn, NULL, 0, FILESIZE, 1, GNUNET_FS_DOWNLOAD_OPTION_NONE, "download", NULL); GNUNET_assert (download != NULL); break; case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: printf ("Download complete, %llu kb/s.\n", (unsigned long long) (FILESIZE * 1000LL / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value) / 1024LL)); GAUGER ("FS", "Local download speed (inserted)", (unsigned long long) (FILESIZE * 1000LL / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value) / 1024LL), "kb/s"); GNUNET_SCHEDULER_add_now (&abort_download_task, NULL); break; case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: GNUNET_assert (download == event->value.download.dc); #if VERBOSE printf ("Download is progressing (%llu/%llu at level %u off %llu)...\n", (unsigned long long) event->value.download.completed, (unsigned long long) event->value.download.size, event->value.download.specifics.progress.depth, (unsigned long long) event->value.download.specifics. progress.offset); #endif break; case GNUNET_FS_STATUS_PUBLISH_ERROR: FPRINTF (stderr, "Error publishing file: %s\n", event->value.publish.specifics.error.message); GNUNET_break (0); GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_DOWNLOAD_ERROR: FPRINTF (stderr, "Error downloading file: %s\n", event->value.download.specifics.error.message); GNUNET_SCHEDULER_add_now (&abort_download_task, NULL); break; case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: break; case GNUNET_FS_STATUS_PUBLISH_START: GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); GNUNET_assert (NULL == event->value.publish.pctx); GNUNET_assert (FILESIZE == event->value.publish.size); GNUNET_assert (0 == event->value.publish.completed); GNUNET_assert (1 == event->value.publish.anonymity); break; case GNUNET_FS_STATUS_PUBLISH_STOPPED: GNUNET_assert (publish == event->value.publish.pc); GNUNET_assert (FILESIZE == event->value.publish.size); GNUNET_assert (1 == event->value.publish.anonymity); GNUNET_SCHEDULER_add_now (&stop_fs_task, NULL); break; case GNUNET_FS_STATUS_DOWNLOAD_START: GNUNET_assert (0 == strcmp ("download", event->value.download.cctx)); GNUNET_assert (NULL == event->value.download.pctx); GNUNET_assert (NULL != event->value.download.uri); GNUNET_assert (0 == strcmp (fn, event->value.download.filename)); GNUNET_assert (FILESIZE == event->value.download.size); GNUNET_assert (0 == event->value.download.completed); GNUNET_assert (1 == event->value.download.anonymity); break; case GNUNET_FS_STATUS_DOWNLOAD_STOPPED: GNUNET_assert (download == event->value.download.dc); GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; default: printf ("Unexpected event: %d\n", event->status); break; } return NULL; } static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE "-L", "DEBUG", #endif "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); } static void stop_arm (struct PeerContext *p) { #if START_ARM if (NULL != p->arm_proc) { if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; } #endif GNUNET_CONFIGURATION_destroy (p->cfg); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { const char *keywords[] = { "down_foo", "down_bar", }; char *buf; struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_FS_Uri *kuri; struct GNUNET_FS_FileInformation *fi; size_t i; struct GNUNET_FS_BlockOptions bo; setup_peer (&p1, "test_fs_download_data.conf"); fs = GNUNET_FS_start (cfg, "test-fs-download", &progress_cb, NULL, GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); GNUNET_assert (NULL != fs); buf = GNUNET_malloc (FILESIZE); for (i = 0; i < FILESIZE; i++) buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); meta = GNUNET_CONTAINER_meta_data_create (); kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); bo.content_priority = 42; bo.anonymity_level = 1; bo.replication_level = 0; bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); fi = GNUNET_FS_file_information_create_from_data (fs, "publish-context", FILESIZE, buf, kuri, meta, GNUNET_NO, &bo); GNUNET_FS_uri_destroy (kuri); GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_assert (NULL != fi); timeout_kill = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_kill_task, NULL); start = GNUNET_TIME_absolute_get (); publish = GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, GNUNET_FS_PUBLISH_OPTION_NONE); GNUNET_assert (publish != NULL); } int main (int argc, char *argv[]) { char *const argvx[] = { "test-fs-download", "-c", "test_fs_download_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("test_fs_download", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "test-fs-download", "nohelp", options, &run, NULL); stop_arm (&p1); GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-download/"); return err; } /* end of test_fs_download.c */ gnunet-0.9.3/src/fs/plugin_block_fs.c0000644000175000017500000002313611760502551014456 00000000000000/* This file is part of GNUnet (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/plugin_block_fs.c * @brief blocks used for file-sharing * @author Christian Grothoff */ #include "platform.h" #include "gnunet_block_plugin.h" #include "block_fs.h" #include "gnunet_signatures.h" #define DEBUG_FS_BLOCK GNUNET_EXTRA_LOGGING /** * Number of bits we set per entry in the bloomfilter. * Do not change! */ #define BLOOMFILTER_K 16 /** * Function called to validate a reply or a request. For * request evaluation, simply pass "NULL" for the reply_block. * Note that it is assumed that the reply has already been * matched to the key (and signatures checked) as it would * be done with the "get_key" function. * * @param cls closure * @param type block type * @param query original query (hash) * @param bf pointer to bloom filter associated with query; possibly updated (!) * @param bf_mutator mutation value for bf * @param xquery extrended query data (can be NULL, depending on type) * @param xquery_size number of bytes in xquery * @param reply_block response to validate * @param reply_block_size number of bytes in reply block * @return characterization of result */ static enum GNUNET_BLOCK_EvaluationResult block_plugin_fs_evaluate (void *cls, enum GNUNET_BLOCK_Type type, const GNUNET_HashCode * query, struct GNUNET_CONTAINER_BloomFilter **bf, int32_t bf_mutator, const void *xquery, size_t xquery_size, const void *reply_block, size_t reply_block_size) { const struct SBlock *sb; GNUNET_HashCode chash; GNUNET_HashCode mhash; const GNUNET_HashCode *nsid; GNUNET_HashCode sh; switch (type) { case GNUNET_BLOCK_TYPE_FS_DBLOCK: case GNUNET_BLOCK_TYPE_FS_IBLOCK: if (xquery_size != 0) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; } if (reply_block == NULL) return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; return GNUNET_BLOCK_EVALUATION_OK_LAST; case GNUNET_BLOCK_TYPE_FS_KBLOCK: case GNUNET_BLOCK_TYPE_FS_NBLOCK: if (xquery_size != 0) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; } if (reply_block == NULL) return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; if (NULL != bf) { GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash); GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash); if (NULL != *bf) { if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash)) return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE; } else { *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, BLOOMFILTER_K); } GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash); } return GNUNET_BLOCK_EVALUATION_OK_MORE; case GNUNET_BLOCK_TYPE_FS_SBLOCK: if (xquery_size != sizeof (GNUNET_HashCode)) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; } if (reply_block == NULL) return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; nsid = xquery; if (reply_block_size < sizeof (struct SBlock)) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } sb = reply_block; GNUNET_CRYPTO_hash (&sb->subspace, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &sh); if (0 != memcmp (nsid, &sh, sizeof (GNUNET_HashCode))) { GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "block-fs", _ ("Reply mismatched in terms of namespace. Discarded.\n")); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } if (NULL != bf) { GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash); GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash); if (NULL != *bf) { if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash)) return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE; } else { *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, BLOOMFILTER_K); } GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash); } return GNUNET_BLOCK_EVALUATION_OK_MORE; default: return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; } } /** * Function called to obtain the key for a block. * * @param cls closure * @param type block type * @param block block to get the key for * @param block_size number of bytes in block * @param key set to the key (query) for the given block * @return GNUNET_OK on success, GNUNET_SYSERR if type not supported * (or if extracting a key from a block of this type does not work) */ static int block_plugin_fs_get_key (void *cls, enum GNUNET_BLOCK_Type type, const void *block, size_t block_size, GNUNET_HashCode * key) { const struct KBlock *kb; const struct SBlock *sb; const struct NBlock *nb; switch (type) { case GNUNET_BLOCK_TYPE_FS_DBLOCK: case GNUNET_BLOCK_TYPE_FS_IBLOCK: GNUNET_CRYPTO_hash (block, block_size, key); return GNUNET_OK; case GNUNET_BLOCK_TYPE_FS_KBLOCK: if (block_size < sizeof (struct KBlock)) { GNUNET_break_op (0); return GNUNET_NO; } kb = block; if (block_size - sizeof (struct KBlock) != ntohl (kb->purpose.size) - sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)) { GNUNET_break_op (0); return GNUNET_NO; } if (GNUNET_OK != GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_FS_KBLOCK, &kb->purpose, &kb->signature, &kb->keyspace)) { GNUNET_break_op (0); return GNUNET_NO; } if (key != NULL) GNUNET_CRYPTO_hash (&kb->keyspace, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), key); return GNUNET_OK; case GNUNET_BLOCK_TYPE_FS_SBLOCK: if (block_size < sizeof (struct SBlock)) { GNUNET_break_op (0); return GNUNET_NO; } sb = block; if (block_size != ntohl (sb->purpose.size) + sizeof (struct GNUNET_CRYPTO_RsaSignature)) { GNUNET_break_op (0); return GNUNET_NO; } if (GNUNET_OK != GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_FS_SBLOCK, &sb->purpose, &sb->signature, &sb->subspace)) { GNUNET_break_op (0); return GNUNET_NO; } if (key != NULL) *key = sb->identifier; return GNUNET_OK; case GNUNET_BLOCK_TYPE_FS_NBLOCK: if (block_size < sizeof (struct NBlock)) { GNUNET_break_op (0); return GNUNET_NO; } nb = block; if (block_size - sizeof (struct NBlock) != ntohl (nb->ns_purpose.size) - sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)) { GNUNET_break_op (0); return GNUNET_NO; } if (block_size != ntohl (nb->ksk_purpose.size) + sizeof (struct GNUNET_CRYPTO_RsaSignature)) { GNUNET_break_op (0); return GNUNET_NO; } if (GNUNET_OK != GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK_KSIG, &nb->ksk_purpose, &nb->ksk_signature, &nb->keyspace)) { GNUNET_break_op (0); return GNUNET_NO; } if (GNUNET_OK != GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK, &nb->ns_purpose, &nb->ns_signature, &nb->subspace)) { GNUNET_break_op (0); return GNUNET_NO; } /* FIXME: we used to xor ID with NSID, * why not here? */ if (key != NULL) GNUNET_CRYPTO_hash (&nb->keyspace, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), key); return GNUNET_OK; default: return GNUNET_SYSERR; } } /** * Entry point for the plugin. */ void * libgnunet_plugin_block_fs_init (void *cls) { static enum GNUNET_BLOCK_Type types[] = { GNUNET_BLOCK_TYPE_FS_DBLOCK, GNUNET_BLOCK_TYPE_FS_IBLOCK, GNUNET_BLOCK_TYPE_FS_KBLOCK, GNUNET_BLOCK_TYPE_FS_SBLOCK, GNUNET_BLOCK_TYPE_FS_NBLOCK, GNUNET_BLOCK_TYPE_ANY /* end of list */ }; struct GNUNET_BLOCK_PluginFunctions *api; api = GNUNET_malloc (sizeof (struct GNUNET_BLOCK_PluginFunctions)); api->evaluate = &block_plugin_fs_evaluate; api->get_key = &block_plugin_fs_get_key; api->types = types; return api; } /** * Exit point from the plugin. */ void * libgnunet_plugin_block_fs_done (void *cls) { struct GNUNET_TRANSPORT_PluginFunctions *api = cls; GNUNET_free (api); return NULL; } /* end of plugin_block_fs.c */ gnunet-0.9.3/src/fs/fs_sharetree.c0000644000175000017500000002751711760502551013777 00000000000000/* This file is part of GNUnet (C) 2005-2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs_sharetree.c * @brief code to manipulate the 'struct GNUNET_FS_ShareTreeItem' tree * @author LRN * @author Christian Grothoff */ #include "platform.h" #include "gnunet_fs_service.h" #include "gnunet_scheduler_lib.h" #include /** * Entry for each unique keyword to track how often * it occured. Contains the keyword and the counter. */ struct KeywordCounter { /** * This is a doubly-linked list */ struct KeywordCounter *prev; /** * This is a doubly-linked list */ struct KeywordCounter *next; /** * Keyword that was found. */ const char *value; /** * How many files have this keyword? */ unsigned int count; }; /** * Aggregate information we keep for meta data in each directory. */ struct MetaCounter { /** * This is a doubly-linked list */ struct MetaCounter *prev; /** * This is a doubly-linked list */ struct MetaCounter *next; /** * Name of the plugin that provided that piece of metadata */ const char *plugin_name; /** * MIME-type of the metadata itself */ const char *data_mime_type; /** * The actual meta data. */ const char *data; /** * Number of bytes in 'data'. */ size_t data_size; /** * Type of the data */ enum EXTRACTOR_MetaType type; /** * Format of the data */ enum EXTRACTOR_MetaFormat format; /** * How many files have meta entries matching this value? * (type and format do not have to match). */ unsigned int count; }; /** * A structure that forms a singly-linked list that serves as a stack * for metadata-processing function. */ struct TrimContext { /** * Map from the hash over the keyword to an 'struct KeywordCounter *' * counter that says how often this keyword was * encountered in the current directory. */ struct GNUNET_CONTAINER_MultiHashMap *keywordcounter; /** * Map from the hash over the metadata to an 'struct MetaCounter *' * counter that says how often this metadata was * encountered in the current directory. */ struct GNUNET_CONTAINER_MultiHashMap *metacounter; /** * Position we are currently manipulating. */ struct GNUNET_FS_ShareTreeItem *pos; /** * Number of times an item has to be found to be moved to the parent. */ unsigned int move_threshold; }; /** * Add the given keyword to the keyword statistics tracker. * * @param cls the multihashmap we store the keyword counters in * @param keyword the keyword to count * @param is_mandatory ignored * @return always GNUNET_OK */ static int add_to_keyword_counter (void *cls, const char *keyword, int is_mandatory) { struct GNUNET_CONTAINER_MultiHashMap *mcm = cls; struct KeywordCounter *cnt; GNUNET_HashCode hc; size_t klen; klen = strlen (keyword) + 1; GNUNET_CRYPTO_hash (keyword, klen - 1, &hc); cnt = GNUNET_CONTAINER_multihashmap_get (mcm, &hc); if (cnt == NULL) { cnt = GNUNET_malloc (sizeof (struct KeywordCounter) + klen); cnt->value = (const char *) &cnt[1]; memcpy (&cnt[1], keyword, klen); GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (mcm, &hc, cnt, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); } cnt->count++; return GNUNET_OK; } /** * Function called on each meta data item. Increments the * respective counter. * * @param cls the container multihashmap to update * @param plugin_name name of the plugin that produced this value; * special values can be used (i.e. '<zlib>' for zlib being * used in the main libextractor library and yielding * meta data). * @param type libextractor-type describing the meta data * @param format basic format information about data * @param data_mime_type mime-type of data (not of the original file); * can be NULL (if mime-type is not known) * @param data actual meta-data found * @param data_len number of bytes in data * @return GNUNET_OK to continue extracting / iterating */ static int add_to_meta_counter (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat format, const char *data_mime_type, const char *data, size_t data_len) { struct GNUNET_CONTAINER_MultiHashMap *map = cls; GNUNET_HashCode key; struct MetaCounter *cnt; GNUNET_CRYPTO_hash (data, data_len, &key); cnt = GNUNET_CONTAINER_multihashmap_get (map, &key); if (cnt == NULL) { cnt = GNUNET_malloc (sizeof (struct MetaCounter)); cnt->data = data; cnt->data_size = data_len; cnt->plugin_name = plugin_name; cnt->type = type; cnt->format = format; cnt->data_mime_type = data_mime_type; GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (map, &key, cnt, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); } cnt->count++; return 0; } /** * Remove keywords above the threshold. * * @param cls the 'struct TrimContext' with the pos to remove the keywords from * @param keyword the keyword to check * @param is_mandatory ignored * @return always GNUNET_OK */ static int remove_high_frequency_keywords (void *cls, const char *keyword, int is_mandatory) { struct TrimContext *tc = cls; struct KeywordCounter *counter; GNUNET_HashCode hc; size_t klen; klen = strlen (keyword) + 1; GNUNET_CRYPTO_hash (keyword, klen - 1, &hc); counter = GNUNET_CONTAINER_multihashmap_get (tc->keywordcounter, &hc); GNUNET_assert (NULL != counter); if (counter->count < tc->move_threshold) return GNUNET_OK; GNUNET_FS_uri_ksk_remove_keyword (tc->pos->ksk_uri, counter->value); return GNUNET_OK; } /** * Move "frequent" keywords over to the target ksk uri, free the * counters. * * @param cls the 'struct TrimContext' * @param key key of the entry * @param value the 'struct KeywordCounter' * @return GNUNET_YES (always) */ static int migrate_and_drop_keywords (void *cls, const GNUNET_HashCode * key, void *value) { struct TrimContext *tc = cls; struct KeywordCounter *counter = value; if (counter->count >= tc->move_threshold) { if (NULL == tc->pos->ksk_uri) tc->pos->ksk_uri = GNUNET_FS_uri_ksk_create_from_args (1, &counter->value); else GNUNET_FS_uri_ksk_add_keyword (tc->pos->ksk_uri, counter->value, GNUNET_NO); } GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (tc->keywordcounter, key, counter)); GNUNET_free (counter); return GNUNET_YES; } /** * Copy "frequent" metadata items over to the * target metadata container, free the counters. * * @param cls the 'struct TrimContext' * @param key key of the entry * @param value the 'struct KeywordCounter' * @return GNUNET_YES (always) */ static int migrate_and_drop_metadata (void *cls, const GNUNET_HashCode * key, void *value) { struct TrimContext *tc = cls; struct MetaCounter *counter = value; if (counter->count >= tc->move_threshold) { if (NULL == tc->pos->meta) tc->pos->meta = GNUNET_CONTAINER_meta_data_create (); GNUNET_CONTAINER_meta_data_insert (tc->pos->meta, counter->plugin_name, counter->type, counter->format, counter->data_mime_type, counter->data, counter->data_size); } GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (tc->metacounter, key, counter)); GNUNET_free (counter); return GNUNET_YES; } /** * Process a share item tree, moving frequent keywords up and * copying frequent metadata up. * * @param tc trim context with hash maps to use * @param tree tree to trim */ static void share_tree_trim (struct TrimContext *tc, struct GNUNET_FS_ShareTreeItem *tree) { struct GNUNET_FS_ShareTreeItem *pos; unsigned int num_children; /* first, trim all children */ num_children = 0; for (pos = tree->children_head; NULL != pos; pos = pos->next) { share_tree_trim (tc, pos); num_children++; } /* consider adding filename to directory meta data */ if (tree->is_directory == GNUNET_YES) { const char *user = getenv ("USER"); if ( (user == NULL) || (0 != strncasecmp (user, tree->short_filename, strlen(user)))) { /* only use filename if it doesn't match $USER */ if (NULL == tree->meta) tree->meta = GNUNET_CONTAINER_meta_data_create (); GNUNET_CONTAINER_meta_data_insert (tree->meta, "", EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, EXTRACTOR_METAFORMAT_UTF8, "text/plain", tree->short_filename, strlen (tree->short_filename) + 1); } } if (1 >= num_children) return; /* nothing to trim */ /* now, count keywords and meta data in children */ for (pos = tree->children_head; NULL != pos; pos = pos->next) { if (NULL != pos->meta) GNUNET_CONTAINER_meta_data_iterate (pos->meta, &add_to_meta_counter, tc->metacounter); if (NULL != pos->ksk_uri) GNUNET_FS_uri_ksk_get_keywords (pos->ksk_uri, &add_to_keyword_counter, tc->keywordcounter); } /* calculate threshold for moving keywords / meta data */ tc->move_threshold = 1 + (num_children / 2); /* remove high-frequency keywords from children */ for (pos = tree->children_head; NULL != pos; pos = pos->next) { tc->pos = pos; if (NULL != pos->ksk_uri) { struct GNUNET_FS_Uri *ksk_uri_copy = GNUNET_FS_uri_dup (pos->ksk_uri); GNUNET_FS_uri_ksk_get_keywords (ksk_uri_copy, &remove_high_frequency_keywords, tc); GNUNET_FS_uri_destroy (ksk_uri_copy); } } /* add high-frequency meta data and keywords to parent */ tc->pos = tree; GNUNET_CONTAINER_multihashmap_iterate (tc->keywordcounter, &migrate_and_drop_keywords, tc); GNUNET_CONTAINER_multihashmap_iterate (tc->metacounter, &migrate_and_drop_metadata, tc); } /** * Process a share item tree, moving frequent keywords up and * copying frequent metadata up. * * @param toplevel toplevel directory in the tree, returned by the scanner */ void GNUNET_FS_share_tree_trim (struct GNUNET_FS_ShareTreeItem *toplevel) { struct TrimContext tc; if (toplevel == NULL) return; tc.keywordcounter = GNUNET_CONTAINER_multihashmap_create (1024); tc.metacounter = GNUNET_CONTAINER_multihashmap_create (1024); share_tree_trim (&tc, toplevel); GNUNET_CONTAINER_multihashmap_destroy (tc.keywordcounter); GNUNET_CONTAINER_multihashmap_destroy (tc.metacounter); } /** * Release memory of a share item tree. * * @param toplevel toplevel of the tree to be freed */ void GNUNET_FS_share_tree_free (struct GNUNET_FS_ShareTreeItem *toplevel) { struct GNUNET_FS_ShareTreeItem *pos; while (NULL != (pos = toplevel->children_head)) GNUNET_FS_share_tree_free (pos); if (NULL != toplevel->parent) GNUNET_CONTAINER_DLL_remove (toplevel->parent->children_head, toplevel->parent->children_tail, toplevel); if (NULL != toplevel->meta) GNUNET_CONTAINER_meta_data_destroy (toplevel->meta); if (NULL != toplevel->ksk_uri) GNUNET_FS_uri_destroy (toplevel->ksk_uri); GNUNET_free_non_null (toplevel->filename); GNUNET_free_non_null (toplevel->short_filename); GNUNET_free (toplevel); } /* end fs_sharetree.c */ gnunet-0.9.3/src/fs/test_fs_start_stop.c0000644000175000017500000000674411760502551015255 00000000000000/* This file is part of GNUnet. (C) 2004, 2005, 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/test_fs_start_stop.c * @brief testcase for fs.c (start-stop only) * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_arm_service.h" #include "gnunet_fs_service.h" #define VERBOSE GNUNET_NO #define START_ARM GNUNET_YES static struct PeerContext p1; struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) { return NULL; } static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE "-L", "DEBUG", #endif "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); } static void stop_arm (struct PeerContext *p) { #if START_ARM if (NULL != p->arm_proc) { if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; } #endif GNUNET_CONFIGURATION_destroy (p->cfg); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_FS_Handle *fs; setup_peer (&p1, "test_fs_data.conf"); fs = GNUNET_FS_start (cfg, "test-fs-start-stop", &progress_cb, NULL, GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); GNUNET_assert (NULL != fs); GNUNET_FS_stop (fs); } int main (int argc, char *argv[]) { char *const argvx[] = { "test-fs-start-stop", "-c", "test_fs_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("test_fs_start_stop", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "test-fs-start-stop", "nohelp", options, &run, NULL); stop_arm (&p1); GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs/"); return 0; } /* end of test_fs_start_stop.c */ gnunet-0.9.3/src/fs/fs_test_lib.c0000644000175000017500000005453611760502551013623 00000000000000/* This file is part of GNUnet. (C) 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs_test_lib.c * @brief library routines for testing FS publishing and downloading * with multiple peers; this code is limited to flat files * and no keywords (those functions can be tested with * single-peer setups; this is for testing routing). * @author Christian Grothoff */ #include "platform.h" #include "fs_api.h" #include "fs_test_lib.h" #include "gnunet_testing_lib.h" #define CONNECT_ATTEMPTS 4 #define CONTENT_LIFETIME GNUNET_TIME_UNIT_HOURS /** * Handle for a daemon started for testing FS. */ struct GNUNET_FS_TestDaemon { /** * Global configuration, only stored in first test daemon, * otherwise NULL. */ struct GNUNET_CONFIGURATION_Handle *gcfg; /** * Handle to the file sharing context using this daemon. */ struct GNUNET_FS_Handle *fs; /** * Handle to the daemon via testing. */ struct GNUNET_TESTING_Daemon *daemon; /** * Note that 'group' will be the same value for all of the * daemons started jointly. */ struct GNUNET_TESTING_PeerGroup *group; /** * Configuration for accessing this peer. */ struct GNUNET_CONFIGURATION_Handle *cfg; /** * ID of this peer. */ struct GNUNET_PeerIdentity id; /** * Function to call when upload is done. */ GNUNET_FS_TEST_UriContinuation publish_cont; /** * Closure for publish_cont. */ void *publish_cont_cls; /** * Task to abort publishing (timeout). */ GNUNET_SCHEDULER_TaskIdentifier publish_timeout_task; /** * Seed for file generation. */ uint32_t publish_seed; /** * Context for current publishing operation. */ struct GNUNET_FS_PublishContext *publish_context; /** * Result URI. */ struct GNUNET_FS_Uri *publish_uri; /** * Name of the temporary file used, or NULL for none. */ char *publish_tmp_file; /** * Function to call when download is done. */ GNUNET_SCHEDULER_Task download_cont; /** * Closure for download_cont. */ void *download_cont_cls; /** * Seed for download verification. */ uint32_t download_seed; /** * Task to abort downloading (timeout). */ GNUNET_SCHEDULER_TaskIdentifier download_timeout_task; /** * Context for current download operation. */ struct GNUNET_FS_DownloadContext *download_context; /** * Verbosity level of the current operation. */ int verbose; }; /** * Check whether peers successfully shut down. */ static void shutdown_callback (void *cls, const char *emsg) { struct GNUNET_CONFIGURATION_Handle *gcfg = cls; if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Shutdown of peers failed: %s\n", emsg); } else { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); #endif } if (gcfg != NULL) GNUNET_CONFIGURATION_destroy (gcfg); } static void report_uri (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FS_TestDaemon *daemon = cls; GNUNET_FS_TEST_UriContinuation cont; struct GNUNET_FS_Uri *uri; GNUNET_FS_publish_stop (daemon->publish_context); daemon->publish_context = NULL; cont = daemon->publish_cont; daemon->publish_cont = NULL; uri = daemon->publish_uri; cont (daemon->publish_cont_cls, uri); GNUNET_FS_uri_destroy (uri); } static void report_success (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FS_TestDaemon *daemon = cls; GNUNET_FS_download_stop (daemon->download_context, GNUNET_YES); daemon->download_context = NULL; GNUNET_SCHEDULER_add_continuation (daemon->download_cont, daemon->download_cont_cls, GNUNET_SCHEDULER_REASON_PREREQ_DONE); daemon->download_cont = NULL; } static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info) { struct GNUNET_FS_TestDaemon *daemon = cls; switch (info->status) { case GNUNET_FS_STATUS_PUBLISH_COMPLETED: GNUNET_SCHEDULER_cancel (daemon->publish_timeout_task); daemon->publish_timeout_task = GNUNET_SCHEDULER_NO_TASK; daemon->publish_uri = GNUNET_FS_uri_dup (info->value.publish.specifics.completed.chk_uri); GNUNET_SCHEDULER_add_continuation (&report_uri, daemon, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_PUBLISH_PROGRESS: if (daemon->verbose) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Publishing at %llu/%llu bytes\n", (unsigned long long) info->value.publish.completed, (unsigned long long) info->value.publish.size); break; case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: if (daemon->verbose) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Download at %llu/%llu bytes\n", (unsigned long long) info->value.download.completed, (unsigned long long) info->value.download.size); break; case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: GNUNET_SCHEDULER_cancel (daemon->download_timeout_task); daemon->download_timeout_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_SCHEDULER_add_continuation (&report_success, daemon, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: break; /* FIXME: monitor data correctness during download progress */ /* FIXME: do performance reports given sufficient verbosity */ /* FIXME: advance timeout task to "immediate" on error */ default: break; } return NULL; } struct StartContext { struct GNUNET_TIME_Relative timeout; unsigned int total; unsigned int have; struct GNUNET_FS_TestDaemon **daemons; GNUNET_SCHEDULER_Task cont; void *cont_cls; struct GNUNET_TESTING_PeerGroup *group; struct GNUNET_CONFIGURATION_Handle *cfg; GNUNET_SCHEDULER_TaskIdentifier timeout_task; }; static void notify_running (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { struct StartContext *sctx = cls; unsigned int i; if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to start daemon: %s\n"), emsg); return; } i = 0; while (i < sctx->total) { if (GNUNET_TESTING_daemon_get (sctx->group, i) == d) break; i++; } GNUNET_assert (i < sctx->total); GNUNET_assert (sctx->have < sctx->total); GNUNET_assert (sctx->daemons[i]->cfg == NULL); sctx->daemons[i]->cfg = GNUNET_CONFIGURATION_dup (cfg); sctx->daemons[i]->group = sctx->group; sctx->daemons[i]->daemon = d; sctx->daemons[i]->id = *id; sctx->have++; if (sctx->have == sctx->total) { GNUNET_SCHEDULER_add_continuation (sctx->cont, sctx->cont_cls, GNUNET_SCHEDULER_REASON_PREREQ_DONE); sctx->daemons[0]->gcfg = sctx->cfg; GNUNET_SCHEDULER_cancel (sctx->timeout_task); for (i = 0; i < sctx->total; i++) { sctx->daemons[i]->fs = GNUNET_FS_start (sctx->daemons[i]->cfg, "", &progress_cb, sctx->daemons[i], GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); } GNUNET_free (sctx); } } static void start_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct StartContext *sctx = cls; unsigned int i; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout while trying to start daemons\n"); GNUNET_TESTING_daemons_stop (sctx->group, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30), &shutdown_callback, NULL); for (i = 0; i < sctx->total; i++) { if (i < sctx->have) GNUNET_CONFIGURATION_destroy (sctx->daemons[i]->cfg); GNUNET_free (sctx->daemons[i]); sctx->daemons[i] = NULL; } GNUNET_CONFIGURATION_destroy (sctx->cfg); GNUNET_SCHEDULER_add_continuation (sctx->cont, sctx->cont_cls, GNUNET_SCHEDULER_REASON_TIMEOUT); GNUNET_free (sctx); } /** * Start daemons for testing. * * @param template_cfg_file configuration template to use * @param timeout if this operation cannot be completed within the * given period, call the continuation with an error code * @param total number of daemons to start * @param daemons array of 'total' entries to be initialized * (array must already be allocated, will be filled) * @param cont function to call when done * @param cont_cls closure for cont */ void GNUNET_FS_TEST_daemons_start (const char *template_cfg_file, struct GNUNET_TIME_Relative timeout, unsigned int total, struct GNUNET_FS_TestDaemon **daemons, GNUNET_SCHEDULER_Task cont, void *cont_cls) { struct StartContext *sctx; unsigned int i; GNUNET_assert (total > 0); sctx = GNUNET_malloc (sizeof (struct StartContext)); sctx->daemons = daemons; sctx->total = total; sctx->cont = cont; sctx->cont_cls = cont_cls; sctx->cfg = GNUNET_CONFIGURATION_create (); if (GNUNET_OK != GNUNET_CONFIGURATION_load (sctx->cfg, template_cfg_file)) { GNUNET_break (0); GNUNET_CONFIGURATION_destroy (sctx->cfg); GNUNET_free (sctx); GNUNET_SCHEDULER_add_continuation (cont, cont_cls, GNUNET_SCHEDULER_REASON_TIMEOUT); return; } for (i = 0; i < total; i++) daemons[i] = GNUNET_malloc (sizeof (struct GNUNET_FS_TestDaemon)); sctx->group = GNUNET_TESTING_daemons_start (sctx->cfg, total, total, /* Outstanding connections */ total, /* Outstanding ssh connections */ timeout, NULL, NULL, ¬ify_running, sctx, NULL, NULL, NULL); sctx->timeout_task = GNUNET_SCHEDULER_add_delayed (timeout, &start_timeout, sctx); } struct GNUNET_FS_TEST_ConnectContext { GNUNET_SCHEDULER_Task cont; void *cont_cls; struct GNUNET_TESTING_ConnectContext *cc; }; /** * Prototype of a function that will be called whenever * two daemons are connected by the testing library. * * @param cls closure * @param first peer id for first daemon * @param second peer id for the second daemon * @param distance distance between the connected peers * @param first_cfg config for the first daemon * @param second_cfg config for the second daemon * @param first_daemon handle for the first daemon * @param second_daemon handle for the second daemon * @param emsg error message (NULL on success) */ static void notify_connection (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, uint32_t distance, const struct GNUNET_CONFIGURATION_Handle *first_cfg, const struct GNUNET_CONFIGURATION_Handle *second_cfg, struct GNUNET_TESTING_Daemon *first_daemon, struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) { struct GNUNET_FS_TEST_ConnectContext *cc = cls; cc->cc = NULL; if (emsg != NULL) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to connect peers: %s\n", emsg); GNUNET_SCHEDULER_add_continuation (cc->cont, cc->cont_cls, (emsg != NULL) ? GNUNET_SCHEDULER_REASON_TIMEOUT : GNUNET_SCHEDULER_REASON_PREREQ_DONE); GNUNET_free (cc); } /** * Connect two daemons for testing. * * @param daemon1 first daemon to connect * @param daemon2 second first daemon to connect * @param timeout if this operation cannot be completed within the * given period, call the continuation with an error code * @param cont function to call when done * @param cont_cls closure for cont */ struct GNUNET_FS_TEST_ConnectContext * GNUNET_FS_TEST_daemons_connect (struct GNUNET_FS_TestDaemon *daemon1, struct GNUNET_FS_TestDaemon *daemon2, struct GNUNET_TIME_Relative timeout, GNUNET_SCHEDULER_Task cont, void *cont_cls) { struct GNUNET_FS_TEST_ConnectContext *ncc; ncc = GNUNET_malloc (sizeof (struct GNUNET_FS_TEST_ConnectContext)); ncc->cont = cont; ncc->cont_cls = cont_cls; ncc->cc = GNUNET_TESTING_daemons_connect (daemon1->daemon, daemon2->daemon, timeout, CONNECT_ATTEMPTS, GNUNET_YES, ¬ify_connection, ncc); return ncc; } /** * Cancel connect operation. * * @param cc operation to cancel */ void GNUNET_FS_TEST_daemons_connect_cancel (struct GNUNET_FS_TEST_ConnectContext *cc) { GNUNET_TESTING_daemons_connect_cancel (cc->cc); GNUNET_free (cc); } /** * Obtain peer configuration used for testing. * * @param daemons array with the daemons * @param off which configuration to get * @return peer configuration */ const struct GNUNET_CONFIGURATION_Handle * GNUNET_FS_TEST_get_configuration (struct GNUNET_FS_TestDaemon **daemons, unsigned int off) { return daemons[off]->cfg; } /** * Obtain peer group used for testing. * * @param daemons array with the daemons (must contain at least one) * @return peer group */ struct GNUNET_TESTING_PeerGroup * GNUNET_FS_TEST_get_group (struct GNUNET_FS_TestDaemon **daemons) { return daemons[0]->group; } /** * Stop daemons used for testing. * * @param total number of daemons to stop * @param daemons array with the daemons (values will be clobbered) */ void GNUNET_FS_TEST_daemons_stop (unsigned int total, struct GNUNET_FS_TestDaemon **daemons) { unsigned int i; struct GNUNET_TESTING_PeerGroup *pg; struct GNUNET_CONFIGURATION_Handle *gcfg; struct GNUNET_FS_TestDaemon *daemon; GNUNET_assert (total > 0); GNUNET_assert (daemons[0] != NULL); pg = daemons[0]->group; gcfg = daemons[0]->gcfg; for (i = 0; i < total; i++) { daemon = daemons[i]; if (daemon->download_timeout_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (daemon->download_timeout_task); daemon->download_timeout_task = GNUNET_SCHEDULER_NO_TASK; } if (daemon->publish_timeout_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (daemon->publish_timeout_task); daemon->publish_timeout_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != daemon->download_context) { GNUNET_FS_download_stop (daemon->download_context, GNUNET_YES); daemon->download_context = NULL; } if (daemon->fs != NULL) GNUNET_FS_stop (daemon->fs); if (daemon->cfg != NULL) GNUNET_CONFIGURATION_destroy (daemon->cfg); if (NULL != daemon->publish_tmp_file) { GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (daemon->publish_tmp_file)); GNUNET_free (daemon->publish_tmp_file); daemon->publish_tmp_file = NULL; } GNUNET_free (daemon); daemons[i] = NULL; } GNUNET_TESTING_daemons_stop (pg, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30), &shutdown_callback, gcfg); } static void publish_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FS_TestDaemon *daemon = cls; GNUNET_FS_TEST_UriContinuation cont; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout while trying to publish data\n"); cont = daemon->publish_cont; daemon->publish_timeout_task = GNUNET_SCHEDULER_NO_TASK; daemon->publish_cont = NULL; GNUNET_FS_publish_stop (daemon->publish_context); daemon->publish_context = NULL; cont (daemon->publish_cont_cls, NULL); } static size_t file_generator (void *cls, uint64_t offset, size_t max, void *buf, char **emsg) { struct GNUNET_FS_TestDaemon *daemon = cls; uint64_t pos; uint8_t *cbuf = buf; int mod; if (emsg != NULL) *emsg = NULL; if (buf == NULL) return 0; for (pos = 0; pos < 8; pos++) cbuf[pos] = (uint8_t) (offset >> pos * 8); for (pos = 8; pos < max; pos++) { mod = (255 - (offset / 1024 / 32)); if (mod == 0) mod = 1; cbuf[pos] = (uint8_t) ((offset * daemon->publish_seed) % mod); } return max; } /** * Publish a file at the given daemon. * * @param daemon where to publish * @param timeout if this operation cannot be completed within the * given period, call the continuation with an error code * @param anonymity option for publication * @param do_index GNUNET_YES for index, GNUNET_NO for insertion, * GNUNET_SYSERR for simulation * @param size size of the file to publish * @param seed seed to use for file generation * @param verbose how verbose to be in reporting * @param cont function to call when done * @param cont_cls closure for cont */ void GNUNET_FS_TEST_publish (struct GNUNET_FS_TestDaemon *daemon, struct GNUNET_TIME_Relative timeout, uint32_t anonymity, int do_index, uint64_t size, uint32_t seed, unsigned int verbose, GNUNET_FS_TEST_UriContinuation cont, void *cont_cls) { struct GNUNET_FS_FileInformation *fi; struct GNUNET_DISK_FileHandle *fh; char *emsg; uint64_t off; char buf[DBLOCK_SIZE]; size_t bsize; struct GNUNET_FS_BlockOptions bo; GNUNET_assert (daemon->publish_cont == NULL); daemon->publish_cont = cont; daemon->publish_cont_cls = cont_cls; daemon->publish_seed = seed; daemon->verbose = verbose; bo.expiration_time = GNUNET_TIME_relative_to_absolute (CONTENT_LIFETIME); bo.anonymity_level = anonymity; bo.content_priority = 42; bo.replication_level = 1; if (GNUNET_YES == do_index) { GNUNET_assert (daemon->publish_tmp_file == NULL); daemon->publish_tmp_file = GNUNET_DISK_mktemp ("fs-test-publish-index"); GNUNET_assert (daemon->publish_tmp_file != NULL); fh = GNUNET_DISK_file_open (daemon->publish_tmp_file, GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); GNUNET_assert (NULL != fh); off = 0; while (off < size) { bsize = GNUNET_MIN (sizeof (buf), size - off); emsg = NULL; GNUNET_assert (bsize == file_generator (daemon, off, bsize, buf, &emsg)); GNUNET_assert (emsg == NULL); GNUNET_assert (bsize == GNUNET_DISK_file_write (fh, buf, bsize)); off += bsize; } GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); fi = GNUNET_FS_file_information_create_from_file (daemon->fs, daemon, daemon->publish_tmp_file, NULL, NULL, do_index, &bo); } else { fi = GNUNET_FS_file_information_create_from_reader (daemon->fs, daemon, size, &file_generator, daemon, NULL, NULL, do_index, &bo); } daemon->publish_context = GNUNET_FS_publish_start (daemon->fs, fi, NULL, NULL, NULL, GNUNET_FS_PUBLISH_OPTION_NONE); daemon->publish_timeout_task = GNUNET_SCHEDULER_add_delayed (timeout, &publish_timeout, daemon); } static void download_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FS_TestDaemon *daemon = cls; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout while trying to download file\n"); daemon->download_timeout_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_FS_download_stop (daemon->download_context, GNUNET_YES); daemon->download_context = NULL; GNUNET_SCHEDULER_add_continuation (daemon->download_cont, daemon->download_cont_cls, GNUNET_SCHEDULER_REASON_TIMEOUT); daemon->download_cont = NULL; } /** * Perform test download. * * @param daemon which peer to download from * @param timeout if this operation cannot be completed within the * given period, call the continuation with an error code * @param anonymity option for download * @param seed used for file validation * @param uri URI of file to download (CHK/LOC only) * @param verbose how verbose to be in reporting * @param cont function to call when done * @param cont_cls closure for cont */ void GNUNET_FS_TEST_download (struct GNUNET_FS_TestDaemon *daemon, struct GNUNET_TIME_Relative timeout, uint32_t anonymity, uint32_t seed, const struct GNUNET_FS_Uri *uri, unsigned int verbose, GNUNET_SCHEDULER_Task cont, void *cont_cls) { uint64_t size; GNUNET_assert (daemon->download_cont == NULL); size = GNUNET_FS_uri_chk_get_file_size (uri); daemon->verbose = verbose; daemon->download_cont = cont; daemon->download_cont_cls = cont_cls; daemon->download_seed = seed; daemon->download_context = GNUNET_FS_download_start (daemon->fs, uri, NULL, NULL, NULL, 0, size, anonymity, GNUNET_FS_DOWNLOAD_OPTION_NONE, NULL, NULL); daemon->download_timeout_task = GNUNET_SCHEDULER_add_delayed (timeout, &download_timeout, daemon); } /* end of test_fs_lib.c */ gnunet-0.9.3/src/fs/test_fs_file_information_data.conf0000644000175000017500000000024711615567501020070 00000000000000@INLINE@ test_fs_defaults.conf [PATHS] SERVICEHOME = /tmp/gnunet-test-fs-file-information/ DEFAULTCONFIG = test_fs_file_information_data.conf [transport] PLUGINS = gnunet-0.9.3/src/fs/gnunet-service-fs_put.c0000644000175000017500000001652211760502551015553 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-service-fs_put.c * @brief API to PUT zero-anonymity index data from our datastore into the DHT * @author Christian Grothoff */ #include "platform.h" #include "gnunet-service-fs.h" #include "gnunet-service-fs_put.h" /** * How often do we at most PUT content into the DHT? */ #define MAX_DHT_PUT_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) /** * How many replicas do we try to create per PUT? */ #define DEFAULT_PUT_REPLICATION 5 /** * Context for each zero-anonymity iterator. */ struct PutOperator { /** * Request to datastore for DHT PUTs (or NULL). */ struct GNUNET_DATASTORE_QueueEntry *dht_qe; /** * Type we request from the datastore. */ enum GNUNET_BLOCK_Type dht_put_type; /** * Handle to PUT operation. */ struct GNUNET_DHT_PutHandle *dht_put; /** * ID of task that collects blocks for DHT PUTs. */ GNUNET_SCHEDULER_TaskIdentifier dht_task; /** * How many entires with zero anonymity of our type do we currently * estimate to have in the database? */ uint64_t zero_anonymity_count_estimate; /** * Current offset when iterating the database. */ uint64_t current_offset; }; /** * ANY-terminated list of our operators (one per type * of block that we're putting into the DHT). */ static struct PutOperator operators[] = { {NULL, GNUNET_BLOCK_TYPE_FS_KBLOCK, 0, 0, 0}, {NULL, GNUNET_BLOCK_TYPE_FS_SBLOCK, 0, 0, 0}, {NULL, GNUNET_BLOCK_TYPE_FS_NBLOCK, 0, 0, 0}, {NULL, GNUNET_BLOCK_TYPE_ANY, 0, 0, 0} }; /** * Task that is run periodically to obtain blocks for DHT PUTs. * * @param cls type of blocks to gather * @param tc scheduler context (unused) */ static void gather_dht_put_blocks (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Calculate when to run the next PUT operation and schedule it. * * @param po put operator to schedule */ static void schedule_next_put (struct PutOperator *po) { struct GNUNET_TIME_Relative delay; if (po->zero_anonymity_count_estimate > 0) { delay = GNUNET_TIME_relative_divide (GNUNET_DHT_DEFAULT_REPUBLISH_FREQUENCY, po->zero_anonymity_count_estimate); delay = GNUNET_TIME_relative_min (delay, MAX_DHT_PUT_FREQ); } else { /* if we have NO zero-anonymity content yet, wait 5 minutes for some to * (hopefully) appear */ delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5); } po->dht_task = GNUNET_SCHEDULER_add_delayed (delay, &gather_dht_put_blocks, po); } /** * Continuation called after DHT PUT operation has finished. * * @param cls type of blocks to gather * @param success GNUNET_OK if the PUT was transmitted, * GNUNET_NO on timeout, * GNUNET_SYSERR on disconnect from service * after the PUT message was transmitted * (so we don't know if it was received or not) */ static void delay_dht_put_blocks (void *cls, int success) { struct PutOperator *po = cls; po->dht_put = NULL; schedule_next_put (po); } /** * Task that is run periodically to obtain blocks for DHT PUTs. * * @param cls type of blocks to gather * @param tc scheduler context */ static void delay_dht_put_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PutOperator *po = cls; po->dht_task = GNUNET_SCHEDULER_NO_TASK; schedule_next_put (po); } /** * Store content in DHT. * * @param cls closure * @param key key for the content * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param expiration expiration time for the content * @param uid unique identifier for the datum; * maybe 0 if no unique identifier is available */ static void process_dht_put_content (void *cls, const GNUNET_HashCode * key, size_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct PutOperator *po = cls; po->dht_qe = NULL; if (key == NULL) { po->zero_anonymity_count_estimate = po->current_offset - 1; po->current_offset = 0; po->dht_task = GNUNET_SCHEDULER_add_now (&delay_dht_put_task, po); return; } po->zero_anonymity_count_estimate = GNUNET_MAX (po->current_offset, po->zero_anonymity_count_estimate); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Retrieved block `%s' of type %u for DHT PUT\n", GNUNET_h2s (key), type); po->dht_put = GNUNET_DHT_put (GSF_dht, key, DEFAULT_PUT_REPLICATION, GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, type, size, data, expiration, GNUNET_TIME_UNIT_FOREVER_REL, &delay_dht_put_blocks, po); } /** * Task that is run periodically to obtain blocks for DHT PUTs. * * @param cls type of blocks to gather * @param tc scheduler context (unused) */ static void gather_dht_put_blocks (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PutOperator *po = cls; po->dht_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; po->dht_qe = GNUNET_DATASTORE_get_zero_anonymity (GSF_dsh, po->current_offset++, 0, UINT_MAX, GNUNET_TIME_UNIT_FOREVER_REL, po->dht_put_type, &process_dht_put_content, po); if (NULL == po->dht_qe) po->dht_task = GNUNET_SCHEDULER_add_now (&delay_dht_put_task, po); } /** * Setup the module. */ void GSF_put_init_ () { unsigned int i; i = 0; while (operators[i].dht_put_type != GNUNET_BLOCK_TYPE_ANY) { operators[i].dht_task = GNUNET_SCHEDULER_add_now (&gather_dht_put_blocks, &operators[i]); i++; } } /** * Shutdown the module. */ void GSF_put_done_ () { struct PutOperator *po; unsigned int i; i = 0; while ((po = &operators[i])->dht_put_type != GNUNET_BLOCK_TYPE_ANY) { if (GNUNET_SCHEDULER_NO_TASK != po->dht_task) { GNUNET_SCHEDULER_cancel (po->dht_task); po->dht_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != po->dht_put) { GNUNET_DHT_put_cancel (po->dht_put); po->dht_put = NULL; } if (NULL != po->dht_qe) { GNUNET_DATASTORE_cancel (po->dht_qe); po->dht_qe = NULL; } i++; } } /* end of gnunet-service-fs_put.c */ gnunet-0.9.3/src/fs/test_fs_unindex_data.conf0000644000175000017500000000022511615567501016212 00000000000000@INLINE@ test_fs_defaults.conf [PATHS] SERVICEHOME = /tmp/gnunet-test-fs-unindex/ DEFAULTCONFIG = test_fs_unindex_data.conf [transport] PLUGINS = gnunet-0.9.3/src/fs/test_gnunet_fs_ns.py.in0000644000175000017500000000670511760502552015664 00000000000000#!@PYTHON@ # This file is part of GNUnet. # (C) 2010 Christian Grothoff (and other contributing authors) # # GNUnet is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2, or (at your # option) any later version. # # GNUnet is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNUnet; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # Testcase for file-sharing command-line tools (namespaces) import sys import os import subprocess import re import shutil srcdir = "../.." gnunet_pyexpect_dir = os.path.join (srcdir, "contrib") if gnunet_pyexpect_dir not in sys.path: sys.path.append (gnunet_pyexpect_dir) from gnunet_pyexpect import pexpect if os.name == 'posix': pseudonym = 'gnunet-pseudonym' gnunetarm = 'gnunet-arm' publish = 'gnunet-publish' unindex = 'gnunet-unindex' search = 'gnunet-search' elif os.name == 'nt': pseudonym = 'gnunet-pseudonym.exe' gnunetarm = 'gnunet-arm.exe' publish = 'gnunet-publish.exe' unindex = 'gnunet-unindex.exe' search = 'gnunet-search.exe' if os.name == "nt": shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-ns"), True) else: shutil.rmtree ("/tmp/gnunet-test-fs-py-ns", True) arm = subprocess.Popen ([gnunetarm, '-sq', '-c', 'test_gnunet_fs_ns_data.conf']) arm.communicate () try: pseu = pexpect () pseu.spawn (None, [pseudonym, '-c', 'test_gnunet_fs_ns_data.conf', '-C', 'licenses', '-k', 'gplad', '-m', 'description:Free Software Licenses', '-R', 'myroot'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pseu.spawn (None, [pseudonym, '-c', 'test_gnunet_fs_ns_data.conf', '-o'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pseu.expect ("stdout", re.compile (r"licenses (.*)\r?\n")) pub = pexpect () pub.spawn (None, [publish, '-c', 'test_gnunet_fs_ns_data.conf', '-k', 'licenses', '-P', 'licenses', '-u', 'gnunet://fs/chk/PC0M19QMQC0BPSHR6BGA228PP6INER1D610MGEMOMEM87222FN8HVUO7PQGO0O9HD2GVLHF2N5IDHEQUNK6LKE428FPO96SKQEA486O.PG7K85JGQ6N599MD5HEP3CHEVFPKQD9JB6NPSLVA3T1SKDS66CFI499VS6MGQ88B0QUAVT1282TCRD4GGFVUKDLGI8F0SPIANA3J2LG.35147', '-t', 'gpl', '-N', 'gpl3'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) s = pexpect () s.spawn (None, [search, '-V', '-t', '1000', '-N', '1', '-c', 'test_gnunet_fs_ns_data.conf', 'gplad'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) s.expect ("stdout", re.compile (r'#0:\r?\n')) s.expect ("stdout", re.compile (r'gnunet-download gnunet://fs/sks/.*/myroot\r?\n')) s.expect ("stdout", re.compile (r'\s*description: Free Software Licenses\r?\n')) pseu = pexpect () pseu.spawn (None, [pseudonym, '-c', 'test_gnunet_fs_ns_data.conf'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pseu.expect ("stdout", re.compile (r'Free Software Licenses.*:\r?\n')) finally: arm = subprocess.Popen ([gnunetarm, '-eq', '-c', 'test_gnunet_fs_ns_data.conf']) arm.communicate () if os.name == "nt": shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-ns"), True) else: shutil.rmtree ("/tmp/gnunet-test-fs-py-ns", True) gnunet-0.9.3/src/fs/test_fs_namespace_data.conf0000644000175000017500000000023111615567501016471 00000000000000@INLINE@ test_fs_defaults.conf [PATHS] SERVICEHOME = /tmp/gnunet-test-fs-namespace/ DEFAULTCONFIG = test_fs_namespace_data.conf [transport] PLUGINS = gnunet-0.9.3/src/fs/fs_test_lib.h0000644000175000017500000001411311760502551013613 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs_test_lib.h * @brief library routines for testing FS publishing and downloading * with multiple peers; this code is limited to flat files * and no keywords (those functions can be tested with * single-peer setups; this is for testing routing). * @author Christian Grothoff */ #ifndef FS_TEST_LIB_H #define FS_TEST_LIB_H #include "gnunet_util_lib.h" #include "gnunet_fs_service.h" /** * Handle for a daemon started for testing FS. */ struct GNUNET_FS_TestDaemon; /** * Start daemons for testing. * * @param template_cfg_file configuration template to use * @param timeout if this operation cannot be completed within the * given period, call the continuation with an error code * @param total number of daemons to start * @param daemons array of 'total' entries to be initialized * (array must already be allocated, will be filled) * @param cont function to call when done; note that if 'cont' * is called with reason "TIMEOUT", then starting the * daemons has failed and the client MUST NOT call * 'GNUNET_FS_TEST_daemons_stop'! * @param cont_cls closure for cont */ void GNUNET_FS_TEST_daemons_start (const char *template_cfg_file, struct GNUNET_TIME_Relative timeout, unsigned int total, struct GNUNET_FS_TestDaemon **daemons, GNUNET_SCHEDULER_Task cont, void *cont_cls); struct GNUNET_FS_TEST_ConnectContext; /** * Connect two daemons for testing. * * @param daemon1 first daemon to connect * @param daemon2 second first daemon to connect * @param timeout if this operation cannot be completed within the * given period, call the continuation with an error code * @param cont function to call when done * @param cont_cls closure for cont */ struct GNUNET_FS_TEST_ConnectContext * GNUNET_FS_TEST_daemons_connect (struct GNUNET_FS_TestDaemon *daemon1, struct GNUNET_FS_TestDaemon *daemon2, struct GNUNET_TIME_Relative timeout, GNUNET_SCHEDULER_Task cont, void *cont_cls); /** * Cancel connect operation. * * @param cc operation to cancel */ void GNUNET_FS_TEST_daemons_connect_cancel (struct GNUNET_FS_TEST_ConnectContext *cc); /** * Obtain peer group used for testing. * * @param daemons array with the daemons (must contain at least one) * @return peer group */ struct GNUNET_TESTING_PeerGroup * GNUNET_FS_TEST_get_group (struct GNUNET_FS_TestDaemon **daemons); /** * Obtain peer configuration used for testing. * * @param daemons array with the daemons * @param off which configuration to get * @return peer configuration */ const struct GNUNET_CONFIGURATION_Handle * GNUNET_FS_TEST_get_configuration (struct GNUNET_FS_TestDaemon **daemons, unsigned int off); /** * Stop daemons used for testing. * * @param total number of daemons to stop * @param daemons array with the daemons (values will be clobbered) */ void GNUNET_FS_TEST_daemons_stop (unsigned int total, struct GNUNET_FS_TestDaemon **daemons); /** * Function signature. * * @param cls closure (user defined) * @param uri a URI, NULL for errors */ typedef void (*GNUNET_FS_TEST_UriContinuation) (void *cls, const struct GNUNET_FS_Uri * uri); /** * Publish a file at the given daemon. * * @param daemon where to publish * @param timeout if this operation cannot be completed within the * given period, call the continuation with an error code * @param anonymity option for publication * @param do_index GNUNET_YES for index, GNUNET_NO for insertion, * GNUNET_SYSERR for simulation * @param size size of the file to publish * @param seed seed to use for file generation * @param verbose how verbose to be in reporting * @param cont function to call when done * @param cont_cls closure for cont */ void GNUNET_FS_TEST_publish (struct GNUNET_FS_TestDaemon *daemon, struct GNUNET_TIME_Relative timeout, uint32_t anonymity, int do_index, uint64_t size, uint32_t seed, unsigned int verbose, GNUNET_FS_TEST_UriContinuation cont, void *cont_cls); /** * Perform test download. * * @param daemon which peer to download from * @param timeout if this operation cannot be completed within the * given period, call the continuation with an error code * @param anonymity option for download * @param seed used for file validation * @param uri URI of file to download (CHK/LOC only) * @param verbose how verbose to be in reporting * @param cont function to call when done * @param cont_cls closure for cont */ void GNUNET_FS_TEST_download (struct GNUNET_FS_TestDaemon *daemon, struct GNUNET_TIME_Relative timeout, uint32_t anonymity, uint32_t seed, const struct GNUNET_FS_Uri *uri, unsigned int verbose, GNUNET_SCHEDULER_Task cont, void *cont_cls); #endif gnunet-0.9.3/src/fs/gnunet-fs.c0000644000175000017500000000633611760502551013227 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-fs.c * @brief special file-sharing functions * @author Christian Grothoff */ #include "platform.h" #include "gnunet_fs_service.h" /** * Return value. */ static int ret; /** * Handle to FS service. */ static struct GNUNET_FS_Handle *fs; /** * Option -i given? */ static int list_indexed_files; /** * Option -v given? */ static int verbose; /** * Print indexed filenames to stdout. * * @param cls closure * @param filename the name of the file * @param file_id hash of the contents of the indexed file * @return GNUNET_OK to continue iteration */ static int print_indexed (void *cls, const char *filename, const GNUNET_HashCode * file_id) { if (NULL == filename) { GNUNET_FS_stop (fs); fs = NULL; return GNUNET_OK; } if (verbose) FPRINTF (stdout, "%s: %s\n", GNUNET_h2s (file_id), filename); else FPRINTF (stdout, "%s\n", filename); return GNUNET_OK; } /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param cfg configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { if (list_indexed_files) { fs = GNUNET_FS_start (cfg, "gnunet-fs", NULL, NULL, GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); if (NULL == fs) { ret = 1; return; } if (NULL == GNUNET_FS_get_indexed_files (fs, &print_indexed, NULL)) { ret = 2; GNUNET_FS_stop (fs); fs = NULL; return; } } } /** * The main function to access special file-sharing functions. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { static struct GNUNET_GETOPT_CommandLineOption options[] = { {'i', "list-indexed", NULL, gettext_noop ("print a list of all indexed files"), 0, &GNUNET_GETOPT_set_one, &list_indexed_files}, GNUNET_GETOPT_OPTION_VERBOSE (&verbose), GNUNET_GETOPT_OPTION_END }; return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-fs [OPTIONS]", gettext_noop ("Special file-sharing operations"), options, &run, NULL)) ? ret : 1; } /* end of gnunet-fs.c */ gnunet-0.9.3/src/fs/fs_namespace.c0000644000175000017500000006615011760502551013745 00000000000000/* This file is part of GNUnet (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs_namespace.c * @brief create and destroy namespaces * @author Christian Grothoff */ #include "platform.h" #include "gnunet_constants.h" #include "gnunet_signatures.h" #include "gnunet_util_lib.h" #include "gnunet_fs_service.h" #include "fs_api.h" /** * Maximum legal size for an sblock. */ #define MAX_SBLOCK_SIZE (60 * 1024) /** * Return the name of the directory in which we store * our local namespaces (or rather, their public keys). * * @param h global fs handle * @return NULL on error, otherwise the name of the directory */ static char * get_namespace_directory (struct GNUNET_FS_Handle *h) { char *dn; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (h->cfg, "FS", "IDENTITY_DIR", &dn)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Configuration fails to specify `%s' in section `%s'\n"), "IDENTITY_DIR", "fs"); return NULL; } return dn; } /** * Return the name of the directory in which we store * the update information graph for the given local namespace. * * @param ns namespace handle * @return NULL on error, otherwise the name of the directory */ static char * get_update_information_directory (struct GNUNET_FS_Namespace *ns) { char *dn; char *ret; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (ns->h->cfg, "FS", "UPDATE_DIR", &dn)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Configuration fails to specify `%s' in section `%s'\n"), "UPDATE_DIR", "fs"); return NULL; } GNUNET_asprintf (&ret, "%s%s%s", dn, DIR_SEPARATOR_STR, ns->name); GNUNET_free (dn); return ret; } /** * Write the namespace update node graph to a file. * * @param ns namespace to dump */ static void write_update_information_graph (struct GNUNET_FS_Namespace *ns) { char *fn; struct GNUNET_BIO_WriteHandle *wh; unsigned int i; struct NamespaceUpdateNode *n; char *uris; fn = get_update_information_directory (ns); wh = GNUNET_BIO_write_open (fn); if (wh == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to open `%s' for writing: %s\n"), STRERROR (errno)); GNUNET_free (fn); return; } if (GNUNET_OK != GNUNET_BIO_write_int32 (wh, ns->update_node_count)) goto END; for (i = 0; i < ns->update_node_count; i++) { n = ns->update_nodes[i]; uris = GNUNET_FS_uri_to_string (n->uri); if ((GNUNET_OK != GNUNET_BIO_write_string (wh, n->id)) || (GNUNET_OK != GNUNET_BIO_write_meta_data (wh, n->md)) || (GNUNET_OK != GNUNET_BIO_write_string (wh, n->update)) || (GNUNET_OK != GNUNET_BIO_write_string (wh, uris))) { GNUNET_free (uris); break; } GNUNET_free (uris); } END: if (GNUNET_OK != GNUNET_BIO_write_close (wh)) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to write `%s': %s\n"), STRERROR (errno)); GNUNET_free (fn); } /** * Read the namespace update node graph from a file. * * @param ns namespace to read */ static void read_update_information_graph (struct GNUNET_FS_Namespace *ns) { char *fn; struct GNUNET_BIO_ReadHandle *rh; unsigned int i; struct NamespaceUpdateNode *n; char *uris; uint32_t count; char *emsg; fn = get_update_information_directory (ns); if (GNUNET_YES != GNUNET_DISK_file_test (fn)) { GNUNET_free (fn); return; } rh = GNUNET_BIO_read_open (fn); if (rh == NULL) { GNUNET_free (fn); return; } if (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &count)) { GNUNET_break (0); goto END; } if (count > 1024 * 1024) { GNUNET_break (0); goto END; } if (count == 0) { GNUNET_break (GNUNET_OK == GNUNET_BIO_read_close (rh, NULL)); GNUNET_free (fn); return; } ns->update_nodes = GNUNET_malloc (count * sizeof (struct NamespaceUpdateNode *)); for (i = 0; i < count; i++) { n = GNUNET_malloc (sizeof (struct NamespaceUpdateNode)); if ((GNUNET_OK != GNUNET_BIO_read_string (rh, "identifier", &n->id, 1024)) || (GNUNET_OK != GNUNET_BIO_read_meta_data (rh, "meta", &n->md)) || (GNUNET_OK != GNUNET_BIO_read_string (rh, "update-id", &n->update, 1024)) || (GNUNET_OK != GNUNET_BIO_read_string (rh, "uri", &uris, 1024 * 2))) { GNUNET_break (0); GNUNET_free_non_null (n->id); GNUNET_free_non_null (n->update); if (n->md != NULL) GNUNET_CONTAINER_meta_data_destroy (n->md); GNUNET_free (n); break; } n->uri = GNUNET_FS_uri_parse (uris, &emsg); GNUNET_free (uris); if (n->uri == NULL) { GNUNET_break (0); GNUNET_free (emsg); GNUNET_free (n->id); GNUNET_free_non_null (n->update); GNUNET_CONTAINER_meta_data_destroy (n->md); GNUNET_free (n); break; } ns->update_nodes[i] = n; } ns->update_node_count = i; END: if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to write `%s': %s\n"), emsg); GNUNET_free (emsg); } GNUNET_free (fn); } /** * Create a namespace with the given name; if one already * exists, return a handle to the existing namespace. * * @param h handle to the file sharing subsystem * @param name name to use for the namespace * @return handle to the namespace, NULL on error */ struct GNUNET_FS_Namespace * GNUNET_FS_namespace_create (struct GNUNET_FS_Handle *h, const char *name) { char *dn; char *fn; struct GNUNET_FS_Namespace *ret; dn = get_namespace_directory (h); GNUNET_asprintf (&fn, "%s%s%s", dn, DIR_SEPARATOR_STR, name); GNUNET_free (dn); ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Namespace)); ret->h = h; ret->rc = 1; ret->key = GNUNET_CRYPTO_rsa_key_create_from_file (fn); if (ret->key == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to create or read private key for namespace `%s'\n"), name); GNUNET_free (ret); GNUNET_free (fn); return NULL; } ret->name = GNUNET_strdup (name); ret->filename = fn; return ret; } /** * Duplicate a namespace handle. * * @param ns namespace handle * @return duplicated handle to the namespace */ struct GNUNET_FS_Namespace * GNUNET_FS_namespace_dup (struct GNUNET_FS_Namespace *ns) { ns->rc++; return ns; } /** * Delete a namespace handle. Can be used for a clean shutdown (free * memory) or also to freeze the namespace to prevent further * insertions by anyone. * * @param namespace handle to the namespace that should be deleted / freed * @param freeze prevents future insertions; creating a namespace * with the same name again will create a fresh namespace instead * * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_FS_namespace_delete (struct GNUNET_FS_Namespace *namespace, int freeze) { unsigned int i; struct NamespaceUpdateNode *nsn; namespace->rc--; if (freeze) { if (0 != UNLINK (namespace->filename)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "unlink", namespace->filename); } if (0 != namespace->rc) return GNUNET_OK; GNUNET_CRYPTO_rsa_key_free (namespace->key); GNUNET_free (namespace->filename); GNUNET_free (namespace->name); for (i = 0; i < namespace->update_node_count; i++) { nsn = namespace->update_nodes[i]; GNUNET_CONTAINER_meta_data_destroy (nsn->md); GNUNET_FS_uri_destroy (nsn->uri); GNUNET_free (nsn->id); GNUNET_free (nsn->update); GNUNET_free (nsn); } GNUNET_array_grow (namespace->update_nodes, namespace->update_node_count, 0); if (namespace->update_map != NULL) GNUNET_CONTAINER_multihashmap_destroy (namespace->update_map); GNUNET_free (namespace); return GNUNET_OK; } /** * Context for the 'process_namespace' callback. * Specifies a function to call on each namespace. */ struct ProcessNamespaceContext { /** * Function to call. */ GNUNET_FS_NamespaceInfoProcessor cb; /** * Closure for 'cb'. */ void *cb_cls; }; /** * Function called with a filename of a namespace. Reads the key and * calls the callback. * * @param cls closure (struct ProcessNamespaceContext) * @param filename complete filename (absolute path) * @return GNUNET_OK to continue to iterate, * GNUNET_SYSERR to abort iteration with error! */ static int process_namespace (void *cls, const char *filename) { struct ProcessNamespaceContext *pnc = cls; struct GNUNET_CRYPTO_RsaPrivateKey *key; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk; GNUNET_HashCode id; const char *name; const char *t; key = GNUNET_CRYPTO_rsa_key_create_from_file (filename); if (key == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Failed to read namespace private key file `%s', deleting it!\n"), filename); if (0 != UNLINK (filename)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename); return GNUNET_OK; } GNUNET_CRYPTO_rsa_key_get_public (key, &pk); GNUNET_CRYPTO_rsa_key_free (key); GNUNET_CRYPTO_hash (&pk, sizeof (pk), &id); name = filename; while (NULL != (t = strstr (name, DIR_SEPARATOR_STR))) name = t + 1; pnc->cb (pnc->cb_cls, name, &id); return GNUNET_OK; } /** * Build a list of all available local (!) namespaces The returned * names are only the nicknames since we only iterate over the local * namespaces. * * @param h handle to the file sharing subsystem * @param cb function to call on each known namespace * @param cb_cls closure for cb */ void GNUNET_FS_namespace_list (struct GNUNET_FS_Handle *h, GNUNET_FS_NamespaceInfoProcessor cb, void *cb_cls) { char *dn; struct ProcessNamespaceContext ctx; dn = get_namespace_directory (h); if (dn == NULL) return; ctx.cb = cb; ctx.cb_cls = cb_cls; GNUNET_DISK_directory_scan (dn, &process_namespace, &ctx); GNUNET_free (dn); } /** * Context for the SKS publication. */ struct GNUNET_FS_PublishSksContext { /** * URI of the new entry in the namespace. */ struct GNUNET_FS_Uri *uri; /** * Namespace update node to add to namespace on success (or to be * deleted if publishing failed). */ struct NamespaceUpdateNode *nsn; /** * Namespace we're publishing to. */ struct GNUNET_FS_Namespace *namespace; /** * Handle to the datastore. */ struct GNUNET_DATASTORE_Handle *dsh; /** * Function to call once we're done. */ GNUNET_FS_PublishContinuation cont; /** * Closure for cont. */ void *cont_cls; /** * Handle for our datastore request. */ struct GNUNET_DATASTORE_QueueEntry *dqe; }; /** * Function called by the datastore API with * the result from the PUT (SBlock) request. * * @param cls closure of type "struct GNUNET_FS_PublishSksContext*" * @param success GNUNET_OK on success * @param min_expiration minimum expiration time required for content to be stored * @param msg error message (or NULL) */ static void sb_put_cont (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) { struct GNUNET_FS_PublishSksContext *psc = cls; GNUNET_HashCode hc; psc->dqe = NULL; if (GNUNET_OK != success) { if (NULL != psc->cont) psc->cont (psc->cont_cls, NULL, msg); GNUNET_FS_publish_sks_cancel (psc); return; } if (NULL != psc->nsn) { /* FIXME: this can be done much more * efficiently by simply appending to the * file and overwriting the 4-byte header */ if (psc->namespace->update_nodes == NULL) read_update_information_graph (psc->namespace); GNUNET_array_append (psc->namespace->update_nodes, psc->namespace->update_node_count, psc->nsn); if (psc->namespace->update_map != NULL) { GNUNET_CRYPTO_hash (psc->nsn->id, strlen (psc->nsn->id), &hc); GNUNET_CONTAINER_multihashmap_put (psc->namespace->update_map, &hc, psc->nsn, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); } psc->nsn = NULL; write_update_information_graph (psc->namespace); } if (NULL != psc->cont) psc->cont (psc->cont_cls, psc->uri, NULL); GNUNET_FS_publish_sks_cancel (psc); } /** * Publish an SBlock on GNUnet. * * @param h handle to the file sharing subsystem * @param namespace namespace to publish in * @param identifier identifier to use * @param update update identifier to use * @param meta metadata to use * @param uri URI to refer to in the SBlock * @param bo block options * @param options publication options * @param cont continuation * @param cont_cls closure for cont * @return NULL on error ('cont' will still be called) */ struct GNUNET_FS_PublishSksContext * GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h, struct GNUNET_FS_Namespace *namespace, const char *identifier, const char *update, const struct GNUNET_CONTAINER_MetaData *meta, const struct GNUNET_FS_Uri *uri, const struct GNUNET_FS_BlockOptions *bo, enum GNUNET_FS_PublishOptions options, GNUNET_FS_PublishContinuation cont, void *cont_cls) { struct GNUNET_FS_PublishSksContext *psc; struct GNUNET_CRYPTO_AesSessionKey sk; struct GNUNET_CRYPTO_AesInitializationVector iv; struct GNUNET_FS_Uri *sks_uri; char *uris; size_t size; size_t slen; size_t nidlen; size_t idlen; ssize_t mdsize; struct SBlock *sb; struct SBlock *sb_enc; char *dest; struct GNUNET_CONTAINER_MetaData *mmeta; GNUNET_HashCode key; /* hash of thisId = key */ GNUNET_HashCode id; /* hash of hc = identifier */ GNUNET_HashCode query; /* id ^ nsid = DB query */ if (NULL == meta) mmeta = GNUNET_CONTAINER_meta_data_create (); else mmeta = GNUNET_CONTAINER_meta_data_duplicate (meta); uris = GNUNET_FS_uri_to_string (uri); slen = strlen (uris) + 1; idlen = strlen (identifier); if (update != NULL) nidlen = strlen (update) + 1; else nidlen = 1; mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (mmeta); size = sizeof (struct SBlock) + slen + nidlen + mdsize; if (size > MAX_SBLOCK_SIZE) { size = MAX_SBLOCK_SIZE; mdsize = size - (sizeof (struct SBlock) + slen + nidlen); } sb = GNUNET_malloc (sizeof (struct SBlock) + size); dest = (char *) &sb[1]; if (update != NULL) memcpy (dest, update, nidlen); else memset (dest, 0, 1); dest += nidlen; memcpy (dest, uris, slen); GNUNET_free (uris); dest += slen; mdsize = GNUNET_CONTAINER_meta_data_serialize (mmeta, &dest, mdsize, GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); GNUNET_CONTAINER_meta_data_destroy (mmeta); if (mdsize == -1) { GNUNET_break (0); GNUNET_free (sb); if (NULL != cont) cont (cont_cls, NULL, _("Internal error.")); return NULL; } size = sizeof (struct SBlock) + mdsize + slen + nidlen; sb_enc = GNUNET_malloc (size); GNUNET_CRYPTO_hash (identifier, idlen, &key); GNUNET_CRYPTO_hash (&key, sizeof (GNUNET_HashCode), &id); sks_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); sks_uri->type = sks; GNUNET_CRYPTO_rsa_key_get_public (namespace->key, &sb_enc->subspace); GNUNET_CRYPTO_hash (&sb_enc->subspace, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &sks_uri->data.sks.namespace); sks_uri->data.sks.identifier = GNUNET_strdup (identifier); GNUNET_CRYPTO_hash_xor (&id, &sks_uri->data.sks.namespace, &sb_enc->identifier); GNUNET_CRYPTO_hash_to_aes_key (&key, &sk, &iv); GNUNET_CRYPTO_aes_encrypt (&sb[1], size - sizeof (struct SBlock), &sk, &iv, &sb_enc[1]); sb_enc->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_SBLOCK); sb_enc->purpose.size = htonl (slen + mdsize + nidlen + sizeof (struct SBlock) - sizeof (struct GNUNET_CRYPTO_RsaSignature)); GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_rsa_sign (namespace->key, &sb_enc->purpose, &sb_enc->signature)); psc = GNUNET_malloc (sizeof (struct GNUNET_FS_PublishSksContext)); psc->uri = sks_uri; psc->cont = cont; psc->namespace = GNUNET_FS_namespace_dup (namespace); psc->cont_cls = cont_cls; if (0 != (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) { GNUNET_free (sb_enc); GNUNET_free (sb); sb_put_cont (psc, GNUNET_OK, GNUNET_TIME_UNIT_ZERO_ABS, NULL); return NULL; } psc->dsh = GNUNET_DATASTORE_connect (h->cfg); if (NULL == psc->dsh) { GNUNET_free (sb_enc); GNUNET_free (sb); sb_put_cont (psc, GNUNET_NO, GNUNET_TIME_UNIT_ZERO_ABS, _("Failed to connect to datastore.")); return NULL; } GNUNET_CRYPTO_hash_xor (&sks_uri->data.sks.namespace, &id, &query); if (NULL != update) { psc->nsn = GNUNET_malloc (sizeof (struct NamespaceUpdateNode)); psc->nsn->id = GNUNET_strdup (identifier); psc->nsn->update = GNUNET_strdup (update); psc->nsn->md = GNUNET_CONTAINER_meta_data_duplicate (meta); psc->nsn->uri = GNUNET_FS_uri_dup (uri); } psc->dqe = GNUNET_DATASTORE_put (psc->dsh, 0, &sb_enc->identifier, size, sb_enc, GNUNET_BLOCK_TYPE_FS_SBLOCK, bo->content_priority, bo->anonymity_level, bo->replication_level, bo->expiration_time, -2, 1, GNUNET_CONSTANTS_SERVICE_TIMEOUT, &sb_put_cont, psc); GNUNET_free (sb); GNUNET_free (sb_enc); return psc; } /** * Abort the SKS publishing operation. * * @param psc context of the operation to abort. */ void GNUNET_FS_publish_sks_cancel (struct GNUNET_FS_PublishSksContext *psc) { if (NULL != psc->dqe) { GNUNET_DATASTORE_cancel (psc->dqe); psc->dqe = NULL; } if (NULL != psc->dsh) { GNUNET_DATASTORE_disconnect (psc->dsh, GNUNET_NO); psc->dsh = NULL; } GNUNET_FS_namespace_delete (psc->namespace, GNUNET_NO); GNUNET_FS_uri_destroy (psc->uri); if (NULL != psc->nsn) { GNUNET_CONTAINER_meta_data_destroy (psc->nsn->md); GNUNET_FS_uri_destroy (psc->nsn->uri); GNUNET_free (psc->nsn->id); GNUNET_free (psc->nsn->update); GNUNET_free (psc->nsn); } GNUNET_free (psc); } /** * Closure for 'process_update_node'. */ struct ProcessUpdateClosure { /** * Function to call for each node. */ GNUNET_FS_IdentifierProcessor ip; /** * Closure for 'ip'. */ void *ip_cls; }; /** * Call the iterator in the closure for each node. * * @param cls closure (of type 'struct ProcessUpdateClosure *') * @param key current key code * @param value value in the hash map (of type 'struct NamespaceUpdateNode *') * @return GNUNET_YES if we should continue to * iterate, * GNUNET_NO if not. */ static int process_update_node (void *cls, const GNUNET_HashCode * key, void *value) { struct ProcessUpdateClosure *pc = cls; struct NamespaceUpdateNode *nsn = value; pc->ip (pc->ip_cls, nsn->id, nsn->uri, nsn->md, nsn->update); return GNUNET_YES; } /** * Closure for 'find_trees'. */ struct FindTreeClosure { /** * Namespace we are operating on. */ struct GNUNET_FS_Namespace *namespace; /** * Array with 'head's of TREEs. */ struct NamespaceUpdateNode **tree_array; /** * Size of 'tree_array' */ unsigned int tree_array_size; /** * Current generational ID used. */ unsigned int nug; /** * Identifier for the current TREE, or UINT_MAX for none yet. */ unsigned int id; }; /** * Find all nodes reachable from the current node (including the * current node itself). If they are in no tree, add them to the * current one. If they are the head of another tree, merge the * trees. If they are in the middle of another tree, let them be. * We can tell that a node is already in an tree by checking if * its 'nug' field is set to the current 'nug' value. It is the * head of an tree if it is in the 'tree_array' under its respective * 'tree_id'. * * In short, we're trying to find the smallest number of tree to * cover a directed graph. * * @param cls closure (of type 'struct FindTreeClosure') * @param key current key code * @param value value in the hash map * @return GNUNET_YES if we should continue to * iterate, * GNUNET_NO if not. */ static int find_trees (void *cls, const GNUNET_HashCode * key, void *value) { struct FindTreeClosure *fc = cls; struct NamespaceUpdateNode *nsn = value; GNUNET_HashCode hc; if (nsn->nug == fc->nug) { if (nsn->tree_id == UINT_MAX) return GNUNET_YES; /* circular */ GNUNET_assert (nsn->tree_id < fc->tree_array_size); if (fc->tree_array[nsn->tree_id] != nsn) return GNUNET_YES; /* part of "another" (directed) TREE, * and not root of it, end trace */ if (nsn->tree_id == fc->id) return GNUNET_YES; /* that's our own root (can this be?) */ /* merge existing TREE, we have a root for both */ fc->tree_array[nsn->tree_id] = NULL; if (fc->id == UINT_MAX) fc->id = nsn->tree_id; /* take over ID */ } else { nsn->nug = fc->nug; nsn->tree_id = UINT_MAX; /* mark as undef */ /* trace */ GNUNET_CRYPTO_hash (nsn->update, strlen (nsn->update), &hc); GNUNET_CONTAINER_multihashmap_get_multiple (fc->namespace->update_map, &hc, &find_trees, fc); } return GNUNET_YES; } /** * List all of the identifiers in the namespace for which we could * produce an update. Namespace updates form a graph where each node * has a name. Each node can have any number of URI/meta-data entries * which can each be linked to other nodes. Cycles are possible. * * Calling this function with "next_id" NULL will cause the library to * call "ip" with a root for each strongly connected component of the * graph (a root being a node from which all other nodes in the Tree * are reachable). * * Calling this function with "next_id" being the name of a node will * cause the library to call "ip" with all children of the node. Note * that cycles within the final tree are possible (including self-loops). * I know, odd definition of a tree, but the GUI will display an actual * tree (GtkTreeView), so that's what counts for the term here. * * @param namespace namespace to inspect for updateable content * @param next_id ID to look for; use NULL to look for tree roots * @param ip function to call on each updateable identifier * @param ip_cls closure for ip */ void GNUNET_FS_namespace_list_updateable (struct GNUNET_FS_Namespace *namespace, const char *next_id, GNUNET_FS_IdentifierProcessor ip, void *ip_cls) { unsigned int i; unsigned int nug; GNUNET_HashCode hc; struct NamespaceUpdateNode *nsn; struct ProcessUpdateClosure pc; struct FindTreeClosure fc; if (namespace->update_nodes == NULL) read_update_information_graph (namespace); if (namespace->update_nodes == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No updateable nodes found for ID `%s'\n", next_id); return; /* no nodes */ } if (namespace->update_map == NULL) { /* need to construct */ namespace->update_map = GNUNET_CONTAINER_multihashmap_create (2 + 3 * namespace->update_node_count / 4); for (i = 0; i < namespace->update_node_count; i++) { nsn = namespace->update_nodes[i]; GNUNET_CRYPTO_hash (nsn->id, strlen (nsn->id), &hc); GNUNET_CONTAINER_multihashmap_put (namespace->update_map, &hc, nsn, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); } } if (next_id != NULL) { GNUNET_CRYPTO_hash (next_id, strlen (next_id), &hc); pc.ip = ip; pc.ip_cls = ip_cls; GNUNET_CONTAINER_multihashmap_get_multiple (namespace->update_map, &hc, &process_update_node, &pc); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calculating TREEs to find roots of update trees\n"); /* Find heads of TREEs in update graph */ nug = ++namespace->nug_gen; fc.tree_array = NULL; fc.tree_array_size = 0; for (i = 0; i < namespace->update_node_count; i++) { nsn = namespace->update_nodes[i]; if (nsn->nug == nug) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TREE of node `%s' is %u\n", nsn->id, nsn->nug); continue; /* already placed in TREE */ } GNUNET_CRYPTO_hash (nsn->update, strlen (nsn->update), &hc); nsn->nug = nug; nsn->tree_id = UINT_MAX; fc.id = UINT_MAX; fc.nug = nug; fc.namespace = namespace; GNUNET_CONTAINER_multihashmap_get_multiple (namespace->update_map, &hc, &find_trees, &fc); if (fc.id == UINT_MAX) { /* start new TREE */ for (fc.id = 0; fc.id < fc.tree_array_size; fc.id++) { if (fc.tree_array[fc.id] == NULL) { fc.tree_array[fc.id] = nsn; nsn->tree_id = fc.id; break; } } if (fc.id == fc.tree_array_size) { GNUNET_array_append (fc.tree_array, fc.tree_array_size, nsn); nsn->tree_id = fc.id; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting new TREE %u with node `%s'\n", nsn->tree_id, nsn->id); /* put all nodes with same identifier into this TREE */ GNUNET_CRYPTO_hash (nsn->id, strlen (nsn->id), &hc); fc.id = nsn->tree_id; fc.nug = nug; fc.namespace = namespace; GNUNET_CONTAINER_multihashmap_get_multiple (namespace->update_map, &hc, &find_trees, &fc); } else { /* make head of TREE "id" */ fc.tree_array[fc.id] = nsn; nsn->tree_id = fc.id; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TREE of node `%s' is %u\n", nsn->id, fc.id); } for (i = 0; i < fc.tree_array_size; i++) { nsn = fc.tree_array[i]; if (NULL != nsn) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Root of TREE %u is node `%s'\n", i, nsn->id); ip (ip_cls, nsn->id, nsn->uri, nsn->md, nsn->update); } } GNUNET_array_grow (fc.tree_array, fc.tree_array_size, 0); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Done processing TREEs\n"); } /* end of fs_namespace.c */ gnunet-0.9.3/src/fs/gnunet-search.c0000644000175000017500000002271211760502551014060 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-search.c * @brief searching for files on GNUnet * @author Christian Grothoff * @author Krista Bennett * @author James Blackwell * @author Igor Wronsky */ #include "platform.h" #include "gnunet_fs_service.h" static int ret; static const struct GNUNET_CONFIGURATION_Handle *cfg; static struct GNUNET_FS_Handle *ctx; static struct GNUNET_FS_SearchContext *sc; static char *output_filename; static struct GNUNET_FS_DirectoryBuilder *db; static unsigned int anonymity = 1; static unsigned long long timeout; static unsigned int results_limit; static unsigned int results = 0; static int verbose; static int local_only; /** * Type of a function that libextractor calls for each * meta data item found. * * @param cls closure (user-defined, unused) * @param plugin_name name of the plugin that produced this value; * special values can be used (i.e. '<zlib>' for zlib being * used in the main libextractor library and yielding * meta data). * @param type libextractor-type describing the meta data * @param format basic format information about data * @param data_mime_type mime-type of data (not of the original file); * can be NULL (if mime-type is not known) * @param data actual meta-data found * @param data_size number of bytes in data * @return 0 to continue extracting, 1 to abort */ static int item_printer (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat format, const char *data_mime_type, const char *data, size_t data_size) { if ((format != EXTRACTOR_METAFORMAT_UTF8) && (format != EXTRACTOR_METAFORMAT_C_STRING)) return 0; if (type == EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME) return 0; printf ("\t%20s: %s\n", dgettext (LIBEXTRACTOR_GETTEXT_DOMAIN, EXTRACTOR_metatype_to_string (type)), data); return 0; } static void clean_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { size_t dsize; void *ddata; GNUNET_FS_stop (ctx); ctx = NULL; if (output_filename == NULL) return; if (GNUNET_OK != GNUNET_FS_directory_builder_finish (db, &dsize, &ddata)) { GNUNET_break (0); GNUNET_free (output_filename); return; } if (dsize != GNUNET_DISK_fn_write (output_filename, ddata, dsize, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)) { FPRINTF (stderr, _("Failed to write directory with search results to `%s'\n"), output_filename); } GNUNET_free_non_null (ddata); GNUNET_free (output_filename); } /** * Called by FS client to give information about the progress of an * operation. * * @param cls closure * @param info details about the event, specifying the event type * and various bits about the event * @return client-context (for the next progress call * for this operation; should be set to NULL for * SUSPEND and STOPPED events). The value returned * will be passed to future callbacks in the respective * field in the GNUNET_FS_ProgressInfo struct. */ static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info) { static unsigned int cnt; char *uri; char *dotdot; char *filename; switch (info->status) { case GNUNET_FS_STATUS_SEARCH_START: break; case GNUNET_FS_STATUS_SEARCH_RESULT: if (db != NULL) GNUNET_FS_directory_builder_add (db, info->value.search.specifics.result.uri, info->value.search.specifics.result.meta, NULL); uri = GNUNET_FS_uri_to_string (info->value.search.specifics.result.uri); printf ("#%u:\n", cnt++); filename = GNUNET_CONTAINER_meta_data_get_by_type (info->value.search. specifics.result.meta, EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME); if (filename != NULL) { while (NULL != (dotdot = strstr (filename, ".."))) dotdot[0] = dotdot[1] = '_'; printf ("gnunet-download -o \"%s\" %s\n", filename, uri); } else printf ("gnunet-download %s\n", uri); if (verbose) GNUNET_CONTAINER_meta_data_iterate (info->value.search.specifics. result.meta, &item_printer, NULL); printf ("\n"); fflush (stdout); GNUNET_free_non_null (filename); GNUNET_free (uri); results++; if ((results_limit > 0) && (results >= results_limit)) GNUNET_SCHEDULER_shutdown (); break; case GNUNET_FS_STATUS_SEARCH_UPDATE: break; case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED: /* ignore */ break; case GNUNET_FS_STATUS_SEARCH_ERROR: FPRINTF (stderr, _("Error searching: %s.\n"), info->value.search.specifics.error.message); GNUNET_SCHEDULER_shutdown (); break; case GNUNET_FS_STATUS_SEARCH_STOPPED: GNUNET_SCHEDULER_add_continuation (&clean_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; default: FPRINTF (stderr, _("Unexpected status: %d\n"), info->status); break; } return NULL; } static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (sc != NULL) { GNUNET_FS_search_stop (sc); sc = NULL; } } /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param c configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { struct GNUNET_FS_Uri *uri; unsigned int argc; enum GNUNET_FS_SearchOptions options; struct GNUNET_TIME_Relative delay; argc = 0; while (NULL != args[argc]) argc++; uri = GNUNET_FS_uri_ksk_create_from_args (argc, (const char **) args); if (NULL == uri) { FPRINTF (stderr, "%s", _("Could not create keyword URI from arguments.\n")); ret = 1; return; } cfg = c; ctx = GNUNET_FS_start (cfg, "gnunet-search", &progress_cb, NULL, GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); if (NULL == ctx) { FPRINTF (stderr, _("Could not initialize `%s' subsystem.\n"), "FS"); GNUNET_FS_uri_destroy (uri); ret = 1; return; } if (output_filename != NULL) db = GNUNET_FS_directory_builder_create (NULL); options = GNUNET_FS_SEARCH_OPTION_NONE; if (local_only) options |= GNUNET_FS_SEARCH_OPTION_LOOPBACK_ONLY; sc = GNUNET_FS_search_start (ctx, uri, anonymity, options, NULL); GNUNET_FS_uri_destroy (uri); if (NULL == sc) { FPRINTF (stderr, "%s", _("Could not start searching.\n")); GNUNET_FS_stop (ctx); ret = 1; return; } if (timeout != 0) { delay.rel_value = timeout; GNUNET_SCHEDULER_add_delayed (delay, &shutdown_task, NULL); } else { GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); } } /** * The main function to search GNUnet. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { {'a', "anonymity", "LEVEL", gettext_noop ("set the desired LEVEL of receiver-anonymity"), 1, &GNUNET_GETOPT_set_uint, &anonymity}, {'n', "no-network", NULL, gettext_noop ("only search the local peer (no P2P network search)"), 0, &GNUNET_GETOPT_set_one, &local_only}, {'o', "output", "PREFIX", gettext_noop ("write search results to file starting with PREFIX"), 1, &GNUNET_GETOPT_set_string, &output_filename}, {'t', "timeout", "VALUE", gettext_noop ("automatically terminate search after VALUE ms"), 1, &GNUNET_GETOPT_set_ulong, &timeout}, {'V', "verbose", NULL, gettext_noop ("be verbose (print progress information)"), 0, &GNUNET_GETOPT_set_one, &verbose}, {'N', "results", "VALUE", gettext_noop ("automatically terminate search after VALUE results are found"), 1, &GNUNET_GETOPT_set_uint, &results_limit}, GNUNET_GETOPT_OPTION_END }; return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-search [OPTIONS] KEYWORD", gettext_noop ("Search GNUnet for files that were published on GNUnet"), options, &run, NULL)) ? ret : 1; } /* end of gnunet-search.c */ gnunet-0.9.3/src/fs/test_gnunet_fs_ns_data.conf0000644000175000017500000000022511615567501016540 00000000000000@INLINE@ test_fs_defaults.conf [PATHS] SERVICEHOME = /tmp/gnunet-test-fs-py-ns/ DEFAULTCONFIG = test_gnunet_fs_ns_data.conf [transport] PLUGINS = gnunet-0.9.3/src/fs/fs_uri.c0000644000175000017500000015546611760502551012621 00000000000000/* This file is part of GNUnet. (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs_uri.c * @brief Parses and produces uri strings. * @author Igor Wronsky, Christian Grothoff * * GNUnet URIs are of the general form "gnunet://MODULE/IDENTIFIER". * The specific structure of "IDENTIFIER" depends on the module and * maybe differenciated into additional subcategories if applicable. * This module only deals with fs identifiers (MODULE = "fs"). *

    * * This module only parses URIs for the AFS module. The FS URIs fall * into four categories, "chk", "sks", "ksk" and "loc". The first three * categories were named in analogy (!) to Freenet, but they do NOT * work in exactly the same way. They are very similar from the user's * point of view (unique file identifier, subspace, keyword), but the * implementation is rather different in pretty much every detail. * The concrete URI formats are: * *

    • * * First, there are URIs that identify a file. They have the format * "gnunet://fs/chk/HEX1.HEX2.SIZE". These URIs can be used to * download the file. The description, filename, mime-type and other * meta-data is NOT part of the file-URI since a URI uniquely * identifies a resource (and the contents of the file would be the * same even if it had a different description). * *
    • * * The second category identifies entries in a namespace. The format * is "gnunet://fs/sks/NAMESPACE/IDENTIFIER" where the namespace * should be given in HEX. Applications may allow using a nickname * for the namespace if the nickname is not ambiguous. The identifier * can be either an ASCII sequence or a HEX-encoding. If the * identifier is in ASCII but the format is ambiguous and could denote * a HEX-string a "/" is appended to indicate ASCII encoding. * *
    • * * The third category identifies ordinary searches. The format is * "gnunet://fs/ksk/KEYWORD[+KEYWORD]*". Using the "+" syntax * it is possible to encode searches with the boolean "AND" operator. * "+" is used since it indicates a commutative 'and' operation and * is unlikely to be used in a keyword by itself. * *
    • * * The last category identifies a datum on a specific machine. The * format is "gnunet://fs/loc/HEX1.HEX2.SIZE.PEER.SIG.EXPTIME". PEER is * the BinName of the public key of the peer storing the datum. The * signature (SIG) certifies that this peer has this content. * HEX1, HEX2 and SIZE correspond to a 'chk' URI. * *
    * * The encoding for hexadecimal values is defined in the hashing.c * module in the gnunetutil library and discussed there. *

    */ #include "platform.h" #include "gnunet_fs_service.h" #include "gnunet_signatures.h" #include "fs_api.h" #include #include #include #include #include /** * Get a unique key from a URI. This is for putting URIs * into HashMaps. The key may change between FS implementations. * * @param uri uri to convert to a unique key * @param key wherer to store the unique key */ void GNUNET_FS_uri_to_key (const struct GNUNET_FS_Uri *uri, GNUNET_HashCode * key) { switch (uri->type) { case chk: *key = uri->data.chk.chk.query; return; case sks: GNUNET_CRYPTO_hash (uri->data.sks.identifier, strlen (uri->data.sks.identifier), key); break; case ksk: if (uri->data.ksk.keywordCount > 0) GNUNET_CRYPTO_hash (uri->data.ksk.keywords[0], strlen (uri->data.ksk.keywords[0]), key); break; case loc: GNUNET_CRYPTO_hash (&uri->data.loc.fi, sizeof (struct FileIdentifier) + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), key); break; default: memset (key, 0, sizeof (GNUNET_HashCode)); break; } } /** * Convert keyword URI to a human readable format * (i.e. the search query that was used in the first place) * * @param uri ksk uri to convert to a string * @return string with the keywords */ char * GNUNET_FS_uri_ksk_to_string_fancy (const struct GNUNET_FS_Uri *uri) { size_t n; char *ret; unsigned int i; const char *keyword; char **keywords; unsigned int keywordCount; if ((uri == NULL) || (uri->type != ksk)) { GNUNET_break (0); return NULL; } keywords = uri->data.ksk.keywords; keywordCount = uri->data.ksk.keywordCount; n = keywordCount + 1; for (i = 0; i < keywordCount; i++) { keyword = keywords[i]; n += strlen (keyword) - 1; if (NULL != strstr (&keyword[1], " ")) n += 2; if (keyword[0] == '+') n++; } ret = GNUNET_malloc (n); strcpy (ret, ""); for (i = 0; i < keywordCount; i++) { keyword = keywords[i]; if (NULL != strstr (&keyword[1], " ")) { strcat (ret, "\""); if (keyword[0] == '+') strcat (ret, keyword); else strcat (ret, &keyword[1]); strcat (ret, "\""); } else { if (keyword[0] == '+') strcat (ret, keyword); else strcat (ret, &keyword[1]); } strcat (ret, " "); } return ret; } /** * Given a keyword with %-encoding (and possibly quotes to protect * spaces), return a copy of the keyword without %-encoding and * without double-quotes (%22). Also, add a space at the beginning * if there is not a '+'. * * @param in string with %-encoding * @param emsg where to store the parser error message (if any) * @return decodded string with leading space (or preserved plus) */ static char * percent_decode_keyword (const char *in, char **emsg) { char *out; char *ret; unsigned int rpos; unsigned int wpos; unsigned int hx; out = GNUNET_strdup (in); rpos = 0; wpos = 0; while (out[rpos] != '\0') { if (out[rpos] == '%') { if (1 != SSCANF (&out[rpos + 1], "%2X", &hx)) { GNUNET_free (out); *emsg = GNUNET_strdup (_("`%' must be followed by HEX number")); return NULL; } rpos += 3; if (hx == '"') continue; /* skip double quote */ out[wpos++] = (char) hx; } else { out[wpos++] = out[rpos++]; } } out[wpos] = '\0'; if (out[0] == '+') { ret = GNUNET_strdup (out); } else { /* need to prefix with space */ ret = GNUNET_malloc (strlen (out) + 2); strcpy (ret, " "); strcat (ret, out); } GNUNET_free (out); return ret; } #define GNUNET_FS_URI_KSK_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_KSK_INFIX /** * Parse a KSK URI. * * @param s an uri string * @param emsg where to store the parser error message (if any) * @return NULL on error, otherwise the KSK URI */ static struct GNUNET_FS_Uri * uri_ksk_parse (const char *s, char **emsg) { struct GNUNET_FS_Uri *ret; char **keywords; unsigned int pos; int max; int iret; int i; size_t slen; char *dup; int saw_quote; GNUNET_assert (s != NULL); slen = strlen (s); pos = strlen (GNUNET_FS_URI_KSK_PREFIX); if ((slen <= pos) || (0 != strncmp (s, GNUNET_FS_URI_KSK_PREFIX, pos))) return NULL; /* not KSK URI */ if ((s[slen - 1] == '+') || (s[pos] == '+')) { *emsg = GNUNET_strdup (_("Malformed KSK URI (must not begin or end with `+')")); return NULL; } max = 1; saw_quote = 0; for (i = pos; i < slen; i++) { if ((s[i] == '%') && (&s[i] == strstr (&s[i], "%22"))) { saw_quote = (saw_quote + 1) % 2; i += 3; continue; } if ((s[i] == '+') && (saw_quote == 0)) { max++; if (s[i - 1] == '+') { *emsg = GNUNET_strdup (_("`++' not allowed in KSK URI")); return NULL; } } } if (saw_quote == 1) { *emsg = GNUNET_strdup (_("Quotes not balanced in KSK URI")); return NULL; } iret = max; dup = GNUNET_strdup (s); keywords = GNUNET_malloc (max * sizeof (char *)); for (i = slen - 1; i >= pos; i--) { if ((s[i] == '%') && (&s[i] == strstr (&s[i], "%22"))) { saw_quote = (saw_quote + 1) % 2; i += 3; continue; } if ((dup[i] == '+') && (saw_quote == 0)) { keywords[--max] = percent_decode_keyword (&dup[i + 1], emsg); if (NULL == keywords[max]) goto CLEANUP; dup[i] = '\0'; } } keywords[--max] = percent_decode_keyword (&dup[pos], emsg); if (NULL == keywords[max]) goto CLEANUP; GNUNET_assert (max == 0); GNUNET_free (dup); ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); ret->type = ksk; ret->data.ksk.keywordCount = iret; ret->data.ksk.keywords = keywords; return ret; CLEANUP: for (i = 0; i < max; i++) GNUNET_free_non_null (keywords[i]); GNUNET_free (keywords); GNUNET_free (dup); return NULL; } #define GNUNET_FS_URI_SKS_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_SKS_INFIX /** * Parse an SKS URI. * * @param s an uri string * @param emsg where to store the parser error message (if any) * @return NULL on error, SKS URI otherwise */ static struct GNUNET_FS_Uri * uri_sks_parse (const char *s, char **emsg) { struct GNUNET_FS_Uri *ret; GNUNET_HashCode namespace; char *identifier; unsigned int pos; size_t slen; char enc[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]; GNUNET_assert (s != NULL); slen = strlen (s); pos = strlen (GNUNET_FS_URI_SKS_PREFIX); if ((slen <= pos) || (0 != strncmp (s, GNUNET_FS_URI_SKS_PREFIX, pos))) return NULL; /* not an SKS URI */ if ((slen < pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) || (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '/')) { *emsg = GNUNET_strdup (_("Malformed SKS URI")); return NULL; } memcpy (enc, &s[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); enc[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (enc, &namespace)) { *emsg = GNUNET_strdup (_("Malformed SKS URI")); return NULL; } identifier = GNUNET_strdup (&s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]); ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); ret->type = sks; ret->data.sks.namespace = namespace; ret->data.sks.identifier = identifier; return ret; } #define GNUNET_FS_URI_CHK_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_CHK_INFIX /** * Parse a CHK URI. * * @param s an uri string * @param emsg where to store the parser error message (if any) * @return NULL on error, CHK URI otherwise */ static struct GNUNET_FS_Uri * uri_chk_parse (const char *s, char **emsg) { struct GNUNET_FS_Uri *ret; struct FileIdentifier fi; unsigned int pos; unsigned long long flen; size_t slen; char h1[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]; char h2[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]; if (NULL == s) return NULL; GNUNET_assert (s != NULL); slen = strlen (s); pos = strlen (GNUNET_FS_URI_CHK_PREFIX); if ((slen < pos + 2 * sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1) || (0 != strncmp (s, GNUNET_FS_URI_CHK_PREFIX, pos))) return NULL; /* not a CHK URI */ if ((s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '.') || (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2 - 1] != '.')) { *emsg = GNUNET_strdup (_("Malformed CHK URI")); return NULL; } memcpy (h1, &s[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); h1[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; memcpy (h2, &s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); h2[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; if ((GNUNET_OK != GNUNET_CRYPTO_hash_from_string (h1, &fi.chk.key)) || (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (h2, &fi.chk.query)) || (1 != SSCANF (&s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2], "%llu", &flen))) { *emsg = GNUNET_strdup (_("Malformed CHK URI")); return NULL; } fi.file_length = GNUNET_htonll (flen); ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); ret->type = chk; ret->data.chk = fi; return ret; } /** * Convert a character back to the binary value * that it represents (given base64-encoding). * * @param a character to convert * @return offset in the "tbl" array */ static unsigned int c2v (unsigned char a) { if ((a >= '0') && (a <= '9')) return a - '0'; if ((a >= 'A') && (a <= 'Z')) return (a - 'A' + 10); if ((a >= 'a') && (a <= 'z')) return (a - 'a' + 36); if (a == '_') return 62; if (a == '=') return 63; return -1; } /** * Convert string back to binary data. * * @param input '\\0'-terminated string * @param data where to write binary data * @param size how much data should be converted * @return number of characters processed from input, * -1 on error */ static int enc2bin (const char *input, void *data, size_t size) { size_t len; size_t pos; unsigned int bits; unsigned int hbits; len = size * 8 / 6; if (((size * 8) % 6) != 0) len++; if (strlen (input) < len) return -1; /* error! */ bits = 0; hbits = 0; len = 0; for (pos = 0; pos < size; pos++) { while (hbits < 8) { bits |= (c2v (input[len++]) << hbits); hbits += 6; } (((unsigned char *) data)[pos]) = (unsigned char) bits; bits >>= 8; hbits -= 8; } return len; } /** * Structure that defines how the * contents of a location URI must be * assembled in memory to create or * verify the signature of a location * URI. */ struct LocUriAssembly { struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; struct GNUNET_TIME_AbsoluteNBO exptime; struct FileIdentifier fi; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded peer; }; #define GNUNET_FS_URI_LOC_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_LOC_INFIX /** * Parse a LOC URI. * Also verifies validity of the location URI. * * @param s an uri string * @param emsg where to store the parser error message (if any) * @return NULL on error, valid LOC URI otherwise */ static struct GNUNET_FS_Uri * uri_loc_parse (const char *s, char **emsg) { struct GNUNET_FS_Uri *uri; char h1[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]; char h2[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]; unsigned int pos; unsigned int npos; unsigned long long exptime; unsigned long long flen; struct GNUNET_TIME_Absolute et; struct GNUNET_CRYPTO_RsaSignature sig; struct LocUriAssembly ass; int ret; size_t slen; GNUNET_assert (s != NULL); slen = strlen (s); pos = strlen (GNUNET_FS_URI_LOC_PREFIX); if ((slen < pos + 2 * sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1) || (0 != strncmp (s, GNUNET_FS_URI_LOC_PREFIX, pos))) return NULL; /* not an SKS URI */ if ((s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '.') || (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2 - 1] != '.')) { *emsg = GNUNET_strdup (_("SKS URI malformed")); return NULL; } memcpy (h1, &s[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); h1[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; memcpy (h2, &s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); h2[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; if ((GNUNET_OK != GNUNET_CRYPTO_hash_from_string (h1, &ass.fi.chk.key)) || (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (h2, &ass.fi.chk.query)) || (1 != SSCANF (&s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2], "%llu", &flen))) { *emsg = GNUNET_strdup (_("SKS URI malformed")); return NULL; } ass.fi.file_length = GNUNET_htonll (flen); npos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2; while ((s[npos] != '\0') && (s[npos] != '.')) npos++; if (s[npos] == '\0') { *emsg = GNUNET_strdup (_("SKS URI malformed")); goto ERR; } npos++; ret = enc2bin (&s[npos], &ass.peer, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); if (ret == -1) { *emsg = GNUNET_strdup (_("SKS URI malformed (could not decode public key)")); goto ERR; } npos += ret; if (s[npos++] != '.') { *emsg = GNUNET_strdup (_("SKS URI malformed (could not find signature)")); goto ERR; } ret = enc2bin (&s[npos], &sig, sizeof (struct GNUNET_CRYPTO_RsaSignature)); if (ret == -1) { *emsg = GNUNET_strdup (_("SKS URI malformed (could not decode signature)")); goto ERR; } npos += ret; if (s[npos++] != '.') { *emsg = GNUNET_strdup (_("SKS URI malformed")); goto ERR; } if (1 != SSCANF (&s[npos], "%llu", &exptime)) { *emsg = GNUNET_strdup (_ ("SKS URI malformed (could not parse expiration time)")); goto ERR; } ass.purpose.size = htonl (sizeof (struct LocUriAssembly)); ass.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT); et.abs_value = exptime; ass.exptime = GNUNET_TIME_absolute_hton (et); if (GNUNET_OK != GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT, &ass.purpose, &sig, &ass.peer)) { *emsg = GNUNET_strdup (_("SKS URI malformed (signature failed validation)")); goto ERR; } uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); uri->type = loc; uri->data.loc.fi = ass.fi; uri->data.loc.peer = ass.peer; uri->data.loc.expirationTime = et; uri->data.loc.contentSignature = sig; return uri; ERR: return NULL; } /** * Convert a UTF-8 String to a URI. * * @param uri string to parse * @param emsg where to store the parser error message (if any) * @return NULL on error */ struct GNUNET_FS_Uri * GNUNET_FS_uri_parse (const char *uri, char **emsg) { struct GNUNET_FS_Uri *ret; char *msg; if (NULL == emsg) emsg = &msg; *emsg = NULL; if ((NULL != (ret = uri_chk_parse (uri, emsg))) || (NULL != (ret = uri_ksk_parse (uri, emsg))) || (NULL != (ret = uri_sks_parse (uri, emsg))) || (NULL != (ret = uri_loc_parse (uri, emsg)))) return ret; if (NULL == *emsg) *emsg = GNUNET_strdup (_("Unrecognized URI type")); if (emsg == &msg) GNUNET_free (msg); return NULL; } /** * Free URI. * * @param uri uri to free */ void GNUNET_FS_uri_destroy (struct GNUNET_FS_Uri *uri) { unsigned int i; GNUNET_assert (uri != NULL); switch (uri->type) { case ksk: for (i = 0; i < uri->data.ksk.keywordCount; i++) GNUNET_free (uri->data.ksk.keywords[i]); GNUNET_array_grow (uri->data.ksk.keywords, uri->data.ksk.keywordCount, 0); break; case sks: GNUNET_free (uri->data.sks.identifier); break; case loc: break; default: /* do nothing */ break; } GNUNET_free (uri); } /** * How many keywords are ANDed in this keyword URI? * * @param uri ksk uri to get the number of keywords from * @return 0 if this is not a keyword URI */ unsigned int GNUNET_FS_uri_ksk_get_keyword_count (const struct GNUNET_FS_Uri *uri) { if (uri->type != ksk) return 0; return uri->data.ksk.keywordCount; } /** * Iterate over all keywords in this keyword URI. * * @param uri ksk uri to get the keywords from * @param iterator function to call on each keyword * @param iterator_cls closure for iterator * @return -1 if this is not a keyword URI, otherwise number of * keywords iterated over until iterator aborted */ int GNUNET_FS_uri_ksk_get_keywords (const struct GNUNET_FS_Uri *uri, GNUNET_FS_KeywordIterator iterator, void *iterator_cls) { unsigned int i; char *keyword; if (uri->type != ksk) return -1; if (iterator == NULL) return uri->data.ksk.keywordCount; for (i = 0; i < uri->data.ksk.keywordCount; i++) { keyword = uri->data.ksk.keywords[i]; /* first character of keyword indicates * if it is mandatory or not */ if (GNUNET_OK != iterator (iterator_cls, &keyword[1], keyword[0] == '+')) return i; } return i; } /** * Add the given keyword to the set of keywords represented by the URI. * Does nothing if the keyword is already present. * * @param uri ksk uri to modify * @param keyword keyword to add * @param is_mandatory is this keyword mandatory? */ void GNUNET_FS_uri_ksk_add_keyword (struct GNUNET_FS_Uri *uri, const char *keyword, int is_mandatory) { unsigned int i; const char *old; char *n; GNUNET_assert (uri->type == ksk); for (i = 0; i < uri->data.ksk.keywordCount; i++) { old = uri->data.ksk.keywords[i]; if (0 == strcmp (&old[1], keyword)) return; } GNUNET_asprintf (&n, is_mandatory ? "+%s" : " %s", keyword); GNUNET_array_append (uri->data.ksk.keywords, uri->data.ksk.keywordCount, n); } /** * Remove the given keyword from the set of keywords represented by the URI. * Does nothing if the keyword is not present. * * @param uri ksk uri to modify * @param keyword keyword to add */ void GNUNET_FS_uri_ksk_remove_keyword (struct GNUNET_FS_Uri *uri, const char *keyword) { unsigned int i; char *old; GNUNET_assert (uri->type == ksk); for (i = 0; i < uri->data.ksk.keywordCount; i++) { old = uri->data.ksk.keywords[i]; if (0 == strcmp (&old[1], keyword)) { uri->data.ksk.keywords[i] = uri->data.ksk.keywords[uri->data.ksk.keywordCount - 1]; GNUNET_array_grow (uri->data.ksk.keywords, uri->data.ksk.keywordCount, uri->data.ksk.keywordCount - 1); GNUNET_free (old); return; } } } /** * Obtain the identity of the peer offering the data * * @param uri the location URI to inspect * @param peer where to store the identify of the peer (presumably) offering the content * @return GNUNET_SYSERR if this is not a location URI, otherwise GNUNET_OK */ int GNUNET_FS_uri_loc_get_peer_identity (const struct GNUNET_FS_Uri *uri, struct GNUNET_PeerIdentity *peer) { if (uri->type != loc) return GNUNET_SYSERR; GNUNET_CRYPTO_hash (&uri->data.loc.peer, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &peer->hashPubKey); return GNUNET_OK; } /** * Obtain the expiration of the LOC URI. * * @param uri location URI to get the expiration from * @return expiration time of the URI */ struct GNUNET_TIME_Absolute GNUNET_FS_uri_loc_get_expiration (const struct GNUNET_FS_Uri *uri) { GNUNET_assert (uri->type == loc); return uri->data.loc.expirationTime; } /** * Obtain the URI of the content itself. * * @param uri location URI to get the content URI from * @return NULL if argument is not a location URI */ struct GNUNET_FS_Uri * GNUNET_FS_uri_loc_get_uri (const struct GNUNET_FS_Uri *uri) { struct GNUNET_FS_Uri *ret; if (uri->type != loc) return NULL; ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); ret->type = chk; ret->data.chk = uri->data.loc.fi; return ret; } /** * Construct a location URI (this peer will be used for the location). * * @param baseUri content offered by the sender * @param cfg configuration information (used to find our hostkey) * @param expiration_time how long will the content be offered? * @return the location URI, NULL on error */ struct GNUNET_FS_Uri * GNUNET_FS_uri_loc_create (const struct GNUNET_FS_Uri *baseUri, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TIME_Absolute expiration_time) { struct GNUNET_FS_Uri *uri; struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; char *keyfile; struct LocUriAssembly ass; if (baseUri->type != chk) return NULL; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY", &keyfile)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Lacking key configuration settings.\n")); return NULL; } my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); if (my_private_key == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not access hostkey file `%s'.\n"), keyfile); GNUNET_free (keyfile); return NULL; } GNUNET_free (keyfile); GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key); ass.purpose.size = htonl (sizeof (struct LocUriAssembly)); ass.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT); ass.exptime = GNUNET_TIME_absolute_hton (expiration_time); ass.fi = baseUri->data.chk; ass.peer = my_public_key; uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); uri->type = loc; uri->data.loc.fi = baseUri->data.chk; uri->data.loc.expirationTime = expiration_time; uri->data.loc.peer = my_public_key; GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_rsa_sign (my_private_key, &ass.purpose, &uri->data.loc.contentSignature)); GNUNET_CRYPTO_rsa_key_free (my_private_key); return uri; } /** * Create an SKS URI from a namespace and an identifier. * * @param ns namespace * @param id identifier * @param emsg where to store an error message * @return an FS URI for the given namespace and identifier */ struct GNUNET_FS_Uri * GNUNET_FS_uri_sks_create (struct GNUNET_FS_Namespace *ns, const char *id, char **emsg) { struct GNUNET_FS_Uri *ns_uri; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk; ns_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); ns_uri->type = sks; GNUNET_CRYPTO_rsa_key_get_public (ns->key, &pk); GNUNET_CRYPTO_hash (&pk, sizeof (pk), &ns_uri->data.sks.namespace); ns_uri->data.sks.identifier = GNUNET_strdup (id); return ns_uri; } /** * Create an SKS URI from a namespace ID and an identifier. * * @param nsid namespace ID * @param id identifier * @return an FS URI for the given namespace and identifier */ struct GNUNET_FS_Uri * GNUNET_FS_uri_sks_create_from_nsid (GNUNET_HashCode * nsid, const char *id) { struct GNUNET_FS_Uri *ns_uri; ns_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); ns_uri->type = sks; ns_uri->data.sks.namespace = *nsid; ns_uri->data.sks.identifier = GNUNET_strdup (id); return ns_uri; } /** * Merge the sets of keywords from two KSK URIs. * (useful for merging the canonicalized keywords with * the original keywords for sharing). * * @param u1 first uri * @param u2 second uri * @return merged URI, NULL on error */ struct GNUNET_FS_Uri * GNUNET_FS_uri_ksk_merge (const struct GNUNET_FS_Uri *u1, const struct GNUNET_FS_Uri *u2) { struct GNUNET_FS_Uri *ret; unsigned int kc; unsigned int i; unsigned int j; int found; const char *kp; char **kl; if ((u1 == NULL) && (u2 == NULL)) return NULL; if (u1 == NULL) return GNUNET_FS_uri_dup (u2); if (u2 == NULL) return GNUNET_FS_uri_dup (u1); if ((u1->type != ksk) || (u2->type != ksk)) { GNUNET_break (0); return NULL; } kc = u1->data.ksk.keywordCount; kl = GNUNET_malloc ((kc + u2->data.ksk.keywordCount) * sizeof (char *)); for (i = 0; i < u1->data.ksk.keywordCount; i++) kl[i] = GNUNET_strdup (u1->data.ksk.keywords[i]); for (i = 0; i < u2->data.ksk.keywordCount; i++) { kp = u2->data.ksk.keywords[i]; found = 0; for (j = 0; j < u1->data.ksk.keywordCount; j++) if (0 == strcmp (kp + 1, kl[j] + 1)) { found = 1; if (kp[0] == '+') kl[j][0] = '+'; break; } if (0 == found) kl[kc++] = GNUNET_strdup (kp); } ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); ret->type = ksk; ret->data.ksk.keywordCount = kc; ret->data.ksk.keywords = kl; return ret; } /** * Duplicate URI. * * @param uri the URI to duplicate * @return copy of the URI */ struct GNUNET_FS_Uri * GNUNET_FS_uri_dup (const struct GNUNET_FS_Uri *uri) { struct GNUNET_FS_Uri *ret; unsigned int i; if (uri == NULL) return NULL; ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); memcpy (ret, uri, sizeof (struct GNUNET_FS_Uri)); switch (ret->type) { case ksk: if (ret->data.ksk.keywordCount >= GNUNET_MAX_MALLOC_CHECKED / sizeof (char *)) { GNUNET_break (0); GNUNET_free (ret); return NULL; } if (ret->data.ksk.keywordCount > 0) { ret->data.ksk.keywords = GNUNET_malloc (ret->data.ksk.keywordCount * sizeof (char *)); for (i = 0; i < ret->data.ksk.keywordCount; i++) ret->data.ksk.keywords[i] = GNUNET_strdup (uri->data.ksk.keywords[i]); } else ret->data.ksk.keywords = NULL; /* just to be sure */ break; case sks: ret->data.sks.identifier = GNUNET_strdup (uri->data.sks.identifier); break; case loc: break; default: break; } return ret; } /** * Create an FS URI from a single user-supplied string of keywords. * The string is broken up at spaces into individual keywords. * Keywords that start with "+" are mandatory. Double-quotes can * be used to prevent breaking up strings at spaces (and also * to specify non-mandatory keywords starting with "+"). * * Keywords must contain a balanced number of double quotes and * double quotes can not be used in the actual keywords (for * example, the string '""foo bar""' will be turned into two * "OR"ed keywords 'foo' and 'bar', not into '"foo bar"'. * * @param keywords the keyword string * @param emsg where to store an error message * @return an FS URI for the given keywords, NULL * if keywords is not legal (i.e. empty). */ struct GNUNET_FS_Uri * GNUNET_FS_uri_ksk_create (const char *keywords, char **emsg) { char **keywordarr; unsigned int num_Words; int inWord; char *pos; struct GNUNET_FS_Uri *uri; char *searchString; int saw_quote; if (keywords == NULL) { *emsg = GNUNET_strdup (_("No keywords specified!\n")); GNUNET_break (0); return NULL; } searchString = GNUNET_strdup (keywords); num_Words = 0; inWord = 0; saw_quote = 0; pos = searchString; while ('\0' != *pos) { if ((saw_quote == 0) && (isspace ((unsigned char) *pos))) { inWord = 0; } else if (0 == inWord) { inWord = 1; ++num_Words; } if ('"' == *pos) saw_quote = (saw_quote + 1) % 2; pos++; } if (num_Words == 0) { GNUNET_free (searchString); *emsg = GNUNET_strdup (_("No keywords specified!\n")); return NULL; } if (saw_quote != 0) { GNUNET_free (searchString); *emsg = GNUNET_strdup (_("Number of double-quotes not balanced!\n")); return NULL; } keywordarr = GNUNET_malloc (num_Words * sizeof (char *)); num_Words = 0; inWord = 0; pos = searchString; while ('\0' != *pos) { if ((saw_quote == 0) && (isspace ((unsigned char) *pos))) { inWord = 0; *pos = '\0'; } else if (0 == inWord) { keywordarr[num_Words] = pos; inWord = 1; ++num_Words; } if ('"' == *pos) saw_quote = (saw_quote + 1) % 2; pos++; } uri = GNUNET_FS_uri_ksk_create_from_args (num_Words, (const char **) keywordarr); GNUNET_free (keywordarr); GNUNET_free (searchString); return uri; } /** * Create an FS URI from a user-supplied command line of keywords. * Arguments should start with "+" to indicate mandatory * keywords. * * @param argc number of keywords * @param argv keywords (double quotes are not required for * keywords containing spaces; however, double * quotes are required for keywords starting with * "+"); there is no mechanism for having double * quotes in the actual keywords (if the user * did specifically specify double quotes, the * caller should convert each double quote * into two single quotes). * @return an FS URI for the given keywords, NULL * if keywords is not legal (i.e. empty). */ struct GNUNET_FS_Uri * GNUNET_FS_uri_ksk_create_from_args (unsigned int argc, const char **argv) { unsigned int i; struct GNUNET_FS_Uri *uri; const char *keyword; char *val; const char *r; char *w; char *emsg; if (argc == 0) return NULL; /* allow URI to be given as one and only keyword and * handle accordingly */ emsg = NULL; if ((argc == 1) && (strlen (argv[0]) > strlen (GNUNET_FS_URI_PREFIX)) && (0 == strncmp (argv[0], GNUNET_FS_URI_PREFIX, strlen (GNUNET_FS_URI_PREFIX))) && (NULL != (uri = GNUNET_FS_uri_parse (argv[0], &emsg)))) return uri; GNUNET_free_non_null (emsg); uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); uri->type = ksk; uri->data.ksk.keywordCount = argc; uri->data.ksk.keywords = GNUNET_malloc (argc * sizeof (char *)); for (i = 0; i < argc; i++) { keyword = argv[i]; if (keyword[0] == '+') val = GNUNET_strdup (keyword); else GNUNET_asprintf (&val, " %s", keyword); r = val; w = val; while ('\0' != *r) { if ('"' == *r) r++; else *(w++) = *(r++); } *w = '\0'; uri->data.ksk.keywords[i] = val; } return uri; } /** * Test if two URIs are equal. * * @param u1 one of the URIs * @param u2 the other URI * @return GNUNET_YES if the URIs are equal */ int GNUNET_FS_uri_test_equal (const struct GNUNET_FS_Uri *u1, const struct GNUNET_FS_Uri *u2) { int ret; unsigned int i; unsigned int j; GNUNET_assert (u1 != NULL); GNUNET_assert (u2 != NULL); if (u1->type != u2->type) return GNUNET_NO; switch (u1->type) { case chk: if (0 == memcmp (&u1->data.chk, &u2->data.chk, sizeof (struct FileIdentifier))) return GNUNET_YES; return GNUNET_NO; case sks: if ((0 == memcmp (&u1->data.sks.namespace, &u2->data.sks.namespace, sizeof (GNUNET_HashCode))) && (0 == strcmp (u1->data.sks.identifier, u2->data.sks.identifier))) return GNUNET_YES; return GNUNET_NO; case ksk: if (u1->data.ksk.keywordCount != u2->data.ksk.keywordCount) return GNUNET_NO; for (i = 0; i < u1->data.ksk.keywordCount; i++) { ret = GNUNET_NO; for (j = 0; j < u2->data.ksk.keywordCount; j++) { if (0 == strcmp (u1->data.ksk.keywords[i], u2->data.ksk.keywords[j])) { ret = GNUNET_YES; break; } } if (ret == GNUNET_NO) return GNUNET_NO; } return GNUNET_YES; case loc: if (memcmp (&u1->data.loc, &u2->data.loc, sizeof (struct FileIdentifier) + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sizeof (struct GNUNET_TIME_Absolute) + sizeof (unsigned short) + sizeof (unsigned short)) != 0) return GNUNET_NO; return GNUNET_YES; default: return GNUNET_NO; } } /** * Is this a namespace URI? * * @param uri the uri to check * @return GNUNET_YES if this is an SKS uri */ int GNUNET_FS_uri_test_sks (const struct GNUNET_FS_Uri *uri) { return uri->type == sks; } /** * Get the ID of a namespace from the given * namespace URI. * * @param uri the uri to get the namespace ID from * @param nsid where to store the ID of the namespace * @return GNUNET_OK on success */ int GNUNET_FS_uri_sks_get_namespace (const struct GNUNET_FS_Uri *uri, GNUNET_HashCode * nsid) { if (!GNUNET_FS_uri_test_sks (uri)) { GNUNET_break (0); return GNUNET_SYSERR; } *nsid = uri->data.sks.namespace; return GNUNET_OK; } /** * Get the content identifier of an SKS URI. * * @param uri the sks uri * @return NULL on error (not a valid SKS URI) */ char * GNUNET_FS_uri_sks_get_content_id (const struct GNUNET_FS_Uri *uri) { if (!GNUNET_FS_uri_test_sks (uri)) { GNUNET_break (0); return NULL; } return GNUNET_strdup (uri->data.sks.identifier); } /** * Convert namespace URI to a human readable format * (using the namespace description, if available). * * @param cfg configuration to use * @param uri SKS uri to convert * @return NULL on error (not an SKS URI) */ char * GNUNET_FS_uri_sks_to_string_fancy (struct GNUNET_CONFIGURATION_Handle *cfg, const struct GNUNET_FS_Uri *uri) { char *ret; char *name; char *unique_name; if (uri->type != sks) return NULL; (void) GNUNET_PSEUDONYM_get_info (cfg, &uri->data.sks.namespace, NULL, NULL, &name, NULL); unique_name = GNUNET_PSEUDONYM_name_uniquify (cfg, &uri->data.sks.namespace, name, NULL); GNUNET_free (name); GNUNET_asprintf (&ret, "%s: %s", unique_name, uri->data.sks.identifier); GNUNET_free (unique_name); return ret; } /** * Is this a keyword URI? * * @param uri the uri * @return GNUNET_YES if this is a KSK uri */ int GNUNET_FS_uri_test_ksk (const struct GNUNET_FS_Uri *uri) { #if EXTRA_CHECKS unsigned int i; if (uri->type == ksk) { for (i=0;i < uri->data.ksk.keywordCount; i++) GNUNET_assert (uri->data.ksk.keywords[i] != NULL); } #endif return uri->type == ksk; } /** * Is this a file (or directory) URI? * * @param uri the uri to check * @return GNUNET_YES if this is a CHK uri */ int GNUNET_FS_uri_test_chk (const struct GNUNET_FS_Uri *uri) { return uri->type == chk; } /** * What is the size of the file that this URI * refers to? * * @param uri the CHK URI to inspect * @return size of the file as specified in the CHK URI */ uint64_t GNUNET_FS_uri_chk_get_file_size (const struct GNUNET_FS_Uri * uri) { switch (uri->type) { case chk: return GNUNET_ntohll (uri->data.chk.file_length); case loc: return GNUNET_ntohll (uri->data.loc.fi.file_length); default: GNUNET_assert (0); } return 0; /* unreachable */ } /** * Is this a location URI? * * @param uri the uri to check * @return GNUNET_YES if this is a LOC uri */ int GNUNET_FS_uri_test_loc (const struct GNUNET_FS_Uri *uri) { return uri->type == loc; } /** * Add a keyword as non-mandatory (with ' '-prefix) to the * given keyword list at offset 'index'. The array is * guaranteed to be long enough. * * @param s keyword to add * @param array array to add the keyword to * @param index offset where to add the keyword */ static void insert_non_mandatory_keyword (const char *s, char **array, int index) { char *nkword; GNUNET_asprintf (&nkword, " %s", /* space to mark as 'non mandatory' */ s); array[index] = nkword; } /** * Test if the given keyword 's' is already present in the * given array, ignoring the '+'-mandatory prefix in the array. * * @param s keyword to test * @param array keywords to test against, with ' ' or '+' prefix to ignore * @param array_length length of the array * @return GNUNET_YES if the keyword exists, GNUNET_NO if not */ static int find_duplicate (const char *s, const char **array, int array_length) { int j; for (j = array_length - 1; j >= 0; j--) if (0 == strcmp (&array[j][1], s)) return GNUNET_YES; return GNUNET_NO; } /** * FIXME: comment */ static char * normalize_metadata (enum EXTRACTOR_MetaFormat format, const char *data, size_t data_len) { uint8_t *free_str = NULL; uint8_t *str_to_normalize = (uint8_t *) data; uint8_t *normalized; size_t r_len; if (str_to_normalize == NULL) return NULL; /* Don't trust libextractor */ if (format == EXTRACTOR_METAFORMAT_UTF8) { free_str = (uint8_t *) u8_check ((const uint8_t *) data, data_len); if (free_str == NULL) free_str = NULL; else format = EXTRACTOR_METAFORMAT_C_STRING; } if (format == EXTRACTOR_METAFORMAT_C_STRING) { free_str = u8_strconv_from_encoding (data, locale_charset (), iconveh_escape_sequence); if (free_str == NULL) return NULL; } normalized = u8_tolower (str_to_normalize, strlen ((char *) str_to_normalize), NULL, UNINORM_NFD, NULL, &r_len); /* free_str is allocated by libunistring internally, use free() */ if (free_str != NULL) free (free_str); if (normalized != NULL) { /* u8_tolower allocates a non-NULL-terminated string! */ free_str = GNUNET_malloc (r_len + 1); memcpy (free_str, normalized, r_len); free_str[r_len] = '\0'; free (normalized); normalized = free_str; } return (char *) normalized; } /** * Counts the number of UTF-8 characters (not bytes) in the string, * returns that count. */ static size_t u8_strcount (const uint8_t *s) { size_t count; ucs4_t c; GNUNET_assert (s != NULL); if (s[0] == 0) return 0; for (count = 0; s != NULL; count++) s = u8_next (&c, s); return count - 1; } /** * Break the filename up by matching [], () and {} pairs to make * keywords. In case of nesting parentheses only the inner pair counts. * You can't escape parentheses to scan something like "[blah\{foo]" to * make a "blah{foo" keyword, this function is only a heuristic! * * @param s string to break down. * @param array array to fill with enclosed tokens. If NULL, then tokens * are only counted. * @param index index at which to start filling the array (entries prior * to it are used to check for duplicates). ignored if array == NULL. * @return number of tokens counted (including duplicates), or number of * tokens extracted (excluding duplicates). 0 if there are no * matching parens in the string (when counting), or when all tokens * were duplicates (when extracting). */ static int get_keywords_from_parens (const char *s, char **array, int index) { int count = 0; char *open_paren; char *close_paren; char *ss; char tmp; if (NULL == s) return 0; ss = GNUNET_strdup (s); open_paren = ss - 1; while (NULL != (open_paren = strpbrk (open_paren + 1, "[{("))) { int match = 0; close_paren = strpbrk (open_paren + 1, "]})"); if (NULL == close_paren) continue; switch (open_paren[0]) { case '[': if (']' == close_paren[0]) match = 1; break; case '{': if ('}' == close_paren[0]) match = 1; break; case '(': if (')' == close_paren[0]) match = 1; break; default: break; } if (match && (close_paren - open_paren > 1)) { tmp = close_paren[0]; close_paren[0] = '\0'; /* Keywords must be at least 3 characters long */ if (u8_strcount ((const uint8_t *) &open_paren[1]) <= 2) { close_paren[0] = tmp; continue; } if (NULL != array) { char *normalized; if (GNUNET_NO == find_duplicate ((const char *) &open_paren[1], (const char **) array, index + count)) { insert_non_mandatory_keyword ((const char *) &open_paren[1], array, index + count); count++; } normalized = normalize_metadata (EXTRACTOR_METAFORMAT_UTF8, &open_paren[1], close_paren - &open_paren[1]); if (normalized != NULL) { if (GNUNET_NO == find_duplicate ((const char *) normalized, (const char **) array, index + count)) { insert_non_mandatory_keyword ((const char *) normalized, array, index + count); count++; } GNUNET_free (normalized); } } else count++; close_paren[0] = tmp; } } GNUNET_free (ss); return count; } /** * Where to break up keywords */ #define TOKENS "_. /-!?#&+@\"\'\\;:," /** * Break the filename up by TOKENS to make * keywords. * * @param s string to break down. * @param array array to fill with tokens. If NULL, then tokens are only * counted. * @param index index at which to start filling the array (entries prior * to it are used to check for duplicates). ignored if array == NULL. * @return number of tokens (>1) counted (including duplicates), or number of * tokens extracted (excluding duplicates). 0 if there are no * separators in the string (when counting), or when all tokens were * duplicates (when extracting). */ static int get_keywords_from_tokens (const char *s, char **array, int index) { char *p; char *ss; int seps = 0; ss = GNUNET_strdup (s); for (p = strtok (ss, TOKENS); p != NULL; p = strtok (NULL, TOKENS)) { /* Keywords must be at least 3 characters long */ if (u8_strcount ((const uint8_t *) p) <= 2) continue; if (NULL != array) { char *normalized; if (GNUNET_NO == find_duplicate (p, (const char **) array, index + seps)) { insert_non_mandatory_keyword (p, array, index + seps); seps++; } normalized = normalize_metadata (EXTRACTOR_METAFORMAT_UTF8, p, strlen (p)); if (normalized != NULL) { if (GNUNET_NO == find_duplicate ((const char *) normalized, (const char **) array, index + seps)) { insert_non_mandatory_keyword ((const char *) normalized, array, index + seps); seps++; } GNUNET_free (normalized); } } else seps++; } GNUNET_free (ss); return seps; } #undef TOKENS /** * Function called on each value in the meta data. * Adds it to the URI. * * @param cls URI to update * @param plugin_name name of the plugin that produced this value; * special values can be used (i.e. '<zlib>' for zlib being * used in the main libextractor library and yielding * meta data). * @param type libextractor-type describing the meta data * @param format basic format information about data * @param data_mime_type mime-type of data (not of the original file); * can be NULL (if mime-type is not known) * @param data actual meta-data found * @param data_len number of bytes in data * @return 0 (always) */ static int gather_uri_data (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat format, const char *data_mime_type, const char *data, size_t data_len) { struct GNUNET_FS_Uri *uri = cls; char *normalized_data; if ((format != EXTRACTOR_METAFORMAT_UTF8) && (format != EXTRACTOR_METAFORMAT_C_STRING)) return 0; /* Keywords must be at least 3 characters long * If given non-utf8 string it will, most likely, find it to be invalid, * and will return the length of its valid part, skipping the keyword. * If it does - fix the extractor, not this check! */ if (u8_strcount ((const uint8_t *) data) <= 2) { return 0; } normalized_data = normalize_metadata (format, data, data_len); if (!find_duplicate (data, (const char **) uri->data.ksk.keywords, uri->data.ksk.keywordCount)) { insert_non_mandatory_keyword (data, uri->data.ksk.keywords, uri->data.ksk.keywordCount); uri->data.ksk.keywordCount++; } if (normalized_data != NULL) { if (!find_duplicate (normalized_data, (const char **) uri->data.ksk.keywords, uri->data.ksk.keywordCount)) { insert_non_mandatory_keyword (normalized_data, uri->data.ksk.keywords, uri->data.ksk.keywordCount); uri->data.ksk.keywordCount++; } GNUNET_free (normalized_data); } return 0; } /** * Construct a keyword-URI from meta-data (take all entries * in the meta-data and construct one large keyword URI * that lists all keywords that can be found in the meta-data). * * @param md metadata to use * @return NULL on error, otherwise a KSK URI */ struct GNUNET_FS_Uri * GNUNET_FS_uri_ksk_create_from_meta_data (const struct GNUNET_CONTAINER_MetaData *md) { struct GNUNET_FS_Uri *ret; char *filename; char *full_name = NULL; char *ss; int ent; int tok_keywords = 0; int paren_keywords = 0; if (md == NULL) return NULL; ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); ret->type = ksk; ent = GNUNET_CONTAINER_meta_data_iterate (md, NULL, NULL); if (ent > 0) { full_name = GNUNET_CONTAINER_meta_data_get_first_by_types (md, EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, -1); if (NULL != full_name) { filename = full_name; while (NULL != (ss = strstr (filename, DIR_SEPARATOR_STR))) filename = ss + 1; tok_keywords = get_keywords_from_tokens (filename, NULL, 0); paren_keywords = get_keywords_from_parens (filename, NULL, 0); } /* x2 because there might be a normalized variant of every keyword */ ret->data.ksk.keywords = GNUNET_malloc (sizeof (char *) * (ent + tok_keywords + paren_keywords) * 2); GNUNET_CONTAINER_meta_data_iterate (md, &gather_uri_data, ret); } if (tok_keywords > 0) ret->data.ksk.keywordCount += get_keywords_from_tokens (filename, ret->data.ksk.keywords, ret->data.ksk.keywordCount); if (paren_keywords > 0) ret->data.ksk.keywordCount += get_keywords_from_parens (filename, ret->data.ksk.keywords, ret->data.ksk.keywordCount); if (ent > 0) GNUNET_free_non_null (full_name); return ret; } /** * In URI-encoding, does the given character * need to be encoded using %-encoding? */ static int needs_percent (char c) { return (! ((isalnum ((unsigned char) c)) || (c == '-') || (c == '_') || (c == '.') || (c == '~'))); } /** * Convert a KSK URI to a string. * * @param uri the URI to convert * @return NULL on error (i.e. keywordCount == 0) */ static char * uri_ksk_to_string (const struct GNUNET_FS_Uri *uri) { char **keywords; unsigned int keywordCount; size_t n; char *ret; unsigned int i; unsigned int j; unsigned int wpos; size_t slen; const char *keyword; if (uri->type != ksk) return NULL; keywords = uri->data.ksk.keywords; keywordCount = uri->data.ksk.keywordCount; n = keywordCount + strlen (GNUNET_FS_URI_PREFIX) + strlen (GNUNET_FS_URI_KSK_INFIX) + 1; for (i = 0; i < keywordCount; i++) { keyword = keywords[i]; slen = strlen (keyword); n += slen; for (j = 0; j < slen; j++) { if ((j == 0) && (keyword[j] == ' ')) { n--; continue; /* skip leading space */ } if (needs_percent (keyword[j])) n += 2; /* will use %-encoding */ } } ret = GNUNET_malloc (n); strcpy (ret, GNUNET_FS_URI_PREFIX); strcat (ret, GNUNET_FS_URI_KSK_INFIX); wpos = strlen (ret); for (i = 0; i < keywordCount; i++) { keyword = keywords[i]; slen = strlen (keyword); for (j = 0; j < slen; j++) { if ((j == 0) && (keyword[j] == ' ')) continue; /* skip leading space */ if (needs_percent (keyword[j])) { sprintf (&ret[wpos], "%%%02X", keyword[j]); wpos += 3; } else { ret[wpos++] = keyword[j]; } } if (i != keywordCount - 1) ret[wpos++] = '+'; } return ret; } /** * Convert SKS URI to a string. * * @param uri sks uri to convert * @return NULL on error */ static char * uri_sks_to_string (const struct GNUNET_FS_Uri *uri) { const GNUNET_HashCode *namespace; const char *identifier; char *ret; struct GNUNET_CRYPTO_HashAsciiEncoded ns; if (uri->type != sks) return NULL; namespace = &uri->data.sks.namespace; identifier = uri->data.sks.identifier; GNUNET_CRYPTO_hash_to_enc (namespace, &ns); GNUNET_asprintf (&ret, "%s%s%s/%s", GNUNET_FS_URI_PREFIX, GNUNET_FS_URI_SKS_INFIX, (const char *) &ns, identifier); return ret; } /** * Convert a CHK URI to a string. * * @param uri chk uri to convert * @return NULL on error */ static char * uri_chk_to_string (const struct GNUNET_FS_Uri *uri) { const struct FileIdentifier *fi; char *ret; struct GNUNET_CRYPTO_HashAsciiEncoded keyhash; struct GNUNET_CRYPTO_HashAsciiEncoded queryhash; if (uri->type != chk) return NULL; fi = &uri->data.chk; GNUNET_CRYPTO_hash_to_enc (&fi->chk.key, &keyhash); GNUNET_CRYPTO_hash_to_enc (&fi->chk.query, &queryhash); GNUNET_asprintf (&ret, "%s%s%s.%s.%llu", GNUNET_FS_URI_PREFIX, GNUNET_FS_URI_CHK_INFIX, (const char *) &keyhash, (const char *) &queryhash, GNUNET_ntohll (fi->file_length)); return ret; } /** * Convert binary data to a string. * * @param data binary data to convert * @param size number of bytes in data * @return converted data */ static char * bin2enc (const void *data, size_t size) { /** * 64 characters for encoding, 6 bits per character */ static char *tbl = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_="; size_t len; size_t pos; unsigned int bits; unsigned int hbits; char *ret; GNUNET_assert (strlen (tbl) == 64); len = size * 8 / 6; if (((size * 8) % 6) != 0) len++; ret = GNUNET_malloc (len + 1); ret[len] = '\0'; len = 0; bits = 0; hbits = 0; for (pos = 0; pos < size; pos++) { bits |= ((((const unsigned char *) data)[pos]) << hbits); hbits += 8; while (hbits >= 6) { ret[len++] = tbl[bits & 63]; bits >>= 6; hbits -= 6; } } if (hbits > 0) ret[len] = tbl[bits & 63]; return ret; } /** * Convert a LOC URI to a string. * * @param uri loc uri to convert * @return NULL on error */ static char * uri_loc_to_string (const struct GNUNET_FS_Uri *uri) { char *ret; struct GNUNET_CRYPTO_HashAsciiEncoded keyhash; struct GNUNET_CRYPTO_HashAsciiEncoded queryhash; char *peerId; char *peerSig; GNUNET_CRYPTO_hash_to_enc (&uri->data.loc.fi.chk.key, &keyhash); GNUNET_CRYPTO_hash_to_enc (&uri->data.loc.fi.chk.query, &queryhash); peerId = bin2enc (&uri->data.loc.peer, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); peerSig = bin2enc (&uri->data.loc.contentSignature, sizeof (struct GNUNET_CRYPTO_RsaSignature)); GNUNET_asprintf (&ret, "%s%s%s.%s.%llu.%s.%s.%llu", GNUNET_FS_URI_PREFIX, GNUNET_FS_URI_LOC_INFIX, (const char *) &keyhash, (const char *) &queryhash, (unsigned long long) GNUNET_ntohll (uri->data.loc. fi.file_length), peerId, peerSig, (unsigned long long) uri->data.loc.expirationTime.abs_value); GNUNET_free (peerSig); GNUNET_free (peerId); return ret; } /** * Convert a URI to a UTF-8 String. * * @param uri uri to convert to a string * @return the UTF-8 string */ char * GNUNET_FS_uri_to_string (const struct GNUNET_FS_Uri *uri) { if (uri == NULL) { GNUNET_break (0); return NULL; } switch (uri->type) { case ksk: return uri_ksk_to_string (uri); case sks: return uri_sks_to_string (uri); case chk: return uri_chk_to_string (uri); case loc: return uri_loc_to_string (uri); default: GNUNET_break (0); return NULL; } } /* end of fs_uri.c */ gnunet-0.9.3/src/fs/gnunet-publish.c0000644000175000017500000005242611760502551014266 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-publish.c * @brief publishing files on GNUnet * @author Christian Grothoff * @author Krista Bennett * @author James Blackwell * @author Igor Wronsky */ #include "platform.h" #include "gnunet_fs_service.h" static int ret; static int verbose; static const struct GNUNET_CONFIGURATION_Handle *cfg; static struct GNUNET_FS_Handle *ctx; static struct GNUNET_FS_PublishContext *pc; static struct GNUNET_CONTAINER_MetaData *meta; static struct GNUNET_FS_Uri *topKeywords; static struct GNUNET_FS_Uri *uri; static struct GNUNET_FS_BlockOptions bo = { {0LL}, 1, 365, 1 }; static char *uri_string; static char *next_id; static char *this_id; static char *pseudonym; static int do_insert; static int disable_extractor; static int do_simulate; static int extract_only; static int do_disable_creation_time; static GNUNET_SCHEDULER_TaskIdentifier kill_task; static struct GNUNET_FS_DirScanner *ds; static struct GNUNET_FS_ShareTreeItem * directory_scan_result; static struct GNUNET_FS_Namespace *namespace; /** * FIXME: docu */ static void do_stop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FS_PublishContext *p; kill_task = GNUNET_SCHEDULER_NO_TASK; if (pc != NULL) { p = pc; pc = NULL; GNUNET_FS_publish_stop (p); } if (NULL != meta) { GNUNET_CONTAINER_meta_data_destroy (meta); meta = NULL; } } /** * Stop the directory scanner (we had an error). * * @param cls closure * @param tc scheduler context */ static void stop_scanner_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { kill_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_FS_directory_scan_abort (ds); ds = NULL; if (namespace != NULL) { GNUNET_FS_namespace_delete (namespace, GNUNET_NO); namespace = NULL; } GNUNET_FS_stop (ctx); ctx = NULL; ret = 1; } /** * Called by FS client to give information about the progress of an * operation. * * @param cls closure * @param info details about the event, specifying the event type * and various bits about the event * @return client-context (for the next progress call * for this operation; should be set to NULL for * SUSPEND and STOPPED events). The value returned * will be passed to future callbacks in the respective * field in the GNUNET_FS_ProgressInfo struct. */ static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info) { char *s; switch (info->status) { case GNUNET_FS_STATUS_PUBLISH_START: break; case GNUNET_FS_STATUS_PUBLISH_PROGRESS: if (verbose) { s = GNUNET_STRINGS_relative_time_to_string (info->value.publish.eta); FPRINTF (stdout, _("Publishing `%s' at %llu/%llu (%s remaining)\n"), info->value.publish.filename, (unsigned long long) info->value.publish.completed, (unsigned long long) info->value.publish.size, s); GNUNET_free (s); } break; case GNUNET_FS_STATUS_PUBLISH_ERROR: FPRINTF (stderr, _("Error publishing: %s.\n"), info->value.publish.specifics.error.message); if (kill_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (kill_task); kill_task = GNUNET_SCHEDULER_NO_TASK; } kill_task = GNUNET_SCHEDULER_add_now (&do_stop_task, NULL); break; case GNUNET_FS_STATUS_PUBLISH_COMPLETED: FPRINTF (stdout, _("Publishing `%s' done.\n"), info->value.publish.filename); s = GNUNET_FS_uri_to_string (info->value.publish.specifics. completed.chk_uri); FPRINTF (stdout, _("URI is `%s'.\n"), s); GNUNET_free (s); if (info->value.publish.pctx == NULL) { if (kill_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (kill_task); kill_task = GNUNET_SCHEDULER_NO_TASK; } kill_task = GNUNET_SCHEDULER_add_now (&do_stop_task, NULL); } break; case GNUNET_FS_STATUS_PUBLISH_STOPPED: GNUNET_break (NULL == pc); return NULL; case GNUNET_FS_STATUS_UNINDEX_PROGRESS: return NULL; case GNUNET_FS_STATUS_UNINDEX_COMPLETED: FPRINTF (stderr, "%s", _("Cleanup after abort complete.\n")); return NULL; default: FPRINTF (stderr, _("Unexpected status: %d\n"), info->status); return NULL; } return ""; /* non-null */ } /** * Print metadata entries (except binary * metadata and the filename). * * @param cls closure * @param plugin_name name of the plugin that generated the meta data * @param type type of the meta data * @param format format of data * @param data_mime_type mime type of data * @param data value of the meta data * @param data_size number of bytes in data * @return always 0 */ static int meta_printer (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat format, const char *data_mime_type, const char *data, size_t data_size) { if ((format != EXTRACTOR_METAFORMAT_UTF8) && (format != EXTRACTOR_METAFORMAT_C_STRING)) return 0; if (type == EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME) return 0; FPRINTF (stdout, "\t%s - %s\n", EXTRACTOR_metatype_to_string (type), data); return 0; } /** * Iterator printing keywords * * @param cls closure * @param keyword the keyword * @param is_mandatory is the keyword mandatory (in a search) * @return GNUNET_OK to continue to iterate, GNUNET_SYSERR to abort */ static int keyword_printer (void *cls, const char *keyword, int is_mandatory) { FPRINTF (stdout, "\t%s\n", keyword); return GNUNET_OK; } /** * Function called on all entries before the publication. This is * where we perform modifications to the default based on command-line * options. * * @param cls closure * @param fi the entry in the publish-structure * @param length length of the file or directory * @param m metadata for the file or directory (can be modified) * @param uri pointer to the keywords that will be used for this entry (can be modified) * @param bo block options * @param do_index should we index? * @param client_info pointer to client context set upon creation (can be modified) * @return GNUNET_OK to continue, GNUNET_NO to remove * this entry from the directory, GNUNET_SYSERR * to abort the iteration */ static int publish_inspector (void *cls, struct GNUNET_FS_FileInformation *fi, uint64_t length, struct GNUNET_CONTAINER_MetaData *m, struct GNUNET_FS_Uri **uri, struct GNUNET_FS_BlockOptions *bo, int *do_index, void **client_info) { char *fn; char *fs; struct GNUNET_FS_Uri *new_uri; if (cls == fi) return GNUNET_OK; if (NULL != topKeywords) { if (*uri != NULL) { new_uri = GNUNET_FS_uri_ksk_merge (topKeywords, *uri); GNUNET_FS_uri_destroy (*uri); *uri = new_uri; GNUNET_FS_uri_destroy (topKeywords); } else { *uri = topKeywords; } topKeywords = NULL; } if (NULL != meta) { GNUNET_CONTAINER_meta_data_merge (m, meta); GNUNET_CONTAINER_meta_data_destroy (meta); meta = NULL; } if (!do_disable_creation_time) GNUNET_CONTAINER_meta_data_add_publication_date (m); if ( (disable_extractor) && (NULL != *uri) ) { GNUNET_FS_uri_destroy (*uri); *uri = NULL; } if (extract_only) { fn = GNUNET_CONTAINER_meta_data_get_by_type (m, EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME); fs = GNUNET_STRINGS_byte_size_fancy (length); FPRINTF (stdout, _("Meta data for file `%s' (%s)\n"), fn, fs); GNUNET_CONTAINER_meta_data_iterate (m, &meta_printer, NULL); FPRINTF (stdout, _("Keywords for file `%s' (%s)\n"), fn, fs); GNUNET_free (fn); GNUNET_free (fs); if (NULL != *uri) GNUNET_FS_uri_ksk_get_keywords (*uri, &keyword_printer, NULL); FPRINTF (stdout, "%s", "\n"); } if (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (m)) GNUNET_FS_file_information_inspect (fi, &publish_inspector, fi); return GNUNET_OK; } /** * FIXME: docu */ static void uri_sks_continuation (void *cls, const struct GNUNET_FS_Uri *ksk_uri, const char *emsg) { if (emsg != NULL) { FPRINTF (stderr, "%s\n", emsg); ret = 1; } GNUNET_FS_uri_destroy (uri); uri = NULL; GNUNET_FS_stop (ctx); ctx = NULL; } /** * FIXME: docu */ static void uri_ksk_continuation (void *cls, const struct GNUNET_FS_Uri *ksk_uri, const char *emsg) { struct GNUNET_FS_Namespace *ns; if (emsg != NULL) { FPRINTF (stderr, "%s\n", emsg); ret = 1; } if (pseudonym != NULL) { ns = GNUNET_FS_namespace_create (ctx, pseudonym); if (ns == NULL) { FPRINTF (stderr, _("Failed to create namespace `%s'\n"), pseudonym); ret = 1; } else { GNUNET_FS_publish_sks (ctx, ns, this_id, next_id, meta, uri, &bo, GNUNET_FS_PUBLISH_OPTION_NONE, &uri_sks_continuation, NULL); GNUNET_assert (GNUNET_OK == GNUNET_FS_namespace_delete (ns, GNUNET_NO)); return; } } GNUNET_FS_uri_destroy (uri); uri = NULL; GNUNET_FS_stop (ctx); ctx = NULL; } /** * FIXME: docu */ static struct GNUNET_FS_FileInformation * get_file_information (struct GNUNET_FS_ShareTreeItem *item) { struct GNUNET_FS_FileInformation *fi; struct GNUNET_FS_FileInformation *fic; struct GNUNET_FS_ShareTreeItem *child; if (item->is_directory == GNUNET_YES) { GNUNET_CONTAINER_meta_data_delete (item->meta, EXTRACTOR_METATYPE_MIMETYPE, NULL, 0); GNUNET_FS_meta_data_make_directory (item->meta); if (NULL == item->ksk_uri) { const char *mime = GNUNET_FS_DIRECTORY_MIME; item->ksk_uri = GNUNET_FS_uri_ksk_create_from_args (1, &mime); } else GNUNET_FS_uri_ksk_add_keyword (item->ksk_uri, GNUNET_FS_DIRECTORY_MIME, GNUNET_NO); fi = GNUNET_FS_file_information_create_empty_directory ( ctx, NULL, item->ksk_uri, item->meta, &bo, item->filename); for (child = item->children_head; child; child = child->next) { fic = get_file_information (child); GNUNET_break (GNUNET_OK == GNUNET_FS_file_information_add (fi, fic)); } } else { fi = GNUNET_FS_file_information_create_from_file ( ctx, NULL, item->filename, item->ksk_uri, item->meta, !do_insert, &bo); } return fi; } /** * FIXME: docu */ static void directory_trim_complete () { struct GNUNET_FS_FileInformation *fi; fi = get_file_information (directory_scan_result); GNUNET_FS_share_tree_free (directory_scan_result); directory_scan_result = NULL; if (fi == NULL) { FPRINTF (stderr, "%s", _("Could not publish\n")); if (namespace != NULL) GNUNET_FS_namespace_delete (namespace, GNUNET_NO); GNUNET_FS_stop (ctx); ret = 1; return; } GNUNET_FS_file_information_inspect (fi, &publish_inspector, NULL); if (extract_only) { if (namespace != NULL) GNUNET_FS_namespace_delete (namespace, GNUNET_NO); GNUNET_FS_file_information_destroy (fi, NULL, NULL); GNUNET_FS_stop (ctx); if (kill_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (kill_task); kill_task = GNUNET_SCHEDULER_NO_TASK; } return; } pc = GNUNET_FS_publish_start (ctx, fi, namespace, this_id, next_id, (do_simulate) ? GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY : GNUNET_FS_PUBLISH_OPTION_NONE); if (NULL == pc) { FPRINTF (stderr, "%s", _("Could not start publishing.\n")); GNUNET_FS_stop (ctx); ret = 1; return; } } /** * Function called by the directory scanner as we build the tree * that we will need to publish later. * * @param cls closure * @param filename which file we are making progress on * @param is_directory GNUNET_YES if this is a directory, * GNUNET_NO if this is a file * GNUNET_SYSERR if it is neither (or unknown) * @param reason kind of progress we are making */ static void directory_scan_cb (void *cls, const char *filename, int is_directory, enum GNUNET_FS_DirScannerProgressUpdateReason reason) { switch (reason) { case GNUNET_FS_DIRSCANNER_FILE_START: if (verbose > 1) { if (is_directory == GNUNET_YES) FPRINTF (stdout, _("Scanning directory `%s'.\n"), filename); else FPRINTF (stdout, _("Scanning file `%s'.\n"), filename); } break; case GNUNET_FS_DIRSCANNER_FILE_IGNORED: FPRINTF (stderr, _("There was trouble processing file `%s', skipping it.\n"), filename); break; case GNUNET_FS_DIRSCANNER_ALL_COUNTED: if (verbose) FPRINTF (stdout, "%s", _("Preprocessing complete.\n")); break; case GNUNET_FS_DIRSCANNER_EXTRACT_FINISHED: if (verbose > 2) FPRINTF (stdout, _("Extracting meta data from file `%s' complete.\n"), filename); break; case GNUNET_FS_DIRSCANNER_FINISHED: if (verbose > 1) FPRINTF (stdout, "%s", _("Meta data extraction has finished.\n")); directory_scan_result = GNUNET_FS_directory_scan_get_result (ds); ds = NULL; GNUNET_FS_share_tree_trim (directory_scan_result); directory_trim_complete (); break; case GNUNET_FS_DIRSCANNER_INTERNAL_ERROR: FPRINTF (stdout, "%s", _("Internal error scanning directory.\n")); if (kill_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (kill_task); kill_task = GNUNET_SCHEDULER_NO_TASK; } kill_task = GNUNET_SCHEDULER_add_now (&stop_scanner_task, NULL); break; default: GNUNET_assert (0); break; } fflush (stdout); } /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param c configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { char *ex; char *emsg; /* check arguments */ if ((uri_string != NULL) && (extract_only)) { printf (_("Cannot extract metadata from a URI!\n")); ret = -1; return; } if (((uri_string == NULL) || (extract_only)) && ((args[0] == NULL) || (args[1] != NULL))) { printf (_("You must specify one and only one filename for insertion.\n")); ret = -1; return; } if ((uri_string != NULL) && (args[0] != NULL)) { printf (_("You must NOT specify an URI and a filename.\n")); ret = -1; return; } if (pseudonym != NULL) { if (NULL == this_id) { FPRINTF (stderr, _("Option `%s' is required when using option `%s'.\n"), "-t", "-P"); ret = -1; return; } } else { /* ordinary insertion checks */ if (NULL != next_id) { FPRINTF (stderr, _("Option `%s' makes no sense without option `%s'.\n"), "-N", "-P"); ret = -1; return; } if (NULL != this_id) { FPRINTF (stderr, _("Option `%s' makes no sense without option `%s'.\n"), "-t", "-P"); ret = -1; return; } } cfg = c; ctx = GNUNET_FS_start (cfg, "gnunet-publish", &progress_cb, NULL, GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); if (NULL == ctx) { FPRINTF (stderr, _("Could not initialize `%s' subsystem.\n"), "FS"); ret = 1; return; } namespace = NULL; if (NULL != pseudonym) { namespace = GNUNET_FS_namespace_create (ctx, pseudonym); if (NULL == namespace) { FPRINTF (stderr, _("Could not create namespace `%s'\n"), pseudonym); GNUNET_FS_stop (ctx); ret = 1; return; } } if (NULL != uri_string) { emsg = NULL; uri = GNUNET_FS_uri_parse (uri_string, &emsg); if (uri == NULL) { FPRINTF (stderr, _("Failed to parse URI: %s\n"), emsg); GNUNET_free (emsg); if (namespace != NULL) GNUNET_FS_namespace_delete (namespace, GNUNET_NO); GNUNET_FS_stop (ctx); ret = 1; return; } GNUNET_FS_publish_ksk (ctx, topKeywords, meta, uri, &bo, GNUNET_FS_PUBLISH_OPTION_NONE, &uri_ksk_continuation, NULL); if (namespace != NULL) GNUNET_FS_namespace_delete (namespace, GNUNET_NO); return; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "FS", "EXTRACTORS", &ex)) ex = NULL; if (0 != ACCESS (args[0], R_OK)) { FPRINTF (stderr, _("Failed to access `%s': %s\n"), args[0], STRERROR (errno)); return; } ds = GNUNET_FS_directory_scan_start (args[0], disable_extractor, ex, &directory_scan_cb, NULL); if (NULL == ds) { FPRINTF (stderr, "%s", _("Failed to start meta directory scanner. Is gnunet-helper-publish-fs installed?\n")); return; } kill_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &do_stop_task, NULL); } /** * The main function to publish content to GNUnet. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { {'a', "anonymity", "LEVEL", gettext_noop ("set the desired LEVEL of sender-anonymity"), 1, &GNUNET_GETOPT_set_uint, &bo.anonymity_level}, {'d', "disable-creation-time", NULL, gettext_noop ("disable adding the creation time to the metadata of the uploaded file"), 0, &GNUNET_GETOPT_set_one, &do_disable_creation_time}, {'D', "disable-extractor", NULL, gettext_noop ("do not use libextractor to add keywords or metadata"), 0, &GNUNET_GETOPT_set_one, &disable_extractor}, {'e', "extract", NULL, gettext_noop ("print list of extracted keywords that would be used, but do not perform upload"), 0, &GNUNET_GETOPT_set_one, &extract_only}, {'k', "key", "KEYWORD", gettext_noop ("add an additional keyword for the top-level file or directory" " (this option can be specified multiple times)"), 1, &GNUNET_FS_getopt_set_keywords, &topKeywords}, {'m', "meta", "TYPE:VALUE", gettext_noop ("set the meta-data for the given TYPE to the given VALUE"), 1, &GNUNET_FS_getopt_set_metadata, &meta}, {'n', "noindex", NULL, gettext_noop ("do not index, perform full insertion (stores entire " "file in encrypted form in GNUnet database)"), 0, &GNUNET_GETOPT_set_one, &do_insert}, {'N', "next", "ID", gettext_noop ("specify ID of an updated version to be published in the future" " (for namespace insertions only)"), 1, &GNUNET_GETOPT_set_string, &next_id}, {'p', "priority", "PRIORITY", gettext_noop ("specify the priority of the content"), 1, &GNUNET_GETOPT_set_uint, &bo.content_priority}, {'P', "pseudonym", "NAME", gettext_noop ("publish the files under the pseudonym NAME (place file into namespace)"), 1, &GNUNET_GETOPT_set_string, &pseudonym}, {'r', "replication", "LEVEL", gettext_noop ("set the desired replication LEVEL"), 1, &GNUNET_GETOPT_set_uint, &bo.replication_level}, {'s', "simulate-only", NULL, gettext_noop ("only simulate the process but do not do any " "actual publishing (useful to compute URIs)"), 0, &GNUNET_GETOPT_set_one, &do_simulate}, {'t', "this", "ID", gettext_noop ("set the ID of this version of the publication" " (for namespace insertions only)"), 1, &GNUNET_GETOPT_set_string, &this_id}, {'u', "uri", "URI", gettext_noop ("URI to be published (can be used instead of passing a " "file to add keywords to the file with the respective URI)"), 1, &GNUNET_GETOPT_set_string, &uri_string}, {'V', "verbose", NULL, gettext_noop ("be verbose (print progress information)"), 0, &GNUNET_GETOPT_set_one, &verbose}, GNUNET_GETOPT_OPTION_END }; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUnet publish starts\n"); bo.expiration_time = GNUNET_FS_year_to_time (GNUNET_FS_get_current_year () + 2); return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-publish [OPTIONS] FILENAME", gettext_noop ("Publish a file or directory on GNUnet"), options, &run, NULL)) ? ret : 1; } /* end of gnunet-publish.c */ gnunet-0.9.3/src/fs/fs_search.c0000644000175000017500000013616511760502551013262 00000000000000/* This file is part of GNUnet. (C) 2001-2006, 2008-2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Tem ple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs_search.c * @brief Helper functions for searching. * @author Christian Grothoff */ #include "platform.h" #include "gnunet_constants.h" #include "gnunet_fs_service.h" #include "gnunet_protocols.h" #include "fs_api.h" /** * Number of availability trials we perform per search result. */ #define AVAILABILITY_TRIALS_MAX 8 /** * Fill in all of the generic fields for a search event and * call the callback. * * @param pi structure to fill in * @param sc overall search context * @return value returned by the callback */ void * GNUNET_FS_search_make_status_ (struct GNUNET_FS_ProgressInfo *pi, struct GNUNET_FS_SearchContext *sc) { void *ret; pi->value.search.sc = sc; pi->value.search.cctx = sc->client_info; pi->value.search.pctx = (NULL == sc->psearch_result) ? NULL : sc->psearch_result->client_info; pi->value.search.query = sc->uri; pi->value.search.duration = GNUNET_TIME_absolute_get_duration (sc->start_time); pi->value.search.anonymity = sc->anonymity; ret = sc->h->upcb (sc->h->upcb_cls, pi); return ret; } /** * Check if the given result is identical * to the given URI. * * @param cls points to the URI we check against * @param key not used * @param value a "struct GNUNET_FS_SearchResult" who's URI we * should compare with * @return GNUNET_SYSERR if the result is present, * GNUNET_OK otherwise */ static int test_result_present (void *cls, const GNUNET_HashCode * key, void *value) { const struct GNUNET_FS_Uri *uri = cls; struct GNUNET_FS_SearchResult *sr = value; if (GNUNET_FS_uri_test_equal (uri, sr->uri)) return GNUNET_SYSERR; return GNUNET_OK; } /** * We've found a new CHK result. Let the client * know about it. * * @param sc the search context * @param sr the specific result */ static void notify_client_chk_result (struct GNUNET_FS_SearchContext *sc, struct GNUNET_FS_SearchResult *sr) { struct GNUNET_FS_ProgressInfo pi; pi.status = GNUNET_FS_STATUS_SEARCH_RESULT; pi.value.search.specifics.result.meta = sr->meta; pi.value.search.specifics.result.uri = sr->uri; pi.value.search.specifics.result.result = sr; pi.value.search.specifics.result.applicability_rank = sr->optional_support; sr->client_info = GNUNET_FS_search_make_status_ (&pi, sc); } /** * We've found new information about an existing CHK result. Let the * client know about it. * * @param sc the search context * @param sr the specific result */ static void notify_client_chk_update (struct GNUNET_FS_SearchContext *sc, struct GNUNET_FS_SearchResult *sr) { struct GNUNET_FS_ProgressInfo pi; pi.status = GNUNET_FS_STATUS_SEARCH_UPDATE; pi.value.search.specifics.update.cctx = sr->client_info; pi.value.search.specifics.update.meta = sr->meta; pi.value.search.specifics.update.uri = sr->uri; pi.value.search.specifics.update.availability_rank = 2 * sr->availability_success - sr->availability_trials; pi.value.search.specifics.update.availability_certainty = sr->availability_trials; pi.value.search.specifics.update.applicability_rank = sr->optional_support; sr->client_info = GNUNET_FS_search_make_status_ (&pi, sc); } /** * Context for "get_result_present". */ struct GetResultContext { /** * The URI we're looking for. */ const struct GNUNET_FS_Uri *uri; /** * Where to store a pointer to the search * result struct if we found a match. */ struct GNUNET_FS_SearchResult *sr; }; /** * Check if the given result is identical to the given URI and if so * return it. * * @param cls a "struct GetResultContext" * @param key not used * @param value a "struct GNUNET_FS_SearchResult" who's URI we * should compare with * @return GNUNET_OK */ static int get_result_present (void *cls, const GNUNET_HashCode * key, void *value) { struct GetResultContext *grc = cls; struct GNUNET_FS_SearchResult *sr = value; if (GNUNET_FS_uri_test_equal (grc->uri, sr->uri)) grc->sr = sr; return GNUNET_OK; } /** * Signal result of last probe to client and then schedule next * probe. */ static void signal_probe_result (struct GNUNET_FS_SearchResult *sr) { struct GNUNET_FS_ProgressInfo pi; pi.status = GNUNET_FS_STATUS_SEARCH_UPDATE; pi.value.search.specifics.update.cctx = sr->client_info; pi.value.search.specifics.update.meta = sr->meta; pi.value.search.specifics.update.uri = sr->uri; pi.value.search.specifics.update.availability_rank = sr->availability_success; pi.value.search.specifics.update.availability_certainty = sr->availability_trials; pi.value.search.specifics.update.applicability_rank = sr->optional_support; sr->client_info = GNUNET_FS_search_make_status_ (&pi, sr->sc); GNUNET_FS_search_start_probe_ (sr); } /** * Handle the case where we have failed to receive a response for our probe. * * @param cls our 'struct GNUNET_FS_SearchResult*' * @param tc scheduler context */ static void probe_failure_handler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FS_SearchResult *sr = cls; sr->probe_cancel_task = GNUNET_SCHEDULER_NO_TASK; sr->availability_trials++; GNUNET_FS_download_stop (sr->probe_ctx, GNUNET_YES); sr->probe_ctx = NULL; GNUNET_FS_search_result_sync_ (sr); signal_probe_result (sr); } /** * Handle the case where we have gotten a response for our probe. * * @param cls our 'struct GNUNET_FS_SearchResult*' * @param tc scheduler context */ static void probe_success_handler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FS_SearchResult *sr = cls; sr->probe_cancel_task = GNUNET_SCHEDULER_NO_TASK; sr->availability_trials++; sr->availability_success++; GNUNET_FS_download_stop (sr->probe_ctx, GNUNET_YES); sr->probe_ctx = NULL; GNUNET_FS_search_result_sync_ (sr); signal_probe_result (sr); } /** * Notification of FS that a search probe has made progress. * This function is used INSTEAD of the client's event handler * for downloads where the GNUNET_FS_DOWNLOAD_IS_PROBE flag is set. * * @param cls closure, always NULL (!), actual closure * is in the client-context of the info struct * @param info details about the event, specifying the event type * and various bits about the event * @return client-context (for the next progress call * for this operation; should be set to NULL for * SUSPEND and STOPPED events). The value returned * will be passed to future callbacks in the respective * field in the GNUNET_FS_ProgressInfo struct. */ void * GNUNET_FS_search_probe_progress_ (void *cls, const struct GNUNET_FS_ProgressInfo *info) { struct GNUNET_FS_SearchResult *sr = info->value.download.cctx; struct GNUNET_TIME_Relative dur; switch (info->status) { case GNUNET_FS_STATUS_DOWNLOAD_START: /* ignore */ break; case GNUNET_FS_STATUS_DOWNLOAD_RESUME: /* probes should never be resumed */ GNUNET_assert (0); break; case GNUNET_FS_STATUS_DOWNLOAD_SUSPEND: /* probes should never be suspended */ GNUNET_break (0); break; case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: /* ignore */ break; case GNUNET_FS_STATUS_DOWNLOAD_ERROR: if (GNUNET_SCHEDULER_NO_TASK != sr->probe_cancel_task) { GNUNET_SCHEDULER_cancel (sr->probe_cancel_task); sr->probe_cancel_task = GNUNET_SCHEDULER_NO_TASK; } sr->probe_cancel_task = GNUNET_SCHEDULER_add_delayed (sr->remaining_probe_time, &probe_failure_handler, sr); break; case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: if (GNUNET_SCHEDULER_NO_TASK != sr->probe_cancel_task) { GNUNET_SCHEDULER_cancel (sr->probe_cancel_task); sr->probe_cancel_task = GNUNET_SCHEDULER_NO_TASK; } sr->probe_cancel_task = GNUNET_SCHEDULER_add_now (&probe_success_handler, sr); break; case GNUNET_FS_STATUS_DOWNLOAD_STOPPED: if (GNUNET_SCHEDULER_NO_TASK != sr->probe_cancel_task) { GNUNET_SCHEDULER_cancel (sr->probe_cancel_task); sr->probe_cancel_task = GNUNET_SCHEDULER_NO_TASK; } sr = NULL; break; case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sr->probe_cancel_task); sr->probe_active_time = GNUNET_TIME_absolute_get (); sr->probe_cancel_task = GNUNET_SCHEDULER_add_delayed (sr->remaining_probe_time, &probe_failure_handler, sr); break; case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: if (GNUNET_SCHEDULER_NO_TASK != sr->probe_cancel_task) { GNUNET_SCHEDULER_cancel (sr->probe_cancel_task); sr->probe_cancel_task = GNUNET_SCHEDULER_NO_TASK; } dur = GNUNET_TIME_absolute_get_duration (sr->probe_active_time); sr->remaining_probe_time = GNUNET_TIME_relative_subtract (sr->remaining_probe_time, dur); GNUNET_FS_search_result_sync_ (sr); break; default: GNUNET_break (0); return NULL; } return sr; } /** * Start download probes for the given search result. * * @param sr the search result */ void GNUNET_FS_search_start_probe_ (struct GNUNET_FS_SearchResult *sr) { uint64_t off; uint64_t len; if (NULL != sr->probe_ctx) return; if (NULL != sr->download) return; if (0 == (sr->sc->h->flags & GNUNET_FS_FLAGS_DO_PROBES)) return; if (sr->availability_trials > AVAILABILITY_TRIALS_MAX) return; if ( (chk != sr->uri->type) && (loc != sr->uri->type)) return; len = GNUNET_FS_uri_chk_get_file_size (sr->uri); if (0 == len) return; if ((len <= DBLOCK_SIZE) && (sr->availability_success > 0)) return; off = len / DBLOCK_SIZE; if (off > 0) off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, off); off *= DBLOCK_SIZE; if (len - off < DBLOCK_SIZE) len = len - off; else len = DBLOCK_SIZE; sr->remaining_probe_time = GNUNET_TIME_relative_multiply (sr->sc->h->avg_block_latency, 2 * (1 + sr->availability_trials)); sr->probe_ctx = GNUNET_FS_download_start (sr->sc->h, sr->uri, sr->meta, NULL, NULL, off, len, sr->sc->anonymity, GNUNET_FS_DOWNLOAD_NO_TEMPORARIES | GNUNET_FS_DOWNLOAD_IS_PROBE, sr, NULL); } /** * We have received a KSK result. Check how it fits in with the * overall query and notify the client accordingly. * * @param sc context for the overall query * @param ent entry for the specific keyword * @param uri the URI that was found * @param meta metadata associated with the URI * under the "ent" keyword */ static void process_ksk_result (struct GNUNET_FS_SearchContext *sc, struct SearchRequestEntry *ent, const struct GNUNET_FS_Uri *uri, const struct GNUNET_CONTAINER_MetaData *meta) { GNUNET_HashCode key; struct GNUNET_FS_SearchResult *sr; struct GetResultContext grc; int is_new; unsigned int koff; /* check if new */ GNUNET_assert (NULL != sc); GNUNET_FS_uri_to_key (uri, &key); if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_get_multiple (ent->results, &key, &test_result_present, (void *) uri)) return; /* duplicate result */ /* try to find search result in master map */ grc.sr = NULL; grc.uri = uri; GNUNET_CONTAINER_multihashmap_get_multiple (sc->master_result_map, &key, &get_result_present, &grc); sr = grc.sr; is_new = (NULL == sr) || (sr->mandatory_missing > 0); if (NULL == sr) { sr = GNUNET_malloc (sizeof (struct GNUNET_FS_SearchResult)); sr->sc = sc; sr->uri = GNUNET_FS_uri_dup (uri); sr->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); sr->mandatory_missing = sc->mandatory_count; sr->key = key; sr->keyword_bitmap = GNUNET_malloc ((sc->uri->data.ksk.keywordCount + 7) / 8); /* round up, count bits */ GNUNET_CONTAINER_multihashmap_put (sc->master_result_map, &key, sr, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); } else { GNUNET_CONTAINER_meta_data_merge (sr->meta, meta); } koff = ent - sc->requests; GNUNET_assert ( (ent >= sc->requests) && (koff < sc->uri->data.ksk.keywordCount)); sr->keyword_bitmap[koff / 8] |= (1 << (koff % 8)); /* check if mandatory satisfied */ if (ent->mandatory) sr->mandatory_missing--; else sr->optional_support++; if (0 != sr->mandatory_missing) return; if (is_new) notify_client_chk_result (sc, sr); else notify_client_chk_update (sc, sr); GNUNET_FS_search_result_sync_ (sr); GNUNET_FS_search_start_probe_ (sr); } /** * Start search for content, internal API. * * @param h handle to the file sharing subsystem * @param uri specifies the search parameters; can be * a KSK URI or an SKS URI. * @param anonymity desired level of anonymity * @param options options for the search * @param cctx client context * @param psearch parent search result (for namespace update searches) * @return context that can be used to control the search */ static struct GNUNET_FS_SearchContext * search_start (struct GNUNET_FS_Handle *h, const struct GNUNET_FS_Uri *uri, uint32_t anonymity, enum GNUNET_FS_SearchOptions options, void *cctx, struct GNUNET_FS_SearchResult *psearch); /** * We have received an SKS result. Start searching for updates and * notify the client if it is a new result. * * @param sc context for the overall query * @param id_update identifier for updates, NULL for none * @param uri the URI that was found * @param meta metadata associated with the URI */ static void process_sks_result (struct GNUNET_FS_SearchContext *sc, const char *id_update, const struct GNUNET_FS_Uri *uri, const struct GNUNET_CONTAINER_MetaData *meta) { struct GNUNET_FS_Uri uu; GNUNET_HashCode key; struct GNUNET_FS_SearchResult *sr; /* check if new */ GNUNET_assert (NULL != sc); GNUNET_FS_uri_to_key (uri, &key); GNUNET_CRYPTO_hash_xor (&uri->data.chk.chk.key, &uri->data.chk.chk.query, &key); if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_get_multiple (sc->master_result_map, &key, &test_result_present, (void *) uri)) return; /* duplicate result */ sr = GNUNET_malloc (sizeof (struct GNUNET_FS_SearchResult)); sr->sc = sc; sr->uri = GNUNET_FS_uri_dup (uri); sr->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); sr->key = key; GNUNET_CONTAINER_multihashmap_put (sc->master_result_map, &key, sr, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); GNUNET_FS_search_result_sync_ (sr); GNUNET_FS_search_start_probe_ (sr); /* notify client */ notify_client_chk_result (sc, sr); /* search for updates */ if (0 == strlen (id_update)) return; /* no updates */ uu.type = sks; uu.data.sks.namespace = sc->uri->data.sks.namespace; uu.data.sks.identifier = GNUNET_strdup (id_update); (void) search_start (sc->h, &uu, sc->anonymity, sc->options, NULL, sr); GNUNET_free (uu.data.sks.identifier); } /** * Decrypt a block using a 'keyword' as the passphrase. Given the * KSK public key derived from the keyword, this function looks up * the original keyword in the search context and decrypts the * given ciphertext block. * * @param sc search context with the keywords * @param public_key public key to use to lookup the keyword * @param edata encrypted data * @param edata_size number of bytes in 'edata' (and 'data') * @param data where to store the plaintext * @return keyword index on success, GNUNET_SYSERR on error (no such * keyword, internal error) */ static int decrypt_block_with_keyword (const struct GNUNET_FS_SearchContext *sc, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, const void *edata, size_t edata_size, char *data) { GNUNET_HashCode q; struct GNUNET_CRYPTO_AesSessionKey skey; struct GNUNET_CRYPTO_AesInitializationVector iv; int i; GNUNET_CRYPTO_hash (public_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &q); /* find key */ for (i = 0; i < sc->uri->data.ksk.keywordCount; i++) if (0 == memcmp (&q, &sc->requests[i].query, sizeof (GNUNET_HashCode))) break; if (i == sc->uri->data.ksk.keywordCount) { /* oops, does not match any of our keywords!? */ GNUNET_break (0); return GNUNET_SYSERR; } /* decrypt */ GNUNET_CRYPTO_hash_to_aes_key (&sc->requests[i].key, &skey, &iv); if (-1 == GNUNET_CRYPTO_aes_decrypt (edata, edata_size, &skey, &iv, data)) { GNUNET_break (0); return GNUNET_SYSERR; } return i; } /** * Process a keyword-search result. * * @param sc our search context * @param kb the kblock * @param size size of kb */ static void process_kblock (struct GNUNET_FS_SearchContext *sc, const struct KBlock *kb, size_t size) { size_t j; char pt[size - sizeof (struct KBlock)]; const char *eos; struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_FS_Uri *uri; char *emsg; int i; if (-1 == (i = decrypt_block_with_keyword (sc, &kb->keyspace, &kb[1], size - sizeof (struct KBlock), pt))) return; /* parse */ eos = memchr (pt, 0, sizeof (pt)); if (NULL == eos) { GNUNET_break_op (0); return; } j = eos - pt + 1; if (sizeof (pt) == j) meta = GNUNET_CONTAINER_meta_data_create (); else meta = GNUNET_CONTAINER_meta_data_deserialize (&pt[j], sizeof (pt) - j); if (NULL == meta) { GNUNET_break_op (0); /* kblock malformed */ return; } uri = GNUNET_FS_uri_parse (pt, &emsg); if (NULL == uri) { GNUNET_break_op (0); /* kblock malformed */ GNUNET_free_non_null (emsg); GNUNET_CONTAINER_meta_data_destroy (meta); return; } /* process */ process_ksk_result (sc, &sc->requests[i], uri, meta); /* clean up */ GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_FS_uri_destroy (uri); } /** * Process a keyword-search result with a namespace advertisment. * * @param sc our search context * @param nb the nblock * @param size size of nb */ static void process_nblock (struct GNUNET_FS_SearchContext *sc, const struct NBlock *nb, size_t size) { size_t j; char pt[size - sizeof (struct NBlock)]; const char *eos; struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_FS_Uri *uri; char *uris; int i; if (-1 == (i = decrypt_block_with_keyword (sc, &nb->keyspace, &nb[1], size - sizeof (struct NBlock), pt))) return; /* parse */ eos = memchr (pt, 0, sizeof (pt)); if (NULL == eos) { GNUNET_break_op (0); return; } j = eos - pt + 1; if (sizeof (pt) == j) meta = GNUNET_CONTAINER_meta_data_create (); else meta = GNUNET_CONTAINER_meta_data_deserialize (&pt[j], sizeof (pt) - j); if (NULL == meta) { GNUNET_break_op (0); /* nblock malformed */ return; } uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); uri->type = sks; uri->data.sks.identifier = GNUNET_strdup (pt); GNUNET_CRYPTO_hash (&nb->subspace, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &uri->data.sks.namespace); uris = GNUNET_FS_uri_to_string (uri); GNUNET_CONTAINER_meta_data_insert (meta, "", EXTRACTOR_METATYPE_URI, EXTRACTOR_METAFORMAT_UTF8, "text/plain", uris, strlen (uris) + 1); GNUNET_free (uris); GNUNET_PSEUDONYM_add (sc->h->cfg, &uri->data.sks.namespace, meta); /* process */ process_ksk_result (sc, &sc->requests[i], uri, meta); /* clean up */ GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_FS_uri_destroy (uri); } /** * Process a namespace-search result. * * @param sc our search context * @param sb the sblock * @param size size of sb */ static void process_sblock (struct GNUNET_FS_SearchContext *sc, const struct SBlock *sb, size_t size) { size_t len = size - sizeof (struct SBlock); char pt[len]; struct GNUNET_CRYPTO_AesSessionKey skey; struct GNUNET_CRYPTO_AesInitializationVector iv; struct GNUNET_FS_Uri *uri; struct GNUNET_CONTAINER_MetaData *meta; const char *id; const char *uris; size_t off; char *emsg; GNUNET_HashCode key; char *identifier; /* decrypt */ identifier = sc->uri->data.sks.identifier; GNUNET_CRYPTO_hash (identifier, strlen (identifier), &key); GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv); if (-1 == GNUNET_CRYPTO_aes_decrypt (&sb[1], len, &skey, &iv, pt)) { GNUNET_break (0); return; } /* parse */ off = GNUNET_STRINGS_buffer_tokenize (pt, len, 2, &id, &uris); if (0 == off) { GNUNET_break_op (0); /* sblock malformed */ return; } meta = GNUNET_CONTAINER_meta_data_deserialize (&pt[off], len - off); if (meta == NULL) { GNUNET_break_op (0); /* sblock malformed */ return; } uri = GNUNET_FS_uri_parse (uris, &emsg); if (NULL == uri) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to parse URI `%s': %s\n", uris, emsg); GNUNET_break_op (0); /* sblock malformed */ GNUNET_free_non_null (emsg); GNUNET_CONTAINER_meta_data_destroy (meta); return; } /* process */ process_sks_result (sc, id, uri, meta); /* clean up */ GNUNET_FS_uri_destroy (uri); GNUNET_CONTAINER_meta_data_destroy (meta); } /** * Process a search result. * * @param sc our search context * @param type type of the result * @param expiration when it will expire * @param data the (encrypted) response * @param size size of data */ static void process_result (struct GNUNET_FS_SearchContext *sc, enum GNUNET_BLOCK_Type type, struct GNUNET_TIME_Absolute expiration, const void *data, size_t size) { if (GNUNET_TIME_absolute_get_duration (expiration).rel_value > 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result received has already expired.\n"); return; /* result expired */ } switch (type) { case GNUNET_BLOCK_TYPE_FS_KBLOCK: if (!GNUNET_FS_uri_test_ksk (sc->uri)) { GNUNET_break (0); return; } if (sizeof (struct KBlock) > size) { GNUNET_break_op (0); return; } process_kblock (sc, data, size); break; case GNUNET_BLOCK_TYPE_FS_SBLOCK: if (!GNUNET_FS_uri_test_sks (sc->uri)) { GNUNET_break (0); return; } if (sizeof (struct SBlock) > size) { GNUNET_break_op (0); return; } process_sblock (sc, data, size); break; case GNUNET_BLOCK_TYPE_FS_NBLOCK: if (!GNUNET_FS_uri_test_ksk (sc->uri)) { GNUNET_break (0); return; } if (sizeof (struct NBlock) > size) { GNUNET_break_op (0); return; } process_nblock (sc, data, size); break; case GNUNET_BLOCK_TYPE_ANY: GNUNET_break (0); break; case GNUNET_BLOCK_TYPE_FS_DBLOCK: GNUNET_break (0); break; case GNUNET_BLOCK_TYPE_FS_ONDEMAND: GNUNET_break (0); break; case GNUNET_BLOCK_TYPE_FS_IBLOCK: GNUNET_break (0); break; default: GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Got result with unknown block type `%d', ignoring"), type); break; } } /** * Shutdown any existing connection to the FS * service and try to establish a fresh one * (and then re-transmit our search request). * * @param sc the search to reconnec */ static void try_reconnect (struct GNUNET_FS_SearchContext *sc); /** * Type of a function to call when we receive a message * from the service. * * @param cls closure * @param msg message received, NULL on timeout or fatal error */ static void receive_results (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_FS_SearchContext *sc = cls; const struct ClientPutMessage *cm; uint16_t msize; if ((NULL == msg) || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_FS_PUT) || (ntohs (msg->size) <= sizeof (struct ClientPutMessage))) { try_reconnect (sc); return; } msize = ntohs (msg->size); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving %u bytes of result from fs service\n", msize); cm = (const struct ClientPutMessage *) msg; process_result (sc, ntohl (cm->type), GNUNET_TIME_absolute_ntoh (cm->expiration), &cm[1], msize - sizeof (struct ClientPutMessage)); /* continue receiving */ GNUNET_CLIENT_receive (sc->client, &receive_results, sc, GNUNET_TIME_UNIT_FOREVER_REL); } /** * Schedule the transmission of the (next) search request * to the service. * * @param sc context for the search */ static void schedule_transmit_search_request (struct GNUNET_FS_SearchContext *sc); /** * Closure for 'build_result_set'. */ struct MessageBuilderContext { /** * How many entries can we store to xoff. */ unsigned int put_cnt; /** * How many entries should we skip. */ unsigned int skip_cnt; /** * Where to store the keys. */ GNUNET_HashCode *xoff; /** * Search context we are iterating for. */ struct GNUNET_FS_SearchContext *sc; /** * Keyword offset the search result must match (0 for SKS) */ unsigned int keyword_offset; }; /** * Iterating over the known results, pick those matching the given * result range and store their keys at 'xoff'. * * @param cls the 'struct MessageBuilderContext' * @param key key for a result * @param value the search result * @return GNUNET_OK to continue iterating */ static int build_result_set (void *cls, const GNUNET_HashCode * key, void *value) { struct MessageBuilderContext *mbc = cls; struct GNUNET_FS_SearchResult *sr = value; if ( (NULL != sr->keyword_bitmap) && (0 == (sr->keyword_bitmap[mbc->keyword_offset / 8] & (1 << (mbc->keyword_offset % 8)))) ) return GNUNET_OK; /* have no match for this keyword yet */ if (mbc->skip_cnt > 0) { mbc->skip_cnt--; return GNUNET_OK; } if (0 == mbc->put_cnt) return GNUNET_SYSERR; mbc->sc->search_request_map_offset++; mbc->xoff[--mbc->put_cnt] = *key; return GNUNET_OK; } /** * Iterating over the known results, count those * matching the given result range and increment * put count for each. * * @param cls the 'struct MessageBuilderContext' * @param key key for a result * @param value the search result * @return GNUNET_OK to continue iterating */ static int find_result_set (void *cls, const GNUNET_HashCode * key, void *value) { struct MessageBuilderContext *mbc = cls; struct GNUNET_FS_SearchResult *sr = value; if ( (NULL != sr->keyword_bitmap) && (0 == (sr->keyword_bitmap[mbc->keyword_offset / 8] & (1 << (mbc->keyword_offset % 8)))) ) return GNUNET_OK; /* have no match for this keyword yet */ mbc->put_cnt++; return GNUNET_OK; } /** * We're ready to transmit the search request to the * file-sharing service. Do it. * * @param cls closure * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_search_request (void *cls, size_t size, void *buf) { struct GNUNET_FS_SearchContext *sc = cls; struct MessageBuilderContext mbc; size_t msize; struct SearchMessage *sm; const char *identifier; GNUNET_HashCode key; GNUNET_HashCode idh; unsigned int sqms; uint32_t options; if (NULL == buf) { try_reconnect (sc); return 0; } mbc.sc = sc; mbc.skip_cnt = sc->search_request_map_offset; sm = buf; sm->header.type = htons (GNUNET_MESSAGE_TYPE_FS_START_SEARCH); mbc.xoff = (GNUNET_HashCode *) & sm[1]; options = SEARCH_MESSAGE_OPTION_NONE; if (0 != (sc->options & GNUNET_FS_SEARCH_OPTION_LOOPBACK_ONLY)) options |= SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY; if (GNUNET_FS_uri_test_ksk (sc->uri)) { msize = sizeof (struct SearchMessage); GNUNET_assert (size >= msize); mbc.keyword_offset = sc->keyword_offset; mbc.put_cnt = 0; GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, &find_result_set, &mbc); sqms = mbc.put_cnt; mbc.put_cnt = (size - msize) / sizeof (GNUNET_HashCode); mbc.put_cnt = GNUNET_MIN (mbc.put_cnt, sqms - mbc.skip_cnt); if (sc->search_request_map_offset < sqms) GNUNET_assert (mbc.put_cnt > 0); sm->header.size = htons (msize); sm->type = htonl (GNUNET_BLOCK_TYPE_ANY); sm->anonymity_level = htonl (sc->anonymity); memset (&sm->target, 0, sizeof (GNUNET_HashCode)); sm->query = sc->requests[sc->keyword_offset].query; msize += sizeof (GNUNET_HashCode) * mbc.put_cnt; GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, &build_result_set, &mbc); sm->header.size = htons (msize); GNUNET_assert (sqms >= sc->search_request_map_offset); if (sqms != sc->search_request_map_offset) { /* more requesting to be done... */ sm->options = htonl (options | SEARCH_MESSAGE_OPTION_CONTINUED); schedule_transmit_search_request (sc); return msize; } sm->options = htonl (options); sc->keyword_offset++; if (sc->uri->data.ksk.keywordCount != sc->keyword_offset) { /* more requesting to be done... */ schedule_transmit_search_request (sc); return msize; } } else { GNUNET_assert (GNUNET_FS_uri_test_sks (sc->uri)); msize = sizeof (struct SearchMessage); GNUNET_assert (size >= msize); sm->type = htonl (GNUNET_BLOCK_TYPE_FS_SBLOCK); sm->anonymity_level = htonl (sc->anonymity); sm->target = sc->uri->data.sks.namespace; identifier = sc->uri->data.sks.identifier; GNUNET_CRYPTO_hash (identifier, strlen (identifier), &key); GNUNET_CRYPTO_hash (&key, sizeof (GNUNET_HashCode), &idh); GNUNET_CRYPTO_hash_xor (&idh, &sm->target, &sm->query); mbc.put_cnt = (size - msize) / sizeof (GNUNET_HashCode); sqms = GNUNET_CONTAINER_multihashmap_size (sc->master_result_map); mbc.put_cnt = GNUNET_MIN (mbc.put_cnt, sqms - mbc.skip_cnt); mbc.keyword_offset = 0; if (sc->search_request_map_offset < sqms) GNUNET_assert (mbc.put_cnt > 0); msize += sizeof (GNUNET_HashCode) * mbc.put_cnt; GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, &build_result_set, &mbc); sm->header.size = htons (msize); GNUNET_assert (sqms >= sc->search_request_map_offset); if (sqms != sc->search_request_map_offset) { /* more requesting to be done... */ sm->options = htonl (options | SEARCH_MESSAGE_OPTION_CONTINUED); schedule_transmit_search_request (sc); return msize; } sm->options = htonl (options); } GNUNET_CLIENT_receive (sc->client, &receive_results, sc, GNUNET_TIME_UNIT_FOREVER_REL); return msize; } /** * Schedule the transmission of the (next) search request * to the service. * * @param sc context for the search */ static void schedule_transmit_search_request (struct GNUNET_FS_SearchContext *sc) { size_t size; unsigned int sqms; unsigned int fit; size = sizeof (struct SearchMessage); sqms = GNUNET_CONTAINER_multihashmap_size (sc->master_result_map) - sc->search_request_map_offset; fit = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - size) / sizeof (GNUNET_HashCode); fit = GNUNET_MIN (fit, sqms); size += sizeof (GNUNET_HashCode) * fit; GNUNET_CLIENT_notify_transmit_ready (sc->client, size, GNUNET_CONSTANTS_SERVICE_TIMEOUT, GNUNET_NO, &transmit_search_request, sc); } /** * Reconnect to the FS service and transmit * our queries NOW. * * @param cls our search context * @param tc unused */ static void do_reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FS_SearchContext *sc = cls; struct GNUNET_CLIENT_Connection *client; sc->task = GNUNET_SCHEDULER_NO_TASK; client = GNUNET_CLIENT_connect ("fs", sc->h->cfg); if (NULL == client) { try_reconnect (sc); return; } sc->client = client; sc->search_request_map_offset = 0; sc->keyword_offset = 0; schedule_transmit_search_request (sc); } /** * Shutdown any existing connection to the FS * service and try to establish a fresh one * (and then re-transmit our search request). * * @param sc the search to reconnec */ static void try_reconnect (struct GNUNET_FS_SearchContext *sc) { if (NULL != sc->client) { GNUNET_CLIENT_disconnect (sc->client); sc->client = NULL; } sc->task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_reconnect, sc); } /** * Start search for content, internal API. * * @param h handle to the file sharing subsystem * @param uri specifies the search parameters; can be * a KSK URI or an SKS URI. * @param anonymity desired level of anonymity * @param options options for the search * @param cctx initial value for the client context * @param psearch parent search result (for namespace update searches) * @return context that can be used to control the search */ static struct GNUNET_FS_SearchContext * search_start (struct GNUNET_FS_Handle *h, const struct GNUNET_FS_Uri *uri, uint32_t anonymity, enum GNUNET_FS_SearchOptions options, void *cctx, struct GNUNET_FS_SearchResult *psearch) { struct GNUNET_FS_SearchContext *sc; struct GNUNET_FS_ProgressInfo pi; sc = GNUNET_malloc (sizeof (struct GNUNET_FS_SearchContext)); sc->h = h; sc->options = options; sc->uri = GNUNET_FS_uri_dup (uri); sc->anonymity = anonymity; sc->start_time = GNUNET_TIME_absolute_get (); if (NULL != psearch) { sc->psearch_result = psearch; psearch->update_search = sc; } sc->master_result_map = GNUNET_CONTAINER_multihashmap_create (16); sc->client_info = cctx; if (GNUNET_OK != GNUNET_FS_search_start_searching_ (sc)) { GNUNET_FS_uri_destroy (sc->uri); GNUNET_CONTAINER_multihashmap_destroy (sc->master_result_map); GNUNET_free (sc); return NULL; } GNUNET_FS_search_sync_ (sc); pi.status = GNUNET_FS_STATUS_SEARCH_START; sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc); return sc; } /** * Build the request and actually initiate the search using the * GNUnet FS service. * * @param sc search context * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_FS_search_start_searching_ (struct GNUNET_FS_SearchContext *sc) { unsigned int i; const char *keyword; GNUNET_HashCode hc; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub; struct GNUNET_CRYPTO_RsaPrivateKey *pk; GNUNET_assert (NULL == sc->client); if (GNUNET_FS_uri_test_ksk (sc->uri)) { GNUNET_assert (0 != sc->uri->data.ksk.keywordCount); sc->requests = GNUNET_malloc (sizeof (struct SearchRequestEntry) * sc->uri->data.ksk.keywordCount); for (i = 0; i < sc->uri->data.ksk.keywordCount; i++) { keyword = &sc->uri->data.ksk.keywords[i][1]; GNUNET_CRYPTO_hash (keyword, strlen (keyword), &hc); pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&hc); GNUNET_assert (NULL != pk); GNUNET_CRYPTO_rsa_key_get_public (pk, &pub); GNUNET_CRYPTO_rsa_key_free (pk); GNUNET_CRYPTO_hash (&pub, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &sc->requests[i].query); sc->requests[i].mandatory = (sc->uri->data.ksk.keywords[i][0] == '+'); if (sc->requests[i].mandatory) sc->mandatory_count++; sc->requests[i].results = GNUNET_CONTAINER_multihashmap_create (4); GNUNET_CRYPTO_hash (keyword, strlen (keyword), &sc->requests[i].key); } } sc->client = GNUNET_CLIENT_connect ("fs", sc->h->cfg); if (NULL == sc->client) return GNUNET_SYSERR; schedule_transmit_search_request (sc); return GNUNET_OK; } /** * Freeze probes for the given search result. * * @param cls the global FS handle * @param key the key for the search result (unused) * @param value the search result to free * @return GNUNET_OK */ static int search_result_freeze_probes (void *cls, const GNUNET_HashCode * key, void *value) { struct GNUNET_FS_SearchResult *sr = value; if (NULL != sr->probe_ctx) { GNUNET_FS_download_stop (sr->probe_ctx, GNUNET_YES); sr->probe_ctx = NULL; } if (GNUNET_SCHEDULER_NO_TASK != sr->probe_cancel_task) { GNUNET_SCHEDULER_cancel (sr->probe_cancel_task); sr->probe_cancel_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != sr->update_search) GNUNET_FS_search_pause (sr->update_search); return GNUNET_OK; } /** * Resume probes for the given search result. * * @param cls the global FS handle * @param key the key for the search result (unused) * @param value the search result to free * @return GNUNET_OK */ static int search_result_resume_probes (void *cls, const GNUNET_HashCode * key, void *value) { struct GNUNET_FS_SearchResult *sr = value; GNUNET_FS_search_start_probe_ (sr); if (NULL != sr->update_search) GNUNET_FS_search_continue (sr->update_search); return GNUNET_OK; } /** * Signal suspend and free the given search result. * * @param cls the global FS handle * @param key the key for the search result (unused) * @param value the search result to free * @return GNUNET_OK */ static int search_result_suspend (void *cls, const GNUNET_HashCode * key, void *value) { struct GNUNET_FS_SearchContext *sc = cls; struct GNUNET_FS_SearchResult *sr = value; struct GNUNET_FS_ProgressInfo pi; if (NULL != sr->download) { GNUNET_FS_download_signal_suspend_ (sr->download); sr->download = NULL; } if (NULL != sr->probe_ctx) { GNUNET_FS_download_stop (sr->probe_ctx, GNUNET_YES); sr->probe_ctx = NULL; } if (NULL != sr->update_search) { GNUNET_FS_search_signal_suspend_ (sr->update_search); sr->update_search = NULL; } pi.status = GNUNET_FS_STATUS_SEARCH_RESULT_SUSPEND; pi.value.search.specifics.result_suspend.cctx = sr->client_info; pi.value.search.specifics.result_suspend.meta = sr->meta; pi.value.search.specifics.result_suspend.uri = sr->uri; sr->client_info = GNUNET_FS_search_make_status_ (&pi, sc); GNUNET_break (NULL == sr->client_info); GNUNET_free_non_null (sr->serialization); GNUNET_FS_uri_destroy (sr->uri); GNUNET_CONTAINER_meta_data_destroy (sr->meta); if (GNUNET_SCHEDULER_NO_TASK != sr->probe_cancel_task) { GNUNET_SCHEDULER_cancel (sr->probe_cancel_task); sr->probe_cancel_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_free_non_null (sr->keyword_bitmap); GNUNET_free (sr); return GNUNET_OK; } /** * Create SUSPEND event for the given search operation * and then clean up our state (without stop signal). * * @param cls the 'struct GNUNET_FS_SearchContext' to signal for */ void GNUNET_FS_search_signal_suspend_ (void *cls) { struct GNUNET_FS_SearchContext *sc = cls; struct GNUNET_FS_ProgressInfo pi; unsigned int i; GNUNET_FS_end_top (sc->h, sc->top); GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, &search_result_suspend, sc); pi.status = GNUNET_FS_STATUS_SEARCH_SUSPEND; sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc); GNUNET_break (NULL == sc->client_info); if (sc->task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (sc->task); if (NULL != sc->client) GNUNET_CLIENT_disconnect (sc->client); GNUNET_CONTAINER_multihashmap_destroy (sc->master_result_map); if (NULL != sc->requests) { GNUNET_assert (GNUNET_FS_uri_test_ksk (sc->uri)); for (i = 0; i < sc->uri->data.ksk.keywordCount; i++) GNUNET_CONTAINER_multihashmap_destroy (sc->requests[i].results); } GNUNET_free_non_null (sc->requests); GNUNET_free_non_null (sc->emsg); GNUNET_FS_uri_destroy (sc->uri); GNUNET_free_non_null (sc->serialization); GNUNET_free (sc); } /** * Start search for content. * * @param h handle to the file sharing subsystem * @param uri specifies the search parameters; can be * a KSK URI or an SKS URI. * @param anonymity desired level of anonymity * @param options options for the search * @param cctx initial value for the client context * @return context that can be used to control the search */ struct GNUNET_FS_SearchContext * GNUNET_FS_search_start (struct GNUNET_FS_Handle *h, const struct GNUNET_FS_Uri *uri, uint32_t anonymity, enum GNUNET_FS_SearchOptions options, void *cctx) { struct GNUNET_FS_SearchContext *ret; ret = search_start (h, uri, anonymity, options, cctx, NULL); if (NULL == ret) return NULL; ret->top = GNUNET_FS_make_top (h, &GNUNET_FS_search_signal_suspend_, ret); return ret; } /** * Pause search. * * @param sc context for the search that should be paused */ void GNUNET_FS_search_pause (struct GNUNET_FS_SearchContext *sc) { struct GNUNET_FS_ProgressInfo pi; if (GNUNET_SCHEDULER_NO_TASK != sc->task) GNUNET_SCHEDULER_cancel (sc->task); sc->task = GNUNET_SCHEDULER_NO_TASK; if (NULL != sc->client) GNUNET_CLIENT_disconnect (sc->client); sc->client = NULL; GNUNET_FS_search_sync_ (sc); GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, &search_result_freeze_probes, sc); pi.status = GNUNET_FS_STATUS_SEARCH_PAUSED; sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc); } /** * Continue paused search. * * @param sc context for the search that should be resumed */ void GNUNET_FS_search_continue (struct GNUNET_FS_SearchContext *sc) { struct GNUNET_FS_ProgressInfo pi; GNUNET_assert (NULL == sc->client); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sc->task); do_reconnect (sc, NULL); GNUNET_FS_search_sync_ (sc); pi.status = GNUNET_FS_STATUS_SEARCH_CONTINUED; sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc); GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, &search_result_resume_probes, sc); } /** * Signal stop for the given search result. * * @param cls the global FS handle * @param key the key for the search result (unused) * @param value the search result to free * @return GNUNET_OK */ static int search_result_stop (void *cls, const GNUNET_HashCode * key, void *value) { struct GNUNET_FS_SearchContext *sc = cls; struct GNUNET_FS_SearchResult *sr = value; struct GNUNET_FS_ProgressInfo pi; if (NULL != sr->download) { sr->download->search = NULL; sr->download->top = GNUNET_FS_make_top (sr->download->h, &GNUNET_FS_download_signal_suspend_, sr->download); if (NULL != sr->download->serialization) { GNUNET_FS_remove_sync_file_ (sc->h, GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD, sr->download->serialization); GNUNET_free (sr->download->serialization); sr->download->serialization = NULL; } pi.status = GNUNET_FS_STATUS_DOWNLOAD_LOST_PARENT; GNUNET_FS_download_make_status_ (&pi, sr->download); GNUNET_FS_download_sync_ (sr->download); sr->download = NULL; } pi.status = GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED; pi.value.search.specifics.result_stopped.cctx = sr->client_info; pi.value.search.specifics.result_stopped.meta = sr->meta; pi.value.search.specifics.result_stopped.uri = sr->uri; sr->client_info = GNUNET_FS_search_make_status_ (&pi, sc); return GNUNET_OK; } /** * Free the given search result. * * @param cls the global FS handle * @param key the key for the search result (unused) * @param value the search result to free * @return GNUNET_OK */ static int search_result_free (void *cls, const GNUNET_HashCode * key, void *value) { struct GNUNET_FS_SearchResult *sr = value; if (NULL != sr->update_search) { GNUNET_FS_search_stop (sr->update_search); GNUNET_assert (NULL == sr->update_search); } GNUNET_break (NULL == sr->client_info); GNUNET_free_non_null (sr->serialization); GNUNET_FS_uri_destroy (sr->uri); GNUNET_CONTAINER_meta_data_destroy (sr->meta); if (NULL != sr->probe_ctx) GNUNET_FS_download_stop (sr->probe_ctx, GNUNET_YES); if (GNUNET_SCHEDULER_NO_TASK != sr->probe_cancel_task) GNUNET_SCHEDULER_cancel (sr->probe_cancel_task); GNUNET_free_non_null (sr->keyword_bitmap); GNUNET_free (sr); return GNUNET_OK; } /** * Stop search for content. * * @param sc context for the search that should be stopped */ void GNUNET_FS_search_stop (struct GNUNET_FS_SearchContext *sc) { struct GNUNET_FS_ProgressInfo pi; unsigned int i; if (NULL != sc->top) GNUNET_FS_end_top (sc->h, sc->top); GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, &search_result_stop, sc); if (NULL != sc->psearch_result) sc->psearch_result->update_search = NULL; if (NULL != sc->serialization) { GNUNET_FS_remove_sync_file_ (sc->h, (sc->psearch_result != NULL) ? GNUNET_FS_SYNC_PATH_CHILD_SEARCH : GNUNET_FS_SYNC_PATH_MASTER_SEARCH, sc->serialization); GNUNET_FS_remove_sync_dir_ (sc->h, (sc->psearch_result != NULL) ? GNUNET_FS_SYNC_PATH_CHILD_SEARCH : GNUNET_FS_SYNC_PATH_MASTER_SEARCH, sc->serialization); GNUNET_free (sc->serialization); } pi.status = GNUNET_FS_STATUS_SEARCH_STOPPED; sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc); GNUNET_break (NULL == sc->client_info); if (GNUNET_SCHEDULER_NO_TASK != sc->task) GNUNET_SCHEDULER_cancel (sc->task); if (NULL != sc->client) GNUNET_CLIENT_disconnect (sc->client); GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, &search_result_free, sc); GNUNET_CONTAINER_multihashmap_destroy (sc->master_result_map); if (NULL != sc->requests) { GNUNET_assert (GNUNET_FS_uri_test_ksk (sc->uri)); for (i = 0; i < sc->uri->data.ksk.keywordCount; i++) GNUNET_CONTAINER_multihashmap_destroy (sc->requests[i].results); } GNUNET_free_non_null (sc->requests); GNUNET_free_non_null (sc->emsg); GNUNET_FS_uri_destroy (sc->uri); GNUNET_free (sc); } /* end of fs_search.c */ gnunet-0.9.3/src/fs/test_fs_uri.c0000644000175000017500000002116011760502551013637 00000000000000/* This file is part of GNUnet. (C) 2003, 2004, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/test_fs_uri.c * @brief Test for fs_uri.c * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_fs_service.h" #include "fs_api.h" #define ABORT() { fprintf(stderr, "Error at %s:%d\n", __FILE__, __LINE__); return 1; } static int testKeyword () { char *uri; struct GNUNET_FS_Uri *ret; char *emsg; if (NULL != (ret = GNUNET_FS_uri_parse ("gnunet://fs/ksk/++", &emsg))) { GNUNET_FS_uri_destroy (ret); ABORT (); } GNUNET_free (emsg); ret = GNUNET_FS_uri_parse ("gnunet://fs/ksk/foo+bar", &emsg); if (ret == NULL) { GNUNET_free (emsg); ABORT (); } if (!GNUNET_FS_uri_test_ksk (ret)) { GNUNET_FS_uri_destroy (ret); ABORT (); } if ((2 != ret->data.ksk.keywordCount) || (0 != strcmp (" foo", ret->data.ksk.keywords[0])) || (0 != strcmp (" bar", ret->data.ksk.keywords[1]))) { GNUNET_FS_uri_destroy (ret); ABORT (); } uri = GNUNET_FS_uri_to_string (ret); if (0 != strcmp (uri, "gnunet://fs/ksk/foo+bar")) { GNUNET_free (uri); GNUNET_FS_uri_destroy (ret); ABORT (); } GNUNET_free (uri); GNUNET_FS_uri_destroy (ret); return 0; } static int testLocation () { struct GNUNET_FS_Uri *uri; char *uric; struct GNUNET_FS_Uri *uri2; struct GNUNET_FS_Uri *baseURI; char *emsg; struct GNUNET_CONFIGURATION_Handle *cfg; baseURI = GNUNET_FS_uri_parse ("gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.42", &emsg); GNUNET_assert (baseURI != NULL); GNUNET_assert (emsg == NULL); cfg = GNUNET_CONFIGURATION_create (); if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, "test_fs_uri_data.conf")) { FPRINTF (stderr, "%s", "Failed to parse configuration file\n"); GNUNET_FS_uri_destroy (baseURI); GNUNET_CONFIGURATION_destroy (cfg); return 1; } uri = GNUNET_FS_uri_loc_create (baseURI, cfg, GNUNET_TIME_absolute_get ()); if (uri == NULL) { GNUNET_break (0); GNUNET_FS_uri_destroy (baseURI); GNUNET_CONFIGURATION_destroy (cfg); return 1; } if (!GNUNET_FS_uri_test_loc (uri)) { GNUNET_break (0); GNUNET_FS_uri_destroy (uri); GNUNET_FS_uri_destroy (baseURI); GNUNET_CONFIGURATION_destroy (cfg); return 1; } uri2 = GNUNET_FS_uri_loc_get_uri (uri); if (!GNUNET_FS_uri_test_equal (baseURI, uri2)) { GNUNET_break (0); GNUNET_FS_uri_destroy (uri); GNUNET_FS_uri_destroy (uri2); GNUNET_FS_uri_destroy (baseURI); GNUNET_CONFIGURATION_destroy (cfg); return 1; } GNUNET_FS_uri_destroy (uri2); GNUNET_FS_uri_destroy (baseURI); uric = GNUNET_FS_uri_to_string (uri); #if 0 /* not for the faint of heart: */ printf ("URI: `%s'\n", uric); #endif uri2 = GNUNET_FS_uri_parse (uric, &emsg); GNUNET_free (uric); if (uri2 == NULL) { GNUNET_break (0); GNUNET_FS_uri_destroy (uri); GNUNET_CONFIGURATION_destroy (cfg); GNUNET_free (emsg); return 1; } GNUNET_assert (NULL == emsg); if (GNUNET_YES != GNUNET_FS_uri_test_equal (uri, uri2)) { GNUNET_break (0); GNUNET_FS_uri_destroy (uri); GNUNET_FS_uri_destroy (uri2); GNUNET_CONFIGURATION_destroy (cfg); return 1; } GNUNET_FS_uri_destroy (uri2); GNUNET_FS_uri_destroy (uri); GNUNET_CONFIGURATION_destroy (cfg); return 0; } static int testNamespace (int i) { char *uri; struct GNUNET_FS_Uri *ret; char *emsg; if (NULL != (ret = GNUNET_FS_uri_parse ("gnunet://fs/sks/D1KJS9H2A82Q65VKQ0ML3RFU6U1D3VUK", &emsg))) { GNUNET_FS_uri_destroy (ret); ABORT (); } GNUNET_free (emsg); if (NULL != (ret = GNUNET_FS_uri_parse ("gnunet://fs/sks/D1KJS9H2A82Q65VKQ0ML3RFU6U1D3V/test", &emsg))) { GNUNET_FS_uri_destroy (ret); ABORT (); } GNUNET_free (emsg); if (NULL != (ret = GNUNET_FS_uri_parse ("gnunet://fs/sks/test", &emsg))) { GNUNET_FS_uri_destroy (ret); ABORT (); } GNUNET_free (emsg); ret = GNUNET_FS_uri_parse ("gnunet://fs/sks/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820/test", &emsg); if (ret == NULL) { GNUNET_free (emsg); ABORT (); } if (GNUNET_FS_uri_test_ksk (ret)) { GNUNET_FS_uri_destroy (ret); ABORT (); } if (!GNUNET_FS_uri_test_sks (ret)) { GNUNET_FS_uri_destroy (ret); ABORT (); } uri = GNUNET_FS_uri_to_string (ret); if (0 != strcmp (uri, "gnunet://fs/sks/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820/test")) { GNUNET_FS_uri_destroy (ret); GNUNET_free (uri); ABORT (); } GNUNET_free (uri); GNUNET_FS_uri_destroy (ret); return 0; } static int testFile (int i) { char *uri; struct GNUNET_FS_Uri *ret; char *emsg; if (NULL != (ret = GNUNET_FS_uri_parse ("gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H00000440000.42", &emsg))) { GNUNET_FS_uri_destroy (ret); ABORT (); } GNUNET_free (emsg); if (NULL != (ret = GNUNET_FS_uri_parse ("gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000", &emsg))) { GNUNET_FS_uri_destroy (ret); ABORT (); } GNUNET_free (emsg); if (NULL != (ret = GNUNET_FS_uri_parse ("gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.FGH", &emsg))) { GNUNET_FS_uri_destroy (ret); ABORT (); } GNUNET_free (emsg); ret = GNUNET_FS_uri_parse ("gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.42", &emsg); if (ret == NULL) { GNUNET_free (emsg); ABORT (); } if (GNUNET_FS_uri_test_ksk (ret)) { GNUNET_FS_uri_destroy (ret); ABORT (); } if (GNUNET_FS_uri_test_sks (ret)) { GNUNET_FS_uri_destroy (ret); ABORT (); } if (GNUNET_ntohll (ret->data.chk.file_length) != 42) { GNUNET_FS_uri_destroy (ret); ABORT (); } uri = GNUNET_FS_uri_to_string (ret); if (0 != strcmp (uri, "gnunet://fs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.42")) { GNUNET_free (uri); GNUNET_FS_uri_destroy (ret); ABORT (); } GNUNET_free (uri); GNUNET_FS_uri_destroy (ret); return 0; } int main (int argc, char *argv[]) { int failureCount = 0; int i; GNUNET_log_setup ("test_fs_uri", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_CRYPTO_random_disable_entropy_gathering (); failureCount += testKeyword (); failureCount += testLocation (); for (i = 0; i < 255; i++) { /* FPRINTF (stderr, "%s", "."); */ failureCount += testNamespace (i); failureCount += testFile (i); } /* FPRINTF (stderr, "%s", "\n"); */ GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-uri"); if (failureCount != 0) return 1; return 0; } /* end of test_fs_uri.c */ gnunet-0.9.3/src/fs/gnunet-service-fs_lc.c0000644000175000017500000003606711760502551015347 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-service-fs_lc.c * @brief API to handle 'local clients' * @author Christian Grothoff */ #include "platform.h" #include "gnunet-service-fs.h" #include "gnunet-service-fs_lc.h" #include "gnunet-service-fs_cp.h" #include "gnunet-service-fs_pr.h" /** * Doubly-linked list of requests we are performing * on behalf of the same client. */ struct ClientRequest { /** * This is a doubly-linked list. */ struct ClientRequest *next; /** * This is a doubly-linked list. */ struct ClientRequest *prev; /** * Request this entry represents. */ struct GSF_PendingRequest *pr; /** * Client list this request belongs to. */ struct GSF_LocalClient *lc; /** * Task scheduled to destroy the request. */ GNUNET_SCHEDULER_TaskIdentifier kill_task; }; /** * Replies to be transmitted to the client. The actual * response message is allocated after this struct. */ struct ClientResponse { /** * This is a doubly-linked list. */ struct ClientResponse *next; /** * This is a doubly-linked list. */ struct ClientResponse *prev; /** * Client list entry this response belongs to. */ struct GSF_LocalClient *lc; /** * Number of bytes in the response. */ size_t msize; }; /** * A local client. */ struct GSF_LocalClient { /** * We keep clients in a DLL. */ struct GSF_LocalClient *next; /** * We keep clients in a DLL. */ struct GSF_LocalClient *prev; /** * ID of the client. */ struct GNUNET_SERVER_Client *client; /** * Head of list of requests performed on behalf * of this client right now. */ struct ClientRequest *cr_head; /** * Tail of list of requests performed on behalf * of this client right now. */ struct ClientRequest *cr_tail; /** * Head of linked list of responses. */ struct ClientResponse *res_head; /** * Tail of linked list of responses. */ struct ClientResponse *res_tail; /** * Context for sending replies. */ struct GNUNET_SERVER_TransmitHandle *th; }; /** * Head of linked list of our local clients. */ static struct GSF_LocalClient *client_head; /** * Head of linked list of our local clients. */ static struct GSF_LocalClient *client_tail; /** * Look up a local client record or create one if it * doesn't exist yet. * * @param client handle of the client * @return handle to local client entry */ struct GSF_LocalClient * GSF_local_client_lookup_ (struct GNUNET_SERVER_Client *client) { struct GSF_LocalClient *pos; pos = client_head; while ((pos != NULL) && (pos->client != client)) pos = pos->next; if (pos != NULL) return pos; pos = GNUNET_malloc (sizeof (struct GSF_LocalClient)); pos->client = client; GNUNET_CONTAINER_DLL_insert (client_head, client_tail, pos); return pos; } /** * Free the given client request. * * @param cls the client request to free * @param tc task context */ static void client_request_destroy (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ClientRequest *cr = cls; struct GSF_LocalClient *lc; cr->kill_task = GNUNET_SCHEDULER_NO_TASK; lc = cr->lc; GNUNET_CONTAINER_DLL_remove (lc->cr_head, lc->cr_tail, cr); GSF_pending_request_cancel_ (cr->pr, GNUNET_NO); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# client searches active"), -1, GNUNET_NO); GNUNET_free (cr); } /** * Handle a reply to a pending request. Also called if a request * expires (then with data == NULL). The handler may be called * many times (depending on the request type), but will not be * called during or after a call to GSF_pending_request_cancel * and will also not be called anymore after a call signalling * expiration. * * @param cls user-specified closure * @param eval evaluation of the result * @param pr handle to the original pending request * @param reply_anonymity_level anonymity level for the reply, UINT32_MAX for "unknown" * @param expiration when does 'data' expire? * @param last_transmission when was the last time we've tried to download this block? (FOREVER if unknown) * @param type type of the block * @param data response data, NULL on request expiration * @param data_len number of bytes in data */ static void client_response_handler (void *cls, enum GNUNET_BLOCK_EvaluationResult eval, struct GSF_PendingRequest *pr, uint32_t reply_anonymity_level, struct GNUNET_TIME_Absolute expiration, struct GNUNET_TIME_Absolute last_transmission, enum GNUNET_BLOCK_Type type, const void *data, size_t data_len) { struct ClientRequest *cr = cls; struct GSF_LocalClient *lc; struct ClientPutMessage *pm; const struct GSF_PendingRequestData *prd; size_t msize; if (NULL == data) { /* ugh, request 'timed out' -- how can this be? */ GNUNET_break (0); return; } prd = GSF_pending_request_get_data_ (pr); GNUNET_break (type != GNUNET_BLOCK_TYPE_ANY); if ((prd->type != type) && (prd->type != GNUNET_BLOCK_TYPE_ANY)) { GNUNET_break (0); return; } GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# replies received for local clients"), 1, GNUNET_NO); GNUNET_assert (pr == cr->pr); lc = cr->lc; msize = sizeof (struct ClientPutMessage) + data_len; { char buf[msize] GNUNET_ALIGN; pm = (struct ClientPutMessage *) buf; pm->header.type = htons (GNUNET_MESSAGE_TYPE_FS_PUT); pm->header.size = htons (msize); pm->type = htonl (type); pm->expiration = GNUNET_TIME_absolute_hton (expiration); pm->last_transmission = GNUNET_TIME_absolute_hton (last_transmission); memcpy (&pm[1], data, data_len); GSF_local_client_transmit_ (lc, &pm->header); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Queued reply to query `%s' for local client\n", GNUNET_h2s (&prd->query), (unsigned int) prd->type); if (eval != GNUNET_BLOCK_EVALUATION_OK_LAST) return; if (GNUNET_SCHEDULER_NO_TASK != cr->kill_task) cr->kill_task = GNUNET_SCHEDULER_add_now (&client_request_destroy, cr); } /** * Handle START_SEARCH-message (search request from local client). * Only responsible for creating the request entry itself and setting * up reply callback and cancellation on client disconnect. Does NOT * execute the actual request strategy (planning). * * @param client identification of the client * @param message the actual message * @param prptr where to store the pending request handle for the request * @return GNUNET_YES to start local processing, * GNUNET_NO to not (yet) start local processing, * GNUNET_SYSERR on error */ int GSF_local_client_start_search_handler_ (struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message, struct GSF_PendingRequest **prptr) { static GNUNET_HashCode all_zeros; const struct SearchMessage *sm; struct GSF_LocalClient *lc; struct ClientRequest *cr; struct GSF_PendingRequestData *prd; uint16_t msize; unsigned int sc; enum GNUNET_BLOCK_Type type; enum GSF_PendingRequestOptions options; msize = ntohs (message->size); if ((msize < sizeof (struct SearchMessage)) || (0 != (msize - sizeof (struct SearchMessage)) % sizeof (GNUNET_HashCode))) { GNUNET_break (0); *prptr = NULL; return GNUNET_SYSERR; } GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# client searches received"), 1, GNUNET_NO); sc = (msize - sizeof (struct SearchMessage)) / sizeof (GNUNET_HashCode); sm = (const struct SearchMessage *) message; type = ntohl (sm->type); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received request for `%s' of type %u from local client\n", GNUNET_h2s (&sm->query), (unsigned int) type); lc = GSF_local_client_lookup_ (client); cr = NULL; /* detect duplicate KBLOCK requests */ if ((type == GNUNET_BLOCK_TYPE_FS_KBLOCK) || (type == GNUNET_BLOCK_TYPE_FS_NBLOCK) || (type == GNUNET_BLOCK_TYPE_ANY)) { cr = lc->cr_head; while (cr != NULL) { prd = GSF_pending_request_get_data_ (cr->pr); /* only unify with queries that hae not yet started local processing (SEARCH_MESSAGE_OPTION_CONTINUED was always set) and that have a matching query and type */ if ((GNUNET_YES != prd->has_started) && (0 != memcmp (&prd->query, &sm->query, sizeof (GNUNET_HashCode))) && (prd->type == type)) break; cr = cr->next; } } if (cr != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have existing request, merging content-seen lists.\n"); GSF_pending_request_update_ (cr->pr, (const GNUNET_HashCode *) &sm[1], sc); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# client searches updated (merged content seen list)"), 1, GNUNET_NO); } else { GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# client searches active"), 1, GNUNET_NO); cr = GNUNET_malloc (sizeof (struct ClientRequest)); cr->lc = lc; GNUNET_CONTAINER_DLL_insert (lc->cr_head, lc->cr_tail, cr); options = GSF_PRO_LOCAL_REQUEST; if (0 != (SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY & ntohl (sm->options))) options |= GSF_PRO_LOCAL_ONLY; cr->pr = GSF_pending_request_create_ (options, type, &sm->query, (type == GNUNET_BLOCK_TYPE_FS_SBLOCK) ? &sm->target /* namespace */ : NULL, (0 != memcmp (&sm->target, &all_zeros, sizeof (GNUNET_HashCode))) ? (const struct GNUNET_PeerIdentity *) &sm->target : NULL, NULL, 0, 0 /* bf */ , ntohl (sm->anonymity_level), 0 /* priority */ , 0 /* ttl */ , 0 /* sender PID */ , 0 /* origin PID */ , (const GNUNET_HashCode *) &sm[1], sc, &client_response_handler, cr); } *prptr = cr->pr; return (0 != (SEARCH_MESSAGE_OPTION_CONTINUED & ntohl (sm->options))) ? GNUNET_NO : GNUNET_YES; } /** * Transmit the given message by copying it to the target buffer * "buf". "buf" will be NULL and "size" zero if the socket was closed * for writing in the meantime. In that case, do nothing * (the disconnect or shutdown handler will take care of the rest). * If we were able to transmit messages and there are still more * pending, ask core again for further calls to this function. * * @param cls closure, pointer to the 'struct GSF_LocalClient' * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_to_client (void *cls, size_t size, void *buf) { struct GSF_LocalClient *lc = cls; char *cbuf = buf; struct ClientResponse *res; size_t msize; lc->th = NULL; if (NULL == buf) return 0; msize = 0; while ((NULL != (res = lc->res_head)) && (res->msize <= size)) { memcpy (&cbuf[msize], &res[1], res->msize); msize += res->msize; size -= res->msize; GNUNET_CONTAINER_DLL_remove (lc->res_head, lc->res_tail, res); GNUNET_free (res); } if (NULL != res) lc->th = GNUNET_SERVER_notify_transmit_ready (lc->client, res->msize, GNUNET_TIME_UNIT_FOREVER_REL, &transmit_to_client, lc); return msize; } /** * Transmit a message to the given local client as soon as possible. * If the client disconnects before transmission, the message is * simply discarded. * * @param lc recipient * @param msg message to transmit to client */ void GSF_local_client_transmit_ (struct GSF_LocalClient *lc, const struct GNUNET_MessageHeader *msg) { struct ClientResponse *res; size_t msize; msize = ntohs (msg->size); res = GNUNET_malloc (sizeof (struct ClientResponse) + msize); res->lc = lc; res->msize = msize; memcpy (&res[1], msg, msize); GNUNET_CONTAINER_DLL_insert_tail (lc->res_head, lc->res_tail, res); if (NULL == lc->th) lc->th = GNUNET_SERVER_notify_transmit_ready (lc->client, msize, GNUNET_TIME_UNIT_FOREVER_REL, &transmit_to_client, lc); } /** * A client disconnected from us. Tear down the local client * record. * * @param cls unused * @param client handle of the client */ void GSF_client_disconnect_handler_ (void *cls, struct GNUNET_SERVER_Client *client) { struct GSF_LocalClient *pos; struct ClientRequest *cr; struct ClientResponse *res; pos = client_head; while ((pos != NULL) && (pos->client != client)) pos = pos->next; if (pos == NULL) return; while (NULL != (cr = pos->cr_head)) { GNUNET_CONTAINER_DLL_remove (pos->cr_head, pos->cr_tail, cr); GSF_pending_request_cancel_ (cr->pr, GNUNET_NO); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# client searches active"), -1, GNUNET_NO); if (GNUNET_SCHEDULER_NO_TASK != cr->kill_task) GNUNET_SCHEDULER_cancel (cr->kill_task); GNUNET_free (cr); } while (NULL != (res = pos->res_head)) { GNUNET_CONTAINER_DLL_remove (pos->res_head, pos->res_tail, res); GNUNET_free (res); } if (pos->th != NULL) { GNUNET_SERVER_notify_transmit_ready_cancel (pos->th); pos->th = NULL; } GSF_handle_local_client_disconnect_ (pos); GNUNET_CONTAINER_DLL_remove (client_head, client_tail, pos); GNUNET_free (pos); } /* end of gnunet-service-fs_lc.c */ gnunet-0.9.3/src/fs/gnunet-helper-fs-publish.c0000644000175000017500000003046411760645101016146 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/fs/gnunet-helper-fs-publish.c * @brief Tool to help extract meta data asynchronously * @author Christian Grothoff * * This program will scan a directory for files with meta data * and report the results to stdout. */ #include "platform.h" #include "gnunet_fs_service.h" /** * A node of a directory tree. */ struct ScanTreeNode { /** * This is a doubly-linked list */ struct ScanTreeNode *next; /** * This is a doubly-linked list */ struct ScanTreeNode *prev; /** * Parent of this node, NULL for top-level entries. */ struct ScanTreeNode *parent; /** * This is a doubly-linked tree * NULL for files and empty directories */ struct ScanTreeNode *children_head; /** * This is a doubly-linked tree * NULL for files and empty directories */ struct ScanTreeNode *children_tail; /** * Name of the file/directory */ char *filename; /** * Size of the file (if it is a file), in bytes. * At the moment it is set to 0 for directories. */ uint64_t file_size; /** * GNUNET_YES if this is a directory */ int is_directory; }; /** * List of libextractor plugins to use for extracting. */ static struct EXTRACTOR_PluginList *plugins; /** * Add meta data that libextractor finds to our meta data * container. * * @param cls closure, our meta data container * @param plugin_name name of the plugin that produced this value; * special values can be used (i.e. '<zlib>' for zlib being * used in the main libextractor library and yielding * meta data). * @param type libextractor-type describing the meta data * @param format basic format information about data * @param data_mime_type mime-type of data (not of the original file); * can be NULL (if mime-type is not known) * @param data actual meta-data found * @param data_len number of bytes in data * @return always 0 to continue extracting */ static int add_to_md (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat format, const char *data_mime_type, const char *data, size_t data_len) { struct GNUNET_CONTAINER_MetaData *md = cls; (void) GNUNET_CONTAINER_meta_data_insert (md, plugin_name, type, format, data_mime_type, data, data_len); return 0; } /** * Free memory of the 'tree' structure * * @param tree tree to free */ static void free_tree (struct ScanTreeNode *tree) { struct ScanTreeNode *pos; while (NULL != (pos = tree->children_head)) free_tree (pos); if (NULL != tree->parent) GNUNET_CONTAINER_DLL_remove (tree->parent->children_head, tree->parent->children_tail, tree); GNUNET_free (tree->filename); GNUNET_free (tree); } /** * Write 'size' bytes from 'buf' into 'out'. * * @param buf buffer with data to write * @param size number of bytes to write * @return GNUNET_OK on success, GNUNET_SYSERR on error */ static int write_all (const void *buf, size_t size) { const char *cbuf = buf; size_t total; ssize_t wr; total = 0; do { wr = write (1, &cbuf[total], size - total); if (wr > 0) total += wr; } while ( (wr > 0) && (total < size) ); if (wr <= 0) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to write to stdout: %s\n", strerror (errno)); return (total == size) ? GNUNET_OK : GNUNET_SYSERR; } /** * Write message to the master process. * * @param message_type message type to use * @param data data to append, NULL for none * @param data_length number of bytes in data * @return GNUNET_SYSERR to stop scanning (the pipe was broken somehow) */ static int write_message (uint16_t message_type, const char *data, size_t data_length) { struct GNUNET_MessageHeader hdr; #if 0 fprintf (stderr, "Helper sends %u-byte message of type %u\n", (unsigned int) (sizeof (struct GNUNET_MessageHeader) + data_length), (unsigned int) message_type); #endif hdr.type = htons (message_type); hdr.size = htons (sizeof (struct GNUNET_MessageHeader) + data_length); if ( (GNUNET_OK != write_all (&hdr, sizeof (hdr))) || (GNUNET_OK != write_all (data, data_length)) ) return GNUNET_SYSERR; return GNUNET_OK; } /** * Function called to (recursively) add all of the files in the * directory to the tree. Called by the directory scanner to initiate * the scan. Does NOT yet add any metadata. * * @param filename file or directory to scan * @param dst where to store the resulting share tree item; * NULL is stored in 'dst' upon recoverable errors (GNUNET_OK is returned) * @return GNUNET_OK on success, GNUNET_SYSERR on error */ static int preprocess_file (const char *filename, struct ScanTreeNode **dst); /** * Closure for the 'scan_callback' */ struct RecursionContext { /** * Parent to add the files to. */ struct ScanTreeNode *parent; /** * Flag to set to GNUNET_YES on serious errors. */ int stop; }; /** * Function called by the directory iterator to (recursively) add all * of the files in the directory to the tree. Called by the directory * scanner to initiate the scan. Does NOT yet add any metadata. * * @param cls the 'struct RecursionContext' * @param filename file or directory to scan * @return GNUNET_OK on success, GNUNET_SYSERR on error */ static int scan_callback (void *cls, const char *filename) { struct RecursionContext *rc = cls; struct ScanTreeNode *chld; if (GNUNET_OK != preprocess_file (filename, &chld)) { rc->stop = GNUNET_YES; return GNUNET_SYSERR; } if (NULL == chld) return GNUNET_OK; chld->parent = rc->parent; GNUNET_CONTAINER_DLL_insert (rc->parent->children_head, rc->parent->children_tail, chld); return GNUNET_OK; } /** * Function called to (recursively) add all of the files in the * directory to the tree. Called by the directory scanner to initiate * the scan. Does NOT yet add any metadata. * * @param filename file or directory to scan * @param dst where to store the resulting share tree item; * NULL is stored in 'dst' upon recoverable errors (GNUNET_OK is returned) * @return GNUNET_OK on success, GNUNET_SYSERR on error */ static int preprocess_file (const char *filename, struct ScanTreeNode **dst) { struct ScanTreeNode *item; struct stat sbuf; uint64_t fsize = 0; if ((0 != STAT (filename, &sbuf)) || ((!S_ISDIR (sbuf.st_mode)) && (GNUNET_OK != GNUNET_DISK_file_size ( filename, &fsize, GNUNET_NO, GNUNET_YES)))) { /* If the file doesn't exist (or is not stat-able for any other reason) skip it (but report it), but do continue. */ if (GNUNET_OK != write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_SKIP_FILE, filename, strlen (filename) + 1)) return GNUNET_SYSERR; /* recoverable error, store 'NULL' in *dst */ *dst = NULL; return GNUNET_OK; } /* Report the progress */ if (GNUNET_OK != write_message (S_ISDIR (sbuf.st_mode) ? GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_DIRECTORY : GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_FILE, filename, strlen (filename) + 1)) return GNUNET_SYSERR; item = GNUNET_malloc (sizeof (struct ScanTreeNode)); item->filename = GNUNET_strdup (filename); item->is_directory = (S_ISDIR (sbuf.st_mode)) ? GNUNET_YES : GNUNET_NO; item->file_size = fsize; if (GNUNET_YES == item->is_directory) { struct RecursionContext rc; rc.parent = item; rc.stop = GNUNET_NO; GNUNET_DISK_directory_scan (filename, &scan_callback, &rc); if ( (GNUNET_YES == rc.stop) || (GNUNET_OK != write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_DIRECTORY, "..", 3)) ) { free_tree (item); return GNUNET_SYSERR; } } *dst = item; return GNUNET_OK; } /** * Extract metadata from files. * * @param item entry we are processing * @return GNUNET_OK on success, GNUNET_SYSERR on fatal errors */ static int extract_files (struct ScanTreeNode *item) { struct GNUNET_CONTAINER_MetaData *meta; ssize_t size; size_t slen; if (GNUNET_YES == item->is_directory) { /* for directories, we simply only descent, no extraction, no progress reporting */ struct ScanTreeNode *pos; for (pos = item->children_head; NULL != pos; pos = pos->next) if (GNUNET_OK != extract_files (pos)) return GNUNET_SYSERR; return GNUNET_OK; } /* this is the expensive operation, *afterwards* we'll check for aborts */ meta = GNUNET_CONTAINER_meta_data_create (); if (NULL != plugins) EXTRACTOR_extract (plugins, item->filename, NULL, 0, &add_to_md, meta); slen = strlen (item->filename) + 1; size = GNUNET_CONTAINER_meta_data_get_serialized_size (meta); if (-1 == size) { /* no meta data */ GNUNET_CONTAINER_meta_data_destroy (meta); if (GNUNET_OK != write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_META_DATA, item->filename, slen)) return GNUNET_SYSERR; return GNUNET_OK; } { char buf[size + slen]; char *dst = &buf[slen]; memcpy (buf, item->filename, slen); size = GNUNET_CONTAINER_meta_data_serialize (meta, &dst, size, GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); if (size < 0) { GNUNET_break (0); size = 0; } GNUNET_CONTAINER_meta_data_destroy (meta); if (GNUNET_OK != write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_META_DATA, buf, slen + size)) return GNUNET_SYSERR; } return GNUNET_OK; } /** * Main function of the helper process to extract meta data. * * @param argc should be 3 * @param argv [0] our binary name * [1] name of the file or directory to process * [2] "-" to disable extraction, NULL for defaults, * otherwise custom plugins to load from LE * @return 0 on success */ int main(int argc, char **argv) { const char *filename_expanded; const char *ex; struct ScanTreeNode *root; #if WINDOWS /* We're using stdout to communicate binary data back to the parent; use * binary mode. */ _setmode (1, _O_BINARY); #endif /* parse command line */ if ( (3 != argc) && (2 != argc) ) { FPRINTF (stderr, "%s", "gnunet-helper-fs-publish needs exactly one or two arguments\n"); return 1; } filename_expanded = argv[1]; ex = argv[2]; if ( (NULL == ex) || (0 != strcmp (ex, "-")) ) { plugins = EXTRACTOR_plugin_add_defaults (EXTRACTOR_OPTION_DEFAULT_POLICY); if (NULL != ex) plugins = EXTRACTOR_plugin_add_config (plugins, ex, EXTRACTOR_OPTION_DEFAULT_POLICY); } /* scan tree to find out how much work there is to be done */ if (GNUNET_OK != preprocess_file (filename_expanded, &root)) { (void) write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_ERROR, NULL, 0); return 2; } /* signal that we're done counting files, so that a percentage of progress can now be calculated */ if (GNUNET_OK != write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_COUNTING_DONE, NULL, 0)) return 3; if (NULL != root) { if (GNUNET_OK != extract_files (root)) { (void) write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_ERROR, NULL, 0); free_tree (root); return 4; } free_tree (root); } /* enable "clean" shutdown by telling parent that we are done */ (void) write_message (GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_FINISHED, NULL, 0); if (NULL != plugins) EXTRACTOR_plugin_remove_all (plugins); return 0; } /* end of gnunet-helper-fs-publish.c */ gnunet-0.9.3/src/fs/test_gnunet_fs_rec_data.tgz0000644000175000017500000004263611504756340016562 00000000000000‹³IºKí}{oW–gþ¾Ÿ¢ , i†’ßN'î4 ÈtÌmYÒH² Ä%²(U›¬bW%sûÝ÷üÎã>Ф’lºw0&ºcI¬ºsÏûu'eóè›?øó˜>ß¾xŸ|ûâqü¯}¾yòäÙ‹—ÏŸ?ùôÛo?yúøåËo²ôÂðY¶]ÞdÙ77MÝÝÖÓé¶ç~ëûÿ¢Ÿ ÿõŒÿ¡óöçÿìñ‹¯çÿøÈùŸ¾üãæÀÓÙn?ÿ'ßöÎÿÙãÇO¿ÉÿqK ŸÿæçYÙñm^Ý'õÍ¡ûg/çëçüýÿ±Ôÿ¤‘ÿ/^>ûJÿÿˆÏWúÿïýýçÿ?餸±þ÷ô«þ÷øÈùŸþôÍñ ÿòøù‹'Ïüù¿ø–õ¿gÏ_~åÿÿˆO¶áóÓéûì§áéðâè$;ÿãÉè8£ÿO/‡nÓãôùP4mYWÙ³Aöô»ì.«"{J4ï\v\/VMysÛe{ÇûüÇìMC2粞v÷ySdoêe5É;z{ªñaöçÛ®[|ÿèÑ´ÖÍÍ£¿¸lxW4«š-ÛlQ4ó²ëŠIÖÕÙ˜FÏòj’MʶkÊëeWdôì57Ç—eѺ¬žfÝ-½9+ÇEÕÙ¤/çEÕ 2z>Cø•ÕMVv¾ª»,ŸÍêûbrè¶m—?çM‘ϯgžºº-jEU4ù,;_^ÓlÙ‰ÎHãæÙ”¶=àÏŠiçW3­×0°B³¢É>—Õ¤ÅÒïëæs{h“è[-^ËæuÛeÞ]4ù¸+Ç´~9÷“¢-oªbâj]þ™¿ÏWÙª^6¼°I=<Û[‰ÁRà ]A–ý¸¢ÕW]“·ÝÀu¿¹ã²êŠj"çt³Ì›œ~/ú3ºµ ø8B ï?§íÔ7M>?8 æXz»¤W踚bž—ô† 0d0Hٵٲ¥‘hé?ä±âí¨GOâ ÷Àž<ÈiUØ…Íø kÉ‹aÍÜÖØW^­ô4>Zê¬È[˜Ð_¯x…ù’¸ ¯ñc½ÌÆyÅ#á;ŒÂÐÒý·´…ºfLøù¶¨²{Ä¢È?c9€€_Ï_aM1-š¸MS˜€ánÑОhÎ3~ónS¬ÉÐw·y‡ƒt·ù H„B% ®­/ÛÓãnnýi„yVN1dv_¶·û?ía\”wxyÙŒ1ä¤È訛¢c¢åÝ=áý½Šg"4öÓÓë8mZÛXV‡Aª¬*î¯3ÀëôÃ}®ê{?î¤Æ˜Œ3_¥Ï¯vŸ,g¶×òiT…ÀpÑwÄy3€¸³IQ­pFØ„Œ)/byûY¿bê\6 HªáýÈS‡Ìè¤k<Ä¡¸qÑtD¾vA„T^—³²Ãa(˜7žR ¥¦/§À@BúI9J~¿>- æcD‰ð2oh¬âK>_Ìh܇VÐ.Ç·â t·Fqô[W2D˜º³i¡›“øÎyKßUX ¦—4`E äåóÂéºÚ5Äš(åñ@=§·WLt{ÚE¨'ÐòXIãºøEµ·„.ŒÙŠ($·Ú¬å%®#ýTš0œ^vÌêPƒ LIíùÉ&ô"‚én³îž°£+í÷nïÉ>¡ ñ½ŽeÈ^'9\`öÞÓ}‚9±Á/0&%~wSÞÞÍŠb,u[–ñ*vñ Òp˜;*¢øSǬ¿«]žWYÞ®m‡ù/o“¶8&>Ùÿ+¾,f`îÎN¢)D<ól KVŒ ¼ê„»ÊÄׄ~ÂþyRç'méŒÃtMñ÷eÙ o^I¤êÐuAHÑ|¦?å­f2È)ʲJæÏ¤Ìq$v @Ð[y§°™dăIw©—-m ’AVt;(é ?Ãí²ž3ÐÊñ. n!ûÊò1=ÀHpê òhßͲrëÛè7^('Œ[DdùŒ´¼¹åGæyµœ’ú@DÐ8åtmÍ\2€ ™ õ‰&¤£®Æõ|AÄIPT¤AòÀÙù&éIDrbg^–µ+Bå99v42ÑMXÃ5H¢—  ™Œô0f=YŽ;QH{"ž,Iæô˜IIC@…‡h Zþ½àk~,Ú— ºèrÚOÊZï wá0…°(Ål¾¾%)„¯þ1f͘Åil·…®†ï.³£Ó×ÙñÙéëÑÕèìô?>$q6-+™‘ßß¹ŠdÌŽ¨§|¾FEÏ<mÕÂe oUîˆÂ=/rÚ•—w³’Ž`–ß+_•š&Jm+Ç–Í@Y ¡`1/$"M3R¾üº 2÷Ðñ²¡ãû9sæ€ÐõÕF#ìÔS*[g«Ï²aN“é#bN&tä-‹˜l‡Dî=µ£/íÉNPjvhe+`CÌãh½d+çUùïy€7¡ÙŽˆdDÖ&€2Ë™õO(T“|Ád‡_yÓÙ9àG$Cxž··8"˜`éA»ÊÁ@!LP¯Tœ° ;®r¤ŽE+QNOû^ÎX>ðâJàúlHèÂ#!¶£krÐJ³«XäŸv®Ù¾Âƒ˜8~Šq”íŒk‹žÁßvE© &êªüœzØÑð<ºS=J¿ö@uç7D®ëpž0š°• ò‘¥BNv ~«—Dæôî™2™ŽŒ“ÖÑ@M’ôë¬dlƒíTVSœFÁ,QŽùÓ˜ŸgDÄ@lú dýSŒ—ú<@óΘdæ•8| E¼¼ËECÇ™ë>$ùgK†ž¸„ìñfi8Ýf32ð1ò»¼œñREyw ¦vQP ñZèBÄV+&äé˜D2÷ÅlæO‚`tWôÑt šW-ÁoyCQazÚùÕ¬áS€F¥¨X)…w¬3T®œ•W9לå"t)—{ÁCµÃbäÄ¡Áv¤¿¶Ð»Ù½!Ê´ºždýÁÙ*ÌsWÈüÒÐ ðmÒ‘WÄ4Ž"_pT'¬¯ŸÖP9Ú§6k‚ybîêáå2cUšD¥æeU°¸†×”D¹7Š`_ø™Å]áçèVñüÞÎp’˜c ¥‡•zå¤{аŠñ&ô…RUdÖxHm1×1Ø–™¥@•Çàqc6±"+e“ÄQYÜëÁxça`à£);¿Â9¤mE1 iÅ=Ä›$ mz"ÌyÁl9ÈšÜÅ.bì Äé`àÃ#Í‹‚X0Ɔ¾mh FŒ'‡d%°éy ÓÓdþNd³#Q à"G_Ï>Ïþ-!˘XÅÂè ”Î®ÿV0Çð¶ {ÈÌÎÍÆ{ U5o&ÙÈ€^)ô( ¹äïÈ<-¡‡‰²‹&Ð)hõ¤Jæ Íú†dýnÉVOVð^ ”ã\´D?Q+êsz“ýx9˽·m0ÌHû[æ7p†T²<ï!Úl%ÊX>¯é¹`áò¶™³*{±!Â]²yCuÝä`j;"•+5BiÔ‹•­ÎËV~ ¨DfL=+ó÷ò}ñ¾òÛBEC|AχøÜøs~#Lþ]þ7Â1±«ºònqo,+•€&àÇ]ô8Óøõ>I¨æŒ´]K«ªèaÁj$(׿éªÁM$~¶Ž8|`²8Ò(ü³*“Ú5’‰@Y\ˆ€<6n§·ŠE\M“~¡u)ªqàQèjl˜1‡ç—ÜÞg²R‹X|5!&"&¬€†ÔS’xÞÌg@—œ…°<ìöJ ÁjY6(Œ;Å ²ïÛè%˜¾œ™jV§½¹2PûFfW×¢„ëD9G`j¶r³²‚[­]^{ИVà­#hìS·ÝÀ™8E4…ˆr-d’wLóeeF,›»‚ Sø®I%+ u¸x Q Û&à5ÙWqñÇ8äÕ~så6-;ÔšÂȞК]¼A±ÆÖçN¦s2ÝÃkIIµÏ÷Ä?C žñ°³§‡ÙyKœéÜ$bF‘]¨ÎæŽâM6(PŒ”öµ)qð=@Ú¬9¢ÏÍÁÏþ`h´‹»ZŒÓå¯àš¸ÈwÇçEg.I›cÒ ·æ¤5ÀéÁnòe5+ç%ÆH}ØÆ[Ö­>5NÉh!ý]N…®XXºØ†dƒU¿^¥à`)XÊÊHƒì†”xpÚ–ù‹·¤×«Ô&äæø©Ésv0j ˆQ›,+Š i‹X¢(×ÞžÝL$úfÐr= ‹yóïáÒ.| „4“´Õ¨ÒÞ›¼ö±3ű¶Ê†+ó6¿¢#¦Í&\ªË’E1[¶â”ô.æè ! %‚çg´×TüêU`Ëê8Š0ÕbŽ$“áW¦œQ@Û7"@”ÞÐc· øVSŠ~¦B ìÔ(dÖåOŽqCœ˜ËÖûXâEöÍéV%4Å.ýD|@×Åm>›”¾ùO⃠Ø9õ!b)&dÞ›¸F#‡÷\HÆ |ñ‘I|OâÙ~Å$lœ0ÇBˆ‰39¯Ûr!"ˆÞd\=öpSg‡³Ëf¼œÃ€†ŸdŠG ±ã 'À 8Ê †v/g–]²ºH§ÄJ|’ò >'O³“·…î@ G¹…g |v>bq÷÷£üBö ÀsDÒêà˜— ?0F=Qr<­“Ã(%¹†œ&]wâÅ>4&s1ÓaŒo«zVß@˜m™s3À(r ÙgÓ匤ùŒñ†6|£Ô¡ÏÃ"%ìÉA?ÎÏ"ÆÑÁ¹OcNȬeŸ[öôqöšÀ0¿¦×Ÿ|÷ÝKДk‰ñ¤bG¬¡ˆ¡ªºôÙ“˜€Ac=¶‡6d<1WHy¥Ä‚ïs›Õ˜%[„ü×%Éþ4 Ì2›/K]&¬a$¯ÂÀ C%µµ—Œ0Ê’7ˆGFb)¯]ŸDEj`|j!H1¿íY‚<ÊÖÀË+ÀFýK‰ðêϤòžiMK`½SgÚ>‹Èl‚wá}lø°..é;⇇¡×RJðG oÓ(ܤX á ê,`žº¡Øô…Ö^I˜ˆ§$ï(Qt˜¿§#Ю٫oRs눺1GdòÄ{ç0aì"4}WÏ–s‘jÄiê†ß%áHS¢såvò› 4â¶¥­4€ˆ7ßµQ”:ˆ|]¹3ª¨f,d%+‹(NõÚø»šžì® b ‰z¿B\_^1dzªØdÛt|¥§ÿÙŽ‚OsœKaD’àC±öbŸAW°w^Æ2õ””§oèp¶ÈÒÔQ²Áaì% 0#$`KœÀ±UF½9&áΡ˜çmôˆõ&ë«4‚OU+1ŸH¤ûùzÎtV Èì!iúônW-ëÀšæÅƒìÿtôÄݰ¾7_äUi~%á›]}åÑVòl²lÄf£Ë€"ÁˆsÕsÉ`œemH$¨HB^íÿÔ=çÂÔØï•hƒŒ¹¾h{$‡Iu½ ÿjUä¸n£GDrFþ'S&"­I±ÈDJ¦8–Ä©á·BêÂ;ˆa¨‘iR\E·j1¤4’É ¹r^™~Èo+>>º"Õ£¶:›ñA6Âÿýø0°)kî*Åçµd¨×ˆH¯­+M8‘¸Í [*Ži¨>¼_^-f¬BJrHkUóà!ì‡Ê[†…D ;ªZM Á)>GÜ5µ.ã£ÓŒŽèÀÖñQ3$ïÔkµq±—ÏÊš³zQ¶æTGq=ç-kfbŽ"¤Ž ’a £˜_9Naß¼|‘¡žx¼);‘'®MA|yô¢-„­Ö“³œ‘‚_"3ì§g,!¨´×ÏÙ—óØÕR ¼ÔÑ©?xàjQIä"Ç"ŸºÌ”Éx”é²ï `ƒ*¯'©a” ü¼ëYÀ˜$¥—ϼµ0lÈ”•¶k¸;ØŠJBx’ù'ä]†ì¢´ßÏðæw{ðæ¬öy fÊìÚø4‘+ò|GòW r˜H¥X]œ¨¼ÃÈþÒy…"Úe›ó¨’j …®”áVè/3ƒ5#Ýä-1˜öÁ×JX­97EI#ÞèÓ˜‚jYlx‘âÖ-0Y¢ÍmbM¶J5ÅVªY²_pQÍAWà_Iÿò)a+/+ñH °à¤݆HxÄŠ¡‰/^¾.„ÛNY`è1i´Úr$Õ¨ûFmíˆMLÔ” ¥ ¡Qä|Œ;AŠØíQjöþ’Í$âH‚ïÄ=á^û@ö$¦¬±Â( ÎxØa¡;¼”HBsî`»œ‹‘Á˜¡ã3\‡ZQÞ5 Ò°Ì ¢­8a™6±\µ‡I–æs’¸”ÝÖô=ÙÝ ^µAZ䨇¼Y8Ï&ZÚ@\œ ž‹/ºâ4ô ² ‘6#Þƒ–[VJw¼ÉÜk¥¦ý%›¸I½¼î¦ËçKµ!ê@GSÏîÎÓü®æ´EÖ<ò«¶‰3¨¬º!ˆ'ÎÕŠR¬`ö ²PI^µëV ÖkÉ¢#ôòiD„¤ãYÞ¶QÉÇ ç–°¸ñÒ×6ô&ÏdL 9—W„„›Þ£µ0¶J9¢â œø,Ù  …s™‰dÙñÂaäÕÈ`ï­Ü+ƒQ9ˆ z„úd mZ@/²Ÿ@–»¬xhÖðšOÓ9ÁÚpŒšâ6+4Ñ d{áLø‘äíˆGÆA¥‚ g]ÕŽô@z»ãb0 AÙ[Å´ÕÃI-ºÍ;8'îùt³Ø™êït@‘gïö}ÚR¼þÈŽÚ¶õõ ½Üõ†0*‹‡3“º#§£[ôˆz¹€ Yr#4öÃ4ÈÆÃ¡‰¶¢§äñj ¨äÖÀã±¹ü­A!(¼”;³ Tݟ칿-ªµ U1›úD gNÀË I†biÅì>„Ž…ûØD´–»²žq!on9“”=®á¬ÇÈnœª0Yuù¸©Û6HS4 á [ÏÙ´avÈÅqÏÄ#•Iü²÷‰ˆ.Kt`m>rÜp@ã#Y/gx{°ë'Ωíʳ›åHLÚjQ†~ Hš1N,+„E8ð¥&?¨¥ÅÐúö0; q™«Âª;Ñ_C€å`M§ÞÇ5_zͽiegÀYÍÇ‘Š )ä|ꢟ¦0±Bn‡nó"dæ\#Pk²´ ‰‰Y¸ƒÕHâ’3"En¡Ü˜Ôf)¦‰“ÕcGV’‹ákÁ%à$¾¾µš'dµ±¤Ë7®Ý‰çÛ²ÔãZ·ÕrϦ3 dU>Ä“œ1t˜7ÑØ®ÚëTr•DÊÜZz’çDÙ¶7ï`kBŒ8«6¥Æ`¹ö RbŸóZÓe6Ocñì¼Ó%°9vø ¨/`s–ØÛ‚% <óš…¼]Õ÷º zFœö¬ûãÞ6ØËô>ÜÁv±¸-ËŸP¦8ÐØ±úEØbJcRiÞ‡­Õû{7æ}„Ù4o«Ã1r%Š¥¾YC«ÇîǤ©Œ%Á!…Vºaþ¹J@ç ŒÂš`QÜ]@¨ÅÆÞQ¤iJüU~¼Ö„$¶&-ýñ-ļ¸L¦4%Âû¤,Ù5ý$‡6{ò‚™é“—ý5¼‚ŽiAˆ _nÊfKsçÅW(á‰ÜÏrói/pùŽ <»™!ÿ°1ßâZ´•ш«Ådôžƒæ‘‹±]vaõã}¿Ïy#Lñ¶W"ƒé$oÊÊ·guù¡âvK kŽà÷šV¨¯.‚Ð=—íµ‘÷лad!¹o¿¶2Ù§ÃÑÃÆ“Kí†$¢o> ,¦Êçòƒ„÷¹×E|ÞF·‡‰Š}¤Î˜¶ÙzYu 3Øžä1ªùÁa„¹âžU Âãb\ª&ÈðiüÓÓðžWIZ]ØIÔÀÄŽL=³üUšãîÜ&ÛÍö¬Ê¶wŒšy³/T(½¶ØûÀ}æ*¶y9‘ÖÞSF§ëj?§’SR†6Žë‹IAª9ƒ]ÝÅøe#|u€p¹^[?Û„e6ܤ߯í¨kÞùTPVo°w¥Dø,Fä3oƒƒÝ„kš8áÜ%5zLº—’j/VO® bSZR$ ³m9o¹‹¦pæÙ††­rV àª3è&kÝèüúœ0‹dÍB`ý…e)mIr¢cÕ/’ÿ›K@ÊtçQP>®§z祑y¼±iÕ°Û8‡½]áÝiÂζõÇ> ^®¨¹k‹~À6àý:i íÀ'áù¶¸˜iÀ)#>u*¬!nÚCBB_gÓQÑ ‘Å1c”[ v$в×ñÖ²"ú©û50…JSÖ50Jn£„'Ó¹f>"ÜØky¯œø€¢q\C·«~¼Þ?²RVâˆó>¸ÍWŒ„^P½“Ó‚n^„aKʴǤõ4@nªÕ•NhÑEu#bäûÙœï<ŠD1Õ8_.­²êtEÒEËJ"г˜•p:¸oÀØ/…*ÄÃÇVNß-n¶õD\o£¤0VÞ‘ÿ(-ÙüÞ¨"vª 7Î÷Œ”¸käªî+€ûˆØ¿ ð¾óJ¨”Õ3Ì52VfõȤªªš¸©4ü @L {B-0°6—6ƒ[¥ƒ;|J–7“7hª1Ky6€ƒ{Í‹X‡a¿2zJÁðËÇÙ„µši§'ÁõEß‘m[3Ô“"¤ßD1ÚÓÚ–ì ÞIY´Ñ^Üoïe '^Šž0-d¶”ó"ôóóÂMy ½c¬žVôÓý`ǹþrCÑÁx©Æ0ª‡ï³¾N3>h9 o8ˢĹø¾]£±Ô‘ãÝz*1OdpþjGhSl—yPXú†Ÿ€7ŠÝ¬Só¡Éÿ0Å9?÷DS/ºø¨# DeoÙßIb»´öBªâ>mÐjY ÎKÙ${Ú `öÝ!{ÿ\ºKC•Q ¾•ж^¹„åNÆÁé]–"'JN$]ÅJ “«ü’Œ¤PýxT‰oæ’Êí»¥¬§²7ŸUfBäâ¢5Y¥ÁoÀ]´,]š71“÷ØanƒÜC)*à†zÁÑÒ¤õPœ€ N-™¦o’ ’sÞ+Ã,´[,Gi¸Ѿu´”j½ ‡v’ƒ3Î÷Ø‘ÒCòZé@X¯P`°F÷ÒnHÓ}¡)™äÓGT™~]ßF£}1!š%¾ðKÜœÊsž-µViT%‘®Æ§ÚHÁ]·/½11ÐBÜ×Ä㬧"^xÎv)¡Ö¿À¦´ ÝIg¬…²'©Ë,j×q,„9‹×!ãcGU¶/Œ§ÿÙ?Žù˜“Ì#¥šÒð*nÉ%*XÒÖr­:%ë–LF{†3ÔDñXc^47‚9q¿/æoÛÈÕibä1[ÖV•­ïNÓÜ%HÔI“KïL8:â˜}H¦ ’sýÈÛ‰~nõk‘`ûj—;2N¸ŠRÜ0ä$+‚˜ôD ôÕcO\P·|óL¯q‘ú<[b]Z¥Ø¯«Ø¨‹·àÑuËš Î¸þ÷œÔßõkÉŸõÅtŠ”«5µYímpž &Tk‘7-3ô±Ï^I>D>×½oS¤“Öjºxþ@±è®ÛÔ«|¦‘²:J¡“ê­°–þ:¶õVZÅ;F· P8ÒÌ_]’,Ì¥)ƒ”óçŒTþƒ>()]ÂU‚ðÙñ.RÔõáÀ°'! 2©DlE²f!³‘Û±ç3í<çì&õzÅMá0OH|Òª’'O³skki-ç*ñ:ÖÍŽ%ÞôTFД÷èrMÀ3¾'¤£ÆtI·˜óÐ“ËØDð8¥·ez†BKQÐe5Æ«öí÷| Iòdh†ƒ]£TàoÉŸ žbuãˆâ©ÑÀƒ´4“þ¦ùX•:RQõí¯“hžÇaÁèÄYá&e®‚ºëKÂÝzÊô´ì.”i ‹õ2pðʨBh‘iÙêÖ%qà‰€õ%£ýM%½æŠv±ã•7š¹ ô ëÙNhø+̽ª}F!w<Ÿf ‰Ë®åG|Âkâ*àPCOz¥¼3¬:RÂrökøöèzØÌ&èªå¹ÎôÌILîˆõ§H¸¡\8iiÁyY8K%tÉvg*m_¤+Å*‰Ì®߆âȲêOdz áf±&®Øû´“nR˜Dµ2÷ˆ£G õNIø½ìÄÿ¦õeH¨Õ|ˆ)U«ÞS°uËÓ=ßv®²‘×taíRlïÈ|wE•K!'_Ö°T¿¿<÷žÜ—¶¶;|Î;¾‘{z‚œÜ Ú…o©=×%W}Ën×öe¨³ó¸›²œzê+ڨЪ¹*p&:xµ¶T©RÛšœ+ Ö$"M#æ€ó½Ò¹M0ò&­.zò›%I™å¶çÎr¢Iz%^Hs–žät’2¸\çªpŽF©¯V ¶e¯´øÑY'‰ªÞˆáQ W¨Ø(œ¢ º.*bHÞ·ÚCßÂ=òÂøÎe{Ïü ƒ˜#¹ßÁ‘ÖÓ|lk=íf±Ùä-¢P €Ž‡í#‹5.ôž¤øæ<™tw…`0@µ2í‚¥,»5÷¶è<è_æs‘…Iáà¦ÚJ—¾)ÒǬqªG‰rN3’­¦5(êt€Ì×ܩߚ¬ Ã¬,¡T7@°]æ’%j3m³*’6©®³4©Žä˜´ð¶¨@l ³í† Ò¥ÙZô„Zƒ5Ó™Ë×9~¸‰±Zg­¯›èxÍ·²l_¿6Î4°Wëö[JkÖtµKøâ Y~Ùö\Ø‚ÊêòAs®P½’N!Š;Â9Rí[¨ÂzÔ Mµƒþ#MÉ"¥nV\»©EžÄé¤Ùí.Ê’ÌðïøÒöÍÑ­ÛÐÔ+ô[Í :½ô$¯½„¤4u»r˜]}á  RO+¯Á †` è郀QB¥ÆÆš®¡Aji(wd?™]À! )',ùjÎyNu(è IW mMcþUm¸’Ä|e+½}ñ|ý±E7XKsϪƒãU8‰ùé֨ï.KŠÑ§Ïð¹;é:WH+ñ–æ“h5ygOòçJní;ñî%iõ?ï‹ð@‚ÖÁ%Ž’âYM6MíIÔß!ª‡•i·Æ9:»€5‚µì#˜HOEÐÀÖœ/,MarŸ{ëy¼îOÿ”½Ë:-Ü™fùE·¥µ–Ü~¾Rƒ›É5KãSs:JÕa È<ðÝØLw ÓÁ»i’¾âš˜B¼Í«ÈH]Ž3'½Û=ŽtÚFµ±Õ“§‡hnué¯1¢ó>Èí.ßÌ5©ç¦¿õúý‰‹b¢}ʲ=³¹Ý’;ÃH8#ÒÃb÷3ÍbCâäû´|›bSÈmeýí·˜×û†¶¿{ÔO¹¶ÁM*âÛZÛXiY[Η³.·{b$So­3Wâ°)V)Oo=¼¦âeÍ/»t¸ÃŒ›Ÿô]EÆZvà…˜¸U×ÉÝUÐuÉ¢G ³ãXò%˜^ã‰h–Þ"3D¾ë¥bj•Š^W'¾@6¾æGGò]$Pò&8¦ ˆX²3-G--‹»=yvˆŒî eâ^Š#XõC×Sü§½BÙo‘R}VŽ„kñ “FÉÍšŸºñZ—Ÿi9™èh.ôå½^ãæ ½ ´6fs 2‡âã$ý¤'êøº5&ë,¯Ör­×Õýß±»ó·gœ4.IÛ‹šù{«Ë›X’D­Vá¢ùãR]%øòü0»(è„iÝŠøî¥ž{`Úv¡d¶j²FGÓ ¶aŒÆlÛÛn,d:C8 §¹Á!Á8ûC†¶µëC‡¤EÙ”¾šW³½×‹¬R’ñÂ%3¾CG®3á)ü¥F¢ÜQœÉГ`#QYy6-ië8{¢Z¢± Ïür>¹\s@Mô)ÄòBZÑÕƒ•ëÁjGݺ(‚^O¯#÷ÀTÊËLjöÝE>ž-Wî¨Ám U¶BçW(×AôW`˜¥ Þ¸€7ë‰q^g8AÛM!jªÞv écãÛÚ¢6ûŸüúܦõExm¢=^áÚÆ|YÉ ‹ô Ì æ re•»+ÒûÌ@} ¡‰û–Ï¡w[u¦¤i_iP5€)Nùˆ|ô&î$<º½a6,FNø@MÝò›ToÔggKÖMÈÎuqÞ”?TÕÉ‘¢ÐS—Pµ¬ Ðõ† Ö „‹{s‚·¥ ¸‚ؤ½$H)ÌîÅ¡O TúY“ÅŽ^ ³Ñevz–ý|tqqtzõ1{sv/²ó‹³Ÿ.ŽÞ ²«3þ}øËÕðô*;^¼]] _g?~tGçç'£ã£O†ÙÉÑϸ9é—ãáùUöóÛáiv†á]³Ë«#¼0:Í~¾]Nâq¡õÅè§·WîíÙÉëáßPõˆfç³ó£‹«Ñðëø0z=Œ×”í]Ò²w²ŸGWoÏÞ_ùÅ»³74ÈÇ쯣Ó׃l8↿œ_ //i4öè­xH_ŽNOÞ¿¦µ ²i„Ó³«ìdD;£Ç®Î³é³6:Cã¿^¿¥_~Œ^¸VëÍèꔦ`ØÉÊߟ]¸ó÷çg—ÃÃL@HƒÀ/F—Íh Ø{ä"èÒïŽN‡˜+Ú³£cÂv³gï!"hß'¯ PÃìõðÍðøjôa8À“4ÍåûwC…÷å êŽNN²Óá1­÷èâcv9¼ø0:f8\ ÏF€ÒñÙÅF9;4zy(Éå>àqbYËÂ1NAÃÀ÷§'€ÄÅðßÞÓ^%YŠ%ÿè§‹!: ÷óˆ†Óóˆ‘ b øú" ÆGB±³ìÝÙëÑ‹"ÎñÙé‡áÇKC…àPöèÇ3æGZȈ×C+”pn¯Þý4¼Œ0s:½d{]žGø¾'|$8P^Ò^q´ô$;¢3Æ@N9G÷žxjˆCsãoñb÷ÂÜëH™œ]Ý룫£ŒWLÿþ8ÄÓÃSÓØÑññû ¢7<7h5—ï‰G§rØ/“øèâµ3"c¼}s4:yÑG<Ì|F ÄŒ€ÑIÈ—û‡ÃÏFohªã·zlYBʳ·t?é±£×FLŽ:-r¤0¡Ýñ GÁ¾oån\‰á1ðr­H%^“„éùŠ<8K9¤ßû&’inôÅgV£Ù¯HgaÍoV.Üq¹”¤;¨„Ž8@—há"ö¿(¨:R~¯6;Ú1gµT‚¢°å ß‘Ð:ø´®Ûz†úynœ,êtôò®œEkßà3‰t°HšÔ…‚¡ÜY" kég_ZLÒ¾ßÖuÇð’ÏyË „áóVîu:bI:ו¥–„È;%eUÐF$½×‡mûp+±¥3è•Ó!Ñ}ÜpcK’»ÖøË²íÕ–42ÒvÒÉ{·ìQ÷i +;—^-ê_· רÜ'‘^Äk7«úø’ÙÆvIçˆ T«30¨¯V:å5Ë ±ºÍ§ØVìßžÛäQIµ'Eiör_K›ÜˆéXÿRofÔÕ0mJÌ#ñz=(ëÞÖýÍŸ¯ÓìÀXV·H¶¨Ù¨ÿ‚uÏ™.}oW¾Êº©"ןN~ßz¼Eûßm¹œH‡¾nÊbŠJƒüð/Ú•È´¬½ãýìÏèN÷š‡¨­|ï/2ï•Þ×jiÉqïïO¹ìÌÔƒÔ mŽ(>¨%çmb_hÁÏv~`fÌšk!äQHùÑ^Znº¿nÙn@ا¿»êá+Òak\4{:NéJ {ÔÔ5HSÙ^ùºZtÐà±Ìù˜•”]õ5/î6Å+ Š×e!– FxÈ·†˜ÉÖ5 ñˆ¯}fsšY·}`í+õ" °s™EöçÛ®[|ÿèÑýýýáMµ<¬››G–îñè/´ #¤î¡è&nm‚&"Â;Ùÿ-WsÏ{øùšºB×(Ü’/¹B{‹å"¶C5Ëz;[Æå첕ðh:§4Ê׸ò¦¸a;îÛ(ÍNㆽh\£%«Öyÿò»)q ¥53ÃôèÇ˳“÷WÓ±%óŠÏT3ëV„ ŸøÆ÷ûÝÃ0\Ÿžƒè`^^Ì08&ò愚}Q´÷$¼Š§ïÆ !àót»ZÀÝÈáÂÌßBhëã5ø·ÿì¶ú¸Ò9m»Åß™egSVD|`;ðL›ÚÍùÐÉÂìÚW*Ýz? Ýõ^Ð’} Ù)L„×õ—Ÿ7©Kæ\S¤Zò¬Ñu½BFƒú«Ã-v£_ÑìsNì[brÝG½ÐI:€ºo'„ñ}[wtXñw~¼ñ1õ”päfçèZIÑÐðµª=qãæm"R÷›D*žÃ8wùH¦[Ü,Œ˜D|>Ò9l/Ú¨V"âË9ÄšqÌB¯õZi±´ýåºNÐ(CØ3gÉJàÈ–:î0£†Š:uCê9:¸ù³„Žî-á^Ó pu·å­ 'Hk¶y÷%Tä“ Ñ´ÔáŠds9Rh6Åâ¶$Uº^Ü®Ý̳߮›Åìð¶›Ïèt¾ù¯ø™”Í£üÑ蔌¸““?hŽÇôyùü9þ}òí‹Çñ¿ôyöòÙ³§ßùî»çü÷Å@ïþ¡ÿ~7@àú1ÿ÷ ÿ÷)ÿ÷9ÿ÷ÅÀÑ_òÏßòÿÄÿýîÍsTEo:Ö>¥|£`ÜLÚˆƒÞ¶\o¾€zิ¿ *¹0&4cÑ fr!]¨bT%Å"ŽfXÈuÄܬ"\†À6 ºájμ= éàl¦HÍì¶jÚ¬ÜÇ‘ûaíÃ0ù6 j-Ù»-f±à?|DìyZÞ,›âk\¯Tï’M pþ)DxÊÙÄnáæ§,O/yÐHŸ·xþh!…¼bx$‚+—ãW¬Šb‰Ÿ.†G¯ß w0r‘yôŽOʰzŸ0ï%T&ýÕ_l'¡ÆOÊÆtÔ87;Ü)ëoOÉôZë6 ¢œ]†ÝÍh95bp?›^…͉vâ¼Ñµh¨3Í€“0i hɉ T¾¬˜”Åg)„àò{Ñ[¥È$ú®ÈÞÑIñv¸Á,ß¶Ô~ŸíùûŽ÷7= „‚M|ò‡º«x!×£ZM5›ú7KxpÆÈþ$ÿ.Ÿ-õžÏ;ÚJläŠÚD†/äÞtn4±Œ<Ÿ6#.´œtž×QaJ°‡„€óÉ–¾ x²­/M(êÆ?vðn$!Giÿ/#ÄÉaŸowõ‚Ò¨KÝ.dÇCÍySj14é'2&ë91˜~‡ÒOtW’¼U¾¬ü?K¹"ËŸdyÌ-8×…“,ø”—±#Áñ©Ù³úf7^º¿ÝWM£=Õ¨ÐHJú.Òf½¸ø%:e)4ð±B—êÒ‰1ïžöX­¬ÄV2¦ƒ(v¥Ã&W.i›…OüÕÞÿ!y˜õê’¯>ütp¼« 7-µ­ y>cþ1É~Y ¡ïrÁÄ!;&¶Ç|«nàsÄâe׸vš#TÅš+wÅ 1fI„9µ¥¶Ú†~./SðCá#V7–ºÉeµl‘ÉËIVÚœ ÆC¯$vÍÊqgÄZ~Lm’¨BÓñ}]y&8Í´•ñK£¨µv€ž†`N×»C«”{¶µ¤*ÑQ»ë¤»Š-Ü•[/Z ¹Irý°Ïtp);Ç™±ì>ëaDè bÇ)U¯Õnçµr\¤¬í}‚l¢ Œ‘.ð¥÷ \‡9Ù¢Hí‹þTV»|•¹Ý±"dåbKga3Ú‘,‹gvãnゥJ¾‹Ò/[]¦RÂ]ÐÏ%ðbWppb¡AJ4¡ßCäà ¨„í=OižÉ®x`7ˆP°ýÔÕB|A‰¬ßU¿âh4„Ý|Ú(ƒ4û…Þo[l÷ú®·¢M¢û6£×2û$›®ê¤¡º–\A Þ°ãGj¨4’oBWZu0yhÝÝB|Åî h(»[¨Ð.ÚϽ¨îʦ®æ‰=*ªŒñ=äÆË‘Î³ÈÆMM3®ÎãúŒùŒmѱã<˜»¾„+1½C£%![x_ûPY6½F¨²xÏÇÇ?Œ¿û.;~srôÓå7ÙÉèGúw¶¨Ûò ?ÿ/§p¼fÓ•óÁóý÷ƒM¡E9w<‰ÐÄ;$hÓÔÙQC&®Ì…úµ 6aÅLJ¹rtÌñ>KÎDj9¾› ‚šÛß 3_ï²=µÞ œG‹õ‚í‚ :´d ´cQƒ7ˆIEºµ L’‚ Ð_I¸_BÎüºæ¿¥mÁrž,ü1-Úc>âÛB%½ÅyÂâÖÄd©!OöT~:<ܵ‹Åè P”–xì|8?ºz»#Þ;¡„Ÿ¥<uu*ª$r:G³EÇæ•¢†99 NÒe…ËnâÚ¤ ‡whðE AùÚ0ErÚÕé‹pÒVÑ<É%~­´‰![?«²wùøì2ûÍ$“K2”ɤQDžT)rÉñ[+"n+m$%ã°müAìLón‰;ÄÒa(泯o€¯HB6÷¶Á>` »žÓ†ZñA‘æVB›¾eëó-+hLsˆ«ƒIšD¶ðž›ñ8ã²òÙŸ^ê_þôò×—Ïõ—Åb~zù|'û_ëùXÇ¿üBCýë¿þ¿êü\W5ÜÁ¸ò;†î¨-1AÈ“›eÎ¥sâ"°Û¸qR\ú&¾3ÐÎL/6 Þ ÓØZÖð0BuÉä—ú›È›å‚ÍñiV.jp™z–\AlÎ)BÈ$ÐrŠæÄ[}ùÞÏ5è+ úCÛÓ:½«_ß}z´l›Gœ øˆ r×¢]ám’Y?¥ßÓ“E7·‰]øÂ*µ;Ìòì|ǵh4vËÈÅታ†y¬ ê§ƒâ‡ó‹á›Ñ/¬_!˯áv”Êù,Eö!s#ñ¶Dgñ†…ª7;>Þbü>ù>ºöXý†¦Ð;\ôÐÛ xEoK@­hûƒ„ó±c\7›·F·€é4Ü ¢áòà/ðüéнŽ]¡}IìNh;¤JYŒÜìS™F •¯"ðu~ê,6½/¥Y¾‚›s©VÎx•(¶ÄÚЫ®ùáõèbWÝ»|6Ád‹ô®èÆ0h lü Y1\S 5gdV¶¾ó¤-åû¶²¶~.œ2 .‚k.Ö‹*Ñr‰y—UF·…çÅ¥ïW«Yi–_÷éüoèÿ¡nµcZÄÝá8 ؾ«µdšâBQzvëPÓ*å¦ °¼¨'«E&ƒã‘ó,ÑÒÆº½sæ‰L˜P†9A,ßÔÚY(<"rtµù\úmõbq–q\ši¡6Ÿ`Êù]$Vµ·gÛÆê5҆˛jnqb9=˜(Þ‘çvóÖ4¾ên¥…¦Dg)4|Æ7ëUµÇ&õ.új- ©ÐŸ‘ ¦~ÑCÁ@Ü7m1GÈ1ŸK{›7EÄúå(ØÎ_DwC$SKº¤©'d&6÷̳«fùò¹ª9ýý `”òG”pdŒèéÏ÷hŒxxû—Ýì¶ÈùnI4¸Š­ìªžtŸwãÒ~Ü$+½Oò†‹¹ì ²¢³Vìñ‘pÏ-²¼¶öA>ôb&ËÞ1À]Ö„‰pXKâ ÜSâ;YޝwI1倱Ü÷‘}‚;×ûz×CpÂWLV­Ý-,w’³l}åý`¬†ù^­E,¹×™ïäTš'~#ζôŽI£ñKué"¼ð¯Ü›÷×xO\yùy9ÅŒÁ)¬fŒ„®ÈH—@˧G×uÝ=’Àw¹Ñâgòe‰¿—´6Ñ÷DÅ“9wlx ¥Ñ#ÁãЉiÉMá¯êIøœ—žèÂ~B™Û ›óVÚkJýTá¯gZI˽9'Ê%ž{Ç"ANy/òq 5¹½d"îÍ$¯FÕRkW ÷+b6¿&N±v]úú䢜‹¸b‘ª)A¹¥em¾’fʶyÉ;Årü6h[ Û•¢1À«íWϽ‚’ _yZ‘o¡x¤VÓß¿Á'çd`kƒû©]VÏwõú&…l¸8/Šd¹U¯ÔyC›ãó÷ÇgïÎN?\~¼¼¾szÓ“üÆË‘»#+‹WJõŸ¿N‘ø¦üû×áÅéðäàL*•µŽ0ÉŠ;l—×»!ÅÀª‰Õƒfe¶¤ÌÏ„í¹ä½’ÙÓÚŪ>Ë©“¶“Q6š²4g)‘©íŸM’< þ•‡Žõ×Àßa1jlUú¸[@RŒÍ67* ŠºÄ¶õ ¡8q•a‚îqá«cKöŸˆÇß.éMhé}¿Ò\¿Z[y¿Ní c9­wÕ’ÛtO¢Ä ì‰xO±ªçvnë¶ÛñÏe{åaq¨s&MÛm“À”ykœßÊ´«”¹ïóp1´À‰ö{I¢tõZ$íºz³ $p’šhŽœ²ëAMÉÓ…"èÆ>ƒ»%ÎæK÷r‰ñÀ®ÂwB¸ s•X&ÇÇ»à3È9ý•³ÃÅàý¤>ÔÃ$¨0«kª~Ãî¯õQ2¿ð£âKÉÙc@}gOÝxû³0×›`¹fÌ’ŽÏNߌ~úõrtEˆº) ÁbqÞO§ÊÀK‚ÅîeP‡¿÷©3›Àªç;yÝ­'lSlý<çÀkÑËÆdõ ›ÕæâÂe+ü!ZkÜ™¨M Î^V¡´DR‡ÌwèÉI›ËqÆ|Kb/· ¬Ž© ˆ¢ÒuFd ~|¯0³ç$³BhßR-8Eeî3©“„íàZÖK²OŽ.~àuì¦~Ü-*xÐNžB÷yt3;§BFï€ùD_íªÔUU–Ÿˆôä=m­!‘‘c±÷þÙ!÷ÿ=ªP»eÅ÷êÅb$¾o«òï˨>Tú¶‚l ™ßQ93áæ|hr¤YÍZÃòÞ_G¿sesù¥˜d©¹ŒBM¯Œ{±MðCå:oo³ðSû„æGÕÒÕ]Œ'Žßî†-6—V¸ãêÙeçÕ©@ ýdiIŸnweOçÐm¸&–pFªUâpN5qIR §Áë˜?°Æ²ë¥….ÜŠ°}žx‚¥œj¯JjWÓ7Ï­uA2±YTkø­åûqÆâ[W/²2ÞjÎ3…%o,J¹´F‚ZnWIj 1 ŠÚɇ˜,jççÑÓÊ|nd®5• ¤Q=Ë›ÑÉPŸÊ}=•F|¯fø„+Zâ;I-§ma”&ý¡×¬¥9÷J)ÀKèI“À‚)&ÅÝ£j))˜>‘—2–r]4t e:¨·‘‡fe®¢p{¥Ž ñ÷eYÖ‰Ë?þ]‡y]ëežºÏâWÝ]Ý.’Ëýïºà$²Ù9K½\È9÷[ibZp|QçÄ»Þã‹/šÆr}ýälÐH8ûš[ÁÜWû²‘¶[ÀYÞ91i™fHôÒ­‚)Moil´¡Ù^búûwƒMÖ£¶dXÚÇÒoÆÝ7$'ÐôRé·ž!òý÷!Ï8Nò³„Žpënz äüA‡¼Ò›Pè°9T*˯êÑí€Õ®¯ ZðLZÎ_l½\AÃ/ü®ïxËe ¦\\’°¹ñb«žØŠäã6®Àà&/¶=É ˆFI2ziÿìÊꯟ¯Ÿ¯Ÿ¯Ÿ¯Ÿ¯Ÿ¯Ÿ¯Ÿ¯Ÿ¯Ÿ¯Ÿ¯Ÿ¯Ÿ¯Ÿ¯Ÿ¯Ÿ¯Ÿ¯Ÿ¯Ÿ¯Ÿ¯Ÿ¯ŸÞçÿ©§9Èðgnunet-0.9.3/src/fs/fs_directory.c0000644000175000017500000004336611760502551014021 00000000000000/* This file is part of GNUnet. (C) 2003, 2004, 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs_directory.c * @brief Helper functions for building directories. * @author Christian Grothoff * * TODO: * - modify directory builder API to support incremental * generation of directories (to allow directories that * would not fit into memory to be created) * - modify directory processor API to support incremental * iteration over FULL directories (without missing entries) * to allow access to directories that do not fit entirely * into memory */ #include "platform.h" #include "gnunet_fs_service.h" #include "fs_api.h" /** * String that is used to indicate that a file * is a GNUnet directory. */ #define GNUNET_DIRECTORY_MAGIC "\211GND\r\n\032\n" /** * Does the meta-data claim that this is a directory? * Checks if the mime-type is that of a GNUnet directory. * * @return GNUNET_YES if it is, GNUNET_NO if it is not, GNUNET_SYSERR if * we have no mime-type information (treat as 'GNUNET_NO') */ int GNUNET_FS_meta_data_test_for_directory (const struct GNUNET_CONTAINER_MetaData *md) { char *mime; int ret; if (NULL == md) return GNUNET_SYSERR; mime = GNUNET_CONTAINER_meta_data_get_by_type (md, EXTRACTOR_METATYPE_MIMETYPE); if (mime == NULL) return GNUNET_SYSERR; ret = (0 == strcmp (mime, GNUNET_FS_DIRECTORY_MIME)) ? GNUNET_YES : GNUNET_NO; GNUNET_free (mime); return ret; } /** * Set the MIMETYPE information for the given * metadata to "application/gnunet-directory". * * @param md metadata to add mimetype to */ void GNUNET_FS_meta_data_make_directory (struct GNUNET_CONTAINER_MetaData *md) { char *mime; mime = GNUNET_CONTAINER_meta_data_get_by_type (md, EXTRACTOR_METATYPE_MIMETYPE); if (mime != NULL) { GNUNET_break (0 == strcmp (mime, GNUNET_FS_DIRECTORY_MIME)); GNUNET_free (mime); return; } GNUNET_CONTAINER_meta_data_insert (md, "", EXTRACTOR_METATYPE_MIMETYPE, EXTRACTOR_METAFORMAT_UTF8, "text/plain", GNUNET_FS_DIRECTORY_MIME, strlen (GNUNET_FS_DIRECTORY_MIME) + 1); } /** * Closure for 'find_full_data'. */ struct GetFullDataClosure { /** * Extracted binary meta data. */ void *data; /** * Number of bytes stored in data. */ size_t size; }; /** * Type of a function that libextractor calls for each * meta data item found. * * @param cls closure (user-defined) * @param plugin_name name of the plugin that produced this value; * special values can be used (i.e. '<zlib>' for zlib being * used in the main libextractor library and yielding * meta data). * @param type libextractor-type describing the meta data * @param format basic format information about data * @param data_mime_type mime-type of data (not of the original file); * can be NULL (if mime-type is not known) * @param data actual meta-data found * @param data_len number of bytes in data * @return 0 to continue extracting, 1 to abort */ static int find_full_data (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat format, const char *data_mime_type, const char *data, size_t data_len) { struct GetFullDataClosure *gfdc = cls; if (type == EXTRACTOR_METATYPE_GNUNET_FULL_DATA) { gfdc->size = data_len; if (data_len > 0) { gfdc->data = GNUNET_malloc (data_len); memcpy (gfdc->data, data, data_len); } return 1; } return 0; } /** * Iterate over all entries in a directory. Note that directories * are structured such that it is possible to iterate over the * individual blocks as well as over the entire directory. Thus * a client can call this function on the buffer in the * GNUNET_FS_ProgressCallback. Also, directories can optionally * include the contents of (small) files embedded in the directory * itself; for those files, the processor may be given the * contents of the file directly by this function. *

    * * Note that this function maybe called on parts of directories. Thus * parser errors should not be reported _at all_ (with GNUNET_break). * Still, if some entries can be recovered despite these parsing * errors, the function should try to do this. * * @param size number of bytes in data * @param data pointer to the beginning of the directory * @param offset offset of data in the directory * @param dep function to call on each entry * @param dep_cls closure for dep * @return GNUNET_OK if this could be a block in a directory, * GNUNET_NO if this could be part of a directory (but not 100% OK) * GNUNET_SYSERR if 'data' does not represent a directory */ int GNUNET_FS_directory_list_contents (size_t size, const void *data, uint64_t offset, GNUNET_FS_DirectoryEntryProcessor dep, void *dep_cls) { struct GetFullDataClosure full_data; const char *cdata = data; char *emsg; uint64_t pos; uint64_t align; uint32_t mdSize; uint64_t epos; struct GNUNET_FS_Uri *uri; struct GNUNET_CONTAINER_MetaData *md; char *filename; if ((offset == 0) && ((size < 8 + sizeof (uint32_t)) || (0 != memcmp (cdata, GNUNET_FS_DIRECTORY_MAGIC, 8)))) return GNUNET_SYSERR; pos = offset; if (offset == 0) { memcpy (&mdSize, &cdata[8], sizeof (uint32_t)); mdSize = ntohl (mdSize); if (mdSize > size - 8 - sizeof (uint32_t)) { /* invalid size */ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("MAGIC mismatch. This is not a GNUnet directory.\n")); return GNUNET_SYSERR; } md = GNUNET_CONTAINER_meta_data_deserialize (&cdata[8 + sizeof (uint32_t)], mdSize); if (md == NULL) { GNUNET_break (0); return GNUNET_SYSERR; /* malformed ! */ } dep (dep_cls, NULL, NULL, md, 0, NULL); GNUNET_CONTAINER_meta_data_destroy (md); pos = 8 + sizeof (uint32_t) + mdSize; } while (pos < size) { /* find end of URI */ if (cdata[pos] == '\0') { /* URI is never empty, must be end of block, * skip to next alignment */ align = ((pos / DBLOCK_SIZE) + 1) * DBLOCK_SIZE; if (align == pos) { /* if we were already aligned, still skip a block! */ align += DBLOCK_SIZE; } pos = align; if (pos >= size) { /* malformed - or partial download... */ break; } } epos = pos; while ((epos < size) && (cdata[epos] != '\0')) epos++; if (epos >= size) return GNUNET_NO; /* malformed - or partial download */ uri = GNUNET_FS_uri_parse (&cdata[pos], &emsg); pos = epos + 1; if (uri == NULL) { GNUNET_free (emsg); pos--; /* go back to '\0' to force going to next alignment */ continue; } if (GNUNET_FS_uri_test_ksk (uri)) { GNUNET_FS_uri_destroy (uri); GNUNET_break (0); return GNUNET_NO; /* illegal in directory! */ } memcpy (&mdSize, &cdata[pos], sizeof (uint32_t)); mdSize = ntohl (mdSize); pos += sizeof (uint32_t); if (pos + mdSize > size) { GNUNET_FS_uri_destroy (uri); return GNUNET_NO; /* malformed - or partial download */ } md = GNUNET_CONTAINER_meta_data_deserialize (&cdata[pos], mdSize); if (md == NULL) { GNUNET_FS_uri_destroy (uri); GNUNET_break (0); return GNUNET_NO; /* malformed ! */ } pos += mdSize; filename = GNUNET_CONTAINER_meta_data_get_by_type (md, EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME); full_data.size = 0; full_data.data = NULL; GNUNET_CONTAINER_meta_data_iterate (md, &find_full_data, &full_data); if (dep != NULL) { dep (dep_cls, filename, uri, md, full_data.size, full_data.data); } GNUNET_free_non_null (full_data.data); GNUNET_free_non_null (filename); GNUNET_CONTAINER_meta_data_destroy (md); GNUNET_FS_uri_destroy (uri); } return GNUNET_OK; } /** * Entries in the directory (builder). */ struct BuilderEntry { /** * This is a linked list. */ struct BuilderEntry *next; /** * Length of this entry. */ size_t len; }; /** * Internal state of a directory builder. */ struct GNUNET_FS_DirectoryBuilder { /** * Meta-data for the directory itself. */ struct GNUNET_CONTAINER_MetaData *meta; /** * Head of linked list of entries. */ struct BuilderEntry *head; /** * Number of entires in the directory. */ unsigned int count; }; /** * Create a directory builder. * * @param mdir metadata for the directory */ struct GNUNET_FS_DirectoryBuilder * GNUNET_FS_directory_builder_create (const struct GNUNET_CONTAINER_MetaData *mdir) { struct GNUNET_FS_DirectoryBuilder *ret; ret = GNUNET_malloc (sizeof (struct GNUNET_FS_DirectoryBuilder)); if (mdir != NULL) ret->meta = GNUNET_CONTAINER_meta_data_duplicate (mdir); else ret->meta = GNUNET_CONTAINER_meta_data_create (); GNUNET_FS_meta_data_make_directory (ret->meta); return ret; } /** * Add an entry to a directory. * * @param bld directory to extend * @param uri uri of the entry (must not be a KSK) * @param md metadata of the entry * @param data raw data of the entry, can be NULL, otherwise * data must point to exactly the number of bytes specified * by the uri which must be of type LOC or CHK */ void GNUNET_FS_directory_builder_add (struct GNUNET_FS_DirectoryBuilder *bld, const struct GNUNET_FS_Uri *uri, const struct GNUNET_CONTAINER_MetaData *md, const void *data) { struct GNUNET_FS_Uri *curi; struct BuilderEntry *e; uint64_t fsize; uint32_t big; ssize_t ret; size_t mds; size_t mdxs; char *uris; char *ser; char *sptr; size_t slen; struct GNUNET_CONTAINER_MetaData *meta; const struct GNUNET_CONTAINER_MetaData *meta_use; GNUNET_assert (!GNUNET_FS_uri_test_ksk (uri)); if (NULL != data) { GNUNET_assert (!GNUNET_FS_uri_test_sks (uri)); if (GNUNET_FS_uri_test_chk (uri)) { fsize = GNUNET_FS_uri_chk_get_file_size (uri); } else { curi = GNUNET_FS_uri_loc_get_uri (uri); GNUNET_assert (NULL != curi); fsize = GNUNET_FS_uri_chk_get_file_size (curi); GNUNET_FS_uri_destroy (curi); } } else { fsize = 0; /* not given */ } if (fsize > MAX_INLINE_SIZE) fsize = 0; /* too large */ uris = GNUNET_FS_uri_to_string (uri); slen = strlen (uris) + 1; mds = GNUNET_CONTAINER_meta_data_get_serialized_size (md); meta_use = md; meta = NULL; if (fsize > 0) { meta = GNUNET_CONTAINER_meta_data_duplicate (md); GNUNET_CONTAINER_meta_data_insert (meta, "", EXTRACTOR_METATYPE_GNUNET_FULL_DATA, EXTRACTOR_METAFORMAT_BINARY, NULL, data, fsize); mdxs = GNUNET_CONTAINER_meta_data_get_serialized_size (meta); if ((slen + sizeof (uint32_t) + mdxs - 1) / DBLOCK_SIZE == (slen + sizeof (uint32_t) + mds - 1) / DBLOCK_SIZE) { /* adding full data would not cause us to cross * additional blocks, so add it! */ meta_use = meta; mds = mdxs; } } if (mds > GNUNET_MAX_MALLOC_CHECKED / 2) mds = GNUNET_MAX_MALLOC_CHECKED / 2; e = GNUNET_malloc (sizeof (struct BuilderEntry) + slen + mds + sizeof (uint32_t)); ser = (char *) &e[1]; memcpy (ser, uris, slen); GNUNET_free (uris); sptr = &ser[slen + sizeof (uint32_t)]; ret = GNUNET_CONTAINER_meta_data_serialize (meta_use, &sptr, mds, GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); if (NULL != meta) GNUNET_CONTAINER_meta_data_destroy (meta); if (ret == -1) mds = 0; else mds = ret; big = htonl (mds); memcpy (&ser[slen], &big, sizeof (uint32_t)); e->len = slen + sizeof (uint32_t) + mds; e->next = bld->head; bld->head = e; bld->count++; } /** * Given the start and end position of a block of * data, return the end position of that data * after alignment to the DBLOCK_SIZE. */ static size_t do_align (size_t start_position, size_t end_position) { size_t align; align = (end_position / DBLOCK_SIZE) * DBLOCK_SIZE; if ((start_position < align) && (end_position > align)) return align + end_position - start_position; return end_position; } /** * Compute a permuation of the blocks to * minimize the cost of alignment. Greedy packer. * * @param start starting position for the first block * @param count size of the two arrays * @param sizes the sizes of the individual blocks * @param perm the permutation of the blocks (updated) */ static void block_align (size_t start, unsigned int count, const size_t * sizes, unsigned int *perm) { unsigned int i; unsigned int j; unsigned int tmp; unsigned int best; ssize_t badness; size_t cpos; size_t cend; ssize_t cbad; unsigned int cval; cpos = start; for (i = 0; i < count; i++) { start = cpos; badness = 0x7FFFFFFF; best = -1; for (j = i; j < count; j++) { cval = perm[j]; cend = cpos + sizes[cval]; if (cpos % DBLOCK_SIZE == 0) { /* prefer placing the largest blocks first */ cbad = -(cend % DBLOCK_SIZE); } else { if (cpos / DBLOCK_SIZE == cend / DBLOCK_SIZE) { /* Data fits into the same block! Prefer small left-overs! */ cbad = DBLOCK_SIZE - cend % DBLOCK_SIZE; } else { /* Would have to waste space to re-align, add big factor, this * case is a real loss (proportional to space wasted)! */ cbad = DBLOCK_SIZE * (DBLOCK_SIZE - cpos % DBLOCK_SIZE); } } if (cbad < badness) { best = j; badness = cbad; } } GNUNET_assert (best != -1); tmp = perm[i]; perm[i] = perm[best]; perm[best] = tmp; cpos += sizes[perm[i]]; cpos = do_align (start, cpos); } } /** * Finish building the directory. Frees the * builder context and returns the directory * in-memory. * * @param bld directory to finish * @param rsize set to the number of bytes needed * @param rdata set to the encoded directory * @return GNUNET_OK on success */ int GNUNET_FS_directory_builder_finish (struct GNUNET_FS_DirectoryBuilder *bld, size_t * rsize, void **rdata) { char *data; char *sptr; size_t *sizes; unsigned int *perm; unsigned int i; unsigned int j; struct BuilderEntry *pos; struct BuilderEntry **bes; size_t size; size_t psize; size_t off; ssize_t ret; uint32_t big; size = strlen (GNUNET_DIRECTORY_MAGIC) + sizeof (uint32_t); size += GNUNET_CONTAINER_meta_data_get_serialized_size (bld->meta); sizes = NULL; perm = NULL; bes = NULL; if (0 < bld->count) { sizes = GNUNET_malloc (bld->count * sizeof (size_t)); perm = GNUNET_malloc (bld->count * sizeof (unsigned int)); bes = GNUNET_malloc (bld->count * sizeof (struct BuilderEntry *)); pos = bld->head; for (i = 0; i < bld->count; i++) { perm[i] = i; bes[i] = pos; sizes[i] = pos->len; pos = pos->next; } block_align (size, bld->count, sizes, perm); /* compute final size with alignment */ for (i = 0; i < bld->count; i++) { psize = size; size += sizes[perm[i]]; size = do_align (psize, size); } } *rsize = size; data = GNUNET_malloc_large (size); if (data == NULL) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "malloc"); *rsize = 0; *rdata = NULL; GNUNET_free_non_null (sizes); GNUNET_free_non_null (perm); GNUNET_free_non_null (bes); return GNUNET_SYSERR; } *rdata = data; memcpy (data, GNUNET_DIRECTORY_MAGIC, strlen (GNUNET_DIRECTORY_MAGIC)); off = strlen (GNUNET_DIRECTORY_MAGIC); sptr = &data[off + sizeof (uint32_t)]; ret = GNUNET_CONTAINER_meta_data_serialize (bld->meta, &sptr, size - off - sizeof (uint32_t), GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL); GNUNET_assert (ret != -1); big = htonl (ret); memcpy (&data[off], &big, sizeof (uint32_t)); off += sizeof (uint32_t) + ret; for (j = 0; j < bld->count; j++) { i = perm[j]; psize = off; off += sizes[i]; off = do_align (psize, off); memcpy (&data[off - sizes[i]], &(bes[i])[1], sizes[i]); GNUNET_free (bes[i]); } GNUNET_free_non_null (sizes); GNUNET_free_non_null (perm); GNUNET_free_non_null (bes); GNUNET_assert (off == size); GNUNET_CONTAINER_meta_data_destroy (bld->meta); GNUNET_free (bld); return GNUNET_OK; } /* end of fs_directory.c */ gnunet-0.9.3/src/fs/fs_misc.c0000644000175000017500000001553211760502551012742 00000000000000/* This file is part of GNUnet. (C) 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs_misc.c * @brief misc. functions related to file-sharing in general * @author Christian Grothoff */ #include "platform.h" #include "gnunet_constants.h" #include "gnunet_fs_service.h" #include "fs_api.h" /** * Suggest a filename based on given metadata. * * @param md given meta data * @return NULL if meta data is useless for suggesting a filename */ char * GNUNET_FS_meta_data_suggest_filename (const struct GNUNET_CONTAINER_MetaData *md) { static const char *mimeMap[][2] = { {"application/bz2", ".bz2"}, {"application/gnunet-directory", ".gnd"}, {"application/java", ".class"}, {"application/msword", ".doc"}, {"application/ogg", ".ogg"}, {"application/pdf", ".pdf"}, {"application/pgp-keys", ".key"}, {"application/pgp-signature", ".pgp"}, {"application/postscript", ".ps"}, {"application/rar", ".rar"}, {"application/rtf", ".rtf"}, {"application/xml", ".xml"}, {"application/x-debian-package", ".deb"}, {"application/x-dvi", ".dvi"}, {"applixation/x-flac", ".flac"}, {"applixation/x-gzip", ".gz"}, {"application/x-java-archive", ".jar"}, {"application/x-java-vm", ".class"}, {"application/x-python-code", ".pyc"}, {"application/x-redhat-package-manager", ".rpm"}, {"application/x-rpm", ".rpm"}, {"application/x-tar", ".tar"}, {"application/x-tex-pk", ".pk"}, {"application/x-texinfo", ".texinfo"}, {"application/x-xcf", ".xcf"}, {"application/x-xfig", ".xfig"}, {"application/zip", ".zip"}, {"audio/midi", ".midi"}, {"audio/mpeg", ".mp3"}, {"audio/real", ".rm"}, {"audio/x-wav", ".wav"}, {"image/gif", ".gif"}, {"image/jpeg", ".jpg"}, {"image/pcx", ".pcx"}, {"image/png", ".png"}, {"image/tiff", ".tiff"}, {"image/x-ms-bmp", ".bmp"}, {"image/x-xpixmap", ".xpm"}, {"text/css", ".css"}, {"text/html", ".html"}, {"text/plain", ".txt"}, {"text/rtf", ".rtf"}, {"text/x-c++hdr", ".h++"}, {"text/x-c++src", ".c++"}, {"text/x-chdr", ".h"}, {"text/x-csrc", ".c"}, {"text/x-java", ".java"}, {"text/x-moc", ".moc"}, {"text/x-pascal", ".pas"}, {"text/x-perl", ".pl"}, {"text/x-python", ".py"}, {"text/x-tex", ".tex"}, {"video/avi", ".avi"}, {"video/mpeg", ".mpeg"}, {"video/quicktime", ".qt"}, {"video/real", ".rm"}, {"video/x-msvideo", ".avi"}, {NULL, NULL}, }; char *ret; unsigned int i; char *mime; char *base; const char *ext; ret = GNUNET_CONTAINER_meta_data_get_by_type (md, EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME); if (ret != NULL) return ret; ext = NULL; mime = GNUNET_CONTAINER_meta_data_get_by_type (md, EXTRACTOR_METATYPE_MIMETYPE); if (mime != NULL) { i = 0; while ((mimeMap[i][0] != NULL) && (0 != strcmp (mime, mimeMap[i][0]))) i++; if (mimeMap[i][1] == NULL) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, _("Did not find mime type `%s' in extension list.\n"), mime); else ext = mimeMap[i][1]; GNUNET_free (mime); } base = GNUNET_CONTAINER_meta_data_get_first_by_types (md, EXTRACTOR_METATYPE_TITLE, EXTRACTOR_METATYPE_BOOK_TITLE, EXTRACTOR_METATYPE_ORIGINAL_TITLE, EXTRACTOR_METATYPE_PACKAGE_NAME, EXTRACTOR_METATYPE_URL, EXTRACTOR_METATYPE_URI, EXTRACTOR_METATYPE_DESCRIPTION, EXTRACTOR_METATYPE_ISRC, EXTRACTOR_METATYPE_JOURNAL_NAME, EXTRACTOR_METATYPE_AUTHOR_NAME, EXTRACTOR_METATYPE_SUBJECT, EXTRACTOR_METATYPE_ALBUM, EXTRACTOR_METATYPE_ARTIST, EXTRACTOR_METATYPE_KEYWORDS, EXTRACTOR_METATYPE_COMMENT, EXTRACTOR_METATYPE_UNKNOWN, -1); if ((base == NULL) && (ext == NULL)) return NULL; if (base == NULL) return GNUNET_strdup (ext); if (ext == NULL) return base; GNUNET_asprintf (&ret, "%s%s", base, ext); GNUNET_free (base); return ret; } /** * Return the current year (i.e. '2011'). */ unsigned int GNUNET_FS_get_current_year () { time_t tp; struct tm *t; tp = time (NULL); t = gmtime (&tp); if (t == NULL) return 0; return t->tm_year + 1900; } /** * Convert a year to an expiration time of January 1st of that year. * * @param year a year (after 1970, please ;-)). * @return absolute time for January 1st of that year. */ struct GNUNET_TIME_Absolute GNUNET_FS_year_to_time (unsigned int year) { struct GNUNET_TIME_Absolute ret; time_t tp; struct tm t; memset (&t, 0, sizeof (t)); if (year < 1900) { GNUNET_break (0); return GNUNET_TIME_absolute_get (); /* now */ } t.tm_year = year - 1900; t.tm_mday = 1; t.tm_mon = 1; t.tm_wday = 1; t.tm_yday = 1; tp = mktime (&t); GNUNET_break (tp != (time_t) - 1); ret.abs_value = tp * 1000LL; /* seconds to ms */ return ret; } /** * Convert an expiration time to the respective year (rounds) * * @param at absolute time * @return year a year (after 1970), 0 on error */ unsigned int GNUNET_FS_time_to_year (struct GNUNET_TIME_Absolute at) { struct tm *t; time_t tp; tp = at.abs_value / 1000; /* ms to seconds */ t = gmtime (&tp); if (t == NULL) return 0; return t->tm_year + 1900; } /* end of fs_misc.c */ gnunet-0.9.3/src/fs/test_fs_data.conf0000644000175000017500000000021511615567501014457 00000000000000@INLINE@ test_fs_defaults.conf [PATHS] SERVICEHOME = /tmp/gnunet-test-fs-data/ DEFAULTCONFIG = test_fs_data.conf [fs] ACTIVEMIGRATION = NO gnunet-0.9.3/src/fs/test_fs_download_indexed.c0000644000175000017500000002713411760502551016356 00000000000000/* This file is part of GNUnet. (C) 2004, 2005, 2006, 2008, 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/test_fs_download_indexed.c * @brief simple testcase for downloading of indexed file * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_arm_service.h" #include "gnunet_fs_service.h" #include #define VERBOSE GNUNET_NO #define START_ARM GNUNET_YES /** * File-size we use for testing. */ #define FILESIZE (1024 * 1024 * 2) /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) /** * How long should our test-content live? */ #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static struct PeerContext p1; static struct GNUNET_TIME_Absolute start; static struct GNUNET_FS_Handle *fs; static struct GNUNET_FS_DownloadContext *download; static struct GNUNET_FS_PublishContext *publish; static GNUNET_SCHEDULER_TaskIdentifier timeout_kill; static char *fn; static char *fn1; static int err; static void timeout_kill_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { fprintf (stderr, "Download not fast enough, timeout!\n"); if (download != NULL) { GNUNET_FS_download_stop (download, GNUNET_YES); download = NULL; } else if (publish != NULL) { GNUNET_FS_publish_stop (publish); publish = NULL; } timeout_kill = GNUNET_SCHEDULER_NO_TASK; err = 1; } static void abort_publish_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (publish != NULL) { GNUNET_FS_publish_stop (publish); publish = NULL; } } static void stop_fs_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_FS_stop (fs); fs = NULL; } static void abort_download_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { uint64_t size; if (download != NULL) { GNUNET_FS_download_stop (download, GNUNET_YES); download = NULL; } GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_size (fn, &size, GNUNET_YES, GNUNET_NO)); GNUNET_assert (size == FILESIZE); GNUNET_DISK_directory_remove (fn); GNUNET_free (fn); fn = NULL; GNUNET_SCHEDULER_cancel (timeout_kill); timeout_kill = GNUNET_SCHEDULER_NO_TASK; } static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) { switch (event->status) { case GNUNET_FS_STATUS_PUBLISH_PROGRESS: #if VERBOSE printf ("Publish is progressing (%llu/%llu at level %u off %llu)...\n", (unsigned long long) event->value.publish.completed, (unsigned long long) event->value.publish.size, event->value.publish.specifics.progress.depth, (unsigned long long) event->value.publish.specifics. progress.offset); #endif break; case GNUNET_FS_STATUS_PUBLISH_COMPLETED: printf ("Publishing complete, %llu kbps.\n", (unsigned long long) (FILESIZE * 1000LL / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value) / 1024LL)); GAUGER ("FS", "Publishing speed (indexing)", (unsigned long long) (FILESIZE * 1000LL / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value) / 1024LL), "kb/s"); fn = GNUNET_DISK_mktemp ("gnunet-download-test-dst"); start = GNUNET_TIME_absolute_get (); download = GNUNET_FS_download_start (fs, event->value.publish.specifics. completed.chk_uri, NULL, fn, NULL, 0, FILESIZE, 1, GNUNET_FS_DOWNLOAD_OPTION_NONE, "download", NULL); GNUNET_assert (download != NULL); break; case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: printf ("Download complete, %llu kbps.\n", (unsigned long long) (FILESIZE * 1000LL / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value) / 1024LL)); GAUGER ("FS", "Local download speed (indexed)", (unsigned long long) (FILESIZE * 1000LL / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value) / 1024LL), "kb/s"); GNUNET_SCHEDULER_add_now (&abort_download_task, NULL); break; case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: GNUNET_assert (download == event->value.download.dc); #if VERBOSE printf ("Download is progressing (%llu/%llu at level %u off %llu)...\n", (unsigned long long) event->value.download.completed, (unsigned long long) event->value.download.size, event->value.download.specifics.progress.depth, (unsigned long long) event->value.download.specifics. progress.offset); #endif break; case GNUNET_FS_STATUS_PUBLISH_ERROR: FPRINTF (stderr, "Error publishing file: %s\n", event->value.publish.specifics.error.message); GNUNET_break (0); GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_DOWNLOAD_ERROR: FPRINTF (stderr, "Error downloading file: %s\n", event->value.download.specifics.error.message); GNUNET_SCHEDULER_add_now (&abort_download_task, NULL); break; case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: break; case GNUNET_FS_STATUS_PUBLISH_START: GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); GNUNET_assert (NULL == event->value.publish.pctx); GNUNET_assert (FILESIZE == event->value.publish.size); GNUNET_assert (0 == event->value.publish.completed); GNUNET_assert (1 == event->value.publish.anonymity); break; case GNUNET_FS_STATUS_PUBLISH_STOPPED: GNUNET_assert (publish == event->value.publish.pc); GNUNET_assert (FILESIZE == event->value.publish.size); GNUNET_assert (1 == event->value.publish.anonymity); GNUNET_SCHEDULER_add_now (&stop_fs_task, NULL); break; case GNUNET_FS_STATUS_DOWNLOAD_START: GNUNET_assert (0 == strcmp ("download", event->value.download.cctx)); GNUNET_assert (NULL == event->value.download.pctx); GNUNET_assert (NULL != event->value.download.uri); GNUNET_assert (0 == strcmp (fn, event->value.download.filename)); GNUNET_assert (FILESIZE == event->value.download.size); GNUNET_assert (0 == event->value.download.completed); GNUNET_assert (1 == event->value.download.anonymity); break; case GNUNET_FS_STATUS_DOWNLOAD_STOPPED: GNUNET_assert (download == event->value.download.dc); GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; default: printf ("Unexpected event: %d\n", event->status); break; } return NULL; } static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); } static void stop_arm (struct PeerContext *p) { #if START_ARM if (NULL != p->arm_proc) { if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; } #endif GNUNET_CONFIGURATION_destroy (p->cfg); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { const char *keywords[] = { "down_foo", "down_bar", }; char *buf; struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_FS_Uri *kuri; struct GNUNET_FS_FileInformation *fi; struct GNUNET_FS_BlockOptions bo; size_t i; setup_peer (&p1, "test_fs_download_data.conf"); fs = GNUNET_FS_start (cfg, "test-fs-download-indexed", &progress_cb, NULL, GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); GNUNET_assert (NULL != fs); fn1 = GNUNET_DISK_mktemp ("gnunet-download-indexed-test"); buf = GNUNET_malloc (FILESIZE); for (i = 0; i < FILESIZE; i++) buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); GNUNET_assert (FILESIZE == GNUNET_DISK_fn_write (fn1, buf, FILESIZE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)); GNUNET_free (buf); meta = GNUNET_CONTAINER_meta_data_create (); kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); bo.content_priority = 42; bo.anonymity_level = 1; bo.replication_level = 0; bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); fi = GNUNET_FS_file_information_create_from_file (fs, "publish-context", fn1, kuri, meta, GNUNET_YES, &bo); GNUNET_FS_uri_destroy (kuri); GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_assert (NULL != fi); timeout_kill = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_kill_task, NULL); start = GNUNET_TIME_absolute_get (); publish = GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, GNUNET_FS_PUBLISH_OPTION_NONE); GNUNET_assert (publish != NULL); } int main (int argc, char *argv[]) { char *const argvx[] = { "test-fs-download-indexed", "-c", "test_fs_download_data.conf", NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("test_fs_download_indexed", "WARNING", NULL); GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "test-fs-download-indexed", "nohelp", options, &run, NULL); stop_arm (&p1); if (fn1 != NULL) { GNUNET_DISK_directory_remove (fn1); GNUNET_free (fn1); } if (fn != NULL) { GNUNET_DISK_directory_remove (fn); GNUNET_free (fn); } GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-download/"); return err; } /* end of test_fs_download_indexed.c */ gnunet-0.9.3/src/fs/test_fs_file_information.c0000644000175000017500000001316511760502551016372 00000000000000/* This file is part of GNUnet. (C) 2004, 2005, 2006, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/test_fs_file_information.c * @brief simple testcase for file_information operations * @author Christian Grothoff * * TODO: * - test that metatdata, etc. are all correct (for example, * there is a known bug with dirname never being set that is * not detected!) * - need to iterate over file-information structure * - other API functions may not yet be tested (such as * filedata-from-callback) */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_fs_service.h" #define VERBOSE GNUNET_NO /** * File-size we use for testing. */ #define FILESIZE (1024 * 1024 * 2) /** * How long should our test-content live? */ #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) static int mycleaner (void *cls, struct GNUNET_FS_FileInformation *fi, uint64_t length, struct GNUNET_CONTAINER_MetaData *meta, struct GNUNET_FS_Uri **uri, struct GNUNET_FS_BlockOptions *bo, int *do_index, void **client_info) { return GNUNET_OK; } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { const char *keywords[] = { "down_foo", "down_bar", }; char *fn1; char *fn2; char *buf; struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_FS_Uri *kuri; struct GNUNET_FS_FileInformation *fi1; struct GNUNET_FS_FileInformation *fi2; struct GNUNET_FS_FileInformation *fidir; struct GNUNET_FS_Handle *fs; size_t i; struct GNUNET_FS_BlockOptions bo; fs = GNUNET_FS_start (cfg, "test-fs-file-information", NULL, NULL, GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); fn1 = GNUNET_DISK_mktemp ("gnunet-file_information-test-dst"); buf = GNUNET_malloc (FILESIZE); for (i = 0; i < FILESIZE; i++) buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); GNUNET_assert (FILESIZE == GNUNET_DISK_fn_write (fn1, buf, FILESIZE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)); GNUNET_free (buf); fn2 = GNUNET_DISK_mktemp ("gnunet-file_information-test-dst"); buf = GNUNET_malloc (FILESIZE); for (i = 0; i < FILESIZE; i++) buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); GNUNET_assert (FILESIZE == GNUNET_DISK_fn_write (fn2, buf, FILESIZE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)); GNUNET_free (buf); meta = GNUNET_CONTAINER_meta_data_create (); kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); bo.content_priority = 42; bo.anonymity_level = 1; bo.replication_level = 0; bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); fi1 = GNUNET_FS_file_information_create_from_file (fs, "file_information-context1", fn1, kuri, meta, GNUNET_YES, &bo); GNUNET_assert (fi1 != NULL); fi2 = GNUNET_FS_file_information_create_from_file (fs, "file_information-context2", fn2, kuri, meta, GNUNET_YES, &bo); GNUNET_assert (fi2 != NULL); fidir = GNUNET_FS_file_information_create_empty_directory (fs, "file_information-context-dir", kuri, meta, &bo, NULL); GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi1)); GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi2)); GNUNET_FS_uri_destroy (kuri); GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_assert (NULL != fidir); /* FIXME: test more of API! */ GNUNET_FS_file_information_destroy (fidir, &mycleaner, NULL); GNUNET_DISK_directory_remove (fn1); GNUNET_DISK_directory_remove (fn2); GNUNET_free_non_null (fn1); GNUNET_free_non_null (fn2); GNUNET_FS_stop (fs); } int main (int argc, char *argv[]) { char *const argvx[] = { "test-fs-file_information", "-c", "test_fs_file_information_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("test_fs_file_information", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "test-fs-file_information", "nohelp", options, &run, NULL); return 0; } /* end of test_fs_file_information.c */ gnunet-0.9.3/src/fs/gnunet-directory.c0000644000175000017500000001323611760502551014620 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-directory.c * @brief display content of GNUnet directories * @author Christian Grothoff */ #include "platform.h" #include "gnunet_fs_service.h" static int ret; /** * Print a meta data entry. * * @param cls closure (unused) * @param plugin_name name of the plugin that generated the meta data * @param type type of the keyword * @param format format of data * @param data_mime_type mime type of data * @param data value of the meta data * @param data_size number of bytes in data * @return always 0 (to continue iterating) */ static int item_printer (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat format, const char *data_mime_type, const char *data, size_t data_size) { if (type == EXTRACTOR_METATYPE_GNUNET_FULL_DATA) { printf (_("\t\n"), (unsigned int) data_size); return 0; } if ((format != EXTRACTOR_METAFORMAT_UTF8) && (format != EXTRACTOR_METAFORMAT_C_STRING)) return 0; if (type == EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME) return 0; printf ("\t%20s: %s\n", dgettext (LIBEXTRACTOR_GETTEXT_DOMAIN, EXTRACTOR_metatype_to_string (type)), data); return 0; } /** * Print an entry in a directory. * * @param cls closure (not used) * @param filename name of the file in the directory * @param uri URI of the file * @param meta metadata for the file; metadata for * the directory if everything else is NULL/zero * @param length length of the available data for the file * (of type size_t since data must certainly fit * into memory; if files are larger than size_t * permits, then they will certainly not be * embedded with the directory itself). * @param data data available for the file (length bytes) */ static void print_entry (void *cls, const char *filename, const struct GNUNET_FS_Uri *uri, const struct GNUNET_CONTAINER_MetaData *meta, size_t length, const void *data) { char *string; char *name; name = GNUNET_CONTAINER_meta_data_get_by_type (meta, EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME); if (uri == NULL) { printf (_("Directory `%s' meta data:\n"), name); GNUNET_CONTAINER_meta_data_iterate (meta, &item_printer, NULL); printf ("\n"); printf (_("Directory `%s' contents:\n"), name); GNUNET_free (name); return; } string = GNUNET_FS_uri_to_string (uri); printf ("%s (%s):\n", name, string); GNUNET_free (string); GNUNET_CONTAINER_meta_data_iterate (meta, &item_printer, NULL); printf ("\n"); GNUNET_free (name); } /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param cfg configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_DISK_MapHandle *map; struct GNUNET_DISK_FileHandle *h; void *data; size_t len; uint64_t size; const char *filename; int i; if (NULL == args[0]) { FPRINTF (stderr, "%s", _("You must specify a filename to inspect.\n")); ret = 1; return; } i = 0; while (NULL != (filename = args[i++])) { if ((GNUNET_OK != GNUNET_DISK_file_size (filename, &size, GNUNET_YES, GNUNET_YES)) || (NULL == (h = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE)))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to read directory `%s'\n"), filename); ret = 1; continue; } len = (size_t) size; data = GNUNET_DISK_file_map (h, &map, GNUNET_DISK_MAP_TYPE_READ, len); GNUNET_assert (NULL != data); if (GNUNET_OK != GNUNET_FS_directory_list_contents (len, data, 0, &print_entry, NULL)) fprintf (stdout, _("`%s' is not a GNUnet directory\n"), filename); else printf ("\n"); GNUNET_DISK_file_unmap (map); GNUNET_DISK_file_close (h); } } /** * The main function to inspect GNUnet directories. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-directory [OPTIONS] FILENAME", gettext_noop ("Display contents of a GNUnet directory"), options, &run, NULL)) ? ret : 1; } /* end of gnunet-directory.c */ gnunet-0.9.3/src/fs/fs_dirmetascan.c0000644000175000017500000003015411760645401014300 00000000000000/* This file is part of GNUnet (C) 2005-2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs_dirmetascan.c * @brief code to asynchronously build a 'struct GNUNET_FS_ShareTreeItem' * from an on-disk directory for publishing; use the 'gnunet-helper-fs-publish'. * @author LRN * @author Christian Grothoff */ #include "platform.h" #include "gnunet_fs_service.h" #include "gnunet_scheduler_lib.h" #include /** * An opaque structure a pointer to which is returned to the * caller to be used to control the scanner. */ struct GNUNET_FS_DirScanner { /** * Helper process. */ struct GNUNET_HELPER_Handle *helper; /** * Expanded filename (as given by the scan initiator). * The scanner thread stores a copy here, and frees it when it finishes. */ char *filename_expanded; /** * Second argument to helper process. */ char *ex_arg; /** * The function that will be called every time there's a progress * message. */ GNUNET_FS_DirScannerProgressCallback progress_callback; /** * A closure for progress_callback. */ void *progress_callback_cls; /** * After the scan is finished, it will contain a pointer to the * top-level directory entry in the directory tree built by the * scanner. */ struct GNUNET_FS_ShareTreeItem *toplevel; /** * Current position during processing. */ struct GNUNET_FS_ShareTreeItem *pos; /** * Task scheduled when we are done. */ GNUNET_SCHEDULER_TaskIdentifier stop_task; /** * Arguments for helper. */ char *args[4]; }; /** * Abort the scan. Must not be called from within the progress_callback * function. * * @param ds directory scanner structure */ void GNUNET_FS_directory_scan_abort (struct GNUNET_FS_DirScanner *ds) { /* terminate helper */ if (NULL != ds->helper) GNUNET_HELPER_stop (ds->helper); /* free resources */ if (NULL != ds->toplevel) GNUNET_FS_share_tree_free (ds->toplevel); if (GNUNET_SCHEDULER_NO_TASK != ds->stop_task) GNUNET_SCHEDULER_cancel (ds->stop_task); GNUNET_free_non_null (ds->ex_arg); GNUNET_free (ds->filename_expanded); GNUNET_free (ds); } /** * Obtain the result of the scan after the scan has signalled * completion. Must not be called prior to completion. The 'ds' is * freed as part of this call. * * @param ds directory scanner structure * @return the results of the scan (a directory tree) */ struct GNUNET_FS_ShareTreeItem * GNUNET_FS_directory_scan_get_result (struct GNUNET_FS_DirScanner *ds) { struct GNUNET_FS_ShareTreeItem *result; /* check that we're actually done */ GNUNET_assert (NULL == ds->helper); /* preserve result */ result = ds->toplevel; ds->toplevel = NULL; GNUNET_FS_directory_scan_abort (ds); return result; } /** * Move in the directory from the given position to the next file * in DFS traversal. * * @param pos current position * @return next file, NULL for none */ static struct GNUNET_FS_ShareTreeItem * advance (struct GNUNET_FS_ShareTreeItem *pos) { int moved; GNUNET_assert (NULL != pos); moved = 0; /* must not terminate, even on file, otherwise "normal" */ while ( (pos->is_directory == GNUNET_YES) || (0 == moved) ) { if ( (moved != -1) && (NULL != pos->children_head) ) { pos = pos->children_head; moved = 1; /* can terminate if file */ continue; } if (NULL != pos->next) { pos = pos->next; moved = 1; /* can terminate if file */ continue; } if (NULL != pos->parent) { pos = pos->parent; moved = -1; /* force move to 'next' or 'parent' */ continue; } /* no more options, end of traversal */ return NULL; } return pos; } /** * Add another child node to the tree. * * @param parent parent of the child, NULL for top level * @param filename name of the file or directory * @param is_directory GNUNET_YES for directories * @return new entry that was just created */ static struct GNUNET_FS_ShareTreeItem * expand_tree (struct GNUNET_FS_ShareTreeItem *parent, const char *filename, int is_directory) { struct GNUNET_FS_ShareTreeItem *chld; size_t slen; chld = GNUNET_malloc (sizeof (struct GNUNET_FS_ShareTreeItem)); chld->parent = parent; chld->filename = GNUNET_strdup (filename); GNUNET_asprintf (&chld->short_filename, "%s%s", GNUNET_STRINGS_get_short_name (filename), is_directory == GNUNET_YES ? "/" : ""); /* make sure we do not end with '//' */ slen = strlen (chld->short_filename); if ( (slen >= 2) && (chld->short_filename[slen-1] == '/') && (chld->short_filename[slen-2] == '/') ) chld->short_filename[slen-1] = '\0'; chld->is_directory = is_directory; if (NULL != parent) GNUNET_CONTAINER_DLL_insert (parent->children_head, parent->children_tail, chld); return chld; } /** * Task run last to shut everything down. * * @param cls the 'struct GNUNET_FS_DirScanner' * @param tc unused */ static void finish_scan (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FS_DirScanner *ds = cls; ds->stop_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_HELPER_stop (ds->helper); ds->helper = NULL; ds->progress_callback (ds->progress_callback_cls, NULL, GNUNET_SYSERR, GNUNET_FS_DIRSCANNER_FINISHED); } /** * Called every time there is data to read from the scanner. * Calls the scanner progress handler. * * @param cls the closure (directory scanner object) * @param client always NULL * @param msg message from the helper process */ static int process_helper_msgs (void *cls, void *client, const struct GNUNET_MessageHeader *msg) { struct GNUNET_FS_DirScanner *ds = cls; const char *filename; size_t left; #if 0 fprintf (stderr, "DMS parses %u-byte message of type %u\n", (unsigned int) ntohs (msg->size), (unsigned int) ntohs (msg->type)); #endif left = ntohs (msg->size) - sizeof (struct GNUNET_MessageHeader); filename = (const char*) &msg[1]; switch (ntohs (msg->type)) { case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_FILE: if (filename[left-1] != '\0') { GNUNET_break (0); break; } ds->progress_callback (ds->progress_callback_cls, filename, GNUNET_NO, GNUNET_FS_DIRSCANNER_FILE_START); if (NULL == ds->toplevel) ds->toplevel = expand_tree (ds->pos, filename, GNUNET_NO); else (void) expand_tree (ds->pos, filename, GNUNET_NO); return GNUNET_OK; case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_DIRECTORY: if (filename[left-1] != '\0') { GNUNET_break (0); break; } if (0 == strcmp ("..", filename)) { if (NULL == ds->pos) { GNUNET_break (0); break; } ds->pos = ds->pos->parent; return GNUNET_OK; } ds->progress_callback (ds->progress_callback_cls, filename, GNUNET_YES, GNUNET_FS_DIRSCANNER_FILE_START); ds->pos = expand_tree (ds->pos, filename, GNUNET_YES); if (NULL == ds->toplevel) ds->toplevel = ds->pos; return GNUNET_OK; case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_ERROR: break; case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_SKIP_FILE: if ('\0' != filename[left-1]) break; ds->progress_callback (ds->progress_callback_cls, filename, GNUNET_SYSERR, GNUNET_FS_DIRSCANNER_FILE_IGNORED); return GNUNET_OK; case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_COUNTING_DONE: if (0 != left) { GNUNET_break (0); break; } if (NULL == ds->toplevel) { GNUNET_break (0); break; } ds->progress_callback (ds->progress_callback_cls, NULL, GNUNET_SYSERR, GNUNET_FS_DIRSCANNER_ALL_COUNTED); ds->pos = ds->toplevel; if (GNUNET_YES == ds->pos->is_directory) ds->pos = advance (ds->pos); return GNUNET_OK; case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_META_DATA: { size_t nlen; const char *end; if (NULL == ds->pos) { GNUNET_break (0); break; } end = memchr (filename, 0, left); if (NULL == end) { GNUNET_break (0); break; } end++; nlen = end - filename; left -= nlen; if (0 != strcmp (filename, ds->pos->filename)) { GNUNET_break (0); break; } ds->progress_callback (ds->progress_callback_cls, filename, GNUNET_YES, GNUNET_FS_DIRSCANNER_EXTRACT_FINISHED); if (0 < left) { ds->pos->meta = GNUNET_CONTAINER_meta_data_deserialize (end, left); if (NULL == ds->pos->meta) { GNUNET_break (0); break; } /* having full filenames is too dangerous; always make sure we clean them up */ GNUNET_CONTAINER_meta_data_delete (ds->pos->meta, EXTRACTOR_METATYPE_FILENAME, NULL, 0); /* instead, put in our 'safer' original filename */ GNUNET_CONTAINER_meta_data_insert (ds->pos->meta, "", EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, EXTRACTOR_METAFORMAT_UTF8, "text/plain", ds->pos->short_filename, strlen (ds->pos->short_filename) + 1); } ds->pos->ksk_uri = GNUNET_FS_uri_ksk_create_from_meta_data (ds->pos->meta); ds->pos = advance (ds->pos); return GNUNET_OK; } case GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_FINISHED: if (NULL != ds->pos) { GNUNET_break (0); break; } if (0 != left) { GNUNET_break (0); break; } if (NULL == ds->toplevel) { GNUNET_break (0); break; } ds->stop_task = GNUNET_SCHEDULER_add_now (&finish_scan, ds); return GNUNET_OK; default: GNUNET_break (0); break; } ds->progress_callback (ds->progress_callback_cls, NULL, GNUNET_SYSERR, GNUNET_FS_DIRSCANNER_INTERNAL_ERROR); return GNUNET_OK; } /** * Start a directory scanner thread. * * @param filename name of the directory to scan * @param disable_extractor GNUNET_YES to not to run libextractor on files (only build a tree) * @param ex if not NULL, must be a list of extra plugins for extractor * @param cb the callback to call when there are scanning progress messages * @param cb_cls closure for 'cb' * @return directory scanner object to be used for controlling the scanner */ struct GNUNET_FS_DirScanner * GNUNET_FS_directory_scan_start (const char *filename, int disable_extractor, const char *ex, GNUNET_FS_DirScannerProgressCallback cb, void *cb_cls) { struct stat sbuf; char *filename_expanded; struct GNUNET_FS_DirScanner *ds; if (0 != STAT (filename, &sbuf)) return NULL; filename_expanded = GNUNET_STRINGS_filename_expand (filename); if (NULL == filename_expanded) return NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting to scan directory `%s'\n", filename_expanded); ds = GNUNET_malloc (sizeof (struct GNUNET_FS_DirScanner)); ds->progress_callback = cb; ds->progress_callback_cls = cb_cls; ds->filename_expanded = filename_expanded; if (disable_extractor) ds->ex_arg = GNUNET_strdup ("-"); else ds->ex_arg = (NULL != ex) ? GNUNET_strdup (ex) : NULL; ds->args[0] = "gnunet-helper-fs-publish"; ds->args[1] = ds->filename_expanded; ds->args[2] = ds->ex_arg; ds->args[3] = NULL; ds->helper = GNUNET_HELPER_start ("gnunet-helper-fs-publish", ds->args, &process_helper_msgs, ds); if (NULL == ds->helper) { GNUNET_free (filename_expanded); GNUNET_free (ds); return NULL; } return ds; } /* end of fs_dirmetascan.c */ gnunet-0.9.3/src/fs/test_fs_uri_data.conf0000644000175000017500000000017211615567501015340 00000000000000@INLINE@ test_fs_defaults.conf [PATHS] SERVICEHOME = /tmp/gnunet-test-fs-uri/ [arm] DEFAULTSERVICES = topology hostlist gnunet-0.9.3/src/fs/gnunet-service-fs_pr.c0000644000175000017500000015465711760505144015401 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-service-fs_pr.c * @brief API to handle pending requests * @author Christian Grothoff */ #include "platform.h" #include "gnunet_load_lib.h" #include "gnunet-service-fs.h" #include "gnunet-service-fs_cp.h" #include "gnunet-service-fs_indexing.h" #include "gnunet-service-fs_pe.h" #include "gnunet-service-fs_pr.h" /** * Maximum size of the datastore queue for P2P operations. Needs to * be large enough to queue MAX_QUEUE_PER_PEER operations for roughly * the number of active (connected) peers. */ #define MAX_DATASTORE_QUEUE (16 * MAX_QUEUE_PER_PEER) /** * Bandwidth value of a 0-priority content (must be fairly high * compared to query since content is typically significantly larger * -- and more valueable since it can take many queries to get one * piece of content). */ #define CONTENT_BANDWIDTH_VALUE 800 /** * Hard limit on the number of results we may get from the datastore per query. */ #define MAX_RESULTS (100 * 1024) /** * An active request. */ struct GSF_PendingRequest { /** * Public data for the request. */ struct GSF_PendingRequestData public_data; /** * Function to call if we encounter a reply. */ GSF_PendingRequestReplyHandler rh; /** * Closure for 'rh' */ void *rh_cls; /** * Array of hash codes of replies we've already seen. */ GNUNET_HashCode *replies_seen; /** * Bloomfilter masking replies we've already seen. */ struct GNUNET_CONTAINER_BloomFilter *bf; /** * Entry for this pending request in the expiration heap, or NULL. */ struct GNUNET_CONTAINER_HeapNode *hnode; /** * Datastore queue entry for this request (or NULL for none). */ struct GNUNET_DATASTORE_QueueEntry *qe; /** * DHT request handle for this request (or NULL for none). */ struct GNUNET_DHT_GetHandle *gh; /** * Function to call upon completion of the local get * request, or NULL for none. */ GSF_LocalLookupContinuation llc_cont; /** * Closure for llc_cont. */ void *llc_cont_cls; /** * Last result from the local datastore lookup evaluation. */ enum GNUNET_BLOCK_EvaluationResult local_result; /** * Identity of the peer that we should use for the 'sender' * (recipient of the response) when forwarding (0 for none). */ GNUNET_PEER_Id sender_pid; /** * Identity of the peer that we should never forward this query * to since it originated this query (0 for none). */ GNUNET_PEER_Id origin_pid; /** * Time we started the last datastore lookup. */ struct GNUNET_TIME_Absolute qe_start; /** * Task that warns us if the local datastore lookup takes too long. */ GNUNET_SCHEDULER_TaskIdentifier warn_task; /** * Current offset for querying our local datastore for results. * Starts at a random value, incremented until we get the same * UID again (detected using 'first_uid'), which is then used * to termiante the iteration. */ uint64_t local_result_offset; /** * Unique ID of the first result from the local datastore; * used to detect wrap-around of the offset. */ uint64_t first_uid; /** * Number of valid entries in the 'replies_seen' array. */ unsigned int replies_seen_count; /** * Length of the 'replies_seen' array. */ unsigned int replies_seen_size; /** * Mingle value we currently use for the bf. */ uint32_t mingle; /** * Do we have a first UID yet? */ unsigned int have_first_uid; }; /** * All pending requests, ordered by the query. Entries * are of type 'struct GSF_PendingRequest*'. */ static struct GNUNET_CONTAINER_MultiHashMap *pr_map; /** * Datastore 'PUT' load tracking. */ static struct GNUNET_LOAD_Value *datastore_put_load; /** * Are we allowed to migrate content to this peer. */ static int active_to_migration; /** * Size of the datastore queue we assume for common requests. * Determined based on the network quota. */ static unsigned int datastore_queue_size; /** * Heap with the request that will expire next at the top. Contains * pointers of type "struct PendingRequest*"; these will *also* be * aliased from the "requests_by_peer" data structures and the * "requests_by_query" table. Note that requests from our clients * don't expire and are thus NOT in the "requests_by_expiration" * (or the "requests_by_peer" tables). */ static struct GNUNET_CONTAINER_Heap *requests_by_expiration_heap; /** * Maximum number of requests (from other peers, overall) that we're * willing to have pending at any given point in time. Can be changed * via the configuration file (32k is just the default). */ static unsigned long long max_pending_requests = (32 * 1024); /** * Recalculate our bloom filter for filtering replies. This function * will create a new bloom filter from scratch, so it should only be * called if we have no bloomfilter at all (and hence can create a * fresh one of minimal size without problems) OR if our peer is the * initiator (in which case we may resize to larger than mimimum size). * * @param pr request for which the BF is to be recomputed */ static void refresh_bloomfilter (struct GSF_PendingRequest *pr) { if (pr->bf != NULL) GNUNET_CONTAINER_bloomfilter_free (pr->bf); pr->mingle = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX); pr->bf = GNUNET_BLOCK_construct_bloomfilter (pr->mingle, pr->replies_seen, pr->replies_seen_count); } /** * Create a new pending request. * * @param options request options * @param type type of the block that is being requested * @param query key for the lookup * @param namespace namespace to lookup, NULL for no namespace * @param target preferred target for the request, NULL for none * @param bf_data raw data for bloom filter for known replies, can be NULL * @param bf_size number of bytes in bf_data * @param mingle mingle value for bf * @param anonymity_level desired anonymity level * @param priority maximum outgoing cummulative request priority to use * @param ttl current time-to-live for the request * @param sender_pid peer ID to use for the sender when forwarding, 0 for none * @param origin_pid peer ID of origin of query (do not loop back) * @param replies_seen hash codes of known local replies * @param replies_seen_count size of the 'replies_seen' array * @param rh handle to call when we get a reply * @param rh_cls closure for rh * @return handle for the new pending request */ struct GSF_PendingRequest * GSF_pending_request_create_ (enum GSF_PendingRequestOptions options, enum GNUNET_BLOCK_Type type, const GNUNET_HashCode * query, const GNUNET_HashCode * namespace, const struct GNUNET_PeerIdentity *target, const char *bf_data, size_t bf_size, uint32_t mingle, uint32_t anonymity_level, uint32_t priority, int32_t ttl, GNUNET_PEER_Id sender_pid, GNUNET_PEER_Id origin_pid, const GNUNET_HashCode * replies_seen, unsigned int replies_seen_count, GSF_PendingRequestReplyHandler rh, void *rh_cls) { struct GSF_PendingRequest *pr; struct GSF_PendingRequest *dpr; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating request handle for `%s' of type %d\n", GNUNET_h2s (query), type); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# Pending requests created"), 1, GNUNET_NO); pr = GNUNET_malloc (sizeof (struct GSF_PendingRequest)); pr->local_result_offset = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); pr->public_data.query = *query; if (GNUNET_BLOCK_TYPE_FS_SBLOCK == type) { GNUNET_assert (NULL != namespace); pr->public_data.namespace = *namespace; } if (NULL != target) { pr->public_data.target = *target; pr->public_data.has_target = GNUNET_YES; } pr->public_data.anonymity_level = anonymity_level; pr->public_data.priority = priority; pr->public_data.original_priority = priority; pr->public_data.options = options; pr->public_data.type = type; pr->public_data.start_time = GNUNET_TIME_absolute_get (); pr->sender_pid = sender_pid; pr->origin_pid = origin_pid; pr->rh = rh; pr->rh_cls = rh_cls; GNUNET_assert ((sender_pid != 0) || (0 == (options & GSF_PRO_FORWARD_ONLY))); if (ttl >= 0) pr->public_data.ttl = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, (uint32_t) ttl)); else pr->public_data.ttl = GNUNET_TIME_absolute_subtract (pr->public_data.start_time, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, (uint32_t) (-ttl))); if (replies_seen_count > 0) { pr->replies_seen_size = replies_seen_count; pr->replies_seen = GNUNET_malloc (sizeof (GNUNET_HashCode) * pr->replies_seen_size); memcpy (pr->replies_seen, replies_seen, replies_seen_count * sizeof (GNUNET_HashCode)); pr->replies_seen_count = replies_seen_count; } if (NULL != bf_data) { pr->bf = GNUNET_CONTAINER_bloomfilter_init (bf_data, bf_size, GNUNET_CONSTANTS_BLOOMFILTER_K); pr->mingle = mingle; } else if ((replies_seen_count > 0) && (0 != (options & GSF_PRO_BLOOMFILTER_FULL_REFRESH))) { refresh_bloomfilter (pr); } GNUNET_CONTAINER_multihashmap_put (pr_map, query, pr, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); if (0 == (options & GSF_PRO_REQUEST_NEVER_EXPIRES)) { pr->hnode = GNUNET_CONTAINER_heap_insert (requests_by_expiration_heap, pr, pr->public_data.ttl.abs_value); /* make sure we don't track too many requests */ while (GNUNET_CONTAINER_heap_get_size (requests_by_expiration_heap) > max_pending_requests) { dpr = GNUNET_CONTAINER_heap_peek (requests_by_expiration_heap); GNUNET_assert (dpr != NULL); if (pr == dpr) break; /* let the request live briefly... */ if (NULL != dpr->rh) dpr->rh (dpr->rh_cls, GNUNET_BLOCK_EVALUATION_REQUEST_VALID, dpr, UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_ABS, GNUNET_TIME_UNIT_FOREVER_ABS, GNUNET_BLOCK_TYPE_ANY, NULL, 0); GSF_pending_request_cancel_ (dpr, GNUNET_YES); } } GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# Pending requests active"), 1, GNUNET_NO); return pr; } /** * Obtain the public data associated with a pending request * * @param pr pending request * @return associated public data */ struct GSF_PendingRequestData * GSF_pending_request_get_data_ (struct GSF_PendingRequest *pr) { return &pr->public_data; } /** * Test if two pending requests are compatible (would generate * the same query modulo filters and should thus be processed * jointly). * * @param pra a pending request * @param prb another pending request * @return GNUNET_OK if the requests are compatible */ int GSF_pending_request_is_compatible_ (struct GSF_PendingRequest *pra, struct GSF_PendingRequest *prb) { if ((pra->public_data.type != prb->public_data.type) || (0 != memcmp (&pra->public_data.query, &prb->public_data.query, sizeof (GNUNET_HashCode))) || ((pra->public_data.type == GNUNET_BLOCK_TYPE_FS_SBLOCK) && (0 != memcmp (&pra->public_data.namespace, &prb->public_data.namespace, sizeof (GNUNET_HashCode))))) return GNUNET_NO; return GNUNET_OK; } /** * Update a given pending request with additional replies * that have been seen. * * @param pr request to update * @param replies_seen hash codes of replies that we've seen * @param replies_seen_count size of the replies_seen array */ void GSF_pending_request_update_ (struct GSF_PendingRequest *pr, const GNUNET_HashCode * replies_seen, unsigned int replies_seen_count) { unsigned int i; GNUNET_HashCode mhash; if (replies_seen_count + pr->replies_seen_count < pr->replies_seen_count) return; /* integer overflow */ if (0 != (pr->public_data.options & GSF_PRO_BLOOMFILTER_FULL_REFRESH)) { /* we're responsible for the BF, full refresh */ if (replies_seen_count + pr->replies_seen_count > pr->replies_seen_size) GNUNET_array_grow (pr->replies_seen, pr->replies_seen_size, replies_seen_count + pr->replies_seen_count); memcpy (&pr->replies_seen[pr->replies_seen_count], replies_seen, sizeof (GNUNET_HashCode) * replies_seen_count); pr->replies_seen_count += replies_seen_count; refresh_bloomfilter (pr); } else { if (NULL == pr->bf) { /* we're not the initiator, but the initiator did not give us * any bloom-filter, so we need to create one on-the-fly */ pr->mingle = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX); pr->bf = GNUNET_BLOCK_construct_bloomfilter (pr->mingle, replies_seen, replies_seen_count); } else { for (i = 0; i < pr->replies_seen_count; i++) { GNUNET_BLOCK_mingle_hash (&replies_seen[i], pr->mingle, &mhash); GNUNET_CONTAINER_bloomfilter_add (pr->bf, &mhash); } } } } /** * Generate the message corresponding to the given pending request for * transmission to other peers (or at least determine its size). * * @param pr request to generate the message for * @param buf_size number of bytes available in buf * @param buf where to copy the message (can be NULL) * @return number of bytes needed (if > buf_size) or used */ size_t GSF_pending_request_get_message_ (struct GSF_PendingRequest *pr, size_t buf_size, void *buf) { char lbuf[GNUNET_SERVER_MAX_MESSAGE_SIZE]; struct GetMessage *gm; GNUNET_HashCode *ext; size_t msize; unsigned int k; uint32_t bm; uint32_t prio; size_t bf_size; struct GNUNET_TIME_Absolute now; int64_t ttl; int do_route; if (buf_size > 0) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Building request message for `%s' of type %d\n", GNUNET_h2s (&pr->public_data.query), pr->public_data.type); k = 0; bm = 0; do_route = (0 == (pr->public_data.options & GSF_PRO_FORWARD_ONLY)); if ((!do_route) && (pr->sender_pid == 0)) { GNUNET_break (0); do_route = GNUNET_YES; } if (!do_route) { bm |= GET_MESSAGE_BIT_RETURN_TO; k++; } if (GNUNET_BLOCK_TYPE_FS_SBLOCK == pr->public_data.type) { bm |= GET_MESSAGE_BIT_SKS_NAMESPACE; k++; } if (GNUNET_YES == pr->public_data.has_target) { bm |= GET_MESSAGE_BIT_TRANSMIT_TO; k++; } bf_size = GNUNET_CONTAINER_bloomfilter_get_size (pr->bf); msize = sizeof (struct GetMessage) + bf_size + k * sizeof (GNUNET_HashCode); GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE); if (buf_size < msize) return msize; gm = (struct GetMessage *) lbuf; gm->header.type = htons (GNUNET_MESSAGE_TYPE_FS_GET); gm->header.size = htons (msize); gm->type = htonl (pr->public_data.type); if (do_route) prio = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, pr->public_data.priority + 1); else prio = 0; pr->public_data.priority -= prio; gm->priority = htonl (prio); now = GNUNET_TIME_absolute_get (); ttl = (int64_t) (pr->public_data.ttl.abs_value - now.abs_value); gm->ttl = htonl (ttl / 1000); gm->filter_mutator = htonl (pr->mingle); gm->hash_bitmap = htonl (bm); gm->query = pr->public_data.query; ext = (GNUNET_HashCode *) & gm[1]; k = 0; if (!do_route) GNUNET_PEER_resolve (pr->sender_pid, (struct GNUNET_PeerIdentity *) &ext[k++]); if (GNUNET_BLOCK_TYPE_FS_SBLOCK == pr->public_data.type) memcpy (&ext[k++], &pr->public_data.namespace, sizeof (GNUNET_HashCode)); if (GNUNET_YES == pr->public_data.has_target) ext[k++] = pr->public_data.target.hashPubKey; if (pr->bf != NULL) GNUNET_assert (GNUNET_SYSERR != GNUNET_CONTAINER_bloomfilter_get_raw_data (pr->bf, (char *) &ext[k], bf_size)); memcpy (buf, gm, msize); return msize; } /** * Iterator to free pending requests. * * @param cls closure, unused * @param key current key code * @param value value in the hash map (pending request) * @return GNUNET_YES (we should continue to iterate) */ static int clean_request (void *cls, const GNUNET_HashCode * key, void *value) { struct GSF_PendingRequest *pr = value; GSF_LocalLookupContinuation cont; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up pending request for `%s'.\n", GNUNET_h2s (key)); if (NULL != (cont = pr->llc_cont)) { pr->llc_cont = NULL; cont (pr->llc_cont_cls, pr, pr->local_result); } GSF_plan_notify_request_done_ (pr); GNUNET_free_non_null (pr->replies_seen); if (NULL != pr->bf) { GNUNET_CONTAINER_bloomfilter_free (pr->bf); pr->bf = NULL; } GNUNET_PEER_change_rc (pr->sender_pid, -1); pr->sender_pid = 0; GNUNET_PEER_change_rc (pr->origin_pid, -1); pr->origin_pid = 0; if (NULL != pr->hnode) { GNUNET_CONTAINER_heap_remove_node (pr->hnode); pr->hnode = NULL; } if (NULL != pr->qe) { GNUNET_DATASTORE_cancel (pr->qe); pr->qe = NULL; } if (NULL != pr->gh) { GNUNET_DHT_get_stop (pr->gh); pr->gh = NULL; } if (GNUNET_SCHEDULER_NO_TASK != pr->warn_task) { GNUNET_SCHEDULER_cancel (pr->warn_task); pr->warn_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (pr_map, &pr->public_data.query, pr)); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# Pending requests active"), -1, GNUNET_NO); GNUNET_free (pr); return GNUNET_YES; } /** * Explicitly cancel a pending request. * * @param pr request to cancel * @param full_cleanup fully purge the request */ void GSF_pending_request_cancel_ (struct GSF_PendingRequest *pr, int full_cleanup) { GSF_LocalLookupContinuation cont; if (NULL == pr_map) return; /* already cleaned up! */ if (GNUNET_YES != full_cleanup) { /* make request inactive (we're no longer interested in more results), * but do NOT remove from our data-structures, we still need it there * to prevent the request from looping */ pr->rh = NULL; if (NULL != (cont = pr->llc_cont)) { pr->llc_cont = NULL; cont (pr->llc_cont_cls, pr, pr->local_result); } GSF_plan_notify_request_done_ (pr); if (NULL != pr->qe) { GNUNET_DATASTORE_cancel (pr->qe); pr->qe = NULL; } if (NULL != pr->gh) { GNUNET_DHT_get_stop (pr->gh); pr->gh = NULL; } if (GNUNET_SCHEDULER_NO_TASK != pr->warn_task) { GNUNET_SCHEDULER_cancel (pr->warn_task); pr->warn_task = GNUNET_SCHEDULER_NO_TASK; } return; } GNUNET_assert (GNUNET_YES == clean_request (NULL, &pr->public_data.query, pr)); } /** * Iterate over all pending requests. * * @param it function to call for each request * @param cls closure for it */ void GSF_iterate_pending_requests_ (GSF_PendingRequestIterator it, void *cls) { GNUNET_CONTAINER_multihashmap_iterate (pr_map, (GNUNET_CONTAINER_HashMapIterator) it, cls); } /** * Closure for "process_reply" function. */ struct ProcessReplyClosure { /** * The data for the reply. */ const void *data; /** * Who gave us this reply? NULL for local host (or DHT) */ struct GSF_ConnectedPeer *sender; /** * When the reply expires. */ struct GNUNET_TIME_Absolute expiration; /** * Size of data. */ size_t size; /** * Type of the block. */ enum GNUNET_BLOCK_Type type; /** * How much was this reply worth to us? */ uint32_t priority; /** * Anonymity requirements for this reply. */ uint32_t anonymity_level; /** * Evaluation result (returned). */ enum GNUNET_BLOCK_EvaluationResult eval; /** * Did we find a matching request? */ int request_found; }; /** * Update the performance data for the sender (if any) since * the sender successfully answered one of our queries. * * @param prq information about the sender * @param pr request that was satisfied */ static void update_request_performance_data (struct ProcessReplyClosure *prq, struct GSF_PendingRequest *pr) { if (prq->sender == NULL) return; GSF_peer_update_performance_ (prq->sender, pr->public_data.start_time, prq->priority); } /** * We have received a reply; handle it! * * @param cls response (struct ProcessReplyClosure) * @param key our query * @param value value in the hash map (info about the query) * @return GNUNET_YES (we should continue to iterate) */ static int process_reply (void *cls, const GNUNET_HashCode * key, void *value) { struct ProcessReplyClosure *prq = cls; struct GSF_PendingRequest *pr = value; GNUNET_HashCode chash; struct GNUNET_TIME_Absolute last_transmission; if (NULL == pr->rh) return GNUNET_YES; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Matched result (type %u) for query `%s' with pending request\n", (unsigned int) prq->type, GNUNET_h2s (key)); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# replies received and matched"), 1, GNUNET_NO); prq->eval = GNUNET_BLOCK_evaluate (GSF_block_ctx, prq->type, key, &pr->bf, pr->mingle, &pr->public_data.namespace, (prq->type == GNUNET_BLOCK_TYPE_FS_SBLOCK) ? sizeof (GNUNET_HashCode) : 0, prq->data, prq->size); switch (prq->eval) { case GNUNET_BLOCK_EVALUATION_OK_MORE: update_request_performance_data (prq, pr); break; case GNUNET_BLOCK_EVALUATION_OK_LAST: /* short cut: stop processing early, no BF-update, etc. */ update_request_performance_data (prq, pr); GNUNET_LOAD_update (GSF_rt_entry_lifetime, GNUNET_TIME_absolute_get_duration (pr-> public_data.start_time).rel_value); if (!GSF_request_plan_reference_get_last_transmission_ (pr->public_data.rpr_head, prq->sender, &last_transmission)) last_transmission.abs_value = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value; /* pass on to other peers / local clients */ pr->rh (pr->rh_cls, prq->eval, pr, prq->anonymity_level, prq->expiration, last_transmission, prq->type, prq->data, prq->size); return GNUNET_YES; case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE: GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# duplicate replies discarded (bloomfilter)"), 1, GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Duplicate response, discarding.\n"); return GNUNET_YES; /* duplicate */ case GNUNET_BLOCK_EVALUATION_RESULT_INVALID: return GNUNET_YES; /* wrong namespace */ case GNUNET_BLOCK_EVALUATION_REQUEST_VALID: GNUNET_break (0); return GNUNET_YES; case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID: GNUNET_break (0); return GNUNET_YES; case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported block type %u\n"), prq->type); return GNUNET_NO; } /* update bloomfilter */ GNUNET_CRYPTO_hash (prq->data, prq->size, &chash); GSF_pending_request_update_ (pr, &chash, 1); if (NULL == prq->sender) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found result for query `%s' in local datastore\n", GNUNET_h2s (key)); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# results found locally"), 1, GNUNET_NO); } else { GSF_dht_lookup_ (pr); } prq->priority += pr->public_data.original_priority; pr->public_data.priority = 0; pr->public_data.original_priority = 0; pr->public_data.results_found++; prq->request_found = GNUNET_YES; /* finally, pass on to other peer / local client */ if (!GSF_request_plan_reference_get_last_transmission_ (pr->public_data.rpr_head, prq->sender, &last_transmission)) last_transmission.abs_value = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value; pr->rh (pr->rh_cls, prq->eval, pr, prq->anonymity_level, prq->expiration, last_transmission, prq->type, prq->data, prq->size); return GNUNET_YES; } /** * Context for the 'put_migration_continuation'. */ struct PutMigrationContext { /** * Start time for the operation. */ struct GNUNET_TIME_Absolute start; /** * Request origin. */ struct GNUNET_PeerIdentity origin; /** * GNUNET_YES if we had a matching request for this block, * GNUNET_NO if not. */ int requested; }; /** * Continuation called to notify client about result of the * operation. * * @param cls closure * @param success GNUNET_SYSERR on failure * @param min_expiration minimum expiration time required for content to be stored * @param msg NULL on success, otherwise an error message */ static void put_migration_continuation (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) { struct PutMigrationContext *pmc = cls; struct GSF_ConnectedPeer *cp; struct GNUNET_TIME_Relative mig_pause; struct GSF_PeerPerformanceData *ppd; if (NULL != datastore_put_load) { if (GNUNET_SYSERR != success) { GNUNET_LOAD_update (datastore_put_load, GNUNET_TIME_absolute_get_duration (pmc->start).rel_value); } else { /* on queue failure / timeout, increase the put load dramatically */ GNUNET_LOAD_update (datastore_put_load, GNUNET_TIME_UNIT_MINUTES.rel_value); } } cp = GSF_peer_get_ (&pmc->origin); if (GNUNET_OK == success) { if (NULL != cp) { ppd = GSF_get_peer_performance_data_ (cp); ppd->migration_delay.rel_value /= 2; } GNUNET_free (pmc); return; } if ( (GNUNET_NO == success) && (GNUNET_NO == pmc->requested) && (NULL != cp) ) { ppd = GSF_get_peer_performance_data_ (cp); if (min_expiration.abs_value > 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking to stop migration for %llu ms because datastore is full\n", (unsigned long long) GNUNET_TIME_absolute_get_remaining (min_expiration).rel_value); GSF_block_peer_migration_ (cp, min_expiration); } else { ppd->migration_delay = GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_SECONDS, ppd->migration_delay); ppd->migration_delay = GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_HOURS, ppd->migration_delay); mig_pause.rel_value = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, ppd->migration_delay.rel_value); ppd->migration_delay = GNUNET_TIME_relative_multiply (ppd->migration_delay, 2); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Replicated content already exists locally, asking to stop migration for %llu ms\n", (unsigned long long) mig_pause.rel_value); GSF_block_peer_migration_ (cp, GNUNET_TIME_relative_to_absolute (mig_pause)); } } GNUNET_free (pmc); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# Datastore `PUT' failures"), 1, GNUNET_NO); } /** * Test if the DATABASE (PUT) load on this peer is too high * to even consider processing the query at * all. * * @return GNUNET_YES if the load is too high to do anything (load high) * GNUNET_NO to process normally (load normal or low) */ static int test_put_load_too_high (uint32_t priority) { double ld; if (NULL == datastore_put_load) return GNUNET_NO; if (GNUNET_LOAD_get_average (datastore_put_load) < 50) return GNUNET_NO; /* very fast */ ld = GNUNET_LOAD_get_load (datastore_put_load); if (ld < 2.0 * (1 + priority)) return GNUNET_NO; GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# storage requests dropped due to high load"), 1, GNUNET_NO); return GNUNET_YES; } /** * Iterator called on each result obtained for a DHT * operation that expects a reply * * @param cls closure * @param exp when will this value expire * @param key key of the result * @param get_path peers on reply path (or NULL if not recorded) * @param get_path_length number of entries in get_path * @param put_path peers on the PUT path (or NULL if not recorded) * @param put_path_length number of entries in get_path * @param type type of the result * @param size number of bytes in data * @param data pointer to the result data */ static void handle_dht_reply (void *cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int put_path_length, enum GNUNET_BLOCK_Type type, size_t size, const void *data) { struct GSF_PendingRequest *pr = cls; struct ProcessReplyClosure prq; struct PutMigrationContext *pmc; GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# Replies received from DHT"), 1, GNUNET_NO); memset (&prq, 0, sizeof (prq)); prq.data = data; prq.expiration = exp; /* do not allow migrated content to live longer than 1 year */ prq.expiration = GNUNET_TIME_absolute_min (GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_YEARS), prq.expiration); prq.size = size; prq.type = type; process_reply (&prq, key, pr); if ((GNUNET_YES == active_to_migration) && (GNUNET_NO == test_put_load_too_high (prq.priority))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Replicating result for query `%s' with priority %u\n", GNUNET_h2s (key), prq.priority); pmc = GNUNET_malloc (sizeof (struct PutMigrationContext)); pmc->start = GNUNET_TIME_absolute_get (); pmc->requested = GNUNET_YES; if (NULL == GNUNET_DATASTORE_put (GSF_dsh, 0, key, size, data, type, prq.priority, 1 /* anonymity */ , 0 /* replication */ , exp, 1 + prq.priority, MAX_DATASTORE_QUEUE, GNUNET_CONSTANTS_SERVICE_TIMEOUT, &put_migration_continuation, pmc)) { put_migration_continuation (pmc, GNUNET_SYSERR, GNUNET_TIME_UNIT_ZERO_ABS, NULL); } } } /** * Consider looking up the data in the DHT (anonymity-level permitting). * * @param pr the pending request to process */ void GSF_dht_lookup_ (struct GSF_PendingRequest *pr) { const void *xquery; size_t xquery_size; struct GNUNET_PeerIdentity pi; char buf[sizeof (GNUNET_HashCode) * 2] GNUNET_ALIGN; if (0 != pr->public_data.anonymity_level) return; if (NULL != pr->gh) { GNUNET_DHT_get_stop (pr->gh); pr->gh = NULL; } xquery = NULL; xquery_size = 0; if (GNUNET_BLOCK_TYPE_FS_SBLOCK == pr->public_data.type) { xquery = buf; memcpy (buf, &pr->public_data.namespace, sizeof (GNUNET_HashCode)); xquery_size = sizeof (GNUNET_HashCode); } if (0 != (pr->public_data.options & GSF_PRO_FORWARD_ONLY)) { GNUNET_assert (0 != pr->sender_pid); GNUNET_PEER_resolve (pr->sender_pid, &pi); memcpy (&buf[xquery_size], &pi, sizeof (struct GNUNET_PeerIdentity)); xquery_size += sizeof (struct GNUNET_PeerIdentity); } pr->gh = GNUNET_DHT_get_start (GSF_dht, pr->public_data.type, &pr->public_data.query, 5 /* DEFAULT_GET_REPLICATION */ , GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, /* FIXME: can no longer pass pr->bf/pr->mingle... */ xquery, xquery_size, &handle_dht_reply, pr); } /** * Task that issues a warning if the datastore lookup takes too long. * * @param cls the 'struct GSF_PendingRequest' * @param tc task context */ static void warn_delay_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GSF_PendingRequest *pr = cls; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Datastore lookup already took %llu ms!\n"), (unsigned long long) GNUNET_TIME_absolute_get_duration (pr->qe_start).rel_value); pr->warn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &warn_delay_task, pr); } /** * Task that issues a warning if the datastore lookup takes too long. * * @param cls the 'struct GSF_PendingRequest' * @param tc task context */ static void odc_warn_delay_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GSF_PendingRequest *pr = cls; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("On-demand lookup already took %llu ms!\n"), (unsigned long long) GNUNET_TIME_absolute_get_duration (pr->qe_start).rel_value); pr->warn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &odc_warn_delay_task, pr); } /** * We're processing (local) results for a search request * from another peer. Pass applicable results to the * peer and if we are done either clean up (operation * complete) or forward to other peers (more results possible). * * @param cls our closure (struct PendingRequest) * @param key key for the content * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param expiration expiration time for the content * @param uid unique identifier for the datum; * maybe 0 if no unique identifier is available */ static void process_local_reply (void *cls, const GNUNET_HashCode * key, size_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct GSF_PendingRequest *pr = cls; GSF_LocalLookupContinuation cont; struct ProcessReplyClosure prq; GNUNET_HashCode query; unsigned int old_rf; GNUNET_SCHEDULER_cancel (pr->warn_task); pr->warn_task = GNUNET_SCHEDULER_NO_TASK; if (NULL != pr->qe) { pr->qe = NULL; if (NULL == key) { GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# Datastore lookups concluded (no results)"), 1, GNUNET_NO); } if (GNUNET_NO == pr->have_first_uid) { pr->first_uid = uid; pr->have_first_uid = 1; } else { if ((uid == pr->first_uid) && (key != NULL)) { GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# Datastore lookups concluded (seen all)"), 1, GNUNET_NO); key = NULL; /* all replies seen! */ } pr->have_first_uid++; if ((pr->have_first_uid > MAX_RESULTS) && (key != NULL)) { GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# Datastore lookups aborted (more than MAX_RESULTS)"), 1, GNUNET_NO); key = NULL; /* all replies seen! */ } } } if (NULL == key) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "No further local responses available.\n"); if ((pr->public_data.type == GNUNET_BLOCK_TYPE_FS_DBLOCK) || (pr->public_data.type == GNUNET_BLOCK_TYPE_FS_IBLOCK)) GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# requested DBLOCK or IBLOCK not found"), 1, GNUNET_NO); goto check_error_and_continue; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received reply for `%s' of type %d with UID %llu from datastore.\n", GNUNET_h2s (key), type, (unsigned long long) uid); if (type == GNUNET_BLOCK_TYPE_FS_ONDEMAND) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found ONDEMAND block, performing on-demand encoding\n"); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# on-demand blocks matched requests"), 1, GNUNET_NO); pr->qe_start = GNUNET_TIME_absolute_get (); pr->warn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &odc_warn_delay_task, pr); if (GNUNET_OK == GNUNET_FS_handle_on_demand_block (key, size, data, type, priority, anonymity, expiration, uid, &process_local_reply, pr)) { GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# on-demand lookups performed successfully"), 1, GNUNET_NO); return; /* we're done */ } GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# on-demand lookups failed"), 1, GNUNET_NO); GNUNET_SCHEDULER_cancel (pr->warn_task); pr->warn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &warn_delay_task, pr); pr->qe = GNUNET_DATASTORE_get_key (GSF_dsh, pr->local_result_offset - 1, &pr->public_data.query, pr->public_data.type == GNUNET_BLOCK_TYPE_FS_DBLOCK ? GNUNET_BLOCK_TYPE_ANY : pr->public_data.type, (0 != (GSF_PRO_PRIORITY_UNLIMITED & pr->public_data.options)) ? UINT_MAX : 1 /* queue priority */ , (0 != (GSF_PRO_PRIORITY_UNLIMITED & pr->public_data.options)) ? UINT_MAX : datastore_queue_size /* max queue size */ , GNUNET_TIME_UNIT_FOREVER_REL, &process_local_reply, pr); if (NULL != pr->qe) return; /* we're done */ GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# Datastore lookups concluded (error queueing)"), 1, GNUNET_NO); goto check_error_and_continue; } old_rf = pr->public_data.results_found; memset (&prq, 0, sizeof (prq)); prq.data = data; prq.expiration = expiration; prq.size = size; if (GNUNET_OK != GNUNET_BLOCK_get_key (GSF_block_ctx, type, data, size, &query)) { GNUNET_break (0); GNUNET_DATASTORE_remove (GSF_dsh, key, size, data, -1, -1, GNUNET_TIME_UNIT_FOREVER_REL, NULL, NULL); pr->qe_start = GNUNET_TIME_absolute_get (); pr->warn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &warn_delay_task, pr); pr->qe = GNUNET_DATASTORE_get_key (GSF_dsh, pr->local_result_offset - 1, &pr->public_data.query, pr->public_data.type == GNUNET_BLOCK_TYPE_FS_DBLOCK ? GNUNET_BLOCK_TYPE_ANY : pr->public_data.type, (0 != (GSF_PRO_PRIORITY_UNLIMITED & pr->public_data.options)) ? UINT_MAX : 1 /* queue priority */ , (0 != (GSF_PRO_PRIORITY_UNLIMITED & pr->public_data.options)) ? UINT_MAX : datastore_queue_size /* max queue size */ , GNUNET_TIME_UNIT_FOREVER_REL, &process_local_reply, pr); if (pr->qe == NULL) { GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# Datastore lookups concluded (error queueing)"), 1, GNUNET_NO); goto check_error_and_continue; } return; } prq.type = type; prq.priority = priority; prq.request_found = GNUNET_NO; prq.anonymity_level = anonymity; if ((old_rf == 0) && (pr->public_data.results_found == 0)) GSF_update_datastore_delay_ (pr->public_data.start_time); process_reply (&prq, key, pr); pr->local_result = prq.eval; if (prq.eval == GNUNET_BLOCK_EVALUATION_OK_LAST) { GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# Datastore lookups concluded (found last result)"), 1, GNUNET_NO); goto check_error_and_continue; } if ((0 == (GSF_PRO_PRIORITY_UNLIMITED & pr->public_data.options)) && ((GNUNET_YES == GSF_test_get_load_too_high_ (0)) || (pr->public_data.results_found > 5 + 2 * pr->public_data.priority))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Load too high, done with request\n"); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# Datastore lookups concluded (load too high)"), 1, GNUNET_NO); goto check_error_and_continue; } pr->qe_start = GNUNET_TIME_absolute_get (); pr->warn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &warn_delay_task, pr); pr->qe = GNUNET_DATASTORE_get_key (GSF_dsh, pr->local_result_offset++, &pr->public_data.query, pr->public_data.type == GNUNET_BLOCK_TYPE_FS_DBLOCK ? GNUNET_BLOCK_TYPE_ANY : pr->public_data.type, (0 != (GSF_PRO_PRIORITY_UNLIMITED & pr-> public_data.options)) ? UINT_MAX : 1 /* queue priority */ , (0 != (GSF_PRO_PRIORITY_UNLIMITED & pr-> public_data.options)) ? UINT_MAX : datastore_queue_size /* max queue size */ , GNUNET_TIME_UNIT_FOREVER_REL, &process_local_reply, pr); /* check if we successfully queued another datastore request; * if so, return, otherwise call our continuation (if we have * any) */ check_error_and_continue: if (NULL != pr->qe) return; if (GNUNET_SCHEDULER_NO_TASK != pr->warn_task) { GNUNET_SCHEDULER_cancel (pr->warn_task); pr->warn_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL == (cont = pr->llc_cont)) return; /* no continuation */ pr->llc_cont = NULL; cont (pr->llc_cont_cls, pr, pr->local_result); } /** * Is the given target a legitimate peer for forwarding the given request? * * @param pr request * @param target * @return GNUNET_YES if this request could be forwarded to the given peer */ int GSF_pending_request_test_target_ (struct GSF_PendingRequest *pr, const struct GNUNET_PeerIdentity *target) { struct GNUNET_PeerIdentity pi; if (0 == pr->origin_pid) return GNUNET_YES; GNUNET_PEER_resolve (pr->origin_pid, &pi); return (0 == memcmp (&pi, target, sizeof (struct GNUNET_PeerIdentity))) ? GNUNET_NO : GNUNET_YES; } /** * Look up the request in the local datastore. * * @param pr the pending request to process * @param cont function to call at the end * @param cont_cls closure for cont */ void GSF_local_lookup_ (struct GSF_PendingRequest *pr, GSF_LocalLookupContinuation cont, void *cont_cls) { GNUNET_assert (NULL == pr->gh); GNUNET_assert (NULL == pr->llc_cont); pr->llc_cont = cont; pr->llc_cont_cls = cont_cls; pr->qe_start = GNUNET_TIME_absolute_get (); pr->warn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &warn_delay_task, pr); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# Datastore lookups initiated"), 1, GNUNET_NO); pr->qe = GNUNET_DATASTORE_get_key (GSF_dsh, pr->local_result_offset++, &pr->public_data.query, pr->public_data.type == GNUNET_BLOCK_TYPE_FS_DBLOCK ? GNUNET_BLOCK_TYPE_ANY : pr->public_data.type, (0 != (GSF_PRO_PRIORITY_UNLIMITED & pr-> public_data.options)) ? UINT_MAX : 1 /* queue priority */ , (0 != (GSF_PRO_PRIORITY_UNLIMITED & pr-> public_data.options)) ? UINT_MAX : datastore_queue_size /* max queue size */ , GNUNET_TIME_UNIT_FOREVER_REL, &process_local_reply, pr); if (NULL != pr->qe) return; GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# Datastore lookups concluded (error queueing)"), 1, GNUNET_NO); GNUNET_SCHEDULER_cancel (pr->warn_task); pr->warn_task = GNUNET_SCHEDULER_NO_TASK; pr->llc_cont = NULL; if (NULL != cont) cont (cont_cls, pr, pr->local_result); } /** * Handle P2P "CONTENT" message. Checks that the message is * well-formed and then checks if there are any pending requests for * this content and possibly passes it on (to local clients or other * peers). Does NOT perform migration (content caching at this peer). * * @param cp the other peer involved (sender or receiver, NULL * for loopback messages where we are both sender and receiver) * @param message the actual message * @return GNUNET_OK if the message was well-formed, * GNUNET_SYSERR if the message was malformed (close connection, * do not cache under any circumstances) */ int GSF_handle_p2p_content_ (struct GSF_ConnectedPeer *cp, const struct GNUNET_MessageHeader *message) { const struct PutMessage *put; uint16_t msize; size_t dsize; enum GNUNET_BLOCK_Type type; struct GNUNET_TIME_Absolute expiration; GNUNET_HashCode query; struct ProcessReplyClosure prq; struct GNUNET_TIME_Relative block_time; double putl; struct PutMigrationContext *pmc; msize = ntohs (message->size); if (msize < sizeof (struct PutMessage)) { GNUNET_break_op (0); return GNUNET_SYSERR; } put = (const struct PutMessage *) message; dsize = msize - sizeof (struct PutMessage); type = ntohl (put->type); expiration = GNUNET_TIME_absolute_ntoh (put->expiration); /* do not allow migrated content to live longer than 1 year */ expiration = GNUNET_TIME_absolute_min (GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_YEARS), expiration); if (type == GNUNET_BLOCK_TYPE_FS_ONDEMAND) return GNUNET_SYSERR; if (GNUNET_OK != GNUNET_BLOCK_get_key (GSF_block_ctx, type, &put[1], dsize, &query)) { GNUNET_break_op (0); return GNUNET_SYSERR; } GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# GAP PUT messages received"), 1, GNUNET_NO); /* now, lookup 'query' */ prq.data = (const void *) &put[1]; if (NULL != cp) prq.sender = cp; else prq.sender = NULL; prq.size = dsize; prq.type = type; prq.expiration = expiration; prq.priority = 0; prq.anonymity_level = UINT32_MAX; prq.request_found = GNUNET_NO; GNUNET_CONTAINER_multihashmap_get_multiple (pr_map, &query, &process_reply, &prq); if (NULL != cp) { GSF_connected_peer_change_preference_ (cp, CONTENT_BANDWIDTH_VALUE + 1000 * prq.priority); GSF_get_peer_performance_data_ (cp)->trust += prq.priority; } if ((GNUNET_YES == active_to_migration) && (GNUNET_NO == test_put_load_too_high (prq.priority))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Replicating result for query `%s' with priority %u\n", GNUNET_h2s (&query), prq.priority); pmc = GNUNET_malloc (sizeof (struct PutMigrationContext)); pmc->start = GNUNET_TIME_absolute_get (); pmc->requested = prq.request_found; GNUNET_assert (0 != GSF_get_peer_performance_data_ (cp)->pid); GNUNET_PEER_resolve (GSF_get_peer_performance_data_ (cp)->pid, &pmc->origin); if (NULL == GNUNET_DATASTORE_put (GSF_dsh, 0, &query, dsize, &put[1], type, prq.priority, 1 /* anonymity */ , 0 /* replication */ , expiration, 1 + prq.priority, MAX_DATASTORE_QUEUE, GNUNET_CONSTANTS_SERVICE_TIMEOUT, &put_migration_continuation, pmc)) { put_migration_continuation (pmc, GNUNET_SYSERR, GNUNET_TIME_UNIT_ZERO_ABS, NULL); } } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Choosing not to keep content `%s' (%d/%d)\n", GNUNET_h2s (&query), active_to_migration, test_put_load_too_high (prq.priority)); } putl = GNUNET_LOAD_get_load (datastore_put_load); if ((NULL != (cp = prq.sender)) && (GNUNET_NO == prq.request_found) && ((GNUNET_YES != active_to_migration) || (putl > 2.5 * (1 + prq.priority)))) { if (GNUNET_YES != active_to_migration) putl = 1.0 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 5); block_time = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 5000 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, (unsigned int) (60000 * putl * putl))); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking to stop migration for %llu ms because of load %f and events %d/%d\n", (unsigned long long) block_time.rel_value, putl, active_to_migration, (GNUNET_NO == prq.request_found)); GSF_block_peer_migration_ (cp, GNUNET_TIME_relative_to_absolute (block_time)); } return GNUNET_OK; } /** * Setup the subsystem. */ void GSF_pending_request_init_ () { unsigned long long bps; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (GSF_cfg, "fs", "MAX_PENDING_REQUESTS", &max_pending_requests)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Configuration fails to specify `%s', assuming default value."), "MAX_PENDING_REQUESTS"); } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_size (GSF_cfg, "ats", "WAN_QUOTA_OUT", &bps)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Configuration fails to specify `%s', assuming default value."), "WAN_QUOTA_OUT"); bps = 65536; } /* queue size should be #queries we can have pending and satisfy within * a carry interval: */ datastore_queue_size = bps * GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S / DBLOCK_SIZE; active_to_migration = GNUNET_CONFIGURATION_get_value_yesno (GSF_cfg, "FS", "CONTENT_CACHING"); datastore_put_load = GNUNET_LOAD_value_init (DATASTORE_LOAD_AUTODECLINE); pr_map = GNUNET_CONTAINER_multihashmap_create (32 * 1024); requests_by_expiration_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); } /** * Shutdown the subsystem. */ void GSF_pending_request_done_ () { GNUNET_CONTAINER_multihashmap_iterate (pr_map, &clean_request, NULL); GNUNET_CONTAINER_multihashmap_destroy (pr_map); pr_map = NULL; GNUNET_CONTAINER_heap_destroy (requests_by_expiration_heap); requests_by_expiration_heap = NULL; GNUNET_LOAD_value_free (datastore_put_load); datastore_put_load = NULL; } /* end of gnunet-service-fs_pr.c */ gnunet-0.9.3/src/fs/gnunet-service-fs_pe.c0000644000175000017500000005534211760502551015352 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-service-fs_pe.c * @brief API to manage query plan * @author Christian Grothoff */ #include "platform.h" #include "gnunet-service-fs.h" #include "gnunet-service-fs_cp.h" #include "gnunet-service-fs_pe.h" #include "gnunet-service-fs_pr.h" /** * List of GSF_PendingRequests this request plan * participates with. */ struct PendingRequestList; /** * Transmission plan for a peer. */ struct PeerPlan; /** * DLL of request plans a particular pending request is * involved with. */ struct GSF_RequestPlanReference { /** * This is a doubly-linked list. */ struct GSF_RequestPlanReference *next; /** * This is a doubly-linked list. */ struct GSF_RequestPlanReference *prev; /** * Associated request plan. */ struct GSF_RequestPlan *rp; /** * Corresponding PendingRequestList. */ struct PendingRequestList *prl; }; /** * List of GSF_PendingRequests this request plan * participates with. */ struct PendingRequestList { /** * This is a doubly-linked list. */ struct PendingRequestList *next; /** * This is a doubly-linked list. */ struct PendingRequestList *prev; /** * Associated pending request. */ struct GSF_PendingRequest *pr; /** * Corresponding GSF_RequestPlanReference. */ struct GSF_RequestPlanReference *rpr; }; /** * Information we keep per request per peer. This is a doubly-linked * list (with head and tail in the 'struct GSF_PendingRequestData') * with one entry in each heap of each 'struct PeerPlan'. Each * entry tracks information relevant for this request and this peer. */ struct GSF_RequestPlan { /** * This is a doubly-linked list. */ struct GSF_RequestPlan *next; /** * This is a doubly-linked list. */ struct GSF_RequestPlan *prev; /** * Heap node associated with this request and this peer. */ struct GNUNET_CONTAINER_HeapNode *hn; /** * The transmission plan for a peer that this request is associated with. */ struct PeerPlan *pp; /** * Head of list of associated pending requests. */ struct PendingRequestList *prl_head; /** * Tail of list of associated pending requests. */ struct PendingRequestList *prl_tail; /** * Earliest time we'd be happy to (re)transmit this request. */ struct GNUNET_TIME_Absolute earliest_transmission; /** * When was the last time we transmitted this request to this peer? 0 for never. */ struct GNUNET_TIME_Absolute last_transmission; /** * Current priority for this request for this target. */ uint64_t priority; /** * How often did we transmit this request to this peer? */ unsigned int transmission_counter; }; /** * Transmission plan for a peer. */ struct PeerPlan { /** * Heap with pending queries (struct GSF_RequestPlan), higher weights mean higher priority. */ struct GNUNET_CONTAINER_Heap *priority_heap; /** * Heap with pending queries (struct GSF_RequestPlan), by transmission time, lowest first. */ struct GNUNET_CONTAINER_Heap *delay_heap; /** * Map of queries to plan entries. All entries in the priority_heap or delay_heap * should be in the plan map. Note that it IS possible for the plan map to have * multiple entries for the same query. */ struct GNUNET_CONTAINER_MultiHashMap *plan_map; /** * Current transmission request handle. */ struct GSF_PeerTransmitHandle *pth; /** * Peer for which this is the plan. */ struct GSF_ConnectedPeer *cp; /** * Current task for executing the plan. */ GNUNET_SCHEDULER_TaskIdentifier task; }; /** * Hash map from peer identities to PeerPlans. */ static struct GNUNET_CONTAINER_MultiHashMap *plans; /** * Sum of all transmission counters (equals total delay for all plan entries). */ static unsigned long long total_delay; /** * Number of plan entries. */ static unsigned long long plan_count; /** * Return the query (key in the plan_map) for the given request plan. * * @param rp a request plan * @return the associated query */ static const GNUNET_HashCode * get_rp_key (struct GSF_RequestPlan *rp) { return &GSF_pending_request_get_data_ (rp->prl_head->pr)->query; } /** * Figure out when and how to transmit to the given peer. * * @param cls the 'struct GSF_ConnectedPeer' for transmission * @param tc scheduler context */ static void schedule_peer_transmission (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Insert the given request plan into the heap with the appropriate weight. * * @param pp associated peer's plan * @param rp request to plan */ static void plan (struct PeerPlan *pp, struct GSF_RequestPlan *rp) { #define N ((double)128.0) /** * Running average delay we currently impose. */ static double avg_delay; struct GSF_PendingRequestData *prd; struct GNUNET_TIME_Relative delay; GNUNET_assert (rp->pp == pp); GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# average retransmission delay (ms)"), total_delay * 1000LL / plan_count, GNUNET_NO); prd = GSF_pending_request_get_data_ (rp->prl_head->pr); if (rp->transmission_counter < 8) delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, rp->transmission_counter); else if (rp->transmission_counter < 32) delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 8 + (1LL << (rp->transmission_counter - 8))); else delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 8 + (1LL << 24)); delay.rel_value = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, delay.rel_value + 1); /* Add 0.01 to avg_delay to avoid division-by-zero later */ avg_delay = (((avg_delay * (N - 1.0)) + delay.rel_value) / N) + 0.01; /* * For the priority, we need to consider a few basic rules: * 1) if we just started requesting (delay is small), we should * virtually always have a priority of zero. * 2) for requests with average latency, our priority should match * the average priority observed on the network * 3) even the longest-running requests should not be WAY out of * the observed average (thus we bound by a factor of 2) * 4) we add +1 to the observed average priority to avoid everyone * staying put at zero (2 * 0 = 0...). * * Using the specific calculation below, we get: * * delay = 0 => priority = 0; * delay = avg delay => priority = running-average-observed-priority; * delay >> avg_delay => priority = 2 * running-average-observed-priority; * * which satisfies all of the rules above. * * Note: M_PI_4 = PI/4 = arctan(1) */ rp->priority = round ((GSF_current_priorities + 1.0) * atan (delay.rel_value / avg_delay)) / M_PI_4; /* Note: usage of 'round' and 'atan' requires -lm */ if (rp->transmission_counter != 0) delay.rel_value += TTL_DECREMENT; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Considering (re)transmission number %u in %llu ms\n", (unsigned int) rp->transmission_counter, (unsigned long long) delay.rel_value); rp->earliest_transmission = GNUNET_TIME_relative_to_absolute (delay); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Earliest (re)transmission for `%s' in %us\n", GNUNET_h2s (&prd->query), rp->transmission_counter); GNUNET_assert (rp->hn == NULL); if (GNUNET_TIME_absolute_get_remaining (rp->earliest_transmission).rel_value == 0) rp->hn = GNUNET_CONTAINER_heap_insert (pp->priority_heap, rp, rp->priority); else rp->hn = GNUNET_CONTAINER_heap_insert (pp->delay_heap, rp, rp->earliest_transmission.abs_value); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains_value (pp->plan_map, get_rp_key (rp), rp)); if (GNUNET_SCHEDULER_NO_TASK != pp->task) GNUNET_SCHEDULER_cancel (pp->task); pp->task = GNUNET_SCHEDULER_add_now (&schedule_peer_transmission, pp); #undef N } /** * Get the pending request with the highest TTL from the given plan. * * @param rp plan to investigate * @return pending request with highest TTL */ struct GSF_PendingRequest * get_latest (const struct GSF_RequestPlan *rp) { struct GSF_PendingRequest *ret; struct PendingRequestList *prl; prl = rp->prl_head; ret = prl->pr; prl = prl->next; while (NULL != prl) { if (GSF_pending_request_get_data_ (prl->pr)->ttl.abs_value > GSF_pending_request_get_data_ (ret)->ttl.abs_value) ret = prl->pr; prl = prl->next; } return ret; } /** * Function called to get a message for transmission. * * @param cls closure * @param buf_size number of bytes available in buf * @param buf where to copy the message, NULL on error (peer disconnect) * @return number of bytes copied to 'buf', can be 0 (without indicating an error) */ static size_t transmit_message_callback (void *cls, size_t buf_size, void *buf) { struct PeerPlan *pp = cls; struct GSF_RequestPlan *rp; size_t msize; pp->pth = NULL; if (NULL == buf) { /* failed, try again... */ pp->task = GNUNET_SCHEDULER_add_now (&schedule_peer_transmission, pp); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# transmission failed (core has no bandwidth)"), 1, GNUNET_NO); return 0; } rp = GNUNET_CONTAINER_heap_peek (pp->priority_heap); if (NULL == rp) { pp->task = GNUNET_SCHEDULER_add_now (&schedule_peer_transmission, pp); return 0; } msize = GSF_pending_request_get_message_ (get_latest (rp), buf_size, buf); if (msize > buf_size) { /* buffer to small (message changed), try again */ pp->task = GNUNET_SCHEDULER_add_now (&schedule_peer_transmission, pp); return 0; } /* remove from root, add again elsewhere... */ GNUNET_assert (rp == GNUNET_CONTAINER_heap_remove_root (pp->priority_heap)); rp->hn = NULL; rp->last_transmission = GNUNET_TIME_absolute_get (); rp->transmission_counter++; total_delay++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing plan %p executed %u times, planning retransmission\n", rp, rp->transmission_counter); plan (pp, rp); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# query messages sent to other peers"), 1, GNUNET_NO); return msize; } /** * Figure out when and how to transmit to the given peer. * * @param cls the 'struct PeerPlan' * @param tc scheduler context */ static void schedule_peer_transmission (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerPlan *pp = cls; struct GSF_RequestPlan *rp; size_t msize; struct GNUNET_TIME_Relative delay; pp->task = GNUNET_SCHEDULER_NO_TASK; if (pp->pth != NULL) { GSF_peer_transmit_cancel_ (pp->pth); pp->pth = NULL; } /* move ready requests to priority queue */ while ((NULL != (rp = GNUNET_CONTAINER_heap_peek (pp->delay_heap))) && (GNUNET_TIME_absolute_get_remaining (rp->earliest_transmission).rel_value == 0)) { GNUNET_assert (rp == GNUNET_CONTAINER_heap_remove_root (pp->delay_heap)); rp->hn = GNUNET_CONTAINER_heap_insert (pp->priority_heap, rp, rp->priority); } if (0 == GNUNET_CONTAINER_heap_get_size (pp->priority_heap)) { /* priority heap (still) empty, check for delay... */ rp = GNUNET_CONTAINER_heap_peek (pp->delay_heap); if (NULL == rp) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No active requests for plan %p.\n", pp); return; /* both queues empty */ } delay = GNUNET_TIME_absolute_get_remaining (rp->earliest_transmission); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sleeping for %llu ms before retrying requests on plan %p.\n", (unsigned long long) delay.rel_value, pp); GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# delay heap timeout"), delay.rel_value, GNUNET_NO); pp->task = GNUNET_SCHEDULER_add_delayed (delay, &schedule_peer_transmission, pp); return; } GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# query plans executed"), 1, GNUNET_NO); /* process from priority heap */ rp = GNUNET_CONTAINER_heap_peek (pp->priority_heap); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing query plan %p\n", rp); GNUNET_assert (NULL != rp); msize = GSF_pending_request_get_message_ (get_latest (rp), 0, NULL); pp->pth = GSF_peer_transmit_ (pp->cp, GNUNET_YES, rp->priority, GNUNET_TIME_UNIT_FOREVER_REL, msize, &transmit_message_callback, pp); GNUNET_assert (NULL != pp->pth); } /** * Closure for 'merge_pr'. */ struct MergeContext { struct GSF_PendingRequest *pr; int merged; }; /** * Iterator that checks if an equivalent request is already * present for this peer. * * @param cls closure * @param query the query * @param element request plan stored at the node * @return GNUNET_YES if we should continue to iterate, * GNUNET_NO if not (merge success) */ static int merge_pr (void *cls, const GNUNET_HashCode * query, void *element) { struct MergeContext *mpr = cls; struct GSF_RequestPlan *rp = element; struct GSF_PendingRequestData *prd; struct GSF_RequestPlanReference *rpr; struct PendingRequestList *prl; struct GSF_PendingRequest *latest; if (GNUNET_OK != GSF_pending_request_is_compatible_ (mpr->pr, rp->prl_head->pr)) return GNUNET_YES; /* merge new request with existing request plan */ rpr = GNUNET_malloc (sizeof (struct GSF_RequestPlanReference)); prl = GNUNET_malloc (sizeof (struct PendingRequestList)); rpr->rp = rp; rpr->prl = prl; prl->rpr = rpr; prl->pr = mpr->pr; prd = GSF_pending_request_get_data_ (mpr->pr); GNUNET_CONTAINER_DLL_insert (prd->rpr_head, prd->rpr_tail, rpr); GNUNET_CONTAINER_DLL_insert (rp->prl_head, rp->prl_tail, prl); mpr->merged = GNUNET_YES; GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# requests merged"), 1, GNUNET_NO); latest = get_latest (rp); if (GSF_pending_request_get_data_ (latest)->ttl.abs_value < prd->ttl.abs_value) { GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# requests refreshed"), 1, GNUNET_NO); rp->transmission_counter = 0; /* reset */ } return GNUNET_NO; } /** * Create a new query plan entry. * * @param cp peer with the entry * @param pr request with the entry */ void GSF_plan_add_ (struct GSF_ConnectedPeer *cp, struct GSF_PendingRequest *pr) { struct GNUNET_PeerIdentity id; struct PeerPlan *pp; struct GSF_PendingRequestData *prd; struct GSF_RequestPlan *rp; struct GSF_RequestPlanReference *rpr; struct PendingRequestList *prl; struct MergeContext mpc; GNUNET_assert (NULL != cp); GSF_connected_peer_get_identity_ (cp, &id); pp = GNUNET_CONTAINER_multihashmap_get (plans, &id.hashPubKey); if (NULL == pp) { pp = GNUNET_malloc (sizeof (struct PeerPlan)); pp->plan_map = GNUNET_CONTAINER_multihashmap_create (128); pp->priority_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX); pp->delay_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); pp->cp = cp; GNUNET_CONTAINER_multihashmap_put (plans, &id.hashPubKey, pp, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); } mpc.merged = GNUNET_NO; mpc.pr = pr; GNUNET_CONTAINER_multihashmap_get_multiple (pp->plan_map, &GSF_pending_request_get_data_ (pr)->query, &merge_pr, &mpc); if (mpc.merged != GNUNET_NO) return; GNUNET_CONTAINER_multihashmap_get_multiple (pp->plan_map, &GSF_pending_request_get_data_ (pr)->query, &merge_pr, &mpc); if (mpc.merged != GNUNET_NO) return; plan_count++; GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# query plan entries"), 1, GNUNET_NO); prd = GSF_pending_request_get_data_ (pr); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Planning transmission of query `%s' to peer `%s'\n", GNUNET_h2s (&prd->query), GNUNET_i2s (&id)); rp = GNUNET_malloc (sizeof (struct GSF_RequestPlan)); rpr = GNUNET_malloc (sizeof (struct GSF_RequestPlanReference)); prl = GNUNET_malloc (sizeof (struct PendingRequestList)); rpr->rp = rp; rpr->prl = prl; prl->rpr = rpr; prl->pr = pr; GNUNET_CONTAINER_DLL_insert (prd->rpr_head, prd->rpr_tail, rpr); GNUNET_CONTAINER_DLL_insert (rp->prl_head, rp->prl_tail, prl); rp->pp = pp; GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_put (pp->plan_map, get_rp_key (rp), rp, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); plan (pp, rp); } /** * Notify the plan about a peer being no longer available; * destroy all entries associated with this peer. * * @param cp connected peer */ void GSF_plan_notify_peer_disconnect_ (const struct GSF_ConnectedPeer *cp) { struct GNUNET_PeerIdentity id; struct PeerPlan *pp; struct GSF_RequestPlan *rp; struct GSF_PendingRequestData *prd; struct PendingRequestList *prl; GSF_connected_peer_get_identity_ (cp, &id); pp = GNUNET_CONTAINER_multihashmap_get (plans, &id.hashPubKey); if (NULL == pp) return; /* nothing was ever planned for this peer */ GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (plans, &id.hashPubKey, pp)); if (NULL != pp->pth) GSF_peer_transmit_cancel_ (pp->pth); if (GNUNET_SCHEDULER_NO_TASK != pp->task) { GNUNET_SCHEDULER_cancel (pp->task); pp->task = GNUNET_SCHEDULER_NO_TASK; } while (NULL != (rp = GNUNET_CONTAINER_heap_remove_root (pp->priority_heap))) { GNUNET_break (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (pp->plan_map, get_rp_key (rp), rp)); while (NULL != (prl = rp->prl_head)) { GNUNET_CONTAINER_DLL_remove (rp->prl_head, rp->prl_tail, prl); prd = GSF_pending_request_get_data_ (prl->pr); GNUNET_CONTAINER_DLL_remove (prd->rpr_head, prd->rpr_tail, prl->rpr); GNUNET_free (prl->rpr); GNUNET_free (prl); } GNUNET_free (rp); } GNUNET_CONTAINER_heap_destroy (pp->priority_heap); while (NULL != (rp = GNUNET_CONTAINER_heap_remove_root (pp->delay_heap))) { GNUNET_break (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (pp->plan_map, get_rp_key (rp), rp)); while (NULL != (prl = rp->prl_head)) { GNUNET_CONTAINER_DLL_remove (rp->prl_head, rp->prl_tail, prl); prd = GSF_pending_request_get_data_ (prl->pr); GNUNET_CONTAINER_DLL_remove (prd->rpr_head, prd->rpr_tail, prl->rpr); GNUNET_free (prl->rpr); GNUNET_free (prl); } GNUNET_free (rp); } GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# query plan entries"), plan_count, GNUNET_NO); GNUNET_CONTAINER_heap_destroy (pp->delay_heap); GNUNET_CONTAINER_multihashmap_destroy (pp->plan_map); GNUNET_free (pp); } /** * Get the last transmission attempt time for the request plan list * referenced by 'rpr_head', that was sent to 'sender' * * @param rpr_head request plan reference list to check. * @param sender the peer that we've sent the request to. * @param result the timestamp to fill. * @return GNUNET_YES if 'result' was changed, GNUNET_NO otherwise. */ int GSF_request_plan_reference_get_last_transmission_ ( struct GSF_RequestPlanReference *rpr_head, struct GSF_ConnectedPeer *sender, struct GNUNET_TIME_Absolute *result) { struct GSF_RequestPlanReference *rpr; for (rpr = rpr_head; rpr; rpr = rpr->next) { if (rpr->rp->pp->cp == sender) { *result = rpr->rp->last_transmission; return GNUNET_YES; } } return GNUNET_NO; } /** * Notify the plan about a request being done; destroy all entries * associated with this request. * * @param pr request that is done */ void GSF_plan_notify_request_done_ (struct GSF_PendingRequest *pr) { struct GSF_RequestPlan *rp; struct GSF_PendingRequestData *prd; struct GSF_RequestPlanReference *rpr; prd = GSF_pending_request_get_data_ (pr); while (NULL != (rpr = prd->rpr_head)) { GNUNET_CONTAINER_DLL_remove (prd->rpr_head, prd->rpr_tail, rpr); rp = rpr->rp; GNUNET_CONTAINER_DLL_remove (rp->prl_head, rp->prl_tail, rpr->prl); if (NULL == rp->prl_head) { GNUNET_CONTAINER_heap_remove_node (rp->hn); plan_count--; GNUNET_break (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (rp->pp->plan_map, &GSF_pending_request_get_data_ (rpr->prl->pr)->query, rp)); GNUNET_free (rp); } GNUNET_free (rpr->prl); GNUNET_free (rpr); } GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# query plan entries"), plan_count, GNUNET_NO); } /** * Initialize plan subsystem. */ void GSF_plan_init () { plans = GNUNET_CONTAINER_multihashmap_create (256); } /** * Shutdown plan subsystem. */ void GSF_plan_done () { GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (plans)); GNUNET_CONTAINER_multihashmap_destroy (plans); } /* end of gnunet-service-fs_pe.h */ gnunet-0.9.3/src/fs/gnunet-service-fs.h0000644000175000017500000001625611760502551014674 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-service-fs.h * @brief shared data structures of gnunet-service-fs.c * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_FS_H #define GNUNET_SERVICE_FS_H #include "gnunet_util_lib.h" #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" #include "gnunet_core_service.h" #include "gnunet_block_lib.h" #include "fs.h" /** * By which amount do we decrement the TTL for simple forwarding / * indirection of the query; in milli-seconds. Set somewhat in * accordance to your network latency (above the time it'll take you * to send a packet and get a reply). */ #define TTL_DECREMENT 5000 /** * At what frequency should our datastore load decrease * automatically (since if we don't use it, clearly the * load must be going down). */ #define DATASTORE_LOAD_AUTODECLINE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250) /** * Only the (mandatory) query is included. */ #define GET_MESSAGE_BIT_QUERY_ONLY 0 /** * The peer identity of a peer waiting for the * reply is included (used if the response * should be transmitted to someone other than * the sender of the GET). */ #define GET_MESSAGE_BIT_RETURN_TO 1 /** * The hash of the public key of the target * namespace is included (for SKS queries). */ #define GET_MESSAGE_BIT_SKS_NAMESPACE 2 /** * The peer identity of a peer that had claimed to have the content * previously is included (can be used if responder-anonymity is not * desired; note that the precursor presumably lacked a direct * connection to the specified peer; still, the receiver is in no way * required to limit forwarding only to the specified peer, it should * only prefer it somewhat if possible). */ #define GET_MESSAGE_BIT_TRANSMIT_TO 4 GNUNET_NETWORK_STRUCT_BEGIN /** * Message sent between peers asking for FS-content. */ struct GetMessage { /** * Message type will be GNUNET_MESSAGE_TYPE_FS_GET. */ struct GNUNET_MessageHeader header; /** * Type of the query (block type). */ uint32_t type GNUNET_PACKED; /** * How important is this request (network byte order) */ uint32_t priority GNUNET_PACKED; /** * Relative time to live in MILLISECONDS (network byte order) */ int32_t ttl GNUNET_PACKED; /** * The content hash should be mutated using this value * before checking against the bloomfilter (used to * get many different filters for the same hash codes). * The number should be in big-endian format when used * for mingling. */ uint32_t filter_mutator GNUNET_PACKED; /** * Which of the optional hash codes are present at the end of the * message? See GET_MESSAGE_BIT_xx constants. For each bit that is * set, an additional GNUNET_HashCode with the respective content * (in order of the bits) will be appended to the end of the GET * message. */ uint32_t hash_bitmap GNUNET_PACKED; /** * Hashcodes of the file(s) we're looking for. * Details depend on the query type. */ GNUNET_HashCode query; /* this is followed by hash codes as specified in the "hash_bitmap"; * after that, an optional bloomfilter (with bits set for replies * that should be suppressed) can be present */ }; /** * Message send by a peer that wants to be excluded * from migration for a while. */ struct MigrationStopMessage { /** * Message type will be * GNUNET_MESSAGE_TYPE_FS_MIGRATION_STOP. */ struct GNUNET_MessageHeader header; /** * Always zero. */ uint32_t reserved GNUNET_PACKED; /** * How long should the block last? */ struct GNUNET_TIME_RelativeNBO duration; }; GNUNET_NETWORK_STRUCT_END /** * A connected peer. */ struct GSF_ConnectedPeer; /** * An active request. */ struct GSF_PendingRequest; /** * A local client. */ struct GSF_LocalClient; /** * Information kept per plan per request ('pe' module). */ struct GSF_RequestPlan; /** * DLL of request plans a particular pending request is * involved with. */ struct GSF_RequestPlanReference; /** * Our connection to the datastore. */ extern struct GNUNET_DATASTORE_Handle *GSF_dsh; /** * Our configuration. */ extern const struct GNUNET_CONFIGURATION_Handle *GSF_cfg; /** * Handle for reporting statistics. */ extern struct GNUNET_STATISTICS_Handle *GSF_stats; /** * Pointer to handle to the core service (points to NULL until we've * connected to it). */ extern struct GNUNET_CORE_Handle *GSF_core; /** * Handle for DHT operations. */ extern struct GNUNET_DHT_Handle *GSF_dht; /** * How long do requests typically stay in the routing table? */ extern struct GNUNET_LOAD_Value *GSF_rt_entry_lifetime; /** * Running average of the observed latency to other peers (round trip). */ extern struct GNUNET_TIME_Relative GSF_avg_latency; /** * Typical priorities we're seeing from other peers right now. Since * most priorities will be zero, this value is the weighted average of * non-zero priorities seen "recently". In order to ensure that new * values do not dramatically change the ratio, values are first * "capped" to a reasonable range (+N of the current value) and then * averaged into the existing value by a ratio of 1:N. Hence * receiving the largest possible priority can still only raise our * "current_priorities" by at most 1. */ extern double GSF_current_priorities; /** * How many query messages have we received 'recently' that * have not yet been claimed as cover traffic? */ extern unsigned int GSF_cover_query_count; /** * How many content messages have we received 'recently' that * have not yet been claimed as cover traffic? */ extern unsigned int GSF_cover_content_count; /** * Our block context. */ extern struct GNUNET_BLOCK_Context *GSF_block_ctx; /** * Are we introducing randomized delays for better anonymity? */ extern int GSF_enable_randomized_delays; /** * Test if the DATABASE (GET) load on this peer is too high * to even consider processing the query at * all. * * @return GNUNET_YES if the load is too high to do anything (load high) * GNUNET_NO to process normally (load normal) * GNUNET_SYSERR to process for free (load low) */ int GSF_test_get_load_too_high_ (uint32_t priority); /** * We've just now completed a datastore request. Update our * datastore load calculations. * * @param start time when the datastore request was issued */ void GSF_update_datastore_delay_ (struct GNUNET_TIME_Absolute start); #endif /* end of gnunet-service-fs.h */ gnunet-0.9.3/src/fs/gnunet-service-fs_cp.c0000644000175000017500000015670111760502551015351 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-service-fs_cp.c * @brief API to handle 'connected peers' * @author Christian Grothoff */ #include "platform.h" #include "gnunet_load_lib.h" #include "gnunet_ats_service.h" #include "gnunet-service-fs.h" #include "gnunet-service-fs_cp.h" #include "gnunet-service-fs_pe.h" #include "gnunet-service-fs_pr.h" #include "gnunet-service-fs_push.h" /** * Ratio for moving average delay calculation. The previous * average goes in with a factor of (n-1) into the calculation. * Must be > 0. */ #define RUNAVG_DELAY_N 16 /** * How often do we flush trust values to disk? */ #define TRUST_FLUSH_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) /** * After how long do we discard a reply? */ #define REPLY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2) /** * Handle to cancel a transmission request. */ struct GSF_PeerTransmitHandle { /** * Kept in a doubly-linked list. */ struct GSF_PeerTransmitHandle *next; /** * Kept in a doubly-linked list. */ struct GSF_PeerTransmitHandle *prev; /** * Handle for an active request for transmission to this * peer, or NULL (if core queue was full). */ struct GNUNET_CORE_TransmitHandle *cth; /** * Time when this transmission request was issued. */ struct GNUNET_TIME_Absolute transmission_request_start_time; /** * Timeout for this request. */ struct GNUNET_TIME_Absolute timeout; /** * Task called on timeout, or 0 for none. */ GNUNET_SCHEDULER_TaskIdentifier timeout_task; /** * Function to call to get the actual message. */ GSF_GetMessageCallback gmc; /** * Peer this request targets. */ struct GSF_ConnectedPeer *cp; /** * Closure for 'gmc'. */ void *gmc_cls; /** * Size of the message to be transmitted. */ size_t size; /** * Set to 1 if we're currently in the process of calling * 'GNUNET_CORE_notify_transmit_ready' (so while cth is * NULL, we should not call notify_transmit_ready for this * handle right now). */ unsigned int cth_in_progress; /** * GNUNET_YES if this is a query, GNUNET_NO for content. */ int is_query; /** * Did we get a reservation already? */ int was_reserved; /** * Priority of this request. */ uint32_t priority; }; /** * Handle for an entry in our delay list. */ struct GSF_DelayedHandle { /** * Kept in a doubly-linked list. */ struct GSF_DelayedHandle *next; /** * Kept in a doubly-linked list. */ struct GSF_DelayedHandle *prev; /** * Peer this transmission belongs to. */ struct GSF_ConnectedPeer *cp; /** * The PUT that was delayed. */ struct PutMessage *pm; /** * Task for the delay. */ GNUNET_SCHEDULER_TaskIdentifier delay_task; /** * Size of the message. */ size_t msize; }; /** * Information per peer and request. */ struct PeerRequest { /** * Handle to generic request. */ struct GSF_PendingRequest *pr; /** * Handle to specific peer. */ struct GSF_ConnectedPeer *cp; /** * Task for asynchronous stopping of this request. */ GNUNET_SCHEDULER_TaskIdentifier kill_task; }; /** * A connected peer. */ struct GSF_ConnectedPeer { /** * Performance data for this peer. */ struct GSF_PeerPerformanceData ppd; /** * Time until when we blocked this peer from migrating * data to us. */ struct GNUNET_TIME_Absolute last_migration_block; /** * Task scheduled to revive migration to this peer. */ GNUNET_SCHEDULER_TaskIdentifier mig_revive_task; /** * Messages (replies, queries, content migration) we would like to * send to this peer in the near future. Sorted by priority, head. */ struct GSF_PeerTransmitHandle *pth_head; /** * Messages (replies, queries, content migration) we would like to * send to this peer in the near future. Sorted by priority, tail. */ struct GSF_PeerTransmitHandle *pth_tail; /** * Messages (replies, queries, content migration) we would like to * send to this peer in the near future. Sorted by priority, head. */ struct GSF_DelayedHandle *delayed_head; /** * Messages (replies, queries, content migration) we would like to * send to this peer in the near future. Sorted by priority, tail. */ struct GSF_DelayedHandle *delayed_tail; /** * Migration stop message in our queue, or NULL if we have none pending. */ struct GSF_PeerTransmitHandle *migration_pth; /** * Context of our GNUNET_ATS_reserve_bandwidth call (or NULL). */ struct GNUNET_ATS_ReservationContext *rc; /** * Task scheduled if we need to retry bandwidth reservation later. */ GNUNET_SCHEDULER_TaskIdentifier rc_delay_task; /** * Active requests from this neighbour, map of query to 'struct PeerRequest'. */ struct GNUNET_CONTAINER_MultiHashMap *request_map; /** * Increase in traffic preference still to be submitted * to the core service for this peer. */ uint64_t inc_preference; /** * Trust rating for this peer on disk. */ uint32_t disk_trust; /** * Which offset in "last_p2p_replies" will be updated next? * (we go round-robin). */ unsigned int last_p2p_replies_woff; /** * Which offset in "last_client_replies" will be updated next? * (we go round-robin). */ unsigned int last_client_replies_woff; /** * Current offset into 'last_request_times' ring buffer. */ unsigned int last_request_times_off; /** * GNUNET_YES if we did successfully reserve 32k bandwidth, * GNUNET_NO if not. */ int did_reserve; }; /** * Map from peer identities to 'struct GSF_ConnectPeer' entries. */ static struct GNUNET_CONTAINER_MultiHashMap *cp_map; /** * Where do we store trust information? */ static char *trustDirectory; /** * Handle to ATS service. */ static struct GNUNET_ATS_PerformanceHandle *ats; /** * Get the filename under which we would store the GNUNET_HELLO_Message * for the given host and protocol. * @return filename of the form DIRECTORY/HOSTID */ static char * get_trust_filename (const struct GNUNET_PeerIdentity *id) { struct GNUNET_CRYPTO_HashAsciiEncoded fil; char *fn; GNUNET_CRYPTO_hash_to_enc (&id->hashPubKey, &fil); GNUNET_asprintf (&fn, "%s%s%s", trustDirectory, DIR_SEPARATOR_STR, &fil); return fn; } /** * Find latency information in 'atsi'. * * @param atsi performance data * @param atsi_count number of records in 'atsi' * @return connection latency */ static struct GNUNET_TIME_Relative get_latency (const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { unsigned int i; for (i = 0; i < atsi_count; i++) if (ntohl (atsi->type) == GNUNET_ATS_QUALITY_NET_DELAY) return GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, ntohl (atsi->value)); return GNUNET_TIME_UNIT_SECONDS; } /** * Update the performance information kept for the given peer. * * @param cp peer record to update * @param atsi transport performance data * @param atsi_count number of records in 'atsi' */ static void update_atsi (struct GSF_ConnectedPeer *cp, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct GNUNET_TIME_Relative latency; latency = get_latency (atsi, atsi_count); GNUNET_LOAD_value_set_decline (cp->ppd.transmission_delay, latency); /* LATER: merge atsi into cp's performance data (if we ever care...) */ } /** * Return the performance data record for the given peer * * @param cp peer to query * @return performance data record for the peer */ struct GSF_PeerPerformanceData * GSF_get_peer_performance_data_ (struct GSF_ConnectedPeer *cp) { return &cp->ppd; } /** * Core is ready to transmit to a peer, get the message. * * @param cls the 'struct GSF_PeerTransmitHandle' of the message * @param size number of bytes core is willing to take * @param buf where to copy the message * @return number of bytes copied to buf */ static size_t peer_transmit_ready_cb (void *cls, size_t size, void *buf); /** * Function called by core upon success or failure of our bandwidth reservation request. * * @param cls the 'struct GSF_ConnectedPeer' of the peer for which we made the request * @param peer identifies the peer * @param amount set to the amount that was actually reserved or unreserved; * either the full requested amount or zero (no partial reservations) * @param res_delay if the reservation could not be satisfied (amount was 0), how * long should the client wait until re-trying? */ static void ats_reserve_callback (void *cls, const struct GNUNET_PeerIdentity *peer, int32_t amount, struct GNUNET_TIME_Relative res_delay); /** * If ready (bandwidth reserved), try to schedule transmission via * core for the given handle. * * @param pth transmission handle to schedule */ static void schedule_transmission (struct GSF_PeerTransmitHandle *pth) { struct GSF_ConnectedPeer *cp; struct GNUNET_PeerIdentity target; if ((NULL != pth->cth) || (0 != pth->cth_in_progress)) return; /* already done */ cp = pth->cp; GNUNET_assert (0 != cp->ppd.pid); GNUNET_PEER_resolve (cp->ppd.pid, &target); if (0 != cp->inc_preference) { GNUNET_ATS_change_preference (ats, &target, GNUNET_ATS_PREFERENCE_BANDWIDTH, (double) cp->inc_preference, GNUNET_ATS_PREFERENCE_END); cp->inc_preference = 0; } if ((GNUNET_YES == pth->is_query) && (GNUNET_YES != pth->was_reserved)) { /* query, need reservation */ if (GNUNET_YES != cp->did_reserve) return; /* not ready */ cp->did_reserve = GNUNET_NO; /* reservation already done! */ pth->was_reserved = GNUNET_YES; cp->rc = GNUNET_ATS_reserve_bandwidth (ats, &target, DBLOCK_SIZE, &ats_reserve_callback, cp); } GNUNET_assert (pth->cth == NULL); pth->cth_in_progress++; pth->cth = GNUNET_CORE_notify_transmit_ready (GSF_core, GNUNET_YES, pth->priority, GNUNET_TIME_absolute_get_remaining (pth->timeout), &target, pth->size, &peer_transmit_ready_cb, pth); GNUNET_assert (0 < pth->cth_in_progress--); } /** * Core is ready to transmit to a peer, get the message. * * @param cls the 'struct GSF_PeerTransmitHandle' of the message * @param size number of bytes core is willing to take * @param buf where to copy the message * @return number of bytes copied to buf */ static size_t peer_transmit_ready_cb (void *cls, size_t size, void *buf) { struct GSF_PeerTransmitHandle *pth = cls; struct GSF_PeerTransmitHandle *pos; struct GSF_ConnectedPeer *cp; size_t ret; GNUNET_assert ((NULL == buf) || (pth->size <= size)); pth->cth = NULL; if (pth->timeout_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (pth->timeout_task); pth->timeout_task = GNUNET_SCHEDULER_NO_TASK; } cp = pth->cp; GNUNET_CONTAINER_DLL_remove (cp->pth_head, cp->pth_tail, pth); if (GNUNET_YES == pth->is_query) { cp->ppd.last_request_times[(cp->last_request_times_off++) % MAX_QUEUE_PER_PEER] = GNUNET_TIME_absolute_get (); GNUNET_assert (0 < cp->ppd.pending_queries--); } else if (GNUNET_NO == pth->is_query) { GNUNET_assert (0 < cp->ppd.pending_replies--); } GNUNET_LOAD_update (cp->ppd.transmission_delay, GNUNET_TIME_absolute_get_duration (pth->transmission_request_start_time).rel_value); ret = pth->gmc (pth->gmc_cls, size, buf); GNUNET_assert (NULL == pth->cth); for (pos = cp->pth_head; pos != NULL; pos = pos->next) { GNUNET_assert (pos != pth); schedule_transmission (pos); } GNUNET_assert (pth->cth == NULL); GNUNET_assert (pth->cth_in_progress == 0); GNUNET_free (pth); return ret; } /** * (re)try to reserve bandwidth from the given peer. * * @param cls the 'struct GSF_ConnectedPeer' to reserve from * @param tc scheduler context */ static void retry_reservation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GSF_ConnectedPeer *cp = cls; struct GNUNET_PeerIdentity target; GNUNET_PEER_resolve (cp->ppd.pid, &target); cp->rc_delay_task = GNUNET_SCHEDULER_NO_TASK; cp->rc = GNUNET_ATS_reserve_bandwidth (ats, &target, DBLOCK_SIZE, &ats_reserve_callback, cp); } /** * Function called by core upon success or failure of our bandwidth reservation request. * * @param cls the 'struct GSF_ConnectedPeer' of the peer for which we made the request * @param peer identifies the peer * @param amount set to the amount that was actually reserved or unreserved; * either the full requested amount or zero (no partial reservations) * @param res_delay if the reservation could not be satisfied (amount was 0), how * long should the client wait until re-trying? */ static void ats_reserve_callback (void *cls, const struct GNUNET_PeerIdentity *peer, int32_t amount, struct GNUNET_TIME_Relative res_delay) { struct GSF_ConnectedPeer *cp = cls; struct GSF_PeerTransmitHandle *pth; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Reserved %d bytes / need to wait %llu ms for reservation\n", (int) amount, (unsigned long long) res_delay.rel_value); cp->rc = NULL; if (0 == amount) { cp->rc_delay_task = GNUNET_SCHEDULER_add_delayed (res_delay, &retry_reservation, cp); return; } cp->did_reserve = GNUNET_YES; pth = cp->pth_head; if ((NULL != pth) && (NULL == pth->cth)) { /* reservation success, try transmission now! */ pth->cth_in_progress++; pth->cth = GNUNET_CORE_notify_transmit_ready (GSF_core, GNUNET_YES, pth->priority, GNUNET_TIME_absolute_get_remaining (pth->timeout), peer, pth->size, &peer_transmit_ready_cb, pth); GNUNET_assert (0 < pth->cth_in_progress--); } } /** * A peer connected to us. Setup the connected peer * records. * * @param peer identity of peer that connected * @param atsi performance data for the connection * @param atsi_count number of records in 'atsi' * @return handle to connected peer entry */ struct GSF_ConnectedPeer * GSF_peer_connect_handler_ (const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct GSF_ConnectedPeer *cp; char *fn; uint32_t trust; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected to peer %s\n", GNUNET_i2s (peer)); cp = GNUNET_malloc (sizeof (struct GSF_ConnectedPeer)); cp->ppd.pid = GNUNET_PEER_intern (peer); cp->ppd.transmission_delay = GNUNET_LOAD_value_init (GNUNET_TIME_UNIT_ZERO); cp->rc = GNUNET_ATS_reserve_bandwidth (ats, peer, DBLOCK_SIZE, &ats_reserve_callback, cp); fn = get_trust_filename (peer); if ((GNUNET_DISK_file_test (fn) == GNUNET_YES) && (sizeof (trust) == GNUNET_DISK_fn_read (fn, &trust, sizeof (trust)))) cp->disk_trust = cp->ppd.trust = ntohl (trust); GNUNET_free (fn); cp->request_map = GNUNET_CONTAINER_multihashmap_create (128); GNUNET_break (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (cp_map, &peer->hashPubKey, cp, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# peers connected"), GNUNET_CONTAINER_multihashmap_size (cp_map), GNUNET_NO); update_atsi (cp, atsi, atsi_count); GSF_push_start_ (cp); return cp; } /** * It may be time to re-start migrating content to this * peer. Check, and if so, restart migration. * * @param cls the 'struct GSF_ConnectedPeer' * @param tc scheduler context */ static void revive_migration (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GSF_ConnectedPeer *cp = cls; struct GNUNET_TIME_Relative bt; cp->mig_revive_task = GNUNET_SCHEDULER_NO_TASK; bt = GNUNET_TIME_absolute_get_remaining (cp->ppd.migration_blocked_until); if (0 != bt.rel_value) { /* still time left... */ cp->mig_revive_task = GNUNET_SCHEDULER_add_delayed (bt, &revive_migration, cp); return; } GSF_push_start_ (cp); } /** * Get a handle for a connected peer. * * @param peer peer's identity * @return NULL if the peer is not currently connected */ struct GSF_ConnectedPeer * GSF_peer_get_ (const struct GNUNET_PeerIdentity *peer) { if (NULL == cp_map) return NULL; return GNUNET_CONTAINER_multihashmap_get (cp_map, &peer->hashPubKey); } /** * Handle P2P "MIGRATION_STOP" message. * * @param cls closure, always NULL * @param other the other peer involved (sender or receiver, NULL * for loopback messages where we are both sender and receiver) * @param message the actual message * @param atsi performance information * @param atsi_count number of records in 'atsi' * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ int GSF_handle_p2p_migration_stop_ (void *cls, const struct GNUNET_PeerIdentity *other, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct GSF_ConnectedPeer *cp; const struct MigrationStopMessage *msm; struct GNUNET_TIME_Relative bt; msm = (const struct MigrationStopMessage *) message; cp = GSF_peer_get_ (other); if (cp == NULL) { GNUNET_break (0); return GNUNET_OK; } GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# migration stop messages received"), 1, GNUNET_NO); bt = GNUNET_TIME_relative_ntoh (msm->duration); GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Migration of content to peer `%s' blocked for %llu ms\n"), GNUNET_i2s (other), (unsigned long long) bt.rel_value); cp->ppd.migration_blocked_until = GNUNET_TIME_relative_to_absolute (bt); if (cp->mig_revive_task == GNUNET_SCHEDULER_NO_TASK) { GSF_push_stop_ (cp); cp->mig_revive_task = GNUNET_SCHEDULER_add_delayed (bt, &revive_migration, cp); } update_atsi (cp, atsi, atsi_count); return GNUNET_OK; } /** * Copy reply and free put message. * * @param cls the 'struct PutMessage' * @param buf_size number of bytes available in buf * @param buf where to copy the message, NULL on error (peer disconnect) * @return number of bytes copied to 'buf', can be 0 (without indicating an error) */ static size_t copy_reply (void *cls, size_t buf_size, void *buf) { struct PutMessage *pm = cls; size_t size; if (buf != NULL) { GNUNET_assert (buf_size >= ntohs (pm->header.size)); size = ntohs (pm->header.size); memcpy (buf, pm, size); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# replies transmitted to other peers"), 1, GNUNET_NO); } else { size = 0; GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# replies dropped"), 1, GNUNET_NO); } GNUNET_free (pm); return size; } /** * Free resources associated with the given peer request. * * @param peerreq request to free * @param query associated key for the request */ static void free_pending_request (struct PeerRequest *peerreq, const GNUNET_HashCode *query) { struct GSF_ConnectedPeer *cp = peerreq->cp; if (peerreq->kill_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (peerreq->kill_task); peerreq->kill_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# P2P searches active"), -1, GNUNET_NO); GNUNET_break (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (cp->request_map, query, peerreq)); GNUNET_free (peerreq); } /** * Cancel all requests associated with the peer. * * @param cls unused * @param query hash code of the request * @param value the 'struct GSF_PendingRequest' * @return GNUNET_YES (continue to iterate) */ static int cancel_pending_request (void *cls, const GNUNET_HashCode * query, void *value) { struct PeerRequest *peerreq = value; struct GSF_PendingRequest *pr = peerreq->pr; struct GSF_PendingRequestData *prd; prd = GSF_pending_request_get_data_ (pr); GSF_pending_request_cancel_ (pr, GNUNET_NO); free_pending_request (peerreq, &prd->query); return GNUNET_OK; } /** * Free the given request. * * @param cls the request to free * @param tc task context */ static void peer_request_destroy (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerRequest *peerreq = cls; struct GSF_PendingRequest *pr = peerreq->pr; struct GSF_PendingRequestData *prd; peerreq->kill_task = GNUNET_SCHEDULER_NO_TASK; prd = GSF_pending_request_get_data_ (pr); cancel_pending_request (NULL, &prd->query, peerreq); } /** * The artificial delay is over, transmit the message now. * * @param cls the 'struct GSF_DelayedHandle' with the message * @param tc scheduler context */ static void transmit_delayed_now (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GSF_DelayedHandle *dh = cls; struct GSF_ConnectedPeer *cp = dh->cp; GNUNET_CONTAINER_DLL_remove (cp->delayed_head, cp->delayed_tail, dh); if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) { GNUNET_free (dh->pm); GNUNET_free (dh); return; } (void) GSF_peer_transmit_ (cp, GNUNET_NO, UINT32_MAX, REPLY_TIMEOUT, dh->msize, ©_reply, dh->pm); GNUNET_free (dh); } /** * Get the randomized delay a response should be subjected to. * * @return desired delay */ static struct GNUNET_TIME_Relative get_randomized_delay () { struct GNUNET_TIME_Relative ret; ret = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2 * GSF_avg_latency.rel_value + 1)); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# artificial delays introduced (ms)"), ret.rel_value, GNUNET_NO); return ret; } /** * Handle a reply to a pending request. Also called if a request * expires (then with data == NULL). The handler may be called * many times (depending on the request type), but will not be * called during or after a call to GSF_pending_request_cancel * and will also not be called anymore after a call signalling * expiration. * * @param cls 'struct PeerRequest' this is an answer for * @param eval evaluation of the result * @param pr handle to the original pending request * @param reply_anonymity_level anonymity level for the reply, UINT32_MAX for "unknown" * @param expiration when does 'data' expire? * @param last_transmission when did we last transmit a request for this block * @param type type of the block * @param data response data, NULL on request expiration * @param data_len number of bytes in data */ static void handle_p2p_reply (void *cls, enum GNUNET_BLOCK_EvaluationResult eval, struct GSF_PendingRequest *pr, uint32_t reply_anonymity_level, struct GNUNET_TIME_Absolute expiration, struct GNUNET_TIME_Absolute last_transmission, enum GNUNET_BLOCK_Type type, const void *data, size_t data_len) { struct PeerRequest *peerreq = cls; struct GSF_ConnectedPeer *cp = peerreq->cp; struct GSF_PendingRequestData *prd; struct PutMessage *pm; size_t msize; GNUNET_assert (data_len + sizeof (struct PutMessage) < GNUNET_SERVER_MAX_MESSAGE_SIZE); GNUNET_assert (peerreq->pr == pr); prd = GSF_pending_request_get_data_ (pr); if (NULL == data) { free_pending_request (peerreq, &prd->query); return; } GNUNET_break (type != GNUNET_BLOCK_TYPE_ANY); if ((prd->type != type) && (prd->type != GNUNET_BLOCK_TYPE_ANY)) { GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# replies dropped due to type mismatch"), 1, GNUNET_NO); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting result for query `%s' to peer\n", GNUNET_h2s (&prd->query)); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# replies received for other peers"), 1, GNUNET_NO); msize = sizeof (struct PutMessage) + data_len; if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); return; } if ((reply_anonymity_level != UINT32_MAX) && (reply_anonymity_level > 1)) { if (reply_anonymity_level - 1 > GSF_cover_content_count) { GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# replies dropped due to insufficient cover traffic"), 1, GNUNET_NO); return; } GSF_cover_content_count -= (reply_anonymity_level - 1); } pm = GNUNET_malloc (msize); pm->header.type = htons (GNUNET_MESSAGE_TYPE_FS_PUT); pm->header.size = htons (msize); pm->type = htonl (type); pm->expiration = GNUNET_TIME_absolute_hton (expiration); memcpy (&pm[1], data, data_len); if ((reply_anonymity_level != UINT32_MAX) && (reply_anonymity_level != 0) && (GSF_enable_randomized_delays == GNUNET_YES)) { struct GSF_DelayedHandle *dh; dh = GNUNET_malloc (sizeof (struct GSF_DelayedHandle)); dh->cp = cp; dh->pm = pm; dh->msize = msize; GNUNET_CONTAINER_DLL_insert (cp->delayed_head, cp->delayed_tail, dh); dh->delay_task = GNUNET_SCHEDULER_add_delayed (get_randomized_delay (), &transmit_delayed_now, dh); } else { (void) GSF_peer_transmit_ (cp, GNUNET_NO, UINT32_MAX, REPLY_TIMEOUT, msize, ©_reply, pm); } if (eval != GNUNET_BLOCK_EVALUATION_OK_LAST) return; if (GNUNET_SCHEDULER_NO_TASK == peerreq->kill_task) { GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# P2P searches destroyed due to ultimate reply"), 1, GNUNET_NO); peerreq->kill_task = GNUNET_SCHEDULER_add_now (&peer_request_destroy, peerreq); } } /** * Increase the host credit by a value. * * @param cp which peer to change the trust value on * @param value is the int value by which the * host credit is to be increased or decreased * @returns the actual change in trust (positive or negative) */ static int change_host_trust (struct GSF_ConnectedPeer *cp, int value) { if (value == 0) return 0; GNUNET_assert (cp != NULL); if (value > 0) { if (cp->ppd.trust + value < cp->ppd.trust) { value = UINT32_MAX - cp->ppd.trust; cp->ppd.trust = UINT32_MAX; } else cp->ppd.trust += value; } else { if (cp->ppd.trust < -value) { value = -cp->ppd.trust; cp->ppd.trust = 0; } else cp->ppd.trust += value; } return value; } /** * We've received a request with the specified priority. Bound it * according to how much we trust the given peer. * * @param prio_in requested priority * @param cp the peer making the request * @return effective priority */ static int32_t bound_priority (uint32_t prio_in, struct GSF_ConnectedPeer *cp) { #define N ((double)128.0) uint32_t ret; double rret; int ld; ld = GSF_test_get_load_too_high_ (0); if (ld == GNUNET_SYSERR) { GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# requests done for free (low load)"), 1, GNUNET_NO); return 0; /* excess resources */ } if (prio_in > INT32_MAX) prio_in = INT32_MAX; ret = -change_host_trust (cp, -(int) prio_in); if (ret > 0) { if (ret > GSF_current_priorities + N) rret = GSF_current_priorities + N; else rret = ret; GSF_current_priorities = (GSF_current_priorities * (N - 1) + rret) / N; } if ((ld == GNUNET_YES) && (ret > 0)) { /* try with charging */ ld = GSF_test_get_load_too_high_ (ret); } if (ld == GNUNET_YES) { GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# request dropped, priority insufficient"), 1, GNUNET_NO); /* undo charge */ change_host_trust (cp, (int) ret); return -1; /* not enough resources */ } else { GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# requests done for a price (normal load)"), 1, GNUNET_NO); } #undef N return ret; } /** * The priority level imposes a bound on the maximum * value for the ttl that can be requested. * * @param ttl_in requested ttl * @param prio given priority * @return ttl_in if ttl_in is below the limit, * otherwise the ttl-limit for the given priority */ static int32_t bound_ttl (int32_t ttl_in, uint32_t prio) { unsigned long long allowed; if (ttl_in <= 0) return ttl_in; allowed = ((unsigned long long) prio) * TTL_DECREMENT / 1000; if (ttl_in > allowed) { if (allowed >= (1 << 30)) return 1 << 30; return allowed; } return ttl_in; } /** * Handle P2P "QUERY" message. Creates the pending request entry * and sets up all of the data structures to that we will * process replies properly. Does not initiate forwarding or * local database lookups. * * @param other the other peer involved (sender or receiver, NULL * for loopback messages where we are both sender and receiver) * @param message the actual message * @return pending request handle, NULL on error */ struct GSF_PendingRequest * GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other, const struct GNUNET_MessageHeader *message) { struct PeerRequest *peerreq; struct GSF_PendingRequest *pr; struct GSF_PendingRequestData *prd; struct GSF_ConnectedPeer *cp; struct GSF_ConnectedPeer *cps; const GNUNET_HashCode *namespace; const struct GNUNET_PeerIdentity *target; enum GSF_PendingRequestOptions options; uint16_t msize; const struct GetMessage *gm; unsigned int bits; const GNUNET_HashCode *opt; uint32_t bm; size_t bfsize; uint32_t ttl_decrement; int32_t priority; int32_t ttl; enum GNUNET_BLOCK_Type type; GNUNET_PEER_Id spid; GNUNET_assert (other != NULL); msize = ntohs (message->size); if (msize < sizeof (struct GetMessage)) { GNUNET_break_op (0); return NULL; } GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# GET requests received (from other peers)"), 1, GNUNET_NO); gm = (const struct GetMessage *) message; type = ntohl (gm->type); bm = ntohl (gm->hash_bitmap); bits = 0; while (bm > 0) { if (1 == (bm & 1)) bits++; bm >>= 1; } if (msize < sizeof (struct GetMessage) + bits * sizeof (GNUNET_HashCode)) { GNUNET_break_op (0); return NULL; } opt = (const GNUNET_HashCode *) &gm[1]; bfsize = msize - sizeof (struct GetMessage) - bits * sizeof (GNUNET_HashCode); /* bfsize must be power of 2, check! */ if (0 != ((bfsize - 1) & bfsize)) { GNUNET_break_op (0); return NULL; } GSF_cover_query_count++; bm = ntohl (gm->hash_bitmap); bits = 0; cps = GSF_peer_get_ (other); if (NULL == cps) { /* peer must have just disconnected */ GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# requests dropped due to initiator not being connected"), 1, GNUNET_NO); return NULL; } if (0 != (bm & GET_MESSAGE_BIT_RETURN_TO)) cp = GSF_peer_get_ ((const struct GNUNET_PeerIdentity *) &opt[bits++]); else cp = cps; if (cp == NULL) { if (0 != (bm & GET_MESSAGE_BIT_RETURN_TO)) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to find RETURN-TO peer `%4s' in connection set. Dropping query.\n", GNUNET_i2s ((const struct GNUNET_PeerIdentity *) &opt[bits - 1])); else GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to find peer `%4s' in connection set. Dropping query.\n", GNUNET_i2s (other)); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# requests dropped due to missing reverse route"), 1, GNUNET_NO); return NULL; } /* note that we can really only check load here since otherwise * peers could find out that we are overloaded by not being * disconnected after sending us a malformed query... */ priority = bound_priority (ntohl (gm->priority), cps); if (priority < 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Dropping query from `%s', this peer is too busy.\n", GNUNET_i2s (other)); return NULL; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received request for `%s' of type %u from peer `%4s' with flags %u\n", GNUNET_h2s (&gm->query), (unsigned int) type, GNUNET_i2s (other), (unsigned int) bm); namespace = (0 != (bm & GET_MESSAGE_BIT_SKS_NAMESPACE)) ? &opt[bits++] : NULL; if ((type == GNUNET_BLOCK_TYPE_FS_SBLOCK) && (namespace == NULL)) { GNUNET_break_op (0); return NULL; } if ((type != GNUNET_BLOCK_TYPE_FS_SBLOCK) && (namespace != NULL)) { GNUNET_break_op (0); return NULL; } target = (0 != (bm & GET_MESSAGE_BIT_TRANSMIT_TO)) ? ((const struct GNUNET_PeerIdentity *) &opt[bits++]) : NULL; options = GSF_PRO_DEFAULTS; spid = 0; if ((GNUNET_LOAD_get_load (cp->ppd.transmission_delay) > 3 * (1 + priority)) || (GNUNET_LOAD_get_average (cp->ppd.transmission_delay) > GNUNET_CONSTANTS_MAX_CORK_DELAY.rel_value * 2 + GNUNET_LOAD_get_average (GSF_rt_entry_lifetime))) { /* don't have BW to send to peer, or would likely take longer than we have for it, * so at best indirect the query */ priority = 0; options |= GSF_PRO_FORWARD_ONLY; spid = GNUNET_PEER_intern (other); GNUNET_assert (0 != spid); } ttl = bound_ttl (ntohl (gm->ttl), priority); /* decrement ttl (always) */ ttl_decrement = 2 * TTL_DECREMENT + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, TTL_DECREMENT); if ((ttl < 0) && (((int32_t) (ttl - ttl_decrement)) > 0)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Dropping query from `%s' due to TTL underflow (%d - %u).\n", GNUNET_i2s (other), ttl, ttl_decrement); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# requests dropped due TTL underflow"), 1, GNUNET_NO); /* integer underflow => drop (should be very rare)! */ return NULL; } ttl -= ttl_decrement; /* test if the request already exists */ peerreq = GNUNET_CONTAINER_multihashmap_get (cp->request_map, &gm->query); if (peerreq != NULL) { pr = peerreq->pr; prd = GSF_pending_request_get_data_ (pr); if ((prd->type == type) && ((type != GNUNET_BLOCK_TYPE_FS_SBLOCK) || (0 == memcmp (&prd->namespace, namespace, sizeof (GNUNET_HashCode))))) { if (prd->ttl.abs_value >= GNUNET_TIME_absolute_get ().abs_value + ttl) { /* existing request has higher TTL, drop new one! */ prd->priority += priority; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have existing request with higher TTL, dropping new request.\n", GNUNET_i2s (other)); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# requests dropped due to higher-TTL request"), 1, GNUNET_NO); return NULL; } /* existing request has lower TTL, drop old one! */ priority += prd->priority; GSF_pending_request_cancel_ (pr, GNUNET_YES); free_pending_request (peerreq, &gm->query); } } peerreq = GNUNET_malloc (sizeof (struct PeerRequest)); peerreq->cp = cp; pr = GSF_pending_request_create_ (options, type, &gm->query, namespace, target, (bfsize > 0) ? (const char *) &opt[bits] : NULL, bfsize, ntohl (gm->filter_mutator), 1 /* anonymity */ , (uint32_t) priority, ttl, spid, GNUNET_PEER_intern (other), NULL, 0, /* replies_seen */ &handle_p2p_reply, peerreq); GNUNET_assert (NULL != pr); peerreq->pr = pr; GNUNET_break (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (cp->request_map, &gm->query, peerreq, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# P2P query messages received and processed"), 1, GNUNET_NO); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# P2P searches active"), 1, GNUNET_NO); return pr; } /** * Function called if there has been a timeout trying to satisfy * a transmission request. * * @param cls the 'struct GSF_PeerTransmitHandle' of the request * @param tc scheduler context */ static void peer_transmit_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GSF_PeerTransmitHandle *pth = cls; struct GSF_ConnectedPeer *cp; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout trying to transmit to other peer\n"); pth->timeout_task = GNUNET_SCHEDULER_NO_TASK; cp = pth->cp; GNUNET_CONTAINER_DLL_remove (cp->pth_head, cp->pth_tail, pth); if (GNUNET_YES == pth->is_query) GNUNET_assert (0 < cp->ppd.pending_queries--); else if (GNUNET_NO == pth->is_query) GNUNET_assert (0 < cp->ppd.pending_replies--); GNUNET_LOAD_update (cp->ppd.transmission_delay, UINT64_MAX); if (NULL != pth->cth) { GNUNET_CORE_notify_transmit_ready_cancel (pth->cth); pth->cth = NULL; } pth->gmc (pth->gmc_cls, 0, NULL); GNUNET_assert (0 == pth->cth_in_progress); GNUNET_free (pth); } /** * Transmit a message to the given peer as soon as possible. * If the peer disconnects before the transmission can happen, * the callback is invoked with a 'NULL' buffer. * * @param cp target peer * @param is_query is this a query (GNUNET_YES) or content (GNUNET_NO) or neither (GNUNET_SYSERR) * @param priority how important is this request? * @param timeout when does this request timeout (call gmc with error) * @param size number of bytes we would like to send to the peer * @param gmc function to call to get the message * @param gmc_cls closure for gmc * @return handle to cancel request */ struct GSF_PeerTransmitHandle * GSF_peer_transmit_ (struct GSF_ConnectedPeer *cp, int is_query, uint32_t priority, struct GNUNET_TIME_Relative timeout, size_t size, GSF_GetMessageCallback gmc, void *gmc_cls) { struct GSF_PeerTransmitHandle *pth; struct GSF_PeerTransmitHandle *pos; struct GSF_PeerTransmitHandle *prev; pth = GNUNET_malloc (sizeof (struct GSF_PeerTransmitHandle)); pth->transmission_request_start_time = GNUNET_TIME_absolute_get (); pth->timeout = GNUNET_TIME_relative_to_absolute (timeout); pth->gmc = gmc; pth->gmc_cls = gmc_cls; pth->size = size; pth->is_query = is_query; pth->priority = priority; pth->cp = cp; /* insertion sort (by priority, descending) */ prev = NULL; pos = cp->pth_head; while ((pos != NULL) && (pos->priority > priority)) { prev = pos; pos = pos->next; } if (prev == NULL) GNUNET_CONTAINER_DLL_insert (cp->pth_head, cp->pth_tail, pth); else GNUNET_CONTAINER_DLL_insert_after (cp->pth_head, cp->pth_tail, prev, pth); if (GNUNET_YES == is_query) cp->ppd.pending_queries++; else if (GNUNET_NO == is_query) cp->ppd.pending_replies++; pth->timeout_task = GNUNET_SCHEDULER_add_delayed (timeout, &peer_transmit_timeout, pth); schedule_transmission (pth); return pth; } /** * Cancel an earlier request for transmission. * * @param pth request to cancel */ void GSF_peer_transmit_cancel_ (struct GSF_PeerTransmitHandle *pth) { struct GSF_ConnectedPeer *cp; if (pth->timeout_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (pth->timeout_task); pth->timeout_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != pth->cth) { GNUNET_CORE_notify_transmit_ready_cancel (pth->cth); pth->cth = NULL; } cp = pth->cp; GNUNET_CONTAINER_DLL_remove (cp->pth_head, cp->pth_tail, pth); if (GNUNET_YES == pth->is_query) GNUNET_assert (0 < cp->ppd.pending_queries--); else if (GNUNET_NO == pth->is_query) GNUNET_assert (0 < cp->ppd.pending_replies--); GNUNET_assert (0 == pth->cth_in_progress); GNUNET_free (pth); } /** * Report on receiving a reply; update the performance record of the given peer. * * @param cp responding peer (will be updated) * @param request_time time at which the original query was transmitted * @param request_priority priority of the original request */ void GSF_peer_update_performance_ (struct GSF_ConnectedPeer *cp, struct GNUNET_TIME_Absolute request_time, uint32_t request_priority) { struct GNUNET_TIME_Relative delay; delay = GNUNET_TIME_absolute_get_duration (request_time); cp->ppd.avg_reply_delay.rel_value = (cp->ppd.avg_reply_delay.rel_value * (RUNAVG_DELAY_N - 1) + delay.rel_value) / RUNAVG_DELAY_N; cp->ppd.avg_priority = (cp->ppd.avg_priority * (RUNAVG_DELAY_N - 1) + request_priority) / RUNAVG_DELAY_N; } /** * Report on receiving a reply in response to an initiating client. * Remember that this peer is good for this client. * * @param cp responding peer (will be updated) * @param initiator_client local client on responsible for query */ void GSF_peer_update_responder_client_ (struct GSF_ConnectedPeer *cp, struct GSF_LocalClient *initiator_client) { cp->ppd.last_client_replies[cp->last_client_replies_woff++ % CS2P_SUCCESS_LIST_SIZE] = initiator_client; } /** * Report on receiving a reply in response to an initiating peer. * Remember that this peer is good for this initiating peer. * * @param cp responding peer (will be updated) * @param initiator_peer other peer responsible for query */ void GSF_peer_update_responder_peer_ (struct GSF_ConnectedPeer *cp, const struct GSF_ConnectedPeer *initiator_peer) { unsigned int woff; woff = cp->last_p2p_replies_woff % P2P_SUCCESS_LIST_SIZE; GNUNET_PEER_change_rc (cp->ppd.last_p2p_replies[woff], -1); cp->ppd.last_p2p_replies[woff] = initiator_peer->ppd.pid; GNUNET_PEER_change_rc (initiator_peer->ppd.pid, 1); cp->last_p2p_replies_woff = (woff + 1) % P2P_SUCCESS_LIST_SIZE; } /** * A peer disconnected from us. Tear down the connected peer * record. * * @param cls unused * @param peer identity of peer that connected */ void GSF_peer_disconnect_handler_ (void *cls, const struct GNUNET_PeerIdentity *peer) { struct GSF_ConnectedPeer *cp; struct GSF_PeerTransmitHandle *pth; struct GSF_DelayedHandle *dh; cp = GSF_peer_get_ (peer); if (NULL == cp) return; /* must have been disconnect from core with * 'peer' == my_id, ignore */ GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (cp_map, &peer->hashPubKey, cp)); GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# peers connected"), GNUNET_CONTAINER_multihashmap_size (cp_map), GNUNET_NO); if (NULL != cp->migration_pth) { GSF_peer_transmit_cancel_ (cp->migration_pth); cp->migration_pth = NULL; } if (NULL != cp->rc) { GNUNET_ATS_reserve_bandwidth_cancel (cp->rc); cp->rc = NULL; } if (GNUNET_SCHEDULER_NO_TASK != cp->rc_delay_task) { GNUNET_SCHEDULER_cancel (cp->rc_delay_task); cp->rc_delay_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_CONTAINER_multihashmap_iterate (cp->request_map, &cancel_pending_request, cp); GNUNET_CONTAINER_multihashmap_destroy (cp->request_map); cp->request_map = NULL; GSF_plan_notify_peer_disconnect_ (cp); GNUNET_LOAD_value_free (cp->ppd.transmission_delay); GNUNET_PEER_decrement_rcs (cp->ppd.last_p2p_replies, P2P_SUCCESS_LIST_SIZE); memset (cp->ppd.last_p2p_replies, 0, sizeof (cp->ppd.last_p2p_replies)); GSF_push_stop_ (cp); while (NULL != (pth = cp->pth_head)) { if (NULL != pth->cth) { GNUNET_CORE_notify_transmit_ready_cancel (pth->cth); pth->cth = NULL; } if (pth->timeout_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (pth->timeout_task); pth->timeout_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_CONTAINER_DLL_remove (cp->pth_head, cp->pth_tail, pth); GNUNET_assert (0 == pth->cth_in_progress); pth->gmc (pth->gmc_cls, 0, NULL); GNUNET_free (pth); } while (NULL != (dh = cp->delayed_head)) { GNUNET_CONTAINER_DLL_remove (cp->delayed_head, cp->delayed_tail, dh); GNUNET_SCHEDULER_cancel (dh->delay_task); GNUNET_free (dh->pm); GNUNET_free (dh); } GNUNET_PEER_change_rc (cp->ppd.pid, -1); if (GNUNET_SCHEDULER_NO_TASK != cp->mig_revive_task) { GNUNET_SCHEDULER_cancel (cp->mig_revive_task); cp->mig_revive_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_free (cp); } /** * Closure for 'call_iterator'. */ struct IterationContext { /** * Function to call on each entry. */ GSF_ConnectedPeerIterator it; /** * Closure for 'it'. */ void *it_cls; }; /** * Function that calls the callback for each peer. * * @param cls the 'struct IterationContext*' * @param key identity of the peer * @param value the 'struct GSF_ConnectedPeer*' * @return GNUNET_YES to continue iteration */ static int call_iterator (void *cls, const GNUNET_HashCode * key, void *value) { struct IterationContext *ic = cls; struct GSF_ConnectedPeer *cp = value; ic->it (ic->it_cls, (const struct GNUNET_PeerIdentity *) key, cp, &cp->ppd); return GNUNET_YES; } /** * Iterate over all connected peers. * * @param it function to call for each peer * @param it_cls closure for it */ void GSF_iterate_connected_peers_ (GSF_ConnectedPeerIterator it, void *it_cls) { struct IterationContext ic; ic.it = it; ic.it_cls = it_cls; GNUNET_CONTAINER_multihashmap_iterate (cp_map, &call_iterator, &ic); } /** * Obtain the identity of a connected peer. * * @param cp peer to reserve bandwidth from * @param id identity to set (written to) */ void GSF_connected_peer_get_identity_ (const struct GSF_ConnectedPeer *cp, struct GNUNET_PeerIdentity *id) { GNUNET_assert (0 != cp->ppd.pid); GNUNET_PEER_resolve (cp->ppd.pid, id); } /** * Assemble a migration stop message for transmission. * * @param cls the 'struct GSF_ConnectedPeer' to use * @param size number of bytes we're allowed to write to buf * @param buf where to copy the message * @return number of bytes copied to buf */ static size_t create_migration_stop_message (void *cls, size_t size, void *buf) { struct GSF_ConnectedPeer *cp = cls; struct MigrationStopMessage msm; cp->migration_pth = NULL; if (NULL == buf) return 0; GNUNET_assert (size >= sizeof (struct MigrationStopMessage)); msm.header.size = htons (sizeof (struct MigrationStopMessage)); msm.header.type = htons (GNUNET_MESSAGE_TYPE_FS_MIGRATION_STOP); msm.reserved = htonl (0); msm.duration = GNUNET_TIME_relative_hton (GNUNET_TIME_absolute_get_remaining (cp->last_migration_block)); memcpy (buf, &msm, sizeof (struct MigrationStopMessage)); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# migration stop messages sent"), 1, GNUNET_NO); return sizeof (struct MigrationStopMessage); } /** * Ask a peer to stop migrating data to us until the given point * in time. * * @param cp peer to ask * @param block_time until when to block */ void GSF_block_peer_migration_ (struct GSF_ConnectedPeer *cp, struct GNUNET_TIME_Absolute block_time) { if (cp->last_migration_block.abs_value > block_time.abs_value) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Migration already blocked for another %llu ms\n", (unsigned long long) GNUNET_TIME_absolute_get_remaining (cp->last_migration_block).rel_value); return; /* already blocked */ } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking to stop migration for %llu ms\n", (unsigned long long) GNUNET_TIME_absolute_get_remaining (block_time).rel_value); cp->last_migration_block = block_time; if (cp->migration_pth != NULL) GSF_peer_transmit_cancel_ (cp->migration_pth); cp->migration_pth = GSF_peer_transmit_ (cp, GNUNET_SYSERR, UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, sizeof (struct MigrationStopMessage), &create_migration_stop_message, cp); } /** * Write host-trust information to a file - flush the buffer entry! * * @param cls closure, not used * @param key host identity * @param value the 'struct GSF_ConnectedPeer' to flush * @return GNUNET_OK to continue iteration */ static int flush_trust (void *cls, const GNUNET_HashCode * key, void *value) { struct GSF_ConnectedPeer *cp = value; char *fn; uint32_t trust; struct GNUNET_PeerIdentity pid; if (cp->ppd.trust == cp->disk_trust) return GNUNET_OK; /* unchanged */ GNUNET_assert (0 != cp->ppd.pid); GNUNET_PEER_resolve (cp->ppd.pid, &pid); fn = get_trust_filename (&pid); if (cp->ppd.trust == 0) { if ((0 != UNLINK (fn)) && (errno != ENOENT)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "unlink", fn); } else { trust = htonl (cp->ppd.trust); if (sizeof (uint32_t) == GNUNET_DISK_fn_write (fn, &trust, sizeof (uint32_t), GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_GROUP_READ | GNUNET_DISK_PERM_OTHER_READ)) cp->disk_trust = cp->ppd.trust; } GNUNET_free (fn); return GNUNET_OK; } /** * Notify core about a preference we have for the given peer * (to allocate more resources towards it). The change will * be communicated the next time we reserve bandwidth with * core (not instantly). * * @param cp peer to reserve bandwidth from * @param pref preference change */ void GSF_connected_peer_change_preference_ (struct GSF_ConnectedPeer *cp, uint64_t pref) { cp->inc_preference += pref; } /** * Call this method periodically to flush trust information to disk. * * @param cls closure, not used * @param tc task context, not used */ static void cron_flush_trust (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (NULL == cp_map) return; GNUNET_CONTAINER_multihashmap_iterate (cp_map, &flush_trust, NULL); if (NULL == tc) return; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; GNUNET_SCHEDULER_add_delayed_with_priority (TRUST_FLUSH_FREQ, GNUNET_SCHEDULER_PRIORITY_HIGH, &cron_flush_trust, NULL); } /** * Initialize peer management subsystem. */ void GSF_connected_peer_init_ () { cp_map = GNUNET_CONTAINER_multihashmap_create (128); ats = GNUNET_ATS_performance_init (GSF_cfg, NULL, NULL); GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (GSF_cfg, "fs", "TRUST", &trustDirectory)); GNUNET_DISK_directory_create (trustDirectory); GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_HIGH, &cron_flush_trust, NULL); } /** * Iterator to free peer entries. * * @param cls closure, unused * @param key current key code * @param value value in the hash map (peer entry) * @return GNUNET_YES (we should continue to iterate) */ static int clean_peer (void *cls, const GNUNET_HashCode * key, void *value) { GSF_peer_disconnect_handler_ (NULL, (const struct GNUNET_PeerIdentity *) key); return GNUNET_YES; } /** * Shutdown peer management subsystem. */ void GSF_connected_peer_done_ () { cron_flush_trust (NULL, NULL); GNUNET_CONTAINER_multihashmap_iterate (cp_map, &clean_peer, NULL); GNUNET_CONTAINER_multihashmap_destroy (cp_map); cp_map = NULL; GNUNET_free (trustDirectory); trustDirectory = NULL; GNUNET_ATS_performance_done (ats); ats = NULL; } /** * Iterator to remove references to LC entry. * * @param cls the 'struct GSF_LocalClient*' to look for * @param key current key code * @param value value in the hash map (peer entry) * @return GNUNET_YES (we should continue to iterate) */ static int clean_local_client (void *cls, const GNUNET_HashCode * key, void *value) { const struct GSF_LocalClient *lc = cls; struct GSF_ConnectedPeer *cp = value; unsigned int i; for (i = 0; i < CS2P_SUCCESS_LIST_SIZE; i++) if (cp->ppd.last_client_replies[i] == lc) cp->ppd.last_client_replies[i] = NULL; return GNUNET_YES; } /** * Notification that a local client disconnected. Clean up all of our * references to the given handle. * * @param lc handle to the local client (henceforth invalid) */ void GSF_handle_local_client_disconnect_ (const struct GSF_LocalClient *lc) { if (NULL == cp_map) return; /* already cleaned up */ GNUNET_CONTAINER_multihashmap_iterate (cp_map, &clean_local_client, (void *) lc); } /* end of gnunet-service-fs_cp.c */ gnunet-0.9.3/src/fs/test_gnunet_fs_idx_data.conf0000644000175000017500000000022711615567501016706 00000000000000@INLINE@ test_fs_defaults.conf [PATHS] SERVICEHOME = /tmp/gnunet-test-fs-py-idx/ DEFAULTCONFIG = test_gnunet_fs_idx_data.conf [transport] PLUGINS = gnunet-0.9.3/src/fs/fs_tree.c0000644000175000017500000003145611760502551012751 00000000000000/* This file is part of GNUnet. (C) 2009-2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs_tree.c * @brief Merkle-tree-ish-CHK file encoding for GNUnet * @see http://gnunet.org/encoding.php3 * @author Krista Bennett * @author Christian Grothoff */ #include "platform.h" #include "fs_tree.h" /** * Context for an ECRS-based file encoder that computes * the Merkle-ish-CHK tree. */ struct GNUNET_FS_TreeEncoder { /** * Global FS context. */ struct GNUNET_FS_Handle *h; /** * Closure for all callbacks. */ void *cls; /** * Function to call on encrypted blocks. */ GNUNET_FS_TreeBlockProcessor proc; /** * Function to call with progress information. */ GNUNET_FS_TreeProgressCallback progress; /** * Function to call to receive input data. */ GNUNET_FS_DataReader reader; /** * Function to call once we're done with processing. */ GNUNET_SCHEDULER_Task cont; /** * Set to an error message (if we had an error). */ char *emsg; /** * Set to the URI (upon successful completion) */ struct GNUNET_FS_Uri *uri; /** * Overall file size. */ uint64_t size; /** * How far are we? */ uint64_t publish_offset; /** * How deep are we? Depth 0 is for the DBLOCKs. */ unsigned int current_depth; /** * How deep is the tree? Always > 0. */ unsigned int chk_tree_depth; /** * In-memory cache of the current CHK tree. * This struct will contain the CHK values * from the root to the currently processed * node in the tree as identified by * "current_depth" and "publish_offset". * The "chktree" will be initially NULL, * then allocated to a sufficient number of * entries for the size of the file and * finally freed once the upload is complete. */ struct ContentHashKey *chk_tree; /** * Are we currently in 'GNUNET_FS_tree_encoder_next'? * Flag used to prevent recursion. */ int in_next; }; /** * Compute the depth of the CHK tree. * * @param flen file length for which to compute the depth * @return depth of the tree, always > 0. A depth of 1 means only a DBLOCK. */ unsigned int GNUNET_FS_compute_depth (uint64_t flen) { unsigned int treeDepth; uint64_t fl; treeDepth = 1; fl = DBLOCK_SIZE; while (fl < flen) { treeDepth++; if (fl * CHK_PER_INODE < fl) { /* integer overflow, this is a HUGE file... */ return treeDepth; } fl = fl * CHK_PER_INODE; } return treeDepth; } /** * Calculate how many bytes of payload a block tree of the given * depth MAY correspond to at most (this function ignores the fact that * some blocks will only be present partially due to the total file * size cutting some blocks off at the end). * * @param depth depth of the block. depth==0 is a DBLOCK. * @return number of bytes of payload a subtree of this depth may correspond to */ uint64_t GNUNET_FS_tree_compute_tree_size (unsigned int depth) { uint64_t rsize; unsigned int i; rsize = DBLOCK_SIZE; for (i = 0; i < depth; i++) rsize *= CHK_PER_INODE; return rsize; } /** * Compute the size of the current IBLOCK. The encoder is * triggering the calculation of the size of an IBLOCK at the * *end* (hence end_offset) of its construction. The IBLOCK * maybe a full or a partial IBLOCK, and this function is to * calculate how long it should be. * * @param depth depth of the IBlock in the tree, 0 would be a DBLOCK, * must be > 0 (this function is for IBLOCKs only!) * @param end_offset current offset in the payload (!) of the overall file, * must be > 0 (since this function is called at the * end of a block). * @return size of the corresponding IBlock */ static uint16_t GNUNET_FS_tree_compute_iblock_size (unsigned int depth, uint64_t end_offset) { unsigned int ret; uint64_t mod; uint64_t bds; GNUNET_assert (depth > 0); GNUNET_assert (end_offset > 0); bds = GNUNET_FS_tree_compute_tree_size (depth); mod = end_offset % bds; if (0 == mod) { /* we were triggered at the end of a full block */ ret = CHK_PER_INODE; } else { /* we were triggered at the end of the file */ bds /= CHK_PER_INODE; ret = mod / bds; if (0 != mod % bds) ret++; } return (uint16_t) (ret * sizeof (struct ContentHashKey)); } /** * Compute how many bytes of data should be stored in * the specified block. * * @param fsize overall file size, must be > 0. * @param offset offset in the original data corresponding * to the beginning of the tree induced by the block; * must be <= fsize * @param depth depth of the node in the tree, 0 for DBLOCK * @return number of bytes stored in this node */ size_t GNUNET_FS_tree_calculate_block_size (uint64_t fsize, uint64_t offset, unsigned int depth) { size_t ret; uint64_t rsize; uint64_t epos; unsigned int chks; GNUNET_assert (fsize > 0); GNUNET_assert (offset <= fsize); if (depth == 0) { ret = DBLOCK_SIZE; if ((offset + ret > fsize) || (offset + ret < offset)) ret = (size_t) (fsize - offset); return ret; } rsize = GNUNET_FS_tree_compute_tree_size (depth - 1); epos = offset + rsize * CHK_PER_INODE; if ((epos < offset) || (epos > fsize)) epos = fsize; /* round up when computing #CHKs in our IBlock */ chks = (epos - offset + rsize - 1) / rsize; GNUNET_assert (chks <= CHK_PER_INODE); return chks * sizeof (struct ContentHashKey); } /** * Initialize a tree encoder. This function will call "proc" and * "progress" on each block in the tree. Once all blocks have been * processed, "cont" will be scheduled. The "reader" will be called * to obtain the (plaintext) blocks for the file. Note that this * function will not actually call "proc". The client must * call "GNUNET_FS_tree_encoder_next" to trigger encryption (and * calling of "proc") for the each block. * * @param h the global FS context * @param size overall size of the file to encode * @param cls closure for reader, proc, progress and cont * @param reader function to call to read plaintext data * @param proc function to call on each encrypted block * @param progress function to call with progress information * @param cont function to call when done */ struct GNUNET_FS_TreeEncoder * GNUNET_FS_tree_encoder_create (struct GNUNET_FS_Handle *h, uint64_t size, void *cls, GNUNET_FS_DataReader reader, GNUNET_FS_TreeBlockProcessor proc, GNUNET_FS_TreeProgressCallback progress, GNUNET_SCHEDULER_Task cont) { struct GNUNET_FS_TreeEncoder *te; te = GNUNET_malloc (sizeof (struct GNUNET_FS_TreeEncoder)); te->h = h; te->size = size; te->cls = cls; te->reader = reader; te->proc = proc; te->progress = progress; te->cont = cont; te->chk_tree_depth = GNUNET_FS_compute_depth (size); te->chk_tree = GNUNET_malloc (te->chk_tree_depth * CHK_PER_INODE * sizeof (struct ContentHashKey)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created tree encoder for file with %llu bytes and depth %u\n", (unsigned long long) size, te->chk_tree_depth); return te; } /** * Compute the offset of the CHK for the * current block in the IBlock above. * * @param depth depth of the IBlock in the tree (aka overall * number of tree levels minus depth); 0 == DBlock * @param end_offset current offset in the overall file, * at the *beginning* of the block for DBLOCKs (depth==0), * otherwise at the *end* of the block (exclusive) * @return (array of CHKs') offset in the above IBlock */ static unsigned int compute_chk_offset (unsigned int depth, uint64_t end_offset) { uint64_t bds; unsigned int ret; bds = GNUNET_FS_tree_compute_tree_size (depth); if (depth > 0) end_offset--; /* round down since for depth > 0 offset is at the END of the block */ ret = end_offset / bds; return ret % CHK_PER_INODE; } /** * Encrypt the next block of the file (and call proc and progress * accordingly; or of course "cont" if we have already completed * encoding of the entire file). * * @param te tree encoder to use */ void GNUNET_FS_tree_encoder_next (struct GNUNET_FS_TreeEncoder *te) { struct ContentHashKey *mychk; const void *pt_block; uint16_t pt_size; char iob[DBLOCK_SIZE]; char enc[DBLOCK_SIZE]; struct GNUNET_CRYPTO_AesSessionKey sk; struct GNUNET_CRYPTO_AesInitializationVector iv; unsigned int off; GNUNET_assert (GNUNET_NO == te->in_next); te->in_next = GNUNET_YES; if (te->chk_tree_depth == te->current_depth) { off = CHK_PER_INODE * (te->chk_tree_depth - 1); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TE done, reading CHK `%s' from %u\n", GNUNET_h2s (&te->chk_tree[off].query), off); te->uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); te->uri->type = chk; te->uri->data.chk.chk = te->chk_tree[off]; te->uri->data.chk.file_length = GNUNET_htonll (te->size); te->in_next = GNUNET_NO; te->cont (te->cls, NULL); return; } if (0 == te->current_depth) { /* read DBLOCK */ pt_size = GNUNET_MIN (DBLOCK_SIZE, te->size - te->publish_offset); if (pt_size != te->reader (te->cls, te->publish_offset, pt_size, iob, &te->emsg)) { te->in_next = GNUNET_NO; te->cont (te->cls, NULL); return; } pt_block = iob; } else { pt_size = GNUNET_FS_tree_compute_iblock_size (te->current_depth, te->publish_offset); pt_block = &te->chk_tree[(te->current_depth - 1) * CHK_PER_INODE]; } off = compute_chk_offset (te->current_depth, te->publish_offset); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TE is at offset %llu and depth %u with block size %u and target-CHK-offset %u\n", (unsigned long long) te->publish_offset, te->current_depth, (unsigned int) pt_size, (unsigned int) off); mychk = &te->chk_tree[te->current_depth * CHK_PER_INODE + off]; GNUNET_CRYPTO_hash (pt_block, pt_size, &mychk->key); GNUNET_CRYPTO_hash_to_aes_key (&mychk->key, &sk, &iv); GNUNET_CRYPTO_aes_encrypt (pt_block, pt_size, &sk, &iv, enc); GNUNET_CRYPTO_hash (enc, pt_size, &mychk->query); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TE calculates query to be `%s', stored at %u\n", GNUNET_h2s (&mychk->query), te->current_depth * CHK_PER_INODE + off); if (NULL != te->proc) te->proc (te->cls, mychk, te->publish_offset, te->current_depth, (0 == te->current_depth) ? GNUNET_BLOCK_TYPE_FS_DBLOCK : GNUNET_BLOCK_TYPE_FS_IBLOCK, enc, pt_size); if (NULL != te->progress) te->progress (te->cls, te->publish_offset, pt_block, pt_size, te->current_depth); if (0 == te->current_depth) { te->publish_offset += pt_size; if ((te->publish_offset == te->size) || (0 == te->publish_offset % (CHK_PER_INODE * DBLOCK_SIZE))) te->current_depth++; } else { if ((off == CHK_PER_INODE) || (te->publish_offset == te->size)) te->current_depth++; else te->current_depth = 0; } te->in_next = GNUNET_NO; } /** * Clean up a tree encoder and return information * about the resulting URI or an error message. * * @param te the tree encoder to clean up * @param uri set to the resulting URI (if encoding finished) * @param emsg set to an error message (if an error occured * within the tree encoder; if this function is called * prior to completion and prior to an internal error, * both "*uri" and "*emsg" will be set to NULL). */ void GNUNET_FS_tree_encoder_finish (struct GNUNET_FS_TreeEncoder *te, struct GNUNET_FS_Uri **uri, char **emsg) { (void) te->reader (te->cls, UINT64_MAX, 0, 0, NULL); GNUNET_assert (GNUNET_NO == te->in_next); if (uri != NULL) *uri = te->uri; else if (NULL != te->uri) GNUNET_FS_uri_destroy (te->uri); if (emsg != NULL) *emsg = te->emsg; else GNUNET_free_non_null (te->emsg); GNUNET_free (te->chk_tree); GNUNET_free (te); } /* end of fs_tree.c */ gnunet-0.9.3/src/fs/test_gnunet_service_fs_migration.c0000644000175000017500000001422411760502551020134 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/test_gnunet_service_fs_migration.c * @brief test content migration between two peers * @author Christian Grothoff */ #include "platform.h" #include "fs_test_lib.h" #include "gnunet_testing_lib.h" #define VERBOSE GNUNET_NO /** * File-size we use for testing. */ #define FILESIZE (2 * 32 * 1024) /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) /** * How long do we give the peers for content migration? */ #define MIGRATION_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 90) #define SEED 42 static struct GNUNET_FS_TestDaemon *daemons[2]; static int ok; static struct GNUNET_TIME_Absolute start_time; static struct GNUNET_FS_TEST_ConnectContext *cc; static void do_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TIME_Relative del; char *fancy; if (NULL != cc) { GNUNET_FS_TEST_daemons_connect_cancel (cc); cc = NULL; } GNUNET_FS_TEST_daemons_stop (2, daemons); if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) { del = GNUNET_TIME_absolute_get_duration (start_time); if (del.rel_value == 0) del.rel_value = 1; fancy = GNUNET_STRINGS_byte_size_fancy (((unsigned long long) FILESIZE) * 1000LL / del.rel_value); FPRINTF (stdout, "Download speed was %s/s\n", fancy); GNUNET_free (fancy); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished download, shutting down\n", (unsigned long long) FILESIZE); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout during download, shutting down with error\n"); ok = 1; } } static void do_download (void *cls, const char *emsg) { struct GNUNET_FS_Uri *uri = cls; if (emsg != NULL) { GNUNET_FS_TEST_daemons_stop (2, daemons); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to stop source daemon: %s\n", emsg); GNUNET_FS_uri_destroy (uri); ok = 1; return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Downloading %llu bytes\n", (unsigned long long) FILESIZE); start_time = GNUNET_TIME_absolute_get (); GNUNET_FS_TEST_download (daemons[0], TIMEOUT, 1, SEED, uri, VERBOSE, &do_stop, NULL); GNUNET_FS_uri_destroy (uri); } static void stop_source_peer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FS_Uri *uri = cls; struct GNUNET_TESTING_PeerGroup *pg; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping source peer\n"); pg = GNUNET_FS_TEST_get_group (daemons); GNUNET_TESTING_daemons_vary (pg, 1, GNUNET_NO, TIMEOUT, &do_download, uri); } static void do_wait (void *cls, const struct GNUNET_FS_Uri *uri) { struct GNUNET_FS_Uri *d; if (NULL == uri) { GNUNET_FS_TEST_daemons_stop (2, daemons); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout during upload attempt, shutting down with error\n"); ok = 1; return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Waiting to allow content to migrate\n"); d = GNUNET_FS_uri_dup (uri); (void) GNUNET_SCHEDULER_add_delayed (MIGRATION_DELAY, &stop_source_peer, d); } static void do_publish (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { cc = NULL; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) { GNUNET_FS_TEST_daemons_stop (2, daemons); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout during connect attempt, shutting down with error\n"); ok = 1; return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing %llu bytes\n", (unsigned long long) FILESIZE); GNUNET_FS_TEST_publish (daemons[1], TIMEOUT, 1, GNUNET_NO, FILESIZE, SEED, VERBOSE, &do_wait, NULL); } static void do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) { FPRINTF (stderr, "%s", "Daemons failed to start!\n"); GNUNET_break (0); ok = 1; return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemons started, will now try to connect them\n"); cc = GNUNET_FS_TEST_daemons_connect (daemons[0], daemons[1], TIMEOUT, &do_publish, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { GNUNET_FS_TEST_daemons_start ("test_gnunet_service_fs_migration_data.conf", TIMEOUT, 2, daemons, &do_connect, NULL); } int main (int argc, char *argv[]) { char *const argvx[] = { "test-gnunet-service-fs-migration", "-c", "fs_test_lib_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_DISK_directory_remove ("/tmp/test-gnunet-service-fs-migration/"); GNUNET_log_setup ("test_gnunet_service_fs_migration", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "test-gnunet-service-fs-migration", "nohelp", options, &run, NULL); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-service-fs-migration/"); return ok; } /* end of test_gnunet_service_fs_migration.c */ gnunet-0.9.3/src/fs/fs_api.c0000644000175000017500000025263411760502551012566 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs_api.c * @brief main FS functions (master initialization, serialization, deserialization, shared code) * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_fs_service.h" #include "fs_api.h" #include "fs_tree.h" /** * How many block requests can we have outstanding in parallel at a time by default? */ #define DEFAULT_MAX_PARALLEL_REQUESTS (1024 * 10) /** * How many downloads can we have outstanding in parallel at a time by default? */ #define DEFAULT_MAX_PARALLEL_DOWNLOADS 16 /** * Start the given job (send signal, remove from pending queue, update * counters and state). * * @param qe job to start */ static void start_job (struct GNUNET_FS_QueueEntry *qe) { GNUNET_assert (NULL == qe->client); qe->client = GNUNET_CLIENT_connect ("fs", qe->h->cfg); if (qe->client == NULL) { GNUNET_break (0); return; } qe->start (qe->cls, qe->client); qe->start_times++; qe->h->active_blocks += qe->blocks; qe->start_time = GNUNET_TIME_absolute_get (); GNUNET_CONTAINER_DLL_remove (qe->h->pending_head, qe->h->pending_tail, qe); GNUNET_CONTAINER_DLL_insert_after (qe->h->running_head, qe->h->running_tail, qe->h->running_tail, qe); } /** * Stop the given job (send signal, remove from active queue, update * counters and state). * * @param qe job to stop */ static void stop_job (struct GNUNET_FS_QueueEntry *qe) { qe->client = NULL; qe->stop (qe->cls); qe->h->active_downloads--; qe->h->active_blocks -= qe->blocks; qe->run_time = GNUNET_TIME_relative_add (qe->run_time, GNUNET_TIME_absolute_get_duration (qe->start_time)); GNUNET_CONTAINER_DLL_remove (qe->h->running_head, qe->h->running_tail, qe); GNUNET_CONTAINER_DLL_insert_after (qe->h->pending_head, qe->h->pending_tail, qe->h->pending_tail, qe); } /** * Process the jobs in the job queue, possibly starting some * and stopping others. * * @param cls the 'struct GNUNET_FS_Handle' * @param tc scheduler context */ static void process_job_queue (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FS_Handle *h = cls; struct GNUNET_FS_QueueEntry *qe; struct GNUNET_FS_QueueEntry *next; struct GNUNET_TIME_Relative run_time; struct GNUNET_TIME_Relative restart_at; struct GNUNET_TIME_Relative rst; struct GNUNET_TIME_Absolute end_time; h->queue_job = GNUNET_SCHEDULER_NO_TASK; restart_at = GNUNET_TIME_UNIT_FOREVER_REL; /* first, see if we can start all the jobs */ next = h->pending_head; while (NULL != (qe = next)) { next = qe->next; if (h->running_head == NULL) { start_job (qe); continue; } if ((qe->blocks + h->active_blocks <= h->max_parallel_requests) && (h->active_downloads < h->max_parallel_downloads)) { start_job (qe); continue; } } if (h->pending_head == NULL) return; /* no need to stop anything */ /* then, check if we should stop some jobs */ next = h->running_head; while (NULL != (qe = next)) { next = qe->next; run_time = GNUNET_TIME_relative_multiply (h->avg_block_latency, qe->blocks * qe->start_times); switch (qe->priority) { case GNUNET_FS_QUEUE_PRIORITY_PROBE: /* run probes for at most 1s * number-of-restarts; note that as the total runtime of a probe is limited to 2m, we don't need to additionally limit the total time of a probe to strictly limit its lifetime. */ run_time = GNUNET_TIME_relative_min (run_time, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1 + qe->start_times)); break; case GNUNET_FS_QUEUE_PRIORITY_NORMAL: break; default: GNUNET_break (0); } end_time = GNUNET_TIME_absolute_add (qe->start_time, run_time); rst = GNUNET_TIME_absolute_get_remaining (end_time); restart_at = GNUNET_TIME_relative_min (rst, restart_at); if (rst.rel_value > 0) continue; stop_job (qe); } /* finally, start some more tasks if we now have empty slots */ next = h->pending_head; while (NULL != (qe = next)) { next = qe->next; if ((qe->blocks + h->active_blocks <= h->max_parallel_requests) && (h->active_downloads < h->max_parallel_downloads)) { start_job (qe); continue; } } h->queue_job = GNUNET_SCHEDULER_add_delayed (restart_at, &process_job_queue, h); } /** * Add a job to the queue. * * @param h handle to the overall FS state * @param start function to call to begin the job * @param stop function to call to pause the job, or on dequeue (if the job was running) * @param cls closure for start and stop * @param blocks number of blocks this jobs uses * @param priority how important is this download * @return queue handle */ struct GNUNET_FS_QueueEntry * GNUNET_FS_queue_ (struct GNUNET_FS_Handle *h, GNUNET_FS_QueueStart start, GNUNET_FS_QueueStop stop, void *cls, unsigned int blocks, enum GNUNET_FS_QueuePriority priority) { struct GNUNET_FS_QueueEntry *qe; qe = GNUNET_malloc (sizeof (struct GNUNET_FS_QueueEntry)); qe->h = h; qe->start = start; qe->stop = stop; qe->cls = cls; qe->queue_time = GNUNET_TIME_absolute_get (); qe->blocks = blocks; qe->priority = priority; GNUNET_CONTAINER_DLL_insert_after (h->pending_head, h->pending_tail, h->pending_tail, qe); if (h->queue_job != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (h->queue_job); h->queue_job = GNUNET_SCHEDULER_add_now (&process_job_queue, h); return qe; } /** * Dequeue a job from the queue. * @param qh handle for the job */ void GNUNET_FS_dequeue_ (struct GNUNET_FS_QueueEntry *qh) { struct GNUNET_FS_Handle *h; h = qh->h; if (qh->client != NULL) stop_job (qh); GNUNET_CONTAINER_DLL_remove (h->pending_head, h->pending_tail, qh); GNUNET_free (qh); if (h->queue_job != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (h->queue_job); h->queue_job = GNUNET_SCHEDULER_add_now (&process_job_queue, h); } /** * Create a top-level activity entry. * * @param h global fs handle * @param ssf suspend signal function to use * @param ssf_cls closure for ssf * @return fresh top-level activity handle */ struct TopLevelActivity * GNUNET_FS_make_top (struct GNUNET_FS_Handle *h, SuspendSignalFunction ssf, void *ssf_cls) { struct TopLevelActivity *ret; ret = GNUNET_malloc (sizeof (struct TopLevelActivity)); ret->ssf = ssf; ret->ssf_cls = ssf_cls; GNUNET_CONTAINER_DLL_insert (h->top_head, h->top_tail, ret); return ret; } /** * Destroy a top-level activity entry. * * @param h global fs handle * @param top top level activity entry */ void GNUNET_FS_end_top (struct GNUNET_FS_Handle *h, struct TopLevelActivity *top) { GNUNET_CONTAINER_DLL_remove (h->top_head, h->top_tail, top); GNUNET_free (top); } /** * Closure for "data_reader_file". */ struct FileInfo { /** * Name of the file to read. */ char *filename; /** * File descriptor, NULL if it has not yet been opened. */ struct GNUNET_DISK_FileHandle *fd; }; /** * Function that provides data by reading from a file. * * @param cls closure (points to the file information) * @param offset offset to read from; it is possible * that the caller might need to go backwards * a bit at times; set to UINT64_MAX to tell * the reader that we won't be reading for a while * (used to close the file descriptor but NOT fully * clean up the reader's state); in this case, * a value of '0' for max should be ignored * @param max maximum number of bytes that should be * copied to buf; readers are not allowed * to provide less data unless there is an error; * a value of "0" will be used at the end to allow * the reader to clean up its internal state * @param buf where the reader should write the data * @param emsg location for the reader to store an error message * @return number of bytes written, usually "max", 0 on error */ size_t GNUNET_FS_data_reader_file_ (void *cls, uint64_t offset, size_t max, void *buf, char **emsg) { struct FileInfo *fi = cls; ssize_t ret; if (UINT64_MAX == offset) { if (NULL != fi->fd) { GNUNET_DISK_file_close (fi->fd); fi->fd = NULL; } return 0; } if (0 == max) { if (NULL != fi->fd) GNUNET_DISK_file_close (fi->fd); GNUNET_free (fi->filename); GNUNET_free (fi); return 0; } if (NULL == fi->fd) { fi->fd = GNUNET_DISK_file_open (fi->filename, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); if (NULL == fi->fd) { GNUNET_asprintf (emsg, _("Could not open file `%s': %s"), fi->filename, STRERROR (errno)); return 0; } } GNUNET_DISK_file_seek (fi->fd, offset, GNUNET_DISK_SEEK_SET); ret = GNUNET_DISK_file_read (fi->fd, buf, max); if (-1 == ret) { GNUNET_asprintf (emsg, _("Could not read file `%s': %s"), fi->filename, STRERROR (errno)); return 0; } if (ret != max) { GNUNET_asprintf (emsg, _("Short read reading from file `%s'!"), fi->filename); return 0; } return max; } /** * Create the closure for the 'GNUNET_FS_data_reader_file_' callback. * * @param filename file to read * @return closure to use, NULL on error */ void * GNUNET_FS_make_file_reader_context_ (const char *filename) { struct FileInfo *fi; fi = GNUNET_malloc (sizeof (struct FileInfo)); fi->filename = GNUNET_STRINGS_filename_expand (filename); if (fi->filename == NULL) { GNUNET_free (fi); return NULL; } return fi; } /** * Function that provides data by copying from a buffer. * * @param cls closure (points to the buffer) * @param offset offset to read from; it is possible * that the caller might need to go backwards * a bit at times; set to UINT64_MAX to tell * the reader that we won't be reading for a while * (used to close the file descriptor but NOT fully * clean up the reader's state); in this case, * a value of '0' for max should be ignored * @param max maximum number of bytes that should be * copied to buf; readers are not allowed * to provide less data unless there is an error; * a value of "0" will be used at the end to allow * the reader to clean up its internal state * @param buf where the reader should write the data * @param emsg location for the reader to store an error message * @return number of bytes written, usually "max", 0 on error */ size_t GNUNET_FS_data_reader_copy_ (void *cls, uint64_t offset, size_t max, void *buf, char **emsg) { char *data = cls; if (UINT64_MAX == offset) return 0; if (max == 0) { GNUNET_free_non_null (data); return 0; } memcpy (buf, &data[offset], max); return max; } /** * Return the full filename where we would store state information * (for serialization/deserialization). * * @param h master context * @param ext component of the path * @param ent entity identifier (or emtpy string for the directory) * @return NULL on error */ static char * get_serialization_file_name (struct GNUNET_FS_Handle *h, const char *ext, const char *ent) { char *basename; char *ret; if (0 == (h->flags & GNUNET_FS_FLAGS_PERSISTENCE)) return NULL; /* persistence not requested */ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (h->cfg, "fs", "STATE_DIR", &basename)) return NULL; GNUNET_asprintf (&ret, "%s%s%s%s%s%s%s", basename, DIR_SEPARATOR_STR, h->client_name, DIR_SEPARATOR_STR, ext, DIR_SEPARATOR_STR, ent); GNUNET_free (basename); return ret; } /** * Return the full filename where we would store state information * (for serialization/deserialization) that is associated with a * parent operation. * * @param h master context * @param ext component of the path * @param uni name of the parent operation * @param ent entity identifier (or emtpy string for the directory) * @return NULL on error */ static char * get_serialization_file_name_in_dir (struct GNUNET_FS_Handle *h, const char *ext, const char *uni, const char *ent) { char *basename; char *ret; if (0 == (h->flags & GNUNET_FS_FLAGS_PERSISTENCE)) return NULL; /* persistence not requested */ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (h->cfg, "fs", "STATE_DIR", &basename)) return NULL; GNUNET_asprintf (&ret, "%s%s%s%s%s%s%s.dir%s%s", basename, DIR_SEPARATOR_STR, h->client_name, DIR_SEPARATOR_STR, ext, DIR_SEPARATOR_STR, uni, DIR_SEPARATOR_STR, ent); GNUNET_free (basename); return ret; } /** * Return a read handle for deserialization. * * @param h master context * @param ext component of the path * @param ent entity identifier (or emtpy string for the directory) * @return NULL on error */ static struct GNUNET_BIO_ReadHandle * get_read_handle (struct GNUNET_FS_Handle *h, const char *ext, const char *ent) { char *fn; struct GNUNET_BIO_ReadHandle *ret; fn = get_serialization_file_name (h, ext, ent); if (fn == NULL) return NULL; ret = GNUNET_BIO_read_open (fn); GNUNET_free (fn); return ret; } /** * Return a write handle for serialization. * * @param h master context * @param ext component of the path * @param ent entity identifier (or emtpy string for the directory) * @return NULL on error */ static struct GNUNET_BIO_WriteHandle * get_write_handle (struct GNUNET_FS_Handle *h, const char *ext, const char *ent) { char *fn; struct GNUNET_BIO_WriteHandle *ret; fn = get_serialization_file_name (h, ext, ent); if (fn == NULL) { return NULL; } ret = GNUNET_BIO_write_open (fn); if (ret == NULL) GNUNET_break (0); GNUNET_free (fn); return ret; } /** * Return a write handle for serialization. * * @param h master context * @param ext component of the path * @param uni name of parent * @param ent entity identifier (or emtpy string for the directory) * @return NULL on error */ static struct GNUNET_BIO_WriteHandle * get_write_handle_in_dir (struct GNUNET_FS_Handle *h, const char *ext, const char *uni, const char *ent) { char *fn; struct GNUNET_BIO_WriteHandle *ret; fn = get_serialization_file_name_in_dir (h, ext, uni, ent); if (fn == NULL) return NULL; ret = GNUNET_BIO_write_open (fn); GNUNET_free (fn); return ret; } /** * Remove serialization/deserialization file from disk. * * @param h master context * @param ext component of the path * @param ent entity identifier */ void GNUNET_FS_remove_sync_file_ (struct GNUNET_FS_Handle *h, const char *ext, const char *ent) { char *filename; if ((NULL == ent) || (0 == strlen (ent))) { GNUNET_break (0); return; } filename = get_serialization_file_name (h, ext, ent); if (filename != NULL) { if (0 != UNLINK (filename)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename); GNUNET_free (filename); } } /** * Remove serialization/deserialization file from disk. * * @param h master context * @param ext component of the path * @param uni parent name * @param ent entity identifier */ static void remove_sync_file_in_dir (struct GNUNET_FS_Handle *h, const char *ext, const char *uni, const char *ent) { char *filename; if ((NULL == ent) || (0 == strlen (ent))) { GNUNET_break (0); return; } filename = get_serialization_file_name_in_dir (h, ext, uni, ent); if (filename != NULL) { if (0 != UNLINK (filename)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename); GNUNET_free (filename); } } /** * Remove serialization/deserialization directory from disk. * * @param h master context * @param ext component of the path * @param uni unique name of parent */ void GNUNET_FS_remove_sync_dir_ (struct GNUNET_FS_Handle *h, const char *ext, const char *uni) { char *dn; if (uni == NULL) return; dn = get_serialization_file_name_in_dir (h, ext, uni, ""); if (dn == NULL) return; if ((GNUNET_OK == GNUNET_DISK_directory_test (dn)) && (GNUNET_OK != GNUNET_DISK_directory_remove (dn))) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "rmdir", dn); GNUNET_free (dn); } /** * Serialize a 'start_time'. Since we use start-times to * calculate the duration of some operation, we actually * do not serialize the absolute time but the (relative) * duration since the start time. When we then * deserialize the start time, we take the current time and * subtract that duration so that we get again an absolute * time stamp that will result in correct performance * calculations. * * @param wh handle for writing * @param timestamp time to serialize * @return GNUNET_OK on success */ static int write_start_time (struct GNUNET_BIO_WriteHandle *wh, struct GNUNET_TIME_Absolute timestamp) { struct GNUNET_TIME_Relative dur; dur = GNUNET_TIME_absolute_get_duration (timestamp); return GNUNET_BIO_write_int64 (wh, dur.rel_value); } /** * Serialize a 'start_time'. Since we use start-times to * calculate the duration of some operation, we actually * do not serialize the absolute time but the (relative) * duration since the start time. When we then * deserialize the start time, we take the current time and * subtract that duration so that we get again an absolute * time stamp that will result in correct performance * calculations. * * @param rh handle for reading * @param timestamp where to write the deserialized timestamp * @return GNUNET_OK on success */ static int read_start_time (struct GNUNET_BIO_ReadHandle *rh, struct GNUNET_TIME_Absolute *timestamp) { struct GNUNET_TIME_Relative dur; if (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &dur.rel_value)) return GNUNET_SYSERR; *timestamp = GNUNET_TIME_absolute_subtract (GNUNET_TIME_absolute_get (), dur); return GNUNET_OK; } /** * Using the given serialization filename, try to deserialize * the file-information tree associated with it. * * @param h master context * @param filename name of the file (without directory) with * the infromation * @return NULL on error */ static struct GNUNET_FS_FileInformation * deserialize_file_information (struct GNUNET_FS_Handle *h, const char *filename); /** * Using the given serialization filename, try to deserialize * the file-information tree associated with it. * * @param h master context * @param fn name of the file (without directory) with * the infromation * @param rh handle for reading * @return NULL on error */ static struct GNUNET_FS_FileInformation * deserialize_fi_node (struct GNUNET_FS_Handle *h, const char *fn, struct GNUNET_BIO_ReadHandle *rh) { struct GNUNET_FS_FileInformation *ret; struct GNUNET_FS_FileInformation *nxt; char b; char *ksks; char *chks; char *filename; uint32_t dsize; if (GNUNET_OK != GNUNET_BIO_read (rh, "status flag", &b, sizeof (b))) { GNUNET_break (0); return NULL; } ret = GNUNET_malloc (sizeof (struct GNUNET_FS_FileInformation)); ret->h = h; ksks = NULL; chks = NULL; filename = NULL; if ((GNUNET_OK != GNUNET_BIO_read_meta_data (rh, "metadata", &ret->meta)) || (GNUNET_OK != GNUNET_BIO_read_string (rh, "ksk-uri", &ksks, 32 * 1024)) || ( (NULL != ksks) && ( (NULL == (ret->keywords = GNUNET_FS_uri_parse (ksks, NULL))) || (GNUNET_YES != GNUNET_FS_uri_test_ksk (ret->keywords)) ) ) || (GNUNET_OK != GNUNET_BIO_read_string (rh, "chk-uri", &chks, 1024)) || ( (NULL != chks) && ( (NULL == (ret->chk_uri = GNUNET_FS_uri_parse (chks, NULL))) || (GNUNET_YES != GNUNET_FS_uri_test_chk (ret->chk_uri))) ) || (GNUNET_OK != read_start_time (rh, &ret->start_time)) || (GNUNET_OK != GNUNET_BIO_read_string (rh, "emsg", &ret->emsg, 16 * 1024)) || (GNUNET_OK != GNUNET_BIO_read_string (rh, "fn", &ret->filename, 16 * 1024)) || (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &ret->bo.expiration_time.abs_value)) || (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &ret->bo.anonymity_level)) || (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &ret->bo.content_priority)) || (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &ret->bo.replication_level))) { GNUNET_break (0); goto cleanup; } switch (b) { case 0: /* file-insert */ if (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &ret->data.file.file_size)) { GNUNET_break (0); goto cleanup; } ret->is_directory = GNUNET_NO; ret->data.file.do_index = GNUNET_NO; ret->data.file.have_hash = GNUNET_NO; ret->data.file.index_start_confirmed = GNUNET_NO; if (GNUNET_NO == ret->is_published) { if (NULL == ret->filename) { ret->data.file.reader = &GNUNET_FS_data_reader_copy_; ret->data.file.reader_cls = GNUNET_malloc_large (ret->data.file.file_size); if (ret->data.file.reader_cls == NULL) goto cleanup; if (GNUNET_OK != GNUNET_BIO_read (rh, "file-data", ret->data.file.reader_cls, ret->data.file.file_size)) { GNUNET_break (0); goto cleanup; } } else { ret->data.file.reader = &GNUNET_FS_data_reader_file_; ret->data.file.reader_cls = GNUNET_FS_make_file_reader_context_ (ret->filename); } } break; case 1: /* file-index, no hash */ if (NULL == ret->filename) { GNUNET_break (0); goto cleanup; } if (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &ret->data.file.file_size)) { GNUNET_break (0); goto cleanup; } ret->is_directory = GNUNET_NO; ret->data.file.do_index = GNUNET_YES; ret->data.file.have_hash = GNUNET_NO; ret->data.file.index_start_confirmed = GNUNET_NO; ret->data.file.reader = &GNUNET_FS_data_reader_file_; ret->data.file.reader_cls = GNUNET_FS_make_file_reader_context_ (ret->filename); break; case 2: /* file-index-with-hash */ if (NULL == ret->filename) { GNUNET_break (0); goto cleanup; } if ((GNUNET_OK != GNUNET_BIO_read_int64 (rh, &ret->data.file.file_size)) || (GNUNET_OK != GNUNET_BIO_read (rh, "fileid", &ret->data.file.file_id, sizeof (GNUNET_HashCode)))) { GNUNET_break (0); goto cleanup; } ret->is_directory = GNUNET_NO; ret->data.file.do_index = GNUNET_YES; ret->data.file.have_hash = GNUNET_YES; ret->data.file.index_start_confirmed = GNUNET_NO; ret->data.file.reader = &GNUNET_FS_data_reader_file_; ret->data.file.reader_cls = GNUNET_FS_make_file_reader_context_ (ret->filename); break; case 3: /* file-index-with-hash-confirmed */ if (NULL == ret->filename) { GNUNET_break (0); goto cleanup; } if ((GNUNET_OK != GNUNET_BIO_read_int64 (rh, &ret->data.file.file_size)) || (GNUNET_OK != GNUNET_BIO_read (rh, "fileid", &ret->data.file.file_id, sizeof (GNUNET_HashCode)))) { GNUNET_break (0); goto cleanup; } ret->is_directory = GNUNET_NO; ret->data.file.do_index = GNUNET_YES; ret->data.file.have_hash = GNUNET_YES; ret->data.file.index_start_confirmed = GNUNET_YES; ret->data.file.reader = &GNUNET_FS_data_reader_file_; ret->data.file.reader_cls = GNUNET_FS_make_file_reader_context_ (ret->filename); break; case 4: /* directory */ ret->is_directory = GNUNET_YES; if ((GNUNET_OK != GNUNET_BIO_read_int32 (rh, &dsize)) || (NULL == (ret->data.dir.dir_data = GNUNET_malloc_large (dsize))) || (GNUNET_OK != GNUNET_BIO_read (rh, "dir-data", ret->data.dir.dir_data, dsize)) || (GNUNET_OK != GNUNET_BIO_read_string (rh, "ent-filename", &filename, 16 * 1024))) { GNUNET_break (0); goto cleanup; } ret->data.dir.dir_size = (uint32_t) dsize; if (filename != NULL) { ret->data.dir.entries = deserialize_file_information (h, filename); GNUNET_free (filename); filename = NULL; nxt = ret->data.dir.entries; while (nxt != NULL) { nxt->dir = ret; nxt = nxt->next; } } break; default: GNUNET_break (0); goto cleanup; } ret->serialization = GNUNET_strdup (fn); if (GNUNET_OK != GNUNET_BIO_read_string (rh, "nxt-filename", &filename, 16 * 1024)) { GNUNET_break (0); goto cleanup; } if (filename != NULL) { ret->next = deserialize_file_information (h, filename); GNUNET_free (filename); filename = NULL; } GNUNET_free_non_null (ksks); GNUNET_free_non_null (chks); return ret; cleanup: GNUNET_free_non_null (ksks); GNUNET_free_non_null (chks); GNUNET_free_non_null (filename); GNUNET_FS_file_information_destroy (ret, NULL, NULL); return NULL; } /** * Using the given serialization filename, try to deserialize * the file-information tree associated with it. * * @param h master context * @param filename name of the file (without directory) with * the infromation * @return NULL on error */ static struct GNUNET_FS_FileInformation * deserialize_file_information (struct GNUNET_FS_Handle *h, const char *filename) { struct GNUNET_FS_FileInformation *ret; struct GNUNET_BIO_ReadHandle *rh; char *emsg; rh = get_read_handle (h, GNUNET_FS_SYNC_PATH_FILE_INFO, filename); if (rh == NULL) return NULL; ret = deserialize_fi_node (h, filename, rh); if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to resume publishing information `%s': %s\n"), filename, emsg); GNUNET_free (emsg); } if (ret == NULL) { if (0 != UNLINK (filename)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename); } return ret; } /** * Given a serialization name (full absolute path), return the * basename of the file (without the path), which must only * consist of the 6 random characters. * * @param fullname name to extract the basename from * @return copy of the basename, NULL on error */ static char * get_serialization_short_name (const char *fullname) { const char *end; const char *nxt; end = NULL; nxt = fullname; /* FIXME: we could do this faster since we know * the length of 'end'... */ while ('\0' != *nxt) { if (DIR_SEPARATOR == *nxt) end = nxt + 1; nxt++; } if ((end == NULL) || (strlen (end) == 0)) { GNUNET_break (0); return NULL; } GNUNET_break (6 == strlen (end)); return GNUNET_strdup (end); } /** * Create a new random name for serialization. Also checks if persistence * is enabled and returns NULL if not. * * @param h master context * @param ext component of the path * @return NULL on errror */ static char * make_serialization_file_name (struct GNUNET_FS_Handle *h, const char *ext) { char *fn; char *dn; char *ret; if (0 == (h->flags & GNUNET_FS_FLAGS_PERSISTENCE)) return NULL; /* persistence not requested */ dn = get_serialization_file_name (h, ext, ""); if (dn == NULL) return NULL; if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (dn)) { GNUNET_free (dn); return NULL; } fn = GNUNET_DISK_mktemp (dn); GNUNET_free (dn); if (fn == NULL) return NULL; /* epic fail */ ret = get_serialization_short_name (fn); GNUNET_free (fn); return ret; } /** * Create a new random name for serialization. Also checks if persistence * is enabled and returns NULL if not. * * @param h master context * @param ext component of the path * @param uni name of parent * @return NULL on errror */ static char * make_serialization_file_name_in_dir (struct GNUNET_FS_Handle *h, const char *ext, const char *uni) { char *fn; char *dn; char *ret; if (0 == (h->flags & GNUNET_FS_FLAGS_PERSISTENCE)) return NULL; /* persistence not requested */ dn = get_serialization_file_name_in_dir (h, ext, uni, ""); if (dn == NULL) return NULL; if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (dn)) { GNUNET_free (dn); return NULL; } fn = GNUNET_DISK_mktemp (dn); GNUNET_free (dn); if (fn == NULL) return NULL; /* epic fail */ ret = get_serialization_short_name (fn); GNUNET_free (fn); return ret; } /** * Copy all of the data from the reader to the write handle. * * @param wh write handle * @param fi file with reader * @return GNUNET_OK on success */ static int copy_from_reader (struct GNUNET_BIO_WriteHandle *wh, struct GNUNET_FS_FileInformation *fi) { char buf[32 * 1024]; uint64_t off; size_t ret; size_t left; char *emsg; emsg = NULL; off = 0; while (off < fi->data.file.file_size) { left = GNUNET_MIN (sizeof (buf), fi->data.file.file_size - off); ret = fi->data.file.reader (fi->data.file.reader_cls, off, left, buf, &emsg); if (ret == 0) { GNUNET_free (emsg); return GNUNET_SYSERR; } if (GNUNET_OK != GNUNET_BIO_write (wh, buf, ret)) return GNUNET_SYSERR; off += ret; } return GNUNET_OK; } /** * Create a temporary file on disk to store the current * state of "fi" in. * * @param fi file information to sync with disk */ void GNUNET_FS_file_information_sync_ (struct GNUNET_FS_FileInformation *fi) { char *fn; struct GNUNET_BIO_WriteHandle *wh; char b; char *ksks; char *chks; if (NULL == fi->serialization) fi->serialization = make_serialization_file_name (fi->h, GNUNET_FS_SYNC_PATH_FILE_INFO); if (NULL == fi->serialization) return; wh = get_write_handle (fi->h, GNUNET_FS_SYNC_PATH_FILE_INFO, fi->serialization); if (wh == NULL) { GNUNET_free (fi->serialization); fi->serialization = NULL; return; } if (GNUNET_YES == fi->is_directory) b = 4; else if (GNUNET_YES == fi->data.file.index_start_confirmed) b = 3; else if (GNUNET_YES == fi->data.file.have_hash) b = 2; else if (GNUNET_YES == fi->data.file.do_index) b = 1; else b = 0; if (fi->keywords != NULL) ksks = GNUNET_FS_uri_to_string (fi->keywords); else ksks = NULL; if (fi->chk_uri != NULL) chks = GNUNET_FS_uri_to_string (fi->chk_uri); else chks = NULL; if ((GNUNET_OK != GNUNET_BIO_write (wh, &b, sizeof (b))) || (GNUNET_OK != GNUNET_BIO_write_meta_data (wh, fi->meta)) || (GNUNET_OK != GNUNET_BIO_write_string (wh, ksks)) || (GNUNET_OK != GNUNET_BIO_write_string (wh, chks)) || (GNUNET_OK != write_start_time (wh, fi->start_time)) || (GNUNET_OK != GNUNET_BIO_write_string (wh, fi->emsg)) || (GNUNET_OK != GNUNET_BIO_write_string (wh, fi->filename)) || (GNUNET_OK != GNUNET_BIO_write_int64 (wh, fi->bo.expiration_time.abs_value)) || (GNUNET_OK != GNUNET_BIO_write_int32 (wh, fi->bo.anonymity_level)) || (GNUNET_OK != GNUNET_BIO_write_int32 (wh, fi->bo.content_priority)) || (GNUNET_OK != GNUNET_BIO_write_int32 (wh, fi->bo.replication_level))) { GNUNET_break (0); goto cleanup; } GNUNET_free_non_null (chks); chks = NULL; GNUNET_free_non_null (ksks); ksks = NULL; switch (b) { case 0: /* file-insert */ if (GNUNET_OK != GNUNET_BIO_write_int64 (wh, fi->data.file.file_size)) { GNUNET_break (0); goto cleanup; } if ((GNUNET_NO == fi->is_published) && (NULL == fi->filename)) if (GNUNET_OK != copy_from_reader (wh, fi)) { GNUNET_break (0); goto cleanup; } break; case 1: /* file-index, no hash */ if (NULL == fi->filename) { GNUNET_break (0); goto cleanup; } if (GNUNET_OK != GNUNET_BIO_write_int64 (wh, fi->data.file.file_size)) { GNUNET_break (0); goto cleanup; } break; case 2: /* file-index-with-hash */ case 3: /* file-index-with-hash-confirmed */ if (NULL == fi->filename) { GNUNET_break (0); goto cleanup; } if ((GNUNET_OK != GNUNET_BIO_write_int64 (wh, fi->data.file.file_size)) || (GNUNET_OK != GNUNET_BIO_write (wh, &fi->data.file.file_id, sizeof (GNUNET_HashCode)))) { GNUNET_break (0); goto cleanup; } break; case 4: /* directory */ if ((GNUNET_OK != GNUNET_BIO_write_int32 (wh, fi->data.dir.dir_size)) || (GNUNET_OK != GNUNET_BIO_write (wh, fi->data.dir.dir_data, (uint32_t) fi->data.dir.dir_size)) || (GNUNET_OK != GNUNET_BIO_write_string (wh, (fi->data.dir.entries == NULL) ? NULL : fi->data.dir. entries->serialization))) { GNUNET_break (0); goto cleanup; } break; default: GNUNET_assert (0); goto cleanup; } if (GNUNET_OK != GNUNET_BIO_write_string (wh, (fi->next != NULL) ? fi->next->serialization : NULL)) { GNUNET_break (0); goto cleanup; } if (GNUNET_OK != GNUNET_BIO_write_close (wh)) { wh = NULL; GNUNET_break (0); goto cleanup; } return; /* done! */ cleanup: if (wh != NULL) (void) GNUNET_BIO_write_close (wh); GNUNET_free_non_null (chks); GNUNET_free_non_null (ksks); fn = get_serialization_file_name (fi->h, GNUNET_FS_SYNC_PATH_FILE_INFO, fi->serialization); if (NULL != fn) { if (0 != UNLINK (fn)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn); GNUNET_free (fn); } GNUNET_free (fi->serialization); fi->serialization = NULL; } /** * Find the entry in the file information struct where the * serialization filename matches the given name. * * @param pos file information to search * @param srch filename to search for * @return NULL if srch was not found in this subtree */ static struct GNUNET_FS_FileInformation * find_file_position (struct GNUNET_FS_FileInformation *pos, const char *srch) { struct GNUNET_FS_FileInformation *r; while (pos != NULL) { if (0 == strcmp (srch, pos->serialization)) return pos; if (pos->is_directory == GNUNET_YES) { r = find_file_position (pos->data.dir.entries, srch); if (r != NULL) return r; } pos = pos->next; } return NULL; } /** * Signal the FS's progress function that we are resuming * an upload. * * @param cls closure (of type "struct GNUNET_FS_PublishContext*") * @param fi the entry in the publish-structure * @param length length of the file or directory * @param meta metadata for the file or directory (can be modified) * @param uri pointer to the keywords that will be used for this entry (can be modified) * @param bo block options (can be modified) * @param do_index should we index? * @param client_info pointer to client context set upon creation (can be modified) * @return GNUNET_OK to continue (always) */ static int fip_signal_resume (void *cls, struct GNUNET_FS_FileInformation *fi, uint64_t length, struct GNUNET_CONTAINER_MetaData *meta, struct GNUNET_FS_Uri **uri, struct GNUNET_FS_BlockOptions *bo, int *do_index, void **client_info) { struct GNUNET_FS_PublishContext *pc = cls; struct GNUNET_FS_ProgressInfo pi; if (GNUNET_YES == pc->skip_next_fi_callback) { pc->skip_next_fi_callback = GNUNET_NO; return GNUNET_OK; } pi.status = GNUNET_FS_STATUS_PUBLISH_RESUME; pi.value.publish.specifics.resume.message = pc->fi->emsg; pi.value.publish.specifics.resume.chk_uri = pc->fi->chk_uri; *client_info = GNUNET_FS_publish_make_status_ (&pi, pc, fi, 0); if (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (meta)) { /* process entries in directory */ pc->skip_next_fi_callback = GNUNET_YES; GNUNET_FS_file_information_inspect (fi, &fip_signal_resume, pc); } return GNUNET_OK; } /** * Function called with a filename of serialized publishing operation * to deserialize. * * @param cls the 'struct GNUNET_FS_Handle*' * @param filename complete filename (absolute path) * @return GNUNET_OK (continue to iterate) */ static int deserialize_publish_file (void *cls, const char *filename) { struct GNUNET_FS_Handle *h = cls; struct GNUNET_BIO_ReadHandle *rh; struct GNUNET_FS_PublishContext *pc; int32_t options; int32_t all_done; char *fi_root; char *ns; char *fi_pos; char *emsg; pc = GNUNET_malloc (sizeof (struct GNUNET_FS_PublishContext)); pc->h = h; pc->serialization = get_serialization_short_name (filename); fi_root = NULL; fi_pos = NULL; ns = NULL; rh = GNUNET_BIO_read_open (filename); if (rh == NULL) { GNUNET_break (0); goto cleanup; } if ((GNUNET_OK != GNUNET_BIO_read_string (rh, "publish-nid", &pc->nid, 1024)) || (GNUNET_OK != GNUNET_BIO_read_string (rh, "publish-nuid", &pc->nuid, 1024)) || (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &options)) || (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &all_done)) || (GNUNET_OK != GNUNET_BIO_read_string (rh, "publish-firoot", &fi_root, 128)) || (GNUNET_OK != GNUNET_BIO_read_string (rh, "publish-fipos", &fi_pos, 128)) || (GNUNET_OK != GNUNET_BIO_read_string (rh, "publish-ns", &ns, 1024))) { GNUNET_break (0); goto cleanup; } pc->options = options; pc->all_done = all_done; if (NULL == fi_root) { GNUNET_break (0); goto cleanup; } pc->fi = deserialize_file_information (h, fi_root); if (pc->fi == NULL) { GNUNET_break (0); goto cleanup; } if (ns != NULL) { pc->namespace = GNUNET_FS_namespace_create (h, ns); if (pc->namespace == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Failed to recover namespace `%s', cannot resume publishing operation.\n"), ns); goto cleanup; } } if ((0 == (pc->options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) && (GNUNET_YES != pc->all_done)) { pc->dsh = GNUNET_DATASTORE_connect (h->cfg); if (NULL == pc->dsh) goto cleanup; } if (fi_pos != NULL) { pc->fi_pos = find_file_position (pc->fi, fi_pos); GNUNET_free (fi_pos); fi_pos = NULL; if (pc->fi_pos == NULL) { /* failed to find position for resuming, outch! Will start from root! */ GNUNET_break (0); if (pc->all_done != GNUNET_YES) pc->fi_pos = pc->fi; } } GNUNET_free (fi_root); fi_root = NULL; /* generate RESUME event(s) */ GNUNET_FS_file_information_inspect (pc->fi, &fip_signal_resume, pc); /* re-start publishing (if needed)... */ if (pc->all_done != GNUNET_YES) { GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == pc->upload_task); pc->upload_task = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, &GNUNET_FS_publish_main_, pc); } if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failure while resuming publishing operation `%s': %s\n"), filename, emsg); GNUNET_free (emsg); } GNUNET_free_non_null (ns); pc->top = GNUNET_FS_make_top (h, &GNUNET_FS_publish_signal_suspend_, pc); return GNUNET_OK; cleanup: GNUNET_free_non_null (pc->nid); GNUNET_free_non_null (pc->nuid); GNUNET_free_non_null (fi_root); GNUNET_free_non_null (fi_pos); GNUNET_free_non_null (ns); if ((rh != NULL) && (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to resume publishing operation `%s': %s\n"), filename, emsg); GNUNET_free (emsg); } if (pc->fi != NULL) GNUNET_FS_file_information_destroy (pc->fi, NULL, NULL); if (0 != UNLINK (filename)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename); GNUNET_free (pc->serialization); GNUNET_free (pc); return GNUNET_OK; } /** * Synchronize this publishing struct with its mirror * on disk. Note that all internal FS-operations that change * publishing structs should already call "sync" internally, * so this function is likely not useful for clients. * * @param pc the struct to sync */ void GNUNET_FS_publish_sync_ (struct GNUNET_FS_PublishContext *pc) { struct GNUNET_BIO_WriteHandle *wh; if (NULL == pc->serialization) pc->serialization = make_serialization_file_name (pc->h, GNUNET_FS_SYNC_PATH_MASTER_PUBLISH); if (NULL == pc->serialization) return; if (NULL == pc->fi) return; if (NULL == pc->fi->serialization) { GNUNET_break (0); return; } wh = get_write_handle (pc->h, GNUNET_FS_SYNC_PATH_MASTER_PUBLISH, pc->serialization); if (wh == NULL) { GNUNET_break (0); goto cleanup; } if ((GNUNET_OK != GNUNET_BIO_write_string (wh, pc->nid)) || (GNUNET_OK != GNUNET_BIO_write_string (wh, pc->nuid)) || (GNUNET_OK != GNUNET_BIO_write_int32 (wh, pc->options)) || (GNUNET_OK != GNUNET_BIO_write_int32 (wh, pc->all_done)) || (GNUNET_OK != GNUNET_BIO_write_string (wh, pc->fi->serialization)) || (GNUNET_OK != GNUNET_BIO_write_string (wh, (pc->fi_pos == NULL) ? NULL : pc->fi_pos->serialization)) || (GNUNET_OK != GNUNET_BIO_write_string (wh, (pc->namespace == NULL) ? NULL : pc->namespace->name))) { GNUNET_break (0); goto cleanup; } if (GNUNET_OK != GNUNET_BIO_write_close (wh)) { wh = NULL; GNUNET_break (0); goto cleanup; } return; cleanup: if (wh != NULL) (void) GNUNET_BIO_write_close (wh); GNUNET_FS_remove_sync_file_ (pc->h, GNUNET_FS_SYNC_PATH_MASTER_PUBLISH, pc->serialization); GNUNET_free (pc->serialization); pc->serialization = NULL; } /** * Synchronize this unindex struct with its mirror * on disk. Note that all internal FS-operations that change * publishing structs should already call "sync" internally, * so this function is likely not useful for clients. * * @param uc the struct to sync */ void GNUNET_FS_unindex_sync_ (struct GNUNET_FS_UnindexContext *uc) { struct GNUNET_BIO_WriteHandle *wh; char *uris; if (NULL == uc->serialization) uc->serialization = make_serialization_file_name (uc->h, GNUNET_FS_SYNC_PATH_MASTER_UNINDEX); if (NULL == uc->serialization) return; wh = get_write_handle (uc->h, GNUNET_FS_SYNC_PATH_MASTER_UNINDEX, uc->serialization); if (wh == NULL) { GNUNET_break (0); goto cleanup; } if (NULL != uc->ksk_uri) uris = GNUNET_FS_uri_to_string (uc->ksk_uri); else uris = NULL; if ((GNUNET_OK != GNUNET_BIO_write_string (wh, uc->filename)) || (GNUNET_OK != GNUNET_BIO_write_int64 (wh, uc->file_size)) || (GNUNET_OK != write_start_time (wh, uc->start_time)) || (GNUNET_OK != GNUNET_BIO_write_int32 (wh, (uint32_t) uc->state)) || (GNUNET_OK != GNUNET_BIO_write (wh, &uc->chk, sizeof (struct ContentHashKey))) || (GNUNET_OK != GNUNET_BIO_write_string (wh, uris)) || (GNUNET_OK != GNUNET_BIO_write_int32 (wh, (uint32_t) uc->ksk_offset)) || ((uc->state == UNINDEX_STATE_FS_NOTIFY) && (GNUNET_OK != GNUNET_BIO_write (wh, &uc->file_id, sizeof (GNUNET_HashCode)))) || ((uc->state == UNINDEX_STATE_ERROR) && (GNUNET_OK != GNUNET_BIO_write_string (wh, uc->emsg)))) { GNUNET_break (0); goto cleanup; } if (GNUNET_OK != GNUNET_BIO_write_close (wh)) { wh = NULL; GNUNET_break (0); goto cleanup; } return; cleanup: if (wh != NULL) (void) GNUNET_BIO_write_close (wh); GNUNET_FS_remove_sync_file_ (uc->h, GNUNET_FS_SYNC_PATH_MASTER_UNINDEX, uc->serialization); GNUNET_free (uc->serialization); uc->serialization = NULL; } /** * Serialize a download request. * * @param wh the 'struct GNUNET_BIO_WriteHandle*' * @param dr the 'struct DownloadRequest' * @return GNUNET_YES on success, GNUNET_NO on error */ static int write_download_request (struct GNUNET_BIO_WriteHandle *wh, struct DownloadRequest *dr) { unsigned int i; if ((GNUNET_OK != GNUNET_BIO_write_int32 (wh, dr->state)) || (GNUNET_OK != GNUNET_BIO_write_int64 (wh, dr->offset)) || (GNUNET_OK != GNUNET_BIO_write_int32 (wh, dr->num_children)) || (GNUNET_OK != GNUNET_BIO_write_int32 (wh, dr->depth))) return GNUNET_NO; if ((dr->state == BRS_CHK_SET) && (GNUNET_OK != GNUNET_BIO_write (wh, &dr->chk, sizeof (struct ContentHashKey)))) return GNUNET_NO; for (i = 0; i < dr->num_children; i++) if (GNUNET_NO == write_download_request (wh, dr->children[i])) return GNUNET_NO; return GNUNET_YES; } /** * Read a download request tree. * * @param rh stream to read from * @return value the 'struct DownloadRequest', NULL on error */ static struct DownloadRequest * read_download_request (struct GNUNET_BIO_ReadHandle *rh) { struct DownloadRequest *dr; unsigned int i; dr = GNUNET_malloc (sizeof (struct DownloadRequest)); if ((GNUNET_OK != GNUNET_BIO_read_int32 (rh, &dr->state)) || (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &dr->offset)) || (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &dr->num_children)) || (dr->num_children > CHK_PER_INODE) || (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &dr->depth)) || ((dr->depth == 0) && (dr->num_children > 0)) || ((dr->depth > 0) && (dr->num_children == 0))) { GNUNET_break (0); dr->num_children = 0; goto cleanup; } if (dr->num_children > 0) dr->children = GNUNET_malloc (dr->num_children * sizeof (struct ContentHashKey)); switch (dr->state) { case BRS_INIT: case BRS_RECONSTRUCT_DOWN: case BRS_RECONSTRUCT_META_UP: case BRS_RECONSTRUCT_UP: break; case BRS_CHK_SET: if (GNUNET_OK != GNUNET_BIO_read (rh, "chk", &dr->chk, sizeof (struct ContentHashKey))) goto cleanup; break; case BRS_DOWNLOAD_DOWN: case BRS_DOWNLOAD_UP: case BRS_ERROR: break; default: GNUNET_break (0); goto cleanup; } for (i = 0; i < dr->num_children; i++) { if (NULL == (dr->children[i] = read_download_request (rh))) goto cleanup; dr->children[i]->parent = dr; } return dr; cleanup: GNUNET_FS_free_download_request_ (dr); return NULL; } /** * Compute the name of the sync file (or directory) for the given download * context. * * @param dc download context to compute for * @param uni unique filename to use, use "" for the directory name * @param ext extension to use, use ".dir" for our own subdirectory * @return the expanded file name, NULL for none */ static char * get_download_sync_filename (struct GNUNET_FS_DownloadContext *dc, const char *uni, const char *ext) { char *par; char *epar; if (dc->parent == NULL) return get_serialization_file_name (dc->h, (dc->search != NULL) ? GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD : GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD, uni); if (dc->parent->serialization == NULL) return NULL; par = get_download_sync_filename (dc->parent, dc->parent->serialization, ""); if (par == NULL) return NULL; GNUNET_asprintf (&epar, "%s.dir%s%s%s", par, DIR_SEPARATOR_STR, uni, ext); GNUNET_free (par); return epar; } /** * Synchronize this download struct with its mirror * on disk. Note that all internal FS-operations that change * publishing structs should already call "sync" internally, * so this function is likely not useful for clients. * * @param dc the struct to sync */ void GNUNET_FS_download_sync_ (struct GNUNET_FS_DownloadContext *dc) { struct GNUNET_BIO_WriteHandle *wh; char *uris; char *fn; char *dir; if (0 != (dc->options & GNUNET_FS_DOWNLOAD_IS_PROBE)) return; /* we don't sync probes */ if (NULL == dc->serialization) { dir = get_download_sync_filename (dc, "", ""); if (dir == NULL) return; if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (dir)) { GNUNET_free (dir); return; } fn = GNUNET_DISK_mktemp (dir); GNUNET_free (dir); if (fn == NULL) return; dc->serialization = get_serialization_short_name (fn); } else { fn = get_download_sync_filename (dc, dc->serialization, ""); if (fn == NULL) { GNUNET_free (dc->serialization); dc->serialization = NULL; GNUNET_free (fn); return; } } wh = GNUNET_BIO_write_open (fn); if (wh == NULL) { GNUNET_free (dc->serialization); dc->serialization = NULL; GNUNET_free (fn); return; } GNUNET_assert ((GNUNET_YES == GNUNET_FS_uri_test_chk (dc->uri)) || (GNUNET_YES == GNUNET_FS_uri_test_loc (dc->uri))); uris = GNUNET_FS_uri_to_string (dc->uri); if ((GNUNET_OK != GNUNET_BIO_write_string (wh, uris)) || (GNUNET_OK != GNUNET_BIO_write_meta_data (wh, dc->meta)) || (GNUNET_OK != GNUNET_BIO_write_string (wh, dc->emsg)) || (GNUNET_OK != GNUNET_BIO_write_string (wh, dc->filename)) || (GNUNET_OK != GNUNET_BIO_write_string (wh, dc->temp_filename)) || (GNUNET_OK != GNUNET_BIO_write_int64 (wh, dc->old_file_size)) || (GNUNET_OK != GNUNET_BIO_write_int64 (wh, dc->offset)) || (GNUNET_OK != GNUNET_BIO_write_int64 (wh, dc->length)) || (GNUNET_OK != GNUNET_BIO_write_int64 (wh, dc->completed)) || (GNUNET_OK != write_start_time (wh, dc->start_time)) || (GNUNET_OK != GNUNET_BIO_write_int32 (wh, dc->anonymity)) || (GNUNET_OK != GNUNET_BIO_write_int32 (wh, (uint32_t) dc->options)) || (GNUNET_OK != GNUNET_BIO_write_int32 (wh, (uint32_t) dc->has_finished))) { GNUNET_break (0); goto cleanup; } if (NULL == dc->emsg) { GNUNET_assert (dc->top_request != NULL); if (GNUNET_YES != write_download_request (wh, dc->top_request)) { GNUNET_break (0); goto cleanup; } } GNUNET_free_non_null (uris); uris = NULL; if (GNUNET_OK != GNUNET_BIO_write_close (wh)) { wh = NULL; GNUNET_break (0); goto cleanup; } GNUNET_free (fn); return; cleanup: if (NULL != wh) (void) GNUNET_BIO_write_close (wh); GNUNET_free_non_null (uris); if (0 != UNLINK (fn)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn); GNUNET_free (fn); GNUNET_free (dc->serialization); dc->serialization = NULL; } /** * Synchronize this search result with its mirror * on disk. Note that all internal FS-operations that change * publishing structs should already call "sync" internally, * so this function is likely not useful for clients. * * @param sr the struct to sync */ void GNUNET_FS_search_result_sync_ (struct GNUNET_FS_SearchResult *sr) { struct GNUNET_BIO_WriteHandle *wh; char *uris; uris = NULL; if (NULL == sr->serialization) sr->serialization = make_serialization_file_name_in_dir (sr->sc->h, (sr->sc->psearch_result == NULL) ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH : GNUNET_FS_SYNC_PATH_CHILD_SEARCH, sr->sc->serialization); if (NULL == sr->serialization) return; wh = get_write_handle_in_dir (sr->sc->h, (sr->sc->psearch_result == NULL) ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH : GNUNET_FS_SYNC_PATH_CHILD_SEARCH, sr->sc->serialization, sr->serialization); if (wh == NULL) { GNUNET_break (0); goto cleanup; } uris = GNUNET_FS_uri_to_string (sr->uri); if ((GNUNET_OK != GNUNET_BIO_write_string (wh, uris)) || (GNUNET_OK != GNUNET_BIO_write_string (wh, sr->download != NULL ? sr->download->serialization : NULL)) || (GNUNET_OK != GNUNET_BIO_write_string (wh, sr->update_search != NULL ? sr->update_search->serialization : NULL)) || (GNUNET_OK != GNUNET_BIO_write_meta_data (wh, sr->meta)) || (GNUNET_OK != GNUNET_BIO_write (wh, &sr->key, sizeof (GNUNET_HashCode))) || (GNUNET_OK != GNUNET_BIO_write_int32 (wh, sr->mandatory_missing)) || (GNUNET_OK != GNUNET_BIO_write_int32 (wh, sr->optional_support)) || (GNUNET_OK != GNUNET_BIO_write_int32 (wh, sr->availability_success)) || (GNUNET_OK != GNUNET_BIO_write_int32 (wh, sr->availability_trials)) ) { GNUNET_break (0); goto cleanup; } if ( (sr->uri != NULL) && (sr->sc->uri->type == ksk) && (GNUNET_OK != GNUNET_BIO_write (wh, sr->keyword_bitmap, (sr->sc->uri->data.ksk.keywordCount + 7) / 8)) ) { GNUNET_break (0); goto cleanup; } if (GNUNET_OK != GNUNET_BIO_write_close (wh)) { wh = NULL; GNUNET_break (0); goto cleanup; } GNUNET_free_non_null (uris); return; cleanup: GNUNET_free_non_null (uris); if (wh != NULL) (void) GNUNET_BIO_write_close (wh); remove_sync_file_in_dir (sr->sc->h, (sr->sc->psearch_result == NULL) ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH : GNUNET_FS_SYNC_PATH_CHILD_SEARCH, sr->sc->serialization, sr->serialization); GNUNET_free (sr->serialization); sr->serialization = NULL; } /** * Synchronize this search struct with its mirror * on disk. Note that all internal FS-operations that change * publishing structs should already call "sync" internally, * so this function is likely not useful for clients. * * @param sc the struct to sync */ void GNUNET_FS_search_sync_ (struct GNUNET_FS_SearchContext *sc) { struct GNUNET_BIO_WriteHandle *wh; char *uris; char in_pause; const char *category; category = (sc->psearch_result == NULL) ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH : GNUNET_FS_SYNC_PATH_CHILD_SEARCH; if (NULL == sc->serialization) sc->serialization = make_serialization_file_name (sc->h, category); if (NULL == sc->serialization) return; uris = NULL; wh = get_write_handle (sc->h, category, sc->serialization); if (wh == NULL) { GNUNET_break (0); goto cleanup; } GNUNET_assert ((GNUNET_YES == GNUNET_FS_uri_test_ksk (sc->uri)) || (GNUNET_YES == GNUNET_FS_uri_test_sks (sc->uri))); uris = GNUNET_FS_uri_to_string (sc->uri); in_pause = (sc->task != GNUNET_SCHEDULER_NO_TASK) ? 'r' : '\0'; if ((GNUNET_OK != GNUNET_BIO_write_string (wh, uris)) || (GNUNET_OK != write_start_time (wh, sc->start_time)) || (GNUNET_OK != GNUNET_BIO_write_string (wh, sc->emsg)) || (GNUNET_OK != GNUNET_BIO_write_int32 (wh, (uint32_t) sc->options)) || (GNUNET_OK != GNUNET_BIO_write (wh, &in_pause, sizeof (in_pause))) || (GNUNET_OK != GNUNET_BIO_write_int32 (wh, sc->anonymity))) { GNUNET_break (0); goto cleanup; } GNUNET_free (uris); uris = NULL; if (GNUNET_OK != GNUNET_BIO_write_close (wh)) { wh = NULL; GNUNET_break (0); goto cleanup; } return; cleanup: if (wh != NULL) (void) GNUNET_BIO_write_close (wh); GNUNET_free_non_null (uris); GNUNET_FS_remove_sync_file_ (sc->h, category, sc->serialization); GNUNET_free (sc->serialization); sc->serialization = NULL; } /** * Function called with a filename of serialized unindexing operation * to deserialize. * * @param cls the 'struct GNUNET_FS_Handle*' * @param filename complete filename (absolute path) * @return GNUNET_OK (continue to iterate) */ static int deserialize_unindex_file (void *cls, const char *filename) { struct GNUNET_FS_Handle *h = cls; struct GNUNET_BIO_ReadHandle *rh; struct GNUNET_FS_UnindexContext *uc; struct GNUNET_FS_ProgressInfo pi; char *emsg; char *uris; uint32_t state; uc = GNUNET_malloc (sizeof (struct GNUNET_FS_UnindexContext)); uc->h = h; uc->serialization = get_serialization_short_name (filename); rh = GNUNET_BIO_read_open (filename); if (rh == NULL) { GNUNET_break (0); goto cleanup; } uris = NULL; if ((GNUNET_OK != GNUNET_BIO_read_string (rh, "unindex-fn", &uc->filename, 10 * 1024)) || (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &uc->file_size)) || (GNUNET_OK != read_start_time (rh, &uc->start_time)) || (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &state)) || (GNUNET_OK != GNUNET_BIO_read (rh, "uri", &uc->chk, sizeof (struct ContentHashKey))) || (GNUNET_OK != GNUNET_BIO_read_string (rh, "unindex-kskuri", &uris, 10 * 1024)) || (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &uc->ksk_offset)) ) { GNUNET_free_non_null (uris); GNUNET_break (0); goto cleanup; } if (NULL != uris) { uc->ksk_uri = GNUNET_FS_uri_parse (uris, &emsg); GNUNET_free (uris); if (NULL == uc->ksk_uri) { GNUNET_break (0); goto cleanup; } } if ( (uc->ksk_offset > 0) && ( (NULL == uc->ksk_uri) || (uc->ksk_offset > uc->ksk_uri->data.ksk.keywordCount) ) ) { GNUNET_break (0); goto cleanup; } uc->state = (enum UnindexState) state; switch (state) { case UNINDEX_STATE_HASHING: break; case UNINDEX_STATE_FS_NOTIFY: if (GNUNET_OK != GNUNET_BIO_read (rh, "unindex-hash", &uc->file_id, sizeof (GNUNET_HashCode))) { GNUNET_break (0); goto cleanup; } break; case UNINDEX_STATE_DS_REMOVE: case UNINDEX_STATE_EXTRACT_KEYWORDS: case UNINDEX_STATE_DS_REMOVE_KBLOCKS: break; case UNINDEX_STATE_COMPLETE: break; case UNINDEX_STATE_ERROR: if (GNUNET_OK != GNUNET_BIO_read_string (rh, "unindex-emsg", &uc->emsg, 10 * 1024)) { GNUNET_break (0); goto cleanup; } break; default: GNUNET_break (0); goto cleanup; } uc->top = GNUNET_FS_make_top (h, &GNUNET_FS_unindex_signal_suspend_, uc); pi.status = GNUNET_FS_STATUS_UNINDEX_RESUME; pi.value.unindex.specifics.resume.message = uc->emsg; GNUNET_FS_unindex_make_status_ (&pi, uc, (uc->state == UNINDEX_STATE_COMPLETE) ? uc->file_size : 0); switch (uc->state) { case UNINDEX_STATE_HASHING: uc->fhc = GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE, uc->filename, HASHING_BLOCKSIZE, &GNUNET_FS_unindex_process_hash_, uc); break; case UNINDEX_STATE_FS_NOTIFY: uc->state = UNINDEX_STATE_HASHING; GNUNET_FS_unindex_process_hash_ (uc, &uc->file_id); break; case UNINDEX_STATE_DS_REMOVE: GNUNET_FS_unindex_do_remove_ (uc); break; case UNINDEX_STATE_EXTRACT_KEYWORDS: GNUNET_FS_unindex_do_extract_keywords_ (uc); break; case UNINDEX_STATE_DS_REMOVE_KBLOCKS: GNUNET_FS_unindex_do_remove_kblocks_ (uc); break; case UNINDEX_STATE_COMPLETE: case UNINDEX_STATE_ERROR: /* no need to resume any operation, we were done */ break; default: break; } if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failure while resuming unindexing operation `%s': %s\n"), filename, emsg); GNUNET_free (emsg); } return GNUNET_OK; cleanup: GNUNET_free_non_null (uc->filename); if ((rh != NULL) && (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to resume unindexing operation `%s': %s\n"), filename, emsg); GNUNET_free (emsg); } if (uc->serialization != NULL) GNUNET_FS_remove_sync_file_ (h, GNUNET_FS_SYNC_PATH_MASTER_UNINDEX, uc->serialization); GNUNET_free_non_null (uc->serialization); GNUNET_free (uc); return GNUNET_OK; } /** * Deserialize a download. * * @param h overall context * @param rh file to deserialize from * @param parent parent download * @param search associated search * @param serialization name under which the search was serialized */ static void deserialize_download (struct GNUNET_FS_Handle *h, struct GNUNET_BIO_ReadHandle *rh, struct GNUNET_FS_DownloadContext *parent, struct GNUNET_FS_SearchResult *search, const char *serialization); /** * Deserialize a search. * * @param h overall context * @param rh file to deserialize from * @param psearch_result parent search result * @param serialization name under which the search was serialized */ static struct GNUNET_FS_SearchContext * deserialize_search (struct GNUNET_FS_Handle *h, struct GNUNET_BIO_ReadHandle *rh, struct GNUNET_FS_SearchResult *psearch_result, const char *serialization); /** * Function called with a filename of serialized search result * to deserialize. * * @param cls the 'struct GNUNET_FS_SearchContext*' * @param filename complete filename (absolute path) * @return GNUNET_OK (continue to iterate) */ static int deserialize_search_result (void *cls, const char *filename) { struct GNUNET_FS_SearchContext *sc = cls; char *ser; char *uris; char *emsg; char *download; char *update_srch; struct GNUNET_BIO_ReadHandle *rh; struct GNUNET_BIO_ReadHandle *drh; struct GNUNET_FS_SearchResult *sr; ser = get_serialization_short_name (filename); rh = GNUNET_BIO_read_open (filename); if (rh == NULL) { if (ser != NULL) { remove_sync_file_in_dir (sc->h, (sc->psearch_result == NULL) ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH : GNUNET_FS_SYNC_PATH_CHILD_SEARCH, sc->serialization, ser); GNUNET_free (ser); } return GNUNET_OK; } emsg = NULL; uris = NULL; download = NULL; update_srch = NULL; sr = GNUNET_malloc (sizeof (struct GNUNET_FS_SearchResult)); sr->sc = sc; sr->serialization = ser; if ((GNUNET_OK != GNUNET_BIO_read_string (rh, "result-uri", &uris, 10 * 1024)) || (NULL == (sr->uri = GNUNET_FS_uri_parse (uris, &emsg))) || (GNUNET_OK != GNUNET_BIO_read_string (rh, "download-lnk", &download, 16)) || (GNUNET_OK != GNUNET_BIO_read_string (rh, "search-lnk", &update_srch, 16)) || (GNUNET_OK != GNUNET_BIO_read_meta_data (rh, "result-meta", &sr->meta)) || (GNUNET_OK != GNUNET_BIO_read (rh, "result-key", &sr->key, sizeof (GNUNET_HashCode))) || (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &sr->mandatory_missing)) || (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &sr->optional_support)) || (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &sr->availability_success)) || (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &sr->availability_trials))) { GNUNET_break (0); goto cleanup; } if (sr->sc->uri->type == ksk) { sr->keyword_bitmap = GNUNET_malloc ((sr->sc->uri->data.ksk.keywordCount + 7) / 8); /* round up, count bits */ if (GNUNET_OK != GNUNET_BIO_read (rh, "keyword-bitmap", sr->keyword_bitmap, (sr->sc->uri->data.ksk.keywordCount + 7) / 8)) { GNUNET_break (0); goto cleanup; } } GNUNET_free (uris); if (download != NULL) { drh = get_read_handle (sc->h, GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD, download); if (drh != NULL) { deserialize_download (sc->h, drh, NULL, sr, download); if (GNUNET_OK != GNUNET_BIO_read_close (drh, &emsg)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to resume sub-download `%s': %s\n"), download, emsg); GNUNET_free (emsg); } } GNUNET_free (download); } if (update_srch != NULL) { drh = get_read_handle (sc->h, GNUNET_FS_SYNC_PATH_CHILD_SEARCH, update_srch); if (drh != NULL) { deserialize_search (sc->h, drh, sr, update_srch); if (GNUNET_OK != GNUNET_BIO_read_close (drh, &emsg)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to resume sub-search `%s': %s\n"), update_srch, emsg); GNUNET_free (emsg); } } GNUNET_free (update_srch); } GNUNET_CONTAINER_multihashmap_put (sc->master_result_map, &sr->key, sr, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failure while resuming search operation `%s': %s\n"), filename, emsg); GNUNET_free (emsg); } return GNUNET_OK; cleanup: GNUNET_free_non_null (download); GNUNET_free_non_null (emsg); GNUNET_free_non_null (uris); GNUNET_free_non_null (update_srch); if (sr->uri != NULL) GNUNET_FS_uri_destroy (sr->uri); if (sr->meta != NULL) GNUNET_CONTAINER_meta_data_destroy (sr->meta); GNUNET_free (sr->serialization); GNUNET_free (sr); if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failure while resuming search operation `%s': %s\n"), filename, emsg); GNUNET_free (emsg); } return GNUNET_OK; } /** * Send the 'resume' signal to the callback; also actually * resume the download (put it in the queue). Does this * recursively for the top-level download and all child * downloads. * * @param dc download to resume */ static void signal_download_resume (struct GNUNET_FS_DownloadContext *dc) { struct GNUNET_FS_DownloadContext *dcc; struct GNUNET_FS_ProgressInfo pi; pi.status = GNUNET_FS_STATUS_DOWNLOAD_RESUME; pi.value.download.specifics.resume.meta = dc->meta; pi.value.download.specifics.resume.message = dc->emsg; GNUNET_FS_download_make_status_ (&pi, dc); dcc = dc->child_head; while (NULL != dcc) { signal_download_resume (dcc); dcc = dcc->next; } if (dc->pending_head != NULL) GNUNET_FS_download_start_downloading_ (dc); } /** * Signal resuming of a search to our clients (for the * top level search and all sub-searches). * * @param sc search being resumed */ static void signal_search_resume (struct GNUNET_FS_SearchContext *sc); /** * Iterator over search results signaling resume to the client for * each result. * * @param cls closure, the 'struct GNUNET_FS_SearchContext' * @param key current key code * @param value value in the hash map, the 'struct GNUNET_FS_SearchResult' * @return GNUNET_YES (we should continue to iterate) */ static int signal_result_resume (void *cls, const GNUNET_HashCode * key, void *value) { struct GNUNET_FS_SearchContext *sc = cls; struct GNUNET_FS_ProgressInfo pi; struct GNUNET_FS_SearchResult *sr = value; if (0 == sr->mandatory_missing) { pi.status = GNUNET_FS_STATUS_SEARCH_RESUME_RESULT; pi.value.search.specifics.resume_result.meta = sr->meta; pi.value.search.specifics.resume_result.uri = sr->uri; pi.value.search.specifics.resume_result.result = sr; pi.value.search.specifics.resume_result.availability_rank = 2 * sr->availability_success - sr->availability_trials; pi.value.search.specifics.resume_result.availability_certainty = sr->availability_trials; pi.value.search.specifics.resume_result.applicability_rank = sr->optional_support; sr->client_info = GNUNET_FS_search_make_status_ (&pi, sc); } if (sr->download != NULL) { signal_download_resume (sr->download); } else { GNUNET_FS_search_start_probe_ (sr); } if (sr->update_search != NULL) signal_search_resume (sr->update_search); return GNUNET_YES; } /** * Free memory allocated by the search context and its children * * @param sc search context to free */ static void free_search_context (struct GNUNET_FS_SearchContext *sc); /** * Iterator over search results freeing each. * * @param cls closure, the 'struct GNUNET_FS_SearchContext' * @param key current key code * @param value value in the hash map, the 'struct GNUNET_FS_SearchResult' * @return GNUNET_YES (we should continue to iterate) */ static int free_result (void *cls, const GNUNET_HashCode * key, void *value) { struct GNUNET_FS_SearchResult *sr = value; if (sr->update_search != NULL) { free_search_context (sr->update_search); GNUNET_assert (NULL == sr->update_search); } GNUNET_CONTAINER_meta_data_destroy (sr->meta); GNUNET_FS_uri_destroy (sr->uri); GNUNET_free (sr); return GNUNET_YES; } /** * Free memory allocated by the search context and its children * * @param sc search context to free */ static void free_search_context (struct GNUNET_FS_SearchContext *sc) { if (sc->serialization != NULL) { GNUNET_FS_remove_sync_file_ (sc->h, (sc->psearch_result == NULL) ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH : GNUNET_FS_SYNC_PATH_CHILD_SEARCH, sc->serialization); GNUNET_FS_remove_sync_dir_ (sc->h, (sc->psearch_result == NULL) ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH : GNUNET_FS_SYNC_PATH_CHILD_SEARCH, sc->serialization); } GNUNET_free_non_null (sc->serialization); GNUNET_free_non_null (sc->emsg); if (sc->uri != NULL) GNUNET_FS_uri_destroy (sc->uri); if (sc->master_result_map != NULL) { GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, &free_result, sc); GNUNET_CONTAINER_multihashmap_destroy (sc->master_result_map); } GNUNET_free (sc); } /** * Function called with a filename of serialized sub-download * to deserialize. * * @param cls the 'struct GNUNET_FS_DownloadContext*' (parent) * @param filename complete filename (absolute path) * @return GNUNET_OK (continue to iterate) */ static int deserialize_subdownload (void *cls, const char *filename) { struct GNUNET_FS_DownloadContext *parent = cls; char *ser; char *emsg; struct GNUNET_BIO_ReadHandle *rh; ser = get_serialization_short_name (filename); rh = GNUNET_BIO_read_open (filename); if (rh == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Failed to resume sub-download `%s': could not open file `%s'\n"), ser, filename); GNUNET_free (ser); return GNUNET_OK; } deserialize_download (parent->h, rh, parent, NULL, ser); if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to resume sub-download `%s': %s\n"), ser, emsg); GNUNET_free (emsg); } GNUNET_free (ser); return GNUNET_OK; } /** * Free this download context and all of its descendants. * (only works during deserialization since not all possible * state it taken care of). * * @param dc context to free */ static void free_download_context (struct GNUNET_FS_DownloadContext *dc) { struct GNUNET_FS_DownloadContext *dcc; if (dc->meta != NULL) GNUNET_CONTAINER_meta_data_destroy (dc->meta); if (dc->uri != NULL) GNUNET_FS_uri_destroy (dc->uri); GNUNET_free_non_null (dc->temp_filename); GNUNET_free_non_null (dc->emsg); GNUNET_free_non_null (dc->filename); GNUNET_free_non_null (dc->serialization); while (NULL != (dcc = dc->child_head)) { GNUNET_CONTAINER_DLL_remove (dc->child_head, dc->child_tail, dcc); free_download_context (dcc); } GNUNET_FS_free_download_request_ (dc->top_request); if (NULL != dc->active) GNUNET_CONTAINER_multihashmap_destroy (dc->active); GNUNET_free (dc); } /** * Deserialize a download. * * @param h overall context * @param rh file to deserialize from * @param parent parent download * @param search associated search * @param serialization name under which the search was serialized */ static void deserialize_download (struct GNUNET_FS_Handle *h, struct GNUNET_BIO_ReadHandle *rh, struct GNUNET_FS_DownloadContext *parent, struct GNUNET_FS_SearchResult *search, const char *serialization) { struct GNUNET_FS_DownloadContext *dc; char *emsg; char *uris; char *dn; uint32_t options; uint32_t status; uris = NULL; emsg = NULL; dc = GNUNET_malloc (sizeof (struct GNUNET_FS_DownloadContext)); dc->parent = parent; dc->h = h; dc->serialization = GNUNET_strdup (serialization); if ((GNUNET_OK != GNUNET_BIO_read_string (rh, "download-uri", &uris, 10 * 1024)) || (NULL == (dc->uri = GNUNET_FS_uri_parse (uris, &emsg))) || ((GNUNET_YES != GNUNET_FS_uri_test_chk (dc->uri)) && (GNUNET_YES != GNUNET_FS_uri_test_loc (dc->uri))) || (GNUNET_OK != GNUNET_BIO_read_meta_data (rh, "download-meta", &dc->meta)) || (GNUNET_OK != GNUNET_BIO_read_string (rh, "download-emsg", &dc->emsg, 10 * 1024)) || (GNUNET_OK != GNUNET_BIO_read_string (rh, "download-fn", &dc->filename, 10 * 1024)) || (GNUNET_OK != GNUNET_BIO_read_string (rh, "download-tfn", &dc->temp_filename, 10 * 1024)) || (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &dc->old_file_size)) || (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &dc->offset)) || (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &dc->length)) || (GNUNET_OK != GNUNET_BIO_read_int64 (rh, &dc->completed)) || (GNUNET_OK != read_start_time (rh, &dc->start_time)) || (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &dc->anonymity)) || (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &options)) || (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &status))) { GNUNET_break (0); goto cleanup; } dc->options = (enum GNUNET_FS_DownloadOptions) options; dc->active = GNUNET_CONTAINER_multihashmap_create (1 + 2 * (dc->length / DBLOCK_SIZE)); dc->has_finished = (int) status; dc->treedepth = GNUNET_FS_compute_depth (GNUNET_FS_uri_chk_get_file_size (dc->uri)); if (GNUNET_FS_uri_test_loc (dc->uri)) GNUNET_assert (GNUNET_OK == GNUNET_FS_uri_loc_get_peer_identity (dc->uri, &dc->target)); if (dc->emsg == NULL) { dc->top_request = read_download_request (rh); if (dc->top_request == NULL) { GNUNET_break (0); goto cleanup; } } dn = get_download_sync_filename (dc, dc->serialization, ".dir"); if (dn != NULL) { if (GNUNET_YES == GNUNET_DISK_directory_test (dn)) GNUNET_DISK_directory_scan (dn, &deserialize_subdownload, dc); GNUNET_free (dn); } if (parent != NULL) { GNUNET_abort (); // for debugging for now - FIXME GNUNET_CONTAINER_DLL_insert (parent->child_head, parent->child_tail, dc); } if (search != NULL) { dc->search = search; search->download = dc; } if ((parent == NULL) && (search == NULL)) { dc->top = GNUNET_FS_make_top (dc->h, &GNUNET_FS_download_signal_suspend_, dc); signal_download_resume (dc); } GNUNET_free (uris); dc->task = GNUNET_SCHEDULER_add_now (&GNUNET_FS_download_start_task_, dc); return; cleanup: GNUNET_free_non_null (uris); GNUNET_free_non_null (emsg); free_download_context (dc); } /** * Signal resuming of a search to our clients (for the * top level search and all sub-searches). * * @param sc search being resumed */ static void signal_search_resume (struct GNUNET_FS_SearchContext *sc) { struct GNUNET_FS_ProgressInfo pi; pi.status = GNUNET_FS_STATUS_SEARCH_RESUME; pi.value.search.specifics.resume.message = sc->emsg; pi.value.search.specifics.resume.is_paused = (sc->client == NULL) ? GNUNET_YES : GNUNET_NO; sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc); GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, &signal_result_resume, sc); } /** * Deserialize a search. * * @param h overall context * @param rh file to deserialize from * @param psearch_result parent search result * @param serialization name under which the search was serialized */ static struct GNUNET_FS_SearchContext * deserialize_search (struct GNUNET_FS_Handle *h, struct GNUNET_BIO_ReadHandle *rh, struct GNUNET_FS_SearchResult *psearch_result, const char *serialization) { struct GNUNET_FS_SearchContext *sc; char *emsg; char *uris; char *dn; uint32_t options; char in_pause; if ((psearch_result != NULL) && (psearch_result->update_search != NULL)) { GNUNET_break (0); return NULL; } uris = NULL; emsg = NULL; sc = GNUNET_malloc (sizeof (struct GNUNET_FS_SearchContext)); if (psearch_result != NULL) { sc->psearch_result = psearch_result; psearch_result->update_search = sc; } sc->h = h; sc->serialization = GNUNET_strdup (serialization); if ((GNUNET_OK != GNUNET_BIO_read_string (rh, "search-uri", &uris, 10 * 1024)) || (NULL == (sc->uri = GNUNET_FS_uri_parse (uris, &emsg))) || ((GNUNET_YES != GNUNET_FS_uri_test_ksk (sc->uri)) && (GNUNET_YES != GNUNET_FS_uri_test_sks (sc->uri))) || (GNUNET_OK != read_start_time (rh, &sc->start_time)) || (GNUNET_OK != GNUNET_BIO_read_string (rh, "search-emsg", &sc->emsg, 10 * 1024)) || (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &options)) || (GNUNET_OK != GNUNET_BIO_read (rh, "search-pause", &in_pause, sizeof (in_pause))) || (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &sc->anonymity))) { GNUNET_break (0); goto cleanup; } sc->options = (enum GNUNET_FS_SearchOptions) options; sc->master_result_map = GNUNET_CONTAINER_multihashmap_create (16); dn = get_serialization_file_name_in_dir (h, (sc->psearch_result == NULL) ? GNUNET_FS_SYNC_PATH_MASTER_SEARCH : GNUNET_FS_SYNC_PATH_CHILD_SEARCH, sc->serialization, ""); if (dn != NULL) { if (GNUNET_YES == GNUNET_DISK_directory_test (dn)) GNUNET_DISK_directory_scan (dn, &deserialize_search_result, sc); GNUNET_free (dn); } if (('\0' == in_pause) && (GNUNET_OK != GNUNET_FS_search_start_searching_ (sc))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not resume running search, will resume as paused search\n")); } signal_search_resume (sc); GNUNET_free (uris); return sc; cleanup: GNUNET_free_non_null (emsg); free_search_context (sc); GNUNET_free_non_null (uris); return NULL; } /** * Function called with a filename of serialized search operation * to deserialize. * * @param cls the 'struct GNUNET_FS_Handle*' * @param filename complete filename (absolute path) * @return GNUNET_OK (continue to iterate) */ static int deserialize_search_file (void *cls, const char *filename) { struct GNUNET_FS_Handle *h = cls; char *ser; char *emsg; struct GNUNET_BIO_ReadHandle *rh; struct GNUNET_FS_SearchContext *sc; struct stat buf; if (0 != STAT (filename, &buf)) { GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "stat", filename); return GNUNET_OK; } if (S_ISDIR (buf.st_mode)) return GNUNET_OK; /* skip directories */ ser = get_serialization_short_name (filename); rh = GNUNET_BIO_read_open (filename); if (rh == NULL) { if (ser != NULL) { GNUNET_FS_remove_sync_file_ (h, GNUNET_FS_SYNC_PATH_MASTER_SEARCH, ser); GNUNET_free (ser); } return GNUNET_OK; } sc = deserialize_search (h, rh, NULL, ser); if (sc != NULL) sc->top = GNUNET_FS_make_top (h, &GNUNET_FS_search_signal_suspend_, sc); GNUNET_free (ser); if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failure while resuming search operation `%s': %s\n"), filename, emsg); GNUNET_free (emsg); } return GNUNET_OK; } /** * Function called with a filename of serialized download operation * to deserialize. * * @param cls the 'struct GNUNET_FS_Handle*' * @param filename complete filename (absolute path) * @return GNUNET_OK (continue to iterate) */ static int deserialize_download_file (void *cls, const char *filename) { struct GNUNET_FS_Handle *h = cls; char *ser; char *emsg; struct GNUNET_BIO_ReadHandle *rh; ser = get_serialization_short_name (filename); rh = GNUNET_BIO_read_open (filename); if (rh == NULL) { if (0 != UNLINK (filename)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename); GNUNET_free (ser); return GNUNET_OK; } deserialize_download (h, rh, NULL, NULL, ser); GNUNET_free (ser); if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failure while resuming download operation `%s': %s\n"), filename, emsg); GNUNET_free (emsg); } return GNUNET_OK; } /** * Deserialize informatin about pending operations. * * @param master_path which master directory should be scanned * @param proc function to call for each entry (will get 'h' for 'cls') * @param h the 'struct GNUNET_FS_Handle*' */ static void deserialization_master (const char *master_path, GNUNET_FileNameCallback proc, struct GNUNET_FS_Handle *h) { char *dn; dn = get_serialization_file_name (h, master_path, ""); if (dn == NULL) return; if (GNUNET_YES == GNUNET_DISK_directory_test (dn)) GNUNET_DISK_directory_scan (dn, proc, h); GNUNET_free (dn); } /** * Setup a connection to the file-sharing service. * * @param cfg configuration to use * @param client_name unique identifier for this client * @param upcb function to call to notify about FS actions * @param upcb_cls closure for upcb * @param flags specific attributes for fs-operations * @param ... list of optional options, terminated with GNUNET_FS_OPTIONS_END * @return NULL on error */ struct GNUNET_FS_Handle * GNUNET_FS_start (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *client_name, GNUNET_FS_ProgressCallback upcb, void *upcb_cls, enum GNUNET_FS_Flags flags, ...) { struct GNUNET_FS_Handle *ret; enum GNUNET_FS_OPTIONS opt; va_list ap; ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Handle)); ret->cfg = cfg; ret->client_name = GNUNET_strdup (client_name); ret->upcb = upcb; ret->upcb_cls = upcb_cls; ret->flags = flags; ret->max_parallel_downloads = DEFAULT_MAX_PARALLEL_DOWNLOADS; ret->max_parallel_requests = DEFAULT_MAX_PARALLEL_REQUESTS; ret->avg_block_latency = GNUNET_TIME_UNIT_MINUTES; /* conservative starting point */ va_start (ap, flags); while (GNUNET_FS_OPTIONS_END != (opt = va_arg (ap, enum GNUNET_FS_OPTIONS))) { switch (opt) { case GNUNET_FS_OPTIONS_DOWNLOAD_PARALLELISM: ret->max_parallel_downloads = va_arg (ap, unsigned int); break; case GNUNET_FS_OPTIONS_REQUEST_PARALLELISM: ret->max_parallel_requests = va_arg (ap, unsigned int); break; default: GNUNET_break (0); GNUNET_free (ret->client_name); GNUNET_free (ret); va_end (ap); return NULL; } } va_end (ap); if (0 != (GNUNET_FS_FLAGS_PERSISTENCE & flags)) { deserialization_master (GNUNET_FS_SYNC_PATH_MASTER_PUBLISH, &deserialize_publish_file, ret); deserialization_master (GNUNET_FS_SYNC_PATH_MASTER_SEARCH, &deserialize_search_file, ret); deserialization_master (GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD, &deserialize_download_file, ret); deserialization_master (GNUNET_FS_SYNC_PATH_MASTER_UNINDEX, &deserialize_unindex_file, ret); } return ret; } /** * Close our connection with the file-sharing service. * The callback given to GNUNET_FS_start will no longer be * called after this function returns. * * @param h handle that was returned from GNUNET_FS_start */ void GNUNET_FS_stop (struct GNUNET_FS_Handle *h) { while (h->top_head != NULL) h->top_head->ssf (h->top_head->ssf_cls); if (h->queue_job != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (h->queue_job); GNUNET_free (h->client_name); GNUNET_free (h); } /* end of fs.c */ gnunet-0.9.3/src/fs/gnunet-service-fs_push.h0000644000175000017500000000315711760502551015727 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-service-fs_push.h * @brief support for pushing out content * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_FS_PUSH_H #define GNUNET_SERVICE_FS_PUSH_H #include "gnunet-service-fs.h" /** * Setup the module. */ void GSF_push_init_ (void); /** * Shutdown the module. */ void GSF_push_done_ (void); /** * A peer connected to us or we are now again allowed to push content. * Start pushing content to this peer. * * @param peer handle for the peer that connected */ void GSF_push_start_ (struct GSF_ConnectedPeer *peer); /** * A peer disconnected from us or asked us to stop pushing content for * a while. Stop pushing content to this peer. * * @param peer handle for the peer that disconnected */ void GSF_push_stop_ (struct GSF_ConnectedPeer *peer); #endif gnunet-0.9.3/src/fs/gnunet-service-fs_push.c0000644000175000017500000003764211760502551015730 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-service-fs_push.c * @brief API to push content from our datastore to other peers * ('anonymous'-content P2P migration) * @author Christian Grothoff */ #include "platform.h" #include "gnunet-service-fs.h" #include "gnunet-service-fs_cp.h" #include "gnunet-service-fs_indexing.h" #include "gnunet-service-fs_push.h" /** * Maximum number of blocks we keep in memory for migration. */ #define MAX_MIGRATION_QUEUE 8 /** * Blocks are at most migrated to this number of peers * plus one, each time they are fetched from the database. */ #define MIGRATION_LIST_SIZE 2 /** * How long must content remain valid for us to consider it for migration? * If content will expire too soon, there is clearly no point in pushing * it to other peers. This value gives the threshold for migration. Note * that if this value is increased, the migration testcase may need to be * adjusted as well (especially the CONTENT_LIFETIME in fs_test_lib.c). */ #define MIN_MIGRATION_CONTENT_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30) /** * Block that is ready for migration to other peers. Actual data is at the end of the block. */ struct MigrationReadyBlock { /** * This is a doubly-linked list. */ struct MigrationReadyBlock *next; /** * This is a doubly-linked list. */ struct MigrationReadyBlock *prev; /** * Query for the block. */ GNUNET_HashCode query; /** * When does this block expire? */ struct GNUNET_TIME_Absolute expiration; /** * Peers we already forwarded this * block to. Zero for empty entries. */ GNUNET_PEER_Id target_list[MIGRATION_LIST_SIZE]; /** * Size of the block. */ size_t size; /** * Number of targets already used. */ unsigned int used_targets; /** * Type of the block. */ enum GNUNET_BLOCK_Type type; }; /** * Information about a peer waiting for * migratable data. */ struct MigrationReadyPeer { /** * This is a doubly-linked list. */ struct MigrationReadyPeer *next; /** * This is a doubly-linked list. */ struct MigrationReadyPeer *prev; /** * Handle to peer. */ struct GSF_ConnectedPeer *peer; /** * Handle for current transmission request, * or NULL for none. */ struct GSF_PeerTransmitHandle *th; /** * Message we are trying to push right now (or NULL) */ struct PutMessage *msg; }; /** * Head of linked list of blocks that can be migrated. */ static struct MigrationReadyBlock *mig_head; /** * Tail of linked list of blocks that can be migrated. */ static struct MigrationReadyBlock *mig_tail; /** * Head of linked list of peers. */ static struct MigrationReadyPeer *peer_head; /** * Tail of linked list of peers. */ static struct MigrationReadyPeer *peer_tail; /** * Request to datastore for migration (or NULL). */ static struct GNUNET_DATASTORE_QueueEntry *mig_qe; /** * ID of task that collects blocks for migration. */ static GNUNET_SCHEDULER_TaskIdentifier mig_task; /** * What is the maximum frequency at which we are allowed to * poll the datastore for migration content? */ static struct GNUNET_TIME_Relative min_migration_delay; /** * Size of the doubly-linked list of migration blocks. */ static unsigned int mig_size; /** * Is this module enabled? */ static int enabled; /** * Delete the given migration block. * * @param mb block to delete */ static void delete_migration_block (struct MigrationReadyBlock *mb) { GNUNET_CONTAINER_DLL_remove (mig_head, mig_tail, mb); GNUNET_PEER_decrement_rcs (mb->target_list, MIGRATION_LIST_SIZE); mig_size--; GNUNET_free (mb); } /** * Find content for migration to this peer. */ static void find_content (struct MigrationReadyPeer *mrp); /** * Transmit the message currently scheduled for * transmission. * * @param cls the 'struct MigrationReadyPeer' * @param buf_size number of bytes available in buf * @param buf where to copy the message, NULL on error (peer disconnect) * @return number of bytes copied to 'buf', can be 0 (without indicating an error) */ static size_t transmit_message (void *cls, size_t buf_size, void *buf) { struct MigrationReadyPeer *peer = cls; struct PutMessage *msg; uint16_t msize; peer->th = NULL; msg = peer->msg; peer->msg = NULL; if (buf == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to migrate content to another peer (disconnect)\n"); GNUNET_free (msg); return 0; } msize = ntohs (msg->header.size); GNUNET_assert (msize <= buf_size); memcpy (buf, msg, msize); GNUNET_free (msg); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Pushing %u bytes to another peer\n", msize); find_content (peer); return msize; } /** * Send the given block to the given peer. * * @param peer target peer * @param block the block * @return GNUNET_YES if the block was deleted (!) */ static int transmit_content (struct MigrationReadyPeer *peer, struct MigrationReadyBlock *block) { size_t msize; struct PutMessage *msg; unsigned int i; struct GSF_PeerPerformanceData *ppd; int ret; ppd = GSF_get_peer_performance_data_ (peer->peer); GNUNET_assert (NULL == peer->th); msize = sizeof (struct PutMessage) + block->size; msg = GNUNET_malloc (msize); msg->header.type = htons (GNUNET_MESSAGE_TYPE_FS_PUT); msg->header.size = htons (msize); msg->type = htonl (block->type); msg->expiration = GNUNET_TIME_absolute_hton (block->expiration); memcpy (&msg[1], &block[1], block->size); peer->msg = msg; for (i = 0; i < MIGRATION_LIST_SIZE; i++) { if (block->target_list[i] == 0) { block->target_list[i] = ppd->pid; GNUNET_PEER_change_rc (block->target_list[i], 1); break; } } if (MIGRATION_LIST_SIZE == i) { delete_migration_block (block); ret = GNUNET_YES; } else { ret = GNUNET_NO; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking for transmission of %u bytes for migration\n", msize); peer->th = GSF_peer_transmit_ (peer->peer, GNUNET_NO, 0 /* priority */ , GNUNET_TIME_UNIT_FOREVER_REL, msize, &transmit_message, peer); return ret; } /** * Count the number of peers this block has * already been forwarded to. * * @param block the block * @return number of times block was forwarded */ static unsigned int count_targets (struct MigrationReadyBlock *block) { unsigned int i; for (i = 0; i < MIGRATION_LIST_SIZE; i++) if (block->target_list[i] == 0) return i; return i; } /** * Check if sending this block to this peer would * be a good idea. * * @param peer target peer * @param block the block * @return score (>= 0: feasible, negative: infeasible) */ static long score_content (struct MigrationReadyPeer *peer, struct MigrationReadyBlock *block) { unsigned int i; struct GSF_PeerPerformanceData *ppd; struct GNUNET_PeerIdentity id; uint32_t dist; ppd = GSF_get_peer_performance_data_ (peer->peer); for (i = 0; i < MIGRATION_LIST_SIZE; i++) if (block->target_list[i] == ppd->pid) return -1; GNUNET_assert (0 != ppd->pid); GNUNET_PEER_resolve (ppd->pid, &id); dist = GNUNET_CRYPTO_hash_distance_u32 (&block->query, &id.hashPubKey); /* closer distance, higher score: */ return UINT32_MAX - dist; } /** * If the migration task is not currently running, consider * (re)scheduling it with the appropriate delay. */ static void consider_gathering (void); /** * Find content for migration to this peer. * * @param mrp peer to find content for */ static void find_content (struct MigrationReadyPeer *mrp) { struct MigrationReadyBlock *pos; long score; long best_score; struct MigrationReadyBlock *best; GNUNET_assert (NULL == mrp->th); best = NULL; best_score = -1; pos = mig_head; while (NULL != pos) { score = score_content (mrp, pos); if (score > best_score) { best_score = score; best = pos; } pos = pos->next; } if (NULL == best) { if (mig_size < MAX_MIGRATION_QUEUE) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No content found for pushing, waiting for queue to fill\n"); return; /* will fill up eventually... */ } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No suitable content found, purging content from full queue\n"); /* failed to find migration target AND * queue is full, purge most-forwarded * block from queue to make room for more */ pos = mig_head; while (NULL != pos) { score = count_targets (pos); if (score >= best_score) { best_score = score; best = pos; } pos = pos->next; } GNUNET_assert (NULL != best); delete_migration_block (best); consider_gathering (); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Preparing to push best content to peer\n"); transmit_content (mrp, best); } /** * Task that is run periodically to obtain blocks for content * migration * * @param cls unused * @param tc scheduler context (also unused) */ static void gather_migration_blocks (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * If the migration task is not currently running, consider * (re)scheduling it with the appropriate delay. */ static void consider_gathering () { struct GNUNET_TIME_Relative delay; if (GSF_dsh == NULL) return; if (mig_qe != NULL) return; if (mig_task != GNUNET_SCHEDULER_NO_TASK) return; if (mig_size >= MAX_MIGRATION_QUEUE) return; delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, mig_size); delay = GNUNET_TIME_relative_divide (delay, MAX_MIGRATION_QUEUE); delay = GNUNET_TIME_relative_max (delay, min_migration_delay); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scheduling gathering task (queue size: %u)\n", mig_size); mig_task = GNUNET_SCHEDULER_add_delayed (delay, &gather_migration_blocks, NULL); } /** * Process content offered for migration. * * @param cls closure * @param key key for the content * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param expiration expiration time for the content * @param uid unique identifier for the datum; * maybe 0 if no unique identifier is available */ static void process_migration_content (void *cls, const GNUNET_HashCode * key, size_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct MigrationReadyBlock *mb; struct MigrationReadyPeer *pos; mig_qe = NULL; if (key == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No content found for migration...\n"); consider_gathering (); return; } if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value < MIN_MIGRATION_CONTENT_LIFETIME.rel_value) { /* content will expire soon, don't bother */ consider_gathering (); return; } if (type == GNUNET_BLOCK_TYPE_FS_ONDEMAND) { if (GNUNET_OK != GNUNET_FS_handle_on_demand_block (key, size, data, type, priority, anonymity, expiration, uid, &process_migration_content, NULL)) consider_gathering (); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Retrieved block `%s' of type %u for migration (queue size: %u/%u)\n", GNUNET_h2s (key), type, mig_size + 1, MAX_MIGRATION_QUEUE); mb = GNUNET_malloc (sizeof (struct MigrationReadyBlock) + size); mb->query = *key; mb->expiration = expiration; mb->size = size; mb->type = type; memcpy (&mb[1], data, size); GNUNET_CONTAINER_DLL_insert_after (mig_head, mig_tail, mig_tail, mb); mig_size++; pos = peer_head; while (pos != NULL) { if (NULL == pos->th) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Preparing to push best content to peer\n"); if (GNUNET_YES == transmit_content (pos, mb)) break; /* 'mb' was freed! */ } pos = pos->next; } consider_gathering (); } /** * Task that is run periodically to obtain blocks for content * migration * * @param cls unused * @param tc scheduler context (also unused) */ static void gather_migration_blocks (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { mig_task = GNUNET_SCHEDULER_NO_TASK; if (mig_size >= MAX_MIGRATION_QUEUE) return; if (GSF_dsh != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking datastore for content for replication (queue size: %u)\n", mig_size); mig_qe = GNUNET_DATASTORE_get_for_replication (GSF_dsh, 0, UINT_MAX, GNUNET_TIME_UNIT_FOREVER_REL, &process_migration_content, NULL); if (NULL == mig_qe) consider_gathering (); } } /** * A peer connected to us. Start pushing content * to this peer. * * @param peer handle for the peer that connected */ void GSF_push_start_ (struct GSF_ConnectedPeer *peer) { struct MigrationReadyPeer *mrp; if (GNUNET_YES != enabled) return; mrp = GNUNET_malloc (sizeof (struct MigrationReadyPeer)); mrp->peer = peer; find_content (mrp); GNUNET_CONTAINER_DLL_insert (peer_head, peer_tail, mrp); } /** * A peer disconnected from us. Stop pushing content * to this peer. * * @param peer handle for the peer that disconnected */ void GSF_push_stop_ (struct GSF_ConnectedPeer *peer) { struct MigrationReadyPeer *pos; pos = peer_head; while (pos != NULL) { if (pos->peer == peer) { GNUNET_CONTAINER_DLL_remove (peer_head, peer_tail, pos); if (NULL != pos->th) { GSF_peer_transmit_cancel_ (pos->th); pos->th = NULL; } if (NULL != pos->msg) { GNUNET_free (pos->msg); pos->msg = NULL; } GNUNET_free (pos); return; } pos = pos->next; } } /** * Setup the module. */ void GSF_push_init_ () { enabled = GNUNET_CONFIGURATION_get_value_yesno (GSF_cfg, "FS", "CONTENT_PUSHING"); if (GNUNET_YES != enabled) return; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (GSF_cfg, "fs", "MIN_MIGRATION_DELAY", &min_migration_delay)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Invalid value specified for option `%s' in section `%s', content pushing disabled\n"), "MIN_MIGRATION_DELAY", "fs"); return; } consider_gathering (); } /** * Shutdown the module. */ void GSF_push_done_ () { if (GNUNET_SCHEDULER_NO_TASK != mig_task) { GNUNET_SCHEDULER_cancel (mig_task); mig_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != mig_qe) { GNUNET_DATASTORE_cancel (mig_qe); mig_qe = NULL; } while (NULL != mig_head) delete_migration_block (mig_head); GNUNET_assert (0 == mig_size); } /* end of gnunet-service-fs_push.c */ gnunet-0.9.3/src/fs/fs_publish_ksk.c0000644000175000017500000002266211760502551014327 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs_publish_ksk.c * @brief publish a URI under a keyword in GNUnet * @see https://gnunet.org/encoding * @author Krista Bennett * @author Christian Grothoff */ #include "platform.h" #include "gnunet_constants.h" #include "gnunet_signatures.h" #include "gnunet_util_lib.h" #include "gnunet_fs_service.h" #include "fs_api.h" #include "fs_tree.h" /** * Maximum legal size for a kblock. */ #define MAX_KBLOCK_SIZE (60 * 1024) /** * Context for the KSK publication. */ struct GNUNET_FS_PublishKskContext { /** * Keywords to use. */ struct GNUNET_FS_Uri *ksk_uri; /** * Global FS context. */ struct GNUNET_FS_Handle *h; /** * The master block that we are sending * (in plaintext), has "mdsize+slen" more * bytes than the struct would suggest. */ struct KBlock *kb; /** * Buffer of the same size as "kb" for * the encrypted version. */ struct KBlock *cpy; /** * Handle to the datastore, NULL if we are just * simulating. */ struct GNUNET_DATASTORE_Handle *dsh; /** * Handle to datastore PUT request. */ struct GNUNET_DATASTORE_QueueEntry *qre; /** * Current task. */ GNUNET_SCHEDULER_TaskIdentifier ksk_task; /** * Function to call once we're done. */ GNUNET_FS_PublishContinuation cont; /** * Closure for cont. */ void *cont_cls; /** * When should the KBlocks expire? */ struct GNUNET_FS_BlockOptions bo; /** * Size of the serialized metadata. */ ssize_t mdsize; /** * Size of the (CHK) URI as a string. */ size_t slen; /** * Keyword that we are currently processing. */ unsigned int i; }; /** * Continuation of "GNUNET_FS_publish_ksk" that performs * the actual publishing operation (iterating over all * of the keywords). * * @param cls closure of type "struct PublishKskContext*" * @param tc unused */ static void publish_ksk_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Function called by the datastore API with * the result from the PUT request. * * @param cls closure of type "struct GNUNET_FS_PublishKskContext*" * @param success GNUNET_OK on success * @param min_expiration minimum expiration time required for content to be stored * @param msg error message (or NULL) */ static void kb_put_cont (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) { struct GNUNET_FS_PublishKskContext *pkc = cls; pkc->qre = NULL; if (GNUNET_OK != success) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "KBlock PUT operation failed: %s\n", msg); pkc->cont (pkc->cont_cls, NULL, msg); GNUNET_FS_publish_ksk_cancel (pkc); return; } pkc->ksk_task = GNUNET_SCHEDULER_add_now (&publish_ksk_cont, pkc); } /** * Continuation of "GNUNET_FS_publish_ksk" that performs the actual * publishing operation (iterating over all of the keywords). * * @param cls closure of type "struct GNUNET_FS_PublishKskContext*" * @param tc unused */ static void publish_ksk_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FS_PublishKskContext *pkc = cls; const char *keyword; GNUNET_HashCode key; GNUNET_HashCode query; struct GNUNET_CRYPTO_AesSessionKey skey; struct GNUNET_CRYPTO_AesInitializationVector iv; struct GNUNET_CRYPTO_RsaPrivateKey *pk; pkc->ksk_task = GNUNET_SCHEDULER_NO_TASK; if ((pkc->i == pkc->ksk_uri->data.ksk.keywordCount) || (NULL == pkc->dsh)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "KSK PUT operation complete\n"); pkc->cont (pkc->cont_cls, pkc->ksk_uri, NULL); GNUNET_FS_publish_ksk_cancel (pkc); return; } keyword = pkc->ksk_uri->data.ksk.keywords[pkc->i++]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing under keyword `%s'\n", &keyword[1]); /* first character of keyword indicates if it is * mandatory or not -- ignore for hashing */ GNUNET_CRYPTO_hash (&keyword[1], strlen (&keyword[1]), &key); GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv); GNUNET_CRYPTO_aes_encrypt (&pkc->kb[1], pkc->slen + pkc->mdsize, &skey, &iv, &pkc->cpy[1]); pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&key); GNUNET_assert (NULL != pk); GNUNET_CRYPTO_rsa_key_get_public (pk, &pkc->cpy->keyspace); GNUNET_CRYPTO_hash (&pkc->cpy->keyspace, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &query); GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_rsa_sign (pk, &pkc->cpy->purpose, &pkc->cpy->signature)); GNUNET_CRYPTO_rsa_key_free (pk); pkc->qre = GNUNET_DATASTORE_put (pkc->dsh, 0, &query, pkc->mdsize + sizeof (struct KBlock) + pkc->slen, pkc->cpy, GNUNET_BLOCK_TYPE_FS_KBLOCK, pkc->bo.content_priority, pkc->bo.anonymity_level, pkc->bo.replication_level, pkc->bo.expiration_time, -2, 1, GNUNET_CONSTANTS_SERVICE_TIMEOUT, &kb_put_cont, pkc); } /** * Publish a CHK under various keywords on GNUnet. * * @param h handle to the file sharing subsystem * @param ksk_uri keywords to use * @param meta metadata to use * @param uri URI to refer to in the KBlock * @param bo per-block options * @param options publication options * @param cont continuation * @param cont_cls closure for cont * @return NULL on error ('cont' will still be called) */ struct GNUNET_FS_PublishKskContext * GNUNET_FS_publish_ksk (struct GNUNET_FS_Handle *h, const struct GNUNET_FS_Uri *ksk_uri, const struct GNUNET_CONTAINER_MetaData *meta, const struct GNUNET_FS_Uri *uri, const struct GNUNET_FS_BlockOptions *bo, enum GNUNET_FS_PublishOptions options, GNUNET_FS_PublishContinuation cont, void *cont_cls) { struct GNUNET_FS_PublishKskContext *pkc; char *uris; size_t size; char *kbe; char *sptr; GNUNET_assert (NULL != uri); pkc = GNUNET_malloc (sizeof (struct GNUNET_FS_PublishKskContext)); pkc->h = h; pkc->bo = *bo; pkc->cont = cont; pkc->cont_cls = cont_cls; if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) { pkc->dsh = GNUNET_DATASTORE_connect (h->cfg); if (NULL == pkc->dsh) { cont (cont_cls, NULL, _("Could not connect to datastore.")); GNUNET_free (pkc); return NULL; } } if (meta == NULL) pkc->mdsize = 0; else pkc->mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta); GNUNET_assert (pkc->mdsize >= 0); uris = GNUNET_FS_uri_to_string (uri); pkc->slen = strlen (uris) + 1; size = pkc->mdsize + sizeof (struct KBlock) + pkc->slen; if (size > MAX_KBLOCK_SIZE) { size = MAX_KBLOCK_SIZE; pkc->mdsize = size - sizeof (struct KBlock) - pkc->slen; } pkc->kb = GNUNET_malloc (size); kbe = (char *) &pkc->kb[1]; memcpy (kbe, uris, pkc->slen); GNUNET_free (uris); sptr = &kbe[pkc->slen]; if (meta != NULL) pkc->mdsize = GNUNET_CONTAINER_meta_data_serialize (meta, &sptr, pkc->mdsize, GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); if (-1 == pkc->mdsize) { GNUNET_break (0); GNUNET_free (pkc->kb); if (pkc->dsh != NULL) { GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO); pkc->dsh = NULL; } GNUNET_free (pkc); cont (cont_cls, NULL, _("Internal error.")); return NULL; } size = sizeof (struct KBlock) + pkc->slen + pkc->mdsize; pkc->cpy = GNUNET_malloc (size); pkc->cpy->purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + pkc->mdsize + pkc->slen); pkc->cpy->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_KBLOCK); pkc->ksk_uri = GNUNET_FS_uri_dup (ksk_uri); pkc->ksk_task = GNUNET_SCHEDULER_add_now (&publish_ksk_cont, pkc); return pkc; } /** * Abort the KSK publishing operation. * * @param pkc context of the operation to abort. */ void GNUNET_FS_publish_ksk_cancel (struct GNUNET_FS_PublishKskContext *pkc) { if (GNUNET_SCHEDULER_NO_TASK != pkc->ksk_task) { GNUNET_SCHEDULER_cancel (pkc->ksk_task); pkc->ksk_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != pkc->qre) { GNUNET_DATASTORE_cancel (pkc->qre); pkc->qre = NULL; } if (NULL != pkc->dsh) { GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO); pkc->dsh = NULL; } GNUNET_free (pkc->cpy); GNUNET_free (pkc->kb); GNUNET_FS_uri_destroy (pkc->ksk_uri); GNUNET_free (pkc); } /* end of fs_publish_ksk.c */ gnunet-0.9.3/src/fs/gnunet-service-fs_indexing.c0000644000175000017500000004450111760502551016546 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-service-fs_indexing.c * @brief program that provides indexing functions of the file-sharing service * @author Christian Grothoff */ #include "platform.h" #include #include "gnunet_core_service.h" #include "gnunet_datastore_service.h" #include "gnunet_peer_lib.h" #include "gnunet_protocols.h" #include "gnunet_signatures.h" #include "gnunet_util_lib.h" #include "gnunet-service-fs.h" #include "gnunet-service-fs_indexing.h" #include "fs.h" /** * In-memory information about indexed files (also available * on-disk). */ struct IndexInfo { /** * This is a linked list. */ struct IndexInfo *next; /** * Name of the indexed file. Memory allocated * at the end of this struct (do not free). */ const char *filename; /** * Context for transmitting confirmation to client, * NULL if we've done this already. */ struct GNUNET_SERVER_TransmitContext *tc; /** * Context for hashing of the file. */ struct GNUNET_CRYPTO_FileHashContext *fhc; /** * Hash of the contents of the file. */ GNUNET_HashCode file_id; }; /** * Linked list of indexed files. */ static struct IndexInfo *indexed_files; /** * Maps hash over content of indexed files to the respective filename. * The filenames are pointers into the indexed_files linked list and * do not need to be freed. */ static struct GNUNET_CONTAINER_MultiHashMap *ifm; /** * Our configuration. */ static const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Datastore handle. Created and destroyed by code in * gnunet-service-fs (this is an alias). */ static struct GNUNET_DATASTORE_Handle *dsh; /** * Write the current index information list to disk. */ static void write_index_list () { struct GNUNET_BIO_WriteHandle *wh; char *fn; struct IndexInfo *pos; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "FS", "INDEXDB", &fn)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, _("Configuration option `%s' in section `%s' missing.\n"), "INDEXDB", "FS"); return; } wh = GNUNET_BIO_write_open (fn); if (NULL == wh) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, _("Could not open `%s'.\n"), fn); GNUNET_free (fn); return; } pos = indexed_files; while (pos != NULL) { if ((GNUNET_OK != GNUNET_BIO_write (wh, &pos->file_id, sizeof (GNUNET_HashCode))) || (GNUNET_OK != GNUNET_BIO_write_string (wh, pos->filename))) break; pos = pos->next; } if (GNUNET_OK != GNUNET_BIO_write_close (wh)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, _("Error writing `%s'.\n"), fn); GNUNET_free (fn); return; } GNUNET_free (fn); } /** * Read index information from disk. */ static void read_index_list () { struct GNUNET_BIO_ReadHandle *rh; char *fn; struct IndexInfo *pos; char *fname; GNUNET_HashCode hc; size_t slen; char *emsg; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "FS", "INDEXDB", &fn)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, _("Configuration option `%s' in section `%s' missing.\n"), "INDEXDB", "FS"); return; } if (GNUNET_NO == GNUNET_DISK_file_test (fn)) { /* no index info yet */ GNUNET_free (fn); return; } rh = GNUNET_BIO_read_open (fn); if (NULL == rh) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, _("Could not open `%s'.\n"), fn); GNUNET_free (fn); return; } while ((GNUNET_OK == GNUNET_BIO_read (rh, "Hash of indexed file", &hc, sizeof (GNUNET_HashCode))) && (GNUNET_OK == GNUNET_BIO_read_string (rh, "Name of indexed file", &fname, 1024 * 16)) && (fname != NULL)) { slen = strlen (fname) + 1; pos = GNUNET_malloc (sizeof (struct IndexInfo) + slen); pos->file_id = hc; pos->filename = (const char *) &pos[1]; memcpy (&pos[1], fname, slen); if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (ifm, &hc, (void *) pos->filename, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) { GNUNET_free (pos); } else { pos->next = indexed_files; indexed_files = pos; } GNUNET_free (fname); } if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg)) GNUNET_free (emsg); GNUNET_free (fn); } /** * We've validated the hash of the file we're about to index. Signal * success to the client and update our internal data structures. * * @param ii the index info entry for the request */ static void signal_index_ok (struct IndexInfo *ii) { if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (ifm, &ii->file_id, (void *) ii->filename, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Index request received for file `%s' is already indexed as `%s'. Permitting anyway.\n"), ii->filename, (const char *) GNUNET_CONTAINER_multihashmap_get (ifm, &ii->file_id)); GNUNET_SERVER_transmit_context_append_data (ii->tc, NULL, 0, GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK); GNUNET_SERVER_transmit_context_run (ii->tc, GNUNET_TIME_UNIT_MINUTES); GNUNET_free (ii); return; } ii->next = indexed_files; indexed_files = ii; write_index_list (); GNUNET_SERVER_transmit_context_append_data (ii->tc, NULL, 0, GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK); GNUNET_SERVER_transmit_context_run (ii->tc, GNUNET_TIME_UNIT_MINUTES); ii->tc = NULL; } /** * Function called once the hash computation over an * indexed file has completed. * * @param cls closure, our publishing context * @param res resulting hash, NULL on error */ static void hash_for_index_val (void *cls, const GNUNET_HashCode * res) { struct IndexInfo *ii = cls; ii->fhc = NULL; if ((res == NULL) || (0 != memcmp (res, &ii->file_id, sizeof (GNUNET_HashCode)))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Hash mismatch trying to index file `%s' which has hash `%s'\n"), ii->filename, GNUNET_h2s (res)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Wanted `%s'\n", GNUNET_h2s (&ii->file_id)); GNUNET_SERVER_transmit_context_append_data (ii->tc, NULL, 0, GNUNET_MESSAGE_TYPE_FS_INDEX_START_FAILED); GNUNET_SERVER_transmit_context_run (ii->tc, GNUNET_TIME_UNIT_MINUTES); GNUNET_free (ii); return; } signal_index_ok (ii); } /** * Handle INDEX_START-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ void GNUNET_FS_handle_index_start (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct IndexStartMessage *ism; char *fn; uint16_t msize; struct IndexInfo *ii; size_t slen; uint64_t dev; uint64_t ino; uint64_t mydev; uint64_t myino; msize = ntohs (message->size); if ((msize <= sizeof (struct IndexStartMessage)) || (((const char *) message)[msize - 1] != '\0')) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } ism = (const struct IndexStartMessage *) message; if (0 != ism->reserved) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } fn = GNUNET_STRINGS_filename_expand ((const char *) &ism[1]); if (fn == NULL) { GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } dev = GNUNET_ntohll (ism->device); ino = GNUNET_ntohll (ism->inode); ism = (const struct IndexStartMessage *) message; slen = strlen (fn) + 1; ii = GNUNET_malloc (sizeof (struct IndexInfo) + slen); ii->filename = (const char *) &ii[1]; memcpy (&ii[1], fn, slen); ii->file_id = ism->file_id; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message for file `%s'\n", "START_INDEX", ii->filename); ii->tc = GNUNET_SERVER_transmit_context_create (client); mydev = 0; myino = 0; if (((dev != 0) || (ino != 0)) && (GNUNET_OK == GNUNET_DISK_file_get_identifiers (fn, &mydev, &myino)) && ((dev == mydev) && (ino == myino))) { /* fast validation OK! */ signal_index_ok (ii); GNUNET_free (fn); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Mismatch in file identifiers (%llu != %llu or %u != %u), need to hash.\n", (unsigned long long) ino, (unsigned long long) myino, (unsigned int) dev, (unsigned int) mydev); /* slow validation, need to hash full file (again) */ ii->fhc = GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE, fn, HASHING_BLOCKSIZE, &hash_for_index_val, ii); if (ii->fhc == NULL) hash_for_index_val (ii, NULL); GNUNET_free (fn); } /** * Handle INDEX_LIST_GET-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ void GNUNET_FS_handle_index_list_get (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct GNUNET_SERVER_TransmitContext *tc; struct IndexInfoMessage *iim; char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN; size_t slen; const char *fn; struct IndexInfo *pos; tc = GNUNET_SERVER_transmit_context_create (client); iim = (struct IndexInfoMessage *) buf; pos = indexed_files; while (NULL != pos) { fn = pos->filename; slen = strlen (fn) + 1; if (slen + sizeof (struct IndexInfoMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); break; } iim->header.type = htons (GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_ENTRY); iim->header.size = htons (slen + sizeof (struct IndexInfoMessage)); iim->reserved = 0; iim->file_id = pos->file_id; memcpy (&iim[1], fn, slen); GNUNET_SERVER_transmit_context_append_message (tc, &iim->header); pos = pos->next; } GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_END); GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_MINUTES); } /** * Handle UNINDEX-message. * * @param cls closure * @param client identification of the client * @param message the actual message */ void GNUNET_FS_handle_unindex (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct UnindexMessage *um; struct IndexInfo *pos; struct IndexInfo *prev; struct IndexInfo *next; struct GNUNET_SERVER_TransmitContext *tc; int found; um = (const struct UnindexMessage *) message; if (0 != um->reserved) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } found = GNUNET_NO; prev = NULL; pos = indexed_files; while (NULL != pos) { next = pos->next; if (0 == memcmp (&pos->file_id, &um->file_id, sizeof (GNUNET_HashCode))) { if (prev == NULL) indexed_files = next; else prev->next = next; GNUNET_break (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (ifm, &pos->file_id, (void *) pos->filename)); GNUNET_free (pos); found = GNUNET_YES; } else { prev = pos; } pos = next; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client requested unindexing of file `%s': %s\n", GNUNET_h2s (&um->file_id), found ? "found" : "not found"); if (GNUNET_YES == found) write_index_list (); tc = GNUNET_SERVER_transmit_context_create (client); GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK); GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_MINUTES); } /** * Continuation called from datastore's remove * function. * * @param cls unused * @param success did the deletion work? * @param min_expiration minimum expiration time required for content to be stored * @param msg error message */ static void remove_cont (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) { if (GNUNET_OK != success) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to delete bogus block: %s\n"), msg); } /** * We've received an on-demand encoded block from the datastore. * Attempt to do on-demand encoding and (if successful), call the * continuation with the resulting block. On error, clean up and ask * the datastore for more results. * * @param key key for the content * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param expiration expiration time for the content * @param uid unique identifier for the datum; * maybe 0 if no unique identifier is available * @param cont function to call with the actual block (at most once, on success) * @param cont_cls closure for cont * @return GNUNET_OK on success */ int GNUNET_FS_handle_on_demand_block (const GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid, GNUNET_DATASTORE_DatumProcessor cont, void *cont_cls) { const struct OnDemandBlock *odb; GNUNET_HashCode nkey; struct GNUNET_CRYPTO_AesSessionKey skey; struct GNUNET_CRYPTO_AesInitializationVector iv; GNUNET_HashCode query; ssize_t nsize; char ndata[DBLOCK_SIZE]; char edata[DBLOCK_SIZE]; const char *fn; struct GNUNET_DISK_FileHandle *fh; uint64_t off; if (size != sizeof (struct OnDemandBlock)) { GNUNET_break (0); GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, GNUNET_TIME_UNIT_FOREVER_REL, &remove_cont, NULL); return GNUNET_SYSERR; } odb = (const struct OnDemandBlock *) data; off = GNUNET_ntohll (odb->offset); fn = (const char *) GNUNET_CONTAINER_multihashmap_get (ifm, &odb->file_id); if ((NULL == fn) || (0 != ACCESS (fn, R_OK))) { GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# index blocks removed: original file inaccessible"), 1, GNUNET_YES); GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, GNUNET_TIME_UNIT_FOREVER_REL, &remove_cont, NULL); return GNUNET_SYSERR; } if ((NULL == (fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE))) || (off != GNUNET_DISK_file_seek (fh, off, GNUNET_DISK_SEEK_SET)) || (-1 == (nsize = GNUNET_DISK_file_read (fh, ndata, sizeof (ndata))))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not access indexed file `%s' (%s) at offset %llu: %s\n"), GNUNET_h2s (&odb->file_id), fn, (unsigned long long) off, (fn == NULL) ? _("not indexed") : STRERROR (errno)); if (fh != NULL) GNUNET_DISK_file_close (fh); GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, GNUNET_TIME_UNIT_FOREVER_REL, &remove_cont, NULL); return GNUNET_SYSERR; } GNUNET_DISK_file_close (fh); GNUNET_CRYPTO_hash (ndata, nsize, &nkey); GNUNET_CRYPTO_hash_to_aes_key (&nkey, &skey, &iv); GNUNET_CRYPTO_aes_encrypt (ndata, nsize, &skey, &iv, edata); GNUNET_CRYPTO_hash (edata, nsize, &query); if (0 != memcmp (&query, key, sizeof (GNUNET_HashCode))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Indexed file `%s' changed at offset %llu\n"), fn, (unsigned long long) off); GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, GNUNET_TIME_UNIT_FOREVER_REL, &remove_cont, NULL); return GNUNET_SYSERR; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "On-demand encoded block for query `%s'\n", GNUNET_h2s (key)); cont (cont_cls, key, nsize, edata, GNUNET_BLOCK_TYPE_FS_DBLOCK, priority, anonymity, expiration, uid); return GNUNET_OK; } /** * Shutdown the module. */ void GNUNET_FS_indexing_done () { struct IndexInfo *pos; GNUNET_CONTAINER_multihashmap_destroy (ifm); ifm = NULL; while (NULL != (pos = indexed_files)) { indexed_files = pos->next; if (pos->fhc != NULL) GNUNET_CRYPTO_hash_file_cancel (pos->fhc); GNUNET_free (pos); } cfg = NULL; } /** * Initialize the indexing submodule. * * @param c configuration to use * @param d datastore to use */ int GNUNET_FS_indexing_init (const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_DATASTORE_Handle *d) { cfg = c; dsh = d; ifm = GNUNET_CONTAINER_multihashmap_create (128); read_index_list (); return GNUNET_OK; } /* end of gnunet-service-fs_indexing.c */ gnunet-0.9.3/src/fs/test_fs_download_data.conf0000644000175000017500000000017711615567501016355 00000000000000@INLINE@ test_fs_defaults.conf [PATHS] SERVICEHOME = /tmp/gnunet-test-fs-download/ DEFAULTCONFIG = test_fs_download_data.conf gnunet-0.9.3/src/fs/test_fs_publish_persistence.c0000644000175000017500000002705611760502551017124 00000000000000/* This file is part of GNUnet. (C) 2004, 2005, 2006, 2008, 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/test_fs_publish_persistence.c * @brief simple testcase for persistence of simple publish operation * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_arm_service.h" #include "gnunet_fs_service.h" #define VERBOSE GNUNET_NO #define START_ARM GNUNET_YES /** * File-size we use for testing. */ #define FILESIZE (1024 * 1024 * 2) /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) /** * How long should our test-content live? */ #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static struct PeerContext p1; static struct GNUNET_TIME_Absolute start; static struct GNUNET_FS_Handle *fs; static const struct GNUNET_CONFIGURATION_Handle *cfg; static struct GNUNET_FS_PublishContext *publish; static struct GNUNET_FS_PublishContext *publish; static char *fn1; static char *fn2; static int err; static GNUNET_SCHEDULER_TaskIdentifier rtask; static void abort_publish_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_FS_publish_stop (publish); publish = NULL; GNUNET_DISK_directory_remove (fn1); GNUNET_free (fn1); fn1 = NULL; GNUNET_DISK_directory_remove (fn2); GNUNET_free (fn2); fn2 = NULL; GNUNET_FS_stop (fs); fs = NULL; if (GNUNET_SCHEDULER_NO_TASK != rtask) { GNUNET_SCHEDULER_cancel (rtask); rtask = GNUNET_SCHEDULER_NO_TASK; } } static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event); static void restart_fs_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { rtask = GNUNET_SCHEDULER_NO_TASK; GNUNET_FS_stop (fs); fs = GNUNET_FS_start (cfg, "test-fs-publish-persistence", &progress_cb, NULL, GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); } /** * Consider scheduling the restart-task. * Only runs the restart task once per event * category. * * @param ev type of the event to consider */ static void consider_restart (int ev) { static int prev[32]; static int off; int i; for (i = 0; i < off; i++) if (prev[i] == ev) return; prev[off++] = ev; rtask = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_URGENT, &restart_fs_task, NULL); } static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) { void *ret; ret = NULL; switch (event->status) { case GNUNET_FS_STATUS_PUBLISH_COMPLETED: consider_restart (event->status); ret = event->value.publish.cctx; printf ("Publish complete, %llu kbps.\n", (unsigned long long) (FILESIZE * 1000LL / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value) / 1024)); if (0 == strcmp ("publish-context-dir", event->value.publish.cctx)) GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); break; case GNUNET_FS_STATUS_PUBLISH_PROGRESS: consider_restart (event->status); ret = event->value.publish.cctx; GNUNET_assert (publish == event->value.publish.pc); #if VERBOSE printf ("Publish is progressing (%llu/%llu at level %u off %llu)...\n", (unsigned long long) event->value.publish.completed, (unsigned long long) event->value.publish.size, event->value.publish.specifics.progress.depth, (unsigned long long) event->value.publish.specifics. progress.offset); #endif break; case GNUNET_FS_STATUS_PUBLISH_SUSPEND: if (event->value.publish.pc == publish) publish = NULL; break; case GNUNET_FS_STATUS_PUBLISH_RESUME: if (NULL == publish) { GNUNET_assert (GNUNET_YES == GNUNET_FS_file_information_is_directory (event-> value.publish. fi)); publish = event->value.publish.pc; return "publish-context-dir"; } break; case GNUNET_FS_STATUS_PUBLISH_ERROR: ret = event->value.publish.cctx; FPRINTF (stderr, "Error publishing file: %s\n", event->value.publish.specifics.error.message); err = 1; GNUNET_SCHEDULER_add_now (&abort_publish_task, NULL); break; case GNUNET_FS_STATUS_PUBLISH_START: consider_restart (event->status); publish = event->value.publish.pc; ret = event->value.publish.cctx; if (0 == strcmp ("publish-context1", event->value.publish.cctx)) { GNUNET_assert (0 == strcmp ("publish-context-dir", event->value.publish.pctx)); GNUNET_assert (FILESIZE == event->value.publish.size); GNUNET_assert (0 == event->value.publish.completed); GNUNET_assert (1 == event->value.publish.anonymity); } else if (0 == strcmp ("publish-context2", event->value.publish.cctx)) { GNUNET_assert (0 == strcmp ("publish-context-dir", event->value.publish.pctx)); GNUNET_assert (FILESIZE == event->value.publish.size); GNUNET_assert (0 == event->value.publish.completed); GNUNET_assert (2 == event->value.publish.anonymity); } else if (0 == strcmp ("publish-context-dir", event->value.publish.cctx)) { GNUNET_assert (0 == event->value.publish.completed); GNUNET_assert (3 == event->value.publish.anonymity); } else GNUNET_assert (0); break; case GNUNET_FS_STATUS_PUBLISH_STOPPED: consider_restart (event->status); if (0 == strcmp ("publish-context-dir", event->value.publish.cctx)) GNUNET_assert (publish == event->value.publish.pc); break; default: printf ("Unexpected event: %d\n", event->status); break; } return ret; } static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE "-L", "DEBUG", #endif "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); } static void stop_arm (struct PeerContext *p) { #if START_ARM if (NULL != p->arm_proc) { if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; } #endif GNUNET_CONFIGURATION_destroy (p->cfg); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { const char *keywords[] = { "down_foo", "down_bar", }; char *buf; struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_FS_Uri *kuri; struct GNUNET_FS_FileInformation *fi1; struct GNUNET_FS_FileInformation *fi2; struct GNUNET_FS_FileInformation *fidir; size_t i; struct GNUNET_FS_BlockOptions bo; cfg = c; setup_peer (&p1, "test_fs_publish_data.conf"); fs = GNUNET_FS_start (cfg, "test-fs-publish-persistence", &progress_cb, NULL, GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); GNUNET_assert (NULL != fs); fn1 = GNUNET_DISK_mktemp ("gnunet-publish-test-dst"); buf = GNUNET_malloc (FILESIZE); for (i = 0; i < FILESIZE; i++) buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); GNUNET_assert (FILESIZE == GNUNET_DISK_fn_write (fn1, buf, FILESIZE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)); GNUNET_free (buf); fn2 = GNUNET_DISK_mktemp ("gnunet-publish-test-dst"); buf = GNUNET_malloc (FILESIZE); for (i = 0; i < FILESIZE; i++) buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); GNUNET_assert (FILESIZE == GNUNET_DISK_fn_write (fn2, buf, FILESIZE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)); GNUNET_free (buf); meta = GNUNET_CONTAINER_meta_data_create (); kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); bo.content_priority = 42; bo.anonymity_level = 1; bo.replication_level = 0; bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); fi1 = GNUNET_FS_file_information_create_from_file (fs, "publish-context1", fn1, kuri, meta, GNUNET_YES, &bo); GNUNET_assert (NULL != fi1); bo.anonymity_level = 2; fi2 = GNUNET_FS_file_information_create_from_file (fs, "publish-context2", fn2, kuri, meta, GNUNET_YES, &bo); GNUNET_assert (NULL != fi2); bo.anonymity_level = 3; fidir = GNUNET_FS_file_information_create_empty_directory (fs, "publish-context-dir", kuri, meta, &bo, NULL); GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi1)); GNUNET_assert (GNUNET_OK == GNUNET_FS_file_information_add (fidir, fi2)); GNUNET_FS_uri_destroy (kuri); GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_assert (NULL != fidir); start = GNUNET_TIME_absolute_get (); GNUNET_FS_publish_start (fs, fidir, NULL, NULL, NULL, GNUNET_FS_PUBLISH_OPTION_NONE); GNUNET_assert (publish != NULL); } int main (int argc, char *argv[]) { char *const argvx[] = { "test-fs-publish-persistence", "-c", "test_fs_publish_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("test_fs_publish_persistence", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "test-fs-publish", "nohelp", options, &run, NULL); stop_arm (&p1); GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-publish/"); if (fn1 != NULL) { GNUNET_DISK_directory_remove (fn1); GNUNET_free (fn1); } if (fn2 != NULL) { GNUNET_DISK_directory_remove (fn2); GNUNET_free (fn2); } return err; } /* end of test_fs_publish_persistence.c */ gnunet-0.9.3/src/fs/test_fs_download_persistence.c0000644000175000017500000003122111760502551017252 00000000000000/* This file is part of GNUnet. (C) 2004, 2005, 2006, 2008, 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/test_fs_download_persistence.c * @brief simple testcase for persistence of simple download operation * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_arm_service.h" #include "gnunet_fs_service.h" #define VERBOSE GNUNET_NO #define START_ARM GNUNET_YES /** * File-size we use for testing. */ #define FILESIZE (1024 * 1024 * 2) /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) /** * How long should our test-content live? */ #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static struct PeerContext p1; static struct GNUNET_TIME_Absolute start; static const struct GNUNET_CONFIGURATION_Handle *cfg; static struct GNUNET_FS_Handle *fs; static struct GNUNET_FS_DownloadContext *download; static struct GNUNET_FS_PublishContext *publish; static GNUNET_SCHEDULER_TaskIdentifier timeout_kill; static char *fn; static int err; static void timeout_kill_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout downloading file\n"); if (download != NULL) { GNUNET_FS_download_stop (download, GNUNET_YES); download = NULL; } else if (publish != NULL) { GNUNET_FS_publish_stop (publish); publish = NULL; } timeout_kill = GNUNET_SCHEDULER_NO_TASK; err = 1; } static void abort_publish_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (publish != NULL) { GNUNET_FS_publish_stop (publish); publish = NULL; } } static void abort_download_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { uint64_t size; if (download != NULL) { GNUNET_FS_download_stop (download, GNUNET_YES); download = NULL; } GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_size (fn, &size, GNUNET_YES, GNUNET_NO)); GNUNET_assert (size == FILESIZE); GNUNET_DISK_directory_remove (fn); GNUNET_free (fn); fn = NULL; GNUNET_SCHEDULER_cancel (timeout_kill); timeout_kill = GNUNET_SCHEDULER_NO_TASK; } static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event); static void restart_fs_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Restarting FS.\n"); GNUNET_FS_stop (fs); fs = GNUNET_FS_start (cfg, "test-fs-download-persistence", &progress_cb, NULL, GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); } /** * Consider scheduling the restart-task. * Only runs the restart task once per event * category. * * @param ev type of the event to consider */ static void consider_restart (int ev) { static int prev[32]; static int off; int i; for (i = 0; i < off; i++) if (prev[i] == ev) return; prev[off++] = ev; GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_URGENT, &restart_fs_task, NULL); } static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) { switch (event->status) { case GNUNET_FS_STATUS_PUBLISH_PROGRESS: #if VERBOSE printf ("Publish is progressing (%llu/%llu at level %u off %llu)...\n", (unsigned long long) event->value.publish.completed, (unsigned long long) event->value.publish.size, event->value.publish.specifics.progress.depth, (unsigned long long) event->value.publish.specifics. progress.offset); #endif break; case GNUNET_FS_STATUS_PUBLISH_COMPLETED: printf ("Publishing complete, %llu kbps.\n", (unsigned long long) (FILESIZE * 1000LL / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value) / 1024LL)); fn = GNUNET_DISK_mktemp ("gnunet-download-test-dst"); start = GNUNET_TIME_absolute_get (); GNUNET_assert (download == NULL); GNUNET_FS_download_start (fs, event->value.publish.specifics.completed.chk_uri, NULL, fn, NULL, 0, FILESIZE, 1, GNUNET_FS_DOWNLOAD_OPTION_NONE, "download", NULL); break; case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: consider_restart (event->status); printf ("Download complete, %llu kbps.\n", (unsigned long long) (FILESIZE * 1000LL / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value) / 1024LL)); GNUNET_SCHEDULER_add_now (&abort_download_task, NULL); break; case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: consider_restart (event->status); GNUNET_assert (download == event->value.download.dc); #if VERBOSE printf ("Download is progressing (%llu/%llu at level %u off %llu)...\n", (unsigned long long) event->value.download.completed, (unsigned long long) event->value.download.size, event->value.download.specifics.progress.depth, (unsigned long long) event->value.download.specifics. progress.offset); #endif break; case GNUNET_FS_STATUS_PUBLISH_ERROR: FPRINTF (stderr, "Error publishing file: %s\n", event->value.publish.specifics.error.message); GNUNET_break (0); GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_DOWNLOAD_ERROR: FPRINTF (stderr, "Error downloading file: %s\n", event->value.download.specifics.error.message); GNUNET_SCHEDULER_add_now (&abort_download_task, NULL); break; case GNUNET_FS_STATUS_PUBLISH_SUSPEND: GNUNET_assert (event->value.publish.pc == publish); publish = NULL; break; case GNUNET_FS_STATUS_PUBLISH_RESUME: GNUNET_assert (NULL == publish); publish = event->value.publish.pc; break; case GNUNET_FS_STATUS_DOWNLOAD_SUSPEND: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download suspended.\n"); GNUNET_assert (event->value.download.dc == download); download = NULL; break; case GNUNET_FS_STATUS_DOWNLOAD_RESUME: GNUNET_assert (NULL == download); download = event->value.download.dc; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download resumed.\n"); break; case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: consider_restart (event->status); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download active.\n"); break; case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: consider_restart (event->status); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download inactive.\n"); break; case GNUNET_FS_STATUS_PUBLISH_START: GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); GNUNET_assert (NULL == event->value.publish.pctx); GNUNET_assert (FILESIZE == event->value.publish.size); GNUNET_assert (0 == event->value.publish.completed); GNUNET_assert (1 == event->value.publish.anonymity); break; case GNUNET_FS_STATUS_PUBLISH_STOPPED: GNUNET_assert (publish == event->value.publish.pc); GNUNET_assert (FILESIZE == event->value.publish.size); GNUNET_assert (1 == event->value.publish.anonymity); GNUNET_FS_stop (fs); fs = NULL; break; case GNUNET_FS_STATUS_DOWNLOAD_START: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download started.\n"); consider_restart (event->status); GNUNET_assert (download == NULL); download = event->value.download.dc; GNUNET_assert (0 == strcmp ("download", event->value.download.cctx)); GNUNET_assert (NULL == event->value.download.pctx); GNUNET_assert (NULL != event->value.download.uri); GNUNET_assert (0 == strcmp (fn, event->value.download.filename)); GNUNET_assert (FILESIZE == event->value.download.size); GNUNET_assert (0 == event->value.download.completed); GNUNET_assert (1 == event->value.download.anonymity); break; case GNUNET_FS_STATUS_DOWNLOAD_STOPPED: GNUNET_assert (download == event->value.download.dc); GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); download = NULL; break; default: printf ("Unexpected event: %d\n", event->status); break; } return NULL; } static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE "-L", "DEBUG", #endif "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); } static void stop_arm (struct PeerContext *p) { #if START_ARM if (NULL != p->arm_proc) { if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; } #endif GNUNET_CONFIGURATION_destroy (p->cfg); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { const char *keywords[] = { "down_foo", "down_bar", }; char *buf; struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_FS_Uri *kuri; struct GNUNET_FS_FileInformation *fi; size_t i; struct GNUNET_FS_BlockOptions bo; cfg = c; setup_peer (&p1, "test_fs_download_data.conf"); fs = GNUNET_FS_start (cfg, "test-fs-download-persistence", &progress_cb, NULL, GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); GNUNET_assert (NULL != fs); buf = GNUNET_malloc (FILESIZE); for (i = 0; i < FILESIZE; i++) buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); meta = GNUNET_CONTAINER_meta_data_create (); kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); bo.content_priority = 42; bo.anonymity_level = 1; bo.replication_level = 0; bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); fi = GNUNET_FS_file_information_create_from_data (fs, "publish-context", FILESIZE, buf, kuri, meta, GNUNET_NO, &bo); GNUNET_FS_uri_destroy (kuri); GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_assert (NULL != fi); timeout_kill = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_kill_task, NULL); start = GNUNET_TIME_absolute_get (); publish = GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, GNUNET_FS_PUBLISH_OPTION_NONE); GNUNET_assert (publish != NULL); } int main (int argc, char *argv[]) { char *const argvx[] = { "test-fs-download-persistence", "-c", "test_fs_download_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("test_fs_download_persistence", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-download/"); GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "test-fs-download-persistence", "nohelp", options, &run, NULL); stop_arm (&p1); GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-download/"); return err; } /* end of test_fs_download_persistence.c */ gnunet-0.9.3/src/fs/test_gnunet_fs_psd_data.conf0000644000175000017500000000022711615567501016710 00000000000000@INLINE@ test_fs_defaults.conf [PATHS] SERVICEHOME = /tmp/gnunet-test-fs-py-psd/ DEFAULTCONFIG = test_gnunet_fs_psd_data.conf [transport] PLUGINS = gnunet-0.9.3/src/fs/perf_gnunet_service_fs_p2p_trust.c0000644000175000017500000003006511760502551020063 00000000000000/* This file is part of GNUnet. (C) 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/perf_gnunet_service_fs_p2p_trust.c * @brief profile P2P routing trust mechanism. Creates * a clique of NUM_DAEMONS (i.e. 3) where two * peers share (seed) different files and download * them from each other while all the other peers * just "leach" those files. Ideally, the seeders * "learn" that they contribute (to each other), * and give the other seeder higher priority; * naturally, this only happens nicely for larger * files; finally, once the seeders are done, the * leachers should see fast download rates as well. * @author Christian Grothoff * * Sample output: * - 10 MB, 3 peers, with delays: * Download speed of type `seeder 1' was 757 KiB/s * Download speed of type `seeder 2' was 613 KiB/s * Download speed of type `leach` was 539 KiB/s * * - 10 MB, 3 peers, without delays: * Download speed of type `seeder 1' was 1784 KiB/s * Download speed of type `seeder 2' was 1604 KiB/s * Download speed of type `leach` was 1384 KiB/s */ #include "platform.h" #include "fs_test_lib.h" #include "gnunet_testing_lib.h" #define VERBOSE GNUNET_NO /** * File-size we use for testing. */ #define FILESIZE (1024 * 1024 * 1) /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30) /** * Number of daemons in clique, must be at least 3 (!). */ #define NUM_DAEMONS 3 /** * Seed for first file on offer. */ #define SEED1 42 /** * Seed for second file on offer. */ #define SEED2 43 static struct GNUNET_FS_TestDaemon *daemons[NUM_DAEMONS]; static int ok; static struct GNUNET_TIME_Absolute start_time; static const char *progname; static struct GNUNET_FS_Uri *uri1; static struct GNUNET_FS_Uri *uri2; static void do_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons); } /** * Master context for 'stat_run'. */ struct StatMaster { struct GNUNET_STATISTICS_Handle *stat; unsigned int daemon; unsigned int value; }; struct StatValues { const char *subsystem; const char *name; }; /** * Statistics we print out. */ static struct StatValues stats[] = { {"fs", "# artificial delays introduced (ms)"}, {"fs", "# queries forwarded"}, {"fs", "# replies received and matched"}, {"fs", "# results found locally"}, {"fs", "# requests forwarded due to high load"}, {"fs", "# requests done for free (low load)"}, {"fs", "# requests dropped, priority insufficient"}, {"fs", "# requests done for a price (normal load)"}, {"fs", "# requests dropped by datastore (queue length limit)"}, {"fs", "# P2P searches received"}, {"fs", "# P2P searches discarded (queue length bound)"}, {"fs", "# replies received for local clients"}, {"fs", "# queries retransmitted to same target"}, {"core", "# bytes decrypted"}, {"core", "# bytes encrypted"}, {"core", "# discarded CORE_SEND requests"}, {"core", "# discarded lower priority CORE_SEND requests"}, {"transport", "# bytes received via TCP"}, {"transport", "# bytes transmitted via TCP"}, {"datacache", "# bytes stored"}, {NULL, NULL} }; /** * Callback function to process statistic values. * * @param cls closure * @param subsystem name of subsystem that created the statistic * @param name the name of the datum * @param value the current value * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration */ static int print_stat (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent) { struct StatMaster *sm = cls; FPRINTF (stderr, "Peer %2u: %12s/%50s = %12llu\n", sm->daemon, subsystem, name, (unsigned long long) value); return GNUNET_OK; } /** * Function that gathers stats from all daemons. */ static void stat_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Function called when GET operation on stats is done. */ static void get_done (void *cls, int success) { struct StatMaster *sm = cls; GNUNET_break (GNUNET_OK == success); sm->value++; GNUNET_SCHEDULER_add_now (&stat_run, sm); } /** * Function that gathers stats from all daemons. */ static void stat_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct StatMaster *sm = cls; if (stats[sm->value].name != NULL) { GNUNET_STATISTICS_get (sm->stat, #if 0 NULL, NULL, #else stats[sm->value].subsystem, stats[sm->value].name, #endif GNUNET_TIME_UNIT_FOREVER_REL, &get_done, &print_stat, sm); return; } GNUNET_STATISTICS_destroy (sm->stat, GNUNET_NO); sm->value = 0; sm->daemon++; if (sm->daemon == NUM_DAEMONS) { GNUNET_free (sm); GNUNET_SCHEDULER_add_now (&do_stop, NULL); return; } sm->stat = GNUNET_STATISTICS_create ("", GNUNET_FS_TEST_get_configuration (daemons, sm->daemon)); GNUNET_SCHEDULER_add_now (&stat_run, sm); } static void do_report (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { static int download_counter; const char *type = cls; struct GNUNET_TIME_Relative del; char *fancy; struct StatMaster *sm; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) { del = GNUNET_TIME_absolute_get_duration (start_time); if (del.rel_value == 0) del.rel_value = 1; fancy = GNUNET_STRINGS_byte_size_fancy (((unsigned long long) FILESIZE) * 1000LL / del.rel_value); FPRINTF (stderr, "Download speed of type `%s' was %s/s\n", type, fancy); GNUNET_free (fancy); if (NUM_DAEMONS != ++download_counter) return; /* more downloads to come */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished all downloads, shutting down\n", (unsigned long long) FILESIZE); sm = GNUNET_malloc (sizeof (struct StatMaster)); sm->stat = GNUNET_STATISTICS_create ("", GNUNET_FS_TEST_get_configuration (daemons, sm->daemon)); GNUNET_SCHEDULER_add_now (&stat_run, sm); } else { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout during download for type `%s', shutting down with error\n", type); ok = 1; GNUNET_SCHEDULER_add_now (&do_stop, NULL); } } static void do_downloads (void *cls, const struct GNUNET_FS_Uri *u2) { int anonymity; unsigned int i; if (NULL == u2) { GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout during upload attempt, shutting down with error\n"); ok = 1; return; } uri2 = GNUNET_FS_uri_dup (u2); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Downloading %llu bytes\n", (unsigned long long) FILESIZE); start_time = GNUNET_TIME_absolute_get (); if (NULL != strstr (progname, "dht")) anonymity = 0; else anonymity = 1; /* (semi) leach-download(s); not true leaches since * these peers do participate in sharing, they just * don't have to offer anything *initially*. */ for (i = 0; i < NUM_DAEMONS - 2; i++) GNUNET_FS_TEST_download (daemons[i], TIMEOUT, anonymity, 0 == (i % 2) ? SEED1 : SEED2, 0 == (i % 2) ? uri1 : uri2, VERBOSE, &do_report, "leach"); /* mutual downloads of (primary) sharing peers */ GNUNET_FS_TEST_download (daemons[NUM_DAEMONS - 2], TIMEOUT, anonymity, SEED1, uri1, VERBOSE, &do_report, "seeder 2"); GNUNET_FS_TEST_download (daemons[NUM_DAEMONS - 1], TIMEOUT, anonymity, SEED2, uri2, VERBOSE, &do_report, "seeder 1"); } static void do_publish2 (void *cls, const struct GNUNET_FS_Uri *u1) { int do_index; int anonymity; if (NULL == u1) { GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout during upload attempt, shutting down with error\n"); ok = 1; return; } uri1 = GNUNET_FS_uri_dup (u1); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing %llu bytes\n", (unsigned long long) FILESIZE); if (NULL != strstr (progname, "index")) do_index = GNUNET_YES; else do_index = GNUNET_NO; if (NULL != strstr (progname, "dht")) anonymity = 0; else anonymity = 1; GNUNET_FS_TEST_publish (daemons[NUM_DAEMONS - 2], TIMEOUT, anonymity, do_index, FILESIZE, SEED2, VERBOSE, &do_downloads, NULL); } static void do_publish1 (void *cls, const char *emsg) { int do_index; int anonymity; if (NULL != emsg) { GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error trying to connect: %s\n", emsg); ok = 1; return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing %llu bytes\n", (unsigned long long) FILESIZE); if (NULL != strstr (progname, "index")) do_index = GNUNET_YES; else do_index = GNUNET_NO; if (NULL != strstr (progname, "dht")) anonymity = 0; else anonymity = 1; GNUNET_FS_TEST_publish (daemons[NUM_DAEMONS - 1], TIMEOUT, anonymity, do_index, FILESIZE, SEED1, VERBOSE, &do_publish2, NULL); } static void do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TESTING_PeerGroup *pg; GNUNET_assert (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemons started, will now try to connect them\n"); pg = GNUNET_FS_TEST_get_group (daemons); GNUNET_TESTING_create_topology (pg, GNUNET_TESTING_TOPOLOGY_CLIQUE, GNUNET_TESTING_TOPOLOGY_NONE, NULL); GNUNET_TESTING_connect_topology (pg, GNUNET_TESTING_TOPOLOGY_CLIQUE, GNUNET_TESTING_TOPOLOGY_OPTION_NONE, 0.0, TIMEOUT, NUM_DAEMONS, &do_publish1, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { GNUNET_FS_TEST_daemons_start ("fs_test_lib_data.conf", TIMEOUT, NUM_DAEMONS, daemons, &do_connect, NULL); } int main (int argc, char *argv[]) { char *const argvx[] = { "perf-gnunet-service-fs-p2p", "-c", "fs_test_lib_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; progname = argv[0]; GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/"); GNUNET_log_setup ("perf_gnunet_service_fs_p2p_trust", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "perf-gnunet-service-fs-p2p-trust", "nohelp", options, &run, NULL); GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/"); return ok; } /* end of perf_gnunet_service_fs_p2p_trust.c */ gnunet-0.9.3/src/fs/fs_list_indexed.c0000644000175000017500000001236611760502551014464 00000000000000/* This file is part of GNUnet. (C) 2003, 2004, 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs_list_indexed.c * @author Christian Grothoff * @brief provide a list of all indexed files */ #include "platform.h" #include "gnunet_constants.h" #include "gnunet_fs_service.h" #include "gnunet_protocols.h" #include "fs_api.h" /** * Context for "GNUNET_FS_get_indexed_files". */ struct GNUNET_FS_GetIndexedContext { /** * Handle to global FS context. */ struct GNUNET_FS_Handle *h; /** * Connection to the FS service. */ struct GNUNET_CLIENT_Connection *client; /** * Function to call for each indexed file. */ GNUNET_FS_IndexedFileProcessor iterator; /** * Closure for iterator. */ void *iterator_cls; /** * Continuation to trigger at the end. */ GNUNET_SCHEDULER_Task cont; /** * Closure for cont. */ void *cont_cls; }; /** * Function called on each response from the FS * service with information about indexed files. * * @param cls closure (of type "struct GNUNET_FS_GetIndexedContext*") * @param msg message with indexing information */ static void handle_index_info (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_FS_GetIndexedContext *gic = cls; const struct IndexInfoMessage *iim; uint16_t msize; const char *filename; if (NULL == msg) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Failed to receive response for `%s' request from `%s' service.\n"), "GET_INDEXED", "fs"); (void) gic->iterator (gic->iterator_cls, NULL, NULL); GNUNET_FS_get_indexed_files_cancel (gic); return; } if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_END) { /* normal end-of-list */ (void) gic->iterator (gic->iterator_cls, NULL, NULL); GNUNET_FS_get_indexed_files_cancel (gic); return; } msize = ntohs (msg->size); iim = (const struct IndexInfoMessage *) msg; filename = (const char *) &iim[1]; if ((ntohs (msg->type) != GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_ENTRY) || (msize <= sizeof (struct IndexInfoMessage)) || (filename[msize - sizeof (struct IndexInfoMessage) - 1] != '\0')) { /* bogus reply */ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Failed to receive valid response for `%s' request from `%s' service.\n"), "GET_INDEXED", "fs"); (void) gic->iterator (gic->iterator_cls, NULL, NULL); GNUNET_FS_get_indexed_files_cancel (gic); return; } if (GNUNET_OK != gic->iterator (gic->iterator_cls, filename, &iim->file_id)) { GNUNET_FS_get_indexed_files_cancel (gic); return; } /* get more */ GNUNET_CLIENT_receive (gic->client, &handle_index_info, gic, GNUNET_CONSTANTS_SERVICE_TIMEOUT); } /** * Iterate over all indexed files. * * @param h handle to the file sharing subsystem * @param iterator function to call on each indexed file * @param iterator_cls closure for iterator * @return NULL on error ('iter' is not called) */ struct GNUNET_FS_GetIndexedContext * GNUNET_FS_get_indexed_files (struct GNUNET_FS_Handle *h, GNUNET_FS_IndexedFileProcessor iterator, void *iterator_cls) { struct GNUNET_CLIENT_Connection *client; struct GNUNET_FS_GetIndexedContext *gic; struct GNUNET_MessageHeader msg; client = GNUNET_CLIENT_connect ("fs", h->cfg); if (NULL == client) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to not connect to `%s' service.\n"), "fs"); return NULL; } gic = GNUNET_malloc (sizeof (struct GNUNET_FS_GetIndexedContext)); gic->h = h; gic->client = client; gic->iterator = iterator; gic->iterator_cls = iterator_cls; msg.size = htons (sizeof (struct GNUNET_MessageHeader)); msg.type = htons (GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET); GNUNET_assert (GNUNET_OK == GNUNET_CLIENT_transmit_and_get_response (client, &msg, GNUNET_CONSTANTS_SERVICE_TIMEOUT, GNUNET_YES, &handle_index_info, gic)); return gic; } /** * Cancel iteration over all indexed files. * * @param gic operation to cancel */ void GNUNET_FS_get_indexed_files_cancel (struct GNUNET_FS_GetIndexedContext *gic) { GNUNET_CLIENT_disconnect (gic->client); GNUNET_free (gic); } /* end of fs_list_indexed.c */ gnunet-0.9.3/src/fs/test_fs_publish_data.conf0000644000175000017500000000026011615567501016205 00000000000000@INLINE@ test_fs_defaults.conf [PATHS] SERVICEHOME = /tmp/gnunet-test-fs-publish/ DEFAULTCONFIG = test_fs_publish_data.conf [transport] PLUGINS = [fs] ACTIVEMIGRATION = NO gnunet-0.9.3/src/fs/fs_unindex.c0000644000175000017500000005775311760502551013474 00000000000000/* This file is part of GNUnet. (C) 2003, 2004, 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs_unindex.c * @author Krista Grothoff * @author Christian Grothoff * @brief Unindex file. */ #include "platform.h" #include "gnunet_constants.h" #include "gnunet_fs_service.h" #include "gnunet_protocols.h" #include "fs_api.h" #include "fs_tree.h" #include "block_fs.h" /** * Function called by the tree encoder to obtain * a block of plaintext data (for the lowest level * of the tree). * * @param cls our publishing context * @param offset identifies which block to get * @param max (maximum) number of bytes to get; returning * fewer will also cause errors * @param buf where to copy the plaintext buffer * @param emsg location to store an error message (on error) * @return number of bytes copied to buf, 0 on error */ static size_t unindex_reader (void *cls, uint64_t offset, size_t max, void *buf, char **emsg) { struct GNUNET_FS_UnindexContext *uc = cls; size_t pt_size; pt_size = GNUNET_MIN (max, uc->file_size - offset); if (offset != GNUNET_DISK_file_seek (uc->fh, offset, GNUNET_DISK_SEEK_SET)) { *emsg = GNUNET_strdup (_("Failed to find given position in file")); return 0; } if (pt_size != GNUNET_DISK_file_read (uc->fh, buf, pt_size)) { *emsg = GNUNET_strdup (_("Failed to read file")); return 0; } return pt_size; } /** * Fill in all of the generic fields for * an unindex event and call the callback. * * @param pi structure to fill in * @param uc overall unindex context * @param offset where we are in the file (for progress) */ void GNUNET_FS_unindex_make_status_ (struct GNUNET_FS_ProgressInfo *pi, struct GNUNET_FS_UnindexContext *uc, uint64_t offset) { pi->value.unindex.uc = uc; pi->value.unindex.cctx = uc->client_info; pi->value.unindex.filename = uc->filename; pi->value.unindex.size = uc->file_size; pi->value.unindex.eta = GNUNET_TIME_calculate_eta (uc->start_time, offset, uc->file_size); pi->value.unindex.duration = GNUNET_TIME_absolute_get_duration (uc->start_time); pi->value.unindex.completed = offset; uc->client_info = uc->h->upcb (uc->h->upcb_cls, pi); } /** * Function called with information about our * progress in computing the tree encoding. * * @param cls closure * @param offset where are we in the file * @param pt_block plaintext of the currently processed block * @param pt_size size of pt_block * @param depth depth of the block in the tree, 0 for DBLOCK */ static void unindex_progress (void *cls, uint64_t offset, const void *pt_block, size_t pt_size, unsigned int depth) { struct GNUNET_FS_UnindexContext *uc = cls; struct GNUNET_FS_ProgressInfo pi; pi.status = GNUNET_FS_STATUS_UNINDEX_PROGRESS; pi.value.unindex.specifics.progress.data = pt_block; pi.value.unindex.specifics.progress.offset = offset; pi.value.unindex.specifics.progress.data_len = pt_size; pi.value.unindex.specifics.progress.depth = depth; GNUNET_FS_unindex_make_status_ (&pi, uc, offset); } /** * We've encountered an error during * unindexing. Signal the client. * * @param uc context for the failed unindexing operation */ static void signal_unindex_error (struct GNUNET_FS_UnindexContext *uc) { struct GNUNET_FS_ProgressInfo pi; pi.status = GNUNET_FS_STATUS_UNINDEX_ERROR; pi.value.unindex.eta = GNUNET_TIME_UNIT_FOREVER_REL; pi.value.unindex.specifics.error.message = uc->emsg; GNUNET_FS_unindex_make_status_ (&pi, uc, 0); } /** * Continuation called to notify client about result of the * datastore removal operation. * * @param cls closure * @param success GNUNET_SYSERR on failure * @param min_expiration minimum expiration time required for content to be stored * @param msg NULL on success, otherwise an error message */ static void process_cont (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) { struct GNUNET_FS_UnindexContext *uc = cls; if (success == GNUNET_SYSERR) { uc->emsg = GNUNET_strdup (msg); signal_unindex_error (uc); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Datastore REMOVE operation succeeded\n"); GNUNET_FS_tree_encoder_next (uc->tc); } /** * Function called asking for the current (encoded) * block to be processed. After processing the * client should either call "GNUNET_FS_tree_encode_next" * or (on error) "GNUNET_FS_tree_encode_finish". * * @param cls closure * @param chk content hash key for the block (key for lookup in the datastore) * @param offset offset of the block * @param depth depth of the block, 0 for DBLOCK * @param type type of the block (IBLOCK or DBLOCK) * @param block the (encrypted) block * @param block_size size of block (in bytes) */ static void unindex_process (void *cls, const struct ContentHashKey *chk, uint64_t offset, unsigned int depth, enum GNUNET_BLOCK_Type type, const void *block, uint16_t block_size) { struct GNUNET_FS_UnindexContext *uc = cls; uint32_t size; const void *data; struct OnDemandBlock odb; if (type != GNUNET_BLOCK_TYPE_FS_DBLOCK) { size = block_size; data = block; } else /* on-demand encoded DBLOCK */ { size = sizeof (struct OnDemandBlock); odb.offset = GNUNET_htonll (offset); odb.file_id = uc->file_id; data = &odb; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending REMOVE request to DATASTORE service\n"); GNUNET_DATASTORE_remove (uc->dsh, &chk->query, size, data, -2, 1, GNUNET_CONSTANTS_SERVICE_TIMEOUT, &process_cont, uc); uc->chk = *chk; } /** * Function called with the response from the * FS service to our unindexing request. * * @param cls closure, unindex context * @param msg NULL on timeout, otherwise the response */ static void process_fs_response (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_FS_UnindexContext *uc = cls; struct GNUNET_FS_ProgressInfo pi; if (uc->client != NULL) { GNUNET_CLIENT_disconnect (uc->client); uc->client = NULL; } if (uc->state != UNINDEX_STATE_FS_NOTIFY) { uc->state = UNINDEX_STATE_ERROR; uc->emsg = GNUNET_strdup (_("Unexpected time for a response from `fs' service.")); GNUNET_FS_unindex_sync_ (uc); signal_unindex_error (uc); return; } if (NULL == msg) { uc->state = UNINDEX_STATE_ERROR; uc->emsg = GNUNET_strdup (_("Timeout waiting for `fs' service.")); GNUNET_FS_unindex_sync_ (uc); signal_unindex_error (uc); return; } if (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK) { uc->state = UNINDEX_STATE_ERROR; uc->emsg = GNUNET_strdup (_("Invalid response from `fs' service.")); GNUNET_FS_unindex_sync_ (uc); signal_unindex_error (uc); return; } uc->state = UNINDEX_STATE_COMPLETE; pi.status = GNUNET_FS_STATUS_UNINDEX_COMPLETED; pi.value.unindex.eta = GNUNET_TIME_UNIT_ZERO; GNUNET_FS_unindex_sync_ (uc); GNUNET_FS_unindex_make_status_ (&pi, uc, uc->file_size); } /** * Function called when we are done with removing KBlocks. * Disconnect from datastore and notify FS service about * the unindex event. * * @param uc our unindexing context */ static void unindex_finish (struct GNUNET_FS_UnindexContext *uc) { char *emsg; struct GNUNET_FS_Uri *uri; struct UnindexMessage req; /* generate final progress message */ unindex_progress (uc, uc->file_size, NULL, 0, 0); GNUNET_FS_tree_encoder_finish (uc->tc, &uri, &emsg); uc->tc = NULL; if (uri != NULL) GNUNET_FS_uri_destroy (uri); GNUNET_DISK_file_close (uc->fh); uc->fh = NULL; GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO); uc->dsh = NULL; uc->state = UNINDEX_STATE_FS_NOTIFY; GNUNET_FS_unindex_sync_ (uc); uc->client = GNUNET_CLIENT_connect ("fs", uc->h->cfg); if (uc->client == NULL) { uc->state = UNINDEX_STATE_ERROR; uc->emsg = GNUNET_strdup (_("Failed to connect to FS service for unindexing.")); GNUNET_FS_unindex_sync_ (uc); signal_unindex_error (uc); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending UNINDEX message to FS service\n"); req.header.size = htons (sizeof (struct UnindexMessage)); req.header.type = htons (GNUNET_MESSAGE_TYPE_FS_UNINDEX); req.reserved = 0; req.file_id = uc->file_id; GNUNET_break (GNUNET_OK == GNUNET_CLIENT_transmit_and_get_response (uc->client, &req.header, GNUNET_CONSTANTS_SERVICE_TIMEOUT, GNUNET_YES, &process_fs_response, uc)); } /** * Function called by the directory scanner as we extract keywords * that we will need to remove KBlocks. * * @param cls the 'struct GNUNET_FS_UnindexContext *' * @param filename which file we are making progress on * @param is_directory GNUNET_YES if this is a directory, * GNUNET_NO if this is a file * GNUNET_SYSERR if it is neither (or unknown) * @param reason kind of progress we are making */ static void unindex_directory_scan_cb (void *cls, const char *filename, int is_directory, enum GNUNET_FS_DirScannerProgressUpdateReason reason) { struct GNUNET_FS_UnindexContext *uc = cls; static struct GNUNET_FS_ShareTreeItem * directory_scan_result; switch (reason) { case GNUNET_FS_DIRSCANNER_FINISHED: directory_scan_result = GNUNET_FS_directory_scan_get_result (uc->dscan); uc->dscan = NULL; if (NULL != directory_scan_result->ksk_uri) { uc->ksk_uri = GNUNET_FS_uri_dup (directory_scan_result->ksk_uri); uc->state = UNINDEX_STATE_DS_REMOVE_KBLOCKS; uc->emsg = GNUNET_strdup (_("Failed to get KSKs from directory scan.")); GNUNET_FS_unindex_sync_ (uc); GNUNET_FS_unindex_do_remove_kblocks_ (uc); } else { unindex_finish (uc); } GNUNET_FS_share_tree_free (directory_scan_result); break; case GNUNET_FS_DIRSCANNER_INTERNAL_ERROR: GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Internal error scanning `%s'.\n"), uc->filename); break; default: break; } } /** * If necessary, connect to the datastore and remove the KBlocks. * * @param uc context for the unindex operation. */ void GNUNET_FS_unindex_do_extract_keywords_ (struct GNUNET_FS_UnindexContext *uc) { char *ex; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (uc->h->cfg, "FS", "EXTRACTORS", &ex)) ex = NULL; uc->dscan = GNUNET_FS_directory_scan_start (uc->filename, GNUNET_NO, ex, &unindex_directory_scan_cb, uc); GNUNET_free_non_null (ex); } /** * Continuation called to notify client about result of the remove * operation for the KBlock. * * @param cls the 'struct GNUNET_FS_UnindexContext *' * @param success GNUNET_SYSERR on failure (including timeout/queue drop) * GNUNET_NO if content was already there * GNUNET_YES (or other positive value) on success * @param min_expiration minimum expiration time required for 0-priority content to be stored * by the datacache at this time, zero for unknown, forever if we have no * space for 0-priority content * @param msg NULL on success, otherwise an error message */ static void continue_after_remove (void *cls, int32_t success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) { struct GNUNET_FS_UnindexContext *uc = cls; uc->dqe = NULL; if (success != GNUNET_YES) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to remove KBlock: %s\n"), msg); uc->ksk_offset++; GNUNET_FS_unindex_do_remove_kblocks_ (uc); } /** * Function called from datastore with result from us looking for * a KBlock. There are four cases: * 1) no result, means we move on to the next keyword * 2) UID is the same as the first UID, means we move on to next keyword * 3) KBlock for a different CHK, means we keep looking for more * 4) KBlock is for our CHK, means we remove the block and then move * on to the next keyword * * @param cls the 'struct GNUNET_FS_UnindexContext *' * @param key key for the content * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param expiration expiration time for the content * @param uid unique identifier for the datum; * maybe 0 if no unique identifier is available */ static void process_kblock_for_unindex (void *cls, const GNUNET_HashCode * key, size_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct GNUNET_FS_UnindexContext *uc = cls; const struct KBlock *kb; struct GNUNET_FS_Uri *chk_uri; uc->dqe = NULL; if (NULL == data) { /* no result */ uc->ksk_offset++; GNUNET_FS_unindex_do_remove_kblocks_ (uc); return; } if (0 == uc->first_uid) { /* remember UID of first result to detect cycles */ uc->first_uid = uid; } else if (uid == uc->first_uid) { /* no more additional results */ uc->ksk_offset++; GNUNET_FS_unindex_do_remove_kblocks_ (uc); return; } GNUNET_assert (GNUNET_BLOCK_TYPE_FS_KBLOCK == type); if (size < sizeof (struct KBlock)) { GNUNET_break (0); goto get_next; } kb = data; { char pt[size - sizeof (struct KBlock)]; struct GNUNET_CRYPTO_AesSessionKey skey; struct GNUNET_CRYPTO_AesInitializationVector iv; GNUNET_CRYPTO_hash_to_aes_key (&uc->key, &skey, &iv); if (-1 == GNUNET_CRYPTO_aes_decrypt (&kb[1], size - sizeof (struct KBlock), &skey, &iv, pt)) { GNUNET_break (0); goto get_next; } if (NULL == memchr (pt, 0, sizeof (pt))) { GNUNET_break (0); goto get_next; } chk_uri = GNUNET_FS_uri_parse (pt, NULL); if (NULL == chk_uri) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to parse URI `%s' from KBlock!\n"), pt); GNUNET_break (0); goto get_next; } } if (0 != memcmp (&uc->chk, &chk_uri->data.chk.chk, sizeof (struct ContentHashKey))) { /* different CHK, ignore */ GNUNET_FS_uri_destroy (chk_uri); goto get_next; } GNUNET_FS_uri_destroy (chk_uri); /* matches! */ uc->dqe = GNUNET_DATASTORE_remove (uc->dsh, key, size, data, 0 /* priority */, 1 /* queue size */, GNUNET_TIME_UNIT_FOREVER_REL, &continue_after_remove, uc); return; get_next: uc->dqe = GNUNET_DATASTORE_get_key (uc->dsh, uc->roff++, &uc->query, GNUNET_BLOCK_TYPE_FS_KBLOCK, 0 /* priority */, 1 /* queue size */, GNUNET_TIME_UNIT_FOREVER_REL, &process_kblock_for_unindex, uc); } /** * If necessary, connect to the datastore and remove the KBlocks. * * @param uc context for the unindex operation. */ void GNUNET_FS_unindex_do_remove_kblocks_ (struct GNUNET_FS_UnindexContext *uc) { const char *keyword; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub; struct GNUNET_CRYPTO_RsaPrivateKey *pk; if (NULL == uc->dsh) uc->dsh = GNUNET_DATASTORE_connect (uc->h->cfg); if (NULL == uc->dsh) { uc->state = UNINDEX_STATE_ERROR; uc->emsg = GNUNET_strdup (_("Failed to connect to `datastore' service.")); GNUNET_FS_unindex_sync_ (uc); signal_unindex_error (uc); return; } if ( (NULL == uc->ksk_uri) || (uc->ksk_offset >= uc->ksk_uri->data.ksk.keywordCount) ) { unindex_finish (uc); return; } /* FIXME: code duplication with fs_search.c here... */ keyword = &uc->ksk_uri->data.ksk.keywords[uc->ksk_offset][1]; GNUNET_CRYPTO_hash (keyword, strlen (keyword), &uc->key); pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&uc->key); GNUNET_assert (pk != NULL); GNUNET_CRYPTO_rsa_key_get_public (pk, &pub); GNUNET_CRYPTO_rsa_key_free (pk); GNUNET_CRYPTO_hash (&pub, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &uc->query); uc->first_uid = 0; uc->dqe = GNUNET_DATASTORE_get_key (uc->dsh, uc->roff++, &uc->query, GNUNET_BLOCK_TYPE_FS_KBLOCK, 0 /* priority */, 1 /* queue size */, GNUNET_TIME_UNIT_FOREVER_REL, &process_kblock_for_unindex, uc); } /** * Function called when the tree encoder has * processed all blocks. Clean up. * * @param cls our unindexing context * @param tc not used */ static void unindex_extract_keywords (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FS_UnindexContext *uc = cls; uc->state = UNINDEX_STATE_EXTRACT_KEYWORDS; GNUNET_FS_unindex_sync_ (uc); GNUNET_FS_unindex_do_extract_keywords_ (uc); } /** * Connect to the datastore and remove the blocks. * * @param uc context for the unindex operation. */ void GNUNET_FS_unindex_do_remove_ (struct GNUNET_FS_UnindexContext *uc) { if (NULL == uc->dsh) uc->dsh = GNUNET_DATASTORE_connect (uc->h->cfg); if (NULL == uc->dsh) { uc->state = UNINDEX_STATE_ERROR; uc->emsg = GNUNET_strdup (_("Failed to connect to `datastore' service.")); GNUNET_FS_unindex_sync_ (uc); signal_unindex_error (uc); return; } uc->fh = GNUNET_DISK_file_open (uc->filename, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); if (NULL == uc->fh) { GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO); uc->dsh = NULL; uc->state = UNINDEX_STATE_ERROR; uc->emsg = GNUNET_strdup (_("Failed to open file for unindexing.")); GNUNET_FS_unindex_sync_ (uc); signal_unindex_error (uc); return; } uc->tc = GNUNET_FS_tree_encoder_create (uc->h, uc->file_size, uc, &unindex_reader, &unindex_process, &unindex_progress, &unindex_extract_keywords); GNUNET_FS_tree_encoder_next (uc->tc); } /** * Function called once the hash of the file * that is being unindexed has been computed. * * @param cls closure, unindex context * @param file_id computed hash, NULL on error */ void GNUNET_FS_unindex_process_hash_ (void *cls, const GNUNET_HashCode * file_id) { struct GNUNET_FS_UnindexContext *uc = cls; uc->fhc = NULL; if (uc->state != UNINDEX_STATE_HASHING) { GNUNET_FS_unindex_stop (uc); return; } if (file_id == NULL) { uc->state = UNINDEX_STATE_ERROR; uc->emsg = GNUNET_strdup (_("Failed to compute hash of file.")); GNUNET_FS_unindex_sync_ (uc); signal_unindex_error (uc); return; } uc->file_id = *file_id; uc->state = UNINDEX_STATE_DS_REMOVE; GNUNET_FS_unindex_sync_ (uc); GNUNET_FS_unindex_do_remove_ (uc); } /** * Create SUSPEND event for the given unindex operation * and then clean up our state (without stop signal). * * @param cls the 'struct GNUNET_FS_UnindexContext' to signal for */ void GNUNET_FS_unindex_signal_suspend_ (void *cls) { struct GNUNET_FS_UnindexContext *uc = cls; struct GNUNET_FS_ProgressInfo pi; /* FIXME: lots of duplication with unindex_stop here! */ if (uc->dscan != NULL) { GNUNET_FS_directory_scan_abort (uc->dscan); uc->dscan = NULL; } if (NULL != uc->dqe) { GNUNET_DATASTORE_cancel (uc->dqe); uc->dqe = NULL; } if (uc->fhc != NULL) { GNUNET_CRYPTO_hash_file_cancel (uc->fhc); uc->fhc = NULL; } if (NULL != uc->ksk_uri) { GNUNET_FS_uri_destroy (uc->ksk_uri); uc->ksk_uri = NULL; } if (uc->client != NULL) { GNUNET_CLIENT_disconnect (uc->client); uc->client = NULL; } if (NULL != uc->dsh) { GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO); uc->dsh = NULL; } if (NULL != uc->tc) { GNUNET_FS_tree_encoder_finish (uc->tc, NULL, NULL); uc->tc = NULL; } if (uc->fh != NULL) { GNUNET_DISK_file_close (uc->fh); uc->fh = NULL; } GNUNET_FS_end_top (uc->h, uc->top); pi.status = GNUNET_FS_STATUS_UNINDEX_SUSPEND; GNUNET_FS_unindex_make_status_ (&pi, uc, (uc->state == UNINDEX_STATE_COMPLETE) ? uc->file_size : 0); GNUNET_break (NULL == uc->client_info); GNUNET_free (uc->filename); GNUNET_free_non_null (uc->serialization); GNUNET_free_non_null (uc->emsg); GNUNET_free (uc); } /** * Unindex a file. * * @param h handle to the file sharing subsystem * @param filename file to unindex * @param cctx initial value for the client context * @return NULL on error, otherwise handle */ struct GNUNET_FS_UnindexContext * GNUNET_FS_unindex_start (struct GNUNET_FS_Handle *h, const char *filename, void *cctx) { struct GNUNET_FS_UnindexContext *ret; struct GNUNET_FS_ProgressInfo pi; uint64_t size; if (GNUNET_OK != GNUNET_DISK_file_size (filename, &size, GNUNET_YES, GNUNET_YES)) return NULL; ret = GNUNET_malloc (sizeof (struct GNUNET_FS_UnindexContext)); ret->h = h; ret->filename = GNUNET_strdup (filename); ret->start_time = GNUNET_TIME_absolute_get (); ret->file_size = size; ret->client_info = cctx; GNUNET_FS_unindex_sync_ (ret); pi.status = GNUNET_FS_STATUS_UNINDEX_START; pi.value.unindex.eta = GNUNET_TIME_UNIT_FOREVER_REL; GNUNET_FS_unindex_make_status_ (&pi, ret, 0); ret->fhc = GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE, filename, HASHING_BLOCKSIZE, &GNUNET_FS_unindex_process_hash_, ret); ret->top = GNUNET_FS_make_top (h, &GNUNET_FS_unindex_signal_suspend_, ret); return ret; } /** * Clean up after completion of an unindex operation. * * @param uc handle */ void GNUNET_FS_unindex_stop (struct GNUNET_FS_UnindexContext *uc) { struct GNUNET_FS_ProgressInfo pi; if (uc->dscan != NULL) { GNUNET_FS_directory_scan_abort (uc->dscan); uc->dscan = NULL; } if (NULL != uc->dqe) { GNUNET_DATASTORE_cancel (uc->dqe); uc->dqe = NULL; } if (uc->fhc != NULL) { GNUNET_CRYPTO_hash_file_cancel (uc->fhc); uc->fhc = NULL; } if (uc->client != NULL) { GNUNET_CLIENT_disconnect (uc->client); uc->client = NULL; } if (NULL != uc->dsh) { GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO); uc->dsh = NULL; } if (NULL != uc->ksk_uri) { GNUNET_FS_uri_destroy (uc->ksk_uri); uc->ksk_uri = NULL; } if (NULL != uc->tc) { GNUNET_FS_tree_encoder_finish (uc->tc, NULL, NULL); uc->tc = NULL; } if (uc->fh != NULL) { GNUNET_DISK_file_close (uc->fh); uc->fh = NULL; } GNUNET_FS_end_top (uc->h, uc->top); if (uc->serialization != NULL) { GNUNET_FS_remove_sync_file_ (uc->h, GNUNET_FS_SYNC_PATH_MASTER_UNINDEX, uc->serialization); GNUNET_free (uc->serialization); uc->serialization = NULL; } pi.status = GNUNET_FS_STATUS_UNINDEX_STOPPED; pi.value.unindex.eta = GNUNET_TIME_UNIT_ZERO; GNUNET_FS_unindex_make_status_ (&pi, uc, (uc->state == UNINDEX_STATE_COMPLETE) ? uc->file_size : 0); GNUNET_break (NULL == uc->client_info); GNUNET_free_non_null (uc->emsg); GNUNET_free (uc->filename); GNUNET_free (uc); } /* end of fs_unindex.c */ gnunet-0.9.3/src/fs/test_fs_search_persistence.c0000644000175000017500000002412111760502551016711 00000000000000/* This file is part of GNUnet. (C) 2004, 2005, 2006, 2008, 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/test_fs_search_persistence.c * @brief simple testcase for persistence of search operation * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_arm_service.h" #include "gnunet_fs_service.h" #define VERBOSE GNUNET_NO #define START_ARM GNUNET_YES /** * File-size we use for testing. */ #define FILESIZE 1024 /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) /** * How long should our test-content live? */ #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_PeerIdentity id; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static struct PeerContext p1; static struct GNUNET_TIME_Absolute start; static struct GNUNET_FS_Handle *fs; static struct GNUNET_FS_SearchContext *search; static struct GNUNET_FS_PublishContext *publish; static const struct GNUNET_CONFIGURATION_Handle *cfg; static void abort_publish_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_FS_publish_stop (publish); publish = NULL; } static void abort_search_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (search != NULL) GNUNET_FS_search_stop (search); search = NULL; } static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event); static void restart_fs_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_FS_stop (fs); fs = GNUNET_FS_start (cfg, "test-fs-search-persistence", &progress_cb, NULL, GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); } /** * Consider scheduling the restart-task. * Only runs the restart task once per event * category. * * @param ev type of the event to consider */ static void consider_restart (int ev) { static int prev[32]; static int off; int i; for (i = 0; i < off; i++) if (prev[i] == ev) return; prev[off++] = ev; GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_URGENT, &restart_fs_task, NULL); } static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) { const char *keywords[] = { "down_foo" }; struct GNUNET_FS_Uri *kuri; switch (event->status) { case GNUNET_FS_STATUS_PUBLISH_PROGRESS: #if VERBOSE printf ("Publish is progressing (%llu/%llu at level %u off %llu)...\n", (unsigned long long) event->value.publish.completed, (unsigned long long) event->value.publish.size, event->value.publish.specifics.progress.depth, (unsigned long long) event->value.publish.specifics. progress.offset); #endif break; case GNUNET_FS_STATUS_PUBLISH_COMPLETED: kuri = GNUNET_FS_uri_ksk_create_from_args (1, keywords); start = GNUNET_TIME_absolute_get (); GNUNET_FS_search_start (fs, kuri, 1, GNUNET_FS_SEARCH_OPTION_NONE, "search"); GNUNET_FS_uri_destroy (kuri); GNUNET_assert (search != NULL); break; case GNUNET_FS_STATUS_PUBLISH_SUSPEND: if (event->value.publish.pc == publish) publish = NULL; break; case GNUNET_FS_STATUS_PUBLISH_RESUME: if (NULL == publish) publish = event->value.publish.pc; break; case GNUNET_FS_STATUS_SEARCH_RESULT: /* FIXME: consider_restart (event->status); cannot be tested with * search result since we exit here after the first one... */ #if VERBOSE printf ("Search complete.\n"); #endif GNUNET_SCHEDULER_add_continuation (&abort_search_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_PUBLISH_ERROR: FPRINTF (stderr, "Error publishing file: %s\n", event->value.publish.specifics.error.message); GNUNET_break (0); GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_SEARCH_ERROR: FPRINTF (stderr, "Error searching file: %s\n", event->value.search.specifics.error.message); GNUNET_SCHEDULER_add_continuation (&abort_search_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_SEARCH_SUSPEND: if (event->value.search.sc == search) search = NULL; break; case GNUNET_FS_STATUS_SEARCH_RESUME: if (NULL == search) { search = event->value.search.sc; return "search"; } break; case GNUNET_FS_STATUS_PUBLISH_START: GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); GNUNET_assert (NULL == event->value.publish.pctx); GNUNET_assert (FILESIZE == event->value.publish.size); GNUNET_assert (0 == event->value.publish.completed); GNUNET_assert (1 == event->value.publish.anonymity); break; case GNUNET_FS_STATUS_PUBLISH_STOPPED: GNUNET_assert (publish == event->value.publish.pc); GNUNET_assert (FILESIZE == event->value.publish.size); GNUNET_assert (1 == event->value.publish.anonymity); GNUNET_FS_stop (fs); fs = NULL; break; case GNUNET_FS_STATUS_SEARCH_START: consider_restart (event->status); GNUNET_assert (search == NULL); search = event->value.search.sc; GNUNET_assert (0 == strcmp ("search", event->value.search.cctx)); GNUNET_assert (1 == event->value.search.anonymity); break; case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED: break; case GNUNET_FS_STATUS_SEARCH_STOPPED: GNUNET_assert (search == event->value.search.sc); GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); search = NULL; break; default: FPRINTF (stderr, "Unexpected event: %d\n", event->status); break; } return NULL; } static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE "-L", "DEBUG", #endif "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); } static void stop_arm (struct PeerContext *p) { #if START_ARM if (NULL != p->arm_proc) { if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; } #endif GNUNET_CONFIGURATION_destroy (p->cfg); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { const char *keywords[] = { "down_foo", "down_bar" }; char *buf; struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_FS_Uri *kuri; struct GNUNET_FS_FileInformation *fi; size_t i; struct GNUNET_FS_BlockOptions bo; cfg = c; setup_peer (&p1, "test_fs_search_data.conf"); fs = GNUNET_FS_start (cfg, "test-fs-search-persistence", &progress_cb, NULL, GNUNET_FS_FLAGS_PERSISTENCE, GNUNET_FS_OPTIONS_END); GNUNET_assert (NULL != fs); buf = GNUNET_malloc (FILESIZE); for (i = 0; i < FILESIZE; i++) buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); meta = GNUNET_CONTAINER_meta_data_create (); kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); bo.content_priority = 42; bo.anonymity_level = 1; bo.replication_level = 0; bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); fi = GNUNET_FS_file_information_create_from_data (fs, "publish-context", FILESIZE, buf, kuri, meta, GNUNET_NO, &bo); GNUNET_FS_uri_destroy (kuri); GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_assert (NULL != fi); start = GNUNET_TIME_absolute_get (); publish = GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, GNUNET_FS_PUBLISH_OPTION_NONE); GNUNET_assert (publish != NULL); } int main (int argc, char *argv[]) { char *const argvx[] = { "test-fs-search-persistence", "-c", "test_fs_search_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-search/"); GNUNET_log_setup ("test_fs_search_persistence", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "test-fs-search-persistence", "nohelp", options, &run, NULL); stop_arm (&p1); GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-search/"); return 0; } /* end of test_fs_search_persistence.c */ gnunet-0.9.3/src/fs/fs_test_lib_data.conf0000644000175000017500000000023711665224123015304 00000000000000@INLINE@ test_fs_defaults.conf [PATHS] SERVICEHOME = /tmp/gnunet-fs-test-lib/ [ats] WAN_QUOTA_IN = 3932160 WAN_QUOTA_OUT = 3932160 [datastore] QUOTA = 2 GB gnunet-0.9.3/src/fs/perf_gnunet_service_fs_p2p.c0000644000175000017500000002254311760502551016624 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/perf_gnunet_service_fs_p2p.c * @brief profile P2P routing using simple publish + download operation * @author Christian Grothoff */ #include "platform.h" #include "fs_test_lib.h" #include "gnunet_testing_lib.h" #define VERBOSE GNUNET_NO /** * File-size we use for testing. */ #define FILESIZE (1024 * 1024 * 10) /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30) #define NUM_DAEMONS 2 #define SEED 42 static struct GNUNET_FS_TestDaemon *daemons[NUM_DAEMONS]; static int ok; static struct GNUNET_TIME_Absolute start_time; static const char *progname; static void do_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons); } /** * Master context for 'stat_run'. */ struct StatMaster { struct GNUNET_STATISTICS_Handle *stat; unsigned int daemon; unsigned int value; }; struct StatValues { const char *subsystem; const char *name; }; /** * Statistics we print out. */ static struct StatValues stats[] = { {"fs", "# artificial delays introduced (ms)"}, {"fs", "# queries forwarded"}, {"fs", "# replies received and matched"}, {"fs", "# results found locally"}, {"fs", "# requests forwarded due to high load"}, {"fs", "# requests done for free (low load)"}, {"fs", "# requests dropped, priority insufficient"}, {"fs", "# requests done for a price (normal load)"}, {"fs", "# requests dropped by datastore (queue length limit)"}, {"fs", "# P2P searches received"}, {"fs", "# P2P searches discarded (queue length bound)"}, {"fs", "# replies received for local clients"}, {"fs", "# queries retransmitted to same target"}, {"core", "# bytes decrypted"}, {"core", "# bytes encrypted"}, {"core", "# discarded CORE_SEND requests"}, {"core", "# discarded CORE_SEND request bytes"}, {"core", "# discarded lower priority CORE_SEND requests"}, {"core", "# discarded lower priority CORE_SEND request bytes"}, {"transport", "# bytes received via TCP"}, {"transport", "# bytes transmitted via TCP"}, {"datacache", "# bytes stored"}, {NULL, NULL} }; /** * Callback function to process statistic values. * * @param cls closure * @param subsystem name of subsystem that created the statistic * @param name the name of the datum * @param value the current value * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration */ static int print_stat (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent) { struct StatMaster *sm = cls; FPRINTF (stderr, "Peer %2u: %12s/%50s = %12llu\n", sm->daemon, subsystem, name, (unsigned long long) value); return GNUNET_OK; } /** * Function that gathers stats from all daemons. */ static void stat_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Function called when GET operation on stats is done. */ static void get_done (void *cls, int success) { struct StatMaster *sm = cls; GNUNET_break (GNUNET_OK == success); sm->value++; GNUNET_SCHEDULER_add_now (&stat_run, sm); } /** * Function that gathers stats from all daemons. */ static void stat_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct StatMaster *sm = cls; if (stats[sm->value].name != NULL) { GNUNET_STATISTICS_get (sm->stat, #if 0 NULL, NULL, #else stats[sm->value].subsystem, stats[sm->value].name, #endif GNUNET_TIME_UNIT_FOREVER_REL, &get_done, &print_stat, sm); return; } GNUNET_STATISTICS_destroy (sm->stat, GNUNET_NO); sm->value = 0; sm->daemon++; if (sm->daemon == NUM_DAEMONS) { GNUNET_free (sm); GNUNET_SCHEDULER_add_now (&do_stop, NULL); return; } sm->stat = GNUNET_STATISTICS_create ("", GNUNET_FS_TEST_get_configuration (daemons, sm->daemon)); GNUNET_SCHEDULER_add_now (&stat_run, sm); } static void do_report (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TIME_Relative del; char *fancy; struct StatMaster *sm; if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) { del = GNUNET_TIME_absolute_get_duration (start_time); if (del.rel_value == 0) del.rel_value = 1; fancy = GNUNET_STRINGS_byte_size_fancy (((unsigned long long) FILESIZE) * 1000LL / del.rel_value); FPRINTF (stdout, "Download speed was %s/s\n", fancy); GNUNET_free (fancy); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished download, shutting down\n", (unsigned long long) FILESIZE); sm = GNUNET_malloc (sizeof (struct StatMaster)); sm->stat = GNUNET_STATISTICS_create ("", GNUNET_FS_TEST_get_configuration (daemons, sm->daemon)); GNUNET_SCHEDULER_add_now (&stat_run, sm); } else { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout during download, shutting down with error\n"); ok = 1; GNUNET_SCHEDULER_add_now (&do_stop, NULL); } } static void do_download (void *cls, const struct GNUNET_FS_Uri *uri) { int anonymity; if (NULL == uri) { GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout during upload attempt, shutting down with error\n"); ok = 1; return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Downloading %llu bytes\n", (unsigned long long) FILESIZE); start_time = GNUNET_TIME_absolute_get (); if (NULL != strstr (progname, "dht")) anonymity = 0; else anonymity = 1; GNUNET_FS_TEST_download (daemons[0], TIMEOUT, anonymity, SEED, uri, VERBOSE, &do_report, NULL); } static void do_publish (void *cls, const char *emsg) { int do_index; int anonymity; if (NULL != emsg) { GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error trying to connect: %s\n", emsg); ok = 1; return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing %llu bytes\n", (unsigned long long) FILESIZE); if (NULL != strstr (progname, "index")) do_index = GNUNET_YES; else do_index = GNUNET_NO; if (NULL != strstr (progname, "dht")) anonymity = 0; else anonymity = 1; GNUNET_FS_TEST_publish (daemons[NUM_DAEMONS - 1], TIMEOUT, anonymity, do_index, FILESIZE, SEED, VERBOSE, &do_download, NULL); } static void do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TESTING_PeerGroup *pg; GNUNET_assert (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemons started, will now try to connect them\n"); pg = GNUNET_FS_TEST_get_group (daemons); GNUNET_break ((NUM_DAEMONS - 1) * 2 == (GNUNET_TESTING_create_topology (pg, GNUNET_TESTING_TOPOLOGY_LINE, GNUNET_TESTING_TOPOLOGY_NONE, NULL))); GNUNET_TESTING_connect_topology (pg, GNUNET_TESTING_TOPOLOGY_LINE, GNUNET_TESTING_TOPOLOGY_OPTION_NONE, 0.0, TIMEOUT, NUM_DAEMONS, &do_publish, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { GNUNET_FS_TEST_daemons_start ("fs_test_lib_data.conf", TIMEOUT, NUM_DAEMONS, daemons, &do_connect, NULL); } int main (int argc, char *argv[]) { char *const argvx[] = { "perf-gnunet-service-fs-p2p", "-c", "fs_test_lib_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; progname = argv[0]; GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/"); GNUNET_log_setup ("perf_gnunet_service_fs_p2p_index", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "perf-gnunet-service-fs-p2p-index", "nohelp", options, &run, NULL); GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/"); return ok; } /* end of perf_gnunet_service_fs_p2p.c */ gnunet-0.9.3/src/fs/gnunet-download.c0000644000175000017500000002162711760502551014426 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-download.c * @brief downloading for files on GNUnet * @author Christian Grothoff * @author Krista Bennett * @author James Blackwell * @author Igor Wronsky */ #include "platform.h" #include "gnunet_fs_service.h" static int ret; static int verbose; static int delete_incomplete; static const struct GNUNET_CONFIGURATION_Handle *cfg; static struct GNUNET_FS_Handle *ctx; static struct GNUNET_FS_DownloadContext *dc; static unsigned int anonymity = 1; static unsigned int parallelism = 16; static unsigned int request_parallelism = 4092; static int do_recursive; static char *filename; static int local_only; static void cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_FS_stop (ctx); ctx = NULL; } static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FS_DownloadContext *d; if (dc != NULL) { d = dc; dc = NULL; GNUNET_FS_download_stop (d, delete_incomplete); } } /** * Called by FS client to give information about the progress of an * operation. * * @param cls closure * @param info details about the event, specifying the event type * and various bits about the event * @return client-context (for the next progress call * for this operation; should be set to NULL for * SUSPEND and STOPPED events). The value returned * will be passed to future callbacks in the respective * field in the GNUNET_FS_ProgressInfo struct. */ static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info) { char *s; char *s2; char *t; switch (info->status) { case GNUNET_FS_STATUS_DOWNLOAD_START: if (verbose > 1) FPRINTF (stderr, _("Starting download `%s'.\n"), info->value.download.filename); break; case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: if (verbose) { s = GNUNET_STRINGS_relative_time_to_string (info->value.download.eta); if (info->value.download.specifics.progress.block_download_duration.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value) s2 = GNUNET_strdup (_("")); else s2 = GNUNET_STRINGS_relative_time_to_string ( info->value.download.specifics.progress.block_download_duration); t = GNUNET_STRINGS_byte_size_fancy (info->value.download.completed * 1000LL / (info->value.download. duration.rel_value + 1)); FPRINTF (stdout, _("Downloading `%s' at %llu/%llu (%s remaining, %s/s). Block took %s to download\n"), info->value.download.filename, (unsigned long long) info->value.download.completed, (unsigned long long) info->value.download.size, s, t, s2); GNUNET_free (s); GNUNET_free (s2); GNUNET_free (t); } break; case GNUNET_FS_STATUS_DOWNLOAD_ERROR: FPRINTF (stderr, _("Error downloading: %s.\n"), info->value.download.specifics.error.message); GNUNET_SCHEDULER_shutdown (); break; case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: s = GNUNET_STRINGS_byte_size_fancy (info->value.download.completed * 1000 / (info->value.download. duration.rel_value + 1)); FPRINTF (stdout, _("Downloading `%s' done (%s/s).\n"), info->value.download.filename, s); GNUNET_free (s); if (info->value.download.dc == dc) GNUNET_SCHEDULER_shutdown (); break; case GNUNET_FS_STATUS_DOWNLOAD_STOPPED: if (info->value.download.dc == dc) GNUNET_SCHEDULER_add_continuation (&cleanup_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: break; default: FPRINTF (stderr, _("Unexpected status: %d\n"), info->status); break; } return NULL; } /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param c configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { struct GNUNET_FS_Uri *uri; char *emsg; enum GNUNET_FS_DownloadOptions options; if (NULL == args[0]) { FPRINTF (stderr, "%s", _("You need to specify a URI argument.\n")); return; } uri = GNUNET_FS_uri_parse (args[0], &emsg); if (NULL == uri) { FPRINTF (stderr, _("Failed to parse URI: %s\n"), emsg); GNUNET_free (emsg); ret = 1; return; } if ((!GNUNET_FS_uri_test_chk (uri)) && (!GNUNET_FS_uri_test_loc (uri))) { FPRINTF (stderr, "%s", _("Only CHK or LOC URIs supported.\n")); ret = 1; GNUNET_FS_uri_destroy (uri); return; } if (NULL == filename) { FPRINTF (stderr, "%s", _("Target filename must be specified.\n")); ret = 1; GNUNET_FS_uri_destroy (uri); return; } cfg = c; ctx = GNUNET_FS_start (cfg, "gnunet-download", &progress_cb, NULL, GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_DOWNLOAD_PARALLELISM, parallelism, GNUNET_FS_OPTIONS_REQUEST_PARALLELISM, request_parallelism, GNUNET_FS_OPTIONS_END); if (NULL == ctx) { FPRINTF (stderr, _("Could not initialize `%s' subsystem.\n"), "FS"); GNUNET_FS_uri_destroy (uri); ret = 1; return; } options = GNUNET_FS_DOWNLOAD_OPTION_NONE; if (do_recursive) options |= GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE; if (local_only) options |= GNUNET_FS_DOWNLOAD_OPTION_LOOPBACK_ONLY; dc = GNUNET_FS_download_start (ctx, uri, NULL, filename, NULL, 0, GNUNET_FS_uri_chk_get_file_size (uri), anonymity, options, NULL, NULL); GNUNET_FS_uri_destroy (uri); if (dc == NULL) { GNUNET_FS_stop (ctx); ctx = NULL; return; } GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); } /** * The main function to download GNUnet. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { {'a', "anonymity", "LEVEL", gettext_noop ("set the desired LEVEL of receiver-anonymity"), 1, &GNUNET_GETOPT_set_uint, &anonymity}, {'D', "delete-incomplete", NULL, gettext_noop ("delete incomplete downloads (when aborted with CTRL-C)"), 0, &GNUNET_GETOPT_set_one, &delete_incomplete}, {'n', "no-network", NULL, gettext_noop ("only search the local peer (no P2P network search)"), 0, &GNUNET_GETOPT_set_uint, &local_only}, {'o', "output", "FILENAME", gettext_noop ("write the file to FILENAME"), 1, &GNUNET_GETOPT_set_string, &filename}, {'p', "parallelism", "DOWNLOADS", gettext_noop ("set the maximum number of parallel downloads that is allowed"), 1, &GNUNET_GETOPT_set_uint, ¶llelism}, {'r', "request-parallelism", "REQUESTS", gettext_noop ("set the maximum number of parallel requests for blocks that is allowed"), 1, &GNUNET_GETOPT_set_uint, &request_parallelism}, {'R', "recursive", NULL, gettext_noop ("download a GNUnet directory recursively"), 0, &GNUNET_GETOPT_set_one, &do_recursive}, {'V', "verbose", NULL, gettext_noop ("be verbose (print progress information)"), 0, &GNUNET_GETOPT_increment_value, &verbose}, GNUNET_GETOPT_OPTION_END }; return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-download [OPTIONS] URI", gettext_noop ("Download files from GNUnet using a GNUnet CHK or LOC URI (gnunet://fs/chk/...)"), options, &run, NULL)) ? ret : 1; } /* end of gnunet-download.c */ gnunet-0.9.3/src/fs/Makefile.in0000644000175000017500000021143011762223643013217 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-directory$(EXEEXT) gnunet-download$(EXEEXT) \ gnunet-publish$(EXEEXT) gnunet-helper-fs-publish$(EXEEXT) \ gnunet-pseudonym$(EXEEXT) gnunet-search$(EXEEXT) \ gnunet-service-fs$(EXEEXT) gnunet-fs$(EXEEXT) \ gnunet-unindex$(EXEEXT) check_PROGRAMS = test_fs_directory$(EXEEXT) test_fs_download$(EXEEXT) \ test_fs_download_indexed$(EXEEXT) \ test_fs_download_persistence$(EXEEXT) \ test_fs_file_information$(EXEEXT) test_fs_getopt$(EXEEXT) \ test_fs_list_indexed$(EXEEXT) test_fs_namespace$(EXEEXT) \ test_fs_namespace_list_updateable$(EXEEXT) \ test_fs_publish$(EXEEXT) test_fs_publish_persistence$(EXEEXT) \ test_fs_search$(EXEEXT) test_fs_search_probes$(EXEEXT) \ test_fs_search_persistence$(EXEEXT) \ test_fs_start_stop$(EXEEXT) test_fs_test_lib$(EXEEXT) \ test_fs_unindex$(EXEEXT) test_fs_unindex_persistence$(EXEEXT) \ test_fs_uri$(EXEEXT) test_gnunet_service_fs_migration$(EXEEXT) \ test_gnunet_service_fs_p2p$(EXEEXT) $(am__EXEEXT_1) @ENABLE_TEST_RUN_TRUE@TESTS = test_fs_directory$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_fs_download$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_fs_download_indexed$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_fs_download_persistence$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_fs_file_information$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_fs_list_indexed$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_fs_namespace$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_fs_namespace_list_updateable$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_fs_publish$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_fs_publish_persistence$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_fs_search$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_fs_search_probes$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_fs_search_persistence$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_fs_start_stop$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_fs_unindex$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_fs_unindex_persistence$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_fs_uri$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_fs_test_lib$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_gnunet_service_fs_migration$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_gnunet_service_fs_p2p$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ perf_gnunet_service_fs_p2p$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ perf_gnunet_service_fs_p2p_index$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ perf_gnunet_service_fs_p2p_trust$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ $(check_SCRIPTS) subdir = src/fs DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/fs.conf.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = fs.conf CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_$(V)) am__v_AR_ = $(am__v_AR_$(AM_DEFAULT_VERBOSITY)) am__v_AR_0 = @echo " AR " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ libgnunetfstest_a_AR = $(AR) $(ARFLAGS) libgnunetfstest_a_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la am_libgnunetfstest_a_OBJECTS = fs_test_lib.$(OBJEXT) libgnunetfstest_a_OBJECTS = $(am_libgnunetfstest_a_OBJECTS) am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \ "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) $(plugin_LTLIBRARIES) am_libgnunet_plugin_block_fs_la_OBJECTS = plugin_block_fs.lo libgnunet_plugin_block_fs_la_OBJECTS = \ $(am_libgnunet_plugin_block_fs_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunet_plugin_block_fs_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunet_plugin_block_fs_la_LDFLAGS) \ $(LDFLAGS) -o $@ am__DEPENDENCIES_1 = libgnunetfs_la_DEPENDENCIES = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am_libgnunetfs_la_OBJECTS = fs_api.lo fs_directory.lo \ fs_dirmetascan.lo fs_download.lo fs_file_information.lo \ fs_getopt.lo fs_list_indexed.lo fs_publish.lo \ fs_publish_ksk.lo fs_misc.lo fs_namespace.lo \ fs_namespace_advertise.lo fs_search.lo fs_sharetree.lo \ fs_tree.lo fs_unindex.lo fs_uri.lo libgnunetfs_la_OBJECTS = $(am_libgnunetfs_la_OBJECTS) libgnunetfs_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetfs_la_LDFLAGS) $(LDFLAGS) -o \ $@ @HAVE_BENCHMARKS_TRUE@am__EXEEXT_1 = \ @HAVE_BENCHMARKS_TRUE@ perf_gnunet_service_fs_p2p$(EXEEXT) \ @HAVE_BENCHMARKS_TRUE@ perf_gnunet_service_fs_p2p_dht$(EXEEXT) \ @HAVE_BENCHMARKS_TRUE@ perf_gnunet_service_fs_p2p_index$(EXEEXT) \ @HAVE_BENCHMARKS_TRUE@ perf_gnunet_service_fs_p2p_trust$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) am_gnunet_directory_OBJECTS = gnunet-directory.$(OBJEXT) gnunet_directory_OBJECTS = $(am_gnunet_directory_OBJECTS) am_gnunet_download_OBJECTS = gnunet-download.$(OBJEXT) gnunet_download_OBJECTS = $(am_gnunet_download_OBJECTS) am_gnunet_fs_OBJECTS = gnunet-fs.$(OBJEXT) gnunet_fs_OBJECTS = $(am_gnunet_fs_OBJECTS) am_gnunet_helper_fs_publish_OBJECTS = \ gnunet-helper-fs-publish.$(OBJEXT) gnunet_helper_fs_publish_OBJECTS = \ $(am_gnunet_helper_fs_publish_OBJECTS) am_gnunet_pseudonym_OBJECTS = gnunet-pseudonym.$(OBJEXT) gnunet_pseudonym_OBJECTS = $(am_gnunet_pseudonym_OBJECTS) am_gnunet_publish_OBJECTS = gnunet-publish.$(OBJEXT) gnunet_publish_OBJECTS = $(am_gnunet_publish_OBJECTS) am_gnunet_search_OBJECTS = gnunet-search.$(OBJEXT) gnunet_search_OBJECTS = $(am_gnunet_search_OBJECTS) am_gnunet_service_fs_OBJECTS = gnunet-service-fs.$(OBJEXT) \ gnunet-service-fs_cp.$(OBJEXT) \ gnunet-service-fs_indexing.$(OBJEXT) \ gnunet-service-fs_lc.$(OBJEXT) gnunet-service-fs_pe.$(OBJEXT) \ gnunet-service-fs_pr.$(OBJEXT) \ gnunet-service-fs_push.$(OBJEXT) \ gnunet-service-fs_put.$(OBJEXT) gnunet_service_fs_OBJECTS = $(am_gnunet_service_fs_OBJECTS) am_gnunet_unindex_OBJECTS = gnunet-unindex.$(OBJEXT) gnunet_unindex_OBJECTS = $(am_gnunet_unindex_OBJECTS) am_perf_gnunet_service_fs_p2p_OBJECTS = \ perf_gnunet_service_fs_p2p.$(OBJEXT) perf_gnunet_service_fs_p2p_OBJECTS = \ $(am_perf_gnunet_service_fs_p2p_OBJECTS) perf_gnunet_service_fs_p2p_DEPENDENCIES = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_perf_gnunet_service_fs_p2p_dht_OBJECTS = \ perf_gnunet_service_fs_p2p.$(OBJEXT) perf_gnunet_service_fs_p2p_dht_OBJECTS = \ $(am_perf_gnunet_service_fs_p2p_dht_OBJECTS) perf_gnunet_service_fs_p2p_dht_DEPENDENCIES = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_perf_gnunet_service_fs_p2p_index_OBJECTS = \ perf_gnunet_service_fs_p2p.$(OBJEXT) perf_gnunet_service_fs_p2p_index_OBJECTS = \ $(am_perf_gnunet_service_fs_p2p_index_OBJECTS) perf_gnunet_service_fs_p2p_index_DEPENDENCIES = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_perf_gnunet_service_fs_p2p_trust_OBJECTS = \ perf_gnunet_service_fs_p2p_trust.$(OBJEXT) perf_gnunet_service_fs_p2p_trust_OBJECTS = \ $(am_perf_gnunet_service_fs_p2p_trust_OBJECTS) perf_gnunet_service_fs_p2p_trust_DEPENDENCIES = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_fs_directory_OBJECTS = test_fs_directory.$(OBJEXT) test_fs_directory_OBJECTS = $(am_test_fs_directory_OBJECTS) test_fs_directory_DEPENDENCIES = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_fs_download_OBJECTS = test_fs_download.$(OBJEXT) test_fs_download_OBJECTS = $(am_test_fs_download_OBJECTS) test_fs_download_DEPENDENCIES = $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_fs_download_indexed_OBJECTS = \ test_fs_download_indexed.$(OBJEXT) test_fs_download_indexed_OBJECTS = \ $(am_test_fs_download_indexed_OBJECTS) test_fs_download_indexed_DEPENDENCIES = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_fs_download_persistence_OBJECTS = \ test_fs_download_persistence.$(OBJEXT) test_fs_download_persistence_OBJECTS = \ $(am_test_fs_download_persistence_OBJECTS) test_fs_download_persistence_DEPENDENCIES = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_fs_file_information_OBJECTS = \ test_fs_file_information.$(OBJEXT) test_fs_file_information_OBJECTS = \ $(am_test_fs_file_information_OBJECTS) test_fs_file_information_DEPENDENCIES = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_fs_getopt_OBJECTS = test_fs_getopt.$(OBJEXT) test_fs_getopt_OBJECTS = $(am_test_fs_getopt_OBJECTS) test_fs_getopt_DEPENDENCIES = $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_fs_list_indexed_OBJECTS = test_fs_list_indexed.$(OBJEXT) test_fs_list_indexed_OBJECTS = $(am_test_fs_list_indexed_OBJECTS) test_fs_list_indexed_DEPENDENCIES = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_fs_namespace_OBJECTS = test_fs_namespace.$(OBJEXT) test_fs_namespace_OBJECTS = $(am_test_fs_namespace_OBJECTS) test_fs_namespace_DEPENDENCIES = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_fs_namespace_list_updateable_OBJECTS = \ test_fs_namespace_list_updateable.$(OBJEXT) test_fs_namespace_list_updateable_OBJECTS = \ $(am_test_fs_namespace_list_updateable_OBJECTS) test_fs_namespace_list_updateable_DEPENDENCIES = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_fs_publish_OBJECTS = test_fs_publish.$(OBJEXT) test_fs_publish_OBJECTS = $(am_test_fs_publish_OBJECTS) test_fs_publish_DEPENDENCIES = $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_fs_publish_persistence_OBJECTS = \ test_fs_publish_persistence.$(OBJEXT) test_fs_publish_persistence_OBJECTS = \ $(am_test_fs_publish_persistence_OBJECTS) test_fs_publish_persistence_DEPENDENCIES = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_fs_search_OBJECTS = test_fs_search.$(OBJEXT) test_fs_search_OBJECTS = $(am_test_fs_search_OBJECTS) test_fs_search_DEPENDENCIES = $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_fs_search_persistence_OBJECTS = \ test_fs_search_persistence.$(OBJEXT) test_fs_search_persistence_OBJECTS = \ $(am_test_fs_search_persistence_OBJECTS) test_fs_search_persistence_DEPENDENCIES = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_fs_search_probes_OBJECTS = test_fs_search_probes.$(OBJEXT) test_fs_search_probes_OBJECTS = $(am_test_fs_search_probes_OBJECTS) test_fs_search_probes_DEPENDENCIES = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_fs_start_stop_OBJECTS = test_fs_start_stop.$(OBJEXT) test_fs_start_stop_OBJECTS = $(am_test_fs_start_stop_OBJECTS) test_fs_start_stop_DEPENDENCIES = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_fs_test_lib_OBJECTS = test_fs_test_lib.$(OBJEXT) test_fs_test_lib_OBJECTS = $(am_test_fs_test_lib_OBJECTS) test_fs_test_lib_DEPENDENCIES = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_fs_unindex_OBJECTS = test_fs_unindex.$(OBJEXT) test_fs_unindex_OBJECTS = $(am_test_fs_unindex_OBJECTS) test_fs_unindex_DEPENDENCIES = $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_fs_unindex_persistence_OBJECTS = \ test_fs_unindex_persistence.$(OBJEXT) test_fs_unindex_persistence_OBJECTS = \ $(am_test_fs_unindex_persistence_OBJECTS) test_fs_unindex_persistence_DEPENDENCIES = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_fs_uri_OBJECTS = test_fs_uri.$(OBJEXT) test_fs_uri_OBJECTS = $(am_test_fs_uri_OBJECTS) test_fs_uri_DEPENDENCIES = $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_gnunet_service_fs_migration_OBJECTS = \ test_gnunet_service_fs_migration.$(OBJEXT) test_gnunet_service_fs_migration_OBJECTS = \ $(am_test_gnunet_service_fs_migration_OBJECTS) test_gnunet_service_fs_migration_DEPENDENCIES = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_gnunet_service_fs_p2p_OBJECTS = \ test_gnunet_service_fs_p2p.$(OBJEXT) test_gnunet_service_fs_p2p_OBJECTS = \ $(am_test_gnunet_service_fs_p2p_OBJECTS) test_gnunet_service_fs_p2p_DEPENDENCIES = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la SCRIPTS = $(bin_SCRIPTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunetfstest_a_SOURCES) \ $(libgnunet_plugin_block_fs_la_SOURCES) \ $(libgnunetfs_la_SOURCES) $(gnunet_directory_SOURCES) \ $(gnunet_download_SOURCES) $(gnunet_fs_SOURCES) \ $(gnunet_helper_fs_publish_SOURCES) \ $(gnunet_pseudonym_SOURCES) $(gnunet_publish_SOURCES) \ $(gnunet_search_SOURCES) $(gnunet_service_fs_SOURCES) \ $(gnunet_unindex_SOURCES) \ $(perf_gnunet_service_fs_p2p_SOURCES) \ $(perf_gnunet_service_fs_p2p_dht_SOURCES) \ $(perf_gnunet_service_fs_p2p_index_SOURCES) \ $(perf_gnunet_service_fs_p2p_trust_SOURCES) \ $(test_fs_directory_SOURCES) $(test_fs_download_SOURCES) \ $(test_fs_download_indexed_SOURCES) \ $(test_fs_download_persistence_SOURCES) \ $(test_fs_file_information_SOURCES) $(test_fs_getopt_SOURCES) \ $(test_fs_list_indexed_SOURCES) $(test_fs_namespace_SOURCES) \ $(test_fs_namespace_list_updateable_SOURCES) \ $(test_fs_publish_SOURCES) \ $(test_fs_publish_persistence_SOURCES) \ $(test_fs_search_SOURCES) \ $(test_fs_search_persistence_SOURCES) \ $(test_fs_search_probes_SOURCES) $(test_fs_start_stop_SOURCES) \ $(test_fs_test_lib_SOURCES) $(test_fs_unindex_SOURCES) \ $(test_fs_unindex_persistence_SOURCES) $(test_fs_uri_SOURCES) \ $(test_gnunet_service_fs_migration_SOURCES) \ $(test_gnunet_service_fs_p2p_SOURCES) DIST_SOURCES = $(libgnunetfstest_a_SOURCES) \ $(libgnunet_plugin_block_fs_la_SOURCES) \ $(libgnunetfs_la_SOURCES) $(gnunet_directory_SOURCES) \ $(gnunet_download_SOURCES) $(gnunet_fs_SOURCES) \ $(gnunet_helper_fs_publish_SOURCES) \ $(gnunet_pseudonym_SOURCES) $(gnunet_publish_SOURCES) \ $(gnunet_search_SOURCES) $(gnunet_service_fs_SOURCES) \ $(gnunet_unindex_SOURCES) \ $(perf_gnunet_service_fs_p2p_SOURCES) \ $(perf_gnunet_service_fs_p2p_dht_SOURCES) \ $(perf_gnunet_service_fs_p2p_index_SOURCES) \ $(perf_gnunet_service_fs_p2p_trust_SOURCES) \ $(test_fs_directory_SOURCES) $(test_fs_download_SOURCES) \ $(test_fs_download_indexed_SOURCES) \ $(test_fs_download_persistence_SOURCES) \ $(test_fs_file_information_SOURCES) $(test_fs_getopt_SOURCES) \ $(test_fs_list_indexed_SOURCES) $(test_fs_namespace_SOURCES) \ $(test_fs_namespace_list_updateable_SOURCES) \ $(test_fs_publish_SOURCES) \ $(test_fs_publish_persistence_SOURCES) \ $(test_fs_search_SOURCES) \ $(test_fs_search_persistence_SOURCES) \ $(test_fs_search_probes_SOURCES) $(test_fs_start_stop_SOURCES) \ $(test_fs_test_lib_SOURCES) $(test_fs_unindex_SOURCES) \ $(test_fs_unindex_persistence_SOURCES) $(test_fs_uri_SOURCES) \ $(test_gnunet_service_fs_migration_SOURCES) \ $(test_gnunet_service_fs_p2p_SOURCES) DATA = $(pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @USE_COVERAGE_TRUE@XLIB = -lgcov pkgcfgdir = $(pkgdatadir)/config.d/ pkgcfg_DATA = \ fs.conf plugindir = $(libdir)/gnunet lib_LTLIBRARIES = libgnunetfs.la plugin_LTLIBRARIES = \ libgnunet_plugin_block_fs.la noinst_LIBRARIES = libgnunetfstest.a libgnunetfs_la_SOURCES = \ fs_api.c fs_api.h fs.h \ fs_directory.c \ fs_dirmetascan.c \ fs_download.c \ fs_file_information.c \ fs_getopt.c \ fs_list_indexed.c \ fs_publish.c \ fs_publish_ksk.c \ fs_misc.c \ fs_namespace.c \ fs_namespace_advertise.c \ fs_search.c \ fs_sharetree.c \ fs_tree.c fs_tree.h \ fs_unindex.c \ fs_uri.c libgnunetfs_la_LIBADD = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) $(XLIB) -lunistring -lextractor libgnunetfs_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 2:1:0 libgnunetfstest_a_SOURCES = \ fs_test_lib.c fs_test_lib.h libgnunetfstest_a_LIBADD = \ $(top_builddir)/src/testing/libgnunettesting.la bin_SCRIPTS = \ gnunet-download-manager.scm gnunet_directory_SOURCES = \ gnunet-directory.c gnunet_directory_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la \ -lextractor \ $(GN_LIBINTL) gnunet_directory_DEPENDENCIES = \ libgnunetfs.la gnunet_fs_SOURCES = \ gnunet-fs.c gnunet_fs_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la \ -lextractor \ $(GN_LIBINTL) gnunet_fs_DEPENDENCIES = \ libgnunetfs.la gnunet_download_SOURCES = \ gnunet-download.c gnunet_download_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_download_DEPENDENCIES = \ libgnunetfs.la gnunet_publish_SOURCES = \ gnunet-publish.c gnunet_publish_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la \ -lextractor \ $(GN_LIBINTL) gnunet_publish_DEPENDENCIES = \ libgnunetfs.la gnunet_helper_fs_publish_SOURCES = \ gnunet-helper-fs-publish.c gnunet_helper_fs_publish_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ -lextractor \ $(GN_LIBINTL) gnunet_helper_fs_publish_DEPENDENCIES = \ libgnunetfs.la gnunet_pseudonym_SOURCES = \ gnunet-pseudonym.c gnunet_pseudonym_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la \ -lextractor \ $(GN_LIBINTL) gnunet_pseudonym_DEPENDENCIES = \ libgnunetfs.la gnunet_search_SOURCES = \ gnunet-search.c gnunet_search_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la \ -lextractor \ $(GN_LIBINTL) gnunet_search_DEPENDENCIES = \ libgnunetfs.la gnunet_service_fs_SOURCES = \ gnunet-service-fs.c gnunet-service-fs.h \ gnunet-service-fs_cp.c gnunet-service-fs_cp.h \ gnunet-service-fs_indexing.c gnunet-service-fs_indexing.h \ gnunet-service-fs_lc.c gnunet-service-fs_lc.h \ gnunet-service-fs_pe.c gnunet-service-fs_pe.h \ gnunet-service-fs_pr.c gnunet-service-fs_pr.h \ gnunet-service-fs_push.c gnunet-service-fs_push.h \ gnunet-service-fs_put.c gnunet-service-fs_put.h gnunet_service_fs_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/block/libgnunetblock.la \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/ats/libgnunetats.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) -lm gnunet_service_fs_DEPENDENCIES = \ libgnunetfs.la gnunet_unindex_SOURCES = \ gnunet-unindex.c gnunet_unindex_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_unindex_DEPENDENCIES = \ libgnunetfs.la libgnunet_plugin_block_fs_la_SOURCES = \ plugin_block_fs.c libgnunet_plugin_block_fs_la_LIBADD = \ $(top_builddir)/src/block/libgnunetblock.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_block_fs_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_block_fs_la_DEPENDENCIES = \ $(top_builddir)/src/block/libgnunetblock.la @HAVE_BENCHMARKS_TRUE@FS_BENCHMARKS = \ @HAVE_BENCHMARKS_TRUE@ perf_gnunet_service_fs_p2p \ @HAVE_BENCHMARKS_TRUE@ perf_gnunet_service_fs_p2p_dht \ @HAVE_BENCHMARKS_TRUE@ perf_gnunet_service_fs_p2p_index \ @HAVE_BENCHMARKS_TRUE@ perf_gnunet_service_fs_p2p_trust @HAVE_PYTHON_PEXPECT_TRUE@check_SCRIPTS = \ @HAVE_PYTHON_PEXPECT_TRUE@ test_gnunet_fs_psd.py \ @HAVE_PYTHON_PEXPECT_TRUE@ test_gnunet_fs_rec.py \ @HAVE_PYTHON_PEXPECT_TRUE@ test_gnunet_fs_idx.py \ @HAVE_PYTHON_PEXPECT_TRUE@ test_gnunet_fs_ns.py @ENABLE_MONKEY_TRUE@TESTS_ENVIRONMENT = @MONKEYPREFIX@ @ENABLE_MONKEY_TRUE@AM_LDFLAGS = -no-install test_fs_directory_SOURCES = \ test_fs_directory.c test_fs_directory_LDADD = \ -lextractor \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_download_SOURCES = \ test_fs_download.c test_fs_download_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_download_indexed_SOURCES = \ test_fs_download_indexed.c test_fs_download_indexed_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_download_persistence_SOURCES = \ test_fs_download_persistence.c test_fs_download_persistence_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_file_information_SOURCES = \ test_fs_file_information.c test_fs_file_information_LDADD = \ -lextractor \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_getopt_SOURCES = \ test_fs_getopt.c test_fs_getopt_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_list_indexed_SOURCES = \ test_fs_list_indexed.c test_fs_list_indexed_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_namespace_SOURCES = \ test_fs_namespace.c test_fs_namespace_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_namespace_list_updateable_SOURCES = \ test_fs_namespace_list_updateable.c test_fs_namespace_list_updateable_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_publish_SOURCES = \ test_fs_publish.c test_fs_publish_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_publish_persistence_SOURCES = \ test_fs_publish_persistence.c test_fs_publish_persistence_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_search_SOURCES = \ test_fs_search.c test_fs_search_LDADD = $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_search_probes_SOURCES = \ test_fs_search_probes.c test_fs_search_probes_LDADD = $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_search_persistence_SOURCES = \ test_fs_search_persistence.c test_fs_search_persistence_LDADD = $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_start_stop_SOURCES = \ test_fs_start_stop.c test_fs_start_stop_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_unindex_SOURCES = \ test_fs_unindex.c test_fs_unindex_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_unindex_persistence_SOURCES = \ test_fs_unindex_persistence.c test_fs_unindex_persistence_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_uri_SOURCES = \ test_fs_uri.c test_fs_uri_LDADD = \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_fs_test_lib_SOURCES = \ test_fs_test_lib.c test_fs_test_lib_LDADD = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_gnunet_service_fs_p2p_SOURCES = \ test_gnunet_service_fs_p2p.c test_gnunet_service_fs_p2p_LDADD = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la test_gnunet_service_fs_migration_SOURCES = \ test_gnunet_service_fs_migration.c test_gnunet_service_fs_migration_LDADD = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la perf_gnunet_service_fs_p2p_SOURCES = \ perf_gnunet_service_fs_p2p.c perf_gnunet_service_fs_p2p_LDADD = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la perf_gnunet_service_fs_p2p_index_SOURCES = \ perf_gnunet_service_fs_p2p.c perf_gnunet_service_fs_p2p_index_LDADD = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la perf_gnunet_service_fs_p2p_dht_SOURCES = \ perf_gnunet_service_fs_p2p.c perf_gnunet_service_fs_p2p_dht_LDADD = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la perf_gnunet_service_fs_p2p_trust_SOURCES = \ perf_gnunet_service_fs_p2p_trust.c perf_gnunet_service_fs_p2p_trust_LDADD = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' EXTRA_DIST = \ test_fs_defaults.conf \ fs_test_lib_data.conf \ test_fs_data.conf \ test_fs_download_data.conf \ test_fs_file_information_data.conf \ fs_test_lib_data.conf \ test_fs_list_indexed_data.conf \ test_fs_namespace_data.conf \ test_fs_publish_data.conf \ test_fs_search_data.conf \ test_fs_unindex_data.conf \ test_fs_uri_data.conf \ test_gnunet_service_fs_migration_data.conf \ test_gnunet_fs_idx_data.conf \ test_gnunet_fs_ns_data.conf \ test_gnunet_fs_psd_data.conf \ test_gnunet_fs_rec_data.conf \ test_gnunet_fs_rec_data.tgz \ test_gnunet_fs_psd.py.in \ test_gnunet_fs_rec.py.in \ test_gnunet_fs_ns.py.in \ test_gnunet_fs_idx.py.in \ $(bin_SCRIPTS) CLEANFILES = $(check_SCRIPTS) all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/fs/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/fs/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): fs.conf: $(top_builddir)/config.status $(srcdir)/fs.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libgnunetfstest.a: $(libgnunetfstest_a_OBJECTS) $(libgnunetfstest_a_DEPENDENCIES) $(AM_V_at)-rm -f libgnunetfstest.a $(AM_V_AR)$(libgnunetfstest_a_AR) libgnunetfstest.a $(libgnunetfstest_a_OBJECTS) $(libgnunetfstest_a_LIBADD) $(AM_V_at)$(RANLIB) libgnunetfstest.a install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ } uninstall-pluginLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ done clean-pluginLTLIBRARIES: -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunet_plugin_block_fs.la: $(libgnunet_plugin_block_fs_la_OBJECTS) $(libgnunet_plugin_block_fs_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_block_fs_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_block_fs_la_OBJECTS) $(libgnunet_plugin_block_fs_la_LIBADD) $(LIBS) libgnunetfs.la: $(libgnunetfs_la_OBJECTS) $(libgnunetfs_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetfs_la_LINK) -rpath $(libdir) $(libgnunetfs_la_OBJECTS) $(libgnunetfs_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-directory$(EXEEXT): $(gnunet_directory_OBJECTS) $(gnunet_directory_DEPENDENCIES) @rm -f gnunet-directory$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_directory_OBJECTS) $(gnunet_directory_LDADD) $(LIBS) gnunet-download$(EXEEXT): $(gnunet_download_OBJECTS) $(gnunet_download_DEPENDENCIES) @rm -f gnunet-download$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_download_OBJECTS) $(gnunet_download_LDADD) $(LIBS) gnunet-fs$(EXEEXT): $(gnunet_fs_OBJECTS) $(gnunet_fs_DEPENDENCIES) @rm -f gnunet-fs$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_fs_OBJECTS) $(gnunet_fs_LDADD) $(LIBS) gnunet-helper-fs-publish$(EXEEXT): $(gnunet_helper_fs_publish_OBJECTS) $(gnunet_helper_fs_publish_DEPENDENCIES) @rm -f gnunet-helper-fs-publish$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_helper_fs_publish_OBJECTS) $(gnunet_helper_fs_publish_LDADD) $(LIBS) gnunet-pseudonym$(EXEEXT): $(gnunet_pseudonym_OBJECTS) $(gnunet_pseudonym_DEPENDENCIES) @rm -f gnunet-pseudonym$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_pseudonym_OBJECTS) $(gnunet_pseudonym_LDADD) $(LIBS) gnunet-publish$(EXEEXT): $(gnunet_publish_OBJECTS) $(gnunet_publish_DEPENDENCIES) @rm -f gnunet-publish$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_publish_OBJECTS) $(gnunet_publish_LDADD) $(LIBS) gnunet-search$(EXEEXT): $(gnunet_search_OBJECTS) $(gnunet_search_DEPENDENCIES) @rm -f gnunet-search$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_search_OBJECTS) $(gnunet_search_LDADD) $(LIBS) gnunet-service-fs$(EXEEXT): $(gnunet_service_fs_OBJECTS) $(gnunet_service_fs_DEPENDENCIES) @rm -f gnunet-service-fs$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_service_fs_OBJECTS) $(gnunet_service_fs_LDADD) $(LIBS) gnunet-unindex$(EXEEXT): $(gnunet_unindex_OBJECTS) $(gnunet_unindex_DEPENDENCIES) @rm -f gnunet-unindex$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_unindex_OBJECTS) $(gnunet_unindex_LDADD) $(LIBS) perf_gnunet_service_fs_p2p$(EXEEXT): $(perf_gnunet_service_fs_p2p_OBJECTS) $(perf_gnunet_service_fs_p2p_DEPENDENCIES) @rm -f perf_gnunet_service_fs_p2p$(EXEEXT) $(AM_V_CCLD)$(LINK) $(perf_gnunet_service_fs_p2p_OBJECTS) $(perf_gnunet_service_fs_p2p_LDADD) $(LIBS) perf_gnunet_service_fs_p2p_dht$(EXEEXT): $(perf_gnunet_service_fs_p2p_dht_OBJECTS) $(perf_gnunet_service_fs_p2p_dht_DEPENDENCIES) @rm -f perf_gnunet_service_fs_p2p_dht$(EXEEXT) $(AM_V_CCLD)$(LINK) $(perf_gnunet_service_fs_p2p_dht_OBJECTS) $(perf_gnunet_service_fs_p2p_dht_LDADD) $(LIBS) perf_gnunet_service_fs_p2p_index$(EXEEXT): $(perf_gnunet_service_fs_p2p_index_OBJECTS) $(perf_gnunet_service_fs_p2p_index_DEPENDENCIES) @rm -f perf_gnunet_service_fs_p2p_index$(EXEEXT) $(AM_V_CCLD)$(LINK) $(perf_gnunet_service_fs_p2p_index_OBJECTS) $(perf_gnunet_service_fs_p2p_index_LDADD) $(LIBS) perf_gnunet_service_fs_p2p_trust$(EXEEXT): $(perf_gnunet_service_fs_p2p_trust_OBJECTS) $(perf_gnunet_service_fs_p2p_trust_DEPENDENCIES) @rm -f perf_gnunet_service_fs_p2p_trust$(EXEEXT) $(AM_V_CCLD)$(LINK) $(perf_gnunet_service_fs_p2p_trust_OBJECTS) $(perf_gnunet_service_fs_p2p_trust_LDADD) $(LIBS) test_fs_directory$(EXEEXT): $(test_fs_directory_OBJECTS) $(test_fs_directory_DEPENDENCIES) @rm -f test_fs_directory$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_fs_directory_OBJECTS) $(test_fs_directory_LDADD) $(LIBS) test_fs_download$(EXEEXT): $(test_fs_download_OBJECTS) $(test_fs_download_DEPENDENCIES) @rm -f test_fs_download$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_fs_download_OBJECTS) $(test_fs_download_LDADD) $(LIBS) test_fs_download_indexed$(EXEEXT): $(test_fs_download_indexed_OBJECTS) $(test_fs_download_indexed_DEPENDENCIES) @rm -f test_fs_download_indexed$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_fs_download_indexed_OBJECTS) $(test_fs_download_indexed_LDADD) $(LIBS) test_fs_download_persistence$(EXEEXT): $(test_fs_download_persistence_OBJECTS) $(test_fs_download_persistence_DEPENDENCIES) @rm -f test_fs_download_persistence$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_fs_download_persistence_OBJECTS) $(test_fs_download_persistence_LDADD) $(LIBS) test_fs_file_information$(EXEEXT): $(test_fs_file_information_OBJECTS) $(test_fs_file_information_DEPENDENCIES) @rm -f test_fs_file_information$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_fs_file_information_OBJECTS) $(test_fs_file_information_LDADD) $(LIBS) test_fs_getopt$(EXEEXT): $(test_fs_getopt_OBJECTS) $(test_fs_getopt_DEPENDENCIES) @rm -f test_fs_getopt$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_fs_getopt_OBJECTS) $(test_fs_getopt_LDADD) $(LIBS) test_fs_list_indexed$(EXEEXT): $(test_fs_list_indexed_OBJECTS) $(test_fs_list_indexed_DEPENDENCIES) @rm -f test_fs_list_indexed$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_fs_list_indexed_OBJECTS) $(test_fs_list_indexed_LDADD) $(LIBS) test_fs_namespace$(EXEEXT): $(test_fs_namespace_OBJECTS) $(test_fs_namespace_DEPENDENCIES) @rm -f test_fs_namespace$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_fs_namespace_OBJECTS) $(test_fs_namespace_LDADD) $(LIBS) test_fs_namespace_list_updateable$(EXEEXT): $(test_fs_namespace_list_updateable_OBJECTS) $(test_fs_namespace_list_updateable_DEPENDENCIES) @rm -f test_fs_namespace_list_updateable$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_fs_namespace_list_updateable_OBJECTS) $(test_fs_namespace_list_updateable_LDADD) $(LIBS) test_fs_publish$(EXEEXT): $(test_fs_publish_OBJECTS) $(test_fs_publish_DEPENDENCIES) @rm -f test_fs_publish$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_fs_publish_OBJECTS) $(test_fs_publish_LDADD) $(LIBS) test_fs_publish_persistence$(EXEEXT): $(test_fs_publish_persistence_OBJECTS) $(test_fs_publish_persistence_DEPENDENCIES) @rm -f test_fs_publish_persistence$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_fs_publish_persistence_OBJECTS) $(test_fs_publish_persistence_LDADD) $(LIBS) test_fs_search$(EXEEXT): $(test_fs_search_OBJECTS) $(test_fs_search_DEPENDENCIES) @rm -f test_fs_search$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_fs_search_OBJECTS) $(test_fs_search_LDADD) $(LIBS) test_fs_search_persistence$(EXEEXT): $(test_fs_search_persistence_OBJECTS) $(test_fs_search_persistence_DEPENDENCIES) @rm -f test_fs_search_persistence$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_fs_search_persistence_OBJECTS) $(test_fs_search_persistence_LDADD) $(LIBS) test_fs_search_probes$(EXEEXT): $(test_fs_search_probes_OBJECTS) $(test_fs_search_probes_DEPENDENCIES) @rm -f test_fs_search_probes$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_fs_search_probes_OBJECTS) $(test_fs_search_probes_LDADD) $(LIBS) test_fs_start_stop$(EXEEXT): $(test_fs_start_stop_OBJECTS) $(test_fs_start_stop_DEPENDENCIES) @rm -f test_fs_start_stop$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_fs_start_stop_OBJECTS) $(test_fs_start_stop_LDADD) $(LIBS) test_fs_test_lib$(EXEEXT): $(test_fs_test_lib_OBJECTS) $(test_fs_test_lib_DEPENDENCIES) @rm -f test_fs_test_lib$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_fs_test_lib_OBJECTS) $(test_fs_test_lib_LDADD) $(LIBS) test_fs_unindex$(EXEEXT): $(test_fs_unindex_OBJECTS) $(test_fs_unindex_DEPENDENCIES) @rm -f test_fs_unindex$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_fs_unindex_OBJECTS) $(test_fs_unindex_LDADD) $(LIBS) test_fs_unindex_persistence$(EXEEXT): $(test_fs_unindex_persistence_OBJECTS) $(test_fs_unindex_persistence_DEPENDENCIES) @rm -f test_fs_unindex_persistence$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_fs_unindex_persistence_OBJECTS) $(test_fs_unindex_persistence_LDADD) $(LIBS) test_fs_uri$(EXEEXT): $(test_fs_uri_OBJECTS) $(test_fs_uri_DEPENDENCIES) @rm -f test_fs_uri$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_fs_uri_OBJECTS) $(test_fs_uri_LDADD) $(LIBS) test_gnunet_service_fs_migration$(EXEEXT): $(test_gnunet_service_fs_migration_OBJECTS) $(test_gnunet_service_fs_migration_DEPENDENCIES) @rm -f test_gnunet_service_fs_migration$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gnunet_service_fs_migration_OBJECTS) $(test_gnunet_service_fs_migration_LDADD) $(LIBS) test_gnunet_service_fs_p2p$(EXEEXT): $(test_gnunet_service_fs_p2p_OBJECTS) $(test_gnunet_service_fs_p2p_DEPENDENCIES) @rm -f test_gnunet_service_fs_p2p$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gnunet_service_fs_p2p_OBJECTS) $(test_gnunet_service_fs_p2p_LDADD) $(LIBS) install-binSCRIPTS: $(bin_SCRIPTS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_directory.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_dirmetascan.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_download.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_file_information.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_getopt.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_list_indexed.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_misc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_namespace.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_namespace_advertise.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_publish.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_publish_ksk.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_search.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_sharetree.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_test_lib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_tree.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_unindex.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs_uri.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-directory.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-download.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-fs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-fs-publish.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-pseudonym.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-publish.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-search.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-fs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-fs_cp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-fs_indexing.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-fs_lc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-fs_pe.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-fs_pr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-fs_push.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-fs_put.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-unindex.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perf_gnunet_service_fs_p2p.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perf_gnunet_service_fs_p2p_trust.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_block_fs.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_directory.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_download.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_download_indexed.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_download_persistence.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_file_information.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_getopt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_list_indexed.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_namespace.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_namespace_list_updateable.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_publish.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_publish_persistence.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_search.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_search_persistence.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_search_probes.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_start_stop.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_test_lib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_unindex.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_unindex_persistence.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_fs_uri.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gnunet_service_fs_migration.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gnunet_service_fs_p2p.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgcfgDATA: $(pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(check_SCRIPTS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LIBRARIES) $(LTLIBRARIES) $(PROGRAMS) $(SCRIPTS) \ $(DATA) install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool clean-noinstLIBRARIES \ clean-pluginLTLIBRARIES mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgcfgDATA install-pluginLTLIBRARIES install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-binSCRIPTS \ install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \ uninstall-libLTLIBRARIES uninstall-pkgcfgDATA \ uninstall-pluginLTLIBRARIES .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool clean-noinstLIBRARIES \ clean-pluginLTLIBRARIES ctags distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-binPROGRAMS install-binSCRIPTS install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-pkgcfgDATA install-pluginLTLIBRARIES \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-binSCRIPTS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES test_gnunet_fs_psd.py: test_gnunet_fs_psd.py.in Makefile $(do_subst) < $(srcdir)/test_gnunet_fs_psd.py.in > test_gnunet_fs_psd.py chmod +x test_gnunet_fs_psd.py test_gnunet_fs_rec.py: test_gnunet_fs_rec.py.in Makefile $(do_subst) < $(srcdir)/test_gnunet_fs_rec.py.in > test_gnunet_fs_rec.py chmod +x test_gnunet_fs_rec.py test_gnunet_fs_ns.py: test_gnunet_fs_ns.py.in Makefile $(do_subst) < $(srcdir)/test_gnunet_fs_ns.py.in > test_gnunet_fs_ns.py chmod +x test_gnunet_fs_ns.py test_gnunet_fs_idx.py: test_gnunet_fs_idx.py.in Makefile $(do_subst) < $(srcdir)/test_gnunet_fs_idx.py.in > test_gnunet_fs_idx.py chmod +x test_gnunet_fs_idx.py # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/fs/test_fs_search_data.conf0000644000175000017500000000022311615567501016003 00000000000000@INLINE@ test_fs_defaults.conf [PATHS] SERVICEHOME = /tmp/gnunet-test-fs-search/ DEFAULTCONFIG = test_fs_search_data.conf [transport] PLUGINS = gnunet-0.9.3/src/fs/test_gnunet_fs_idx.py.in0000644000175000017500000000623711760502552016030 00000000000000#!@PYTHON@ # This file is part of GNUnet. # (C) 2010 Christian Grothoff (and other contributing authors) # # GNUnet is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2, or (at your # option) any later version. # # GNUnet is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNUnet; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # Testcase for file-sharing command-line tools (indexing and unindexing) import sys import os import subprocess import re import shutil srcdir = "../.." gnunet_pyexpect_dir = os.path.join (srcdir, "contrib") if gnunet_pyexpect_dir not in sys.path: sys.path.append (gnunet_pyexpect_dir) from gnunet_pyexpect import pexpect if os.name == 'posix': download = 'gnunet-download' gnunetarm = 'gnunet-arm' publish = 'gnunet-publish' unindex = 'gnunet-unindex' elif os.name == 'nt': download = 'gnunet-download.exe' gnunetarm = 'gnunet-arm.exe' publish = 'gnunet-publish.exe' unindex = 'gnunet-unindex.exe' if os.name == "nt": shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-idx"), True) else: shutil.rmtree ("/tmp/gnunet-test-fs-py-idx", True) arm = subprocess.Popen ([gnunetarm, '-sq', '-c', 'test_gnunet_fs_idx_data.conf']) arm.communicate () try: pub = pexpect () pub.spawn (None, [publish, '-c', 'test_gnunet_fs_idx_data.conf', '-m', "description:The GNU Public License", '-k', 'gpl', '../../COPYING'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pub.expect ("stdout", re.compile (r"URI is `gnunet://fs/chk/PC0M19QMQC0BPSHR6BGA228PP6INER1D610MGEMOMEM87222FN8HVUO7PQGO0O9HD2GVLHF2N5IDHEQUNK6LKE428FPO96SKQEA486O\.PG7K85JGQ6N599MD5HEP3CHEVFPKQD9JB6NPSLVA3T1SKDS66CFI499VS6MGQ88B0QUAVT1282TCRD4GGFVUKDLGI8F0SPIANA3J2LG\.35147'\.\r?\n")) down = pexpect () down.spawn (None, [download, '-c', 'test_gnunet_fs_idx_data.conf', '-o', 'COPYING', 'gnunet://fs/chk/PC0M19QMQC0BPSHR6BGA228PP6INER1D610MGEMOMEM87222FN8HVUO7PQGO0O9HD2GVLHF2N5IDHEQUNK6LKE428FPO96SKQEA486O.PG7K85JGQ6N599MD5HEP3CHEVFPKQD9JB6NPSLVA3T1SKDS66CFI499VS6MGQ88B0QUAVT1282TCRD4GGFVUKDLGI8F0SPIANA3J2LG.35147'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) down.expect ("stdout", re.compile (r"Downloading `COPYING' done (.*).\r?\n")) os.remove ("COPYING") un = pexpect () un.spawn (None, [unindex, '-c', 'test_gnunet_fs_idx_data.conf', '../../COPYING'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) un.expect ("stdout", re.compile (r'Unindexing done\.\r?\n')) finally: arm = subprocess.Popen ([gnunetarm, '-eq', '-c', 'test_gnunet_fs_idx_data.conf']) arm.communicate () if os.name == "nt": shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-fs-py-idx"), True) else: shutil.rmtree ("/tmp/gnunet-test-fs-py-idx", True) gnunet-0.9.3/src/fs/fs_getopt.c0000644000175000017500000001453111760502551013307 00000000000000/* This file is part of GNUnet. (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs_getopt.c * @brief helper functions for command-line argument processing * @author Igor Wronsky, Christian Grothoff */ #include "platform.h" #include "gnunet_fs_service.h" #include "fs_api.h" /* ******************** command-line option parsing API ******************** */ /** * Command-line option parser function that allows the user * to specify one or more '-k' options with keywords. Each * specified keyword will be added to the URI. A pointer to * the URI must be passed as the "scls" argument. * * @param ctx command line processor context * @param scls must be of type "struct GNUNET_FS_Uri **" * @param option name of the option (typically 'k') * @param value command line argument given * @return GNUNET_OK on success */ int GNUNET_FS_getopt_set_keywords (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, const char *value) { struct GNUNET_FS_Uri **uri = scls; struct GNUNET_FS_Uri *u = *uri; char *val; size_t slen; if (u == NULL) { u = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); *uri = u; u->type = ksk; u->data.ksk.keywordCount = 0; u->data.ksk.keywords = NULL; } else { GNUNET_assert (u->type == ksk); } slen = strlen (value); if (slen == 0) return GNUNET_SYSERR; /* cannot be empty */ if (value[0] == '+') { /* simply preserve the "mandatory" flag */ if (slen < 2) return GNUNET_SYSERR; /* empty keywords not allowed */ if ((value[1] == '"') && (slen > 3) && (value[slen - 1] == '"')) { /* remove the quotes, keep the '+' */ val = GNUNET_malloc (slen - 1); val[0] = '+'; memcpy (&val[1], &value[2], slen - 3); val[slen - 2] = '\0'; } else { /* no quotes, just keep the '+' */ val = GNUNET_strdup (value); } } else { if ((value[0] == '"') && (slen > 2) && (value[slen - 1] == '"')) { /* remove the quotes, add a space */ val = GNUNET_malloc (slen); val[0] = ' '; memcpy (&val[1], &value[1], slen - 2); val[slen - 1] = '\0'; } else { /* add a space to indicate "not mandatory" */ val = GNUNET_malloc (slen + 2); strcpy (val, " "); strcat (val, value); } } GNUNET_array_append (u->data.ksk.keywords, u->data.ksk.keywordCount, val); return GNUNET_OK; } /** * Command-line option parser function that allows the user to specify * one or more '-m' options with metadata. Each specified entry of * the form "type=value" will be added to the metadata. A pointer to * the metadata must be passed as the "scls" argument. * * @param ctx command line processor context * @param scls must be of type "struct GNUNET_MetaData **" * @param option name of the option (typically 'k') * @param value command line argument given * @return GNUNET_OK on success */ int GNUNET_FS_getopt_set_metadata (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, const char *value) { struct GNUNET_CONTAINER_MetaData **mm = scls; enum EXTRACTOR_MetaType type; const char *typename; const char *typename_i18n; struct GNUNET_CONTAINER_MetaData *meta; char *tmp; meta = *mm; if (meta == NULL) { meta = GNUNET_CONTAINER_meta_data_create (); *mm = meta; } #if ENABLE_NLS tmp = GNUNET_STRINGS_to_utf8 (value, strlen (value), nl_langinfo (CODESET)); #else tmp = GNUNET_STRINGS_to_utf8 (value, strlen (value), "utf-8"); #endif type = EXTRACTOR_metatype_get_max (); while (type > 0) { type--; typename = EXTRACTOR_metatype_to_string (type); typename_i18n = dgettext (LIBEXTRACTOR_GETTEXT_DOMAIN, typename); if ((strlen (tmp) >= strlen (typename) + 1) && (tmp[strlen (typename)] == ':') && (0 == strncmp (typename, tmp, strlen (typename)))) { GNUNET_CONTAINER_meta_data_insert (meta, "", type, EXTRACTOR_METAFORMAT_UTF8, "text/plain", &tmp[strlen (typename) + 1], strlen (&tmp[strlen (typename) + 1]) + 1); GNUNET_free (tmp); tmp = NULL; break; } if ((strlen (tmp) >= strlen (typename_i18n) + 1) && (tmp[strlen (typename_i18n)] == ':') && (0 == strncmp (typename_i18n, tmp, strlen (typename_i18n)))) { GNUNET_CONTAINER_meta_data_insert (meta, "", type, EXTRACTOR_METAFORMAT_UTF8, "text/plain", &tmp[strlen (typename_i18n) + 1], strlen (&tmp [strlen (typename_i18n) + 1]) + 1); GNUNET_free (tmp); tmp = NULL; break; } } if (tmp != NULL) { GNUNET_CONTAINER_meta_data_insert (meta, "", EXTRACTOR_METATYPE_UNKNOWN, EXTRACTOR_METAFORMAT_UTF8, "text/plain", tmp, strlen (tmp) + 1); GNUNET_free (tmp); printf (_ ("Unknown metadata type in metadata option `%s'. Using metadata type `unknown' instead.\n"), value); } return GNUNET_OK; } /* end of fs_getopt.c */ gnunet-0.9.3/src/fs/fs_publish.c0000644000175000017500000012062211760502551013452 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs_publish.c * @brief publish a file or directory in GNUnet * @see https://gnunet.org/encoding * @author Krista Bennett * @author Christian Grothoff */ #include "platform.h" #include "gnunet_constants.h" #include "gnunet_signatures.h" #include "gnunet_util_lib.h" #include "gnunet_fs_service.h" #include "fs_api.h" #include "fs_tree.h" /** * Fill in all of the generic fields for * a publish event and call the callback. * * @param pi structure to fill in * @param pc overall publishing context * @param p file information for the file being published * @param offset where in the file are we so far * @return value returned from callback */ void * GNUNET_FS_publish_make_status_ (struct GNUNET_FS_ProgressInfo *pi, struct GNUNET_FS_PublishContext *pc, const struct GNUNET_FS_FileInformation *p, uint64_t offset) { pi->value.publish.pc = pc; pi->value.publish.fi = p; pi->value.publish.cctx = p->client_info; pi->value.publish.pctx = (NULL == p->dir) ? NULL : p->dir->client_info; pi->value.publish.filename = p->filename; pi->value.publish.size = (p->is_directory == GNUNET_YES) ? p->data.dir.dir_size : p->data.file.file_size; pi->value.publish.eta = GNUNET_TIME_calculate_eta (p->start_time, offset, pi->value.publish.size); pi->value.publish.completed = offset; pi->value.publish.duration = GNUNET_TIME_absolute_get_duration (p->start_time); pi->value.publish.anonymity = p->bo.anonymity_level; return pc->h->upcb (pc->h->upcb_cls, pi); } /** * Cleanup the publish context, we're done with it. * * @param pc struct to clean up */ static void publish_cleanup (struct GNUNET_FS_PublishContext *pc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up publish context (done!)\n"); if (pc->fhc != NULL) { GNUNET_CRYPTO_hash_file_cancel (pc->fhc); pc->fhc = NULL; } GNUNET_FS_file_information_destroy (pc->fi, NULL, NULL); if (pc->namespace != NULL) { GNUNET_FS_namespace_delete (pc->namespace, GNUNET_NO); pc->namespace = NULL; } GNUNET_free_non_null (pc->nid); GNUNET_free_non_null (pc->nuid); GNUNET_free_non_null (pc->serialization); if (pc->dsh != NULL) { GNUNET_DATASTORE_disconnect (pc->dsh, GNUNET_NO); pc->dsh = NULL; } if (pc->client != NULL) { GNUNET_CLIENT_disconnect (pc->client); pc->client = NULL; } GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == pc->upload_task); GNUNET_free (pc); } /** * Function called by the datastore API with * the result from the PUT request. * * @param cls the 'struct GNUNET_FS_PublishContext' * @param success GNUNET_OK on success * @param min_expiration minimum expiration time required for content to be stored * @param msg error message (or NULL) */ static void ds_put_cont (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) { struct GNUNET_FS_PublishContext *pc = cls; struct GNUNET_FS_ProgressInfo pi; pc->qre = NULL; if (GNUNET_SYSERR == success) { GNUNET_asprintf (&pc->fi_pos->emsg, _("Publishing failed: %s"), msg); pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR; pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL; pi.value.publish.specifics.error.message = pc->fi_pos->emsg; pc->fi_pos->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, pc->fi_pos, 0); if ((pc->fi_pos->is_directory != GNUNET_YES) && (pc->fi_pos->filename != NULL) && (pc->fi_pos->data.file.do_index == GNUNET_YES)) { /* run unindex to clean up */ GNUNET_FS_unindex_start (pc->h, pc->fi_pos->filename, NULL); } } GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == pc->upload_task); pc->upload_task = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, &GNUNET_FS_publish_main_, pc); } /** * Generate the callback that signals clients * that a file (or directory) has been completely * published. * * @param p the completed upload * @param pc context of the publication */ static void signal_publish_completion (struct GNUNET_FS_FileInformation *p, struct GNUNET_FS_PublishContext *pc) { struct GNUNET_FS_ProgressInfo pi; pi.status = GNUNET_FS_STATUS_PUBLISH_COMPLETED; pi.value.publish.eta = GNUNET_TIME_UNIT_ZERO; pi.value.publish.specifics.completed.chk_uri = p->chk_uri; p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, GNUNET_ntohll (p->chk_uri->data. chk.file_length)); } /** * Generate the callback that signals clients * that a file (or directory) has encountered * a problem during publication. * * @param p the upload that had trouble * @param pc context of the publication * @param emsg error message */ static void signal_publish_error (struct GNUNET_FS_FileInformation *p, struct GNUNET_FS_PublishContext *pc, const char *emsg) { struct GNUNET_FS_ProgressInfo pi; p->emsg = GNUNET_strdup (emsg); pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR; pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL; pi.value.publish.specifics.error.message = emsg; p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, 0); if ((p->is_directory != GNUNET_YES) && (p->filename != NULL) && (p->data.file.do_index == GNUNET_YES)) { /* run unindex to clean up */ GNUNET_FS_unindex_start (pc->h, p->filename, NULL); } } /** * Datastore returns from reservation cancel request. * * @param cls the 'struct GNUNET_FS_PublishContext' * @param success success code (not used) * @param min_expiration minimum expiration time required for content to be stored * @param msg error message (typically NULL, not used) */ static void finish_release_reserve (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) { struct GNUNET_FS_PublishContext *pc = cls; pc->qre = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Releasing reserve done!\n"); signal_publish_completion (pc->fi, pc); pc->all_done = GNUNET_YES; GNUNET_FS_publish_sync_ (pc); } /** * We've finished publishing the SBlock as part of a larger upload. * Check the result and complete the larger upload. * * @param cls the "struct GNUNET_FS_PublishContext*" of the larger upload * @param uri URI of the published SBlock * @param emsg NULL on success, otherwise error message */ static void publish_sblocks_cont (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) { struct GNUNET_FS_PublishContext *pc = cls; pc->sks_pc = NULL; if (NULL != emsg) { signal_publish_error (pc->fi, pc, emsg); GNUNET_FS_publish_sync_ (pc); return; } GNUNET_assert (pc->qre == NULL); if ((pc->dsh != NULL) && (pc->rid != 0)) { pc->qre = GNUNET_DATASTORE_release_reserve (pc->dsh, pc->rid, UINT_MAX, UINT_MAX, GNUNET_TIME_UNIT_FOREVER_REL, &finish_release_reserve, pc); } else { finish_release_reserve (pc, GNUNET_OK, GNUNET_TIME_UNIT_ZERO_ABS, NULL); } } /** * We are almost done publishing the structure, * add SBlocks (if needed). * * @param pc overall upload data */ static void publish_sblock (struct GNUNET_FS_PublishContext *pc) { if (NULL != pc->namespace) pc->sks_pc = GNUNET_FS_publish_sks (pc->h, pc->namespace, pc->nid, pc->nuid, pc->fi->meta, pc->fi->chk_uri, &pc->fi->bo, pc->options, &publish_sblocks_cont, pc); else publish_sblocks_cont (pc, NULL, NULL); } /** * We've finished publishing a KBlock as part of a larger upload. * Check the result and continue the larger upload. * * @param cls the "struct GNUNET_FS_PublishContext*" * of the larger upload * @param uri URI of the published blocks * @param emsg NULL on success, otherwise error message */ static void publish_kblocks_cont (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) { struct GNUNET_FS_PublishContext *pc = cls; struct GNUNET_FS_FileInformation *p = pc->fi_pos; pc->ksk_pc = NULL; if (NULL != emsg) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error uploading KSK blocks: %s\n", emsg); signal_publish_error (p, pc, emsg); GNUNET_FS_file_information_sync_ (p); GNUNET_FS_publish_sync_ (pc); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == pc->upload_task); pc->upload_task = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, &GNUNET_FS_publish_main_, pc); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "KSK blocks published, moving on to next file\n"); if (NULL != p->dir) signal_publish_completion (p, pc); /* move on to next file */ if (NULL != p->next) pc->fi_pos = p->next; else pc->fi_pos = p->dir; GNUNET_FS_publish_sync_ (pc); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == pc->upload_task); pc->upload_task = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, &GNUNET_FS_publish_main_, pc); } /** * Function called by the tree encoder to obtain * a block of plaintext data (for the lowest level * of the tree). * * @param cls our publishing context * @param offset identifies which block to get * @param max (maximum) number of bytes to get; returning * fewer will also cause errors * @param buf where to copy the plaintext buffer * @param emsg location to store an error message (on error) * @return number of bytes copied to buf, 0 on error */ static size_t block_reader (void *cls, uint64_t offset, size_t max, void *buf, char **emsg) { struct GNUNET_FS_PublishContext *pc = cls; struct GNUNET_FS_FileInformation *p; size_t pt_size; const char *dd; p = pc->fi_pos; if (p->is_directory == GNUNET_YES) { pt_size = GNUNET_MIN (max, p->data.dir.dir_size - offset); dd = p->data.dir.dir_data; memcpy (buf, &dd[offset], pt_size); } else { if (UINT64_MAX == offset) return p->data.file.reader (p->data.file.reader_cls, offset, 0, NULL, NULL); pt_size = GNUNET_MIN (max, p->data.file.file_size - offset); if (pt_size == 0) return 0; /* calling reader with pt_size==0 * might free buf, so don't! */ if (pt_size != p->data.file.reader (p->data.file.reader_cls, offset, pt_size, buf, emsg)) return 0; } return pt_size; } /** * The tree encoder has finished processing a * file. Call it's finish method and deal with * the final result. * * @param cls our publishing context * @param tc scheduler's task context (not used) */ static void encode_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FS_PublishContext *pc = cls; struct GNUNET_FS_FileInformation *p; struct GNUNET_FS_ProgressInfo pi; char *emsg; uint64_t flen; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished with tree encoder\n"); p = pc->fi_pos; GNUNET_FS_tree_encoder_finish (p->te, &p->chk_uri, &emsg); p->te = NULL; if (NULL != emsg) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error during tree walk: %s\n", emsg); GNUNET_asprintf (&p->emsg, _("Publishing failed: %s"), emsg); GNUNET_free (emsg); pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR; pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL; pi.value.publish.specifics.error.message = p->emsg; p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, 0); } else { /* final progress event */ GNUNET_assert (NULL != p->chk_uri); flen = GNUNET_FS_uri_chk_get_file_size (p->chk_uri); pi.status = GNUNET_FS_STATUS_PUBLISH_PROGRESS; pi.value.publish.specifics.progress.data = NULL; pi.value.publish.specifics.progress.offset = flen; pi.value.publish.specifics.progress.data_len = 0; pi.value.publish.specifics.progress.depth = GNUNET_FS_compute_depth (flen); p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, flen); } GNUNET_FS_file_information_sync_ (p); /* continue with main */ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == pc->upload_task); pc->upload_task = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, &GNUNET_FS_publish_main_, pc); } /** * Function called asking for the current (encoded) * block to be processed. After processing the * client should either call "GNUNET_FS_tree_encode_next" * or (on error) "GNUNET_FS_tree_encode_finish". * * @param cls closure * @param chk content hash key for the block * @param offset offset of the block in the file * @param depth depth of the block in the file, 0 for DBLOCK * @param type type of the block (IBLOCK or DBLOCK) * @param block the (encrypted) block * @param block_size size of block (in bytes) */ static void block_proc (void *cls, const struct ContentHashKey *chk, uint64_t offset, unsigned int depth, enum GNUNET_BLOCK_Type type, const void *block, uint16_t block_size) { struct GNUNET_FS_PublishContext *pc = cls; struct GNUNET_FS_FileInformation *p; struct OnDemandBlock odb; p = pc->fi_pos; if (NULL == pc->dsh) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Waiting for datastore connection\n"); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == pc->upload_task); pc->upload_task = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, &GNUNET_FS_publish_main_, pc); return; } if ((p->is_directory != GNUNET_YES) && (GNUNET_YES == p->data.file.do_index) && (type == GNUNET_BLOCK_TYPE_FS_DBLOCK)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Indexing block `%s' for offset %llu with index size %u\n", GNUNET_h2s (&chk->query), (unsigned long long) offset, sizeof (struct OnDemandBlock)); odb.offset = GNUNET_htonll (offset); odb.file_id = p->data.file.file_id; GNUNET_assert (pc->qre == NULL); pc->qre = GNUNET_DATASTORE_put (pc->dsh, (p->is_directory == GNUNET_YES) ? 0 : pc->rid, &chk->query, sizeof (struct OnDemandBlock), &odb, GNUNET_BLOCK_TYPE_FS_ONDEMAND, p->bo.content_priority, p->bo.anonymity_level, p->bo.replication_level, p->bo.expiration_time, -2, 1, GNUNET_CONSTANTS_SERVICE_TIMEOUT, &ds_put_cont, pc); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing block `%s' for offset %llu with size %u\n", GNUNET_h2s (&chk->query), (unsigned long long) offset, (unsigned int) block_size); GNUNET_assert (pc->qre == NULL); pc->qre = GNUNET_DATASTORE_put (pc->dsh, (p->is_directory == GNUNET_YES) ? 0 : pc->rid, &chk->query, block_size, block, type, p->bo.content_priority, p->bo.anonymity_level, p->bo.replication_level, p->bo.expiration_time, -2, 1, GNUNET_CONSTANTS_SERVICE_TIMEOUT, &ds_put_cont, pc); } /** * Function called with information about our * progress in computing the tree encoding. * * @param cls closure * @param offset where are we in the file * @param pt_block plaintext of the currently processed block * @param pt_size size of pt_block * @param depth depth of the block in the tree, 0 for DBLOCK */ static void progress_proc (void *cls, uint64_t offset, const void *pt_block, size_t pt_size, unsigned int depth) { struct GNUNET_FS_PublishContext *pc = cls; struct GNUNET_FS_FileInformation *p; struct GNUNET_FS_ProgressInfo pi; p = pc->fi_pos; pi.status = GNUNET_FS_STATUS_PUBLISH_PROGRESS; pi.value.publish.specifics.progress.data = pt_block; pi.value.publish.specifics.progress.offset = offset; pi.value.publish.specifics.progress.data_len = pt_size; pi.value.publish.specifics.progress.depth = depth; p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, offset); } /** * We are uploading a file or directory; load (if necessary) the next * block into memory, encrypt it and send it to the FS service. Then * continue with the main task. * * @param pc overall upload data */ static void publish_content (struct GNUNET_FS_PublishContext *pc) { struct GNUNET_FS_FileInformation *p; char *emsg; struct GNUNET_FS_DirectoryBuilder *db; struct GNUNET_FS_FileInformation *dirpos; void *raw_data; uint64_t size; p = pc->fi_pos; GNUNET_assert (p != NULL); if (NULL == p->te) { if (p->is_directory == GNUNET_YES) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating directory\n"); db = GNUNET_FS_directory_builder_create (p->meta); dirpos = p->data.dir.entries; while (NULL != dirpos) { if (dirpos->is_directory == GNUNET_YES) { raw_data = dirpos->data.dir.dir_data; dirpos->data.dir.dir_data = NULL; } else { raw_data = NULL; if ((dirpos->data.file.file_size < MAX_INLINE_SIZE) && (dirpos->data.file.file_size > 0)) { raw_data = GNUNET_malloc (dirpos->data.file.file_size); emsg = NULL; if (dirpos->data.file.file_size != dirpos->data.file.reader (dirpos->data.file.reader_cls, 0, dirpos->data.file.file_size, raw_data, &emsg)) { GNUNET_free_non_null (emsg); GNUNET_free (raw_data); raw_data = NULL; } } } GNUNET_FS_directory_builder_add (db, dirpos->chk_uri, dirpos->meta, raw_data); GNUNET_free_non_null (raw_data); dirpos = dirpos->next; } GNUNET_free_non_null (p->data.dir.dir_data); p->data.dir.dir_data = NULL; p->data.dir.dir_size = 0; GNUNET_FS_directory_builder_finish (db, &p->data.dir.dir_size, &p->data.dir.dir_data); GNUNET_FS_file_information_sync_ (p); } size = (p->is_directory == GNUNET_YES) ? p->data.dir.dir_size : p->data.file.file_size; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating tree encoder\n"); p->te = GNUNET_FS_tree_encoder_create (pc->h, size, pc, &block_reader, &block_proc, &progress_proc, &encode_cont); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing next block from tree\n"); GNUNET_FS_tree_encoder_next (p->te); } /** * Process the response (or lack thereof) from * the "fs" service to our 'start index' request. * * @param cls closure (of type "struct GNUNET_FS_PublishContext*"_) * @param msg the response we got */ static void process_index_start_response (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_FS_PublishContext *pc = cls; struct GNUNET_FS_FileInformation *p; const char *emsg; uint16_t msize; GNUNET_CLIENT_disconnect (pc->client); pc->client = NULL; p = pc->fi_pos; if (msg == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Can not index file `%s': %s. Will try to insert instead.\n"), p->filename, _("timeout on index-start request to `fs' service")); p->data.file.do_index = GNUNET_NO; GNUNET_FS_file_information_sync_ (p); publish_content (pc); return; } if (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK) { msize = ntohs (msg->size); emsg = (const char *) &msg[1]; if ((msize <= sizeof (struct GNUNET_MessageHeader)) || (emsg[msize - sizeof (struct GNUNET_MessageHeader) - 1] != '\0')) emsg = gettext_noop ("unknown error"); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Can not index file `%s': %s. Will try to insert instead.\n"), p->filename, gettext (emsg)); p->data.file.do_index = GNUNET_NO; GNUNET_FS_file_information_sync_ (p); publish_content (pc); return; } p->data.file.index_start_confirmed = GNUNET_YES; /* success! continue with indexing */ GNUNET_FS_file_information_sync_ (p); publish_content (pc); } /** * Function called once the hash computation over an * indexed file has completed. * * @param cls closure, our publishing context * @param res resulting hash, NULL on error */ static void hash_for_index_cb (void *cls, const GNUNET_HashCode * res) { struct GNUNET_FS_PublishContext *pc = cls; struct GNUNET_FS_FileInformation *p; struct IndexStartMessage *ism; size_t slen; struct GNUNET_CLIENT_Connection *client; uint64_t dev; uint64_t ino; char *fn; pc->fhc = NULL; p = pc->fi_pos; if (NULL == res) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Can not index file `%s': %s. Will try to insert instead.\n"), p->filename, _("failed to compute hash")); p->data.file.do_index = GNUNET_NO; GNUNET_FS_file_information_sync_ (p); publish_content (pc); return; } if (GNUNET_YES == p->data.file.index_start_confirmed) { publish_content (pc); return; } fn = GNUNET_STRINGS_filename_expand (p->filename); GNUNET_assert (fn != NULL); slen = strlen (fn) + 1; if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct IndexStartMessage)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Can not index file `%s': %s. Will try to insert instead.\n"), fn, _("filename too long")); GNUNET_free (fn); p->data.file.do_index = GNUNET_NO; GNUNET_FS_file_information_sync_ (p); publish_content (pc); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hash of indexed file `%s' is `%s'\n", p->filename, GNUNET_h2s (res)); if (0 != (pc->options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) { p->data.file.file_id = *res; p->data.file.have_hash = GNUNET_YES; p->data.file.index_start_confirmed = GNUNET_YES; GNUNET_FS_file_information_sync_ (p); publish_content (pc); GNUNET_free (fn); return; } client = GNUNET_CLIENT_connect ("fs", pc->h->cfg); if (NULL == client) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Can not index file `%s': %s. Will try to insert instead.\n"), p->filename, _("could not connect to `fs' service")); p->data.file.do_index = GNUNET_NO; publish_content (pc); GNUNET_free (fn); return; } if (p->data.file.have_hash != GNUNET_YES) { p->data.file.file_id = *res; p->data.file.have_hash = GNUNET_YES; GNUNET_FS_file_information_sync_ (p); } ism = GNUNET_malloc (sizeof (struct IndexStartMessage) + slen); ism->header.size = htons (sizeof (struct IndexStartMessage) + slen); ism->header.type = htons (GNUNET_MESSAGE_TYPE_FS_INDEX_START); if (GNUNET_OK == GNUNET_DISK_file_get_identifiers (p->filename, &dev, &ino)) { ism->device = GNUNET_htonll (dev); ism->inode = GNUNET_htonll (ino); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Failed to get file identifiers for `%s'\n"), p->filename); } ism->file_id = *res; memcpy (&ism[1], fn, slen); GNUNET_free (fn); pc->client = client; GNUNET_break (GNUNET_YES == GNUNET_CLIENT_transmit_and_get_response (client, &ism->header, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &process_index_start_response, pc)); GNUNET_free (ism); } /** * Main function that performs the upload. * * @param cls "struct GNUNET_FS_PublishContext" identifies the upload * @param tc task context */ void GNUNET_FS_publish_main_ (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FS_PublishContext *pc = cls; struct GNUNET_FS_ProgressInfo pi; struct GNUNET_FS_FileInformation *p; struct GNUNET_FS_Uri *loc; char *fn; pc->upload_task = GNUNET_SCHEDULER_NO_TASK; p = pc->fi_pos; if (NULL == p) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing complete, now publishing SKS and KSK blocks.\n"); /* upload of entire hierarchy complete, * publish namespace entries */ GNUNET_FS_publish_sync_ (pc); publish_sblock (pc); return; } /* find starting position */ while ((p->is_directory == GNUNET_YES) && (NULL != p->data.dir.entries) && (NULL == p->emsg) && (NULL == p->data.dir.entries->chk_uri)) { p = p->data.dir.entries; pc->fi_pos = p; GNUNET_FS_publish_sync_ (pc); } /* abort on error */ if (NULL != p->emsg) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error uploading: %s\n", p->emsg); /* error with current file, abort all * related files as well! */ while (NULL != p->dir) { fn = GNUNET_CONTAINER_meta_data_get_by_type (p->meta, EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME); p = p->dir; if (fn != NULL) { GNUNET_asprintf (&p->emsg, _("Recursive upload failed at `%s': %s"), fn, p->emsg); GNUNET_free (fn); } else { GNUNET_asprintf (&p->emsg, _("Recursive upload failed: %s"), p->emsg); } pi.status = GNUNET_FS_STATUS_PUBLISH_ERROR; pi.value.publish.eta = GNUNET_TIME_UNIT_FOREVER_REL; pi.value.publish.specifics.error.message = p->emsg; p->client_info = GNUNET_FS_publish_make_status_ (&pi, pc, p, 0); } pc->all_done = GNUNET_YES; GNUNET_FS_publish_sync_ (pc); return; } /* handle completion */ if (NULL != p->chk_uri) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "File upload complete, now publishing KSK blocks.\n"); if (0 == p->bo.anonymity_level) { /* zero anonymity, box CHK URI in LOC URI */ loc = GNUNET_FS_uri_loc_create (p->chk_uri, pc->h->cfg, p->bo.expiration_time); GNUNET_FS_uri_destroy (p->chk_uri); p->chk_uri = loc; } GNUNET_FS_publish_sync_ (pc); /* upload of "p" complete, publish KBlocks! */ if (p->keywords != NULL) { pc->ksk_pc = GNUNET_FS_publish_ksk (pc->h, p->keywords, p->meta, p->chk_uri, &p->bo, pc->options, &publish_kblocks_cont, pc); } else { publish_kblocks_cont (pc, p->chk_uri, NULL); } return; } if ((p->is_directory != GNUNET_YES) && (p->data.file.do_index)) { if (NULL == p->filename) { p->data.file.do_index = GNUNET_NO; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Can not index file `%s': %s. Will try to insert instead.\n"), "", _("needs to be an actual file")); GNUNET_FS_file_information_sync_ (p); publish_content (pc); return; } if (p->data.file.have_hash) { hash_for_index_cb (pc, &p->data.file.file_id); } else { p->start_time = GNUNET_TIME_absolute_get (); pc->fhc = GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE, p->filename, HASHING_BLOCKSIZE, &hash_for_index_cb, pc); } return; } publish_content (pc); } /** * Signal the FS's progress function that we are starting * an upload. * * @param cls closure (of type "struct GNUNET_FS_PublishContext*") * @param fi the entry in the publish-structure * @param length length of the file or directory * @param meta metadata for the file or directory (can be modified) * @param uri pointer to the keywords that will be used for this entry (can be modified) * @param bo block options * @param do_index should we index? * @param client_info pointer to client context set upon creation (can be modified) * @return GNUNET_OK to continue (always) */ static int fip_signal_start (void *cls, struct GNUNET_FS_FileInformation *fi, uint64_t length, struct GNUNET_CONTAINER_MetaData *meta, struct GNUNET_FS_Uri **uri, struct GNUNET_FS_BlockOptions *bo, int *do_index, void **client_info) { struct GNUNET_FS_PublishContext *pc = cls; struct GNUNET_FS_ProgressInfo pi; unsigned int kc; uint64_t left; if (GNUNET_YES == pc->skip_next_fi_callback) { pc->skip_next_fi_callback = GNUNET_NO; return GNUNET_OK; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting publish operation\n"); if (*do_index) { /* space for on-demand blocks */ pc->reserve_space += ((length + DBLOCK_SIZE - 1) / DBLOCK_SIZE) * sizeof (struct OnDemandBlock); } else { /* space for DBlocks */ pc->reserve_space += length; } /* entries for IBlocks and DBlocks, space for IBlocks */ left = length; while (1) { left = (left + DBLOCK_SIZE - 1) / DBLOCK_SIZE; pc->reserve_entries += left; if (left <= 1) break; left = left * sizeof (struct ContentHashKey); pc->reserve_space += left; } pc->reserve_entries++; /* entries and space for keywords */ if (NULL != *uri) { kc = GNUNET_FS_uri_ksk_get_keyword_count (*uri); pc->reserve_entries += kc; pc->reserve_space += GNUNET_SERVER_MAX_MESSAGE_SIZE * kc; } pi.status = GNUNET_FS_STATUS_PUBLISH_START; *client_info = GNUNET_FS_publish_make_status_ (&pi, pc, fi, 0); GNUNET_FS_file_information_sync_ (fi); if ((fi->is_directory) && (fi->dir != NULL)) { /* We are a directory, and we are not top-level; process entries in directory */ pc->skip_next_fi_callback = GNUNET_YES; GNUNET_FS_file_information_inspect (fi, &fip_signal_start, pc); } return GNUNET_OK; } /** * Signal the FS's progress function that we are suspending * an upload. * * @param cls closure (of type "struct GNUNET_FS_PublishContext*") * @param fi the entry in the publish-structure * @param length length of the file or directory * @param meta metadata for the file or directory (can be modified) * @param uri pointer to the keywords that will be used for this entry (can be modified) * @param bo block options * @param do_index should we index? * @param client_info pointer to client context set upon creation (can be modified) * @return GNUNET_OK to continue (always) */ static int fip_signal_suspend (void *cls, struct GNUNET_FS_FileInformation *fi, uint64_t length, struct GNUNET_CONTAINER_MetaData *meta, struct GNUNET_FS_Uri **uri, struct GNUNET_FS_BlockOptions *bo, int *do_index, void **client_info) { struct GNUNET_FS_PublishContext *pc = cls; struct GNUNET_FS_ProgressInfo pi; uint64_t off; if (GNUNET_YES == pc->skip_next_fi_callback) { pc->skip_next_fi_callback = GNUNET_NO; return GNUNET_OK; } if (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (meta)) { /* process entries in directory */ pc->skip_next_fi_callback = GNUNET_YES; GNUNET_FS_file_information_inspect (fi, &fip_signal_suspend, pc); } if (NULL != pc->ksk_pc) { GNUNET_FS_publish_ksk_cancel (pc->ksk_pc); pc->ksk_pc = NULL; } if (NULL != pc->sks_pc) { GNUNET_FS_publish_sks_cancel (pc->sks_pc); pc->sks_pc = NULL; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Suspending publish operation\n"); GNUNET_free_non_null (fi->serialization); fi->serialization = NULL; off = (fi->chk_uri == NULL) ? 0 : length; pi.status = GNUNET_FS_STATUS_PUBLISH_SUSPEND; GNUNET_break (NULL == GNUNET_FS_publish_make_status_ (&pi, pc, fi, off)); *client_info = NULL; if (NULL != pc->qre) { GNUNET_DATASTORE_cancel (pc->qre); pc->qre = NULL; } if (NULL != pc->dsh) { GNUNET_DATASTORE_disconnect (pc->dsh, GNUNET_NO); pc->dsh = NULL; } pc->rid = 0; return GNUNET_OK; } /** * Create SUSPEND event for the given publish operation * and then clean up our state (without stop signal). * * @param cls the 'struct GNUNET_FS_PublishContext' to signal for */ void GNUNET_FS_publish_signal_suspend_ (void *cls) { struct GNUNET_FS_PublishContext *pc = cls; if (GNUNET_SCHEDULER_NO_TASK != pc->upload_task) { GNUNET_SCHEDULER_cancel (pc->upload_task); pc->upload_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_FS_file_information_inspect (pc->fi, &fip_signal_suspend, pc); GNUNET_FS_end_top (pc->h, pc->top); pc->top = NULL; publish_cleanup (pc); } /** * We have gotten a reply for our space reservation request. * Either fail (insufficient space) or start publishing for good. * * @param cls the 'struct GNUNET_FS_PublishContext*' * @param success positive reservation ID on success * @param min_expiration minimum expiration time required for content to be stored * @param msg error message on error, otherwise NULL */ static void finish_reserve (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) { struct GNUNET_FS_PublishContext *pc = cls; pc->qre = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Reservation complete (%d)!\n", success); if ((msg != NULL) || (success <= 0)) { GNUNET_asprintf (&pc->fi->emsg, _("Insufficient space for publishing: %s"), msg); signal_publish_error (pc->fi, pc, pc->fi->emsg); return; } pc->rid = success; GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == pc->upload_task); pc->upload_task = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, &GNUNET_FS_publish_main_, pc); } /** * Publish a file or directory. * * @param h handle to the file sharing subsystem * @param fi information about the file or directory structure to publish * @param namespace namespace to publish the file in, NULL for no namespace * @param nid identifier to use for the publishd content in the namespace * (can be NULL, must be NULL if namespace is NULL) * @param nuid update-identifier that will be used for future updates * (can be NULL, must be NULL if namespace or nid is NULL) * @param options options for the publication * @return context that can be used to control the publish operation */ struct GNUNET_FS_PublishContext * GNUNET_FS_publish_start (struct GNUNET_FS_Handle *h, struct GNUNET_FS_FileInformation *fi, struct GNUNET_FS_Namespace *namespace, const char *nid, const char *nuid, enum GNUNET_FS_PublishOptions options) { struct GNUNET_FS_PublishContext *ret; struct GNUNET_DATASTORE_Handle *dsh; GNUNET_assert (NULL != h); if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) { dsh = GNUNET_DATASTORE_connect (h->cfg); if (NULL == dsh) return NULL; } else { dsh = NULL; } ret = GNUNET_malloc (sizeof (struct GNUNET_FS_PublishContext)); ret->dsh = dsh; ret->h = h; ret->fi = fi; ret->namespace = namespace; ret->options = options; if (namespace != NULL) { namespace->rc++; GNUNET_assert (NULL != nid); ret->nid = GNUNET_strdup (nid); if (NULL != nuid) ret->nuid = GNUNET_strdup (nuid); } /* signal start */ GNUNET_FS_file_information_inspect (ret->fi, &fip_signal_start, ret); ret->fi_pos = ret->fi; ret->top = GNUNET_FS_make_top (h, &GNUNET_FS_publish_signal_suspend_, ret); GNUNET_FS_publish_sync_ (ret); if (NULL != ret->dsh) { GNUNET_assert (NULL == ret->qre); GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Reserving space for %u entries and %llu bytes for publication\n"), (unsigned int) ret->reserve_entries, (unsigned long long) ret->reserve_space); ret->qre = GNUNET_DATASTORE_reserve (ret->dsh, ret->reserve_space, ret->reserve_entries, UINT_MAX, UINT_MAX, GNUNET_TIME_UNIT_FOREVER_REL, &finish_reserve, ret); } else { GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == ret->upload_task); ret->upload_task = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_BACKGROUND, &GNUNET_FS_publish_main_, ret); } return ret; } /** * Signal the FS's progress function that we are stopping * an upload. * * @param cls closure (of type "struct GNUNET_FS_PublishContext*") * @param fi the entry in the publish-structure * @param length length of the file or directory * @param meta metadata for the file or directory (can be modified) * @param uri pointer to the keywords that will be used for this entry (can be modified) * @param bo block options (can be modified) * @param do_index should we index? * @param client_info pointer to client context set upon creation (can be modified) * @return GNUNET_OK to continue (always) */ static int fip_signal_stop (void *cls, struct GNUNET_FS_FileInformation *fi, uint64_t length, struct GNUNET_CONTAINER_MetaData *meta, struct GNUNET_FS_Uri **uri, struct GNUNET_FS_BlockOptions *bo, int *do_index, void **client_info) { struct GNUNET_FS_PublishContext *pc = cls; struct GNUNET_FS_ProgressInfo pi; uint64_t off; if (GNUNET_YES == pc->skip_next_fi_callback) { pc->skip_next_fi_callback = GNUNET_NO; return GNUNET_OK; } if (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (meta)) { /* process entries in directory first */ pc->skip_next_fi_callback = GNUNET_YES; GNUNET_FS_file_information_inspect (fi, &fip_signal_stop, pc); } if (fi->serialization != NULL) { GNUNET_FS_remove_sync_file_ (pc->h, GNUNET_FS_SYNC_PATH_FILE_INFO, fi->serialization); GNUNET_free (fi->serialization); fi->serialization = NULL; } off = (fi->chk_uri == NULL) ? 0 : length; pi.status = GNUNET_FS_STATUS_PUBLISH_STOPPED; GNUNET_break (NULL == GNUNET_FS_publish_make_status_ (&pi, pc, fi, off)); *client_info = NULL; return GNUNET_OK; } /** * Stop an upload. Will abort incomplete uploads (but * not remove blocks that have already been publishd) or * simply clean up the state for completed uploads. * Must NOT be called from within the event callback! * * @param pc context for the upload to stop */ void GNUNET_FS_publish_stop (struct GNUNET_FS_PublishContext *pc) { struct GNUNET_FS_ProgressInfo pi; uint64_t off; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publish stop called\n"); GNUNET_FS_end_top (pc->h, pc->top); if (NULL != pc->ksk_pc) { GNUNET_FS_publish_ksk_cancel (pc->ksk_pc); pc->ksk_pc = NULL; } if (NULL != pc->sks_pc) { GNUNET_FS_publish_sks_cancel (pc->sks_pc); pc->sks_pc = NULL; } if (GNUNET_SCHEDULER_NO_TASK != pc->upload_task) { GNUNET_SCHEDULER_cancel (pc->upload_task); pc->upload_task = GNUNET_SCHEDULER_NO_TASK; } pc->skip_next_fi_callback = GNUNET_YES; GNUNET_FS_file_information_inspect (pc->fi, &fip_signal_stop, pc); if (pc->fi->serialization != NULL) { GNUNET_FS_remove_sync_file_ (pc->h, GNUNET_FS_SYNC_PATH_FILE_INFO, pc->fi->serialization); GNUNET_free (pc->fi->serialization); pc->fi->serialization = NULL; } off = (pc->fi->chk_uri == NULL) ? 0 : GNUNET_ntohll (pc->fi->chk_uri->data.chk.file_length); if (pc->serialization != NULL) { GNUNET_FS_remove_sync_file_ (pc->h, GNUNET_FS_SYNC_PATH_MASTER_PUBLISH, pc->serialization); GNUNET_free (pc->serialization); pc->serialization = NULL; } if (NULL != pc->qre) { GNUNET_DATASTORE_cancel (pc->qre); pc->qre = NULL; } pi.status = GNUNET_FS_STATUS_PUBLISH_STOPPED; GNUNET_break (NULL == GNUNET_FS_publish_make_status_ (&pi, pc, pc->fi, off)); publish_cleanup (pc); } /* end of fs_publish.c */ gnunet-0.9.3/src/fs/test_fs_test_lib.c0000644000175000017500000001015511760502551014647 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/test_fs_test_lib.c * @brief test fs test library * @author Christian Grothoff */ #include "platform.h" #include "fs_test_lib.h" #define VERBOSE GNUNET_NO /** * File-size we use for testing. */ #define FILESIZE (1024 * 1024 * 2) /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) #define NUM_DAEMONS 2 #define SEED 42 static struct GNUNET_FS_TestDaemon *daemons[NUM_DAEMONS]; static struct GNUNET_FS_TEST_ConnectContext *cc; static int ret; static void do_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (NULL != cc) { GNUNET_FS_TEST_daemons_connect_cancel (cc); cc = NULL; } if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) { GNUNET_break (0); ret = 1; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished download, shutting down\n", (unsigned long long) FILESIZE); } GNUNET_FS_TEST_daemons_stop (NUM_DAEMONS, daemons); } static void do_download (void *cls, const struct GNUNET_FS_Uri *uri) { if (NULL == uri) { GNUNET_break (0); GNUNET_SCHEDULER_add_now (&do_stop, NULL); ret = 1; return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Downloading %llu bytes\n", (unsigned long long) FILESIZE); GNUNET_FS_TEST_download (daemons[0], TIMEOUT, 1, SEED, uri, VERBOSE, &do_stop, NULL); } static void do_publish (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { cc = NULL; if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) { GNUNET_break (0); ret = 1; GNUNET_SCHEDULER_add_now (&do_stop, NULL); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing %llu bytes\n", (unsigned long long) FILESIZE); GNUNET_FS_TEST_publish (daemons[0], TIMEOUT, 1, GNUNET_NO, FILESIZE, SEED, VERBOSE, &do_download, NULL); } static void do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) { GNUNET_break (0); ret = 1; GNUNET_SCHEDULER_add_now (&do_stop, NULL); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemons started, will now try to connect them\n"); cc = GNUNET_FS_TEST_daemons_connect (daemons[0], daemons[1], TIMEOUT, &do_publish, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { GNUNET_FS_TEST_daemons_start ("fs_test_lib_data.conf", TIMEOUT, NUM_DAEMONS, daemons, &do_connect, NULL); } int main (int argc, char *argv[]) { char *const argvx[] = { "test-fs-test-lib", "-c", "fs_test_lib_data.conf", NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/"); GNUNET_log_setup ("test_fs_test_lib", "WARNING", NULL); GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "test-fs-test-lib", "nohelp", options, &run, NULL); GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-lib/"); return ret; } /* end of test_fs_test_lib.c */ gnunet-0.9.3/src/fs/fs.conf.in0000644000175000017500000000142611760502552013035 00000000000000[fs] AUTOSTART = YES INDEXDB = $SERVICEHOME/fs/idxinfo.lst TRUST = $SERVICEHOME/fs/credit/ IDENTITY_DIR = $SERVICEHOME/fs/identities/ STATE_DIR = $SERVICEHOME/fs/persistence/ UPDATE_DIR = $SERVICEHOME/fs/updates/ @UNIXONLY@ PORT = 2094 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-fs ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DELAY = YES CONTENT_CACHING = YES CONTENT_PUSHING = YES UNIXPATH = /tmp/gnunet-service-fs.sock UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES # DEBUG = YES MAX_PENDING_REQUESTS = 65536 # Maximum frequency we're allowed to poll the datastore # for content for migration (can be used to reduce # GNUnet's disk-IO rate) MIN_MIGRATION_DELAY = 100 ms EXPECTED_NEIGHBOUR_COUNT = 128 # Enable monkey? PREFIX = @MONKEYPREFIX@ gnunet-0.9.3/src/fs/fs_tree.h0000644000175000017500000001567711760502551012765 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs_tree.h * @brief Merkle-tree-ish-CHK file encoding for GNUnet * @see https://gnunet.org/encoding * @author Krista Bennett * @author Christian Grothoff * * TODO: * - decide if this API should be made public (gnunet_fs_service.h) * or remain "internal" (but with exported symbols?) */ #ifndef GNUNET_FS_TREE_H #define GNUNET_FS_TREE_H #include "fs_api.h" /** * Compute the depth of the CHK tree. * * @param flen file length for which to compute the depth * @return depth of the tree, always > 0. A depth of 1 means only a DBLOCK. */ unsigned int GNUNET_FS_compute_depth (uint64_t flen); /** * Calculate how many bytes of payload a block tree of the given * depth MAY correspond to at most (this function ignores the fact that * some blocks will only be present partially due to the total file * size cutting some blocks off at the end). * * @param depth depth of the block. depth==0 is a DBLOCK. * @return number of bytes of payload a subtree of this depth may correspond to */ uint64_t GNUNET_FS_tree_compute_tree_size (unsigned int depth); /** * Compute how many bytes of data should be stored in * the specified block. * * @param fsize overall file size, must be > 0. * @param offset offset in the original data corresponding * to the beginning of the tree induced by the block; * must be < fsize * @param depth depth of the node in the tree, 0 for DBLOCK * @return number of bytes stored in this node */ size_t GNUNET_FS_tree_calculate_block_size (uint64_t fsize, uint64_t offset, unsigned int depth); /** * Context for an ECRS-based file encoder that computes * the Merkle-ish-CHK tree. */ struct GNUNET_FS_TreeEncoder; /** * Function called asking for the current (encoded) * block to be processed. After processing the * client should either call "GNUNET_FS_tree_encode_next" * or (on error) "GNUNET_FS_tree_encode_finish". * * @param cls closure * @param chk content hash key for the block * @param offset offset of the block * @param depth depth of the block, 0 for DBLOCKs * @param type type of the block (IBLOCK or DBLOCK) * @param block the (encrypted) block * @param block_size size of block (in bytes) */ typedef void (*GNUNET_FS_TreeBlockProcessor) (void *cls, const struct ContentHashKey * chk, uint64_t offset, unsigned int depth, enum GNUNET_BLOCK_Type type, const void *block, uint16_t block_size); /** * Function called with information about our * progress in computing the tree encoding. * * @param cls closure * @param offset where are we in the file * @param pt_block plaintext of the currently processed block * @param pt_size size of pt_block * @param depth depth of the block in the tree, 0 for DBLOCKS */ typedef void (*GNUNET_FS_TreeProgressCallback) (void *cls, uint64_t offset, const void *pt_block, size_t pt_size, unsigned int depth); /** * Initialize a tree encoder. This function will call "proc" and * "progress" on each block in the tree. Once all blocks have been * processed, "cont" will be scheduled. The "reader" will be called * to obtain the (plaintext) blocks for the file. Note that this * function will actually never call "proc"; the "proc" function must * be triggered by calling "GNUNET_FS_tree_encoder_next" to trigger * encryption (and calling of "proc") for each block. * * @param h the global FS context * @param size overall size of the file to encode * @param cls closure for reader, proc, progress and cont * @param reader function to call to read plaintext data * @param proc function to call on each encrypted block * @param progress function to call with progress information * @param cont function to call when done * @return tree encoder context */ struct GNUNET_FS_TreeEncoder * GNUNET_FS_tree_encoder_create (struct GNUNET_FS_Handle *h, uint64_t size, void *cls, GNUNET_FS_DataReader reader, GNUNET_FS_TreeBlockProcessor proc, GNUNET_FS_TreeProgressCallback progress, GNUNET_SCHEDULER_Task cont); /** * Encrypt the next block of the file (and * call proc and progress accordingly; or * of course "cont" if we have already completed * encoding of the entire file). * * @param te tree encoder to use */ void GNUNET_FS_tree_encoder_next (struct GNUNET_FS_TreeEncoder *te); /** * Clean up a tree encoder and return information * about the resulting URI or an error message. * * @param te the tree encoder to clean up * @param uri set to the resulting URI (if encoding finished) * @param emsg set to an error message (if an error occured * within the tree encoder; if this function is called * prior to completion and prior to an internal error, * both "*uri" and "*emsg" will be set to NULL). */ void GNUNET_FS_tree_encoder_finish (struct GNUNET_FS_TreeEncoder *te, struct GNUNET_FS_Uri **uri, char **emsg); #if 0 /* the functions below will be needed for persistence but are not yet implemented -- FIXME... */ /** * Get data that would be needed to resume * the encoding later. * * @param te encoding to resume * @param data set to the resume data * @param size set to the size of the resume data */ void GNUNET_FS_tree_encoder_resume_get_data (const struct GNUNET_FS_TreeEncoder *te, void **data, size_t * size); /** * Reset tree encoder to point previously * obtained for resuming. * * @param te encoding to resume * @param data the resume data * @param size the size of the resume data */ void GNUNET_FS_tree_encoder_resume (struct GNUNET_FS_TreeEncoder *te, const void *data, size_t size); #endif #endif /* end of fs_tree.h */ gnunet-0.9.3/src/fs/test_fs_defaults.conf0000644000175000017500000000207411725220336015354 00000000000000[PATHS] SERVICEHOME = /tmp/gnunet-test-fs-lib/ DEFAULTCONFIG = fs_test_lib_data.conf [gnunetd] HOSTKEY = $SERVICEHOME/.hostkey [resolver] PORT = 43464 HOSTNAME = localhost [transport] PORT = 43465 PLUGINS = tcp [nat] DISABLEV6 = YES ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 USE_LOCALADDR = NO [arm] PORT = 43466 HOSTNAME = localhost DEFAULTSERVICES = fs [datastore] QUOTA = 100 MB [statistics] PORT = 43467 HOSTNAME = localhost [transport-tcp] BINDTO = 127.0.0.1 PORT = 43468 [peerinfo] PORT = 43469 HOSTNAME = localhost [ats] WAN_QUOTA_IN = 65536 WAN_QUOTA_OUT = 65536 [core] PORT = 43470 HOSTNAME = localhost [fs] PORT = 43471 HOSTNAME = localhost CONTENT_CACHING = YES CONTENT_PUSHING = YES DELAY = YES [testing] WEAKRANDOM = YES HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat [dhtcache] QUOTA=65536 DATABASE=sqlite [mesh] AUTOSTART = NO [dns] AUTOSTART = NO [nse] AUTOSTART = NO [dv] AUTOSTART = NO [chat] AUTOSTART = NO [gns] AUTOSTART = NO [vpn] AUTOSTART = NO [namestore] AUTOSTART = NO gnunet-0.9.3/src/fs/fs_namespace_advertise.c0000644000175000017500000002170511760502551016010 00000000000000/* This file is part of GNUnet (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs_namespace_advertise.c * @brief advertise namespaces (creating NBlocks) * @author Christian Grothoff */ #include "platform.h" #include "gnunet_constants.h" #include "gnunet_signatures.h" #include "gnunet_util_lib.h" #include "gnunet_fs_service.h" #include "fs_api.h" /** * Maximum legal size for an nblock. */ #define MAX_NBLOCK_SIZE (60 * 1024) /** * Context for advertising a namespace. */ struct GNUNET_FS_AdvertisementContext { /** * Function to call with the result. */ GNUNET_FS_PublishContinuation cont; /** * Closure for cont. */ void *cont_cls; /** * Datastore handle. */ struct GNUNET_DATASTORE_Handle *dsh; /** * Our KSK URI. */ struct GNUNET_FS_Uri *ksk_uri; /** * Plaintext. */ char *pt; /** * NBlock to sign and store. */ struct NBlock *nb; /** * The namespace. */ struct GNUNET_FS_Namespace *ns; /** * Current datastore queue entry for advertising. */ struct GNUNET_DATASTORE_QueueEntry *dqe; /** * Block options. */ struct GNUNET_FS_BlockOptions bo; /** * Number of bytes of plaintext. */ size_t pt_size; /** * Current keyword offset. */ unsigned int pos; }; // FIXME: I see no good reason why this should need to be done // in a new task (anymore). Integrate with 'cancel' function below? /** * Disconnect from the datastore. * * @param cls datastore handle * @param tc scheduler context */ static void do_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_DATASTORE_Handle *dsh = cls; GNUNET_DATASTORE_disconnect (dsh, GNUNET_NO); } /** * Continuation called to notify client about result of the * operation. * * @param cls closure (our struct GNUNET_FS_AdvertismentContext) * @param success GNUNET_SYSERR on failure * @param min_expiration minimum expiration time required for content to be stored * @param msg NULL on success, otherwise an error message */ static void advertisement_cont (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg) { struct GNUNET_FS_AdvertisementContext *ac = cls; const char *keyword; GNUNET_HashCode key; GNUNET_HashCode query; struct GNUNET_CRYPTO_AesSessionKey skey; struct GNUNET_CRYPTO_AesInitializationVector iv; struct GNUNET_CRYPTO_RsaPrivateKey *pk; ac->dqe = NULL; if (GNUNET_SYSERR == success) { /* error! */ (void) GNUNET_SCHEDULER_add_now (&do_disconnect, ac->dsh); ac->dsh = NULL; if (msg == NULL) { GNUNET_break (0); msg = _("Unknown error"); } if (ac->cont != NULL) { ac->cont (ac->cont_cls, NULL, msg); ac->cont = NULL; } GNUNET_FS_namespace_advertise_cancel (ac); return; } if (ac->pos == ac->ksk_uri->data.ksk.keywordCount) { /* done! */ (void) GNUNET_SCHEDULER_add_now (&do_disconnect, ac->dsh); ac->dsh = NULL; if (ac->cont != NULL) { ac->cont (ac->cont_cls, ac->ksk_uri, NULL); ac->cont = NULL; } GNUNET_FS_namespace_advertise_cancel (ac); return; } keyword = ac->ksk_uri->data.ksk.keywords[ac->pos++]; /* first character of keyword indicates if it is * mandatory or not -- ignore for hashing */ GNUNET_CRYPTO_hash (&keyword[1], strlen (&keyword[1]), &key); GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv); GNUNET_CRYPTO_aes_encrypt (ac->pt, ac->pt_size, &skey, &iv, &ac->nb[1]); GNUNET_break (GNUNET_OK == GNUNET_CRYPTO_rsa_sign (ac->ns->key, &ac->nb->ns_purpose, &ac->nb->ns_signature)); pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&key); GNUNET_assert (pk != NULL); GNUNET_CRYPTO_rsa_key_get_public (pk, &ac->nb->keyspace); GNUNET_CRYPTO_hash (&ac->nb->keyspace, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &query); GNUNET_break (GNUNET_OK == GNUNET_CRYPTO_rsa_sign (pk, &ac->nb->ksk_purpose, &ac->nb->ksk_signature)); GNUNET_CRYPTO_rsa_key_free (pk); ac->dqe = GNUNET_DATASTORE_put (ac->dsh, 0 /* no reservation */ , &query, ac->pt_size + sizeof (struct NBlock), ac->nb, GNUNET_BLOCK_TYPE_FS_NBLOCK, ac->bo.content_priority, ac->bo.anonymity_level, ac->bo.replication_level, ac->bo.expiration_time, -2, 1, GNUNET_CONSTANTS_SERVICE_TIMEOUT, &advertisement_cont, ac); } /** * Publish an advertismement for a namespace. * * @param h handle to the file sharing subsystem * @param ksk_uri keywords to use for advertisment * @param namespace handle for the namespace that should be advertised * @param meta meta-data for the namespace advertisement * @param bo block options * @param rootEntry name of the root of the namespace * @param cont continuation * @param cont_cls closure for cont * @return NULL on error ('cont' is still called) */ struct GNUNET_FS_AdvertisementContext * GNUNET_FS_namespace_advertise (struct GNUNET_FS_Handle *h, struct GNUNET_FS_Uri *ksk_uri, struct GNUNET_FS_Namespace *namespace, const struct GNUNET_CONTAINER_MetaData *meta, const struct GNUNET_FS_BlockOptions *bo, const char *rootEntry, GNUNET_FS_PublishContinuation cont, void *cont_cls) { size_t reslen; size_t size; ssize_t mdsize; struct NBlock *nb; char *mdst; struct GNUNET_DATASTORE_Handle *dsh; struct GNUNET_FS_AdvertisementContext *ctx; char *pt; /* create advertisements */ mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta); if (-1 == mdsize) { cont (cont_cls, NULL, _("Failed to serialize meta data")); return NULL; } reslen = strlen (rootEntry) + 1; size = mdsize + sizeof (struct NBlock) + reslen; if (size > MAX_NBLOCK_SIZE) { size = MAX_NBLOCK_SIZE; mdsize = size - sizeof (struct NBlock) - reslen; } pt = GNUNET_malloc (mdsize + reslen); memcpy (pt, rootEntry, reslen); mdst = &pt[reslen]; mdsize = GNUNET_CONTAINER_meta_data_serialize (meta, &mdst, mdsize, GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); if (-1 == mdsize) { GNUNET_break (0); GNUNET_free (pt); cont (cont_cls, NULL, _("Failed to serialize meta data")); return NULL; } size = mdsize + sizeof (struct NBlock) + reslen; nb = GNUNET_malloc (size); GNUNET_CRYPTO_rsa_key_get_public (namespace->key, &nb->subspace); nb->ns_purpose.size = htonl (mdsize + reslen + sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); nb->ns_purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK); nb->ksk_purpose.size = htonl (size - sizeof (struct GNUNET_CRYPTO_RsaSignature)); nb->ksk_purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK_KSIG); dsh = GNUNET_DATASTORE_connect (h->cfg); if (NULL == dsh) { GNUNET_free (nb); GNUNET_free (pt); cont (cont_cls, NULL, _("Failed to connect to datastore service")); return NULL; } ctx = GNUNET_malloc (sizeof (struct GNUNET_FS_AdvertisementContext)); ctx->cont = cont; ctx->cont_cls = cont_cls; ctx->dsh = dsh; ctx->ksk_uri = GNUNET_FS_uri_dup (ksk_uri); ctx->nb = nb; ctx->pt = pt; ctx->pt_size = mdsize + reslen; ctx->ns = namespace; ctx->ns->rc++; ctx->bo = *bo; advertisement_cont (ctx, GNUNET_OK, GNUNET_TIME_UNIT_ZERO_ABS, NULL); return ctx; } /** * Abort the namespace advertisement operation. * * @param ac context of the operation to abort. */ void GNUNET_FS_namespace_advertise_cancel (struct GNUNET_FS_AdvertisementContext *ac) { if (NULL != ac->dqe) { GNUNET_DATASTORE_cancel (ac->dqe); ac->dqe = NULL; } if (NULL != ac->dsh) { GNUNET_DATASTORE_disconnect (ac->dsh, GNUNET_NO); ac->dsh = NULL; } GNUNET_FS_uri_destroy (ac->ksk_uri); GNUNET_free (ac->pt); GNUNET_free (ac->nb); GNUNET_FS_namespace_delete (ac->ns, GNUNET_NO); GNUNET_free (ac); } /* end of fs_namespace_advertise.c */ gnunet-0.9.3/src/fs/fs_download.c0000644000175000017500000022674011762443755013637 00000000000000/* This file is part of GNUnet. (C) 2001-2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs_download.c * @brief download methods * @author Christian Grothoff */ #include "platform.h" #include "gnunet_constants.h" #include "gnunet_fs_service.h" #include "fs_api.h" #include "fs_tree.h" /** * Determine if the given download (options and meta data) should cause * use to try to do a recursive download. */ static int is_recursive_download (struct GNUNET_FS_DownloadContext *dc) { return (0 != (dc->options & GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE)) && ((GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (dc->meta)) || ((NULL == dc->meta) && ((NULL == dc->filename) || ((strlen (dc->filename) >= strlen (GNUNET_FS_DIRECTORY_EXT)) && (NULL != strstr (dc->filename + strlen (dc->filename) - strlen (GNUNET_FS_DIRECTORY_EXT), GNUNET_FS_DIRECTORY_EXT)))))); } /** * We're storing the IBLOCKS after the DBLOCKS on disk (so that we * only have to truncate the file once we're done). * * Given the offset of a block (with respect to the DBLOCKS) and its * depth, return the offset where we would store this block in the * file. * * @param fsize overall file size * @param off offset of the block in the file * @param depth depth of the block in the tree, 0 for DBLOCK * @return off for DBLOCKS (depth == treedepth), * otherwise an offset past the end * of the file that does not overlap * with the range for any other block */ static uint64_t compute_disk_offset (uint64_t fsize, uint64_t off, unsigned int depth) { unsigned int i; uint64_t lsize; /* what is the size of all IBlocks for depth "i"? */ uint64_t loff; /* where do IBlocks for depth "i" start? */ unsigned int ioff; /* which IBlock corresponds to "off" at depth "i"? */ if (0 == depth) return off; /* first IBlocks start at the end of file, rounded up * to full DBLOCK_SIZE */ loff = ((fsize + DBLOCK_SIZE - 1) / DBLOCK_SIZE) * DBLOCK_SIZE; lsize = ((fsize + DBLOCK_SIZE - 1) / DBLOCK_SIZE) * sizeof (struct ContentHashKey); GNUNET_assert (0 == (off % DBLOCK_SIZE)); ioff = (off / DBLOCK_SIZE); for (i = 1; i < depth; i++) { loff += lsize; lsize = (lsize + CHK_PER_INODE - 1) / CHK_PER_INODE; GNUNET_assert (lsize > 0); GNUNET_assert (0 == (ioff % CHK_PER_INODE)); ioff /= CHK_PER_INODE; } return loff + ioff * sizeof (struct ContentHashKey); } /** * Fill in all of the generic fields for a download event and call the * callback. * * @param pi structure to fill in * @param dc overall download context */ void GNUNET_FS_download_make_status_ (struct GNUNET_FS_ProgressInfo *pi, struct GNUNET_FS_DownloadContext *dc) { pi->value.download.dc = dc; pi->value.download.cctx = dc->client_info; pi->value.download.pctx = (NULL == dc->parent) ? NULL : dc->parent->client_info; pi->value.download.sctx = (NULL == dc->search) ? NULL : dc->search->client_info; pi->value.download.uri = dc->uri; pi->value.download.filename = dc->filename; pi->value.download.size = dc->length; /* FIXME: Fix duration calculation to account for pauses */ pi->value.download.duration = GNUNET_TIME_absolute_get_duration (dc->start_time); pi->value.download.completed = dc->completed; pi->value.download.anonymity = dc->anonymity; pi->value.download.eta = GNUNET_TIME_calculate_eta (dc->start_time, dc->completed, dc->length); pi->value.download.is_active = (NULL == dc->client) ? GNUNET_NO : GNUNET_YES; if (0 == (dc->options & GNUNET_FS_DOWNLOAD_IS_PROBE)) dc->client_info = dc->h->upcb (dc->h->upcb_cls, pi); else dc->client_info = GNUNET_FS_search_probe_progress_ (NULL, pi); } /** * We're ready to transmit a search request to the * file-sharing service. Do it. If there is * more than one request pending, try to send * multiple or request another transmission. * * @param cls closure * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_download_request (void *cls, size_t size, void *buf); /** * Closure for iterator processing results. */ struct ProcessResultClosure { /** * Hash of data. */ GNUNET_HashCode query; /** * Data found in P2P network. */ const void *data; /** * Our download context. */ struct GNUNET_FS_DownloadContext *dc; /** * Number of bytes in data. */ size_t size; /** * Type of data. */ enum GNUNET_BLOCK_Type type; /** * Flag to indicate if this block should be stored on disk. */ int do_store; /** * When did we last transmit the request? */ struct GNUNET_TIME_Absolute last_transmission; }; /** * Iterator over entries in the pending requests in the 'active' map for the * reply that we just got. * * @param cls closure (our 'struct ProcessResultClosure') * @param key query for the given value / request * @param value value in the hash map (a 'struct DownloadRequest') * @return GNUNET_YES (we should continue to iterate); unless serious error */ static int process_result_with_request (void *cls, const GNUNET_HashCode * key, void *value); /** * We've found a matching block without downloading it. * Encrypt it and pass it to our "receive" function as * if we had received it from the network. * * @param dc download in question * @param chk request this relates to * @param dr request details * @param block plaintext data matching request * @param len number of bytes in block * @param do_store should we still store the block on disk? * @return GNUNET_OK on success */ static int encrypt_existing_match (struct GNUNET_FS_DownloadContext *dc, const struct ContentHashKey *chk, struct DownloadRequest *dr, const char *block, size_t len, int do_store) { struct ProcessResultClosure prc; char enc[len]; struct GNUNET_CRYPTO_AesSessionKey sk; struct GNUNET_CRYPTO_AesInitializationVector iv; GNUNET_HashCode query; GNUNET_CRYPTO_hash_to_aes_key (&chk->key, &sk, &iv); if (-1 == GNUNET_CRYPTO_aes_encrypt (block, len, &sk, &iv, enc)) { GNUNET_break (0); return GNUNET_SYSERR; } GNUNET_CRYPTO_hash (enc, len, &query); if (0 != memcmp (&query, &chk->query, sizeof (GNUNET_HashCode))) { GNUNET_break_op (0); return GNUNET_SYSERR; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Matching %u byte block for `%s' at offset %llu already present, no need for download!\n", (unsigned int) len, dc->filename, (unsigned long long) dr->offset); /* already got it! */ prc.dc = dc; prc.data = enc; prc.size = len; prc.type = (0 == dr->depth) ? GNUNET_BLOCK_TYPE_FS_DBLOCK : GNUNET_BLOCK_TYPE_FS_IBLOCK; prc.query = chk->query; prc.do_store = do_store; prc.last_transmission = GNUNET_TIME_UNIT_FOREVER_ABS; process_result_with_request (&prc, &chk->key, dr); return GNUNET_OK; } /** * We've lost our connection with the FS service. * Re-establish it and re-transmit all of our * pending requests. * * @param dc download context that is having trouble */ static void try_reconnect (struct GNUNET_FS_DownloadContext *dc); /** * We found an entry in a directory. Check if the respective child * already exists and if not create the respective child download. * * @param cls the parent download * @param filename name of the file in the directory * @param uri URI of the file (CHK or LOC) * @param meta meta data of the file * @param length number of bytes in data * @param data contents of the file (or NULL if they were not inlined) */ static void trigger_recursive_download (void *cls, const char *filename, const struct GNUNET_FS_Uri *uri, const struct GNUNET_CONTAINER_MetaData *meta, size_t length, const void *data); /** * We're done downloading a directory. Open the file and * trigger all of the (remaining) child downloads. * * @param dc context of download that just completed */ static void full_recursive_download (struct GNUNET_FS_DownloadContext *dc) { size_t size; uint64_t size64; void *data; struct GNUNET_DISK_FileHandle *h; struct GNUNET_DISK_MapHandle *m; size64 = GNUNET_FS_uri_chk_get_file_size (dc->uri); size = (size_t) size64; if (size64 != (uint64_t) size) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Recursive downloads of directories larger than 4 GB are not supported on 32-bit systems\n")); return; } if (NULL != dc->filename) { h = GNUNET_DISK_file_open (dc->filename, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); } else { GNUNET_assert (NULL != dc->temp_filename); h = GNUNET_DISK_file_open (dc->temp_filename, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); } if (NULL == h) return; /* oops */ data = GNUNET_DISK_file_map (h, &m, GNUNET_DISK_MAP_TYPE_READ, size); if (NULL == data) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Directory too large for system address space\n")); } else { GNUNET_FS_directory_list_contents (size, data, 0, &trigger_recursive_download, dc); GNUNET_DISK_file_unmap (m); } GNUNET_DISK_file_close (h); if (NULL == dc->filename) { if (0 != UNLINK (dc->temp_filename)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", dc->temp_filename); GNUNET_free (dc->temp_filename); dc->temp_filename = NULL; } } /** * Check if all child-downloads have completed (or trigger them if * necessary) and once we're completely done, signal completion (and * possibly recurse to parent). This function MUST be called when the * download of a file itself is done or when the download of a file is * done and then later a direct child download has completed (and * hence this download may complete itself). * * @param dc download to check for completion of children */ static void check_completed (struct GNUNET_FS_DownloadContext *dc) { struct GNUNET_FS_ProgressInfo pi; struct GNUNET_FS_DownloadContext *pos; /* first, check if we need to download children */ if ((NULL == dc->child_head) && (is_recursive_download (dc))) full_recursive_download (dc); /* then, check if children are done already */ for (pos = dc->child_head; NULL != pos; pos = pos->next) { if ((pos->emsg == NULL) && (pos->completed < pos->length)) return; /* not done yet */ if ((pos->child_head != NULL) && (pos->has_finished != GNUNET_YES)) return; /* not transitively done yet */ } /* All of our children are done, so mark this download done */ dc->has_finished = GNUNET_YES; if (NULL != dc->job_queue) { GNUNET_FS_dequeue_ (dc->job_queue); dc->job_queue = NULL; } if (GNUNET_SCHEDULER_NO_TASK != dc->task) { GNUNET_SCHEDULER_cancel (dc->task); dc->task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != dc->rfh) { GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (dc->rfh)); dc->rfh = NULL; } GNUNET_FS_download_sync_ (dc); /* signal completion */ pi.status = GNUNET_FS_STATUS_DOWNLOAD_COMPLETED; GNUNET_FS_download_make_status_ (&pi, dc); /* let parent know */ if (NULL != dc->parent) check_completed (dc->parent); } /** * We got a block of plaintext data (from the meta data). * Try it for upward reconstruction of the data. On success, * the top-level block will move to state BRS_DOWNLOAD_UP. * * @param dc context for the download * @param dr download request to match against * @param data plaintext data, starting from the beginning of the file * @param data_len number of bytes in data */ static void try_match_block (struct GNUNET_FS_DownloadContext *dc, struct DownloadRequest *dr, const char *data, size_t data_len) { struct GNUNET_FS_ProgressInfo pi; unsigned int i; char enc[DBLOCK_SIZE]; struct ContentHashKey chks[CHK_PER_INODE]; struct ContentHashKey in_chk; struct GNUNET_CRYPTO_AesSessionKey sk; struct GNUNET_CRYPTO_AesInitializationVector iv; size_t dlen; struct DownloadRequest *drc; struct GNUNET_DISK_FileHandle *fh; int complete; const char *fn; const char *odata; size_t odata_len; odata = data; odata_len = data_len; if (BRS_DOWNLOAD_UP == dr->state) return; if (dr->depth > 0) { complete = GNUNET_YES; for (i = 0; i < dr->num_children; i++) { drc = dr->children[i]; try_match_block (dc, drc, data, data_len); if (drc->state != BRS_RECONSTRUCT_META_UP) complete = GNUNET_NO; else chks[i] = drc->chk; } if (GNUNET_YES != complete) return; data = (const char *) chks; dlen = dr->num_children * sizeof (struct ContentHashKey); } else { if (dr->offset > data_len) return; /* oops */ dlen = GNUNET_MIN (data_len - dr->offset, DBLOCK_SIZE); } GNUNET_CRYPTO_hash (&data[dr->offset], dlen, &in_chk.key); GNUNET_CRYPTO_hash_to_aes_key (&in_chk.key, &sk, &iv); if (-1 == GNUNET_CRYPTO_aes_encrypt (&data[dr->offset], dlen, &sk, &iv, enc)) { GNUNET_break (0); return; } GNUNET_CRYPTO_hash (enc, dlen, &in_chk.query); switch (dr->state) { case BRS_INIT: dr->chk = in_chk; dr->state = BRS_RECONSTRUCT_META_UP; break; case BRS_CHK_SET: if (0 != memcmp (&in_chk, &dr->chk, sizeof (struct ContentHashKey))) { /* other peer provided bogus meta data */ GNUNET_break_op (0); break; } /* write block to disk */ fn = (NULL != dc->filename) ? dc->filename : dc->temp_filename; fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_TRUNCATE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_GROUP_READ | GNUNET_DISK_PERM_OTHER_READ); if (NULL == fh) { GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", fn); GNUNET_asprintf (&dc->emsg, _("Failed to open file `%s' for writing"), fn); GNUNET_DISK_file_close (fh); dr->state = BRS_ERROR; pi.status = GNUNET_FS_STATUS_DOWNLOAD_ERROR; pi.value.download.specifics.error.message = dc->emsg; GNUNET_FS_download_make_status_ (&pi, dc); return; } if (data_len != GNUNET_DISK_file_write (fh, odata, odata_len)) { GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "write", fn); GNUNET_asprintf (&dc->emsg, _("Failed to open file `%s' for writing"), fn); GNUNET_DISK_file_close (fh); dr->state = BRS_ERROR; pi.status = GNUNET_FS_STATUS_DOWNLOAD_ERROR; pi.value.download.specifics.error.message = dc->emsg; GNUNET_FS_download_make_status_ (&pi, dc); return; } GNUNET_DISK_file_close (fh); /* signal success */ dr->state = BRS_DOWNLOAD_UP; dc->completed = dc->length; GNUNET_FS_download_sync_ (dc); pi.status = GNUNET_FS_STATUS_DOWNLOAD_PROGRESS; pi.value.download.specifics.progress.data = data; pi.value.download.specifics.progress.offset = 0; pi.value.download.specifics.progress.data_len = dlen; pi.value.download.specifics.progress.depth = 0; pi.value.download.specifics.progress.trust_offered = 0; pi.value.download.specifics.progress.block_download_duration = GNUNET_TIME_UNIT_ZERO; GNUNET_FS_download_make_status_ (&pi, dc); if ((NULL != dc->filename) && (0 != truncate (dc->filename, GNUNET_ntohll (dc->uri->data.chk.file_length)))) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "truncate", dc->filename); check_completed (dc); break; default: /* how did we get here? */ GNUNET_break (0); break; } } /** * Type of a function that libextractor calls for each * meta data item found. If we find full data meta data, * call 'try_match_block' on it. * * @param cls our 'struct GNUNET_FS_DownloadContext*' * @param plugin_name name of the plugin that produced this value; * special values can be used (i.e. '<zlib>' for zlib being * used in the main libextractor library and yielding * meta data). * @param type libextractor-type describing the meta data * @param format basic format information about data * @param data_mime_type mime-type of data (not of the original file); * can be NULL (if mime-type is not known) * @param data actual meta-data found * @param data_len number of bytes in data * @return 0 to continue extracting, 1 to abort */ static int match_full_data (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat format, const char *data_mime_type, const char *data, size_t data_len) { struct GNUNET_FS_DownloadContext *dc = cls; if (EXTRACTOR_METATYPE_GNUNET_FULL_DATA != type) return 0; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found %u bytes of FD!\n", (unsigned int) data_len); if (GNUNET_FS_uri_chk_get_file_size (dc->uri) != data_len) { GNUNET_break_op (0); return 1; /* bogus meta data */ } try_match_block (dc, dc->top_request, data, data_len); return 1; } /** * Set the state of the given download request to * BRS_DOWNLOAD_UP and propagate it up the tree. * * @param dr download request that is done */ static void propagate_up (struct DownloadRequest *dr) { unsigned int i; do { dr->state = BRS_DOWNLOAD_UP; dr = dr->parent; if (NULL == dr) break; for (i = 0; i < dr->num_children; i++) if (dr->children[i]->state != BRS_DOWNLOAD_UP) break; } while (i == dr->num_children); } /** * Try top-down reconstruction. Before, the given request node * must have the state BRS_CHK_SET. Afterwards, more nodes may * have that state or advanced to BRS_DOWNLOAD_DOWN or even * BRS_DOWNLOAD_UP. It is also possible to get BRS_ERROR on the * top level. * * @param dc overall download this block belongs to * @param dr block to reconstruct */ static void try_top_down_reconstruction (struct GNUNET_FS_DownloadContext *dc, struct DownloadRequest *dr) { uint64_t off; char block[DBLOCK_SIZE]; GNUNET_HashCode key; uint64_t total; size_t len; unsigned int i; struct DownloadRequest *drc; uint64_t child_block_size; const struct ContentHashKey *chks; int up_done; GNUNET_assert (NULL != dc->rfh); GNUNET_assert (BRS_CHK_SET == dr->state); total = GNUNET_FS_uri_chk_get_file_size (dc->uri); GNUNET_assert (dr->depth < dc->treedepth); len = GNUNET_FS_tree_calculate_block_size (total, dr->offset, dr->depth); GNUNET_assert (len <= DBLOCK_SIZE); off = compute_disk_offset (total, dr->offset, dr->depth); if (dc->old_file_size < off + len) return; /* failure */ if (off != GNUNET_DISK_file_seek (dc->rfh, off, GNUNET_DISK_SEEK_SET)) { GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "seek", dc->filename); return; /* failure */ } if (len != GNUNET_DISK_file_read (dc->rfh, block, len)) { GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "read", dc->filename); return; /* failure */ } GNUNET_CRYPTO_hash (block, len, &key); if (0 != memcmp (&key, &dr->chk.key, sizeof (GNUNET_HashCode))) return; /* mismatch */ if (GNUNET_OK != encrypt_existing_match (dc, &dr->chk, dr, block, len, GNUNET_NO)) { /* hash matches but encrypted block does not, really bad */ dr->state = BRS_ERROR; /* propagate up */ while (NULL != dr->parent) { dr = dr->parent; dr->state = BRS_ERROR; } return; } /* block matches */ dr->state = BRS_DOWNLOAD_DOWN; /* set CHKs for children */ up_done = GNUNET_YES; chks = (const struct ContentHashKey *) block; for (i = 0; i < dr->num_children; i++) { drc = dr->children[i]; GNUNET_assert (drc->offset >= dr->offset); child_block_size = GNUNET_FS_tree_compute_tree_size (drc->depth); GNUNET_assert (0 == (drc->offset - dr->offset) % child_block_size); if (BRS_INIT == drc->state) { drc->state = BRS_CHK_SET; drc->chk = chks[drc->chk_idx]; try_top_down_reconstruction (dc, drc); } if (BRS_DOWNLOAD_UP != drc->state) up_done = GNUNET_NO; /* children not all done */ } if (GNUNET_YES == up_done) propagate_up (dr); /* children all done (or no children...) */ } /** * Schedule the download of the specified block in the tree. * * @param dc overall download this block belongs to * @param dr request to schedule */ static void schedule_block_download (struct GNUNET_FS_DownloadContext *dc, struct DownloadRequest *dr) { unsigned int i; switch (dr->state) { case BRS_INIT: GNUNET_assert (0); break; case BRS_RECONSTRUCT_DOWN: GNUNET_assert (0); break; case BRS_RECONSTRUCT_META_UP: GNUNET_assert (0); break; case BRS_RECONSTRUCT_UP: GNUNET_assert (0); break; case BRS_CHK_SET: /* normal case, start download */ break; case BRS_DOWNLOAD_DOWN: for (i = 0; i < dr->num_children; i++) schedule_block_download (dc, dr->children[i]); return; case BRS_DOWNLOAD_UP: /* We're done! */ return; case BRS_ERROR: GNUNET_break (0); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scheduling download at offset %llu and depth %u for `%s'\n", (unsigned long long) dr->offset, dr->depth, GNUNET_h2s (&dr->chk.query)); if (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains_value (dc->active, &dr->chk.query, dr)) return; /* already active */ GNUNET_CONTAINER_multihashmap_put (dc->active, &dr->chk.query, dr, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); if (NULL == dc->client) return; /* download not active */ GNUNET_CONTAINER_DLL_insert (dc->pending_head, dc->pending_tail, dr); dr->is_pending = GNUNET_YES; if (NULL == dc->th) dc->th = GNUNET_CLIENT_notify_transmit_ready (dc->client, sizeof (struct SearchMessage), GNUNET_CONSTANTS_SERVICE_TIMEOUT, GNUNET_NO, &transmit_download_request, dc); } #define GNUNET_FS_URI_CHK_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_CHK_INFIX /** * We found an entry in a directory. Check if the respective child * already exists and if not create the respective child download. * * @param cls the parent download * @param filename name of the file in the directory * @param uri URI of the file (CHK or LOC) * @param meta meta data of the file * @param length number of bytes in data * @param data contents of the file (or NULL if they were not inlined) */ static void trigger_recursive_download (void *cls, const char *filename, const struct GNUNET_FS_Uri *uri, const struct GNUNET_CONTAINER_MetaData *meta, size_t length, const void *data) { struct GNUNET_FS_DownloadContext *dc = cls; struct GNUNET_FS_DownloadContext *cpos; char *temp_name; char *fn; char *us; char *ext; char *dn; char *pos; char *full_name; char *sfn; if (NULL == uri) return; /* entry for the directory itself */ cpos = dc->child_head; while (NULL != cpos) { if ((GNUNET_FS_uri_test_equal (uri, cpos->uri)) || ((NULL != filename) && (0 == strcmp (cpos->filename, filename)))) break; cpos = cpos->next; } if (NULL != cpos) return; /* already exists */ fn = NULL; if (NULL == filename) { fn = GNUNET_FS_meta_data_suggest_filename (meta); if (NULL == fn) { us = GNUNET_FS_uri_to_string (uri); fn = GNUNET_strdup (&us[strlen (GNUNET_FS_URI_CHK_PREFIX)]); GNUNET_free (us); } else if ('.' == fn[0]) { ext = fn; us = GNUNET_FS_uri_to_string (uri); GNUNET_asprintf (&fn, "%s%s", &us[strlen (GNUNET_FS_URI_CHK_PREFIX)], ext); GNUNET_free (ext); GNUNET_free (us); } /* change '\' to '/' (this should have happened * during insertion, but malicious peers may * not have done this) */ while (NULL != (pos = strstr (fn, "\\"))) *pos = '/'; /* remove '../' everywhere (again, well-behaved * peers don't do this, but don't trust that * we did not get something nasty) */ while (NULL != (pos = strstr (fn, "../"))) { pos[0] = '_'; pos[1] = '_'; pos[2] = '_'; } filename = fn; } if (NULL == dc->filename) { full_name = NULL; } else { dn = GNUNET_strdup (dc->filename); GNUNET_break ((strlen (dn) >= strlen (GNUNET_FS_DIRECTORY_EXT)) && (NULL != strstr (dn + strlen (dn) - strlen (GNUNET_FS_DIRECTORY_EXT), GNUNET_FS_DIRECTORY_EXT))); sfn = GNUNET_strdup (filename); while ((strlen (sfn) > 0) && ('/' == filename[strlen (sfn) - 1])) sfn[strlen (sfn) - 1] = '\0'; if ((strlen (dn) >= strlen (GNUNET_FS_DIRECTORY_EXT)) && (NULL != strstr (dn + strlen (dn) - strlen (GNUNET_FS_DIRECTORY_EXT), GNUNET_FS_DIRECTORY_EXT))) dn[strlen (dn) - strlen (GNUNET_FS_DIRECTORY_EXT)] = '\0'; if ((GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (meta)) && ((strlen (filename) < strlen (GNUNET_FS_DIRECTORY_EXT)) || (NULL == strstr (filename + strlen (filename) - strlen (GNUNET_FS_DIRECTORY_EXT), GNUNET_FS_DIRECTORY_EXT)))) { GNUNET_asprintf (&full_name, "%s%s%s%s", dn, DIR_SEPARATOR_STR, sfn, GNUNET_FS_DIRECTORY_EXT); } else { GNUNET_asprintf (&full_name, "%s%s%s", dn, DIR_SEPARATOR_STR, sfn); } GNUNET_free (sfn); GNUNET_free (dn); } if ((NULL != full_name) && (GNUNET_OK != GNUNET_DISK_directory_create_for_file (full_name))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Failed to create directory for recursive download of `%s'\n"), full_name); GNUNET_free (full_name); GNUNET_free_non_null (fn); return; } temp_name = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Triggering recursive download of size %llu with %u bytes MD\n", (unsigned long long) GNUNET_FS_uri_chk_get_file_size (uri), (unsigned int) GNUNET_CONTAINER_meta_data_get_serialized_size (meta)); GNUNET_FS_download_start (dc->h, uri, meta, full_name, temp_name, 0, GNUNET_FS_uri_chk_get_file_size (uri), dc->anonymity, dc->options, NULL, dc); GNUNET_free_non_null (full_name); GNUNET_free_non_null (temp_name); GNUNET_free_non_null (fn); } /** * (recursively) free download request structure * * @param dr request to free */ void GNUNET_FS_free_download_request_ (struct DownloadRequest *dr) { unsigned int i; if (NULL == dr) return; for (i = 0; i < dr->num_children; i++) GNUNET_FS_free_download_request_ (dr->children[i]); GNUNET_free_non_null (dr->children); GNUNET_free (dr); } /** * Iterator over entries in the pending requests in the 'active' map for the * reply that we just got. * * @param cls closure (our 'struct ProcessResultClosure') * @param key query for the given value / request * @param value value in the hash map (a 'struct DownloadRequest') * @return GNUNET_YES (we should continue to iterate); unless serious error */ static int process_result_with_request (void *cls, const GNUNET_HashCode * key, void *value) { struct ProcessResultClosure *prc = cls; struct DownloadRequest *dr = value; struct GNUNET_FS_DownloadContext *dc = prc->dc; struct DownloadRequest *drc; struct GNUNET_DISK_FileHandle *fh = NULL; struct GNUNET_CRYPTO_AesSessionKey skey; struct GNUNET_CRYPTO_AesInitializationVector iv; char pt[prc->size]; struct GNUNET_FS_ProgressInfo pi; uint64_t off; size_t bs; size_t app; int i; struct ContentHashKey *chkarr; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received %u byte block `%s' matching pending request at depth %u and offset %llu/%llu\n", (unsigned int) prc->size, GNUNET_h2s (key), dr->depth, (unsigned long long) dr->offset, (unsigned long long) GNUNET_ntohll (dc->uri->data. chk.file_length)); bs = GNUNET_FS_tree_calculate_block_size (GNUNET_ntohll (dc->uri->data.chk.file_length), dr->offset, dr->depth); if (prc->size != bs) { GNUNET_asprintf (&dc->emsg, _ ("Internal error or bogus download URI (expected %u bytes at depth %u and offset %llu/%llu, got %u bytes)"), bs, dr->depth, (unsigned long long) dr->offset, (unsigned long long) GNUNET_ntohll (dc->uri->data. chk.file_length), prc->size); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s\n", dc->emsg); while (NULL != dr->parent) { dr->state = BRS_ERROR; dr = dr->parent; } dr->state = BRS_ERROR; goto signal_error; } (void) GNUNET_CONTAINER_multihashmap_remove (dc->active, &prc->query, dr); if (GNUNET_YES == dr->is_pending) { GNUNET_CONTAINER_DLL_remove (dc->pending_head, dc->pending_tail, dr); dr->is_pending = GNUNET_NO; } GNUNET_CRYPTO_hash_to_aes_key (&dr->chk.key, &skey, &iv); if (-1 == GNUNET_CRYPTO_aes_decrypt (prc->data, prc->size, &skey, &iv, pt)) { GNUNET_break (0); dc->emsg = GNUNET_strdup (_("internal error decrypting content")); goto signal_error; } off = compute_disk_offset (GNUNET_ntohll (dc->uri->data.chk.file_length), dr->offset, dr->depth); /* save to disk */ if ((GNUNET_YES == prc->do_store) && ((NULL != dc->filename) || (is_recursive_download (dc))) && ((dr->depth == dc->treedepth) || (0 == (dc->options & GNUNET_FS_DOWNLOAD_NO_TEMPORARIES)))) { fh = GNUNET_DISK_file_open (NULL != dc->filename ? dc->filename : dc->temp_filename, GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_CREATE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_GROUP_READ | GNUNET_DISK_PERM_OTHER_READ); if (NULL == fh) { GNUNET_asprintf (&dc->emsg, _("Download failed: could not open file `%s': %s"), dc->filename, STRERROR (errno)); goto signal_error; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Saving decrypted block to disk at offset %llu\n", (unsigned long long) off); if ((off != GNUNET_DISK_file_seek (fh, off, GNUNET_DISK_SEEK_SET))) { GNUNET_asprintf (&dc->emsg, _("Failed to seek to offset %llu in file `%s': %s"), (unsigned long long) off, dc->filename, STRERROR (errno)); goto signal_error; } if (prc->size != GNUNET_DISK_file_write (fh, pt, prc->size)) { GNUNET_asprintf (&dc->emsg, _ ("Failed to write block of %u bytes at offset %llu in file `%s': %s"), (unsigned int) prc->size, (unsigned long long) off, dc->filename, STRERROR (errno)); goto signal_error; } GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fh)); fh = NULL; } if (0 == dr->depth) { /* DBLOCK, update progress and try recursion if applicable */ app = prc->size; if (dr->offset < dc->offset) { /* starting offset begins in the middle of pt, * do not count first bytes as progress */ GNUNET_assert (app > (dc->offset - dr->offset)); app -= (dc->offset - dr->offset); } if (dr->offset + prc->size > dc->offset + dc->length) { /* end of block is after relevant range, * do not count last bytes as progress */ GNUNET_assert (app > (dr->offset + prc->size) - (dc->offset + dc->length)); app -= (dr->offset + prc->size) - (dc->offset + dc->length); } dc->completed += app; /* do recursive download if option is set and either meta data * says it is a directory or if no meta data is given AND filename * ends in '.gnd' (top-level case) */ if (is_recursive_download (dc)) GNUNET_FS_directory_list_contents (prc->size, pt, off, &trigger_recursive_download, dc); } GNUNET_assert (dc->completed <= dc->length); dr->state = BRS_DOWNLOAD_DOWN; pi.status = GNUNET_FS_STATUS_DOWNLOAD_PROGRESS; pi.value.download.specifics.progress.data = pt; pi.value.download.specifics.progress.offset = dr->offset; pi.value.download.specifics.progress.data_len = prc->size; pi.value.download.specifics.progress.depth = dr->depth; pi.value.download.specifics.progress.trust_offered = 0; if (prc->last_transmission.abs_value != GNUNET_TIME_UNIT_FOREVER_ABS.abs_value) pi.value.download.specifics.progress.block_download_duration = GNUNET_TIME_absolute_get_duration (prc->last_transmission); else pi.value.download.specifics.progress.block_download_duration = GNUNET_TIME_UNIT_ZERO; /* found locally */ GNUNET_FS_download_make_status_ (&pi, dc); if (0 == dr->depth) propagate_up (dr); if (dc->completed == dc->length) { /* download completed, signal */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download completed, truncating file to desired length %llu\n", (unsigned long long) GNUNET_ntohll (dc->uri->data. chk.file_length)); /* truncate file to size (since we store IBlocks at the end) */ if (NULL != dc->filename) { if (0 != truncate (dc->filename, GNUNET_ntohll (dc->uri->data.chk.file_length))) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "truncate", dc->filename); } GNUNET_assert (0 == dr->depth); check_completed (dc); } if (0 == dr->depth) { /* bottom of the tree, no child downloads possible, just sync */ GNUNET_FS_download_sync_ (dc); return GNUNET_YES; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Triggering downloads of children (this block was at depth %u and offset %llu)\n", dr->depth, (unsigned long long) dr->offset); GNUNET_assert (0 == (prc->size % sizeof (struct ContentHashKey))); chkarr = (struct ContentHashKey *) pt; for (i = dr->num_children - 1; i >= 0; i--) { drc = dr->children[i]; switch (drc->state) { case BRS_INIT: if ((drc->chk_idx + 1) * sizeof (struct ContentHashKey) > prc->size) { /* 'chkarr' does not have enough space for this chk_idx; internal error! */ GNUNET_break (0); dc->emsg = GNUNET_strdup (_("internal error decoding tree")); goto signal_error; } drc->chk = chkarr[drc->chk_idx]; drc->state = BRS_CHK_SET; if (GNUNET_YES == dc->issue_requests) schedule_block_download (dc, drc); break; case BRS_RECONSTRUCT_DOWN: GNUNET_assert (0); break; case BRS_RECONSTRUCT_META_UP: GNUNET_assert (0); break; case BRS_RECONSTRUCT_UP: GNUNET_assert (0); break; case BRS_CHK_SET: GNUNET_assert (0); break; case BRS_DOWNLOAD_DOWN: GNUNET_assert (0); break; case BRS_DOWNLOAD_UP: GNUNET_assert (0); break; case BRS_ERROR: GNUNET_assert (0); break; default: GNUNET_assert (0); break; } } GNUNET_FS_download_sync_ (dc); return GNUNET_YES; signal_error: if (NULL != fh) GNUNET_DISK_file_close (fh); pi.status = GNUNET_FS_STATUS_DOWNLOAD_ERROR; pi.value.download.specifics.error.message = dc->emsg; GNUNET_FS_download_make_status_ (&pi, dc); /* abort all pending requests */ if (NULL != dc->th) { GNUNET_CLIENT_notify_transmit_ready_cancel (dc->th); dc->th = NULL; } GNUNET_CLIENT_disconnect (dc->client); dc->in_receive = GNUNET_NO; dc->client = NULL; GNUNET_FS_free_download_request_ (dc->top_request); dc->top_request = NULL; GNUNET_CONTAINER_multihashmap_destroy (dc->active); dc->active = NULL; dc->pending_head = NULL; dc->pending_tail = NULL; GNUNET_FS_download_sync_ (dc); return GNUNET_NO; } /** * Process a download result. * * @param dc our download context * @param type type of the result * @param last_transmission when was this block requested the last time? (FOREVER if unknown/not applicable) * @param data the (encrypted) response * @param size size of data */ static void process_result (struct GNUNET_FS_DownloadContext *dc, enum GNUNET_BLOCK_Type type, struct GNUNET_TIME_Absolute last_transmission, const void *data, size_t size) { struct ProcessResultClosure prc; prc.dc = dc; prc.data = data; prc.size = size; prc.type = type; prc.do_store = GNUNET_YES; prc.last_transmission = last_transmission; GNUNET_CRYPTO_hash (data, size, &prc.query); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received result for query `%s' from `%s'-service\n", GNUNET_h2s (&prc.query), "FS"); GNUNET_CONTAINER_multihashmap_get_multiple (dc->active, &prc.query, &process_result_with_request, &prc); } /** * Type of a function to call when we receive a message * from the service. * * @param cls closure * @param msg message received, NULL on timeout or fatal error */ static void receive_results (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_FS_DownloadContext *dc = cls; const struct ClientPutMessage *cm; uint16_t msize; if ((NULL == msg) || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_FS_PUT) || (sizeof (struct ClientPutMessage) > ntohs (msg->size))) { GNUNET_break (NULL == msg); try_reconnect (dc); return; } msize = ntohs (msg->size); cm = (const struct ClientPutMessage *) msg; process_result (dc, ntohl (cm->type), GNUNET_TIME_absolute_ntoh (cm->last_transmission), &cm[1], msize - sizeof (struct ClientPutMessage)); if (NULL == dc->client) return; /* fatal error */ /* continue receiving */ GNUNET_CLIENT_receive (dc->client, &receive_results, dc, GNUNET_TIME_UNIT_FOREVER_REL); } /** * We're ready to transmit a search request to the * file-sharing service. Do it. If there is * more than one request pending, try to send * multiple or request another transmission. * * @param cls closure * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_download_request (void *cls, size_t size, void *buf) { struct GNUNET_FS_DownloadContext *dc = cls; size_t msize; struct SearchMessage *sm; struct DownloadRequest *dr; dc->th = NULL; if (NULL == buf) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting download request failed, trying to reconnect\n"); try_reconnect (dc); return 0; } GNUNET_assert (size >= sizeof (struct SearchMessage)); msize = 0; sm = buf; while ((NULL != (dr = dc->pending_head)) && (size >= msize + sizeof (struct SearchMessage))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting download request for `%s' to `%s'-service\n", GNUNET_h2s (&dr->chk.query), "FS"); memset (sm, 0, sizeof (struct SearchMessage)); sm->header.size = htons (sizeof (struct SearchMessage)); sm->header.type = htons (GNUNET_MESSAGE_TYPE_FS_START_SEARCH); if (0 != (dc->options & GNUNET_FS_DOWNLOAD_OPTION_LOOPBACK_ONLY)) sm->options = htonl (GNUNET_FS_SEARCH_OPTION_LOOPBACK_ONLY); else sm->options = htonl (GNUNET_FS_SEARCH_OPTION_NONE); if (0 == dr->depth) sm->type = htonl (GNUNET_BLOCK_TYPE_FS_DBLOCK); else sm->type = htonl (GNUNET_BLOCK_TYPE_FS_IBLOCK); sm->anonymity_level = htonl (dc->anonymity); sm->target = dc->target.hashPubKey; sm->query = dr->chk.query; GNUNET_CONTAINER_DLL_remove (dc->pending_head, dc->pending_tail, dr); dr->is_pending = GNUNET_NO; msize += sizeof (struct SearchMessage); sm++; } if (NULL != dc->pending_head) { dc->th = GNUNET_CLIENT_notify_transmit_ready (dc->client, sizeof (struct SearchMessage), GNUNET_CONSTANTS_SERVICE_TIMEOUT, GNUNET_NO, &transmit_download_request, dc); GNUNET_assert (NULL != dc->th); } if (GNUNET_NO == dc->in_receive) { dc->in_receive = GNUNET_YES; GNUNET_CLIENT_receive (dc->client, &receive_results, dc, GNUNET_TIME_UNIT_FOREVER_REL); } return msize; } /** * Reconnect to the FS service and transmit our queries NOW. * * @param cls our download context * @param tc unused */ static void do_reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FS_DownloadContext *dc = cls; struct GNUNET_CLIENT_Connection *client; dc->task = GNUNET_SCHEDULER_NO_TASK; client = GNUNET_CLIENT_connect ("fs", dc->h->cfg); if (NULL == client) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Connecting to `%s'-service failed, will try again.\n", "FS"); try_reconnect (dc); return; } dc->client = client; if (NULL != dc->pending_head) { dc->th = GNUNET_CLIENT_notify_transmit_ready (client, sizeof (struct SearchMessage), GNUNET_CONSTANTS_SERVICE_TIMEOUT, GNUNET_NO, &transmit_download_request, dc); GNUNET_assert (NULL != dc->th); } } /** * Add entries to the pending list. * * @param cls our download context * @param key unused * @param entry entry of type "struct DownloadRequest" * @return GNUNET_OK */ static int retry_entry (void *cls, const GNUNET_HashCode * key, void *entry) { struct GNUNET_FS_DownloadContext *dc = cls; struct DownloadRequest *dr = entry; dr->next = NULL; dr->prev = NULL; GNUNET_CONTAINER_DLL_insert (dc->pending_head, dc->pending_tail, dr); dr->is_pending = GNUNET_YES; return GNUNET_OK; } /** * We've lost our connection with the FS service. * Re-establish it and re-transmit all of our * pending requests. * * @param dc download context that is having trouble */ static void try_reconnect (struct GNUNET_FS_DownloadContext *dc) { if (NULL != dc->client) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Moving all requests back to pending list\n"); if (NULL != dc->th) { GNUNET_CLIENT_notify_transmit_ready_cancel (dc->th); dc->th = NULL; } /* full reset of the pending list */ dc->pending_head = NULL; dc->pending_tail = NULL; GNUNET_CONTAINER_multihashmap_iterate (dc->active, &retry_entry, dc); GNUNET_CLIENT_disconnect (dc->client); dc->in_receive = GNUNET_NO; dc->client = NULL; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Will try to reconnect in 1s\n"); dc->task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_reconnect, dc); } /** * We're allowed to ask the FS service for our blocks. Start the download. * * @param cls the 'struct GNUNET_FS_DownloadContext' * @param client handle to use for communcation with FS (we must destroy it!) */ static void activate_fs_download (void *cls, struct GNUNET_CLIENT_Connection *client) { struct GNUNET_FS_DownloadContext *dc = cls; struct GNUNET_FS_ProgressInfo pi; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download activated\n"); GNUNET_assert (NULL != client); GNUNET_assert (NULL == dc->client); GNUNET_assert (NULL == dc->th); dc->client = client; pi.status = GNUNET_FS_STATUS_DOWNLOAD_ACTIVE; GNUNET_FS_download_make_status_ (&pi, dc); dc->pending_head = NULL; dc->pending_tail = NULL; GNUNET_CONTAINER_multihashmap_iterate (dc->active, &retry_entry, dc); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking for transmission to FS service\n"); if (NULL != dc->pending_head) { dc->th = GNUNET_CLIENT_notify_transmit_ready (dc->client, sizeof (struct SearchMessage), GNUNET_CONSTANTS_SERVICE_TIMEOUT, GNUNET_NO, &transmit_download_request, dc); GNUNET_assert (NULL != dc->th); } } /** * We must stop to ask the FS service for our blocks. Pause the download. * * @param cls the 'struct GNUNET_FS_DownloadContext' */ static void deactivate_fs_download (void *cls) { struct GNUNET_FS_DownloadContext *dc = cls; struct GNUNET_FS_ProgressInfo pi; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download deactivated\n"); if (NULL != dc->th) { GNUNET_CLIENT_notify_transmit_ready_cancel (dc->th); dc->th = NULL; } if (NULL != dc->client) { GNUNET_CLIENT_disconnect (dc->client); dc->in_receive = GNUNET_NO; dc->client = NULL; } dc->pending_head = NULL; dc->pending_tail = NULL; pi.status = GNUNET_FS_STATUS_DOWNLOAD_INACTIVE; GNUNET_FS_download_make_status_ (&pi, dc); } /** * (recursively) Create a download request structure. * * @param parent parent of the current entry * @param chk_idx index of the chk for this block in the parent block * @param depth depth of the current entry, 0 are the DBLOCKs, * top level block is 'dc->treedepth - 1' * @param dr_offset offset in the original file this block maps to * (as in, offset of the first byte of the first DBLOCK * in the subtree rooted in the returned download request tree) * @param file_start_offset desired starting offset for the download * in the original file; requesting tree should not contain * DBLOCKs prior to the file_start_offset * @param desired_length desired number of bytes the user wanted to access * (from file_start_offset). Resulting tree should not contain * DBLOCKs after file_start_offset + file_length. * @return download request tree for the given range of DBLOCKs at * the specified depth */ static struct DownloadRequest * create_download_request (struct DownloadRequest *parent, unsigned int chk_idx, unsigned int depth, uint64_t dr_offset, uint64_t file_start_offset, uint64_t desired_length) { struct DownloadRequest *dr; unsigned int i; unsigned int head_skip; uint64_t child_block_size; dr = GNUNET_malloc (sizeof (struct DownloadRequest)); dr->parent = parent; dr->depth = depth; dr->offset = dr_offset; dr->chk_idx = chk_idx; if (0 == depth) return dr; child_block_size = GNUNET_FS_tree_compute_tree_size (depth - 1); /* calculate how many blocks at this level are not interesting * from the start (rounded down), either because of the requested * file offset or because this IBlock is further along */ if (dr_offset < file_start_offset) head_skip = file_start_offset / child_block_size; else head_skip = 0; /* calculate index of last block at this level that is interesting (rounded up) */ dr->num_children = (file_start_offset + desired_length - dr_offset) / child_block_size; if (dr->num_children * child_block_size < file_start_offset + desired_length - dr_offset) dr->num_children++; /* round up */ dr->num_children -= head_skip; if (dr->num_children > CHK_PER_INODE) dr->num_children = CHK_PER_INODE; /* cap at max */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Block at offset %llu and depth %u has %u children\n", (unsigned long long) dr_offset, depth, dr->num_children); /* now we can get the total number of *interesting* children for this block */ /* why else would we have gotten here to begin with? (that'd be a bad logic error) */ GNUNET_assert (dr->num_children > 0); dr->children = GNUNET_malloc (dr->num_children * sizeof (struct DownloadRequest *)); for (i = 0; i < dr->num_children; i++) dr->children[i] = create_download_request (dr, i + head_skip, depth - 1, dr_offset + (i + head_skip) * child_block_size, file_start_offset, desired_length); return dr; } /** * Continuation after a possible attempt to reconstruct * the current IBlock from the existing file. * * @param cls the 'struct ReconstructContext' * @param tc scheduler context */ static void reconstruct_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FS_DownloadContext *dc = cls; /* clean up state from tree encoder */ if (dc->task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (dc->task); dc->task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != dc->rfh) { GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (dc->rfh)); dc->rfh = NULL; } /* start "normal" download */ dc->issue_requests = GNUNET_YES; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting normal download\n"); schedule_block_download (dc, dc->top_request); } /** * Task requesting the next block from the tree encoder. * * @param cls the 'struct GNUJNET_FS_DownloadContext' we're processing * @param tc task context */ static void get_next_block (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FS_DownloadContext *dc = cls; dc->task = GNUNET_SCHEDULER_NO_TASK; GNUNET_FS_tree_encoder_next (dc->te); } /** * Function called asking for the current (encoded) * block to be processed. After processing the * client should either call "GNUNET_FS_tree_encode_next" * or (on error) "GNUNET_FS_tree_encode_finish". * * This function checks if the content on disk matches * the expected content based on the URI. * * @param cls closure * @param chk content hash key for the block * @param offset offset of the block * @param depth depth of the block, 0 for DBLOCK * @param type type of the block (IBLOCK or DBLOCK) * @param block the (encrypted) block * @param block_size size of block (in bytes) */ static void reconstruct_cb (void *cls, const struct ContentHashKey *chk, uint64_t offset, unsigned int depth, enum GNUNET_BLOCK_Type type, const void *block, uint16_t block_size) { struct GNUNET_FS_DownloadContext *dc = cls; struct GNUNET_FS_ProgressInfo pi; struct DownloadRequest *dr; uint64_t blen; unsigned int chld; /* find corresponding request entry */ dr = dc->top_request; while (dr->depth > depth) { GNUNET_assert (dr->num_children > 0); blen = GNUNET_FS_tree_compute_tree_size (dr->depth - 1); chld = (offset - dr->offset) / blen; if (chld < dr->children[0]->chk_idx) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Block %u < %u irrelevant for our range\n", chld, dr->children[0]->chk_idx); dc->task = GNUNET_SCHEDULER_add_now (&get_next_block, dc); return; /* irrelevant block */ } if (chld > dr->children[dr->num_children-1]->chk_idx) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Block %u > %u irrelevant for our range\n", chld, dr->children[dr->num_children-1]->chk_idx); dc->task = GNUNET_SCHEDULER_add_now (&get_next_block, dc); return; /* irrelevant block */ } dr = dr->children[chld - dr->children[0]->chk_idx]; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Matched TE block with request at offset %llu and depth %u in state %d\n", (unsigned long long) dr->offset, dr->depth, dr->state); /* FIXME: this code needs more testing and might need to handle more states... */ switch (dr->state) { case BRS_INIT: break; case BRS_RECONSTRUCT_DOWN: break; case BRS_RECONSTRUCT_META_UP: break; case BRS_RECONSTRUCT_UP: break; case BRS_CHK_SET: if (0 == memcmp (chk, &dr->chk, sizeof (struct ContentHashKey))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Reconstruction succeeded, can use block at offset %llu, depth %u\n", (unsigned long long) offset, depth); /* block matches, hence tree below matches; * this request is done! */ dr->state = BRS_DOWNLOAD_UP; (void) GNUNET_CONTAINER_multihashmap_remove (dc->active, &dr->chk.query, dr); if (GNUNET_YES == dr->is_pending) { GNUNET_break (0); /* how did we get here? */ GNUNET_CONTAINER_DLL_remove (dc->pending_head, dc->pending_tail, dr); dr->is_pending = GNUNET_NO; } /* calculate how many bytes of payload this block * corresponds to */ blen = GNUNET_FS_tree_compute_tree_size (dr->depth); /* how many of those bytes are in the requested range? */ blen = GNUNET_MIN (blen, dc->length + dc->offset - dr->offset); /* signal progress */ dc->completed += blen; pi.status = GNUNET_FS_STATUS_DOWNLOAD_PROGRESS; pi.value.download.specifics.progress.data = NULL; pi.value.download.specifics.progress.offset = offset; pi.value.download.specifics.progress.data_len = 0; pi.value.download.specifics.progress.depth = 0; pi.value.download.specifics.progress.trust_offered = 0; pi.value.download.specifics.progress.block_download_duration = GNUNET_TIME_UNIT_ZERO; GNUNET_FS_download_make_status_ (&pi, dc); /* FIXME: duplicated code from 'process_result_with_request - refactor */ if (dc->completed == dc->length) { /* download completed, signal */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download completed, truncating file to desired length %llu\n", (unsigned long long) GNUNET_ntohll (dc->uri->data. chk.file_length)); /* truncate file to size (since we store IBlocks at the end) */ if (NULL != dc->filename) { if (0 != truncate (dc->filename, GNUNET_ntohll (dc->uri->data.chk.file_length))) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "truncate", dc->filename); } } } else GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Reconstruction failed, need to download block at offset %llu, depth %u\n", (unsigned long long) offset, depth); break; case BRS_DOWNLOAD_DOWN: break; case BRS_DOWNLOAD_UP: break; case BRS_ERROR: break; default: GNUNET_assert (0); break; } dc->task = GNUNET_SCHEDULER_add_now (&get_next_block, dc); if ((dr == dc->top_request) && (dr->state == BRS_DOWNLOAD_UP)) check_completed (dc); } /** * Function called by the tree encoder to obtain a block of plaintext * data (for the lowest level of the tree). * * @param cls our 'struct ReconstructContext' * @param offset identifies which block to get * @param max (maximum) number of bytes to get; returning * fewer will also cause errors * @param buf where to copy the plaintext buffer * @param emsg location to store an error message (on error) * @return number of bytes copied to buf, 0 on error */ static size_t fh_reader (void *cls, uint64_t offset, size_t max, void *buf, char **emsg) { struct GNUNET_FS_DownloadContext *dc = cls; struct GNUNET_DISK_FileHandle *fh = dc->rfh; ssize_t ret; if (NULL != emsg) *emsg = NULL; if (offset != GNUNET_DISK_file_seek (fh, offset, GNUNET_DISK_SEEK_SET)) { if (NULL != emsg) *emsg = GNUNET_strdup (strerror (errno)); return 0; } ret = GNUNET_DISK_file_read (fh, buf, max); if (ret < 0) { if (NULL != emsg) *emsg = GNUNET_strdup (strerror (errno)); return 0; } return ret; } /** * Task that creates the initial (top-level) download * request for the file. * * @param cls the 'struct GNUNET_FS_DownloadContext' * @param tc scheduler context */ void GNUNET_FS_download_start_task_ (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FS_DownloadContext *dc = cls; struct GNUNET_FS_ProgressInfo pi; struct GNUNET_DISK_FileHandle *fh; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start task running...\n"); dc->task = GNUNET_SCHEDULER_NO_TASK; if (0 == dc->length) { /* no bytes required! */ if (NULL != dc->filename) { fh = GNUNET_DISK_file_open (dc->filename, GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_CREATE | ((0 == GNUNET_FS_uri_chk_get_file_size (dc->uri)) ? GNUNET_DISK_OPEN_TRUNCATE : 0), GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_GROUP_READ | GNUNET_DISK_PERM_OTHER_READ); GNUNET_DISK_file_close (fh); } GNUNET_FS_download_sync_ (dc); pi.status = GNUNET_FS_STATUS_DOWNLOAD_START; pi.value.download.specifics.start.meta = dc->meta; GNUNET_FS_download_make_status_ (&pi, dc); check_completed (dc); return; } if (NULL != dc->emsg) return; if (NULL == dc->top_request) { dc->top_request = create_download_request (NULL, 0, dc->treedepth - 1, 0, dc->offset, dc->length); dc->top_request->state = BRS_CHK_SET; dc->top_request->chk = (dc->uri->type == chk) ? dc->uri->data.chk.chk : dc->uri->data.loc.fi.chk; /* signal start */ GNUNET_FS_download_sync_ (dc); if (NULL != dc->search) GNUNET_FS_search_result_sync_ (dc->search); pi.status = GNUNET_FS_STATUS_DOWNLOAD_START; pi.value.download.specifics.start.meta = dc->meta; GNUNET_FS_download_make_status_ (&pi, dc); } GNUNET_FS_download_start_downloading_ (dc); /* attempt reconstruction from disk */ if (GNUNET_YES == GNUNET_DISK_file_test (dc->filename)) dc->rfh = GNUNET_DISK_file_open (dc->filename, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); if (dc->top_request->state == BRS_CHK_SET) { if (NULL != dc->rfh) { /* first, try top-down */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying top-down reconstruction for `%s'\n", dc->filename); try_top_down_reconstruction (dc, dc->top_request); switch (dc->top_request->state) { case BRS_CHK_SET: break; /* normal */ case BRS_DOWNLOAD_DOWN: break; /* normal, some blocks already down */ case BRS_DOWNLOAD_UP: /* already done entirely, party! */ if (NULL != dc->rfh) { /* avoid hanging on to file handle longer than * necessary */ GNUNET_DISK_file_close (dc->rfh); dc->rfh = NULL; } return; case BRS_ERROR: GNUNET_asprintf (&dc->emsg, _("Invalid URI")); GNUNET_FS_download_sync_ (dc); pi.status = GNUNET_FS_STATUS_DOWNLOAD_ERROR; pi.value.download.specifics.error.message = dc->emsg; GNUNET_FS_download_make_status_ (&pi, dc); return; default: GNUNET_assert (0); break; } } } /* attempt reconstruction from meta data */ if ((GNUNET_FS_uri_chk_get_file_size (dc->uri) <= MAX_INLINE_SIZE) && (NULL != dc->meta)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to find embedded meta data for download of size %llu with %u bytes MD\n", (unsigned long long) GNUNET_FS_uri_chk_get_file_size (dc->uri), (unsigned int) GNUNET_CONTAINER_meta_data_get_serialized_size (dc->meta)); GNUNET_CONTAINER_meta_data_iterate (dc->meta, &match_full_data, dc); if (BRS_DOWNLOAD_UP == dc->top_request->state) { if (NULL != dc->rfh) { /* avoid hanging on to file handle longer than * necessary */ GNUNET_DISK_file_close (dc->rfh); dc->rfh = NULL; } return; /* finished, status update was already done for us */ } } if (NULL != dc->rfh) { /* finally, actually run bottom-up */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying bottom-up reconstruction of file `%s'\n", dc->filename); dc->te = GNUNET_FS_tree_encoder_create (dc->h, GNUNET_FS_uri_chk_get_file_size (dc->uri), dc, &fh_reader, &reconstruct_cb, NULL, &reconstruct_cont); dc->task = GNUNET_SCHEDULER_add_now (&get_next_block, dc); } else { /* simple, top-level download */ dc->issue_requests = GNUNET_YES; schedule_block_download (dc, dc->top_request); } if (BRS_DOWNLOAD_UP == dc->top_request->state) check_completed (dc); } /** * Create SUSPEND event for the given download operation * and then clean up our state (without stop signal). * * @param cls the 'struct GNUNET_FS_DownloadContext' to signal for */ void GNUNET_FS_download_signal_suspend_ (void *cls) { struct GNUNET_FS_DownloadContext *dc = cls; struct GNUNET_FS_ProgressInfo pi; if (NULL != dc->top) GNUNET_FS_end_top (dc->h, dc->top); while (NULL != dc->child_head) GNUNET_FS_download_signal_suspend_ (dc->child_head); if (NULL != dc->search) { dc->search->download = NULL; dc->search = NULL; } if (NULL != dc->job_queue) { GNUNET_FS_dequeue_ (dc->job_queue); dc->job_queue = NULL; } if (NULL != dc->parent) GNUNET_CONTAINER_DLL_remove (dc->parent->child_head, dc->parent->child_tail, dc); if (GNUNET_SCHEDULER_NO_TASK != dc->task) { GNUNET_SCHEDULER_cancel (dc->task); dc->task = GNUNET_SCHEDULER_NO_TASK; } pi.status = GNUNET_FS_STATUS_DOWNLOAD_SUSPEND; GNUNET_FS_download_make_status_ (&pi, dc); if (NULL != dc->te) { GNUNET_FS_tree_encoder_finish (dc->te, NULL, NULL); dc->te = NULL; } if (NULL != dc->rfh) { GNUNET_DISK_file_close (dc->rfh); dc->rfh = NULL; } GNUNET_FS_free_download_request_ (dc->top_request); if (NULL != dc->active) { GNUNET_CONTAINER_multihashmap_destroy (dc->active); dc->active = NULL; } GNUNET_free_non_null (dc->filename); GNUNET_CONTAINER_meta_data_destroy (dc->meta); GNUNET_FS_uri_destroy (dc->uri); GNUNET_free_non_null (dc->temp_filename); GNUNET_free_non_null (dc->serialization); GNUNET_free (dc); } /** * Helper function to setup the download context. * * @param h handle to the file sharing subsystem * @param uri the URI of the file (determines what to download); CHK or LOC URI * @param meta known metadata for the file (can be NULL) * @param filename where to store the file, maybe NULL (then no file is * created on disk and data must be grabbed from the callbacks) * @param tempname where to store temporary file data, not used if filename is non-NULL; * can be NULL (in which case we will pick a name if needed); the temporary file * may already exist, in which case we will try to use the data that is there and * if it is not what is desired, will overwrite it * @param offset at what offset should we start the download (typically 0) * @param length how many bytes should be downloaded starting at offset * @param anonymity anonymity level to use for the download * @param options various options * @param cctx initial value for the client context for this download * @return context that can be used to control this download */ struct GNUNET_FS_DownloadContext * create_download_context (struct GNUNET_FS_Handle *h, const struct GNUNET_FS_Uri *uri, const struct GNUNET_CONTAINER_MetaData *meta, const char *filename, const char *tempname, uint64_t offset, uint64_t length, uint32_t anonymity, enum GNUNET_FS_DownloadOptions options, void *cctx) { struct GNUNET_FS_DownloadContext *dc; GNUNET_assert (GNUNET_FS_uri_test_chk (uri) || GNUNET_FS_uri_test_loc (uri)); if ((offset + length < offset) || (offset + length > GNUNET_FS_uri_chk_get_file_size (uri))) { GNUNET_break (0); return NULL; } dc = GNUNET_malloc (sizeof (struct GNUNET_FS_DownloadContext)); dc->h = h; dc->uri = GNUNET_FS_uri_dup (uri); dc->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); dc->client_info = cctx; dc->start_time = GNUNET_TIME_absolute_get (); if (NULL != filename) { dc->filename = GNUNET_strdup (filename); if (GNUNET_YES == GNUNET_DISK_file_test (filename)) GNUNET_break (GNUNET_OK == GNUNET_DISK_file_size (filename, &dc->old_file_size, GNUNET_YES, GNUNET_YES)); } if (GNUNET_FS_uri_test_loc (dc->uri)) GNUNET_assert (GNUNET_OK == GNUNET_FS_uri_loc_get_peer_identity (dc->uri, &dc->target)); dc->offset = offset; dc->length = length; dc->anonymity = anonymity; dc->options = options; dc->active = GNUNET_CONTAINER_multihashmap_create (1 + 2 * (length / DBLOCK_SIZE)); dc->treedepth = GNUNET_FS_compute_depth (GNUNET_FS_uri_chk_get_file_size (dc->uri)); if ((NULL == filename) && (is_recursive_download (dc))) { if (NULL != tempname) dc->temp_filename = GNUNET_strdup (tempname); else dc->temp_filename = GNUNET_DISK_mktemp ("gnunet-directory-download-tmp"); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting download `%s' of %llu bytes with tree depth %u\n", filename, (unsigned long long) length, dc->treedepth); dc->task = GNUNET_SCHEDULER_add_now (&GNUNET_FS_download_start_task_, dc); return dc; } /** * Download parts of a file. Note that this will store * the blocks at the respective offset in the given file. Also, the * download is still using the blocking of the underlying FS * encoding. As a result, the download may *write* outside of the * given boundaries (if offset and length do not match the 32k FS * block boundaries).

    * * This function should be used to focus a download towards a * particular portion of the file (optimization), not to strictly * limit the download to exactly those bytes. * * @param h handle to the file sharing subsystem * @param uri the URI of the file (determines what to download); CHK or LOC URI * @param meta known metadata for the file (can be NULL) * @param filename where to store the file, maybe NULL (then no file is * created on disk and data must be grabbed from the callbacks) * @param tempname where to store temporary file data, not used if filename is non-NULL; * can be NULL (in which case we will pick a name if needed); the temporary file * may already exist, in which case we will try to use the data that is there and * if it is not what is desired, will overwrite it * @param offset at what offset should we start the download (typically 0) * @param length how many bytes should be downloaded starting at offset * @param anonymity anonymity level to use for the download * @param options various options * @param cctx initial value for the client context for this download * @param parent parent download to associate this download with (use NULL * for top-level downloads; useful for manually-triggered recursive downloads) * @return context that can be used to control this download */ struct GNUNET_FS_DownloadContext * GNUNET_FS_download_start (struct GNUNET_FS_Handle *h, const struct GNUNET_FS_Uri *uri, const struct GNUNET_CONTAINER_MetaData *meta, const char *filename, const char *tempname, uint64_t offset, uint64_t length, uint32_t anonymity, enum GNUNET_FS_DownloadOptions options, void *cctx, struct GNUNET_FS_DownloadContext *parent) { struct GNUNET_FS_DownloadContext *dc; dc = create_download_context (h, uri, meta, filename, tempname, offset, length, anonymity, options, cctx); if (NULL == dc) return NULL; dc->parent = parent; if (NULL != parent) GNUNET_CONTAINER_DLL_insert (parent->child_head, parent->child_tail, dc); else dc->top = GNUNET_FS_make_top (dc->h, &GNUNET_FS_download_signal_suspend_, dc); return dc; } /** * Download parts of a file based on a search result. The download * will be associated with the search result (and the association * will be preserved when serializing/deserializing the state). * If the search is stopped, the download will not be aborted but * be 'promoted' to a stand-alone download. * * As with the other download function, this will store * the blocks at the respective offset in the given file. Also, the * download is still using the blocking of the underlying FS * encoding. As a result, the download may *write* outside of the * given boundaries (if offset and length do not match the 32k FS * block boundaries).

    * * The given range can be used to focus a download towards a * particular portion of the file (optimization), not to strictly * limit the download to exactly those bytes. * * @param h handle to the file sharing subsystem * @param sr the search result to use for the download (determines uri and * meta data and associations) * @param filename where to store the file, maybe NULL (then no file is * created on disk and data must be grabbed from the callbacks) * @param tempname where to store temporary file data, not used if filename is non-NULL; * can be NULL (in which case we will pick a name if needed); the temporary file * may already exist, in which case we will try to use the data that is there and * if it is not what is desired, will overwrite it * @param offset at what offset should we start the download (typically 0) * @param length how many bytes should be downloaded starting at offset * @param anonymity anonymity level to use for the download * @param options various download options * @param cctx initial value for the client context for this download * @return context that can be used to control this download */ struct GNUNET_FS_DownloadContext * GNUNET_FS_download_start_from_search (struct GNUNET_FS_Handle *h, struct GNUNET_FS_SearchResult *sr, const char *filename, const char *tempname, uint64_t offset, uint64_t length, uint32_t anonymity, enum GNUNET_FS_DownloadOptions options, void *cctx) { struct GNUNET_FS_DownloadContext *dc; if ((NULL == sr) || (NULL != sr->download)) { GNUNET_break (0); return NULL; } dc = create_download_context (h, sr->uri, sr->meta, filename, tempname, offset, length, anonymity, options, cctx); if (NULL == dc) return NULL; dc->search = sr; sr->download = dc; if (NULL != sr->probe_ctx) { GNUNET_FS_download_stop (sr->probe_ctx, GNUNET_YES); sr->probe_ctx = NULL; } return dc; } /** * Start the downloading process (by entering the queue). * * @param dc our download context */ void GNUNET_FS_download_start_downloading_ (struct GNUNET_FS_DownloadContext *dc) { if (dc->completed == dc->length) return; GNUNET_assert (NULL == dc->job_queue); dc->job_queue = GNUNET_FS_queue_ (dc->h, &activate_fs_download, &deactivate_fs_download, dc, (dc->length + DBLOCK_SIZE - 1) / DBLOCK_SIZE, (0 == (dc->options & GNUNET_FS_DOWNLOAD_IS_PROBE)) ? GNUNET_FS_QUEUE_PRIORITY_NORMAL : GNUNET_FS_QUEUE_PRIORITY_PROBE); } /** * Stop a download (aborts if download is incomplete). * * @param dc handle for the download * @param do_delete delete files of incomplete downloads */ void GNUNET_FS_download_stop (struct GNUNET_FS_DownloadContext *dc, int do_delete) { struct GNUNET_FS_ProgressInfo pi; int have_children; int search_was_null; if (NULL != dc->top) GNUNET_FS_end_top (dc->h, dc->top); if (GNUNET_SCHEDULER_NO_TASK != dc->task) { GNUNET_SCHEDULER_cancel (dc->task); dc->task = GNUNET_SCHEDULER_NO_TASK; } search_was_null = (NULL == dc->search); if (NULL != dc->search) { dc->search->download = NULL; GNUNET_FS_search_result_sync_ (dc->search); dc->search = NULL; } if (NULL != dc->job_queue) { GNUNET_FS_dequeue_ (dc->job_queue); dc->job_queue = NULL; } if (NULL != dc->te) { GNUNET_FS_tree_encoder_finish (dc->te, NULL, NULL); dc->te = NULL; } have_children = (NULL != dc->child_head) ? GNUNET_YES : GNUNET_NO; while (NULL != dc->child_head) GNUNET_FS_download_stop (dc->child_head, do_delete); if (NULL != dc->parent) GNUNET_CONTAINER_DLL_remove (dc->parent->child_head, dc->parent->child_tail, dc); if (NULL != dc->serialization) GNUNET_FS_remove_sync_file_ (dc->h, ((NULL != dc->parent) || (! search_was_null)) ? GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD : GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD, dc->serialization); if ((GNUNET_YES == have_children) && (NULL == dc->parent)) GNUNET_FS_remove_sync_dir_ (dc->h, (! search_was_null) ? GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD : GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD, dc->serialization); pi.status = GNUNET_FS_STATUS_DOWNLOAD_STOPPED; GNUNET_FS_download_make_status_ (&pi, dc); GNUNET_FS_free_download_request_ (dc->top_request); dc->top_request = NULL; if (NULL != dc->active) { GNUNET_CONTAINER_multihashmap_destroy (dc->active); dc->active = NULL; } if (NULL != dc->filename) { if ((dc->completed != dc->length) && (GNUNET_YES == do_delete)) { if (0 != UNLINK (dc->filename)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", dc->filename); } GNUNET_free (dc->filename); } GNUNET_CONTAINER_meta_data_destroy (dc->meta); GNUNET_FS_uri_destroy (dc->uri); if (NULL != dc->temp_filename) { if (0 != UNLINK (dc->temp_filename)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "unlink", dc->temp_filename); GNUNET_free (dc->temp_filename); } GNUNET_free_non_null (dc->serialization); GNUNET_free (dc); } /* end of fs_download.c */ gnunet-0.9.3/src/fs/gnunet-service-fs.c0000644000175000017500000004522611760502551014666 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-service-fs.c * @brief gnunet anonymity protocol implementation * @author Christian Grothoff * * To use: * - consider re-issue GSF_dht_lookup_ after non-DHT reply received */ #include "platform.h" #include #include "gnunet_constants.h" #include "gnunet_core_service.h" #include "gnunet_dht_service.h" #include "gnunet_datastore_service.h" #include "gnunet_load_lib.h" #include "gnunet_peer_lib.h" #include "gnunet_protocols.h" #include "gnunet_signatures.h" #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" #include "gnunet_util_lib.h" #include "gnunet-service-fs_cp.h" #include "gnunet-service-fs_indexing.h" #include "gnunet-service-fs_lc.h" #include "gnunet-service-fs_pe.h" #include "gnunet-service-fs_pr.h" #include "gnunet-service-fs_push.h" #include "gnunet-service-fs_put.h" #include "fs.h" /** * Size for the hash map for DHT requests from the FS * service. Should be about the number of concurrent * DHT requests we plan to make. */ #define FS_DHT_HT_SIZE 1024 /** * How quickly do we age cover traffic? At the given * time interval, remaining cover traffic counters are * decremented by 1/16th. */ #define COVER_AGE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) /* ****************************** globals ****************************** */ /** * Our connection to the datastore. */ struct GNUNET_DATASTORE_Handle *GSF_dsh; /** * Our configuration. */ const struct GNUNET_CONFIGURATION_Handle *GSF_cfg; /** * Handle for reporting statistics. */ struct GNUNET_STATISTICS_Handle *GSF_stats; /** * Handle for DHT operations. */ struct GNUNET_DHT_Handle *GSF_dht; /** * How long do requests typically stay in the routing table? */ struct GNUNET_LOAD_Value *GSF_rt_entry_lifetime; /** * Running average of the observed latency to other peers (round trip). * Initialized to 5s as the initial default. */ struct GNUNET_TIME_Relative GSF_avg_latency = { 500 }; /** * Typical priorities we're seeing from other peers right now. Since * most priorities will be zero, this value is the weighted average of * non-zero priorities seen "recently". In order to ensure that new * values do not dramatically change the ratio, values are first * "capped" to a reasonable range (+N of the current value) and then * averaged into the existing value by a ratio of 1:N. Hence * receiving the largest possible priority can still only raise our * "current_priorities" by at most 1. */ double GSF_current_priorities; /** * How many query messages have we received 'recently' that * have not yet been claimed as cover traffic? */ unsigned int GSF_cover_query_count; /** * How many content messages have we received 'recently' that * have not yet been claimed as cover traffic? */ unsigned int GSF_cover_content_count; /** * Our block context. */ struct GNUNET_BLOCK_Context *GSF_block_ctx; /** * Pointer to handle to the core service (points to NULL until we've * connected to it). */ struct GNUNET_CORE_Handle *GSF_core; /** * Are we introducing randomized delays for better anonymity? */ int GSF_enable_randomized_delays; /* ***************************** locals ******************************* */ /** * Configuration for block library. */ static struct GNUNET_CONFIGURATION_Handle *block_cfg; /** * ID of our task that we use to age the cover counters. */ static GNUNET_SCHEDULER_TaskIdentifier cover_age_task; /** * Datastore 'GET' load tracking. */ static struct GNUNET_LOAD_Value *datastore_get_load; /** * Identity of this peer. */ static struct GNUNET_PeerIdentity my_id; /** * Task that periodically ages our cover traffic statistics. * * @param cls unused closure * @param tc task context */ static void age_cover_counters (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GSF_cover_content_count = (GSF_cover_content_count * 15) / 16; GSF_cover_query_count = (GSF_cover_query_count * 15) / 16; cover_age_task = GNUNET_SCHEDULER_add_delayed (COVER_AGE_FREQUENCY, &age_cover_counters, NULL); } /** * We've just now completed a datastore request. Update our * datastore load calculations. * * @param start time when the datastore request was issued */ void GSF_update_datastore_delay_ (struct GNUNET_TIME_Absolute start) { struct GNUNET_TIME_Relative delay; delay = GNUNET_TIME_absolute_get_duration (start); GNUNET_LOAD_update (datastore_get_load, delay.rel_value); } /** * Test if the DATABASE (GET) load on this peer is too high * to even consider processing the query at * all. * * @return GNUNET_YES if the load is too high to do anything (load high) * GNUNET_NO to process normally (load normal) * GNUNET_SYSERR to process for free (load low) */ int GSF_test_get_load_too_high_ (uint32_t priority) { double ld; ld = GNUNET_LOAD_get_load (datastore_get_load); if (ld < 1) return GNUNET_SYSERR; if (ld <= priority) return GNUNET_NO; return GNUNET_YES; } /** * We've received peer performance information. Update * our running average for the P2P latency. * * @param atsi performance information * @param atsi_count number of 'atsi' records */ static void update_latencies (const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { unsigned int i; for (i = 0; i < atsi_count; i++) { if (ntohl (atsi[i].type) == GNUNET_ATS_QUALITY_NET_DELAY) { GSF_avg_latency.rel_value = (GSF_avg_latency.rel_value * 31 + GNUNET_MIN (5000, ntohl (atsi[i].value))) / 32; GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# running average P2P latency (ms)"), GSF_avg_latency.rel_value, GNUNET_NO); break; } } } /** * Handle P2P "PUT" message. * * @param cls closure, always NULL * @param other the other peer involved (sender or receiver, NULL * for loopback messages where we are both sender and receiver) * @param message the actual message * @param atsi performance information * @param atsi_count number of records in 'atsi' * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_p2p_put (void *cls, const struct GNUNET_PeerIdentity *other, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct GSF_ConnectedPeer *cp; cp = GSF_peer_get_ (other); if (NULL == cp) { GNUNET_break (0); return GNUNET_OK; } GSF_cover_content_count++; update_latencies (atsi, atsi_count); return GSF_handle_p2p_content_ (cp, message); } /** * We have a new request, consider forwarding it to the given * peer. * * @param cls the 'struct GSF_PendingRequest' * @param peer identity of the peer * @param cp handle to the connected peer record * @param ppd peer performance data */ static void consider_request_for_forwarding (void *cls, const struct GNUNET_PeerIdentity *peer, struct GSF_ConnectedPeer *cp, const struct GSF_PeerPerformanceData *ppd) { struct GSF_PendingRequest *pr = cls; if (GNUNET_YES != GSF_pending_request_test_target_ (pr, peer)) { GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# Loopback routes suppressed"), 1, GNUNET_NO); return; } GSF_plan_add_ (cp, pr); } /** * Function to be called after we're done processing * replies from the local lookup. If the result status * code indicates that there may be more replies, plan * forwarding the request. * * @param cls closure (NULL) * @param pr the pending request we were processing * @param result final datastore lookup result */ static void consider_forwarding (void *cls, struct GSF_PendingRequest *pr, enum GNUNET_BLOCK_EvaluationResult result) { if (GNUNET_BLOCK_EVALUATION_OK_LAST == result) return; /* we're done... */ GSF_iterate_connected_peers_ (&consider_request_for_forwarding, pr); } /** * Handle P2P "GET" request. * * @param cls closure, always NULL * @param other the other peer involved (sender or receiver, NULL * for loopback messages where we are both sender and receiver) * @param message the actual message * @param atsi performance information * @param atsi_count number of records in 'atsi' * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_p2p_get (void *cls, const struct GNUNET_PeerIdentity *other, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct GSF_PendingRequest *pr; pr = GSF_handle_p2p_query_ (other, message); if (NULL == pr) return GNUNET_SYSERR; GSF_pending_request_get_data_ (pr)->has_started = GNUNET_YES; GSF_local_lookup_ (pr, &consider_forwarding, NULL); update_latencies (atsi, atsi_count); return GNUNET_OK; } /** * We're done with the local lookup, now consider * P2P processing (depending on request options and * result status). Also signal that we can now * receive more request information from the client. * * @param cls the client doing the request ('struct GNUNET_SERVER_Client') * @param pr the pending request we were processing * @param result final datastore lookup result */ static void start_p2p_processing (void *cls, struct GSF_PendingRequest *pr, enum GNUNET_BLOCK_EvaluationResult result) { struct GNUNET_SERVER_Client *client = cls; struct GSF_PendingRequestData *prd; prd = GSF_pending_request_get_data_ (pr); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished database lookup for local request `%s' with result %d\n", GNUNET_h2s (&prd->query), result); GNUNET_SERVER_receive_done (client, GNUNET_OK); if (GNUNET_BLOCK_EVALUATION_OK_LAST == result) return; /* we're done, 'pr' was already destroyed... */ if (0 != (GSF_PRO_LOCAL_ONLY & prd->options)) { GSF_pending_request_cancel_ (pr, GNUNET_YES); return; } GSF_dht_lookup_ (pr); consider_forwarding (NULL, pr, result); } /** * Handle START_SEARCH-message (search request from client). * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_start_search (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct GSF_PendingRequest *pr; int ret; pr = NULL; ret = GSF_local_client_start_search_handler_ (client, message, &pr); switch (ret) { case GNUNET_SYSERR: GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); break; case GNUNET_NO: GNUNET_SERVER_receive_done (client, GNUNET_OK); break; case GNUNET_YES: GSF_pending_request_get_data_ (pr)->has_started = GNUNET_YES; GSF_local_lookup_ (pr, &start_p2p_processing, client); break; default: GNUNET_assert (0); } } /** * Task run during shutdown. * * @param cls unused * @param tc unused */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (NULL != GSF_core) { GNUNET_CORE_disconnect (GSF_core); GSF_core = NULL; } GSF_put_done_ (); GSF_push_done_ (); GSF_pending_request_done_ (); GSF_plan_done (); GSF_connected_peer_done_ (); GNUNET_DATASTORE_disconnect (GSF_dsh, GNUNET_NO); GSF_dsh = NULL; GNUNET_DHT_disconnect (GSF_dht); GSF_dht = NULL; GNUNET_BLOCK_context_destroy (GSF_block_ctx); GSF_block_ctx = NULL; GNUNET_CONFIGURATION_destroy (block_cfg); block_cfg = NULL; GNUNET_STATISTICS_destroy (GSF_stats, GNUNET_NO); GSF_stats = NULL; if (GNUNET_SCHEDULER_NO_TASK != cover_age_task) { GNUNET_SCHEDULER_cancel (cover_age_task); cover_age_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_FS_indexing_done (); GNUNET_LOAD_value_free (datastore_get_load); datastore_get_load = NULL; GNUNET_LOAD_value_free (GSF_rt_entry_lifetime); GSF_rt_entry_lifetime = NULL; } /** * Function called for each pending request whenever a new * peer connects, giving us a chance to decide about submitting * the existing request to the new peer. * * @param cls the 'struct GSF_ConnectedPeer' of the new peer * @param key query for the request * @param pr handle to the pending request * @return GNUNET_YES to continue to iterate */ static int consider_peer_for_forwarding (void *cls, const GNUNET_HashCode * key, struct GSF_PendingRequest *pr) { struct GSF_ConnectedPeer *cp = cls; struct GNUNET_PeerIdentity pid; GSF_connected_peer_get_identity_ (cp, &pid); if (GNUNET_YES != GSF_pending_request_test_target_ (pr, &pid)) { GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# Loopback routes suppressed"), 1, GNUNET_NO); return GNUNET_YES; } GSF_plan_add_ (cp, pr); return GNUNET_YES; } /** * Method called whenever a given peer connects. * * @param cls closure, not used * @param peer peer identity this notification is about * @param atsi performance information * @param atsi_count number of records in 'atsi' */ static void peer_connect_handler (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct GSF_ConnectedPeer *cp; if (0 == memcmp (&my_id, peer, sizeof (struct GNUNET_PeerIdentity))) return; cp = GSF_peer_connect_handler_ (peer, atsi, atsi_count); if (NULL == cp) return; GSF_iterate_pending_requests_ (&consider_peer_for_forwarding, cp); } /** * Function called after GNUNET_CORE_connect has succeeded * (or failed for good). Note that the private key of the * peer is intentionally not exposed here; if you need it, * your process should try to read the private key file * directly (which should work if you are authorized...). * * @param cls closure * @param server handle to the server, NULL if we failed * @param my_identity ID of this peer, NULL if we failed */ static void peer_init_handler (void *cls, struct GNUNET_CORE_Handle *server, const struct GNUNET_PeerIdentity *my_identity) { my_id = *my_identity; } /** * Process fs requests. * * @param server the initialized server * @param c configuration to use */ static int main_init (struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *c) { static const struct GNUNET_CORE_MessageHandler p2p_handlers[] = { {&handle_p2p_get, GNUNET_MESSAGE_TYPE_FS_GET, 0}, {&handle_p2p_put, GNUNET_MESSAGE_TYPE_FS_PUT, 0}, {&GSF_handle_p2p_migration_stop_, GNUNET_MESSAGE_TYPE_FS_MIGRATION_STOP, sizeof (struct MigrationStopMessage)}, {NULL, 0, 0} }; static const struct GNUNET_SERVER_MessageHandler handlers[] = { {&GNUNET_FS_handle_index_start, NULL, GNUNET_MESSAGE_TYPE_FS_INDEX_START, 0}, {&GNUNET_FS_handle_index_list_get, NULL, GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET, sizeof (struct GNUNET_MessageHeader)}, {&GNUNET_FS_handle_unindex, NULL, GNUNET_MESSAGE_TYPE_FS_UNINDEX, sizeof (struct UnindexMessage)}, {&handle_start_search, NULL, GNUNET_MESSAGE_TYPE_FS_START_SEARCH, 0}, {NULL, NULL, 0, 0} }; GSF_core = GNUNET_CORE_connect (GSF_cfg, 1, NULL, &peer_init_handler, &peer_connect_handler, &GSF_peer_disconnect_handler_, NULL, GNUNET_NO, NULL, GNUNET_NO, p2p_handlers); if (NULL == GSF_core) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to connect to `%s' service.\n"), "core"); return GNUNET_SYSERR; } GNUNET_SERVER_disconnect_notify (server, &GSF_client_disconnect_handler_, NULL); GNUNET_SERVER_add_handlers (server, handlers); cover_age_task = GNUNET_SCHEDULER_add_delayed (COVER_AGE_FREQUENCY, &age_cover_counters, NULL); datastore_get_load = GNUNET_LOAD_value_init (DATASTORE_LOAD_AUTODECLINE); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); return GNUNET_OK; } /** * Process fs requests. * * @param cls closure * @param server the initialized server * @param cfg configuration to use */ static void run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *cfg) { GSF_cfg = cfg; GSF_enable_randomized_delays = GNUNET_CONFIGURATION_get_value_yesno (cfg, "fs", "DELAY"); GSF_dsh = GNUNET_DATASTORE_connect (cfg); if (NULL == GSF_dsh) { GNUNET_SCHEDULER_shutdown (); return; } GSF_rt_entry_lifetime = GNUNET_LOAD_value_init (GNUNET_TIME_UNIT_FOREVER_REL); GSF_stats = GNUNET_STATISTICS_create ("fs", cfg); block_cfg = GNUNET_CONFIGURATION_create (); GNUNET_CONFIGURATION_set_value_string (block_cfg, "block", "PLUGINS", "fs"); GSF_block_ctx = GNUNET_BLOCK_context_create (block_cfg); GNUNET_assert (NULL != GSF_block_ctx); GSF_dht = GNUNET_DHT_connect (cfg, FS_DHT_HT_SIZE); GSF_plan_init (); GSF_pending_request_init_ (); GSF_connected_peer_init_ (); GSF_push_init_ (); GSF_put_init_ (); if ((GNUNET_OK != GNUNET_FS_indexing_init (cfg, GSF_dsh)) || (GNUNET_OK != main_init (server, cfg))) { GNUNET_SCHEDULER_shutdown (); shutdown_task (NULL, NULL); return; } } /** * The main function for the fs service. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { return (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "fs", GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; } /* end of gnunet-service-fs.c */ gnunet-0.9.3/src/fs/gnunet-service-fs_pe.h0000644000175000017500000000452511760502551015354 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-service-fs_pe.h * @brief API to manage query plan * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_FS_PE_H #define GNUNET_SERVICE_FS_PE_H #include "gnunet-service-fs.h" /** * Create a new query plan entry. * * @param cp peer with the entry * @param pr request with the entry */ void GSF_plan_add_ (struct GSF_ConnectedPeer *cp, struct GSF_PendingRequest *pr); /** * Notify the plan about a peer being no longer available; * destroy all entries associated with this peer. * * @param cp connected peer */ void GSF_plan_notify_peer_disconnect_ (const struct GSF_ConnectedPeer *cp); /** * Notify the plan about a request being done; * destroy all entries associated with this request. * * @param pr request that is done */ void GSF_plan_notify_request_done_ (struct GSF_PendingRequest *pr); /** * Get the last transmission attempt time for the request plan list * referenced by 'rpr_head', that was sent to 'sender' * * @param rpr_head request plan reference list to check. * @param sender the peer that we've sent the request to. * @param result the timestamp to fill. * @return GNUNET_YES if 'result' was changed, GNUNET_NO otherwise. */ int GSF_request_plan_reference_get_last_transmission_ ( struct GSF_RequestPlanReference *rpr_head, struct GSF_ConnectedPeer *sender, struct GNUNET_TIME_Absolute *result); /** * Initialize plan subsystem. */ void GSF_plan_init (void); /** * Shutdown plan subsystem. */ void GSF_plan_done (void); #endif /* end of gnunet-service-fs_pe.h */ gnunet-0.9.3/src/fs/test_fs_namespace.c0000644000175000017500000002663511760502551015010 00000000000000/* This file is part of GNUnet. (C) 2005, 2006, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/test_fs_namespace.c * @brief Test for fs_namespace.c * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_arm_service.h" #include "gnunet_fs_service.h" #define VERBOSE GNUNET_NO #define START_ARM GNUNET_YES static struct PeerContext p1; static GNUNET_HashCode nsid; static struct GNUNET_FS_Uri *sks_expect_uri; static struct GNUNET_FS_Uri *ksk_expect_uri; static struct GNUNET_FS_Handle *fs; static struct GNUNET_FS_SearchContext *sks_search; static struct GNUNET_FS_SearchContext *ksk_search; static GNUNET_SCHEDULER_TaskIdentifier kill_task; static int update_started; static int err; struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); } static void stop_arm (struct PeerContext *p) { #if START_ARM if (NULL != p->arm_proc) { if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; } #endif GNUNET_CONFIGURATION_destroy (p->cfg); } static void abort_ksk_search_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (ksk_search != NULL) { GNUNET_FS_search_stop (ksk_search); ksk_search = NULL; if (sks_search == NULL) { GNUNET_FS_stop (fs); if (GNUNET_SCHEDULER_NO_TASK != kill_task) GNUNET_SCHEDULER_cancel (kill_task); } } } static void abort_sks_search_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_FS_Namespace *ns; if (sks_search == NULL) return; GNUNET_FS_search_stop (sks_search); sks_search = NULL; ns = GNUNET_FS_namespace_create (fs, "testNamespace"); GNUNET_assert (NULL != ns); GNUNET_assert (GNUNET_OK == GNUNET_FS_namespace_delete (ns, GNUNET_YES)); if (ksk_search == NULL) { GNUNET_FS_stop (fs); if (GNUNET_SCHEDULER_NO_TASK != kill_task) GNUNET_SCHEDULER_cancel (kill_task); } } static void do_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { FPRINTF (stderr, "%s", "Operation timed out\n"); kill_task = GNUNET_SCHEDULER_NO_TASK; abort_sks_search_task (NULL, tc); abort_ksk_search_task (NULL, tc); } static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) { switch (event->status) { case GNUNET_FS_STATUS_SEARCH_RESULT: if (sks_search == event->value.search.sc) { if (!GNUNET_FS_uri_test_equal (sks_expect_uri, event->value.search.specifics.result.uri)) { FPRINTF (stderr, "%s", "Wrong result for sks search!\n"); err = 1; } /* give system 1ms to initiate update search! */ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, &abort_sks_search_task, NULL); } else if (ksk_search == event->value.search.sc) { if (!GNUNET_FS_uri_test_equal (ksk_expect_uri, event->value.search.specifics.result.uri)) { FPRINTF (stderr, "%s", "Wrong result for ksk search!\n"); err = 1; } GNUNET_SCHEDULER_add_continuation (&abort_ksk_search_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } else { FPRINTF (stderr, "%s", "Unexpected search result received!\n"); GNUNET_break (0); } break; case GNUNET_FS_STATUS_SEARCH_ERROR: FPRINTF (stderr, "Error searching file: %s\n", event->value.search.specifics.error.message); if (sks_search == event->value.search.sc) GNUNET_SCHEDULER_add_continuation (&abort_sks_search_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); else if (ksk_search == event->value.search.sc) GNUNET_SCHEDULER_add_continuation (&abort_ksk_search_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); else GNUNET_break (0); break; case GNUNET_FS_STATUS_SEARCH_START: GNUNET_assert ((NULL == event->value.search.cctx) || (0 == strcmp ("sks_search", event->value.search.cctx)) || (0 == strcmp ("ksk_search", event->value.search.cctx))); if (NULL == event->value.search.cctx) { GNUNET_assert (0 == strcmp ("sks_search", event->value.search.pctx)); update_started = GNUNET_YES; } GNUNET_assert (1 == event->value.search.anonymity); break; case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED: return NULL; case GNUNET_FS_STATUS_SEARCH_STOPPED: return NULL; default: FPRINTF (stderr, "Unexpected event: %d\n", event->status); break; } return event->value.search.cctx; } static void publish_cont (void *cls, const struct GNUNET_FS_Uri *ksk_uri, const char *emsg) { char *msg; struct GNUNET_FS_Uri *sks_uri; char sbuf[1024]; struct GNUNET_CRYPTO_HashAsciiEncoded enc; if (NULL != emsg) { FPRINTF (stderr, "Error publishing: %s\n", emsg); err = 1; GNUNET_FS_stop (fs); return; } GNUNET_CRYPTO_hash_to_enc (&nsid, &enc); GNUNET_snprintf (sbuf, sizeof (sbuf), "gnunet://fs/sks/%s/this", &enc); sks_uri = GNUNET_FS_uri_parse (sbuf, &msg); if (NULL == sks_uri) { FPRINTF (stderr, "failed to parse URI `%s': %s\n", sbuf, msg); err = 1; GNUNET_FS_stop (fs); GNUNET_free_non_null (msg); return; } ksk_search = GNUNET_FS_search_start (fs, ksk_uri, 1, GNUNET_FS_SEARCH_OPTION_NONE, "ksk_search"); sks_search = GNUNET_FS_search_start (fs, sks_uri, 1, GNUNET_FS_SEARCH_OPTION_NONE, "sks_search"); GNUNET_FS_uri_destroy (sks_uri); } static void sks_cont (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) { struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_FS_Uri *ksk_uri; char *msg; struct GNUNET_FS_BlockOptions bo; if (NULL == uri) { fprintf (stderr, "Error publishing: %s\n", emsg); err = 1; GNUNET_FS_stop (fs); return; } meta = GNUNET_CONTAINER_meta_data_create (); msg = NULL; ksk_uri = GNUNET_FS_uri_parse ("gnunet://fs/ksk/ns-search", &msg); GNUNET_assert (NULL == msg); ksk_expect_uri = GNUNET_FS_uri_dup (uri); bo.content_priority = 1; bo.anonymity_level = 1; bo.replication_level = 0; bo.expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); GNUNET_FS_publish_ksk (fs, ksk_uri, meta, uri, &bo, GNUNET_FS_PUBLISH_OPTION_NONE, &publish_cont, NULL); GNUNET_FS_uri_destroy (ksk_uri); GNUNET_CONTAINER_meta_data_destroy (meta); } static void adv_cont (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) { struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_FS_Namespace *ns; struct GNUNET_FS_BlockOptions bo; if (NULL != emsg) { FPRINTF (stderr, "Error publishing: %s\n", emsg); err = 1; GNUNET_FS_stop (fs); return; } ns = GNUNET_FS_namespace_create (fs, "testNamespace"); GNUNET_assert (NULL != ns); meta = GNUNET_CONTAINER_meta_data_create (); GNUNET_assert (NULL == emsg); sks_expect_uri = GNUNET_FS_uri_dup (uri); bo.content_priority = 1; bo.anonymity_level = 1; bo.replication_level = 0; bo.expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); GNUNET_FS_publish_sks (fs, ns, "this", "next", meta, uri, /* FIXME: this is non-sense (use CHK URI!?) */ &bo, GNUNET_FS_PUBLISH_OPTION_NONE, &sks_cont, NULL); GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_FS_namespace_delete (ns, GNUNET_NO); } static void ns_iterator (void *cls, const char *name, const GNUNET_HashCode * id) { int *ok = cls; if (0 != strcmp (name, "testNamespace")) return; *ok = GNUNET_YES; nsid = *id; } static void testNamespace () { struct GNUNET_FS_Namespace *ns; struct GNUNET_FS_BlockOptions bo; struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_FS_Uri *ksk_uri; int ok; ns = GNUNET_FS_namespace_create (fs, "testNamespace"); GNUNET_assert (NULL != ns); ok = GNUNET_NO; GNUNET_FS_namespace_list (fs, &ns_iterator, &ok); if (GNUNET_NO == ok) { FPRINTF (stderr, "%s", "namespace_list failed to find namespace!\n"); GNUNET_FS_namespace_delete (ns, GNUNET_YES); GNUNET_FS_stop (fs); err = 1; return; } meta = GNUNET_CONTAINER_meta_data_create (); ksk_uri = GNUNET_FS_uri_parse ("gnunet://fs/ksk/testnsa", NULL); bo.content_priority = 1; bo.anonymity_level = 1; bo.replication_level = 0; bo.expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); GNUNET_FS_namespace_advertise (fs, ksk_uri, ns, meta, &bo, "root", &adv_cont, NULL); kill_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &do_timeout, NULL); GNUNET_FS_uri_destroy (ksk_uri); GNUNET_FS_namespace_delete (ns, GNUNET_NO); GNUNET_CONTAINER_meta_data_destroy (meta); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { setup_peer (&p1, "test_fs_namespace_data.conf"); fs = GNUNET_FS_start (cfg, "test-fs-namespace", &progress_cb, NULL, GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); testNamespace (); } int main (int argc, char *argv[]) { char *const argvx[] = { "test-fs-namespace", "-c", "test_fs_namespace_data.conf", NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("test_fs_namespace", "WARNING", NULL); GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "test-fs-namespace", "nohelp", options, &run, NULL); stop_arm (&p1); if (GNUNET_YES != update_started) { FPRINTF (stderr, "%s", "Update search never started!\n"); err = 1; } GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-namespace/"); return err; } /* end of test_fs_namespace.c */ gnunet-0.9.3/src/fs/gnunet-service-fs_put.h0000644000175000017500000000224011760502551015550 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/gnunet-service-fs_put.h * @brief support for putting content into the DHT * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_FS_PUT_H #define GNUNET_SERVICE_FS_PUT_H #include "gnunet-service-fs.h" /** * Setup the module. */ void GSF_put_init_ (void); /** * Shutdown the module. */ void GSF_put_done_ (void); #endif gnunet-0.9.3/src/fs/test_gnunet_service_fs_migration_data.conf0000644000175000017500000000031611665224123021625 00000000000000@INLINE@ test_fs_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-service-fs-migration/ DEFAULTCONFIG = test_gnunet_service_fs_migration_data.conf [ats] WAN_QUOTA_IN = 3932160 WAN_QUOTA_OUT = 3932160 gnunet-0.9.3/src/fs/test_fs_search_probes.c0000644000175000017500000002045311760502551015663 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/test_fs_search_probes.c * @brief simple testcase for publish + search operation with probes * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_arm_service.h" #include "gnunet_fs_service.h" #define START_ARM GNUNET_YES /** * File-size we use for testing. */ #define FILESIZE 1024 /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) /** * How long should our test-content live? */ #define LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_PeerIdentity id; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static struct PeerContext p1; static struct GNUNET_TIME_Absolute start; static struct GNUNET_FS_Handle *fs; static struct GNUNET_FS_SearchContext *search; static struct GNUNET_FS_PublishContext *publish; static void abort_publish_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_FS_publish_stop (publish); publish = NULL; } static void abort_search_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (search != NULL) GNUNET_FS_search_stop (search); search = NULL; } static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) { const char *keywords[] = { "down_foo" }; struct GNUNET_FS_Uri *kuri; switch (event->status) { case GNUNET_FS_STATUS_PUBLISH_PROGRESS: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publish is progressing (%llu/%llu at level %u off %llu)...\n", (unsigned long long) event->value.publish.completed, (unsigned long long) event->value.publish.size, event->value.publish.specifics.progress.depth, (unsigned long long) event->value.publish.specifics. progress.offset); break; case GNUNET_FS_STATUS_PUBLISH_COMPLETED: kuri = GNUNET_FS_uri_ksk_create_from_args (1, keywords); start = GNUNET_TIME_absolute_get (); search = GNUNET_FS_search_start (fs, kuri, 1, GNUNET_FS_SEARCH_OPTION_NONE, "search"); GNUNET_FS_uri_destroy (kuri); GNUNET_assert (search != NULL); break; case GNUNET_FS_STATUS_SEARCH_RESULT: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Search complete.\n"); break; case GNUNET_FS_STATUS_PUBLISH_ERROR: FPRINTF (stderr, "Error publishing file: %s\n", event->value.publish.specifics.error.message); GNUNET_break (0); GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_SEARCH_ERROR: FPRINTF (stderr, "Error searching file: %s\n", event->value.search.specifics.error.message); GNUNET_SCHEDULER_add_continuation (&abort_search_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; case GNUNET_FS_STATUS_PUBLISH_START: GNUNET_assert (0 == strcmp ("publish-context", event->value.publish.cctx)); GNUNET_assert (NULL == event->value.publish.pctx); GNUNET_assert (FILESIZE == event->value.publish.size); GNUNET_assert (0 == event->value.publish.completed); GNUNET_assert (1 == event->value.publish.anonymity); break; case GNUNET_FS_STATUS_PUBLISH_STOPPED: GNUNET_assert (publish == event->value.publish.pc); GNUNET_assert (FILESIZE == event->value.publish.size); GNUNET_assert (1 == event->value.publish.anonymity); GNUNET_FS_stop (fs); fs = NULL; break; case GNUNET_FS_STATUS_SEARCH_UPDATE: GNUNET_assert (0 < event->value.search.specifics.update.availability_rank); GNUNET_assert (0 < event->value.search.specifics.update.availability_certainty); GNUNET_SCHEDULER_add_now (&abort_search_task, NULL); break; case GNUNET_FS_STATUS_SEARCH_START: GNUNET_assert (search == NULL); GNUNET_assert (0 == strcmp ("search", event->value.search.cctx)); GNUNET_assert (1 == event->value.search.anonymity); break; case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED: break; case GNUNET_FS_STATUS_SEARCH_STOPPED: GNUNET_assert (search == event->value.search.sc); GNUNET_SCHEDULER_add_continuation (&abort_publish_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); break; default: FPRINTF (stderr, "Unexpected event: %d\n", event->status); break; } return NULL; } static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); } static void stop_arm (struct PeerContext *p) { #if START_ARM if (NULL != p->arm_proc) { if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; } #endif GNUNET_CONFIGURATION_destroy (p->cfg); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { const char *keywords[] = { "down_foo", "down_bar" }; char *buf; struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_FS_Uri *kuri; struct GNUNET_FS_BlockOptions bo; struct GNUNET_FS_FileInformation *fi; size_t i; setup_peer (&p1, "test_fs_search_data.conf"); fs = GNUNET_FS_start (cfg, "test-fs-search", &progress_cb, NULL, GNUNET_FS_FLAGS_DO_PROBES, GNUNET_FS_OPTIONS_END); GNUNET_assert (NULL != fs); buf = GNUNET_malloc (FILESIZE); for (i = 0; i < FILESIZE; i++) buf[i] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 256); meta = GNUNET_CONTAINER_meta_data_create (); kuri = GNUNET_FS_uri_ksk_create_from_args (2, keywords); bo.content_priority = 42; bo.anonymity_level = 1; bo.replication_level = 0; bo.expiration_time = GNUNET_TIME_relative_to_absolute (LIFETIME); fi = GNUNET_FS_file_information_create_from_data (fs, "publish-context", FILESIZE, buf, kuri, meta, GNUNET_NO, &bo); GNUNET_FS_uri_destroy (kuri); GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_assert (NULL != fi); start = GNUNET_TIME_absolute_get (); publish = GNUNET_FS_publish_start (fs, fi, NULL, NULL, NULL, GNUNET_FS_PUBLISH_OPTION_NONE); GNUNET_assert (publish != NULL); } int main (int argc, char *argv[]) { char *const argvx[] = { "test-fs-search-probes", "-c", "test_fs_search_data.conf", NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("test_fs_search_probes", "WARNING", NULL); GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "test-fs-search", "nohelp", options, &run, NULL); stop_arm (&p1); GNUNET_DISK_directory_remove ("/tmp/gnunet-test-fs-search/"); return 0; } /* end of test_fs_search_probes.c */ gnunet-0.9.3/src/fs/fs_file_information.c0000644000175000017500000004015111760502551015326 00000000000000/* This file is part of GNUnet. (C) 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file fs/fs_file_information.c * @brief Manage information for publishing directory hierarchies * @author Christian Grothoff */ #include "platform.h" #include #include "gnunet_fs_service.h" #include "fs_api.h" #include "fs_tree.h" /** * Obtain the name under which this file information * structure is stored on disk. Only works for top-level * file information structures. * * @param s structure to get the filename for * @return NULL on error, otherwise filename that * can be passed to "GNUNET_FS_file_information_recover" * to read this fi-struct from disk. */ const char * GNUNET_FS_file_information_get_id (struct GNUNET_FS_FileInformation *s) { if (NULL != s->dir) return NULL; return s->serialization; } /** * Obtain the filename from the file information structure. * * @param s structure to get the filename for * @return "filename" field of the structure (can be NULL) */ const char * GNUNET_FS_file_information_get_filename (struct GNUNET_FS_FileInformation *s) { return s->filename; } /** * Set the filename in the file information structure. * If filename was already set, frees it before setting the new one. * Makes a copy of the argument. * * @param s structure to get the filename for * @param filename filename to set */ void GNUNET_FS_file_information_set_filename (struct GNUNET_FS_FileInformation *s, const char *filename) { GNUNET_free_non_null (s->filename); if (filename) s->filename = GNUNET_strdup (filename); else s->filename = NULL; } /** * Create an entry for a file in a publish-structure. * * @param h handle to the file sharing subsystem * @param client_info initial value for the client-info value for this entry * @param filename name of the file or directory to publish * @param keywords under which keywords should this file be available * directly; can be NULL * @param meta metadata for the file * @param do_index GNUNET_YES for index, GNUNET_NO for insertion, * GNUNET_SYSERR for simulation * @param bo block options * @return publish structure entry for the file */ struct GNUNET_FS_FileInformation * GNUNET_FS_file_information_create_from_file (struct GNUNET_FS_Handle *h, void *client_info, const char *filename, const struct GNUNET_FS_Uri *keywords, const struct GNUNET_CONTAINER_MetaData *meta, int do_index, const struct GNUNET_FS_BlockOptions *bo) { struct FileInfo *fi; uint64_t fsize; struct GNUNET_FS_FileInformation *ret; const char *fn; const char *ss; #if WINDOWS char fn_conv[MAX_PATH]; #endif /* FIXME: should includeSymLinks be GNUNET_NO or GNUNET_YES here? */ if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fsize, GNUNET_NO, GNUNET_YES)) { GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "stat", filename); return NULL; } fi = GNUNET_FS_make_file_reader_context_ (filename); if (fi == NULL) { GNUNET_break (0); return NULL; } ret = GNUNET_FS_file_information_create_from_reader (h, client_info, fsize, &GNUNET_FS_data_reader_file_, fi, keywords, meta, do_index, bo); if (ret == NULL) return NULL; ret->h = h; ret->filename = GNUNET_strdup (filename); #if !WINDOWS fn = filename; #else plibc_conv_to_win_path (filename, fn_conv); fn = fn_conv; #endif while (NULL != (ss = strstr (fn, DIR_SEPARATOR_STR))) fn = ss + 1; /* FIXME: If we assume that on other platforms CRT is UTF-8-aware, then * this should be changed to EXTRACTOR_METAFORMAT_UTF8 */ #if !WINDOWS GNUNET_CONTAINER_meta_data_insert (ret->meta, "", EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, EXTRACTOR_METAFORMAT_C_STRING, "text/plain", fn, strlen (fn) + 1); #else GNUNET_CONTAINER_meta_data_insert (ret->meta, "", EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, EXTRACTOR_METAFORMAT_UTF8, "text/plain", fn, strlen (fn) + 1); #endif return ret; } /** * Create an entry for a file in a publish-structure. * * @param h handle to the file sharing subsystem * @param client_info initial value for the client-info value for this entry * @param length length of the file * @param data data for the file (should not be used afterwards by * the caller; callee will "free") * @param keywords under which keywords should this file be available * directly; can be NULL * @param meta metadata for the file * @param do_index GNUNET_YES for index, GNUNET_NO for insertion, * GNUNET_SYSERR for simulation * @param bo block options * @return publish structure entry for the file */ struct GNUNET_FS_FileInformation * GNUNET_FS_file_information_create_from_data (struct GNUNET_FS_Handle *h, void *client_info, uint64_t length, void *data, const struct GNUNET_FS_Uri *keywords, const struct GNUNET_CONTAINER_MetaData *meta, int do_index, const struct GNUNET_FS_BlockOptions *bo) { if (GNUNET_YES == do_index) { GNUNET_break (0); return NULL; } return GNUNET_FS_file_information_create_from_reader (h, client_info, length, &GNUNET_FS_data_reader_copy_, data, keywords, meta, do_index, bo); } /** * Create an entry for a file in a publish-structure. * * @param h handle to the file sharing subsystem * @param client_info initial value for the client-info value for this entry * @param length length of the file * @param reader function that can be used to obtain the data for the file * @param reader_cls closure for "reader" * @param keywords under which keywords should this file be available * directly; can be NULL * @param meta metadata for the file * @param do_index GNUNET_YES for index, GNUNET_NO for insertion, * GNUNET_SYSERR for simulation * @param bo block options * @return publish structure entry for the file */ struct GNUNET_FS_FileInformation * GNUNET_FS_file_information_create_from_reader (struct GNUNET_FS_Handle *h, void *client_info, uint64_t length, GNUNET_FS_DataReader reader, void *reader_cls, const struct GNUNET_FS_Uri *keywords, const struct GNUNET_CONTAINER_MetaData *meta, int do_index, const struct GNUNET_FS_BlockOptions *bo) { struct GNUNET_FS_FileInformation *ret; if ((GNUNET_YES == do_index) && (reader != &GNUNET_FS_data_reader_file_)) { GNUNET_break (0); return NULL; } ret = GNUNET_malloc (sizeof (struct GNUNET_FS_FileInformation)); ret->h = h; ret->client_info = client_info; ret->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); if (ret->meta == NULL) ret->meta = GNUNET_CONTAINER_meta_data_create (); ret->keywords = (keywords == NULL) ? NULL : GNUNET_FS_uri_dup (keywords); ret->data.file.reader = reader; ret->data.file.reader_cls = reader_cls; ret->data.file.do_index = do_index; ret->data.file.file_size = length; ret->bo = *bo; return ret; } /** * Test if a given entry represents a directory. * * @param ent check if this FI represents a directory * @return GNUNET_YES if so, GNUNET_NO if not */ int GNUNET_FS_file_information_is_directory (const struct GNUNET_FS_FileInformation *ent) { return ent->is_directory; } /** * Create an entry for an empty directory in a publish-structure. * This function should be used by applications for which the * use of "GNUNET_FS_file_information_create_from_directory" * is not appropriate. * * @param h handle to the file sharing subsystem * @param client_info initial value for the client-info value for this entry * @param meta metadata for the directory * @param keywords under which keywords should this directory be available * directly; can be NULL * @param bo block options * @param filename name of the directory; can be NULL * @return publish structure entry for the directory , NULL on error */ struct GNUNET_FS_FileInformation * GNUNET_FS_file_information_create_empty_directory (struct GNUNET_FS_Handle *h, void *client_info, const struct GNUNET_FS_Uri *keywords, const struct GNUNET_CONTAINER_MetaData *meta, const struct GNUNET_FS_BlockOptions *bo, const char *filename) { struct GNUNET_FS_FileInformation *ret; ret = GNUNET_malloc (sizeof (struct GNUNET_FS_FileInformation)); ret->h = h; ret->client_info = client_info; ret->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); ret->keywords = GNUNET_FS_uri_dup (keywords); ret->bo = *bo; ret->is_directory = GNUNET_YES; if (filename != NULL) ret->filename = GNUNET_strdup (filename); return ret; } /** * Add an entry to a directory in a publish-structure. Clients * should never modify publish structures that were passed to * "GNUNET_FS_publish_start" already. * * @param dir the directory * @param ent the entry to add; the entry must not have been * added to any other directory at this point and * must not include "dir" in its structure * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_FS_file_information_add (struct GNUNET_FS_FileInformation *dir, struct GNUNET_FS_FileInformation *ent) { if ((ent->dir != NULL) || (ent->next != NULL) || (dir->is_directory != GNUNET_YES)) { GNUNET_break (0); return GNUNET_SYSERR; } ent->dir = dir; ent->next = dir->data.dir.entries; dir->data.dir.entries = ent; dir->data.dir.dir_size = 0; return GNUNET_OK; } /** * Inspect a file or directory in a publish-structure. Clients * should never modify publish structures that were passed to * "GNUNET_FS_publish_start" already. When called on a directory, * this function will FIRST call "proc" with information about * the directory itself and then for each of the files in the * directory (but not for files in subdirectories). When called * on a file, "proc" will be called exactly once (with information * about the specific file). * * @param dir the directory * @param proc function to call on each entry * @param proc_cls closure for proc */ void GNUNET_FS_file_information_inspect (struct GNUNET_FS_FileInformation *dir, GNUNET_FS_FileInformationProcessor proc, void *proc_cls) { struct GNUNET_FS_FileInformation *pos; int no; no = GNUNET_NO; if (GNUNET_OK != proc (proc_cls, dir, (dir->is_directory == GNUNET_YES) ? dir->data.dir.dir_size : dir->data. file.file_size, dir->meta, &dir->keywords, &dir->bo, (dir->is_directory == GNUNET_YES) ? &no : &dir->data.file.do_index, &dir->client_info)) return; if (dir->is_directory != GNUNET_YES) return; pos = dir->data.dir.entries; while (pos != NULL) { no = GNUNET_NO; if (GNUNET_OK != proc (proc_cls, pos, (pos->is_directory == GNUNET_YES) ? pos->data.dir.dir_size : pos->data. file.file_size, pos->meta, &pos->keywords, &pos->bo, (pos->is_directory == GNUNET_YES) ? &no : &pos->data.file.do_index, &pos->client_info)) break; pos = pos->next; } } /** * Destroy publish-structure. Clients should never destroy publish * structures that were passed to "GNUNET_FS_publish_start" already. * * @param fi structure to destroy * @param cleaner function to call on each entry in the structure * (useful to clean up client_info); can be NULL; return * values are ignored * @param cleaner_cls closure for cleaner */ void GNUNET_FS_file_information_destroy (struct GNUNET_FS_FileInformation *fi, GNUNET_FS_FileInformationProcessor cleaner, void *cleaner_cls) { struct GNUNET_FS_FileInformation *pos; int no; no = GNUNET_NO; if (fi->is_directory == GNUNET_YES) { /* clean up directory */ while (NULL != (pos = fi->data.dir.entries)) { fi->data.dir.entries = pos->next; GNUNET_FS_file_information_destroy (pos, cleaner, cleaner_cls); } /* clean up client-info */ if (NULL != cleaner) cleaner (cleaner_cls, fi, fi->data.dir.dir_size, fi->meta, &fi->keywords, &fi->bo, &no, &fi->client_info); GNUNET_free_non_null (fi->data.dir.dir_data); } else { /* call clean-up function of the reader */ if (fi->data.file.reader != NULL) fi->data.file.reader (fi->data.file.reader_cls, 0, 0, NULL, NULL); /* clean up client-info */ if (NULL != cleaner) cleaner (cleaner_cls, fi, fi->data.file.file_size, fi->meta, &fi->keywords, &fi->bo, &fi->data.file.do_index, &fi->client_info); } GNUNET_free_non_null (fi->filename); GNUNET_free_non_null (fi->emsg); GNUNET_free_non_null (fi->chk_uri); /* clean up serialization */ if ((NULL != fi->serialization) && (0 != UNLINK (fi->serialization))) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fi->serialization); if (NULL != fi->keywords) GNUNET_FS_uri_destroy (fi->keywords); if (NULL != fi->meta) GNUNET_CONTAINER_meta_data_destroy (fi->meta); GNUNET_free_non_null (fi->serialization); if (fi->te != NULL) { GNUNET_FS_tree_encoder_finish (fi->te, NULL, NULL); fi->te = NULL; } GNUNET_free (fi); } /* end of fs_file_information.c */ gnunet-0.9.3/src/transport/0000755000175000017500000000000011763406750012660 500000000000000gnunet-0.9.3/src/transport/gnunet-transport-certificate-creation0000755000175000017500000001277411763406612022152 00000000000000#! /bin/bash # gnunet-transport-certificate-creation - temporary wrapper script for .libs/gnunet-transport-certificate-creation # Generated by ltmain.sh (GNU libtool) 2.2.6b Debian-2.2.6b-2 # # The gnunet-transport-certificate-creation program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed='/bin/sed -e 1s/^X//' sed_quote_subst='s/\([`"$\\]\)/\\\1/g' # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command="(cd /home/grothoff/gnunet-0.9.3/src/transport; { test -z \"\${LIBRARY_PATH+set}\" || unset LIBRARY_PATH || { LIBRARY_PATH=; export LIBRARY_PATH; }; }; { test -z \"\${COMPILER_PATH+set}\" || unset COMPILER_PATH || { COMPILER_PATH=; export COMPILER_PATH; }; }; { test -z \"\${GCC_EXEC_PREFIX+set}\" || unset GCC_EXEC_PREFIX || { GCC_EXEC_PREFIX=; export GCC_EXEC_PREFIX; }; }; { test -z \"\${LD_RUN_PATH+set}\" || unset LD_RUN_PATH || { LD_RUN_PATH=; export LD_RUN_PATH; }; }; LD_LIBRARY_PATH=/usr/lib/debug:/home/grothoff/lib; export LD_LIBRARY_PATH; PATH=/opt/jdk1.6.0_22/bin:/usr/lib/jvm/java-6-sun//bin:.:/home/grothoff/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games; export PATH; gcc -fno-strict-aliasing -Wall -g -Wall -Werror -O0 -I/home/grothoff//include -o \$progdir/\$file gnunet-transport-certificate-creation.o -L/home/grothoff//lib ../../src/util/.libs/libgnunetutil.so -ldl -Wl,-rpath -Wl,/home/grothoff/gnunet-0.9.3/src/util/.libs)" # This environment variable determines our operation mode. if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then # install mode needs the following variables: generated_by_libtool_version='2.2.6b' notinst_deplibs=' ../../src/util/libgnunetutil.la' else # When we are sourced in execute mode, $file and $ECHO are already set. if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then ECHO="echo" file="$0" # Make sure echo works. if test "X$1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then # Yippee, $ECHO works! : else # Restart under the correct shell, and then maybe $ECHO will work. exec /bin/bash "$0" --no-reexec ${1+"$@"} fi fi # Find the directory that this script lives in. thisdir=`$ECHO "X$file" | $Xsed -e 's%/[^/]*$%%'` test "x$thisdir" = "x$file" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=`ls -ld "$file" | /bin/sed -n 's/.*-> //p'` while test -n "$file"; do destdir=`$ECHO "X$file" | $Xsed -e 's%/[^/]*$%%'` # If there was a directory component, then change thisdir. if test "x$destdir" != "x$file"; then case "$destdir" in [\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;; *) thisdir="$thisdir/$destdir" ;; esac fi file=`$ECHO "X$file" | $Xsed -e 's%^.*/%%'` file=`ls -ld "$thisdir/$file" | /bin/sed -n 's/.*-> //p'` done # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then # special case for '.' if test "$thisdir" = "."; then thisdir=`pwd` fi # remove .libs from thisdir case "$thisdir" in *[\\/].libs ) thisdir=`$ECHO "X$thisdir" | $Xsed -e 's%[\\/][^\\/]*$%%'` ;; .libs ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=`cd "$thisdir" && pwd` test -n "$absdir" && thisdir="$absdir" program=lt-'gnunet-transport-certificate-creation' progdir="$thisdir/.libs" if test ! -f "$progdir/$program" || { file=`ls -1dt "$progdir/$program" "$progdir/../$program" 2>/dev/null | /bin/sed 1q`; \ test "X$file" != "X$progdir/$program"; }; then file="$$-$program" if test ! -d "$progdir"; then mkdir "$progdir" else rm -f "$progdir/$file" fi # relink executable if necessary if test -n "$relink_command"; then if relink_command_output=`eval $relink_command 2>&1`; then : else echo "$relink_command_output" >&2 rm -f "$progdir/$file" exit 1 fi fi mv -f "$progdir/$file" "$progdir/$program" 2>/dev/null || { rm -f "$progdir/$program"; mv -f "$progdir/$file" "$progdir/$program"; } rm -f "$progdir/$file" fi if test -f "$progdir/$program"; then if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then # Run the actual program with our arguments. exec "$progdir/$program" ${1+"$@"} $ECHO "$0: cannot exec $program $*" 1>&2 exit 1 fi else # The program doesn't exist. $ECHO "$0: error: \`$progdir/$program' does not exist" 1>&2 $ECHO "This script is just a wrapper for $program." 1>&2 echo "See the libtool documentation for more information." 1>&2 exit 1 fi fi gnunet-0.9.3/src/transport/gnunet-service-transport_neighbours.c0000644000175000017500000030153011762127443022161 00000000000000/* This file is part of GNUnet. (C) 2010,2011,2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/gnunet-service-transport_neighbours.c * @brief neighbour management * @author Christian Grothoff * * TODO: * - "address_change_cb" is NEVER invoked; when should we call this one exactly? * - TEST, TEST, TEST... */ #include "platform.h" #include "gnunet_ats_service.h" #include "gnunet-service-transport_neighbours.h" #include "gnunet-service-transport_plugins.h" #include "gnunet-service-transport_validation.h" #include "gnunet-service-transport_clients.h" #include "gnunet-service-transport.h" #include "gnunet_peerinfo_service.h" #include "gnunet-service-transport_blacklist.h" #include "gnunet_constants.h" #include "transport.h" /** * Size of the neighbour hash map. */ #define NEIGHBOUR_TABLE_SIZE 256 /** * Time we give plugin to transmit DISCONNECT message before the * neighbour entry self-destructs. */ #define DISCONNECT_SENT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100) /** * How often must a peer violate bandwidth quotas before we start * to simply drop its messages? */ #define QUOTA_VIOLATION_DROP_THRESHOLD 10 /** * How often do we send KEEPALIVE messages to each of our neighbours and measure * the latency with this neighbour? * (idle timeout is 5 minutes or 300 seconds, so with 100s interval we * send 3 keepalives in each interval, so 3 messages would need to be * lost in a row for a disconnect). */ #define KEEPALIVE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 100) /** * How long are we willing to wait for a response from ATS before timing out? */ #define ATS_RESPONSE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500) /** * How long are we willing to wait for an ACK from the other peer before * giving up on our connect operation? */ #define SETUP_CONNECTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) /** * How long are we willing to wait for a successful reconnect if * an existing connection went down? Much shorter than the * usual SETUP_CONNECTION_TIMEOUT as we do not inform the * higher layers about the disconnect during this period. */ #define FAST_RECONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) /** * How long are we willing to wait for a response from the blacklist * subsystem before timing out? */ #define BLACKLIST_RESPONSE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500) GNUNET_NETWORK_STRUCT_BEGIN /** * Message a peer sends to another to indicate that it intends to * setup a connection/session for data exchange. A 'SESSION_CONNECT' * should be answered with a 'SESSION_CONNECT_ACK' with the same body * to confirm. A 'SESSION_CONNECT_ACK' should then be followed with * a 'SESSION_ACK'. Once the 'SESSION_ACK' is received, both peers * should be connected. */ struct SessionConnectMessage { /** * Header of type 'GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT' * or 'GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT_ACK' */ struct GNUNET_MessageHeader header; /** * Always zero. */ uint32_t reserved GNUNET_PACKED; /** * Absolute time at the sender. Only the most recent connect * message implies which session is preferred by the sender. */ struct GNUNET_TIME_AbsoluteNBO timestamp; }; /** * Message we send to the other peer to notify him that we intentionally * are disconnecting (to reduce timeouts). This is just a friendly * notification, peers must not rely on always receiving disconnect * messages. */ struct SessionDisconnectMessage { /** * Header of type 'GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT' */ struct GNUNET_MessageHeader header; /** * Always zero. */ uint32_t reserved GNUNET_PACKED; /** * Purpose of the signature. Extends over the timestamp. * Purpose should be GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DISCONNECT. */ struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; /** * Absolute time at the sender. Only the most recent connect * message implies which session is preferred by the sender. */ struct GNUNET_TIME_AbsoluteNBO timestamp; /** * Public key of the sender. */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; /** * Signature of the peer that sends us the disconnect. Only * valid if the timestamp is AFTER the timestamp from the * corresponding 'CONNECT' message. */ struct GNUNET_CRYPTO_RsaSignature signature; }; GNUNET_NETWORK_STRUCT_END /** * For each neighbour we keep a list of messages * that we still want to transmit to the neighbour. */ struct MessageQueue { /** * This is a doubly linked list. */ struct MessageQueue *next; /** * This is a doubly linked list. */ struct MessageQueue *prev; /** * Function to call once we're done. */ GST_NeighbourSendContinuation cont; /** * Closure for 'cont' */ void *cont_cls; /** * The message(s) we want to transmit, GNUNET_MessageHeader(s) * stuck together in memory. Allocated at the end of this struct. */ const char *message_buf; /** * Size of the message buf */ size_t message_buf_size; /** * At what time should we fail? */ struct GNUNET_TIME_Absolute timeout; }; /** * Possible state of a neighbour. Initially, we are S_NOT_CONNECTED. * * Then, there are two main paths. If we receive a CONNECT message, we * first run a check against the blacklist and ask ATS for a * suggestion. (S_CONNECT_RECV_ATS). If the blacklist comes back * positive, we give the address to ATS. If ATS makes a suggestion, * we ALSO give that suggestion to the blacklist * (S_CONNECT_RECV_BLACKLIST). Once the blacklist approves the * address we got from ATS, we send our CONNECT_ACK and go to * S_CONNECT_RECV_ACK. If we receive a SESSION_ACK, we go to * S_CONNECTED (and notify everyone about the new connection). If the * operation times out, we go to S_DISCONNECT. * * The other case is where we transmit a CONNECT message first. We * start with S_INIT_ATS. If we get an address, we enter * S_INIT_BLACKLIST and check the blacklist. If the blacklist is OK * with the connection, we actually send the CONNECT message and go to * state S_CONNECT_SENT. Once we receive a CONNECT_ACK, we go to * S_CONNECTED (and notify everyone about the new connection and send * back a SESSION_ACK). If the operation times out, we go to * S_DISCONNECT. * * If the session is in trouble (i.e. transport-level disconnect or * timeout), we go to S_RECONNECT_ATS where we ask ATS for a new * address (we don't notify anyone about the disconnect yet). Once we * have a new address, we go to S_RECONNECT_BLACKLIST to check the new * address against the blacklist. If the blacklist approves, we enter * S_RECONNECT_SENT and send a CONNECT message. If we receive a * CONNECT_ACK, we go to S_CONNECTED and nobody noticed that we had * trouble; we also send a SESSION_ACK at this time just in case. If * the operation times out, we go to S_DISCONNECT (and notify everyone * about the lost connection). * * If ATS decides to switch addresses while we have a normal * connection, we go to S_CONNECTED_SWITCHING_BLACKLIST to check the * new address against the blacklist. If the blacklist approves, we * go to S_CONNECTED_SWITCHING_CONNECT_SENT and send a * SESSION_CONNECT. If we get a SESSION_ACK back, we switch the * primary connection to the suggested alternative from ATS, go back * to S_CONNECTED and send a SESSION_ACK to the other peer just to be * sure. If the operation times out (or the blacklist disapproves), * we go to S_CONNECTED (and notify ATS that the given alternative * address is "invalid"). * * Once a session is in S_DISCONNECT, it is cleaned up and then goes * to (S_DISCONNECT_FINISHED). If we receive an explicit disconnect * request, we can go from any state to S_DISCONNECT, possibly after * generating disconnect notifications. * * Note that it is quite possible that while we are in any of these * states, we could receive a 'CONNECT' request from the other peer. * We then enter a 'weird' state where we pursue our own primary state * machine (as described above), but with the 'send_connect_ack' flag * set to 1. If our state machine allows us to send a 'CONNECT_ACK' * (because we have an acceptable address), we send the 'CONNECT_ACK' * and set the 'send_connect_ack' to 2. If we then receive a * 'SESSION_ACK', we go to 'S_CONNECTED' (and reset 'send_connect_ack' * to 0). * */ enum State { /** * fresh peer or completely disconnected */ S_NOT_CONNECTED = 0, /** * Asked to initiate connection, trying to get address from ATS */ S_INIT_ATS, /** * Asked to initiate connection, trying to get address approved * by blacklist. */ S_INIT_BLACKLIST, /** * Sent CONNECT message to other peer, waiting for CONNECT_ACK */ S_CONNECT_SENT, /** * Received a CONNECT, asking ATS about address suggestions. */ S_CONNECT_RECV_ATS, /** * Received CONNECT from other peer, got an address, checking with blacklist. */ S_CONNECT_RECV_BLACKLIST, /** * CONNECT request from other peer was SESSION_ACK'ed, waiting for * SESSION_ACK. */ S_CONNECT_RECV_ACK, /** * Got our CONNECT_ACK/SESSION_ACK, connection is up. */ S_CONNECTED, /** * Connection got into trouble, rest of the system still believes * it to be up, but we're getting a new address from ATS. */ S_RECONNECT_ATS, /** * Connection got into trouble, rest of the system still believes * it to be up; we are checking the new address against the blacklist. */ S_RECONNECT_BLACKLIST, /** * Sent CONNECT over new address (either by ATS telling us to switch * addresses or from RECONNECT_ATS); if this fails, we need to tell * the rest of the system about a disconnect. */ S_RECONNECT_SENT, /** * We have some primary connection, but ATS suggested we switch * to some alternative; we're now checking the alternative against * the blacklist. */ S_CONNECTED_SWITCHING_BLACKLIST, /** * We have some primary connection, but ATS suggested we switch * to some alternative; we now sent a CONNECT message for the * alternative session to the other peer and waiting for a * CONNECT_ACK to make this our primary connection. */ S_CONNECTED_SWITCHING_CONNECT_SENT, /** * Disconnect in progress (we're sending the DISCONNECT message to the * other peer; after that is finished, the state will be cleaned up). */ S_DISCONNECT, /** * We're finished with the disconnect; clean up state now! */ S_DISCONNECT_FINISHED }; /** * A possible address we could use to communicate with a neighbour. */ struct NeighbourAddress { /** * Active session for this address. */ struct Session *session; /** * Network-level address information. */ struct GNUNET_HELLO_Address *address; /** * Timestamp of the 'SESSION_CONNECT' message we sent to the other * peer for this address. Use to check that the ACK is in response * to our most recent 'CONNECT'. */ struct GNUNET_TIME_Absolute connect_timestamp; /** * Inbound bandwidth from ATS for this address. */ struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in; /** * Outbound bandwidth from ATS for this address. */ struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out; /** * Did we tell ATS that this is our 'active' address? */ int ats_active; }; /** * Entry in neighbours. */ struct NeighbourMapEntry { /** * Head of list of messages we would like to send to this peer; * must contain at most one message per client. */ struct MessageQueue *messages_head; /** * Tail of list of messages we would like to send to this peer; must * contain at most one message per client. */ struct MessageQueue *messages_tail; /** * Are we currently trying to send a message? If so, which one? */ struct MessageQueue *is_active; /** * Primary address we currently use to communicate with the neighbour. */ struct NeighbourAddress primary_address; /** * Alternative address currently under consideration for communicating * with the neighbour. */ struct NeighbourAddress alternative_address; /** * Identity of this neighbour. */ struct GNUNET_PeerIdentity id; /** * Main task that drives this peer (timeouts, keepalives, etc.). * Always runs the 'master_task'. */ GNUNET_SCHEDULER_TaskIdentifier task; /** * At what time should we sent the next keep-alive message? */ struct GNUNET_TIME_Absolute keep_alive_time; /** * At what time did we sent the last keep-alive message? Used * to calculate round-trip time ("latency"). */ struct GNUNET_TIME_Absolute last_keep_alive_time; /** * Timestamp we should include in our next CONNECT_ACK message. * (only valid if 'send_connect_ack' is GNUNET_YES). Used to build * our CONNECT_ACK message. */ struct GNUNET_TIME_Absolute connect_ack_timestamp; /** * Time where we should cut the connection (timeout) if we don't * make progress in the state machine (or get a KEEPALIVE_RESPONSE * if we are in S_CONNECTED). */ struct GNUNET_TIME_Absolute timeout; /** * Latest calculated latency value */ struct GNUNET_TIME_Relative latency; /** * Tracker for inbound bandwidth. */ struct GNUNET_BANDWIDTH_Tracker in_tracker; /** * How often has the other peer (recently) violated the inbound * traffic limit? Incremented by 10 per violation, decremented by 1 * per non-violation (for each time interval). */ unsigned int quota_violation_count; /** * The current state of the peer. */ enum State state; /** * Did we sent an KEEP_ALIVE message and are we expecting a response? */ int expect_latency_response; /** * Flag to set if we still need to send a CONNECT_ACK message to the other peer * (once we have an address to use and the peer has been allowed by our * blacklist). Set to 1 if we need to send a CONNECT_ACK. Set to 2 if we * did send a CONNECT_ACK and should go to 'S_CONNECTED' upon receiving * a 'SESSION_ACK' (regardless of what our own state machine might say). */ int send_connect_ack; }; /** * Context for blacklist checks and the 'handle_test_blacklist_cont' * function. Stores information about ongoing blacklist checks. */ struct BlackListCheckContext { /** * We keep blacklist checks in a DLL. */ struct BlackListCheckContext *next; /** * We keep blacklist checks in a DLL. */ struct BlackListCheckContext *prev; /** * Address that is being checked. */ struct NeighbourAddress na; /** * ATS information about the address. */ struct GNUNET_ATS_Information *ats; /** * Handle to the ongoing blacklist check. */ struct GST_BlacklistCheck *bc; /** * Size of the 'ats' array. */ uint32_t ats_count; }; /** * Hash map from peer identities to the respective 'struct NeighbourMapEntry'. */ static struct GNUNET_CONTAINER_MultiHashMap *neighbours; /** * We keep blacklist checks in a DLL so that we can find * the 'sessions' in their 'struct NeighbourAddress' if * a session goes down. */ static struct BlackListCheckContext *bc_head; /** * We keep blacklist checks in a DLL. */ static struct BlackListCheckContext *bc_tail; /** * Closure for connect_notify_cb, disconnect_notify_cb and address_change_cb */ static void *callback_cls; /** * Function to call when we connected to a neighbour. */ static GNUNET_TRANSPORT_NotifyConnect connect_notify_cb; /** * Function to call when we disconnected from a neighbour. */ static GNUNET_TRANSPORT_NotifyDisconnect disconnect_notify_cb; /** * Function to call when we changed an active address of a neighbour. */ static GNUNET_TRANSPORT_PeerIterateCallback address_change_cb; /** * counter for connected neighbours */ static unsigned int neighbours_connected; /** * Number of bytes we have currently queued for transmission. */ static unsigned long long bytes_in_send_queue; /** * Lookup a neighbour entry in the neighbours hash map. * * @param pid identity of the peer to look up * @return the entry, NULL if there is no existing record */ static struct NeighbourMapEntry * lookup_neighbour (const struct GNUNET_PeerIdentity *pid) { if (NULL == neighbours) return NULL; return GNUNET_CONTAINER_multihashmap_get (neighbours, &pid->hashPubKey); } static const char * print_state (int state) { switch (state) { case S_NOT_CONNECTED: return "S_NOT_CONNECTED"; break; case S_INIT_ATS: return "S_INIT_ATS"; break; case S_INIT_BLACKLIST: return "S_INIT_BLACKLIST"; break; case S_CONNECT_SENT: return "S_CONNECT_SENT"; break; case S_CONNECT_RECV_ATS: return "S_CONNECT_RECV_ATS"; break; case S_CONNECT_RECV_BLACKLIST: return "S_CONNECT_RECV_BLACKLIST"; break; case S_CONNECT_RECV_ACK: return "S_CONNECT_RECV_ACK"; break; case S_CONNECTED: return "S_CONNECTED"; break; case S_RECONNECT_ATS: return "S_RECONNECT_ATS"; break; case S_RECONNECT_BLACKLIST: return "S_RECONNECT_BLACKLIST"; break; case S_RECONNECT_SENT: return "S_RECONNECT_SENT"; break; case S_CONNECTED_SWITCHING_BLACKLIST: return "S_CONNECTED_SWITCHING_BLACKLIST"; break; case S_CONNECTED_SWITCHING_CONNECT_SENT: return "S_CONNECTED_SWITCHING_CONNECT_SENT"; break; case S_DISCONNECT: return "S_DISCONNECT"; break; case S_DISCONNECT_FINISHED: return "S_DISCONNECT_FINISHED"; break; default: return "UNDEFINED"; GNUNET_break (0); break; } GNUNET_break (0); return "UNDEFINED"; } /** * Test if we're connected to the given peer. * * @param n neighbour entry of peer to test * @return GNUNET_YES if we are connected, GNUNET_NO if not */ static int test_connected (struct NeighbourMapEntry *n) { if (NULL == n) return GNUNET_NO; switch (n->state) { case S_NOT_CONNECTED: case S_INIT_ATS: case S_INIT_BLACKLIST: case S_CONNECT_SENT: case S_CONNECT_RECV_ATS: case S_CONNECT_RECV_BLACKLIST: case S_CONNECT_RECV_ACK: return GNUNET_NO; case S_CONNECTED: case S_RECONNECT_ATS: case S_RECONNECT_BLACKLIST: case S_RECONNECT_SENT: case S_CONNECTED_SWITCHING_BLACKLIST: case S_CONNECTED_SWITCHING_CONNECT_SENT: return GNUNET_YES; case S_DISCONNECT: case S_DISCONNECT_FINISHED: return GNUNET_NO; default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state)); GNUNET_break (0); break; } return GNUNET_SYSERR; } /** * Send information about a new outbound quota to our clients. * * @param target affected peer * @param quota new quota */ static void send_outbound_quota (const struct GNUNET_PeerIdentity *target, struct GNUNET_BANDWIDTH_Value32NBO quota) { struct QuotaSetMessage q_msg; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending outbound quota of %u Bps for peer `%s' to all clients\n", ntohl (quota.value__), GNUNET_i2s (target)); q_msg.header.size = htons (sizeof (struct QuotaSetMessage)); q_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA); q_msg.quota = quota; q_msg.peer = (*target); GST_clients_broadcast (&q_msg.header, GNUNET_NO); } /** * We don't need a given neighbour address any more. * Release its resources and give appropriate notifications * to ATS and other subsystems. * * @param na address we are done with; 'na' itself must NOT be 'free'd, only the contents! */ static void free_address (struct NeighbourAddress *na) { if (GNUNET_YES == na->ats_active) { GST_validation_set_address_use (na->address, na->session, GNUNET_NO, __LINE__); GNUNET_ATS_address_in_use (GST_ats, na->address, na->session, GNUNET_NO); } na->ats_active = GNUNET_NO; if (NULL != na->address) { GNUNET_HELLO_address_free (na->address); na->address = NULL; } na->session = NULL; } /** * Initialize the 'struct NeighbourAddress'. * * @param na neighbour address to initialize * @param address address of the other peer, NULL if other peer * connected to us * @param session session to use (or NULL, in which case an * address must be setup) * @param bandwidth_in inbound quota to be used when connection is up * @param bandwidth_out outbound quota to be used when connection is up * @param is_active GNUNET_YES to mark this as the active address with ATS */ static void set_address (struct NeighbourAddress *na, const struct GNUNET_HELLO_Address *address, struct Session *session, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out, int is_active) { struct GNUNET_TRANSPORT_PluginFunctions *papi; if (NULL == (papi = GST_plugins_find (address->transport_name))) { GNUNET_break (0); return; } if (session == na->session) { na->bandwidth_in = bandwidth_in; na->bandwidth_out = bandwidth_out; if (is_active != na->ats_active) { na->ats_active = is_active; GNUNET_ATS_address_in_use (GST_ats, na->address, na->session, is_active); GST_validation_set_address_use (na->address, na->session, is_active, __LINE__); } if (GNUNET_YES == is_active) { /* FIXME: is this the right place to set quotas? */ GST_neighbours_set_incoming_quota (&address->peer, bandwidth_in); send_outbound_quota (&address->peer, bandwidth_out); } return; } free_address (na); if (NULL == session) session = papi->get_session (papi->cls, address); if (NULL == session) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to obtain new session for peer `%s' and address '%s'\n", GNUNET_i2s (&address->peer), GST_plugins_a2s (address)); GNUNET_ATS_address_destroyed (GST_ats, address, NULL); return; } na->address = GNUNET_HELLO_address_copy (address); na->bandwidth_in = bandwidth_in; na->bandwidth_out = bandwidth_out; na->session = session; na->ats_active = is_active; if (GNUNET_YES == is_active) { /* Telling ATS about new session */ GNUNET_ATS_address_update (GST_ats, na->address, na->session, NULL, 0); GNUNET_ATS_address_in_use (GST_ats, na->address, na->session, GNUNET_YES); GST_validation_set_address_use (na->address, na->session, GNUNET_YES, __LINE__); /* FIXME: is this the right place to set quotas? */ GST_neighbours_set_incoming_quota (&address->peer, bandwidth_in); send_outbound_quota (&address->peer, bandwidth_out); } } /** * Free a neighbour map entry. * * @param n entry to free * @param keep_sessions GNUNET_NO to tell plugin to terminate sessions, * GNUNET_YES to keep all sessions */ static void free_neighbour (struct NeighbourMapEntry *n, int keep_sessions) { struct MessageQueue *mq; struct GNUNET_TRANSPORT_PluginFunctions *papi; n->is_active = NULL; /* always free'd by its own continuation! */ /* fail messages currently in the queue */ while (NULL != (mq = n->messages_head)) { GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq); if (NULL != mq->cont) mq->cont (mq->cont_cls, GNUNET_SYSERR); GNUNET_free (mq); } /* It is too late to send other peer disconnect notifications, but at least internally we need to get clean... */ if (GNUNET_YES == test_connected (n)) { GNUNET_STATISTICS_set (GST_stats, gettext_noop ("# peers connected"), --neighbours_connected, GNUNET_NO); disconnect_notify_cb (callback_cls, &n->id); } /* FIXME-PLUGIN-API: This does not seem to guarantee that all transport sessions eventually get killed due to inactivity; they MUST have their own timeout logic (but at least TCP doesn't have one yet). Are we sure that EVERY 'session' of a plugin is actually cleaned up this way!? Note that if we are switching between two TCP sessions to the same peer, the existing plugin API gives us not even the means to selectively kill only one of them! Killing all sessions like this seems to be very, very wrong. */ if ((GNUNET_NO == keep_sessions) && (NULL != n->primary_address.address) && (NULL != (papi = GST_plugins_find (n->primary_address.address->transport_name)))) papi->disconnect (papi->cls, &n->id); n->state = S_DISCONNECT_FINISHED; GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (neighbours, &n->id.hashPubKey, n)); /* cut transport-level connection */ free_address (&n->primary_address); free_address (&n->alternative_address); // FIXME-ATS-API: we might want to be more specific about // which states we do this from in the future (ATS should // have given us a 'suggest_address' handle, and if we have // such a handle, we should cancel the operation here! GNUNET_ATS_suggest_address_cancel (GST_ats, &n->id); if (GNUNET_SCHEDULER_NO_TASK != n->task) { GNUNET_SCHEDULER_cancel (n->task); n->task = GNUNET_SCHEDULER_NO_TASK; } /* free rest of memory */ GNUNET_free (n); } /** * Transmit a message using the current session of the given * neighbour. * * @param n entry for the recipient * @param msgbuf buffer to transmit * @param msgbuf_size number of bytes in buffer * @param priority transmission priority * @param timeout transmission timeout * @param cont continuation to call when finished (can be NULL) * @param cont_cls closure for cont */ static void send_with_session (struct NeighbourMapEntry *n, const char *msgbuf, size_t msgbuf_size, uint32_t priority, struct GNUNET_TIME_Relative timeout, GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) { struct GNUNET_TRANSPORT_PluginFunctions *papi; GNUNET_assert (n->primary_address.session != NULL); if ( ( (NULL == (papi = GST_plugins_find (n->primary_address.address->transport_name))) || (-1 == papi->send (papi->cls, n->primary_address.session, msgbuf, msgbuf_size, priority, timeout, cont, cont_cls))) && (NULL != cont) ) cont (cont_cls, &n->id, GNUNET_SYSERR); GNUNET_break (NULL != papi); } /** * Master task run for every neighbour. Performs all of the time-related * activities (keep alive, send next message, disconnect if idle, finish * clean up after disconnect). * * @param cls the 'struct NeighbourMapEntry' for which we are running * @param tc scheduler context (unused) */ static void master_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Function called when the 'DISCONNECT' message has been sent by the * plugin. Frees the neighbour --- if the entry still exists. * * @param cls NULL * @param target identity of the neighbour that was disconnected * @param result GNUNET_OK if the disconnect got out successfully */ static void send_disconnect_cont (void *cls, const struct GNUNET_PeerIdentity *target, int result) { struct NeighbourMapEntry *n; n = lookup_neighbour (target); if (NULL == n) return; /* already gone */ if (S_DISCONNECT != n->state) return; /* have created a fresh entry since */ n->state = S_DISCONNECT; if (GNUNET_SCHEDULER_NO_TASK != n->task) GNUNET_SCHEDULER_cancel (n->task); n->task = GNUNET_SCHEDULER_add_now (&master_task, n); } /** * Transmit a DISCONNECT message to the other peer. * * @param n neighbour to send DISCONNECT message. */ static void send_disconnect (struct NeighbourMapEntry *n) { struct SessionDisconnectMessage disconnect_msg; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending DISCONNECT message to peer `%4s'\n", GNUNET_i2s (&n->id)); disconnect_msg.header.size = htons (sizeof (struct SessionDisconnectMessage)); disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT); disconnect_msg.reserved = htonl (0); disconnect_msg.purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sizeof (struct GNUNET_TIME_AbsoluteNBO)); disconnect_msg.purpose.purpose = htonl (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT); disconnect_msg.timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); disconnect_msg.public_key = GST_my_public_key; GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_rsa_sign (GST_my_private_key, &disconnect_msg.purpose, &disconnect_msg.signature)); send_with_session (n, (const char *) &disconnect_msg, sizeof (disconnect_msg), UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, &send_disconnect_cont, NULL); GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# DISCONNECT messages sent"), 1, GNUNET_NO); } /** * Disconnect from the given neighbour, clean up the record. * * @param n neighbour to disconnect from */ static void disconnect_neighbour (struct NeighbourMapEntry *n) { /* depending on state, notify neighbour and/or upper layers of this peer about disconnect */ switch (n->state) { case S_NOT_CONNECTED: case S_INIT_ATS: case S_INIT_BLACKLIST: /* other peer is completely unaware of us, no need to send DISCONNECT */ n->state = S_DISCONNECT_FINISHED; free_neighbour (n, GNUNET_NO); return; case S_CONNECT_SENT: send_disconnect (n); n->state = S_DISCONNECT; break; case S_CONNECT_RECV_ATS: case S_CONNECT_RECV_BLACKLIST: /* we never ACK'ed the other peer's request, no need to send DISCONNECT */ n->state = S_DISCONNECT_FINISHED; free_neighbour (n, GNUNET_NO); return; case S_CONNECT_RECV_ACK: /* we DID ACK the other peer's request, must send DISCONNECT */ send_disconnect (n); n->state = S_DISCONNECT; break; case S_CONNECTED: case S_RECONNECT_BLACKLIST: case S_RECONNECT_SENT: case S_CONNECTED_SWITCHING_BLACKLIST: case S_CONNECTED_SWITCHING_CONNECT_SENT: /* we are currently connected, need to send disconnect and do internal notifications and update statistics */ send_disconnect (n); GNUNET_STATISTICS_set (GST_stats, gettext_noop ("# peers connected"), --neighbours_connected, GNUNET_NO); disconnect_notify_cb (callback_cls, &n->id); n->state = S_DISCONNECT; break; case S_RECONNECT_ATS: /* ATS address request timeout, disconnect without sending disconnect message */ GNUNET_STATISTICS_set (GST_stats, gettext_noop ("# peers connected"), --neighbours_connected, GNUNET_NO); disconnect_notify_cb (callback_cls, &n->id); n->state = S_DISCONNECT; break; case S_DISCONNECT: /* already disconnected, ignore */ break; case S_DISCONNECT_FINISHED: /* already cleaned up, how did we get here!? */ GNUNET_assert (0); break; default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state)); GNUNET_break (0); break; } /* schedule timeout to clean up */ if (GNUNET_SCHEDULER_NO_TASK != n->task) GNUNET_SCHEDULER_cancel (n->task); n->task = GNUNET_SCHEDULER_add_delayed (DISCONNECT_SENT_TIMEOUT, &master_task, n); } /** * We're done with our transmission attempt, continue processing. * * @param cls the 'struct MessageQueue' of the message * @param receiver intended receiver * @param success whether it worked or not */ static void transmit_send_continuation (void *cls, const struct GNUNET_PeerIdentity *receiver, int success) { struct MessageQueue *mq = cls; struct NeighbourMapEntry *n; if (NULL == (n = lookup_neighbour (receiver))) { GNUNET_free (mq); return; /* disconnect or other error while transmitting, can happen */ } if (n->is_active == mq) { /* this is still "our" neighbour, remove us from its queue and allow it to send the next message now */ n->is_active = NULL; if (GNUNET_SCHEDULER_NO_TASK != n->task) GNUNET_SCHEDULER_cancel (n->task); n->task = GNUNET_SCHEDULER_add_now (&master_task, n); } GNUNET_assert (bytes_in_send_queue >= mq->message_buf_size); bytes_in_send_queue -= mq->message_buf_size; GNUNET_STATISTICS_set (GST_stats, gettext_noop ("# bytes in message queue for other peers"), bytes_in_send_queue, GNUNET_NO); if (GNUNET_OK == success) GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# messages transmitted to other peers"), 1, GNUNET_NO); else GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# transmission failures for messages to other peers"), 1, GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message to `%s' of type %u was a %s\n", GNUNET_i2s (receiver), ntohs (((struct GNUNET_MessageHeader *) mq->message_buf)->type), (success == GNUNET_OK) ? "success" : "FAILURE"); if (NULL != mq->cont) mq->cont (mq->cont_cls, success); GNUNET_free (mq); } /** * Check the message list for the given neighbour and if we can * send a message, do so. This function should only be called * if the connection is at least generally ready for transmission. * While we will only send one message at a time, no bandwidth * quota management is performed here. If a message was given to * the plugin, the continuation will automatically re-schedule * the 'master' task once the next message might be transmitted. * * @param n target peer for which to transmit */ static void try_transmission_to_peer (struct NeighbourMapEntry *n) { struct MessageQueue *mq; struct GNUNET_TIME_Relative timeout; if (NULL == n->primary_address.address) { /* no address, why are we here? */ GNUNET_break (0); return; } if ((0 == n->primary_address.address->address_length) && (NULL == n->primary_address.session)) { /* no address, why are we here? */ GNUNET_break (0); return; } if (NULL != n->is_active) { /* transmission already pending */ return; } /* timeout messages from the queue that are past their due date */ while (NULL != (mq = n->messages_head)) { timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout); if (timeout.rel_value > 0) break; GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# messages timed out while in transport queue"), 1, GNUNET_NO); GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq); n->is_active = mq; transmit_send_continuation (mq, &n->id, GNUNET_SYSERR); /* timeout */ } if (NULL == mq) return; /* no more messages */ GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq); n->is_active = mq; send_with_session (n, mq->message_buf, mq->message_buf_size, 0 /* priority */, timeout, &transmit_send_continuation, mq); } /** * Send keepalive message to the neighbour. Must only be called * if we are on 'connected' state. Will internally determine * if a keepalive is truly needed (so can always be called). * * @param n neighbour that went idle and needs a keepalive */ static void send_keepalive (struct NeighbourMapEntry *n) { struct GNUNET_MessageHeader m; GNUNET_assert (S_CONNECTED == n->state); if (GNUNET_TIME_absolute_get_remaining (n->keep_alive_time).rel_value > 0) return; /* no keepalive needed at this time */ m.size = htons (sizeof (struct GNUNET_MessageHeader)); m.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE); send_with_session (n, (const void *) &m, sizeof (m), UINT32_MAX /* priority */, KEEPALIVE_FREQUENCY, NULL, NULL); GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# keepalives sent"), 1, GNUNET_NO); n->expect_latency_response = GNUNET_YES; n->last_keep_alive_time = GNUNET_TIME_absolute_get (); n->keep_alive_time = GNUNET_TIME_relative_to_absolute (KEEPALIVE_FREQUENCY); } /** * Keep the connection to the given neighbour alive longer, * we received a KEEPALIVE (or equivalent); send a response. * * @param neighbour neighbour to keep alive (by sending keep alive response) */ void GST_neighbours_keepalive (const struct GNUNET_PeerIdentity *neighbour) { struct NeighbourMapEntry *n; struct GNUNET_MessageHeader m; if (NULL == (n = lookup_neighbour (neighbour))) { GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# KEEPALIVE messages discarded (peer unknown)"), 1, GNUNET_NO); return; } if (NULL == n->primary_address.session) { GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# KEEPALIVE messages discarded (no session)"), 1, GNUNET_NO); return; } /* send reply to allow neighbour to measure latency */ m.size = htons (sizeof (struct GNUNET_MessageHeader)); m.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE); send_with_session(n, (const void *) &m, sizeof (m), UINT32_MAX /* priority */, KEEPALIVE_FREQUENCY, NULL, NULL); } /** * We received a KEEP_ALIVE_RESPONSE message and use this to calculate * latency to this peer. Pass the updated information (existing ats * plus calculated latency) to ATS. * * @param neighbour neighbour to keep alive * @param ats performance data * @param ats_count number of entries in ats */ void GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { struct NeighbourMapEntry *n; uint32_t latency; struct GNUNET_ATS_Information ats_new[ats_count + 1]; if (NULL == (n = lookup_neighbour (neighbour))) { GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# KEEPALIVE_RESPONSE messages discarded (not connected)"), 1, GNUNET_NO); return; } if ( (S_CONNECTED != n->state) || (GNUNET_YES != n->expect_latency_response) ) { GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# KEEPALIVE_RESPONSE messages discarded (not expected)"), 1, GNUNET_NO); return; } n->expect_latency_response = GNUNET_NO; n->latency = GNUNET_TIME_absolute_get_duration (n->last_keep_alive_time); n->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Latency for peer `%s' is %llu ms\n", GNUNET_i2s (&n->id), n->latency.rel_value); memcpy (ats_new, ats, sizeof (struct GNUNET_ATS_Information) * ats_count); /* append latency */ ats_new[ats_count].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY); if (n->latency.rel_value > UINT32_MAX) latency = UINT32_MAX; else latency = n->latency.rel_value; ats_new[ats_count].value = htonl (latency); GNUNET_ATS_address_update (GST_ats, n->primary_address.address, n->primary_address.session, ats_new, ats_count + 1); } /** * We have received a message from the given sender. How long should * we delay before receiving more? (Also used to keep the peer marked * as live). * * @param sender sender of the message * @param size size of the message * @param do_forward set to GNUNET_YES if the message should be forwarded to clients * GNUNET_NO if the neighbour is not connected or violates the quota, * GNUNET_SYSERR if the connection is not fully up yet * @return how long to wait before reading more from this sender */ struct GNUNET_TIME_Relative GST_neighbours_calculate_receive_delay (const struct GNUNET_PeerIdentity *sender, ssize_t size, int *do_forward) { struct NeighbourMapEntry *n; struct GNUNET_TIME_Relative ret; if (NULL == neighbours) { *do_forward = GNUNET_NO; return GNUNET_TIME_UNIT_FOREVER_REL; /* This can happen during shutdown */ } if (NULL == (n = lookup_neighbour (sender))) { GST_neighbours_try_connect (sender); if (NULL == (n = lookup_neighbour (sender))) { GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# messages discarded due to lack of neighbour record"), 1, GNUNET_NO); *do_forward = GNUNET_NO; return GNUNET_TIME_UNIT_ZERO; } } if (! test_connected (n)) { *do_forward = GNUNET_SYSERR; return GNUNET_TIME_UNIT_ZERO; } if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, size)) { n->quota_violation_count++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Bandwidth quota (%u b/s) violation detected (total of %u).\n", n->in_tracker.available_bytes_per_s__, n->quota_violation_count); /* Discount 32k per violation */ GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, -32 * 1024); } else { if (n->quota_violation_count > 0) { /* try to add 32k back */ GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, 32 * 1024); n->quota_violation_count--; } } if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD) { GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# bandwidth quota violations by other peers"), 1, GNUNET_NO); *do_forward = GNUNET_NO; return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT; } *do_forward = GNUNET_YES; ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 32 * 1024); if (ret.rel_value > 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n", (unsigned long long) n->in_tracker. consumption_since_last_update__, (unsigned int) n->in_tracker.available_bytes_per_s__, (unsigned long long) ret.rel_value); GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# ms throttling suggested"), (int64_t) ret.rel_value, GNUNET_NO); } return ret; } /** * Transmit a message to the given target using the active connection. * * @param target destination * @param msg message to send * @param msg_size number of bytes in msg * @param timeout when to fail with timeout * @param cont function to call when done * @param cont_cls closure for 'cont' */ void GST_neighbours_send (const struct GNUNET_PeerIdentity *target, const void *msg, size_t msg_size, struct GNUNET_TIME_Relative timeout, GST_NeighbourSendContinuation cont, void *cont_cls) { struct NeighbourMapEntry *n; struct MessageQueue *mq; /* All ove these cases should never happen; they are all API violations. But we check anyway, just to be sure. */ if (NULL == (n = lookup_neighbour (target))) { GNUNET_break (0); if (NULL != cont) cont (cont_cls, GNUNET_SYSERR); return; } if (GNUNET_YES != test_connected (n)) { GNUNET_break (0); if (NULL != cont) cont (cont_cls, GNUNET_SYSERR); return; } bytes_in_send_queue += msg_size; GNUNET_STATISTICS_set (GST_stats, gettext_noop ("# bytes in message queue for other peers"), bytes_in_send_queue, GNUNET_NO); mq = GNUNET_malloc (sizeof (struct MessageQueue) + msg_size); mq->cont = cont; mq->cont_cls = cont_cls; memcpy (&mq[1], msg, msg_size); mq->message_buf = (const char *) &mq[1]; mq->message_buf_size = msg_size; mq->timeout = GNUNET_TIME_relative_to_absolute (timeout); GNUNET_CONTAINER_DLL_insert_tail (n->messages_head, n->messages_tail, mq); if ( (NULL != n->is_active) || ( (NULL == n->primary_address.session) && (NULL == n->primary_address.address)) ) return; if (GNUNET_SCHEDULER_NO_TASK != n->task) GNUNET_SCHEDULER_cancel (n->task); n->task = GNUNET_SCHEDULER_add_now (&master_task, n); } /** * Send a SESSION_CONNECT message via the given address. * * @param na address to use */ static void send_session_connect (struct NeighbourAddress *na) { struct GNUNET_TRANSPORT_PluginFunctions *papi; struct SessionConnectMessage connect_msg; if (NULL == (papi = GST_plugins_find (na->address->transport_name))) { GNUNET_break (0); return; } if (NULL == na->session) na->session = papi->get_session (papi->cls, na->address); if (NULL == na->session) { GNUNET_break (0); return; } na->connect_timestamp = GNUNET_TIME_absolute_get (); connect_msg.header.size = htons (sizeof (struct SessionConnectMessage)); connect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT); connect_msg.reserved = htonl (0); connect_msg.timestamp = GNUNET_TIME_absolute_hton (na->connect_timestamp); (void) papi->send (papi->cls, na->session, (const char *) &connect_msg, sizeof (struct SessionConnectMessage), UINT_MAX, GNUNET_TIME_UNIT_FOREVER_REL, NULL, NULL); } /** * Send a SESSION_CONNECT_ACK message via the given address. * * @param address address to use * @param session session to use * @param timestamp timestamp to use for the ACK message */ static void send_session_connect_ack_message (const struct GNUNET_HELLO_Address *address, struct Session *session, struct GNUNET_TIME_Absolute timestamp) { struct GNUNET_TRANSPORT_PluginFunctions *papi; struct SessionConnectMessage connect_msg; if (NULL == (papi = GST_plugins_find (address->transport_name))) { GNUNET_break (0); return; } if (NULL == session) session = papi->get_session (papi->cls, address); if (NULL == session) { GNUNET_break (0); return; } connect_msg.header.size = htons (sizeof (struct SessionConnectMessage)); connect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT_ACK); connect_msg.reserved = htonl (0); connect_msg.timestamp = GNUNET_TIME_absolute_hton (timestamp); (void) papi->send (papi->cls, session, (const char *) &connect_msg, sizeof (struct SessionConnectMessage), UINT_MAX, GNUNET_TIME_UNIT_FOREVER_REL, NULL, NULL); } /** * Create a fresh entry in the neighbour map for the given peer * * @param peer peer to create an entry for * @return new neighbour map entry */ static struct NeighbourMapEntry * setup_neighbour (const struct GNUNET_PeerIdentity *peer) { struct NeighbourMapEntry *n; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating new neighbour entry for `%s'\n", GNUNET_i2s (peer)); n = GNUNET_malloc (sizeof (struct NeighbourMapEntry)); n->id = *peer; n->state = S_NOT_CONNECTED; n->latency = GNUNET_TIME_UNIT_FOREVER_REL; GNUNET_BANDWIDTH_tracker_init (&n->in_tracker, GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT, MAX_BANDWIDTH_CARRY_S); n->task = GNUNET_SCHEDULER_add_now (&master_task, n); GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (neighbours, &n->id.hashPubKey, n, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); return n; } /** * Check if the two given addresses are the same. * Actually only checks if the sessions are non-NULL * (which they should be) and then if they are identical; * the actual addresses don't matter if the session * pointers match anyway, and we must have session pointers * at this time. * * @param a1 first address to compare * @param a2 other address to compare * @return GNUNET_NO if the addresses do not match, GNUNET_YES if they do match */ static int address_matches (const struct NeighbourAddress *a1, const struct NeighbourAddress *a2) { if ( (NULL == a1->session) || (NULL == a2->session) ) { GNUNET_break (0); return 0; } return (a1->session == a2->session) ? GNUNET_YES : GNUNET_NO; } /** * Try to create a connection to the given target (eventually). * * @param target peer to try to connect to */ void GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target) { struct NeighbourMapEntry *n; if (NULL == neighbours) return; /* during shutdown, do nothing */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asked to connect to peer `%s'\n", GNUNET_i2s (target)); if (0 == memcmp (target, &GST_my_identity, sizeof (struct GNUNET_PeerIdentity))) { /* refuse to connect to myself */ /* FIXME: can this happen? Is this not an API violation? */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Refusing to try to connect to myself.\n"); return; } n = lookup_neighbour (target); if (NULL != n) { switch (n->state) { case S_NOT_CONNECTED: /* this should not be possible */ GNUNET_break (0); free_neighbour (n, GNUNET_NO); break; case S_INIT_ATS: case S_INIT_BLACKLIST: case S_CONNECT_SENT: case S_CONNECT_RECV_ATS: case S_CONNECT_RECV_BLACKLIST: case S_CONNECT_RECV_ACK: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ignoring request to try to connect to `%s', already trying!\n", GNUNET_i2s (target)); return; /* already trying */ case S_CONNECTED: case S_RECONNECT_ATS: case S_RECONNECT_BLACKLIST: case S_RECONNECT_SENT: case S_CONNECTED_SWITCHING_BLACKLIST: case S_CONNECTED_SWITCHING_CONNECT_SENT: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ignoring request to try to connect, already connected to `%s'!\n", GNUNET_i2s (target)); return; /* already connected */ case S_DISCONNECT: /* get rid of remains, ready to re-try immediately */ free_neighbour (n, GNUNET_NO); break; case S_DISCONNECT_FINISHED: /* should not be possible */ GNUNET_assert (0); default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state)); GNUNET_break (0); free_neighbour (n, GNUNET_NO); break; } } n = setup_neighbour (target); n->state = S_INIT_ATS; n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT); GNUNET_ATS_reset_backoff (GST_ats, target); GNUNET_ATS_suggest_address (GST_ats, target); } /** * Function called with the result of a blacklist check. * * @param cls closure with the 'struct BlackListCheckContext' * @param peer peer this check affects * @param result GNUNET_OK if the address is allowed */ static void handle_test_blacklist_cont (void *cls, const struct GNUNET_PeerIdentity *peer, int result) { struct BlackListCheckContext *bcc = cls; struct NeighbourMapEntry *n; bcc->bc = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection to new address of peer `%s' based on blacklist is `%s'\n", GNUNET_i2s (peer), (GNUNET_OK == result) ? "allowed" : "FORBIDDEN"); if (GNUNET_OK == result) { /* valid new address, let ATS know! */ GNUNET_ATS_address_update (GST_ats, bcc->na.address, bcc->na.session, bcc->ats, bcc->ats_count); } if (NULL == (n = lookup_neighbour (peer))) goto cleanup; /* nobody left to care about new address */ switch (n->state) { case S_NOT_CONNECTED: /* this should not be possible */ GNUNET_break (0); free_neighbour (n, GNUNET_NO); break; case S_INIT_ATS: /* still waiting on ATS suggestion */ break; case S_INIT_BLACKLIST: /* check if the address the blacklist was fine with matches ATS suggestion, if so, we can move on! */ if ( (GNUNET_OK == result) && (1 == n->send_connect_ack) ) { n->send_connect_ack = 2; send_session_connect_ack_message (bcc->na.address, bcc->na.session, n->connect_ack_timestamp); } if (GNUNET_YES != address_matches (&bcc->na, &n->primary_address)) break; /* result for an address we currently don't care about */ if (GNUNET_OK == result) { n->timeout = GNUNET_TIME_relative_to_absolute (SETUP_CONNECTION_TIMEOUT); n->state = S_CONNECT_SENT; send_session_connect (&n->primary_address); } else { // FIXME: should also possibly destroy session with plugin!? GNUNET_ATS_address_destroyed (GST_ats, bcc->na.address, NULL); free_address (&n->primary_address); n->state = S_INIT_ATS; n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT); // FIXME: do we need to ask ATS again for suggestions? GNUNET_ATS_suggest_address (GST_ats, &n->id); } break; case S_CONNECT_SENT: /* waiting on CONNECT_ACK, send ACK if one is pending */ if ( (GNUNET_OK == result) && (1 == n->send_connect_ack) ) { n->send_connect_ack = 2; send_session_connect_ack_message (n->primary_address.address, n->primary_address.session, n->connect_ack_timestamp); } break; case S_CONNECT_RECV_ATS: /* still waiting on ATS suggestion, don't care about blacklist */ break; case S_CONNECT_RECV_BLACKLIST: if (GNUNET_YES != address_matches (&bcc->na, &n->primary_address)) break; /* result for an address we currently don't care about */ if (GNUNET_OK == result) { n->timeout = GNUNET_TIME_relative_to_absolute (SETUP_CONNECTION_TIMEOUT); n->state = S_CONNECT_RECV_ACK; send_session_connect_ack_message (bcc->na.address, bcc->na.session, n->connect_ack_timestamp); if (1 == n->send_connect_ack) n->send_connect_ack = 2; } else { // FIXME: should also possibly destroy session with plugin!? GNUNET_ATS_address_destroyed (GST_ats, bcc->na.address, NULL); free_address (&n->primary_address); n->state = S_INIT_ATS; n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT); // FIXME: do we need to ask ATS again for suggestions? GNUNET_ATS_reset_backoff (GST_ats, peer); GNUNET_ATS_suggest_address (GST_ats, &n->id); } break; case S_CONNECT_RECV_ACK: /* waiting on SESSION_ACK, send ACK if one is pending */ if ( (GNUNET_OK == result) && (1 == n->send_connect_ack) ) { n->send_connect_ack = 2; send_session_connect_ack_message (n->primary_address.address, n->primary_address.session, n->connect_ack_timestamp); } break; case S_CONNECTED: /* already connected, don't care about blacklist */ break; case S_RECONNECT_ATS: /* still waiting on ATS suggestion, don't care about blacklist */ break; case S_RECONNECT_BLACKLIST: if ( (GNUNET_OK == result) && (1 == n->send_connect_ack) ) { n->send_connect_ack = 2; send_session_connect_ack_message (bcc->na.address, bcc->na.session, n->connect_ack_timestamp); } if (GNUNET_YES != address_matches (&bcc->na, &n->primary_address)) break; /* result for an address we currently don't care about */ if (GNUNET_OK == result) { send_session_connect (&n->primary_address); n->timeout = GNUNET_TIME_relative_to_absolute (FAST_RECONNECT_TIMEOUT); n->state = S_RECONNECT_SENT; } else { GNUNET_ATS_address_destroyed (GST_ats, bcc->na.address, NULL); n->state = S_RECONNECT_ATS; n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT); // FIXME: do we need to ask ATS again for suggestions? GNUNET_ATS_suggest_address (GST_ats, &n->id); } break; case S_RECONNECT_SENT: /* waiting on CONNECT_ACK, don't care about blacklist */ if ( (GNUNET_OK == result) && (1 == n->send_connect_ack) ) { n->send_connect_ack = 2; send_session_connect_ack_message (n->primary_address.address, n->primary_address.session, n->connect_ack_timestamp); } break; case S_CONNECTED_SWITCHING_BLACKLIST: if (GNUNET_YES != address_matches (&bcc->na, &n->alternative_address)) break; /* result for an address we currently don't care about */ if (GNUNET_OK == result) { send_session_connect (&n->alternative_address); n->state = S_CONNECTED_SWITCHING_CONNECT_SENT; } else { GNUNET_ATS_address_destroyed (GST_ats, bcc->na.address, NULL); free_address (&n->alternative_address); n->state = S_CONNECTED; } break; case S_CONNECTED_SWITCHING_CONNECT_SENT: /* waiting on CONNECT_ACK, don't care about blacklist */ if ( (GNUNET_OK == result) && (1 == n->send_connect_ack) ) { n->send_connect_ack = 2; send_session_connect_ack_message (n->primary_address.address, n->primary_address.session, n->connect_ack_timestamp); } break; case S_DISCONNECT: /* Nothing to do here, ATS will already do what can be done */ break; case S_DISCONNECT_FINISHED: /* should not be possible */ GNUNET_assert (0); break; default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state)); GNUNET_break (0); free_neighbour (n, GNUNET_NO); break; } cleanup: GNUNET_HELLO_address_free (bcc->na.address); GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bcc); GNUNET_free (bcc); } /** * We want to know if connecting to a particular peer via * a particular address is allowed. Check it! * * @param peer identity of the peer to switch the address for * @param ts time at which the check was initiated * @param address address of the other peer, NULL if other peer * connected to us * @param session session to use (or NULL) * @param ats performance data * @param ats_count number of entries in ats (excluding 0-termination) */ static void check_blacklist (const struct GNUNET_PeerIdentity *peer, struct GNUNET_TIME_Absolute ts, const struct GNUNET_HELLO_Address *address, struct Session *session, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { struct BlackListCheckContext *bcc; struct GST_BlacklistCheck *bc; bcc = GNUNET_malloc (sizeof (struct BlackListCheckContext) + sizeof (struct GNUNET_ATS_Information) * ats_count); bcc->ats_count = ats_count; bcc->na.address = GNUNET_HELLO_address_copy (address); bcc->na.session = session; bcc->na.connect_timestamp = ts; bcc->ats = (struct GNUNET_ATS_Information *) &bcc[1]; memcpy (bcc->ats, ats, sizeof (struct GNUNET_ATS_Information) * ats_count); GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bcc); if (NULL != (bc = GST_blacklist_test_allowed (peer, address->transport_name, &handle_test_blacklist_cont, bcc))) bcc->bc = bc; /* if NULL == bc, 'cont' was already called and 'bcc' already free'd, so we must only store 'bc' if 'bc' is non-NULL... */ } /** * We received a 'SESSION_CONNECT' message from the other peer. * Consider switching to it. * * @param message possibly a 'struct SessionConnectMessage' (check format) * @param peer identity of the peer to switch the address for * @param address address of the other peer, NULL if other peer * connected to us * @param session session to use (or NULL) * @param ats performance data * @param ats_count number of entries in ats (excluding 0-termination) */ void GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Address *address, struct Session *session, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { const struct SessionConnectMessage *scm; struct NeighbourMapEntry *n; struct GNUNET_TIME_Absolute ts; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received CONNECT message from peer `%s'\n", GNUNET_i2s (peer)); if (ntohs (message->size) != sizeof (struct SessionConnectMessage)) { GNUNET_break_op (0); return; } if (NULL == neighbours) return; /* we're shutting down */ scm = (const struct SessionConnectMessage *) message; GNUNET_break_op (0 == ntohl (scm->reserved)); ts = GNUNET_TIME_absolute_ntoh (scm->timestamp); n = lookup_neighbour (peer); if (NULL == n) n = setup_neighbour (peer); n->send_connect_ack = 1; n->connect_ack_timestamp = ts; switch (n->state) { case S_NOT_CONNECTED: n->state = S_CONNECT_RECV_ATS; n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT); GNUNET_ATS_reset_backoff (GST_ats, peer); GNUNET_ATS_suggest_address (GST_ats, peer); check_blacklist (peer, ts, address, session, ats, ats_count); break; case S_INIT_ATS: case S_INIT_BLACKLIST: case S_CONNECT_SENT: case S_CONNECT_RECV_ATS: case S_CONNECT_RECV_BLACKLIST: case S_CONNECT_RECV_ACK: /* It can never hurt to have an alternative address in the above cases, see if it is allowed */ check_blacklist (peer, ts, address, session, ats, ats_count); break; case S_CONNECTED: /* we are already connected and can thus send the ACK immediately; still, it can never hurt to have an alternative address, so also tell ATS about it */ GNUNET_assert (NULL != n->primary_address.address); GNUNET_assert (NULL != n->primary_address.session); n->send_connect_ack = 0; send_session_connect_ack_message (n->primary_address.address, n->primary_address.session, ts); check_blacklist (peer, ts, address, session, ats, ats_count); break; case S_RECONNECT_ATS: case S_RECONNECT_BLACKLIST: case S_RECONNECT_SENT: /* It can never hurt to have an alternative address in the above cases, see if it is allowed */ check_blacklist (peer, ts, address, session, ats, ats_count); break; case S_CONNECTED_SWITCHING_BLACKLIST: case S_CONNECTED_SWITCHING_CONNECT_SENT: /* we are already connected and can thus send the ACK immediately; still, it can never hurt to have an alternative address, so also tell ATS about it */ GNUNET_assert (NULL != n->primary_address.address); GNUNET_assert (NULL != n->primary_address.session); n->send_connect_ack = 0; send_session_connect_ack_message (n->primary_address.address, n->primary_address.session, ts); check_blacklist (peer, ts, address, session, ats, ats_count); break; case S_DISCONNECT: /* get rid of remains without terminating sessions, ready to re-try */ free_neighbour (n, GNUNET_YES); n = setup_neighbour (peer); n->state = S_CONNECT_RECV_ATS; GNUNET_ATS_reset_backoff (GST_ats, peer); GNUNET_ATS_suggest_address (GST_ats, peer); break; case S_DISCONNECT_FINISHED: /* should not be possible */ GNUNET_assert (0); break; default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state)); GNUNET_break (0); free_neighbour (n, GNUNET_NO); break; } } /** * For an existing neighbour record, set the active connection to * use the given address. * * @param peer identity of the peer to switch the address for * @param address address of the other peer, NULL if other peer * connected to us * @param session session to use (or NULL) * @param ats performance data * @param ats_count number of entries in ats * @param bandwidth_in inbound quota to be used when connection is up * @param bandwidth_out outbound quota to be used when connection is up */ void GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Address *address, struct Session *session, const struct GNUNET_ATS_Information *ats, uint32_t ats_count, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out) { struct NeighbourMapEntry *n; struct GNUNET_TRANSPORT_PluginFunctions *papi; GNUNET_assert (address->transport_name != NULL); if (NULL == (n = lookup_neighbour (peer))) return; /* Obtain an session for this address from plugin */ if (NULL == (papi = GST_plugins_find (address->transport_name))) { /* we don't have the plugin for this address */ GNUNET_ATS_address_destroyed (GST_ats, address, NULL); return; } if ((NULL == session) && (0 == address->address_length)) { GNUNET_break (0); if (strlen (address->transport_name) > 0) GNUNET_ATS_address_destroyed (GST_ats, address, session); return; } if (NULL == session) session = papi->get_session (papi->cls, address); if (NULL == session) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to obtain new session for peer `%s' and address '%s'\n", GNUNET_i2s (&address->peer), GST_plugins_a2s (address)); GNUNET_ATS_address_destroyed (GST_ats, address, NULL); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS tells us to switch to address '%s' for peer `%s'\n", (address->address_length != 0) ? GST_plugins_a2s (address): "", GNUNET_i2s (peer)); switch (n->state) { case S_NOT_CONNECTED: GNUNET_break (0); free_neighbour (n, GNUNET_NO); return; case S_INIT_ATS: set_address (&n->primary_address, address, session, bandwidth_in, bandwidth_out, GNUNET_NO); n->state = S_INIT_BLACKLIST; n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT); check_blacklist (&n->id, n->connect_ack_timestamp, address, session, ats, ats_count); break; case S_INIT_BLACKLIST: /* ATS suggests a different address, switch again */ set_address (&n->primary_address, address, session, bandwidth_in, bandwidth_out, GNUNET_NO); n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT); check_blacklist (&n->id, n->connect_ack_timestamp, address, session, ats, ats_count); break; case S_CONNECT_SENT: /* ATS suggests a different address, switch again */ set_address (&n->primary_address, address, session, bandwidth_in, bandwidth_out, GNUNET_NO); n->state = S_INIT_BLACKLIST; n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT); check_blacklist (&n->id, n->connect_ack_timestamp, address, session, ats, ats_count); break; case S_CONNECT_RECV_ATS: set_address (&n->primary_address, address, session, bandwidth_in, bandwidth_out, GNUNET_NO); n->state = S_CONNECT_RECV_BLACKLIST; n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT); check_blacklist (&n->id, n->connect_ack_timestamp, address, session, ats, ats_count); break; case S_CONNECT_RECV_BLACKLIST: case S_CONNECT_RECV_ACK: /* ATS asks us to switch while we were trying to connect; switch to new address and check blacklist again */ set_address (&n->primary_address, address, session, bandwidth_in, bandwidth_out, GNUNET_NO); n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT); check_blacklist (&n->id, n->connect_ack_timestamp, address, session, ats, ats_count); break; case S_CONNECTED: GNUNET_assert (NULL != n->primary_address.address); GNUNET_assert (NULL != n->primary_address.session); if (n->primary_address.session == session) { /* not an address change, just a quota change */ set_address (&n->primary_address, address, session, bandwidth_in, bandwidth_out, GNUNET_YES); break; } /* ATS asks us to switch a life connection; see if we can get a CONNECT_ACK on it before we actually do this! */ set_address (&n->alternative_address, address, session, bandwidth_in, bandwidth_out, GNUNET_NO); n->state = S_CONNECTED_SWITCHING_BLACKLIST; check_blacklist (&n->id, GNUNET_TIME_absolute_get (), address, session, ats, ats_count); break; case S_RECONNECT_ATS: set_address (&n->primary_address, address, session, bandwidth_in, bandwidth_out, GNUNET_NO); n->state = S_RECONNECT_BLACKLIST; n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT); check_blacklist (&n->id, n->connect_ack_timestamp, address, session, ats, ats_count); break; case S_RECONNECT_BLACKLIST: /* ATS asks us to switch while we were trying to reconnect; switch to new address and check blacklist again */ set_address (&n->primary_address, address, session, bandwidth_in, bandwidth_out, GNUNET_NO); n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT); check_blacklist (&n->id, n->connect_ack_timestamp, address, session, ats, ats_count); break; case S_RECONNECT_SENT: /* ATS asks us to switch while we were trying to reconnect; switch to new address and check blacklist again */ set_address (&n->primary_address, address, session, bandwidth_in, bandwidth_out, GNUNET_NO); n->state = S_RECONNECT_BLACKLIST; n->timeout = GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT); check_blacklist (&n->id, n->connect_ack_timestamp, address, session, ats, ats_count); break; case S_CONNECTED_SWITCHING_BLACKLIST: if (n->primary_address.session == session) { /* ATS switches back to still-active session */ free_address (&n->alternative_address); n->state = S_CONNECTED; break; } /* ATS asks us to switch a life connection, update blacklist check */ set_address (&n->alternative_address, address, session, bandwidth_in, bandwidth_out, GNUNET_NO); check_blacklist (&n->id, GNUNET_TIME_absolute_get (), address, session, ats, ats_count); break; case S_CONNECTED_SWITCHING_CONNECT_SENT: if (n->primary_address.session == session) { /* ATS switches back to still-active session */ free_address (&n->alternative_address); n->state = S_CONNECTED; break; } /* ATS asks us to switch a life connection, update blacklist check */ set_address (&n->alternative_address, address, session, bandwidth_in, bandwidth_out, GNUNET_NO); n->state = S_CONNECTED_SWITCHING_BLACKLIST; check_blacklist (&n->id, GNUNET_TIME_absolute_get (), address, session, ats, ats_count); break; case S_DISCONNECT: /* not going to switch addresses while disconnecting */ return; case S_DISCONNECT_FINISHED: GNUNET_assert (0); break; default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state)); GNUNET_break (0); break; } } /** * Master task run for every neighbour. Performs all of the time-related * activities (keep alive, send next message, disconnect if idle, finish * clean up after disconnect). * * @param cls the 'struct NeighbourMapEntry' for which we are running * @param tc scheduler context (unused) */ static void master_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct NeighbourMapEntry *n = cls; struct GNUNET_TIME_Relative delay; n->task = GNUNET_SCHEDULER_NO_TASK; delay = GNUNET_TIME_absolute_get_remaining (n->timeout); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "master task runs for neighbour `%s' in state %d with timeout in %llu ms\n", GNUNET_i2s (&n->id), n->state, (unsigned long long) delay.rel_value); switch (n->state) { case S_NOT_CONNECTED: /* invalid state for master task, clean up */ GNUNET_break (0); n->state = S_DISCONNECT_FINISHED; free_neighbour (n, GNUNET_NO); return; case S_INIT_ATS: if (0 == delay.rel_value) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection to `%s' timed out waiting for ATS to provide address\n", GNUNET_i2s (&n->id)); n->state = S_DISCONNECT_FINISHED; free_neighbour (n, GNUNET_NO); return; } break; case S_INIT_BLACKLIST: if (0 == delay.rel_value) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection to `%s' timed out waiting for BLACKLIST to approve address\n", GNUNET_i2s (&n->id)); n->state = S_DISCONNECT_FINISHED; free_neighbour (n, GNUNET_NO); return; } break; case S_CONNECT_SENT: if (0 == delay.rel_value) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection to `%s' timed out waiting for other peer to send CONNECT_ACK\n", GNUNET_i2s (&n->id)); disconnect_neighbour (n); return; } break; case S_CONNECT_RECV_ATS: if (0 == delay.rel_value) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection to `%s' timed out waiting ATS to provide address to use for CONNECT_ACK\n", GNUNET_i2s (&n->id)); n->state = S_DISCONNECT_FINISHED; free_neighbour (n, GNUNET_NO); return; } break; case S_CONNECT_RECV_BLACKLIST: if (0 == delay.rel_value) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection to `%s' timed out waiting BLACKLIST to approve address to use for CONNECT_ACK\n", GNUNET_i2s (&n->id)); n->state = S_DISCONNECT_FINISHED; free_neighbour (n, GNUNET_NO); return; } break; case S_CONNECT_RECV_ACK: if (0 == delay.rel_value) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection to `%s' timed out waiting for other peer to send SESSION_ACK\n", GNUNET_i2s (&n->id)); disconnect_neighbour (n); return; } break; case S_CONNECTED: if (0 == delay.rel_value) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection to `%s' timed out, missing KEEPALIVE_RESPONSEs\n", GNUNET_i2s (&n->id)); disconnect_neighbour (n); return; } try_transmission_to_peer (n); send_keepalive (n); break; case S_RECONNECT_ATS: if (0 == delay.rel_value) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection to `%s' timed out, waiting for ATS replacement address\n", GNUNET_i2s (&n->id)); disconnect_neighbour (n); return; } break; case S_RECONNECT_BLACKLIST: if (0 == delay.rel_value) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection to `%s' timed out, waiting for BLACKLIST to approve replacement address\n", GNUNET_i2s (&n->id)); disconnect_neighbour (n); return; } break; case S_RECONNECT_SENT: if (0 == delay.rel_value) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection to `%s' timed out, waiting for other peer to CONNECT_ACK replacement address\n", GNUNET_i2s (&n->id)); disconnect_neighbour (n); return; } break; case S_CONNECTED_SWITCHING_BLACKLIST: if (0 == delay.rel_value) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection to `%s' timed out, missing KEEPALIVE_RESPONSEs\n", GNUNET_i2s (&n->id)); disconnect_neighbour (n); return; } try_transmission_to_peer (n); send_keepalive (n); break; case S_CONNECTED_SWITCHING_CONNECT_SENT: if (0 == delay.rel_value) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection to `%s' timed out, missing KEEPALIVE_RESPONSEs (after trying to CONNECT on alternative address)\n", GNUNET_i2s (&n->id)); disconnect_neighbour (n); return; } try_transmission_to_peer (n); send_keepalive (n); break; case S_DISCONNECT: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up connection to `%s' after sending DISCONNECT\n", GNUNET_i2s (&n->id)); n->state = S_DISCONNECT_FINISHED; free_neighbour (n, GNUNET_NO); return; case S_DISCONNECT_FINISHED: /* how did we get here!? */ GNUNET_assert (0); break; default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state)); GNUNET_break (0); break; } if ( (S_CONNECTED_SWITCHING_CONNECT_SENT == n->state) || (S_CONNECTED_SWITCHING_BLACKLIST == n->state) || (S_CONNECTED == n->state) ) { /* if we are *now* in one of these three states, we're sending keep alive messages, so we need to consider the keepalive delay, not just the connection timeout */ delay = GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (n->keep_alive_time), delay); } if (GNUNET_SCHEDULER_NO_TASK == n->task) n->task = GNUNET_SCHEDULER_add_delayed (delay, &master_task, n); } /** * Send a SESSION_ACK message to the neighbour to confirm that we * got his CONNECT_ACK. * * @param n neighbour to send the SESSION_ACK to */ static void send_session_ack_message (struct NeighbourMapEntry *n) { struct GNUNET_MessageHeader msg; msg.size = htons (sizeof (struct GNUNET_MessageHeader)); msg.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK); (void) send_with_session(n, (const char *) &msg, sizeof (struct GNUNET_MessageHeader), UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, NULL, NULL); } /** * We received a 'SESSION_CONNECT_ACK' message from the other peer. * Consider switching to it. * * @param message possibly a 'struct SessionConnectMessage' (check format) * @param peer identity of the peer to switch the address for * @param address address of the other peer, NULL if other peer * connected to us * @param session session to use (or NULL) * @param ats performance data * @param ats_count number of entries in ats */ void GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Address *address, struct Session *session, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { const struct SessionConnectMessage *scm; struct GNUNET_TIME_Absolute ts; struct NeighbourMapEntry *n; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received CONNECT_ACK message from peer `%s'\n", GNUNET_i2s (peer)); if (ntohs (message->size) != sizeof (struct SessionConnectMessage)) { GNUNET_break_op (0); return; } scm = (const struct SessionConnectMessage *) message; GNUNET_break_op (ntohl (scm->reserved) == 0); if (NULL == (n = lookup_neighbour (peer))) { GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# unexpected CONNECT_ACK messages (no peer)"), 1, GNUNET_NO); return; } ts = GNUNET_TIME_absolute_ntoh (scm->timestamp); switch (n->state) { case S_NOT_CONNECTED: GNUNET_break (0); free_neighbour (n, GNUNET_NO); return; case S_INIT_ATS: case S_INIT_BLACKLIST: GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# unexpected CONNECT_ACK messages (not ready)"), 1, GNUNET_NO); break; case S_CONNECT_SENT: if (ts.abs_value != n->primary_address.connect_timestamp.abs_value) break; /* ACK does not match our original CONNECT message */ n->state = S_CONNECTED; n->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); GNUNET_STATISTICS_set (GST_stats, gettext_noop ("# peers connected"), ++neighbours_connected, GNUNET_NO); connect_notify_cb (callback_cls, &n->id, ats, ats_count); set_address (&n->primary_address, n->primary_address.address, n->primary_address.session, n->primary_address.bandwidth_in, n->primary_address.bandwidth_out, GNUNET_YES); send_session_ack_message (n); break; case S_CONNECT_RECV_ATS: case S_CONNECT_RECV_BLACKLIST: case S_CONNECT_RECV_ACK: GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# unexpected CONNECT_ACK messages (not ready)"), 1, GNUNET_NO); break; case S_CONNECTED: /* duplicate CONNECT_ACK, let's answer by duplciate SESSION_ACK just in case */ send_session_ack_message (n); break; case S_RECONNECT_ATS: case S_RECONNECT_BLACKLIST: /* we didn't expect any CONNECT_ACK, as we are waiting for ATS to give us a new address... */ GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# unexpected CONNECT_ACK messages (waiting on ATS)"), 1, GNUNET_NO); break; case S_RECONNECT_SENT: /* new address worked; go back to connected! */ n->state = S_CONNECTED; send_session_ack_message (n); break; case S_CONNECTED_SWITCHING_BLACKLIST: /* duplicate CONNECT_ACK, let's answer by duplciate SESSION_ACK just in case */ send_session_ack_message (n); break; case S_CONNECTED_SWITCHING_CONNECT_SENT: /* new address worked; adopt it and go back to connected! */ n->state = S_CONNECTED; n->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); GNUNET_break (GNUNET_NO == n->alternative_address.ats_active); set_address (&n->primary_address, n->alternative_address.address, n->alternative_address.session, n->alternative_address.bandwidth_in, n->alternative_address.bandwidth_out, GNUNET_YES); free_address (&n->alternative_address); send_session_ack_message (n); break; case S_DISCONNECT: GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# unexpected CONNECT_ACK messages (disconnecting)"), 1, GNUNET_NO); break; case S_DISCONNECT_FINISHED: GNUNET_assert (0); break; default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state)); GNUNET_break (0); break; } } /** * A session was terminated. Take note; if needed, try to get * an alternative address from ATS. * * @param peer identity of the peer where the session died * @param session session that is gone */ void GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer, struct Session *session) { struct NeighbourMapEntry *n; struct BlackListCheckContext *bcc; struct BlackListCheckContext *bcc_next; /* make sure to cancel all ongoing blacklist checks involving 'session' */ bcc_next = bc_head; while (NULL != (bcc = bcc_next)) { bcc_next = bcc->next; if (bcc->na.session == session) { GST_blacklist_test_cancel (bcc->bc); GNUNET_HELLO_address_free (bcc->na.address); GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bcc); GNUNET_free (bcc); } } if (NULL == (n = lookup_neighbour (peer))) return; /* can't affect us */ if (session != n->primary_address.session) { if (session == n->alternative_address.session) { free_address (&n->alternative_address); if ( (S_CONNECTED_SWITCHING_BLACKLIST == n->state) || (S_CONNECTED_SWITCHING_CONNECT_SENT == n->state) ) n->state = S_CONNECTED; else GNUNET_break (0); } return; /* doesn't affect us further */ } n->expect_latency_response = GNUNET_NO; switch (n->state) { case S_NOT_CONNECTED: GNUNET_break (0); free_neighbour (n, GNUNET_NO); return; case S_INIT_ATS: GNUNET_break (0); free_neighbour (n, GNUNET_NO); return; case S_INIT_BLACKLIST: case S_CONNECT_SENT: free_address (&n->primary_address); n->state = S_INIT_ATS; n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT); // FIXME: need to ask ATS for suggestions again? GNUNET_ATS_suggest_address (GST_ats, &n->id); break; case S_CONNECT_RECV_ATS: case S_CONNECT_RECV_BLACKLIST: case S_CONNECT_RECV_ACK: /* error on inbound session; free neighbour entirely */ free_address (&n->primary_address); free_neighbour (n, GNUNET_NO); return; case S_CONNECTED: free_address (&n->primary_address); n->state = S_RECONNECT_ATS; n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT); /* FIXME: is this ATS call needed? */ GNUNET_ATS_suggest_address (GST_ats, &n->id); break; case S_RECONNECT_ATS: /* we don't have an address, how can it go down? */ GNUNET_break (0); break; case S_RECONNECT_BLACKLIST: case S_RECONNECT_SENT: n->state = S_RECONNECT_ATS; n->timeout = GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT); // FIXME: need to ask ATS for suggestions again? GNUNET_ATS_suggest_address (GST_ats, &n->id); break; case S_CONNECTED_SWITCHING_BLACKLIST: /* primary went down while we were checking secondary against blacklist, adopt secondary as primary */ free_address (&n->primary_address); n->primary_address = n->alternative_address; memset (&n->alternative_address, 0, sizeof (struct NeighbourAddress)); n->timeout = GNUNET_TIME_relative_to_absolute (FAST_RECONNECT_TIMEOUT); n->state = S_RECONNECT_BLACKLIST; break; case S_CONNECTED_SWITCHING_CONNECT_SENT: /* primary went down while we were waiting for CONNECT_ACK on secondary; secondary as primary */ free_address (&n->primary_address); n->primary_address = n->alternative_address; memset (&n->alternative_address, 0, sizeof (struct NeighbourAddress)); n->timeout = GNUNET_TIME_relative_to_absolute (FAST_RECONNECT_TIMEOUT); n->state = S_RECONNECT_SENT; break; case S_DISCONNECT: free_address (&n->primary_address); break; case S_DISCONNECT_FINISHED: /* neighbour was freed and plugins told to terminate session */ break; default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state)); GNUNET_break (0); break; } if (GNUNET_SCHEDULER_NO_TASK != n->task) GNUNET_SCHEDULER_cancel (n->task); n->task = GNUNET_SCHEDULER_add_now (&master_task, n); } /** * We received a 'SESSION_ACK' message from the other peer. * If we sent a 'CONNECT_ACK' last, this means we are now * connected. Otherwise, do nothing. * * @param message possibly a 'struct SessionConnectMessage' (check format) * @param peer identity of the peer to switch the address for * @param address address of the other peer, NULL if other peer * connected to us * @param session session to use (or NULL) * @param ats performance data * @param ats_count number of entries in ats */ void GST_neighbours_handle_session_ack (const struct GNUNET_MessageHeader *message, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Address *address, struct Session *session, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { struct NeighbourMapEntry *n; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received SESSION_ACK message from peer `%s'\n", GNUNET_i2s (peer)); if (ntohs (message->size) != sizeof (struct GNUNET_MessageHeader)) { GNUNET_break_op (0); return; } if (NULL == (n = lookup_neighbour (peer))) return; /* check if we are in a plausible state for having sent a CONNECT_ACK. If not, return, otherwise break */ if ( ( (S_CONNECT_RECV_ACK != n->state) && (S_CONNECT_SENT != n->state) ) || (2 != n->send_connect_ack) ) { GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# unexpected SESSION ACK messages"), 1, GNUNET_NO); return; } n->state = S_CONNECTED; n->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); GNUNET_STATISTICS_set (GST_stats, gettext_noop ("# peers connected"), ++neighbours_connected, GNUNET_NO); connect_notify_cb (callback_cls, &n->id, ats, ats_count); set_address (&n->primary_address, n->primary_address.address, n->primary_address.session, n->primary_address.bandwidth_in, n->primary_address.bandwidth_out, GNUNET_YES); } /** * Test if we're connected to the given peer. * * @param target peer to test * @return GNUNET_YES if we are connected, GNUNET_NO if not */ int GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target) { return test_connected (lookup_neighbour (target)); } /** * Change the incoming quota for the given peer. * * @param neighbour identity of peer to change qutoa for * @param quota new quota */ void GST_neighbours_set_incoming_quota (const struct GNUNET_PeerIdentity *neighbour, struct GNUNET_BANDWIDTH_Value32NBO quota) { struct NeighbourMapEntry *n; if (NULL == (n = lookup_neighbour (neighbour))) { GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# SET QUOTA messages ignored (no such peer)"), 1, GNUNET_NO); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Setting inbound quota of %u Bps for peer `%s' to all clients\n", ntohl (quota.value__), GNUNET_i2s (&n->id)); GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker, quota); if (0 != ntohl (quota.value__)) return; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s' due to `%s'\n", GNUNET_i2s (&n->id), "SET_QUOTA"); if (GNUNET_YES == test_connected (n)) GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# disconnects due to quota of 0"), 1, GNUNET_NO); disconnect_neighbour (n); } /** * We received a disconnect message from the given peer, * validate and process. * * @param peer sender of the message * @param msg the disconnect message */ void GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *msg) { struct NeighbourMapEntry *n; const struct SessionDisconnectMessage *sdm; GNUNET_HashCode hc; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received DISCONNECT message from peer `%s'\n", GNUNET_i2s (peer)); if (ntohs (msg->size) != sizeof (struct SessionDisconnectMessage)) { // GNUNET_break_op (0); GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# disconnect messages ignored (old format)"), 1, GNUNET_NO); return; } sdm = (const struct SessionDisconnectMessage *) msg; if (NULL == (n = lookup_neighbour (peer))) return; /* gone already */ if (GNUNET_TIME_absolute_ntoh (sdm->timestamp).abs_value <= n->connect_ack_timestamp.abs_value) { GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# disconnect messages ignored (timestamp)"), 1, GNUNET_NO); return; } GNUNET_CRYPTO_hash (&sdm->public_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &hc); if (0 != memcmp (peer, &hc, sizeof (struct GNUNET_PeerIdentity))) { GNUNET_break_op (0); return; } if (ntohl (sdm->purpose.size) != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sizeof (struct GNUNET_TIME_AbsoluteNBO)) { GNUNET_break_op (0); return; } if (GNUNET_OK != GNUNET_CRYPTO_rsa_verify (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT, &sdm->purpose, &sdm->signature, &sdm->public_key)) { GNUNET_break_op (0); return; } if (GNUNET_YES == test_connected (n)) GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# other peer asked to disconnect from us"), 1, GNUNET_NO); disconnect_neighbour (n); } /** * Closure for the neighbours_iterate function. */ struct IteratorContext { /** * Function to call on each connected neighbour. */ GST_NeighbourIterator cb; /** * Closure for 'cb'. */ void *cb_cls; }; /** * Call the callback from the closure for each connected neighbour. * * @param cls the 'struct IteratorContext' * @param key the hash of the public key of the neighbour * @param value the 'struct NeighbourMapEntry' * @return GNUNET_OK (continue to iterate) */ static int neighbours_iterate (void *cls, const GNUNET_HashCode * key, void *value) { struct IteratorContext *ic = cls; struct NeighbourMapEntry *n = value; if (GNUNET_YES == test_connected (n)) ic->cb (ic->cb_cls, &n->id, NULL, 0, n->primary_address.address); return GNUNET_OK; } /** * Iterate over all connected neighbours. * * @param cb function to call * @param cb_cls closure for cb */ void GST_neighbours_iterate (GST_NeighbourIterator cb, void *cb_cls) { struct IteratorContext ic; if (NULL == neighbours) return; /* can happen during shutdown */ ic.cb = cb; ic.cb_cls = cb_cls; GNUNET_CONTAINER_multihashmap_iterate (neighbours, &neighbours_iterate, &ic); } /** * If we have an active connection to the given target, it must be shutdown. * * @param target peer to disconnect from */ void GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target) { struct NeighbourMapEntry *n; if (NULL == (n = lookup_neighbour (target))) return; /* not active */ if (GNUNET_YES == test_connected (n)) GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# disconnected from peer upon explicit request"), 1, GNUNET_NO); disconnect_neighbour (n); } /** * Obtain current latency information for the given neighbour. * * @param peer to get the latency for * @return observed latency of the address, FOREVER if the * the connection is not up */ struct GNUNET_TIME_Relative GST_neighbour_get_latency (const struct GNUNET_PeerIdentity *peer) { struct NeighbourMapEntry *n; n = lookup_neighbour (peer); if (NULL == n) return GNUNET_TIME_UNIT_FOREVER_REL; switch (n->state) { case S_CONNECTED: case S_RECONNECT_SENT: case S_RECONNECT_ATS: return n->latency; case S_NOT_CONNECTED: case S_INIT_BLACKLIST: case S_INIT_ATS: case S_CONNECT_SENT: case S_CONNECT_RECV_BLACKLIST: case S_DISCONNECT: case S_DISCONNECT_FINISHED: return GNUNET_TIME_UNIT_FOREVER_REL; default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state)); GNUNET_break (0); break; } return GNUNET_TIME_UNIT_FOREVER_REL; } /** * Obtain current address information for the given neighbour. * * @param peer * @return address currently used */ struct GNUNET_HELLO_Address * GST_neighbour_get_current_address (const struct GNUNET_PeerIdentity *peer) { struct NeighbourMapEntry *n; n = lookup_neighbour (peer); if (NULL == n) return NULL; return n->primary_address.address; } /** * Initialize the neighbours subsystem. * * @param cls closure for callbacks * @param connect_cb function to call if we connect to a peer * @param disconnect_cb function to call if we disconnect from a peer * @param peer_address_cb function to call if we change an active address * of a neighbour */ void GST_neighbours_start (void *cls, GNUNET_TRANSPORT_NotifyConnect connect_cb, GNUNET_TRANSPORT_NotifyDisconnect disconnect_cb, GNUNET_TRANSPORT_PeerIterateCallback peer_address_cb) { callback_cls = cls; connect_notify_cb = connect_cb; disconnect_notify_cb = disconnect_cb; address_change_cb = peer_address_cb; neighbours = GNUNET_CONTAINER_multihashmap_create (NEIGHBOUR_TABLE_SIZE); } /** * Disconnect from the given neighbour. * * @param cls unused * @param key hash of neighbour's public key (not used) * @param value the 'struct NeighbourMapEntry' of the neighbour * @return GNUNET_OK (continue to iterate) */ static int disconnect_all_neighbours (void *cls, const GNUNET_HashCode * key, void *value) { struct NeighbourMapEntry *n = value; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n", GNUNET_i2s (&n->id), "SHUTDOWN_TASK"); n->state = S_DISCONNECT_FINISHED; free_neighbour (n, GNUNET_NO); return GNUNET_OK; } /** * Cleanup the neighbours subsystem. */ void GST_neighbours_stop () { if (NULL == neighbours) return; GNUNET_CONTAINER_multihashmap_iterate (neighbours, &disconnect_all_neighbours, NULL); GNUNET_CONTAINER_multihashmap_destroy (neighbours); neighbours = NULL; callback_cls = NULL; connect_notify_cb = NULL; disconnect_notify_cb = NULL; address_change_cb = NULL; } /* end of file gnunet-service-transport_neighbours.c */ gnunet-0.9.3/src/transport/plugin_transport_udp.h0000644000175000017500000001317611760502551017234 00000000000000/* This file is part of GNUnet (C) 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/plugin_transport_udp.h * @brief Implementation of the UDP transport protocol * @author Christian Grothoff * @author Nathan Evans * @author Matthias Wachs */ #include "platform.h" #include "gnunet_hello_lib.h" #include "gnunet_util_lib.h" #include "gnunet_fragmentation_lib.h" #include "gnunet_nat_lib.h" #include "gnunet_protocols.h" #include "gnunet_resolver_service.h" #include "gnunet_signatures.h" #include "gnunet_constants.h" #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" #include "gnunet_transport_plugin.h" #include "transport.h" #define LOG(kind,...) GNUNET_log_from (kind, "transport-udp", __VA_ARGS__) #define DEBUG_UDP GNUNET_NO #define DEBUG_UDP_BROADCASTING GNUNET_NO /** * MTU for fragmentation subsystem. Should be conservative since * all communicating peers MUST work with this MTU. */ #define UDP_MTU 1400 GNUNET_NETWORK_STRUCT_BEGIN /** * Network format for IPv4 addresses. */ struct IPv4UdpAddress { /** * IPv4 address, in network byte order. */ uint32_t ipv4_addr GNUNET_PACKED; /** * Port number, in network byte order. */ uint16_t u4_port GNUNET_PACKED; }; /** * Network format for IPv6 addresses. */ struct IPv6UdpAddress { /** * IPv6 address. */ struct in6_addr ipv6_addr GNUNET_PACKED; /** * Port number, in network byte order. */ uint16_t u6_port GNUNET_PACKED; }; GNUNET_NETWORK_STRUCT_END /** * UDP Message-Packet header (after defragmentation). */ struct UDPMessage { /** * Message header. */ struct GNUNET_MessageHeader header; /** * Always zero for now. */ uint32_t reserved; /** * What is the identity of the sender */ struct GNUNET_PeerIdentity sender; }; /** * Encapsulation of all of the state of the plugin. */ struct Plugin { /** * Our environment. */ struct GNUNET_TRANSPORT_PluginEnvironment *env; /** * Session of peers with whom we are currently connected, * map of peer identity to 'struct PeerSession'. */ struct GNUNET_CONTAINER_MultiHashMap *sessions; /** * Heap with all of our defragmentation activities. */ struct GNUNET_CONTAINER_Heap *defrag_ctxs; /** * ID of select task */ GNUNET_SCHEDULER_TaskIdentifier select_task; GNUNET_SCHEDULER_TaskIdentifier select_task_v6; /** * Tokenizer for inbound messages. */ struct GNUNET_SERVER_MessageStreamTokenizer *mst; /** * Bandwidth tracker to limit global UDP traffic. */ struct GNUNET_BANDWIDTH_Tracker tracker; /** * Address we were told to bind to exclusively (IPv4). */ char *bind4_address; /** * Address we were told to bind to exclusively (IPv6). */ char *bind6_address; /** * Handle to NAT traversal support. */ struct GNUNET_NAT_Handle *nat; /** * FD Read set */ struct GNUNET_NETWORK_FDSet *rs_v4; /** * FD Write set */ struct GNUNET_NETWORK_FDSet *ws_v4; int with_v4_ws; /** * The read socket for IPv4 */ struct GNUNET_NETWORK_Handle *sockv4; /** * FD Read set */ struct GNUNET_NETWORK_FDSet *rs_v6; /** * FD Write set */ struct GNUNET_NETWORK_FDSet *ws_v6; int with_v6_ws; /** * The read socket for IPv6 */ struct GNUNET_NETWORK_Handle *sockv6; /** * Beacon broadcasting * ------------------- */ /** * Broadcast interval */ struct GNUNET_TIME_Relative broadcast_interval; /** * Broadcast with IPv4 */ int broadcast_ipv4; /** * Broadcast with IPv6 */ int broadcast_ipv6; /** * Tokenizer for inbound messages. */ struct GNUNET_SERVER_MessageStreamTokenizer *broadcast_ipv6_mst; struct GNUNET_SERVER_MessageStreamTokenizer *broadcast_ipv4_mst; /** * ID of select broadcast task */ GNUNET_SCHEDULER_TaskIdentifier send_ipv4_broadcast_task; /** * ID of select broadcast task */ GNUNET_SCHEDULER_TaskIdentifier send_ipv6_broadcast_task; /** * IPv6 multicast address */ struct sockaddr_in6 ipv6_multicast_address; /** * DLL of IPv4 broadcast addresses */ struct BroadcastAddress *ipv4_broadcast_tail; struct BroadcastAddress *ipv4_broadcast_head; /** * Enable IPv6 */ int enable_ipv6; /** * Port we broadcasting on. */ uint16_t broadcast_port; /** * Port we listen on. */ uint16_t port; /** * Port we advertise on. */ uint16_t aport; struct UDPMessageWrapper *ipv4_queue_head; struct UDPMessageWrapper *ipv4_queue_tail; struct UDPMessageWrapper *ipv6_queue_head; struct UDPMessageWrapper *ipv6_queue_tail; }; const char * udp_address_to_string (void *cls, const void *addr, size_t addrlen); void udp_broadcast_receive (); void setup_broadcast (struct Plugin *plugin, struct sockaddr_in6 *serverAddrv6, struct sockaddr_in *serverAddrv4); void stop_broadcast (struct Plugin *plugin); /* end of plugin_transport_udp.h */ gnunet-0.9.3/src/transport/gnunet-service-transport_neighbours.h0000644000175000017500000002514411760502551022165 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/gnunet-service-transport_neighbours.h * @brief neighbour management API * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_TRANSPORT_NEIGHBOURS_H #define GNUNET_SERVICE_TRANSPORT_NEIGHBOURS_H #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" #include "gnunet_transport_plugin.h" #include "gnunet_util_lib.h" // TODO: // - ATS and similar info is a bit lacking in the API right now... /** * Initialize the neighbours subsystem. * * @param cls closure for callbacks * @param connect_cb function to call if we connect to a peer * @param disconnect_cb function to call if we disconnect from a peer * @param peer_address_cb function to call if a neighbour's active address changes */ void GST_neighbours_start (void *cls, GNUNET_TRANSPORT_NotifyConnect connect_cb, GNUNET_TRANSPORT_NotifyDisconnect disconnect_cb, GNUNET_TRANSPORT_PeerIterateCallback peer_address_cb); /** * Cleanup the neighbours subsystem. */ void GST_neighbours_stop (void); /** * Try to create a connection to the given target (eventually). * * @param target peer to try to connect to */ void GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target); /** * Test if we're connected to the given peer. * * @param target peer to test * @return GNUNET_YES if we are connected, GNUNET_NO if not */ int GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target); /** * Function called after the transmission is done. * * @param cls closure * @param success GNUNET_OK on success, GNUNET_NO on failure, GNUNET_SYSERR if we're not connected */ typedef void (*GST_NeighbourSendContinuation) (void *cls, int success); /** * Transmit a message to the given target using the active connection. * * @param target destination * @param msg message to send * @param msg_size number of bytes in msg * @param timeout when to fail with timeout * @param cont function to call when done * @param cont_cls closure for 'cont' */ void GST_neighbours_send (const struct GNUNET_PeerIdentity *target, const void *msg, size_t msg_size, struct GNUNET_TIME_Relative timeout, GST_NeighbourSendContinuation cont, void *cont_cls); /** * We have received a message from the given sender. * How long should we delay before receiving more? * (Also used to keep the peer marked as live). * * @param sender sender of the message * @param size size of the message * @param do_forward set to GNUNET_YES if the message should be forwarded to clients * GNUNET_NO if the neighbour is not connected or violates the quota * @return how long to wait before reading more from this sender */ struct GNUNET_TIME_Relative GST_neighbours_calculate_receive_delay (const struct GNUNET_PeerIdentity *sender, ssize_t size, int *do_forward); /** * Keep the connection to the given neighbour alive longer, * we received a KEEPALIVE (or equivalent). * * @param neighbour neighbour to keep alive */ void GST_neighbours_keepalive (const struct GNUNET_PeerIdentity *neighbour); /** * We received a KEEP_ALIVE_RESPONSE message and use this to calculate latency * to this peer * * @param neighbour neighbour to keep alive * @param ats performance data * @param ats_count number of entries in ats */ void GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour, const struct GNUNET_ATS_Information *ats, uint32_t ats_count); /** * Change the incoming quota for the given peer. * * @param neighbour identity of peer to change qutoa for * @param quota new quota */ void GST_neighbours_set_incoming_quota (const struct GNUNET_PeerIdentity *neighbour, struct GNUNET_BANDWIDTH_Value32NBO quota); /** * If we have an active connection to the given target, it must be shutdown. * * @param target peer to disconnect from */ void GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target); /** * Function called for each connected neighbour. * * @param cls closure * @param neighbour identity of the neighbour * @param ats performance data * @param ats_count number of entries in ats (including 0-termination) * @param address the address (or NULL) */ typedef void (*GST_NeighbourIterator) (void *cls, const struct GNUNET_PeerIdentity * neighbour, const struct GNUNET_ATS_Information * ats, uint32_t ats_count, const struct GNUNET_HELLO_Address * address); /** * Iterate over all connected neighbours. * * @param cb function to call * @param cb_cls closure for cb */ void GST_neighbours_iterate (GST_NeighbourIterator cb, void *cb_cls); /** * A session was terminated. Take note. * * @param peer identity of the peer where the session died * @param session session that is gone */ void GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer, struct Session *session); /** * For an existing neighbour record, set the active connection to * use the given address. * * @param peer identity of the peer to switch the address for * @param address address of the other peer, NULL if other peer * connected to us * @param session session to use (or NULL) * @param ats performance data * @param ats_count number of entries in ats * @param bandwidth_in inbound quota to be used when connection is up * @param bandwidth_out outbound quota to be used when connection is up */ void GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Address *address, struct Session *session, const struct GNUNET_ATS_Information *ats, uint32_t ats_count, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out); /** * We received a 'SESSION_CONNECT' message from the other peer. * Consider switching to it. * * @param message possibly a 'struct SessionConnectMessage' (check format) * @param peer identity of the peer to switch the address for * @param address address of the other peer, NULL if other peer * connected to us * @param session session to use (or NULL) * @param ats performance data * @param ats_count number of entries in ats (excluding 0-termination) */ void GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Address *address, struct Session *session, const struct GNUNET_ATS_Information *ats, uint32_t ats_count); /** * We received a 'SESSION_CONNECT_ACK' message from the other peer. * Consider switching to it. * * @param message possibly a 'struct SessionConnectMessage' (check format) * @param peer identity of the peer to switch the address for * @param address address of the other peer, NULL if other peer * connected to us * @param session session to use (or NULL) * @param ats performance data * @param ats_count number of entries in ats */ void GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Address *address, struct Session *session, const struct GNUNET_ATS_Information *ats, uint32_t ats_count); /** * We received a 'SESSION_ACK' message from the other peer. * FIXME: describe what this means! * * @param message possibly a 'struct SessionConnectMessage' (check format) * @param peer identity of the peer to switch the address for * @param address address of the other peer, NULL if other peer * connected to us * @param session session to use (or NULL) * @param ats performance data * @param ats_count number of entries in ats */ void GST_neighbours_handle_session_ack (const struct GNUNET_MessageHeader *message, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Address *address, struct Session *session, const struct GNUNET_ATS_Information *ats, uint32_t ats_count); /** * Obtain current latency information for the given neighbour. * * @param peer * @return observed latency of the address, FOREVER if the address was * never successfully validated */ struct GNUNET_TIME_Relative GST_neighbour_get_latency (const struct GNUNET_PeerIdentity *peer); /** * Obtain current address information for the given neighbour. * * @param peer * @return address currently used */ struct GNUNET_HELLO_Address * GST_neighbour_get_current_address (const struct GNUNET_PeerIdentity *peer); /** * We received a disconnect message from the given peer, * validate and process. * * @param peer sender of the message * @param msg the disconnect message */ void GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *msg); #endif /* end of file gnunet-service-transport_neighbours.h */ gnunet-0.9.3/src/transport/test_transport_api_reliability_http_nat_peer2.conf0000644000175000017500000000127611665224122024760 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-http-p2/ DEFAULTCONFIG = test_transport_api_reliability_http_nat_peer2.conf [ats] WAN_QUOTA_OUT = 1073741824 WAN_QUOTA_IN = 1073741824 [transport-http] PORT = 12090 [arm] PORT = 12095 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12094 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12093 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12092 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] #DEBUG = YES PORT = 12091 PLUGINS = http UNIXPATH = /tmp/gnunet-p2-service-transport.sock #PREFIX = valgrind --leak-check=full gnunet-0.9.3/src/transport/test_quota_compliance_tcp_peer2.conf0000644000175000017500000000111411750306133021757 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-tcp-p2/ DEFAULTCONFIG = test_quota_compliance_tcp_peer2.conf [transport-tcp] PORT = 12015 TIMEOUT = 5 s [arm] PORT = 12014 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12013 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12012 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12011 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12010 PLUGINS = tcp UNIXPATH = /tmp/gnunet-p2-service-transport.sock gnunet-0.9.3/src/transport/transport_api_address_lookup.c0000644000175000017500000002531311760502551020724 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/transport_api_address_lookup.c * @brief given a peer id, get all known addresses from transport service * * This api provides the ability to query the transport service about * the status of connections to a specific peer. Calls back with a * pretty printed string of the address, as formatted by the appropriate * transport plugin, and whether or not the address given is currently * in the 'connected' state (according to the transport service). */ #include "platform.h" #include "gnunet_client_lib.h" #include "gnunet_arm_service.h" #include "gnunet_hello_lib.h" #include "gnunet_protocols.h" #include "gnunet_server_lib.h" #include "gnunet_time_lib.h" #include "gnunet_transport_service.h" #include "transport.h" /** * Context for the address lookup. */ struct GNUNET_TRANSPORT_PeerIterateContext { /** * Function to call with the binary address. */ GNUNET_TRANSPORT_PeerIterateCallback cb; /** * Closure for cb. */ void *cb_cls; /** * Connection to the service. */ struct GNUNET_CLIENT_Connection *client; /** * Configuration we use. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * When should this operation time out? */ struct GNUNET_TIME_Absolute timeout; /** * Backoff for reconnect. */ struct GNUNET_TIME_Relative backoff; /** * Task ID for reconnect. */ GNUNET_SCHEDULER_TaskIdentifier reconnect_task; /** * Identity of the peer to monitor. */ struct GNUNET_PeerIdentity peer; /** * Was this a one-shot request? */ int one_shot; }; /** * Function called with responses from the service. * * @param cls our 'struct GNUNET_TRANSPORT_PeerAddressLookupContext*' * @param msg NULL on timeout or error, otherwise presumably a * message with the human-readable address */ static void peer_address_response_processor (void *cls, const struct GNUNET_MessageHeader *msg); /** * Send our subscription request to the service. * * @param pal_ctx our context */ static void send_request (struct GNUNET_TRANSPORT_PeerIterateContext *pal_ctx) { struct AddressIterateMessage msg; msg.header.size = htons (sizeof (struct AddressIterateMessage)); msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE); msg.one_shot = htonl (pal_ctx->one_shot); msg.timeout = GNUNET_TIME_absolute_hton (pal_ctx->timeout); msg.peer = pal_ctx->peer; GNUNET_assert (GNUNET_OK == GNUNET_CLIENT_transmit_and_get_response (pal_ctx->client, &msg.header, GNUNET_TIME_absolute_get_remaining (pal_ctx->timeout), GNUNET_YES, &peer_address_response_processor, pal_ctx)); } /** * Task run to re-establish the connection. * * @param cls our 'struct GNUNET_TRANSPORT_PeerAddressLookupContext*' * @param tc scheduler context, unused */ static void do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TRANSPORT_PeerIterateContext *pal_ctx = cls; pal_ctx->reconnect_task = GNUNET_SCHEDULER_NO_TASK; pal_ctx->client = GNUNET_CLIENT_connect ("transport", pal_ctx->cfg); GNUNET_assert (NULL != pal_ctx->client); send_request (pal_ctx); } /** * Cut the existing connection and reconnect. * * @param pal_ctx our context */ static void reconnect (struct GNUNET_TRANSPORT_PeerIterateContext *pal_ctx) { GNUNET_assert (GNUNET_NO == pal_ctx->one_shot); GNUNET_CLIENT_disconnect (pal_ctx->client); pal_ctx->client = NULL; pal_ctx->backoff = GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_MILLISECONDS, GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply (pal_ctx->backoff, 2), GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30))); pal_ctx->reconnect_task = GNUNET_SCHEDULER_add_delayed (pal_ctx->backoff, &do_connect, pal_ctx); } /** * Function called with responses from the service. * * @param cls our 'struct GNUNET_TRANSPORT_PeerAddressLookupContext*' * @param msg NULL on timeout or error, otherwise presumably a * message with the human-readable address */ static void peer_address_response_processor (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_TRANSPORT_PeerIterateContext *pal_ctx = cls; struct AddressIterateResponseMessage *air_msg; struct GNUNET_HELLO_Address *address; const char *addr; const char *transport_name; uint16_t size; size_t alen; size_t tlen; if (msg == NULL) { if (pal_ctx->one_shot) { pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL); GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pal_ctx); } else { reconnect (pal_ctx); } return; } size = ntohs (msg->size); GNUNET_break (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE); if (size == sizeof (struct GNUNET_MessageHeader)) { /* done! */ if (pal_ctx->one_shot) { pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL); GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pal_ctx); } else { reconnect (pal_ctx); } return; } if ((size < sizeof (struct AddressIterateResponseMessage)) || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE)) { GNUNET_break (0); if (pal_ctx->one_shot) { pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL); GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pal_ctx); } else { reconnect (pal_ctx); } return; } air_msg = (struct AddressIterateResponseMessage *) msg; tlen = ntohl (air_msg->pluginlen); alen = ntohl (air_msg->addrlen); if (size != sizeof (struct AddressIterateResponseMessage) + tlen + alen) { GNUNET_break (0); if (pal_ctx->one_shot) { pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL); GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pal_ctx); } else { reconnect (pal_ctx); } return; } if (alen == 0 && tlen == 0) { pal_ctx->cb (pal_ctx->cb_cls, &air_msg->peer, NULL); } else { addr = (const char *) &air_msg[1]; transport_name = &addr[alen]; if (transport_name[tlen - 1] != '\0') { GNUNET_break (0); if (pal_ctx->one_shot) { pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL); GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pal_ctx); } else { reconnect (pal_ctx); } return; } /* notify client */ address = GNUNET_HELLO_address_allocate (&air_msg->peer, transport_name, addr, alen); pal_ctx->cb (pal_ctx->cb_cls, &air_msg->peer, address); GNUNET_HELLO_address_free (address); } /* expect more replies */ GNUNET_CLIENT_receive (pal_ctx->client, &peer_address_response_processor, pal_ctx, GNUNET_TIME_absolute_get_remaining (pal_ctx->timeout)); } /** * Return all the known addresses for a specific peer or all peers. * Returns continuously all address if one_shot is set to GNUNET_NO * * CHANGE: Returns the address(es) that we are currently using for this * peer. Upon completion, the 'AddressLookUpCallback' is called one more * time with 'NULL' for the address and the peer. After this, the operation must no * longer be explicitly canceled. * * @param cfg configuration to use * @param peer peer identity to look up the addresses of, CHANGE: allow NULL for all (connected) peers * @param one_shot GNUNET_YES to return the current state and then end (with NULL+NULL), * GNUNET_NO to monitor the set of addresses used (continuously, must be explicitly canceled) * @param timeout how long is the lookup allowed to take at most (irrelevant if one_shot is set to GNUNET_NO) * @param peer_address_callback function to call with the results * @param peer_address_callback_cls closure for peer_address_callback */ struct GNUNET_TRANSPORT_PeerIterateContext * GNUNET_TRANSPORT_peer_get_active_addresses (const struct GNUNET_CONFIGURATION_Handle *cfg, const struct GNUNET_PeerIdentity *peer, int one_shot, struct GNUNET_TIME_Relative timeout, GNUNET_TRANSPORT_PeerIterateCallback peer_address_callback, void *peer_address_callback_cls) { struct GNUNET_TRANSPORT_PeerIterateContext *pal_ctx; struct GNUNET_CLIENT_Connection *client; client = GNUNET_CLIENT_connect ("transport", cfg); if (client == NULL) return NULL; if (GNUNET_YES != one_shot) timeout = GNUNET_TIME_UNIT_FOREVER_REL; pal_ctx = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PeerIterateContext)); pal_ctx->cb = peer_address_callback; pal_ctx->cb_cls = peer_address_callback_cls; pal_ctx->cfg = cfg; pal_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); if (NULL != peer) pal_ctx->peer = *peer; pal_ctx->one_shot = one_shot; pal_ctx->client = client; send_request (pal_ctx); return pal_ctx; } /** * Cancel request for address conversion. * * @param alc handle for the request to cancel */ void GNUNET_TRANSPORT_peer_get_active_addresses_cancel (struct GNUNET_TRANSPORT_PeerIterateContext *alc) { if (NULL != alc->client) { GNUNET_CLIENT_disconnect (alc->client); alc->client = NULL; } if (GNUNET_SCHEDULER_NO_TASK != alc->reconnect_task) { GNUNET_SCHEDULER_cancel (alc->reconnect_task); alc->reconnect_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_free (alc); } /* end of transport_api_peer_address_lookup.c */ gnunet-0.9.3/src/transport/plugin_transport_wlan.h0000644000175000017500000001377311760502551017410 00000000000000/* This file is part of GNUnet (C) 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/plugin_transport_wlan.h * @brief header for transport plugin and the helper for wlan * @author David Brodski */ #ifndef PLUGIN_TRANSPORT_WLAN #define PLUGIN_TRANSPORT_WLAN #include #include "gnunet_common.h" /** * Number fo bytes in a mac address. */ #define MAC_ADDR_SIZE 6 /** * Value for "Management" in the 'frame_control' field of the * struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame. */ #define IEEE80211_FC0_TYPE_MGT 0x00 /** * Value for "Control" in the 'frame_control' field of the * struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame. */ #define IEEE80211_FC0_TYPE_CTL 0x04 /** * Value for DATA in the 'frame_control' field of the * struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame. */ #define IEEE80211_FC0_TYPE_DATA 0x08 GNUNET_NETWORK_STRUCT_BEGIN /** * A MAC Address. */ struct GNUNET_TRANSPORT_WLAN_MacAddress { uint8_t mac[MAC_ADDR_SIZE]; }; /** * Format of a WLAN Control Message. */ struct GNUNET_TRANSPORT_WLAN_HelperControlMessage { /** * Message header. Type is * GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL */ struct GNUNET_MessageHeader hdr; /** * MAC Address of the local WLAN interface. */ struct GNUNET_TRANSPORT_WLAN_MacAddress mac; }; /** * generic definitions for IEEE 802.11 frames */ struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame { /** * 802.11 Frame Control field. A bitmask. The overall field is a * 16-bit mask of the respecitve fields. The lowest two bits should * be 0, then comes the "type" (2 bits, see IEEE80211_FC0_TYPE_* * constants), followed by 4-bit subtype (all zeros for ad-hoc), * followed by various flags (to DS, from DS, more frag, retry, * power management, more data, WEP, strict), all of which we also * keep at zero. */ uint16_t frame_control GNUNET_PACKED; /** * Microseconds to reserve link (duration), 0 by default */ uint16_t duration GNUNET_PACKED; /** * Address 1: destination address in ad-hoc mode or AP, BSSID if station, */ struct GNUNET_TRANSPORT_WLAN_MacAddress addr1; /** * Address 2: source address if in ad-hoc-mode or station, BSSID if AP */ struct GNUNET_TRANSPORT_WLAN_MacAddress addr2; /** * Address 3: BSSID in ad-hoc mode, Destination if station, source if AP */ struct GNUNET_TRANSPORT_WLAN_MacAddress addr3; /** * 802.11 sequence control field; contains fragment number an sequence * number (we set this to all zeros). */ uint16_t sequence_control GNUNET_PACKED; /** * Link layer control (LLC). Set to a GNUnet-specific value. */ u_int8_t llc[4]; /* payload */ } GNUNET_PACKED; /** * Message from the plugin to the WLAN helper: send the given message with the * given connection parameters. */ struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage { /** * Type is 'GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER'. */ struct GNUNET_MessageHeader header; /** * wlan send rate */ uint8_t rate; /** * Antenna; the first antenna is 0. */ uint8_t antenna; /** * Transmit power expressed as unitless distance from max power set at factory calibration. * 0 is max power. Monotonically nondecreasing with lower power levels. */ uint16_t tx_power GNUNET_PACKED; /** * IEEE Frame to transmit (the sender MAC address will be overwritten by the helper as it does not * trust the plugin to set it correctly). */ struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame frame; /* actual payload follows */ }; /** * Message from the WLAN helper to the plugin: we have received the given message with the * given performance characteristics. */ /** * struct to represent infos gathered form the radiotap fields, see RadiotapHeader for more Infos */ struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage { /** * Type is 'GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER'. */ struct GNUNET_MessageHeader header; /** * Information about which of the fields below are actually valid. * 0 for none. FIXME: not properly initialized so far (always zero). */ uint32_t ri_present GNUNET_PACKED; /** * IEEE80211_RADIOTAP_TSFT, 0 if unknown. */ uint64_t ri_mactime GNUNET_PACKED; /** * from radiotap * either IEEE80211_RADIOTAP_DBM_ANTSIGNAL * or IEEE80211_RADIOTAP_DB_ANTSIGNAL, 0 if unknown. */ int32_t ri_power GNUNET_PACKED; /** * either IEEE80211_RADIOTAP_DBM_ANTNOISE * or IEEE80211_RADIOTAP_DB_ANTNOISE, 0 if unknown. */ int32_t ri_noise GNUNET_PACKED; /** * IEEE80211_RADIOTAP_CHANNEL, 0 if unknown. */ uint32_t ri_channel GNUNET_PACKED; /** * Frequency we use. 0 if unknown. */ uint32_t ri_freq GNUNET_PACKED; /** * IEEE80211_RADIOTAP_RATE * 50000, 0 if unknown. */ uint32_t ri_rate GNUNET_PACKED; /** * IEEE80211_RADIOTAP_ANTENNA, 0 if unknown. */ uint32_t ri_antenna GNUNET_PACKED; /** * IEEE Frame. */ struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame frame; /* followed by payload */ }; GNUNET_NETWORK_STRUCT_END /** * GNUnet bssid */ static const struct GNUNET_TRANSPORT_WLAN_MacAddress mac_bssid_gnunet = { {0x13, 0x22, 0x33, 0x44, 0x55, 0x66} }; /** * Broadcast MAC */ static const struct GNUNET_TRANSPORT_WLAN_MacAddress bc_all_mac = { {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} }; #endif gnunet-0.9.3/src/transport/test_quota_compliance_http_asymmetric_peer1.conf0000644000175000017500000000115411661530125024411 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test_quota_compliance_peer1 DEFAULTCONFIG = test_quota_compliance_http_peer1.conf [transport-http] PORT = 4010 [arm] PORT = 4015 UNIXPATH = /tmp/test_quota_compliance_http_arm_peer1.sock [statistics] PORT = 4014 UNIXPATH = /tmp/test_quota_compliance_http_statistics_peer1.sock [resolver] PORT = 4013 UNIXPATH = /tmp/test_quota_compliance_http_resolver_peer1.sock [peerinfo] PORT = 4012 UNIXPATH = /tmp/test_quota_compliance_http_peerinfo_peer1.sock [transport] PORT = 4011 PLUGINS = http UNIXPATH = /tmp/test_quota_compliance_http_transport_peer1.sock gnunet-0.9.3/src/transport/test_transport_api_timeout_https_peer2.conf0000644000175000017500000000120711661530125023447 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-https-p2/ DEFAULTCONFIG = test_transport_api_https_peer2.conf [transport-https] PORT = 12110 KEY_FILE = $SERVICEHOME/https_key_p2.key CERT_FILE = $SERVICEHOME/https_cert_p2.crt [arm] PORT = 12115 UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12114 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12113 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12112 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12111 PLUGINS = https UNIXPATH = /tmp/gnunet-p2-service-transport.sock DEBUG = NO gnunet-0.9.3/src/transport/gnunet-service-transport_blacklist.c0000644000175000017500000005275411760502551021772 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/gnunet-service-transport_blacklist.c * @brief blacklisting implementation * @author Christian Grothoff */ #include "platform.h" #include "gnunet-service-transport.h" #include "gnunet-service-transport_blacklist.h" #include "gnunet-service-transport_neighbours.h" #include "transport.h" /** * Size of the blacklist hash map. */ #define TRANSPORT_BLACKLIST_HT_SIZE 64 /** * Context we use when performing a blacklist check. */ struct GST_BlacklistCheck; /** * Information kept for each client registered to perform * blacklisting. */ struct Blacklisters { /** * This is a linked list. */ struct Blacklisters *next; /** * This is a linked list. */ struct Blacklisters *prev; /** * Client responsible for this entry. */ struct GNUNET_SERVER_Client *client; /** * Blacklist check that we're currently performing (or NULL * if we're performing one that has been cancelled). */ struct GST_BlacklistCheck *bc; /** * Set to GNUNET_YES if we're currently waiting for a reply. */ int waiting_for_reply; }; /** * Context we use when performing a blacklist check. */ struct GST_BlacklistCheck { /** * This is a linked list. */ struct GST_BlacklistCheck *next; /** * This is a linked list. */ struct GST_BlacklistCheck *prev; /** * Peer being checked. */ struct GNUNET_PeerIdentity peer; /** * Continuation to call with the result. */ GST_BlacklistTestContinuation cont; /** * Closure for cont. */ void *cont_cls; /** * Current transmission request handle for this client, or NULL if no * request is pending. */ struct GNUNET_SERVER_TransmitHandle *th; /** * Our current position in the blacklisters list. */ struct Blacklisters *bl_pos; /** * Current task performing the check. */ GNUNET_SCHEDULER_TaskIdentifier task; }; /** * Head of DLL of active blacklisting queries. */ static struct GST_BlacklistCheck *bc_head; /** * Tail of DLL of active blacklisting queries. */ static struct GST_BlacklistCheck *bc_tail; /** * Head of DLL of blacklisting clients. */ static struct Blacklisters *bl_head; /** * Tail of DLL of blacklisting clients. */ static struct Blacklisters *bl_tail; /** * Hashmap of blacklisted peers. Values are of type 'char *' (transport names), * can be NULL if we have no static blacklist. */ static struct GNUNET_CONTAINER_MultiHashMap *blacklist; /** * Perform next action in the blacklist check. * * @param cls the 'struct BlacklistCheck*' * @param tc unused */ static void do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Called whenever a client is disconnected. Frees our * resources associated with that client. * * @param cls closure (unused) * @param client identification of the client */ static void client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client) { struct Blacklisters *bl; struct GST_BlacklistCheck *bc; if (client == NULL) return; for (bl = bl_head; bl != NULL; bl = bl->next) { if (bl->client != client) continue; for (bc = bc_head; bc != NULL; bc = bc->next) { if (bc->bl_pos != bl) continue; bc->bl_pos = bl->next; if (bc->th != NULL) { GNUNET_SERVER_notify_transmit_ready_cancel (bc->th); bc->th = NULL; } if (bc->task == GNUNET_SCHEDULER_NO_TASK) bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc); break; } GNUNET_CONTAINER_DLL_remove (bl_head, bl_tail, bl); GNUNET_SERVER_client_drop (bl->client); GNUNET_free (bl); break; } } /** * Read the blacklist file, containing transport:peer entries. * Provided the transport is loaded, set up hashmap with these * entries to blacklist peers by transport. * */ static void read_blacklist_file () { char *fn; char *data; size_t pos; size_t colon_pos; int tsize; struct GNUNET_PeerIdentity pid; uint64_t fsize; struct GNUNET_CRYPTO_HashAsciiEncoded enc; unsigned int entries_found; char *transport_name; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (GST_cfg, "TRANSPORT", "BLACKLIST_FILE", &fn)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Option `%s' in section `%s' not specified!\n", "BLACKLIST_FILE", "TRANSPORT"); return; } if (GNUNET_OK != GNUNET_DISK_file_test (fn)) GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (GNUNET_OK != GNUNET_DISK_file_size (fn, &fsize, GNUNET_NO, GNUNET_YES)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not read blacklist file `%s'\n"), fn); GNUNET_free (fn); return; } if (fsize == 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Blacklist file `%s' is empty.\n"), fn); GNUNET_free (fn); return; } /* FIXME: use mmap */ data = GNUNET_malloc_large (fsize); GNUNET_assert (data != NULL); if (fsize != GNUNET_DISK_fn_read (fn, data, fsize)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to read blacklist from `%s'\n"), fn); GNUNET_free (fn); GNUNET_free (data); return; } entries_found = 0; pos = 0; while ((pos < fsize) && isspace ((unsigned char) data[pos])) pos++; while ((fsize >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) && (pos <= fsize - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded))) { colon_pos = pos; while ((colon_pos < fsize) && (data[colon_pos] != ':') && (!isspace ((unsigned char) data[colon_pos]))) colon_pos++; if (colon_pos >= fsize) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Syntax error in blacklist file at offset %llu, giving up!\n"), (unsigned long long) colon_pos); GNUNET_free (fn); GNUNET_free (data); return; } if (isspace ((unsigned char) data[colon_pos])) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Syntax error in blacklist file at offset %llu, skipping bytes.\n"), (unsigned long long) colon_pos); pos = colon_pos; while ((pos < fsize) && isspace ((unsigned char) data[pos])) pos++; continue; } tsize = colon_pos - pos; if ((pos >= fsize) || (pos + tsize >= fsize) || (tsize == 0)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Syntax error in blacklist file at offset %llu, giving up!\n"), (unsigned long long) colon_pos); GNUNET_free (fn); GNUNET_free (data); return; } if (tsize < 1) continue; transport_name = GNUNET_malloc (tsize + 1); memcpy (transport_name, &data[pos], tsize); pos = colon_pos + 1; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read transport name `%s' in blacklist file.\n", transport_name); memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); if (!isspace ((unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1])) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Syntax error in blacklist file at offset %llu, skipping bytes.\n"), (unsigned long long) pos); pos++; while ((pos < fsize) && (!isspace ((unsigned char) data[pos]))) pos++; GNUNET_free_non_null (transport_name); continue; } enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"), (unsigned long long) pos, &enc); } else { if (0 != memcmp (&pid, &GST_my_identity, sizeof (struct GNUNET_PeerIdentity))) { entries_found++; GST_blacklist_add_peer (&pid, transport_name); } else { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Found myself `%s' in blacklist (useless, ignored)\n"), GNUNET_i2s (&pid)); } } pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded); GNUNET_free_non_null (transport_name); while ((pos < fsize) && isspace ((unsigned char) data[pos])) pos++; } GNUNET_STATISTICS_update (GST_stats, "# Transport entries blacklisted", entries_found, GNUNET_NO); GNUNET_free (data); GNUNET_free (fn); } /** * Start blacklist subsystem. * * @param server server used to accept clients from */ void GST_blacklist_start (struct GNUNET_SERVER_Handle *server) { read_blacklist_file (); GNUNET_SERVER_disconnect_notify (server, &client_disconnect_notification, NULL); } /** * Free the given entry in the blacklist. * * @param cls unused * @param key host identity (unused) * @param value the blacklist entry * @return GNUNET_OK (continue to iterate) */ static int free_blacklist_entry (void *cls, const GNUNET_HashCode * key, void *value) { char *be = value; GNUNET_free (be); return GNUNET_OK; } /** * Stop blacklist subsystem. */ void GST_blacklist_stop () { if (NULL != blacklist) { GNUNET_CONTAINER_multihashmap_iterate (blacklist, &free_blacklist_entry, NULL); GNUNET_CONTAINER_multihashmap_destroy (blacklist); blacklist = NULL; } } /** * Transmit blacklist query to the client. * * @param cls the 'struct GST_BlacklistCheck' * @param size number of bytes allowed * @param buf where to copy the message * @return number of bytes copied to buf */ static size_t transmit_blacklist_message (void *cls, size_t size, void *buf) { struct GST_BlacklistCheck *bc = cls; struct Blacklisters *bl; struct BlacklistMessage bm; bc->th = NULL; if (size == 0) { GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK); bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to send blacklist test for peer `%s' to client\n", GNUNET_i2s (&bc->peer)); return 0; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending blacklist test for peer `%s' to client\n", GNUNET_i2s (&bc->peer)); bl = bc->bl_pos; bm.header.size = htons (sizeof (struct BlacklistMessage)); bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY); bm.is_allowed = htonl (0); bm.peer = bc->peer; memcpy (buf, &bm, sizeof (bm)); GNUNET_SERVER_receive_done (bl->client, GNUNET_OK); bl->waiting_for_reply = GNUNET_YES; return sizeof (bm); } /** * Perform next action in the blacklist check. * * @param cls the 'struct GST_BlacklistCheck*' * @param tc unused */ static void do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GST_BlacklistCheck *bc = cls; struct Blacklisters *bl; bc->task = GNUNET_SCHEDULER_NO_TASK; bl = bc->bl_pos; if (bl == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No other blacklist clients active, will allow neighbour `%s'\n", GNUNET_i2s (&bc->peer)); bc->cont (bc->cont_cls, &bc->peer, GNUNET_OK); GNUNET_CONTAINER_DLL_remove(bc_head, bc_tail, bc); GNUNET_free (bc); return; } if ((bl->bc != NULL) || (bl->waiting_for_reply != GNUNET_NO)) return; /* someone else busy with this client */ bl->bc = bc; bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client, sizeof (struct BlacklistMessage), GNUNET_TIME_UNIT_FOREVER_REL, &transmit_blacklist_message, bc); } /** * Got the result about an existing connection from a new blacklister. * Shutdown the neighbour if necessary. * * @param cls unused * @param peer the neighbour that was investigated * @param allowed GNUNET_OK if we can keep it, * GNUNET_NO if we must shutdown the connection */ static void confirm_or_drop_neighbour (void *cls, const struct GNUNET_PeerIdentity *peer, int allowed) { if (GNUNET_OK == allowed) return; /* we're done */ GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# disconnects due to blacklist"), 1, GNUNET_NO); GST_neighbours_force_disconnect (peer); } /** * Closure for 'test_connection_ok'. */ struct TestConnectionContext { /** * Is this the first neighbour we're checking? */ int first; /** * Handle to the blacklisting client we need to ask. */ struct Blacklisters *bl; }; /** * Test if an existing connection is still acceptable given a new * blacklisting client. * * @param cls the 'struct TestConnectionContest' * @param neighbour neighbour's identity * @param ats performance data * @param ats_count number of entries in ats (excluding 0-termination) * @param address the address */ static void test_connection_ok (void *cls, const struct GNUNET_PeerIdentity *neighbour, const struct GNUNET_ATS_Information *ats, uint32_t ats_count, const struct GNUNET_HELLO_Address *address) { struct TestConnectionContext *tcc = cls; struct GST_BlacklistCheck *bc; bc = GNUNET_malloc (sizeof (struct GST_BlacklistCheck)); GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc); bc->peer = *neighbour; bc->cont = &confirm_or_drop_neighbour; bc->cont_cls = NULL; bc->bl_pos = tcc->bl; if (GNUNET_YES == tcc->first) { /* all would wait for the same client, no need to * create more than just the first task right now */ bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc); tcc->first = GNUNET_NO; } } /** * Initialize a blacklisting client. We got a blacklist-init * message from this client, add him to the list of clients * to query for blacklisting. * * @param cls unused * @param client the client * @param message the blacklist-init message that was sent */ void GST_blacklist_handle_init (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct Blacklisters *bl; struct TestConnectionContext tcc; bl = bl_head; while (bl != NULL) { if (bl->client == client) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } bl = bl->next; } GNUNET_SERVER_client_mark_monitor (client); bl = GNUNET_malloc (sizeof (struct Blacklisters)); bl->client = client; GNUNET_SERVER_client_keep (client); GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl); /* confirm that all existing connections are OK! */ tcc.bl = bl; tcc.first = GNUNET_YES; GST_neighbours_iterate (&test_connection_ok, &tcc); } /** * A blacklisting client has sent us reply. Process it. * * @param cls unused * @param client the client * @param message the blacklist-init message that was sent */ void GST_blacklist_handle_reply (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct BlacklistMessage *msg = (const struct BlacklistMessage *) message; struct Blacklisters *bl; struct GST_BlacklistCheck *bc; bl = bl_head; while ((bl != NULL) && (bl->client != client)) bl = bl->next; if (bl == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist client disconnected\n"); /* FIXME: other error handling here!? */ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } bc = bl->bc; bl->bc = NULL; bl->waiting_for_reply = GNUNET_NO; if (NULL != bc) { /* only run this if the blacklist check has not been * cancelled in the meantime... */ if (ntohl (msg->is_allowed) == GNUNET_SYSERR) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist check failed, peer not allowed\n"); bc->cont (bc->cont_cls, &bc->peer, GNUNET_NO); GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc); GNUNET_free (bc); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist check succeeded, continuing with checks\n"); bc->bl_pos = bc->bl_pos->next; bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc); } } /* check if any other bc's are waiting for this blacklister */ bc = bc_head; for (bc = bc_head; bc != NULL; bc = bc->next) if ((bc->bl_pos == bl) && (GNUNET_SCHEDULER_NO_TASK == bc->task)) { bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc); break; } } /** * Add the given peer to the blacklist (for the given transport). * * @param peer peer to blacklist * @param transport_name transport to blacklist for this peer, NULL for all */ void GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer, const char *transport_name) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding peer `%s' with plugin `%s' to blacklist\n", GNUNET_i2s (peer), transport_name); if (blacklist == NULL) blacklist = GNUNET_CONTAINER_multihashmap_create (TRANSPORT_BLACKLIST_HT_SIZE); GNUNET_CONTAINER_multihashmap_put (blacklist, &peer->hashPubKey, GNUNET_strdup (transport_name), GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); } /** * Test if the given blacklist entry matches. If so, * abort the iteration. * * @param cls the transport name to match (const char*) * @param key the key (unused) * @param value the 'char *' (name of a blacklisted transport) * @return GNUNET_OK if the entry does not match, GNUNET_NO if it matches */ static int test_blacklisted (void *cls, const GNUNET_HashCode * key, void *value) { const char *transport_name = cls; char *be = value; /* blacklist check for specific no specific transport*/ if (transport_name == NULL) return GNUNET_NO; /* blacklist check for specific transport */ if (0 == strcmp (transport_name, be)) return GNUNET_NO; /* abort iteration! */ return GNUNET_OK; } /** * Test if a peer/transport combination is blacklisted. * * @param peer the identity of the peer to test * @param transport_name name of the transport to test, never NULL * @param cont function to call with result * @param cont_cls closure for 'cont' * @return handle to the blacklist check, NULL if the decision * was made instantly and 'cont' was already called */ struct GST_BlacklistCheck * GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer, const char *transport_name, GST_BlacklistTestContinuation cont, void *cont_cls) { struct GST_BlacklistCheck *bc; GNUNET_assert (peer != NULL); if ((blacklist != NULL) && (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_get_multiple (blacklist, &peer->hashPubKey, &test_blacklisted, (void *) transport_name))) { /* disallowed by config, disapprove instantly */ GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# disconnects due to blacklist"), 1, GNUNET_NO); if (cont != NULL) cont (cont_cls, peer, GNUNET_NO); return NULL; } if (bl_head == NULL) { /* no blacklist clients, approve instantly */ if (cont != NULL) cont (cont_cls, peer, GNUNET_OK); return NULL; } /* need to query blacklist clients */ bc = GNUNET_malloc (sizeof (struct GST_BlacklistCheck)); GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc); bc->peer = *peer; bc->cont = cont; bc->cont_cls = cont_cls; bc->bl_pos = bl_head; bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc); return bc; } /** * Cancel a blacklist check. * * @param bc check to cancel */ void GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc) { GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc); if (bc->bl_pos != NULL) { if (bc->bl_pos->bc == bc) { /* we're at the head of the queue, remove us! */ bc->bl_pos->bc = NULL; } } if (GNUNET_SCHEDULER_NO_TASK != bc->task) { GNUNET_SCHEDULER_cancel (bc->task); bc->task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != bc->th) { GNUNET_SERVER_notify_transmit_ready_cancel (bc->th); bc->th = NULL; } GNUNET_free (bc); } /* end of file gnunet-service-transport_blacklist.c */ gnunet-0.9.3/src/transport/test_plugin_transport_data.conf0000644000175000017500000000046311661530125021103 00000000000000@INLINE@ test_transport_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunetd-plugin-transport/ DEFAULTCONFIG = test_plugin_transport_data.conf [transport-tcp] PORT = 2368 TIMEOUT = 5 s [arm] PORT = 2366 [statistics] PORT = 2367 [resolver] PORT = 2364 [peerinfo] PORT = 2369 [transport] PORT = 2365 gnunet-0.9.3/src/transport/test_transport_api_udp_nat_peer2.conf0000644000175000017500000000114611646062515022201 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-udp-nat-p2/ DEFAULTCONFIG = test_transport_api_udp_nat_peer2.conf [nat] ALLOW_NAT = YES [transport-udp] PORT = 12070 [arm] PORT = 12075 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12074 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12073 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12072 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12071 PLUGINS = udp UNIXPATH = /tmp/gnunet-p2-service-transport.sock DEBUG = NO gnunet-0.9.3/src/transport/test_transport_api_tcp_nat_peer2.conf0000644000175000017500000000121411750306133022164 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-tcp-nat-p2/ DEFAULTCONFIG = test_transport_api_tcp_nat_peer2.conf [nat] DISABLEV6 = YES ENABLE_NAT_CLIENT = YES [transport-tcp] PORT = 12030 TIMEOUT = 5 s [arm] PORT = 12034 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12033 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12032 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12031 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 45923 PLUGINS = tcp UNIXPATH = /tmp/gnunet-p2-service-transport.sock #DEBUG = YES gnunet-0.9.3/src/transport/test_quota_compliance_tcp_asymmetric_peer1.conf0000644000175000017500000000121511750306133024215 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/quota-tcp-p1/ DEFAULTCONFIG = test_quota_compliance_tcp_asymmetric_peer1.conf [transport-tcp] PORT = 4094 [transport-udp] PORT = 4094 [arm] PORT = 4087 UNIXPATH = /tmp/test_quota_compliance_tcp_arm_peer1.sock [statistics] PORT = 4088 UNIXPATH = /tmp/test_quota_compliance_tcp_statistics_peer1.sock [resolver] PORT = 4089 UNIXPATH = /tmp/test_quota_compliance_tcp_resolver_peer1.sock [peerinfo] PORT = 4090 UNIXPATH = /tmp/test_quota_compliance_tcp_peerinfo_peer1.sock [transport] PORT = 4091 PLUGINS = tcp UNIXPATH = /tmp/test_quota_compliance_tcp_transport_peer1.sock gnunet-0.9.3/src/transport/test_quota_compliance_https_asymmetric_peer2.conf0000644000175000017500000000124411661530125024575 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test_quota_compliance_peer2 DEFAULTCONFIG = test_quota_compliance_https_peer2.conf [transport-https] PORT = 3001 KEY_FILE = https_key_quota_p2.key CERT_FILE = https_cert_qutoa_p2.crt [arm] PORT = 3006 UNIXPATH = /tmp/test_quota_compliance_https_arm_peer2.sock [statistics] PORT = 3005 UNIXPATH = /tmp/test_quota_compliance_https_statistics_peer2.sock [resolver] PORT = 3004 UNIXPATH = /tmp/test_quota_compliance_https_resolver_peer2.sock [peerinfo] PORT = 3003 UNIXPATH = /tmp/test_quota_compliance_https_peerinfo_peer2.sock [transport] PORT = 3002 PLUGINS = https UNIXPATH = /tmp/https_transport_peer2.sock gnunet-0.9.3/src/transport/test_transport_startonly.conf0000644000175000017500000000027311626663234020663 00000000000000@INLINE@ test_transport_defaults.conf [PATHS] DEFAULTCONFIG = test_transport_api_data.conf [arm] DEFAULTSERVICES = transport [transport-tcp] PORT = 2094 [transport-udp] PORT = 2094 gnunet-0.9.3/src/transport/test_quota_compliance_tcp_asymmetric_peer2.conf0000644000175000017500000000113111750306133024213 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/quota-tcp-p2/ DEFAULTCONFIG = test_quota_compliance_tcp_asymmetric_peer2.conf [transport-tcp] PORT = 12015 TIMEOUT = 5 s [arm] PORT = 12014 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12013 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12012 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12011 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12010 PLUGINS = tcp UNIXPATH = /tmp/gnunet-p2-service-transport.sock gnunet-0.9.3/src/transport/Makefile.am0000644000175000017500000007363111762221531014635 00000000000000INCLUDES = -I$(top_srcdir)/src/include -I$(top_builddir)/src/include plugindir = $(libdir)/gnunet pkgcfgdir= $(pkgdatadir)/config.d/ pkgcfg_DATA = \ transport.conf if HAVE_MHD GN_LIBMHD = -lmicrohttpd HTTP_PLUGIN_LA = libgnunet_plugin_transport_http.la HTTP_API_TEST = test_transport_api_http HTTP_NAT_API_TEST = test_transport_api_http_nat HTTP_API_TIMEOUT_TEST = test_transport_api_timeout_http HTTP_REL_TEST = test_transport_api_reliability_http HTTP_NAT_REL_TEST = test_transport_api_reliability_http_nat HTTP_QUOTA_TEST = test_quota_compliance_http \ test_quota_compliance_http_asymmetric HTTPS_PLUGIN_LA = libgnunet_plugin_transport_https.la HTTPS_API_TEST = test_transport_api_https HTTPS_NAT_API_TEST = test_transport_api_https_nat HTTPS_API_TIMEOUT_TEST = test_transport_api_timeout_https HTTPS_REL_TEST = test_transport_api_reliability_https HTTPS_NAT_REL_TEST = test_transport_api_reliability_https_nat HTTPS_QUOTA_TEST = test_quota_compliance_https \ test_quota_compliance_https_asymmetric endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 endif if LINUX WLAN_BIN = gnunet-helper-transport-wlan WLAN_BIN_DUMMY = gnunet-helper-transport-wlan-dummy WLAN_BIN_SENDER = gnunet-transport-wlan-sender WLAN_PLUGIN_LA = libgnunet_plugin_transport_wlan.la WLAN_API_TEST = test_transport_api_wlan WLAN_REL_TEST = test_transport_api_reliability_wlan WLAN_UREL_TEST = test_transport_api_unreliability_wlan endif if LINUX install-exec-hook: $(SUDO_BINARY) chown root:root $(bindir)/gnunet-helper-transport-wlan || true $(SUDO_BINARY) chmod u+s $(bindir)/gnunet-helper-transport-wlan || true else install-exec-hook: endif if !MINGW UNIX_PLUGIN_LA = libgnunet_plugin_transport_unix.la UNIX_PLUGIN_TEST = test_transport_api_unix UNIX_PLUGIN_TIMEOUT_TEST = test_transport_api_timeout_unix UNIX_REL_TEST = test_transport_api_unreliability_unix UNIX_QUOTA_TEST = test_quota_compliance_unix \ test_quota_compliance_unix_asymmetric endif noinst_PROGRAMS = \ $(WLAN_BIN_SENDER) # gnunet-transport-connect-running-peers lib_LTLIBRARIES = \ libgnunettransport.la \ libgnunettransporttesting.la libgnunettransporttesting_la_SOURCES = \ transport-testing.c transport-testing.h libgnunettransporttesting_la_LIBADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) libgnunettransporttesting_la_DEPENDENCIES = \ libgnunettransport.la libgnunettransporttesting_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) libgnunettransport_la_SOURCES = \ transport_api.c transport.h \ transport_api_blacklist.c \ transport_api_address_to_string.c \ transport_api_address_lookup.c libgnunettransport_la_LIBADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) libgnunettransport_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 1:0:0 bin_PROGRAMS = \ gnunet-transport \ $(WLAN_BIN) \ $(WLAN_BIN_DUMMY) \ gnunet-service-transport \ gnunet-transport-certificate-creation #bin_SCRIPTS = \ # gnunet-transport-certificate-creation gnunet_transport_certificate_creation_SOURCES = \ gnunet-transport-certificate-creation.c gnunet_transport_certificate_creation_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la gnunet_helper_transport_wlan_SOURCES = \ gnunet-helper-transport-wlan.c gnunet_helper_transport_wlan_dummy_SOURCES = \ gnunet-helper-transport-wlan-dummy.c gnunet_helper_transport_wlan_dummy_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la gnunet_transport_wlan_sender_SOURCES = \ gnunet-transport-wlan-sender.c gnunet_transport_wlan_sender_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la gnunet_transport_SOURCES = \ gnunet-transport.c gnunet_transport_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_transport_DEPENDENCIES = \ libgnunettransport.la gnunet_service_transport_SOURCES = \ gnunet-service-transport.c gnunet-service-transport.h \ gnunet-service-transport_blacklist.h gnunet-service-transport_blacklist.c \ gnunet-service-transport_clients.h gnunet-service-transport_clients.c \ gnunet-service-transport_hello.h gnunet-service-transport_hello.c \ gnunet-service-transport_neighbours.h gnunet-service-transport_neighbours.c \ gnunet-service-transport_plugins.h gnunet-service-transport_plugins.c \ gnunet-service-transport_validation.h gnunet-service-transport_validation.c gnunet_service_transport_LDADD = \ $(top_builddir)/src/ats/libgnunetats.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_GLPK) \ $(GN_LIBINTL) plugin_LTLIBRARIES = \ libgnunet_plugin_transport_tcp.la \ libgnunet_plugin_transport_udp.la \ $(UNIX_PLUGIN_LA) \ $(HTTP_PLUGIN_LA) \ $(HTTPS_PLUGIN_LA) \ $(WLAN_PLUGIN_LA) \ libgnunet_plugin_transport_template.la libgnunet_plugin_transport_tcp_la_SOURCES = \ plugin_transport_tcp.c libgnunet_plugin_transport_tcp_la_LIBADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_transport_tcp_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_transport_template_la_SOURCES = \ plugin_transport_template.c libgnunet_plugin_transport_template_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_transport_template_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_transport_wlan_la_SOURCES = \ plugin_transport_wlan.c plugin_transport_wlan.h libgnunet_plugin_transport_wlan_la_LIBADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_transport_wlan_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_transport_udp_la_SOURCES = \ plugin_transport_udp.c plugin_transport_udp.h \ plugin_transport_udp_broadcasting.c libgnunet_plugin_transport_udp_la_LIBADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_transport_udp_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_transport_unix_la_SOURCES = \ plugin_transport_unix.c libgnunet_plugin_transport_unix_la_LIBADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_transport_unix_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_transport_http_la_SOURCES = \ plugin_transport_http.c plugin_transport_http.h \ plugin_transport_http_client.c plugin_transport_http_server.c libgnunet_plugin_transport_http_la_LIBADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ @LIBCURL@ \ $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_transport_http_la_LDFLAGS = \ $(GN_LIBMHD) \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_transport_http_la_CFLAGS = \ $(CFLAGS) libgnunet_plugin_transport_http_la_CPPFLAGS = \ @LIBCURL_CPPFLAGS@ libgnunet_plugin_transport_https_la_SOURCES = \ plugin_transport_http.c plugin_transport_http.h \ plugin_transport_http_client.c plugin_transport_http_server.c libgnunet_plugin_transport_https_la_LIBADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ @LIBCURL@ \ $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_transport_https_la_LDFLAGS = \ $(GN_LIBMHD) \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_transport_https_la_CFLAGS = \ $(CFLAGS) -DBUILD_HTTPS libgnunet_plugin_transport_https_la_CPPFLAGS = \ @LIBCURL_CPPFLAGS@ check_PROGRAMS = \ test_transport_testing \ test_transport_startonly \ test_transport_api_blacklisting \ test_transport_api_disconnect_tcp \ test_transport_api_bidirectional_connect \ test_transport_api_tcp \ test_transport_api_restart_1peer \ test_transport_api_restart_2peers \ test_transport_api_timeout_tcp \ test_transport_api_limited_sockets_tcp \ test_transport_api_tcp_nat \ test_transport_api_udp \ test_transport_api_timeout_udp \ $(UNIX_PLUGIN_TEST) \ $(UNIX_PLUGIN_TIMEOUT_TEST) \ test_transport_api_udp_nat \ $(HTTP_API_TEST) \ $(HTTP_NAT_API_TEST) \ $(HTTP_API_TIMEOUT_TEST) \ $(HTTPS_API_TEST) \ $(HTTPS_NAT_API_TEST) \ $(HTTPS_API_TIMEOUT_TEST) \ test_transport_api_multi \ test_transport_api_reliability_tcp \ test_transport_api_reliability_tcp_nat \ test_transport_api_unreliability_udp \ test_transport_api_unreliability_constant_udp \ $(UNIX_REL_TEST) \ $(HTTP_REL_TEST) \ $(HTTP_NAT_REL_TEST) \ $(HTTPS_REL_TEST) \ $(HTTPS_NAT_REL_TEST) \ test_quota_compliance_tcp \ test_quota_compliance_tcp_asymmetric \ test_quota_compliance_udp \ $(UNIX_QUOTA_TEST) \ $(HTTP_QUOTA_TEST) \ $(HTTPS_QUOTA_TEST) \ $(WLAN_API_TEST) \ $(WLAN_REL_TEST) \ $(WLAN_UREL_TEST) if ENABLE_TEST_RUN TESTS = \ test_transport_testing \ test_transport_startonly \ test_transport_api_blacklisting \ test_transport_api_disconnect_tcp \ test_transport_api_bidirectional_connect \ test_transport_api_tcp \ test_transport_api_restart_1peer \ test_transport_api_restart_2peers \ test_transport_api_timeout_tcp \ test_transport_api_limited_sockets_tcp \ test_transport_api_tcp_nat \ test_transport_api_udp \ test_transport_api_timeout_udp \ $(UNIX_PLUGIN_TEST) \ $(UNIX_PLUGIN_TIMEOUT_TEST) \ test_transport_api_udp_nat \ $(HTTP_API_TEST) \ $(HTTP_NAT_API_TEST) \ $(HTTP_API_TIMEOUT_TEST) \ $(HTTPS_API_TEST) \ $(HTTPS_NAT_API_TEST) \ $(HTTPS_API_TIMEOUT_TEST) \ test_transport_api_multi \ test_transport_api_reliability_tcp \ test_transport_api_reliability_tcp_nat \ test_transport_api_unreliability_udp \ test_transport_api_unreliability_constant_udp \ $(UNIX_REL_TEST) \ $(HTTP_REL_TEST) \ $(HTTP_NAT_REL_TEST) \ $(HTTPS_REL_TEST) \ $(HTTPS_NAT_REL_TEST) \ test_quota_compliance_tcp \ test_quota_compliance_tcp_asymmetric \ test_quota_compliance_udp \ $(UNIX_QUOTA_TEST) \ $(HTTP_QUOTA_TEST) \ $(HTTPS_QUOTA_TEST) \ $(WLAN_API_TEST) \ $(WLAN_REL_TEST) \ $(WLAN_UREL_TEST) endif test_transport_testing_SOURCES = \ test_transport_testing.c test_transport_testing_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la #gnunet_transport_connect_running_peers_SOURCES = \ # gnunet-transport-connect-running-peers.c #gnunet_transport_connect_running_peers_LDADD = \ # $(top_builddir)/src/transport/libgnunettransport.la \ # $(top_builddir)/src/hello/libgnunethello.la \ # $(top_builddir)/src/util/libgnunetutil.la \ # $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_blacklisting_SOURCES = \ test_transport_api_blacklisting.c test_transport_api_blacklisting_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_disconnect_tcp_SOURCES = \ test_transport_api_disconnect.c test_transport_api_disconnect_tcp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_startonly_SOURCES = \ test_transport_startonly.c test_transport_startonly_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_tcp_SOURCES = \ test_transport_api.c test_transport_api_tcp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_bidirectional_connect_SOURCES = \ test_transport_api_bidirectional_connect.c test_transport_api_bidirectional_connect_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_restart_1peer_SOURCES = \ test_transport_api_restart_1peer.c test_transport_api_restart_1peer_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_restart_2peers_SOURCES = \ test_transport_api_restart_2peers.c test_transport_api_restart_2peers_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_limited_sockets_tcp_SOURCES = \ test_transport_api_limited_sockets.c test_transport_api_limited_sockets_tcp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_tcp_nat_SOURCES = \ test_transport_api.c test_transport_api_tcp_nat_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_reliability_tcp_SOURCES = \ test_transport_api_reliability.c test_transport_api_reliability_tcp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_timeout_tcp_SOURCES = \ test_transport_api_timeout.c test_transport_api_timeout_tcp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_timeout_unix_SOURCES = \ test_transport_api_timeout.c test_transport_api_timeout_unix_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_timeout_http_SOURCES = \ test_transport_api_timeout.c test_transport_api_timeout_http_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_timeout_https_SOURCES = \ test_transport_api_timeout.c test_transport_api_timeout_https_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_reliability_tcp_nat_SOURCES = \ test_transport_api_reliability.c test_transport_api_reliability_tcp_nat_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_reliability_wlan_SOURCES = \ test_transport_api_reliability.c test_transport_api_reliability_wlan_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_unreliability_wlan_SOURCES = \ test_transport_api_unreliability.c test_transport_api_unreliability_wlan_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_udp_SOURCES = \ test_transport_api.c test_transport_api_udp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_timeout_udp_SOURCES = \ test_transport_api_timeout.c test_transport_api_timeout_udp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_udp_nat_SOURCES = \ test_transport_api.c test_transport_api_udp_nat_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_unix_SOURCES = \ test_transport_api.c test_transport_api_unix_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_http_SOURCES = \ test_transport_api.c test_transport_api_http_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_http_nat_SOURCES = \ test_transport_api.c test_transport_api_http_nat_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_reliability_http_SOURCES = \ test_transport_api_reliability.c test_transport_api_reliability_http_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_reliability_http_nat_SOURCES = \ test_transport_api_reliability.c test_transport_api_reliability_http_nat_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_https_SOURCES = \ test_transport_api.c test_transport_api_https_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_https_nat_SOURCES = \ test_transport_api.c test_transport_api_https_nat_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_reliability_https_SOURCES = \ test_transport_api_reliability.c test_transport_api_reliability_https_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_reliability_https_nat_SOURCES = \ test_transport_api_reliability.c test_transport_api_reliability_https_nat_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_unreliability_unix_SOURCES = \ test_transport_api_unreliability.c test_transport_api_unreliability_unix_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_unreliability_udp_SOURCES = \ test_transport_api_unreliability.c test_transport_api_unreliability_udp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_unreliability_constant_udp_SOURCES = \ test_transport_api_unreliability_constant.c test_transport_api_unreliability_constant_udp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la if LINUX test_transport_api_wlan_SOURCES = \ test_transport_api.c test_transport_api_wlan_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la endif test_quota_compliance_tcp_SOURCES = \ test_quota_compliance.c test_quota_compliance_tcp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_quota_compliance_tcp_asymmetric_SOURCES = \ test_quota_compliance.c test_quota_compliance_tcp_asymmetric_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la #test_quota_compliance_tcp_asymmetric_send_constant_SOURCES = \ # test_quota_compliance.c #test_quota_compliance_tcp_asymmetric_send_constant_LDADD = \ # $(top_builddir)/src/transport/libgnunettransport.la \ # $(top_builddir)/src/util/libgnunetutil.la test_quota_compliance_http_SOURCES = \ test_quota_compliance.c test_quota_compliance_http_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_quota_compliance_http_asymmetric_SOURCES = \ test_quota_compliance.c test_quota_compliance_http_asymmetric_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la #test_quota_compliance_http_asymmetric_send_constant_SOURCES = \ # test_quota_compliance.c #test_quota_compliance_http_asymmetric_send_constant_LDADD = \ # $(top_builddir)/src/transport/libgnunettransport.la \ # $(top_builddir)/src/util/libgnunetutil.la test_quota_compliance_https_SOURCES = \ test_quota_compliance.c test_quota_compliance_https_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_quota_compliance_https_asymmetric_SOURCES = \ test_quota_compliance.c test_quota_compliance_https_asymmetric_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la #test_quota_compliance_https_asymmetric_send_constant_SOURCES = \ # test_quota_compliance.c #test_quota_compliance_https_asymmetric_send_constant_LDADD = \ # $(top_builddir)/src/transport/libgnunettransport.la \ # $(top_builddir)/src/util/libgnunetutil.la test_quota_compliance_udp_SOURCES = \ test_quota_compliance.c test_quota_compliance_udp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_quota_compliance_unix_SOURCES = \ test_quota_compliance.c test_quota_compliance_unix_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_quota_compliance_unix_asymmetric_SOURCES = \ test_quota_compliance.c test_quota_compliance_unix_asymmetric_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_multi_SOURCES = \ test_transport_api.c test_transport_api_multi_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la EXTRA_DIST = \ gnunet-transport-certificate-creation \ template_cfg_peer1.conf\ template_cfg_peer2.conf\ test_plugin_transport_data.conf\ test_plugin_transport_data_udp.conf\ test_quota_compliance_data.conf\ test_quota_compliance_http_peer1.conf\ test_quota_compliance_http_peer2.conf\ test_quota_compliance_https_peer1.conf\ test_quota_compliance_https_peer2.conf\ test_quota_compliance_tcp_peer1.conf\ test_quota_compliance_tcp_peer2.conf\ test_quota_compliance_udp_peer1.conf\ test_quota_compliance_udp_peer2.conf\ test_quota_compliance_unix_peer1.conf\ test_quota_compliance_unix_peer2.conf\ test_quota_compliance_http_asymmetric_peer1.conf\ test_quota_compliance_http_asymmetric_peer2.conf\ test_quota_compliance_https_asymmetric_peer1.conf\ test_quota_compliance_https_asymmetric_peer2.conf\ test_quota_compliance_tcp_asymmetric_peer1.conf\ test_quota_compliance_tcp_asymmetric_peer2.conf\ test_quota_compliance_unix_asymmetric_peer1.conf\ test_quota_compliance_unix_asymmetric_peer2.conf\ test_transport_api_data.conf\ test_transport_api_http_peer1.conf\ test_transport_api_http_peer2.conf\ test_transport_api_https_peer1.conf\ test_transport_api_https_peer2.conf\ test_transport_api_limited_sockets_tcp_peer1.conf\ test_transport_api_limited_sockets_tcp_peer2.conf\ test_transport_api_timeout_tcp_peer1.conf\ test_transport_api_timeout_tcp_peer2.conf\ test_transport_api_multi_peer1.conf\ test_transport_api_multi_peer2.conf\ test_transport_api_reliability_http_peer1.conf\ test_transport_api_reliability_http_peer2.conf\ test_transport_api_reliability_https_peer1.conf\ test_transport_api_reliability_https_peer2.conf\ test_transport_api_reliability_tcp_nat_peer1.conf\ test_transport_api_reliability_tcp_nat_peer2.conf\ test_transport_api_reliability_tcp_peer1.conf\ test_transport_api_reliability_tcp_peer2.conf\ test_transport_api_reliability_wlan_peer1.conf\ test_transport_api_reliability_wlan_peer2.conf\ test_transport_api_bidirectional_connect_peer1.conf\ test_transport_api_bidirectional_connect_peer2.conf\ test_transport_api_tcp_nat_peer1.conf\ test_transport_api_tcp_nat_peer2.conf\ test_transport_api_tcp_peer1.conf\ test_transport_api_tcp_peer2.conf\ test_transport_api_udp_nat_peer1.conf\ test_transport_api_udp_nat_peer2.conf\ test_transport_api_udp_peer1.conf\ test_transport_api_udp_peer2.conf\ test_transport_api_timeout_udp_peer1.conf\ test_transport_api_timeout_udp_peer2.conf\ test_transport_api_unix_peer1.conf\ test_transport_api_unix_peer2.conf\ test_transport_api_timeout_unix_peer1.conf\ test_transport_api_timeout_unix_peer2.conf\ test_transport_api_unreliability_udp_peer1.conf\ test_transport_api_unreliability_udp_peer2.conf\ test_transport_api_unreliability_unix_peer1.conf\ test_transport_api_unreliability_unix_peer2.conf\ test_transport_api_unreliability_wlan_peer1.conf\ test_transport_api_unreliability_wlan_peer2.conf\ test_transport_api_wlan_peer1.conf\ test_transport_api_wlan_peer2.conf\ test_transport_defaults.conf\ test_transport_startonly.conf\ test_transport_api_disconnect_tcp_peer1.conf\ test_transport_api_disconnect_tcp_peer2.conf\ test_transport_api_http_nat_peer1.conf\ test_transport_api_http_nat_peer2.conf\ test_transport_api_https_nat_peer1.conf\ test_transport_api_https_nat_peer2.conf\ test_transport_api_reliability_http_nat_peer1.conf\ test_transport_api_reliability_http_nat_peer2.conf\ test_transport_api_reliability_https_nat_peer1.conf\ test_transport_api_reliability_https_nat_peer2.conf\ test_transport_api_timeout_http_peer1.conf\ test_transport_api_timeout_http_peer2.conf\ test_transport_api_timeout_https_peer1.conf\ test_transport_api_timeout_https_peer2.conf\ test_transport_api_unreliability_constant_udp_peer1.conf\ test_transport_api_unreliability_constant_udp_peer2.conf gnunet-0.9.3/src/transport/plugin_transport_http.h0000644000175000017500000002376611761753145017441 00000000000000/* This file is part of GNUnet (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/plugin_transport_http.h * @brief http transport service plugin * @author Matthias Wachs */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_constants.h" #include "gnunet_protocols.h" #include "gnunet_connection_lib.h" #include "gnunet_service_lib.h" #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" #include "gnunet_resolver_service.h" #include "gnunet_server_lib.h" #include "gnunet_container_lib.h" #include "gnunet_transport_plugin.h" #include "gnunet_os_lib.h" #include "gnunet_nat_lib.h" #include "microhttpd.h" #include #define DEBUG_HTTP GNUNET_EXTRA_LOGGING #define VERBOSE_SERVER GNUNET_EXTRA_LOGGING #define VERBOSE_CLIENT GNUNET_EXTRA_LOGGING #define VERBOSE_CURL GNUNET_NO #if BUILD_HTTPS #define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_https_init #define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_https_done #else #define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_http_init #define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_http_done #endif #define INBOUND GNUNET_YES #define OUTBOUND GNUNET_NO #define HTTP_NOT_VALIDATED_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) /** * Encapsulation of all of the state of the plugin. */ struct Plugin { /** * General handles * --------------- */ /** * Our environment. */ struct GNUNET_TRANSPORT_PluginEnvironment *env; /** * Linked list of open sessions. */ struct Session *head; struct Session *tail; /** * NAT handle & address management */ struct GNUNET_NAT_Handle *nat; /** * List of own addresses */ /** * IPv4 addresses DLL head */ struct IPv4HttpAddressWrapper *ipv4_addr_head; /** * IPv4 addresses DLL tail */ struct IPv4HttpAddressWrapper *ipv4_addr_tail; /** * IPv6 addresses DLL head */ struct IPv6HttpAddressWrapper *ipv6_addr_head; /** * IPv6 addresses DLL tail */ struct IPv6HttpAddressWrapper *ipv6_addr_tail; /** * Plugin configuration * -------------------- */ /** * Plugin name * Equals configuration section: transport-http, transport-https */ char *name; /** * Plugin protocol * http, https */ char *protocol; /** * Use IPv4? * GNUNET_YES or GNUNET_NO */ int ipv4; /** * Use IPv6? * GNUNET_YES or GNUNET_NO */ int ipv6; /** * Does plugin just use outbound connections and not accept inbound? */ int client_only; /** * Port used */ uint16_t port; /** * Maximum number of sockets the plugin can use * Each http inbound /outbound connections are two connections */ int max_connections; /** * Number of outbound sessions */ unsigned int outbound_sessions; /** * Number of inbound sessions */ unsigned int inbound_sessions; /** * Plugin HTTPS SSL/TLS options * ---------------------------- */ /** * libCurl TLS crypto init string, can be set to enhance performance * * Example: * * Use RC4-128 instead of AES: * NONE:+VERS-TLS1.0:+ARCFOUR-128:+SHA1:+RSA:+COMP-NULL * */ char *crypto_init; /** * TLS key */ char *key; /** * TLS certificate */ char *cert; /** * Plugin values * ------------- */ /** * Current number of establishes connections */ int cur_connections; /** * Last used unique HTTP connection tag */ uint32_t last_tag; /** * Server handles * -------------- */ /** * MHD IPv4 daemon */ struct MHD_Daemon *server_v4; /** * MHD IPv4 task */ GNUNET_SCHEDULER_TaskIdentifier server_v4_task; /** * The IPv4 server is scheduled to run asap */ int server_v4_immediately; /** * MHD IPv6 daemon */ struct MHD_Daemon *server_v6; /** * MHD IPv4 task */ GNUNET_SCHEDULER_TaskIdentifier server_v6_task; /** * The IPv6 server is scheduled to run asap */ int server_v6_immediately; /** * IPv4 server socket to bind to */ struct sockaddr_in *server_addr_v4; /** * IPv6 server socket to bind to */ struct sockaddr_in6 *server_addr_v6; /** * Server semi connections * A full session consists of 2 semi-connections: send and receive * If not both directions are established the server keeps this sessions here */ struct Session *server_semi_head; struct Session *server_semi_tail; /* * Client handles */ /** * cURL Multihandle */ CURLM *client_mh; /** * curl perform task */ GNUNET_SCHEDULER_TaskIdentifier client_perform_task; }; GNUNET_NETWORK_STRUCT_BEGIN /** * IPv4 addresses */ struct IPv4HttpAddress { /** * IPv4 address, in network byte order. */ uint32_t ipv4_addr GNUNET_PACKED; /** * Port number, in network byte order. */ uint16_t u4_port GNUNET_PACKED; }; /** * IPv4 addresses */ struct IPv6HttpAddress { /** * IPv6 address. */ struct in6_addr ipv6_addr GNUNET_PACKED; /** * Port number, in network byte order. */ uint16_t u6_port GNUNET_PACKED; }; GNUNET_NETWORK_STRUCT_END struct ServerConnection { /* _RECV or _SEND */ int direction; /* Should this connection get disconnected? GNUNET_YES/NO */ int disconnect; /* The session this server connection belongs to */ struct Session *session; /* The MHD connection */ struct MHD_Connection *mhd_conn; }; /** * Session handle for connections. */ struct Session { /** * Stored in a linked list. */ struct Session *next; /** * Stored in a linked list. */ struct Session *prev; /** * Pointer to the global plugin struct. */ struct Plugin *plugin; /** * Address */ void *addr; /** * Address length */ size_t addrlen; /** * ATS network type in NBO */ uint32_t ats_address_network_type; /** * To whom are we talking to */ struct GNUNET_PeerIdentity target; /** * next pointer for double linked list */ struct HTTP_Message *msg_head; /** * previous pointer for double linked list */ struct HTTP_Message *msg_tail; /** * Message stream tokenizer for incoming data */ struct GNUNET_SERVER_MessageStreamTokenizer *msg_tk; /** * Absolute time when to receive data again * Used for receive throttling */ struct GNUNET_TIME_Absolute next_receive; /** * Inbound or outbound connection * Outbound: GNUNET_NO (client is used to send and receive) * Inbound : GNUNET_YES (server is used to send and receive) */ int inbound; /** * Unique HTTP/S connection tag for this connection */ uint32_t tag; /** * Client handles */ /** * Client send handle */ void *client_put; /** * Client receive handle */ void *client_get; /** * Task to wake up client receive handle when receiving is allowed again */ GNUNET_SCHEDULER_TaskIdentifier recv_wakeup_task; /** * Session timeout task */ GNUNET_SCHEDULER_TaskIdentifier timeout_task; /** * Is client send handle paused since there are no data to send? * GNUNET_YES/NO */ int client_put_paused; /** * Server handles */ /** * Client send handle */ struct ServerConnection *server_recv; /** * Client send handle */ struct ServerConnection *server_send; }; /** * Message to send using http */ struct HTTP_Message { /** * next pointer for double linked list */ struct HTTP_Message *next; /** * previous pointer for double linked list */ struct HTTP_Message *prev; /** * buffer containing data to send */ char *buf; /** * amount of data already sent */ size_t pos; /** * buffer length */ size_t size; /** * Continuation function to call once the transmission buffer * has again space available. NULL if there is no * continuation to call. */ GNUNET_TRANSPORT_TransmitContinuation transmit_cont; /** * Closure for transmit_cont. */ void *transmit_cont_cls; }; struct Session * create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, const void *addr, size_t addrlen); int exist_session (struct Plugin *plugin, struct Session *s); void delete_session (struct Session *s); int exist_session (struct Plugin *plugin, struct Session *s); struct GNUNET_TIME_Relative http_plugin_receive (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, struct Session *session, const char *sender_address, uint16_t sender_address_len); const char * http_plugin_address_to_string (void *cls, const void *addr, size_t addrlen); int client_disconnect (struct Session *s); int client_connect (struct Session *s); int client_send (struct Session *s, struct HTTP_Message *msg); int client_start (struct Plugin *plugin); void client_stop (struct Plugin *plugin); int server_disconnect (struct Session *s); int server_send (struct Session *s, struct HTTP_Message *msg); int server_start (struct Plugin *plugin); void server_stop (struct Plugin *plugin); void notify_session_end (void *cls, const struct GNUNET_PeerIdentity *peer, struct Session *s); /* end of plugin_transport_http.h */ gnunet-0.9.3/src/transport/test_transport_api_reliability_http_peer1.conf0000644000175000017500000000113311665472561024121 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-http-p1/ DEFAULTCONFIG = test_transport_api_reliability_http_peer1.conf [transport-tcp] TIMEOUT = 5 s [transport-http] PORT = 12180 [arm] PORT = 12185 UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12184 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12183 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12182 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12181 PLUGINS = http UNIXPATH = /tmp/gnunet-p1-service-transport.sock #DEBUG = YES gnunet-0.9.3/src/transport/test_transport_api_timeout_tcp_peer1.conf0000644000175000017500000000112211750306133023065 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-tcp-p1/ DEFAULTCONFIG = test_transport_api_timeout_tcp_peer1.conf [transport-tcp] PORT = 12000 TIMEOUT = 5 s [arm] PORT = 12005 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12004 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12003 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12002 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12001 PLUGINS = tcp UNIXPATH = /tmp/gnunet-p1-service-transport.sock gnunet-0.9.3/src/transport/test_transport_api_unreliability_constant_udp_peer1.conf0000644000175000017500000000111411665472561026205 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-udp-p1/ DEFAULTCONFIG = test_transport_api_unreliability_constant_udp_peer1.conf [transport-udp] PORT = 12040 MAX_BPS = 1073741824 [arm] PORT = 12045 UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12044 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12043 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12042 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12041 PLUGINS = udp UNIXPATH = /tmp/gnunet-p1-service-transport.sock gnunet-0.9.3/src/transport/test_transport_api_reliability_https_nat_peer1.conf0000644000175000017500000000123011665472561025144 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-https-p1/ DEFAULTCONFIG = test_transport_api_reliability_https_nat_peer1.conf [nat] BEHIND_NAT = YES ENABLE_NAT_SERVER = YES [transport-https] PORT = 0 KEY_FILE = $SERVICEHOME/https_key_p1.key CERT_FILE = $SERVICEHOME/https_cert_p1.crt [arm] PORT = 12105 [statistics] PORT = 12104 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12103 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12102 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12101 PLUGINS = https UNIXPATH = /tmp/gnunet-p1-service-transport.sock DEBUG = NO gnunet-0.9.3/src/transport/test_transport_api_udp_peer2.conf0000644000175000017500000000110211663237620021327 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-udp-p2/ DEFAULTCONFIG = test_transport_api_udp_peer2.conf [transport-udp] PORT = 12050 BROADCAST = NO MAX_BPS = 50000000 [arm] PORT = 12055 UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12054 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12053 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12052 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12051 PLUGINS = udp UNIXPATH = /tmp/gnunet-p2-service-transport.sock gnunet-0.9.3/src/transport/test_transport_api_reliability_https_nat_peer2.conf0000644000175000017500000000122711665472561025153 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-https-p2/ DEFAULTCONFIG = test_transport_api_reliability_https_nat_peer2.conf [transport-https] PORT = 12110 KEY_FILE = $SERVICEHOME/https_key_p2.key CERT_FILE = $SERVICEHOME/https_cert_p2.crt [arm] PORT = 12115 UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12114 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12113 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12112 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12111 PLUGINS = https UNIXPATH = /tmp/gnunet-p2-service-transport.sock DEBUG = NO gnunet-0.9.3/src/transport/test_transport_api_http_nat_peer2.conf0000644000175000017500000000116411661530125022362 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-http-p2/ DEFAULTCONFIG = test_transport_api_http_nat_peer2.conf [transport-http] PORT = 12090 [arm] PORT = 12095 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12094 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12093 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12092 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] #DEBUG = YES PORT = 12091 PLUGINS = http UNIXPATH = /tmp/gnunet-p2-service-transport.sock #PREFIX = valgrind --leak-check=full gnunet-0.9.3/src/transport/transport_api_blacklist.c0000644000175000017500000001740411760502551017660 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/transport_api_blacklist.c * @brief library to access the blacklisting functions of the transport service * @author Christian Grothoff */ #include "platform.h" #include "gnunet_client_lib.h" #include "gnunet_arm_service.h" #include "gnunet_hello_lib.h" #include "gnunet_protocols.h" #include "gnunet_server_lib.h" #include "gnunet_time_lib.h" #include "gnunet_transport_service.h" #include "transport.h" /** * Handle for blacklisting requests. */ struct GNUNET_TRANSPORT_Blacklist { /** * Connection to transport service. */ struct GNUNET_CLIENT_Connection *client; /** * Configuration to use. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Pending handle for the current request. */ struct GNUNET_CLIENT_TransmitHandle *th; /** * Function to call for determining if a peer is allowed * to communicate with us. */ GNUNET_TRANSPORT_BlacklistCallback cb; /** * Closure for 'cb'. */ void *cb_cls; /** * Peer currently under consideration. */ struct GNUNET_PeerIdentity peer; }; /** * Establish blacklist connection to transport service. * * @param br overall handle */ static void reconnect (struct GNUNET_TRANSPORT_Blacklist *br); /** * Send our reply to a blacklisting request. * * @param br our overall context */ static void reply (struct GNUNET_TRANSPORT_Blacklist *br); /** * Handle blacklist queries. * * @param cls our overall handle * @param msg query */ static void query_handler (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_TRANSPORT_Blacklist *br = cls; const struct BlacklistMessage *bm; GNUNET_assert (br != NULL); if ((NULL == msg) || (ntohs (msg->size) != sizeof (struct BlacklistMessage)) || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY)) { reconnect (br); return; } bm = (const struct BlacklistMessage *) msg; GNUNET_break (0 == ntohl (bm->is_allowed)); br->peer = bm->peer; reply (br); } /** * Receive blacklist queries from transport service. * * @param br overall handle */ static void receive (struct GNUNET_TRANSPORT_Blacklist *br) { GNUNET_CLIENT_receive (br->client, &query_handler, br, GNUNET_TIME_UNIT_FOREVER_REL); } /** * Transmit the blacklist initialization request to the service. * * @param cls closure (struct GNUNET_TRANSPORT_Blacklist*) * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_blacklist_init (void *cls, size_t size, void *buf) { struct GNUNET_TRANSPORT_Blacklist *br = cls; struct GNUNET_MessageHeader req; br->th = NULL; if (buf == NULL) { reconnect (br); return 0; } req.size = htons (sizeof (struct GNUNET_MessageHeader)); req.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT); memcpy (buf, &req, sizeof (req)); receive (br); return sizeof (req); } /** * Establish blacklist connection to transport service. * * @param br overall handle */ static void reconnect (struct GNUNET_TRANSPORT_Blacklist *br) { if (br->client != NULL) GNUNET_CLIENT_disconnect (br->client); br->client = GNUNET_CLIENT_connect ("transport", br->cfg); GNUNET_assert (br->client != NULL); br->th = GNUNET_CLIENT_notify_transmit_ready (br->client, sizeof (struct GNUNET_MessageHeader), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &transmit_blacklist_init, br); } /** * Transmit the blacklist response to the service. * * @param cls closure (struct GNUNET_TRANSPORT_Blacklist*) * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_blacklist_reply (void *cls, size_t size, void *buf) { struct GNUNET_TRANSPORT_Blacklist *br = cls; struct BlacklistMessage req; br->th = NULL; if (buf == NULL) { reconnect (br); return 0; } req.header.size = htons (sizeof (req)); req.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY); req.is_allowed = htonl (br->cb (br->cb_cls, &br->peer)); req.peer = br->peer; memcpy (buf, &req, sizeof (req)); br->th = NULL; receive (br); return sizeof (req); } /** * Send our reply to a blacklisting request. * * @param br our overall context */ static void reply (struct GNUNET_TRANSPORT_Blacklist *br) { GNUNET_assert (br->th == NULL); br->th = GNUNET_CLIENT_notify_transmit_ready (br->client, sizeof (struct BlacklistMessage), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_NO, &transmit_blacklist_reply, br); if (br->th == NULL) { reconnect (br); return; } } /** * Install a blacklist callback. The service will be queried for all * existing connections as well as any fresh connections to check if * they are permitted. If the blacklisting callback is unregistered, * all hosts that were denied in the past will automatically be * whitelisted again. Cancelling the blacklist handle is also the * only way to re-enable connections from peers that were previously * blacklisted. * * @param cfg configuration to use * @param cb callback to invoke to check if connections are allowed * @param cb_cls closure for cb * @return NULL on error, otherwise handle for cancellation */ struct GNUNET_TRANSPORT_Blacklist * GNUNET_TRANSPORT_blacklist (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_TRANSPORT_BlacklistCallback cb, void *cb_cls) { struct GNUNET_CLIENT_Connection *client; struct GNUNET_TRANSPORT_Blacklist *ret; client = GNUNET_CLIENT_connect ("transport", cfg); if (NULL == client) return NULL; ret = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_Blacklist)); ret->client = client; ret->cfg = cfg; ret->cb = cb; ret->cb_cls = cb_cls; GNUNET_assert (ret->th == NULL); ret->th = GNUNET_CLIENT_notify_transmit_ready (client, sizeof (struct GNUNET_MessageHeader), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &transmit_blacklist_init, ret); return ret; } /** * Abort the blacklist. Note that this function is the only way for * removing a peer from the blacklist. * * @param br handle of the request that is to be cancelled */ void GNUNET_TRANSPORT_blacklist_cancel (struct GNUNET_TRANSPORT_Blacklist *br) { if (br->th != NULL) { GNUNET_CLIENT_notify_transmit_ready_cancel (br->th); br->th = NULL; } GNUNET_CLIENT_disconnect (br->client); GNUNET_free (br); } /* end of transport_api_blacklist.c */ gnunet-0.9.3/src/transport/test_transport_api_unreliability_wlan_peer1.conf0000644000175000017500000000104411665472561024447 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-wlan-p1/ DEFAULTCONFIG = test_transport_api_wlan_peer1.conf [transport-wlan] TESTMODE = 1 [arm] PORT = 12164 UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12163 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12162 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12161 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12160 PLUGINS = wlan UNIXPATH = /tmp/gnunet-p1-service-transport.sock gnunet-0.9.3/src/transport/test_transport_api_data.conf0000644000175000017500000000023011615567500020354 00000000000000@INLINE@ test_transport_defaults.conf [PATHS] DEFAULTCONFIG = test_transport_api_data.conf [transport-tcp] PORT = 2094 [transport-udp] PORT = 2094 gnunet-0.9.3/src/transport/test_quota_compliance_data.conf0000644000175000017500000000046311661530125021014 00000000000000@INLINE@ test_transport_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunetd-plugin-transport/ DEFAULTCONFIG = test_quota_compliance_data.conf [transport-tcp] PORT = 2368 TIMEOUT = 5 s [arm] PORT = 2366 [statistics] PORT = 2367 [resolver] PORT = 2364 [peerinfo] PORT = 2369 [transport] PORT = 2365 gnunet-0.9.3/src/transport/test_transport_api_wlan_peer1.conf0000644000175000017500000000156611665472561021524 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-wlan-p1/ DEFAULTCONFIG = test_transport_api_wlan_peer1.conf [transport-wlan] INTERFACE = mon0 TESTMODE = 1 [arm] DEBUG = YES PORT = 12164 UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12163 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12162 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12161 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12160 PLUGINS = wlan #DEBUG = YES UNIXPATH = /tmp/gnunet-p1-service-transport.sock #PREFIX = xterm -T transport2 -e gdb --command=cmd --args #PREFIX = valgrind --leak-check=full --show-reachable=yes --main-stacksize=104857600 #PREFIX = valgrind --leak-check=full --show-reachable=yes #PREFIX = valgrind --leak-check=full #PREFIX = valgrind --tool=massif #PREFIX = gdbserver :2345 gnunet-0.9.3/src/transport/test_transport_api_unreliability_unix_peer1.conf0000644000175000017500000000106111665472561024470 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-unix-p1/ DEFAULTCONFIG = test_transport_api_unreliability_unix_peer1.conf [arm] PORT = 12125 UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12124 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12123 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12122 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12121 PLUGINS = unix UNIXPATH = /tmp/gnunet-p1-service-transport.sock [transport-unix] PORT = 12120 gnunet-0.9.3/src/transport/test_transport_api_http_peer1.conf0000644000175000017500000000132211661530125021513 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-http-p1/ DEFAULTCONFIG = test_transport_api_http_peer1.conf [transport-http] PORT = 12080 [arm] PORT = 12085 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12084 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12083 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12082 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] #DEBUG = YES PORT = 12081 PLUGINS = http #BINARY = .libs/gnunet-service-transport UNIXPATH = /tmp/gnunet-p1-service-transport.sock #PREFIX = valgrind --leak-check=full #PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args gnunet-0.9.3/src/transport/test_transport_api_wlan_peer2.conf0000644000175000017500000000156511665472561021524 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-wlan-p2/ DEFAULTCONFIG = test_transport_api_wlan_peer2.conf [transport-wlan] INTERFACE = mon1 TESTMODE = 2 [arm] PORT = 12174 DEBUG = YES UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12173 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12172 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12171 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12170 PLUGINS = wlan #DEBUG = YES UNIXPATH = /tmp/gnunet-p2-service-transport.sock #PREFIX = xterm -T transport2 -e gdb --command=cmd --args #PREFIX = valgrind --leak-check=full --show-reachable=yes --main-stacksize=104857600 #PREFIX = valgrind --leak-check=full --show-reachable=yes #PREFIX = valgrind --leak-check=full #PREFIX = valgrind --tool=massif #PREFIX = gdbserver :2345 gnunet-0.9.3/src/transport/test_transport_api_multi_peer1.conf0000644000175000017500000000132211661530125021666 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-multi-p1/ DEFAULTCONFIG = test_transport_api_multi_peer1.conf [transport-tcp] PORT = 12140 TIMEOUT = 5 s [transport-udp] PORT = 12141 [transport-http] PORT = 12142 [transport-https] PORT = 12143 [arm] PORT = 12149 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12148 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12147 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12146 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12145 PLUGINS = tcp udp unix UNIXPATH = /tmp/gnunet-p1-service-transport.sock [transport-unix] PORT = 12144 gnunet-0.9.3/src/transport/test_transport_api_https_nat_peer2.conf0000644000175000017500000000121311661530125022540 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-https-p2/ DEFAULTCONFIG = test_transport_api_https_nat_peer2.conf [transport-https] PORT = 12110 KEY_FILE = $SERVICEHOME/https_key_p2.key CERT_FILE = $SERVICEHOME/https_cert_p2.crt [arm] PORT = 12115 UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12114 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12113 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12112 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12111 PLUGINS = https UNIXPATH = /tmp/gnunet-p2-service-transport.sock DEBUG = NO gnunet-0.9.3/src/transport/plugin_transport_http_server.c0000644000175000017500000011477511762211256021014 00000000000000/* This file is part of GNUnet (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/plugin_transport_http.c * @brief http transport service plugin * @author Matthias Wachs */ #include "plugin_transport_http.h" #define HTTP_ERROR_RESPONSE "404 Not Found

    Not Found

    The requested URL was not found on this server.


    " #define _RECEIVE 0 #define _SEND 1 static struct Plugin * p; /** * Function that queries MHD's select sets and * starts the task waiting for them. * @param plugin plugin * @param daemon_handle the MHD daemon handle * @param now schedule now or with MHD delay * @return gnunet task identifier */ static GNUNET_SCHEDULER_TaskIdentifier server_schedule (struct Plugin *plugin, struct MHD_Daemon *daemon_handle, int now); static void server_log (void *arg, const char *fmt, va_list ap) { char text[1024]; vsnprintf (text, sizeof (text), fmt, ap); va_end (ap); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Server: %s\n", text); } /** * Check if incoming connection is accepted. * NOTE: Here every connection is accepted * @param cls plugin as closure * @param addr address of incoming connection * @param addr_len address length of incoming connection * @return MHD_YES if connection is accepted, MHD_NO if connection is rejected * */ static int server_accept_cb (void *cls, const struct sockaddr *addr, socklen_t addr_len) { struct Plugin *plugin = cls; if (plugin->cur_connections <= plugin->max_connections) return MHD_YES; else { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Server: Cannot accept new connections\n"); return MHD_NO; } } #if BUILD_HTTPS static char * server_load_file (const char *file) { struct GNUNET_DISK_FileHandle *gn_file; uint64_t fsize; char *text = NULL; if (GNUNET_OK != GNUNET_DISK_file_size (file, &fsize, GNUNET_NO, GNUNET_YES)) return NULL; text = GNUNET_malloc (fsize + 1); gn_file = GNUNET_DISK_file_open (file, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_USER_READ); if (gn_file == NULL) { GNUNET_free (text); return NULL; } if (GNUNET_SYSERR == GNUNET_DISK_file_read (gn_file, text, fsize)) { GNUNET_free (text); GNUNET_DISK_file_close (gn_file); return NULL; } text[fsize] = '\0'; GNUNET_DISK_file_close (gn_file); return text; } #endif #if BUILD_HTTPS static int server_load_certificate (struct Plugin *plugin) { int res = GNUNET_OK; char *key_file; char *cert_file; /* Get crypto init string from config * If not present just use default values */ GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name, "CRYPTO_INIT", &plugin->crypto_init)); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name, "KEY_FILE", &key_file)) { key_file = GNUNET_strdup ("https_key.key"); } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name, "CERT_FILE", &cert_file)) { GNUNET_asprintf (&cert_file, "%s", "https_cert.crt"); } /* read key & certificates from file */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loading TLS certificate from key-file `%s' cert-file`%s'\n", key_file, cert_file); plugin->key = server_load_file (key_file); plugin->cert = server_load_file (cert_file); if ((plugin->key == NULL) || (plugin->cert == NULL)) { struct GNUNET_OS_Process *cert_creation; GNUNET_free_non_null (plugin->key); plugin->key = NULL; GNUNET_free_non_null (plugin->cert); plugin->cert = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No usable TLS certificate found, creating certificate\n"); errno = 0; cert_creation = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "gnunet-transport-certificate-creation", "gnunet-transport-certificate-creation", key_file, cert_file, NULL); if (cert_creation == NULL) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, _ ("Could not create a new TLS certificate, program `gnunet-transport-certificate-creation' could not be started!\n")); GNUNET_free (key_file); GNUNET_free (cert_file); GNUNET_free_non_null (plugin->key); plugin->key = NULL; GNUNET_free_non_null (plugin->cert); plugin->cert = NULL; GNUNET_free_non_null (plugin->crypto_init); plugin->crypto_init = NULL; return GNUNET_SYSERR; } GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (cert_creation)); GNUNET_OS_process_destroy (cert_creation); plugin->key = server_load_file (key_file); plugin->cert = server_load_file (cert_file); } if ((plugin->key == NULL) || (plugin->cert == NULL)) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, _ ("No usable TLS certificate found and creating one failed!\n"), "transport-https"); GNUNET_free (key_file); GNUNET_free (cert_file); GNUNET_free_non_null (plugin->key); plugin->key = NULL; GNUNET_free_non_null (plugin->cert); plugin->cert = NULL; GNUNET_free_non_null (plugin->crypto_init); plugin->crypto_init = NULL; return GNUNET_SYSERR; } GNUNET_free (key_file); GNUNET_free (cert_file); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TLS certificate loaded\n"); return res; } #endif /** * Reschedule the execution of both IPv4 and IPv6 server * @param plugin the plugin * @param server which server to schedule v4 or v6? * @param now GNUNET_YES to schedule execution immediately, GNUNET_NO to wait * until timeout */ static void server_reschedule (struct Plugin *plugin, struct MHD_Daemon *server, int now) { if ((server == plugin->server_v4) && (plugin->server_v4 != NULL)) { if (GNUNET_YES == plugin->server_v4_immediately) return; /* No rescheduling, server will run asap */ if (GNUNET_YES == now) plugin->server_v4_immediately = GNUNET_YES; if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (plugin->server_v4_task); plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; } plugin->server_v4_task = server_schedule (plugin, plugin->server_v4, now); } if ((server == plugin->server_v6) && (plugin->server_v6 != NULL)) { if (GNUNET_YES == plugin->server_v6_immediately) return; /* No rescheduling, server will run asap */ if (GNUNET_YES == now) plugin->server_v6_immediately = GNUNET_YES; if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (plugin->server_v6_task); plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; } plugin->server_v6_task = server_schedule (plugin, plugin->server_v6, now); } } /** * Callback called by MessageStreamTokenizer when a message has arrived * @param cls current session as closure * @param client clien * @param message the message to be forwarded to transport service */ static int server_receive_mst_cb (void *cls, void *client, const struct GNUNET_MessageHeader *message) { struct Session *s = cls; GNUNET_assert (NULL != p); if (GNUNET_NO == exist_session(p, s)) return GNUNET_OK; struct Plugin *plugin = s->plugin; struct GNUNET_TIME_Relative delay; delay = http_plugin_receive (s, &s->target, message, s, s->addr, s->addrlen); s->next_receive = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), delay); if (delay.rel_value > 0) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Server: peer `%s' address `%s' next read delayed for %llu ms\n", GNUNET_i2s (&s->target), http_plugin_address_to_string (NULL, s->addr, s->addrlen), delay); } return GNUNET_OK; } /** * Callback called by MHD when it needs data to send * @param cls current session * @param pos position in buffer * @param buf the buffer to write data to * @param max max number of bytes available in buffer * @return bytes written to buffer */ static ssize_t server_send_callback (void *cls, uint64_t pos, char *buf, size_t max) { struct Session *s = cls; ssize_t bytes_read = 0; struct HTTP_Message *msg; GNUNET_assert (NULL != p); if (GNUNET_NO == exist_session(p, s)) return 0; msg = s->msg_head; if (NULL != msg) { /* sending */ bytes_read = GNUNET_MIN (msg->size - msg->pos, max); memcpy (buf, &msg->buf[msg->pos], bytes_read); msg->pos += bytes_read; /* removing message */ if (msg->pos == msg->size) { GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); if (NULL != msg->transmit_cont) msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK); GNUNET_free (msg); } } GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, "Server: %p: sent %u bytes\n", s, bytes_read); return bytes_read; } static struct Session * server_lookup_session (struct Plugin *plugin, struct ServerConnection * sc) { struct Session *s; for (s = plugin->head; NULL != s; s = s->next) if ((s->server_recv == sc) || (s->server_send == sc)) return s; for (s = plugin->server_semi_head; NULL != s; s = s->next) if ((s->server_recv == sc) || (s->server_send == sc)) return s; return NULL; } static struct ServerConnection * server_lookup_serverconnection (struct Plugin *plugin, struct MHD_Connection *mhd_connection, const char *url, const char *method) { struct Session *s = NULL; struct Session *t; struct ServerConnection *sc = NULL; const union MHD_ConnectionInfo *conn_info; struct GNUNET_ATS_Information ats; struct IPv4HttpAddress a4; struct IPv6HttpAddress a6; struct sockaddr_in *s4; struct sockaddr_in6 *s6; void *a; size_t a_len; struct GNUNET_PeerIdentity target; int check = GNUNET_NO; uint32_t tag = 0; int direction = GNUNET_SYSERR; conn_info = MHD_get_connection_info (mhd_connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS); if ((conn_info->client_addr->sa_family != AF_INET) && (conn_info->client_addr->sa_family != AF_INET6)) return NULL; if ((strlen (&url[1]) >= 105) && (url[104] == ';')) { char hash[104]; char *tagc = (char *) &url[105]; memcpy (&hash, &url[1], 103); hash[103] = '\0'; if (GNUNET_OK == GNUNET_CRYPTO_hash_from_string ((const char *) &hash, &(target.hashPubKey))) { tag = strtoul (tagc, NULL, 10); if (tagc > 0) check = GNUNET_YES; } } if (0 == strcmp (MHD_HTTP_METHOD_PUT, method)) direction = _RECEIVE; else if (0 == strcmp (MHD_HTTP_METHOD_GET, method)) direction = _SEND; else { GNUNET_break_op (0); goto error; } if (check == GNUNET_NO) goto error; plugin->cur_connections++; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Server: New %s connection from %s with tag %u\n", method, GNUNET_i2s (&target), tag); /* find duplicate session */ t = plugin->head; while (t != NULL) { if ((t->inbound) && (0 == memcmp (&t->target, &target, sizeof (struct GNUNET_PeerIdentity))) && /* FIXME add source address comparison */ (t->tag == tag)) break; t = t->next; } if (t != NULL) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Server: Duplicate session, dismissing new connection from peer `%s'\n", GNUNET_i2s (&target)); goto error; } /* find semi-session */ t = plugin->server_semi_head; while (t != NULL) { /* FIXME add source address comparison */ if ((0 == memcmp (&t->target, &target, sizeof (struct GNUNET_PeerIdentity))) && (t->tag == tag)) { break; } t = t->next; } if (t == NULL) goto create; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Server: Found existing semi-session for `%s'\n", GNUNET_i2s (&target)); if ((direction == _SEND) && (t->server_send != NULL)) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Server: Duplicate GET session, dismissing new connection from peer `%s'\n", GNUNET_i2s (&target)); goto error; } else { s = t; GNUNET_CONTAINER_DLL_remove (plugin->server_semi_head, plugin->server_semi_tail, s); GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Server: Found matching semi-session, merging session for peer `%s'\n", GNUNET_i2s (&target)); plugin->inbound_sessions ++; GNUNET_STATISTICS_set (plugin->env->stats, "# HTTP inbound sessions", plugin->inbound_sessions, GNUNET_NO); GNUNET_assert (NULL != s); goto found; } if ((direction == _RECEIVE) && (t->server_recv != NULL)) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Server: Duplicate PUT session, dismissing new connection from peer `%s'\n", GNUNET_i2s (&target)); goto error; } else { s = t; GNUNET_CONTAINER_DLL_remove (plugin->server_semi_head, plugin->server_semi_tail, s); GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Server: Found matching semi-session, merging session for peer `%s'\n", GNUNET_i2s (&target)); plugin->inbound_sessions ++; GNUNET_STATISTICS_set (plugin->env->stats, "# HTTP inbound sessions", plugin->inbound_sessions, GNUNET_NO); GNUNET_assert (NULL != s); goto found; } create: /* create new session */ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Server: Creating new session for peer `%s' \n", GNUNET_i2s (&target)); switch (conn_info->client_addr->sa_family) { case (AF_INET): s4 = ((struct sockaddr_in *) conn_info->client_addr); a4.u4_port = s4->sin_port; memcpy (&a4.ipv4_addr, &s4->sin_addr, sizeof (struct in_addr)); a = &a4; a_len = sizeof (struct IPv4HttpAddress); ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) s4, sizeof (struct sockaddr_in)); break; case (AF_INET6): s6 = ((struct sockaddr_in6 *) conn_info->client_addr); a6.u6_port = s6->sin6_port; memcpy (&a6.ipv6_addr, &s6->sin6_addr, sizeof (struct in6_addr)); a = &a6; a_len = sizeof (struct IPv6HttpAddress); ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) s6, sizeof (struct sockaddr_in6)); break; default: GNUNET_break (0); goto error; } s = create_session (plugin, &target, a, a_len); GNUNET_assert (NULL != s); s->ats_address_network_type = ats.value; s->inbound = GNUNET_YES; s->next_receive = GNUNET_TIME_UNIT_ZERO_ABS; s->tag = tag; s->server_recv = NULL; s->server_send = NULL; GNUNET_CONTAINER_DLL_insert (plugin->server_semi_head, plugin->server_semi_tail, s); goto found; error: GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Server: Invalid connection request\n"); return NULL; found: sc = GNUNET_malloc (sizeof (struct ServerConnection)); sc->mhd_conn = mhd_connection; sc->direction = direction; sc->session = s; if (direction == _SEND) s->server_send = sc; if (direction == _RECEIVE) s->server_recv = sc; #if MHD_VERSION >= 0x00090E00 int to = (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Server: Setting timeout for %p to %u sec.\n", sc, to); MHD_set_connection_option (mhd_connection, MHD_CONNECTION_OPTION_TIMEOUT, to); struct MHD_Daemon *d = NULL; if (s->addrlen == sizeof (struct IPv6HttpAddress)) d = plugin->server_v6; if (s->addrlen == sizeof (struct IPv4HttpAddress)) d = plugin->server_v4; server_reschedule (plugin, d, GNUNET_NO); #endif return sc; } /** * Process GET or PUT request received via MHD. For * GET, queue response that will send back our pending * messages. For PUT, process incoming data and send * to GNUnet core. In either case, check if a session * already exists and create a new one if not. */ static int server_access_cb (void *cls, struct MHD_Connection *mhd_connection, const char *url, const char *method, const char *version, const char *upload_data, size_t * upload_data_size, void **httpSessionCache) { struct Plugin *plugin = cls; struct ServerConnection *sc = *httpSessionCache; struct Session *s; struct MHD_Response *response; int res = MHD_YES; GNUNET_assert (cls != NULL); if (sc == NULL) { /* new connection */ sc = server_lookup_serverconnection (plugin, mhd_connection, url, method); if (sc != NULL) (*httpSessionCache) = sc; else { response = MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE), HTTP_ERROR_RESPONSE, MHD_NO, MHD_NO); res = MHD_queue_response (mhd_connection, MHD_HTTP_NOT_FOUND, response); MHD_destroy_response (response); return res; } } else { /* 'old' connection */ if (NULL == server_lookup_session (plugin, sc)) { /* Session was already disconnected */ return MHD_NO; } } /* existing connection */ sc = (*httpSessionCache); s = sc->session; GNUNET_assert (NULL != s); /* connection is to be disconnected */ if (sc->disconnect == GNUNET_YES) { /* Sent HTTP/1.1: 200 OK as PUT Response\ */ response = MHD_create_response_from_data (strlen ("Thank you!"), "Thank you!", MHD_NO, MHD_NO); res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response); MHD_destroy_response (response); return MHD_YES; } GNUNET_assert (s != NULL); /* Check if both directions are connected */ if ((sc->session->server_recv == NULL) || (sc->session->server_send == NULL)) { /* Delayed read from since not both semi-connections are connected */ return MHD_YES; } if (sc->direction == _SEND) { response = MHD_create_response_from_callback (-1, 32 * 1024, &server_send_callback, s, NULL); MHD_queue_response (mhd_connection, MHD_HTTP_OK, response); MHD_destroy_response (response); return MHD_YES; } if (sc->direction == _RECEIVE) { if (*upload_data_size == 0) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Server: Peer `%s' PUT on address `%s' connected\n", GNUNET_i2s (&s->target), http_plugin_address_to_string (NULL, s->addr, s->addrlen)); return MHD_YES; } /* Receiving data */ if ((*upload_data_size > 0)) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Server: peer `%s' PUT on address `%s' received %u bytes\n", GNUNET_i2s (&s->target), http_plugin_address_to_string (NULL, s->addr, s->addrlen), *upload_data_size); struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); if ((s->next_receive.abs_value <= now.abs_value)) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Server: %p: PUT with %u bytes forwarded to MST\n", s, *upload_data_size); if (s->msg_tk == NULL) { s->msg_tk = GNUNET_SERVER_mst_create (&server_receive_mst_cb, s); } GNUNET_SERVER_mst_receive (s->msg_tk, s, upload_data, *upload_data_size, GNUNET_NO, GNUNET_NO); #if MHD_VERSION >= 0x00090E00 int to = (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000); struct ServerConnection *t = NULL; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Server: Received %u bytes\n", *upload_data_size); /* Setting timeouts for other connections */ if (s->server_recv != NULL) { t = s->server_recv; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Server: Setting timeout for %p to %u sec.\n", t, to); MHD_set_connection_option (t->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, to); } if (s->server_send != NULL) { t = s->server_send; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Server: Setting timeout for %p to %u sec.\n", t, to); MHD_set_connection_option (t->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, to); } struct MHD_Daemon *d = NULL; if (s->addrlen == sizeof (struct IPv6HttpAddress)) d = plugin->server_v6; if (s->addrlen == sizeof (struct IPv4HttpAddress)) d = plugin->server_v4; server_reschedule (plugin, d, GNUNET_NO); #endif (*upload_data_size) = 0; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Server: %p no inbound bandwidth available! Next read was delayed by %llu ms\n", s, now.abs_value - s->next_receive.abs_value); } return MHD_YES; } else return MHD_NO; } return res; } static void server_disconnect_cb (void *cls, struct MHD_Connection *connection, void **httpSessionCache) { struct ServerConnection *sc = *httpSessionCache; struct ServerConnection *tc = NULL; struct Session *s = NULL; struct Session *t = NULL; struct Plugin *plugin = NULL; if (sc == NULL) return; if (NULL == (s = server_lookup_session (p, sc))) return; GNUNET_assert (NULL != p); if (GNUNET_NO == exist_session(p, s)) return; plugin = s->plugin; if (sc->direction == _SEND) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Server: %p peer `%s' GET on address `%s' disconnected\n", s->server_send, GNUNET_i2s (&s->target), http_plugin_address_to_string (NULL, s->addr, s->addrlen)); s->server_send = NULL; if (NULL != (tc = s->server_recv)) { tc->disconnect = GNUNET_YES; GNUNET_assert (NULL != tc->mhd_conn); #if MHD_VERSION >= 0x00090E00 MHD_set_connection_option (tc->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, 1); #endif } } if (sc->direction == _RECEIVE) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Server: %p peer `%s' PUT on address `%s' disconnected\n", s->server_recv, GNUNET_i2s (&s->target), http_plugin_address_to_string (NULL, s->addr, s->addrlen)); s->server_recv = NULL; if (NULL != (tc = s->server_send)) { tc->disconnect = GNUNET_YES; GNUNET_assert (NULL != tc->mhd_conn); #if MHD_VERSION >= 0x00090E00 MHD_set_connection_option (tc->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, 1); #endif } if (s->msg_tk != NULL) { GNUNET_SERVER_mst_destroy (s->msg_tk); s->msg_tk = NULL; } } GNUNET_free (sc); t = plugin->server_semi_head; while (t != NULL) { if (t == s) { GNUNET_CONTAINER_DLL_remove (plugin->server_semi_head, plugin->server_semi_tail, s); GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); break; } t = t->next; } plugin->cur_connections--; struct MHD_Daemon *d = NULL; if (s->addrlen == sizeof (struct IPv6HttpAddress)) d = plugin->server_v6; if (s->addrlen == sizeof (struct IPv4HttpAddress)) d = plugin->server_v4; server_reschedule (plugin, d, GNUNET_NO); if ((s->server_send == NULL) && (s->server_recv == NULL)) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Server: peer `%s' on address `%s' disconnected\n", GNUNET_i2s (&s->target), http_plugin_address_to_string (NULL, s->addr, s->addrlen)); if (s->msg_tk != NULL) { GNUNET_SERVER_mst_destroy (s->msg_tk); s->msg_tk = NULL; } GNUNET_assert (plugin->inbound_sessions > 0); plugin->inbound_sessions --; GNUNET_STATISTICS_set (plugin->env->stats, "# HTTP inbound sessions", plugin->inbound_sessions, GNUNET_NO); notify_session_end (s->plugin, &s->target, s); } } int server_disconnect (struct Session *s) { if (s->server_send != NULL) { ((struct ServerConnection *) s->server_send)->disconnect = GNUNET_YES; } if (s->server_recv != NULL) { ((struct ServerConnection *) s->server_recv)->disconnect = GNUNET_YES; } return GNUNET_OK; } int server_send (struct Session *s, struct HTTP_Message *msg) { GNUNET_CONTAINER_DLL_insert_tail (s->msg_head, s->msg_tail, msg); if (s->addrlen == sizeof (struct IPv4HttpAddress)) { server_reschedule (s->plugin, s->plugin->server_v4, GNUNET_YES); } else if (s->addrlen == sizeof (struct IPv6HttpAddress)) { server_reschedule (s->plugin, s->plugin->server_v6, GNUNET_YES); } else return GNUNET_SYSERR; return GNUNET_OK; } /** * Call MHD IPv4 to process pending requests and then go back * and schedule the next run. * @param cls plugin as closure * @param tc task context */ static void server_v4_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Plugin *plugin = cls; GNUNET_assert (cls != NULL); plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; #if 0 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Running IPv4 server\n"); #endif plugin->server_v4_immediately = GNUNET_NO; GNUNET_assert (MHD_YES == MHD_run (plugin->server_v4)); server_reschedule (plugin, plugin->server_v4, GNUNET_NO); } /** * Call MHD IPv6 to process pending requests and then go back * and schedule the next run. * @param cls plugin as closure * @param tc task context */ static void server_v6_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Plugin *plugin = cls; GNUNET_assert (cls != NULL); plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; #if 0 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Running IPv6 server\n"); #endif plugin->server_v6_immediately = GNUNET_NO; GNUNET_assert (MHD_YES == MHD_run (plugin->server_v6)); server_reschedule (plugin, plugin->server_v6, GNUNET_NO); } /** * Function that queries MHD's select sets and * starts the task waiting for them. * @param plugin plugin * @param daemon_handle the MHD daemon handle * @return gnunet task identifier */ static GNUNET_SCHEDULER_TaskIdentifier server_schedule (struct Plugin *plugin, struct MHD_Daemon *daemon_handle, int now) { GNUNET_SCHEDULER_TaskIdentifier ret; fd_set rs; fd_set ws; fd_set es; struct GNUNET_NETWORK_FDSet *wrs; struct GNUNET_NETWORK_FDSet *wws; struct GNUNET_NETWORK_FDSet *wes; int max; unsigned MHD_LONG_LONG timeout; static unsigned long long last_timeout = 0; int haveto; struct GNUNET_TIME_Relative tv; ret = GNUNET_SCHEDULER_NO_TASK; FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es); wrs = GNUNET_NETWORK_fdset_create (); wes = GNUNET_NETWORK_fdset_create (); wws = GNUNET_NETWORK_fdset_create (); max = -1; GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max)); haveto = MHD_get_timeout (daemon_handle, &timeout); if (haveto == MHD_YES) { if (timeout != last_timeout) { #if VERBOSE_SERVER GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "SELECT Timeout changed from %llu to %llu\n", last_timeout, timeout); #endif last_timeout = timeout; } tv.rel_value = (uint64_t) timeout; } else tv = GNUNET_TIME_UNIT_SECONDS; /* Force immediate run, since we have outbound data to send */ if (now == GNUNET_YES) tv = GNUNET_TIME_UNIT_MILLISECONDS; GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1); if (daemon_handle == plugin->server_v4) { if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (plugin->server_v4_task); plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; } #if 0 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Scheduling IPv4 server task in %llu ms\n", tv); #endif ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, tv, wrs, wws, &server_v4_run, plugin); } if (daemon_handle == plugin->server_v6) { if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (plugin->server_v6_task); plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; } #if 0 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Scheduling IPv6 server task in %llu ms\n", tv); #endif ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, tv, wrs, wws, &server_v6_run, plugin); } GNUNET_NETWORK_fdset_destroy (wrs); GNUNET_NETWORK_fdset_destroy (wws); GNUNET_NETWORK_fdset_destroy (wes); return ret; } int server_start (struct Plugin *plugin) { int res = GNUNET_OK; unsigned int timeout; p = plugin; GNUNET_assert (NULL != plugin); #if BUILD_HTTPS res = server_load_certificate (plugin); if (res == GNUNET_SYSERR) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "Could not load or create server certificate! Loading plugin failed!\n"); return res; } #endif #if MHD_VERSION >= 0x00090E00 timeout = HTTP_NOT_VALIDATED_TIMEOUT.rel_value / 1000; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "MHD can set timeout per connection! Default time out %u sec.\n", timeout); #else timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000; GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name, "MHD cannot set timeout per connection! Default time out %u sec.\n", timeout); #endif plugin->server_v4 = NULL; if (plugin->ipv4 == GNUNET_YES) { plugin->server_v4 = MHD_start_daemon ( #if VERBOSE_SERVER MHD_USE_DEBUG | #endif #if BUILD_HTTPS MHD_USE_SSL | #endif MHD_NO_FLAG, plugin->port, &server_accept_cb, plugin, &server_access_cb, plugin, MHD_OPTION_SOCK_ADDR, (struct sockaddr_in *) plugin->server_addr_v4, MHD_OPTION_CONNECTION_LIMIT, (unsigned int) plugin->max_connections, #if BUILD_HTTPS MHD_OPTION_HTTPS_PRIORITIES, plugin->crypto_init, MHD_OPTION_HTTPS_MEM_KEY, plugin->key, MHD_OPTION_HTTPS_MEM_CERT, plugin->cert, #endif MHD_OPTION_CONNECTION_TIMEOUT, timeout, MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (2 * GNUNET_SERVER_MAX_MESSAGE_SIZE), MHD_OPTION_NOTIFY_COMPLETED, &server_disconnect_cb, plugin, MHD_OPTION_EXTERNAL_LOGGER, server_log, NULL, MHD_OPTION_END); } plugin->server_v6 = NULL; if (plugin->ipv6 == GNUNET_YES) { plugin->server_v6 = MHD_start_daemon ( #if VERBOSE_SERVER MHD_USE_DEBUG | #endif #if BUILD_HTTPS MHD_USE_SSL | #endif MHD_USE_IPv6, plugin->port, &server_accept_cb, plugin, &server_access_cb, plugin, MHD_OPTION_SOCK_ADDR, (struct sockaddr_in6 *) plugin->server_addr_v6, MHD_OPTION_CONNECTION_LIMIT, (unsigned int) plugin->max_connections, #if BUILD_HTTPS MHD_OPTION_HTTPS_PRIORITIES, plugin->crypto_init, MHD_OPTION_HTTPS_MEM_KEY, plugin->key, MHD_OPTION_HTTPS_MEM_CERT, plugin->cert, #endif MHD_OPTION_CONNECTION_TIMEOUT, timeout, MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (2 * GNUNET_SERVER_MAX_MESSAGE_SIZE), MHD_OPTION_NOTIFY_COMPLETED, &server_disconnect_cb, plugin, MHD_OPTION_EXTERNAL_LOGGER, server_log, NULL, MHD_OPTION_END); } if ((plugin->ipv4 == GNUNET_YES) && (plugin->server_v4 == NULL)) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "Failed to start %s IPv4 server component on port %u\n", plugin->name, plugin->port); return GNUNET_SYSERR; } server_reschedule (plugin, plugin->server_v4, GNUNET_NO); if ((plugin->ipv6 == GNUNET_YES) && (plugin->server_v6 == NULL)) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "Failed to start %s IPv6 server component on port %u\n", plugin->name, plugin->port); return GNUNET_SYSERR; } server_reschedule (plugin, plugin->server_v6, GNUNET_NO); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "%s server component started on port %u\n", plugin->name, plugin->port); return res; } void server_stop (struct Plugin *plugin) { struct Session *s = NULL; struct Session *t = NULL; struct MHD_Daemon *server_v4_tmp = plugin->server_v4; plugin->server_v4 = NULL; struct MHD_Daemon *server_v6_tmp = plugin->server_v6; plugin->server_v6 = NULL; if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (plugin->server_v4_task); plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; } if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (plugin->server_v6_task); plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; } if (server_v6_tmp != NULL) { MHD_stop_daemon (server_v4_tmp); } if (server_v6_tmp != NULL) { MHD_stop_daemon (server_v6_tmp); } /* cleaning up semi-sessions never propagated */ s = plugin->server_semi_head; while (s != NULL) { #if VERBOSE_SERVER GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Deleting semi-sessions %p\n", s); #endif t = s->next; struct HTTP_Message *msg = s->msg_head; struct HTTP_Message *tmp = NULL; while (msg != NULL) { tmp = msg->next; GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); if (msg->transmit_cont != NULL) { msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR); } GNUNET_free (msg); msg = tmp; } delete_session (s); s = t; } p = NULL; #if BUILD_HTTPS GNUNET_free_non_null (plugin->crypto_init); GNUNET_free_non_null (plugin->cert); GNUNET_free_non_null (plugin->key); #endif GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "%s server component stopped\n", plugin->name); } /* end of plugin_transport_http.c */ gnunet-0.9.3/src/transport/test_transport_api_reliability_wlan_peer2.conf0000644000175000017500000000106411665472561024107 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-wlan-p2/ DEFAULTCONFIG = test_transport_api_wlan_peer2.conf [transport-wlan] INTERFACE = mon1 TESTMODE = 2 [arm] PORT = 12174 UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12173 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12172 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12171 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12170 PLUGINS = wlan UNIXPATH = /tmp/gnunet-p2-service-transport.sock gnunet-0.9.3/src/transport/test_transport_api_udp_nat_peer1.conf0000644000175000017500000000121311723116126022165 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-udp-nat-p1/ DEFAULTCONFIG = test_transport_api_udp_nat_peer1.conf [nat] BEHIND_NAT = YES ALLOW_NAT = NO ONLY_NAT_ADDRESSES = YES [transport-udp] PORT = 0 [arm] PORT = 12065 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12064 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12063 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12062 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12061 PLUGINS = udp UNIXPATH = /tmp/gnunet-p1-service-transport.sock DEBUG = NO gnunet-0.9.3/src/transport/test_transport_api_reliability_tcp_peer2.conf0000644000175000017500000000114111750306133023712 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-tcp-p2/ DEFAULTCONFIG = test_transport_api_reliability_tcp_peer2.conf [transport-tcp] PORT = 12015 TIMEOUT = 5 s [arm] PORT = 12014 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12013 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12012 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12011 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12010 PLUGINS = tcp UNIXPATH = /tmp/gnunet-p2-service-transport.sock #DEBUG = YES gnunet-0.9.3/src/transport/test_quota_compliance_https_asymmetric_peer1.conf0000644000175000017500000000127311661530125024576 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test_quota_compliance_peer1/ DEFAULTCONFIG = test_quota_compliance_https_peer1.conf [transport-https] PORT = 4001 KEY_FILE = https_key_quota_p1.key CERT_FILE = https_cert_quota_p1.crt [arm] PORT = 4006 UNIXPATH = /tmp/test_quota_compliance_https_arm_peer1.sock [statistics] PORT = 4005 UNIXPATH = /tmp/test_quota_compliance_https_statistics_peer1.sock [resolver] PORT = 4004 UNIXPATH = /tmp/test_quota_compliance_https_resolver_peer1.sock [peerinfo] PORT = 4003 UNIXPATH = /tmp/test_quota_compliance_https_peerinfo_peer1.sock [transport] PORT = 4002 PLUGINS = https UNIXPATH = /tmp/test_quota_compliance_https_transport_peer1.sock gnunet-0.9.3/src/transport/gnunet-helper-transport-wlan.c0000644000175000017500000017027111760502551020513 00000000000000/* This file is part of GNUnet. (C) 2010, 2011, 2012 Christian Grothoff (and other contributing authors) Copyright (c) 2007, 2008, Andy Green Copyright (C) 2009 Thomas d'Otreppe GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/transport/gnunet-helper-transport-wlan.c * @brief mediator between the wlan interface and gnunet; must run as root (SUID will do) * This code will work under GNU/Linux only. * @author David Brodski * @author Christian Grothoff * * This program will allow receiving and sending traffic from the WLAN * interface. It will force traffic to be in 'ad-hoc' mode, use the * proper MAC address of the WLAN interface and use a GNUnet-specific * SSID (and a GNUnet-specific SNAP header). It only takes a single * argument, which is the name of the WLAN interface to use. The * program detects if the interface is not a WLAN interface and exits * with an error in that case. * * Once initialized, the program will first send a 'struct * GNUNET_TRANSPORT_WLAN_HelperControlMessage' to 'stdout'. That * message contains the MAC address of the WLAN interface. It will * then read messages from the WLAN interface and send them together * with performance information as 'struct * GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage' messages to 'stdout'. * Furthermore, it will read a stream of messages from 'stdin' that * have the format from 'struct * GNUNET_TRANSPORT_WLAN_RadiotapSendMessage'. Those messages will * then be sent via the WLAN interface; however, the sender MAC * address will be forced to be the correct address from our WLAN * card. If 'stdin' closes, receiving from the WLAN interface will * continue. If 'stdout' causes a SIGPIPE, the process dies from the * signal. Errors cause an error message to be reported to 'stderr', * in most cases the process also exits (with status code '1'). The * program never terminates normally; it is safe to kill the * process with SIGTERM or SIGKILL at any time. * * Since it uses RAW sockets, the binary must be installed SUID or run * as 'root'. In order to keep the security risk of the resulting * SUID binary minimal, the program ONLY opens the RAW socket with * root privileges, then drops them and only then starts to process * command line arguments. The code also does not link against any * shared libraries (except libc) and is strictly minimal (except for * checking for errors). The following list of people have reviewed * this code and considered it safe since the last modification (if * you reviewed it, please have your name added to the list): * * - Christian Grothoff (Apr 3rd 2012) */ /*- * we use our local copy of ieee80211_radiotap.h * * - since we can't support extensions we don't understand * - since linux does not include it in userspace headers * * Portions of this code were taken from the ieee80211_radiotap.h header, * which is * * Copyright (c) 2003, 2004 David Young. 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. The name of David Young may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``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 DAVID * YOUNG 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. */ /* * Modifications to fit into the linux IEEE 802.11 stack, * Mike Kershaw (dragorn@kismetwireless.net) */ /* * parts taken from aircrack-ng, parts changend. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gnunet_protocols.h" #include "plugin_transport_wlan.h" /** * Packet format type for the messages we receive from * the kernel. This is for plain messages (with no * performance information included). */ #define ARPHRD_IEEE80211 801 /** * Packet format type for the messages we receive from * the kernel. This is for the PRISM format. */ #define ARPHRD_IEEE80211_PRISM 802 /** * Packet format type for the messages we receive from * the kernel. This is for messages with a * 'struct Ieee80211RadiotapHeader' (see below). */ #define ARPHRD_IEEE80211_FULL 803 /** * Maximum size of a message allowed in either direction * (used for our receive and sent buffers). */ #define MAXLINE 4096 /* ********* structure of messages of type ARPHRD_IEEE80211_PRISM *********** */ /** * Device name length in PRISM frames. * (In the kernel, this is "WLAN_DEVNAMELEN_MAX") */ #define PRISM_DEVICE_NAME_LENGTH 16 /** * Monitor Frame (indicator that we have a 'struct PrismHeader'). */ #define PRISM_MSGCODE_MONITOR 0x0041 /** * Mac time element. In micro-seconds. * Drivers appear to use a 64bit counter to hold mactime internal * the then fill the prism header with the lower 32 bits */ #define PRISM_DID_MACTIME 0x2041 /** * Channel element */ #define PRISM_DID_CHANNEL 0x3041 /** * Signal element. Should be the signal strength in dbm, some people * suggest that instead "100 - (strength in dbm)" is used (to make this * a positive integer). */ #define PRISM_DID_SIGNAL 0x6041 /** * Noise element */ #define PRISM_DID_NOISE 0x7041 /** * Rate element, in units/multiples of 500Khz */ #define PRISM_DID_RATE 0x8041 /** * Value is set (supplied) */ #define PRISM_STATUS_OK 0 /** * Value not supplied. */ #define PRISM_STATUS_NO_VALUE 1 /** * Values in the 'struct PrismHeader'. All in host byte order (!). */ struct PrismValue { /** * This has a different ID for each parameter, see * PRISM_DID_* constants. */ uint32_t did; /** * See PRISM_STATUS_*-constants. Note that they are unusual: 0 = set; 1 = not set */ uint16_t status; /** * length of data (which is always a uint32_t, but presumably this can be used * to specify that fewer bytes are used (with values in 'len' from 0-4). We * ignore this field. */ uint16_t len; /** * The data value */ uint32_t data; } __attribute__ ((packed)); /** * Prism header format ('struct p80211msg' in Linux). All in host byte order (!). */ struct PrismHeader { /** * We expect this to be a PRISM_MSGCODE_*. */ uint32_t msgcode; /** * The length of the entire header. */ uint32_t msglen; /** * Name of the device that captured the packet. */ char devname[PRISM_DEVICE_NAME_LENGTH]; /* followed by 'struct PrismValue's. Documentation suggests that these are typically the hosttime, mactime, channel, rssi, sq, signal, noise, rate, istx and frmlen values, but documentation is sparse. So we will use the 'did' fields to find out what we actually got. */ } __attribute__ ((packed)); /* ****** end of structure of messages of type ARPHRD_IEEE80211_PRISM ******* */ /* ********** structure of messages of type ARPHRD_IEEE80211_FULL *********** */ /** * Bits in the 'it_present' bitmask from the 'struct * Ieee80211RadiotapHeader'. For each value, we give the name, data * type, unit and then a description below. Note that the actual size * of the extension can be bigger as arguments must be padded so that * args of a given length must begin at a boundary of that length. * However, note that compound args are allowed (eg, 2 x uint16_t for * IEEE80211_RADIOTAP_CHANNEL) so total argument length is not a * reliable indicator of alignment requirement. See also * 'man 9 ieee80211_radiotap'. */ enum RadiotapType { /** * IEEE80211_RADIOTAP_TSFT __le64 microseconds * * Value in microseconds of the MAC's 64-bit 802.11 Time * Synchronization Function timer when the first bit of the * MPDU arrived at the MAC. For received frames, only. */ IEEE80211_RADIOTAP_TSFT = 0, /** * IEEE80211_RADIOTAP_FLAGS uint8_t bitmap * * Properties of transmitted and received frames. See flags * defined below. */ IEEE80211_RADIOTAP_FLAGS = 1, /** * IEEE80211_RADIOTAP_RATE uint8_t 500kb/s * * Tx/Rx data rate */ IEEE80211_RADIOTAP_RATE = 2, /** * IEEE80211_RADIOTAP_CHANNEL 2 x __le16 MHz, bitmap * * Tx/Rx frequency in MHz, followed by flags (see below). */ IEEE80211_RADIOTAP_CHANNEL = 3, /** * IEEE80211_RADIOTAP_FHSS __le16 see below * * For frequency-hopping radios, the hop set (first byte) * and pattern (second byte). */ IEEE80211_RADIOTAP_FHSS = 4, /** * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from * one milliwatt (dBm) * * RF signal power at the antenna, decibel difference from * one milliwatt. */ IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, /** * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from * one milliwatt (dBm) * * RF noise power at the antenna, decibel difference from one * milliwatt. */ IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, /** * IEEE80211_RADIOTAP_LOCK_QUALITY __le16 unitless * * Quality of Barker code lock. Unitless. Monotonically * nondecreasing with "better" lock strength. Called "Signal * Quality" in datasheets. (Is there a standard way to measure * this?) */ IEEE80211_RADIOTAP_LOCK_QUALITY = 7, /** * IEEE80211_RADIOTAP_TX_ATTENUATION __le16 unitless * * Transmit power expressed as unitless distance from max * power set at factory calibration. 0 is max power. * Monotonically nondecreasing with lower power levels. */ IEEE80211_RADIOTAP_TX_ATTENUATION = 8, /** * IEEE80211_RADIOTAP_DB_TX_ATTENUATION __le16 decibels (dB) * * Transmit power expressed as decibel distance from max power * set at factory calibration. 0 is max power. Monotonically * nondecreasing with lower power levels. */ IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, /** * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from * one milliwatt (dBm) * * Transmit power expressed as dBm (decibels from a 1 milliwatt * reference). This is the absolute power level measured at * the antenna port. */ IEEE80211_RADIOTAP_DBM_TX_POWER = 10, /** * IEEE80211_RADIOTAP_ANTENNA uint8_t antenna index * * Unitless indication of the Rx/Tx antenna for this packet. * The first antenna is antenna 0. */ IEEE80211_RADIOTAP_ANTENNA = 11, /** * IEEE80211_RADIOTAP_DB_ANTSIGNAL uint8_t decibel (dB) * * RF signal power at the antenna, decibel difference from an * arbitrary, fixed reference. */ IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, /** * IEEE80211_RADIOTAP_DB_ANTNOISE uint8_t decibel (dB) * * RF noise power at the antenna, decibel difference from an * arbitrary, fixed reference point. */ IEEE80211_RADIOTAP_DB_ANTNOISE = 13, /** * IEEE80211_RADIOTAP_RX_FLAGS __le16 bitmap * * Properties of received frames. See flags defined below. */ IEEE80211_RADIOTAP_RX_FLAGS = 14, /** * IEEE80211_RADIOTAP_TX_FLAGS __le16 bitmap * * Properties of transmitted frames. See flags defined below. */ IEEE80211_RADIOTAP_TX_FLAGS = 15, /** * IEEE80211_RADIOTAP_RTS_RETRIES uint8_t data * * Number of rts retries a transmitted frame used. */ IEEE80211_RADIOTAP_RTS_RETRIES = 16, /** * IEEE80211_RADIOTAP_DATA_RETRIES uint8_t data * * Number of unicast retries a transmitted frame used. */ IEEE80211_RADIOTAP_DATA_RETRIES = 17, /** * Extension bit, used to indicate that more bits are needed for * the bitmask. */ IEEE80211_RADIOTAP_EXT = 31 }; /** * Bitmask indicating an extension of the bitmask is used. * (Mask corresponding to IEEE80211_RADIOTAP_EXT). */ #define IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK (1 << IEEE80211_RADIOTAP_EXT) /** * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get * as part of a 'struct Ieee80211RadiotapHeader' extension * if the IEEE80211_RADIOTAP_FLAGS bit is set in * 'it_present'). The radiotap flags are an 8-bit field. * * Frame was sent/received during CFP (Contention Free Period) */ #define IEEE80211_RADIOTAP_F_CFP 0x01 /** * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get * as part of a 'struct Ieee80211RadiotapHeader' extension * if the IEEE80211_RADIOTAP_FLAGS bit is set in * 'it_present'). The radiotap flags are an 8-bit field. * * Frame was sent/received with short preamble */ #define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /** * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get * as part of a 'struct Ieee80211RadiotapHeader' extension * if the IEEE80211_RADIOTAP_FLAGS bit is set in * 'it_present'). The radiotap flags are an 8-bit field. * * Frame was sent/received with WEP encryption */ #define IEEE80211_RADIOTAP_F_WEP 0x04 /** * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get * as part of a 'struct Ieee80211RadiotapHeader' extension * if the IEEE80211_RADIOTAP_FLAGS bit is set in * 'it_present'). The radiotap flags are an 8-bit field. * * Frame was sent/received with fragmentation */ #define IEEE80211_RADIOTAP_F_FRAG 0x08 /** * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get * as part of a 'struct Ieee80211RadiotapHeader' extension * if the IEEE80211_RADIOTAP_FLAGS bit is set in * 'it_present'). The radiotap flags are an 8-bit field. * * Frame includes FCS (CRC at the end that needs to be removeD). */ #define IEEE80211_RADIOTAP_F_FCS 0x10 /** * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get * as part of a 'struct Ieee80211RadiotapHeader' extension * if the IEEE80211_RADIOTAP_FLAGS bit is set in * 'it_present'). The radiotap flags are an 8-bit field. * * Frame has padding between 802.11 header and payload * (to 32-bit boundary) */ #define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /** * For IEEE80211_RADIOTAP_RX_FLAGS: * frame failed crc check */ #define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /** * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'): * failed due to excessive retries */ #define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /** * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'): * used cts 'protection' */ #define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /** * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'): * used rts/cts handshake */ #define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /** * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'): * frame should not be ACKed */ #define IEEE80211_RADIOTAP_F_TX_NOACK 0x0008 /** * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'): * sequence number handled by userspace */ #define IEEE80211_RADIOTAP_F_TX_NOSEQ 0x0010 /** * Generic header for radiotap messages (receiving and sending). A * bit mask (it_present) determines which specific records follow. * * I am trying to describe precisely what the application programmer * should expect in the following, and for that reason I tell the * units and origin of each measurement (where it applies), or else I * use sufficiently weaselly language ("is a monotonically nondecreasing * function of...") that I cannot set false expectations for lawyerly * readers. * * The radio capture header precedes the 802.11 header. * All data in the header is little endian on all platforms. */ struct Ieee80211RadiotapHeader { /** * Version 0. Only increases for drastic changes, introduction of * compatible new fields does not count. */ uint8_t it_version; /** * Padding. Set to 0. */ uint8_t it_pad; /** * length of the whole header in bytes, including it_version, * it_pad, it_len, and data fields. */ uint16_t it_len; /** * A bitmap telling which fields are present. Set bit 31 * (0x80000000) to extend the bitmap by another 32 bits. Additional * extensions are made by setting bit 31. */ uint32_t it_present; }; /** * Format of the header we need to prepend to messages to be sent to the * Kernel. */ struct RadiotapTransmissionHeader { /** * First we begin with the 'generic' header we also get when receiving * messages. */ struct Ieee80211RadiotapHeader header; /** * Transmission rate (we use 0, kernel makes up its mind anyway). */ uint8_t rate; /** * Padding (we use 0). There is a requirement to pad args, so that * args of a given length must begin at a boundary of that length. * As our next argument is the 'it_len' with 2 bytes, we need 1 byte * of padding. */ uint8_t pad1; /** * Transmission flags from on the IEEE80211_RADIOTAP_F_TX_* constant family. */ uint16_t txflags; }; /** * The above 'struct RadiotapTransmissionHeader' should have the * following value for 'header.it_present' based on the presence of * the 'rate' and 'txflags' in the overall struct. */ #define IEEE80211_RADIOTAP_OUR_TRANSMISSION_HEADER_MASK ((1 << IEEE80211_RADIOTAP_RATE) | (1 << IEEE80211_RADIOTAP_TX_FLAGS)) /** * struct Ieee80211RadiotapHeaderIterator - tracks walk through present radiotap arguments * in the radiotap header. Used when we parse radiotap packets received from the kernel. */ struct Ieee80211RadiotapHeaderIterator { /** * pointer to the radiotap header we are walking through */ const struct Ieee80211RadiotapHeader *rtheader; /** * pointer to current radiotap arg */ const uint8_t *this_arg; /** * internal next argument pointer */ const uint8_t *arg; /** * internal pointer to next present uint32_t (if IEEE80211_RADIOTAP_EXT is used). */ const uint32_t *next_bitmap; /** * length of radiotap header in host byte ordering */ size_t max_length; /** * internal shifter for current uint32_t bitmap, (it_present in host byte order), * If bit 0 is set, the 'arg_index' argument is present. */ uint32_t bitmap_shifter; /** * IEEE80211_RADIOTAP_... index of current arg */ unsigned int this_arg_index; /** * internal next argument index */ unsigned int arg_index; }; /* ************** end of structure of ARPHRD_IEEE80211_FULL ************** */ /* ************************** our globals ******************************* */ /** * struct for storing the information of the hardware. There is only * one of these. */ struct HardwareInfos { /** * file descriptor for the raw socket */ int fd_raw; /** * Which format has the header that we're getting when receiving packets? * Some ARPHRD_IEEE80211_XXX-value. */ int arptype_in; /** * Name of the interface, not necessarily 0-terminated (!). */ char iface[IFNAMSIZ]; /** * MAC address of our own WLAN interface. */ struct GNUNET_TRANSPORT_WLAN_MacAddress pl_mac; }; /** * IO buffer used for buffering data in transit (to wireless or to stdout). */ struct SendBuffer { /** * How many bytes of data are stored in 'buf' for transmission right now? * Data always starts at offset 0 and extends to 'size'. */ size_t size; /** * How many bytes that were stored in 'buf' did we already write to the * destination? Always smaller than 'size'. */ size_t pos; /** * Buffered data; twice the maximum allowed message size as we add some * headers. */ char buf[MAXLINE * 2]; }; /** * Buffer for data read from stdin to be transmitted to the wirless card. */ static struct SendBuffer write_pout; /** * Buffer for data read from the wireless card to be transmitted to stdout. */ static struct SendBuffer write_std; /* *********** specialized version of server_mst.c begins here ********** */ /** * To what multiple do we align messages? 8 byte should suffice for everyone * for now. */ #define ALIGN_FACTOR 8 /** * Smallest supported message. */ #define MIN_BUFFER_SIZE sizeof (struct GNUNET_MessageHeader) /** * Functions with this signature are called whenever a * complete message is received by the tokenizer. * * @param cls closure * @param message the actual message */ typedef void (*MessageTokenizerCallback) (void *cls, const struct GNUNET_MessageHeader * message); /** * Handle to a message stream tokenizer. */ struct MessageStreamTokenizer { /** * Function to call on completed messages. */ MessageTokenizerCallback cb; /** * Closure for cb. */ void *cb_cls; /** * Size of the buffer (starting at 'hdr'). */ size_t curr_buf; /** * How many bytes in buffer have we already processed? */ size_t off; /** * How many bytes in buffer are valid right now? */ size_t pos; /** * Beginning of the buffer. Typed like this to force alignment. */ struct GNUNET_MessageHeader *hdr; }; /** * Create a message stream tokenizer. * * @param cb function to call on completed messages * @param cb_cls closure for cb * @return handle to tokenizer */ static struct MessageStreamTokenizer * mst_create (MessageTokenizerCallback cb, void *cb_cls) { struct MessageStreamTokenizer *ret; ret = malloc (sizeof (struct MessageStreamTokenizer)); if (NULL == ret) { fprintf (stderr, "Failed to allocate buffer for tokenizer\n"); exit (1); } ret->hdr = malloc (MIN_BUFFER_SIZE); if (NULL == ret->hdr) { fprintf (stderr, "Failed to allocate buffer for alignment\n"); exit (1); } ret->curr_buf = MIN_BUFFER_SIZE; ret->cb = cb; ret->cb_cls = cb_cls; return ret; } /** * Add incoming data to the receive buffer and call the * callback for all complete messages. * * @param mst tokenizer to use * @param buf input data to add * @param size number of bytes in buf * @return GNUNET_OK if we are done processing (need more data) * GNUNET_SYSERR if the data stream is corrupt */ static int mst_receive (struct MessageStreamTokenizer *mst, const char *buf, size_t size) { const struct GNUNET_MessageHeader *hdr; size_t delta; uint16_t want; char *ibuf; int need_align; unsigned long offset; int ret; ret = GNUNET_OK; ibuf = (char *) mst->hdr; while (mst->pos > 0) { do_align: if ((mst->curr_buf - mst->off < sizeof (struct GNUNET_MessageHeader)) || (0 != (mst->off % ALIGN_FACTOR))) { /* need to align or need more space */ mst->pos -= mst->off; memmove (ibuf, &ibuf[mst->off], mst->pos); mst->off = 0; } if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader)) { delta = GNUNET_MIN (sizeof (struct GNUNET_MessageHeader) - (mst->pos - mst->off), size); memcpy (&ibuf[mst->pos], buf, delta); mst->pos += delta; buf += delta; size -= delta; } if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader)) { return GNUNET_OK; } hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off]; want = ntohs (hdr->size); if (want < sizeof (struct GNUNET_MessageHeader)) { fprintf (stderr, "Received invalid message from stdin\n"); exit (1); } if (mst->curr_buf - mst->off < want) { /* need more space */ mst->pos -= mst->off; memmove (ibuf, &ibuf[mst->off], mst->pos); mst->off = 0; } if (want > mst->curr_buf) { mst->hdr = realloc (mst->hdr, want); if (NULL == mst->hdr) { fprintf (stderr, "Failed to allocate buffer for alignment\n"); exit (1); } ibuf = (char *) mst->hdr; mst->curr_buf = want; } hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off]; if (mst->pos - mst->off < want) { delta = GNUNET_MIN (want - (mst->pos - mst->off), size); memcpy (&ibuf[mst->pos], buf, delta); mst->pos += delta; buf += delta; size -= delta; } if (mst->pos - mst->off < want) { return GNUNET_OK; } mst->cb (mst->cb_cls, hdr); mst->off += want; if (mst->off == mst->pos) { /* reset to beginning of buffer, it's free right now! */ mst->off = 0; mst->pos = 0; } } while (size > 0) { if (size < sizeof (struct GNUNET_MessageHeader)) break; offset = (unsigned long) buf; need_align = (0 != offset % ALIGN_FACTOR) ? GNUNET_YES : GNUNET_NO; if (GNUNET_NO == need_align) { /* can try to do zero-copy and process directly from original buffer */ hdr = (const struct GNUNET_MessageHeader *) buf; want = ntohs (hdr->size); if (want < sizeof (struct GNUNET_MessageHeader)) { fprintf (stderr, "Received invalid message from stdin\n"); exit (1); } if (size < want) break; /* or not, buffer incomplete, so copy to private buffer... */ mst->cb (mst->cb_cls, hdr); buf += want; size -= want; } else { /* need to copy to private buffer to align; * yes, we go a bit more spagetti than usual here */ goto do_align; } } if (size > 0) { if (size + mst->pos > mst->curr_buf) { mst->hdr = realloc (mst->hdr, size + mst->pos); if (NULL == mst->hdr) { fprintf (stderr, "Failed to allocate buffer for alignment\n"); exit (1); } ibuf = (char *) mst->hdr; mst->curr_buf = size + mst->pos; } if (mst->pos + size > mst->curr_buf) { fprintf (stderr, "Assertion failed\n"); exit (1); } memcpy (&ibuf[mst->pos], buf, size); mst->pos += size; } return ret; } /** * Destroys a tokenizer. * * @param mst tokenizer to destroy */ static void mst_destroy (struct MessageStreamTokenizer *mst) { free (mst->hdr); free (mst); } /* ***************** end of server_mst.c clone ***************** **/ /* ************** code for handling of ARPHRD_IEEE80211_FULL ************** */ /** * Radiotap header iteration * * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator * struct Ieee80211RadiotapHeaderIterator (no need to init the struct beforehand) * then loop calling __ieee80211_radiotap_iterator_next()... it returns -1 * if there are no more args in the header, or the next argument type index * that is present. The iterator's this_arg member points to the start of the * argument associated with the current argument index that is present, * which can be found in the iterator's this_arg_index member. This arg * index corresponds to the IEEE80211_RADIOTAP_... defines. * * @param iterator iterator to initialize * @param radiotap_header message to parse * @param max_length number of valid bytes in radiotap_header * @return 0 on success, -1 on error */ static int ieee80211_radiotap_iterator_init (struct Ieee80211RadiotapHeaderIterator *iterator, const struct Ieee80211RadiotapHeader *radiotap_header, size_t max_length) { if ( (iterator == NULL) || (radiotap_header == NULL) ) return -1; /* Linux only supports version 0 radiotap format */ if (0 != radiotap_header->it_version) return -1; /* sanity check for allowed length and radiotap length field */ if ( (max_length < sizeof (struct Ieee80211RadiotapHeader)) || (max_length < (GNUNET_le16toh (radiotap_header->it_len))) ) return -1; memset (iterator, 0, sizeof (struct Ieee80211RadiotapHeaderIterator)); iterator->rtheader = radiotap_header; iterator->max_length = GNUNET_le16toh (radiotap_header->it_len); iterator->bitmap_shifter = GNUNET_le32toh (radiotap_header->it_present); iterator->arg = ((uint8_t *) radiotap_header) + sizeof (struct Ieee80211RadiotapHeader); /* find payload start allowing for extended bitmap(s) */ if (0 != (iterator->bitmap_shifter & IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK)) { while (GNUNET_le32toh (*((uint32_t *) iterator->arg)) & IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK) { iterator->arg += sizeof (uint32_t); /* * check for insanity where the present bitmaps * keep claiming to extend up to or even beyond the * stated radiotap header length */ if (iterator->arg - ((uint8_t*) iterator->rtheader) > iterator->max_length) return -1; } iterator->arg += sizeof (uint32_t); /* * no need to check again for blowing past stated radiotap * header length, becuase ieee80211_radiotap_iterator_next * checks it before it is dereferenced */ } /* we are all initialized happily */ return 0; } /** * Returns the next radiotap parser iterator arg. * * This function returns the next radiotap arg index (IEEE80211_RADIOTAP_...) * and sets iterator->this_arg to point to the payload for the arg. It takes * care of alignment handling and extended present fields. interator->this_arg * can be changed by the caller. The args pointed to are in little-endian * format. * * @param iterator: radiotap_iterator to move to next arg (if any) * @return next present arg index on success or -1 if no more or error */ static int ieee80211_radiotap_iterator_next (struct Ieee80211RadiotapHeaderIterator *iterator) { /* * small length lookup table for all radiotap types we heard of * starting from b0 in the bitmap, so we can walk the payload * area of the radiotap header * * There is a requirement to pad args, so that args * of a given length must begin at a boundary of that length * -- but note that compound args are allowed (eg, 2 x uint16_t * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not * a reliable indicator of alignment requirement. * * upper nybble: content alignment for arg * lower nybble: content length for arg */ static const uint8_t rt_sizes[] = { [IEEE80211_RADIOTAP_TSFT] = 0x88, [IEEE80211_RADIOTAP_FLAGS] = 0x11, [IEEE80211_RADIOTAP_RATE] = 0x11, [IEEE80211_RADIOTAP_CHANNEL] = 0x24, [IEEE80211_RADIOTAP_FHSS] = 0x22, [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11, [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11, [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22, [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22, [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22, [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11, [IEEE80211_RADIOTAP_ANTENNA] = 0x11, [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11, [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11, [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22, [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22, [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11, [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11 /* * add more here as they are defined in * include/net/ieee80211_radiotap.h */ }; /* * for every radiotap entry we can at * least skip (by knowing the length)... */ while (iterator->arg_index < sizeof (rt_sizes)) { int hit = (0 != (iterator->bitmap_shifter & 1)); if (hit) { unsigned int wanted_alignment; unsigned int unalignment; /* * arg is present, account for alignment padding * 8-bit args can be at any alignment * 16-bit args must start on 16-bit boundary * 32-bit args must start on 32-bit boundary * 64-bit args must start on 64-bit boundary * * note that total arg size can differ from alignment of * elements inside arg, so we use upper nybble of length table * to base alignment on. First, 'wanted_alignment' is set to be * 1 for 8-bit, 2 for 16-bit, 4 for 32-bit and 8 for 64-bit * arguments. Then, we calculate the 'unalignment' (how many * bytes we are over by taking the difference of 'arg' and the * overall starting point modulo the desired alignment. As * desired alignments are powers of two, we can do modulo with * binary "&" (and also avoid the possibility of a division by * zero if the 'rt_sizes' table contains bogus entries). * * also note: these alignments are relative to the start of the * radiotap header. There is no guarantee that the radiotap * header itself is aligned on any kind of boundary, thus we * need to really look at the delta here. */ wanted_alignment = rt_sizes[iterator->arg_index] >> 4; unalignment = (((void *) iterator->arg) - ((void *) iterator->rtheader)) & (wanted_alignment - 1); if (0 != unalignment) { /* need padding (by 'wanted_alignment - unalignment') */ iterator->arg_index += wanted_alignment - unalignment; } /* * this is what we will return to user, but we need to * move on first so next call has something fresh to test */ iterator->this_arg_index = iterator->arg_index; iterator->this_arg = iterator->arg; /* internally move on the size of this arg (using lower nybble from the table) */ iterator->arg += rt_sizes[iterator->arg_index] & 0x0f; /* * check for insanity where we are given a bitmap that * claims to have more arg content than the length of the * radiotap section. We will normally end up equalling this * max_length on the last arg, never exceeding it. */ if ((((void *) iterator->arg) - ((void *) iterator->rtheader)) > iterator->max_length) return -1; } /* Now, move on to next bit / next entry */ iterator->arg_index++; if (0 == (iterator->arg_index % 32)) { /* completed current uint32_t bitmap */ if (0 != (iterator->bitmap_shifter & 1)) { /* bit 31 was set, there is more; move to next uint32_t bitmap */ iterator->bitmap_shifter = GNUNET_le32toh (*iterator->next_bitmap); iterator->next_bitmap++; } else { /* no more bitmaps: end (by setting arg_index to high, unsupported value) */ iterator->arg_index = sizeof (rt_sizes); } } else { /* just try the next bit (while loop will move on) */ iterator->bitmap_shifter >>= 1; } /* if we found a valid arg earlier, return it now */ if (hit) return iterator->this_arg_index; } /* we don't know how to handle any more args (or there are no more), so we're done (this is not an error) */ return -1; } /** * Calculate crc32, the start of the calculation * * @param buf buffer to calc the crc * @param len len of the buffer * @return crc sum */ static unsigned long calc_crc_osdep (const unsigned char *buf, size_t len) { static const unsigned long int crc_tbl_osdep[256] = { 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D }; unsigned long crc = 0xFFFFFFFF; for (; len > 0; len--, buf++) crc = crc_tbl_osdep[(crc ^ *buf) & 0xFF] ^ (crc >> 8); return (~crc); } /** * Calculate and check crc of the wlan packet * * @param buf buffer of the packet, with len + 4 bytes of data, * the last 4 bytes being the checksum * @param len length of the payload in data * @return 0 on success (checksum matches), 1 on error */ static int check_crc_buf_osdep (const unsigned char *buf, size_t len) { unsigned long crc; crc = calc_crc_osdep (buf, len); buf += len; if (((crc) & 0xFF) == buf[0] && ((crc >> 8) & 0xFF) == buf[1] && ((crc >> 16) & 0xFF) == buf[2] && ((crc >> 24) & 0xFF) == buf[3]) return 0; return 1; } /* ************end of code for handling of ARPHRD_IEEE80211_FULL ************** */ /* ************beginning of code for reading packets from kernel ************** */ /** * Return the channel from the frequency (in Mhz) * * @param frequency of the channel * @return number of the channel */ static int get_channel_from_frequency (int32_t frequency) { if (frequency >= 2412 && frequency <= 2472) return (frequency - 2407) / 5; if (frequency == 2484) return 14; if (frequency >= 5000 && frequency <= 6100) return (frequency - 5000) / 5; return -1; } /** * Get the channel used by our WLAN interface. * * @param dev pointer to the dev struct of the card * @return channel number, -1 on error */ static int linux_get_channel (const struct HardwareInfos *dev) { struct iwreq wrq; int32_t frequency; memset (&wrq, 0, sizeof (struct iwreq)); strncpy (wrq.ifr_name, dev->iface, IFNAMSIZ); if (0 > ioctl (dev->fd_raw, SIOCGIWFREQ, &wrq)) return -1; frequency = wrq.u.freq.m; /* 'iw_freq' defines 'm' as '__s32', so we keep it signed */ if (100000000 < frequency) frequency /= 100000; else if (1000000 < frequency) frequency /= 1000; if (1000 < frequency) return get_channel_from_frequency (frequency); return frequency; } /** * Read from the raw socket (the wlan card), parse the packet and * put the result into the buffer for transmission to 'stdout'. * * @param dev pointer to the struct of the wlan card * @param buf buffer to read to; first bytes will be the 'struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame', * followed by the actual payload * @param buf_size size of the buffer * @param ri where to write radiotap_rx info * @return number of bytes written to 'buf' */ static ssize_t linux_read (struct HardwareInfos *dev, unsigned char *buf, size_t buf_size, struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *ri) { unsigned char tmpbuf[buf_size]; ssize_t caplen; size_t n; int got_signal = 0; int got_noise = 0; int got_channel = 0; int fcs_removed = 0; caplen = read (dev->fd_raw, tmpbuf, buf_size); if (0 > caplen) { if (EAGAIN == errno) return 0; fprintf (stderr, "Failed to read from RAW socket: %s\n", strerror (errno)); return -1; } memset (ri, 0, sizeof (*ri)); switch (dev->arptype_in) { case ARPHRD_IEEE80211_PRISM: { const struct PrismHeader *ph; ph = (const struct PrismHeader*) tmpbuf; n = ph->msglen; if ( (n < 8) || (n >= caplen) ) return 0; /* invalid format */ if ( (PRISM_MSGCODE_MONITOR == ph->msgcode) && (n >= sizeof (struct PrismHeader)) ) { const char *pos; size_t left; struct PrismValue pv; left = n - sizeof (struct PrismHeader); pos = (const char *) &ph[1]; while (left > sizeof (struct PrismValue)) { left -= sizeof (struct PrismValue); memcpy (&pv, pos, sizeof (struct PrismValue)); pos += sizeof (struct PrismValue); switch (pv.did) { case PRISM_DID_NOISE: if (PRISM_STATUS_OK == pv.status) { ri->ri_noise = pv.data; got_noise = 1; } break; case PRISM_DID_RATE: if (PRISM_STATUS_OK == pv.status) ri->ri_rate = pv.data * 500000; break; case PRISM_DID_CHANNEL: if (PRISM_STATUS_OK == pv.status) { ri->ri_channel = pv.data; got_channel = 1; } break; case PRISM_DID_MACTIME: if (PRISM_STATUS_OK == pv.status) ri->ri_mactime = pv.data; break; case PRISM_DID_SIGNAL: if (PRISM_STATUS_OK == pv.status) { ri->ri_power = pv.data; got_signal = 1; } break; } } } if ( (n < 8) || (n >= caplen) ) return 0; /* invalid format */ } break; case ARPHRD_IEEE80211_FULL: { struct Ieee80211RadiotapHeaderIterator iterator; struct Ieee80211RadiotapHeader *rthdr; memset (&iterator, 0, sizeof (iterator)); rthdr = (struct Ieee80211RadiotapHeader *) tmpbuf; n = GNUNET_le16toh (rthdr->it_len); if ( (n < sizeof (struct Ieee80211RadiotapHeader)) || (n >= caplen)) return 0; /* invalid 'it_len' */ if (0 != ieee80211_radiotap_iterator_init (&iterator, rthdr, caplen)) return 0; /* go through the radiotap arguments we have been given by the driver */ while (0 <= ieee80211_radiotap_iterator_next (&iterator)) { switch (iterator.this_arg_index) { case IEEE80211_RADIOTAP_TSFT: ri->ri_mactime = GNUNET_le64toh (*((uint64_t *) iterator.this_arg)); break; case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: if (!got_signal) { ri->ri_power = * ((int8_t*) iterator.this_arg); got_signal = 1; } break; case IEEE80211_RADIOTAP_DB_ANTSIGNAL: if (!got_signal) { ri->ri_power = * ((int8_t*) iterator.this_arg); got_signal = 1; } break; case IEEE80211_RADIOTAP_DBM_ANTNOISE: if (!got_noise) { ri->ri_noise = * ((int8_t*) iterator.this_arg); got_noise = 1; } break; case IEEE80211_RADIOTAP_DB_ANTNOISE: if (!got_noise) { ri->ri_noise = * ((int8_t*) iterator.this_arg); got_noise = 1; } break; case IEEE80211_RADIOTAP_ANTENNA: ri->ri_antenna = *iterator.this_arg; break; case IEEE80211_RADIOTAP_CHANNEL: ri->ri_channel = *iterator.this_arg; got_channel = 1; break; case IEEE80211_RADIOTAP_RATE: ri->ri_rate = (*iterator.this_arg) * 500000; break; case IEEE80211_RADIOTAP_FLAGS: { uint8_t flags = *iterator.this_arg; /* is the CRC visible at the end? if so, remove */ if (0 != (flags & IEEE80211_RADIOTAP_F_FCS)) { fcs_removed = 1; caplen -= sizeof (uint32_t); } break; } case IEEE80211_RADIOTAP_RX_FLAGS: { uint16_t flags = ntohs (* ((uint16_t *) iterator.this_arg)); if (0 != (flags & IEEE80211_RADIOTAP_F_RX_BADFCS)) return 0; } break; } /* end of 'switch' */ } /* end of the 'while' loop */ } break; case ARPHRD_IEEE80211: n = 0; /* no header */ break; default: errno = ENOTSUP; /* unsupported format */ return -1; } caplen -= n; if (! got_channel) ri->ri_channel = linux_get_channel (dev); /* detect CRC32 at the end, even if the flag wasn't set and remove it */ if ( (0 == fcs_removed) && (0 == check_crc_buf_osdep (tmpbuf + n, caplen - sizeof (uint32_t))) ) { /* NOTE: this heuristic can of course fail if there happens to be a matching checksum at the end. Would be good to have some data to see how often this heuristic actually works. */ caplen -= sizeof (uint32_t); } /* copy payload to target buffer */ memcpy (buf, tmpbuf + n, caplen); return caplen; } /* ************end of code for reading packets from kernel ************** */ /* ************other helper functions for main start here ************** */ /** * Open the wireless network interface for reading/writing. * * @param dev pointer to the device struct * @return 0 on success */ static int open_device_raw (struct HardwareInfos *dev) { struct ifreq ifr; struct iwreq wrq; struct packet_mreq mr; struct sockaddr_ll sll; /* find the interface index */ memset (&ifr, 0, sizeof (ifr)); strncpy (ifr.ifr_name, dev->iface, IFNAMSIZ); if (-1 == ioctl (dev->fd_raw, SIOCGIFINDEX, &ifr)) { fprintf (stderr, "ioctl(SIOCGIFINDEX) on interface `%.*s' failed: %s\n", IFNAMSIZ, dev->iface, strerror (errno)); return 1; } /* lookup the hardware type */ memset (&sll, 0, sizeof (sll)); sll.sll_family = AF_PACKET; sll.sll_ifindex = ifr.ifr_ifindex; sll.sll_protocol = htons (ETH_P_ALL); if (-1 == ioctl (dev->fd_raw, SIOCGIFHWADDR, &ifr)) { fprintf (stderr, "ioctl(SIOCGIFHWADDR) on interface `%.*s' failed: %s\n", IFNAMSIZ, dev->iface, strerror (errno)); return 1; } /* lookup iw mode */ memset (&wrq, 0, sizeof (struct iwreq)); strncpy (wrq.ifr_name, dev->iface, IFNAMSIZ); if (-1 == ioctl (dev->fd_raw, SIOCGIWMODE, &wrq)) { /* most probably not supported (ie for rtap ipw interface) * * so just assume its correctly set... */ wrq.u.mode = IW_MODE_MONITOR; } if (((ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211) && (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_PRISM) && (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_FULL)) || (wrq.u.mode != IW_MODE_MONITOR)) { fprintf (stderr, "Error: interface `%.*s' is not in monitor mode\n", IFNAMSIZ, dev->iface); return 1; } /* Is interface st to up, broadcast & running ? */ if ((ifr.ifr_flags | IFF_UP | IFF_BROADCAST | IFF_RUNNING) != ifr.ifr_flags) { /* Bring interface up */ ifr.ifr_flags |= IFF_UP | IFF_BROADCAST | IFF_RUNNING; if (-1 == ioctl (dev->fd_raw, SIOCSIFFLAGS, &ifr)) { fprintf (stderr, "ioctl(SIOCSIFFLAGS) on interface `%.*s' failed: %s\n", IFNAMSIZ, dev->iface, strerror (errno)); return 1; } } /* bind the raw socket to the interface */ if (-1 == bind (dev->fd_raw, (struct sockaddr *) &sll, sizeof (sll))) { fprintf (stderr, "Failed to bind interface `%.*s': %s\n", IFNAMSIZ, dev->iface, strerror (errno)); return 1; } /* lookup the hardware type */ if (-1 == ioctl (dev->fd_raw, SIOCGIFHWADDR, &ifr)) { fprintf (stderr, "ioctl(SIOCGIFHWADDR) on interface `%.*s' failed: %s\n", IFNAMSIZ, dev->iface, strerror (errno)); return 1; } memcpy (&dev->pl_mac, ifr.ifr_hwaddr.sa_data, MAC_ADDR_SIZE); dev->arptype_in = ifr.ifr_hwaddr.sa_family; if ((ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211) && (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_PRISM) && (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_FULL)) { fprintf (stderr, "Unsupported hardware link type %d on interface `%.*s'\n", ifr.ifr_hwaddr.sa_family, IFNAMSIZ, dev->iface); return 1; } /* enable promiscuous mode */ memset (&mr, 0, sizeof (mr)); mr.mr_ifindex = sll.sll_ifindex; mr.mr_type = PACKET_MR_PROMISC; if (0 != setsockopt (dev->fd_raw, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof (mr))) { fprintf (stderr, "Failed to enable promiscuous mode on interface `%.*s'\n", IFNAMSIZ, dev->iface); return 1; } return 0; } /** * Test if the given interface name really corresponds to a wireless * device. * * @param iface name of the interface * @return 0 on success, 1 on error */ static int test_wlan_interface (const char *iface) { char strbuf[512]; struct stat sbuf; int ret; ret = snprintf (strbuf, sizeof (strbuf), "/sys/class/net/%s/phy80211/subsystem", iface); if ((ret < 0) || (ret >= sizeof (strbuf)) || (0 != stat (strbuf, &sbuf))) { fprintf (stderr, "Did not find 802.11 interface `%s'. Exiting.\n", iface); exit (1); } return 0; } /** * Test incoming packets mac for being our own. * * @param taIeeeHeader buffer of the packet * @param dev the Hardware_Infos struct * @return 0 if mac belongs to us, 1 if mac is for another target */ static int mac_test (const struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *taIeeeHeader, const struct HardwareInfos *dev) { if (0 != memcmp (&taIeeeHeader->addr3, &mac_bssid_gnunet, MAC_ADDR_SIZE)) return 1; /* not a GNUnet ad-hoc package */ if ( (0 == memcmp (&taIeeeHeader->addr1, &dev->pl_mac, MAC_ADDR_SIZE)) || (0 == memcmp (&taIeeeHeader->addr1, &bc_all_mac, MAC_ADDR_SIZE)) ) return 0; /* for us, or broadcast */ return 1; /* not for us */ } /** * Set the wlan header to sane values to make attacks more difficult * * @param taIeeeHeader pointer to the header of the packet * @param dev pointer to the Hardware_Infos struct */ static void mac_set (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *taIeeeHeader, const struct HardwareInfos *dev) { taIeeeHeader->frame_control = htons (IEEE80211_FC0_TYPE_DATA); taIeeeHeader->addr2 = dev->pl_mac; taIeeeHeader->addr3 = mac_bssid_gnunet; } /** * Process data from the stdin. Takes the message, prepends the * radiotap transmission header, forces the sender MAC to be correct * and puts it into our buffer for transmission to the kernel. * * @param cls pointer to the device struct ('struct HardwareInfos*') * @param hdr pointer to the start of the packet */ static void stdin_send_hw (void *cls, const struct GNUNET_MessageHeader *hdr) { struct HardwareInfos *dev = cls; const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *header; struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *wlanheader; size_t sendsize; struct RadiotapTransmissionHeader rtheader; sendsize = ntohs (hdr->size); if ( (sendsize < sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage)) || (GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER != ntohs (hdr->type)) ) { fprintf (stderr, "Received malformed message\n"); exit (1); } sendsize -= (sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) - sizeof (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame)); if (MAXLINE < sendsize) { fprintf (stderr, "Packet too big for buffer\n"); exit (1); } header = (const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) hdr; rtheader.header.it_version = 0; rtheader.header.it_pad = 0; rtheader.header.it_len = GNUNET_htole16 (sizeof (rtheader)); rtheader.header.it_present = GNUNET_htole16 (IEEE80211_RADIOTAP_OUR_TRANSMISSION_HEADER_MASK); rtheader.rate = header->rate; rtheader.pad1 = 0; rtheader.txflags = GNUNET_htole16 (IEEE80211_RADIOTAP_F_TX_NOACK | IEEE80211_RADIOTAP_F_TX_NOSEQ); memcpy (write_pout.buf, &rtheader, sizeof (rtheader)); memcpy (&write_pout.buf[sizeof (rtheader)], &header->frame, sendsize); wlanheader = (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *) &write_pout.buf[sizeof (rtheader)]; /* payload contains MAC address, but we don't trust it, so we'll * overwrite it with OUR MAC address to prevent mischief */ mac_set (wlanheader, dev); write_pout.size = sendsize + sizeof (rtheader); } /** * Main function of the helper. This code accesses a WLAN interface * in monitoring mode (layer 2) and then forwards traffic in both * directions between the WLAN interface and stdin/stdout of this * process. Error messages are written to stdout. * * @param argc number of arguments, must be 2 * @param argv arguments only argument is the name of the interface (i.e. 'mon0') * @return 0 on success (never happens, as we don't return unless aborted), 1 on error */ int main (int argc, char *argv[]) { struct HardwareInfos dev; char readbuf[MAXLINE]; int maxfd; fd_set rfds; fd_set wfds; int stdin_open; struct MessageStreamTokenizer *stdin_mst; int raw_eno; memset (&dev, 0, sizeof (dev)); dev.fd_raw = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL)); raw_eno = errno; /* remember for later */ /* drop privs */ { uid_t uid = getuid (); #ifdef HAVE_SETRESUID if (0 != setresuid (uid, uid, uid)) { fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno)); if (-1 != dev.fd_raw) (void) close (dev.fd_raw); return 1; } #else if (0 != (setuid (uid) | seteuid (uid))) { fprintf (stderr, "Failed to setuid: %s\n", strerror (errno)); if (-1 != dev.fd_raw) (void) close (dev.fd_raw); return 1; } } #endif /* now that we've dropped root rights, we can do error checking */ if (2 != argc) { fprintf (stderr, "You must specify the name of the interface as the first and only argument to this program.\n"); if (-1 != dev.fd_raw) (void) close (dev.fd_raw); return 1; } if (-1 == dev.fd_raw) { fprintf (stderr, "Failed to create raw socket: %s\n", strerror (raw_eno)); return 1; } if (dev.fd_raw >= FD_SETSIZE) { fprintf (stderr, "File descriptor too large for select (%d > %d)\n", dev.fd_raw, FD_SETSIZE); (void) close (dev.fd_raw); return 1; } if (0 != test_wlan_interface (argv[1])) { (void) close (dev.fd_raw); return 1; } strncpy (dev.iface, argv[1], IFNAMSIZ); if (0 != open_device_raw (&dev)) { (void) close (dev.fd_raw); return 1; } /* send MAC address of the WLAN interface to STDOUT first */ { struct GNUNET_TRANSPORT_WLAN_HelperControlMessage macmsg; macmsg.hdr.size = htons (sizeof (macmsg)); macmsg.hdr.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL); memcpy (&macmsg.mac, &dev.pl_mac, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); memcpy (write_std.buf, &macmsg, sizeof (macmsg)); write_std.size = sizeof (macmsg); } stdin_mst = mst_create (&stdin_send_hw, &dev); stdin_open = 1; while (1) { maxfd = -1; FD_ZERO (&rfds); if ((0 == write_pout.size) && (1 == stdin_open)) { FD_SET (STDIN_FILENO, &rfds); maxfd = MAX (maxfd, STDIN_FILENO); } if (0 == write_std.size) { FD_SET (dev.fd_raw, &rfds); maxfd = MAX (maxfd, dev.fd_raw); } FD_ZERO (&wfds); if (0 < write_std.size) { FD_SET (STDOUT_FILENO, &wfds); maxfd = MAX (maxfd, STDOUT_FILENO); } if (0 < write_pout.size) { FD_SET (dev.fd_raw, &wfds); maxfd = MAX (maxfd, dev.fd_raw); } { int retval = select (maxfd + 1, &rfds, &wfds, NULL, NULL); if ((-1 == retval) && (EINTR == errno)) continue; if (0 > retval) { fprintf (stderr, "select failed: %s\n", strerror (errno)); break; } } if (FD_ISSET (STDOUT_FILENO, &wfds)) { ssize_t ret = write (STDOUT_FILENO, write_std.buf + write_std.pos, write_std.size - write_std.pos); if (0 > ret) { fprintf (stderr, "Failed to write to STDOUT: %s\n", strerror (errno)); break; } write_std.pos += ret; if (write_std.pos == write_std.size) { write_std.pos = 0; write_std.size = 0; } } if (FD_ISSET (dev.fd_raw, &wfds)) { ssize_t ret = write (dev.fd_raw, write_pout.buf + write_std.pos, write_pout.size - write_pout.pos); if (0 > ret) { fprintf (stderr, "Failed to write to WLAN device: %s\n", strerror (errno)); break; } write_pout.pos += ret; if ((write_pout.pos != write_pout.size) && (0 != ret)) { /* we should not get partial sends with packet-oriented devices... */ fprintf (stderr, "Write error, partial send: %u/%u\n", (unsigned int) write_pout.pos, (unsigned int) write_pout.size); break; } if (write_pout.pos == write_pout.size) { write_pout.pos = 0; write_pout.size = 0; } } if (FD_ISSET (STDIN_FILENO, &rfds)) { ssize_t ret = read (STDIN_FILENO, readbuf, sizeof (readbuf)); if (0 > ret) { fprintf (stderr, "Read error from STDIN: %s\n", strerror (errno)); break; } if (0 == ret) { /* stop reading... */ stdin_open = 0; } mst_receive (stdin_mst, readbuf, ret); } if (FD_ISSET (dev.fd_raw, &rfds)) { struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *rrm; ssize_t ret; rrm = (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *) write_std.buf; ret = linux_read (&dev, (unsigned char *) &rrm->frame, sizeof (write_std.buf) - sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage) + sizeof (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame), rrm); if (0 > ret) { fprintf (stderr, "Read error from raw socket: %s\n", strerror (errno)); break; } if ((0 < ret) && (0 == mac_test (&rrm->frame, &dev))) { write_std.size = ret + sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage) - sizeof (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame); rrm->header.size = htons (write_std.size); rrm->header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER); } } } /* Error handling, try to clean up a bit at least */ mst_destroy (stdin_mst); (void) close (dev.fd_raw); return 1; /* we never exit 'normally' */ } /* end of gnunet-helper-transport-wlan.c */ gnunet-0.9.3/src/transport/gnunet-service-transport_hello.c0000644000175000017500000001725011760502551021115 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/gnunet-service-transport_hello.c * @brief hello management implementation * @author Christian Grothoff */ #include "platform.h" #include "gnunet_constants.h" #include "gnunet_hello_lib.h" #include "gnunet_peerinfo_service.h" #include "gnunet_statistics_service.h" #include "gnunet-service-transport_hello.h" #include "gnunet-service-transport.h" #include "gnunet-service-transport_plugins.h" /** * How often do we refresh our HELLO (due to expiration concerns)? */ #define HELLO_REFRESH_PERIOD GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6) /** * Entry in linked list of network addresses for ourselves. Also * includes a cached signature for 'struct TransportPongMessage's. */ struct OwnAddressList { /** * This is a doubly-linked list. */ struct OwnAddressList *next; /** * This is a doubly-linked list. */ struct OwnAddressList *prev; /** * The address. */ struct GNUNET_HELLO_Address *address; /** * How long until the current signature expires? (ZERO if the * signature was never created). */ struct GNUNET_TIME_Absolute pong_sig_expires; /** * Signature for a 'struct TransportPongMessage' for this address. */ struct GNUNET_CRYPTO_RsaSignature pong_signature; }; /** * Our HELLO message. */ static struct GNUNET_HELLO_Message *our_hello; /** * Function to call on HELLO changes. */ static GST_HelloCallback hello_cb; /** * Closure for 'hello_cb'. */ static void *hello_cb_cls; /** * Head of my addresses. */ struct OwnAddressList *oal_head; /** * Tail of my addresses. */ struct OwnAddressList *oal_tail; /** * Identifier of 'refresh_hello' task. */ static GNUNET_SCHEDULER_TaskIdentifier hello_task; /** * Closure for 'address_generator'. */ struct GeneratorContext { /** * Where are we in the DLL? */ struct OwnAddressList *addr_pos; /** * When do addresses expire? */ struct GNUNET_TIME_Absolute expiration; }; /** * Add an address from the 'OwnAddressList' to the buffer. * * @param cls the 'struct GeneratorContext' * @param max maximum number of bytes left * @param buf where to write the address */ static size_t address_generator (void *cls, size_t max, void *buf) { struct GeneratorContext *gc = cls; size_t ret; if (NULL == gc->addr_pos) return 0; ret = GNUNET_HELLO_add_address (gc->addr_pos->address, gc->expiration, buf, max); gc->addr_pos = gc->addr_pos->next; return ret; } /** * Construct our HELLO message from all of the addresses of * all of the transports. * * @param cls unused * @param tc scheduler context */ static void refresh_hello_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GeneratorContext gc; hello_task = GNUNET_SCHEDULER_NO_TASK; gc.addr_pos = oal_head; gc.expiration = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION); GNUNET_free (our_hello); our_hello = GNUNET_HELLO_create (&GST_my_public_key, &address_generator, &gc); GNUNET_assert (NULL != our_hello); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size (our_hello)); GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# refreshed my HELLO"), 1, GNUNET_NO); if (NULL != hello_cb) hello_cb (hello_cb_cls, GST_hello_get ()); GNUNET_PEERINFO_add_peer (GST_peerinfo, our_hello, NULL, NULL); hello_task = GNUNET_SCHEDULER_add_delayed (HELLO_REFRESH_PERIOD, &refresh_hello_task, NULL); } /** * Schedule task to refresh hello (unless such a * task exists already). */ static void refresh_hello () { if (hello_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (hello_task); hello_task = GNUNET_SCHEDULER_add_now (&refresh_hello_task, NULL); } /** * Initialize the HELLO module. * * @param cb function to call whenever our HELLO changes * @param cb_cls closure for cb */ void GST_hello_start (GST_HelloCallback cb, void *cb_cls) { hello_cb = cb; hello_cb_cls = cb_cls; our_hello = GNUNET_HELLO_create (&GST_my_public_key, NULL, NULL); GNUNET_assert (NULL != our_hello); refresh_hello (); } /** * Shutdown the HELLO module. */ void GST_hello_stop () { hello_cb = NULL; hello_cb_cls = NULL; if (GNUNET_SCHEDULER_NO_TASK != hello_task) { GNUNET_SCHEDULER_cancel (hello_task); hello_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != our_hello) { GNUNET_free (our_hello); our_hello = NULL; } } /** * Obtain this peers HELLO message. * * @return our HELLO message */ const struct GNUNET_MessageHeader * GST_hello_get () { return (struct GNUNET_MessageHeader *) our_hello; } /** * Add or remove an address from this peer's HELLO message. * * @param addremove GNUNET_YES to add, GNUNET_NO to remove * @param address address to add or remove */ void GST_hello_modify_addresses (int addremove, const struct GNUNET_HELLO_Address *address) { struct OwnAddressList *al; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, (addremove == GNUNET_YES) ? "Adding `%s' to the set of our addresses\n" : "Removing `%s' from the set of our addresses\n", GST_plugins_a2s (address)); GNUNET_assert (address != NULL); if (GNUNET_NO == addremove) { for (al = oal_head; al != NULL; al = al->next) if (0 == GNUNET_HELLO_address_cmp (address, al->address)) { GNUNET_CONTAINER_DLL_remove (oal_head, oal_tail, al); GNUNET_HELLO_address_free (al->address); GNUNET_free (al); refresh_hello (); return; } /* address to be removed not found!? */ GNUNET_break (0); return; } al = GNUNET_malloc (sizeof (struct OwnAddressList)); GNUNET_CONTAINER_DLL_insert (oal_head, oal_tail, al); al->address = GNUNET_HELLO_address_copy (address); refresh_hello (); } /** * Test if a particular address is one of ours. * * @param address address to test * @param sig location where to cache PONG signatures for this address [set] * @param sig_expiration how long until the current 'sig' expires? * (ZERO if sig was never created) [set] * @return GNUNET_YES if this is one of our addresses, * GNUNET_NO if not */ int GST_hello_test_address (const struct GNUNET_HELLO_Address *address, struct GNUNET_CRYPTO_RsaSignature **sig, struct GNUNET_TIME_Absolute **sig_expiration) { struct OwnAddressList *al; for (al = oal_head; al != NULL; al = al->next) if (0 == GNUNET_HELLO_address_cmp (address, al->address)) { *sig = &al->pong_signature; *sig_expiration = &al->pong_sig_expires; return GNUNET_YES; } *sig = NULL; *sig_expiration = NULL; return GNUNET_NO; } /* end of file gnunet-service-transport_hello.c */ gnunet-0.9.3/src/transport/test_transport_api_reliability_https_peer2.conf0000644000175000017500000000121011665472561024301 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-https-p2/ DEFAULTCONFIG = test_transport_api_reliability_https_peer2.conf [transport-https] PORT = 12310 KEY_FILE = $SERVICEHOME/https_key_p2.key CERT_FILE = $SERVICEHOME/https_cert_p2.crt [arm] PORT = 12315 UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12314 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12313 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12312 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12311 PLUGINS = https UNIXPATH = /tmp/gnunet-p2-service-transport.sock gnunet-0.9.3/src/transport/gnunet-service-transport_validation.h0000644000175000017500000001253611760502551022153 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/gnunet-service-transport_validation.h * @brief address validation API * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_TRANSPORT_VALIDATION_H #define GNUNET_SERVICE_TRANSPORT_VALIDATION_H #include "gnunet_statistics_service.h" #include "gnunet_transport_plugin.h" #include "gnunet_util_lib.h" #include "gnunet_hello_lib.h" /** * Start the validation subsystem. */ void GST_validation_start (void); /** * Stop the validation subsystem. */ void GST_validation_stop (void); /** * Update if we are using an address for a connection actively right now. * Based on this, the validation module will measure latency for the * address more or less often. * * @param address the address * @param session the session * @param in_use GNUNET_YES if we are now using the address for a connection, * GNUNET_NO if we are no longer using the address for a connection * @param line line of caller just for DEBUGGING! */ void GST_validation_set_address_use (const struct GNUNET_HELLO_Address *address, struct Session *session, int in_use, int line); /** * Query validation about the latest observed latency on a given * address. * * @param sender peer * @param address the address * @param session session * @return observed latency of the address, FOREVER if the address was * never successfully validated */ struct GNUNET_TIME_Relative GST_validation_get_address_latency (const struct GNUNET_PeerIdentity *sender, const struct GNUNET_HELLO_Address *address, struct Session *session); /** * We've received a PING. If appropriate, generate a PONG. * * @param sender peer sending the PING * @param hdr the PING * @param sender_address address of the sender, NULL if we did not initiate * @param session session we got the PING from */ void GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *hdr, const struct GNUNET_HELLO_Address *sender_address, struct Session *session); /** * We've received a PONG. Check if it matches a pending PING and * mark the respective address as confirmed. * * @param sender peer sending the PONG * @param hdr the PONG */ void GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *hdr); /** * We've received a HELLO, check which addresses are new and trigger * validation. * * @param hello the HELLO we received */ void GST_validation_handle_hello (const struct GNUNET_MessageHeader *hello); /** * Function called for each address (or address status change) that * the validation module is aware of (for the given target). * * @param cls closure * @param public_key public key for the peer, never NULL * @param valid_until is ZERO if we never validated the address, * otherwise a time up to when we consider it (or was) valid * @param validation_block is FOREVER if the address is for an unsupported plugin (from PEERINFO) * is ZERO if the address is considered valid (no validation needed) * otherwise a time in the future if we're currently denying re-validation * @param address the address */ typedef void (*GST_ValidationAddressCallback) (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded * public_key, struct GNUNET_TIME_Absolute valid_until, struct GNUNET_TIME_Absolute validation_block, const struct GNUNET_HELLO_Address * address); /** * Call the given function for each address for the given target. * * @param target peer information is requested for * @param cb function to call; will not be called after this function returns * @param cb_cls closure for 'cb' */ void GST_validation_get_addresses (const struct GNUNET_PeerIdentity *target, GST_ValidationAddressCallback cb, void *cb_cls); #endif /* end of file gnunet-service-transport_validation.h */ gnunet-0.9.3/src/transport/transport.h0000644000175000017500000002150111760502551014775 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/transport.h * @brief common internal definitions for transport service * @author Christian Grothoff */ #ifndef TRANSPORT_H #define TRANSPORT_H #include "gnunet_crypto_lib.h" #include "gnunet_time_lib.h" #include "gnunet_transport_service.h" #include "gnunet_constants.h" #define DEBUG_TRANSPORT GNUNET_EXTRA_LOGGING /** * For how long do we allow unused bandwidth * from the past to carry over into the future? (in seconds) */ #define MAX_BANDWIDTH_CARRY_S GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S /** * How often do we (at most) do a full quota * recalculation? (in ms) */ #define MIN_QUOTA_REFRESH_TIME 2000 /** * Maximum frequency for re-evaluating latencies for all transport addresses. */ #define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1) /** * Maximum frequency for re-evaluating latencies for connected addresses. */ #define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1) GNUNET_NETWORK_STRUCT_BEGIN /** * Message from the transport service to the library * asking to check if both processes agree about this * peers identity. */ struct StartMessage { /** * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_START */ struct GNUNET_MessageHeader header; /** * 0: no options * 1: The 'self' field should be checked * 2: this client is interested in payload traffic */ uint32_t options; /** * Identity we think we have. If it does not match, the * receiver should print out an error message and disconnect. */ struct GNUNET_PeerIdentity self; }; /** * Message from the transport service to the library * informing about neighbors. */ struct ConnectInfoMessage { /** * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT */ struct GNUNET_MessageHeader header; /** * Number of ATS key-value pairs that follow this struct * (excluding the 0-terminator). */ uint32_t ats_count GNUNET_PACKED; /** * Identity of the new neighbour. */ struct GNUNET_PeerIdentity id; }; /** * Message from the transport service to the library * informing about disconnects. */ struct DisconnectInfoMessage { /** * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT */ struct GNUNET_MessageHeader header; /** * Reserved, always zero. */ uint32_t reserved GNUNET_PACKED; /** * Who got disconnected? */ struct GNUNET_PeerIdentity peer; }; /** * Message type for sending a request connect message * to the transport service. Must be done before transport * api will allow messages to be queued/sent to transport * service for transmission to a peer. */ struct TransportRequestConnectMessage { /** * Message header */ struct GNUNET_MessageHeader header; /** * For alignment. */ uint32_t reserved; /** * Identity of the peer we would like to connect to. */ struct GNUNET_PeerIdentity peer; }; /** * Message used to set a particular bandwidth quota. Sent TO the * service to set an incoming quota, sent FROM the service to update * an outgoing quota. */ struct QuotaSetMessage { /** * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA */ struct GNUNET_MessageHeader header; /** * Quota. */ struct GNUNET_BANDWIDTH_Value32NBO quota; /** * About which peer are we talking here? */ struct GNUNET_PeerIdentity peer; }; /** * Message used to notify the transport API about a message * received from the network. The actual message follows. */ struct InboundMessage { /** * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_RECV */ struct GNUNET_MessageHeader header; /** * Number of ATS key-value pairs that follow this struct * (excluding the 0-terminator). */ uint32_t ats_count GNUNET_PACKED; /** * Which peer sent the message? */ struct GNUNET_PeerIdentity peer; }; /** * Message used to notify the transport API that it can * send another message to the transport service. */ struct SendOkMessage { /** * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK */ struct GNUNET_MessageHeader header; /** * GNUNET_OK if the transmission succeeded, * GNUNET_SYSERR if it failed (i.e. network disconnect); * in either case, it is now OK for this client to * send us another message for the given peer. */ uint32_t success GNUNET_PACKED; /** * Latency estimate. */ struct GNUNET_TIME_RelativeNBO latency; /** * Which peer can send more now? */ struct GNUNET_PeerIdentity peer; }; /** * Message used to notify the transport service about a message * to be transmitted to another peer. The actual message follows. */ struct OutboundMessage { /** * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_SEND */ struct GNUNET_MessageHeader header; /** * Message priority. */ uint32_t priority GNUNET_PACKED; /** * Allowed delay. */ struct GNUNET_TIME_RelativeNBO timeout; /** * Which peer should receive the message? */ struct GNUNET_PeerIdentity peer; }; /** * Message from the library to the transport service * asking for converting a transport address to a * human-readable UTF-8 string. */ struct AddressLookupMessage { /** * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING */ struct GNUNET_MessageHeader header; /** * Should the conversion use numeric IP addresses (otherwise * a reverse DNS lookup is OK -- if applicable). */ int16_t numeric_only GNUNET_PACKED; /** * Length of the (binary) address in bytes, in big-endian. */ uint16_t addrlen GNUNET_PACKED; /** * timeout to give up. */ struct GNUNET_TIME_RelativeNBO timeout; /* followed by 'addrlen' bytes of the actual address, then * followed by the 0-terminated name of the transport */ }; /** * Message from the library to the transport service * asking for human readable addresses known for a peer. */ struct PeerAddressLookupMessage { /** * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PEER_ADDRESS_LOOKUP */ struct GNUNET_MessageHeader header; /** * For alignment. */ uint32_t reserved; /** * timeout to give up. FIXME: remove in the future. */ struct GNUNET_TIME_RelativeNBO timeout; /** * The identity of the peer to look up. */ struct GNUNET_PeerIdentity peer; }; /** * Message from the library to the transport service * asking for binary addresses known for a peer. */ struct AddressIterateMessage { /** * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE */ struct GNUNET_MessageHeader header; /** * One shot call or continous replies? */ uint32_t one_shot; /** * timeout to give up. FIXME: remove in the future */ struct GNUNET_TIME_AbsoluteNBO timeout; /** * The identity of the peer to look up. */ struct GNUNET_PeerIdentity peer; }; /** * Message from the transport service to the library * containing binary addresses known for a peer. * Memory layout: * [AddressIterateResponseMessage][address[addrlen]][transportname[pluginlen]] */ struct AddressIterateResponseMessage { /** * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE */ struct GNUNET_MessageHeader header; /** * For alignment. */ uint32_t reserved; /** * Peer identity */ struct GNUNET_PeerIdentity peer; /** * address length */ uint32_t addrlen GNUNET_PACKED; /** * length of the plugin name */ uint32_t pluginlen GNUNET_PACKED; }; /** * Change in blacklisting (either request or notification, * depending on which direction it is going). */ struct BlacklistMessage { /** * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY or * GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY. */ struct GNUNET_MessageHeader header; /** * 0 for the query, GNUNET_OK (allowed) or GNUNET_SYSERR (disallowed) * for the response. */ uint32_t is_allowed GNUNET_PACKED; /** * Which peer is being blacklisted or queried? */ struct GNUNET_PeerIdentity peer; }; GNUNET_NETWORK_STRUCT_END /* end of transport.h */ #endif gnunet-0.9.3/src/transport/test_transport_api_timeout.c0000644000175000017500000002234111760502551020431 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/test_transport_api_timeout.c * @brief test case for transport plugin implementations complying timeout * settings * * * This test case serves ensures that no peer disconnect events occurs * while plugins are idle */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_hello_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_transport_service.h" #include "transport.h" #include "transport-testing.h" #define VERBOSE GNUNET_NO #define START_ARM GNUNET_YES /** * How long until we give up on transmitting the message? */ #define WAIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 90) #define MTYPE 12345 static char *test_source; static char *test_plugin; static char *test_name; static int ok; static GNUNET_SCHEDULER_TaskIdentifier die_task; static GNUNET_SCHEDULER_TaskIdentifier timer_task; static struct GNUNET_TRANSPORT_TESTING_handle *tth; static struct PeerContext *p1; static struct PeerContext *p2; static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; static struct GNUNET_TRANSPORT_TransmitHandle *th; static char *cfg_file_p1; static char *cfg_file_p2; static struct GNUNET_TIME_Relative time_running; static int shutdown_flag; static int disconnects; #if VERBOSE #define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) #else #define OKPP do { ok++; } while (0) #endif static void end () { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); if (timer_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (timer_task); timer_task = GNUNET_SCHEDULER_NO_TASK; } if (die_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; } if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); if (disconnects == 0) ok = 0; else { ok = disconnects; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Had %u disconnects while waiting %llu seconds \n", disconnects, WAIT.rel_value); } GNUNET_TRANSPORT_TESTING_done (tth); } static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { die_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); if (timer_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (timer_task); timer_task = GNUNET_SCHEDULER_NO_TASK; } if (cc != NULL) GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; if (p1 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); if (p2 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); ok = GNUNET_SYSERR; GNUNET_TRANSPORT_TESTING_done (tth); } static void notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received message of type %d from peer %s!\n", ntohs (message->type), GNUNET_i2s (peer)); } static void notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' connected to us (%p)!\n", GNUNET_i2s (peer), cls); } static void notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { if (shutdown_flag != GNUNET_YES) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "FAIL! Peer `%4s' disconnected during waiting period!\n", GNUNET_i2s (peer)); disconnects++; } if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; } static void timer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { static int percentage; timer_task = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; percentage += 10; time_running = GNUNET_TIME_relative_add (time_running, GNUNET_TIME_relative_divide (WAIT, 10)); if (time_running.rel_value == GNUNET_TIME_relative_max (time_running, WAIT).rel_value) { FPRINTF (stderr, "%s", "100%%\n"); shutdown_flag = GNUNET_YES; GNUNET_SCHEDULER_add_now (&end, NULL); } else { FPRINTF (stderr, "%u%%..", percentage); timer_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (WAIT, 10), &timer, NULL); } } static void testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) { cc = NULL; char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %s <-> %s\n", p1_c, GNUNET_i2s (&p2->id)); GNUNET_free (p1_c); shutdown_flag = GNUNET_NO; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Waiting for %llu seconds\n", (WAIT.rel_value) / 1000); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_delayed (WAIT, &end_badly, NULL); timer_task = GNUNET_SCHEDULER_add_now (&timer, NULL); } static void start_cb (struct PeerContext *p, void *cls) { static int started; started++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, GNUNET_i2s (&p->id)); if (started != 2) return; char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n", p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id)); cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); if ((p1 == NULL) || (p2 == NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } } static int check () { static char *const argv[] = { "test-transport-api-timeout", "-c", "test_transport_api_data.conf", NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; #if WRITECONFIG setTransportOptions ("test_transport_api_data.conf"); #endif timer_task = GNUNET_SCHEDULER_NO_TASK; ok = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-transport-api-timeout", "nohelp", options, &run, &ok); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); GNUNET_log_setup (test_name, "WARNING", NULL); GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source); GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source, &test_plugin); tth = GNUNET_TRANSPORT_TESTING_init (); GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1); GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2); ret = check (); GNUNET_free (cfg_file_p1); GNUNET_free (cfg_file_p2); GNUNET_free (test_source); GNUNET_free (test_plugin); GNUNET_free (test_name); return ret; } /* end of test_transport_api_timeout.c*/ gnunet-0.9.3/src/transport/gnunet-service-transport_clients.h0000644000175000017500000000467311760502551021465 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/gnunet-service-transport_clients.h * @brief plugin management API * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_TRANSPORT_CLIENTS_H #define GNUNET_SERVICE_TRANSPORT_CLIENTS_H #include "gnunet_statistics_service.h" #include "gnunet_util_lib.h" #include "gnunet_hello_lib.h" /** * Start handling requests from clients. * * @param server server used to accept clients from. */ void GST_clients_start (struct GNUNET_SERVER_Handle *server); /** * Stop processing clients. */ void GST_clients_stop (void); /** * Broadcast the given message to all of our clients. * * @param msg message to broadcast * @param may_drop GNUNET_YES if the message can be dropped / is payload */ void GST_clients_broadcast (const struct GNUNET_MessageHeader *msg, int may_drop); /** * Send the given message to a particular client * * @param client target of the message * @param msg message to transmit * @param may_drop GNUNET_YES if the message can be dropped */ void GST_clients_unicast (struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *msg, int may_drop); /** * Broadcast the new active address to all clients monitoring the peer. * * @param peer peer this update is about (never NULL) * @param address address, NULL on disconnect */ void GST_clients_broadcast_address_notification (const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Address *address); #endif /* end of file gnunet-service-transport_clients.h */ gnunet-0.9.3/src/transport/test_transport_api_timeout_udp_peer1.conf0000644000175000017500000000120211721510741023066 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-udp-p1/ DEFAULTCONFIG = test_transport_api_udp_peer1.conf [transport-udp] PORT = 12040 BROADCAST = NO BROADCAST_INTERVAL = 30000 MAX_BPS = 50000000 [arm] PORT = 12045 UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12044 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12043 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12042 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] #PREFIX = valgrind --leak-check=full PORT = 12041 PLUGINS = udp UNIXPATH = /tmp/gnunet-p1-service-transport.sock gnunet-0.9.3/src/transport/plugin_transport_udp.c0000644000175000017500000021743011760676474017246 00000000000000/* This file is part of GNUnet (C) 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/plugin_transport_udp.c * @brief Implementation of the UDP transport protocol * @author Christian Grothoff * @author Nathan Evans * @author Matthias Wachs */ #include "platform.h" #include "plugin_transport_udp.h" #include "gnunet_hello_lib.h" #include "gnunet_util_lib.h" #include "gnunet_fragmentation_lib.h" #include "gnunet_nat_lib.h" #include "gnunet_protocols.h" #include "gnunet_resolver_service.h" #include "gnunet_signatures.h" #include "gnunet_constants.h" #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" #include "gnunet_transport_plugin.h" #include "transport.h" #define LOG(kind,...) GNUNET_log_from (kind, "transport-udp", __VA_ARGS__) /** * Number of messages we can defragment in parallel. We only really * defragment 1 message at a time, but if messages get re-ordered, we * may want to keep knowledge about the previous message to avoid * discarding the current message in favor of a single fragment of a * previous message. 3 should be good since we don't expect massive * message reorderings with UDP. */ #define UDP_MAX_MESSAGES_IN_DEFRAG 3 /** * We keep a defragmentation queue per sender address. How many * sender addresses do we support at the same time? Memory consumption * is roughly a factor of 32k * UDP_MAX_MESSAGES_IN_DEFRAG times this * value. (So 128 corresponds to 12 MB and should suffice for * connecting to roughly 128 peers via UDP). */ #define UDP_MAX_SENDER_ADDRESSES_WITH_DEFRAG 128 /** * Closure for 'append_port'. */ struct PrettyPrinterContext { /** * Function to call with the result. */ GNUNET_TRANSPORT_AddressStringCallback asc; /** * Clsoure for 'asc'. */ void *asc_cls; /** * Port to add after the IP address. */ uint16_t port; }; struct Session { /** * Which peer is this session for? */ struct GNUNET_PeerIdentity target; struct FragmentationContext * frag_ctx; /** * Address of the other peer */ const struct sockaddr *sock_addr; /** * Desired delay for next sending we send to other peer */ struct GNUNET_TIME_Relative flow_delay_for_other_peer; /** * Desired delay for next sending we received from other peer */ struct GNUNET_TIME_Absolute flow_delay_from_other_peer; /** * Session timeout task */ GNUNET_SCHEDULER_TaskIdentifier timeout_task; /** * expected delay for ACKs */ struct GNUNET_TIME_Relative last_expected_delay; struct GNUNET_ATS_Information ats; size_t addrlen; unsigned int rc; int in_destroy; }; struct SessionCompareContext { struct Session *res; const struct GNUNET_HELLO_Address *addr; }; /** * Closure for 'process_inbound_tokenized_messages' */ struct SourceInformation { /** * Sender identity. */ struct GNUNET_PeerIdentity sender; /** * Source address. */ const void *arg; struct Session *session; /** * Number of bytes in source address. */ size_t args; }; /** * Closure for 'find_receive_context'. */ struct FindReceiveContext { /** * Where to store the result. */ struct DefragContext *rc; /** * Address to find. */ const struct sockaddr *addr; struct Session *session; /** * Number of bytes in 'addr'. */ socklen_t addr_len; }; /** * Data structure to track defragmentation contexts based * on the source of the UDP traffic. */ struct DefragContext { /** * Defragmentation context. */ struct GNUNET_DEFRAGMENT_Context *defrag; /** * Source address this receive context is for (allocated at the * end of the struct). */ const struct sockaddr *src_addr; /** * Reference to master plugin struct. */ struct Plugin *plugin; /** * Node in the defrag heap. */ struct GNUNET_CONTAINER_HeapNode *hnode; /** * Length of 'src_addr' */ size_t addr_len; }; /** * Closure for 'process_inbound_tokenized_messages' */ struct FragmentationContext { struct FragmentationContext * next; struct FragmentationContext * prev; struct Plugin * plugin; struct GNUNET_FRAGMENT_Context * frag; struct Session * session; /** * Function to call upon completion of the transmission. */ GNUNET_TRANSPORT_TransmitContinuation cont; /** * Closure for 'cont'. */ void *cont_cls; struct GNUNET_TIME_Absolute timeout; size_t bytes_to_send; }; struct UDPMessageWrapper { struct Session *session; struct UDPMessageWrapper *prev; struct UDPMessageWrapper *next; char *udp; /** * Function to call upon completion of the transmission. */ GNUNET_TRANSPORT_TransmitContinuation cont; /** * Closure for 'cont'. */ void *cont_cls; struct FragmentationContext *frag_ctx; size_t msg_size; struct GNUNET_TIME_Absolute timeout; }; /** * UDP ACK Message-Packet header (after defragmentation). */ struct UDP_ACK_Message { /** * Message header. */ struct GNUNET_MessageHeader header; /** * Desired delay for flow control */ uint32_t delay; /** * What is the identity of the sender */ struct GNUNET_PeerIdentity sender; }; /** * Encapsulation of all of the state of the plugin. */ struct Plugin * plugin; /** * We have been notified that our readset has something to read. We don't * know which socket needs to be read, so we have to check each one * Then reschedule this function to be called again once more is available. * * @param cls the plugin handle * @param tc the scheduling context (for rescheduling this function again) */ static void udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * We have been notified that our readset has something to read. We don't * know which socket needs to be read, so we have to check each one * Then reschedule this function to be called again once more is available. * * @param cls the plugin handle * @param tc the scheduling context (for rescheduling this function again) */ static void udp_plugin_select_v6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Start session timeout */ static void start_session_timeout (struct Session *s); /** * Increment session timeout due to activity */ static void reschedule_session_timeout (struct Session *s); /** * Cancel timeout */ static void stop_session_timeout (struct Session *s); /** * Function called for a quick conversion of the binary address to * a numeric address. Note that the caller must not free the * address and that the next call to this function is allowed * to override the address again. * * @param cls closure * @param addr binary address * @param addrlen length of the address * @return string representing the same address */ const char * udp_address_to_string (void *cls, const void *addr, size_t addrlen) { static char rbuf[INET6_ADDRSTRLEN + 10]; char buf[INET6_ADDRSTRLEN]; const void *sb; struct in_addr a4; struct in6_addr a6; const struct IPv4UdpAddress *t4; const struct IPv6UdpAddress *t6; int af; uint16_t port; if (addrlen == sizeof (struct IPv6UdpAddress)) { t6 = addr; af = AF_INET6; port = ntohs (t6->u6_port); memcpy (&a6, &t6->ipv6_addr, sizeof (a6)); sb = &a6; } else if (addrlen == sizeof (struct IPv4UdpAddress)) { t4 = addr; af = AF_INET; port = ntohs (t4->u4_port); memcpy (&a4, &t4->ipv4_addr, sizeof (a4)); sb = &a4; } else { GNUNET_break_op (0); return NULL; } inet_ntop (af, sb, buf, INET6_ADDRSTRLEN); GNUNET_snprintf (rbuf, sizeof (rbuf), (af == AF_INET6) ? "[%s]:%u" : "%s:%u", buf, port); return rbuf; } /** * Function called to convert a string address to * a binary address. * * @param cls closure ('struct Plugin*') * @param addr string address * @param addrlen length of the address * @param buf location to store the buffer * @param added location to store the number of bytes in the buffer. * If the function returns GNUNET_SYSERR, its contents are undefined. * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ static int udp_string_to_address (void *cls, const char *addr, uint16_t addrlen, void **buf, size_t *added) { struct sockaddr_storage socket_address; if ((NULL == addr) || (0 == addrlen)) { GNUNET_break (0); return GNUNET_SYSERR; } if ('\0' != addr[addrlen - 1]) { return GNUNET_SYSERR; } if (strlen (addr) != addrlen - 1) { return GNUNET_SYSERR; } if (GNUNET_OK != GNUNET_STRINGS_to_address_ip (addr, strlen (addr), &socket_address)) { return GNUNET_SYSERR; } switch (socket_address.ss_family) { case AF_INET: { struct IPv4UdpAddress *u4; struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address; u4 = GNUNET_malloc (sizeof (struct IPv4UdpAddress)); u4->ipv4_addr = in4->sin_addr.s_addr; u4->u4_port = in4->sin_port; *buf = u4; *added = sizeof (struct IPv4UdpAddress); return GNUNET_OK; } case AF_INET6: { struct IPv6UdpAddress *u6; struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address; u6 = GNUNET_malloc (sizeof (struct IPv6UdpAddress)); u6->ipv6_addr = in6->sin6_addr; u6->u6_port = in6->sin6_port; *buf = u6; *added = sizeof (struct IPv6UdpAddress); return GNUNET_OK; } default: GNUNET_break (0); return GNUNET_SYSERR; } } /** * Append our port and forward the result. * * @param cls a 'struct PrettyPrinterContext' * @param hostname result from DNS resolver */ static void append_port (void *cls, const char *hostname) { struct PrettyPrinterContext *ppc = cls; char *ret; if (hostname == NULL) { ppc->asc (ppc->asc_cls, NULL); GNUNET_free (ppc); return; } GNUNET_asprintf (&ret, "%s:%d", hostname, ppc->port); ppc->asc (ppc->asc_cls, ret); GNUNET_free (ret); } /** * Convert the transports address to a nice, human-readable * format. * * @param cls closure * @param type name of the transport that generated the address * @param addr one of the addresses of the host, NULL for the last address * the specific address format depends on the transport * @param addrlen length of the address * @param numeric should (IP) addresses be displayed in numeric form? * @param timeout after how long should we give up? * @param asc function to call on each string * @param asc_cls closure for asc */ static void udp_plugin_address_pretty_printer (void *cls, const char *type, const void *addr, size_t addrlen, int numeric, struct GNUNET_TIME_Relative timeout, GNUNET_TRANSPORT_AddressStringCallback asc, void *asc_cls) { struct PrettyPrinterContext *ppc; const void *sb; size_t sbs; struct sockaddr_in a4; struct sockaddr_in6 a6; const struct IPv4UdpAddress *u4; const struct IPv6UdpAddress *u6; uint16_t port; if (addrlen == sizeof (struct IPv6UdpAddress)) { u6 = addr; memset (&a6, 0, sizeof (a6)); a6.sin6_family = AF_INET6; #if HAVE_SOCKADDR_IN_SIN_LEN a6.sin6_len = sizeof (a6); #endif a6.sin6_port = u6->u6_port; memcpy (&a6.sin6_addr, &u6->ipv6_addr, sizeof (struct in6_addr)); port = ntohs (u6->u6_port); sb = &a6; sbs = sizeof (a6); } else if (addrlen == sizeof (struct IPv4UdpAddress)) { u4 = addr; memset (&a4, 0, sizeof (a4)); a4.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN a4.sin_len = sizeof (a4); #endif a4.sin_port = u4->u4_port; a4.sin_addr.s_addr = u4->ipv4_addr; port = ntohs (u4->u4_port); sb = &a4; sbs = sizeof (a4); } else if (0 == addrlen) { asc (asc_cls, ""); asc (asc_cls, NULL); return; } else { /* invalid address */ GNUNET_break_op (0); asc (asc_cls, NULL); return; } ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext)); ppc->asc = asc; ppc->asc_cls = asc_cls; ppc->port = port; GNUNET_RESOLVER_hostname_get (sb, sbs, !numeric, timeout, &append_port, ppc); } static void call_continuation (struct UDPMessageWrapper *udpw, int result) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Calling continuation for %u byte message to `%s' with result %s\n", udpw->msg_size, GNUNET_i2s (&udpw->session->target), (GNUNET_OK == result) ? "OK" : "SYSERR"); if (NULL != udpw->cont) { udpw->cont (udpw->cont_cls, &udpw->session->target,result); } } /** * Check if the given port is plausible (must be either our listen * port or our advertised port). If it is neither, we return * GNUNET_SYSERR. * * @param plugin global variables * @param in_port port number to check * @return GNUNET_OK if port is either open_port or adv_port */ static int check_port (struct Plugin *plugin, uint16_t in_port) { if ((in_port == plugin->port) || (in_port == plugin->aport)) return GNUNET_OK; return GNUNET_SYSERR; } /** * Function that will be called to check if a binary address for this * plugin is well-formed and corresponds to an address for THIS peer * (as per our configuration). Naturally, if absolutely necessary, * plugins can be a bit conservative in their answer, but in general * plugins should make sure that the address does not redirect * traffic to a 3rd party that might try to man-in-the-middle our * traffic. * * @param cls closure, should be our handle to the Plugin * @param addr pointer to the address * @param addrlen length of addr * @return GNUNET_OK if this is a plausible address for this peer * and transport, GNUNET_SYSERR if not * */ static int udp_plugin_check_address (void *cls, const void *addr, size_t addrlen) { struct Plugin *plugin = cls; struct IPv4UdpAddress *v4; struct IPv6UdpAddress *v6; if ((addrlen != sizeof (struct IPv4UdpAddress)) && (addrlen != sizeof (struct IPv6UdpAddress))) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (addrlen == sizeof (struct IPv4UdpAddress)) { v4 = (struct IPv4UdpAddress *) addr; if (GNUNET_OK != check_port (plugin, ntohs (v4->u4_port))) return GNUNET_SYSERR; if (GNUNET_OK != GNUNET_NAT_test_address (plugin->nat, &v4->ipv4_addr, sizeof (struct in_addr))) return GNUNET_SYSERR; } else { v6 = (struct IPv6UdpAddress *) addr; if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr)) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (GNUNET_OK != check_port (plugin, ntohs (v6->u6_port))) return GNUNET_SYSERR; if (GNUNET_OK != GNUNET_NAT_test_address (plugin->nat, &v6->ipv6_addr, sizeof (struct in6_addr))) return GNUNET_SYSERR; } return GNUNET_OK; } /** * Task to free resources associated with a session. * * @param s session to free */ static void free_session (struct Session *s) { if (s->frag_ctx != NULL) { GNUNET_FRAGMENT_context_destroy(s->frag_ctx->frag); GNUNET_free (s->frag_ctx); s->frag_ctx = NULL; } GNUNET_free (s); } /** * Functions with this signature are called whenever we need * to close a session due to a disconnect or failure to * establish a connection. * * @param s session to close down */ static void disconnect_session (struct Session *s) { struct UDPMessageWrapper *udpw; struct UDPMessageWrapper *next; GNUNET_assert (GNUNET_YES != s->in_destroy); LOG (GNUNET_ERROR_TYPE_DEBUG, "Session %p to peer `%s' address ended \n", s, GNUNET_i2s (&s->target), GNUNET_a2s (s->sock_addr, s->addrlen)); stop_session_timeout(s); next = plugin->ipv4_queue_head; while (NULL != (udpw = next)) { next = udpw->next; if (udpw->session == s) { GNUNET_CONTAINER_DLL_remove(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw); call_continuation(udpw, GNUNET_SYSERR); GNUNET_free (udpw); } } next = plugin->ipv6_queue_head; while (NULL != (udpw = next)) { next = udpw->next; if (udpw->session == s) { GNUNET_CONTAINER_DLL_remove(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw); call_continuation(udpw, GNUNET_SYSERR); GNUNET_free (udpw); } udpw = next; } plugin->env->session_end (plugin->env->cls, &s->target, s); if (NULL != s->frag_ctx) { if (NULL != s->frag_ctx->cont) { s->frag_ctx->cont (s->frag_ctx->cont_cls, &s->target, GNUNET_SYSERR); LOG (GNUNET_ERROR_TYPE_DEBUG, "Calling continuation for fragemented message to `%s' with result SYSERR\n", GNUNET_i2s (&s->target)); } } GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (plugin->sessions, &s->target.hashPubKey, s)); GNUNET_STATISTICS_set(plugin->env->stats, "# UDP sessions active", GNUNET_CONTAINER_multihashmap_size(plugin->sessions), GNUNET_NO); if (s->rc > 0) s->in_destroy = GNUNET_YES; else free_session (s); } /** * Destroy a session, plugin is being unloaded. * * @param cls unused * @param key hash of public key of target peer * @param value a 'struct PeerSession*' to clean up * @return GNUNET_OK (continue to iterate) */ static int disconnect_and_free_it (void *cls, const GNUNET_HashCode * key, void *value) { disconnect_session(value); return GNUNET_OK; } /** * Disconnect from a remote node. Clean up session if we have one for this peer * * @param cls closure for this call (should be handle to Plugin) * @param target the peeridentity of the peer to disconnect * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed */ static void udp_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) { struct Plugin *plugin = cls; GNUNET_assert (plugin != NULL); GNUNET_assert (target != NULL); LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer `%s'\n", GNUNET_i2s (target)); /* Clean up sessions */ GNUNET_CONTAINER_multihashmap_get_multiple (plugin->sessions, &target->hashPubKey, &disconnect_and_free_it, plugin); } static struct Session * create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, const void *addr, size_t addrlen, GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) { struct Session *s; const struct IPv4UdpAddress *t4; const struct IPv6UdpAddress *t6; struct sockaddr_in *v4; struct sockaddr_in6 *v6; size_t len; switch (addrlen) { case sizeof (struct IPv4UdpAddress): if (NULL == plugin->sockv4) { return NULL; } t4 = addr; s = GNUNET_malloc (sizeof (struct Session) + sizeof (struct sockaddr_in)); len = sizeof (struct sockaddr_in); v4 = (struct sockaddr_in *) &s[1]; v4->sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN v4->sin_len = sizeof (struct sockaddr_in); #endif v4->sin_port = t4->u4_port; v4->sin_addr.s_addr = t4->ipv4_addr; s->ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) v4, sizeof (struct sockaddr_in)); break; case sizeof (struct IPv6UdpAddress): if (NULL == plugin->sockv6) { return NULL; } t6 = addr; s = GNUNET_malloc (sizeof (struct Session) + sizeof (struct sockaddr_in6)); len = sizeof (struct sockaddr_in6); v6 = (struct sockaddr_in6 *) &s[1]; v6->sin6_family = AF_INET6; #if HAVE_SOCKADDR_IN_SIN_LEN v6->sin6_len = sizeof (struct sockaddr_in6); #endif v6->sin6_port = t6->u6_port; v6->sin6_addr = t6->ipv6_addr; s->ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) v6, sizeof (struct sockaddr_in6)); break; default: /* Must have a valid address to send to */ GNUNET_break_op (0); return NULL; } s->addrlen = len; s->target = *target; s->sock_addr = (const struct sockaddr *) &s[1]; s->last_expected_delay = GNUNET_TIME_UNIT_SECONDS; start_session_timeout(s); return s; } static int session_cmp_it (void *cls, const GNUNET_HashCode * key, void *value) { struct SessionCompareContext * cctx = cls; const struct GNUNET_HELLO_Address *address = cctx->addr; struct Session *s = value; socklen_t s_addrlen = s->addrlen; LOG (GNUNET_ERROR_TYPE_DEBUG, "Comparing address %s <-> %s\n", udp_address_to_string (NULL, (void *) address->address, address->address_length), GNUNET_a2s (s->sock_addr, s->addrlen)); if ((address->address_length == sizeof (struct IPv4UdpAddress)) && (s_addrlen == sizeof (struct sockaddr_in))) { struct IPv4UdpAddress * u4 = NULL; u4 = (struct IPv4UdpAddress *) address->address; const struct sockaddr_in *s4 = (const struct sockaddr_in *) s->sock_addr; if ((0 == memcmp ((const void *) &u4->ipv4_addr,(const void *) &s4->sin_addr, sizeof (struct in_addr))) && (u4->u4_port == s4->sin_port)) { cctx->res = s; return GNUNET_NO; } } if ((address->address_length == sizeof (struct IPv6UdpAddress)) && (s_addrlen == sizeof (struct sockaddr_in6))) { struct IPv6UdpAddress * u6 = NULL; u6 = (struct IPv6UdpAddress *) address->address; const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) s->sock_addr; if ((0 == memcmp (&u6->ipv6_addr, &s6->sin6_addr, sizeof (struct in6_addr))) && (u6->u6_port == s6->sin6_port)) { cctx->res = s; return GNUNET_NO; } } return GNUNET_YES; } /** * Creates a new outbound session the transport service will use to send data to the * peer * * @param cls the plugin * @param address the address * @return the session or NULL of max connections exceeded */ static struct Session * udp_plugin_get_session (void *cls, const struct GNUNET_HELLO_Address *address) { struct Session * s = NULL; struct Plugin * plugin = cls; struct IPv6UdpAddress * udp_a6; struct IPv4UdpAddress * udp_a4; GNUNET_assert (plugin != NULL); GNUNET_assert (address != NULL); if ((address->address == NULL) || ((address->address_length != sizeof (struct IPv4UdpAddress)) && (address->address_length != sizeof (struct IPv6UdpAddress)))) { GNUNET_break (0); return NULL; } if (address->address_length == sizeof (struct IPv4UdpAddress)) { if (plugin->sockv4 == NULL) return NULL; udp_a4 = (struct IPv4UdpAddress *) address->address; if (udp_a4->u4_port == 0) return NULL; } if (address->address_length == sizeof (struct IPv6UdpAddress)) { if (plugin->sockv6 == NULL) return NULL; udp_a6 = (struct IPv6UdpAddress *) address->address; if (udp_a6->u6_port == 0) return NULL; } /* check if session already exists */ struct SessionCompareContext cctx; cctx.addr = address; cctx.res = NULL; LOG (GNUNET_ERROR_TYPE_DEBUG, "Looking for existing session for peer `%s' `%s' \n", GNUNET_i2s (&address->peer), udp_address_to_string(NULL, address->address, address->address_length)); GNUNET_CONTAINER_multihashmap_get_multiple(plugin->sessions, &address->peer.hashPubKey, session_cmp_it, &cctx); if (cctx.res != NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Found existing session %p\n", cctx.res); return cctx.res; } /* otherwise create new */ s = create_session (plugin, &address->peer, address->address, address->address_length, NULL, NULL); LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating new session %p for peer `%s' address `%s'\n", s, GNUNET_i2s(&address->peer), udp_address_to_string(NULL,address->address,address->address_length)); GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (plugin->sessions, &s->target.hashPubKey, s, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); GNUNET_STATISTICS_set(plugin->env->stats, "# UDP sessions active", GNUNET_CONTAINER_multihashmap_size(plugin->sessions), GNUNET_NO); return s; } static void enqueue (struct Plugin *plugin, struct UDPMessageWrapper * udpw) { if (udpw->session->addrlen == sizeof (struct sockaddr_in)) GNUNET_CONTAINER_DLL_insert(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw); if (udpw->session->addrlen == sizeof (struct sockaddr_in6)) GNUNET_CONTAINER_DLL_insert(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw); } /** * Fragment message was transmitted via UDP, let fragmentation know * to send the next fragment now. * * @param cls the 'struct UDPMessageWrapper' of the fragment * @param target destination peer (ignored) * @param result GNUNET_OK on success (ignored) */ static void send_next_fragment (void *cls, const struct GNUNET_PeerIdentity *target, int result) { struct UDPMessageWrapper *udpw = cls; GNUNET_FRAGMENT_context_transmission_done (udpw->frag_ctx->frag); } /** * Function that is called with messages created by the fragmentation * module. In the case of the 'proc' callback of the * GNUNET_FRAGMENT_context_create function, this function must * eventually call 'GNUNET_FRAGMENT_context_transmission_done'. * * @param cls closure, the 'struct FragmentationContext' * @param msg the message that was created */ static void enqueue_fragment (void *cls, const struct GNUNET_MessageHeader *msg) { struct FragmentationContext *frag_ctx = cls; struct Plugin *plugin = frag_ctx->plugin; struct UDPMessageWrapper * udpw; struct Session *s; size_t msg_len = ntohs (msg->size); LOG (GNUNET_ERROR_TYPE_DEBUG, "Enqueuing fragment with %u bytes %u\n", msg_len , sizeof (struct UDPMessageWrapper)); udpw = GNUNET_malloc (sizeof (struct UDPMessageWrapper) + msg_len); udpw->session = frag_ctx->session; s = udpw->session; udpw->udp = (char *) &udpw[1]; udpw->msg_size = msg_len; udpw->cont = &send_next_fragment; udpw->cont_cls = udpw; udpw->timeout = frag_ctx->timeout; udpw->frag_ctx = frag_ctx; memcpy (udpw->udp, msg, msg_len); enqueue (plugin, udpw); if (s->addrlen == sizeof (struct sockaddr_in)) { if (plugin->with_v4_ws == GNUNET_NO) { if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel(plugin->select_task); plugin->select_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs_v4, plugin->ws_v4, &udp_plugin_select, plugin); plugin->with_v4_ws = GNUNET_YES; } } else if (s->addrlen == sizeof (struct sockaddr_in6)) { if (plugin->with_v6_ws == GNUNET_NO) { if (plugin->select_task_v6 != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel(plugin->select_task_v6); plugin->select_task_v6 = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs_v6, plugin->ws_v6, &udp_plugin_select_v6, plugin); plugin->with_v6_ws = GNUNET_YES; } } } /** * Function that can be used by the transport service to transmit * a message using the plugin. Note that in the case of a * peer disconnecting, the continuation MUST be called * prior to the disconnect notification itself. This function * will be called with this peer's HELLO message to initiate * a fresh connection to another peer. * * @param cls closure * @param s which session must be used * @param msgbuf the message to transmit * @param msgbuf_size number of bytes in 'msgbuf' * @param priority how important is the message (most plugins will * ignore message priority and just FIFO) * @param to how long to wait at most for the transmission (does not * require plugins to discard the message after the timeout, * just advisory for the desired delay; most plugins will ignore * this as well) * @param cont continuation to call once the message has * been transmitted (or if the transport is ready * for the next transmission call; or if the * peer disconnected...); can be NULL * @param cont_cls closure for cont * @return number of bytes used (on the physical network, with overheads); * -1 on hard errors (i.e. address invalid); 0 is a legal value * and does NOT mean that the message was not transmitted (DV) */ static ssize_t udp_plugin_send (void *cls, struct Session *s, const char *msgbuf, size_t msgbuf_size, unsigned int priority, struct GNUNET_TIME_Relative to, GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) { struct Plugin *plugin = cls; size_t mlen = msgbuf_size + sizeof (struct UDPMessage); struct UDPMessageWrapper * udpw; struct UDPMessage *udp; char mbuf[mlen]; GNUNET_assert (plugin != NULL); GNUNET_assert (s != NULL); if ((s->addrlen == sizeof (struct sockaddr_in6)) && (plugin->sockv6 == NULL)) return GNUNET_SYSERR; if ((s->addrlen == sizeof (struct sockaddr_in)) && (plugin->sockv4 == NULL)) return GNUNET_SYSERR; if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); return GNUNET_SYSERR; } if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains_value(plugin->sessions, &s->target.hashPubKey, s)) { GNUNET_break (0); return GNUNET_SYSERR; } LOG (GNUNET_ERROR_TYPE_DEBUG, "UDP transmits %u-byte message to `%s' using address `%s'\n", mlen, GNUNET_i2s (&s->target), GNUNET_a2s(s->sock_addr, s->addrlen)); /* Message */ udp = (struct UDPMessage *) mbuf; udp->header.size = htons (mlen); udp->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_MESSAGE); udp->reserved = htonl (0); udp->sender = *plugin->env->my_identity; reschedule_session_timeout(s); if (mlen <= UDP_MTU) { udpw = GNUNET_malloc (sizeof (struct UDPMessageWrapper) + mlen); udpw->session = s; udpw->udp = (char *) &udpw[1]; udpw->msg_size = mlen; udpw->timeout = GNUNET_TIME_absolute_add(GNUNET_TIME_absolute_get(), to); udpw->cont = cont; udpw->cont_cls = cont_cls; udpw->frag_ctx = NULL; memcpy (udpw->udp, udp, sizeof (struct UDPMessage)); memcpy (&udpw->udp[sizeof (struct UDPMessage)], msgbuf, msgbuf_size); enqueue (plugin, udpw); } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "UDP has to fragment message \n"); if (s->frag_ctx != NULL) return GNUNET_SYSERR; memcpy (&udp[1], msgbuf, msgbuf_size); struct FragmentationContext * frag_ctx = GNUNET_malloc(sizeof (struct FragmentationContext)); frag_ctx->plugin = plugin; frag_ctx->session = s; frag_ctx->cont = cont; frag_ctx->cont_cls = cont_cls; frag_ctx->timeout = GNUNET_TIME_absolute_add(GNUNET_TIME_absolute_get(), to); frag_ctx->bytes_to_send = mlen; frag_ctx->frag = GNUNET_FRAGMENT_context_create (plugin->env->stats, UDP_MTU, &plugin->tracker, s->last_expected_delay, &udp->header, &enqueue_fragment, frag_ctx); s->frag_ctx = frag_ctx; } if (s->addrlen == sizeof (struct sockaddr_in)) { if (plugin->with_v4_ws == GNUNET_NO) { if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel(plugin->select_task); plugin->select_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs_v4, plugin->ws_v4, &udp_plugin_select, plugin); plugin->with_v4_ws = GNUNET_YES; } } else if (s->addrlen == sizeof (struct sockaddr_in6)) { if (plugin->with_v6_ws == GNUNET_NO) { if (plugin->select_task_v6 != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel(plugin->select_task_v6); plugin->select_task_v6 = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs_v6, plugin->ws_v6, &udp_plugin_select_v6, plugin); plugin->with_v6_ws = GNUNET_YES; } } return mlen; } /** * Our external IP address/port mapping has changed. * * @param cls closure, the 'struct LocalAddrList' * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean * the previous (now invalid) one * @param addr either the previous or the new public IP address * @param addrlen actual lenght of the address */ static void udp_nat_port_map_callback (void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen) { struct Plugin *plugin = cls; struct IPv4UdpAddress u4; struct IPv6UdpAddress u6; void *arg; size_t args; /* convert 'addr' to our internal format */ switch (addr->sa_family) { case AF_INET: GNUNET_assert (addrlen == sizeof (struct sockaddr_in)); u4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; u4.u4_port = ((struct sockaddr_in *) addr)->sin_port; arg = &u4; args = sizeof (u4); break; case AF_INET6: GNUNET_assert (addrlen == sizeof (struct sockaddr_in6)); memcpy (&u6.ipv6_addr, &((struct sockaddr_in6 *) addr)->sin6_addr, sizeof (struct in6_addr)); u6.u6_port = ((struct sockaddr_in6 *) addr)->sin6_port; arg = &u6; args = sizeof (u6); break; default: GNUNET_break (0); return; } /* modify our published address list */ plugin->env->notify_address (plugin->env->cls, add_remove, arg, args); } /** * Message tokenizer has broken up an incomming message. Pass it on * to the service. * * @param cls the 'struct Plugin' * @param client the 'struct SourceInformation' * @param hdr the actual message */ static int process_inbound_tokenized_messages (void *cls, void *client, const struct GNUNET_MessageHeader *hdr) { struct Plugin *plugin = cls; struct SourceInformation *si = client; struct GNUNET_ATS_Information ats[2]; struct GNUNET_TIME_Relative delay; GNUNET_assert (si->session != NULL); if (GNUNET_YES == si->session->in_destroy) return GNUNET_OK; /* setup ATS */ ats[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); ats[0].value = htonl (1); ats[1] = si->session->ats; GNUNET_break (ntohl(ats[1].value) != GNUNET_ATS_NET_UNSPECIFIED); delay = plugin->env->receive (plugin->env->cls, &si->sender, hdr, (const struct GNUNET_ATS_Information *) &ats, 2, NULL, si->arg, si->args); si->session->flow_delay_for_other_peer = delay; reschedule_session_timeout(si->session); return GNUNET_OK; } /** * We've received a UDP Message. Process it (pass contents to main service). * * @param plugin plugin context * @param msg the message * @param sender_addr sender address * @param sender_addr_len number of bytes in sender_addr */ static void process_udp_message (struct Plugin *plugin, const struct UDPMessage *msg, const struct sockaddr *sender_addr, socklen_t sender_addr_len) { struct SourceInformation si; struct Session * s; struct IPv4UdpAddress u4; struct IPv6UdpAddress u6; const void *arg; size_t args; if (0 != ntohl (msg->reserved)) { GNUNET_break_op (0); return; } if (ntohs (msg->header.size) < sizeof (struct GNUNET_MessageHeader) + sizeof (struct UDPMessage)) { GNUNET_break_op (0); return; } /* convert address */ switch (sender_addr->sa_family) { case AF_INET: GNUNET_assert (sender_addr_len == sizeof (struct sockaddr_in)); u4.ipv4_addr = ((struct sockaddr_in *) sender_addr)->sin_addr.s_addr; u4.u4_port = ((struct sockaddr_in *) sender_addr)->sin_port; arg = &u4; args = sizeof (u4); break; case AF_INET6: GNUNET_assert (sender_addr_len == sizeof (struct sockaddr_in6)); u6.ipv6_addr = ((struct sockaddr_in6 *) sender_addr)->sin6_addr; u6.u6_port = ((struct sockaddr_in6 *) sender_addr)->sin6_port; arg = &u6; args = sizeof (u6); break; default: GNUNET_break (0); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Received message with %u bytes from peer `%s' at `%s'\n", (unsigned int) ntohs (msg->header.size), GNUNET_i2s (&msg->sender), GNUNET_a2s (sender_addr, sender_addr_len)); struct GNUNET_HELLO_Address * address = GNUNET_HELLO_address_allocate(&msg->sender, "udp", arg, args); s = udp_plugin_get_session(plugin, address); GNUNET_free (address); /* iterate over all embedded messages */ si.session = s; si.sender = msg->sender; si.arg = arg; si.args = args; s->rc++; GNUNET_SERVER_mst_receive (plugin->mst, &si, (const char *) &msg[1], ntohs (msg->header.size) - sizeof (struct UDPMessage), GNUNET_YES, GNUNET_NO); s->rc--; if ( (0 == s->rc) && (GNUNET_YES == s->in_destroy)) free_session (s); } /** * Scan the heap for a receive context with the given address. * * @param cls the 'struct FindReceiveContext' * @param node internal node of the heap * @param element value stored at the node (a 'struct ReceiveContext') * @param cost cost associated with the node * @return GNUNET_YES if we should continue to iterate, * GNUNET_NO if not. */ static int find_receive_context (void *cls, struct GNUNET_CONTAINER_HeapNode *node, void *element, GNUNET_CONTAINER_HeapCostType cost) { struct FindReceiveContext *frc = cls; struct DefragContext *e = element; if ((frc->addr_len == e->addr_len) && (0 == memcmp (frc->addr, e->src_addr, frc->addr_len))) { frc->rc = e; return GNUNET_NO; } return GNUNET_YES; } /** * Process a defragmented message. * * @param cls the 'struct ReceiveContext' * @param msg the message */ static void fragment_msg_proc (void *cls, const struct GNUNET_MessageHeader *msg) { struct DefragContext *rc = cls; if (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_MESSAGE) { GNUNET_break (0); return; } if (ntohs (msg->size) < sizeof (struct UDPMessage)) { GNUNET_break (0); return; } process_udp_message (rc->plugin, (const struct UDPMessage *) msg, rc->src_addr, rc->addr_len); } struct LookupContext { const struct sockaddr * addr; struct Session *res; size_t addrlen; }; static int lookup_session_by_addr_it (void *cls, const GNUNET_HashCode * key, void *value) { struct LookupContext *l_ctx = cls; struct Session * s = value; if ((s->addrlen == l_ctx->addrlen) && (0 == memcmp (s->sock_addr, l_ctx->addr, s->addrlen))) { l_ctx->res = s; return GNUNET_NO; } return GNUNET_YES; } /** * Transmit an acknowledgement. * * @param cls the 'struct ReceiveContext' * @param id message ID (unused) * @param msg ack to transmit */ static void ack_proc (void *cls, uint32_t id, const struct GNUNET_MessageHeader *msg) { struct DefragContext *rc = cls; size_t msize = sizeof (struct UDP_ACK_Message) + ntohs (msg->size); struct UDP_ACK_Message *udp_ack; uint32_t delay = 0; struct UDPMessageWrapper *udpw; struct Session *s; struct LookupContext l_ctx; l_ctx.addr = rc->src_addr; l_ctx.addrlen = rc->addr_len; l_ctx.res = NULL; GNUNET_CONTAINER_multihashmap_iterate (rc->plugin->sessions, &lookup_session_by_addr_it, &l_ctx); s = l_ctx.res; if (NULL == s) return; if (s->flow_delay_for_other_peer.rel_value <= UINT32_MAX) delay = s->flow_delay_for_other_peer.rel_value; LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending ACK to `%s' including delay of %u ms\n", GNUNET_a2s (rc->src_addr, (rc->src_addr->sa_family == AF_INET) ? sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6)), delay); udpw = GNUNET_malloc (sizeof (struct UDPMessageWrapper) + msize); udpw->msg_size = msize; udpw->session = s; udpw->timeout = GNUNET_TIME_UNIT_FOREVER_ABS; udpw->udp = (char *)&udpw[1]; udp_ack = (struct UDP_ACK_Message *) udpw->udp; udp_ack->header.size = htons ((uint16_t) msize); udp_ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_ACK); udp_ack->delay = htonl (delay); udp_ack->sender = *rc->plugin->env->my_identity; memcpy (&udp_ack[1], msg, ntohs (msg->size)); enqueue (rc->plugin, udpw); } static void read_process_msg (struct Plugin *plugin, const struct GNUNET_MessageHeader *msg, const char *addr, socklen_t fromlen) { if (ntohs (msg->size) < sizeof (struct UDPMessage)) { GNUNET_break_op (0); return; } process_udp_message (plugin, (const struct UDPMessage *) msg, (const struct sockaddr *) addr, fromlen); } static void read_process_ack (struct Plugin *plugin, const struct GNUNET_MessageHeader *msg, char *addr, socklen_t fromlen) { const struct GNUNET_MessageHeader *ack; const struct UDP_ACK_Message *udp_ack; struct LookupContext l_ctx; struct Session *s; struct GNUNET_TIME_Relative flow_delay; if (ntohs (msg->size) < sizeof (struct UDP_ACK_Message) + sizeof (struct GNUNET_MessageHeader)) { GNUNET_break_op (0); return; } udp_ack = (const struct UDP_ACK_Message *) msg; l_ctx.addr = (const struct sockaddr *) addr; l_ctx.addrlen = fromlen; l_ctx.res = NULL; GNUNET_CONTAINER_multihashmap_iterate (plugin->sessions, &lookup_session_by_addr_it, &l_ctx); s = l_ctx.res; if ((s == NULL) || (s->frag_ctx == NULL)) return; flow_delay.rel_value = (uint64_t) ntohl (udp_ack->delay); LOG (GNUNET_ERROR_TYPE_DEBUG, "We received a sending delay of %llu\n", flow_delay.rel_value); s->flow_delay_from_other_peer = GNUNET_TIME_relative_to_absolute (flow_delay); ack = (const struct GNUNET_MessageHeader *) &udp_ack[1]; if (ntohs (ack->size) != ntohs (msg->size) - sizeof (struct UDP_ACK_Message)) { GNUNET_break_op (0); return; } if (GNUNET_OK != GNUNET_FRAGMENT_process_ack (s->frag_ctx->frag, ack)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "UDP processes %u-byte acknowledgement from `%s' at `%s'\n", (unsigned int) ntohs (msg->size), GNUNET_i2s (&udp_ack->sender), GNUNET_a2s ((const struct sockaddr *) addr, fromlen)); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "FULL MESSAGE ACKed\n", (unsigned int) ntohs (msg->size), GNUNET_i2s (&udp_ack->sender), GNUNET_a2s ((const struct sockaddr *) addr, fromlen)); s->last_expected_delay = GNUNET_FRAGMENT_context_destroy (s->frag_ctx->frag); struct UDPMessageWrapper * udpw; struct UDPMessageWrapper * tmp; if (s->addrlen == sizeof (struct sockaddr_in6)) { udpw = plugin->ipv6_queue_head; while (NULL != udpw) { tmp = udpw->next; if ((udpw->frag_ctx != NULL) && (udpw->frag_ctx == s->frag_ctx)) { GNUNET_CONTAINER_DLL_remove(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw); GNUNET_free (udpw); } udpw = tmp; } } if (s->addrlen == sizeof (struct sockaddr_in)) { udpw = plugin->ipv4_queue_head; while (udpw!= NULL) { tmp = udpw->next; if ((udpw->frag_ctx != NULL) && (udpw->frag_ctx == s->frag_ctx)) { GNUNET_CONTAINER_DLL_remove(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw); GNUNET_free (udpw); } udpw = tmp; } } if (s->frag_ctx->cont != NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Calling continuation for fragmented message to `%s' with result %s\n", GNUNET_i2s (&s->target), "OK"); s->frag_ctx->cont (s->frag_ctx->cont_cls, &udp_ack->sender, GNUNET_OK); } GNUNET_free (s->frag_ctx); s->frag_ctx = NULL; } static void read_process_fragment (struct Plugin *plugin, const struct GNUNET_MessageHeader *msg, char *addr, socklen_t fromlen) { struct DefragContext *d_ctx; struct GNUNET_TIME_Absolute now; struct FindReceiveContext frc; frc.rc = NULL; frc.addr = (const struct sockaddr *) addr; frc.addr_len = fromlen; LOG (GNUNET_ERROR_TYPE_DEBUG, "UDP processes %u-byte fragment from `%s'\n", (unsigned int) ntohs (msg->size), GNUNET_a2s ((const struct sockaddr *) addr, fromlen)); /* Lookup existing receive context for this address */ GNUNET_CONTAINER_heap_iterate (plugin->defrag_ctxs, &find_receive_context, &frc); now = GNUNET_TIME_absolute_get (); d_ctx = frc.rc; if (d_ctx == NULL) { /* Create a new defragmentation context */ d_ctx = GNUNET_malloc (sizeof (struct DefragContext) + fromlen); memcpy (&d_ctx[1], addr, fromlen); d_ctx->src_addr = (const struct sockaddr *) &d_ctx[1]; d_ctx->addr_len = fromlen; d_ctx->plugin = plugin; d_ctx->defrag = GNUNET_DEFRAGMENT_context_create (plugin->env->stats, UDP_MTU, UDP_MAX_MESSAGES_IN_DEFRAG, d_ctx, &fragment_msg_proc, &ack_proc); d_ctx->hnode = GNUNET_CONTAINER_heap_insert (plugin->defrag_ctxs, d_ctx, (GNUNET_CONTAINER_HeapCostType) now.abs_value); LOG (GNUNET_ERROR_TYPE_DEBUG, "Created new defragmentation context for %u-byte fragment from `%s'\n", (unsigned int) ntohs (msg->size), GNUNET_a2s ((const struct sockaddr *) addr, fromlen)); } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "Found existing defragmentation context for %u-byte fragment from `%s'\n", (unsigned int) ntohs (msg->size), GNUNET_a2s ((const struct sockaddr *) addr, fromlen)); } if (GNUNET_OK == GNUNET_DEFRAGMENT_process_fragment (d_ctx->defrag, msg)) { /* keep this 'rc' from expiring */ GNUNET_CONTAINER_heap_update_cost (plugin->defrag_ctxs, d_ctx->hnode, (GNUNET_CONTAINER_HeapCostType) now.abs_value); } if (GNUNET_CONTAINER_heap_get_size (plugin->defrag_ctxs) > UDP_MAX_SENDER_ADDRESSES_WITH_DEFRAG) { /* remove 'rc' that was inactive the longest */ d_ctx = GNUNET_CONTAINER_heap_remove_root (plugin->defrag_ctxs); GNUNET_assert (NULL != d_ctx); GNUNET_DEFRAGMENT_context_destroy (d_ctx->defrag); GNUNET_free (d_ctx); } } /** * Read and process a message from the given socket. * * @param plugin the overall plugin * @param rsock socket to read from */ static void udp_select_read (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *rsock) { socklen_t fromlen; char addr[32]; char buf[65536] GNUNET_ALIGN; ssize_t size; const struct GNUNET_MessageHeader *msg; fromlen = sizeof (addr); memset (&addr, 0, sizeof (addr)); size = GNUNET_NETWORK_socket_recvfrom (rsock, buf, sizeof (buf), (struct sockaddr *) &addr, &fromlen); if (size < sizeof (struct GNUNET_MessageHeader)) { GNUNET_break_op (0); return; } msg = (const struct GNUNET_MessageHeader *) buf; LOG (GNUNET_ERROR_TYPE_DEBUG, "UDP received %u-byte message from `%s' type %i\n", (unsigned int) size, GNUNET_a2s ((const struct sockaddr *) addr, fromlen), ntohs (msg->type)); if (size != ntohs (msg->size)) { GNUNET_break_op (0); return; } switch (ntohs (msg->type)) { case GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON: udp_broadcast_receive (plugin, &buf, size, addr, fromlen); return; case GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_MESSAGE: read_process_msg (plugin, msg, addr, fromlen); return; case GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_ACK: read_process_ack (plugin, msg, addr, fromlen); return; case GNUNET_MESSAGE_TYPE_FRAGMENT: read_process_fragment (plugin, msg, addr, fromlen); return; default: GNUNET_break_op (0); return; } } static size_t udp_select_send (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *sock) { ssize_t sent; size_t slen; struct GNUNET_TIME_Absolute max; struct UDPMessageWrapper *udpw = NULL; if (sock == plugin->sockv4) { udpw = plugin->ipv4_queue_head; } else if (sock == plugin->sockv6) { udpw = plugin->ipv6_queue_head; } else { GNUNET_break (0); return 0; } const struct sockaddr * sa = udpw->session->sock_addr; slen = udpw->session->addrlen; max = GNUNET_TIME_absolute_max(udpw->timeout, GNUNET_TIME_absolute_get()); while (udpw != NULL) { if (max.abs_value != udpw->timeout.abs_value) { /* Message timed out */ call_continuation(udpw, GNUNET_SYSERR); if (udpw->frag_ctx != NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Fragmented message for peer `%s' with size %u timed out\n", GNUNET_i2s(&udpw->session->target), udpw->frag_ctx->bytes_to_send); udpw->session->last_expected_delay = GNUNET_FRAGMENT_context_destroy(udpw->frag_ctx->frag); GNUNET_free (udpw->frag_ctx); udpw->session->frag_ctx = NULL; } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "Message for peer `%s' with size %u timed out\n", GNUNET_i2s(&udpw->session->target), udpw->msg_size); } if (sock == plugin->sockv4) { GNUNET_CONTAINER_DLL_remove(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw); GNUNET_free (udpw); udpw = plugin->ipv4_queue_head; } else if (sock == plugin->sockv6) { GNUNET_CONTAINER_DLL_remove(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw); GNUNET_free (udpw); udpw = plugin->ipv6_queue_head; } } else { struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_remaining (udpw->session->flow_delay_from_other_peer); if (delta.rel_value == 0) { /* this message is not delayed */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Message for peer `%s' (%u bytes) is not delayed \n", GNUNET_i2s(&udpw->session->target), udpw->msg_size); break; } else { /* this message is delayed, try next */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Message for peer `%s' (%u bytes) is delayed for %llu \n", GNUNET_i2s(&udpw->session->target), udpw->msg_size, delta); udpw = udpw->next; } } } if (udpw == NULL) { /* No message left */ return 0; } sent = GNUNET_NETWORK_socket_sendto (sock, udpw->udp, udpw->msg_size, sa, slen); if (GNUNET_SYSERR == sent) { const struct GNUNET_ATS_Information type = plugin->env->get_address_type (plugin->env->cls,sa, slen); if ((GNUNET_ATS_NET_WAN == type.value) && ((ENETUNREACH == errno) || (ENETDOWN == errno))) { /* "Network unreachable" or "Network down" */ /* * This indicates that this system is IPv6 enabled, but does not * have a valid global IPv6 address assigned */ LOG (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, _("UDP could not message to `%s': `%s'. " "Please check your network configuration and disable IPv6 if your " "connection does not have a global IPv6 address\n"), GNUNET_a2s (sa, slen), STRERROR (errno)); } else { LOG (GNUNET_ERROR_TYPE_ERROR, "UDP could not transmit %u-byte message to `%s': `%s'\n", (unsigned int) (udpw->msg_size), GNUNET_a2s (sa, slen), STRERROR (errno)); } call_continuation(udpw, GNUNET_SYSERR); } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "UDP transmitted %u-byte message to `%s' (%d: %s)\n", (unsigned int) (udpw->msg_size), GNUNET_a2s (sa, slen), (int) sent, (sent < 0) ? STRERROR (errno) : "ok"); call_continuation(udpw, GNUNET_OK); } if (sock == plugin->sockv4) GNUNET_CONTAINER_DLL_remove(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw); else if (sock == plugin->sockv6) GNUNET_CONTAINER_DLL_remove(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw); GNUNET_free (udpw); udpw = NULL; return sent; } /** * We have been notified that our readset has something to read. We don't * know which socket needs to be read, so we have to check each one * Then reschedule this function to be called again once more is available. * * @param cls the plugin handle * @param tc the scheduling context (for rescheduling this function again) */ static void udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Plugin *plugin = cls; plugin->select_task = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; plugin->with_v4_ws = GNUNET_NO; if ((tc->reason & GNUNET_SCHEDULER_REASON_READ_READY) != 0) { if ((NULL != plugin->sockv4) && (GNUNET_NETWORK_fdset_isset (tc->read_ready, plugin->sockv4))) udp_select_read (plugin, plugin->sockv4); } if ((tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) != 0) { if ((NULL != plugin->sockv4) && (plugin->ipv4_queue_head != NULL) && (GNUNET_NETWORK_fdset_isset (tc->write_ready, plugin->sockv4))) { udp_select_send (plugin, plugin->sockv4); } } if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (plugin->select_task); plugin->select_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs_v4, (plugin->ipv4_queue_head != NULL) ? plugin->ws_v4 : NULL, &udp_plugin_select, plugin); if (plugin->ipv4_queue_head != NULL) plugin->with_v4_ws = GNUNET_YES; else plugin->with_v4_ws = GNUNET_NO; } /** * We have been notified that our readset has something to read. We don't * know which socket needs to be read, so we have to check each one * Then reschedule this function to be called again once more is available. * * @param cls the plugin handle * @param tc the scheduling context (for rescheduling this function again) */ static void udp_plugin_select_v6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Plugin *plugin = cls; plugin->select_task_v6 = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; plugin->with_v6_ws = GNUNET_NO; if ((tc->reason & GNUNET_SCHEDULER_REASON_READ_READY) != 0) { if ((NULL != plugin->sockv6) && (GNUNET_NETWORK_fdset_isset (tc->read_ready, plugin->sockv6))) udp_select_read (plugin, plugin->sockv6); } if ((tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) != 0) { if ((NULL != plugin->sockv6) && (plugin->ipv6_queue_head != NULL) && (GNUNET_NETWORK_fdset_isset (tc->write_ready, plugin->sockv6))) { udp_select_send (plugin, plugin->sockv6); } } if (plugin->select_task_v6 != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (plugin->select_task_v6); plugin->select_task_v6 = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs_v6, (plugin->ipv6_queue_head != NULL) ? plugin->ws_v6 : NULL, &udp_plugin_select_v6, plugin); if (plugin->ipv6_queue_head != NULL) plugin->with_v6_ws = GNUNET_YES; else plugin->with_v6_ws = GNUNET_NO; } static int setup_sockets (struct Plugin *plugin, struct sockaddr_in6 *serverAddrv6, struct sockaddr_in *serverAddrv4) { int tries; int sockets_created = 0; struct sockaddr *serverAddr; struct sockaddr *addrs[2]; socklen_t addrlens[2]; socklen_t addrlen; /* Create IPv6 socket */ if (plugin->enable_ipv6 == GNUNET_YES) { plugin->sockv6 = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_DGRAM, 0); if (NULL == plugin->sockv6) { LOG (GNUNET_ERROR_TYPE_WARNING, "Disabling IPv6 since it is not supported on this system!\n"); plugin->enable_ipv6 = GNUNET_NO; } else { #if HAVE_SOCKADDR_IN_SIN_LEN serverAddrv6->sin6_len = sizeof (serverAddrv6); #endif serverAddrv6->sin6_family = AF_INET6; serverAddrv6->sin6_addr = in6addr_any; serverAddrv6->sin6_port = htons (plugin->port); addrlen = sizeof (struct sockaddr_in6); serverAddr = (struct sockaddr *) serverAddrv6; LOG (GNUNET_ERROR_TYPE_DEBUG, "Binding to IPv6 port %d\n", ntohs (serverAddrv6->sin6_port)); tries = 0; while (GNUNET_NETWORK_socket_bind (plugin->sockv6, serverAddr, addrlen) != GNUNET_OK) { serverAddrv6->sin6_port = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 33537) + 32000); /* Find a good, non-root port */ LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv6 Binding failed, trying new port %d\n", ntohs (serverAddrv6->sin6_port)); tries++; if (tries > 10) { GNUNET_NETWORK_socket_close (plugin->sockv6); plugin->sockv6 = NULL; break; } } if (plugin->sockv6 != NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv6 socket created on port %d\n", ntohs (serverAddrv6->sin6_port)); addrs[sockets_created] = (struct sockaddr *) serverAddrv6; addrlens[sockets_created] = sizeof (struct sockaddr_in6); sockets_created++; } } } /* Create IPv4 socket */ plugin->sockv4 = GNUNET_NETWORK_socket_create (PF_INET, SOCK_DGRAM, 0); if (NULL == plugin->sockv4) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket"); } else { #if HAVE_SOCKADDR_IN_SIN_LEN serverAddrv4->sin_len = sizeof (serverAddrv4); #endif serverAddrv4->sin_family = AF_INET; serverAddrv4->sin_addr.s_addr = INADDR_ANY; serverAddrv4->sin_port = htons (plugin->port); addrlen = sizeof (struct sockaddr_in); serverAddr = (struct sockaddr *) serverAddrv4; LOG (GNUNET_ERROR_TYPE_DEBUG, "Binding to IPv4 port %d\n", ntohs (serverAddrv4->sin_port)); tries = 0; while (GNUNET_NETWORK_socket_bind (plugin->sockv4, serverAddr, addrlen) != GNUNET_OK) { serverAddrv4->sin_port = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 33537) + 32000); /* Find a good, non-root port */ LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv4 Binding failed, trying new port %d\n", ntohs (serverAddrv4->sin_port)); tries++; if (tries > 10) { GNUNET_NETWORK_socket_close (plugin->sockv4); plugin->sockv4 = NULL; break; } } if (plugin->sockv4 != NULL) { addrs[sockets_created] = (struct sockaddr *) serverAddrv4; addrlens[sockets_created] = sizeof (struct sockaddr_in); sockets_created++; } } /* Create file descriptors */ plugin->rs_v4 = GNUNET_NETWORK_fdset_create (); plugin->ws_v4 = GNUNET_NETWORK_fdset_create (); GNUNET_NETWORK_fdset_zero (plugin->rs_v4); GNUNET_NETWORK_fdset_zero (plugin->ws_v4); if (NULL != plugin->sockv4) { GNUNET_NETWORK_fdset_set (plugin->rs_v4, plugin->sockv4); GNUNET_NETWORK_fdset_set (plugin->ws_v4, plugin->sockv4); } if (sockets_created == 0) LOG (GNUNET_ERROR_TYPE_WARNING, _("Failed to open UDP sockets\n")); plugin->select_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs_v4, NULL, &udp_plugin_select, plugin); plugin->with_v4_ws = GNUNET_NO; if (plugin->enable_ipv6 == GNUNET_YES) { plugin->rs_v6 = GNUNET_NETWORK_fdset_create (); plugin->ws_v6 = GNUNET_NETWORK_fdset_create (); GNUNET_NETWORK_fdset_zero (plugin->rs_v6); GNUNET_NETWORK_fdset_zero (plugin->ws_v6); if (NULL != plugin->sockv6) { GNUNET_NETWORK_fdset_set (plugin->rs_v6, plugin->sockv6); GNUNET_NETWORK_fdset_set (plugin->ws_v6, plugin->sockv6); } plugin->select_task_v6 = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs_v6, NULL, &udp_plugin_select_v6, plugin); plugin->with_v6_ws = GNUNET_NO; } plugin->nat = GNUNET_NAT_register (plugin->env->cfg, GNUNET_NO, plugin->port, sockets_created, (const struct sockaddr **) addrs, addrlens, &udp_nat_port_map_callback, NULL, plugin); return sockets_created; } /** * Session was idle, so disconnect it */ static void session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_assert (NULL != cls); struct Session *s = cls; s->timeout_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Session %p was idle for %llu, disconnecting\n", s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); /* call session destroy function */ disconnect_session(s); } /** * Start session timeout */ static void start_session_timeout (struct Session *s) { GNUNET_assert (NULL != s); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == s->timeout_task); s->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, &session_timeout, s); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout for session %p set to %llu\n", s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); } /** * Increment session timeout due to activity */ static void reschedule_session_timeout (struct Session *s) { GNUNET_assert (NULL != s); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task); GNUNET_SCHEDULER_cancel (s->timeout_task); s->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, &session_timeout, s); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout rescheduled for session %p set to %llu\n", s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); } /** * Cancel timeout */ static void stop_session_timeout (struct Session *s) { GNUNET_assert (NULL != s); if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task) { GNUNET_SCHEDULER_cancel (s->timeout_task); s->timeout_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout rescheduled for session %p canceled\n", s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout for session %p was not active\n", s); } } /** * The exported method. Makes the core api available via a global and * returns the udp transport API. * * @param cls our 'struct GNUNET_TRANSPORT_PluginEnvironment' * @return our 'struct GNUNET_TRANSPORT_PluginFunctions' */ void * libgnunet_plugin_transport_udp_init (void *cls) { struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; struct GNUNET_TRANSPORT_PluginFunctions *api; struct Plugin *p; unsigned long long port; unsigned long long aport; unsigned long long broadcast; unsigned long long udp_max_bps; unsigned long long enable_v6; char * bind4_address; char * bind6_address; struct GNUNET_TIME_Relative interval; struct sockaddr_in serverAddrv4; struct sockaddr_in6 serverAddrv6; int res; if (NULL == env->receive) { /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully initialze the plugin or the API */ api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); api->cls = NULL; api->address_pretty_printer = &udp_plugin_address_pretty_printer; api->address_to_string = &udp_address_to_string; api->string_to_address = &udp_string_to_address; return api; } GNUNET_assert( NULL != env->stats); /* Get port number */ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-udp", "PORT", &port)) port = 2086; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-udp", "ADVERTISED_PORT", &aport)) aport = port; if (port > 65535) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Given `%s' option is out of range: %llu > %u\n"), "PORT", port, 65535); return NULL; } /* Protocols */ if ((GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (env->cfg, "nat", "DISABLEV6"))) { enable_v6 = GNUNET_NO; } else enable_v6 = GNUNET_YES; /* Addresses */ memset (&serverAddrv6, 0, sizeof (serverAddrv6)); memset (&serverAddrv4, 0, sizeof (serverAddrv4)); if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (env->cfg, "transport-udp", "BINDTO", &bind4_address)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Binding udp plugin to specific address: `%s'\n", bind4_address); if (1 != inet_pton (AF_INET, bind4_address, &serverAddrv4.sin_addr)) { GNUNET_free (bind4_address); return NULL; } } if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (env->cfg, "transport-udp", "BINDTO6", &bind6_address)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Binding udp plugin to specific address: `%s'\n", bind6_address); if (1 != inet_pton (AF_INET6, bind6_address, &serverAddrv6.sin6_addr)) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid IPv6 address: `%s'\n"), bind6_address); GNUNET_free_non_null (bind4_address); GNUNET_free (bind6_address); return NULL; } } /* Enable neighbour discovery */ broadcast = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, "transport-udp", "BROADCAST"); if (broadcast == GNUNET_SYSERR) broadcast = GNUNET_NO; if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (env->cfg, "transport-udp", "BROADCAST_INTERVAL", &interval)) { interval = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10); } /* Maximum datarate */ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-udp", "MAX_BPS", &udp_max_bps)) { udp_max_bps = 1024 * 1024 * 50; /* 50 MB/s == infinity for practical purposes */ } p = GNUNET_malloc (sizeof (struct Plugin)); api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); GNUNET_BANDWIDTH_tracker_init (&p->tracker, GNUNET_BANDWIDTH_value_init ((uint32_t)udp_max_bps), 30); p->sessions = GNUNET_CONTAINER_multihashmap_create (10); p->defrag_ctxs = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); p->mst = GNUNET_SERVER_mst_create (&process_inbound_tokenized_messages, p); p->port = port; p->aport = aport; p->broadcast_interval = interval; p->enable_ipv6 = enable_v6; p->env = env; plugin = p; api->cls = p; api->send = NULL; api->disconnect = &udp_disconnect; api->address_pretty_printer = &udp_plugin_address_pretty_printer; api->address_to_string = &udp_address_to_string; api->string_to_address = &udp_string_to_address; api->check_address = &udp_plugin_check_address; api->get_session = &udp_plugin_get_session; api->send = &udp_plugin_send; LOG (GNUNET_ERROR_TYPE_DEBUG, "Setting up sockets\n"); res = setup_sockets (p, &serverAddrv6, &serverAddrv4); if ((res == 0) || ((p->sockv4 == NULL) && (p->sockv6 == NULL))) { LOG (GNUNET_ERROR_TYPE_ERROR, "Failed to create network sockets, plugin failed\n"); GNUNET_free (p); GNUNET_free (api); return NULL; } if (broadcast == GNUNET_YES) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting broadcasting\n"); setup_broadcast (p, &serverAddrv6, &serverAddrv4); } GNUNET_free_non_null (bind4_address); GNUNET_free_non_null (bind6_address); return api; } static int heap_cleanup_iterator (void *cls, struct GNUNET_CONTAINER_HeapNode * node, void *element, GNUNET_CONTAINER_HeapCostType cost) { struct DefragContext * d_ctx = element; GNUNET_CONTAINER_heap_remove_node (node); GNUNET_DEFRAGMENT_context_destroy(d_ctx->defrag); GNUNET_free (d_ctx); return GNUNET_YES; } /** * The exported method. Makes the core api available via a global and * returns the udp transport API. * * @param cls our 'struct GNUNET_TRANSPORT_PluginEnvironment' * @return NULL */ void * libgnunet_plugin_transport_udp_done (void *cls) { struct GNUNET_TRANSPORT_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; if (NULL == plugin) { GNUNET_free (api); return NULL; } stop_broadcast (plugin); if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (plugin->select_task); plugin->select_task = GNUNET_SCHEDULER_NO_TASK; } if (plugin->select_task_v6 != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (plugin->select_task_v6); plugin->select_task_v6 = GNUNET_SCHEDULER_NO_TASK; } /* Closing sockets */ if (plugin->sockv4 != NULL) { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (plugin->sockv4)); plugin->sockv4 = NULL; } GNUNET_NETWORK_fdset_destroy (plugin->rs_v4); GNUNET_NETWORK_fdset_destroy (plugin->ws_v4); if (plugin->sockv6 != NULL) { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (plugin->sockv6)); plugin->sockv6 = NULL; GNUNET_NETWORK_fdset_destroy (plugin->rs_v6); GNUNET_NETWORK_fdset_destroy (plugin->ws_v6); } GNUNET_NAT_unregister (plugin->nat); if (plugin->defrag_ctxs != NULL) { GNUNET_CONTAINER_heap_iterate(plugin->defrag_ctxs, heap_cleanup_iterator, NULL); GNUNET_CONTAINER_heap_destroy(plugin->defrag_ctxs); plugin->defrag_ctxs = NULL; } if (plugin->mst != NULL) { GNUNET_SERVER_mst_destroy(plugin->mst); plugin->mst = NULL; } /* Clean up leftover messages */ struct UDPMessageWrapper * udpw; udpw = plugin->ipv4_queue_head; while (udpw != NULL) { struct UDPMessageWrapper *tmp = udpw->next; GNUNET_CONTAINER_DLL_remove(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw); call_continuation(udpw, GNUNET_SYSERR); GNUNET_free (udpw); udpw = tmp; } udpw = plugin->ipv6_queue_head; while (udpw != NULL) { struct UDPMessageWrapper *tmp = udpw->next; GNUNET_CONTAINER_DLL_remove(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw); call_continuation(udpw, GNUNET_SYSERR); GNUNET_free (udpw); udpw = tmp; } /* Clean up sessions */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up sessions\n"); GNUNET_CONTAINER_multihashmap_iterate (plugin->sessions, &disconnect_and_free_it, plugin); GNUNET_CONTAINER_multihashmap_destroy (plugin->sessions); plugin->nat = NULL; GNUNET_free (plugin); GNUNET_free (api); return NULL; } /* end of plugin_transport_udp.c */ gnunet-0.9.3/src/transport/test_transport_api_https_nat_peer1.conf0000644000175000017500000000121411661530125022540 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-https-p1/ DEFAULTCONFIG = test_transport_api_https_nat_peer1.conf [nat] BEHIND_NAT = YES ENABLE_NAT_SERVER = YES [transport-https] PORT = 0 KEY_FILE = $SERVICEHOME/https_key_p1.key CERT_FILE = $SERVICEHOME/https_cert_p1.crt [arm] PORT = 12105 [statistics] PORT = 12104 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12103 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12102 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12101 PLUGINS = https UNIXPATH = /tmp/gnunet-p1-service-transport.sock DEBUG = NO gnunet-0.9.3/src/transport/test_transport_api_restart_1peer.c0000644000175000017500000003147411760502551021532 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/test_transport_api_restart_1peer.c * @brief base test case for transport implementations * * This test case starts 2 peers, connects and exchanges a message * 1 peer is restarted and tested if peers reconnect * C code apparently. */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_hello_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_transport_service.h" #include "transport.h" #include "transport-testing.h" #define START_ARM GNUNET_YES /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) /** * How long until we give up on transmitting the message? */ #define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) #define MTYPE 12345 static char *test_name; static int ok; static GNUNET_SCHEDULER_TaskIdentifier die_task; static GNUNET_SCHEDULER_TaskIdentifier send_task; static GNUNET_SCHEDULER_TaskIdentifier reconnect_task; static struct PeerContext *p1; static int p1_connected; static struct PeerContext *p2; static int p2_connected; static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; static struct GNUNET_TRANSPORT_TransmitHandle *th; static struct GNUNET_TRANSPORT_TESTING_handle *tth; static char *cfg_file_p1; static char *cfg_file_p2; static int restarted; static void end () { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); if (send_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (send_task); send_task = GNUNET_SCHEDULER_NO_TASK; if (reconnect_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (reconnect_task); reconnect_task = GNUNET_SCHEDULER_NO_TASK; if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); p1 = NULL; GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); p2 = NULL; } static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { die_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); if (restarted == GNUNET_YES) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peer was restarted\n"); if (restarted == GNUNET_NO) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peer was NOT restarted\n"); if (reconnect_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (reconnect_task); reconnect_task = GNUNET_SCHEDULER_NO_TASK; if (send_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (send_task); send_task = GNUNET_SCHEDULER_NO_TASK; if (cc != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n")); GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); cc = NULL; } if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; if (p1 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); if (p2 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); ok = GNUNET_SYSERR; } static void reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerContext *p = cls; reconnect_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_TRANSPORT_try_connect (p->th, &p2->id); reconnect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect, p); } static void restart_cb (struct PeerContext *p, void *cls) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Restarted peer %u (`%4s'), issuing reconnect\n", p->no, GNUNET_i2s (&p->id)); reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, p); } static void restart (struct PeerContext *p, char *cfg_file) { GNUNET_assert (p != NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Restarting peer %u (`%4s')\n", p->no, GNUNET_i2s (&p->id)); GNUNET_TRANSPORT_TESTING_restart_peer (tth, p, cfg_file, &restart_cb, p); return; } static void notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { struct PeerContext *p = cls; struct PeerContext *t = NULL; if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) t = p1; if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) t = p2; GNUNET_assert (t != NULL); char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') received message of type %d and size %u size from peer %u (`%4s')!\n", p->no, ps, ntohs (message->type), ntohs (message->size), t->no, GNUNET_i2s (&t->id)); GNUNET_free (ps); if ((MTYPE == ntohs (message->type)) && (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size))) { if (restarted == GNUNET_NO) { restarted = GNUNET_YES; restart (p1, cfg_file_p1); return; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Restarted peers connected and message was sent, stopping test...\n"); ok = 0; end (); } } else { GNUNET_break (0); ok = 1; if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); } } static size_t notify_ready (void *cls, size_t size, void *buf) { struct PeerContext *p = cls; struct GNUNET_MessageHeader *hdr; th = NULL; if (buf == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout occurred while waiting for transmit_ready\n"); if (GNUNET_SCHEDULER_NO_TASK != die_task) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); ok = 42; return 0; } GNUNET_assert (size >= 256); if (buf != NULL) { hdr = buf; hdr->size = htons (sizeof (struct GNUNET_MessageHeader)); hdr->type = htons (MTYPE); } char *ps = GNUNET_strdup (GNUNET_i2s (&p2->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') sending message with type %u and size %u bytes to peer %u (`%4s')\n", p2->no, ps, ntohs (hdr->type), ntohs (hdr->size), p->no, GNUNET_i2s (&p->id)); GNUNET_free (ps); return sizeof (struct GNUNET_MessageHeader); } static void sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { send_task = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; char *receiver_s = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message from peer %u (`%4s') -> peer %u (`%s') !\n", p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s); GNUNET_free (receiver_s); th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, 256, 0, TIMEOUT_TRANSMIT, ¬ify_ready, p1); } static void notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { static int c; c++; struct PeerContext *p = cls; struct PeerContext *t = NULL; if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) { p1_connected = GNUNET_YES; t = p1; } if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) { p2_connected = GNUNET_YES; t = p2; } GNUNET_assert (t != NULL); char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s'): peer %u (`%s') connected to me!\n", p->no, ps, t->no, GNUNET_i2s (peer)); GNUNET_free (ps); if ((restarted == GNUNET_YES) && ((p1_connected == GNUNET_YES) && (p2_connected == GNUNET_YES))) { /* Peer was restarted and we received 3 connect messages (2 from first connect, 1 from reconnect) */ send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL); } } static void notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { struct PeerContext *p = cls; if ( (NULL != p1) && (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity)))) { p1_connected = GNUNET_NO; } if ( (NULL != p2) && (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity)))) { p2_connected = GNUNET_NO; } char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s'): peer (`%s') disconnected from me!\n", p->no, ps, GNUNET_i2s (peer)); GNUNET_free (ps); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; if (GNUNET_SCHEDULER_NO_TASK != send_task) GNUNET_SCHEDULER_cancel (send_task); send_task = GNUNET_SCHEDULER_NO_TASK; } static void testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) { cc = NULL; char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n", p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id)); GNUNET_free (p1_c); send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL); } static void start_cb (struct PeerContext *p, void *cls) { static int started; started++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, GNUNET_i2s (&p->id)); if (started != 2) return; char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n", p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id)); GNUNET_free (sender_c); cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); p1_connected = GNUNET_NO; p2_connected = GNUNET_NO; p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); if ((p1 == NULL) || (p2 == NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } } static int check () { static char *const argv[] = { "test-transport-api", "-c", "test_transport_api_data.conf", NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; #if WRITECONFIG setTransportOptions ("test_transport_api_data.conf"); #endif send_task = GNUNET_SCHEDULER_NO_TASK; ok = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name, "nohelp", options, &run, &ok); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); GNUNET_log_setup (test_name, "WARNING", NULL); tth = GNUNET_TRANSPORT_TESTING_init (); GNUNET_asprintf (&cfg_file_p1, "test_transport_api_tcp_peer1.conf"); GNUNET_asprintf (&cfg_file_p2, "test_transport_api_tcp_peer2.conf"); ret = check (); GNUNET_free (cfg_file_p1); GNUNET_free (cfg_file_p2); GNUNET_free (test_name); GNUNET_TRANSPORT_TESTING_done (tth); return ret; } /* end of test_transport_api_restart_1peer.c */ gnunet-0.9.3/src/transport/test_transport_api.c0000644000175000017500000002676411761756177016720 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/test_transport_api.c * @brief base test case for transport implementations * * This test case serves as a base for tcp, udp, and udp-nat * transport test cases. Based on the executable being run * the correct test case will be performed. Conservation of * C code apparently. */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_hello_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_transport_service.h" #include "transport.h" #include "transport-testing.h" #define START_ARM GNUNET_YES /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) /** * How long until we give up on transmitting the message? */ #define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) #define TEST_MESSAGE_SIZE 2600 #define TEST_MESSAGE_TYPE 12345 static char *test_source; static char *test_plugin; static char *test_name; static int ok; static int s_started; static int s_connected; static int s_sending; static GNUNET_SCHEDULER_TaskIdentifier die_task; static GNUNET_SCHEDULER_TaskIdentifier send_task; static struct PeerContext *p1; static struct PeerContext *p2; static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; static struct GNUNET_TRANSPORT_TransmitHandle *th; static struct GNUNET_TRANSPORT_TESTING_handle *tth; static char *cfg_file_p1; static char *cfg_file_p2; static void end () { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); if (send_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (send_task); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); } static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { die_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); if (send_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (send_task); if (cc != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n")); GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); cc = NULL; } if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer were not ready to send data\n")); if (s_started == GNUNET_NO) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peers were not started \n")); else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peers were started \n")); if (s_connected == GNUNET_NO) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer were not connected\n")); else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer were connected\n")); if (s_sending == GNUNET_NO) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer were not ready to send data\n")); else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer were ready to send data\n")); th = NULL; if (p1 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer 1 was not started\n")); if (p2 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer 2 was not started\n")); ok = GNUNET_SYSERR; } static void notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { struct PeerContext *p = cls; struct PeerContext *t = NULL; if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) t = p1; if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) t = p2; GNUNET_assert (t != NULL); char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') received message of type %d and size %u size from peer %u (`%4s')!\n", p->no, ps, ntohs (message->type), ntohs (message->size), t->no, GNUNET_i2s (&t->id)); GNUNET_free (ps); if ((TEST_MESSAGE_TYPE == ntohs (message->type)) && (TEST_MESSAGE_SIZE == ntohs (message->size))) { ok = 0; end (); } else { GNUNET_break (0); ok = 1; end (); } } static size_t notify_ready (void *cls, size_t size, void *buf) { struct PeerContext *p = cls; struct GNUNET_MessageHeader *hdr; th = NULL; if (buf == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout occurred while waiting for transmit_ready\n"); if (GNUNET_SCHEDULER_NO_TASK != die_task) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); ok = 42; return 0; } GNUNET_assert (size >= TEST_MESSAGE_SIZE); if (buf != NULL) { memset (buf, '\0', TEST_MESSAGE_SIZE); hdr = buf; hdr->size = htons (TEST_MESSAGE_SIZE); hdr->type = htons (TEST_MESSAGE_TYPE); } char *ps = GNUNET_strdup (GNUNET_i2s (&p2->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') sending message with type %u and size %u bytes to peer %u (`%4s')\n", p2->no, ps, ntohs (hdr->type), ntohs (hdr->size), p->no, GNUNET_i2s (&p->id)); GNUNET_free (ps); return TEST_MESSAGE_SIZE; } static void sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { send_task = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; char *receiver_s = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message from peer %u (`%4s') -> peer %u (`%s') !\n", p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s); GNUNET_free (receiver_s); s_sending = GNUNET_YES; th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, TEST_MESSAGE_SIZE, 0, TIMEOUT_TRANSMIT, ¬ify_ready, p1); } static void notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { static int c; c++; struct PeerContext *p = cls; struct PeerContext *t = NULL; if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) t = p1; if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) t = p2; GNUNET_assert (t != NULL); char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s'): peer %u (`%s') connected to me!\n", p->no, ps, t->no, GNUNET_i2s (peer)); GNUNET_free (ps); } static void notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { struct PeerContext *p = cls; char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s'): peer (`%s') disconnected from me!\n", p->no, ps, GNUNET_i2s (peer)); GNUNET_free (ps); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; } static void testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) { cc = NULL; char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n", p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id)); GNUNET_free (p1_c); s_connected = GNUNET_YES; send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL); } static void start_cb (struct PeerContext *p, void *cls) { static int started; started++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, GNUNET_i2s (&p->id)); if (started != 2) return; else s_started = GNUNET_YES; char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n", p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id)); GNUNET_free (sender_c); cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); s_started = GNUNET_NO; s_connected = GNUNET_NO; s_sending = GNUNET_NO; p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); if ((p1 == NULL) || (p2 == NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } } static int check () { static char *const argv[] = { "test-transport-api", "-c", "test_transport_api_data.conf", NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; #if WRITECONFIG setTransportOptions ("test_transport_api_data.conf"); #endif send_task = GNUNET_SCHEDULER_NO_TASK; ok = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name, "nohelp", options, &run, &ok); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source); GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source, &test_plugin); GNUNET_log_setup (test_name, "WARNING", NULL); tth = GNUNET_TRANSPORT_TESTING_init (); GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1); GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2); ret = check (); GNUNET_free (cfg_file_p1); GNUNET_free (cfg_file_p2); GNUNET_free (test_source); GNUNET_free (test_plugin); GNUNET_free (test_name); GNUNET_TRANSPORT_TESTING_done (tth); return ret; } /* end of test_transport_api.c */ gnunet-0.9.3/src/transport/test_transport_api_reliability_tcp_peer1.conf0000644000175000017500000000112511750306133023713 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-tcp-p1/ DEFAULTCONFIG = test_transport_api_reliability_tcp_peer1.conf [transport-tcp] PORT = 12000 TIMEOUT = 5 s [arm] PORT = 12005 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12004 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12003 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12002 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12001 PLUGINS = tcp UNIXPATH = /tmp/gnunet-p1-service-transport.sock gnunet-0.9.3/src/transport/plugin_transport_http_client.c0000644000175000017500000004664111762211256020760 00000000000000/* This file is part of GNUnet (C) 2002--2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/plugin_transport_http_client.c * @brief http transport service plugin * @author Matthias Wachs */ #include "plugin_transport_http.h" static struct Plugin * p; #if VERBOSE_CURL /** * Function to log curl debug messages with GNUNET_log * @param curl handle * @param type curl_infotype * @param data data * @param size size * @param cls closure * @return 0 */ static int client_log (CURL * curl, curl_infotype type, char *data, size_t size, void *cls) { if (type == CURLINFO_TEXT) { char text[size + 2]; memcpy (text, data, size); if (text[size - 1] == '\n') text[size] = '\0'; else { text[size] = '\n'; text[size + 1] = '\0'; } #if BUILD_HTTPS GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-https", "Client: %p - %s", cls, text); #else GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-http", "Client: %p - %s", cls, text); #endif } return 0; } #endif /** * Task performing curl operations * @param cls plugin as closure * @param tc gnunet scheduler task context */ static void client_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Function setting up file descriptors and scheduling task to run * * @param plugin plugin as closure * @param now schedule task in 1ms, regardless of what curl may say * @return GNUNET_SYSERR for hard failure, GNUNET_OK for ok */ static int client_schedule (struct Plugin *plugin, int now) { fd_set rs; fd_set ws; fd_set es; int max; struct GNUNET_NETWORK_FDSet *grs; struct GNUNET_NETWORK_FDSet *gws; long to; CURLMcode mret; struct GNUNET_TIME_Relative timeout; /* Cancel previous scheduled task */ if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (plugin->client_perform_task); plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; } max = -1; FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es); mret = curl_multi_fdset (plugin->client_mh, &rs, &ws, &es, &max); if (mret != CURLM_OK) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), "curl_multi_fdset", __FILE__, __LINE__, curl_multi_strerror (mret)); return GNUNET_SYSERR; } mret = curl_multi_timeout (plugin->client_mh, &to); if (to == -1) timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1); else timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, to); if (now == GNUNET_YES) timeout = GNUNET_TIME_UNIT_MILLISECONDS; if (mret != CURLM_OK) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), "curl_multi_timeout", __FILE__, __LINE__, curl_multi_strerror (mret)); return GNUNET_SYSERR; } grs = GNUNET_NETWORK_fdset_create (); gws = GNUNET_NETWORK_fdset_create (); GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1); GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1); plugin->client_perform_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, timeout, grs, gws, &client_run, plugin); GNUNET_NETWORK_fdset_destroy (gws); GNUNET_NETWORK_fdset_destroy (grs); return GNUNET_OK; } int client_send (struct Session *s, struct HTTP_Message *msg) { GNUNET_assert (s != NULL); GNUNET_CONTAINER_DLL_insert_tail (s->msg_head, s->msg_tail, msg); if (GNUNET_YES != exist_session(p, s)) { GNUNET_break (0); return GNUNET_SYSERR; } if (s->client_put_paused == GNUNET_YES) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, "Client: %p was suspended, unpausing\n", s->client_put); s->client_put_paused = GNUNET_NO; curl_easy_pause (s->client_put, CURLPAUSE_CONT); } client_schedule (s->plugin, GNUNET_YES); return GNUNET_OK; } /** * Task performing curl operations * * @param cls plugin as closure * @param tc gnunet scheduler task context */ static void client_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Plugin *plugin = cls; int running; CURLMcode mret; GNUNET_assert (cls != NULL); plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; do { running = 0; mret = curl_multi_perform (plugin->client_mh, &running); CURLMsg *msg; int msgs_left; while ((msg = curl_multi_info_read (plugin->client_mh, &msgs_left))) { CURL *easy_h = msg->easy_handle; struct Session *s = NULL; char *d = (char *) s; //GNUNET_assert (easy_h != NULL); if (easy_h == NULL) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Client: connection to ended with reason %i: `%s', %i handles running\n", msg->data.result, curl_easy_strerror (msg->data.result), running); continue; } GNUNET_assert (CURLE_OK == curl_easy_getinfo (easy_h, CURLINFO_PRIVATE, &d)); s = (struct Session *) d; if (GNUNET_YES != exist_session(plugin, s)) { GNUNET_break (0); return; } GNUNET_assert (s != NULL); if (msg->msg == CURLMSG_DONE) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Client: %p connection to '%s' %s ended with reason %i: `%s'\n", msg->easy_handle, GNUNET_i2s (&s->target), http_plugin_address_to_string (NULL, s->addr, s->addrlen), msg->data.result, curl_easy_strerror (msg->data.result)); client_disconnect (s); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Notifying about ended session to peer `%s' `%s'\n", GNUNET_i2s (&s->target), http_plugin_address_to_string (plugin, s->addr, s->addrlen)); notify_session_end (plugin, &s->target, s); } } } while (mret == CURLM_CALL_MULTI_PERFORM); client_schedule (plugin, GNUNET_NO); } int client_disconnect (struct Session *s) { int res = GNUNET_OK; CURLMcode mret; struct Plugin *plugin = s->plugin; struct HTTP_Message *msg; struct HTTP_Message *t; if (GNUNET_YES != exist_session(plugin, s)) { GNUNET_break (0); return GNUNET_SYSERR; } if (s->client_put != NULL) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Client: %p Deleting outbound PUT session to peer `%s'\n", s->client_put, GNUNET_i2s (&s->target)); mret = curl_multi_remove_handle (plugin->client_mh, s->client_put); if (mret != CURLM_OK) { curl_easy_cleanup (s->client_put); res = GNUNET_SYSERR; GNUNET_break (0); } curl_easy_cleanup (s->client_put); s->client_put = NULL; } if (s->recv_wakeup_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (s->recv_wakeup_task); s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK; } if (s->client_get != NULL) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Client: %p Deleting outbound GET session to peer `%s'\n", s->client_get, GNUNET_i2s (&s->target)); mret = curl_multi_remove_handle (plugin->client_mh, s->client_get); if (mret != CURLM_OK) { curl_easy_cleanup (s->client_get); res = GNUNET_SYSERR; GNUNET_break (0); } curl_easy_cleanup (s->client_get); s->client_get = NULL; } msg = s->msg_head; while (msg != NULL) { t = msg->next; if (NULL != msg->transmit_cont) msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR); GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); GNUNET_free (msg); msg = t; } plugin->cur_connections -= 2; GNUNET_assert (plugin->outbound_sessions > 0); plugin->outbound_sessions --; GNUNET_STATISTICS_set (plugin->env->stats, "# HTTP outbound sessions", plugin->outbound_sessions, GNUNET_NO); /* Re-schedule since handles have changed */ if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (plugin->client_perform_task); plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; } client_schedule (plugin, GNUNET_YES); return res; } static int client_receive_mst_cb (void *cls, void *client, const struct GNUNET_MessageHeader *message) { struct Session *s = cls; struct GNUNET_TIME_Relative delay; if (GNUNET_YES != exist_session(p, s)) { GNUNET_break (0); return GNUNET_OK; } delay = http_plugin_receive (s, &s->target, message, s, s->addr, s->addrlen); s->next_receive = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), delay); if (GNUNET_TIME_absolute_get ().abs_value < s->next_receive.abs_value) { struct Plugin *plugin = s->plugin; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Client: peer `%s' address `%s' next read delayed for %llu ms\n", GNUNET_i2s (&s->target), GNUNET_a2s (s->addr, s->addrlen), delay); } return GNUNET_OK; } static void client_wake_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Session *s = cls; if (GNUNET_YES != exist_session(p, s)) { GNUNET_break (0); return; } s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, "Client: %p Waking up receive handle\n", s->client_get); if (s->client_get != NULL) curl_easy_pause (s->client_get, CURLPAUSE_CONT); } /** * Callback method used with libcurl * Method is called when libcurl needs to write data during sending * * @param stream pointer where to write data * @param size size of an individual element * @param nmemb count of elements that can be written to the buffer * @param cls destination pointer, passed to the libcurl handle * @return bytes read from stream */ static size_t client_receive (void *stream, size_t size, size_t nmemb, void *cls) { struct Session *s = cls; struct GNUNET_TIME_Absolute now; size_t len = size * nmemb; struct Plugin *plugin = s->plugin; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Client: Received %Zu bytes from peer `%s'\n", len, GNUNET_i2s (&s->target)); now = GNUNET_TIME_absolute_get (); if (now.abs_value < s->next_receive.abs_value) { struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference (now, s->next_receive); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Client: %p No inbound bandwidth available! Next read was delayed for %llu ms\n", s->client_get, delta.rel_value); if (s->recv_wakeup_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (s->recv_wakeup_task); s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK; } s->recv_wakeup_task = GNUNET_SCHEDULER_add_delayed (delta, &client_wake_up, s); return CURLPAUSE_ALL; } if (NULL == s->msg_tk) s->msg_tk = GNUNET_SERVER_mst_create (&client_receive_mst_cb, s); GNUNET_SERVER_mst_receive (s->msg_tk, s, stream, len, GNUNET_NO, GNUNET_NO); return len; } /** * Callback method used with libcurl * Method is called when libcurl needs to read data during sending * * @param stream pointer where to write data * @param size size of an individual element * @param nmemb count of elements that can be written to the buffer * @param cls source pointer, passed to the libcurl handle * @return bytes written to stream, returning 0 will terminate connection! */ static size_t client_send_cb (void *stream, size_t size, size_t nmemb, void *cls) { struct Session *s = cls; struct Plugin *plugin = s->plugin; struct HTTP_Message *msg = s->msg_head; size_t len; if (GNUNET_YES != exist_session(plugin, s)) { GNUNET_break (0); return 0; } if (NULL == msg) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Client: %p Nothing to send! Suspending PUT handle!\n", s->client_put); s->client_put_paused = GNUNET_YES; return CURL_READFUNC_PAUSE; } /* data to send */ GNUNET_assert (msg->pos < msg->size); /* calculate how much fits in buffer */ len = GNUNET_MIN (msg->size - msg->pos, size * nmemb); memcpy (stream, &msg->buf[msg->pos], len); msg->pos += len; if (msg->pos == msg->size) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Client: %p Message with %u bytes sent, removing message from queue\n", s->client_put, msg->size, msg->pos); /* Calling transmit continuation */ GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); if (NULL != msg->transmit_cont) msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK); GNUNET_free (msg); } return len; } int client_connect (struct Session *s) { struct Plugin *plugin = s->plugin; int res = GNUNET_OK; char *url; CURLMcode mret; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Initiating outbound session peer `%s'\n", GNUNET_i2s (&s->target)); s->inbound = GNUNET_NO; plugin->last_tag++; /* create url */ GNUNET_asprintf (&url, "%s%s;%u", http_plugin_address_to_string (plugin, s->addr, s->addrlen), GNUNET_h2s_full (&plugin->env->my_identity->hashPubKey), plugin->last_tag); #if 0 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "URL `%s'\n", url); #endif /* create get connection */ s->client_get = curl_easy_init (); #if VERBOSE_CURL curl_easy_setopt (s->client_get, CURLOPT_VERBOSE, 1L); curl_easy_setopt (s->client_get, CURLOPT_DEBUGFUNCTION, &client_log); curl_easy_setopt (s->client_get, CURLOPT_DEBUGDATA, s->client_get); #endif #if BUILD_HTTPS curl_easy_setopt (s->client_get, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); curl_easy_setopt (s->client_get, CURLOPT_SSL_VERIFYPEER, 0); curl_easy_setopt (s->client_get, CURLOPT_SSL_VERIFYHOST, 0); #endif curl_easy_setopt (s->client_get, CURLOPT_URL, url); //curl_easy_setopt (s->client_get, CURLOPT_HEADERFUNCTION, &curl_get_header_cb); //curl_easy_setopt (s->client_get, CURLOPT_WRITEHEADER, ps); curl_easy_setopt (s->client_get, CURLOPT_READFUNCTION, client_send_cb); curl_easy_setopt (s->client_get, CURLOPT_READDATA, s); curl_easy_setopt (s->client_get, CURLOPT_WRITEFUNCTION, client_receive); curl_easy_setopt (s->client_get, CURLOPT_WRITEDATA, s); curl_easy_setopt (s->client_get, CURLOPT_TIMEOUT_MS, (long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); curl_easy_setopt (s->client_get, CURLOPT_PRIVATE, s); curl_easy_setopt (s->client_get, CURLOPT_CONNECTTIMEOUT_MS, (long) HTTP_NOT_VALIDATED_TIMEOUT.rel_value); curl_easy_setopt (s->client_get, CURLOPT_BUFFERSIZE, 2 * GNUNET_SERVER_MAX_MESSAGE_SIZE); #if CURL_TCP_NODELAY curl_easy_setopt (ps->recv_endpoint, CURLOPT_TCP_NODELAY, 1); #endif /* create put connection */ s->client_put = curl_easy_init (); #if VERBOSE_CURL curl_easy_setopt (s->client_put, CURLOPT_VERBOSE, 1L); curl_easy_setopt (s->client_put, CURLOPT_DEBUGFUNCTION, &client_log); curl_easy_setopt (s->client_put, CURLOPT_DEBUGDATA, s->client_put); #endif #if BUILD_HTTPS curl_easy_setopt (s->client_put, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); curl_easy_setopt (s->client_put, CURLOPT_SSL_VERIFYPEER, 0); curl_easy_setopt (s->client_put, CURLOPT_SSL_VERIFYHOST, 0); #endif curl_easy_setopt (s->client_put, CURLOPT_URL, url); curl_easy_setopt (s->client_put, CURLOPT_PUT, 1L); //curl_easy_setopt (s->client_put, CURLOPT_HEADERFUNCTION, &curl_put_header_cb); //curl_easy_setopt (s->client_put, CURLOPT_WRITEHEADER, ps); curl_easy_setopt (s->client_put, CURLOPT_READFUNCTION, client_send_cb); curl_easy_setopt (s->client_put, CURLOPT_READDATA, s); curl_easy_setopt (s->client_put, CURLOPT_WRITEFUNCTION, client_receive); curl_easy_setopt (s->client_put, CURLOPT_WRITEDATA, s); curl_easy_setopt (s->client_put, CURLOPT_TIMEOUT_MS, (long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); curl_easy_setopt (s->client_put, CURLOPT_PRIVATE, s); curl_easy_setopt (s->client_put, CURLOPT_CONNECTTIMEOUT_MS, (long) HTTP_NOT_VALIDATED_TIMEOUT.rel_value); curl_easy_setopt (s->client_put, CURLOPT_BUFFERSIZE, 2 * GNUNET_SERVER_MAX_MESSAGE_SIZE); #if CURL_TCP_NODELAY curl_easy_setopt (s->client_put, CURLOPT_TCP_NODELAY, 1); #endif GNUNET_free (url); mret = curl_multi_add_handle (plugin->client_mh, s->client_get); if (mret != CURLM_OK) { curl_easy_cleanup (s->client_get); res = GNUNET_SYSERR; GNUNET_break (0); } mret = curl_multi_add_handle (plugin->client_mh, s->client_put); if (mret != CURLM_OK) { curl_multi_remove_handle (plugin->client_mh, s->client_get); curl_easy_cleanup (s->client_get); curl_easy_cleanup (s->client_put); res = GNUNET_SYSERR; GNUNET_break (0); } /* Perform connect */ plugin->cur_connections += 2; plugin->outbound_sessions ++; GNUNET_STATISTICS_set (plugin->env->stats, "# HTTP outbound sessions", plugin->outbound_sessions, GNUNET_NO); /* Re-schedule since handles have changed */ if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (plugin->client_perform_task); plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; } plugin->client_perform_task = GNUNET_SCHEDULER_add_now (client_run, plugin); return res; } int client_start (struct Plugin *plugin) { int res = GNUNET_OK; p = plugin; curl_global_init (CURL_GLOBAL_ALL); plugin->client_mh = curl_multi_init (); if (NULL == plugin->client_mh) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, _ ("Could not initialize curl multi handle, failed to start %s plugin!\n"), plugin->name); res = GNUNET_SYSERR; } return res; } void client_stop (struct Plugin *plugin) { p = NULL; if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (plugin->client_perform_task); plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; } curl_multi_cleanup (plugin->client_mh); curl_global_cleanup (); } /* end of plugin_transport_http_client.c */ gnunet-0.9.3/src/transport/test_transport_api_unreliability_unix_peer2.conf0000644000175000017500000000106111665472561024471 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-unix-p2/ DEFAULTCONFIG = test_transport_api_unreliability_unix_peer2.conf [arm] PORT = 12135 UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12134 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12133 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12132 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12131 PLUGINS = unix UNIXPATH = /tmp/gnunet-p2-service-transport.sock [transport-unix] PORT = 12131 gnunet-0.9.3/src/transport/plugin_transport_template.c0000644000175000017500000002014311760502551020242 00000000000000/* This file is part of GNUnet (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/plugin_transport_template.c * @brief template for a new transport service * @author Christian Grothoff */ #include "platform.h" #include "gnunet_protocols.h" #include "gnunet_connection_lib.h" #include "gnunet_server_lib.h" #include "gnunet_service_lib.h" #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" #include "gnunet_transport_plugin.h" #define DEBUG_TEMPLATE GNUNET_EXTRA_LOGGING /** * After how long do we expire an address that we * learned from another peer if it is not reconfirmed * by anyone? */ #define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6) /** * Encapsulation of all of the state of the plugin. */ struct Plugin; /** * Session handle for connections. */ struct Session { /** * Stored in a linked list. */ struct Session *next; /** * Pointer to the global plugin struct. */ struct Plugin *plugin; /** * The client (used to identify this connection) */ /* void *client; */ /** * Continuation function to call once the transmission buffer * has again space available. NULL if there is no * continuation to call. */ GNUNET_TRANSPORT_TransmitContinuation transmit_cont; /** * Closure for transmit_cont. */ void *transmit_cont_cls; /** * To whom are we talking to (set to our identity * if we are still waiting for the welcome message) */ struct GNUNET_PeerIdentity sender; /** * At what time did we reset last_received last? */ struct GNUNET_TIME_Absolute last_quota_update; /** * How many bytes have we received since the "last_quota_update" * timestamp? */ uint64_t last_received; /** * Number of bytes per ms that this peer is allowed * to send to us. */ uint32_t quota; }; /** * Encapsulation of all of the state of the plugin. */ struct Plugin { /** * Our environment. */ struct GNUNET_TRANSPORT_PluginEnvironment *env; /** * List of open sessions. */ struct Session *sessions; }; /** * Function that can be used by the transport service to transmit * a message using the plugin. Note that in the case of a * peer disconnecting, the continuation MUST be called * prior to the disconnect notification itself. This function * will be called with this peer's HELLO message to initiate * a fresh connection to another peer. * * @param cls closure * @param session which session must be used * @param msgbuf the message to transmit * @param msgbuf_size number of bytes in 'msgbuf' * @param priority how important is the message (most plugins will * ignore message priority and just FIFO) * @param to how long to wait at most for the transmission (does not * require plugins to discard the message after the timeout, * just advisory for the desired delay; most plugins will ignore * this as well) * @param cont continuation to call once the message has * been transmitted (or if the transport is ready * for the next transmission call; or if the * peer disconnected...); can be NULL * @param cont_cls closure for cont * @return number of bytes used (on the physical network, with overheads); * -1 on hard errors (i.e. address invalid); 0 is a legal value * and does NOT mean that the message was not transmitted (DV) */ static ssize_t template_plugin_send (void *cls, struct Session *session, const char *msgbuf, size_t msgbuf_size, unsigned int priority, struct GNUNET_TIME_Relative to, GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) { struct Plugin *plugin = cls; int bytes_sent = 0; GNUNET_assert (plugin != NULL); GNUNET_assert (session != NULL); /* struct Plugin *plugin = cls; */ return bytes_sent; } /** * Function that can be used to force the plugin to disconnect * from the given peer and cancel all previous transmissions * (and their continuationc). * * @param cls closure * @param target peer from which to disconnect */ static void template_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) { // struct Plugin *plugin = cls; // FIXME } /** * Convert the transports address to a nice, human-readable * format. * * @param cls closure * @param type name of the transport that generated the address * @param addr one of the addresses of the host, NULL for the last address * the specific address format depends on the transport * @param addrlen length of the address * @param numeric should (IP) addresses be displayed in numeric form? * @param timeout after how long should we give up? * @param asc function to call on each string * @param asc_cls closure for asc */ static void template_plugin_address_pretty_printer (void *cls, const char *type, const void *addr, size_t addrlen, int numeric, struct GNUNET_TIME_Relative timeout, GNUNET_TRANSPORT_AddressStringCallback asc, void *asc_cls) { asc (asc_cls, NULL); } /** * Another peer has suggested an address for this * peer and transport plugin. Check that this could be a valid * address. If so, consider adding it to the list * of addresses. * * @param cls closure * @param addr pointer to the address * @param addrlen length of addr * @return GNUNET_OK if this is a plausible address for this peer * and transport */ static int template_plugin_address_suggested (void *cls, const void *addr, size_t addrlen) { /* struct Plugin *plugin = cls; */ /* check if the address is plausible; if so, * add it to our list! */ return GNUNET_OK; } /** * Function called for a quick conversion of the binary address to * a numeric address. Note that the caller must not free the * address and that the next call to this function is allowed * to override the address again. * * @param cls closure * @param addr binary address * @param addrlen length of the address * @return string representing the same address */ static const char * template_plugin_address_to_string (void *cls, const void *addr, size_t addrlen) { GNUNET_break (0); return NULL; } /** * Entry point for the plugin. */ void * gnunet_plugin_transport_template_init (void *cls) { struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; struct GNUNET_TRANSPORT_PluginFunctions *api; struct Plugin *plugin; plugin = GNUNET_malloc (sizeof (struct Plugin)); plugin->env = env; api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); api->cls = plugin; api->send = &template_plugin_send; api->disconnect = &template_plugin_disconnect; api->address_pretty_printer = &template_plugin_address_pretty_printer; api->check_address = &template_plugin_address_suggested; api->address_to_string = &template_plugin_address_to_string; return api; } /** * Exit point from the plugin. */ void * gnunet_plugin_transport_template_done (void *cls) { struct GNUNET_TRANSPORT_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; GNUNET_free (plugin); GNUNET_free (api); return NULL; } /* end of plugin_transport_template.c */ gnunet-0.9.3/src/transport/test_quota_compliance_unix_asymmetric_peer1.conf0000644000175000017500000000116711647100177024425 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test_quota_compliance_peer1/ DEFAULTCONFIG = test_quota_compliance_unix_asymmetric_peer1.conf [arm] PORT = 4087 UNIXPATH = /tmp/test_quota_compliance_unix_arm_peer1.sock [statistics] PORT = 4088 UNIXPATH = /tmp/test_quota_compliance_unix_statistics_peer1.sock [resolver] PORT = 4089 UNIXPATH = /tmp/test_quota_compliance_unix_resolver_peer1.sock [peerinfo] PORT = 4090 UNIXPATH = /tmp/test_quota_compliance_unix_peerinfo_peer1.sock [transport] PORT = 4091 PLUGINS = unix UNIXPATH = /tmp/test_quota_compliance_unix_transport_peer1.sock [transport-unix] PORT = 4092 gnunet-0.9.3/src/transport/plugin_transport_udp_broadcasting.c0000644000175000017500000003726011760502551021747 00000000000000/* This file is part of GNUnet (C) 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/plugin_transport_udp_broadcasting.c * @brief Neighbour discovery with UDP * @author Christian Grothoff * @author Matthias Wachs */ #include "platform.h" #include "plugin_transport_udp.h" #include "gnunet_hello_lib.h" #include "gnunet_util_lib.h" #include "gnunet_fragmentation_lib.h" #include "gnunet_nat_lib.h" #include "gnunet_protocols.h" #include "gnunet_resolver_service.h" #include "gnunet_signatures.h" #include "gnunet_constants.h" #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" #include "gnunet_transport_plugin.h" #include "transport.h" #define LOG(kind,...) GNUNET_log_from (kind, "transport-udp", __VA_ARGS__) struct UDP_Beacon_Message { /** * Message header. */ struct GNUNET_MessageHeader header; /** * What is the identity of the sender */ struct GNUNET_PeerIdentity sender; }; struct BroadcastAddress { struct BroadcastAddress *next; struct BroadcastAddress *prev; void *addr; socklen_t addrlen; }; struct Mstv4Context { struct Plugin *plugin; struct IPv4UdpAddress addr; /** * ATS network type in NBO */ uint32_t ats_address_network_type; }; struct Mstv6Context { struct Plugin *plugin; struct IPv6UdpAddress addr; /** * ATS network type in NBO */ uint32_t ats_address_network_type; }; int broadcast_ipv6_mst_cb (void *cls, void *client, const struct GNUNET_MessageHeader *message) { struct Plugin *plugin = cls; struct Mstv6Context *mc = client; const struct GNUNET_MessageHeader *hello; struct UDP_Beacon_Message *msg; msg = (struct UDP_Beacon_Message *) message; if (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON != ntohs (msg->header.type)) return GNUNET_OK; LOG (GNUNET_ERROR_TYPE_DEBUG, "Received beacon with %u bytes from peer `%s' via address `%s'\n", ntohs (msg->header.size), GNUNET_i2s (&msg->sender), udp_address_to_string (NULL, &mc->addr, sizeof (mc->addr))); struct GNUNET_ATS_Information atsi[2]; /* setup ATS */ atsi[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); atsi[0].value = htonl (1); atsi[1].type = htonl (GNUNET_ATS_NETWORK_TYPE); atsi[1].value = mc->ats_address_network_type; GNUNET_break (ntohl(mc->ats_address_network_type) != GNUNET_ATS_NET_UNSPECIFIED); hello = (struct GNUNET_MessageHeader *) &msg[1]; plugin->env->receive (plugin->env->cls, &msg->sender, hello, (const struct GNUNET_ATS_Information *) &atsi, 2, NULL, (const char *) &mc->addr, sizeof (mc->addr)); GNUNET_STATISTICS_update (plugin->env->stats, _ ("# IPv6 multicast HELLO beacons received via udp"), 1, GNUNET_NO); GNUNET_free (mc); return GNUNET_OK; } int broadcast_ipv4_mst_cb (void *cls, void *client, const struct GNUNET_MessageHeader *message) { struct Plugin *plugin = cls; struct Mstv4Context *mc = client; const struct GNUNET_MessageHeader *hello; struct UDP_Beacon_Message *msg; msg = (struct UDP_Beacon_Message *) message; if (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON != ntohs (msg->header.type)) return GNUNET_OK; LOG (GNUNET_ERROR_TYPE_DEBUG, "Received beacon with %u bytes from peer `%s' via address `%s'\n", ntohs (msg->header.size), GNUNET_i2s (&msg->sender), udp_address_to_string (NULL, &mc->addr, sizeof (mc->addr))); struct GNUNET_ATS_Information atsi[2]; /* setup ATS */ atsi[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); atsi[0].value = htonl (1); atsi[1].type = htonl (GNUNET_ATS_NETWORK_TYPE); atsi[1].value = mc->ats_address_network_type; GNUNET_break (ntohl(mc->ats_address_network_type) != GNUNET_ATS_NET_UNSPECIFIED); hello = (struct GNUNET_MessageHeader *) &msg[1]; plugin->env->receive (plugin->env->cls, &msg->sender, hello, (const struct GNUNET_ATS_Information *) &atsi, 2, NULL, (const char *) &mc->addr, sizeof (mc->addr)); GNUNET_STATISTICS_update (plugin->env->stats, _ ("# IPv4 broadcast HELLO beacons received via udp"), 1, GNUNET_NO); GNUNET_free (mc); return GNUNET_OK; } void udp_broadcast_receive (struct Plugin *plugin, const char * buf, ssize_t size, struct sockaddr *addr, size_t addrlen) { struct GNUNET_ATS_Information ats; if ((GNUNET_YES == plugin->broadcast_ipv4) && (addrlen == sizeof (struct sockaddr_in))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Received IPv4 HELLO beacon broadcast with %i bytes from address %s\n", size, GNUNET_a2s ((const struct sockaddr *) addr, addrlen)); struct Mstv4Context *mc; mc = GNUNET_malloc (sizeof (struct Mstv4Context)); struct sockaddr_in *av4 = (struct sockaddr_in *) addr; mc->addr.ipv4_addr = av4->sin_addr.s_addr; mc->addr.u4_port = av4->sin_port; ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) addr, addrlen); mc->ats_address_network_type = ats.value; GNUNET_assert (NULL != plugin->broadcast_ipv4_mst); if (GNUNET_OK != GNUNET_SERVER_mst_receive (plugin->broadcast_ipv4_mst, mc, buf, size, GNUNET_NO, GNUNET_NO)) GNUNET_free (mc); } else if ((GNUNET_YES == plugin->broadcast_ipv4) && (addrlen == sizeof (struct sockaddr_in6))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Received IPv6 HELLO beacon broadcast with %i bytes from address %s\n", size, GNUNET_a2s ((const struct sockaddr *) &addr, addrlen)); struct Mstv6Context *mc; mc = GNUNET_malloc (sizeof (struct Mstv6Context)); struct sockaddr_in6 *av6 = (struct sockaddr_in6 *) addr; mc->addr.ipv6_addr = av6->sin6_addr; mc->addr.u6_port = av6->sin6_port; ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) addr, addrlen); mc->ats_address_network_type = ats.value; GNUNET_assert (NULL != plugin->broadcast_ipv4_mst); if (GNUNET_OK != GNUNET_SERVER_mst_receive (plugin->broadcast_ipv6_mst, mc, buf, size, GNUNET_NO, GNUNET_NO)) GNUNET_free (mc); } } static unsigned int prepare_beacon (struct Plugin *plugin, struct UDP_Beacon_Message *msg) { uint16_t hello_size; uint16_t msg_size; const struct GNUNET_MessageHeader *hello; hello = plugin->env->get_our_hello (); hello_size = GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello); msg_size = hello_size + sizeof (struct UDP_Beacon_Message); if (hello_size < (sizeof (struct GNUNET_MessageHeader)) || (msg_size > (UDP_MTU))) return 0; msg->sender = *(plugin->env->my_identity); msg->header.size = htons (msg_size); msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON); memcpy (&msg[1], hello, hello_size); return msg_size; } static void udp_ipv4_broadcast_send (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Plugin *plugin = cls; int sent; uint16_t msg_size; char buf[65536] GNUNET_ALIGN; struct BroadcastAddress *baddr; plugin->send_ipv4_broadcast_task = GNUNET_SCHEDULER_NO_TASK; msg_size = prepare_beacon(plugin, (struct UDP_Beacon_Message *) &buf); sent = 0; baddr = plugin->ipv4_broadcast_head; /* just IPv4 */ while ((baddr != NULL) && (baddr->addrlen == sizeof (struct sockaddr_in))) { struct sockaddr_in *addr = (struct sockaddr_in *) baddr->addr; addr->sin_port = htons (plugin->port); sent = GNUNET_NETWORK_socket_sendto (plugin->sockv4, &buf, msg_size, (const struct sockaddr *) addr, baddr->addrlen); if (sent == GNUNET_SYSERR) GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sendto"); else { LOG (GNUNET_ERROR_TYPE_DEBUG, "Sent HELLO beacon broadcast with %i bytes to address %s\n", sent, GNUNET_a2s (baddr->addr, baddr->addrlen)); } baddr = baddr->next; } plugin->send_ipv4_broadcast_task = GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval, &udp_ipv4_broadcast_send, plugin); } static void udp_ipv6_broadcast_send (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Plugin *plugin = cls; int sent; uint16_t msg_size; char buf[65536] GNUNET_ALIGN; plugin->send_ipv6_broadcast_task = GNUNET_SCHEDULER_NO_TASK; msg_size = prepare_beacon(plugin, (struct UDP_Beacon_Message *) &buf); sent = 0; sent = GNUNET_NETWORK_socket_sendto (plugin->sockv6, &buf, msg_size, (const struct sockaddr *) &plugin->ipv6_multicast_address, sizeof (struct sockaddr_in6)); if (sent == GNUNET_SYSERR) GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sendto"); else { LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending IPv6 HELLO beacon broadcast with %i bytes to address %s\n", sent, GNUNET_a2s ((const struct sockaddr *) &plugin->ipv6_multicast_address, sizeof (struct sockaddr_in6))); } plugin->send_ipv6_broadcast_task = GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval, &udp_ipv6_broadcast_send, plugin); } static int iface_proc (void *cls, const char *name, int isDefault, const struct sockaddr *addr, const struct sockaddr *broadcast_addr, const struct sockaddr *netmask, socklen_t addrlen) { struct Plugin *plugin = cls; if (addr != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "address %s for interface %s %p\n ", GNUNET_a2s (addr, addrlen), name, addr); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "broadcast address %s for interface %s %p\n ", GNUNET_a2s (broadcast_addr, addrlen), name, broadcast_addr); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "netmask %s for interface %s %p\n ", GNUNET_a2s (netmask, addrlen), name, netmask); /* Collecting broadcast addresses */ if (broadcast_addr != NULL) { struct BroadcastAddress *ba = GNUNET_malloc (sizeof (struct BroadcastAddress)); ba->addr = GNUNET_malloc (addrlen); memcpy (ba->addr, broadcast_addr, addrlen); ba->addrlen = addrlen; GNUNET_CONTAINER_DLL_insert (plugin->ipv4_broadcast_head, plugin->ipv4_broadcast_tail, ba); } } return GNUNET_OK; } void setup_broadcast (struct Plugin *plugin, struct sockaddr_in6 *serverAddrv6, struct sockaddr_in *serverAddrv4) { /* create IPv4 broadcast socket */ plugin->broadcast_ipv4 = GNUNET_NO; if (plugin->sockv4 != NULL) { int yes = 1; if (GNUNET_NETWORK_socket_setsockopt (plugin->sockv4, SOL_SOCKET, SO_BROADCAST, &yes, sizeof (int)) != GNUNET_OK) { LOG (GNUNET_ERROR_TYPE_WARNING, _ ("Failed to set IPv4 broadcast option for broadcast socket on port %d\n"), ntohs (serverAddrv4->sin_port)); } else { GNUNET_OS_network_interfaces_list (iface_proc, plugin); plugin->send_ipv4_broadcast_task = GNUNET_SCHEDULER_add_now (&udp_ipv4_broadcast_send, plugin); plugin->broadcast_ipv4_mst = GNUNET_SERVER_mst_create (broadcast_ipv4_mst_cb, plugin); LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv4 Broadcasting running\n"); plugin->broadcast_ipv4 = GNUNET_YES; } } plugin->broadcast_ipv6 = GNUNET_NO; if (plugin->sockv6 != NULL) { memset (&plugin->ipv6_multicast_address, 0, sizeof (struct sockaddr_in6)); GNUNET_assert (1 == inet_pton (AF_INET6, "FF05::13B", &plugin->ipv6_multicast_address.sin6_addr)); plugin->ipv6_multicast_address.sin6_family = AF_INET6; plugin->ipv6_multicast_address.sin6_port = htons (plugin->port); plugin->broadcast_ipv6_mst = GNUNET_SERVER_mst_create (broadcast_ipv6_mst_cb, plugin); /* Create IPv6 multicast request */ struct ipv6_mreq multicastRequest; multicastRequest.ipv6mr_multiaddr = plugin->ipv6_multicast_address.sin6_addr; /* TODO: 0 selects the "best" interface, tweak to use all interfaces * * http://tools.ietf.org/html/rfc2553#section-5.2: * * IPV6_JOIN_GROUP * * Join a multicast group on a specified local interface. If the * interface index is specified as 0, the kernel chooses the local * interface. For example, some kernels look up the multicast * group in the normal IPv6 routing table and using the resulting * interface. * */ multicastRequest.ipv6mr_interface = 0; /* Join the multicast group */ if (GNUNET_NETWORK_socket_setsockopt (plugin->sockv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &multicastRequest, sizeof (multicastRequest)) != GNUNET_OK) { LOG (GNUNET_ERROR_TYPE_WARNING, "Failed to join IPv6 multicast group: IPv6 broadcasting not running\n"); } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv6 broadcasting running\n"); plugin->send_ipv6_broadcast_task = GNUNET_SCHEDULER_add_now (&udp_ipv6_broadcast_send, plugin); plugin->broadcast_ipv6 = GNUNET_YES; } } } void stop_broadcast (struct Plugin *plugin) { if (plugin->broadcast_ipv4) { if (plugin->send_ipv4_broadcast_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (plugin->send_ipv4_broadcast_task); plugin->send_ipv4_broadcast_task = GNUNET_SCHEDULER_NO_TASK; } if (plugin->broadcast_ipv4_mst != NULL) GNUNET_SERVER_mst_destroy (plugin->broadcast_ipv4_mst); while (plugin->ipv4_broadcast_head != NULL) { struct BroadcastAddress *p = plugin->ipv4_broadcast_head; GNUNET_CONTAINER_DLL_remove (plugin->ipv4_broadcast_head, plugin->ipv4_broadcast_tail, p); GNUNET_free (p->addr); GNUNET_free (p); } } if (plugin->broadcast_ipv6) { /* Create IPv6 multicast request */ struct ipv6_mreq multicastRequest; multicastRequest.ipv6mr_multiaddr = plugin->ipv6_multicast_address.sin6_addr; multicastRequest.ipv6mr_interface = 0; /* Join the multicast address */ if (GNUNET_NETWORK_socket_setsockopt (plugin->sockv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *) &multicastRequest, sizeof (multicastRequest)) != GNUNET_OK) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, setsockopt); } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv6 Broadcasting stopped\n"); } if (plugin->send_ipv6_broadcast_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (plugin->send_ipv6_broadcast_task); plugin->send_ipv6_broadcast_task = GNUNET_SCHEDULER_NO_TASK; } if (plugin->broadcast_ipv6_mst != NULL) GNUNET_SERVER_mst_destroy (plugin->broadcast_ipv6_mst); } } /* end of plugin_transport_udp_broadcasting.c */ gnunet-0.9.3/src/transport/test_plugin_transport_data_udp.conf0000644000175000017500000000000111615567500021745 00000000000000 gnunet-0.9.3/src/transport/test_transport_api_udp_peer1.conf0000644000175000017500000000120211663237620021327 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-udp-p1/ DEFAULTCONFIG = test_transport_api_udp_peer1.conf [transport-udp] PORT = 12040 BROADCAST = NO BROADCAST_INTERVAL = 30000 MAX_BPS = 50000000 [arm] PORT = 12045 UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12044 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12043 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12042 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] #PREFIX = valgrind --leak-check=full PORT = 12041 PLUGINS = udp UNIXPATH = /tmp/gnunet-p1-service-transport.sock gnunet-0.9.3/src/transport/test_transport_api_unix_peer2.conf0000644000175000017500000000104311647100177021524 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-unix-p2/ DEFAULTCONFIG = test_transport_api_unix_peer2.conf [arm] PORT = 12135 UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12134 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12133 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12132 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12131 PLUGINS = unix UNIXPATH = /tmp/gnunet-p2-service-transport.sock [transport-unix] PORT = 12136 gnunet-0.9.3/src/transport/plugin_transport_tcp.c0000644000175000017500000021551211762336500017224 00000000000000/* This file is part of GNUnet (C) 2002--2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/plugin_transport_tcp.c * @brief Implementation of the TCP transport service * @author Christian Grothoff */ #include "platform.h" #include "gnunet_hello_lib.h" #include "gnunet_constants.h" #include "gnunet_connection_lib.h" #include "gnunet_container_lib.h" #include "gnunet_nat_lib.h" #include "gnunet_os_lib.h" #include "gnunet_protocols.h" #include "gnunet_resolver_service.h" #include "gnunet_server_lib.h" #include "gnunet_service_lib.h" #include "gnunet_signatures.h" #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" #include "gnunet_transport_plugin.h" #include "transport.h" #define LOG(kind,...) GNUNET_log_from (kind, "transport-tcp",__VA_ARGS__) /** * How long until we give up on establishing an NAT connection? * Must be > 4 RTT */ #define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) GNUNET_NETWORK_STRUCT_BEGIN /** * Initial handshake message for a session. */ struct WelcomeMessage { /** * Type is GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME. */ struct GNUNET_MessageHeader header; /** * Identity of the node connecting (TCP client) */ struct GNUNET_PeerIdentity clientIdentity; }; /** * Basically a WELCOME message, but with the purpose * of giving the waiting peer a client handle to use */ struct TCP_NAT_ProbeMessage { /** * Type is GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE. */ struct GNUNET_MessageHeader header; /** * Identity of the sender of the message. */ struct GNUNET_PeerIdentity clientIdentity; }; GNUNET_NETWORK_STRUCT_END /** * Context for sending a NAT probe via TCP. */ struct TCPProbeContext { /** * Active probes are kept in a DLL. */ struct TCPProbeContext *next; /** * Active probes are kept in a DLL. */ struct TCPProbeContext *prev; /** * Probe connection. */ struct GNUNET_CONNECTION_Handle *sock; /** * Message to be sent. */ struct TCP_NAT_ProbeMessage message; /** * Handle to the transmission. */ struct GNUNET_CONNECTION_TransmitHandle *transmit_handle; /** * Transport plugin handle. */ struct Plugin *plugin; }; GNUNET_NETWORK_STRUCT_BEGIN /** * Network format for IPv4 addresses. */ struct IPv4TcpAddress { /** * IPv4 address, in network byte order. */ uint32_t ipv4_addr GNUNET_PACKED; /** * Port number, in network byte order. */ uint16_t t4_port GNUNET_PACKED; }; /** * Network format for IPv6 addresses. */ struct IPv6TcpAddress { /** * IPv6 address. */ struct in6_addr ipv6_addr GNUNET_PACKED; /** * Port number, in network byte order. */ uint16_t t6_port GNUNET_PACKED; }; GNUNET_NETWORK_STRUCT_END /** * Encapsulation of all of the state of the plugin. */ struct Plugin; /** * Information kept for each message that is yet to * be transmitted. */ struct PendingMessage { /** * This is a doubly-linked list. */ struct PendingMessage *next; /** * This is a doubly-linked list. */ struct PendingMessage *prev; /** * The pending message */ const char *msg; /** * Continuation function to call once the message * has been sent. Can be NULL if there is no * continuation to call. */ GNUNET_TRANSPORT_TransmitContinuation transmit_cont; /** * Closure for transmit_cont. */ void *transmit_cont_cls; /** * Timeout value for the pending message. */ struct GNUNET_TIME_Absolute timeout; /** * So that the gnunet-service-transport can group messages together, * these pending messages need to accept a message buffer and size * instead of just a GNUNET_MessageHeader. */ size_t message_size; }; /** * Session handle for TCP connections. */ struct Session { /** * API requirement. */ struct SessionHeader header; /** * Pointer to the global plugin struct. */ struct Plugin *plugin; /** * The client (used to identify this connection) */ struct GNUNET_SERVER_Client *client; /** * Task cleaning up a NAT client connection establishment attempt; */ GNUNET_SCHEDULER_TaskIdentifier nat_connection_timeout; /** * Messages currently pending for transmission * to this peer, if any. */ struct PendingMessage *pending_messages_head; /** * Messages currently pending for transmission * to this peer, if any. */ struct PendingMessage *pending_messages_tail; /** * Handle for pending transmission request. */ struct GNUNET_SERVER_TransmitHandle *transmit_handle; /** * To whom are we talking to (set to our identity * if we are still waiting for the welcome message) */ struct GNUNET_PeerIdentity target; /** * ID of task used to delay receiving more to throttle sender. */ GNUNET_SCHEDULER_TaskIdentifier receive_delay_task; /** * Session timeout task */ GNUNET_SCHEDULER_TaskIdentifier timeout_task; /** * Address of the other peer (either based on our 'connect' * call or on our 'accept' call). * * struct IPv4TcpAddress or struct IPv6TcpAddress * */ void *addr; /** * Length of connect_addr. */ size_t addrlen; /** * Last activity on this connection. Used to select preferred * connection. */ struct GNUNET_TIME_Absolute last_activity; /** * Are we still expecting the welcome message? (GNUNET_YES/GNUNET_NO) */ int expecting_welcome; /** * Was this a connection that was inbound (we accepted)? (GNUNET_YES/GNUNET_NO) */ int inbound; /** * Was this session created using NAT traversal? */ int is_nat; /** * ATS network type in NBO */ uint32_t ats_address_network_type; }; /** * Encapsulation of all of the state of the plugin. */ struct Plugin { /** * Our environment. */ struct GNUNET_TRANSPORT_PluginEnvironment *env; /** * The listen socket. */ struct GNUNET_CONNECTION_Handle *lsock; /** * Our handle to the NAT module. */ struct GNUNET_NAT_Handle *nat; /** * Map from peer identities to sessions for the given peer. */ struct GNUNET_CONTAINER_MultiHashMap *sessionmap; /** * Handle to the network service. */ struct GNUNET_SERVICE_Context *service; /** * Handle to the server for this service. */ struct GNUNET_SERVER_Handle *server; /** * Copy of the handler array where the closures are * set to this struct's instance. */ struct GNUNET_SERVER_MessageHandler *handlers; /** * Map of peers we have tried to contact behind a NAT */ struct GNUNET_CONTAINER_MultiHashMap *nat_wait_conns; /** * List of active TCP probes. */ struct TCPProbeContext *probe_head; /** * List of active TCP probes. */ struct TCPProbeContext *probe_tail; /** * Handle for (DYN)DNS lookup of our external IP. */ struct GNUNET_RESOLVER_RequestHandle *ext_dns; /** * How many more TCP sessions are we allowed to open right now? */ unsigned long long max_connections; /** * ID of task used to update our addresses when one expires. */ GNUNET_SCHEDULER_TaskIdentifier address_update_task; /** * Port that we are actually listening on. */ uint16_t open_port; /** * Port that the user said we would have visible to the * rest of the world. */ uint16_t adv_port; }; /** * Start session timeout */ static void start_session_timeout (struct Session *s); /** * Increment session timeout due to activity */ static void reschedule_session_timeout (struct Session *s); /** * Cancel timeout */ static void stop_session_timeout (struct Session *s); /* DEBUG CODE */ static const char * tcp_address_to_string (void *cls, const void *addr, size_t addrlen); static unsigned int sessions; static void inc_sessions (struct Plugin *plugin, struct Session *session, int line) { sessions++; unsigned int size = GNUNET_CONTAINER_multihashmap_size(plugin->sessionmap); if (sessions != size) LOG (GNUNET_ERROR_TYPE_DEBUG, "Inconsistent sessions %u <-> session map size: %u\n", sessions, size); LOG (GNUNET_ERROR_TYPE_DEBUG, "%4i Session increased to %u (session map size: %u): `%s' `%s'\n", line, sessions, size, GNUNET_i2s (&session->target), tcp_address_to_string (NULL, session->addr, session->addrlen)); } static void dec_sessions (struct Plugin *plugin, struct Session *session, int line) { GNUNET_assert (sessions > 0); unsigned int size = GNUNET_CONTAINER_multihashmap_size(plugin->sessionmap); sessions--; if (sessions != size) LOG (GNUNET_ERROR_TYPE_DEBUG, "Inconsistent sessions %u <-> session map size: %u\n", sessions, size); LOG (GNUNET_ERROR_TYPE_DEBUG, "%4i Session decreased to %u (session map size: %u): `%s' `%s'\n", line, sessions, size, GNUNET_i2s (&session->target), tcp_address_to_string (NULL, session->addr, session->addrlen)); } /* DEBUG CODE */ /** * Function to check if an inbound connection is acceptable. * Mostly used to limit the total number of open connections * we can have. * * @param cls the 'struct Plugin' * @param ucred credentials, if available, otherwise NULL * @param addr address * @param addrlen length of address * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR * for unknown address family (will be denied). */ static int plugin_tcp_access_check (void *cls, const struct GNUNET_CONNECTION_Credentials *ucred, const struct sockaddr *addr, socklen_t addrlen) { struct Plugin *plugin = cls; LOG (GNUNET_ERROR_TYPE_DEBUG, "Accepting new incoming TCP connection\n"); if (0 == plugin->max_connections) return GNUNET_NO; plugin->max_connections--; return GNUNET_YES; } /** * Our external IP address/port mapping has changed. * * @param cls closure, the 'struct LocalAddrList' * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean * the previous (now invalid) one * @param addr either the previous or the new public IP address * @param addrlen actual lenght of the address */ static void tcp_nat_port_map_callback (void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen) { struct Plugin *plugin = cls; struct IPv4TcpAddress t4; struct IPv6TcpAddress t6; void *arg; size_t args; LOG (GNUNET_ERROR_TYPE_DEBUG, "NPMC called with %d for address `%s'\n", add_remove, GNUNET_a2s (addr, addrlen)); /* convert 'addr' to our internal format */ switch (addr->sa_family) { case AF_INET: GNUNET_assert (addrlen == sizeof (struct sockaddr_in)); t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; t4.t4_port = ((struct sockaddr_in *) addr)->sin_port; arg = &t4; args = sizeof (t4); break; case AF_INET6: GNUNET_assert (addrlen == sizeof (struct sockaddr_in6)); memcpy (&t6.ipv6_addr, &((struct sockaddr_in6 *) addr)->sin6_addr, sizeof (struct in6_addr)); t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port; arg = &t6; args = sizeof (t6); break; default: GNUNET_break (0); return; } /* modify our published address list */ plugin->env->notify_address (plugin->env->cls, add_remove, arg, args); } /** * Function called for a quick conversion of the binary address to * a numeric address. Note that the caller must not free the * address and that the next call to this function is allowed * to override the address again. * * @param cls closure ('struct Plugin*') * @param addr binary address * @param addrlen length of the address * @return string representing the same address */ static const char * tcp_address_to_string (void *cls, const void *addr, size_t addrlen) { static char rbuf[INET6_ADDRSTRLEN + 12]; char buf[INET6_ADDRSTRLEN]; const void *sb; struct in_addr a4; struct in6_addr a6; const struct IPv4TcpAddress *t4; const struct IPv6TcpAddress *t6; int af; uint16_t port; switch (addrlen) { case sizeof (struct IPv6TcpAddress): t6 = addr; af = AF_INET6; port = ntohs (t6->t6_port); memcpy (&a6, &t6->ipv6_addr, sizeof (a6)); sb = &a6; break; case sizeof (struct IPv4TcpAddress): t4 = addr; af = AF_INET; port = ntohs (t4->t4_port); memcpy (&a4, &t4->ipv4_addr, sizeof (a4)); sb = &a4; break; default: LOG (GNUNET_ERROR_TYPE_ERROR, _("Unexpected address length: %u bytes\n"), (unsigned int) addrlen); GNUNET_break (0); return NULL; } if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop"); return NULL; } GNUNET_snprintf (rbuf, sizeof (rbuf), (af == AF_INET6) ? "[%s]:%u" : "%s:%u", buf, port); return rbuf; } /** * Function called to convert a string address to * a binary address. * * @param cls closure ('struct Plugin*') * @param addr string address * @param addrlen length of the address * @param buf location to store the buffer * @param added location to store the number of bytes in the buffer. * If the function returns GNUNET_SYSERR, its contents are undefined. * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ static int tcp_string_to_address (void *cls, const char *addr, uint16_t addrlen, void **buf, size_t *added) { struct sockaddr_storage socket_address; if ((NULL == addr) || (addrlen == 0)) { GNUNET_break (0); return GNUNET_SYSERR; } if ('\0' != addr[addrlen - 1]) { GNUNET_break (0); return GNUNET_SYSERR; } if (strlen (addr) != addrlen - 1) { GNUNET_break (0); return GNUNET_SYSERR; } if (GNUNET_OK != GNUNET_STRINGS_to_address_ip (addr, strlen (addr), &socket_address)) { GNUNET_break (0); return GNUNET_SYSERR; } switch (socket_address.ss_family) { case AF_INET: { struct IPv4TcpAddress *t4; struct sockaddr_in *in4 = (struct sockaddr_in *) &socket_address; t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress)); t4->ipv4_addr = in4->sin_addr.s_addr; t4->t4_port = in4->sin_port; *buf = t4; *added = sizeof (struct IPv4TcpAddress); return GNUNET_OK; } case AF_INET6: { struct IPv6TcpAddress *t6; struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &socket_address; t6 = GNUNET_malloc (sizeof (struct IPv6TcpAddress)); t6->ipv6_addr = in6->sin6_addr; t6->t6_port = in6->sin6_port; *buf = t6; *added = sizeof (struct IPv6TcpAddress); return GNUNET_OK; } default: return GNUNET_SYSERR; } } struct SessionClientCtx { const struct GNUNET_SERVER_Client *client; struct Session *ret; }; static int session_lookup_by_client_it (void *cls, const GNUNET_HashCode * key, void *value) { struct SessionClientCtx *sc_ctx = cls; struct Session *s = value; if (s->client == sc_ctx->client) { sc_ctx->ret = s; return GNUNET_NO; } return GNUNET_YES; } /** * Find the session handle for the given client. * * @param plugin the plugin * @param client which client to find the session handle for * @return NULL if no matching session exists */ static struct Session * lookup_session_by_client (struct Plugin *plugin, const struct GNUNET_SERVER_Client *client) { struct SessionClientCtx sc_ctx; sc_ctx.client = client; sc_ctx.ret = NULL; GNUNET_CONTAINER_multihashmap_iterate (plugin->sessionmap, &session_lookup_by_client_it, &sc_ctx); return sc_ctx.ret; } /** * Create a new session. Also queues a welcome message. * * @param plugin the plugin * @param target peer to connect to * @param client client to use, reference counter must have already been increased * @param is_nat this a NAT session, we should wait for a client to * connect to us from an address, then assign that to * the session * @return new session object */ static struct Session * create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, struct GNUNET_SERVER_Client *client, int is_nat) { struct Session *ret; struct PendingMessage *pm; struct WelcomeMessage welcome; if (GNUNET_YES != is_nat) GNUNET_assert (NULL != client); else GNUNET_assert (NULL == client); LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating new session for peer `%4s'\n", GNUNET_i2s (target)); ret = GNUNET_malloc (sizeof (struct Session)); ret->last_activity = GNUNET_TIME_absolute_get (); ret->plugin = plugin; ret->is_nat = is_nat; ret->client = client; ret->target = *target; ret->expecting_welcome = GNUNET_YES; ret->ats_address_network_type = htonl (GNUNET_ATS_NET_UNSPECIFIED); pm = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (struct WelcomeMessage)); pm->msg = (const char *) &pm[1]; pm->message_size = sizeof (struct WelcomeMessage); welcome.header.size = htons (sizeof (struct WelcomeMessage)); welcome.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME); welcome.clientIdentity = *plugin->env->my_identity; memcpy (&pm[1], &welcome, sizeof (welcome)); pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS; GNUNET_STATISTICS_update (plugin->env->stats, gettext_noop ("# bytes currently in TCP buffers"), pm->message_size, GNUNET_NO); GNUNET_CONTAINER_DLL_insert (ret->pending_messages_head, ret->pending_messages_tail, pm); if (GNUNET_YES != is_nat) { GNUNET_STATISTICS_update (plugin->env->stats, gettext_noop ("# TCP sessions active"), 1, GNUNET_NO); } start_session_timeout (ret); return ret; } /** * If we have pending messages, ask the server to * transmit them (schedule the respective tasks, etc.) * * @param session for which session should we do this */ static void process_pending_messages (struct Session *session); /** * Function called to notify a client about the socket * being ready to queue more data. "buf" will be * NULL and "size" zero if the socket was closed for * writing in the meantime. * * @param cls closure * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t do_transmit (void *cls, size_t size, void *buf) { struct Session *session = cls; struct GNUNET_PeerIdentity pid; struct Plugin *plugin; struct PendingMessage *pos; struct PendingMessage *hd; struct PendingMessage *tl; struct GNUNET_TIME_Absolute now; char *cbuf; size_t ret; GNUNET_assert (NULL != session); session->transmit_handle = NULL; plugin = session->plugin; if (NULL == buf) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Timeout trying to transmit to peer `%4s', discarding message queue.\n", GNUNET_i2s (&session->target)); /* timeout; cancel all messages that have already expired */ hd = NULL; tl = NULL; ret = 0; now = GNUNET_TIME_absolute_get (); while ((NULL != (pos = session->pending_messages_head)) && (pos->timeout.abs_value <= now.abs_value)) { GNUNET_CONTAINER_DLL_remove (session->pending_messages_head, session->pending_messages_tail, pos); LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to transmit %u byte message to `%4s'.\n", pos->message_size, GNUNET_i2s (&session->target)); ret += pos->message_size; GNUNET_CONTAINER_DLL_insert_after (hd, tl, tl, pos); } /* do this call before callbacks (so that if callbacks destroy * session, they have a chance to cancel actions done by this * call) */ process_pending_messages (session); pid = session->target; /* no do callbacks and do not use session again since * the callbacks may abort the session */ while (NULL != (pos = hd)) { GNUNET_CONTAINER_DLL_remove (hd, tl, pos); if (pos->transmit_cont != NULL) pos->transmit_cont (pos->transmit_cont_cls, &pid, GNUNET_SYSERR); GNUNET_free (pos); } GNUNET_STATISTICS_update (plugin->env->stats, gettext_noop ("# bytes currently in TCP buffers"), -(int64_t) ret, GNUNET_NO); GNUNET_STATISTICS_update (plugin->env->stats, gettext_noop ("# bytes discarded by TCP (timeout)"), ret, GNUNET_NO); return 0; } /* copy all pending messages that would fit */ ret = 0; cbuf = buf; hd = NULL; tl = NULL; while (NULL != (pos = session->pending_messages_head)) { if (ret + pos->message_size > size) break; GNUNET_CONTAINER_DLL_remove (session->pending_messages_head, session->pending_messages_tail, pos); GNUNET_assert (size >= pos->message_size); LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting message of type %u\n", ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type)); /* FIXME: this memcpy can be up to 7% of our total runtime */ memcpy (cbuf, pos->msg, pos->message_size); cbuf += pos->message_size; ret += pos->message_size; size -= pos->message_size; GNUNET_CONTAINER_DLL_insert_tail (hd, tl, pos); } /* schedule 'continuation' before callbacks so that callbacks that * cancel everything don't cause us to use a session that no longer * exists... */ process_pending_messages (session); session->last_activity = GNUNET_TIME_absolute_get (); pid = session->target; /* we'll now call callbacks that may cancel the session; hence * we should not use 'session' after this point */ while (NULL != (pos = hd)) { GNUNET_CONTAINER_DLL_remove (hd, tl, pos); if (pos->transmit_cont != NULL) pos->transmit_cont (pos->transmit_cont_cls, &pid, GNUNET_OK); GNUNET_free (pos); } GNUNET_assert (hd == NULL); GNUNET_assert (tl == NULL); LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting %u bytes\n", ret); GNUNET_STATISTICS_update (plugin->env->stats, gettext_noop ("# bytes currently in TCP buffers"), -(int64_t) ret, GNUNET_NO); GNUNET_STATISTICS_update (plugin->env->stats, gettext_noop ("# bytes transmitted via TCP"), ret, GNUNET_NO); return ret; } /** * If we have pending messages, ask the server to * transmit them (schedule the respective tasks, etc.) * * @param session for which session should we do this */ static void process_pending_messages (struct Session *session) { struct PendingMessage *pm; GNUNET_assert (session->client != NULL); if (session->transmit_handle != NULL) return; if (NULL == (pm = session->pending_messages_head)) return; session->transmit_handle = GNUNET_SERVER_notify_transmit_ready (session->client, pm->message_size, GNUNET_TIME_absolute_get_remaining (pm->timeout), &do_transmit, session); } /** * Functions with this signature are called whenever we need * to close a session due to a disconnect or failure to * establish a connection. * * @param session session to close down */ static void disconnect_session (struct Session *session) { struct PendingMessage *pm; struct Plugin * plugin = session->plugin; LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting session of peer `%s' address `%s'\n", GNUNET_i2s (&session->target), tcp_address_to_string (NULL, session->addr, session->addrlen)); stop_session_timeout (session); if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (plugin->sessionmap, &session->target.hashPubKey, session)) { GNUNET_STATISTICS_update (session->plugin->env->stats, gettext_noop ("# TCP sessions active"), -1, GNUNET_NO); dec_sessions (plugin, session, __LINE__); } else GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (plugin->nat_wait_conns, &session->target.hashPubKey, session)); /* clean up state */ if (session->transmit_handle != NULL) { GNUNET_SERVER_notify_transmit_ready_cancel (session->transmit_handle); session->transmit_handle = NULL; } session->plugin->env->session_end (session->plugin->env->cls, &session->target, session); if (GNUNET_SCHEDULER_NO_TASK != session->nat_connection_timeout) { GNUNET_SCHEDULER_cancel (session->nat_connection_timeout); session->nat_connection_timeout = GNUNET_SCHEDULER_NO_TASK; } while (NULL != (pm = session->pending_messages_head)) { LOG (GNUNET_ERROR_TYPE_DEBUG, pm->transmit_cont != NULL ? "Could not deliver message to `%4s'.\n" : "Could not deliver message to `%4s', notifying.\n", GNUNET_i2s (&session->target)); GNUNET_STATISTICS_update (session->plugin->env->stats, gettext_noop ("# bytes currently in TCP buffers"), -(int64_t) pm->message_size, GNUNET_NO); GNUNET_STATISTICS_update (session->plugin->env->stats, gettext_noop ("# bytes discarded by TCP (disconnect)"), pm->message_size, GNUNET_NO); GNUNET_CONTAINER_DLL_remove (session->pending_messages_head, session->pending_messages_tail, pm); if (NULL != pm->transmit_cont) pm->transmit_cont (pm->transmit_cont_cls, &session->target, GNUNET_SYSERR); GNUNET_free (pm); } if (session->receive_delay_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (session->receive_delay_task); if (NULL != session->client) GNUNET_SERVER_receive_done (session->client, GNUNET_SYSERR); } if (NULL != session->client) { GNUNET_SERVER_client_disconnect (session->client); GNUNET_SERVER_client_drop (session->client); session->client = NULL; } GNUNET_free_non_null (session->addr); GNUNET_assert (NULL == session->transmit_handle); GNUNET_free (session); } /** * Function that can be used by the transport service to transmit * a message using the plugin. Note that in the case of a * peer disconnecting, the continuation MUST be called * prior to the disconnect notification itself. This function * will be called with this peer's HELLO message to initiate * a fresh connection to another peer. * * @param cls closure * @param session which session must be used * @param msgbuf the message to transmit * @param msgbuf_size number of bytes in 'msgbuf' * @param priority how important is the message (most plugins will * ignore message priority and just FIFO) * @param to how long to wait at most for the transmission (does not * require plugins to discard the message after the timeout, * just advisory for the desired delay; most plugins will ignore * this as well) * @param cont continuation to call once the message has * been transmitted (or if the transport is ready * for the next transmission call; or if the * peer disconnected...); can be NULL * @param cont_cls closure for cont * @return number of bytes used (on the physical network, with overheads); * -1 on hard errors (i.e. address invalid); 0 is a legal value * and does NOT mean that the message was not transmitted (DV) */ static ssize_t tcp_plugin_send (void *cls, struct Session *session, const char *msgbuf, size_t msgbuf_size, unsigned int priority, struct GNUNET_TIME_Relative to, GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) { struct Plugin * plugin = cls; struct PendingMessage *pm; GNUNET_assert (NULL != plugin); GNUNET_assert (NULL != session); /* create new message entry */ pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size); pm->msg = (const char *) &pm[1]; memcpy (&pm[1], msgbuf, msgbuf_size); pm->message_size = msgbuf_size; pm->timeout = GNUNET_TIME_relative_to_absolute (to); pm->transmit_cont = cont; pm->transmit_cont_cls = cont_cls; LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to transmit %u bytes to `%s', added message to list.\n", msgbuf_size, GNUNET_i2s (&session->target)); reschedule_session_timeout (session); if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains_value(plugin->sessionmap, &session->target.hashPubKey, session)) { GNUNET_assert (session->client != NULL); GNUNET_SERVER_client_set_timeout (session->client, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); GNUNET_STATISTICS_update (plugin->env->stats, gettext_noop ("# bytes currently in TCP buffers"), msgbuf_size, GNUNET_NO); /* append pm to pending_messages list */ GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head, session->pending_messages_tail, pm); process_pending_messages (session); return msgbuf_size; } else if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains_value(plugin->nat_wait_conns, &session->target.hashPubKey, session)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "This NAT WAIT session for peer `%s' is not yet ready!\n", GNUNET_i2s (&session->target)); GNUNET_STATISTICS_update (plugin->env->stats, gettext_noop ("# bytes currently in TCP buffers"), msgbuf_size, GNUNET_NO); /* append pm to pending_messages list */ GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head, session->pending_messages_tail, pm); return msgbuf_size; } else { if (NULL != cont) cont (cont_cls, &session->target, GNUNET_SYSERR); GNUNET_break (0); GNUNET_free (pm); return GNUNET_SYSERR; /* session does not exist here */ } } struct SessionItCtx { void *addr; size_t addrlen; struct Session *result; }; static int session_lookup_it (void *cls, const GNUNET_HashCode *key, void *value) { struct SessionItCtx * si_ctx = cls; struct Session * session = value; #if 0 char * a1 = strdup (tcp_address_to_string(NULL, session->addr, session->addrlen)); char * a2 = strdup (tcp_address_to_string(NULL, si_ctx->addr, si_ctx->addrlen)); LOG (GNUNET_ERROR_TYPE_DEBUG, "Comparing: %s %u <-> %s %u\n", a1, session->addrlen, a2, si_ctx->addrlen); GNUNET_free (a1); GNUNET_free (a2); #endif if (session->addrlen != si_ctx->addrlen) { return GNUNET_YES; } if (0 != memcmp (session->addr, si_ctx->addr, si_ctx->addrlen)) { return GNUNET_YES; } #if 0 a1 = strdup (tcp_address_to_string(NULL, session->addr, session->addrlen)); a2 = strdup (tcp_address_to_string(NULL, si_ctx->addr, si_ctx->addrlen)); LOG (GNUNET_ERROR_TYPE_DEBUG, "Comparing: %s %u <-> %s %u , OK!\n", a1, session->addrlen, a2, si_ctx->addrlen); GNUNET_free (a1); GNUNET_free (a2); #endif /* Found existing session */ si_ctx->result = session; return GNUNET_NO; } /** * Task cleaning up a NAT connection attempt after timeout */ static void nat_connect_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Session *session = cls; LOG (GNUNET_ERROR_TYPE_DEBUG, "NAT WAIT connection to `%4s' at `%s' could not be established, removing session\n", GNUNET_i2s (&session->target), tcp_address_to_string(NULL, session->addr, session->addrlen)); disconnect_session (session); } /** * Create a new session to transmit data to the target * This session will used to send data to this peer and the plugin will * notify us by calling the env->session_end function * * @param cls closure * @param address pointer to the GNUNET_HELLO_Address * @return the session if the address is valid, NULL otherwise */ static struct Session * tcp_plugin_get_session (void *cls, const struct GNUNET_HELLO_Address *address) { struct Plugin * plugin = cls; struct Session * session = NULL; int af; const void *sb; size_t sbs; struct GNUNET_CONNECTION_Handle *sa; struct sockaddr_in a4; struct sockaddr_in6 a6; const struct IPv4TcpAddress *t4; const struct IPv6TcpAddress *t6; struct GNUNET_ATS_Information ats; unsigned int is_natd = GNUNET_NO; size_t addrlen; GNUNET_assert (plugin != NULL); GNUNET_assert (address != NULL); addrlen = address->address_length; LOG (GNUNET_ERROR_TYPE_DEBUG, "Trying to get session for `%s' address of peer `%s'\n", tcp_address_to_string(NULL, address->address, address->address_length), GNUNET_i2s (&address->peer)); /* look for existing session */ if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(plugin->sessionmap, &address->peer.hashPubKey)) { struct SessionItCtx si_ctx; si_ctx.addr = (void *) address->address; si_ctx.addrlen = address->address_length; si_ctx.result = NULL; GNUNET_CONTAINER_multihashmap_get_multiple(plugin->sessionmap, &address->peer.hashPubKey, &session_lookup_it, &si_ctx); if (si_ctx.result != NULL) { session = si_ctx.result; LOG (GNUNET_ERROR_TYPE_DEBUG, "Found exisiting session for `%s' address `%s' session %p\n", GNUNET_i2s (&address->peer), tcp_address_to_string(NULL, address->address, address->address_length), session); return session; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Existing sessions did not match address `%s' or peer `%s'\n", tcp_address_to_string(NULL, address->address, address->address_length), GNUNET_i2s (&address->peer)); } if (addrlen == sizeof (struct IPv6TcpAddress)) { GNUNET_assert (NULL != address->address); /* make static analysis happy */ t6 = address->address; af = AF_INET6; memset (&a6, 0, sizeof (a6)); #if HAVE_SOCKADDR_IN_SIN_LEN a6.sin6_len = sizeof (a6); #endif a6.sin6_family = AF_INET6; a6.sin6_port = t6->t6_port; if (t6->t6_port == 0) is_natd = GNUNET_YES; memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof (struct in6_addr)); sb = &a6; sbs = sizeof (a6); } else if (addrlen == sizeof (struct IPv4TcpAddress)) { GNUNET_assert (NULL != address->address); /* make static analysis happy */ t4 = address->address; af = AF_INET; memset (&a4, 0, sizeof (a4)); #if HAVE_SOCKADDR_IN_SIN_LEN a4.sin_len = sizeof (a4); #endif a4.sin_family = AF_INET; a4.sin_port = t4->t4_port; if (t4->t4_port == 0) is_natd = GNUNET_YES; a4.sin_addr.s_addr = t4->ipv4_addr; sb = &a4; sbs = sizeof (a4); } else { LOG (GNUNET_ERROR_TYPE_ERROR, _("Address of unexpected length: %u\n"), addrlen); GNUNET_break (0); return NULL; } ats = plugin->env->get_address_type (plugin->env->cls, sb ,sbs); if ((is_natd == GNUNET_YES) && (addrlen == sizeof (struct IPv6TcpAddress))) { /* NAT client only works with IPv4 addresses */ return NULL; } if (0 == plugin->max_connections) { /* saturated */ return NULL; } if ((is_natd == GNUNET_YES) && (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (plugin->nat_wait_conns, &address->peer.hashPubKey))) { /* Only do one NAT punch attempt per peer identity */ return NULL; } if ((is_natd == GNUNET_YES) && (NULL != plugin->nat) && (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (plugin->nat_wait_conns, &address->peer.hashPubKey))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Found valid IPv4 NAT address (creating session)!\n") ; session = create_session (plugin, &address->peer, NULL, GNUNET_YES); session->addrlen = 0; session->addr = NULL; session->ats_address_network_type = ats.value; session->nat_connection_timeout = GNUNET_SCHEDULER_add_delayed(NAT_TIMEOUT, &nat_connect_timeout, session); GNUNET_assert (session != NULL); GNUNET_assert (GNUNET_CONTAINER_multihashmap_put (plugin->nat_wait_conns, &address->peer.hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) == GNUNET_OK); LOG (GNUNET_ERROR_TYPE_DEBUG, "Created NAT WAIT connection to `%4s' at `%s'\n", GNUNET_i2s (&session->target), GNUNET_a2s (sb, sbs)); if (GNUNET_OK == GNUNET_NAT_run_client (plugin->nat, &a4)) return session; else { LOG (GNUNET_ERROR_TYPE_DEBUG, "Running NAT client for `%4s' at `%s' failed\n", GNUNET_i2s (&session->target), GNUNET_a2s (sb, sbs)); disconnect_session (session); return NULL; } } /* create new outbound session */ GNUNET_assert (0 != plugin->max_connections); sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs); if (sa == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to create connection to `%4s' at `%s'\n", GNUNET_i2s (&session->target), GNUNET_a2s (sb, sbs)); return NULL; } plugin->max_connections--; LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to transmit to `%4s', creating fresh session using address `%s'.\n", GNUNET_i2s (&address->peer), GNUNET_a2s (sb, sbs)); session = create_session (plugin, &address->peer, GNUNET_SERVER_connect_socket (plugin->server, sa), GNUNET_NO); session->addr = GNUNET_malloc (addrlen); memcpy (session->addr, address->address, addrlen); session->addrlen = addrlen; session->ats_address_network_type = ats.value; GNUNET_CONTAINER_multihashmap_put(plugin->sessionmap, &address->peer.hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); inc_sessions (plugin, session, __LINE__); LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating new session for `%s' address `%s' session %p\n", GNUNET_i2s (&address->peer), tcp_address_to_string(NULL, address->address, address->address_length), session); /* Send TCP Welcome */ process_pending_messages (session); return session; } static int session_disconnect_it (void *cls, const GNUNET_HashCode * key, void *value) { struct Session *session = value; GNUNET_STATISTICS_update (session->plugin->env->stats, gettext_noop ("# transport-service disconnect requests for TCP"), 1, GNUNET_NO); disconnect_session (session); return GNUNET_YES; } /** * Function that can be called to force a disconnect from the * specified neighbour. This should also cancel all previously * scheduled transmissions. Obviously the transmission may have been * partially completed already, which is OK. The plugin is supposed * to close the connection (if applicable) and no longer call the * transmit continuation(s). * * Finally, plugin MUST NOT call the services's receive function to * notify the service that the connection to the specified target was * closed after a getting this call. * * @param cls closure * @param target peer for which the last transmission is * to be cancelled */ static void tcp_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) { struct Plugin *plugin = cls; LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s'\n", GNUNET_i2s (target)); GNUNET_CONTAINER_multihashmap_get_multiple (plugin->sessionmap, &target->hashPubKey, &session_disconnect_it, plugin); GNUNET_CONTAINER_multihashmap_get_multiple (plugin->nat_wait_conns, &target->hashPubKey, &session_disconnect_it, plugin); } /** * Context for address to string conversion. */ struct PrettyPrinterContext { /** * Function to call with the result. */ GNUNET_TRANSPORT_AddressStringCallback asc; /** * Clsoure for 'asc'. */ void *asc_cls; /** * Port to add after the IP address. */ uint16_t port; int ipv6; }; /** * Append our port and forward the result. * * @param cls the 'struct PrettyPrinterContext*' * @param hostname hostname part of the address */ static void append_port (void *cls, const char *hostname) { struct PrettyPrinterContext *ppc = cls; char *ret; if (hostname == NULL) { ppc->asc (ppc->asc_cls, NULL); GNUNET_free (ppc); return; } if (GNUNET_YES == ppc->ipv6) GNUNET_asprintf (&ret, "[%s]:%d", hostname, ppc->port); else GNUNET_asprintf (&ret, "%s:%d", hostname, ppc->port); ppc->asc (ppc->asc_cls, ret); GNUNET_free (ret); } /** * Convert the transports address to a nice, human-readable * format. * * @param cls closure * @param type name of the transport that generated the address * @param addr one of the addresses of the host, NULL for the last address * the specific address format depends on the transport * @param addrlen length of the address * @param numeric should (IP) addresses be displayed in numeric form? * @param timeout after how long should we give up? * @param asc function to call on each string * @param asc_cls closure for asc */ static void tcp_plugin_address_pretty_printer (void *cls, const char *type, const void *addr, size_t addrlen, int numeric, struct GNUNET_TIME_Relative timeout, GNUNET_TRANSPORT_AddressStringCallback asc, void *asc_cls) { struct PrettyPrinterContext *ppc; const void *sb; size_t sbs; struct sockaddr_in a4; struct sockaddr_in6 a6; const struct IPv4TcpAddress *t4; const struct IPv6TcpAddress *t6; uint16_t port; if (addrlen == sizeof (struct IPv6TcpAddress)) { t6 = addr; memset (&a6, 0, sizeof (a6)); a6.sin6_family = AF_INET6; a6.sin6_port = t6->t6_port; memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof (struct in6_addr)); port = ntohs (t6->t6_port); sb = &a6; sbs = sizeof (a6); } else if (addrlen == sizeof (struct IPv4TcpAddress)) { t4 = addr; memset (&a4, 0, sizeof (a4)); a4.sin_family = AF_INET; a4.sin_port = t4->t4_port; a4.sin_addr.s_addr = t4->ipv4_addr; port = ntohs (t4->t4_port); sb = &a4; sbs = sizeof (a4); } else if (0 == addrlen) { asc (asc_cls, ""); asc (asc_cls, NULL); return; } else { /* invalid address */ GNUNET_break_op (0); asc (asc_cls, NULL); return; } ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext)); if (addrlen == sizeof (struct IPv6TcpAddress)) ppc->ipv6 = GNUNET_YES; else ppc->ipv6 = GNUNET_NO; ppc->asc = asc; ppc->asc_cls = asc_cls; ppc->port = port; GNUNET_RESOLVER_hostname_get (sb, sbs, !numeric, timeout, &append_port, ppc); } /** * Check if the given port is plausible (must be either our listen * port or our advertised port), or any port if we are behind NAT * and do not have a port open. If it is neither, we return * GNUNET_SYSERR. * * @param plugin global variables * @param in_port port number to check * @return GNUNET_OK if port is either open_port or adv_port */ static int check_port (struct Plugin *plugin, uint16_t in_port) { if ((in_port == plugin->adv_port) || (in_port == plugin->open_port)) return GNUNET_OK; return GNUNET_SYSERR; } /** * Function that will be called to check if a binary address for this * plugin is well-formed and corresponds to an address for THIS peer * (as per our configuration). Naturally, if absolutely necessary, * plugins can be a bit conservative in their answer, but in general * plugins should make sure that the address does not redirect * traffic to a 3rd party that might try to man-in-the-middle our * traffic. * * @param cls closure, our 'struct Plugin*' * @param addr pointer to the address * @param addrlen length of addr * @return GNUNET_OK if this is a plausible address for this peer * and transport, GNUNET_SYSERR if not */ static int tcp_plugin_check_address (void *cls, const void *addr, size_t addrlen) { struct Plugin *plugin = cls; struct IPv4TcpAddress *v4; struct IPv6TcpAddress *v6; if ((addrlen != sizeof (struct IPv4TcpAddress)) && (addrlen != sizeof (struct IPv6TcpAddress))) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (addrlen == sizeof (struct IPv4TcpAddress)) { v4 = (struct IPv4TcpAddress *) addr; if (GNUNET_OK != check_port (plugin, ntohs (v4->t4_port))) return GNUNET_SYSERR; if (GNUNET_OK != GNUNET_NAT_test_address (plugin->nat, &v4->ipv4_addr, sizeof (struct in_addr))) return GNUNET_SYSERR; } else { v6 = (struct IPv6TcpAddress *) addr; if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr)) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (GNUNET_OK != check_port (plugin, ntohs (v6->t6_port))) return GNUNET_SYSERR; if (GNUNET_OK != GNUNET_NAT_test_address (plugin->nat, &v6->ipv6_addr, sizeof (struct in6_addr))) return GNUNET_SYSERR; } return GNUNET_OK; } /** * We've received a nat probe from this peer via TCP. Finish * creating the client session and resume sending of queued * messages. * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_tcp_nat_probe (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct Plugin *plugin = cls; struct Session *session; const struct TCP_NAT_ProbeMessage *tcp_nat_probe; size_t alen; void *vaddr; struct IPv4TcpAddress *t4; struct IPv6TcpAddress *t6; const struct sockaddr_in *s4; const struct sockaddr_in6 *s6; LOG (GNUNET_ERROR_TYPE_DEBUG, "received NAT probe\n"); /* We have received a TCP NAT probe, meaning we (hopefully) initiated * a connection to this peer by running gnunet-nat-client. This peer * received the punch message and now wants us to use the new connection * as the default for that peer. Do so and then send a WELCOME message * so we can really be connected! */ if (ntohs (message->size) != sizeof (struct TCP_NAT_ProbeMessage)) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message; if (0 == memcmp (&tcp_nat_probe->clientIdentity, plugin->env->my_identity, sizeof (struct GNUNET_PeerIdentity))) { /* refuse connections from ourselves */ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } session = GNUNET_CONTAINER_multihashmap_get (plugin->nat_wait_conns, &tcp_nat_probe-> clientIdentity.hashPubKey); if (session == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Did NOT find session for NAT probe!\n"); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Found session for NAT probe!\n"); if (session->nat_connection_timeout != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (session->nat_connection_timeout); session->nat_connection_timeout = GNUNET_SCHEDULER_NO_TASK; } if (GNUNET_OK != GNUNET_SERVER_client_get_address (client, &vaddr, &alen)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); disconnect_session (session); return; } GNUNET_assert (GNUNET_CONTAINER_multihashmap_remove (plugin->nat_wait_conns, &tcp_nat_probe->clientIdentity.hashPubKey, session) == GNUNET_YES); GNUNET_CONTAINER_multihashmap_put(plugin->sessionmap, &session->target.hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); session->last_activity = GNUNET_TIME_absolute_get (); session->inbound = GNUNET_NO; LOG (GNUNET_ERROR_TYPE_DEBUG, "Found address `%s' for incoming connection\n", GNUNET_a2s (vaddr, alen)); switch (((const struct sockaddr *) vaddr)->sa_family) { case AF_INET: s4 = vaddr; t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress)); t4->t4_port = s4->sin_port; t4->ipv4_addr = s4->sin_addr.s_addr; session->addr = t4; session->addrlen = sizeof (struct IPv4TcpAddress); break; case AF_INET6: s6 = vaddr; t6 = GNUNET_malloc (sizeof (struct IPv6TcpAddress)); t6->t6_port = s6->sin6_port; memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof (struct in6_addr)); session->addr = t6; session->addrlen = sizeof (struct IPv6TcpAddress); break; default: GNUNET_break_op (0); LOG (GNUNET_ERROR_TYPE_DEBUG, "Bad address for incoming connection!\n"); GNUNET_free (vaddr); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); disconnect_session (session); return; } GNUNET_free (vaddr); GNUNET_break (NULL == session->client); GNUNET_SERVER_client_keep (client); session->client = client; inc_sessions (plugin, session, __LINE__); GNUNET_STATISTICS_update (plugin->env->stats, gettext_noop ("# TCP sessions active"), 1, GNUNET_NO); process_pending_messages (session); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * We've received a welcome from this peer via TCP. Possibly create a * fresh client record and send back our welcome. * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_tcp_welcome (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct Plugin *plugin = cls; const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message; struct Session *session; size_t alen; void *vaddr; struct IPv4TcpAddress *t4; struct IPv6TcpAddress *t6; const struct sockaddr_in *s4; const struct sockaddr_in6 *s6; if (0 == memcmp (&wm->clientIdentity, plugin->env->my_identity, sizeof (struct GNUNET_PeerIdentity))) { /* refuse connections from ourselves */ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Received %s message from `%4s'\n", "WELCOME", GNUNET_i2s (&wm->clientIdentity)); GNUNET_STATISTICS_update (plugin->env->stats, gettext_noop ("# TCP WELCOME messages received"), 1, GNUNET_NO); session = lookup_session_by_client (plugin, client); if (session != NULL) { if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Found existing session %p for peer `%s'\n", session, GNUNET_a2s (vaddr, alen)); GNUNET_free (vaddr); } } else { GNUNET_SERVER_client_keep (client); session = create_session (plugin, &wm->clientIdentity, client, GNUNET_NO); session->inbound = GNUNET_YES; if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen)) { if (alen == sizeof (struct sockaddr_in)) { s4 = vaddr; t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress)); t4->t4_port = s4->sin_port; t4->ipv4_addr = s4->sin_addr.s_addr; session->addr = t4; session->addrlen = sizeof (struct IPv4TcpAddress); } else if (alen == sizeof (struct sockaddr_in6)) { s6 = vaddr; t6 = GNUNET_malloc (sizeof (struct IPv6TcpAddress)); t6->t6_port = s6->sin6_port; memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof (struct in6_addr)); session->addr = t6; session->addrlen = sizeof (struct IPv6TcpAddress); } struct GNUNET_ATS_Information ats; ats = plugin->env->get_address_type (plugin->env->cls, vaddr ,alen); session->ats_address_network_type = ats.value; GNUNET_free (vaddr); } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "Did not obtain TCP socket address for incoming connection\n"); } GNUNET_CONTAINER_multihashmap_put(plugin->sessionmap, &wm->clientIdentity.hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); inc_sessions (plugin, session, __LINE__); } if (session->expecting_welcome != GNUNET_YES) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } session->last_activity = GNUNET_TIME_absolute_get (); session->expecting_welcome = GNUNET_NO; process_pending_messages (session); GNUNET_SERVER_client_set_timeout (client, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Task to signal the server that we can continue * receiving from the TCP client now. * * @param cls the 'struct Session*' * @param tc task context (unused) */ static void delayed_done (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Session *session = cls; struct GNUNET_TIME_Relative delay; struct GNUNET_ATS_Information ats; session->receive_delay_task = GNUNET_SCHEDULER_NO_TASK; delay = session->plugin->env->receive (session->plugin->env->cls, &session->target, NULL, &ats, 0, session, NULL, 0); reschedule_session_timeout (session); if (delay.rel_value == 0) GNUNET_SERVER_receive_done (session->client, GNUNET_OK); else session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session); } /** * We've received data for this peer via TCP. Unbox, * compute latency and forward. * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_tcp_data (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct Plugin *plugin = cls; struct Session *session; struct GNUNET_TIME_Relative delay; uint16_t type; type = ntohs (message->type); if ((GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) || (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type)) { /* We don't want to propagate WELCOME and NAT Probe messages up! */ GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } session = lookup_session_by_client (plugin, client); if (NULL == session) { /* No inbound session found */ void *vaddr; size_t alen; GNUNET_SERVER_client_get_address (client, &vaddr, &alen); LOG (GNUNET_ERROR_TYPE_ERROR, "Received unexpected %u bytes of type %u from `%s'\n", (unsigned int) ntohs (message->size), (unsigned int) ntohs (message->type), GNUNET_a2s(vaddr, alen)); GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); GNUNET_free_non_null(vaddr); return; } else if (GNUNET_YES == session->expecting_welcome) { /* Session is expecting WELCOME message */ void *vaddr; size_t alen; GNUNET_SERVER_client_get_address (client, &vaddr, &alen); LOG (GNUNET_ERROR_TYPE_ERROR, "Received unexpected %u bytes of type %u from `%s'\n", (unsigned int) ntohs (message->size), (unsigned int) ntohs (message->type), GNUNET_a2s(vaddr, alen)); GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); GNUNET_free_non_null(vaddr); return; } session->last_activity = GNUNET_TIME_absolute_get (); LOG (GNUNET_ERROR_TYPE_DEBUG, "Passing %u bytes of type %u from `%4s' to transport service.\n", (unsigned int) ntohs (message->size), (unsigned int) ntohs (message->type), GNUNET_i2s (&session->target)); GNUNET_STATISTICS_update (plugin->env->stats, gettext_noop ("# bytes received via TCP"), ntohs (message->size), GNUNET_NO); struct GNUNET_ATS_Information distance[2]; distance[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); distance[0].value = htonl (1); distance[1].type = htonl (GNUNET_ATS_NETWORK_TYPE); distance[1].value = session->ats_address_network_type; GNUNET_break (ntohl(session->ats_address_network_type) != GNUNET_ATS_NET_UNSPECIFIED); GNUNET_assert (GNUNET_CONTAINER_multihashmap_contains_value (plugin->sessionmap, &session->target.hashPubKey, session)); delay = plugin->env->receive (plugin->env->cls, &session->target, message, (const struct GNUNET_ATS_Information *) &distance, 1, session, (GNUNET_YES == session->inbound) ? NULL : session->addr, (GNUNET_YES == session->inbound) ? 0 : session->addrlen); reschedule_session_timeout (session); if (delay.rel_value == 0) { GNUNET_SERVER_receive_done (client, GNUNET_OK); } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "Throttling receiving from `%s' for %llu ms\n", GNUNET_i2s (&session->target), (unsigned long long) delay.rel_value); GNUNET_SERVER_disable_receive_done_warning (client); session->receive_delay_task = GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session); } } /** * Functions with this signature are called whenever a peer * is disconnected on the network level. * * @param cls closure * @param client identification of the client */ static void disconnect_notify (void *cls, struct GNUNET_SERVER_Client *client) { struct Plugin *plugin = cls; struct Session *session; if (client == NULL) return; plugin->max_connections++; session = lookup_session_by_client (plugin, client); if (session == NULL) return; /* unknown, nothing to do */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying session of `%4s' with %s due to network-level disconnect.\n", GNUNET_i2s (&session->target), (session->addr != NULL) ? tcp_address_to_string (session->plugin, session->addr, session->addrlen) : "*"); GNUNET_STATISTICS_update (session->plugin->env->stats, gettext_noop ("# network-level TCP disconnect events"), 1, GNUNET_NO); disconnect_session (session); } /** * We can now send a probe message, copy into buffer to really send. * * @param cls closure, a struct TCPProbeContext * @param size max size to copy * @param buf buffer to copy message to * @return number of bytes copied into buf */ static size_t notify_send_probe (void *cls, size_t size, void *buf) { struct TCPProbeContext *tcp_probe_ctx = cls; struct Plugin *plugin = tcp_probe_ctx->plugin; size_t ret; tcp_probe_ctx->transmit_handle = NULL; GNUNET_CONTAINER_DLL_remove (plugin->probe_head, plugin->probe_tail, tcp_probe_ctx); if (buf == NULL) { GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock); GNUNET_free (tcp_probe_ctx); return 0; } GNUNET_assert (size >= sizeof (tcp_probe_ctx->message)); memcpy (buf, &tcp_probe_ctx->message, sizeof (tcp_probe_ctx->message)); GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server, tcp_probe_ctx->sock); ret = sizeof (tcp_probe_ctx->message); GNUNET_free (tcp_probe_ctx); return ret; } /** * Function called by the NAT subsystem suggesting another peer wants * to connect to us via connection reversal. Try to connect back to the * given IP. * * @param cls closure * @param addr address to try * @param addrlen number of bytes in addr */ static void try_connection_reversal (void *cls, const struct sockaddr *addr, socklen_t addrlen) { struct Plugin *plugin = cls; struct GNUNET_CONNECTION_Handle *sock; struct TCPProbeContext *tcp_probe_ctx; /** * We have received an ICMP response, ostensibly from a peer * that wants to connect to us! Send a message to establish a connection. */ sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET, addr, addrlen); if (sock == NULL) { /* failed for some odd reason (out of sockets?); ignore attempt */ return; } /* FIXME: do we need to track these probe context objects so that * we can clean them up on plugin unload? */ tcp_probe_ctx = GNUNET_malloc (sizeof (struct TCPProbeContext)); tcp_probe_ctx->message.header.size = htons (sizeof (struct TCP_NAT_ProbeMessage)); tcp_probe_ctx->message.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE); memcpy (&tcp_probe_ctx->message.clientIdentity, plugin->env->my_identity, sizeof (struct GNUNET_PeerIdentity)); tcp_probe_ctx->plugin = plugin; tcp_probe_ctx->sock = sock; GNUNET_CONTAINER_DLL_insert (plugin->probe_head, plugin->probe_tail, tcp_probe_ctx); tcp_probe_ctx->transmit_handle = GNUNET_CONNECTION_notify_transmit_ready (sock, ntohs (tcp_probe_ctx-> message.header.size), GNUNET_TIME_UNIT_FOREVER_REL, ¬ify_send_probe, tcp_probe_ctx); } /** * Session was idle, so disconnect it */ static void session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_assert (NULL != cls); struct Session *s = cls; s->timeout_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Session %p was idle for %llu, disconnecting\n", s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); /* call session destroy function */ disconnect_session(s); } /** * Start session timeout */ static void start_session_timeout (struct Session *s) { GNUNET_assert (NULL != s); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == s->timeout_task); s->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, &session_timeout, s); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout for session %p set to %llu\n", s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); } /** * Increment session timeout due to activity */ static void reschedule_session_timeout (struct Session *s) { GNUNET_assert (NULL != s); if (GNUNET_SCHEDULER_NO_TASK == s->timeout_task) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout for peer `%s' %s not scheduled\n", GNUNET_i2s (&s->target), tcp_address_to_string(NULL, s->addr, s->addrlen)); return; } GNUNET_SCHEDULER_cancel (s->timeout_task); s->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, &session_timeout, s); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout rescheduled for session %p set to %llu\n", s, (unsigned long long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); } /** * Cancel timeout */ static void stop_session_timeout (struct Session *s) { GNUNET_assert (NULL != s); if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task) { GNUNET_SCHEDULER_cancel (s->timeout_task); s->timeout_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout rescheduled for session %p canceled\n", s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout for session %p was not active\n", s); } } /** * Entry point for the plugin. * * @param cls closure, the 'struct GNUNET_TRANSPORT_PluginEnvironment*' * @return the 'struct GNUNET_TRANSPORT_PluginFunctions*' or NULL on error */ void * libgnunet_plugin_transport_tcp_init (void *cls) { static const struct GNUNET_SERVER_MessageHandler my_handlers[] = { {&handle_tcp_welcome, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME, sizeof (struct WelcomeMessage)}, {&handle_tcp_nat_probe, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE, sizeof (struct TCP_NAT_ProbeMessage)}, {&handle_tcp_data, NULL, GNUNET_MESSAGE_TYPE_ALL, 0}, {NULL, NULL, 0, 0} }; struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; struct GNUNET_TRANSPORT_PluginFunctions *api; struct Plugin *plugin; struct GNUNET_SERVICE_Context *service; unsigned long long aport; unsigned long long bport; unsigned long long max_connections; unsigned int i; struct GNUNET_TIME_Relative idle_timeout; int ret; struct sockaddr **addrs; socklen_t *addrlens; if (NULL == env->receive) { /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully initialze the plugin or the API */ api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); api->cls = NULL; api->address_pretty_printer = &tcp_plugin_address_pretty_printer; api->address_to_string = &tcp_address_to_string; api->string_to_address = &tcp_string_to_address; return api; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp", "MAX_CONNECTIONS", &max_connections)) max_connections = 128; aport = 0; if ((GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp", "PORT", &bport)) || (bport > 65535) || ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp", "ADVERTISED-PORT", &aport)) && (aport > 65535))) { LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Require valid port number for service `%s' in configuration!\n"), "transport-tcp"); return NULL; } if (aport == 0) aport = bport; if (bport == 0) aport = 0; if (bport != 0) { service = GNUNET_SERVICE_start ("transport-tcp", env->cfg, GNUNET_SERVICE_OPTION_NONE); if (service == NULL) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Failed to start service.\n")); return NULL; } } else service = NULL; plugin = GNUNET_malloc (sizeof (struct Plugin)); plugin->sessionmap = GNUNET_CONTAINER_multihashmap_create(max_connections); plugin->max_connections = max_connections; plugin->open_port = bport; plugin->adv_port = aport; plugin->env = env; plugin->lsock = NULL; if ((service != NULL) && (GNUNET_SYSERR != (ret = GNUNET_SERVICE_get_server_addresses ("transport-tcp", env->cfg, &addrs, &addrlens)))) { plugin->nat = GNUNET_NAT_register (env->cfg, GNUNET_YES, aport, (unsigned int) ret, (const struct sockaddr **) addrs, addrlens, &tcp_nat_port_map_callback, &try_connection_reversal, plugin); while (ret > 0) { ret--; GNUNET_assert (addrs[ret] != NULL); GNUNET_free (addrs[ret]); } GNUNET_free_non_null (addrs); GNUNET_free_non_null (addrlens); } else { plugin->nat = GNUNET_NAT_register (env->cfg, GNUNET_YES, 0, 0, NULL, NULL, NULL, &try_connection_reversal, plugin); } api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); api->cls = plugin; api->send = &tcp_plugin_send; api->get_session = &tcp_plugin_get_session; api->disconnect = &tcp_plugin_disconnect; api->address_pretty_printer = &tcp_plugin_address_pretty_printer; api->check_address = &tcp_plugin_check_address; api->address_to_string = &tcp_address_to_string; api->string_to_address = &tcp_string_to_address; plugin->service = service; if (service != NULL) { plugin->server = GNUNET_SERVICE_get_server (service); } else { if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (env->cfg, "transport-tcp", "TIMEOUT", &idle_timeout)) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to find option %s in section %s!\n"), "TIMEOUT", "transport-tcp"); if (plugin->nat != NULL) GNUNET_NAT_unregister (plugin->nat); GNUNET_free (plugin); GNUNET_free (api); return NULL; } plugin->server = GNUNET_SERVER_create_with_sockets (&plugin_tcp_access_check, plugin, NULL, idle_timeout, GNUNET_YES); } plugin->handlers = GNUNET_malloc (sizeof (my_handlers)); memcpy (plugin->handlers, my_handlers, sizeof (my_handlers)); for (i = 0; i < sizeof (my_handlers) / sizeof (struct GNUNET_SERVER_MessageHandler); i++) plugin->handlers[i].callback_cls = plugin; GNUNET_SERVER_add_handlers (plugin->server, plugin->handlers); GNUNET_SERVER_disconnect_notify (plugin->server, &disconnect_notify, plugin); plugin->nat_wait_conns = GNUNET_CONTAINER_multihashmap_create (16); if (bport != 0) LOG (GNUNET_ERROR_TYPE_INFO, _("TCP transport listening on port %llu\n"), bport); else LOG (GNUNET_ERROR_TYPE_INFO, _ ("TCP transport not listening on any port (client only)\n")); if (aport != bport) LOG (GNUNET_ERROR_TYPE_INFO, _ ("TCP transport advertises itself as being on port %llu\n"), aport); /* Initially set connections to 0 */ GNUNET_STATISTICS_set(plugin->env->stats, gettext_noop ("# TCP sessions active"), 0, GNUNET_NO); return api; } /** * Exit point from the plugin. */ void * libgnunet_plugin_transport_tcp_done (void *cls) { struct GNUNET_TRANSPORT_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; struct TCPProbeContext *tcp_probe; if (NULL == plugin) { GNUNET_free (api); return NULL; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down TCP plugin\n"); /* Removing leftover sessions */ GNUNET_CONTAINER_multihashmap_iterate(plugin->sessionmap, &session_disconnect_it, NULL); /* Removing leftover NAT sessions */ GNUNET_CONTAINER_multihashmap_iterate(plugin->nat_wait_conns, &session_disconnect_it, NULL); if (plugin->service != NULL) GNUNET_SERVICE_stop (plugin->service); else GNUNET_SERVER_destroy (plugin->server); GNUNET_free (plugin->handlers); if (plugin->nat != NULL) GNUNET_NAT_unregister (plugin->nat); while (NULL != (tcp_probe = plugin->probe_head)) { GNUNET_CONTAINER_DLL_remove (plugin->probe_head, plugin->probe_tail, tcp_probe); GNUNET_CONNECTION_destroy (tcp_probe->sock); GNUNET_free (tcp_probe); } GNUNET_CONTAINER_multihashmap_destroy (plugin->nat_wait_conns); GNUNET_CONTAINER_multihashmap_destroy (plugin->sessionmap); GNUNET_free (plugin); GNUNET_free (api); return NULL; } /* end of plugin_transport_tcp.c */ gnunet-0.9.3/src/transport/test_transport_api_timeout_tcp_peer2.conf0000644000175000017500000000113211750306133023067 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-tcp-p2/ DEFAULTCONFIG = test_transport_api_timeout_tcp_peer2.conf [nat] ALLOW_NAT = NO [transport-tcp] PORT = 12100 [arm] PORT = 12014 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12013 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12012 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12011 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12010 PLUGINS = tcp UNIXPATH = /tmp/gnunet-p2-service-transport.sock gnunet-0.9.3/src/transport/plugin_transport_http.c0000644000175000017500000014241311762202311017404 00000000000000/* This file is part of GNUnet (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/plugin_transport_http.c * @brief http transport service plugin * @author Matthias Wachs */ #include "plugin_transport_http.h" /** * After how long do we expire an address that we * learned from another peer if it is not reconfirmed * by anyone? */ #define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6) /** * Wrapper to manage IPv4 addresses */ struct IPv4HttpAddressWrapper { /** * Linked list next */ struct IPv4HttpAddressWrapper *next; /** * Linked list previous */ struct IPv4HttpAddressWrapper *prev; struct IPv4HttpAddress addr; }; /** * Wrapper for IPv4 addresses. */ struct IPv6HttpAddressWrapper { /** * Linked list next */ struct IPv6HttpAddressWrapper *next; /** * Linked list previous */ struct IPv6HttpAddressWrapper *prev; struct IPv6HttpAddress addr6; }; /** * Context for address to string conversion. */ struct PrettyPrinterContext { /** * Function to call with the result. */ GNUNET_TRANSPORT_AddressStringCallback asc; /** * Plugin */ struct Plugin *plugin; /** * Clsoure for 'asc'. */ void *asc_cls; /** * Port to add after the IP address. */ uint16_t port; uint32_t addrlen; int numeric; }; /** * Encapsulation of all of the state of the plugin. */ struct Plugin; /** * Start session timeout */ static void start_session_timeout (struct Session *s); /** * Increment session timeout due to activity */ static void reschedule_session_timeout (struct Session *s); /** * Cancel timeout */ static void stop_session_timeout (struct Session *s); /** * Append our port and forward the result. * * @param cls the 'struct PrettyPrinterContext*' * @param hostname hostname part of the address */ static void append_port (void *cls, const char *hostname) { struct PrettyPrinterContext *ppc = cls; static char rbuf[INET6_ADDRSTRLEN + 13]; if (hostname == NULL) { ppc->asc (ppc->asc_cls, NULL); GNUNET_free (ppc); return; } #if !BUILD_HTTPS const char *protocol = "http"; #else const char *protocol = "https"; #endif GNUNET_assert ((strlen (hostname) + 7) < (INET6_ADDRSTRLEN + 13)); if (ppc->addrlen == sizeof (struct IPv6HttpAddress)) { if (ppc->numeric == GNUNET_YES) GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://[%s]:%u/", protocol, hostname, ppc->port); else { if (strchr(hostname, ':') != NULL) GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://[%s]:%u/", protocol, hostname, ppc->port); else GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://%s:%u/", protocol, hostname, ppc->port); } } else if (ppc->addrlen == sizeof (struct IPv4HttpAddress)) GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://%s:%u/", protocol, hostname, ppc->port); ppc->asc (ppc->asc_cls, rbuf); } /** * Convert the transports address to a nice, human-readable * format. * * @param cls closure * @param type name of the transport that generated the address * @param addr one of the addresses of the host, NULL for the last address * the specific address format depends on the transport * @param addrlen length of the address * @param numeric should (IP) addresses be displayed in numeric form? * @param timeout after how long should we give up? * @param asc function to call on each string * @param asc_cls closure for asc */ static void http_plugin_address_pretty_printer (void *cls, const char *type, const void *addr, size_t addrlen, int numeric, struct GNUNET_TIME_Relative timeout, GNUNET_TRANSPORT_AddressStringCallback asc, void *asc_cls) { GNUNET_assert (cls != NULL); struct PrettyPrinterContext *ppc; const void *sb; struct sockaddr_in s4; struct sockaddr_in6 s6; size_t sbs; uint16_t port = 0; if ((addrlen == sizeof (struct IPv6HttpAddress)) && (addr != NULL)) { struct IPv6HttpAddress *a6 = (struct IPv6HttpAddress *) addr; s6.sin6_family = AF_INET6; s6.sin6_addr = a6->ipv6_addr; s6.sin6_port = a6->u6_port; #if HAVE_SOCKADDR_IN_SIN_LEN s6.sin6_len = sizeof (struct sockaddr_in6); #endif sb = &s6; sbs = sizeof (struct sockaddr_in6); port = ntohs (a6->u6_port); } else if ((addrlen == sizeof (struct IPv4HttpAddress)) && (addr != NULL)) { struct IPv4HttpAddress *a4 = (struct IPv4HttpAddress *) addr; s4.sin_family = AF_INET; s4.sin_addr.s_addr = a4->ipv4_addr; s4.sin_port = a4->u4_port; #if HAVE_SOCKADDR_IN_SIN_LEN s4.sin_len = sizeof (struct sockaddr_in); #endif sb = &s4; sbs = sizeof (struct sockaddr_in); port = ntohs (a4->u4_port); } else if (0 == addrlen) { asc (asc_cls, ""); asc (asc_cls, NULL); return; } else { /* invalid address */ GNUNET_break_op (0); asc (asc_cls, NULL); return; } ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext)); ppc->asc = asc; ppc->asc_cls = asc_cls; ppc->port = port; ppc->plugin = cls; ppc->addrlen = addrlen; ppc->numeric = numeric; GNUNET_RESOLVER_hostname_get (sb, sbs, !numeric, timeout, &append_port, ppc); } /** * Another peer has suggested an address for this * peer and transport plugin. Check that this could be a valid * address. If so, consider adding it to the list * of addresses. * * @param cls closure * @param addr pointer to the address * @param addrlen length of addr * @return GNUNET_OK if this is a plausible address for this peer * and transport */ static int http_plugin_address_suggested (void *cls, const void *addr, size_t addrlen) { struct Plugin *plugin = cls; struct IPv4HttpAddressWrapper *w_tv4 = plugin->ipv4_addr_head; struct IPv6HttpAddressWrapper *w_tv6 = plugin->ipv6_addr_head; GNUNET_assert (cls != NULL); if ((addrlen != sizeof (struct sockaddr_in)) || (addrlen != sizeof (struct sockaddr_in6))) return GNUNET_SYSERR; if (addrlen == sizeof (struct IPv4HttpAddress)) { struct IPv4HttpAddress *a4 = (struct IPv4HttpAddress *) addr; while (w_tv4 != NULL) { if ((0 == memcmp (&w_tv4->addr.ipv4_addr, &a4->ipv4_addr, sizeof (struct in_addr))) && (w_tv4->addr.u4_port == a4->u4_port)) break; w_tv4 = w_tv4->next; } if (w_tv4 != NULL) return GNUNET_OK; else return GNUNET_SYSERR; } if (addrlen == sizeof (struct sockaddr_in6)) { struct IPv6HttpAddress *a6 = (struct IPv6HttpAddress *) addr; while (w_tv6 != NULL) { if ((0 == memcmp (&w_tv6->addr6.ipv6_addr, &a6->ipv6_addr, sizeof (struct in6_addr))) && (w_tv6->addr6.u6_port == a6->u6_port)) break; w_tv6 = w_tv6->next; } if (w_tv6 != NULL) return GNUNET_OK; else return GNUNET_SYSERR; } return GNUNET_OK; } struct GNUNET_TIME_Relative http_plugin_receive (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, struct Session *session, const char *sender_address, uint16_t sender_address_len) { struct Session *s = cls; struct Plugin *plugin = s->plugin; struct GNUNET_TIME_Relative delay; struct GNUNET_ATS_Information atsi[2]; atsi[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); atsi[0].value = htonl (1); atsi[1].type = htonl (GNUNET_ATS_NETWORK_TYPE); atsi[1].value = session->ats_address_network_type; GNUNET_break (session->ats_address_network_type != ntohl (GNUNET_ATS_NET_UNSPECIFIED)); reschedule_session_timeout (session); delay = plugin->env->receive (plugin->env->cls, &s->target, message, (const struct GNUNET_ATS_Information *) &atsi, 2, s, s->addr, s->addrlen); return delay; } /** * Function called to convert a string address to * a binary address. * * @param cls closure ('struct Plugin*') * @param addr string address * @param addrlen length of the address * @param buf location to store the buffer * If the function returns GNUNET_SYSERR, its contents are undefined. * @param added length of created address * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int http_string_to_address (void *cls, const char *addr, uint16_t addrlen, void **buf, size_t *added) { #if !BUILD_HTTPS char *protocol = "http"; #else char *protocol = "https"; #endif char *addr_str = NULL; struct sockaddr_in addr_4; struct sockaddr_in6 addr_6; struct IPv4HttpAddress * http_4addr; struct IPv6HttpAddress * http_6addr; if ((NULL == addr) || (addrlen == 0)) { GNUNET_break (0); return GNUNET_SYSERR; } if ('\0' != addr[addrlen - 1]) { GNUNET_break (0); return GNUNET_SYSERR; } if (strlen (addr) != addrlen - 1) { GNUNET_break (0); return GNUNET_SYSERR; } /* protocoll + "://" + ":" */ if (addrlen <= (strlen (protocol) + 4)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid address string `%s' to convert to address\n", addr); GNUNET_break (0); return GNUNET_SYSERR; } if (NULL == (addr_str = strstr(addr, "://"))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid address string `%s' to convert to address\n", addr); GNUNET_break (0); return GNUNET_SYSERR; } addr_str = &addr_str[3]; if (addr_str[strlen(addr_str)-1] == '/') addr_str[strlen(addr_str)-1] = '\0'; if (GNUNET_OK == GNUNET_STRINGS_to_address_ipv4(addr_str, strlen(addr_str), &addr_4)) { http_4addr = GNUNET_malloc (sizeof (struct IPv4HttpAddress)); http_4addr->u4_port = addr_4.sin_port; http_4addr->ipv4_addr = (uint32_t) addr_4.sin_addr.s_addr; (*buf) = http_4addr; (*added) = sizeof (struct IPv4HttpAddress); return GNUNET_OK; } if (GNUNET_OK == GNUNET_STRINGS_to_address_ipv6(addr_str, strlen(addr_str), &addr_6)) { http_6addr = GNUNET_malloc (sizeof (struct IPv6HttpAddress)); http_6addr->u6_port = addr_6.sin6_port; http_6addr->ipv6_addr = addr_6.sin6_addr; (*buf) = http_6addr; (*added) = sizeof (struct IPv6HttpAddress); return GNUNET_OK; } GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid address string `%s' to convert to address\n", addr_str); GNUNET_break (0); return GNUNET_SYSERR; } /** * Function called for a quick conversion of the binary address to * a numeric address. Note that the caller must not free the * address and that the next call to this function is allowed * to override the address again. * * @param cls closure * @param addr binary address * @param addrlen length of the address * @return string representing the same address */ const char * http_plugin_address_to_string (void *cls, const void *addr, size_t addrlen) { struct IPv4HttpAddress *a4; struct IPv6HttpAddress *a6; char *address; static char rbuf[INET6_ADDRSTRLEN + 13]; uint16_t port; int res = 0; if (addrlen == sizeof (struct IPv6HttpAddress)) { a6 = (struct IPv6HttpAddress *) addr; address = GNUNET_malloc (INET6_ADDRSTRLEN); GNUNET_assert (NULL != inet_ntop (AF_INET6, &a6->ipv6_addr, address, INET6_ADDRSTRLEN)); port = ntohs (a6->u6_port); } else if (addrlen == sizeof (struct IPv4HttpAddress)) { a4 = (struct IPv4HttpAddress *) addr; address = GNUNET_malloc (INET_ADDRSTRLEN); GNUNET_assert (NULL != inet_ntop (AF_INET, &(a4->ipv4_addr), address, INET_ADDRSTRLEN)); port = ntohs (a4->u4_port); } else { /* invalid address */ GNUNET_break (0); return NULL; } #if !BUILD_HTTPS char *protocol = "http"; #else char *protocol = "https"; #endif GNUNET_assert (strlen (address) + 7 < (INET6_ADDRSTRLEN + 13)); if (addrlen == sizeof (struct IPv6HttpAddress)) res = GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://[%s]:%u/", protocol, address, port); else if (addrlen == sizeof (struct IPv4HttpAddress)) res = GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://%s:%u/", protocol, address, port); GNUNET_free (address); GNUNET_assert (res != 0); return rbuf; } struct Session * lookup_session_old (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, struct Session *session, const void *addr, size_t addrlen, int force_address) { struct Session *t; int e_peer; int e_addr; for (t = plugin->head; NULL != t; t = t->next) { #if 0 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "Comparing peer `%s' address `%s' len %i session %p to \n", GNUNET_i2s (target), GNUNET_a2s (addr, addrlen), addrlen, session); GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "peer `%s' address `%s' len %i session %p \n\n", GNUNET_i2s (&t->target), GNUNET_a2s (t->addr, t->addrlen), t->addrlen, t); GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "memcmp %i \n", memcmp (addr, t->addr, addrlen)); #endif e_peer = GNUNET_NO; e_addr = GNUNET_NO; if (0 == memcmp (target, &t->target, sizeof (struct GNUNET_PeerIdentity))) { e_peer = GNUNET_YES; if ( (addrlen == t->addrlen) && (0 == memcmp (addr, t->addr, addrlen)) ) e_addr = GNUNET_YES; if ( (t == session) && (t->addrlen == session->addrlen) && (0 == memcmp (session->addr, t->addr, t->addrlen)) ) e_addr = GNUNET_YES; } if ( ((e_peer == GNUNET_YES) && (force_address == GNUNET_NO)) || ((e_peer == GNUNET_YES) && (force_address == GNUNET_YES) && (e_addr == GNUNET_YES)) || ((e_peer == GNUNET_YES) && (force_address == GNUNET_SYSERR)) ) return t; } return NULL; } struct Session * lookup_session (struct Plugin *plugin, const struct GNUNET_HELLO_Address *address) { struct Session *pos; for (pos = plugin->head; NULL != pos; pos = pos->next) if ( (0 == memcmp (&address->peer, &pos->target, sizeof (struct GNUNET_PeerIdentity))) && (address->address_length == pos->addrlen) && (0 == memcmp (address->address, pos->addr, pos->addrlen)) ) return pos; return NULL; } int exist_session (struct Plugin *plugin, struct Session *s) { struct Session * head; GNUNET_assert (NULL != plugin); GNUNET_assert (NULL != s); for (head = plugin->head; head != NULL; head = head->next) { if (head == s) return GNUNET_YES; } return GNUNET_NO; } void delete_session (struct Session *s) { stop_session_timeout(s); if (s->msg_tk != NULL) { GNUNET_SERVER_mst_destroy (s->msg_tk); s->msg_tk = NULL; } GNUNET_free (s->addr); GNUNET_free_non_null (s->server_recv); GNUNET_free_non_null (s->server_send); GNUNET_free (s); } struct Session * create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, const void *addr, size_t addrlen) { struct Session *s = NULL; GNUNET_assert ((addrlen == sizeof (struct IPv6HttpAddress)) || (addrlen == sizeof (struct IPv4HttpAddress))); s = GNUNET_malloc (sizeof (struct Session)); memcpy (&s->target, target, sizeof (struct GNUNET_PeerIdentity)); s->plugin = plugin; s->addr = GNUNET_malloc (addrlen); memcpy (s->addr, addr, addrlen); s->addrlen = addrlen; s->ats_address_network_type = htonl (GNUNET_ATS_NET_UNSPECIFIED); start_session_timeout(s); return s; } void notify_session_end (void *cls, const struct GNUNET_PeerIdentity *peer, struct Session *s) { struct Plugin *plugin = cls; plugin->env->session_end (plugin->env->cls, peer, s); GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s); delete_session (s); } /** * Creates a new outbound session the transport service will use to send data to the * peer * * @param cls the plugin * @param address the address * @return the session or NULL of max connections exceeded */ static struct Session * http_get_session (void *cls, const struct GNUNET_HELLO_Address *address) { struct Plugin *plugin = cls; struct Session * s = NULL; struct GNUNET_ATS_Information ats; size_t addrlen; GNUNET_assert (plugin != NULL); GNUNET_assert (address != NULL); GNUNET_assert (address->address != NULL); ats.type = htonl (GNUNET_ATS_ARRAY_TERMINATOR); ats.value = htonl (GNUNET_ATS_ARRAY_TERMINATOR); /* find existing session */ s = lookup_session (plugin, address); if (s != NULL) return s; if (plugin->max_connections <= plugin->cur_connections) { GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name, "Maximum number of connections reached, " "cannot connect to peer `%s'\n", GNUNET_i2s (&address->peer)); return NULL; } /* create new session */ addrlen = address->address_length; GNUNET_assert ((addrlen == sizeof (struct IPv6HttpAddress)) || (addrlen == sizeof (struct IPv4HttpAddress))); s = create_session (plugin, &address->peer, address->address, address->address_length); /* Get ATS type */ if (addrlen == sizeof (struct IPv4HttpAddress)) { struct IPv4HttpAddress *a4 = (struct IPv4HttpAddress *) address->address; struct sockaddr_in s4; s4.sin_family = AF_INET; s4.sin_addr.s_addr = a4->ipv4_addr; s4.sin_port = a4->u4_port; #if HAVE_SOCKADDR_IN_SIN_LEN s4.sin_len = sizeof (struct sockaddr_in); #endif ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) &s4, sizeof (struct sockaddr_in)); } if (addrlen == sizeof (struct IPv6HttpAddress)) { struct IPv6HttpAddress *a6 = (struct IPv6HttpAddress *) address->address; struct sockaddr_in6 s6; s6.sin6_family = AF_INET6; s6.sin6_addr = a6->ipv6_addr; s6.sin6_port = a6->u6_port; #if HAVE_SOCKADDR_IN_SIN_LEN s6.sin6_len = sizeof (struct sockaddr_in6); #endif ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) &s6, sizeof (struct sockaddr_in6)); } s->ats_address_network_type = ats.value; /* add new session */ GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); /* initiate new connection */ if (GNUNET_SYSERR == client_connect (s)) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "Cannot connect to peer `%s' address `%s''\n", http_plugin_address_to_string(NULL, s->addr, s->addrlen), GNUNET_i2s (&s->target)); GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s); delete_session (s); return NULL; } return s; } /** * Function that can be used by the transport service to transmit * a message using the plugin. Note that in the case of a * peer disconnecting, the continuation MUST be called * prior to the disconnect notification itself. This function * will be called with this peer's HELLO message to initiate * a fresh connection to another peer. * * @param cls closure * @param session which session must be used * @param msgbuf the message to transmit * @param msgbuf_size number of bytes in 'msgbuf' * @param priority how important is the message (most plugins will * ignore message priority and just FIFO) * @param to how long to wait at most for the transmission (does not * require plugins to discard the message after the timeout, * just advisory for the desired delay; most plugins will ignore * this as well) * @param cont continuation to call once the message has * been transmitted (or if the transport is ready * for the next transmission call; or if the * peer disconnected...); can be NULL * @param cont_cls closure for cont * @return number of bytes used (on the physical network, with overheads); * -1 on hard errors (i.e. address invalid); 0 is a legal value * and does NOT mean that the message was not transmitted (DV) */ static ssize_t http_plugin_send (void *cls, struct Session *session, const char *msgbuf, size_t msgbuf_size, unsigned int priority, struct GNUNET_TIME_Relative to, GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) { struct Plugin *plugin = cls; struct HTTP_Message *msg; struct Session *tmp; size_t res = -1; GNUNET_assert (plugin != NULL); GNUNET_assert (session != NULL); /* lookup if session is really existing */ tmp = plugin->head; while (tmp != NULL) { if ((tmp == session) && (0 == memcmp (&session->target, &tmp->target, sizeof (struct GNUNET_PeerIdentity))) && (session->addrlen == tmp->addrlen) && (0 == memcmp (session->addr, tmp->addr, tmp->addrlen))) break; tmp = tmp->next; } if (tmp == NULL) { GNUNET_break_op (0); return res; } /* create new message and schedule */ msg = GNUNET_malloc (sizeof (struct HTTP_Message) + msgbuf_size); msg->next = NULL; msg->size = msgbuf_size; msg->pos = 0; msg->buf = (char *) &msg[1]; msg->transmit_cont = cont; msg->transmit_cont_cls = cont_cls; memcpy (msg->buf, msgbuf, msgbuf_size); reschedule_session_timeout (session); if (session->inbound == GNUNET_NO) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Using outbound client session %p to send to `%s'\n", session, GNUNET_i2s (&session->target)); client_send (session, msg); res = msgbuf_size; } if (session->inbound == GNUNET_YES) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Using inbound server %p session to send to `%s'\n", session, GNUNET_i2s (&session->target)); server_send (session, msg); res = msgbuf_size; } return res; } /** * Function that can be used to force the plugin to disconnect * from the given peer and cancel all previous transmissions * (and their continuationc). * * @param cls closure * @param target peer from which to disconnect */ static void http_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) { struct Plugin *plugin = cls; struct Session *next = NULL; struct Session *s = plugin->head; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Transport tells me to disconnect `%s'\n", GNUNET_i2s (target)); while (s != NULL) { next = s->next; if (0 == memcmp (target, &s->target, sizeof (struct GNUNET_PeerIdentity))) { if (s->inbound == GNUNET_NO) GNUNET_assert (GNUNET_OK == client_disconnect (s)); else GNUNET_assert (GNUNET_OK == server_disconnect (s)); GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s); struct HTTP_Message *msg = s->msg_head; struct HTTP_Message *tmp = NULL; while (msg != NULL) { tmp = msg->next; GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); if (msg->transmit_cont != NULL) { msg->transmit_cont (msg->transmit_cont_cls, target, GNUNET_SYSERR); } GNUNET_free (msg); msg = tmp; } delete_session (s); } s = next; } } static void * find_address (struct Plugin *plugin, const struct sockaddr *addr, socklen_t addrlen) { int af; struct IPv4HttpAddressWrapper *w_t4 = NULL; struct IPv6HttpAddressWrapper *w_t6 = NULL; af = addr->sa_family; switch (af) { case AF_INET: w_t4 = plugin->ipv4_addr_head; struct sockaddr_in *a4 = (struct sockaddr_in *) addr; while (w_t4 != NULL) { int res = memcmp (&w_t4->addr.ipv4_addr, &a4->sin_addr, sizeof (struct in_addr)); if (res == 0) { if (a4->sin_port != w_t4->addr.u4_port) res = -1; } if (0 == res) break; w_t4 = w_t4->next; } return w_t4; break; case AF_INET6: w_t6 = plugin->ipv6_addr_head; struct sockaddr_in6 *a6 = (struct sockaddr_in6 *) addr; while (w_t6) { int res = memcmp (&w_t6->addr6.ipv6_addr, &a6->sin6_addr, sizeof (struct in6_addr)); if (res == 0) { if (a6->sin6_port != w_t6->addr6.u6_port) res = -1; } if (0 == res) break; w_t6 = w_t6->next; } return w_t6; break; default: return NULL; } return NULL; } static void nat_add_address (void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen) { struct Plugin *plugin = cls; struct IPv4HttpAddressWrapper *w_t4 = NULL; struct IPv6HttpAddressWrapper *w_t6 = NULL; int af; af = addr->sa_family; switch (af) { case AF_INET: w_t4 = find_address (plugin, addr, addrlen); if (w_t4 == NULL) { struct sockaddr_in *a4 = (struct sockaddr_in *) addr; w_t4 = GNUNET_malloc (sizeof (struct IPv4HttpAddressWrapper)); memcpy (&w_t4->addr.ipv4_addr, &a4->sin_addr, sizeof (struct in_addr)); w_t4->addr.u4_port = a4->sin_port; GNUNET_CONTAINER_DLL_insert (plugin->ipv4_addr_head, plugin->ipv4_addr_tail, w_t4); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Notifying transport to add IPv4 address `%s'\n", http_plugin_address_to_string (NULL, &w_t4->addr, sizeof (struct IPv4HttpAddress))); plugin->env->notify_address (plugin->env->cls, add_remove, &w_t4->addr, sizeof (struct IPv4HttpAddress)); } break; case AF_INET6: w_t6 = find_address (plugin, addr, addrlen); if (w_t6 == NULL) { w_t6 = GNUNET_malloc (sizeof (struct IPv6HttpAddressWrapper)); struct sockaddr_in6 *a6 = (struct sockaddr_in6 *) addr; memcpy (&w_t6->addr6.ipv6_addr, &a6->sin6_addr, sizeof (struct in6_addr)); w_t6->addr6.u6_port = a6->sin6_port; GNUNET_CONTAINER_DLL_insert (plugin->ipv6_addr_head, plugin->ipv6_addr_tail, w_t6); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Notifying transport to add IPv6 address `%s'\n", http_plugin_address_to_string (NULL, &w_t6->addr6, sizeof (struct IPv6HttpAddress))); plugin->env->notify_address (plugin->env->cls, add_remove, &w_t6->addr6, sizeof (struct IPv6HttpAddress)); } break; default: return; } } static void nat_remove_address (void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen) { struct Plugin *plugin = cls; struct IPv4HttpAddressWrapper *w_t4 = NULL; struct IPv6HttpAddressWrapper *w_t6 = NULL; int af; af = addr->sa_family; switch (af) { case AF_INET: w_t4 = find_address (plugin, addr, addrlen); if (w_t4 == NULL) return; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Notifying transport to remove IPv4 address `%s'\n", http_plugin_address_to_string (NULL, &w_t4->addr, sizeof (struct IPv4HttpAddress))); plugin->env->notify_address (plugin->env->cls, add_remove, &w_t4->addr, sizeof (struct IPv4HttpAddress)); GNUNET_CONTAINER_DLL_remove (plugin->ipv4_addr_head, plugin->ipv4_addr_tail, w_t4); GNUNET_free (w_t4); break; case AF_INET6: w_t6 = find_address (plugin, addr, addrlen); if (w_t6 == NULL) return; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Notifying transport to remove IPv6 address `%s'\n", http_plugin_address_to_string (NULL, &w_t6->addr6, sizeof (struct IPv6HttpAddress))); plugin->env->notify_address (plugin->env->cls, add_remove, &w_t6->addr6, sizeof (struct IPv6HttpAddress)); GNUNET_CONTAINER_DLL_remove (plugin->ipv6_addr_head, plugin->ipv6_addr_tail, w_t6); GNUNET_free (w_t6); break; default: return; } } /** * Our external IP address/port mapping has changed. * * @param cls closure, the 'struct LocalAddrList' * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean * the previous (now invalid) one * @param addr either the previous or the new public IP address * @param addrlen actual lenght of the address */ static void nat_port_map_callback (void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen) { GNUNET_assert (cls != NULL); struct Plugin *plugin = cls; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "NPMC called %s to address `%s'\n", (add_remove == GNUNET_NO) ? "remove" : "add", GNUNET_a2s (addr, addrlen)); switch (add_remove) { case GNUNET_YES: nat_add_address (cls, add_remove, addr, addrlen); break; case GNUNET_NO: nat_remove_address (cls, add_remove, addr, addrlen); break; } } void http_check_ipv6 (struct Plugin *plugin) { struct GNUNET_NETWORK_Handle *desc = NULL; if (plugin->ipv6 == GNUNET_YES) { /* probe IPv6 support */ desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); if (NULL == desc) { if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) || (errno == EACCES)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket"); } GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name, _ ("Disabling IPv6 since it is not supported on this system!\n")); plugin->ipv6 = GNUNET_NO; } else { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc)); desc = NULL; } GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Testing IPv6 on this system: %s\n", (plugin->ipv6 == GNUNET_YES) ? "successful" : "failed"); } } int http_get_addresses (struct Plugin *plugin, const char *serviceName, const struct GNUNET_CONFIGURATION_Handle *cfg, struct sockaddr ***addrs, socklen_t ** addr_lens) { int disablev6; unsigned long long port; struct addrinfo hints; struct addrinfo *res; struct addrinfo *pos; struct addrinfo *next; unsigned int i; int resi; int ret; struct sockaddr **saddrs; socklen_t *saddrlens; char *hostname; *addrs = NULL; *addr_lens = NULL; disablev6 = !plugin->ipv6; port = 0; if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "PORT")) { GNUNET_break (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg, serviceName, "PORT", &port)); if (port > 65535) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Require valid port number for service in configuration!\n")); return GNUNET_SYSERR; } } if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "BINDTO")) { GNUNET_break (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, serviceName, "BINDTO", &hostname)); } else hostname = NULL; if (hostname != NULL) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Resolving `%s' since that is where `%s' will bind to.\n", hostname, serviceName); memset (&hints, 0, sizeof (struct addrinfo)); if (disablev6) hints.ai_family = AF_INET; if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) || (res == NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to resolve `%s': %s\n"), hostname, gai_strerror (ret)); GNUNET_free (hostname); return GNUNET_SYSERR; } next = res; i = 0; while (NULL != (pos = next)) { next = pos->ai_next; if ((disablev6) && (pos->ai_family == AF_INET6)) continue; i++; } if (0 == i) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to find %saddress for `%s'.\n"), disablev6 ? "IPv4 " : "", hostname); freeaddrinfo (res); GNUNET_free (hostname); return GNUNET_SYSERR; } resi = i; saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); i = 0; next = res; while (NULL != (pos = next)) { next = pos->ai_next; if ((disablev6) && (pos->ai_family == AF_INET6)) continue; if ((pos->ai_protocol != IPPROTO_TCP) && (pos->ai_protocol != 0)) continue; /* not TCP */ if ((pos->ai_socktype != SOCK_STREAM) && (pos->ai_socktype != 0)) continue; /* huh? */ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Service will bind to `%s'\n", GNUNET_a2s (pos->ai_addr, pos->ai_addrlen)); if (pos->ai_family == AF_INET) { GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in)); saddrlens[i] = pos->ai_addrlen; saddrs[i] = GNUNET_malloc (saddrlens[i]); memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); } else { GNUNET_assert (pos->ai_family == AF_INET6); GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in6)); saddrlens[i] = pos->ai_addrlen; saddrs[i] = GNUNET_malloc (saddrlens[i]); memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); } i++; } GNUNET_free (hostname); freeaddrinfo (res); resi = i; } else { /* will bind against everything, just set port */ if (disablev6) { /* V4-only */ resi = 1; i = 0; saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); saddrlens[i] = sizeof (struct sockaddr_in); saddrs[i] = GNUNET_malloc (saddrlens[i]); #if HAVE_SOCKADDR_IN_SIN_LEN ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i]; #endif ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET; ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); } else { /* dual stack */ resi = 2; saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); i = 0; saddrlens[i] = sizeof (struct sockaddr_in6); saddrs[i] = GNUNET_malloc (saddrlens[i]); #if HAVE_SOCKADDR_IN_SIN_LEN ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0]; #endif ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6; ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); i++; saddrlens[i] = sizeof (struct sockaddr_in); saddrs[i] = GNUNET_malloc (saddrlens[i]); #if HAVE_SOCKADDR_IN_SIN_LEN ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1]; #endif ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET; ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); } } *addrs = saddrs; *addr_lens = saddrlens; return resi; } static void start_report_addresses (struct Plugin *plugin) { int res = GNUNET_OK; struct sockaddr **addrs; socklen_t *addrlens; res = http_get_addresses (plugin, plugin->name, plugin->env->cfg, &addrs, &addrlens); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, _("Found %u addresses to report to NAT service\n"), res); if (res != GNUNET_SYSERR) { plugin->nat = GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, plugin->port, (unsigned int) res, (const struct sockaddr **) addrs, addrlens, &nat_port_map_callback, NULL, plugin); while (res > 0) { res--; #if 0 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, _("FREEING %s\n"), GNUNET_a2s (addrs[res], addrlens[res])); #endif GNUNET_assert (addrs[res] != NULL); GNUNET_free (addrs[res]); } GNUNET_free_non_null (addrs); GNUNET_free_non_null (addrlens); } else { plugin->nat = GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, 0, 0, NULL, NULL, NULL, NULL, plugin); } } static void stop_report_addresses (struct Plugin *plugin) { /* Stop NAT handle */ GNUNET_NAT_unregister (plugin->nat); /* Clean up addresses */ struct IPv4HttpAddressWrapper *w_t4; struct IPv6HttpAddressWrapper *w_t6; while (plugin->ipv4_addr_head != NULL) { w_t4 = plugin->ipv4_addr_head; GNUNET_CONTAINER_DLL_remove (plugin->ipv4_addr_head, plugin->ipv4_addr_tail, w_t4); GNUNET_free (w_t4); } while (plugin->ipv6_addr_head != NULL) { w_t6 = plugin->ipv6_addr_head; GNUNET_CONTAINER_DLL_remove (plugin->ipv6_addr_head, plugin->ipv6_addr_tail, w_t6); GNUNET_free (w_t6); } } static int configure_plugin (struct Plugin *plugin) { int res = GNUNET_OK; /* Use IPv4? */ if (GNUNET_CONFIGURATION_have_value (plugin->env->cfg, plugin->name, "USE_IPv4")) { plugin->ipv4 = GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name, "USE_IPv4"); } else plugin->ipv4 = GNUNET_YES; /* Use IPv6? */ if (GNUNET_CONFIGURATION_have_value (plugin->env->cfg, plugin->name, "USE_IPv6")) { plugin->ipv6 = GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name, "USE_IPv6"); } else plugin->ipv6 = GNUNET_YES; if ((plugin->ipv4 == GNUNET_NO) && (plugin->ipv6 == GNUNET_NO)) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, _ ("Neither IPv4 nor IPv6 are enabled! Fix in configuration\n"), plugin->name); res = GNUNET_SYSERR; } /* Reading port number from config file */ unsigned long long port; if ((GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name, "PORT", &port)) || (port > 65535)) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, _("Port is required! Fix in configuration\n"), plugin->name); res = GNUNET_SYSERR; goto fail; } plugin->port = port; plugin->client_only = GNUNET_NO; if (plugin->port == 0) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, _("Port 0, client only mode\n")); plugin->client_only = GNUNET_YES; } char *bind4_address = NULL; if ((plugin->ipv4 == GNUNET_YES) && (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name, "BINDTO", &bind4_address))) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Binding %s plugin to specific IPv4 address: `%s'\n", plugin->protocol, bind4_address); plugin->server_addr_v4 = GNUNET_malloc (sizeof (struct sockaddr_in)); if (1 != inet_pton (AF_INET, bind4_address, &plugin->server_addr_v4->sin_addr)) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, _ ("Specific IPv4 address `%s' for plugin %s in configuration file is invalid! Binding to all addresses!\n"), bind4_address, plugin->protocol); GNUNET_free (plugin->server_addr_v4); plugin->server_addr_v4 = NULL; } else { plugin->server_addr_v4->sin_family = AF_INET; plugin->server_addr_v4->sin_port = htons (plugin->port); } GNUNET_free (bind4_address); } char *bind6_address = NULL; if ((plugin->ipv6 == GNUNET_YES) && (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name, "BINDTO6", &bind6_address))) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Binding %s plugin to specific IPv6 address: `%s'\n", plugin->protocol, bind6_address); plugin->server_addr_v6 = GNUNET_malloc (sizeof (struct sockaddr_in6)); if (1 != inet_pton (AF_INET6, bind6_address, &plugin->server_addr_v6->sin6_addr)) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, _ ("Specific IPv6 address `%s' for plugin %s in configuration file is invalid! Binding to all addresses!\n"), bind6_address, plugin->protocol); GNUNET_free (plugin->server_addr_v6); plugin->server_addr_v6 = NULL; } else { plugin->server_addr_v6->sin6_family = AF_INET6; plugin->server_addr_v6->sin6_port = htons (plugin->port); } GNUNET_free (bind6_address); } /* Optional parameters */ unsigned long long maxneigh; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name, "MAX_CONNECTIONS", &maxneigh)) maxneigh = 128; plugin->max_connections = maxneigh; fail: return res; } /** * Session was idle, so disconnect it */ static void session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_assert (NULL != cls); struct Session *s = cls; s->timeout_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Session %p was idle for %llu, disconnecting\n", s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); /* call session destroy function */ if (s->inbound == GNUNET_NO) GNUNET_assert (GNUNET_OK == client_disconnect (s)); else GNUNET_assert (GNUNET_OK == server_disconnect (s)); } /** * Start session timeout */ static void start_session_timeout (struct Session *s) { GNUNET_assert (NULL != s); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == s->timeout_task); s->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, &session_timeout, s); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout for session %p set to %llu\n", s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); } /** * Increment session timeout due to activity */ static void reschedule_session_timeout (struct Session *s) { GNUNET_assert (NULL != s); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task); GNUNET_SCHEDULER_cancel (s->timeout_task); s->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, &session_timeout, s); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout rescheduled for session %p set to %llu\n", s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); } /** * Cancel timeout */ static void stop_session_timeout (struct Session *s) { GNUNET_assert (NULL != s); if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task) { GNUNET_SCHEDULER_cancel (s->timeout_task); s->timeout_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout rescheduled for session %p canceled\n", s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout for session %p was not active\n", s); } } /** * Entry point for the plugin. */ void * LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls) { struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; struct GNUNET_TRANSPORT_PluginFunctions *api; struct Plugin *plugin; int res; if (NULL == env->receive) { /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully initialze the plugin or the API */ api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); api->cls = NULL; api->address_pretty_printer = &http_plugin_address_pretty_printer; api->address_to_string = &http_plugin_address_to_string; api->string_to_address = &http_string_to_address; return api; } plugin = GNUNET_malloc (sizeof (struct Plugin)); plugin->env = env; plugin->outbound_sessions = 0; plugin->inbound_sessions = 0; api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); api->cls = plugin; api->disconnect = &http_plugin_disconnect; api->address_pretty_printer = &http_plugin_address_pretty_printer; api->check_address = &http_plugin_address_suggested; api->address_to_string = &http_plugin_address_to_string; api->string_to_address = &http_string_to_address; api->get_session = &http_get_session; api->send = &http_plugin_send; #if BUILD_HTTPS plugin->name = "transport-https"; plugin->protocol = "https"; #else plugin->name = "transport-http"; plugin->protocol = "http"; #endif /* Configure plugin from configuration */ res = configure_plugin (plugin); if (res == GNUNET_SYSERR) { GNUNET_free_non_null (plugin->server_addr_v4); GNUNET_free_non_null (plugin->server_addr_v6); GNUNET_free (plugin); GNUNET_free (api); return NULL; } /* checking IPv6 support */ http_check_ipv6 (plugin); /* Start client */ res = client_start (plugin); if (res == GNUNET_SYSERR) { GNUNET_free_non_null (plugin->server_addr_v4); GNUNET_free_non_null (plugin->server_addr_v6); GNUNET_free (plugin); GNUNET_free (api); return NULL; } /* Start server */ if (plugin->client_only == GNUNET_NO) { res = server_start (plugin); if (res == GNUNET_SYSERR) { server_stop (plugin); client_stop (plugin); GNUNET_free_non_null (plugin->server_addr_v4); GNUNET_free_non_null (plugin->server_addr_v6); GNUNET_free (plugin); GNUNET_free (api); return NULL; } } /* Report addresses to transport service */ start_report_addresses (plugin); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Plugin `%s' loaded\n", plugin->name); return api; } /** * Exit point from the plugin. */ void * LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls) { struct GNUNET_TRANSPORT_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; struct Session *s; if (NULL == plugin) { GNUNET_free (api); return NULL; } /* Stop reporting addresses to transport service */ stop_report_addresses (plugin); /* cleaning up sessions */ s = plugin->head; while (s != NULL) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Disconnecting `%s' \n", GNUNET_i2s (&s->target)); if (s->inbound == GNUNET_NO) GNUNET_assert (GNUNET_OK == client_disconnect (s)); else GNUNET_assert (GNUNET_OK == server_disconnect (s)); s = s->next; } GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Stopping server\n"); /* Stop server */ server_stop (plugin); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Stopping client\n"); /* Stop client */ client_stop (plugin); /* deleting up sessions */ s = plugin->head; while (s != NULL) { struct Session *t = s->next; GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s); struct HTTP_Message *msg = s->msg_head; struct HTTP_Message *tmp = NULL; while (msg != NULL) { tmp = msg->next; GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); if (msg->transmit_cont != NULL) { msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR); } GNUNET_free (msg); msg = tmp; } delete_session (s); s = t; } GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Plugin `%s' unloaded\n", plugin->name); GNUNET_free_non_null (plugin->server_addr_v4); GNUNET_free_non_null (plugin->server_addr_v6); GNUNET_free (plugin); GNUNET_free (api); return NULL; } /* end of plugin_transport_http.c */ gnunet-0.9.3/src/transport/test_transport_api_reliability_https_peer1.conf0000644000175000017500000000120711665472561024306 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-https-p1/ DEFAULTCONFIG = test_transport_api_reliability_https_peer1.conf [transport-https] PORT = 12300 KEY_FILE = $SERVICEHOME/https_key_p1.key CERT_FILE = $SERVICEHOME/https_cert_p1.crt [arm] PORT = 12305 UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12304 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12303 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12302 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12301 PLUGINS = https UNIXPATH = /tmp/gnunet-p1-service-transport.sock gnunet-0.9.3/src/transport/test_transport_api_disconnect_tcp_peer1.conf0000644000175000017500000000112611750306133023534 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-tcp-p1/ DEFAULTCONFIG = test_transport_api_tcp_peer1.conf [transport-tcp] PORT = 12000 TIMEOUT = 5 s [arm] PORT = 12005 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12004 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12003 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12002 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12001 PLUGINS = tcp UNIXPATH = /tmp/gnunet-p1-service-transport.sock #DEBUG = YES gnunet-0.9.3/src/transport/gnunet-transport-wlan-sender.c0000644000175000017500000001461311760502551020511 00000000000000/* This file is part of GNUnet (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/gnunet-transport-wlan-sender.c * @brief program to send via WLAN as much as possible (to test physical/theoretical throughput) * @author David Brodski */ #include "platform.h" #include "gnunet_protocols.h" #include "plugin_transport_wlan.h" #define WLAN_MTU 1500 /** * LLC fields for better compatibility */ #define WLAN_LLC_DSAP_FIELD 0x1f #define WLAN_LLC_SSAP_FIELD 0x1f #define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */ #define IEEE80211_FC0_VERSION_MASK 0x03 #define IEEE80211_FC0_VERSION_SHIFT 0 #define IEEE80211_FC0_VERSION_0 0x00 #define IEEE80211_FC0_TYPE_MASK 0x0c #define IEEE80211_FC0_TYPE_SHIFT 2 #define IEEE80211_FC0_TYPE_MGT 0x00 #define IEEE80211_FC0_TYPE_CTL 0x04 #define IEEE80211_FC0_TYPE_DATA 0x08 /** * function to fill the radiotap header * @param header pointer to the radiotap header * @param size total message size * @return GNUNET_YES at success */ static int getRadiotapHeader (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *header, uint16_t size) { header->header.size = htons (size); header->header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER); header->rate = 255; header->tx_power = 0; header->antenna = 0; return GNUNET_YES; } /** * function to generate the wlan hardware header for one packet * @param Header address to write the header to * @param to_mac_addr pointer to the address of the recipient * @param mac pointer to the mac address to send from (normally overwritten over by helper) * @param size size of the whole packet, needed to calculate the time to send the packet * @return GNUNET_YES if there was no error */ static int getWlanHeader (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *Header, const struct GNUNET_TRANSPORT_WLAN_MacAddress *to_mac_addr, const struct GNUNET_TRANSPORT_WLAN_MacAddress *mac, unsigned int size) { const int rate = 11000000; Header->frame_control = htons (IEEE80211_FC0_TYPE_DATA); Header->addr3 = mac_bssid_gnunet; Header->addr2 = *mac; Header->addr1 = *to_mac_addr; Header->duration = GNUNET_htole16 ((size * 1000000) / rate + 290); Header->llc[0] = WLAN_LLC_DSAP_FIELD; Header->llc[1] = WLAN_LLC_SSAP_FIELD; Header->llc[2] = 0; // FIXME Header->llc[3] = 0; // FIXME return GNUNET_YES; } int main (int argc, char *argv[]) { char msg_buf[WLAN_MTU]; struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *radiotap; unsigned int temp[6]; struct GNUNET_TRANSPORT_WLAN_MacAddress inmac; struct GNUNET_TRANSPORT_WLAN_MacAddress outmac; int pos; long long count; double bytes_per_s; time_t start; time_t akt; int i; if (4 != argc) { fprintf (stderr, "This program must be started with the interface and the targets and source mac as argument.\n"); fprintf (stderr, "Usage: interface-name mac-target mac-source\n" "e.g. mon0 11-22-33-44-55-66 12-34-56-78-90-ab\n"); return 1; } if (6 != SSCANF (argv[3], "%x-%x-%x-%x-%x-%x", &temp[0], &temp[1], &temp[2], &temp[3], &temp[4], &temp[5])) { fprintf (stderr, "Usage: interface-name mac-target mac-source\n" "e.g. mon0 11-22-33-44-55-66 12-34-56-78-90-ab\n"); return 1; } for (i = 0; i < 6; i++) outmac.mac[i] = temp[i]; if (6 != SSCANF (argv[2], "%x-%x-%x-%x-%x-%x", &temp[0], &temp[1], &temp[2], &temp[3], &temp[4], &temp[5])) { fprintf (stderr, "Usage: interface-name mac-target mac-source\n" "e.g. mon0 11-22-33-44-55-66 12-34-56-78-90-ab\n"); return 1; } for (i = 0; i < 6; i++) inmac.mac[i] = temp[i]; pid_t pid; int commpipe[2]; /* This holds the fd for the input & output of the pipe */ /* Setup communication pipeline first */ if (pipe (commpipe)) { fprintf (stderr, "Failed to create pipe: %s\n", STRERROR (errno)); exit (1); } /* Attempt to fork and check for errors */ if ((pid = fork ()) == -1) { fprintf (stderr, "Failed to fork: %s\n", STRERROR (errno)); exit (1); } if (pid) { /* A positive (non-negative) PID indicates the parent process */ close (commpipe[0]); /* Close unused side of pipe (in side) */ setvbuf (stdout, (char *) NULL, _IONBF, 0); /* Set non-buffered output on stdout */ radiotap = (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) msg_buf; getRadiotapHeader (radiotap, WLAN_MTU); pos = 0; getWlanHeader (&radiotap->frame, &outmac, &inmac, WLAN_MTU); start = time (NULL); count = 0; while (1) { pos += write (commpipe[1], msg_buf, WLAN_MTU - pos); if (pos % WLAN_MTU == 0) { pos = 0; count++; if (count % 1000 == 0) { akt = time (NULL); bytes_per_s = count * WLAN_MTU / (akt - start); bytes_per_s /= 1024; printf ("send %f kbytes/s\n", bytes_per_s); } } } } else { /* A zero PID indicates that this is the child process */ (void) close (0); if (-1 == dup2 (commpipe[0], 0)) /* Replace stdin with the in side of the pipe */ fprintf (stderr, "dup2 failed: %s\n", strerror (errno)); (void) close (commpipe[1]); /* Close unused side of pipe (out side) */ /* Replace the child fork with a new process */ if (execl ("gnunet-helper-transport-wlan", "gnunet-helper-transport-wlan", argv[1], NULL) == -1) { fprintf (stderr, "Could not start gnunet-helper-transport-wlan!"); _exit (1); } } return 0; } gnunet-0.9.3/src/transport/test_transport_api_tcp_peer2.conf0000644000175000017500000000111111760460612021322 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-tcp-p2/ DEFAULTCONFIG = test_transport_api_tcp_peer2.conf [transport-tcp] PORT = 12015 TIMEOUT = 5 s [arm] PORT = 12014 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12013 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12012 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12011 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12010 PLUGINS = tcp UNIXPATH = /tmp/gnunet-p2-service-transport.sock gnunet-0.9.3/src/transport/test_transport_api_unix_peer1.conf0000644000175000017500000000104311646062515021525 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-unix-p1/ DEFAULTCONFIG = test_transport_api_unix_peer1.conf [arm] PORT = 12125 UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12124 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12123 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12122 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12121 PLUGINS = unix UNIXPATH = /tmp/gnunet-p1-service-transport.sock [transport-unix] PORT = 12120 gnunet-0.9.3/src/transport/test_transport_api_tcp_nat_peer1.conf0000644000175000017500000000123111750306133022162 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-tcp-nat-p1/ DEFAULTCONFIG = test_transport_api_tcp_nat_peer1.conf [nat] BEHIND_NAT = YES ENABLE_NAT_SERVER = YES DISABLEV6 = YES [transport-tcp] PORT = 0 TIMEOUT = 5 s [arm] PORT = 1204 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12023 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12022 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12021 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 29542 PLUGINS = tcp UNIXPATH = /tmp/gnunet-p1-service-transport.sock #DEBUG = YES gnunet-0.9.3/src/transport/test_transport_api_unreliability_udp_peer1.conf0000644000175000017500000000110011665472561024267 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-udp-p1/ DEFAULTCONFIG = test_transport_api_unreliability_udp_peer1.conf [transport-udp] PORT = 12040 MAX_BPS = 5000000 [arm] PORT = 12045 UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12044 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12043 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12042 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12041 PLUGINS = udp UNIXPATH = /tmp/gnunet-p1-service-transport.sock gnunet-0.9.3/src/transport/test_transport_defaults.conf0000644000175000017500000000114111760460612020420 00000000000000[PATHS] SERVICEHOME = /tmp/test-transport-api/ DEFAULTCONFIG = test_transport_defaults.conf [transport-tcp] TIMEOUT = 300 s [arm] DEFAULTSERVICES = [transport] PREFIX = [core] AUTOSTART = NO [datastore] AUTOSTART = NO [fs] AUTOSTART = NO [dht] AUTOSTART = NO [mesh] AUTOSTART = NO [nse] AUTOSTART = NO [dns] AUTOSTART = NO [dv] AUTOSTART = NO [gns] AUTOSTART = NO [chat] AUTOSTART = NO [namestore] AUTOSTART = NO [vpn] AUTOSTART = NO [lockmanager] AUTOSTART = NO [nat] DISABLEV6 = YES BINDTO = 127.0.0.1 INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 [TESTING] WEAKRANDOM = YES gnunet-0.9.3/src/transport/test_transport_api_blacklisting.c0000644000175000017500000003042511761756107021424 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/transport_api_blacklisting.c * @brief test for the blacklisting API * @author Matthias Wachs * */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_hello_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_transport_service.h" #include "transport.h" #include "transport-testing.h" #define VERBOSE GNUNET_NO #define VERBOSE_ARM GNUNET_NO #define START_ARM GNUNET_YES struct PeerContext *p1; struct PeerContext *p2; static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; struct GNUNET_TRANSPORT_TransmitHandle *th; struct GNUNET_TRANSPORT_TESTING_handle *tth; /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) /** * How long until we give up on transmitting the message? */ #define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) #define TEST_MESSAGE_SIZE 2600 #define TEST_MESSAGE_TYPE 12345 static int ok; static int connected; static int blacklist_request_p1; static int blacklist_request_p2; struct GNUNET_TRANSPORT_Blacklist * blacklist_p1; struct GNUNET_TRANSPORT_Blacklist * blacklist_p2; static GNUNET_SCHEDULER_TaskIdentifier die_task; static GNUNET_SCHEDULER_TaskIdentifier send_task; static GNUNET_SCHEDULER_TaskIdentifier shutdown_task; #if VERBOSE #define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) #else #define OKPP do { ok++; } while (0) #endif static void end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping\n"); if (send_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (send_task); if (die_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; } if (cc != NULL) { GNUNET_TRANSPORT_TESTING_connect_peers_cancel(tth, cc); cc = NULL; } if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; if (blacklist_p1 != NULL) { GNUNET_TRANSPORT_blacklist_cancel (blacklist_p1); blacklist_p1 = NULL; } if (blacklist_p2 != NULL) { GNUNET_TRANSPORT_blacklist_cancel (blacklist_p2); blacklist_p2 = NULL; } if (p1 != NULL) { GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); p1 = NULL; } if (p2 != NULL) { GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); p2 = NULL; } if ((blacklist_request_p1 == GNUNET_YES) && (blacklist_request_p2 == GNUNET_YES) && (connected == GNUNET_NO)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Peers were not connected, success\n")); ok = 0; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Peers were not connected, fail\n")); ok = 1; } } static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (send_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (send_task); send_task = GNUNET_SCHEDULER_NO_TASK; } if (shutdown_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (shutdown_task); shutdown_task = GNUNET_SCHEDULER_NO_TASK; } if (cc != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n")); GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); cc = NULL; } if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; if (blacklist_p1 != NULL) GNUNET_TRANSPORT_blacklist_cancel (blacklist_p1); if (blacklist_p2 != NULL) GNUNET_TRANSPORT_blacklist_cancel (blacklist_p2); if (p1 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); if (p2 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); ok = GNUNET_SYSERR; } static void notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { struct PeerContext *p = cls; struct PeerContext *t = NULL; if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) t = p1; if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) t = p2; GNUNET_assert (t != NULL); char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') received message of type %d and size %u size from peer %u (`%4s')!\n", p->no, ps, ntohs (message->type), ntohs (message->size), t->no, GNUNET_i2s (&t->id)); GNUNET_free (ps); if ((TEST_MESSAGE_TYPE == ntohs (message->type)) && (TEST_MESSAGE_SIZE == ntohs (message->size))) { ok = 0; shutdown_task = GNUNET_SCHEDULER_add_now(&end, NULL); } else { GNUNET_break (0); ok = 1; shutdown_task = GNUNET_SCHEDULER_add_now(&end, NULL); } } static size_t notify_ready (void *cls, size_t size, void *buf) { struct PeerContext *p = cls; struct GNUNET_MessageHeader *hdr; th = NULL; if (buf == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout occurred while waiting for transmit_ready\n"); if (GNUNET_SCHEDULER_NO_TASK != die_task) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; } die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); ok = 42; return 0; } GNUNET_assert (size >= TEST_MESSAGE_SIZE); if (buf != NULL) { hdr = buf; hdr->size = htons (TEST_MESSAGE_SIZE); hdr->type = htons (TEST_MESSAGE_TYPE); } char *ps = GNUNET_strdup (GNUNET_i2s (&p2->id)); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peer %u (`%4s') sending message with type %u and size %u bytes to peer %u (`%4s')\n", p2->no, ps, ntohs (hdr->type), ntohs (hdr->size), p->no, GNUNET_i2s (&p->id)); GNUNET_free (ps); return TEST_MESSAGE_SIZE; } static void sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { send_task = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; char *receiver_s = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message from peer %u (`%4s') -> peer %u (`%s') !\n", p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s); GNUNET_free (receiver_s); th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, TEST_MESSAGE_SIZE, 0, TIMEOUT_TRANSMIT, ¬ify_ready, p1); } static void notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { static int c; c++; struct PeerContext *p = cls; struct PeerContext *t = NULL; if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) t = p1; if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) t = p2; GNUNET_assert (t != NULL); char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s'): peer %u (`%s') connected to me!\n", p->no, ps, t->no, GNUNET_i2s (peer)); GNUNET_free (ps); } static void notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { struct PeerContext *p = cls; char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s'): peer (`%s') disconnected from me!\n", p->no, ps, GNUNET_i2s (peer)); GNUNET_free (ps); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; } static void testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) { cc = NULL; char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n", p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id)); GNUNET_free (p1_c); send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL); } int blacklist_cb (void *cls, const struct GNUNET_PeerIdentity * pid) { struct PeerContext * p = cls; int res = GNUNET_SYSERR; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u : Blacklist request for peer `%s'\n", p->no, GNUNET_i2s (pid)); if (p == p1) { blacklist_request_p1 = GNUNET_YES; res = GNUNET_OK; } else if (p == p2) { blacklist_request_p2 = GNUNET_YES; res = GNUNET_SYSERR; } if (((blacklist_request_p2 == GNUNET_YES) && (blacklist_request_p1 == GNUNET_YES)) && (shutdown_task == GNUNET_SCHEDULER_NO_TASK)) { shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3), &end, NULL); } return res; } void start_cb (struct PeerContext *p, void *cls) { static int started; started++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, GNUNET_i2s (&p->id)); if (started != 2) return; char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n", p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id)); GNUNET_free (sender_c); cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); connected = GNUNET_NO; blacklist_request_p1 = GNUNET_NO; blacklist_request_p2 = GNUNET_NO; p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, "test_transport_api_tcp_peer1.conf", 1, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, "test_transport_api_tcp_peer2.conf", 2, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); blacklist_p1 = GNUNET_TRANSPORT_blacklist (p1->cfg, &blacklist_cb, p1); blacklist_p2 = GNUNET_TRANSPORT_blacklist (p2->cfg, &blacklist_cb, p2); GNUNET_assert (blacklist_p1 != NULL); GNUNET_assert (blacklist_p2 != NULL); } static int check () { static char *const argv[] = { "test-transport-api-blacklisting", "-c", "test_transport_api_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; #if WRITECONFIG setTransportOptions ("test_transport_api_data.conf"); #endif ok = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-transport-api-blacklisting", "nohelp", options, &run, &ok); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-transport-api-blacklisting", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); tth = GNUNET_TRANSPORT_TESTING_init (); ret = check (); GNUNET_TRANSPORT_TESTING_done (tth); return ret; } /* end of transport_api_blacklisting.c */ gnunet-0.9.3/src/transport/test_transport_api_tcp_peer1.conf0000644000175000017500000000112611750306133021323 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-tcp-p1/ DEFAULTCONFIG = test_transport_api_tcp_peer1.conf [transport-tcp] PORT = 12000 TIMEOUT = 5 s [arm] PORT = 12005 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12004 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12003 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12002 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12001 UNIXPATH = /tmp/gnunet-p1-service-transport.sock PLUGINS = tcp #DEBUG = YES gnunet-0.9.3/src/transport/test_quota_compliance_tcp_peer1.conf0000644000175000017500000000120211750306133021754 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/quota-tcp-p1/ DEFAULTCONFIG = test_quota_compliance_tcp_peer1.conf [transport-tcp] PORT = 4094 [transport-udp] PORT = 4094 [arm] PORT = 4087 UNIXPATH = /tmp/test_quota_compliance_tcp_arm_peer1.sock [statistics] PORT = 4088 UNIXPATH = /tmp/test_quota_compliance_tcp_statistics_peer1.sock [resolver] PORT = 4089 UNIXPATH = /tmp/test_quota_compliance_tcp_resolver_peer1.sock [peerinfo] PORT = 4090 UNIXPATH = /tmp/test_quota_compliance_tcp_peerinfo_peer1.sock [transport] PORT = 4091 PLUGINS = tcp UNIXPATH = /tmp/test_quota_compliance_tcp_transport_peer1.sock gnunet-0.9.3/src/transport/test_transport_testing.c0000644000175000017500000001462111760502551017571 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/test_transport_api.c * @brief base test case for transport implementations * * This test case serves as a base for tcp, udp, and udp-nat * transport test cases. Based on the executable being run * the correct test case will be performed. Conservation of * C code apparently. */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_hello_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_transport_service.h" #include "transport.h" #include "transport-testing.h" #define VERBOSE GNUNET_NO #define VERBOSE_ARM GNUNET_NO #define START_ARM GNUNET_YES /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) GNUNET_SCHEDULER_TaskIdentifier timeout_task; static struct PeerContext *p1; static struct PeerContext *p2; static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; struct GNUNET_TRANSPORT_TESTING_handle *tth; static int connected = GNUNET_NO; static int ret = 0; static void end () { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); if (timeout_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (timeout_task); GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); GNUNET_TRANSPORT_TESTING_done (tth); } static void end_badly () { timeout_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); if (p1 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); if (p2 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); GNUNET_TRANSPORT_TESTING_done (tth); ret = GNUNET_SYSERR; } static void testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) { char *ps = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') connected to peer %u (`%s')!\n", p1->no, ps, p2->no, GNUNET_i2s (&p2->id)); GNUNET_free (ps); GNUNET_SCHEDULER_add_now (&end, NULL); } static void notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' connected \n", GNUNET_i2s (peer)); connected++; } static void notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' disconnected \n", GNUNET_i2s (peer)); } static void notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving\n"); } void start_cb (struct PeerContext *p, void *cls) { static int started; started++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, GNUNET_i2s (&p->id)); if (started != 2) return; char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n", p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id)); GNUNET_free (sender_c); cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { tth = GNUNET_TRANSPORT_TESTING_init (); timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &end_badly, NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting peer\n"); p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, "test_transport_api_tcp_peer1.conf", 1, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, p1); GNUNET_assert (p1->hostkeyfile != NULL); p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, "test_transport_api_tcp_peer2.conf", 2, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, p2); GNUNET_assert (p2->hostkeyfile != NULL); if (p1 == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer1 was not started successfully\n"); if (timeout_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (timeout_task); timeout_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); } if (p2 == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer2 was not started successfully\n"); if (timeout_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (timeout_task); timeout_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); } } int main (int argc, char *argv[]) { GNUNET_log_setup ("test_transport_testing", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); char *const argv_1[] = { "test_transport_testing", "-c", "test_transport_api_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_PROGRAM_run ((sizeof (argv_1) / sizeof (char *)) - 1, argv_1, "test_transport_testing", "nohelp", options, &run, &ret); return ret; } /* end of test_transport_api.c */ gnunet-0.9.3/src/transport/test_transport_api_https_peer1.conf0000644000175000017500000000113411661530125021677 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-https-p1/ DEFAULTCONFIG = test_transport_api_https_peer1.conf [transport-https] PORT = 12100 KEY_FILE = $SERVICEHOME/https_key_p1.key CERT_FILE = $SERVICEHOME/https_cert_p1.crt [arm] PORT = 12105 [statistics] PORT = 12104 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12103 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12102 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12101 PLUGINS = https UNIXPATH = /tmp/gnunet-p1-service-transport.sock DEBUG = NO gnunet-0.9.3/src/transport/transport-testing.h0000644000175000017500000001745011760502551016460 00000000000000/* This file is part of GNUnet. (C) 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport-testing.h * @brief testing lib for transport service * * @author Matthias Wachs */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_getopt_lib.h" #include "gnunet_hello_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_container_lib.h" #include "gnunet_transport_service.h" #define GNUNET_TRANSPORT_TESTING_ConnectRequest void * /** * Context for a single peer */ struct PeerContext; /** * Callback when two peers are connected and both have called the connect callback * to notify clients about a new peer */ typedef void (*GNUNET_TRANSPORT_TESTING_start_cb) (struct PeerContext * p, void *cls); /** * Callback when two peers are connected and both have called the connect callback * to notify clients about a new peer */ typedef void (*GNUNET_TRANSPORT_TESTING_connect_cb) (struct PeerContext * p1, struct PeerContext * p2, void *cls); struct GNUNET_TRANSPORT_TESTING_handle; /** * Context for a single peer */ struct PeerContext { struct PeerContext *next; struct PeerContext *prev; struct GNUNET_TRANSPORT_TESTING_handle *tth; struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_TRANSPORT_Handle *th; struct GNUNET_TRANSPORT_GetHelloHandle *ghh; struct GNUNET_PeerIdentity id; struct GNUNET_OS_Process *arm_proc; GNUNET_TRANSPORT_ReceiveCallback rec; GNUNET_TRANSPORT_NotifyConnect nc; GNUNET_TRANSPORT_NotifyDisconnect nd; GNUNET_TRANSPORT_TESTING_start_cb start_cb; struct GNUNET_HELLO_Message *hello; void *cb_cls; char *servicehome; char *hostkeyfile; unsigned int no; }; struct ConnectingContext { struct ConnectingContext *next; struct ConnectingContext *prev; struct PeerContext *p1; struct PeerContext *p2; GNUNET_SCHEDULER_TaskIdentifier tct; GNUNET_TRANSPORT_TESTING_connect_cb cb; void *cb_cls; struct GNUNET_TRANSPORT_Handle *th_p1; struct GNUNET_TRANSPORT_Handle *th_p2; int p1_c; int p2_c; }; struct GNUNET_TRANSPORT_TESTING_handle { struct ConnectingContext *cc_head; struct ConnectingContext *cc_tail; char *hostkey_data; int hostkeys_total; int hostkeys_last; struct PeerContext *p_head; struct PeerContext *p_tail; }; /** * Start a peer with the given configuration * @param tth the testing handle * @param cfgname configuration file * @param peer_id the peer_id * @param rec receive callback * @param nc connect callback * @param nd disconnect callback * @param start_cb start callback * @param cb_cls closure for callback * @return the peer context */ struct PeerContext * GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_handle *tth, const char *cfgname, int peer_id, GNUNET_TRANSPORT_ReceiveCallback rec, GNUNET_TRANSPORT_NotifyConnect nc, GNUNET_TRANSPORT_NotifyDisconnect nd, GNUNET_TRANSPORT_TESTING_start_cb start_cb, void *cb_cls); /** * shutdown the given peer * @param tth the testing handle * @param p the peer */ void GNUNET_TRANSPORT_TESTING_stop_peer (struct GNUNET_TRANSPORT_TESTING_handle *tth, struct PeerContext *pc); /** * Restart the given peer * @param tth testing handle * @param p the peer * @param cfgname the cfg file used to restart * @param restart_cb restart callback * @param cb_cls callback closure * @return GNUNET_OK in success otherwise GNUNET_SYSERR */ int GNUNET_TRANSPORT_TESTING_restart_peer (struct GNUNET_TRANSPORT_TESTING_handle *tth, struct PeerContext *p, const char *cfgname, GNUNET_TRANSPORT_TESTING_start_cb restart_cb, void *cb_cls); /** * Connect the given peers and call the callback when both peers report the * inbound connection. Remarks: start_peer's notify_connect callback can be called * before. * * @param tth transport testing handle * @param p1 peer 1 * @param p2 peer 2 * @param cb the callback to call when both peers notified that they are connected * @param cls callback cls * @return a connect request handle */ GNUNET_TRANSPORT_TESTING_ConnectRequest GNUNET_TRANSPORT_TESTING_connect_peers (struct GNUNET_TRANSPORT_TESTING_handle *tth, struct PeerContext *p1, struct PeerContext *p2, GNUNET_TRANSPORT_TESTING_connect_cb cb, void *cls); /** * Cancel the request to connect two peers * Tou MUST cancel the request if you stop the peers before the peers connected succesfully * @param tth testing * @param ccr a connect request handle */ void GNUNET_TRANSPORT_TESTING_connect_peers_cancel (struct GNUNET_TRANSPORT_TESTING_handle *tth, GNUNET_TRANSPORT_TESTING_ConnectRequest ccr); /** * Clean up the transport testing * @param tth transport testing handle */ void GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_handle *tth); /** * Initialize the transport testing * @return transport testing handle */ struct GNUNET_TRANSPORT_TESTING_handle * GNUNET_TRANSPORT_TESTING_init (); /* * Some utility functions */ /** * Extracts the test filename from an absolute file name and removes the extension * @param file absolute file name * @param dest where to store result */ void GNUNET_TRANSPORT_TESTING_get_test_name (const char *file, char **dest); /** * This function takes the filename (e.g. argv[0), removes a "lt-"-prefix and * if existing ".exe"-prefix and adds the peer-number * * @param file filename of the test, e.g. argv[0] * @param dest where to write the filename * @param count peer number */ void GNUNET_TRANSPORT_TESTING_get_config_name (const char *file, char **dest, int count); /** * Extracts the plugin anme from an absolute file name and the test name * @param file absolute file name * @param test test name * @param dest where to store result */ void GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *executable, const char *testname, char **pluginname); /** * Extracts the filename from an absolute file name and removes the extenstion * @param file absolute file name * @param dest where to store result */ void GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file, char **testname); /* end of transport_testing.h */ gnunet-0.9.3/src/transport/test_transport_api_timeout_http_peer1.conf0000644000175000017500000000133111661530125023261 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-http-p1/ DEFAULTCONFIG = test_transport_api_http_peer1.conf [nat] [transport-http] PORT = 12080 [arm] PORT = 12085 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12084 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12083 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12082 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] #DEBUG = YES PORT = 12081 PLUGINS = http #BINARY = .libs/gnunet-service-transport UNIXPATH = /tmp/gnunet-p1-service-transport.sock #PREFIX = valgrind --leak-check=full #PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args gnunet-0.9.3/src/transport/test_transport_api_bidirectional_connect_peer1.conf0000644000175000017500000000141411752320467025066 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-tcp-p1/ DEFAULTCONFIG = test_transport_api_bidirectional_connect_peer1.conf [arm] PORT = 12000 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12001 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12002 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12003 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12004 UNIXPATH = /tmp/gnunet-p1-service-transport.sock #DEBUG = YES [transport-tcp] PORT = 12005 TIMEOUT = 5 s [transport-udp] PORT = 12006 TIMEOUT = 5 s [transport-unix] PORT = 12007 TIMEOUT = 5 s [transport-http] PORT = 12008 TIMEOUT = 5 s [transport-https] PORT = 12009 TIMEOUT = 5 sgnunet-0.9.3/src/transport/test_transport_api_timeout_https_peer1.conf0000644000175000017500000000113411661530125023445 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-https-p1/ DEFAULTCONFIG = test_transport_api_https_peer1.conf [transport-https] PORT = 12100 KEY_FILE = $SERVICEHOME/https_key_p1.key CERT_FILE = $SERVICEHOME/https_cert_p1.crt [arm] PORT = 12105 [statistics] PORT = 12104 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12103 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12102 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12101 PLUGINS = https UNIXPATH = /tmp/gnunet-p1-service-transport.sock DEBUG = NO gnunet-0.9.3/src/transport/plugin_transport_unix.c0000644000175000017500000011357011762111032017411 00000000000000/* This file is part of GNUnet (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/plugin_transport_unix.c * @brief Transport plugin using unix domain sockets (!) * Clearly, can only be used locally on Unix/Linux hosts... * ONLY INTENDED FOR TESTING!!! * @author Christian Grothoff * @author Nathan Evans */ #include "platform.h" #include "gnunet_hello_lib.h" #include "gnunet_connection_lib.h" #include "gnunet_container_lib.h" #include "gnunet_os_lib.h" #include "gnunet_peerinfo_service.h" #include "gnunet_protocols.h" #include "gnunet_resolver_service.h" #include "gnunet_server_lib.h" #include "gnunet_signatures.h" #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" #include "gnunet_transport_plugin.h" #include "transport.h" #define MAX_PROBES 20 /* * Transport cost to peer, always 1 for UNIX (direct connection) */ #define UNIX_DIRECT_DISTANCE 1 #define DEFAULT_NAT_PORT 0 /** * How long until we give up on transmitting the welcome message? */ #define HOSTNAME_RESOLVE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) /** * Starting port for listening and sending, eventually a config value */ #define UNIX_NAT_DEFAULT_PORT 22086 GNUNET_NETWORK_STRUCT_BEGIN /** * UNIX Message-Packet header. */ struct UNIXMessage { /** * Message header. */ struct GNUNET_MessageHeader header; /** * What is the identity of the sender (GNUNET_hash of public key) */ struct GNUNET_PeerIdentity sender; }; struct Session { void *addr; size_t addrlen; struct GNUNET_PeerIdentity target; /** * Session timeout task */ GNUNET_SCHEDULER_TaskIdentifier timeout_task; struct Plugin * plugin; }; struct UNIXMessageWrapper { struct UNIXMessageWrapper *next; struct UNIXMessageWrapper *prev; struct UNIXMessage * msg; size_t msgsize; struct GNUNET_TIME_Relative timeout; unsigned int priority; struct Session *session; GNUNET_TRANSPORT_TransmitContinuation cont; void *cont_cls; }; /* Forward definition */ struct Plugin; /** * UNIX NAT "Session" */ struct PeerSession { /** * Stored in a linked list. */ struct PeerSession *next; /** * Pointer to the global plugin struct. */ struct Plugin *plugin; /** * To whom are we talking to (set to our identity * if we are still waiting for the welcome message) */ struct GNUNET_PeerIdentity target; /** * Address of the other peer (either based on our 'connect' * call or on our 'accept' call). */ void *connect_addr; /** * Length of connect_addr. */ size_t connect_alen; /** * Are we still expecting the welcome message? (GNUNET_YES/GNUNET_NO) */ int expecting_welcome; /** * From which socket do we need to send to this peer? */ struct GNUNET_NETWORK_Handle *sock; /* * Queue of messages for this peer, in the case that * we have to await a connection... */ struct MessageQueue *messages; }; /** * Information we keep for each of our listen sockets. */ struct UNIX_Sock_Info { /** * The network handle */ struct GNUNET_NETWORK_Handle *desc; /** * The port we bound to */ uint16_t port; }; /** * Encapsulation of all of the state of the plugin. */ struct Plugin { /** * Our environment. */ struct GNUNET_TRANSPORT_PluginEnvironment *env; /** * Sessions */ struct GNUNET_CONTAINER_MultiHashMap *session_map; /** * ID of task used to update our addresses when one expires. */ GNUNET_SCHEDULER_TaskIdentifier address_update_task; /** * ID of select task */ GNUNET_SCHEDULER_TaskIdentifier select_task; /** * Integer to append to unix domain socket. */ uint16_t port; /** * FD Read set */ struct GNUNET_NETWORK_FDSet *rs; /** * FD Write set */ struct GNUNET_NETWORK_FDSet *ws; int with_ws; /** * socket that we transmit all data with */ struct UNIX_Sock_Info unix_sock; /** * Path of our unix domain socket (/tmp/unix-plugin-PORT) */ char *unix_socket_path; struct UNIXMessageWrapper *msg_head; struct UNIXMessageWrapper *msg_tail; /** * ATS network */ struct GNUNET_ATS_Information ats_network; unsigned int bytes_in_queue; unsigned int bytes_in_sent; unsigned int bytes_in_recv; unsigned int bytes_discarded; }; /** * Start session timeout */ static void start_session_timeout (struct Session *s); /** * Increment session timeout due to activity */ static void reschedule_session_timeout (struct Session *s); /** * Cancel timeout */ static void stop_session_timeout (struct Session *s); static void unix_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); static void reschedule_select (struct Plugin * plugin) { if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (plugin->select_task); plugin->select_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != plugin->msg_head) { plugin->select_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs, plugin->ws, &unix_plugin_select, plugin); plugin->with_ws = GNUNET_YES; } else { plugin->select_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs, NULL, &unix_plugin_select, plugin); plugin->with_ws = GNUNET_NO; } } struct LookupCtx { struct Session *s; const struct sockaddr_un *addr; }; int lookup_session_it (void *cls, const GNUNET_HashCode * key, void *value) { struct LookupCtx *lctx = cls; struct Session *t = value; if (0 == strcmp (t->addr, lctx->addr->sun_path)) { lctx->s = t; return GNUNET_NO; } return GNUNET_YES; } static struct Session * lookup_session (struct Plugin *plugin, struct GNUNET_PeerIdentity *sender, const struct sockaddr_un *addr) { struct LookupCtx lctx; GNUNET_assert (NULL != plugin); GNUNET_assert (NULL != sender); GNUNET_assert (NULL != addr); lctx.s = NULL; lctx.addr = addr; GNUNET_CONTAINER_multihashmap_get_multiple (plugin->session_map, &sender->hashPubKey, &lookup_session_it, &lctx); return lctx.s; } /** * Functions with this signature are called whenever we need * to close a session due to a disconnect or failure to * establish a connection. * * @param s session to close down */ static void disconnect_session (struct Session *s) { struct UNIXMessageWrapper *msgw; struct UNIXMessageWrapper *next; struct Plugin * plugin = s->plugin; int removed; GNUNET_assert (plugin != NULL); GNUNET_assert (s != NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting session for peer `%s' `%s' \n", GNUNET_i2s (&s->target), s->addr); stop_session_timeout (s); plugin->env->session_end (plugin->env->cls, &s->target, s); msgw = plugin->msg_head; removed = GNUNET_NO; next = plugin->msg_head; while (NULL != next) { msgw = next; next = msgw->next; if (msgw->session != s) continue; GNUNET_CONTAINER_DLL_remove (plugin->msg_head, plugin->msg_tail, msgw); if (NULL != msgw->cont) msgw->cont (msgw->cont_cls, &msgw->session->target, GNUNET_SYSERR); GNUNET_free (msgw->msg); GNUNET_free (msgw); removed = GNUNET_YES; } if ((GNUNET_YES == removed) && (NULL == plugin->msg_head)) reschedule_select (plugin); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(plugin->session_map, &s->target.hashPubKey, s)); GNUNET_STATISTICS_set(plugin->env->stats, "# UNIX sessions active", GNUNET_CONTAINER_multihashmap_size(plugin->session_map), GNUNET_NO); GNUNET_free (s); } static int get_session_delete_it (void *cls, const GNUNET_HashCode * key, void *value) { struct Session *s = value; disconnect_session (s); return GNUNET_YES; } /** * Disconnect from a remote node. Clean up session if we have one for this peer * * @param cls closure for this call (should be handle to Plugin) * @param target the peeridentity of the peer to disconnect * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed */ static void unix_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) { struct Plugin *plugin = cls; GNUNET_assert (plugin != NULL); GNUNET_CONTAINER_multihashmap_get_multiple (plugin->session_map, &target->hashPubKey, &get_session_delete_it, plugin); return; } /** * Shutdown the server process (stop receiving inbound traffic). Maybe * restarted later! * * @param cls Handle to the plugin for this transport * * @return returns the number of sockets successfully closed, * should equal the number of sockets successfully opened */ static int unix_transport_server_stop (void *cls) { struct Plugin *plugin = cls; struct UNIXMessageWrapper * msgw = plugin->msg_head; while (NULL != (msgw = plugin->msg_head)) { GNUNET_CONTAINER_DLL_remove (plugin->msg_head, plugin->msg_tail, msgw); if (msgw->cont != NULL) msgw->cont (msgw->cont_cls, &msgw->session->target, GNUNET_SYSERR); GNUNET_free (msgw->msg); GNUNET_free (msgw); } if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (plugin->select_task); plugin->select_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != plugin->unix_sock.desc) { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (plugin->unix_sock.desc)); plugin->unix_sock.desc = NULL; plugin->with_ws = GNUNET_NO; } return GNUNET_OK; } /** * Actually send out the message, assume we've got the address and * send_handle squared away! * * @param cls closure * @param send_handle which handle to send message on * @param target who should receive this message (ignored by UNIX) * @param msgbuf one or more GNUNET_MessageHeader(s) strung together * @param msgbuf_size the size of the msgbuf to send * @param priority how important is the message (ignored by UNIX) * @param timeout when should we time out (give up) if we can not transmit? * @param addr the addr to send the message to, needs to be a sockaddr for us * @param addrlen the len of addr * @param cont continuation to call once the message has * been transmitted (or if the transport is ready * for the next transmission call; or if the * peer disconnected...) * @param cont_cls closure for cont * * @return the number of bytes written, -1 on errors */ static ssize_t unix_real_send (void *cls, struct GNUNET_NETWORK_Handle *send_handle, const struct GNUNET_PeerIdentity *target, const char *msgbuf, size_t msgbuf_size, unsigned int priority, struct GNUNET_TIME_Relative timeout, const void *addr, size_t addrlen, GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) { struct Plugin *plugin = cls; ssize_t sent; const void *sb; size_t sbs; struct sockaddr_un un; size_t slen; int retry; GNUNET_assert (NULL != plugin); if (send_handle == NULL) { /* We do not have a send handle */ GNUNET_break (0); if (cont != NULL) cont (cont_cls, target, GNUNET_SYSERR); return -1; } if ((addr == NULL) || (addrlen == 0)) { /* Can never send if we don't have an address */ GNUNET_break (0); if (cont != NULL) cont (cont_cls, target, GNUNET_SYSERR); return -1; } /* Prepare address */ memset (&un, 0, sizeof (un)); un.sun_family = AF_UNIX; slen = strlen (addr) + 1; if (slen >= sizeof (un.sun_path)) slen = sizeof (un.sun_path) - 1; GNUNET_assert (slen < sizeof (un.sun_path)); memcpy (un.sun_path, addr, slen); un.sun_path[slen] = '\0'; slen = sizeof (struct sockaddr_un); #if LINUX un.sun_path[0] = '\0'; #endif #if HAVE_SOCKADDR_IN_SIN_LEN un.sun_len = (u_char) slen; #endif sb = (struct sockaddr *) &un; sbs = slen; /* Send the data */ sent = 0; retry = GNUNET_NO; sent = GNUNET_NETWORK_socket_sendto (send_handle, msgbuf, msgbuf_size, sb, sbs); if ((GNUNET_SYSERR == sent) && ((errno == EAGAIN) || (errno == ENOBUFS))) { /* We have to retry later: retry */ return 0; } if ((GNUNET_SYSERR == sent) && (errno == EMSGSIZE)) { socklen_t size = 0; socklen_t len = sizeof (size); GNUNET_NETWORK_socket_getsockopt ((struct GNUNET_NETWORK_Handle *) send_handle, SOL_SOCKET, SO_SNDBUF, &size, &len); if (size < msgbuf_size) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to increase socket buffer size from %i to %i for message size %i\n", size, ((msgbuf_size / 1000) + 2) * 1000, msgbuf_size); size = ((msgbuf_size / 1000) + 2) * 1000; if (GNUNET_NETWORK_socket_setsockopt ((struct GNUNET_NETWORK_Handle *) send_handle, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)) == GNUNET_OK) { /* Increased buffer size, retry sending */ return 0; } else { /* Could not increase buffer size: error, no retry */ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsockopt"); return -1; } } else { /* Buffer is bigger than message: error, no retry * This should never happen!*/ GNUNET_break (0); return -1; } } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNIX transmit %u-byte message to %s (%d: %s)\n", (unsigned int) msgbuf_size, GNUNET_a2s (sb, sbs), (int) sent, (sent < 0) ? STRERROR (errno) : "ok"); /* Calling continuation */ if (cont != NULL) { if ((sent == GNUNET_SYSERR) && (retry == GNUNET_NO)) cont (cont_cls, target, GNUNET_SYSERR); if (sent > 0) cont (cont_cls, target, GNUNET_OK); } /* return number of bytes successfully sent */ if (sent > 0) return sent; if (sent == 0) { /* That should never happen */ GNUNET_break (0); return -1; } /* failed and retry: return 0 */ if ((GNUNET_SYSERR == sent) && (retry == GNUNET_YES)) return 0; /* failed and no retry: return -1 */ if ((GNUNET_SYSERR == sent) && (retry == GNUNET_NO)) return -1; /* default */ return -1; } struct gsi_ctx { char *address; size_t addrlen; struct Session *res; }; static int get_session_it (void *cls, const GNUNET_HashCode * key, void *value) { struct gsi_ctx *gsi = cls; struct Session *s = value; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Comparing session %s %s\n", gsi->address, s->addr); if ((gsi->addrlen == s->addrlen) && (0 == memcmp (gsi->address, s->addr, s->addrlen))) { gsi->res = s; return GNUNET_NO; } return GNUNET_YES; } /** * Creates a new outbound session the transport service will use to send data to the * peer * * @param cls the plugin * @param address the address * @return the session or NULL of max connections exceeded */ static struct Session * unix_plugin_get_session (void *cls, const struct GNUNET_HELLO_Address *address) { struct Session * s = NULL; struct Plugin *plugin = cls; struct gsi_ctx gsi; /* Checks */ GNUNET_assert (plugin != NULL); GNUNET_assert (address != NULL); /* Check if already existing */ gsi.address = (char *) address->address; gsi.addrlen = address->address_length; gsi.res = NULL; GNUNET_CONTAINER_multihashmap_get_multiple (plugin->session_map, &address->peer.hashPubKey, &get_session_it, &gsi); if (gsi.res != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found existing session\n"); return gsi.res; } /* Create a new session */ s = GNUNET_malloc (sizeof (struct Session) + address->address_length); s->addr = &s[1]; s->addrlen = address->address_length; s->plugin = plugin; memcpy(s->addr, address->address, s->addrlen); memcpy(&s->target, &address->peer, sizeof (struct GNUNET_PeerIdentity)); start_session_timeout (s); GNUNET_CONTAINER_multihashmap_put (plugin->session_map, &address->peer.hashPubKey, s, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); GNUNET_STATISTICS_set(plugin->env->stats, "# UNIX sessions active", GNUNET_CONTAINER_multihashmap_size(plugin->session_map), GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating new session\n"); return s; } /* * @param cls the plugin handle * @param tc the scheduling context (for rescheduling this function again) * * We have been notified that our writeset has something to read. We don't * know which socket needs to be read, so we have to check each one * Then reschedule this function to be called again once more is available. * */ static void unix_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Function that can be used by the transport service to transmit * a message using the plugin. Note that in the case of a * peer disconnecting, the continuation MUST be called * prior to the disconnect notification itself. This function * will be called with this peer's HELLO message to initiate * a fresh connection to another peer. * * @param cls closure * @param session which session must be used * @param msgbuf the message to transmit * @param msgbuf_size number of bytes in 'msgbuf' * @param priority how important is the message (most plugins will * ignore message priority and just FIFO) * @param to how long to wait at most for the transmission (does not * require plugins to discard the message after the timeout, * just advisory for the desired delay; most plugins will ignore * this as well) * @param cont continuation to call once the message has * been transmitted (or if the transport is ready * for the next transmission call; or if the * peer disconnected...); can be NULL * @param cont_cls closure for cont * @return number of bytes used (on the physical network, with overheads); * -1 on hard errors (i.e. address invalid); 0 is a legal value * and does NOT mean that the message was not transmitted (DV) */ static ssize_t unix_plugin_send (void *cls, struct Session *session, const char *msgbuf, size_t msgbuf_size, unsigned int priority, struct GNUNET_TIME_Relative to, GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) { struct Plugin *plugin = cls; struct UNIXMessageWrapper *wrapper; struct UNIXMessage *message; int ssize; GNUNET_assert (plugin != NULL); GNUNET_assert (session != NULL); if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_contains_value(plugin->session_map, &session->target.hashPubKey, session)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid session for peer `%s' `%s'\n", GNUNET_i2s (&session->target), (char *) session->addr); GNUNET_break (0); return GNUNET_SYSERR; } ssize = sizeof (struct UNIXMessage) + msgbuf_size; message = GNUNET_malloc (sizeof (struct UNIXMessage) + msgbuf_size); message->header.size = htons (ssize); message->header.type = htons (0); memcpy (&message->sender, plugin->env->my_identity, sizeof (struct GNUNET_PeerIdentity)); memcpy (&message[1], msgbuf, msgbuf_size); reschedule_session_timeout (session); wrapper = GNUNET_malloc (sizeof (struct UNIXMessageWrapper)); wrapper->msg = message; wrapper->msgsize = ssize; wrapper->priority = priority; wrapper->timeout = to; wrapper->cont = cont; wrapper->cont_cls = cont_cls; wrapper->session = session; GNUNET_CONTAINER_DLL_insert(plugin->msg_head, plugin->msg_tail, wrapper); plugin->bytes_in_queue += ssize; GNUNET_STATISTICS_set (plugin->env->stats,"# UNIX bytes in send queue", plugin->bytes_in_queue, GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent %d bytes to `%s'\n", ssize, (char *) session->addr); if (plugin->with_ws == GNUNET_NO) { reschedule_select (plugin); } return ssize; } /** * Demultiplexer for UNIX messages * * @param plugin the main plugin for this transport * @param sender from which peer the message was received * @param currhdr pointer to the header of the message * @param un the address from which the message was received * @param fromlen the length of the address */ static void unix_demultiplexer (struct Plugin *plugin, struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *currhdr, const struct sockaddr_un *un, size_t fromlen) { struct GNUNET_ATS_Information ats[2]; struct Session *s = NULL; struct GNUNET_HELLO_Address * addr; ats[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); ats[0].value = htonl (UNIX_DIRECT_DISTANCE); ats[1] = plugin->ats_network; GNUNET_break (ntohl(plugin->ats_network.value) != GNUNET_ATS_NET_UNSPECIFIED); GNUNET_assert (fromlen >= sizeof (struct sockaddr_un)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received message from %s\n", un->sun_path); plugin->bytes_in_recv += ntohs(currhdr->size); GNUNET_STATISTICS_set (plugin->env->stats,"# UNIX bytes received", plugin->bytes_in_recv, GNUNET_NO); addr = GNUNET_HELLO_address_allocate(sender, "unix", un->sun_path, strlen (un->sun_path) + 1); s = lookup_session (plugin, sender, un); if (NULL == s) s = unix_plugin_get_session (plugin, addr); reschedule_session_timeout (s); plugin->env->receive (plugin->env->cls, sender, currhdr, (const struct GNUNET_ATS_Information *) &ats, 2, s, un->sun_path, strlen (un->sun_path) + 1); GNUNET_free (addr); } static void unix_plugin_select_read (struct Plugin * plugin) { char buf[65536] GNUNET_ALIGN; struct UNIXMessage *msg; struct GNUNET_PeerIdentity sender; struct sockaddr_un un; socklen_t addrlen; ssize_t ret; int offset; int tsize; char *msgbuf; const struct GNUNET_MessageHeader *currhdr; uint16_t csize; addrlen = sizeof (un); memset (&un, 0, sizeof (un)); ret = GNUNET_NETWORK_socket_recvfrom (plugin->unix_sock.desc, buf, sizeof (buf), (struct sockaddr *) &un, &addrlen); if ((GNUNET_SYSERR == ret) && ((errno == EAGAIN) || (errno == ENOBUFS))) return; if (ret == GNUNET_SYSERR) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "recvfrom"); return; } else { #if LINUX un.sun_path[0] = '/'; #endif GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read %d bytes from socket %s\n", ret, &un.sun_path[0]); } GNUNET_assert (AF_UNIX == (un.sun_family)); msg = (struct UNIXMessage *) buf; csize = ntohs (msg->header.size); if ((csize < sizeof (struct UNIXMessage)) || (csize > ret)) { GNUNET_break_op (0); return; } msgbuf = (char *) &msg[1]; memcpy (&sender, &msg->sender, sizeof (struct GNUNET_PeerIdentity)); offset = 0; tsize = csize - sizeof (struct UNIXMessage); while (offset + sizeof (struct GNUNET_MessageHeader) <= tsize) { currhdr = (struct GNUNET_MessageHeader *) &msgbuf[offset]; csize = ntohs (currhdr->size); if ((csize < sizeof (struct GNUNET_MessageHeader)) || (csize > tsize - offset)) { GNUNET_break_op (0); break; } unix_demultiplexer (plugin, &sender, currhdr, &un, sizeof (un)); offset += csize; } } static void unix_plugin_select_write (struct Plugin * plugin) { static int retry_counter; int sent = 0; struct UNIXMessageWrapper * msgw = plugin->msg_head; sent = unix_real_send (plugin, plugin->unix_sock.desc, &msgw->session->target, (const char *) msgw->msg, msgw->msgsize, msgw->priority, msgw->timeout, msgw->session->addr, msgw->session->addrlen, msgw->cont, msgw->cont_cls); if (sent == 0) { /* failed and retry */ retry_counter++; GNUNET_STATISTICS_set (plugin->env->stats,"# UNIX retry attempt", retry_counter, GNUNET_NO); return; } if (retry_counter > 0 ) { /* no retry: reset counter */ retry_counter = 0; GNUNET_STATISTICS_set (plugin->env->stats,"# UNIX retry attempt", retry_counter, GNUNET_NO); } if (sent == -1) { /* failed and no retry */ GNUNET_CONTAINER_DLL_remove(plugin->msg_head, plugin->msg_tail, msgw); GNUNET_assert (plugin->bytes_in_queue >= msgw->msgsize); plugin->bytes_in_queue -= msgw->msgsize; GNUNET_STATISTICS_set (plugin->env->stats,"# UNIX bytes in send queue", plugin->bytes_in_queue, GNUNET_NO); plugin->bytes_discarded += msgw->msgsize; GNUNET_STATISTICS_set (plugin->env->stats,"# UNIX bytes discarded", plugin->bytes_discarded, GNUNET_NO); GNUNET_free (msgw->msg); GNUNET_free (msgw); return; } if (sent > 0) { /* successfully sent bytes */ GNUNET_CONTAINER_DLL_remove(plugin->msg_head, plugin->msg_tail, msgw); GNUNET_assert (plugin->bytes_in_queue >= msgw->msgsize); plugin->bytes_in_queue -= msgw->msgsize; GNUNET_STATISTICS_set (plugin->env->stats,"# UNIX bytes in send queue", plugin->bytes_in_queue, GNUNET_NO); plugin->bytes_in_sent += msgw->msgsize; GNUNET_STATISTICS_set (plugin->env->stats,"# UNIX bytes sent", plugin->bytes_in_sent, GNUNET_NO); GNUNET_free (msgw->msg); GNUNET_free (msgw); return; } } /** * We have been notified that our writeset has something to read. We don't * know which socket needs to be read, so we have to check each one * Then reschedule this function to be called again once more is available. * * @param cls the plugin handle * @param tc the scheduling context (for rescheduling this function again) */ static void unix_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Plugin *plugin = cls; plugin->select_task = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; if ((tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) != 0) { /* Ready to send data */ GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->write_ready, plugin->unix_sock.desc)); if (plugin->msg_head != NULL) unix_plugin_select_write (plugin); } if ((tc->reason & GNUNET_SCHEDULER_REASON_READ_READY) != 0) { /* Ready to receive data */ GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready, plugin->unix_sock.desc)); unix_plugin_select_read (plugin); } reschedule_select (plugin); } /** * Create a slew of UNIX sockets. If possible, use IPv6 and IPv4. * * @param cls closure for server start, should be a struct Plugin * * @return number of sockets created or GNUNET_SYSERR on error */ static int unix_transport_server_start (void *cls) { struct Plugin *plugin = cls; struct sockaddr *serverAddr; socklen_t addrlen; struct sockaddr_un un; size_t slen; memset (&un, 0, sizeof (un)); un.sun_family = AF_UNIX; slen = strlen (plugin->unix_socket_path) + 1; if (slen >= sizeof (un.sun_path)) slen = sizeof (un.sun_path) - 1; memcpy (un.sun_path, plugin->unix_socket_path, slen); un.sun_path[slen] = '\0'; slen = sizeof (struct sockaddr_un); #if HAVE_SOCKADDR_IN_SIN_LEN un.sun_len = (u_char) slen; #endif serverAddr = (struct sockaddr *) &un; addrlen = slen; #if LINUX un.sun_path[0] = '\0'; #endif plugin->ats_network = plugin->env->get_address_type (plugin->env->cls, serverAddr, addrlen); plugin->unix_sock.desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_DGRAM, 0); if (NULL == plugin->unix_sock.desc) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket"); return GNUNET_SYSERR; } if (GNUNET_NETWORK_socket_bind (plugin->unix_sock.desc, serverAddr, addrlen) != GNUNET_OK) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind"); GNUNET_NETWORK_socket_close (plugin->unix_sock.desc); plugin->unix_sock.desc = NULL; return GNUNET_SYSERR; } GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "unix", "Bound to `%s'\n", &un.sun_path[0]); plugin->rs = GNUNET_NETWORK_fdset_create (); plugin->ws = GNUNET_NETWORK_fdset_create (); GNUNET_NETWORK_fdset_zero (plugin->rs); GNUNET_NETWORK_fdset_zero (plugin->ws); GNUNET_NETWORK_fdset_set (plugin->rs, plugin->unix_sock.desc); GNUNET_NETWORK_fdset_set (plugin->ws, plugin->unix_sock.desc); reschedule_select (plugin); return 1; } /** * Function that will be called to check if a binary address for this * plugin is well-formed and corresponds to an address for THIS peer * (as per our configuration). Naturally, if absolutely necessary, * plugins can be a bit conservative in their answer, but in general * plugins should make sure that the address does not redirect * traffic to a 3rd party that might try to man-in-the-middle our * traffic. * * @param cls closure, should be our handle to the Plugin * @param addr pointer to the address * @param addrlen length of addr * @return GNUNET_OK if this is a plausible address for this peer * and transport, GNUNET_SYSERR if not * */ static int unix_check_address (void *cls, const void *addr, size_t addrlen) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Informing transport service about my address `%s'\n", (char *) addr); return GNUNET_OK; } /** * Convert the transports address to a nice, human-readable * format. * * @param cls closure * @param type name of the transport that generated the address * @param addr one of the addresses of the host, NULL for the last address * the specific address format depends on the transport * @param addrlen length of the address * @param numeric should (IP) addresses be displayed in numeric form? * @param timeout after how long should we give up? * @param asc function to call on each string * @param asc_cls closure for asc */ static void unix_plugin_address_pretty_printer (void *cls, const char *type, const void *addr, size_t addrlen, int numeric, struct GNUNET_TIME_Relative timeout, GNUNET_TRANSPORT_AddressStringCallback asc, void *asc_cls) { if ((NULL != addr) && (addrlen > 0)) { asc (asc_cls, (const char *) addr); } else { GNUNET_break (0); asc (asc_cls, ""); } asc (asc_cls, NULL); } /** * Function called to convert a string address to * a binary address. * * @param cls closure ('struct Plugin*') * @param addr string address * @param addrlen length of the address (strlen(addr) + '\0') * @param buf location to store the buffer * If the function returns GNUNET_SYSERR, its contents are undefined. * @param added length of created address * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ static int unix_string_to_address (void *cls, const char *addr, uint16_t addrlen, void **buf, size_t *added) { if ((NULL == addr) || (0 == addrlen)) { GNUNET_break (0); return GNUNET_SYSERR; } if ('\0' != addr[addrlen - 1]) { GNUNET_break (0); return GNUNET_SYSERR; } if (strlen (addr) != addrlen - 1) { GNUNET_break (0); return GNUNET_SYSERR; } (*buf) = strdup (addr); (*added) = strlen (addr) + 1; return GNUNET_OK; } /** * Function called for a quick conversion of the binary address to * a numeric address. Note that the caller must not free the * address and that the next call to this function is allowed * to override the address again. * * @param cls closure * @param addr binary address * @param addrlen length of the address * @return string representing the same address */ static const char * unix_address_to_string (void *cls, const void *addr, size_t addrlen) { if ((addr != NULL) && (addrlen > 0)) return (const char *) addr; return NULL; } /** * Notify transport service about address * * @param cls the plugin * @param tc unused */ static void address_notification (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Plugin *plugin = cls; plugin->env->notify_address (plugin->env->cls, GNUNET_YES, plugin->unix_socket_path, strlen (plugin->unix_socket_path) + 1); } /** * Session was idle, so disconnect it */ static void session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_assert (NULL != cls); struct Session *s = cls; s->timeout_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Session %p was idle for %llu, disconnecting\n", s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); /* call session destroy function */ disconnect_session(s); } /** * Start session timeout */ static void start_session_timeout (struct Session *s) { GNUNET_assert (NULL != s); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == s->timeout_task); s->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, &session_timeout, s); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout for session %p set to %llu\n", s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); } /** * Increment session timeout due to activity */ static void reschedule_session_timeout (struct Session *s) { GNUNET_assert (NULL != s); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task); GNUNET_SCHEDULER_cancel (s->timeout_task); s->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, &session_timeout, s); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout rescheduled for session %p set to %llu\n", s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); } /** * Cancel timeout */ static void stop_session_timeout (struct Session *s) { GNUNET_assert (NULL != s); if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task) { GNUNET_SCHEDULER_cancel (s->timeout_task); s->timeout_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout rescheduled for session %p canceled\n", s, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout for session %p was not active\n", s); } } /** * The exported method. Makes the core api available via a global and * returns the unix transport API. */ void * libgnunet_plugin_transport_unix_init (void *cls) { struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; unsigned long long port; struct GNUNET_TRANSPORT_PluginFunctions *api; struct Plugin *plugin; int sockets_created; if (NULL == env->receive) { /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully initialze the plugin or the API */ api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); api->cls = NULL; api->address_pretty_printer = &unix_plugin_address_pretty_printer; api->address_to_string = &unix_address_to_string; api->string_to_address = &unix_string_to_address; return api; } GNUNET_assert( NULL != env->stats); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-unix", "PORT", &port)) port = UNIX_NAT_DEFAULT_PORT; plugin = GNUNET_malloc (sizeof (struct Plugin)); plugin->port = port; plugin->env = env; GNUNET_asprintf (&plugin->unix_socket_path, "/tmp/unix-plugin-sock.%d", plugin->port); api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); api->cls = plugin; api->get_session = &unix_plugin_get_session; api->send = &unix_plugin_send; api->disconnect = &unix_disconnect; api->address_pretty_printer = &unix_plugin_address_pretty_printer; api->address_to_string = &unix_address_to_string; api->check_address = &unix_check_address; api->string_to_address = &unix_string_to_address; sockets_created = unix_transport_server_start (plugin); if (sockets_created == 0) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to open UNIX sockets\n")); plugin->session_map = GNUNET_CONTAINER_multihashmap_create(10); GNUNET_SCHEDULER_add_now (address_notification, plugin); return api; } void * libgnunet_plugin_transport_unix_done (void *cls) { struct GNUNET_TRANSPORT_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; if (NULL == plugin) { GNUNET_free (api); return NULL; } unix_transport_server_stop (plugin); GNUNET_CONTAINER_multihashmap_iterate (plugin->session_map, &get_session_delete_it, plugin); GNUNET_CONTAINER_multihashmap_destroy (plugin->session_map); if (NULL != plugin->rs) GNUNET_NETWORK_fdset_destroy (plugin->rs); if (NULL != plugin->ws) GNUNET_NETWORK_fdset_destroy (plugin->ws); GNUNET_free (plugin->unix_socket_path); GNUNET_free (plugin); GNUNET_free (api); return NULL; } /* end of plugin_transport_unix.c */ gnunet-0.9.3/src/transport/test_transport_api_http_nat_peer1.conf0000644000175000017500000000140211661530125022354 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-http-p1/ DEFAULTCONFIG = test_transport_api_http_nat_peer1.conf [nat] BEHIND_NAT = YES ENABLE_NAT_SERVER = YES [transport-http] PORT = 0 [arm] PORT = 12085 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12084 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12083 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12082 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] #DEBUG = YES PORT = 12081 PLUGINS = http #BINARY = .libs/gnunet-service-transport UNIXPATH = /tmp/gnunet-p1-service-transport.sock #PREFIX = valgrind --leak-check=full #PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args gnunet-0.9.3/src/transport/transport-testing.c0000644000175000017500000005637011760502551016457 00000000000000/* This file is part of GNUnet. (C) 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport-testing.c * @brief testing lib for transport service * * @author Matthias Wachs */ #include "transport-testing.h" #define HOSTKEYFILESIZE 914 static const char * get_host_key (struct GNUNET_TRANSPORT_TESTING_handle *tth) { if (tth->hostkey_data == NULL) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", "No precomputed hostkeys available\n"); return NULL; } if (tth->hostkeys_total > tth->hostkeys_last) { tth->hostkeys_last++; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", "Used hostkey %u of %u available hostkeys\n", tth->hostkeys_last, tth->hostkeys_total); return &tth->hostkey_data[(tth->hostkeys_last - 1) * HOSTKEYFILESIZE]; } GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", "No hostkey available (%u of %u already used)\n", tth->hostkeys_last, tth->hostkeys_total); return NULL; } static struct PeerContext * find_peer_context (struct GNUNET_TRANSPORT_TESTING_handle *tth, const struct GNUNET_PeerIdentity *peer) { GNUNET_assert (tth != NULL); struct PeerContext *t = tth->p_head; while (t != NULL) { if (0 == memcmp (&t->id, peer, sizeof (struct GNUNET_PeerIdentity))) break; t = t->next; } return t; } static struct ConnectingContext * find_connecting_context (struct GNUNET_TRANSPORT_TESTING_handle *tth, struct PeerContext *p1, struct PeerContext *p2) { GNUNET_assert (tth != NULL); struct ConnectingContext *cc = tth->cc_head; while (cc != NULL) { if ((cc->p1 == p1) && (cc->p2 == p2)) break; if ((cc->p1 == p2) && (cc->p2 == p1)) break; cc = cc->next; } return cc; } static void notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { struct PeerContext *p = cls; /* Find PeerContext */ GNUNET_assert (p != 0); GNUNET_assert (p->tth != NULL); struct PeerContext *p2 = find_peer_context (p->tth, peer); if (p == NULL) return; if (p->nc != NULL) p->nc (p->cb_cls, peer, ats, ats_count); char *p2_s; if (p2 != NULL) GNUNET_asprintf (&p2_s, "%u (`%s')", p2->no, GNUNET_i2s (&p2->id)); else GNUNET_asprintf (&p2_s, "`%s'", GNUNET_i2s (peer)); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", "Peers %s connected to peer %u (`%s')\n", p2_s, p->no, GNUNET_i2s (&p->id)); GNUNET_free (p2_s); /* Find ConnectingContext */ struct ConnectingContext *cc = find_connecting_context (p->tth, p, p2); if (cc == NULL) return; if (p == cc->p1) cc->p1_c = GNUNET_YES; if (p == cc->p2) cc->p2_c = GNUNET_YES; if ((cc->p1_c == GNUNET_YES) && (cc->p2_c == GNUNET_YES)) { cc->cb (cc->p1, cc->p2, cc->cb_cls); GNUNET_TRANSPORT_TESTING_connect_peers_cancel (p->tth, cc); } } static void notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { struct PeerContext *p = cls; /* Find PeerContext */ int no = 0; struct PeerContext *p2 = NULL; if (p != NULL) { GNUNET_assert (p->tth != NULL); p2 = find_peer_context (p->tth, peer); no = p->no; } char *p2_s; if (p2 != NULL) GNUNET_asprintf (&p2_s, "%u (`%s')", p2->no, GNUNET_i2s (&p2->id)); else GNUNET_asprintf (&p2_s, "`%s'", GNUNET_i2s (peer)); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", "Peers %s disconnected from peer %u (`%s')\n", p2_s, no, GNUNET_i2s (&p->id)); GNUNET_free (p2_s); if (p == NULL) return; if (p->nd != NULL) p->nd (p->cb_cls, peer); } static void notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { struct PeerContext *p = cls; if (p == NULL) return; if (p->rec != NULL) p->rec (p->cb_cls, peer, message, ats, ats_count); } static void get_hello (void *cb_cls, const struct GNUNET_MessageHeader *message) { struct PeerContext *p = cb_cls; GNUNET_assert (message != NULL); GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) message, &p->id)); GNUNET_free_non_null (p->hello); p->hello = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (message); if (p->start_cb != NULL) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", "Peer %u (`%s') successfully started\n", p->no, GNUNET_i2s (&p->id)); p->start_cb (p, p->cb_cls); p->start_cb = NULL; } } static void try_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ConnectingContext *cc = cls; struct PeerContext *p1 = cc->p1; struct PeerContext *p2 = cc->p2; cc->tct = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; GNUNET_assert (cc != NULL); GNUNET_assert (cc->p1 != NULL); GNUNET_assert (cc->p2 != NULL); char *p2_s = GNUNET_strdup (GNUNET_i2s (&p2->id)); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", "Asking peer %u (`%s') to connect peer %u (`%s'), providing HELLO with %u bytes\n", p1->no, GNUNET_i2s (&p1->id), p2->no, p2_s, GNUNET_HELLO_size (cc->p2->hello)); GNUNET_free (p2_s); GNUNET_TRANSPORT_offer_hello (cc->th_p1, (const struct GNUNET_MessageHeader *) cc-> p2->hello, NULL, NULL); GNUNET_TRANSPORT_try_connect (cc->th_p1, &p2->id); cc->tct = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &try_connect, cc); } /** * Start a peer with the given configuration * @param tth the testing handle * @param cfgname configuration file * @param peer_id the peer_id * @param rec receive callback * @param nc connect callback * @param nd disconnect callback * @param start_cb start callback * @param cb_cls closure for callback * @return the peer context */ struct PeerContext * GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_handle *tth, const char *cfgname, int peer_id, GNUNET_TRANSPORT_ReceiveCallback rec, GNUNET_TRANSPORT_NotifyConnect nc, GNUNET_TRANSPORT_NotifyDisconnect nd, GNUNET_TRANSPORT_TESTING_start_cb start_cb, void *cb_cls) { const char *hostkey = NULL; struct GNUNET_DISK_FileHandle *fn; GNUNET_assert (tth != NULL); if (GNUNET_DISK_file_test (cfgname) == GNUNET_NO) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing", "File not found: `%s' \n", cfgname); return NULL; } struct PeerContext *p = GNUNET_malloc (sizeof (struct PeerContext)); p->cfg = GNUNET_CONFIGURATION_create (); GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); if (GNUNET_CONFIGURATION_have_value (p->cfg, "PATHS", "SERVICEHOME")) GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (p->cfg, "PATHS", "SERVICEHOME", &p->servicehome)); if (NULL != p->servicehome) GNUNET_DISK_directory_remove (p->servicehome); hostkey = get_host_key (tth); if (hostkey != NULL) { GNUNET_asprintf (&p->hostkeyfile, "%s/.hostkey", p->servicehome); GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_create_for_file (p->hostkeyfile)); fn = GNUNET_DISK_file_open (p->hostkeyfile, GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_CREATE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); GNUNET_assert (fn != NULL); GNUNET_assert (HOSTKEYFILESIZE == GNUNET_DISK_file_write (fn, hostkey, HOSTKEYFILESIZE)); GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fn)); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", "Wrote hostkey to file: `%s' \n", p->hostkeyfile); } p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, "-L", "ERROR", NULL); p->no = peer_id; p->tth = tth; p->nc = nc; p->nd = nd; p->rec = rec; p->start_cb = start_cb; if (cb_cls != NULL) p->cb_cls = cb_cls; else p->cb_cls = p; p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p, ¬ify_receive, ¬ify_connect, ¬ify_disconnect); GNUNET_assert (p->th != NULL); p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &get_hello, p); GNUNET_assert (p->ghh != NULL); GNUNET_CONTAINER_DLL_insert (tth->p_head, tth->p_tail, p); return p; } /** * Restart the given peer * @param tth testing handle * @param p the peer * @param cfgname the cfg file used to restart * @param restart_cb callback to call when restarted * @param cb_cls callback closure * @return GNUNET_OK in success otherwise GNUNET_SYSERR */ int GNUNET_TRANSPORT_TESTING_restart_peer (struct GNUNET_TRANSPORT_TESTING_handle *tth, struct PeerContext *p, const char *cfgname, GNUNET_TRANSPORT_TESTING_start_cb restart_cb, void *cb_cls) { struct GNUNET_DISK_FileHandle *fn; GNUNET_assert (tth != NULL); GNUNET_assert (p != NULL); GNUNET_assert (p->hostkeyfile != NULL); GNUNET_assert (p->servicehome != NULL); /* shutdown */ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", "Stopping peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id)); if (p->ghh != NULL) GNUNET_TRANSPORT_get_hello_cancel (p->ghh); p->ghh = NULL; if (p->th != NULL) GNUNET_TRANSPORT_disconnect (p->th); if (NULL != p->arm_proc) { if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); GNUNET_OS_process_wait (p->arm_proc); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; } if (p->hello != NULL) GNUNET_free (p->hello); p->hello = NULL; if (p->cfg != NULL) GNUNET_CONFIGURATION_destroy (p->cfg); p->cfg = NULL; /* start */ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", "Restarting peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id)); sleep (5); // YUCK! if (GNUNET_DISK_file_test (cfgname) == GNUNET_NO) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing", "File not found: `%s' \n", cfgname); goto fail; } p->cfg = GNUNET_CONFIGURATION_create (); GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); if (!GNUNET_CONFIGURATION_have_value (p->cfg, "PATHS", "SERVICEHOME")) goto fail; fn = GNUNET_DISK_file_open (p->hostkeyfile, GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_CREATE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (fn == NULL) goto fail; if (GNUNET_OK != GNUNET_DISK_file_close (fn)) goto fail; p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, "-L", "ERROR", NULL); p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p, ¬ify_receive, ¬ify_connect, ¬ify_disconnect); GNUNET_assert (p->th != NULL); p->start_cb = restart_cb; p->cb_cls = cb_cls; p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &get_hello, p); GNUNET_assert (p->ghh != NULL); return GNUNET_OK; fail: GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", "Restarting peer %u (`%s') failed, removing peer\n", p->no, GNUNET_i2s (&p->id)); GNUNET_TRANSPORT_TESTING_stop_peer (tth, p); return GNUNET_SYSERR; } /** * shutdown the given peer * @param tth testing handle * @param p the peer */ void GNUNET_TRANSPORT_TESTING_stop_peer (struct GNUNET_TRANSPORT_TESTING_handle *tth, struct PeerContext *p) { GNUNET_assert (p != NULL); if (p->ghh != NULL) { GNUNET_TRANSPORT_get_hello_cancel (p->ghh); p->ghh = NULL; } if (p->th != NULL) GNUNET_TRANSPORT_disconnect (p->th); if (NULL != p->arm_proc) { if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); GNUNET_OS_process_wait (p->arm_proc); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; } if (p->hostkeyfile != NULL) { GNUNET_DISK_directory_remove (p->hostkeyfile); GNUNET_free (p->hostkeyfile); } if (p->servicehome != NULL) { GNUNET_DISK_directory_remove (p->servicehome); GNUNET_free (p->servicehome); } if (p->hello != NULL) { GNUNET_free (p->hello); p->hello = NULL; } if (p->cfg != NULL) { GNUNET_CONFIGURATION_destroy (p->cfg); p->cfg = NULL; } GNUNET_CONTAINER_DLL_remove (tth->p_head, tth->p_tail, p); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", "Peer %u (`%s') stopped \n", p->no, GNUNET_i2s (&p->id)); GNUNET_free (p); } /** * Connect the given peers and call the callback when both peers report the * inbound connection. Remarks: start_peer's notify_connect callback can be called * before. * * @param tth transport testing handle * @param p1 peer 1 * @param p2 peer 2 * @param cb the callback to call when both peers notified that they are connected * @param cls callback cls * @return a connect request handle */ GNUNET_TRANSPORT_TESTING_ConnectRequest GNUNET_TRANSPORT_TESTING_connect_peers (struct GNUNET_TRANSPORT_TESTING_handle *tth, struct PeerContext *p1, struct PeerContext *p2, GNUNET_TRANSPORT_TESTING_connect_cb cb, void *cls) { GNUNET_assert (tth != NULL); struct ConnectingContext *cc = GNUNET_malloc (sizeof (struct ConnectingContext)); GNUNET_assert (p1 != NULL); GNUNET_assert (p2 != NULL); cc->p1 = p1; cc->p2 = p2; cc->cb = cb; if (cls != NULL) cc->cb_cls = cls; else cc->cb_cls = cc; cc->th_p1 = p1->th; cc->th_p2 = p2->th; GNUNET_assert (cc->th_p1 != NULL); GNUNET_assert (cc->th_p2 != NULL); GNUNET_CONTAINER_DLL_insert (tth->cc_head, tth->cc_tail, cc); cc->tct = GNUNET_SCHEDULER_add_now (&try_connect, cc); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", "New connect request %X\n", cc); return cc; } /** * Cancel the request to connect two peers * Tou MUST cancel the request if you stop the peers before the peers connected succesfully * * @param tth transport testing handle * @param ccr a connect request handle */ void GNUNET_TRANSPORT_TESTING_connect_peers_cancel (struct GNUNET_TRANSPORT_TESTING_handle *tth, GNUNET_TRANSPORT_TESTING_ConnectRequest ccr) { struct ConnectingContext *cc = ccr; GNUNET_assert (tth != NULL); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", "Canceling connect request %X!\n", cc); if (cc->tct != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (cc->tct); cc->tct = GNUNET_SCHEDULER_NO_TASK; GNUNET_CONTAINER_DLL_remove (tth->cc_head, tth->cc_tail, cc); GNUNET_free (cc); } /** * Clean up the transport testing * @param tth transport testing handle */ void GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_handle *tth) { struct ConnectingContext *cc = tth->cc_head; struct ConnectingContext *ct = NULL; struct PeerContext *p = tth->p_head; struct PeerContext *t = NULL; GNUNET_assert (tth != NULL); while (cc != tth->cc_tail) { ct = cc->next; GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing", "Developer forgot to cancel connect request %X!\n", cc); GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); cc = ct; } while (p != NULL) { t = p->next; GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing", "Developer forgot to stop peer!\n"); GNUNET_TRANSPORT_TESTING_stop_peer (tth, p); p = t; } GNUNET_free_non_null (tth->hostkey_data); GNUNET_free (tth); tth = NULL; } /** * Initialize the transport testing * @return transport testing handle */ struct GNUNET_TRANSPORT_TESTING_handle * GNUNET_TRANSPORT_TESTING_init () { struct GNUNET_TRANSPORT_TESTING_handle *tth; struct GNUNET_DISK_FileHandle *fd; uint64_t fs; uint64_t total_hostkeys; /* prepare hostkeys */ tth = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_TESTING_handle)); tth->hostkey_data = NULL; const char *hostkeys_file = "../../contrib/testing_hostkeys.dat"; if (GNUNET_YES != GNUNET_DISK_file_test (hostkeys_file)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not read hostkeys file!\n")); } else { /* Check hostkey file size, read entire thing into memory */ fd = GNUNET_DISK_file_open (hostkeys_file, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); if (NULL == fd) { GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", hostkeys_file); GNUNET_free (tth); return NULL; } if (GNUNET_OK != GNUNET_DISK_file_size (hostkeys_file, &fs, GNUNET_YES, GNUNET_YES)) fs = 0; if (0 != (fs % HOSTKEYFILESIZE)) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing", "File size %llu seems incorrect for hostkeys...\n", fs); } else { total_hostkeys = fs / HOSTKEYFILESIZE; tth->hostkey_data = GNUNET_malloc_large (fs); GNUNET_assert (fs == GNUNET_DISK_file_read (fd, tth->hostkey_data, fs)); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", "Read %llu hostkeys from file\n", total_hostkeys); tth->hostkeys_total = total_hostkeys; } GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); } return tth; } /* * Some utility functions */ /** * Removes all directory separators from absolute filename * @param file the absolute file name, e.g. as found in argv[0] * @return extracted file name, has to be freed by caller */ static char * extract_filename (const char *file) { char *pch = GNUNET_strdup (file); char *backup = pch; char *filename = NULL; char *res; if (NULL != strstr (pch, "/")) { pch = strtok (pch, "/"); while (pch != NULL) { pch = strtok (NULL, "/"); if (pch != NULL) { filename = pch; } } } else filename = pch; res = GNUNET_strdup (filename); GNUNET_free (backup); return res; } /** * Extracts the test filename from an absolute file name and removes the extension * @param file absolute file name * @param dest where to store result */ void GNUNET_TRANSPORT_TESTING_get_test_name (const char *file, char **dest) { char *filename = extract_filename (file); char *backup = filename; char *dotexe; if (filename == NULL) goto fail; /* remove "lt-" */ filename = strstr (filename, "tes"); if (filename == NULL) goto fail; /* remove ".exe" */ if (NULL != (dotexe = strstr (filename, ".exe"))) dotexe[0] = '\0'; goto suc; fail: (*dest) = NULL; return; suc: /* create filename */ GNUNET_asprintf (dest, "%s", filename); GNUNET_free (backup); } /** * Extracts the filename from an absolute file name and removes the extension * @param file absolute file name * @param dest where to store result */ void GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file, char **dest) { char *src = extract_filename (file); char *split; split = strstr (src, "."); if (split != NULL) { split[0] = '\0'; } GNUNET_asprintf (dest, "%s", src); GNUNET_free (src); } /** * Extracts the plugin name from an absolute file name and the test name * * @param file absolute file name * @param test test name * @param dest where to store result */ void GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *file, const char *test, char **dest) { char *filename; char *dotexe; char *e = extract_filename (file); char *t = extract_filename (test); if (NULL == e) goto fail; /* remove "lt-" */ filename = strstr (e, "tes"); if (NULL == filename) goto fail; /* remove ".exe" */ if (NULL != (dotexe = strstr (filename, ".exe"))) dotexe[0] = '\0'; /* find last _ */ filename = strstr (filename, t); if (NULL == filename) goto fail; /* copy plugin */ filename += strlen (t); if ('\0' != *filename) filename++; GNUNET_asprintf (dest, "%s", filename); goto suc; fail: (*dest) = NULL; suc: GNUNET_free (t); GNUNET_free (e); } /** * This function takes the filename (e.g. argv[0), removes a "lt-"-prefix and * if existing ".exe"-prefix and adds the peer-number * * @param file filename of the test, e.g. argv[0] * @param dest where to write the filename * @param count peer number */ void GNUNET_TRANSPORT_TESTING_get_config_name (const char *file, char **dest, int count) { char *filename = extract_filename (file); char *backup = filename; char *dotexe; if (NULL == filename) goto fail; /* remove "lt-" */ filename = strstr (filename, "tes"); if (NULL == filename) goto fail; /* remove ".exe" */ if (NULL != (dotexe = strstr (filename, ".exe"))) dotexe[0] = '\0'; GNUNET_asprintf (dest, "%s_peer%u.conf", filename, count); GNUNET_free (backup); return; fail: (*dest) = NULL; GNUNET_free (backup); } /* end of transport-testing.c */ gnunet-0.9.3/src/transport/test_transport_api_https_peer2.conf0000644000175000017500000000120711661530125021701 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-https-p2/ DEFAULTCONFIG = test_transport_api_https_peer2.conf [transport-https] PORT = 12110 KEY_FILE = $SERVICEHOME/https_key_p2.key CERT_FILE = $SERVICEHOME/https_cert_p2.crt [arm] PORT = 12115 UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12114 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12113 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12112 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12111 PLUGINS = https UNIXPATH = /tmp/gnunet-p2-service-transport.sock DEBUG = NO gnunet-0.9.3/src/transport/test_transport_api_reliability_http_peer2.conf0000644000175000017500000000107411665472561024126 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-http-p2/ DEFAULTCONFIG = test_transport_api_reliability_http_peer2.conf [transport-http] PORT = 12190 [arm] PORT = 12195 UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12194 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12193 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12192 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12191 PLUGINS = http UNIXPATH = /tmp/gnunet-p2-service-transport.sock #DEBUG = YES gnunet-0.9.3/src/transport/test_transport_api_unreliability_udp_peer2.conf0000644000175000017500000000110011665472561024270 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-udp-p2/ DEFAULTCONFIG = test_transport_api_unreliability_udp_peer2.conf [transport-udp] PORT = 12050 MAX_BPS = 5000000 [arm] PORT = 12055 UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12054 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12053 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12052 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12051 PLUGINS = udp UNIXPATH = /tmp/gnunet-p2-service-transport.sock gnunet-0.9.3/src/transport/test_transport_api_limited_sockets.c0000644000175000017500000002363311760502551022132 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/test_transport_api_limited_sockets.c * @brief base test case for transport implementations * * This test case serves as a base for tcp, udp, and udp-nat * transport test cases. Based on the executable being run * the correct test case will be performed. Conservation of * C code apparently. */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_hello_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_transport_service.h" #include "transport.h" #include "transport-testing.h" #define VERBOSE GNUNET_NO #define VERBOSE_ARM GNUNET_NO #define START_ARM GNUNET_YES /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) /** * How long until we give up on transmitting the message? */ #define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) #define MTYPE 12345 #define MAX_FILES 50 static char *test_source; static char *test_plugin; static char *test_name; static int ok; static GNUNET_SCHEDULER_TaskIdentifier die_task; static GNUNET_SCHEDULER_TaskIdentifier send_task; static struct PeerContext *p1; static struct PeerContext *p2; static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; static struct GNUNET_TRANSPORT_TransmitHandle *th; static struct GNUNET_TRANSPORT_TESTING_handle *tth; static char *cfg_file_p1; static char *cfg_file_p2; #if VERBOSE #define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) #else #define OKPP do { ok++; } while (0) #endif static void end () { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); if (send_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (send_task); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); } static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { die_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); if (send_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (send_task); if (cc != NULL) GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; if (p1 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); if (p2 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); ok = GNUNET_SYSERR; } static void notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received message of type %d from peer %s!\n", ntohs (message->type), GNUNET_i2s (peer)); if ((MTYPE == ntohs (message->type)) && (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size))) { ok = 0; end (); } else { GNUNET_break (0); ok = 1; end (); } } static size_t notify_ready (void *cls, size_t size, void *buf) { struct PeerContext *p = cls; struct GNUNET_MessageHeader *hdr; th = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting message with %u bytes to peer %s\n", sizeof (struct GNUNET_MessageHeader), GNUNET_i2s (&p->id)); GNUNET_assert (size >= 256); if (buf != NULL) { hdr = buf; hdr->size = htons (sizeof (struct GNUNET_MessageHeader)); hdr->type = htons (MTYPE); } return sizeof (struct GNUNET_MessageHeader); } static void notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' connected to us (%p)!\n", GNUNET_i2s (peer), cls); } static void notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' disconnected (%p)!\n", GNUNET_i2s (peer), cls); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; } static void sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { send_task = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; th = GNUNET_TRANSPORT_notify_transmit_ready (p1->th, &p2->id, 256, 0, TIMEOUT, ¬ify_ready, &p1); } static void testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) { cc = NULL; char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %s <-> %s\n", p1_c, GNUNET_i2s (&p2->id)); GNUNET_free (p1_c); // FIXME: THIS IS REQUIRED! SEEMS TO BE A BUG! send_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &sendtask, NULL); } static void start_cb (struct PeerContext *p, void *cls) { static int started; started++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, GNUNET_i2s (&p->id)); if (started != 2) return; cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); tth = GNUNET_TRANSPORT_TESTING_init (); p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); if ((p1 == NULL) || (p2 == NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } } static int check () { static char *const argv[] = { "test-transport-api", "-c", "test_transport_api_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; #if WRITECONFIG setTransportOptions ("test_transport_api_data.conf"); #endif send_task = GNUNET_SCHEDULER_NO_TASK; ok = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name, "nohelp", options, &run, &ok); return ok; } int main (int argc, char *argv[]) { int ret = 0; test_plugin = NULL; GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source); GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source, &test_plugin); GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); GNUNET_log_setup (test_name, #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); #if !HAVE_SETRLIMIT GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot run test on this system\n"); GNUNET_free (test_source); GNUNET_free (test_plugin); GNUNET_free (test_name); return 0; #else struct rlimit r_file_old; struct rlimit r_file_new; int res; res = getrlimit (RLIMIT_NOFILE, &r_file_old); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Maximum number of open files was: %u/%u\n", r_file_old.rlim_cur, r_file_old.rlim_max); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Setting maximum number of open files to: %u\n", MAX_FILES); r_file_new.rlim_cur = MAX_FILES; r_file_new.rlim_max = r_file_old.rlim_max; res = setrlimit (RLIMIT_NOFILE, &r_file_new); if (res != 0) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Setting limit failed!\n"); GNUNET_free (test_source); GNUNET_free (test_plugin); GNUNET_free (test_name); return 0; } GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1); GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2); ret = check (); #endif GNUNET_free (cfg_file_p1); GNUNET_free (cfg_file_p2); GNUNET_free (test_source); GNUNET_free (test_plugin); GNUNET_free (test_name); #if HAVE_SETRLIMIT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Restoring previous value maximum number of open files\n"); res = setrlimit (RLIMIT_NOFILE, &r_file_old); if (res != 0) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Restoring limit failed!\n"); return 0; } #endif return ret; } /* end of test_transport_api_limited_sockets.c */ gnunet-0.9.3/src/transport/test_transport_api_disconnect_tcp_peer2.conf0000644000175000017500000000111111750306133023527 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-tcp-p2/ DEFAULTCONFIG = test_transport_api_tcp_peer2.conf [transport-tcp] PORT = 12015 TIMEOUT = 5 s [arm] PORT = 12014 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12013 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12012 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12011 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12010 PLUGINS = tcp UNIXPATH = /tmp/gnunet-p2-service-transport.sock gnunet-0.9.3/src/transport/gnunet-service-transport_plugins.c0000644000175000017500000001515411760502551021474 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/gnunet-service-transport_plugins.c * @brief plugin management * @author Christian Grothoff */ #include "platform.h" #include "gnunet-service-transport.h" #include "gnunet-service-transport_hello.h" #include "gnunet-service-transport_plugins.h" /** * Entry in doubly-linked list of all of our plugins. */ struct TransportPlugin { /** * This is a doubly-linked list. */ struct TransportPlugin *next; /** * This is a doubly-linked list. */ struct TransportPlugin *prev; /** * API of the transport as returned by the plugin's * initialization function. */ struct GNUNET_TRANSPORT_PluginFunctions *api; /** * Short name for the plugin (i.e. "tcp"). */ char *short_name; /** * Name of the library (i.e. "gnunet_plugin_transport_tcp"). */ char *lib_name; /** * Environment this transport service is using * for this plugin. */ struct GNUNET_TRANSPORT_PluginEnvironment env; }; /** * Head of DLL of all loaded plugins. */ static struct TransportPlugin *plugins_head; /** * Head of DLL of all loaded plugins. */ static struct TransportPlugin *plugins_tail; /** * Load and initialize all plugins. The respective functions will be * invoked by the plugins when the respective events happen. The * closure will be set to a 'const char*' containing the name of the * plugin that caused the call. * * @param recv_cb function to call when data is received * @param address_cb function to call when our public addresses changed * @param session_end_cb function to call when a session was terminated * @param address_type_cb function to call when a address type is requested */ void GST_plugins_load (GNUNET_TRANSPORT_PluginReceiveCallback recv_cb, GNUNET_TRANSPORT_AddressNotification address_cb, GNUNET_TRANSPORT_SessionEnd session_end_cb, GNUNET_TRANSPORT_AddressToType address_type_cb) { struct TransportPlugin *plug; struct TransportPlugin *next; unsigned long long tneigh; char *libname; char *plugs; char *pos; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (GST_cfg, "TRANSPORT", "NEIGHBOUR_LIMIT", &tneigh)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Transport service is lacking NEIGHBOUR_LIMIT option.\n")); return; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (GST_cfg, "TRANSPORT", "PLUGINS", &plugs)) return; GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting transport plugins `%s'\n"), plugs); for (pos = strtok (plugs, " "); pos != NULL; pos = strtok (NULL, " ")) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' transport plugin\n"), pos); GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", pos); plug = GNUNET_malloc (sizeof (struct TransportPlugin)); plug->short_name = GNUNET_strdup (pos); plug->lib_name = libname; plug->env.cfg = GST_cfg; plug->env.my_identity = &GST_my_identity; plug->env.get_our_hello = &GST_hello_get; plug->env.cls = plug->short_name; plug->env.receive = recv_cb; plug->env.notify_address = address_cb; plug->env.session_end = session_end_cb; plug->env.get_address_type = address_type_cb; plug->env.max_connections = tneigh; plug->env.stats = GST_stats; GNUNET_CONTAINER_DLL_insert (plugins_head, plugins_tail, plug); } GNUNET_free (plugs); next = plugins_head; while (next != NULL) { plug = next; next = plug->next; plug->api = GNUNET_PLUGIN_load (plug->lib_name, &plug->env); if (plug->api == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to load transport plugin for `%s'\n"), plug->lib_name); GNUNET_CONTAINER_DLL_remove (plugins_head, plugins_tail, plug); GNUNET_free (plug->short_name); GNUNET_free (plug->lib_name); GNUNET_free (plug); } } } /** * Unload all plugins */ void GST_plugins_unload () { struct TransportPlugin *plug; while (NULL != (plug = plugins_head)) { GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api)); GNUNET_free (plug->lib_name); GNUNET_free (plug->short_name); GNUNET_CONTAINER_DLL_remove (plugins_head, plugins_tail, plug); GNUNET_free (plug); } } /** * Obtain the plugin API based on a plugin name. * * @param name name of the plugin * @return the plugin's API, NULL if the plugin is not loaded */ struct GNUNET_TRANSPORT_PluginFunctions * GST_plugins_find (const char *name) { struct TransportPlugin *head = plugins_head; while ((head != NULL) && (0 != strcmp (name, head->short_name))) head = head->next; if (NULL == head) return NULL; return head->api; } /** * Convert a given address to a human-readable format. Note that the * return value will be overwritten on the next call to this function. * * @param address the address to convert * @return statically allocated (!) human-readable address */ const char * GST_plugins_a2s (const struct GNUNET_HELLO_Address *address) { struct GNUNET_TRANSPORT_PluginFunctions *api; static char unable_to_show[1024]; if (address == NULL) return ""; api = GST_plugins_find (address->transport_name); if (NULL == api) return ""; if (0 == address->address_length) { GNUNET_snprintf (unable_to_show, sizeof (unable_to_show), "", (unsigned int) address->address_length, address->transport_name); return unable_to_show; } return api->address_to_string (NULL, address->address, address->address_length); } /* end of file gnunet-service-transport_plugins.c */ gnunet-0.9.3/src/transport/test_transport_api_timeout_unix_peer2.conf0000644000175000017500000000104311721510741023265 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-unix-p2/ DEFAULTCONFIG = test_transport_api_unix_peer2.conf [arm] PORT = 12135 UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12134 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12133 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12132 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12131 PLUGINS = unix UNIXPATH = /tmp/gnunet-p2-service-transport.sock [transport-unix] PORT = 12136 gnunet-0.9.3/src/transport/test_transport_api_unreliability_constant_udp_peer2.conf0000644000175000017500000000111411665472561026206 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-udp-p2/ DEFAULTCONFIG = test_transport_api_unreliability_constant_udp_peer2.conf [transport-udp] PORT = 12050 MAX_BPS = 1073741824 [arm] PORT = 12055 UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12054 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12053 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12052 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12051 PLUGINS = udp UNIXPATH = /tmp/gnunet-p2-service-transport.sock gnunet-0.9.3/src/transport/test_quota_compliance_http_asymmetric_peer2.conf0000644000175000017500000000115411661530125024412 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test_quota_compliance_peer2 DEFAULTCONFIG = test_quota_compliance_http_peer2.conf [transport-http] PORT = 3010 [arm] PORT = 3015 UNIXPATH = /tmp/test_quota_compliance_http_arm_peer2.sock [statistics] PORT = 3014 UNIXPATH = /tmp/test_quota_compliance_http_statistics_peer2.sock [resolver] PORT = 3013 UNIXPATH = /tmp/test_quota_compliance_http_resolver_peer2.sock [peerinfo] PORT = 3012 UNIXPATH = /tmp/test_quota_compliance_http_peerinfo_peer2.sock [transport] PORT = 3011 PLUGINS = http UNIXPATH = /tmp/test_quota_compliance_http_transport_peer2.sock gnunet-0.9.3/src/transport/plugin_transport_wlan.c0000644000175000017500000014133311760502551017375 00000000000000/* This file is part of GNUnet (C) 2010, 2011, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/plugin_transport_wlan.c * @brief transport plugin for wlan * @author David Brodski * @author Christian Grothoff */ #include "platform.h" #include "gnunet_hello_lib.h" #include "gnunet_protocols.h" #include "gnunet_util_lib.h" #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" #include "gnunet_transport_plugin.h" #include "plugin_transport_wlan.h" #include "gnunet_common.h" #include "gnunet_crypto_lib.h" #include "gnunet_fragmentation_lib.h" #include "gnunet_constants.h" #define LOG(kind,...) GNUNET_log_from (kind, "transport-wlan",__VA_ARGS__) /** * Max size of packet (that we give to the WLAN driver for transmission) */ #define WLAN_MTU 1430 /** * time out of a mac endpoint */ #define MACENDPOINT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 2) /** * We reduce the frequence of HELLO beacons in relation to * the number of MAC addresses currently visible to us. * This is the multiplication factor. */ #define HELLO_BEACON_SCALING_FACTOR GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2) /** * Maximum number of messages in defragmentation queue per MAC */ #define MESSAGES_IN_DEFRAG_QUEUE_PER_MAC 2 /** * Link layer control fields for better compatibility * (i.e. GNUnet over WLAN is not IP-over-WLAN). */ #define WLAN_LLC_DSAP_FIELD 0x1f #define WLAN_LLC_SSAP_FIELD 0x1f GNUNET_NETWORK_STRUCT_BEGIN /** * Header for messages which need fragmentation. This is the format of * a message we obtain AFTER defragmentation. We then need to check * the CRC and then tokenize the payload and pass it to the * 'receive' callback. */ struct WlanHeader { /** * Message type is GNUNET_MESSAGE_TYPE_WLAN_DATA. */ struct GNUNET_MessageHeader header; /** * CRC32 checksum (only over the payload), in NBO. */ uint32_t crc GNUNET_PACKED; /** * Sender of the message. */ struct GNUNET_PeerIdentity sender; /** * Target of the message. */ struct GNUNET_PeerIdentity target; /* followed by payload, possibly including multiple messages! */ }; GNUNET_NETWORK_STRUCT_END /** * Information kept for each message that is yet to be fragmented and * transmitted. */ struct PendingMessage { /** * next entry in the DLL */ struct PendingMessage *next; /** * previous entry in the DLL */ struct PendingMessage *prev; /** * The pending message */ struct WlanHeader *msg; /** * Continuation function to call once the message * has been sent. Can be NULL if there is no * continuation to call. */ GNUNET_TRANSPORT_TransmitContinuation transmit_cont; /** * Cls for transmit_cont */ void *transmit_cont_cls; /** * Timeout task (for this message). */ GNUNET_SCHEDULER_TaskIdentifier timeout_task; }; /** * Session handle for connections with other peers. */ struct Session { /** * API requirement (must be first). */ struct SessionHeader header; /** * We keep all sessions in a DLL at their respective * 'struct MACEndpoint'. */ struct Session *next; /** * We keep all sessions in a DLL at their respective * 'struct MACEndpoint'. */ struct Session *prev; /** * MAC endpoint with the address of this peer. */ struct MacEndpoint *mac; /** * Head of messages currently pending for transmission to this peer. */ struct PendingMessage *pending_message_head; /** * Tail of messages currently pending for transmission to this peer. */ struct PendingMessage *pending_message_tail; /** * To whom are we talking to (set to our identity * if we are still waiting for the welcome message) */ struct GNUNET_PeerIdentity target; /** * When should this session time out? */ struct GNUNET_TIME_Absolute timeout; /** * Timeout task (for the session). */ GNUNET_SCHEDULER_TaskIdentifier timeout_task; }; /** * Struct for messages that are being fragmented in a MAC's transmission queue. */ struct FragmentMessage { /** * This is a doubly-linked list. */ struct FragmentMessage *next; /** * This is a doubly-linked list. */ struct FragmentMessage *prev; /** * MAC endpoint this message belongs to */ struct MacEndpoint *macendpoint; /** * Fragmentation context */ struct GNUNET_FRAGMENT_Context *fragcontext; /** * Transmission handle to helper (to cancel if the frag context * is destroyed early for some reason). */ struct GNUNET_HELPER_SendHandle *sh; /** * Intended recipient. */ struct GNUNET_PeerIdentity target; /** * Timeout value for the message. */ struct GNUNET_TIME_Absolute timeout; /** * Timeout task. */ GNUNET_SCHEDULER_TaskIdentifier timeout_task; /** * Continuation to call when we're done with this message. */ GNUNET_TRANSPORT_TransmitContinuation cont; /** * Closure for 'cont' */ void *cont_cls; }; /** * Struct to represent one network card connection */ struct MacEndpoint { /** * We keep all MACs in a DLL in the plugin. */ struct MacEndpoint *next; /** * We keep all MACs in a DLL in the plugin. */ struct MacEndpoint *prev; /** * Pointer to the global plugin struct. */ struct Plugin *plugin; /** * Head of sessions that use this MAC. */ struct Session *sessions_head; /** * Tail of sessions that use this MAC. */ struct Session *sessions_tail; /** * Head of messages we are currently sending to this MAC. */ struct FragmentMessage *sending_messages_head; /** * Tail of messages we are currently sending to this MAC. */ struct FragmentMessage *sending_messages_tail; /** * Defrag context for this MAC */ struct GNUNET_DEFRAGMENT_Context *defrag; /** * When should this endpoint time out? */ struct GNUNET_TIME_Absolute timeout; /** * Timeout task. */ GNUNET_SCHEDULER_TaskIdentifier timeout_task; /** * count of messages in the fragment out queue for this mac endpoint */ unsigned int fragment_messages_out_count; /** * peer mac address */ struct GNUNET_TRANSPORT_WLAN_MacAddress addr; /** * Desired transmission power for this MAC */ uint16_t tx_power; /** * Desired transmission rate for this MAC */ uint8_t rate; /** * Antenna we should use for this MAC */ uint8_t antenna; }; /** * Encapsulation of all of the state of the plugin. */ struct Plugin { /** * Our environment. */ struct GNUNET_TRANSPORT_PluginEnvironment *env; /** * Handle to helper process for priviledged operations. */ struct GNUNET_HELPER_Handle *suid_helper; /** * ARGV-vector for the helper (all helpers take only the binary * name, one actual argument, plus the NULL terminator for 'argv'). */ char * helper_argv[3]; /** * The interface of the wlan card given to us by the user. */ char *interface; /** * Tokenizer for demultiplexing of data packets resulting from defragmentation. */ struct GNUNET_SERVER_MessageStreamTokenizer *fragment_data_tokenizer; /** * Tokenizer for demultiplexing of data packets received from the suid helper */ struct GNUNET_SERVER_MessageStreamTokenizer *helper_payload_tokenizer; /** * Tokenizer for demultiplexing of data packets that follow the WLAN Header */ struct GNUNET_SERVER_MessageStreamTokenizer *wlan_header_payload_tokenizer; /** * Head of list of open connections. */ struct MacEndpoint *mac_head; /** * Tail of list of open connections. */ struct MacEndpoint *mac_tail; /** * Number of connections */ unsigned int mac_count; /** * Task that periodically sends a HELLO beacon via the helper. */ GNUNET_SCHEDULER_TaskIdentifier beacon_task; /** * Tracker for bandwidth limit */ struct GNUNET_BANDWIDTH_Tracker tracker; /** * The mac_address of the wlan card given to us by the helper. */ struct GNUNET_TRANSPORT_WLAN_MacAddress mac_address; /** * Have we received a control message with our MAC address yet? */ int have_mac; }; /** * Information associated with a message. Can contain * the session or the MAC endpoint associated with the * message (or both). */ struct MacAndSession { /** * NULL if the identity of the other peer is not known. */ struct Session *session; /** * MAC address of the other peer, NULL if not known. */ struct MacEndpoint *endpoint; }; /** * Print MAC addresses nicely. * * @param mac the mac address * @return string to a static buffer with the human-readable mac, will be overwritten during the next call to this function */ static const char * mac_to_string (const struct GNUNET_TRANSPORT_WLAN_MacAddress * mac) { static char macstr[20]; GNUNET_snprintf (macstr, sizeof (macstr), "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X", mac->mac[0], mac->mac[1], mac->mac[2], mac->mac[3], mac->mac[4], mac->mac[5]); return macstr; } /** * Fill the radiotap header * * @param endpoint pointer to the endpoint, can be NULL * @param header pointer to the radiotap header * @param size total message size */ static void get_radiotap_header (struct MacEndpoint *endpoint, struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *header, uint16_t size) { header->header.type = ntohs (GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER); header->header.size = ntohs (size); if (NULL != endpoint) { header->rate = endpoint->rate; header->tx_power = endpoint->tx_power; header->antenna = endpoint->antenna; } else { header->rate = 255; header->tx_power = 0; header->antenna = 0; } } /** * Generate the WLAN hardware header for one packet * * @param plugin the plugin handle * @param header address to write the header to * @param to_mac_addr address of the recipient * @param size size of the whole packet, needed to calculate the time to send the packet */ static void get_wlan_header (struct Plugin *plugin, struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *header, const struct GNUNET_TRANSPORT_WLAN_MacAddress *to_mac_addr, unsigned int size) { const int rate = 11000000; header->frame_control = htons (IEEE80211_FC0_TYPE_DATA); header->addr1 = *to_mac_addr; header->addr2 = plugin->mac_address; header->addr3 = mac_bssid_gnunet; header->duration = GNUNET_htole16 ((size * 1000000) / rate + 290); header->sequence_control = 0; // FIXME? header->llc[0] = WLAN_LLC_DSAP_FIELD; header->llc[1] = WLAN_LLC_SSAP_FIELD; header->llc[2] = 0; // FIXME? header->llc[3] = 0; // FIXME? } /** * Send an ACK for a fragment we received. * * @param cls the 'struct MacEndpoint' the ACK must be sent to * @param msg_id id of the message * @param hdr pointer to the hdr where the ack is stored */ static void send_ack (void *cls, uint32_t msg_id, const struct GNUNET_MessageHeader *hdr) { struct MacEndpoint *endpoint = cls; struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage* radio_header; uint16_t msize = ntohs (hdr->size); size_t size = sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) + msize; char buf[size]; if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending ACK to helper\n"); radio_header = (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) buf; get_radiotap_header (endpoint, radio_header, size); get_wlan_header (endpoint->plugin, &radio_header->frame, &endpoint->addr, size); memcpy (&radio_header[1], hdr, msize); if (NULL != GNUNET_HELPER_send (endpoint->plugin->suid_helper, &radio_header->header, GNUNET_NO /* dropping ACKs is bad */, NULL, NULL)) GNUNET_STATISTICS_update (endpoint->plugin->env->stats, _("# WLAN ACKs sent"), 1, GNUNET_NO); } /** * Handles the data after all fragments are put together * * @param cls macendpoint this messages belongs to * @param hdr pointer to the data */ static void wlan_data_message_handler (void *cls, const struct GNUNET_MessageHeader *hdr) { struct MacEndpoint *endpoint = cls; struct Plugin *plugin = endpoint->plugin; struct MacAndSession mas; GNUNET_STATISTICS_update (plugin->env->stats, _("# WLAN messages defragmented"), 1, GNUNET_NO); mas.session = NULL; mas.endpoint = endpoint; (void) GNUNET_SERVER_mst_receive (plugin->fragment_data_tokenizer, &mas, (const char *) hdr, ntohs (hdr->size), GNUNET_YES, GNUNET_NO); } /** * Free a session * * @param session the session free */ static void free_session (struct Session *session) { struct MacEndpoint *endpoint = session->mac; struct PendingMessage *pm; endpoint->plugin->env->session_end (endpoint->plugin->env->cls, &session->target, session); while (NULL != (pm = session->pending_message_head)) { GNUNET_CONTAINER_DLL_remove (session->pending_message_head, session->pending_message_tail, pm); if (GNUNET_SCHEDULER_NO_TASK != pm->timeout_task) { GNUNET_SCHEDULER_cancel (pm->timeout_task); pm->timeout_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_free (pm->msg); GNUNET_free (pm); } GNUNET_CONTAINER_DLL_remove (endpoint->sessions_head, endpoint->sessions_tail, session); if (session->timeout_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (session->timeout_task); session->timeout_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_STATISTICS_update (endpoint->plugin->env->stats, _("# WLAN sessions allocated"), -1, GNUNET_NO); GNUNET_free (session); } /** * A session is timing out. Clean up. * * @param cls pointer to the Session * @param tc pointer to the GNUNET_SCHEDULER_TaskContext */ static void session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Session * session = cls; struct GNUNET_TIME_Relative timeout; session->timeout_task = GNUNET_SCHEDULER_NO_TASK; timeout = GNUNET_TIME_absolute_get_remaining (session->timeout); if (0 == timeout.rel_value) { free_session (session); return; } session->timeout_task = GNUNET_SCHEDULER_add_delayed (timeout, &session_timeout, session); } /** * Create a new session * * @param endpoint pointer to the mac endpoint of the peer * @param peer peer identity to use for this session * @return returns the session */ static struct Session * create_session (struct MacEndpoint *endpoint, const struct GNUNET_PeerIdentity *peer) { struct Session *session; for (session = endpoint->sessions_head; NULL != session; session = session->next) if (0 == memcmp (peer, &session->target, sizeof (struct GNUNET_PeerIdentity))) { session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); return session; } GNUNET_STATISTICS_update (endpoint->plugin->env->stats, _("# WLAN sessions allocated"), 1, GNUNET_NO); session = GNUNET_malloc (sizeof (struct Session)); GNUNET_CONTAINER_DLL_insert_tail (endpoint->sessions_head, endpoint->sessions_tail, session); session->mac = endpoint; session->target = *peer; session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); session->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, &session_timeout, session); LOG (GNUNET_ERROR_TYPE_DEBUG, "Created new session for peer `%s' with endpoint %s\n", GNUNET_i2s (peer), mac_to_string (&endpoint->addr)); return session; } /** * Function called once we have successfully given the fragment * message to the SUID helper process and we are thus ready for * the next fragment. * * @param cls the 'struct FragmentMessage' * @param result result of the operation (GNUNET_OK on success, GNUNET_NO if the helper died, GNUNET_SYSERR * if the helper was stopped) */ static void fragment_transmission_done (void *cls, int result) { struct FragmentMessage *fm = cls; fm->sh = NULL; GNUNET_FRAGMENT_context_transmission_done (fm->fragcontext); } /** * Transmit a fragment of a message. * * @param cls 'struct FragmentMessage' this fragment message belongs to * @param hdr pointer to the start of the fragment message */ static void transmit_fragment (void *cls, const struct GNUNET_MessageHeader *hdr) { struct FragmentMessage *fm = cls; struct MacEndpoint *endpoint = fm->macendpoint; size_t size; uint16_t msize; msize = ntohs (hdr->size); size = sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) + msize; { char buf[size]; struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *radio_header; radio_header = (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) buf; get_radiotap_header (endpoint, radio_header, size); get_wlan_header (endpoint->plugin, &radio_header->frame, &endpoint->addr, size); memcpy (&radio_header[1], hdr, msize); GNUNET_assert (NULL == fm->sh); fm->sh = GNUNET_HELPER_send (endpoint->plugin->suid_helper, &radio_header->header, GNUNET_NO, &fragment_transmission_done, fm); if (NULL != fm->sh) GNUNET_STATISTICS_update (endpoint->plugin->env->stats, _("# WLAN message fragments sent"), 1, GNUNET_NO); else GNUNET_FRAGMENT_context_transmission_done (fm->fragcontext); } } /** * Frees the space of a message in the fragment queue (send queue) * * @param fm message to free */ static void free_fragment_message (struct FragmentMessage *fm) { struct MacEndpoint *endpoint = fm->macendpoint; GNUNET_STATISTICS_update (endpoint->plugin->env->stats, _("# WLAN messages pending (with fragmentation)"), -1, GNUNET_NO); GNUNET_CONTAINER_DLL_remove (endpoint->sending_messages_head, endpoint->sending_messages_tail, fm); if (NULL != fm->sh) { GNUNET_HELPER_send_cancel (fm->sh); fm->sh = NULL; } GNUNET_FRAGMENT_context_destroy (fm->fragcontext); if (fm->timeout_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (fm->timeout_task); fm->timeout_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_free (fm); } /** * A FragmentMessage has timed out. Remove it. * * @param cls pointer to the 'struct FragmentMessage' * @param tc pointer to the GNUNET_SCHEDULER_TaskContext */ static void fragmentmessage_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct FragmentMessage *fm = cls; fm->timeout_task = GNUNET_SCHEDULER_NO_TASK; if (NULL != fm->cont) { fm->cont (fm->cont_cls, &fm->target, GNUNET_SYSERR); fm->cont = NULL; } free_fragment_message (fm); } /** * Transmit a message to the given destination with fragmentation. * * @param endpoint desired destination * @param timeout how long can the message wait? * @param target peer that should receive the message * @param msg message to transmit * @param cont continuation to call once the message has * been transmitted (or if the transport is ready * for the next transmission call; or if the * peer disconnected...); can be NULL * @param cont_cls closure for cont */ static void send_with_fragmentation (struct MacEndpoint *endpoint, struct GNUNET_TIME_Relative timeout, const struct GNUNET_PeerIdentity *target, const struct GNUNET_MessageHeader *msg, GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) { struct FragmentMessage *fm; struct Plugin *plugin; plugin = endpoint->plugin; fm = GNUNET_malloc (sizeof (struct FragmentMessage)); fm->macendpoint = endpoint; fm->target = *target; fm->timeout = GNUNET_TIME_relative_to_absolute (timeout); fm->cont = cont; fm->cont_cls = cont_cls; fm->fragcontext = GNUNET_FRAGMENT_context_create (plugin->env->stats, WLAN_MTU, &plugin->tracker, GNUNET_TIME_UNIT_SECONDS, msg, &transmit_fragment, fm); fm->timeout_task = GNUNET_SCHEDULER_add_delayed (timeout, &fragmentmessage_timeout, fm); GNUNET_CONTAINER_DLL_insert_tail (endpoint->sending_messages_head, endpoint->sending_messages_tail, fm); } /** * Free a MAC endpoint. * * @param endpoint pointer to the MacEndpoint to free */ static void free_macendpoint (struct MacEndpoint *endpoint) { struct Plugin *plugin = endpoint->plugin; struct FragmentMessage *fm; struct Session *session; GNUNET_STATISTICS_update (plugin->env->stats, _("# WLAN MAC endpoints allocated"), -1, GNUNET_NO); while (NULL != (session = endpoint->sessions_head)) free_session (session); while (NULL != (fm = endpoint->sending_messages_head)) free_fragment_message (fm); GNUNET_CONTAINER_DLL_remove (plugin->mac_head, plugin->mac_tail, endpoint); if (NULL != endpoint->defrag) { GNUNET_DEFRAGMENT_context_destroy(endpoint->defrag); endpoint->defrag = NULL; } plugin->mac_count--; if (GNUNET_SCHEDULER_NO_TASK != endpoint->timeout_task) { GNUNET_SCHEDULER_cancel (endpoint->timeout_task); endpoint->timeout_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_free (endpoint); } /** * A MAC endpoint is timing out. Clean up. * * @param cls pointer to the MacEndpoint * @param tc pointer to the GNUNET_SCHEDULER_TaskContext */ static void macendpoint_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct MacEndpoint *endpoint = cls; struct GNUNET_TIME_Relative timeout; endpoint->timeout_task = GNUNET_SCHEDULER_NO_TASK; timeout = GNUNET_TIME_absolute_get_remaining (endpoint->timeout); if (0 == timeout.rel_value) { free_macendpoint (endpoint); return; } endpoint->timeout_task = GNUNET_SCHEDULER_add_delayed (timeout, &macendpoint_timeout, endpoint); } /** * Find (or create) a MacEndpoint with a specific MAC address * * @param plugin pointer to the plugin struct * @param addr the MAC address of the endpoint * @return handle to our data structure for this MAC */ static struct MacEndpoint * create_macendpoint (struct Plugin *plugin, const struct GNUNET_TRANSPORT_WLAN_MacAddress *addr) { struct MacEndpoint *pos; for (pos = plugin->mac_head; NULL != pos; pos = pos->next) if (0 == memcmp (addr, &pos->addr, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) return pos; pos = GNUNET_malloc (sizeof (struct MacEndpoint)); pos->addr = *addr; pos->plugin = plugin; pos->defrag = GNUNET_DEFRAGMENT_context_create (plugin->env->stats, WLAN_MTU, MESSAGES_IN_DEFRAG_QUEUE_PER_MAC, pos, &wlan_data_message_handler, &send_ack); pos->timeout = GNUNET_TIME_relative_to_absolute (MACENDPOINT_TIMEOUT); pos->timeout_task = GNUNET_SCHEDULER_add_delayed (MACENDPOINT_TIMEOUT, &macendpoint_timeout, pos); GNUNET_CONTAINER_DLL_insert (plugin->mac_head, plugin->mac_tail, pos); plugin->mac_count++; GNUNET_STATISTICS_update (plugin->env->stats, _("# WLAN MAC endpoints allocated"), 1, GNUNET_NO); LOG (GNUNET_ERROR_TYPE_DEBUG, "New MAC endpoint `%s'\n", mac_to_string (addr)); return pos; } /** * Creates a new outbound session the transport service will use to send data to the * peer * * @param cls the plugin * @param address the address * @return the session or NULL of max connections exceeded */ static struct Session * wlan_plugin_get_session (void *cls, const struct GNUNET_HELLO_Address *address) { struct Plugin *plugin = cls; struct MacEndpoint *endpoint; if (NULL == address) return NULL; if (sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress) != address->address_length) { GNUNET_break (0); return NULL; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Service asked to create session for peer `%s' with MAC `%s'\n", GNUNET_i2s (&address->peer), mac_to_string (address->address)); endpoint = create_macendpoint (plugin, address->address); return create_session (endpoint, &address->peer); } /** * Function that can be used to force the plugin to disconnect * from the given peer and cancel all previous transmissions * (and their continuation). * * @param cls closure * @param target peer from which to disconnect */ static void wlan_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) { struct Plugin *plugin = cls; struct Session *session; struct MacEndpoint *endpoint; for (endpoint = plugin->mac_head; NULL != endpoint; endpoint = endpoint->next) for (session = endpoint->sessions_head; NULL != session; session = session->next) if (0 == memcmp (target, &session->target, sizeof (struct GNUNET_PeerIdentity))) { free_session (session); break; /* inner-loop only (in case peer has another MAC as well!) */ } } /** * Function that can be used by the transport service to transmit * a message using the plugin. Note that in the case of a * peer disconnecting, the continuation MUST be called * prior to the disconnect notification itself. This function * will be called with this peer's HELLO message to initiate * a fresh connection to another peer. * * @param cls closure * @param session which session must be used * @param msgbuf the message to transmit * @param msgbuf_size number of bytes in 'msgbuf' * @param priority how important is the message (most plugins will * ignore message priority and just FIFO) * @param to how long to wait at most for the transmission (does not * require plugins to discard the message after the timeout, * just advisory for the desired delay; most plugins will ignore * this as well) * @param cont continuation to call once the message has * been transmitted (or if the transport is ready * for the next transmission call; or if the * peer disconnected...); can be NULL * @param cont_cls closure for cont * @return number of bytes used (on the physical network, with overheads); * -1 on hard errors (i.e. address invalid); 0 is a legal value * and does NOT mean that the message was not transmitted (DV) */ static ssize_t wlan_plugin_send (void *cls, struct Session *session, const char *msgbuf, size_t msgbuf_size, unsigned int priority, struct GNUNET_TIME_Relative to, GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) { struct Plugin *plugin = cls; struct WlanHeader *wlanheader; size_t size = msgbuf_size + sizeof (struct WlanHeader); char buf[size] GNUNET_ALIGN; LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting %u bytes of payload to peer `%s' (starting with %u byte message of type %u)\n", msgbuf_size, GNUNET_i2s (&session->target), (unsigned int) ntohs (((struct GNUNET_MessageHeader*)msgbuf)->size), (unsigned int) ntohs (((struct GNUNET_MessageHeader*)msgbuf)->type)); wlanheader = (struct WlanHeader *) buf; wlanheader->header.size = htons (msgbuf_size + sizeof (struct WlanHeader)); wlanheader->header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA); wlanheader->sender = *plugin->env->my_identity; wlanheader->target = session->target; wlanheader->crc = htonl (GNUNET_CRYPTO_crc32_n (msgbuf, msgbuf_size)); memcpy (&wlanheader[1], msgbuf, msgbuf_size); send_with_fragmentation (session->mac, to, &session->target, &wlanheader->header, cont, cont_cls); return size; } /** * We have received data from the WLAN via some session. Process depending * on the message type (HELLO, DATA, FRAGMENTATION or FRAGMENTATION-ACK). * * @param cls pointer to the plugin * @param client pointer to the session this message belongs to * @param hdr start of the message */ static int process_data (void *cls, void *client, const struct GNUNET_MessageHeader *hdr) { struct Plugin *plugin = cls; struct MacAndSession *mas = client; struct MacAndSession xmas; #define NUM_ATS 2 struct GNUNET_ATS_Information ats[NUM_ATS]; /* FIXME: do better here */ struct FragmentMessage *fm; struct GNUNET_PeerIdentity tmpsource; const struct WlanHeader *wlanheader; int ret; uint16_t msize; ats[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); ats[0].value = htonl (1); ats[1].type = htonl (GNUNET_ATS_NETWORK_TYPE); ats[1].value = htonl (GNUNET_ATS_NET_WLAN); msize = ntohs (hdr->size); switch (ntohs (hdr->type)) { case GNUNET_MESSAGE_TYPE_HELLO: if (GNUNET_OK != GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) hdr, &tmpsource)) { GNUNET_break_op (0); break; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing %u bytes of HELLO from peer `%s' at MAC %s\n", (unsigned int) msize, GNUNET_i2s (&tmpsource), mac_to_string (&mas->endpoint->addr)); GNUNET_STATISTICS_update (plugin->env->stats, _("# HELLO messages received via WLAN"), 1, GNUNET_NO); plugin->env->receive (plugin->env->cls, &tmpsource, hdr, ats, NUM_ATS, mas->session, (mas->endpoint == NULL) ? NULL : (const char *) &mas->endpoint->addr, (mas->endpoint == NULL) ? 0 : sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); break; case GNUNET_MESSAGE_TYPE_FRAGMENT: if (NULL == mas->endpoint) { GNUNET_break (0); break; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing %u bytes of FRAGMENT from MAC %s\n", (unsigned int) msize, mac_to_string (&mas->endpoint->addr)); GNUNET_STATISTICS_update (plugin->env->stats, _("# fragments received via WLAN"), 1, GNUNET_NO); (void) GNUNET_DEFRAGMENT_process_fragment (mas->endpoint->defrag, hdr); break; case GNUNET_MESSAGE_TYPE_FRAGMENT_ACK: if (NULL == mas->endpoint) { GNUNET_break (0); break; } GNUNET_STATISTICS_update (plugin->env->stats, _("# ACKs received via WLAN"), 1, GNUNET_NO); for (fm = mas->endpoint->sending_messages_head; NULL != fm; fm = fm->next) { ret = GNUNET_FRAGMENT_process_ack (fm->fragcontext, hdr); if (GNUNET_OK == ret) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Got last ACK, finished message transmission to `%s' (%p)\n", mac_to_string (&mas->endpoint->addr), fm); mas->endpoint->timeout = GNUNET_TIME_relative_to_absolute (MACENDPOINT_TIMEOUT); if (NULL != fm->cont) { fm->cont (fm->cont_cls, &fm->target, GNUNET_OK); fm->cont = NULL; } free_fragment_message (fm); break; } if (GNUNET_NO == ret) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Got an ACK, message transmission to `%s' not yet finished\n", mac_to_string (&mas->endpoint->addr)); break; } } LOG (GNUNET_ERROR_TYPE_DEBUG, "ACK not matched against any active fragmentation with MAC `%s'\n", mac_to_string (&mas->endpoint->addr)); break; case GNUNET_MESSAGE_TYPE_WLAN_DATA: if (NULL == mas->endpoint) { GNUNET_break (0); break; } if (msize < sizeof (struct WlanHeader)) { GNUNET_break (0); break; } wlanheader = (const struct WlanHeader *) hdr; if (0 != memcmp (&wlanheader->target, plugin->env->my_identity, sizeof (struct GNUNET_PeerIdentity))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "WLAN data for `%s', not for me, ignoring\n", GNUNET_i2s (&wlanheader->target)); break; } if (ntohl (wlanheader->crc) != GNUNET_CRYPTO_crc32_n (&wlanheader[1], msize - sizeof (struct WlanHeader))) { GNUNET_STATISTICS_update (plugin->env->stats, _("# WLAN DATA messages discarded due to CRC32 error"), 1, GNUNET_NO); break; } xmas.endpoint = mas->endpoint; xmas.session = create_session (mas->endpoint, &wlanheader->sender); LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing %u bytes of WLAN DATA from peer `%s'\n", (unsigned int) msize, GNUNET_i2s (&wlanheader->sender)); (void) GNUNET_SERVER_mst_receive (plugin->wlan_header_payload_tokenizer, &xmas, (const char *) &wlanheader[1], msize - sizeof (struct WlanHeader), GNUNET_YES, GNUNET_NO); break; default: if (NULL == mas->endpoint) { GNUNET_break (0); break; } if (NULL == mas->session) { GNUNET_break (0); break; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Received packet with %u bytes of type %u from peer %s\n", (unsigned int) msize, (unsigned int) ntohs (hdr->type), GNUNET_i2s (&mas->session->target)); plugin->env->receive (plugin->env->cls, &mas->session->target, hdr, ats, NUM_ATS, mas->session, (mas->endpoint == NULL) ? NULL : (const char *) &mas->endpoint->addr, (mas->endpoint == NULL) ? 0 : sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); break; } return GNUNET_OK; } #undef NUM_ATS /** * Function used for to process the data from the suid process * * @param cls the plugin handle * @param client client that send the data (not used) * @param hdr header of the GNUNET_MessageHeader */ static int handle_helper_message (void *cls, void *client, const struct GNUNET_MessageHeader *hdr) { struct Plugin *plugin = cls; const struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *rxinfo; const struct GNUNET_TRANSPORT_WLAN_HelperControlMessage *cm; struct MacAndSession mas; uint16_t msize; msize = ntohs (hdr->size); switch (ntohs (hdr->type)) { case GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL: if (msize != sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage)) { GNUNET_break (0); break; } cm = (const struct GNUNET_TRANSPORT_WLAN_HelperControlMessage *) hdr; if (GNUNET_YES == plugin->have_mac) { if (0 == memcmp (&plugin->mac_address, &cm->mac, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) break; /* no change */ /* remove old address */ plugin->env->notify_address (plugin->env->cls, GNUNET_NO, &plugin->mac_address, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); } plugin->mac_address = cm->mac; plugin->have_mac = GNUNET_YES; LOG (GNUNET_ERROR_TYPE_DEBUG, "Received WLAN_HELPER_CONTROL message with MAC address `%s' for peer `%s'\n", mac_to_string (&cm->mac), GNUNET_i2s (plugin->env->my_identity)); plugin->env->notify_address (plugin->env->cls, GNUNET_YES, &plugin->mac_address, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); break; case GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER: LOG (GNUNET_ERROR_TYPE_DEBUG, "Got data message from helper with %u bytes\n", msize); GNUNET_STATISTICS_update (plugin->env->stats, _("# DATA messages received via WLAN"), 1, GNUNET_NO); if (msize < sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)) { GNUNET_break (0); LOG (GNUNET_ERROR_TYPE_DEBUG, "Size of packet is too small (%u bytes)\n", msize); break; } rxinfo = (const struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *) hdr; /* check if message is actually for us */ if (0 != memcmp (&rxinfo->frame.addr3, &mac_bssid_gnunet, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) { /* Not the GNUnet BSSID */ break; } if ( (0 != memcmp (&rxinfo->frame.addr1, &bc_all_mac, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) && (0 != memcmp (&rxinfo->frame.addr1, &plugin->mac_address, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) ) { /* Neither broadcast nor specifically for us */ break; } if (0 == memcmp (&rxinfo->frame.addr2, &plugin->mac_address, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) { /* packet is FROM us, thus not FOR us */ break; } GNUNET_STATISTICS_update (plugin->env->stats, _("# WLAN DATA messages processed"), 1, GNUNET_NO); LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving %u bytes of data from MAC `%s'\n", (unsigned int) (msize - sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)), mac_to_string (&rxinfo->frame.addr2)); mas.endpoint = create_macendpoint (plugin, &rxinfo->frame.addr2); mas.session = NULL; (void) GNUNET_SERVER_mst_receive (plugin->helper_payload_tokenizer, &mas, (const char*) &rxinfo[1], msize - sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage), GNUNET_YES, GNUNET_NO); break; default: GNUNET_break (0); LOG (GNUNET_ERROR_TYPE_DEBUG, "Unexpected message of type %u (%u bytes)", ntohs (hdr->type), ntohs (hdr->size)); break; } return GNUNET_OK; } /** * Task to (periodically) send a HELLO beacon * * @param cls pointer to the plugin struct * @param tc scheduler context */ static void send_hello_beacon (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Plugin *plugin = cls; uint16_t size; uint16_t hello_size; struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *radioHeader; const struct GNUNET_MessageHeader *hello; hello = plugin->env->get_our_hello (); hello_size = GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello); GNUNET_assert (sizeof (struct WlanHeader) + hello_size <= WLAN_MTU); size = sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) + hello_size; { char buf[size] GNUNET_ALIGN; LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending %u byte HELLO beacon\n", (unsigned int) size); radioHeader = (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage*) buf; get_radiotap_header (NULL, radioHeader, size); get_wlan_header (plugin, &radioHeader->frame, &bc_all_mac, size); memcpy (&radioHeader[1], hello, hello_size); if (NULL != GNUNET_HELPER_send (plugin->suid_helper, &radioHeader->header, GNUNET_YES /* can drop */, NULL, NULL)) GNUNET_STATISTICS_update (plugin->env->stats, _("# HELLO beacons sent via WLAN"), 1, GNUNET_NO); } plugin->beacon_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (HELLO_BEACON_SCALING_FACTOR, plugin->mac_count + 1), &send_hello_beacon, plugin); } /** * Another peer has suggested an address for this * peer and transport plugin. Check that this could be a valid * address. If so, consider adding it to the list * of addresses. * * @param cls closure * @param addr pointer to the address * @param addrlen length of addr * @return GNUNET_OK if this is a plausible address for this peer * and transport */ static int wlan_plugin_address_suggested (void *cls, const void *addr, size_t addrlen) { struct Plugin *plugin = cls; if (addrlen != sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (GNUNET_YES != plugin->have_mac) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Rejecting MAC `%s': I don't know my MAC!\n", mac_to_string (addr)); return GNUNET_NO; /* don't know my MAC */ } if (0 != memcmp (addr, &plugin->mac_address, addrlen)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Rejecting MAC `%s': not my MAC!\n", mac_to_string (addr)); return GNUNET_NO; /* not my MAC */ } return GNUNET_OK; } /** * Function called for a quick conversion of the binary address to * a numeric address. Note that the caller must not free the * address and that the next call to this function is allowed * to override the address again. * * @param cls closure * @param addr binary address * @param addrlen length of the address * @return string representing the same address */ static const char * wlan_plugin_address_to_string (void *cls, const void *addr, size_t addrlen) { const struct GNUNET_TRANSPORT_WLAN_MacAddress *mac; if (sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress) != addrlen) { GNUNET_break (0); return NULL; } mac = addr; return GNUNET_strdup (mac_to_string (mac)); } /** * Convert the transports address to a nice, human-readable format. * * @param cls closure * @param type name of the transport that generated the address * @param addr one of the addresses of the host, NULL for the last address * the specific address format depends on the transport * @param addrlen length of the address * @param numeric should (IP) addresses be displayed in numeric form? * @param timeout after how long should we give up? * @param asc function to call on each string * @param asc_cls closure for asc */ static void wlan_plugin_address_pretty_printer (void *cls, const char *type, const void *addr, size_t addrlen, int numeric, struct GNUNET_TIME_Relative timeout, GNUNET_TRANSPORT_AddressStringCallback asc, void *asc_cls) { const struct GNUNET_TRANSPORT_WLAN_MacAddress *mac; char *ret; if (sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress) != addrlen) { /* invalid address */ LOG (GNUNET_ERROR_TYPE_WARNING, _("WLAN address with invalid size encountered\n")); asc (asc_cls, NULL); return; } mac = addr; ret = GNUNET_strdup (mac_to_string (mac)); asc (asc_cls, ret); GNUNET_free (ret); asc (asc_cls, NULL); } /** * Exit point from the plugin. * * @param cls pointer to the api struct */ void * libgnunet_plugin_transport_wlan_done (void *cls) { struct GNUNET_TRANSPORT_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; struct MacEndpoint *endpoint; struct MacEndpoint *endpoint_next; if (NULL == plugin) { GNUNET_free (api); return NULL; } if (GNUNET_SCHEDULER_NO_TASK != plugin->beacon_task) { GNUNET_SCHEDULER_cancel (plugin->beacon_task); plugin->beacon_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != plugin->suid_helper) { GNUNET_HELPER_stop (plugin->suid_helper); plugin->suid_helper = NULL; } endpoint_next = plugin->mac_head; while (NULL != (endpoint = endpoint_next)) { endpoint_next = endpoint->next; free_macendpoint (endpoint); } if (NULL != plugin->fragment_data_tokenizer) { GNUNET_SERVER_mst_destroy (plugin->fragment_data_tokenizer); plugin->fragment_data_tokenizer = NULL; } if (NULL != plugin->wlan_header_payload_tokenizer) { GNUNET_SERVER_mst_destroy (plugin->wlan_header_payload_tokenizer); plugin->wlan_header_payload_tokenizer = NULL; } if (NULL != plugin->helper_payload_tokenizer) { GNUNET_SERVER_mst_destroy (plugin->helper_payload_tokenizer); plugin->helper_payload_tokenizer = NULL; } GNUNET_free_non_null (plugin->interface); GNUNET_free (plugin); GNUNET_free (api); return NULL; } /** * Function called to convert a string address to * a binary address. * * @param cls closure ('struct Plugin*') * @param addr string address * @param addrlen length of the address * @param buf location to store the buffer * @param added location to store the number of bytes in the buffer. * If the function returns GNUNET_SYSERR, its contents are undefined. * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ static int wlan_string_to_address (void *cls, const char *addr, uint16_t addrlen, void **buf, size_t *added) { struct GNUNET_TRANSPORT_WLAN_MacAddress *mac; unsigned int a[6]; unsigned int i; if ((NULL == addr) || (addrlen == 0)) { GNUNET_break (0); return GNUNET_SYSERR; } if ('\0' != addr[addrlen - 1]) { GNUNET_break (0); return GNUNET_SYSERR; } if (strlen (addr) != addrlen - 1) { GNUNET_break (0); return GNUNET_SYSERR; } if (6 != SSCANF (addr, "%X:%X:%X:%X:%X:%X", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5])) { GNUNET_break (0); return GNUNET_SYSERR; } mac = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); for (i=0;i<6;i++) mac->mac[i] = a[i]; *buf = mac; *added = sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress); return GNUNET_OK; } /** * Entry point for the plugin. * * @param cls closure, the 'struct GNUNET_TRANSPORT_PluginEnvironment*' * @return the 'struct GNUNET_TRANSPORT_PluginFunctions*' or NULL on error */ void * libgnunet_plugin_transport_wlan_init (void *cls) { struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; struct GNUNET_TRANSPORT_PluginFunctions *api; struct Plugin *plugin; char *interface; unsigned long long testmode; /* check for 'special' mode */ if (NULL == env->receive) { /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully initialze the plugin or the API */ api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); api->cls = NULL; api->address_pretty_printer = &wlan_plugin_address_pretty_printer; api->address_to_string = &wlan_plugin_address_to_string; api->string_to_address = &wlan_string_to_address; return api; } testmode = 0; /* check configuration */ if ( (GNUNET_YES == GNUNET_CONFIGURATION_have_value (env->cfg, "transport-wlan", "TESTMODE")) && ( (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-wlan", "TESTMODE", &testmode)) || (testmode > 2) ) ) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid configuration option `%s' in section `%s'\n"), "TESTMODE", "transport-wlan"); return NULL; } if ( (0 == testmode) && (GNUNET_YES != GNUNET_OS_check_helper_binary ("gnunet-helper-transport-wlan")) ) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Helper binary `%s' not SUID, cannot run WLAN transport\n"), "gnunet-helper-transport-wlan"); return NULL; } if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (env->cfg, "transport-wlan", "INTERFACE", &interface)) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Missing configuration option `%s' in section `%s'\n"), "INTERFACE", "transport-wlan"); return NULL; } plugin = GNUNET_malloc (sizeof (struct Plugin)); plugin->interface = interface; plugin->env = env; GNUNET_STATISTICS_set (plugin->env->stats, _("# WLAN sessions allocated"), 0, GNUNET_NO); GNUNET_STATISTICS_set (plugin->env->stats, _("# WLAN MAC endpoints allocated"), 0, 0); GNUNET_BANDWIDTH_tracker_init (&plugin->tracker, GNUNET_BANDWIDTH_value_init (100 * 1024 * 1024 / 8), 100); plugin->fragment_data_tokenizer = GNUNET_SERVER_mst_create (&process_data, plugin); plugin->wlan_header_payload_tokenizer = GNUNET_SERVER_mst_create (&process_data, plugin); plugin->helper_payload_tokenizer = GNUNET_SERVER_mst_create (&process_data, plugin); plugin->beacon_task = GNUNET_SCHEDULER_add_now (&send_hello_beacon, plugin); switch (testmode) { case 0: /* normal */ plugin->helper_argv[0] = (char *) "gnunet-helper-transport-wlan"; plugin->helper_argv[1] = interface; plugin->helper_argv[2] = NULL; plugin->suid_helper = GNUNET_HELPER_start ("gnunet-helper-transport-wlan", plugin->helper_argv, &handle_helper_message, plugin); break; case 1: /* testmode, peer 1 */ plugin->helper_argv[0] = (char *) "gnunet-helper-transport-wlan-dummy"; plugin->helper_argv[1] = (char *) "1"; plugin->helper_argv[2] = NULL; plugin->suid_helper = GNUNET_HELPER_start ("gnunet-helper-transport-wlan-dummy", plugin->helper_argv, &handle_helper_message, plugin); break; case 2: /* testmode, peer 2 */ plugin->helper_argv[0] = (char *) "gnunet-helper-transport-wlan-dummy"; plugin->helper_argv[1] = (char *) "2"; plugin->helper_argv[2] = NULL; plugin->suid_helper = GNUNET_HELPER_start ("gnunet-helper-transport-wlan-dummy", plugin->helper_argv, &handle_helper_message, plugin); break; default: GNUNET_assert (0); } api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); api->cls = plugin; api->send = &wlan_plugin_send; api->get_session = &wlan_plugin_get_session; api->disconnect = &wlan_plugin_disconnect; api->address_pretty_printer = &wlan_plugin_address_pretty_printer; api->check_address = &wlan_plugin_address_suggested; api->address_to_string = &wlan_plugin_address_to_string; api->string_to_address = &wlan_string_to_address; return api; } /* end of plugin_transport_wlan.c */ gnunet-0.9.3/src/transport/template_cfg_peer2.conf0000644000175000017500000000162011750306133017163 00000000000000@INLINE@ test_transport_defaults.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-tcp-p2/ DEFAULTCONFIG = template_cfg_peer2.conf [gnunetd] HOSTKEY = $SERVICEHOME/.hostkey [nat] RETURN_LOCAL_ADDRESSES = YES DISABLEV6 = NO [transport-tcp] PORT = 12100 TIMEOUT = 5 s [transport-udp] BROADCAST = NO [transport-unix] PORT = 12017 [arm] PORT = 12014 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12013 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12012 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12011 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock TRUST = $SERVICEHOME/data/credit/ [transport] #PREFIX = valgrind --leak-check=full PORT = 12010 UNIXPATH = /tmp/gnunet-p2-service-transport.sock [ats] #DEBUG = YES WAN_QUOTA_IN = 1 GB WAN_QUOTA_OUT = 1 GB PORT = 12016 UNIXPATH = /tmp/gnunet-p2-service-ats.sock gnunet-0.9.3/src/transport/transport.conf.in0000644000175000017500000000243411760502552016105 00000000000000[transport] AUTOSTART = YES @UNIXONLY@ PORT = 2091 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-transport #PREFIX = valgrind NEIGHBOUR_LIMIT = 50 ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; PLUGINS = tcp udp UNIXPATH = /tmp/gnunet-service-transport.sock BLACKLIST_FILE = $SERVICEHOME/blacklist # This could possibly be relaxed UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES # DISABLE_SOCKET_FORWARDING = NO # USERNAME = # MAXBUF = # TIMEOUT = # DISABLEV6 = # BINDTO = # REJECT_FROM = # REJECT_FROM6 = # PREFIX = valgrind --leak-check=full [transport-unix] PORT = 22086 [transport-tcp] # Use 0 to ONLY advertise as a peer behind NAT (no port binding) PORT = 2086 ADVERTISED_PORT = 2086 # Maximum number of open TCP connections allowed MAX_CONNECTIONS = 128 TIMEOUT = 5 s # ACCEPT_FROM = # ACCEPT_FROM6 = # REJECT_FROM = # REJECT_FROM6 = # BINDTO = MAX_CONNECTIONS = 128 [transport-udp] PORT = 2086 BROADCAST = YES BROADCAST_INTERVAL = 30000 MAX_BPS = 1000000 [transport-http] PORT = 1080 MAX_CONNECTIONS = 128 [transport-https] PORT = 4433 CRYPTO_INIT = NORMAL KEY_FILE = https.key CERT_FILE = https.cert MAX_CONNECTIONS = 128 [transport-wlan] # Name of the interface in monitor mode (typically monX) INTERFACE = mon0 # Real hardware, no testing TESTMODE = 0 gnunet-0.9.3/src/transport/gnunet-transport.c0000644000175000017500000004213611760502551016275 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/transport/gnunet-transport.c * @brief Tool to help configure, measure and control the transport subsystem. * @author Christian Grothoff * @author Nathan Evans * * This utility can be used to test if a transport mechanism for * GNUnet is properly configured. */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_resolver_service.h" #include "gnunet_protocols.h" #include "gnunet_transport_service.h" #include "gnunet_nat_lib.h" /** * How long do we wait for the NAT test to report success? * Should match NAT_SERVER_TIMEOUT in 'nat_test.c'. */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) #define RESOLUTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) /** * Which peer should we connect to? */ static char *cpid; /** * Handle to transport service. */ static struct GNUNET_TRANSPORT_Handle *handle; /** * Option -s. */ static int benchmark_send; /** * Option -b. */ static int benchmark_receive; /** * Option -l. */ static int benchmark_receive; /** * Option -i. */ static int iterate_connections; /** * Option -t. */ static int test_configuration; /** * Option -m. */ static int monitor_connections; /** * Option -n. */ static int numeric; /** * Global return value (0 success). */ static int ret; /** * Number of bytes of traffic we received so far. */ static unsigned long long traffic_received; /** * Number of bytes of traffic we sent so far. */ static unsigned long long traffic_sent; /** * Starting time of transmitting/receiving data. */ static struct GNUNET_TIME_Absolute start_time; /** * Handle for current transmission request. */ static struct GNUNET_TRANSPORT_TransmitHandle *th; /** * Identity of the peer we transmit to / connect to. * (equivalent to 'cpid' string). */ static struct GNUNET_PeerIdentity pid; /** * Task scheduled for cleanup / termination of the process. */ static GNUNET_SCHEDULER_TaskIdentifier end; static struct GNUNET_CONTAINER_MultiHashMap *peers; /** * Selected level of verbosity. */ static int verbosity; /** * Resolver process handle. */ struct GNUNET_OS_Process *resolver; /** * Number of tasks running that still need the resolver. */ static unsigned int resolver_users; /** * Context for a plugin test. */ struct TestContext { /** * Handle to the active NAT test. */ struct GNUNET_NAT_Test *tst; /** * Task identifier for the timeout. */ GNUNET_SCHEDULER_TaskIdentifier tsk; /** * Name of plugin under test. */ const char *name; }; /** * Display the result of the test. * * @param tc test context * @param result GNUNET_YES on success */ static void display_test_result (struct TestContext *tc, int result) { if (GNUNET_YES != result) { FPRINTF (stderr, "Configuration for plugin `%s' did not work!\n", tc->name); } else { FPRINTF (stderr, "Configuration for plugin `%s' is working!\n", tc->name); } if (GNUNET_SCHEDULER_NO_TASK != tc->tsk) { GNUNET_SCHEDULER_cancel (tc->tsk); tc->tsk = GNUNET_SCHEDULER_NO_TASK; } if (NULL != tc->tst) { GNUNET_NAT_test_stop (tc->tst); tc->tst = NULL; } GNUNET_free (tc); resolver_users--; if ((0 == resolver_users) && (NULL != resolver)) { GNUNET_break (0 == GNUNET_OS_process_kill (resolver, SIGTERM)); GNUNET_OS_process_destroy (resolver); resolver = NULL; } } /** * Function called by NAT on success. * Clean up and update GUI (with success). * * @param cls test context * @param success currently always GNUNET_OK */ static void result_callback (void *cls, int success) { struct TestContext *tc = cls; display_test_result (tc, success); } /** * Function called if NAT failed to confirm success. * Clean up and update GUI (with failure). * * @param cls test context * @param tc scheduler callback */ static void fail_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct TestContext *tstc = cls; tstc->tsk = GNUNET_SCHEDULER_NO_TASK; display_test_result (tstc, GNUNET_NO); } /** * Test our plugin's configuration (NAT traversal, etc.). * * @param cfg configuration to test */ static void do_test_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg) { char *plugins; char *tok; unsigned long long bnd_port; unsigned long long adv_port; struct TestContext *tc; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "transport", "plugins", &plugins)) { FPRINTF (stderr, "%s", _ ("No transport plugins configured, peer will never communicate\n")); ret = 4; return; } for (tok = strtok (plugins, " "); tok != NULL; tok = strtok (NULL, " ")) { char section[12 + strlen (tok)]; GNUNET_snprintf (section, sizeof (section), "transport-%s", tok); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, section, "PORT", &bnd_port)) { FPRINTF (stderr, _("No port configured for plugin `%s', cannot test it\n"), tok); continue; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, section, "ADVERTISED_PORT", &adv_port)) adv_port = bnd_port; if (NULL == resolver) resolver = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-resolver", "gnunet-service-resolver", NULL); resolver_users++; GNUNET_RESOLVER_connect (cfg); tc = GNUNET_malloc (sizeof (struct TestContext)); tc->name = GNUNET_strdup (tok); tc->tst = GNUNET_NAT_test_start (cfg, (0 == strcasecmp (tok, "udp")) ? GNUNET_NO : GNUNET_YES, (uint16_t) bnd_port, (uint16_t) adv_port, &result_callback, tc); if (NULL == tc->tst) { display_test_result (tc, GNUNET_SYSERR); continue; } tc->tsk = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &fail_timeout, tc); } GNUNET_free (plugins); } /** * Shutdown, print statistics. */ static void do_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TIME_Relative duration; if (NULL != th) { GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; } GNUNET_TRANSPORT_disconnect (handle); if (benchmark_receive) { duration = GNUNET_TIME_absolute_get_duration (start_time); FPRINTF (stdout, _("Received %llu bytes/s (%llu bytes in %llu ms)\n"), 1000 * traffic_received / (1 + duration.rel_value), traffic_received, (unsigned long long) duration.rel_value); } if (benchmark_send) { duration = GNUNET_TIME_absolute_get_duration (start_time); FPRINTF (stdout, _("Transmitted %llu bytes/s (%llu bytes in %llu ms)\n"), 1000 * traffic_sent / (1 + duration.rel_value), traffic_sent, (unsigned long long) duration.rel_value); } } /** * Function called to notify a client about the socket * begin ready to queue more data. "buf" will be * NULL and "size" zero if the socket was closed for * writing in the meantime. * * @param cls closure * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_data (void *cls, size_t size, void *buf) { struct GNUNET_MessageHeader *m = buf; GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE); m->size = ntohs (size); m->type = ntohs (GNUNET_MESSAGE_TYPE_DUMMY); memset (&m[1], 52, size - sizeof (struct GNUNET_MessageHeader)); traffic_sent += size; th = GNUNET_TRANSPORT_notify_transmit_ready (handle, &pid, 32 * 1024, 0, GNUNET_TIME_UNIT_FOREVER_REL, &transmit_data, NULL); if (verbosity > 0) FPRINTF (stdout, _("Transmitting %u bytes to %s\n"), (unsigned int) size, GNUNET_i2s (&pid)); return size; } /** * Function called to notify transport users that another * peer connected to us. * * @param cls closure * @param peer the peer that connected * @param ats performance data * @param ats_count number of entries in ats (excluding 0-termination) */ static void notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { if (verbosity > 0) FPRINTF (stdout, _("Connected to %s\n"), GNUNET_i2s (peer)); if (0 != memcmp (&pid, peer, sizeof (struct GNUNET_PeerIdentity))) return; ret = 0; if (benchmark_send) { start_time = GNUNET_TIME_absolute_get (); th = GNUNET_TRANSPORT_notify_transmit_ready (handle, peer, 32 * 1024, 0, GNUNET_TIME_UNIT_FOREVER_REL, &transmit_data, NULL); } else { /* all done, terminate instantly */ GNUNET_SCHEDULER_cancel (end); end = GNUNET_SCHEDULER_add_now (&do_disconnect, NULL); } } /** * Function called to notify transport users that another * peer disconnected from us. * * @param cls closure * @param peer the peer that disconnected */ static void notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { if (verbosity > 0) FPRINTF (stdout, _("Disconnected from %s\n"), GNUNET_i2s (peer)); if ((0 == memcmp (&pid, peer, sizeof (struct GNUNET_PeerIdentity))) && (NULL != th)) { GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; GNUNET_SCHEDULER_cancel (end); end = GNUNET_SCHEDULER_add_now (&do_disconnect, NULL); } } /** * Function called by the transport for each received message. * * @param cls closure * @param peer (claimed) identity of the other peer * @param message the message * @param ats performance data * @param ats_count number of entries in ats */ static void notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { if (!benchmark_receive) return; if (verbosity > 0) FPRINTF (stdout, _("Received %u bytes from %s\n"), (unsigned int) ntohs (message->size), GNUNET_i2s (peer)); if (traffic_received == 0) start_time = GNUNET_TIME_absolute_get (); traffic_received += ntohs (message->size); } struct ResolutionContext { struct GNUNET_HELLO_Address *addrcp; int printed; }; static void process_string (void *cls, const char *address) { struct ResolutionContext *rc = cls; struct GNUNET_HELLO_Address *addrcp = rc->addrcp; if (address != NULL) { FPRINTF (stdout, _("Peer `%s': %s %s\n"), GNUNET_i2s (&addrcp->peer), addrcp->transport_name, address); rc->printed = GNUNET_YES; } else { /* done */ if (GNUNET_NO == rc->printed) FPRINTF (stdout, _("Peer `%s': %s \n"), GNUNET_i2s (&addrcp->peer), addrcp->transport_name); GNUNET_free (rc->addrcp); GNUNET_free (rc); } } /** * Function to call with a binary address * * @param cls closure * @param peer identity of the peer * @param address binary address (NULL on disconnect) */ static void process_address (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Address *address) { const struct GNUNET_CONFIGURATION_Handle *cfg = cls; struct ResolutionContext *rc; if (peer == NULL) { /* done */ return; } if (address == NULL) { FPRINTF (stdout, _("Peer `%s' disconnected\n"), GNUNET_i2s (peer)); return; } rc = GNUNET_malloc(sizeof (struct ResolutionContext)); rc->addrcp = GNUNET_HELLO_address_copy(address); rc->printed = GNUNET_NO; GNUNET_assert (NULL != rc); /* Resolve address to string */ GNUNET_TRANSPORT_address_to_string (cfg, address, numeric, RESOLUTION_TIMEOUT, &process_string, rc); } /** * Task run in monitor mode when the user presses CTRL-C to abort. * Stops monitoring activity. * * @param cls the 'struct GNUNET_TRANSPORT_PeerIterateContext *' * @param tc scheduler context */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TRANSPORT_PeerIterateContext *pic = cls; GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pic); if (NULL != peers) { GNUNET_CONTAINER_multihashmap_destroy (peers); peers = NULL; } } /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param cfg configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { if (test_configuration) { do_test_configuration (cfg); } if (benchmark_send && (NULL == cpid)) { FPRINTF (stderr, _("Option `%s' makes no sense without option `%s'.\n"), "-s", "-C"); return; } if (NULL != cpid) { ret = 1; if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (cpid, &pid.hashPubKey)) { FPRINTF (stderr, _("Failed to parse peer identity `%s'\n"), cpid); return; } handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, ¬ify_receive, ¬ify_connect, ¬ify_disconnect); GNUNET_TRANSPORT_try_connect (handle, &pid); end = GNUNET_SCHEDULER_add_delayed (benchmark_send ? GNUNET_TIME_UNIT_FOREVER_REL : GNUNET_TIME_UNIT_SECONDS, &do_disconnect, NULL); } else if (benchmark_receive) { handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, ¬ify_receive, ¬ify_connect, ¬ify_disconnect); GNUNET_TRANSPORT_try_connect (handle, &pid); end = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &do_disconnect, NULL); } if (iterate_connections) { peers = GNUNET_CONTAINER_multihashmap_create (20); GNUNET_TRANSPORT_peer_get_active_addresses (cfg, NULL, GNUNET_YES, TIMEOUT, &process_address, (void *) cfg); } if (monitor_connections) { struct GNUNET_TRANSPORT_PeerIterateContext *pic; pic = GNUNET_TRANSPORT_peer_get_active_addresses (cfg, NULL, GNUNET_NO, GNUNET_TIME_UNIT_FOREVER_REL, &process_address, (void *) cfg); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, pic); } } int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { {'b', "benchmark", NULL, gettext_noop ("measure how fast we are receiving data (until CTRL-C)"), 0, &GNUNET_GETOPT_set_one, &benchmark_receive}, {'C', "connect", "PEER", gettext_noop ("try to connect to the given peer"), 1, &GNUNET_GETOPT_set_string, &cpid}, {'i', "information", NULL, gettext_noop ("provide information about all current connections (once)"), 0, &GNUNET_GETOPT_set_one, &iterate_connections}, {'m', "monitor", NULL, gettext_noop ("provide information about all current connections (continuously)"), 0, &GNUNET_GETOPT_set_one, &monitor_connections}, {'n', "numeric", NULL, gettext_noop ("do not resolve hostnames"), 0, &GNUNET_GETOPT_set_one, &numeric}, {'s', "send", NULL, gettext_noop ("send data for benchmarking to the other peer (until CTRL-C)"), 0, &GNUNET_GETOPT_set_one, &benchmark_send}, {'t', "test", NULL, gettext_noop ("test transport configuration (involves external server)"), 0, &GNUNET_GETOPT_set_one, &test_configuration}, GNUNET_GETOPT_OPTION_VERBOSE (&verbosity), GNUNET_GETOPT_OPTION_END }; return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-transport", gettext_noop ("Direct access to transport service."), options, &run, NULL)) ? ret : 1; } /* end of gnunet-transport.c */ gnunet-0.9.3/src/transport/test_transport_api_timeout_http_peer2.conf0000644000175000017500000000116711661530125023271 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-http-p2/ DEFAULTCONFIG = test_transport_api_http_peer2.conf [nat] [transport-http] PORT = 12090 [arm] PORT = 12095 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12094 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12093 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12092 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] #DEBUG = YES PORT = 12091 PLUGINS = http UNIXPATH = /tmp/gnunet-p2-service-transport.sock #PREFIX = valgrind --leak-check=full gnunet-0.9.3/src/transport/transport_api_address_to_string.c0000644000175000017500000001346211760502551021425 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "platform.h" #include "gnunet_client_lib.h" #include "gnunet_arm_service.h" #include "gnunet_hello_lib.h" #include "gnunet_protocols.h" #include "gnunet_server_lib.h" #include "gnunet_time_lib.h" #include "gnunet_transport_service.h" #include "transport.h" /** * Context for the address lookup. */ struct GNUNET_TRANSPORT_AddressToStringContext { /** * Function to call with the human-readable address. */ GNUNET_TRANSPORT_AddressToStringCallback cb; /** * Closure for cb. */ void *cb_cls; /** * Connection to the service. */ struct GNUNET_CLIENT_Connection *client; /** * When should this operation time out? */ struct GNUNET_TIME_Absolute timeout; }; /** * Function called with responses from the service. * * @param cls our 'struct GNUNET_TRANSPORT_AddressLookupContext*' * @param msg NULL on timeout or error, otherwise presumably a * message with the human-readable address */ static void address_response_processor (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_TRANSPORT_AddressToStringContext *alucb = cls; const char *address; uint16_t size; if (msg == NULL) { alucb->cb (alucb->cb_cls, NULL); GNUNET_CLIENT_disconnect (alucb->client); GNUNET_free (alucb); return; } GNUNET_break (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY); size = ntohs (msg->size); if (size == sizeof (struct GNUNET_MessageHeader)) { /* done! */ alucb->cb (alucb->cb_cls, NULL); GNUNET_CLIENT_disconnect (alucb->client); GNUNET_free (alucb); return; } address = (const char *) &msg[1]; if (address[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0') { /* invalid reply */ GNUNET_break (0); alucb->cb (alucb->cb_cls, NULL); GNUNET_CLIENT_disconnect (alucb->client); GNUNET_free (alucb); return; } /* expect more replies */ GNUNET_CLIENT_receive (alucb->client, &address_response_processor, alucb, GNUNET_TIME_absolute_get_remaining (alucb->timeout)); alucb->cb (alucb->cb_cls, address); } /** * Convert a binary address into a human readable address. * * @param cfg configuration to use * @param address address to convert (binary format) * @param numeric should (IP) addresses be displayed in numeric form * (otherwise do reverse DNS lookup) * @param timeout how long is the lookup allowed to take at most * @param aluc function to call with the results * @param aluc_cls closure for aluc * @return handle to cancel the operation, NULL on error */ struct GNUNET_TRANSPORT_AddressToStringContext * GNUNET_TRANSPORT_address_to_string (const struct GNUNET_CONFIGURATION_Handle *cfg, const struct GNUNET_HELLO_Address *address, int numeric, struct GNUNET_TIME_Relative timeout, GNUNET_TRANSPORT_AddressToStringCallback aluc, void *aluc_cls) { size_t len; size_t alen; size_t slen; struct AddressLookupMessage *msg; struct GNUNET_TRANSPORT_AddressToStringContext *alc; struct GNUNET_CLIENT_Connection *client; char *addrbuf; GNUNET_assert (address != NULL); alen = address->address_length; slen = strlen (address->transport_name) + 1; len = sizeof (struct AddressLookupMessage) + alen + slen; if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); return NULL; } client = GNUNET_CLIENT_connect ("transport", cfg); if (NULL == client) return NULL; msg = GNUNET_malloc (len); msg->header.size = htons (len); msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING); msg->numeric_only = htons ((int16_t) numeric); msg->addrlen = htons ((uint16_t) alen); msg->timeout = GNUNET_TIME_relative_hton (timeout); addrbuf = (char *) &msg[1]; memcpy (addrbuf, address->address, alen); memcpy (&addrbuf[alen], address->transport_name, slen); alc = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_AddressToStringContext)); alc->cb = aluc; alc->cb_cls = aluc_cls; alc->timeout = GNUNET_TIME_relative_to_absolute (timeout); alc->client = client; GNUNET_assert (GNUNET_OK == GNUNET_CLIENT_transmit_and_get_response (client, &msg->header, timeout, GNUNET_YES, &address_response_processor, alc)); GNUNET_free (msg); return alc; } /** * Cancel request for address conversion. * * @param alc handle for the request to cancel */ void GNUNET_TRANSPORT_address_to_string_cancel (struct GNUNET_TRANSPORT_AddressToStringContext *alc) { GNUNET_CLIENT_disconnect (alc->client); GNUNET_free (alc); } /* end of transport_api_address_to_string.c */ gnunet-0.9.3/src/transport/test_transport_api_timeout_unix_peer1.conf0000644000175000017500000000104311721510741023264 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-unix-p1/ DEFAULTCONFIG = test_transport_api_unix_peer1.conf [arm] PORT = 12125 UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12124 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12123 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12122 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12121 PLUGINS = unix UNIXPATH = /tmp/gnunet-p1-service-transport.sock [transport-unix] PORT = 12120 gnunet-0.9.3/src/transport/gnunet-service-transport_validation.c0000644000175000017500000011516311762202311022137 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/gnunet-service-transport_validation.c * @brief address validation subsystem * @author Christian Grothoff */ #include "platform.h" #include "gnunet-service-transport_validation.h" #include "gnunet-service-transport_plugins.h" #include "gnunet-service-transport_hello.h" #include "gnunet-service-transport_blacklist.h" #include "gnunet-service-transport.h" #include "gnunet_hello_lib.h" #include "gnunet_ats_service.h" #include "gnunet_peerinfo_service.h" #include "gnunet_signatures.h" /** * How long is a PONG signature valid? We'll recycle a signature until * 1/4 of this time is remaining. PONGs should expire so that if our * external addresses change an adversary cannot replay them indefinitely. * OTOH, we don't want to spend too much time generating PONG signatures, * so they must have some lifetime to reduce our CPU usage. */ #define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1) /** * After how long do we expire an address in a HELLO that we just * validated? This value is also used for our own addresses when we * create a HELLO. */ #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12) /** * How often do we allow PINGing an address that we have not yet * validated? This also determines how long we track an address that * we cannot validate (because after this time we can destroy the * validation record). */ #define UNVALIDATED_PING_KEEPALIVE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) /** * How often do we PING an address that we have successfully validated * in the past but are not actively using? Should be (significantly) * smaller than HELLO_ADDRESS_EXPIRATION. */ #define VALIDATED_PING_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) /** * How often do we PING an address that we are currently using? */ #define CONNECTED_PING_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2) /** * How much delay is acceptable for sending the PING or PONG? */ #define ACCEPTABLE_PING_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) /** * Size of the validation map hashmap. */ #define VALIDATION_MAP_SIZE 256 /** * Priority to use for PINGs */ #define PING_PRIORITY 2 /** * Priority to use for PONGs */ #define PONG_PRIORITY 4 GNUNET_NETWORK_STRUCT_BEGIN /** * Message used to ask a peer to validate receipt (to check an address * from a HELLO). Followed by the address we are trying to validate, * or an empty address if we are just sending a PING to confirm that a * connection which the receiver (of the PING) initiated is still valid. */ struct TransportPingMessage { /** * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING */ struct GNUNET_MessageHeader header; /** * Challenge code (to ensure fresh reply). */ uint32_t challenge GNUNET_PACKED; /** * Who is the intended recipient? */ struct GNUNET_PeerIdentity target; }; /** * Message used to validate a HELLO. The challenge is included in the * confirmation to make matching of replies to requests possible. The * signature signs our public key, an expiration time and our address.

    * * This message is followed by our transport address that the PING tried * to confirm (if we liked it). The address can be empty (zero bytes) * if the PING had not address either (and we received the request via * a connection that we initiated). */ struct TransportPongMessage { /** * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG */ struct GNUNET_MessageHeader header; /** * Challenge code from PING (showing freshness). Not part of what * is signed so that we can re-use signatures. */ uint32_t challenge GNUNET_PACKED; /** * Signature. */ struct GNUNET_CRYPTO_RsaSignature signature; /** * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a * plausible address for the signing peer. */ struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; /** * When does this signature expire? */ struct GNUNET_TIME_AbsoluteNBO expiration; /** * Size of address appended to this message (part of what is * being signed, hence not redundant). */ uint32_t addrlen GNUNET_PACKED; }; GNUNET_NETWORK_STRUCT_END /** * Information about an address under validation */ struct ValidationEntry { /** * The address. */ struct GNUNET_HELLO_Address *address; /** * Handle to the blacklist check (if we're currently in it). */ struct GST_BlacklistCheck *bc; /** * Public key of the peer. */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; /** * The identity of the peer. FIXME: duplicated (also in 'address') */ struct GNUNET_PeerIdentity pid; /** * ID of task that will clean up this entry if nothing happens. */ GNUNET_SCHEDULER_TaskIdentifier timeout_task; /** * ID of task that will trigger address revalidation. */ GNUNET_SCHEDULER_TaskIdentifier revalidation_task; /** * At what time did we send the latest validation request (PING)? */ struct GNUNET_TIME_Absolute send_time; /** * Until when is this address valid? * ZERO if it is not currently considered valid. */ struct GNUNET_TIME_Absolute valid_until; /** * How long until we can try to validate this address again? * FOREVER if the address is for an unsupported plugin (from PEERINFO) * ZERO if the address is considered valid (no validation needed) * otherwise a time in the future if we're currently denying re-validation */ struct GNUNET_TIME_Absolute revalidation_block; /** * Last observed latency for this address (round-trip), delay between * last PING sent and PONG received; FOREVER if we never got a PONG. */ struct GNUNET_TIME_Relative latency; /** * Challenge number we used. */ uint32_t challenge; /** * When passing the address in 'add_valid_peer_address', did we * copy the address to the HELLO yet? */ int copied; /** * Are we currently using this address for a connection? */ int in_use; /** * Are we expecting a PONG message for this validation entry? */ int expecting_pong; /* FIXME: DEBUGGING */ int last_line_set_to_no; int last_line_set_to_yes; }; /** * Context of currently active requests to peerinfo * for validation of HELLOs. */ struct CheckHelloValidatedContext { /** * This is a doubly-linked list. */ struct CheckHelloValidatedContext *next; /** * This is a doubly-linked list. */ struct CheckHelloValidatedContext *prev; /** * Hello that we are validating. */ const struct GNUNET_HELLO_Message *hello; }; /** * Head of linked list of HELLOs awaiting validation. */ static struct CheckHelloValidatedContext *chvc_head; /** * Tail of linked list of HELLOs awaiting validation */ static struct CheckHelloValidatedContext *chvc_tail; /** * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses * of the given peer that we are currently validating, have validated * or are blocked from re-validation for a while). */ static struct GNUNET_CONTAINER_MultiHashMap *validation_map; /** * Context for peerinfo iteration. */ static struct GNUNET_PEERINFO_NotifyContext *pnc; /** * Context for the validation entry match function. */ struct ValidationEntryMatchContext { /** * Where to store the result? */ struct ValidationEntry *ve; /** * Address we're interested in. */ const struct GNUNET_HELLO_Address *address; }; /** * Iterate over validation entries until a matching one is found. * * @param cls the 'struct ValidationEntryMatchContext' * @param key peer identity (unused) * @param value a 'struct ValidationEntry' to match * @return GNUNET_YES if the entry does not match, * GNUNET_NO if the entry does match */ static int validation_entry_match (void *cls, const GNUNET_HashCode * key, void *value) { struct ValidationEntryMatchContext *vemc = cls; struct ValidationEntry *ve = value; if (0 == GNUNET_HELLO_address_cmp (ve->address, vemc->address)) { vemc->ve = ve; return GNUNET_NO; } return GNUNET_YES; } /** * Iterate over validation entries and free them. * * @param cls (unused) * @param key peer identity (unused) * @param value a 'struct ValidationEntry' to clean up * @return GNUNET_YES (continue to iterate) */ static int cleanup_validation_entry (void *cls, const GNUNET_HashCode * key, void *value) { struct ValidationEntry *ve = value; if (NULL != ve->bc) { GST_blacklist_test_cancel (ve->bc); ve->bc = NULL; } GNUNET_break (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (validation_map, &ve->pid.hashPubKey, ve)); GNUNET_HELLO_address_free (ve->address); if (GNUNET_SCHEDULER_NO_TASK != ve->timeout_task) { GNUNET_SCHEDULER_cancel (ve->timeout_task); ve->timeout_task = GNUNET_SCHEDULER_NO_TASK; } if (GNUNET_SCHEDULER_NO_TASK != ve->revalidation_task) { GNUNET_SCHEDULER_cancel (ve->revalidation_task); ve->revalidation_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_free (ve); return GNUNET_OK; } /** * Address validation cleanup task. Assesses if the record is no * longer valid and then possibly triggers its removal. * * @param cls the 'struct ValidationEntry' * @param tc scheduler context (unused) */ static void timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ValidationEntry *ve = cls; struct GNUNET_TIME_Absolute max; struct GNUNET_TIME_Relative left; ve->timeout_task = GNUNET_SCHEDULER_NO_TASK; max = GNUNET_TIME_absolute_max (ve->valid_until, ve->revalidation_block); left = GNUNET_TIME_absolute_get_remaining (max); if (left.rel_value > 0) { /* should wait a bit longer */ ve->timeout_task = GNUNET_SCHEDULER_add_delayed (left, &timeout_hello_validation, ve); return; } GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# address records discarded"), 1, GNUNET_NO); cleanup_validation_entry (NULL, &ve->pid.hashPubKey, ve); } /** * Function called with the result from blacklisting. * Send a PING to the other peer if a communication is allowed. * * @param cls our 'struct ValidationEntry' * @param pid identity of the other peer * @param result GNUNET_OK if the connection is allowed, GNUNET_NO if not */ static void transmit_ping_if_allowed (void *cls, const struct GNUNET_PeerIdentity *pid, int result) { struct ValidationEntry *ve = cls; struct TransportPingMessage ping; struct GNUNET_TRANSPORT_PluginFunctions *papi; const struct GNUNET_MessageHeader *hello; ssize_t ret; size_t tsize; size_t slen; uint16_t hsize; ve->bc = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting plain PING to `%s' %s\n", GNUNET_i2s (pid), GST_plugins_a2s (ve->address)); slen = strlen (ve->address->transport_name) + 1; hello = GST_hello_get (); hsize = ntohs (hello->size); tsize = sizeof (struct TransportPingMessage) + ve->address->address_length + slen + hsize; ping.header.size = htons (sizeof (struct TransportPingMessage) + ve->address->address_length + slen); ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING); ping.challenge = htonl (ve->challenge); ping.target = *pid; if (tsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Not transmitting `%s' with `%s', message too big (%u bytes!). This should not happen.\n"), "HELLO", "PING", (unsigned int) tsize); /* message too big (!?), get rid of HELLO */ hsize = 0; tsize = sizeof (struct TransportPingMessage) + ve->address->address_length + slen + hsize; } { char message_buf[tsize]; /* build message with structure: * [HELLO][TransportPingMessage][Transport name][Address] */ memcpy (message_buf, hello, hsize); memcpy (&message_buf[hsize], &ping, sizeof (struct TransportPingMessage)); memcpy (&message_buf[sizeof (struct TransportPingMessage) + hsize], ve->address->transport_name, slen); memcpy (&message_buf[sizeof (struct TransportPingMessage) + slen + hsize], ve->address, ve->address->address_length); papi = GST_plugins_find (ve->address->transport_name); if (papi == NULL) ret = -1; else { GNUNET_assert (papi->send != NULL); GNUNET_assert (papi->get_session != NULL); struct Session * session = papi->get_session(papi->cls, ve->address); if (session != NULL) { ret = papi->send (papi->cls, session, message_buf, tsize, PING_PRIORITY, ACCEPTABLE_PING_DELAY, NULL, NULL); } else { /* Could not get a valid session */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not get a valid session for `%s' %s\n", GNUNET_i2s (pid), GST_plugins_a2s (ve->address)); ret = -1; } } } if (-1 != ret) { ve->send_time = GNUNET_TIME_absolute_get (); GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# PING without HELLO messages sent"), 1, GNUNET_NO); ve->expecting_pong = GNUNET_YES; } } /** * Do address validation again to keep address valid. * * @param cls the 'struct ValidationEntry' * @param tc scheduler context (unused) */ static void revalidate_address (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ValidationEntry *ve = cls; struct GNUNET_TIME_Relative canonical_delay; struct GNUNET_TIME_Relative delay; struct GST_BlacklistCheck *bc; uint32_t rdelay; ve->revalidation_task = GNUNET_SCHEDULER_NO_TASK; delay = GNUNET_TIME_absolute_get_remaining (ve->revalidation_block); /* How long until we can possibly permit the next PING? */ canonical_delay = (ve->in_use == GNUNET_YES) ? CONNECTED_PING_FREQUENCY : ((GNUNET_TIME_absolute_get_remaining (ve->valid_until).rel_value > 0) ? VALIDATED_PING_FREQUENCY : UNVALIDATED_PING_KEEPALIVE); if (delay.rel_value > canonical_delay.rel_value * 2) { /* situation changed, recalculate delay */ delay = canonical_delay; ve->revalidation_block = GNUNET_TIME_relative_to_absolute (delay); } if (delay.rel_value > 0) { /* should wait a bit longer */ ve->revalidation_task = GNUNET_SCHEDULER_add_delayed (delay, &revalidate_address, ve); return; } ve->revalidation_block = GNUNET_TIME_relative_to_absolute (canonical_delay); /* schedule next PINGing with some extra random delay to avoid synchronous re-validations */ rdelay = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, canonical_delay.rel_value); delay = GNUNET_TIME_relative_add (canonical_delay, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, rdelay)); ve->revalidation_task = GNUNET_SCHEDULER_add_delayed (delay, &revalidate_address, ve); /* start PINGing by checking blacklist */ GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# address revalidations started"), 1, GNUNET_NO); bc = GST_blacklist_test_allowed (&ve->pid, ve->address->transport_name, &transmit_ping_if_allowed, ve); if (NULL != bc) ve->bc = bc; /* only set 'bc' if 'transmit_ping_if_allowed' was not already * called... */ } /** * Find a ValidationEntry entry for the given neighbour that matches * the given address and transport. If none exists, create one (but * without starting any validation). * * @param public_key public key of the peer, NULL for unknown * @param address address to find * @return validation entry matching the given specifications, NULL * if we don't have an existing entry and no public key was given */ static struct ValidationEntry * find_validation_entry (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, const struct GNUNET_HELLO_Address *address) { struct ValidationEntryMatchContext vemc; struct ValidationEntry *ve; vemc.ve = NULL; vemc.address = address; GNUNET_CONTAINER_multihashmap_get_multiple (validation_map, &address->peer.hashPubKey, &validation_entry_match, &vemc); if (NULL != (ve = vemc.ve)) return ve; if (public_key == NULL) return NULL; ve = GNUNET_malloc (sizeof (struct ValidationEntry)); ve->in_use = GNUNET_SYSERR; /* not defined */ ve->last_line_set_to_no = 0; ve->last_line_set_to_yes = 0; ve->address = GNUNET_HELLO_address_copy (address); ve->public_key = *public_key; ve->pid = address->peer; ve->latency = GNUNET_TIME_UNIT_FOREVER_REL; ve->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); ve->timeout_task = GNUNET_SCHEDULER_add_delayed (UNVALIDATED_PING_KEEPALIVE, &timeout_hello_validation, ve); GNUNET_CONTAINER_multihashmap_put (validation_map, &address->peer.hashPubKey, ve, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); ve->expecting_pong = GNUNET_NO; return ve; } /** * Iterator which adds the given address to the set of validated * addresses. * * @param cls original HELLO message * @param address the address * @param expiration expiration time * @return GNUNET_OK (keep the address) */ static int add_valid_address (void *cls, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration) { const struct GNUNET_HELLO_Message *hello = cls; struct ValidationEntry *ve; struct GNUNET_PeerIdentity pid; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value == 0) return GNUNET_OK; /* expired */ if ((GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid)) || (GNUNET_OK != GNUNET_HELLO_get_key (hello, &public_key))) { GNUNET_break (0); return GNUNET_OK; /* invalid HELLO !? */ } if (0 == memcmp (&GST_my_identity, &pid, sizeof (struct GNUNET_PeerIdentity))) { /* Peerinfo returned own identity, skip validation */ return GNUNET_OK; } ve = find_validation_entry (&public_key, address); ve->valid_until = GNUNET_TIME_absolute_max (ve->valid_until, expiration); if (GNUNET_SCHEDULER_NO_TASK == ve->revalidation_task) ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address, ve); GNUNET_ATS_address_update (GST_ats, address, NULL, NULL, 0); return GNUNET_OK; } /** * Function called for any HELLO known to PEERINFO. * * @param cls unused * @param peer id of the peer, NULL for last call * @param hello hello message for the peer (can be NULL) * @param err_msg error message */ static void process_peerinfo_hello (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Message *hello, const char *err_msg) { GNUNET_assert (NULL != peer); if (NULL == hello) return; GNUNET_assert (NULL == GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &add_valid_address, (void *) hello)); } /** * Start the validation subsystem. */ void GST_validation_start () { validation_map = GNUNET_CONTAINER_multihashmap_create (VALIDATION_MAP_SIZE); pnc = GNUNET_PEERINFO_notify (GST_cfg, &process_peerinfo_hello, NULL); } /** * Stop the validation subsystem. */ void GST_validation_stop () { struct CheckHelloValidatedContext *chvc; GNUNET_CONTAINER_multihashmap_iterate (validation_map, &cleanup_validation_entry, NULL); GNUNET_CONTAINER_multihashmap_destroy (validation_map); validation_map = NULL; while (NULL != (chvc = chvc_head)) { GNUNET_CONTAINER_DLL_remove (chvc_head, chvc_tail, chvc); GNUNET_free (chvc); } GNUNET_PEERINFO_notify_cancel (pnc); } /** * Send the given PONG to the given address. * * @param cls the PONG message * @param public_key public key for the peer, never NULL * @param valid_until is ZERO if we never validated the address, * otherwise a time up to when we consider it (or was) valid * @param validation_block is FOREVER if the address is for an unsupported plugin (from PEERINFO) * is ZERO if the address is considered valid (no validation needed) * otherwise a time in the future if we're currently denying re-validation * @param address target address */ static void multicast_pong (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, struct GNUNET_TIME_Absolute valid_until, struct GNUNET_TIME_Absolute validation_block, const struct GNUNET_HELLO_Address *address) { struct TransportPongMessage *pong = cls; struct GNUNET_TRANSPORT_PluginFunctions *papi; papi = GST_plugins_find (address->transport_name); if (papi == NULL) return; GNUNET_assert (papi->send != NULL); GNUNET_assert (papi->get_session != NULL); struct Session * session = papi->get_session(papi->cls, address); if (session == NULL) { GNUNET_break (0); return; } papi->send (papi->cls, session, (const char *) pong, ntohs (pong->header.size), PONG_PRIORITY, ACCEPTABLE_PING_DELAY, NULL, NULL); } /** * We've received a PING. If appropriate, generate a PONG. * * @param sender peer sending the PING * @param hdr the PING * @param sender_address the sender address as we got it * @param session session we got the PING from */ void GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *hdr, const struct GNUNET_HELLO_Address *sender_address, struct Session *session) { const struct TransportPingMessage *ping; struct TransportPongMessage *pong; struct GNUNET_TRANSPORT_PluginFunctions *papi; struct GNUNET_CRYPTO_RsaSignature *sig_cache; struct GNUNET_TIME_Absolute *sig_cache_exp; const char *addr; const char *addrend; size_t alen; size_t slen; ssize_t ret; struct GNUNET_HELLO_Address address; if (ntohs (hdr->size) < sizeof (struct TransportPingMessage)) { GNUNET_break_op (0); return; } ping = (const struct TransportPingMessage *) hdr; if (0 != memcmp (&ping->target, &GST_my_identity, sizeof (struct GNUNET_PeerIdentity))) { GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# PING message for different peer received"), 1, GNUNET_NO); return; } GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# PING messages received"), 1, GNUNET_NO); addr = (const char *) &ping[1]; alen = ntohs (hdr->size) - sizeof (struct TransportPingMessage); /* peer wants to confirm that this is one of our addresses, this is what is * used for address validation */ sig_cache = NULL; sig_cache_exp = NULL; if (0 < alen) { addrend = memchr (addr, '\0', alen); if (NULL == addrend) { GNUNET_break_op (0); return; } addrend++; slen = strlen (addr) + 1; alen -= slen; address.address = addrend; address.address_length = alen; address.transport_name = addr; address.peer = *sender; if (GNUNET_YES != GST_hello_test_address (&address, &sig_cache, &sig_cache_exp)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Not confirming PING with address `%s' since I cannot confirm having this address.\n"), GST_plugins_a2s (&address)); return; } } else { addrend = NULL; /* make gcc happy */ slen = 0; static struct GNUNET_CRYPTO_RsaSignature no_address_signature; static struct GNUNET_TIME_Absolute no_address_signature_expiration; sig_cache = &no_address_signature; sig_cache_exp = &no_address_signature_expiration; } pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen); pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen); pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG); pong->purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + sizeof (uint32_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + alen + slen); pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN); pong->challenge = ping->challenge; pong->addrlen = htonl (alen + slen); memcpy (&pong[1], addr, slen); memcpy (&((char *) &pong[1])[slen], addrend, alen); if (GNUNET_TIME_absolute_get_remaining (*sig_cache_exp).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) { /* create / update cached sig */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating PONG signature to indicate ownership.\n"); *sig_cache_exp = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME); pong->expiration = GNUNET_TIME_absolute_hton (*sig_cache_exp); GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_rsa_sign (GST_my_private_key, &pong->purpose, sig_cache)); } else { pong->expiration = GNUNET_TIME_absolute_hton (*sig_cache_exp); } pong->signature = *sig_cache; GNUNET_assert (sender_address != NULL); /* first see if the session we got this PING from can be used to transmit * a response reliably */ papi = GST_plugins_find (sender_address->transport_name); if (papi == NULL) ret = -1; else { GNUNET_assert (papi->send != NULL); GNUNET_assert (papi->get_session != NULL); if (session == NULL) { session = papi->get_session (papi->cls, sender_address); } if (session == NULL) { GNUNET_break (0); ret = -1; } else { ret = papi->send (papi->cls, session, (const char *) pong, ntohs (pong->header.size), PONG_PRIORITY, ACCEPTABLE_PING_DELAY, NULL, NULL); } } if (ret != -1) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitted PONG to `%s' via reliable mechanism\n", GNUNET_i2s (sender)); /* done! */ GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# PONGs unicast via reliable transport"), 1, GNUNET_NO); GNUNET_free (pong); return; } /* no reliable method found, try transmission via all known addresses */ GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# PONGs multicast to all available addresses"), 1, GNUNET_NO); GST_validation_get_addresses (sender, &multicast_pong, pong); GNUNET_free (pong); } /** * Context for the 'validate_address' function */ struct ValidateAddressContext { /** * Hash of the public key of the peer whose address is being validated. */ struct GNUNET_PeerIdentity pid; /** * Public key of the peer whose address is being validated. */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; }; /** * Iterator callback to go over all addresses and try to validate them * (unless blocked or already validated). * * @param cls pointer to a 'struct ValidateAddressContext' * @param address the address * @param expiration expiration time * @return GNUNET_OK (keep the address) */ static int validate_address_iterator (void *cls, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration) { const struct ValidateAddressContext *vac = cls; struct ValidationEntry *ve; if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value == 0) return GNUNET_OK; /* expired */ ve = find_validation_entry (&vac->public_key, address); if (GNUNET_SCHEDULER_NO_TASK == ve->revalidation_task) ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address, ve); return GNUNET_OK; } /** * Add the validated peer address to the HELLO. * * @param cls the 'struct ValidationEntry' with the validated address * @param max space in buf * @param buf where to add the address * @return number of bytes written, 0 to signal the * end of the iteration. */ static size_t add_valid_peer_address (void *cls, size_t max, void *buf) { struct ValidationEntry *ve = cls; if (GNUNET_YES == ve->copied) return 0; /* terminate */ ve->copied = GNUNET_YES; return GNUNET_HELLO_add_address (ve->address, ve->valid_until, buf, max); } /** * We've received a PONG. Check if it matches a pending PING and * mark the respective address as confirmed. * * @param sender peer sending the PONG * @param hdr the PONG */ void GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *hdr) { const struct TransportPongMessage *pong; struct ValidationEntry *ve; const char *tname; const char *addr; size_t addrlen; size_t slen; size_t size; struct GNUNET_HELLO_Message *hello; struct GNUNET_HELLO_Address address; if (ntohs (hdr->size) < sizeof (struct TransportPongMessage)) { GNUNET_break_op (0); return; } GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# PONG messages received"), 1, GNUNET_NO); pong = (const struct TransportPongMessage *) hdr; tname = (const char *) &pong[1]; size = ntohs (hdr->size) - sizeof (struct TransportPongMessage); addr = memchr (tname, '\0', size); if (NULL == addr) { GNUNET_break_op (0); return; } addr++; slen = strlen (tname) + 1; addrlen = size - slen; address.peer = *sender; address.address = addr; address.address_length = addrlen; address.transport_name = tname; ve = find_validation_entry (NULL, &address); if ((NULL == ve) || (ve->expecting_pong == GNUNET_NO)) { GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# PONGs dropped, no matching pending validation"), 1, GNUNET_NO); return; } /* now check that PONG is well-formed */ if (0 != memcmp (&ve->pid, sender, sizeof (struct GNUNET_PeerIdentity))) { GNUNET_break_op (0); return; } if (GNUNET_OK != GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN, &pong->purpose, &pong->signature, &ve->public_key)) { GNUNET_break_op (0); return; } if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0) { GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# PONGs dropped, signature expired"), 1, GNUNET_NO); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Address validated for peer `%s' with plugin `%s': `%s'\n", GNUNET_i2s (sender), tname, GST_plugins_a2s (ve->address)); /* validity achieved, remember it! */ ve->expecting_pong = GNUNET_NO; ve->valid_until = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION); ve->latency = GNUNET_TIME_absolute_get_duration (ve->send_time); { struct GNUNET_ATS_Information ats; ats.type = htonl (GNUNET_ATS_QUALITY_NET_DELAY); ats.value = htonl ((uint32_t) ve->latency.rel_value); GNUNET_ATS_address_update (GST_ats, ve->address, NULL, &ats, 1); } /* build HELLO to store in PEERINFO */ ve->copied = GNUNET_NO; hello = GNUNET_HELLO_create (&ve->public_key, &add_valid_peer_address, ve); GNUNET_PEERINFO_add_peer (GST_peerinfo, hello, NULL, NULL); GNUNET_free (hello); } /** * We've received a HELLO, check which addresses are new and trigger * validation. * * @param hello the HELLO we received */ void GST_validation_handle_hello (const struct GNUNET_MessageHeader *hello) { const struct GNUNET_HELLO_Message *hm = (const struct GNUNET_HELLO_Message *) hello; struct ValidateAddressContext vac; struct GNUNET_HELLO_Message *h; if ((GNUNET_OK != GNUNET_HELLO_get_id (hm, &vac.pid)) || (GNUNET_OK != GNUNET_HELLO_get_key (hm, &vac.public_key))) { /* malformed HELLO */ GNUNET_break (0); return; } if (0 == memcmp (&GST_my_identity, &vac.pid, sizeof (struct GNUNET_PeerIdentity))) return; /* Add peer identity without addresses to peerinfo service */ h = GNUNET_HELLO_create (&vac.public_key, NULL, NULL); GNUNET_PEERINFO_add_peer (GST_peerinfo, h, NULL, NULL); #if VERBOSE_VALIDATION GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Adding `%s' without addresses for peer `%s'\n"), "HELLO", GNUNET_i2s (&vac.pid)); #endif GNUNET_free (h); GNUNET_assert (NULL == GNUNET_HELLO_iterate_addresses (hm, GNUNET_NO, &validate_address_iterator, &vac)); } /** * Closure for 'iterate_addresses' */ struct IteratorContext { /** * Function to call on each address. */ GST_ValidationAddressCallback cb; /** * Closure for 'cb'. */ void *cb_cls; }; /** * Call the callback in the closure for each validation entry. * * @param cls the 'struct GST_ValidationIteratorContext' * @param key the peer's identity * @param value the 'struct ValidationEntry' * @return GNUNET_OK (continue to iterate) */ static int iterate_addresses (void *cls, const GNUNET_HashCode * key, void *value) { struct IteratorContext *ic = cls; struct ValidationEntry *ve = value; ic->cb (ic->cb_cls, &ve->public_key, ve->valid_until, ve->revalidation_block, ve->address); return GNUNET_OK; } /** * Call the given function for each address for the given target. * Can either give a snapshot (synchronous API) or be continuous. * * @param target peer information is requested for * @param cb function to call; will not be called after this function returns * @param cb_cls closure for 'cb' */ void GST_validation_get_addresses (const struct GNUNET_PeerIdentity *target, GST_ValidationAddressCallback cb, void *cb_cls) { struct IteratorContext ic; ic.cb = cb; ic.cb_cls = cb_cls; GNUNET_CONTAINER_multihashmap_get_multiple (validation_map, &target->hashPubKey, &iterate_addresses, &ic); } /** * Update if we are using an address for a connection actively right now. * Based on this, the validation module will measure latency for the * address more or less often. * * @param address the address * @param session the session * @param in_use GNUNET_YES if we are now using the address for a connection, * GNUNET_NO if we are no longer using the address for a connection * @param line line of caller just for DEBUGGING! */ void GST_validation_set_address_use (const struct GNUNET_HELLO_Address *address, struct Session *session, int in_use, int line) { struct ValidationEntry *ve; if (NULL != address) ve = find_validation_entry (NULL, address); else ve = NULL; /* FIXME: lookup based on session... */ if (NULL == ve) { /* this can happen for inbound connections (sender_address_len == 0); */ return; } if (ve->in_use == in_use) { if (GNUNET_YES == in_use) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error setting address in use for peer `%s' `%s' to USED: set last time by %i, called now by %i\n", GNUNET_i2s (&address->peer), GST_plugins_a2s (address), ve->last_line_set_to_yes, line); } if (GNUNET_NO == in_use) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error setting address in use for peer `%s' `%s' to NOT_USED: set last time by %i, called now by %i\n", GNUNET_i2s (&address->peer), GST_plugins_a2s (address), ve->last_line_set_to_no, line); } } if (GNUNET_YES == in_use) { ve->last_line_set_to_yes = line; } if (GNUNET_NO == in_use) { ve->last_line_set_to_no = line; } GNUNET_break (ve->in_use != in_use); /* should be different... */ ve->in_use = in_use; if (in_use == GNUNET_YES) { /* from now on, higher frequeny, so reschedule now */ GNUNET_SCHEDULER_cancel (ve->revalidation_task); ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address, ve); } } /** * Query validation about the latest observed latency on a given * address. * * @param sender peer * @param address the address * @param session session * @return observed latency of the address, FOREVER if the address was * never successfully validated */ struct GNUNET_TIME_Relative GST_validation_get_address_latency (const struct GNUNET_PeerIdentity *sender, const struct GNUNET_HELLO_Address *address, struct Session *session) { struct ValidationEntry *ve; if (NULL == address) { GNUNET_break (0); // FIXME: support having latency only with session... return GNUNET_TIME_UNIT_FOREVER_REL; } ve = find_validation_entry (NULL, address); if (NULL == ve) return GNUNET_TIME_UNIT_FOREVER_REL; return ve->latency; } /* end of file gnunet-service-transport_validation.c */ gnunet-0.9.3/src/transport/test_quota_compliance_https_peer1.conf0000644000175000017500000000127311661530125022341 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test_quota_compliance_peer1/ DEFAULTCONFIG = test_quota_compliance_https_peer1.conf [transport-https] PORT = 4001 KEY_FILE = https_key_quota_p1.key CERT_FILE = https_cert_quota_p1.crt [arm] PORT = 4006 UNIXPATH = /tmp/test_quota_compliance_https_arm_peer1.sock [statistics] PORT = 4005 UNIXPATH = /tmp/test_quota_compliance_https_statistics_peer1.sock [resolver] PORT = 4004 UNIXPATH = /tmp/test_quota_compliance_https_resolver_peer1.sock [peerinfo] PORT = 4003 UNIXPATH = /tmp/test_quota_compliance_https_peerinfo_peer1.sock [transport] PORT = 4002 PLUGINS = https UNIXPATH = /tmp/test_quota_compliance_https_transport_peer1.sock gnunet-0.9.3/src/transport/test_quota_compliance_https_peer2.conf0000644000175000017500000000124411661530125022340 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test_quota_compliance_peer2 DEFAULTCONFIG = test_quota_compliance_https_peer2.conf [transport-https] PORT = 3001 KEY_FILE = https_key_quota_p2.key CERT_FILE = https_cert_qutoa_p2.crt [arm] PORT = 3006 UNIXPATH = /tmp/test_quota_compliance_https_arm_peer2.sock [statistics] PORT = 3005 UNIXPATH = /tmp/test_quota_compliance_https_statistics_peer2.sock [resolver] PORT = 3004 UNIXPATH = /tmp/test_quota_compliance_https_resolver_peer2.sock [peerinfo] PORT = 3003 UNIXPATH = /tmp/test_quota_compliance_https_peerinfo_peer2.sock [transport] PORT = 3002 PLUGINS = https UNIXPATH = /tmp/https_transport_peer2.sock gnunet-0.9.3/src/transport/gnunet-service-transport_hello.h0000644000175000017500000000531211760502551021116 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/gnunet-service-transport_hello.h * @brief hello API * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_TRANSPORT_HELLO_H #define GNUNET_SERVICE_TRANSPORT_HELLO_H #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" #include "gnunet_util_lib.h" #include "gnunet_hello_lib.h" /** * Signature of a function to call whenever our hello changes. * * @param cls closure * @param hello updated HELLO */ typedef void (*GST_HelloCallback) (void *cls, const struct GNUNET_MessageHeader * hello); /** * Initialize the HELLO module. * * @param cb function to call whenever our HELLO changes * @param cb_cls closure for cb */ void GST_hello_start (GST_HelloCallback cb, void *cb_cls); /** * Shutdown the HELLO module. */ void GST_hello_stop (void); /** * Obtain this peers HELLO message. * * @return our HELLO message */ const struct GNUNET_MessageHeader * GST_hello_get (void); /** * Add or remove an address from this peer's HELLO message. * * @param addremove GNUNET_YES to add, GNUNET_NO to remove * @param address address to add or remove */ void GST_hello_modify_addresses (int addremove, const struct GNUNET_HELLO_Address *address); /** * Test if a particular address is one of ours. * * @param address the address to test * @param sig location where to cache PONG signatures for this address [set] * @param sig_expiration how long until the current 'sig' expires? * (ZERO if sig was never created) [set] * @return GNUNET_YES if this is one of our addresses, * GNUNET_NO if not */ int GST_hello_test_address (const struct GNUNET_HELLO_Address *address, struct GNUNET_CRYPTO_RsaSignature **sig, struct GNUNET_TIME_Absolute **sig_expiration); #endif /* end of file gnunet-service-transport_hello.h */ gnunet-0.9.3/src/transport/test_quota_compliance_unix_peer2.conf0000644000175000017500000000121211647100177022160 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test_quota_compliance_peer2 DEFAULTCONFIG = test_quota_compliance_unix_peer2.conf [transport-unix] PORT = 12136 [arm] PORT = 3087 UNIXPATH = /tmp/test_quota_compliance_unix_arm_peer2.sock [statistics] PORT = 3088 UNIXPATH = /tmp/test_quota_compliance_unix_statistics_peer2.sock [resolver] PORT = 3089 UNIXPATH = /tmp/test_quota_compliance_unix_resolver_peer2.sock [peerinfo] PORT = 3090 UNIXPATH = /tmp/test_quota_compliance_unix_peerinfo_peer2.sock [transport] PORT = 3091 PLUGINS = unix UNIXPATH = /tmp/test_quota_compliance_unix_transport_peer2.sock [transport-unix] PORT = 3368 gnunet-0.9.3/src/transport/test_transport_api_unreliability_wlan_peer2.conf0000644000175000017500000000106411665472561024452 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-wlan-p2/ DEFAULTCONFIG = test_transport_api_wlan_peer2.conf [transport-wlan] INTERFACE = mon1 TESTMODE = 2 [arm] PORT = 12174 UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12173 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12172 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12171 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12170 PLUGINS = wlan UNIXPATH = /tmp/gnunet-p2-service-transport.sock gnunet-0.9.3/src/transport/test_transport_api_unreliability_constant.c0000644000175000017500000003301711760502551023532 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/test_transport_api_unreliability_constant.c * @brief test case for transports; ensures messages get * through, regardless of order, constant packet size * * This test case serves as a base for unreliable * transport test cases to check that the transports * achieve reliable message delivery. */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_hello_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_server_lib.h" #include "gnunet_transport_service.h" #include "gauger.h" #include "transport.h" #include "transport-testing.h" #define VERBOSE GNUNET_NO #define VERBOSE_ARM GNUNET_NO #define START_ARM GNUNET_YES /** * Testcase timeout */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 900) /** * How long until we give up on transmitting the message? */ #define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) static char *test_source; static char *test_plugin; static char *test_name; static int ok; static GNUNET_SCHEDULER_TaskIdentifier die_task; struct PeerContext *p1; struct PeerContext *p2; struct GNUNET_TRANSPORT_TransmitHandle *th; struct GNUNET_TRANSPORT_TESTING_handle *tth; char *cfg_file_p1; char *cfg_file_p2; uint32_t max_bps_p1; uint32_t max_bps_p2; static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; /* * Testcase specific declarations */ /** * Note that this value must not significantly exceed * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise * messages may be dropped even for a reliable transport. */ #define TOTAL_MSGS (1024 * 3) #define MTYPE 12345 #define MSG_SIZE 10000 GNUNET_NETWORK_STRUCT_BEGIN struct TestMessage { struct GNUNET_MessageHeader header; uint32_t num; }; GNUNET_NETWORK_STRUCT_END static char *test_name; static int msg_scheduled; static int msg_sent; static int msg_recv_expected; static int msg_recv; static int test_failed; static unsigned long long total_bytes; static struct GNUNET_TIME_Absolute start_time; /* * END Testcase specific declarations */ #if VERBOSE #define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) #else #define OKPP do { ok++; } while (0) #endif int get_bit (const char *map, unsigned int bit); static void end () { unsigned long long delta; char *value_name; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value; FPRINTF (stderr, "\nThroughput was %llu kb/s\n", total_bytes * 1000 / 1024 / delta); GNUNET_asprintf (&value_name, "unreliable_%s", test_plugin); GAUGER ("TRANSPORT", value_name, (int) (total_bytes * 1000 / 1024 / delta), "kb/s"); GNUNET_free (value_name); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; if (cc != NULL) GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); cc = NULL; GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); GNUNET_TRANSPORT_TESTING_done (tth); ok = 0; if (test_failed == GNUNET_NO) ok = GNUNET_SYSERR; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GOT %u of %u messages\n", msg_recv, TOTAL_MSGS); } static void end_badly () { die_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); if (test_failed == GNUNET_NO) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Testcase timeout\n"); else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Reliability failed: Last message sent %u, Next message scheduled %u, Last message received %u, Message expected %u\n", msg_sent, msg_scheduled, msg_recv, msg_recv_expected); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; if (cc != NULL) GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); cc = NULL; if (p1 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); if (p2 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); GNUNET_TRANSPORT_TESTING_done (tth); ok = GNUNET_SYSERR; } static unsigned int get_size (unsigned int iter) { /* unsigned int ret; ret = (iter * iter * iter); return sizeof (struct TestMessage) + (ret % 60000); */ return MSG_SIZE; } static void notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { static int n; unsigned int s; char cbuf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; const struct TestMessage *hdr; hdr = (const struct TestMessage *) message; if (MTYPE != ntohs (message->type)) return; msg_recv_expected = n; msg_recv = ntohl (hdr->num); if (msg_recv_expected != msg_recv) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected message no %u, got %u\n", msg_recv_expected, msg_recv); if (GNUNET_SCHEDULER_NO_TASK != die_task) GNUNET_SCHEDULER_cancel (die_task); test_failed = GNUNET_YES; die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } s = get_size (ntohl (hdr->num)); if (ntohs (message->size) != s) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected message %u of size %u, got %u bytes of message %u\n", ntohl (hdr->num), s, ntohs (message->size), ntohl (hdr->num)); if (GNUNET_SCHEDULER_NO_TASK != die_task) GNUNET_SCHEDULER_cancel (die_task); test_failed = GNUNET_YES; die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } memset (cbuf, ntohl (hdr->num), s - sizeof (struct TestMessage)); if (0 != memcmp (cbuf, &hdr[1], s - sizeof (struct TestMessage))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected message %u with bits %u, but body did not match\n", ntohl (hdr->num), (unsigned char) n); if (GNUNET_SCHEDULER_NO_TASK != die_task) GNUNET_SCHEDULER_cancel (die_task); test_failed = GNUNET_YES; die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } #if VERBOSE if (ntohl (hdr->num) % 5 == 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got message %u of size %u\n", ntohl (hdr->num), ntohs (message->size)); } #endif n++; if (0 == (n % (TOTAL_MSGS / 100))) { FPRINTF (stderr, "%s", "."); if (GNUNET_SCHEDULER_NO_TASK != die_task) GNUNET_SCHEDULER_cancel (die_task); test_failed = GNUNET_YES; die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); } if (n == TOTAL_MSGS) { /* because of starting with 0 */ msg_recv++; FPRINTF (stderr, "%s", "\n"); end (); } } static size_t notify_ready (void *cls, size_t size, void *buf) { static int n; char *cbuf = buf; struct TestMessage hdr; unsigned int s; unsigned int ret; th = NULL; if (buf == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout occurred while waiting for transmit_ready\n"); if (GNUNET_SCHEDULER_NO_TASK != die_task) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); ok = 42; return 0; } ret = 0; s = get_size (n); GNUNET_assert (size >= s); GNUNET_assert (buf != NULL); cbuf = buf; do { hdr.header.size = htons (s); hdr.header.type = htons (MTYPE); hdr.num = htonl (n); msg_sent = n; memcpy (&cbuf[ret], &hdr, sizeof (struct TestMessage)); ret += sizeof (struct TestMessage); memset (&cbuf[ret], n, s - sizeof (struct TestMessage)); ret += s - sizeof (struct TestMessage); #if VERBOSE if (n % 1 == 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message %u of size %u\n", n, s); } #endif n++; s = get_size (n); if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16)) break; /* sometimes pack buffer full, sometimes not */ } while (size - ret >= s); if (n < TOTAL_MSGS) { th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, s, 0, TIMEOUT_TRANSMIT, ¬ify_ready, NULL); msg_scheduled = n; } else { FPRINTF (stderr, "%s", "\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All messages scheduled to be sent!!\n"); if (GNUNET_SCHEDULER_NO_TASK != die_task) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); } if (n % 5000 == 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Returning total message block of size %u\n", ret); } total_bytes += ret; return ret; } static void notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' connected to us (%p)!\n", GNUNET_i2s (peer), cls); } static void notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' disconnected (%p)!\n", GNUNET_i2s (peer), cls); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; } static void sendtask () { start_time = GNUNET_TIME_absolute_get (); th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, get_size (0), 0, TIMEOUT_TRANSMIT, ¬ify_ready, NULL); } static void testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) { char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %s <-> %s\n", p1_c, GNUNET_i2s (&p2->id)); GNUNET_free (p1_c); cc = NULL; GNUNET_SCHEDULER_add_now (&sendtask, NULL); } void start_cb (struct PeerContext *p, void *cls) { static int started; started++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, GNUNET_i2s (&p->id)); if (started != 2) return; cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); if ((p1 == NULL) || (p2 == NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } } static int check () { static char *const argv[] = { "test-transport-api-unreliability-constant", "-c", "test_transport_api_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; #if WRITECONFIG setTransportOptions ("test_transport_api_data.conf"); #endif ok = GNUNET_SYSERR; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name, "nohelp", options, &run, &ok); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); GNUNET_log_setup (test_name, #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source); GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source, &test_plugin); tth = GNUNET_TRANSPORT_TESTING_init (); GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1); GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2); ret = check (); GNUNET_free (cfg_file_p1); GNUNET_free (cfg_file_p2); GNUNET_free (test_source); GNUNET_free (test_plugin); GNUNET_free (test_name); return ret; } /* end of test_transport_api_unreliability_constant.c */ gnunet-0.9.3/src/transport/test_quota_compliance_unix_peer1.conf0000644000175000017500000000115411647100177022164 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test_quota_compliance_peer1/ DEFAULTCONFIG = test_quota_compliance_unix_peer1.conf [transport-unix] PORT = 12120 [arm] PORT = 4087 UNIXPATH = /tmp/test_quota_compliance_unix_arm_peer1.sock [statistics] PORT = 4088 UNIXPATH = /tmp/test_quota_compliance_unix_statistics_peer1.sock [resolver] PORT = 4089 UNIXPATH = /tmp/test_quota_compliance_unix_resolver_peer1.sock [peerinfo] PORT = 4090 UNIXPATH = /tmp/test_quota_compliance_unix_peerinfo_peer1.sock [transport] PORT = 4091 PLUGINS = unix UNIXPATH = /tmp/test_quota_compliance_unix_transport_peer1.sock gnunet-0.9.3/src/transport/test_quota_compliance_unix_asymmetric_peer2.conf0000644000175000017500000000116611647100177024425 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test_quota_compliance_peer2 DEFAULTCONFIG = test_quota_compliance_unix_asymmetric_peer2.conf [arm] PORT = 3087 UNIXPATH = /tmp/test_quota_compliance_unix_arm_peer2.sock [statistics] PORT = 3088 UNIXPATH = /tmp/test_quota_compliance_unix_statistics_peer2.sock [resolver] PORT = 3089 UNIXPATH = /tmp/test_quota_compliance_unix_resolver_peer2.sock [peerinfo] PORT = 3090 UNIXPATH = /tmp/test_quota_compliance_unix_peerinfo_peer2.sock [transport] PORT = 3091 PLUGINS = unix UNIXPATH = /tmp/test_quota_compliance_unix_transport_peer2.sock [transport-unix] PORT = 3368 gnunet-0.9.3/src/transport/test_transport_api_reliability_http_nat_peer1.conf0000644000175000017500000000141611665472561024767 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-http-p1/ DEFAULTCONFIG = test_transport_api_reliability_http_nat_peer1.conf [nat] BEHIND_NAT = YES ENABLE_NAT_SERVER = YES [transport-http] PORT = 0 [arm] PORT = 12085 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12084 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12083 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12082 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] #DEBUG = YES PORT = 12081 PLUGINS = http #BINARY = .libs/gnunet-service-transport UNIXPATH = /tmp/gnunet-p1-service-transport.sock #PREFIX = valgrind --leak-check=full #PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args gnunet-0.9.3/src/transport/test_transport_api_limited_sockets_tcp_peer1.conf0000644000175000017500000000111211750306133024560 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-tcp-p1/ DEFAULTCONFIG = test_transport_api_tcp_peer1.conf [transport-tcp] PORT = 12000 TIMEOUT = 5 s [arm] PORT = 12005 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12004 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12003 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12002 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12001 PLUGINS = tcp UNIXPATH = /tmp/gnunet-p1-service-transport.sock gnunet-0.9.3/src/transport/gnunet-service-transport.h0000644000175000017500000000346011760502551017735 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/gnunet-service-transport.h * @brief globals * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_TRANSPORT_H #define GNUNET_SERVICE_TRANSPORT_H #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" #include "gnunet_util_lib.h" #define VERBOSE_VALIDATION GNUNET_YES /** * Statistics handle. */ extern struct GNUNET_STATISTICS_Handle *GST_stats; /** * Configuration handle. */ extern const struct GNUNET_CONFIGURATION_Handle *GST_cfg; /** * Configuration handle. */ extern struct GNUNET_PeerIdentity GST_my_identity; /** * Handle to peerinfo service. */ extern struct GNUNET_PEERINFO_Handle *GST_peerinfo; /** * Our public key. */ extern struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded GST_my_public_key; /** * Our private key. */ extern struct GNUNET_CRYPTO_RsaPrivateKey *GST_my_private_key; /** * ATS handle. */ extern struct GNUNET_ATS_SchedulingHandle *GST_ats; #endif /* end of file gnunet-service-transport_plugins.h */ gnunet-0.9.3/src/transport/test_quota_compliance_udp_peer1.conf0000644000175000017500000000116711647100177021775 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test_quota_compliance_peer1/ DEFAULTCONFIG = test_quota_compliance_udp_peer1.conf [transport-udp] PORT = 4368 MAX_BPS = 50000000 [arm] PORT = 4087 UNIXPATH = /tmp/test_quota_compliance_udp_arm_peer1.sock [statistics] PORT = 4088 UNIXPATH = /tmp/test_quota_compliance_udp_statistics_peer1.sock [resolver] PORT = 4089 UNIXPATH = /tmp/test_quota_compliance_udp_resolver_peer1.sock [peerinfo] PORT = 4090 UNIXPATH = /tmp/test_quota_compliance_udp_peerinfo_peer1.sock [transport] PORT = 4091 PLUGINS = udp UNIXPATH = /tmp/test_quota_compliance_udp_transport_peer1.sock gnunet-0.9.3/src/transport/test_transport_api_http_peer2.conf0000644000175000017500000000116011661530125021514 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-http-p2/ DEFAULTCONFIG = test_transport_api_http_peer2.conf [transport-http] PORT = 12090 [arm] PORT = 12095 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12094 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12093 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12092 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] #DEBUG = YES PORT = 12091 PLUGINS = http UNIXPATH = /tmp/gnunet-p2-service-transport.sock #PREFIX = valgrind --leak-check=full gnunet-0.9.3/src/transport/Makefile.in0000644000175000017500000036730111762223645014656 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ noinst_PROGRAMS = $(am__EXEEXT_22) bin_PROGRAMS = gnunet-transport$(EXEEXT) $(am__EXEEXT_1) \ $(am__EXEEXT_2) gnunet-service-transport$(EXEEXT) \ gnunet-transport-certificate-creation$(EXEEXT) check_PROGRAMS = test_transport_testing$(EXEEXT) \ test_transport_startonly$(EXEEXT) \ test_transport_api_blacklisting$(EXEEXT) \ test_transport_api_disconnect_tcp$(EXEEXT) \ test_transport_api_bidirectional_connect$(EXEEXT) \ test_transport_api_tcp$(EXEEXT) \ test_transport_api_restart_1peer$(EXEEXT) \ test_transport_api_restart_2peers$(EXEEXT) \ test_transport_api_timeout_tcp$(EXEEXT) \ test_transport_api_limited_sockets_tcp$(EXEEXT) \ test_transport_api_tcp_nat$(EXEEXT) \ test_transport_api_udp$(EXEEXT) \ test_transport_api_timeout_udp$(EXEEXT) $(am__EXEEXT_3) \ $(am__EXEEXT_4) test_transport_api_udp_nat$(EXEEXT) \ $(am__EXEEXT_5) $(am__EXEEXT_6) $(am__EXEEXT_7) \ $(am__EXEEXT_8) $(am__EXEEXT_9) $(am__EXEEXT_10) \ test_transport_api_multi$(EXEEXT) \ test_transport_api_reliability_tcp$(EXEEXT) \ test_transport_api_reliability_tcp_nat$(EXEEXT) \ test_transport_api_unreliability_udp$(EXEEXT) \ test_transport_api_unreliability_constant_udp$(EXEEXT) \ $(am__EXEEXT_11) $(am__EXEEXT_12) $(am__EXEEXT_13) \ $(am__EXEEXT_14) $(am__EXEEXT_15) \ test_quota_compliance_tcp$(EXEEXT) \ test_quota_compliance_tcp_asymmetric$(EXEEXT) \ test_quota_compliance_udp$(EXEEXT) $(am__EXEEXT_16) \ $(am__EXEEXT_17) $(am__EXEEXT_18) $(am__EXEEXT_19) \ $(am__EXEEXT_20) $(am__EXEEXT_21) @ENABLE_TEST_RUN_TRUE@TESTS = test_transport_testing$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_startonly$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_blacklisting$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_disconnect_tcp$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_bidirectional_connect$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_tcp$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_restart_1peer$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_restart_2peers$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_timeout_tcp$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_limited_sockets_tcp$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_tcp_nat$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_udp$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_timeout_udp$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_3) $(am__EXEEXT_4) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_udp_nat$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_5) $(am__EXEEXT_6) \ @ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_7) $(am__EXEEXT_8) \ @ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_9) $(am__EXEEXT_10) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_multi$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_reliability_tcp$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_reliability_tcp_nat$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_unreliability_udp$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_transport_api_unreliability_constant_udp$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_11) $(am__EXEEXT_12) \ @ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_13) $(am__EXEEXT_14) \ @ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_15) \ @ENABLE_TEST_RUN_TRUE@ test_quota_compliance_tcp$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_quota_compliance_tcp_asymmetric$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_quota_compliance_udp$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_16) $(am__EXEEXT_17) \ @ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_18) $(am__EXEEXT_19) \ @ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_20) $(am__EXEEXT_21) subdir = src/transport DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/transport.conf.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = transport.conf CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \ "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) $(plugin_LTLIBRARIES) libgnunet_plugin_transport_http_la_DEPENDENCIES = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la am_libgnunet_plugin_transport_http_la_OBJECTS = \ libgnunet_plugin_transport_http_la-plugin_transport_http.lo \ libgnunet_plugin_transport_http_la-plugin_transport_http_client.lo \ libgnunet_plugin_transport_http_la-plugin_transport_http_server.lo libgnunet_plugin_transport_http_la_OBJECTS = \ $(am_libgnunet_plugin_transport_http_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunet_plugin_transport_http_la_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CCLD) $(libgnunet_plugin_transport_http_la_CFLAGS) $(CFLAGS) \ $(libgnunet_plugin_transport_http_la_LDFLAGS) $(LDFLAGS) -o $@ @HAVE_MHD_TRUE@am_libgnunet_plugin_transport_http_la_rpath = -rpath \ @HAVE_MHD_TRUE@ $(plugindir) libgnunet_plugin_transport_https_la_DEPENDENCIES = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la am_libgnunet_plugin_transport_https_la_OBJECTS = \ libgnunet_plugin_transport_https_la-plugin_transport_http.lo \ libgnunet_plugin_transport_https_la-plugin_transport_http_client.lo \ libgnunet_plugin_transport_https_la-plugin_transport_http_server.lo libgnunet_plugin_transport_https_la_OBJECTS = \ $(am_libgnunet_plugin_transport_https_la_OBJECTS) libgnunet_plugin_transport_https_la_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CCLD) $(libgnunet_plugin_transport_https_la_CFLAGS) \ $(CFLAGS) $(libgnunet_plugin_transport_https_la_LDFLAGS) \ $(LDFLAGS) -o $@ @HAVE_MHD_TRUE@am_libgnunet_plugin_transport_https_la_rpath = -rpath \ @HAVE_MHD_TRUE@ $(plugindir) libgnunet_plugin_transport_tcp_la_DEPENDENCIES = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la am_libgnunet_plugin_transport_tcp_la_OBJECTS = \ plugin_transport_tcp.lo libgnunet_plugin_transport_tcp_la_OBJECTS = \ $(am_libgnunet_plugin_transport_tcp_la_OBJECTS) libgnunet_plugin_transport_tcp_la_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libgnunet_plugin_transport_tcp_la_LDFLAGS) $(LDFLAGS) -o $@ libgnunet_plugin_transport_template_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_libgnunet_plugin_transport_template_la_OBJECTS = \ plugin_transport_template.lo libgnunet_plugin_transport_template_la_OBJECTS = \ $(am_libgnunet_plugin_transport_template_la_OBJECTS) libgnunet_plugin_transport_template_la_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libgnunet_plugin_transport_template_la_LDFLAGS) $(LDFLAGS) \ -o $@ libgnunet_plugin_transport_udp_la_DEPENDENCIES = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la am_libgnunet_plugin_transport_udp_la_OBJECTS = \ plugin_transport_udp.lo plugin_transport_udp_broadcasting.lo libgnunet_plugin_transport_udp_la_OBJECTS = \ $(am_libgnunet_plugin_transport_udp_la_OBJECTS) libgnunet_plugin_transport_udp_la_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libgnunet_plugin_transport_udp_la_LDFLAGS) $(LDFLAGS) -o $@ libgnunet_plugin_transport_unix_la_DEPENDENCIES = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/util/libgnunetutil.la am_libgnunet_plugin_transport_unix_la_OBJECTS = \ plugin_transport_unix.lo libgnunet_plugin_transport_unix_la_OBJECTS = \ $(am_libgnunet_plugin_transport_unix_la_OBJECTS) libgnunet_plugin_transport_unix_la_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libgnunet_plugin_transport_unix_la_LDFLAGS) $(LDFLAGS) -o $@ @MINGW_FALSE@am_libgnunet_plugin_transport_unix_la_rpath = -rpath \ @MINGW_FALSE@ $(plugindir) libgnunet_plugin_transport_wlan_la_DEPENDENCIES = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \ $(top_builddir)/src/util/libgnunetutil.la am_libgnunet_plugin_transport_wlan_la_OBJECTS = \ plugin_transport_wlan.lo libgnunet_plugin_transport_wlan_la_OBJECTS = \ $(am_libgnunet_plugin_transport_wlan_la_OBJECTS) libgnunet_plugin_transport_wlan_la_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libgnunet_plugin_transport_wlan_la_LDFLAGS) $(LDFLAGS) -o $@ @LINUX_TRUE@am_libgnunet_plugin_transport_wlan_la_rpath = -rpath \ @LINUX_TRUE@ $(plugindir) am__DEPENDENCIES_1 = libgnunettransport_la_DEPENDENCIES = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_libgnunettransport_la_OBJECTS = transport_api.lo \ transport_api_blacklist.lo transport_api_address_to_string.lo \ transport_api_address_lookup.lo libgnunettransport_la_OBJECTS = $(am_libgnunettransport_la_OBJECTS) libgnunettransport_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunettransport_la_LDFLAGS) \ $(LDFLAGS) -o $@ am_libgnunettransporttesting_la_OBJECTS = transport-testing.lo libgnunettransporttesting_la_OBJECTS = \ $(am_libgnunettransporttesting_la_OBJECTS) libgnunettransporttesting_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunettransporttesting_la_LDFLAGS) \ $(LDFLAGS) -o $@ @LINUX_TRUE@am__EXEEXT_1 = gnunet-helper-transport-wlan$(EXEEXT) @LINUX_TRUE@am__EXEEXT_2 = \ @LINUX_TRUE@ gnunet-helper-transport-wlan-dummy$(EXEEXT) @MINGW_FALSE@am__EXEEXT_3 = test_transport_api_unix$(EXEEXT) @MINGW_FALSE@am__EXEEXT_4 = test_transport_api_timeout_unix$(EXEEXT) @HAVE_MHD_TRUE@am__EXEEXT_5 = test_transport_api_http$(EXEEXT) @HAVE_MHD_TRUE@am__EXEEXT_6 = test_transport_api_http_nat$(EXEEXT) @HAVE_MHD_TRUE@am__EXEEXT_7 = \ @HAVE_MHD_TRUE@ test_transport_api_timeout_http$(EXEEXT) @HAVE_MHD_TRUE@am__EXEEXT_8 = test_transport_api_https$(EXEEXT) @HAVE_MHD_TRUE@am__EXEEXT_9 = test_transport_api_https_nat$(EXEEXT) @HAVE_MHD_TRUE@am__EXEEXT_10 = \ @HAVE_MHD_TRUE@ test_transport_api_timeout_https$(EXEEXT) @MINGW_FALSE@am__EXEEXT_11 = \ @MINGW_FALSE@ test_transport_api_unreliability_unix$(EXEEXT) @HAVE_MHD_TRUE@am__EXEEXT_12 = \ @HAVE_MHD_TRUE@ test_transport_api_reliability_http$(EXEEXT) @HAVE_MHD_TRUE@am__EXEEXT_13 = test_transport_api_reliability_http_nat$(EXEEXT) @HAVE_MHD_TRUE@am__EXEEXT_14 = \ @HAVE_MHD_TRUE@ test_transport_api_reliability_https$(EXEEXT) @HAVE_MHD_TRUE@am__EXEEXT_15 = test_transport_api_reliability_https_nat$(EXEEXT) @MINGW_FALSE@am__EXEEXT_16 = test_quota_compliance_unix$(EXEEXT) \ @MINGW_FALSE@ test_quota_compliance_unix_asymmetric$(EXEEXT) @HAVE_MHD_TRUE@am__EXEEXT_17 = test_quota_compliance_http$(EXEEXT) \ @HAVE_MHD_TRUE@ test_quota_compliance_http_asymmetric$(EXEEXT) @HAVE_MHD_TRUE@am__EXEEXT_18 = test_quota_compliance_https$(EXEEXT) \ @HAVE_MHD_TRUE@ test_quota_compliance_https_asymmetric$(EXEEXT) @LINUX_TRUE@am__EXEEXT_19 = test_transport_api_wlan$(EXEEXT) @LINUX_TRUE@am__EXEEXT_20 = \ @LINUX_TRUE@ test_transport_api_reliability_wlan$(EXEEXT) @LINUX_TRUE@am__EXEEXT_21 = \ @LINUX_TRUE@ test_transport_api_unreliability_wlan$(EXEEXT) @LINUX_TRUE@am__EXEEXT_22 = gnunet-transport-wlan-sender$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) am_gnunet_helper_transport_wlan_OBJECTS = \ gnunet-helper-transport-wlan.$(OBJEXT) gnunet_helper_transport_wlan_OBJECTS = \ $(am_gnunet_helper_transport_wlan_OBJECTS) gnunet_helper_transport_wlan_LDADD = $(LDADD) am_gnunet_helper_transport_wlan_dummy_OBJECTS = \ gnunet-helper-transport-wlan-dummy.$(OBJEXT) gnunet_helper_transport_wlan_dummy_OBJECTS = \ $(am_gnunet_helper_transport_wlan_dummy_OBJECTS) gnunet_helper_transport_wlan_dummy_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_gnunet_service_transport_OBJECTS = \ gnunet-service-transport.$(OBJEXT) \ gnunet-service-transport_blacklist.$(OBJEXT) \ gnunet-service-transport_clients.$(OBJEXT) \ gnunet-service-transport_hello.$(OBJEXT) \ gnunet-service-transport_neighbours.$(OBJEXT) \ gnunet-service-transport_plugins.$(OBJEXT) \ gnunet-service-transport_validation.$(OBJEXT) gnunet_service_transport_OBJECTS = \ $(am_gnunet_service_transport_OBJECTS) gnunet_service_transport_DEPENDENCIES = \ $(top_builddir)/src/ats/libgnunetats.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_gnunet_transport_OBJECTS = gnunet-transport.$(OBJEXT) gnunet_transport_OBJECTS = $(am_gnunet_transport_OBJECTS) am_gnunet_transport_certificate_creation_OBJECTS = \ gnunet-transport-certificate-creation.$(OBJEXT) gnunet_transport_certificate_creation_OBJECTS = \ $(am_gnunet_transport_certificate_creation_OBJECTS) gnunet_transport_certificate_creation_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_gnunet_transport_wlan_sender_OBJECTS = \ gnunet-transport-wlan-sender.$(OBJEXT) gnunet_transport_wlan_sender_OBJECTS = \ $(am_gnunet_transport_wlan_sender_OBJECTS) gnunet_transport_wlan_sender_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_test_quota_compliance_http_OBJECTS = \ test_quota_compliance.$(OBJEXT) test_quota_compliance_http_OBJECTS = \ $(am_test_quota_compliance_http_OBJECTS) test_quota_compliance_http_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_quota_compliance_http_asymmetric_OBJECTS = \ test_quota_compliance.$(OBJEXT) test_quota_compliance_http_asymmetric_OBJECTS = \ $(am_test_quota_compliance_http_asymmetric_OBJECTS) test_quota_compliance_http_asymmetric_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_quota_compliance_https_OBJECTS = \ test_quota_compliance.$(OBJEXT) test_quota_compliance_https_OBJECTS = \ $(am_test_quota_compliance_https_OBJECTS) test_quota_compliance_https_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_quota_compliance_https_asymmetric_OBJECTS = \ test_quota_compliance.$(OBJEXT) test_quota_compliance_https_asymmetric_OBJECTS = \ $(am_test_quota_compliance_https_asymmetric_OBJECTS) test_quota_compliance_https_asymmetric_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_quota_compliance_tcp_OBJECTS = \ test_quota_compliance.$(OBJEXT) test_quota_compliance_tcp_OBJECTS = \ $(am_test_quota_compliance_tcp_OBJECTS) test_quota_compliance_tcp_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_quota_compliance_tcp_asymmetric_OBJECTS = \ test_quota_compliance.$(OBJEXT) test_quota_compliance_tcp_asymmetric_OBJECTS = \ $(am_test_quota_compliance_tcp_asymmetric_OBJECTS) test_quota_compliance_tcp_asymmetric_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_quota_compliance_udp_OBJECTS = \ test_quota_compliance.$(OBJEXT) test_quota_compliance_udp_OBJECTS = \ $(am_test_quota_compliance_udp_OBJECTS) test_quota_compliance_udp_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_quota_compliance_unix_OBJECTS = \ test_quota_compliance.$(OBJEXT) test_quota_compliance_unix_OBJECTS = \ $(am_test_quota_compliance_unix_OBJECTS) test_quota_compliance_unix_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_quota_compliance_unix_asymmetric_OBJECTS = \ test_quota_compliance.$(OBJEXT) test_quota_compliance_unix_asymmetric_OBJECTS = \ $(am_test_quota_compliance_unix_asymmetric_OBJECTS) test_quota_compliance_unix_asymmetric_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_bidirectional_connect_OBJECTS = \ test_transport_api_bidirectional_connect.$(OBJEXT) test_transport_api_bidirectional_connect_OBJECTS = \ $(am_test_transport_api_bidirectional_connect_OBJECTS) test_transport_api_bidirectional_connect_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_blacklisting_OBJECTS = \ test_transport_api_blacklisting.$(OBJEXT) test_transport_api_blacklisting_OBJECTS = \ $(am_test_transport_api_blacklisting_OBJECTS) test_transport_api_blacklisting_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_disconnect_tcp_OBJECTS = \ test_transport_api_disconnect.$(OBJEXT) test_transport_api_disconnect_tcp_OBJECTS = \ $(am_test_transport_api_disconnect_tcp_OBJECTS) test_transport_api_disconnect_tcp_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_http_OBJECTS = test_transport_api.$(OBJEXT) test_transport_api_http_OBJECTS = \ $(am_test_transport_api_http_OBJECTS) test_transport_api_http_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_http_nat_OBJECTS = test_transport_api.$(OBJEXT) test_transport_api_http_nat_OBJECTS = \ $(am_test_transport_api_http_nat_OBJECTS) test_transport_api_http_nat_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_https_OBJECTS = test_transport_api.$(OBJEXT) test_transport_api_https_OBJECTS = \ $(am_test_transport_api_https_OBJECTS) test_transport_api_https_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_https_nat_OBJECTS = \ test_transport_api.$(OBJEXT) test_transport_api_https_nat_OBJECTS = \ $(am_test_transport_api_https_nat_OBJECTS) test_transport_api_https_nat_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_limited_sockets_tcp_OBJECTS = \ test_transport_api_limited_sockets.$(OBJEXT) test_transport_api_limited_sockets_tcp_OBJECTS = \ $(am_test_transport_api_limited_sockets_tcp_OBJECTS) test_transport_api_limited_sockets_tcp_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_multi_OBJECTS = test_transport_api.$(OBJEXT) test_transport_api_multi_OBJECTS = \ $(am_test_transport_api_multi_OBJECTS) test_transport_api_multi_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_reliability_http_OBJECTS = \ test_transport_api_reliability.$(OBJEXT) test_transport_api_reliability_http_OBJECTS = \ $(am_test_transport_api_reliability_http_OBJECTS) test_transport_api_reliability_http_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_reliability_http_nat_OBJECTS = \ test_transport_api_reliability.$(OBJEXT) test_transport_api_reliability_http_nat_OBJECTS = \ $(am_test_transport_api_reliability_http_nat_OBJECTS) test_transport_api_reliability_http_nat_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_reliability_https_OBJECTS = \ test_transport_api_reliability.$(OBJEXT) test_transport_api_reliability_https_OBJECTS = \ $(am_test_transport_api_reliability_https_OBJECTS) test_transport_api_reliability_https_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_reliability_https_nat_OBJECTS = \ test_transport_api_reliability.$(OBJEXT) test_transport_api_reliability_https_nat_OBJECTS = \ $(am_test_transport_api_reliability_https_nat_OBJECTS) test_transport_api_reliability_https_nat_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_reliability_tcp_OBJECTS = \ test_transport_api_reliability.$(OBJEXT) test_transport_api_reliability_tcp_OBJECTS = \ $(am_test_transport_api_reliability_tcp_OBJECTS) test_transport_api_reliability_tcp_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_reliability_tcp_nat_OBJECTS = \ test_transport_api_reliability.$(OBJEXT) test_transport_api_reliability_tcp_nat_OBJECTS = \ $(am_test_transport_api_reliability_tcp_nat_OBJECTS) test_transport_api_reliability_tcp_nat_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_reliability_wlan_OBJECTS = \ test_transport_api_reliability.$(OBJEXT) test_transport_api_reliability_wlan_OBJECTS = \ $(am_test_transport_api_reliability_wlan_OBJECTS) test_transport_api_reliability_wlan_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_restart_1peer_OBJECTS = \ test_transport_api_restart_1peer.$(OBJEXT) test_transport_api_restart_1peer_OBJECTS = \ $(am_test_transport_api_restart_1peer_OBJECTS) test_transport_api_restart_1peer_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_restart_2peers_OBJECTS = \ test_transport_api_restart_2peers.$(OBJEXT) test_transport_api_restart_2peers_OBJECTS = \ $(am_test_transport_api_restart_2peers_OBJECTS) test_transport_api_restart_2peers_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_tcp_OBJECTS = test_transport_api.$(OBJEXT) test_transport_api_tcp_OBJECTS = $(am_test_transport_api_tcp_OBJECTS) test_transport_api_tcp_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_tcp_nat_OBJECTS = test_transport_api.$(OBJEXT) test_transport_api_tcp_nat_OBJECTS = \ $(am_test_transport_api_tcp_nat_OBJECTS) test_transport_api_tcp_nat_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_timeout_http_OBJECTS = \ test_transport_api_timeout.$(OBJEXT) test_transport_api_timeout_http_OBJECTS = \ $(am_test_transport_api_timeout_http_OBJECTS) test_transport_api_timeout_http_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_timeout_https_OBJECTS = \ test_transport_api_timeout.$(OBJEXT) test_transport_api_timeout_https_OBJECTS = \ $(am_test_transport_api_timeout_https_OBJECTS) test_transport_api_timeout_https_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_timeout_tcp_OBJECTS = \ test_transport_api_timeout.$(OBJEXT) test_transport_api_timeout_tcp_OBJECTS = \ $(am_test_transport_api_timeout_tcp_OBJECTS) test_transport_api_timeout_tcp_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_timeout_udp_OBJECTS = \ test_transport_api_timeout.$(OBJEXT) test_transport_api_timeout_udp_OBJECTS = \ $(am_test_transport_api_timeout_udp_OBJECTS) test_transport_api_timeout_udp_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_timeout_unix_OBJECTS = \ test_transport_api_timeout.$(OBJEXT) test_transport_api_timeout_unix_OBJECTS = \ $(am_test_transport_api_timeout_unix_OBJECTS) test_transport_api_timeout_unix_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_udp_OBJECTS = test_transport_api.$(OBJEXT) test_transport_api_udp_OBJECTS = $(am_test_transport_api_udp_OBJECTS) test_transport_api_udp_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_udp_nat_OBJECTS = test_transport_api.$(OBJEXT) test_transport_api_udp_nat_OBJECTS = \ $(am_test_transport_api_udp_nat_OBJECTS) test_transport_api_udp_nat_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_unix_OBJECTS = test_transport_api.$(OBJEXT) test_transport_api_unix_OBJECTS = \ $(am_test_transport_api_unix_OBJECTS) test_transport_api_unix_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_unreliability_constant_udp_OBJECTS = \ test_transport_api_unreliability_constant.$(OBJEXT) test_transport_api_unreliability_constant_udp_OBJECTS = \ $(am_test_transport_api_unreliability_constant_udp_OBJECTS) test_transport_api_unreliability_constant_udp_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_unreliability_udp_OBJECTS = \ test_transport_api_unreliability.$(OBJEXT) test_transport_api_unreliability_udp_OBJECTS = \ $(am_test_transport_api_unreliability_udp_OBJECTS) test_transport_api_unreliability_udp_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_unreliability_unix_OBJECTS = \ test_transport_api_unreliability.$(OBJEXT) test_transport_api_unreliability_unix_OBJECTS = \ $(am_test_transport_api_unreliability_unix_OBJECTS) test_transport_api_unreliability_unix_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_api_unreliability_wlan_OBJECTS = \ test_transport_api_unreliability.$(OBJEXT) test_transport_api_unreliability_wlan_OBJECTS = \ $(am_test_transport_api_unreliability_wlan_OBJECTS) test_transport_api_unreliability_wlan_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am__test_transport_api_wlan_SOURCES_DIST = test_transport_api.c @LINUX_TRUE@am_test_transport_api_wlan_OBJECTS = \ @LINUX_TRUE@ test_transport_api.$(OBJEXT) test_transport_api_wlan_OBJECTS = \ $(am_test_transport_api_wlan_OBJECTS) @LINUX_TRUE@test_transport_api_wlan_DEPENDENCIES = $(top_builddir)/src/transport/libgnunettransport.la \ @LINUX_TRUE@ $(top_builddir)/src/hello/libgnunethello.la \ @LINUX_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \ @LINUX_TRUE@ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_startonly_OBJECTS = \ test_transport_startonly.$(OBJEXT) test_transport_startonly_OBJECTS = \ $(am_test_transport_startonly_OBJECTS) test_transport_startonly_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la am_test_transport_testing_OBJECTS = test_transport_testing.$(OBJEXT) test_transport_testing_OBJECTS = $(am_test_transport_testing_OBJECTS) test_transport_testing_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunet_plugin_transport_http_la_SOURCES) \ $(libgnunet_plugin_transport_https_la_SOURCES) \ $(libgnunet_plugin_transport_tcp_la_SOURCES) \ $(libgnunet_plugin_transport_template_la_SOURCES) \ $(libgnunet_plugin_transport_udp_la_SOURCES) \ $(libgnunet_plugin_transport_unix_la_SOURCES) \ $(libgnunet_plugin_transport_wlan_la_SOURCES) \ $(libgnunettransport_la_SOURCES) \ $(libgnunettransporttesting_la_SOURCES) \ $(gnunet_helper_transport_wlan_SOURCES) \ $(gnunet_helper_transport_wlan_dummy_SOURCES) \ $(gnunet_service_transport_SOURCES) \ $(gnunet_transport_SOURCES) \ $(gnunet_transport_certificate_creation_SOURCES) \ $(gnunet_transport_wlan_sender_SOURCES) \ $(test_quota_compliance_http_SOURCES) \ $(test_quota_compliance_http_asymmetric_SOURCES) \ $(test_quota_compliance_https_SOURCES) \ $(test_quota_compliance_https_asymmetric_SOURCES) \ $(test_quota_compliance_tcp_SOURCES) \ $(test_quota_compliance_tcp_asymmetric_SOURCES) \ $(test_quota_compliance_udp_SOURCES) \ $(test_quota_compliance_unix_SOURCES) \ $(test_quota_compliance_unix_asymmetric_SOURCES) \ $(test_transport_api_bidirectional_connect_SOURCES) \ $(test_transport_api_blacklisting_SOURCES) \ $(test_transport_api_disconnect_tcp_SOURCES) \ $(test_transport_api_http_SOURCES) \ $(test_transport_api_http_nat_SOURCES) \ $(test_transport_api_https_SOURCES) \ $(test_transport_api_https_nat_SOURCES) \ $(test_transport_api_limited_sockets_tcp_SOURCES) \ $(test_transport_api_multi_SOURCES) \ $(test_transport_api_reliability_http_SOURCES) \ $(test_transport_api_reliability_http_nat_SOURCES) \ $(test_transport_api_reliability_https_SOURCES) \ $(test_transport_api_reliability_https_nat_SOURCES) \ $(test_transport_api_reliability_tcp_SOURCES) \ $(test_transport_api_reliability_tcp_nat_SOURCES) \ $(test_transport_api_reliability_wlan_SOURCES) \ $(test_transport_api_restart_1peer_SOURCES) \ $(test_transport_api_restart_2peers_SOURCES) \ $(test_transport_api_tcp_SOURCES) \ $(test_transport_api_tcp_nat_SOURCES) \ $(test_transport_api_timeout_http_SOURCES) \ $(test_transport_api_timeout_https_SOURCES) \ $(test_transport_api_timeout_tcp_SOURCES) \ $(test_transport_api_timeout_udp_SOURCES) \ $(test_transport_api_timeout_unix_SOURCES) \ $(test_transport_api_udp_SOURCES) \ $(test_transport_api_udp_nat_SOURCES) \ $(test_transport_api_unix_SOURCES) \ $(test_transport_api_unreliability_constant_udp_SOURCES) \ $(test_transport_api_unreliability_udp_SOURCES) \ $(test_transport_api_unreliability_unix_SOURCES) \ $(test_transport_api_unreliability_wlan_SOURCES) \ $(test_transport_api_wlan_SOURCES) \ $(test_transport_startonly_SOURCES) \ $(test_transport_testing_SOURCES) DIST_SOURCES = $(libgnunet_plugin_transport_http_la_SOURCES) \ $(libgnunet_plugin_transport_https_la_SOURCES) \ $(libgnunet_plugin_transport_tcp_la_SOURCES) \ $(libgnunet_plugin_transport_template_la_SOURCES) \ $(libgnunet_plugin_transport_udp_la_SOURCES) \ $(libgnunet_plugin_transport_unix_la_SOURCES) \ $(libgnunet_plugin_transport_wlan_la_SOURCES) \ $(libgnunettransport_la_SOURCES) \ $(libgnunettransporttesting_la_SOURCES) \ $(gnunet_helper_transport_wlan_SOURCES) \ $(gnunet_helper_transport_wlan_dummy_SOURCES) \ $(gnunet_service_transport_SOURCES) \ $(gnunet_transport_SOURCES) \ $(gnunet_transport_certificate_creation_SOURCES) \ $(gnunet_transport_wlan_sender_SOURCES) \ $(test_quota_compliance_http_SOURCES) \ $(test_quota_compliance_http_asymmetric_SOURCES) \ $(test_quota_compliance_https_SOURCES) \ $(test_quota_compliance_https_asymmetric_SOURCES) \ $(test_quota_compliance_tcp_SOURCES) \ $(test_quota_compliance_tcp_asymmetric_SOURCES) \ $(test_quota_compliance_udp_SOURCES) \ $(test_quota_compliance_unix_SOURCES) \ $(test_quota_compliance_unix_asymmetric_SOURCES) \ $(test_transport_api_bidirectional_connect_SOURCES) \ $(test_transport_api_blacklisting_SOURCES) \ $(test_transport_api_disconnect_tcp_SOURCES) \ $(test_transport_api_http_SOURCES) \ $(test_transport_api_http_nat_SOURCES) \ $(test_transport_api_https_SOURCES) \ $(test_transport_api_https_nat_SOURCES) \ $(test_transport_api_limited_sockets_tcp_SOURCES) \ $(test_transport_api_multi_SOURCES) \ $(test_transport_api_reliability_http_SOURCES) \ $(test_transport_api_reliability_http_nat_SOURCES) \ $(test_transport_api_reliability_https_SOURCES) \ $(test_transport_api_reliability_https_nat_SOURCES) \ $(test_transport_api_reliability_tcp_SOURCES) \ $(test_transport_api_reliability_tcp_nat_SOURCES) \ $(test_transport_api_reliability_wlan_SOURCES) \ $(test_transport_api_restart_1peer_SOURCES) \ $(test_transport_api_restart_2peers_SOURCES) \ $(test_transport_api_tcp_SOURCES) \ $(test_transport_api_tcp_nat_SOURCES) \ $(test_transport_api_timeout_http_SOURCES) \ $(test_transport_api_timeout_https_SOURCES) \ $(test_transport_api_timeout_tcp_SOURCES) \ $(test_transport_api_timeout_udp_SOURCES) \ $(test_transport_api_timeout_unix_SOURCES) \ $(test_transport_api_udp_SOURCES) \ $(test_transport_api_udp_nat_SOURCES) \ $(test_transport_api_unix_SOURCES) \ $(test_transport_api_unreliability_constant_udp_SOURCES) \ $(test_transport_api_unreliability_udp_SOURCES) \ $(test_transport_api_unreliability_unix_SOURCES) \ $(test_transport_api_unreliability_wlan_SOURCES) \ $(am__test_transport_api_wlan_SOURCES_DIST) \ $(test_transport_startonly_SOURCES) \ $(test_transport_testing_SOURCES) DATA = $(pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include -I$(top_builddir)/src/include plugindir = $(libdir)/gnunet pkgcfgdir = $(pkgdatadir)/config.d/ pkgcfg_DATA = \ transport.conf @HAVE_MHD_TRUE@GN_LIBMHD = -lmicrohttpd @HAVE_MHD_TRUE@HTTP_PLUGIN_LA = libgnunet_plugin_transport_http.la @HAVE_MHD_TRUE@HTTP_API_TEST = test_transport_api_http @HAVE_MHD_TRUE@HTTP_NAT_API_TEST = test_transport_api_http_nat @HAVE_MHD_TRUE@HTTP_API_TIMEOUT_TEST = test_transport_api_timeout_http @HAVE_MHD_TRUE@HTTP_REL_TEST = test_transport_api_reliability_http @HAVE_MHD_TRUE@HTTP_NAT_REL_TEST = test_transport_api_reliability_http_nat @HAVE_MHD_TRUE@HTTP_QUOTA_TEST = test_quota_compliance_http \ @HAVE_MHD_TRUE@ test_quota_compliance_http_asymmetric @HAVE_MHD_TRUE@HTTPS_PLUGIN_LA = libgnunet_plugin_transport_https.la @HAVE_MHD_TRUE@HTTPS_API_TEST = test_transport_api_https @HAVE_MHD_TRUE@HTTPS_NAT_API_TEST = test_transport_api_https_nat @HAVE_MHD_TRUE@HTTPS_API_TIMEOUT_TEST = test_transport_api_timeout_https @HAVE_MHD_TRUE@HTTPS_REL_TEST = test_transport_api_reliability_https @HAVE_MHD_TRUE@HTTPS_NAT_REL_TEST = test_transport_api_reliability_https_nat @HAVE_MHD_TRUE@HTTPS_QUOTA_TEST = test_quota_compliance_https \ @HAVE_MHD_TRUE@ test_quota_compliance_https_asymmetric @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @LINUX_TRUE@WLAN_BIN = gnunet-helper-transport-wlan @LINUX_TRUE@WLAN_BIN_DUMMY = gnunet-helper-transport-wlan-dummy @LINUX_TRUE@WLAN_BIN_SENDER = gnunet-transport-wlan-sender @LINUX_TRUE@WLAN_PLUGIN_LA = libgnunet_plugin_transport_wlan.la @LINUX_TRUE@WLAN_API_TEST = test_transport_api_wlan @LINUX_TRUE@WLAN_REL_TEST = test_transport_api_reliability_wlan @LINUX_TRUE@WLAN_UREL_TEST = test_transport_api_unreliability_wlan @MINGW_FALSE@UNIX_PLUGIN_LA = libgnunet_plugin_transport_unix.la @MINGW_FALSE@UNIX_PLUGIN_TEST = test_transport_api_unix @MINGW_FALSE@UNIX_PLUGIN_TIMEOUT_TEST = test_transport_api_timeout_unix @MINGW_FALSE@UNIX_REL_TEST = test_transport_api_unreliability_unix @MINGW_FALSE@UNIX_QUOTA_TEST = test_quota_compliance_unix \ @MINGW_FALSE@ test_quota_compliance_unix_asymmetric # gnunet-transport-connect-running-peers lib_LTLIBRARIES = \ libgnunettransport.la \ libgnunettransporttesting.la libgnunettransporttesting_la_SOURCES = \ transport-testing.c transport-testing.h libgnunettransporttesting_la_LIBADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) libgnunettransporttesting_la_DEPENDENCIES = \ libgnunettransport.la libgnunettransporttesting_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) libgnunettransport_la_SOURCES = \ transport_api.c transport.h \ transport_api_blacklist.c \ transport_api_address_to_string.c \ transport_api_address_lookup.c libgnunettransport_la_LIBADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) libgnunettransport_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 1:0:0 #bin_SCRIPTS = \ # gnunet-transport-certificate-creation gnunet_transport_certificate_creation_SOURCES = \ gnunet-transport-certificate-creation.c gnunet_transport_certificate_creation_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la gnunet_helper_transport_wlan_SOURCES = \ gnunet-helper-transport-wlan.c gnunet_helper_transport_wlan_dummy_SOURCES = \ gnunet-helper-transport-wlan-dummy.c gnunet_helper_transport_wlan_dummy_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la gnunet_transport_wlan_sender_SOURCES = \ gnunet-transport-wlan-sender.c gnunet_transport_wlan_sender_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la gnunet_transport_SOURCES = \ gnunet-transport.c gnunet_transport_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_transport_DEPENDENCIES = \ libgnunettransport.la gnunet_service_transport_SOURCES = \ gnunet-service-transport.c gnunet-service-transport.h \ gnunet-service-transport_blacklist.h gnunet-service-transport_blacklist.c \ gnunet-service-transport_clients.h gnunet-service-transport_clients.c \ gnunet-service-transport_hello.h gnunet-service-transport_hello.c \ gnunet-service-transport_neighbours.h gnunet-service-transport_neighbours.c \ gnunet-service-transport_plugins.h gnunet-service-transport_plugins.c \ gnunet-service-transport_validation.h gnunet-service-transport_validation.c gnunet_service_transport_LDADD = \ $(top_builddir)/src/ats/libgnunetats.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_GLPK) \ $(GN_LIBINTL) plugin_LTLIBRARIES = \ libgnunet_plugin_transport_tcp.la \ libgnunet_plugin_transport_udp.la \ $(UNIX_PLUGIN_LA) \ $(HTTP_PLUGIN_LA) \ $(HTTPS_PLUGIN_LA) \ $(WLAN_PLUGIN_LA) \ libgnunet_plugin_transport_template.la libgnunet_plugin_transport_tcp_la_SOURCES = \ plugin_transport_tcp.c libgnunet_plugin_transport_tcp_la_LIBADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_transport_tcp_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_transport_template_la_SOURCES = \ plugin_transport_template.c libgnunet_plugin_transport_template_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_transport_template_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_transport_wlan_la_SOURCES = \ plugin_transport_wlan.c plugin_transport_wlan.h libgnunet_plugin_transport_wlan_la_LIBADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_transport_wlan_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_transport_udp_la_SOURCES = \ plugin_transport_udp.c plugin_transport_udp.h \ plugin_transport_udp_broadcasting.c libgnunet_plugin_transport_udp_la_LIBADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_transport_udp_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_transport_unix_la_SOURCES = \ plugin_transport_unix.c libgnunet_plugin_transport_unix_la_LIBADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_transport_unix_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_transport_http_la_SOURCES = \ plugin_transport_http.c plugin_transport_http.h \ plugin_transport_http_client.c plugin_transport_http_server.c libgnunet_plugin_transport_http_la_LIBADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ @LIBCURL@ \ $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_transport_http_la_LDFLAGS = \ $(GN_LIBMHD) \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_transport_http_la_CFLAGS = \ $(CFLAGS) libgnunet_plugin_transport_http_la_CPPFLAGS = \ @LIBCURL_CPPFLAGS@ libgnunet_plugin_transport_https_la_SOURCES = \ plugin_transport_http.c plugin_transport_http.h \ plugin_transport_http_client.c plugin_transport_http_server.c libgnunet_plugin_transport_https_la_LIBADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ @LIBCURL@ \ $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_transport_https_la_LDFLAGS = \ $(GN_LIBMHD) \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_transport_https_la_CFLAGS = \ $(CFLAGS) -DBUILD_HTTPS libgnunet_plugin_transport_https_la_CPPFLAGS = \ @LIBCURL_CPPFLAGS@ test_transport_testing_SOURCES = \ test_transport_testing.c test_transport_testing_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la #gnunet_transport_connect_running_peers_SOURCES = \ # gnunet-transport-connect-running-peers.c #gnunet_transport_connect_running_peers_LDADD = \ # $(top_builddir)/src/transport/libgnunettransport.la \ # $(top_builddir)/src/hello/libgnunethello.la \ # $(top_builddir)/src/util/libgnunetutil.la \ # $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_blacklisting_SOURCES = \ test_transport_api_blacklisting.c test_transport_api_blacklisting_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_disconnect_tcp_SOURCES = \ test_transport_api_disconnect.c test_transport_api_disconnect_tcp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_startonly_SOURCES = \ test_transport_startonly.c test_transport_startonly_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_tcp_SOURCES = \ test_transport_api.c test_transport_api_tcp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_bidirectional_connect_SOURCES = \ test_transport_api_bidirectional_connect.c test_transport_api_bidirectional_connect_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_restart_1peer_SOURCES = \ test_transport_api_restart_1peer.c test_transport_api_restart_1peer_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_restart_2peers_SOURCES = \ test_transport_api_restart_2peers.c test_transport_api_restart_2peers_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_limited_sockets_tcp_SOURCES = \ test_transport_api_limited_sockets.c test_transport_api_limited_sockets_tcp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_tcp_nat_SOURCES = \ test_transport_api.c test_transport_api_tcp_nat_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_reliability_tcp_SOURCES = \ test_transport_api_reliability.c test_transport_api_reliability_tcp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_timeout_tcp_SOURCES = \ test_transport_api_timeout.c test_transport_api_timeout_tcp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_timeout_unix_SOURCES = \ test_transport_api_timeout.c test_transport_api_timeout_unix_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_timeout_http_SOURCES = \ test_transport_api_timeout.c test_transport_api_timeout_http_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_timeout_https_SOURCES = \ test_transport_api_timeout.c test_transport_api_timeout_https_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_reliability_tcp_nat_SOURCES = \ test_transport_api_reliability.c test_transport_api_reliability_tcp_nat_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_reliability_wlan_SOURCES = \ test_transport_api_reliability.c test_transport_api_reliability_wlan_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_unreliability_wlan_SOURCES = \ test_transport_api_unreliability.c test_transport_api_unreliability_wlan_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_udp_SOURCES = \ test_transport_api.c test_transport_api_udp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_timeout_udp_SOURCES = \ test_transport_api_timeout.c test_transport_api_timeout_udp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_udp_nat_SOURCES = \ test_transport_api.c test_transport_api_udp_nat_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_unix_SOURCES = \ test_transport_api.c test_transport_api_unix_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_http_SOURCES = \ test_transport_api.c test_transport_api_http_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_http_nat_SOURCES = \ test_transport_api.c test_transport_api_http_nat_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_reliability_http_SOURCES = \ test_transport_api_reliability.c test_transport_api_reliability_http_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_reliability_http_nat_SOURCES = \ test_transport_api_reliability.c test_transport_api_reliability_http_nat_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_https_SOURCES = \ test_transport_api.c test_transport_api_https_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_https_nat_SOURCES = \ test_transport_api.c test_transport_api_https_nat_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_reliability_https_SOURCES = \ test_transport_api_reliability.c test_transport_api_reliability_https_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_reliability_https_nat_SOURCES = \ test_transport_api_reliability.c test_transport_api_reliability_https_nat_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_unreliability_unix_SOURCES = \ test_transport_api_unreliability.c test_transport_api_unreliability_unix_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_unreliability_udp_SOURCES = \ test_transport_api_unreliability.c test_transport_api_unreliability_udp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_unreliability_constant_udp_SOURCES = \ test_transport_api_unreliability_constant.c test_transport_api_unreliability_constant_udp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la @LINUX_TRUE@test_transport_api_wlan_SOURCES = \ @LINUX_TRUE@ test_transport_api.c @LINUX_TRUE@test_transport_api_wlan_LDADD = \ @LINUX_TRUE@ $(top_builddir)/src/transport/libgnunettransport.la \ @LINUX_TRUE@ $(top_builddir)/src/hello/libgnunethello.la \ @LINUX_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \ @LINUX_TRUE@ $(top_builddir)/src/transport/libgnunettransporttesting.la test_quota_compliance_tcp_SOURCES = \ test_quota_compliance.c test_quota_compliance_tcp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_quota_compliance_tcp_asymmetric_SOURCES = \ test_quota_compliance.c test_quota_compliance_tcp_asymmetric_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la #test_quota_compliance_tcp_asymmetric_send_constant_SOURCES = \ # test_quota_compliance.c #test_quota_compliance_tcp_asymmetric_send_constant_LDADD = \ # $(top_builddir)/src/transport/libgnunettransport.la \ # $(top_builddir)/src/util/libgnunetutil.la test_quota_compliance_http_SOURCES = \ test_quota_compliance.c test_quota_compliance_http_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_quota_compliance_http_asymmetric_SOURCES = \ test_quota_compliance.c test_quota_compliance_http_asymmetric_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la #test_quota_compliance_http_asymmetric_send_constant_SOURCES = \ # test_quota_compliance.c #test_quota_compliance_http_asymmetric_send_constant_LDADD = \ # $(top_builddir)/src/transport/libgnunettransport.la \ # $(top_builddir)/src/util/libgnunetutil.la test_quota_compliance_https_SOURCES = \ test_quota_compliance.c test_quota_compliance_https_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_quota_compliance_https_asymmetric_SOURCES = \ test_quota_compliance.c test_quota_compliance_https_asymmetric_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la #test_quota_compliance_https_asymmetric_send_constant_SOURCES = \ # test_quota_compliance.c #test_quota_compliance_https_asymmetric_send_constant_LDADD = \ # $(top_builddir)/src/transport/libgnunettransport.la \ # $(top_builddir)/src/util/libgnunetutil.la test_quota_compliance_udp_SOURCES = \ test_quota_compliance.c test_quota_compliance_udp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_quota_compliance_unix_SOURCES = \ test_quota_compliance.c test_quota_compliance_unix_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_quota_compliance_unix_asymmetric_SOURCES = \ test_quota_compliance.c test_quota_compliance_unix_asymmetric_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la test_transport_api_multi_SOURCES = \ test_transport_api.c test_transport_api_multi_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la EXTRA_DIST = \ gnunet-transport-certificate-creation \ template_cfg_peer1.conf\ template_cfg_peer2.conf\ test_plugin_transport_data.conf\ test_plugin_transport_data_udp.conf\ test_quota_compliance_data.conf\ test_quota_compliance_http_peer1.conf\ test_quota_compliance_http_peer2.conf\ test_quota_compliance_https_peer1.conf\ test_quota_compliance_https_peer2.conf\ test_quota_compliance_tcp_peer1.conf\ test_quota_compliance_tcp_peer2.conf\ test_quota_compliance_udp_peer1.conf\ test_quota_compliance_udp_peer2.conf\ test_quota_compliance_unix_peer1.conf\ test_quota_compliance_unix_peer2.conf\ test_quota_compliance_http_asymmetric_peer1.conf\ test_quota_compliance_http_asymmetric_peer2.conf\ test_quota_compliance_https_asymmetric_peer1.conf\ test_quota_compliance_https_asymmetric_peer2.conf\ test_quota_compliance_tcp_asymmetric_peer1.conf\ test_quota_compliance_tcp_asymmetric_peer2.conf\ test_quota_compliance_unix_asymmetric_peer1.conf\ test_quota_compliance_unix_asymmetric_peer2.conf\ test_transport_api_data.conf\ test_transport_api_http_peer1.conf\ test_transport_api_http_peer2.conf\ test_transport_api_https_peer1.conf\ test_transport_api_https_peer2.conf\ test_transport_api_limited_sockets_tcp_peer1.conf\ test_transport_api_limited_sockets_tcp_peer2.conf\ test_transport_api_timeout_tcp_peer1.conf\ test_transport_api_timeout_tcp_peer2.conf\ test_transport_api_multi_peer1.conf\ test_transport_api_multi_peer2.conf\ test_transport_api_reliability_http_peer1.conf\ test_transport_api_reliability_http_peer2.conf\ test_transport_api_reliability_https_peer1.conf\ test_transport_api_reliability_https_peer2.conf\ test_transport_api_reliability_tcp_nat_peer1.conf\ test_transport_api_reliability_tcp_nat_peer2.conf\ test_transport_api_reliability_tcp_peer1.conf\ test_transport_api_reliability_tcp_peer2.conf\ test_transport_api_reliability_wlan_peer1.conf\ test_transport_api_reliability_wlan_peer2.conf\ test_transport_api_bidirectional_connect_peer1.conf\ test_transport_api_bidirectional_connect_peer2.conf\ test_transport_api_tcp_nat_peer1.conf\ test_transport_api_tcp_nat_peer2.conf\ test_transport_api_tcp_peer1.conf\ test_transport_api_tcp_peer2.conf\ test_transport_api_udp_nat_peer1.conf\ test_transport_api_udp_nat_peer2.conf\ test_transport_api_udp_peer1.conf\ test_transport_api_udp_peer2.conf\ test_transport_api_timeout_udp_peer1.conf\ test_transport_api_timeout_udp_peer2.conf\ test_transport_api_unix_peer1.conf\ test_transport_api_unix_peer2.conf\ test_transport_api_timeout_unix_peer1.conf\ test_transport_api_timeout_unix_peer2.conf\ test_transport_api_unreliability_udp_peer1.conf\ test_transport_api_unreliability_udp_peer2.conf\ test_transport_api_unreliability_unix_peer1.conf\ test_transport_api_unreliability_unix_peer2.conf\ test_transport_api_unreliability_wlan_peer1.conf\ test_transport_api_unreliability_wlan_peer2.conf\ test_transport_api_wlan_peer1.conf\ test_transport_api_wlan_peer2.conf\ test_transport_defaults.conf\ test_transport_startonly.conf\ test_transport_api_disconnect_tcp_peer1.conf\ test_transport_api_disconnect_tcp_peer2.conf\ test_transport_api_http_nat_peer1.conf\ test_transport_api_http_nat_peer2.conf\ test_transport_api_https_nat_peer1.conf\ test_transport_api_https_nat_peer2.conf\ test_transport_api_reliability_http_nat_peer1.conf\ test_transport_api_reliability_http_nat_peer2.conf\ test_transport_api_reliability_https_nat_peer1.conf\ test_transport_api_reliability_https_nat_peer2.conf\ test_transport_api_timeout_http_peer1.conf\ test_transport_api_timeout_http_peer2.conf\ test_transport_api_timeout_https_peer1.conf\ test_transport_api_timeout_https_peer2.conf\ test_transport_api_unreliability_constant_udp_peer1.conf\ test_transport_api_unreliability_constant_udp_peer2.conf all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/transport/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/transport/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): transport.conf: $(top_builddir)/config.status $(srcdir)/transport.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ } uninstall-pluginLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ done clean-pluginLTLIBRARIES: -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunet_plugin_transport_http.la: $(libgnunet_plugin_transport_http_la_OBJECTS) $(libgnunet_plugin_transport_http_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_transport_http_la_LINK) $(am_libgnunet_plugin_transport_http_la_rpath) $(libgnunet_plugin_transport_http_la_OBJECTS) $(libgnunet_plugin_transport_http_la_LIBADD) $(LIBS) libgnunet_plugin_transport_https.la: $(libgnunet_plugin_transport_https_la_OBJECTS) $(libgnunet_plugin_transport_https_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_transport_https_la_LINK) $(am_libgnunet_plugin_transport_https_la_rpath) $(libgnunet_plugin_transport_https_la_OBJECTS) $(libgnunet_plugin_transport_https_la_LIBADD) $(LIBS) libgnunet_plugin_transport_tcp.la: $(libgnunet_plugin_transport_tcp_la_OBJECTS) $(libgnunet_plugin_transport_tcp_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_transport_tcp_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_transport_tcp_la_OBJECTS) $(libgnunet_plugin_transport_tcp_la_LIBADD) $(LIBS) libgnunet_plugin_transport_template.la: $(libgnunet_plugin_transport_template_la_OBJECTS) $(libgnunet_plugin_transport_template_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_transport_template_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_transport_template_la_OBJECTS) $(libgnunet_plugin_transport_template_la_LIBADD) $(LIBS) libgnunet_plugin_transport_udp.la: $(libgnunet_plugin_transport_udp_la_OBJECTS) $(libgnunet_plugin_transport_udp_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_transport_udp_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_transport_udp_la_OBJECTS) $(libgnunet_plugin_transport_udp_la_LIBADD) $(LIBS) libgnunet_plugin_transport_unix.la: $(libgnunet_plugin_transport_unix_la_OBJECTS) $(libgnunet_plugin_transport_unix_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_transport_unix_la_LINK) $(am_libgnunet_plugin_transport_unix_la_rpath) $(libgnunet_plugin_transport_unix_la_OBJECTS) $(libgnunet_plugin_transport_unix_la_LIBADD) $(LIBS) libgnunet_plugin_transport_wlan.la: $(libgnunet_plugin_transport_wlan_la_OBJECTS) $(libgnunet_plugin_transport_wlan_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_transport_wlan_la_LINK) $(am_libgnunet_plugin_transport_wlan_la_rpath) $(libgnunet_plugin_transport_wlan_la_OBJECTS) $(libgnunet_plugin_transport_wlan_la_LIBADD) $(LIBS) libgnunettransport.la: $(libgnunettransport_la_OBJECTS) $(libgnunettransport_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunettransport_la_LINK) -rpath $(libdir) $(libgnunettransport_la_OBJECTS) $(libgnunettransport_la_LIBADD) $(LIBS) libgnunettransporttesting.la: $(libgnunettransporttesting_la_OBJECTS) $(libgnunettransporttesting_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunettransporttesting_la_LINK) -rpath $(libdir) $(libgnunettransporttesting_la_OBJECTS) $(libgnunettransporttesting_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-helper-transport-wlan$(EXEEXT): $(gnunet_helper_transport_wlan_OBJECTS) $(gnunet_helper_transport_wlan_DEPENDENCIES) @rm -f gnunet-helper-transport-wlan$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_helper_transport_wlan_OBJECTS) $(gnunet_helper_transport_wlan_LDADD) $(LIBS) gnunet-helper-transport-wlan-dummy$(EXEEXT): $(gnunet_helper_transport_wlan_dummy_OBJECTS) $(gnunet_helper_transport_wlan_dummy_DEPENDENCIES) @rm -f gnunet-helper-transport-wlan-dummy$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_helper_transport_wlan_dummy_OBJECTS) $(gnunet_helper_transport_wlan_dummy_LDADD) $(LIBS) gnunet-service-transport$(EXEEXT): $(gnunet_service_transport_OBJECTS) $(gnunet_service_transport_DEPENDENCIES) @rm -f gnunet-service-transport$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_service_transport_OBJECTS) $(gnunet_service_transport_LDADD) $(LIBS) gnunet-transport$(EXEEXT): $(gnunet_transport_OBJECTS) $(gnunet_transport_DEPENDENCIES) @rm -f gnunet-transport$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_transport_OBJECTS) $(gnunet_transport_LDADD) $(LIBS) gnunet-transport-certificate-creation$(EXEEXT): $(gnunet_transport_certificate_creation_OBJECTS) $(gnunet_transport_certificate_creation_DEPENDENCIES) @rm -f gnunet-transport-certificate-creation$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_transport_certificate_creation_OBJECTS) $(gnunet_transport_certificate_creation_LDADD) $(LIBS) gnunet-transport-wlan-sender$(EXEEXT): $(gnunet_transport_wlan_sender_OBJECTS) $(gnunet_transport_wlan_sender_DEPENDENCIES) @rm -f gnunet-transport-wlan-sender$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_transport_wlan_sender_OBJECTS) $(gnunet_transport_wlan_sender_LDADD) $(LIBS) test_quota_compliance_http$(EXEEXT): $(test_quota_compliance_http_OBJECTS) $(test_quota_compliance_http_DEPENDENCIES) @rm -f test_quota_compliance_http$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_quota_compliance_http_OBJECTS) $(test_quota_compliance_http_LDADD) $(LIBS) test_quota_compliance_http_asymmetric$(EXEEXT): $(test_quota_compliance_http_asymmetric_OBJECTS) $(test_quota_compliance_http_asymmetric_DEPENDENCIES) @rm -f test_quota_compliance_http_asymmetric$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_quota_compliance_http_asymmetric_OBJECTS) $(test_quota_compliance_http_asymmetric_LDADD) $(LIBS) test_quota_compliance_https$(EXEEXT): $(test_quota_compliance_https_OBJECTS) $(test_quota_compliance_https_DEPENDENCIES) @rm -f test_quota_compliance_https$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_quota_compliance_https_OBJECTS) $(test_quota_compliance_https_LDADD) $(LIBS) test_quota_compliance_https_asymmetric$(EXEEXT): $(test_quota_compliance_https_asymmetric_OBJECTS) $(test_quota_compliance_https_asymmetric_DEPENDENCIES) @rm -f test_quota_compliance_https_asymmetric$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_quota_compliance_https_asymmetric_OBJECTS) $(test_quota_compliance_https_asymmetric_LDADD) $(LIBS) test_quota_compliance_tcp$(EXEEXT): $(test_quota_compliance_tcp_OBJECTS) $(test_quota_compliance_tcp_DEPENDENCIES) @rm -f test_quota_compliance_tcp$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_quota_compliance_tcp_OBJECTS) $(test_quota_compliance_tcp_LDADD) $(LIBS) test_quota_compliance_tcp_asymmetric$(EXEEXT): $(test_quota_compliance_tcp_asymmetric_OBJECTS) $(test_quota_compliance_tcp_asymmetric_DEPENDENCIES) @rm -f test_quota_compliance_tcp_asymmetric$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_quota_compliance_tcp_asymmetric_OBJECTS) $(test_quota_compliance_tcp_asymmetric_LDADD) $(LIBS) test_quota_compliance_udp$(EXEEXT): $(test_quota_compliance_udp_OBJECTS) $(test_quota_compliance_udp_DEPENDENCIES) @rm -f test_quota_compliance_udp$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_quota_compliance_udp_OBJECTS) $(test_quota_compliance_udp_LDADD) $(LIBS) test_quota_compliance_unix$(EXEEXT): $(test_quota_compliance_unix_OBJECTS) $(test_quota_compliance_unix_DEPENDENCIES) @rm -f test_quota_compliance_unix$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_quota_compliance_unix_OBJECTS) $(test_quota_compliance_unix_LDADD) $(LIBS) test_quota_compliance_unix_asymmetric$(EXEEXT): $(test_quota_compliance_unix_asymmetric_OBJECTS) $(test_quota_compliance_unix_asymmetric_DEPENDENCIES) @rm -f test_quota_compliance_unix_asymmetric$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_quota_compliance_unix_asymmetric_OBJECTS) $(test_quota_compliance_unix_asymmetric_LDADD) $(LIBS) test_transport_api_bidirectional_connect$(EXEEXT): $(test_transport_api_bidirectional_connect_OBJECTS) $(test_transport_api_bidirectional_connect_DEPENDENCIES) @rm -f test_transport_api_bidirectional_connect$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_bidirectional_connect_OBJECTS) $(test_transport_api_bidirectional_connect_LDADD) $(LIBS) test_transport_api_blacklisting$(EXEEXT): $(test_transport_api_blacklisting_OBJECTS) $(test_transport_api_blacklisting_DEPENDENCIES) @rm -f test_transport_api_blacklisting$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_blacklisting_OBJECTS) $(test_transport_api_blacklisting_LDADD) $(LIBS) test_transport_api_disconnect_tcp$(EXEEXT): $(test_transport_api_disconnect_tcp_OBJECTS) $(test_transport_api_disconnect_tcp_DEPENDENCIES) @rm -f test_transport_api_disconnect_tcp$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_disconnect_tcp_OBJECTS) $(test_transport_api_disconnect_tcp_LDADD) $(LIBS) test_transport_api_http$(EXEEXT): $(test_transport_api_http_OBJECTS) $(test_transport_api_http_DEPENDENCIES) @rm -f test_transport_api_http$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_http_OBJECTS) $(test_transport_api_http_LDADD) $(LIBS) test_transport_api_http_nat$(EXEEXT): $(test_transport_api_http_nat_OBJECTS) $(test_transport_api_http_nat_DEPENDENCIES) @rm -f test_transport_api_http_nat$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_http_nat_OBJECTS) $(test_transport_api_http_nat_LDADD) $(LIBS) test_transport_api_https$(EXEEXT): $(test_transport_api_https_OBJECTS) $(test_transport_api_https_DEPENDENCIES) @rm -f test_transport_api_https$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_https_OBJECTS) $(test_transport_api_https_LDADD) $(LIBS) test_transport_api_https_nat$(EXEEXT): $(test_transport_api_https_nat_OBJECTS) $(test_transport_api_https_nat_DEPENDENCIES) @rm -f test_transport_api_https_nat$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_https_nat_OBJECTS) $(test_transport_api_https_nat_LDADD) $(LIBS) test_transport_api_limited_sockets_tcp$(EXEEXT): $(test_transport_api_limited_sockets_tcp_OBJECTS) $(test_transport_api_limited_sockets_tcp_DEPENDENCIES) @rm -f test_transport_api_limited_sockets_tcp$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_limited_sockets_tcp_OBJECTS) $(test_transport_api_limited_sockets_tcp_LDADD) $(LIBS) test_transport_api_multi$(EXEEXT): $(test_transport_api_multi_OBJECTS) $(test_transport_api_multi_DEPENDENCIES) @rm -f test_transport_api_multi$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_multi_OBJECTS) $(test_transport_api_multi_LDADD) $(LIBS) test_transport_api_reliability_http$(EXEEXT): $(test_transport_api_reliability_http_OBJECTS) $(test_transport_api_reliability_http_DEPENDENCIES) @rm -f test_transport_api_reliability_http$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_reliability_http_OBJECTS) $(test_transport_api_reliability_http_LDADD) $(LIBS) test_transport_api_reliability_http_nat$(EXEEXT): $(test_transport_api_reliability_http_nat_OBJECTS) $(test_transport_api_reliability_http_nat_DEPENDENCIES) @rm -f test_transport_api_reliability_http_nat$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_reliability_http_nat_OBJECTS) $(test_transport_api_reliability_http_nat_LDADD) $(LIBS) test_transport_api_reliability_https$(EXEEXT): $(test_transport_api_reliability_https_OBJECTS) $(test_transport_api_reliability_https_DEPENDENCIES) @rm -f test_transport_api_reliability_https$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_reliability_https_OBJECTS) $(test_transport_api_reliability_https_LDADD) $(LIBS) test_transport_api_reliability_https_nat$(EXEEXT): $(test_transport_api_reliability_https_nat_OBJECTS) $(test_transport_api_reliability_https_nat_DEPENDENCIES) @rm -f test_transport_api_reliability_https_nat$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_reliability_https_nat_OBJECTS) $(test_transport_api_reliability_https_nat_LDADD) $(LIBS) test_transport_api_reliability_tcp$(EXEEXT): $(test_transport_api_reliability_tcp_OBJECTS) $(test_transport_api_reliability_tcp_DEPENDENCIES) @rm -f test_transport_api_reliability_tcp$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_reliability_tcp_OBJECTS) $(test_transport_api_reliability_tcp_LDADD) $(LIBS) test_transport_api_reliability_tcp_nat$(EXEEXT): $(test_transport_api_reliability_tcp_nat_OBJECTS) $(test_transport_api_reliability_tcp_nat_DEPENDENCIES) @rm -f test_transport_api_reliability_tcp_nat$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_reliability_tcp_nat_OBJECTS) $(test_transport_api_reliability_tcp_nat_LDADD) $(LIBS) test_transport_api_reliability_wlan$(EXEEXT): $(test_transport_api_reliability_wlan_OBJECTS) $(test_transport_api_reliability_wlan_DEPENDENCIES) @rm -f test_transport_api_reliability_wlan$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_reliability_wlan_OBJECTS) $(test_transport_api_reliability_wlan_LDADD) $(LIBS) test_transport_api_restart_1peer$(EXEEXT): $(test_transport_api_restart_1peer_OBJECTS) $(test_transport_api_restart_1peer_DEPENDENCIES) @rm -f test_transport_api_restart_1peer$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_restart_1peer_OBJECTS) $(test_transport_api_restart_1peer_LDADD) $(LIBS) test_transport_api_restart_2peers$(EXEEXT): $(test_transport_api_restart_2peers_OBJECTS) $(test_transport_api_restart_2peers_DEPENDENCIES) @rm -f test_transport_api_restart_2peers$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_restart_2peers_OBJECTS) $(test_transport_api_restart_2peers_LDADD) $(LIBS) test_transport_api_tcp$(EXEEXT): $(test_transport_api_tcp_OBJECTS) $(test_transport_api_tcp_DEPENDENCIES) @rm -f test_transport_api_tcp$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_tcp_OBJECTS) $(test_transport_api_tcp_LDADD) $(LIBS) test_transport_api_tcp_nat$(EXEEXT): $(test_transport_api_tcp_nat_OBJECTS) $(test_transport_api_tcp_nat_DEPENDENCIES) @rm -f test_transport_api_tcp_nat$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_tcp_nat_OBJECTS) $(test_transport_api_tcp_nat_LDADD) $(LIBS) test_transport_api_timeout_http$(EXEEXT): $(test_transport_api_timeout_http_OBJECTS) $(test_transport_api_timeout_http_DEPENDENCIES) @rm -f test_transport_api_timeout_http$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_timeout_http_OBJECTS) $(test_transport_api_timeout_http_LDADD) $(LIBS) test_transport_api_timeout_https$(EXEEXT): $(test_transport_api_timeout_https_OBJECTS) $(test_transport_api_timeout_https_DEPENDENCIES) @rm -f test_transport_api_timeout_https$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_timeout_https_OBJECTS) $(test_transport_api_timeout_https_LDADD) $(LIBS) test_transport_api_timeout_tcp$(EXEEXT): $(test_transport_api_timeout_tcp_OBJECTS) $(test_transport_api_timeout_tcp_DEPENDENCIES) @rm -f test_transport_api_timeout_tcp$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_timeout_tcp_OBJECTS) $(test_transport_api_timeout_tcp_LDADD) $(LIBS) test_transport_api_timeout_udp$(EXEEXT): $(test_transport_api_timeout_udp_OBJECTS) $(test_transport_api_timeout_udp_DEPENDENCIES) @rm -f test_transport_api_timeout_udp$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_timeout_udp_OBJECTS) $(test_transport_api_timeout_udp_LDADD) $(LIBS) test_transport_api_timeout_unix$(EXEEXT): $(test_transport_api_timeout_unix_OBJECTS) $(test_transport_api_timeout_unix_DEPENDENCIES) @rm -f test_transport_api_timeout_unix$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_timeout_unix_OBJECTS) $(test_transport_api_timeout_unix_LDADD) $(LIBS) test_transport_api_udp$(EXEEXT): $(test_transport_api_udp_OBJECTS) $(test_transport_api_udp_DEPENDENCIES) @rm -f test_transport_api_udp$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_udp_OBJECTS) $(test_transport_api_udp_LDADD) $(LIBS) test_transport_api_udp_nat$(EXEEXT): $(test_transport_api_udp_nat_OBJECTS) $(test_transport_api_udp_nat_DEPENDENCIES) @rm -f test_transport_api_udp_nat$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_udp_nat_OBJECTS) $(test_transport_api_udp_nat_LDADD) $(LIBS) test_transport_api_unix$(EXEEXT): $(test_transport_api_unix_OBJECTS) $(test_transport_api_unix_DEPENDENCIES) @rm -f test_transport_api_unix$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_unix_OBJECTS) $(test_transport_api_unix_LDADD) $(LIBS) test_transport_api_unreliability_constant_udp$(EXEEXT): $(test_transport_api_unreliability_constant_udp_OBJECTS) $(test_transport_api_unreliability_constant_udp_DEPENDENCIES) @rm -f test_transport_api_unreliability_constant_udp$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_unreliability_constant_udp_OBJECTS) $(test_transport_api_unreliability_constant_udp_LDADD) $(LIBS) test_transport_api_unreliability_udp$(EXEEXT): $(test_transport_api_unreliability_udp_OBJECTS) $(test_transport_api_unreliability_udp_DEPENDENCIES) @rm -f test_transport_api_unreliability_udp$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_unreliability_udp_OBJECTS) $(test_transport_api_unreliability_udp_LDADD) $(LIBS) test_transport_api_unreliability_unix$(EXEEXT): $(test_transport_api_unreliability_unix_OBJECTS) $(test_transport_api_unreliability_unix_DEPENDENCIES) @rm -f test_transport_api_unreliability_unix$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_unreliability_unix_OBJECTS) $(test_transport_api_unreliability_unix_LDADD) $(LIBS) test_transport_api_unreliability_wlan$(EXEEXT): $(test_transport_api_unreliability_wlan_OBJECTS) $(test_transport_api_unreliability_wlan_DEPENDENCIES) @rm -f test_transport_api_unreliability_wlan$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_unreliability_wlan_OBJECTS) $(test_transport_api_unreliability_wlan_LDADD) $(LIBS) test_transport_api_wlan$(EXEEXT): $(test_transport_api_wlan_OBJECTS) $(test_transport_api_wlan_DEPENDENCIES) @rm -f test_transport_api_wlan$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_wlan_OBJECTS) $(test_transport_api_wlan_LDADD) $(LIBS) test_transport_startonly$(EXEEXT): $(test_transport_startonly_OBJECTS) $(test_transport_startonly_DEPENDENCIES) @rm -f test_transport_startonly$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_startonly_OBJECTS) $(test_transport_startonly_LDADD) $(LIBS) test_transport_testing$(EXEEXT): $(test_transport_testing_OBJECTS) $(test_transport_testing_DEPENDENCIES) @rm -f test_transport_testing$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_testing_OBJECTS) $(test_transport_testing_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-transport-wlan-dummy.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-transport-wlan.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-transport.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-transport_blacklist.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-transport_clients.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-transport_hello.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-transport_neighbours.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-transport_plugins.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-transport_validation.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-transport-certificate-creation.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-transport-wlan-sender.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-transport.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_client.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_server.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_client.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_server.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_transport_tcp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_transport_template.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_transport_udp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_transport_udp_broadcasting.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_transport_unix.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_transport_wlan.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_quota_compliance.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_bidirectional_connect.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_blacklisting.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_disconnect.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_limited_sockets.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_reliability.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_restart_1peer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_restart_2peers.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_timeout.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_unreliability.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_unreliability_constant.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_startonly.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_testing.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transport-testing.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transport_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transport_api_address_lookup.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transport_api_address_to_string.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transport_api_blacklist.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< libgnunet_plugin_transport_http_la-plugin_transport_http.lo: plugin_transport_http.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_http_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_http_la_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_transport_http_la-plugin_transport_http.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http.Tpo -c -o libgnunet_plugin_transport_http_la-plugin_transport_http.lo `test -f 'plugin_transport_http.c' || echo '$(srcdir)/'`plugin_transport_http.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http.Tpo $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_transport_http.c' object='libgnunet_plugin_transport_http_la-plugin_transport_http.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_http_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_http_la_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_transport_http_la-plugin_transport_http.lo `test -f 'plugin_transport_http.c' || echo '$(srcdir)/'`plugin_transport_http.c libgnunet_plugin_transport_http_la-plugin_transport_http_client.lo: plugin_transport_http_client.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_http_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_http_la_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_transport_http_la-plugin_transport_http_client.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_client.Tpo -c -o libgnunet_plugin_transport_http_la-plugin_transport_http_client.lo `test -f 'plugin_transport_http_client.c' || echo '$(srcdir)/'`plugin_transport_http_client.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_client.Tpo $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_client.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_transport_http_client.c' object='libgnunet_plugin_transport_http_la-plugin_transport_http_client.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_http_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_http_la_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_transport_http_la-plugin_transport_http_client.lo `test -f 'plugin_transport_http_client.c' || echo '$(srcdir)/'`plugin_transport_http_client.c libgnunet_plugin_transport_http_la-plugin_transport_http_server.lo: plugin_transport_http_server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_http_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_http_la_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_transport_http_la-plugin_transport_http_server.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_server.Tpo -c -o libgnunet_plugin_transport_http_la-plugin_transport_http_server.lo `test -f 'plugin_transport_http_server.c' || echo '$(srcdir)/'`plugin_transport_http_server.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_server.Tpo $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_server.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_transport_http_server.c' object='libgnunet_plugin_transport_http_la-plugin_transport_http_server.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_http_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_http_la_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_transport_http_la-plugin_transport_http_server.lo `test -f 'plugin_transport_http_server.c' || echo '$(srcdir)/'`plugin_transport_http_server.c libgnunet_plugin_transport_https_la-plugin_transport_http.lo: plugin_transport_http.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_https_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_https_la_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_transport_https_la-plugin_transport_http.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http.Tpo -c -o libgnunet_plugin_transport_https_la-plugin_transport_http.lo `test -f 'plugin_transport_http.c' || echo '$(srcdir)/'`plugin_transport_http.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http.Tpo $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_transport_http.c' object='libgnunet_plugin_transport_https_la-plugin_transport_http.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_https_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_https_la_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_transport_https_la-plugin_transport_http.lo `test -f 'plugin_transport_http.c' || echo '$(srcdir)/'`plugin_transport_http.c libgnunet_plugin_transport_https_la-plugin_transport_http_client.lo: plugin_transport_http_client.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_https_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_https_la_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_transport_https_la-plugin_transport_http_client.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_client.Tpo -c -o libgnunet_plugin_transport_https_la-plugin_transport_http_client.lo `test -f 'plugin_transport_http_client.c' || echo '$(srcdir)/'`plugin_transport_http_client.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_client.Tpo $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_client.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_transport_http_client.c' object='libgnunet_plugin_transport_https_la-plugin_transport_http_client.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_https_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_https_la_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_transport_https_la-plugin_transport_http_client.lo `test -f 'plugin_transport_http_client.c' || echo '$(srcdir)/'`plugin_transport_http_client.c libgnunet_plugin_transport_https_la-plugin_transport_http_server.lo: plugin_transport_http_server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_https_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_https_la_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_transport_https_la-plugin_transport_http_server.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_server.Tpo -c -o libgnunet_plugin_transport_https_la-plugin_transport_http_server.lo `test -f 'plugin_transport_http_server.c' || echo '$(srcdir)/'`plugin_transport_http_server.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_server.Tpo $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_server.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_transport_http_server.c' object='libgnunet_plugin_transport_https_la-plugin_transport_http_server.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_https_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_https_la_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_transport_https_la-plugin_transport_http_server.lo `test -f 'plugin_transport_http_server.c' || echo '$(srcdir)/'`plugin_transport_http_server.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgcfgDATA: $(pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool clean-noinstPROGRAMS \ clean-pluginLTLIBRARIES mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgcfgDATA install-pluginLTLIBRARIES install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-exec-hook install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES .MAKE: check-am install-am install-exec-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool clean-noinstPROGRAMS \ clean-pluginLTLIBRARIES ctags distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-binPROGRAMS install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-exec-hook \ install-html install-html-am install-info install-info-am \ install-libLTLIBRARIES install-man install-pdf install-pdf-am \ install-pkgcfgDATA install-pluginLTLIBRARIES install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ uninstall-am uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES @LINUX_TRUE@install-exec-hook: @LINUX_TRUE@ $(SUDO_BINARY) chown root:root $(bindir)/gnunet-helper-transport-wlan || true @LINUX_TRUE@ $(SUDO_BINARY) chmod u+s $(bindir)/gnunet-helper-transport-wlan || true @LINUX_FALSE@install-exec-hook: # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/transport/test_transport_api_reliability_tcp_nat_peer1.conf0000644000175000017500000000124511750306133024560 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-reliability-tcp-nat-p1/ DEFAULTCONFIG = test_transport_api_reliability_tcp_nat_peer1.conf [nat] BEHIND_NAT = YES ENABLE_NAT_SERVER = YES DISABLEV6 = YES [transport-tcp] PORT = 0 TIMEOUT = 5 s [arm] PORT = 1204 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12023 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12022 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12021 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 29542 PLUGINS = tcp UNIXPATH = /tmp/gnunet-p1-service-transport.sock gnunet-0.9.3/src/transport/gnunet-transport-certificate-creation.c0000644000175000017500000000502411760502551022352 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/gnunet-transport-certificate-creation.c * @brief create certificate for HTTPS transport * @author LRN * */ #include "platform.h" #include "gnunet_disk_lib.h" #include "gnunet_os_lib.h" static void removecerts (const char *file1, const char *file2) { if (GNUNET_DISK_file_test (file1) == GNUNET_YES) { CHMOD (file1, S_IWUSR | S_IRUSR); REMOVE (file1); } if (GNUNET_DISK_file_test (file2) == GNUNET_YES) { CHMOD (file2, S_IWUSR | S_IRUSR); REMOVE (file2); } } int main (int argc, char **argv) { struct GNUNET_OS_Process *openssl; if (argc != 3) return 1; removecerts (argv[1], argv[2]); close (2); /* eliminate stderr */ /* Create RSA Private Key */ /* openssl genrsa -out $1 1024 2> /dev/null */ openssl = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "openssl", "openssl", "genrsa", "-out", argv[1], "1024", NULL); if (openssl == NULL) return 2; GNUNET_assert (GNUNET_OS_process_wait (openssl) == GNUNET_OK); GNUNET_OS_process_destroy (openssl); /* Create a self-signed certificate in batch mode using rsa key */ /* openssl req -batch -days 365 -out $2 -new -x509 -key $1 2> /dev/null */ openssl = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "openssl", "openssl", "req", "-batch", "-days", "365", "-out", argv[2], "-new", "-x509", "-key", argv[1], NULL); if (openssl == NULL) return 3; GNUNET_assert (GNUNET_OS_process_wait (openssl) == GNUNET_OK); GNUNET_OS_process_destroy (openssl); CHMOD (argv[1], S_IRUSR); CHMOD (argv[2], S_IRUSR); return 0; } /* end of gnunet-transport-certificate-creation.c */ gnunet-0.9.3/src/transport/test_quota_compliance_udp_peer2.conf0000644000175000017500000000116711647100177021776 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test_quota_compliance_peer2 DEFAULTCONFIG = test_quota_compliance_udp_peer2.conf [transport-udp] PORT = 3368 MAX_BPS = 50000000 [arm] PORT = 3087 UNIXPATH = /tmp/test_quota_compliance_udp_arm_peer2.sock [statistics] PORT = 3088 UNIXPATH = /tmp/test_quota_compliance_udp_statistics_peer2.sock [resolver] PORT = 3089 UNIXPATH = /tmp/test_quota_compliance_udp_resolver_peer2.sock [peerinfo] PORT = 3090 UNIXPATH = /tmp/test_quota_compliance_udp_peerinfo_peer2.sock [transport] PORT = 3091 PLUGINS = udp UNIXPATH = /tmp/test_quota_compliance_udp_transport_peer2.sock gnunet-0.9.3/src/transport/test_transport_api_limited_sockets_tcp_peer2.conf0000644000175000017500000000110511750306133024563 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-tcp-p2/ DEFAULTCONFIG = test_transport_api_tcp_peer2.conf [transport-tcp] PORT = 0 TIMEOUT = 5 s [arm] PORT = 12014 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12013 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12012 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12011 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12010 PLUGINS = tcp UNIXPATH = /tmp/gnunet-p2-service-transport.sock gnunet-0.9.3/src/transport/test_transport_api_reliability.c0000644000175000017500000003405311762202311021250 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/test_transport_api_reliability.c * @brief base test case for transport implementations * * This test case serves as a base for tcp and http * transport test cases to check that the transports * achieve reliable message delivery. */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_hello_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_server_lib.h" #include "gnunet_transport_service.h" #include "gauger.h" #include "transport.h" #include "transport-testing.h" #define VERBOSE GNUNET_NO #define VERBOSE_ARM GNUNET_NO #define START_ARM GNUNET_YES /** * Testcase timeout */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) /** * How long until we give up on transmitting the message? */ #define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) static char *test_source; static char *test_plugin; static char *test_name; static int ok; static GNUNET_SCHEDULER_TaskIdentifier die_task; struct PeerContext *p1; struct PeerContext *p2; struct PeerContext *sender; struct PeerContext *receiver; struct GNUNET_TRANSPORT_TransmitHandle *th; char *cfg_file_p1; char *cfg_file_p2; struct GNUNET_TRANSPORT_TESTING_handle *tth; static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; /* * Testcase specific declarations */ /** * Note that this value must not significantly exceed * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise * messages may be dropped even for a reliable transport. */ #define TOTAL_MSGS (1024 * 2) #define MTYPE 12345 GNUNET_NETWORK_STRUCT_BEGIN struct TestMessage { struct GNUNET_MessageHeader header; uint32_t num; }; GNUNET_NETWORK_STRUCT_END static int msg_scheduled; static int msg_sent; static int msg_recv_expected; static int msg_recv; static int test_failed; static int test_connected; static unsigned long long total_bytes; static struct GNUNET_TIME_Absolute start_time; /* * END Testcase specific declarations */ #if VERBOSE #define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) #else #define OKPP do { ok++; } while (0) #endif static void end () { unsigned long long delta; char *value_name; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value; FPRINTF (stderr, "\nThroughput was %llu kb/s\n", total_bytes * 1000 / 1024 / delta); GNUNET_asprintf (&value_name, "reliable_%s", test_plugin); GAUGER ("TRANSPORT", value_name, (int) (total_bytes * 1000 / 1024 / delta), "kb/s"); GNUNET_free (value_name); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; if (cc != NULL) GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); GNUNET_TRANSPORT_TESTING_done (tth); } static void end_badly () { die_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); if (test_connected == GNUNET_YES) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers got connected\n"); else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers got NOT connected\n"); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; if (cc != NULL) GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); if (p1 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); if (p2 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); GNUNET_TRANSPORT_TESTING_done (tth); ok = GNUNET_SYSERR; } static unsigned int get_size (unsigned int iter) { unsigned int ret; ret = (iter * iter * iter); return sizeof (struct TestMessage) + (ret % 60000); } static void notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { static int n; unsigned int s; char cbuf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; const struct TestMessage *hdr; hdr = (const struct TestMessage *) message; s = get_size (n); if (MTYPE != ntohs (message->type)) return; msg_recv_expected = n; msg_recv = ntohl (hdr->num); if (ntohs (message->size) != (s)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected message %u of size %u, got %u bytes of message %u\n", n, s, ntohs (message->size), ntohl (hdr->num)); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); test_failed = GNUNET_YES; die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } if (ntohl (hdr->num) != n) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected message %u of size %u, got %u bytes of message %u\n", n, s, ntohs (message->size), ntohl (hdr->num)); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); test_failed = GNUNET_YES; die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } memset (cbuf, n, s - sizeof (struct TestMessage)); if (0 != memcmp (cbuf, &hdr[1], s - sizeof (struct TestMessage))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected message %u with bits %u, but body did not match at position %u\n", n, (unsigned char) n); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); test_failed = GNUNET_YES; die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } #if VERBOSE if (ntohl (hdr->num) % 5000 == 0) { struct PeerContext *p = cls; char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') got message %u of size %u from peer (`%s')\n", p->no, ps, ntohl (hdr->num), ntohs (message->size), GNUNET_i2s (peer)); GNUNET_free (ps); } #endif n++; if (0 == (n % (TOTAL_MSGS / 100))) { FPRINTF (stderr, "%s", "."); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); } if (n == TOTAL_MSGS) { ok = 0; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\nAll messages received\n"); end (); } } static size_t notify_ready (void *cls, size_t size, void *buf) { static int n; char *cbuf = buf; struct TestMessage hdr; unsigned int s; unsigned int ret; th = NULL; if (buf == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout occurred while waiting for transmit_ready for message %u of %u\n", msg_scheduled, TOTAL_MSGS); if (GNUNET_SCHEDULER_NO_TASK != die_task) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); ok = 42; return 0; } ret = 0; s = get_size (n); GNUNET_assert (size >= s); GNUNET_assert (buf != NULL); cbuf = buf; do { hdr.header.size = htons (s); hdr.header.type = htons (MTYPE); hdr.num = htonl (n); msg_sent = n; memcpy (&cbuf[ret], &hdr, sizeof (struct TestMessage)); ret += sizeof (struct TestMessage); memset (&cbuf[ret], n, s - sizeof (struct TestMessage)); ret += s - sizeof (struct TestMessage); #if VERBOSE if (n % 5000 == 0) { char *receiver_s = GNUNET_strdup (GNUNET_i2s (&receiver->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message of size %u from peer %u (`%4s') -> peer %u (`%s') !\n", n, sender->no, GNUNET_i2s (&sender->id), receiver->no, receiver_s); GNUNET_free (receiver_s); } #endif n++; s = get_size (n); if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16)) break; /* sometimes pack buffer full, sometimes not */ } while (size - ret >= s); if (n < TOTAL_MSGS) { if (th == NULL) th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, s, 0, TIMEOUT_TRANSMIT, ¬ify_ready, NULL); msg_scheduled = n; } if (n % 5000 == 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Returning total message block of size %u\n", ret); } total_bytes += ret; if (n == TOTAL_MSGS) { FPRINTF (stderr, "%s", "\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All messages sent\n"); } return ret; } static void notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { struct PeerContext *p = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') connected to us!\n", p->no, GNUNET_i2s (peer)); } static void notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { struct PeerContext *p = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') disconnected!\n", p->no, GNUNET_i2s (peer)); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; } static void sendtask () { start_time = GNUNET_TIME_absolute_get (); th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, get_size (0), 0, TIMEOUT_TRANSMIT, ¬ify_ready, NULL); } static void testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) { char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n", p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id)); GNUNET_free (p1_c); test_connected = GNUNET_YES; cc = NULL; GNUNET_SCHEDULER_add_now (&sendtask, NULL); } void start_cb (struct PeerContext *p, void *cls) { static int started; started++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, GNUNET_i2s (&p->id)); if (started != 2) return; test_connected = GNUNET_NO; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u: `%s' using configuration file `%s'\n", p1->no, GNUNET_i2s (&p1->id), cfg_file_p1); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u: `%s' using configuration file `%s'\n", p2->no, GNUNET_i2s (&p2->id), cfg_file_p2); sender = p2; receiver = p1; char *sender_c = GNUNET_strdup (GNUNET_i2s (&sender->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test triest to send from %u (%s) -> peer %u (%s)\n", sender->no, sender_c, receiver->no, GNUNET_i2s (&receiver->id)); GNUNET_free (sender_c); cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); if ((p1 == NULL) || (p2 == NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } } static int check () { static char *argv[] = { "test_transport", "-c", "test_transport_api_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; #if WRITECONFIG setTransportOptions ("test_transport_api_data.conf"); #endif ok = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name, "nohelp", options, &run, &ok); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); GNUNET_log_setup (test_name, #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source); GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source, &test_plugin); tth = GNUNET_TRANSPORT_TESTING_init (); GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1); GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2); ret = check (); GNUNET_free (cfg_file_p1); GNUNET_free (cfg_file_p2); GNUNET_free (test_source); GNUNET_free (test_plugin); GNUNET_free (test_name); return ret; } /* end of test_transport_api_reliability.c */ gnunet-0.9.3/src/transport/test_transport_api_restart_2peers.c0000644000175000017500000003033711761760651021723 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/test_transport_api_restart_2peers.c * @brief base test case for transport implementations * * This test case starts 2 peers, connects and exchanges a message * boths peer are restarted and tested if peers reconnect * C code apparently. */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_hello_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_transport_service.h" #include "transport.h" #include "transport-testing.h" #define START_ARM GNUNET_YES /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 90) /** * How long until we give up on transmitting the message? */ #define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) #define MTYPE 12345 static char *test_name; static int ok; static GNUNET_SCHEDULER_TaskIdentifier die_task; static GNUNET_SCHEDULER_TaskIdentifier send_task; static GNUNET_SCHEDULER_TaskIdentifier reconnect_task; static struct PeerContext *p1; static struct PeerContext *p2; static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; static struct GNUNET_TRANSPORT_TransmitHandle *th; static struct GNUNET_TRANSPORT_TESTING_handle *tth; static char *cfg_file_p1; static char *cfg_file_p2; static int restarted; static void end () { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); if (send_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (send_task); send_task = GNUNET_SCHEDULER_NO_TASK; if (reconnect_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (reconnect_task); reconnect_task = GNUNET_SCHEDULER_NO_TASK; if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); } static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { die_task = GNUNET_SCHEDULER_NO_TASK; if (restarted == GNUNET_YES) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peer was restarted, but communication did not resume\n"); if (restarted == GNUNET_NO) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peer was NOT (even) restarted\n"); if (reconnect_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (reconnect_task); reconnect_task = GNUNET_SCHEDULER_NO_TASK; if (send_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (send_task); send_task = GNUNET_SCHEDULER_NO_TASK; if (cc != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n")); GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); cc = NULL; } if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; if (p1 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); if (p2 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); ok = GNUNET_SYSERR; } static void reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerContext *p = cls; reconnect_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_TRANSPORT_try_connect (p1->th, &p2->id); reconnect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect, p); } static void restart_cb (struct PeerContext *p, void *cls) { static int c; c++; if (c != 2) return; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Restarted peer %u (`%4s'), issuing reconnect\n", p->no, GNUNET_i2s (&p->id)); reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, p); } static void restart (struct PeerContext *p, char *cfg_file) { GNUNET_assert (p != NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Restarting peer %u (`%4s')\n", p->no, GNUNET_i2s (&p->id)); GNUNET_TRANSPORT_TESTING_restart_peer (tth, p, cfg_file, &restart_cb, p); } static void notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { struct PeerContext *p = cls; struct PeerContext *t = NULL; if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) t = p1; if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) t = p2; GNUNET_assert (t != NULL); char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') received message of type %d and size %u size from peer %u (`%4s')!\n", p->no, ps, ntohs (message->type), ntohs (message->size), t->no, GNUNET_i2s (&t->id)); GNUNET_free (ps); if ((MTYPE == ntohs (message->type)) && (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size))) { if (restarted == GNUNET_NO) { restarted = GNUNET_YES; restart (p1, cfg_file_p1); restart (p2, cfg_file_p2); return; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Restarted peers connected, stopping test...\n"); ok = 0; end (); } } else { GNUNET_break (0); ok = 1; if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); } } static size_t notify_ready (void *cls, size_t size, void *buf) { struct PeerContext *p = cls; struct GNUNET_MessageHeader *hdr; th = NULL; if (buf == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout occurred while waiting for transmit_ready\n"); if (GNUNET_SCHEDULER_NO_TASK != die_task) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); ok = 42; return 0; } GNUNET_assert (size >= 256); if (buf != NULL) { hdr = buf; hdr->size = htons (sizeof (struct GNUNET_MessageHeader)); hdr->type = htons (MTYPE); } char *ps = GNUNET_strdup (GNUNET_i2s (&p2->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') sending message with type %u and size %u bytes to peer %u (`%4s')\n", p2->no, ps, ntohs (hdr->type), ntohs (hdr->size), p->no, GNUNET_i2s (&p->id)); GNUNET_free (ps); return sizeof (struct GNUNET_MessageHeader); } static void sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { send_task = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; char *receiver_s = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message from peer %u (`%4s') -> peer %u (`%s') !\n", p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s); GNUNET_free (receiver_s); th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, 256, 0, TIMEOUT_TRANSMIT, ¬ify_ready, p1); } static void notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { static int c; c++; struct PeerContext *p = cls; struct PeerContext *t = NULL; if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) t = p1; if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) t = p2; GNUNET_assert (t != NULL); char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s'): peer %u (`%s') connected to me!\n", p->no, ps, t->no, GNUNET_i2s (peer)); GNUNET_free (ps); if ((restarted == GNUNET_YES) && (c == 4)) { send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL); } } static void notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { struct PeerContext *p = cls; char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s'): peer (`%s') disconnected from me!\n", p->no, ps, GNUNET_i2s (peer)); GNUNET_free (ps); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; if (GNUNET_SCHEDULER_NO_TASK != send_task) GNUNET_SCHEDULER_cancel (send_task); send_task = GNUNET_SCHEDULER_NO_TASK; } static void testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) { cc = NULL; char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n", p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id)); GNUNET_free (p1_c); send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL); } static void start_cb (struct PeerContext *p, void *cls) { static int started; started++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, GNUNET_i2s (&p->id)); if (started != 2) return; char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n", p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id)); GNUNET_free (sender_c); cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); if ((p1 == NULL) || (p2 == NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } } static int check () { static char *const argv[] = { "test-transport-api", "-c", "test_transport_api_data.conf", NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; #if WRITECONFIG setTransportOptions ("test_transport_api_data.conf"); #endif send_task = GNUNET_SCHEDULER_NO_TASK; ok = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name, "nohelp", options, &run, NULL); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); GNUNET_log_setup (test_name, "WARNING", NULL); tth = GNUNET_TRANSPORT_TESTING_init (); GNUNET_asprintf (&cfg_file_p1, "test_transport_api_tcp_peer1.conf"); GNUNET_asprintf (&cfg_file_p2, "test_transport_api_tcp_peer2.conf"); ret = check (); GNUNET_free (cfg_file_p1); GNUNET_free (cfg_file_p2); GNUNET_free (test_name); GNUNET_TRANSPORT_TESTING_done (tth); return ret; } /* end of test_transport_api_restart_2peers.c */ gnunet-0.9.3/src/transport/test_quota_compliance_http_peer2.conf0000644000175000017500000000115411661530125022155 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test_quota_compliance_peer2 DEFAULTCONFIG = test_quota_compliance_http_peer2.conf [transport-http] PORT = 3010 [arm] PORT = 3015 UNIXPATH = /tmp/test_quota_compliance_http_arm_peer2.sock [statistics] PORT = 3014 UNIXPATH = /tmp/test_quota_compliance_http_statistics_peer2.sock [resolver] PORT = 3013 UNIXPATH = /tmp/test_quota_compliance_http_resolver_peer2.sock [peerinfo] PORT = 3012 UNIXPATH = /tmp/test_quota_compliance_http_peerinfo_peer2.sock [transport] PORT = 3011 PLUGINS = http UNIXPATH = /tmp/test_quota_compliance_http_transport_peer2.sock gnunet-0.9.3/src/transport/test_transport_api_reliability_wlan_peer1.conf0000644000175000017500000000104411665472561024104 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-wlan-p1/ DEFAULTCONFIG = test_transport_api_wlan_peer1.conf [transport-wlan] TESTMODE = 1 [arm] PORT = 12164 UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12163 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12162 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12161 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12160 PLUGINS = wlan UNIXPATH = /tmp/gnunet-p1-service-transport.sock gnunet-0.9.3/src/transport/test_transport_api_disconnect.c0000644000175000017500000002627111760502551021102 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/test_transport_api_disconnect.c * @brief base test case for transport implementations * * This test case tests disconnect notifications in peer shutdown */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_hello_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_transport_service.h" #include "transport.h" #include "transport-testing.h" #define VERBOSE GNUNET_NO #define VERBOSE_ARM GNUNET_NO #define START_ARM GNUNET_YES /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) /** * How long until we give up on transmitting the message? */ #define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) #define MTYPE 12345 static char *test_source; static char *test_plugin; static char *test_name; static int ok; static GNUNET_SCHEDULER_TaskIdentifier die_task; static GNUNET_SCHEDULER_TaskIdentifier send_task; struct PeerContext *p1; struct PeerContext *p2; static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; struct GNUNET_TRANSPORT_TransmitHandle *th; struct GNUNET_TRANSPORT_TESTING_handle *tth; int shutdown_; char *cfg_file_p1; char *cfg_file_p2; #if VERBOSE #define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) #else #define OKPP do { ok++; } while (0) #endif static void end () { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); if (send_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (send_task); send_task = GNUNET_SCHEDULER_NO_TASK; } if (die_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; } if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; if (p1 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); p1 = NULL; if (p2 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); p2 = NULL; /* success */ ok = 0; } static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { die_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); if (cc != NULL) { GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); cc = NULL; } if (send_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (send_task); send_task = GNUNET_SCHEDULER_NO_TASK; } if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; if (p1 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); if (p2 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); ok = GNUNET_SYSERR; } static void notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { struct PeerContext *p = cls; char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s'): peer (`%s') disconnected from me!\n", p->no, ps, GNUNET_i2s (peer)); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; if (shutdown_ == GNUNET_YES) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Complete, shutting down...\n"); GNUNET_SCHEDULER_add_now (&end, NULL); } } static void stop_peer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; struct PeerContext *p = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutting down peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id)); shutdown_ = GNUNET_YES; GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); p2 = NULL; GNUNET_assert (p2 == NULL); } static void notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { struct PeerContext *p = cls; struct PeerContext *t = NULL; if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) t = p1; if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) t = p2; GNUNET_assert (t != NULL); char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') received message of type %d and size %u size from peer %u (`%4s')!\n", p->no, ps, ntohs (message->type), ntohs (message->size), t->no, GNUNET_i2s (&t->id)); if ((MTYPE == ntohs (message->type)) && (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size))) { ok = 1; GNUNET_SCHEDULER_add_now (stop_peer, p2); return; } } static size_t notify_ready (void *cls, size_t size, void *buf) { struct PeerContext *p = cls; struct GNUNET_MessageHeader *hdr; th = NULL; if (buf == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout occurred while waiting for transmit_ready\n"); if (GNUNET_SCHEDULER_NO_TASK != die_task) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); ok = 42; return 0; } GNUNET_assert (size >= 256); if (buf != NULL) { hdr = buf; hdr->size = htons (sizeof (struct GNUNET_MessageHeader)); hdr->type = htons (MTYPE); } char *ps = GNUNET_strdup (GNUNET_i2s (&p2->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') sending message with type %u and size %u bytes to peer %u (`%4s')\n", p2->no, ps, ntohs (hdr->type), ntohs (hdr->size), p->no, GNUNET_i2s (&p->id)); GNUNET_free (ps); return sizeof (struct GNUNET_MessageHeader); } static void sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { send_task = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; char *receiver_s = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message from peer %u (`%4s') -> peer %u (`%s') !\n", p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s); GNUNET_free (receiver_s); th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, 256, 0, TIMEOUT_TRANSMIT, ¬ify_ready, p1); } static void notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { static int c; c++; struct PeerContext *p = cls; struct PeerContext *t = NULL; if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) t = p1; if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) t = p2; GNUNET_assert (t != NULL); char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s'): peer %u (`%s') connected to me!\n", p->no, ps, t->no, GNUNET_i2s (peer)); GNUNET_free (ps); } static void testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) { cc = NULL; char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n", p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id)); GNUNET_free (p1_c); send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL); } void start_cb (struct PeerContext *p, void *cls) { static int started; started++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, GNUNET_i2s (&p->id)); if (started != 2) return; char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n", p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id)); cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); if ((p1 == NULL) || (p2 == NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } } static int check () { static char *const argv[] = { "test-transport-api", "-c", "test_transport_api_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; #if WRITECONFIG setTransportOptions ("test_transport_api_data.conf"); #endif send_task = GNUNET_SCHEDULER_NO_TASK; ok = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name, "nohelp", options, &run, &ok); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); GNUNET_log_setup (test_name, #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source); GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source, &test_plugin); tth = GNUNET_TRANSPORT_TESTING_init (); GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1); GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2); ret = check (); GNUNET_free (cfg_file_p1); GNUNET_free (cfg_file_p2); GNUNET_free (test_source); GNUNET_free (test_plugin); GNUNET_free (test_name); GNUNET_TRANSPORT_TESTING_done (tth); return ret; } /* end of test_transport_api.c */ gnunet-0.9.3/src/transport/test_quota_compliance_http_peer1.conf0000644000175000017500000000115411661530125022154 00000000000000@INLINE@ template_cfg_peer1.conf [PATHS] SERVICEHOME = /tmp/test_quota_compliance_peer1 DEFAULTCONFIG = test_quota_compliance_http_peer1.conf [transport-http] PORT = 4010 [arm] PORT = 4015 UNIXPATH = /tmp/test_quota_compliance_http_arm_peer1.sock [statistics] PORT = 4014 UNIXPATH = /tmp/test_quota_compliance_http_statistics_peer1.sock [resolver] PORT = 4013 UNIXPATH = /tmp/test_quota_compliance_http_resolver_peer1.sock [peerinfo] PORT = 4012 UNIXPATH = /tmp/test_quota_compliance_http_peerinfo_peer1.sock [transport] PORT = 4011 PLUGINS = http UNIXPATH = /tmp/test_quota_compliance_http_transport_peer1.sock gnunet-0.9.3/src/transport/test_transport_api_bidirectional_connect.c0000644000175000017500000002547311760502551023275 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/test_transport_api_bidirectional_connect.c * @brief base test case for transport implementations * * Perform a 3-way handshake connection set up in both directions at * (almost) the same time */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_hello_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_transport_service.h" #include "transport.h" #include "transport-testing.h" /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) /** * How long until we give up on transmitting the message? */ #define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) #define MTYPE 12345 static char *test_source; static char *test_plugin; static char *test_name; static int ok; static GNUNET_SCHEDULER_TaskIdentifier die_task; static GNUNET_SCHEDULER_TaskIdentifier send_task; static struct PeerContext *p1; static struct PeerContext *p2; static GNUNET_TRANSPORT_TESTING_ConnectRequest cc1; static GNUNET_TRANSPORT_TESTING_ConnectRequest cc2; static struct GNUNET_TRANSPORT_TransmitHandle *th; static struct GNUNET_TRANSPORT_TESTING_handle *tth; static char *cfg_file_p1; static char *cfg_file_p2; static void end () { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); if (send_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (send_task); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); if (NULL != th) { GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; } GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); } static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { die_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); if (send_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (send_task); if (NULL != cc2) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n")); GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc2); cc2 = NULL; } if (NULL != cc1) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n")); GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc1); cc1 = NULL; } if (NULL != th) { GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; } if (p1 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); if (p2 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); ok = GNUNET_SYSERR; } static void notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { struct PeerContext *p = cls; struct PeerContext *t = NULL; if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) t = p1; if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) t = p2; GNUNET_assert (t != NULL); char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') received message of type %d and size %u size from peer %u (`%4s')!\n", p->no, ps, ntohs (message->type), ntohs (message->size), t->no, GNUNET_i2s (&t->id)); if ((MTYPE == ntohs (message->type)) && (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size))) { ok = 0; end (); } else { GNUNET_break (0); ok = 1; end (); } } static size_t notify_ready (void *cls, size_t size, void *buf) { struct PeerContext *p = cls; struct GNUNET_MessageHeader *hdr; th = NULL; if (buf == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout occurred while waiting for transmit_ready\n"); if (GNUNET_SCHEDULER_NO_TASK != die_task) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); ok = 42; return 0; } GNUNET_assert (size >= 256); if (buf != NULL) { hdr = buf; hdr->size = htons (sizeof (struct GNUNET_MessageHeader)); hdr->type = htons (MTYPE); } char *ps = GNUNET_strdup (GNUNET_i2s (&p2->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') sending message with type %u and size %u bytes to peer %u (`%4s')\n", p2->no, ps, ntohs (hdr->type), ntohs (hdr->size), p->no, GNUNET_i2s (&p->id)); GNUNET_free (ps); return sizeof (struct GNUNET_MessageHeader); } static void sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { send_task = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; char *receiver_s = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message from peer %u (`%4s') -> peer %u (`%s') !\n", p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s); GNUNET_free (receiver_s); th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, 256, 0, TIMEOUT_TRANSMIT, ¬ify_ready, p1); } static void notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { static int c; c++; struct PeerContext *p = cls; struct PeerContext *t = NULL; if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity))) t = p1; if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity))) t = p2; GNUNET_assert (t != NULL); char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s'): peer %u (`%s') connected to me!\n", p->no, ps, t->no, GNUNET_i2s (peer)); GNUNET_free (ps); } static void notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { struct PeerContext *p = cls; char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s'): peer (`%s') disconnected from me!\n", p->no, ps, GNUNET_i2s (peer)); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; } static void testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) { if (cls == cc1) { cc1 = NULL; GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc2); } if (cls == cc2) { cc2 = NULL; GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc1); } char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n", p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id)); GNUNET_free (p1_c); send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL); } static void start_cb (struct PeerContext *p, void *cls) { static int started; started++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, GNUNET_i2s (&p->id)); if (started != 2) return; char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test tries to connect peer %u (`%s') <-> peer %u (`%s')\n", p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id)); cc1 = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p2, p1, &testing_connect_cb, NULL); cc2 = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); if ((p1 == NULL) || (p2 == NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } } static int check () { static char *const argv[] = { "test-transport-api", "-c", "test_transport_api_data.conf", NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; #if WRITECONFIG setTransportOptions ("test_transport_api_data.conf"); #endif send_task = GNUNET_SCHEDULER_NO_TASK; ok = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name, "nohelp", options, &run, &ok); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); GNUNET_log_setup (test_name, "WARNING", NULL); GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source); GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source, &test_plugin); tth = GNUNET_TRANSPORT_TESTING_init (); GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1); GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2); ret = check (); GNUNET_free (cfg_file_p1); GNUNET_free (cfg_file_p2); GNUNET_free (test_source); GNUNET_free (test_plugin); GNUNET_free (test_name); GNUNET_TRANSPORT_TESTING_done (tth); return ret; } /* end of test_transport_api_bidirectional_connect.c */ gnunet-0.9.3/src/transport/test_transport_api_timeout_udp_peer2.conf0000644000175000017500000000110211721510741023066 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-udp-p2/ DEFAULTCONFIG = test_transport_api_udp_peer2.conf [transport-udp] PORT = 12050 BROADCAST = NO MAX_BPS = 50000000 [arm] PORT = 12055 UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12054 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12053 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12052 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12051 PLUGINS = udp UNIXPATH = /tmp/gnunet-p2-service-transport.sock gnunet-0.9.3/src/transport/gnunet-service-transport_clients.c0000644000175000017500000007426111760502551021460 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/gnunet-service-transport_clients.c * @brief plugin management API * @author Christian Grothoff */ #include "platform.h" #include "gnunet-service-transport_blacklist.h" #include "gnunet-service-transport_clients.h" #include "gnunet-service-transport_hello.h" #include "gnunet-service-transport_neighbours.h" #include "gnunet-service-transport_plugins.h" #include "gnunet-service-transport_validation.h" #include "gnunet-service-transport.h" #include "transport.h" /** * How many messages can we have pending for a given client process * before we start to drop incoming messages? We typically should * have only one client and so this would be the primary buffer for * messages, so the number should be chosen rather generously. * * The expectation here is that most of the time the queue is large * enough so that a drop is virtually never required. Note that * this value must be about as large as 'TOTAL_MSGS' in the * 'test_transport_api_reliability.c', otherwise that testcase may * fail. */ #define MAX_PENDING (128 * 1024) /** * Linked list of messages to be transmitted to the client. Each * entry is followed by the actual message. */ struct ClientMessageQueueEntry { /** * This is a doubly-linked list. */ struct ClientMessageQueueEntry *next; /** * This is a doubly-linked list. */ struct ClientMessageQueueEntry *prev; }; /** * Client connected to the transport service. */ struct TransportClient { /** * This is a doubly-linked list. */ struct TransportClient *next; /** * This is a doubly-linked list. */ struct TransportClient *prev; /** * Handle to the client. */ struct GNUNET_SERVER_Client *client; /** * Linked list of messages yet to be transmitted to * the client. */ struct ClientMessageQueueEntry *message_queue_head; /** * Tail of linked list of messages yet to be transmitted to the * client. */ struct ClientMessageQueueEntry *message_queue_tail; /** * Current transmit request handle. */ struct GNUNET_SERVER_TransmitHandle *th; /** * Length of the list of messages pending for this client. */ unsigned int message_count; /** * Is this client interested in payload messages? */ int send_payload; }; /** * Client monitoring changes of active addresses of our neighbours. */ struct MonitoringClient { /** * This is a doubly-linked list. */ struct MonitoringClient *next; /** * This is a doubly-linked list. */ struct MonitoringClient *prev; /** * Handle to the client. */ struct GNUNET_SERVER_Client *client; /** * Peer identity to monitor the addresses of. * Zero to monitor all neighrours. */ struct GNUNET_PeerIdentity peer; }; /** * Head of linked list of all clients to this service. */ static struct TransportClient *clients_head; /** * Tail of linked list of all clients to this service. */ static struct TransportClient *clients_tail; /** * Head of linked list of monitoring clients. */ static struct MonitoringClient *monitoring_clients_head; /** * Tail of linked list of monitoring clients. */ static struct MonitoringClient *monitoring_clients_tail; /** * Notification context, to send updates on changes to active addresses * of our neighbours. */ struct GNUNET_SERVER_NotificationContext *nc = NULL; /** * Find the internal handle associated with the given client handle * * @param client server's client handle to look up * @return internal client handle */ static struct TransportClient * lookup_client (struct GNUNET_SERVER_Client *client) { struct TransportClient *tc; tc = clients_head; while (tc != NULL) { if (tc->client == client) return tc; tc = tc->next; } return NULL; } /** * Create the internal handle for the given server client handle * * @param client server's client handle to create our internal handle for * @return fresh internal client handle */ static struct TransportClient * setup_client (struct GNUNET_SERVER_Client *client) { struct TransportClient *tc; GNUNET_assert (lookup_client (client) == NULL); tc = GNUNET_malloc (sizeof (struct TransportClient)); tc->client = client; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc); return tc; } /** * Find the handle to the monitoring client associated with the given * client handle * * @param client server's client handle to look up * @return handle to the monitoring client */ static struct MonitoringClient * lookup_monitoring_client (struct GNUNET_SERVER_Client *client) { struct MonitoringClient *mc; mc = monitoring_clients_head; while (mc != NULL) { if (mc->client == client) return mc; mc = mc->next; } return NULL; } /** * Setup a new monitoring client using the given server client handle and * the peer identity. * * @param client server's client handle to create our internal handle for * @param peer identity of the peer to monitor the addresses of, * zero to monitor all neighrours. * @return handle to the new monitoring client */ static struct MonitoringClient * setup_monitoring_client (struct GNUNET_SERVER_Client *client, struct GNUNET_PeerIdentity *peer) { struct MonitoringClient *mc; GNUNET_assert (lookup_monitoring_client (client) == NULL); mc = GNUNET_malloc (sizeof (struct MonitoringClient)); mc->client = client; mc->peer = *peer; GNUNET_CONTAINER_DLL_insert (monitoring_clients_head, monitoring_clients_tail, mc); GNUNET_SERVER_notification_context_add (nc, client); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p started monitoring of the peer `%s'\n", mc, GNUNET_i2s (peer)); return mc; } /** * Function called to notify a client about the socket being ready to * queue more data. "buf" will be NULL and "size" zero if the socket * was closed for writing in the meantime. * * @param cls closure * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_to_client_callback (void *cls, size_t size, void *buf) { struct TransportClient *tc = cls; struct ClientMessageQueueEntry *q; const struct GNUNET_MessageHeader *msg; char *cbuf; uint16_t msize; size_t tsize; tc->th = NULL; if (buf == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission to client failed, closing connection.\n"); return 0; } cbuf = buf; tsize = 0; while (NULL != (q = tc->message_queue_head)) { msg = (const struct GNUNET_MessageHeader *) &q[1]; msize = ntohs (msg->size); if (msize + tsize > size) break; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting message of type %u to client %p.\n", ntohs (msg->type), tc); GNUNET_CONTAINER_DLL_remove (tc->message_queue_head, tc->message_queue_tail, q); tc->message_count--; memcpy (&cbuf[tsize], msg, msize); GNUNET_free (q); tsize += msize; } if (NULL != q) { GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader)); tc->th = GNUNET_SERVER_notify_transmit_ready (tc->client, msize, GNUNET_TIME_UNIT_FOREVER_REL, &transmit_to_client_callback, tc); GNUNET_assert (tc->th != NULL); } return tsize; } /** * Queue the given message for transmission to the given client * * @param tc target of the message * @param msg message to transmit * @param may_drop GNUNET_YES if the message can be dropped */ static void unicast (struct TransportClient *tc, const struct GNUNET_MessageHeader *msg, int may_drop) { struct ClientMessageQueueEntry *q; uint16_t msize; if (msg == NULL) { GNUNET_break (0); return; } if ((tc->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Dropping message of type %u and size %u, have %u/%u messages pending\n"), ntohs (msg->type), ntohs (msg->size), tc->message_count, MAX_PENDING); GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# messages dropped due to slow client"), 1, GNUNET_NO); return; } msize = ntohs (msg->size); GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader)); q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize); memcpy (&q[1], msg, msize); GNUNET_CONTAINER_DLL_insert_tail (tc->message_queue_head, tc->message_queue_tail, q); tc->message_count++; if (tc->th != NULL) return; tc->th = GNUNET_SERVER_notify_transmit_ready (tc->client, msize, GNUNET_TIME_UNIT_FOREVER_REL, &transmit_to_client_callback, tc); GNUNET_assert (tc->th != NULL); } /** * Called whenever a client is disconnected. Frees our * resources associated with that client. * * @param cls closure * @param client identification of the client */ static void client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client) { struct TransportClient *tc; struct MonitoringClient *mc; struct ClientMessageQueueEntry *mqe; if (client == NULL) return; mc = lookup_monitoring_client (client); if (mc != NULL) { GNUNET_CONTAINER_DLL_remove (monitoring_clients_head, monitoring_clients_tail, mc); GNUNET_free (mc); } tc = lookup_client (client); if (tc == NULL) return; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "Client %p disconnected, cleaning up.\n", tc); while (NULL != (mqe = tc->message_queue_head)) { GNUNET_CONTAINER_DLL_remove (tc->message_queue_head, tc->message_queue_tail, mqe); tc->message_count--; GNUNET_free (mqe); } GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc); if (tc->th != NULL) { GNUNET_SERVER_notify_transmit_ready_cancel (tc->th); tc->th = NULL; } GNUNET_break (0 == tc->message_count); GNUNET_free (tc); } /** * Function called for each of our connected neighbours. Notify the * client about the existing neighbour. * * @param cls the 'struct TransportClient' to notify * @param peer identity of the neighbour * @param ats performance data * @param ats_count number of entries in ats (excluding 0-termination) * @param address the address */ static void notify_client_about_neighbour (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *ats, uint32_t ats_count, const struct GNUNET_HELLO_Address *address) { struct TransportClient *tc = cls; struct ConnectInfoMessage *cim; struct GNUNET_ATS_Information *ap; size_t size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_ATS_Information); char buf[size] GNUNET_ALIGN; GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE); cim = (struct ConnectInfoMessage *) buf; cim->header.size = htons (size); cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT); cim->ats_count = htonl (ats_count); cim->id = *peer; ap = (struct GNUNET_ATS_Information *) &cim[1]; memcpy (ap, ats, ats_count * sizeof (struct GNUNET_ATS_Information)); unicast (tc, &cim->header, GNUNET_NO); } /** * Initialize a normal client. We got a start message from this * client, add him to the list of clients for broadcasting of inbound * messages. * * @param cls unused * @param client the client * @param message the start message that was sent */ static void clients_handle_start (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct StartMessage *start; struct TransportClient *tc; uint32_t options; tc = lookup_client (client); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "Client %p sent START\n", tc); if (tc != NULL) { /* got 'start' twice from the same client, not allowed */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "TransportClient %p ServerClient %p sent multiple START messages\n", tc, tc->client); GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } start = (const struct StartMessage *) message; options = ntohl (start->options); if ((0 != (1 & options)) && (0 != memcmp (&start->self, &GST_my_identity, sizeof (struct GNUNET_PeerIdentity)))) { /* client thinks this is a different peer, reject */ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Rejecting control connection from peer `%s', which is not me!\n"), GNUNET_i2s (&start->self)); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } tc = setup_client (client); tc->send_payload = (0 != (2 & options)); unicast (tc, GST_hello_get (), GNUNET_NO); GST_neighbours_iterate (¬ify_client_about_neighbour, tc); GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Client sent us a HELLO. Process the request. * * @param cls unused * @param client the client * @param message the HELLO message */ static void clients_handle_hello (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { GST_validation_handle_hello (message); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Closure for 'handle_send_transmit_continuation' */ struct SendTransmitContinuationContext { /** * Client that made the request. */ struct GNUNET_SERVER_Client *client; /** * Peer that was the target. */ struct GNUNET_PeerIdentity target; }; /** * Function called after the transmission is done. Notify the client that it is * OK to send the next message. * * @param cls closure * @param success GNUNET_OK on success, GNUNET_NO on failure, GNUNET_SYSERR if we're not connected */ static void handle_send_transmit_continuation (void *cls, int success) { struct SendTransmitContinuationContext *stcc = cls; struct SendOkMessage send_ok_msg; send_ok_msg.header.size = htons (sizeof (send_ok_msg)); send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK); send_ok_msg.success = htonl (success); send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL); send_ok_msg.peer = stcc->target; GST_clients_unicast (stcc->client, &send_ok_msg.header, GNUNET_NO); GNUNET_SERVER_client_drop (stcc->client); GNUNET_free (stcc); } /** * Client asked for transmission to a peer. Process the request. * * @param cls unused * @param client the client * @param message the send message that was sent */ static void clients_handle_send (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct OutboundMessage *obm; const struct GNUNET_MessageHeader *obmm; struct SendTransmitContinuationContext *stcc; uint16_t size; uint16_t msize; struct TransportClient *tc; tc = lookup_client (client); if (NULL == tc) { /* client asked for transmission before 'START' */ GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } size = ntohs (message->size); if (size < sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } obm = (const struct OutboundMessage *) message; obmm = (const struct GNUNET_MessageHeader *) &obm[1]; msize = size - sizeof (struct OutboundMessage); if (msize < sizeof (struct GNUNET_MessageHeader)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' request from client with target `%4s' and first message of type %u and total size %u\n", "SEND", GNUNET_i2s (&obm->peer), ntohs (obmm->type), msize); if (GNUNET_NO == GST_neighbours_test_connected (&obm->peer)) { /* not connected, not allowed to send; can happen due to asynchronous operations */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not send message to peer `%s': not connected\n", GNUNET_i2s (&obm->peer)); GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# bytes payload dropped (other peer was not connected)"), msize, GNUNET_NO); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } GNUNET_SERVER_receive_done (client, GNUNET_OK); stcc = GNUNET_malloc (sizeof (struct SendTransmitContinuationContext)); stcc->target = obm->peer; stcc->client = client; GNUNET_SERVER_client_keep (client); GST_neighbours_send (&obm->peer, obmm, msize, GNUNET_TIME_relative_ntoh (obm->timeout), &handle_send_transmit_continuation, stcc); } /** * Try to initiate a connection to the given peer if the blacklist * allowed it. * * @param cls closure (unused, NULL) * @param peer identity of peer that was tested * @param result GNUNET_OK if the connection is allowed, * GNUNET_NO if not */ static void try_connect_if_allowed (void *cls, const struct GNUNET_PeerIdentity *peer, int result) { if (GNUNET_OK != result) return; /* not allowed */ GST_neighbours_try_connect (peer); } /** * Handle request connect message * * @param cls closure (always NULL) * @param client identification of the client * @param message the actual message */ static void clients_handle_request_connect (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct TransportRequestConnectMessage *trcm = (const struct TransportRequestConnectMessage *) message; GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# REQUEST CONNECT messages received"), 1, GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer `%s'\n", GNUNET_i2s (&trcm->peer)); (void) GST_blacklist_test_allowed (&trcm->peer, NULL, &try_connect_if_allowed, NULL); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Take the given address and append it to the set of results sent back to * the client. * * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*') * @param buf text to transmit */ static void transmit_address_to_client (void *cls, const char *buf) { struct GNUNET_SERVER_TransmitContext *tc = cls; if (NULL == buf) { GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY); GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); return; } GNUNET_SERVER_transmit_context_append_data (tc, buf, strlen (buf) + 1, GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY); } /** * Client asked to resolve an address. Process the request. * * @param cls unused * @param client the client * @param message the resolution request */ static void clients_handle_address_to_string (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct AddressLookupMessage *alum; struct GNUNET_TRANSPORT_PluginFunctions *papi; const char *plugin_name; const char *address; uint32_t address_len; uint16_t size; struct GNUNET_SERVER_TransmitContext *tc; struct GNUNET_TIME_Relative rtimeout; int32_t numeric; size = ntohs (message->size); if (size < sizeof (struct AddressLookupMessage)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } alum = (const struct AddressLookupMessage *) message; address_len = ntohs (alum->addrlen); if (size <= sizeof (struct AddressLookupMessage) + address_len) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } address = (const char *) &alum[1]; plugin_name = (const char *) &address[address_len]; if (plugin_name[size - sizeof (struct AddressLookupMessage) - address_len - 1] != '\0') { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout); numeric = ntohs (alum->numeric_only); tc = GNUNET_SERVER_transmit_context_create (client); papi = GST_plugins_find (plugin_name); if (NULL == papi) { GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY); GNUNET_SERVER_transmit_context_run (tc, rtimeout); return; } GNUNET_SERVER_disable_receive_done_warning (client); papi->address_pretty_printer (papi->cls, plugin_name, address, address_len, numeric, rtimeout, &transmit_address_to_client, tc); } /** * Compose AddressIterateResponseMessage using the given peer and address. * * @param peer identity of the peer * @param address the address, NULL on disconnect * @return composed message */ static struct AddressIterateResponseMessage * compose_address_iterate_response_message (const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Address *address) { struct AddressIterateResponseMessage *msg; size_t size; size_t tlen; size_t alen; char *addr; GNUNET_assert (NULL != peer); if (NULL != address) { tlen = strlen (address->transport_name) + 1; alen = address->address_length; } else tlen = alen = 0; size = (sizeof (struct AddressIterateResponseMessage) + alen + tlen); msg = GNUNET_malloc (size); msg->header.size = htons (size); msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE); msg->reserved = htonl (0); msg->peer = *peer; msg->addrlen = htonl (alen); msg->pluginlen = htonl (tlen); if (NULL != address) { addr = (char *) &msg[1]; memcpy (addr, address->address, alen); memcpy (&addr[alen], address->transport_name, tlen); } return msg; } /** * Output the active address of connected neighbours to the given client. * * @param cls the 'struct GNUNET_SERVER_TransmitContext' for transmission to the client * @param peer identity of the neighbour * @param ats performance data * @param ats_count number of entries in ats (excluding 0-termination) * @param address the address */ static void output_address (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *ats, uint32_t ats_count, const struct GNUNET_HELLO_Address *address) { struct GNUNET_SERVER_TransmitContext *tc = cls; struct AddressIterateResponseMessage *msg; msg = compose_address_iterate_response_message (peer, address); GNUNET_SERVER_transmit_context_append_message (tc, &msg->header); GNUNET_free (msg); } /** * Client asked to obtain information about all actively used addresses * of connected peers * Process the request. * * @param cls unused * @param client the client * @param message the peer address information request */ static void clients_handle_address_iterate (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { static struct GNUNET_PeerIdentity all_zeros; struct GNUNET_SERVER_TransmitContext *tc; struct AddressIterateMessage *msg; struct GNUNET_HELLO_Address *address; if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } if (ntohs (message->size) != sizeof (struct AddressIterateMessage)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } msg = (struct AddressIterateMessage *) message; if ( (GNUNET_YES != ntohl (msg->one_shot)) && (NULL != lookup_monitoring_client (client)) ) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "ServerClient %p tried to start monitoring twice\n", client); GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_SERVER_disable_receive_done_warning (client); tc = GNUNET_SERVER_transmit_context_create (client); if (0 == memcmp (&msg->peer, &all_zeros, sizeof (struct GNUNET_PeerIdentity))) { /* iterate over all neighbours */ GST_neighbours_iterate (&output_address, tc); } else { /* just return one neighbour */ address = GST_neighbour_get_current_address (&msg->peer); if (address != NULL) output_address (tc, &msg->peer, NULL, 0, address); } if (GNUNET_YES != ntohl (msg->one_shot)) setup_monitoring_client (client, &msg->peer); else GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE); GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); } /** * Start handling requests from clients. * * @param server server used to accept clients from. */ void GST_clients_start (struct GNUNET_SERVER_Handle *server) { static const struct GNUNET_SERVER_MessageHandler handlers[] = { {&clients_handle_start, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)}, {&clients_handle_hello, NULL, GNUNET_MESSAGE_TYPE_HELLO, 0}, {&clients_handle_send, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0}, {&clients_handle_request_connect, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof (struct TransportRequestConnectMessage)}, {&clients_handle_address_to_string, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING, 0}, {&clients_handle_address_iterate, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE, sizeof (struct AddressIterateMessage)}, {&GST_blacklist_handle_init, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)}, {&GST_blacklist_handle_reply, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)}, {NULL, NULL, 0, 0} }; nc = GNUNET_SERVER_notification_context_create (server, 0); GNUNET_SERVER_add_handlers (server, handlers); GNUNET_SERVER_disconnect_notify (server, &client_disconnect_notification, NULL); } /** * Stop processing clients. */ void GST_clients_stop () { if (NULL != nc) { GNUNET_SERVER_notification_context_destroy (nc); nc = NULL; } } /** * Broadcast the given message to all of our clients. * * @param msg message to broadcast * @param may_drop GNUNET_YES if the message can be dropped / is payload */ void GST_clients_broadcast (const struct GNUNET_MessageHeader *msg, int may_drop) { struct TransportClient *tc; for (tc = clients_head; tc != NULL; tc = tc->next) { if ((GNUNET_YES == may_drop) && (GNUNET_YES != tc->send_payload)) continue; /* skip, this client does not care about payload */ unicast (tc, msg, may_drop); } } /** * Send the given message to a particular client * * @param client target of the message * @param msg message to transmit * @param may_drop GNUNET_YES if the message can be dropped */ void GST_clients_unicast (struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *msg, int may_drop) { struct TransportClient *tc; tc = lookup_client (client); if (NULL == tc) return; /* client got disconnected in the meantime, drop message */ unicast (tc, msg, may_drop); } /** * Broadcast the new active address to all clients monitoring the peer. * * @param peer peer this update is about (never NULL) * @param address address, NULL on disconnect */ void GST_clients_broadcast_address_notification (const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Address *address) { struct AddressIterateResponseMessage *msg; struct MonitoringClient *mc; static struct GNUNET_PeerIdentity all_zeros; msg = compose_address_iterate_response_message (peer, address); mc = monitoring_clients_head; while (mc != NULL) { if ((0 == memcmp (&mc->peer, &all_zeros, sizeof (struct GNUNET_PeerIdentity))) || (0 == memcmp (&mc->peer, peer, sizeof (struct GNUNET_PeerIdentity)))) { GNUNET_SERVER_notification_context_unicast (nc, mc->client, &msg->header, GNUNET_NO); } mc = mc->next; } GNUNET_free (msg); } /* end of file gnunet-service-transport_clients.c */ gnunet-0.9.3/src/transport/test_transport_api_reliability_tcp_nat_peer2.conf0000644000175000017500000000123111750306133024554 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-reliability-tcp-nat-p2/ DEFAULTCONFIG = test_transport_api_reliability_tcp_nat_peer2.conf [nat] DISABLEV6 = YES ENABLE_NAT_CLIENT = YES [transport-tcp] PORT = 12030 TIMEOUT = 5 s [arm] PORT = 12034 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12033 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12032 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12031 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 45923 PLUGINS = tcp UNIXPATH = /tmp/gnunet-p2-service-transport.sock gnunet-0.9.3/src/transport/test_transport_api_unreliability.c0000644000175000017500000003535011760502551021623 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/test_transport_api_unreliability.c * @brief test case for transports; ensures messages get * through, regardless of order * * This test case serves as a base for unreliable * transport test cases to check that the transports * achieve reliable message delivery. */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_hello_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_server_lib.h" #include "gnunet_transport_service.h" #include "gauger.h" #include "transport.h" #include "transport-testing.h" #define VERBOSE GNUNET_NO #define VERBOSE_ARM GNUNET_NO #define START_ARM GNUNET_YES /** * Testcase timeout */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 900) /** * How long until we give up on transmitting the message? */ #define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) static char *test_source; static char *test_plugin; static char *test_name; static int ok; static GNUNET_SCHEDULER_TaskIdentifier die_task; struct PeerContext *p1; struct PeerContext *p2; struct GNUNET_TRANSPORT_TransmitHandle *th; char *cfg_file_p1; char *cfg_file_p2; uint32_t max_bps_p1; uint32_t max_bps_p2; struct GNUNET_TRANSPORT_TESTING_handle *tth; /* * Testcase specific declarations */ /** * Note that this value must not significantly exceed * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise * messages may be dropped even for a reliable transport. */ #define TOTAL_MSGS (1024 * 3) #define MTYPE 12345 GNUNET_NETWORK_STRUCT_BEGIN struct TestMessage { struct GNUNET_MessageHeader header; uint32_t num; }; GNUNET_NETWORK_STRUCT_END static char *test_name; static int msg_scheduled; static int msg_sent; static int msg_recv_expected; static int msg_recv; static int test_connected; static int test_sending; static int test_send_timeout; static unsigned long long total_bytes; static struct GNUNET_TIME_Absolute start_time; static char bitmap[TOTAL_MSGS / 8]; static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; /* * END Testcase specific declarations */ #if VERBOSE #define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) #else #define OKPP do { ok++; } while (0) #endif static int get_bit (const char *map, unsigned int bit); static void end () { unsigned long long delta; char *value_name; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value; FPRINTF (stderr, "\nThroughput was %llu kb/s\n", total_bytes * 1000 / 1024 / delta); GNUNET_asprintf (&value_name, "unreliable_%s", test_plugin); GAUGER ("TRANSPORT", value_name, (int) (total_bytes * 1000 / 1024 / delta), "kb/s"); GNUNET_free (value_name); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; if (cc != NULL) GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); cc = NULL; GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); GNUNET_TRANSPORT_TESTING_done (tth); ok = 0; int i; for (i = 0; i < TOTAL_MSGS; i++) { if (get_bit (bitmap, i) == 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Did not receive message %d\n", i); ok = -1; } } } static void end_badly () { die_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); if (test_connected == GNUNET_YES) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers got connected\n"); else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers got NOT connected\n"); if (test_sending == GNUNET_NO) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Testcase did not send any messages before timeout\n"); else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Reliability failed: Last message sent %u, Next message scheduled %u, Last message received %u, Message expected %u\n", msg_sent, msg_scheduled, msg_recv, msg_recv_expected); if (test_send_timeout == GNUNET_YES) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test had timeout while waiting to send data\n"); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; if (cc != NULL) GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); cc = NULL; if (p1 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); if (p2 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); GNUNET_TRANSPORT_TESTING_done (tth); ok = GNUNET_SYSERR; } static unsigned int get_size (unsigned int iter) { unsigned int ret; ret = (iter * iter * iter); #ifndef LINUX /* FreeBSD/OSX etc. Unix DGRAMs do not work * with large messages */ if (0 == strcmp ("unix", test_plugin)) return sizeof (struct TestMessage) + (ret % 1024); #endif return sizeof (struct TestMessage) + (ret % 60000); } /** * Sets a bit active in the bitmap. * * @param bitIdx which bit to set */ static void set_bit (unsigned int bitIdx) { size_t arraySlot; unsigned int targetBit; if (bitIdx >= sizeof (bitmap) * 8) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "tried to set bit %d of %d(!?!?)\n", bitIdx, sizeof (bitmap) * 8); return; } arraySlot = bitIdx / 8; targetBit = (1L << (bitIdx % 8)); bitmap[arraySlot] |= targetBit; } /** * Obtain a bit from bitmap. * @param map the bitmap * @param bit index from bitmap * * @return Bit \a bit from hashcode \a code */ static int get_bit (const char *map, unsigned int bit) { if (bit >= TOTAL_MSGS) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "get bit %d of %d(!?!?)\n", bit, sizeof (bitmap) * 8); return 0; } return ((map)[bit >> 3] & (1 << (bit & 7))) > 0; } static void notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { static int n; unsigned int s; char cbuf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; const struct TestMessage *hdr; hdr = (const struct TestMessage *) message; if (MTYPE != ntohs (message->type)) return; msg_recv_expected = n; msg_recv = ntohl (hdr->num); s = get_size (ntohl (hdr->num)); if (ntohs (message->size) != s) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected message %u of size %u, got %u bytes of message %u\n", ntohl (hdr->num), s, ntohs (message->size), ntohl (hdr->num)); if (GNUNET_SCHEDULER_NO_TASK != die_task) GNUNET_SCHEDULER_cancel (die_task); test_sending = GNUNET_YES; die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } memset (cbuf, ntohl (hdr->num), s - sizeof (struct TestMessage)); if (0 != memcmp (cbuf, &hdr[1], s - sizeof (struct TestMessage))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected message %u with bits %u, but body did not match\n", ntohl (hdr->num), (unsigned char) n); if (GNUNET_SCHEDULER_NO_TASK != die_task) GNUNET_SCHEDULER_cancel (die_task); test_sending = GNUNET_YES; die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } #if VERBOSE if (ntohl (hdr->num) % 5 == 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got message %u of size %u\n", ntohl (hdr->num), ntohs (message->size)); } #endif n++; set_bit (ntohl (hdr->num)); test_sending = GNUNET_YES; if (0 == (n % (TOTAL_MSGS / 100))) { FPRINTF (stderr, "%s", "."); if (GNUNET_SCHEDULER_NO_TASK != die_task) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); } if (n == TOTAL_MSGS) { end (); } } static size_t notify_ready (void *cls, size_t size, void *buf) { static int n; char *cbuf = buf; struct TestMessage hdr; unsigned int s; unsigned int ret; th = NULL; if (buf == NULL) { test_send_timeout = GNUNET_YES; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout occurred while waiting for transmit_ready for msg %u of %u\n", msg_scheduled, TOTAL_MSGS); if (GNUNET_SCHEDULER_NO_TASK != die_task) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); ok = 42; return 0; } ret = 0; s = get_size (n); GNUNET_assert (size >= s); GNUNET_assert (buf != NULL); cbuf = buf; do { hdr.header.size = htons (s); hdr.header.type = htons (MTYPE); hdr.num = htonl (n); msg_sent = n; memcpy (&cbuf[ret], &hdr, sizeof (struct TestMessage)); ret += sizeof (struct TestMessage); memset (&cbuf[ret], n, s - sizeof (struct TestMessage)); ret += s - sizeof (struct TestMessage); #if VERBOSE if (n % 5000 == 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message %u of size %u\n", n, s); } #endif n++; s = get_size (n); if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16)) break; /* sometimes pack buffer full, sometimes not */ } while (size - ret >= s); if (n < TOTAL_MSGS) { th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, s, 0, TIMEOUT_TRANSMIT, ¬ify_ready, NULL); msg_scheduled = n; } else { FPRINTF (stderr, "%s", "\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All messages scheduled to be sent\n"); if (GNUNET_SCHEDULER_NO_TASK != die_task) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); } if (n % 5000 == 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Returning total message block of size %u\n", ret); } total_bytes += ret; return ret; } static void notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' connected to us (%p)!\n", GNUNET_i2s (peer), cls); } static void notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' disconnected (%p)!\n", GNUNET_i2s (peer), cls); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; } static void sendtask () { start_time = GNUNET_TIME_absolute_get (); th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, get_size (0), 0, TIMEOUT_TRANSMIT, ¬ify_ready, NULL); } static void testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) { char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %s <-> %s\n", p1_c, GNUNET_i2s (&p2->id)); GNUNET_free (p1_c); test_connected = GNUNET_YES; cc = NULL; GNUNET_SCHEDULER_add_now (&sendtask, NULL); } void start_cb (struct PeerContext *p, void *cls) { static int started; started++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, GNUNET_i2s (&p->id)); if (started != 2) return; test_connected = GNUNET_NO; cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); test_send_timeout = GNUNET_NO; p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); if ((p1 == NULL) || (p2 == NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } } static int check () { static char *const argv[] = { "test-transport-api-unreliability", "-c", "test_transport_api_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; #if WRITECONFIG setTransportOptions ("test_transport_api_data.conf"); #endif ok = GNUNET_SYSERR; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name, "nohelp", options, &run, &ok); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); GNUNET_log_setup (test_name, #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source); GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source, &test_plugin); tth = GNUNET_TRANSPORT_TESTING_init (); GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1); GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2); ret = check (); GNUNET_free (cfg_file_p1); GNUNET_free (cfg_file_p2); GNUNET_free (test_source); GNUNET_free (test_plugin); GNUNET_free (test_name); return ret; } /* end of test_transport_api_unreliability.c */ gnunet-0.9.3/src/transport/template_cfg_peer1.conf0000644000175000017500000000157311750306133017171 00000000000000@INLINE@ test_transport_defaults.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-tcp-p1/ DEFAULTCONFIG = template_cfg_peer1.conf [gnunetd] HOSTKEY = $SERVICEHOME/.hostkey [nat] RETURN_LOCAL_ADDRESSES = YES DISABLEV6 = NO [transport-tcp] PORT = 12000 TIMEOUT = 5 s [transport-udp] BROADCAST = NO [transport-unix] PORT = 12007 [arm] PORT = 12005 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12004 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12003 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12002 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] #PREFIX = valgrind --leak-check=full PORT = 12001 #DEBUG = YES UNIXPATH = /tmp/gnunet-p1-service-transport.sock [ats] #DEBUG = YES WAN_QUOTA_IN = 1 GB WAN_QUOTA_OUT = 1 GB PORT = 12006 UNIXPATH = /tmp/gnunet-p1-service-ats.sock gnunet-0.9.3/src/transport/gnunet-helper-transport-wlan-dummy.c0000644000175000017500000003052611760502551021642 00000000000000/* This file is part of GNUnet. (C) 2010, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/gnunet-helper-transport-wlan-dummy.c * @brief helper for the testcases for plugin_transport_wlan.c * @author David Brodski */ #include "platform.h" #include "gnunet_protocols.h" #include "gnunet_util_lib.h" #include "plugin_transport_wlan.h" /** * Name of the fifo to use for IPC with the other dummy process. */ #define FIFO_FILE1 "/tmp/test-transport/api-wlan-p1/WLAN_FIFO_in" /** * Name of the fifo to use for IPC with the other dummy process. */ #define FIFO_FILE2 "/tmp/test-transport/api-wlan-p1/WLAN_FIFO_out" /** * Maximum size of a message allowed in either direction * (used for our receive and sent buffers). */ #define MAXLINE 4096 /** * IO buffer used for buffering data in transit. */ struct SendBuffer { /** * How many bytes that were stored in 'buf' did we already write to the * destination? Always smaller than 'size'. */ size_t pos; /** * How many bytes of data are stored in 'buf' for transmission right now? * Data always starts at offset 0 and extends to 'size'. */ size_t size; /** * Buffered data; twice the maximum allowed message size as we add some * headers. */ char buf[MAXLINE * 2]; }; /** * Flag set to 1 if we are to terminate, otherwise 0. */ static int closeprog; /** * We're being killed, clean up. * * @param sig killing signal */ static void sigfunc (int sig) { closeprog = 1; (void) unlink (FIFO_FILE1); (void) unlink (FIFO_FILE2); } /** * Create control message for plugin * * @param buffer pointer to buffer for the message * @param mac pointer to the mac address * @return number of bytes written */ static int send_mac_to_plugin (char *buffer, struct GNUNET_TRANSPORT_WLAN_MacAddress *mac) { struct GNUNET_TRANSPORT_WLAN_HelperControlMessage macmsg; memcpy (&macmsg.mac, (char *) mac, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); macmsg.hdr.size = htons (sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage)); macmsg.hdr.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL); memcpy (buffer, &macmsg, sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage)); return sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage); } /** * We got a message from the FIFO, check it, convert the message * type to the output forward and copy it to the buffer for stdout. * * @param cls the 'struct SendBuffer' to copy the converted message to * @param client unused * @param hdr inbound message from the FIFO */ static int stdin_send (void *cls, void *client, const struct GNUNET_MessageHeader *hdr) { struct SendBuffer *write_pout = cls; const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *in; size_t payload_size; struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage newheader; uint16_t sendsize; sendsize = ntohs (hdr->size); in = (const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) hdr; if ( (GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER != ntohs (hdr->type)) || (sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) > sendsize) ) { FPRINTF (stderr, "%s", "Received malformed message\n"); exit (1); } payload_size = sendsize - sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage); if ((payload_size + sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage) + write_pout->size) > MAXLINE * 2) { FPRINTF (stderr, "%s", "Packet too big for buffer\n"); exit (1); } memset (&newheader, 0, sizeof (newheader)); newheader.header.size = htons (payload_size + sizeof (newheader)); newheader.header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER); newheader.frame = in->frame; memcpy (write_pout->buf + write_pout->size, &newheader, sizeof (newheader)); write_pout->size += sizeof (newheader); memcpy (write_pout->buf + write_pout->size, &in[1], payload_size); write_pout->size += payload_size; return GNUNET_OK; } /** * We read a full message from stdin. Copy it to our send buffer. * * @param cls the 'struct SendBuffer' to copy to * @param client unused * @param hdr the message we received to copy to the buffer */ static int file_in_send (void *cls, void *client, const struct GNUNET_MessageHeader *hdr) { struct SendBuffer *write_std = cls; uint16_t sendsize; sendsize = ntohs (hdr->size); if ((sendsize + write_std->size) > MAXLINE * 2) { FPRINTF (stderr, "%s", "Packet too big for buffer\n"); exit (1); } memcpy (write_std->buf + write_std->size, hdr, sendsize); write_std->size += sendsize; return GNUNET_OK; } /** * Main function of a program that pretends to be a WLAN card. * * @param argc should be 2 * @param argv either '1' or '2', depending on which of the two cards this dummy is to emulate * @return 1 on error, 0 if terminated normally via signal */ int main (int argc, char *argv[]) { struct stat st; int erg; FILE *fpin = NULL; FILE *fpout = NULL; int fdpin; int fdpout; char readbuf[MAXLINE]; int readsize; struct SendBuffer write_std; struct SendBuffer write_pout; int ret; int maxfd; fd_set rfds; fd_set wfds; struct timeval tv; int retval; struct GNUNET_SERVER_MessageStreamTokenizer *stdin_mst = NULL; struct GNUNET_SERVER_MessageStreamTokenizer *file_in_mst = NULL; struct GNUNET_TRANSPORT_WLAN_MacAddress macaddr; int first; if ( (2 != argc) || ((0 != strcmp (argv[1], "1")) && (0 != strcmp (argv[1], "2"))) ) { FPRINTF (stderr, "%s", "This program must be started with the operating mode (1 or 2) as the only argument.\n"); return 1; } /* make the fifos if needed */ umask (0); if ( (GNUNET_OK != GNUNET_DISK_directory_create_for_file (FIFO_FILE1)) || (GNUNET_OK != GNUNET_DISK_directory_create_for_file (FIFO_FILE2)) ) { FPRINTF (stderr, "Failed to create directory for file `%s'\n", FIFO_FILE1); return 1; } if (0 == strcmp (argv[1], "1") ) { if (0 != stat (FIFO_FILE1, &st)) { erg = mkfifo (FIFO_FILE1, 0666); if ( (0 != erg) && (EEXIST != errno) ) FPRINTF (stderr, "Error in mkfifo(%s): %s\n", FIFO_FILE1, strerror (errno)); } } else { if (0 != stat (FIFO_FILE2, &st)) { erg = mkfifo (FIFO_FILE2, 0666); if ( (0 != erg) && (EEXIST != errno) ) FPRINTF (stderr, "Error in mkfifo(%s): %s\n", FIFO_FILE2, strerror (errno)); } } if (0 == strcmp (argv[1], "1")) { first = 1; fpin = fopen (FIFO_FILE1, "r"); if (NULL == fpin) { FPRINTF (stderr, "fopen of read FIFO_FILE1 failed: %s\n", STRERROR (errno)); goto end; } if (NULL == (fpout = fopen (FIFO_FILE2, "w"))) { erg = mkfifo (FIFO_FILE2, 0666); fpout = fopen (FIFO_FILE2, "w"); } if (NULL == fpout) { FPRINTF (stderr, "fopen of write FIFO_FILE2 failed: %s\n", STRERROR (errno)); goto end; } } else { first = 0; if (NULL == (fpout = fopen (FIFO_FILE1, "w"))) { erg = mkfifo (FIFO_FILE1, 0666); fpout = fopen (FIFO_FILE1, "w"); } if (NULL == fpout) { FPRINTF (stderr, "fopen of write FIFO_FILE1 failed: %s\n", STRERROR (errno)); goto end; } fpin = fopen (FIFO_FILE2, "r"); if (NULL == fpin) { FPRINTF (stderr, "fopen of read FIFO_FILE2 failed: %s\n", STRERROR (errno)); goto end; } } fdpin = fileno (fpin); GNUNET_assert (fpin >= 0); if (fdpin >= FD_SETSIZE) { FPRINTF (stderr, "File fdpin number too large (%d > %u)\n", fdpin, (unsigned int) FD_SETSIZE); goto end; } fdpout = fileno (fpout); GNUNET_assert (fdpout >= 0); if (fdpout >= FD_SETSIZE) { FPRINTF (stderr, "File fdpout number too large (%d > %u)\n", fdpout, (unsigned int) FD_SETSIZE); goto end; } signal (SIGINT, &sigfunc); signal (SIGTERM, &sigfunc); write_std.size = 0; write_std.pos = 0; write_pout.size = 0; write_pout.pos = 0; stdin_mst = GNUNET_SERVER_mst_create (&stdin_send, &write_pout); file_in_mst = GNUNET_SERVER_mst_create (&file_in_send, &write_std); /* Send 'random' mac address */ macaddr.mac[0] = 0x13; macaddr.mac[1] = 0x22; macaddr.mac[2] = 0x33; macaddr.mac[3] = 0x44; macaddr.mac[4] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 256); macaddr.mac[5] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, 256); write_std.size = send_mac_to_plugin (write_std.buf, &macaddr); while (0 == closeprog) { maxfd = -1; tv.tv_sec = 5; tv.tv_usec = 0; FD_ZERO (&rfds); FD_ZERO (&wfds); /* if output queue is empty, read */ if (0 == write_pout.size) { FD_SET (STDIN_FILENO, &rfds); maxfd = MAX (STDIN_FILENO, maxfd); } if (0 == write_std.size) { FD_SET (fdpin, &rfds); maxfd = MAX (fdpin, maxfd); } /* if there is something to write, try to write */ if (0 < write_std.size) { FD_SET (STDOUT_FILENO, &wfds); maxfd = MAX (maxfd, STDOUT_FILENO); } if (0 < write_pout.size) { FD_SET (fdpout, &wfds); maxfd = MAX (maxfd, fdpout); } retval = select (maxfd + 1, &rfds, &wfds, NULL, &tv); if ((-1 == retval) && (EINTR == errno)) continue; if (0 > retval) { FPRINTF (stderr, "select failed: %s\n", STRERROR (errno)); closeprog = 1; break; } if (FD_ISSET (STDOUT_FILENO, &wfds)) { ret = write (STDOUT_FILENO, write_std.buf + write_std.pos, write_std.size - write_std.pos); if (0 > ret) { closeprog = 1; FPRINTF (stderr, "Write ERROR to STDOUT_FILENO: %s\n", STRERROR (errno)); break; } else { write_std.pos += ret; /* check if finished writing */ if (write_std.pos == write_std.size) { write_std.pos = 0; write_std.size = 0; } } } if (FD_ISSET (fdpout, &wfds)) { ret = write (fdpout, write_pout.buf + write_pout.pos, write_pout.size - write_pout.pos); if (0 > ret) { closeprog = 1; FPRINTF (stderr, "Write ERROR to fdpout failed: %s\n", STRERROR (errno)); } else { write_pout.pos += ret; /* check if finished writing */ if (write_pout.pos == write_pout.size) { write_pout.pos = 0; write_pout.size = 0; } } } if (FD_ISSET (STDIN_FILENO, &rfds)) { readsize = read (STDIN_FILENO, readbuf, sizeof (readbuf)); if (0 > readsize) { closeprog = 1; FPRINTF (stderr, "Error reading from STDIN_FILENO: %s\n", STRERROR (errno)); } else if (0 < readsize) { GNUNET_SERVER_mst_receive (stdin_mst, NULL, readbuf, readsize, GNUNET_NO, GNUNET_NO); } else { /* eof */ closeprog = 1; } } if (FD_ISSET (fdpin, &rfds)) { readsize = read (fdpin, readbuf, sizeof (readbuf)); if (0 > readsize) { closeprog = 1; FPRINTF (stderr, "Error reading from fdpin: %s\n", STRERROR (errno)); break; } else if (0 < readsize) { GNUNET_SERVER_mst_receive (file_in_mst, NULL, readbuf, readsize, GNUNET_NO, GNUNET_NO); } else { /* eof */ closeprog = 1; } } } end: /* clean up */ if (NULL != stdin_mst) GNUNET_SERVER_mst_destroy (stdin_mst); if (NULL != file_in_mst) GNUNET_SERVER_mst_destroy (file_in_mst); if (NULL != fpout) fclose (fpout); if (NULL != fpin) fclose (fpin); if (1 == first) { (void) unlink (FIFO_FILE1); (void) unlink (FIFO_FILE2); } return 0; } gnunet-0.9.3/src/transport/test_transport_startonly.c0000644000175000017500000001200511760502551020145 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/test_transport_api.c * @brief base test case for transport implementations * * This test case serves as a base for tcp, udp, and udp-nat * transport test cases. Based on the executable being run * the correct test case will be performed. Conservation of * C code apparently. */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_hello_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_transport_service.h" #include "transport.h" #include "transport-testing.h" #define VERBOSE GNUNET_NO #define VERBOSE_ARM GNUNET_NO #define START_ARM GNUNET_YES /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 90) #define ITERATIONS 10 GNUNET_SCHEDULER_TaskIdentifier timeout_task; static struct PeerContext *p1; struct GNUNET_TRANSPORT_TESTING_handle *tth; static int connected = GNUNET_NO; static int ret = 0; static int i; static void end () { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); if (timeout_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (timeout_task); timeout_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Exiting\n"); } static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); timeout_task = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; if (p1 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); ret = GNUNET_SYSERR; } static void notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' connected \n", GNUNET_i2s (peer)); connected++; } static void notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' disconnected \n", GNUNET_i2s (peer)); } static void notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving\n"); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { tth = GNUNET_TRANSPORT_TESTING_init (); timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); i = 1; FPRINTF (stderr, "%i", i); while (i <= ITERATIONS) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting peer\n"); p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, "test_transport_startonly.conf", 1, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, NULL, p1); if (p1 != NULL) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer was successfully started\n"); else GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer1 was not started successfully\n"); GNUNET_assert (p1 != NULL); GNUNET_assert (p1->th != NULL); GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); i++; if (i <= ITERATIONS) FPRINTF (stderr, "..%i", i); } tth = GNUNET_TRANSPORT_TESTING_init (); FPRINTF (stderr, "%s", "\n"); end (); } int main (int argc, char *argv[]) { GNUNET_log_setup ("test_transport_testing", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); char *const argv_1[] = { "test_transport_testing", "-c", "test_transport_api_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_PROGRAM_run ((sizeof (argv_1) / sizeof (char *)) - 1, argv_1, "test_transport_testing", "nohelp", options, &run, &ret); return ret; } /* end of test_transport_api.c */ gnunet-0.9.3/src/transport/test_transport_api_multi_peer2.conf0000644000175000017500000000135011661530125021670 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-multi-p2/ DEFAULTCONFIG = test_transport_api_multi_peer2.conf [nat] ALLOW_NAT = NO [transport-tcp] PORT = 12150 TIMEOUT = 5 s [transport-udp] PORT = 12151 [transport-http] PORT = 12152 [transport-https] PORT = 12153 [arm] PORT = 12159 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12158 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12157 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12156 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12155 PLUGINS = tcp udp unix UNIXPATH = /tmp/gnunet-p2-service-transport.sock [transport-unix] PORT = 12154 gnunet-0.9.3/src/transport/test_transport_api_bidirectional_connect_peer2.conf0000644000175000017500000000137711752320467025077 00000000000000@INLINE@ template_cfg_peer2.conf [PATHS] SERVICEHOME = /tmp/test-transport/api-tcp-p2/ DEFAULTCONFIG = test_transport_api_bidirectional_connect_peer2.conf [arm] PORT = 12010 DEFAULTSERVICES = transport UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 12011 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 12012 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 12013 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 12014 UNIXPATH = /tmp/gnunet-p2-service-transport.sock [transport-tcp] PORT = 12015 TIMEOUT = 5 s [transport-udp] PORT = 12016 TIMEOUT = 5 s [transport-unix] PORT = 12017 TIMEOUT = 5 s [transport-http] PORT = 12018 TIMEOUT = 5 s [transport-https] PORT = 12019 TIMEOUT = 5 sgnunet-0.9.3/src/transport/test_quota_compliance.c0000644000175000017500000004176111760502551017330 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/test_quota_compliance.c * @brief base test case for transport implementations * * This test case tests quota compliance both on transport level */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_hello_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_server_lib.h" #include "gnunet_transport_service.h" #include "gauger.h" #include "transport.h" #include "transport-testing.h" #define VERBOSE GNUNET_NO #define VERBOSE_ARM GNUNET_NO #define START_ARM GNUNET_YES /** * Testcase timeout */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) /** * How long until we give up on transmitting the message? */ #define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20) #define DURATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) static char *test_source; static char *test_plugin; static char *test_name; static int ok; static GNUNET_SCHEDULER_TaskIdentifier die_task; static GNUNET_SCHEDULER_TaskIdentifier measure_task; struct PeerContext *p1; struct PeerContext *p2; struct PeerContext *sender; struct PeerContext *receiver; struct GNUNET_TRANSPORT_TransmitHandle *th; char *cfg_file_p1; char *gen_cfg_p2; unsigned long long quota_in_p1; unsigned long long quota_out_p1; char *cfg_file_p2; char *gen_cfg_p1; unsigned long long quota_in_p2; unsigned long long quota_out_p2; struct GNUNET_TRANSPORT_TESTING_handle *tth; static GNUNET_TRANSPORT_TESTING_ConnectRequest cc; /* * Testcase specific declarations */ /** * Note that this value must not significantly exceed * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise * messages may be dropped even for a reliable transport. */ #define TOTAL_MSGS (1024 * 2) #define MTYPE 12345 GNUNET_NETWORK_STRUCT_BEGIN struct TestMessage { struct GNUNET_MessageHeader header; uint32_t num; }; GNUNET_NETWORK_STRUCT_END static int msg_scheduled; static int msg_sent; static int msg_recv_expected; static int msg_recv; static int test_failed; static int test_connected; static unsigned long long total_bytes_sent; static struct GNUNET_TIME_Absolute start_time; /* * END Testcase specific declarations */ #if VERBOSE #define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0) #else #define OKPP do { ok++; } while (0) #endif static void end () { unsigned long long delta; unsigned long long datarate; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n"); delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value; datarate = (total_bytes_sent * 1000) / delta; FPRINTF (stderr, "Throughput was %llu b/s\n", datarate); test_failed = GNUNET_NO; if (datarate > quota_in_p2) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Datarate of %llu b/s higher than allowed inbound quota of %llu b/s\n", datarate, quota_in_p2); test_failed = GNUNET_YES; } if (datarate > quota_out_p1) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Datarate of %llu b/s higher than allowed outbound quota of %llu b/s\n", datarate, quota_out_p1); test_failed = GNUNET_YES; } if (test_failed == GNUNET_NO) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Datarate of %llu b/s complied to allowed outbound quota of %llu b/s and inbound quota of %llu b/s\n", datarate, quota_out_p1, quota_in_p2); } if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; if (cc != NULL) GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); } static void end_badly () { die_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n"); if (measure_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (measure_task); if (test_connected == GNUNET_YES) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers got connected\n"); else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers got NOT connected\n"); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; if (cc != NULL) GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc); if (p1 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); if (p2 != NULL) GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); ok = GNUNET_SYSERR; } static unsigned int get_size (unsigned int iter) { unsigned int ret; ret = (iter * iter * iter); return sizeof (struct TestMessage) + (ret % 60000); } static void notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { static int n; unsigned int s; char cbuf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; const struct TestMessage *hdr; hdr = (const struct TestMessage *) message; s = get_size (n); if (MTYPE != ntohs (message->type)) return; msg_recv_expected = n; msg_recv = ntohl (hdr->num); if (ntohs (message->size) != (s)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected message %u of size %u, got %u bytes of message %u\n", n, s, ntohs (message->size), ntohl (hdr->num)); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); test_failed = GNUNET_YES; die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } if (ntohl (hdr->num) != n) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected message %u of size %u, got %u bytes of message %u\n", n, s, ntohs (message->size), ntohl (hdr->num)); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); test_failed = GNUNET_YES; die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } memset (cbuf, n, s - sizeof (struct TestMessage)); if (0 != memcmp (cbuf, &hdr[1], s - sizeof (struct TestMessage))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected message %u with bits %u, but body did not match\n", n, (unsigned char) n); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); test_failed = GNUNET_YES; die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } #if VERBOSE if (ntohl (hdr->num) % 5000 == 0) { struct PeerContext *p = cls; char *ps = GNUNET_strdup (GNUNET_i2s (&p->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') got message %u of size %u from peer (`%s')\n", p->no, ps, ntohl (hdr->num), ntohs (message->size), GNUNET_i2s (peer)); GNUNET_free (ps); } #endif n++; } static size_t notify_ready (void *cls, size_t size, void *buf) { static int n; char *cbuf = buf; struct TestMessage hdr; unsigned int s; unsigned int ret; th = NULL; if (buf == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout occurred while waiting for transmit_ready for message %u of %u\n", msg_scheduled, TOTAL_MSGS); if (GNUNET_SCHEDULER_NO_TASK != die_task) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); ok = 42; return 0; } ret = 0; s = get_size (n); GNUNET_assert (size >= s); GNUNET_assert (buf != NULL); cbuf = buf; do { hdr.header.size = htons (s); hdr.header.type = htons (MTYPE); hdr.num = htonl (n); msg_sent = n; memcpy (&cbuf[ret], &hdr, sizeof (struct TestMessage)); ret += sizeof (struct TestMessage); memset (&cbuf[ret], n, s - sizeof (struct TestMessage)); ret += s - sizeof (struct TestMessage); #if VERBOSE if (n % 5000 == 0) { char *receiver_s = GNUNET_strdup (GNUNET_i2s (&receiver->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message of size %u from peer %u (`%4s') -> peer %u (`%s') !\n", n, sender->no, GNUNET_i2s (&sender->id), receiver->no, receiver_s); GNUNET_free (receiver_s); } #endif n++; s = get_size (n); if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16)) break; /* sometimes pack buffer full, sometimes not */ } while (size - ret >= s); if (n < TOTAL_MSGS) { if (th == NULL) th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, s, 0, TIMEOUT_TRANSMIT, ¬ify_ready, NULL); msg_scheduled = n; } if (n % 5000 == 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Returning total message block of size %u\n", ret); } total_bytes_sent += ret; if (n == TOTAL_MSGS) { FPRINTF (stderr, "%s", "\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All messages sent\n"); } return ret; } static void notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { struct PeerContext *p = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') connected to us!\n", p->no, GNUNET_i2s (peer)); } static void notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { struct PeerContext *p = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') disconnected!\n", p->no, GNUNET_i2s (peer)); if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; } static void sendtask () { start_time = GNUNET_TIME_absolute_get (); th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, get_size (0), 0, TIMEOUT_TRANSMIT, ¬ify_ready, NULL); } static void measure (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { static int counter; measure_task = GNUNET_SCHEDULER_NO_TASK; counter++; if ((DURATION.rel_value / 1000) < counter) { FPRINTF (stderr, "%s", ".\n"); GNUNET_SCHEDULER_add_now (&end, NULL); } else { FPRINTF (stderr, "%s", "."); measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &measure, NULL); } } static void testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls) { char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n", p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id)); GNUNET_free (p1_c); cc = NULL; test_connected = GNUNET_YES; measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &measure, NULL); GNUNET_SCHEDULER_add_now (&sendtask, NULL); } void start_cb (struct PeerContext *p, void *cls) { static int started; started++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no, GNUNET_i2s (&p->id)); if (started != 2) return; test_connected = GNUNET_NO; sender = p2; receiver = p1; char *sender_c = GNUNET_strdup (GNUNET_i2s (&sender->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test tries to send from %u (%s) -> peer %u (%s)\n", sender->no, sender_c, receiver->no, GNUNET_i2s (&receiver->id)); cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb, NULL); } static char * generate_config (char *cfg_file, unsigned long long quota_in, unsigned long long quota_out) { char *fname = NULL; struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create (); GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (cfg, cfg_file)); GNUNET_asprintf (&fname, "q_in_%llu_q_out_%llu_%s", quota_in, quota_out, cfg_file); GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG", fname); GNUNET_CONFIGURATION_set_value_number (cfg, "ats", "WAN_QUOTA_IN", quota_in); GNUNET_CONFIGURATION_set_value_number (cfg, "ats", "WAN_QUOTA_OUT", quota_out); GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_write (cfg, fname)); GNUNET_CONFIGURATION_destroy (cfg); return fname; } static void run_measurement (unsigned long long p1_quota_in, unsigned long long p1_quota_out, unsigned long long p2_quota_in, unsigned long long p2_quota_out) { die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); /* setting ATS quota */ quota_out_p1 = p1_quota_out; gen_cfg_p1 = generate_config (cfg_file_p1, p1_quota_in, p1_quota_out); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Generated config file `%s'\n", gen_cfg_p1); quota_in_p2 = p2_quota_in; gen_cfg_p2 = generate_config (cfg_file_p2, p2_quota_in, p2_quota_out); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Generated config file `%s'\n", gen_cfg_p2); p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, gen_cfg_p1, 1, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, gen_cfg_p2, 2, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); if ((p1 == NULL) || (p2 == NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); return; } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { unsigned long long p1_quota_in = 10000; unsigned long long p1_quota_out = 10000; unsigned long long p2_quota_in = 10000; unsigned long long p2_quota_out = 10000; if (NULL != strstr (test_name, "asymmetric")) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running asymmetric test with sending peer unlimited, receiving peer (in/out): %llu/%llu b/s \n", p2_quota_in, p2_quota_out); p1_quota_out = 1024 * 1024 * 1024; p1_quota_in = 1024 * 1024 * 1024; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running symmetric test with (in/out) %llu/%llu b/s \n", p2_quota_in, p2_quota_out); } run_measurement (p1_quota_in, p1_quota_out, p2_quota_in, p2_quota_out); } static int check () { static char *argv[] = { "test_transport-quota-compliance", "-c", "test_quota_compliance_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; static struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; ok = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name, "nohelp", options, &run, &ok); return ok; } int main (int argc, char *argv[]) { GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name); GNUNET_log_setup (test_name, #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source); GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source, &test_plugin); tth = GNUNET_TRANSPORT_TESTING_init (); GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1); GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2); check (); GNUNET_free (cfg_file_p1); GNUNET_free (cfg_file_p2); if (GNUNET_YES == GNUNET_DISK_file_test (gen_cfg_p1)) { GNUNET_DISK_directory_remove (gen_cfg_p1); GNUNET_free (gen_cfg_p1); } if (GNUNET_YES == GNUNET_DISK_file_test (gen_cfg_p2)) { GNUNET_DISK_directory_remove (gen_cfg_p2); GNUNET_free (gen_cfg_p2); } GNUNET_free (test_source); GNUNET_free (test_plugin); GNUNET_free (test_name); GNUNET_TRANSPORT_TESTING_done (tth); return test_failed; } /* end of test_quota_compliance.c */ gnunet-0.9.3/src/transport/transport_api.c0000644000175000017500000011273411760502551015632 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/transport_api.c * @brief library to access the low-level P2P IO service * @author Christian Grothoff * * TODO: * - adjust testcases to use new 'try connect' style (should be easy, breaks API compatibility!) * - adjust core service to use new 'try connect' style (should be MUCH nicer there as well!) * - test test test */ #include "platform.h" #include "gnunet_constants.h" #include "gnunet_bandwidth_lib.h" #include "gnunet_client_lib.h" #include "gnunet_constants.h" #include "gnunet_container_lib.h" #include "gnunet_arm_service.h" #include "gnunet_hello_lib.h" #include "gnunet_protocols.h" #include "gnunet_server_lib.h" #include "gnunet_time_lib.h" #include "gnunet_transport_service.h" #include "transport.h" #define LOG(kind,...) GNUNET_log_from (kind, "transport-api",__VA_ARGS__) /** * How large to start with for the hashmap of neighbours. */ #define STARTING_NEIGHBOURS_SIZE 16 /** * Handle for a message that should be transmitted to the service. * Used for both control messages and normal messages. */ struct GNUNET_TRANSPORT_TransmitHandle { /** * We keep all requests in a DLL. */ struct GNUNET_TRANSPORT_TransmitHandle *next; /** * We keep all requests in a DLL. */ struct GNUNET_TRANSPORT_TransmitHandle *prev; /** * Neighbour for this handle, NULL for control messages. */ struct Neighbour *neighbour; /** * Function to call when notify_size bytes are available * for transmission. */ GNUNET_CONNECTION_TransmitReadyNotify notify; /** * Closure for notify. */ void *notify_cls; /** * Timeout for this request, 0 for control messages. */ struct GNUNET_TIME_Absolute timeout; /** * Task to trigger request timeout if the request is stalled due to * congestion. */ GNUNET_SCHEDULER_TaskIdentifier timeout_task; /** * How many bytes is our notify callback waiting for? */ size_t notify_size; /** * How important is this message? Not used for control messages. */ uint32_t priority; }; /** * Entry in hash table of all of our current neighbours. */ struct Neighbour { /** * Overall transport handle. */ struct GNUNET_TRANSPORT_Handle *h; /** * Active transmit handle or NULL. */ struct GNUNET_TRANSPORT_TransmitHandle *th; /** * Identity of this neighbour. */ struct GNUNET_PeerIdentity id; /** * Outbound bandwidh tracker. */ struct GNUNET_BANDWIDTH_Tracker out_tracker; /** * Entry in our readyness heap (which is sorted by 'next_ready' * value). NULL if there is no pending transmission request for * this neighbour or if we're waiting for 'is_ready' to become * true AFTER the 'out_tracker' suggested that this peer's quota * has been satisfied (so once 'is_ready' goes to GNUNET_YES, * we should immediately go back into the heap). */ struct GNUNET_CONTAINER_HeapNode *hn; /** * Is this peer currently ready to receive a message? */ int is_ready; }; /** * Linked list of functions to call whenever our HELLO is updated. */ struct GNUNET_TRANSPORT_GetHelloHandle { /** * This is a doubly linked list. */ struct GNUNET_TRANSPORT_GetHelloHandle *next; /** * This is a doubly linked list. */ struct GNUNET_TRANSPORT_GetHelloHandle *prev; /** * Transport handle. */ struct GNUNET_TRANSPORT_Handle *handle; /** * Callback to call once we got our HELLO. */ GNUNET_TRANSPORT_HelloUpdateCallback rec; /** * Closure for rec. */ void *rec_cls; }; /** * Handle for the transport service (includes all of the * state for the transport service). */ struct GNUNET_TRANSPORT_Handle { /** * Closure for the callbacks. */ void *cls; /** * Function to call for received data. */ GNUNET_TRANSPORT_ReceiveCallback rec; /** * function to call on connect events */ GNUNET_TRANSPORT_NotifyConnect nc_cb; /** * function to call on disconnect events */ GNUNET_TRANSPORT_NotifyDisconnect nd_cb; /** * Head of DLL of control messages. */ struct GNUNET_TRANSPORT_TransmitHandle *control_head; /** * Tail of DLL of control messages. */ struct GNUNET_TRANSPORT_TransmitHandle *control_tail; /** * The current HELLO message for this peer. Updated * whenever transports change their addresses. */ struct GNUNET_HELLO_Message *my_hello; /** * My client connection to the transport service. */ struct GNUNET_CLIENT_Connection *client; /** * Handle to our registration with the client for notification. */ struct GNUNET_CLIENT_TransmitHandle *cth; /** * Linked list of pending requests for our HELLO. */ struct GNUNET_TRANSPORT_GetHelloHandle *hwl_head; /** * Linked list of pending requests for our HELLO. */ struct GNUNET_TRANSPORT_GetHelloHandle *hwl_tail; /** * My configuration. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Hash map of the current connected neighbours of this peer. * Maps peer identities to 'struct Neighbour' entries. */ struct GNUNET_CONTAINER_MultiHashMap *neighbours; /** * Heap sorting peers with pending messages by the timestamps that * specify when we could next send a message to the respective peer. * Excludes control messages (which can always go out immediately). * Maps time stamps to 'struct Neighbour' entries. */ struct GNUNET_CONTAINER_Heap *ready_heap; /** * Peer identity as assumed by this process, or all zeros. */ struct GNUNET_PeerIdentity self; /** * ID of the task trying to reconnect to the service. */ GNUNET_SCHEDULER_TaskIdentifier reconnect_task; /** * ID of the task trying to trigger transmission for a peer while * maintaining bandwidth quotas. In use if there are no control * messages and the smallest entry in the 'ready_heap' has a time * stamp in the future. */ GNUNET_SCHEDULER_TaskIdentifier quota_task; /** * Delay until we try to reconnect. */ struct GNUNET_TIME_Relative reconnect_delay; /** * Should we check that 'self' matches what the service thinks? * (if GNUNET_NO, then 'self' is all zeros!). */ int check_self; }; /** * Schedule the task to send one message, either from the control * list or the peer message queues to the service. * * @param h transport service to schedule a transmission for */ static void schedule_transmission (struct GNUNET_TRANSPORT_Handle *h); /** * Function that will schedule the job that will try * to connect us again to the client. * * @param h transport service to reconnect */ static void disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_Handle *h); /** * Get the neighbour list entry for the given peer * * @param h our context * @param peer peer to look up * @return NULL if no such peer entry exists */ static struct Neighbour * neighbour_find (struct GNUNET_TRANSPORT_Handle *h, const struct GNUNET_PeerIdentity *peer) { return GNUNET_CONTAINER_multihashmap_get (h->neighbours, &peer->hashPubKey); } /** * Add neighbour to our list * * @return NULL if this API is currently disconnecting from the service */ static struct Neighbour * neighbour_add (struct GNUNET_TRANSPORT_Handle *h, const struct GNUNET_PeerIdentity *pid) { struct Neighbour *n; LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating entry for neighbour `%4s'.\n", GNUNET_i2s (pid)); n = GNUNET_malloc (sizeof (struct Neighbour)); n->id = *pid; n->h = h; n->is_ready = GNUNET_YES; GNUNET_BANDWIDTH_tracker_init (&n->out_tracker, GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT, MAX_BANDWIDTH_CARRY_S); GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (h->neighbours, &pid->hashPubKey, n, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); return n; } /** * Iterator over hash map entries, for deleting state of a neighbour. * * @param cls the 'struct GNUNET_TRANSPORT_Handle*' * @param key peer identity * @param value value in the hash map, the neighbour entry to delete * @return GNUNET_YES if we should continue to * iterate, * GNUNET_NO if not. */ static int neighbour_delete (void *cls, const GNUNET_HashCode * key, void *value) { struct GNUNET_TRANSPORT_Handle *handle = cls; struct Neighbour *n = value; if (NULL != handle->nd_cb) handle->nd_cb (handle->cls, &n->id); GNUNET_assert (NULL == n->th); GNUNET_assert (NULL == n->hn); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (handle->neighbours, key, n)); GNUNET_free (n); return GNUNET_YES; } /** * Function we use for handling incoming messages. * * @param cls closure (struct GNUNET_TRANSPORT_Handle *) * @param msg message received, NULL on timeout or fatal error */ static void demultiplexer (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_TRANSPORT_Handle *h = cls; const struct DisconnectInfoMessage *dim; const struct ConnectInfoMessage *cim; const struct InboundMessage *im; const struct GNUNET_MessageHeader *imm; const struct SendOkMessage *okm; const struct QuotaSetMessage *qm; const struct GNUNET_ATS_Information *ats; struct GNUNET_TRANSPORT_GetHelloHandle *hwl; struct GNUNET_TRANSPORT_GetHelloHandle *next_hwl; struct Neighbour *n; struct GNUNET_PeerIdentity me; uint16_t size; uint32_t ats_count; GNUNET_assert (h->client != NULL); if (msg == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Error receiving from transport service, disconnecting temporarily.\n"); disconnect_and_schedule_reconnect (h); return; } GNUNET_CLIENT_receive (h->client, &demultiplexer, h, GNUNET_TIME_UNIT_FOREVER_REL); size = ntohs (msg->size); switch (ntohs (msg->type)) { case GNUNET_MESSAGE_TYPE_HELLO: if (GNUNET_OK != GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) msg, &me)) { GNUNET_break (0); break; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving (my own) `%s' message, I am `%4s'.\n", "HELLO", GNUNET_i2s (&me)); GNUNET_free_non_null (h->my_hello); h->my_hello = NULL; if (size < sizeof (struct GNUNET_MessageHeader)) { GNUNET_break (0); break; } h->my_hello = GNUNET_malloc (size); memcpy (h->my_hello, msg, size); hwl = h->hwl_head; while (NULL != hwl) { next_hwl = hwl->next; hwl->rec (hwl->rec_cls, (const struct GNUNET_MessageHeader *) h->my_hello); hwl = next_hwl; } break; case GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT: if (size < sizeof (struct ConnectInfoMessage)) { GNUNET_break (0); break; } cim = (const struct ConnectInfoMessage *) msg; ats_count = ntohl (cim->ats_count); if (size != sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_ATS_Information)) { GNUNET_break (0); break; } ats = (const struct GNUNET_ATS_Information *) &cim[1]; LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message for `%4s'.\n", "CONNECT", GNUNET_i2s (&cim->id)); n = neighbour_find (h, &cim->id); if (n != NULL) { GNUNET_break (0); break; } n = neighbour_add (h, &cim->id); if (h->nc_cb != NULL) h->nc_cb (h->cls, &n->id, ats, ats_count); break; case GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT: if (size != sizeof (struct DisconnectInfoMessage)) { GNUNET_break (0); break; } dim = (const struct DisconnectInfoMessage *) msg; GNUNET_break (ntohl (dim->reserved) == 0); LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message for `%4s'.\n", "DISCONNECT", GNUNET_i2s (&dim->peer)); n = neighbour_find (h, &dim->peer); if (n == NULL) { GNUNET_break (0); break; } neighbour_delete (h, &dim->peer.hashPubKey, n); break; case GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK: if (size != sizeof (struct SendOkMessage)) { GNUNET_break (0); break; } okm = (const struct SendOkMessage *) msg; LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message, transmission %s.\n", "SEND_OK", ntohl (okm->success) == GNUNET_OK ? "succeeded" : "failed"); n = neighbour_find (h, &okm->peer); if (n == NULL) break; GNUNET_break (GNUNET_NO == n->is_ready); n->is_ready = GNUNET_YES; if ((n->th != NULL) && (n->hn == NULL)) { GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != n->th->timeout_task); GNUNET_SCHEDULER_cancel (n->th->timeout_task); n->th->timeout_task = GNUNET_SCHEDULER_NO_TASK; /* we've been waiting for this (congestion, not quota, * caused delayed transmission) */ n->hn = GNUNET_CONTAINER_heap_insert (h->ready_heap, n, 0); schedule_transmission (h); } break; case GNUNET_MESSAGE_TYPE_TRANSPORT_RECV: LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message.\n", "RECV"); if (size < sizeof (struct InboundMessage) + sizeof (struct GNUNET_MessageHeader)) { GNUNET_break (0); break; } im = (const struct InboundMessage *) msg; ats_count = ntohl (im->ats_count); ats = (const struct GNUNET_ATS_Information *) &im[1]; imm = (const struct GNUNET_MessageHeader *) &ats[ats_count]; if (ntohs (imm->size) + sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_ATS_Information) != size) { GNUNET_break (0); break; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Received message of type %u from `%4s'.\n", ntohs (imm->type), GNUNET_i2s (&im->peer)); n = neighbour_find (h, &im->peer); if (n == NULL) { GNUNET_break (0); break; } if (h->rec != NULL) h->rec (h->cls, &im->peer, imm, ats, ats_count); break; case GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA: LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message.\n", "SET_QUOTA"); if (size != sizeof (struct QuotaSetMessage)) { GNUNET_break (0); break; } qm = (const struct QuotaSetMessage *) msg; n = neighbour_find (h, &qm->peer); if (n == NULL) break; GNUNET_BANDWIDTH_tracker_update_quota (&n->out_tracker, qm->quota); break; default: LOG (GNUNET_ERROR_TYPE_ERROR, _("Received unexpected message of type %u in %s:%u\n"), ntohs (msg->type), __FILE__, __LINE__); GNUNET_break (0); break; } } /** * A transmission request could not be satisfied because of * network congestion. Notify the initiator and clean up. * * @param cls the 'struct GNUNET_TRANSPORT_TransmitHandle' * @param tc scheduler context */ static void timeout_request_due_to_congestion (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TRANSPORT_TransmitHandle *th = cls; struct Neighbour *n = th->neighbour; n->th->timeout_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_assert (th == n->th); GNUNET_assert (NULL == n->hn); n->th = NULL; th->notify (th->notify_cls, 0, NULL); GNUNET_free (th); } /** * Transmit message(s) to service. * * @param cls handle to transport * @param size number of bytes available in buf * @param buf where to copy the message * @return number of bytes copied to buf */ static size_t transport_notify_ready (void *cls, size_t size, void *buf) { struct GNUNET_TRANSPORT_Handle *h = cls; struct GNUNET_TRANSPORT_TransmitHandle *th; struct Neighbour *n; char *cbuf; struct OutboundMessage obm; size_t ret; size_t nret; size_t mret; GNUNET_assert (NULL != h->client); h->cth = NULL; if (NULL == buf) { /* transmission failed */ disconnect_and_schedule_reconnect (h); return 0; } cbuf = buf; ret = 0; /* first send control messages */ while ((NULL != (th = h->control_head)) && (th->notify_size <= size)) { GNUNET_CONTAINER_DLL_remove (h->control_head, h->control_tail, th); nret = th->notify (th->notify_cls, size, &cbuf[ret]); LOG (GNUNET_ERROR_TYPE_DEBUG, "Added %u bytes of control message at %u\n", nret, ret); GNUNET_free (th); ret += nret; size -= nret; } /* then, if possible and no control messages pending, send data messages */ while ((NULL == h->control_head) && (NULL != (n = GNUNET_CONTAINER_heap_peek (h->ready_heap)))) { if (GNUNET_YES != n->is_ready) { /* peer not ready, wait for notification! */ GNUNET_assert (n == GNUNET_CONTAINER_heap_remove_root (h->ready_heap)); n->hn = NULL; GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == n->th->timeout_task); n->th->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (n->th->timeout), &timeout_request_due_to_congestion, n->th); continue; } th = n->th; if (th->notify_size + sizeof (struct OutboundMessage) > size) break; /* does not fit */ if (GNUNET_BANDWIDTH_tracker_get_delay (&n->out_tracker, th->notify_size).rel_value > 0) break; /* too early */ GNUNET_assert (n == GNUNET_CONTAINER_heap_remove_root (h->ready_heap)); n->hn = NULL; n->th = NULL; n->is_ready = GNUNET_NO; GNUNET_assert (size >= sizeof (struct OutboundMessage)); mret = th->notify (th->notify_cls, size - sizeof (struct OutboundMessage), &cbuf[ret + sizeof (struct OutboundMessage)]); GNUNET_assert (mret <= size - sizeof (struct OutboundMessage)); if (mret != 0) { GNUNET_assert (mret + sizeof (struct OutboundMessage) < GNUNET_SERVER_MAX_MESSAGE_SIZE); obm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND); obm.header.size = htons (mret + sizeof (struct OutboundMessage)); obm.priority = htonl (th->priority); obm.timeout = GNUNET_TIME_relative_hton (GNUNET_TIME_absolute_get_remaining (th->timeout)); obm.peer = n->id; memcpy (&cbuf[ret], &obm, sizeof (struct OutboundMessage)); ret += (mret + sizeof (struct OutboundMessage)); size -= (mret + sizeof (struct OutboundMessage)); GNUNET_BANDWIDTH_tracker_consume (&n->out_tracker, mret); } GNUNET_free (th); } /* if there are more pending messages, try to schedule those */ schedule_transmission (h); LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting %u bytes to transport service\n", ret); return ret; } /** * Schedule the task to send one message, either from the control * list or the peer message queues to the service. * * @param cls transport service to schedule a transmission for * @param tc scheduler context */ static void schedule_transmission_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TRANSPORT_Handle *h = cls; size_t size; struct GNUNET_TRANSPORT_TransmitHandle *th; struct Neighbour *n; h->quota_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_assert (NULL != h->client); /* destroy all requests that have timed out */ while ((NULL != (n = GNUNET_CONTAINER_heap_peek (h->ready_heap))) && (GNUNET_TIME_absolute_get_remaining (n->th->timeout).rel_value == 0)) { /* notify client that the request could not be satisfied within * the given time constraints */ th = n->th; n->th = NULL; GNUNET_assert (n == GNUNET_CONTAINER_heap_remove_root (h->ready_heap)); n->hn = NULL; LOG (GNUNET_ERROR_TYPE_DEBUG, "Signalling timeout for transmission to peer %s due to congestion\n", GNUNET_i2s (&n->id)); GNUNET_assert (0 == th->notify (th->notify_cls, 0, NULL)); GNUNET_free (th); } if (NULL != h->cth) return; if (NULL != h->control_head) { size = h->control_head->notify_size; } else { n = GNUNET_CONTAINER_heap_peek (h->ready_heap); if (NULL == n) return; /* no pending messages */ size = n->th->notify_size + sizeof (struct OutboundMessage); } LOG (GNUNET_ERROR_TYPE_DEBUG, "Calling notify_transmit_ready\n"); h->cth = GNUNET_CLIENT_notify_transmit_ready (h->client, size, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_NO, &transport_notify_ready, h); GNUNET_assert (NULL != h->cth); } /** * Schedule the task to send one message, either from the control * list or the peer message queues to the service. * * @param h transport service to schedule a transmission for */ static void schedule_transmission (struct GNUNET_TRANSPORT_Handle *h) { struct GNUNET_TIME_Relative delay; struct Neighbour *n; GNUNET_assert (NULL != h->client); if (h->quota_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (h->quota_task); h->quota_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != h->control_head) delay = GNUNET_TIME_UNIT_ZERO; else if (NULL != (n = GNUNET_CONTAINER_heap_peek (h->ready_heap))) delay = GNUNET_BANDWIDTH_tracker_get_delay (&n->out_tracker, n->th->notify_size); else return; /* no work to be done */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Scheduling next transmission to service in %llu ms\n", (unsigned long long) delay.rel_value); h->quota_task = GNUNET_SCHEDULER_add_delayed (delay, &schedule_transmission_task, h); } /** * Queue control request for transmission to the transport * service. * * @param h handle to the transport service * @param size number of bytes to be transmitted * @param notify function to call to get the content * @param notify_cls closure for notify */ static void schedule_control_transmit (struct GNUNET_TRANSPORT_Handle *h, size_t size, GNUNET_CONNECTION_TransmitReadyNotify notify, void *notify_cls) { struct GNUNET_TRANSPORT_TransmitHandle *th; LOG (GNUNET_ERROR_TYPE_DEBUG, "Control transmit of %u bytes requested\n", size); th = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_TransmitHandle)); th->notify = notify; th->notify_cls = notify_cls; th->notify_size = size; GNUNET_CONTAINER_DLL_insert_tail (h->control_head, h->control_tail, th); schedule_transmission (h); } /** * Transmit START message to service. * * @param cls unused * @param size number of bytes available in buf * @param buf where to copy the message * @return number of bytes copied to buf */ static size_t send_start (void *cls, size_t size, void *buf) { struct GNUNET_TRANSPORT_Handle *h = cls; struct StartMessage s; uint32_t options; if (buf == NULL) { /* Can only be shutdown, just give up */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutdown while trying to transmit `%s' request.\n", "START"); return 0; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' request.\n", "START"); GNUNET_assert (size >= sizeof (struct StartMessage)); s.header.size = htons (sizeof (struct StartMessage)); s.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_START); options = 0; if (h->check_self) options |= 1; if (h->rec != NULL) options |= 2; s.options = htonl (options); s.self = h->self; memcpy (buf, &s, sizeof (struct StartMessage)); GNUNET_CLIENT_receive (h->client, &demultiplexer, h, GNUNET_TIME_UNIT_FOREVER_REL); return sizeof (struct StartMessage); } /** * Try again to connect to transport service. * * @param cls the handle to the transport service * @param tc scheduler context */ static void reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TRANSPORT_Handle *h = cls; h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) { /* shutdown, just give up */ return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to transport service.\n"); GNUNET_assert (h->client == NULL); GNUNET_assert (h->control_head == NULL); GNUNET_assert (h->control_tail == NULL); h->client = GNUNET_CLIENT_connect ("transport", h->cfg); GNUNET_assert (h->client != NULL); schedule_control_transmit (h, sizeof (struct StartMessage), &send_start, h); } /** * Function that will schedule the job that will try * to connect us again to the client. * * @param h transport service to reconnect */ static void disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_Handle *h) { struct GNUNET_TRANSPORT_TransmitHandle *th; GNUNET_assert (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK); if (NULL != h->cth) { GNUNET_CLIENT_notify_transmit_ready_cancel (h->cth); h->cth = NULL; } if (NULL != h->client) { GNUNET_CLIENT_disconnect (h->client); h->client = NULL; } /* Forget about all neighbours that we used to be connected to */ GNUNET_CONTAINER_multihashmap_iterate (h->neighbours, &neighbour_delete, h); if (h->quota_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (h->quota_task); h->quota_task = GNUNET_SCHEDULER_NO_TASK; } while ((NULL != (th = h->control_head))) { GNUNET_CONTAINER_DLL_remove (h->control_head, h->control_tail, th); th->notify (th->notify_cls, 0, NULL); GNUNET_free (th); } LOG (GNUNET_ERROR_TYPE_DEBUG, "Scheduling task to reconnect to transport service in %llu ms.\n", h->reconnect_delay.rel_value); h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h); if (h->reconnect_delay.rel_value == 0) { h->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; } else { h->reconnect_delay = GNUNET_TIME_relative_multiply (h->reconnect_delay, 2); h->reconnect_delay = GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS, h->reconnect_delay); } } /** * Send REQUEST_CONNECT message to the service. * * @param cls the 'struct GNUNET_PeerIdentity' * @param size number of bytes available in buf * @param buf where to copy the message * @return number of bytes copied to buf */ static size_t send_try_connect (void *cls, size_t size, void *buf) { struct GNUNET_PeerIdentity *pid = cls; struct TransportRequestConnectMessage msg; if (buf == NULL) { GNUNET_free (pid); return 0; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' request with respect to `%4s'.\n", "REQUEST_CONNECT", GNUNET_i2s (pid)); GNUNET_assert (size >= sizeof (struct TransportRequestConnectMessage)); msg.header.size = htons (sizeof (struct TransportRequestConnectMessage)); msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT); msg.reserved = htonl (0); msg.peer = *pid; memcpy (buf, &msg, sizeof (msg)); GNUNET_free (pid); return sizeof (struct TransportRequestConnectMessage); } /** * Ask the transport service to establish a connection to * the given peer. * * @param handle connection to transport service * @param target who we should try to connect to */ void GNUNET_TRANSPORT_try_connect (struct GNUNET_TRANSPORT_Handle *handle, const struct GNUNET_PeerIdentity *target) { struct GNUNET_PeerIdentity *pid; if (NULL == handle->client) return; pid = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity)); *pid = *target; schedule_control_transmit (handle, sizeof (struct TransportRequestConnectMessage), &send_try_connect, pid); } /** * Send HELLO message to the service. * * @param cls the HELLO message to send * @param size number of bytes available in buf * @param buf where to copy the message * @return number of bytes copied to buf */ static size_t send_hello (void *cls, size_t size, void *buf) { struct GNUNET_MessageHeader *msg = cls; uint16_t ssize; if (buf == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Timeout while trying to transmit `%s' request.\n", "HELLO"); GNUNET_free (msg); return 0; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' request.\n", "HELLO"); ssize = ntohs (msg->size); GNUNET_assert (size >= ssize); memcpy (buf, msg, ssize); GNUNET_free (msg); return ssize; } /** * Offer the transport service the HELLO of another peer. Note that * the transport service may just ignore this message if the HELLO is * malformed or useless due to our local configuration. * * @param handle connection to transport service * @param hello the hello message * @param cont continuation to call when HELLO has been sent * @param cls closure for continuation * */ void GNUNET_TRANSPORT_offer_hello (struct GNUNET_TRANSPORT_Handle *handle, const struct GNUNET_MessageHeader *hello, GNUNET_SCHEDULER_Task cont, void *cls) { uint16_t size; struct GNUNET_PeerIdentity peer; struct GNUNET_MessageHeader *msg; if (NULL == handle->client) return; GNUNET_break (ntohs (hello->type) == GNUNET_MESSAGE_TYPE_HELLO); size = ntohs (hello->size); GNUNET_break (size >= sizeof (struct GNUNET_MessageHeader)); if (GNUNET_OK != GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) hello, &peer)) { GNUNET_break (0); return; } msg = GNUNET_malloc (size); memcpy (msg, hello, size); LOG (GNUNET_ERROR_TYPE_DEBUG, "Offering `%s' message of `%4s' to transport for validation.\n", "HELLO", GNUNET_i2s (&peer)); schedule_control_transmit (handle, size, &send_hello, msg); } /** * Obtain the HELLO message for this peer. * * @param handle connection to transport service * @param rec function to call with the HELLO, sender will be our peer * identity; message and sender will be NULL on timeout * (handshake with transport service pending/failed). * cost estimate will be 0. * @param rec_cls closure for rec * @return handle to cancel the operation */ struct GNUNET_TRANSPORT_GetHelloHandle * GNUNET_TRANSPORT_get_hello (struct GNUNET_TRANSPORT_Handle *handle, GNUNET_TRANSPORT_HelloUpdateCallback rec, void *rec_cls) { struct GNUNET_TRANSPORT_GetHelloHandle *hwl; hwl = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_GetHelloHandle)); hwl->rec = rec; hwl->rec_cls = rec_cls; hwl->handle = handle; GNUNET_CONTAINER_DLL_insert (handle->hwl_head, handle->hwl_tail, hwl); if (handle->my_hello != NULL) rec (rec_cls, (const struct GNUNET_MessageHeader *) handle->my_hello); return hwl; } /** * Stop receiving updates about changes to our HELLO message. * * @param ghh handle to cancel */ void GNUNET_TRANSPORT_get_hello_cancel (struct GNUNET_TRANSPORT_GetHelloHandle *ghh) { struct GNUNET_TRANSPORT_Handle *handle = ghh->handle; GNUNET_CONTAINER_DLL_remove (handle->hwl_head, handle->hwl_tail, ghh); GNUNET_free (ghh); } /** * Connect to the transport service. Note that the connection may * complete (or fail) asynchronously. * * @param cfg configuration to use * @param self our own identity (API should check that it matches * the identity found by transport), or NULL (no check) * @param cls closure for the callbacks * @param rec receive function to call * @param nc function to call on connect events * @param nd function to call on disconnect events */ struct GNUNET_TRANSPORT_Handle * GNUNET_TRANSPORT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, const struct GNUNET_PeerIdentity *self, void *cls, GNUNET_TRANSPORT_ReceiveCallback rec, GNUNET_TRANSPORT_NotifyConnect nc, GNUNET_TRANSPORT_NotifyDisconnect nd) { struct GNUNET_TRANSPORT_Handle *ret; ret = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_Handle)); if (self != NULL) { ret->self = *self; ret->check_self = GNUNET_YES; } ret->cfg = cfg; ret->cls = cls; ret->rec = rec; ret->nc_cb = nc; ret->nd_cb = nd; ret->reconnect_delay = GNUNET_TIME_UNIT_ZERO; ret->neighbours = GNUNET_CONTAINER_multihashmap_create (STARTING_NEIGHBOURS_SIZE); ret->ready_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); ret->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, ret); return ret; } /** * Disconnect from the transport service. * * @param handle handle to the service as returned from GNUNET_TRANSPORT_connect */ void GNUNET_TRANSPORT_disconnect (struct GNUNET_TRANSPORT_Handle *handle) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Transport disconnect called!\n"); /* this disconnects all neighbours... */ if (handle->reconnect_task == GNUNET_SCHEDULER_NO_TASK) disconnect_and_schedule_reconnect (handle); /* and now we stop trying to connect again... */ if (handle->reconnect_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (handle->reconnect_task); handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_CONTAINER_multihashmap_destroy (handle->neighbours); handle->neighbours = NULL; if (handle->quota_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (handle->quota_task); handle->quota_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_free_non_null (handle->my_hello); handle->my_hello = NULL; GNUNET_assert (handle->hwl_head == NULL); GNUNET_assert (handle->hwl_tail == NULL); GNUNET_CONTAINER_heap_destroy (handle->ready_heap); handle->ready_heap = NULL; GNUNET_free (handle); } /** * Check if we could queue a message of the given size for * transmission. The transport service will take both its * internal buffers and bandwidth limits imposed by the * other peer into consideration when answering this query. * * @param handle connection to transport service * @param target who should receive the message * @param size how big is the message we want to transmit? * @param priority how important is the message? * @param timeout after how long should we give up (and call * notify with buf NULL and size 0)? * @param notify function to call when we are ready to * send such a message * @param notify_cls closure for notify * @return NULL if someone else is already waiting to be notified * non-NULL if the notify callback was queued (can be used to cancel * using GNUNET_TRANSPORT_notify_transmit_ready_cancel) */ struct GNUNET_TRANSPORT_TransmitHandle * GNUNET_TRANSPORT_notify_transmit_ready (struct GNUNET_TRANSPORT_Handle *handle, const struct GNUNET_PeerIdentity *target, size_t size, uint32_t priority, struct GNUNET_TIME_Relative timeout, GNUNET_CONNECTION_TransmitReadyNotify notify, void *notify_cls) { struct Neighbour *n; struct GNUNET_TRANSPORT_TransmitHandle *th; struct GNUNET_TIME_Relative delay; n = neighbour_find (handle, target); if (NULL == n) { /* use GNUNET_TRANSPORT_try_connect first, only use this function * once a connection has been established */ GNUNET_assert (0); return NULL; } if (NULL != n->th) { /* attempt to send two messages at the same time to the same peer */ GNUNET_assert (0); return NULL; } GNUNET_assert (NULL == n->hn); th = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_TransmitHandle)); th->neighbour = n; th->notify = notify; th->notify_cls = notify_cls; th->timeout = GNUNET_TIME_relative_to_absolute (timeout); th->notify_size = size; th->priority = priority; n->th = th; /* calculate when our transmission should be ready */ delay = GNUNET_BANDWIDTH_tracker_get_delay (&n->out_tracker, size); if (delay.rel_value > timeout.rel_value) delay.rel_value = 0; /* notify immediately (with failure) */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Bandwidth tracker allows next transmission to peer %s in %llu ms\n", GNUNET_i2s (target), (unsigned long long) delay.rel_value); n->hn = GNUNET_CONTAINER_heap_insert (handle->ready_heap, n, delay.rel_value); schedule_transmission (handle); return th; } /** * Cancel the specified transmission-ready notification. * * @param th handle returned from GNUNET_TRANSPORT_notify_transmit_ready */ void GNUNET_TRANSPORT_notify_transmit_ready_cancel (struct GNUNET_TRANSPORT_TransmitHandle *th) { struct Neighbour *n; GNUNET_assert (NULL == th->next); GNUNET_assert (NULL == th->prev); n = th->neighbour; GNUNET_assert (th == n->th); n->th = NULL; if (n->hn != NULL) { GNUNET_CONTAINER_heap_remove_node (n->hn); n->hn = NULL; } else { GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != th->timeout_task); GNUNET_SCHEDULER_cancel (th->timeout_task); th->timeout_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_free (th); } /* end of transport_api.c */ gnunet-0.9.3/src/transport/gnunet-service-transport_blacklist.h0000644000175000017500000000723111760502551021765 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/gnunet-service-transport_blacklist.h * @brief blacklisting API * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_TRANSPORT_BLACKLIST_H #define GNUNET_SERVICE_TRANSPORT_BLACKLIST_H #include "gnunet_statistics_service.h" #include "gnunet_util_lib.h" /** * Start blacklist subsystem. * * @param server server used to accept clients from */ void GST_blacklist_start (struct GNUNET_SERVER_Handle *server); /** * Stop blacklist subsystem. */ void GST_blacklist_stop (void); /** * Initialize a blacklisting client. We got a blacklist-init * message from this client, add him to the list of clients * to query for blacklisting. * * @param cls unused * @param client the client * @param message the blacklist-init message that was sent */ void GST_blacklist_handle_init (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message); /** * A blacklisting client has sent us reply. Process it. * * @param cls unused * @param client the client * @param message the blacklist-init message that was sent */ void GST_blacklist_handle_reply (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message); /** * Add the given peer to the blacklist (for the given transport). * * @param peer peer to blacklist * @param transport_name transport to blacklist for this peer, NULL for all */ void GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer, const char *transport_name); /** * Handle to an active blacklist check. */ struct GST_BlacklistCheck; /** * Continuation called from a blacklist test. * * @param cls closure * @param peer identity of peer that was tested * @param result GNUNET_OK if the connection is allowed, * GNUNET_NO if not */ typedef void (*GST_BlacklistTestContinuation) (void *cls, const struct GNUNET_PeerIdentity * peer, int result); /** * Test if a peer/transport combination is blacklisted. * * @param peer the identity of the peer to test * @param transport_name name of the transport to test, never NULL * @param cont function to call with result * @param cont_cls closure for 'cont' * @return handle to the blacklist check, NULL if the decision * was made instantly and 'cont' was already called */ struct GST_BlacklistCheck * GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer, const char *transport_name, GST_BlacklistTestContinuation cont, void *cont_cls); /** * Cancel a blacklist check. * * @param bc check to cancel */ void GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc); #endif /* end of file gnunet-service-transport_blacklist.h */ gnunet-0.9.3/src/transport/gnunet-service-transport_plugins.h0000644000175000017500000000522111760502551021473 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/gnunet-service-transport_plugins.h * @brief plugin management API * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_TRANSPORT_PLUGINS_H #define GNUNET_SERVICE_TRANSPORT_PLUGINS_H #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" #include "gnunet_transport_plugin.h" #include "gnunet_util_lib.h" #include "gnunet_hello_lib.h" /** * Load and initialize all plugins. The respective functions will be * invoked by the plugins when the respective events happen. The * closure will be set to a 'const char*' containing the name of the * plugin that caused the call. * * @param recv_cb function to call when data is received * @param address_cb function to call when our public addresses changed * @param session_end_cb function to call when a session was terminated * @param address_type_cb function to call when a address type is requested */ void GST_plugins_load (GNUNET_TRANSPORT_PluginReceiveCallback recv_cb, GNUNET_TRANSPORT_AddressNotification address_cb, GNUNET_TRANSPORT_SessionEnd session_end_cb, GNUNET_TRANSPORT_AddressToType address_type_cb); /** * Unload all plugins */ void GST_plugins_unload (void); /** * Obtain the plugin API based on a plugin name. * * @param name name of the plugin * @return the plugin's API, NULL if the plugin is not loaded */ struct GNUNET_TRANSPORT_PluginFunctions * GST_plugins_find (const char *name); /** * Convert a given address to a human-readable format. Note that the * return value will be overwritten on the next call to this function. * * @param address address to convert * @return statically allocated (!) human-readable address */ const char * GST_plugins_a2s (const struct GNUNET_HELLO_Address *address); #endif /* end of file gnunet-service-transport_plugins.h */ gnunet-0.9.3/src/transport/gnunet-service-transport.c0000644000175000017500000005326011761753145017743 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file transport/gnunet-service-transport.c * @brief * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_hello_lib.h" #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" #include "gnunet_peerinfo_service.h" #include "gnunet_ats_service.h" #include "gnunet-service-transport.h" #include "gnunet-service-transport_blacklist.h" #include "gnunet-service-transport_clients.h" #include "gnunet-service-transport_hello.h" #include "gnunet-service-transport_neighbours.h" #include "gnunet-service-transport_plugins.h" #include "gnunet-service-transport_validation.h" #include "transport.h" /* globals */ /** * Statistics handle. */ struct GNUNET_STATISTICS_Handle *GST_stats; /** * Configuration handle. */ const struct GNUNET_CONFIGURATION_Handle *GST_cfg; /** * Configuration handle. */ struct GNUNET_PeerIdentity GST_my_identity; /** * Handle to peerinfo service. */ struct GNUNET_PEERINFO_Handle *GST_peerinfo; /** * Our public key. */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded GST_my_public_key; /** * Our private key. */ struct GNUNET_CRYPTO_RsaPrivateKey *GST_my_private_key; /** * ATS handle. */ struct GNUNET_ATS_SchedulingHandle *GST_ats; /** * DEBUGGING connection counter */ static int connections; /** * Transmit our HELLO message to the given (connected) neighbour. * * @param cls the 'HELLO' message * @param target a connected neighbour * @param ats performance information (unused) * @param ats_count number of records in ats (unused) * @param address the address */ static void transmit_our_hello (void *cls, const struct GNUNET_PeerIdentity *target, const struct GNUNET_ATS_Information *ats, uint32_t ats_count, const struct GNUNET_HELLO_Address *address) { const struct GNUNET_MessageHeader *hello = cls; GST_neighbours_send (target, (const char *) hello, ntohs (hello->size), GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION, NULL, NULL); } /** * My HELLO has changed. Tell everyone who should know. * * @param cls unused * @param hello new HELLO */ static void process_hello_update (void *cls, const struct GNUNET_MessageHeader *hello) { GST_clients_broadcast (hello, GNUNET_NO); GST_neighbours_iterate (&transmit_our_hello, (void *) hello); } /** * We received some payload. Prepare to pass it on to our clients. * * @param peer (claimed) identity of the other peer * @param address the address * @param session session used * @param message the message to process * @param ats performance information * @param ats_count number of records in ats * @return how long the plugin should wait until receiving more data */ static struct GNUNET_TIME_Relative process_payload (const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Address *address, struct Session *session, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { struct GNUNET_TIME_Relative ret; int do_forward; struct InboundMessage *im; size_t msg_size = ntohs (message->size); size_t size = sizeof (struct InboundMessage) + msg_size + sizeof (struct GNUNET_ATS_Information) * (ats_count + 1); char buf[size] GNUNET_ALIGN; struct GNUNET_ATS_Information *ap; ret = GNUNET_TIME_UNIT_ZERO; do_forward = GNUNET_SYSERR; ret = GST_neighbours_calculate_receive_delay (peer, msg_size, &do_forward); if (!GST_neighbours_test_connected (peer)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Discarded %u bytes type %u payload from peer `%s'\n", msg_size, ntohs (message->type), GNUNET_i2s (peer)); GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# bytes payload discarded due to not connected peer "), msg_size, GNUNET_NO); return ret; } if (do_forward != GNUNET_YES) return ret; im = (struct InboundMessage *) buf; im->header.size = htons (size); im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV); im->ats_count = htonl (ats_count + 1); im->peer = *peer; ap = (struct GNUNET_ATS_Information *) &im[1]; memcpy (ap, ats, ats_count * sizeof (struct GNUNET_ATS_Information)); ap[ats_count].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY); ap[ats_count].value = htonl ((uint32_t) GST_neighbour_get_latency (peer).rel_value); memcpy (&ap[ats_count + 1], message, ntohs (message->size)); GNUNET_ATS_address_update (GST_ats, address, session, ap, ats_count + 1); GST_clients_broadcast (&im->header, GNUNET_YES); return ret; } /** * Function called by the transport for each received message. * This function should also be called with "NULL" for the * message to signal that the other peer disconnected. * * @param cls closure, const char* with the name of the plugin we received the message from * @param peer (claimed) identity of the other peer * @param message the message, NULL if we only care about * learning about the delay until we should receive again -- FIXME! * @param ats performance information * @param ats_count number of records in ats * @param session identifier used for this session (NULL for plugins * that do not offer bi-directional communication to the sender * using the same "connection") * @param sender_address binary address of the sender (if we established the * connection or are otherwise sure of it; should be NULL * for inbound TCP/UDP connections since it it not clear * that we could establish ourselves a connection to that * IP address and get the same system) * @param sender_address_len number of bytes in sender_address * @return how long the plugin should wait until receiving more data * (plugins that do not support this, can ignore the return value) */ static struct GNUNET_TIME_Relative plugin_env_receive_callback (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *ats, uint32_t ats_count, struct Session *session, const char *sender_address, uint16_t sender_address_len) { const char *plugin_name = cls; struct GNUNET_TIME_Relative ret; struct GNUNET_HELLO_Address address; uint16_t type; address.peer = *peer; address.address = sender_address; address.address_length = sender_address_len; address.transport_name = plugin_name; ret = GNUNET_TIME_UNIT_ZERO; if (NULL == message) goto end; type = ntohs (message->type); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received Message with type %u from peer `%s'\n", type, GNUNET_i2s (peer)); GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# bytes total received"), ntohs (message->size), GNUNET_NO); switch (type) { case GNUNET_MESSAGE_TYPE_HELLO: GST_validation_handle_hello (message); return ret; case GNUNET_MESSAGE_TYPE_TRANSPORT_PING: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "Processing `%s' from `%s'\n", "PING", (sender_address != NULL) ? GST_plugins_a2s (&address) : ""); GST_validation_handle_ping (peer, message, &address, session); break; case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "Processing `%s' from `%s'\n", "PONG", (sender_address != NULL) ? GST_plugins_a2s (&address) : ""); GST_validation_handle_pong (peer, message); break; case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT: GST_neighbours_handle_connect (message, peer, &address, session, ats, ats_count); break; case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT_ACK: GST_neighbours_handle_connect_ack (message, peer, &address, session, ats, ats_count); break; case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK: GST_neighbours_handle_session_ack (message, peer, &address, session, ats, ats_count); break; case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT: GST_neighbours_handle_disconnect_message (peer, message); break; case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE: GST_neighbours_keepalive (peer); break; case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE: GST_neighbours_keepalive_response (peer, ats, ats_count); break; default: /* should be payload */ GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# bytes payload received"), ntohs (message->size), GNUNET_NO); ret = process_payload (peer, &address, session, message, ats, ats_count); break; } end: #if 1 /* FIXME: this should not be needed, and not sure it's good to have it, but without * this connections seem to go extra-slow */ GNUNET_ATS_address_update (GST_ats, &address, session, ats, ats_count); #endif GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Allowing receive from peer %s to continue in %llu ms\n", GNUNET_i2s (peer), (unsigned long long) ret.rel_value); return ret; } /** * Function that will be called for each address the transport * is aware that it might be reachable under. Update our HELLO. * * @param cls name of the plugin (const char*) * @param add_remove should the address added (YES) or removed (NO) from the * set of valid addresses? * @param addr one of the addresses of the host * the specific address format depends on the transport * @param addrlen length of the address */ static void plugin_env_address_change_notification (void *cls, int add_remove, const void *addr, size_t addrlen) { const char *plugin_name = cls; struct GNUNET_HELLO_Address address; address.peer = GST_my_identity; address.transport_name = plugin_name; address.address = addr; address.address_length = addrlen; GST_hello_modify_addresses (add_remove, &address); } /** * Function that will be called whenever the plugin internally * cleans up a session pointer and hence the service needs to * discard all of those sessions as well. Plugins that do not * use sessions can simply omit calling this function and always * use NULL wherever a session pointer is needed. This function * should be called BEFORE a potential "TransmitContinuation" * from the "TransmitFunction". * * @param cls closure * @param peer which peer was the session for * @param session which session is being destoyed */ static void plugin_env_session_end (void *cls, const struct GNUNET_PeerIdentity *peer, struct Session *session) { const char *transport_name = cls; struct GNUNET_HELLO_Address address; GNUNET_assert (strlen (transport_name) > 0); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Session %X to peer `%s' ended \n", session, GNUNET_i2s (peer)); if (NULL != session) GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "transport-ats", "Telling ATS to destroy session %p from peer %s\n", session, GNUNET_i2s (peer)); address.peer = *peer; address.address = NULL; address.address_length = 0; address.transport_name = transport_name; GST_neighbours_session_terminated (peer, session); GNUNET_ATS_address_destroyed (GST_ats, &address, session); } /** * Function that will be called to figure if an address is an loopback, * LAN, WAN etc. address * * @param cls closure * @param addr binary address * @param addrlen length of the address * @return ATS Information containing the network type */ static struct GNUNET_ATS_Information plugin_env_address_to_type (void *cls, const struct sockaddr *addr, size_t addrlen) { struct GNUNET_ATS_Information ats; ats.type = htonl (GNUNET_ATS_NETWORK_TYPE); ats.value = htonl (GNUNET_ATS_NET_UNSPECIFIED); if (GST_ats == NULL) { GNUNET_break (0); return ats; } if (((addr->sa_family != AF_INET) && (addrlen != sizeof (struct sockaddr_in))) && ((addr->sa_family != AF_INET6) && (addrlen != sizeof (struct sockaddr_in6))) && (addr->sa_family != AF_UNIX)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed address with length %u `%s'\n", addrlen, GNUNET_a2s(addr, addrlen)); GNUNET_break (0); return (const struct GNUNET_ATS_Information) ats; } return GNUNET_ATS_address_get_type(GST_ats, addr, addrlen); } /** * Function called by ATS to notify the callee that the * assigned bandwidth or address for a given peer was changed. If the * callback is called with address/bandwidth assignments of zero, the * ATS disconnect function will still be called once the disconnect * actually happened. * * @param cls closure * @param address address to use (for peer given in address) * @param session session to use (if available) * @param bandwidth_out assigned outbound bandwidth for the connection, 0 to disconnect from peer * @param bandwidth_in assigned inbound bandwidth for the connection, 0 to disconnect from peer * @param ats ATS information * @param ats_count number of ATS elements */ static void ats_request_address_change (void *cls, const struct GNUNET_HELLO_Address *address, struct Session *session, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { uint32_t bw_in = ntohl (bandwidth_in.value__); uint32_t bw_out = ntohl (bandwidth_out.value__); /* ATS tells me to disconnect from peer */ if ((bw_in == 0) && (bw_out == 0)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS tells me to disconnect from peer `%s'\n", GNUNET_i2s (&address->peer)); GST_neighbours_force_disconnect (&address->peer); return; } GST_neighbours_switch_to_address (&address->peer, address, session, ats, ats_count, bandwidth_in, bandwidth_out); } /** * Function called to notify transport users that another * peer connected to us. * * @param cls closure * @param peer the peer that connected * @param ats performance data * @param ats_count number of entries in ats */ static void neighbours_connect_notification (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { size_t len = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_ATS_Information); char buf[len] GNUNET_ALIGN; struct ConnectInfoMessage *connect_msg = (struct ConnectInfoMessage *) buf; struct GNUNET_ATS_Information *ap; connections++; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "We are now connected to peer `%s' and %u peers in total\n", GNUNET_i2s (peer), connections); connect_msg->header.size = htons (sizeof (buf)); connect_msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT); connect_msg->ats_count = htonl (ats_count); connect_msg->id = *peer; ap = (struct GNUNET_ATS_Information *) &connect_msg[1]; memcpy (ap, ats, ats_count * sizeof (struct GNUNET_ATS_Information)); GST_clients_broadcast (&connect_msg->header, GNUNET_NO); } /** * Function called to notify transport users that another * peer disconnected from us. * * @param cls closure * @param peer the peer that disconnected */ static void neighbours_disconnect_notification (void *cls, const struct GNUNET_PeerIdentity *peer) { struct DisconnectInfoMessage disconnect_msg; connections--; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer `%s' disconnected and we are connected to %u peers\n", GNUNET_i2s (peer), connections); disconnect_msg.header.size = htons (sizeof (struct DisconnectInfoMessage)); disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT); disconnect_msg.reserved = htonl (0); disconnect_msg.peer = *peer; GST_clients_broadcast (&disconnect_msg.header, GNUNET_NO); } /** * Function called to notify transport users that a neighbour peer changed its * active address. * * @param cls closure * @param peer peer this update is about (never NULL) * @param address address, NULL on disconnect */ static void neighbours_address_notification (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Address *address) { GST_clients_broadcast_address_notification (peer, address); } /** * Function called when the service shuts down. Unloads our plugins * and cancels pending validations. * * @param cls closure, unused * @param tc task context (unused) */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GST_neighbours_stop (); GST_validation_stop (); GST_plugins_unload (); GNUNET_ATS_scheduling_done (GST_ats); GST_ats = NULL; GST_clients_stop (); GST_blacklist_stop (); GST_hello_stop (); if (GST_peerinfo != NULL) { GNUNET_PEERINFO_disconnect (GST_peerinfo); GST_peerinfo = NULL; } if (GST_stats != NULL) { GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO); GST_stats = NULL; } if (GST_my_private_key != NULL) { GNUNET_CRYPTO_rsa_key_free (GST_my_private_key); GST_my_private_key = NULL; } } /** * Initiate transport service. * * @param cls closure * @param server the initialized server * @param c configuration to use */ static void run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *c) { char *keyfile; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded tmp; /* setup globals */ GST_cfg = c; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (c, "GNUNETD", "HOSTKEY", &keyfile)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Transport service is lacking key configuration settings. Exiting.\n")); GNUNET_SCHEDULER_shutdown (); return; } GST_my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); GNUNET_free (keyfile); if (GST_my_private_key == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Transport service could not access hostkey. Exiting.\n")); GNUNET_SCHEDULER_shutdown (); return; } GST_stats = GNUNET_STATISTICS_create ("transport", c); GST_peerinfo = GNUNET_PEERINFO_connect (c); memset (&GST_my_public_key, '\0', sizeof (GST_my_public_key)); memset (&tmp, '\0', sizeof (tmp)); GNUNET_CRYPTO_rsa_key_get_public (GST_my_private_key, &GST_my_public_key); GNUNET_CRYPTO_hash (&GST_my_public_key, sizeof (GST_my_public_key), &GST_my_identity.hashPubKey); GNUNET_assert (NULL != GST_my_private_key); GNUNET_assert (0 != memcmp (&GST_my_public_key, &tmp, sizeof (GST_my_public_key))); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); if (GST_peerinfo == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not access PEERINFO service. Exiting.\n")); GNUNET_SCHEDULER_shutdown (); return; } /* start subsystems */ GST_hello_start (&process_hello_update, NULL); GNUNET_assert (NULL != GST_hello_get()); GST_blacklist_start (server); GST_ats = GNUNET_ATS_scheduling_init (GST_cfg, &ats_request_address_change, NULL); GST_plugins_load (&plugin_env_receive_callback, &plugin_env_address_change_notification, &plugin_env_session_end, &plugin_env_address_to_type); GST_neighbours_start (NULL, &neighbours_connect_notification, &neighbours_disconnect_notification, &neighbours_address_notification); GST_clients_start (server); GST_validation_start (); } /** * The main function for the transport service. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { return (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "transport", GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; } /* end of file gnunet-service-transport.c */ gnunet-0.9.3/src/mysql/0000755000175000017500000000000011763406747011777 500000000000000gnunet-0.9.3/src/mysql/Makefile.am0000644000175000017500000000062011733356070013737 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage endif lib_LTLIBRARIES = libgnunetmysql.la libgnunetmysql_la_SOURCES = \ mysql.c libgnunetmysql_la_LIBADD = -lmysqlclient \ $(top_builddir)/src/util/libgnunetutil.la libgnunetmysql_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:0:0 gnunet-0.9.3/src/mysql/mysql.c0000644000175000017500000004704711760502551013227 00000000000000/* This file is part of GNUnet (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file mysql/mysql.c * @brief library to help with access to a MySQL database * @author Christian Grothoff */ #include "platform.h" #include #include "gnunet_mysql_lib.h" /** * Maximum number of supported parameters for a prepared * statement. Increase if needed. */ #define MAX_PARAM 16 /** * Die with an error message that indicates * a failure of the command 'cmd' with the message given * by strerror(errno). */ #define DIE_MYSQL(cmd, dbh) do { GNUNET_log_from (GNUNET_ERROR_TYPE__ERROR, "mysql", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, mysql_error((dbh)->dbf)); GNUNET_abort(); } while(0); /** * Log an error message at log-level 'level' that indicates * a failure of the command 'cmd' on file 'filename' * with the message given by strerror(errno). */ #define LOG_MYSQL(level, cmd, dbh) do { GNUNET_log_from (level, "mysql", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, mysql_error((dbh)->dbf)); } while(0); /** * Mysql context. */ struct GNUNET_MYSQL_Context { /** * Our configuration. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Our section. */ const char *section; /** * Handle to the mysql database. */ MYSQL *dbf; /** * Head of list of our prepared statements. */ struct GNUNET_MYSQL_StatementHandle *shead; /** * Tail of list of our prepared statements. */ struct GNUNET_MYSQL_StatementHandle *stail; /** * Filename of "my.cnf" (msyql configuration). */ char *cnffile; }; /** * Handle for a prepared statement. */ struct GNUNET_MYSQL_StatementHandle { /** * Kept in a DLL. */ struct GNUNET_MYSQL_StatementHandle *next; /** * Kept in a DLL. */ struct GNUNET_MYSQL_StatementHandle *prev; /** * Original query string. */ char *query; /** * Handle to MySQL prepared statement. */ MYSQL_STMT *statement; /** * Is the MySQL prepared statement valid, or do we need to re-initialize it? */ int valid; }; /** * Obtain the location of ".my.cnf". * * @param cfg our configuration * @param section the section * @return NULL on error */ static char * get_my_cnf_path (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section) { char *cnffile; char *home_dir; struct stat st; #ifndef WINDOWS struct passwd *pw; #endif int configured; #ifndef WINDOWS pw = getpwuid (getuid ()); if (!pw) { GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_ERROR, "mysql", "getpwuid"); return NULL; } if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg, section, "CONFIG")) { GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, section, "CONFIG", &cnffile)); configured = GNUNET_YES; } else { home_dir = GNUNET_strdup (pw->pw_dir); GNUNET_asprintf (&cnffile, "%s/.my.cnf", home_dir); GNUNET_free (home_dir); configured = GNUNET_NO; } #else home_dir = (char *) GNUNET_malloc (_MAX_PATH + 1); plibc_conv_to_win_path ("~/", home_dir); GNUNET_asprintf (&cnffile, "%s/.my.cnf", home_dir); GNUNET_free (home_dir); configured = GNUNET_NO; #endif GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "mysql", _("Trying to use file `%s' for MySQL configuration.\n"), cnffile); if ((0 != STAT (cnffile, &st)) || (0 != ACCESS (cnffile, R_OK)) || (!S_ISREG (st.st_mode))) { if (configured == GNUNET_YES) GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "mysql", _("Could not access file `%s': %s\n"), cnffile, STRERROR (errno)); GNUNET_free (cnffile); return NULL; } return cnffile; } /** * Open the connection with the database (and initialize * our default options). * * @param mc database context to initialze * @return GNUNET_OK on success */ static int iopen (struct GNUNET_MYSQL_Context *mc) { char *mysql_dbname; char *mysql_server; char *mysql_user; char *mysql_password; unsigned long long mysql_port; my_bool reconnect; unsigned int timeout; mc->dbf = mysql_init (NULL); if (mc->dbf == NULL) return GNUNET_SYSERR; if (mc->cnffile != NULL) mysql_options (mc->dbf, MYSQL_READ_DEFAULT_FILE, mc->cnffile); mysql_options (mc->dbf, MYSQL_READ_DEFAULT_GROUP, "client"); reconnect = 0; mysql_options (mc->dbf, MYSQL_OPT_RECONNECT, &reconnect); mysql_options (mc->dbf, MYSQL_OPT_CONNECT_TIMEOUT, (const void *) &timeout); mysql_options (mc->dbf, MYSQL_SET_CHARSET_NAME, "UTF8"); timeout = 60; /* in seconds */ mysql_options (mc->dbf, MYSQL_OPT_READ_TIMEOUT, (const void *) &timeout); mysql_options (mc->dbf, MYSQL_OPT_WRITE_TIMEOUT, (const void *) &timeout); mysql_dbname = NULL; if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "DATABASE")) GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (mc->cfg, mc->section, "DATABASE", &mysql_dbname)); else mysql_dbname = GNUNET_strdup ("gnunet"); mysql_user = NULL; if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "USER")) { GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (mc->cfg, mc->section, "USER", &mysql_user)); } mysql_password = NULL; if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "PASSWORD")) { GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (mc->cfg, mc->section, "PASSWORD", &mysql_password)); } mysql_server = NULL; if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "HOST")) { GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (mc->cfg, mc->section, "HOST", &mysql_server)); } mysql_port = 0; if (GNUNET_YES == GNUNET_CONFIGURATION_have_value (mc->cfg, mc->section, "PORT")) { GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (mc->cfg, mc->section, "PORT", &mysql_port)); } GNUNET_assert (mysql_dbname != NULL); mysql_real_connect (mc->dbf, mysql_server, mysql_user, mysql_password, mysql_dbname, (unsigned int) mysql_port, NULL, CLIENT_IGNORE_SIGPIPE); GNUNET_free_non_null (mysql_server); GNUNET_free_non_null (mysql_user); GNUNET_free_non_null (mysql_password); GNUNET_free (mysql_dbname); if (mysql_error (mc->dbf)[0]) { LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_real_connect", mc); return GNUNET_SYSERR; } return GNUNET_OK; } /** * Create a mysql context. * * @param cfg configuration * @param section configuration section to use to get MySQL configuration options * @return the mysql context */ struct GNUNET_MYSQL_Context * GNUNET_MYSQL_context_create (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section) { struct GNUNET_MYSQL_Context *mc; mc = GNUNET_malloc (sizeof (struct GNUNET_MYSQL_Context)); mc->cfg = cfg; mc->section = section; mc->cnffile = get_my_cnf_path (cfg, section); return mc; } /** * Close database connection and all prepared statements (we got a DB * error). * * @param mc mysql context */ void GNUNET_MYSQL_statements_invalidate (struct GNUNET_MYSQL_Context *mc) { struct GNUNET_MYSQL_StatementHandle *sh; for (sh = mc->shead; NULL != sh; sh = sh->next) { if (GNUNET_YES == sh->valid) { mysql_stmt_close (sh->statement); sh->valid = GNUNET_NO; } sh->statement = NULL; } if (NULL != mc->dbf) { mysql_close (mc->dbf); mc->dbf = NULL; } } /** * Destroy a mysql context. Also frees all associated prepared statements. * * @param mc context to destroy */ void GNUNET_MYSQL_context_destroy (struct GNUNET_MYSQL_Context *mc) { struct GNUNET_MYSQL_StatementHandle *sh; GNUNET_MYSQL_statements_invalidate (mc); while (NULL != (sh = mc->shead)) { GNUNET_CONTAINER_DLL_remove (mc->shead, mc->stail, sh); GNUNET_free (sh->query); GNUNET_free (sh); } GNUNET_free (mc); mysql_library_end (); } /** * Prepare a statement. Prepared statements are automatically discarded * when the MySQL context is destroyed. * * @param mc mysql context * @param query query text * @return prepared statement, NULL on error */ struct GNUNET_MYSQL_StatementHandle * GNUNET_MYSQL_statement_prepare (struct GNUNET_MYSQL_Context *mc, const char *query) { struct GNUNET_MYSQL_StatementHandle *sh; sh = GNUNET_malloc (sizeof (struct GNUNET_MYSQL_StatementHandle)); sh->query = GNUNET_strdup (query); GNUNET_CONTAINER_DLL_insert (mc->shead, mc->stail, sh); return sh; } /** * Run a SQL statement. * * @param mc mysql context * @param sql SQL statement to run * @return GNUNET_OK on success * GNUNET_SYSERR if there was a problem */ int GNUNET_MYSQL_statement_run (struct GNUNET_MYSQL_Context *mc, const char *sql) { if ((NULL == mc->dbf) && (GNUNET_OK != iopen (mc))) return GNUNET_SYSERR; mysql_query (mc->dbf, sql); if (mysql_error (mc->dbf)[0]) { LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_query", mc); GNUNET_MYSQL_statements_invalidate (mc); return GNUNET_SYSERR; } return GNUNET_OK; } /** * Prepare a statement for running. * * @param mc mysql context * @param sh statement handle to prepare * @return GNUNET_OK on success */ static int prepare_statement (struct GNUNET_MYSQL_Context *mc, struct GNUNET_MYSQL_StatementHandle *sh) { if (GNUNET_YES == sh->valid) return GNUNET_OK; if ((NULL == mc->dbf) && (GNUNET_OK != iopen (mc))) return GNUNET_SYSERR; sh->statement = mysql_stmt_init (mc->dbf); if (NULL == sh->statement) { GNUNET_MYSQL_statements_invalidate (mc); return GNUNET_SYSERR; } if (0 != mysql_stmt_prepare (sh->statement, sh->query, strlen (sh->query))) { LOG_MYSQL (GNUNET_ERROR_TYPE_ERROR, "mysql_stmt_prepare", mc); mysql_stmt_close (sh->statement); sh->statement = NULL; GNUNET_MYSQL_statements_invalidate (mc); return GNUNET_SYSERR; } sh->valid = GNUNET_YES; return GNUNET_OK; } /** * Get internal handle for a prepared statement. This function should rarely * be used, and if, with caution! On failures during the interaction with * the handle, you must call 'GNUNET_MYSQL_statements_invalidate'! * * @param mc mysql context * @param sh prepared statement to introspect * @return MySQL statement handle, NULL on error */ MYSQL_STMT * GNUNET_MYSQL_statement_get_stmt (struct GNUNET_MYSQL_Context * mc, struct GNUNET_MYSQL_StatementHandle * sh) { (void) prepare_statement (mc, sh); return sh->statement; } /** * Bind the parameters for the given MySQL statement * and run it. * * @param mc mysql context * @param sh statement to bind and run * @param ap arguments for the binding * @return GNUNET_SYSERR on error, GNUNET_OK on success */ static int init_params (struct GNUNET_MYSQL_Context *mc, struct GNUNET_MYSQL_StatementHandle *sh, va_list ap) { MYSQL_BIND qbind[MAX_PARAM]; unsigned int pc; unsigned int off; enum enum_field_types ft; pc = mysql_stmt_param_count (sh->statement); if (pc > MAX_PARAM) { /* increase internal constant! */ GNUNET_break (0); return GNUNET_SYSERR; } memset (qbind, 0, sizeof (qbind)); off = 0; ft = 0; while ((pc > 0) && (-1 != (int) (ft = va_arg (ap, enum enum_field_types)))) { qbind[off].buffer_type = ft; switch (ft) { case MYSQL_TYPE_FLOAT: qbind[off].buffer = va_arg (ap, float *); break; case MYSQL_TYPE_LONGLONG: qbind[off].buffer = va_arg (ap, unsigned long long *); qbind[off].is_unsigned = va_arg (ap, int); break; case MYSQL_TYPE_LONG: qbind[off].buffer = va_arg (ap, unsigned int *); qbind[off].is_unsigned = va_arg (ap, int); break; case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_STRING: case MYSQL_TYPE_BLOB: qbind[off].buffer = va_arg (ap, void *); qbind[off].buffer_length = va_arg (ap, unsigned long); qbind[off].length = va_arg (ap, unsigned long *); break; default: /* unsupported type */ GNUNET_break (0); return GNUNET_SYSERR; } pc--; off++; } if (!((pc == 0) && (-1 != (int) ft) && (va_arg (ap, int) == -1))) { GNUNET_break (0); return GNUNET_SYSERR; } if (mysql_stmt_bind_param (sh->statement, qbind)) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "mysql", _("`%s' failed at %s:%d with error: %s\n"), "mysql_stmt_bind_param", __FILE__, __LINE__, mysql_stmt_error (sh->statement)); GNUNET_MYSQL_statements_invalidate (mc); return GNUNET_SYSERR; } if (mysql_stmt_execute (sh->statement)) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "mysql", _("`%s' failed at %s:%d with error: %s\n"), "mysql_stmt_execute", __FILE__, __LINE__, mysql_stmt_error (sh->statement)); GNUNET_MYSQL_statements_invalidate (mc); return GNUNET_SYSERR; } return GNUNET_OK; } /** * Run a prepared SELECT statement. * * @param mc mysql context * @param s statement to run * @param result_size number of elements in results array * @param results pointer to already initialized MYSQL_BIND * array (of sufficient size) for passing results * @param processor function to call on each result * @param processor_cls extra argument to processor * @param ap pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective * values (size + buffer-reference for pointers); terminated * with "-1" * @return GNUNET_SYSERR on error, otherwise * the number of successfully affected (or queried) rows */ int GNUNET_MYSQL_statement_run_prepared_select_va (struct GNUNET_MYSQL_Context *mc, struct GNUNET_MYSQL_StatementHandle *s, unsigned int result_size, MYSQL_BIND * results, GNUNET_MYSQL_DataProcessor processor, void *processor_cls, va_list ap) { int ret; unsigned int rsize; int total; if (GNUNET_OK != prepare_statement (mc, s)) { GNUNET_break (0); return GNUNET_SYSERR; } if (GNUNET_OK != init_params (mc, s, ap)) { GNUNET_break (0); return GNUNET_SYSERR; } rsize = mysql_stmt_field_count (s->statement); if (rsize > result_size) { GNUNET_break (0); return GNUNET_SYSERR; } if (mysql_stmt_bind_result (s->statement, results)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("`%s' failed at %s:%d with error: %s\n"), "mysql_stmt_bind_result", __FILE__, __LINE__, mysql_stmt_error (s->statement)); GNUNET_MYSQL_statements_invalidate (mc); return GNUNET_SYSERR; } total = 0; while (1) { ret = mysql_stmt_fetch (s->statement); if (ret == MYSQL_NO_DATA) break; if (ret != 0) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "mysql", _("`%s' failed at %s:%d with error: %s\n"), "mysql_stmt_fetch", __FILE__, __LINE__, mysql_stmt_error (s->statement)); GNUNET_MYSQL_statements_invalidate (mc); return GNUNET_SYSERR; } total++; if ((NULL == processor) || (GNUNET_OK != processor (processor_cls, rsize, results))) break; } mysql_stmt_reset (s->statement); return total; } /** * Run a prepared SELECT statement. * * @param mc mysql context * @param sh handle to SELECT statment * @param result_size number of elements in results array * @param results pointer to already initialized MYSQL_BIND * array (of sufficient size) for passing results * @param processor function to call on each result * @param processor_cls extra argument to processor * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective * values (size + buffer-reference for pointers); terminated * with "-1" * @return GNUNET_SYSERR on error, otherwise * the number of successfully affected (or queried) rows */ int GNUNET_MYSQL_statement_run_prepared_select (struct GNUNET_MYSQL_Context *mc, struct GNUNET_MYSQL_StatementHandle *sh, unsigned int result_size, MYSQL_BIND * results, GNUNET_MYSQL_DataProcessor processor, void *processor_cls, ...) { va_list ap; int ret; va_start (ap, processor_cls); ret = GNUNET_MYSQL_statement_run_prepared_select_va (mc, sh, result_size, results, processor, processor_cls, ap); va_end (ap); return ret; } /** * Run a prepared statement that does NOT produce results. * * @param mc mysql context * @param sh handle to statment * @param insert_id NULL or address where to store the row ID of whatever * was inserted (only for INSERT statements!) * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective * values (size + buffer-reference for pointers); terminated * with "-1" * @return GNUNET_SYSERR on error, otherwise * the number of successfully affected rows */ int GNUNET_MYSQL_statement_run_prepared (struct GNUNET_MYSQL_Context *mc, struct GNUNET_MYSQL_StatementHandle *sh, unsigned long long *insert_id, ...) { va_list ap; int affected; if (GNUNET_OK != prepare_statement (mc, sh)) return GNUNET_SYSERR; va_start (ap, insert_id); if (GNUNET_OK != init_params (mc, sh, ap)) { va_end (ap); return GNUNET_SYSERR; } va_end (ap); affected = mysql_stmt_affected_rows (sh->statement); if (NULL != insert_id) *insert_id = (unsigned long long) mysql_stmt_insert_id (sh->statement); mysql_stmt_reset (sh->statement); return affected; } /* end of mysql.c */ gnunet-0.9.3/src/mysql/Makefile.in0000644000175000017500000005037211762217212013755 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = src/mysql DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) libgnunetmysql_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_libgnunetmysql_la_OBJECTS = mysql.lo libgnunetmysql_la_OBJECTS = $(am_libgnunetmysql_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunetmysql_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetmysql_la_LDFLAGS) $(LDFLAGS) \ -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunetmysql_la_SOURCES) DIST_SOURCES = $(libgnunetmysql_la_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage lib_LTLIBRARIES = libgnunetmysql.la libgnunetmysql_la_SOURCES = \ mysql.c libgnunetmysql_la_LIBADD = -lmysqlclient \ $(top_builddir)/src/util/libgnunetutil.la libgnunetmysql_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:0:0 all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/mysql/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/mysql/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunetmysql.la: $(libgnunetmysql_la_OBJECTS) $(libgnunetmysql_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetmysql_la_LINK) -rpath $(libdir) $(libgnunetmysql_la_OBJECTS) $(libgnunetmysql_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mysql.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libLTLIBRARIES install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/postgres/0000755000175000017500000000000011763406747012500 500000000000000gnunet-0.9.3/src/postgres/Makefile.am0000644000175000017500000000062611733356067014454 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage endif lib_LTLIBRARIES = libgnunetpostgres.la libgnunetpostgres_la_SOURCES = \ postgres.c libgnunetpostgres_la_LIBADD = -lpq \ $(top_builddir)/src/util/libgnunetutil.la libgnunetpostgres_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:0:0 gnunet-0.9.3/src/postgres/postgres.c0000644000175000017500000001307511760502551014423 00000000000000/* This file is part of GNUnet (C) 2009, 2010, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file postgres/postgres.c * @brief library to help with access to a Postgres database * @author Christian Grothoff */ #include "platform.h" #include "gnunet_postgres_lib.h" /** * Check if the result obtained from Postgres has * the desired status code. If not, log an error, clear the * result and return GNUNET_SYSERR. * * @param dbh database handle * @param ret return value from database operation to check * @param expected_status desired status * @param command description of the command that was run * @param args arguments given to the command * @param filename name of the source file where the command was run * @param line line number in the source file * @return GNUNET_OK if the result is acceptable */ int GNUNET_POSTGRES_check_result_ (PGconn * dbh, PGresult * ret, int expected_status, const char *command, const char *args, const char *filename, int line) { if (ret == NULL) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "postgres", "Postgres failed to allocate result for `%s:%s' at %s:%d\n", command, args, filename, line); return GNUNET_SYSERR; } if (PQresultStatus (ret) != expected_status) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "postgres", _("`%s:%s' failed at %s:%d with error: %s"), command, args, filename, line, PQerrorMessage (dbh)); PQclear (ret); return GNUNET_SYSERR; } return GNUNET_OK; } /** * Run simple SQL statement (without results). * * @param dbh database handle * @param sql statement to run * @param filename filename for error reporting * @param line code line for error reporting * @return GNUNET_OK on success */ int GNUNET_POSTGRES_exec_ (PGconn * dbh, const char *sql, const char *filename, int line) { PGresult *ret; ret = PQexec (dbh, sql); if (GNUNET_OK != GNUNET_POSTGRES_check_result_ (dbh, ret, PGRES_COMMAND_OK, "PQexec", sql, filename, line)) return GNUNET_SYSERR; PQclear (ret); return GNUNET_OK; } /** * Prepare SQL statement. * * @param dbh database handle * @param name name for the prepared SQL statement * @param sql SQL code to prepare * @param nparms number of parameters in sql * @param filename filename for error reporting * @param line code line for error reporting * @return GNUNET_OK on success */ int GNUNET_POSTGRES_prepare_ (PGconn * dbh, const char *name, const char *sql, int nparms, const char *filename, int line) { PGresult *ret; ret = PQprepare (dbh, name, sql, nparms, NULL); if (GNUNET_OK != GNUNET_POSTGRES_check_result_ (dbh, ret, PGRES_COMMAND_OK, "PQprepare", sql, filename, line)) return GNUNET_SYSERR; PQclear (ret); return GNUNET_OK; } /** * Connect to a postgres database * * @param cfg configuration * @param section configuration section to use to get Postgres configuration options * @return the postgres handle */ PGconn * GNUNET_POSTGRES_connect (const struct GNUNET_CONFIGURATION_Handle * cfg, const char *section) { PGconn *dbh; char *conninfo; /* Open database and precompile statements */ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, section, "CONFIG", &conninfo)) conninfo = NULL; dbh = PQconnectdb (conninfo == NULL ? "" : conninfo); GNUNET_free_non_null (conninfo); if (NULL == dbh) { /* FIXME: warn about out-of-memory? */ return NULL; } if (PQstatus (dbh) != CONNECTION_OK) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "postgres", _("Unable to initialize Postgres: %s"), PQerrorMessage (dbh)); PQfinish (dbh); return NULL; } return dbh; } /** * Delete the row identified by the given rowid (qid * in postgres). * * @param dbh database handle * @param stmt name of the prepared statement * @param rowid which row to delete * @return GNUNET_OK on success */ int GNUNET_POSTGRES_delete_by_rowid (PGconn * dbh, const char *stmt, uint32_t rowid) { uint32_t brow = htonl (rowid); const char *paramValues[] = { (const char *) &brow }; int paramLengths[] = { sizeof (brow) }; const int paramFormats[] = { 1 }; PGresult *ret; ret = PQexecPrepared (dbh, stmt, 1, paramValues, paramLengths, paramFormats, 1); if (GNUNET_OK != GNUNET_POSTGRES_check_result_ (dbh, ret, PGRES_COMMAND_OK, "PQexecPrepared", "delrow", __FILE__, __LINE__)) { return GNUNET_SYSERR; } PQclear (ret); return GNUNET_OK; } /* end of postgres.c */ gnunet-0.9.3/src/postgres/Makefile.in0000644000175000017500000005047111762217212014456 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = src/postgres DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) libgnunetpostgres_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_libgnunetpostgres_la_OBJECTS = postgres.lo libgnunetpostgres_la_OBJECTS = $(am_libgnunetpostgres_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunetpostgres_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetpostgres_la_LDFLAGS) \ $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunetpostgres_la_SOURCES) DIST_SOURCES = $(libgnunetpostgres_la_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage lib_LTLIBRARIES = libgnunetpostgres.la libgnunetpostgres_la_SOURCES = \ postgres.c libgnunetpostgres_la_LIBADD = -lpq \ $(top_builddir)/src/util/libgnunetutil.la libgnunetpostgres_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:0:0 all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/postgres/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/postgres/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunetpostgres.la: $(libgnunetpostgres_la_OBJECTS) $(libgnunetpostgres_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetpostgres_la_LINK) -rpath $(libdir) $(libgnunetpostgres_la_OBJECTS) $(libgnunetpostgres_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/postgres.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libLTLIBRARIES install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/dv/0000755000175000017500000000000011763406751011236 500000000000000gnunet-0.9.3/src/dv/plugin_transport_dv.c0000644000175000017500000003117711760502551015426 00000000000000/* This file is part of GNUnet (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dv/plugin_transport_dv.c * @brief DV transport service, takes incoming DV requests and deals with * the DV service * @author Nathan Evans * @author Christian Grothoff */ #include "platform.h" #include "gnunet_protocols.h" #include "gnunet_connection_lib.h" #include "gnunet_server_lib.h" #include "gnunet_service_lib.h" #include "gnunet_statistics_service.h" #include "gnunet_dv_service.h" #include "gnunet_transport_service.h" #include "gnunet_transport_plugin.h" #include "dv.h" #define DEBUG_TEMPLATE GNUNET_EXTRA_LOGGING /** * Encapsulation of all of the state of the plugin. */ struct Plugin; /** * Session handle for connections. */ struct Session { /** * Stored in a linked list. */ struct Session *next; /** * Pointer to the global plugin struct. */ struct Plugin *plugin; /** * The client (used to identify this connection) */ /* void *client; */ /** * Continuation function to call once the transmission buffer * has again space available. NULL if there is no * continuation to call. */ GNUNET_TRANSPORT_TransmitContinuation transmit_cont; /** * Closure for transmit_cont. */ void *transmit_cont_cls; /** * To whom are we talking to (set to our identity * if we are still waiting for the welcome message) */ struct GNUNET_PeerIdentity sender; /** * At what time did we reset last_received last? */ struct GNUNET_TIME_Absolute last_quota_update; /** * How many bytes have we received since the "last_quota_update" * timestamp? */ uint64_t last_received; /** * Number of bytes per ms that this peer is allowed * to send to us. */ uint32_t quota; }; /** * Encapsulation of all of the state of the plugin. */ struct Plugin { /** * Our environment. */ struct GNUNET_TRANSPORT_PluginEnvironment *env; /** * List of open sessions. */ struct Session *sessions; /** * Our server. */ //struct GNUNET_SERVER_Handle *server; /* * Handle to the running service. */ //struct GNUNET_SERVICE_Context *service; /** * Copy of the handler array where the closures are * set to this struct's instance. */ struct GNUNET_SERVER_MessageHandler *handlers; /** * Handle to the DV service */ struct GNUNET_DV_Handle *dv_handle; }; /** * Handler for messages received from the DV service. */ void handle_dv_message_received (void *cls, struct GNUNET_PeerIdentity *sender, char *msg, size_t msg_len, uint32_t distance, char *sender_address, size_t sender_address_len) { struct Plugin *plugin = cls; #if DEBUG_DV_MESSAGES char *my_id; my_id = GNUNET_strdup (GNUNET_i2s (plugin->env->my_identity)); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "plugin_transport_dv", _("%s Received message from %s of type %d, distance %u!\n"), my_id, GNUNET_i2s (sender), ntohs (((struct GNUNET_MessageHeader *) msg)->type), distance); if (sender_address_len == (2 * sizeof (struct GNUNET_PeerIdentity))) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "plugin_transport_dv", "Parsed sender address: %s:%s\n", GNUNET_i2s ((struct GNUNET_PeerIdentity *) sender_address), GNUNET_h2s (& ((struct GNUNET_PeerIdentity *) &sender_address[sizeof (struct GNUNET_PeerIdentity)])->hashPubKey)); } GNUNET_free_non_null (my_id); #endif struct GNUNET_ATS_Information ats[1]; ats[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); ats[0].value = htonl (distance); plugin->env->receive (plugin->env->cls, sender, (struct GNUNET_MessageHeader *) msg, (const struct GNUNET_ATS_Information *) &ats, 1, NULL, sender_address, sender_address_len); } /* Question: how does the transport service learn of a newly connected (gossipped about) * DV peer? Should the plugin (here) create a HELLO for that peer and send it along, * or should the DV service create a HELLO and send it to us via the other part? */ /** * Function that can be used by the transport service to transmit * a message using the plugin. * * @param cls closure * @param session the session used * @param priority how important is the message * @param msgbuf the message to transmit * @param msgbuf_size number of bytes in 'msgbuf' * @param timeout when should we time out * @param cont continuation to call once the message has * been transmitted (or if the transport is ready * for the next transmission call; or if the * peer disconnected...) * @param cont_cls closure for cont * @return number of bytes used (on the physical network, with overheads); * -1 on hard errors (i.e. address invalid); 0 is a legal value * and does NOT mean that the message was not transmitted (DV) */ static ssize_t dv_plugin_send (void *cls, struct Session *session, const char *msgbuf, size_t msgbuf_size, unsigned int priority, struct GNUNET_TIME_Relative timeout, GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) { int ret = -1; #if 0 struct Plugin *plugin = cls; ret = GNUNET_DV_send (plugin->dv_handle, &session->sender, msgbuf, msgbuf_size, priority, timeout, addr, addrlen, cont, cont_cls); #endif return ret; } /** * Function that can be used to force the plugin to disconnect * from the given peer and cancel all previous transmissions * (and their continuations). * * @param cls closure * @param target peer from which to disconnect */ static void dv_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) { // struct Plugin *plugin = cls; // TODO: Add message type to send to dv service to "disconnect" a peer } /** * Convert the transports address to a nice, human-readable * format. * * @param cls closure * @param type name of the transport that generated the address * @param addr one of the addresses of the host, NULL for the last address * the specific address format depends on the transport * @param addrlen length of the address * @param numeric should (IP) addresses be displayed in numeric form? * @param timeout after how long should we give up? * @param asc function to call on each string * @param asc_cls closure for asc */ static void dv_plugin_address_pretty_printer (void *cls, const char *type, const void *addr, size_t addrlen, int numeric, struct GNUNET_TIME_Relative timeout, GNUNET_TRANSPORT_AddressStringCallback asc, void *asc_cls) { char *dest_peer; char *via_peer; char *print_string; char *addr_buf = (char *) addr; if (addrlen != sizeof (struct GNUNET_PeerIdentity) * 2) { asc (asc_cls, NULL); } else { dest_peer = GNUNET_strdup (GNUNET_i2s ((struct GNUNET_PeerIdentity *) addr)); via_peer = GNUNET_strdup (GNUNET_i2s ((struct GNUNET_PeerIdentity *) &addr_buf[sizeof (struct GNUNET_PeerIdentity)])); GNUNET_asprintf (&print_string, "DV Peer `%s' via peer`%s'", dest_peer, via_peer); asc (asc_cls, print_string); asc (asc_cls, NULL); GNUNET_free (via_peer); GNUNET_free (dest_peer); GNUNET_free (print_string); } } /** * Convert the DV address to a pretty string. * * @param cls closure * @param addr the (hopefully) DV address * @param addrlen the length of the address * * @return string representing the DV address */ static const char * address_to_string (void *cls, const void *addr, size_t addrlen) { static char return_buffer[2 * 4 + 2]; // Two four character peer identity prefixes a ':' and '\0' struct GNUNET_CRYPTO_HashAsciiEncoded peer_hash; struct GNUNET_CRYPTO_HashAsciiEncoded via_hash; struct GNUNET_PeerIdentity *peer; struct GNUNET_PeerIdentity *via; char *addr_buf = (char *) addr; if (addrlen == (2 * sizeof (struct GNUNET_PeerIdentity))) { peer = (struct GNUNET_PeerIdentity *) addr_buf; via = (struct GNUNET_PeerIdentity *) &addr_buf[sizeof (struct GNUNET_PeerIdentity)]; GNUNET_CRYPTO_hash_to_enc (&peer->hashPubKey, &peer_hash); peer_hash.encoding[4] = '\0'; GNUNET_CRYPTO_hash_to_enc (&via->hashPubKey, &via_hash); via_hash.encoding[4] = '\0'; GNUNET_snprintf (return_buffer, sizeof (return_buffer), "%s:%s", &peer_hash, &via_hash); } else return NULL; return return_buffer; } /** * Another peer has suggested an address for this peer and transport * plugin. Check that this could be a valid address. This function * is not expected to 'validate' the address in the sense of trying to * connect to it but simply to see if the binary format is technically * legal for establishing a connection to this peer (and make sure that * the address really corresponds to our network connection/settings * and not some potential man-in-the-middle). * * @param cls closure * @param addr pointer to the address * @param addrlen length of addr * @return GNUNET_OK if this is a plausible address for this peer * and transport, GNUNET_SYSERR if not * */ static int dv_plugin_check_address (void *cls, const void *addr, size_t addrlen) { struct Plugin *plugin = cls; /* Verify that the first peer of this address matches our peer id! */ if ((addrlen != (2 * sizeof (struct GNUNET_PeerIdentity))) || (0 != memcmp (addr, plugin->env->my_identity, sizeof (struct GNUNET_PeerIdentity)))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Address not correct size or identity doesn't match ours!\n", GNUNET_i2s (plugin->env->my_identity)); if (addrlen == (2 * sizeof (struct GNUNET_PeerIdentity))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer in address is %s\n", GNUNET_i2s (addr)); } return GNUNET_SYSERR; } return GNUNET_OK; } /** * Create a new session to transmit data to the target * This session will used to send data to this peer and the plugin will * notify us by calling the env->session_end function * * @param cls the plugin * @param address the address * @return the session if the address is valid, NULL otherwise */ static struct Session * dv_get_session (void *cls, const struct GNUNET_HELLO_Address *address) { return NULL; } /** * Entry point for the plugin. */ void * libgnunet_plugin_transport_dv_init (void *cls) { struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; struct GNUNET_TRANSPORT_PluginFunctions *api; struct Plugin *plugin; plugin = GNUNET_malloc (sizeof (struct Plugin)); plugin->env = env; plugin->dv_handle = GNUNET_DV_connect (env->cfg, &handle_dv_message_received, plugin); if (plugin->dv_handle == NULL) { GNUNET_free (plugin); return NULL; } api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); api->cls = plugin; api->send = &dv_plugin_send; api->disconnect = &dv_plugin_disconnect; api->address_pretty_printer = &dv_plugin_address_pretty_printer; api->check_address = &dv_plugin_check_address; api->address_to_string = &address_to_string; api->get_session = dv_get_session; return api; } /** * Exit point from the plugin. */ void * libgnunet_plugin_transport_dv_done (void *cls) { struct GNUNET_TRANSPORT_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; if (plugin->dv_handle != NULL) GNUNET_DV_disconnect (plugin->dv_handle); GNUNET_free (plugin); GNUNET_free (api); return NULL; } /* end of plugin_transport_dv.c */ gnunet-0.9.3/src/dv/Makefile.am0000644000175000017500000000376011704315746013216 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIB = -lgcov endif plugindir = $(libdir)/gnunet pkgcfgdir= $(pkgdatadir)/config.d/ pkgcfg_DATA = \ dv.conf lib_LTLIBRARIES = libgnunetdv.la plugin_LTLIBRARIES = libgnunet_plugin_transport_dv.la libgnunetdv_la_SOURCES = \ dv_api.c dv.h libgnunetdv_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(GN_LIBINTL) $(XLIB) libgnunetdv_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 0:0:0 bin_PROGRAMS = \ gnunet-service-dv gnunet_service_dv_SOURCES = \ gnunet-service-dv.c gnunet_service_dv_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/dv/libgnunetdv.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_service_dv_DEPENDENCIES = \ libgnunetdv.la libgnunet_plugin_transport_dv_la_SOURCES = \ plugin_transport_dv.c libgnunet_plugin_transport_dv_la_LIBADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/dv/libgnunetdv.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_transport_dv_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_transport_dv_la_DEPENDENCIES = \ libgnunetdv.la check_PROGRAMS = \ test_transport_api_dv # test_dv_topology if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) $(check_SCRIPTS) endif test_transport_api_dv_SOURCES = \ test_transport_api_dv.c test_transport_api_dv_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la EXTRA_DIST = \ test_transport_dv_data.conf gnunet-0.9.3/src/dv/test_transport_api_dv.c0000644000175000017500000011177711760502551015745 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dv/test_transport_api_dv.c * @brief base testcase for testing distance vector transport */ #include "platform.h" #include "gnunet_testing_lib.h" #include "gnunet_core_service.h" #define VERBOSE 1 #define TEST_ALL GNUNET_NO /** * How long until we fail the whole testcase? */ #define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600) /** * How long until we give up on starting the peers? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 500) #define DEFAULT_NUM_PEERS 4 #define DEFAULT_ADDITIONAL_MESSAGES 2 #define MAX_OUTSTANDING_CONNECTIONS 100 static float fail_percentage = 0.00; static int ok; static unsigned long long num_additional_messages; static unsigned long long num_peers; static unsigned int total_connections; static unsigned int failed_connections; static unsigned int total_server_connections; static unsigned int total_messages_received; static unsigned int total_other_expected_messages; static unsigned int temp_total_other_messages; static unsigned int total_other_messages; static unsigned int expected_messages; static unsigned int expected_connections; static unsigned long long peers_left; static struct GNUNET_TESTING_PeerGroup *pg; const struct GNUNET_CONFIGURATION_Handle *main_cfg; static GNUNET_SCHEDULER_TaskIdentifier die_task; static char *dotOutFileName = "topology.dot"; static FILE *dotOutFile; static char *blacklist_transports; static int transmit_ready_scheduled; static int transmit_ready_failed; static int transmit_ready_called; static enum GNUNET_TESTING_Topology topology; static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* Don't do any blacklisting */ static enum GNUNET_TESTING_Topology connection_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */ static enum GNUNET_TESTING_TopologyOption connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; static double connect_topology_option_modifier = 0.0; static char *test_directory; struct GNUNET_CONTAINER_MultiHashMap *peer_daemon_hash; #define MTYPE 12345 GNUNET_NETWORK_STRUCT_BEGIN struct GNUNET_TestMessage { /** * Header of the message */ struct GNUNET_MessageHeader header; /** * Unique identifier for this message. */ uint32_t uid; }; GNUNET_NETWORK_STRUCT_END struct PeerContext { /* This is a linked list */ struct PeerContext *next; /** * Handle to the daemon */ struct GNUNET_TESTING_Daemon *daemon; /* Handle to the peer core */ struct GNUNET_CORE_Handle *peer_handle; }; static struct PeerContext *all_peers; struct TestMessageContext { /* This is a linked list */ struct TestMessageContext *next; /* Handle to the sending peer core */ struct GNUNET_CORE_Handle *peer1handle; /* Handle to the receiving peer core */ struct GNUNET_CORE_Handle *peer2handle; /* Handle to the sending peer daemon */ struct GNUNET_TESTING_Daemon *peer1; /* Handle to the receiving peer daemon */ struct GNUNET_TESTING_Daemon *peer2; /* Identifier for this message, so we don't disconnect other peers! */ uint32_t uid; /* Task for disconnecting cores, allow task to be cancelled on shutdown */ GNUNET_SCHEDULER_TaskIdentifier disconnect_task; }; static struct TestMessageContext *test_messages; static struct TestMessageContext *other_test_messages; /** * Check whether peers successfully shut down. */ void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); #endif if (ok == 0) ok = 666; } else { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); #endif } } static void finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_assert (pg != NULL); struct PeerContext *peer_pos; struct PeerContext *free_peer_pos; struct TestMessageContext *pos; struct TestMessageContext *free_pos; die_task = GNUNET_SCHEDULER_NO_TASK; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called finish testing, stopping daemons.\n"); #endif peer_pos = all_peers; while (peer_pos != NULL) { if (peer_pos->peer_handle != NULL) GNUNET_CORE_disconnect (peer_pos->peer_handle); free_peer_pos = peer_pos; peer_pos = peer_pos->next; GNUNET_free (free_peer_pos); } all_peers = NULL; pos = test_messages; while (pos != NULL) { if (pos->peer1handle != NULL) { GNUNET_CORE_disconnect (pos->peer1handle); pos->peer1handle = NULL; } if (pos->peer2handle != NULL) { GNUNET_CORE_disconnect (pos->peer2handle); pos->peer2handle = NULL; } free_pos = pos; pos = pos->next; if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (free_pos->disconnect_task); } GNUNET_free (free_pos); } pos = other_test_messages; while (pos != NULL) { if (pos->peer1handle != NULL) { GNUNET_CORE_disconnect (pos->peer1handle); pos->peer1handle = NULL; } if (pos->peer2handle != NULL) { GNUNET_CORE_disconnect (pos->peer2handle); pos->peer2handle = NULL; } free_pos = pos; pos = pos->next; if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (free_pos->disconnect_task); } GNUNET_free (free_pos); } #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n", transmit_ready_scheduled, transmit_ready_failed, transmit_ready_called); #endif #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling daemons_stop\n"); #endif GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "daemons_stop finished\n"); #endif if (dotOutFile != NULL) { FPRINTF (dotOutFile, "%s", "}"); FCLOSE (dotOutFile); } ok = 0; } static void disconnect_cores (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct TestMessageContext *pos = cls; /* Disconnect from the respective cores */ #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer 1 `%4s'\n", GNUNET_i2s (&pos->peer1->id)); #endif if (pos->peer1handle != NULL) GNUNET_CORE_disconnect (pos->peer1handle); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer 2 `%4s'\n", GNUNET_i2s (&pos->peer2->id)); #endif if (pos->peer2handle != NULL) GNUNET_CORE_disconnect (pos->peer2handle); /* Set handles to NULL so test case can be ended properly */ pos->peer1handle = NULL; pos->peer2handle = NULL; pos->disconnect_task = GNUNET_SCHEDULER_NO_TASK; /* Decrement total connections so new can be established */ total_server_connections -= 2; } static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { char *msg = cls; struct TestMessageContext *pos; struct TestMessageContext *free_pos; struct PeerContext *peer_pos; struct PeerContext *free_peer_pos; die_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "End badly was called (%s)... stopping daemons.\n", msg); peer_pos = all_peers; while (peer_pos != NULL) { if (peer_pos->peer_handle != NULL) GNUNET_CORE_disconnect (peer_pos->peer_handle); free_peer_pos = peer_pos; peer_pos = peer_pos->next; GNUNET_free (free_peer_pos); } all_peers = NULL; pos = test_messages; while (pos != NULL) { if (pos->peer1handle != NULL) { GNUNET_CORE_disconnect (pos->peer1handle); pos->peer1handle = NULL; } if (pos->peer2handle != NULL) { GNUNET_CORE_disconnect (pos->peer2handle); pos->peer2handle = NULL; } free_pos = pos; pos = pos->next; GNUNET_free (free_pos); } pos = other_test_messages; while (pos != NULL) { if (pos->peer1handle != NULL) { GNUNET_CORE_disconnect (pos->peer1handle); pos->peer1handle = NULL; } if (pos->peer2handle != NULL) { GNUNET_CORE_disconnect (pos->peer2handle); pos->peer2handle = NULL; } free_pos = pos; pos = pos->next; if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (free_pos->disconnect_task); } GNUNET_free (free_pos); } if (pg != NULL) { GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); ok = 7331; /* Opposite of leet */ } else ok = 401; /* Never got peers started */ if (dotOutFile != NULL) { FPRINTF (dotOutFile, "%s", "}"); FCLOSE (dotOutFile); } } static void send_other_messages (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Get distance information from 'atsi'. * * @param atsi performance data * @return connected transport distance */ static uint32_t get_atsi_distance (const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { unsigned int i; for (i = 0; i < atsi_count; i++) { if (ntohl (atsi->type) == GNUNET_ATS_QUALITY_NET_DISTANCE) return ntohl (atsi->value); } GNUNET_break (0); /* FIXME: we do not have distance data? Assume direct neighbor. */ return 1; } static int process_mtype (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct TestMessageContext *pos = cls; struct GNUNET_TestMessage *msg = (struct GNUNET_TestMessage *) message; #if VERBOSE uint32_t distance; #endif if (pos->uid != ntohl (msg->uid)) return GNUNET_OK; #if VERBOSE distance = get_atsi_distance (atsi, atsi_count); #endif GNUNET_assert (0 == memcmp (peer, &pos->peer1->id, sizeof (struct GNUNET_PeerIdentity))); if (total_other_expected_messages == 0) { total_messages_received++; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received message from `%4s', type %d, uid %u, distance %u.\n", GNUNET_i2s (peer), ntohs (message->type), ntohl (msg->uid), distance); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Total messages received %d, expected %d.\n", total_messages_received, expected_messages); #endif } else { total_other_messages++; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received message from `%4s', type %d, uid %u, distance %u.\n", GNUNET_i2s (peer), ntohs (message->type), ntohl (msg->uid), distance); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Total OTHER messages received %d, expected %d.\n", total_other_messages, total_other_expected_messages); #endif } if ((total_messages_received == expected_messages) && (total_other_messages == 0)) { GNUNET_SCHEDULER_cancel (die_task); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scheduling timeout from DV connections.\n"); #endif die_task = GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, "waiting for DV peers to connect!"); } else if ((total_other_expected_messages > 0) && (total_other_messages == total_other_expected_messages)) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&finish_testing, NULL); } else { pos->disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cores, pos); } return GNUNET_OK; } static size_t transmit_ready (void *cls, size_t size, void *buf) { struct GNUNET_TestMessage *m; struct TestMessageContext *pos = cls; GNUNET_assert (buf != NULL); m = (struct GNUNET_TestMessage *) buf; m->header.type = htons (MTYPE); m->header.size = htons (sizeof (struct GNUNET_TestMessage)); m->uid = htonl (pos->uid); transmit_ready_called++; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "transmit ready for peer %s\ntransmit_ready's scheduled %d, transmit_ready's called %d\n", GNUNET_i2s (&pos->peer1->id), transmit_ready_scheduled, transmit_ready_called); #endif return sizeof (struct GNUNET_TestMessage); } static struct GNUNET_CORE_MessageHandler no_handlers[] = { {NULL, 0, 0} }; static struct GNUNET_CORE_MessageHandler handlers[] = { {&process_mtype, MTYPE, sizeof (struct GNUNET_TestMessage)}, {NULL, 0, 0} }; /** * Notify of all peer1's peers, once peer 2 is found, schedule connect * to peer two for message send. * * @param cls closure * @param peer peer identity this notification is about * @param atsi performance data for the connection * @param atsi_count number of ATS information included */ static void connect_notify_peer2 (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct TestMessageContext *pos = cls; if (0 == memcmp (&pos->peer1->id, peer, sizeof (struct GNUNET_PeerIdentity))) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core connection from `%s' to `%4s' verfied, sending message!\n", GNUNET_i2s (&pos->peer2->id), GNUNET_h2s (&peer->hashPubKey)); #endif if (NULL == GNUNET_CORE_notify_transmit_ready (pos->peer1handle, GNUNET_YES, 0, TIMEOUT, &pos->peer2->id, sizeof (struct GNUNET_TestMessage), &transmit_ready, pos)) { /* This probably shouldn't happen, but it does (timing issue?) */ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n", GNUNET_i2s (&pos->peer2->id)); transmit_ready_failed++; total_other_expected_messages--; } else { transmit_ready_scheduled++; } } } static void init_notify_peer2 (void *cls, struct GNUNET_CORE_Handle *server, const struct GNUNET_PeerIdentity *my_identity) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core connection to `%4s' established, awaiting connections.\n", GNUNET_i2s (my_identity)); #endif total_server_connections++; } /** * Notify of all peer1's peers, once peer 2 is found, schedule connect * to peer two for message send. * * @param cls closure * @param peer peer identity this notification is about * @param atsi performance data for the connection * @param atsi_count number of atsi datums */ static void connect_notify_peer1 (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct TestMessageContext *pos = cls; if (0 == memcmp (&pos->peer2->id, peer, sizeof (struct GNUNET_PeerIdentity))) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core connection from `%s' to `%4s' verified.\n", GNUNET_i2s (&pos->peer1->id), GNUNET_h2s (&peer->hashPubKey)); #endif /* * Connect to the receiving peer */ pos->peer2handle = GNUNET_CORE_connect (pos->peer2->cfg, 1, pos, &init_notify_peer2, &connect_notify_peer2, NULL, NULL, GNUNET_YES, NULL, GNUNET_YES, handlers); } } static void init_notify_peer1 (void *cls, struct GNUNET_CORE_Handle *server, const struct GNUNET_PeerIdentity *my_identity) { total_server_connections++; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core connection to `%4s' established, awaiting connections...\n", GNUNET_i2s (my_identity)); #endif } static void send_test_messages (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct TestMessageContext *pos = cls; if (((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) || (cls == NULL)) return; if (die_task == GNUNET_SCHEDULER_NO_TASK) { die_task = GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, "from create topology (timeout)"); } if (total_server_connections >= MAX_OUTSTANDING_CONNECTIONS) { GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1), &send_test_messages, pos); return; /* Otherwise we'll double schedule messages here! */ } #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Attempting to send test message from %s to %s\n", pos->peer1->shortname, pos->peer2->shortname); #endif /* * Connect to the sending peer */ pos->peer1handle = GNUNET_CORE_connect (pos->peer1->cfg, 1, pos, &init_notify_peer1, &connect_notify_peer1, NULL, NULL, GNUNET_NO, NULL, GNUNET_NO, no_handlers); GNUNET_assert (pos->peer1handle != NULL); if (total_server_connections < MAX_OUTSTANDING_CONNECTIONS) { GNUNET_SCHEDULER_add_now (&send_test_messages, pos->next); } else { GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1), &send_test_messages, pos->next); } } static void send_other_messages (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct TestMessageContext *pos; struct TestMessageContext *free_pos; struct PeerContext *peer_pos; #if TEST_ALL struct PeerContext *inner_peer_pos; struct TestMessageContext *temp_context; #endif peer_pos = all_peers; while (peer_pos != NULL) { if (peer_pos->peer_handle != NULL) { GNUNET_CORE_disconnect (peer_pos->peer_handle); peer_pos->peer_handle = NULL; } #if TEST_ALL inner_peer_pos = all_peers; while (inner_peer_pos != NULL) { if (inner_peer_pos != peer_pos) { temp_total_other_messages++; temp_context = GNUNET_malloc (sizeof (struct TestMessageContext)); temp_context->peer1 = peer_pos->daemon; temp_context->peer2 = inner_peer_pos->daemon; temp_context->next = other_test_messages; temp_context->uid = total_connections + temp_total_other_messages; temp_context->disconnect_task = GNUNET_SCHEDULER_NO_TASK; other_test_messages = temp_context; } inner_peer_pos = inner_peer_pos->next; } #endif peer_pos = peer_pos->next; } all_peers = NULL; pos = test_messages; while (pos != NULL) { if (pos->peer1handle != NULL) { GNUNET_CORE_disconnect (pos->peer1handle); pos->peer1handle = NULL; } if (pos->peer2handle != NULL) { GNUNET_CORE_disconnect (pos->peer2handle); pos->peer2handle = NULL; } free_pos = pos; pos = pos->next; if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (free_pos->disconnect_task); } GNUNET_free (free_pos); } test_messages = NULL; total_other_expected_messages = temp_total_other_messages; if (total_other_expected_messages == 0) { GNUNET_SCHEDULER_add_now (&end_badly, "send_other_messages had 0 messages to send, no DV connections made!"); } #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Preparing to send %d other test messages\n", total_other_expected_messages); #endif GNUNET_SCHEDULER_add_now (&send_test_messages, other_test_messages); if (GNUNET_SCHEDULER_NO_TASK != die_task) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 250), &end_badly, "from send_other_messages"); } static void topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, uint32_t distance, const struct GNUNET_CONFIGURATION_Handle *first_cfg, const struct GNUNET_CONFIGURATION_Handle *second_cfg, struct GNUNET_TESTING_Daemon *first_daemon, struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) { struct TestMessageContext *temp_context; if (emsg == NULL) { total_connections++; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s, distance %u\n", first_daemon->shortname, second_daemon->shortname, distance); #endif temp_context = GNUNET_malloc (sizeof (struct TestMessageContext)); temp_context->peer1 = first_daemon; temp_context->peer2 = second_daemon; temp_context->next = test_messages; temp_context->uid = total_connections; temp_context->disconnect_task = GNUNET_SCHEDULER_NO_TASK; test_messages = temp_context; expected_messages++; } #if VERBOSE else { failed_connections++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect peer %s to peer %s with error :\n%s\n", first_daemon->shortname, second_daemon->shortname, emsg); } #endif if (total_connections == expected_connections) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created %u total connections, which is our target number! Calling send messages.\n", total_connections); #endif if (GNUNET_SCHEDULER_NO_TASK != die_task) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_SCHEDULER_add_now (&send_test_messages, test_messages); } else if (total_connections + failed_connections == expected_connections) { if (failed_connections < (unsigned int) (fail_percentage * total_connections)) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; /* FIXME: ret value!? */ GNUNET_SCHEDULER_add_now (&send_test_messages, test_messages); } else { if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from topology_callback (too many failed connections)"); } } else { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d total connections, %d failed connections, Want %d (at least %d)\n", total_connections, failed_connections, expected_connections, expected_connections - (unsigned int) (fail_percentage * expected_connections)); #endif } } /** * Method called whenever a given peer connects. * * @param cls closure * @param peer peer identity this notification is about * @param atsi performance data about this peer's connection * @param atsi_count number of atsi datums * */ static void all_connect_handler (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct GNUNET_TESTING_Daemon *d = cls; struct GNUNET_TESTING_Daemon *second_daemon; char *second_shortname; #if !TEST_ALL struct TestMessageContext *temp_context; #endif uint32_t distance; if (0 == memcmp (&d->id, peer, sizeof (struct GNUNET_PeerIdentity))) return; second_shortname = GNUNET_strdup (GNUNET_i2s (peer)); distance = get_atsi_distance (atsi, atsi_count); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s, distance %u\n", d->shortname, second_shortname, distance); #endif second_daemon = GNUNET_CONTAINER_multihashmap_get (peer_daemon_hash, &peer->hashPubKey); if (second_daemon == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Couldn't find second peer!\n"); GNUNET_free (second_shortname); return; } #if !TEST_ALL if (distance > 1) { temp_total_other_messages++; temp_context = GNUNET_malloc (sizeof (struct TestMessageContext)); temp_context->peer1 = d; temp_context->peer2 = second_daemon; temp_context->next = other_test_messages; temp_context->uid = total_connections + temp_total_other_messages; temp_context->disconnect_task = GNUNET_SCHEDULER_NO_TASK; other_test_messages = temp_context; } #endif if (dotOutFile != NULL) { if (distance == 1) FPRINTF (dotOutFile, "\tn%s -- n%s;\n", d->shortname, second_shortname); else if (distance == 2) FPRINTF (dotOutFile, "\tn%s -- n%s [color=blue];\n", d->shortname, second_shortname); else if (distance == 3) FPRINTF (dotOutFile, "\tn%s -- n%s [color=red];\n", d->shortname, second_shortname); else if (distance == 4) FPRINTF (dotOutFile, "\tn%s -- n%s [color=green];\n", d->shortname, second_shortname); else FPRINTF (dotOutFile, "\tn%s -- n%s [color=brown];\n", d->shortname, second_shortname); } GNUNET_free (second_shortname); if (temp_total_other_messages == num_additional_messages) { /* FIXME: ret value!? */ GNUNET_SCHEDULER_add_now (&send_other_messages, NULL); } } static void peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { struct PeerContext *new_peer; if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to start daemon with error: `%s'\n", emsg); return; } GNUNET_assert (id != NULL); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", (num_peers - peers_left) + 1, num_peers); #endif GNUNET_assert (GNUNET_SYSERR != GNUNET_CONTAINER_multihashmap_put (peer_daemon_hash, &id->hashPubKey, d, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); new_peer = GNUNET_malloc (sizeof (struct PeerContext)); new_peer->peer_handle = GNUNET_CORE_connect (cfg, 1, d, NULL, &all_connect_handler, NULL, NULL, GNUNET_NO, NULL, GNUNET_NO, no_handlers); new_peer->daemon = d; new_peer->next = all_peers; all_peers = new_peer; peers_left--; if (peers_left == 0) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All %d daemons started, now creating topology!\n", num_peers); #endif GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; expected_connections = -1; if ((pg != NULL) && (peers_left == 0)) { expected_connections = GNUNET_TESTING_connect_topology (pg, connection_topology, connect_topology_option, connect_topology_option_modifier, TIMEOUT, 12, NULL, NULL); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n", expected_connections); #endif } if (expected_connections == GNUNET_SYSERR) { die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from connect topology (bad return)"); } else { /* Set up task in case topology creation doesn't finish * within a reasonable amount of time */ die_task = GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, "from connect topology (timeout)"); } ok = 0; } } /** * Callback indicating that the hostkey was created for a peer. * * @param cls NULL * @param id the peer identity * @param d the daemon handle (pretty useless at this point, remove?) * @param emsg non-null on failure */ static void hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, struct GNUNET_TESTING_Daemon *d, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Hostkey callback received error: %s\n", emsg); } #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostkey created for peer `%s'\n", GNUNET_i2s (id)); #endif peers_left--; if (peers_left == 0) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All %d hostkeys created, now creating topology!\n", num_peers); #endif if (GNUNET_SCHEDULER_NO_TASK != die_task) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; } /* create topology */ peers_left = num_peers; /* Reset counter */ if (GNUNET_TESTING_create_topology (pg, topology, blacklist_topology, blacklist_transports) != GNUNET_SYSERR) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Topology set up, now starting peers!\n"); #endif GNUNET_TESTING_daemons_continue_startup (pg); /* Set up task in case topology creation doesn't finish * within a reasonable amount of time */ die_task = GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, "from continue startup (timeout)"); } else { die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from create topology (bad return)"); } ok = 0; } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { char *topology_str; char *connect_topology_str; char *blacklist_topology_str; char *connect_topology_option_str; char *connect_topology_option_modifier_string; ok = 1; dotOutFile = fopen (dotOutFileName, "w"); if (dotOutFile != NULL) { FPRINTF (dotOutFile, "%s", "strict graph G {\n"); } #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons based on config file %s\n", cfgfile); #endif if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", &test_directory)) { ok = 404; return; } if ((GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "topology", &topology_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get (&topology, topology_str))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid topology `%s' given for section %s option %s\n", topology_str, "TESTING", "TOPOLOGY"); topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */ } if ((GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "connect_topology", &connect_topology_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get (&connection_topology, connect_topology_str))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid connect topology `%s' given for section %s option %s\n", connect_topology_str, "TESTING", "CONNECT_TOPOLOGY"); } GNUNET_free_non_null (connect_topology_str); if ((GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "connect_topology_option", &connect_topology_option_str)) && (GNUNET_NO == GNUNET_TESTING_topology_option_get (&connect_topology_option, connect_topology_option_str))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid connect topology option `%s' given for section %s option %s\n", connect_topology_option_str, "TESTING", "CONNECT_TOPOLOGY_OPTION"); connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */ } GNUNET_free_non_null (connect_topology_option_str); if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "connect_topology_option_modifier", &connect_topology_option_modifier_string)) { if (SSCANF (connect_topology_option_modifier_string, "%lf", &connect_topology_option_modifier) != 1) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), connect_topology_option_modifier_string, "connect_topology_option_modifier", "TESTING"); } GNUNET_free (connect_topology_option_modifier_string); } if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "blacklist_transports", &blacklist_transports)) blacklist_transports = NULL; if ((GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "blacklist_topology", &blacklist_topology_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get (&blacklist_topology, blacklist_topology_str))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid topology `%s' given for section %s option %s\n", topology_str, "TESTING", "BLACKLIST_TOPOLOGY"); } GNUNET_free_non_null (topology_str); GNUNET_free_non_null (blacklist_topology_str); if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", &num_peers)) num_peers = DEFAULT_NUM_PEERS; if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "additional_messages", &num_additional_messages)) num_additional_messages = DEFAULT_ADDITIONAL_MESSAGES; main_cfg = cfg; GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1); peers_left = num_peers; /* Set up a task to end testing if peer start fails */ die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, "didn't start all daemons in reasonable amount of time!!!"); peer_daemon_hash = GNUNET_CONTAINER_multihashmap_create (peers_left); pg = GNUNET_TESTING_daemons_start (cfg, peers_left, /* Total number of peers */ peers_left, /* Number of outstanding connections */ peers_left, /* Number of parallel ssh connections, or peers being started at once */ TIMEOUT, &hostkey_callback, NULL, &peers_started_callback, NULL, &topology_callback, NULL, NULL); } static int check () { int ret; char *const argv[] = { "test-transport-dv", "-c", "test_transport_dv_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; ret = GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-transport-dv", "nohelp", options, &run, &ok); if (ret != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "`test-transport-dv': Failed with error code %d\n", ret); } return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-transport-dv", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); /** * Need to remove base directory, subdirectories taken care * of by the testing framework. */ if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to remove testing directory %s\n", test_directory); } return ret; } /* end of test_transport_api_dv.c */ gnunet-0.9.3/src/dv/test_transport_dv_data.conf0000644000175000017500000000207211662010677016577 00000000000000[PATHS] SERVICEHOME = /tmp/test-gnunet-dv-testing/ DEFAULTCONFIG = test_transport_dv_data.conf [resolver] PORT = 2564 [transport] DEBUG = YES PORT = 2565 PLUGINS = tcp dv BLACKLIST_FILE = $SERVICEHOME/blacklist BINARY = gnunet-service-transport USE_LOCALADDR = NO [arm] PORT = 2566 DEFAULTSERVICES = [statistics] PORT = 2567 [transport-tcp] PORT = 2568 BINDTO = 127.0.0.1 [transport-udp] PORT = 2568 [peerinfo] PORT = 2569 [core] PORT = 2570 [dv] AUTOSTART = YES DEBUG = NO ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; BINARY = gnunet-service-dv CONFIG = $DEFAULTCONFIG HOME = $SERVICEHOME HOSTNAME = localhost PORT = 2571 [testing] NUM_PEERS = 3 ADDITIONAL_MESSAGES = 10 DEBUG = NO WEAKRANDOM = YES TOPOLOGY = CLIQUE CONNECT_TOPOLOGY = LINE BLACKLIST_TOPOLOGY = LINE BLACKLIST_TRANSPORTS = tcp F2F = YES HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat [fs] AUTOSTART = NO [nat] DISABLEV6 = YES ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 USE_LOCALADDR = NO [dns] AUTOSTART = NO [nse] AUTOSTART = NO gnunet-0.9.3/src/dv/dv.conf.in0000644000175000017500000000053611760502552013040 00000000000000[dv] AUTOSTART = YES DEBUG = NO ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; BINARY = gnunet-service-dv CONFIG = $DEFAULTCONFIG HOME = $SERVICEHOME HOSTNAME = localhost @UNIXONLY@ PORT = 2571 UNIXPATH = /tmp/gnunet-service-dv.sock UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES # ACCEPT_FROM = # ACCEPT_FROM6 = # REJECT_FROM = # REJECT_FROM6 = # BINDTO = gnunet-0.9.3/src/dv/gnunet-service-dv.c0000644000175000017500000031567711762207515014706 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dv/gnunet-service-dv.c * @brief the distance vector service, primarily handles gossip of nearby * peers and sending/receiving DV messages from core and decapsulating * them * * @author Christian Grothoff * @author Nathan Evans * */ #include "platform.h" #include "gnunet_client_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_os_lib.h" #include "gnunet_protocols.h" #include "gnunet_service_lib.h" #include "gnunet_core_service.h" #include "gnunet_signal_lib.h" #include "gnunet_util_lib.h" #include "gnunet_hello_lib.h" #include "gnunet_peerinfo_service.h" #include "gnunet_crypto_lib.h" #include "gnunet_statistics_service.h" #include "dv.h" /** * For testing mostly, remember only the * shortest path to a distant neighbor. */ #define AT_MOST_ONE GNUNET_NO #define USE_PEER_ID GNUNET_YES /** * How many outstanding messages (unknown sender) will we allow per peer? */ #define MAX_OUTSTANDING_MESSAGES 5 /** * How often do we check about sending out more peer information (if * we are connected to no peers previously). */ #define GNUNET_DV_DEFAULT_SEND_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 500000) /** * How long do we wait at most between sending out information? */ #define GNUNET_DV_MAX_SEND_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 500000) /** * How long can we have not heard from a peer and * still have it in our tables? */ #define GNUNET_DV_PEER_EXPIRATION_TIME GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 1000)) /** * Priority for gossip. */ #define GNUNET_DV_DHT_GOSSIP_PRIORITY (GNUNET_EXTREME_PRIORITY / 10) /** * How often should we check if expiration time has elapsed for * some peer? */ #define GNUNET_DV_MAINTAIN_FREQUENCY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5)) /** * How long to allow a message to be delayed? */ #define DV_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5)) /** * Priority to use for DV data messages. */ #define DV_PRIORITY 0 /** * The cost to a direct neighbor. We used to use 0, but 1 makes more sense. */ #define DIRECT_NEIGHBOR_COST 1 /** * The default number of direct connections to store in DV (max) */ #define DEFAULT_DIRECT_CONNECTIONS 50 /** * The default size of direct + extended peers in DV (max) */ #define DEFAULT_DV_SIZE 100 /** * The default fisheye depth, from how many hops away will * we keep peers? */ #define DEFAULT_FISHEYE_DEPTH 4 /** * Linked list of messages to send to clients. */ struct PendingMessage { /** * Pointer to next item in the list */ struct PendingMessage *next; /** * Pointer to previous item in the list */ struct PendingMessage *prev; /** * The PeerIdentity to send to */ struct GNUNET_PeerIdentity recipient; /** * The result of message sending. */ struct GNUNET_DV_SendResultMessage *send_result; /** * Message importance level. */ unsigned int importance; /** * Size of message. */ unsigned int msg_size; /** * How long to wait before sending message. */ struct GNUNET_TIME_Relative timeout; /** * Actual message to be sent; // avoid allocation */ const struct GNUNET_MessageHeader *msg; // msg = (cast) &pm[1]; // memcpy (&pm[1], data, len); }; struct FastGossipNeighborList { /** * Next element of DLL */ struct FastGossipNeighborList *next; /** * Prev element of DLL */ struct FastGossipNeighborList *prev; /** * The neighbor to gossip about */ struct DistantNeighbor *about; }; /** * Context created whenever a direct peer connects to us, * used to gossip other peers to it. */ struct NeighborSendContext { /** * The peer we will gossip to. */ struct DirectNeighbor *toNeighbor; /** * The task associated with this context. */ GNUNET_SCHEDULER_TaskIdentifier task; /** * Head of DLL of peers to gossip about * as fast as possible to this peer, for initial * set up. */ struct FastGossipNeighborList *fast_gossip_list_head; /** * Tail of DLL of peers to gossip about * as fast as possible to this peer, for initial * set up. */ struct FastGossipNeighborList *fast_gossip_list_tail; }; /** * Struct to hold information for updating existing neighbors */ struct NeighborUpdateInfo { /** * Cost */ unsigned int cost; /** * The existing neighbor */ struct DistantNeighbor *neighbor; /** * The referrer of the possibly existing peer */ struct DirectNeighbor *referrer; /** * The time we heard about this peer */ struct GNUNET_TIME_Absolute now; /** * Peer id this peer uses to refer to neighbor. */ unsigned int referrer_peer_id; }; /** * Struct to store a single message received with * an unknown sender. */ struct UnknownSenderMessage { /** * Message sender (immediate) */ struct GNUNET_PeerIdentity sender; /** * The actual message received */ struct GNUNET_MessageHeader *message; /** * Latency of connection */ struct GNUNET_TIME_Relative latency; /** * Distance to destination */ uint32_t distance; /** * Unknown sender id */ uint32_t sender_id; }; /** * Struct where actual neighbor information is stored, * referenced by min_heap and max_heap. Freeing dealt * with when items removed from hashmap. */ struct DirectNeighbor { /** * Identity of neighbor. */ struct GNUNET_PeerIdentity identity; /** * PublicKey of neighbor. */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; /** * Head of DLL of nodes that this direct neighbor referred to us. */ struct DistantNeighbor *referee_head; /** * Tail of DLL of nodes that this direct neighbor referred to us. */ struct DistantNeighbor *referee_tail; /** * The sending context for gossiping peers to this neighbor. */ struct NeighborSendContext *send_context; /** * Is this one of the direct neighbors that we are "hiding" * from DV? */ int hidden; /** * Save messages immediately from this direct neighbor from a * distan peer we don't know on the chance that it will be * gossiped about and we can deliver the message. */ struct UnknownSenderMessage pending_messages[MAX_OUTSTANDING_MESSAGES]; }; /** * Struct where actual neighbor information is stored, * referenced by min_heap and max_heap. Freeing dealt * with when items removed from hashmap. */ struct DistantNeighbor { /** * We keep distant neighbor's of the same referrer in a DLL. */ struct DistantNeighbor *next; /** * We keep distant neighbor's of the same referrer in a DLL. */ struct DistantNeighbor *prev; /** * Node in min heap */ struct GNUNET_CONTAINER_HeapNode *min_loc; /** * Node in max heap */ struct GNUNET_CONTAINER_HeapNode *max_loc; /** * Identity of referrer (next hop towards 'neighbor'). */ struct DirectNeighbor *referrer; /** * Identity of neighbor. */ struct GNUNET_PeerIdentity identity; /** * PublicKey of neighbor. */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey; /** * Last time we received routing information from this peer */ struct GNUNET_TIME_Absolute last_activity; /** * Last time we sent routing information about this peer */ struct GNUNET_TIME_Absolute last_gossip; /** * Cost to neighbor, used for actual distance vector computations */ unsigned int cost; /** * Random identifier *we* use for this peer, to be used as shortcut * instead of sending full peer id for each message */ unsigned int our_id; /** * Random identifier the *referrer* uses for this peer. */ unsigned int referrer_id; /** * Is this one of the direct neighbors that we are "hiding" * from DV? */ int hidden; }; struct PeerIteratorContext { /** * The actual context, to be freed later. */ struct GNUNET_PEERINFO_IteratorContext *ic; /** * The neighbor about which we are concerned. */ struct DirectNeighbor *neighbor; /** * The distant neighbor entry for this direct neighbor. */ struct DistantNeighbor *distant; }; /** * Context used for creating hello messages when * gossips are received. */ struct HelloContext { /** * Identity of distant neighbor. */ struct GNUNET_PeerIdentity distant_peer; /** * Identity of direct neighbor, via which we send this message. */ const struct GNUNET_PeerIdentity *direct_peer; /** * How many addresses do we need to add (always starts at 1, then set to 0) */ int addresses_to_add; }; struct DV_SendContext { /** * The distant peer (should always match) */ struct GNUNET_PeerIdentity *distant_peer; /** * The direct peer, we need to verify the referrer of. */ struct GNUNET_PeerIdentity *direct_peer; /** * The message to be sent */ struct GNUNET_MessageHeader *message; /** * The pre-built send result message. Simply needs to be queued * and freed once send has been called! */ struct GNUNET_DV_SendResultMessage *send_result; /** * The size of the message being sent, may be larger * than message->header.size because it's multiple * messages packed into one! */ size_t message_size; /** * How important is this message? */ unsigned int importance; /** * Timeout for this message */ struct GNUNET_TIME_Relative timeout; /** * Unique ID for DV message */ unsigned int uid; }; struct FindDestinationContext { unsigned int tid; struct DistantNeighbor *dest; }; struct FindIDContext { unsigned int tid; struct GNUNET_PeerIdentity *dest; const struct GNUNET_PeerIdentity *via; }; struct DisconnectContext { /** * Distant neighbor to get pid from. */ struct DistantNeighbor *distant; /** * Direct neighbor that disconnected. */ struct DirectNeighbor *direct; }; struct TokenizedMessageContext { /** * Immediate sender of this message */ const struct GNUNET_PeerIdentity *peer; /** * Distant sender of the message */ struct DistantNeighbor *distant; /** * Uid for this set of messages */ uint32_t uid; }; /** * Context for finding the least cost peer to send to. * Transport selection can only go so far. */ struct FindLeastCostContext { struct DistantNeighbor *target; unsigned int least_cost; }; /** * Handle to the core service api. */ static struct GNUNET_CORE_Handle *coreAPI; /** * Stream tokenizer to handle messages coming in from core. */ static struct GNUNET_SERVER_MessageStreamTokenizer *coreMST; /** * The identity of our peer. */ static struct GNUNET_PeerIdentity my_identity; /** * The configuration for this service. */ static const struct GNUNET_CONFIGURATION_Handle *cfg; /** * The client, the DV plugin connected to us. Hopefully * this client will never change, although if the plugin dies * and returns for some reason it may happen. */ static struct GNUNET_SERVER_Client *client_handle; /** * Task to run when we shut down, cleaning up all our trash */ static GNUNET_SCHEDULER_TaskIdentifier cleanup_task; static size_t default_dv_priority = 0; static char *my_short_id; /** * Transmit handle to the plugin. */ static struct GNUNET_SERVER_TransmitHandle *plugin_transmit_handle; /** * Head of DLL for client messages */ static struct PendingMessage *plugin_pending_head; /** * Tail of DLL for client messages */ static struct PendingMessage *plugin_pending_tail; /** * Handle to the peerinfo service */ static struct GNUNET_PEERINFO_Handle *peerinfo_handle; /** * Transmit handle to core service. */ static struct GNUNET_CORE_TransmitHandle *core_transmit_handle; /** * Head of DLL for core messages */ static struct PendingMessage *core_pending_head; /** * Tail of DLL for core messages */ static struct PendingMessage *core_pending_tail; /** * Map of PeerIdentifiers to 'struct GNUNET_dv_neighbor*'s for all * directly connected peers. */ static struct GNUNET_CONTAINER_MultiHashMap *direct_neighbors; /** * Map of PeerIdentifiers to 'struct GNUNET_dv_neighbor*'s for * peers connected via DV (extended neighborhood). Does ALSO * include any peers that are in 'direct_neighbors'; for those * peers, the cost will be zero and the referrer all zeros. */ static struct GNUNET_CONTAINER_MultiHashMap *extended_neighbors; /** * We use the min heap (min refers to cost) to prefer * gossipping about peers with small costs. */ static struct GNUNET_CONTAINER_Heap *neighbor_min_heap; /** * We use the max heap (max refers to cost) for general * iterations over all peers and to remove the most costly * connection if we have too many. */ static struct GNUNET_CONTAINER_Heap *neighbor_max_heap; /** * Handle for the statistics service. */ struct GNUNET_STATISTICS_Handle *stats; /** * How far out to keep peers we learn about. */ static unsigned long long fisheye_depth; /** * How many peers to store at most. */ static unsigned long long max_table_size; /** * We've been given a target ID based on the random numbers that * we assigned to our DV-neighborhood. Find the entry for the * respective neighbor. */ static int find_destination (void *cls, struct GNUNET_CONTAINER_HeapNode *node, void *element, GNUNET_CONTAINER_HeapCostType cost) { struct FindDestinationContext *fdc = cls; struct DistantNeighbor *dn = element; if (fdc->tid != dn->our_id) return GNUNET_YES; fdc->dest = dn; return GNUNET_NO; } /** * We've been given a target ID based on the random numbers that * we assigned to our DV-neighborhood. Find the entry for the * respective neighbor. */ static int find_specific_id (void *cls, const GNUNET_HashCode * key, void *value) { struct FindIDContext *fdc = cls; struct DistantNeighbor *dn = value; if (memcmp (&dn->referrer->identity, fdc->via, sizeof (struct GNUNET_PeerIdentity)) == 0) { fdc->tid = dn->referrer_id; return GNUNET_NO; } return GNUNET_YES; } /** * Find a distant peer whose referrer_id matches what we're * looking for. For looking up a peer we've gossipped about * but is now disconnected. Need to do this because we don't * want to remove those that may be accessible via a different * route. */ static int find_distant_peer (void *cls, const GNUNET_HashCode * key, void *value) { struct FindDestinationContext *fdc = cls; struct DistantNeighbor *distant = value; if (fdc->tid == distant->referrer_id) { fdc->dest = distant; return GNUNET_NO; } return GNUNET_YES; } /** * Function called to notify a client about the socket * begin ready to queue more data. "buf" will be * NULL and "size" zero if the socket was closed for * writing in the meantime. * * @param cls closure * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ size_t transmit_to_plugin (void *cls, size_t size, void *buf) { char *cbuf = buf; struct PendingMessage *reply; size_t off; size_t msize; if (buf == NULL) { /* client disconnected */ #if DEBUG_DV_MESSAGES GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: %s buffer was NULL (client disconnect?)\n", my_short_id, "transmit_to_plugin"); #endif return 0; } plugin_transmit_handle = NULL; off = 0; while ((NULL != (reply = plugin_pending_head)) && (size >= off + (msize = ntohs (reply->msg->size)))) { GNUNET_CONTAINER_DLL_remove (plugin_pending_head, plugin_pending_tail, reply); memcpy (&cbuf[off], reply->msg, msize); GNUNET_free (reply); off += msize; } if (plugin_pending_head != NULL) plugin_transmit_handle = GNUNET_SERVER_notify_transmit_ready (client_handle, ntohs (plugin_pending_head->msg-> size), GNUNET_TIME_UNIT_FOREVER_REL, &transmit_to_plugin, NULL); return off; } /** * Send a message to the dv plugin. * * @param sender the direct sender of the message * @param message the message to send to the plugin * (may be an encapsulated type) * @param message_size the size of the message to be sent * @param distant_neighbor the original sender of the message * @param cost the cost to the original sender of the message */ void send_to_plugin (const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, size_t message_size, struct GNUNET_PeerIdentity *distant_neighbor, size_t cost) { struct GNUNET_DV_MessageReceived *received_msg; struct PendingMessage *pending_message; char *sender_address; size_t sender_address_len; char *packed_msg_start; int size; #if DEBUG_DV GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "send_to_plugin called with peer %s as sender\n", GNUNET_i2s (distant_neighbor)); #endif if (memcmp (sender, distant_neighbor, sizeof (struct GNUNET_PeerIdentity)) != 0) { sender_address_len = sizeof (struct GNUNET_PeerIdentity) * 2; sender_address = GNUNET_malloc (sender_address_len); memcpy (sender_address, distant_neighbor, sizeof (struct GNUNET_PeerIdentity)); memcpy (&sender_address[sizeof (struct GNUNET_PeerIdentity)], sender, sizeof (struct GNUNET_PeerIdentity)); } else { sender_address_len = sizeof (struct GNUNET_PeerIdentity); sender_address = GNUNET_malloc (sender_address_len); memcpy (sender_address, sender, sizeof (struct GNUNET_PeerIdentity)); } size = sizeof (struct GNUNET_DV_MessageReceived) + sender_address_len + message_size; received_msg = GNUNET_malloc (size); received_msg->header.size = htons (size); received_msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_RECEIVE); received_msg->distance = htonl (cost); received_msg->msg_len = htonl (message_size); /* Set the sender in this message to be the original sender! */ memcpy (&received_msg->sender, distant_neighbor, sizeof (struct GNUNET_PeerIdentity)); /* Copy the intermediate sender to the end of the message, this is how the transport identifies this peer */ memcpy (&received_msg[1], sender_address, sender_address_len); GNUNET_free (sender_address); /* Copy the actual message after the sender */ packed_msg_start = (char *) &received_msg[1]; packed_msg_start = &packed_msg_start[sender_address_len]; memcpy (packed_msg_start, message, message_size); pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + size); pending_message->msg = (struct GNUNET_MessageHeader *) &pending_message[1]; memcpy (&pending_message[1], received_msg, size); GNUNET_free (received_msg); GNUNET_CONTAINER_DLL_insert_after (plugin_pending_head, plugin_pending_tail, plugin_pending_tail, pending_message); if (client_handle != NULL) { if (plugin_transmit_handle == NULL) { plugin_transmit_handle = GNUNET_SERVER_notify_transmit_ready (client_handle, size, GNUNET_TIME_UNIT_FOREVER_REL, &transmit_to_plugin, NULL); } } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to queue message for plugin, client_handle not yet set (how?)!\n"); } } /* Declare here so retry_core_send is aware of it */ size_t core_transmit_notify (void *cls, size_t size, void *buf); /** * Try to send another message from our core sending list */ static void try_core_send (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PendingMessage *pending; pending = core_pending_head; if (core_transmit_handle != NULL) return; /* Message send already in progress */ if ((pending != NULL) && (coreAPI != NULL)) core_transmit_handle = GNUNET_CORE_notify_transmit_ready (coreAPI, GNUNET_YES, pending->importance, pending->timeout, &pending->recipient, pending->msg_size, &core_transmit_notify, NULL); } /** * Function called to notify a client about the socket * being ready to queue more data. "buf" will be * NULL and "size" zero if the socket was closed for * writing in the meantime. * * @param cls closure (NULL) * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ size_t core_transmit_notify (void *cls, size_t size, void *buf) { char *cbuf = buf; struct PendingMessage *pending; struct PendingMessage *client_reply; size_t off; size_t msize; if (buf == NULL) { /* client disconnected */ #if DEBUG_DV GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s': buffer was NULL\n", "DHT"); #endif return 0; } core_transmit_handle = NULL; off = 0; pending = core_pending_head; if ((pending != NULL) && (size >= (msize = ntohs (pending->msg->size)))) { #if DEBUG_DV GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' : transmit_notify (core) called with size %d\n", "dv service", msize); #endif GNUNET_CONTAINER_DLL_remove (core_pending_head, core_pending_tail, pending); if (pending->send_result != NULL) /* Will only be non-null if a real client asked for this send */ { client_reply = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (struct GNUNET_DV_SendResultMessage)); client_reply->msg = (struct GNUNET_MessageHeader *) &client_reply[1]; memcpy (&client_reply[1], pending->send_result, sizeof (struct GNUNET_DV_SendResultMessage)); GNUNET_free (pending->send_result); GNUNET_CONTAINER_DLL_insert_after (plugin_pending_head, plugin_pending_tail, plugin_pending_tail, client_reply); if (client_handle != NULL) { if (plugin_transmit_handle == NULL) { plugin_transmit_handle = GNUNET_SERVER_notify_transmit_ready (client_handle, sizeof (struct GNUNET_DV_SendResultMessage), GNUNET_TIME_UNIT_FOREVER_REL, &transmit_to_plugin, NULL); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to queue message for plugin, must be one in progress already!!\n"); } } } memcpy (&cbuf[off], pending->msg, msize); GNUNET_free (pending); off += msize; } /*reply = core_pending_head; */ GNUNET_SCHEDULER_add_now (&try_core_send, NULL); /*if (reply != NULL) * core_transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, GNUNET_YES, reply->importance, reply->timeout, &reply->recipient, reply->msg_size, &core_transmit_notify, NULL); */ return off; } /** * Send a DV data message via DV. * * @param sender the original sender of the message * @param recipient the next hop recipient, may be our direct peer, maybe not * @param send_context the send context */ static int send_message_via (const struct GNUNET_PeerIdentity *sender, const struct GNUNET_PeerIdentity *recipient, struct DV_SendContext *send_context) { p2p_dv_MESSAGE_Data *toSend; unsigned int msg_size; unsigned int recipient_id; unsigned int sender_id; struct DistantNeighbor *source; struct PendingMessage *pending_message; struct FindIDContext find_context; #if DEBUG_DV char shortname[5]; #endif msg_size = send_context->message_size + sizeof (p2p_dv_MESSAGE_Data); find_context.dest = send_context->distant_peer; find_context.via = recipient; find_context.tid = 0; GNUNET_CONTAINER_multihashmap_get_multiple (extended_neighbors, &send_context-> distant_peer->hashPubKey, &find_specific_id, &find_context); if (find_context.tid == 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: find_specific_id failed to find peer!\n", my_short_id); /* target unknown to us, drop! */ return GNUNET_SYSERR; } recipient_id = find_context.tid; if (0 == (memcmp (&my_identity, sender, sizeof (struct GNUNET_PeerIdentity)))) { sender_id = 0; source = GNUNET_CONTAINER_multihashmap_get (extended_neighbors, &sender->hashPubKey); if (source != NULL) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: send_message_via found %s, myself in extended peer list???\n", my_short_id, GNUNET_i2s (&source->identity)); } else { source = GNUNET_CONTAINER_multihashmap_get (extended_neighbors, &sender->hashPubKey); if (source == NULL) { /* sender unknown to us, drop! */ return GNUNET_SYSERR; } sender_id = source->our_id; } pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size); pending_message->msg = (struct GNUNET_MessageHeader *) &pending_message[1]; pending_message->send_result = send_context->send_result; memcpy (&pending_message->recipient, recipient, sizeof (struct GNUNET_PeerIdentity)); pending_message->msg_size = msg_size; pending_message->importance = send_context->importance; pending_message->timeout = send_context->timeout; toSend = (p2p_dv_MESSAGE_Data *) pending_message->msg; toSend->header.size = htons (msg_size); toSend->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DATA); toSend->sender = htonl (sender_id); toSend->recipient = htonl (recipient_id); #if DEBUG_DV_MESSAGES toSend->uid = send_context->uid; /* Still sent around in network byte order */ #else toSend->uid = htonl (0); #endif memcpy (&toSend[1], send_context->message, send_context->message_size); #if DEBUG_DV memcpy (&shortname, GNUNET_i2s (send_context->distant_peer), 4); shortname[4] = '\0'; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Notifying core of send to destination `%s' via `%s' size %u\n", "DV", &shortname, GNUNET_i2s (recipient), msg_size); #endif GNUNET_CONTAINER_DLL_insert_after (core_pending_head, core_pending_tail, core_pending_tail, pending_message); GNUNET_SCHEDULER_add_now (try_core_send, NULL); return GNUNET_YES; } /** * Given a FindLeastCostContext, and a set * of peers that match the target, return the cheapest. * * @param cls closure, a struct FindLeastCostContext * @param key the key identifying the target peer * @param value the target peer * * @return GNUNET_YES to continue iteration, GNUNET_NO to stop */ static int find_least_cost_peer (void *cls, const GNUNET_HashCode * key, void *value) { struct FindLeastCostContext *find_context = cls; struct DistantNeighbor *dn = value; if (dn->cost < find_context->least_cost) { find_context->target = dn; } if (dn->cost == DIRECT_NEIGHBOR_COST) return GNUNET_NO; return GNUNET_YES; } /** * Send a DV data message via DV. * * @param recipient the ultimate recipient of this message * @param sender the original sender of the message * @param specific_neighbor the specific neighbor to send this message via * @param message the packed message * @param message_size size of the message * @param importance what priority to send this message with * @param uid the unique identifier of this message (or 0 for none) * @param timeout how long to possibly delay sending this message */ static int send_message (const struct GNUNET_PeerIdentity *recipient, const struct GNUNET_PeerIdentity *sender, const struct DistantNeighbor *specific_neighbor, const struct GNUNET_MessageHeader *message, size_t message_size, unsigned int importance, unsigned int uid, struct GNUNET_TIME_Relative timeout) { p2p_dv_MESSAGE_Data *toSend; unsigned int msg_size; unsigned int cost; unsigned int recipient_id; unsigned int sender_id; struct DistantNeighbor *target; struct DistantNeighbor *source; struct PendingMessage *pending_message; struct FindLeastCostContext find_least_ctx; #if DEBUG_DV_PEER_NUMBERS struct GNUNET_CRYPTO_HashAsciiEncoded encPeerFrom; struct GNUNET_CRYPTO_HashAsciiEncoded encPeerTo; struct GNUNET_CRYPTO_HashAsciiEncoded encPeerVia; #endif msg_size = message_size + sizeof (p2p_dv_MESSAGE_Data); find_least_ctx.least_cost = -1; find_least_ctx.target = NULL; /* * Need to find the least cost peer, lest the transport selection keep * picking the same DV route for the same destination which results * in messages looping forever. Relatively cheap, we don't iterate * over all known peers, just those that apply. */ GNUNET_CONTAINER_multihashmap_get_multiple (extended_neighbors, &recipient->hashPubKey, &find_least_cost_peer, &find_least_ctx); target = find_least_ctx.target; if (target == NULL) { /* target unknown to us, drop! */ return GNUNET_SYSERR; } recipient_id = target->referrer_id; source = GNUNET_CONTAINER_multihashmap_get (extended_neighbors, &sender->hashPubKey); if (source == NULL) { if (0 != (memcmp (&my_identity, sender, sizeof (struct GNUNET_PeerIdentity)))) { /* sender unknown to us, drop! */ return GNUNET_SYSERR; } sender_id = 0; /* 0 == us */ } else { /* find out the number that we use when we gossip about * the sender */ sender_id = source->our_id; } #if DEBUG_DV_PEER_NUMBERS GNUNET_CRYPTO_hash_to_enc (&source->identity.hashPubKey, &encPeerFrom); GNUNET_CRYPTO_hash_to_enc (&target->referrer->identity.hashPubKey, &encPeerVia); encPeerFrom.encoding[4] = '\0'; encPeerVia.encoding[4] = '\0'; #endif if ((sender_id != 0) && (0 == memcmp (&source->identity, &target->referrer->identity, sizeof (struct GNUNET_PeerIdentity)))) { return 0; } cost = target->cost; pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size); pending_message->msg = (struct GNUNET_MessageHeader *) &pending_message[1]; pending_message->send_result = NULL; pending_message->importance = importance; pending_message->timeout = timeout; memcpy (&pending_message->recipient, &target->referrer->identity, sizeof (struct GNUNET_PeerIdentity)); pending_message->msg_size = msg_size; toSend = (p2p_dv_MESSAGE_Data *) pending_message->msg; toSend->header.size = htons (msg_size); toSend->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DATA); toSend->sender = htonl (sender_id); toSend->recipient = htonl (recipient_id); #if DEBUG_DV_MESSAGES toSend->uid = htonl (uid); #else toSend->uid = htonl (0); #endif #if DEBUG_DV_PEER_NUMBERS GNUNET_CRYPTO_hash_to_enc (&target->identity.hashPubKey, &encPeerTo); encPeerTo.encoding[4] = '\0'; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Sending DATA message. Sender id %u, source %s, destination %s, via %s\n", GNUNET_i2s (&my_identity), sender_id, &encPeerFrom, &encPeerTo, &encPeerVia); #endif memcpy (&toSend[1], message, message_size); if ((source != NULL) && (source->pkey == NULL)) /* Test our hypothesis about message failures! */ { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: Sending message, but anticipate recipient will not know sender!!!\n\n\n", my_short_id); } GNUNET_CONTAINER_DLL_insert_after (core_pending_head, core_pending_tail, core_pending_tail, pending_message); #if DEBUG_DV GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Notifying core of send size %d to destination `%s'\n", "DV SEND MESSAGE", msg_size, GNUNET_i2s (recipient)); #endif GNUNET_SCHEDULER_add_now (try_core_send, NULL); return (int) cost; } #if USE_PEER_ID struct CheckPeerContext { /** * Peer we found */ struct DistantNeighbor *peer; /** * Sender id to search for */ unsigned int sender_id; }; /** * Iterator over hash map entries. * * @param cls closure * @param key current key code * @param value value in the hash map * @return GNUNET_YES if we should continue to * iterate, * GNUNET_NO if not. */ int checkPeerID (void *cls, const GNUNET_HashCode * key, void *value) { struct CheckPeerContext *ctx = cls; struct DistantNeighbor *distant = value; if (memcmp (key, &ctx->sender_id, sizeof (unsigned int)) == 0) { ctx->peer = distant; return GNUNET_NO; } return GNUNET_YES; } #endif /** * Handler for messages parsed out by the tokenizer from * DV DATA received for this peer. * * @param cls NULL * @param client the TokenizedMessageContext which contains message information * @param message the actual message */ int tokenized_message_handler (void *cls, void *client, const struct GNUNET_MessageHeader *message) { struct TokenizedMessageContext *ctx = client; GNUNET_break_op (ntohs (message->type) != GNUNET_MESSAGE_TYPE_DV_GOSSIP); GNUNET_break_op (ntohs (message->type) != GNUNET_MESSAGE_TYPE_DV_DATA); if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_DV_GOSSIP) && (ntohs (message->type) != GNUNET_MESSAGE_TYPE_DV_DATA)) { #if DEBUG_DV_MESSAGES GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Receives %s message for me, uid %u, size %d, type %d cost %u from %s!\n", my_short_id, "DV DATA", ctx->uid, ntohs (message->size), ntohs (message->type), ctx->distant->cost, GNUNET_i2s (&ctx->distant->identity)); #endif GNUNET_assert (memcmp (ctx->peer, &ctx->distant->identity, sizeof (struct GNUNET_PeerIdentity)) != 0); send_to_plugin (ctx->peer, message, ntohs (message->size), &ctx->distant->identity, ctx->distant->cost); } return GNUNET_OK; } #if DELAY_FORWARDS struct DelayedMessageContext { struct GNUNET_PeerIdentity dest; struct GNUNET_PeerIdentity sender; struct GNUNET_MessageHeader *message; size_t message_size; uint32_t uid; }; void send_message_delayed (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct DelayedMessageContext *msg_ctx = cls; if (msg_ctx != NULL) { send_message (&msg_ctx->dest, &msg_ctx->sender, NULL, msg_ctx->message, msg_ctx->message_size, default_dv_priority, msg_ctx->uid, GNUNET_TIME_UNIT_FOREVER_REL); GNUNET_free (msg_ctx->message); GNUNET_free (msg_ctx); } } #endif /** * Get distance information from 'atsi'. * * @param atsi performance data * @param atsi_count number of entries in atsi * @return connected transport distance */ static uint32_t get_atsi_distance (const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { unsigned int i; for (i = 0; i < atsi_count; i++) if (ntohl (atsi[i].type) == GNUNET_ATS_QUALITY_NET_DISTANCE) return ntohl (atsi->value); /* FIXME: we do not have distance data? Assume direct neighbor. */ return DIRECT_NEIGHBOR_COST; } /** * Find latency information in 'atsi'. * * @param atsi performance data * @param atsi_count number of entries in atsi * @return connection latency */ static struct GNUNET_TIME_Relative get_atsi_latency (const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { unsigned int i; for (i = 0; i < atsi_count; i++) if (ntohl (atsi[i].type) == GNUNET_ATS_QUALITY_NET_DELAY) return GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, ntohl (atsi->value)); GNUNET_break (0); /* how can we not have latency data? */ return GNUNET_TIME_UNIT_SECONDS; } /** * Core handler for dv data messages. Whatever this message * contains all we really have to do is rip it out of its * DV layering and give it to our pal the DV plugin to report * in with. * * @param cls closure * @param peer peer which sent the message (immediate sender) * @param message the message * @param atsi transport ATS information (latency, distance, etc.) * @param atsi_count number of entries in atsi */ static int handle_dv_data_message (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { const p2p_dv_MESSAGE_Data *incoming = (const p2p_dv_MESSAGE_Data *) message; const struct GNUNET_MessageHeader *packed_message; struct DirectNeighbor *dn; struct DistantNeighbor *pos; unsigned int sid; /* Sender id */ unsigned int tid; /* Target id */ struct GNUNET_PeerIdentity *original_sender; struct GNUNET_PeerIdentity *destination; struct FindDestinationContext fdc; struct TokenizedMessageContext tkm_ctx; int i; int found_pos; #if DELAY_FORWARDS struct DelayedMessageContext *delayed_context; #endif #if USE_PEER_ID struct CheckPeerContext checkPeerCtx; #endif #if DEBUG_DV_MESSAGES char *sender_id; #endif int ret; size_t packed_message_size; char *cbuf; uint32_t distance; /* Distance information */ struct GNUNET_TIME_Relative latency; /* Latency information */ packed_message_size = ntohs (incoming->header.size) - sizeof (p2p_dv_MESSAGE_Data); #if DEBUG_DV GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Receives DATA message from %s size %d, packed size %d!\n", my_short_id, GNUNET_i2s (peer), ntohs (incoming->header.size), packed_message_size); #endif if (ntohs (incoming->header.size) < sizeof (p2p_dv_MESSAGE_Data) + sizeof (struct GNUNET_MessageHeader)) { #if DEBUG_DV GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s': Message sizes don't add up, total size %u, expected at least %u!\n", "dv service", ntohs (incoming->header.size), sizeof (p2p_dv_MESSAGE_Data) + sizeof (struct GNUNET_MessageHeader)); #endif return GNUNET_SYSERR; } /* Iterate over ATS_Information to get distance and latency */ latency = get_atsi_latency (atsi, atsi_count); distance = get_atsi_distance (atsi, atsi_count); dn = GNUNET_CONTAINER_multihashmap_get (direct_neighbors, &peer->hashPubKey); if (dn == NULL) return GNUNET_OK; sid = ntohl (incoming->sender); #if USE_PEER_ID if (sid != 0) { checkPeerCtx.sender_id = sid; checkPeerCtx.peer = NULL; GNUNET_CONTAINER_multihashmap_iterate (extended_neighbors, &checkPeerID, &checkPeerCtx); pos = checkPeerCtx.peer; } else { pos = GNUNET_CONTAINER_multihashmap_get (extended_neighbors, &peer->hashPubKey); } #else pos = dn->referee_head; while ((NULL != pos) && (pos->referrer_id != sid)) pos = pos->next; #endif if (pos == NULL) { #if DEBUG_DV_MESSAGES GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: unknown sender (%u), Message uid %u from %s!\n", my_short_id, ntohl (incoming->sender), ntohl (incoming->uid), GNUNET_i2s (&dn->identity)); pos = dn->referee_head; while ((NULL != pos) && (pos->referrer_id != sid)) { sender_id = GNUNET_strdup (GNUNET_i2s (&pos->identity)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "I know sender %u %s\n", pos->referrer_id, sender_id); GNUNET_free (sender_id); pos = pos->next; } #endif found_pos = -1; for (i = 0; i < MAX_OUTSTANDING_MESSAGES; i++) { if (dn->pending_messages[i].sender_id == 0) { found_pos = i; break; } } if (found_pos == -1) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: Too many unknown senders (%u), ignoring message! Message uid %llu from %s!\n", my_short_id, ntohl (incoming->sender), ntohl (incoming->uid), GNUNET_i2s (&dn->identity)); } else { dn->pending_messages[found_pos].message = GNUNET_malloc (ntohs (message->size)); memcpy (dn->pending_messages[found_pos].message, message, ntohs (message->size)); dn->pending_messages[found_pos].distance = distance; dn->pending_messages[found_pos].latency = latency; memcpy (&dn->pending_messages[found_pos].sender, peer, sizeof (struct GNUNET_PeerIdentity)); dn->pending_messages[found_pos].sender_id = sid; } /* unknown sender */ return GNUNET_OK; } original_sender = &pos->identity; tid = ntohl (incoming->recipient); if (tid == 0) { /* 0 == us */ cbuf = (char *) &incoming[1]; tkm_ctx.peer = peer; tkm_ctx.distant = pos; tkm_ctx.uid = ntohl (incoming->uid); if (GNUNET_OK != GNUNET_SERVER_mst_receive (coreMST, &tkm_ctx, cbuf, packed_message_size, GNUNET_NO, GNUNET_NO)) { GNUNET_break_op (0); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: %s Received corrupt data, discarding!", my_short_id, "DV SERVICE"); } return GNUNET_OK; } else { packed_message = (struct GNUNET_MessageHeader *) &incoming[1]; } /* FIXME: this is the *only* per-request operation we have in DV * that is O(n) in relation to the number of connected peers; a * hash-table lookup could easily solve this (minor performance * issue) */ fdc.tid = tid; fdc.dest = NULL; GNUNET_CONTAINER_heap_iterate (neighbor_max_heap, &find_destination, &fdc); #if DEBUG_DV GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Receives %s message for someone else!\n", "dv", "DV DATA"); #endif if (fdc.dest == NULL) { #if DEBUG_DV_MESSAGES GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Receives %s message uid %u for someone we don't know (id %u)!\n", my_short_id, "DV DATA", ntohl (incoming->uid), tid); #endif return GNUNET_OK; } destination = &fdc.dest->identity; if (0 == memcmp (destination, peer, sizeof (struct GNUNET_PeerIdentity))) { /* FIXME: create stat: routing loop-discard! */ #if DEBUG_DV_MESSAGES GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: DROPPING MESSAGE uid %u type %d, routing loop! Message immediately from %s!\n", my_short_id, ntohl (incoming->uid), ntohs (packed_message->type), GNUNET_i2s (&dn->identity)); #endif return GNUNET_OK; } /* At this point we have a message, and we need to forward it on to the * next DV hop. */ #if DEBUG_DV_MESSAGES GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: FORWARD %s message for %s, uid %u, size %d type %d, cost %u!\n", my_short_id, "DV DATA", GNUNET_i2s (destination), ntohl (incoming->uid), ntohs (packed_message->size), ntohs (packed_message->type), pos->cost); #endif #if DELAY_FORWARDS if (GNUNET_TIME_absolute_get_duration (pos->last_gossip).abs_value < GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2).abs_value) { delayed_context = GNUNET_malloc (sizeof (struct DelayedMessageContext)); memcpy (&delayed_context->dest, destination, sizeof (struct GNUNET_PeerIdentity)); memcpy (&delayed_context->sender, original_sender, sizeof (struct GNUNET_PeerIdentity)); delayed_context->message = GNUNET_malloc (packed_message_size); memcpy (delayed_context->message, packed_message, packed_message_size); delayed_context->message_size = packed_message_size; delayed_context->uid = ntohl (incoming->uid); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 2500), &send_message_delayed, delayed_context); return GNUNET_OK; } else #endif { ret = send_message (destination, original_sender, NULL, packed_message, packed_message_size, default_dv_priority, ntohl (incoming->uid), GNUNET_TIME_UNIT_FOREVER_REL); } if (ret != GNUNET_SYSERR) return GNUNET_OK; else { #if DEBUG_MESSAGE_DROP char *direct_id = GNUNET_strdup (GNUNET_i2s (&dn->identity)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: DROPPING MESSAGE type %d, forwarding failed! Message immediately from %s!\n", GNUNET_i2s (&my_identity), ntohs (((struct GNUNET_MessageHeader *) &incoming[1])->type), direct_id); GNUNET_free (direct_id); #endif return GNUNET_SYSERR; } } #if DEBUG_DV /** * Iterator over hash map entries. * * @param cls closure (NULL) * @param key current key code * @param value value in the hash map (DistantNeighbor) * @return GNUNET_YES if we should continue to * iterate, * GNUNET_NO if not. */ int print_neighbors (void *cls, const GNUNET_HashCode * key, void *abs_value) { struct DistantNeighbor *distant_neighbor = abs_value; char my_shortname[5]; char referrer_shortname[5]; memcpy (&my_shortname, GNUNET_i2s (&my_identity), 4); my_shortname[4] = '\0'; memcpy (&referrer_shortname, GNUNET_i2s (&distant_neighbor->referrer->identity), 4); referrer_shortname[4] = '\0'; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "`%s' %s: Peer `%s', distance %d, referrer `%s' pkey: %s\n", &my_shortname, "DV", GNUNET_i2s (&distant_neighbor->identity), distant_neighbor->cost, &referrer_shortname, distant_neighbor->pkey == NULL ? "no" : "yes"); return GNUNET_YES; } #endif /** * Scheduled task which gossips about known direct peers to other connected * peers. Will run until called with reason shutdown. */ static void neighbor_send_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct NeighborSendContext *send_context = cls; #if DEBUG_DV_GOSSIP_SEND char *encPeerAbout; char *encPeerTo; #endif struct DistantNeighbor *about; struct DirectNeighbor *to; struct FastGossipNeighborList *about_list; p2p_dv_MESSAGE_NeighborInfo *message; struct PendingMessage *pending_message; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) { #if DEBUG_DV_GOSSIP GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Called with reason shutdown, shutting down!\n", GNUNET_i2s (&my_identity)); #endif return; } if (send_context->fast_gossip_list_head != NULL) { about_list = send_context->fast_gossip_list_head; about = about_list->about; GNUNET_CONTAINER_DLL_remove (send_context->fast_gossip_list_head, send_context->fast_gossip_list_tail, about_list); GNUNET_free (about_list); } else { /* FIXME: this may become a problem, because the heap walk has only one internal "walker". This means * that if two neighbor_send_tasks are operating in lockstep (which is quite possible, given default * values for all connected peers) there may be a serious bias as to which peers get gossiped about! * Probably the *best* way to fix would be to have an opaque pointer to the walk position passed as * part of the walk_get_next call. Then the heap would have to keep a list of walks, or reset the walk * whenever a modification has been detected. Yuck either way. Perhaps we could iterate over the heap * once to get a list of peers to gossip about and gossip them over time... But then if one goes away * in the mean time that becomes nasty. For now we'll just assume that the walking is done * asynchronously enough to avoid major problems (-; * * NOTE: probably fixed once we decided send rate based on allowed bandwidth. */ about = GNUNET_CONTAINER_heap_walk_get_next (neighbor_min_heap); } to = send_context->toNeighbor; if ((about != NULL) && (to != about->referrer /* split horizon */ ) && #if SUPPORT_HIDING (about->hidden == GNUNET_NO) && #endif (to != NULL) && (0 != memcmp (&about->identity, &to->identity, sizeof (struct GNUNET_PeerIdentity))) && (about->pkey != NULL)) { #if DEBUG_DV_GOSSIP_SEND encPeerAbout = GNUNET_strdup (GNUNET_i2s (&about->identity)); encPeerTo = GNUNET_strdup (GNUNET_i2s (&to->identity)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Sending info about peer %s id %u to directly connected peer %s\n", GNUNET_i2s (&my_identity), encPeerAbout, about->our_id, encPeerTo); GNUNET_free (encPeerAbout); GNUNET_free (encPeerTo); #endif about->last_gossip = GNUNET_TIME_absolute_get (); pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (p2p_dv_MESSAGE_NeighborInfo)); pending_message->msg = (struct GNUNET_MessageHeader *) &pending_message[1]; pending_message->importance = default_dv_priority; pending_message->timeout = GNUNET_TIME_UNIT_FOREVER_REL; memcpy (&pending_message->recipient, &to->identity, sizeof (struct GNUNET_PeerIdentity)); pending_message->msg_size = sizeof (p2p_dv_MESSAGE_NeighborInfo); message = (p2p_dv_MESSAGE_NeighborInfo *) pending_message->msg; message->header.size = htons (sizeof (p2p_dv_MESSAGE_NeighborInfo)); message->header.type = htons (GNUNET_MESSAGE_TYPE_DV_GOSSIP); message->cost = htonl (about->cost); message->neighbor_id = htonl (about->our_id); memcpy (&message->pkey, about->pkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); memcpy (&message->neighbor, &about->identity, sizeof (struct GNUNET_PeerIdentity)); GNUNET_CONTAINER_DLL_insert_after (core_pending_head, core_pending_tail, core_pending_tail, pending_message); GNUNET_SCHEDULER_add_now (try_core_send, NULL); /*if (core_transmit_handle == NULL) * core_transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, GNUNET_YES, default_dv_priority, GNUNET_TIME_UNIT_FOREVER_REL, &to->identity, sizeof(p2p_dv_MESSAGE_NeighborInfo), &core_transmit_notify, NULL); */ } if (send_context->fast_gossip_list_head != NULL) /* If there are other peers in the fast list, schedule right away */ { #if DEBUG_DV_PEER_NUMBERS GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "DV SERVICE: still in fast send mode\n"); #endif send_context->task = GNUNET_SCHEDULER_add_now (&neighbor_send_task, send_context); } else { #if DEBUG_DV_PEER_NUMBERS GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "DV SERVICE: entering slow send mode\n"); #endif send_context->task = GNUNET_SCHEDULER_add_delayed (GNUNET_DV_DEFAULT_SEND_INTERVAL, &neighbor_send_task, send_context); } return; } /** * Handle START-message. This is the first message sent to us * by the client (can only be one!). * * @param cls closure (always NULL) * @param client identification of the client * @param message the actual message */ static void handle_start (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { #if DEBUG_DV GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' request from client\n", "START"); #endif client_handle = client; GNUNET_SERVER_client_keep (client_handle); GNUNET_SERVER_receive_done (client, GNUNET_OK); } #if UNSIMPLER /** * Iterate over hash map entries for a distant neighbor, * if direct neighbor matches context call send message * * @param cls closure, a DV_SendContext * @param key current key code * @param value value in the hash map * @return GNUNET_YES if we should continue to * iterate, * GNUNET_NO if not. */ int send_iterator (void *cls, const GNUNET_HashCode * key, void *abs_value) { struct DV_SendContext *send_context = cls; struct DistantNeighbor *distant_neighbor = abs_value; if (memcmp (distant_neighbor->referrer, send_context->direct_peer, sizeof (struct GNUNET_PeerIdentity)) == 0) /* They match, send and free */ { send_message_via (&my_identity, distant_neighbor, send_context); return GNUNET_NO; } return GNUNET_YES; } #endif /** * Service server's handler for message send requests (which come * bubbling up to us through the DV plugin). * * @param cls closure * @param client identification of the client * @param message the actual message */ void handle_dv_send_message (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct GNUNET_DV_SendMessage *send_msg; struct GNUNET_DV_SendResultMessage *send_result_msg; struct PendingMessage *pending_message; size_t address_len; size_t message_size; struct GNUNET_PeerIdentity *destination; struct GNUNET_PeerIdentity *direct; struct GNUNET_MessageHeader *message_buf; char *temp_pos; int offset; static struct GNUNET_CRYPTO_HashAsciiEncoded dest_hash; struct DV_SendContext *send_context; #if DEBUG_DV_MESSAGES char *cbuf; struct GNUNET_MessageHeader *packed_message; #endif if (client_handle == NULL) { client_handle = client; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Setting initial client handle, never received `%s' message?\n", "dv", "START"); } else if (client_handle != client) { client_handle = client; /* What should we do in this case, assert fail or just log the warning? */ #if DEBUG_DV GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Setting client handle (was a different client!)!\n", "dv"); #endif } GNUNET_assert (ntohs (message->size) > sizeof (struct GNUNET_DV_SendMessage)); send_msg = (struct GNUNET_DV_SendMessage *) message; address_len = ntohl (send_msg->addrlen); GNUNET_assert (address_len == sizeof (struct GNUNET_PeerIdentity) * 2); message_size = ntohs (message->size) - sizeof (struct GNUNET_DV_SendMessage) - address_len; destination = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity)); direct = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity)); message_buf = GNUNET_malloc (message_size); temp_pos = (char *) &send_msg[1]; /* Set pointer to end of message */ offset = 0; /* Offset starts at zero */ memcpy (destination, &temp_pos[offset], sizeof (struct GNUNET_PeerIdentity)); offset += sizeof (struct GNUNET_PeerIdentity); memcpy (direct, &temp_pos[offset], sizeof (struct GNUNET_PeerIdentity)); offset += sizeof (struct GNUNET_PeerIdentity); memcpy (message_buf, &temp_pos[offset], message_size); if (memcmp (&send_msg->target, destination, sizeof (struct GNUNET_PeerIdentity)) != 0) { GNUNET_CRYPTO_hash_to_enc (&destination->hashPubKey, &dest_hash); /* GNUNET_i2s won't properly work, need to hash one ourselves */ dest_hash.encoding[4] = '\0'; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: asked to send message to `%s', but address is for `%s'!", "DV SERVICE", GNUNET_i2s (&send_msg->target), (const char *) &dest_hash.encoding); } #if DEBUG_DV_MESSAGES cbuf = (char *) message_buf; offset = 0; while (offset < message_size) { packed_message = (struct GNUNET_MessageHeader *) &cbuf[offset]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: DV PLUGIN SEND uid %u type %d to %s\n", my_short_id, ntohl (send_msg->uid), ntohs (packed_message->type), GNUNET_i2s (destination)); offset += ntohs (packed_message->size); } /*GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "%s: DV PLUGIN SEND uid %u type %d to %s\n", my_short_id, ntohl(send_msg->uid), ntohs(message_buf->type), GNUNET_i2s(destination)); */ #endif GNUNET_CRYPTO_hash_to_enc (&destination->hashPubKey, &dest_hash); /* GNUNET_i2s won't properly work, need to hash one ourselves */ dest_hash.encoding[4] = '\0'; send_context = GNUNET_malloc (sizeof (struct DV_SendContext)); send_result_msg = GNUNET_malloc (sizeof (struct GNUNET_DV_SendResultMessage)); send_result_msg->header.size = htons (sizeof (struct GNUNET_DV_SendResultMessage)); send_result_msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND_RESULT); send_result_msg->uid = send_msg->uid; /* No need to ntohl->htonl this */ send_context->importance = ntohl (send_msg->priority); send_context->timeout = send_msg->timeout; send_context->direct_peer = direct; send_context->distant_peer = destination; send_context->message = message_buf; send_context->message_size = message_size; send_context->send_result = send_result_msg; #if DEBUG_DV_MESSAGES send_context->uid = send_msg->uid; #endif if (send_message_via (&my_identity, direct, send_context) != GNUNET_YES) { send_result_msg->result = htons (1); pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (struct GNUNET_DV_SendResultMessage)); pending_message->msg = (struct GNUNET_MessageHeader *) &pending_message[1]; memcpy (&pending_message[1], send_result_msg, sizeof (struct GNUNET_DV_SendResultMessage)); GNUNET_free (send_result_msg); GNUNET_CONTAINER_DLL_insert_after (plugin_pending_head, plugin_pending_tail, plugin_pending_tail, pending_message); if (client_handle != NULL) { if (plugin_transmit_handle == NULL) { plugin_transmit_handle = GNUNET_SERVER_notify_transmit_ready (client_handle, sizeof (struct GNUNET_DV_SendResultMessage), GNUNET_TIME_UNIT_FOREVER_REL, &transmit_to_plugin, NULL); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to queue message for plugin, must be one in progress already!!\n"); } } GNUNET_CRYPTO_hash_to_enc (&destination->hashPubKey, &dest_hash); /* GNUNET_i2s won't properly work, need to hash one ourselves */ dest_hash.encoding[4] = '\0'; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s DV SEND failed to send message to destination `%s' via `%s'\n", my_short_id, (const char *) &dest_hash.encoding, GNUNET_i2s (direct)); } /* In bizarro world GNUNET_SYSERR indicates that we succeeded */ #if UNSIMPLER if (GNUNET_SYSERR != GNUNET_CONTAINER_multihashmap_get_multiple (extended_neighbors, &destination->hashPubKey, &send_iterator, send_context)) { send_result_msg->result = htons (1); pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (struct GNUNET_DV_SendResultMessage)); pending_message->msg = (struct GNUNET_MessageHeader *) &pending_message[1]; memcpy (&pending_message[1], send_result_msg, sizeof (struct GNUNET_DV_SendResultMessage)); GNUNET_free (send_result_msg); GNUNET_CONTAINER_DLL_insert_after (plugin_pending_head, plugin_pending_tail, plugin_pending_tail, pending_message); if (client_handle != NULL) { if (plugin_transmit_handle == NULL) { plugin_transmit_handle = GNUNET_SERVER_notify_transmit_ready (client_handle, sizeof (struct GNUNET_DV_SendResultMessage), GNUNET_TIME_UNIT_FOREVER_REL, &transmit_to_plugin, NULL); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to queue message for plugin, must be one in progress already!!\n"); } } GNUNET_CRYPTO_hash_to_enc (&destination->hashPubKey, &dest_hash); /* GNUNET_i2s won't properly work, need to hash one ourselves */ dest_hash.encoding[4] = '\0'; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s DV SEND failed to send message to destination `%s' via `%s'\n", my_short_id, (const char *) &dest_hash.encoding, GNUNET_i2s (direct)); } #endif GNUNET_free (message_buf); GNUNET_free (send_context); GNUNET_free (direct); GNUNET_free (destination); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** Forward declarations **/ static int handle_dv_gossip_message (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count); static int handle_dv_disconnect_message (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count); /** End forward declarations **/ /** * List of handlers for the messages understood by this * service. * * Hmm... will we need to register some handlers with core and * some handlers with our server here? Because core should be * getting the incoming DV messages (from whichever lower level * transport) and then our server should be getting messages * from the dv_plugin, right? */ static struct GNUNET_CORE_MessageHandler core_handlers[] = { {&handle_dv_data_message, GNUNET_MESSAGE_TYPE_DV_DATA, 0}, {&handle_dv_gossip_message, GNUNET_MESSAGE_TYPE_DV_GOSSIP, 0}, {&handle_dv_disconnect_message, GNUNET_MESSAGE_TYPE_DV_DISCONNECT, 0}, {NULL, 0, 0} }; static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = { {&handle_dv_send_message, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND, 0}, {&handle_start, NULL, GNUNET_MESSAGE_TYPE_DV_START, 0}, {NULL, NULL, 0, 0} }; /** * Free a DistantNeighbor node, including removing it * from the referer's list. */ static void distant_neighbor_free (struct DistantNeighbor *referee) { struct DirectNeighbor *referrer; referrer = referee->referrer; if (referrer != NULL) { GNUNET_CONTAINER_DLL_remove (referrer->referee_head, referrer->referee_tail, referee); } GNUNET_CONTAINER_heap_remove_node (referee->max_loc); GNUNET_CONTAINER_heap_remove_node (referee->min_loc); GNUNET_CONTAINER_multihashmap_remove_all (extended_neighbors, &referee->identity.hashPubKey); GNUNET_free_non_null (referee->pkey); GNUNET_free (referee); } /** * Free a DirectNeighbor node, including removing it * from the referer's list. */ static void direct_neighbor_free (struct DirectNeighbor *direct) { struct NeighborSendContext *send_context; struct FastGossipNeighborList *about_list; struct FastGossipNeighborList *prev_about; send_context = direct->send_context; if (send_context->task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (send_context->task); about_list = send_context->fast_gossip_list_head; while (about_list != NULL) { GNUNET_CONTAINER_DLL_remove (send_context->fast_gossip_list_head, send_context->fast_gossip_list_tail, about_list); prev_about = about_list; about_list = about_list->next; GNUNET_free (prev_about); } GNUNET_free (send_context); GNUNET_free (direct); } /** * Multihashmap iterator for sending out disconnect messages * for a peer. * * @param cls the peer that was disconnected * @param key key value stored under * @param value the direct neighbor to send disconnect to * * @return GNUNET_YES to continue iteration, GNUNET_NO to stop */ static int schedule_disconnect_messages (void *cls, const GNUNET_HashCode * key, void *value) { struct DisconnectContext *disconnect_context = cls; struct DirectNeighbor *disconnected = disconnect_context->direct; struct DirectNeighbor *notify = value; struct PendingMessage *pending_message; p2p_dv_MESSAGE_Disconnect *disconnect_message; if (memcmp (¬ify->identity, &disconnected->identity, sizeof (struct GNUNET_PeerIdentity)) == 0) return GNUNET_YES; /* Don't send disconnect message to peer that disconnected! */ pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (p2p_dv_MESSAGE_Disconnect)); pending_message->msg = (struct GNUNET_MessageHeader *) &pending_message[1]; pending_message->importance = default_dv_priority; pending_message->timeout = GNUNET_TIME_UNIT_FOREVER_REL; memcpy (&pending_message->recipient, ¬ify->identity, sizeof (struct GNUNET_PeerIdentity)); pending_message->msg_size = sizeof (p2p_dv_MESSAGE_Disconnect); disconnect_message = (p2p_dv_MESSAGE_Disconnect *) pending_message->msg; disconnect_message->header.size = htons (sizeof (p2p_dv_MESSAGE_Disconnect)); disconnect_message->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DISCONNECT); disconnect_message->peer_id = htonl (disconnect_context->distant->our_id); GNUNET_CONTAINER_DLL_insert_after (core_pending_head, core_pending_tail, core_pending_tail, pending_message); GNUNET_SCHEDULER_add_now (try_core_send, NULL); /*if (core_transmit_handle == NULL) * core_transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, GNUNET_YES, default_dv_priority, GNUNET_TIME_UNIT_FOREVER_REL, ¬ify->identity, sizeof(p2p_dv_MESSAGE_Disconnect), &core_transmit_notify, NULL); */ return GNUNET_YES; } /** * Multihashmap iterator for freeing extended neighbors. * * @param cls NULL * @param key key value stored under * @param value the distant neighbor to be freed * * @return GNUNET_YES to continue iteration, GNUNET_NO to stop */ static int free_extended_neighbors (void *cls, const GNUNET_HashCode * key, void *value) { struct DistantNeighbor *distant = value; distant_neighbor_free (distant); return GNUNET_YES; } /** * Multihashmap iterator for freeing direct neighbors. * * @param cls NULL * @param key key value stored under * @param value the direct neighbor to be freed * * @return GNUNET_YES to continue iteration, GNUNET_NO to stop */ static int free_direct_neighbors (void *cls, const GNUNET_HashCode * key, void *value) { struct DirectNeighbor *direct = value; direct_neighbor_free (direct); return GNUNET_YES; } /** * Task run during shutdown. * * @param cls unused * @param tc unused */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { #if DEBUG_DV GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "calling CORE_DISCONNECT\n"); GNUNET_CONTAINER_multihashmap_iterate (extended_neighbors, &print_neighbors, NULL); #endif GNUNET_CONTAINER_multihashmap_iterate (extended_neighbors, &free_extended_neighbors, NULL); GNUNET_CONTAINER_multihashmap_destroy (extended_neighbors); GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors, &free_direct_neighbors, NULL); GNUNET_CONTAINER_multihashmap_destroy (direct_neighbors); GNUNET_CONTAINER_heap_destroy (neighbor_max_heap); GNUNET_CONTAINER_heap_destroy (neighbor_min_heap); GNUNET_CORE_disconnect (coreAPI); coreAPI = NULL; GNUNET_PEERINFO_disconnect (peerinfo_handle); GNUNET_SERVER_mst_destroy (coreMST); GNUNET_free_non_null (my_short_id); #if DEBUG_DV GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CORE_DISCONNECT completed\n"); #endif } /** * To be called on core init/fail. */ void core_init (void *cls, struct GNUNET_CORE_Handle *server, const struct GNUNET_PeerIdentity *identity) { if (server == NULL) { GNUNET_SCHEDULER_cancel (cleanup_task); GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); return; } #if DEBUG_DV GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Core connection initialized, I am peer: %s\n", "dv", GNUNET_i2s (identity)); #endif memcpy (&my_identity, identity, sizeof (struct GNUNET_PeerIdentity)); my_short_id = GNUNET_strdup (GNUNET_i2s (&my_identity)); coreAPI = server; } #if PKEY_NO_NEIGHBOR_ON_ADD /** * Iterator over hash map entries. * * @param cls closure * @param key current key code * @param value value in the hash map * @return GNUNET_YES if we should continue to * iterate, * GNUNET_NO if not. */ static int add_pkey_to_extended (void *cls, const GNUNET_HashCode * key, void *abs_value) { struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey = cls; struct DistantNeighbor *distant_neighbor = abs_value; if (distant_neighbor->pkey == NULL) { distant_neighbor->pkey = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); memcpy (distant_neighbor->pkey, pkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); } return GNUNET_YES; } #endif /** * Iterator over hash map entries. * * @param cls closure * @param key current key code * @param value value in the hash map * @return GNUNET_YES if we should continue to * iterate, * GNUNET_NO if not. */ static int update_matching_neighbors (void *cls, const GNUNET_HashCode * key, void *value) { struct NeighborUpdateInfo *update_info = cls; struct DistantNeighbor *distant_neighbor = value; if (update_info->referrer == distant_neighbor->referrer) /* Direct neighbor matches, update it's info and return GNUNET_NO */ { /* same referrer, cost change! */ GNUNET_CONTAINER_heap_update_cost (neighbor_max_heap, update_info->neighbor->max_loc, update_info->cost); GNUNET_CONTAINER_heap_update_cost (neighbor_min_heap, update_info->neighbor->min_loc, update_info->cost); update_info->neighbor->last_activity = update_info->now; update_info->neighbor->cost = update_info->cost; update_info->neighbor->referrer_id = update_info->referrer_peer_id; return GNUNET_NO; } return GNUNET_YES; } /** * Iterate over all current direct peers, add DISTANT newly connected * peer to the fast gossip list for that peer so we get DV routing * information out as fast as possible! * * @param cls the newly connected neighbor we will gossip about * @param key the hashcode of the peer * @param value the direct neighbor we should gossip to * * @return GNUNET_YES to continue iteration, GNUNET_NO otherwise */ static int add_distant_all_direct_neighbors (void *cls, const GNUNET_HashCode * key, void *value) { struct DirectNeighbor *direct = (struct DirectNeighbor *) value; struct DistantNeighbor *distant = (struct DistantNeighbor *) cls; struct NeighborSendContext *send_context = direct->send_context; struct FastGossipNeighborList *gossip_entry; #if DEBUG_DV char *encPeerAbout; char *encPeerTo; #endif if (distant == NULL) { return GNUNET_YES; } if (memcmp (&direct->identity, &distant->identity, sizeof (struct GNUNET_PeerIdentity)) == 0) { return GNUNET_YES; /* Don't gossip to a peer about itself! */ } #if SUPPORT_HIDING if (distant->hidden == GNUNET_YES) return GNUNET_YES; /* This peer should not be gossipped about (hidden) */ #endif gossip_entry = GNUNET_malloc (sizeof (struct FastGossipNeighborList)); gossip_entry->about = distant; GNUNET_CONTAINER_DLL_insert_after (send_context->fast_gossip_list_head, send_context->fast_gossip_list_tail, send_context->fast_gossip_list_tail, gossip_entry); #if DEBUG_DV encPeerAbout = GNUNET_strdup (GNUNET_i2s (&distant->identity)); encPeerTo = GNUNET_strdup (GNUNET_i2s (&direct->identity)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Fast send info about peer %s id %u for directly connected peer %s\n", GNUNET_i2s (&my_identity), encPeerAbout, distant->our_id, encPeerTo); GNUNET_free (encPeerAbout); GNUNET_free (encPeerTo); #endif /*if (send_context->task != GNUNET_SCHEDULER_NO_TASK) * GNUNET_SCHEDULER_cancel(send_context->task); */ send_context->task = GNUNET_SCHEDULER_add_now (&neighbor_send_task, send_context); return GNUNET_YES; } /** * Callback for hello address creation. * * @param cls closure, a struct HelloContext * @param max maximum number of bytes that can be written to buf * @param buf where to write the address information * * @return number of bytes written, 0 to signal the * end of the iteration. */ static size_t generate_hello_address (void *cls, size_t max, void *buf) { struct HelloContext *hello_context = cls; struct GNUNET_HELLO_Address hello_address; char *addr_buffer; size_t offset; size_t size; size_t ret; if (hello_context->addresses_to_add == 0) return 0; /* Hello "address" will be concatenation of distant peer and direct peer identities */ size = 2 * sizeof (struct GNUNET_PeerIdentity); GNUNET_assert (max >= size); addr_buffer = GNUNET_malloc (size); offset = 0; /* Copy the distant peer identity to buffer */ memcpy (addr_buffer, &hello_context->distant_peer, sizeof (struct GNUNET_PeerIdentity)); offset += sizeof (struct GNUNET_PeerIdentity); /* Copy the direct peer identity to buffer */ memcpy (&addr_buffer[offset], hello_context->direct_peer, sizeof (struct GNUNET_PeerIdentity)); memset (&hello_address.peer, 0, sizeof (struct GNUNET_PeerIdentity)); hello_address.address = addr_buffer; hello_address.transport_name = "dv"; hello_address.address_length = size; ret = GNUNET_HELLO_add_address (&hello_address, GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS), buf, max); hello_context->addresses_to_add--; GNUNET_free (addr_buffer); return ret; } /** * Handles when a peer is either added due to being newly connected * or having been gossiped about, also called when the cost for a neighbor * needs to be updated. * * @param peer identity of the peer whose info is being added/updated * @param pkey public key of the peer whose info is being added/updated * @param referrer_peer_id id to use when sending to 'peer' * @param referrer if this is a gossiped peer, who did we hear it from? * @param cost the cost of communicating with this peer via 'referrer' * * @return the added neighbor, the updated neighbor or NULL (neighbor * not added) */ static struct DistantNeighbor * addUpdateNeighbor (const struct GNUNET_PeerIdentity *peer, struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey, unsigned int referrer_peer_id, struct DirectNeighbor *referrer, unsigned int cost) { struct DistantNeighbor *neighbor; struct DistantNeighbor *max; struct GNUNET_TIME_Absolute now; struct NeighborUpdateInfo *neighbor_update; struct HelloContext *hello_context; struct GNUNET_HELLO_Message *hello_msg; unsigned int our_id; char *addr1; char *addr2; int i; #if DEBUG_DV_PEER_NUMBERS char *encAbout; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s Received sender id (%u)!\n", "DV SERVICE", referrer_peer_id); #endif now = GNUNET_TIME_absolute_get (); neighbor = GNUNET_CONTAINER_multihashmap_get (extended_neighbors, &peer->hashPubKey); neighbor_update = GNUNET_malloc (sizeof (struct NeighborUpdateInfo)); neighbor_update->neighbor = neighbor; neighbor_update->cost = cost; neighbor_update->now = now; neighbor_update->referrer = referrer; neighbor_update->referrer_peer_id = referrer_peer_id; if (neighbor != NULL) { #if USE_PEER_ID memcpy (&our_id, &neighbor->identity, sizeof (unsigned int)); #else our_id = neighbor->our_id; #endif } else { #if USE_PEER_ID memcpy (&our_id, peer, sizeof (unsigned int)); #else our_id = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, RAND_MAX - 1) + 1; #endif } /* Either we do not know this peer, or we already do but via a different immediate peer */ if ((neighbor == NULL) || (GNUNET_CONTAINER_multihashmap_get_multiple (extended_neighbors, &peer->hashPubKey, &update_matching_neighbors, neighbor_update) != GNUNET_SYSERR)) { #if AT_MOST_ONE if ((neighbor != NULL) && (cost < neighbor->cost)) /* New cost is less than old, remove old */ { distant_neighbor_free (neighbor); } else if (neighbor != NULL) /* Only allow one DV connection to each peer */ { return NULL; } #endif /* new neighbor! */ if (cost > fisheye_depth) { /* too costly */ GNUNET_free (neighbor_update); return NULL; } #if DEBUG_DV_PEER_NUMBERS encAbout = GNUNET_strdup (GNUNET_i2s (peer)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: %s Chose NEW id (%u) for peer %s!\n", GNUNET_i2s (&my_identity), "DV SERVICE", our_id, encAbout); GNUNET_free (encAbout); #endif if (max_table_size <= GNUNET_CONTAINER_multihashmap_size (extended_neighbors)) { /* remove most expensive entry */ max = GNUNET_CONTAINER_heap_peek (neighbor_max_heap); GNUNET_assert (max != NULL); if (cost > max->cost) { /* new entry most expensive, don't create */ GNUNET_free (neighbor_update); return NULL; } if (max->cost > 1) { /* only free if this is not a direct connection; * we could theoretically have more direct * connections than DV entries allowed total! */ distant_neighbor_free (max); } } neighbor = GNUNET_malloc (sizeof (struct DistantNeighbor)); GNUNET_CONTAINER_DLL_insert (referrer->referee_head, referrer->referee_tail, neighbor); neighbor->max_loc = GNUNET_CONTAINER_heap_insert (neighbor_max_heap, neighbor, cost); neighbor->min_loc = GNUNET_CONTAINER_heap_insert (neighbor_min_heap, neighbor, cost); neighbor->referrer = referrer; memcpy (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity)); if (pkey != NULL) /* pkey will be null on direct neighbor addition */ { neighbor->pkey = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); memcpy (neighbor->pkey, pkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); } else neighbor->pkey = pkey; neighbor->last_activity = now; neighbor->cost = cost; neighbor->referrer_id = referrer_peer_id; neighbor->our_id = our_id; neighbor->hidden = (cost == DIRECT_NEIGHBOR_COST) ? (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 4) == 0) : GNUNET_NO; GNUNET_CONTAINER_multihashmap_put (extended_neighbors, &peer->hashPubKey, neighbor, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); if (referrer_peer_id != 0) { for (i = 0; i < MAX_OUTSTANDING_MESSAGES; i++) { if (referrer->pending_messages[i].sender_id == referrer_peer_id) /* We have a queued message from just learned about peer! */ { #if DEBUG_DV_MESSAGES GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: learned about peer %llu from which we have a previous unknown message, processing!\n", my_short_id, referrer_peer_id); #endif struct GNUNET_ATS_Information atsi[2]; atsi[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); atsi[0].value = htonl (referrer->pending_messages[i].distance); atsi[1].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY); atsi[1].value = htonl ((uint32_t) referrer->pending_messages[i]. latency.rel_value); handle_dv_data_message (NULL, &referrer->pending_messages[i].sender, referrer->pending_messages[i].message, atsi, 2); GNUNET_free (referrer->pending_messages[i].message); referrer->pending_messages[i].sender_id = 0; } } } if ((cost != DIRECT_NEIGHBOR_COST) && (neighbor->pkey != NULL)) { /* Added neighbor, now send HELLO to transport */ hello_context = GNUNET_malloc (sizeof (struct HelloContext)); hello_context->direct_peer = &referrer->identity; memcpy (&hello_context->distant_peer, peer, sizeof (struct GNUNET_PeerIdentity)); hello_context->addresses_to_add = 1; hello_msg = GNUNET_HELLO_create (pkey, &generate_hello_address, hello_context); GNUNET_assert (memcmp (hello_context->direct_peer, &hello_context->distant_peer, sizeof (struct GNUNET_PeerIdentity)) != 0); addr1 = GNUNET_strdup (GNUNET_i2s (hello_context->direct_peer)); addr2 = GNUNET_strdup (GNUNET_i2s (&hello_context->distant_peer)); #if DEBUG_DV GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: GIVING HELLO size %d for %s via %s to TRANSPORT\n", my_short_id, GNUNET_HELLO_size (hello_msg), addr2, addr1); #endif GNUNET_free (addr1); GNUNET_free (addr2); send_to_plugin (hello_context->direct_peer, GNUNET_HELLO_get_header (hello_msg), GNUNET_HELLO_size (hello_msg), &hello_context->distant_peer, cost); GNUNET_free (hello_context); GNUNET_free (hello_msg); } } else { #if DEBUG_DV_GOSSIP GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Already know peer %s distance %d, referrer id %d!\n", "dv", GNUNET_i2s (peer), cost, referrer_peer_id); #endif } #if DEBUG_DV GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Size of extended_neighbors is %d\n", "dv", GNUNET_CONTAINER_multihashmap_size (extended_neighbors)); #endif GNUNET_free (neighbor_update); return neighbor; } /** * Core handler for dv disconnect messages. These will be used * by us to tell transport via the dv plugin that a peer can * no longer be contacted by us via a certain address. We should * then propagate these messages on, given that the distance to * the peer indicates we would have gossiped about it to others. * * @param cls closure * @param peer peer which sent the message (immediate sender) * @param message the message * @param atsi performance data * @param atsi_count number of entries in atsi */ static int handle_dv_disconnect_message (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct DirectNeighbor *referrer; struct DistantNeighbor *distant; p2p_dv_MESSAGE_Disconnect *enc_message = (p2p_dv_MESSAGE_Disconnect *) message; if (ntohs (message->size) < sizeof (p2p_dv_MESSAGE_Disconnect)) { return GNUNET_SYSERR; /* invalid message */ } referrer = GNUNET_CONTAINER_multihashmap_get (direct_neighbors, &peer->hashPubKey); if (referrer == NULL) return GNUNET_OK; distant = referrer->referee_head; while (distant != NULL) { if (distant->referrer_id == ntohl (enc_message->peer_id)) { distant_neighbor_free (distant); distant = referrer->referee_head; } else distant = distant->next; } return GNUNET_OK; } /** * Core handler for dv gossip messages. These will be used * by us to create a HELLO message for the newly peer containing * which direct peer we can connect through, and what the cost * is. This HELLO will then be scheduled for validation by the * transport service so that it can be used by all others. * * @param cls closure * @param peer peer which sent the message (immediate sender) * @param message the message * @param atsi performance data * @param atsi_count number of entries in atsi */ static int handle_dv_gossip_message (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct DirectNeighbor *referrer; p2p_dv_MESSAGE_NeighborInfo *enc_message = (p2p_dv_MESSAGE_NeighborInfo *) message; if (ntohs (message->size) < sizeof (p2p_dv_MESSAGE_NeighborInfo)) { return GNUNET_SYSERR; /* invalid message */ } #if DEBUG_DV_GOSSIP_RECEIPT char *encPeerAbout; char *encPeerFrom; encPeerAbout = GNUNET_strdup (GNUNET_i2s (&enc_message->neighbor)); encPeerFrom = GNUNET_strdup (GNUNET_i2s (peer)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Received %s message from peer %s about peer %s id %u distance %d!\n", GNUNET_i2s (&my_identity), "DV GOSSIP", encPeerFrom, encPeerAbout, ntohl (enc_message->neighbor_id), ntohl (enc_message->cost) + 1); GNUNET_free (encPeerAbout); GNUNET_free (encPeerFrom); #endif referrer = GNUNET_CONTAINER_multihashmap_get (direct_neighbors, &peer->hashPubKey); if (referrer == NULL) return GNUNET_OK; addUpdateNeighbor (&enc_message->neighbor, &enc_message->pkey, ntohl (enc_message->neighbor_id), referrer, ntohl (enc_message->cost) + 1); return GNUNET_OK; } /** * Iterate over all currently known peers, add them to the * fast gossip list for this peer so we get DV routing information * out as fast as possible! * * @param cls the direct neighbor we will gossip to * @param key the hashcode of the peer * @param value the distant neighbor we should add to the list * * @return GNUNET_YES to continue iteration, GNUNET_NO otherwise */ static int add_all_extended_peers (void *cls, const GNUNET_HashCode * key, void *value) { struct NeighborSendContext *send_context = (struct NeighborSendContext *) cls; struct DistantNeighbor *distant = (struct DistantNeighbor *) value; struct FastGossipNeighborList *gossip_entry; if (memcmp (&send_context->toNeighbor->identity, &distant->identity, sizeof (struct GNUNET_PeerIdentity)) == 0) return GNUNET_YES; /* Don't gossip to a peer about itself! */ #if SUPPORT_HIDING if (distant->hidden == GNUNET_YES) return GNUNET_YES; /* This peer should not be gossipped about (hidden) */ #endif gossip_entry = GNUNET_malloc (sizeof (struct FastGossipNeighborList)); gossip_entry->about = distant; GNUNET_CONTAINER_DLL_insert_after (send_context->fast_gossip_list_head, send_context->fast_gossip_list_tail, send_context->fast_gossip_list_tail, gossip_entry); return GNUNET_YES; } #if INSANE_GOSSIP /** * Iterator over hash map entries. * * @param cls closure * @param key current key code * @param value value in the hash map * @return GNUNET_YES if we should continue to * iterate, * GNUNET_NO if not. */ static int gossip_all_to_all_iterator (void *cls, const GNUNET_HashCode * key, void *abs_value) { struct DirectNeighbor *direct = abs_value; GNUNET_CONTAINER_multihashmap_iterate (extended_neighbors, &add_all_extended_peers, direct->send_context); if (direct->send_context->task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (direct->send_context->task); direct->send_context->task = GNUNET_SCHEDULER_add_now (&neighbor_send_task, direct->send_context); return GNUNET_YES; } /** * Task run during shutdown. * * @param cls unused * @param tc unused */ static void gossip_all_to_all (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors, &gossip_all_to_all_iterator, NULL); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), &gossip_all_to_all, NULL); } #endif /** * Iterate over all current direct peers, add newly connected peer * to the fast gossip list for that peer so we get DV routing * information out as fast as possible! * * @param cls the newly connected neighbor we will gossip about * @param key the hashcode of the peer * @param value the direct neighbor we should gossip to * * @return GNUNET_YES to continue iteration, GNUNET_NO otherwise */ static int add_all_direct_neighbors (void *cls, const GNUNET_HashCode * key, void *value) { struct DirectNeighbor *direct = (struct DirectNeighbor *) value; struct DirectNeighbor *to = (struct DirectNeighbor *) cls; struct DistantNeighbor *distant; struct NeighborSendContext *send_context = direct->send_context; struct FastGossipNeighborList *gossip_entry; char *direct_id; distant = GNUNET_CONTAINER_multihashmap_get (extended_neighbors, &to->identity.hashPubKey); if (distant == NULL) { return GNUNET_YES; } if (memcmp (&direct->identity, &to->identity, sizeof (struct GNUNET_PeerIdentity)) == 0) { return GNUNET_YES; /* Don't gossip to a peer about itself! */ } #if SUPPORT_HIDING if (distant->hidden == GNUNET_YES) return GNUNET_YES; /* This peer should not be gossipped about (hidden) */ #endif direct_id = GNUNET_strdup (GNUNET_i2s (&direct->identity)); #if DEBUG_DV_GOSSIP GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s: adding peer %s to fast send list for %s\n", my_short_id, GNUNET_i2s (&distant->identity), direct_id); #endif GNUNET_free (direct_id); gossip_entry = GNUNET_malloc (sizeof (struct FastGossipNeighborList)); gossip_entry->about = distant; GNUNET_CONTAINER_DLL_insert_after (send_context->fast_gossip_list_head, send_context->fast_gossip_list_tail, send_context->fast_gossip_list_tail, gossip_entry); if (send_context->task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (send_context->task); send_context->task = GNUNET_SCHEDULER_add_now (&neighbor_send_task, send_context); //tc.reason = GNUNET_SCHEDULER_REASON_TIMEOUT; //neighbor_send_task(send_context, &tc); return GNUNET_YES; } /** * Type of an iterator over the hosts. Note that each * host will be called with each available protocol. * * @param cls closure * @param peer id of the peer, NULL for last call * @param hello hello message for the peer (can be NULL) * @param err_msg NULL if successful, otherwise contains error message */ static void process_peerinfo (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Message *hello, const char *err_msg) { struct PeerIteratorContext *peerinfo_iterator = cls; struct DirectNeighbor *neighbor = peerinfo_iterator->neighbor; struct DistantNeighbor *distant = peerinfo_iterator->distant; #if DEBUG_DV_PEER_NUMBERS char *neighbor_pid; #endif int sent; if (err_msg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Error in communication with PEERINFO service\n")); /* return; */ } if (peer == NULL) { if (distant->pkey == NULL) { #if DEBUG_DV GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to get peerinfo information for this peer, retrying!\n"); #endif peerinfo_iterator->ic = GNUNET_PEERINFO_iterate (peerinfo_handle, &peerinfo_iterator->neighbor->identity, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3), &process_peerinfo, peerinfo_iterator); } else { GNUNET_free (peerinfo_iterator); } return; } if (memcmp (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity) != 0)) return; if ((hello != NULL) && (GNUNET_HELLO_get_key (hello, &neighbor->pkey) == GNUNET_OK)) { if (distant->pkey == NULL) { distant->pkey = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); memcpy (distant->pkey, &neighbor->pkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); } sent = GNUNET_CONTAINER_multihashmap_iterate (extended_neighbors, &add_all_extended_peers, neighbor->send_context); if (stats != NULL) { GNUNET_STATISTICS_update (stats, "# distant peers gossiped to direct neighbors", sent, GNUNET_NO); } #if DEBUG_DV_PEER_NUMBERS neighbor_pid = GNUNET_strdup (GNUNET_i2s (&neighbor->identity)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Gossipped %d extended peers to %s\n", GNUNET_i2s (&my_identity), sent, neighbor_pid); #endif sent = GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors, &add_all_direct_neighbors, neighbor); if (stats != NULL) { GNUNET_STATISTICS_update (stats, "# direct peers gossiped to direct neighbors", sent, GNUNET_NO); } #if DEBUG_DV_PEER_NUMBERS GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Gossipped about %s to %d direct peers\n", GNUNET_i2s (&my_identity), neighbor_pid, sent); GNUNET_free (neighbor_pid); #endif neighbor->send_context->task = GNUNET_SCHEDULER_add_now (&neighbor_send_task, neighbor->send_context); } } /** * Method called whenever a peer connects. * * @param cls closure * @param peer peer identity this notification is about * @param atsi performance data * @param atsi_count number of entries in atsi */ static void handle_core_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct DirectNeighbor *neighbor; struct DistantNeighbor *about; struct PeerIteratorContext *peerinfo_iterator; int sent; uint32_t distance; /* Check for connect to self message */ if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity))) return; distance = get_atsi_distance (atsi, atsi_count); if ((distance == DIRECT_NEIGHBOR_COST) && (GNUNET_CONTAINER_multihashmap_get (direct_neighbors, &peer->hashPubKey) == NULL)) { peerinfo_iterator = GNUNET_malloc (sizeof (struct PeerIteratorContext)); neighbor = GNUNET_malloc (sizeof (struct DirectNeighbor)); neighbor->send_context = GNUNET_malloc (sizeof (struct NeighborSendContext)); neighbor->send_context->toNeighbor = neighbor; memcpy (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity)); GNUNET_assert (GNUNET_SYSERR != GNUNET_CONTAINER_multihashmap_put (direct_neighbors, &peer->hashPubKey, neighbor, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); about = addUpdateNeighbor (peer, NULL, 0, neighbor, DIRECT_NEIGHBOR_COST); peerinfo_iterator->distant = about; peerinfo_iterator->neighbor = neighbor; peerinfo_iterator->ic = GNUNET_PEERINFO_iterate (peerinfo_handle, peer, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3), &process_peerinfo, peerinfo_iterator); if ((about != NULL) && (about->pkey == NULL)) { #if DEBUG_DV GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Newly added peer %s has NULL pkey!\n", GNUNET_i2s (peer)); #endif } else if (about != NULL) { GNUNET_free (peerinfo_iterator); } } else { about = GNUNET_CONTAINER_multihashmap_get (extended_neighbors, &peer->hashPubKey); if ((GNUNET_CONTAINER_multihashmap_get (direct_neighbors, &peer->hashPubKey) == NULL) && (about != NULL)) { sent = GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors, &add_distant_all_direct_neighbors, about); if (stats != NULL) GNUNET_STATISTICS_update (stats, "# direct peers gossiped to new direct neighbors", sent, GNUNET_NO); } #if DEBUG_DV GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Distance (%d) greater than %d or already know about peer (%s), not re-adding!\n", "dv", distance, DIRECT_NEIGHBOR_COST, GNUNET_i2s (peer)); #endif return; } } /** * Method called whenever a given peer disconnects. * * @param cls closure * @param peer peer identity this notification is about */ void handle_core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { struct DirectNeighbor *neighbor; struct DistantNeighbor *referee; struct FindDestinationContext fdc; struct DisconnectContext disconnect_context; struct PendingMessage *pending_pos; #if DEBUG_DV GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Receives core peer disconnect message!\n", "dv"); #endif /* Check for disconnect from self message */ if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity))) return; neighbor = GNUNET_CONTAINER_multihashmap_get (direct_neighbors, &peer->hashPubKey); if (neighbor == NULL) { return; } pending_pos = core_pending_head; while (NULL != pending_pos) { if (0 == memcmp (&pending_pos->recipient, &neighbor->identity, sizeof (struct GNUNET_PeerIdentity))) { GNUNET_CONTAINER_DLL_remove (core_pending_head, core_pending_tail, pending_pos); pending_pos = core_pending_head; } else pending_pos = pending_pos->next; } while (NULL != (referee = neighbor->referee_head)) distant_neighbor_free (referee); fdc.dest = NULL; fdc.tid = 0; GNUNET_CONTAINER_multihashmap_iterate (extended_neighbors, &find_distant_peer, &fdc); if (fdc.dest != NULL) { disconnect_context.direct = neighbor; disconnect_context.distant = fdc.dest; GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors, &schedule_disconnect_messages, &disconnect_context); } GNUNET_assert (neighbor->referee_tail == NULL); if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_remove (direct_neighbors, &peer->hashPubKey, neighbor)) { GNUNET_break (0); } if ((neighbor->send_context != NULL) && (neighbor->send_context->task != GNUNET_SCHEDULER_NO_TASK)) GNUNET_SCHEDULER_cancel (neighbor->send_context->task); GNUNET_free (neighbor); } /** * Process dv requests. * * @param cls closure * @param server the initialized server * @param c configuration to use */ static void run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *c) { unsigned long long max_hosts; cfg = c; /* FIXME: Read from config, or calculate, or something other than this! */ max_hosts = DEFAULT_DIRECT_CONNECTIONS; max_table_size = DEFAULT_DV_SIZE; fisheye_depth = DEFAULT_FISHEYE_DEPTH; if (GNUNET_CONFIGURATION_have_value (cfg, "dv", "max_direct_connections")) GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg, "dv", "max_direct_connections", &max_hosts)); if (GNUNET_CONFIGURATION_have_value (cfg, "dv", "max_total_connections")) GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg, "dv", "max_total_connections", &max_table_size)); if (GNUNET_CONFIGURATION_have_value (cfg, "dv", "fisheye_depth")) GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg, "dv", "fisheye_depth", &fisheye_depth)); neighbor_min_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); neighbor_max_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX); direct_neighbors = GNUNET_CONTAINER_multihashmap_create (max_hosts); extended_neighbors = GNUNET_CONTAINER_multihashmap_create (max_table_size * 3); GNUNET_SERVER_add_handlers (server, plugin_handlers); coreAPI = GNUNET_CORE_connect (cfg, 1, NULL, /* FIXME: anything we want to pass around? */ &core_init, &handle_core_connect, &handle_core_disconnect, NULL, GNUNET_NO, NULL, GNUNET_NO, core_handlers); if (coreAPI == NULL) return; coreMST = GNUNET_SERVER_mst_create (&tokenized_message_handler, NULL); peerinfo_handle = GNUNET_PEERINFO_connect (cfg); if (peerinfo_handle == NULL) { GNUNET_CORE_disconnect (coreAPI); return; } /* Scheduled the task to clean up when shutdown is called */ cleanup_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); } /** * The main function for the dv service. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { return (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "dv", GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; } gnunet-0.9.3/src/dv/dv_api.c0000644000175000017500000004132411760502551012560 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dv/dv_api.c * @brief library to access the DV service * @author Christian Grothoff * @author Nathan Evans */ #include "platform.h" #include "gnunet_bandwidth_lib.h" #include "gnunet_client_lib.h" #include "gnunet_constants.h" #include "gnunet_container_lib.h" #include "gnunet_arm_service.h" #include "gnunet_hello_lib.h" #include "gnunet_protocols.h" #include "gnunet_server_lib.h" #include "gnunet_time_lib.h" #include "gnunet_dv_service.h" #include "dv.h" #include "gnunet_transport_plugin.h" #define LOG(kind,...) GNUNET_log_from (kind, "dv-api",__VA_ARGS__) /** * Store ready to send messages */ struct PendingMessages { /** * Linked list of pending messages */ struct PendingMessages *next; /** * Message that is pending */ struct GNUNET_DV_SendMessage *msg; /** * Timeout for this message */ struct GNUNET_TIME_Absolute timeout; }; /** * Handle for the service. */ struct GNUNET_DV_Handle { /** * Configuration to use. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Socket (if available). */ struct GNUNET_CLIENT_Connection *client; /** * Currently pending transmission request. */ struct GNUNET_CLIENT_TransmitHandle *th; /** * List of the currently pending messages for the DV service. */ struct PendingMessages *pending_list; /** * Message we are currently sending. */ struct PendingMessages *current; /** * Handler for messages we receive from the DV service */ GNUNET_DV_MessageReceivedHandler receive_handler; /** * Closure for the receive handler */ void *receive_cls; /** * Current unique ID */ uint32_t uid_gen; /** * Hashmap containing outstanding send requests awaiting confirmation. */ struct GNUNET_CONTAINER_MultiHashMap *send_callbacks; }; struct StartContext { /** * Start message */ struct GNUNET_MessageHeader *message; /** * Handle to service, in case of timeout */ struct GNUNET_DV_Handle *handle; }; struct SendCallbackContext { /** * The continuation to call once a message is confirmed sent (or failed) */ GNUNET_TRANSPORT_TransmitContinuation cont; /** * Closure to call with send continuation. */ void *cont_cls; /** * Target of the message. */ struct GNUNET_PeerIdentity target; }; /** * Convert unique ID to hash code. * * @param uid unique ID to convert * @param hash set to uid (extended with zeros) */ static void hash_from_uid (uint32_t uid, GNUNET_HashCode * hash) { memset (hash, 0, sizeof (GNUNET_HashCode)); *((uint32_t *) hash) = uid; } /** * Try to (re)connect to the dv service. * * @param ret handle to the (disconnected) dv service * * @return GNUNET_YES on success, GNUNET_NO on failure. */ static int try_connect (struct GNUNET_DV_Handle *ret) { if (ret->client != NULL) return GNUNET_OK; ret->client = GNUNET_CLIENT_connect ("dv", ret->cfg); if (ret->client != NULL) return GNUNET_YES; #if DEBUG_DV_MESSAGES LOG (GNUNET_ERROR_TYPE_DEBUG, _("Failed to connect to the dv service!\n")); #endif return GNUNET_NO; } static void process_pending_message (struct GNUNET_DV_Handle *handle); /** * Send complete, schedule next * * @param handle handle to the dv service * @param code return code for send (unused) */ static void finish (struct GNUNET_DV_Handle *handle, int code) { struct PendingMessages *pos = handle->current; handle->current = NULL; process_pending_message (handle); GNUNET_free (pos->msg); GNUNET_free (pos); } /** * Notification that we can send data * * @param cls handle to the dv service (struct GNUNET_DV_Handle) * @param size how many bytes can we send * @param buf where to copy the message to send * * @return how many bytes we copied to buf */ static size_t transmit_pending (void *cls, size_t size, void *buf) { struct GNUNET_DV_Handle *handle = cls; size_t ret; size_t tsize; #if DEBUG_DV if (handle->current != NULL) LOG (GNUNET_ERROR_TYPE_DEBUG, "DV API: Transmit pending called with message type %d\n", ntohs (handle->current->msg->header.type)); #endif if (buf == NULL) { #if DEBUG_DV LOG (GNUNET_ERROR_TYPE_DEBUG, "DV API: Transmit pending FAILED!\n\n\n"); #endif finish (handle, GNUNET_SYSERR); return 0; } handle->th = NULL; ret = 0; if (handle->current != NULL) { tsize = ntohs (handle->current->msg->header.size); if (size >= tsize) { memcpy (buf, handle->current->msg, tsize); #if DEBUG_DV LOG (GNUNET_ERROR_TYPE_DEBUG, "DV API: Copied %d bytes into buffer!\n\n\n", tsize); #endif finish (handle, GNUNET_OK); return tsize; } } return ret; } /** * Try to send messages from list of messages to send * * @param handle handle to the distance vector service */ static void process_pending_message (struct GNUNET_DV_Handle *handle) { if (handle->current != NULL) return; /* action already pending */ if (GNUNET_YES != try_connect (handle)) { finish (handle, GNUNET_SYSERR); return; } /* schedule next action */ handle->current = handle->pending_list; if (NULL == handle->current) { return; } handle->pending_list = handle->pending_list->next; handle->current->next = NULL; if (NULL == (handle->th = GNUNET_CLIENT_notify_transmit_ready (handle->client, ntohs (handle->current->msg-> header.size), handle->current->msg->timeout, GNUNET_YES, &transmit_pending, handle))) { #if DEBUG_DV LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to transmit request to dv service.\n"); #endif finish (handle, GNUNET_SYSERR); } } /** * Add a pending message to the linked list * * @param handle handle to the specified DV api * @param msg the message to add to the list */ static void add_pending (struct GNUNET_DV_Handle *handle, struct GNUNET_DV_SendMessage *msg) { struct PendingMessages *new_message; struct PendingMessages *pos; struct PendingMessages *last; new_message = GNUNET_malloc (sizeof (struct PendingMessages)); new_message->msg = msg; if (handle->pending_list != NULL) { pos = handle->pending_list; while (pos != NULL) { last = pos; pos = pos->next; } last->next = new_message; } else { handle->pending_list = new_message; } process_pending_message (handle); } /** * Handles a message sent from the DV service to us. * Parse it out and give it to the plugin. * * @param cls the handle to the DV API * @param msg the message that was received */ void handle_message_receipt (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_DV_Handle *handle = cls; struct GNUNET_DV_MessageReceived *received_msg; struct GNUNET_DV_SendResultMessage *send_result_msg; size_t packed_msg_len; size_t sender_address_len; char *sender_address; char *packed_msg; char *packed_msg_start; GNUNET_HashCode uidhash; struct SendCallbackContext *send_ctx; if (msg == NULL) { #if DEBUG_DV_MESSAGES LOG (GNUNET_ERROR_TYPE_DEBUG, "DV_API receive: connection closed\n"); #endif return; /* Connection closed? */ } GNUNET_assert ((ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_DV_RECEIVE) || (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND_RESULT)); switch (ntohs (msg->type)) { case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_RECEIVE: if (ntohs (msg->size) < sizeof (struct GNUNET_DV_MessageReceived)) return; received_msg = (struct GNUNET_DV_MessageReceived *) msg; packed_msg_len = ntohl (received_msg->msg_len); sender_address_len = ntohs (msg->size) - packed_msg_len - sizeof (struct GNUNET_DV_MessageReceived); GNUNET_assert (sender_address_len > 0); sender_address = GNUNET_malloc (sender_address_len); memcpy (sender_address, &received_msg[1], sender_address_len); packed_msg_start = (char *) &received_msg[1]; packed_msg = GNUNET_malloc (packed_msg_len); memcpy (packed_msg, &packed_msg_start[sender_address_len], packed_msg_len); #if DEBUG_DV_MESSAGES LOG (GNUNET_ERROR_TYPE_DEBUG, "DV_API receive: packed message type: %d or %d\n", ntohs (((struct GNUNET_MessageHeader *) packed_msg)->type), ((struct GNUNET_MessageHeader *) packed_msg)->type); LOG (GNUNET_ERROR_TYPE_DEBUG, "DV_API receive: message sender reported as %s\n", GNUNET_i2s (&received_msg->sender)); LOG (GNUNET_ERROR_TYPE_DEBUG, "DV_API receive: distance is %u\n", ntohl (received_msg->distance)); #endif handle->receive_handler (handle->receive_cls, &received_msg->sender, packed_msg, packed_msg_len, ntohl (received_msg->distance), sender_address, sender_address_len); GNUNET_free (sender_address); break; case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND_RESULT: if (ntohs (msg->size) < sizeof (struct GNUNET_DV_SendResultMessage)) return; send_result_msg = (struct GNUNET_DV_SendResultMessage *) msg; hash_from_uid (ntohl (send_result_msg->uid), &uidhash); send_ctx = GNUNET_CONTAINER_multihashmap_get (handle->send_callbacks, &uidhash); if ((send_ctx != NULL) && (send_ctx->cont != NULL)) { if (ntohl (send_result_msg->result) == 0) { send_ctx->cont (send_ctx->cont_cls, &send_ctx->target, GNUNET_OK); } else { send_ctx->cont (send_ctx->cont_cls, &send_ctx->target, GNUNET_SYSERR); } } GNUNET_free_non_null (send_ctx); break; default: break; } GNUNET_CLIENT_receive (handle->client, &handle_message_receipt, handle, GNUNET_TIME_UNIT_FOREVER_REL); } /** * Send a message from the plugin to the DV service indicating that * a message should be sent via DV to some peer. * * @param dv_handle the handle to the DV api * @param target the final target of the message * @param msgbuf the msg(s) to send * @param msgbuf_size the size of msgbuf * @param priority priority to pass on to core when sending the message * @param timeout how long can this message be delayed (pass through to core) * @param addr the address of this peer (internally known to DV) * @param addrlen the length of the peer address * @param cont continuation to call once the message has been sent (or failed) * @param cont_cls closure for continuation * */ int GNUNET_DV_send (struct GNUNET_DV_Handle *dv_handle, const struct GNUNET_PeerIdentity *target, const char *msgbuf, size_t msgbuf_size, unsigned int priority, struct GNUNET_TIME_Relative timeout, const void *addr, size_t addrlen, GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) { struct GNUNET_DV_SendMessage *msg; struct SendCallbackContext *send_ctx; char *end_of_message; GNUNET_HashCode uidhash; int msize; #if DEBUG_DV_MESSAGES dv_handle->uid_gen = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, UINT32_MAX); #else dv_handle->uid_gen++; #endif msize = sizeof (struct GNUNET_DV_SendMessage) + addrlen + msgbuf_size; msg = GNUNET_malloc (msize); msg->header.size = htons (msize); msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND); memcpy (&msg->target, target, sizeof (struct GNUNET_PeerIdentity)); msg->priority = htonl (priority); msg->timeout = timeout; msg->addrlen = htonl (addrlen); msg->uid = htonl (dv_handle->uid_gen); memcpy (&msg[1], addr, addrlen); end_of_message = (char *) &msg[1]; end_of_message = &end_of_message[addrlen]; memcpy (end_of_message, msgbuf, msgbuf_size); add_pending (dv_handle, msg); send_ctx = GNUNET_malloc (sizeof (struct SendCallbackContext)); send_ctx->cont = cont; send_ctx->cont_cls = cont_cls; memcpy (&send_ctx->target, target, sizeof (struct GNUNET_PeerIdentity)); hash_from_uid (dv_handle->uid_gen, &uidhash); GNUNET_CONTAINER_multihashmap_put (dv_handle->send_callbacks, &uidhash, send_ctx, GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); return GNUNET_OK; } /** * Callback to transmit a start message to * the DV service, once we can send * * @param cls struct StartContext * @param size how much can we send * @param buf where to copy the message * * @return number of bytes copied to buf */ static size_t transmit_start (void *cls, size_t size, void *buf) { struct StartContext *start_context = cls; struct GNUNET_DV_Handle *handle = start_context->handle; size_t tsize; #if DEBUG_DV LOG (GNUNET_ERROR_TYPE_DEBUG, "DV API: sending start request to service\n"); #endif if (buf == NULL) { GNUNET_free (start_context->message); GNUNET_free (start_context); GNUNET_DV_disconnect (handle); return 0; } tsize = ntohs (start_context->message->size); if (size >= tsize) { memcpy (buf, start_context->message, tsize); GNUNET_free (start_context->message); GNUNET_free (start_context); GNUNET_CLIENT_receive (handle->client, &handle_message_receipt, handle, GNUNET_TIME_UNIT_FOREVER_REL); return tsize; } return 0; } /** * Connect to the DV service * * @param cfg the configuration to use * @param receive_handler method call when on receipt from the service * @param receive_handler_cls closure for receive_handler * * @return handle to the DV service */ struct GNUNET_DV_Handle * GNUNET_DV_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_DV_MessageReceivedHandler receive_handler, void *receive_handler_cls) { struct GNUNET_DV_Handle *handle; struct GNUNET_MessageHeader *start_message; struct StartContext *start_context; handle = GNUNET_malloc (sizeof (struct GNUNET_DV_Handle)); handle->cfg = cfg; handle->pending_list = NULL; handle->current = NULL; handle->th = NULL; handle->client = GNUNET_CLIENT_connect ("dv", cfg); handle->receive_handler = receive_handler; handle->receive_cls = receive_handler_cls; if (handle->client == NULL) { GNUNET_free (handle); return NULL; } start_message = GNUNET_malloc (sizeof (struct GNUNET_MessageHeader)); start_message->size = htons (sizeof (struct GNUNET_MessageHeader)); start_message->type = htons (GNUNET_MESSAGE_TYPE_DV_START); start_context = GNUNET_malloc (sizeof (struct StartContext)); start_context->handle = handle; start_context->message = start_message; GNUNET_CLIENT_notify_transmit_ready (handle->client, sizeof (struct GNUNET_MessageHeader), GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60), GNUNET_YES, &transmit_start, start_context); handle->send_callbacks = GNUNET_CONTAINER_multihashmap_create (100); return handle; } /** * Disconnect from the DV service * * @param handle the current handle to the service to disconnect */ void GNUNET_DV_disconnect (struct GNUNET_DV_Handle *handle) { struct PendingMessages *pos; GNUNET_assert (handle != NULL); if (handle->th != NULL) /* We have a live transmit request in the Aether */ { GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th); handle->th = NULL; } if (handle->current != NULL) /* We are trying to send something now, clean it up */ GNUNET_free (handle->current); while (NULL != (pos = handle->pending_list)) /* Remove all pending sends from the list */ { handle->pending_list = pos->next; GNUNET_free (pos); } if (handle->client != NULL) /* Finally, disconnect from the service */ { GNUNET_CLIENT_disconnect (handle->client); handle->client = NULL; } GNUNET_free (handle); } /* end of dv_api.c */ gnunet-0.9.3/src/dv/dv.h0000644000175000017500000001414111760502551011731 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @author Christian Grothoff * @author NOT Nathan Evans * @file dv/dv.h */ #ifndef DV_H #define DV_H #include "gnunet_common.h" #define DEBUG_DV_GOSSIP GNUNET_EXTRA_LOGGING #define DEBUG_DV_GOSSIP_SEND GNUNET_EXTRA_LOGGING #define DEBUG_DV_GOSSIP_RECEIPT GNUNET_EXTRA_LOGGING #define DEBUG_DV_MESSAGES GNUNET_EXTRA_LOGGING #define DEBUG_DV GNUNET_EXTRA_LOGGING #define DEBUG_DV_PEER_NUMBERS GNUNET_EXTRA_LOGGING #define DEBUG_MESSAGE_DROP GNUNET_EXTRA_LOGGING typedef void (*GNUNET_DV_MessageReceivedHandler) (void *cls, struct GNUNET_PeerIdentity * sender, char *msg, size_t msg_len, uint32_t distance, char *sender_address, size_t sender_address_len); GNUNET_NETWORK_STRUCT_BEGIN /** * DV Message, contains a message that was received * via DV for this peer! Internal. * * Sender address is copied to the end of this struct, * followed by the actual message received. */ struct GNUNET_DV_MessageReceived { /** * Type: GNUNET_MESSAGE_TYPE_TRANSPORT_DV_MESSAGE */ struct GNUNET_MessageHeader header; /** * The sender of the message */ struct GNUNET_PeerIdentity sender; /** * The length of the message that was sent (appended to this end of struct) */ uint32_t msg_len; /** * The distance to the peer that we received the message from */ uint32_t distance; }; /** * DV Message, indicates that we have learned of a new DV level peer. * Internal. * * Sender address is copied to the end of this struct. */ struct GNUNET_DV_ConnectMessage { /** * Type: GNUNET_MESSAGE_TYPE_TRANSPORT_DV_MESSAGE */ struct GNUNET_MessageHeader header; /** * The sender of the message */ struct GNUNET_PeerIdentity *sender; /** * The message that was sent */ struct GNUNET_MessageHeader *msg; /** * The distance to the peer that we received the message from */ uint32_t distance; /** * Length of the sender address, appended to end of this message */ uint32_t sender_address_len; }; /** * Message to return result from a send attempt. * Internal. */ struct GNUNET_DV_SendResultMessage { /** * Type: GNUNET_MESSAGE_TYPE_DV_SEND_RESULT */ struct GNUNET_MessageHeader header; /** * Unique ID for attempted sent message. */ uint32_t uid; /** * Result of attempted send, 0 for send okay, * 1 for failure of any reason. */ uint32_t result; }; /** * Message to send a message over DV via a specific peer. * Internal. */ struct GNUNET_DV_SendMessage { /** * Type: GNUNET_MESSAGE_TYPE_DV_SEND */ struct GNUNET_MessageHeader header; /** * Intended final recipient of this message */ struct GNUNET_PeerIdentity target; /** * Message priority */ uint32_t priority; /** * Unique ID for this message, for confirm callback. */ uint32_t uid; /** * How long can we delay sending? */ struct GNUNET_TIME_Relative timeout; /** * Size of the address (appended to end of struct) */ uint32_t addrlen; /** * The message(s) to be sent. */ char *msgbuf; /* * Sender, appended to end of struct tells via whom * to send this message. */ }; /** * Message that gets sent between nodes updating dv infos */ typedef struct { /* Message Header */ struct GNUNET_MessageHeader header; /** * Cost from received from node to neighbor node, takes distance into account */ uint32_t cost GNUNET_PACKED; /** * Identity of neighbor we learned information about */ struct GNUNET_PeerIdentity neighbor; /** * PublicKey of neighbor. */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; /** * Neighbor ID to use when sending to this peer */ uint32_t neighbor_id GNUNET_PACKED; } p2p_dv_MESSAGE_NeighborInfo; /** * Message that gets sent between nodes carrying information */ typedef struct { struct GNUNET_MessageHeader header; /** * Unique ID for this message. Will be zero unless * message tracking is desired. */ uint32_t uid GNUNET_PACKED; /** * Identity of peer that ultimately sent the message. * Should be looked up in the set of 'neighbor_id's of * the referring peer. */ uint32_t sender GNUNET_PACKED; /** * Identity of neighbor this message is going to. Should * be looked up in the set of our own identifiers for * neighbors! */ uint32_t recipient GNUNET_PACKED; } p2p_dv_MESSAGE_Data; /** * Message that gets sent between nodes indicating a peer * was disconnected. */ typedef struct { struct GNUNET_MessageHeader header; /** * Identity of neighbor that was disconnected. */ uint32_t peer_id GNUNET_PACKED; } p2p_dv_MESSAGE_Disconnect; GNUNET_NETWORK_STRUCT_END struct GNUNET_DV_Handle * GNUNET_DV_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_DV_MessageReceivedHandler receive_handler, void *receive_handler_cls); /** * Disconnect from the DV service * * @param handle the current handle to the service to disconnect */ void GNUNET_DV_disconnect (struct GNUNET_DV_Handle *handle); #endif gnunet-0.9.3/src/dv/Makefile.in0000644000175000017500000007734111762217211013225 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-service-dv$(EXEEXT) check_PROGRAMS = test_transport_api_dv$(EXEEXT) @ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) subdir = src/dv DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/dv.conf.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = dv.conf CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \ "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) $(plugin_LTLIBRARIES) am_libgnunet_plugin_transport_dv_la_OBJECTS = plugin_transport_dv.lo libgnunet_plugin_transport_dv_la_OBJECTS = \ $(am_libgnunet_plugin_transport_dv_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunet_plugin_transport_dv_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) \ $(libgnunet_plugin_transport_dv_la_LDFLAGS) $(LDFLAGS) -o $@ am__DEPENDENCIES_1 = libgnunetdv_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am_libgnunetdv_la_OBJECTS = dv_api.lo libgnunetdv_la_OBJECTS = $(am_libgnunetdv_la_OBJECTS) libgnunetdv_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetdv_la_LDFLAGS) $(LDFLAGS) -o \ $@ PROGRAMS = $(bin_PROGRAMS) am_gnunet_service_dv_OBJECTS = gnunet-service-dv.$(OBJEXT) gnunet_service_dv_OBJECTS = $(am_gnunet_service_dv_OBJECTS) am_test_transport_api_dv_OBJECTS = test_transport_api_dv.$(OBJEXT) test_transport_api_dv_OBJECTS = $(am_test_transport_api_dv_OBJECTS) test_transport_api_dv_DEPENDENCIES = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunet_plugin_transport_dv_la_SOURCES) \ $(libgnunetdv_la_SOURCES) $(gnunet_service_dv_SOURCES) \ $(test_transport_api_dv_SOURCES) DIST_SOURCES = $(libgnunet_plugin_transport_dv_la_SOURCES) \ $(libgnunetdv_la_SOURCES) $(gnunet_service_dv_SOURCES) \ $(test_transport_api_dv_SOURCES) DATA = $(pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @USE_COVERAGE_TRUE@XLIB = -lgcov plugindir = $(libdir)/gnunet pkgcfgdir = $(pkgdatadir)/config.d/ pkgcfg_DATA = \ dv.conf lib_LTLIBRARIES = libgnunetdv.la plugin_LTLIBRARIES = libgnunet_plugin_transport_dv.la libgnunetdv_la_SOURCES = \ dv_api.c dv.h libgnunetdv_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(GN_LIBINTL) $(XLIB) libgnunetdv_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 0:0:0 gnunet_service_dv_SOURCES = \ gnunet-service-dv.c gnunet_service_dv_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/dv/libgnunetdv.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_service_dv_DEPENDENCIES = \ libgnunetdv.la libgnunet_plugin_transport_dv_la_SOURCES = \ plugin_transport_dv.c libgnunet_plugin_transport_dv_la_LIBADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/dv/libgnunetdv.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_transport_dv_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_transport_dv_la_DEPENDENCIES = \ libgnunetdv.la test_transport_api_dv_SOURCES = \ test_transport_api_dv.c test_transport_api_dv_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la EXTRA_DIST = \ test_transport_dv_data.conf all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/dv/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/dv/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): dv.conf: $(top_builddir)/config.status $(srcdir)/dv.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ } uninstall-pluginLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ done clean-pluginLTLIBRARIES: -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunet_plugin_transport_dv.la: $(libgnunet_plugin_transport_dv_la_OBJECTS) $(libgnunet_plugin_transport_dv_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_transport_dv_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_transport_dv_la_OBJECTS) $(libgnunet_plugin_transport_dv_la_LIBADD) $(LIBS) libgnunetdv.la: $(libgnunetdv_la_OBJECTS) $(libgnunetdv_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetdv_la_LINK) -rpath $(libdir) $(libgnunetdv_la_OBJECTS) $(libgnunetdv_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-service-dv$(EXEEXT): $(gnunet_service_dv_OBJECTS) $(gnunet_service_dv_DEPENDENCIES) @rm -f gnunet-service-dv$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_service_dv_OBJECTS) $(gnunet_service_dv_LDADD) $(LIBS) test_transport_api_dv$(EXEEXT): $(test_transport_api_dv_OBJECTS) $(test_transport_api_dv_DEPENDENCIES) @rm -f test_transport_api_dv$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_transport_api_dv_OBJECTS) $(test_transport_api_dv_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dv_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-dv.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_transport_dv.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_dv.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgcfgDATA: $(pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool clean-pluginLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgcfgDATA install-pluginLTLIBRARIES install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool clean-pluginLTLIBRARIES \ ctags distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-libLTLIBRARIES \ install-man install-pdf install-pdf-am install-pkgcfgDATA \ install-pluginLTLIBRARIES install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/topology/0000755000175000017500000000000011763406750012500 500000000000000gnunet-0.9.3/src/topology/Makefile.am0000644000175000017500000000174111654545775014471 00000000000000INCLUDES = -I$(top_srcdir)/src/include if USE_COVERAGE AM_CFLAGS = --coverage -O0 endif pkgcfgdir= $(pkgdatadir)/config.d/ dist_pkgcfg_DATA = \ topology.conf bin_PROGRAMS = \ gnunet-daemon-topology gnunet_daemon_topology_SOURCES = \ gnunet-daemon-topology.c gnunet_daemon_topology_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) check_PROGRAMS = \ test_gnunet_daemon_topology if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) endif test_gnunet_daemon_topology_SOURCES = \ test_gnunet_daemon_topology.c test_gnunet_daemon_topology_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ test_gnunet_daemon_topology_data.conf gnunet-0.9.3/src/topology/test_gnunet_daemon_topology.c0000644000175000017500000001243511760502551020400 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file topology/test_gnunet_daemon_topology.c * @brief testcase for topology maintenance code */ #include "platform.h" #include "gnunet_testing_lib.h" #define NUM_PEERS 2 /** * How long until we give up on connecting the peers? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600) #define CONNECT_ATTEMPTS 3 static int ok; static int peers_left; static int connect_left; static struct GNUNET_TESTING_PeerGroup *pg; static struct GNUNET_TESTING_Daemon *first; static struct GNUNET_TESTING_Daemon *last; /** * Active connection attempt. */ struct GNUNET_TESTING_ConnectContext *cc[NUM_PEERS]; /** * Check whether peers successfully shut down. */ static void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); if (ok == 0) ok = 666; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); } } static void clean_up_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { unsigned int i; for (i = 0; i < NUM_PEERS; i++) { if (NULL != cc[i]) { GNUNET_TESTING_daemons_connect_cancel (cc[i]); cc[i] = NULL; } } GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); ok = 0; } static void notify_connect_complete (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, unsigned int distance, const struct GNUNET_CONFIGURATION_Handle *first_cfg, const struct GNUNET_CONFIGURATION_Handle *second_cfg, struct GNUNET_TESTING_Daemon *first_daemon, struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) { struct GNUNET_TESTING_ConnectContext **cc = cls; unsigned int i; *cc = NULL; if (NULL != emsg) { FPRINTF (stderr, "Failed to connect two peers: %s\n", emsg); for (i = 0; i < NUM_PEERS; i++) if (NULL != cc[i]) { GNUNET_TESTING_daemons_connect_cancel (cc[i]); cc[i] = NULL; } GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); GNUNET_assert (0); return; } connect_left--; if (connect_left == 0) { /* FIXME: check that topology adds a few more links * in addition to those that were seeded */ GNUNET_SCHEDULER_add_now (&clean_up_task, NULL); } } static void my_cb (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { GNUNET_assert (id != NULL); peers_left--; if (first == NULL) { connect_left = NUM_PEERS; first = d; last = d; return; } cc[peers_left] = GNUNET_TESTING_daemons_connect (last, d, TIMEOUT, CONNECT_ATTEMPTS, GNUNET_YES, ¬ify_connect_complete, &cc[peers_left]); if (peers_left == 0) { /* close circle */ cc[NUM_PEERS - 1] = GNUNET_TESTING_daemons_connect (d, first, TIMEOUT, CONNECT_ATTEMPTS, GNUNET_YES, ¬ify_connect_complete, &cc[NUM_PEERS - 1]); } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { ok = 1; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); peers_left = NUM_PEERS; pg = GNUNET_TESTING_daemons_start (cfg, peers_left, peers_left, peers_left, TIMEOUT, NULL, NULL, &my_cb, NULL, NULL, NULL, NULL); GNUNET_assert (pg != NULL); } static int check () { char *const argv[] = { "test-gnunet-daemon-topology", "-c", "test_gnunet_daemon_topology_data.conf", NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-gnunet-daemon-topology", "nohelp", options, &run, &ok); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-gnunet-daemon-topology", "WARNING", NULL); ret = check (); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-topology"); return ret; } /* end of test_gnunet_daemon_topology.c */ gnunet-0.9.3/src/topology/gnunet-daemon-topology.c0000644000175000017500000011717611762202310017175 00000000000000/* This file is part of GNUnet. (C) 2007, 2008, 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file topology/gnunet-daemon-topology.c * @brief code for maintaining the mesh topology * @author Christian Grothoff */ #include "platform.h" #include "gnunet_constants.h" #include "gnunet_core_service.h" #include "gnunet_protocols.h" #include "gnunet_peerinfo_service.h" #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" #include "gnunet_util_lib.h" /** * Minimum required delay between calls to GNUNET_TRANSPORT_try_connect. */ #define MAX_CONNECT_FREQUENCY_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250) /** * For how long do we blacklist a peer after a failed connection * attempt? This is the baseline factor which is then multiplied by * two to the power of the number of failed attempts. */ #define GREYLIST_AFTER_ATTEMPT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1) /** * For how long do we blacklist a friend after a failed connection * attempt? This is the baseline factor which is then multiplied by * two to the power of the number of failed attempts. */ #define GREYLIST_AFTER_ATTEMPT_FRIEND GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2) /** * For how long do we blacklist anyone under any cirumstances at least after a failed connection * attempt? This is the absolute minimum, regardless of what the calculation based on * exponential backoff returns. */ #define GREYLIST_AFTER_ATTEMPT_MIN GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) /** * For how long do we blacklist anyone under any cirumstances at most after a failed connection * attempt? This is the absolute maximum, regardless of what the calculation based on * exponential back-off returns. */ #define GREYLIST_AFTER_ATTEMPT_MAX GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1) /** * At what frequency do we sent HELLOs to a peer? */ #define HELLO_ADVERTISEMENT_MIN_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) /** * After what time period do we expire the HELLO Bloom filter? */ #define HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4) /** * Record for neighbours, friends and blacklisted peers. */ struct Peer { /** * Which peer is this entry about? */ struct GNUNET_PeerIdentity pid; /** * Our handle for the request to transmit HELLOs to this peer; NULL * if no such request is pending. */ struct GNUNET_CORE_TransmitHandle *hello_req; /** * Pointer to the HELLO message of this peer; can be NULL. */ struct GNUNET_HELLO_Message *hello; /** * Bloom filter used to mark which peers already got the HELLO * from this peer. */ struct GNUNET_CONTAINER_BloomFilter *filter; /** * Until what time should we not try to connect again * to this peer? */ struct GNUNET_TIME_Absolute greylisted_until; /** * Next time we are allowed to transmit a HELLO to this peer? */ struct GNUNET_TIME_Absolute next_hello_allowed; /** * When should we reset the bloom filter of this entry? */ struct GNUNET_TIME_Absolute filter_expiration; /** * ID of task we use to wait for the time to send the next HELLO * to this peer. */ GNUNET_SCHEDULER_TaskIdentifier hello_delay_task; /** * Task for issuing GNUNET_TRANSPORT_try_connect for this peer. */ GNUNET_SCHEDULER_TaskIdentifier attempt_connect_task; /** * ID of task we use to clear peers from the greylist. */ GNUNET_SCHEDULER_TaskIdentifier greylist_clean_task; /** * How often have we tried so far? */ unsigned int connect_attempts; /** * Is this peer listed here because he is a friend? */ int is_friend; /** * Are we connected to this peer right now? */ int is_connected; }; /** * Our peerinfo notification context. We use notification * to instantly learn about new peers as they are discovered. */ static struct GNUNET_PEERINFO_NotifyContext *peerinfo_notify; /** * Our configuration. */ static const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Handle to the core API. */ static struct GNUNET_CORE_Handle *handle; /** * Handle to the transport API. */ static struct GNUNET_TRANSPORT_Handle *transport; /** * Identity of this peer. */ static struct GNUNET_PeerIdentity my_identity; /** * All of our friends, all of our current neighbours and all peers for * which we have HELLOs. So pretty much everyone. Maps peer identities * to 'struct Peer *' values. */ static struct GNUNET_CONTAINER_MultiHashMap *peers; /** * Handle for reporting statistics. */ static struct GNUNET_STATISTICS_Handle *stats; /** * Blacklist (NULL if we have none). */ static struct GNUNET_TRANSPORT_Blacklist *blacklist; /** * When can we next ask transport to create a connection? */ static struct GNUNET_TIME_Absolute next_connect_attempt; /** * Task scheduled to try to add peers. */ static GNUNET_SCHEDULER_TaskIdentifier add_task; /** * Flag to disallow non-friend connections (pure F2F mode). */ static int friends_only; /** * Minimum number of friends to have in the * connection set before we allow non-friends. */ static unsigned int minimum_friend_count; /** * Number of peers (friends and others) that we are currently connected to. */ static unsigned int connection_count; /** * Target number of connections. */ static unsigned int target_connection_count; /** * Number of friends that we are currently connected to. */ static unsigned int friend_count; /** * Should the topology daemon try to establish connections? */ static int autoconnect; /** * Function that decides if a connection is acceptable or not. * If we have a blacklist, only friends are allowed, so the check * is rather simple. * * @param cls closure * @param pid peer to approve or disapproave * @return GNUNET_OK if the connection is allowed */ static int blacklist_check (void *cls, const struct GNUNET_PeerIdentity *pid) { struct Peer *pos; pos = GNUNET_CONTAINER_multihashmap_get (peers, &pid->hashPubKey); if ((pos != NULL) && (pos->is_friend == GNUNET_YES)) return GNUNET_OK; GNUNET_STATISTICS_update (stats, gettext_noop ("# peers blacklisted"), 1, GNUNET_NO); return GNUNET_SYSERR; } /** * Whitelist all peers that we blacklisted; we've passed * the minimum number of friends. */ static void whitelist_peers () { if (blacklist != NULL) { GNUNET_TRANSPORT_blacklist_cancel (blacklist); blacklist = NULL; } } /** * Check if an additional connection from the given peer is allowed. * * @param peer connection to check * @return GNUNET_OK if the connection is allowed */ static int is_connection_allowed (struct Peer *peer) { if (0 == memcmp (&my_identity, &peer->pid, sizeof (struct GNUNET_PeerIdentity))) return GNUNET_SYSERR; /* disallow connections to self */ if (peer->is_friend) return GNUNET_OK; if (GNUNET_YES == friends_only) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Determined that `%s' is not allowed to connect (not a friend)\n", GNUNET_i2s (&peer->pid)); return GNUNET_SYSERR; } if (friend_count >= minimum_friend_count) return GNUNET_OK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Determined that `%s' is not allowed to connect (not enough connected friends)\n", GNUNET_i2s (&peer->pid)); return GNUNET_SYSERR; } /** * Free all resources associated with the given peer. * * @param cls closure (not used) * @param pid identity of the peer * @param value peer to free * @return GNUNET_YES (always: continue to iterate) */ static int free_peer (void *cls, const GNUNET_HashCode * pid, void *value) { struct Peer *pos = value; GNUNET_break (GNUNET_NO == pos->is_connected); GNUNET_break (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (peers, pid, pos)); if (pos->hello_req != NULL) GNUNET_CORE_notify_transmit_ready_cancel (pos->hello_req); if (pos->hello_delay_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (pos->hello_delay_task); if (pos->attempt_connect_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (pos->attempt_connect_task); if (pos->greylist_clean_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (pos->greylist_clean_task); GNUNET_free_non_null (pos->hello); if (pos->filter != NULL) GNUNET_CONTAINER_bloomfilter_free (pos->filter); GNUNET_free (pos); return GNUNET_YES; } /** * Discard peer entries for greylisted peers * where the greylisting has expired. * * @param cls 'struct Peer' to greylist * @param tc scheduler context */ static void remove_from_greylist (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Try to connect to the specified peer. * * @param pos peer to connect to */ static void attempt_connect (struct Peer *pos) { struct GNUNET_TIME_Relative rem; if ((connection_count >= target_connection_count) && (friend_count >= minimum_friend_count)) return; if (GNUNET_YES == pos->is_connected) return; if (GNUNET_OK != is_connection_allowed (pos)) return; if (GNUNET_TIME_absolute_get_remaining (pos->greylisted_until).rel_value > 0) return; if (GNUNET_YES == pos->is_friend) rem = GREYLIST_AFTER_ATTEMPT_FRIEND; else rem = GREYLIST_AFTER_ATTEMPT; rem = GNUNET_TIME_relative_multiply (rem, connection_count); rem = GNUNET_TIME_relative_divide (rem, target_connection_count); if (pos->connect_attempts > 30) pos->connect_attempts = 30; rem = GNUNET_TIME_relative_multiply (rem, 1 << (++pos->connect_attempts)); rem = GNUNET_TIME_relative_max (rem, GREYLIST_AFTER_ATTEMPT_MIN); rem = GNUNET_TIME_relative_min (rem, GREYLIST_AFTER_ATTEMPT_MAX); pos->greylisted_until = GNUNET_TIME_relative_to_absolute (rem); if (pos->greylist_clean_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (pos->greylist_clean_task); pos->greylist_clean_task = GNUNET_SCHEDULER_add_delayed (rem, &remove_from_greylist, pos); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking to connect to `%s'\n", GNUNET_i2s (&pos->pid)); GNUNET_STATISTICS_update (stats, gettext_noop ("# connect requests issued to transport"), 1, GNUNET_NO); GNUNET_TRANSPORT_try_connect (transport, &pos->pid); } /** * Try to connect to the specified peer. * * @param cls peer to connect to * @param tc scheduler context */ static void do_attempt_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Peer *pos = cls; struct GNUNET_TIME_Relative delay; pos->attempt_connect_task = GNUNET_SCHEDULER_NO_TASK; if (GNUNET_YES == pos->is_connected) return; delay = GNUNET_TIME_absolute_get_remaining (next_connect_attempt); if (delay.rel_value > 0) { pos->attempt_connect_task = GNUNET_SCHEDULER_add_delayed (delay, &do_attempt_connect, pos); return; } next_connect_attempt = GNUNET_TIME_relative_to_absolute (MAX_CONNECT_FREQUENCY_DELAY); attempt_connect (pos); } /** * Schedule a task to try to connect to the specified peer. * * @param pos peer to connect to */ static void schedule_attempt_connect (struct Peer *pos) { if (GNUNET_SCHEDULER_NO_TASK != pos->attempt_connect_task) return; pos->attempt_connect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (next_connect_attempt), &do_attempt_connect, pos); } /** * Discard peer entries for greylisted peers * where the greylisting has expired. * * @param cls 'struct Peer' to greylist * @param tc scheduler context */ static void remove_from_greylist (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Peer *pos = cls; struct GNUNET_TIME_Relative rem; pos->greylist_clean_task = GNUNET_SCHEDULER_NO_TASK; rem = GNUNET_TIME_absolute_get_remaining (pos->greylisted_until); if (rem.rel_value == 0) { schedule_attempt_connect (pos); } else { pos->greylist_clean_task = GNUNET_SCHEDULER_add_delayed (rem, &remove_from_greylist, pos); } if ((GNUNET_NO == pos->is_friend) && (GNUNET_NO == pos->is_connected) && (NULL == pos->hello)) { free_peer (NULL, &pos->pid.hashPubKey, pos); return; } } /** * Create a new entry in the peer list. * * @param peer identity of the new entry * @param hello hello message, can be NULL * @param is_friend is the new entry for a friend? * @return the new entry */ static struct Peer * make_peer (const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Message *hello, int is_friend) { struct Peer *ret; ret = GNUNET_malloc (sizeof (struct Peer)); ret->pid = *peer; ret->is_friend = is_friend; if (hello != NULL) { ret->hello = GNUNET_malloc (GNUNET_HELLO_size (hello)); memcpy (ret->hello, hello, GNUNET_HELLO_size (hello)); } GNUNET_break (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (peers, &peer->hashPubKey, ret, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); return ret; } /** * Setup bloom filter for the given peer entry. * * @param peer entry to initialize */ static void setup_filter (struct Peer *peer) { /* 2^{-5} chance of not sending a HELLO to a peer is * acceptably small (if the filter is 50% full); * 64 bytes of memory are small compared to the rest * of the data structure and would only really become * "useless" once a HELLO has been passed on to ~100 * other peers, which is likely more than enough in * any case; hence 64, 5 as bloomfilter parameters. */ peer->filter = GNUNET_CONTAINER_bloomfilter_init (NULL, 64, 5); peer->filter_expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY); /* never send a peer its own HELLO */ GNUNET_CONTAINER_bloomfilter_add (peer->filter, &peer->pid.hashPubKey); } /** * Function to fill send buffer with HELLO. * * @param cls 'struct Peer' of the target peer * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t hello_advertising_ready (void *cls, size_t size, void *buf); /** * Closure for 'find_advertisable_hello'. */ struct FindAdvHelloContext { /** * Peer we want to advertise to. */ struct Peer *peer; /** * Where to store the result (peer selected for advertising). */ struct Peer *result; /** * Maximum HELLO size we can use right now. */ size_t max_size; struct GNUNET_TIME_Relative next_adv; }; /** * Find a peer that would be reasonable for advertising. * * @param cls closure * @param pid identity of a peer * @param value 'struct Peer*' for the peer we are considering * @return GNUNET_YES (continue iteration) */ static int find_advertisable_hello (void *cls, const GNUNET_HashCode * pid, void *value) { struct FindAdvHelloContext *fah = cls; struct Peer *pos = value; struct GNUNET_TIME_Relative rst_time; size_t hs; if (pos == fah->peer) return GNUNET_YES; if (pos->hello == NULL) return GNUNET_YES; rst_time = GNUNET_TIME_absolute_get_remaining (pos->filter_expiration); if (0 == rst_time.rel_value) { /* time to discard... */ GNUNET_CONTAINER_bloomfilter_free (pos->filter); setup_filter (pos); } fah->next_adv = GNUNET_TIME_relative_min (rst_time, fah->next_adv); hs = GNUNET_HELLO_size (pos->hello); if (hs > fah->max_size) return GNUNET_YES; if (GNUNET_NO == GNUNET_CONTAINER_bloomfilter_test (pos->filter, &fah->peer->pid.hashPubKey)) fah->result = pos; return GNUNET_YES; } /** * Calculate when we would like to send the next HELLO to this * peer and ask for it. * * @param cls for which peer to schedule the HELLO * @param tc task context */ static void schedule_next_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Peer *pl = cls; struct FindAdvHelloContext fah; size_t next_want; struct GNUNET_TIME_Relative delay; pl->hello_delay_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_assert (GNUNET_YES == pl->is_connected); if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; /* we're out of here */ if (pl->hello_req != NULL) return; /* did not finish sending the previous one */ /* find applicable HELLOs */ fah.peer = pl; fah.result = NULL; fah.max_size = GNUNET_SERVER_MAX_MESSAGE_SIZE - 1; fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL; GNUNET_CONTAINER_multihashmap_iterate (peers, &find_advertisable_hello, &fah); pl->hello_delay_task = GNUNET_SCHEDULER_add_delayed (fah.next_adv, &schedule_next_hello, pl); if (fah.result == NULL) return; next_want = GNUNET_HELLO_size (fah.result->hello); delay = GNUNET_TIME_absolute_get_remaining (pl->next_hello_allowed); if (delay.rel_value == 0) { /* now! */ pl->hello_req = GNUNET_CORE_notify_transmit_ready (handle, GNUNET_YES, 0, GNUNET_CONSTANTS_SERVICE_TIMEOUT, &pl->pid, next_want, &hello_advertising_ready, pl); } } /** * Cancel existing requests for sending HELLOs to this peer * and recalculate when we should send HELLOs to it based * on our current state (something changed!). * * @param cls closure, 'struct Peer' to skip, or NULL * @param pid identity of a peer * @param value 'struct Peer*' for the peer * @return GNUNET_YES (always) */ static int reschedule_hellos (void *cls, const GNUNET_HashCode * pid, void *value) { struct Peer *peer = value; struct Peer *skip = cls; if (skip == peer) return GNUNET_YES; if (!peer->is_connected) return GNUNET_YES; if (peer->hello_req != NULL) { GNUNET_CORE_notify_transmit_ready_cancel (peer->hello_req); peer->hello_req = NULL; } if (peer->hello_delay_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (peer->hello_delay_task); peer->hello_delay_task = GNUNET_SCHEDULER_NO_TASK; } peer->hello_delay_task = GNUNET_SCHEDULER_add_now (&schedule_next_hello, peer); return GNUNET_YES; } /** * Method called whenever a peer connects. * * @param cls closure * @param peer peer identity this notification is about * @param atsi performance data * @param atsi_count number of records in 'atsi' */ static void connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct Peer *pos; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core told us that we are connecting to `%s'\n", GNUNET_i2s (peer)); if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity))) return; connection_count++; GNUNET_STATISTICS_set (stats, gettext_noop ("# peers connected"), connection_count, GNUNET_NO); pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); if (NULL == pos) { pos = make_peer (peer, NULL, GNUNET_NO); GNUNET_break (GNUNET_OK == is_connection_allowed (pos)); } else { GNUNET_assert (GNUNET_NO == pos->is_connected); pos->greylisted_until.abs_value = 0; /* remove greylisting */ } pos->is_connected = GNUNET_YES; pos->connect_attempts = 0; /* re-set back-off factor */ if (pos->is_friend) { if ((friend_count == minimum_friend_count - 1) && (GNUNET_YES != friends_only)) whitelist_peers (); friend_count++; GNUNET_STATISTICS_set (stats, gettext_noop ("# friends connected"), friend_count, GNUNET_NO); } reschedule_hellos (NULL, &peer->hashPubKey, pos); } /** * Try to add more peers to our connection set. * * @param cls closure, not used * @param pid identity of a peer * @param value 'struct Peer*' for the peer * @return GNUNET_YES (continue to iterate) */ static int try_add_peers (void *cls, const GNUNET_HashCode * pid, void *value) { struct Peer *pos = value; schedule_attempt_connect (pos); return GNUNET_YES; } /** * Last task run during shutdown. Disconnects us from * the transport and core. * * @param cls unused, NULL * @param tc scheduler context */ static void add_peer_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { add_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_CONTAINER_multihashmap_iterate (peers, &try_add_peers, NULL); } /** * Method called whenever a peer disconnects. * * @param cls closure * @param peer peer identity this notification is about */ static void disconnect_notify (void *cls, const struct GNUNET_PeerIdentity *peer) { struct Peer *pos; if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity))) return; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core told us that we disconnected from `%s'\n", GNUNET_i2s (peer)); pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); if (NULL == pos) { GNUNET_break (0); return; } if (pos->is_connected != GNUNET_YES) { GNUNET_break (0); return; } pos->is_connected = GNUNET_NO; connection_count--; if (NULL != pos->hello_req) { GNUNET_CORE_notify_transmit_ready_cancel (pos->hello_req); pos->hello_req = NULL; } if (GNUNET_SCHEDULER_NO_TASK != pos->hello_delay_task) { GNUNET_SCHEDULER_cancel (pos->hello_delay_task); pos->hello_delay_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_STATISTICS_set (stats, gettext_noop ("# peers connected"), connection_count, GNUNET_NO); if (pos->is_friend) { friend_count--; GNUNET_STATISTICS_set (stats, gettext_noop ("# friends connected"), friend_count, GNUNET_NO); } if (((connection_count < target_connection_count) || (friend_count < minimum_friend_count)) && (GNUNET_SCHEDULER_NO_TASK == add_task)) add_task = GNUNET_SCHEDULER_add_now (&add_peer_task, NULL); if ((friend_count < minimum_friend_count) && (blacklist == NULL)) blacklist = GNUNET_TRANSPORT_blacklist (cfg, &blacklist_check, NULL); } /** * Iterator called on each address. * * @param cls flag that we will set if we see any addresses * @param address the address of the peer * @param expiration when will the given address expire * @return GNUNET_SYSERR always, to terminate iteration */ static int address_iterator (void *cls, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration) { int *flag = cls; *flag = GNUNET_YES; return GNUNET_SYSERR; } /** * We've gotten a HELLO from another peer. Consider it for * advertising. * * @param hello the HELLO we got */ static void consider_for_advertising (const struct GNUNET_HELLO_Message *hello) { int have_address; struct GNUNET_PeerIdentity pid; struct GNUNET_TIME_Absolute dt; struct GNUNET_HELLO_Message *nh; struct Peer *peer; uint16_t size; if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid)) { GNUNET_break (0); return; } if (0 == memcmp (&pid, &my_identity, sizeof (struct GNUNET_PeerIdentity))) return; /* that's me! */ have_address = GNUNET_NO; GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &address_iterator, &have_address); if (GNUNET_NO == have_address) return; /* no point in advertising this one... */ peer = GNUNET_CONTAINER_multihashmap_get (peers, &pid.hashPubKey); if (NULL == peer) { peer = make_peer (&pid, hello, GNUNET_NO); } else if (peer->hello != NULL) { dt = GNUNET_HELLO_equals (peer->hello, hello, GNUNET_TIME_absolute_get ()); if (dt.abs_value == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value) return; /* nothing new here */ } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found `%s' from peer `%s' for advertising\n", "HELLO", GNUNET_i2s (&pid)); if (peer->hello != NULL) { nh = GNUNET_HELLO_merge (peer->hello, hello); GNUNET_free (peer->hello); peer->hello = nh; } else { size = GNUNET_HELLO_size (hello); peer->hello = GNUNET_malloc (size); memcpy (peer->hello, hello, size); } if (peer->filter != NULL) GNUNET_CONTAINER_bloomfilter_free (peer->filter); setup_filter (peer); /* since we have a new HELLO to pick from, re-schedule all * HELLO requests that are not bound by the HELLO send rate! */ GNUNET_CONTAINER_multihashmap_iterate (peers, &reschedule_hellos, peer); } /** * PEERINFO calls this function to let us know about a possible peer * that we might want to connect to. * * @param cls closure (not used) * @param peer potential peer to connect to * @param hello HELLO for this peer (or NULL) * @param err_msg NULL if successful, otherwise contains error message */ static void process_peer (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Message *hello, const char *err_msg) { struct Peer *pos; if (err_msg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Error in communication with PEERINFO service: %s\n"), err_msg); GNUNET_PEERINFO_notify_cancel (peerinfo_notify); peerinfo_notify = GNUNET_PEERINFO_notify (cfg, &process_peer, NULL); return; } GNUNET_assert (peer != NULL); if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity))) return; /* that's me! */ if (hello == NULL) { /* free existing HELLO, if any */ pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); if (NULL != pos) { GNUNET_free_non_null (pos->hello); pos->hello = NULL; if (pos->filter != NULL) { GNUNET_CONTAINER_bloomfilter_free (pos->filter); pos->filter = NULL; } if ((GNUNET_NO == pos->is_connected) && (GNUNET_NO == pos->is_friend) && (0 == GNUNET_TIME_absolute_get_remaining (pos-> greylisted_until).rel_value)) free_peer (NULL, &pos->pid.hashPubKey, pos); } return; } consider_for_advertising (hello); pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); if (pos == NULL) pos = make_peer (peer, hello, GNUNET_NO); GNUNET_assert (NULL != pos); if (GNUNET_YES == pos->is_connected) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Already connected to peer `%s'\n", GNUNET_i2s (peer)); return; } if (GNUNET_TIME_absolute_get_remaining (pos->greylisted_until).rel_value > 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Already tried peer `%s' recently\n", GNUNET_i2s (peer)); return; /* peer still greylisted */ } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Considering connecting to peer `%s'\n", GNUNET_i2s (peer)); schedule_attempt_connect (pos); } /** * Function called after GNUNET_CORE_connect has succeeded * (or failed for good). * * @param cls closure * @param server handle to the server, NULL if we failed * @param my_id ID of this peer, NULL if we failed */ static void core_init (void *cls, struct GNUNET_CORE_Handle *server, const struct GNUNET_PeerIdentity *my_id) { if (server == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Failed to connect to core service, can not manage topology!\n")); GNUNET_SCHEDULER_shutdown (); return; } handle = server; my_identity = *my_id; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "I am peer `%s'\n", GNUNET_i2s (my_id)); peerinfo_notify = GNUNET_PEERINFO_notify (cfg, &process_peer, NULL); } /** * Read the friends file. */ static void read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg) { char *fn; char *data; size_t pos; struct GNUNET_PeerIdentity pid; uint64_t fsize; struct GNUNET_CRYPTO_HashAsciiEncoded enc; unsigned int entries_found; struct Peer *fl; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "TOPOLOGY", "FRIENDS", &fn)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Option `%s' in section `%s' not specified!\n"), "FRIENDS", "TOPOLOGY"); return; } if (GNUNET_OK != GNUNET_DISK_file_test (fn)) GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (GNUNET_OK != GNUNET_DISK_file_size (fn, &fsize, GNUNET_NO, GNUNET_YES)) { if ((friends_only) || (minimum_friend_count > 0)) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not read friends list `%s'\n"), fn); GNUNET_free (fn); return; } if (fsize == 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Friends file `%s' is empty.\n"), fn); GNUNET_free (fn); return; } data = GNUNET_malloc_large (fsize); if (data == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to read friends list from `%s': out of memory\n"), fn); GNUNET_free (fn); return; } if (fsize != GNUNET_DISK_fn_read (fn, data, fsize)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to read friends list from `%s'\n"), fn); GNUNET_free (fn); GNUNET_free (data); return; } entries_found = 0; pos = 0; while ((pos < fsize) && isspace ((unsigned char) data[pos])) pos++; while ((fsize >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) && (pos <= fsize - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded))) { memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); if (!isspace ((unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1])) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Syntax error in topology specification at offset %llu, skipping bytes.\n"), (unsigned long long) pos); pos++; while ((pos < fsize) && (!isspace ((unsigned char) data[pos]))) pos++; continue; } enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n"), (unsigned long long) pos, &enc); } else { if (0 != memcmp (&pid, &my_identity, sizeof (struct GNUNET_PeerIdentity))) { entries_found++; fl = make_peer (&pid, NULL, GNUNET_YES); GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Found friend `%s' in configuration\n"), GNUNET_i2s (&fl->pid)); } else { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Found myself `%s' in friend list (useless, ignored)\n"), GNUNET_i2s (&pid)); } } pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded); while ((pos < fsize) && isspace ((unsigned char) data[pos])) pos++; } GNUNET_free (data); GNUNET_free (fn); GNUNET_STATISTICS_update (stats, gettext_noop ("# friends in configuration"), entries_found, GNUNET_NO); if ((minimum_friend_count > entries_found) && (friends_only == GNUNET_NO)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Fewer friends specified than required by minimum friend count. Will only connect to friends.\n")); } if ((minimum_friend_count > target_connection_count) && (friends_only == GNUNET_NO)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("More friendly connections required than target total number of connections.\n")); } } /** * This function is called whenever an encrypted HELLO message is * received. * * @param cls closure * @param other the other peer involved (sender or receiver, NULL * for loopback messages where we are both sender and receiver) * @param message the actual HELLO message * @param atsi performance data * @param atsi_count number of records in 'atsi' * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_encrypted_hello (void *cls, const struct GNUNET_PeerIdentity *other, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct Peer *peer; struct GNUNET_PeerIdentity pid; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received encrypted `%s' from peer `%s'", "HELLO", GNUNET_i2s (other)); if (GNUNET_OK != GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) message, &pid)) { GNUNET_break_op (0); return GNUNET_SYSERR; } GNUNET_STATISTICS_update (stats, gettext_noop ("# HELLO messages received"), 1, GNUNET_NO); peer = GNUNET_CONTAINER_multihashmap_get (peers, &pid.hashPubKey); if (NULL == peer) { if ((GNUNET_YES == friends_only) || (friend_count < minimum_friend_count)) return GNUNET_OK; } else { if ((GNUNET_YES != peer->is_friend) && (GNUNET_YES == friends_only)) return GNUNET_OK; if ((GNUNET_YES != peer->is_friend) && (friend_count < minimum_friend_count)) return GNUNET_OK; } if (transport != NULL) GNUNET_TRANSPORT_offer_hello (transport, message, NULL, NULL); return GNUNET_OK; } /** * Function to fill send buffer with HELLO. * * @param cls 'struct Peer' of the target peer * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t hello_advertising_ready (void *cls, size_t size, void *buf) { struct Peer *pl = cls; struct FindAdvHelloContext fah; size_t want; pl->hello_req = NULL; GNUNET_assert (GNUNET_YES == pl->is_connected); /* find applicable HELLOs */ fah.peer = pl; fah.result = NULL; fah.max_size = size; fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL; GNUNET_CONTAINER_multihashmap_iterate (peers, &find_advertisable_hello, &fah); want = 0; if (fah.result != NULL) { want = GNUNET_HELLO_size (fah.result->hello); GNUNET_assert (want <= size); memcpy (buf, fah.result->hello, want); GNUNET_CONTAINER_bloomfilter_add (fah.result->filter, &pl->pid.hashPubKey); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' with %u bytes", "HELLO", (unsigned int) want); GNUNET_STATISTICS_update (stats, gettext_noop ("# HELLO messages gossipped"), 1, GNUNET_NO); } if (pl->hello_delay_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (pl->hello_delay_task); pl->next_hello_allowed = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY); pl->hello_delay_task = GNUNET_SCHEDULER_add_now (&schedule_next_hello, pl); return want; } /** * Last task run during shutdown. Disconnects us from * the transport and core. * * @param cls unused, NULL * @param tc scheduler context */ static void cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (NULL != peerinfo_notify) { GNUNET_PEERINFO_notify_cancel (peerinfo_notify); peerinfo_notify = NULL; } GNUNET_TRANSPORT_disconnect (transport); transport = NULL; if (handle != NULL) { GNUNET_CORE_disconnect (handle); handle = NULL; } whitelist_peers (); if (GNUNET_SCHEDULER_NO_TASK != add_task) { GNUNET_SCHEDULER_cancel (add_task); add_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_CONTAINER_multihashmap_iterate (peers, &free_peer, NULL); GNUNET_CONTAINER_multihashmap_destroy (peers); peers = NULL; if (stats != NULL) { GNUNET_STATISTICS_destroy (stats, GNUNET_NO); stats = NULL; } } /** * Main function that will be run. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param c configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { static struct GNUNET_CORE_MessageHandler handlers[] = { {&handle_encrypted_hello, GNUNET_MESSAGE_TYPE_HELLO, 0}, {NULL, 0, 0} }; unsigned long long opt; cfg = c; stats = GNUNET_STATISTICS_create ("topology", cfg); autoconnect = GNUNET_CONFIGURATION_get_value_yesno (cfg, "TOPOLOGY", "AUTOCONNECT"); friends_only = GNUNET_CONFIGURATION_get_value_yesno (cfg, "TOPOLOGY", "FRIENDS-ONLY"); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "TOPOLOGY", "MINIMUM-FRIENDS", &opt)) opt = 0; minimum_friend_count = (unsigned int) opt; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "TOPOLOGY", "TARGET-CONNECTION-COUNT", &opt)) opt = 16; target_connection_count = (unsigned int) opt; peers = GNUNET_CONTAINER_multihashmap_create (target_connection_count * 2); if ((friends_only == GNUNET_YES) || (minimum_friend_count > 0)) read_friends_file (cfg); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Topology would like %u connections with at least %u friends (%s)\n", target_connection_count, minimum_friend_count, autoconnect ? "autoconnect enabled" : "autoconnect disabled"); if ((friend_count < minimum_friend_count) && (blacklist == NULL)) blacklist = GNUNET_TRANSPORT_blacklist (cfg, &blacklist_check, NULL); transport = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, NULL, NULL, NULL); handle = GNUNET_CORE_connect (cfg, 1, NULL, &core_init, &connect_notify, &disconnect_notify, NULL, GNUNET_NO, NULL, GNUNET_NO, handlers); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleaning_task, NULL); if (NULL == transport) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to connect to `%s' service.\n"), "transport"); GNUNET_SCHEDULER_shutdown (); return; } if (NULL == handle) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to connect to `%s' service.\n"), "core"); GNUNET_SCHEDULER_shutdown (); return; } } /** * The main function for the topology daemon. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; int ret; ret = (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-daemon-topology", _ ("GNUnet topology control (maintaining P2P mesh and F2F constraints)"), options, &run, NULL)) ? 0 : 1; return ret; } /* end of gnunet-daemon-topology.c */ gnunet-0.9.3/src/topology/test_gnunet_daemon_topology_data.conf0000644000175000017500000000151211725220741022065 00000000000000[PATHS] SERVICEHOME = /tmp/test-gnunet-topology/ [resolver] PORT = 2664 [transport] PORT = 2665 PLUGINS = tcp #DEBUG = YES #PREFIX = xterm -e xterm -T transport -e gdb -x cmd --args #PREFIX = valgrind --tool=memcheck --log-file=logs%p [arm] PORT = 2666 DEFAULTSERVICES = topology [statistics] PORT = 2667 [transport-tcp] PORT = 2668 BINDTO = 127.0.0.1 [nat] DISABLEV6 = YES ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 USE_LOCALADDR = NO USE_HOSTNAME = NO [peerinfo] PORT = 2669 [core] PORT = 2670 #DEBUG = YES [topology] # DEBUG = YES #PREFIX = valgrind --tool=memcheck [fs] AUTOSTART = NO [datastore] AUTOSTART = NO [testing] WEAKRANDOM = YES HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat [dns] AUTOSTART = NO [namestore] AUTOSTART = NO [nse] AUTOSTART = NO gnunet-0.9.3/src/topology/topology.conf0000644000175000017500000000027111654545775015155 00000000000000[topology] MINIMUM-FRIENDS = 0 FRIENDS-ONLY = NO AUTOCONNECT = YES TARGET-CONNECTION-COUNT = 16 FRIENDS = $SERVICEHOME/friends CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-topology gnunet-0.9.3/src/topology/Makefile.in0000644000175000017500000006475711762217213014501 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-daemon-topology$(EXEEXT) check_PROGRAMS = test_gnunet_daemon_topology$(EXEEXT) subdir = src/topology DIST_COMMON = $(dist_pkgcfg_DATA) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" PROGRAMS = $(bin_PROGRAMS) am_gnunet_daemon_topology_OBJECTS = gnunet-daemon-topology.$(OBJEXT) gnunet_daemon_topology_OBJECTS = $(am_gnunet_daemon_topology_OBJECTS) am__DEPENDENCIES_1 = gnunet_daemon_topology_DEPENDENCIES = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent am_test_gnunet_daemon_topology_OBJECTS = \ test_gnunet_daemon_topology.$(OBJEXT) test_gnunet_daemon_topology_OBJECTS = \ $(am_test_gnunet_daemon_topology_OBJECTS) test_gnunet_daemon_topology_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(gnunet_daemon_topology_SOURCES) \ $(test_gnunet_daemon_topology_SOURCES) DIST_SOURCES = $(gnunet_daemon_topology_SOURCES) \ $(test_gnunet_daemon_topology_SOURCES) am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' DATA = $(dist_pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 pkgcfgdir = $(pkgdatadir)/config.d/ dist_pkgcfg_DATA = \ topology.conf gnunet_daemon_topology_SOURCES = \ gnunet-daemon-topology.c gnunet_daemon_topology_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) @ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) test_gnunet_daemon_topology_SOURCES = \ test_gnunet_daemon_topology.c test_gnunet_daemon_topology_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ test_gnunet_daemon_topology_data.conf all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/topology/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/topology/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-daemon-topology$(EXEEXT): $(gnunet_daemon_topology_OBJECTS) $(gnunet_daemon_topology_DEPENDENCIES) @rm -f gnunet-daemon-topology$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_daemon_topology_OBJECTS) $(gnunet_daemon_topology_LDADD) $(LIBS) test_gnunet_daemon_topology$(EXEEXT): $(test_gnunet_daemon_topology_OBJECTS) $(test_gnunet_daemon_topology_DEPENDENCIES) @rm -f test_gnunet_daemon_topology$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gnunet_daemon_topology_OBJECTS) $(test_gnunet_daemon_topology_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-daemon-topology.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gnunet_daemon_topology.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_pkgcfgDATA: $(dist_pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-dist_pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(PROGRAMS) $(DATA) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_pkgcfgDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-dist_pkgcfgDATA .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libtool ctags distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-binPROGRAMS install-data install-data-am \ install-dist_pkgcfgDATA install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-dist_pkgcfgDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/chat/0000755000175000017500000000000011763406751011544 500000000000000gnunet-0.9.3/src/chat/chat.c0000644000175000017500000006355111760502551012551 00000000000000/* This file is part of GNUnet. (C) 2008, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file chat/chat.c * @brief convenience API for sending and receiving chat messages * @author Christian Grothoff * @author Nathan Evans * @author Vitaly Minko */ #include "platform.h" #include "gnunet_constants.h" #include "gnunet_protocols.h" #include "gnunet_signatures.h" #include "chat.h" #define DEBUG_CHAT GNUNET_EXTRA_LOGGING #define NICK_IDENTITY_PREFIX ".chat_identity_" /** * Handle for a chat room. */ struct GNUNET_CHAT_Room { struct GNUNET_CLIENT_Connection *client; const struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_CONTAINER_MetaData *member_info; char *room_name; struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; struct MemberList *members; int is_joined; GNUNET_CHAT_JoinCallback join_callback; void *join_callback_cls; GNUNET_CHAT_MessageCallback message_callback; void *message_callback_cls; GNUNET_CHAT_MemberListCallback member_list_callback; void *member_list_callback_cls; GNUNET_CHAT_MessageConfirmation confirmation_callback; void *confirmation_cls; uint32_t sequence_number; uint32_t msg_options; }; /** * Linked list of members in the chat room. */ struct MemberList { struct MemberList *next; /** * Description of the member. */ struct GNUNET_CONTAINER_MetaData *meta; /** * Member ID (pseudonym). */ GNUNET_HashCode id; }; /** * Context for transmitting a send-message request. */ struct GNUNET_CHAT_SendMessageContext { /** * Handle for the chat room. */ struct GNUNET_CHAT_Room *chat_room; /** * Message that we're sending. */ char *message; /** * Options for the message. */ enum GNUNET_CHAT_MsgOptions options; /** * Receiver of the message. NULL to send to everyone in the room. */ const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *receiver; /** * Sequence id of the message. */ uint32_t sequence_number; }; /** * Context for transmitting a confirmation receipt. */ struct GNUNET_CHAT_SendReceiptContext { /** * Handle for the chat room. */ struct GNUNET_CHAT_Room *chat_room; /** * The original message that we're going to acknowledge. */ struct ReceiveNotificationMessage *received_msg; }; /** * Ask client to send a join request. */ static int rejoin_room (struct GNUNET_CHAT_Room *chat_room); /** * Transmit a confirmation receipt to the chat service. * * @param cls closure, pointer to the 'struct GNUNET_CHAT_SendReceiptContext' * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_acknowledge_request (void *cls, size_t size, void *buf) { struct GNUNET_CHAT_SendReceiptContext *src = cls; struct ConfirmationReceiptMessage *receipt; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub_key; uint16_t msg_len; size_t msg_size; if (NULL == buf) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not transmit confirmation receipt\n")); return 0; } #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting confirmation receipt to the service\n"); #endif msg_size = sizeof (struct ConfirmationReceiptMessage); GNUNET_assert (size >= msg_size); receipt = buf; receipt->header.size = htons (msg_size); receipt->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT); receipt->reserved = htonl (0); receipt->sequence_number = src->received_msg->sequence_number; receipt->reserved2 = htonl (0); receipt->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); GNUNET_CRYPTO_rsa_key_get_public (src->chat_room->my_private_key, &pub_key); GNUNET_CRYPTO_hash (&pub_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &receipt->target); receipt->author = src->received_msg->sender; receipt->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT); receipt->purpose.size = htonl (msg_size - sizeof (struct GNUNET_MessageHeader) - sizeof (uint32_t) - sizeof (struct GNUNET_CRYPTO_RsaSignature)); msg_len = ntohs (src->received_msg->header.size) - sizeof (struct ReceiveNotificationMessage); GNUNET_CRYPTO_hash (&src->received_msg[1], msg_len, &receipt->content); GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_rsa_sign (src->chat_room->my_private_key, &receipt->purpose, &receipt->signature)); GNUNET_free (src->received_msg); GNUNET_free (src); return msg_size; } /** * Handles messages received from the service. Calls the proper client * callback. */ static void process_result (struct GNUNET_CHAT_Room *room, const struct GNUNET_MessageHeader *reply) { struct LeaveNotificationMessage *leave_msg; struct JoinNotificationMessage *join_msg; struct ReceiveNotificationMessage *received_msg; struct ConfirmationReceiptMessage *receipt; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; GNUNET_HashCode id; const GNUNET_HashCode *sender; struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_CHAT_SendReceiptContext *src; struct MemberList *pos; struct MemberList *prev; struct GNUNET_CRYPTO_AesSessionKey key; char decrypted_msg[MAX_MESSAGE_LENGTH]; uint16_t size; uint16_t meta_len; uint16_t msg_len; char *message_content; size = ntohs (reply->size); switch (ntohs (reply->type)) { case GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION: #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a join notification\n"); #endif if (size < sizeof (struct JoinNotificationMessage)) { GNUNET_break (0); return; } join_msg = (struct JoinNotificationMessage *) reply; meta_len = size - sizeof (struct JoinNotificationMessage); meta = GNUNET_CONTAINER_meta_data_deserialize ((const char *) &join_msg[1], meta_len); if (NULL == meta) { GNUNET_break (0); return; } pos = GNUNET_malloc (sizeof (struct MemberList)); pos->meta = meta; GNUNET_CRYPTO_hash (&join_msg->public_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &pos->id); GNUNET_PSEUDONYM_add (room->cfg, &pos->id, meta); pos->next = room->members; room->members = pos; if (GNUNET_NO == room->is_joined) { GNUNET_CRYPTO_rsa_key_get_public (room->my_private_key, &pkey); if (0 == memcmp (&join_msg->public_key, &pkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded))) { room->join_callback (room->join_callback_cls); room->is_joined = GNUNET_YES; } else { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("The current user must be the the first one joined\n")); GNUNET_break (0); return; } } else room->member_list_callback (room->member_list_callback_cls, meta, &join_msg->public_key, ntohl (join_msg->msg_options)); break; case GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION: #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a leave notification\n"); #endif if (size < sizeof (struct LeaveNotificationMessage)) { GNUNET_break (0); return; } leave_msg = (struct LeaveNotificationMessage *) reply; room->member_list_callback (room->member_list_callback_cls, NULL, &leave_msg->user, GNUNET_CHAT_MSG_OPTION_NONE); GNUNET_CRYPTO_hash (&leave_msg->user, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &id); prev = NULL; pos = room->members; while ((NULL != pos) && (0 != memcmp (&pos->id, &id, sizeof (GNUNET_HashCode)))) { prev = pos; pos = pos->next; } GNUNET_assert (NULL != pos); if (NULL == prev) room->members = pos->next; else prev->next = pos->next; GNUNET_CONTAINER_meta_data_destroy (pos->meta); GNUNET_free (pos); break; case GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION: #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a message notification\n"); #endif if (size <= sizeof (struct ReceiveNotificationMessage)) { GNUNET_break (0); return; } received_msg = (struct ReceiveNotificationMessage *) reply; if (0 != (ntohl (received_msg->msg_options) & GNUNET_CHAT_MSG_ACKNOWLEDGED)) { src = GNUNET_malloc (sizeof (struct GNUNET_CHAT_SendReceiptContext)); src->chat_room = room; src->received_msg = GNUNET_memdup (received_msg, size); GNUNET_CLIENT_notify_transmit_ready (room->client, sizeof (struct ConfirmationReceiptMessage), GNUNET_CONSTANTS_SERVICE_TIMEOUT, GNUNET_YES, &transmit_acknowledge_request, src); } msg_len = size - sizeof (struct ReceiveNotificationMessage); if (0 != (ntohl (received_msg->msg_options) & GNUNET_CHAT_MSG_PRIVATE)) { if (-1 == GNUNET_CRYPTO_rsa_decrypt (room->my_private_key, &received_msg->encrypted_key, &key, sizeof (struct GNUNET_CRYPTO_AesSessionKey))) { GNUNET_break (0); return; } msg_len = GNUNET_CRYPTO_aes_decrypt (&received_msg[1], msg_len, &key, (const struct GNUNET_CRYPTO_AesInitializationVector *) INITVALUE, decrypted_msg); message_content = decrypted_msg; } else { message_content = GNUNET_malloc (msg_len + 1); memcpy (message_content, &received_msg[1], msg_len); } message_content[msg_len] = '\0'; if (0 != (ntohl (received_msg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS)) { sender = NULL; meta = NULL; } else { pos = room->members; while ((NULL != pos) && (0 != memcmp (&pos->id, &received_msg->sender, sizeof (GNUNET_HashCode)))) pos = pos->next; GNUNET_assert (NULL != pos); sender = &received_msg->sender; meta = pos->meta; } room->message_callback (room->message_callback_cls, room, sender, meta, message_content, GNUNET_TIME_absolute_ntoh (received_msg->timestamp), ntohl (received_msg->msg_options)); if (message_content != decrypted_msg) GNUNET_free (message_content); break; case GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION: #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a confirmation receipt\n"); #endif if (size < sizeof (struct ConfirmationReceiptMessage)) { GNUNET_break (0); return; } receipt = (struct ConfirmationReceiptMessage *) reply; if (NULL != room->confirmation_callback) room->confirmation_callback (room->confirmation_cls, room, ntohl (receipt->sequence_number), GNUNET_TIME_absolute_ntoh (receipt->timestamp), &receipt->target); break; default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unknown message type: '%u'\n"), ntohs (reply->type)); GNUNET_break_op (0); break; } } /** * Listen for incoming messages on this chat room. Also, support servers going * away/coming back (i.e. rejoin chat room to keep server state up to date). * * @param cls closure, pointer to the 'struct GNUNET_CHAT_Room' * @param msg message received, NULL on timeout or fatal error */ static void receive_results (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_CHAT_Room *chat_room = cls; #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a message from the service\n"); #endif if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & GNUNET_SCHEDULER_get_reason ())) return; if (NULL == msg) { GNUNET_break (0); rejoin_room (chat_room); return; } process_result (chat_room, msg); if (NULL == chat_room->client) return; /* fatal error */ /* continue receiving */ GNUNET_CLIENT_receive (chat_room->client, &receive_results, chat_room, GNUNET_TIME_UNIT_FOREVER_REL); } /** * Read existing private key from file or create a new one if it does not exist * yet. * Returns the private key on success, NULL on error. */ static struct GNUNET_CRYPTO_RsaPrivateKey * init_private_key (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *nick_name) { char *home; char *keyfile; struct GNUNET_CRYPTO_RsaPrivateKey *privKey; #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Initializing private key\n"); #endif if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "chat", "HOME", &home)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Configuration option `%s' in section `%s' missing\n"), "HOME", "chat"); return NULL; } GNUNET_DISK_directory_create (home); if (GNUNET_OK != GNUNET_DISK_directory_test (home)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to access chat home directory `%s'\n"), home); GNUNET_free (home); return NULL; } /* read or create private key */ keyfile = GNUNET_malloc (strlen (home) + strlen (NICK_IDENTITY_PREFIX) + strlen (nick_name) + 2); strcpy (keyfile, home); GNUNET_free (home); if (keyfile[strlen (keyfile) - 1] != DIR_SEPARATOR) strcat (keyfile, DIR_SEPARATOR_STR); strcat (keyfile, NICK_IDENTITY_PREFIX); strcat (keyfile, nick_name); privKey = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); if (NULL == privKey) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to create/open key in file `%s'\n"), keyfile); } GNUNET_free (keyfile); return privKey; } /** * Transmit a join request to the chat service. * * @param cls closure, pointer to the 'struct GNUNET_CHAT_Room' * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_join_request (void *cls, size_t size, void *buf) { struct GNUNET_CHAT_Room *chat_room = cls; struct JoinRequestMessage *join_msg; char *room; char *meta; size_t room_len; ssize_t meta_len; size_t size_of_join; if (NULL == buf) { #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not transmit join request, retrying...\n"); #endif rejoin_room (chat_room); return 0; } #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting join request to the service\n"); #endif room_len = strlen (chat_room->room_name); meta_len = GNUNET_CONTAINER_meta_data_get_serialized_size (chat_room->member_info); size_of_join = sizeof (struct JoinRequestMessage) + meta_len + room_len; GNUNET_assert (size >= size_of_join); join_msg = buf; join_msg->header.size = htons (size); join_msg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST); join_msg->msg_options = htonl (chat_room->msg_options); join_msg->room_name_len = htons (room_len); join_msg->reserved = htons (0); join_msg->reserved2 = htonl (0); GNUNET_CRYPTO_rsa_key_get_public (chat_room->my_private_key, &join_msg->public_key); room = (char *) &join_msg[1]; memcpy (room, chat_room->room_name, room_len); meta = &room[room_len]; if (GNUNET_SYSERR == GNUNET_CONTAINER_meta_data_serialize (chat_room->member_info, &meta, meta_len, GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not serialize metadata\n")); return 0; } GNUNET_CLIENT_receive (chat_room->client, &receive_results, chat_room, GNUNET_TIME_UNIT_FOREVER_REL); return size_of_join; } /** * Ask to send a join request. */ static int rejoin_room (struct GNUNET_CHAT_Room *chat_room) { size_t size_of_join; size_of_join = sizeof (struct JoinRequestMessage) + GNUNET_CONTAINER_meta_data_get_serialized_size (chat_room->member_info) + strlen (chat_room->room_name); if (NULL == GNUNET_CLIENT_notify_transmit_ready (chat_room->client, size_of_join, GNUNET_CONSTANTS_SERVICE_TIMEOUT, GNUNET_YES, &transmit_join_request, chat_room)) return GNUNET_SYSERR; return GNUNET_OK; } /** * Leave a chat room. */ void GNUNET_CHAT_leave_room (struct GNUNET_CHAT_Room *chat_room) { struct MemberList *pos; #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Leaving the room '%s'\n", chat_room->room_name); #endif GNUNET_CLIENT_disconnect (chat_room->client); GNUNET_free (chat_room->room_name); GNUNET_CONTAINER_meta_data_destroy (chat_room->member_info); GNUNET_CRYPTO_rsa_key_free (chat_room->my_private_key); while (NULL != chat_room->members) { pos = chat_room->members; chat_room->members = pos->next; GNUNET_CONTAINER_meta_data_destroy (pos->meta); GNUNET_free (pos); } GNUNET_free (chat_room); } /** * Join a chat room. * * @param cfg configuration * @param nick_name nickname of the user joining (used to * determine which public key to use); * the nickname should probably also * be used in the member_info (as "EXTRACTOR_TITLE") * @param member_info information about the joining member * @param room_name name of the room * @param msg_options message options of the joining user * @param joinCallback function to call on successful join * @param join_cls closure for joinCallback * @param messageCallback which function to call if a message has * been received? * @param message_cls argument to callback * @param memberCallback which function to call for join/leave notifications * @param member_cls argument to callback * @param confirmationCallback which function to call for confirmations (maybe NULL) * @param confirmation_cls argument to callback * @param me member ID (pseudonym) * @return NULL on error */ struct GNUNET_CHAT_Room * GNUNET_CHAT_join_room (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *nick_name, struct GNUNET_CONTAINER_MetaData *member_info, const char *room_name, enum GNUNET_CHAT_MsgOptions msg_options, GNUNET_CHAT_JoinCallback joinCallback, void *join_cls, GNUNET_CHAT_MessageCallback messageCallback, void *message_cls, GNUNET_CHAT_MemberListCallback memberCallback, void *member_cls, GNUNET_CHAT_MessageConfirmation confirmationCallback, void *confirmation_cls, GNUNET_HashCode * me) { struct GNUNET_CHAT_Room *chat_room; struct GNUNET_CRYPTO_RsaPrivateKey *priv_key; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub_key; struct GNUNET_CLIENT_Connection *client; #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Joining the room '%s'\n", room_name); #endif priv_key = init_private_key (cfg, nick_name); if (NULL == priv_key) return NULL; GNUNET_CRYPTO_rsa_key_get_public (priv_key, &pub_key); GNUNET_CRYPTO_hash (&pub_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), me); GNUNET_PSEUDONYM_add (cfg, me, member_info); client = GNUNET_CLIENT_connect ("chat", cfg); if (NULL == client) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to connect to the chat service\n")); return NULL; } if (NULL == joinCallback) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Undefined mandatory parameter: joinCallback\n")); return NULL; } if (NULL == messageCallback) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Undefined mandatory parameter: messageCallback\n")); return NULL; } if (NULL == memberCallback) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Undefined mandatory parameter: memberCallback\n")); return NULL; } chat_room = GNUNET_malloc (sizeof (struct GNUNET_CHAT_Room)); chat_room->msg_options = msg_options; chat_room->room_name = GNUNET_strdup (room_name); chat_room->member_info = GNUNET_CONTAINER_meta_data_duplicate (member_info); chat_room->my_private_key = priv_key; chat_room->is_joined = GNUNET_NO; chat_room->join_callback = joinCallback; chat_room->join_callback_cls = join_cls; chat_room->message_callback = messageCallback; chat_room->message_callback_cls = message_cls; chat_room->member_list_callback = memberCallback; chat_room->member_list_callback_cls = member_cls; chat_room->confirmation_callback = confirmationCallback; chat_room->confirmation_cls = confirmation_cls; chat_room->cfg = cfg; chat_room->client = client; chat_room->members = NULL; if (GNUNET_SYSERR == rejoin_room (chat_room)) { GNUNET_CHAT_leave_room (chat_room); return NULL; } return chat_room; } /** * Transmit a send-message request to the chat service. * * @param cls closure, pointer to the 'struct GNUNET_CHAT_SendMessageContext' * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_send_request (void *cls, size_t size, void *buf) { struct GNUNET_CHAT_SendMessageContext *smc = cls; struct TransmitRequestMessage *msg_to_send; size_t msg_size; if (NULL == buf) { #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not transmit a chat message\n"); #endif return 0; } #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting a chat message to the service\n"); #endif msg_size = strlen (smc->message) + sizeof (struct TransmitRequestMessage); GNUNET_assert (size >= msg_size); msg_to_send = buf; msg_to_send->header.size = htons (msg_size); msg_to_send->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST); msg_to_send->msg_options = htonl (smc->options); msg_to_send->sequence_number = htonl (smc->sequence_number); msg_to_send->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); msg_to_send->reserved = htonl (0); if (NULL == smc->receiver) memset (&msg_to_send->target, 0, sizeof (GNUNET_HashCode)); else GNUNET_CRYPTO_hash (smc->receiver, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &msg_to_send->target); memcpy (&msg_to_send[1], smc->message, strlen (smc->message)); /** * Client don't encode private messages since public keys of other members are * stored on the service side. */ if (smc->options & GNUNET_CHAT_MSG_AUTHENTICATED) { msg_to_send->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE); msg_to_send->purpose.size = htonl (msg_size - sizeof (struct GNUNET_MessageHeader) - sizeof (struct GNUNET_CRYPTO_RsaSignature)); GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_rsa_sign (smc->chat_room->my_private_key, &msg_to_send->purpose, &msg_to_send->signature)); } GNUNET_free (smc->message); GNUNET_free (smc); return msg_size; } /** * Send a message. * * @param room handle for the chat room * @param message message to be sent * @param options options for the message * @param receiver use NULL to send to everyone in the room * @param sequence_number where to write the sequence id of the message */ void GNUNET_CHAT_send_message (struct GNUNET_CHAT_Room *room, const char *message, enum GNUNET_CHAT_MsgOptions options, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *receiver, uint32_t * sequence_number) { size_t msg_size; struct GNUNET_CHAT_SendMessageContext *smc; #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending a message\n"); #endif room->sequence_number++; if (NULL != sequence_number) *sequence_number = room->sequence_number; smc = GNUNET_malloc (sizeof (struct GNUNET_CHAT_SendMessageContext)); smc->chat_room = room; smc->message = GNUNET_strdup (message); smc->options = options; smc->receiver = receiver; smc->sequence_number = room->sequence_number; msg_size = strlen (message) + sizeof (struct TransmitRequestMessage); GNUNET_CLIENT_notify_transmit_ready (room->client, msg_size, GNUNET_CONSTANTS_SERVICE_TIMEOUT, GNUNET_YES, &transmit_send_request, smc); } /* end of chat.c */ gnunet-0.9.3/src/chat/chat.conf.in0000644000175000017500000000063011760502552013647 00000000000000[chat] AUTOSTART = YES @UNIXONLY@ PORT = 2090 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-chat ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-chat.sock UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES # DISABLE_SOCKET_FORWARDING = NO # USERNAME = # MAXBUF = # TIMEOUT = # DISABLEV6 = # BINDTO = # REJECT_FROM = # REJECT_FROM6 = # PREFIX = gnunet-0.9.3/src/chat/test_chat_data.conf0000644000175000017500000000127711611077627015307 00000000000000[PATHS] SERVICEHOME = /tmp/gnunet-test-chat/ DEFAULTCONFIG = test_chat_data.conf [gnunetd] HOSTKEY = $SERVICEHOME/.hostkey [resolver] PORT = 42464 HOSTNAME = localhost [transport] PORT = 42465 PLUGINS = [arm] PORT = 42466 HOSTNAME = localhost DEFAULTSERVICES = core chat [peerinfo] PORT = 42469 HOSTNAME = localhost [core] PORT = 42470 HOSTNAME = localhost [chat] PORT = 42471 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-chat [testing] WEAKRANDOM = YES [nat] DISABLEV6 = YES BINDTO = 127.0.0.1 ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 [dns] AUTOSTART = NO [nse] AUTOSTART = NO gnunet-0.9.3/src/chat/Makefile.am0000644000175000017500000000605211704315747013522 00000000000000INCLUDES = -I$(top_srcdir)/src/include pkgcfgdir= $(pkgdatadir)/config.d/ pkgcfg_DATA = \ chat.conf if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = -fprofile-arcs -ftest-coverage endif lib_LTLIBRARIES = libgnunetchat.la libgnunetchat_la_SOURCES = \ chat.c chat.h libgnunetchat_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la libgnunetchat_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 0:0:0 bin_PROGRAMS = \ gnunet-service-chat \ gnunet-chat gnunet_service_chat_SOURCES = \ gnunet-service-chat.c gnunet_service_chat_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_chat_SOURCES = \ gnunet-chat.c gnunet_chat_LDADD = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_chat_DEPENDENCIES = \ libgnunetchat.la check_PROGRAMS = \ test_chat \ test_chat_acknowledgement \ test_chat_anonymous \ test_chat_authentication \ test_chat_p2p \ test_chat_acknowledgement_p2p \ test_chat_anonymous_p2p \ test_chat_authentication_p2p \ test_chat_private \ test_chat_private_p2p if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) endif test_chat_SOURCES = \ test_chat.c test_chat_LDADD = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la test_chat_acknowledgement_SOURCES = \ test_chat.c test_chat_acknowledgement_LDADD = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la test_chat_anonymous_SOURCES = \ test_chat.c test_chat_anonymous_LDADD = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la test_chat_authentication_SOURCES = \ test_chat.c test_chat_authentication_LDADD = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la test_chat_p2p_SOURCES = \ test_chat.c test_chat_p2p_LDADD = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la test_chat_acknowledgement_p2p_SOURCES = \ test_chat.c test_chat_acknowledgement_p2p_LDADD = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la test_chat_anonymous_p2p_SOURCES = \ test_chat.c test_chat_anonymous_p2p_LDADD = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la test_chat_authentication_p2p_SOURCES = \ test_chat.c test_chat_authentication_p2p_LDADD = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la test_chat_private_SOURCES = \ test_chat_private.c test_chat_private_LDADD = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la test_chat_private_p2p_SOURCES = \ test_chat_private.c test_chat_private_p2p_LDADD = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ test_chat_data.conf \ test_chat_peer1.conf \ test_chat_peer2.conf \ test_chat_peer3.conf gnunet-0.9.3/src/chat/gnunet-service-chat.c0000644000175000017500000015623611760502551015510 00000000000000/* This file is part of GNUnet. (C) 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file chat/gnunet-service-chat.c * @brief service providing chat functionality * @author Christian Grothoff * @author Vitaly Minko */ #include "platform.h" #include "gnunet_core_service.h" #include "gnunet_crypto_lib.h" #include "gnunet_protocols.h" #include "gnunet_service_lib.h" #include "gnunet_signatures.h" #include "chat.h" #define DEBUG_CHAT_SERVICE GNUNET_EXTRA_LOGGING #define MAX_TRANSMIT_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) #define EXPECTED_NEIGHBOUR_COUNT 16 #define QUEUE_SIZE 16 #define MAX_ANONYMOUS_MSG_LIST_LENGTH 16 /** * Linked list of our current clients. */ struct ChatClient { struct ChatClient *next; /** * Handle for a chat client (NULL for external clients). */ struct GNUNET_SERVER_Client *client; /** * Public key of the client. */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; /** * Name of the room which the client is in. */ char *room; /** * Serialized metadata of the client. */ char *member_info; /** * Hash of the public key (for convenience). */ GNUNET_HashCode id; /** * Options which the client is willing to receive. */ uint32_t msg_options; /** * Length of serialized metadata in member_info. */ uint16_t meta_len; /** * Sequence number of the last message sent by the client. */ uint32_t msg_sequence_number; /** * Sequence number of the last receipt sent by the client. * Used to discard already processed receipts. */ uint32_t rcpt_sequence_number; }; /** * Information about a peer that we are connected to. * We track data that is useful for determining which * peers should receive our requests. */ struct ConnectedPeer { /** * The peer's identity. */ GNUNET_PEER_Id pid; }; /** * Linked list of recent anonymous messages. */ struct AnonymousMessage { struct AnonymousMessage *next; /** * Hash of the message. */ GNUNET_HashCode hash; }; /** * Handle to the core service (NULL until we've connected to it). */ static struct GNUNET_CORE_Handle *core; /** * Our configuration. */ static const struct GNUNET_CONFIGURATION_Handle *cfg; /** * The identity of this host. */ static const struct GNUNET_PeerIdentity *me; /** * Head of the list of current clients. */ static struct ChatClient *client_list_head = NULL; /** * Notification context containing all connected clients. */ struct GNUNET_SERVER_NotificationContext *nc = NULL; /** * Head of the list of recent anonymous messages. */ static struct AnonymousMessage *anonymous_list_head = NULL; /** * Map of peer identifiers to "struct ConnectedPeer" (for that peer). */ static struct GNUNET_CONTAINER_MultiHashMap *connected_peers; static void remember_anonymous_message (const struct P2PReceiveNotificationMessage *p2p_rnmsg) { static GNUNET_HashCode hash; struct AnonymousMessage *anon_msg; struct AnonymousMessage *prev; int anon_list_len; GNUNET_CRYPTO_hash (p2p_rnmsg, ntohs (p2p_rnmsg->header.size), &hash); anon_msg = GNUNET_malloc (sizeof (struct AnonymousMessage)); anon_msg->hash = hash; anon_msg->next = anonymous_list_head; anonymous_list_head = anon_msg; anon_list_len = 1; prev = NULL; while ((NULL != anon_msg->next)) { prev = anon_msg; anon_msg = anon_msg->next; anon_list_len++; } if (anon_list_len == MAX_ANONYMOUS_MSG_LIST_LENGTH) { GNUNET_free (anon_msg); if (NULL != prev) prev->next = NULL; } } static int lookup_anonymous_message (const struct P2PReceiveNotificationMessage *p2p_rnmsg) { static GNUNET_HashCode hash; struct AnonymousMessage *anon_msg; GNUNET_CRYPTO_hash (p2p_rnmsg, ntohs (p2p_rnmsg->header.size), &hash); anon_msg = anonymous_list_head; while ((NULL != anon_msg) && (0 != memcmp (&anon_msg->hash, &hash, sizeof (GNUNET_HashCode)))) anon_msg = anon_msg->next; return (NULL != anon_msg); } /** * Transmit a message notification to the peer. * * @param cls closure, pointer to the 'struct P2PReceiveNotificationMessage' * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_message_notification_to_peer (void *cls, size_t size, void *buf) { struct P2PReceiveNotificationMessage *my_msg = cls; struct P2PReceiveNotificationMessage *m = buf; size_t msg_size; #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P message notification\n"); #endif if (buf == NULL) { /* client disconnected */ #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Buffer is NULL, dropping the message\n"); #endif return 0; } msg_size = ntohs (my_msg->header.size); GNUNET_assert (size >= msg_size); memcpy (m, my_msg, msg_size); GNUNET_free (my_msg); return msg_size; } /** * Ask to send a message notification to the peer. */ static int send_message_noficiation (void *cls, const GNUNET_HashCode * key, void *value) { struct P2PReceiveNotificationMessage *msg = cls; struct ConnectedPeer *cp = value; struct GNUNET_PeerIdentity pid; struct P2PReceiveNotificationMessage *my_msg; GNUNET_PEER_resolve (cp->pid, &pid); #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message notification to `%s'\n", GNUNET_i2s (&pid)); #endif my_msg = GNUNET_memdup (msg, ntohs (msg->header.size)); if (NULL == GNUNET_CORE_notify_transmit_ready (core, GNUNET_NO, 1, MAX_TRANSMIT_DELAY, &pid, ntohs (msg->header.size), &transmit_message_notification_to_peer, my_msg)) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to queue a message notification\n")); return GNUNET_YES; } /** * A client sent a chat message. Encrypt the message text if the message is * private. Send the message to local room members and to all connected peers. * * @param cls closure, NULL * @param client identification of the client * @param message the actual message */ static void handle_transmit_request (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { static GNUNET_HashCode all_zeros; const struct TransmitRequestMessage *trmsg; struct ReceiveNotificationMessage *rnmsg; struct P2PReceiveNotificationMessage *p2p_rnmsg; struct ChatClient *pos; struct ChatClient *target; struct GNUNET_CRYPTO_AesSessionKey key; char encrypted_msg[MAX_MESSAGE_LENGTH]; const char *room; size_t room_len; int msg_len; int is_priv; int is_anon; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a chat message\n"); if (ntohs (message->size) <= sizeof (struct TransmitRequestMessage)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n"); GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } trmsg = (const struct TransmitRequestMessage *) message; msg_len = ntohs (trmsg->header.size) - sizeof (struct TransmitRequestMessage); is_priv = (0 != (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_PRIVATE)); if (is_priv) { #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting the message text\n"); #endif GNUNET_CRYPTO_aes_create_session_key (&key); msg_len = GNUNET_CRYPTO_aes_encrypt (&trmsg[1], msg_len, &key, (const struct GNUNET_CRYPTO_AesInitializationVector *) INITVALUE, encrypted_msg); if (-1 == msg_len) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not encrypt the message text\n"); GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } } rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len); rnmsg->header.size = htons (sizeof (struct ReceiveNotificationMessage) + msg_len); rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION); rnmsg->msg_options = trmsg->msg_options; rnmsg->timestamp = trmsg->timestamp; pos = client_list_head; while ((NULL != pos) && (pos->client != client)) pos = pos->next; if (NULL == pos) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "The client is not a member of a chat room. Client has to " "join a chat room first\n"); GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); GNUNET_free (rnmsg); return; } room = pos->room; pos->msg_sequence_number = ntohl (trmsg->sequence_number); is_anon = (0 != (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS)); if (is_anon) { memset (&rnmsg->sender, 0, sizeof (GNUNET_HashCode)); rnmsg->sequence_number = 0; } else { rnmsg->sender = pos->id; rnmsg->sequence_number = trmsg->sequence_number; } if (is_priv) { #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting the session key using the public key of '%s'\n", GNUNET_h2s (&trmsg->target)); #endif if (0 == memcmp (&all_zeros, &trmsg->target, sizeof (GNUNET_HashCode))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: private, but no target\n"); GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); GNUNET_free (rnmsg); return; } memcpy (&rnmsg[1], encrypted_msg, msg_len); target = client_list_head; while ((NULL != target) && (0 != memcmp (&target->id, &trmsg->target, sizeof (GNUNET_HashCode)))) target = target->next; if (NULL == target) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unknown target of the private message\n"); GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); GNUNET_free (rnmsg); return; } if (GNUNET_SYSERR == GNUNET_CRYPTO_rsa_encrypt (&key, sizeof (struct GNUNET_CRYPTO_AesSessionKey), &target->public_key, &rnmsg->encrypted_key)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not encrypt the session key\n"); GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); GNUNET_free (rnmsg); return; } } else { memcpy (&rnmsg[1], &trmsg[1], msg_len); } pos = client_list_head; #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message to local room members\n"); #endif while (NULL != pos) { if ((0 == strcmp (room, pos->room)) && (NULL != pos->client) && (pos->client != client)) { if (((!is_priv) || (0 == memcmp (&trmsg->target, &pos->id, sizeof (GNUNET_HashCode)))) && (0 == (ntohl (trmsg->msg_options) & (~pos->msg_options)))) { GNUNET_SERVER_notification_context_unicast (nc, pos->client, &rnmsg->header, GNUNET_NO); } } pos = pos->next; } #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Broadcasting message to neighbour peers\n"); #endif if (is_anon) { room_len = strlen (room); p2p_rnmsg = GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) + msg_len + room_len); p2p_rnmsg->header.size = htons (sizeof (struct P2PReceiveNotificationMessage) + msg_len + room_len); p2p_rnmsg->room_name_len = htons (room_len); memcpy ((char *) &p2p_rnmsg[1], room, room_len); memcpy ((char *) &p2p_rnmsg[1] + room_len, &trmsg[1], msg_len); } else { p2p_rnmsg = GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) + msg_len); p2p_rnmsg->header.size = htons (sizeof (struct P2PReceiveNotificationMessage) + msg_len); if (is_priv) { memcpy (&p2p_rnmsg[1], encrypted_msg, msg_len); memcpy (&p2p_rnmsg->encrypted_key, &rnmsg->encrypted_key, sizeof (struct GNUNET_CRYPTO_RsaEncryptedData)); } else memcpy (&p2p_rnmsg[1], &trmsg[1], msg_len); } p2p_rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION); p2p_rnmsg->msg_options = trmsg->msg_options; p2p_rnmsg->sequence_number = trmsg->sequence_number; p2p_rnmsg->timestamp = trmsg->timestamp; p2p_rnmsg->reserved = htons (0); p2p_rnmsg->sender = rnmsg->sender; p2p_rnmsg->target = trmsg->target; if (is_anon) remember_anonymous_message (p2p_rnmsg); GNUNET_CONTAINER_multihashmap_iterate (connected_peers, &send_message_noficiation, p2p_rnmsg); GNUNET_free (p2p_rnmsg); GNUNET_SERVER_receive_done (client, GNUNET_OK); GNUNET_free (rnmsg); } /** * Transmit a join notification to the peer. * * @param cls closure, pointer to the 'struct ChatClient' * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_join_notification_to_peer (void *cls, size_t size, void *buf) { struct ChatClient *entry = cls; struct P2PJoinNotificationMessage *m = buf; size_t room_len; size_t meta_len; size_t msg_size; char *roomptr; #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P join notification\n"); #endif room_len = strlen (entry->room); meta_len = entry->meta_len; msg_size = sizeof (struct P2PJoinNotificationMessage) + meta_len + room_len; GNUNET_assert (size >= msg_size); GNUNET_assert (NULL != buf); m = buf; m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION); m->header.size = htons (msg_size); m->msg_options = htonl (entry->msg_options); m->room_name_len = htons (room_len); m->reserved = htons (0); m->reserved2 = htonl (0); m->public_key = entry->public_key; roomptr = (char *) &m[1]; memcpy (roomptr, entry->room, room_len); if (meta_len > 0) memcpy (&roomptr[room_len], entry->member_info, meta_len); return msg_size; } /** * Ask to send a join notification to the peer. */ static int send_join_noficiation (void *cls, const GNUNET_HashCode * key, void *value) { struct ChatClient *entry = cls; struct ConnectedPeer *cp = value; struct GNUNET_PeerIdentity pid; size_t msg_size; GNUNET_PEER_resolve (cp->pid, &pid); #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending join notification to `%s'\n", GNUNET_i2s (&pid)); #endif msg_size = sizeof (struct P2PJoinNotificationMessage) + strlen (entry->room) + entry->meta_len; if (NULL == GNUNET_CORE_notify_transmit_ready (core, GNUNET_NO, 1, MAX_TRANSMIT_DELAY, &pid, msg_size, &transmit_join_notification_to_peer, entry)) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to queue a join notification\n")); return GNUNET_YES; } /** * A client asked for entering a chat room. Add the new member to the list of * clients and notify remaining room members. * * @param cls closure, NULL * @param client identification of the client * @param message the actual message */ static void handle_join_request (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct JoinRequestMessage *jrmsg; char *room_name; const char *roomptr; uint16_t header_size; uint16_t meta_len; uint16_t room_name_len; struct ChatClient *new_entry; struct ChatClient *entry; struct JoinNotificationMessage *jnmsg; struct JoinNotificationMessage *entry_jnmsg; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a join request\n"); if (ntohs (message->size) <= sizeof (struct JoinRequestMessage)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n"); GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } jrmsg = (const struct JoinRequestMessage *) message; header_size = ntohs (jrmsg->header.size); room_name_len = ntohs (jrmsg->room_name_len); if (header_size - sizeof (struct JoinRequestMessage) <= room_name_len) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong length of the room name\n"); GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } meta_len = header_size - sizeof (struct JoinRequestMessage) - room_name_len; roomptr = (const char *) &jrmsg[1]; room_name = GNUNET_malloc (room_name_len + 1); memcpy (room_name, roomptr, room_name_len); room_name[room_name_len] = '\0'; new_entry = GNUNET_malloc (sizeof (struct ChatClient)); memset (new_entry, 0, sizeof (struct ChatClient)); new_entry->client = client; new_entry->room = room_name; new_entry->public_key = jrmsg->public_key; new_entry->meta_len = meta_len; if (meta_len > 0) { new_entry->member_info = GNUNET_malloc (meta_len); memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len); } else new_entry->member_info = NULL; GNUNET_CRYPTO_hash (&new_entry->public_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &new_entry->id); new_entry->msg_options = ntohl (jrmsg->msg_options); new_entry->next = client_list_head; client_list_head = new_entry; #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Synchronizing room members between local clients\n"); #endif jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len); jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION); jnmsg->header.size = htons (sizeof (struct JoinNotificationMessage) + meta_len); jnmsg->msg_options = jrmsg->msg_options; jnmsg->public_key = new_entry->public_key; memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len); GNUNET_SERVER_notification_context_add (nc, client); entry = client_list_head; while (NULL != entry) { if (0 == strcmp (room_name, entry->room)) { if (NULL != entry->client) GNUNET_SERVER_notification_context_unicast (nc, entry->client, &jnmsg->header, GNUNET_NO); if (entry->client != client) { entry_jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + entry->meta_len); entry_jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION); entry_jnmsg->header.size = htons (sizeof (struct JoinNotificationMessage) + entry->meta_len); entry_jnmsg->msg_options = entry->msg_options; entry_jnmsg->public_key = entry->public_key; memcpy (&entry_jnmsg[1], entry->member_info, entry->meta_len); GNUNET_SERVER_notification_context_unicast (nc, client, &entry_jnmsg->header, GNUNET_NO); GNUNET_free (entry_jnmsg); } } entry = entry->next; } #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Broadcasting join notification to neighbour peers\n"); #endif GNUNET_CONTAINER_multihashmap_iterate (connected_peers, &send_join_noficiation, new_entry); GNUNET_SERVER_receive_done (client, GNUNET_OK); GNUNET_free (jnmsg); } /** * Transmit a confirmation receipt to the peer. * * @param cls closure, pointer to the 'struct P2PConfirmationReceiptMessage' * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_confirmation_receipt_to_peer (void *cls, size_t size, void *buf) { struct P2PConfirmationReceiptMessage *receipt = cls; size_t msg_size; #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P confirmation receipt to '%s'\n", GNUNET_h2s (&receipt->target)); #endif if (buf == NULL) { /* client disconnected */ #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Buffer is NULL, dropping the message\n"); #endif return 0; } msg_size = sizeof (struct P2PConfirmationReceiptMessage); GNUNET_assert (size >= msg_size); memcpy (buf, receipt, msg_size); GNUNET_free (receipt); return msg_size; } /** * Ask to send a confirmation receipt to the peer. */ static int send_confirmation_receipt (void *cls, const GNUNET_HashCode * key, void *value) { struct P2PConfirmationReceiptMessage *receipt = cls; struct ConnectedPeer *cp = value; struct GNUNET_PeerIdentity pid; struct P2PConfirmationReceiptMessage *my_receipt; size_t msg_size; GNUNET_PEER_resolve (cp->pid, &pid); #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending confirmation receipt to `%s'\n", GNUNET_i2s (&pid)); #endif msg_size = sizeof (struct P2PConfirmationReceiptMessage); my_receipt = GNUNET_memdup (receipt, sizeof (struct P2PConfirmationReceiptMessage)); if (NULL == GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 1, MAX_TRANSMIT_DELAY, &pid, msg_size, &transmit_confirmation_receipt_to_peer, my_receipt)) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to queue a confirmation receipt\n")); return GNUNET_YES; } /** * A client sent a confirmation receipt. Broadcast the receipt to all connected * peers if the author of the original message is a local client. Otherwise * check the signature and notify the user if the signature is valid. * * @param cls closure, NULL * @param client identification of the client * @param message the actual message */ static void handle_acknowledge_request (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct ConfirmationReceiptMessage *receipt; struct ConfirmationReceiptMessage *crmsg; struct P2PConfirmationReceiptMessage *p2p_crmsg; struct ChatClient *target; struct ChatClient *author; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a confirmation receipt\n"); receipt = (const struct ConfirmationReceiptMessage *) message; author = client_list_head; while ((NULL != author) && (0 != memcmp (&receipt->author, &author->id, sizeof (GNUNET_HashCode)))) author = author->next; if (NULL == author) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unknown author of the original message\n"); GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } target = client_list_head; while ((NULL != target) && (0 != memcmp (&receipt->target, &target->id, sizeof (GNUNET_HashCode)))) target = target->next; if (NULL == target) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unknown target of the confirmation receipt\n"); GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } if (NULL == author->client) { target->rcpt_sequence_number++; #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Broadcasting %s's receipt #%u to neighbour peers\n", GNUNET_h2s (&target->id), target->rcpt_sequence_number); #endif p2p_crmsg = GNUNET_malloc (sizeof (struct P2PConfirmationReceiptMessage)); p2p_crmsg->header.size = htons (sizeof (struct P2PConfirmationReceiptMessage)); p2p_crmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT); p2p_crmsg->reserved = htonl (0); p2p_crmsg->signature = receipt->signature; p2p_crmsg->purpose = receipt->purpose; p2p_crmsg->msg_sequence_number = receipt->sequence_number; p2p_crmsg->timestamp = receipt->timestamp; p2p_crmsg->target = receipt->target; p2p_crmsg->author = receipt->author; p2p_crmsg->content = receipt->content; p2p_crmsg->sequence_number = htonl (target->rcpt_sequence_number); GNUNET_CONTAINER_multihashmap_iterate (connected_peers, &send_confirmation_receipt, p2p_crmsg); GNUNET_free (p2p_crmsg); } else { #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Verifying signature of the receipt\n"); #endif if (GNUNET_OK != GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT, &receipt->purpose, &receipt->signature, &target->public_key)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid signature of the receipt\n"); GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending receipt to the client which sent the original message\n"); #endif crmsg = GNUNET_memdup (receipt, sizeof (struct ConfirmationReceiptMessage)); crmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION); GNUNET_SERVER_notification_context_unicast (nc, author->client, &crmsg->header, GNUNET_NO); GNUNET_free (crmsg); } GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * Transmit a leave notification to the peer. * * @param cls closure, pointer to the * 'struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded' * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_leave_notification_to_peer (void *cls, size_t size, void *buf) { struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key = cls; struct P2PLeaveNotificationMessage *m = buf; size_t msg_size; #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P leave notification\n"); #endif if (buf == NULL) { /* client disconnected */ #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Buffer is NULL, dropping the message\n"); #endif return 0; } msg_size = sizeof (struct P2PLeaveNotificationMessage); GNUNET_assert (size >= msg_size); m = buf; m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION); m->header.size = htons (msg_size); m->reserved = htonl (0); m->user = *public_key; GNUNET_free (public_key); return msg_size; } /** * Ask to send a leave notification to the peer. */ static int send_leave_noficiation (void *cls, const GNUNET_HashCode * key, void *value) { struct ChatClient *entry = cls; struct ConnectedPeer *cp = value; struct GNUNET_PeerIdentity pid; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key; size_t msg_size; GNUNET_PEER_resolve (cp->pid, &pid); #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending leave notification to `%s'\n", GNUNET_i2s (&pid)); #endif msg_size = sizeof (struct P2PLeaveNotificationMessage); public_key = GNUNET_memdup (&entry->public_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); if (NULL == GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 1, MAX_TRANSMIT_DELAY, &pid, msg_size, &transmit_leave_notification_to_peer, public_key)) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to queue a leave notification\n")); return GNUNET_YES; } /** * A client disconnected. Remove all of its data structure entries and notify * remaining room members. * * @param cls closure, NULL * @param client identification of the client */ static void handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) { struct ChatClient *entry; struct ChatClient *pos; struct ChatClient *prev; struct LeaveNotificationMessage lnmsg; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client disconnected\n"); pos = client_list_head; prev = NULL; while ((NULL != pos) && (pos->client != client)) { prev = pos; pos = pos->next; } if (NULL == pos) { #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No such client. There is nothing to do\n"); #endif return; } if (NULL == prev) client_list_head = pos->next; else prev->next = pos->next; entry = client_list_head; #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Notifying local room members that the client has disconnected\n"); #endif lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage)); lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION); lnmsg.reserved = htonl (0); lnmsg.user = pos->public_key; while (NULL != entry) { if ((0 == strcmp (pos->room, entry->room)) && (NULL != entry->client)) { GNUNET_SERVER_notification_context_unicast (nc, entry->client, &lnmsg.header, GNUNET_NO); } entry = entry->next; } #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Broadcasting leave notification to neighbour peers\n"); #endif GNUNET_CONTAINER_multihashmap_iterate (connected_peers, &send_leave_noficiation, pos); GNUNET_free (pos->room); GNUNET_free_non_null (pos->member_info); GNUNET_free (pos); } /** * Handle P2P join notification. * * @param cls closure, always NULL * @param other the other peer involved * @param message the actual message * @param atsi performance information * @param atsi_count number of entries in atsi * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_p2p_join_notification (void *cls, const struct GNUNET_PeerIdentity *other, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { const struct P2PJoinNotificationMessage *p2p_jnmsg; char *room_name; const char *roomptr; uint16_t header_size; uint16_t meta_len; uint16_t room_name_len; struct ChatClient *new_entry; struct ChatClient *entry; struct JoinNotificationMessage *jnmsg; GNUNET_HashCode id; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P join notification\n"); if (ntohs (message->size) <= sizeof (struct P2PJoinNotificationMessage)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n"); GNUNET_break_op (0); return GNUNET_SYSERR; } p2p_jnmsg = (const struct P2PJoinNotificationMessage *) message; header_size = ntohs (p2p_jnmsg->header.size); room_name_len = ntohs (p2p_jnmsg->room_name_len); if (header_size - sizeof (struct P2PJoinNotificationMessage) <= room_name_len) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong length of the room name\n"); GNUNET_break_op (0); return GNUNET_SYSERR; } GNUNET_CRYPTO_hash (&p2p_jnmsg->public_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &id); entry = client_list_head; while (NULL != entry) { if (0 == memcmp (&entry->id, &id, sizeof (GNUNET_HashCode))) { #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "The client has already joined. There is nothing to do\n"); #endif return GNUNET_OK; } entry = entry->next; } meta_len = header_size - sizeof (struct P2PJoinNotificationMessage) - room_name_len; roomptr = (const char *) &p2p_jnmsg[1]; room_name = GNUNET_malloc (room_name_len + 1); memcpy (room_name, roomptr, room_name_len); room_name[room_name_len] = '\0'; new_entry = GNUNET_malloc (sizeof (struct ChatClient)); memset (new_entry, 0, sizeof (struct ChatClient)); new_entry->id = id; new_entry->client = NULL; new_entry->room = room_name; new_entry->public_key = p2p_jnmsg->public_key; new_entry->meta_len = meta_len; if (meta_len > 0) { new_entry->member_info = GNUNET_malloc (meta_len); memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len); } else new_entry->member_info = NULL; new_entry->msg_options = ntohl (p2p_jnmsg->msg_options); new_entry->next = client_list_head; client_list_head = new_entry; #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Notifying local room members that we have a new client\n"); #endif jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len); jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION); jnmsg->header.size = htons (sizeof (struct JoinNotificationMessage) + meta_len); jnmsg->msg_options = p2p_jnmsg->msg_options; jnmsg->public_key = new_entry->public_key; memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len); entry = client_list_head; while (NULL != entry) { if ((0 == strcmp (room_name, entry->room)) && (NULL != entry->client)) { GNUNET_SERVER_notification_context_unicast (nc, entry->client, &jnmsg->header, GNUNET_NO); } entry = entry->next; } #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Broadcasting join notification to neighbour peers\n"); #endif GNUNET_CONTAINER_multihashmap_iterate (connected_peers, &send_join_noficiation, new_entry); GNUNET_free (jnmsg); return GNUNET_OK; } /** * Handle P2P leave notification. * * @param cls closure, always NULL * @param other the other peer involved * @param message the actual message * @param atsi performance information * @param atsi_count number of entries in atsi * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_p2p_leave_notification (void *cls, const struct GNUNET_PeerIdentity *other, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { const struct P2PLeaveNotificationMessage *p2p_lnmsg; GNUNET_HashCode id; struct ChatClient *pos; struct ChatClient *prev; struct ChatClient *entry; struct LeaveNotificationMessage lnmsg; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P leave notification\n"); p2p_lnmsg = (const struct P2PLeaveNotificationMessage *) message; GNUNET_CRYPTO_hash (&p2p_lnmsg->user, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &id); pos = client_list_head; prev = NULL; while (NULL != pos) { if (0 == memcmp (&pos->id, &id, sizeof (GNUNET_HashCode))) break; prev = pos; pos = pos->next; } if (NULL == pos) { #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No such client. There is nothing to do\n"); #endif return GNUNET_OK; } if (NULL == prev) client_list_head = pos->next; else prev->next = pos->next; #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Notifying local room members that the client has gone away\n"); #endif lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage)); lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION); lnmsg.reserved = htonl (0); lnmsg.user = pos->public_key; entry = client_list_head; while (NULL != entry) { if (0 == strcmp (pos->room, entry->room) && (NULL != entry->client)) { GNUNET_SERVER_notification_context_unicast (nc, entry->client, &lnmsg.header, GNUNET_NO); } entry = entry->next; } #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Broadcasting leave notification to neighbour peers\n"); #endif GNUNET_CONTAINER_multihashmap_iterate (connected_peers, &send_leave_noficiation, pos); GNUNET_free (pos->room); GNUNET_free_non_null (pos->member_info); GNUNET_free (pos); return GNUNET_OK; } /** * Handle P2P message notification. * * @param cls closure, always NULL * @param other the other peer involved * @param message the actual message * @param atsi performance information * @param atsi_count number of entries in atsi * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_p2p_message_notification (void *cls, const struct GNUNET_PeerIdentity *other, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { const struct P2PReceiveNotificationMessage *p2p_rnmsg; struct P2PReceiveNotificationMessage *my_p2p_rnmsg; struct ReceiveNotificationMessage *rnmsg; struct ChatClient *sender; struct ChatClient *pos; static GNUNET_HashCode all_zeros; int is_priv; int is_anon; uint16_t msg_len; uint16_t room_name_len; char *room_name = NULL; char *text; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P message notification\n"); if (ntohs (message->size) <= sizeof (struct P2PReceiveNotificationMessage)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n"); GNUNET_break_op (0); return GNUNET_SYSERR; } p2p_rnmsg = (const struct P2PReceiveNotificationMessage *) message; msg_len = ntohs (p2p_rnmsg->header.size) - sizeof (struct P2PReceiveNotificationMessage); is_anon = (0 != (ntohl (p2p_rnmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS)); if (is_anon) { room_name_len = ntohs (p2p_rnmsg->room_name_len); if (msg_len <= room_name_len) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong length of the room name\n"); GNUNET_break_op (0); return GNUNET_SYSERR; } msg_len -= room_name_len; if (lookup_anonymous_message (p2p_rnmsg)) { #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "This anonymous message has already been handled."); #endif return GNUNET_OK; } remember_anonymous_message (p2p_rnmsg); room_name = GNUNET_malloc (room_name_len + 1); memcpy (room_name, (char *) &p2p_rnmsg[1], room_name_len); room_name[room_name_len] = '\0'; text = (char *) &p2p_rnmsg[1] + room_name_len; } else { sender = client_list_head; while ((NULL != sender) && (0 != memcmp (&sender->id, &p2p_rnmsg->sender, sizeof (GNUNET_HashCode)))) sender = sender->next; if (NULL == sender) { /* not an error since the sender may have left before we got the * message */ #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Unknown source. Rejecting the message\n"); #endif return GNUNET_OK; } if (sender->msg_sequence_number >= ntohl (p2p_rnmsg->sequence_number)) { #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "This message has already been handled." " Sequence numbers (msg/sender): %u/%u\n", ntohl (p2p_rnmsg->sequence_number), sender->msg_sequence_number); #endif return GNUNET_OK; } sender->msg_sequence_number = ntohl (p2p_rnmsg->sequence_number); room_name = sender->room; text = (char *) &p2p_rnmsg[1]; } #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message to local room members\n"); #endif rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len); rnmsg->header.size = htons (sizeof (struct ReceiveNotificationMessage) + msg_len); rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION); rnmsg->msg_options = p2p_rnmsg->msg_options; rnmsg->sequence_number = p2p_rnmsg->sequence_number; rnmsg->reserved = htonl (0); rnmsg->timestamp = p2p_rnmsg->timestamp; is_priv = (0 != memcmp (&all_zeros, &p2p_rnmsg->target, sizeof (GNUNET_HashCode))); if (is_priv) memcpy (&rnmsg->encrypted_key, &p2p_rnmsg->encrypted_key, sizeof (struct GNUNET_CRYPTO_RsaEncryptedData)); rnmsg->sender = p2p_rnmsg->sender; memcpy (&rnmsg[1], text, msg_len); pos = client_list_head; while (NULL != pos) { if ((0 == strcmp (room_name, pos->room)) && (NULL != pos->client)) { if (((!is_priv) || (0 == memcmp (&p2p_rnmsg->target, &pos->id, sizeof (GNUNET_HashCode)))) && (0 == (ntohl (p2p_rnmsg->msg_options) & (~pos->msg_options)))) { GNUNET_SERVER_notification_context_unicast (nc, pos->client, &rnmsg->header, GNUNET_NO); } } pos = pos->next; } if (is_anon) GNUNET_free (room_name); #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Broadcasting message notification to neighbour peers\n"); #endif my_p2p_rnmsg = GNUNET_memdup (p2p_rnmsg, ntohs (p2p_rnmsg->header.size)); GNUNET_CONTAINER_multihashmap_iterate (connected_peers, &send_message_noficiation, my_p2p_rnmsg); GNUNET_free (rnmsg); return GNUNET_OK; } /** * Handle P2P sync request. * * @param cls closure, always NULL * @param other the other peer involved * @param message the actual message * @param atsi performance information * @param atsi_count number of entries in atsi * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_p2p_sync_request (void *cls, const struct GNUNET_PeerIdentity *other, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct ChatClient *entry; struct GNUNET_CORE_TransmitHandle *th; size_t msg_size; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P sync request\n"); #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Notifying the requester of all known clients\n"); #endif entry = client_list_head; while (NULL != entry) { msg_size = sizeof (struct P2PJoinNotificationMessage) + strlen (entry->room) + entry->meta_len; th = GNUNET_CORE_notify_transmit_ready (core, GNUNET_NO, 1, MAX_TRANSMIT_DELAY, other, msg_size, &transmit_join_notification_to_peer, entry); GNUNET_assert (NULL != th); entry = entry->next; } return GNUNET_OK; } /** * Handle P2P confirmation receipt. * * @param cls closure, always NULL * @param other the other peer involved * @param message the actual message * @param atsi performance information * @param atsi_count number of entries in atsi * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_p2p_confirmation_receipt (void *cls, const struct GNUNET_PeerIdentity *other, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { const struct P2PConfirmationReceiptMessage *p2p_crmsg; struct P2PConfirmationReceiptMessage *my_p2p_crmsg; struct ConfirmationReceiptMessage *crmsg; struct ChatClient *target; struct ChatClient *author; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P confirmation receipt\n"); p2p_crmsg = (const struct P2PConfirmationReceiptMessage *) message; target = client_list_head; while ((NULL != target) && (0 != memcmp (&target->id, &p2p_crmsg->target, sizeof (GNUNET_HashCode)))) target = target->next; if (NULL == target) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unknown source of the receipt. Rejecting the message\n"); GNUNET_break_op (0); return GNUNET_SYSERR; } if (target->rcpt_sequence_number >= ntohl (p2p_crmsg->sequence_number)) { #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "This receipt has already been handled." " Sequence numbers (msg/sender): %u/%u\n", ntohl (p2p_crmsg->sequence_number), target->rcpt_sequence_number); #endif return GNUNET_OK; } target->rcpt_sequence_number = ntohl (p2p_crmsg->sequence_number); author = client_list_head; while ((NULL != author) && (0 != memcmp (&author->id, &p2p_crmsg->author, sizeof (GNUNET_HashCode)))) author = author->next; if (NULL == author) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unknown addressee. Rejecting the receipt\n"); GNUNET_break_op (0); return GNUNET_SYSERR; } if (NULL == author->client) { #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "The author of the original message is not a local client." " Broadcasting receipt to neighbour peers\n"); #endif my_p2p_crmsg = GNUNET_memdup (p2p_crmsg, sizeof (struct P2PConfirmationReceiptMessage)); GNUNET_CONTAINER_multihashmap_iterate (connected_peers, &send_confirmation_receipt, my_p2p_crmsg); GNUNET_free (my_p2p_crmsg); } else { #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "The author of the original message is a local client." " Verifying signature of the receipt\n"); #endif crmsg = GNUNET_malloc (sizeof (struct ConfirmationReceiptMessage)); crmsg->header.size = htons (sizeof (struct ConfirmationReceiptMessage)); crmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION); crmsg->signature = p2p_crmsg->signature; crmsg->purpose = p2p_crmsg->purpose; crmsg->sequence_number = p2p_crmsg->msg_sequence_number; crmsg->reserved2 = 0; crmsg->timestamp = p2p_crmsg->timestamp; crmsg->target = p2p_crmsg->target; crmsg->author = p2p_crmsg->author; crmsg->content = p2p_crmsg->content; if (GNUNET_OK != GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT, &crmsg->purpose, &crmsg->signature, &target->public_key)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid signature of the receipt\n"); GNUNET_break_op (0); return GNUNET_SYSERR; } #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "The author of the original message is a local client." " Sending receipt to the client\n"); #endif GNUNET_SERVER_notification_context_unicast (nc, author->client, &crmsg->header, GNUNET_NO); GNUNET_free (crmsg); } return GNUNET_OK; } /** * Transmit a sync request to the peer. * * @param cls closure, NULL * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_sync_request_to_peer (void *cls, size_t size, void *buf) { struct GNUNET_MessageHeader *m = buf; size_t msg_size; #if DEBUG_CHAT_SERVICE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P sync request\n"); #endif msg_size = sizeof (struct GNUNET_MessageHeader); GNUNET_assert (size >= msg_size); GNUNET_assert (NULL != buf); m = buf; m->type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST); m->size = htons (msg_size); return msg_size; } /** * Method called whenever a peer connects. * * @param cls closure * @param peer peer identity this notification is about * @param atsi performance data * @param atsi_count number of entries in atsi */ static void peer_connect_handler (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct ConnectedPeer *cp; struct GNUNET_CORE_TransmitHandle *th; if (0 == memcmp (peer, me, sizeof (struct GNUNET_PeerIdentity))) return; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer connected: %s\n", GNUNET_i2s (peer)); th = GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 1, MAX_TRANSMIT_DELAY, peer, sizeof (struct GNUNET_MessageHeader), &transmit_sync_request_to_peer, NULL); GNUNET_assert (NULL != th); cp = GNUNET_CONTAINER_multihashmap_get (connected_peers, &peer->hashPubKey); if (NULL != cp) { GNUNET_break (0); return; } cp = GNUNET_malloc (sizeof (struct ConnectedPeer)); cp->pid = GNUNET_PEER_intern (peer); GNUNET_break (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (connected_peers, &peer->hashPubKey, cp, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); } /** * Iterator to free peer entries. * * @param cls closure, unused * @param key current key code * @param value value in the hash map (peer entry) * @return GNUNET_YES (we should continue to iterate) */ static int clean_peer (void *cls, const GNUNET_HashCode * key, void *value) { struct ConnectedPeer *cp; const struct GNUNET_PeerIdentity *peer = (const struct GNUNET_PeerIdentity *) key; cp = GNUNET_CONTAINER_multihashmap_get (connected_peers, &peer->hashPubKey); if (cp == NULL) return GNUNET_YES; GNUNET_break (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (connected_peers, &peer->hashPubKey, cp)); GNUNET_PEER_change_rc (cp->pid, -1); GNUNET_free (cp); return GNUNET_YES; } /** * Method called whenever a peer disconnects. * * @param cls closure, not used * @param peer peer identity this notification is about */ static void peer_disconnect_handler (void *cls, const struct GNUNET_PeerIdentity *peer) { if (0 == memcmp (peer, me, sizeof (struct GNUNET_PeerIdentity))) return; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer disconnected: %s\n", GNUNET_i2s (peer)); clean_peer (NULL, (const GNUNET_HashCode *) peer, NULL); } /** * Task run during shutdown. * * @param cls unused * @param tc unused */ static void cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct AnonymousMessage *next_msg; struct ChatClient *next_client; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Cleaning up\n"); if (NULL != core) { GNUNET_CORE_disconnect (core); core = NULL; } if (NULL != nc) { GNUNET_SERVER_notification_context_destroy (nc); nc = NULL; } while (NULL != client_list_head) { next_client = client_list_head->next; GNUNET_free (client_list_head->room); GNUNET_free_non_null (client_list_head->member_info); GNUNET_free (client_list_head); client_list_head = next_client; } while (NULL != anonymous_list_head) { next_msg = anonymous_list_head->next; GNUNET_free (anonymous_list_head); anonymous_list_head = next_msg; } GNUNET_CONTAINER_multihashmap_iterate (connected_peers, &clean_peer, NULL); GNUNET_CONTAINER_multihashmap_destroy (connected_peers); connected_peers = NULL; } /** * To be called on core init/fail. * * @param cls closure, NULL * @param server handle to the server for this service * @param my_identity the public identity of this peer */ static void core_init (void *cls, struct GNUNET_CORE_Handle *server, const struct GNUNET_PeerIdentity *my_identity) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Core initialized\n"); me = my_identity; } /** * Process chat requests. * * @param cls closure, NULL * @param server the initialized server * @param c configuration to use */ static void run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *c) { static const struct GNUNET_SERVER_MessageHandler handlers[] = { {&handle_join_request, NULL, GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST, 0}, {&handle_transmit_request, NULL, GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST, 0}, {&handle_acknowledge_request, NULL, GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT, sizeof (struct ConfirmationReceiptMessage)}, {NULL, NULL, 0, 0} }; static const struct GNUNET_CORE_MessageHandler p2p_handlers[] = { {&handle_p2p_join_notification, GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION, 0}, {&handle_p2p_leave_notification, GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION, sizeof (struct P2PLeaveNotificationMessage)}, {&handle_p2p_message_notification, GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION, 0}, {&handle_p2p_sync_request, GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST, sizeof (struct GNUNET_MessageHeader)}, {&handle_p2p_confirmation_receipt, GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT, sizeof (struct P2PConfirmationReceiptMessage)}, {NULL, 0, 0} }; GNUNET_log_setup ("gnunet-service-chat", #if DEBUG_CHAT_SERVICE "DEBUG", #else "WARNING", #endif NULL); cfg = c; nc = GNUNET_SERVER_notification_context_create (server, 16); connected_peers = GNUNET_CONTAINER_multihashmap_create (EXPECTED_NEIGHBOUR_COUNT); GNUNET_SERVER_add_handlers (server, handlers); core = GNUNET_CORE_connect (cfg, QUEUE_SIZE, NULL, &core_init, &peer_connect_handler, &peer_disconnect_handler, NULL, GNUNET_NO, NULL, GNUNET_NO, p2p_handlers); GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, NULL); } /** * The main function for the chat service. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { return (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "chat", GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; } /* end of gnunet-service-chat.c */ gnunet-0.9.3/src/chat/test_chat_peer1.conf0000644000175000017500000000311011647100200015355 00000000000000[PATHS] SERVICEHOME = /tmp/gnunet-test-chat-peer-1/ DEFAULTCONFIG = test_chat_peer1.conf [gnunetd] HOSTKEY = $SERVICEHOME/.hostkey [hostlist] HTTPPORT = 31000 OPTIONS = -p [resolver] PORT = 31001 HOSTNAME = localhost UNIXPATH = /tmp/gnunet-chat-p1-service-resolver.sock [transport] PORT = 31002 UNIXPATH = /tmp/gnunet-chat-p1-service-transport.sock PLUGINS = tcp #BINARY = /home/grothoff/bin/gnunet-service-transport #PREFIX = valgrind [transport-tcp] PORT = 31003 [arm] PORT = 31004 UNIXPATH = /tmp/gnunet-chat-p1-service-arm.sock HOSTNAME = localhost DEFAULTSERVICES = resolver transport core topology hostlist statistics chat [core] PORT = 31005 UNIXPATH = /tmp/gnunet-chat-p1-service-core.sock HOSTNAME = localhost [topology] MINIMUM-FRIENDS = 0 FRIENDS-ONLY = NO AUTOCONNECT = YES TARGET-CONNECTION-COUNT = 16 FRIENDS = $SERVICEHOME/friends CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-topology [peerinfo] PORT = 31006 UNIXPATH = /tmp/gnunet-chat-p1-service-peerinfo.sock HOSTNAME = localhost [statistics] PORT = 31007 HOSTNAME = localhost UNIXPATH = /tmp/gnunet-chat-p1-service-statistics.sock [chat] PORT = 31008 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-chat [testing] WEAKRANDOM = YES [fs] AUTOSTART = NO [datastore] AUTOSTART = NO [dht] AUTOSTART = NO [mesh] AUTOSTART = NO [nat] DISABLEV6 = YES BINDTO = 127.0.0.1 ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 [dns] AUTOSTART = NO [nse] AUTOSTART = NO [ats] PORT = 31971 UNIXPATH = /tmp/gnunet-chat-p1-service-ats.sock gnunet-0.9.3/src/chat/test_chat_peer2.conf0000644000175000017500000000313311647100200015363 00000000000000[PATHS] SERVICEHOME = /tmp/gnunet-test-chat-peer-2/ DEFAULTCONFIG = test_chat_peer2.conf [gnunetd] HOSTKEY = $SERVICEHOME/.hostkey [hostlist] SERVERS = http://localhost:31000/ OPTIONS = -b [resolver] PORT = 32001 HOSTNAME = localhost UNIXPATH = /tmp/gnunet-chat-p2-service-resolver.sock [transport] PORT = 32002 UNIXPATH = /tmp/gnunet-chat-p2-service-transport.sock PLUGINS = tcp #BINARY = /home/grothoff/bin/gnunet-service-transport #PREFIX = valgrind [transport-tcp] PORT = 32003 [arm] PORT = 32004 UNIXPATH = /tmp/gnunet-chat-p2-service-arm.sock HOSTNAME = localhost DEFAULTSERVICES = resolver transport core topology hostlist statistics chat [core] PORT = 32005 UNIXPATH = /tmp/gnunet-chat-p2-service-core.sock HOSTNAME = localhost [topology] MINIMUM-FRIENDS = 0 FRIENDS-ONLY = NO AUTOCONNECT = YES TARGET-CONNECTION-COUNT = 16 FRIENDS = $SERVICEHOME/friends CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-topology [peerinfo] PORT = 32006 UNIXPATH = /tmp/gnunet-chat-p2-service-peerinfo.sock HOSTNAME = localhost [statistics] PORT = 32007 HOSTNAME = localhost UNIXPATH = /tmp/gnunet-chat-p2-service-statistics.sock [chat] PORT = 32008 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-chat [testing] WEAKRANDOM = YES [fs] AUTOSTART = NO [datastore] AUTOSTART = NO [dht] AUTOSTART = NO [mesh] AUTOSTART = NO [nat] DISABLEV6 = YES BINDTO = 127.0.0.1 ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 [dns] AUTOSTART = NO [nse] AUTOSTART = NO [ats] PORT = 32971 UNIXPATH = /tmp/gnunet-chat-p2-service-ats.sock gnunet-0.9.3/src/chat/test_chat.c0000644000175000017500000003716711760502551013614 00000000000000/* This file is part of GNUnet. (C) 2005, 2006, 2007, 2008, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file chat/test_chat.c * @brief base test case for the chat library * @author Christian Grothoff * @author Nathan Evans * @author Vitaly Minko * * This test case serves as a base for simple chatting, anonymous chatting, * authenticated chatting and acknowledgements test cases. Based on the * executable being run the correct test case will be performed. Private * chatting is covered by a separate test case since it requires 3 users. */ #include "platform.h" #include "gnunet_crypto_lib.h" #include "gnunet_util_lib.h" #include "gnunet_arm_service.h" #include "gnunet_chat_service.h" #define VERBOSE GNUNET_NO #define START_ARM GNUNET_YES /** * How long until we give up on passing the test? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; struct Wanted { struct GNUNET_CONTAINER_MetaData *meta; GNUNET_HashCode *sender; char *msg; const char *me; enum GNUNET_CHAT_MsgOptions opt; uint32_t sequence_number; struct GNUNET_TIME_Absolute timestamp; GNUNET_SCHEDULER_Task next_task; void *next_task_cls; }; static struct PeerContext p1; static struct PeerContext p2; static GNUNET_HashCode alice; static GNUNET_HashCode bob; static struct GNUNET_CHAT_Room *alice_room; static struct GNUNET_CHAT_Room *bob_room; static struct GNUNET_CONTAINER_MetaData *alice_meta; static struct GNUNET_CONTAINER_MetaData *bob_meta; static struct Wanted alice_wanted; static struct Wanted bob_wanted; static GNUNET_SCHEDULER_TaskIdentifier kill_task; static GNUNET_SCHEDULER_TaskIdentifier wait_task; static int err; static int is_ready; static int is_p2p; static int is_ackn; static int is_anon; static int is_auth; static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE "-L", "DEBUG", #endif "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); } static void stop_arm (struct PeerContext *p) { #if START_ARM if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; #endif GNUNET_CONFIGURATION_destroy (p->cfg); } static void abort_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (alice_room != NULL) { GNUNET_CHAT_leave_room (alice_room); alice_room = NULL; } if (bob_room != NULL) { GNUNET_CHAT_leave_room (bob_room); bob_room = NULL; } err = 1; } static void timeout_kill (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { #if VERBOSE printf ("Timed out, stopping the test.\n"); #endif kill_task = GNUNET_SCHEDULER_NO_TASK; if (wait_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (wait_task); wait_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_SCHEDULER_add_continuation (&abort_test, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } static int join_cb (void *cls) { struct Wanted *want = cls; #if VERBOSE printf ("%s has joined\n", want->me); #endif if (NULL != want->next_task) GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); return GNUNET_OK; } static int member_list_cb (void *cls, const struct GNUNET_CONTAINER_MetaData *member_info, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *member_id, enum GNUNET_CHAT_MsgOptions options) { struct Wanted *want = cls; GNUNET_HashCode sender; #if VERBOSE printf ("%s - told that %s has %s\n", want->me, member_info == NULL ? NULL : GNUNET_CONTAINER_meta_data_get_by_type (member_info, EXTRACTOR_METATYPE_TITLE), member_info == NULL ? "left" : "joined"); #endif GNUNET_CRYPTO_hash (member_id, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &sender); if ((0 == memcmp (&sender, want->sender, sizeof (GNUNET_HashCode))) && (((member_info == NULL) && (want->meta == NULL)) || ((member_info != NULL) && (want->meta != NULL) && (GNUNET_CONTAINER_meta_data_test_equal (member_info, want->meta)))) && (options == want->opt)) { if (NULL != want->next_task) GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); } else { GNUNET_SCHEDULER_cancel (kill_task); kill_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_SCHEDULER_add_now (&abort_test, NULL); } return GNUNET_OK; } static int receive_cb (void *cls, struct GNUNET_CHAT_Room *room, const GNUNET_HashCode * sender, const struct GNUNET_CONTAINER_MetaData *meta, const char *message, struct GNUNET_TIME_Absolute timestamp, enum GNUNET_CHAT_MsgOptions options) { struct Wanted *want = cls; #if VERBOSE printf ("%s - told that %s said %s\n", want->me, meta == NULL ? NULL : GNUNET_CONTAINER_meta_data_get_by_type (meta, EXTRACTOR_METATYPE_TITLE), message); #endif if ((0 == strcmp (message, want->msg)) && (((sender == NULL) && (want->sender == NULL)) || ((sender != NULL) && (want->sender != NULL) && (0 == memcmp (sender, want->sender, sizeof (GNUNET_HashCode))))) && (GNUNET_CONTAINER_meta_data_test_equal (meta, want->meta)) && (options == want->opt) && /* Not == since the library sets the actual timestamp, so it may be * slightly greater */ (timestamp.abs_value >= want->timestamp.abs_value)) { if (NULL != want->next_task) GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); } else { GNUNET_SCHEDULER_cancel (kill_task); kill_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_SCHEDULER_add_now (&abort_test, NULL); } return GNUNET_OK; } static int confirmation_cb (void *cls, struct GNUNET_CHAT_Room *room, uint32_t orig_seq_number, struct GNUNET_TIME_Absolute timestamp, const GNUNET_HashCode * receiver) { struct Wanted *want = cls; #if VERBOSE printf ("%s - told that %s acknowledged message #%d\n", want->me, GNUNET_CONTAINER_meta_data_get_by_type (want->meta, EXTRACTOR_METATYPE_TITLE), orig_seq_number); #endif if ((0 == memcmp (receiver, want->sender, sizeof (GNUNET_HashCode))) && (orig_seq_number == want->sequence_number) && (timestamp.abs_value >= want->timestamp.abs_value)) { if (NULL != want->next_task) GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); } else { GNUNET_SCHEDULER_cancel (kill_task); kill_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_SCHEDULER_add_now (&abort_test, NULL); } return GNUNET_OK; } static void wait_until_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_SCHEDULER_Task task = cls; #if VERBOSE printf ("Waiting...\n"); #endif if (is_ready) { wait_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_SCHEDULER_add_now (task, NULL); } else wait_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 50), &wait_until_ready, task); } static void disconnect_alice (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { #if VERBOSE printf ("Alice is leaving.\n"); #endif if (is_p2p) stop_arm (&p2); GNUNET_CHAT_leave_room (alice_room); alice_room = NULL; GNUNET_SCHEDULER_cancel (kill_task); kill_task = GNUNET_SCHEDULER_NO_TASK; } static void disconnect_bob (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { #if VERBOSE printf ("Bod is leaving.\n"); #endif alice_wanted.meta = NULL; alice_wanted.sender = &bob; alice_wanted.msg = NULL; alice_wanted.opt = 0; alice_wanted.next_task = &disconnect_alice; alice_wanted.next_task_cls = NULL; GNUNET_CHAT_leave_room (bob_room); bob_room = NULL; } static void set_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { is_ready = GNUNET_YES; } static void send_to_alice (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { #if VERBOSE printf ("Bob says 'Hi!'\n"); #endif alice_wanted.meta = bob_meta; alice_wanted.sender = &bob; alice_wanted.msg = "Hi Alice!"; alice_wanted.opt = GNUNET_CHAT_MSG_OPTION_NONE; alice_wanted.timestamp = GNUNET_TIME_absolute_get (); alice_wanted.next_task = &disconnect_bob; alice_wanted.next_task_cls = NULL; GNUNET_CHAT_send_message (bob_room, "Hi Alice!", GNUNET_CHAT_MSG_OPTION_NONE, NULL, NULL); } static void send_to_bob (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { enum GNUNET_CHAT_MsgOptions options; uint32_t *seq = NULL; #if VERBOSE printf ("Alice says 'Hi!'\n"); #endif if (is_ackn) { options = GNUNET_CHAT_MSG_ACKNOWLEDGED; alice_wanted.meta = bob_meta; alice_wanted.sender = &bob; alice_wanted.timestamp = GNUNET_TIME_absolute_get (); alice_wanted.next_task = &disconnect_bob; alice_wanted.next_task_cls = NULL; bob_wanted.meta = alice_meta; bob_wanted.sender = &alice; bob_wanted.next_task = NULL; seq = &(alice_wanted.sequence_number); } else if (is_anon) { options = GNUNET_CHAT_MSG_ANONYMOUS; bob_wanted.meta = NULL; bob_wanted.sender = NULL; bob_wanted.next_task = &disconnect_bob; } else if (is_auth) { options = GNUNET_CHAT_MSG_AUTHENTICATED; bob_wanted.meta = alice_meta; bob_wanted.sender = &alice; bob_wanted.next_task = &disconnect_bob; } else { options = GNUNET_CHAT_MSG_OPTION_NONE; bob_wanted.meta = alice_meta; bob_wanted.sender = &alice; bob_wanted.next_task = &send_to_alice; } bob_wanted.msg = "Hi Bob!"; bob_wanted.opt = options; bob_wanted.timestamp = GNUNET_TIME_absolute_get (); bob_wanted.next_task_cls = NULL; GNUNET_CHAT_send_message (alice_room, "Hi Bob!", options, NULL, seq); } static void prepare_for_alice_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { bob_wanted.meta = alice_meta; bob_wanted.sender = &alice; bob_wanted.msg = NULL; bob_wanted.opt = -1; bob_wanted.next_task = &set_ready; bob_wanted.next_task_cls = NULL; } static void join_bob_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { #if VERBOSE printf ("Bob joining\n"); #endif alice_wanted.meta = bob_meta; alice_wanted.sender = &bob; alice_wanted.msg = NULL; alice_wanted.opt = -1; alice_wanted.next_task = &wait_until_ready; alice_wanted.next_task_cls = &send_to_bob; bob_wanted.next_task = &prepare_for_alice_task; bob_wanted.next_task_cls = NULL; is_ready = GNUNET_NO; bob_room = GNUNET_CHAT_join_room (is_p2p ? p2.cfg : p1.cfg, "bob", bob_meta, "test", -1, &join_cb, &bob_wanted, &receive_cb, &bob_wanted, &member_list_cb, &bob_wanted, &confirmation_cb, &bob_wanted, &bob); if (NULL == bob_room) { GNUNET_SCHEDULER_cancel (kill_task); kill_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_CHAT_leave_room (alice_room); alice_room = NULL; err = 1; } } static void join_alice_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { #if VERBOSE printf ("Alice joining\n"); #endif alice_wanted.next_task = &join_bob_task; alice_wanted.next_task_cls = NULL; alice_room = GNUNET_CHAT_join_room (p1.cfg, "alice", alice_meta, "test", -1, &join_cb, &alice_wanted, &receive_cb, &alice_wanted, &member_list_cb, &alice_wanted, &confirmation_cb, &alice_wanted, &alice); if (NULL == alice_room) { GNUNET_SCHEDULER_cancel (kill_task); kill_task = GNUNET_SCHEDULER_NO_TASK; err = 1; } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { if (is_p2p) { setup_peer (&p1, "test_chat_peer1.conf"); setup_peer (&p2, "test_chat_peer2.conf"); } else setup_peer (&p1, "test_chat_data.conf"); memset (&alice_wanted, 0, sizeof (struct Wanted)); memset (&bob_wanted, 0, sizeof (struct Wanted)); alice_wanted.me = "Alice"; bob_wanted.me = "Bob"; alice_meta = GNUNET_CONTAINER_meta_data_create (); GNUNET_CONTAINER_meta_data_insert (alice_meta, "", EXTRACTOR_METATYPE_TITLE, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "Alice", strlen ("Alice") + 1); bob_meta = GNUNET_CONTAINER_meta_data_create (); GNUNET_CONTAINER_meta_data_insert (bob_meta, "", EXTRACTOR_METATYPE_TITLE, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "Bob", strlen ("Bob") + 1); kill_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_kill, NULL); GNUNET_SCHEDULER_add_now (&join_alice_task, NULL); } int main (int argc, char *argv[]) { char *const argvx[] = { "test-chat", "-c", "test_chat_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("test_chat", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); if (strstr (argv[0], "p2p") != NULL) { is_p2p = GNUNET_YES; } if (strstr (argv[0], "acknowledgment") != NULL) { is_ackn = GNUNET_YES; } else if (strstr (argv[0], "anonymous") != NULL) { is_anon = GNUNET_YES; } else if (strstr (argv[0], "authentication") != NULL) { is_auth = GNUNET_YES; } GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "test-chat", "nohelp", options, &run, NULL); stop_arm (&p1); GNUNET_CONTAINER_meta_data_destroy (alice_meta); GNUNET_CONTAINER_meta_data_destroy (bob_meta); if (is_p2p) { GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-1/"); GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-2/"); } else GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat/"); return err; } /* end of test_chat.c */ gnunet-0.9.3/src/chat/test_chat_peer3.conf0000644000175000017500000000303211611077627015403 00000000000000[PATHS] SERVICEHOME = /tmp/gnunet-test-chat-peer-3/ DEFAULTCONFIG = test_chat_peer3.conf [gnunetd] HOSTKEY = $SERVICEHOME/.hostkey [hostlist] SERVERS = http://localhost:31000/ OPTIONS = -b [resolver] PORT = 33001 HOSTNAME = localhost UNIXPATH = /tmp/gnunet-chat-p3-service-resolver.sock [transport] PORT = 33002 UNIXPATH = /tmp/gnunet-chat-p3-service-transport.sock PLUGINS = tcp #BINARY = /home/grothoff/bin/gnunet-service-transport #PREFIX = valgrind [transport-tcp] PORT = 33003 [arm] PORT = 33004 UNIXPATH = /tmp/gnunet-chat-p3-service-arm.sock HOSTNAME = localhost DEFAULTSERVICES = resolver transport core topology hostlist statistics chat [core] PORT = 33005 UNIXPATH = /tmp/gnunet-chat-p3-service-core.sock HOSTNAME = localhost [topology] MINIMUM-FRIENDS = 0 FRIENDS-ONLY = NO AUTOCONNECT = YES TARGET-CONNECTION-COUNT = 16 FRIENDS = $SERVICEHOME/friends CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-topology [peerinfo] PORT = 33006 UNIXPATH = /tmp/gnunet-chat-p3-service-peerinfo.sock HOSTNAME = localhost [statistics] PORT = 33007 HOSTNAME = localhost UNIXPATH = /tmp/gnunet-chat-p3-service-statistics.sock [chat] PORT = 33008 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-chat [testing] WEAKRANDOM = YES [fs] AUTOSTART = NO [datastore] AUTOSTART = NO [dht] AUTOSTART = NO [mesh] AUTOSTART = NO [nat] DISABLEV6 = YES BINDTO = 127.0.0.1 ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 [dns] AUTOSTART = NO [nse] AUTOSTART = NO gnunet-0.9.3/src/chat/test_chat_private.c0000644000175000017500000004410011760502551015327 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file chat/test_chat_private.c * @brief testcase for private chatting * @author Vitaly Minko */ #include "platform.h" #include "gnunet_crypto_lib.h" #include "gnunet_util_lib.h" #include "gnunet_arm_service.h" #include "gnunet_chat_service.h" #define VERBOSE GNUNET_NO #define START_ARM GNUNET_YES /** * How long until we give up on passing the test? */ #define KILL_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) /** * How long until we give up on receiving somebody else's private message? */ #define PM_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; struct Wanted { struct GNUNET_CONTAINER_MetaData *meta; GNUNET_HashCode *sender; /** * Alternative meta/sender is used when we expect join/leave notification * from two peers and don't know which one will come first. */ struct GNUNET_CONTAINER_MetaData *meta2; GNUNET_HashCode *sender2; char *msg; const char *me; enum GNUNET_CHAT_MsgOptions opt; struct GNUNET_TIME_Absolute timestamp; GNUNET_SCHEDULER_Task next_task; void *next_task_cls; }; static struct PeerContext p1; static struct PeerContext p2; static struct PeerContext p3; static GNUNET_HashCode alice; static GNUNET_HashCode bob; static GNUNET_HashCode carol; static struct GNUNET_CHAT_Room *alice_room; static struct GNUNET_CHAT_Room *bob_room; static struct GNUNET_CHAT_Room *carol_room; static struct GNUNET_CONTAINER_MetaData *alice_meta; static struct GNUNET_CONTAINER_MetaData *bob_meta; static struct GNUNET_CONTAINER_MetaData *carol_meta; static struct Wanted alice_wanted; static struct Wanted bob_wanted; static struct Wanted carol_wanted; static GNUNET_SCHEDULER_TaskIdentifier kill_task; static GNUNET_SCHEDULER_TaskIdentifier finish_task; static GNUNET_SCHEDULER_TaskIdentifier wait_task; static int err; static int alice_ready; static int bob_ready; static int is_p2p; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *bob_public_key = NULL; static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE "-L", "DEBUG", #endif "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); } static void stop_arm (struct PeerContext *p) { #if START_ARM if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; #endif GNUNET_CONFIGURATION_destroy (p->cfg); } static void abort_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (alice_room != NULL) { GNUNET_CHAT_leave_room (alice_room); alice_room = NULL; } if (bob_room != NULL) { GNUNET_CHAT_leave_room (bob_room); bob_room = NULL; } if (carol_room != NULL) { GNUNET_CHAT_leave_room (carol_room); carol_room = NULL; } err = 1; } static void timeout_kill (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { #if VERBOSE printf ("Timed out, stopping the test.\n"); #endif kill_task = GNUNET_SCHEDULER_NO_TASK; if (wait_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (wait_task); wait_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_SCHEDULER_add_continuation (&abort_test, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } static int join_cb (void *cls) { struct Wanted *want = cls; #if VERBOSE printf ("%s has joined\n", want->me); #endif if (NULL != want->next_task) GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); return GNUNET_OK; } static int member_list_cb (void *cls, const struct GNUNET_CONTAINER_MetaData *member_info, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *member_id, enum GNUNET_CHAT_MsgOptions options) { struct Wanted *want = cls; GNUNET_HashCode sender; #if VERBOSE printf ("%s - told that %s has %s\n", want->me, member_info == NULL ? NULL : GNUNET_CONTAINER_meta_data_get_by_type (member_info, EXTRACTOR_METATYPE_TITLE), member_info == NULL ? "left" : "joined"); #endif GNUNET_CRYPTO_hash (member_id, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &sender); /* entertain both primary and an alternative sender/meta */ if (((0 == memcmp (&sender, want->sender, sizeof (GNUNET_HashCode))) || ((want->sender2 != NULL) && (0 == memcmp (&sender, want->sender2, sizeof (GNUNET_HashCode))))) && (((member_info == NULL) && (want->meta == NULL)) || ((member_info != NULL) && (((want->meta != NULL) && GNUNET_CONTAINER_meta_data_test_equal (member_info, want->meta)) || ((want->meta2 != NULL) && GNUNET_CONTAINER_meta_data_test_equal (member_info, want->meta2))))) && (options == want->opt)) { /* remember Bob's public key, we need it to send private message */ if (NULL == bob_public_key && (0 == memcmp (&bob, want->sender, sizeof (GNUNET_HashCode)))) bob_public_key = GNUNET_memdup (member_id, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); if (want->sender2 != NULL) { /* flush alternative sender */ if (0 == memcmp (&sender, want->sender, sizeof (GNUNET_HashCode))) { want->sender = want->sender2; want->meta = want->meta2; } want->sender2 = NULL; want->meta2 = NULL; } else if (NULL != want->next_task) GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); } else { GNUNET_SCHEDULER_cancel (kill_task); kill_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_SCHEDULER_add_now (&abort_test, NULL); } return GNUNET_OK; } static int receive_cb (void *cls, struct GNUNET_CHAT_Room *room, const GNUNET_HashCode * sender, const struct GNUNET_CONTAINER_MetaData *meta, const char *message, struct GNUNET_TIME_Absolute timestamp, enum GNUNET_CHAT_MsgOptions options) { struct Wanted *want = cls; #if VERBOSE printf ("%s - told that %s said '%s'\n", want->me, meta == NULL ? NULL : GNUNET_CONTAINER_meta_data_get_by_type (meta, EXTRACTOR_METATYPE_TITLE), message); #endif if ((want->msg != NULL) && (0 == strcmp (message, want->msg)) && (((sender == NULL) && (want->sender == NULL)) || ((sender != NULL) && (want->sender != NULL) && (0 == memcmp (sender, want->sender, sizeof (GNUNET_HashCode))))) && (GNUNET_CONTAINER_meta_data_test_equal (meta, want->meta)) && (options == want->opt) && /* Not == since the library sets the actual timestamp, so it may be * slightly greater */ (timestamp.abs_value >= want->timestamp.abs_value)) { if (NULL != want->next_task) GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); } else { GNUNET_SCHEDULER_cancel (kill_task); kill_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_SCHEDULER_cancel (finish_task); finish_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_SCHEDULER_add_now (&abort_test, NULL); } return GNUNET_OK; } static void wait_until_all_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_SCHEDULER_Task task = cls; #if VERBOSE printf ("Waiting...\n"); #endif if (alice_ready && bob_ready) { wait_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_SCHEDULER_add_now (task, NULL); } else wait_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 5000), &wait_until_all_ready, task); } static void set_alice_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { alice_ready = GNUNET_YES; } static void set_bob_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { bob_ready = GNUNET_YES; } static void disconnect_alice (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { #if VERBOSE printf ("Alice is leaving.\n"); #endif if (is_p2p) stop_arm (&p2); GNUNET_CHAT_leave_room (alice_room); alice_room = NULL; GNUNET_SCHEDULER_cancel (kill_task); kill_task = GNUNET_SCHEDULER_NO_TASK; } static void disconnect_bob (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { #if VERBOSE printf ("Bod is leaving.\n"); #endif if (is_p2p) stop_arm (&p3); alice_wanted.meta = NULL; alice_wanted.sender = &bob; alice_wanted.msg = NULL; alice_wanted.opt = 0; alice_wanted.next_task = &disconnect_alice; alice_wanted.next_task_cls = NULL; GNUNET_CHAT_leave_room (bob_room); bob_room = NULL; } static void disconnect_carol (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { #if VERBOSE printf ("Carol is leaving.\n"); #endif alice_wanted.meta = NULL; alice_wanted.sender = &carol; alice_wanted.msg = NULL; alice_wanted.opt = 0; alice_wanted.next_task = &set_alice_ready; alice_wanted.next_task_cls = NULL; alice_ready = GNUNET_NO; bob_wanted.meta = NULL; bob_wanted.sender = &carol; bob_wanted.msg = NULL; bob_wanted.opt = 0; bob_wanted.next_task = &wait_until_all_ready; bob_wanted.next_task_cls = &disconnect_bob; bob_ready = GNUNET_YES; GNUNET_CHAT_leave_room (carol_room); carol_room = NULL; } static void send_from_alice_to_bob (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { uint32_t seq; #if VERBOSE printf ("Alice says 'Hi!' to Bob\n"); #endif alice_ready = GNUNET_YES; bob_ready = GNUNET_NO; bob_wanted.meta = alice_meta; bob_wanted.sender = &alice; bob_wanted.msg = "Hi Bob!"; bob_wanted.opt = GNUNET_CHAT_MSG_PRIVATE; bob_wanted.next_task = &set_bob_ready; bob_wanted.next_task_cls = NULL; /* Carol should not receive this message */ carol_wanted.meta = NULL; carol_wanted.sender = NULL; carol_wanted.msg = NULL; carol_wanted.opt = 0; carol_wanted.next_task = NULL; carol_wanted.next_task_cls = NULL; GNUNET_CHAT_send_message (alice_room, "Hi Bob!", GNUNET_CHAT_MSG_PRIVATE, bob_public_key, &seq); finish_task = GNUNET_SCHEDULER_add_delayed (PM_TIMEOUT, &wait_until_all_ready, &disconnect_carol); } static void prepare_bob_for_alice_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { bob_wanted.meta = alice_meta; bob_wanted.sender = &alice; bob_wanted.msg = NULL; bob_wanted.opt = -1; bob_wanted.next_task = &set_bob_ready; bob_wanted.next_task_cls = NULL; } static void prepare_carol_for_alice_and_bob_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { carol_wanted.meta = alice_meta; carol_wanted.sender = &alice; /* set alternative meta/sender since we don't know from which peer * notification will come first */ carol_wanted.meta2 = bob_meta; carol_wanted.sender2 = &bob; carol_wanted.msg = NULL; carol_wanted.opt = -1; carol_wanted.next_task = &wait_until_all_ready; carol_wanted.next_task_cls = &send_from_alice_to_bob; } static void join_carol_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { #if VERBOSE printf ("Carol joining\n"); #endif alice_wanted.meta = carol_meta; alice_wanted.sender = &carol; alice_wanted.msg = NULL; alice_wanted.opt = -1; alice_wanted.next_task = &set_alice_ready; alice_wanted.next_task_cls = NULL; alice_ready = GNUNET_NO; bob_wanted.meta = carol_meta; bob_wanted.sender = &carol; bob_wanted.msg = NULL; bob_wanted.opt = -1; bob_wanted.next_task = &set_bob_ready; bob_wanted.next_task_cls = NULL; bob_ready = GNUNET_NO; carol_wanted.next_task = &prepare_carol_for_alice_and_bob_task; carol_wanted.next_task_cls = NULL; carol_room = GNUNET_CHAT_join_room (is_p2p ? p3.cfg : p1.cfg, "carol", carol_meta, "test", -1, &join_cb, &carol_wanted, &receive_cb, &carol_wanted, &member_list_cb, &carol_wanted, NULL, NULL, &carol); if (NULL == carol_room) { GNUNET_SCHEDULER_cancel (kill_task); kill_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_CHAT_leave_room (alice_room); alice_room = NULL; GNUNET_CHAT_leave_room (bob_room); bob_room = NULL; err = 1; } } static void join_bob_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { #if VERBOSE printf ("Bob joining\n"); #endif alice_wanted.meta = bob_meta; alice_wanted.sender = &bob; alice_wanted.msg = NULL; alice_wanted.opt = -1; alice_wanted.next_task = &wait_until_all_ready; alice_wanted.next_task_cls = &join_carol_task; alice_ready = GNUNET_YES; bob_wanted.next_task = &prepare_bob_for_alice_task; bob_wanted.next_task_cls = NULL; bob_ready = GNUNET_NO; bob_room = GNUNET_CHAT_join_room (is_p2p ? p2.cfg : p1.cfg, "bob", bob_meta, "test", -1, &join_cb, &bob_wanted, &receive_cb, &bob_wanted, &member_list_cb, &bob_wanted, NULL, NULL, &bob); if (NULL == bob_room) { GNUNET_SCHEDULER_cancel (kill_task); kill_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_CHAT_leave_room (alice_room); alice_room = NULL; err = 1; } } static void join_alice_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { #if VERBOSE printf ("Alice joining\n"); #endif alice_wanted.next_task = &join_bob_task; alice_wanted.next_task_cls = NULL; alice_room = GNUNET_CHAT_join_room (p1.cfg, "alice", alice_meta, "test", -1, &join_cb, &alice_wanted, &receive_cb, &alice_wanted, &member_list_cb, &alice_wanted, NULL, NULL, &alice); if (NULL == alice_room) { GNUNET_SCHEDULER_cancel (kill_task); kill_task = GNUNET_SCHEDULER_NO_TASK; err = 1; } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { if (is_p2p) { setup_peer (&p1, "test_chat_peer1.conf"); setup_peer (&p2, "test_chat_peer2.conf"); setup_peer (&p3, "test_chat_peer3.conf"); } else setup_peer (&p1, "test_chat_data.conf"); memset (&alice_wanted, 0, sizeof (struct Wanted)); memset (&bob_wanted, 0, sizeof (struct Wanted)); memset (&carol_wanted, 0, sizeof (struct Wanted)); alice_wanted.me = "Alice"; bob_wanted.me = "Bob"; carol_wanted.me = "Carol"; alice_meta = GNUNET_CONTAINER_meta_data_create (); GNUNET_CONTAINER_meta_data_insert (alice_meta, "", EXTRACTOR_METATYPE_TITLE, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "Alice", strlen ("Alice") + 1); bob_meta = GNUNET_CONTAINER_meta_data_create (); GNUNET_CONTAINER_meta_data_insert (bob_meta, "", EXTRACTOR_METATYPE_TITLE, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "Bob", strlen ("Bob") + 1); carol_meta = GNUNET_CONTAINER_meta_data_create (); GNUNET_CONTAINER_meta_data_insert (carol_meta, "", EXTRACTOR_METATYPE_TITLE, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "Carol", strlen ("Carol") + 1); kill_task = GNUNET_SCHEDULER_add_delayed (KILL_TIMEOUT, &timeout_kill, NULL); GNUNET_SCHEDULER_add_now (&join_alice_task, NULL); } int main (int argc, char *argv[]) { char *const argvx[] = { "test-chat", "-c", "test_chat_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_log_setup ("test_chat", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); if (strstr (argv[0], "p2p") != NULL) { is_p2p = GNUNET_YES; } GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "test-chat", "nohelp", options, &run, NULL); stop_arm (&p1); GNUNET_CONTAINER_meta_data_destroy (alice_meta); GNUNET_CONTAINER_meta_data_destroy (bob_meta); GNUNET_CONTAINER_meta_data_destroy (carol_meta); if (is_p2p) { GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-1/"); GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-2/"); GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-3/"); } else GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat/"); return err; } /* end of test_chat_private.c */ gnunet-0.9.3/src/chat/Makefile.in0000644000175000017500000010763011762217210013525 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-service-chat$(EXEEXT) gnunet-chat$(EXEEXT) check_PROGRAMS = test_chat$(EXEEXT) test_chat_acknowledgement$(EXEEXT) \ test_chat_anonymous$(EXEEXT) test_chat_authentication$(EXEEXT) \ test_chat_p2p$(EXEEXT) test_chat_acknowledgement_p2p$(EXEEXT) \ test_chat_anonymous_p2p$(EXEEXT) \ test_chat_authentication_p2p$(EXEEXT) \ test_chat_private$(EXEEXT) test_chat_private_p2p$(EXEEXT) subdir = src/chat DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/chat.conf.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = chat.conf CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) libgnunetchat_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_libgnunetchat_la_OBJECTS = chat.lo libgnunetchat_la_OBJECTS = $(am_libgnunetchat_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunetchat_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetchat_la_LDFLAGS) $(LDFLAGS) \ -o $@ PROGRAMS = $(bin_PROGRAMS) am_gnunet_chat_OBJECTS = gnunet-chat.$(OBJEXT) gnunet_chat_OBJECTS = $(am_gnunet_chat_OBJECTS) am__DEPENDENCIES_1 = am_gnunet_service_chat_OBJECTS = gnunet-service-chat.$(OBJEXT) gnunet_service_chat_OBJECTS = $(am_gnunet_service_chat_OBJECTS) gnunet_service_chat_DEPENDENCIES = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_test_chat_OBJECTS = test_chat.$(OBJEXT) test_chat_OBJECTS = $(am_test_chat_OBJECTS) test_chat_DEPENDENCIES = $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_chat_acknowledgement_OBJECTS = test_chat.$(OBJEXT) test_chat_acknowledgement_OBJECTS = \ $(am_test_chat_acknowledgement_OBJECTS) test_chat_acknowledgement_DEPENDENCIES = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_chat_acknowledgement_p2p_OBJECTS = test_chat.$(OBJEXT) test_chat_acknowledgement_p2p_OBJECTS = \ $(am_test_chat_acknowledgement_p2p_OBJECTS) test_chat_acknowledgement_p2p_DEPENDENCIES = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_chat_anonymous_OBJECTS = test_chat.$(OBJEXT) test_chat_anonymous_OBJECTS = $(am_test_chat_anonymous_OBJECTS) test_chat_anonymous_DEPENDENCIES = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_chat_anonymous_p2p_OBJECTS = test_chat.$(OBJEXT) test_chat_anonymous_p2p_OBJECTS = \ $(am_test_chat_anonymous_p2p_OBJECTS) test_chat_anonymous_p2p_DEPENDENCIES = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_chat_authentication_OBJECTS = test_chat.$(OBJEXT) test_chat_authentication_OBJECTS = \ $(am_test_chat_authentication_OBJECTS) test_chat_authentication_DEPENDENCIES = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_chat_authentication_p2p_OBJECTS = test_chat.$(OBJEXT) test_chat_authentication_p2p_OBJECTS = \ $(am_test_chat_authentication_p2p_OBJECTS) test_chat_authentication_p2p_DEPENDENCIES = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_chat_p2p_OBJECTS = test_chat.$(OBJEXT) test_chat_p2p_OBJECTS = $(am_test_chat_p2p_OBJECTS) test_chat_p2p_DEPENDENCIES = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_chat_private_OBJECTS = test_chat_private.$(OBJEXT) test_chat_private_OBJECTS = $(am_test_chat_private_OBJECTS) test_chat_private_DEPENDENCIES = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_chat_private_p2p_OBJECTS = test_chat_private.$(OBJEXT) test_chat_private_p2p_OBJECTS = $(am_test_chat_private_p2p_OBJECTS) test_chat_private_p2p_DEPENDENCIES = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunetchat_la_SOURCES) $(gnunet_chat_SOURCES) \ $(gnunet_service_chat_SOURCES) $(test_chat_SOURCES) \ $(test_chat_acknowledgement_SOURCES) \ $(test_chat_acknowledgement_p2p_SOURCES) \ $(test_chat_anonymous_SOURCES) \ $(test_chat_anonymous_p2p_SOURCES) \ $(test_chat_authentication_SOURCES) \ $(test_chat_authentication_p2p_SOURCES) \ $(test_chat_p2p_SOURCES) $(test_chat_private_SOURCES) \ $(test_chat_private_p2p_SOURCES) DIST_SOURCES = $(libgnunetchat_la_SOURCES) $(gnunet_chat_SOURCES) \ $(gnunet_service_chat_SOURCES) $(test_chat_SOURCES) \ $(test_chat_acknowledgement_SOURCES) \ $(test_chat_acknowledgement_p2p_SOURCES) \ $(test_chat_anonymous_SOURCES) \ $(test_chat_anonymous_p2p_SOURCES) \ $(test_chat_authentication_SOURCES) \ $(test_chat_authentication_p2p_SOURCES) \ $(test_chat_p2p_SOURCES) $(test_chat_private_SOURCES) \ $(test_chat_private_p2p_SOURCES) DATA = $(pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include pkgcfgdir = $(pkgdatadir)/config.d/ pkgcfg_DATA = \ chat.conf @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = -fprofile-arcs -ftest-coverage lib_LTLIBRARIES = libgnunetchat.la libgnunetchat_la_SOURCES = \ chat.c chat.h libgnunetchat_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la libgnunetchat_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 0:0:0 gnunet_service_chat_SOURCES = \ gnunet-service-chat.c gnunet_service_chat_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_chat_SOURCES = \ gnunet-chat.c gnunet_chat_LDADD = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_chat_DEPENDENCIES = \ libgnunetchat.la @ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) test_chat_SOURCES = \ test_chat.c test_chat_LDADD = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la test_chat_acknowledgement_SOURCES = \ test_chat.c test_chat_acknowledgement_LDADD = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la test_chat_anonymous_SOURCES = \ test_chat.c test_chat_anonymous_LDADD = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la test_chat_authentication_SOURCES = \ test_chat.c test_chat_authentication_LDADD = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la test_chat_p2p_SOURCES = \ test_chat.c test_chat_p2p_LDADD = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la test_chat_acknowledgement_p2p_SOURCES = \ test_chat.c test_chat_acknowledgement_p2p_LDADD = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la test_chat_anonymous_p2p_SOURCES = \ test_chat.c test_chat_anonymous_p2p_LDADD = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la test_chat_authentication_p2p_SOURCES = \ test_chat.c test_chat_authentication_p2p_LDADD = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la test_chat_private_SOURCES = \ test_chat_private.c test_chat_private_LDADD = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la test_chat_private_p2p_SOURCES = \ test_chat_private.c test_chat_private_p2p_LDADD = \ $(top_builddir)/src/chat/libgnunetchat.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ test_chat_data.conf \ test_chat_peer1.conf \ test_chat_peer2.conf \ test_chat_peer3.conf all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/chat/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/chat/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): chat.conf: $(top_builddir)/config.status $(srcdir)/chat.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunetchat.la: $(libgnunetchat_la_OBJECTS) $(libgnunetchat_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetchat_la_LINK) -rpath $(libdir) $(libgnunetchat_la_OBJECTS) $(libgnunetchat_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-chat$(EXEEXT): $(gnunet_chat_OBJECTS) $(gnunet_chat_DEPENDENCIES) @rm -f gnunet-chat$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_chat_OBJECTS) $(gnunet_chat_LDADD) $(LIBS) gnunet-service-chat$(EXEEXT): $(gnunet_service_chat_OBJECTS) $(gnunet_service_chat_DEPENDENCIES) @rm -f gnunet-service-chat$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_service_chat_OBJECTS) $(gnunet_service_chat_LDADD) $(LIBS) test_chat$(EXEEXT): $(test_chat_OBJECTS) $(test_chat_DEPENDENCIES) @rm -f test_chat$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_chat_OBJECTS) $(test_chat_LDADD) $(LIBS) test_chat_acknowledgement$(EXEEXT): $(test_chat_acknowledgement_OBJECTS) $(test_chat_acknowledgement_DEPENDENCIES) @rm -f test_chat_acknowledgement$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_chat_acknowledgement_OBJECTS) $(test_chat_acknowledgement_LDADD) $(LIBS) test_chat_acknowledgement_p2p$(EXEEXT): $(test_chat_acknowledgement_p2p_OBJECTS) $(test_chat_acknowledgement_p2p_DEPENDENCIES) @rm -f test_chat_acknowledgement_p2p$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_chat_acknowledgement_p2p_OBJECTS) $(test_chat_acknowledgement_p2p_LDADD) $(LIBS) test_chat_anonymous$(EXEEXT): $(test_chat_anonymous_OBJECTS) $(test_chat_anonymous_DEPENDENCIES) @rm -f test_chat_anonymous$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_chat_anonymous_OBJECTS) $(test_chat_anonymous_LDADD) $(LIBS) test_chat_anonymous_p2p$(EXEEXT): $(test_chat_anonymous_p2p_OBJECTS) $(test_chat_anonymous_p2p_DEPENDENCIES) @rm -f test_chat_anonymous_p2p$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_chat_anonymous_p2p_OBJECTS) $(test_chat_anonymous_p2p_LDADD) $(LIBS) test_chat_authentication$(EXEEXT): $(test_chat_authentication_OBJECTS) $(test_chat_authentication_DEPENDENCIES) @rm -f test_chat_authentication$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_chat_authentication_OBJECTS) $(test_chat_authentication_LDADD) $(LIBS) test_chat_authentication_p2p$(EXEEXT): $(test_chat_authentication_p2p_OBJECTS) $(test_chat_authentication_p2p_DEPENDENCIES) @rm -f test_chat_authentication_p2p$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_chat_authentication_p2p_OBJECTS) $(test_chat_authentication_p2p_LDADD) $(LIBS) test_chat_p2p$(EXEEXT): $(test_chat_p2p_OBJECTS) $(test_chat_p2p_DEPENDENCIES) @rm -f test_chat_p2p$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_chat_p2p_OBJECTS) $(test_chat_p2p_LDADD) $(LIBS) test_chat_private$(EXEEXT): $(test_chat_private_OBJECTS) $(test_chat_private_DEPENDENCIES) @rm -f test_chat_private$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_chat_private_OBJECTS) $(test_chat_private_LDADD) $(LIBS) test_chat_private_p2p$(EXEEXT): $(test_chat_private_p2p_OBJECTS) $(test_chat_private_p2p_DEPENDENCIES) @rm -f test_chat_private_p2p$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_chat_private_p2p_OBJECTS) $(test_chat_private_p2p_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chat.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-chat.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-chat.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_chat.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_chat_private.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgcfgDATA: $(pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgcfgDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-binPROGRAMS install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-pkgcfgDATA install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/chat/chat.h0000644000175000017500000002544211760502551012553 00000000000000/* This file is part of GNUnet (C) 2008, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file chat/chat.h * @brief support for chat * @author Christian Grothoff * @author Nathan Evans * @author Vitaly Minko */ #ifndef CHAT_H #define CHAT_H #include "gnunet_chat_service.h" /** * Constant IV since we generate a new session key per each message. */ #define INITVALUE "InitializationVectorValue" /** * Client-service messages */ GNUNET_NETWORK_STRUCT_BEGIN /** * Notification sent by service to client indicating that we've received a chat * message. After this struct, the remaining bytes are the actual text message. * If the mesasge is private, then the text is encrypted, otherwise it's * plaintext. */ struct ReceiveNotificationMessage { /** * Message type will be GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION */ struct GNUNET_MessageHeader header; /** * Message options, see GNUNET_CHAT_MsgOptions. */ uint32_t msg_options GNUNET_PACKED; /** * Sequence number of the message (unique per sender). */ uint32_t sequence_number GNUNET_PACKED; /** * For alignment (should be zero). */ uint32_t reserved GNUNET_PACKED; /** * Timestamp of the message. */ struct GNUNET_TIME_AbsoluteNBO timestamp; /** * Hash of the public key of the pseudonym of the sender of the message. * Should be all zeros for anonymous. */ GNUNET_HashCode sender; /** * The encrypted session key. */ struct GNUNET_CRYPTO_RsaEncryptedData encrypted_key; }; /** * Request sent by client to transmit a chat message to another room members. * After this struct, the remaining bytes are the actual message in plaintext. * Private messages are encrypted on the service side. */ struct TransmitRequestMessage { /** * Message type will be GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST */ struct GNUNET_MessageHeader header; /** * For alignment (should be zero). */ uint32_t reserved GNUNET_PACKED; /** * Signature confirming receipt. Signature covers everything from header * through content. */ struct GNUNET_CRYPTO_RsaSignature signature; /** * What is being signed and why? */ struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; /** * Desired message options, see GNUNET_CHAT_MsgOptions. */ uint32_t msg_options GNUNET_PACKED; /** * Sequence number of the message (unique per sender). */ uint32_t sequence_number GNUNET_PACKED; /** * Timestamp of the message. */ struct GNUNET_TIME_AbsoluteNBO timestamp; /** * Who should receive this message? Set to all zeros for "everyone". */ GNUNET_HashCode target; }; /** * Receipt sent from a message receiver to the service to confirm delivery of * a chat message and from the service to sender of the original message to * acknowledge delivery. */ struct ConfirmationReceiptMessage { /** * Message type will be * GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT when sending from client, * GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION when sending to client. */ struct GNUNET_MessageHeader header; /** * For alignment (should be zero). */ uint32_t reserved GNUNET_PACKED; /** * Signature confirming receipt. Signature covers everything from header * through content. */ struct GNUNET_CRYPTO_RsaSignature signature; /** * What is being signed and why? */ struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; /** * Sequence number of the original message. */ uint32_t sequence_number GNUNET_PACKED; /** * For alignment (should be zero). */ uint32_t reserved2 GNUNET_PACKED; /** * Time of receipt. */ struct GNUNET_TIME_AbsoluteNBO timestamp; /** * Who is confirming the receipt? */ GNUNET_HashCode target; /** * Who is the author of the chat message? */ GNUNET_HashCode author; /** * Hash of the (possibly encrypted) content. */ GNUNET_HashCode content; }; /** * Message send from client to daemon to join a chat room. * This struct is followed by the room name and then * the serialized ECRS meta data describing the new member. */ struct JoinRequestMessage { /** * Message type will be GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST */ struct GNUNET_MessageHeader header; /** * Options. Set all options that this client is willing to receive. * For example, if the client does not want to receive anonymous or * OTR messages but is willing to generate acknowledgements and * receive private messages, this should be set to * GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED. */ uint32_t msg_options GNUNET_PACKED; /** * Length of the room name. */ uint16_t room_name_len GNUNET_PACKED; /** * For alignment (should be zero). */ uint16_t reserved GNUNET_PACKED; uint32_t reserved2 GNUNET_PACKED; /** * Public key of the joining member. */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; }; /** * Message send by server to client to indicate joining of another room member. * This struct is followed by the serialized ECRS MetaData describing the new * member. */ struct JoinNotificationMessage { /** * Message type will be GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION */ struct GNUNET_MessageHeader header; /** * Options. Set to all options that the new user is willing to * process. For example, if the client does not want to receive * anonymous or OTR messages but is willing to generate * acknowledgements and receive private messages, this should be set * to GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED. */ uint32_t msg_options GNUNET_PACKED; /** * Public key of the new user. */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; }; /** * Message send by server to client to indicate leaving of another room member. */ struct LeaveNotificationMessage { /** * Message type will be GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION */ struct GNUNET_MessageHeader header; /** * Reserved (for alignment). */ uint32_t reserved GNUNET_PACKED; /** * Who is leaving? */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded user; }; /** * Peer-to-peer messages */ /** * Message send by one peer to another to indicate joining of another room * member. This struct is followed by the room name and then the serialized * ECRS MetaData describing the new member. */ struct P2PJoinNotificationMessage { /** * Message type will be GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION */ struct GNUNET_MessageHeader header; /** * Options. Set all options that this client is willing to receive. * For example, if the client does not want to receive anonymous or * OTR messages but is willing to generate acknowledgements and * receive private messages, this should be set to * GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED. */ uint32_t msg_options GNUNET_PACKED; /** * Length of the room name. */ uint16_t room_name_len GNUNET_PACKED; /** * Reserved (should be zero). */ uint16_t reserved GNUNET_PACKED; uint32_t reserved2 GNUNET_PACKED; /** * Public key of the joining member. */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; }; /** * Message send by one peer to another to indicate leaving of another room * member. */ struct P2PLeaveNotificationMessage { /** * Message type will be GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION */ struct GNUNET_MessageHeader header; /** * Reserved (for alignment). */ uint32_t reserved GNUNET_PACKED; /** * Who is leaving? */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded user; }; /** * Message send by one peer to another to indicate receiving of a chat message. * This struct is followed by the room name (only if the message is anonymous) * and then the remaining bytes are the actual text message. If the mesasge is * private, then the text is encrypted, otherwise it's plaintext. */ struct P2PReceiveNotificationMessage { /** * Message type will be GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION */ struct GNUNET_MessageHeader header; /** * Message options, see GNUNET_CHAT_MsgOptions. */ uint32_t msg_options GNUNET_PACKED; /** * Sequence number of the message (unique per sender). */ uint32_t sequence_number GNUNET_PACKED; /** * Length of the room name. This is only used for anonymous messages. */ uint16_t room_name_len GNUNET_PACKED; /** * Reserved (for alignment). */ uint16_t reserved GNUNET_PACKED; /** * Timestamp of the message. */ struct GNUNET_TIME_AbsoluteNBO timestamp; /** * Hash of the public key of the pseudonym of the sender of the message * Should be all zeros for anonymous. */ GNUNET_HashCode sender; /** * Who should receive this message? Set to all zeros for "everyone". */ GNUNET_HashCode target; /** * The encrypted session key. */ struct GNUNET_CRYPTO_RsaEncryptedData encrypted_key; }; /** * Receipt sent from one peer to another to confirm delivery of a chat message. */ struct P2PConfirmationReceiptMessage { /** * Message type will be GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT */ struct GNUNET_MessageHeader header; /** * For alignment (should be zero). */ uint32_t reserved GNUNET_PACKED; /** * Signature confirming receipt. Signature covers everything from header * through content. */ struct GNUNET_CRYPTO_RsaSignature signature; /** * What is being signed and why? */ struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; /** * Sequence number of the original message. */ uint32_t msg_sequence_number GNUNET_PACKED; /** * Sequence number of the receipt. */ uint32_t sequence_number GNUNET_PACKED; /** * Time of receipt. */ struct GNUNET_TIME_AbsoluteNBO timestamp; /** * Who is confirming the receipt? */ GNUNET_HashCode target; /** * Who is the author of the chat message? */ GNUNET_HashCode author; /** * Hash of the (possibly encrypted) content. */ GNUNET_HashCode content; }; GNUNET_NETWORK_STRUCT_END #endif /* end of chat.h */ gnunet-0.9.3/src/chat/gnunet-chat.c0000644000175000017500000005056511760502551014050 00000000000000/* This file is part of GNUnet. (C) 2007, 2008, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file chat/gnunet-chat.c * @brief Minimal chat command line tool * @author Christian Grothoff * @author Nathan Evans * @author Vitaly Minko */ #include "platform.h" #include "gnunet_getopt_lib.h" #include "gnunet_program_lib.h" #include "gnunet_chat_service.h" #include static int ret; static const struct GNUNET_CONFIGURATION_Handle *cfg; static char *nickname; static char *room_name; static struct GNUNET_CONTAINER_MetaData *meta; static struct GNUNET_CHAT_Room *room; static GNUNET_SCHEDULER_TaskIdentifier handle_cmd_task; typedef int (*ActionFunction)(const char *argumetns, const void *xtra); struct ChatCommand { const char *command; ActionFunction Action; const char *helptext; }; struct UserList { struct UserList *next; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; int ignored; }; static struct UserList *users; static void free_user_list () { struct UserList *next; while (NULL != users) { next = users->next; GNUNET_free (users); users = next; } } static int do_help (const char *args, const void *xtra); /** * Callback used for notification that we have joined the room. * * @param cls closure * @return GNUNET_OK */ static int join_cb (void *cls) { FPRINTF (stdout, "%s", _("Joined\n")); return GNUNET_OK; } /** * Callback used for notification about incoming messages. * * @param cls closure, NULL * @param room in which room was the message received? * @param sender what is the ID of the sender? (maybe NULL) * @param member_info information about the joining member * @param message the message text * @param timestamp time when the member joined * @param options options for the message * @return GNUNET_OK to accept the message now, GNUNET_NO to * accept (but user is away), GNUNET_SYSERR to signal denied delivery */ static int receive_cb (void *cls, struct GNUNET_CHAT_Room *room, const GNUNET_HashCode * sender, const struct GNUNET_CONTAINER_MetaData *member_info, const char *message, struct GNUNET_TIME_Absolute timestamp, enum GNUNET_CHAT_MsgOptions options) { char *non_unique_nick; char *nick; int nick_is_a_dup; char *time; const char *fmt; if (NULL == sender) nick = GNUNET_strdup (_("anonymous")); else { if (GNUNET_OK != GNUNET_PSEUDONYM_get_info (cfg, sender, NULL, NULL, &non_unique_nick, &nick_is_a_dup) || (nick_is_a_dup == GNUNET_YES)) { GNUNET_free (non_unique_nick); non_unique_nick = GNUNET_strdup (_("anonymous")); } nick = GNUNET_PSEUDONYM_name_uniquify (cfg, sender, non_unique_nick, NULL); GNUNET_free (non_unique_nick); } fmt = NULL; switch ((int) options) { case GNUNET_CHAT_MSG_OPTION_NONE: case GNUNET_CHAT_MSG_ANONYMOUS: fmt = _("(%s) `%s' said: %s\n"); break; case GNUNET_CHAT_MSG_PRIVATE: fmt = _("(%s) `%s' said to you: %s\n"); break; case GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ANONYMOUS: fmt = _("(%s) `%s' said to you: %s\n"); break; case GNUNET_CHAT_MSG_AUTHENTICATED: fmt = _("(%s) `%s' said for sure: %s\n"); break; case GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_AUTHENTICATED: fmt = _("(%s) `%s' said to you for sure: %s\n"); break; case GNUNET_CHAT_MSG_ACKNOWLEDGED: fmt = _("(%s) `%s' was confirmed that you received: %s\n"); break; case GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED: fmt = _("(%s) `%s' was confirmed that you and only you received: %s\n"); break; case GNUNET_CHAT_MSG_AUTHENTICATED | GNUNET_CHAT_MSG_ACKNOWLEDGED: fmt = _("(%s) `%s' was confirmed that you received from him or her: %s\n"); break; case GNUNET_CHAT_MSG_AUTHENTICATED | GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED: fmt = _ ("(%s) `%s' was confirmed that you and only you received from him or her: %s\n"); break; case GNUNET_CHAT_MSG_OFF_THE_RECORD: fmt = _("(%s) `%s' said off the record: %s\n"); break; default: fmt = _("(%s) <%s> said using an unknown message type: %s\n"); break; } time = GNUNET_STRINGS_absolute_time_to_string (timestamp); FPRINTF (stdout, fmt, time, nick, message); GNUNET_free (nick); GNUNET_free (time); return GNUNET_OK; } /** * Callback used for message delivery confirmations. * * @param cls closure, NULL * @param room in which room was the message received? * @param orig_seq_number sequence number of the original message * @param timestamp when was the message received? * @param receiver who is confirming the receipt? * @return GNUNET_OK to continue, GNUNET_SYSERR to refuse processing further * confirmations from anyone for this message */ static int confirmation_cb (void *cls, struct GNUNET_CHAT_Room *room, uint32_t orig_seq_number, struct GNUNET_TIME_Absolute timestamp, const GNUNET_HashCode * receiver) { char *nick; char *unique_nick; int nick_is_a_dup; if (GNUNET_OK != GNUNET_PSEUDONYM_get_info (cfg, receiver, NULL, NULL, &nick, &nick_is_a_dup) || (nick_is_a_dup == GNUNET_YES)) { GNUNET_free (nick); nick = GNUNET_strdup (_("anonymous")); } unique_nick = GNUNET_PSEUDONYM_name_uniquify (cfg, receiver, nick, NULL); GNUNET_free (nick); FPRINTF (stdout, _("'%s' acknowledged message #%d\n"), unique_nick, orig_seq_number); GNUNET_free (unique_nick); return GNUNET_OK; } /** * Callback used for notification that another room member has joined or left. * * @param cls closure (not used) * @param member_info will be non-null if the member is joining, NULL if he is * leaving * @param member_id hash of public key of the user (for unique identification) * @param options what types of messages is this member willing to receive? * @return GNUNET_OK */ static int member_list_cb (void *cls, const struct GNUNET_CONTAINER_MetaData *member_info, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *member_id, enum GNUNET_CHAT_MsgOptions options) { char *nick; char *non_unique_nick; int nick_is_a_dup; GNUNET_HashCode id; struct UserList *pos; struct UserList *prev; GNUNET_CRYPTO_hash (member_id, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &id); if (GNUNET_OK != GNUNET_PSEUDONYM_get_info (cfg, &id, NULL, NULL, &non_unique_nick, &nick_is_a_dup) || (nick_is_a_dup == GNUNET_YES)) { GNUNET_free (non_unique_nick); non_unique_nick = GNUNET_strdup (_("anonymous")); } nick = GNUNET_PSEUDONYM_name_uniquify (cfg, &id, non_unique_nick, NULL); GNUNET_free (non_unique_nick); FPRINTF (stdout, member_info != NULL ? _("`%s' entered the room\n") : _("`%s' left the room\n"), nick); GNUNET_free (nick); if (NULL != member_info) { /* user joining */ pos = GNUNET_malloc (sizeof (struct UserList)); pos->next = users; pos->pkey = *member_id; pos->ignored = GNUNET_NO; users = pos; } else { /* user leaving */ prev = NULL; pos = users; while ((NULL != pos) && (0 != memcmp (&pos->pkey, member_id, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))) { prev = pos; pos = pos->next; } if (NULL == pos) { GNUNET_break (0); } else { if (NULL == prev) users = pos->next; else prev->next = pos->next; GNUNET_free (pos); } } return GNUNET_OK; } static int do_join (const char *arg, const void *xtra) { char *my_name; int my_name_is_a_dup; GNUNET_HashCode me; if (arg[0] == '#') arg++; /* ignore first hash */ GNUNET_CHAT_leave_room (room); free_user_list (); GNUNET_free (room_name); room_name = GNUNET_strdup (arg); room = GNUNET_CHAT_join_room (cfg, nickname, meta, room_name, -1, &join_cb, NULL, &receive_cb, NULL, &member_list_cb, NULL, &confirmation_cb, NULL, &me); if (NULL == room) { FPRINTF (stdout, "%s", _("Could not change username\n")); return GNUNET_SYSERR; } if ((GNUNET_OK != GNUNET_PSEUDONYM_get_info (cfg, &me, NULL, NULL, &my_name, &my_name_is_a_dup)) || (my_name_is_a_dup == GNUNET_YES)) { GNUNET_free (my_name); my_name = GNUNET_strdup (_("anonymous")); } /* Don't uniquify our own name - other people will have a different * suffix for our own name anyway. */ FPRINTF (stdout, _("Joining room `%s' as user `%s'...\n"), room_name, my_name); GNUNET_free (my_name); return GNUNET_OK; } static int do_nick (const char *msg, const void *xtra) { char *my_name; int my_name_is_a_dup; GNUNET_HashCode me; GNUNET_CHAT_leave_room (room); free_user_list (); GNUNET_free (nickname); GNUNET_CONTAINER_meta_data_destroy (meta); nickname = GNUNET_strdup (msg); meta = GNUNET_CONTAINER_meta_data_create (); GNUNET_CONTAINER_meta_data_insert (meta, "", EXTRACTOR_METATYPE_TITLE, EXTRACTOR_METAFORMAT_UTF8, "text/plain", nickname, strlen (nickname) + 1); room = GNUNET_CHAT_join_room (cfg, nickname, meta, room_name, -1, &join_cb, NULL, &receive_cb, NULL, &member_list_cb, NULL, &confirmation_cb, NULL, &me); if (NULL == room) { FPRINTF (stdout, "%s", _("Could not change username\n")); return GNUNET_SYSERR; } if ((GNUNET_OK != GNUNET_PSEUDONYM_get_info (cfg, &me, NULL, NULL, &my_name, &my_name_is_a_dup)) || (my_name_is_a_dup == GNUNET_YES)) { GNUNET_free (my_name); my_name = GNUNET_strdup (_("anonymous")); } FPRINTF (stdout, _("Changed username to `%s'\n"), my_name); GNUNET_free (my_name); return GNUNET_OK; } static int do_names (const char *msg, const void *xtra) { char *name; char *unique_name; int name_is_a_dup; struct UserList *pos; GNUNET_HashCode pid; FPRINTF (stdout, _("Users in room `%s': "), room_name); pos = users; while (NULL != pos) { GNUNET_CRYPTO_hash (&pos->pkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &pid); if (GNUNET_OK != GNUNET_PSEUDONYM_get_info (cfg, &pid, NULL, NULL, &name, &name_is_a_dup) || (name_is_a_dup == GNUNET_YES)) { GNUNET_free (name); name = GNUNET_strdup (_("anonymous")); } unique_name = GNUNET_PSEUDONYM_name_uniquify (cfg, &pid, name, NULL); GNUNET_free (name); FPRINTF (stdout, "`%s' ", unique_name); GNUNET_free (unique_name); pos = pos->next; } FPRINTF (stdout, "%s", "\n"); return GNUNET_OK; } static int do_send (const char *msg, const void *xtra) { uint32_t seq; GNUNET_CHAT_send_message (room, msg, GNUNET_CHAT_MSG_OPTION_NONE, NULL, &seq); return GNUNET_OK; } static int do_send_pm (const char *msg, const void *xtra) { char *user; GNUNET_HashCode uid; GNUNET_HashCode pid; uint32_t seq; struct UserList *pos; if (NULL == strstr (msg, " ")) { FPRINTF (stderr, "%s", _("Syntax: /msg USERNAME MESSAGE")); return GNUNET_OK; } user = GNUNET_strdup (msg); strstr (user, " ")[0] = '\0'; msg += strlen (user) + 1; if (GNUNET_OK != GNUNET_PSEUDONYM_name_to_id (cfg, user, &uid)) { FPRINTF (stderr, _("Unknown user `%s'. Make sure you specify its numeric suffix, if any.\n"), user); GNUNET_free (user); return GNUNET_OK; } pos = users; while (NULL != pos) { GNUNET_CRYPTO_hash (&pos->pkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &pid); if (0 == memcmp (&pid, &uid, sizeof (GNUNET_HashCode))) break; pos = pos->next; } if (NULL == pos) { FPRINTF (stderr, _("User `%s' is currently not in the room!\n"), user); GNUNET_free (user); return GNUNET_OK; } GNUNET_CHAT_send_message (room, msg, GNUNET_CHAT_MSG_PRIVATE, &pos->pkey, &seq); GNUNET_free (user); return GNUNET_OK; } static int do_send_sig (const char *msg, const void *xtra) { uint32_t seq; GNUNET_CHAT_send_message (room, msg, GNUNET_CHAT_MSG_AUTHENTICATED, NULL, &seq); return GNUNET_OK; } static int do_send_ack (const char *msg, const void *xtra) { uint32_t seq; GNUNET_CHAT_send_message (room, msg, GNUNET_CHAT_MSG_ACKNOWLEDGED, NULL, &seq); return GNUNET_OK; } static int do_send_anonymous (const char *msg, const void *xtra) { uint32_t seq; GNUNET_CHAT_send_message (room, msg, GNUNET_CHAT_MSG_ANONYMOUS, NULL, &seq); return GNUNET_OK; } static int do_quit (const char *args, const void *xtra) { return GNUNET_SYSERR; } static int do_unknown (const char *msg, const void *xtra) { FPRINTF (stderr, _("Unknown command `%s'\n"), msg); return GNUNET_OK; } /** * List of supported IRC commands. The order matters! */ static struct ChatCommand commands[] = { {"/join ", &do_join, gettext_noop ("Use `/join #roomname' to join a chat room. Joining a room will cause you" " to leave the current room")}, {"/nick ", &do_nick, gettext_noop ("Use `/nick nickname' to change your nickname. This will cause you to" " leave the current room and immediately rejoin it with the new name.")}, {"/msg ", &do_send_pm, gettext_noop ("Use `/msg nickname message' to send a private message to the specified" " user")}, {"/notice ", &do_send_pm, gettext_noop ("The `/notice' command is an alias for `/msg'")}, {"/query ", &do_send_pm, gettext_noop ("The `/query' command is an alias for `/msg'")}, {"/sig ", &do_send_sig, gettext_noop ("Use `/sig message' to send a signed public message")}, {"/ack ", &do_send_ack, gettext_noop ("Use `/ack message' to require signed acknowledgment of the message")}, {"/anonymous ", &do_send_anonymous, gettext_noop ("Use `/anonymous message' to send a public anonymous message")}, {"/anon ", &do_send_anonymous, gettext_noop ("The `/anon' command is an alias for `/anonymous'")}, {"/quit", &do_quit, gettext_noop ("Use `/quit' to terminate gnunet-chat")}, {"/leave", &do_quit, gettext_noop ("The `/leave' command is an alias for `/quit'")}, {"/names", &do_names, gettext_noop ("Use `/names' to list all of the current members in the chat room")}, {"/help", &do_help, gettext_noop ("Use `/help command' to get help for a specific command")}, /* Add standard commands: * /whois (print metadata), * /ignore (set flag, check on receive!) */ /* the following three commands must be last! */ {"/", &do_unknown, NULL}, {"", &do_send, NULL}, {NULL, NULL, NULL}, }; static int do_help (const char *args, const void *xtra) { int i; i = 0; while ((NULL != args) && (0 != strlen (args)) && (commands[i].Action != &do_help)) { if (0 == strncasecmp (&args[1], &commands[i].command[1], strlen (args) - 1)) { FPRINTF (stdout, "%s\n", gettext (commands[i].helptext)); return GNUNET_OK; } i++; } i = 0; FPRINTF (stdout, "%s", "Available commands:"); while (commands[i].Action != &do_help) { FPRINTF (stdout, " %s", gettext (commands[i].command)); i++; } FPRINTF (stdout, "%s", "\n"); FPRINTF (stdout, "%s\n", gettext (commands[i].helptext)); return GNUNET_OK; } static void do_stop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_CHAT_leave_room (room); if (handle_cmd_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (handle_cmd_task); handle_cmd_task = GNUNET_SCHEDULER_NO_TASK; } free_user_list (); GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_free (room_name); GNUNET_free (nickname); } void handle_command (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { char message[MAX_MESSAGE_LENGTH + 1]; int i; /* read message from command line and handle it */ memset (message, 0, MAX_MESSAGE_LENGTH + 1); if (NULL == fgets (message, MAX_MESSAGE_LENGTH, stdin)) goto next; if (strlen (message) == 0) goto next; if (message[strlen (message) - 1] == '\n') message[strlen (message) - 1] = '\0'; if (strlen (message) == 0) goto next; i = 0; while ((NULL != commands[i].command) && (0 != strncasecmp (commands[i].command, message, strlen (commands[i].command)))) i++; if (GNUNET_OK != commands[i].Action (&message[strlen (commands[i].command)], NULL)) goto out; next: handle_cmd_task = GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100), GNUNET_SCHEDULER_PRIORITY_UI, &handle_command, NULL); return; out: handle_cmd_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_SCHEDULER_shutdown (); } /** * Main function that will be run by the scheduler. * * @param cls closure, NULL * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param c configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { GNUNET_HashCode me; char *my_name; int my_name_is_a_dup; cfg = c; /* check arguments */ if (NULL == nickname) { FPRINTF (stderr, "%s", _("You must specify a nickname\n")); ret = -1; return; } if (NULL == room_name) room_name = GNUNET_strdup ("gnunet"); meta = GNUNET_CONTAINER_meta_data_create (); GNUNET_CONTAINER_meta_data_insert (meta, "", EXTRACTOR_METATYPE_TITLE, EXTRACTOR_METAFORMAT_UTF8, "text/plain", nickname, strlen (nickname) + 1); room = GNUNET_CHAT_join_room (cfg, nickname, meta, room_name, -1, &join_cb, NULL, &receive_cb, NULL, &member_list_cb, NULL, &confirmation_cb, NULL, &me); if (NULL == room) { FPRINTF (stderr, _("Failed to join room `%s'\n"), room_name); GNUNET_free (room_name); GNUNET_free (nickname); GNUNET_CONTAINER_meta_data_destroy (meta); ret = -1; return; } if ((GNUNET_OK != GNUNET_PSEUDONYM_get_info (cfg, &me, NULL, NULL, &my_name, &my_name_is_a_dup)) || (my_name_is_a_dup == GNUNET_YES)) { GNUNET_free (my_name); my_name = GNUNET_strdup (_("anonymous")); } FPRINTF (stdout, _("Joining room `%s' as user `%s'...\n"), room_name, my_name); GNUNET_free (my_name); handle_cmd_task = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_UI, &handle_command, NULL); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &do_stop_task, NULL); } /** * The main function to chat via GNUnet. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { int flags; static const struct GNUNET_GETOPT_CommandLineOption options[] = { {'n', "nick", "NAME", gettext_noop ("set the nickname to use (required)"), 1, &GNUNET_GETOPT_set_string, &nickname}, {'r', "room", "NAME", gettext_noop ("set the chat room to join"), 1, &GNUNET_GETOPT_set_string, &room_name}, GNUNET_GETOPT_OPTION_END }; #ifndef WINDOWS flags = fcntl (0, F_GETFL, 0); flags |= O_NONBLOCK; fcntl (0, F_SETFL, flags); #endif return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-chat", gettext_noop ("Join a chat on GNUnet."), options, &run, NULL)) ? ret : 1; } /* end of gnunet-chat.c */ gnunet-0.9.3/src/nat/0000755000175000017500000000000011763406750011406 500000000000000gnunet-0.9.3/src/nat/test_nat_test.c0000644000175000017500000000636411760502551014354 00000000000000/* This file is part of GNUnet. (C) 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * Testcase for the NAT testing code. * * @file nat/test_nat_test.c * @brief Testcase for NAT testing functions * @author Christian Grothoff */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_util_lib.h" #include "gnunet_nat_lib.h" /** * Time to wait before stopping NAT test, in seconds */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) static int ret = 1; static struct GNUNET_NAT_Test *tst; static GNUNET_SCHEDULER_TaskIdentifier end; static void end_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_NAT_test_stop (tst); } static void report_success (void *cls, int success) { GNUNET_assert (GNUNET_OK == success); ret = 0; GNUNET_SCHEDULER_cancel (end); end = GNUNET_SCHEDULER_add_now (&end_test, NULL); } /** * Main function run with scheduler. */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { tst = GNUNET_NAT_test_start (cfg, GNUNET_YES, 1285, 1285, &report_success, NULL); if (NULL == tst) return; end = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_test, NULL); } int main (int argc, char *const argv[]) { struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; struct GNUNET_OS_Process *gns; int nat_res; char *const argv_prog[] = { "test-nat-test", "-c", "test_nat_test_data.conf", NULL }; GNUNET_log_setup ("test-nat-test", "WARNING", NULL); nat_res = GNUNET_OS_check_helper_binary ("gnunet-nat-server"); if (GNUNET_SYSERR == nat_res) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Cannot run NAT test: `%s' file not found\n", "gnunet-nat-server"); return 0; } gns = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-nat-server", "gnunet-nat-server", "-c", "test_nat_test_data.conf", "12345", NULL); GNUNET_assert (NULL != gns); GNUNET_PROGRAM_run (3, argv_prog, "test-nat-test", "nohelp", options, &run, NULL); GNUNET_break (0 == GNUNET_OS_process_kill (gns, SIGTERM)); GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (gns)); GNUNET_OS_process_destroy (gns); if (0 != ret) fprintf (stderr, "NAT test failed to report success\n"); return ret; } /* end of test_nat_test.c */ gnunet-0.9.3/src/nat/test_nat_mini.c0000644000175000017500000000705311760502551014325 00000000000000/* This file is part of GNUnet. (C) 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * Testcase for port redirection and public IP address retrieval. * This test never fails, because there need to be a NAT box set up for tha * * @file nat/test_nat_mini.c * @brief Testcase for NAT library - mini * @author Christian Grothoff * * TODO: actually use ARM to start resolver service to make DNS work! */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_util_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_nat_lib.h" #define VERBOSE GNUNET_NO /* Time to wait before stopping NAT, in seconds */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) /** * Function called on each address that the NAT service * believes to be valid for the transport. */ static void addr_callback (void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen) { fprintf (stderr, "Address changed: %s `%s' (%u bytes)\n", add_remove == GNUNET_YES ? "added" : "removed", GNUNET_a2s (addr, addrlen), (unsigned int) addrlen); } /** * Function that terminates the test. */ static void stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_NAT_MiniHandle *mini = cls; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stopping NAT and quitting...\n"); GNUNET_NAT_mini_map_stop (mini); } #define PORT 10000 /** * Main function run with scheduler. */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_NAT_MiniHandle *mini; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Requesting NAT redirection for port %u...\n", PORT); mini = GNUNET_NAT_mini_map_start (PORT, GNUNET_YES /* tcp */ , &addr_callback, NULL); if (NULL == mini) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Could not start UPnP interaction\n"); return; } GNUNET_SCHEDULER_add_delayed (TIMEOUT, &stop, mini); } int main (int argc, char *const argv[]) { struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; char *const argv_prog[] = { "test-nat-mini", "-c", "test_nat_data.conf", "-L", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL }; GNUNET_log_setup ("test-nat-mini", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "UPnP test for NAT library, timeout set to %d seconds\n", TIMEOUT); GNUNET_PROGRAM_run (5, argv_prog, "test-nat-mini", "nohelp", options, &run, NULL); return 0; } /* end of test_nat_mini.c */ gnunet-0.9.3/src/nat/Makefile.am0000644000175000017500000000427311654545772013377 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols NATBIN = gnunet-helper-nat-server gnunet-helper-nat-client NATSERVER = gnunet-helper-nat-server-windows.c NATCLIENT = gnunet-helper-nat-client-windows.c endif pkgcfgdir= $(pkgdatadir)/config.d/ dist_pkgcfg_DATA = \ nat.conf if ENABLE_TEST_RUN nattest = $(bindir)/gnunet-nat-server endif if LINUX NATBIN = gnunet-helper-nat-server gnunet-helper-nat-client NATSERVER = gnunet-helper-nat-server.c NATCLIENT = gnunet-helper-nat-client.c install-exec-hook: $(SUDO_BINARY) chown root:root $(bindir)/gnunet-helper-nat-server $(bindir)/gnunet-helper-nat-client $(nattest) || true $(SUDO_BINARY) chmod u+s $(bindir)/gnunet-helper-nat-server $(bindir)/gnunet-helper-nat-client $(nattest) || true else install-exec-hook: endif bin_PROGRAMS = \ gnunet-nat-server \ $(NATBIN) gnunet_nat_server_SOURCES = \ gnunet-nat-server.c nat.h gnunet_nat_server_LDADD = \ $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la gnunet_nat_server_DEPENDENCIES = \ libgnunetnat.la gnunet_helper_nat_server_SOURCES = \ $(NATSERVER) gnunet_helper_nat_client_SOURCES = \ $(NATCLIENT) if USE_COVERAGE AM_CFLAGS = -fprofile-arcs -ftest-coverage endif lib_LTLIBRARIES = libgnunetnat.la libgnunetnat_la_SOURCES = \ nat.c nat.h \ nat_test.c \ nat_mini.c libgnunetnat_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) @EXT_LIBS@ libgnunetnat_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 0:0:0 check_PROGRAMS = \ test_nat \ test_nat_mini \ test_nat_test if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) endif test_nat_SOURCES = \ test_nat.c test_nat_LDADD = \ $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la test_nat_mini_SOURCES = \ test_nat_mini.c test_nat_mini_LDADD = \ $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la test_nat_test_SOURCES = \ test_nat_test.c test_nat_test_LDADD = \ $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ test_nat_data.conf \ test_nat_test_data.conf gnunet-0.9.3/src/nat/test_nat_data.conf0000644000175000017500000000530411760460614015005 00000000000000[PATHS] SERVICEHOME = /tmp/nat-test # SERVICEHOME = /var/lib/gnunet/ # DEFAULTCONFIG = /etc/gnunet.conf # If 'DEFAULTCONFIG' is not defined, the current # configuration file is assumed to be the default, # which is what we want by default... [gnunetd] HOSTKEY = $SERVICEHOME/.hostkey [TESTING] WEAKRANDOM = NO [client] HOME = $SERVICEHOME [nat] # Are we behind NAT? BEHIND_NAT = YES # Is the NAT hole-punched? PUNCHED_NAT = NO # Disable UPNP by default until it gets cleaner! ENABLE_UPNP = YES # Use addresses from the local network interfaces (inluding loopback, but also others) USE_LOCALADDR = YES # External IP address of the NAT box (if known); IPv4 dotted-decimal ONLY at this time (should allow DynDNS!) # normal interface IP address for non-NATed peers; # possibly auto-detected (using UPnP) if possible if not specified # EXTERNAL_ADDRESS = # Should we use ICMP-based NAT traversal to try connect to NATed peers # or, if we are behind NAT, to allow connections to us? ENABLE_ICMP_CLIENT = NO ENABLE_ICMP_SERVER = NO # IP address of the interface connected to the NAT box; IPv4 dotted-decimal ONLY; # normal interface IP address for non-NATed peers; # likely auto-detected (via interface list) if not specified (!) # INTERNAL_ADDRESS = # Disable IPv6 support DISABLEV6 = NO [arm] PORT = 2087 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-arm ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DEFAULTSERVICES = topology hostlist UNIXPATH = /tmp/gnunet-service-arm.sock UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES # GLOBAL_POSTFIX = -l $SERVICEHOME/{}-logs # GLOBAL_PREFIX = # USERNAME = # MAXBUF = # TIMEOUT = # DISABLEV6 = # BINDTO = # REJECT_FROM = # REJECT_FROM6 = # PREFIX = [statistics] AUTOSTART = YES PORT = 2088 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-statistics ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-statistics.sock UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES # DISABLE_SOCKET_FORWARDING = NO # USERNAME = # MAXBUF = # TIMEOUT = # DISABLEV6 = # BINDTO = # REJECT_FROM = # REJECT_FROM6 = # PREFIX = [resolver] AUTOSTART = YES PORT = 2089 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-resolver ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-resolver.sock UNIX_MATCH_UID = NO UNIX_MATCH_GID = NO # DISABLE_SOCKET_FORWARDING = NO # USERNAME = # MAXBUF = # TIMEOUT = # DISABLEV6 = # BINDTO = # REJECT_FROM = # REJECT_FROM6 = # PREFIX = [peerinfo] AUTOSTART = NO [transport] AUTOSTART = NO [core] AUTOSTART = NO [datastore] AUTOSTART = NO [fs] AUTOSTART = NO [dht] AUTOSTART = NO [mesh] AUTOSTART = NO [nse] AUTOSTART = NO gnunet-0.9.3/src/nat/gnunet-nat-server.c0000644000175000017500000002071511760502551015054 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/nat/gnunet-nat-server.c * @brief Daemon to run on 'gnunet.org' to help test NAT traversal code * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_nat_lib.h" #include "gnunet_protocols.h" #include "nat.h" /** * Our server. */ static struct GNUNET_SERVER_Handle *server; /** * Our configuration. */ static const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Try contacting the peer using autonomous * NAT traveral method. * * @param dst_ipv4 IPv4 address to send the fake ICMP message * @param dport destination port to include in ICMP message * @param is_tcp mark for TCP (GNUNET_YES) or UDP (GNUNET_NO) */ static void try_anat (uint32_t dst_ipv4, uint16_t dport, int is_tcp) { struct GNUNET_NAT_Handle *h; struct sockaddr_in sa; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking for connection reversal with %x and code %u\n", (unsigned int) dst_ipv4, (unsigned int) dport); h = GNUNET_NAT_register (cfg, is_tcp, dport, 0, NULL, NULL, NULL, NULL, NULL); memset (&sa, 0, sizeof (sa)); sa.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = sizeof (sa); #endif sa.sin_addr.s_addr = dst_ipv4; GNUNET_NAT_run_client (h, &sa); GNUNET_NAT_unregister (h); } /** * Closure for 'tcp_send'. */ struct TcpContext { /** * TCP socket. */ struct GNUNET_NETWORK_Handle *s; /** * Data to transmit. */ uint16_t data; }; /** * Task called by the scheduler once we can do the TCP send * (or once we failed to connect...). * * @param cls the 'struct TcpContext' * @param tc scheduler context */ static void tcp_send (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct TcpContext *ctx = cls; if ((NULL != tc->write_ready) && (GNUNET_NETWORK_fdset_isset (tc->write_ready, ctx->s))) { if (-1 == GNUNET_NETWORK_socket_send (ctx->s, &ctx->data, sizeof (ctx->data))) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send"); } GNUNET_NETWORK_socket_shutdown (ctx->s, SHUT_RDWR); } GNUNET_NETWORK_socket_close (ctx->s); GNUNET_free (ctx); } /** * Try to send 'data' to the * IP 'dst_ipv4' at port 'dport' via TCP. * * @param dst_ipv4 target IP * @param dport target port * @param data data to send */ static void try_send_tcp (uint32_t dst_ipv4, uint16_t dport, uint16_t data) { struct GNUNET_NETWORK_Handle *s; struct sockaddr_in sa; struct TcpContext *ctx; s = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); if (NULL == s) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket"); return; } memset (&sa, 0, sizeof (sa)); sa.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = sizeof (sa); #endif sa.sin_addr.s_addr = dst_ipv4; sa.sin_port = htons (dport); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending TCP message to `%s'\n", GNUNET_a2s ((struct sockaddr *) &sa, sizeof (sa))); if ((GNUNET_OK != GNUNET_NETWORK_socket_connect (s, (const struct sockaddr *) &sa, sizeof (sa))) && (errno != EINPROGRESS)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "connect"); GNUNET_NETWORK_socket_close (s); return; } ctx = GNUNET_malloc (sizeof (struct TcpContext)); ctx->s = s; ctx->data = data; GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_SECONDS, s, &tcp_send, ctx); } /** * Try to send 'data' to the * IP 'dst_ipv4' at port 'dport' via UDP. * * @param dst_ipv4 target IP * @param dport target port * @param data data to send */ static void try_send_udp (uint32_t dst_ipv4, uint16_t dport, uint16_t data) { struct GNUNET_NETWORK_Handle *s; struct sockaddr_in sa; s = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0); if (NULL == s) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket"); return; } memset (&sa, 0, sizeof (sa)); sa.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = sizeof (sa); #endif sa.sin_addr.s_addr = dst_ipv4; sa.sin_port = htons (dport); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending UDP packet to `%s'\n", GNUNET_a2s ((struct sockaddr *) &sa, sizeof (sa))); if (-1 == GNUNET_NETWORK_socket_sendto (s, &data, sizeof (data), (const struct sockaddr *) &sa, sizeof (sa))) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "sendto"); GNUNET_NETWORK_socket_close (s); } /** * We've received a request to probe a NAT * traversal. Do it. * * @param cls unused * @param client handle to client (we always close) * @param msg message with details about what to test */ static void test (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *msg) { const struct GNUNET_NAT_TestMessage *tm; uint16_t dport; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received test request\n"); tm = (const struct GNUNET_NAT_TestMessage *) msg; dport = ntohs (tm->dport); if (0 == dport) try_anat (tm->dst_ipv4, ntohs (tm->data), (int) ntohl (tm->is_tcp)); else if (GNUNET_YES == ntohl (tm->is_tcp)) try_send_tcp (tm->dst_ipv4, dport, tm->data); else try_send_udp (tm->dst_ipv4, dport, tm->data); GNUNET_SERVER_receive_done (client, GNUNET_NO); } /** * Task run during shutdown. * * @param cls unused * @param tc scheduler context */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_SERVER_destroy (server); server = NULL; } /** * Main function that will be run. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param c configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { static const struct GNUNET_SERVER_MessageHandler handlers[] = { {&test, NULL, GNUNET_MESSAGE_TYPE_NAT_TEST, sizeof (struct GNUNET_NAT_TestMessage)}, {NULL, NULL, 0, 0} }; unsigned int port; struct sockaddr_in in4; struct sockaddr_in6 in6; socklen_t slen[] = { sizeof (in4), sizeof (in6), 0 }; struct sockaddr *sa[] = { (struct sockaddr *) &in4, (struct sockaddr *) &in6, NULL }; cfg = c; if ((args[0] == NULL) || (1 != SSCANF (args[0], "%u", &port)) || (0 == port) || (65536 <= port)) { FPRINTF (stderr, _ ("Please pass valid port number as the first argument! (got `%s')\n"), args[0]); return; } memset (&in4, 0, sizeof (in4)); memset (&in6, 0, sizeof (in6)); in4.sin_family = AF_INET; in4.sin_port = htons ((uint16_t) port); in6.sin6_family = AF_INET6; in6.sin6_port = htons ((uint16_t) port); #if HAVE_SOCKADDR_IN_SIN_LEN in4.sin_len = sizeof (in4); in6.sin6_len = sizeof (in6); #endif server = GNUNET_SERVER_create (NULL, NULL, (struct sockaddr * const *) sa, slen, GNUNET_TIME_UNIT_SECONDS, GNUNET_YES); GNUNET_SERVER_add_handlers (server, handlers); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); } /** * Main function of gnunet-nat-server. * * @param argc number of command-line arguments * @param argv command line * @return 0 on success, -1 on error */ int main (int argc, char *const argv[]) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "gnunet-nat-server [options] PORT", _("GNUnet NAT traversal test helper daemon"), options, &run, NULL)) return 1; return 0; } /* end of gnunet-nat-server.c */ gnunet-0.9.3/src/nat/nat.conf0000644000175000017500000000277411654545772013000 00000000000000[nat] # Are we behind NAT? BEHIND_NAT = NO # Is the NAT hole-punched? PUNCHED_NAT = NO # Enable UPNP by default? ENABLE_UPNP = NO # Use addresses from the local network interfaces (inluding loopback, but also others) USE_LOCALADDR = YES # Use address obtained from a DNS lookup of our hostname USE_HOSTNAME = NO # External IP address of the NAT box (if known); IPv4 dotted-decimal ONLY at this time (should allow DynDNS!) # normal interface IP address for non-NATed peers; # possibly auto-detected (using UPnP) if possible if not specified # EXTERNAL_ADDRESS = # Should we use ICMP-based NAT traversal to try connect to NATed peers # or, if we are behind NAT, to allow connections to us? ENABLE_ICMP_CLIENT = NO ENABLE_ICMP_SERVER = NO # IP address of the interface connected to the NAT box; IPv4 dotted-decimal ONLY; # normal interface IP address for non-NATed peers; # likely auto-detected (via interface list) if not specified (!) # INTERNAL_ADDRESS = # Disable IPv6 support DISABLEV6 = NO # Do we use addresses from localhost address ranges? (::1, 127.0.0.0/8) RETURN_LOCAL_ADDRESSES = NO # How often do we query the DNS resolver # for our hostname (to get our own IP), in ms HOSTNAME_DNS_FREQUENCY = 1200000 # How often do we iterate over our # network interfaces to check for changes # in our IP address? in ms IFC_SCAN_FREQUENCY = 3000000 # How often do we query the DNS resolver # for our hostname (to get our own IP), in ms DYNDNS_FREQUENCY = 140000 [gnunet-nat-server] HOSTNAME = gnunet.org PORT = 5724 gnunet-0.9.3/src/nat/test_nat_test_data.conf0000644000175000017500000000244111760460614016043 00000000000000[PATHS] SERVICEHOME = /tmp/nat-test # SERVICEHOME = /var/lib/gnunet/ # DEFAULTCONFIG = /etc/gnunet.conf # If 'DEFAULTCONFIG' is not defined, the current # configuration file is assumed to be the default, # which is what we want by default... [gnunet-nat-server] HOSTNAME = localhost PORT = 12345 [nat] # Are we behind NAT? BEHIND_NAT = NO # Is the NAT hole-punched? PUNCHED_NAT = YES # Disable UPNP by default until it gets cleaner! ENABLE_UPNP = NO # Use addresses from the local network interfaces (inluding loopback, but also others) USE_LOCALADDR = YES RETURN_LOCAL_ADDRESSES = YES # External IP address of the NAT box (if known); IPv4 dotted-decimal ONLY at this time (should allow DynDNS!) # normal interface IP address for non-NATed peers; # possibly auto-detected (using UPnP) if possible if not specified # EXTERNAL_ADDRESS = # Should we use ICMP-based NAT traversal to try connect to NATed peers # or, if we are behind NAT, to allow connections to us? ENABLE_ICMP_CLIENT = NO ENABLE_ICMP_SERVER = NO # IP address of the interface connected to the NAT box; IPv4 dotted-decimal ONLY; # normal interface IP address for non-NATed peers; # likely auto-detected (via interface list) if not specified (!) INTERNAL_ADDRESS = 127.0.0.1 # Disable IPv6 support DISABLEV6 = YES [nse] AUTOSTART = NO gnunet-0.9.3/src/nat/test_nat.c0000644000175000017500000001210411760502551013302 00000000000000/* This file is part of GNUnet. (C) 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * Testcase for port redirection and public IP address retrieval. * This test never fails, because there need to be a NAT box set up for that. * So we only get IP address and open the 2086 port using any NAT traversal * method available, wait for 30s, close ports and return. * Have a look at the logs and use NMAP to check that it works with your box. * * @file nat/test_nat.c * @brief Testcase for NAT library * @author Milan Bouchet-Valat * @author Christian Grothoff * * TODO: actually use ARM to start resolver service to make DNS work! */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_util_lib.h" #include "gnunet_program_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_nat_lib.h" /** * Time to wait before stopping NAT, in seconds */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) /** * Function called on each address that the NAT service * believes to be valid for the transport. */ static void addr_callback (void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Address changed: %s `%s' (%u bytes)\n", add_remove == GNUNET_YES ? "added" : "removed", GNUNET_a2s (addr, addrlen), (unsigned int) addrlen); } /** * Function that terminates the test. */ static void stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_NAT_Handle *nat = cls; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stopping NAT and quitting...\n"); GNUNET_NAT_unregister (nat); } struct addr_cls { struct sockaddr *addr; socklen_t addrlen; }; /** * Return the address of the default interface, * or any interface with a valid address if the default is not valid * * @param cls the 'struct addr_cls' * @param name name of the interface * @param isDefault do we think this may be our default interface * @param addr address of the interface * @param addrlen number of bytes in addr * @return GNUNET_OK to continue iterating */ static int process_if (void *cls, const char *name, int isDefault, const struct sockaddr *addr, const struct sockaddr *broadcast_addr, const struct sockaddr *netmask, socklen_t addrlen) { struct addr_cls *data = cls; if (addr == NULL) return GNUNET_OK; GNUNET_free_non_null (data->addr); data->addr = GNUNET_malloc (addrlen); memcpy (data->addr, addr, addrlen); data->addrlen = addrlen; if (isDefault) return GNUNET_SYSERR; return GNUNET_OK; } /** * Main function run with scheduler. */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_NAT_Handle *nat; struct addr_cls data; struct sockaddr *addr; data.addr = NULL; GNUNET_OS_network_interfaces_list (process_if, &data); if (NULL == data.addr) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not find a valid interface address!\n"); exit (GNUNET_SYSERR); } addr = data.addr; GNUNET_assert (addr->sa_family == AF_INET || addr->sa_family == AF_INET6); if (addr->sa_family == AF_INET) ((struct sockaddr_in *) addr)->sin_port = htons (2086); else ((struct sockaddr_in6 *) addr)->sin6_port = htons (2086); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Requesting NAT redirection from address %s...\n", GNUNET_a2s (addr, data.addrlen)); nat = GNUNET_NAT_register (cfg, GNUNET_YES /* tcp */ , 2086, 1, (const struct sockaddr **) &addr, &data.addrlen, &addr_callback, NULL, NULL); GNUNET_free (addr); GNUNET_SCHEDULER_add_delayed (TIMEOUT, &stop, nat); } int main (int argc, char *const argv[]) { struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; char *const argv_prog[] = { "test-nat", "-c", "test_nat_data.conf", NULL }; GNUNET_log_setup ("test-nat", "WARNING", NULL); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Testing NAT library, timeout set to %d seconds\n", TIMEOUT); GNUNET_PROGRAM_run (3, argv_prog, "test-nat", "nohelp", options, &run, NULL); return 0; } /* end of test_nat.c */ gnunet-0.9.3/src/nat/gnunet-helper-nat-server-windows.c0000644000175000017500000003167111760502551020024 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/nat/gnunet-helper-nat-server-windows.c * @brief Windows tool to help bypass NATs using ICMP method * This code will work under W32 only * @author Christian Grothoff * * This program will send ONE ICMP message every 500 ms RAW sockets * to a DUMMY IP address and also listens for ICMP replies. Since * it uses RAW sockets, it must be run as an administrative user. * In order to keep the security risk of the resulting binary * minimal, the program ONLY opens the two RAW sockets with administrative * privileges, then drops them and only then starts to process * command line arguments. The code also does not link against * any shared libraries (except libc) and is strictly minimal * (except for checking for errors). The following list of people * have reviewed this code and considered it safe since the last * modification (if you reviewed it, please have your name added * to the list): * * - Nathan Evans * - Christian Grothoff */ #define _GNU_SOURCE #define FD_SETSIZE 1024 #include #include #include #include #include #include #include #include #include #include #include /** * Should we print some debug output? */ #define VERBOSE 0 /** * Must match IP given in the client. */ #define DUMMY_IP "192.0.2.86" /** * Default Port */ #define NAT_TRAV_PORT 22225 /** * Must match packet ID used by gnunet-helper-nat-client.c */ #define PACKET_ID 256 /** * TTL to use for our outgoing messages. */ #define IPDEFTTL 64 #define ICMP_ECHO 8 #define ICMP_TIME_EXCEEDED 11 /** * How often do we send our ICMP messages to receive replies? */ #define ICMP_SEND_FREQUENCY_MS 500 /** * IPv4 header. */ struct ip_header { /** * Version (4 bits) + Internet header length (4 bits) */ uint8_t vers_ihl; /** * Type of service */ uint8_t tos; /** * Total length */ uint16_t pkt_len; /** * Identification */ uint16_t id; /** * Flags (3 bits) + Fragment offset (13 bits) */ uint16_t flags_frag_offset; /** * Time to live */ uint8_t ttl; /** * Protocol */ uint8_t proto; /** * Header checksum */ uint16_t checksum; /** * Source address */ uint32_t src_ip; /** * Destination address */ uint32_t dst_ip; }; /** * Format of ICMP packet. */ struct icmp_ttl_exceeded_header { uint8_t type; uint8_t code; uint16_t checksum; uint32_t unused; /* followed by original payload */ }; struct icmp_echo_header { uint8_t type; uint8_t code; uint16_t checksum; uint32_t reserved; }; /** * Beginning of UDP packet. */ struct udp_header { uint16_t src_port; uint16_t dst_port; uint16_t length; uint16_t crc; }; /** * Socket we use to receive "fake" ICMP replies. */ static SOCKET icmpsock; /** * Socket we use to send our ICMP requests. */ static SOCKET rawsock; /** * Socket we use to send our UDP requests. */ static SOCKET udpsock; /** * Target "dummy" address. */ static struct in_addr dummy; /** * CRC-16 for IP/ICMP headers. * * @param data what to calculate the CRC over * @param bytes number of bytes in data (must be multiple of 2) * @return the CRC 16. */ static uint16_t calc_checksum (const uint16_t * data, unsigned int bytes) { uint32_t sum; unsigned int i; sum = 0; for (i = 0; i < bytes / 2; i++) sum += data[i]; sum = (sum & 0xffff) + (sum >> 16); sum = htons (0xffff - sum); return sum; } /** * Convert IPv4 address from text to binary form. * * @param af address family * @param cp the address to print * @param buf where to write the address result * @return 1 on success */ static int inet_pton (int af, const char *cp, struct in_addr *buf) { buf->s_addr = inet_addr (cp); if (buf->s_addr == INADDR_NONE) { fprintf (stderr, "Error %d handling address %s", WSAGetLastError (), cp); return 0; } return 1; } /** * Send an ICMP message to the dummy IP. * * @param my_ip source address (our ip address) */ static void send_icmp_echo (const struct in_addr *my_ip) { char packet[sizeof (struct ip_header) + sizeof (struct icmp_echo_header)]; struct icmp_echo_header icmp_echo; struct ip_header ip_pkt; struct sockaddr_in dst; size_t off; int err; off = 0; ip_pkt.vers_ihl = 0x45; ip_pkt.tos = 0; ip_pkt.pkt_len = htons (sizeof (packet)); ip_pkt.id = htons (PACKET_ID); ip_pkt.flags_frag_offset = 0; ip_pkt.ttl = IPDEFTTL; ip_pkt.proto = IPPROTO_ICMP; ip_pkt.checksum = 0; ip_pkt.src_ip = my_ip->s_addr; ip_pkt.dst_ip = dummy.s_addr; ip_pkt.checksum = htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header))); memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header)); off += sizeof (struct ip_header); icmp_echo.type = ICMP_ECHO; icmp_echo.code = 0; icmp_echo.reserved = 0; icmp_echo.checksum = 0; icmp_echo.checksum = htons (calc_checksum ((uint16_t *) & icmp_echo, sizeof (struct icmp_echo_header))); memcpy (&packet[off], &icmp_echo, sizeof (struct icmp_echo_header)); off += sizeof (struct icmp_echo_header); memset (&dst, 0, sizeof (dst)); dst.sin_family = AF_INET; dst.sin_addr = dummy; err = sendto (rawsock, packet, off, 0, (struct sockaddr *) &dst, sizeof (dst)); if (err < 0) { #if VERBOSE fprintf (stderr, "sendto failed: %s\n", strerror (errno)); #endif } else if (err != off) { fprintf (stderr, "Error: partial send of ICMP message\n"); } } /** * Send a UDP message to the dummy IP. */ static void send_udp () { struct sockaddr_in dst; ssize_t err; memset (&dst, 0, sizeof (dst)); dst.sin_family = AF_INET; dst.sin_addr = dummy; dst.sin_port = htons (NAT_TRAV_PORT); err = sendto (udpsock, NULL, 0, 0, (struct sockaddr *) &dst, sizeof (dst)); if (err < 0) { #if VERBOSE fprintf (stderr, "sendto failed: %s\n", strerror (errno)); #endif } else if (0 != err) { fprintf (stderr, "Error: partial send of ICMP message\n"); } } /** * We've received an ICMP response. Process it. */ static void process_icmp_response () { char buf[65536]; ssize_t have; struct in_addr source_ip; struct ip_header ip_pkt; struct icmp_ttl_exceeded_header icmp_ttl; struct icmp_echo_header icmp_echo; struct udp_header udp_pkt; size_t off; uint16_t port; DWORD ssize; have = read (icmpsock, buf, sizeof (buf)); if (have == -1) { fprintf (stderr, "Error reading raw socket: %s\n", strerror (errno)); return; } #if VERBOSE fprintf (stderr, "Received message of %u bytes\n", (unsigned int) have); #endif if (have < (ssize_t) (sizeof (struct ip_header) + sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct ip_header))) { /* malformed */ return; } off = 0; memcpy (&ip_pkt, &buf[off], sizeof (struct ip_header)); off += sizeof (struct ip_header); memcpy (&source_ip, &ip_pkt.src_ip, sizeof (source_ip)); memcpy (&icmp_ttl, &buf[off], sizeof (struct icmp_ttl_exceeded_header)); off += sizeof (struct icmp_ttl_exceeded_header); if ((ICMP_TIME_EXCEEDED != icmp_ttl.type) || (0 != icmp_ttl.code)) { /* different type than what we want */ return; } /* skip 2nd IP header */ memcpy (&ip_pkt, &buf[off], sizeof (struct ip_header)); off += sizeof (struct ip_header); switch (ip_pkt.proto) { case IPPROTO_ICMP: if (have != (sizeof (struct ip_header) * 2 + sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct icmp_echo_header))) { /* malformed */ return; } /* grab ICMP ECHO content */ memcpy (&icmp_echo, &buf[off], sizeof (struct icmp_echo_header)); port = (uint16_t) ntohl (icmp_echo.reserved); break; case IPPROTO_UDP: if (have != (sizeof (struct ip_header) * 2 + sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct udp_header))) { /* malformed */ return; } /* grab UDP content */ memcpy (&udp_pkt, &buf[off], sizeof (struct udp_header)); port = ntohs (udp_pkt.length); break; default: /* different type than what we want */ return; } ssize = sizeof (buf); WSAAddressToString ((LPSOCKADDR) & source_ip, sizeof (source_ip), NULL, buf, &ssize); if (port == 0) fprintf (stdout, "%s\n", buf); else fprintf (stdout, "%s:%u\n", buf, (unsigned int) port); fflush (stdout); } /** * Create an ICMP raw socket for reading. * * @return INVALID_SOCKET on error */ static SOCKET make_icmp_socket () { SOCKET ret; ret = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); if (INVALID_SOCKET == ret) { fprintf (stderr, "Error opening RAW socket: %s\n", strerror (errno)); return INVALID_SOCKET; } return ret; } /** * Create an ICMP raw socket for writing. * * @return INVALID_SOCKET on error */ static SOCKET make_raw_socket () { DWORD bOptVal = TRUE; int bOptLen = sizeof (bOptVal); rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); if (INVALID_SOCKET == rawsock) { fprintf (stderr, "Error opening RAW socket: %s\n", strerror (errno)); return INVALID_SOCKET; } if (0 != setsockopt (rawsock, SOL_SOCKET, SO_BROADCAST, (char *) &bOptVal, bOptLen)) { fprintf (stderr, "Error setting SO_BROADCAST to ON: %s\n", strerror (errno)); closesocket (rawsock); return INVALID_SOCKET; } if (0 != setsockopt (rawsock, IPPROTO_IP, IP_HDRINCL, (char *) &bOptVal, bOptLen)) { fprintf (stderr, "Error setting IP_HDRINCL to ON: %s\n", strerror (errno)); closesocket (rawsock); return INVALID_SOCKET; } return rawsock; } /** * Create a UDP socket for writing. * * @param my_ip source address (our ip address) * @return INVALID_SOCKET on error */ static SOCKET make_udp_socket (const struct in_addr *my_ip) { SOCKET ret; struct sockaddr_in addr; ret = socket (AF_INET, SOCK_DGRAM, 0); if (INVALID_SOCKET == ret) { fprintf (stderr, "Error opening UDP socket: %s\n", strerror (errno)); return INVALID_SOCKET; } memset (&addr, 0, sizeof (addr)); addr.sin_family = AF_INET; addr.sin_addr = *my_ip; addr.sin_port = htons (NAT_TRAV_PORT); if (0 != bind (ret, (struct sockaddr *) &addr, sizeof (addr))) { fprintf (stderr, "Error binding UDP socket to port %u: %s\n", NAT_TRAV_PORT, strerror (errno)); /* likely problematic, but not certain, try to continue */ } return ret; } int main (int argc, char *const *argv) { struct in_addr external; fd_set rs; struct timeval tv; WSADATA wsaData; unsigned int alt; alt = 0; if (2 != argc) { fprintf (stderr, "This program must be started with our (internal NAT) IP as the only argument.\n"); return 1; } if (1 != inet_pton (AF_INET, argv[1], &external)) { fprintf (stderr, "Error parsing IPv4 address: %s, error %s\n", argv[1], strerror (errno)); return 1; } if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) { fprintf (stderr, "Internal error converting dummy IP to binary.\n"); return 2; } if (WSAStartup (MAKEWORD (2, 1), &wsaData) != 0) { fprintf (stderr, "Failed to find Winsock 2.1 or better.\n"); return 2; } if (INVALID_SOCKET == (icmpsock = make_icmp_socket ())) { return 3; } if (INVALID_SOCKET == (make_raw_socket ())) { closesocket (icmpsock); return 3; } if (INVALID_SOCKET == (udpsock = make_udp_socket (&external))) { closesocket (icmpsock); closesocket (rawsock); return 3; } while (1) { FD_ZERO (&rs); FD_SET (icmpsock, &rs); tv.tv_sec = 0; tv.tv_usec = ICMP_SEND_FREQUENCY_MS * 1000; if (-1 == select (icmpsock + 1, &rs, NULL, NULL, &tv)) { if (errno == EINTR) continue; fprintf (stderr, "select failed: %s\n", strerror (errno)); break; } if (FD_ISSET (icmpsock, &rs)) process_icmp_response (); if (0 == (++alt % 2)) send_icmp_echo (&external); else send_udp (); } /* select failed (internal error or OS out of resources) */ closesocket (icmpsock); closesocket (rawsock); closesocket (udpsock); WSACleanup (); return 4; } /* end of gnunet-helper-nat-server-windows.c */ gnunet-0.9.3/src/nat/gnunet-helper-nat-server.c0000644000175000017500000003324311760502551016331 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/nat/gnunet-helper-nat-server.c * @brief Tool to help bypass NATs using ICMP method; must run as root (SUID will do) * This code will work under GNU/Linux only (or maybe BSDs, but never W32) * @author Christian Grothoff * * This program will send ONE ICMP message every 500 ms RAW sockets * to a DUMMY IP address and also listens for ICMP replies. Since * it uses RAW sockets, it must be installed SUID or run as 'root'. * In order to keep the security risk of the resulting SUID binary * minimal, the program ONLY opens the two RAW sockets with root * privileges, then drops them and only then starts to process * command line arguments. The code also does not link against * any shared libraries (except libc) and is strictly minimal * (except for checking for errors). The following list of people * have reviewed this code and considered it safe since the last * modification (if you reviewed it, please have your name added * to the list): * * - Christian Grothoff * - Nathan Evans * - Benjamin Kuperman (22 Aug 2010) * - Jacob Appelbaum (19 Dec 2011) */ #if HAVE_CONFIG_H /* Just needed for HAVE_SOCKADDR_IN_SIN_LEN test macro! */ #include "gnunet_config.h" #else #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** * Should we print some debug output? */ #define VERBOSE 0 /** * Must match packet ID used by gnunet-helper-nat-client.c */ #define PACKET_ID 256 /** * Must match IP given in the client. */ #define DUMMY_IP "192.0.2.86" /** * Port for UDP */ #define NAT_TRAV_PORT 22225 /** * How often do we send our ICMP messages to receive replies? */ #define ICMP_SEND_FREQUENCY_MS 500 /** * IPv4 header. */ struct ip_header { /** * Version (4 bits) + Internet header length (4 bits) */ uint8_t vers_ihl; /** * Type of service */ uint8_t tos; /** * Total length */ uint16_t pkt_len; /** * Identification */ uint16_t id; /** * Flags (3 bits) + Fragment offset (13 bits) */ uint16_t flags_frag_offset; /** * Time to live */ uint8_t ttl; /** * Protocol */ uint8_t proto; /** * Header checksum */ uint16_t checksum; /** * Source address */ uint32_t src_ip; /** * Destination address */ uint32_t dst_ip; }; /** * Format of ICMP packet. */ struct icmp_ttl_exceeded_header { uint8_t type; uint8_t code; uint16_t checksum; uint32_t unused; /* followed by original payload */ }; struct icmp_echo_header { uint8_t type; uint8_t code; uint16_t checksum; uint32_t reserved; }; /** * Beginning of UDP packet. */ struct udp_header { uint16_t src_port; uint16_t dst_port; uint16_t length; uint16_t crc; }; /** * Socket we use to receive "fake" ICMP replies. */ static int icmpsock; /** * Socket we use to send our ICMP requests. */ static int rawsock; /** * Socket we use to send our UDP requests. */ static int udpsock; /** * Target "dummy" address. */ static struct in_addr dummy; /** * CRC-16 for IP/ICMP headers. * * @param data what to calculate the CRC over * @param bytes number of bytes in data (must be multiple of 2) * @return the CRC 16. */ static uint16_t calc_checksum (const uint16_t * data, unsigned int bytes) { uint32_t sum; unsigned int i; sum = 0; for (i = 0; i < bytes / 2; i++) sum += data[i]; sum = (sum & 0xffff) + (sum >> 16); sum = htons (0xffff - sum); return sum; } /** * Send an ICMP message to the dummy IP. * * @param my_ip source address (our ip address) */ static void send_icmp_echo (const struct in_addr *my_ip) { char packet[sizeof (struct ip_header) + sizeof (struct icmp_echo_header)]; struct icmp_echo_header icmp_echo; struct ip_header ip_pkt; struct sockaddr_in dst; size_t off; int err; off = 0; ip_pkt.vers_ihl = 0x45; ip_pkt.tos = 0; ip_pkt.pkt_len = htons (sizeof (packet)); ip_pkt.id = htons (PACKET_ID); ip_pkt.flags_frag_offset = 0; ip_pkt.ttl = IPDEFTTL; ip_pkt.proto = IPPROTO_ICMP; ip_pkt.checksum = 0; ip_pkt.src_ip = my_ip->s_addr; ip_pkt.dst_ip = dummy.s_addr; ip_pkt.checksum = htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header))); memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header)); off += sizeof (struct ip_header); icmp_echo.type = ICMP_ECHO; icmp_echo.code = 0; icmp_echo.checksum = 0; icmp_echo.reserved = 0; icmp_echo.checksum = htons (calc_checksum ((uint16_t *) & icmp_echo, sizeof (struct icmp_echo_header))); memcpy (&packet[off], &icmp_echo, sizeof (struct icmp_echo_header)); off += sizeof (struct icmp_echo_header); memset (&dst, 0, sizeof (dst)); dst.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN dst.sin_len = sizeof (struct sockaddr_in); #endif dst.sin_addr = dummy; err = sendto (rawsock, packet, off, 0, (struct sockaddr *) &dst, sizeof (dst)); if (err < 0) { #if VERBOSE fprintf (stderr, "sendto failed: %s\n", strerror (errno)); #endif } else if (sizeof (packet) != err) { fprintf (stderr, "Error: partial send of ICMP message\n"); } } /** * Send a UDP message to the dummy IP. */ static void send_udp () { struct sockaddr_in dst; ssize_t err; memset (&dst, 0, sizeof (dst)); dst.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN dst.sin_len = sizeof (struct sockaddr_in); #endif dst.sin_addr = dummy; dst.sin_port = htons (NAT_TRAV_PORT); err = sendto (udpsock, NULL, 0, 0, (struct sockaddr *) &dst, sizeof (dst)); if (err < 0) { #if VERBOSE fprintf (stderr, "sendto failed: %s\n", strerror (errno)); #endif } else if (0 != err) { fprintf (stderr, "Error: partial send of ICMP message\n"); } } /** * We've received an ICMP response. Process it. */ static void process_icmp_response () { char buf[65536]; ssize_t have; struct in_addr source_ip; struct ip_header ip_pkt; struct icmp_ttl_exceeded_header icmp_ttl; struct icmp_echo_header icmp_echo; struct udp_header udp_pkt; size_t off; uint16_t port; have = read (icmpsock, buf, sizeof (buf)); if (-1 == have) { fprintf (stderr, "Error reading raw socket: %s\n", strerror (errno)); return; } #if VERBOSE fprintf (stderr, "Received message of %u bytes\n", (unsigned int) have); #endif if (have < (ssize_t) (sizeof (struct ip_header) + sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct ip_header))) { /* malformed */ return; } off = 0; memcpy (&ip_pkt, &buf[off], sizeof (struct ip_header)); off += sizeof (struct ip_header); memcpy (&icmp_ttl, &buf[off], sizeof (struct icmp_ttl_exceeded_header)); off += sizeof (struct icmp_ttl_exceeded_header); if ((ICMP_TIME_EXCEEDED != icmp_ttl.type) || (0 != icmp_ttl.code)) { /* different type than what we want */ return; } /* skip 2nd IP header */ memcpy (&ip_pkt, &buf[off], sizeof (struct ip_header)); off += sizeof (struct ip_header); switch (ip_pkt.proto) { case IPPROTO_ICMP: if (have != (sizeof (struct ip_header) * 2 + sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct icmp_echo_header))) { /* malformed */ return; } /* grab ICMP ECHO content */ memcpy (&icmp_echo, &buf[off], sizeof (struct icmp_echo_header)); port = (uint16_t) ntohl (icmp_echo.reserved); break; case IPPROTO_UDP: if (have != (sizeof (struct ip_header) * 2 + sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct udp_header))) { /* malformed */ return; } /* grab UDP content */ memcpy (&udp_pkt, &buf[off], sizeof (struct udp_header)); port = ntohs (udp_pkt.length); break; default: /* different type than what we want */ return; } source_ip.s_addr = ip_pkt.src_ip; if (port == 0) fprintf (stdout, "%s\n", inet_ntop (AF_INET, &source_ip, buf, sizeof (buf))); else fprintf (stdout, "%s:%u\n", inet_ntop (AF_INET, &source_ip, buf, sizeof (buf)), (unsigned int) port); fflush (stdout); } /** * Fully initialize the raw socket. * * @return -1 on error, 0 on success */ static int setup_raw_socket () { const int one = 1; if (-1 == setsockopt (rawsock, SOL_SOCKET, SO_BROADCAST, (char *) &one, sizeof (one))) { fprintf (stderr, "setsockopt failed: %s\n", strerror (errno)); return -1; } if (-1 == setsockopt (rawsock, IPPROTO_IP, IP_HDRINCL, (char *) &one, sizeof (one))) { fprintf (stderr, "setsockopt failed: %s\n", strerror (errno)); return -1; } return 0; } /** * Create a UDP socket for writing. * * @param my_ip source address (our ip address) * @return -1 on error */ static int make_udp_socket (const struct in_addr *my_ip) { int ret; struct sockaddr_in addr; ret = socket (AF_INET, SOCK_DGRAM, 0); if (-1 == ret) { fprintf (stderr, "Error opening UDP socket: %s\n", strerror (errno)); return -1; } memset (&addr, 0, sizeof (addr)); addr.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN addr.sin_len = sizeof (struct sockaddr_in); #endif addr.sin_addr = *my_ip; addr.sin_port = htons (NAT_TRAV_PORT); if (0 != bind (ret, &addr, sizeof (addr))) { fprintf (stderr, "Error binding UDP socket to port %u: %s\n", NAT_TRAV_PORT, strerror (errno)); (void) close (ret); return -1; } return ret; } int main (int argc, char *const *argv) { struct in_addr external; fd_set rs; struct timeval tv; uid_t uid; unsigned int alt; int icmp_eno; int raw_eno; int global_ret; /* Create an ICMP raw socket for reading (we'll check errors later) */ icmpsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); icmp_eno = errno; /* Create an (ICMP) raw socket for writing (we'll check errors later) */ rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_RAW); raw_eno = errno; udpsock = -1; /* drop root rights */ uid = getuid (); #ifdef HAVE_SETRESUID if (0 != setresuid (uid, uid, uid)) { fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno)); global_ret = 1; goto error_exit; } #else if (0 != (setuid (uid) | seteuid (uid))) { fprintf (stderr, "Failed to setuid: %s\n", strerror (errno)); global_ret = 2; goto error_exit; } #endif /* Now that we run without root rights, we can do error checking... */ if (2 != argc) { fprintf (stderr, "This program must be started with our (internal NAT) IP as the only argument.\n"); global_ret = 3; goto error_exit; } if (1 != inet_pton (AF_INET, argv[1], &external)) { fprintf (stderr, "Error parsing IPv4 address: %s\n", strerror (errno)); global_ret = 4; goto error_exit; } if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) { fprintf (stderr, "Internal error converting dummy IP to binary.\n"); global_ret = 5; goto error_exit; } /* error checking icmpsock */ if (-1 == icmpsock) { fprintf (stderr, "Error opening RAW socket: %s\n", strerror (icmp_eno)); global_ret = 6; goto error_exit; } if (icmpsock >= FD_SETSIZE) { /* this could happen if we were started with a large number of already-open file descriptors... */ fprintf (stderr, "Socket number too large (%d > %u)\n", icmpsock, (unsigned int) FD_SETSIZE); global_ret = 7; goto error_exit; } /* error checking rawsock */ if (-1 == rawsock) { fprintf (stderr, "Error opening RAW socket: %s\n", strerror (raw_eno)); global_ret = 8; goto error_exit; } /* no need to check 'rawsock' against FD_SETSIZE as it is never used with 'select' */ if (0 != setup_raw_socket ()) { global_ret = 9; goto error_exit; } if (-1 == (udpsock = make_udp_socket (&external))) { global_ret = 10; goto error_exit; } alt = 0; while (1) { FD_ZERO (&rs); FD_SET (icmpsock, &rs); tv.tv_sec = 0; tv.tv_usec = ICMP_SEND_FREQUENCY_MS * 1000; if (-1 == select (icmpsock + 1, &rs, NULL, NULL, &tv)) { if (errno == EINTR) continue; fprintf (stderr, "select failed: %s\n", strerror (errno)); break; } if (1 == getppid ()) /* Check the parent process id, if 1 the parent has died, so we should die too */ break; if (FD_ISSET (icmpsock, &rs)) process_icmp_response (); if (0 == (++alt % 2)) send_icmp_echo (&external); else send_udp (); } /* select failed (internal error or OS out of resources) */ global_ret = 11; error_exit: if (-1 != icmpsock) (void) close (icmpsock); if (-1 != rawsock) (void) close (rawsock); if (-1 != udpsock) (void) close (udpsock); return global_ret; } /* end of gnunet-helper-nat-server.c */ gnunet-0.9.3/src/nat/nat.c0000644000175000017500000011751111760502551012253 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file nat/nat.c * @brief Library handling UPnP and NAT-PMP port forwarding and * external IP address retrieval * @author Milan Bouchet-Valat * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_resolver_service.h" #include "gnunet_nat_lib.h" #include "nat.h" #define LOG(kind,...) GNUNET_log_from (kind, "nat", __VA_ARGS__) /** * How often do we scan for changes in our IP address from our local * interfaces? */ #define IFC_SCAN_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) /** * How often do we scan for changes in how our hostname resolves? */ #define HOSTNAME_DNS_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 20) /** * How often do we scan for changes in how our external (dyndns) hostname resolves? */ #define DYNDNS_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 7) /** * How long until we give up trying to resolve our own hostname? */ #define HOSTNAME_RESOLVE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) /** * Where did the given local address originate from? * To be used for debugging as well as in the future * to remove all addresses from a certain source when * we reevaluate the source. */ enum LocalAddressSource { /** * Address was obtained by DNS resolution of the external hostname * given in the configuration (i.e. hole-punched DynDNS setup). */ LAL_EXTERNAL_IP, /** * Address was obtained by looking up our own hostname in DNS. */ LAL_HOSTNAME_DNS, /** * Address was obtained by scanning our hosts's network interfaces * and taking their address (no DNS involved). */ LAL_INTERFACE_ADDRESS, /** * Addresses we were explicitly bound to. */ LAL_BINDTO_ADDRESS, /** * Addresses from UPnP or PMP */ LAL_UPNP, /** * End of the list. */ LAL_END }; /** * List of local addresses that we currently deem valid. Actual * struct is followed by the 'struct sockaddr'. Note that the code * intentionally makes no attempt to ensure that a particular address * is only listed once (especially since it may come from different * sources, and the source is an "internal" construct). */ struct LocalAddressList { /** * This is a linked list. */ struct LocalAddressList *next; /** * Previous entry. */ struct LocalAddressList *prev; /** * Number of bytes of address that follow. */ socklen_t addrlen; /** * Origin of the local address. */ enum LocalAddressSource source; }; /** * Handle for miniupnp-based NAT traversal actions. */ struct MiniList { /** * Doubly-linked list. */ struct MiniList *next; /** * Doubly-linked list. */ struct MiniList *prev; /** * Handle to mini-action. */ struct GNUNET_NAT_MiniHandle *mini; /** * Local port number that was mapped. */ uint16_t port; }; /** * Handle for active NAT registrations. */ struct GNUNET_NAT_Handle { /** * Configuration to use. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Function to call when we learn about a new address. */ GNUNET_NAT_AddressCallback address_callback; /** * Function to call when we notice another peer asking for * connection reversal. */ GNUNET_NAT_ReversalCallback reversal_callback; /** * Closure for 'callback'. */ void *callback_cls; /** * Handle for (DYN)DNS lookup of our external IP. */ struct GNUNET_RESOLVER_RequestHandle *ext_dns; /** * Handle for request of hostname resolution, non-NULL if pending. */ struct GNUNET_RESOLVER_RequestHandle *hostname_dns; /** * stdout pipe handle for the gnunet-helper-nat-server process */ struct GNUNET_DISK_PipeHandle *server_stdout; /** * stdout file handle (for reading) for the gnunet-helper-nat-server process */ const struct GNUNET_DISK_FileHandle *server_stdout_handle; /** * Linked list of currently valid addresses (head). */ struct LocalAddressList *lal_head; /** * Linked list of currently valid addresses (tail). */ struct LocalAddressList *lal_tail; /** * How long do we wait for restarting a crashed gnunet-helper-nat-server? */ struct GNUNET_TIME_Relative server_retry_delay; /** * ID of select gnunet-helper-nat-server stdout read task */ GNUNET_SCHEDULER_TaskIdentifier server_read_task; /** * ID of interface IP-scan task */ GNUNET_SCHEDULER_TaskIdentifier ifc_task; /** * ID of hostname DNS lookup task */ GNUNET_SCHEDULER_TaskIdentifier hostname_task; /** * ID of DynDNS lookup task */ GNUNET_SCHEDULER_TaskIdentifier dns_task; /** * ID of task to add addresses from bind. */ GNUNET_SCHEDULER_TaskIdentifier bind_task; /** * How often do we scan for changes in our IP address from our local * interfaces? */ struct GNUNET_TIME_Relative ifc_scan_frequency; /** * How often do we scan for changes in how our hostname resolves? */ struct GNUNET_TIME_Relative hostname_dns_frequency; /** * How often do we scan for changes in how our external (dyndns) hostname resolves? */ struct GNUNET_TIME_Relative dyndns_frequency; /** * The process id of the server process (if behind NAT) */ struct GNUNET_OS_Process *server_proc; /** * LAN address as passed by the caller (array). */ struct sockaddr **local_addrs; /** * Length of the 'local_addrs'. */ socklen_t *local_addrlens; /** * List of handles for UPnP-traversal, one per local port (if * not IPv6-only). */ struct MiniList *mini_head; /** * List of handles for UPnP-traversal, one per local port (if * not IPv6-only). */ struct MiniList *mini_tail; /** * Number of entries in 'local_addrs' array. */ unsigned int num_local_addrs; /** * Our external address (according to config, UPnP may disagree...), * in dotted decimal notation, IPv4-only. Or NULL if not known. */ char *external_address; /** * Presumably our internal address (according to config) */ char *internal_address; /** * Is this transport configured to be behind a NAT? */ int behind_nat; /** * Has the NAT been punched? (according to config) */ int nat_punched; /** * Is this transport configured to allow connections to NAT'd peers? */ int enable_nat_client; /** * Should we run the gnunet-helper-nat-server? */ int enable_nat_server; /** * Are we allowed to try UPnP/PMP for NAT traversal? */ int enable_upnp; /** * Should we use local addresses (loopback)? (according to config) */ int use_localaddresses; /** * Should we return local addresses to clients */ int return_localaddress; /** * Should we do a DNS lookup of our hostname to find out our own IP? */ int use_hostname; /** * Is using IPv6 disabled? */ int disable_ipv6; /** * Is this TCP or UDP? */ int is_tcp; /** * Port we advertise to the outside. */ uint16_t adv_port; }; /** * Try to start the gnunet-helper-nat-server (if it is not * already running). * * @param h handle to NAT */ static void start_gnunet_nat_server (struct GNUNET_NAT_Handle *h); /** * Remove all addresses from the list of 'local' addresses * that originated from the given source. * * @param h handle to NAT * @param src source that identifies addresses to remove */ static void remove_from_address_list_by_source (struct GNUNET_NAT_Handle *h, enum LocalAddressSource src) { struct LocalAddressList *pos; struct LocalAddressList *next; next = h->lal_head; while (NULL != (pos = next)) { next = pos->next; if (pos->source != src) continue; GNUNET_CONTAINER_DLL_remove (h->lal_head, h->lal_tail, pos); if (NULL != h->address_callback) h->address_callback (h->callback_cls, GNUNET_NO, (const struct sockaddr *) &pos[1], pos->addrlen); GNUNET_free (pos); } } /** * Add the given address to the list of 'local' addresses, thereby * making it a 'legal' address for this peer to have. * * @param h handle to NAT * @param src where did the local address originate from? * @param arg the address, some 'struct sockaddr' * @param arg_size number of bytes in arg */ static void add_to_address_list_as_is (struct GNUNET_NAT_Handle *h, enum LocalAddressSource src, const struct sockaddr *arg, socklen_t arg_size) { struct LocalAddressList *lal; lal = GNUNET_malloc (sizeof (struct LocalAddressList) + arg_size); memcpy (&lal[1], arg, arg_size); lal->addrlen = arg_size; lal->source = src; GNUNET_CONTAINER_DLL_insert (h->lal_head, h->lal_tail, lal); LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding address `%s' from source %d\n", GNUNET_a2s (arg, arg_size), src); if (NULL != h->address_callback) h->address_callback (h->callback_cls, GNUNET_YES, arg, arg_size); } /** * Add the given address to the list of 'local' addresses, thereby * making it a 'legal' address for this peer to have. Set the * port number in the process to the advertised port and possibly * also to zero (if we have the gnunet-helper-nat-server). * * @param h handle to NAT * @param src where did the local address originate from? * @param arg the address, some 'struct sockaddr' * @param arg_size number of bytes in arg */ static void add_to_address_list (struct GNUNET_NAT_Handle *h, enum LocalAddressSource src, const struct sockaddr *arg, socklen_t arg_size) { struct sockaddr_in s4; const struct sockaddr_in *in4; struct sockaddr_in6 s6; const struct sockaddr_in6 *in6; if (arg_size == sizeof (struct sockaddr_in)) { in4 = (const struct sockaddr_in *) arg; s4 = *in4; s4.sin_port = htons (h->adv_port); add_to_address_list_as_is (h, src, (const struct sockaddr *) &s4, sizeof (struct sockaddr_in)); if (GNUNET_YES == h->enable_nat_server) { /* also add with PORT = 0 to indicate NAT server is enabled */ s4.sin_port = htons (0); add_to_address_list_as_is (h, src, (const struct sockaddr *) &s4, sizeof (struct sockaddr_in)); } } else if (arg_size == sizeof (struct sockaddr_in6)) { if (GNUNET_YES != h->disable_ipv6) { in6 = (const struct sockaddr_in6 *) arg; s6 = *in6; s6.sin6_port = htons (h->adv_port); add_to_address_list_as_is (h, src, (const struct sockaddr *) &s6, sizeof (struct sockaddr_in6)); } } else { GNUNET_assert (0); } } /** * Add the given IP address to the list of 'local' addresses, thereby * making it a 'legal' address for this peer to have. * * @param h handle to NAT * @param src where did the local address originate from? * @param addr the address, some 'struct in_addr' or 'struct in6_addr' * @param addrlen number of bytes in addr */ static void add_ip_to_address_list (struct GNUNET_NAT_Handle *h, enum LocalAddressSource src, const void *addr, socklen_t addrlen) { struct sockaddr_in s4; const struct in_addr *in4; struct sockaddr_in6 s6; const struct in6_addr *in6; if (addrlen == sizeof (struct in_addr)) { in4 = (const struct in_addr *) addr; memset (&s4, 0, sizeof (s4)); s4.sin_family = AF_INET; s4.sin_port = 0; #if HAVE_SOCKADDR_IN_SIN_LEN s4.sin_len = (u_char) sizeof (struct sockaddr_in); #endif s4.sin_addr = *in4; add_to_address_list (h, src, (const struct sockaddr *) &s4, sizeof (struct sockaddr_in)); if (GNUNET_YES == h->enable_nat_server) { /* also add with PORT = 0 to indicate NAT server is enabled */ s4.sin_port = htons (0); add_to_address_list (h, src, (const struct sockaddr *) &s4, sizeof (struct sockaddr_in)); } } else if (addrlen == sizeof (struct in6_addr)) { if (GNUNET_YES != h->disable_ipv6) { in6 = (const struct in6_addr *) addr; memset (&s6, 0, sizeof (s6)); s6.sin6_family = AF_INET6; s6.sin6_port = htons (h->adv_port); #if HAVE_SOCKADDR_IN_SIN_LEN s6.sin6_len = (u_char) sizeof (struct sockaddr_in6); #endif s6.sin6_addr = *in6; add_to_address_list (h, src, (const struct sockaddr *) &s6, sizeof (struct sockaddr_in6)); } } else { GNUNET_assert (0); } } /** * Task to do DNS lookup on our external hostname to * get DynDNS-IP addresses. * * @param cls the NAT handle * @param tc scheduler context */ static void resolve_dns (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Our (external) hostname was resolved and the configuration says that * the NAT was hole-punched. * * @param cls the 'struct Plugin' * @param addr NULL on error, otherwise result of DNS lookup * @param addrlen number of bytes in addr */ static void process_external_ip (void *cls, const struct sockaddr *addr, socklen_t addrlen) { struct GNUNET_NAT_Handle *h = cls; struct in_addr dummy; if (addr == NULL) { h->ext_dns = NULL; if (1 == inet_pton (AF_INET, h->external_address, &dummy)) return; /* repated lookup pointless: was numeric! */ h->dns_task = GNUNET_SCHEDULER_add_delayed (h->dyndns_frequency, &resolve_dns, h); return; } add_to_address_list (h, LAL_EXTERNAL_IP, addr, addrlen); } /** * Task to do a lookup on our hostname for IP addresses. * * @param cls the NAT handle * @param tc scheduler context */ static void resolve_hostname (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Function called by the resolver for each address obtained from DNS * for our own hostname. Add the addresses to the list of our IP * addresses. * * @param cls closure * @param addr one of the addresses of the host, NULL for the last address * @param addrlen length of the address */ static void process_hostname_ip (void *cls, const struct sockaddr *addr, socklen_t addrlen) { struct GNUNET_NAT_Handle *h = cls; if (addr == NULL) { h->hostname_dns = NULL; h->hostname_task = GNUNET_SCHEDULER_add_delayed (h->hostname_dns_frequency, &resolve_hostname, h); return; } add_to_address_list (h, LAL_HOSTNAME_DNS, addr, addrlen); } /** * Add the IP of our network interface to the list of * our IP addresses. * * @param cls the 'struct GNUNET_NAT_Handle' * @param name name of the interface * @param isDefault do we think this may be our default interface * @param addr address of the interface * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned) * @param netmask the network mask (can be NULL for unknown or unassigned)) * @param addrlen number of bytes in addr * @return GNUNET_OK to continue iterating */ static int process_interfaces (void *cls, const char *name, int isDefault, const struct sockaddr *addr, const struct sockaddr *broadcast_addr, const struct sockaddr *netmask, socklen_t addrlen) { struct GNUNET_NAT_Handle *h = cls; const struct sockaddr_in *s4; const struct sockaddr_in6 *s6; const void *ip; char buf[INET6_ADDRSTRLEN]; switch (addr->sa_family) { case AF_INET: s4 = (struct sockaddr_in *) addr; ip = &s4->sin_addr; /* Check if address is in 127.0.0.0/8 */ uint32_t address = ntohl ((uint32_t) (s4->sin_addr.s_addr)); uint32_t value = (address & 0xFF000000) ^ 0x7F000000; if ((h->return_localaddress == GNUNET_NO) && (value == 0)) { return GNUNET_OK; } if (GNUNET_YES == h->use_localaddresses) { add_ip_to_address_list (h, LAL_INTERFACE_ADDRESS, &s4->sin_addr, sizeof (struct in_addr)); } break; case AF_INET6: s6 = (struct sockaddr_in6 *) addr; if (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr)) { /* skip link local addresses */ return GNUNET_OK; } if ((h->return_localaddress == GNUNET_NO) && (IN6_IS_ADDR_LOOPBACK (&((struct sockaddr_in6 *) addr)->sin6_addr))) { return GNUNET_OK; } ip = &s6->sin6_addr; if (GNUNET_YES == h->use_localaddresses) { add_ip_to_address_list (h, LAL_INTERFACE_ADDRESS, &s6->sin6_addr, sizeof (struct in6_addr)); } break; default: GNUNET_break (0); return GNUNET_OK; } if ((h->internal_address == NULL) && (h->server_proc == NULL) && (h->server_read_task == GNUNET_SCHEDULER_NO_TASK) && (GNUNET_YES == isDefault) && ((addr->sa_family == AF_INET) || (addr->sa_family == AF_INET6))) { /* no internal address configured, but we found a "default" * interface, try using that as our 'internal' address */ h->internal_address = GNUNET_strdup (inet_ntop (addr->sa_family, ip, buf, sizeof (buf))); start_gnunet_nat_server (h); } return GNUNET_OK; } /** * Task that restarts the gnunet-helper-nat-server process after a crash * after a certain delay. * * @param cls the 'struct GNUNET_NAT_Handle' * @param tc scheduler context */ static void restart_nat_server (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_NAT_Handle *h = cls; h->server_read_task = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; start_gnunet_nat_server (h); } /** * We have been notified that gnunet-helper-nat-server has written something to stdout. * Handle the output, then reschedule this function to be called again once * more is available. * * @param cls the NAT handle * @param tc the scheduling context */ static void nat_server_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_NAT_Handle *h = cls; char mybuf[40]; ssize_t bytes; size_t i; int port; const char *port_start; struct sockaddr_in sin_addr; h->server_read_task = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; memset (mybuf, 0, sizeof (mybuf)); bytes = GNUNET_DISK_file_read (h->server_stdout_handle, mybuf, sizeof (mybuf)); if (bytes < 1) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Finished reading from server stdout with code: %d\n", bytes); if (0 != GNUNET_OS_process_kill (h->server_proc, SIGTERM)) GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING, "nat", "kill"); GNUNET_OS_process_wait (h->server_proc); GNUNET_OS_process_destroy (h->server_proc); h->server_proc = NULL; GNUNET_DISK_pipe_close (h->server_stdout); h->server_stdout = NULL; h->server_stdout_handle = NULL; /* now try to restart it */ h->server_retry_delay = GNUNET_TIME_relative_multiply (h->server_retry_delay, 2); h->server_retry_delay = GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_HOURS, h->server_retry_delay); h->server_read_task = GNUNET_SCHEDULER_add_delayed (h->server_retry_delay, &restart_nat_server, h); return; } port_start = NULL; for (i = 0; i < sizeof (mybuf); i++) { if (mybuf[i] == '\n') { mybuf[i] = '\0'; break; } if ((mybuf[i] == ':') && (i + 1 < sizeof (mybuf))) { mybuf[i] = '\0'; port_start = &mybuf[i + 1]; } } /* construct socket address of sender */ memset (&sin_addr, 0, sizeof (sin_addr)); sin_addr.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN sin_addr.sin_len = sizeof (sin_addr); #endif if ((NULL == port_start) || (1 != SSCANF (port_start, "%d", &port)) || (-1 == inet_pton (AF_INET, mybuf, &sin_addr.sin_addr))) { /* should we restart gnunet-helper-nat-server? */ LOG (GNUNET_ERROR_TYPE_WARNING, "nat", _("gnunet-helper-nat-server generated malformed address `%s'\n"), mybuf); h->server_read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, h->server_stdout_handle, &nat_server_read, h); return; } sin_addr.sin_port = htons ((uint16_t) port); LOG (GNUNET_ERROR_TYPE_DEBUG, "gnunet-helper-nat-server read: %s:%d\n", mybuf, port); h->reversal_callback (h->callback_cls, (const struct sockaddr *) &sin_addr, sizeof (sin_addr)); h->server_read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, h->server_stdout_handle, &nat_server_read, h); } /** * Try to start the gnunet-helper-nat-server (if it is not * already running). * * @param h handle to NAT */ static void start_gnunet_nat_server (struct GNUNET_NAT_Handle *h) { if ((h->behind_nat == GNUNET_YES) && (h->enable_nat_server == GNUNET_YES) && (h->internal_address != NULL) && (NULL != (h->server_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES)))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting `%s' at `%s'\n", "gnunet-helper-nat-server", h->internal_address); /* Start the server process */ h->server_proc = GNUNET_OS_start_process (GNUNET_NO, NULL, h->server_stdout, "gnunet-helper-nat-server", "gnunet-helper-nat-server", h->internal_address, NULL); if (h->server_proc == NULL) { LOG (GNUNET_ERROR_TYPE_WARNING, "nat", _("Failed to start %s\n"), "gnunet-helper-nat-server"); GNUNET_DISK_pipe_close (h->server_stdout); h->server_stdout = NULL; } else { /* Close the write end of the read pipe */ GNUNET_DISK_pipe_close_end (h->server_stdout, GNUNET_DISK_PIPE_END_WRITE); h->server_stdout_handle = GNUNET_DISK_pipe_handle (h->server_stdout, GNUNET_DISK_PIPE_END_READ); h->server_read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, h->server_stdout_handle, &nat_server_read, h); } } } /** * Task to scan the local network interfaces for IP addresses. * * @param cls the NAT handle * @param tc scheduler context */ static void list_interfaces (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_NAT_Handle *h = cls; h->ifc_task = GNUNET_SCHEDULER_NO_TASK; remove_from_address_list_by_source (h, LAL_INTERFACE_ADDRESS); GNUNET_OS_network_interfaces_list (&process_interfaces, h); h->ifc_task = GNUNET_SCHEDULER_add_delayed (h->ifc_scan_frequency, &list_interfaces, h); } /** * Task to do a lookup on our hostname for IP addresses. * * @param cls the NAT handle * @param tc scheduler context */ static void resolve_hostname (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_NAT_Handle *h = cls; h->hostname_task = GNUNET_SCHEDULER_NO_TASK; remove_from_address_list_by_source (h, LAL_HOSTNAME_DNS); h->hostname_dns = GNUNET_RESOLVER_hostname_resolve (AF_UNSPEC, HOSTNAME_RESOLVE_TIMEOUT, &process_hostname_ip, h); } /** * Task to do DNS lookup on our external hostname to * get DynDNS-IP addresses. * * @param cls the NAT handle * @param tc scheduler context */ static void resolve_dns (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_NAT_Handle *h = cls; h->dns_task = GNUNET_SCHEDULER_NO_TASK; remove_from_address_list_by_source (h, LAL_EXTERNAL_IP); h->ext_dns = GNUNET_RESOLVER_ip_get (h->external_address, AF_INET, GNUNET_TIME_UNIT_MINUTES, &process_external_ip, h); } /** * Add or remove UPnP-mapped addresses. * * @param cls the GNUNET_NAT_Handle * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean * the previous (now invalid) one * @param addr either the previous or the new public IP address * @param addrlen actual lenght of the address */ static void upnp_add (void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen) { struct GNUNET_NAT_Handle *h = cls; struct LocalAddressList *pos; struct LocalAddressList *next; if (GNUNET_YES == add_remove) { add_to_address_list (h, LAL_UPNP, addr, addrlen); return; } /* remove address */ next = h->lal_head; while (NULL != (pos = next)) { next = pos->next; if ((pos->source != LAL_UPNP) || (pos->addrlen != addrlen) || (0 != memcmp (&pos[1], addr, addrlen))) continue; GNUNET_CONTAINER_DLL_remove (h->lal_head, h->lal_tail, pos); if (NULL != h->address_callback) h->address_callback (h->callback_cls, GNUNET_NO, (const struct sockaddr *) &pos[1], pos->addrlen); GNUNET_free (pos); return; /* only remove once */ } /* asked to remove address that does not exist */ GNUNET_break (0); } /** * Try to add a port mapping using UPnP. * * @param h overall NAT handle * @param port port to map with UPnP */ static void add_minis (struct GNUNET_NAT_Handle *h, uint16_t port) { struct MiniList *ml; ml = h->mini_head; while (NULL != ml) { if (port == ml->port) return; /* already got this port */ ml = ml->next; } ml = GNUNET_malloc (sizeof (struct MiniList)); ml->port = port; ml->mini = GNUNET_NAT_mini_map_start (port, h->is_tcp, &upnp_add, h); GNUNET_CONTAINER_DLL_insert (h->mini_head, h->mini_tail, ml); } /** * Task to add addresses from original bind to set of valid addrs. * * @param cls the NAT handle * @param tc scheduler context */ static void add_from_bind (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { static struct in6_addr any = IN6ADDR_ANY_INIT; struct GNUNET_NAT_Handle *h = cls; unsigned int i; struct sockaddr *sa; const struct sockaddr_in *v4; h->bind_task = GNUNET_SCHEDULER_NO_TASK; for (i = 0; i < h->num_local_addrs; i++) { sa = h->local_addrs[i]; switch (sa->sa_family) { case AF_INET: if (sizeof (struct sockaddr_in) != h->local_addrlens[i]) { GNUNET_break (0); break; } v4 = (const struct sockaddr_in *) sa; if (0 != v4->sin_addr.s_addr) add_to_address_list (h, LAL_BINDTO_ADDRESS, sa, sizeof (struct sockaddr_in)); if (h->enable_upnp) add_minis (h, ntohs (v4->sin_port)); break; case AF_INET6: if (sizeof (struct sockaddr_in6) != h->local_addrlens[i]) { GNUNET_break (0); break; } if (0 != memcmp (&((const struct sockaddr_in6 *) sa)->sin6_addr, &any, sizeof (struct in6_addr))) add_to_address_list (h, LAL_BINDTO_ADDRESS, sa, sizeof (struct sockaddr_in6)); break; default: break; } } } /** * Attempt to enable port redirection and detect public IP address contacting * UPnP or NAT-PMP routers on the local network. Use addr to specify to which * of the local host's addresses should the external port be mapped. The port * is taken from the corresponding sockaddr_in[6] field. * * @param cfg configuration to use * @param is_tcp GNUNET_YES for TCP, GNUNET_NO for UDP * @param adv_port advertised port (port we are either bound to or that our OS * locally performs redirection from to our bound port). * @param num_addrs number of addresses in 'addrs' * @param addrs the local addresses packets should be redirected to * @param addrlens actual lengths of the addresses * @param address_callback function to call everytime the public IP address changes * @param reversal_callback function to call if someone wants connection reversal from us * @param callback_cls closure for callbacks * @return NULL on error, otherwise handle that can be used to unregister */ struct GNUNET_NAT_Handle * GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg, int is_tcp, uint16_t adv_port, unsigned int num_addrs, const struct sockaddr **addrs, const socklen_t * addrlens, GNUNET_NAT_AddressCallback address_callback, GNUNET_NAT_ReversalCallback reversal_callback, void *callback_cls) { struct GNUNET_NAT_Handle *h; struct in_addr in_addr; unsigned int i; LOG (GNUNET_ERROR_TYPE_DEBUG, "Registered with NAT service at port %u with %u IP bound local addresses\n", (unsigned int) adv_port, num_addrs); h = GNUNET_malloc (sizeof (struct GNUNET_NAT_Handle)); h->server_retry_delay = GNUNET_TIME_UNIT_SECONDS; h->cfg = cfg; h->is_tcp = is_tcp; h->address_callback = address_callback; h->reversal_callback = reversal_callback; h->callback_cls = callback_cls; h->num_local_addrs = num_addrs; h->adv_port = adv_port; if (num_addrs != 0) { h->local_addrs = GNUNET_malloc (num_addrs * sizeof (struct sockaddr *)); h->local_addrlens = GNUNET_malloc (num_addrs * sizeof (socklen_t)); for (i = 0; i < num_addrs; i++) { GNUNET_assert (addrlens[i] > 0); GNUNET_assert (addrs[i] != NULL); h->local_addrlens[i] = addrlens[i]; h->local_addrs[i] = GNUNET_malloc (addrlens[i]); memcpy (h->local_addrs[i], addrs[i], addrlens[i]); } } h->bind_task = GNUNET_SCHEDULER_add_now (&add_from_bind, h); if (GNUNET_OK == GNUNET_CONFIGURATION_have_value (cfg, "nat", "INTERNAL_ADDRESS")) { (void) GNUNET_CONFIGURATION_get_value_string (cfg, "nat", "INTERNAL_ADDRESS", &h->internal_address); } if ((h->internal_address != NULL) && (inet_pton (AF_INET, h->internal_address, &in_addr) != 1)) { LOG (GNUNET_ERROR_TYPE_WARNING, "nat", _("Malformed %s `%s' given in configuration!\n"), "INTERNAL_ADDRESS", h->internal_address); GNUNET_free (h->internal_address); h->internal_address = NULL; } if (GNUNET_OK == GNUNET_CONFIGURATION_have_value (cfg, "nat", "EXTERNAL_ADDRESS")) { (void) GNUNET_CONFIGURATION_get_value_string (cfg, "nat", "EXTERNAL_ADDRESS", &h->external_address); } h->behind_nat = GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "BEHIND_NAT"); h->nat_punched = GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "PUNCHED_NAT"); h->enable_nat_client = GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "ENABLE_ICMP_CLIENT"); h->enable_nat_server = GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "ENABLE_ICMP_SERVER"); h->enable_upnp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "ENABLE_UPNP"); h->use_localaddresses = GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "USE_LOCALADDR"); h->return_localaddress = GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "RETURN_LOCAL_ADDRESSES"); h->use_hostname = GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "USE_HOSTNAME"); h->disable_ipv6 = GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "DISABLEV6"); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "nat", "DYNDNS_FREQUENCY", &h->dyndns_frequency)) h->dyndns_frequency = DYNDNS_FREQUENCY; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "nat", "IFC_SCAN_FREQUENCY", &h->ifc_scan_frequency)) h->ifc_scan_frequency = IFC_SCAN_FREQUENCY; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "nat", "HOSTNAME_DNS_FREQUENCY", &h->hostname_dns_frequency)) h->hostname_dns_frequency = HOSTNAME_DNS_FREQUENCY; if (NULL == reversal_callback) h->enable_nat_server = GNUNET_NO; /* Check if NAT was hole-punched */ if ((NULL != h->address_callback) && (h->external_address != NULL) && (h->nat_punched == GNUNET_YES)) { h->dns_task = GNUNET_SCHEDULER_add_now (&resolve_dns, h); h->enable_nat_server = GNUNET_NO; h->enable_upnp = GNUNET_NO; } /* Test for SUID binaries */ if ((h->behind_nat == GNUNET_YES) && (GNUNET_YES == h->enable_nat_server) && (GNUNET_YES != GNUNET_OS_check_helper_binary ("gnunet-helper-nat-server"))) { h->enable_nat_server = GNUNET_NO; LOG (GNUNET_ERROR_TYPE_WARNING, _ ("Configuration requires `%s', but binary is not installed properly (SUID bit not set). Option disabled.\n"), "gnunet-helper-nat-server"); } if ((GNUNET_YES == h->enable_nat_client) && (GNUNET_YES != GNUNET_OS_check_helper_binary ("gnunet-helper-nat-client"))) { h->enable_nat_client = GNUNET_NO; LOG (GNUNET_ERROR_TYPE_WARNING, _ ("Configuration requires `%s', but binary is not installed properly (SUID bit not set). Option disabled.\n"), "gnunet-helper-nat-client"); } start_gnunet_nat_server (h); /* FIXME: add support for UPnP, etc */ if (NULL != h->address_callback) { h->ifc_task = GNUNET_SCHEDULER_add_now (&list_interfaces, h); if (GNUNET_YES == h->use_hostname) h->hostname_task = GNUNET_SCHEDULER_add_now (&resolve_hostname, h); } return h; } /** * Stop port redirection and public IP address detection for the given handle. * This frees the handle, after having sent the needed commands to close open ports. * * @param h the handle to stop */ void GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *h) { unsigned int i; struct LocalAddressList *lal; struct MiniList *ml; while (NULL != (ml = h->mini_head)) { GNUNET_CONTAINER_DLL_remove (h->mini_head, h->mini_tail, ml); if (NULL != ml->mini) GNUNET_NAT_mini_map_stop (ml->mini); GNUNET_free (ml); } if (h->ext_dns != NULL) { GNUNET_RESOLVER_request_cancel (h->ext_dns); h->ext_dns = NULL; } if (NULL != h->hostname_dns) { GNUNET_RESOLVER_request_cancel (h->hostname_dns); h->hostname_dns = NULL; } if (GNUNET_SCHEDULER_NO_TASK != h->server_read_task) { GNUNET_SCHEDULER_cancel (h->server_read_task); h->server_read_task = GNUNET_SCHEDULER_NO_TASK; } if (GNUNET_SCHEDULER_NO_TASK != h->bind_task) { GNUNET_SCHEDULER_cancel (h->bind_task); h->bind_task = GNUNET_SCHEDULER_NO_TASK; } if (GNUNET_SCHEDULER_NO_TASK != h->ifc_task) { GNUNET_SCHEDULER_cancel (h->ifc_task); h->ifc_task = GNUNET_SCHEDULER_NO_TASK; } if (GNUNET_SCHEDULER_NO_TASK != h->hostname_task) { GNUNET_SCHEDULER_cancel (h->hostname_task); h->hostname_task = GNUNET_SCHEDULER_NO_TASK; } if (GNUNET_SCHEDULER_NO_TASK != h->dns_task) { GNUNET_SCHEDULER_cancel (h->dns_task); h->dns_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != h->server_proc) { if (0 != GNUNET_OS_process_kill (h->server_proc, SIGTERM)) GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING, "nat", "kill"); GNUNET_OS_process_wait (h->server_proc); GNUNET_OS_process_destroy (h->server_proc); h->server_proc = NULL; GNUNET_DISK_pipe_close (h->server_stdout); h->server_stdout = NULL; h->server_stdout_handle = NULL; } if (NULL != h->server_stdout) { GNUNET_DISK_pipe_close (h->server_stdout); h->server_stdout = NULL; h->server_stdout_handle = NULL; } while (NULL != (lal = h->lal_head)) { GNUNET_CONTAINER_DLL_remove (h->lal_head, h->lal_tail, lal); if (NULL != h->address_callback) h->address_callback (h->callback_cls, GNUNET_NO, (const struct sockaddr *) &lal[1], lal->addrlen); GNUNET_free (lal); } for (i = 0; i < h->num_local_addrs; i++) GNUNET_free (h->local_addrs[i]); GNUNET_free_non_null (h->local_addrs); GNUNET_free_non_null (h->local_addrlens); GNUNET_free_non_null (h->external_address); GNUNET_free_non_null (h->internal_address); GNUNET_free (h); } /** * We learned about a peer (possibly behind NAT) so run the * gnunet-helper-nat-client to send dummy ICMP responses to cause * that peer to connect to us (connection reversal). * * @return GNUNET_SYSERR on error, GNUNET_NO if nat client is disabled, * GNUNET_OK otherwise */ int GNUNET_NAT_run_client (struct GNUNET_NAT_Handle *h, const struct sockaddr_in *sa) { char inet4[INET_ADDRSTRLEN]; char port_as_string[6]; struct GNUNET_OS_Process *proc; if (GNUNET_YES != h->enable_nat_client) return GNUNET_NO; /* not permitted / possible */ if (h->internal_address == NULL) { LOG (GNUNET_ERROR_TYPE_WARNING, "nat", _ ("Internal IP address not known, cannot use ICMP NAT traversal method\n")); return GNUNET_SYSERR; } GNUNET_assert (sa->sin_family == AF_INET); if (NULL == inet_ntop (AF_INET, &sa->sin_addr, inet4, INET_ADDRSTRLEN)) { GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING, "nat", "inet_ntop"); return GNUNET_SYSERR; } GNUNET_snprintf (port_as_string, sizeof (port_as_string), "%d", h->adv_port); LOG (GNUNET_ERROR_TYPE_DEBUG, _("Running gnunet-helper-nat-client %s %s %u\n"), h->internal_address, inet4, (unsigned int) h->adv_port); proc = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "gnunet-helper-nat-client", "gnunet-helper-nat-client", h->internal_address, inet4, port_as_string, NULL); if (NULL == proc) return GNUNET_SYSERR; /* we know that the gnunet-helper-nat-client will terminate virtually * instantly */ GNUNET_OS_process_wait (proc); GNUNET_OS_process_destroy (proc); return GNUNET_OK; } /** * Test if the given address is (currently) a plausible IP address for this peer. * * @param h the handle returned by register * @param addr IP address to test (IPv4 or IPv6) * @param addrlen number of bytes in addr * @return GNUNET_YES if the address is plausible, * GNUNET_NO if the address is not plausible, * GNUNET_SYSERR if the address is malformed */ int GNUNET_NAT_test_address (struct GNUNET_NAT_Handle *h, const void *addr, socklen_t addrlen) { struct LocalAddressList *pos; const struct sockaddr_in *in4; const struct sockaddr_in6 *in6; if ((addrlen != sizeof (struct in_addr)) && (addrlen != sizeof (struct in6_addr))) { GNUNET_break (0); return GNUNET_SYSERR; } pos = h->lal_head; while (NULL != pos) { if (pos->addrlen == sizeof (struct sockaddr_in)) { in4 = (struct sockaddr_in *) &pos[1]; if ((addrlen == sizeof (struct in_addr)) && (0 == memcmp (&in4->sin_addr, addr, sizeof (struct in_addr)))) return GNUNET_YES; } else if (pos->addrlen == sizeof (struct sockaddr_in6)) { in6 = (struct sockaddr_in6 *) &pos[1]; if ((addrlen == sizeof (struct in6_addr)) && (0 == memcmp (&in6->sin6_addr, addr, sizeof (struct in6_addr)))) return GNUNET_YES; } else { GNUNET_assert (0); } pos = pos->next; } LOG (GNUNET_ERROR_TYPE_WARNING, "Asked to validate one of my addresses and validation failed!\n"); return GNUNET_NO; } /* end of nat.c */ gnunet-0.9.3/src/nat/nat.h0000644000175000017500000000305011760502551012250 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/nat/nat.h * @brief Messages for interaction with gnunet-nat-server * @author Christian Grothoff * */ #ifndef NAT_H #define NAT_H #include "gnunet_util_lib.h" GNUNET_NETWORK_STRUCT_BEGIN /** * Request to test NAT traversal. */ struct GNUNET_NAT_TestMessage { /** * Header with type "GNUNET_MESSAGE_TYPE_NAT_TEST" */ struct GNUNET_MessageHeader header; /** * IPv4 target IP address */ uint32_t dst_ipv4; /** * Port to use, 0 to send dummy ICMP response. */ uint16_t dport; /** * Data to send OR advertised-port (in NBO) to use for dummy ICMP. */ uint16_t data; /** * GNUNET_YES for TCP, GNUNET_NO for UDP. */ int32_t is_tcp; }; GNUNET_NETWORK_STRUCT_END #endif gnunet-0.9.3/src/nat/gnunet-helper-nat-client-windows.c0000644000175000017500000003033311760502551017766 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/nat/gnunet-helper-nat-client-windows.c * @brief Tool to help bypass NATs using ICMP method; must run as * administrator on W32 * This code is forx W32. * @author Nathan Evans * * This program will send ONE ICMP message using RAW sockets * to the IP address specified as the second argument. Since * it uses RAW sockets, it must be installed SUID or run as 'root'. * In order to keep the security risk of the resulting SUID binary * minimal, the program ONLY opens the RAW socket with root * privileges, then drops them and only then starts to process * command line arguments. The code also does not link against * any shared libraries (except libc) and is strictly minimal * (except for checking for errors). The following list of people * have reviewed this code and considered it safe since the last * modification (if you reviewed it, please have your name added * to the list): * * - Christian Grothoff * - Nathan Evans */ #define _GNU_SOURCE #define FD_SETSIZE 1024 #include #include #include #include #include #include #include #include #include #include #include #define ICMP_ECHO 8 #define IPDEFTTL 64 #define ICMP_TIME_EXCEEDED 11 /** * Must match IP given in the server. */ #define DUMMY_IP "192.0.2.86" #define NAT_TRAV_PORT 22225 /** * IPv4 header. */ struct ip_header { /** * Version (4 bits) + Internet header length (4 bits) */ uint8_t vers_ihl; /** * Type of service */ uint8_t tos; /** * Total length */ uint16_t pkt_len; /** * Identification */ uint16_t id; /** * Flags (3 bits) + Fragment offset (13 bits) */ uint16_t flags_frag_offset; /** * Time to live */ uint8_t ttl; /** * Protocol */ uint8_t proto; /** * Header checksum */ uint16_t checksum; /** * Source address */ uint32_t src_ip; /** * Destination address */ uint32_t dst_ip; }; /** * Format of ICMP packet. */ struct icmp_ttl_exceeded_header { uint8_t type; uint8_t code; uint16_t checksum; uint32_t unused; /* followed by original payload */ }; struct icmp_echo_header { uint8_t type; uint8_t code; uint16_t checksum; uint32_t reserved; }; /** * Beginning of UDP packet. */ struct udp_header { uint16_t src_port; uint16_t dst_port; uint16_t length; uint16_t crc; }; /** * Socket we use to send our ICMP packets. */ static SOCKET rawsock; /** * Target "dummy" address. */ static struct in_addr dummy; /** * Port we are listening on (communicated to the server). */ static uint16_t port; /** * Convert IPv4 address from text to binary form. * * @param af address family * @param cp the address to print * @param buf where to write the address result * @return 1 on success */ static int inet_pton (int af, const char *cp, struct in_addr *buf) { buf->s_addr = inet_addr (cp); if (buf->s_addr == INADDR_NONE) { fprintf (stderr, "Error %d handling address %s", WSAGetLastError (), cp); return 0; } return 1; } /** * CRC-16 for IP/ICMP headers. * * @param data what to calculate the CRC over * @param bytes number of bytes in data (must be multiple of 2) * @return the CRC 16. */ static uint16_t calc_checksum (const uint16_t * data, unsigned int bytes) { uint32_t sum; unsigned int i; sum = 0; for (i = 0; i < bytes / 2; i++) sum += data[i]; sum = (sum & 0xffff) + (sum >> 16); sum = htons (0xffff - sum); return sum; } /** * Send an ICMP message to the target. * * @param my_ip source address * @param other target address */ static void send_icmp_udp (const struct in_addr *my_ip, const struct in_addr *other) { char packet[sizeof (struct ip_header) * 2 + sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct udp_header)]; struct ip_header ip_pkt; struct icmp_ttl_exceeded_header icmp_pkt; struct udp_header udp_pkt; struct sockaddr_in dst; size_t off; int err; /* ip header: send to (known) ip address */ off = 0; ip_pkt.vers_ihl = 0x45; ip_pkt.tos = 0; ip_pkt.pkt_len = htons (sizeof (packet)); ip_pkt.id = htons (256); ip_pkt.flags_frag_offset = 0; ip_pkt.ttl = 128; ip_pkt.proto = IPPROTO_ICMP; ip_pkt.checksum = 0; ip_pkt.src_ip = my_ip->s_addr; ip_pkt.dst_ip = other->s_addr; ip_pkt.checksum = htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header))); memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header)); off += sizeof (struct ip_header); icmp_pkt.type = ICMP_TIME_EXCEEDED; icmp_pkt.code = 0; icmp_pkt.checksum = 0; icmp_pkt.unused = 0; memcpy (&packet[off], &icmp_pkt, sizeof (struct icmp_ttl_exceeded_header)); off += sizeof (struct icmp_ttl_exceeded_header); /* ip header of the presumably 'lost' udp packet */ ip_pkt.vers_ihl = 0x45; ip_pkt.tos = 0; ip_pkt.pkt_len = htons (sizeof (struct ip_header) + sizeof (struct udp_header)); ip_pkt.id = htons (0); ip_pkt.flags_frag_offset = 0; ip_pkt.ttl = 128; ip_pkt.proto = IPPROTO_UDP; ip_pkt.checksum = 0; ip_pkt.src_ip = other->s_addr; ip_pkt.dst_ip = dummy.s_addr; ip_pkt.checksum = htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header))); memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header)); off += sizeof (struct ip_header); /* build UDP header */ udp_pkt.src_port = htons (NAT_TRAV_PORT); udp_pkt.dst_port = htons (NAT_TRAV_PORT); udp_pkt.length = htons (port); udp_pkt.crc = 0; memcpy (&packet[off], &udp_pkt, sizeof (struct udp_header)); off += sizeof (struct udp_header); /* no go back to calculate ICMP packet checksum */ icmp_pkt.checksum = htons (calc_checksum ((uint16_t *) & packet[off], sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct ip_header) + sizeof (struct udp_header))); memcpy (&packet[sizeof (struct ip_header)], &icmp_pkt, sizeof (struct icmp_ttl_exceeded_header)); memset (&dst, 0, sizeof (dst)); dst.sin_family = AF_INET; dst.sin_addr = *other; err = sendto (rawsock, packet, sizeof (packet), 0, (struct sockaddr *) &dst, sizeof (dst)); if (err < 0) { fprintf (stderr, "sendto failed: %s\n", strerror (errno)); } else if (sizeof (packet) != (size_t) err) { fprintf (stderr, "Error: partial send of ICMP message\n"); } } /** * Send an ICMP message to the target. * * @param my_ip source address * @param other target address */ static void send_icmp (const struct in_addr *my_ip, const struct in_addr *other) { struct ip_header ip_pkt; struct icmp_ttl_exceeded_header icmp_ttl; struct icmp_echo_header icmp_echo; struct sockaddr_in dst; char packet[sizeof (struct ip_header) * 2 + sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct icmp_echo_header)]; size_t off; int err; /* ip header: send to (known) ip address */ off = 0; ip_pkt.vers_ihl = 0x45; ip_pkt.tos = 0; ip_pkt.pkt_len = htons (sizeof (packet)); ip_pkt.id = htons (256); ip_pkt.flags_frag_offset = 0; ip_pkt.ttl = IPDEFTTL; ip_pkt.proto = IPPROTO_ICMP; ip_pkt.checksum = 0; ip_pkt.src_ip = my_ip->s_addr; ip_pkt.dst_ip = other->s_addr; ip_pkt.checksum = htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header))); memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header)); off += sizeof (ip_pkt); /* icmp reply: time exceeded */ icmp_ttl.type = ICMP_TIME_EXCEEDED; icmp_ttl.code = 0; icmp_ttl.checksum = 0; icmp_ttl.unused = 0; memcpy (&packet[off], &icmp_ttl, sizeof (struct icmp_ttl_exceeded_header)); off += sizeof (struct icmp_ttl_exceeded_header); /* ip header of the presumably 'lost' udp packet */ ip_pkt.vers_ihl = 0x45; ip_pkt.tos = 0; ip_pkt.pkt_len = htons (sizeof (struct ip_header) + sizeof (struct icmp_echo_header)); ip_pkt.id = htons (256); ip_pkt.flags_frag_offset = 0; ip_pkt.ttl = 1; /* real TTL would be 1 on a time exceeded packet */ ip_pkt.proto = IPPROTO_ICMP; ip_pkt.src_ip = other->s_addr; ip_pkt.dst_ip = dummy.s_addr; ip_pkt.checksum = 0; ip_pkt.checksum = htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header))); memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header)); off += sizeof (struct ip_header); icmp_echo.type = ICMP_ECHO; icmp_echo.code = 0; icmp_echo.reserved = htonl (port); icmp_echo.checksum = 0; icmp_echo.checksum = htons (calc_checksum ((uint16_t *) & icmp_echo, sizeof (struct icmp_echo_header))); memcpy (&packet[off], &icmp_echo, sizeof (struct icmp_echo_header)); /* no go back to calculate ICMP packet checksum */ off = sizeof (struct ip_header); icmp_ttl.checksum = htons (calc_checksum ((uint16_t *) & packet[off], sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct ip_header) + sizeof (struct icmp_echo_header))); memcpy (&packet[off], &icmp_ttl, sizeof (struct icmp_ttl_exceeded_header)); memset (&dst, 0, sizeof (dst)); dst.sin_family = AF_INET; dst.sin_addr = *other; err = sendto (rawsock, packet, sizeof (packet), 0, (struct sockaddr *) &dst, sizeof (dst)); if (err < 0) { fprintf (stderr, "sendto failed: %s\n", strerror (errno)); } else if (sizeof (packet) != (size_t) err) { fprintf (stderr, "Error: partial send of ICMP message\n"); } } /** * Create an ICMP raw socket. * * @return INVALID_SOCKET on error */ static SOCKET make_raw_socket () { DWORD bOptVal = TRUE; int bOptLen = sizeof (bOptVal); SOCKET ret; ret = socket (AF_INET, SOCK_RAW, IPPROTO_RAW); if (INVALID_SOCKET == ret) { fprintf (stderr, "Error opening RAW socket: %s\n", strerror (errno)); return INVALID_SOCKET; } if (0 != setsockopt (ret, SOL_SOCKET, SO_BROADCAST, (char *) &bOptVal, bOptLen)) { fprintf (stderr, "Error setting SO_BROADCAST to ON: %s\n", strerror (errno)); closesocket (rawsock); return INVALID_SOCKET; } if (0 != setsockopt (ret, IPPROTO_IP, IP_HDRINCL, (char *) &bOptVal, bOptLen)) { fprintf (stderr, "Error setting IP_HDRINCL to ON: %s\n", strerror (errno)); closesocket (rawsock); return INVALID_SOCKET; } return ret; } int main (int argc, char *const *argv) { struct in_addr external; struct in_addr target; WSADATA wsaData; unsigned int p; if (argc != 4) { fprintf (stderr, "This program must be started with our IP, the targets external IP, and our port as arguments.\n"); return 1; } if ((1 != inet_pton (AF_INET, argv[1], &external)) || (1 != inet_pton (AF_INET, argv[2], &target))) { fprintf (stderr, "Error parsing IPv4 address: %s\n", strerror (errno)); return 1; } if ((1 != sscanf (argv[3], "%u", &p)) || (0 == p) || (0xFFFF < p)) { fprintf (stderr, "Error parsing port value `%s'\n", argv[3]); return 1; } port = (uint16_t) p; if (0 != WSAStartup (MAKEWORD (2, 1), &wsaData)) { fprintf (stderr, "Failed to find Winsock 2.1 or better.\n"); return 2; } if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) { fprintf (stderr, "Internal error converting dummy IP to binary.\n"); return 2; } if (-1 == (rawsock = make_raw_socket ())) return 3; send_icmp (&external, &target); send_icmp_udp (&external, &target); closesocket (rawsock); WSACleanup (); return 0; } /* end of gnunet-helper-nat-client-windows.c */ gnunet-0.9.3/src/nat/Makefile.in0000644000175000017500000010132211762217212013362 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-nat-server$(EXEEXT) $(am__EXEEXT_1) check_PROGRAMS = test_nat$(EXEEXT) test_nat_mini$(EXEEXT) \ test_nat_test$(EXEEXT) subdir = src/nat DIST_COMMON = $(dist_pkgcfg_DATA) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libgnunetnat_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_libgnunetnat_la_OBJECTS = nat.lo nat_test.lo nat_mini.lo libgnunetnat_la_OBJECTS = $(am_libgnunetnat_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunetnat_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetnat_la_LDFLAGS) $(LDFLAGS) \ -o $@ @LINUX_FALSE@@MINGW_TRUE@am__EXEEXT_1 = \ @LINUX_FALSE@@MINGW_TRUE@ gnunet-helper-nat-server$(EXEEXT) \ @LINUX_FALSE@@MINGW_TRUE@ gnunet-helper-nat-client$(EXEEXT) @LINUX_TRUE@am__EXEEXT_1 = gnunet-helper-nat-server$(EXEEXT) \ @LINUX_TRUE@ gnunet-helper-nat-client$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) am__gnunet_helper_nat_client_SOURCES_DIST = \ gnunet-helper-nat-client.c gnunet-helper-nat-client-windows.c @LINUX_FALSE@@MINGW_TRUE@am__objects_1 = gnunet-helper-nat-client-windows.$(OBJEXT) @LINUX_TRUE@am__objects_1 = gnunet-helper-nat-client.$(OBJEXT) am_gnunet_helper_nat_client_OBJECTS = $(am__objects_1) gnunet_helper_nat_client_OBJECTS = \ $(am_gnunet_helper_nat_client_OBJECTS) gnunet_helper_nat_client_LDADD = $(LDADD) am__gnunet_helper_nat_server_SOURCES_DIST = \ gnunet-helper-nat-server.c gnunet-helper-nat-server-windows.c @LINUX_FALSE@@MINGW_TRUE@am__objects_2 = gnunet-helper-nat-server-windows.$(OBJEXT) @LINUX_TRUE@am__objects_2 = gnunet-helper-nat-server.$(OBJEXT) am_gnunet_helper_nat_server_OBJECTS = $(am__objects_2) gnunet_helper_nat_server_OBJECTS = \ $(am_gnunet_helper_nat_server_OBJECTS) gnunet_helper_nat_server_LDADD = $(LDADD) am_gnunet_nat_server_OBJECTS = gnunet-nat-server.$(OBJEXT) gnunet_nat_server_OBJECTS = $(am_gnunet_nat_server_OBJECTS) am_test_nat_OBJECTS = test_nat.$(OBJEXT) test_nat_OBJECTS = $(am_test_nat_OBJECTS) test_nat_DEPENDENCIES = $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_nat_mini_OBJECTS = test_nat_mini.$(OBJEXT) test_nat_mini_OBJECTS = $(am_test_nat_mini_OBJECTS) test_nat_mini_DEPENDENCIES = $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_nat_test_OBJECTS = test_nat_test.$(OBJEXT) test_nat_test_OBJECTS = $(am_test_nat_test_OBJECTS) test_nat_test_DEPENDENCIES = $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunetnat_la_SOURCES) \ $(gnunet_helper_nat_client_SOURCES) \ $(gnunet_helper_nat_server_SOURCES) \ $(gnunet_nat_server_SOURCES) $(test_nat_SOURCES) \ $(test_nat_mini_SOURCES) $(test_nat_test_SOURCES) DIST_SOURCES = $(libgnunetnat_la_SOURCES) \ $(am__gnunet_helper_nat_client_SOURCES_DIST) \ $(am__gnunet_helper_nat_server_SOURCES_DIST) \ $(gnunet_nat_server_SOURCES) $(test_nat_SOURCES) \ $(test_nat_mini_SOURCES) $(test_nat_test_SOURCES) DATA = $(dist_pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @LINUX_TRUE@NATBIN = gnunet-helper-nat-server gnunet-helper-nat-client @MINGW_TRUE@NATBIN = gnunet-helper-nat-server gnunet-helper-nat-client @LINUX_TRUE@NATSERVER = gnunet-helper-nat-server.c @MINGW_TRUE@NATSERVER = gnunet-helper-nat-server-windows.c @LINUX_TRUE@NATCLIENT = gnunet-helper-nat-client.c @MINGW_TRUE@NATCLIENT = gnunet-helper-nat-client-windows.c pkgcfgdir = $(pkgdatadir)/config.d/ dist_pkgcfg_DATA = \ nat.conf @ENABLE_TEST_RUN_TRUE@nattest = $(bindir)/gnunet-nat-server gnunet_nat_server_SOURCES = \ gnunet-nat-server.c nat.h gnunet_nat_server_LDADD = \ $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la gnunet_nat_server_DEPENDENCIES = \ libgnunetnat.la gnunet_helper_nat_server_SOURCES = \ $(NATSERVER) gnunet_helper_nat_client_SOURCES = \ $(NATCLIENT) @USE_COVERAGE_TRUE@AM_CFLAGS = -fprofile-arcs -ftest-coverage lib_LTLIBRARIES = libgnunetnat.la libgnunetnat_la_SOURCES = \ nat.c nat.h \ nat_test.c \ nat_mini.c libgnunetnat_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) @EXT_LIBS@ libgnunetnat_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 0:0:0 @ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) test_nat_SOURCES = \ test_nat.c test_nat_LDADD = \ $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la test_nat_mini_SOURCES = \ test_nat_mini.c test_nat_mini_LDADD = \ $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la test_nat_test_SOURCES = \ test_nat_test.c test_nat_test_LDADD = \ $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ test_nat_data.conf \ test_nat_test_data.conf all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/nat/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/nat/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunetnat.la: $(libgnunetnat_la_OBJECTS) $(libgnunetnat_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetnat_la_LINK) -rpath $(libdir) $(libgnunetnat_la_OBJECTS) $(libgnunetnat_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-helper-nat-client$(EXEEXT): $(gnunet_helper_nat_client_OBJECTS) $(gnunet_helper_nat_client_DEPENDENCIES) @rm -f gnunet-helper-nat-client$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_helper_nat_client_OBJECTS) $(gnunet_helper_nat_client_LDADD) $(LIBS) gnunet-helper-nat-server$(EXEEXT): $(gnunet_helper_nat_server_OBJECTS) $(gnunet_helper_nat_server_DEPENDENCIES) @rm -f gnunet-helper-nat-server$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_helper_nat_server_OBJECTS) $(gnunet_helper_nat_server_LDADD) $(LIBS) gnunet-nat-server$(EXEEXT): $(gnunet_nat_server_OBJECTS) $(gnunet_nat_server_DEPENDENCIES) @rm -f gnunet-nat-server$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_nat_server_OBJECTS) $(gnunet_nat_server_LDADD) $(LIBS) test_nat$(EXEEXT): $(test_nat_OBJECTS) $(test_nat_DEPENDENCIES) @rm -f test_nat$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_nat_OBJECTS) $(test_nat_LDADD) $(LIBS) test_nat_mini$(EXEEXT): $(test_nat_mini_OBJECTS) $(test_nat_mini_DEPENDENCIES) @rm -f test_nat_mini$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_nat_mini_OBJECTS) $(test_nat_mini_LDADD) $(LIBS) test_nat_test$(EXEEXT): $(test_nat_test_OBJECTS) $(test_nat_test_DEPENDENCIES) @rm -f test_nat_test$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_nat_test_OBJECTS) $(test_nat_test_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-nat-client-windows.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-nat-client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-nat-server-windows.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-nat-server.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-nat-server.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nat.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nat_mini.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nat_test.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_nat.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_nat_mini.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_nat_test.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_pkgcfgDATA: $(dist_pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-dist_pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_pkgcfgDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-exec-hook install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-dist_pkgcfgDATA \ uninstall-libLTLIBRARIES .MAKE: check-am install-am install-exec-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-binPROGRAMS install-data \ install-data-am install-dist_pkgcfgDATA install-dvi \ install-dvi-am install-exec install-exec-am install-exec-hook \ install-html install-html-am install-info install-info-am \ install-libLTLIBRARIES install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-dist_pkgcfgDATA uninstall-libLTLIBRARIES @LINUX_TRUE@install-exec-hook: @LINUX_TRUE@ $(SUDO_BINARY) chown root:root $(bindir)/gnunet-helper-nat-server $(bindir)/gnunet-helper-nat-client $(nattest) || true @LINUX_TRUE@ $(SUDO_BINARY) chmod u+s $(bindir)/gnunet-helper-nat-server $(bindir)/gnunet-helper-nat-client $(nattest) || true @LINUX_FALSE@install-exec-hook: # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/nat/nat_test.c0000644000175000017500000003136511760502551013314 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file nat/nat_test.c * @brief functions to test if the NAT configuration is successful at achieving NAT traversal (with the help of a gnunet-nat-server) * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_nat_lib.h" #include "nat.h" #define LOG(kind,...) GNUNET_log_from (kind, "nat", __VA_ARGS__) #define NAT_SERVER_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) /** * Entry we keep for each incoming connection. */ struct NatActivity { /** * This is a doubly-linked list. */ struct NatActivity *next; /** * This is a doubly-linked list. */ struct NatActivity *prev; /** * Socket of the incoming connection. */ struct GNUNET_NETWORK_Handle *sock; /** * Handle of the master context. */ struct GNUNET_NAT_Test *h; /** * Task reading from the incoming connection. */ GNUNET_SCHEDULER_TaskIdentifier rtask; }; /** * Entry we keep for each connection to the gnunet-nat-service. */ struct ClientActivity { /** * This is a doubly-linked list. */ struct ClientActivity *next; /** * This is a doubly-linked list. */ struct ClientActivity *prev; /** * Socket of the incoming connection. */ struct GNUNET_CLIENT_Connection *client; }; /** * Handle to a NAT test. */ struct GNUNET_NAT_Test { /** * Configuration used */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Function to call with success report */ GNUNET_NAT_TestCallback report; /** * Closure for 'report'. */ void *report_cls; /** * Handle to NAT traversal in use */ struct GNUNET_NAT_Handle *nat; /** * Handle to listen socket, or NULL */ struct GNUNET_NETWORK_Handle *lsock; /** * Head of list of nat activities. */ struct NatActivity *na_head; /** * Tail of list of nat activities. */ struct NatActivity *na_tail; /** * Head of list of client activities. */ struct ClientActivity *ca_head; /** * Tail of list of client activities. */ struct ClientActivity *ca_tail; /** * Identity of task for the listen socket (if any) */ GNUNET_SCHEDULER_TaskIdentifier ltask; /** * GNUNET_YES if we're testing TCP */ int is_tcp; /** * Data that should be transmitted or source-port. */ uint16_t data; /** * Advertised port to the other peer. */ uint16_t adv_port; }; /** * Function called from GNUNET_NAT_register whenever someone asks us * to do connection reversal. * * @param cls closure, our 'struct GNUNET_NAT_Handle' * @param addr public IP address of the other peer * @param addrlen actual lenght of the address */ static void reversal_cb (void *cls, const struct sockaddr *addr, socklen_t addrlen) { struct GNUNET_NAT_Test *h = cls; const struct sockaddr_in *sa; if (addrlen != sizeof (struct sockaddr_in)) return; sa = (const struct sockaddr_in *) addr; if (h->data != sa->sin_port) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Received connection reversal request for wrong port\n"); return; /* wrong port */ } /* report success */ h->report (h->report_cls, GNUNET_OK); } /** * Activity on our incoming socket. Read data from the * incoming connection. * * @param cls the 'struct NatActivity' * @param tc scheduler context */ static void do_udp_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_NAT_Test *tst = cls; uint16_t data; tst->ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, tst->lsock, &do_udp_read, tst); if ((NULL != tc->write_ready) && (GNUNET_NETWORK_fdset_isset (tc->read_ready, tst->lsock)) && (sizeof (data) == GNUNET_NETWORK_socket_recv (tst->lsock, &data, sizeof (data)))) { if (data == tst->data) tst->report (tst->report_cls, GNUNET_OK); else LOG (GNUNET_ERROR_TYPE_DEBUG, "Received data mismatches expected value\n"); } else LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to receive data from inbound connection\n"); } /** * Activity on our incoming socket. Read data from the * incoming connection. * * @param cls the 'struct NatActivity' * @param tc scheduler context */ static void do_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct NatActivity *na = cls; struct GNUNET_NAT_Test *tst; uint16_t data; na->rtask = GNUNET_SCHEDULER_NO_TASK; tst = na->h; GNUNET_CONTAINER_DLL_remove (tst->na_head, tst->na_tail, na); if ((NULL != tc->write_ready) && (GNUNET_NETWORK_fdset_isset (tc->read_ready, na->sock)) && (sizeof (data) == GNUNET_NETWORK_socket_recv (na->sock, &data, sizeof (data)))) { if (data == tst->data) tst->report (tst->report_cls, GNUNET_OK); else LOG (GNUNET_ERROR_TYPE_DEBUG, "Received data mismatches expected value\n"); } else LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to receive data from inbound connection\n"); GNUNET_NETWORK_socket_close (na->sock); GNUNET_free (na); } /** * Activity on our listen socket. Accept the * incoming connection. * * @param cls the 'struct GNUNET_NAT_Test' * @param tc scheduler context */ static void do_accept (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_NAT_Test *tst = cls; struct GNUNET_NETWORK_Handle *s; struct NatActivity *wl; tst->ltask = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; tst->ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, tst->lsock, &do_accept, tst); s = GNUNET_NETWORK_socket_accept (tst->lsock, NULL, NULL); if (NULL == s) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO, "accept"); return; /* odd error */ } LOG (GNUNET_ERROR_TYPE_DEBUG, "Got an inbound connection, waiting for data\n"); wl = GNUNET_malloc (sizeof (struct NatActivity)); wl->sock = s; wl->h = tst; wl->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, wl->sock, &do_read, wl); GNUNET_CONTAINER_DLL_insert (tst->na_head, tst->na_tail, wl); } /** * Address-callback, used to send message to gnunet-nat-server. * * @param cls closure * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean * the previous (now invalid) one * @param addr either the previous or the new public IP address * @param addrlen actual lenght of the address */ static void addr_cb (void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen) { struct GNUNET_NAT_Test *h = cls; struct ClientActivity *ca; struct GNUNET_CLIENT_Connection *client; struct GNUNET_NAT_TestMessage msg; const struct sockaddr_in *sa; if (GNUNET_YES != add_remove) return; if (addrlen != sizeof (struct sockaddr_in)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "NAT test ignores IPv6 address `%s' returned from NAT library\n", GNUNET_a2s (addr, addrlen)); return; /* ignore IPv6 here */ } LOG (GNUNET_ERROR_TYPE_DEBUG, "Asking gnunet-nat-server to connect to `%s'\n", GNUNET_a2s (addr, addrlen)); sa = (const struct sockaddr_in *) addr; msg.header.size = htons (sizeof (struct GNUNET_NAT_TestMessage)); msg.header.type = htons (GNUNET_MESSAGE_TYPE_NAT_TEST); msg.dst_ipv4 = sa->sin_addr.s_addr; msg.dport = sa->sin_port; msg.data = h->data; msg.is_tcp = htonl ((uint32_t) h->is_tcp); client = GNUNET_CLIENT_connect ("gnunet-nat-server", h->cfg); if (NULL == client) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to connect to `gnunet-nat-server'\n")); return; } ca = GNUNET_malloc (sizeof (struct ClientActivity)); ca->client = client; GNUNET_CONTAINER_DLL_insert (h->ca_head, h->ca_tail, ca); GNUNET_break (GNUNET_OK == GNUNET_CLIENT_transmit_and_get_response (client, &msg.header, NAT_SERVER_TIMEOUT, GNUNET_YES, NULL, NULL)); } /** * Start testing if NAT traversal works using the * given configuration (IPv4-only). * * @param cfg configuration for the NAT traversal * @param is_tcp GNUNET_YES to test TCP, GNUNET_NO to test UDP * @param bnd_port port to bind to, 0 for connection reversal * @param adv_port externally advertised port to use * @param report function to call with the result of the test * @param report_cls closure for report * @return handle to cancel NAT test */ struct GNUNET_NAT_Test * GNUNET_NAT_test_start (const struct GNUNET_CONFIGURATION_Handle *cfg, int is_tcp, uint16_t bnd_port, uint16_t adv_port, GNUNET_NAT_TestCallback report, void *report_cls) { struct GNUNET_NAT_Test *ret; struct sockaddr_in sa; const struct sockaddr *addrs[] = { (const struct sockaddr *) &sa }; const socklen_t addrlens[] = { sizeof (sa) }; memset (&sa, 0, sizeof (sa)); sa.sin_family = AF_INET; sa.sin_port = htons (bnd_port); #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = sizeof (sa); #endif ret = GNUNET_malloc (sizeof (struct GNUNET_NAT_Test)); ret->cfg = cfg; ret->is_tcp = is_tcp; ret->data = bnd_port; ret->adv_port = adv_port; ret->report = report; ret->report_cls = report_cls; if (bnd_port == 0) { ret->nat = GNUNET_NAT_register (cfg, is_tcp, 0, 0, NULL, NULL, &addr_cb, &reversal_cb, ret); } else { ret->lsock = GNUNET_NETWORK_socket_create (AF_INET, (is_tcp == GNUNET_YES) ? SOCK_STREAM : SOCK_DGRAM, 0); if ((ret->lsock == NULL) || (GNUNET_OK != GNUNET_NETWORK_socket_bind (ret->lsock, (const struct sockaddr *) &sa, sizeof (sa)))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Failed to create listen socket bound to `%s' for NAT test: %s\n"), GNUNET_a2s ((const struct sockaddr *) &sa, sizeof (sa)), STRERROR (errno)); if (NULL != ret->lsock) GNUNET_NETWORK_socket_close (ret->lsock); GNUNET_free (ret); return NULL; } if (GNUNET_YES == is_tcp) { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_listen (ret->lsock, 5)); ret->ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, ret->lsock, &do_accept, ret); } else { ret->ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, ret->lsock, &do_udp_read, ret); } LOG (GNUNET_ERROR_TYPE_DEBUG, "NAT test listens on port %u (%s)\n", bnd_port, (GNUNET_YES == is_tcp) ? "tcp" : "udp"); ret->nat = GNUNET_NAT_register (cfg, is_tcp, adv_port, 1, addrs, addrlens, &addr_cb, NULL, ret); } return ret; } /** * Stop an active NAT test. * * @param tst test to stop. */ void GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst) { struct NatActivity *pos; struct ClientActivity *cpos; LOG (GNUNET_ERROR_TYPE_DEBUG, "Stopping NAT test\n"); while (NULL != (cpos = tst->ca_head)) { GNUNET_CONTAINER_DLL_remove (tst->ca_head, tst->ca_tail, cpos); GNUNET_CLIENT_disconnect (cpos->client); GNUNET_free (cpos); } while (NULL != (pos = tst->na_head)) { GNUNET_CONTAINER_DLL_remove (tst->na_head, tst->na_tail, pos); GNUNET_SCHEDULER_cancel (pos->rtask); GNUNET_NETWORK_socket_close (pos->sock); GNUNET_free (pos); } if (GNUNET_SCHEDULER_NO_TASK != tst->ltask) GNUNET_SCHEDULER_cancel (tst->ltask); if (NULL != tst->lsock) GNUNET_NETWORK_socket_close (tst->lsock); GNUNET_NAT_unregister (tst->nat); GNUNET_free (tst); } /* end of nat_test.c */ gnunet-0.9.3/src/nat/gnunet-helper-nat-client.c0000644000175000017500000003071011760502551016275 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/nat/gnunet-helper-nat-client.c * @brief Tool to help bypass NATs using ICMP method; must run as root (SUID will do) * This code will work under GNU/Linux only. * @author Christian Grothoff * * This program will send ONE ICMP message using RAW sockets * to the IP address specified as the second argument. Since * it uses RAW sockets, it must be installed SUID or run as 'root'. * In order to keep the security risk of the resulting SUID binary * minimal, the program ONLY opens the RAW socket with root * privileges, then drops them and only then starts to process * command line arguments. The code also does not link against * any shared libraries (except libc) and is strictly minimal * (except for checking for errors). The following list of people * have reviewed this code and considered it safe since the last * modification (if you reviewed it, please have your name added * to the list): * * - Christian Grothoff * - Nathan Evans * - Benjamin Kuperman (22 Aug 2010) */ #if HAVE_CONFIG_H /* Just needed for HAVE_SOCKADDR_IN_SIN_LEN test macro! */ #include "gnunet_config.h" #else #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include #include #include /** * Must match IP given in the server. */ #define DUMMY_IP "192.0.2.86" #define NAT_TRAV_PORT 22225 /** * Must match packet ID used by gnunet-helper-nat-server.c */ #define PACKET_ID 256 /** * IPv4 header. */ struct ip_header { /** * Version (4 bits) + Internet header length (4 bits) */ uint8_t vers_ihl; /** * Type of service */ uint8_t tos; /** * Total length */ uint16_t pkt_len; /** * Identification */ uint16_t id; /** * Flags (3 bits) + Fragment offset (13 bits) */ uint16_t flags_frag_offset; /** * Time to live */ uint8_t ttl; /** * Protocol */ uint8_t proto; /** * Header checksum */ uint16_t checksum; /** * Source address */ uint32_t src_ip; /** * Destination address */ uint32_t dst_ip; }; /** * Format of ICMP packet. */ struct icmp_ttl_exceeded_header { uint8_t type; uint8_t code; uint16_t checksum; uint32_t unused; /* followed by original payload */ }; struct icmp_echo_header { uint8_t type; uint8_t code; uint16_t checksum; uint32_t reserved; }; /** * Beginning of UDP packet. */ struct udp_header { uint16_t src_port; uint16_t dst_port; uint16_t length; uint16_t crc; }; /** * Socket we use to send our fake ICMP replies. */ static int rawsock; /** * Target "dummy" address of the packet we pretend to respond to. */ static struct in_addr dummy; /** * Our "source" port. */ static uint16_t port; /** * CRC-16 for IP/ICMP headers. * * @param data what to calculate the CRC over * @param bytes number of bytes in data (must be multiple of 2) * @return the CRC 16. */ static uint16_t calc_checksum (const uint16_t * data, unsigned int bytes) { uint32_t sum; unsigned int i; sum = 0; for (i = 0; i < bytes / 2; i++) sum += data[i]; sum = (sum & 0xffff) + (sum >> 16); sum = htons (0xffff - sum); return sum; } /** * Send an ICMP message to the target. * * @param my_ip source address * @param other target address */ static void send_icmp_udp (const struct in_addr *my_ip, const struct in_addr *other) { char packet[sizeof (struct ip_header) * 2 + sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct udp_header)]; struct ip_header ip_pkt; struct icmp_ttl_exceeded_header icmp_pkt; struct udp_header udp_pkt; struct sockaddr_in dst; size_t off; int err; /* ip header: send to (known) ip address */ off = 0; ip_pkt.vers_ihl = 0x45; ip_pkt.tos = 0; ip_pkt.pkt_len = htons (sizeof (packet)); ip_pkt.id = htons (PACKET_ID); ip_pkt.flags_frag_offset = 0; ip_pkt.ttl = 128; ip_pkt.proto = IPPROTO_ICMP; ip_pkt.checksum = 0; ip_pkt.src_ip = my_ip->s_addr; ip_pkt.dst_ip = other->s_addr; ip_pkt.checksum = htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header))); memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header)); off += sizeof (struct ip_header); icmp_pkt.type = ICMP_TIME_EXCEEDED; icmp_pkt.code = 0; icmp_pkt.checksum = 0; icmp_pkt.unused = 0; memcpy (&packet[off], &icmp_pkt, sizeof (struct icmp_ttl_exceeded_header)); off += sizeof (struct icmp_ttl_exceeded_header); /* ip header of the presumably 'lost' udp packet */ ip_pkt.vers_ihl = 0x45; ip_pkt.tos = 0; ip_pkt.pkt_len = htons (sizeof (struct ip_header) + sizeof (struct udp_header)); ip_pkt.id = htons (0); ip_pkt.flags_frag_offset = 0; ip_pkt.ttl = 128; ip_pkt.proto = IPPROTO_UDP; ip_pkt.checksum = 0; ip_pkt.src_ip = other->s_addr; ip_pkt.dst_ip = dummy.s_addr; ip_pkt.checksum = htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header))); memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header)); off += sizeof (struct ip_header); /* build UDP header */ udp_pkt.src_port = htons (NAT_TRAV_PORT); udp_pkt.dst_port = htons (NAT_TRAV_PORT); udp_pkt.length = htons (port); udp_pkt.crc = 0; memcpy (&packet[off], &udp_pkt, sizeof (struct udp_header)); off += sizeof (struct udp_header); /* set ICMP checksum */ icmp_pkt.checksum = htons (calc_checksum ((uint16_t *) & packet[sizeof (struct ip_header)], sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct ip_header) + sizeof (struct udp_header))); memcpy (&packet[sizeof (struct ip_header)], &icmp_pkt, sizeof (struct icmp_ttl_exceeded_header)); memset (&dst, 0, sizeof (dst)); dst.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN dst.sin_len = sizeof (struct sockaddr_in); #endif dst.sin_addr = *other; err = sendto (rawsock, packet, sizeof (packet), 0, (struct sockaddr *) &dst, sizeof (dst)); if (err < 0) { fprintf (stderr, "sendto failed: %s\n", strerror (errno)); } else if (sizeof (packet) != (size_t) err) { fprintf (stderr, "Error: partial send of ICMP message\n"); } } /** * Send an ICMP message to the target. * * @param my_ip source address * @param other target address */ static void send_icmp (const struct in_addr *my_ip, const struct in_addr *other) { struct ip_header ip_pkt; struct icmp_ttl_exceeded_header icmp_ttl; struct icmp_echo_header icmp_echo; struct sockaddr_in dst; char packet[sizeof (struct ip_header) * 2 + sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct icmp_echo_header)]; size_t off; int err; /* ip header: send to (known) ip address */ off = 0; ip_pkt.vers_ihl = 0x45; ip_pkt.tos = 0; ip_pkt.pkt_len = htons (sizeof (packet)); ip_pkt.id = htons (PACKET_ID); ip_pkt.flags_frag_offset = 0; ip_pkt.ttl = IPDEFTTL; ip_pkt.proto = IPPROTO_ICMP; ip_pkt.checksum = 0; ip_pkt.src_ip = my_ip->s_addr; ip_pkt.dst_ip = other->s_addr; ip_pkt.checksum = htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header))); memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header)); off = sizeof (ip_pkt); /* icmp reply: time exceeded */ icmp_ttl.type = ICMP_TIME_EXCEEDED; icmp_ttl.code = 0; icmp_ttl.checksum = 0; icmp_ttl.unused = 0; memcpy (&packet[off], &icmp_ttl, sizeof (struct icmp_ttl_exceeded_header)); off += sizeof (struct icmp_ttl_exceeded_header); /* ip header of the presumably 'lost' udp packet */ ip_pkt.vers_ihl = 0x45; ip_pkt.tos = 0; ip_pkt.pkt_len = htons (sizeof (struct ip_header) + sizeof (struct icmp_echo_header)); ip_pkt.id = htons (PACKET_ID); ip_pkt.flags_frag_offset = 0; ip_pkt.ttl = 1; /* real TTL would be 1 on a time exceeded packet */ ip_pkt.proto = IPPROTO_ICMP; ip_pkt.src_ip = other->s_addr; ip_pkt.dst_ip = dummy.s_addr; ip_pkt.checksum = 0; ip_pkt.checksum = htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header))); memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header)); off += sizeof (struct ip_header); icmp_echo.type = ICMP_ECHO; icmp_echo.code = 0; icmp_echo.reserved = htonl (port); icmp_echo.checksum = 0; icmp_echo.checksum = htons (calc_checksum ((uint16_t *) & icmp_echo, sizeof (struct icmp_echo_header))); memcpy (&packet[off], &icmp_echo, sizeof (struct icmp_echo_header)); /* no go back to calculate ICMP packet checksum */ off = sizeof (struct ip_header); icmp_ttl.checksum = htons (calc_checksum ((uint16_t *) & packet[off], sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct ip_header) + sizeof (struct icmp_echo_header))); memcpy (&packet[off], &icmp_ttl, sizeof (struct icmp_ttl_exceeded_header)); /* prepare for transmission */ memset (&dst, 0, sizeof (dst)); dst.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN dst.sin_len = sizeof (struct sockaddr_in); #endif dst.sin_addr = *other; err = sendto (rawsock, packet, sizeof (packet), 0, (struct sockaddr *) &dst, sizeof (dst)); if (err < 0) { fprintf (stderr, "sendto failed: %s\n", strerror (errno)); } else if (sizeof (packet) != (size_t) err) { fprintf (stderr, "Error: partial send of ICMP message\n"); } } int main (int argc, char *const *argv) { const int one = 1; struct in_addr external; struct in_addr target; uid_t uid; unsigned int p; int raw_eno; int global_ret; /* Create an ICMP raw socket for writing (only operation that requires root) */ rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_RAW); raw_eno = errno; /* for later error checking */ /* now drop root privileges */ uid = getuid (); #ifdef HAVE_SETRESUID if (0 != setresuid (uid, uid, uid)) { fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno)); global_ret = 1; goto cleanup; } #else if (0 != (setuid (uid) | seteuid (uid))) { fprintf (stderr, "Failed to setuid: %s\n", strerror (errno)); global_ret = 2; goto cleanup; } #endif if (-1 == rawsock) { fprintf (stderr, "Error opening RAW socket: %s\n", strerror (raw_eno)); global_ret = 3; goto cleanup; } if (0 != setsockopt (rawsock, SOL_SOCKET, SO_BROADCAST, (char *) &one, sizeof (one))) { fprintf (stderr, "setsockopt failed: %s\n", strerror (errno)); global_ret = 4; goto cleanup; } if (0 != setsockopt (rawsock, IPPROTO_IP, IP_HDRINCL, (char *) &one, sizeof (one))) { fprintf (stderr, "setsockopt failed: %s\n", strerror (errno)); global_ret = 5; goto cleanup; } if (4 != argc) { fprintf (stderr, "This program must be started with our IP, the targets external IP, and our port as arguments.\n"); global_ret = 6; goto cleanup; } if ((1 != inet_pton (AF_INET, argv[1], &external)) || (1 != inet_pton (AF_INET, argv[2], &target))) { fprintf (stderr, "Error parsing IPv4 address: %s\n", strerror (errno)); global_ret = 7; goto cleanup; } if ((1 != sscanf (argv[3], "%u", &p)) || (0 == p) || (0xFFFF < p)) { fprintf (stderr, "Error parsing port value `%s'\n", argv[3]); global_ret = 8; goto cleanup; } port = (uint16_t) p; if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) { fprintf (stderr, "Internal error converting dummy IP to binary.\n"); global_ret = 9; goto cleanup; } send_icmp (&external, &target); send_icmp_udp (&external, &target); global_ret = 0; cleanup: if (-1 != rawsock) (void) close (rawsock); return global_ret; } /* end of gnunet-helper-nat-client.c */ gnunet-0.9.3/src/nat/nat_mini.c0000644000175000017500000003715511760502551013274 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file nat/nat_mini.c * @brief functions for interaction with miniupnp; tested with miniupnpc 1.5 * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_nat_lib.h" #include "nat.h" #define LOG(kind,...) GNUNET_log_from (kind, "nat", __VA_ARGS__) /** * How long do we give upnpc to create a mapping? */ #define MAP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) /** * How long do we give upnpc to remove a mapping? */ #define UNMAP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) /** * How often do we check for changes in the mapping? */ #define MAP_REFRESH_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) /** * Opaque handle to cancel "GNUNET_NAT_mini_get_external_ipv4" operation. */ struct GNUNET_NAT_ExternalHandle { /** * Function to call with the result. */ GNUNET_NAT_IPCallback cb; /** * Closure for 'cb'. */ void *cb_cls; /** * Read task. */ GNUNET_SCHEDULER_TaskIdentifier task; /** * Handle to 'external-ip' process. */ struct GNUNET_OS_Process *eip; /** * Handle to stdout pipe of 'external-ip'. */ struct GNUNET_DISK_PipeHandle *opipe; /** * Read handle of 'opipe'. */ const struct GNUNET_DISK_FileHandle *r; /** * When should this operation time out? */ struct GNUNET_TIME_Absolute timeout; /** * Number of bytes in 'buf' that are valid. */ size_t off; /** * Destination of our read operation (output of 'external-ip'). */ char buf[17]; }; /** * Read the output of 'external-ip' into buf. When complete, parse the * address and call our callback. * * @param cls the 'struct GNUNET_NAT_ExternalHandle' * @param tc scheduler context */ static void read_external_ipv4 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_NAT_ExternalHandle *eh = cls; ssize_t ret; struct in_addr addr; int iret; eh->task = GNUNET_SCHEDULER_NO_TASK; if (GNUNET_YES == GNUNET_NETWORK_fdset_handle_isset (tc->read_ready, eh->r)) ret = GNUNET_DISK_file_read (eh->r, &eh->buf[eh->off], sizeof (eh->buf) - eh->off); else ret = -1; /* error reading, timeout, etc. */ if (ret > 0) { /* try to read more */ eh->off += ret; eh->task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining (eh->timeout), eh->r, &read_external_ipv4, eh); return; } iret = GNUNET_NO; if ((eh->off > 7) && (eh->buf[eh->off - 1] == '\n')) { eh->buf[eh->off - 1] = '\0'; if (1 == inet_pton (AF_INET, eh->buf, &addr)) { if (addr.s_addr == 0) iret = GNUNET_NO; /* got 0.0.0.0 */ else iret = GNUNET_OK; } } eh->cb (eh->cb_cls, (iret == GNUNET_OK) ? &addr : NULL); GNUNET_NAT_mini_get_external_ipv4_cancel (eh); } /** * Try to get the external IPv4 address of this peer. * * @param timeout when to fail * @param cb function to call with result * @param cb_cls closure for 'cb' * @return handle for cancellation (can only be used until 'cb' is called), NULL on error */ struct GNUNET_NAT_ExternalHandle * GNUNET_NAT_mini_get_external_ipv4 (struct GNUNET_TIME_Relative timeout, GNUNET_NAT_IPCallback cb, void *cb_cls) { struct GNUNET_NAT_ExternalHandle *eh; if (GNUNET_SYSERR == GNUNET_OS_check_helper_binary ("external-ip")) return NULL; eh = GNUNET_malloc (sizeof (struct GNUNET_NAT_ExternalHandle)); eh->cb = cb; eh->cb_cls = cb_cls; eh->opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); if (NULL == eh->opipe) { GNUNET_free (eh); return NULL; } eh->eip = GNUNET_OS_start_process (GNUNET_NO, NULL, eh->opipe, "external-ip", "external-ip", NULL); if (NULL == eh->eip) { GNUNET_DISK_pipe_close (eh->opipe); GNUNET_free (eh); return NULL; } GNUNET_DISK_pipe_close_end (eh->opipe, GNUNET_DISK_PIPE_END_WRITE); eh->timeout = GNUNET_TIME_relative_to_absolute (timeout); eh->r = GNUNET_DISK_pipe_handle (eh->opipe, GNUNET_DISK_PIPE_END_READ); eh->task = GNUNET_SCHEDULER_add_read_file (timeout, eh->r, &read_external_ipv4, eh); return eh; } /** * Cancel operation. * * @param eh operation to cancel */ void GNUNET_NAT_mini_get_external_ipv4_cancel (struct GNUNET_NAT_ExternalHandle *eh) { (void) GNUNET_OS_process_kill (eh->eip, SIGKILL); GNUNET_OS_process_destroy (eh->eip); GNUNET_DISK_pipe_close (eh->opipe); if (GNUNET_SCHEDULER_NO_TASK != eh->task) GNUNET_SCHEDULER_cancel (eh->task); GNUNET_free (eh); } /** * Handle to a mapping created with upnpc. */ struct GNUNET_NAT_MiniHandle { /** * Function to call on mapping changes. */ GNUNET_NAT_AddressCallback ac; /** * Closure for 'ac'. */ void *ac_cls; /** * Command used to install the map. */ struct GNUNET_OS_CommandHandle *map_cmd; /** * Command used to refresh our map information. */ struct GNUNET_OS_CommandHandle *refresh_cmd; /** * Command used to remove the mapping. */ struct GNUNET_OS_CommandHandle *unmap_cmd; /** * Our current external mapping (if we have one). */ struct sockaddr_in current_addr; /** * We check the mapping periodically to see if it * still works. This task triggers the check. */ GNUNET_SCHEDULER_TaskIdentifier refresh_task; /** * Are we mapping TCP or UDP? */ int is_tcp; /** * Did we succeed with creating a mapping? */ int did_map; /** * Did we find our mapping during refresh scan? */ int found; /** * Which port are we mapping? */ uint16_t port; }; /** * Run upnpc -l to find out if our mapping changed. * * @param cls the 'struct GNUNET_NAT_MiniHandle' * @param tc scheduler context */ static void do_refresh (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Process the output from the 'upnpc -r' command. * * @param cls the 'struct GNUNET_NAT_MiniHandle' * @param line line of output, NULL at the end */ static void process_map_output (void *cls, const char *line); /** * Process the output from 'upnpc -l' to see if our * external mapping changed. If so, do the notifications. * * @param cls the 'struct GNUNET_NAT_MiniHandle' * @param line line of output, NULL at the end */ static void process_refresh_output (void *cls, const char *line) { struct GNUNET_NAT_MiniHandle *mini = cls; char pstr[9]; const char *s; unsigned int nport; struct in_addr exip; if (NULL == line) { GNUNET_OS_command_stop (mini->refresh_cmd); mini->refresh_cmd = NULL; if (mini->found == GNUNET_NO) { /* mapping disappeared, try to re-create */ if (mini->did_map) { mini->ac (mini->ac_cls, GNUNET_NO, (const struct sockaddr *) &mini->current_addr, sizeof (mini->current_addr)); mini->did_map = GNUNET_NO; } GNUNET_snprintf (pstr, sizeof (pstr), "%u", (unsigned int) mini->port); mini->map_cmd = GNUNET_OS_command_run (&process_map_output, mini, MAP_TIMEOUT, "upnpc", "upnpc", "-r", pstr, mini->is_tcp ? "tcp" : "udp", NULL); if (NULL != mini->map_cmd) return; } mini->refresh_task = GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ, &do_refresh, mini); return; } if (!mini->did_map) return; /* never mapped, won't find our mapping anyway */ /* we're looking for output of the form: * "ExternalIPAddress = 12.134.41.124" */ s = strstr (line, "ExternalIPAddress = "); if (NULL != s) { s += strlen ("ExternalIPAddress = "); if (1 != inet_pton (AF_INET, s, &exip)) return; /* skip */ if (exip.s_addr == mini->current_addr.sin_addr.s_addr) return; /* no change */ /* update mapping */ mini->ac (mini->ac_cls, GNUNET_NO, (const struct sockaddr *) &mini->current_addr, sizeof (mini->current_addr)); mini->current_addr.sin_addr = exip; mini->ac (mini->ac_cls, GNUNET_YES, (const struct sockaddr *) &mini->current_addr, sizeof (mini->current_addr)); return; } /* * we're looking for output of the form: * * "0 TCP 3000->192.168.2.150:3000 'libminiupnpc' ''" * "1 UDP 3001->192.168.2.150:3001 'libminiupnpc' ''" * * the pattern we look for is: * * "%s TCP PORT->STRING:OURPORT *" or * "%s UDP PORT->STRING:OURPORT *" */ GNUNET_snprintf (pstr, sizeof (pstr), ":%u ", mini->port); if (NULL == (s = strstr (line, "->"))) return; /* skip */ if (NULL == strstr (s, pstr)) return; /* skip */ if (1 != SSCANF (line, (mini->is_tcp) ? "%*u TCP %u->%*s:%*u %*s" : "%*u UDP %u->%*s:%*u %*s", &nport)) return; /* skip */ mini->found = GNUNET_YES; if (nport == ntohs (mini->current_addr.sin_port)) return; /* no change */ /* external port changed, update mapping */ mini->ac (mini->ac_cls, GNUNET_NO, (const struct sockaddr *) &mini->current_addr, sizeof (mini->current_addr)); mini->current_addr.sin_port = htons ((uint16_t) nport); mini->ac (mini->ac_cls, GNUNET_YES, (const struct sockaddr *) &mini->current_addr, sizeof (mini->current_addr)); } /** * Run upnpc -l to find out if our mapping changed. * * @param cls the 'struct GNUNET_NAT_MiniHandle' * @param tc scheduler context */ static void do_refresh (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_NAT_MiniHandle *mini = cls; mini->refresh_task = GNUNET_SCHEDULER_NO_TASK; mini->found = GNUNET_NO; mini->refresh_cmd = GNUNET_OS_command_run (&process_refresh_output, mini, MAP_TIMEOUT, "upnpc", "upnpc", "-l", NULL); } /** * Process the output from the 'upnpc -r' command. * * @param cls the 'struct GNUNET_NAT_MiniHandle' * @param line line of output, NULL at the end */ static void process_map_output (void *cls, const char *line) { struct GNUNET_NAT_MiniHandle *mini = cls; const char *ipaddr; char *ipa; const char *pstr; unsigned int port; if (NULL == line) { GNUNET_OS_command_stop (mini->map_cmd); mini->map_cmd = NULL; mini->refresh_task = GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ, &do_refresh, mini); return; } /* * The upnpc output we're after looks like this: * * "external 87.123.42.204:3000 TCP is redirected to internal 192.168.2.150:3000" */ if ((NULL == (ipaddr = strstr (line, " "))) || (NULL == (pstr = strstr (ipaddr, ":"))) || (1 != SSCANF (pstr + 1, "%u", &port))) { return; /* skip line */ } ipa = GNUNET_strdup (ipaddr + 1); strstr (ipa, ":")[0] = '\0'; if (1 != inet_pton (AF_INET, ipa, &mini->current_addr.sin_addr)) { GNUNET_free (ipa); return; /* skip line */ } GNUNET_free (ipa); mini->current_addr.sin_port = htons (port); mini->current_addr.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN mini->current_addr.sin_len = sizeof (struct sockaddr_in); #endif mini->did_map = GNUNET_YES; mini->ac (mini->ac_cls, GNUNET_YES, (const struct sockaddr *) &mini->current_addr, sizeof (mini->current_addr)); } /** * Start mapping the given port using (mini)upnpc. This function * should typically not be used directly (it is used within the * general-purpose 'GNUNET_NAT_register' code). However, it can be * used if specifically UPnP-based NAT traversal is to be used or * tested. * * @param port port to map * @param is_tcp GNUNET_YES to map TCP, GNUNET_NO for UDP * @param ac function to call with mapping result * @param ac_cls closure for 'ac' * @return NULL on error (no 'upnpc' installed) */ struct GNUNET_NAT_MiniHandle * GNUNET_NAT_mini_map_start (uint16_t port, int is_tcp, GNUNET_NAT_AddressCallback ac, void *ac_cls) { struct GNUNET_NAT_MiniHandle *ret; char pstr[6]; if (GNUNET_SYSERR == GNUNET_OS_check_helper_binary ("upnpc")) return NULL; ret = GNUNET_malloc (sizeof (struct GNUNET_NAT_MiniHandle)); ret->ac = ac; ret->ac_cls = ac_cls; ret->is_tcp = is_tcp; ret->port = port; GNUNET_snprintf (pstr, sizeof (pstr), "%u", (unsigned int) port); ret->map_cmd = GNUNET_OS_command_run (&process_map_output, ret, MAP_TIMEOUT, "upnpc", "upnpc", "-r", pstr, is_tcp ? "tcp" : "udp", NULL); if (NULL != ret->map_cmd) return ret; ret->refresh_task = GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ, &do_refresh, ret); return ret; } /** * Process output from our 'unmap' command. * * @param cls the 'struct GNUNET_NAT_MiniHandle' * @param line line of output, NULL at the end */ static void process_unmap_output (void *cls, const char *line) { struct GNUNET_NAT_MiniHandle *mini = cls; if (NULL == line) { LOG (GNUNET_ERROR_TYPE_DEBUG, "UPnP unmap done\n"); GNUNET_OS_command_stop (mini->unmap_cmd); mini->unmap_cmd = NULL; GNUNET_free (mini); return; } /* we don't really care about the output... */ } /** * Remove a mapping created with (mini)upnpc. Calling * this function will give 'upnpc' 1s to remove tha mapping, * so while this function is non-blocking, a task will be * left with the scheduler for up to 1s past this call. * * @param mini the handle */ void GNUNET_NAT_mini_map_stop (struct GNUNET_NAT_MiniHandle *mini) { char pstr[6]; if (GNUNET_SCHEDULER_NO_TASK != mini->refresh_task) { GNUNET_SCHEDULER_cancel (mini->refresh_task); mini->refresh_task = GNUNET_SCHEDULER_NO_TASK; } if (mini->refresh_cmd != NULL) { GNUNET_OS_command_stop (mini->refresh_cmd); mini->refresh_cmd = NULL; } if (!mini->did_map) { if (mini->map_cmd != NULL) { GNUNET_OS_command_stop (mini->map_cmd); mini->map_cmd = NULL; } GNUNET_free (mini); return; } mini->ac (mini->ac_cls, GNUNET_NO, (const struct sockaddr *) &mini->current_addr, sizeof (mini->current_addr)); /* Note: oddly enough, deletion uses the external port whereas * addition uses the internal port; this rarely matters since they * often are the same, but it might... */ GNUNET_snprintf (pstr, sizeof (pstr), "%u", (unsigned int) ntohs (mini->current_addr.sin_port)); LOG (GNUNET_ERROR_TYPE_DEBUG, "Unmapping port %u with UPnP\n", ntohs (mini->current_addr.sin_port)); mini->unmap_cmd = GNUNET_OS_command_run (&process_unmap_output, mini, UNMAP_TIMEOUT, "upnpc", "upnpc", "-d", pstr, mini->is_tcp ? "tcp" : "udp", NULL); } /* end of nat_mini.c */ gnunet-0.9.3/src/testing/0000755000175000017500000000000011763406750012301 500000000000000gnunet-0.9.3/src/testing/test_testing_data_topology_erdos_renyi.conf0000644000175000017500000000020611615731356023130 00000000000000@INLINE@ test_testing_defaults.conf [PATHS] DEFAULTCONFIG = test_testing_data_topology_clique.conf [TESTING] TOPOLOGY = ERDOS_RENYI gnunet-0.9.3/src/testing/testing_peergroup.c0000644000175000017500000010277511760502551016137 00000000000000/* This file is part of GNUnet (C) 2008-2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testing/testing_peergroup.c * @brief API implementation for easy peer group creation * @author Nathan Evans * @author Christian Grothoff * */ #include "platform.h" #include "gnunet_constants.h" #include "gnunet_arm_service.h" #include "gnunet_testing_lib.h" #include "gnunet_core_service.h" #include "gnunet_disk_lib.h" /** Globals **/ #define DEFAULT_CONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) #define DEFAULT_CONNECT_ATTEMPTS 2 /** Struct definitions **/ struct PeerGroupStartupContext { struct GNUNET_TESTING_PeerGroup *pg; const struct GNUNET_CONFIGURATION_Handle *cfg; unsigned int total; unsigned int peers_left; unsigned long long max_concurrent_connections; /** * Maximum attemps to connect two daemons. */ unsigned long long connect_attempts; /** * How long to spend trying to establish all the connections? */ struct GNUNET_TIME_Relative connect_timeout; unsigned long long max_concurrent_ssh; struct GNUNET_TIME_Absolute timeout; GNUNET_TESTING_NotifyConnection connect_cb; GNUNET_TESTING_NotifyCompletion peergroup_cb; /** * Closure for all peergroup callbacks. */ void *cls; const struct GNUNET_TESTING_Host *hostnames; /** * FIXME document */ enum GNUNET_TESTING_Topology topology; float topology_percentage; float topology_probability; /** * FIXME document */ enum GNUNET_TESTING_Topology restrict_topology; /** * FIXME document */ char *restrict_transports; /** * Initial connections */ enum GNUNET_TESTING_Topology connect_topology; enum GNUNET_TESTING_TopologyOption connect_topology_option; double connect_topology_option_modifier; int verbose; struct ProgressMeter *hostkey_meter; struct ProgressMeter *peer_start_meter; struct ProgressMeter *connect_meter; /** * Task used to kill the peergroup. */ GNUNET_SCHEDULER_TaskIdentifier die_task; char *fail_reason; /** * Variable used to store the number of connections we should wait for. */ unsigned int expected_connections; /** * Time when the connecting peers was started. */ struct GNUNET_TIME_Absolute connect_start_time; /** * The total number of connections that have been created so far. */ unsigned int total_connections; /** * The total number of connections that have failed so far. */ unsigned int failed_connections; /** * File handle to write out topology in dot format. */ struct GNUNET_DISK_FileHandle *topology_output_file; }; struct TopologyOutputContext { struct GNUNET_DISK_FileHandle *file; GNUNET_TESTING_NotifyCompletion notify_cb; void *notify_cb_cls; }; /** * Simple struct to keep track of progress, and print a * percentage meter for long running tasks. */ struct ProgressMeter { /** * Total number of tasks to complete. */ unsigned int total; /** * Print percentage done after modnum tasks. */ unsigned int modnum; /** * Print a . each dotnum tasks. */ unsigned int dotnum; /** * Total number completed thus far. */ unsigned int completed; /** * Whether or not to print. */ int print; /** * Startup string for progress meter. */ char *startup_string; }; /** Utility functions **/ /** * Create a meter to keep track of the progress of some task. * * @param total the total number of items to complete * @param start_string a string to prefix the meter with (if printing) * @param print GNUNET_YES to print the meter, GNUNET_NO to count * internally only * * @return the progress meter */ static struct ProgressMeter * create_meter (unsigned int total, char *start_string, int print) { struct ProgressMeter *ret; ret = GNUNET_malloc (sizeof (struct ProgressMeter)); ret->print = print; ret->total = total; ret->modnum = (total / 4 == 0) ? 1 : (total / 4); ret->dotnum = (total / 50) + 1; if (start_string != NULL) ret->startup_string = GNUNET_strdup (start_string); else ret->startup_string = GNUNET_strdup (""); return ret; } /** * Update progress meter (increment by one). * * @param meter the meter to update and print info for * * @return GNUNET_YES if called the total requested, * GNUNET_NO if more items expected */ static int update_meter (struct ProgressMeter *meter) { if (meter->print == GNUNET_YES) { if (meter->completed % meter->modnum == 0) { if (meter->completed == 0) { FPRINTF (stdout, "%sProgress: [0%%", meter->startup_string); } else FPRINTF (stdout, "%d%%", (int) (((float) meter->completed / meter->total) * 100)); } else if (meter->completed % meter->dotnum == 0) FPRINTF (stdout, "%s", "."); if (meter->completed + 1 == meter->total) FPRINTF (stdout, "%d%%]\n", 100); fflush (stdout); } meter->completed++; if (meter->completed == meter->total) return GNUNET_YES; return GNUNET_NO; } /** * Reset progress meter. * * @param meter the meter to reset * * @return GNUNET_YES if meter reset, * GNUNET_SYSERR on error */ static int reset_meter (struct ProgressMeter *meter) { if (meter == NULL) return GNUNET_SYSERR; meter->completed = 0; return GNUNET_YES; } /** * Release resources for meter * * @param meter the meter to free */ static void free_meter (struct ProgressMeter *meter) { GNUNET_free_non_null (meter->startup_string); GNUNET_free (meter); } /** Functions for creating, starting and connecting the peergroup **/ /** * Check whether peers successfully shut down. */ static void internal_shutdown_callback (void *cls, const char *emsg) { struct PeerGroupStartupContext *pg_start_ctx = cls; if (emsg != NULL) pg_start_ctx->peergroup_cb (pg_start_ctx->cls, emsg); else pg_start_ctx->peergroup_cb (pg_start_ctx->cls, pg_start_ctx->fail_reason); } /** * Check if the get_handle is being used, if so stop the request. Either * way, schedule the end_badly_cont function which actually shuts down the * test. */ static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerGroupStartupContext *pg_start_ctx = cls; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failing peer group startup with error: `%s'!\n", pg_start_ctx->fail_reason); GNUNET_TESTING_daemons_stop (pg_start_ctx->pg, GNUNET_TIME_absolute_get_remaining (pg_start_ctx->timeout), &internal_shutdown_callback, pg_start_ctx); if (pg_start_ctx->hostkey_meter != NULL) { free_meter (pg_start_ctx->hostkey_meter); pg_start_ctx->hostkey_meter = NULL; } if (pg_start_ctx->peer_start_meter != NULL) { free_meter (pg_start_ctx->peer_start_meter); pg_start_ctx->peer_start_meter = NULL; } if (pg_start_ctx->connect_meter != NULL) { free_meter (pg_start_ctx->connect_meter); pg_start_ctx->connect_meter = NULL; } } /** * This function is called whenever a connection attempt is finished between two of * the started peers (started with GNUNET_TESTING_daemons_start). The total * number of times this function is called should equal the number returned * from the GNUNET_TESTING_connect_topology call. * * The emsg variable is NULL on success (peers connected), and non-NULL on * failure (peers failed to connect). */ static void internal_topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, uint32_t distance, const struct GNUNET_CONFIGURATION_Handle *first_cfg, const struct GNUNET_CONFIGURATION_Handle *second_cfg, struct GNUNET_TESTING_Daemon *first_daemon, struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) { struct PeerGroupStartupContext *pg_start_ctx = cls; char *temp_str; char *second_str; int temp; #if TIMING unsigned long long duration; unsigned long long total_duration; unsigned int new_connections; unsigned int new_failed_connections; double conns_per_sec_recent; double conns_per_sec_total; double failed_conns_per_sec_recent; double failed_conns_per_sec_total; #endif #if TIMING if (GNUNET_TIME_absolute_get_difference (connect_last_time, GNUNET_TIME_absolute_get ()).rel_value > GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, CONN_UPDATE_DURATION).rel_value) { /* Get number of new connections */ new_connections = total_connections - previous_connections; /* Get number of new FAILED connections */ new_failed_connections = failed_connections - previous_failed_connections; /* Get duration in seconds */ duration = GNUNET_TIME_absolute_get_difference (connect_last_time, GNUNET_TIME_absolute_get ()).rel_value / 1000; total_duration = GNUNET_TIME_absolute_get_difference (connect_start_time, GNUNET_TIME_absolute_get ()).rel_value / 1000; failed_conns_per_sec_recent = (double) new_failed_connections / duration; failed_conns_per_sec_total = (double) failed_connections / total_duration; conns_per_sec_recent = (double) new_connections / duration; conns_per_sec_total = (double) total_connections / total_duration; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Recent: %.2f/s, Total: %.2f/s, Recent failed: %.2f/s, total failed %.2f/s\n", conns_per_sec_recent, CONN_UPDATE_DURATION, conns_per_sec_total, failed_conns_per_sec_recent, failed_conns_per_sec_total); connect_last_time = GNUNET_TIME_absolute_get (); previous_connections = total_connections; previous_failed_connections = failed_connections; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "have %u total_connections, %u failed\n", total_connections, failed_connections); } #endif if (emsg == NULL) { pg_start_ctx->total_connections++; #if VERBOSE > 1 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s, distance %u\n", first_daemon->shortname, second_daemon->shortname, distance); #endif if (pg_start_ctx->topology_output_file != NULL) { second_str = GNUNET_strdup (GNUNET_i2s (second)); temp = GNUNET_asprintf (&temp_str, "\t\"%s\" -- \"%s\"\n", GNUNET_i2s (first), second_str); GNUNET_free (second_str); if (temp > 0) GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str, temp); GNUNET_free (temp_str); } } else { pg_start_ctx->failed_connections++; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to connect peer %s to peer %s with error :\n%s\n", first_daemon->shortname, second_daemon->shortname, emsg); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect peer %s to peer %s with error :\n%s\n", first_daemon->shortname, second_daemon->shortname, emsg); #endif } GNUNET_assert (pg_start_ctx->connect_meter != NULL); if (pg_start_ctx->connect_cb != NULL) pg_start_ctx->connect_cb (pg_start_ctx->cls, first, second, distance, first_cfg, second_cfg, first_daemon, second_daemon, emsg); if (GNUNET_YES != update_meter (pg_start_ctx->connect_meter)) { /* No finished yet */ return; } #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created %d total connections, which is our target number! Starting next phase of testing.\n", pg_start_ctx->total_connections); #endif #if TIMING total_duration = GNUNET_TIME_absolute_get_difference (connect_start_time, GNUNET_TIME_absolute_get ()).rel_value / 1000; failed_conns_per_sec_total = (double) failed_connections / total_duration; conns_per_sec_total = (double) total_connections / total_duration; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Overall connection info --- Total: %u, Total Failed %u/s\n", total_connections, failed_connections); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Overall connection info --- Total: %.2f/s, Total Failed %.2f/s\n", conns_per_sec_total, failed_conns_per_sec_total); #endif GNUNET_assert (pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK); GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); /* Call final callback, signifying that the peer group has been started and connected */ if (pg_start_ctx->peergroup_cb != NULL) pg_start_ctx->peergroup_cb (pg_start_ctx->cls, NULL); if (pg_start_ctx->topology_output_file != NULL) { temp = GNUNET_asprintf (&temp_str, "}\n"); if (temp > 0) GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str, temp); GNUNET_free (temp_str); GNUNET_DISK_file_close (pg_start_ctx->topology_output_file); } GNUNET_free_non_null (pg_start_ctx->fail_reason); if (NULL != pg_start_ctx->hostkey_meter) free_meter(pg_start_ctx->hostkey_meter); if (NULL != pg_start_ctx->peer_start_meter) free_meter(pg_start_ctx->peer_start_meter); if (NULL != pg_start_ctx->connect_meter) free_meter(pg_start_ctx->connect_meter); GNUNET_free (pg_start_ctx); } /** * Callback called for each started daemon. * * @param cls Clause (PG Context). * @param id PeerIdentidy of started daemon. * @param cfg Configuration used by the daemon. * @param d Handle for the daemon. * @param emsg Error message, NULL on success. */ static void internal_peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { struct PeerGroupStartupContext *pg_start_ctx = cls; if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to start daemon with error: `%s'\n", emsg); return; } GNUNET_assert (id != NULL); #if VERBOSE > 1 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", (pg_start_ctx->total - pg_start_ctx->peers_left) + 1, pg_start_ctx->total); #endif pg_start_ctx->peers_left--; if (NULL == pg_start_ctx->peer_start_meter) { /* Cancelled Ctrl-C or error */ return; } if (GNUNET_YES == update_meter (pg_start_ctx->peer_start_meter)) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All %d daemons started, now connecting peers!\n", pg_start_ctx->total); #endif GNUNET_assert (pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK); GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); pg_start_ctx->expected_connections = UINT_MAX; // FIXME: why whould peers_left be != 0?? Or pg NULL? if ((pg_start_ctx->pg != NULL) && (pg_start_ctx->peers_left == 0)) { pg_start_ctx->connect_start_time = GNUNET_TIME_absolute_get (); pg_start_ctx->expected_connections = GNUNET_TESTING_connect_topology (pg_start_ctx->pg, pg_start_ctx->connect_topology, pg_start_ctx->connect_topology_option, pg_start_ctx->connect_topology_option_modifier, pg_start_ctx->connect_timeout, pg_start_ctx->connect_attempts, NULL, NULL); pg_start_ctx->connect_meter = create_meter (pg_start_ctx->expected_connections, "Peer connection ", pg_start_ctx->verbose); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n", pg_start_ctx->expected_connections); } if (pg_start_ctx->expected_connections == 0) { GNUNET_free_non_null (pg_start_ctx->fail_reason); pg_start_ctx->fail_reason = GNUNET_strdup ("from connect topology (bad return)"); pg_start_ctx->die_task = GNUNET_SCHEDULER_add_now (&end_badly, pg_start_ctx); return; } GNUNET_free_non_null (pg_start_ctx->fail_reason); pg_start_ctx->fail_reason = GNUNET_strdup ("from connect topology (timeout)"); pg_start_ctx->die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (pg_start_ctx->timeout), &end_badly, pg_start_ctx); } } /** * Callback indicating that the hostkey was created for a peer. * * @param cls NULL * @param id the peer identity * @param d the daemon handle (pretty useless at this point, remove?) * @param emsg non-null on failure */ static void internal_hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, struct GNUNET_TESTING_Daemon *d, const char *emsg) { struct PeerGroupStartupContext *pg_start_ctx = cls; unsigned int create_expected_connections; if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Hostkey callback received error: %s\n", emsg); } #if VERBOSE > 1 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostkey (%d/%d) created for peer `%s'\n", pg_start_ctx->total - pg_start_ctx->peers_left + 1, pg_start_ctx->total, GNUNET_i2s (id)); #endif pg_start_ctx->peers_left--; if (GNUNET_YES == update_meter (pg_start_ctx->hostkey_meter)) { GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); GNUNET_free_non_null (pg_start_ctx->fail_reason); /* Set up task in case topology creation doesn't finish * within a reasonable amount of time */ pg_start_ctx->fail_reason = GNUNET_strdup ("from create_topology"); pg_start_ctx->die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (pg_start_ctx->timeout), &end_badly, pg_start_ctx); pg_start_ctx->peers_left = pg_start_ctx->total; /* Reset counter */ create_expected_connections = GNUNET_TESTING_create_topology (pg_start_ctx->pg, pg_start_ctx->topology, pg_start_ctx->restrict_topology, pg_start_ctx->restrict_transports); if (create_expected_connections > 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Topology set up, have %u expected connections, now starting peers!\n", create_expected_connections); GNUNET_TESTING_daemons_continue_startup (pg_start_ctx->pg); } else { GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); GNUNET_free_non_null (pg_start_ctx->fail_reason); pg_start_ctx->fail_reason = GNUNET_strdup ("from create topology (bad return)"); pg_start_ctx->die_task = GNUNET_SCHEDULER_add_now (&end_badly, pg_start_ctx); return; } GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); GNUNET_free_non_null (pg_start_ctx->fail_reason); pg_start_ctx->fail_reason = GNUNET_strdup ("from continue startup (timeout)"); pg_start_ctx->die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (pg_start_ctx->timeout), &end_badly, pg_start_ctx); } } /** * Prototype of a callback function indicating that two peers * are currently connected. * * @param cls closure * @param first peer id for first daemon * @param second peer id for the second daemon * @param emsg error message (NULL on success) */ void write_topology_cb (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, const char *emsg) { struct TopologyOutputContext *topo_ctx; int temp; char *temp_str; char *temp_pid2; topo_ctx = (struct TopologyOutputContext *) cls; GNUNET_assert (topo_ctx->file != NULL); if ((emsg == NULL) && (first != NULL) && (second != NULL)) { GNUNET_assert (first != NULL); GNUNET_assert (second != NULL); temp_pid2 = GNUNET_strdup (GNUNET_i2s (second)); temp = GNUNET_asprintf (&temp_str, "\t\"%s\" -- \"%s\"\n", GNUNET_i2s (first), temp_pid2); GNUNET_free (temp_pid2); GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp); } else if ((emsg == NULL) && (first == NULL) && (second == NULL)) { temp = GNUNET_asprintf (&temp_str, "}\n"); GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp); GNUNET_DISK_file_close (topo_ctx->file); topo_ctx->notify_cb (topo_ctx->notify_cb_cls, NULL); GNUNET_free (topo_ctx); } else { temp = GNUNET_asprintf (&temp_str, "}\n"); GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp); GNUNET_DISK_file_close (topo_ctx->file); topo_ctx->notify_cb (topo_ctx->notify_cb_cls, emsg); GNUNET_free (topo_ctx); } } /** * Print current topology to a graphviz readable file. * * @param pg a currently running peergroup to print to file * @param output_filename the file to write the topology to * @param notify_cb callback to call upon completion or failure * @param notify_cb_cls closure for notify_cb * */ void GNUNET_TESTING_peergroup_topology_to_file (struct GNUNET_TESTING_PeerGroup *pg, const char *output_filename, GNUNET_TESTING_NotifyCompletion notify_cb, void *notify_cb_cls) { struct TopologyOutputContext *topo_ctx; int temp; char *temp_str; topo_ctx = GNUNET_malloc (sizeof (struct TopologyOutputContext)); topo_ctx->notify_cb = notify_cb; topo_ctx->notify_cb_cls = notify_cb_cls; topo_ctx->file = GNUNET_DISK_file_open (output_filename, GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_CREATE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (topo_ctx->file == NULL) { notify_cb (notify_cb_cls, "Failed to open output file!"); GNUNET_free (topo_ctx); return; } temp = GNUNET_asprintf (&temp_str, "strict graph G {\n"); if (temp > 0) GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp); GNUNET_free_non_null (temp_str); GNUNET_TESTING_get_topology (pg, &write_topology_cb, topo_ctx); } /** * Start a peer group with a given number of peers. Notify * on completion of peer startup and connection based on given * topological constraints. Optionally notify on each * established connection. * * @param cfg configuration template to use * @param total number of daemons to start * @param timeout total time allowed for peers to start * @param connect_cb function to call each time two daemons are connected * @param peergroup_cb function to call once all peers are up and connected * @param peergroup_cls closure for peergroup callbacks * @param hostnames linked list of host structs to use to start peers on * (NULL to run on localhost only) * * @return NULL on error, otherwise handle to control peer group */ struct GNUNET_TESTING_PeerGroup * GNUNET_TESTING_peergroup_start (const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned int total, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_NotifyConnection connect_cb, GNUNET_TESTING_NotifyCompletion peergroup_cb, void *peergroup_cls, const struct GNUNET_TESTING_Host *hostnames) { struct PeerGroupStartupContext *pg_start_ctx; char *temp_str; int temp; struct GNUNET_TIME_Relative rtimeout; GNUNET_assert (total > 0); GNUNET_assert (cfg != NULL); pg_start_ctx = GNUNET_malloc (sizeof (struct PeerGroupStartupContext)); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_attempts", &pg_start_ctx->connect_attempts)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", "testing", "connect_attempts"); GNUNET_free (pg_start_ctx); return NULL; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "CONNECT_TIMEOUT", &pg_start_ctx->connect_timeout)) { pg_start_ctx->connect_timeout = DEFAULT_CONNECT_TIMEOUT; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "max_outstanding_connections", &pg_start_ctx->max_concurrent_connections)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", "testing", "max_outstanding_connections"); GNUNET_free (pg_start_ctx); return NULL; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "max_concurrent_ssh", &pg_start_ctx->max_concurrent_ssh)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", "testing", "max_concurrent_ssh"); GNUNET_free (pg_start_ctx); return NULL; } if (GNUNET_SYSERR == (pg_start_ctx->verbose = GNUNET_CONFIGURATION_get_value_yesno (cfg, "testing", "use_progressbars"))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", "testing", "use_progressbars"); GNUNET_free (pg_start_ctx); return NULL; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "PEERGROUP_TIMEOUT", &rtimeout)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", "testing", "PEERGROUP_TIMEOUT"); GNUNET_free (pg_start_ctx); return NULL; } pg_start_ctx->timeout = GNUNET_TIME_relative_to_absolute (rtimeout); /* Read topology related options from the configuration file */ temp_str = NULL; if ((GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "topology", &temp_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get (&pg_start_ctx->topology, temp_str))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid topology `%s' given for section %s option %s\n", temp_str, "TESTING", "TOPOLOGY"); pg_start_ctx->topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */ } GNUNET_free_non_null (temp_str); if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "topology_output_file", &temp_str)) { pg_start_ctx->topology_output_file = GNUNET_DISK_file_open (temp_str, GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_CREATE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (pg_start_ctx->topology_output_file != NULL) { GNUNET_free (temp_str); temp = GNUNET_asprintf (&temp_str, "strict graph G {\n"); if (temp > 0) GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str, temp); } GNUNET_free (temp_str); } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "percentage", &temp_str)) pg_start_ctx->topology_percentage = 0.5; else { pg_start_ctx->topology_percentage = atof (temp_str); GNUNET_free (temp_str); } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "probability", &temp_str)) pg_start_ctx->topology_probability = 0.5; else { pg_start_ctx->topology_probability = atof (temp_str); GNUNET_free (temp_str); } if ((GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "connect_topology", &temp_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get (&pg_start_ctx->connect_topology, temp_str))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid connect topology `%s' given for section %s option %s\n", temp_str, "TESTING", "CONNECT_TOPOLOGY"); } GNUNET_free_non_null (temp_str); if ((GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "connect_topology_option", &temp_str)) && (GNUNET_NO == GNUNET_TESTING_topology_option_get (&pg_start_ctx->connect_topology_option, temp_str))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid connect topology option `%s' given for section %s option %s\n", temp_str, "TESTING", "CONNECT_TOPOLOGY_OPTION"); pg_start_ctx->connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */ } GNUNET_free_non_null (temp_str); if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "connect_topology_option_modifier", &temp_str)) { if (SSCANF (temp_str, "%lf", &pg_start_ctx->connect_topology_option_modifier) != 1) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), temp_str, "connect_topology_option_modifier", "TESTING"); GNUNET_free (temp_str); GNUNET_free (pg_start_ctx); return NULL; } GNUNET_free (temp_str); } if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "blacklist_transports", &pg_start_ctx->restrict_transports)) pg_start_ctx->restrict_transports = NULL; pg_start_ctx->restrict_topology = GNUNET_TESTING_TOPOLOGY_NONE; if ((GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "blacklist_topology", &temp_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get (&pg_start_ctx->restrict_topology, temp_str))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid topology `%s' given for section %s option %s\n", temp_str, "TESTING", "BLACKLIST_TOPOLOGY"); } GNUNET_free_non_null (temp_str); pg_start_ctx->cfg = cfg; pg_start_ctx->total = total; pg_start_ctx->peers_left = total; pg_start_ctx->connect_cb = connect_cb; pg_start_ctx->peergroup_cb = peergroup_cb; pg_start_ctx->cls = peergroup_cls; pg_start_ctx->hostnames = hostnames; pg_start_ctx->hostkey_meter = create_meter (pg_start_ctx->peers_left, "Hostkeys created ", pg_start_ctx->verbose); pg_start_ctx->peer_start_meter = create_meter (pg_start_ctx->peers_left, "Peers started ", pg_start_ctx->verbose); /* Make compilers happy */ reset_meter (pg_start_ctx->peer_start_meter); pg_start_ctx->fail_reason = GNUNET_strdup ("didn't generate all hostkeys within allowed startup time!"); pg_start_ctx->die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (pg_start_ctx->timeout), &end_badly, pg_start_ctx); pg_start_ctx->pg = GNUNET_TESTING_daemons_start (pg_start_ctx->cfg, pg_start_ctx->peers_left, pg_start_ctx->max_concurrent_connections, pg_start_ctx->max_concurrent_ssh, GNUNET_TIME_absolute_get_remaining (pg_start_ctx->timeout), &internal_hostkey_callback, pg_start_ctx, &internal_peers_started_callback, pg_start_ctx, &internal_topology_callback, pg_start_ctx, pg_start_ctx->hostnames); return pg_start_ctx->pg; } /* end of testing_peergroup.c */ gnunet-0.9.3/src/testing/testing_new.c0000644000175000017500000007361011762055613014717 00000000000000/* This file is part of GNUnet (C) 2008, 2009, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testing/testing_new.c * @brief convenience API for writing testcases for GNUnet * Many testcases need to start and stop a peer/service * and this library is supposed to make that easier * for TESTCASES. Normal programs should always * use functions from gnunet_{util,arm}_lib.h. This API is * ONLY for writing testcases (or internal use of the testbed). * @author Christian Grothoff * */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_testing_lib-new.h" #define LOG(kind,...) \ GNUNET_log_from (kind, "gnunettestingnew", __VA_ARGS__) /** * Size of a hostkey when written to a file */ #define HOSTKEYFILESIZE 914 /** * Handle for a system on which GNUnet peers are executed; * a system is used for reserving unique paths and ports. */ struct GNUNET_TESTING_System { /** * Prefix (i.e. "/tmp/gnunet-testing/") we prepend to each * SERVICEHOME. */ char *tmppath; /** * The hostname of the controller */ char *controller; /** * Hostkeys data, contains "HOSTKEYFILESIZE * total_hostkeys" bytes. */ char *hostkeys_data; /** * Bitmap where each TCP port that has already been reserved for * some GNUnet peer is recorded. Note that we additionally need to * test if a port is already in use by non-GNUnet components before * assigning it to a peer/service. If we detect that a port is * already in use, we also mark it in this bitmap. So all the bits * that are zero merely indicate ports that MIGHT be available for * peers. */ uint32_t reserved_tcp_ports[65536 / 32]; /** * Bitmap where each UDP port that has already been reserved for * some GNUnet peer is recorded. Note that we additionally need to * test if a port is already in use by non-GNUnet components before * assigning it to a peer/service. If we detect that a port is * already in use, we also mark it in this bitmap. So all the bits * that are zero merely indicate ports that MIGHT be available for * peers. */ uint32_t reserved_udp_ports[65536 / 32]; /** * Counter we use to make service home paths unique on this system; * the full path consists of the tmppath and this number. Each * UNIXPATH for a peer is also modified to include the respective * path counter to ensure uniqueness. This field is incremented * by one for each configured peer. Even if peers are destroyed, * we never re-use path counters. */ uint32_t path_counter; /** * The number of hostkeys */ uint32_t total_hostkeys; }; /** * Handle for a GNUnet peer controlled by testing. */ struct GNUNET_TESTING_Peer { /** * Path to the configuration file for this peer. */ char *cfgfile; /** * Binary to be executed during 'GNUNET_TESTING_peer_start'. * Typically 'gnunet-service-arm' (but can be set to a * specific service by 'GNUNET_TESTING_service_run' if * necessary). */ char *main_binary; /** * Handle to the running binary of the service, NULL if the * peer/service is currently not running. */ struct GNUNET_OS_Process *main_process; }; /** * Lowest port used for GNUnet testing. Should be high enough to not * conflict with other applications running on the hosts but be low * enough to not conflict with client-ports (typically starting around * 32k). */ #define LOW_PORT 12000 /** * Highest port used for GNUnet testing. Should be low enough to not * conflict with the port range for "local" ports (client apps; see * /proc/sys/net/ipv4/ip_local_port_range on Linux for example). */ #define HIGH_PORT 56000 /** * Create a system handle. There must only be one system * handle per operating system. * * @param tmppath prefix path to use for all service homes * @param controller hostname of the controlling host, * service configurations are modified to allow * control connections from this host; can be NULL * @return handle to this system, NULL on error */ struct GNUNET_TESTING_System * GNUNET_TESTING_system_create (const char *tmppath, const char *controller) { struct GNUNET_TESTING_System *system; if (NULL == tmppath) { LOG (GNUNET_ERROR_TYPE_ERROR, _("tmppath cannot be NULL\n")); return NULL; } system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System)); system->tmppath = GNUNET_strdup (tmppath); if (NULL != controller) system->controller = GNUNET_strdup (controller); return system; } /** * Free system resources. * * @param system system to be freed * @param remove_paths should the 'tmppath' and all subdirectories * be removed (clean up on shutdown)? */ void GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system, int remove_paths) { if (NULL != system->hostkeys_data) { GNUNET_break (0); /* Use GNUNET_TESTING_hostkeys_unload() */ GNUNET_TESTING_hostkeys_unload (system); } if (GNUNET_YES == remove_paths) GNUNET_DISK_directory_remove (system->tmppath); GNUNET_free (system->tmppath); GNUNET_free_non_null (system->controller); GNUNET_free (system); } /** * Reserve a TCP or UDP port for a peer. * * @param system system to use for reservation tracking * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP * @return 0 if no free port was available */ uint16_t GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system, int is_tcp) { struct GNUNET_NETWORK_Handle *socket; struct addrinfo hint; struct addrinfo *ret; uint32_t *port_buckets; char *open_port_str; int bind_status; uint32_t xor_image; uint16_t index; uint16_t open_port; uint16_t pos; /* FIXME: Instead of using getaddrinfo we should try to determine the port status by the following heurestics. On systems which support both IPv4 and IPv6, only ports open on both address families are considered open. On system with either IPv4 or IPv6. A port is considered open if it's open in the respective address family */ hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */ hint.ai_socktype = (GNUNET_YES == is_tcp)? SOCK_STREAM : SOCK_DGRAM; hint.ai_protocol = 0; hint.ai_addrlen = 0; hint.ai_addr = NULL; hint.ai_canonname = NULL; hint.ai_next = NULL; hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */ port_buckets = (GNUNET_YES == is_tcp) ? system->reserved_tcp_ports : system->reserved_udp_ports; for (index = (LOW_PORT / 32) + 1; index < (HIGH_PORT / 32); index++) { xor_image = (UINT32_MAX ^ port_buckets[index]); if (0 == xor_image) /* Ports in the bucket are full */ continue; pos = 0; while (pos < 32) { if (0 == ((xor_image >> pos) & 1U)) { pos++; continue; } open_port = (index * 32) + pos; GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port); ret = NULL; GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret)); GNUNET_free (open_port_str); socket = GNUNET_NETWORK_socket_create (ret->ai_family, (GNUNET_YES == is_tcp) ? SOCK_STREAM : SOCK_DGRAM, 0); GNUNET_assert (NULL != socket); bind_status = GNUNET_NETWORK_socket_bind (socket, ret->ai_addr, ret->ai_addrlen); freeaddrinfo (ret); GNUNET_NETWORK_socket_close (socket); socket = NULL; port_buckets[index] |= (1U << pos); /* Set the port bit */ if (GNUNET_OK == bind_status) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Found a free port %u\n", (unsigned int) open_port); return open_port; } pos++; } } return 0; } /** * Release reservation of a TCP or UDP port for a peer * (used during GNUNET_TESTING_peer_destroy). * * @param system system to use for reservation tracking * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP * @param port reserved port to release */ void GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system, int is_tcp, uint16_t port) { uint32_t *port_buckets; uint16_t bucket; uint16_t pos; port_buckets = (GNUNET_YES == is_tcp) ? system->reserved_tcp_ports : system->reserved_udp_ports; bucket = port / 32; pos = port % 32; LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port); if (0 == (port_buckets[bucket] & (1U << pos))) { GNUNET_break(0); /* Port was not reserved by us using reserve_port() */ return; } port_buckets[bucket] &= ~(1U << pos); } /** * Reserve a SERVICEHOME path for a peer. * * @param system system to use for reservation tracking * @return NULL on error, otherwise fresh unique path to use * as the servicehome for the peer; must be freed by the caller */ // static char * reserve_path (struct GNUNET_TESTING_System *system) { char *reserved_path; GNUNET_asprintf (&reserved_path, "%s/%u", system->tmppath, system->path_counter++); return reserved_path; } /** * Testing includes a number of pre-created hostkeys for faster peer * startup. This function loads such keys into memory from a file. * * @param system the testing system handle * @param filename the path of the hostkeys file * @return GNUNET_OK on success; GNUNET_SYSERR on error */ int GNUNET_TESTING_hostkeys_load (struct GNUNET_TESTING_System *system, const char *filename) { struct GNUNET_DISK_FileHandle *fd; uint64_t fs; if (GNUNET_YES != GNUNET_DISK_file_test (filename)) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Hostkeys file not found: %s\n"), filename); return GNUNET_SYSERR; } /* Check hostkey file size, read entire thing into memory */ fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); if (NULL == fd) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Could not open hostkeys file: %s\n"), filename); return GNUNET_SYSERR; } if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES)) fs = 0; if (0 == fs) { GNUNET_DISK_file_close (fd); return GNUNET_SYSERR; /* File is empty */ } if (0 != (fs % HOSTKEYFILESIZE)) { GNUNET_DISK_file_close (fd); LOG (GNUNET_ERROR_TYPE_ERROR, _("Incorrect hostkey file format: %s\n"), filename); return GNUNET_SYSERR; } GNUNET_break (NULL == system->hostkeys_data); system->total_hostkeys = fs / HOSTKEYFILESIZE; system->hostkeys_data = GNUNET_malloc_large (fs); /* free in hostkeys_unload */ GNUNET_assert (fs == GNUNET_DISK_file_read (fd, system->hostkeys_data, fs)); GNUNET_DISK_file_close (fd); return GNUNET_OK; } /** * Function to remove the loaded hostkeys * * @param system the testing system handle */ void GNUNET_TESTING_hostkeys_unload (struct GNUNET_TESTING_System *system) { GNUNET_break (NULL != system->hostkeys_data); GNUNET_free_non_null (system->hostkeys_data); system->hostkeys_data = NULL; system->total_hostkeys = 0; } /** * Testing includes a number of pre-created hostkeys for * faster peer startup. This function can be used to * access the n-th key of those pre-created hostkeys; note * that these keys are ONLY useful for testing and not * secure as the private keys are part of the public * GNUnet source code. * * This is primarily a helper function used internally * by 'GNUNET_TESTING_peer_configure'. * * @param system the testing system handle * @param key_number desired pre-created hostkey to obtain * @param id set to the peer's identity (hash of the public * key; if NULL, GNUNET_SYSERR is returned immediately * @return GNUNET_SYSERR on error (not enough keys) */ int GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system, uint32_t key_number, struct GNUNET_PeerIdentity *id) { struct GNUNET_CRYPTO_RsaPrivateKey *private_key; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; if ((NULL == id) || (NULL == system->hostkeys_data)) return GNUNET_SYSERR; if (key_number >= system->total_hostkeys) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Key number %u does not exist\n"), key_number); return GNUNET_SYSERR; } private_key = GNUNET_CRYPTO_rsa_decode_key (system->hostkeys_data + (key_number * HOSTKEYFILESIZE), HOSTKEYFILESIZE); if (NULL == private_key) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Error while decoding key %u\n"), key_number); return GNUNET_SYSERR; } GNUNET_CRYPTO_rsa_key_get_public (private_key, &public_key); GNUNET_CRYPTO_hash (&public_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &(id->hashPubKey)); GNUNET_CRYPTO_rsa_key_free (private_key); return GNUNET_OK; } /** * Structure for holding data to build new configurations from a configuration * template */ struct UpdateContext { /** * The system for which we are building configurations */ struct GNUNET_TESTING_System *system; /** * The configuration we are building */ struct GNUNET_CONFIGURATION_Handle *cfg; /** * The customized service home path for this peer */ char *service_home; /** * build status - to signal error while building a configuration */ int status; }; /** * Function to iterate over options. Copies * the options to the target configuration, * updating PORT values as needed. * * @param cls the UpdateContext * @param section name of the section * @param option name of the option * @param value value of the option */ static void update_config (void *cls, const char *section, const char *option, const char *value) { struct UpdateContext *uc = cls; unsigned int ival; char cval[12]; char uval[128]; char *single_variable; char *per_host_variable; unsigned long long num_per_host; uint16_t new_port; if (GNUNET_OK != uc->status) return; if (! ((0 == strcmp (option, "PORT")) || (0 == strcmp (option, "UNIXPATH")) || (0 == strcmp (option, "HOSTNAME")))) return; GNUNET_asprintf (&single_variable, "single_%s_per_host", section); GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section); if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival))) { if ((ival != 0) && (GNUNET_YES != GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing", single_variable))) { /* FIXME: What about UDP? */ new_port = GNUNET_TESTING_reserve_port (uc->system, GNUNET_YES); if (0 == new_port) { uc->status = GNUNET_SYSERR; return; } GNUNET_snprintf (cval, sizeof (cval), "%u", new_port); value = cval; } else if ((ival != 0) && (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing", single_variable)) && GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing", per_host_variable, &num_per_host)) { /* GNUNET_snprintf (cval, sizeof (cval), "%u", */ /* ival + ctx->fdnum % num_per_host); */ /* value = cval; */ GNUNET_break (0); /* FIXME */ } } if (0 == strcmp (option, "UNIXPATH")) { if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing", single_variable)) { GNUNET_snprintf (uval, sizeof (uval), "%s/%s.sock", uc->service_home, section); value = uval; } else if ((GNUNET_YES == GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing", per_host_variable, &num_per_host)) && (num_per_host > 0)) { GNUNET_break(0); /* FIXME */ } } if ((0 == strcmp (option, "HOSTNAME")) && (NULL != uc->system->controller)) { value = uc->system->controller; } GNUNET_free (single_variable); GNUNET_free (per_host_variable); GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value); } /** * Section iterator to set ACCEPT_FROM in all sections * * @param cls the UpdateContext * @param section name of the section */ static void update_config_sections (void *cls, const char *section) { struct UpdateContext *uc = cls; char *orig_allowed_hosts; char *allowed_hosts; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "ACCEPT_FROM", &orig_allowed_hosts)) { orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;"); } if (NULL == uc->system->controller) allowed_hosts = GNUNET_strdup (orig_allowed_hosts); else GNUNET_asprintf (&allowed_hosts, "%s %s;", orig_allowed_hosts, uc->system->controller); GNUNET_free (orig_allowed_hosts); GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, "ACCEPT_FROM", allowed_hosts); GNUNET_free (allowed_hosts); } /** * Create a new configuration using the given configuration * as a template; ports and paths will be modified to select * available ports on the local system. If we run * out of "*port" numbers, return SYSERR. * * This is primarily a helper function used internally * by 'GNUNET_TESTING_peer_configure'. * * @param system system to use to coordinate resource usage * @param cfg template configuration to update * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will * be incomplete and should not be used there upon */ int GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system, struct GNUNET_CONFIGURATION_Handle *cfg) { struct UpdateContext uc; uc.system = system; uc.cfg = cfg; uc.status = GNUNET_OK; GNUNET_asprintf (&uc.service_home, "%s/%u", system->tmppath, system->path_counter++); GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "SERVICEHOME", uc.service_home); /* make PORTs and UNIXPATHs unique */ GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc); /* allow connections to services from system controller host */ GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc); /* enable loopback-based connections between peers */ GNUNET_CONFIGURATION_set_value_string (cfg, "nat", "USE_LOCALADDR", "YES"); GNUNET_free (uc.service_home); return uc.status; } /** * Configure a GNUnet peer. GNUnet must be installed on the local * system and available in the PATH. * * @param system system to use to coordinate resource usage * @param cfg configuration to use; will be UPDATED (to reflect needed * changes in port numbers and paths) * @param key_number number of the hostkey to use for the peer * @param id identifier for the daemon, will be set, can be NULL * @param emsg set to error message (set to NULL on success), can be NULL * @return handle to the peer, NULL on error */ struct GNUNET_TESTING_Peer * GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system, struct GNUNET_CONFIGURATION_Handle *cfg, uint32_t key_number, struct GNUNET_PeerIdentity *id, char **emsg) { struct GNUNET_TESTING_Peer *peer; struct GNUNET_DISK_FileHandle *fd; char *service_home; char hostkey_filename[128]; char *config_filename; char *emsg_; if (NULL != emsg) *emsg = NULL; if (GNUNET_OK != GNUNET_TESTING_configuration_create (system, cfg)) { GNUNET_asprintf (&emsg_, _("Failed to create configuration for peer (not enough free ports?)\n")); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_); if (NULL != emsg) *emsg = emsg_; else GNUNET_free (emsg_); return NULL; } if (key_number >= system->total_hostkeys) { GNUNET_asprintf (&emsg_, _("You attempted to create a testbed with more than %u hosts. Please precompute more hostkeys first.\n"), (unsigned int) system->total_hostkeys); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_); if (NULL != emsg) *emsg = emsg_; else GNUNET_free (emsg_); return NULL; } if ((NULL != id) && (GNUNET_SYSERR == GNUNET_TESTING_hostkey_get (system, key_number, id))) { GNUNET_asprintf (&emsg_, _("Failed to initialize hostkey for peer %u\n"), (unsigned int) key_number); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_); if (NULL != emsg) *emsg = emsg_; else GNUNET_free (emsg_); return NULL; } GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", "SERVICEHOME", &service_home)); GNUNET_snprintf (hostkey_filename, sizeof (hostkey_filename), "%s/.hostkey", service_home); fd = GNUNET_DISK_file_open (hostkey_filename, GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (NULL == fd) { GNUNET_break (0); return NULL; } if (HOSTKEYFILESIZE != GNUNET_DISK_file_write (fd, system->hostkeys_data + (key_number * HOSTKEYFILESIZE), HOSTKEYFILESIZE)) { GNUNET_asprintf (&emsg_, _("Failed to write hostkey file for peer %u: %s\n"), (unsigned int) key_number, STRERROR (errno)); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_); if (NULL != emsg) *emsg = emsg_; else GNUNET_free (emsg_); GNUNET_DISK_file_close (fd); return NULL; } GNUNET_DISK_file_close (fd); GNUNET_asprintf (&config_filename, "%s/config", service_home); GNUNET_free (service_home); if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename)) { GNUNET_asprintf (&emsg_, _("Failed to write configuration file `%s' for peer %u: %s\n"), config_filename, (unsigned int) key_number, STRERROR (errno)); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_); if (NULL != emsg) *emsg = emsg_; else GNUNET_free (emsg_); return NULL; } peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer)); peer->cfgfile = config_filename; /* Free in peer_destroy */ peer->main_binary = GNUNET_strdup ("gnunet-service-arm"); return peer; } /** * Start the peer. * * @param peer peer to start * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running) */ int GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer) { if (NULL != peer->main_process) { GNUNET_break (0); return GNUNET_SYSERR; } GNUNET_assert (NULL != peer->cfgfile); peer->main_process = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, peer->main_binary, "-c", peer->cfgfile, NULL); if (NULL == peer->main_process) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to start `%s': %s\n"), peer->main_binary, STRERROR (errno)); return GNUNET_SYSERR; } return GNUNET_OK; } /** * Stop the peer. * * @param peer peer to stop * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer not running) */ int GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer) { if (NULL == peer->main_process) { GNUNET_break (0); return GNUNET_SYSERR; } (void) GNUNET_OS_process_kill (peer->main_process, SIGTERM); GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (peer->main_process)); GNUNET_OS_process_destroy (peer->main_process); peer->main_process = NULL; return GNUNET_OK; } /** * Destroy the peer. Releases resources locked during peer configuration. * If the peer is still running, it will be stopped AND a warning will be * printed (users of the API should stop the peer explicitly first). * * @param peer peer to destroy */ void GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer) { if (NULL != peer->main_process) { GNUNET_break (0); GNUNET_TESTING_peer_stop (peer); } GNUNET_free (peer->cfgfile); GNUNET_free (peer->main_binary); GNUNET_free (peer); } /** * Start a single peer and run a test using the testing library. * Starts a peer using the given configuration and then invokes the * given callback. This function ALSO initializes the scheduler loop * and should thus be called directly from "main". The testcase * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'. * * @param tmppath path for storing temporary data for the test * @param cfgfilename name of the configuration file to use; * use NULL to only run with defaults * @param tm main function of the testcase * @param tm_cls closure for 'tm' * @return 0 on success, 1 on error */ int GNUNET_TESTING_peer_run (const char *tmppath, const char *cfgfilename, GNUNET_TESTING_TestMain tm, void *tm_cls) { return GNUNET_TESTING_service_run (tmppath, "arm", cfgfilename, tm, tm_cls); } /** * Structure for holding service data */ struct ServiceContext { /** * The configuration of the peer in which the service is run */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Callback to signal service startup */ GNUNET_TESTING_TestMain tm; /** * Closure for the above callback */ void *tm_cls; }; /** * Callback to be called when SCHEDULER has been started * * @param cls the ServiceContext * @param tc the TaskContext */ static void service_run_main (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ServiceContext *sc = cls; sc->tm (sc->tm_cls, sc->cfg); } /** * Start a single service (no ARM, except of course if the given * service name is 'arm') and run a test using the testing library. * Starts a service using the given configuration and then invokes the * given callback. This function ALSO initializes the scheduler loop * and should thus be called directly from "main". The testcase * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'. * * This function is useful if the testcase is for a single service * and if that service doesn't itself depend on other services. * * @param tmppath path for storing temporary data for the test * @param service_name name of the service to run * @param cfgfilename name of the configuration file to use; * use NULL to only run with defaults * @param tm main function of the testcase * @param tm_cls closure for 'tm' * @return 0 on success, 1 on error */ int GNUNET_TESTING_service_run (const char *tmppath, const char *service_name, const char *cfgfilename, GNUNET_TESTING_TestMain tm, void *tm_cls) { struct ServiceContext sc; struct GNUNET_TESTING_System *system; struct GNUNET_TESTING_Peer *peer; struct GNUNET_CONFIGURATION_Handle *cfg; char *data_dir; char *hostkeys_file; data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR); GNUNET_asprintf (&hostkeys_file, "%s/testing_hostkeys.dat", data_dir); GNUNET_free (data_dir); system = GNUNET_TESTING_system_create (tmppath, "localhost"); if (NULL == system) { GNUNET_free (hostkeys_file); return 1; } if (GNUNET_OK != GNUNET_TESTING_hostkeys_load (system, hostkeys_file)) { GNUNET_free (hostkeys_file); GNUNET_TESTING_system_destroy (system, GNUNET_YES); return 1; } GNUNET_free (hostkeys_file); cfg = GNUNET_CONFIGURATION_create (); if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename)) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to load configuration from %s\n"), cfgfilename); GNUNET_CONFIGURATION_destroy (cfg); GNUNET_TESTING_system_destroy (system, GNUNET_YES); return 1; } peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL); if (NULL == peer) { GNUNET_CONFIGURATION_destroy (cfg); GNUNET_TESTING_hostkeys_unload (system); GNUNET_TESTING_system_destroy (system, GNUNET_YES); return 1; } GNUNET_TESTING_hostkeys_unload (system); GNUNET_free (peer->main_binary); GNUNET_asprintf (&peer->main_binary, "gnunet-service-%s", service_name); if (GNUNET_OK != GNUNET_TESTING_peer_start (peer)) { GNUNET_TESTING_peer_destroy (peer); GNUNET_CONFIGURATION_destroy (cfg); GNUNET_TESTING_system_destroy (system, GNUNET_YES); return 1; } sc.cfg = cfg; sc.tm = tm; sc.tm_cls = tm_cls; GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */ if (GNUNET_OK != GNUNET_TESTING_peer_stop (peer)) { GNUNET_TESTING_peer_destroy (peer); GNUNET_CONFIGURATION_destroy (cfg); GNUNET_TESTING_system_destroy (system, GNUNET_YES); return 1; } GNUNET_TESTING_peer_destroy (peer); GNUNET_CONFIGURATION_destroy (cfg); GNUNET_TESTING_system_destroy (system, GNUNET_YES); return 0; } /* end of testing_new.c */ gnunet-0.9.3/src/testing/test_testing_topology_churn.c0000644000175000017500000002077511760502551020240 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testing/test_testing_topology_churn.c * @brief base testcase for testing simple churn functionality */ #include "platform.h" #include "gnunet_testing_lib.h" #include "gnunet_core_service.h" /** * How long until we fail the whole testcase? */ #define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600) /** * How long until we give up on starting the peers? (Must be longer than the connect timeout!) */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) #define DEFAULT_NUM_PEERS 4 static int ok; static unsigned long long num_peers; static unsigned int expected_connections; static unsigned int expected_failed_connections; static unsigned long long peers_left; static struct GNUNET_TESTING_PeerGroup *pg; const struct GNUNET_CONFIGURATION_Handle *main_cfg; GNUNET_SCHEDULER_TaskIdentifier die_task; static char *test_directory; #define MTYPE 12345 GNUNET_NETWORK_STRUCT_BEGIN struct GNUNET_TestMessage { /** * Header of the message */ struct GNUNET_MessageHeader header; /** * Unique identifier for this message. */ uint32_t uid; }; GNUNET_NETWORK_STRUCT_END /** * Check whether peers successfully shut down. */ void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); if (ok == 0) ok = 666; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); } } static void finish_testing () { GNUNET_assert (pg != NULL); if (die_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (die_task); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called finish testing, stopping daemons.\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling daemons_stop\n"); GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "daemons_stop finished\n"); ok = 0; } static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { char *msg = cls; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "End badly was called (%s)... stopping daemons.\n", msg); if (pg != NULL) { GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); ok = 7331; /* Opposite of leet */ } else ok = 401; /* Never got peers started */ } struct ChurnTestContext { GNUNET_SCHEDULER_Task next_task; }; static struct ChurnTestContext churn_ctx; /** * Churn callback, report on success or failure of churn operation. * * @param cls closure * @param emsg NULL on success */ void churn_callback (void *cls, const char *emsg) { if (emsg == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Successfully churned peers!\n", emsg); GNUNET_SCHEDULER_add_now (churn_ctx.next_task, NULL); } else { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to churn peers with error `%s'\n", emsg); GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); } } static void churn_peers_both () { churn_ctx.next_task = &finish_testing; GNUNET_TESTING_daemons_churn (pg, NULL, 1, 1, TIMEOUT, &churn_callback, NULL); } static void churn_peers_off_again () { churn_ctx.next_task = &churn_peers_both; GNUNET_TESTING_daemons_churn (pg, NULL, 2, 0, TIMEOUT, &churn_callback, NULL); } static void churn_peers_on () { churn_ctx.next_task = &churn_peers_off_again; GNUNET_TESTING_daemons_churn (pg, NULL, 0, 2, TIMEOUT, &churn_callback, NULL); } static void churn_peers_off () { churn_ctx.next_task = &churn_peers_on; GNUNET_TESTING_daemons_churn (pg, NULL, 2, 0, TIMEOUT, &churn_callback, NULL); } static void peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to start daemon with error: `%s'\n", emsg); return; } GNUNET_assert (id != NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", (num_peers - peers_left) + 1, num_peers); peers_left--; if (peers_left == 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All %d daemons started, now testing churn!\n", num_peers); GNUNET_SCHEDULER_cancel (die_task); /* Set up task in case topology creation doesn't finish * within a reasonable amount of time */ die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, "from peers_started_callback"); churn_peers_off (); ok = 0; } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { ok = 1; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons based on config file %s\n", cfgfile); if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", &test_directory)) { ok = 404; return; } if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", &num_peers)) num_peers = DEFAULT_NUM_PEERS; main_cfg = cfg; peers_left = num_peers; GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1); /* For this specific test we only really want a CLIQUE topology as the * overlay allowed topology, and a RING topology as the underlying connection * allowed topology. So we will expect only num_peers * 2 connections to * work, and (num_peers * (num_peers - 1)) - (num_peers * 2) to fail. */ expected_connections = num_peers * (num_peers - 1); expected_failed_connections = expected_connections - (num_peers * 2); /* Set up a task to end testing if peer start fails */ die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, "didn't start all daemons in reasonable amount of time!!!"); pg = GNUNET_TESTING_daemons_start (cfg, peers_left, peers_left, peers_left, TIMEOUT, NULL, NULL, &peers_started_callback, NULL, NULL, NULL, NULL); } static int check () { int ret; char *const argv[] = { "test-testing-topology-churn", "-c", "test_testing_data_topology_churn.conf", NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; ret = GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-testing-topology-churn", "nohelp", options, &run, &ok); if (ret != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "`test-testing-topology-churn': Failed with error code %d\n", ret); } return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test_testing_topology_churn", "WARNING", NULL); ret = check (); /** * Need to remove base directory, subdirectories taken care * of by the testing framework. */ if (test_directory != NULL) { if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to remove testing directory %s\n", test_directory); } } return ret; } /* end of test_testing_topology_churn.c */ gnunet-0.9.3/src/testing/test_testing_new_peerstartup.c0000644000175000017500000001123711761753145020415 00000000000000/* This file is part of GNUnet (C) 2008, 2009, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testing/test_testing_new_peerstartup.c * @brief test case for testing peer startup and shutdown using new testing * library * @author Sree Harsha Totakura */ #include "platform.h" #include "gnunet_configuration_lib.h" #include "gnunet_os_lib.h" #include "gnunet_testing_lib-new.h" #define LOG(kind,...) \ GNUNET_log (kind, __VA_ARGS__) #define TIME_REL_SEC(sec) \ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec) /** * The testing context */ struct TestingContext { /** * The testing system */ struct GNUNET_TESTING_System *system; /** * The peer which has been started by the testing system */ struct GNUNET_TESTING_Peer *peer; /** * The running configuration of the peer */ struct GNUNET_CONFIGURATION_Handle *cfg; }; /** * Task for shutdown * * @param cls the testing context * @param tc the tast context */ static void do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct TestingContext *test_ctx = cls; GNUNET_assert (GNUNET_OK == GNUNET_TESTING_peer_stop (test_ctx->peer)); GNUNET_TESTING_peer_destroy (test_ctx->peer); GNUNET_CONFIGURATION_destroy (test_ctx->cfg); GNUNET_TESTING_hostkeys_unload (test_ctx->system); GNUNET_TESTING_system_destroy (test_ctx->system, GNUNET_YES); GNUNET_free (test_ctx); } /** * Main point of test execution */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_TESTING_System *system; struct GNUNET_TESTING_Peer *peer; struct GNUNET_CONFIGURATION_Handle *new_cfg; struct TestingContext *test_ctx; char *data_dir; char *hostkeys_file; char *emsg; char *_tmpdir; char *tmpdir; #ifdef MINGW char *tmpdir_w; #endif struct GNUNET_PeerIdentity id; _tmpdir = getenv ("TMP"); if (NULL == _tmpdir) _tmpdir = getenv ("TEMP"); if (NULL == _tmpdir) _tmpdir = getenv ("TMPDIR"); if (NULL == _tmpdir) _tmpdir = "/tmp"; GNUNET_asprintf (&tmpdir, "%s/%s", _tmpdir, "test-gnunet-testing_new-XXXXXX"); #ifdef MINGW tmpdir_w = GNUNET_malloc (MAX_PATH + 1); GNUNET_assert (ERROR_SUCCESS == plibc_conv_to_win_path (tmpdir, tmpdir_w)); GNUNET_free (tmpdir); tmpdir = tmpdir_w; //GNUNET_assert (0 == _mktemp_s (tmpdir, strlen (tmpdir) + 1)); #else GNUNET_assert (mkdtemp (tmpdir) == tmpdir); #endif /* LOG (GNUNET_ERROR_TYPE_ERROR, */ /* "Temporary directory: %s\n", tmpdir); */ system = GNUNET_TESTING_system_create (tmpdir, "localhost"); GNUNET_assert (NULL != system); GNUNET_free (tmpdir); data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR); GNUNET_asprintf (&hostkeys_file, "%s/testing_hostkeys.dat", data_dir); GNUNET_free (data_dir); GNUNET_assert (GNUNET_OK == GNUNET_TESTING_hostkeys_load (system, hostkeys_file)); GNUNET_free (hostkeys_file); new_cfg = GNUNET_CONFIGURATION_dup (cfg); emsg = NULL; peer = GNUNET_TESTING_peer_configure (system, new_cfg, 0, &id, &emsg); GNUNET_assert (NULL != peer); GNUNET_assert (NULL == emsg); GNUNET_assert (GNUNET_OK == GNUNET_TESTING_peer_start (peer)); test_ctx = GNUNET_malloc (sizeof (struct TestingContext)); test_ctx->system = system; test_ctx->peer = peer; test_ctx->cfg = new_cfg; GNUNET_SCHEDULER_add_delayed (TIME_REL_SEC (5), &do_shutdown, test_ctx); } int main (int argc, char *argv[]) { struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test_testing_new_peerstartup", "test case for peerstartup using new testing library", options, &run, NULL)) return 1; return 0; } gnunet-0.9.3/src/testing/test_testing_data_topology_stability.conf0000644000175000017500000000024311661530126022604 00000000000000@INLINE@ test_testing_defaults.conf [PATHS] DEFAULTCONFIG = test_testing_data_topology_clique.conf [TESTING] SETTLE_TIME = 600 s NUM_PEERS = 2 TOPOLOGY = CLIQUE gnunet-0.9.3/src/testing/Makefile.am0000644000175000017500000002315711762055613014262 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIB = -lgcov endif pkgcfgdir= $(pkgdatadir)/config.d/ dist_pkgcfg_DATA = \ testing.conf if HAVE_EXPENSIVE_TESTS EXPENSIVE_TESTS = \ test_testing_topology_stability \ test_testing_topology_clique_random \ test_testing_topology_clique_minimum \ test_testing_topology_clique_dfs \ test_testing_topology_churn \ test_testing_topology_line \ test_testing_topology_blacklist \ test_testing_group_remote \ test_testing_topology_ring \ test_testing_topology_2d_torus \ test_testing_topology_small_world_ring \ test_testing_topology_small_world_torus \ test_testing_topology_erdos_renyi \ test_testing_topology_internat \ test_testing_topology_scale_free endif lib_LTLIBRARIES = \ libgnunettesting.la \ libgnunettesting_new.la libgnunettesting_la_SOURCES = \ helper.c \ testing.c \ testing_group.c \ testing_peergroup.c libgnunettesting_la_LIBADD = $(XLIB) \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ -lm \ $(top_builddir)/src/util/libgnunetutil.la libgnunettesting_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:1:0 libgnunettesting_new_la_SOURCES = \ testing_new.c libgnunettesting_new_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la libgnunettesting_new_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:1:0 bin_PROGRAMS = \ gnunet-testing check_PROGRAMS = \ test_testing \ test_testing_connect \ test_testing_reconnect \ test_testing_group \ test_testing_peergroup \ test_testing_topology_stability \ test_testing_topology_clique \ test_testing_topology_clique_random \ test_testing_topology_clique_minimum \ test_testing_topology_clique_dfs \ test_testing_topology_churn \ test_testing_topology_line \ test_testing_topology_blacklist \ test_testing_group_remote \ test_testing_2dtorus \ test_testing_topology_ring \ test_testing_topology_2d_torus \ test_testing_topology_small_world_ring \ test_testing_topology_small_world_torus \ test_testing_topology_erdos_renyi \ test_testing_topology_internat \ test_testing_topology_none \ test_testing_topology_scale_free \ test_testing_new_portreservation \ test_testing_new_peerstartup \ test_testing_new_servicestartup if ENABLE_TEST_RUN TESTS = \ test_testing \ test_testing_connect \ test_testing_reconnect \ test_testing_group \ test_testing_peergroup \ test_testing_new_portreservation \ test_testing_new_peerstartup \ test_testing_new_servicestartup endif gnunet_testing_SOURCES = \ gnunet-testing.c gnunet_testing_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_testing_DEPENDENCIES = \ libgnunettesting.la test_testing_SOURCES = \ test_testing.c test_testing_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_connect_SOURCES = \ test_testing_connect.c test_testing_connect_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_reconnect_SOURCES = \ test_testing_reconnect.c test_testing_reconnect_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_group_SOURCES = \ test_testing_group.c test_testing_group_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_peergroup_SOURCES = \ test_testing_peergroup.c test_testing_peergroup_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_clique_SOURCES = \ test_testing_topology.c test_testing_topology_clique_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_stability_SOURCES = \ test_testing_topology.c test_testing_topology_stability_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_blacklist_SOURCES = \ test_testing_topology_blacklist.c test_testing_topology_blacklist_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_churn_SOURCES = \ test_testing_topology_churn.c test_testing_topology_churn_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_clique_random_SOURCES = \ test_testing_topology.c test_testing_topology_clique_random_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_clique_minimum_SOURCES = \ test_testing_topology.c test_testing_topology_clique_minimum_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_clique_dfs_SOURCES = \ test_testing_topology.c test_testing_topology_clique_dfs_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_line_SOURCES = \ test_testing_topology.c test_testing_topology_line_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_group_remote_SOURCES = \ test_testing_group_remote.c test_testing_group_remote_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_2dtorus_SOURCES = \ test_testing_2dtorus.c test_testing_2dtorus_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_ring_SOURCES = \ test_testing_topology.c test_testing_topology_ring_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_2d_torus_SOURCES = \ test_testing_topology.c test_testing_topology_2d_torus_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_small_world_ring_SOURCES = \ test_testing_topology.c test_testing_topology_small_world_ring_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_small_world_torus_SOURCES = \ test_testing_topology.c test_testing_topology_small_world_torus_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_internat_SOURCES = \ test_testing_topology.c test_testing_topology_internat_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_erdos_renyi_SOURCES = \ test_testing_topology.c test_testing_topology_erdos_renyi_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_scale_free_SOURCES = \ test_testing_topology.c test_testing_topology_scale_free_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_none_SOURCES = \ test_testing_topology.c test_testing_topology_none_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_new_portreservation_SOURCES = \ test_testing_new_portreservation.c test_testing_new_portreservation_LDADD = \ $(top_builddir)/src/testing/libgnunettesting_new.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_new_peerstartup_SOURCES = \ test_testing_new_peerstartup.c test_testing_new_peerstartup_LDADD = \ $(top_builddir)/src/testing/libgnunettesting_new.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_new_servicestartup_SOURCES = \ test_testing_new_servicestartup.c test_testing_new_servicestartup_LDADD = \ $(top_builddir)/src/testing/libgnunettesting_new.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ test_testing_defaults.conf \ test_testing_data.conf \ test_testing_connect_peer1.conf \ test_testing_connect_peer2.conf \ test_testing_2dtorus.conf \ test_testing_data_topology_clique.conf \ test_testing_data_topology_clique_random.conf \ test_testing_data_topology_clique_minimum.conf \ test_testing_data_topology_clique_dfs.conf \ test_testing_data_topology_ring.conf \ test_testing_data_topology_2d_torus.conf \ test_testing_data_topology_small_world_ring.conf \ test_testing_data_topology_small_world_torus.conf \ test_testing_data_topology_erdos_renyi.conf \ test_testing_data_topology_internat.conf \ test_testing_data_topology_scale_free.conf \ test_testing_data_topology_blacklist.conf \ test_testing_data_topology_churn.conf \ test_testing_data_topology_none.conf \ test_testing_data_remote.conf \ test_testing_data_topology_stability.conf \ test_testing_peergroup_data.conf gnunet-0.9.3/src/testing/test_testing_data_topology_clique_random.conf0000644000175000017500000000043711615731537023437 00000000000000@INLINE@ test_testing_defaults.conf [PATHS] DEFAULTCONFIG = test_testing_data_topology_clique.conf [TESTING] NUM_PEERS = 20 TOPOLOGY = CLIQUE CONNECT_TOPOLOGY_OPTION = CONNECT_RANDOM_SUBSET CONNECT_TOPOLOGY_OPTION_MODIFIER = .15 [statistics] AUTOSTART = NO [resolver] AUTOSTART = NO gnunet-0.9.3/src/testing/testing.conf0000644000175000017500000000045111661530126014535 00000000000000[TESTING] # How long before failing a connection? CONNECT_TIMEOUT = 30 s # How many connect attempts should we make? CONNECT_ATTEMPTS = 3 # How many connections can happen simultaneously? MAX_OUTSTANDING_CONNECTIONS = 50 # Should we clean up the files on peer group shutdown? DELETE_FILES = YES gnunet-0.9.3/src/testing/test_testing_data_topology_clique.conf0000644000175000017500000000031411661530126022061 00000000000000@INLINE@ test_testing_defaults.conf [PATHS] DEFAULTCONFIG = test_testing_data_topology_clique.conf [TESTING] CONNECT_TIMEOUT = 180 s CONNECT_ATTEMPTS = 14 NUM_PEERS = 4 TOPOLOGY = CLIQUE SETTLE_TIME = 0 gnunet-0.9.3/src/testing/test_testing_new_portreservation.c0000644000175000017500000000602011760674075021302 00000000000000/* This file is part of GNUnet (C) 2008, 2009, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testing/test_testing_new_portreservation.c * @brief test case for testing port reservation routines from the new testing * library API * @author Sree Harsha Totakura */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_testing_lib-new.h" #define LOG(kind,...) \ GNUNET_log (kind, __VA_ARGS__) /** * Main point of test execution */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_TESTING_System *system; uint16_t new_port1; uint16_t new_port2; uint16_t old_port1; system = GNUNET_TESTING_system_create ("/tmp/gnunet-testing-new", "localhost"); GNUNET_assert (NULL != system); new_port1 = GNUNET_TESTING_reserve_port (system, GNUNET_YES); LOG (GNUNET_ERROR_TYPE_DEBUG, "Reserved TCP port %u\n", new_port1); GNUNET_assert (0 != new_port1); new_port2 = GNUNET_TESTING_reserve_port (system, GNUNET_YES); LOG (GNUNET_ERROR_TYPE_DEBUG, "Reserved TCP port %u\n", new_port2); GNUNET_assert (0 != new_port2); GNUNET_assert (new_port1 != new_port2); GNUNET_TESTING_release_port (system, GNUNET_YES, new_port1); old_port1 = new_port1; new_port1 = 0; new_port1 = GNUNET_TESTING_reserve_port (system, GNUNET_YES); LOG (GNUNET_ERROR_TYPE_DEBUG, "Reserved TCP port %u\n", new_port1); GNUNET_assert (0 != new_port1); GNUNET_assert (old_port1 == new_port1); GNUNET_TESTING_release_port (system, GNUNET_YES, new_port1); GNUNET_TESTING_release_port (system, GNUNET_YES, new_port2); GNUNET_TESTING_system_destroy (system, GNUNET_NO); } int main (int argc, char *argv[]) { struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test_testing_new_portreservation", "test case for testing port reservation routines" " from the new testing library API", options, &run, NULL)) { return 1; } return 0; } gnunet-0.9.3/src/testing/test_testing_topology_blacklist.c0000644000175000017500000004234211760502551021063 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testing/test_testing_topology_blacklist.c * @brief base testcase for testing transport level blacklisting */ #include "platform.h" #include "gnunet_testing_lib.h" #include "gnunet_core_service.h" #define VERBOSE GNUNET_NO /** * How long until we fail the whole testcase? */ #define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600) /** * How long until we give up on starting the peers? (Must be longer than the connect timeout!) */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) #define DEFAULT_NUM_PEERS 4 #define MAX_OUTSTANDING_CONNECTIONS 300 static int ok; struct GNUNET_TIME_Relative connect_timeout; static unsigned long long connect_attempts; static unsigned long long num_peers; static unsigned int total_connections; static unsigned int failed_connections; static unsigned int expected_connections; static unsigned int expected_failed_connections; static unsigned long long peers_left; static struct GNUNET_TESTING_PeerGroup *pg; const struct GNUNET_CONFIGURATION_Handle *main_cfg; GNUNET_SCHEDULER_TaskIdentifier die_task; static char *dotOutFileName; static FILE *dotOutFile; static char *blacklist_transports; static enum GNUNET_TESTING_Topology topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Overlay should allow all connections */ static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_RING; /* Blacklist underlay into a ring */ static enum GNUNET_TESTING_Topology connection_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */ static enum GNUNET_TESTING_TopologyOption connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Try to connect all possible OVERLAY connections */ static double connect_topology_option_modifier = 0.0; static char *test_directory; #define MTYPE 12345 GNUNET_NETWORK_STRUCT_BEGIN struct GNUNET_TestMessage { /** * Header of the message */ struct GNUNET_MessageHeader header; /** * Unique identifier for this message. */ uint32_t uid; }; GNUNET_NETWORK_STRUCT_END /** * Check whether peers successfully shut down. */ void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); #endif if (ok == 0) ok = 666; } else { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); #endif } } static void finish_testing () { GNUNET_assert (pg != NULL); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called finish testing, stopping daemons.\n"); #endif sleep (1); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling daemons_stop\n"); #endif GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "daemons_stop finished\n"); #endif if (dotOutFile != NULL) { FPRINTF (dotOutFile, "%s", "}"); FCLOSE (dotOutFile); } ok = 0; } static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { char *msg = cls; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "End badly was called (%s)... stopping daemons.\n", msg); if (pg != NULL) { GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); ok = 7331; /* Opposite of leet */ } else ok = 401; /* Never got peers started */ if (dotOutFile != NULL) { FPRINTF (dotOutFile, "%s", "}"); FCLOSE (dotOutFile); } } void topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, uint32_t distance, const struct GNUNET_CONFIGURATION_Handle *first_cfg, const struct GNUNET_CONFIGURATION_Handle *second_cfg, struct GNUNET_TESTING_Daemon *first_daemon, struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) { if (emsg == NULL) { total_connections++; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s\n", first_daemon->shortname, second_daemon->shortname); #endif if (dotOutFile != NULL) FPRINTF (dotOutFile, "\tn%s -- n%s;\n", first_daemon->shortname, second_daemon->shortname); } else { failed_connections++; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect peer %s to peer %s with error :\n%s\n", first_daemon->shortname, second_daemon->shortname, emsg); #endif } if (total_connections == expected_connections) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created %d total connections, which is our target number (that's bad)!\n", total_connections); #endif GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from topology_callback (too many successful connections)"); } else if (total_connections + failed_connections == expected_connections) { if ((failed_connections == expected_failed_connections) && (total_connections == expected_connections - expected_failed_connections)) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; die_task = GNUNET_SCHEDULER_add_now (&finish_testing, NULL); } else { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from topology_callback (wrong number of failed connections)"); } } else { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d total connections, %d failed connections, Want %d (failed) and %d (successful)\n", total_connections, failed_connections, expected_failed_connections, expected_connections - expected_failed_connections); #endif } } static void connect_topology () { expected_connections = -1; if ((pg != NULL) && (peers_left == 0)) { expected_connections = GNUNET_TESTING_connect_topology (pg, connection_topology, connect_topology_option, connect_topology_option_modifier, connect_timeout, connect_attempts, NULL, NULL); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n", expected_connections); #endif } GNUNET_SCHEDULER_cancel (die_task); if (expected_connections == GNUNET_SYSERR) { die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from connect topology (bad return)"); } die_task = GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, "from connect topology (timeout)"); } static void create_topology () { peers_left = num_peers; /* Reset counter */ if (GNUNET_TESTING_create_topology (pg, topology, blacklist_topology, blacklist_transports) != GNUNET_SYSERR) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Topology set up, now starting peers!\n"); #endif GNUNET_TESTING_daemons_continue_startup (pg); } else { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from create topology (bad return)"); } GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, "from continue startup (timeout)"); } static void peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to start daemon with error: `%s'\n", emsg); return; } GNUNET_assert (id != NULL); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", (num_peers - peers_left) + 1, num_peers); #endif peers_left--; if (peers_left == 0) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All %d daemons started, now creating topology!\n", num_peers); #endif GNUNET_SCHEDULER_cancel (die_task); /* Set up task in case topology creation doesn't finish * within a reasonable amount of time */ die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, "from peers_started_callback"); connect_topology (); ok = 0; } } /** * Callback indicating that the hostkey was created for a peer. * * @param cls NULL * @param id the peer identity * @param d the daemon handle (pretty useless at this point, remove?) * @param emsg non-null on failure */ void hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, struct GNUNET_TESTING_Daemon *d, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Hostkey callback received error: %s\n", emsg); } #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostkey created for peer `%s'\n", GNUNET_i2s (id)); #endif peers_left--; if (peers_left == 0) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All %d hostkeys created, now creating topology!\n", num_peers); #endif GNUNET_SCHEDULER_cancel (die_task); /* Set up task in case topology creation doesn't finish * within a reasonable amount of time */ die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, "from hostkey_callback"); GNUNET_SCHEDULER_add_now (&create_topology, NULL); ok = 0; } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { unsigned long long topology_num; unsigned long long connect_topology_num; unsigned long long blacklist_topology_num; unsigned long long connect_topology_option_num; char *connect_topology_option_modifier_string; ok = 1; dotOutFile = FOPEN (dotOutFileName, "w"); if (dotOutFile != NULL) { FPRINTF (dotOutFile, "%s", "strict graph G {\n"); } #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons based on config file %s\n", cfgfile); #endif if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", &test_directory)) { ok = 404; if (dotOutFile != NULL) { FCLOSE (dotOutFile); } return; } if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "topology", &topology_num)) topology = topology_num; if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_topology", &connect_topology_num)) connection_topology = connect_topology_num; if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_topology_option", &connect_topology_option_num)) connect_topology_option = connect_topology_option_num; if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "connect_topology_option_modifier", &connect_topology_option_modifier_string)) { if (SSCANF (connect_topology_option_modifier_string, "%lf", &connect_topology_option_modifier) != 1) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), connect_topology_option_modifier_string, "connect_topology_option_modifier", "TESTING"); GNUNET_free (connect_topology_option_modifier_string); ok = 707; if (dotOutFile != NULL) { FCLOSE (dotOutFile); } return; } GNUNET_free (connect_topology_option_modifier_string); } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "blacklist_transports", &blacklist_transports)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "No transports specified for blacklisting in blacklist testcase (this shouldn't happen!)\n"); ok = 808; if (dotOutFile != NULL) { FCLOSE (dotOutFile); } return; } if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "blacklist_topology", &blacklist_topology_num)) blacklist_topology = blacklist_topology_num; if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", &num_peers)) num_peers = DEFAULT_NUM_PEERS; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "CONNECT_TIMEOUT", &connect_timeout)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", "testing", "CONNECT_TIMEOUT"); return; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_attempts", &connect_attempts)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", "testing", "connect_attempts"); return; } main_cfg = cfg; GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1); peers_left = num_peers; /* For this specific test we only really want a CLIQUE topology as the * overlay allowed topology, and a RING topology as the underlying connection * allowed topology. So we will expect only num_peers * 2 connections to * work, and (num_peers * (num_peers - 1)) - (num_peers * 2) to fail. */ expected_connections = num_peers * (num_peers - 1); expected_failed_connections = expected_connections - (num_peers * 2); /* Set up a task to end testing if peer start fails */ die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, "didn't start all daemons in reasonable amount of time!!!"); pg = GNUNET_TESTING_daemons_start (cfg, peers_left, peers_left, peers_left, TIMEOUT, &hostkey_callback, NULL, &peers_started_callback, NULL, &topology_callback, NULL, NULL); } static int check () { int ret; char *const argv[] = { "test-testing-topology-blacklist", "-c", "test_testing_data_topology_blacklist.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; ret = GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-testing-topology-blacklist", "nohelp", options, &run, &ok); if (ret != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "`test-testing-topology-blacklist': Failed with error code %d\n", ret); } return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test_testing_topology_blacklist", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); /** * Need to remove base directory, subdirectories taken care * of by the testing framework. */ if (test_directory != NULL) { if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to remove testing directory %s\n", test_directory); } } return ret; } /* end of test_testing_topology_blacklist.c */ gnunet-0.9.3/src/testing/test_testing_data_topology_internat.conf0000644000175000017500000000020311615731362022424 00000000000000@INLINE@ test_testing_defaults.conf [PATHS] DEFAULTCONFIG = test_testing_data_topology_clique.conf [TESTING] TOPOLOGY = INTERNAT gnunet-0.9.3/src/testing/test_testing_data_remote.conf0000644000175000017500000000032011615731240020132 00000000000000@INLINE@ test_testing_defaults.conf [PATHS] DEFAULTCONFIG = test_testing_data_remote.conf [TESTING] CONTROL_HOST = 127.0.0.1 HOSTFILE = remote_hosts.txt MAX_OUTSTANDING_SSH = 5 [statistics] AUTOSTART = NO gnunet-0.9.3/src/testing/test_testing_data.conf0000644000175000017500000000016211615725571016575 00000000000000@INLINE@ test_testing_defaults.conf [PATHS] DEFAULTCONFIG = test_testing_data.conf [arm] DEFAULTSERVICES = core gnunet-0.9.3/src/testing/gnunet-testing.c0000644000175000017500000002152411760502551015335 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testing/gnunet-testing.c * @brief tool to use testing functionality from cmd line * @author Christian Grothoff */ #include "platform.h" #include "gnunet_getopt_lib.h" #include "gnunet_program_lib.h" #include "gnunet_testing_lib.h" #define HOSTKEYFILESIZE 914 /** * Final status code. */ static int ret; static unsigned int create_hostkey; static unsigned int create_cfg; static int create_no; static char * create_cfg_template; static char * create_hostkey_file; static int create_unique_cfgs (const char * template, const unsigned int no) { int fail = GNUNET_NO; uint16_t port = 20000; uint32_t upnum = 1; uint32_t fdnum = 1; if (GNUNET_NO == GNUNET_DISK_file_test(template)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Configuration template `%s': file not found\n", create_cfg_template); return 1; } int cur = 0; char * cur_file; char *service_home = NULL; char *cur_service_home = NULL; struct GNUNET_CONFIGURATION_Handle *cfg_new = NULL; struct GNUNET_CONFIGURATION_Handle *cfg_tmpl = GNUNET_CONFIGURATION_create(); /* load template */ if ((create_cfg_template != NULL) && (GNUNET_OK != GNUNET_CONFIGURATION_load(cfg_tmpl, create_cfg_template))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not load template `%s'\n", create_cfg_template); GNUNET_CONFIGURATION_destroy(cfg_tmpl); return 1; } /* load defaults */ else if (GNUNET_OK != GNUNET_CONFIGURATION_load(cfg_tmpl, NULL)) { GNUNET_break (0); return 1; } if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg_tmpl, "PATHS", "SERVICEHOME", &service_home)) { GNUNET_asprintf(&service_home, "%s", "/tmp/testing"); } else { int s = strlen (service_home); if (service_home[s-1] == DIR_SEPARATOR) service_home[s-1] = '\0'; } while (cur < no) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating configuration no. %u \n", cur); if (create_cfg_template != NULL) GNUNET_asprintf (&cur_file,"%04u-%s",cur, create_cfg_template); else GNUNET_asprintf (&cur_file,"%04u%s",cur, ".conf"); GNUNET_asprintf (&cur_service_home, "%s-%04u%c",service_home, cur, DIR_SEPARATOR); GNUNET_CONFIGURATION_set_value_string (cfg_tmpl,"PATHS","SERVICEHOME", cur_service_home); GNUNET_CONFIGURATION_set_value_string (cfg_tmpl,"PATHS","DEFAULTCONFIG", cur_file); GNUNET_free (cur_service_home); cfg_new = GNUNET_TESTING_create_cfg(cfg_tmpl, cur, &port, &upnum, NULL, &fdnum); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Writing configuration no. %u to file `%s' \n", cur, cur_file); if (GNUNET_OK != GNUNET_CONFIGURATION_write(cfg_new, cur_file)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write configuration no. %u \n", cur); fail = GNUNET_YES; } GNUNET_CONFIGURATION_destroy (cfg_new); GNUNET_free (cur_file); if (fail == GNUNET_YES) break; cur ++; } GNUNET_CONFIGURATION_destroy(cfg_tmpl); GNUNET_free (service_home); if (fail == GNUNET_NO) return 0; else return 1; } static int create_hostkeys (const unsigned int no) { struct GNUNET_DISK_FileHandle *fd; int cur = 0; uint64_t fs; uint64_t total_hostkeys; char *hostkey_data; char *hostkey_src_file; char *hostkey_dest_file; /* prepare hostkeys */ if (create_hostkey_file == NULL) hostkey_src_file = "../../contrib/testing_hostkeys.dat"; else { hostkey_src_file = create_hostkey_file; } if (GNUNET_YES != GNUNET_DISK_file_test (hostkey_src_file)) { if (create_hostkey_file == NULL) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not read hostkeys file, specify hostkey file with -H!\n")); else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Specified hostkey file `%s' not found!\n"), create_hostkey_file); return 1; } else { /* Check hostkey file size, read entire thing into memory */ fd = GNUNET_DISK_file_open (hostkey_src_file, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); if (NULL == fd) { GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", hostkey_src_file); return 1; } if (GNUNET_OK != GNUNET_DISK_file_size (hostkey_src_file, &fs, GNUNET_YES, GNUNET_YES)) fs = 0; if (0 != (fs % HOSTKEYFILESIZE)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "File size %llu seems incorrect for hostkeys...\n", fs); } else { total_hostkeys = fs / HOSTKEYFILESIZE; hostkey_data = GNUNET_malloc_large (fs); GNUNET_assert (fs == GNUNET_DISK_file_read (fd, hostkey_data, fs)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read %llu hostkeys from file\n", total_hostkeys); } GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); } while (cur < no) { GNUNET_asprintf (&hostkey_dest_file, "%04u-hostkey",cur); GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_create_for_file (hostkey_dest_file)); fd = GNUNET_DISK_file_open (hostkey_dest_file, GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_CREATE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); GNUNET_assert (fd != NULL); GNUNET_assert (HOSTKEYFILESIZE == GNUNET_DISK_file_write (fd, &hostkey_data[cur * HOSTKEYFILESIZE], HOSTKEYFILESIZE)); GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", "Wrote hostkey to file: `%s' \n", hostkey_dest_file); GNUNET_free (hostkey_dest_file); cur ++; } GNUNET_free (hostkey_data); return 0; } /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param cfg configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { /* main code here */ if (create_cfg == GNUNET_YES) { if (create_no > 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating %u configuration files based on template `%s'\n", create_no, create_cfg_template); ret = create_unique_cfgs (create_cfg_template, create_no); } else { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing arguments! \n"); ret = 1; } } if (create_hostkey == GNUNET_YES) { if (create_no > 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating %u hostkeys \n", create_no); ret = create_hostkeys (create_no); } else { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing arguments! \n"); ret = 1; } } GNUNET_free_non_null (create_cfg_template); } /** * The main function. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { {'C', "cfg", NULL, gettext_noop ("create unique configuration files"), GNUNET_NO, &GNUNET_GETOPT_set_one, &create_cfg}, {'k', "key", NULL, gettext_noop ("create hostkey files from pre-computed hostkey list"), GNUNET_NO, &GNUNET_GETOPT_set_one, &create_hostkey}, {'H', "hostkeys", NULL, gettext_noop ("host key file"), GNUNET_YES, &GNUNET_GETOPT_set_string, &create_hostkey_file}, {'n', "number", NULL, gettext_noop ("number of unique configuration files or hostkeys to create"), GNUNET_YES, &GNUNET_GETOPT_set_uint, &create_no}, {'t', "template", NULL, gettext_noop ("configuration template"), GNUNET_YES, &GNUNET_GETOPT_set_string, &create_cfg_template}, GNUNET_GETOPT_OPTION_END }; return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-testing", gettext_noop ("Command line tool to access the testing library"), options, &run, NULL)) ? ret : 1; } /* end of gnunet-testing.c */ gnunet-0.9.3/src/testing/test_testing_peergroup.c0000644000175000017500000001051611760502551017165 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testing/test_testing_peergroup.c * @brief testcase for functions to connect peers in testing_peergroup.c */ #include "platform.h" #include "gnunet_testing_lib.h" #define VERBOSE GNUNET_NO #define NUM_PEERS 4 /** * How long until we give up on connecting the peers? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) static int ok; static int peers_left; static struct GNUNET_TESTING_PeerGroup *pg; /** * Check whether peers successfully shut down. */ void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); #endif if (ok == 0) ok = 666; } else { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); #endif ok = 0; } } static void my_cb (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peergroup callback called with error, aborting test!\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n"); ok = 1; GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer Group started successfully, ending test!\n"); /** * If something is to actually be DONE with the testcase, it should * be put in here. Usually there will be a struct declared (or global * variables can be used) to keep track of the state, statistics, * handles to peers, etc. The example here is the opaque "TestCaseData" * struct that could be passed into a function "additional_code_for_testing" * which can be used to perform actions on the peers in the peergroup. * Also, the GNUNET_TESTING_daemons_stop call would need to be removed, * and only called once all of the testing is complete. */ /** * struct TestcaseData *state_closure; * GNUNET_SCHEDULER_add_now(&additional_code_for_testing, state_closure); */ GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_CONFIGURATION_Handle *testing_cfg; ok = 1; testing_cfg = GNUNET_CONFIGURATION_create (); GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (testing_cfg, cfgfile)); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", "use_progressbars", "YES"); #endif peers_left = NUM_PEERS; pg = GNUNET_TESTING_peergroup_start (testing_cfg, peers_left, TIMEOUT, NULL, &my_cb, NULL, NULL); GNUNET_assert (pg != NULL); } static int check () { char *const argv[] = { "test-testing-peergroup", "-c", "test_testing_peergroup_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-testing-peergroup", "nohelp", options, &run, &ok); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-testing-peergroup", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-testing"); return ret; } /* end of test_testing_peergroup.c */ gnunet-0.9.3/src/testing/test_testing_connect_peer1.conf0000644000175000017500000000126111760476766020424 00000000000000@INLINE@ test_testing_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-testing-connect-peer1/ DEFAULTCONFIG = test_testing_connect_peer1.conf [transport-tcp] PORT = 12568 [arm] PORT = 12566 DEFAULTSERVICES = core UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12567 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12564 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12569 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12565 UNIXPATH = /tmp/gnunet-p1-service-transport.sock [core] PORT = 12570 UNIXPATH = /tmp/gnunet-p1-service-core.sock [ats] PORT = 12571 UNIXPATH = /tmp/gnunet-p1-service-ats.sock gnunet-0.9.3/src/testing/testing_group.c0000644000175000017500000064613311761753145015274 00000000000000/* This file is part of GNUnet (C) 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testing/testing_group.c * @brief convenience API for writing testcases for GNUnet * @author Nathan Evans * @author Christian Grothoff */ #include "platform.h" #include "gnunet_constants.h" #include "gnunet_arm_service.h" #include "gnunet_testing_lib.h" #include "gnunet_core_service.h" #define USE_START_HELPER GNUNET_YES #define OLD 1 /* Before connecting peers, send all of the HELLOs */ #define USE_SEND_HELLOS GNUNET_NO #define TOPOLOGY_HACK GNUNET_YES /** * Lowest port used for GNUnet testing. Should be high enough to not * conflict with other applications running on the hosts but be low * enough to not conflict with client-ports (typically starting around * 32k). */ #define LOW_PORT 12000 /** * Highest port used for GNUnet testing. Should be low enough to not * conflict with the port range for "local" ports (client apps; see * /proc/sys/net/ipv4/ip_local_port_range on Linux for example). */ #define HIGH_PORT 56000 /* Maximum time to delay connect attempt */ #define MAX_CONNECT_DELAY 300 /** * Which list of peers do we need to modify? */ enum PeerLists { /** Modify allowed peers */ ALLOWED, /** Modify connect peers */ CONNECT, /** Modify blacklist peers */ BLACKLIST, /** Modify workingset peers */ WORKING_SET }; /** * Prototype of a function called whenever two peers would be connected * in a certain topology. */ typedef unsigned int (*GNUNET_TESTING_ConnectionProcessor) (struct GNUNET_TESTING_PeerGroup * pg, unsigned int first, unsigned int second, enum PeerLists list, unsigned int check); /** * Context for handling churning a peer group */ struct ChurnContext { /** * The peergroup we are dealing with. */ struct GNUNET_TESTING_PeerGroup *pg; /** * Name of the service to churn on/off, NULL * to churn entire peer. */ char *service; /** * Callback used to notify of churning finished */ GNUNET_TESTING_NotifyCompletion cb; /** * Closure for callback */ void *cb_cls; /** * Number of peers that still need to be started */ unsigned int num_to_start; /** * Number of peers that still need to be stopped */ unsigned int num_to_stop; /** * Number of peers that failed to start */ unsigned int num_failed_start; /** * Number of peers that failed to stop */ unsigned int num_failed_stop; }; struct RestartContext { /** * The group of peers being restarted */ struct GNUNET_TESTING_PeerGroup *peer_group; /** * How many peers have been restarted thus far */ unsigned int peers_restarted; /** * How many peers got an error when restarting */ unsigned int peers_restart_failed; /** * The function to call once all peers have been restarted */ GNUNET_TESTING_NotifyCompletion callback; /** * Closure for callback function */ void *callback_cls; }; struct SendHelloContext { /** * Global handle to the peer group. */ struct GNUNET_TESTING_PeerGroup *pg; /** * The data about this specific peer. */ struct PeerData *peer; /** * The next HELLO that needs sent to this peer. */ struct PeerConnection *peer_pos; /** * Are we connected to CORE yet? */ unsigned int core_ready; /** * How many attempts should we make for failed connections? */ unsigned int connect_attempts; /** * Task for scheduling core connect requests to be sent. */ GNUNET_SCHEDULER_TaskIdentifier core_connect_task; }; struct ShutdownContext { struct GNUNET_TESTING_PeerGroup *pg; /** * Total peers to wait for */ unsigned int total_peers; /** * Number of peers successfully shut down */ unsigned int peers_down; /** * Number of peers failed to shut down */ unsigned int peers_failed; /** * Number of peers we have started shutting * down. If too many, wait on them. */ unsigned int outstanding; /** * Timeout for shutdown. */ struct GNUNET_TIME_Relative timeout; /** * Callback to call when all peers either * shutdown or failed to shutdown */ GNUNET_TESTING_NotifyCompletion cb; /** * Closure for cb */ void *cb_cls; /** * Should we delete all of the files from the peers? */ int delete_files; }; /** * Individual shutdown context for a particular peer. */ struct PeerShutdownContext { /** * Pointer to the high level shutdown context. */ struct ShutdownContext *shutdown_ctx; /** * The daemon handle for the peer to shut down. */ struct GNUNET_TESTING_Daemon *daemon; }; /** * Individual shutdown context for a particular peer. */ struct PeerRestartContext { /** * Pointer to the high level restart context. */ struct ChurnRestartContext *churn_restart_ctx; /** * The daemon handle for the peer to shut down. */ struct GNUNET_TESTING_Daemon *daemon; }; struct ServiceStartContext { struct GNUNET_TESTING_PeerGroup *pg; unsigned int remaining; GNUNET_TESTING_NotifyCompletion cb; unsigned int outstanding; char *service; struct GNUNET_TIME_Relative timeout; void *cb_cls; }; /** * Individual shutdown context for a particular peer. */ struct PeerServiceStartContext { /** * Pointer to the high level start context. */ struct ServiceStartContext *start_ctx; /** * The daemon handle for the peer to start the service on. */ struct GNUNET_TESTING_Daemon *daemon; }; struct CreateTopologyContext { /** * Function to call with number of connections */ GNUNET_TESTING_NotifyConnections cont; /** * Closure for connection notification */ void *cls; }; enum States { /** Waiting to read number of peers */ NUM_PEERS, /** Should find next peer index */ PEER_INDEX, /** Should find colon */ COLON, /** Should read other peer index, space, or endline */ OTHER_PEER_INDEX }; #if OLD struct PeerConnection { /** * Doubly Linked list */ struct PeerConnection *prev; /* * Doubly Linked list */ struct PeerConnection *next; /* * Index of daemon in pg->peers */ uint32_t index; }; #endif struct InternalStartContext { /** * Pointer to peerdata */ struct PeerData *peer; /** * Timeout for peer startup */ struct GNUNET_TIME_Relative timeout; /** * Client callback for hostkey notification */ GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback; /** * Closure for hostkey_callback */ void *hostkey_cls; /** * Client callback for peer start notification */ GNUNET_TESTING_NotifyDaemonRunning start_cb; /** * Closure for cb */ void *start_cb_cls; /** * Hostname, where to start the peer */ const char *hostname; /** * Username to use when connecting to the * host via ssh. */ const char *username; /** * Pointer to starting memory location of a hostkey */ const char *hostkey; /** * Port to use for ssh. */ uint16_t sshport; }; struct ChurnRestartContext { /** * PeerGroup that we are working with. */ struct GNUNET_TESTING_PeerGroup *pg; /** * Number of restarts currently in flight. */ unsigned int outstanding; /** * Handle to the underlying churn context. */ struct ChurnContext *churn_ctx; /** * How long to allow the operation to take. */ struct GNUNET_TIME_Relative timeout; }; struct OutstandingSSH { struct OutstandingSSH *next; struct OutstandingSSH *prev; /** * Number of current ssh connections. */ uint32_t outstanding; /** * The hostname of this peer. */ const char *hostname; }; /** * Data we keep per peer. */ struct PeerData { /** * (Initial) configuration of the host. * (initial because clients could change * it and we would not know about those * updates). */ struct GNUNET_CONFIGURATION_Handle *cfg; /** * Handle for controlling the daemon. */ struct GNUNET_TESTING_Daemon *daemon; /** * The peergroup this peer belongs to. */ struct GNUNET_TESTING_PeerGroup *pg; #if OLD /** * Linked list of allowed peer connections. */ struct PeerConnection *allowed_peers_head; /** * Linked list of allowed peer connections. */ struct PeerConnection *allowed_peers_tail; /** * Linked list of blacklisted peer connections. */ struct PeerConnection *blacklisted_peers_head; /** * Linked list of blacklisted peer connections. */ struct PeerConnection *blacklisted_peers_tail; /** * Linked list of connect peer connections. */ struct PeerConnection *connect_peers_head; /** * Linked list of connect peer connections. */ struct PeerConnection *connect_peers_tail; /** * Linked list of connect peer connections. */ struct PeerConnection *connect_peers_working_set_head; /** * Linked list of connect peer connections. */ struct PeerConnection *connect_peers_working_set_tail; #else /** * Hash map of allowed peer connections (F2F created topology) */ struct GNUNET_CONTAINER_MultiHashMap *allowed_peers; /** * Hash map of blacklisted peers */ struct GNUNET_CONTAINER_MultiHashMap *blacklisted_peers; /** * Hash map of peer connections */ struct GNUNET_CONTAINER_MultiHashMap *connect_peers; /** * Temporary hash map of peer connections */ struct GNUNET_CONTAINER_MultiHashMap *connect_peers_working_set; #endif /** * Temporary variable for topology creation, should be reset before * creating any topology so the count is valid once finished. */ int num_connections; /** * Context to keep track of peers being started, to * stagger hostkey generation and peer startup. */ struct InternalStartContext internal_context; /** * Task ID for the queued internal_continue_startup task */ GNUNET_SCHEDULER_TaskIdentifier startup_task; }; /** * Linked list of per-host data. */ struct HostData { /** * Name of the host. */ char *hostname; /** * SSH username to use when connecting to this host. */ char *username; /** * SSH port to use when connecting to this host. */ uint16_t sshport; /** * Lowest port that we have not yet used * for GNUnet. */ uint16_t minport; }; struct TopologyIterateContext { /** * The peergroup we are working with. */ struct GNUNET_TESTING_PeerGroup *pg; /** * Callback for notifying of two connected peers. */ GNUNET_TESTING_NotifyTopology topology_cb; /** * Closure for topology_cb */ void *cls; /** * Number of peers currently connected to. */ unsigned int connected; /** * Number of peers we have finished iterating. */ unsigned int completed; /** * Number of peers total. */ unsigned int total; }; struct StatsIterateContext { /** * The peergroup that we are dealing with. */ struct GNUNET_TESTING_PeerGroup *pg; /** * Continuation to call once all stats information has been retrieved. */ GNUNET_STATISTICS_Callback cont; /** * Proc function to call on each value received. */ GNUNET_TESTING_STATISTICS_Iterator proc; /** * Closure for topology_cb */ void *cls; /** * Number of peers currently connected to. */ unsigned int connected; /** * Number of peers we have finished iterating. */ unsigned int completed; /** * Number of peers total. */ unsigned int total; }; struct CoreContext { void *iter_context; struct GNUNET_TESTING_Daemon *daemon; }; struct StatsCoreContext { void *iter_context; struct GNUNET_TESTING_Daemon *daemon; /** * Handle to the statistics service. */ struct GNUNET_STATISTICS_Handle *stats_handle; /** * Handle for getting statistics. */ struct GNUNET_STATISTICS_GetHandle *stats_get_handle; }; struct ConnectTopologyContext { /** * How many connections are left to create. */ unsigned int remaining_connections; /** * Handle to group of peers. */ struct GNUNET_TESTING_PeerGroup *pg; /** * How long to try this connection before timing out. */ struct GNUNET_TIME_Relative connect_timeout; /** * How many times to retry connecting the two peers. */ unsigned int connect_attempts; /** * Temp value set for each iteration. */ //struct PeerData *first; /** * Notification that all peers are connected. */ GNUNET_TESTING_NotifyCompletion notify_connections_done; /** * Closure for notify. */ void *notify_cls; }; struct ConnectContext; /** * Handle to a group of GNUnet peers. */ struct GNUNET_TESTING_PeerGroup { /** * Configuration template. */ const struct GNUNET_CONFIGURATION_Handle *cfg; struct ConnectContext *cc_head; struct ConnectContext *cc_tail; /** * Function to call on each started daemon. */ //GNUNET_TESTING_NotifyDaemonRunning cb; /** * Closure for cb. */ //void *cb_cls; /* * Function to call on each topology connection created */ GNUNET_TESTING_NotifyConnection notify_connection; /* * Callback for notify_connection */ void *notify_connection_cls; /** * Array of information about hosts. */ struct HostData *hosts; /** * Number of hosts (size of HostData) */ unsigned int num_hosts; /** * Array of "total" peers. */ struct PeerData *peers; /** * Number of peers in this group. */ unsigned int total; /** * At what time should we fail the peer startup process? */ struct GNUNET_TIME_Absolute max_timeout; /** * How many peers are being started right now? */ unsigned int starting; /** * How many peers have already been started? */ unsigned int started; /** * Number of possible connections to peers * at a time. */ unsigned int max_outstanding_connections; /** * Number of ssh connections to peers (max). */ unsigned int max_concurrent_ssh; /** * Number of connects we are waiting on, allows us to rate limit * connect attempts. */ unsigned int outstanding_connects; /** * Number of HELLOs we have yet to send. */ unsigned int remaining_hellos; /** * How many connects have already been scheduled? */ unsigned int total_connects_scheduled; /** * Hostkeys loaded from a file. */ char *hostkey_data; /** * Head of DLL to keep track of the number of outstanding * ssh connections per peer. */ struct OutstandingSSH *ssh_head; /** * Tail of DLL to keep track of the number of outstanding * ssh connections per peer. */ struct OutstandingSSH *ssh_tail; /** * Stop scheduling peers connecting. */ unsigned int stop_connects; /** * Connection context for peer group. */ struct ConnectTopologyContext ct_ctx; }; struct UpdateContext { /** * The altered configuration. */ struct GNUNET_CONFIGURATION_Handle *ret; /** * The original configuration to alter. */ const struct GNUNET_CONFIGURATION_Handle *orig; /** * The hostname that this peer will run on. */ const char *hostname; /** * The next possible port to assign. */ unsigned int nport; /** * Unique number for unix domain sockets. */ unsigned int upnum; /** * Unique number for this peer/host to offset * things that are grouped by host. */ unsigned int fdnum; }; struct ConnectContext { struct ConnectContext *next; struct ConnectContext *prev; /** * Index of peer to connect second to. */ uint32_t first_index; /** * Index of peer to connect first to. */ uint32_t second_index; /** * Task associated with the attempt to connect. */ GNUNET_SCHEDULER_TaskIdentifier task; /** * Context in 'testing.c', to cancel connection attempt. */ struct GNUNET_TESTING_ConnectContext *cc; /** * Higher level topology connection context. */ struct ConnectTopologyContext *ct_ctx; /** * Whether this connection has been accounted for in the schedule_connect call. */ int counted; }; struct UnblacklistContext { /** * The peergroup */ struct GNUNET_TESTING_PeerGroup *pg; /** * uid of the first peer */ uint32_t first_uid; }; struct RandomContext { /** * The peergroup */ struct GNUNET_TESTING_PeerGroup *pg; /** * uid of the first peer */ uint32_t first_uid; /** * Peer data for first peer. */ struct PeerData *first; /** * Random percentage to use */ double percentage; }; struct MinimumContext { /** * The peergroup */ struct GNUNET_TESTING_PeerGroup *pg; /** * uid of the first peer */ uint32_t first_uid; /** * Peer data for first peer. */ struct PeerData *first; /** * Number of conns per peer */ unsigned int num_to_add; /** * Permuted array of all possible connections. Only add the Nth * peer if it's in the Nth position. */ unsigned int *pg_array; /** * What number is the current element we are iterating over? */ unsigned int current; }; struct DFSContext { /** * The peergroup */ struct GNUNET_TESTING_PeerGroup *pg; /** * uid of the first peer */ uint32_t first_uid; /** * uid of the second peer */ uint32_t second_uid; /** * Peer data for first peer. */ struct PeerData *first; /** * Which peer has been chosen as the one to add? */ unsigned int chosen; /** * What number is the current element we are iterating over? */ unsigned int current; }; /** * Simple struct to keep track of progress, and print a * nice little percentage meter for long running tasks. */ struct ProgressMeter { unsigned int total; unsigned int modnum; unsigned int dotnum; unsigned int completed; int print; char *startup_string; }; #if !OLD /** * Convert unique ID to hash code. * * @param uid unique ID to convert * @param hash set to uid (extended with zeros) */ static void hash_from_uid (uint32_t uid, GNUNET_HashCode * hash) { memset (hash, 0, sizeof (GNUNET_HashCode)); *((uint32_t *) hash) = uid; } /** * Convert hash code to unique ID. * * @param uid unique ID to convert * @param hash set to uid (extended with zeros) */ static void uid_from_hash (const GNUNET_HashCode * hash, uint32_t * uid) { memcpy (uid, hash, sizeof (uint32_t)); } #endif #if USE_SEND_HELLOS static struct GNUNET_CORE_MessageHandler no_handlers[] = { {NULL, 0, 0} }; #endif /** * Create a meter to keep track of the progress of some task. * * @param total the total number of items to complete * @param start_string a string to prefix the meter with (if printing) * @param print GNUNET_YES to print the meter, GNUNET_NO to count * internally only * * @return the progress meter */ static struct ProgressMeter * create_meter (unsigned int total, char *start_string, int print) { struct ProgressMeter *ret; ret = GNUNET_malloc (sizeof (struct ProgressMeter)); ret->print = print; ret->total = total; ret->modnum = total / 4; if (ret->modnum == 0) /* Divide by zero check */ ret->modnum = 1; ret->dotnum = (total / 50) + 1; if (start_string != NULL) ret->startup_string = GNUNET_strdup (start_string); else ret->startup_string = GNUNET_strdup (""); return ret; } /** * Update progress meter (increment by one). * * @param meter the meter to update and print info for * * @return GNUNET_YES if called the total requested, * GNUNET_NO if more items expected */ static int update_meter (struct ProgressMeter *meter) { if (meter->print == GNUNET_YES) { if (meter->completed % meter->modnum == 0) { if (meter->completed == 0) { FPRINTF (stdout, "%sProgress: [0%%", meter->startup_string); } else FPRINTF (stdout, "%d%%", (int) (((float) meter->completed / meter->total) * 100)); } else if (meter->completed % meter->dotnum == 0) FPRINTF (stdout, "%s", "."); if (meter->completed + 1 == meter->total) FPRINTF (stdout, "%d%%]\n", 100); fflush (stdout); } meter->completed++; if (meter->completed == meter->total) return GNUNET_YES; if (meter->completed > meter->total) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Progress meter overflow!!\n"); return GNUNET_NO; } /** * Reset progress meter. * * @param meter the meter to reset * * @return GNUNET_YES if meter reset, * GNUNET_SYSERR on error */ static int reset_meter (struct ProgressMeter *meter) { if (meter == NULL) return GNUNET_SYSERR; meter->completed = 0; return GNUNET_YES; } /** * Release resources for meter * * @param meter the meter to free */ static void free_meter (struct ProgressMeter *meter) { GNUNET_free_non_null (meter->startup_string); GNUNET_free (meter); } /** * Get a topology from a string input. * * @param topology where to write the retrieved topology * @param topology_string The string to attempt to * get a configuration value from * @return GNUNET_YES if topology string matched a * known topology, GNUNET_NO if not */ int GNUNET_TESTING_topology_get (enum GNUNET_TESTING_Topology *topology, const char *topology_string) { /** * Strings representing topologies in enum */ static const char *topology_strings[] = { /** * A clique (everyone connected to everyone else). */ "CLIQUE", /** * Small-world network (2d torus plus random links). */ "SMALL_WORLD", /** * Small-world network (ring plus random links). */ "SMALL_WORLD_RING", /** * Ring topology. */ "RING", /** * 2-d torus. */ "2D_TORUS", /** * Random graph. */ "ERDOS_RENYI", /** * Certain percentage of peers are unable to communicate directly * replicating NAT conditions */ "INTERNAT", /** * Scale free topology. */ "SCALE_FREE", /** * Straight line topology. */ "LINE", /** * All peers are disconnected. */ "NONE", /** * Read the topology from a file. */ "FROM_FILE", NULL }; int curr = 0; if (topology_string == NULL) return GNUNET_NO; while (topology_strings[curr] != NULL) { if (strcasecmp (topology_strings[curr], topology_string) == 0) { *topology = curr; return GNUNET_YES; } curr++; } *topology = GNUNET_TESTING_TOPOLOGY_NONE; return GNUNET_NO; } /** * Get connect topology option from string input. * * @param topology_option where to write the retrieved topology * @param topology_string The string to attempt to * get a configuration value from * @return GNUNET_YES if string matched a known * topology option, GNUNET_NO if not */ int GNUNET_TESTING_topology_option_get (enum GNUNET_TESTING_TopologyOption *topology_option, const char *topology_string) { /** * Options for connecting a topology as strings. */ static const char *topology_option_strings[] = { /** * Try to connect all peers specified in the topology. */ "CONNECT_ALL", /** * Choose a random subset of connections to create. */ "CONNECT_RANDOM_SUBSET", /** * Create at least X connections for each peer. */ "CONNECT_MINIMUM", /** * Using a depth first search, create one connection * per peer. If any are missed (graph disconnected) * start over at those peers until all have at least one * connection. */ "CONNECT_DFS", /** * Find the N closest peers to each allowed peer in the * topology and make sure a connection to those peers * exists in the connect topology. */ "CONNECT_CLOSEST", /** * No options specified. */ "CONNECT_NONE", NULL }; int curr = 0; if (topology_string == NULL) return GNUNET_NO; while (NULL != topology_option_strings[curr]) { if (strcasecmp (topology_option_strings[curr], topology_string) == 0) { *topology_option = curr; return GNUNET_YES; } curr++; } *topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_NONE; return GNUNET_NO; } /** * Function to iterate over options. Copies * the options to the target configuration, * updating PORT values as needed. * * @param cls closure * @param section name of the section * @param option name of the option * @param value value of the option */ static void update_config (void *cls, const char *section, const char *option, const char *value) { struct UpdateContext *ctx = cls; unsigned int ival; char cval[12]; char uval[128]; char *single_variable; char *per_host_variable; unsigned long long num_per_host; GNUNET_asprintf (&single_variable, "single_%s_per_host", section); GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section); if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival))) { if ((ival != 0) && (GNUNET_YES != GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing", single_variable))) { GNUNET_snprintf (cval, sizeof (cval), "%u", ctx->nport++); value = cval; } else if ((ival != 0) && (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing", single_variable)) && GNUNET_CONFIGURATION_get_value_number (ctx->orig, "testing", per_host_variable, &num_per_host)) { GNUNET_snprintf (cval, sizeof (cval), "%u", ival + ctx->fdnum % num_per_host); value = cval; } /* FIXME: REMOVE FOREVER HACK HACK HACK */ if (0 == strcasecmp (section, "transport-tcp")) GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, "ADVERTISED_PORT", value); } if (0 == strcmp (option, "UNIXPATH")) { if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing", single_variable)) { GNUNET_snprintf (uval, sizeof (uval), "/tmp/test-service-%s-%u", section, ctx->upnum++); value = uval; } else if ((GNUNET_YES == GNUNET_CONFIGURATION_get_value_number (ctx->orig, "testing", per_host_variable, &num_per_host)) && (num_per_host > 0)) { GNUNET_snprintf (uval, sizeof (uval), "/tmp/test-service-%s-%u", section, ctx->fdnum % num_per_host); value = uval; } } if ((0 == strcmp (option, "HOSTNAME")) && (ctx->hostname != NULL)) { value = ctx->hostname; } GNUNET_free (single_variable); GNUNET_free (per_host_variable); GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, option, value); } /** * Create a new configuration using the given configuration * as a template; however, each PORT in the existing cfg * must be renumbered by incrementing "*port". If we run * out of "*port" numbers, return NULL. * * @param cfg template configuration * @param off the current peer offset * @param port port numbers to use, update to reflect * port numbers that were used * @param upnum number to make unix domain socket names unique * @param hostname hostname of the controlling host, to allow control connections from * @param fdnum number used to offset the unix domain socket for grouped processes * (such as statistics or peerinfo, which can be shared among others) * * @return new configuration, NULL on error */ struct GNUNET_CONFIGURATION_Handle * GNUNET_TESTING_create_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, uint32_t off, uint16_t * port, uint32_t * upnum, const char *hostname, uint32_t * fdnum) { struct UpdateContext uc; uint16_t orig; char *control_host; char *allowed_hosts; unsigned long long skew_variance; unsigned long long skew_offset; long long actual_offset; orig = *port; uc.nport = *port; uc.upnum = *upnum; uc.fdnum = *fdnum; uc.ret = GNUNET_CONFIGURATION_create (); uc.hostname = hostname; uc.orig = cfg; GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc); if (uc.nport >= HIGH_PORT) { *port = orig; GNUNET_CONFIGURATION_destroy (uc.ret); return NULL; } if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "skew_variance", &skew_variance)) && (skew_variance > 0)) { skew_offset = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, skew_variance + 1); actual_offset = skew_offset - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, skew_variance + 1); /* Min is -skew_variance, Max is skew_variance */ skew_offset = skew_variance + actual_offset; /* Normal distribution around 0 */ GNUNET_CONFIGURATION_set_value_number (uc.ret, "testing", "skew_offset", skew_offset); } if (GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "control_host", &control_host) == GNUNET_OK) { if (hostname != NULL) GNUNET_asprintf (&allowed_hosts, "%s; 127.0.0.1; %s;", control_host, hostname); else GNUNET_asprintf (&allowed_hosts, "%s; 127.0.0.1;", control_host); GNUNET_CONFIGURATION_set_value_string (uc.ret, "core", "ACCEPT_FROM", allowed_hosts); GNUNET_CONFIGURATION_set_value_string (uc.ret, "nse", "ACCEPT_FROM", allowed_hosts); GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport", "ACCEPT_FROM", allowed_hosts); GNUNET_CONFIGURATION_set_value_string (uc.ret, "dht", "ACCEPT_FROM", allowed_hosts); GNUNET_CONFIGURATION_set_value_string (uc.ret, "statistics", "ACCEPT_FROM", allowed_hosts); GNUNET_CONFIGURATION_set_value_string (uc.ret, "core", "UNIXPATH", ""); GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport", "UNIXPATH", ""); GNUNET_CONFIGURATION_set_value_string (uc.ret, "dht", "UNIXPATH", ""); GNUNET_CONFIGURATION_set_value_string (uc.ret, "statistics", "UNIXPATH", ""); GNUNET_CONFIGURATION_set_value_string (uc.ret, "nse", "UNIXPATH", ""); GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "USE_LOCALADDR", "YES"); GNUNET_free_non_null (control_host); GNUNET_free (allowed_hosts); } /* arm needs to know to allow connections from the host on which it is running, * otherwise gnunet-arm is unable to connect to it in some instances */ if (hostname != NULL) { GNUNET_asprintf (&allowed_hosts, "%s; 127.0.0.1;", hostname); GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "BINDTO", hostname); GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "INTERNAL_ADDRESS", hostname); GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "EXTERNAL_ADDRESS", hostname); GNUNET_CONFIGURATION_set_value_string (uc.ret, "disablev6", "BINDTO", "YES"); GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-tcp", "USE_LOCALADDR", "YES"); GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-udp", "USE_LOCALADDR", "YES"); GNUNET_CONFIGURATION_set_value_string (uc.ret, "arm", "ACCEPT_FROM", allowed_hosts); GNUNET_free (allowed_hosts); } else { GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "USE_LOCALADDR", "YES"); GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "BINDTO", "127.0.0.1"); GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "INTERNAL_ADDRESS", "127.0.0.1"); GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "EXTERNAL_ADDRESS", "127.0.0.1"); GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "disablev6", "YES"); } *port = (uint16_t) uc.nport; *upnum = uc.upnum; uc.fdnum++; *fdnum = uc.fdnum; return uc.ret; } /* * Remove entries from the peer connection list * * @param pg the peer group we are working with * @param first index of the first peer * @param second index of the second peer * @param list the peer list to use * @param check UNUSED * * @return the number of connections added (can be 0, 1 or 2) * */ static unsigned int remove_connections (struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, unsigned int second, enum PeerLists list, unsigned int check) { int removed; #if OLD struct PeerConnection **first_list; struct PeerConnection **second_list; struct PeerConnection *first_iter; struct PeerConnection *second_iter; struct PeerConnection **first_tail; struct PeerConnection **second_tail; #else GNUNET_HashCode hash_first; GNUNET_HashCode hash_second; hash_from_uid (first, &hash_first); hash_from_uid (second, &hash_second); #endif removed = 0; #if OLD switch (list) { case ALLOWED: first_list = &pg->peers[first].allowed_peers_head; second_list = &pg->peers[second].allowed_peers_head; first_tail = &pg->peers[first].allowed_peers_tail; second_tail = &pg->peers[second].allowed_peers_tail; break; case CONNECT: first_list = &pg->peers[first].connect_peers_head; second_list = &pg->peers[second].connect_peers_head; first_tail = &pg->peers[first].connect_peers_tail; second_tail = &pg->peers[second].connect_peers_tail; break; case BLACKLIST: first_list = &pg->peers[first].blacklisted_peers_head; second_list = &pg->peers[second].blacklisted_peers_head; first_tail = &pg->peers[first].blacklisted_peers_tail; second_tail = &pg->peers[second].blacklisted_peers_tail; break; case WORKING_SET: first_list = &pg->peers[first].connect_peers_working_set_head; second_list = &pg->peers[second].connect_peers_working_set_head; first_tail = &pg->peers[first].connect_peers_working_set_tail; second_tail = &pg->peers[second].connect_peers_working_set_tail; break; default: GNUNET_break (0); return 0; } first_iter = *first_list; while (first_iter != NULL) { if (first_iter->index == second) { GNUNET_CONTAINER_DLL_remove (*first_list, *first_tail, first_iter); GNUNET_free (first_iter); removed++; break; } first_iter = first_iter->next; } second_iter = *second_list; while (second_iter != NULL) { if (second_iter->index == first) { GNUNET_CONTAINER_DLL_remove (*second_list, *second_tail, second_iter); GNUNET_free (second_iter); removed++; break; } second_iter = second_iter->next; } #else if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (pg-> peers[first].blacklisted_peers, &hash_second)) { GNUNET_CONTAINER_multihashmap_remove_all (pg-> peers[first].blacklisted_peers, &hash_second); } if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (pg-> peers[second].blacklisted_peers, &hash_first)) { GNUNET_CONTAINER_multihashmap_remove_all (pg-> peers[second].blacklisted_peers, &hash_first); } #endif return removed; } /** * Add entries to the some list * * @param pg the peer group we are working with * @param first index of the first peer * @param second index of the second peer * @param list the list type that we should modify * @param check GNUNET_YES to check lists before adding * GNUNET_NO to force add * * @return the number of connections added (can be 0, 1 or 2) * */ static unsigned int add_connections (struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, unsigned int second, enum PeerLists list, unsigned int check) { int added; int add_first; int add_second; struct PeerConnection **first_list; struct PeerConnection **second_list; struct PeerConnection *first_iter; struct PeerConnection *second_iter; struct PeerConnection *new_first; struct PeerConnection *new_second; struct PeerConnection **first_tail; struct PeerConnection **second_tail; switch (list) { case ALLOWED: first_list = &pg->peers[first].allowed_peers_head; second_list = &pg->peers[second].allowed_peers_head; first_tail = &pg->peers[first].allowed_peers_tail; second_tail = &pg->peers[second].allowed_peers_tail; break; case CONNECT: first_list = &pg->peers[first].connect_peers_head; second_list = &pg->peers[second].connect_peers_head; first_tail = &pg->peers[first].connect_peers_tail; second_tail = &pg->peers[second].connect_peers_tail; break; case BLACKLIST: first_list = &pg->peers[first].blacklisted_peers_head; second_list = &pg->peers[second].blacklisted_peers_head; first_tail = &pg->peers[first].blacklisted_peers_tail; second_tail = &pg->peers[second].blacklisted_peers_tail; break; case WORKING_SET: first_list = &pg->peers[first].connect_peers_working_set_head; second_list = &pg->peers[second].connect_peers_working_set_head; first_tail = &pg->peers[first].connect_peers_working_set_tail; second_tail = &pg->peers[second].connect_peers_working_set_tail; break; default: GNUNET_break (0); return 0; } add_first = GNUNET_YES; add_second = GNUNET_YES; if (check == GNUNET_YES) { first_iter = *first_list; while (first_iter != NULL) { if (first_iter->index == second) { add_first = GNUNET_NO; break; } first_iter = first_iter->next; } second_iter = *second_list; while (second_iter != NULL) { if (second_iter->index == first) { add_second = GNUNET_NO; break; } second_iter = second_iter->next; } } added = 0; if (add_first) { new_first = GNUNET_malloc (sizeof (struct PeerConnection)); new_first->index = second; GNUNET_CONTAINER_DLL_insert (*first_list, *first_tail, new_first); pg->peers[first].num_connections++; added++; } if (add_second) { new_second = GNUNET_malloc (sizeof (struct PeerConnection)); new_second->index = first; GNUNET_CONTAINER_DLL_insert (*second_list, *second_tail, new_second); pg->peers[second].num_connections++; added++; } return added; } /** * Scale free network construction as described in: * * "Emergence of Scaling in Random Networks." Science 286, 509-512, 1999. * * Start with a network of "one" peer, then progressively add * peers up to the total number. At each step, iterate over * all possible peers and connect new peer based on number of * existing connections of the target peer. * * @param pg the peer group we are dealing with * @param proc the connection processor to use * @param list the peer list to use * * @return the number of connections created */ static unsigned int create_scale_free (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) { unsigned int total_connections; unsigned int outer_count; unsigned int i; unsigned int previous_total_connections; double random; double probability; GNUNET_assert (pg->total > 1); /* Add a connection between the first two nodes */ total_connections = proc (pg, 0, 1, list, GNUNET_YES); for (outer_count = 1; outer_count < pg->total; outer_count++) { previous_total_connections = total_connections; for (i = 0; i < outer_count; i++) { probability = pg->peers[i].num_connections / (double) previous_total_connections; random = ((double) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX)) / ((double) UINT64_MAX); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Considering connecting peer %d to peer %d\n", outer_count, i); if (random < probability) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", outer_count, i); total_connections += proc (pg, outer_count, i, list, GNUNET_YES); } } } return total_connections; } /** * Create a topology given a peer group (set of running peers) * and a connection processor. Creates a small world topology * according to the rewired ring construction. The basic * behavior is that a ring topology is created, but with some * probability instead of connecting a peer to the next * neighbor in the ring a connection will be created to a peer * selected uniformly at random. We use the TESTING * PERCENTAGE option to specify what number of * connections each peer should have. Default is 2, * which makes the ring, any given number is multiplied by * the log of the network size; i.e. a PERCENTAGE of 2 makes * each peer have on average 2logn connections. The additional * connections are made at increasing distance around the ring * from the original peer, or to random peers based on the re- * wiring probability. The TESTING * PROBABILITY option is used as the probability that a given * connection is rewired. * * @param pg the peergroup to create the topology on * @param proc the connection processor to call to actually set * up connections between two peers * @param list the peer list to use * * @return the number of connections that were set up * */ static unsigned int create_small_world_ring (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) { unsigned int i, j; int nodeToConnect; unsigned int natLog; unsigned int randomPeer; double random, logNModifier, probability; unsigned int smallWorldConnections; int connsPerPeer; char *p_string; int max; int min; unsigned int useAnd; int connect_attempts; logNModifier = 0.5; /* FIXME: default value? */ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PERCENTAGE", &p_string)) { if (SSCANF (p_string, "%lf", &logNModifier) != 1) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), p_string, "LOGNMODIFIER", "TESTING"); GNUNET_free (p_string); } probability = 0.5; /* FIXME: default percentage? */ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PROBABILITY", &p_string)) { if (SSCANF (p_string, "%lf", &probability) != 1) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), p_string, "PERCENTAGE", "TESTING"); GNUNET_free (p_string); } natLog = log (pg->total); connsPerPeer = ceil (natLog * logNModifier); if (connsPerPeer % 2 == 1) connsPerPeer += 1; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Target is %d connections per peer.", connsPerPeer); smallWorldConnections = 0; connect_attempts = 0; for (i = 0; i < pg->total; i++) { useAnd = 0; max = i + connsPerPeer / 2; min = i - connsPerPeer / 2; if (max > pg->total - 1) { max = max - pg->total; useAnd = 1; } if (min < 0) { min = pg->total - 1 + min; useAnd = 1; } for (j = 0; j < connsPerPeer / 2; j++) { random = ((double) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX) / ((double) UINT64_MAX)); if (random < probability) { /* Connect to uniformly selected random peer */ randomPeer = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, pg->total); while ((((randomPeer < max) && (randomPeer > min)) && (useAnd == 0)) || (((randomPeer > min) || (randomPeer < max)) && (useAnd == 1))) { randomPeer = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, pg->total); } smallWorldConnections += proc (pg, i, randomPeer, list, GNUNET_YES); } else { nodeToConnect = i + j + 1; if (nodeToConnect > pg->total - 1) { nodeToConnect = nodeToConnect - pg->total; } connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); } } } connect_attempts += smallWorldConnections; return connect_attempts; } /** * Create a topology given a peer group (set of running peers) * and a connection processor. * * @param pg the peergroup to create the topology on * @param proc the connection processor to call to actually set * up connections between two peers * @param list the peer list to use * * @return the number of connections that were set up * */ static unsigned int create_nated_internet (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) { unsigned int outer_count, inner_count; unsigned int cutoff; int connect_attempts; double nat_percentage; char *p_string; nat_percentage = 0.6; /* FIXME: default percentage? */ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PERCENTAGE", &p_string)) { if (SSCANF (p_string, "%lf", &nat_percentage) != 1) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), p_string, "PERCENTAGE", "TESTING"); GNUNET_free (p_string); } cutoff = (unsigned int) (nat_percentage * pg->total); connect_attempts = 0; for (outer_count = 0; outer_count < pg->total - 1; outer_count++) { for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) { if ((outer_count > cutoff) || (inner_count > cutoff)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", outer_count, inner_count); connect_attempts += proc (pg, outer_count, inner_count, list, GNUNET_YES); } } } return connect_attempts; } #if TOPOLOGY_HACK /** * Create a topology given a peer group (set of running peers) * and a connection processor. * * @param pg the peergroup to create the topology on * @param proc the connection processor to call to actually set * up connections between two peers * @param list the peer list to use * * @return the number of connections that were set up * */ static unsigned int create_nated_internet_copy (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) { unsigned int outer_count, inner_count; unsigned int cutoff; int connect_attempts; double nat_percentage; char *p_string; unsigned int count; struct ProgressMeter *conn_meter; nat_percentage = 0.6; /* FIXME: default percentage? */ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PERCENTAGE", &p_string)) { if (SSCANF (p_string, "%lf", &nat_percentage) != 1) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), p_string, "PERCENTAGE", "TESTING"); GNUNET_free (p_string); } cutoff = (unsigned int) (nat_percentage * pg->total); count = 0; for (outer_count = 0; outer_count < pg->total - 1; outer_count++) { for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) { if ((outer_count > cutoff) || (inner_count > cutoff)) { count++; } } } conn_meter = create_meter (count, "NAT COPY", GNUNET_YES); connect_attempts = 0; for (outer_count = 0; outer_count < pg->total - 1; outer_count++) { for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) { if ((outer_count > cutoff) || (inner_count > cutoff)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", outer_count, inner_count); connect_attempts += proc (pg, outer_count, inner_count, list, GNUNET_YES); add_connections (pg, outer_count, inner_count, ALLOWED, GNUNET_NO); update_meter (conn_meter); } } } free_meter (conn_meter); return connect_attempts; } #endif /** * Create a topology given a peer group (set of running peers) * and a connection processor. * * @param pg the peergroup to create the topology on * @param proc the connection processor to call to actually set * up connections between two peers * @param list the peer list to use * * @return the number of connections that were set up * */ static unsigned int create_small_world (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) { unsigned int i, j, k; unsigned int square; unsigned int rows; unsigned int cols; unsigned int toggle = 1; unsigned int nodeToConnect; unsigned int natLog; unsigned int node1Row; unsigned int node1Col; unsigned int node2Row; unsigned int node2Col; unsigned int distance; double probability, random, percentage; unsigned int smallWorldConnections; unsigned int small_world_it; char *p_string; int connect_attempts; square = floor (sqrt (pg->total)); rows = square; cols = square; percentage = 0.5; /* FIXME: default percentage? */ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PERCENTAGE", &p_string)) { if (SSCANF (p_string, "%lf", &percentage) != 1) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), p_string, "PERCENTAGE", "TESTING"); GNUNET_free (p_string); } if (percentage < 0.0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Invalid value `%s' for option `%s' in section `%s': got %f, needed value greater than 0\n"), "PERCENTAGE", "TESTING", percentage); percentage = 0.5; } probability = 0.5; /* FIXME: default percentage? */ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PROBABILITY", &p_string)) { if (SSCANF (p_string, "%lf", &probability) != 1) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), p_string, "PROBABILITY", "TESTING"); GNUNET_free (p_string); } if (square * square != pg->total) { while (rows * cols < pg->total) { if (toggle % 2 == 0) rows++; else cols++; toggle++; } } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting nodes in 2d torus topology: %u rows %u columns\n", rows, cols); connect_attempts = 0; /* Rows and columns are all sorted out, now iterate over all nodes and connect each * to the node to its right and above. Once this is over, we'll have our torus! * Special case for the last node (if the rows and columns are not equal), connect * to the first in the row to maintain topology. */ for (i = 0; i < pg->total; i++) { /* First connect to the node to the right */ if (((i + 1) % cols != 0) && (i + 1 != pg->total)) nodeToConnect = i + 1; else if (i + 1 == pg->total) nodeToConnect = rows * cols - cols; else nodeToConnect = i - cols + 1; connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); if (i < cols) { nodeToConnect = (rows * cols) - cols + i; if (nodeToConnect >= pg->total) nodeToConnect -= cols; } else nodeToConnect = i - cols; if (nodeToConnect < pg->total) connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); } natLog = log (pg->total); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "natural log of %d is %d, will run %d iterations\n", pg->total, natLog, (int) (natLog * percentage)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Total connections added thus far: %u!\n", connect_attempts); smallWorldConnections = 0; small_world_it = (unsigned int) (natLog * percentage); if (small_world_it < 1) small_world_it = 1; GNUNET_assert (small_world_it > 0 && small_world_it < (unsigned int) -1); for (i = 0; i < small_world_it; i++) { for (j = 0; j < pg->total; j++) { /* Determine the row and column of node at position j on the 2d torus */ node1Row = j / cols; node1Col = j - (node1Row * cols); for (k = 0; k < pg->total; k++) { /* Determine the row and column of node at position k on the 2d torus */ node2Row = k / cols; node2Col = k - (node2Row * cols); /* Simple Cartesian distance */ distance = abs (node1Row - node2Row) + abs (node1Col - node2Col); if (distance > 1) { /* Calculate probability as 1 over the square of the distance */ probability = 1.0 / (distance * distance); /* Choose a random value between 0 and 1 */ random = ((double) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX)) / ((double) UINT64_MAX); /* If random < probability, then connect the two nodes */ if (random < probability) smallWorldConnections += proc (pg, j, k, list, GNUNET_YES); } } } } connect_attempts += smallWorldConnections; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Total connections added for small world: %d!\n", smallWorldConnections); return connect_attempts; } /** * Create a topology given a peer group (set of running peers) * and a connection processor. * * @param pg the peergroup to create the topology on * @param proc the connection processor to call to actually set * up connections between two peers * @param list the peer list to use * * @return the number of connections that were set up * */ static unsigned int create_erdos_renyi (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) { double temp_rand; unsigned int outer_count; unsigned int inner_count; int connect_attempts; double probability; char *p_string; probability = 0.5; /* FIXME: default percentage? */ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PROBABILITY", &p_string)) { if (SSCANF (p_string, "%lf", &probability) != 1) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), p_string, "PROBABILITY", "TESTING"); GNUNET_free (p_string); } connect_attempts = 0; for (outer_count = 0; outer_count < pg->total - 1; outer_count++) { for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) { temp_rand = ((double) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX)) / ((double) UINT64_MAX); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "rand is %f probability is %f\n", temp_rand, probability); if (temp_rand < probability) { connect_attempts += proc (pg, outer_count, inner_count, list, GNUNET_YES); } } } return connect_attempts; } /** * Create a topology given a peer group (set of running peers) * and a connection processor. This particular function creates * the connections for a 2d-torus, plus additional "closest" * connections per peer. * * @param pg the peergroup to create the topology on * @param proc the connection processor to call to actually set * up connections between two peers * @param list the peer list to use * * @return the number of connections that were set up * */ static unsigned int create_2d_torus (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) { unsigned int i; unsigned int square; unsigned int rows; unsigned int cols; unsigned int toggle = 1; unsigned int nodeToConnect; int connect_attempts; connect_attempts = 0; square = floor (sqrt (pg->total)); rows = square; cols = square; if (square * square != pg->total) { while (rows * cols < pg->total) { if (toggle % 2 == 0) rows++; else cols++; toggle++; } } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting nodes in 2d torus topology: %u rows %u columns\n", rows, cols); /* Rows and columns are all sorted out, now iterate over all nodes and connect each * to the node to its right and above. Once this is over, we'll have our torus! * Special case for the last node (if the rows and columns are not equal), connect * to the first in the row to maintain topology. */ for (i = 0; i < pg->total; i++) { /* First connect to the node to the right */ if (((i + 1) % cols != 0) && (i + 1 != pg->total)) nodeToConnect = i + 1; else if (i + 1 == pg->total) nodeToConnect = rows * cols - cols; else nodeToConnect = i - cols + 1; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", i, nodeToConnect); connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); /* Second connect to the node immediately above */ if (i < cols) { nodeToConnect = (rows * cols) - cols + i; if (nodeToConnect >= pg->total) nodeToConnect -= cols; } else nodeToConnect = i - cols; if (nodeToConnect < pg->total) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", i, nodeToConnect); connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); } } return connect_attempts; } /** * Create a topology given a peer group (set of running peers) * and a connection processor. * * @param pg the peergroup to create the topology on * @param proc the connection processor to call to actually set * up connections between two peers * @param list the peer list to use * @param check does the connection processor need to check before * performing an action on the list? * * @return the number of connections that were set up * */ static unsigned int create_clique (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list, unsigned int check) { unsigned int outer_count; unsigned int inner_count; int connect_attempts; struct ProgressMeter *conn_meter; connect_attempts = 0; conn_meter = create_meter ((((pg->total * pg->total) + pg->total) / 2) - pg->total, "Create Clique ", GNUNET_NO); for (outer_count = 0; outer_count < pg->total - 1; outer_count++) { for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", outer_count, inner_count); connect_attempts += proc (pg, outer_count, inner_count, list, check); update_meter (conn_meter); } } reset_meter (conn_meter); free_meter (conn_meter); return connect_attempts; } #if !OLD /** * Iterator over hash map entries. * * @param cls closure the peer group * @param key the key stored in the hashmap is the * index of the peer to connect to * @param value value in the hash map, handle to the peer daemon * @return GNUNET_YES if we should continue to * iterate, * GNUNET_NO if not. */ static int unblacklist_iterator (void *cls, const GNUNET_HashCode * key, void *value) { struct UnblacklistContext *un_ctx = cls; uint32_t second_pos; uid_from_hash (key, &second_pos); unblacklist_connections (un_ctx->pg, un_ctx->first_uid, second_pos); return GNUNET_YES; } #endif #if !OLD /** * Create a blacklist topology based on the allowed topology * which disallows any connections not in the allowed topology * at the transport level. * * @param pg the peergroup to create the topology on * @param proc the connection processor to call to allow * up connections between two peers * * @return the number of connections that were set up * */ static unsigned int copy_allowed (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc) { unsigned int count; unsigned int total; struct PeerConnection *iter; #if !OLD struct UnblacklistContext un_ctx; un_ctx.pg = pg; #endif total = 0; for (count = 0; count < pg->total - 1; count++) { #if OLD iter = pg->peers[count].allowed_peers_head; while (iter != NULL) { remove_connections (pg, count, iter->index, BLACKLIST, GNUNET_YES); //unblacklist_connections(pg, count, iter->index); iter = iter->next; } #else un_ctx.first_uid = count; total += GNUNET_CONTAINER_multihashmap_iterate (pg->peers[count].allowed_peers, &unblacklist_iterator, &un_ctx); #endif } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Unblacklisted %u peers\n", total); return total; } #endif /** * Create a topology given a peer group (set of running peers) * and a connection processor. * * @param pg the peergroup to create the topology on * @param proc the connection processor to call to actually set * up connections between two peers * @param list which list should be modified * * @return the number of connections that were set up * */ static unsigned int create_line (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) { unsigned int count; unsigned int connect_attempts; connect_attempts = 0; /* Connect each peer to the next highest numbered peer */ for (count = 0; count < pg->total - 1; count++) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", count, count + 1); connect_attempts += proc (pg, count, count + 1, list, GNUNET_YES); } return connect_attempts; } /** * Create a topology given a peer group (set of running peers) * and a connection processor. * * @param pg the peergroup to create the topology on * @param filename the file to read topology information from * @param proc the connection processor to call to actually set * up connections between two peers * @param list the peer list to use * * @return the number of connections that were set up * */ static unsigned int create_from_file (struct GNUNET_TESTING_PeerGroup *pg, char *filename, GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) { int connect_attempts; unsigned int first_peer_index; unsigned int second_peer_index; struct stat frstat; int count; char *data; const char *buf; unsigned int total_peers; enum States curr_state; connect_attempts = 0; if (GNUNET_OK != GNUNET_DISK_file_test (filename)) GNUNET_DISK_fn_write (filename, NULL, 0, GNUNET_DISK_PERM_USER_READ); if ((0 != STAT (filename, &frstat)) || (frstat.st_size == 0)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not open file `%s' specified for topology!", filename); return connect_attempts; } data = GNUNET_malloc_large (frstat.st_size); GNUNET_assert (data != NULL); if (frstat.st_size != GNUNET_DISK_fn_read (filename, data, frstat.st_size)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not read file %s specified for host list, ending test!", filename); GNUNET_free (data); return connect_attempts; } buf = data; count = 0; first_peer_index = 0; /* First line should contain a single integer, specifying the number of peers */ /* Each subsequent line should contain this format PEER_INDEX:OTHER_PEER_INDEX[,...] */ curr_state = NUM_PEERS; while (count < frstat.st_size - 1) { if ((buf[count] == '\n') || (buf[count] == ' ')) { count++; continue; } switch (curr_state) { case NUM_PEERS: errno = 0; total_peers = strtoul (&buf[count], NULL, 10); if (errno != 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to read number of peers from topology file!\n"); GNUNET_free (data); return connect_attempts; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found %u total peers in topology\n", total_peers); GNUNET_assert (total_peers == pg->total); curr_state = PEER_INDEX; while ((buf[count] != '\n') && (count < frstat.st_size - 1)) count++; count++; break; case PEER_INDEX: errno = 0; first_peer_index = strtoul (&buf[count], NULL, 10); if (errno != 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to read peer index from topology file!\n"); GNUNET_free (data); return connect_attempts; } while ((buf[count] != ':') && (count < frstat.st_size - 1)) count++; count++; curr_state = OTHER_PEER_INDEX; break; case COLON: if (1 == sscanf (&buf[count], ":")) curr_state = OTHER_PEER_INDEX; count++; break; case OTHER_PEER_INDEX: errno = 0; second_peer_index = strtoul (&buf[count], NULL, 10); if (errno != 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to peer index from topology file!\n"); GNUNET_free (data); return connect_attempts; } /* Assume file is written with first peer 1, but array index is 0 */ connect_attempts += proc (pg, first_peer_index - 1, second_peer_index - 1, list, GNUNET_YES); while ((buf[count] != '\n') && (buf[count] != ',') && (count < frstat.st_size - 1)) count++; if (buf[count] == '\n') { curr_state = PEER_INDEX; } else if (buf[count] != ',') { curr_state = OTHER_PEER_INDEX; } count++; break; default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found bad data in topology file while in state %d!\n", curr_state); GNUNET_break (0); GNUNET_free (data); return connect_attempts; } } GNUNET_free (data); return connect_attempts; } /** * Create a topology given a peer group (set of running peers) * and a connection processor. * * @param pg the peergroup to create the topology on * @param proc the connection processor to call to actually set * up connections between two peers * @param list the peer list to use * * @return the number of connections that were set up * */ static unsigned int create_ring (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) { unsigned int count; int connect_attempts; connect_attempts = 0; /* Connect each peer to the next highest numbered peer */ for (count = 0; count < pg->total - 1; count++) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", count, count + 1); connect_attempts += proc (pg, count, count + 1, list, GNUNET_YES); } /* Connect the last peer to the first peer */ connect_attempts += proc (pg, pg->total - 1, 0, list, GNUNET_YES); return connect_attempts; } #if !OLD /** * Iterator for writing friends of a peer to a file. * * @param cls closure, an open writable file handle * @param key the key the daemon was stored under * @param value the GNUNET_TESTING_Daemon that needs to be written. * * @return GNUNET_YES to continue iteration * * TODO: Could replace friend_file_iterator and blacklist_file_iterator * with a single file_iterator that takes a closure which contains * the prefix to write before the peer. Then this could be used * for blacklisting multiple transports and writing the friend * file. I'm sure *someone* will complain loudly about other * things that negate these functions even existing so no point in * "fixing" now. */ static int friend_file_iterator (void *cls, const GNUNET_HashCode * key, void *value) { FILE *temp_friend_handle = cls; struct GNUNET_TESTING_Daemon *peer = value; struct GNUNET_PeerIdentity *temppeer; struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc; temppeer = &peer->id; GNUNET_CRYPTO_hash_to_enc (&temppeer->hashPubKey, &peer_enc); FPRINTF (temp_friend_handle, "%s\n", (char *) &peer_enc); return GNUNET_YES; } struct BlacklistContext { /* * The (open) file handle to write to */ FILE *temp_file_handle; /* * The transport that this peer will be blacklisted on. */ char *transport; }; /** * Iterator for writing blacklist data to appropriate files. * * @param cls closure, an open writable file handle * @param key the key the daemon was stored under * @param value the GNUNET_TESTING_Daemon that needs to be written. * * @return GNUNET_YES to continue iteration */ static int blacklist_file_iterator (void *cls, const GNUNET_HashCode * key, void *value) { struct BlacklistContext *blacklist_ctx = cls; struct GNUNET_TESTING_Daemon *peer = value; struct GNUNET_PeerIdentity *temppeer; struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc; temppeer = &peer->id; GNUNET_CRYPTO_hash_to_enc (&temppeer->hashPubKey, &peer_enc); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Writing entry %s:%s to file\n", blacklist_ctx->transport, (char *) &peer_enc); FPRINTF (blacklist_ctx->temp_file_handle, "%s:%s\n", blacklist_ctx->transport, (char *) &peer_enc); return GNUNET_YES; } #endif /* * Create the friend files based on the PeerConnection's * of each peer in the peer group, and copy the files * to the appropriate place * * @param pg the peer group we are dealing with */ static int create_and_copy_friend_files (struct GNUNET_TESTING_PeerGroup *pg) { FILE *temp_friend_handle; unsigned int pg_iter; char *temp_service_path; struct GNUNET_OS_Process **procarr; char *arg; char *mytemp; #if NOT_STUPID enum GNUNET_OS_ProcessStatusType type; unsigned long return_code; int count; int max_wait = 10; #endif int ret; ret = GNUNET_OK; #if OLD struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc; struct PeerConnection *conn_iter; #endif procarr = GNUNET_malloc (sizeof (struct GNUNET_OS_Process *) * pg->total); for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { mytemp = GNUNET_DISK_mktemp ("friends"); GNUNET_assert (mytemp != NULL); temp_friend_handle = FOPEN (mytemp, "wt"); GNUNET_assert (temp_friend_handle != NULL); #if OLD conn_iter = pg->peers[pg_iter].allowed_peers_head; while (conn_iter != NULL) { GNUNET_CRYPTO_hash_to_enc (&pg->peers[conn_iter->index].daemon-> id.hashPubKey, &peer_enc); FPRINTF (temp_friend_handle, "%s\n", (char *) &peer_enc); conn_iter = conn_iter->next; } #else GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].allowed_peers, &friend_file_iterator, temp_friend_handle); #endif FCLOSE (temp_friend_handle); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (pg->peers[pg_iter].daemon->cfg, "PATHS", "SERVICEHOME", &temp_service_path)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"), "SERVICEHOME", "PATHS"); if (UNLINK (mytemp) != 0) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", mytemp); GNUNET_free (mytemp); break; } if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */ { GNUNET_asprintf (&arg, "%s/friends", temp_service_path); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Copying file with RENAME(%s,%s)\n", mytemp, arg); RENAME (mytemp, arg); procarr[pg_iter] = NULL; GNUNET_free (arg); } else /* Remote, scp the file to the correct place */ { if (NULL != pg->peers[pg_iter].daemon->username) GNUNET_asprintf (&arg, "%s@%s:%s/friends", pg->peers[pg_iter].daemon->username, pg->peers[pg_iter].daemon->hostname, temp_service_path); else GNUNET_asprintf (&arg, "%s:%s/friends", pg->peers[pg_iter].daemon->hostname, temp_service_path); procarr[pg_iter] = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", mytemp, arg, NULL); GNUNET_assert (procarr[pg_iter] != NULL); ret = GNUNET_OS_process_wait (procarr[pg_iter]); /* FIXME: schedule this, throttle! */ GNUNET_OS_process_destroy (procarr[pg_iter]); if (ret != GNUNET_OK) { /* FIXME: free contents of 'procarr' array */ GNUNET_free (procarr); GNUNET_free (temp_service_path); GNUNET_free (mytemp); GNUNET_free (arg); return ret; } procarr[pg_iter] = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Copying file with command scp %s %s\n", mytemp, arg); GNUNET_free (arg); } GNUNET_free (temp_service_path); GNUNET_free (mytemp); } #if NOT_STUPID count = 0; ret = GNUNET_SYSERR; while ((count < max_wait) && (ret != GNUNET_OK)) { ret = GNUNET_OK; for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking copy status of file %d\n", pg_iter); if (procarr[pg_iter] != NULL) /* Check for already completed! */ { if (GNUNET_OS_process_status (procarr[pg_iter], &type, &return_code) != GNUNET_OK) { ret = GNUNET_SYSERR; } else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0)) { ret = GNUNET_SYSERR; } else { GNUNET_OS_process_destroy (procarr[pg_iter]); procarr[pg_iter] = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "File %d copied\n", pg_iter); } } } count++; if (ret == GNUNET_SYSERR) { /* FIXME: why sleep here? -CG */ sleep (1); } } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished copying all friend files!\n"); #endif GNUNET_free (procarr); return ret; } /* * Create the blacklist files based on the PeerConnection's * of each peer in the peer group, and copy the files * to the appropriate place. * * @param pg the peer group we are dealing with * @param transports space delimited list of transports to blacklist */ static int create_and_copy_blacklist_files (struct GNUNET_TESTING_PeerGroup *pg, const char *transports) { FILE *temp_file_handle; unsigned int pg_iter; char *temp_service_path; struct GNUNET_OS_Process **procarr; char *arg; char *mytemp; enum GNUNET_OS_ProcessStatusType type; unsigned long return_code; int count; int ret; int max_wait = 10; int transport_len; unsigned int i; char *pos; char *temp_transports; #if OLD struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc; struct PeerConnection *conn_iter; #else static struct BlacklistContext blacklist_ctx; #endif procarr = GNUNET_malloc (sizeof (struct GNUNET_OS_Process *) * pg->total); for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { mytemp = GNUNET_DISK_mktemp ("blacklist"); GNUNET_assert (mytemp != NULL); temp_file_handle = FOPEN (mytemp, "wt"); GNUNET_assert (temp_file_handle != NULL); temp_transports = GNUNET_strdup (transports); #if !OLD blacklist_ctx.temp_file_handle = temp_file_handle; #endif transport_len = strlen (temp_transports) + 1; pos = NULL; for (i = 0; i < transport_len; i++) { if ((temp_transports[i] == ' ') && (pos == NULL)) continue; /* At start of string (whitespace) */ else if ((temp_transports[i] == ' ') || (temp_transports[i] == '\0')) /* At end of string */ { temp_transports[i] = '\0'; #if OLD conn_iter = pg->peers[pg_iter].blacklisted_peers_head; while (conn_iter != NULL) { GNUNET_CRYPTO_hash_to_enc (&pg->peers[conn_iter->index].daemon-> id.hashPubKey, &peer_enc); FPRINTF (temp_file_handle, "%s:%s\n", pos, (char *) &peer_enc); conn_iter = conn_iter->next; } #else blacklist_ctx.transport = pos; (void) GNUNET_CONTAINER_multihashmap_iterate (pg-> peers [pg_iter].blacklisted_peers, &blacklist_file_iterator, &blacklist_ctx); #endif pos = NULL; } /* At beginning of actual string */ else if (pos == NULL) { pos = &temp_transports[i]; } } GNUNET_free (temp_transports); FCLOSE (temp_file_handle); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (pg->peers[pg_iter].daemon->cfg, "PATHS", "SERVICEHOME", &temp_service_path)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"), "SERVICEHOME", "PATHS"); if (UNLINK (mytemp) != 0) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", mytemp); GNUNET_free (mytemp); break; } if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */ { GNUNET_asprintf (&arg, "%s/blacklist", temp_service_path); RENAME (mytemp, arg); procarr[pg_iter] = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Copying file with RENAME (%s,%s)\n", mytemp, arg); GNUNET_free (arg); } else /* Remote, scp the file to the correct place */ { if (NULL != pg->peers[pg_iter].daemon->username) GNUNET_asprintf (&arg, "%s@%s:%s/blacklist", pg->peers[pg_iter].daemon->username, pg->peers[pg_iter].daemon->hostname, temp_service_path); else GNUNET_asprintf (&arg, "%s:%s/blacklist", pg->peers[pg_iter].daemon->hostname, temp_service_path); procarr[pg_iter] = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", mytemp, arg, NULL); GNUNET_assert (procarr[pg_iter] != NULL); GNUNET_OS_process_wait (procarr[pg_iter]); /* FIXME: add scheduled blacklist file copy that parallelizes file copying! */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Copying file with command scp %s %s\n", mytemp, arg); GNUNET_free (arg); } GNUNET_free (temp_service_path); GNUNET_free (mytemp); } count = 0; ret = GNUNET_SYSERR; while ((count < max_wait) && (ret != GNUNET_OK)) { ret = GNUNET_OK; for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking copy status of file %d\n", pg_iter); if (procarr[pg_iter] != NULL) /* Check for already completed! */ { if (GNUNET_OS_process_status (procarr[pg_iter], &type, &return_code) != GNUNET_OK) { ret = GNUNET_SYSERR; } else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0)) { ret = GNUNET_SYSERR; } else { GNUNET_OS_process_destroy (procarr[pg_iter]); procarr[pg_iter] = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "File %d copied\n", pg_iter); } } } count++; if (ret == GNUNET_SYSERR) { /* FIXME: why sleep here? -CG */ sleep (1); } } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished copying all blacklist files!\n"); GNUNET_free (procarr); return ret; } /* Forward Declaration */ static void schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Choose a random peer's next connection to create, and * call schedule_connect to set up the connect task. * * @param pg the peer group to connect */ static void preschedule_connect (struct GNUNET_TESTING_PeerGroup *pg) { struct ConnectTopologyContext *ct_ctx = &pg->ct_ctx; struct PeerConnection *connection_iter; struct ConnectContext *connect_context; uint32_t random_peer; if (ct_ctx->remaining_connections == 0) return; random_peer = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, pg->total); while (pg->peers[random_peer].connect_peers_head == NULL) random_peer = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, pg->total); connection_iter = pg->peers[random_peer].connect_peers_head; connect_context = GNUNET_malloc (sizeof (struct ConnectContext)); connect_context->first_index = random_peer; connect_context->second_index = connection_iter->index; connect_context->ct_ctx = ct_ctx; connect_context->task = GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context); GNUNET_CONTAINER_DLL_insert (pg->cc_head, pg->cc_tail, connect_context); GNUNET_CONTAINER_DLL_remove (pg->peers[random_peer].connect_peers_head, pg->peers[random_peer].connect_peers_tail, connection_iter); GNUNET_free (connection_iter); ct_ctx->remaining_connections--; } #if USE_SEND_HELLOS /* Forward declaration */ static void schedule_send_hellos (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Close connections and free the hello context. * * @param cls the 'struct SendHelloContext *' * @param tc scheduler context */ static void free_hello_context (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct SendHelloContext *send_hello_context = cls; if (send_hello_context->peer->daemon->server != NULL) { GNUNET_CORE_disconnect (send_hello_context->peer->daemon->server); send_hello_context->peer->daemon->server = NULL; } if (send_hello_context->peer->daemon->th != NULL) { GNUNET_TRANSPORT_disconnect (send_hello_context->peer->daemon->th); send_hello_context->peer->daemon->th = NULL; } if (send_hello_context->core_connect_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (send_hello_context->core_connect_task); send_hello_context->core_connect_task = GNUNET_SCHEDULER_NO_TASK; } send_hello_context->pg->outstanding_connects--; GNUNET_free (send_hello_context); } /** * For peers that haven't yet connected, notify * the caller that they have failed (timeout). * * @param cls the 'struct SendHelloContext *' * @param tc scheduler context */ static void notify_remaining_connections_failed (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct SendHelloContext *send_hello_context = cls; struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg; struct PeerConnection *connection; GNUNET_CORE_disconnect (send_hello_context->peer->daemon->server); send_hello_context->peer->daemon->server = NULL; connection = send_hello_context->peer->connect_peers_head; while (connection != NULL) { if (pg->notify_connection != NULL) { pg->notify_connection (pg->notify_connection_cls, &send_hello_context->peer->daemon->id, &pg->peers[connection->index].daemon->id, 0, /* FIXME */ send_hello_context->peer->daemon->cfg, pg->peers[connection->index].daemon->cfg, send_hello_context->peer->daemon, pg->peers[connection->index].daemon, "Peers failed to connect (timeout)"); } GNUNET_CONTAINER_DLL_remove (send_hello_context->peer->connect_peers_head, send_hello_context->peer->connect_peers_tail, connection); GNUNET_free (connection); connection = connection->next; } GNUNET_SCHEDULER_add_now (&free_hello_context, send_hello_context); #if BAD other_peer = &pg->peers[connection->index]; #endif } /** * For peers that haven't yet connected, send * CORE connect requests. * * @param cls the 'struct SendHelloContext *' * @param tc scheduler context */ static void send_core_connect_requests (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct SendHelloContext *send_hello_context = cls; struct PeerConnection *conn; GNUNET_assert (send_hello_context->peer->daemon->server != NULL); send_hello_context->core_connect_task = GNUNET_SCHEDULER_NO_TASK; send_hello_context->connect_attempts++; if (send_hello_context->connect_attempts < send_hello_context->pg->ct_ctx.connect_attempts) { conn = send_hello_context->peer->connect_peers_head; while (conn != NULL) { GNUNET_TRANSPORT_try_connect (send_hello_context->peer->daemon->th, &send_hello_context->pg->peers[conn-> index].daemon-> id); conn = conn->next; } send_hello_context->core_connect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (send_hello_context->pg-> ct_ctx.connect_timeout, send_hello_context->pg-> ct_ctx.connect_attempts), &send_core_connect_requests, send_hello_context); } else { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Timeout before all connections created, marking rest as failed!\n"); GNUNET_SCHEDULER_add_now (¬ify_remaining_connections_failed, send_hello_context); } } /** * Success, connection is up. Signal client our success. * * @param cls our "struct SendHelloContext" * @param peer identity of the peer that has connected * @param atsi performance information * * FIXME: remove peers from BOTH lists, call notify twice, should * double the speed of connections as long as the list iteration * doesn't take too long! */ static void core_connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi) { struct SendHelloContext *send_hello_context = cls; struct PeerConnection *connection; struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg; #if BAD struct PeerData *other_peer; #endif GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected peer %s to peer %s\n", ctx->d1->shortname, GNUNET_i2s (peer)); if (0 == memcmp (&send_hello_context->peer->daemon->id, peer, sizeof (struct GNUNET_PeerIdentity))) return; connection = send_hello_context->peer->connect_peers_head; #if BAD other_peer = NULL; #endif while ((connection != NULL) && (0 != memcmp (&pg->peers[connection->index].daemon->id, peer, sizeof (struct GNUNET_PeerIdentity)))) { connection = connection->next; } if (connection == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected peer %s to %s, not in list (no problem(?))\n", GNUNET_i2s (peer), send_hello_context->peer->daemon->shortname); } else { #if BAD other_peer = &pg->peers[connection->index]; #endif if (pg->notify_connection != NULL) { pg->notify_connection (pg->notify_connection_cls, &send_hello_context->peer->daemon->id, peer, 0, /* FIXME */ send_hello_context->peer->daemon->cfg, pg->peers[connection->index].daemon->cfg, send_hello_context->peer->daemon, pg->peers[connection->index].daemon, NULL); } GNUNET_CONTAINER_DLL_remove (send_hello_context->peer->connect_peers_head, send_hello_context->peer->connect_peers_tail, connection); GNUNET_free (connection); } #if BAD /* Notify of reverse connection and remove from other peers list of outstanding */ if (other_peer != NULL) { connection = other_peer->connect_peers_head; while ((connection != NULL) && (0 != memcmp (&send_hello_context->peer->daemon->id, &pg->peers[connection->index].daemon->id, sizeof (struct GNUNET_PeerIdentity)))) { connection = connection->next; } if (connection != NULL) { if (pg->notify_connection != NULL) { pg->notify_connection (pg->notify_connection_cls, peer, &send_hello_context->peer->daemon->id, 0, /* FIXME */ pg->peers[connection->index].daemon->cfg, send_hello_context->peer->daemon->cfg, pg->peers[connection->index].daemon, send_hello_context->peer->daemon, NULL); } GNUNET_CONTAINER_DLL_remove (other_peer->connect_peers_head, other_peer->connect_peers_tail, connection); GNUNET_free (connection); } } #endif if (send_hello_context->peer->connect_peers_head == NULL) { GNUNET_SCHEDULER_add_now (&free_hello_context, send_hello_context); } } /** * Notify of a successful connection to the core service. * * @param cls a struct SendHelloContext * * @param server handle to the core service * @param my_identity the peer identity of this peer */ void core_init (void *cls, struct GNUNET_CORE_Handle *server, struct GNUNET_PeerIdentity *my_identity) { struct SendHelloContext *send_hello_context = cls; send_hello_context->core_ready = GNUNET_YES; } /** * Function called once a hello has been sent * to the transport, move on to the next one * or go away forever. * * @param cls the 'struct SendHelloContext *' * @param tc scheduler context */ static void hello_sent_callback (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct SendHelloContext *send_hello_context = cls; //unsigned int pg_iter; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) { GNUNET_free (send_hello_context); return; } send_hello_context->pg->remaining_hellos--; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent HELLO, have %d remaining!\n", send_hello_context->pg->remaining_hellos); if (send_hello_context->peer_pos == NULL) /* All HELLOs (for this peer!) have been transmitted! */ { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All hellos for this peer sent, disconnecting transport!\n"); GNUNET_assert (send_hello_context->peer->daemon->th != NULL); GNUNET_TRANSPORT_disconnect (send_hello_context->peer->daemon->th); send_hello_context->peer->daemon->th = NULL; GNUNET_assert (send_hello_context->peer->daemon->server == NULL); send_hello_context->peer->daemon->server = GNUNET_CORE_connect (send_hello_context->peer->cfg, 1, send_hello_context, &core_init, &core_connect_notify, NULL, NULL, NULL, GNUNET_NO, NULL, GNUNET_NO, no_handlers); send_hello_context->core_connect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (send_hello_context->pg-> ct_ctx.connect_timeout, send_hello_context->pg-> ct_ctx.connect_attempts), &send_core_connect_requests, send_hello_context); } else GNUNET_SCHEDULER_add_now (&schedule_send_hellos, send_hello_context); } /** * Connect to a peer, give it all the HELLO's of those peers * we will later ask it to connect to. * * @param ct_ctx the overall connection context */ static void schedule_send_hellos (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct SendHelloContext *send_hello_context = cls; struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) { GNUNET_free (send_hello_context); return; } GNUNET_assert (send_hello_context->peer_pos != NULL); /* All of the HELLO sends to be scheduled have been scheduled! */ if (((send_hello_context->peer->daemon->th == NULL) && (pg->outstanding_connects > pg->max_outstanding_connections)) || (pg->stop_connects == GNUNET_YES)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Delaying connect, we have too many outstanding connections!\n"); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100), &schedule_send_hellos, send_hello_context); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating connection, outstanding_connections is %d\n", outstanding_connects); if (send_hello_context->peer->daemon->th == NULL) { pg->outstanding_connects++; /* Actual TRANSPORT, CORE connections! */ send_hello_context->peer->daemon->th = GNUNET_TRANSPORT_connect (send_hello_context->peer->cfg, NULL, send_hello_context, NULL, NULL, NULL); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Offering HELLO of peer %s to peer %s\n", send_hello_context->peer->daemon->shortname, pg->peers[send_hello_context->peer_pos->index]. daemon->shortname); GNUNET_TRANSPORT_offer_hello (send_hello_context->peer->daemon->th, (const struct GNUNET_MessageHeader *) pg->peers[send_hello_context->peer_pos-> index].daemon->hello, &hello_sent_callback, send_hello_context); send_hello_context->peer_pos = send_hello_context->peer_pos->next; GNUNET_assert (send_hello_context->peer->daemon->th != NULL); } } #endif /** * Internal notification of a connection, kept so that we can ensure some connections * happen instead of flooding all testing daemons with requests to connect. */ static void internal_connect_notify (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, uint32_t distance, const struct GNUNET_CONFIGURATION_Handle *first_cfg, const struct GNUNET_CONFIGURATION_Handle *second_cfg, struct GNUNET_TESTING_Daemon *first_daemon, struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) { struct ConnectContext *connect_ctx = cls; struct ConnectTopologyContext *ct_ctx = connect_ctx->ct_ctx; struct GNUNET_TESTING_PeerGroup *pg = ct_ctx->pg; struct PeerConnection *connection; GNUNET_assert (NULL != connect_ctx->cc); connect_ctx->cc = NULL; GNUNET_assert (0 < pg->outstanding_connects); pg->outstanding_connects--; GNUNET_CONTAINER_DLL_remove (pg->cc_head, pg->cc_tail, connect_ctx); /* * Check whether the inverse connection has been scheduled yet, * if not, we can remove it from the other peers list and avoid * even trying to connect them again! */ connection = pg->peers[connect_ctx->second_index].connect_peers_head; #if BAD other_peer = NULL; #endif while ((connection != NULL) && (0 != memcmp (first, &pg->peers[connection->index].daemon->id, sizeof (struct GNUNET_PeerIdentity)))) connection = connection->next; if (connection != NULL) /* Can safely remove! */ { GNUNET_assert (0 < ct_ctx->remaining_connections); ct_ctx->remaining_connections--; if (pg->notify_connection != NULL) /* Notify of reverse connection */ pg->notify_connection (pg->notify_connection_cls, second, first, distance, second_cfg, first_cfg, second_daemon, first_daemon, emsg); GNUNET_CONTAINER_DLL_remove (pg-> peers[connect_ctx-> second_index].connect_peers_head, pg->peers[connect_ctx-> second_index].connect_peers_tail, connection); GNUNET_free (connection); } if (ct_ctx->remaining_connections == 0) { if (ct_ctx->notify_connections_done != NULL) { ct_ctx->notify_connections_done (ct_ctx->notify_cls, NULL); ct_ctx->notify_connections_done = NULL; } } else preschedule_connect (pg); if (pg->notify_connection != NULL) pg->notify_connection (pg->notify_connection_cls, first, second, distance, first_cfg, second_cfg, first_daemon, second_daemon, emsg); GNUNET_free (connect_ctx); } /** * Either delay a connection (because there are too many outstanding) * or schedule it for right now. * * @param cls a connection context * @param tc the task runtime context */ static void schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ConnectContext *connect_context = cls; struct GNUNET_TESTING_PeerGroup *pg = connect_context->ct_ctx->pg; connect_context->task = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; if ((pg->outstanding_connects > pg->max_outstanding_connections) || (pg->stop_connects == GNUNET_YES)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Delaying connect, we have too many outstanding connections!\n"); connect_context->task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100), &schedule_connect, connect_context); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating connection, outstanding_connections is %d (max %d)\n", pg->outstanding_connects, pg->max_outstanding_connections); pg->outstanding_connects++; pg->total_connects_scheduled++; GNUNET_assert (NULL == connect_context->cc); connect_context->cc = GNUNET_TESTING_daemons_connect (pg-> peers[connect_context-> first_index].daemon, pg->peers[connect_context-> second_index].daemon, connect_context->ct_ctx->connect_timeout, connect_context->ct_ctx->connect_attempts, #if USE_SEND_HELLOS GNUNET_NO, #else GNUNET_YES, #endif &internal_connect_notify, connect_context); } #if !OLD /** * Iterator for actually scheduling connections to be created * between two peers. * * @param cls closure, a GNUNET_TESTING_Daemon * @param key the key the second Daemon was stored under * @param value the GNUNET_TESTING_Daemon that the first is to connect to * * @return GNUNET_YES to continue iteration */ static int connect_iterator (void *cls, const GNUNET_HashCode * key, void *value) { struct ConnectTopologyContext *ct_ctx = cls; struct PeerData *first = ct_ctx->first; struct GNUNET_TESTING_Daemon *second = value; struct ConnectContext *connect_context; connect_context = GNUNET_malloc (sizeof (struct ConnectContext)); connect_context->first = first->daemon; connect_context->second = second; connect_context->ct_ctx = ct_ctx; connect_context->task = GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context); GNUNET_CONTAINER_DLL_insert (ct_ctx->pg->cc_head, ct_ctx->pg->cc_tail, connect_context); return GNUNET_YES; } #endif #if !OLD /** * Iterator for copying all entries in the allowed hashmap to the * connect hashmap. * * @param cls closure, a GNUNET_TESTING_Daemon * @param key the key the second Daemon was stored under * @param value the GNUNET_TESTING_Daemon that the first is to connect to * * @return GNUNET_YES to continue iteration */ static int copy_topology_iterator (void *cls, const GNUNET_HashCode * key, void *value) { struct PeerData *first = cls; GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (first->connect_peers, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); return GNUNET_YES; } #endif /** * Make the peers to connect the same as those that are allowed to be * connected. * * @param pg the peer group */ static int copy_allowed_topology (struct GNUNET_TESTING_PeerGroup *pg) { unsigned int pg_iter; int ret; int total; #if OLD struct PeerConnection *iter; #endif total = 0; ret = 0; for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { #if OLD iter = pg->peers[pg_iter].allowed_peers_head; while (iter != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating connection between %d and %d\n", pg_iter, iter->index); total += add_connections (pg, pg_iter, iter->index, CONNECT, GNUNET_YES); //total += add_actual_connections(pg, pg_iter, iter->index); iter = iter->next; } #else ret = GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].allowed_peers, ©_topology_iterator, &pg->peers[pg_iter]); #endif if (GNUNET_SYSERR == ret) return GNUNET_SYSERR; total = total + ret; } return total; } /** * Connect the topology as specified by the PeerConnection's * of each peer in the peer group * * @param pg the peer group we are dealing with * @param connect_timeout how long try connecting two peers * @param connect_attempts how many times (max) to attempt * @param notify_callback callback to notify when finished * @param notify_cls closure for notify callback * * @return the number of connections that will be attempted */ static int connect_topology (struct GNUNET_TESTING_PeerGroup *pg, struct GNUNET_TIME_Relative connect_timeout, unsigned int connect_attempts, GNUNET_TESTING_NotifyCompletion notify_callback, void *notify_cls) { unsigned int pg_iter; unsigned int total; #if OLD struct PeerConnection *connection_iter; #endif #if USE_SEND_HELLOS struct SendHelloContext *send_hello_context; #endif total = 0; pg->ct_ctx.notify_connections_done = notify_callback; pg->ct_ctx.notify_cls = notify_cls; pg->ct_ctx.pg = pg; for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { #if OLD connection_iter = pg->peers[pg_iter].connect_peers_head; while (connection_iter != NULL) { connection_iter = connection_iter->next; total++; } #else total += GNUNET_CONTAINER_multihashmap_size (pg->peers[pg_iter].connect_peers); #endif } if (total == 0) return total; pg->ct_ctx.connect_timeout = connect_timeout; pg->ct_ctx.connect_attempts = connect_attempts; pg->ct_ctx.remaining_connections = total; #if USE_SEND_HELLOS /* First give all peers the HELLO's of other peers (connect to first peer's transport service, give HELLO's of other peers, continue...) */ pg->remaining_hellos = total; for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { send_hello_context = GNUNET_malloc (sizeof (struct SendHelloContext)); send_hello_context->peer = &pg->peers[pg_iter]; send_hello_context->peer_pos = pg->peers[pg_iter].connect_peers_head; send_hello_context->pg = pg; GNUNET_SCHEDULER_add_now (&schedule_send_hellos, send_hello_context); } #else for (pg_iter = 0; pg_iter < pg->max_outstanding_connections; pg_iter++) { preschedule_connect (pg); } #endif return total; } /** * Takes a peer group and creates a topology based on the * one specified. Creates a topology means generates friend * files for the peers so they can only connect to those allowed * by the topology. This will only have an effect once peers * are started if the FRIENDS_ONLY option is set in the base * config. Also takes an optional restrict topology which * disallows connections based on particular transports * UNLESS they are specified in the restricted topology. * * @param pg the peer group struct representing the running peers * @param topology which topology to connect the peers in * @param restrict_topology disallow restrict_transports transport * connections to peers NOT in this topology * use GNUNET_TESTING_TOPOLOGY_NONE for no restrictions * @param restrict_transports space delimited list of transports to blacklist * to create restricted topology * * @return the maximum number of connections were all allowed peers * connected to each other */ unsigned int GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg, enum GNUNET_TESTING_Topology topology, enum GNUNET_TESTING_Topology restrict_topology, const char *restrict_transports) { int ret; unsigned int num_connections; int unblacklisted_connections; char *filename; struct PeerConnection *conn_iter; struct PeerConnection *temp_conn; unsigned int off; #if !OLD unsigned int i; for (i = 0; i < pg->total; i++) { pg->peers[i].allowed_peers = GNUNET_CONTAINER_multihashmap_create (100); pg->peers[i].connect_peers = GNUNET_CONTAINER_multihashmap_create (100); pg->peers[i].blacklisted_peers = GNUNET_CONTAINER_multihashmap_create (100); pg->peers[i].pg = pg; } #endif switch (topology) { case GNUNET_TESTING_TOPOLOGY_CLIQUE: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating clique topology\n"); num_connections = create_clique (pg, &add_connections, ALLOWED, GNUNET_NO); break; case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating small world (ring) topology\n"); num_connections = create_small_world_ring (pg, &add_connections, ALLOWED); break; case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating small world (2d-torus) topology\n"); num_connections = create_small_world (pg, &add_connections, ALLOWED); break; case GNUNET_TESTING_TOPOLOGY_RING: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating ring topology\n"); num_connections = create_ring (pg, &add_connections, ALLOWED); break; case GNUNET_TESTING_TOPOLOGY_2D_TORUS: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating 2d torus topology\n"); num_connections = create_2d_torus (pg, &add_connections, ALLOWED); break; case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating Erdos-Renyi topology\n"); num_connections = create_erdos_renyi (pg, &add_connections, ALLOWED); break; case GNUNET_TESTING_TOPOLOGY_INTERNAT: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating InterNAT topology\n"); num_connections = create_nated_internet (pg, &add_connections, ALLOWED); break; case GNUNET_TESTING_TOPOLOGY_SCALE_FREE: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating Scale Free topology\n"); num_connections = create_scale_free (pg, &add_connections, ALLOWED); break; case GNUNET_TESTING_TOPOLOGY_LINE: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating straight line topology\n"); num_connections = create_line (pg, &add_connections, ALLOWED); break; case GNUNET_TESTING_TOPOLOGY_FROM_FILE: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating topology from file!\n"); if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (pg->cfg, "testing", "topology_file", &filename)) num_connections = create_from_file (pg, filename, &add_connections, ALLOWED); else { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Missing configuration option TESTING:TOPOLOGY_FILE for creating topology from file!\n"); num_connections = 0; } break; case GNUNET_TESTING_TOPOLOGY_NONE: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Creating no allowed topology (all peers can connect at core level)\n")); num_connections = pg->total * pg->total; /* Clique is allowed! */ break; default: num_connections = 0; break; } if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING", "F2F")) { ret = create_and_copy_friend_files (pg); if (ret != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed during friend file copying!\n"); return GNUNET_SYSERR; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Friend files created/copied successfully!\n"); } } /* Use the create clique method to initially set all connections as blacklisted. */ if ((restrict_topology != GNUNET_TESTING_TOPOLOGY_NONE) && (restrict_topology != GNUNET_TESTING_TOPOLOGY_FROM_FILE)) create_clique (pg, &add_connections, BLACKLIST, GNUNET_NO); else return num_connections; unblacklisted_connections = 0; /* Un-blacklist connections as per the topology specified */ switch (restrict_topology) { case GNUNET_TESTING_TOPOLOGY_CLIQUE: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklisting all but clique topology\n"); unblacklisted_connections = create_clique (pg, &remove_connections, BLACKLIST, GNUNET_NO); break; case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklisting all but small world (ring) topology\n"); unblacklisted_connections = create_small_world_ring (pg, &remove_connections, BLACKLIST); break; case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklisting all but small world (2d-torus) topology\n"); unblacklisted_connections = create_small_world (pg, &remove_connections, BLACKLIST); break; case GNUNET_TESTING_TOPOLOGY_RING: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklisting all but ring topology\n"); unblacklisted_connections = create_ring (pg, &remove_connections, BLACKLIST); break; case GNUNET_TESTING_TOPOLOGY_2D_TORUS: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklisting all but 2d torus topology\n"); unblacklisted_connections = create_2d_torus (pg, &remove_connections, BLACKLIST); break; case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklisting all but Erdos-Renyi topology\n"); unblacklisted_connections = create_erdos_renyi (pg, &remove_connections, BLACKLIST); break; case GNUNET_TESTING_TOPOLOGY_INTERNAT: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklisting all but InterNAT topology\n"); #if TOPOLOGY_HACK for (off = 0; off < pg->total; off++) { conn_iter = pg->peers[off].allowed_peers_head; while (conn_iter != NULL) { temp_conn = conn_iter->next; GNUNET_free (conn_iter); conn_iter = temp_conn; } pg->peers[off].allowed_peers_head = NULL; pg->peers[off].allowed_peers_tail = NULL; conn_iter = pg->peers[off].connect_peers_head; while (conn_iter != NULL) { temp_conn = conn_iter->next; GNUNET_free (conn_iter); conn_iter = temp_conn; } pg->peers[off].connect_peers_head = NULL; pg->peers[off].connect_peers_tail = NULL; } unblacklisted_connections = create_nated_internet_copy (pg, &remove_connections, BLACKLIST); #else unblacklisted_connections = create_nated_internet (pg, &remove_connections, BLACKLIST); #endif break; case GNUNET_TESTING_TOPOLOGY_SCALE_FREE: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklisting all but Scale Free topology\n"); unblacklisted_connections = create_scale_free (pg, &remove_connections, BLACKLIST); break; case GNUNET_TESTING_TOPOLOGY_LINE: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklisting all but straight line topology\n"); unblacklisted_connections = create_line (pg, &remove_connections, BLACKLIST); default: break; } if ((unblacklisted_connections > 0) && (restrict_transports != NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating blacklist with `%s'\n", restrict_transports); ret = create_and_copy_blacklist_files (pg, restrict_transports); if (ret != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed during blacklist file copying!\n"); return 0; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist files created/copied successfully!\n"); } } return num_connections; } #if !OLD /** * Iterator for choosing random peers to connect. * * @param cls closure, a RandomContext * @param key the key the second Daemon was stored under * @param value the GNUNET_TESTING_Daemon that the first is to connect to * * @return GNUNET_YES to continue iteration */ static int random_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value) { struct RandomContext *random_ctx = cls; double random_number; uint32_t second_pos; GNUNET_HashCode first_hash; random_number = ((double) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX)) / ((double) UINT64_MAX); if (random_number < random_ctx->percentage) { GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (random_ctx-> first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); } /* Now we have considered this particular connection, remove it from the second peer so it's not double counted */ uid_from_hash (key, &second_pos); hash_from_uid (random_ctx->first_uid, &first_hash); GNUNET_assert (random_ctx->pg->total > second_pos); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (random_ctx-> pg->peers [second_pos].connect_peers, &first_hash, random_ctx-> first->daemon)); return GNUNET_YES; } /** * Iterator for adding at least X peers to a peers connection set. * * @param cls closure, MinimumContext * @param key the key the second Daemon was stored under * @param value the GNUNET_TESTING_Daemon that the first is to connect to * * @return GNUNET_YES to continue iteration */ static int minimum_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value) { struct MinimumContext *min_ctx = cls; uint32_t second_pos; GNUNET_HashCode first_hash; unsigned int i; if (GNUNET_CONTAINER_multihashmap_size (min_ctx->first->connect_peers_working_set) < min_ctx->num_to_add) { for (i = 0; i < min_ctx->num_to_add; i++) { if (min_ctx->pg_array[i] == min_ctx->current) { GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (min_ctx-> first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); uid_from_hash (key, &second_pos); hash_from_uid (min_ctx->first_uid, &first_hash); GNUNET_assert (min_ctx->pg->total > second_pos); GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (min_ctx-> pg->peers [second_pos].connect_peers_working_set, &first_hash, min_ctx->first-> daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); /* Now we have added this particular connection, remove it from the second peer's map so it's not double counted */ GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (min_ctx-> pg->peers [second_pos].connect_peers, &first_hash, min_ctx-> first->daemon)); } } min_ctx->current++; return GNUNET_YES; } else return GNUNET_NO; /* We can stop iterating, we have enough peers! */ } /** * Iterator for adding peers to a connection set based on a depth first search. * * @param cls closure, MinimumContext * @param key the key the second daemon was stored under * @param value the GNUNET_TESTING_Daemon that the first is to connect to * * @return GNUNET_YES to continue iteration */ static int dfs_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value) { struct DFSContext *dfs_ctx = cls; GNUNET_HashCode first_hash; if (dfs_ctx->current == dfs_ctx->chosen) { GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (dfs_ctx-> first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); uid_from_hash (key, &dfs_ctx->second_uid); hash_from_uid (dfs_ctx->first_uid, &first_hash); GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (dfs_ctx-> pg->peers[dfs_ctx-> second_uid].connect_peers_working_set, &first_hash, dfs_ctx->first->daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (dfs_ctx-> pg->peers [dfs_ctx->second_uid].connect_peers, &first_hash, dfs_ctx-> first->daemon)); /* Can't remove second from first yet because we are currently iterating, hence the return value in the DFSContext! */ return GNUNET_NO; /* We have found our peer, don't iterate more */ } dfs_ctx->current++; return GNUNET_YES; } #endif /** * From the set of connections possible, choose percentage percent of connections * to actually connect. * * @param pg the peergroup we are dealing with * @param percentage what percent of total connections to make */ void choose_random_connections (struct GNUNET_TESTING_PeerGroup *pg, double percentage) { uint32_t pg_iter; #if OLD struct PeerConnection *conn_iter; double random_number; #else struct RandomContext random_ctx; #endif for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { #if OLD conn_iter = pg->peers[pg_iter].connect_peers_head; while (conn_iter != NULL) { random_number = ((double) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX)) / ((double) UINT64_MAX); if (random_number < percentage) { add_connections (pg, pg_iter, conn_iter->index, WORKING_SET, GNUNET_YES); } conn_iter = conn_iter->next; } #else random_ctx.first_uid = pg_iter; random_ctx.first = &pg->peers[pg_iter]; random_ctx.percentage = percentage; random_ctx.pg = pg; pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create (pg->total); GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].connect_peers, &random_connect_iterator, &random_ctx); /* Now remove the old connections */ GNUNET_CONTAINER_multihashmap_destroy (pg->peers[pg_iter].connect_peers); /* And replace with the random set */ pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set; #endif } for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { conn_iter = pg->peers[pg_iter].connect_peers_head; while (pg->peers[pg_iter].connect_peers_head != NULL) remove_connections (pg, pg_iter, pg->peers[pg_iter].connect_peers_head->index, CONNECT, GNUNET_YES); pg->peers[pg_iter].connect_peers_head = pg->peers[pg_iter].connect_peers_working_set_head; pg->peers[pg_iter].connect_peers_tail = pg->peers[pg_iter].connect_peers_working_set_tail; pg->peers[pg_iter].connect_peers_working_set_head = NULL; pg->peers[pg_iter].connect_peers_working_set_tail = NULL; } } /** * Count the number of connections in a linked list of connections. * * @param conn_list the connection list to get the count of * * @return the number of elements in the list */ static unsigned int count_connections (struct PeerConnection *conn_list) { struct PeerConnection *iter; unsigned int count; count = 0; iter = conn_list; while (iter != NULL) { iter = iter->next; count++; } return count; } static unsigned int count_workingset_connections (struct GNUNET_TESTING_PeerGroup *pg) { unsigned int count; unsigned int pg_iter; #if OLD struct PeerConnection *conn_iter; #endif count = 0; for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { #if OLD conn_iter = pg->peers[pg_iter].connect_peers_working_set_head; while (conn_iter != NULL) { count++; conn_iter = conn_iter->next; } #else count += GNUNET_CONTAINER_multihashmap_size (pg-> peers [pg_iter].connect_peers_working_set); #endif } return count; } static unsigned int count_allowed_connections (struct GNUNET_TESTING_PeerGroup *pg) { unsigned int count; unsigned int pg_iter; #if OLD struct PeerConnection *conn_iter; #endif count = 0; for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { #if OLD conn_iter = pg->peers[pg_iter].allowed_peers_head; while (conn_iter != NULL) { count++; conn_iter = conn_iter->next; } #else count += GNUNET_CONTAINER_multihashmap_size (pg->peers[pg_iter].allowed_peers); #endif } return count; } /** * From the set of connections possible, choose at least num connections per * peer. * * @param pg the peergroup we are dealing with * @param num how many connections at least should each peer have (if possible)? */ static void choose_minimum (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num) { #if !OLD struct MinimumContext minimum_ctx; #else struct PeerConnection *conn_iter; unsigned int temp_list_size; unsigned int i; unsigned int count; uint32_t random; /* Random list entry to connect peer to */ #endif uint32_t pg_iter; #if OLD for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { temp_list_size = count_connections (pg->peers[pg_iter].connect_peers_head); if (temp_list_size == 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Peer %d has 0 connections!?!?\n", pg_iter); break; } for (i = 0; i < num; i++) { random = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, temp_list_size); conn_iter = pg->peers[pg_iter].connect_peers_head; for (count = 0; count < random; count++) conn_iter = conn_iter->next; /* We now have a random connection, connect it! */ GNUNET_assert (conn_iter != NULL); add_connections (pg, pg_iter, conn_iter->index, WORKING_SET, GNUNET_YES); } } #else for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create (num); } for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { minimum_ctx.first_uid = pg_iter; minimum_ctx.pg_array = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_CONTAINER_multihashmap_size (pg->peers[pg_iter].connect_peers)); minimum_ctx.first = &pg->peers[pg_iter]; minimum_ctx.pg = pg; minimum_ctx.num_to_add = num; minimum_ctx.current = 0; GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].connect_peers, &minimum_connect_iterator, &minimum_ctx); } for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { /* Remove the "old" connections */ GNUNET_CONTAINER_multihashmap_destroy (pg->peers[pg_iter].connect_peers); /* And replace with the working set */ pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set; } #endif for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { while (pg->peers[pg_iter].connect_peers_head != NULL) { conn_iter = pg->peers[pg_iter].connect_peers_head; GNUNET_CONTAINER_DLL_remove (pg->peers[pg_iter].connect_peers_head, pg->peers[pg_iter].connect_peers_tail, conn_iter); GNUNET_free (conn_iter); /*remove_connections(pg, pg_iter, pg->peers[pg_iter].connect_peers_head->index, CONNECT, GNUNET_YES); */ } pg->peers[pg_iter].connect_peers_head = pg->peers[pg_iter].connect_peers_working_set_head; pg->peers[pg_iter].connect_peers_tail = pg->peers[pg_iter].connect_peers_working_set_tail; pg->peers[pg_iter].connect_peers_working_set_head = NULL; pg->peers[pg_iter].connect_peers_working_set_tail = NULL; } } #if !OLD struct FindClosestContext { /** * The currently known closest peer. */ struct GNUNET_TESTING_Daemon *closest; /** * The info for the peer we are adding connections for. */ struct PeerData *curr_peer; /** * The distance (bits) between the current * peer and the currently known closest. */ unsigned int closest_dist; /** * The offset of the closest known peer in * the peer group. */ unsigned int closest_num; }; /** * Iterator over hash map entries of the allowed * peer connections. Find the closest, not already * connected peer and return it. * * @param cls closure (struct FindClosestContext) * @param key current key code (hash of offset in pg) * @param value value in the hash map - a GNUNET_TESTING_Daemon * @return GNUNET_YES if we should continue to * iterate, * GNUNET_NO if not. */ static int find_closest_peers (void *cls, const GNUNET_HashCode * key, void *value) { struct FindClosestContext *closest_ctx = cls; struct GNUNET_TESTING_Daemon *daemon = value; if (((closest_ctx->closest == NULL) || (GNUNET_CRYPTO_hash_matching_bits (&daemon->id.hashPubKey, &closest_ctx->curr_peer->daemon->id.hashPubKey) > closest_ctx->closest_dist)) && (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (closest_ctx-> curr_peer->connect_peers, key))) { closest_ctx->closest_dist = GNUNET_CRYPTO_hash_matching_bits (&daemon->id.hashPubKey, &closest_ctx->curr_peer->daemon-> id.hashPubKey); closest_ctx->closest = daemon; uid_from_hash (key, &closest_ctx->closest_num); } return GNUNET_YES; } /** * From the set of connections possible, choose at num connections per * peer based on depth which are closest out of those allowed. Guaranteed * to add num peers to connect to, provided there are that many peers * in the underlay topology to connect to. * * @param pg the peergroup we are dealing with * @param num how many connections at least should each peer have (if possible)? * @param proc processor to actually add the connections * @param list the peer list to use */ void add_closest (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num, GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) { #if OLD #else struct FindClosestContext closest_ctx; #endif uint32_t pg_iter; uint32_t i; for (i = 0; i < num; i++) /* Each time find a closest peer (from those available) */ { for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { closest_ctx.curr_peer = &pg->peers[pg_iter]; closest_ctx.closest = NULL; closest_ctx.closest_dist = 0; closest_ctx.closest_num = 0; GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].allowed_peers, &find_closest_peers, &closest_ctx); if (closest_ctx.closest != NULL) { GNUNET_assert (closest_ctx.closest_num < pg->total); proc (pg, pg_iter, closest_ctx.closest_num, list); } } } } #endif /** * From the set of connections possible, choose at least num connections per * peer based on depth first traversal of peer connections. If DFS leaves * peers unconnected, ensure those peers get connections. * * @param pg the peergroup we are dealing with * @param num how many connections at least should each peer have (if possible)? */ void perform_dfs (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num) { uint32_t pg_iter; uint32_t dfs_count; uint32_t starting_peer; uint32_t least_connections; uint32_t random_connection; #if OLD unsigned int temp_count; struct PeerConnection *peer_iter; #else struct DFSContext dfs_ctx; GNUNET_HashCode second_hash; #endif #if OLD starting_peer = 0; dfs_count = 0; while ((count_workingset_connections (pg) < num * pg->total) && (count_allowed_connections (pg) > 0)) { if (dfs_count % pg->total == 0) /* Restart the DFS at some weakly connected peer */ { least_connections = -1; /* Set to very high number */ for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { temp_count = count_connections (pg-> peers[pg_iter].connect_peers_working_set_head); if (temp_count < least_connections) { starting_peer = pg_iter; least_connections = temp_count; } } } temp_count = count_connections (pg->peers[starting_peer].connect_peers_head); if (temp_count == 0) continue; /* FIXME: infinite loop? */ random_connection = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, temp_count); temp_count = 0; peer_iter = pg->peers[starting_peer].connect_peers_head; while (temp_count < random_connection) { peer_iter = peer_iter->next; temp_count++; } GNUNET_assert (peer_iter != NULL); add_connections (pg, starting_peer, peer_iter->index, WORKING_SET, GNUNET_NO); remove_connections (pg, starting_peer, peer_iter->index, CONNECT, GNUNET_YES); starting_peer = peer_iter->index; dfs_count++; } #else for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create (num); } starting_peer = 0; dfs_count = 0; while ((count_workingset_connections (pg) < num * pg->total) && (count_allowed_connections (pg) > 0)) { if (dfs_count % pg->total == 0) /* Restart the DFS at some weakly connected peer */ { least_connections = -1; /* Set to very high number */ for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { if (GNUNET_CONTAINER_multihashmap_size (pg->peers[pg_iter].connect_peers_working_set) < least_connections) { starting_peer = pg_iter; least_connections = GNUNET_CONTAINER_multihashmap_size (pg-> peers [pg_iter].connect_peers_working_set); } } } if (GNUNET_CONTAINER_multihashmap_size (pg->peers[starting_peer].connect_peers) == 0) /* Ensure there is at least one peer left to connect! */ { dfs_count = 0; continue; } /* Choose a random peer from the chosen peers set of connections to add */ dfs_ctx.chosen = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_CONTAINER_multihashmap_size (pg->peers [starting_peer].connect_peers)); dfs_ctx.first_uid = starting_peer; dfs_ctx.first = &pg->peers[starting_peer]; dfs_ctx.pg = pg; dfs_ctx.current = 0; GNUNET_CONTAINER_multihashmap_iterate (pg-> peers[starting_peer].connect_peers, &dfs_connect_iterator, &dfs_ctx); /* Remove the second from the first, since we will be continuing the search and may encounter the first peer again! */ hash_from_uid (dfs_ctx.second_uid, &second_hash); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (pg->peers [starting_peer].connect_peers, &second_hash, pg-> peers [dfs_ctx.second_uid].daemon)); starting_peer = dfs_ctx.second_uid; } for (pg_iter = 0; pg_iter < pg->total; pg_iter++) { /* Remove the "old" connections */ GNUNET_CONTAINER_multihashmap_destroy (pg->peers[pg_iter].connect_peers); /* And replace with the working set */ pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set; } #endif } /** * Internal callback for topology information for a particular peer. */ static void internal_topology_callback (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct CoreContext *core_ctx = cls; struct TopologyIterateContext *iter_ctx = core_ctx->iter_context; if (peer == NULL) /* Either finished, or something went wrong */ { iter_ctx->completed++; iter_ctx->connected--; /* One core context allocated per iteration, must free! */ GNUNET_free (core_ctx); } else { iter_ctx->topology_cb (iter_ctx->cls, &core_ctx->daemon->id, peer, NULL); } if (iter_ctx->completed == iter_ctx->total) { iter_ctx->topology_cb (iter_ctx->cls, NULL, NULL, NULL); /* Once all are done, free the iteration context */ GNUNET_free (iter_ctx); } } /** * Check running topology iteration tasks, if below max start a new one, otherwise * schedule for some time in the future. */ static void schedule_get_topology (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct CoreContext *core_context = cls; struct TopologyIterateContext *topology_context = (struct TopologyIterateContext *) core_context->iter_context; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; if (topology_context->connected > topology_context->pg->max_outstanding_connections) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Delaying connect, we have too many outstanding connections!\n"); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100), &schedule_get_topology, core_context); } else { topology_context->connected++; if (GNUNET_OK != GNUNET_CORE_iterate_peers (core_context->daemon->cfg, &internal_topology_callback, core_context)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Topology iteration failed.\n"); internal_topology_callback (core_context, NULL, NULL, 0); } } } /** * Iterate over all (running) peers in the peer group, retrieve * all connections that each currently has. */ void GNUNET_TESTING_get_topology (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_NotifyTopology cb, void *cls) { struct TopologyIterateContext *topology_context; struct CoreContext *core_ctx; unsigned int i; unsigned int total_count; /* Allocate a single topology iteration context */ topology_context = GNUNET_malloc (sizeof (struct TopologyIterateContext)); topology_context->topology_cb = cb; topology_context->cls = cls; topology_context->pg = pg; total_count = 0; for (i = 0; i < pg->total; i++) { if (pg->peers[i].daemon->running == GNUNET_YES) { /* Allocate one core context per core we need to connect to */ core_ctx = GNUNET_malloc (sizeof (struct CoreContext)); core_ctx->daemon = pg->peers[i].daemon; /* Set back pointer to topology iteration context */ core_ctx->iter_context = topology_context; GNUNET_SCHEDULER_add_now (&schedule_get_topology, core_ctx); total_count++; } } if (total_count == 0) { cb (cls, NULL, NULL, "Cannot iterate over topology, no running peers!"); GNUNET_free (topology_context); } else topology_context->total = total_count; return; } /** * Callback function to process statistic values. * This handler is here only really to insert a peer * identity (or daemon) so the statistics can be uniquely * tied to a single running peer. * * @param cls closure * @param subsystem name of subsystem that created the statistic * @param name the name of the datum * @param value the current value * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration */ static int internal_stats_callback (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent) { struct StatsCoreContext *core_context = cls; struct StatsIterateContext *stats_context = (struct StatsIterateContext *) core_context->iter_context; return stats_context->proc (stats_context->cls, &core_context->daemon->id, subsystem, name, value, is_persistent); } /** * We don't need the statistics handle anymore, destroy it. * * @param cls Closure (the statistics handle to destroy) * @param tc Task Context */ static void internal_destroy_statistics (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_STATISTICS_Handle *h = cls; GNUNET_STATISTICS_destroy (h, GNUNET_NO); } /** * Internal continuation call for statistics iteration. * * @param cls closure, the CoreContext for this iteration * @param success whether or not the statistics iterations * was canceled or not (we don't care) */ static void internal_stats_cont (void *cls, int success) { struct StatsCoreContext *core_context = cls; struct StatsIterateContext *stats_context = (struct StatsIterateContext *) core_context->iter_context; stats_context->connected--; stats_context->completed++; if (stats_context->completed == stats_context->total) { stats_context->cont (stats_context->cls, GNUNET_YES); GNUNET_free (stats_context); } if (core_context->stats_handle != NULL) /* Cannot destroy handle inside the continuation */ GNUNET_SCHEDULER_add_now (&internal_destroy_statistics, core_context->stats_handle); GNUNET_free (core_context); } /** * Check running topology iteration tasks, if below max start a new one, otherwise * schedule for some time in the future. */ static void schedule_get_statistics (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct StatsCoreContext *core_context = cls; struct StatsIterateContext *stats_context = (struct StatsIterateContext *) core_context->iter_context; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; if (stats_context->connected > stats_context->pg->max_outstanding_connections) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Delaying connect, we have too many outstanding connections!\n"); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100), &schedule_get_statistics, core_context); } else { stats_context->connected++; core_context->stats_handle = GNUNET_STATISTICS_create ("testing", core_context->daemon->cfg); if (core_context->stats_handle == NULL) { internal_stats_cont (core_context, GNUNET_NO); return; } core_context->stats_get_handle = GNUNET_STATISTICS_get (core_context->stats_handle, NULL, NULL, GNUNET_TIME_UNIT_FOREVER_REL, &internal_stats_cont, &internal_stats_callback, core_context); if (core_context->stats_get_handle == NULL) internal_stats_cont (core_context, GNUNET_NO); } } struct DuplicateStats { /** * Next item in the list */ struct DuplicateStats *next; /** * Nasty string, concatenation of relevant information. */ char *unique_string; }; /** * Check whether the combination of port/host/unix domain socket * already exists in the list of peers being checked for statistics. * * @param pg the peergroup in question * @param specific_peer the peer we're concerned with * @param stats_list the list to return to the caller * * @return GNUNET_YES if the statistics instance has been seen already, * GNUNET_NO if not (and we may have added it to the list) */ static int stats_check_existing (struct GNUNET_TESTING_PeerGroup *pg, struct PeerData *specific_peer, struct DuplicateStats **stats_list) { struct DuplicateStats *pos; char *unix_domain_socket; unsigned long long port; char *to_match; if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "testing", "single_statistics_per_host")) return GNUNET_NO; /* Each peer has its own statistics instance, do nothing! */ pos = *stats_list; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (specific_peer->cfg, "statistics", "unixpath", &unix_domain_socket)) return GNUNET_NO; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (specific_peer->cfg, "statistics", "port", &port)) { GNUNET_free (unix_domain_socket); return GNUNET_NO; } if (specific_peer->daemon->hostname != NULL) GNUNET_asprintf (&to_match, "%s%s%llu", specific_peer->daemon->hostname, unix_domain_socket, port); else GNUNET_asprintf (&to_match, "%s%llu", unix_domain_socket, port); while (pos != NULL) { if (0 == strcmp (to_match, pos->unique_string)) { GNUNET_free (unix_domain_socket); GNUNET_free (to_match); return GNUNET_YES; } pos = pos->next; } pos = GNUNET_malloc (sizeof (struct DuplicateStats)); pos->unique_string = to_match; pos->next = *stats_list; *stats_list = pos; GNUNET_free (unix_domain_socket); return GNUNET_NO; } /** * Iterate over all (running) peers in the peer group, retrieve * all statistics from each. * * @param pg the peergroup to iterate statistics of * @param cont continuation to call once all stats have been retrieved * @param proc processing function for each statistic from each peer * @param cls closure to pass to proc * */ void GNUNET_TESTING_get_statistics (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_STATISTICS_Callback cont, GNUNET_TESTING_STATISTICS_Iterator proc, void *cls) { struct StatsIterateContext *stats_context; struct StatsCoreContext *core_ctx; unsigned int i; unsigned int total_count; struct DuplicateStats *stats_list; struct DuplicateStats *pos; stats_list = NULL; /* Allocate a single stats iteration context */ stats_context = GNUNET_malloc (sizeof (struct StatsIterateContext)); stats_context->cont = cont; stats_context->proc = proc; stats_context->cls = cls; stats_context->pg = pg; total_count = 0; for (i = 0; i < pg->total; i++) { if ((pg->peers[i].daemon->running == GNUNET_YES) && (GNUNET_NO == stats_check_existing (pg, &pg->peers[i], &stats_list))) { /* Allocate one core context per core we need to connect to */ core_ctx = GNUNET_malloc (sizeof (struct StatsCoreContext)); core_ctx->daemon = pg->peers[i].daemon; /* Set back pointer to topology iteration context */ core_ctx->iter_context = stats_context; GNUNET_SCHEDULER_add_now (&schedule_get_statistics, core_ctx); total_count++; } } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Retrieving stats from %u total instances.\n", total_count); if (0 != total_count) stats_context->total = total_count; else GNUNET_free (stats_context); if (stats_list != NULL) { pos = stats_list; while (pos != NULL) { GNUNET_free (pos->unique_string); stats_list = pos->next; GNUNET_free (pos); pos = stats_list->next; } } return; } /** * Stop the connection process temporarily. * * @param pg the peer group to stop connecting */ void GNUNET_TESTING_stop_connections (struct GNUNET_TESTING_PeerGroup *pg) { pg->stop_connects = GNUNET_YES; } /** * Resume the connection process temporarily. * * @param pg the peer group to resume connecting */ void GNUNET_TESTING_resume_connections (struct GNUNET_TESTING_PeerGroup *pg) { pg->stop_connects = GNUNET_NO; } /** * There are many ways to connect peers that are supported by this function. * To connect peers in the same topology that was created via the * GNUNET_TESTING_create_topology, the topology variable must be set to * GNUNET_TESTING_TOPOLOGY_NONE. If the topology variable is specified, * a new instance of that topology will be generated and attempted to be * connected. This could result in some connections being impossible, * because some topologies are non-deterministic. * * @param pg the peer group struct representing the running peers * @param topology which topology to connect the peers in * @param options options for connecting the topology * @param option_modifier modifier for options that take a parameter * @param connect_timeout how long to wait before giving up on connecting * two peers * @param connect_attempts how many times to attempt to connect two peers * over the connect_timeout duration * @param notify_callback notification to be called once all connections completed * @param notify_cls closure for notification callback * * @return the number of connections that will be attempted, GNUNET_SYSERR on error */ int GNUNET_TESTING_connect_topology (struct GNUNET_TESTING_PeerGroup *pg, enum GNUNET_TESTING_Topology topology, enum GNUNET_TESTING_TopologyOption options, double option_modifier, struct GNUNET_TIME_Relative connect_timeout, unsigned int connect_attempts, GNUNET_TESTING_NotifyCompletion notify_callback, void *notify_cls) { switch (topology) { case GNUNET_TESTING_TOPOLOGY_CLIQUE: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating clique CONNECT topology\n"); create_clique (pg, &add_connections, CONNECT, GNUNET_NO); break; case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating small world (ring) CONNECT topology\n"); create_small_world_ring (pg, &add_connections, CONNECT); break; case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating small world (2d-torus) CONNECT topology\n"); create_small_world (pg, &add_connections, CONNECT); break; case GNUNET_TESTING_TOPOLOGY_RING: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating ring CONNECT topology\n"); create_ring (pg, &add_connections, CONNECT); break; case GNUNET_TESTING_TOPOLOGY_2D_TORUS: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating 2d torus CONNECT topology\n"); create_2d_torus (pg, &add_connections, CONNECT); break; case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating Erdos-Renyi CONNECT topology\n"); create_erdos_renyi (pg, &add_connections, CONNECT); break; case GNUNET_TESTING_TOPOLOGY_INTERNAT: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating InterNAT CONNECT topology\n"); create_nated_internet (pg, &add_connections, CONNECT); break; case GNUNET_TESTING_TOPOLOGY_SCALE_FREE: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating Scale Free CONNECT topology\n"); create_scale_free (pg, &add_connections, CONNECT); break; case GNUNET_TESTING_TOPOLOGY_LINE: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating straight line CONNECT topology\n"); create_line (pg, &add_connections, CONNECT); break; case GNUNET_TESTING_TOPOLOGY_NONE: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating no CONNECT topology\n"); copy_allowed_topology (pg); break; default: GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Unknown topology specification, can't connect peers!\n")); return GNUNET_SYSERR; } switch (options) { case GNUNET_TESTING_TOPOLOGY_OPTION_RANDOM: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting random subset (%'.2f percent) of possible peers\n", 100 * option_modifier); choose_random_connections (pg, option_modifier); break; case GNUNET_TESTING_TOPOLOGY_OPTION_MINIMUM: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting a minimum of %u peers each (if possible)\n", (unsigned int) option_modifier); choose_minimum (pg, (unsigned int) option_modifier); break; case GNUNET_TESTING_TOPOLOGY_OPTION_DFS: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using DFS to connect a minimum of %u peers each (if possible)\n", (unsigned int) option_modifier); #if FIXME perform_dfs (pg, (int) option_modifier); #endif break; case GNUNET_TESTING_TOPOLOGY_OPTION_ADD_CLOSEST: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finding additional %u closest peers each (if possible)\n", (unsigned int) option_modifier); #if FIXME add_closest (pg, (unsigned int) option_modifier, &add_connections, CONNECT); #endif break; case GNUNET_TESTING_TOPOLOGY_OPTION_NONE: break; case GNUNET_TESTING_TOPOLOGY_OPTION_ALL: break; default: break; } return connect_topology (pg, connect_timeout, connect_attempts, notify_callback, notify_cls); } /** * Lookup and return the number of SSH connections to a host. * * @param hostname the hostname to lookup in the list * @param pg the peergroup that the host belongs to * * @return the number of current ssh connections to the host */ static unsigned int count_outstanding_at_host (const char *hostname, struct GNUNET_TESTING_PeerGroup *pg) { struct OutstandingSSH *pos; pos = pg->ssh_head; while ((pos != NULL) && (strcmp (pos->hostname, hostname) != 0)) pos = pos->next; GNUNET_assert (pos != NULL); return pos->outstanding; } /** * Increment the number of SSH connections to a host by one. * * @param hostname the hostname to lookup in the list * @param pg the peergroup that the host belongs to * */ static void increment_outstanding_at_host (const char *hostname, struct GNUNET_TESTING_PeerGroup *pg) { struct OutstandingSSH *pos; pos = pg->ssh_head; while ((NULL != pos) && (strcmp (pos->hostname, hostname) != 0)) pos = pos->next; GNUNET_assert (NULL != pos); pos->outstanding++; } /** * Decrement the number of SSH connections to a host by one. * * @param hostname the hostname to lookup in the list * @param pg the peergroup that the host belongs to * */ static void decrement_outstanding_at_host (const char *hostname, struct GNUNET_TESTING_PeerGroup *pg) { struct OutstandingSSH *pos; pos = pg->ssh_head; while ((pos != NULL) && (strcmp (pos->hostname, hostname) != 0)) pos = pos->next; GNUNET_assert (pos != NULL); pos->outstanding--; } /** * Callback that is called whenever a hostkey is generated * for a peer. Call the real callback and decrement the * starting counter for the peergroup. * * @param cls closure * @param id identifier for the daemon, NULL on error * @param d handle for the daemon * @param emsg error message (NULL on success) */ static void internal_hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, struct GNUNET_TESTING_Daemon *d, const char *emsg) { struct InternalStartContext *internal_context = cls; internal_context->peer->pg->starting--; internal_context->peer->pg->started++; if (internal_context->hostname != NULL) decrement_outstanding_at_host (internal_context->hostname, internal_context->peer->pg); if (internal_context->hostkey_callback != NULL) internal_context->hostkey_callback (internal_context->hostkey_cls, id, d, emsg); else if (internal_context->peer->pg->started == internal_context->peer->pg->total) { internal_context->peer->pg->started = 0; /* Internal startup may use this counter! */ GNUNET_TESTING_daemons_continue_startup (internal_context->peer->pg); } } /** * Callback that is called whenever a peer has finished starting. * Call the real callback and decrement the starting counter * for the peergroup. * * @param cls closure * @param id identifier for the daemon, NULL on error * @param cfg config * @param d handle for the daemon * @param emsg error message (NULL on success) */ static void internal_startup_callback (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { struct InternalStartContext *internal_context = cls; internal_context->peer->pg->starting--; if (internal_context->hostname != NULL) decrement_outstanding_at_host (internal_context->hostname, internal_context->peer->pg); if (internal_context->start_cb != NULL) internal_context->start_cb (internal_context->start_cb_cls, id, cfg, d, emsg); } /** * Calls GNUNET_TESTING_daemon_continue_startup to set the daemon's state * from HOSTKEY_CREATED to TOPOLOGY_SETUP. Makes sure not to saturate a host * with requests delaying them when needed. * * @param cls closure: internal context of the daemon. * @param tc TaskContext */ static void internal_continue_startup (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct InternalStartContext *internal_context = cls; internal_context->peer->startup_task = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) { return; } if ((internal_context->peer->pg->starting < internal_context->peer->pg->max_concurrent_ssh) || ((internal_context->hostname != NULL) && (count_outstanding_at_host (internal_context->hostname, internal_context->peer->pg) < internal_context->peer->pg->max_concurrent_ssh))) { if (internal_context->hostname != NULL) increment_outstanding_at_host (internal_context->hostname, internal_context->peer->pg); internal_context->peer->pg->starting++; GNUNET_TESTING_daemon_continue_startup (internal_context->peer->daemon); } else { internal_context->peer->startup_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100), &internal_continue_startup, internal_context); } } /** * Callback for informing us about a successful * or unsuccessful churn start call. * * @param cls a ChurnContext * @param id the peer identity of the started peer * @param cfg the handle to the configuration of the peer * @param d handle to the daemon for the peer * @param emsg NULL on success, non-NULL on failure * */ void churn_start_callback (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { struct ChurnRestartContext *startup_ctx = cls; struct ChurnContext *churn_ctx = startup_ctx->churn_ctx; unsigned int total_left; char *error_message; error_message = NULL; if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Churn stop callback failed with error `%s'\n", emsg); churn_ctx->num_failed_start++; } else { churn_ctx->num_to_start--; } total_left = (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) + (churn_ctx->num_to_start - churn_ctx->num_failed_start); if (total_left == 0) { if ((churn_ctx->num_failed_stop > 0) || (churn_ctx->num_failed_start > 0)) GNUNET_asprintf (&error_message, "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!", churn_ctx->num_failed_start, churn_ctx->num_failed_stop); churn_ctx->cb (churn_ctx->cb_cls, error_message); GNUNET_free_non_null (error_message); GNUNET_free (churn_ctx); GNUNET_free (startup_ctx); } } static void schedule_churn_restart (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerRestartContext *peer_restart_ctx = cls; struct ChurnRestartContext *startup_ctx = peer_restart_ctx->churn_restart_ctx; if (startup_ctx->outstanding > startup_ctx->pg->max_concurrent_ssh) GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100), &schedule_churn_restart, peer_restart_ctx); else { if (startup_ctx->churn_ctx->service != NULL) GNUNET_TESTING_daemon_start_stopped_service (peer_restart_ctx->daemon, startup_ctx-> churn_ctx->service, startup_ctx->timeout, &churn_start_callback, startup_ctx); else GNUNET_TESTING_daemon_start_stopped (peer_restart_ctx->daemon, startup_ctx->timeout, &churn_start_callback, startup_ctx); GNUNET_free (peer_restart_ctx); } } /** * Callback for informing us about a successful * or unsuccessful churn start call. * * @param cls a struct ServiceStartContext *startup_ctx * @param id the peer identity of the started peer * @param cfg the handle to the configuration of the peer * @param d handle to the daemon for the peer * @param emsg NULL on success, non-NULL on failure * */ void service_start_callback (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { struct ServiceStartContext *startup_ctx = (struct ServiceStartContext *) cls; if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Service start failed with error `%s'\n", emsg); } startup_ctx->outstanding--; startup_ctx->remaining--; if (startup_ctx->remaining == 0) { startup_ctx->cb (startup_ctx->cb_cls, NULL); GNUNET_free (startup_ctx->service); GNUNET_free (startup_ctx); } } static void schedule_service_start (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerServiceStartContext *peer_ctx = cls; struct ServiceStartContext *startup_ctx = peer_ctx->start_ctx; if (startup_ctx->outstanding > startup_ctx->pg->max_concurrent_ssh) GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100), &schedule_service_start, peer_ctx); else { GNUNET_TESTING_daemon_start_service (peer_ctx->daemon, startup_ctx->service, startup_ctx->timeout, &service_start_callback, startup_ctx); GNUNET_free (peer_ctx); } } static void internal_start (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct InternalStartContext *internal_context = cls; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) { return; } if ((internal_context->peer->pg->starting < internal_context->peer->pg->max_concurrent_ssh) || ((internal_context->hostname != NULL) && (count_outstanding_at_host (internal_context->hostname, internal_context->peer->pg) < internal_context->peer->pg->max_concurrent_ssh))) { if (internal_context->hostname != NULL) increment_outstanding_at_host (internal_context->hostname, internal_context->peer->pg); internal_context->peer->pg->starting++; internal_context->peer->daemon = GNUNET_TESTING_daemon_start (internal_context->peer->cfg, internal_context->timeout, GNUNET_NO, internal_context->hostname, internal_context->username, internal_context->sshport, internal_context->hostkey, &internal_hostkey_callback, internal_context, &internal_startup_callback, internal_context); } else { GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100), &internal_start, internal_context); } } #if USE_START_HELPER struct PeerStartHelperContext { struct GNUNET_TESTING_PeerGroup *pg; struct HostData *host; struct GNUNET_OS_Process *proc; }; static void check_peers_started (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerStartHelperContext *helper = cls; enum GNUNET_OS_ProcessStatusType type; unsigned long code; unsigned int i; GNUNET_TESTING_NotifyDaemonRunning cb; if (GNUNET_NO == GNUNET_OS_process_status (helper->proc, &type, &code)) /* Still running, wait some more! */ { GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &check_peers_started, helper); return; } helper->pg->starting--; if (helper->pg->starting == 0) /* All peers have finished starting! */ { /* Call the peer started callback for each peer, set proper FSM state (?) */ for (i = 0; i < helper->pg->total; i++) { cb = helper->pg->peers[i].daemon->cb; helper->pg->peers[i].daemon->cb = NULL; helper->pg->peers[i].daemon->running = GNUNET_YES; helper->pg->peers[i].daemon->phase = SP_START_DONE; if (NULL != cb) { if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) cb (helper->pg->peers[i].daemon->cb_cls, &helper->pg->peers[i].daemon->id, helper->pg->peers[i].daemon->cfg, helper->pg->peers[i].daemon, "Failed to execute peerStartHelper.pl, or return code bad!"); else cb (helper->pg->peers[i].daemon->cb_cls, &helper->pg->peers[i].daemon->id, helper->pg->peers[i].daemon->cfg, helper->pg->peers[i].daemon, NULL); } } } GNUNET_OS_process_destroy (helper->proc); } static void start_peer_helper (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerStartHelperContext *helper = cls; char *baseservicehome; char *tempdir; char *arg; /* ssh user@host peerStartHelper /path/to/basedirectory */ GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (helper->pg->cfg, "PATHS", "SERVICEHOME", &baseservicehome)); GNUNET_asprintf (&tempdir, "%s/%s/", baseservicehome, helper->host->hostname); if (NULL != helper->host->username) GNUNET_asprintf (&arg, "%s@%s", helper->host->username, helper->host->hostname); else GNUNET_asprintf (&arg, "%s", helper->host->hostname); /* FIXME: Doesn't support ssh_port option! */ helper->proc = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", arg, "peerStartHelper.pl", tempdir, NULL); GNUNET_assert (helper->proc != NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "starting peers with cmd ssh %s %s %s\n", arg, "peerStartHelper.pl", tempdir); GNUNET_SCHEDULER_add_now (&check_peers_started, helper); GNUNET_free (tempdir); GNUNET_free (baseservicehome); GNUNET_free (arg); } #endif /** * Function which continues a peer group starting up * after successfully generating hostkeys for each peer. * * @param pg the peer group to continue starting * */ void GNUNET_TESTING_daemons_continue_startup (struct GNUNET_TESTING_PeerGroup *pg) { unsigned int i; #if USE_START_HELPER if ((pg->num_hosts > 0) && (pg->hostkey_data != NULL)) { struct PeerStartHelperContext *helper; pg->starting = pg->num_hosts; for (i = 0; i < pg->num_hosts; i++) { helper = GNUNET_malloc (sizeof (struct PeerStartHelperContext)); helper->pg = pg; helper->host = &pg->hosts[i]; GNUNET_SCHEDULER_add_now (&start_peer_helper, helper); } } else { pg->starting = 0; for (i = 0; i < pg->total; i++) { pg->peers[i].startup_task = GNUNET_SCHEDULER_add_now (&internal_continue_startup, &pg->peers[i].internal_context); } } #else pg->starting = 0; for (i = 0; i < pg->total; i++) { pg->peers[i].startup_task = GNUNET_SCHEDULER_add_now (&internal_continue_startup, &pg->peers[i].internal_context); } #endif } #if USE_START_HELPER static void call_hostkey_callbacks (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TESTING_PeerGroup *pg = cls; unsigned int i; for (i = 0; i < pg->total; i++) { if (pg->peers[i].internal_context.hostkey_callback != NULL) pg->peers[i].internal_context.hostkey_callback (pg->peers[i]. internal_context.hostkey_cls, &pg->peers[i].daemon->id, pg->peers[i].daemon, NULL); } if (pg->peers[0].internal_context.hostkey_callback == NULL) GNUNET_TESTING_daemons_continue_startup (pg); } #endif /** * Start count gnunet instances with the same set of transports and * applications. The port numbers (any option called "PORT") will be * adjusted to ensure that no two peers running on the same system * have the same port(s) in their respective configurations. * * @param cfg configuration template to use * @param total number of daemons to start * @param max_concurrent_connections for testing, how many peers can * we connect to simultaneously * @param max_concurrent_ssh when starting with ssh, how many ssh * connections will we allow at once (based on remote hosts allowed!) * @param timeout total time allowed for peers to start * @param hostkey_callback function to call on each peers hostkey generation * if NULL, peers will be started by this call, if non-null, * GNUNET_TESTING_daemons_continue_startup must be called after * successful hostkey generation * @param hostkey_cls closure for hostkey callback * @param cb function to call on each daemon that was started * @param cb_cls closure for cb * @param connect_callback function to call each time two hosts are connected * @param connect_callback_cls closure for connect_callback * @param hostnames linked list of host structs to use to start peers on * (NULL to run on localhost only) * * @return NULL on error, otherwise handle to control peer group */ struct GNUNET_TESTING_PeerGroup * GNUNET_TESTING_daemons_start (const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned int total, unsigned int max_concurrent_connections, unsigned int max_concurrent_ssh, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback, void *hostkey_cls, GNUNET_TESTING_NotifyDaemonRunning cb, void *cb_cls, GNUNET_TESTING_NotifyConnection connect_callback, void *connect_callback_cls, const struct GNUNET_TESTING_Host *hostnames) { struct GNUNET_TESTING_PeerGroup *pg; const struct GNUNET_TESTING_Host *hostpos; const char *hostname; const char *username; char *baseservicehome; char *newservicehome; char *tmpdir; char *hostkeys_file; char *arg; char *ssh_port_str; struct GNUNET_DISK_FileHandle *fd; struct GNUNET_CONFIGURATION_Handle *pcfg; unsigned int off; struct OutstandingSSH *ssh_entry; unsigned int hostcnt; unsigned int i; uint16_t minport; uint16_t sshport; uint32_t upnum; uint32_t fdnum; uint64_t fs; uint64_t total_hostkeys; struct GNUNET_OS_Process *proc; username = NULL; if (0 == total) { GNUNET_break (0); return NULL; } upnum = 0; fdnum = 0; pg = GNUNET_malloc (sizeof (struct GNUNET_TESTING_PeerGroup)); pg->cfg = cfg; pg->notify_connection = connect_callback; pg->notify_connection_cls = connect_callback_cls; pg->total = total; pg->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); pg->peers = GNUNET_malloc (total * sizeof (struct PeerData)); pg->max_outstanding_connections = max_concurrent_connections; pg->max_concurrent_ssh = max_concurrent_ssh; if (NULL != hostnames) { off = 0; hostpos = hostnames; while (hostpos != NULL) { hostpos = hostpos->next; off++; } pg->hosts = GNUNET_malloc (off * sizeof (struct HostData)); off = 0; hostpos = hostnames; while (hostpos != NULL) { pg->hosts[off].minport = LOW_PORT; pg->hosts[off].hostname = GNUNET_strdup (hostpos->hostname); if (hostpos->username != NULL) pg->hosts[off].username = GNUNET_strdup (hostpos->username); pg->hosts[off].sshport = hostpos->port; hostpos = hostpos->next; off++; } if (off == 0) { pg->hosts = NULL; } hostcnt = off; minport = 0; pg->num_hosts = off; } else { hostcnt = 0; minport = LOW_PORT; } /* Create the servicehome directory for each remote peer */ GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", "SERVICEHOME", &baseservicehome)); for (i = 0; i < pg->num_hosts; i++) { ssh_entry = GNUNET_malloc (sizeof (struct OutstandingSSH)); ssh_entry->hostname = pg->hosts[i].hostname; /* Don't free! */ GNUNET_CONTAINER_DLL_insert (pg->ssh_head, pg->ssh_tail, ssh_entry); GNUNET_asprintf (&tmpdir, "%s/%s", baseservicehome, pg->hosts[i].hostname); if (NULL != pg->hosts[i].username) GNUNET_asprintf (&arg, "%s@%s", pg->hosts[i].username, pg->hosts[i].hostname); else GNUNET_asprintf (&arg, "%s", pg->hosts[i].hostname); if (pg->hosts[i].sshport != 0) { GNUNET_asprintf (&ssh_port_str, "%d", pg->hosts[i].sshport); proc = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", "-P", ssh_port_str, "-q", arg, "mkdir -p", tmpdir, NULL); } else proc = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", arg, "mkdir -p", tmpdir, NULL); GNUNET_assert (proc != NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating remote dir with command ssh %s %s %s\n", arg, " mkdir -p ", tmpdir); GNUNET_free (tmpdir); GNUNET_free (arg); GNUNET_OS_process_wait (proc); GNUNET_OS_process_destroy (proc); } GNUNET_free (baseservicehome); baseservicehome = NULL; if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "TESTING", "HOSTKEYSFILE", &hostkeys_file)) { if (GNUNET_YES != GNUNET_DISK_file_test (hostkeys_file)) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Could not read hostkeys file!\n")); else { /* Check hostkey file size, read entire thing into memory */ fd = GNUNET_DISK_file_open (hostkeys_file, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); if (NULL == fd) { GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", hostkeys_file); GNUNET_free (hostkeys_file); for (i = 0; i < pg->num_hosts; i++) { GNUNET_free (pg->hosts[i].hostname); GNUNET_free_non_null (pg->hosts[i].username); } GNUNET_free (pg->peers); GNUNET_free (pg->hosts); GNUNET_free (pg); return NULL; } if (GNUNET_OK != GNUNET_DISK_file_size (hostkeys_file, &fs, GNUNET_YES, GNUNET_YES)) fs = 0; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found file size %llu for hostkeys\n", fs); if (0 != (fs % HOSTKEYFILESIZE)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "File size %llu seems incorrect for hostkeys...\n", fs); } else { total_hostkeys = fs / HOSTKEYFILESIZE; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Will read %llu hostkeys from file\n", total_hostkeys); pg->hostkey_data = GNUNET_malloc_large (fs); GNUNET_assert (fs == GNUNET_DISK_file_read (fd, pg->hostkey_data, fs)); } GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); } GNUNET_free (hostkeys_file); } for (off = 0; off < total; off++) { if (hostcnt > 0) { hostname = pg->hosts[off % hostcnt].hostname; username = pg->hosts[off % hostcnt].username; sshport = pg->hosts[off % hostcnt].sshport; pcfg = GNUNET_TESTING_create_cfg (cfg, off, &pg->hosts[off % hostcnt].minport, &upnum, hostname, &fdnum); } else { hostname = NULL; username = NULL; sshport = 0; pcfg = GNUNET_TESTING_create_cfg (cfg, off, &minport, &upnum, hostname, &fdnum); } if (NULL == pcfg) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not create configuration for peer number %u on `%s'!\n"), off, hostname == NULL ? "localhost" : hostname); continue; } if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (pcfg, "PATHS", "SERVICEHOME", &baseservicehome)) { if (hostname != NULL) GNUNET_asprintf (&newservicehome, "%s/%s/%d/", baseservicehome, hostname, off); else GNUNET_asprintf (&newservicehome, "%s/%d/", baseservicehome, off); GNUNET_free (baseservicehome); baseservicehome = NULL; } else { tmpdir = getenv ("TMPDIR"); tmpdir = tmpdir ? tmpdir : "/tmp"; if (hostname != NULL) GNUNET_asprintf (&newservicehome, "%s/%s/%s/%d/", tmpdir, hostname, "gnunet-testing-test-test", off); else GNUNET_asprintf (&newservicehome, "%s/%s/%d/", tmpdir, "gnunet-testing-test-test", off); } GNUNET_CONFIGURATION_set_value_string (pcfg, "PATHS", "SERVICEHOME", newservicehome); GNUNET_free (newservicehome); pg->peers[off].cfg = pcfg; pg->peers[off].pg = pg; pg->peers[off].internal_context.peer = &pg->peers[off]; pg->peers[off].internal_context.timeout = timeout; pg->peers[off].internal_context.hostname = hostname; pg->peers[off].internal_context.username = username; pg->peers[off].internal_context.sshport = sshport; if (pg->hostkey_data != NULL) pg->peers[off].internal_context.hostkey = &pg->hostkey_data[off * HOSTKEYFILESIZE]; pg->peers[off].internal_context.hostkey_callback = hostkey_callback; pg->peers[off].internal_context.hostkey_cls = hostkey_cls; pg->peers[off].internal_context.start_cb = cb; pg->peers[off].internal_context.start_cb_cls = cb_cls; #if !USE_START_HELPER GNUNET_SCHEDULER_add_now (&internal_start, &pg->peers[off].internal_context); #else if ((pg->hostkey_data != NULL) && (hostcnt > 0)) { pg->peers[off].daemon = GNUNET_TESTING_daemon_start (pcfg, timeout, GNUNET_YES, hostname, username, sshport, pg->peers[off].internal_context.hostkey, &internal_hostkey_callback, &pg->peers[off].internal_context, &internal_startup_callback, &pg->peers[off].internal_context); /** * At this point, given that we had a hostkeyfile, * we can call the hostkey callback! * But first, we should copy (rsync) all of the configs * and hostkeys to the remote peers. Then let topology * creation happen, then call the peer start helper processes, * then set pg->whatever_phase for each peer and let them * enter the fsm to get the HELLO's for peers and start connecting. */ } else { GNUNET_SCHEDULER_add_now (&internal_start, &pg->peers[off].internal_context); } #endif } #if USE_START_HELPER /* Now the peergroup has been set up, hostkeys and configs written to files. */ if ((pg->hostkey_data != NULL) && (hostcnt > 0)) { for (off = 0; off < hostcnt; off++) { if (hostcnt > 0) { hostname = pg->hosts[off % hostcnt].hostname; username = pg->hosts[off % hostcnt].username; sshport = pg->hosts[off % hostcnt].sshport; } else { hostname = NULL; username = NULL; sshport = 0; } if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", "SERVICEHOME", &baseservicehome)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "baseservice home is %s\n", baseservicehome); if (hostname != NULL) GNUNET_asprintf (&newservicehome, "%s/%s/", baseservicehome, hostname); else GNUNET_asprintf (&newservicehome, "%s/", baseservicehome); GNUNET_free (baseservicehome); baseservicehome = NULL; } else { tmpdir = getenv ("TMPDIR"); tmpdir = tmpdir ? tmpdir : "/tmp"; if (hostname != NULL) GNUNET_asprintf (&newservicehome, "%s/%s/%s/", tmpdir, hostname, "gnunet-testing-test-test"); else GNUNET_asprintf (&newservicehome, "%s/%s/", tmpdir, "gnunet-testing-test-test", off); } if (NULL != username) GNUNET_asprintf (&arg, "%s@%s:%s", username, pg->hosts[off].hostname, newservicehome); else GNUNET_asprintf (&arg, "%s:%s", pg->hosts[off].hostname, newservicehome); /* FIXME: Doesn't support ssh_port option! */ proc = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "rsync", "rsync", "-r", newservicehome, arg, NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "copying directory with command rsync -r %s %s\n", newservicehome, arg); GNUNET_free (newservicehome); GNUNET_free (arg); if (NULL == proc) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not start `%s' process to copy configuration directory.\n"), "scp"); GNUNET_assert (0); } GNUNET_OS_process_wait (proc); GNUNET_OS_process_destroy (proc); } /* Now all the configuration files and hostkeys are copied to the remote host. Call the hostkey callback for each peer! */ GNUNET_SCHEDULER_add_now (&call_hostkey_callbacks, pg); } #endif return pg; } /* * Get a daemon by number, so callers don't have to do nasty * offsetting operation. */ struct GNUNET_TESTING_Daemon * GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg, unsigned int position) { if (position < pg->total) return pg->peers[position].daemon; return NULL; } /* * Get a daemon by peer identity, so callers can * retrieve the daemon without knowing it's offset. * * @param pg the peer group to retrieve the daemon from * @param peer_id the peer identity of the daemon to retrieve * * @return the daemon on success, or NULL if no such peer identity is found */ struct GNUNET_TESTING_Daemon * GNUNET_TESTING_daemon_get_by_id (struct GNUNET_TESTING_PeerGroup *pg, const struct GNUNET_PeerIdentity *peer_id) { unsigned int i; for (i = 0; i < pg->total; i++) { if (0 == memcmp (&pg->peers[i].daemon->id, peer_id, sizeof (struct GNUNET_PeerIdentity))) return pg->peers[i].daemon; } return NULL; } /** * Prototype of a function that will be called when a * particular operation was completed the testing library. * * @param cls closure (a struct RestartContext) * @param id id of the peer that was restarted * @param cfg handle to the configuration of the peer * @param d handle to the daemon that was restarted * @param emsg NULL on success */ static void restart_callback (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { struct RestartContext *restart_context = cls; if (emsg == NULL) { restart_context->peers_restarted++; } else { restart_context->peers_restart_failed++; } if (restart_context->peers_restarted == restart_context->peer_group->total) { restart_context->callback (restart_context->callback_cls, NULL); GNUNET_free (restart_context); } else if (restart_context->peers_restart_failed + restart_context->peers_restarted == restart_context->peer_group->total) { restart_context->callback (restart_context->callback_cls, "Failed to restart peers!"); GNUNET_free (restart_context); } } /** * Callback for informing us about a successful * or unsuccessful churn stop call. * * @param cls a ChurnContext * @param emsg NULL on success, non-NULL on failure * */ static void churn_stop_callback (void *cls, const char *emsg) { struct ShutdownContext *shutdown_ctx = cls; struct ChurnContext *churn_ctx = shutdown_ctx->cb_cls; unsigned int total_left; char *error_message; error_message = NULL; shutdown_ctx->outstanding--; if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Churn stop callback failed with error `%s'\n", emsg); churn_ctx->num_failed_stop++; } else { churn_ctx->num_to_stop--; } total_left = (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) + (churn_ctx->num_to_start - churn_ctx->num_failed_start); if (total_left == 0) { if ((churn_ctx->num_failed_stop > 0) || (churn_ctx->num_failed_start > 0)) { GNUNET_asprintf (&error_message, "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!", churn_ctx->num_failed_start, churn_ctx->num_failed_stop); } churn_ctx->cb (churn_ctx->cb_cls, error_message); GNUNET_free_non_null (error_message); GNUNET_free (churn_ctx); GNUNET_free (shutdown_ctx); } } /** * Count the number of running peers. * * @param pg handle for the peer group * * @return the number of currently running peers in the peer group */ unsigned int GNUNET_TESTING_daemons_running (struct GNUNET_TESTING_PeerGroup *pg) { unsigned int i; unsigned int running = 0; for (i = 0; i < pg->total; i++) { if (pg->peers[i].daemon->running == GNUNET_YES) { GNUNET_assert (running != -1); running++; } } return running; } /** * Task to rate limit the number of outstanding peer shutdown * requests. This is necessary for making sure we don't do * too many ssh connections at once, but is generally nicer * to any system as well (graduated task starts, as opposed * to calling gnunet-arm N times all at once). */ static void schedule_churn_shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerShutdownContext *peer_shutdown_ctx = cls; struct ShutdownContext *shutdown_ctx; struct ChurnContext *churn_ctx; GNUNET_assert (peer_shutdown_ctx != NULL); shutdown_ctx = peer_shutdown_ctx->shutdown_ctx; GNUNET_assert (shutdown_ctx != NULL); churn_ctx = (struct ChurnContext *) shutdown_ctx->cb_cls; if (shutdown_ctx->outstanding > churn_ctx->pg->max_concurrent_ssh) GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100), &schedule_churn_shutdown_task, peer_shutdown_ctx); else { shutdown_ctx->outstanding++; if (churn_ctx->service != NULL) GNUNET_TESTING_daemon_stop_service (peer_shutdown_ctx->daemon, churn_ctx->service, shutdown_ctx->timeout, shutdown_ctx->cb, shutdown_ctx); else GNUNET_TESTING_daemon_stop (peer_shutdown_ctx->daemon, shutdown_ctx->timeout, shutdown_ctx->cb, shutdown_ctx, GNUNET_NO, GNUNET_YES); GNUNET_free (peer_shutdown_ctx); } } /** * Simulate churn by stopping some peers (and possibly * re-starting others if churn is called multiple times). This * function can only be used to create leave-join churn (peers "never" * leave for good). First "voff" random peers that are currently * online will be taken offline; then "von" random peers that are then * offline will be put back online. No notifications will be * generated for any of these operations except for the callback upon * completion. * * @param pg handle for the peer group * @param service the service to churn off/on, NULL to churn peer * @param voff number of peers that should go offline * @param von number of peers that should come back online; * must be zero on first call (since "testbed_start" * always starts all of the peers) * @param timeout how long to wait for operations to finish before * giving up * @param cb function to call at the end * @param cb_cls closure for cb */ void GNUNET_TESTING_daemons_churn (struct GNUNET_TESTING_PeerGroup *pg, char *service, unsigned int voff, unsigned int von, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_NotifyCompletion cb, void *cb_cls) { struct ChurnContext *churn_ctx; struct ShutdownContext *shutdown_ctx; struct PeerShutdownContext *peer_shutdown_ctx; struct PeerRestartContext *peer_restart_ctx; struct ChurnRestartContext *churn_startup_ctx; unsigned int running; unsigned int stopped; unsigned int total_running; unsigned int total_stopped; unsigned int i; unsigned int *running_arr; unsigned int *stopped_arr; unsigned int *running_permute; unsigned int *stopped_permute; char *pos; shutdown_ctx = NULL; peer_shutdown_ctx = NULL; peer_restart_ctx = NULL; churn_startup_ctx = NULL; running = 0; stopped = 0; if ((von == 0) && (voff == 0)) /* No peers at all? */ { cb (cb_cls, NULL); return; } for (i = 0; i < pg->total; i++) { if (service == NULL) { if (pg->peers[i].daemon->running == GNUNET_YES) { GNUNET_assert (running != -1); running++; } else { GNUNET_assert (stopped != -1); stopped++; } } else { /* FIXME: make churned services a list! */ pos = pg->peers[i].daemon->churned_services; /* FIXME: while (pos != NULL) */ if (pos != NULL) { #if FIXME if (0 == strcasecmp (pos, service)) { break; } #endif GNUNET_assert (stopped != -1); stopped++; /* FIXME: pos = pos->next; */ } if (pos == NULL) { GNUNET_assert (running != -1); running++; } } } if (voff > running) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Trying to stop more peers (%d) than are currently running (%d)!\n", voff, running); cb (cb_cls, "Trying to stop more peers than are currently running!"); return; } if (von > stopped) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Trying to start more peers (%d) than are currently stopped (%d)!\n", von, stopped); cb (cb_cls, "Trying to start more peers than are currently stopped!"); return; } churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext)); if (service != NULL) churn_ctx->service = GNUNET_strdup (service); running_arr = NULL; if (running > 0) running_arr = GNUNET_malloc (running * sizeof (unsigned int)); stopped_arr = NULL; if (stopped > 0) stopped_arr = GNUNET_malloc (stopped * sizeof (unsigned int)); running_permute = NULL; stopped_permute = NULL; if (running > 0) running_permute = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, running); if (stopped > 0) stopped_permute = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, stopped); total_running = running; total_stopped = stopped; running = 0; stopped = 0; churn_ctx->num_to_start = von; churn_ctx->num_to_stop = voff; churn_ctx->cb = cb; churn_ctx->cb_cls = cb_cls; churn_ctx->pg = pg; for (i = 0; i < pg->total; i++) { if (service == NULL) { if (pg->peers[i].daemon->running == GNUNET_YES) { GNUNET_assert ((running_arr != NULL) && (total_running > running)); running_arr[running] = i; running++; } else { GNUNET_assert ((stopped_arr != NULL) && (total_stopped > stopped)); stopped_arr[stopped] = i; stopped++; } } else { /* FIXME: make churned services a list! */ pos = pg->peers[i].daemon->churned_services; /* FIXME: while (pos != NULL) */ if (pos != NULL) { GNUNET_assert ((stopped_arr != NULL) && (total_stopped > stopped)); stopped_arr[stopped] = i; stopped++; /* FIXME: pos = pos->next; */ } if (pos == NULL) { GNUNET_assert ((running_arr != NULL) && (total_running > running)); running_arr[running] = i; running++; } } } GNUNET_assert (running >= voff); if (voff > 0) { shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext)); shutdown_ctx->cb = &churn_stop_callback; shutdown_ctx->cb_cls = churn_ctx; shutdown_ctx->total_peers = voff; shutdown_ctx->timeout = timeout; } for (i = 0; i < voff; i++) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peer %d!\n", running_arr[running_permute[i]]); GNUNET_assert (running_arr != NULL); peer_shutdown_ctx = GNUNET_malloc (sizeof (struct PeerShutdownContext)); peer_shutdown_ctx->daemon = pg->peers[running_arr[running_permute[i]]].daemon; peer_shutdown_ctx->shutdown_ctx = shutdown_ctx; GNUNET_SCHEDULER_add_now (&schedule_churn_shutdown_task, peer_shutdown_ctx); } GNUNET_assert (stopped >= von); if (von > 0) { churn_startup_ctx = GNUNET_malloc (sizeof (struct ChurnRestartContext)); churn_startup_ctx->churn_ctx = churn_ctx; churn_startup_ctx->timeout = timeout; churn_startup_ctx->pg = pg; } for (i = 0; i < von; i++) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting up peer %d!\n", stopped_arr[stopped_permute[i]]); GNUNET_assert (stopped_arr != NULL); peer_restart_ctx = GNUNET_malloc (sizeof (struct PeerRestartContext)); peer_restart_ctx->churn_restart_ctx = churn_startup_ctx; peer_restart_ctx->daemon = pg->peers[stopped_arr[stopped_permute[i]]].daemon; GNUNET_SCHEDULER_add_now (&schedule_churn_restart, peer_restart_ctx); } GNUNET_free_non_null (running_arr); GNUNET_free_non_null (stopped_arr); GNUNET_free_non_null (running_permute); GNUNET_free_non_null (stopped_permute); } /* * Start a given service for each of the peers in the peer group. * * @param pg handle for the peer group * @param service the service to start * @param timeout how long to wait for operations to finish before * giving up * @param cb function to call once finished * @param cb_cls closure for cb * */ void GNUNET_TESTING_daemons_start_service (struct GNUNET_TESTING_PeerGroup *pg, char *service, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_NotifyCompletion cb, void *cb_cls) { struct ServiceStartContext *start_ctx; struct PeerServiceStartContext *peer_start_ctx; unsigned int i; GNUNET_assert (service != NULL); start_ctx = GNUNET_malloc (sizeof (struct ServiceStartContext)); start_ctx->pg = pg; start_ctx->remaining = pg->total; start_ctx->cb = cb; start_ctx->cb_cls = cb_cls; start_ctx->service = GNUNET_strdup (service); start_ctx->timeout = timeout; for (i = 0; i < pg->total; i++) { peer_start_ctx = GNUNET_malloc (sizeof (struct PeerServiceStartContext)); peer_start_ctx->start_ctx = start_ctx; peer_start_ctx->daemon = pg->peers[i].daemon; GNUNET_SCHEDULER_add_now (&schedule_service_start, peer_start_ctx); } } /** * Restart all peers in the given group. * * @param pg the handle to the peer group * @param callback function to call on completion (or failure) * @param callback_cls closure for the callback function */ void GNUNET_TESTING_daemons_restart (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_NotifyCompletion callback, void *callback_cls) { struct RestartContext *restart_context; unsigned int off; if (pg->total > 0) { restart_context = GNUNET_malloc (sizeof (struct RestartContext)); restart_context->peer_group = pg; restart_context->peers_restarted = 0; restart_context->callback = callback; restart_context->callback_cls = callback_cls; for (off = 0; off < pg->total; off++) { GNUNET_TESTING_daemon_restart (pg->peers[off].daemon, &restart_callback, restart_context); } } } /** * Start or stop an individual peer from the given group. * * @param pg handle to the peer group * @param offset which peer to start or stop * @param desired_status GNUNET_YES to have it running, GNUNET_NO to stop it * @param timeout how long to wait for shutdown * @param cb function to call at the end * @param cb_cls closure for cb */ void GNUNET_TESTING_daemons_vary (struct GNUNET_TESTING_PeerGroup *pg, unsigned int offset, int desired_status, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_NotifyCompletion cb, void *cb_cls) { struct ShutdownContext *shutdown_ctx; struct ChurnRestartContext *startup_ctx; struct ChurnContext *churn_ctx; if (GNUNET_NO == desired_status) { if (NULL != pg->peers[offset].daemon) { shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext)); churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext)); churn_ctx->num_to_start = 0; churn_ctx->num_to_stop = 1; churn_ctx->cb = cb; churn_ctx->cb_cls = cb_cls; shutdown_ctx->cb_cls = churn_ctx; GNUNET_TESTING_daemon_stop (pg->peers[offset].daemon, timeout, &churn_stop_callback, shutdown_ctx, GNUNET_NO, GNUNET_YES); } } else if (GNUNET_YES == desired_status) { if (NULL == pg->peers[offset].daemon) { startup_ctx = GNUNET_malloc (sizeof (struct ChurnRestartContext)); churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext)); churn_ctx->num_to_start = 1; churn_ctx->num_to_stop = 0; churn_ctx->cb = cb; churn_ctx->cb_cls = cb_cls; startup_ctx->churn_ctx = churn_ctx; GNUNET_TESTING_daemon_start_stopped (pg->peers[offset].daemon, timeout, &churn_start_callback, startup_ctx); } } else GNUNET_break (0); } /** * Callback for shutting down peers in a peer group. * * @param cls closure (struct ShutdownContext) * @param emsg NULL on success */ static void internal_shutdown_callback (void *cls, const char *emsg) { struct PeerShutdownContext *peer_shutdown_ctx = cls; struct ShutdownContext *shutdown_ctx = peer_shutdown_ctx->shutdown_ctx; unsigned int off; int i; struct OutstandingSSH *ssh_pos; shutdown_ctx->outstanding--; if (peer_shutdown_ctx->daemon->hostname != NULL) decrement_outstanding_at_host (peer_shutdown_ctx->daemon->hostname, shutdown_ctx->pg); if (emsg == NULL) { shutdown_ctx->peers_down++; } else { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "internal_shutdown_callback", "Failed to stop a peer: %s\n", emsg); shutdown_ctx->peers_failed++; } if ((shutdown_ctx->cb != NULL) && (shutdown_ctx->peers_down + shutdown_ctx->peers_failed == shutdown_ctx->total_peers)) { if (shutdown_ctx->peers_failed > 0) shutdown_ctx->cb (shutdown_ctx->cb_cls, "Not all peers successfully shut down!"); else shutdown_ctx->cb (shutdown_ctx->cb_cls, NULL); for (i = 0; i < shutdown_ctx->pg->total; i++) { if (shutdown_ctx->pg->peers[i].startup_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (shutdown_ctx->pg->peers[i].startup_task); } GNUNET_free (shutdown_ctx->pg->peers); GNUNET_free_non_null (shutdown_ctx->pg->hostkey_data); for (off = 0; off < shutdown_ctx->pg->num_hosts; off++) { GNUNET_free (shutdown_ctx->pg->hosts[off].hostname); GNUNET_free_non_null (shutdown_ctx->pg->hosts[off].username); } GNUNET_free_non_null (shutdown_ctx->pg->hosts); while (NULL != (ssh_pos = shutdown_ctx->pg->ssh_head)) { GNUNET_CONTAINER_DLL_remove (shutdown_ctx->pg->ssh_head, shutdown_ctx->pg->ssh_tail, ssh_pos); GNUNET_free (ssh_pos); } GNUNET_free (shutdown_ctx->pg); GNUNET_free (shutdown_ctx); } GNUNET_free (peer_shutdown_ctx); } /** * Task to rate limit the number of outstanding peer shutdown * requests. This is necessary for making sure we don't do * too many ssh connections at once, but is generally nicer * to any system as well (graduated task starts, as opposed * to calling gnunet-arm N times all at once). */ static void schedule_shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerShutdownContext *peer_shutdown_ctx = cls; struct ShutdownContext *shutdown_ctx; struct GNUNET_TESTING_Daemon *d; GNUNET_assert (peer_shutdown_ctx != NULL); d = peer_shutdown_ctx->daemon; shutdown_ctx = peer_shutdown_ctx->shutdown_ctx; GNUNET_assert (shutdown_ctx != NULL); if ((shutdown_ctx->outstanding < shutdown_ctx->pg->max_concurrent_ssh) || ((d->hostname != NULL) && (count_outstanding_at_host (d->hostname, shutdown_ctx->pg) < shutdown_ctx->pg->max_concurrent_ssh))) { if (d->hostname != NULL) increment_outstanding_at_host (d->hostname, shutdown_ctx->pg); shutdown_ctx->outstanding++; GNUNET_TESTING_daemon_stop (d, shutdown_ctx->timeout, &internal_shutdown_callback, peer_shutdown_ctx, shutdown_ctx->delete_files, GNUNET_NO); } else GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100), &schedule_shutdown_task, peer_shutdown_ctx); } /** * Read a testing hosts file based on a configuration. * Returns a DLL of hosts (caller must free!) on success * or NULL on failure. * * @param cfg a configuration with a testing section * * @return DLL of hosts on success, NULL on failure */ struct GNUNET_TESTING_Host * GNUNET_TESTING_hosts_load (const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_TESTING_Host *hosts; struct GNUNET_TESTING_Host *temphost; char *data; char *buf; char *hostfile; struct stat frstat; int count; int ret; /* Check for a hostfile containing user@host:port triples */ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "hostfile", &hostfile)) return NULL; hosts = NULL; temphost = NULL; data = NULL; if (hostfile != NULL) { if (GNUNET_OK != GNUNET_DISK_file_test (hostfile)) GNUNET_DISK_fn_write (hostfile, NULL, 0, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if ((0 != STAT (hostfile, &frstat)) || (frstat.st_size == 0)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not open file specified for host list, ending test!"); GNUNET_free (hostfile); return NULL; } data = GNUNET_malloc_large (frstat.st_size); GNUNET_assert (data != NULL); if (frstat.st_size != GNUNET_DISK_fn_read (hostfile, data, frstat.st_size)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not read file %s specified for host list, ending test!", hostfile); GNUNET_free (hostfile); GNUNET_free (data); return NULL; } GNUNET_free_non_null (hostfile); buf = data; count = 0; while (count < frstat.st_size - 1) { count++; if (((data[count] == '\n')) && (buf != &data[count])) { data[count] = '\0'; temphost = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Host)); ret = SSCANF (buf, "%a[a-zA-Z0-9_]@%a[a-zA-Z0-9.]:%hd", &temphost->username, &temphost->hostname, &temphost->port); if (3 == ret) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully read host %s, port %d and user %s from file\n", temphost->hostname, temphost->port, temphost->username); } else { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Error reading line `%s' in hostfile\n", buf); GNUNET_free (temphost); buf = &data[count + 1]; continue; } temphost->next = hosts; hosts = temphost; buf = &data[count + 1]; } else if ((data[count] == '\n') || (data[count] == '\0')) buf = &data[count + 1]; } } GNUNET_free_non_null (data); return hosts; } /** * Shutdown all peers started in the given group. * * @param pg handle to the peer group * @param timeout how long to wait for shutdown * @param cb callback to notify upon success or failure * @param cb_cls closure for cb */ void GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_NotifyCompletion cb, void *cb_cls) { unsigned int off; struct ShutdownContext *shutdown_ctx; struct PeerShutdownContext *peer_shutdown_ctx; #if OLD struct PeerConnection *conn_iter; struct PeerConnection *temp_conn; #endif struct ConnectContext *cc; GNUNET_assert (pg->total > 0); while (NULL != (cc = pg->cc_head)) { GNUNET_CONTAINER_DLL_remove (pg->cc_head, pg->cc_tail, cc); if (GNUNET_SCHEDULER_NO_TASK != cc->task) GNUNET_SCHEDULER_cancel (cc->task); if (NULL != cc->cc) GNUNET_TESTING_daemons_connect_cancel (cc->cc); GNUNET_free (cc); } shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext)); shutdown_ctx->delete_files = GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING", "DELETE_FILES"); shutdown_ctx->cb = cb; shutdown_ctx->cb_cls = cb_cls; shutdown_ctx->total_peers = pg->total; shutdown_ctx->timeout = timeout; shutdown_ctx->pg = pg; for (off = 0; off < pg->total; off++) { GNUNET_assert (NULL != pg->peers[off].daemon); peer_shutdown_ctx = GNUNET_malloc (sizeof (struct PeerShutdownContext)); peer_shutdown_ctx->daemon = pg->peers[off].daemon; peer_shutdown_ctx->shutdown_ctx = shutdown_ctx; GNUNET_SCHEDULER_add_now (&schedule_shutdown_task, peer_shutdown_ctx); if (NULL != pg->peers[off].cfg) { GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg); pg->peers[off].cfg = NULL; } #if OLD // FIXME Do DLL remove for all pg->peers[off].LIST conn_iter = pg->peers[off].allowed_peers_head; while (conn_iter != NULL) { temp_conn = conn_iter->next; GNUNET_free (conn_iter); conn_iter = temp_conn; } pg->peers[off].allowed_peers_head = NULL; conn_iter = pg->peers[off].connect_peers_head; while (conn_iter != NULL) { temp_conn = conn_iter->next; GNUNET_free (conn_iter); conn_iter = temp_conn; } pg->peers[off].connect_peers_head = NULL; conn_iter = pg->peers[off].blacklisted_peers_head; while (conn_iter != NULL) { temp_conn = conn_iter->next; GNUNET_free (conn_iter); conn_iter = temp_conn; } pg->peers[off].blacklisted_peers_head = NULL; conn_iter = pg->peers[off].connect_peers_working_set_head; while (conn_iter != NULL) { temp_conn = conn_iter->next; GNUNET_free (conn_iter); conn_iter = temp_conn; } pg->peers[off].connect_peers_working_set_head = NULL; #else if (pg->peers[off].allowed_peers != NULL) GNUNET_CONTAINER_multihashmap_destroy (pg->peers[off].allowed_peers); if (pg->peers[off].connect_peers != NULL) GNUNET_CONTAINER_multihashmap_destroy (pg->peers[off].connect_peers); if (pg->peers[off].blacklisted_peers != NULL) GNUNET_CONTAINER_multihashmap_destroy (pg->peers[off].blacklisted_peers); #endif } } /* end of testing_group.c */ gnunet-0.9.3/src/testing/test_testing_connect.c0000644000175000017500000001240411760502551016604 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testing/test_testing_connect.c * @brief testcase for functions to connect two peers in testing.c */ #include "platform.h" #include "gnunet_testing_lib.h" #define VERBOSE GNUNET_NO /** * How long until we give up on connecting the peers? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) #define CONNECT_ATTEMPTS 3 static int ok; static struct GNUNET_TESTING_Daemon *d1; static struct GNUNET_TESTING_Daemon *d2; static struct GNUNET_CONFIGURATION_Handle *c1; static struct GNUNET_CONFIGURATION_Handle *c2; static struct GNUNET_TESTING_ConnectContext *cc; static void end2_cb (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Ending with error: %s\n", emsg); ok = 1; } else { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Both daemons terminated, will now exit.\n"); #endif ok = 0; } } static void end1_cb (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Stopping daemon 1 gave: %s\n", emsg); ok = 1; } else { ok = 0; } GNUNET_TESTING_daemon_stop (d2, TIMEOUT, &end2_cb, NULL, GNUNET_YES, GNUNET_NO); d2 = NULL; } static void finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_TESTING_daemon_stop (d1, TIMEOUT, &end1_cb, NULL, GNUNET_YES, GNUNET_NO); d1 = NULL; } static void my_connect_complete (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, unsigned int distance, const struct GNUNET_CONFIGURATION_Handle *first_cfg, const struct GNUNET_CONFIGURATION_Handle *second_cfg, struct GNUNET_TESTING_Daemon *first_daemon, struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) { cc = NULL; GNUNET_SCHEDULER_add_now (&finish_testing, NULL); } static void my_cb2 (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { GNUNET_assert (id != NULL); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon `%s' started.\n", GNUNET_i2s (id)); #endif cc = GNUNET_TESTING_daemons_connect (d1, d2, TIMEOUT, CONNECT_ATTEMPTS, GNUNET_YES, &my_connect_complete, NULL); } static void my_cb1 (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { GNUNET_assert (id != NULL); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon `%s' started.\n", GNUNET_i2s (id)); #endif d2 = GNUNET_TESTING_daemon_start (c2, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, NULL, NULL, &my_cb2, NULL); GNUNET_assert (d2 != NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { ok = 1; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemon.\n"); #endif c1 = GNUNET_CONFIGURATION_create (); GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (c1, "test_testing_connect_peer1.conf")); c2 = GNUNET_CONFIGURATION_create (); GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (c2, "test_testing_connect_peer2.conf")); d1 = GNUNET_TESTING_daemon_start (c1, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, NULL, NULL, &my_cb1, NULL); GNUNET_assert (d1 != NULL); } static int check () { char *const argv[] = { "test-testing", "-c", "test_testing_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-testing-connect", "nohelp", options, &run, &ok); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-testing-connect", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); return ret; } /* end of test_testing_connect.c */ gnunet-0.9.3/src/testing/test_testing_group.c0000644000175000017500000001071611760502551016313 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testing/test_testing_group.c * @brief testcase for functions to connect peers in testing.c */ #include "platform.h" #include "gnunet_testing_lib.h" #define VERBOSE GNUNET_NO #define NUM_PEERS 4 /** * How long until we give up on connecting the peers? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) static int ok; static int peers_left; static int failed_peers; static struct GNUNET_TESTING_PeerGroup *pg; /** * Check whether peers successfully shut down. */ void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); #endif if (ok == 0) ok = 666; } else { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); #endif } } static void my_cb (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { if (id == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start callback called with error (too long starting peers), aborting test!\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n"); failed_peers++; if (failed_peers == peers_left) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Too many peers failed, ending test!\n"); ok = 1; GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); } return; } peers_left--; if (peers_left == 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers started successfully, ending test!\n"); GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); ok = 0; } else if (failed_peers == peers_left) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Too many peers failed, ending test!\n"); ok = 1; GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { ok = 1; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); #endif peers_left = NUM_PEERS; pg = GNUNET_TESTING_daemons_start (cfg, peers_left, /* Total number of peers */ peers_left, /* Number of outstanding connections */ peers_left, /* Number of parallel ssh connections, or peers being started at once */ TIMEOUT, NULL, NULL, &my_cb, NULL, NULL, NULL, NULL); GNUNET_assert (pg != NULL); } static int check () { char *const argv[] = { "test-testing", "-c", "test_testing_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-testing-group", "nohelp", options, &run, &ok); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-testing-group", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); /** * Still need to remove the base testing directory here, * because group starts will create subdirectories under this * main dir. However, we no longer need to sleep, as the * shutdown sequence won't return until everything is cleaned * up. */ GNUNET_DISK_directory_remove ("/tmp/test-gnunet-testing"); return ret; } /* end of test_testing_group.c */ gnunet-0.9.3/src/testing/test_testing_data_topology_clique_dfs.conf0000644000175000017500000000041511615731530022720 00000000000000@INLINE@ test_testing_defaults.conf [PATHS] DEFAULTCONFIG = test_testing_data_topology_clique.conf [TESTING] NUM_PEERS = 7 TOPOLOGY = CLIQUE CONNECT_TOPOLOGY_OPTION = CONNECT_DFS CONNECT_TOPOLOGY_OPTION_MODIFIER = 2.0 [arm] DEFAULTSERVICES = peerinfo transport core gnunet-0.9.3/src/testing/test_testing_data_topology_churn.conf0000644000175000017500000000025611615731523021726 00000000000000@INLINE@ test_testing_defaults.conf [PATHS] DEFAULTCONFIG = test_testing_data_topology_churn.conf [TESTING] NUM_PEERS = 12 [arm] DEFAULTSERVICES = peerinfo transport core gnunet-0.9.3/src/testing/test_testing.c0000644000175000017500000000577211760502551015105 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testing/test_testing.c * @brief testcase for testing.c */ #include "platform.h" #include "gnunet_testing_lib.h" #define VERBOSE GNUNET_YES #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) static int ok; static void end_cb (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Ending with error: %s\n", emsg); ok = 1; } else { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon terminated, will now exit.\n"); #endif ok = 0; } } void do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TESTING_Daemon *d = cls; GNUNET_TESTING_daemon_stop (d, TIMEOUT, &end_cb, NULL, GNUNET_YES, GNUNET_NO); } static void my_cb (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { GNUNET_assert (id != NULL); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon `%s' started, will now stop it.\n", GNUNET_i2s (id)); #endif GNUNET_SCHEDULER_add_now (&do_shutdown, d); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_TESTING_Daemon *d; ok = 1; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemon.\n"); #endif d = GNUNET_TESTING_daemon_start (cfg, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, NULL, NULL, &my_cb, NULL); GNUNET_assert (d != NULL); } static int check () { char *const argv[] = { "test-testing", "-c", "test_testing_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-testing", "nohelp", options, &run, &ok); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-testing", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); return ret; } /* end of test_testing.c */ gnunet-0.9.3/src/testing/test_testing_reconnect.c0000644000175000017500000001446711760502551017146 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testing/test_testing_reconnect.c * @brief testcase for functions to connect two peers in testing.c */ #include "platform.h" #include "gnunet_testing_lib.h" #define VERBOSE GNUNET_YES /** * How long until we give up on connecting the peers? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) #define CONNECT_ATTEMPTS 3 static int ok; static struct GNUNET_TESTING_Daemon *d1; static struct GNUNET_TESTING_Daemon *d2; static struct GNUNET_CONFIGURATION_Handle *c1; static struct GNUNET_CONFIGURATION_Handle *c2; static struct GNUNET_TESTING_ConnectContext *cc; /** * How many start-connect-stop iterations should we do? */ #define NUM_PHASES 2 static int phase; /** * Run the next phase of starting daemons, connecting them and * stopping them again. */ static void run_phase (void); static void end2_cb (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Ending with error: %s\n", emsg); ok = 1; } else { if (phase < NUM_PHASES) { FPRINTF (stderr, "%s", "."); run_phase (); return; } FPRINTF (stderr, "%s", ".\n"); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Both daemons terminated, will now exit.\n"); #endif ok = 0; } } static void end1_cb (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Stopping daemon 1 gave: %s\n", emsg); ok = 1; } else { ok = 0; } if (d2 != NULL) { GNUNET_TESTING_daemon_stop (d2, TIMEOUT, &end2_cb, NULL, (phase == NUM_PHASES) ? GNUNET_YES : GNUNET_NO, GNUNET_NO); d2 = NULL; } } static void finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_TESTING_daemon_stop (d1, TIMEOUT, &end1_cb, NULL, (phase == NUM_PHASES) ? GNUNET_YES : GNUNET_NO, GNUNET_NO); d1 = NULL; } static void my_connect_complete (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, unsigned int distance, const struct GNUNET_CONFIGURATION_Handle *first_cfg, const struct GNUNET_CONFIGURATION_Handle *second_cfg, struct GNUNET_TESTING_Daemon *first_daemon, struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) { cc = NULL; #if VERBOSE FPRINTF (stderr, "Peer %s ", GNUNET_i2s (first)); FPRINTF (stderr, "connected to %s\n", GNUNET_i2s (second)); #endif GNUNET_SCHEDULER_add_now (&finish_testing, NULL); } static void my_cb2 (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Starting daemon 2 gave: %s\n", emsg); GNUNET_assert (0); return; } GNUNET_assert (id != NULL); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon `%s' started.\n", GNUNET_i2s (id)); #endif cc = GNUNET_TESTING_daemons_connect (d1, d2, TIMEOUT, CONNECT_ATTEMPTS, GNUNET_YES, &my_connect_complete, NULL); } static void my_cb1 (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Starting daemon 1 gave: %s\n", emsg); GNUNET_assert (0); return; } GNUNET_assert (id != NULL); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon `%s' started.\n", GNUNET_i2s (id)); #endif d2 = GNUNET_TESTING_daemon_start (c2, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, NULL, NULL, &my_cb2, NULL); GNUNET_assert (d2 != NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { ok = 1; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemon.\n"); #endif c1 = GNUNET_CONFIGURATION_create (); GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (c1, "test_testing_connect_peer1.conf")); c2 = GNUNET_CONFIGURATION_create (); GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (c2, "test_testing_connect_peer2.conf")); run_phase (); } static void run_phase () { phase++; d1 = GNUNET_TESTING_daemon_start (c1, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, NULL, NULL, &my_cb1, NULL); GNUNET_assert (d1 != NULL); } static int check () { char *const argv[] = { "test-testing-reconnect", "-c", "test_testing_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-testing-reconnect", "nohelp", options, &run, &ok); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-testing-reconnect", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); return ret; } /* end of test_testing_reconnect.c */ gnunet-0.9.3/src/testing/test_testing_group_remote.c0000644000175000017500000001633511760502551017671 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testing/test_testing_group_remote.c * @brief testcase for testing remote and local starting and connecting * of hosts from the testing library. The test_testing_data_remote.conf * file should be modified if this testcase is intended to be used. */ #include "platform.h" #include "gnunet_testing_lib.h" #define VERBOSE GNUNET_YES /** * How long until we give up on connecting the peers? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) #define DEFAULT_NUM_PEERS 8; static int ok; static int peers_left; static int peers_failed; static struct GNUNET_TESTING_PeerGroup *pg; static unsigned long long num_peers; /** * Check whether peers successfully shut down. */ void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed (error %s)!\n", emsg); #endif if (ok == 0) ok = 666; } else { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); #endif } } static void my_cb (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { if (emsg != NULL) { peers_failed++; } peers_left--; if (peers_left == 0) { GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); ok = 0; } else if (peers_failed == peers_left) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Too many peers failed, ending test!\n"); GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_TESTING_Host *hosts; struct GNUNET_TESTING_Host *hostpos; struct GNUNET_TESTING_Host *temphost; char *hostfile; struct stat frstat; char *buf; char *data; int count; int ret; ok = 1; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); #endif if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", &num_peers)) num_peers = DEFAULT_NUM_PEERS; GNUNET_assert (num_peers > 0 && num_peers < (unsigned long long) -1); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "hostfile", &hostfile)) hostfile = NULL; hosts = NULL; data = NULL; if (hostfile != NULL) { if (GNUNET_OK != GNUNET_DISK_file_test (hostfile)) GNUNET_DISK_fn_write (hostfile, NULL, 0, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if ((0 != STAT (hostfile, &frstat)) || (frstat.st_size == 0)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not open file specified for host list, ending test!"); ok = 1119; GNUNET_free (hostfile); return; } data = GNUNET_malloc_large (frstat.st_size); GNUNET_assert (data != NULL); if (frstat.st_size != GNUNET_DISK_fn_read (hostfile, data, frstat.st_size)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not read file %s specified for host list, ending test!", hostfile); GNUNET_free (hostfile); GNUNET_free (data); return; } GNUNET_free_non_null (hostfile); buf = data; count = 0; while (count < frstat.st_size) { count++; if (count >= frstat.st_size) break; /* if (((data[count] == '\n') || (data[count] == '\0')) && (buf != &data[count])) */ if (((data[count] == '\n')) && (buf != &data[count])) { data[count] = '\0'; temphost = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Host)); ret = SSCANF (buf, "%a[a-zA-Z0-9]@%a[a-zA-Z0-9.]:%hd", &temphost->username, &temphost->hostname, &temphost->port); if (3 == ret) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Successfully read host %s, port %d and user %s from file\n", temphost->hostname, temphost->port, temphost->username); } else { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Error reading line `%s' in hostfile\n", buf); GNUNET_free (temphost); buf = &data[count + 1]; continue; } /* temphost->hostname = buf; */ temphost->next = hosts; hosts = temphost; buf = &data[count + 1]; } else if ((data[count] == '\n') || (data[count] == '\0')) buf = &data[count + 1]; } } peers_left = num_peers; pg = GNUNET_TESTING_daemons_start (cfg, peers_left, /* Total number of peers */ peers_left, /* Number of outstanding connections */ peers_left, /* Number of parallel ssh connections, or peers being started at once */ TIMEOUT, NULL, NULL, &my_cb, NULL, NULL, NULL, hosts); hostpos = hosts; while (hostpos != NULL) { temphost = hostpos->next; GNUNET_free (hostpos->hostname); GNUNET_free (hostpos->username); GNUNET_free (hostpos); hostpos = temphost; } GNUNET_free_non_null (data); GNUNET_assert (pg != NULL); } static int check () { char *const argv[] = { "test-testing", "-c", "test_testing_data_remote.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-testing-group", "nohelp", options, &run, &ok); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-testing-group", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); /** * Still need to remove the base testing directory here, * because group starts will create subdirectories under this * main dir. However, we no longer need to sleep, as the * shutdown sequence won't return until everything is cleaned * up. */ GNUNET_DISK_directory_remove ("/tmp/test-gnunet-testing"); return ret; } /* end of test_testing_group.c */ gnunet-0.9.3/src/testing/test_testing_data_topology_blacklist.conf0000644000175000017500000000035511615731255022561 00000000000000@INLINE@ test_testing_defaults.conf [PATHS] DEFAULTCONFIG = test_testing_data_topology_blacklist.conf [TESTING] NUM_PEERS = 4 TOPOLOGY = CLIQUE BLACKLIST_TOPOLOGY = RING BLACKLIST_TRANSPORTS = tcp udp http [transport-udp] PORT = 2568 gnunet-0.9.3/src/testing/helper.c0000644000175000017500000000460011760502551013635 00000000000000/* This file is part of GNUnet (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testing/helper.c * @brief helper functions for testing * @author Christian Grothoff * */ #include "platform.h" #include "gnunet_testing_lib.h" /** * Obtain the peer identity of the peer with the given configuration * handle. This function reads the private key of the peer, obtains * the public key and hashes it. * * @param cfg configuration of the peer * @param pid where to store the peer identity * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int GNUNET_TESTING_get_peer_identity (const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_PeerIdentity *pid) { char *keyfile; struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY", &keyfile)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Peer is lacking HOSTKEY configuration setting.\n")); return GNUNET_SYSERR; } my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); GNUNET_free (keyfile); if (my_private_key == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not access hostkey.\n")); return GNUNET_SYSERR; } GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key); GNUNET_CRYPTO_rsa_key_free (my_private_key); GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key), &pid->hashPubKey); return GNUNET_OK; } /* end of helper.c */ gnunet-0.9.3/src/testing/test_testing_2dtorus.c0000644000175000017500000002324011760517221016555 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testing/test_testing_2dtorus.c * * @brief Test for creating a 2dtorus. */ #include "platform.h" #include "gnunet_testing_lib.h" #define VERBOSE GNUNET_YES #define REMOVE_DIR GNUNET_YES /** * How long until we give up on connecting the peers? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500) /** * Time to wait for stuff that should be rather fast */ #define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) /** * How many events have happened */ static int ok; /** * Be verbose */ static int verbose; /** * Total number of peers in the test. */ static unsigned long long num_peers; /** * Global configuration file */ static struct GNUNET_CONFIGURATION_Handle *testing_cfg; /** * Total number of currently running peers. */ static unsigned long long peers_running; /** * Total number of successful connections in the whole network. */ static unsigned int total_connections; /** * Total number of counted topo connections */ static unsigned int topo_connections; /** * Total number of failed connections in the whole network. */ static unsigned int failed_connections; /** * The currently running peer group. */ static struct GNUNET_TESTING_PeerGroup *pg; /** * Task called to disconnect peers */ static GNUNET_SCHEDULER_TaskIdentifier disconnect_task; /** * Task called to shutdown test. */ static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle; /** * Check whether peers successfully shut down. */ static void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Shutdown of peers failed!\n"); #endif ok--; } else { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: All peers successfully shut down!\n"); #endif } } static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Ending test.\n"); #endif GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); GNUNET_CONFIGURATION_destroy (testing_cfg); } static void disconnect_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: disconnecting peers\n"); if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle) { GNUNET_SCHEDULER_cancel (shutdown_handle); shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); } } /** * Prototype of a callback function indicating that two peers * are currently connected. * * @param cls closure * @param first peer id for first daemon * @param second peer id for the second daemon * @param distance distance between the connected peers * @param emsg error message (NULL on success) */ void topo_cb (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, const char *emsg) { topo_connections++; if (NULL != emsg) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: Error by topo %u: %s\n", topo_connections, emsg); } else { if (first == NULL || second == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Connection %u NULL\n", topo_connections); if (disconnect_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (disconnect_task); GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL); } return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Connection %u ok\n", topo_connections); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: %s\n", GNUNET_i2s (first)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: %s\n", GNUNET_i2s (second)); } } /** * peergroup_ready: start test when all peers are connected * @param cls closure * @param emsg error message */ static void peergroup_ready (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Peergroup callback called with error, aborting test!\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Error from testing: `%s'\n", emsg); ok--; GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); return; } #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "************************************************************\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Peer Group started successfully!\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Have %u connections\n", total_connections); #endif peers_running = GNUNET_TESTING_daemons_running (pg); if (0 < failed_connections) { ok = GNUNET_SYSERR; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: %u connections have FAILED!\n", failed_connections); disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL); } else { GNUNET_TESTING_get_topology (pg, &topo_cb, NULL); disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_peers, NULL); ok = GNUNET_OK; } } /** * Function that will be called whenever two daemons are connected by * the testing library. * * @param cls closure * @param first peer id for first daemon * @param second peer id for the second daemon * @param distance distance between the connected peers * @param first_cfg config for the first daemon * @param second_cfg config for the second daemon * @param first_daemon handle for the first daemon * @param second_daemon handle for the second daemon * @param emsg error message (NULL on success) */ static void connect_cb (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, uint32_t distance, const struct GNUNET_CONFIGURATION_Handle *first_cfg, const struct GNUNET_CONFIGURATION_Handle *second_cfg, struct GNUNET_TESTING_Daemon *first_daemon, struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) { if (emsg == NULL) { total_connections++; } else { failed_connections++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Problem with new connection (%s)\n", emsg); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: (%s)\n", GNUNET_i2s (first)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: (%s)\n", GNUNET_i2s (second)); } } /** * run: load configuration options and schedule test to run (start peergroup) * @param cls closure * @param args argv * @param cfgfile configuration file name (can be NULL) * @param cfg configuration handle */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_TESTING_Host *hosts; ok = GNUNET_NO; total_connections = 0; failed_connections = 0; testing_cfg = GNUNET_CONFIGURATION_dup (cfg); GNUNET_log_setup ("test_testing_2dtorus", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Starting daemons.\n"); GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", "use_progressbars", "YES"); #endif if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing", "num_peers", &num_peers)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Option TESTING:NUM_PEERS is required!\n"); return; } hosts = GNUNET_TESTING_hosts_load (testing_cfg); pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT, &connect_cb, &peergroup_ready, NULL, hosts); GNUNET_assert (pg != NULL); shutdown_handle = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); } /** * test_testing_2dtorus command line options */ static struct GNUNET_GETOPT_CommandLineOption options[] = { {'V', "verbose", NULL, gettext_noop ("be verbose (print progress information)"), 0, &GNUNET_GETOPT_set_one, &verbose}, GNUNET_GETOPT_OPTION_END }; /** * Main: start test */ int main (int argc, char *argv[]) { char *const argv2[] = { argv[0], "-c", "test_testing_2dtorus.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Start\n"); GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, "test_testing_2dtorus", gettext_noop ("Test testing 2d torus."), options, &run, NULL); #if REMOVE_DIR GNUNET_DISK_directory_remove ("/tmp/test_testing_2dtorus"); #endif if (GNUNET_OK != ok) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: FAILED!\n"); return 1; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: success\n"); return 0; } /* end of test_testing_2dtorus.c */ gnunet-0.9.3/src/testing/test_testing_data_topology_scale_free.conf0000644000175000017500000000031111615731565022675 00000000000000@INLINE@ test_testing_defaults.conf [PATHS] DEFAULTCONFIG = test_testing_data_topology_scale_free.conf [TESTING] NUM_PEERS = 50 TOPOLOGY = SCALE_FREE [arm] DEFAULTSERVICES = peerinfo transport core gnunet-0.9.3/src/testing/test_testing_2dtorus.conf0000644000175000017500000000256511751071052017264 00000000000000@INLINE@ test_testing_defaults.conf [PATHS] SERVICEHOME = /tmp/test_testing_2dtorus/ DEFAULTCONFIG = test_testing_2dtorus.conf [arm] PORT = 10010 DEFAULTSERVICES = core #DEBUG = YES [statistics] AUTOSTART = YES PORT = 10000 [dht] DEBUG = NO AUTOSTART = YES ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; HOSTNAME = localhost PORT = 10001 [nse] WORKBITS = 0 [dns] AUTOSTART = NO PORT = 10011 [transport] PORT = 10002 AUTOSTART = YES PLUGINS = tcp [nat] DISABLEV6 = YES BINDTO = 127.0.0.1 ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 [ats] WAN_QUOTA_IN = 1 GB WAN_QUOTA_OUT = 1 GB [core] AUTOSTART = YES PORT = 10003 [peerinfo] AUTOSTART = YES PORT = 10004 [testing] NUM_PEERS = 16 WEAKRANDOM = YES TOPOLOGY = 2D_TORUS CONNECT_TOPOLOGY = 2D_TORUS #TOPOLOGY_FILE = small.dat CONNECT_TOPOLOGY = 2D_TORUS #CONNECT_TOPOLOGY_OPTION = CONNECT_MINIMUM #CONNECT_TOPOLOGY_OPTION_MODIFIER = 25 #PERCENTAGE = 3 #PROBABILITY = .1 F2F = NO CONNECT_TIMEOUT = 600 s CONNECT_ATTEMPTS = 2 DEBUG = YES HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat MAX_CONCURRENT_SSH = 10 USE_PROGRESSBARS = YES PEERGROUP_TIMEOUT = 2400 s TOPOLOGY_OUTPUT_FILE = testing_topo_initial MAX_OUTSTANDING_CONNECTIONS = 75 #SINGLE_PEERINFO_PER_HOST = YES #NUM_PEERINFO_PER_HOST = 10 #SINGLE_STATISTICS_PER_HOST = YES #NUM_STATISTICS_PER_HOST = 10 DELETE_FILES = YES gnunet-0.9.3/src/testing/test_testing_peergroup_data.conf0000644000175000017500000000073211661530126020657 00000000000000@INLINE@ test_testing_defaults.conf [PATHS] DEFAULTCONFIG = test_testing_peergroup_data.conf [TESTING] CONNECT_ATTEMPTS = 2 MAX_OUTSTANDING_CONNECTIONS = 20 MAX_CONCURRENT_SSH = 1 PEERGROUP_TIMEOUT = 300 s TOPOLOGY = CLIQUE PERCENTAGE = 0.5 PROBABILITY = 0.5 CONNECT_TOPOLOGY = CLIQUE CONNECT_TOPOLOGY_OPTION = CONNECT_NONE CONNECT_TOPOLOGY_OPTION_MODIFIER = 0.0 BLACKLIST_TOPOLOGY = NONE BLACKLIST_TRANSPORTS = tcp udp USE_PROGRESSBARS = NO [arm] DEFAULTSERVICES = core gnunet-0.9.3/src/testing/testing.c0000644000175000017500000022154211760502551014041 00000000000000/* This file is part of GNUnet (C) 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testing/testing.c * @brief convenience API for writing testcases for GNUnet * Many testcases need to start and stop gnunetd, * and this library is supposed to make that easier * for TESTCASES. Normal programs should always * use functions from gnunet_{util,arm}_lib.h. This API is * ONLY for writing testcases! * @author Christian Grothoff * */ #include "platform.h" #include "gnunet_arm_service.h" #include "gnunet_core_service.h" #include "gnunet_constants.h" #include "gnunet_testing_lib.h" #include "gnunet_transport_service.h" #include "gnunet_hello_lib.h" /** * Hack to deal with initial HELLO's being often devoid of addresses. * This hack causes 'process_hello' to ignore HELLOs without addresses. * The correct implementation would continue with 'process_hello' until * the connection could be established... */ #define EMPTY_HACK GNUNET_YES /** * How long do we wait after starting gnunet-service-arm * for the core service to be alive? */ #define ARM_START_WAIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) /** * How many times are we willing to try to wait for "scp" or * "gnunet-service-arm" to complete (waitpid) before giving up? */ #define MAX_EXEC_WAIT_RUNS 250 static struct GNUNET_CORE_MessageHandler no_handlers[] = { {NULL, 0, 0} }; #if EMPTY_HACK static int test_address (void *cls, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration) { int *empty = cls; *empty = GNUNET_NO; return GNUNET_OK; } #endif /** * Receive the HELLO from one peer, give it to the other * and ask them to connect. * * @param cls Closure (daemon whose hello is this). * @param message HELLO message of peer */ static void process_hello (void *cls, const struct GNUNET_MessageHeader *message) { struct GNUNET_TESTING_Daemon *daemon = cls; int msize; #if EMPTY_HACK int empty; empty = GNUNET_YES; GNUNET_assert (message != NULL); GNUNET_HELLO_iterate_addresses ((const struct GNUNET_HELLO_Message *) message, GNUNET_NO, &test_address, &empty); if (GNUNET_YES == empty) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Skipping empty HELLO address of peer %s\n", GNUNET_i2s (&daemon->id)); return; } #endif GNUNET_assert (daemon->phase == SP_GET_HELLO || daemon->phase == SP_START_DONE); daemon->cb = NULL; // FIXME: why??? (see fsm:SP_START_CORE, notify_daemon_started) if (daemon->task != GNUNET_SCHEDULER_NO_TASK) /* Assertion here instead? */ GNUNET_SCHEDULER_cancel (daemon->task); if (daemon->server != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' from transport service of `%4s', disconnecting core!\n", "HELLO", GNUNET_i2s (&daemon->id)); GNUNET_CORE_disconnect (daemon->server); daemon->server = NULL; } msize = ntohs (message->size); if (msize < 1) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "HELLO message of peer %s is of size 0\n", GNUNET_i2s (&daemon->id)); return; } if (daemon->ghh != NULL) { GNUNET_TRANSPORT_get_hello_cancel (daemon->ghh); daemon->ghh = NULL; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' from transport service of `%4s'\n", "HELLO", GNUNET_i2s (&daemon->id)); GNUNET_free_non_null (daemon->hello); daemon->hello = GNUNET_malloc (msize); memcpy (daemon->hello, message, msize); if (daemon->th != NULL) { GNUNET_TRANSPORT_disconnect (daemon->th); daemon->th = NULL; } daemon->phase = SP_START_DONE; } /** * Notify of a peer being up and running. Scheduled as a task * so that variables which may need to be set are set before * the connect callback can set up new operations. * FIXME: what variables?????? where from???? * * @param cls the testing daemon * @param tc task scheduler context */ static void notify_daemon_started (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TESTING_Daemon *d = cls; GNUNET_TESTING_NotifyDaemonRunning cb; cb = d->cb; d->cb = NULL; if (NULL != cb) cb (d->cb_cls, &d->id, d->cfg, d, NULL); } /** * Finite-state machine for starting GNUnet. * * @param cls our "struct GNUNET_TESTING_Daemon" * @param tc unused */ static void start_fsm (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TESTING_Daemon *d = cls; GNUNET_TESTING_NotifyDaemonRunning cb; enum GNUNET_OS_ProcessStatusType type; unsigned long code; char *dst; int bytes_read; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %s FSM is in phase %u.\n", GNUNET_i2s (&d->id), d->phase); d->task = GNUNET_SCHEDULER_NO_TASK; switch (d->phase) { case SP_COPYING: /* confirm copying complete */ if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_copying, &type, &code)) { if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) { cb = d->cb; d->cb = NULL; if (NULL != cb) cb (d->cb_cls, NULL, d->cfg, d, _ ("`scp' does not seem to terminate (timeout copying config).\n")); return; } /* wait some more */ d->task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, d); return; } if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) { cb = d->cb; d->cb = NULL; if (NULL != cb) cb (d->cb_cls, NULL, d->cfg, d, _("`scp' did not complete cleanly.\n")); return; } GNUNET_OS_process_destroy (d->proc_arm_copying); d->proc_arm_copying = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully copied configuration file.\n"); d->phase = SP_COPIED; /* fall-through */ case SP_COPIED: /* Start create hostkey process if we don't already know the peer identity! */ if (GNUNET_NO == d->have_hostkey) { GNUNET_assert (NULL == d->proc_arm_peerinfo); d->pipe_stdout = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_YES); if (d->pipe_stdout == NULL) { cb = d->cb; d->cb = NULL; if (NULL != cb) cb (d->cb_cls, NULL, d->cfg, d, (NULL == d->hostname) ? _("Failed to create pipe for `gnunet-peerinfo' process.\n") : _("Failed to create pipe for `ssh' process.\n")); return; } if (NULL == d->hostname) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting `%s', with command `%s %s %s %s'.\n", "gnunet-peerinfo", "gnunet-peerinfo", "-c", d->cfgfile, "-sq"); d->proc_arm_peerinfo = GNUNET_OS_start_process (GNUNET_YES, NULL, d->pipe_stdout, "gnunet-peerinfo", "gnunet-peerinfo", "-c", d->cfgfile, "-sq", NULL); GNUNET_DISK_pipe_close_end (d->pipe_stdout, GNUNET_DISK_PIPE_END_WRITE); } else { if (d->username != NULL) GNUNET_asprintf (&dst, "%s@%s", d->username, d->hostname); else dst = GNUNET_strdup (d->hostname); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting `%s', with command `%s %s %s %s %s %s'.\n", "gnunet-peerinfo", "ssh", dst, "gnunet-peerinfo", "-c", d->cfgfile, "-sq"); if (d->ssh_port_str == NULL) { d->proc_arm_peerinfo = GNUNET_OS_start_process (GNUNET_NO, NULL, d->pipe_stdout, "ssh", "ssh", "-q", dst, "gnunet-peerinfo", "-c", d->cfgfile, "-sq", NULL); } else { d->proc_arm_peerinfo = GNUNET_OS_start_process (GNUNET_NO, NULL, d->pipe_stdout, "ssh", "ssh", "-p", d->ssh_port_str, "-q", dst, "gnunet-peerinfo", "-c", d->cfgfile, "-sq", NULL); } GNUNET_DISK_pipe_close_end (d->pipe_stdout, GNUNET_DISK_PIPE_END_WRITE); GNUNET_free (dst); } if (NULL == d->proc_arm_peerinfo) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not start `%s' process to create hostkey.\n"), (NULL == d->hostname) ? "gnunet-peerinfo" : "ssh"); cb = d->cb; d->cb = NULL; if (NULL != cb) cb (d->cb_cls, NULL, d->cfg, d, (NULL == d->hostname) ? _("Failed to start `gnunet-peerinfo' process.\n") : _("Failed to start `ssh' process.\n")); GNUNET_DISK_pipe_close (d->pipe_stdout); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started `%s', waiting for hostkey.\n", "gnunet-peerinfo"); d->phase = SP_HOSTKEY_CREATE; d->task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining (d->max_timeout), GNUNET_DISK_pipe_handle (d->pipe_stdout, GNUNET_DISK_PIPE_END_READ), &start_fsm, d); } else /* Already have a hostkey! */ { if (d->hostkey_callback != NULL) { d->hostkey_callback (d->hostkey_cls, &d->id, d, NULL); d->hostkey_callback = NULL; d->phase = SP_HOSTKEY_CREATED; } else d->phase = SP_TOPOLOGY_SETUP; /* wait some more */ d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); } break; case SP_HOSTKEY_CREATE: bytes_read = GNUNET_DISK_file_read (GNUNET_DISK_pipe_handle (d->pipe_stdout, GNUNET_DISK_PIPE_END_READ), &d->hostkeybuf[d->hostkeybufpos], sizeof (d->hostkeybuf) - d->hostkeybufpos); if (bytes_read > 0) d->hostkeybufpos += bytes_read; if ((d->hostkeybufpos < 104) && (bytes_read > 0)) { /* keep reading */ d->task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining (d->max_timeout), GNUNET_DISK_pipe_handle (d->pipe_stdout, GNUNET_DISK_PIPE_END_READ), &start_fsm, d); return; } d->hostkeybuf[103] = '\0'; if ((bytes_read < 0) || (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (d->hostkeybuf, &d->id.hashPubKey))) { /* error */ if (bytes_read < 0) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Error reading from gnunet-peerinfo: %s\n"), STRERROR (errno)); else GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Malformed output from gnunet-peerinfo!\n")); cb = d->cb; d->cb = NULL; GNUNET_DISK_pipe_close (d->pipe_stdout); d->pipe_stdout = NULL; (void) GNUNET_OS_process_kill (d->proc_arm_peerinfo, SIGKILL); GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (d->proc_arm_peerinfo)); GNUNET_OS_process_destroy (d->proc_arm_peerinfo); d->proc_arm_peerinfo = NULL; if (NULL != cb) cb (d->cb_cls, NULL, d->cfg, d, _("Failed to get hostkey!\n")); return; } d->shortname = GNUNET_strdup (GNUNET_i2s (&d->id)); GNUNET_DISK_pipe_close (d->pipe_stdout); d->pipe_stdout = NULL; (void) GNUNET_OS_process_kill (d->proc_arm_peerinfo, SIGKILL); GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (d->proc_arm_peerinfo)); GNUNET_OS_process_destroy (d->proc_arm_peerinfo); d->proc_arm_peerinfo = NULL; d->have_hostkey = GNUNET_YES; if (d->hostkey_callback != NULL) { d->hostkey_callback (d->hostkey_cls, &d->id, d, NULL); d->hostkey_callback = NULL; d->phase = SP_HOSTKEY_CREATED; } else { d->phase = SP_TOPOLOGY_SETUP; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully got hostkey!\n"); /* Fall through */ case SP_HOSTKEY_CREATED: /* wait for topology finished */ if ((GNUNET_YES == d->dead) || (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0)) { cb = d->cb; d->cb = NULL; if (NULL != cb) cb (d->cb_cls, NULL, d->cfg, d, _("`Failed while waiting for topology setup!\n")); return; } d->task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, d); break; case SP_TOPOLOGY_SETUP: /* Indicates topology setup has completed! */ /* start GNUnet on remote host */ if (NULL == d->hostname) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting `%s', with command `%s %s %s %s'.\n", "gnunet-arm", "gnunet-arm", "-c", d->cfgfile, "-s"); d->proc_arm_start = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", "-c", d->cfgfile, "-s", "-q", "-T", GNUNET_TIME_relative_to_string (GNUNET_TIME_absolute_get_remaining (d->max_timeout)), NULL); } else { if (d->username != NULL) GNUNET_asprintf (&dst, "%s@%s", d->username, d->hostname); else dst = GNUNET_strdup (d->hostname); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Starting `%s', with command `%s %s %s %s %s %s %s'.\n", "gnunet-arm", "ssh", dst, "gnunet-arm", "-c", d->cfgfile, "-s", "-q"); if (d->ssh_port_str == NULL) { d->proc_arm_start = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", "-q", dst, "gnunet-arm", "-c", d->cfgfile, "-s", "-q", "-T", GNUNET_TIME_relative_to_string (GNUNET_TIME_absolute_get_remaining (d->max_timeout)), NULL); } else { d->proc_arm_start = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", "-p", d->ssh_port_str, "-q", dst, "gnunet-arm", "-c", d->cfgfile, "-s", "-q", "-T", GNUNET_TIME_relative_to_string (GNUNET_TIME_absolute_get_remaining (d->max_timeout)), NULL); } GNUNET_free (dst); } if (NULL == d->proc_arm_start) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not start `%s' process to start GNUnet.\n"), (NULL == d->hostname) ? "gnunet-arm" : "ssh"); cb = d->cb; d->cb = NULL; if (NULL != cb) cb (d->cb_cls, NULL, d->cfg, d, (NULL == d->hostname) ? _("Failed to start `gnunet-arm' process.\n") : _("Failed to start `ssh' process.\n")); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started `%s', waiting for `%s' to be up.\n", "gnunet-arm", "gnunet-service-core"); d->phase = SP_START_ARMING; d->task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, d); // FIXME: busy wait? break; case SP_START_ARMING: if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_start, &type, &code)) { if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) { cb = d->cb; d->cb = NULL; if (NULL != cb) cb (d->cb_cls, NULL, d->cfg, d, (NULL == d->hostname) ? _("`gnunet-arm' does not seem to terminate.\n") : _("`ssh' does not seem to terminate.\n")); if (d->cfg != NULL) { GNUNET_CONFIGURATION_destroy (d->cfg); d->cfg = NULL; } if (d->cfgfile != NULL) { GNUNET_free (d->cfgfile); d->cfgfile = NULL; } GNUNET_free_non_null (d->hostname); GNUNET_free_non_null (d->username); GNUNET_OS_process_destroy (d->proc_arm_start); d->proc_arm_start = NULL; d->username = NULL; d->hostname = NULL; // Quick hack to avoid crashing (testing need to be d->cfg = NULL; // overhauled anyway, and the error managing is // GNUNET_free (d); // FIXME (could this leak) // pretty broken anyway. return; } /* wait some more */ d->task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, d); // FIXME: busy wait? return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully started `%s'.\n", "gnunet-arm"); GNUNET_OS_process_destroy (d->proc_arm_start); d->proc_arm_start = NULL; d->phase = SP_START_CORE; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling CORE_connect\n"); /* Fall through */ case SP_START_CORE: if (d->server != NULL) GNUNET_CORE_disconnect (d->server); d->th = GNUNET_TRANSPORT_connect (d->cfg, &d->id, d, NULL, NULL, NULL); if (d->th == NULL) { if (GNUNET_YES == d->dead) GNUNET_TESTING_daemon_stop (d, GNUNET_TIME_absolute_get_remaining (d->max_timeout), d->dead_cb, d->dead_cb_cls, GNUNET_YES, GNUNET_NO); else if (NULL != d->cb) d->cb (d->cb_cls, &d->id, d->cfg, d, _("Failed to connect to transport service!\n")); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected to transport service `%s', getting HELLO\n", GNUNET_i2s (&d->id)); d->ghh = GNUNET_TRANSPORT_get_hello (d->th, &process_hello, d); /* FIXME: store task ID somewhere! */ GNUNET_SCHEDULER_add_now (¬ify_daemon_started, d); /*cb = d->cb; * d->cb = NULL; * if (NULL != cb) * cb (d->cb_cls, &d->id, d->cfg, d, NULL); */ d->running = GNUNET_YES; d->phase = SP_GET_HELLO; break; case SP_GET_HELLO: if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) { if (d->server != NULL) GNUNET_CORE_disconnect (d->server); if (d->th != NULL) GNUNET_TRANSPORT_disconnect (d->th); cb = d->cb; d->cb = NULL; if (NULL != cb) cb (d->cb_cls, NULL, d->cfg, d, _("Unable to get HELLO for peer!\n")); GNUNET_CONFIGURATION_destroy (d->cfg); GNUNET_free (d->cfgfile); GNUNET_free_non_null (d->hostname); GNUNET_free_non_null (d->username); GNUNET_free (d); return; } if (d->hello != NULL) return; GNUNET_assert (d->task == GNUNET_SCHEDULER_NO_TASK); d->task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_CONSTANTS_SERVICE_RETRY, 2), &start_fsm, d); break; case SP_START_DONE: GNUNET_break (0); break; case SP_SERVICE_START: /* confirm gnunet-arm exited */ if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_srv_start, &type, &code)) { if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) { cb = d->cb; d->cb = NULL; if (NULL != cb) cb (d->cb_cls, NULL, d->cfg, d, (NULL == d->hostname) ? _("`gnunet-arm' does not seem to terminate.\n") : _("`ssh' does not seem to terminate.\n")); return; } /* wait some more */ d->task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, d); return; } #if EXTRA_CHECKS if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) { cb = d->cb; d->cb = NULL; if (NULL != cb) cb (d->cb_cls, NULL, d->cfg, d, (NULL == d->hostname) ? _ ("`gnunet-arm' terminated with non-zero exit status (or timed out)!\n") : _("`ssh' does not seem to terminate.\n")); return; } #endif GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service startup complete!\n"); cb = d->cb; d->cb = NULL; d->phase = SP_START_DONE; if (NULL != cb) cb (d->cb_cls, &d->id, d->cfg, d, NULL); GNUNET_OS_process_destroy (d->proc_arm_srv_start); d->proc_arm_srv_start = NULL; break; case SP_SERVICE_SHUTDOWN_START: /* confirm copying complete */ if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_srv_stop, &type, &code)) { if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) { if (NULL != d->dead_cb) d->dead_cb (d->dead_cb_cls, _ ("either `gnunet-arm' or `ssh' does not seem to terminate.\n")); return; } /* wait some more */ d->task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, d); return; } #if EXTRA_CHECKS if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) { if (NULL != d->dead_cb) d->dead_cb (d->dead_cb_cls, _ ("shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n")); return; } #endif GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service shutdown complete.\n"); if (NULL != d->dead_cb) d->dead_cb (d->dead_cb_cls, NULL); break; case SP_SHUTDOWN_START: /* confirm copying complete !??? */ if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_stop, &type, &code)) { if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) { if (NULL != d->dead_cb) d->dead_cb (d->dead_cb_cls, _ ("either `gnunet-arm' or `ssh' does not seem to terminate.\n")); if (d->th != NULL) { GNUNET_TRANSPORT_get_hello_cancel (d->ghh); d->ghh = NULL; GNUNET_TRANSPORT_disconnect (d->th); d->th = NULL; } if (d->cfg != NULL) { GNUNET_CONFIGURATION_destroy (d->cfg); d->cfg = NULL; } if (d->cfgfile != NULL) { GNUNET_free (d->cfgfile); d->cfgfile = NULL; } GNUNET_free_non_null (d->hello); GNUNET_free_non_null (d->hostname); GNUNET_free_non_null (d->username); GNUNET_free_non_null (d->shortname); GNUNET_OS_process_destroy (d->proc_arm_stop); d->proc_arm_stop = NULL; GNUNET_free (d); return; } /* wait some more */ d->task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, d); return; } if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) { if (NULL != d->dead_cb) d->dead_cb (d->dead_cb_cls, _ ("shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n")); if (d->th != NULL) { GNUNET_TRANSPORT_get_hello_cancel (d->ghh); d->ghh = NULL; GNUNET_TRANSPORT_disconnect (d->th); d->th = NULL; } if (d->server != NULL) { GNUNET_CORE_disconnect (d->server); d->server = NULL; } GNUNET_CONFIGURATION_destroy (d->cfg); d->cfg = NULL; GNUNET_free (d->cfgfile); GNUNET_free_non_null (d->hello); GNUNET_free_non_null (d->hostname); GNUNET_free_non_null (d->username); GNUNET_free_non_null (d->shortname); GNUNET_OS_process_destroy (d->proc_arm_stop); d->proc_arm_stop = NULL; GNUNET_free (d); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer shutdown complete.\n"); if (d->server != NULL) { GNUNET_CORE_disconnect (d->server); d->server = NULL; } if (d->th != NULL) { GNUNET_TRANSPORT_get_hello_cancel (d->ghh); d->ghh = NULL; GNUNET_TRANSPORT_disconnect (d->th); d->th = NULL; } if (NULL != d->dead_cb) d->dead_cb (d->dead_cb_cls, NULL); /* state clean up and notifications */ if (d->churn == GNUNET_NO) { GNUNET_CONFIGURATION_destroy (d->cfg); d->cfg = NULL; GNUNET_free (d->cfgfile); GNUNET_free_non_null (d->hostname); GNUNET_free_non_null (d->username); } GNUNET_free_non_null (d->hello); d->hello = NULL; GNUNET_free_non_null (d->shortname); GNUNET_OS_process_destroy (d->proc_arm_stop); d->proc_arm_stop = NULL; d->shortname = NULL; if (d->churn == GNUNET_NO) GNUNET_free (d); break; case SP_CONFIG_UPDATE: /* confirm copying complete */ if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_copying, &type, &code)) { if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) /* FIXME: config update should take timeout parameter! */ { cb = d->cb; d->cb = NULL; if (NULL != cb) cb (d->cb_cls, NULL, d->cfg, d, _("`scp' does not seem to terminate.\n")); return; } /* wait some more */ d->task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, d); return; } if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) { if (NULL != d->update_cb) d->update_cb (d->update_cb_cls, _("`scp' did not complete cleanly.\n")); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully copied configuration file.\n"); if (NULL != d->update_cb) d->update_cb (d->update_cb_cls, NULL); d->phase = SP_START_DONE; break; } } /** * Continues GNUnet daemon startup when user wanted to be notified * once a hostkey was generated (for creating friends files, blacklists, * etc.). * * @param daemon the daemon to finish starting */ void GNUNET_TESTING_daemon_continue_startup (struct GNUNET_TESTING_Daemon *daemon) { GNUNET_assert (daemon->phase == SP_HOSTKEY_CREATED); daemon->phase = SP_TOPOLOGY_SETUP; } /** * Check whether the given daemon is running. * * @param daemon the daemon to check * * @return GNUNET_YES if the daemon is up, GNUNET_NO if the * daemon is down, GNUNET_SYSERR on error. */ int GNUNET_TESTING_test_daemon_running (struct GNUNET_TESTING_Daemon *daemon) { if (daemon == NULL) return GNUNET_SYSERR; if (daemon->running == GNUNET_YES) return GNUNET_YES; return GNUNET_NO; } /** * Starts a GNUnet daemon service which has been previously stopped. * * @param d the daemon for which the service should be started * @param service the name of the service to start * @param timeout how long to wait for process for shutdown to complete * @param cb function called once the service starts * @param cb_cls closure for cb */ void GNUNET_TESTING_daemon_start_stopped_service (struct GNUNET_TESTING_Daemon *d, char *service, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_NotifyDaemonRunning cb, void *cb_cls) { char *arg; d->cb = cb; d->cb_cls = cb_cls; GNUNET_assert (d->running == GNUNET_YES); if (d->phase == SP_CONFIG_UPDATE) { GNUNET_SCHEDULER_cancel (d->task); d->phase = SP_START_DONE; } if (d->churned_services == NULL) { d->cb (d->cb_cls, &d->id, d->cfg, d, "No service has been churned off yet!!"); return; } d->phase = SP_SERVICE_START; GNUNET_free (d->churned_services); d->churned_services = NULL; d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); /* Check if this is a local or remote process */ if (NULL != d->hostname) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting gnunet-arm with config `%s' on host `%s'.\n", d->cfgfile, d->hostname); if (d->username != NULL) GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); else arg = GNUNET_strdup (d->hostname); d->proc_arm_srv_start = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", "-q", arg, "gnunet-arm", "-c", d->cfgfile, "-i", service, "-q", "-T", GNUNET_TIME_relative_to_string (timeout), NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting gnunet-arm with command ssh %s gnunet-arm -c %s -i %s -q\n", arg, "gnunet-arm", d->cfgfile, service); GNUNET_free (arg); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting gnunet-arm with config `%s' locally.\n", d->cfgfile); d->proc_arm_srv_start = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", "-c", d->cfgfile, "-i", service, "-q", "-T", GNUNET_TIME_relative_to_string (timeout), NULL); } d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); } /** * Starts a GNUnet daemon's service. * * @param d the daemon for which the service should be started * @param service the name of the service to start * @param timeout how long to wait for process for startup * @param cb function called once gnunet-arm returns * @param cb_cls closure for cb */ void GNUNET_TESTING_daemon_start_service (struct GNUNET_TESTING_Daemon *d, const char *service, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_NotifyDaemonRunning cb, void *cb_cls) { char *arg; d->cb = cb; d->cb_cls = cb_cls; GNUNET_assert (service != NULL); GNUNET_assert (d->running == GNUNET_YES); GNUNET_assert (d->phase == SP_START_DONE); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Starting service %s for peer `%4s'\n"), service, GNUNET_i2s (&d->id)); d->phase = SP_SERVICE_START; d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); /* Check if this is a local or remote process */ if (NULL != d->hostname) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting gnunet-arm with config `%s' on host `%s'.\n", d->cfgfile, d->hostname); if (d->username != NULL) GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); else arg = GNUNET_strdup (d->hostname); d->proc_arm_srv_start = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", "-q", arg, "gnunet-arm", "-c", d->cfgfile, "-i", service, "-q", "-T", GNUNET_TIME_relative_to_string (timeout), NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting gnunet-arm with command ssh %s gnunet-arm -c %s -i %s -q -T %s\n", arg, "gnunet-arm", d->cfgfile, service, GNUNET_TIME_relative_to_string (timeout)); GNUNET_free (arg); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting gnunet-arm with config `%s' locally.\n", d->cfgfile); d->proc_arm_srv_start = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", "-c", d->cfgfile, "-i", service, "-q", "-T", GNUNET_TIME_relative_to_string (timeout), NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting gnunet-arm with command %s -c %s -i %s -q -T %s\n", "gnunet-arm", d->cfgfile, service, GNUNET_TIME_relative_to_string (timeout)); } d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); } /** * Start a peer that has previously been stopped using the daemon_stop * call (and files weren't deleted and the allow restart flag) * * @param daemon the daemon to start (has been previously stopped) * @param timeout how long to wait for restart * @param cb the callback for notification when the peer is running * @param cb_cls closure for the callback */ void GNUNET_TESTING_daemon_start_stopped (struct GNUNET_TESTING_Daemon *daemon, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_NotifyDaemonRunning cb, void *cb_cls) { if (daemon->running == GNUNET_YES) { cb (cb_cls, &daemon->id, daemon->cfg, daemon, "Daemon already running, can't restart!"); return; } daemon->cb = cb; daemon->cb_cls = cb_cls; daemon->phase = SP_TOPOLOGY_SETUP; daemon->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); /* FIXME: why add_continuation? */ GNUNET_SCHEDULER_add_continuation (&start_fsm, daemon, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } /** * Starts a GNUnet daemon. GNUnet must be installed on the target * system and available in the PATH. The machine must furthermore be * reachable via "ssh" (unless the hostname is "NULL") without the * need to enter a password. * * @param cfg configuration to use * @param timeout how long to wait starting up peers * @param pretend GNUNET_YES to set up files but not start peer GNUNET_NO * to really start the peer (default) * @param hostname name of the machine where to run GNUnet * (use NULL for localhost). * @param ssh_username ssh username to use when connecting to hostname * @param sshport port to pass to ssh process when connecting to hostname * @param hostkey pointer to a hostkey to be written to disk (instead of being generated) * @param hostkey_callback function to call once the hostkey has been * generated for this peer, but it hasn't yet been started * (NULL to start immediately, otherwise waits on GNUNET_TESTING_daemon_continue_start) * @param hostkey_cls closure for hostkey callback * @param cb function to call once peer is up, or failed to start * @param cb_cls closure for cb * @return handle to the daemon (actual start will be completed asynchronously) */ struct GNUNET_TESTING_Daemon * GNUNET_TESTING_daemon_start (const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TIME_Relative timeout, int pretend, const char *hostname, const char *ssh_username, uint16_t sshport, const char *hostkey, GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback, void *hostkey_cls, GNUNET_TESTING_NotifyDaemonRunning cb, void *cb_cls) { struct GNUNET_TESTING_Daemon *ret; char *arg; char *username; char *servicehome; char *baseservicehome; char *slash; char *hostkeyfile; char *temp_file_name; struct GNUNET_DISK_FileHandle *fn; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; struct GNUNET_CRYPTO_RsaPrivateKey *private_key; ret = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Daemon)); ret->hostname = (hostname == NULL) ? NULL : GNUNET_strdup (hostname); if (sshport != 0) { GNUNET_asprintf (&ret->ssh_port_str, "%d", sshport); } else ret->ssh_port_str = NULL; /* Find service home and base service home directories, create it if it doesn't exist */ GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", "SERVICEHOME", &servicehome)); GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_create (servicehome)); GNUNET_asprintf (&temp_file_name, "%s/gnunet-testing-config", servicehome); ret->cfgfile = GNUNET_DISK_mktemp (temp_file_name); GNUNET_free (temp_file_name); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Setting up peer with configuration file `%s'.\n", ret->cfgfile); if (NULL == ret->cfgfile) { GNUNET_free_non_null (ret->ssh_port_str); GNUNET_free_non_null (ret->hostname); GNUNET_free (ret); return NULL; } ret->hostkey_callback = hostkey_callback; ret->hostkey_cls = hostkey_cls; ret->cb = cb; ret->cb_cls = cb_cls; ret->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); ret->cfg = GNUNET_CONFIGURATION_dup (cfg); GNUNET_CONFIGURATION_set_value_string (ret->cfg, "PATHS", "DEFAULTCONFIG", ret->cfgfile); if (hostkey != NULL) /* Get the peer identity from the hostkey */ { private_key = GNUNET_CRYPTO_rsa_decode_key (hostkey, HOSTKEYFILESIZE); GNUNET_assert (private_key != NULL); GNUNET_CRYPTO_rsa_key_get_public (private_key, &public_key); GNUNET_CRYPTO_hash (&public_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &ret->id.hashPubKey); ret->shortname = GNUNET_strdup (GNUNET_i2s (&ret->id)); ret->have_hostkey = GNUNET_YES; GNUNET_CRYPTO_rsa_key_free (private_key); } /* Write hostkey to file, if we were given one */ hostkeyfile = NULL; if (hostkey != NULL) { GNUNET_asprintf (&hostkeyfile, "%s/.hostkey", servicehome); fn = GNUNET_DISK_file_open (hostkeyfile, GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_CREATE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); GNUNET_assert (fn != NULL); GNUNET_assert (HOSTKEYFILESIZE == GNUNET_DISK_file_write (fn, hostkey, HOSTKEYFILESIZE)); GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fn)); } /* write configuration to temporary file */ if (GNUNET_OK != GNUNET_CONFIGURATION_write (ret->cfg, ret->cfgfile)) { if (0 != UNLINK (ret->cfgfile)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", ret->cfgfile); GNUNET_CONFIGURATION_destroy (ret->cfg); GNUNET_free_non_null (ret->hostname); GNUNET_free (ret->cfgfile); GNUNET_free (ret); return NULL; } if (ssh_username != NULL) username = GNUNET_strdup (ssh_username); if ((ssh_username == NULL) && (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "TESTING", "USERNAME", &username))) { if (NULL != getenv ("USER")) username = GNUNET_strdup (getenv ("USER")); else username = NULL; } ret->username = username; if (GNUNET_NO == pretend) /* Copy files, enter finite state machine */ { /* copy directory to remote host */ if (NULL != hostname) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Copying configuration directory to host `%s'.\n", hostname); baseservicehome = GNUNET_strdup (servicehome); /* Remove trailing /'s */ while (baseservicehome[strlen (baseservicehome) - 1] == '/') baseservicehome[strlen (baseservicehome) - 1] = '\0'; /* Find next directory /, jump one ahead */ slash = strrchr (baseservicehome, '/'); if (slash != NULL) *(++slash) = '\0'; ret->phase = SP_COPYING; if (NULL != username) GNUNET_asprintf (&arg, "%s@%s:%s", username, hostname, baseservicehome); else GNUNET_asprintf (&arg, "%s:%s", hostname, baseservicehome); GNUNET_free (baseservicehome); if (ret->ssh_port_str == NULL) { ret->proc_arm_copying = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", "-r", "-q", servicehome, arg, NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "copying directory with command scp -r %s %s\n", servicehome, arg); } else { ret->proc_arm_copying = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", "-r", "-P", ret->ssh_port_str, "-q", servicehome, arg, NULL); } GNUNET_free (arg); if (NULL == ret->proc_arm_copying) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not start `%s' process to copy configuration directory.\n"), "scp"); if (0 != UNLINK (ret->cfgfile)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", ret->cfgfile); GNUNET_CONFIGURATION_destroy (ret->cfg); GNUNET_free_non_null (ret->hostname); GNUNET_free_non_null (ret->username); GNUNET_free (ret->cfgfile); GNUNET_free (ret); if ((hostkey != NULL) && (0 != UNLINK (hostkeyfile))) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", hostkeyfile); GNUNET_free_non_null (hostkeyfile); GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (servicehome)); GNUNET_free (servicehome); return NULL; } ret->task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, ret); GNUNET_free_non_null (hostkeyfile); GNUNET_free (servicehome); return ret; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No need to copy configuration file since we are running locally.\n"); ret->phase = SP_COPIED; /* FIXME: why add_cont? */ GNUNET_SCHEDULER_add_continuation (&start_fsm, ret, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } GNUNET_free_non_null (hostkeyfile); GNUNET_free (servicehome); return ret; } /** * Restart (stop and start) a GNUnet daemon. * * @param d the daemon that should be restarted * @param cb function called once the daemon is (re)started * @param cb_cls closure for cb */ void GNUNET_TESTING_daemon_restart (struct GNUNET_TESTING_Daemon *d, GNUNET_TESTING_NotifyDaemonRunning cb, void *cb_cls) { char *arg; char *del_arg; del_arg = NULL; if (NULL != d->cb) { d->dead = GNUNET_YES; return; } d->cb = cb; d->cb_cls = cb_cls; if (d->phase == SP_CONFIG_UPDATE) { GNUNET_SCHEDULER_cancel (d->task); d->phase = SP_START_DONE; } if (d->server != NULL) { GNUNET_CORE_disconnect (d->server); d->server = NULL; } if (d->th != NULL) { GNUNET_TRANSPORT_get_hello_cancel (d->ghh); d->ghh = NULL; GNUNET_TRANSPORT_disconnect (d->th); d->th = NULL; } /* state clean up and notifications */ GNUNET_free_non_null (d->hello); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Terminating peer `%4s'\n"), GNUNET_i2s (&d->id)); d->phase = SP_START_ARMING; /* Check if this is a local or remote process */ if (NULL != d->hostname) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping gnunet-arm with config `%s' on host `%s'.\n", d->cfgfile, d->hostname); if (d->username != NULL) GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); else arg = GNUNET_strdup (d->hostname); d->proc_arm_stop = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", "-q", arg, "gnunet-arm", "-c", d->cfgfile, "-e", "-r", NULL); /* Use -r to restart arm and all services */ GNUNET_free (arg); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping gnunet-arm with config `%s' locally.\n", d->cfgfile); d->proc_arm_stop = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", "-c", d->cfgfile, "-e", "-r", NULL); } GNUNET_free_non_null (del_arg); d->task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, d); } /** * Stops a GNUnet daemon. * * @param d the daemon that should be stopped * @param service the name of the service to stop * @param timeout how long to wait for process for shutdown to complete * @param cb function called once the daemon was stopped * @param cb_cls closure for cb */ void GNUNET_TESTING_daemon_stop_service (struct GNUNET_TESTING_Daemon *d, const char *service, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_NotifyCompletion cb, void *cb_cls) { char *arg; d->dead_cb = cb; d->dead_cb_cls = cb_cls; GNUNET_assert (d->running == GNUNET_YES); if (d->phase == SP_CONFIG_UPDATE) { GNUNET_SCHEDULER_cancel (d->task); d->phase = SP_START_DONE; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Terminating peer `%4s'\n"), GNUNET_i2s (&d->id)); if (d->churned_services != NULL) { d->dead_cb (d->dead_cb_cls, "A service has already been turned off!!"); return; } d->phase = SP_SERVICE_SHUTDOWN_START; d->churned_services = GNUNET_strdup (service); d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); /* Check if this is a local or remote process */ if (NULL != d->hostname) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping gnunet-arm with config `%s' on host `%s'.\n", d->cfgfile, d->hostname); if (d->username != NULL) GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); else arg = GNUNET_strdup (d->hostname); d->proc_arm_srv_stop = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", "-q", arg, "gnunet-arm", "-c", d->cfgfile, "-k", service, "-q", "-T", GNUNET_TIME_relative_to_string (timeout), NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping gnunet-arm with command ssh %s gnunet-arm -c %s -k %s -q\n", arg, "gnunet-arm", d->cfgfile, service); GNUNET_free (arg); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping gnunet-arm with config `%s' locally.\n", d->cfgfile); d->proc_arm_srv_stop = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", "-c", d->cfgfile, "-k", service, "-q", "-T", GNUNET_TIME_relative_to_string (timeout), NULL); } d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); } /** * Forcefully terminate a process and clean up the child. * * @param proc handle to process to kill */ static void kill_and_close_process (struct GNUNET_OS_Process *proc) { (void) GNUNET_OS_process_kill (proc, SIGKILL); GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (proc)); GNUNET_OS_process_destroy (proc); } /** * Stops a GNUnet daemon. * * @param d the daemon that should be stopped * @param timeout how long to wait for process for shutdown to complete * @param cb function called once the daemon was stopped * @param cb_cls closure for cb * @param delete_files GNUNET_YES to remove files, GNUNET_NO * to leave them * @param allow_restart GNUNET_YES to restart peer later (using this API) * GNUNET_NO to kill off and clean up for good */ void GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_NotifyCompletion cb, void *cb_cls, int delete_files, int allow_restart) { char *arg; char *del_arg; d->dead_cb = cb; d->dead_cb_cls = cb_cls; if (NULL != d->cb) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Setting d->dead on peer `%4s'\n"), GNUNET_i2s (&d->id)); d->dead = GNUNET_YES; return; } if (NULL != d->proc_arm_start) { kill_and_close_process (d->proc_arm_start); d->proc_arm_start = NULL; } if (NULL != d->proc_arm_srv_start) { kill_and_close_process (d->proc_arm_srv_start); d->proc_arm_srv_start = NULL; } if (NULL != d->proc_arm_srv_stop) { kill_and_close_process (d->proc_arm_srv_stop); d->proc_arm_srv_stop = NULL; } if (NULL != d->proc_arm_copying) { kill_and_close_process (d->proc_arm_copying); d->proc_arm_copying = NULL; } if (NULL != d->proc_arm_peerinfo) { kill_and_close_process (d->proc_arm_peerinfo); d->proc_arm_peerinfo = NULL; } if ((d->running == GNUNET_NO) && (d->churn == GNUNET_YES)) { /* Peer has already been stopped in churn context! * Free what was left from churning! */ GNUNET_assert (d->cfg != NULL); GNUNET_CONFIGURATION_destroy (d->cfg); if (delete_files == GNUNET_YES) { if (0 != UNLINK (d->cfgfile)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "unlink"); } } GNUNET_free (d->cfgfile); GNUNET_free_non_null (d->hostname); GNUNET_free_non_null (d->username); if (NULL != d->dead_cb) d->dead_cb (d->dead_cb_cls, NULL); /* FIXME: this should be an assert and the test below should not be required, but testing is broken... */ GNUNET_break (NULL == d->proc_arm_stop); if (NULL == d->proc_arm_stop) GNUNET_free (d); return; } del_arg = NULL; if (delete_files == GNUNET_YES) { GNUNET_asprintf (&del_arg, "-d"); } if (d->phase == SP_CONFIG_UPDATE) { GNUNET_SCHEDULER_cancel (d->task); d->phase = SP_START_DONE; } /** Move this call to scheduled shutdown as fix for CORE_connect calling daemon_stop? if (d->server != NULL) { GNUNET_CORE_disconnect (d->server); d->server = NULL; } */ /* shutdown ARM process (will terminate others) */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Terminating peer `%4s'\n" , GNUNET_i2s (&d->id)); d->phase = SP_SHUTDOWN_START; d->running = GNUNET_NO; if (allow_restart == GNUNET_YES) d->churn = GNUNET_YES; if (d->th != NULL) { GNUNET_TRANSPORT_get_hello_cancel (d->ghh); d->ghh = NULL; GNUNET_TRANSPORT_disconnect (d->th); d->th = NULL; } /* Check if this is a local or remote process */ if (NULL != d->hostname) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping gnunet-arm with config `%s' on host `%s'.\n", d->cfgfile, d->hostname); if (d->username != NULL) GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); else arg = GNUNET_strdup (d->hostname); d->proc_arm_stop = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", "-q", arg, "gnunet-arm", "-c", d->cfgfile, "-e", "-q", "-T", GNUNET_TIME_relative_to_string (timeout), del_arg, NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping gnunet-arm with command ssh %s gnunet-arm -c %s -e -q %s\n", arg, "gnunet-arm", d->cfgfile, del_arg); /* Use -e to end arm, and -d to remove temp files */ GNUNET_free (arg); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping gnunet-arm with config `%s' locally.\n", d->cfgfile); d->proc_arm_stop = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "gnunet-arm", "gnunet-arm", "-c", d->cfgfile, "-e", "-q", "-T", GNUNET_TIME_relative_to_string (timeout), del_arg, NULL); GNUNET_assert (NULL != d->proc_arm_stop); } GNUNET_free_non_null (del_arg); d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); if (GNUNET_SCHEDULER_NO_TASK != d->task) GNUNET_SCHEDULER_cancel(d->task); d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); } /** * Changes the configuration of a GNUnet daemon. * * @param d the daemon that should be modified * @param cfg the new configuration for the daemon * @param cb function called once the configuration was changed * @param cb_cls closure for cb */ void GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d, struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_TESTING_NotifyCompletion cb, void *cb_cls) { char *arg; if (d->phase != SP_START_DONE) { if (NULL != cb) cb (cb_cls, _ ("Peer not yet running, can not change configuration at this point.")); return; } /* 1) write configuration to temporary file */ if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, d->cfgfile)) { if (NULL != cb) cb (cb_cls, _("Failed to write new configuration to disk.")); return; } /* 2) copy file to remote host (if necessary) */ if (NULL == d->hostname) { /* signal success */ if (NULL != cb) cb (cb_cls, NULL); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Copying updated configuration file to remote host `%s'.\n", d->hostname); d->phase = SP_CONFIG_UPDATE; if (NULL != d->username) GNUNET_asprintf (&arg, "%s@%s:%s", d->username, d->hostname, d->cfgfile); else GNUNET_asprintf (&arg, "%s:%s", d->hostname, d->cfgfile); d->proc_arm_copying = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", "-q", d->cfgfile, arg, NULL); GNUNET_free (arg); if (NULL == d->proc_arm_copying) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not start `%s' process to copy configuration file.\n"), "scp"); if (NULL != cb) cb (cb_cls, _("Failed to copy new configuration to remote machine.")); d->phase = SP_START_DONE; return; } d->update_cb = cb; d->update_cb_cls = cb_cls; d->task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, d); } /** * Data kept for each pair of peers that we try * to connect. */ struct GNUNET_TESTING_ConnectContext { /** * Testing handle to the first daemon. */ struct GNUNET_TESTING_Daemon *d1; /** * Handle to core of first daemon (to check connect) */ struct GNUNET_CORE_Handle *d1core; /** * Have we actually connected to the core of the first daemon yet? */ int d1core_ready; /** * Testing handle to the second daemon. */ struct GNUNET_TESTING_Daemon *d2; /** * Transport handle to the first daemon (to offer the HELLO of the second daemon to). */ struct GNUNET_TRANSPORT_Handle *d1th; /** * Function to call once we are done (or have timed out). */ GNUNET_TESTING_NotifyConnection cb; /** * Closure for "nb". */ void *cb_cls; /** * The relative timeout from whence this connect attempt was * started. Allows for reconnect attempts. */ struct GNUNET_TIME_Relative relative_timeout; /** * Maximum number of connect attempts, will retry connection * this number of times on failures. */ unsigned int connect_attempts; /** * Hello timeout task */ GNUNET_SCHEDULER_TaskIdentifier hello_send_task; /** * Connect timeout task */ GNUNET_SCHEDULER_TaskIdentifier timeout_task; /** * When should this operation be complete (or we must trigger * a timeout). */ struct GNUNET_TIME_Relative timeout_hello; /** * Was the connection attempt successful? */ int connected; /** * When connecting, do we need to send the HELLO? */ int send_hello; /** * The distance between the two connected peers */ uint32_t distance; }; /** Forward declaration **/ static void reattempt_daemons_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Notify callback about success or failure of the attempt * to connect the two peers * * @param cls our "struct GNUNET_TESTING_ConnectContext" (freed) * @param tc reason tells us if we succeeded or failed */ static void notify_connect_result (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TESTING_ConnectContext *ctx = cls; ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK; if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (ctx->hello_send_task); ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK; } if (ctx->d1th != NULL) GNUNET_TRANSPORT_disconnect (ctx->d1th); ctx->d1th = NULL; if (ctx->d1core != NULL) GNUNET_CORE_disconnect (ctx->d1core); ctx->d1core = NULL; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) { GNUNET_free (ctx); return; } if (ctx->connected == GNUNET_YES) { if (ctx->cb != NULL) { ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, ctx->distance, ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2, NULL); } } else if (ctx->connect_attempts > 0) { ctx->d1core_ready = GNUNET_NO; ctx->timeout_task = GNUNET_SCHEDULER_add_now (&reattempt_daemons_connect, ctx); return; } else { if (ctx->cb != NULL) { ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2, _("Peers failed to connect")); } } GNUNET_free (ctx); } /** * Success, connection is up. Signal client our success. * * @param cls our "struct GNUNET_TESTING_ConnectContext" * @param peer identity of the peer that has connected * @param atsi performance information * @param atsi_count number of records in 'atsi' * */ static void connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct GNUNET_TESTING_ConnectContext *ctx = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected peer %s to peer %s\n", ctx->d1->shortname, GNUNET_i2s (peer)); if (0 != memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity))) return; ctx->connected = GNUNET_YES; ctx->distance = 0; /* FIXME: distance */ if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (ctx->hello_send_task); ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_SCHEDULER_cancel (ctx->timeout_task); ctx->timeout_task = GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); } static void send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TESTING_ConnectContext *ctx = cls; struct GNUNET_MessageHeader *hello; ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; if ((ctx->d1core_ready == GNUNET_YES) && (ctx->d2->hello != NULL) && (NULL != GNUNET_HELLO_get_header (ctx->d2->hello)) && (ctx->d1->phase == SP_START_DONE) && (ctx->d2->phase == SP_START_DONE)) { hello = GNUNET_HELLO_get_header (ctx->d2->hello); GNUNET_assert (hello != NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Offering hello of %s to %s\n", ctx->d2->shortname, ctx->d1->shortname); GNUNET_TRANSPORT_offer_hello (ctx->d1th, hello, NULL, NULL); GNUNET_assert (ctx->d1core != NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending connect request to TRANSPORT of %s for peer %s\n", GNUNET_i2s (&ctx->d1->id), GNUNET_h2s (&ctx->d2->id.hashPubKey)); GNUNET_TRANSPORT_try_connect (ctx->d1th, &ctx->d2->id); ctx->timeout_hello = GNUNET_TIME_relative_add (ctx->timeout_hello, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500)); } ctx->hello_send_task = GNUNET_SCHEDULER_add_delayed (ctx->timeout_hello, &send_hello, ctx); } /** * Notify of a successful connection to the core service. * * @param cls a ConnectContext * @param server handle to the core service * @param my_identity the peer identity of this peer */ void core_init_notify (void *cls, struct GNUNET_CORE_Handle *server, const struct GNUNET_PeerIdentity *my_identity) { struct GNUNET_TESTING_ConnectContext *connect_ctx = cls; connect_ctx->d1core_ready = GNUNET_YES; if (connect_ctx->send_hello == GNUNET_NO) { GNUNET_TRANSPORT_try_connect (connect_ctx->d1th, &connect_ctx->d2->id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending connect request to TRANSPORT of %s for peer %s\n", connect_ctx->d1->shortname, connect_ctx->d2->shortname); } } /** * Try to connect again some peers that failed in an earlier attempt. This will * be tried as many times as connection_attempts in the configuration file. * * @param cls Closure (connection context between the two peers). * @param tc TaskContext. */ static void reattempt_daemons_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_TESTING_ConnectContext *ctx = cls; ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK; if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) return; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "re-attempting connect of peer %s to peer %s\n", ctx->d1->shortname, ctx->d2->shortname); ctx->connect_attempts--; GNUNET_assert (ctx->d1core == NULL); ctx->d1core_ready = GNUNET_NO; ctx->d1core = GNUNET_CORE_connect (ctx->d1->cfg, 1, ctx, &core_init_notify, &connect_notify, NULL, NULL, GNUNET_NO, NULL, GNUNET_NO, no_handlers); if (ctx->d1core == NULL) { if (NULL != ctx->cb) ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2, _("Failed to connect to core service of first peer!\n")); GNUNET_free (ctx); return; } /* Don't know reason for initial connect failure, update the HELLO for the second peer */ if (NULL != ctx->d2->hello) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "updating %s's HELLO\n", ctx->d2->shortname); GNUNET_free (ctx->d2->hello); ctx->d2->hello = NULL; if (NULL != ctx->d2->th) { GNUNET_TRANSPORT_get_hello_cancel (ctx->d2->ghh); ctx->d2->ghh = NULL; GNUNET_TRANSPORT_disconnect (ctx->d2->th); } ctx->d2->th = GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL, NULL, NULL); GNUNET_assert (ctx->d2->th != NULL); ctx->d2->ghh = GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "didn't have %s's HELLO\n", ctx->d2->shortname); } if ((NULL == ctx->d2->hello) && (ctx->d2->th == NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "didn't have %s's HELLO, trying to get it now\n", ctx->d2->shortname); ctx->d2->th = GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL, NULL, NULL); if (NULL == ctx->d2->th) { GNUNET_CORE_disconnect (ctx->d1core); GNUNET_free (ctx); if (NULL != ctx->cb) ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2, _("Failed to connect to transport service!\n")); return; } ctx->d2->ghh = GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2); } else { if (NULL == ctx->d2->hello) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "didn't have %s's HELLO but th wasn't NULL, not trying!!\n", ctx->d2->shortname); } } if (ctx->send_hello == GNUNET_YES) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending %s's HELLO to %s\n", ctx->d1->shortname, ctx->d2->shortname); ctx->d1th = GNUNET_TRANSPORT_connect (ctx->d1->cfg, &ctx->d1->id, ctx->d1, NULL, NULL, NULL); if (ctx->d1th == NULL) { GNUNET_CORE_disconnect (ctx->d1core); GNUNET_free (ctx); if (NULL != ctx->cb) ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2, _("Failed to connect to transport service!\n")); return; } GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == ctx->hello_send_task); ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to reconnect %s to %s\n", ctx->d1->shortname, ctx->d2->shortname); GNUNET_TRANSPORT_try_connect (ctx->d1th, &ctx->d2->id); } ctx->timeout_task = GNUNET_SCHEDULER_add_delayed (ctx->relative_timeout, ¬ify_connect_result, ctx); } /** * Iterator for currently known peers, to ensure * that we don't try to send duplicate connect * requests to core. * * @param cls our "struct GNUNET_TESTING_ConnectContext" * @param peer identity of the peer that has connected, * NULL when iteration has finished * @param atsi performance information * @param atsi_count number of records in 'atsi' * */ static void core_initial_iteration (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct GNUNET_TESTING_ConnectContext *ctx = cls; if ((peer != NULL) && (0 == memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity)))) { ctx->connected = GNUNET_YES; ctx->distance = 0; /* FIXME: distance */ return; } if (peer != NULL) return; /* ignore other peers */ /* peer == NULL: End of iteration over peers */ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == ctx->timeout_task); if (ctx->connected == GNUNET_YES) { ctx->timeout_task = GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); return; } /* Peer not already connected, need to schedule connect request! */ if (ctx->d1core == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers are NOT connected, connecting to core!\n"); ctx->d1core = GNUNET_CORE_connect (ctx->d1->cfg, 1, ctx, &core_init_notify, &connect_notify, NULL, NULL, GNUNET_NO, NULL, GNUNET_NO, no_handlers); } if (ctx->d1core == NULL) { ctx->timeout_task = GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); return; } if ((NULL == ctx->d2->hello) && (ctx->d2->th == NULL)) /* Do not yet have the second peer's hello, set up a task to get it */ { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Don't have d2's HELLO, trying to get it!\n"); ctx->d2->th = GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL, NULL, NULL); if (ctx->d2->th == NULL) { GNUNET_CORE_disconnect (ctx->d1core); ctx->d1core = NULL; ctx->timeout_task = GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); return; } ctx->d2->ghh = GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2); } if (ctx->send_hello == GNUNET_YES) { ctx->d1th = GNUNET_TRANSPORT_connect (ctx->d1->cfg, &ctx->d1->id, ctx->d1, NULL, NULL, NULL); if (ctx->d1th == NULL) { GNUNET_CORE_disconnect (ctx->d1core); ctx->d1core = NULL; ctx->timeout_task = GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); return; } GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == ctx->hello_send_task); ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx); } ctx->timeout_task = GNUNET_SCHEDULER_add_delayed (ctx->relative_timeout, ¬ify_connect_result, ctx); } /** * Establish a connection between two GNUnet daemons. The daemons * must both be running and not be stopped until either the * 'cb' callback is called OR the connection request has been * explicitly cancelled. * * @param d1 handle for the first daemon * @param d2 handle for the second daemon * @param timeout how long is the connection attempt * allowed to take? * @param max_connect_attempts how many times should we try to reconnect * (within timeout) * @param send_hello GNUNET_YES to send the HELLO, GNUNET_NO to assume * the HELLO has already been exchanged * @param cb function to call at the end * @param cb_cls closure for cb * @return handle to cancel the request */ struct GNUNET_TESTING_ConnectContext * GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1, struct GNUNET_TESTING_Daemon *d2, struct GNUNET_TIME_Relative timeout, unsigned int max_connect_attempts, int send_hello, GNUNET_TESTING_NotifyConnection cb, void *cb_cls) { struct GNUNET_TESTING_ConnectContext *ctx; if ((d1->running == GNUNET_NO) || (d2->running == GNUNET_NO)) { if (NULL != cb) cb (cb_cls, &d1->id, &d2->id, 0, d1->cfg, d2->cfg, d1, d2, _("Peers are not fully running yet, can not connect!\n")); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Peers are not up!\n"); return NULL; } ctx = GNUNET_malloc (sizeof (struct GNUNET_TESTING_ConnectContext)); ctx->d1 = d1; ctx->d2 = d2; ctx->timeout_hello = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500); ctx->relative_timeout = GNUNET_TIME_relative_divide (timeout, max_connect_attempts); ctx->cb = cb; ctx->cb_cls = cb_cls; ctx->connect_attempts = max_connect_attempts; ctx->connected = GNUNET_NO; ctx->send_hello = send_hello; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asked to connect peer %s to peer %s\n", d1->shortname, d2->shortname); /* Core is up! Iterate over all _known_ peers first to check if we are already connected to the peer! */ GNUNET_assert (NULL != GNUNET_CORE_is_peer_connected (ctx->d1->cfg, &ctx->d2->id, &core_initial_iteration, ctx)); return ctx; } /** * Cancel an attempt to connect two daemons. * * @param cc connect context */ void GNUNET_TESTING_daemons_connect_cancel (struct GNUNET_TESTING_ConnectContext *cc) { if (GNUNET_SCHEDULER_NO_TASK != cc->timeout_task) { GNUNET_SCHEDULER_cancel (cc->timeout_task); cc->timeout_task = GNUNET_SCHEDULER_NO_TASK; } if (GNUNET_SCHEDULER_NO_TASK != cc->hello_send_task) { GNUNET_SCHEDULER_cancel (cc->hello_send_task); cc->hello_send_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != cc->d1core) { GNUNET_CORE_disconnect (cc->d1core); cc->d1core = NULL; } if (NULL != cc->d1th) { GNUNET_TRANSPORT_disconnect (cc->d1th); cc->d1th = NULL; } GNUNET_free (cc); } /* end of testing.c */ gnunet-0.9.3/src/testing/test_testing_data_topology_clique_minimum.conf0000644000175000017500000000034111615731533023620 00000000000000@INLINE@ test_testing_defaults.conf [PATHS] DEFAULTCONFIG = test_testing_data_topology_clique.conf [TESTING] NUM_PEERS = 20 TOPOLOGY = CLIQUE CONNECT_TOPOLOGY_OPTION = CONNECT_MINIMUM CONNECT_TOPOLOGY_OPTION_MODIFIER = 2.0 gnunet-0.9.3/src/testing/test_testing_data_topology_2d_torus.conf0000644000175000017500000000022311751071052022335 00000000000000@INLINE@ test_testing_defaults.conf [PATHS] DEFAULTCONFIG = test_testing_data_topology_2d_torus.conf [TESTING] NUM_PEERS = 13 TOPOLOGY = 2D_TORUS gnunet-0.9.3/src/testing/test_testing_topology.c0000644000175000017500000011114711760502551017033 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testing/test_testing_topology.c * @brief base testcase for testing all the topologies provided */ #include "platform.h" #include "gnunet_testing_lib.h" #include "gnunet_core_service.h" #include "gnunet_os_lib.h" #define PROGRESS_BARS GNUNET_YES #define DELAY_FOR_LOGGING GNUNET_NO /** * How long until we fail the whole testcase? */ #define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 240) /** * How long until we give up on starting the peers? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 500) #define SECONDS_PER_PEER_START 120 #define DEFAULT_NUM_PEERS 4 #define MAX_OUTSTANDING_CONNECTIONS 100 static float fail_percentage = 0.05; static int ok; static unsigned long long num_peers; struct GNUNET_TIME_Relative connect_timeout; static unsigned long long connect_attempts; static unsigned int topology_connections; static unsigned int total_connections; static unsigned int failed_connections; static unsigned int total_server_connections; static unsigned int total_messages_received; static unsigned int expected_messages; static unsigned int expected_connections; static unsigned long long peers_left; static struct GNUNET_TESTING_PeerGroup *pg; const struct GNUNET_CONFIGURATION_Handle *main_cfg; GNUNET_SCHEDULER_TaskIdentifier die_task; static char *dotOutFileName; static struct GNUNET_TIME_Relative settle_time; static FILE *dotOutFile; static char *topology_string; static char *blacklist_transports; static int transmit_ready_scheduled; static int transmit_ready_failed; static int transmit_ready_called; static unsigned int modnum; static unsigned int dotnum; static enum GNUNET_TESTING_Topology topology; static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* Don't do any blacklisting */ static enum GNUNET_TESTING_Topology connection_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */ static enum GNUNET_TESTING_TopologyOption connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; static double connect_topology_option_modifier = 0.0; static char *test_directory; #define MTYPE 12345 GNUNET_NETWORK_STRUCT_BEGIN struct GNUNET_TestMessage { /** * Header of the message */ struct GNUNET_MessageHeader header; /** * Unique identifier for this message. */ uint32_t uid; }; GNUNET_NETWORK_STRUCT_END struct TestMessageContext { /* This is a linked list */ struct TestMessageContext *next; /* Handle to the sending peer core */ struct GNUNET_CORE_Handle *peer1handle; /* Handle to the receiving peer core */ struct GNUNET_CORE_Handle *peer2handle; /* Handle to the sending peer daemon */ struct GNUNET_TESTING_Daemon *peer1; /* Handle to the receiving peer daemon */ struct GNUNET_TESTING_Daemon *peer2; /* Identifier for this message, so we don't disconnect other peers! */ uint32_t uid; /* Has peer1 been notified already of a connection to peer2? */ int peer1notified; /* Has the core of peer2 been connected already? */ int peer2connected; /* Task for disconnecting cores, allow task to be cancelled on shutdown */ GNUNET_SCHEDULER_TaskIdentifier disconnect_task; }; static struct TestMessageContext *test_messages; /** * Check whether peers successfully shut down. */ static void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Shutdown of peers failed: %s!\n", emsg); if (ok == 0) ok = 666; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); } } #if DELAY_FOR_LOGGING static void gather_log_data () { char *peer_number; char *connect_number; struct GNUNET_OS_Process *mem_process; GNUNET_asprintf (&peer_number, "%llu", num_peers); GNUNET_asprintf (&connect_number, "%llu", expected_connections); mem_process = GNUNET_OS_start_process (NULL, NULL, "./memsize.pl", "memsize.pl", "totals.txt", peer_number, connect_number, NULL); GNUNET_OS_process_wait (mem_process); GNUNET_OS_process_destroy (mem_process); mem_process = NULL; } #endif static void finish_testing () { GNUNET_assert (pg != NULL); struct TestMessageContext *pos; struct TestMessageContext *free_pos; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called finish testing, stopping daemons.\n"); pos = test_messages; while (pos != NULL) { if (pos->peer1handle != NULL) { GNUNET_CORE_disconnect (pos->peer1handle); pos->peer1handle = NULL; } if (pos->peer2handle != NULL) { GNUNET_CORE_disconnect (pos->peer2handle); pos->peer2handle = NULL; } free_pos = pos; pos = pos->next; if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (free_pos->disconnect_task); } GNUNET_free (free_pos); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n", transmit_ready_scheduled, transmit_ready_failed, transmit_ready_called); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling daemons_stop\n"); GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); if (dotOutFile != NULL) { FPRINTF (dotOutFile, "%s", "}"); FCLOSE (dotOutFile); } ok = 0; } static void disconnect_cores (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct TestMessageContext *pos = cls; /* Disconnect from the respective cores */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer 1 `%4s'\n", GNUNET_i2s (&pos->peer1->id)); if (pos->peer1handle != NULL) { GNUNET_CORE_disconnect (pos->peer1handle); pos->peer1handle = NULL; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer 2 `%4s'\n", GNUNET_i2s (&pos->peer2->id)); if (pos->peer2handle != NULL) { GNUNET_CORE_disconnect (pos->peer2handle); pos->peer2handle = NULL; } pos->disconnect_task = GNUNET_SCHEDULER_NO_TASK; /* Decrement total connections so new can be established */ total_server_connections -= 2; } #if DO_STATS static void stats_finished (void *cls, int result) { GNUNET_SCHEDULER_add_now (&finish_testing, NULL); } /** * Callback function to process statistic values. * * @param cls closure * @param peer the peer the statistics belong to * @param subsystem name of subsystem that created the statistic * @param name the name of the datum * @param value the current value * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration */ static int stats_print (void *cls, const struct GNUNET_PeerIdentity *peer, const char *subsystem, const char *name, uint64_t value, int is_persistent) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s:%s:%s -- %llu\n", GNUNET_i2s (peer), subsystem, name, value); return GNUNET_OK; } #endif static void topology_cb (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, const char *emsg) { FILE *outfile = cls; if (first != NULL) { if (outfile != NULL) { FPRINTF (outfile, "\t\"%s\" -- ", GNUNET_i2s (first)); FPRINTF (outfile, "\"%s\";\n", GNUNET_i2s (second)); } topology_connections++; } else { FPRINTF (stderr, "Finished iterating over topology, %d total connections!\n", topology_connections); if (outfile != NULL) { FPRINTF (outfile, "%s", "}\n"); FCLOSE (outfile); #if DO_STATS GNUNET_TESTING_get_statistics (pg, &stats_finished, &stats_print, NULL); #endif GNUNET_SCHEDULER_add_now (&finish_testing, NULL); } } } static int process_mtype (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { char *dotOutFileNameFinished; FILE *dotOutFileFinished; struct TestMessageContext *pos = cls; struct GNUNET_TestMessage *msg = (struct GNUNET_TestMessage *) message; if (pos->uid != ntohl (msg->uid)) return GNUNET_OK; #if PROGRESS_BARS if ((total_messages_received) % modnum == 0) { if (total_messages_received == 0) FPRINTF (stdout, "%s", "0%%"); else FPRINTF (stdout, "%d%%", (int) (((float) total_messages_received / expected_messages) * 100)); } else if (total_messages_received % dotnum == 0) { FPRINTF (stdout, "%s", "."); } fflush (stdout); #endif total_messages_received++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received message from `%4s', type %d.\n", GNUNET_i2s (peer), ntohs (message->type)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Total messages received %d, expected %d.\n", total_messages_received, expected_messages); if (total_messages_received == expected_messages) { #if PROGRESS_BARS FPRINTF (stdout, "%s", "100%%]\n"); #endif GNUNET_SCHEDULER_cancel (die_task); GNUNET_asprintf (&dotOutFileNameFinished, "%s.dot", "final_topology"); dotOutFileFinished = FOPEN (dotOutFileNameFinished, "w"); GNUNET_free (dotOutFileNameFinished); if (dotOutFileFinished != NULL) { FPRINTF (dotOutFileFinished, "%s", "strict graph G {\n"); } topology_connections = 0; GNUNET_TESTING_get_topology (pg, &topology_cb, dotOutFileFinished); //GNUNET_SCHEDULER_add_now (&finish_testing, NULL); } else { pos->disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cores, pos); } return GNUNET_OK; } static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { char *msg = cls; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Ending with error: %s\n", msg); struct TestMessageContext *pos; struct TestMessageContext *free_pos; pos = test_messages; while (pos != NULL) { if (pos->peer1handle != NULL) { GNUNET_CORE_disconnect (pos->peer1handle); pos->peer1handle = NULL; } if (pos->peer2handle != NULL) { GNUNET_CORE_disconnect (pos->peer2handle); pos->peer2handle = NULL; } free_pos = pos; pos = pos->next; GNUNET_free (free_pos); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n", transmit_ready_scheduled, transmit_ready_failed, transmit_ready_called); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Total messages received %d, expected %d.\n", total_messages_received, expected_messages); if (pg != NULL) { GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); ok = 7331; /* Opposite of leet */ } else ok = 401; /* Never got peers started */ if (dotOutFile != NULL) { FPRINTF (dotOutFile, "%s", "}"); FCLOSE (dotOutFile); } } static size_t transmit_ready (void *cls, size_t size, void *buf) { struct GNUNET_TestMessage *m; struct TestMessageContext *pos = cls; GNUNET_assert (buf != NULL); m = (struct GNUNET_TestMessage *) buf; m->header.type = htons (MTYPE); m->header.size = htons (sizeof (struct GNUNET_TestMessage)); m->uid = htonl (pos->uid); transmit_ready_called++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "transmit ready for peer %s\ntransmit_ready's scheduled %d, transmit_ready's called %d\n", GNUNET_i2s (&pos->peer1->id), transmit_ready_scheduled, transmit_ready_called); return sizeof (struct GNUNET_TestMessage); } static struct GNUNET_CORE_MessageHandler no_handlers[] = { {NULL, 0, 0} }; static struct GNUNET_CORE_MessageHandler handlers[] = { {&process_mtype, MTYPE, sizeof (struct GNUNET_TestMessage)}, {NULL, 0, 0} }; static void init_notify_peer2 (void *cls, struct GNUNET_CORE_Handle *server, const struct GNUNET_PeerIdentity *my_identity) { struct TestMessageContext *pos = cls; total_server_connections++; pos->peer2connected = GNUNET_YES; if (pos->peer1notified == GNUNET_YES) /* Peer 1 has been notified of connection to peer 2 */ { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scheduling message send to peer `%s' from peer `%s' (init_notify_peer2)\n", GNUNET_i2s (my_identity), GNUNET_h2s (&pos->peer1->id.hashPubKey)); if (NULL == GNUNET_CORE_notify_transmit_ready (pos->peer1handle, GNUNET_YES, 0, TIMEOUT, &pos->peer2->id, sizeof (struct GNUNET_TestMessage), &transmit_ready, pos)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n", GNUNET_i2s (&pos->peer2->id)); transmit_ready_failed++; } else { transmit_ready_scheduled++; } } } /** * Method called whenever a given peer connects. * * @param cls closure * @param peer peer identity this notification is about * @param atsi performance data for the connection * @param atsi_count number of records in 'atsi' */ static void connect_notify_peers (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct TestMessageContext *pos = cls; if (0 == memcmp (peer, &pos->peer2->id, sizeof (struct GNUNET_PeerIdentity))) { pos->peer1notified = GNUNET_YES; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' notified of connection to peer `%s'\n", GNUNET_i2s (&pos->peer1->id), GNUNET_h2s (&peer->hashPubKey)); } else return; if (pos->peer2connected == GNUNET_YES) /* Already connected and notified of connection, send message! */ { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scheduling message send to peer `%s' from peer `%s' (init_notify_peer2)\n", GNUNET_i2s (&pos->peer2->id), GNUNET_h2s (&pos->peer1->id.hashPubKey)); if (NULL == GNUNET_CORE_notify_transmit_ready (pos->peer1handle, GNUNET_YES, 0, TIMEOUT, &pos->peer2->id, sizeof (struct GNUNET_TestMessage), &transmit_ready, pos)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n", GNUNET_i2s (&pos->peer2->id)); transmit_ready_failed++; } else { transmit_ready_scheduled++; } } } static void init_notify_peer1 (void *cls, struct GNUNET_CORE_Handle *server, const struct GNUNET_PeerIdentity *my_identity) { struct TestMessageContext *pos = cls; total_server_connections++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core connection to `%4s' established, setting up handles\n", GNUNET_i2s (my_identity)); /* * Connect to the receiving peer */ pos->peer2handle = GNUNET_CORE_connect (pos->peer2->cfg, 1, pos, &init_notify_peer2, NULL, NULL, NULL, GNUNET_YES, NULL, GNUNET_YES, handlers); } static void send_test_messages (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct TestMessageContext *pos = cls; if ((pos == test_messages) && (settle_time.rel_value > 0)) { topology_connections = 0; GNUNET_TESTING_get_topology (pg, &topology_cb, NULL); } if (((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) || (cls == NULL)) return; if (die_task == GNUNET_SCHEDULER_NO_TASK) { die_task = GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, "from send test messages (timeout)"); } if (total_server_connections >= MAX_OUTSTANDING_CONNECTIONS) { GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1), &send_test_messages, pos); return; /* Otherwise we'll double schedule messages here! */ } /* * Connect to the sending peer */ pos->peer1handle = GNUNET_CORE_connect (pos->peer1->cfg, 1, pos, &init_notify_peer1, &connect_notify_peers, NULL, NULL, GNUNET_NO, NULL, GNUNET_NO, no_handlers); GNUNET_assert (pos->peer1handle != NULL); if (total_server_connections < MAX_OUTSTANDING_CONNECTIONS) { GNUNET_SCHEDULER_add_now (&send_test_messages, pos->next); } else { GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1), &send_test_messages, pos->next); } } static void topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, uint32_t distance, const struct GNUNET_CONFIGURATION_Handle *first_cfg, const struct GNUNET_CONFIGURATION_Handle *second_cfg, struct GNUNET_TESTING_Daemon *first_daemon, struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) { struct TestMessageContext *temp_context; if (emsg == NULL) { #if PROGRESS_BARS if ((total_connections) % modnum == 0) { if (total_connections == 0) FPRINTF (stdout, "%s", "0%%"); else FPRINTF (stdout, "%d%%", (int) (((float) total_connections / expected_connections) * 100)); } else if (total_connections % dotnum == 0) { FPRINTF (stdout, "%s", "."); } fflush (stdout); #endif total_connections++; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "connected peer %s to peer %s\n", first_daemon->shortname, second_daemon->shortname); temp_context = GNUNET_malloc (sizeof (struct TestMessageContext)); temp_context->peer1 = first_daemon; temp_context->peer2 = second_daemon; temp_context->next = test_messages; temp_context->uid = total_connections; temp_context->disconnect_task = GNUNET_SCHEDULER_NO_TASK; test_messages = temp_context; expected_messages++; if (dotOutFile != NULL) FPRINTF (dotOutFile, "\tn%s -- n%s;\n", first_daemon->shortname, second_daemon->shortname); } else { failed_connections++; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to connect peer %s to peer %s with error :\n%s\n", first_daemon->shortname, second_daemon->shortname, emsg); } if (total_connections == expected_connections) { #if PROGRESS_BARS FPRINTF (stdout, "%s", "100%%]\n"); #endif GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created %d total connections, which is our target number! Calling send messages.\n", total_connections); modnum = expected_messages / 4; dotnum = (expected_messages / 50) + 1; if (modnum == 0) modnum = 1; if (dotnum == 0) dotnum = 1; GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; #if DELAY_FOR_LOGGING FPRINTF (stdout, "%s", "Sending test messages in 10 seconds.\n"); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10), &send_test_messages, test_messages); gather_log_data (); #else if (settle_time.rel_value > 0) { GNUNET_TESTING_get_topology (pg, &topology_cb, NULL); } GNUNET_SCHEDULER_add_delayed (settle_time, &send_test_messages, test_messages); #endif #if PROGRESS_BARS FPRINTF (stdout, "%s", "Test message progress: ["); #endif } else if (total_connections + failed_connections == expected_connections) { if (failed_connections < (unsigned int) (fail_percentage * total_connections)) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_SCHEDULER_add_now (&send_test_messages, test_messages); } else { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from topology_callback (too many failed connections)"); } } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d total connections, %d failed connections, Want %d (at least %d)\n", total_connections, failed_connections, expected_connections, expected_connections - (unsigned int) (fail_percentage * expected_connections)); } } static void topology_creation_finished (void *cls, const char *emsg) { if (emsg == NULL) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All topology connections created successfully!\n"); } static void connect_topology () { expected_connections = -1; if ((pg != NULL) && (peers_left == 0)) { expected_connections = GNUNET_TESTING_connect_topology (pg, connection_topology, connect_topology_option, connect_topology_option_modifier, connect_timeout, connect_attempts, &topology_creation_finished, NULL); #if PROGRESS_BARS GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n", expected_connections); #endif } GNUNET_SCHEDULER_cancel (die_task); if (expected_connections < 1) { die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from connect topology (bad return)"); return; } die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, SECONDS_PER_PEER_START * num_peers), &end_badly, "from connect topology (timeout)"); modnum = expected_connections / 4; dotnum = (expected_connections / 50) + 1; if (modnum == 0) modnum = 1; if (dotnum == 0) dotnum = 1; #if PROGRESS_BARS FPRINTF (stdout, "%s", "Peer connection progress: ["); #endif } static void create_topology () { peers_left = num_peers; /* Reset counter */ if (GNUNET_TESTING_create_topology (pg, topology, blacklist_topology, blacklist_transports) != GNUNET_SYSERR) { #if PROGRESS_BARS GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Topology set up, now starting peers!\n"); FPRINTF (stdout, "%s", "Daemon start progress ["); #endif GNUNET_TESTING_daemons_continue_startup (pg); } else { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from create topology (bad return)"); } GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, SECONDS_PER_PEER_START * num_peers), &end_badly, "from continue startup (timeout)"); } static void peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to start daemon with error: `%s'\n", emsg); return; } GNUNET_assert (id != NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", (num_peers - peers_left) + 1, num_peers); #if PROGRESS_BARS if ((num_peers - peers_left) % modnum == 0) { if (num_peers - peers_left == 0) FPRINTF (stdout, "%s", "0%%"); else FPRINTF (stdout, "%d%%", (int) (((float) (num_peers - peers_left) / num_peers) * 100)); } else if ((num_peers - peers_left) % dotnum == 0) { FPRINTF (stdout, "%s", "."); } fflush (stdout); #endif peers_left--; if (peers_left == 0) { #if PROGRESS_BARS FPRINTF (stdout, "%s", "100%%]\n"); #endif GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All %d daemons started, now connecting peers!\n", num_peers); GNUNET_SCHEDULER_cancel (die_task); /* Set up task in case topology creation doesn't finish * within a reasonable amount of time */ die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 8), &end_badly, "from peers_started_callback"); #if DELAY_FOR_LOGGING FPRINTF (stdout, "%s", "Connecting topology in 10 seconds\n"); gather_log_data (); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10), &connect_topology, NULL); #else connect_topology (); #endif ok = 0; } } /** * Callback indicating that the hostkey was created for a peer. * * @param cls NULL * @param id the peer identity * @param d the daemon handle (pretty useless at this point, remove?) * @param emsg non-null on failure */ void hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, struct GNUNET_TESTING_Daemon *d, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Hostkey callback received error: %s\n", emsg); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostkey (%d/%d) created for peer `%s'\n", num_peers - peers_left, num_peers, GNUNET_i2s (id)); #if PROGRESS_BARS if ((num_peers - peers_left) % modnum == 0) { if (num_peers - peers_left == 0) FPRINTF (stdout, "%s", "0%%"); else FPRINTF (stdout, "%d%%", (int) (((float) (num_peers - peers_left) / num_peers) * 100)); } else if ((num_peers - peers_left) % dotnum == 0) { FPRINTF (stdout, "%s", "."); } fflush (stdout); #endif peers_left--; if (peers_left == 0) { #if PROGRESS_BARS FPRINTF (stdout, "%s", "100%%]\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All %d hostkeys created, now creating topology!\n", num_peers); #endif GNUNET_SCHEDULER_cancel (die_task); /* Set up task in case topology creation doesn't finish * within a reasonable amount of time */ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "from create_topology"); GNUNET_SCHEDULER_add_now (&create_topology, NULL); ok = 0; } } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { char *topology_str; char *connect_topology_str; char *blacklist_topology_str; char *connect_topology_option_str; char *connect_topology_option_modifier_string; unsigned long long max_outstanding_connections; ok = 1; dotOutFile = FOPEN (dotOutFileName, "w"); if (dotOutFile != NULL) { FPRINTF (dotOutFile, "%s", "strict graph G {\n"); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons based on config file %s\n", cfgfile); if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", &test_directory)) { ok = 404; return; } if ((GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "topology", &topology_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get (&topology, topology_str))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid topology `%s' given for section %s option %s\n", topology_str, "TESTING", "TOPOLOGY"); topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */ } if ((GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "connect_topology", &connect_topology_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get (&connection_topology, connect_topology_str))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid connect topology `%s' given for section %s option %s\n", connect_topology_str, "TESTING", "CONNECT_TOPOLOGY"); } GNUNET_free_non_null (connect_topology_str); if ((GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "connect_topology_option", &connect_topology_option_str)) && (GNUNET_NO == GNUNET_TESTING_topology_option_get (&connect_topology_option, connect_topology_option_str))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid connect topology option `%s' given for section %s option %s\n", connect_topology_option_str, "TESTING", "CONNECT_TOPOLOGY_OPTION"); connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */ } GNUNET_free_non_null (connect_topology_option_str); if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "connect_topology_option_modifier", &connect_topology_option_modifier_string)) { if (SSCANF (connect_topology_option_modifier_string, "%lf", &connect_topology_option_modifier) != 1) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), connect_topology_option_modifier_string, "connect_topology_option_modifier", "TESTING"); } GNUNET_free (connect_topology_option_modifier_string); } if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "blacklist_transports", &blacklist_transports)) blacklist_transports = NULL; if ((GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "blacklist_topology", &blacklist_topology_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get (&blacklist_topology, blacklist_topology_str))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid topology `%s' given for section %s option %s\n", topology_str, "TESTING", "BLACKLIST_TOPOLOGY"); } GNUNET_free_non_null (topology_str); GNUNET_free_non_null (blacklist_topology_str); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "SETTLE_TIME", &settle_time)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", "testing", "SETTLE_TIME"); return; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "CONNECT_TIMEOUT", &connect_timeout)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", "testing", "CONNECT_TIMEOUT"); return; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_attempts", &connect_attempts)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", "testing", "connect_attempts"); return; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "max_outstanding_connections", &max_outstanding_connections)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", "testing", "max_outstanding_connections"); return; } if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", &num_peers)) num_peers = DEFAULT_NUM_PEERS; main_cfg = cfg; peers_left = num_peers; modnum = num_peers / 4; dotnum = (num_peers / 50) + 1; if (modnum == 0) modnum = 1; if (dotnum == 0) dotnum = 1; #if PROGRESS_BARS FPRINTF (stdout, "%s", "Hostkey generation progress: ["); #endif /* Set up a task to end testing if peer start fails */ die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, SECONDS_PER_PEER_START * num_peers), &end_badly, "didn't generate all hostkeys within a reasonable amount of time!!!"); GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1); pg = GNUNET_TESTING_daemons_start (cfg, peers_left, max_outstanding_connections, peers_left, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, SECONDS_PER_PEER_START * num_peers), &hostkey_callback, NULL, &peers_started_callback, NULL, &topology_callback, NULL, NULL); } static int check () { char *binary_name; char *config_file_name; GNUNET_asprintf (&binary_name, "test-testing-topology-%s", topology_string); GNUNET_asprintf (&config_file_name, "test_testing_data_topology_%s.conf", topology_string); int ret; char *const argv[] = { binary_name, "-c", config_file_name, NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; ret = GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, binary_name, "nohelp", options, &run, &ok); if (ret != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "`test-testing-topology-%s': Failed with error code %d\n", topology_string, ret); } GNUNET_free (binary_name); GNUNET_free (config_file_name); return ok; } int main (int argc, char *argv[]) { int ret; char *binary_start_pos; char *our_binary_name; char *dotexe; binary_start_pos = strchr (argv[0], '/'); GNUNET_assert (binary_start_pos != NULL); topology_string = strstr (binary_start_pos, "_topology"); GNUNET_assert (topology_string != NULL); topology_string++; topology_string = strstr (topology_string, "_"); GNUNET_assert (topology_string != NULL); topology_string++; topology_string = GNUNET_strdup (topology_string); if (NULL != (dotexe = strstr (topology_string, ".exe"))) dotexe[0] = '\0'; GNUNET_asprintf (&our_binary_name, "test-testing-topology_%s", topology_string); GNUNET_asprintf (&dotOutFileName, "topology_%s.dot", topology_string); GNUNET_log_setup (our_binary_name, "WARNING", NULL); ret = check (); GNUNET_free (topology_string); /** * Need to remove base directory, subdirectories taken care * of by the testing framework. */ if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to remove testing directory %s\n", test_directory); } GNUNET_free (our_binary_name); return ret; } /* end of test_testing_topology.c */ gnunet-0.9.3/src/testing/Makefile.in0000644000175000017500000016202411762217213014264 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-testing$(EXEEXT) check_PROGRAMS = test_testing$(EXEEXT) test_testing_connect$(EXEEXT) \ test_testing_reconnect$(EXEEXT) test_testing_group$(EXEEXT) \ test_testing_peergroup$(EXEEXT) \ test_testing_topology_stability$(EXEEXT) \ test_testing_topology_clique$(EXEEXT) \ test_testing_topology_clique_random$(EXEEXT) \ test_testing_topology_clique_minimum$(EXEEXT) \ test_testing_topology_clique_dfs$(EXEEXT) \ test_testing_topology_churn$(EXEEXT) \ test_testing_topology_line$(EXEEXT) \ test_testing_topology_blacklist$(EXEEXT) \ test_testing_group_remote$(EXEEXT) \ test_testing_2dtorus$(EXEEXT) \ test_testing_topology_ring$(EXEEXT) \ test_testing_topology_2d_torus$(EXEEXT) \ test_testing_topology_small_world_ring$(EXEEXT) \ test_testing_topology_small_world_torus$(EXEEXT) \ test_testing_topology_erdos_renyi$(EXEEXT) \ test_testing_topology_internat$(EXEEXT) \ test_testing_topology_none$(EXEEXT) \ test_testing_topology_scale_free$(EXEEXT) \ test_testing_new_portreservation$(EXEEXT) \ test_testing_new_peerstartup$(EXEEXT) \ test_testing_new_servicestartup$(EXEEXT) @ENABLE_TEST_RUN_TRUE@TESTS = test_testing$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_testing_connect$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_testing_reconnect$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_testing_group$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_testing_peergroup$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_testing_new_portreservation$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_testing_new_peerstartup$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_testing_new_servicestartup$(EXEEXT) subdir = src/testing DIST_COMMON = $(dist_pkgcfg_DATA) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libgnunettesting_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la am_libgnunettesting_la_OBJECTS = helper.lo testing.lo testing_group.lo \ testing_peergroup.lo libgnunettesting_la_OBJECTS = $(am_libgnunettesting_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunettesting_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunettesting_la_LDFLAGS) \ $(LDFLAGS) -o $@ libgnunettesting_new_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_libgnunettesting_new_la_OBJECTS = testing_new.lo libgnunettesting_new_la_OBJECTS = \ $(am_libgnunettesting_new_la_OBJECTS) libgnunettesting_new_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunettesting_new_la_LDFLAGS) \ $(LDFLAGS) -o $@ PROGRAMS = $(bin_PROGRAMS) am_gnunet_testing_OBJECTS = gnunet-testing.$(OBJEXT) gnunet_testing_OBJECTS = $(am_gnunet_testing_OBJECTS) am_test_testing_OBJECTS = test_testing.$(OBJEXT) test_testing_OBJECTS = $(am_test_testing_OBJECTS) test_testing_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_2dtorus_OBJECTS = test_testing_2dtorus.$(OBJEXT) test_testing_2dtorus_OBJECTS = $(am_test_testing_2dtorus_OBJECTS) test_testing_2dtorus_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_connect_OBJECTS = test_testing_connect.$(OBJEXT) test_testing_connect_OBJECTS = $(am_test_testing_connect_OBJECTS) test_testing_connect_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_group_OBJECTS = test_testing_group.$(OBJEXT) test_testing_group_OBJECTS = $(am_test_testing_group_OBJECTS) test_testing_group_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_group_remote_OBJECTS = \ test_testing_group_remote.$(OBJEXT) test_testing_group_remote_OBJECTS = \ $(am_test_testing_group_remote_OBJECTS) test_testing_group_remote_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_new_peerstartup_OBJECTS = \ test_testing_new_peerstartup.$(OBJEXT) test_testing_new_peerstartup_OBJECTS = \ $(am_test_testing_new_peerstartup_OBJECTS) test_testing_new_peerstartup_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting_new.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_new_portreservation_OBJECTS = \ test_testing_new_portreservation.$(OBJEXT) test_testing_new_portreservation_OBJECTS = \ $(am_test_testing_new_portreservation_OBJECTS) test_testing_new_portreservation_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting_new.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_new_servicestartup_OBJECTS = \ test_testing_new_servicestartup.$(OBJEXT) test_testing_new_servicestartup_OBJECTS = \ $(am_test_testing_new_servicestartup_OBJECTS) test_testing_new_servicestartup_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting_new.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_peergroup_OBJECTS = test_testing_peergroup.$(OBJEXT) test_testing_peergroup_OBJECTS = $(am_test_testing_peergroup_OBJECTS) test_testing_peergroup_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_reconnect_OBJECTS = test_testing_reconnect.$(OBJEXT) test_testing_reconnect_OBJECTS = $(am_test_testing_reconnect_OBJECTS) test_testing_reconnect_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_topology_2d_torus_OBJECTS = \ test_testing_topology.$(OBJEXT) test_testing_topology_2d_torus_OBJECTS = \ $(am_test_testing_topology_2d_torus_OBJECTS) test_testing_topology_2d_torus_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_topology_blacklist_OBJECTS = \ test_testing_topology_blacklist.$(OBJEXT) test_testing_topology_blacklist_OBJECTS = \ $(am_test_testing_topology_blacklist_OBJECTS) test_testing_topology_blacklist_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_topology_churn_OBJECTS = \ test_testing_topology_churn.$(OBJEXT) test_testing_topology_churn_OBJECTS = \ $(am_test_testing_topology_churn_OBJECTS) test_testing_topology_churn_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_topology_clique_OBJECTS = \ test_testing_topology.$(OBJEXT) test_testing_topology_clique_OBJECTS = \ $(am_test_testing_topology_clique_OBJECTS) test_testing_topology_clique_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_topology_clique_dfs_OBJECTS = \ test_testing_topology.$(OBJEXT) test_testing_topology_clique_dfs_OBJECTS = \ $(am_test_testing_topology_clique_dfs_OBJECTS) test_testing_topology_clique_dfs_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_topology_clique_minimum_OBJECTS = \ test_testing_topology.$(OBJEXT) test_testing_topology_clique_minimum_OBJECTS = \ $(am_test_testing_topology_clique_minimum_OBJECTS) test_testing_topology_clique_minimum_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_topology_clique_random_OBJECTS = \ test_testing_topology.$(OBJEXT) test_testing_topology_clique_random_OBJECTS = \ $(am_test_testing_topology_clique_random_OBJECTS) test_testing_topology_clique_random_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_topology_erdos_renyi_OBJECTS = \ test_testing_topology.$(OBJEXT) test_testing_topology_erdos_renyi_OBJECTS = \ $(am_test_testing_topology_erdos_renyi_OBJECTS) test_testing_topology_erdos_renyi_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_topology_internat_OBJECTS = \ test_testing_topology.$(OBJEXT) test_testing_topology_internat_OBJECTS = \ $(am_test_testing_topology_internat_OBJECTS) test_testing_topology_internat_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_topology_line_OBJECTS = \ test_testing_topology.$(OBJEXT) test_testing_topology_line_OBJECTS = \ $(am_test_testing_topology_line_OBJECTS) test_testing_topology_line_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_topology_none_OBJECTS = \ test_testing_topology.$(OBJEXT) test_testing_topology_none_OBJECTS = \ $(am_test_testing_topology_none_OBJECTS) test_testing_topology_none_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_topology_ring_OBJECTS = \ test_testing_topology.$(OBJEXT) test_testing_topology_ring_OBJECTS = \ $(am_test_testing_topology_ring_OBJECTS) test_testing_topology_ring_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_topology_scale_free_OBJECTS = \ test_testing_topology.$(OBJEXT) test_testing_topology_scale_free_OBJECTS = \ $(am_test_testing_topology_scale_free_OBJECTS) test_testing_topology_scale_free_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_topology_small_world_ring_OBJECTS = \ test_testing_topology.$(OBJEXT) test_testing_topology_small_world_ring_OBJECTS = \ $(am_test_testing_topology_small_world_ring_OBJECTS) test_testing_topology_small_world_ring_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_topology_small_world_torus_OBJECTS = \ test_testing_topology.$(OBJEXT) test_testing_topology_small_world_torus_OBJECTS = \ $(am_test_testing_topology_small_world_torus_OBJECTS) test_testing_topology_small_world_torus_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_testing_topology_stability_OBJECTS = \ test_testing_topology.$(OBJEXT) test_testing_topology_stability_OBJECTS = \ $(am_test_testing_topology_stability_OBJECTS) test_testing_topology_stability_DEPENDENCIES = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunettesting_la_SOURCES) \ $(libgnunettesting_new_la_SOURCES) $(gnunet_testing_SOURCES) \ $(test_testing_SOURCES) $(test_testing_2dtorus_SOURCES) \ $(test_testing_connect_SOURCES) $(test_testing_group_SOURCES) \ $(test_testing_group_remote_SOURCES) \ $(test_testing_new_peerstartup_SOURCES) \ $(test_testing_new_portreservation_SOURCES) \ $(test_testing_new_servicestartup_SOURCES) \ $(test_testing_peergroup_SOURCES) \ $(test_testing_reconnect_SOURCES) \ $(test_testing_topology_2d_torus_SOURCES) \ $(test_testing_topology_blacklist_SOURCES) \ $(test_testing_topology_churn_SOURCES) \ $(test_testing_topology_clique_SOURCES) \ $(test_testing_topology_clique_dfs_SOURCES) \ $(test_testing_topology_clique_minimum_SOURCES) \ $(test_testing_topology_clique_random_SOURCES) \ $(test_testing_topology_erdos_renyi_SOURCES) \ $(test_testing_topology_internat_SOURCES) \ $(test_testing_topology_line_SOURCES) \ $(test_testing_topology_none_SOURCES) \ $(test_testing_topology_ring_SOURCES) \ $(test_testing_topology_scale_free_SOURCES) \ $(test_testing_topology_small_world_ring_SOURCES) \ $(test_testing_topology_small_world_torus_SOURCES) \ $(test_testing_topology_stability_SOURCES) DIST_SOURCES = $(libgnunettesting_la_SOURCES) \ $(libgnunettesting_new_la_SOURCES) $(gnunet_testing_SOURCES) \ $(test_testing_SOURCES) $(test_testing_2dtorus_SOURCES) \ $(test_testing_connect_SOURCES) $(test_testing_group_SOURCES) \ $(test_testing_group_remote_SOURCES) \ $(test_testing_new_peerstartup_SOURCES) \ $(test_testing_new_portreservation_SOURCES) \ $(test_testing_new_servicestartup_SOURCES) \ $(test_testing_peergroup_SOURCES) \ $(test_testing_reconnect_SOURCES) \ $(test_testing_topology_2d_torus_SOURCES) \ $(test_testing_topology_blacklist_SOURCES) \ $(test_testing_topology_churn_SOURCES) \ $(test_testing_topology_clique_SOURCES) \ $(test_testing_topology_clique_dfs_SOURCES) \ $(test_testing_topology_clique_minimum_SOURCES) \ $(test_testing_topology_clique_random_SOURCES) \ $(test_testing_topology_erdos_renyi_SOURCES) \ $(test_testing_topology_internat_SOURCES) \ $(test_testing_topology_line_SOURCES) \ $(test_testing_topology_none_SOURCES) \ $(test_testing_topology_ring_SOURCES) \ $(test_testing_topology_scale_free_SOURCES) \ $(test_testing_topology_small_world_ring_SOURCES) \ $(test_testing_topology_small_world_torus_SOURCES) \ $(test_testing_topology_stability_SOURCES) DATA = $(dist_pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @USE_COVERAGE_TRUE@XLIB = -lgcov pkgcfgdir = $(pkgdatadir)/config.d/ dist_pkgcfg_DATA = \ testing.conf @HAVE_EXPENSIVE_TESTS_TRUE@EXPENSIVE_TESTS = \ @HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_stability \ @HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_clique_random \ @HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_clique_minimum \ @HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_clique_dfs \ @HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_churn \ @HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_line \ @HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_blacklist \ @HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_group_remote \ @HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_ring \ @HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_2d_torus \ @HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_small_world_ring \ @HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_small_world_torus \ @HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_erdos_renyi \ @HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_internat \ @HAVE_EXPENSIVE_TESTS_TRUE@ test_testing_topology_scale_free lib_LTLIBRARIES = \ libgnunettesting.la \ libgnunettesting_new.la libgnunettesting_la_SOURCES = \ helper.c \ testing.c \ testing_group.c \ testing_peergroup.c libgnunettesting_la_LIBADD = $(XLIB) \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ -lm \ $(top_builddir)/src/util/libgnunetutil.la libgnunettesting_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:1:0 libgnunettesting_new_la_SOURCES = \ testing_new.c libgnunettesting_new_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la libgnunettesting_new_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:1:0 gnunet_testing_SOURCES = \ gnunet-testing.c gnunet_testing_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_testing_DEPENDENCIES = \ libgnunettesting.la test_testing_SOURCES = \ test_testing.c test_testing_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_connect_SOURCES = \ test_testing_connect.c test_testing_connect_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_reconnect_SOURCES = \ test_testing_reconnect.c test_testing_reconnect_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_group_SOURCES = \ test_testing_group.c test_testing_group_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_peergroup_SOURCES = \ test_testing_peergroup.c test_testing_peergroup_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_clique_SOURCES = \ test_testing_topology.c test_testing_topology_clique_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_stability_SOURCES = \ test_testing_topology.c test_testing_topology_stability_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_blacklist_SOURCES = \ test_testing_topology_blacklist.c test_testing_topology_blacklist_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_churn_SOURCES = \ test_testing_topology_churn.c test_testing_topology_churn_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_clique_random_SOURCES = \ test_testing_topology.c test_testing_topology_clique_random_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_clique_minimum_SOURCES = \ test_testing_topology.c test_testing_topology_clique_minimum_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_clique_dfs_SOURCES = \ test_testing_topology.c test_testing_topology_clique_dfs_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_line_SOURCES = \ test_testing_topology.c test_testing_topology_line_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_group_remote_SOURCES = \ test_testing_group_remote.c test_testing_group_remote_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_2dtorus_SOURCES = \ test_testing_2dtorus.c test_testing_2dtorus_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_ring_SOURCES = \ test_testing_topology.c test_testing_topology_ring_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_2d_torus_SOURCES = \ test_testing_topology.c test_testing_topology_2d_torus_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_small_world_ring_SOURCES = \ test_testing_topology.c test_testing_topology_small_world_ring_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_small_world_torus_SOURCES = \ test_testing_topology.c test_testing_topology_small_world_torus_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_internat_SOURCES = \ test_testing_topology.c test_testing_topology_internat_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_erdos_renyi_SOURCES = \ test_testing_topology.c test_testing_topology_erdos_renyi_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_scale_free_SOURCES = \ test_testing_topology.c test_testing_topology_scale_free_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_topology_none_SOURCES = \ test_testing_topology.c test_testing_topology_none_LDADD = \ $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_new_portreservation_SOURCES = \ test_testing_new_portreservation.c test_testing_new_portreservation_LDADD = \ $(top_builddir)/src/testing/libgnunettesting_new.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_new_peerstartup_SOURCES = \ test_testing_new_peerstartup.c test_testing_new_peerstartup_LDADD = \ $(top_builddir)/src/testing/libgnunettesting_new.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_new_servicestartup_SOURCES = \ test_testing_new_servicestartup.c test_testing_new_servicestartup_LDADD = \ $(top_builddir)/src/testing/libgnunettesting_new.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ test_testing_defaults.conf \ test_testing_data.conf \ test_testing_connect_peer1.conf \ test_testing_connect_peer2.conf \ test_testing_2dtorus.conf \ test_testing_data_topology_clique.conf \ test_testing_data_topology_clique_random.conf \ test_testing_data_topology_clique_minimum.conf \ test_testing_data_topology_clique_dfs.conf \ test_testing_data_topology_ring.conf \ test_testing_data_topology_2d_torus.conf \ test_testing_data_topology_small_world_ring.conf \ test_testing_data_topology_small_world_torus.conf \ test_testing_data_topology_erdos_renyi.conf \ test_testing_data_topology_internat.conf \ test_testing_data_topology_scale_free.conf \ test_testing_data_topology_blacklist.conf \ test_testing_data_topology_churn.conf \ test_testing_data_topology_none.conf \ test_testing_data_remote.conf \ test_testing_data_topology_stability.conf \ test_testing_peergroup_data.conf all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/testing/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/testing/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunettesting.la: $(libgnunettesting_la_OBJECTS) $(libgnunettesting_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunettesting_la_LINK) -rpath $(libdir) $(libgnunettesting_la_OBJECTS) $(libgnunettesting_la_LIBADD) $(LIBS) libgnunettesting_new.la: $(libgnunettesting_new_la_OBJECTS) $(libgnunettesting_new_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunettesting_new_la_LINK) -rpath $(libdir) $(libgnunettesting_new_la_OBJECTS) $(libgnunettesting_new_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-testing$(EXEEXT): $(gnunet_testing_OBJECTS) $(gnunet_testing_DEPENDENCIES) @rm -f gnunet-testing$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_testing_OBJECTS) $(gnunet_testing_LDADD) $(LIBS) test_testing$(EXEEXT): $(test_testing_OBJECTS) $(test_testing_DEPENDENCIES) @rm -f test_testing$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_OBJECTS) $(test_testing_LDADD) $(LIBS) test_testing_2dtorus$(EXEEXT): $(test_testing_2dtorus_OBJECTS) $(test_testing_2dtorus_DEPENDENCIES) @rm -f test_testing_2dtorus$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_2dtorus_OBJECTS) $(test_testing_2dtorus_LDADD) $(LIBS) test_testing_connect$(EXEEXT): $(test_testing_connect_OBJECTS) $(test_testing_connect_DEPENDENCIES) @rm -f test_testing_connect$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_connect_OBJECTS) $(test_testing_connect_LDADD) $(LIBS) test_testing_group$(EXEEXT): $(test_testing_group_OBJECTS) $(test_testing_group_DEPENDENCIES) @rm -f test_testing_group$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_group_OBJECTS) $(test_testing_group_LDADD) $(LIBS) test_testing_group_remote$(EXEEXT): $(test_testing_group_remote_OBJECTS) $(test_testing_group_remote_DEPENDENCIES) @rm -f test_testing_group_remote$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_group_remote_OBJECTS) $(test_testing_group_remote_LDADD) $(LIBS) test_testing_new_peerstartup$(EXEEXT): $(test_testing_new_peerstartup_OBJECTS) $(test_testing_new_peerstartup_DEPENDENCIES) @rm -f test_testing_new_peerstartup$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_new_peerstartup_OBJECTS) $(test_testing_new_peerstartup_LDADD) $(LIBS) test_testing_new_portreservation$(EXEEXT): $(test_testing_new_portreservation_OBJECTS) $(test_testing_new_portreservation_DEPENDENCIES) @rm -f test_testing_new_portreservation$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_new_portreservation_OBJECTS) $(test_testing_new_portreservation_LDADD) $(LIBS) test_testing_new_servicestartup$(EXEEXT): $(test_testing_new_servicestartup_OBJECTS) $(test_testing_new_servicestartup_DEPENDENCIES) @rm -f test_testing_new_servicestartup$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_new_servicestartup_OBJECTS) $(test_testing_new_servicestartup_LDADD) $(LIBS) test_testing_peergroup$(EXEEXT): $(test_testing_peergroup_OBJECTS) $(test_testing_peergroup_DEPENDENCIES) @rm -f test_testing_peergroup$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_peergroup_OBJECTS) $(test_testing_peergroup_LDADD) $(LIBS) test_testing_reconnect$(EXEEXT): $(test_testing_reconnect_OBJECTS) $(test_testing_reconnect_DEPENDENCIES) @rm -f test_testing_reconnect$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_reconnect_OBJECTS) $(test_testing_reconnect_LDADD) $(LIBS) test_testing_topology_2d_torus$(EXEEXT): $(test_testing_topology_2d_torus_OBJECTS) $(test_testing_topology_2d_torus_DEPENDENCIES) @rm -f test_testing_topology_2d_torus$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_topology_2d_torus_OBJECTS) $(test_testing_topology_2d_torus_LDADD) $(LIBS) test_testing_topology_blacklist$(EXEEXT): $(test_testing_topology_blacklist_OBJECTS) $(test_testing_topology_blacklist_DEPENDENCIES) @rm -f test_testing_topology_blacklist$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_topology_blacklist_OBJECTS) $(test_testing_topology_blacklist_LDADD) $(LIBS) test_testing_topology_churn$(EXEEXT): $(test_testing_topology_churn_OBJECTS) $(test_testing_topology_churn_DEPENDENCIES) @rm -f test_testing_topology_churn$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_topology_churn_OBJECTS) $(test_testing_topology_churn_LDADD) $(LIBS) test_testing_topology_clique$(EXEEXT): $(test_testing_topology_clique_OBJECTS) $(test_testing_topology_clique_DEPENDENCIES) @rm -f test_testing_topology_clique$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_topology_clique_OBJECTS) $(test_testing_topology_clique_LDADD) $(LIBS) test_testing_topology_clique_dfs$(EXEEXT): $(test_testing_topology_clique_dfs_OBJECTS) $(test_testing_topology_clique_dfs_DEPENDENCIES) @rm -f test_testing_topology_clique_dfs$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_topology_clique_dfs_OBJECTS) $(test_testing_topology_clique_dfs_LDADD) $(LIBS) test_testing_topology_clique_minimum$(EXEEXT): $(test_testing_topology_clique_minimum_OBJECTS) $(test_testing_topology_clique_minimum_DEPENDENCIES) @rm -f test_testing_topology_clique_minimum$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_topology_clique_minimum_OBJECTS) $(test_testing_topology_clique_minimum_LDADD) $(LIBS) test_testing_topology_clique_random$(EXEEXT): $(test_testing_topology_clique_random_OBJECTS) $(test_testing_topology_clique_random_DEPENDENCIES) @rm -f test_testing_topology_clique_random$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_topology_clique_random_OBJECTS) $(test_testing_topology_clique_random_LDADD) $(LIBS) test_testing_topology_erdos_renyi$(EXEEXT): $(test_testing_topology_erdos_renyi_OBJECTS) $(test_testing_topology_erdos_renyi_DEPENDENCIES) @rm -f test_testing_topology_erdos_renyi$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_topology_erdos_renyi_OBJECTS) $(test_testing_topology_erdos_renyi_LDADD) $(LIBS) test_testing_topology_internat$(EXEEXT): $(test_testing_topology_internat_OBJECTS) $(test_testing_topology_internat_DEPENDENCIES) @rm -f test_testing_topology_internat$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_topology_internat_OBJECTS) $(test_testing_topology_internat_LDADD) $(LIBS) test_testing_topology_line$(EXEEXT): $(test_testing_topology_line_OBJECTS) $(test_testing_topology_line_DEPENDENCIES) @rm -f test_testing_topology_line$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_topology_line_OBJECTS) $(test_testing_topology_line_LDADD) $(LIBS) test_testing_topology_none$(EXEEXT): $(test_testing_topology_none_OBJECTS) $(test_testing_topology_none_DEPENDENCIES) @rm -f test_testing_topology_none$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_topology_none_OBJECTS) $(test_testing_topology_none_LDADD) $(LIBS) test_testing_topology_ring$(EXEEXT): $(test_testing_topology_ring_OBJECTS) $(test_testing_topology_ring_DEPENDENCIES) @rm -f test_testing_topology_ring$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_topology_ring_OBJECTS) $(test_testing_topology_ring_LDADD) $(LIBS) test_testing_topology_scale_free$(EXEEXT): $(test_testing_topology_scale_free_OBJECTS) $(test_testing_topology_scale_free_DEPENDENCIES) @rm -f test_testing_topology_scale_free$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_topology_scale_free_OBJECTS) $(test_testing_topology_scale_free_LDADD) $(LIBS) test_testing_topology_small_world_ring$(EXEEXT): $(test_testing_topology_small_world_ring_OBJECTS) $(test_testing_topology_small_world_ring_DEPENDENCIES) @rm -f test_testing_topology_small_world_ring$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_topology_small_world_ring_OBJECTS) $(test_testing_topology_small_world_ring_LDADD) $(LIBS) test_testing_topology_small_world_torus$(EXEEXT): $(test_testing_topology_small_world_torus_OBJECTS) $(test_testing_topology_small_world_torus_DEPENDENCIES) @rm -f test_testing_topology_small_world_torus$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_topology_small_world_torus_OBJECTS) $(test_testing_topology_small_world_torus_LDADD) $(LIBS) test_testing_topology_stability$(EXEEXT): $(test_testing_topology_stability_OBJECTS) $(test_testing_topology_stability_DEPENDENCIES) @rm -f test_testing_topology_stability$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_testing_topology_stability_OBJECTS) $(test_testing_topology_stability_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-testing.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/helper.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing_2dtorus.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing_connect.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing_group.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing_group_remote.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing_new_peerstartup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing_new_portreservation.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing_new_servicestartup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing_peergroup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing_reconnect.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing_topology.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing_topology_blacklist.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testing_topology_churn.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testing.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testing_group.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testing_new.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testing_peergroup.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_pkgcfgDATA: $(dist_pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-dist_pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_pkgcfgDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-dist_pkgcfgDATA \ uninstall-libLTLIBRARIES .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-binPROGRAMS install-data \ install-data-am install-dist_pkgcfgDATA install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libLTLIBRARIES install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-dist_pkgcfgDATA uninstall-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/testing/test_testing_connect_peer2.conf0000644000175000017500000000126111647100202020372 00000000000000@INLINE@ test_testing_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-testing-connect-peer2/ DEFAULTCONFIG = test_testing_connect_peer2.conf [transport-tcp] PORT = 22568 [arm] PORT = 22566 DEFAULTSERVICES = core UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 22567 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 22564 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 22569 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 22565 UNIXPATH = /tmp/gnunet-p2-service-transport.sock [core] PORT = 22570 UNIXPATH = /tmp/gnunet-p2-service-core.sock [ats] PORT = 22571 UNIXPATH = /tmp/gnunet-p2-service-ats.sock gnunet-0.9.3/src/testing/test_testing_new_servicestartup.c0000644000175000017500000000624611762055613021122 00000000000000/* This file is part of GNUnet (C) 2008, 2009, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file testing/test_testing_new_servicestartup.c * @brief test case for testing service startup using new testing API * @author Sree Harsha Totakura */ #include "platform.h" #include "gnunet_testing_lib-new.h" #define LOG(kind,...) \ GNUNET_log (kind, __VA_ARGS__) #define TIME_REL_SEC(sec) \ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec) /** * Global test status */ static int test_success; /** * The shutdown task. Used to signal that testing is done and service has to be * stopped * * @param cls NULL */ static void shutdown_task(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { test_success = GNUNET_YES; GNUNET_SCHEDULER_shutdown (); } /** * The testing callback function * * @param cls NULL * @param cfg the configuration with which the current testing service is run */ static void test_run (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg) { GNUNET_assert (NULL == cls); GNUNET_assert (NULL != cfg); LOG (GNUNET_ERROR_TYPE_DEBUG, "Service arm started successfully\n"); GNUNET_SCHEDULER_add_delayed (TIME_REL_SEC (3), &shutdown_task, NULL); } /** * The main point of execution */ int main (int argc, char *argv[]) { char *_tmpdir; char *tmpdir; #ifdef MINGW char *tmpdir_w; #endif GNUNET_log_setup ("test_testing_new_servicestartup", "DEBUG", NULL); _tmpdir = getenv ("TMP"); if (NULL == _tmpdir) _tmpdir = getenv ("TEMP"); if (NULL == _tmpdir) _tmpdir = getenv ("TMPDIR"); if (NULL == _tmpdir) _tmpdir = "/tmp"; GNUNET_asprintf (&tmpdir, "%s/%s", _tmpdir, "test-gnunet-testing_new-XXXXXX"); #ifdef MINGW tmpdir_w = GNUNET_malloc (MAX_PATH + 1); GNUNET_assert (ERROR_SUCCESS == plibc_conv_to_win_path (tmpdir, tmpdir_w)); GNUNET_free (tmpdir); tmpdir = tmpdir_w; //GNUNET_assert (0 == _mktemp_s (tmpdir, strlen (tmpdir) + 1)); #else GNUNET_assert (mkdtemp (tmpdir) == tmpdir); #endif test_success = GNUNET_NO; GNUNET_assert (0 == GNUNET_TESTING_service_run (tmpdir, "arm", "test_testing_defaults.conf", &test_run, NULL)); GNUNET_free (tmpdir); return (GNUNET_YES == test_success) ? 0 : 1; } gnunet-0.9.3/src/testing/test_testing_data_topology_small_world_torus.conf0000644000175000017500000000020611615731424024355 00000000000000@INLINE@ test_testing_defaults.conf [PATHS] DEFAULTCONFIG = test_testing_data_topology_clique.conf [TESTING] TOPOLOGY = SMALL_WORLD gnunet-0.9.3/src/testing/test_testing_data_topology_ring.conf0000644000175000017500000000017711615731406021550 00000000000000@INLINE@ test_testing_defaults.conf [PATHS] DEFAULTCONFIG = test_testing_data_topology_clique.conf [TESTING] TOPOLOGY = RING gnunet-0.9.3/src/testing/test_testing_data_topology_none.conf0000644000175000017500000000061311615731670021546 00000000000000@INLINE@ test_testing_defaults.conf [PATHS] DEFAULTCONFIG = test_testing_data_topology_clique.conf [TESTING] NUM_PEERS = 1000 TOPOLOGY = NONE F2F = NO BLACKLIST_TOPOLOGY = NONE CONNECT_TOPOLOGY = RING [arm] PORT = 0 [statistics] AUTOSTART = NO PORT = 0 [resolver] AUTOSTART = NO PORT = 0 [peerinfo] PORT = 0 [transport] PORT = 0 [core] PORT = 0 [topology] PORT = 0 [hostlist] PORT = 0 gnunet-0.9.3/src/testing/test_testing_defaults.conf0000644000175000017500000000151411761166662017477 00000000000000[PATHS] SERVICEHOME = /tmp/test-gnunet-testing/ DEFAULTCONFIG = test_testing_defaults.conf [resolver] PORT = 2564 [transport] PORT = 2565 PLUGINS = tcp [arm] PORT = 2566 DEFAULTSERVICES = [statistics] PORT = 2567 [transport-tcp] PORT = 2568 BINDTO = 127.0.0.1 [peerinfo] PORT = 2569 [core] PORT = 2570 [testing] NUM_PEERS = 5 WEAKRANDOM = YES F2F = YES HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat [dht] AUTOSTART = NO [nat] DISABLEV6 = YES ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 USE_LOCALADDR = NO [dns] AUTOSTART = NO [nse] AUTOSTART = NO [mesh] AUTOSTART = NO [datastore] AUTOSTART = NO [fs] AUTOSTART = NO [dv] AUTOSTART = NO [chat] AUTOSTART = NO [vpn] AUTOSTART = NO [gns] AUTOSTART = NO [namestore] AUTOSTART = NO [lockmanager] AUTOSTART = NO gnunet-0.9.3/src/testing/test_testing_data_topology_small_world_ring.conf0000644000175000017500000000023211615731420024133 00000000000000@INLINE@ test_testing_defaults.conf [PATHS] DEFAULTCONFIG = test_testing_data_topology_clique.conf [TESTING] NUM_PEERS = 25 TOPOLOGY = SMALL_WORLD_RING gnunet-0.9.3/src/block/0000755000175000017500000000000011763406747011724 500000000000000gnunet-0.9.3/src/block/Makefile.am0000644000175000017500000000255311722750265013675 00000000000000INCLUDES = -I$(top_srcdir)/src/include plugindir = $(libdir)/gnunet if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage endif lib_LTLIBRARIES = libgnunetblock.la plugin_LTLIBRARIES = \ libgnunet_plugin_block_template.la \ libgnunet_plugin_block_test.la libgnunet_plugin_block_template_la_SOURCES = \ plugin_block_template.c libgnunet_plugin_block_template_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_block_template_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_block_test_la_SOURCES = \ plugin_block_test.c libgnunet_plugin_block_test_la_LIBADD = \ $(top_builddir)/src/block/libgnunetblock.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_block_test_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_block_test_la_DEPENDENCIES = \ libgnunetblock.la libgnunetblock_la_SOURCES = \ block.c libgnunetblock_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la libgnunetblock_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la libgnunetblock_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:0:0 check_PROGRAMS = \ test_block #TESTS = $(check_PROGRAMS) test_block_SOURCES = \ test_block.c test_block_LDADD = \ $(top_builddir)/src/block/libgnunetblock.la \ $(top_builddir)/src/util/libgnunetutil.la gnunet-0.9.3/src/block/test_block.c0000644000175000017500000000470611760502551014133 00000000000000/* This file is part of GNUnet (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file block/test_block.c * @brief test for block.c * @author Christian Grothoff */ #include "platform.h" #include "gnunet_block_lib.h" #define DEBUG GNUNET_EXTRA_LOGGING #define VERBOSE GNUNET_NO static int test_fs (struct GNUNET_BLOCK_Context *ctx) { GNUNET_HashCode key; char block[4]; memset (block, 1, sizeof (block)); if (GNUNET_OK != GNUNET_BLOCK_get_key (ctx, GNUNET_BLOCK_TYPE_FS_DBLOCK, block, sizeof (block), &key)) return 1; if (GNUNET_BLOCK_EVALUATION_OK_LAST != GNUNET_BLOCK_evaluate (ctx, GNUNET_BLOCK_TYPE_FS_DBLOCK, &key, NULL, 0, NULL, 0, block, sizeof (block))) return 2; if (GNUNET_BLOCK_EVALUATION_REQUEST_VALID != GNUNET_BLOCK_evaluate (ctx, GNUNET_BLOCK_TYPE_FS_DBLOCK, &key, NULL, 0, NULL, 0, NULL, 0)) return 4; GNUNET_log_skip (1, GNUNET_NO); if (GNUNET_BLOCK_EVALUATION_REQUEST_INVALID != GNUNET_BLOCK_evaluate (ctx, GNUNET_BLOCK_TYPE_FS_DBLOCK, &key, NULL, 0, "bogus", 5, NULL, 0)) return 8; GNUNET_log_skip (0, GNUNET_YES); return 0; } int main (int argc, char *argv[]) { int ret; struct GNUNET_BLOCK_Context *ctx; struct GNUNET_CONFIGURATION_Handle *cfg; GNUNET_log_setup ("test-block", "WARNING", NULL); cfg = GNUNET_CONFIGURATION_create (); GNUNET_CONFIGURATION_set_value_string (cfg, "block", "PLUGINS", "fs"); ctx = GNUNET_BLOCK_context_create (cfg); ret = test_fs (ctx); GNUNET_BLOCK_context_destroy (ctx); GNUNET_CONFIGURATION_destroy (cfg); if (ret != 0) FPRINTF (stderr, "Tests failed: %d\n", ret); return ret; } gnunet-0.9.3/src/block/block.c0000644000175000017500000002054111760502551013067 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file block/block.c * @brief library for data block manipulation * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_constants.h" #include "gnunet_signatures.h" #include "gnunet_block_lib.h" #include "gnunet_block_plugin.h" /** * Handle for a plugin. */ struct Plugin { /** * Name of the shared library. */ char *library_name; /** * Plugin API. */ struct GNUNET_BLOCK_PluginFunctions *api; }; /** * Handle to an initialized block library. */ struct GNUNET_BLOCK_Context { /** * Array of our plugins. */ struct Plugin **plugins; /** * Size of the 'plugins' array. */ unsigned int num_plugins; /** * Our configuration. */ const struct GNUNET_CONFIGURATION_Handle *cfg; }; /** * Mingle hash with the mingle_number to produce different bits. * * @param in original hash code * @param mingle_number number for hash permutation * @param hc where to store the result. */ void GNUNET_BLOCK_mingle_hash (const GNUNET_HashCode * in, uint32_t mingle_number, GNUNET_HashCode * hc) { GNUNET_HashCode m; GNUNET_CRYPTO_hash (&mingle_number, sizeof (uint32_t), &m); GNUNET_CRYPTO_hash_xor (&m, in, hc); } /** * Add a plugin to the list managed by the block library. * * @param cls the block context * @param library_name name of the plugin * @param lib_ret the plugin API */ static void add_plugin (void *cls, const char *library_name, void *lib_ret) { struct GNUNET_BLOCK_Context *ctx = cls; struct GNUNET_BLOCK_PluginFunctions *api = lib_ret; struct Plugin *plugin; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Loading block plugin `%s'\n"), library_name); plugin = GNUNET_malloc (sizeof (struct Plugin)); plugin->api = api; plugin->library_name = GNUNET_strdup (library_name); GNUNET_array_append (ctx->plugins, ctx->num_plugins, plugin); } /** * Create a block context. Loads the block plugins. * * @param cfg configuration to use * @return NULL on error */ struct GNUNET_BLOCK_Context * GNUNET_BLOCK_context_create (const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_BLOCK_Context *ctx; ctx = GNUNET_malloc (sizeof (struct GNUNET_BLOCK_Context)); ctx->cfg = cfg; GNUNET_PLUGIN_load_all ("libgnunet_plugin_block_", NULL, &add_plugin, ctx); return ctx; } /** * Destroy the block context. * * @param ctx context to destroy */ void GNUNET_BLOCK_context_destroy (struct GNUNET_BLOCK_Context *ctx) { unsigned int i; struct Plugin *plugin; for (i = 0; i < ctx->num_plugins; i++) { plugin = ctx->plugins[i]; GNUNET_break (NULL == GNUNET_PLUGIN_unload (plugin->library_name, plugin->api)); GNUNET_free (plugin->library_name); GNUNET_free (plugin); } GNUNET_free (ctx->plugins); GNUNET_free (ctx); } /** * Find a plugin for the given type. * * @param ctx context to search * @param type type to look for * @return NULL if no matching plugin exists */ static struct GNUNET_BLOCK_PluginFunctions * find_plugin (struct GNUNET_BLOCK_Context *ctx, enum GNUNET_BLOCK_Type type) { struct Plugin *plugin; unsigned int i; unsigned int j; for (i = 0; i < ctx->num_plugins; i++) { plugin = ctx->plugins[i]; j = 0; while (0 != (plugin->api->types[j])) { if (type == plugin->api->types[j]) return plugin->api; j++; } } return NULL; } /** * Function called to validate a reply or a request. For * request evaluation, simply pass "NULL" for the reply_block. * Note that it is assumed that the reply has already been * matched to the key (and signatures checked) as it would * be done with the "get_key" function. * * @param ctx block contxt * @param type block type * @param query original query (hash) * @param bf pointer to bloom filter associated with query; possibly updated (!) * @param bf_mutator mutation value for bf * @param xquery extended query data (can be NULL, depending on type) * @param xquery_size number of bytes in xquery * @param reply_block response to validate * @param reply_block_size number of bytes in reply block * @return characterization of result */ enum GNUNET_BLOCK_EvaluationResult GNUNET_BLOCK_evaluate (struct GNUNET_BLOCK_Context *ctx, enum GNUNET_BLOCK_Type type, const GNUNET_HashCode * query, struct GNUNET_CONTAINER_BloomFilter **bf, int32_t bf_mutator, const void *xquery, size_t xquery_size, const void *reply_block, size_t reply_block_size) { struct GNUNET_BLOCK_PluginFunctions *plugin = find_plugin (ctx, type); if (plugin == NULL) return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; return plugin->evaluate (plugin->cls, type, query, bf, bf_mutator, xquery, xquery_size, reply_block, reply_block_size); } /** * Function called to obtain the key for a block. * * @param ctx block context * @param type block type * @param block block to get the key for * @param block_size number of bytes in block * @param key set to the key (query) for the given block * @return GNUNET_OK on success, GNUNET_SYSERR if type not supported * (or if extracting a key from a block of this type does not work) */ int GNUNET_BLOCK_get_key (struct GNUNET_BLOCK_Context *ctx, enum GNUNET_BLOCK_Type type, const void *block, size_t block_size, GNUNET_HashCode * key) { struct GNUNET_BLOCK_PluginFunctions *plugin = find_plugin (ctx, type); if (plugin == NULL) return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; return plugin->get_key (plugin->cls, type, block, block_size, key); } /** * How many bytes should a bloomfilter be if we have already seen * entry_count responses? Note that GNUNET_CONSTANTS_BLOOMFILTER_K gives us the number * of bits set per entry. Furthermore, we should not re-size the * filter too often (to keep it cheap). * * Since other peers will also add entries but not resize the filter, * we should generally pick a slightly larger size than what the * strict math would suggest. * * @return must be a power of two and smaller or equal to 2^15. */ static size_t compute_bloomfilter_size (unsigned int entry_count) { size_t size; unsigned int ideal = (entry_count * GNUNET_CONSTANTS_BLOOMFILTER_K) / 4; uint16_t max = 1 << 15; if (entry_count > max) return max; size = 8; while ((size < max) && (size < ideal)) size *= 2; if (size > max) return max; return size; } /** * Construct a bloom filter that would filter out the given * results. * * @param bf_mutator mutation value to use * @param seen_results results already seen * @param seen_results_count number of entries in 'seen_results' * @return NULL if seen_results_count is 0, otherwise a BF * that would match the given results. */ struct GNUNET_CONTAINER_BloomFilter * GNUNET_BLOCK_construct_bloomfilter (int32_t bf_mutator, const GNUNET_HashCode * seen_results, unsigned int seen_results_count) { struct GNUNET_CONTAINER_BloomFilter *bf; GNUNET_HashCode mhash; unsigned int i; size_t nsize; nsize = compute_bloomfilter_size (seen_results_count); bf = GNUNET_CONTAINER_bloomfilter_init (NULL, nsize, GNUNET_CONSTANTS_BLOOMFILTER_K); for (i = 0; i < seen_results_count; i++) { GNUNET_BLOCK_mingle_hash (&seen_results[i], bf_mutator, &mhash); GNUNET_CONTAINER_bloomfilter_add (bf, &mhash); } return bf; } /* end of block.c */ gnunet-0.9.3/src/block/plugin_block_test.c0000644000175000017500000001065711760502551015513 00000000000000/* This file is part of GNUnet (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file block/plugin_block_test.c * @brief block plugin to test the DHT as a simple key-value store; * this plugin simply accepts any (new) response for any key * @author Christian Grothoff */ #include "platform.h" #include "gnunet_block_plugin.h" #define DEBUG_TEST GNUNET_EXTRA_LOGGING /** * Number of bits we set per entry in the bloomfilter. * Do not change! */ #define BLOOMFILTER_K 16 /** * Function called to validate a reply or a request. For * request evaluation, simply pass "NULL" for the reply_block. * * @param cls closure * @param type block type * @param query original query (hash) * @param bf pointer to bloom filter associated with query; possibly updated (!) * @param bf_mutator mutation value for bf * @param xquery extrended query data (can be NULL, depending on type) * @param xquery_size number of bytes in xquery * @param reply_block response to validate * @param reply_block_size number of bytes in reply block * @return characterization of result */ static enum GNUNET_BLOCK_EvaluationResult block_plugin_test_evaluate (void *cls, enum GNUNET_BLOCK_Type type, const GNUNET_HashCode * query, struct GNUNET_CONTAINER_BloomFilter **bf, int32_t bf_mutator, const void *xquery, size_t xquery_size, const void *reply_block, size_t reply_block_size) { GNUNET_HashCode chash; GNUNET_HashCode mhash; if (type != GNUNET_BLOCK_TYPE_TEST) return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; if (xquery_size != 0) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; } if (NULL == reply_block) return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; if (NULL != bf) { GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash); GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash); if (NULL != *bf) { if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash)) return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE; } else { *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, BLOOMFILTER_K); } GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash); } return GNUNET_BLOCK_EVALUATION_OK_MORE; } /** * Function called to obtain the key for a block. * * @param cls closure * @param type block type * @param block block to get the key for * @param block_size number of bytes in block * @param key set to the key (query) for the given block * @return GNUNET_OK on success, GNUNET_SYSERR if type not supported * (or if extracting a key from a block of this type does not work) */ static int block_plugin_test_get_key (void *cls, enum GNUNET_BLOCK_Type type, const void *block, size_t block_size, GNUNET_HashCode * key) { /* always fails since there is no fixed relationship between * keys and values for test values */ return GNUNET_SYSERR; } /** * Entry point for the plugin. */ void * libgnunet_plugin_block_test_init (void *cls) { static enum GNUNET_BLOCK_Type types[] = { GNUNET_BLOCK_TYPE_TEST, GNUNET_BLOCK_TYPE_ANY /* end of list */ }; struct GNUNET_BLOCK_PluginFunctions *api; api = GNUNET_malloc (sizeof (struct GNUNET_BLOCK_PluginFunctions)); api->evaluate = &block_plugin_test_evaluate; api->get_key = &block_plugin_test_get_key; api->types = types; return api; } /** * Exit point from the plugin. */ void * libgnunet_plugin_block_test_done (void *cls) { struct GNUNET_TRANSPORT_PluginFunctions *api = cls; GNUNET_free (api); return NULL; } /* end of plugin_block_test.c */ gnunet-0.9.3/src/block/Makefile.in0000644000175000017500000006242111762217210013676 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ check_PROGRAMS = test_block$(EXEEXT) subdir = src/block DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" LTLIBRARIES = $(lib_LTLIBRARIES) $(plugin_LTLIBRARIES) libgnunet_plugin_block_template_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_libgnunet_plugin_block_template_la_OBJECTS = \ plugin_block_template.lo libgnunet_plugin_block_template_la_OBJECTS = \ $(am_libgnunet_plugin_block_template_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunet_plugin_block_template_la_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libgnunet_plugin_block_template_la_LDFLAGS) $(LDFLAGS) -o $@ am_libgnunet_plugin_block_test_la_OBJECTS = plugin_block_test.lo libgnunet_plugin_block_test_la_OBJECTS = \ $(am_libgnunet_plugin_block_test_la_OBJECTS) libgnunet_plugin_block_test_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) \ $(libgnunet_plugin_block_test_la_LDFLAGS) $(LDFLAGS) -o $@ am_libgnunetblock_la_OBJECTS = block.lo libgnunetblock_la_OBJECTS = $(am_libgnunetblock_la_OBJECTS) libgnunetblock_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetblock_la_LDFLAGS) $(LDFLAGS) \ -o $@ am_test_block_OBJECTS = test_block.$(OBJEXT) test_block_OBJECTS = $(am_test_block_OBJECTS) test_block_DEPENDENCIES = $(top_builddir)/src/block/libgnunetblock.la \ $(top_builddir)/src/util/libgnunetutil.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunet_plugin_block_template_la_SOURCES) \ $(libgnunet_plugin_block_test_la_SOURCES) \ $(libgnunetblock_la_SOURCES) $(test_block_SOURCES) DIST_SOURCES = $(libgnunet_plugin_block_template_la_SOURCES) \ $(libgnunet_plugin_block_test_la_SOURCES) \ $(libgnunetblock_la_SOURCES) $(test_block_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include plugindir = $(libdir)/gnunet @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage lib_LTLIBRARIES = libgnunetblock.la plugin_LTLIBRARIES = \ libgnunet_plugin_block_template.la \ libgnunet_plugin_block_test.la libgnunet_plugin_block_template_la_SOURCES = \ plugin_block_template.c libgnunet_plugin_block_template_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_block_template_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_block_test_la_SOURCES = \ plugin_block_test.c libgnunet_plugin_block_test_la_LIBADD = \ $(top_builddir)/src/block/libgnunetblock.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_block_test_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_block_test_la_DEPENDENCIES = \ libgnunetblock.la libgnunetblock_la_SOURCES = \ block.c libgnunetblock_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la libgnunetblock_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la libgnunetblock_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:0:0 #TESTS = $(check_PROGRAMS) test_block_SOURCES = \ test_block.c test_block_LDADD = \ $(top_builddir)/src/block/libgnunetblock.la \ $(top_builddir)/src/util/libgnunetutil.la all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/block/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/block/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ } uninstall-pluginLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ done clean-pluginLTLIBRARIES: -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunet_plugin_block_template.la: $(libgnunet_plugin_block_template_la_OBJECTS) $(libgnunet_plugin_block_template_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_block_template_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_block_template_la_OBJECTS) $(libgnunet_plugin_block_template_la_LIBADD) $(LIBS) libgnunet_plugin_block_test.la: $(libgnunet_plugin_block_test_la_OBJECTS) $(libgnunet_plugin_block_test_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_block_test_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_block_test_la_OBJECTS) $(libgnunet_plugin_block_test_la_LIBADD) $(LIBS) libgnunetblock.la: $(libgnunetblock_la_OBJECTS) $(libgnunetblock_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetblock_la_LINK) -rpath $(libdir) $(libgnunetblock_la_OBJECTS) $(libgnunetblock_la_LIBADD) $(LIBS) clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list test_block$(EXEEXT): $(test_block_OBJECTS) $(test_block_DEPENDENCIES) @rm -f test_block$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_block_OBJECTS) $(test_block_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/block.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_block_template.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_block_test.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_block.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) check: check-am all-am: Makefile $(LTLIBRARIES) installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool clean-pluginLTLIBRARIES mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pluginLTLIBRARIES install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES uninstall-pluginLTLIBRARIES .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean \ clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool clean-pluginLTLIBRARIES ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libLTLIBRARIES install-man install-pdf install-pdf-am \ install-pluginLTLIBRARIES install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-libLTLIBRARIES uninstall-pluginLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/block/plugin_block_template.c0000644000175000017500000000671511760502551016347 00000000000000/* This file is part of GNUnet (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file block/plugin_block_template.c * @brief template for a block plugin * @author Christian Grothoff */ #include "platform.h" #include "gnunet_block_plugin.h" #define DEBUG_TEMPLATE GNUNET_EXTRA_LOGGING /** * Function called to validate a reply or a request. For * request evaluation, simply pass "NULL" for the reply_block. * * @param cls closure * @param type block type * @param query original query (hash) * @param bf pointer to bloom filter associated with query; possibly updated (!) * @param bf_mutator mutation value for bf * @param xquery extrended query data (can be NULL, depending on type) * @param xquery_size number of bytes in xquery * @param reply_block response to validate * @param reply_block_size number of bytes in reply block * @return characterization of result */ static enum GNUNET_BLOCK_EvaluationResult block_plugin_template_evaluate (void *cls, enum GNUNET_BLOCK_Type type, const GNUNET_HashCode * query, struct GNUNET_CONTAINER_BloomFilter **bf, int32_t bf_mutator, const void *xquery, size_t xquery_size, const void *reply_block, size_t reply_block_size) { return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; } /** * Function called to obtain the key for a block. * * @param cls closure * @param type block type * @param block block to get the key for * @param block_size number of bytes in block * @param key set to the key (query) for the given block * @return GNUNET_OK on success, GNUNET_SYSERR if type not supported * (or if extracting a key from a block of this type does not work) */ static int block_plugin_template_get_key (void *cls, enum GNUNET_BLOCK_Type type, const void *block, size_t block_size, GNUNET_HashCode * key) { return GNUNET_SYSERR; } /** * Entry point for the plugin. */ void * libgnunet_plugin_block_template_init (void *cls) { static enum GNUNET_BLOCK_Type types[] = { /* FIXME: insert supported block types here */ GNUNET_BLOCK_TYPE_ANY /* end of list */ }; struct GNUNET_BLOCK_PluginFunctions *api; api = GNUNET_malloc (sizeof (struct GNUNET_BLOCK_PluginFunctions)); api->evaluate = &block_plugin_template_evaluate; api->get_key = &block_plugin_template_get_key; api->types = types; return api; } /** * Exit point from the plugin. */ void * libgnunet_plugin_block_template_done (void *cls) { struct GNUNET_TRANSPORT_PluginFunctions *api = cls; GNUNET_free (api); return NULL; } /* end of plugin_block_template.c */ gnunet-0.9.3/src/mesh/0000755000175000017500000000000011763406750011560 500000000000000gnunet-0.9.3/src/mesh/mesh_api.c0000644000175000017500000014204011760502551013423 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file mesh/mesh_api.c * @brief mesh api: client implementation of mesh service * @author Bartlomiej Polot * * STRUCTURE: * - CONSTANTS * - DATA STRUCTURES * - AUXILIARY FUNCTIONS * - RECEIVE HANDLERS * - SEND FUNCTIONS * - API CALL DEFINITIONS */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_client_lib.h" #include "gnunet_util_lib.h" #include "gnunet_peer_lib.h" #include "gnunet_mesh_service.h" #include "mesh.h" #include "mesh_protocol.h" #define LOG(kind,...) GNUNET_log_from (kind, "mesh-api",__VA_ARGS__) /******************************************************************************/ /************************ DATA STRUCTURES ****************************/ /******************************************************************************/ /** * Transmission queue to the service */ struct GNUNET_MESH_TransmitHandle { /** * Double Linked list */ struct GNUNET_MESH_TransmitHandle *next; /** * Double Linked list */ struct GNUNET_MESH_TransmitHandle *prev; /** * Tunnel this message is sent on / for (may be NULL for control messages). */ struct GNUNET_MESH_Tunnel *tunnel; /** * Callback to obtain the message to transmit, or NULL if we * got the message in 'data'. Notice that messages built * by 'notify' need to be encapsulated with information about * the 'target'. */ GNUNET_CONNECTION_TransmitReadyNotify notify; /** * Closure for 'notify' */ void *notify_cls; /** * How long is this message valid. Once the timeout has been * reached, the message must no longer be sent. If this * is a message with a 'notify' callback set, the 'notify' * function should be called with 'buf' NULL and size 0. */ struct GNUNET_TIME_Absolute timeout; /** * Task triggering a timeout, can be NO_TASK if the timeout is FOREVER. */ GNUNET_SCHEDULER_TaskIdentifier timeout_task; /** * Priority of the message. The queue is sorted by priority, * control messages have the maximum priority (UINT32_MAX). */ uint32_t priority; /** * Target of the message, 0 for multicast. This field * is only valid if 'notify' is non-NULL. */ GNUNET_PEER_Id target; /** * Size of 'data' -- or the desired size of 'notify' if 'data' is NULL. */ size_t size; }; /** * Opaque handle to the service. */ struct GNUNET_MESH_Handle { /** * Handle to the server connection, to send messages later */ struct GNUNET_CLIENT_Connection *client; /** * Set of handlers used for processing incoming messages in the tunnels */ const struct GNUNET_MESH_MessageHandler *message_handlers; /** * Set of applications that should be claimed to be offered at this node. * Note that this is just informative, the appropiate handlers must be * registered independently and the mapping is up to the developer of the * client application. */ const GNUNET_MESH_ApplicationType *applications; /** * Double linked list of the tunnels this client is connected to. */ struct GNUNET_MESH_Tunnel *tunnels_head; struct GNUNET_MESH_Tunnel *tunnels_tail; /** * Callback for inbound tunnel creation */ GNUNET_MESH_InboundTunnelNotificationHandler *new_tunnel; /** * Callback for inbound tunnel disconnection */ GNUNET_MESH_TunnelEndHandler *cleaner; /** * Handle to cancel pending transmissions in case of disconnection */ struct GNUNET_CLIENT_TransmitHandle *th; /** * Closure for all the handlers given by the client */ void *cls; /** * Messages to send to the service */ struct GNUNET_MESH_TransmitHandle *th_head; struct GNUNET_MESH_TransmitHandle *th_tail; /** * tid of the next tunnel to create (to avoid reusing IDs often) */ MESH_TunnelNumber next_tid; unsigned int n_handlers; unsigned int n_applications; unsigned int max_queue_size; /** * Have we started the task to receive messages from the service * yet? We do this after we send the 'MESH_LOCAL_CONNECT' message. */ int in_receive; /** * Number of packets queued */ unsigned int npackets; /** * Configuration given by the client, in case of reconnection */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Time to the next reconnect in case one reconnect fails */ struct GNUNET_TIME_Relative reconnect_time; /** * Task for trying to reconnect. */ GNUNET_SCHEDULER_TaskIdentifier reconnect_task; }; /** * Description of a peer */ struct GNUNET_MESH_Peer { /** * ID of the peer in short form */ GNUNET_PEER_Id id; /** * Tunnel this peer belongs to */ struct GNUNET_MESH_Tunnel *t; /** * Flag indicating whether service has informed about its connection */ int connected; }; /** * Opaque handle to a tunnel. */ struct GNUNET_MESH_Tunnel { /** * DLL */ struct GNUNET_MESH_Tunnel *next; struct GNUNET_MESH_Tunnel *prev; /** * Callback to execute when peers connect to the tunnel */ GNUNET_MESH_PeerConnectHandler connect_handler; /** * Callback to execute when peers disconnect from the tunnel */ GNUNET_MESH_PeerDisconnectHandler disconnect_handler; /** * Closure for the connect/disconnect handlers */ void *cls; /** * Handle to the mesh this tunnel belongs to */ struct GNUNET_MESH_Handle *mesh; /** * Local ID of the tunnel */ MESH_TunnelNumber tid; /** * Owner of the tunnel. 0 if the tunnel is the local client. */ GNUNET_PEER_Id owner; /** * All peers added to the tunnel */ struct GNUNET_MESH_Peer **peers; /** * List of application types that have been requested for this tunnel */ GNUNET_MESH_ApplicationType *apps; /** * Any data the caller wants to put in here */ void *ctx; /** * Number of peers added to the tunnel */ unsigned int npeers; /** * Number of packets queued in this tunnel */ unsigned int npackets; /** * Number of applications requested this tunnel */ unsigned int napps; }; /******************************************************************************/ /*********************** AUXILIARY FUNCTIONS *************************/ /******************************************************************************/ /** * Get the tunnel handler for the tunnel specified by id from the given handle * @param h Mesh handle * @param tid ID of the wanted tunnel * @return handle to the required tunnel or NULL if not found */ static struct GNUNET_MESH_Tunnel * retrieve_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid) { struct GNUNET_MESH_Tunnel *t; t = h->tunnels_head; while (t != NULL) { if (t->tid == tid) return t; t = t->next; } return NULL; } /** * Create a new tunnel and insert it in the tunnel list of the mesh handle * @param h Mesh handle * @param tid desired tid of the tunnel, 0 to assign one automatically * @return handle to the created tunnel */ static struct GNUNET_MESH_Tunnel * create_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid) { struct GNUNET_MESH_Tunnel *t; t = GNUNET_malloc (sizeof (struct GNUNET_MESH_Tunnel)); GNUNET_CONTAINER_DLL_insert (h->tunnels_head, h->tunnels_tail, t); t->mesh = h; if (0 == tid) { t->tid = h->next_tid; while (NULL != retrieve_tunnel (h, h->next_tid)) { h->next_tid++; h->next_tid &= ~GNUNET_MESH_LOCAL_TUNNEL_ID_SERV; h->next_tid |= GNUNET_MESH_LOCAL_TUNNEL_ID_CLI; } } else { t->tid = tid; } return t; } /** * Destroy the specified tunnel. * - Destroys all peers, calling the disconnect callback on each if needed * - Cancels all outgoing traffic for that tunnel, calling respective notifys * - Calls cleaner if tunnel was inbound * - Frees all memory used * * @param t Pointer to the tunnel. * @param call_cleaner Whether to call the cleaner handler. * * @return Handle to the required tunnel or NULL if not found. */ static void destroy_tunnel (struct GNUNET_MESH_Tunnel *t, int call_cleaner) { struct GNUNET_MESH_Handle *h; struct GNUNET_PeerIdentity pi; struct GNUNET_MESH_TransmitHandle *th; struct GNUNET_MESH_TransmitHandle *next; unsigned int i; if (NULL == t) { GNUNET_break (0); return; } h = t->mesh; /* disconnect all peers */ GNUNET_CONTAINER_DLL_remove (h->tunnels_head, h->tunnels_tail, t); for (i = 0; i < t->npeers; i++) { if ( (NULL != t->disconnect_handler) && t->peers[i]->connected) { GNUNET_PEER_resolve (t->peers[i]->id, &pi); t->disconnect_handler (t->cls, &pi); } GNUNET_PEER_change_rc (t->peers[i]->id, -1); GNUNET_free (t->peers[i]); } /* signal tunnel destruction */ if ( (NULL != h->cleaner) && (0 != t->owner) && (GNUNET_YES == call_cleaner) ) h->cleaner (h->cls, t, t->ctx); /* check that clients did not leave messages behind in the queue */ for (th = h->th_head; NULL != th; th = next) { next = th->next; if (th->tunnel != t) continue; /* Clients should have aborted their requests already. * Management traffic should be ok, as clients can't cancel that */ GNUNET_break (NULL == th->notify); GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th); /* clean up request */ if (GNUNET_SCHEDULER_NO_TASK != th->timeout_task) GNUNET_SCHEDULER_cancel (th->timeout_task); GNUNET_free (th); } /* if there are no more pending requests with mesh service, cancel active request */ /* Note: this should be unnecessary... */ if ( (NULL == h->th_head) && (NULL != h->th)) { GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); h->th = NULL; } if (t->npeers > 0) GNUNET_free (t->peers); if (0 != t->owner) GNUNET_PEER_change_rc (t->owner, -1); if (0 != t->napps && t->apps) GNUNET_free (t->apps); GNUNET_free (t); return; } /** * Get the peer descriptor for the peer with id from the given tunnel * @param t Tunnel handle * @param id Short form ID of the wanted peer * @return handle to the requested peer or NULL if not found */ static struct GNUNET_MESH_Peer * retrieve_peer (struct GNUNET_MESH_Tunnel *t, GNUNET_PEER_Id id) { unsigned int i; for (i = 0; i < t->npeers; i++) if (t->peers[i]->id == id) return t->peers[i]; return NULL; } /** * Add a peer into a tunnel * @param t Tunnel handle * @param pi Full ID of the new peer * @return handle to the newly created peer */ static struct GNUNET_MESH_Peer * add_peer_to_tunnel (struct GNUNET_MESH_Tunnel *t, const struct GNUNET_PeerIdentity *pi) { struct GNUNET_MESH_Peer *p; GNUNET_PEER_Id id; if (0 != t->owner) { GNUNET_break (0); return NULL; } id = GNUNET_PEER_intern (pi); p = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer)); p->id = id; p->t = t; GNUNET_array_append (t->peers, t->npeers, p); return p; } /** * Remove a peer from a tunnel * @param p Peer handle */ static void remove_peer_from_tunnel (struct GNUNET_MESH_Peer *p) { unsigned int i; for (i = 0; i < p->t->npeers; i++) { if (p->t->peers[i] == p) break; } if (i == p->t->npeers) { GNUNET_break (0); return; } p->t->peers[i] = p->t->peers[p->t->npeers - 1]; GNUNET_array_grow (p->t->peers, p->t->npeers, p->t->npeers - 1); } /** * Notify client that the transmission has timed out * @param cls closure * @param tc task context */ static void timeout_transmission (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_MESH_TransmitHandle *th = cls; struct GNUNET_MESH_Handle *mesh; mesh = th->tunnel->mesh; GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th); if (th->notify != NULL) th->notify (th->notify_cls, 0, NULL); GNUNET_free (th); if ((NULL == mesh->th_head) && (NULL != mesh->th)) { /* queue empty, no point in asking for transmission */ GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th); mesh->th = NULL; } } /** * Add a transmit handle to the transmission queue by priority and set the * timeout if needed. * * @param h mesh handle with the queue head and tail * @param th handle to the packet to be transmitted */ static void add_to_queue (struct GNUNET_MESH_Handle *h, struct GNUNET_MESH_TransmitHandle *th) { struct GNUNET_MESH_TransmitHandle *p; p = h->th_head; while ((NULL != p) && (th->priority <= p->priority)) p = p->next; if (NULL == p) p = h->th_tail; else p = p->prev; GNUNET_CONTAINER_DLL_insert_after (h->th_head, h->th_tail, p, th); if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value == th->timeout.abs_value) return; th->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (th->timeout), &timeout_transmission, th); } /** * Auxiliary function to send an already constructed packet to the service. * Takes care of creating a new queue element, copying the message and * calling the tmt_rdy function if necessary. * * @param h mesh handle * @param msg message to transmit * @param tunnel tunnel this send is related to (NULL if N/A) */ static void send_packet (struct GNUNET_MESH_Handle *h, const struct GNUNET_MessageHeader *msg, struct GNUNET_MESH_Tunnel *tunnel); /** * Reconnect callback: tries to reconnect again after a failer previous * reconnecttion * @param cls closure (mesh handle) * @param tc task context */ static void reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Send a connect packet to the service with the applications and types * requested by the user. * * @param h The mesh handle. * */ static void send_connect (struct GNUNET_MESH_Handle *h) { size_t size; size = sizeof (struct GNUNET_MESH_ClientConnect); size += h->n_applications * sizeof (GNUNET_MESH_ApplicationType); size += h->n_handlers * sizeof (uint16_t); { char buf[size] GNUNET_ALIGN; struct GNUNET_MESH_ClientConnect *msg; GNUNET_MESH_ApplicationType *apps; uint16_t napps; uint16_t *types; uint16_t ntypes; /* build connection packet */ msg = (struct GNUNET_MESH_ClientConnect *) buf; msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT); msg->header.size = htons (size); apps = (GNUNET_MESH_ApplicationType *) &msg[1]; for (napps = 0; napps < h->n_applications; napps++) { apps[napps] = htonl (h->applications[napps]); LOG (GNUNET_ERROR_TYPE_DEBUG, " app %u\n", h->applications[napps]); } types = (uint16_t *) & apps[napps]; for (ntypes = 0; ntypes < h->n_handlers; ntypes++) types[ntypes] = htons (h->message_handlers[ntypes].type); msg->applications = htons (napps); msg->types = htons (ntypes); LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending %lu bytes long message %d types and %d apps\n", ntohs (msg->header.size), ntypes, napps); send_packet (h, &msg->header, NULL); } } /** * Reconnect to the service, retransmit all infomation to try to restore the * original state. * * @param h handle to the mesh * * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...) */ static int do_reconnect (struct GNUNET_MESH_Handle *h) { struct GNUNET_MESH_Tunnel *t; unsigned int i; LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n"); LOG (GNUNET_ERROR_TYPE_DEBUG, "******* RECONNECT *******\n"); LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n"); h->in_receive = GNUNET_NO; /* disconnect */ if (NULL != h->th) { GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); h->th = NULL; } if (NULL != h->client) { GNUNET_CLIENT_disconnect (h->client); } /* connect again */ h->client = GNUNET_CLIENT_connect ("mesh", h->cfg); if (h->client == NULL) { h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_time, &reconnect_cbk, h); h->reconnect_time = GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS, GNUNET_TIME_relative_multiply (h->reconnect_time, 2)); LOG (GNUNET_ERROR_TYPE_DEBUG, " Next retry in %sms\n", GNUNET_TIME_relative_to_string (h->reconnect_time)); GNUNET_break (0); return GNUNET_NO; } else { h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS; } send_connect (h); /* Rebuild all tunnels */ for (t = h->tunnels_head; NULL != t; t = t->next) { struct GNUNET_MESH_TunnelMessage tmsg; struct GNUNET_MESH_PeerControl pmsg; if (t->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) { /* Tunnel was created by service (incoming tunnel) */ /* TODO: Notify service of missing tunnel, to request * creator to recreate path (find a path to him via DHT?) */ continue; } tmsg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE); tmsg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage)); tmsg.tunnel_id = htonl (t->tid); send_packet (h, &tmsg.header, t); pmsg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl)); pmsg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD); pmsg.tunnel_id = htonl (t->tid); /* Reconnect all peers */ for (i = 0; i < t->npeers; i++) { GNUNET_PEER_resolve (t->peers[i]->id, &pmsg.peer); if (NULL != t->disconnect_handler && t->peers[i]->connected) t->disconnect_handler (t->cls, &pmsg.peer); /* If the tunnel was "by type", dont connect individual peers */ if (0 == t->napps) send_packet (t->mesh, &pmsg.header, t); } /* Reconnect all types, if any */ for (i = 0; i < t->napps; i++) { struct GNUNET_MESH_ConnectPeerByType msg; msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectPeerByType)); msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD_BY_TYPE); msg.tunnel_id = htonl (t->tid); msg.type = htonl (t->apps[i]); send_packet (t->mesh, &msg.header, t); } } return GNUNET_YES; } /** * Reconnect callback: tries to reconnect again after a failer previous * reconnecttion * @param cls closure (mesh handle) * @param tc task context */ static void reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_MESH_Handle *h = cls; h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; do_reconnect (h); } /** * Reconnect to the service, retransmit all infomation to try to restore the * original state. * * @param h handle to the mesh * * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...) */ static void reconnect (struct GNUNET_MESH_Handle *h) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Requested RECONNECT\n"); if (GNUNET_SCHEDULER_NO_TASK == h->reconnect_task) h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_time, &reconnect_cbk, h); } /******************************************************************************/ /*********************** RECEIVE HANDLERS ****************************/ /******************************************************************************/ /** * Process the new tunnel notification and add it to the tunnels in the handle * * @param h The mesh handle * @param msg A message with the details of the new incoming tunnel */ static void process_tunnel_created (struct GNUNET_MESH_Handle *h, const struct GNUNET_MESH_TunnelNotification *msg) { struct GNUNET_MESH_Tunnel *t; MESH_TunnelNumber tid; tid = ntohl (msg->tunnel_id); if (tid < GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) { GNUNET_break (0); return; } if (NULL != h->new_tunnel) { struct GNUNET_ATS_Information atsi; t = create_tunnel (h, tid); t->owner = GNUNET_PEER_intern (&msg->peer); t->npeers = 1; t->peers = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer *)); t->peers[0] = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer)); t->peers[0]->t = t; t->peers[0]->connected = 1; t->peers[0]->id = t->owner; GNUNET_PEER_change_rc (t->owner, 1); t->mesh = h; t->tid = tid; atsi.type = 0; atsi.value = 0; t->ctx = h->new_tunnel (h->cls, t, &msg->peer, &atsi); LOG (GNUNET_ERROR_TYPE_DEBUG, "new incoming tunnel %X\n", t->tid); } else { struct GNUNET_MESH_TunnelMessage d_msg; LOG (GNUNET_ERROR_TYPE_DEBUG, "No handler for incoming tunnels\n"); d_msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY); d_msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage)); d_msg.tunnel_id = msg->tunnel_id; send_packet (h, &d_msg.header, NULL); } return; } /** * Process the tunnel destroy notification and free associated resources * * @param h The mesh handle * @param msg A message with the details of the tunnel being destroyed */ static void process_tunnel_destroy (struct GNUNET_MESH_Handle *h, const struct GNUNET_MESH_TunnelMessage *msg) { struct GNUNET_MESH_Tunnel *t; MESH_TunnelNumber tid; tid = ntohl (msg->tunnel_id); t = retrieve_tunnel (h, tid); if (NULL == t) { return; } if (0 == t->owner) { GNUNET_break (0); } LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel %X destroyed\n", t->tid); destroy_tunnel (t, GNUNET_YES); return; } /** * Process the new peer event and notify the upper level of it * * @param h The mesh handle * @param msg A message with the details of the peer event */ static void process_peer_event (struct GNUNET_MESH_Handle *h, const struct GNUNET_MESH_PeerControl *msg) { struct GNUNET_MESH_Tunnel *t; struct GNUNET_MESH_Peer *p; struct GNUNET_ATS_Information atsi; GNUNET_PEER_Id id; uint16_t size; LOG (GNUNET_ERROR_TYPE_DEBUG, "processig peer event\n"); size = ntohs (msg->header.size); if (size != sizeof (struct GNUNET_MESH_PeerControl)) { GNUNET_break (0); return; } t = retrieve_tunnel (h, ntohl (msg->tunnel_id)); if (NULL == t) { GNUNET_break (0); return; } id = GNUNET_PEER_search (&msg->peer); if ((p = retrieve_peer (t, id)) == NULL) p = add_peer_to_tunnel (t, &msg->peer); if (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD == ntohs (msg->header.type)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "adding peer\n"); if (NULL != t->connect_handler) { atsi.type = 0; atsi.value = 0; t->connect_handler (t->cls, &msg->peer, &atsi); } p->connected = 1; } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "removing peer\n"); if (NULL != t->disconnect_handler && p->connected) { t->disconnect_handler (t->cls, &msg->peer); } remove_peer_from_tunnel (p); GNUNET_free (p); } LOG (GNUNET_ERROR_TYPE_DEBUG, "processing peer event END\n"); } /** * Process the incoming data packets * * @param h The mesh handle * @param message A message encapsulating the data * * @return GNUNET_YES if everything went fine * GNUNET_NO if client closed connection (h no longer valid) */ static int process_incoming_data (struct GNUNET_MESH_Handle *h, const struct GNUNET_MessageHeader *message) { const struct GNUNET_MessageHeader *payload; const struct GNUNET_MESH_MessageHandler *handler; const struct GNUNET_PeerIdentity *peer; struct GNUNET_MESH_Unicast *ucast; struct GNUNET_MESH_Multicast *mcast; struct GNUNET_MESH_ToOrigin *to_orig; struct GNUNET_MESH_Tunnel *t; unsigned int i; uint16_t type; LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a data message!\n"); type = ntohs (message->type); switch (type) { case GNUNET_MESSAGE_TYPE_MESH_UNICAST: ucast = (struct GNUNET_MESH_Unicast *) message; t = retrieve_tunnel (h, ntohl (ucast->tid)); payload = (struct GNUNET_MessageHeader *) &ucast[1]; peer = &ucast->oid; LOG (GNUNET_ERROR_TYPE_DEBUG, " ucast on tunnel %s [%x]\n", GNUNET_i2s (peer), ntohl (ucast->tid)); break; case GNUNET_MESSAGE_TYPE_MESH_MULTICAST: mcast = (struct GNUNET_MESH_Multicast *) message; t = retrieve_tunnel (h, ntohl (mcast->tid)); payload = (struct GNUNET_MessageHeader *) &mcast[1]; peer = &mcast->oid; LOG (GNUNET_ERROR_TYPE_DEBUG, " mcast on tunnel %s [%x]\n", GNUNET_i2s (peer), ntohl (mcast->tid)); break; case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN: to_orig = (struct GNUNET_MESH_ToOrigin *) message; t = retrieve_tunnel (h, ntohl (to_orig->tid)); payload = (struct GNUNET_MessageHeader *) &to_orig[1]; peer = &to_orig->sender; LOG (GNUNET_ERROR_TYPE_DEBUG, " torig on tunnel %s [%x]\n", GNUNET_i2s (peer), ntohl (to_orig->tid)); break; default: GNUNET_break (0); return GNUNET_YES; } if (NULL == t) { /* Tunnel was ignored, probably service didn't get it yet */ return GNUNET_YES; } type = ntohs (payload->type); for (i = 0; i < h->n_handlers; i++) { handler = &h->message_handlers[i]; if (handler->type == type) { struct GNUNET_ATS_Information atsi; atsi.type = 0; atsi.value = 0; if (GNUNET_OK != handler->callback (h->cls, t, &t->ctx, peer, payload, &atsi)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "MESH: callback caused disconnection\n"); GNUNET_MESH_disconnect (h); return GNUNET_NO; } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "MESH: callback completed successfully\n"); } } } return GNUNET_YES; } /** * Function to process all messages received from the service * * @param cls closure * @param msg message received, NULL on timeout or fatal error */ static void msg_received (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_MESH_Handle *h = cls; if (msg == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Received NULL msg\n"); reconnect (h); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "received a message type %hu from MESH\n", ntohs (msg->type)); switch (ntohs (msg->type)) { /* Notify of a new incoming tunnel */ case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE: process_tunnel_created (h, (struct GNUNET_MESH_TunnelNotification *) msg); break; /* Notify of a tunnel disconnection */ case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY: process_tunnel_destroy (h, (struct GNUNET_MESH_TunnelMessage *) msg); break; /* Notify of a new peer or a peer disconnect in the tunnel */ case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD: case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL: process_peer_event (h, (struct GNUNET_MESH_PeerControl *) msg); break; /* Notify of a new data packet in the tunnel */ case GNUNET_MESSAGE_TYPE_MESH_UNICAST: case GNUNET_MESSAGE_TYPE_MESH_MULTICAST: case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN: if (GNUNET_NO == process_incoming_data (h, msg)) return; break; /* We shouldn't get any other packages, log and ignore */ default: LOG (GNUNET_ERROR_TYPE_WARNING, "MESH: unsolicited message form service (type %d)\n", ntohs (msg->type)); } LOG (GNUNET_ERROR_TYPE_DEBUG, "message processed\n"); GNUNET_CLIENT_receive (h->client, &msg_received, h, GNUNET_TIME_UNIT_FOREVER_REL); } /******************************************************************************/ /************************ SEND FUNCTIONS ****************************/ /******************************************************************************/ /** * Function called to send a message to the service. * "buf" will be NULL and "size" zero if the socket was closed for writing in * the meantime. * * @param cls closure, the mesh handle * @param size number of bytes available in buf * @param buf where the callee should write the connect message * @return number of bytes written to buf */ static size_t send_callback (void *cls, size_t size, void *buf) { struct GNUNET_MESH_Handle *h = cls; struct GNUNET_MESH_TransmitHandle *th; char *cbuf = buf; size_t tsize; size_t psize; LOG (GNUNET_ERROR_TYPE_DEBUG, "Send packet() Buffer %u\n", size); h->th = NULL; if ((0 == size) || (NULL == buf)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Received NULL callback\n"); reconnect (h); return 0; } tsize = 0; while ((NULL != (th = h->th_head)) && (size >= th->size)) { if (NULL != th->notify) { if (th->tunnel->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) { /* traffic to origin */ struct GNUNET_MESH_ToOrigin to; struct GNUNET_MessageHeader *mh; GNUNET_assert (size >= th->size); mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (to)]; psize = th->notify (th->notify_cls, size - sizeof (to), mh); LOG (GNUNET_ERROR_TYPE_DEBUG, " to origin, type %u\n", ntohs (mh->type)); if (psize > 0) { psize += sizeof (to); GNUNET_assert (size >= psize); to.header.size = htons (psize); to.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN); to.tid = htonl (th->tunnel->tid); memset (&to.oid, 0, sizeof (struct GNUNET_PeerIdentity)); memset (&to.sender, 0, sizeof (struct GNUNET_PeerIdentity)); memcpy (cbuf, &to, sizeof (to)); } } else if (th->target == 0) { /* multicast */ struct GNUNET_MESH_Multicast mc; struct GNUNET_MessageHeader *mh; GNUNET_assert (size >= th->size); mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (mc)]; psize = th->notify (th->notify_cls, size - sizeof (mc), mh); LOG (GNUNET_ERROR_TYPE_DEBUG, " multicast, type %u\n", ntohs (mh->type)); if (psize > 0) { psize += sizeof (mc); GNUNET_assert (size >= psize); mc.header.size = htons (psize); mc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_MULTICAST); mc.tid = htonl (th->tunnel->tid); mc.mid = 0; mc.ttl = 0; memset (&mc.oid, 0, sizeof (struct GNUNET_PeerIdentity)); memcpy (cbuf, &mc, sizeof (mc)); } } else { /* unicast */ struct GNUNET_MESH_Unicast uc; struct GNUNET_MessageHeader *mh; GNUNET_assert (size >= th->size); mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (uc)]; psize = th->notify (th->notify_cls, size - sizeof (uc), mh); LOG (GNUNET_ERROR_TYPE_DEBUG, " unicast, type %u\n", ntohs (mh->type)); if (psize > 0) { psize += sizeof (uc); GNUNET_assert (size >= psize); uc.header.size = htons (psize); uc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_UNICAST); uc.tid = htonl (th->tunnel->tid); memset (&uc.oid, 0, sizeof (struct GNUNET_PeerIdentity)); GNUNET_PEER_resolve (th->target, &uc.destination); memcpy (cbuf, &uc, sizeof (uc)); } } } else { memcpy (cbuf, &th[1], th->size); psize = th->size; } if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (th->timeout_task); if (NULL != th->notify) { th->tunnel->mesh->npackets--; th->tunnel->npackets--; } GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th); GNUNET_free (th); cbuf += psize; size -= psize; tsize += psize; } LOG (GNUNET_ERROR_TYPE_DEBUG, " total size: %u\n", tsize); if (NULL != (th = h->th_head)) { LOG (GNUNET_ERROR_TYPE_DEBUG, " next size: %u\n", th->size); if (NULL == h->th) h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, th->size, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &send_callback, h); } LOG (GNUNET_ERROR_TYPE_DEBUG, "Send packet() END\n"); if (GNUNET_NO == h->in_receive) { h->in_receive = GNUNET_YES; GNUNET_CLIENT_receive (h->client, &msg_received, h, GNUNET_TIME_UNIT_FOREVER_REL); } return tsize; } /** * Auxiliary function to send an already constructed packet to the service. * Takes care of creating a new queue element, copying the message and * calling the tmt_rdy function if necessary. * * @param h mesh handle * @param msg message to transmit * @param tunnel tunnel this send is related to (NULL if N/A) */ static void send_packet (struct GNUNET_MESH_Handle *h, const struct GNUNET_MessageHeader *msg, struct GNUNET_MESH_Tunnel *tunnel) { struct GNUNET_MESH_TransmitHandle *th; size_t msize; msize = ntohs (msg->size); th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle) + msize); th->priority = UINT32_MAX; th->timeout = GNUNET_TIME_UNIT_FOREVER_ABS; th->size = msize; th->tunnel = tunnel; memcpy (&th[1], msg, msize); add_to_queue (h, th); if (NULL != h->th) return; h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, msize, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &send_callback, h); } /******************************************************************************/ /********************** API CALL DEFINITIONS *************************/ /******************************************************************************/ /** * Connect to the mesh service. * * @param cfg configuration to use * @param queue_size size of the data message queue, shared among all tunnels * (each tunnel is guaranteed to accept at least one message, * no matter what is the status of other tunnels) * @param cls closure for the various callbacks that follow * (including handlers in the handlers array) * @param new_tunnel function called when an *inbound* tunnel is created * @param cleaner function called when an *inbound* tunnel is destroyed by the * remote peer, it is *not* called if GNUNET_MESH_tunnel_destroy * is called on the tunnel * @param handlers callbacks for messages we care about, NULL-terminated * note that the mesh is allowed to drop notifications about * inbound messages if the client does not process them fast * enough (for this notification type, a bounded queue is used) * @param stypes list of the applications that this client claims to provide * @return handle to the mesh service NULL on error * (in this case, init is never called) */ struct GNUNET_MESH_Handle * GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned int queue_size, void *cls, GNUNET_MESH_InboundTunnelNotificationHandler new_tunnel, GNUNET_MESH_TunnelEndHandler cleaner, const struct GNUNET_MESH_MessageHandler *handlers, const GNUNET_MESH_ApplicationType *stypes) { struct GNUNET_MESH_Handle *h; LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_MESH_connect()\n"); h = GNUNET_malloc (sizeof (struct GNUNET_MESH_Handle)); h->cfg = cfg; h->max_queue_size = queue_size; h->new_tunnel = new_tunnel; h->cleaner = cleaner; h->client = GNUNET_CLIENT_connect ("mesh", cfg); if (h->client == NULL) { GNUNET_break (0); GNUNET_free (h); return NULL; } h->cls = cls; /* FIXME memdup? */ h->applications = stypes; h->message_handlers = handlers; h->next_tid = GNUNET_MESH_LOCAL_TUNNEL_ID_CLI; h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS; h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; /* count handlers and apps, calculate size */ for (h->n_applications = 0; stypes[h->n_applications]; h->n_applications++) ; for (h->n_handlers = 0; handlers[h->n_handlers].type; h->n_handlers++) ; send_connect (h); LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_MESH_connect() END\n"); return h; } /** * Disconnect from the mesh service. All tunnels will be destroyed. All tunnel * disconnect callbacks will be called on any still connected peers, notifying * about their disconnection. The registered inbound tunnel cleaner will be * called should any inbound tunnels still exist. * * @param handle connection to mesh to disconnect */ void GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle) { struct GNUNET_MESH_Tunnel *t; struct GNUNET_MESH_Tunnel *aux; struct GNUNET_MESH_TransmitHandle *th; t = handle->tunnels_head; while (NULL != t) { aux = t->next; if (t->tid < GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) { GNUNET_break (0); LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel %X not destroyed\n", t->tid); } destroy_tunnel (t, GNUNET_YES); t = aux; } while ( (th = handle->th_head) != NULL) { struct GNUNET_MessageHeader *msg; /* Make sure it is an allowed packet (everything else should have been * already canceled). */ GNUNET_break (UINT32_MAX == th->priority); GNUNET_break (NULL == th->notify); msg = (struct GNUNET_MessageHeader *) &th[1]; switch (ntohs(msg->type)) { case GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT: case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY: break; default: GNUNET_break (0); LOG (GNUNET_ERROR_TYPE_DEBUG, "unexpected msg %u\n", ntohs(msg->type)); } GNUNET_CONTAINER_DLL_remove (handle->th_head, handle->th_tail, th); GNUNET_free (th); } if (NULL != handle->th) { GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th); handle->th = NULL; } if (NULL != handle->client) { GNUNET_CLIENT_disconnect (handle->client); handle->client = NULL; } if (GNUNET_SCHEDULER_NO_TASK != handle->reconnect_task) { GNUNET_SCHEDULER_cancel(handle->reconnect_task); handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_free (handle); } /** * Create a new tunnel (we're initiator and will be allowed to add/remove peers * and to broadcast). * * @param h mesh handle * @param tunnel_ctx client's tunnel context to associate with the tunnel * @param connect_handler function to call when peers are actually connected * @param disconnect_handler function to call when peers are disconnected * @param handler_cls closure for connect/disconnect handlers */ struct GNUNET_MESH_Tunnel * GNUNET_MESH_tunnel_create (struct GNUNET_MESH_Handle *h, void *tunnel_ctx, GNUNET_MESH_PeerConnectHandler connect_handler, GNUNET_MESH_PeerDisconnectHandler disconnect_handler, void *handler_cls) { struct GNUNET_MESH_Tunnel *t; struct GNUNET_MESH_TunnelMessage msg; LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating new tunnel\n"); t = create_tunnel (h, 0); t->connect_handler = connect_handler; t->disconnect_handler = disconnect_handler; t->cls = handler_cls; t->ctx = tunnel_ctx; msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE); msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage)); msg.tunnel_id = htonl (t->tid); send_packet (h, &msg.header, t); return t; } /** * Destroy an existing tunnel. The existing callback for the tunnel will NOT * be called. * * @param tunnel tunnel handle */ void GNUNET_MESH_tunnel_destroy (struct GNUNET_MESH_Tunnel *tunnel) { struct GNUNET_MESH_Handle *h; struct GNUNET_MESH_TunnelMessage msg; struct GNUNET_MESH_TransmitHandle *th; LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying tunnel\n"); h = tunnel->mesh; msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY); msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage)); msg.tunnel_id = htonl (tunnel->tid); th = h->th_head; while (th != NULL) { struct GNUNET_MESH_TransmitHandle *aux; if (th->tunnel == tunnel) { aux = th->next; /* FIXME call the handler? */ if (NULL != th->notify) th->notify (th->notify_cls, 0, NULL); GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th); GNUNET_free (th); th = aux; } else th = th->next; } destroy_tunnel (tunnel, GNUNET_NO); send_packet (h, &msg.header, NULL); } /** * Request that a peer should be added to the tunnel. The existing * connect handler will be called ONCE with either success or failure. * This function should NOT be called again with the same peer before the * connect handler is called. * * @param tunnel handle to existing tunnel * @param peer peer to add */ void GNUNET_MESH_peer_request_connect_add (struct GNUNET_MESH_Tunnel *tunnel, const struct GNUNET_PeerIdentity *peer) { struct GNUNET_MESH_PeerControl msg; GNUNET_PEER_Id peer_id; unsigned int i; peer_id = GNUNET_PEER_intern (peer); for (i = 0; i < tunnel->npeers; i++) { if (tunnel->peers[i]->id == peer_id) { /* Peer already exists in tunnel */ GNUNET_PEER_change_rc (peer_id, -1); GNUNET_break (0); return; } } if (NULL == add_peer_to_tunnel (tunnel, peer)) return; msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl)); msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD); msg.tunnel_id = htonl (tunnel->tid); msg.peer = *peer; send_packet (tunnel->mesh, &msg.header, tunnel); return; } /** * Request that a peer should be removed from the tunnel. The existing * disconnect handler will be called ONCE if we were connected. * * @param tunnel handle to existing tunnel * @param peer peer to remove */ void GNUNET_MESH_peer_request_connect_del (struct GNUNET_MESH_Tunnel *tunnel, const struct GNUNET_PeerIdentity *peer) { struct GNUNET_MESH_PeerControl msg; GNUNET_PEER_Id peer_id; unsigned int i; peer_id = GNUNET_PEER_search (peer); if (0 == peer_id) { GNUNET_break (0); return; } for (i = 0; i < tunnel->npeers; i++) if (tunnel->peers[i]->id == peer_id) break; if (i == tunnel->npeers) { GNUNET_break (0); return; } if (NULL != tunnel->disconnect_handler && tunnel->peers[i]->connected == 1) tunnel->disconnect_handler (tunnel->cls, peer); GNUNET_PEER_change_rc (peer_id, -1); GNUNET_free (tunnel->peers[i]); tunnel->peers[i] = tunnel->peers[tunnel->npeers - 1]; GNUNET_array_grow (tunnel->peers, tunnel->npeers, tunnel->npeers - 1); msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl)); msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL); msg.tunnel_id = htonl (tunnel->tid); memcpy (&msg.peer, peer, sizeof (struct GNUNET_PeerIdentity)); send_packet (tunnel->mesh, &msg.header, tunnel); } /** * Request that the mesh should try to connect to a peer supporting the given * message type. * * @param tunnel handle to existing tunnel * @param app_type application type that must be supported by the peer (MESH * should discover peer in proximity handling this type) */ void GNUNET_MESH_peer_request_connect_by_type (struct GNUNET_MESH_Tunnel *tunnel, GNUNET_MESH_ApplicationType app_type) { struct GNUNET_MESH_ConnectPeerByType msg; GNUNET_array_append (tunnel->apps, tunnel->napps, app_type); LOG (GNUNET_ERROR_TYPE_DEBUG, "* CONNECT BY TYPE *\n"); msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectPeerByType)); msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD_BY_TYPE); msg.tunnel_id = htonl (tunnel->tid); msg.type = htonl (app_type); send_packet (tunnel->mesh, &msg.header, tunnel); } /** * Ask the mesh to call "notify" once it is ready to transmit the * given number of bytes to the specified "target". If we are not yet * connected to the specified peer, a call to this function will cause * us to try to establish a connection. * * @param tunnel tunnel to use for transmission * @param cork is corking allowed for this transmission? * @param priority how important is the message? * @param maxdelay how long can the message wait? * @param target destination for the message, * NULL for multicast to all tunnel targets * @param notify_size how many bytes of buffer space does notify want? * @param notify function to call when buffer space is available; * will be called with NULL on timeout or if the overall queue * for this peer is larger than queue_size and this is currently * the message with the lowest priority * @param notify_cls closure for notify * @return non-NULL if the notify callback was queued, * NULL if we can not even queue the request (insufficient * memory); if NULL is returned, "notify" will NOT be called. */ struct GNUNET_MESH_TransmitHandle * GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel, int cork, uint32_t priority, struct GNUNET_TIME_Relative maxdelay, const struct GNUNET_PeerIdentity *target, size_t notify_size, GNUNET_CONNECTION_TransmitReadyNotify notify, void *notify_cls) { struct GNUNET_MESH_TransmitHandle *th; struct GNUNET_MESH_TransmitHandle *least_priority_th; uint32_t least_priority; size_t overhead; GNUNET_assert (NULL != tunnel); LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh notify transmit ready called\n"); if (NULL != target) LOG (GNUNET_ERROR_TYPE_DEBUG, " target %s\n", GNUNET_i2s (target)); else LOG (GNUNET_ERROR_TYPE_DEBUG, " target multicast\n"); GNUNET_assert (NULL != notify); if (tunnel->mesh->npackets >= tunnel->mesh->max_queue_size && tunnel->npackets > 0) { /* queue full */ if (0 == priority) return NULL; th = tunnel->mesh->th_tail; least_priority = priority; least_priority_th = NULL; while (NULL != th) { if (th->priority < least_priority && th->tunnel->npackets > 1) { least_priority_th = th; least_priority = th->priority; } th = th->prev; } if (NULL == least_priority_th) return NULL; /* Can't be a control message */ GNUNET_assert (NULL != least_priority_th->notify); least_priority_th->notify (notify_cls, 0, NULL); least_priority_th->tunnel->npackets--; tunnel->mesh->npackets--; GNUNET_CONTAINER_DLL_remove (tunnel->mesh->th_head, tunnel->mesh->th_tail, least_priority_th); if (GNUNET_SCHEDULER_NO_TASK != least_priority_th->timeout_task) GNUNET_SCHEDULER_cancel (least_priority_th->timeout_task); GNUNET_free (least_priority_th); } tunnel->npackets++; tunnel->mesh->npackets++; th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle)); th->tunnel = tunnel; th->priority = priority; th->timeout = GNUNET_TIME_relative_to_absolute (maxdelay); th->target = GNUNET_PEER_intern (target); if (tunnel->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) overhead = sizeof (struct GNUNET_MESH_ToOrigin); else if (NULL == target) overhead = sizeof (struct GNUNET_MESH_Multicast); else overhead = sizeof (struct GNUNET_MESH_Unicast); th->size = notify_size + overhead; th->notify = notify; th->notify_cls = notify_cls; add_to_queue (tunnel->mesh, th); if (NULL != tunnel->mesh->th) return th; tunnel->mesh->th = GNUNET_CLIENT_notify_transmit_ready (tunnel->mesh->client, th->size, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &send_callback, tunnel->mesh); return th; } /** * Cancel the specified transmission-ready notification. * * @param th handle that was returned by "notify_transmit_ready". */ void GNUNET_MESH_notify_transmit_ready_cancel (struct GNUNET_MESH_TransmitHandle *th) { struct GNUNET_MESH_Handle *mesh; mesh = th->tunnel->mesh; if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (th->timeout_task); GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th); GNUNET_free (th); if ((NULL == mesh->th_head) && (NULL != mesh->th)) { /* queue empty, no point in asking for transmission */ GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th); mesh->th = NULL; } } /** * Transition API for tunnel ctx management */ void GNUNET_MESH_tunnel_set_data (struct GNUNET_MESH_Tunnel *tunnel, void *data) { tunnel->ctx = data; } /** * Transition API for tunnel ctx management */ void * GNUNET_MESH_tunnel_get_data (struct GNUNET_MESH_Tunnel *tunnel) { return tunnel->ctx; } gnunet-0.9.3/src/mesh/mesh_tunnel_tree.h0000644000175000017500000002213311760502551015203 00000000000000/* This file is part of GNUnet. (C) 2001 - 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file mesh/mesh_tunnel_tree.h * @brief Tunnel tree handling functions * @author Bartlomiej Polot */ #include "mesh.h" /******************************************************************************/ /************************ DATA STRUCTURES ****************************/ /******************************************************************************/ /** * Information regarding a possible path to reach a single peer */ struct MeshPeerPath { /** * Linked list */ struct MeshPeerPath *next; struct MeshPeerPath *prev; /** * List of all the peers that form the path from origin to target. */ GNUNET_PEER_Id *peers; /** * Number of peers (hops) in the path */ unsigned int length; }; /** * Node of path tree for a tunnel */ struct MeshTunnelTreeNode; /** * Tree to reach all peers in the tunnel */ struct MeshTunnelTree; /******************************************************************************/ /************************* FUNCTIONS *****************************/ /******************************************************************************/ /** * Create a new path. * * @param length How many hops will the path have. * * @return A newly allocated path with a peer array of the specified length. */ struct MeshPeerPath * path_new (unsigned int length); /** * Invert the path. * * @param path The path to invert. */ void path_invert (struct MeshPeerPath *path); /** * Duplicate a path, incrementing short peer's rc. * * @param path The path to duplicate. */ struct MeshPeerPath * path_duplicate (struct MeshPeerPath *path); /** * Get the length of a path. * * @param path The path to measure, with the local peer at any point of it. * * @return Number of hops to reach destination. * UINT_MAX in case the peer is not in the path. */ unsigned int path_get_length (struct MeshPeerPath *path); /** * Destroy the path and free any allocated resources linked to it * * @param p the path to destroy * * @return GNUNET_OK on success */ int path_destroy (struct MeshPeerPath *p); /******************************************************************************/ /** * Method called whenever a node has been marked as disconnected. * * @param cls Closure. * @param peer_id short ID of peer that is no longer reachable. */ typedef void (*MeshTreeCallback) (void *cls, GNUNET_PEER_Id peer_id); /** * Create a new tunnel tree associated to a tunnel * * @param peer A short peer id of the root of the tree * * @return A newly allocated and initialized tunnel tree */ struct MeshTunnelTree * tree_new (GNUNET_PEER_Id peer); /** * Set the status of a node. * * @param tree Tree. * @param peer A short peer id of the node. * @param status New status to set. */ void tree_set_status (struct MeshTunnelTree *tree, GNUNET_PEER_Id peer, enum MeshPeerState status); /** * Get the status of a node. * * @param tree Tree whose local id we want to now. * @param peer A short peer id of the node. * * @return Short peer id of local peer. */ enum MeshPeerState tree_get_status (struct MeshTunnelTree *tree, GNUNET_PEER_Id peer); /** * Get the id of the predecessor of the local node. * * @param tree Tree whose local id we want to now. * * @return Short peer id of local peer. */ GNUNET_PEER_Id tree_get_predecessor (struct MeshTunnelTree *tree); /** * Find the first peer whom to send a packet to go down this path * * @param t The tunnel tree to use * @param peer The peerinfo of the peer we are trying to reach * * @return peerinfo of the peer who is the first hop in the tunnel * NULL on error */ struct GNUNET_PeerIdentity * tree_get_first_hop (struct MeshTunnelTree *t, GNUNET_PEER_Id peer); /** * Find the given peer in the tree. * * @param tree Tree where to look for the peer. * @param peer_id Peer to find. * * @return Pointer to the node of the peer. NULL if not found. */ struct MeshTunnelTreeNode * tree_find_peer (struct MeshTunnelTree *tree, GNUNET_PEER_Id peer_id); /** * Iterate over all children of the local node. * * @param tree Tree to use. Must have "me" set. * @param cb Callback to call over each child. * @param cls Closure. */ void tree_iterate_children (struct MeshTunnelTree *tree, MeshTreeCallback cb, void *cls); /** * Recusively update the info about what is the first hop to reach the node * * @param tree Tree this nodes belongs to. * @param parent_id Short ID from node form which to start updating. * @param hop If known, ID of the first hop. * If not known, NULL to find out and pass on children. */ void tree_update_first_hops (struct MeshTunnelTree *tree, GNUNET_PEER_Id parent_id, struct GNUNET_PeerIdentity *hop); /** * Delete the current path to the peer, including all now unused relays. * The destination peer is NOT destroyed, it is returned in order to either set * a new path to it or destroy it explicitly, taking care of it's child nodes. * * @param t Tunnel tree where to delete the path from. * @param peer_id Short ID of the destination peer whose path we want to remove. * @param cb Callback to use to notify about which peers are going to be * disconnected. * @param cbcls Closure for cb. * * @return pointer to the pathless node. * NULL when not found */ struct MeshTunnelTreeNode * tree_del_path (struct MeshTunnelTree *t, GNUNET_PEER_Id peer_id, MeshTreeCallback cb, void *cbcls); /** * Return a newly allocated individual path to reach a peer from the local peer, * according to the path tree of some tunnel. * * @param t Tunnel from which to read the path tree * @param peer Destination peer to whom we want a path * * @return A newly allocated individual path to reach the destination peer. * Path must be destroyed afterwards. */ struct MeshPeerPath * tree_get_path_to_peer (struct MeshTunnelTree *t, GNUNET_PEER_Id peer); /** * Integrate a stand alone path into the tunnel tree. * * @param t Tunnel where to add the new path. * @param p Path to be integrated. * @param cb Callback to use to notify about peers temporarily disconnecting. * @param cbcls Closure for cb. * * @return GNUNET_OK in case of success. * GNUNET_SYSERR in case of error. */ int tree_add_path (struct MeshTunnelTree *t, const struct MeshPeerPath *p, MeshTreeCallback cb, void *cbcls); /** * Notifies a tree that a connection it might be using is broken. * Marks all peers down the paths as disconnected and notifies the client. * * @param t Tree to use. * @param p1 Short id of one of the peers (order unimportant) * @param p2 Short id of one of the peers (order unimportant) * @param cb Function to call for every peer that is marked as disconnected. * @param cbcls Closure for cb. * * @return Short ID of the first disconnected peer in the tree. */ GNUNET_PEER_Id tree_notify_connection_broken (struct MeshTunnelTree *t, GNUNET_PEER_Id p1, GNUNET_PEER_Id p2, MeshTreeCallback cb, void *cbcls); /** * Deletes a peer from a tunnel, liberating all unused resources on the path to * it. It shouldn't have children, if it has they will be destroyed as well. * If the tree is not local and no longer has any paths, the root node will be * destroyed and marked as NULL. * * @param t Tunnel tree to use. * @param peer Short ID of the peer to remove from the tunnel tree. * @param cb Callback to notify client of disconnected peers. * @param cbcls Closure for cb. * * @return GNUNET_YES if the tunnel still has nodes */ int tree_del_peer (struct MeshTunnelTree *t, GNUNET_PEER_Id peer, MeshTreeCallback cb, void *cbcls); /** * Get the cost of the path relative to the already built tunnel tree * * @param t The tunnel tree to which compare * @param path The individual path to reach a peer * * @return Number of hops to reach destination, UINT_MAX in case the peer is not * in the path */ unsigned int tree_get_path_cost (struct MeshTunnelTree *t, struct MeshPeerPath *path); /** * Print the tree on stderr * * @param t The tree */ void tree_debug (struct MeshTunnelTree *t); /** * Destroy the whole tree and free all used memory and Peer_Ids * * @param t Tree to be destroyed */ void tree_destroy (struct MeshTunnelTree *t); gnunet-0.9.3/src/mesh/test_mesh_2dtorus.c0000644000175000017500000002321311760517237015322 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file mesh/test_mesh_2dtorus.c * * @brief Test for creating a 2dtorus. */ #include "platform.h" #include "gnunet_testing_lib.h" #define VERBOSE GNUNET_YES #define REMOVE_DIR GNUNET_YES /** * How long until we give up on connecting the peers? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500) /** * Time to wait for stuff that should be rather fast */ #define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) /** * How many events have happened */ static int ok; /** * Be verbose */ static int verbose; /** * Total number of peers in the test. */ static unsigned long long num_peers; /** * Global configuration file */ static struct GNUNET_CONFIGURATION_Handle *testing_cfg; /** * Total number of currently running peers. */ static unsigned long long peers_running; /** * Total number of successful connections in the whole network. */ static unsigned int total_connections; /** * Total number of counted topo connections */ static unsigned int topo_connections; /** * Total number of failed connections in the whole network. */ static unsigned int failed_connections; /** * The currently running peer group. */ static struct GNUNET_TESTING_PeerGroup *pg; /** * Task called to disconnect peers */ static GNUNET_SCHEDULER_TaskIdentifier disconnect_task; /** * Task called to shutdown test. */ static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle; /** * Check whether peers successfully shut down. */ static void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: Shutdown of peers failed! (%s)\n", emsg); ok--; } #if VERBOSE else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: All peers successfully shut down!\n"); } #endif GNUNET_CONFIGURATION_destroy (testing_cfg); } static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Ending test.\n"); #endif GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); } static void disconnect_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: disconnecting peers\n"); if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle) { GNUNET_SCHEDULER_cancel (shutdown_handle); shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); } } /** * Prototype of a callback function indicating that two peers * are currently connected. * * @param cls closure * @param first peer id for first daemon * @param second peer id for the second daemon * @param distance distance between the connected peers * @param emsg error message (NULL on success) */ void topo_cb (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, const char *emsg) { topo_connections++; if (NULL != emsg) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: Error by topo %u: %s\n", topo_connections, emsg); } else { if (first == NULL || second == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Connection %u NULL\n", topo_connections); if (disconnect_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (disconnect_task); disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL); } return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Connection %u ok\n", topo_connections); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: %s\n", GNUNET_i2s (first)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: %s\n", GNUNET_i2s (second)); } } /** * peergroup_ready: start test when all peers are connected * @param cls closure * @param emsg error message */ static void peergroup_ready (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Peergroup callback called with error, aborting test!\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Error from testing: `%s'\n", emsg); ok--; GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); return; } #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "************************************************************\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Peer Group started successfully!\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Have %u connections\n", total_connections); #endif peers_running = GNUNET_TESTING_daemons_running (pg); if (0 < failed_connections) { ok = GNUNET_SYSERR; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: %u connections have FAILED!\n", failed_connections); disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL); } else { GNUNET_TESTING_get_topology (pg, &topo_cb, NULL); disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_peers, NULL); ok = GNUNET_OK; } } /** * Function that will be called whenever two daemons are connected by * the testing library. * * @param cls closure * @param first peer id for first daemon * @param second peer id for the second daemon * @param distance distance between the connected peers * @param first_cfg config for the first daemon * @param second_cfg config for the second daemon * @param first_daemon handle for the first daemon * @param second_daemon handle for the second daemon * @param emsg error message (NULL on success) */ static void connect_cb (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, uint32_t distance, const struct GNUNET_CONFIGURATION_Handle *first_cfg, const struct GNUNET_CONFIGURATION_Handle *second_cfg, struct GNUNET_TESTING_Daemon *first_daemon, struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) { if (emsg == NULL) { total_connections++; } else { failed_connections++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Problem with new connection (%s)\n", emsg); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: (%s)\n", GNUNET_i2s (first)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: (%s)\n", GNUNET_i2s (second)); } } /** * run: load configuration options and schedule test to run (start peergroup) * @param cls closure * @param args argv * @param cfgfile configuration file name (can be NULL) * @param cfg configuration handle */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_TESTING_Host *hosts; ok = GNUNET_NO; total_connections = 0; failed_connections = 0; testing_cfg = GNUNET_CONFIGURATION_dup (cfg); GNUNET_log_setup ("test_mesh_2dtorus", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Starting daemons.\n"); GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", "use_progressbars", "YES"); #endif if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing", "num_peers", &num_peers)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Option TESTING:NUM_PEERS is required!\n"); return; } hosts = GNUNET_TESTING_hosts_load (testing_cfg); pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT, &connect_cb, &peergroup_ready, NULL, hosts); GNUNET_assert (pg != NULL); shutdown_handle = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); } /** * test_mesh_2dtorus command line options */ static struct GNUNET_GETOPT_CommandLineOption options[] = { {'V', "verbose", NULL, gettext_noop ("be verbose (print progress information)"), 0, &GNUNET_GETOPT_set_one, &verbose}, GNUNET_GETOPT_OPTION_END }; /** * Main: start test */ int main (int argc, char *argv[]) { char *const argv2[] = { argv[0], "-c", "test_mesh_2dtorus.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Start\n"); GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, "test_mesh_2dtorus", gettext_noop ("Test mesh 2d torus."), options, &run, NULL); #if REMOVE_DIR GNUNET_DISK_directory_remove ("/tmp/test_mesh_2dtorus"); #endif if (GNUNET_OK != ok) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: FAILED!\n"); return 1; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: success\n"); return 0; } /* end of test_mesh_2dtorus.c */ gnunet-0.9.3/src/mesh/test_mesh_local_2.c0000644000175000017500000002402211760502551015223 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file mesh/test_mesh_local.c * @brief test mesh local: test of tunnels with just one peer * @author Bartlomiej Polot */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_dht_service.h" #include "gnunet_mesh_service.h" #define VERBOSE 1 #define VERBOSE_ARM 0 static struct GNUNET_OS_Process *arm_pid; static struct GNUNET_MESH_Handle *mesh_peer_1; static struct GNUNET_MESH_Handle *mesh_peer_2; static struct GNUNET_MESH_Tunnel *t; static unsigned int one = 1; static unsigned int two = 2; static int result; static GNUNET_SCHEDULER_TaskIdentifier abort_task; static GNUNET_SCHEDULER_TaskIdentifier test_task; /** * Shutdown nicely */ static void do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: shutdown\n"); if (0 != abort_task) { GNUNET_SCHEDULER_cancel (abort_task); } if (NULL != t) { GNUNET_MESH_tunnel_destroy(t); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: D1\n"); if (NULL != mesh_peer_1) { GNUNET_MESH_disconnect (mesh_peer_1); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: D2\n"); if (NULL != mesh_peer_2) { GNUNET_MESH_disconnect (mesh_peer_2); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: arm\n"); if (0 != GNUNET_OS_process_kill (arm_pid, SIGTERM)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Wait\n"); GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (arm_pid)); GNUNET_OS_process_destroy (arm_pid); } /** * Something went wrong and timed out. Kill everything and set error flag */ static void do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: ABORT\n"); if (0 != test_task) { GNUNET_SCHEDULER_cancel (test_task); } result = GNUNET_SYSERR; abort_task = 0; do_shutdown (cls, tc); } /** * Function is called whenever a message is received. * * @param cls closure (set from GNUNET_MESH_connect) * @param tunnel connection to the other end * @param tunnel_ctx place to store local state associated with the tunnel * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int data_callback (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Data callback\n"); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2), &do_shutdown, NULL); return GNUNET_OK; } /** * Method called whenever another peer has added us to a tunnel * the other peer initiated. * * @param cls closure * @param tunnel new handle to the tunnel * @param initiator peer that started the tunnel * @param atsi performance information for the tunnel * @return initial tunnel context for the tunnel (can be NULL -- that's not an error) */ static void * inbound_tunnel (void *cls, struct GNUNET_MESH_Tunnel *tunnel, const struct GNUNET_PeerIdentity *initiator, const struct GNUNET_ATS_Information *atsi) { unsigned int id = *(unsigned int *) cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: received incoming tunnel\n"); if (id != 1) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: received incoming tunnel on peer 2\n"); result = GNUNET_SYSERR; } return NULL; } /** * Function called whenever an inbound tunnel is destroyed. Should clean up * any associated state. * * @param cls closure (set from GNUNET_MESH_connect) * @param tunnel connection to the other end (henceforth invalid) * @param tunnel_ctx place where local state associated * with the tunnel is stored */ static void inbound_end (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx) { unsigned int id = *(unsigned int *) cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: incoming tunnel closed\n"); if (id != 1) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: received closing tunnel on peer 2\n"); result = GNUNET_SYSERR; } } /** * Method called whenever a peer has disconnected from the tunnel. * * @param cls closure * @param peer peer identity the tunnel stopped working with */ static void peer_conected (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: peer connected\n"); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_shutdown, NULL); } /** * Method called whenever a peer has connected to the tunnel. * * @param cls closure * @param peer peer identity the tunnel was created to, NULL on timeout * @param atsi performance data for the connection */ static void peer_disconnected (void *cls, const struct GNUNET_PeerIdentity *peer) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: peer disconnected\n"); } /** * Handler array for traffic received on peer1 */ static struct GNUNET_MESH_MessageHandler handlers1[] = { {&data_callback, 1, 0}, {NULL, 0, 0} }; /** * Handler array for traffic received on peer2 (none expected) */ static struct GNUNET_MESH_MessageHandler handlers2[] = { {NULL, 0, 0} }; /** * Start looking for a peer by type */ static void do_connect_peer_1 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CONFIGURATION_Handle *cfg = cls; static const GNUNET_MESH_ApplicationType app1[] = { 1, 0 }; test_task = GNUNET_SCHEDULER_NO_TASK; mesh_peer_1 = GNUNET_MESH_connect (cfg, /* configuration */ 10, /* queue size */ (void *) &one, /* cls */ &inbound_tunnel, /* inbound new hndlr */ &inbound_end, /* inbound end hndlr */ handlers1, /* traffic handlers */ app1); /* apps offered */ } /** * Main test function */ static void test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CONFIGURATION_Handle *cfg = cls; static const GNUNET_MESH_ApplicationType app2[] = { 0 }; test_task = GNUNET_SCHEDULER_NO_TASK; mesh_peer_2 = GNUNET_MESH_connect (cfg, /* configuration */ 10, /* queue size */ (void *) &two, /* cls */ &inbound_tunnel, /* inbound new hndlr */ &inbound_end, /* inbound end hndlr */ handlers2, /* traffic handlers */ app2); /* apps offered */ if (NULL == mesh_peer_2) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: Couldn't connect to mesh :(\n"); return; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: YAY! CONNECTED TO MESH :D\n"); } t = GNUNET_MESH_tunnel_create (mesh_peer_2, NULL, &peer_conected, &peer_disconnected, (void *) &two); GNUNET_MESH_peer_request_connect_by_type (t, 1); test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), &do_connect_peer_1, cfg); } /** * Initialize framework and start test */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { GNUNET_log_setup ("test_mesh_local", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); arm_pid = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE_ARM "-L", "DEBUG", #endif "-c", "test_mesh.conf", NULL); abort_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20), &do_abort, NULL); test_task = GNUNET_SCHEDULER_add_now (&test, (void *) cfg); } /** * Main */ int main (int argc, char *argv[]) { int ret; char *const argv2[] = { "test-mesh-local", "-c", "test_mesh.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; ret = GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, "test-mesh-local", "nohelp", options, &run, NULL); if (GNUNET_OK != ret) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "run failed with error code %d\n", ret); return 1; } if (GNUNET_SYSERR == result) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test failed\n"); return 1; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test ok\n"); return 0; } gnunet-0.9.3/src/mesh/test_mesh_path.conf0000644000175000017500000000160211761764462015362 00000000000000[fs] AUTOSTART = NO [resolver] AUTOSTART = NO [mesh] DEBUG = YES AUTOSTART = YES ACCEPT_FROM = 127.0.0.1; HOSTNAME = localhost PORT = 10511 # PREFIX = valgrind --leak-check=full # PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args [dht] DEBUG = NO AUTOSTART = YES ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; HOSTNAME = localhost PORT = 12100 [block] plugins = dht test [dhtcache] QUOTA = 1 MB DATABASE = sqlite [transport] PLUGINS = tcp DEBUG = NO ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; NEIGHBOUR_LIMIT = 50 PORT = 12365 [ats] WAN_QUOTA_OUT = 3932160 WAN_QUOTA_IN = 3932160 [core] PORT = 12092 [arm] DEFAULTSERVICES = core PORT = 12366 DEBUG = NO [transport-tcp] TIMEOUT = 300 s PORT = 12368 [TESTING] WEAKRANDOM = YES [gnunetd] HOSTKEY = $SERVICEHOME/.hostkey [PATHS] DEFAULTCONFIG = test_mesh.conf SERVICEHOME = /tmp/test-mesh/ [dns] AUTOSTART = NO [nse] AUTOSTART = NO gnunet-0.9.3/src/mesh/Makefile.am0000644000175000017500000000737311762221551013537 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIB = -lgcov endif pkgcfgdir= $(pkgdatadir)/config.d/ pkgcfg_DATA = \ mesh.conf AM_CLFAGS = -g bin_PROGRAMS = \ gnunet-service-mesh lib_LTLIBRARIES = \ libgnunetmesh.la gnunet_service_mesh_SOURCES = \ gnunet-service-mesh.c \ mesh_tunnel_tree.c mesh_tunnel_tree.h gnunet_service_mesh_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la\ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/util/libgnunetutil.la gnunet_service_mesh_DEPENDENCIES = \ $(top_builddir)/src/core/libgnunetcore.la\ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunetmesh_la_SOURCES = \ mesh_api.c mesh.h mesh_protocol.h libgnunetmesh_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(XLIB) libgnunetmesh_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 1:0:0 check_PROGRAMS = \ test_mesh_api \ test_mesh_tree_api \ test_mesh_local_1 \ test_mesh_local_2 \ test_mesh_2dtorus \ test_mesh_small_unicast \ test_mesh_small_multicast \ test_mesh_small_speed \ test_mesh_small_speed_ack test_mesh_api_SOURCES = \ test_mesh_api.c test_mesh_api_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/mesh/libgnunetmesh.la test_mesh_api_DEPENDENCIES = \ libgnunetmesh.la \ $(top_builddir)/src/util/libgnunetutil.la test_mesh_tree_api_SOURCES = \ test_mesh_tree_api.c test_mesh_tree_api_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/dht/libgnunetdht.la test_mesh_tree_api_DEPENDENCIES = \ libgnunetmesh.la \ $(top_builddir)/src/dht/libgnunetdht.la test_mesh_local_1_SOURCES = \ test_mesh_local_1.c test_mesh_local_1_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/mesh/libgnunetmesh.la test_mesh_local_1_DEPENDENCIES = \ libgnunetmesh.la test_mesh_local_2_SOURCES = \ test_mesh_local_2.c test_mesh_local_2_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/mesh/libgnunetmesh.la test_mesh_local_2_DEPENDENCIES = \ libgnunetmesh.la test_mesh_2dtorus_SOURCES = \ test_mesh_2dtorus.c test_mesh_2dtorus_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la test_mesh_small_unicast_SOURCES = \ test_mesh_small.c test_mesh_small_unicast_LDADD = \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la test_mesh_small_unicast_DEPENDENCIES = \ libgnunetmesh.la test_mesh_small_multicast_SOURCES = \ test_mesh_small.c test_mesh_small_multicast_LDADD = \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la test_mesh_small_multicast_DEPENDENCIES = \ libgnunetmesh.la test_mesh_small_speed_SOURCES = \ test_mesh_small.c test_mesh_small_speed_LDADD = \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la test_mesh_small_speed_DEPENDENCIES = \ libgnunetmesh.la test_mesh_small_speed_ack_SOURCES = \ test_mesh_small.c test_mesh_small_speed_ack_LDADD = \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la test_mesh_small_speed_ack_DEPENDENCIES = \ libgnunetmesh.la if ENABLE_TEST_RUN TESTS = test_mesh_api test_mesh_tree_api test_mesh_local_1 test_mesh_local_2 \ test_mesh_2dtorus test_mesh_small_unicast test_mesh_small_multicast endif EXTRA_DIST = \ test_mesh.conf \ test_mesh_2dtorus.conf \ test_mesh_small.conf \ test_mesh_path.conf gnunet-0.9.3/src/mesh/test_mesh_tree_api.c0000644000175000017500000002467111760502551015512 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file mesh/test_mesh_tree_api.c * @brief test mesh tree api: test of tree & path management api * @author Bartlomiej Polot */ #include "platform.h" #include "gnunet_common.h" #include "gnunet_util_lib.h" #include "gnunet_dht_service.h" #include "gnunet_mesh_service.h" #include "mesh.h" #ifndef MESH_TUNNEL_TREE_C #include "mesh_tunnel_tree.c" #define MESH_TUNNEL_TREE_C #endif #define VERBOSE 1 int failed; int cb_call; struct GNUNET_PeerIdentity *pi[10]; struct MeshTunnelTree *tree; static void cb (void *cls, GNUNET_PEER_Id peer_id) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: CB: Disconnected %u\n", peer_id); if (0 == cb_call) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: and it shouldn't!\n"); failed++; } cb_call--; } /** * Check if a node has all expected properties. * * @param peer_id Short ID of the peer to test. * @param status Expected status of the peer. * @param children Expected number of children of the peer. * @param first_hop Short ID of the expected first hop towards the peer. */ static void test_assert (GNUNET_PEER_Id peer_id, enum MeshPeerState status, unsigned int children, GNUNET_PEER_Id first_hop) { struct MeshTunnelTreeNode *n; struct MeshTunnelTreeNode *c; unsigned int i; int pre_failed; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Checking peer %u\n", peer_id); pre_failed = failed; n = tree_find_peer (tree, peer_id); if (n->peer != peer_id) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Retrieved peer has wrong ID! (Got %u, expected %u)\n", n->peer, peer_id); failed++; } if (n->status != status) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Retrieved peer has wrong status! (Got %u, expected %u)\n", n->status, status); failed++; } for (c = n->children_head, i = 0; NULL != c; c = c->next, i++) ; if (i != children) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Retrieved peer wrong has number of children! (Got %u, expected %u)\n", i, children); failed++; } if (0 != first_hop && GNUNET_PEER_search (tree_get_first_hop (tree, peer_id)) != first_hop) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Wrong first hop! (Got %u, expected %u)\n", GNUNET_PEER_search (tree_get_first_hop (tree, peer_id)), first_hop); failed++; } if (pre_failed != failed) { struct GNUNET_PeerIdentity id; GNUNET_PEER_resolve (peer_id, &id); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "*** Peer %s (%u) has failed %d checks!\n", GNUNET_i2s (&id), peer_id, failed - pre_failed); } } static void finish (void) { unsigned int i; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Finishing...\n"); for (i = 0; i < 10; i++) { GNUNET_free (pi[i]); } } /** * Convert an integer int to a peer identity */ static struct GNUNET_PeerIdentity * get_pi (uint32_t id) { struct GNUNET_PeerIdentity *pi; pi = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity)); pi->hashPubKey.bits[0] = id + 1; return pi; } int main (int argc, char *argv[]) { struct MeshTunnelTreeNode *node; struct MeshPeerPath *path; struct MeshPeerPath *path1; unsigned int i; failed = 0; cb_call = 0; GNUNET_log_setup ("test_mesh_api_tree", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); for (i = 0; i < 10; i++) { pi[i] = get_pi (i); GNUNET_break (i + 1 == GNUNET_PEER_intern (pi[i])); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer %u: %s\n", i + 1, GNUNET_h2s (&pi[i]->hashPubKey)); } tree = tree_new (1); tree->me = tree->root; path = path_new (5); path->peers[0] = 1; path->peers[1] = 2; path->peers[2] = 3; path->peers[3] = 4; path->length = 4; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Adding first path: 1 2 3 4\n"); tree_add_path (tree, path, &cb, NULL); tree_debug (tree); path1 = tree_get_path_to_peer (tree, 4); if (NULL == path1 || path->length != path1->length || memcmp (path->peers, path1->peers, path->length) != 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Retrieved path != original\n"); failed++; } path_destroy (path1); test_assert (4, MESH_PEER_SEARCHING, 0, 2); test_assert (3, MESH_PEER_RELAY, 1, 0); test_assert (2, MESH_PEER_RELAY, 1, 0); test_assert (1, MESH_PEER_ROOT, 1, 0); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Adding second path: 1 2 3\n"); path->length--; tree_add_path (tree, path, &cb, NULL); tree_debug (tree); test_assert (4, MESH_PEER_SEARCHING, 0, 2); test_assert (3, MESH_PEER_SEARCHING, 1, 2); test_assert (2, MESH_PEER_RELAY, 1, 0); test_assert (1, MESH_PEER_ROOT, 1, 0); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Adding third path 1 2 3 5\n"); path->length++; path->peers[3] = 5; tree_add_path (tree, path, &cb, NULL); tree_debug (tree); test_assert (5, MESH_PEER_SEARCHING, 0, 2); test_assert (4, MESH_PEER_SEARCHING, 0, 2); test_assert (3, MESH_PEER_SEARCHING, 2, 2); test_assert (2, MESH_PEER_RELAY, 1, 0); test_assert (1, MESH_PEER_ROOT, 1, 0); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Calculating costs...\n"); for (i = 1; i < 5; i++) { path->length = i; if (tree_get_path_cost (tree, path) != 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: length %u cost failed!\n", i); failed++; } } path->length++; path->peers[4] = 6; if (tree_get_path_cost (tree, path) != 1) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: length %u cost failed!\n", i); failed++; } path->peers[3] = 7; if (tree_get_path_cost (tree, path) != 2) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: length %u cost failed!\n", i); failed++; } path->length--; if (tree_get_path_cost (tree, path) != 1) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: length %u cost failed!\n", i); failed++; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Deleting third path (5)\n"); tree_set_status (tree, 5, MESH_PEER_READY); cb_call = 1; node = tree_del_path (tree, 5, &cb, NULL); tree_debug (tree); if (cb_call != 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%u callbacks missed!\n", cb_call); failed++; } if (node->peer != 5) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Retrieved peer != original\n"); failed++; } test_assert (4, MESH_PEER_SEARCHING, 0, 2); test_assert (3, MESH_PEER_SEARCHING, 1, 2); test_assert (2, MESH_PEER_RELAY, 1, 0); test_assert (1, MESH_PEER_ROOT, 1, 0); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Destroying node copy...\n"); GNUNET_free (node); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Adding new shorter first path...\n"); path->length = 2; path->peers[1] = 4; cb_call = 1; tree_find_peer (tree, 4)->status = MESH_PEER_READY; tree_add_path (tree, path, &cb, NULL); tree_debug (tree); if (cb_call != 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%u callbacks missed!\n", cb_call); failed++; } test_assert (4, MESH_PEER_SEARCHING, 0, 4); test_assert (3, MESH_PEER_SEARCHING, 0, 2); test_assert (2, MESH_PEER_RELAY, 1, 0); test_assert (1, MESH_PEER_ROOT, 2, 0); GNUNET_free (path->peers); GNUNET_free (path); tree_destroy (tree); /****************************************************************************/ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test:\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Testing relay trees\n"); for (i = 0; i < 10; i++) { GNUNET_break (i + 1 == GNUNET_PEER_intern (pi[i])); } tree = tree_new (2); path = path_new (8); path->peers[0] = 2; path->peers[1] = 1; path->peers[2] = 3; path->length = 3; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Adding first path: 2 1 3\n"); tree_add_path (tree, path, &cb, NULL); tree_debug (tree); test_assert (3, MESH_PEER_SEARCHING, 0, 3); test_assert (1, MESH_PEER_RELAY, 1, 0); test_assert (2, MESH_PEER_ROOT, 1, 0); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Adding long path: 2 1 4 5 3\n"); path->peers[2] = 4; path->peers[3] = 5; path->peers[4] = 3; path->length = 5; tree_add_path (tree, path, &cb, NULL); tree_debug (tree); test_assert (3, MESH_PEER_SEARCHING, 0, 4); test_assert (5, MESH_PEER_RELAY, 1, 4); test_assert (4, MESH_PEER_RELAY, 1, 4); test_assert (1, MESH_PEER_RELAY, 1, 0); test_assert (2, MESH_PEER_ROOT, 1, 0); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Even longer path: 2 6 1 7 8 4 5 3\n"); path->peers[0] = 2; path->peers[1] = 6; path->peers[2] = 1; path->peers[3] = 7; path->peers[4] = 8; path->peers[5] = 4; path->peers[6] = 5; path->peers[7] = 3; path->length = 8; tree_add_path (tree, path, &cb, NULL); tree_debug (tree); test_assert (3, MESH_PEER_SEARCHING, 0, 7); test_assert (5, MESH_PEER_RELAY, 1, 7); test_assert (4, MESH_PEER_RELAY, 1, 7); test_assert (8, MESH_PEER_RELAY, 1, 7); test_assert (7, MESH_PEER_RELAY, 1, 7); test_assert (1, MESH_PEER_RELAY, 1, 0); test_assert (6, MESH_PEER_RELAY, 1, 0); test_assert (2, MESH_PEER_ROOT, 1, 0); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Adding first path: 2 1 3\n"); path->peers[1] = 1; path->peers[2] = 3; path->length = 3; tree_add_path (tree, path, &cb, NULL); tree_debug (tree); test_assert (3, MESH_PEER_SEARCHING, 0, 3); test_assert (1, MESH_PEER_RELAY, 1, 0); test_assert (2, MESH_PEER_ROOT, 1, 0); GNUNET_free (path->peers); GNUNET_free (path); tree_destroy (tree); finish (); if (failed > 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%u tests failed\n", failed); return 1; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: OK\n"); return 0; } gnunet-0.9.3/src/mesh/mesh_tunnel_tree.c0000644000175000017500000006623011760502551015204 00000000000000/* This file is part of GNUnet. (C) 2001 - 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file mesh/mesh_tunnel_tree.c * @brief Tunnel tree handling functions * @author Bartlomiej Polot */ #include "mesh.h" #include "mesh_tunnel_tree.h" #define MESH_TREE_DEBUG GNUNET_YES /** * Node of path tree for a tunnel */ struct MeshTunnelTreeNode { /** * Peer this node describes */ GNUNET_PEER_Id peer; /** * Parent node in the tree */ struct MeshTunnelTreeNode *parent; /** * DLL of siblings */ struct MeshTunnelTreeNode *next; /** * DLL of siblings */ struct MeshTunnelTreeNode *prev; /** * DLL of children */ struct MeshTunnelTreeNode *children_head; /** * DLL of children */ struct MeshTunnelTreeNode *children_tail; /** * Status of the peer in the tunnel */ enum MeshPeerState status; }; /** * Tree to reach all peers in the tunnel */ struct MeshTunnelTree { /** * Root node of peer tree */ struct MeshTunnelTreeNode *root; /** * Node that represents our position in the tree (for non local tunnels) */ struct MeshTunnelTreeNode *me; /** * DLL of disconneted nodes */ struct MeshTunnelTreeNode *disconnected_head; /** * DLL of disconneted nodes */ struct MeshTunnelTreeNode *disconnected_tail; /** * Cache of all peers and the first hop to them. * Indexed by PeerIdentity, contains a pointer to the PeerIdentity * of 1st hop. */ struct GNUNET_CONTAINER_MultiHashMap *first_hops; }; /** * Create a new path * * @param length How many hops will the path have. * * @return A newly allocated path with a peer array of the specified length. */ struct MeshPeerPath * path_new (unsigned int length) { struct MeshPeerPath *p; p = GNUNET_malloc (sizeof (struct MeshPeerPath)); if (length > 0) { p->length = length; p->peers = GNUNET_malloc (length * sizeof (GNUNET_PEER_Id)); } return p; } /** * Invert the path * * @param path the path to invert */ void path_invert (struct MeshPeerPath *path) { GNUNET_PEER_Id aux; unsigned int i; for (i = 0; i < path->length / 2; i++) { aux = path->peers[i]; path->peers[i] = path->peers[path->length - i - 1]; path->peers[path->length - i - 1] = aux; } } /** * Duplicate a path, incrementing short peer's rc. * * @param path The path to duplicate. */ struct MeshPeerPath * path_duplicate (struct MeshPeerPath *path) { struct MeshPeerPath *aux; unsigned int i; aux = path_new (path->length); memcpy (aux->peers, path->peers, path->length * sizeof (GNUNET_PEER_Id)); for (i = 0; i < path->length; i++) GNUNET_PEER_change_rc (path->peers[i], 1); return aux; } /** * Recusively update the info about what is the first hop to reach the node * * @param tree Tree this nodes belongs to. * @param parent The node form which to start updating. * @param hop If known, ID of the first hop. * If not known, NULL to find out and pass on children. */ static void tree_node_update_first_hops (struct MeshTunnelTree *tree, struct MeshTunnelTreeNode *parent, struct GNUNET_PeerIdentity *hop); /** * Get the length of a path. * * @param path The path to measure, with the local peer at any point of it. * * @return Number of hops to reach destination. * UINT_MAX in case the peer is not in the path. */ unsigned int path_get_length (struct MeshPeerPath *path) { if (NULL == path) return UINT_MAX; return path->length; } /** * Destroy the path and free any allocated resources linked to it * * @param p the path to destroy * * @return GNUNET_OK on success */ int path_destroy (struct MeshPeerPath *p) { if (NULL == p) return GNUNET_OK; GNUNET_PEER_decrement_rcs (p->peers, p->length); GNUNET_free_non_null (p->peers); GNUNET_free (p); return GNUNET_OK; } /** * Allocates and initializes a new node. * Sets ID and parent of the new node and inserts it in the DLL of the parent * * @param parent Node that will be the parent from the new node, NULL for root * @param peer Short Id of the new node * * @return Newly allocated node */ static struct MeshTunnelTreeNode * tree_node_new (struct MeshTunnelTreeNode *parent, GNUNET_PEER_Id peer) { struct MeshTunnelTreeNode *node; node = GNUNET_malloc (sizeof (struct MeshTunnelTreeNode)); node->peer = peer; GNUNET_PEER_change_rc (peer, 1); node->parent = parent; if (NULL != parent) GNUNET_CONTAINER_DLL_insert (parent->children_head, parent->children_tail, node); return node; } /** * Recursively find the given peer. * * @param parent Node where to start looking. * @param peer_id Short ID of the peer to find. * * @return Pointer to the node of the peer. NULL if not found. */ static struct MeshTunnelTreeNode * tree_node_find_peer (struct MeshTunnelTreeNode *parent, GNUNET_PEER_Id peer_id) { struct MeshTunnelTreeNode *n; struct MeshTunnelTreeNode *r; if (parent->peer == peer_id) return parent; for (n = parent->children_head; NULL != n; n = n->next) { r = tree_node_find_peer (n, peer_id); if (NULL != r) return r; } return NULL; } /** * Recusively update the info about what is the first hop to reach the node * * @param tree Tree this nodes belongs to. * @param parent ID from node form which to start updating. * @param hop If known, ID of the first hop. * If not known, NULL to find out and pass on children. */ static void tree_node_update_first_hops (struct MeshTunnelTree *tree, struct MeshTunnelTreeNode *parent, struct GNUNET_PeerIdentity *hop) { struct GNUNET_PeerIdentity pi; struct GNUNET_PeerIdentity *copy; struct GNUNET_PeerIdentity id; struct MeshTunnelTreeNode *n; #if MESH_TREE_DEBUG GNUNET_PEER_resolve (parent->peer, &id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Finding first hop for %s.\n", GNUNET_i2s (&id)); #endif if (NULL == hop) { struct MeshTunnelTreeNode *aux; struct MeshTunnelTreeNode *old; aux = old = parent; while (aux != tree->me) { #if MESH_TREE_DEBUG GNUNET_PEER_resolve (aux->peer, &id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: ... checking %s.\n", GNUNET_i2s (&id)); #endif old = aux; aux = aux->parent; GNUNET_assert (NULL != aux); } #if MESH_TREE_DEBUG GNUNET_PEER_resolve (old->peer, &id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: It's %s!\n", GNUNET_i2s (&id)); #endif hop = π GNUNET_PEER_resolve (old->peer, hop); } GNUNET_PEER_resolve (parent->peer, &id); copy = GNUNET_CONTAINER_multihashmap_get (tree->first_hops, &id.hashPubKey); if (NULL == copy) copy = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity)); *copy = *hop; (void) GNUNET_CONTAINER_multihashmap_put (tree->first_hops, &id.hashPubKey, copy, GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); for (n = parent->children_head; NULL != n; n = n->next) { tree_node_update_first_hops (tree, n, hop); } } static void tree_node_debug (struct MeshTunnelTreeNode *n, uint16_t level) { struct MeshTunnelTreeNode *c; struct GNUNET_PeerIdentity id;; uint16_t i; for (i = 0; i < level; i++) FPRINTF (stderr, "%s", " "); if (n->status == MESH_PEER_READY) FPRINTF (stderr, "%s", "#"); if (n->status == MESH_PEER_SEARCHING) FPRINTF (stderr, "%s", "+"); if (n->status == MESH_PEER_RELAY) FPRINTF (stderr, "%s", "-"); if (n->status == MESH_PEER_RECONNECTING) FPRINTF (stderr, "%s", "*"); GNUNET_PEER_resolve (n->peer, &id); FPRINTF (stderr, "%s, [%u, %p] ", GNUNET_i2s (&id), n->peer, n); if (NULL != n->parent) { GNUNET_PEER_resolve (n->parent->peer, &id); FPRINTF (stderr, "(-> %s [%u])\n", GNUNET_i2s (&id), n->parent->peer); } else FPRINTF (stderr, "%s", "(root)\n"); for (c = n->children_head; NULL != c; c = c->next) tree_node_debug (c, level + 1); } /** * Destroys and frees the node and all children * * @param parent Parent node to be destroyed */ static void tree_node_destroy (struct MeshTunnelTreeNode *parent) { struct MeshTunnelTreeNode *n; struct MeshTunnelTreeNode *next; #if MESH_TREE_DEBUG struct GNUNET_PeerIdentity id; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Destroying node %u\n", parent->peer); GNUNET_PEER_resolve (parent->peer, &id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: (%s)\n", GNUNET_i2s (&id)); #endif n = parent->children_head; while (NULL != n) { next = n->next; tree_node_destroy (n); n = next; } GNUNET_PEER_change_rc (parent->peer, -1); if (NULL != parent->parent) GNUNET_CONTAINER_DLL_remove (parent->parent->children_head, parent->parent->children_tail, parent); GNUNET_free (parent); } /** * Create a new tree. * * @param peer A short peer id of the root of the tree. * * @return A newly allocated and initialized tunnel tree. */ struct MeshTunnelTree * tree_new (GNUNET_PEER_Id peer) { struct MeshTunnelTree *tree; tree = GNUNET_malloc (sizeof (struct MeshTunnelTree)); tree->first_hops = GNUNET_CONTAINER_multihashmap_create (32); tree->root = tree_node_new (NULL, peer); tree->root->status = MESH_PEER_ROOT; if (1 == peer) { tree->me = tree->root; } return tree; } /** * Set the status of a node. * * @param tree Tree. * @param peer A short peer id of the node. * @param status New status to set. */ void tree_set_status (struct MeshTunnelTree *tree, GNUNET_PEER_Id peer, enum MeshPeerState status) { struct MeshTunnelTreeNode *n; n = tree_find_peer (tree, peer); if (NULL == n) return; n->status = status; } /** * Get the status of a node. * * @param tree Tree whose node's status we want to now. * @param peer A short peer id of the node. * * @return Status of the peer. */ enum MeshPeerState tree_get_status (struct MeshTunnelTree *tree, GNUNET_PEER_Id peer) { struct MeshTunnelTreeNode *n; n = tree_find_peer (tree, peer); if (NULL == n) return MESH_PEER_INVALID; return n->status; } /** * Get the id of the predecessor of the local node. * * @param tree Tree whose local id we want to now. * * @return Short peer id of local peer. */ GNUNET_PEER_Id tree_get_predecessor (struct MeshTunnelTree *tree) { if (NULL != tree->me && NULL != tree->me->parent) return tree->me->parent->peer; else return (GNUNET_PEER_Id) 0; } /** * Find the first peer whom to send a packet to go down this path * * @param t The tunnel tree to use * @param peer The peerinfo of the peer we are trying to reach * * @return peerinfo of the peer who is the first hop in the tunnel * NULL on error */ struct GNUNET_PeerIdentity * tree_get_first_hop (struct MeshTunnelTree *t, GNUNET_PEER_Id peer) { struct GNUNET_PeerIdentity id; struct GNUNET_PeerIdentity *r; GNUNET_PEER_resolve (peer, &id); r = GNUNET_CONTAINER_multihashmap_get (t->first_hops, &id.hashPubKey); if (NULL == r) { struct MeshTunnelTreeNode *n; n = tree_find_peer (t, peer); if (NULL != t->me && NULL != n) { tree_node_update_first_hops (t, n, NULL); r = GNUNET_CONTAINER_multihashmap_get (t->first_hops, &id.hashPubKey); GNUNET_assert (NULL != r); } else { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Tree structure inconsistent! me: %p, n: %p", t->me, n); GNUNET_break (0); } } return r; } /** * Find the given peer in the tree. * * @param tree Tree where to look for the peer. * @param peer_id Short ID of the peer to find. * * @return Pointer to the node of the peer. NULL if not found. */ struct MeshTunnelTreeNode * tree_find_peer (struct MeshTunnelTree *tree, GNUNET_PEER_Id peer_id) { return tree_node_find_peer (tree->root, peer_id); } /** * Recusively mark peer and children as disconnected, notify client * * @param tree Tree this node belongs to * @param parent Node to be clean, potentially with children * @param cb Callback to use to notify about disconnected peers. * @param cbcls Closure for cb. */ static void tree_mark_peers_disconnected (struct MeshTunnelTree *tree, struct MeshTunnelTreeNode *parent, MeshTreeCallback cb, void *cbcls) { struct GNUNET_PeerIdentity *pi; struct GNUNET_PeerIdentity id; struct MeshTunnelTreeNode *n; for (n = parent->children_head; NULL != n; n = n->next) { tree_mark_peers_disconnected (tree, n, cb, cbcls); } if (MESH_PEER_READY == parent->status) { if (NULL != cb) cb (cbcls, parent->peer); parent->status = MESH_PEER_RECONNECTING; } /* Remove and free info about first hop */ GNUNET_PEER_resolve (parent->peer, &id); pi = GNUNET_CONTAINER_multihashmap_get (tree->first_hops, &id.hashPubKey); GNUNET_CONTAINER_multihashmap_remove_all (tree->first_hops, &id.hashPubKey); if (NULL != pi) GNUNET_free (pi); } /** * Iterate over all children of the local node. * * @param tree Tree to use. Must have "me" set. * @param cb Callback to call over each child. * @param cls Closure. */ void tree_iterate_children (struct MeshTunnelTree *tree, MeshTreeCallback cb, void *cls) { struct MeshTunnelTreeNode *n; if (NULL == tree->me) { GNUNET_break (0); return; } for (n = tree->me->children_head; NULL != n; n = n->next) { cb (cls, n->peer); } } /** * Recusively update the info about what is the first hop to reach the node * * @param tree Tree this nodes belongs to. * @param parent_id Short ID from node form which to start updating. * @param hop If known, ID of the first hop. * If not known, NULL to find out and pass on children. */ void tree_update_first_hops (struct MeshTunnelTree *tree, GNUNET_PEER_Id parent_id, struct GNUNET_PeerIdentity *hop) { tree_node_update_first_hops (tree, tree_find_peer (tree, parent_id), hop); } /** * Delete the current path to the peer, including all now unused relays. * The destination peer is NOT destroyed, it is returned in order to either set * a new path to it or destroy it explicitly, taking care of it's child nodes. * * @param t Tunnel tree where to delete the path from. * @param peer_id Short ID of the destination peer whose path we want to remove. * @param cb Callback to use to notify about disconnected peers. * @param cbcls Closure for cb. * * @return pointer to the pathless node. * NULL when not found */ struct MeshTunnelTreeNode * tree_del_path (struct MeshTunnelTree *t, GNUNET_PEER_Id peer_id, MeshTreeCallback cb, void *cbcls) { struct MeshTunnelTreeNode *parent; struct MeshTunnelTreeNode *node; struct MeshTunnelTreeNode *n; #if MESH_TREE_DEBUG struct GNUNET_PeerIdentity id; GNUNET_PEER_resolve (peer_id, &id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Deleting path to %s.\n", GNUNET_i2s (&id)); #endif if (peer_id == t->root->peer) return NULL; for (n = t->disconnected_head; NULL != n; n = n->next) { if (n->peer == peer_id) { /* Was already pathless, waiting for reconnection */ GNUNET_CONTAINER_DLL_remove (t->disconnected_head, t->disconnected_tail, n); return n; } } n = tree_find_peer (t, peer_id); if (NULL == n) return NULL; node = n; parent = n->parent; GNUNET_CONTAINER_DLL_remove (parent->children_head, parent->children_tail, n); n->parent = NULL; while (MESH_PEER_RELAY == parent->status && NULL == parent->children_head) { #if MESH_TREE_DEBUG GNUNET_PEER_resolve (parent->peer, &id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Deleting node %s.\n", GNUNET_i2s (&id)); #endif n = parent->parent; tree_node_destroy (parent); parent = n; } #if MESH_TREE_DEBUG GNUNET_PEER_resolve (parent->peer, &id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Not deleted peer %s.\n", GNUNET_i2s (&id)); #endif tree_mark_peers_disconnected (t, node, cb, cbcls); return node; } /** * Return a newly allocated individual path to reach a peer from the local peer, * according to the path tree of some tunnel. * * @param t Tunnel from which to read the path tree. * @param peer Short ID of the destination peer to whom we want a path. * * @return A newly allocated individual path to reach the destination peer. * Path must be destroyed afterwards. */ struct MeshPeerPath * tree_get_path_to_peer (struct MeshTunnelTree *t, GNUNET_PEER_Id peer) { struct MeshTunnelTreeNode *n; struct MeshPeerPath *p; n = tree_find_peer (t, peer); if (NULL == n) { GNUNET_break (0); return NULL; } p = path_new (0); /* Building the path (inverted!) */ while (n->peer != 1) { GNUNET_array_append (p->peers, p->length, n->peer); GNUNET_PEER_change_rc (n->peer, 1); n = n->parent; if (NULL == n) { GNUNET_break (0); path_destroy (p); return NULL; } } GNUNET_array_append (p->peers, p->length, 1); GNUNET_PEER_change_rc (1, 1); path_invert (p); return p; } /** * Integrate a stand alone path into the tunnel tree. * If the peer toward which the new path is already in the tree, the peer * and its children will be maked as disconnected and the callback * will be called on each one of them. They will be maked as online only after * receiving a PATH ACK for the new path for each one of them, so the caller * should take care of sending a new CREATE PATH message for each disconnected * peer. * * @param t Tunnel where to add the new path. * @param p Path to be integrated. * @param cb Callback to use to notify about peers temporarily disconnecting. * @param cbcls Closure for cb. * * @return GNUNET_OK in case of success. * GNUNET_SYSERR in case of error. * * TODO: optimize * - go backwards on path looking for each peer in the present tree * - do not disconnect peers until new path is created & connected */ int tree_add_path (struct MeshTunnelTree *t, const struct MeshPeerPath *p, MeshTreeCallback cb, void *cbcls) { struct MeshTunnelTreeNode *parent; struct MeshTunnelTreeNode *oldnode; struct MeshTunnelTreeNode *n; struct MeshTunnelTreeNode *c; struct GNUNET_PeerIdentity id; int me; unsigned int i; #if MESH_TREE_DEBUG GNUNET_PEER_resolve (p->peers[p->length - 1], &id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Adding path [%u] towards peer %s.\n", p->length, GNUNET_i2s (&id)); #endif GNUNET_assert (0 != p->length); parent = n = t->root; if (n->peer != p->peers[0]) { GNUNET_break (0); return GNUNET_SYSERR; } if (1 == p->length) return GNUNET_OK; oldnode = tree_del_path (t, p->peers[p->length - 1], cb, cbcls); /* Look for the first node that is not already present in the tree * * Assuming that the tree is somewhat balanced, O(log n * log N). * - Length of the path is expected to be log N (size of whole network). * - Each level of the tree is expected to have log n children (size of tree). */ me = t->root->peer == 1 ? 0 : -1; for (i = 1; i < p->length; i++) { #if MESH_TREE_DEBUG GNUNET_PEER_resolve (p->peers[i], &id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Looking for peer %s.\n", GNUNET_i2s (&id)); #endif parent = n; if (p->peers[i] == 1) me = i; for (c = n->children_head; NULL != c; c = c->next) { if (c->peer == p->peers[i]) { #if MESH_TREE_DEBUG GNUNET_PEER_resolve (parent->peer, &id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Found in children of %s.\n", GNUNET_i2s (&id)); #endif n = c; break; } } /* If we couldn't find a child equal to path[i], we have reached the end * of the common path. */ if (parent == n) break; } #if MESH_TREE_DEBUG GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: All childen visited.\n"); #endif /* Add the rest of the path as a branch from parent. */ while (i < p->length) { #if MESH_TREE_DEBUG GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Adding peer %u to %u.\n", p->peers[i], parent->peer); GNUNET_PEER_resolve (p->peers[i], &id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Adding peer %s.\n", GNUNET_i2s (&id)); GNUNET_PEER_resolve (parent->peer, &id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: to %s.\n", GNUNET_i2s (&id)); #endif if (i == p->length - 1 && NULL != oldnode) { #if MESH_TREE_DEBUG GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Putting old node into place.\n"); #endif oldnode->parent = parent; GNUNET_CONTAINER_DLL_insert (parent->children_head, parent->children_tail, oldnode); tree_node_update_first_hops (t, oldnode, NULL); n = oldnode; } else { #if MESH_TREE_DEBUG GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Creating new node.\n"); #endif n = tree_node_new (parent, p->peers[i]); n->status = MESH_PEER_RELAY; } if (n->peer == 1) { t->me = n; me = i; } i++; parent = n; } n->status = MESH_PEER_SEARCHING; GNUNET_break (-1 != me); /* Add info about first hop into hashmap. */ if (-1 != me && me < p->length - 1) { #if MESH_TREE_DEBUG GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH: finding first hop (own pos %d/%u)\n", me, p->length - 1); #endif GNUNET_PEER_resolve (p->peers[me + 1], &id); tree_update_first_hops (t, p->peers[me + 1], &id); } #if MESH_TREE_DEBUG else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH: was last in path, not updating first hops (%d/%u)\n", me, p->length - 1); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: New node added.\n"); #endif if (NULL == t->me) t->me = tree_find_peer (t, 1); return GNUNET_OK; } /** * Notifies a tree that a connection it might be using is broken. * Marks all peers down the paths as disconnected and notifies the client. * * @param t Tree to use. * @param p1 Short id of one of the peers (order unimportant) * @param p2 Short id of one of the peers (order unimportant) * @param cb Function to call for every peer that is marked as disconnected. * @param cbcls Closure for cb. * * @return Short ID of the first disconnected peer in the tree. */ GNUNET_PEER_Id tree_notify_connection_broken (struct MeshTunnelTree *t, GNUNET_PEER_Id p1, GNUNET_PEER_Id p2, MeshTreeCallback cb, void *cbcls) { struct MeshTunnelTreeNode *n; struct MeshTunnelTreeNode *c; n = tree_find_peer (t, p1); if (NULL == n) return 0; if (NULL != n->parent && n->parent->peer == p2) { tree_mark_peers_disconnected (t, n, cb, cbcls); GNUNET_CONTAINER_DLL_remove (n->parent->children_head, n->parent->children_tail, n); GNUNET_CONTAINER_DLL_insert (t->disconnected_head, t->disconnected_tail, n); return p1; } for (c = n->children_head; NULL != c; c = c->next) { if (c->peer == p2) { tree_mark_peers_disconnected (t, c, cb, cbcls); GNUNET_CONTAINER_DLL_remove (n->children_head, n->children_tail, c); GNUNET_CONTAINER_DLL_insert (t->disconnected_head, t->disconnected_tail, c); return p2; } } return 0; } /** * Deletes a peer from a tunnel, liberating all unused resources on the path to * it. It shouldn't have children, if it has they will be destroyed as well. * If the tree is not local and no longer has any paths, the root node will be * destroyed and marked as NULL. * * @param t Tunnel tree to use. * @param peer Short ID of the peer to remove from the tunnel tree. * @param cb Callback to notify client of disconnected peers. * @param cbcls Closure for cb. * * @return GNUNET_OK or GNUNET_SYSERR */ int tree_del_peer (struct MeshTunnelTree *t, GNUNET_PEER_Id peer, MeshTreeCallback cb, void *cbcls) { struct MeshTunnelTreeNode *n; n = tree_del_path (t, peer, cb, cbcls); if (NULL == n) { GNUNET_break (0); return GNUNET_YES; } GNUNET_break_op (NULL == n->children_head); tree_node_destroy (n); if (NULL == t->root->children_head && t->me != t->root) { tree_node_destroy (t->root); t->root = NULL; return GNUNET_NO; } return GNUNET_YES; } /** * Get the cost of the path relative to the already built tunnel tree. * * @param t The tunnel tree to which compare. * @param path The individual path to reach a peer. It has to start at the * root of the tree to be comparable. * * @return Number of hops to reach destination, UINT_MAX in case the peer is not * in the path. * * TODO: adapt to allow any start / root combination * TODO: take in account state of the nodes */ unsigned int tree_get_path_cost (struct MeshTunnelTree *t, struct MeshPeerPath *path) { struct MeshTunnelTreeNode *n; struct MeshTunnelTreeNode *p; unsigned int i; unsigned int l; l = path_get_length (path); p = t->root; if (t->root->peer != path->peers[0]) { GNUNET_break (0); return UINT_MAX; } for (i = 1; i < l; i++) { for (n = p->children_head; NULL != n; n = n->next) { if (path->peers[i] == n->peer) { break; } } if (NULL == n) return l - i; p = n; } return l - i; } /** * Print the tree on stderr * * @param t The tree */ void tree_debug (struct MeshTunnelTree *t) { tree_node_debug (t->root, 0); } /** * Iterator over hash map peer entries and frees all data in it. * Used prior to destroying a hashmap. Makes you miss anonymous functions in C. * * @param cls closure * @param key current key code (will no longer contain valid data!!) * @param value value in the hash map (treated as void *) * @return GNUNET_YES if we should continue to iterate, GNUNET_NO if not. */ static int iterate_free (void *cls, const GNUNET_HashCode * key, void *value) { GNUNET_free (value); return GNUNET_YES; } /** * Destroy the whole tree and free all used memory and Peer_Ids * * @param t Tree to be destroyed */ void tree_destroy (struct MeshTunnelTree *t) { #if MESH_TREE_DEBUG GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Destroying tree\n"); #endif tree_node_destroy (t->root); GNUNET_CONTAINER_multihashmap_iterate (t->first_hops, &iterate_free, NULL); GNUNET_CONTAINER_multihashmap_destroy (t->first_hops); GNUNET_free (t); } gnunet-0.9.3/src/mesh/mesh.h0000644000175000017500000001647411760502551012612 00000000000000/* This file is part of GNUnet. (C) 2001 - 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @author Bartlomiej Polot * @file mesh/mesh.h */ #ifndef MESH_H_ #define MESH_H_ #include #define MESH_DEBUG GNUNET_YES #include "platform.h" #include "gnunet_common.h" #include "gnunet_util_lib.h" #include "gnunet_peer_lib.h" #include "gnunet_core_service.h" #include "gnunet_protocols.h" #include /******************************************************************************/ /******************** MESH LOCAL MESSAGES *************************/ /******************************************************************************/ /* Any API call should be documented in the folowing table under API CALL. * Also, any message type should be documented in the following table, with the * associated event. * * API CALL (GNUNET_MESH_*) MESSAGE USED * ------------------------ ------------ * connect GNUNET_MESH_ClientConnect * disconnect None (network level disconnect) * * tunnel_create GNUNET_MESH_TunnelMessage * tunnel_destroy GNUNET_MESH_TunnelMessage * * peer_request_connect_add GNUNET_MESH_PeerControl * peer_request_connect_del GNUNET_MESH_PeerControl * peer_request_connect_by_type GNUNET_MESH_ConnectPeerByType * * notify_transmit_ready *GNUNET_MESH_TransmitReady?* * notify_transmit_ready_cancel None (clear of internal data structures) * * * * EVENT MESSAGE USED * ----- ------------ * data GNUNET_MESH_Data OR * GNUNET_MESH_DataBroadcast * new incoming tunnel GNUNET_MESH_PeerControl * peer connects to a tunnel GNUNET_MESH_PeerControl * peer disconnects from a tunnel GNUNET_MESH_PeerControl */ /******************************************************************************/ /************************** CONSTANTS ******************************/ /******************************************************************************/ #define GNUNET_MESH_LOCAL_TUNNEL_ID_CLI 0x80000000 #define GNUNET_MESH_LOCAL_TUNNEL_ID_SERV 0xB0000000 #define CORE_QUEUE_SIZE 10 #define LOCAL_QUEUE_SIZE 100 /******************************************************************************/ /************************** MESSAGES ******************************/ /******************************************************************************/ GNUNET_NETWORK_STRUCT_BEGIN /** * Message for a client to register to the service */ struct GNUNET_MESH_ClientConnect { /** * Type: GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT * * Size: sizeof(struct GNUNET_MESH_ClientConnect) + * sizeof(MESH_ApplicationType) * applications + * sizeof(uint16_t) * types */ struct GNUNET_MessageHeader header; uint16_t applications GNUNET_PACKED; uint16_t types GNUNET_PACKED; /* uint16_t list_apps[applications] */ /* uint16_t list_types[types] */ }; /** * Type for tunnel numbering. * - Local tunnel numbers given by the service (incoming) are >= 0xB0000000 * - Local tunnel numbers given by the client (created) are >= 0x80000000 * - Global tunnel numbers are < 0x80000000 */ typedef uint32_t MESH_TunnelNumber; /** * Message for a client to create and destroy tunnels. */ struct GNUNET_MESH_TunnelMessage { /** * Type: GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_[CREATE|DESTROY] * * Size: sizeof(struct GNUNET_MESH_TunnelMessage) */ struct GNUNET_MessageHeader header; /** * ID of a tunnel controlled by this client. */ MESH_TunnelNumber tunnel_id GNUNET_PACKED; }; /** * Message for the service to let a client know about created tunnels. */ struct GNUNET_MESH_TunnelNotification { /** * Type: GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE * * Size: sizeof(struct GNUNET_MESH_TunnelMessage) */ struct GNUNET_MessageHeader header; /** * ID of a tunnel controlled by this client. */ MESH_TunnelNumber tunnel_id GNUNET_PACKED; /** * Peer at the other end, if any */ struct GNUNET_PeerIdentity peer; }; /** * Message for: * - request adding and deleting peers from a tunnel * - notify the client that peers have connected: * -- requested * -- unrequested (new incoming tunnels) * - notify the client that peers have disconnected */ struct GNUNET_MESH_PeerControl { /** * Type: GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_[ADD|DEL] * (client to service, client created tunnel) * GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_[CONNECTED|DISCONNECTED] * (service to client) * * Size: sizeof(struct GNUNET_MESH_PeerControl) */ struct GNUNET_MessageHeader header; /** * ID of a tunnel controlled by this client. */ MESH_TunnelNumber tunnel_id GNUNET_PACKED; /** * Peer to connect/disconnect. */ struct GNUNET_PeerIdentity peer; }; /** * Message for connecting to peers offering a certain service. */ struct GNUNET_MESH_ConnectPeerByType { /** * Type: GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_BY_TYPE | * GNUNET_MESSAGE_TYPE_MESH_LOCAL_DISCONNECT_PEER_BY_TYPE */ struct GNUNET_MessageHeader header; /** * ID of a tunnel controlled by this client. */ MESH_TunnelNumber tunnel_id GNUNET_PACKED; /** * Type specification */ GNUNET_MESH_ApplicationType type GNUNET_PACKED; }; GNUNET_NETWORK_STRUCT_END /******************************************************************************/ /************************ ENUMERATIONS ****************************/ /******************************************************************************/ /** * All the states a peer participating in a tunnel can be in. */ enum MeshPeerState { /** * Uninitialized status, should never appear in operation. */ MESH_PEER_INVALID, /** * Peer is the root and owner of the tree */ MESH_PEER_ROOT, /** * Peer only retransmits traffic, is not a final destination */ MESH_PEER_RELAY, /** * Path to the peer not known yet */ MESH_PEER_SEARCHING, /** * Request sent, not yet answered. */ MESH_PEER_WAITING, /** * Peer connected and ready to accept data */ MESH_PEER_READY, /** * Peer connected previosly but not responding */ MESH_PEER_RECONNECTING }; #endif gnunet-0.9.3/src/mesh/gnunet-service-mesh.c0000644000175000017500000042714211760516063015542 00000000000000/* This file is part of GNUnet. (C) 2001 - 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file mesh/gnunet-service-mesh.c * @brief GNUnet MESH service * @author Bartlomiej Polot * * STRUCTURE: * - DATA STRUCTURES * - GLOBAL VARIABLES * - GENERAL HELPERS * - PERIODIC FUNCTIONS * - MESH NETWORK HANDLER HELPERS * - MESH NETWORK HANDLES * - MESH LOCAL HANDLER HELPERS * - MESH LOCAL HANDLES * - MAIN FUNCTIONS (main & run) * * TODO: * - error reporting (CREATE/CHANGE/ADD/DEL?) -- new message! * - partial disconnect reporting -- same as error reporting? * - add vs create? change vs. keep-alive? same msg or different ones? -- thinking... * - speed requirement specification (change?) in mesh API -- API call * - add ping message * - relay corking down to core * - set ttl relative to tree depth * TODO END */ #include "platform.h" #include "mesh.h" #include "mesh_protocol.h" #include "gnunet_dht_service.h" #include "mesh_tunnel_tree.h" /* TODO: move into configuration file */ #define REFRESH_PATH_TIME GNUNET_TIME_relative_multiply(\ GNUNET_TIME_UNIT_SECONDS,\ 300) #define APP_ANNOUNCE_TIME GNUNET_TIME_relative_multiply(\ GNUNET_TIME_UNIT_SECONDS,\ 5) #define ID_ANNOUNCE_TIME GNUNET_TIME_relative_multiply(\ GNUNET_TIME_UNIT_SECONDS,\ 5) #define UNACKNOWLEDGED_WAIT GNUNET_TIME_relative_multiply(\ GNUNET_TIME_UNIT_SECONDS,\ 2) #define DEFAULT_TTL 64 /* TODO END */ #define MESH_DEBUG_DHT GNUNET_YES #define MESH_DEBUG_CONNECTION GNUNET_NO #if MESH_DEBUG_CONNECTION #define DEBUG_CONN(...) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__) #else #define DEBUG_CONN(...) #endif #if MESH_DEBUG_DHT #define DEBUG_DHT(...) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__) #else #define DEBUG_DHT(...) #endif /******************************************************************************/ /************************ DATA STRUCTURES ****************************/ /******************************************************************************/ /** FWD declaration */ struct MeshPeerInfo; /** * Struct representing a piece of data being sent to other peers */ struct MeshData { /** Tunnel it belongs to. */ struct MeshTunnel *t; /** In case of a multicast, task to allow a client to send more data if * some neighbor is too slow. */ GNUNET_SCHEDULER_TaskIdentifier *task; /** How many remaining neighbors we need to send this to. */ unsigned int *reference_counter; /** Size of the data. */ size_t data_len; /** Data itself */ void *data; }; /** * Struct containing all info possibly needed to build a package when called * back by core. */ struct MeshTransmissionDescriptor { /** ID of the tunnel this packet travels in */ struct MESH_TunnelID *origin; /** Who was this message being sent to */ struct MeshPeerInfo *peer; /** Ultimate destination of the packet */ GNUNET_PEER_Id destination; /** Which handler was used to request the transmission */ unsigned int handler_n; /** Data descriptor */ struct MeshData* mesh_data; }; /** * Struct containing all information regarding a given peer */ struct MeshPeerInfo { /** * ID of the peer */ GNUNET_PEER_Id id; /** * Last time we heard from this peer */ struct GNUNET_TIME_Absolute last_contact; /** * Number of attempts to reconnect so far */ int n_reconnect_attempts; /** * Paths to reach the peer, ordered by ascending hop count */ struct MeshPeerPath *path_head; /** * Paths to reach the peer, ordered by ascending hop count */ struct MeshPeerPath *path_tail; /** * Handle to stop the DHT search for a path to this peer */ struct GNUNET_DHT_GetHandle *dhtget; /** * Closure given to the DHT GET */ struct MeshPathInfo *dhtgetcls; /** * Handles to stop queued transmissions for this peer */ struct GNUNET_CORE_TransmitHandle *core_transmit[CORE_QUEUE_SIZE]; /** * Pointer to info stuctures used as cls for queued transmissions */ void *infos[CORE_QUEUE_SIZE]; /** * Type of message being in each transmission */ uint16_t types[CORE_QUEUE_SIZE]; /** * Array of tunnels this peer participates in * (most probably a small amount, therefore not a hashmap) * When the path to the peer changes, notify these tunnels to let them * re-adjust their path trees. */ struct MeshTunnel **tunnels; /** * Number of tunnels this peers participates in */ unsigned int ntunnels; }; /** * Data scheduled to transmit (to local client or remote peer) */ struct MeshQueue { /** * Double linked list */ struct MeshQueue *next; struct MeshQueue *prev; /** * Target of the data (NULL if target is client) */ struct MeshPeerInfo *peer; /** * Client to send the data to (NULL if target is peer) */ struct MeshClient *client; /** * Size of the message to transmit */ unsigned int size; /** * How old is the data? */ struct GNUNET_TIME_Absolute timestamp; /** * Data itself */ struct GNUNET_MessageHeader *data; }; /** * Globally unique tunnel identification (owner + number) * DO NOT USE OVER THE NETWORK */ struct MESH_TunnelID { /** * Node that owns the tunnel */ GNUNET_PEER_Id oid; /** * Tunnel number to differentiate all the tunnels owned by the node oid * ( tid < GNUNET_MESH_LOCAL_TUNNEL_ID_CLI ) */ MESH_TunnelNumber tid; }; struct MeshClient; /* FWD declaration */ /** * Struct containing all information regarding a tunnel * For an intermediate node the improtant info used will be: * - id Tunnel unique identification * - paths[0] To know where to send it next * - metainfo: ready, speeds, accounting */ struct MeshTunnel { /** * Tunnel ID */ struct MESH_TunnelID id; /** * Local tunnel number ( >= GNUNET_MESH_LOCAL_TUNNEL_ID_CLI or 0 ) */ MESH_TunnelNumber local_tid; /** * Local tunnel number for local destination clients (incoming number) * ( >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV or 0). All clients share the same * number. */ MESH_TunnelNumber local_tid_dest; /** * ID of the last multicast packet seen/sent. */ uint32_t mid; /** * Last time the tunnel was used */ struct GNUNET_TIME_Absolute timestamp; /** * Peers in the tunnel, indexed by PeerIdentity -> (MeshPeerInfo) * containing peers added by id or by type, not intermediate peers. */ struct GNUNET_CONTAINER_MultiHashMap *peers; /** * Number of peers that are connected and potentially ready to receive data */ unsigned int peers_ready; /** * Number of peers that have been added to the tunnel */ unsigned int peers_total; /** * Client owner of the tunnel, if any */ struct MeshClient *owner; /** * Clients that have been informed about the tunnel, if any */ struct MeshClient **clients; /** * Number of elements in clients */ unsigned int nclients; /** * Clients that have requested to leave the tunnel */ struct MeshClient **ignore; /** * Number of elements in clients */ unsigned int nignore; /** * Messages ready to transmit */ struct MeshQueue *queue_head; struct MeshQueue *queue_tail; /** * Tunnel paths */ struct MeshTunnelTree *tree; /** * Application type we are looking for in this tunnel */ GNUNET_MESH_ApplicationType type; /** * Used to search peers offering a service */ struct GNUNET_DHT_GetHandle *dht_get_type; /** * Task to keep the used paths alive */ GNUNET_SCHEDULER_TaskIdentifier path_refresh_task; /** * Task to destroy the tunnel after timeout * * FIXME: merge the two? a tunnel will have either * a path refresh OR a timeout, never both! */ GNUNET_SCHEDULER_TaskIdentifier timeout_task; }; /** * Info needed to work with tunnel paths and peers */ struct MeshPathInfo { /** * Tunnel */ struct MeshTunnel *t; /** * Neighbouring peer to whom we send the packet to */ struct MeshPeerInfo *peer; /** * Path itself */ struct MeshPeerPath *path; /** * Position in peer's transmit queue */ unsigned int pos; }; /** * Struct containing information about a client of the service */ struct MeshClient { /** * Linked list next */ struct MeshClient *next; /** * Linked list prev */ struct MeshClient *prev; /** * Tunnels that belong to this client, indexed by local id */ struct GNUNET_CONTAINER_MultiHashMap *own_tunnels; /** * Tunnels this client has accepted, indexed by incoming local id */ struct GNUNET_CONTAINER_MultiHashMap *incoming_tunnels; /** * Tunnels this client has rejected, indexed by incoming local id */ struct GNUNET_CONTAINER_MultiHashMap *ignore_tunnels; /** * Handle to communicate with the client */ struct GNUNET_SERVER_Client *handle; /** * Applications that this client has claimed to provide */ struct GNUNET_CONTAINER_MultiHashMap *apps; /** * Messages that this client has declared interest in */ struct GNUNET_CONTAINER_MultiHashMap *types; /** * Whether the client is active or shutting down (don't send confirmations * to a client that is shutting down. */ int shutting_down; /** * ID of the client, mainly for debug messages */ unsigned int id; }; /******************************************************************************/ /************************ DEBUG FUNCTIONS ****************************/ /******************************************************************************/ #if MESH_DEBUG /** * GNUNET_SCHEDULER_Task for printing a message after some operation is done * @param cls string to print * @param success GNUNET_OK if the PUT was transmitted, * GNUNET_NO on timeout, * GNUNET_SYSERR on disconnect from service * after the PUT message was transmitted * (so we don't know if it was received or not) */ #if 0 static void mesh_debug (void *cls, int success) { char *s = cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s (%d)\n", s, success); } #endif #endif /******************************************************************************/ /*********************** GLOBAL VARIABLES ****************************/ /******************************************************************************/ /** * All the clients */ static struct MeshClient *clients; static struct MeshClient *clients_tail; /** * Tunnels known, indexed by MESH_TunnelID (MeshTunnel) */ static struct GNUNET_CONTAINER_MultiHashMap *tunnels; /** * Tunnels incoming, indexed by MESH_TunnelNumber * (which is greater than GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) */ static struct GNUNET_CONTAINER_MultiHashMap *incoming_tunnels; /** * Peers known, indexed by PeerIdentity (MeshPeerInfo) */ static struct GNUNET_CONTAINER_MultiHashMap *peers; /** * Handle to communicate with core */ static struct GNUNET_CORE_Handle *core_handle; /** * Handle to communicate with transport */ // static struct GNUNET_TRANSPORT_Handle *transport_handle; /** * Handle to use DHT */ static struct GNUNET_DHT_Handle *dht_handle; /** * Handle to server */ static struct GNUNET_SERVER_Handle *server_handle; /** * Notification context, to send messages to local clients */ static struct GNUNET_SERVER_NotificationContext *nc; /** * Local peer own ID (memory efficient handle) */ static GNUNET_PEER_Id myid; /** * Local peer own ID (full value) */ static struct GNUNET_PeerIdentity my_full_id; /** * Own private key */ static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; /** * Own public key. */ static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; /** * Tunnel ID for the next created tunnel (global tunnel number) */ static MESH_TunnelNumber next_tid; /** * Tunnel ID for the next incoming tunnel (local tunnel number) */ static MESH_TunnelNumber next_local_tid; /** * All application types provided by this peer */ static struct GNUNET_CONTAINER_MultiHashMap *applications; /** * All message types clients of this peer are interested in */ static struct GNUNET_CONTAINER_MultiHashMap *types; /** * Task to periodically announce provided applications */ GNUNET_SCHEDULER_TaskIdentifier announce_applications_task; /** * Task to periodically announce itself in the network */ GNUNET_SCHEDULER_TaskIdentifier announce_id_task; /** * Next ID to assign to a client */ unsigned int next_client_id; /******************************************************************************/ /************************ ITERATORS ****************************/ /******************************************************************************/ /* FIXME move iterators here */ /******************************************************************************/ /************************ PERIODIC FUNCTIONS ****************************/ /******************************************************************************/ /** * Announce iterator over for each application provided by the peer * * @param cls closure * @param key current key code * @param value value in the hash map * @return GNUNET_YES if we should continue to * iterate, * GNUNET_NO if not. */ static int announce_application (void *cls, const GNUNET_HashCode * key, void *value) { /* FIXME are hashes in multihash map equal on all aquitectures? */ /* FIXME: keep return value of 'put' to possibly cancel!? */ GNUNET_DHT_put (dht_handle, key, 10, GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, GNUNET_BLOCK_TYPE_TEST, sizeof (struct GNUNET_PeerIdentity), (const char *) &my_full_id, GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), APP_ANNOUNCE_TIME), APP_ANNOUNCE_TIME, NULL, NULL); return GNUNET_OK; } /** * Periodically announce what applications are provided by local clients * * @param cls closure * @param tc task context */ static void announce_applications (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) { announce_applications_task = GNUNET_SCHEDULER_NO_TASK; return; } DEBUG_DHT ("Starting PUT for apps\n"); GNUNET_CONTAINER_multihashmap_iterate (applications, &announce_application, NULL); announce_applications_task = GNUNET_SCHEDULER_add_delayed (APP_ANNOUNCE_TIME, &announce_applications, cls); DEBUG_DHT ("Finished PUT for apps\n"); return; } /** * Periodically announce self id in the DHT * * @param cls closure * @param tc task context */ static void announce_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) { announce_id_task = GNUNET_SCHEDULER_NO_TASK; return; } /* TODO * - Set data expiration in function of X * - Adapt X to churn */ DEBUG_DHT ("DHT_put for ID %s started.\n", GNUNET_i2s (&my_full_id)); GNUNET_DHT_put (dht_handle, /* DHT handle */ &my_full_id.hashPubKey, /* Key to use */ 10, /* Replication level */ GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, /* DHT options */ GNUNET_BLOCK_TYPE_TEST, /* Block type */ sizeof (my_full_id), /* Size of the data */ (char *) &my_full_id, /* Data itself */ GNUNET_TIME_UNIT_FOREVER_ABS, /* Data expiration */ GNUNET_TIME_UNIT_FOREVER_REL, /* Retry time */ NULL, /* Continuation */ NULL); /* Continuation closure */ announce_id_task = GNUNET_SCHEDULER_add_delayed (ID_ANNOUNCE_TIME, &announce_id, cls); } /** * Function to process paths received for a new peer addition. The recorded * paths form the initial tunnel, which can be optimized later. * Called on each result obtained for the DHT search. * * @param cls closure * @param exp when will this value expire * @param key key of the result * @param type type of the result * @param size number of bytes in data * @param data pointer to the result data */ static void dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int put_path_length, enum GNUNET_BLOCK_Type type, size_t size, const void *data); /******************************************************************************/ /****************** GENERAL HELPER FUNCTIONS ************************/ /******************************************************************************/ /** * Search for a tunnel by global ID using full PeerIdentities * * @param oid owner of the tunnel * @param tid global tunnel number * * @return tunnel handler, NULL if doesn't exist */ static struct MeshTunnel * tunnel_get (struct GNUNET_PeerIdentity *oid, MESH_TunnelNumber tid); /** * Delete an active client from the tunnel. * * @param t Tunnel. * @param c Client. */ static void tunnel_delete_active_client (struct MeshTunnel *t, const struct MeshClient *c); /** * Notify a tunnel that a connection has broken that affects at least * some of its peers. * * @param t Tunnel affected. * @param p1 Peer that got disconnected from p2. * @param p2 Peer that got disconnected from p1. * * @return Short ID of the peer disconnected (either p1 or p2). * 0 if the tunnel remained unaffected. */ static GNUNET_PEER_Id tunnel_notify_connection_broken (struct MeshTunnel *t, GNUNET_PEER_Id p1, GNUNET_PEER_Id p2); /** * Check if client has registered with the service and has not disconnected * * @param client the client to check * * @return non-NULL if client exists in the global DLL */ static struct MeshClient * client_get (struct GNUNET_SERVER_Client *client) { struct MeshClient *c; c = clients; while (NULL != c) { if (c->handle == client) return c; c = c->next; } return NULL; } /** * Checks if a given client has subscribed to certain message type * * @param message_type Type of message to check * @param c Client to check * * @return GNUNET_YES or GNUNET_NO, depending on subscription status * * TODO inline? */ static int client_is_subscribed (uint16_t message_type, struct MeshClient *c) { GNUNET_HashCode hc; GNUNET_CRYPTO_hash (&message_type, sizeof (uint16_t), &hc); return GNUNET_CONTAINER_multihashmap_contains (c->types, &hc); } /** * Allow a client to send more data after transmitting a multicast message * which some neighbor has not yet accepted altough a reasonable time has * passed. * * @param cls Closure (DataDescriptor containing the task identifier) * @param tc Task Context * * FIXME reference counter cshould be just int */ static void client_allow_send (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct MeshData *mdata = cls; if (GNUNET_SCHEDULER_REASON_SHUTDOWN == tc->reason) return; GNUNET_assert (NULL != mdata->reference_counter); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CLIENT ALLOW SEND DESPITE %u COPIES PENDING\n", *(mdata->reference_counter)); *(mdata->task) = GNUNET_SCHEDULER_NO_TASK; GNUNET_SERVER_receive_done (mdata->t->owner->handle, GNUNET_OK); } /** * Check whether client wants traffic from a tunnel. * * @param c Client to check. * @param t Tunnel to be found. * * @return GNUNET_YES if client knows tunnel. * * TODO look in client hashmap */ static int client_wants_tunnel (struct MeshClient *c, struct MeshTunnel *t) { unsigned int i; for (i = 0; i < t->nclients; i++) if (t->clients[i] == c) return GNUNET_YES; return GNUNET_NO; } /** * Check whether client has been informed about a tunnel. * * @param c Client to check. * @param t Tunnel to be found. * * @return GNUNET_YES if client knows tunnel. * * TODO look in client hashmap */ static int client_knows_tunnel (struct MeshClient *c, struct MeshTunnel *t) { unsigned int i; for (i = 0; i < t->nignore; i++) if (t->ignore[i] == c) return GNUNET_YES; return client_wants_tunnel(c, t); } /** * Marks a client as uninterested in traffic from the tunnel, updating both * client and tunnel to reflect this. * * @param c Client that doesn't want traffic anymore. * @param t Tunnel which should be ignored. * * FIXME when to delete an incoming tunnel? */ static void client_ignore_tunnel (struct MeshClient *c, struct MeshTunnel *t) { GNUNET_HashCode hash; GNUNET_CRYPTO_hash(&t->local_tid_dest, sizeof (MESH_TunnelNumber), &hash); GNUNET_break (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (c->incoming_tunnels, &hash, t)); GNUNET_break (GNUNET_YES == GNUNET_CONTAINER_multihashmap_put (c->ignore_tunnels, &hash, t, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); tunnel_delete_active_client (t, c); GNUNET_array_append (t->ignore, t->nignore, c); } /** * Deletes a tunnel from a client (either owner or destination). To be used on * tunnel destroy, otherwise, use client_ignore_tunnel. * * @param c Client whose tunnel to delete. * @param t Tunnel which should be deleted. */ static void client_delete_tunnel (struct MeshClient *c, struct MeshTunnel *t) { GNUNET_HashCode hash; if (c == t->owner) { GNUNET_CRYPTO_hash(&t->local_tid, sizeof (MESH_TunnelNumber), &hash); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (c->own_tunnels, &hash, t)); } else { GNUNET_CRYPTO_hash(&t->local_tid_dest, sizeof (MESH_TunnelNumber), &hash); // FIXME XOR? GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (c->incoming_tunnels, &hash, t) || GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (c->ignore_tunnels, &hash, t)); } } /** * Send the message to all clients that have subscribed to its type * * @param msg Pointer to the message itself * @param payload Pointer to the payload of the message. * @return number of clients this message was sent to */ static unsigned int send_subscribed_clients (const struct GNUNET_MessageHeader *msg, const struct GNUNET_MessageHeader *payload) { struct GNUNET_PeerIdentity *oid; struct MeshClient *c; struct MeshTunnel *t; MESH_TunnelNumber *tid; unsigned int count; uint16_t type; char cbuf[htons (msg->size)]; type = ntohs (payload->type); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending to clients...\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "message of type %u\n", type); memcpy (cbuf, msg, sizeof (cbuf)); switch (htons (msg->type)) { struct GNUNET_MESH_Unicast *uc; struct GNUNET_MESH_Multicast *mc; struct GNUNET_MESH_ToOrigin *to; case GNUNET_MESSAGE_TYPE_MESH_UNICAST: uc = (struct GNUNET_MESH_Unicast *) cbuf; tid = &uc->tid; oid = &uc->oid; break; case GNUNET_MESSAGE_TYPE_MESH_MULTICAST: mc = (struct GNUNET_MESH_Multicast *) cbuf; tid = &mc->tid; oid = &mc->oid; break; case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN: to = (struct GNUNET_MESH_ToOrigin *) cbuf; tid = &to->tid; oid = &to->oid; break; default: GNUNET_break (0); return 0; } t = tunnel_get (oid, ntohl (*tid)); if (NULL == t) { GNUNET_break (0); return 0; } for (count = 0, c = clients; c != NULL; c = c->next) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " client %u\n", c->id); if (client_is_subscribed (type, c)) { if (htons (msg->type) == GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN) { if (c != t->owner) continue; *tid = htonl (t->local_tid); } else { if (GNUNET_NO == client_knows_tunnel (c, t)) { /* This client doesn't know the tunnel */ struct GNUNET_MESH_TunnelNotification tmsg; GNUNET_HashCode hash; tmsg.header.size = htons (sizeof (tmsg)); tmsg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE); GNUNET_PEER_resolve (t->id.oid, &tmsg.peer); tmsg.tunnel_id = htonl (t->local_tid_dest); GNUNET_SERVER_notification_context_unicast (nc, c->handle, &tmsg.header, GNUNET_NO); GNUNET_array_append (t->clients, t->nclients, c); GNUNET_CRYPTO_hash (&t->local_tid_dest, sizeof (MESH_TunnelNumber), &hash); GNUNET_break (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put ( c->incoming_tunnels, &hash, t, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); } *tid = htonl (t->local_tid_dest); } /* Check if the client wants to get traffic from the tunnel */ if (GNUNET_NO == client_wants_tunnel(c, t)) continue; count++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " sending\n"); GNUNET_SERVER_notification_context_unicast (nc, c->handle, (struct GNUNET_MessageHeader *) cbuf, GNUNET_YES); } } return count; } /** * Notify the client that owns the tunnel that a peer has connected to it * (the requested path to it has been confirmed). * * @param t Tunnel whose owner to notify * @param id Short id of the peer that has connected */ static void send_client_peer_connected (const struct MeshTunnel *t, const GNUNET_PEER_Id id) { struct GNUNET_MESH_PeerControl pc; pc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD); pc.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl)); pc.tunnel_id = htonl (t->local_tid); GNUNET_PEER_resolve (id, &pc.peer); GNUNET_SERVER_notification_context_unicast (nc, t->owner->handle, &pc.header, GNUNET_NO); } /** * Notify all clients (not depending on registration status) that the incoming * tunnel is no longer valid. * * @param t Tunnel that was destroyed. */ static void send_clients_tunnel_destroy (struct MeshTunnel *t) { struct GNUNET_MESH_TunnelMessage msg; msg.header.size = htons (sizeof (msg)); msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY); msg.tunnel_id = htonl (t->local_tid_dest); GNUNET_SERVER_notification_context_broadcast (nc, &msg.header, GNUNET_NO); } /** * Notify clients of tunnel disconnections, if needed. * In case the origin disconnects, the destination clients get a tunnel destroy * notification. If the last destination disconnects (only one remaining client * in tunnel), the origin gets a (local ID) peer disconnected. * Note that the function must be called BEFORE removing the client from * the tunnel. * * @param t Tunnel that was destroyed. * @param c Client that disconnected. */ static void send_client_tunnel_disconnect (struct MeshTunnel *t, struct MeshClient *c) { unsigned int i; if (c == t->owner) { struct GNUNET_MESH_TunnelMessage msg; msg.header.size = htons (sizeof (msg)); msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY); msg.tunnel_id = htonl (t->local_tid_dest); for (i = 0; i < t->nclients; i++) GNUNET_SERVER_notification_context_unicast (nc, t->clients[i]->handle, &msg.header, GNUNET_NO); } // FIXME when to disconnect an incoming tunnel? else if (1 == t->nclients && NULL != t->owner) { struct GNUNET_MESH_PeerControl msg; msg.header.size = htons (sizeof (msg)); msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL); msg.tunnel_id = htonl (t->local_tid); msg.peer = my_full_id; GNUNET_SERVER_notification_context_unicast (nc, t->owner->handle, &msg.header, GNUNET_NO); } } /** * Function called to notify a client about the socket * being ready to queue more data. "buf" will be * NULL and "size" zero if the socket was closed for * writing in the meantime. * * @param cls closure * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t send_core_create_path (void *cls, size_t size, void *buf); /** * Function called to notify a client about the socket * being ready to queue more data. "buf" will be * NULL and "size" zero if the socket was closed for * writing in the meantime. * * @param cls closure (data itself) * @param size number of bytes available in buf * @param buf where the callee should write the message * * @return number of bytes written to buf */ static size_t send_core_data_multicast (void *cls, size_t size, void *buf); /** * Decrements the reference counter and frees all resources if needed * * @param mesh_data Data Descriptor used in a multicast message. * Freed no longer needed (last message). */ static void data_descriptor_decrement_multicast (struct MeshData *mesh_data) { /* Make sure it's a multicast packet */ GNUNET_assert (NULL != mesh_data->reference_counter); if (0 == --(*(mesh_data->reference_counter))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Last copy!\n"); if (NULL != mesh_data->task) { if (GNUNET_SCHEDULER_NO_TASK != *(mesh_data->task)) { GNUNET_SCHEDULER_cancel (*(mesh_data->task)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " notifying client...\n"); GNUNET_SERVER_receive_done (mesh_data->t->owner->handle, GNUNET_OK); } GNUNET_free (mesh_data->task); } GNUNET_free (mesh_data->reference_counter); GNUNET_free (mesh_data->data); GNUNET_free (mesh_data); } } /** * Cancel a core transmission that was already requested and free all resources * associated to the request. * * @param peer PeeInfo of the peer whose transmission is cancelled. * @param i Position of the transmission to be cancelled. */ static void peer_info_cancel_transmission (struct MeshPeerInfo *peer, unsigned int i) { if (NULL != peer->core_transmit[i]) { struct MeshTransmissionDescriptor *dd; struct MeshPathInfo *path_info; #if MESH_DEBUG { struct GNUNET_PeerIdentity id; GNUNET_PEER_resolve (peer->id, &id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Cancelling data transmission at %s [%u]\n", GNUNET_i2s (&id), i); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " message type %u\n", peer->types[i]); } #endif /* TODO: notify that tranmission has failed */ switch (peer->types[i]) { case GNUNET_MESSAGE_TYPE_MESH_MULTICAST: case GNUNET_MESSAGE_TYPE_MESH_UNICAST: case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " type payload\n"); dd = peer->infos[i]; data_descriptor_decrement_multicast (dd->mesh_data); break; case GNUNET_MESSAGE_TYPE_MESH_PATH_CREATE: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " type create path\n"); path_info = peer->infos[i]; path_destroy (path_info->path); break; default: GNUNET_break (0); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " type unknown!\n"); } GNUNET_CORE_notify_transmit_ready_cancel (peer->core_transmit[i]); peer->core_transmit[i] = NULL; GNUNET_free (peer->infos[i]); } } /** * Get a unused CORE slot to transmit a message to a peer. If all the slots * are used, cancel one and return it's position. * * @param peer PeerInfo of the neighbor we want to transmit to. * * @return The index of an available slot to transmit to the neighbor. */ static unsigned int peer_info_transmit_slot (struct MeshPeerInfo *peer) { unsigned int i; for (i = 0; peer->core_transmit[i]; i++) { if (i == (CORE_QUEUE_SIZE - 1)) { /* All positions are taken! Overwriting! */ GNUNET_break (0); peer_info_cancel_transmission (peer, 0); return 0; } } return i; } /** * Retrieve the MeshPeerInfo stucture associated with the peer, create one * and insert it in the appropiate structures if the peer is not known yet. * * @param peer Full identity of the peer. * * @return Existing or newly created peer info. */ static struct MeshPeerInfo * peer_info_get (const struct GNUNET_PeerIdentity *peer) { struct MeshPeerInfo *peer_info; peer_info = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); if (NULL == peer_info) { peer_info = (struct MeshPeerInfo *) GNUNET_malloc (sizeof (struct MeshPeerInfo)); GNUNET_CONTAINER_multihashmap_put (peers, &peer->hashPubKey, peer_info, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); peer_info->id = GNUNET_PEER_intern (peer); } return peer_info; } /** * Retrieve the MeshPeerInfo stucture associated with the peer, create one * and insert it in the appropiate structures if the peer is not known yet. * * @param peer Short identity of the peer. * * @return Existing or newly created peer info. */ static struct MeshPeerInfo * peer_info_get_short (const GNUNET_PEER_Id peer) { struct GNUNET_PeerIdentity id; GNUNET_PEER_resolve (peer, &id); return peer_info_get (&id); } /** * Iterator to remove the tunnel from the list of tunnels a peer participates * in. * * @param cls Closure (tunnel info) * @param key GNUNET_PeerIdentity of the peer (unused) * @param value PeerInfo of the peer * * @return always GNUNET_YES, to keep iterating */ static int peer_info_delete_tunnel (void *cls, const GNUNET_HashCode * key, void *value) { struct MeshTunnel *t = cls; struct MeshPeerInfo *peer = value; unsigned int i; for (i = 0; i < peer->ntunnels; i++) { if (0 == memcmp (&peer->tunnels[i]->id, &t->id, sizeof (struct MESH_TunnelID))) { peer->ntunnels--; peer->tunnels[i] = peer->tunnels[peer->ntunnels]; peer->tunnels = GNUNET_realloc (peer->tunnels, peer->ntunnels); return GNUNET_YES; } } return GNUNET_YES; } /** * Core callback to write a * * @param cls Closure (MeshTransmissionDescriptor with data in "data" member). * @param size Number of bytes available in buf. * @param buf Where the to write the message. * * @return number of bytes written to buf */ static size_t send_core_data_raw (void *cls, size_t size, void *buf) { struct MeshTransmissionDescriptor *info = cls; struct GNUNET_MessageHeader *msg; size_t total_size; GNUNET_assert (NULL != info); GNUNET_assert (NULL != info->mesh_data); msg = (struct GNUNET_MessageHeader *) info->mesh_data->data; total_size = ntohs (msg->size); if (total_size > size) { struct GNUNET_PeerIdentity id; GNUNET_PEER_resolve (info->peer->id, &id); info->peer->core_transmit[info->handler_n] = GNUNET_CORE_notify_transmit_ready (core_handle, 0, 100, GNUNET_TIME_UNIT_FOREVER_REL, &id, size, &send_core_data_raw, info); return 0; } info->peer->core_transmit[info->handler_n] = NULL; memcpy (buf, msg, total_size); GNUNET_free (info->mesh_data); GNUNET_free (info); return total_size; } /** * Sends an already built message to a peer, properly registrating * all used resources. * * @param message Message to send. Fucntion makes a copy of it. * @param peer Short ID of the neighbor whom to send the message. * * FIXME tunnel? */ static void send_message (const struct GNUNET_MessageHeader *message, const struct GNUNET_PeerIdentity *peer) { struct MeshTransmissionDescriptor *info; struct MeshPeerInfo *neighbor; struct MeshPeerPath *p; unsigned int i; size_t size; // GNUNET_TRANSPORT_try_connect(); size = ntohs (message->size); info = GNUNET_malloc (sizeof (struct MeshTransmissionDescriptor)); info->mesh_data = GNUNET_malloc (sizeof (struct MeshData)); info->mesh_data->data = GNUNET_malloc (size); memcpy (info->mesh_data->data, message, size); info->mesh_data->data_len = size; neighbor = peer_info_get (peer); for (p = neighbor->path_head; NULL != p; p = p->next) { if (2 == p->length) { break; } } if (NULL == p) { GNUNET_break (0); GNUNET_free (info->mesh_data->data); GNUNET_free (info->mesh_data); GNUNET_free (info); return; } i = peer_info_transmit_slot (neighbor); info->handler_n = i; info->peer = neighbor; neighbor->types[i] = GNUNET_MESSAGE_TYPE_MESH_UNICAST; neighbor->infos[i] = info; neighbor->core_transmit[i] = GNUNET_CORE_notify_transmit_ready (core_handle, 0, 100, GNUNET_TIME_UNIT_FOREVER_REL, peer, size, &send_core_data_raw, info); } /** * Sends a CREATE PATH message for a path to a peer, properly registrating * all used resources. * * @param peer PeerInfo of the final peer for whom this path is being created. * @param p Path itself. * @param t Tunnel for which the path is created. */ static void send_create_path (struct MeshPeerInfo *peer, struct MeshPeerPath *p, struct MeshTunnel *t) { struct GNUNET_PeerIdentity id; struct MeshPathInfo *path_info; struct MeshPeerInfo *neighbor; unsigned int i; if (NULL == p) { p = tree_get_path_to_peer (t->tree, peer->id); if (NULL == p) { GNUNET_break (0); return; } } for (i = 0; i < p->length; i++) { if (p->peers[i] == myid) break; } if (i >= p->length - 1) { path_destroy (p); GNUNET_break (0); return; } GNUNET_PEER_resolve (p->peers[i + 1], &id); path_info = GNUNET_malloc (sizeof (struct MeshPathInfo)); path_info->path = p; path_info->t = t; neighbor = peer_info_get (&id); path_info->peer = neighbor; path_info->pos = peer_info_transmit_slot (neighbor); neighbor->types[path_info->pos] = GNUNET_MESSAGE_TYPE_MESH_PATH_CREATE; neighbor->infos[path_info->pos] = path_info; neighbor->core_transmit[path_info->pos] = GNUNET_CORE_notify_transmit_ready (core_handle, /* handle */ 0, /* cork */ 0, /* priority */ GNUNET_TIME_UNIT_FOREVER_REL, /* timeout */ &id, /* target */ sizeof (struct GNUNET_MESH_ManipulatePath) + (p->length * sizeof (struct GNUNET_PeerIdentity)), /*size */ &send_core_create_path, /* callback */ path_info); /* cls */ } /** * Sends a DESTROY PATH message to free resources for a path in a tunnel * * @param t Tunnel whose path to destroy. * @param destination Short ID of the peer to whom the path to destroy. */ static void send_destroy_path (struct MeshTunnel *t, GNUNET_PEER_Id destination) { struct MeshPeerPath *p; size_t size; p = tree_get_path_to_peer (t->tree, destination); if (NULL == p) { GNUNET_break (0); return; } size = sizeof (struct GNUNET_MESH_ManipulatePath); size += p->length * sizeof (struct GNUNET_PeerIdentity); { struct GNUNET_MESH_ManipulatePath *msg; struct GNUNET_PeerIdentity *pi; char cbuf[size]; unsigned int i; msg = (struct GNUNET_MESH_ManipulatePath *) cbuf; msg->header.size = htons (size); msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_PATH_DESTROY); msg->tid = htonl (t->id.tid); pi = (struct GNUNET_PeerIdentity *) &msg[1]; for (i = 0; i < p->length; i++) { GNUNET_PEER_resolve (p->peers[i], &pi[i]); } send_message (&msg->header, tree_get_first_hop (t->tree, destination)); } path_destroy (p); } /** * Try to establish a new connection to this peer. * Use the best path for the given tunnel. * If the peer doesn't have any path to it yet, try to get one. * If the peer already has some path, send a CREATE PATH towards it. * * @param peer PeerInfo of the peer. * @param t Tunnel for which to create the path, if possible. */ static void peer_info_connect (struct MeshPeerInfo *peer, struct MeshTunnel *t) { struct MeshPeerPath *p; struct MeshPathInfo *path_info; if (NULL != peer->path_head) { p = tree_get_path_to_peer (t->tree, peer->id); if (NULL == p) { GNUNET_break (0); return; } // FIXME always send create path to self if (p->length > 1) { send_create_path (peer, p, t); } else { GNUNET_HashCode hash; path_destroy (p); send_client_peer_connected (t, myid); t->local_tid_dest = next_local_tid++; GNUNET_CRYPTO_hash (&t->local_tid_dest, sizeof (MESH_TunnelNumber), &hash); if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (incoming_tunnels, &hash, t, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) { GNUNET_break (0); return; } } } else if (NULL == peer->dhtget) { struct GNUNET_PeerIdentity id; GNUNET_PEER_resolve (peer->id, &id); path_info = GNUNET_malloc (sizeof (struct MeshPathInfo)); path_info->peer = peer; path_info->t = t; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Starting DHT GET for peer %s\n", GNUNET_i2s (&id)); peer->dhtgetcls = path_info; peer->dhtget = GNUNET_DHT_get_start (dht_handle, /* handle */ GNUNET_BLOCK_TYPE_TEST, /* type */ &id.hashPubKey, /* key to search */ 10, /* replication level */ GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, NULL, /* xquery */ 0, /* xquery bits */ &dht_get_id_handler, path_info); } /* Otherwise, there is no path but the DHT get is already started. */ } /** * Task to delay the connection of a peer * * @param cls Closure (path info with tunnel and peer to connect). * Will be free'd on exection. * @param tc TaskContext */ static void peer_info_connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct MeshPathInfo *path_info = cls; if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) { GNUNET_free (cls); return; } peer_info_connect (path_info->peer, path_info->t); GNUNET_free (cls); } /** * Destroy the peer_info and free any allocated resources linked to it * * @param pi The peer_info to destroy. * * @return GNUNET_OK on success */ static int peer_info_destroy (struct MeshPeerInfo *pi) { struct GNUNET_PeerIdentity id; struct MeshPeerPath *p; struct MeshPeerPath *nextp; unsigned int i; GNUNET_PEER_resolve (pi->id, &id); GNUNET_PEER_change_rc (pi->id, -1); if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (peers, &id.hashPubKey, pi)) { GNUNET_break (0); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "removing peer %s, not in hashmap\n", GNUNET_i2s (&id)); } if (NULL != pi->dhtget) { GNUNET_DHT_get_stop (pi->dhtget); GNUNET_free (pi->dhtgetcls); } for (i = 0; i < CORE_QUEUE_SIZE; i++) { peer_info_cancel_transmission (pi, i); } p = pi->path_head; while (NULL != p) { nextp = p->next; GNUNET_CONTAINER_DLL_remove (pi->path_head, pi->path_tail, p); path_destroy (p); p = nextp; } GNUNET_free (pi); return GNUNET_OK; } /** * Remove all paths that rely on a direct connection between p1 and p2 * from the peer itself and notify all tunnels about it. * * @param peer PeerInfo of affected peer. * @param p1 GNUNET_PEER_Id of one peer. * @param p2 GNUNET_PEER_Id of another peer that was connected to the first and * no longer is. * * TODO: optimize (see below) */ static void peer_info_remove_path (struct MeshPeerInfo *peer, GNUNET_PEER_Id p1, GNUNET_PEER_Id p2) { struct MeshPeerPath *p; struct MeshPeerPath *aux; struct MeshPeerInfo *peer_d; GNUNET_PEER_Id d; unsigned int destroyed; unsigned int best; unsigned int cost; unsigned int i; destroyed = 0; p = peer->path_head; while (NULL != p) { aux = p->next; for (i = 0; i < (p->length - 1); i++) { if ((p->peers[i] == p1 && p->peers[i + 1] == p2) || (p->peers[i] == p2 && p->peers[i + 1] == p1)) { GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, p); path_destroy (p); destroyed++; break; } } p = aux; } if (0 == destroyed) return; for (i = 0; i < peer->ntunnels; i++) { d = tunnel_notify_connection_broken (peer->tunnels[i], p1, p2); if (0 == d) continue; /* TODO * Problem: one or more peers have been deleted from the tunnel tree. * We don't know who they are to try to add them again. * We need to try to find a new path for each of the disconnected peers. * Some of them might already have a path to reach them that does not * involve p1 and p2. Adding all anew might render in a better tree than * the trivial immediate fix. * * Trivial immiediate fix: try to reconnect to the disconnected node. All * its children will be reachable trough him. */ peer_d = peer_info_get_short (d); best = UINT_MAX; aux = NULL; for (p = peer_d->path_head; NULL != p; p = p->next) { if ((cost = tree_get_path_cost (peer->tunnels[i]->tree, p)) < best) { best = cost; aux = p; } } if (NULL != aux) { /* No callback, as peer will be already disconnected and a connection * scheduled by tunnel_notify_connection_broken. */ tree_add_path (peer->tunnels[i]->tree, aux, NULL, NULL); } else { peer_info_connect (peer_d, peer->tunnels[i]); } } } /** * Add the path to the peer and update the path used to reach it in case this * is the shortest. * * @param peer_info Destination peer to add the path to. * @param path New path to add. Last peer must be the peer in arg 1. * Path will be either used of freed if already known. * @param trusted Do we trust that this path is real? */ void peer_info_add_path (struct MeshPeerInfo *peer_info, struct MeshPeerPath *path, int trusted) { struct MeshPeerPath *aux; unsigned int l; unsigned int l2; if ((NULL == peer_info) || (NULL == path)) { GNUNET_break (0); path_destroy (path); return; } if (path->peers[path->length - 1] != peer_info->id) { GNUNET_break (0); path_destroy (path); return; } if (path->length <= 2 && GNUNET_NO == trusted) { /* Only allow CORE to tell us about direct paths */ path_destroy (path); return; } GNUNET_assert (peer_info->id == path->peers[path->length - 1]); for (l = 1; l < path->length; l++) { if (path->peers[l] == myid) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shortening path by %u\n", l); for (l2 = 0; l2 < path->length - l; l2++) { path->peers[l2] = path->peers[l + l2]; } path->length -= l; l = 1; path->peers = GNUNET_realloc (path->peers, path->length * sizeof (GNUNET_PEER_Id)); } } #if MESH_DEBUG { struct GNUNET_PeerIdentity id; GNUNET_PEER_resolve (peer_info->id, &id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "adding path [%u] to peer %s\n", path->length, GNUNET_i2s (&id)); } #endif l = path_get_length (path); if (0 == l) { GNUNET_free (path); return; } GNUNET_assert (peer_info->id == path->peers[path->length - 1]); for (aux = peer_info->path_head; aux != NULL; aux = aux->next) { l2 = path_get_length (aux); if (l2 > l) { GNUNET_CONTAINER_DLL_insert_before (peer_info->path_head, peer_info->path_tail, aux, path); return; } else { if (l2 == l && memcmp (path->peers, aux->peers, l) == 0) { path_destroy (path); return; } } } GNUNET_CONTAINER_DLL_insert_tail (peer_info->path_head, peer_info->path_tail, path); return; } /** * Add the path to the origin peer and update the path used to reach it in case * this is the shortest. * The path is given in peer_info -> destination, therefore we turn the path * upside down first. * * @param peer_info Peer to add the path to, being the origin of the path. * @param path New path to add after being inversed. * @param trusted Do we trust that this path is real? */ static void peer_info_add_path_to_origin (struct MeshPeerInfo *peer_info, struct MeshPeerPath *path, int trusted) { path_invert (path); peer_info_add_path (peer_info, path, trusted); } /** * Build a PeerPath from the paths returned from the DHT, reversing the paths * to obtain a local peer -> destination path and interning the peer ids. * * @return Newly allocated and created path */ static struct MeshPeerPath * path_build_from_dht (const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int put_path_length) { struct MeshPeerPath *p; GNUNET_PEER_Id id; int i; p = path_new (1); p->peers[0] = myid; GNUNET_PEER_change_rc (myid, 1); i = get_path_length; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " GET has %d hops.\n", i); for (i--; i >= 0; i--) { id = GNUNET_PEER_intern (&get_path[i]); if (p->length > 0 && id == p->peers[p->length - 1]) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Optimizing 1 hop out.\n"); GNUNET_PEER_change_rc (id, -1); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Adding from GET: %s.\n", GNUNET_i2s (&get_path[i])); p->length++; p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) * p->length); p->peers[p->length - 1] = id; } } i = put_path_length; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " PUT has %d hops.\n", i); for (i--; i >= 0; i--) { id = GNUNET_PEER_intern (&put_path[i]); if (id == myid) { /* PUT path went through us, so discard the path up until now and start * from here to get a much shorter (and loop-free) path. */ path_destroy (p); p = path_new (0); } if (p->length > 0 && id == p->peers[p->length - 1]) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Optimizing 1 hop out.\n"); GNUNET_PEER_change_rc (id, -1); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Adding from PUT: %s.\n", GNUNET_i2s (&put_path[i])); p->length++; p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) * p->length); p->peers[p->length - 1] = id; } } #if MESH_DEBUG if (get_path_length > 0) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " (first of GET: %s)\n", GNUNET_i2s (&get_path[0])); if (put_path_length > 0) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " (first of PUT: %s)\n", GNUNET_i2s (&put_path[0])); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " In total: %d hops\n", p->length); for (i = 0; i < p->length; i++) { struct GNUNET_PeerIdentity peer_id; GNUNET_PEER_resolve (p->peers[i], &peer_id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %u: %s\n", p->peers[i], GNUNET_i2s (&peer_id)); } #endif return p; } /** * Adds a path to the peer_infos of all the peers in the path * * @param p Path to process. * @param confirmed Whether we know if the path works or not. FIXME use */ static void path_add_to_peers (struct MeshPeerPath *p, int confirmed) { unsigned int i; /* TODO: invert and add */ for (i = 0; i < p->length && p->peers[i] != myid; i++) /* skip'em */ ; for (i++; i < p->length; i++) { struct MeshPeerInfo *aux; struct MeshPeerPath *copy; aux = peer_info_get_short (p->peers[i]); copy = path_duplicate (p); copy->length = i + 1; peer_info_add_path (aux, copy, GNUNET_NO); } } /** * Send keepalive packets for a peer * * @param cls Closure (tunnel for which to send the keepalive). * @param tc Notification context. * * TODO: implement explicit multicast keepalive? */ static void path_refresh (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Search for a tunnel among the incoming tunnels * * @param tid the local id of the tunnel * * @return tunnel handler, NULL if doesn't exist */ static struct MeshTunnel * tunnel_get_incoming (MESH_TunnelNumber tid) { GNUNET_HashCode hash; GNUNET_assert (tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV); GNUNET_CRYPTO_hash (&tid, sizeof (MESH_TunnelNumber), &hash); return GNUNET_CONTAINER_multihashmap_get (incoming_tunnels, &hash); } /** * Search for a tunnel among the tunnels for a client * * @param c the client whose tunnels to search in * @param tid the local id of the tunnel * * @return tunnel handler, NULL if doesn't exist */ static struct MeshTunnel * tunnel_get_by_local_id (struct MeshClient *c, MESH_TunnelNumber tid) { if (tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) { return tunnel_get_incoming (tid); } else { GNUNET_HashCode hash; GNUNET_CRYPTO_hash (&tid, sizeof (MESH_TunnelNumber), &hash); return GNUNET_CONTAINER_multihashmap_get (c->own_tunnels, &hash); } } /** * Search for a tunnel by global ID using PEER_ID * * @param pi owner of the tunnel * @param tid global tunnel number * * @return tunnel handler, NULL if doesn't exist */ static struct MeshTunnel * tunnel_get_by_pi (GNUNET_PEER_Id pi, MESH_TunnelNumber tid) { struct MESH_TunnelID id; GNUNET_HashCode hash; id.oid = pi; id.tid = tid; GNUNET_CRYPTO_hash (&id, sizeof (struct MESH_TunnelID), &hash); return GNUNET_CONTAINER_multihashmap_get (tunnels, &hash); } /** * Search for a tunnel by global ID using full PeerIdentities * * @param oid owner of the tunnel * @param tid global tunnel number * * @return tunnel handler, NULL if doesn't exist */ static struct MeshTunnel * tunnel_get (struct GNUNET_PeerIdentity *oid, MESH_TunnelNumber tid) { return tunnel_get_by_pi (GNUNET_PEER_search (oid), tid); } /** * Delete an active client from the tunnel. * * @param t Tunnel. * @param c Client. */ static void tunnel_delete_active_client (struct MeshTunnel *t, const struct MeshClient *c) { unsigned int i; for (i = 0; i < t->nclients; i++) { if (t->clients[i] == c) { t->clients[i] = t->clients[t->nclients - 1]; GNUNET_array_grow (t->clients, t->nclients, t->nclients - 1); break; } } } /** * Delete an ignored client from the tunnel. * * @param t Tunnel. * @param c Client. */ static void tunnel_delete_ignored_client (struct MeshTunnel *t, const struct MeshClient *c) { unsigned int i; for (i = 0; i < t->nignore; i++) { if (t->ignore[i] == c) { t->ignore[i] = t->ignore[t->nignore - 1]; GNUNET_array_grow (t->ignore, t->nignore, t->nignore - 1); break; } } } /** * Delete a client from the tunnel. It should be only done on * client disconnection, otherwise use client_ignore_tunnel. * * @param t Tunnel. * @param c Client. */ static void tunnel_delete_client (struct MeshTunnel *t, const struct MeshClient *c) { tunnel_delete_ignored_client (t, c); tunnel_delete_active_client (t, c); } /** * Callback used to notify a client owner of a tunnel that a peer has * disconnected, most likely because of a path change. * * @param cls Closure (tunnel this notification is about). * @param peer_id Short ID of disconnected peer. */ void notify_peer_disconnected (void *cls, GNUNET_PEER_Id peer_id) { struct MeshTunnel *t = cls; struct MeshPeerInfo *peer; struct MeshPathInfo *path_info; if (NULL != t->owner && NULL != nc) { struct GNUNET_MESH_PeerControl msg; msg.header.size = htons (sizeof (msg)); msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL); msg.tunnel_id = htonl (t->local_tid); GNUNET_PEER_resolve (peer_id, &msg.peer); GNUNET_SERVER_notification_context_unicast (nc, t->owner->handle, &msg.header, GNUNET_NO); } peer = peer_info_get_short (peer_id); path_info = GNUNET_malloc (sizeof (struct MeshPathInfo)); path_info->peer = peer; path_info->t = t; GNUNET_SCHEDULER_add_now (&peer_info_connect_task, path_info); } /** * Add a peer to a tunnel, accomodating paths accordingly and initializing all * needed rescources. * If peer already exists, reevaluate shortest path and change if different. * * @param t Tunnel we want to add a new peer to * @param peer PeerInfo of the peer being added * */ static void tunnel_add_peer (struct MeshTunnel *t, struct MeshPeerInfo *peer) { struct GNUNET_PeerIdentity id; struct MeshPeerPath *best_p; struct MeshPeerPath *p; unsigned int best_cost; unsigned int cost; GNUNET_PEER_resolve (peer->id, &id); if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (t->peers, &id.hashPubKey)) { t->peers_total++; GNUNET_array_append (peer->tunnels, peer->ntunnels, t); GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (t->peers, &id.hashPubKey, peer, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); } if (NULL != (p = peer->path_head)) { best_p = p; best_cost = tree_get_path_cost (t->tree, p); while (NULL != p) { if ((cost = tree_get_path_cost (t->tree, p)) < best_cost) { best_cost = cost; best_p = p; } p = p->next; } tree_add_path (t->tree, best_p, ¬ify_peer_disconnected, t); if (GNUNET_SCHEDULER_NO_TASK == t->path_refresh_task) t->path_refresh_task = GNUNET_SCHEDULER_add_delayed (REFRESH_PATH_TIME, &path_refresh, t); } else { /* Start a DHT get */ peer_info_connect (peer, t); } } /** * Add a path to a tunnel which we don't own, just to remember the next hop. * If destination node was already in the tunnel, the first hop information * will be replaced with the new path. * * @param t Tunnel we want to add a new peer to * @param p Path to add * @param own_pos Position of local node in path. * */ static void tunnel_add_path (struct MeshTunnel *t, struct MeshPeerPath *p, unsigned int own_pos) { struct GNUNET_PeerIdentity id; GNUNET_assert (0 != own_pos); tree_add_path (t->tree, p, NULL, NULL); if (own_pos < p->length - 1) { GNUNET_PEER_resolve (p->peers[own_pos + 1], &id); tree_update_first_hops (t->tree, myid, &id); } } /** * Notifies a tunnel that a connection has broken that affects at least * some of its peers. Sends a notification towards the root of the tree. * In case the peer is the owner of the tree, notifies the client that owns * the tunnel and tries to reconnect. * * @param t Tunnel affected. * @param p1 Peer that got disconnected from p2. * @param p2 Peer that got disconnected from p1. * * @return Short ID of the peer disconnected (either p1 or p2). * 0 if the tunnel remained unaffected. */ static GNUNET_PEER_Id tunnel_notify_connection_broken (struct MeshTunnel *t, GNUNET_PEER_Id p1, GNUNET_PEER_Id p2) { GNUNET_PEER_Id pid; pid = tree_notify_connection_broken (t->tree, p1, p2, ¬ify_peer_disconnected, t); if (myid != p1 && myid != p2) { return pid; } if (pid != myid) { if (tree_get_predecessor (t->tree) != 0) { /* We are the peer still connected, notify owner of the disconnection. */ struct GNUNET_MESH_PathBroken msg; struct GNUNET_PeerIdentity neighbor; msg.header.size = htons (sizeof (msg)); msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_PATH_BROKEN); GNUNET_PEER_resolve (t->id.oid, &msg.oid); msg.tid = htonl (t->id.tid); msg.peer1 = my_full_id; GNUNET_PEER_resolve (pid, &msg.peer2); GNUNET_PEER_resolve (tree_get_predecessor (t->tree), &neighbor); send_message (&msg.header, &neighbor); } } return pid; } /** * Send a multicast packet to a neighbor. * * @param cls Closure (Info about the multicast packet) * @param neighbor_id Short ID of the neighbor to send the packet to. */ static void tunnel_send_multicast_iterator (void *cls, GNUNET_PEER_Id neighbor_id) { struct MeshData *mdata = cls; struct MeshTransmissionDescriptor *info; struct GNUNET_PeerIdentity neighbor; unsigned int i; info = GNUNET_malloc (sizeof (struct MeshTransmissionDescriptor)); info->mesh_data = mdata; (*(mdata->reference_counter)) ++; info->destination = neighbor_id; GNUNET_PEER_resolve (neighbor_id, &neighbor); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " sending to %s...\n", GNUNET_i2s (&neighbor)); info->peer = peer_info_get (&neighbor); GNUNET_assert (NULL != info->peer); i = peer_info_transmit_slot (info->peer); info->handler_n = i; info->peer->infos[i] = info; info->peer->types[i] = GNUNET_MESSAGE_TYPE_MESH_MULTICAST; info->peer->core_transmit[i] = GNUNET_CORE_notify_transmit_ready (core_handle, 0, 0, GNUNET_TIME_UNIT_FOREVER_REL, &neighbor, info->mesh_data->data_len, &send_core_data_multicast, info); } /** * Send a message in a tunnel in multicast, sending a copy to each child node * down the local one in the tunnel tree. * * @param t Tunnel in which to send the data. * @param msg Message to be sent. * @param internal Has the service generated this message? */ static void tunnel_send_multicast (struct MeshTunnel *t, const struct GNUNET_MessageHeader *msg, int internal) { struct MeshData *mdata; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " sending a multicast packet...\n"); mdata = GNUNET_malloc (sizeof (struct MeshData)); mdata->data_len = ntohs (msg->size); mdata->reference_counter = GNUNET_malloc (sizeof (unsigned int)); mdata->t = t; mdata->data = GNUNET_malloc (mdata->data_len); memcpy (mdata->data, msg, mdata->data_len); if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_MESH_MULTICAST) { struct GNUNET_MESH_Multicast *mcast; mcast = (struct GNUNET_MESH_Multicast *) mdata->data; mcast->ttl = htonl (ntohl (mcast->ttl) - 1); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " data packet, ttl: %u\n", ntohl (mcast->ttl)); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " not a data packet, no ttl\n"); } if (NULL != t->owner && GNUNET_YES != t->owner->shutting_down && GNUNET_NO == internal) { mdata->task = GNUNET_malloc (sizeof (GNUNET_SCHEDULER_TaskIdentifier)); (*(mdata->task)) = GNUNET_SCHEDULER_add_delayed (UNACKNOWLEDGED_WAIT, &client_allow_send, mdata); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "timeout task %u\n", *(mdata->task)); } tree_iterate_children (t->tree, &tunnel_send_multicast_iterator, mdata); if (*(mdata->reference_counter) == 0) { GNUNET_free (mdata->data); GNUNET_free (mdata->reference_counter); if (NULL != mdata->task) { GNUNET_SCHEDULER_cancel(*(mdata->task)); GNUNET_free (mdata->task); GNUNET_SERVER_receive_done(t->owner->handle, GNUNET_OK); } // FIXME change order? GNUNET_free (mdata); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " sending a multicast packet done\n"); return; } /** * Send a message to all peers in this tunnel that the tunnel is no longer * valid. * * @param t The tunnel whose peers to notify. */ static void tunnel_send_destroy (struct MeshTunnel *t) { struct GNUNET_MESH_TunnelDestroy msg; msg.header.size = htons (sizeof (msg)); msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY); GNUNET_PEER_resolve (t->id.oid, &msg.oid); msg.tid = htonl (t->id.tid); tunnel_send_multicast (t, &msg.header, GNUNET_NO); } /** * Destroy the tunnel and free any allocated resources linked to it. * * @param t the tunnel to destroy * * @return GNUNET_OK on success */ static int tunnel_destroy (struct MeshTunnel *t) { struct MeshClient *c; struct MeshQueue *q; struct MeshQueue *qn; GNUNET_HashCode hash; unsigned int i; int r; if (NULL == t) return GNUNET_OK; r = GNUNET_OK; c = t->owner; #if MESH_DEBUG { struct GNUNET_PeerIdentity id; GNUNET_PEER_resolve (t->id.oid, &id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying tunnel %s [%x]\n", GNUNET_i2s (&id), t->id.tid); if (NULL != c) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); } #endif GNUNET_CRYPTO_hash (&t->id, sizeof (struct MESH_TunnelID), &hash); if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (tunnels, &hash, t)) { r = GNUNET_SYSERR; } GNUNET_CRYPTO_hash (&t->local_tid, sizeof (MESH_TunnelNumber), &hash); if (NULL != c && GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (c->own_tunnels, &hash, t)) { r = GNUNET_SYSERR; } GNUNET_CRYPTO_hash (&t->local_tid_dest, sizeof (MESH_TunnelNumber), &hash); for (i = 0; i < t->nclients; i++) { c = t->clients[i]; if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (c->incoming_tunnels, &hash, t)) { r = GNUNET_SYSERR; } } for (i = 0; i < t->nignore; i++) { c = t->ignore[i]; if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (c->ignore_tunnels, &hash, t)) { r = GNUNET_SYSERR; } } if (t->nclients > 0) { if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (incoming_tunnels, &hash, t)) { r = GNUNET_SYSERR; } GNUNET_free (t->clients); } if (NULL != t->peers) { GNUNET_CONTAINER_multihashmap_iterate (t->peers, &peer_info_delete_tunnel, t); GNUNET_CONTAINER_multihashmap_destroy (t->peers); } q = t->queue_head; while (NULL != q) { if (NULL != q->data) GNUNET_free (q->data); qn = q->next; GNUNET_free (q); q = qn; /* TODO cancel core transmit ready in case it was active */ } tree_destroy (t->tree); if (NULL != t->dht_get_type) GNUNET_DHT_get_stop (t->dht_get_type); if (GNUNET_SCHEDULER_NO_TASK != t->timeout_task) GNUNET_SCHEDULER_cancel (t->timeout_task); if (GNUNET_SCHEDULER_NO_TASK != t->path_refresh_task) GNUNET_SCHEDULER_cancel (t->path_refresh_task); GNUNET_free (t); return r; } /** * Removes an explicit path from a tunnel, freeing all intermediate nodes * that are no longer needed, as well as nodes of no longer reachable peers. * The tunnel itself is also destoyed if results in a remote empty tunnel. * * @param t Tunnel from which to remove the path. * @param peer Short id of the peer which should be removed. */ static void tunnel_delete_peer (struct MeshTunnel *t, GNUNET_PEER_Id peer) { if (GNUNET_NO == tree_del_peer (t->tree, peer, NULL, NULL)) tunnel_destroy (t); } /** * tunnel_destroy_iterator: iterator for deleting each tunnel that belongs to a * client when the client disconnects. If the client is not the owner, the * owner will get notified if no more clients are in the tunnel and the client * get removed from the tunnel's list. * * @param cls closure (client that is disconnecting) * @param key the hash of the local tunnel id (used to access the hashmap) * @param value the value stored at the key (tunnel to destroy) * * @return GNUNET_OK on success */ static int tunnel_destroy_iterator (void *cls, const GNUNET_HashCode * key, void *value) { struct MeshTunnel *t = value; struct MeshClient *c = cls; int r; send_client_tunnel_disconnect(t, c); if (c != t->owner) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %u is destination, keeping the tunnel alive.\n", c->id); tunnel_delete_client(t, c); client_delete_tunnel(c, t); return GNUNET_OK; } tunnel_send_destroy(t); r = tunnel_destroy (t); return r; } /** * Timeout function, destroys tunnel if called * * @param cls Closure (tunnel to destroy). * @param tc TaskContext */ static void tunnel_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct MeshTunnel *t = cls; if (GNUNET_SCHEDULER_REASON_SHUTDOWN == tc->reason) return; t->timeout_task = GNUNET_SCHEDULER_NO_TASK; tunnel_destroy (t); } /** * Resets the tunnel timeout. Starts it if no timeout was running. * * @param t Tunnel whose timeout to reset. */ static void tunnel_reset_timeout (struct MeshTunnel *t) { if (GNUNET_SCHEDULER_NO_TASK != t->timeout_task) GNUNET_SCHEDULER_cancel (t->timeout_task); t->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (REFRESH_PATH_TIME, 4), &tunnel_timeout, t); } /******************************************************************************/ /**************** MESH NETWORK HANDLER HELPERS ***********************/ /******************************************************************************/ /** * Function called to notify a client about the socket * being ready to queue more data. "buf" will be * NULL and "size" zero if the socket was closed for * writing in the meantime. * * @param cls closure * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t send_core_create_path (void *cls, size_t size, void *buf) { struct MeshPathInfo *info = cls; struct GNUNET_MESH_ManipulatePath *msg; struct GNUNET_PeerIdentity *peer_ptr; struct MeshPeerInfo *peer = info->peer; struct MeshTunnel *t = info->t; struct MeshPeerPath *p = info->path; size_t size_needed; int i; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CREATE PATH sending...\n"); size_needed = sizeof (struct GNUNET_MESH_ManipulatePath) + p->length * sizeof (struct GNUNET_PeerIdentity); if (size < size_needed || NULL == buf) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "create path retransmit!\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " buf: %p\n", buf); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " size: (%u/%u)\n", size, size_needed); info->peer->core_transmit[info->pos] = GNUNET_CORE_notify_transmit_ready (core_handle, 0, 0, GNUNET_TIME_UNIT_FOREVER_REL, tree_get_first_hop (t->tree, peer->id), size_needed, &send_core_create_path, info); return 0; } info->peer->core_transmit[info->pos] = NULL; #if MESH_DEBUG { struct GNUNET_PeerIdentity id; GNUNET_PEER_resolve (peer->id, &id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " setting core_transmit %s [%u] to NULL\n", GNUNET_i2s (&id), info->pos); } #endif msg = (struct GNUNET_MESH_ManipulatePath *) buf; msg->header.size = htons (size_needed); msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_PATH_CREATE); msg->tid = ntohl (t->id.tid); peer_ptr = (struct GNUNET_PeerIdentity *) &msg[1]; for (i = 0; i < p->length; i++) { GNUNET_PEER_resolve (p->peers[i], peer_ptr++); } path_destroy (p); GNUNET_free (info); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CREATE PATH (%u bytes long) sent!\n", size_needed); return size_needed; } /** * Function called to notify a client about the socket * being ready to queue more data. "buf" will be * NULL and "size" zero if the socket was closed for * writing in the meantime. * * @param cls closure (data itself) * @param size number of bytes available in buf * @param buf where the callee should write the message * * @return number of bytes written to buf */ static size_t send_core_data_multicast (void *cls, size_t size, void *buf) { struct MeshTransmissionDescriptor *info = cls; size_t total_size; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Multicast callback.\n"); GNUNET_assert (NULL != info); GNUNET_assert (NULL != info->peer); total_size = info->mesh_data->data_len; GNUNET_assert (total_size < GNUNET_SERVER_MAX_MESSAGE_SIZE); if (total_size > size) { /* Retry */ struct GNUNET_PeerIdentity id; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Multicast: retransmitting... (%u/%u)\n", size, total_size); GNUNET_PEER_resolve (info->peer->id, &id); info->peer->core_transmit[info->handler_n] = GNUNET_CORE_notify_transmit_ready (core_handle, 0, 0, GNUNET_TIME_UNIT_FOREVER_REL, &id, total_size, &send_core_data_multicast, info); return 0; } info->peer->core_transmit[info->handler_n] = NULL; info->peer->infos[info->handler_n] = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " copying data...\n"); memcpy (buf, info->mesh_data->data, total_size); #if MESH_DEBUG { struct GNUNET_MESH_Multicast *mc; struct GNUNET_MessageHeader *mh; mh = buf; if (ntohs (mh->type) == GNUNET_MESSAGE_TYPE_MESH_MULTICAST) { mc = (struct GNUNET_MESH_Multicast *) mh; mh = (struct GNUNET_MessageHeader *) &mc[1]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " multicast, payload type %u\n", ntohs (mh->type)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " multicast, payload size %u\n", ntohs (mh->size)); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " type %u\n", ntohs (mh->type)); } } #endif data_descriptor_decrement_multicast (info->mesh_data); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "freeing info...\n"); GNUNET_free (info); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "return %u\n", total_size); return total_size; } /** * Function called to notify a client about the socket * being ready to queue more data. "buf" will be * NULL and "size" zero if the socket was closed for * writing in the meantime. * * @param cls closure (MeshTransmissionDescriptor) * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t send_core_path_ack (void *cls, size_t size, void *buf) { struct MeshTransmissionDescriptor *info = cls; struct GNUNET_MESH_PathACK *msg = buf; GNUNET_assert (NULL != info); if (info->peer) { info->peer->core_transmit[info->handler_n] = NULL; } if (sizeof (struct GNUNET_MESH_PathACK) > size) { GNUNET_break (0); return 0; } msg->header.size = htons (sizeof (struct GNUNET_MESH_PathACK)); msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_PATH_ACK); GNUNET_PEER_resolve (info->origin->oid, &msg->oid); msg->tid = htonl (info->origin->tid); msg->peer_id = my_full_id; GNUNET_free (info); /* TODO add signature */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "PATH ACK sent!\n"); return sizeof (struct GNUNET_MESH_PathACK); } /******************************************************************************/ /******************** MESH NETWORK HANDLERS **************************/ /******************************************************************************/ /** * Core handler for path creation * * @param cls closure * @param message message * @param peer peer identity this notification is about * @param atsi performance data * @param atsi_count number of records in 'atsi' * * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_mesh_path_create (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { unsigned int own_pos; uint16_t size; uint16_t i; MESH_TunnelNumber tid; struct GNUNET_MESH_ManipulatePath *msg; struct GNUNET_PeerIdentity *pi; GNUNET_HashCode hash; struct MeshPeerPath *path; struct MeshPeerInfo *dest_peer_info; struct MeshPeerInfo *orig_peer_info; struct MeshTunnel *t; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received a path create msg [%s]\n", GNUNET_i2s (&my_full_id)); size = ntohs (message->size); if (size < sizeof (struct GNUNET_MESH_ManipulatePath)) { GNUNET_break_op (0); return GNUNET_OK; } size -= sizeof (struct GNUNET_MESH_ManipulatePath); if (size % sizeof (struct GNUNET_PeerIdentity)) { GNUNET_break_op (0); return GNUNET_OK; } size /= sizeof (struct GNUNET_PeerIdentity); if (size < 2) { GNUNET_break_op (0); return GNUNET_OK; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " path has %u hops.\n", size); msg = (struct GNUNET_MESH_ManipulatePath *) message; tid = ntohl (msg->tid); pi = (struct GNUNET_PeerIdentity *) &msg[1]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " path is for tunnel %s [%X].\n", GNUNET_i2s (pi), tid); t = tunnel_get (pi, tid); if (NULL == t) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Creating tunnel\n"); t = GNUNET_malloc (sizeof (struct MeshTunnel)); t->id.oid = GNUNET_PEER_intern (pi); t->id.tid = tid; while (NULL != tunnel_get_incoming (next_local_tid)) next_local_tid = (next_local_tid + 1) | GNUNET_MESH_LOCAL_TUNNEL_ID_SERV; t->local_tid_dest = next_local_tid++; next_local_tid = next_local_tid | GNUNET_MESH_LOCAL_TUNNEL_ID_SERV; t->tree = tree_new (t->id.oid); GNUNET_CRYPTO_hash (&t->id, sizeof (struct MESH_TunnelID), &hash); if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (tunnels, &hash, t, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) { tunnel_destroy (t); GNUNET_break (0); return GNUNET_OK; } tunnel_reset_timeout (t); GNUNET_CRYPTO_hash (&t->local_tid_dest, sizeof (MESH_TunnelNumber), &hash); if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (incoming_tunnels, &hash, t, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) { tunnel_destroy (t); GNUNET_break (0); return GNUNET_OK; } } dest_peer_info = GNUNET_CONTAINER_multihashmap_get (peers, &pi[size - 1].hashPubKey); if (NULL == dest_peer_info) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Creating PeerInfo for destination.\n"); dest_peer_info = GNUNET_malloc (sizeof (struct MeshPeerInfo)); dest_peer_info->id = GNUNET_PEER_intern (&pi[size - 1]); GNUNET_CONTAINER_multihashmap_put (peers, &pi[size - 1].hashPubKey, dest_peer_info, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); } orig_peer_info = GNUNET_CONTAINER_multihashmap_get (peers, &pi->hashPubKey); if (NULL == orig_peer_info) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Creating PeerInfo for origin.\n"); orig_peer_info = GNUNET_malloc (sizeof (struct MeshPeerInfo)); orig_peer_info->id = GNUNET_PEER_intern (pi); GNUNET_CONTAINER_multihashmap_put (peers, &pi->hashPubKey, orig_peer_info, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Creating path...\n"); path = path_new (size); own_pos = 0; for (i = 0; i < size; i++) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ... adding %s\n", GNUNET_i2s (&pi[i])); path->peers[i] = GNUNET_PEER_intern (&pi[i]); if (path->peers[i] == myid) own_pos = i; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Own position: %u\n", own_pos); if (own_pos == 0) { /* cannot be self, must be 'not found' */ /* create path: self not found in path through self */ GNUNET_break_op (0); path_destroy (path); /* FIXME error. destroy tunnel? leave for timeout? */ return 0; } path_add_to_peers (path, GNUNET_NO); tunnel_add_path (t, path, own_pos); if (own_pos == size - 1) { /* It is for us! Send ack. */ struct MeshTransmissionDescriptor *info; unsigned int j; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " It's for us!\n"); peer_info_add_path_to_origin (orig_peer_info, path, GNUNET_NO); if (NULL == t->peers) { /* New tunnel! Notify clients on data. */ t->peers = GNUNET_CONTAINER_multihashmap_create (4); } GNUNET_break (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (t->peers, &my_full_id.hashPubKey, peer_info_get (&my_full_id), GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE)); /* FIXME use send_message */ info = GNUNET_malloc (sizeof (struct MeshTransmissionDescriptor)); info->origin = &t->id; info->peer = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); GNUNET_assert (NULL != info->peer); j = peer_info_transmit_slot (info->peer); info->handler_n = j; info->peer->types[j] = GNUNET_MESSAGE_TYPE_MESH_PATH_ACK; info->peer->infos[j] = info; info->peer->core_transmit[j] = GNUNET_CORE_notify_transmit_ready (core_handle, 0, 10, GNUNET_TIME_UNIT_FOREVER_REL, peer, sizeof (struct GNUNET_MESH_PathACK), &send_core_path_ack, info); } else { struct MeshPeerPath *path2; /* It's for somebody else! Retransmit. */ path2 = path_duplicate (path); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Retransmitting.\n"); peer_info_add_path (dest_peer_info, path2, GNUNET_NO); path2 = path_duplicate (path); peer_info_add_path_to_origin (orig_peer_info, path2, GNUNET_NO); send_create_path (dest_peer_info, path, t); } return GNUNET_OK; } /** * Core handler for path destruction * * @param cls closure * @param message message * @param peer peer identity this notification is about * @param atsi performance data * @param atsi_count number of records in 'atsi' * * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_mesh_path_destroy (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct GNUNET_MESH_ManipulatePath *msg; struct GNUNET_PeerIdentity *pi; struct MeshPeerPath *path; struct MeshTunnel *t; unsigned int own_pos; unsigned int i; size_t size; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received a PATH DESTROY msg from %s\n", GNUNET_i2s (peer)); size = ntohs (message->size); if (size < sizeof (struct GNUNET_MESH_ManipulatePath)) { GNUNET_break_op (0); return GNUNET_OK; } size -= sizeof (struct GNUNET_MESH_ManipulatePath); if (size % sizeof (struct GNUNET_PeerIdentity)) { GNUNET_break_op (0); return GNUNET_OK; } size /= sizeof (struct GNUNET_PeerIdentity); if (size < 2) { GNUNET_break_op (0); return GNUNET_OK; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " path has %u hops.\n", size); msg = (struct GNUNET_MESH_ManipulatePath *) message; pi = (struct GNUNET_PeerIdentity *) &msg[1]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " path is for tunnel %s [%X].\n", GNUNET_i2s (pi), msg->tid); t = tunnel_get (pi, ntohl (msg->tid)); if (NULL == t) { /* TODO notify back: we don't know this tunnel */ GNUNET_break_op (0); return GNUNET_OK; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Creating path...\n"); path = path_new (size); own_pos = 0; for (i = 0; i < size; i++) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ... adding %s\n", GNUNET_i2s (&pi[i])); path->peers[i] = GNUNET_PEER_intern (&pi[i]); if (path->peers[i] == myid) own_pos = i; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Own position: %u\n", own_pos); if (own_pos < path->length - 1) send_message (message, &pi[own_pos + 1]); else send_client_tunnel_disconnect(t, NULL); tunnel_delete_peer (t, path->peers[path->length - 1]); path_destroy (path); return GNUNET_OK; } /** * Core handler for notifications of broken paths * * @param cls closure * @param message message * @param peer peer identity this notification is about * @param atsi performance data * @param atsi_count number of records in 'atsi' * * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_mesh_path_broken (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct GNUNET_MESH_PathBroken *msg; struct MeshTunnel *t; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received a PATH BROKEN msg from %s\n", GNUNET_i2s (peer)); msg = (struct GNUNET_MESH_PathBroken *) message; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n", GNUNET_i2s (&msg->peer1)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n", GNUNET_i2s (&msg->peer2)); t = tunnel_get (&msg->oid, ntohl (msg->tid)); if (NULL == t) { GNUNET_break_op (0); return GNUNET_OK; } tunnel_notify_connection_broken (t, GNUNET_PEER_search (&msg->peer1), GNUNET_PEER_search (&msg->peer2)); return GNUNET_OK; } /** * Core handler for tunnel destruction * * @param cls closure * @param message message * @param peer peer identity this notification is about * @param atsi performance data * @param atsi_count number of records in 'atsi' * * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_mesh_tunnel_destroy (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct GNUNET_MESH_TunnelDestroy *msg; struct MeshTunnel *t; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a TUNNEL DESTROY packet from %s\n", GNUNET_i2s (peer)); msg = (struct GNUNET_MESH_TunnelDestroy *) message; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " for tunnel %s [%u]\n", GNUNET_i2s (&msg->oid), ntohl (msg->tid)); t = tunnel_get (&msg->oid, ntohl (msg->tid)); if (NULL == t) { /* Probably already got the message from another path, * destroyed the tunnel and retransmitted to children. * Safe to ignore. */ return GNUNET_OK; } if (t->id.oid == myid) { GNUNET_break_op (0); return GNUNET_OK; } if (t->local_tid_dest >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) { /* Tunnel was incoming, notify clients */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "INCOMING TUNNEL %X %X\n", t->local_tid, t->local_tid_dest); send_clients_tunnel_destroy (t); } tunnel_send_destroy (t); tunnel_destroy (t); return GNUNET_OK; } /** * Core handler for mesh network traffic going from the origin to a peer * * @param cls closure * @param peer peer identity this notification is about * @param message message * @param atsi performance data * @param atsi_count number of records in 'atsi' * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_mesh_data_unicast (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct GNUNET_MESH_Unicast *msg; struct MeshTunnel *t; GNUNET_PEER_Id pid; size_t size; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "got a unicast packet from %s\n", GNUNET_i2s (peer)); size = ntohs (message->size); if (size < sizeof (struct GNUNET_MESH_Unicast) + sizeof (struct GNUNET_MessageHeader)) { GNUNET_break (0); return GNUNET_OK; } msg = (struct GNUNET_MESH_Unicast *) message; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " of type %u\n", ntohs (msg[1].header.type)); t = tunnel_get (&msg->oid, ntohl (msg->tid)); if (NULL == t) { /* TODO notify back: we don't know this tunnel */ GNUNET_break_op (0); return GNUNET_OK; } tunnel_reset_timeout (t); pid = GNUNET_PEER_search (&msg->destination); if (pid == myid) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " it's for us! sending to clients...\n"); send_subscribed_clients (message, (struct GNUNET_MessageHeader *) &msg[1]); return GNUNET_OK; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n"); send_message (message, tree_get_first_hop (t->tree, pid)); return GNUNET_OK; } /** * Core handler for mesh network traffic going from the origin to all peers * * @param cls closure * @param message message * @param peer peer identity this notification is about * @param atsi performance data * @param atsi_count number of records in 'atsi' * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) * * TODO: Check who we got this from, to validate route. */ static int handle_mesh_data_multicast (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct GNUNET_MESH_Multicast *msg; struct MeshTunnel *t; size_t size; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "got a multicast packet from %s\n", GNUNET_i2s (peer)); size = ntohs (message->size); if (sizeof (struct GNUNET_MESH_Multicast) + sizeof (struct GNUNET_MessageHeader) > size) { GNUNET_break_op (0); return GNUNET_OK; } msg = (struct GNUNET_MESH_Multicast *) message; t = tunnel_get (&msg->oid, ntohl (msg->tid)); if (NULL == t) { /* TODO notify that we dont know that tunnel */ GNUNET_break_op (0); return GNUNET_OK; } if (t->mid == ntohl (msg->mid)) { /* FIXME: already seen this packet, log dropping */ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, " Already seen mid %u, DROPPING!\n", t->mid); return GNUNET_OK; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " mid %u not seen yet, forwarding\n", ntohl (msg->mid)); } t->mid = ntohl (msg->mid); tunnel_reset_timeout (t); /* Transmit to locally interested clients */ if (NULL != t->peers && GNUNET_CONTAINER_multihashmap_contains (t->peers, &my_full_id.hashPubKey)) { send_subscribed_clients (message, &msg[1].header); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ttl: %u\n", ntohl (msg->ttl)); if (ntohl (msg->ttl) == 0) { /* FIXME: ttl is 0, log dropping */ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, " TTL is 0, DROPPING!\n"); return GNUNET_OK; } tunnel_send_multicast (t, message, GNUNET_NO); return GNUNET_OK; } /** * Core handler for mesh network traffic toward the owner of a tunnel * * @param cls closure * @param message message * @param peer peer identity this notification is about * @param atsi performance data * @param atsi_count number of records in 'atsi' * * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_mesh_data_to_orig (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct GNUNET_MESH_ToOrigin *msg; struct GNUNET_PeerIdentity id; struct MeshPeerInfo *peer_info; struct MeshTunnel *t; size_t size; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "got a ToOrigin packet from %s\n", GNUNET_i2s (peer)); size = ntohs (message->size); if (size < sizeof (struct GNUNET_MESH_ToOrigin) + /* Payload must be */ sizeof (struct GNUNET_MessageHeader)) /* at least a header */ { GNUNET_break_op (0); return GNUNET_OK; } msg = (struct GNUNET_MESH_ToOrigin *) message; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " of type %u\n", ntohs (msg[1].header.type)); t = tunnel_get (&msg->oid, ntohl (msg->tid)); if (NULL == t) { /* TODO notify that we dont know this tunnel (whom)? */ GNUNET_break_op (0); return GNUNET_OK; } if (t->id.oid == myid) { char cbuf[size]; struct GNUNET_MESH_ToOrigin *copy; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " it's for us! sending to clients...\n"); if (NULL == t->owner) { /* got data packet for ownerless tunnel */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " no clients!\n"); GNUNET_break_op (0); return GNUNET_OK; } /* TODO signature verification */ memcpy (cbuf, message, size); copy = (struct GNUNET_MESH_ToOrigin *) cbuf; copy->tid = htonl (t->local_tid); GNUNET_SERVER_notification_context_unicast (nc, t->owner->handle, ©->header, GNUNET_YES); return GNUNET_OK; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n"); peer_info = peer_info_get (&msg->oid); if (NULL == peer_info) { /* unknown origin of tunnel */ GNUNET_break (0); return GNUNET_OK; } GNUNET_PEER_resolve (tree_get_predecessor (t->tree), &id); send_message (message, &id); return GNUNET_OK; } /** * Core handler for path ACKs * * @param cls closure * @param message message * @param peer peer identity this notification is about * @param atsi performance data * @param atsi_count number of records in 'atsi' * * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handle_mesh_path_ack (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct GNUNET_MESH_PathACK *msg; struct GNUNET_PeerIdentity id; struct MeshPeerInfo *peer_info; struct MeshPeerPath *p; struct MeshTunnel *t; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received a path ACK msg [%s]\n", GNUNET_i2s (&my_full_id)); msg = (struct GNUNET_MESH_PathACK *) message; t = tunnel_get (&msg->oid, msg->tid); if (NULL == t) { /* TODO notify that we don't know the tunnel */ return GNUNET_OK; } peer_info = peer_info_get (&msg->peer_id); /* Add paths to peers? */ p = tree_get_path_to_peer (t->tree, peer_info->id); if (NULL != p) { path_add_to_peers (p, GNUNET_YES); path_destroy (p); } else { GNUNET_break (0); } /* Message for us? */ if (0 == memcmp (&msg->oid, &my_full_id, sizeof (struct GNUNET_PeerIdentity))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " It's for us!\n"); if (NULL == t->owner) { GNUNET_break_op (0); return GNUNET_OK; } if (NULL != t->dht_get_type) { GNUNET_DHT_get_stop (t->dht_get_type); t->dht_get_type = NULL; } if (tree_get_status (t->tree, peer_info->id) != MESH_PEER_READY) { tree_set_status (t->tree, peer_info->id, MESH_PEER_READY); send_client_peer_connected (t, peer_info->id); } return GNUNET_OK; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n"); GNUNET_PEER_resolve (tree_get_predecessor (t->tree), &id); peer_info = peer_info_get (&msg->oid); if (NULL == peer_info) { /* If we know the tunnel, we should DEFINITELY know the peer */ GNUNET_break (0); return GNUNET_OK; } send_message (message, &id); return GNUNET_OK; } /** * Functions to handle messages from core */ static struct GNUNET_CORE_MessageHandler core_handlers[] = { {&handle_mesh_path_create, GNUNET_MESSAGE_TYPE_MESH_PATH_CREATE, 0}, {&handle_mesh_path_destroy, GNUNET_MESSAGE_TYPE_MESH_PATH_DESTROY, 0}, {&handle_mesh_path_broken, GNUNET_MESSAGE_TYPE_MESH_PATH_BROKEN, sizeof (struct GNUNET_MESH_PathBroken)}, {&handle_mesh_tunnel_destroy, GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY, 0}, {&handle_mesh_data_unicast, GNUNET_MESSAGE_TYPE_MESH_UNICAST, 0}, {&handle_mesh_data_multicast, GNUNET_MESSAGE_TYPE_MESH_MULTICAST, 0}, {&handle_mesh_data_to_orig, GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN, 0}, {&handle_mesh_path_ack, GNUNET_MESSAGE_TYPE_MESH_PATH_ACK, sizeof (struct GNUNET_MESH_PathACK)}, {NULL, 0, 0} }; /******************************************************************************/ /**************** MESH LOCAL HANDLER HELPERS ***********************/ /******************************************************************************/ /** * deregister_app: iterator for removing each application registered by a client * * @param cls closure * @param key the hash of the application id (used to access the hashmap) * @param value the value stored at the key (client) * * @return GNUNET_OK on success */ static int deregister_app (void *cls, const GNUNET_HashCode * key, void *value) { GNUNET_break (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (applications, key, value)); return GNUNET_OK; } #if LATER /** * notify_client_connection_failure: notify a client that the connection to the * requested remote peer is not possible (for instance, no route found) * Function called when the socket is ready to queue more data. "buf" will be * NULL and "size" zero if the socket was closed for writing in the meantime. * * @param cls closure * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t notify_client_connection_failure (void *cls, size_t size, void *buf) { int size_needed; struct MeshPeerInfo *peer_info; struct GNUNET_MESH_PeerControl *msg; struct GNUNET_PeerIdentity id; if (0 == size && NULL == buf) { // TODO retry? cancel? return 0; } size_needed = sizeof (struct GNUNET_MESH_PeerControl); peer_info = (struct MeshPeerInfo *) cls; msg = (struct GNUNET_MESH_PeerControl *) buf; msg->header.size = htons (sizeof (struct GNUNET_MESH_PeerControl)); msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DISCONNECTED); // msg->tunnel_id = htonl(peer_info->t->tid); GNUNET_PEER_resolve (peer_info->id, &id); memcpy (&msg->peer, &id, sizeof (struct GNUNET_PeerIdentity)); return size_needed; } #endif /** * Send keepalive packets for a peer * * @param cls Closure (tunnel for which to send the keepalive). * @param tc Notification context. * * TODO: implement explicit multicast keepalive? */ static void path_refresh (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct MeshTunnel *t = cls; struct GNUNET_MessageHeader *payload; struct GNUNET_MESH_Multicast *msg; size_t size = sizeof (struct GNUNET_MESH_Multicast) + sizeof (struct GNUNET_MessageHeader); char cbuf[size]; if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) { return; } t->path_refresh_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending keepalive for tunnel %d\n", t->id.tid); msg = (struct GNUNET_MESH_Multicast *) cbuf; msg->header.size = htons (size); msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_MULTICAST); msg->oid = my_full_id; msg->tid = htonl (t->id.tid); msg->ttl = htonl (DEFAULT_TTL); msg->mid = htonl (t->mid + 1); t->mid++; payload = (struct GNUNET_MessageHeader *) &msg[1]; payload->size = htons (sizeof (struct GNUNET_MessageHeader)); payload->type = htons (GNUNET_MESSAGE_TYPE_MESH_PATH_KEEPALIVE); tunnel_send_multicast (t, &msg->header, GNUNET_YES); t->path_refresh_task = GNUNET_SCHEDULER_add_delayed (REFRESH_PATH_TIME, &path_refresh, t); return; } /** * Function to process paths received for a new peer addition. The recorded * paths form the initial tunnel, which can be optimized later. * Called on each result obtained for the DHT search. * * @param cls closure * @param exp when will this value expire * @param key key of the result * @param get_path path of the get request * @param get_path_length lenght of get_path * @param put_path path of the put request * @param put_path_length length of the put_path * @param type type of the result * @param size number of bytes in data * @param data pointer to the result data * * TODO: re-issue the request after certain time? cancel after X results? */ static void dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int put_path_length, enum GNUNET_BLOCK_Type type, size_t size, const void *data) { struct MeshPathInfo *path_info = cls; struct MeshPeerPath *p; struct GNUNET_PeerIdentity pi; int i; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got results from DHT!\n"); GNUNET_PEER_resolve (path_info->peer->id, &pi); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " for %s\n", GNUNET_i2s (&pi)); p = path_build_from_dht (get_path, get_path_length, put_path, put_path_length); path_add_to_peers (p, GNUNET_NO); path_destroy(p); for (i = 0; i < path_info->peer->ntunnels; i++) { tunnel_add_peer (path_info->peer->tunnels[i], path_info->peer); peer_info_connect (path_info->peer, path_info->t); } return; } /** * Function to process paths received for a new peer addition. The recorded * paths form the initial tunnel, which can be optimized later. * Called on each result obtained for the DHT search. * * @param cls closure * @param exp when will this value expire * @param key key of the result * @param get_path path of the get request * @param get_path_length lenght of get_path * @param put_path path of the put request * @param put_path_length length of the put_path * @param type type of the result * @param size number of bytes in data * @param data pointer to the result data */ static void dht_get_type_handler (void *cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int put_path_length, enum GNUNET_BLOCK_Type type, size_t size, const void *data) { const struct GNUNET_PeerIdentity *pi = data; struct MeshTunnel *t = cls; struct MeshPeerInfo *peer_info; struct MeshPeerPath *p; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "got type DHT result!\n"); if (size != sizeof (struct GNUNET_PeerIdentity)) { GNUNET_break_op (0); return; } GNUNET_assert (NULL != t->owner); peer_info = peer_info_get (pi); (void) GNUNET_CONTAINER_multihashmap_put (t->peers, &pi->hashPubKey, peer_info, GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); p = path_build_from_dht (get_path, get_path_length, put_path, put_path_length); path_add_to_peers (p, GNUNET_NO); path_destroy(p); tunnel_add_peer (t, peer_info); peer_info_connect (peer_info, t); } /******************************************************************************/ /********************* MESH LOCAL HANDLES **************************/ /******************************************************************************/ /** * Handler for client disconnection * * @param cls closure * @param client identification of the client; NULL * for the last call when the server is destroyed */ static void handle_local_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) { struct MeshClient *c; struct MeshClient *next; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "client disconnected\n"); if (client == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " (SERVER DOWN)\n"); return; } c = clients; while (NULL != c) { if (c->handle != client) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ... searching\n"); c = c->next; continue; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "matching client found (%u)\n", c->id); GNUNET_SERVER_client_drop (c->handle); c->shutting_down = GNUNET_YES; GNUNET_assert (NULL != c->own_tunnels); GNUNET_assert (NULL != c->incoming_tunnels); GNUNET_CONTAINER_multihashmap_iterate (c->own_tunnels, &tunnel_destroy_iterator, c); GNUNET_CONTAINER_multihashmap_iterate (c->incoming_tunnels, &tunnel_destroy_iterator, c); GNUNET_CONTAINER_multihashmap_iterate (c->ignore_tunnels, &tunnel_destroy_iterator, c); GNUNET_CONTAINER_multihashmap_destroy (c->own_tunnels); GNUNET_CONTAINER_multihashmap_destroy (c->incoming_tunnels); GNUNET_CONTAINER_multihashmap_destroy (c->ignore_tunnels); /* deregister clients applications */ if (NULL != c->apps) { GNUNET_CONTAINER_multihashmap_iterate (c->apps, &deregister_app, NULL); GNUNET_CONTAINER_multihashmap_destroy (c->apps); } if (0 == GNUNET_CONTAINER_multihashmap_size (applications) && GNUNET_SCHEDULER_NO_TASK != announce_applications_task) { GNUNET_SCHEDULER_cancel (announce_applications_task); announce_applications_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != c->types) GNUNET_CONTAINER_multihashmap_destroy (c->types); next = c->next; GNUNET_CONTAINER_DLL_remove (clients, clients_tail, c); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " CLIENT FREE at %p\n", c); GNUNET_free (c); c = next; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " done!\n"); return; } /** * Handler for new clients * * @param cls closure * @param client identification of the client * @param message the actual message, which includes messages the client wants */ static void handle_local_new_client (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct GNUNET_MESH_ClientConnect *cc_msg; struct MeshClient *c; GNUNET_MESH_ApplicationType *a; unsigned int size; uint16_t ntypes; uint16_t *t; uint16_t napps; uint16_t i; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "new client connected\n"); /* Check data sanity */ size = ntohs (message->size) - sizeof (struct GNUNET_MESH_ClientConnect); cc_msg = (struct GNUNET_MESH_ClientConnect *) message; ntypes = ntohs (cc_msg->types); napps = ntohs (cc_msg->applications); if (size != ntypes * sizeof (uint16_t) + napps * sizeof (GNUNET_MESH_ApplicationType)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } /* Create new client structure */ c = GNUNET_malloc (sizeof (struct MeshClient)); c->id = next_client_id++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " CLIENT NEW %u\n", c->id); c->handle = client; GNUNET_SERVER_client_keep (client); a = (GNUNET_MESH_ApplicationType *) &cc_msg[1]; if (napps > 0) { GNUNET_MESH_ApplicationType at; GNUNET_HashCode hc; c->apps = GNUNET_CONTAINER_multihashmap_create (napps); for (i = 0; i < napps; i++) { at = ntohl (a[i]); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " app type: %u\n", at); GNUNET_CRYPTO_hash (&at, sizeof (at), &hc); /* store in clients hashmap */ GNUNET_CONTAINER_multihashmap_put (c->apps, &hc, c, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); /* store in global hashmap, for announcements */ GNUNET_CONTAINER_multihashmap_put (applications, &hc, c, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); } if (GNUNET_SCHEDULER_NO_TASK == announce_applications_task) announce_applications_task = GNUNET_SCHEDULER_add_now (&announce_applications, NULL); } if (ntypes > 0) { uint16_t u16; GNUNET_HashCode hc; t = (uint16_t *) & a[napps]; c->types = GNUNET_CONTAINER_multihashmap_create (ntypes); for (i = 0; i < ntypes; i++) { u16 = ntohs (t[i]); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " msg type: %u\n", u16); GNUNET_CRYPTO_hash (&u16, sizeof (u16), &hc); /* store in clients hashmap */ GNUNET_CONTAINER_multihashmap_put (c->types, &hc, c, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); /* store in global hashmap */ GNUNET_CONTAINER_multihashmap_put (types, &hc, c, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); } } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " client has %u+%u subscriptions\n", napps, ntypes); GNUNET_CONTAINER_DLL_insert (clients, clients_tail, c); c->own_tunnels = GNUNET_CONTAINER_multihashmap_create (32); c->incoming_tunnels = GNUNET_CONTAINER_multihashmap_create (32); c->ignore_tunnels = GNUNET_CONTAINER_multihashmap_create (32); GNUNET_SERVER_notification_context_add (nc, client); GNUNET_SERVER_receive_done (client, GNUNET_OK); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "new client processed\n"); } /** * Handler for requests of new tunnels * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_local_tunnel_create (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct GNUNET_MESH_TunnelMessage *t_msg; struct MeshTunnel *t; struct MeshClient *c; GNUNET_HashCode hash; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "new tunnel requested\n"); /* Sanity check for client registration */ if (NULL == (c = client_get (client))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); /* Message sanity check */ if (sizeof (struct GNUNET_MESH_TunnelMessage) != ntohs (message->size)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } t_msg = (struct GNUNET_MESH_TunnelMessage *) message; /* Sanity check for tunnel numbering */ if (0 == (ntohl (t_msg->tunnel_id) & GNUNET_MESH_LOCAL_TUNNEL_ID_CLI)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } /* Sanity check for duplicate tunnel IDs */ if (NULL != tunnel_get_by_local_id (c, ntohl (t_msg->tunnel_id))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } t = GNUNET_malloc (sizeof (struct MeshTunnel)); while (NULL != tunnel_get_by_pi (myid, next_tid)) next_tid = (next_tid + 1) & ~GNUNET_MESH_LOCAL_TUNNEL_ID_CLI; t->id.tid = next_tid++; next_tid = next_tid & ~GNUNET_MESH_LOCAL_TUNNEL_ID_CLI; t->id.oid = myid; t->local_tid = ntohl (t_msg->tunnel_id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CREATED TUNNEL %s [%x] (%x)\n", GNUNET_i2s (&my_full_id), t->id.tid, t->local_tid); t->owner = c; t->peers = GNUNET_CONTAINER_multihashmap_create (32); GNUNET_CRYPTO_hash (&t->local_tid, sizeof (MESH_TunnelNumber), &hash); if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (c->own_tunnels, &hash, t, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_CRYPTO_hash (&t->id, sizeof (struct MESH_TunnelID), &hash); if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (tunnels, &hash, t, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } t->tree = tree_new (myid); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "new tunnel created\n"); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } /** * Handler for requests of deleting tunnels * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_local_tunnel_destroy (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct GNUNET_MESH_TunnelMessage *tunnel_msg; struct MeshClient *c; struct MeshTunnel *t; MESH_TunnelNumber tid; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a DESTROY TUNNEL from client!\n"); /* Sanity check for client registration */ if (NULL == (c = client_get (client))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } /* Message sanity check */ if (sizeof (struct GNUNET_MESH_TunnelMessage) != ntohs (message->size)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); tunnel_msg = (struct GNUNET_MESH_TunnelMessage *) message; /* Retrieve tunnel */ tid = ntohl (tunnel_msg->tunnel_id); t = tunnel_get_by_local_id(c, tid); if (NULL == t) { GNUNET_break (0); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " tunnel %X not found\n", tid); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } if (c != t->owner || tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) { client_ignore_tunnel (c, t); #if 0 // TODO: when to destroy incoming tunnel? if (t->nclients == 0) { GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (incoming_tunnels, &hash, t)); GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (t->peers, &my_full_id.hashPubKey, t)); } #endif GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } send_client_tunnel_disconnect(t, c); client_delete_tunnel(c, t); /* Don't try to ACK the client about the tunnel_destroy multicast packet */ t->owner = NULL; tunnel_send_destroy (t); tunnel_destroy (t); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } /** * Handler for connection requests to new peers * * @param cls closure * @param client identification of the client * @param message the actual message (PeerControl) */ static void handle_local_connect_add (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct GNUNET_MESH_PeerControl *peer_msg; struct MeshPeerInfo *peer_info; struct MeshClient *c; struct MeshTunnel *t; MESH_TunnelNumber tid; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got connection request\n"); /* Sanity check for client registration */ if (NULL == (c = client_get (client))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } peer_msg = (struct GNUNET_MESH_PeerControl *) message; /* Sanity check for message size */ if (sizeof (struct GNUNET_MESH_PeerControl) != ntohs (peer_msg->header.size)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } /* Tunnel exists? */ tid = ntohl (peer_msg->tunnel_id); t = tunnel_get_by_local_id (c, tid); if (NULL == t) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } /* Does client own tunnel? */ if (t->owner->handle != client) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " for %s\n", GNUNET_i2s (&peer_msg->peer)); peer_info = peer_info_get (&peer_msg->peer); tunnel_add_peer (t, peer_info); peer_info_connect (peer_info, t); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } /** * Handler for disconnection requests of peers in a tunnel * * @param cls closure * @param client identification of the client * @param message the actual message (PeerControl) */ static void handle_local_connect_del (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct GNUNET_MESH_PeerControl *peer_msg; struct MeshPeerInfo *peer_info; struct MeshClient *c; struct MeshTunnel *t; MESH_TunnelNumber tid; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a PEER DEL request\n"); /* Sanity check for client registration */ if (NULL == (c = client_get (client))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } peer_msg = (struct GNUNET_MESH_PeerControl *) message; /* Sanity check for message size */ if (sizeof (struct GNUNET_MESH_PeerControl) != ntohs (peer_msg->header.size)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } /* Tunnel exists? */ tid = ntohl (peer_msg->tunnel_id); t = tunnel_get_by_local_id (c, tid); if (NULL == t) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " on tunnel %X\n", t->id.tid); /* Does client own tunnel? */ if (t->owner->handle != client) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " for peer %s\n", GNUNET_i2s (&peer_msg->peer)); /* Is the peer in the tunnel? */ peer_info = GNUNET_CONTAINER_multihashmap_get (t->peers, &peer_msg->peer.hashPubKey); if (NULL == peer_info) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } /* Ok, delete peer from tunnel */ GNUNET_CONTAINER_multihashmap_remove_all (t->peers, &peer_msg->peer.hashPubKey); send_destroy_path (t, peer_info->id); tunnel_delete_peer (t, peer_info->id); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } /** * Handler for connection requests to new peers by type * * @param cls closure * @param client identification of the client * @param message the actual message (ConnectPeerByType) */ static void handle_local_connect_by_type (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct GNUNET_MESH_ConnectPeerByType *connect_msg; struct MeshClient *c; struct MeshTunnel *t; GNUNET_HashCode hash; MESH_TunnelNumber tid; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "got connect by type request\n"); /* Sanity check for client registration */ if (NULL == (c = client_get (client))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } connect_msg = (struct GNUNET_MESH_ConnectPeerByType *) message; /* Sanity check for message size */ if (sizeof (struct GNUNET_MESH_ConnectPeerByType) != ntohs (connect_msg->header.size)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } /* Tunnel exists? */ tid = ntohl (connect_msg->tunnel_id); t = tunnel_get_by_local_id (c, tid); if (NULL == t) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } /* Does client own tunnel? */ if (t->owner->handle != client) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } /* Do WE have the service? */ t->type = ntohl (connect_msg->type); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " type requested: %u\n", t->type); GNUNET_CRYPTO_hash (&t->type, sizeof (GNUNET_MESH_ApplicationType), &hash); if (GNUNET_CONTAINER_multihashmap_contains (applications, &hash) == GNUNET_YES) { /* Yes! Fast forward, add ourselves to the tunnel and send the * good news to the client, and alert the destination client of * an incoming tunnel. * * FIXME send a path create to self, avoid code duplication */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " available locally\n"); GNUNET_CONTAINER_multihashmap_put (t->peers, &my_full_id.hashPubKey, peer_info_get (&my_full_id), GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " notifying client\n"); send_client_peer_connected (t, myid); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Done\n"); GNUNET_SERVER_receive_done (client, GNUNET_OK); t->local_tid_dest = next_local_tid++; GNUNET_CRYPTO_hash (&t->local_tid_dest, sizeof (MESH_TunnelNumber), &hash); GNUNET_CONTAINER_multihashmap_put (incoming_tunnels, &hash, t, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); return; } /* Ok, lets find a peer offering the service */ if (NULL != t->dht_get_type) { GNUNET_DHT_get_stop (t->dht_get_type); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " looking in DHT for %s\n", GNUNET_h2s (&hash)); t->dht_get_type = GNUNET_DHT_get_start (dht_handle, GNUNET_BLOCK_TYPE_TEST, &hash, 10, GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, NULL, 0, &dht_get_type_handler, t); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } /** * Handler for client traffic directed to one peer * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_local_unicast (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct MeshClient *c; struct MeshTunnel *t; struct MeshPeerInfo *pi; struct GNUNET_MESH_Unicast *data_msg; MESH_TunnelNumber tid; size_t size; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a unicast request from a client!\n"); /* Sanity check for client registration */ if (NULL == (c = client_get (client))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } data_msg = (struct GNUNET_MESH_Unicast *) message; /* Sanity check for message size */ size = ntohs (message->size); if (sizeof (struct GNUNET_MESH_Unicast) + sizeof (struct GNUNET_MessageHeader) > size) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } /* Tunnel exists? */ tid = ntohl (data_msg->tid); t = tunnel_get_by_local_id (c, tid); if (NULL == t) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } /* Is it a local tunnel? Then, does client own the tunnel? */ if (t->owner->handle != client) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } pi = GNUNET_CONTAINER_multihashmap_get (t->peers, &data_msg->destination.hashPubKey); /* Is the selected peer in the tunnel? */ if (NULL == pi) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } /* Ok, everything is correct, send the message * (pretend we got it from a mesh peer) */ { char buf[ntohs (message->size)] GNUNET_ALIGN; struct GNUNET_MESH_Unicast *copy; /* Work around const limitation */ copy = (struct GNUNET_MESH_Unicast *) buf; memcpy (buf, data_msg, size); copy->oid = my_full_id; copy->tid = htonl (t->id.tid); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " calling generic handler...\n"); handle_mesh_data_unicast (NULL, &my_full_id, ©->header, NULL, 0); } GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } /** * Handler for client traffic directed to the origin * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_local_to_origin (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct GNUNET_MESH_ToOrigin *data_msg; struct GNUNET_PeerIdentity id; struct MeshClient *c; struct MeshTunnel *t; MESH_TunnelNumber tid; size_t size; /* Sanity check for client registration */ if (NULL == (c = client_get (client))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } data_msg = (struct GNUNET_MESH_ToOrigin *) message; /* Sanity check for message size */ size = ntohs (message->size); if (sizeof (struct GNUNET_MESH_ToOrigin) + sizeof (struct GNUNET_MessageHeader) > size) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } /* Tunnel exists? */ tid = ntohl (data_msg->tid); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a ToOrigin request from a client! Tunnel %X\n", tid); if (tid < GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } t = tunnel_get_by_local_id (c, tid); if (NULL == t) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } /* It should be sent by someone who has this as incoming tunnel. */ if (-1 == client_knows_tunnel (c, t)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_PEER_resolve (t->id.oid, &id); /* Ok, everything is correct, send the message * (pretend we got it from a mesh peer) */ { char buf[ntohs (message->size)] GNUNET_ALIGN; struct GNUNET_MESH_ToOrigin *copy; /* Work around const limitation */ copy = (struct GNUNET_MESH_ToOrigin *) buf; memcpy (buf, data_msg, size); copy->oid = id; copy->tid = htonl (t->id.tid); copy->sender = my_full_id; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " calling generic handler...\n"); handle_mesh_data_to_orig (NULL, &my_full_id, ©->header, NULL, 0); } GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } /** * Handler for client traffic directed to all peers in a tunnel * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_local_multicast (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct MeshClient *c; struct MeshTunnel *t; struct GNUNET_MESH_Multicast *data_msg; MESH_TunnelNumber tid; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a multicast request from a client!\n"); /* Sanity check for client registration */ if (NULL == (c = client_get (client))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } data_msg = (struct GNUNET_MESH_Multicast *) message; /* Sanity check for message size */ if (sizeof (struct GNUNET_MESH_Multicast) + sizeof (struct GNUNET_MessageHeader) > ntohs (data_msg->header.size)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } /* Tunnel exists? */ tid = ntohl (data_msg->tid); t = tunnel_get_by_local_id (c, tid); if (NULL == t) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } /* Does client own tunnel? */ if (t->owner->handle != client) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } { char buf[ntohs (message->size)] GNUNET_ALIGN; struct GNUNET_MESH_Multicast *copy; copy = (struct GNUNET_MESH_Multicast *) buf; memcpy (buf, message, ntohs (message->size)); copy->oid = my_full_id; copy->tid = htonl (t->id.tid); copy->ttl = htonl (DEFAULT_TTL); copy->mid = htonl (t->mid + 1); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " calling generic handler...\n"); handle_mesh_data_multicast (client, &my_full_id, ©->header, NULL, 0); } /* receive done gets called when last copy is sent to a neighbor */ return; } /** * Functions to handle messages from clients */ static struct GNUNET_SERVER_MessageHandler client_handlers[] = { {&handle_local_new_client, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT, 0}, {&handle_local_tunnel_create, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE, sizeof (struct GNUNET_MESH_TunnelMessage)}, {&handle_local_tunnel_destroy, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY, sizeof (struct GNUNET_MESH_TunnelMessage)}, {&handle_local_connect_add, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD, sizeof (struct GNUNET_MESH_PeerControl)}, {&handle_local_connect_del, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL, sizeof (struct GNUNET_MESH_PeerControl)}, {&handle_local_connect_by_type, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD_BY_TYPE, sizeof (struct GNUNET_MESH_ConnectPeerByType)}, {&handle_local_unicast, NULL, GNUNET_MESSAGE_TYPE_MESH_UNICAST, 0}, {&handle_local_to_origin, NULL, GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN, 0}, {&handle_local_multicast, NULL, GNUNET_MESSAGE_TYPE_MESH_MULTICAST, 0}, {NULL, NULL, 0, 0} }; /** * To be called on core init/fail. * * @param cls service closure * @param server handle to the server for this service * @param identity the public identity of this peer */ static void core_init (void *cls, struct GNUNET_CORE_Handle *server, const struct GNUNET_PeerIdentity *identity) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core init\n"); core_handle = server; if (0 != memcmp (identity, &my_full_id, sizeof (my_full_id)) || NULL == server) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Wrong CORE service\n")); GNUNET_SCHEDULER_shutdown (); } return; } /** * Method called whenever a given peer connects. * * @param cls closure * @param peer peer identity this notification is about * @param atsi performance data for the connection * @param atsi_count number of records in 'atsi' */ static void core_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { struct MeshPeerInfo *peer_info; struct MeshPeerPath *path; DEBUG_CONN ("Peer connected\n"); DEBUG_CONN (" %s\n", GNUNET_i2s (&my_full_id)); peer_info = peer_info_get (peer); if (myid == peer_info->id) { DEBUG_CONN (" (self)\n"); return; } else { DEBUG_CONN (" %s\n", GNUNET_i2s (peer)); } path = path_new (2); path->peers[0] = myid; path->peers[1] = peer_info->id; GNUNET_PEER_change_rc (myid, 1); GNUNET_PEER_change_rc (peer_info->id, 1); peer_info_add_path (peer_info, path, GNUNET_YES); return; } /** * Method called whenever a peer disconnects. * * @param cls closure * @param peer peer identity this notification is about */ static void core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { struct MeshPeerInfo *pi; unsigned int i; DEBUG_CONN ("Peer disconnected\n"); pi = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); if (NULL == pi) { GNUNET_break (0); return; } for (i = 0; i < CORE_QUEUE_SIZE; i++) { /* TODO: notify that the transmission failed */ peer_info_cancel_transmission (pi, i); } peer_info_remove_path (pi, pi->id, myid); if (myid == pi->id) { DEBUG_CONN (" (self)\n"); } return; } /******************************************************************************/ /************************ MAIN FUNCTIONS ****************************/ /******************************************************************************/ /** * Iterator over tunnel hash map entries to destroy the tunnel during shutdown. * * @param cls closure * @param key current key code * @param value value in the hash map * @return GNUNET_YES if we should continue to iterate, * GNUNET_NO if not. */ static int shutdown_tunnel (void *cls, const GNUNET_HashCode * key, void *value) { struct MeshTunnel *t = value; tunnel_destroy (t); return GNUNET_YES; } /** * Iterator over peer hash map entries to destroy the tunnel during shutdown. * * @param cls closure * @param key current key code * @param value value in the hash map * @return GNUNET_YES if we should continue to iterate, * GNUNET_NO if not. */ static int shutdown_peer (void *cls, const GNUNET_HashCode * key, void *value) { struct MeshPeerInfo *p = value; peer_info_destroy (p); return GNUNET_YES; } /** * Task run during shutdown. * * @param cls unused * @param tc unused */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutting down\n"); if (core_handle != NULL) { GNUNET_CORE_disconnect (core_handle); core_handle = NULL; } GNUNET_CONTAINER_multihashmap_iterate (tunnels, &shutdown_tunnel, NULL); GNUNET_CONTAINER_multihashmap_iterate (peers, &shutdown_peer, NULL); if (dht_handle != NULL) { GNUNET_DHT_disconnect (dht_handle); dht_handle = NULL; } if (nc != NULL) { GNUNET_SERVER_notification_context_destroy (nc); nc = NULL; } if (GNUNET_SCHEDULER_NO_TASK != announce_id_task) { GNUNET_SCHEDULER_cancel (announce_id_task); announce_id_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shut down\n"); } /** * Process mesh requests. * * @param cls closure * @param server the initialized server * @param c configuration to use */ static void run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *c) { struct MeshPeerInfo *peer; struct MeshPeerPath *p; char *keyfile; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "starting to run\n"); server_handle = server; core_handle = GNUNET_CORE_connect (c, /* Main configuration */ CORE_QUEUE_SIZE, /* queue size */ NULL, /* Closure passed to MESH functions */ &core_init, /* Call core_init once connected */ &core_connect, /* Handle connects */ &core_disconnect, /* remove peers on disconnects */ NULL, /* Don't notify about all incoming messages */ GNUNET_NO, /* For header only in notification */ NULL, /* Don't notify about all outbound messages */ GNUNET_NO, /* For header-only out notification */ core_handlers); /* Register these handlers */ if (core_handle == NULL) { GNUNET_break (0); GNUNET_SCHEDULER_shutdown (); return; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (c, "GNUNETD", "HOSTKEY", &keyfile)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Mesh service is lacking key configuration settings. Exiting.\n")); GNUNET_SCHEDULER_shutdown (); return; } my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); GNUNET_free (keyfile); if (my_private_key == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Mesh service could not access hostkey. Exiting.\n")); GNUNET_SCHEDULER_shutdown (); return; } GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key); GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key), &my_full_id.hashPubKey); myid = GNUNET_PEER_intern (&my_full_id); // // transport_handle = GNUNET_TRANSPORT_connect(c, // // &my_full_id, // // NULL, // // NULL, // // NULL, // // NULL); dht_handle = GNUNET_DHT_connect (c, 64); if (dht_handle == NULL) { GNUNET_break (0); } next_tid = 0; next_local_tid = GNUNET_MESH_LOCAL_TUNNEL_ID_SERV; tunnels = GNUNET_CONTAINER_multihashmap_create (32); incoming_tunnels = GNUNET_CONTAINER_multihashmap_create (32); peers = GNUNET_CONTAINER_multihashmap_create (32); applications = GNUNET_CONTAINER_multihashmap_create (32); types = GNUNET_CONTAINER_multihashmap_create (32); GNUNET_SERVER_add_handlers (server_handle, client_handlers); nc = GNUNET_SERVER_notification_context_create (server_handle, LOCAL_QUEUE_SIZE); GNUNET_SERVER_disconnect_notify (server_handle, &handle_local_client_disconnect, NULL); clients = NULL; clients_tail = NULL; next_client_id = 0; announce_applications_task = GNUNET_SCHEDULER_NO_TASK; announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, cls); /* Create a peer_info for the local peer */ peer = peer_info_get (&my_full_id); p = path_new (1); p->peers[0] = myid; GNUNET_PEER_change_rc (myid, 1); peer_info_add_path (peer, p, GNUNET_YES); /* Scheduled the task to clean up when shutdown is called */ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "end of run()\n"); } /** * The main function for the mesh service. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { int ret; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "main()\n"); ret = (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "mesh", GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "main() END\n"); return ret; } gnunet-0.9.3/src/mesh/test_mesh_api.c0000644000175000017500000001224711760502551014467 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file mesh/test_mesh_api.c * @brief test mesh api: dummy test of callbacks * @author Bartlomiej Polot */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_dht_service.h" #include "gnunet_mesh_service.h" #define VERBOSE 1 #define VERBOSE_ARM 0 static struct GNUNET_OS_Process *arm_pid; static struct GNUNET_MESH_Handle *mesh; static struct GNUNET_MESH_Tunnel *t; static int result; static GNUNET_SCHEDULER_TaskIdentifier abort_task; static GNUNET_SCHEDULER_TaskIdentifier test_task; /** * Function is called whenever a message is received. * * @param cls closure (set from GNUNET_MESH_connect) * @param tunnel connection to the other end * @param tunnel_ctx place to store local state associated with the tunnel * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int callback (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi) { return GNUNET_OK; } static struct GNUNET_MESH_MessageHandler handlers[] = { {&callback, 1, 0}, {NULL, 0, 0} }; static void do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (NULL != t) { GNUNET_MESH_tunnel_destroy (t); } if (0 != abort_task) { GNUNET_SCHEDULER_cancel (abort_task); } if (NULL != mesh) { GNUNET_MESH_disconnect (mesh); } if (0 != GNUNET_OS_process_kill (arm_pid, SIGTERM)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); } GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (arm_pid)); GNUNET_OS_process_destroy (arm_pid); } static void do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (0 != test_task) { GNUNET_SCHEDULER_cancel (test_task); } result = GNUNET_SYSERR; abort_task = 0; do_shutdown (cls, tc); } static void test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CONFIGURATION_Handle *cfg = cls; static const GNUNET_MESH_ApplicationType app[] = { 1, 2, 3, 4, 5, 6, 7, 8, 0 }; test_task = (GNUNET_SCHEDULER_TaskIdentifier) 0; mesh = GNUNET_MESH_connect (cfg, 10, NULL, NULL, NULL, handlers, app); if (NULL == mesh) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: Couldn't connect to mesh :(\n"); return; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: YAY! CONNECTED TO MESH :D\n"); } t = GNUNET_MESH_tunnel_create (mesh, NULL, NULL, NULL, NULL); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5), &do_shutdown, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { GNUNET_log_setup ("test_mesh_api", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); arm_pid = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE_ARM "-L", "DEBUG", #endif "-c", "test_mesh.conf", NULL); abort_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20), &do_abort, NULL); test_task = GNUNET_SCHEDULER_add_now (&test, (void *) cfg); } int main (int argc, char *argv[]) { int ret; char *const argv2[] = { "test-mesh-api", "-c", "test_mesh.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; ret = GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, "test-mesh-api", "nohelp", options, &run, NULL); if (GNUNET_OK != ret) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "run failed with error code %d\n", ret); return 1; } if (GNUNET_SYSERR == result) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test failed\n"); return 1; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test ok\n"); return 0; } gnunet-0.9.3/src/mesh/test_mesh_2dtorus.conf0000644000175000017500000000275311665224123016024 00000000000000[PATHS] SERVICEHOME = /tmp/test_mesh_small/ DEFAULTCONFIG = test_mesh_small.conf [arm] PORT = 10010 DEFAULTSERVICES = core dht mesh #DEBUG = YES [statistics] AUTOSTART = YES PORT = 10000 [dht] DEBUG = NO AUTOSTART = YES ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; HOSTNAME = localhost PORT = 10001 [nse] WORKBITS = 0 [dns] AUTOSTART = NO PORT = 10011 [transport] PORT = 10002 AUTOSTART = YES [nat] DISABLEV6 = YES BINDTO = 127.0.0.1 ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 [ats] WAN_QUOTA_IN = 1 GB WAN_QUOTA_OUT = 1 GB [core] AUTOSTART = YES PORT = 10003 [peerinfo] AUTOSTART = YES PORT = 10004 [mesh] PORT = 10005 DEBUG=YES ACCEPT_FROM = 127.0.0.1; HOSTNAME = localhost # PREFIX = valgrind --leak-check=full # PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args [testing] NUM_PEERS = 16 WEAKRANDOM = YES TOPOLOGY = 2D_TORUS CONNECT_TOPOLOGY = 2D_TORUS #TOPOLOGY_FILE = small.dat CONNECT_TOPOLOGY = 2D_TORUS #CONNECT_TOPOLOGY_OPTION = CONNECT_MINIMUM #CONNECT_TOPOLOGY_OPTION_MODIFIER = 25 #PERCENTAGE = 3 #PROBABILITY = .1 F2F = NO CONNECT_TIMEOUT = 600 s CONNECT_ATTEMPTS = 2 DEBUG = YES HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat MAX_CONCURRENT_SSH = 10 USE_PROGRESSBARS = YES PEERGROUP_TIMEOUT = 2400 s TOPOLOGY_OUTPUT_FILE = mesh_topo_initial MAX_OUTSTANDING_CONNECTIONS = 75 #SINGLE_PEERINFO_PER_HOST = YES #NUM_PEERINFO_PER_HOST = 10 #SINGLE_STATISTICS_PER_HOST = YES #NUM_STATISTICS_PER_HOST = 10 DELETE_FILES = YES gnunet-0.9.3/src/mesh/test_mesh_small.c0000644000175000017500000006612511760517251015035 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file mesh/test_mesh_small.c * * @brief Test for the mesh service: retransmission of traffic. */ #include #include "platform.h" #include "gnunet_testing_lib.h" #include "gnunet_mesh_service.h" #include #define VERBOSE GNUNET_YES #define REMOVE_DIR GNUNET_YES struct MeshPeer { struct MeshPeer *prev; struct MeshPeer *next; struct GNUNET_TESTING_Daemon *daemon; struct GNUNET_MESH_Handle *mesh_handle; }; /** * How long until we give up on connecting the peers? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500) /** * Time to wait for stuff that should be rather fast */ #define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) /** * DIFFERENT TESTS TO RUN */ #define SETUP 0 #define UNICAST 1 #define MULTICAST 2 #define SPEED 3 #define SPEED_ACK 4 /** * Which test are we running? */ static int test; /** * How many events have happened */ static int ok; static int peers_in_tunnel; static int peers_responded; static int data_sent; static int data_received; static int data_ack; /** * Be verbose */ static int verbose; /** * Total number of peers in the test. */ static unsigned long long num_peers; /** * Global configuration file */ static struct GNUNET_CONFIGURATION_Handle *testing_cfg; /** * Total number of currently running peers. */ static unsigned long long peers_running; /** * Total number of connections in the whole network. */ static unsigned int total_connections; /** * The currently running peer group. */ static struct GNUNET_TESTING_PeerGroup *pg; /** * File to report results to. */ static struct GNUNET_DISK_FileHandle *output_file; /** * File to log connection info, statistics to. */ static struct GNUNET_DISK_FileHandle *data_file; /** * How many data points to capture before triggering next round? */ static struct GNUNET_TIME_Relative wait_time; /** * Task called to disconnect peers. */ static GNUNET_SCHEDULER_TaskIdentifier disconnect_task; /** * Task To perform tests */ static GNUNET_SCHEDULER_TaskIdentifier test_task; /** * Task called to shutdown test. */ static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle; static char *topology_file; static struct GNUNET_TESTING_Daemon *d1; static GNUNET_PEER_Id pid1; static struct GNUNET_TESTING_Daemon *d2; static struct GNUNET_TESTING_Daemon *d3; static struct GNUNET_MESH_Handle *h1; static struct GNUNET_MESH_Handle *h2; static struct GNUNET_MESH_Handle *h3; static struct GNUNET_MESH_Tunnel *t; static struct GNUNET_MESH_Tunnel *incoming_t; static struct GNUNET_MESH_Tunnel *incoming_t2; static struct GNUNET_TIME_Absolute start_time; static struct GNUNET_TIME_Absolute end_time; static struct GNUNET_TIME_Relative total_time; /** * Check whether peers successfully shut down. */ static void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); #endif ok--; } else { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); #endif } GNUNET_CONFIGURATION_destroy (testing_cfg); } /** * Shut down peergroup, clean up. */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n"); #endif if (disconnect_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (disconnect_task); disconnect_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != h1) { GNUNET_MESH_disconnect (h1); h1 = NULL; } if (NULL != h2) { GNUNET_MESH_disconnect (h2); h2 = NULL; } if (test == MULTICAST && NULL != h3) { GNUNET_MESH_disconnect (h3); h3 = NULL; } if (data_file != NULL) GNUNET_DISK_file_close (data_file); GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); } /** * Disconnect from mesh services af all peers, call shutdown. */ static void disconnect_mesh_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnecting mesh service of peers\n"); disconnect_task = GNUNET_SCHEDULER_NO_TASK; if (NULL != t) { GNUNET_MESH_tunnel_destroy(t); t = NULL; } if (NULL != incoming_t) { GNUNET_MESH_tunnel_destroy(incoming_t); incoming_t = NULL; } if (NULL != incoming_t2) { GNUNET_MESH_tunnel_destroy(incoming_t2); incoming_t2 = NULL; } GNUNET_MESH_disconnect (h1); GNUNET_MESH_disconnect (h2); h1 = h2 = NULL; if (test == MULTICAST) { GNUNET_MESH_disconnect (h3); h3 = NULL; } if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle) { GNUNET_SCHEDULER_cancel (shutdown_handle); shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); } } size_t tmt_rdy (void *cls, size_t size, void *buf); static void data_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_MESH_TransmitHandle *th; if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0) return; th = GNUNET_MESH_notify_transmit_ready (t, GNUNET_NO, 0, GNUNET_TIME_UNIT_FOREVER_REL, &d2->id, sizeof (struct GNUNET_MessageHeader), &tmt_rdy, (void *) 1L); if (NULL == th) { unsigned long i = (unsigned long) cls; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Retransmission\n"); if (0 == i) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, " in 1 ms\n"); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, &data_task, (void *)1UL); } else { i++; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "in %u ms\n", i); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply( GNUNET_TIME_UNIT_MILLISECONDS, i), &data_task, (void *)i); } } } /** * Transmit ready callback * * @param cls Closure. * @param size Size of the buffer we have. * @param buf Buffer to copy data to. */ size_t tmt_rdy (void *cls, size_t size, void *buf) { struct GNUNET_MessageHeader *msg = buf; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " tmt_rdy called\n"); if (size < sizeof (struct GNUNET_MessageHeader) || NULL == buf) return 0; msg->size = htons (sizeof (struct GNUNET_MessageHeader)); msg->type = htons ((long) cls); if (test == SPEED) { data_sent++; if (data_sent < 1000) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Scheduling %d packet\n", data_sent); GNUNET_SCHEDULER_add_now(&data_task, NULL); } } return sizeof (struct GNUNET_MessageHeader); } /** * Function is called whenever a message is received. * * @param cls closure (set from GNUNET_MESH_connect) * @param tunnel connection to the other end * @param tunnel_ctx place to store local state associated with the tunnel * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ int data_callback (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi) { long client = (long) cls; switch (client) { case 1L: GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Origin client got a response!\n"); ok++; GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); peers_responded++; data_ack++; if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) { GNUNET_SCHEDULER_cancel (disconnect_task); disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers, NULL); } if (test == MULTICAST && peers_responded < 2) return GNUNET_OK; if (test == SPEED_ACK) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received ack %u\n", data_ack); GNUNET_MESH_notify_transmit_ready (tunnel, GNUNET_NO, 0, GNUNET_TIME_UNIT_FOREVER_REL, sender, sizeof (struct GNUNET_MessageHeader), &tmt_rdy, (void *) 1L); if (data_ack < 1000) return GNUNET_OK; end_time = GNUNET_TIME_absolute_get(); total_time = GNUNET_TIME_absolute_get_difference(start_time, end_time); FPRINTF (stderr, "\nTest time %llu ms\n", (unsigned long long) total_time.rel_value); FPRINTF (stderr, "Test bandwidth: %f kb/s\n", 4000.0 / total_time.rel_value); FPRINTF (stderr, "Test throughput: %f packets/s\n", 1000000.0 / total_time.rel_value); GAUGER ("MESH", "Tunnel 5 peers", 1000000.0 / total_time.rel_value, "packets/s"); } GNUNET_assert (tunnel == t); GNUNET_MESH_tunnel_destroy (t); t = NULL; break; case 2L: case 3L: GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Destination client %u got a message.\n", client); ok++; GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); if (SPEED != test) { GNUNET_MESH_notify_transmit_ready (tunnel, GNUNET_NO, 0, GNUNET_TIME_UNIT_FOREVER_REL, sender, sizeof (struct GNUNET_MessageHeader), &tmt_rdy, (void *) 1L); } else { data_received++; GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received data %u\n", data_received); if (data_received < 1000) return GNUNET_OK; } if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) { GNUNET_SCHEDULER_cancel (disconnect_task); disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers, NULL); } break; default: break; } return GNUNET_OK; } /** * Handlers, for diverse services */ static struct GNUNET_MESH_MessageHandler handlers[] = { {&data_callback, 1, sizeof (struct GNUNET_MessageHeader)}, {NULL, 0, 0} }; /** * Method called whenever another peer has added us to a tunnel * the other peer initiated. * * @param cls closure * @param tunnel new handle to the tunnel * @param initiator peer that started the tunnel * @param atsi performance information for the tunnel * @return initial tunnel context for the tunnel * (can be NULL -- that's not an error) */ static void * incoming_tunnel (void *cls, struct GNUNET_MESH_Tunnel *tunnel, const struct GNUNET_PeerIdentity *initiator, const struct GNUNET_ATS_Information *atsi) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Incoming tunnel from %s to peer %d\n", GNUNET_i2s (initiator), (long) cls); ok++; GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); if ((long) cls == 2L) incoming_t = tunnel; else if ((long) cls == 3L) incoming_t2 = tunnel; else { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Incoming tunnel for unknown client %lu\n", (long) cls); } if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) { GNUNET_SCHEDULER_cancel (disconnect_task); disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers, NULL); } return NULL; } /** * Function called whenever an inbound tunnel is destroyed. Should clean up * any associated state. * * @param cls closure (set from GNUNET_MESH_connect) * @param tunnel connection to the other end (henceforth invalid) * @param tunnel_ctx place where local state associated * with the tunnel is stored */ static void tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx) { long i = (long) cls; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Incoming tunnel disconnected at peer %d\n", i); if (2L == i) { ok++; incoming_t = NULL; } else if (3L == i) { ok++; incoming_t2 = NULL; } else GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unknown peer! %d\n", i); GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); peers_in_tunnel--; if (peers_in_tunnel > 0) return; if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) { GNUNET_SCHEDULER_cancel (disconnect_task); disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_mesh_peers, NULL); } return; } /** * Method called whenever a tunnel falls apart. * * @param cls closure * @param peer peer identity the tunnel stopped working with */ static void dh (void *cls, const struct GNUNET_PeerIdentity *peer) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "peer %s disconnected\n", GNUNET_i2s (peer)); return; } /** * Method called whenever a peer connects to a tunnel. * * @param cls closure * @param peer peer identity the tunnel was created to, NULL on timeout * @param atsi performance data for the connection */ static void ch (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi) { struct GNUNET_PeerIdentity *dest; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "peer %s connected\n", GNUNET_i2s (peer)); if (0 == memcmp (&d2->id, peer, sizeof (d2->id)) && (long) cls == 1L) { ok++; } if (test == MULTICAST && 0 == memcmp (&d3->id, peer, sizeof (d3->id)) && (long) cls == 1L) { ok++; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok); switch (test) { case UNICAST: case SPEED: case SPEED_ACK: dest = &d2->id; break; case MULTICAST: peers_in_tunnel++; if (peers_in_tunnel < 2) return; dest = NULL; break; default: return; } if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) { GNUNET_SCHEDULER_cancel (disconnect_task); disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers, NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending data...\n"); peers_responded = 0; data_ack = 0; data_received = 0; data_sent = 0; start_time = GNUNET_TIME_absolute_get(); GNUNET_MESH_notify_transmit_ready (t, GNUNET_NO, 0, GNUNET_TIME_UNIT_FOREVER_REL, dest, sizeof (struct GNUNET_MessageHeader), &tmt_rdy, (void *) 1L); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnect already run?\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Aborting...\n"); } return; } static void do_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test_task\n"); if (test == MULTICAST) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "add peer 3\n"); GNUNET_MESH_peer_request_connect_add (t, &d3->id); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "add peer 2\n"); GNUNET_MESH_peer_request_connect_add (t, &d2->id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "schedule timeout in 90s\n"); if (GNUNET_SCHEDULER_NO_TASK != disconnect_task) { GNUNET_SCHEDULER_cancel (disconnect_task); disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers, NULL); } } /** * connect_mesh_service: connect to the mesh service of one of the peers * */ static void connect_mesh_service (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_MESH_ApplicationType app; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connect_mesh_service\n"); d2 = GNUNET_TESTING_daemon_get (pg, 4); if (test == MULTICAST) { d3 = GNUNET_TESTING_daemon_get (pg, 3); } app = (GNUNET_MESH_ApplicationType) 0; #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connecting to mesh service of peer %s\n", GNUNET_i2s (&d1->id)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connecting to mesh service of peer %s\n", GNUNET_i2s (&d2->id)); if (test == MULTICAST) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connecting to mesh service of peer %s\n", GNUNET_i2s (&d3->id)); } #endif h1 = GNUNET_MESH_connect (d1->cfg, 5, (void *) 1L, NULL, &tunnel_cleaner, handlers, &app); h2 = GNUNET_MESH_connect (d2->cfg, 5, (void *) 2L, &incoming_tunnel, &tunnel_cleaner, handlers, &app); if (test == MULTICAST) { h3 = GNUNET_MESH_connect (d3->cfg, 5, (void *) 3L, &incoming_tunnel, &tunnel_cleaner, handlers, &app); } t = GNUNET_MESH_tunnel_create (h1, NULL, &ch, &dh, (void *) 1L); peers_in_tunnel = 0; test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1), &do_test, NULL); } /** * peergroup_ready: start test when all peers are connected * @param cls closure * @param emsg error message */ static void peergroup_ready (void *cls, const char *emsg) { char *buf; int buf_len; unsigned int i; if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peergroup callback called with error, aborting test!\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n", emsg); ok--; GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); return; } #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "************************************************************\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer Group started successfully!\n"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %u connections\n", total_connections); #endif if (data_file != NULL) { buf = NULL; buf_len = GNUNET_asprintf (&buf, "CONNECTIONS_0: %u\n", total_connections); if (buf_len > 0) GNUNET_DISK_file_write (data_file, buf, buf_len); GNUNET_free (buf); } peers_running = GNUNET_TESTING_daemons_running (pg); for (i = 0; i < num_peers; i++) { GNUNET_PEER_Id peer_id; d1 = GNUNET_TESTING_daemon_get (pg, i); peer_id = GNUNET_PEER_intern (&d1->id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %u: %s\n", peer_id, GNUNET_i2s (&d1->id)); } d1 = GNUNET_TESTING_daemon_get (pg, 0); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer looking: %s\n", GNUNET_i2s (&d1->id)); pid1 = GNUNET_PEER_intern (&d1->id); GNUNET_SCHEDULER_add_now (&connect_mesh_service, NULL); disconnect_task = GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_mesh_peers, NULL); } /** * Function that will be called whenever two daemons are connected by * the testing library. * * @param cls closure * @param first peer id for first daemon * @param second peer id for the second daemon * @param distance distance between the connected peers * @param first_cfg config for the first daemon * @param second_cfg config for the second daemon * @param first_daemon handle for the first daemon * @param second_daemon handle for the second daemon * @param emsg error message (NULL on success) */ static void connect_cb (void *cls, const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second, uint32_t distance, const struct GNUNET_CONFIGURATION_Handle *first_cfg, const struct GNUNET_CONFIGURATION_Handle *second_cfg, struct GNUNET_TESTING_Daemon *first_daemon, struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) { if (emsg == NULL) { total_connections++; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem with new connection (%s)\n", emsg); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " (%s)\n", GNUNET_i2s (first)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " (%s)\n", GNUNET_i2s (second)); } } /** * run: load configuration options and schedule test to run (start peergroup) * @param cls closure * @param args argv * @param cfgfile configuration file name (can be NULL) * @param cfg configuration handle */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { char *temp_str; struct GNUNET_TESTING_Host *hosts; char *data_filename; ok = 0; testing_cfg = GNUNET_CONFIGURATION_dup (cfg); GNUNET_log_setup ("test_mesh_small", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", "use_progressbars", "YES"); #endif if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing", "num_peers", &num_peers)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Option TESTING:NUM_PEERS is required!\n"); return; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (testing_cfg, "test_mesh_small", "WAIT_TIME", &wait_time)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Option test_mesh_small:wait_time is required!\n"); return; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (testing_cfg, "testing", "topology_output_file", &topology_file)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Option test_mesh_small:topology_output_file is required!\n"); return; } if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (testing_cfg, "test_mesh_small", "data_output_file", &data_filename)) { data_file = GNUNET_DISK_file_open (data_filename, GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_CREATE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (data_file == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n", data_filename); GNUNET_free (data_filename); } } if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "test_mesh_small", "output_file", &temp_str)) { output_file = GNUNET_DISK_file_open (temp_str, GNUNET_DISK_OPEN_READWRITE | GNUNET_DISK_OPEN_CREATE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (output_file == NULL) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n", temp_str); } GNUNET_free_non_null (temp_str); hosts = GNUNET_TESTING_hosts_load (testing_cfg); pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT, &connect_cb, &peergroup_ready, NULL, hosts); GNUNET_assert (pg != NULL); shutdown_handle = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); } /** * test_mesh_small command line options */ static struct GNUNET_GETOPT_CommandLineOption options[] = { {'V', "verbose", NULL, gettext_noop ("be verbose (print progress information)"), 0, &GNUNET_GETOPT_set_one, &verbose}, GNUNET_GETOPT_OPTION_END }; /** * Main: start test */ int main (int argc, char *argv[]) { char * argv2[] = { argv[0], "-c", "test_mesh_small.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; int argc2 = (sizeof (argv2) / sizeof (char *)) - 1; /* Each peer is supposed to generate the following callbacks: * 1 incoming tunnel (@dest) * 1 connected peer (@orig) * 1 received data packet (@dest) * 1 received data packet (@orig) * 1 received tunnel destroy (@dest) * _________________________________ * 5 x ok expected per peer */ int ok_goal; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start\n"); if (strstr (argv[0], "test_mesh_small_unicast") != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNICAST\n"); test = UNICAST; ok_goal = 5; } else if (strstr (argv[0], "test_mesh_small_multicast") != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MULTICAST\n"); test = MULTICAST; ok_goal = 10; } else if (strstr (argv[0], "test_mesh_small_speed_ack") != NULL) { /* Each peer is supposed to generate the following callbacks: * 1 incoming tunnel (@dest) * 1 connected peer (@orig) * 1000 received data packet (@dest) * 1000 received data packet (@orig) * 1 received tunnel destroy (@dest) * _________________________________ * 5 x ok expected per peer */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n"); test = SPEED_ACK; ok_goal = 2003; argv2 [3] = NULL; // remove -L DEBUG #if VERBOSE argc2 -= 2; #endif } else if (strstr (argv[0], "test_mesh_small_speed") != NULL) { /* Each peer is supposed to generate the following callbacks: * 1 incoming tunnel (@dest) * 1 connected peer (@orig) * 1000 received data packet (@dest) * 1 received tunnel destroy (@dest) * _________________________________ * 5 x ok expected per peer */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n"); test = SPEED; ok_goal = 1003; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNKNOWN\n"); test = SETUP; ok_goal = 0; } GNUNET_PROGRAM_run (argc2, argv2, "test_mesh_small", gettext_noop ("Test mesh in a small network."), options, &run, NULL); #if REMOVE_DIR GNUNET_DISK_directory_remove ("/tmp/test_mesh_small"); #endif if (ok_goal > ok) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "FAILED! (%d/%d)\n", ok, ok_goal); return 1; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n"); return 0; } /* end of test_mesh_small.c */ gnunet-0.9.3/src/mesh/mesh.conf.in0000644000175000017500000000041511760502552013702 00000000000000[mesh] AUTOSTART = YES @UNIXONLY@ PORT = 2096 HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-mesh ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-mesh.sock UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES gnunet-0.9.3/src/mesh/test_mesh_local_1.c0000644000175000017500000002456211760502551015233 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file mesh/test_mesh_local.c * @brief test mesh local: test of tunnels with just one peer * @author Bartlomiej Polot */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_dht_service.h" #include "gnunet_mesh_service.h" #define VERBOSE 1 #define VERBOSE_ARM 0 static struct GNUNET_OS_Process *arm_pid; static struct GNUNET_MESH_Handle *mesh_peer_1; static struct GNUNET_MESH_Handle *mesh_peer_2; static struct GNUNET_MESH_Tunnel *t; static unsigned int one = 1; static unsigned int two = 2; static int result; static GNUNET_SCHEDULER_TaskIdentifier abort_task; static GNUNET_SCHEDULER_TaskIdentifier test_task; static GNUNET_SCHEDULER_TaskIdentifier shutdown_task; /** * Shutdown nicely */ static void do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: shutdown\n"); if (0 != abort_task) { GNUNET_SCHEDULER_cancel (abort_task); } if (NULL != t) { GNUNET_MESH_tunnel_destroy(t); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: D1\n"); if (NULL != mesh_peer_1) { GNUNET_MESH_disconnect (mesh_peer_1); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: D2\n"); if (NULL != mesh_peer_2) { GNUNET_MESH_disconnect (mesh_peer_2); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: arm\n"); if (0 != GNUNET_OS_process_kill (arm_pid, SIGTERM)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Wait\n"); GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (arm_pid)); GNUNET_OS_process_destroy (arm_pid); } /** * Something went wrong and timed out. Kill everything and set error flag */ static void do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: ABORT\n"); if (0 != test_task) { GNUNET_SCHEDULER_cancel (test_task); } result = GNUNET_SYSERR; abort_task = 0; if (GNUNET_SCHEDULER_NO_TASK != shutdown_task) { GNUNET_SCHEDULER_cancel (shutdown_task); shutdown_task = GNUNET_SCHEDULER_NO_TASK; } do_shutdown (cls, tc); } /** * Function is called whenever a message is received. * * @param cls closure (set from GNUNET_MESH_connect) * @param tunnel connection to the other end * @param tunnel_ctx place to store local state associated with the tunnel * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int data_callback (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Data callback\n"); if (GNUNET_SCHEDULER_NO_TASK != shutdown_task) GNUNET_SCHEDULER_cancel (shutdown_task); shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2), &do_shutdown, NULL); return GNUNET_OK; } /** * Method called whenever another peer has added us to a tunnel * the other peer initiated. * * @param cls closure * @param tunnel new handle to the tunnel * @param initiator peer that started the tunnel * @param atsi performance information for the tunnel * @return initial tunnel context for the tunnel (can be NULL -- that's not an error) */ static void * inbound_tunnel (void *cls, struct GNUNET_MESH_Tunnel *tunnel, const struct GNUNET_PeerIdentity *initiator, const struct GNUNET_ATS_Information *atsi) { unsigned int id = *(unsigned int *) cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: received incoming tunnel\n"); if (id != 1) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: received incoming tunnel on peer 2\n"); result = GNUNET_SYSERR; } return NULL; } /** * Function called whenever an inbound tunnel is destroyed. Should clean up * any associated state. * * @param cls closure (set from GNUNET_MESH_connect) * @param tunnel connection to the other end (henceforth invalid) * @param tunnel_ctx place where local state associated * with the tunnel is stored */ static void inbound_end (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx) { unsigned int id = *(unsigned int *) cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: incoming tunnel closed\n"); if (id != 1) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: received closing tunnel on peer 2\n"); result = GNUNET_SYSERR; } } /** * Method called whenever a peer has connected to the tunnel. * * @param cls closure * @param peer peer identity the tunnel stopped working with */ static void peer_conected (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: peer connected\n"); if (GNUNET_SCHEDULER_NO_TASK != shutdown_task) GNUNET_SCHEDULER_cancel(shutdown_task); shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_shutdown, NULL); } /** * Method called whenever a peer has connected to the tunnel. * * @param cls closure * @param peer peer identity the tunnel was created to, NULL on timeout * @param atsi performance data for the connection */ static void peer_disconnected (void *cls, const struct GNUNET_PeerIdentity *peer) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: peer disconnected\n"); } /** * Handler array for traffic received on peer1 */ static struct GNUNET_MESH_MessageHandler handlers1[] = { {&data_callback, 1, 0}, {NULL, 0, 0} }; /** * Handler array for traffic received on peer2 (none expected) */ static struct GNUNET_MESH_MessageHandler handlers2[] = { {NULL, 0, 0} }; /** * Start looking for a peer by type */ static void do_find (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: CONNECT BY TYPE\n"); GNUNET_MESH_peer_request_connect_by_type (t, 1); } /** * Main test function */ static void test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CONFIGURATION_Handle *cfg = cls; static const GNUNET_MESH_ApplicationType app1[] = { 1, 0 }; static const GNUNET_MESH_ApplicationType app2[] = { 0 }; test_task = GNUNET_SCHEDULER_NO_TASK; mesh_peer_1 = GNUNET_MESH_connect (cfg, /* configuration */ 10, /* queue size */ (void *) &one, /* cls */ &inbound_tunnel, /* inbound new hndlr */ &inbound_end, /* inbound end hndlr */ handlers1, /* traffic handlers */ app1); /* apps offered */ mesh_peer_2 = GNUNET_MESH_connect (cfg, /* configuration */ 10, /* queue size */ (void *) &two, /* cls */ &inbound_tunnel, /* inbound new hndlr */ &inbound_end, /* inbound end hndlr */ handlers2, /* traffic handlers */ app2); /* apps offered */ if (NULL == mesh_peer_1 || NULL == mesh_peer_2) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: Couldn't connect to mesh :(\n"); return; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: YAY! CONNECTED TO MESH :D\n"); } t = GNUNET_MESH_tunnel_create (mesh_peer_2, NULL, &peer_conected, &peer_disconnected, (void *) &two); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_find, NULL); } /** * Initialize framework and start test */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { GNUNET_log_setup ("test_mesh_local", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); arm_pid = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE_ARM "-L", "DEBUG", #endif "-c", "test_mesh.conf", NULL); abort_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20), &do_abort, NULL); test_task = GNUNET_SCHEDULER_add_now (&test, (void *) cfg); } /** * Main */ int main (int argc, char *argv[]) { int ret; char *const argv2[] = { "test-mesh-local", "-c", "test_mesh.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; result = GNUNET_OK; ret = GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, "test-mesh-local", "nohelp", options, &run, NULL); if (GNUNET_OK != ret) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "run failed with error code %d\n", ret); return 1; } if (GNUNET_SYSERR == result) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test failed\n"); return 1; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test ok\n"); return 0; } gnunet-0.9.3/src/mesh/test_mesh_small.conf0000644000175000017500000000325111721232277015526 00000000000000[PATHS] SERVICEHOME = /tmp/test_mesh_small/ DEFAULTCONFIG = test_mesh_small.conf [arm] PORT = 10010 DEFAULTSERVICES = core dht mesh #DEBUG = YES [statistics] AUTOSTART = YES PORT = 10000 [dht] DEBUG = NO AUTOSTART = YES ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; HOSTNAME = localhost PORT = 10001 [nse] WORKBITS = 0 INTERVAL = 60 s WORKDELAY = 500 ms [dns] AUTOSTART = NO PORT = 10011 [transport] PORT = 10002 AUTOSTART = YES [nat] DISABLEV6 = YES BINDTO = 127.0.0.1 ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 [ats] WAN_QUOTA_IN = 1 GB WAN_QUOTA_OUT = 1 GB [core] AUTOSTART = YES PORT = 10003 [peerinfo] AUTOSTART = YES PORT = 10004 [mesh] PORT = 10005 DEBUG = YES ACCEPT_FROM = 127.0.0.1; HOSTNAME = localhost # PREFIX = valgrind --leak-check=full --suppressions=valgrind-mesh.supp # PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args [testing] NUM_PEERS = 5 WEAKRANDOM = YES TOPOLOGY = NONE CONNECT_TOPOLOGY = LINE BLACKLIST_TOPOLOGY = LINE BLACKLIST_TRANSPORTS = tcp udp http unix #TOPOLOGY_FILE = small.dat #CONNECT_TOPOLOGY_OPTION = CONNECT_MINIMUM #CONNECT_TOPOLOGY_OPTION_MODIFIER = 25 #PERCENTAGE = 3 #PROBABILITY = .1 F2F = NO CONNECT_TIMEOUT = 660 s CONNECT_ATTEMPTS = 2 DEBUG = YES HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat MAX_CONCURRENT_SSH = 10 USE_PROGRESSBARS = YES PEERGROUP_TIMEOUT = 2400 s TOPOLOGY_OUTPUT_FILE = mesh_topo_initial MAX_OUTSTANDING_CONNECTIONS = 75 #SINGLE_PEERINFO_PER_HOST = YES #NUM_PEERINFO_PER_HOST = 10 #SINGLE_STATISTICS_PER_HOST = YES #NUM_STATISTICS_PER_HOST = 10 DELETE_FILES = YES [test_mesh_small] WAIT_TIME = 300 s CONNECTION_LIMIT = 16 #DATA_OUTPUT_FILE=data_output gnunet-0.9.3/src/mesh/test_mesh.conf0000644000175000017500000000163611761764472014356 00000000000000[fs] AUTOSTART = NO [resolver] AUTOSTART = NO [mesh] DEBUG = YES AUTOSTART = YES ACCEPT_FROM = 127.0.0.1; HOSTNAME = localhost PORT = 10511 # PREFIX = valgrind --leak-check=full # PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args [dht] DEBUG = NO AUTOSTART = YES ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; HOSTNAME = localhost PORT = 12100 [block] plugins = dht test [dhtcache] QUOTA = 1 MB DATABASE = sqlite [transport] PLUGINS = tcp DEBUG = NO ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; NEIGHBOUR_LIMIT = 50 PORT = 12365 [ats] WAN_QUOTA_OUT = 3932160 WAN_QUOTA_IN = 3932160 [core] PORT = 12092 [arm] DEFAULTSERVICES = core PORT = 12366 DEBUG = NO [transport-tcp] TIMEOUT = 300 s PORT = 12368 [TESTING] WEAKRANDOM = YES [gnunetd] HOSTKEY = $SERVICEHOME/.hostkey [PATHS] DEFAULTCONFIG = test_mesh.conf SERVICEHOME = /tmp/test-mesh/ [dns] AUTOSTART = NO [nse] AUTOSTART = NO [namestore] AUTOSTART = NO gnunet-0.9.3/src/mesh/Makefile.in0000644000175000017500000010617711762223642013555 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-service-mesh$(EXEEXT) check_PROGRAMS = test_mesh_api$(EXEEXT) test_mesh_tree_api$(EXEEXT) \ test_mesh_local_1$(EXEEXT) test_mesh_local_2$(EXEEXT) \ test_mesh_2dtorus$(EXEEXT) test_mesh_small_unicast$(EXEEXT) \ test_mesh_small_multicast$(EXEEXT) \ test_mesh_small_speed$(EXEEXT) \ test_mesh_small_speed_ack$(EXEEXT) @ENABLE_TEST_RUN_TRUE@TESTS = test_mesh_api$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_mesh_tree_api$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_mesh_local_1$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_mesh_local_2$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_mesh_2dtorus$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_mesh_small_unicast$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@ test_mesh_small_multicast$(EXEEXT) subdir = src/mesh DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/mesh.conf.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = mesh.conf CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libgnunetmesh_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_libgnunetmesh_la_OBJECTS = mesh_api.lo libgnunetmesh_la_OBJECTS = $(am_libgnunetmesh_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunetmesh_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetmesh_la_LDFLAGS) $(LDFLAGS) \ -o $@ PROGRAMS = $(bin_PROGRAMS) am_gnunet_service_mesh_OBJECTS = gnunet-service-mesh.$(OBJEXT) \ mesh_tunnel_tree.$(OBJEXT) gnunet_service_mesh_OBJECTS = $(am_gnunet_service_mesh_OBJECTS) am_test_mesh_2dtorus_OBJECTS = test_mesh_2dtorus.$(OBJEXT) test_mesh_2dtorus_OBJECTS = $(am_test_mesh_2dtorus_OBJECTS) test_mesh_2dtorus_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la am_test_mesh_api_OBJECTS = test_mesh_api.$(OBJEXT) test_mesh_api_OBJECTS = $(am_test_mesh_api_OBJECTS) am_test_mesh_local_1_OBJECTS = test_mesh_local_1.$(OBJEXT) test_mesh_local_1_OBJECTS = $(am_test_mesh_local_1_OBJECTS) am_test_mesh_local_2_OBJECTS = test_mesh_local_2.$(OBJEXT) test_mesh_local_2_OBJECTS = $(am_test_mesh_local_2_OBJECTS) am_test_mesh_small_multicast_OBJECTS = test_mesh_small.$(OBJEXT) test_mesh_small_multicast_OBJECTS = \ $(am_test_mesh_small_multicast_OBJECTS) am_test_mesh_small_speed_OBJECTS = test_mesh_small.$(OBJEXT) test_mesh_small_speed_OBJECTS = $(am_test_mesh_small_speed_OBJECTS) am_test_mesh_small_speed_ack_OBJECTS = test_mesh_small.$(OBJEXT) test_mesh_small_speed_ack_OBJECTS = \ $(am_test_mesh_small_speed_ack_OBJECTS) am_test_mesh_small_unicast_OBJECTS = test_mesh_small.$(OBJEXT) test_mesh_small_unicast_OBJECTS = \ $(am_test_mesh_small_unicast_OBJECTS) am_test_mesh_tree_api_OBJECTS = test_mesh_tree_api.$(OBJEXT) test_mesh_tree_api_OBJECTS = $(am_test_mesh_tree_api_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunetmesh_la_SOURCES) $(gnunet_service_mesh_SOURCES) \ $(test_mesh_2dtorus_SOURCES) $(test_mesh_api_SOURCES) \ $(test_mesh_local_1_SOURCES) $(test_mesh_local_2_SOURCES) \ $(test_mesh_small_multicast_SOURCES) \ $(test_mesh_small_speed_SOURCES) \ $(test_mesh_small_speed_ack_SOURCES) \ $(test_mesh_small_unicast_SOURCES) \ $(test_mesh_tree_api_SOURCES) DIST_SOURCES = $(libgnunetmesh_la_SOURCES) \ $(gnunet_service_mesh_SOURCES) $(test_mesh_2dtorus_SOURCES) \ $(test_mesh_api_SOURCES) $(test_mesh_local_1_SOURCES) \ $(test_mesh_local_2_SOURCES) \ $(test_mesh_small_multicast_SOURCES) \ $(test_mesh_small_speed_SOURCES) \ $(test_mesh_small_speed_ack_SOURCES) \ $(test_mesh_small_unicast_SOURCES) \ $(test_mesh_tree_api_SOURCES) DATA = $(pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @USE_COVERAGE_TRUE@XLIB = -lgcov pkgcfgdir = $(pkgdatadir)/config.d/ pkgcfg_DATA = \ mesh.conf AM_CLFAGS = -g lib_LTLIBRARIES = \ libgnunetmesh.la gnunet_service_mesh_SOURCES = \ gnunet-service-mesh.c \ mesh_tunnel_tree.c mesh_tunnel_tree.h gnunet_service_mesh_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la\ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/util/libgnunetutil.la gnunet_service_mesh_DEPENDENCIES = \ $(top_builddir)/src/core/libgnunetcore.la\ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunetmesh_la_SOURCES = \ mesh_api.c mesh.h mesh_protocol.h libgnunetmesh_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(XLIB) libgnunetmesh_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ -version-info 1:0:0 test_mesh_api_SOURCES = \ test_mesh_api.c test_mesh_api_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/mesh/libgnunetmesh.la test_mesh_api_DEPENDENCIES = \ libgnunetmesh.la \ $(top_builddir)/src/util/libgnunetutil.la test_mesh_tree_api_SOURCES = \ test_mesh_tree_api.c test_mesh_tree_api_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/dht/libgnunetdht.la test_mesh_tree_api_DEPENDENCIES = \ libgnunetmesh.la \ $(top_builddir)/src/dht/libgnunetdht.la test_mesh_local_1_SOURCES = \ test_mesh_local_1.c test_mesh_local_1_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/mesh/libgnunetmesh.la test_mesh_local_1_DEPENDENCIES = \ libgnunetmesh.la test_mesh_local_2_SOURCES = \ test_mesh_local_2.c test_mesh_local_2_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/mesh/libgnunetmesh.la test_mesh_local_2_DEPENDENCIES = \ libgnunetmesh.la test_mesh_2dtorus_SOURCES = \ test_mesh_2dtorus.c test_mesh_2dtorus_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la test_mesh_small_unicast_SOURCES = \ test_mesh_small.c test_mesh_small_unicast_LDADD = \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la test_mesh_small_unicast_DEPENDENCIES = \ libgnunetmesh.la test_mesh_small_multicast_SOURCES = \ test_mesh_small.c test_mesh_small_multicast_LDADD = \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la test_mesh_small_multicast_DEPENDENCIES = \ libgnunetmesh.la test_mesh_small_speed_SOURCES = \ test_mesh_small.c test_mesh_small_speed_LDADD = \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la test_mesh_small_speed_DEPENDENCIES = \ libgnunetmesh.la test_mesh_small_speed_ack_SOURCES = \ test_mesh_small.c test_mesh_small_speed_ack_LDADD = \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/testing/libgnunettesting.la test_mesh_small_speed_ack_DEPENDENCIES = \ libgnunetmesh.la EXTRA_DIST = \ test_mesh.conf \ test_mesh_2dtorus.conf \ test_mesh_small.conf \ test_mesh_path.conf all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/mesh/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/mesh/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mesh.conf: $(top_builddir)/config.status $(srcdir)/mesh.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunetmesh.la: $(libgnunetmesh_la_OBJECTS) $(libgnunetmesh_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetmesh_la_LINK) -rpath $(libdir) $(libgnunetmesh_la_OBJECTS) $(libgnunetmesh_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-service-mesh$(EXEEXT): $(gnunet_service_mesh_OBJECTS) $(gnunet_service_mesh_DEPENDENCIES) @rm -f gnunet-service-mesh$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_service_mesh_OBJECTS) $(gnunet_service_mesh_LDADD) $(LIBS) test_mesh_2dtorus$(EXEEXT): $(test_mesh_2dtorus_OBJECTS) $(test_mesh_2dtorus_DEPENDENCIES) @rm -f test_mesh_2dtorus$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_mesh_2dtorus_OBJECTS) $(test_mesh_2dtorus_LDADD) $(LIBS) test_mesh_api$(EXEEXT): $(test_mesh_api_OBJECTS) $(test_mesh_api_DEPENDENCIES) @rm -f test_mesh_api$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_mesh_api_OBJECTS) $(test_mesh_api_LDADD) $(LIBS) test_mesh_local_1$(EXEEXT): $(test_mesh_local_1_OBJECTS) $(test_mesh_local_1_DEPENDENCIES) @rm -f test_mesh_local_1$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_mesh_local_1_OBJECTS) $(test_mesh_local_1_LDADD) $(LIBS) test_mesh_local_2$(EXEEXT): $(test_mesh_local_2_OBJECTS) $(test_mesh_local_2_DEPENDENCIES) @rm -f test_mesh_local_2$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_mesh_local_2_OBJECTS) $(test_mesh_local_2_LDADD) $(LIBS) test_mesh_small_multicast$(EXEEXT): $(test_mesh_small_multicast_OBJECTS) $(test_mesh_small_multicast_DEPENDENCIES) @rm -f test_mesh_small_multicast$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_mesh_small_multicast_OBJECTS) $(test_mesh_small_multicast_LDADD) $(LIBS) test_mesh_small_speed$(EXEEXT): $(test_mesh_small_speed_OBJECTS) $(test_mesh_small_speed_DEPENDENCIES) @rm -f test_mesh_small_speed$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_mesh_small_speed_OBJECTS) $(test_mesh_small_speed_LDADD) $(LIBS) test_mesh_small_speed_ack$(EXEEXT): $(test_mesh_small_speed_ack_OBJECTS) $(test_mesh_small_speed_ack_DEPENDENCIES) @rm -f test_mesh_small_speed_ack$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_mesh_small_speed_ack_OBJECTS) $(test_mesh_small_speed_ack_LDADD) $(LIBS) test_mesh_small_unicast$(EXEEXT): $(test_mesh_small_unicast_OBJECTS) $(test_mesh_small_unicast_DEPENDENCIES) @rm -f test_mesh_small_unicast$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_mesh_small_unicast_OBJECTS) $(test_mesh_small_unicast_LDADD) $(LIBS) test_mesh_tree_api$(EXEEXT): $(test_mesh_tree_api_OBJECTS) $(test_mesh_tree_api_DEPENDENCIES) @rm -f test_mesh_tree_api$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_mesh_tree_api_OBJECTS) $(test_mesh_tree_api_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-mesh.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mesh_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mesh_tunnel_tree.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_mesh_2dtorus.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_mesh_api.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_mesh_local_1.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_mesh_local_2.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_mesh_small.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_mesh_tree_api.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgcfgDATA: $(pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgcfgDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-binPROGRAMS install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-pkgcfgDATA install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/mesh/mesh_protocol.h0000644000175000017500000001254011760502551014521 00000000000000/* This file is part of GNUnet. (C) 2001 - 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @author Bartlomiej Polot * @file mesh/mesh_protocol.h */ #ifndef MESH_PROTOCOL_H_ #define MESH_PROTOCOL_H_ #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /******************************************************************************/ /******************** MESH NETWORK MESSAGES **************************/ /******************************************************************************/ GNUNET_NETWORK_STRUCT_BEGIN /** * Message for mesh path management */ struct GNUNET_MESH_ManipulatePath { /** * Type: GNUNET_MESSAGE_TYPE_MESH_PATH_[CREATE|CHANGE|ADD|DEL] * * Size: sizeof(struct GNUNET_MESH_ManipulatePath) + * path_length * sizeof (struct GNUNET_PeerIdentity) */ struct GNUNET_MessageHeader header; /** * Global id of the tunnel this path belongs to, * unique in conjunction with the origin. */ uint32_t tid GNUNET_PACKED; /** * path_length structs defining the *whole* path from the origin [0] to the * final destination [path_length-1]. */ /* struct GNUNET_PeerIdentity peers[path_length]; */ }; /** * Message for mesh data traffic to all tunnel targets. */ struct GNUNET_MESH_Multicast { /** * Type: GNUNET_MESSAGE_TYPE_MESH_MULTICAST */ struct GNUNET_MessageHeader header; /** * TID of the tunnel */ uint32_t tid GNUNET_PACKED; /** * Number of hops to live */ uint32_t ttl GNUNET_PACKED; /** * Unique ID of the packet */ uint32_t mid GNUNET_PACKED; /** * OID of the tunnel */ struct GNUNET_PeerIdentity oid; /** * Payload follows */ }; /** * Message for mesh data traffic to a particular destination from origin. */ struct GNUNET_MESH_Unicast { /** * Type: GNUNET_MESSAGE_TYPE_MESH_UNICAST */ struct GNUNET_MessageHeader header; /** * TID of the tunnel */ uint32_t tid GNUNET_PACKED; /** * OID of the tunnel */ struct GNUNET_PeerIdentity oid; /** * Destination. */ struct GNUNET_PeerIdentity destination; /** * Payload follows */ }; /** * Message for mesh data traffic from a tunnel participant to origin. */ struct GNUNET_MESH_ToOrigin { /** * Type: GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN */ struct GNUNET_MessageHeader header; /** * TID of the tunnel */ uint32_t tid GNUNET_PACKED; /** * OID of the tunnel */ struct GNUNET_PeerIdentity oid; /** * Sender of the message. */ struct GNUNET_PeerIdentity sender; /** * Payload follows */ }; /** * Message for ack'ing a path */ struct GNUNET_MESH_PathACK { /** * Type: GNUNET_MESSAGE_TYPE_MESH_PATH_ACK */ struct GNUNET_MessageHeader header; /** * TID of the tunnel */ uint32_t tid GNUNET_PACKED; /** * OID of the tunnel */ struct GNUNET_PeerIdentity oid; /** * ID of the endpoint */ struct GNUNET_PeerIdentity peer_id; /* TODO: signature */ }; /** * Message for notifying a disconnection in a path */ struct GNUNET_MESH_PathBroken { /** * Type: GNUNET_MESSAGE_TYPE_MESH_PATH_BROKEN */ struct GNUNET_MessageHeader header; /** * TID of the tunnel */ uint32_t tid GNUNET_PACKED; /** * OID of the tunnel */ struct GNUNET_PeerIdentity oid; /** * ID of the endpoint */ struct GNUNET_PeerIdentity peer1; /** * ID of the endpoint */ struct GNUNET_PeerIdentity peer2; /* TODO: signature */ }; /** * Message to destroy a tunnel */ struct GNUNET_MESH_TunnelDestroy { /** * Type: GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY */ struct GNUNET_MessageHeader header; /** * TID of the tunnel */ uint32_t tid GNUNET_PACKED; /** * OID of the tunnel */ struct GNUNET_PeerIdentity oid; /* TODO: signature */ }; /** * Message for mesh flow control */ struct GNUNET_MESH_SpeedNotify { /** * Type: GNUNET_MESSAGE_TYPE_DATA_SPEED_NOTIFY */ struct GNUNET_MessageHeader header; /** * TID of the tunnel */ uint32_t tid GNUNET_PACKED; /** * OID of the tunnel */ struct GNUNET_PeerIdentity oid; /** * Slowest link down the path (above minimum speed requirement). */ uint32_t speed_min; }; GNUNET_NETWORK_STRUCT_END #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef MES_PROTOCOL_H */ #endif /* end of mesh_protocol.h */ gnunet-0.9.3/src/gns/0000755000175000017500000000000011763406750011413 500000000000000gnunet-0.9.3/src/gns/test_gns_simple_get_authority.c0000644000175000017500000002652011760520032017635 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file gns/test_gns_simple_shorten.c * @brief basic shorten test for gns api * */ #include "platform.h" #include "gnunet_testing_lib.h" #include "gnunet_core_service.h" #include "block_dns.h" #include "gnunet_signatures.h" #include "gnunet_namestore_service.h" #include "../namestore/namestore.h" #include "gnunet_dnsparser_lib.h" #include "gnunet_gns_service.h" /* DEFINES */ #define VERBOSE GNUNET_YES /* Timeout for entire testcase */ #define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 20) /* If number of peers not in config file, use this number */ #define DEFAULT_NUM_PEERS 2 /* test records to resolve */ #define TEST_DOMAIN "www.alice.bob.gnunet" #define TEST_IP "127.0.0.1" #define TEST_RECORD_NAME "www" #define TEST_AUTHORITY_BOB "bob" #define TEST_AUTHORITY_ALICE "alice" #define TEST_ALICE_PSEU "carol" #define TEST_EXPECTED_RESULT "alice.bob.gnunet" #define KEYFILE_BOB "../namestore/zonefiles/HGU0A0VCU334DN7F2I9UIUMVQMM7JMSD142LIMNUGTTV9R0CF4EG.zkey" #define KEYFILE_ALICE "../namestore/zonefiles/N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey" /* Globals */ /** * Directory to store temp data in, defined in config file */ static char *test_directory; static struct GNUNET_TESTING_PeerGroup *pg; /* Task handle to use to schedule test failure */ GNUNET_SCHEDULER_TaskIdentifier die_task; /* Global return value (0 for success, anything else for failure) */ static int ok; static struct GNUNET_NAMESTORE_Handle *namestore_handle; static struct GNUNET_GNS_Handle *gns_handle; const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Check whether peers successfully shut down. */ static void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error on shutdown! ret=%d\n", ok); if (ok == 0) ok = 2; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "done(ret=%d)!\n", ok); } /** * Called when gns_get_authority finishes */ static void process_auth_result(void* cls, const char* aname) { GNUNET_GNS_disconnect(gns_handle); ok = 0; if (aname == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "get_authority test failed!\n"); ok = 1; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s authority is %s\n", (char*)cls, aname); if (0 != strcmp(aname, TEST_EXPECTED_RESULT)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "get_authority test failed! (wanted: %s got: %s\n", TEST_EXPECTED_RESULT, aname); ok = 1; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "get_authority test finished!\n"); } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down peer1!\n"); GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); } /** * Function scheduled to be run on the successful start of services * tries to shorten the name TEST_DOMAIN using gns */ static void commence_testing (void *cls, int32_t success, const char *emsg) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnecting from namestore\n"); GNUNET_NAMESTORE_disconnect(namestore_handle, GNUNET_YES); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connecting to gns\n"); gns_handle = GNUNET_GNS_connect(cfg); if (NULL == gns_handle) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "failed to connect to gns\n"); ok = 1; return; } GNUNET_GNS_get_authority(gns_handle, TEST_DOMAIN, &process_auth_result, TEST_DOMAIN); } /** * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut * down the peers without freeing memory associated with GET request. */ static void end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (pg != NULL) GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); GNUNET_SCHEDULER_cancel (die_task); } /** * Check if the get_handle is being used, if so stop the request. Either * way, schedule the end_badly_cont function which actually shuts down the * test. */ static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failing test with error: `%s'!\n", (char *) cls); GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL); ok = 1; } static void do_shorten(void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *_cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded our_pkey; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded alice_pkey; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded bob_pkey; struct GNUNET_CRYPTO_RsaPrivateKey *our_key; struct GNUNET_CRYPTO_RsaPrivateKey *alice_key; struct GNUNET_CRYPTO_RsaPrivateKey *bob_key; struct GNUNET_CRYPTO_ShortHashCode bob_hash; struct GNUNET_CRYPTO_ShortHashCode alice_hash; struct GNUNET_CRYPTO_RsaSignature *sig; char* our_keyfile; cfg = _cfg; GNUNET_SCHEDULER_cancel (die_task); /* put records into namestore */ namestore_handle = GNUNET_NAMESTORE_connect(cfg); if (NULL == namestore_handle) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to namestore\n"); ok = -1; return; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", "ZONEKEY", &our_keyfile)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n"); ok = -1; return; } our_key = GNUNET_CRYPTO_rsa_key_create_from_file (our_keyfile); GNUNET_free(our_keyfile); bob_key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE_BOB); alice_key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE_ALICE); GNUNET_CRYPTO_rsa_key_get_public (our_key, &our_pkey); GNUNET_CRYPTO_rsa_key_get_public (alice_key, &alice_pkey); GNUNET_CRYPTO_rsa_key_get_public (bob_key, &bob_pkey); struct GNUNET_NAMESTORE_RecordData rd; char* ip = TEST_IP; struct in_addr *web = GNUNET_malloc(sizeof(struct in_addr)); rd.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; GNUNET_assert(1 == inet_pton (AF_INET, ip, web)); GNUNET_CRYPTO_short_hash(&bob_pkey, sizeof(bob_pkey), &bob_hash); rd.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode); rd.data = &bob_hash; rd.record_type = GNUNET_GNS_RECORD_PKEY; /* put bob into our zone */ GNUNET_NAMESTORE_record_create (namestore_handle, our_key, TEST_AUTHORITY_BOB, &rd, NULL, NULL); /* put alice into bobs zone */ GNUNET_CRYPTO_short_hash(&alice_pkey, sizeof(alice_pkey), &alice_hash); rd.data = &alice_hash; sig = GNUNET_NAMESTORE_create_signature(bob_key, GNUNET_TIME_UNIT_FOREVER_ABS, TEST_AUTHORITY_ALICE, &rd, 1); GNUNET_NAMESTORE_record_put (namestore_handle, &bob_pkey, TEST_AUTHORITY_ALICE, GNUNET_TIME_UNIT_FOREVER_ABS, 1, &rd, sig, NULL, NULL); /* put www A record and PSEU into alice's zone */ rd.data_size = sizeof(struct in_addr); rd.data = web; rd.record_type = GNUNET_DNSPARSER_TYPE_A; sig = GNUNET_NAMESTORE_create_signature(alice_key,GNUNET_TIME_UNIT_FOREVER_ABS, TEST_RECORD_NAME, &rd, 1); GNUNET_NAMESTORE_record_put (namestore_handle, &alice_pkey, TEST_RECORD_NAME, GNUNET_TIME_UNIT_FOREVER_ABS, 1, &rd, sig, NULL, NULL); rd.data_size = strlen(TEST_ALICE_PSEU); rd.data = TEST_ALICE_PSEU; rd.record_type = GNUNET_GNS_RECORD_PSEU; GNUNET_free(sig); sig = GNUNET_NAMESTORE_create_signature(alice_key,GNUNET_TIME_UNIT_FOREVER_ABS, "", &rd, 1); GNUNET_NAMESTORE_record_put (namestore_handle, &alice_pkey, "", GNUNET_TIME_UNIT_FOREVER_ABS, 1, &rd, sig, &commence_testing, NULL); GNUNET_free(sig); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { cfg = c; /* Get path from configuration file */ if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", &test_directory)) { ok = 404; return; } /* Set up a task to end testing if peer start fails */ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "didn't start all daemons in reasonable amount of time!!!"); /* Start alice */ pg = GNUNET_TESTING_daemons_start(cfg, 1, 1, 1, TIMEOUT, NULL, NULL, &do_shorten, NULL, NULL, NULL, NULL); } static int check () { int ret; /* Arguments for GNUNET_PROGRAM_run */ char *const argv[] = { "test-gns-simple-get-authority", /* Name to give running binary */ "-c", "test_gns_simple_lookup.conf", /* Config file to use */ #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; /* Run the run function as a new program */ ret = GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-gns-simple-get-authority", "nohelp", options, &run, &ok); if (ret != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "`test-gns-simple-get-authority': Failed with error code %d\n", ret); } return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-gns-simple-lookup", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); /** * Need to remove base directory, subdirectories taken care * of by the testing framework. */ return ret; } /* end of test_gns_twopeer.c */ gnunet-0.9.3/src/gns/test_gns_dht_threepeer.c0000644000175000017500000003606111760502551016226 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file gns/test_gns_dht_threepeer.c * @brief tests dht lookup over 3 peers * * topology: * alice <----> bob <-----> dave * * alice queries for www.buddy.bob.gnunet * */ #include "platform.h" #include "gnunet_disk_lib.h" #include "gnunet_testing_lib.h" #include "gnunet_core_service.h" #include "gnunet_dht_service.h" #include "block_dns.h" #include "gnunet_signatures.h" #include "gnunet_namestore_service.h" #include "gnunet_dnsparser_lib.h" #include "gnunet_gns_service.h" /* DEFINES */ #define VERBOSE GNUNET_YES /* Timeout for entire testcase */ #define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 180) #define ZONE_PUT_WAIT_TIME GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30) /* If number of peers not in config file, use this number */ #define DEFAULT_NUM_PEERS 2 #define TEST_DOMAIN "www.buddy.bob.gnunet" #define TEST_IP "1.1.1.1" #define TEST_DAVE_PSEU "hagbard" #define TEST_NUM_PEERS 3 #define TEST_NUM_CON 3 /* Globals */ /** * Directory to store temp data in, defined in config file */ static char *test_directory; /** * Variable used to store the number of connections we should wait for. */ static unsigned int expected_connections; /** * Variable used to keep track of how many peers aren't yet started. */ static unsigned long long peers_left; struct GNUNET_TESTING_Daemon *d1; struct GNUNET_TESTING_Daemon *d2; struct GNUNET_TESTING_Daemon *d3; /** * Total number of peers to run, set based on config file. */ static unsigned long long num_peers; /** * Global used to count how many connections we have currently * been notified about (how many times has topology_callback been called * with success?) */ static unsigned int total_connections; /** * Global used to count how many failed connections we have * been notified about (how many times has topology_callback * been called with failure?) */ static unsigned int failed_connections; /* Task handle to use to schedule test failure */ GNUNET_SCHEDULER_TaskIdentifier die_task; GNUNET_SCHEDULER_TaskIdentifier bob_task; /* Global return value (0 for success, anything else for failure) */ static int ok; int bob_online, alice_online, dave_online; const struct GNUNET_CONFIGURATION_Handle *alice_cfg; struct GNUNET_CONFIGURATION_Handle *cfg_bob; struct GNUNET_CONFIGURATION_Handle *cfg_dave; struct GNUNET_CRYPTO_ShortHashCode bob_hash; struct GNUNET_CRYPTO_ShortHashCode dave_hash; struct GNUNET_TESTING_Daemon *alice_daemon; struct GNUNET_TESTING_Daemon *bob_daemon; struct GNUNET_TESTING_Daemon *dave_daemon; struct GNUNET_TESTING_PeerGroup *pg; struct GNUNET_GNS_Handle *gh; /** * Function scheduled to be run on the successful completion of this * testcase. Specifically, called when our get request completes. */ static void finish_testing (void *cls, const char *emsg) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Test finished! (ret=%d)\n", ok); } /** * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut * down the peers without freeing memory associated with GET request. */ static void end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { die_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &finish_testing, NULL); } /** * Check if the get_handle is being used, if so stop the request. Either * way, schedule the end_badly_cont function which actually shuts down the * test. */ static void end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { die_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Failing test with error: `%s'!\n", (char *) cls); die_task = GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL); ok = 1; } static void on_lookup_result(void *cls, uint32_t rd_count, const struct GNUNET_NAMESTORE_RecordData *rd) { int i; char* string_val; const char* typename; if (rd_count == 0) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Lookup failed!\n"); ok = 2; } else { ok = 1; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "name: %s\n", (char*)cls); for (i=0; ishortname, second_daemon->shortname, distance); #endif } #if VERBOSE else { failed_connections++; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Failed to connect peer %s to peer %s with error :\n%s\n", first_daemon->shortname, second_daemon->shortname, emsg); } #endif if (total_connections == expected_connections) { #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Created %d total connections, which is our target number! Starting next phase of testing.\n", total_connections); #endif GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_NO_TASK; //die_task = // GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "from connect"); //commence_testing(); } else if (total_connections + failed_connections == expected_connections) { GNUNET_SCHEDULER_cancel (die_task); die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from topology_callback (too many failed connections)"); } } void all_connected(void *cls, const char *emsg) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Created all connections! Starting next phase of testing.\n"); GNUNET_SCHEDULER_add_delayed (ZONE_PUT_WAIT_TIME, &commence_testing, NULL); } void ns_create_cont(void *cls, int32_t s, const char *emsg) { GNUNET_NAMESTORE_disconnect((struct GNUNET_NAMESTORE_Handle *)cls, 0); } static void daemon_started (void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { struct GNUNET_NAMESTORE_Handle *ns; char* keyfile; struct GNUNET_CRYPTO_RsaPrivateKey *key; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; struct in_addr *web; struct GNUNET_NAMESTORE_RecordData rd; rd.flags = GNUNET_NAMESTORE_RF_AUTHORITY | GNUNET_NAMESTORE_RF_NONE; rd.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; if (NULL == dave_daemon) { if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", "ZONEKEY", &keyfile)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n"); ok = -1; return; } dave_daemon = d; key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This is now dave\n"); ns = GNUNET_NAMESTORE_connect(cfg); GNUNET_CRYPTO_rsa_key_get_public (key, &pkey); GNUNET_CRYPTO_short_hash(&pkey, sizeof(pkey), &dave_hash); web = GNUNET_malloc(sizeof(struct in_addr)); GNUNET_assert(1 == inet_pton (AF_INET, TEST_IP, web)); rd.data_size = sizeof(struct in_addr); rd.data = web; rd.record_type = GNUNET_GNS_RECORD_TYPE_A; GNUNET_NAMESTORE_record_create (ns, key, "www", &rd, NULL, NULL); rd.data_size = strlen(TEST_DAVE_PSEU); rd.data = TEST_DAVE_PSEU; rd.record_type = GNUNET_GNS_RECORD_PSEU; GNUNET_NAMESTORE_record_create (ns, key, "+", &rd, ns_create_cont, ns); GNUNET_CRYPTO_rsa_key_free(key); GNUNET_free(keyfile); GNUNET_free(web); return; } if (NULL == bob_daemon) { if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", "ZONEKEY", &keyfile)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n"); ok = -1; return; } bob_daemon = d; key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This is now bob\n"); ns = GNUNET_NAMESTORE_connect(cfg); GNUNET_CRYPTO_rsa_key_get_public (key, &pkey); GNUNET_CRYPTO_short_hash(&pkey, sizeof(pkey), &bob_hash); rd.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode); rd.data = &dave_hash; rd.record_type = GNUNET_GNS_RECORD_PKEY; GNUNET_NAMESTORE_record_create (ns, key, "buddy", &rd, ns_create_cont, ns); GNUNET_CRYPTO_rsa_key_free(key); GNUNET_free(keyfile); return; } if (NULL == alice_daemon) { if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", "ZONEKEY", &keyfile)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n"); ok = -1; return; } alice_daemon = d; alice_cfg = cfg; key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This is now alice\n"); ns = GNUNET_NAMESTORE_connect(cfg); rd.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode); rd.data = &bob_hash; rd.record_type = GNUNET_GNS_RECORD_PKEY; GNUNET_NAMESTORE_record_create (ns, key, "bob", &rd, ns_create_cont, ns); GNUNET_CRYPTO_rsa_key_free(key); GNUNET_free(keyfile); GNUNET_TESTING_connect_topology (pg, GNUNET_TESTING_TOPOLOGY_CLIQUE, GNUNET_TESTING_TOPOLOGY_OPTION_ALL, 0, TIMEOUT, 3, &all_connected, NULL); return; } GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This is a random guy\n"); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { /* Get path from configuration file */ if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", &test_directory)) { ok = 404; return; } GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "starting\n"); /* Get number of peers to start from configuration (should be two) */ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", &num_peers)) num_peers = DEFAULT_NUM_PEERS; /* Set peers_left so we know when all peers started */ peers_left = num_peers; bob_daemon = NULL; dave_daemon = NULL; alice_daemon = NULL; pg = GNUNET_TESTING_daemons_start (cfg, TEST_NUM_PEERS, TEST_NUM_CON, TEST_NUM_CON, TIMEOUT, NULL, NULL, &daemon_started, NULL, &daemon_connected, NULL, NULL); /* Set up a task to end testing if peer start fails */ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "didn't start all daemons in reasonable amount of time!!!"); alice_online = 0; bob_online = 0; dave_online = 0; expected_connections = 2; /* Start alice */ //d1 = GNUNET_TESTING_daemon_start(cfg_alice, TIMEOUT, GNUNET_NO, NULL, NULL, 0, // NULL, NULL, NULL, &alice_started, NULL); } static int check () { int ret; /* Arguments for GNUNET_PROGRAM_run */ char *const argv[] = { "test-gns-twopeer", /* Name to give running binary */ "-c", "test_gns_dht_default.conf", /* Config file to use */ #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; /* Run the run function as a new program */ ret = GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-gns-threepeer", "nohelp", options, &run, &ok); if (ret != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "`test-gns-threepeer': Failed with error code %d\n", ret); } return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-gns-threepeer", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); /** * Need to remove base directory, subdirectories taken care * of by the testing framework. */ return ret; } /* end of test_gns_threepeer.c */ gnunet-0.9.3/src/gns/test_gns_simple_lookup.conf0000644000175000017500000000351011761764434016775 00000000000000@INLINE@ test_gns_defaults.conf [fs] AUTOSTART = NO [resolver] AUTOSTART = NO HOSTNAME = localhost [dht] DEBUG = NO AUTOSTART = YES ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; HOSTNAME = localhost PORT = 12100 BINARY = gnunet-service-dht [block] plugins = dht test gns [dhtcache] QUOTA = 1 MB DATABASE = sqlite [transport] PLUGINS = tcp DEBUG = NO ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; NEIGHBOUR_LIMIT = 50 PORT = 12365 [ats] WAN_QUOTA_IN = 1 GB WAN_QUOTA_OUT = 1 GB [core] PORT = 12092 [arm] DEFAULTSERVICES = core dht namestore gns PORT = 12366 DEBUG = NO [transport-tcp] TIMEOUT = 300 s PORT = 12368 BINDTO = 127.0.0.1 [TESTING] WEAKRANDOM = YES [gnunetd] HOSTKEY = $SERVICEHOME/.hostkey [PATHS] DEFAULTCONFIG = test_gns_simple_lookup.conf SERVICEHOME = /tmp/test-gnunetd-gns-peer-1/ [nat] DISABLEV6 = YES ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 USE_LOCALADDR = NO [dns] AUTOSTART = YES DNS_EXIT = 8.8.8.8 [gns] #PREFIX = valgrind -v --leak-check=full --track-origins=yes AUTOSTART = YES BINARY = gnunet-service-gns ZONEKEY = $SERVICEHOME/.hostkey #ZONEKEY = $SERVICEHOME/gns/zonekey.zkey HIJACK_DNS = NO UNIXPATH = /tmp/gnunet-service-gns.sock HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG AUTO_IMPORT_PKEY = YES MAX_PARALLEL_BACKGROUND_QUERIES = 10 DEFAULT_LOOKUP_TIMEOUT = 5 RECORD_PUT_INTERVAL = 1 ZONE_PUT_INTERVAL = 5 [nse] AUTOSTART = NO [statistics] AUTOSTART = NO [namestore] PORT = 22371 AUTOSTART = YES UNIXPATH = /tmp/gnunet-service-namestore-default.sock UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-namestore ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DATABASE = sqlite ZONEFILE_DIRECTORY = $SERVICEHOME [namestore-sqlite] FILENAME = $SERVICEHOME/sqlite-default.db gnunet-0.9.3/src/gns/Makefile.am0000644000175000017500000002273411762422560013373 00000000000000INCLUDES = -I$(top_srcdir)/src/include if HAVE_GLIBCNSS NSS_SUBDIR = nss endif SUBDIRS = . $(NSS_SUBDIR) if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 endif pkgcfgdir= $(pkgdatadir)/config.d/ plugindir = $(libdir)/gnunet pkgcfg_DATA = \ gns.conf lib_LTLIBRARIES = \ libgnunetgns.la if HAVE_MHD DO_FCFSD=gnunet-gns-fcfsd DO_PROXY=gnunet-gns-proxy endif bin_PROGRAMS = \ gnunet-service-gns \ $(DO_FCFSD) \ $(DO_PROXY) \ gnunet-gns #noinst_PROGRAMS = \ # gnunet-gns-lookup check_PROGRAMS = \ test_gns_simple_shorten \ test_gns_simple_get_authority \ test_gns_simple_lookup \ test_gns_simple_delegated_lookup \ test_gns_simple_mx_lookup \ test_gns_simple_zkey_lookup \ test_gns_dht_delegated_lookup \ test_gns_pseu_shorten \ test_gns_max_queries \ test_gns_dht_threepeer # test_gns_simple_lookup # test_gns_simple_delegated_lookup # test_gns_dht_delegated_lookup plugin_LTLIBRARIES = \ libgnunet_plugin_block_gns.la test_gns_dht_threepeer_SOURCES = \ test_gns_dht_threepeer.c test_gns_dht_threepeer_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_dht_threepeer_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_lookup_SOURCES = \ test_gns_simple_lookup.c test_gns_simple_lookup_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_lookup_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_delegated_lookup_SOURCES = \ test_gns_simple_delegated_lookup.c test_gns_simple_delegated_lookup_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_delegated_lookup_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_mx_lookup_SOURCES = \ test_gns_simple_mx_lookup.c test_gns_simple_mx_lookup_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_mx_lookup_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_zkey_lookup_SOURCES = \ test_gns_simple_zkey_lookup.c test_gns_simple_zkey_lookup_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_zkey_lookup_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_dht_delegated_lookup_SOURCES = \ test_gns_dht_delegated_lookup.c test_gns_dht_delegated_lookup_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_dht_delegated_lookup_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_shorten_SOURCES = \ test_gns_simple_shorten.c test_gns_simple_shorten_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_shorten_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_get_authority_SOURCES = \ test_gns_simple_get_authority.c test_gns_simple_get_authority_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_get_authority_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_pseu_shorten_SOURCES = \ test_gns_pseu_shorten.c test_gns_pseu_shorten_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_pseu_shorten_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_max_queries_SOURCES = \ test_gns_max_queries.c test_gns_max_queries_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_max_queries_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la gnunet_gns_SOURCES = \ gnunet-gns.c gnunet_gns_LDADD = \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(GN_LIBINTL) gnunet_gns_DEPENDENCIES = \ libgnunetgns.la gnunet_gns_proxy_SOURCES = \ gnunet-gns-proxy.c gns_proxy_proto.h gnunet_gns_proxy_LDADD = -lmicrohttpd \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_gns_proxy_DEPENDENCIES = \ libgnunetgns.la gnunet_service_gns_SOURCES = \ gnunet-service-gns.c \ gnunet-service-gns_resolver.c gnunet-service-gns_resolver.h \ gnunet-service-gns_interceptor.c gnunet-service-gns_interceptor.h gnunet_service_gns_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/dns/libgnunetdns.la \ $(top_builddir)/src/dns/libgnunetdnsparser.la \ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(GN_LIBINTL) gnunet_service_gns_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/dns/libgnunetdns.la \ $(top_builddir)/src/dns/libgnunetdnsparser.la \ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la gnunet_gns_fcfsd_SOURCES = \ gnunet-gns-fcfsd.c gnunet_gns_fcfsd_LDADD = -lmicrohttpd \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(GN_LIBINTL) gnunet_gns_fcfsd_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la libgnunetgns_la_SOURCES = \ gns_api.c gns.h libgnunetgns_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la $(XLIB) \ $(top_builddir)/src/namestore/libgnunetnamestore.la libgnunetgns_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) libgnunetgns_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la libgnunet_plugin_block_gns_la_SOURCES = \ plugin_block_gns.c libgnunet_plugin_block_gns_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/block/libgnunetblock.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la libgnunet_plugin_block_gns_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_block_gns_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/block/libgnunetblock.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la #Build stub api #libgnunetnamestore_la_SOURCES = \ # namestore_stub_api.c #libgnunetnamestore_la_LIBADD = \ # $(top_builddir)/src/util/libgnunetutil.la $(XLIB) #libgnunetnamestore_la_LDFLAGS = \ # $(GN_LIB_LDFLAGS) #libgnunetnamestore_la_DEPENDENCIES = \ # $(top_builddir)/src/util/libgnunetutil.la if ENABLE_TEST_RUN if LINUX TESTS = $(check_PROGRAMS) endif endif EXTRA_DIST = \ test_gns_defaults.conf \ test_gns_simple_lookup.conf \ test_gns_dht_default.conf gnunet-0.9.3/src/gns/test_gns_simple_delegated_lookup.c0000644000175000017500000002507311760520007020261 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file gns/test_gns_twopeer.c * @brief base testcase for testing DHT service with * two running peers. * * This testcase starts peers using the GNUNET_TESTING_daemons_start * function call. On peer start, connects to the peers DHT service * by calling GNUNET_DHT_connected. Once notified about all peers * being started (by the peers_started_callback function), calls * GNUNET_TESTING_connect_topology, which connects the peers in a * "straight line" topology. On notification that all peers have * been properly connected, calls the do_get function which initiates * a GNUNET_DHT_get from the *second* peer. Once the GNUNET_DHT_get * function starts, runs the do_put function to insert data at the first peer. * If the GET is successful, schedules finish_testing * to stop the test and shut down peers. If GET is unsuccessful * after GET_TIMEOUT seconds, prints an error message and shuts down * the peers. */ #include "platform.h" #include "gnunet_testing_lib.h" #include "gnunet_core_service.h" #include "block_dns.h" #include "gnunet_signatures.h" #include "gnunet_namestore_service.h" #include "../namestore/namestore.h" #include "gnunet_dnsparser_lib.h" #include "gnunet_gns_service.h" /* DEFINES */ #define VERBOSE GNUNET_YES /* Timeout for entire testcase */ #define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 20) /* If number of peers not in config file, use this number */ #define DEFAULT_NUM_PEERS 2 /* test records to resolve */ #define TEST_DOMAIN "www.bob.gnunet" #define TEST_IP "127.0.0.1" #define TEST_RECORD_NAME "www" #define TEST_AUTHORITY_NAME "bob" #define KEYFILE_BOB "../namestore/zonefiles/HGU0A0VCU334DN7F2I9UIUMVQMM7JMSD142LIMNUGTTV9R0CF4EG.zkey" /* Globals */ /** * Directory to store temp data in, defined in config file */ static char *test_directory; static struct GNUNET_TESTING_PeerGroup *pg; /* Task handle to use to schedule test failure */ GNUNET_SCHEDULER_TaskIdentifier die_task; /* Global return value (0 for success, anything else for failure) */ static int ok; static struct GNUNET_NAMESTORE_Handle *namestore_handle; static struct GNUNET_GNS_Handle *gns_handle; const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Check whether peers successfully shut down. */ void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error on shutdown! ret=%d\n", ok); if (ok == 0) ok = 2; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "done(ret=%d)!\n", ok); } static void on_lookup_result(void *cls, uint32_t rd_count, const struct GNUNET_NAMESTORE_RecordData *rd) { struct in_addr a; int i; char* addr; if (rd_count == 0) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Lookup failed, rp_filtering?\n"); ok = 2; } else { ok = 1; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "name: %s\n", (char*)cls); for (i=0; i #include #include /** * Invalid method page. */ #define METHOD_ERROR "Illegal requestGo away." /** * Front page. (/) */ #define MAIN_PAGE "GNUnet FCFS Authority Name Registration Service

    What is your desired domain name?

    What is your public key? " /** * Second page (/S) */ #define SUBMIT_PAGE "%s%s" /** * Mime type for HTML pages. */ #define MIME_HTML "text/html" /** * Name of our cookie. */ #define COOKIE_NAME "gns-fcfs" /** * Phases a request goes through. */ enum Phase { /** * Start phase (parsing POST, checking). */ RP_START = 0, /** * Lookup to see if the domain name is taken. */ RP_LOOKUP, /** * Storing of the record. */ RP_PUT, /** * We're done with success. */ RP_SUCCESS, /** * Send failure message. */ RP_FAIL }; /** * Data kept per request. */ struct Request { /** * Associated session. */ struct Session *session; /** * Post processor handling form data (IF this is * a POST request). */ struct MHD_PostProcessor *pp; /** * URL to serve in response to this POST (if this request * was a 'POST') */ const char *post_url; /** * Active request with the namestore. */ struct GNUNET_NAMESTORE_QueueEntry *qe; /** * Current processing phase. */ enum Phase phase; /** * Domain name submitted via form. */ char domain_name[64]; /** * Public key submitted via form. */ char public_key[64]; }; /** * MHD deamon reference. */ static struct MHD_Daemon *httpd; /** * Main HTTP task. */ static GNUNET_SCHEDULER_TaskIdentifier httpd_task; /** * Handle to the namestore. */ static struct GNUNET_NAMESTORE_Handle *ns; /** * Hash of the public key of the fcfsd zone. */ static struct GNUNET_CRYPTO_ShortHashCode fcfsd_zone; /** * Private key for the fcfsd zone. */ static struct GNUNET_CRYPTO_RsaPrivateKey *fcfs_zone_pkey; /** * Handler that returns a simple static HTTP page. * * @param connection connection to use * @return MHD_YES on success */ static int serve_main_page (struct MHD_Connection *connection) { int ret; struct MHD_Response *response; /* return static form */ response = MHD_create_response_from_buffer (strlen (MAIN_PAGE), (void *) MAIN_PAGE, MHD_RESPMEM_PERSISTENT); MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE, MIME_HTML); ret = MHD_queue_response (connection, MHD_HTTP_OK, response); MHD_destroy_response (response); return ret; } /** * Send the 'SUBMIT_PAGE'. * * @param info information string to send to the user * @param request request information * @param connection connection to use */ static int fill_s_reply (const char *info, struct Request *request, struct MHD_Connection *connection) { int ret; char *reply; struct MHD_Response *response; GNUNET_asprintf (&reply, SUBMIT_PAGE, info, info); /* return static form */ response = MHD_create_response_from_buffer (strlen (reply), (void *) reply, MHD_RESPMEM_MUST_FREE); MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE, MIME_HTML); ret = MHD_queue_response (connection, MHD_HTTP_OK, response); MHD_destroy_response (response); return ret; } /** * Iterator over key-value pairs where the value * maybe made available in increments and/or may * not be zero-terminated. Used for processing * POST data. * * @param cls user-specified closure * @param kind type of the value * @param key 0-terminated key for the value * @param filename name of the uploaded file, NULL if not known * @param content_type mime-type of the data, NULL if not known * @param transfer_encoding encoding of the data, NULL if not known * @param data pointer to size bytes of data at the * specified offset * @param off offset of data in the overall value * @param size number of bytes in data available * @return MHD_YES to continue iterating, * MHD_NO to abort the iteration */ static int post_iterator (void *cls, enum MHD_ValueKind kind, const char *key, const char *filename, const char *content_type, const char *transfer_encoding, const char *data, uint64_t off, size_t size) { struct Request *request = cls; if (0 == strcmp ("domain", key)) { if (size + off >= sizeof(request->domain_name)) size = sizeof (request->domain_name) - off - 1; memcpy (&request->domain_name[off], data, size); request->domain_name[size+off] = '\0'; return MHD_YES; } if (0 == strcmp ("pkey", key)) { if (size + off >= sizeof(request->public_key)) size = sizeof (request->public_key) - off - 1; memcpy (&request->public_key[off], data, size); request->public_key[size+off] = '\0'; return MHD_YES; } GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported form value `%s'\n"), key); return MHD_YES; } /** * Task run whenever HTTP server operations are pending. * * @param cls unused * @param tc scheduler context */ static void do_httpd (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Schedule task to run MHD server now. */ static void run_httpd_now () { if (GNUNET_SCHEDULER_NO_TASK != httpd_task) { GNUNET_SCHEDULER_cancel (httpd_task); httpd_task = GNUNET_SCHEDULER_NO_TASK; } httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd, NULL); } /** * Continuation called to notify client about result of the * operation. * * @param cls closure * @param success GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate) * GNUNET_NO if content was already there * GNUNET_YES (or other positive value) on success * @param emsg NULL on success, otherwise an error message */ static void put_continuation (void *cls, int32_t success, const char *emsg) { struct Request *request = cls; request->qe = NULL; if (0 >= success) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to create record for domain `%s': %s\n"), request->domain_name, emsg); request->phase = RP_FAIL; } else request->phase = RP_SUCCESS; run_httpd_now (); } /** * Test if a name mapping was found, if so, refuse. If not, initiate storing of the record. * * @param cls closure * @param zone_key public key of the zone * @param expire when does the corresponding block in the DHT expire (until * when should we never do a DHT lookup for the same name again)?; * GNUNET_TIME_UNIT_ZERO_ABS if there are no records of any type in the namestore, * or the expiration time of the block in the namestore (even if there are zero * records matching the desired record type) * @param name name that is being mapped (at most 255 characters long) * @param rd_count number of entries in 'rd' array * @param rd array of records with data to store * @param signature signature of the record block, NULL if signature is unavailable (i.e. * because the user queried for a particular record type only) */ static void zone_to_name_cb (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *name, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { struct Request *request = cls; struct GNUNET_NAMESTORE_RecordData r; struct GNUNET_CRYPTO_ShortHashCode pub; request->qe = NULL; if (NULL != name) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Found existing name `%s' for the given key\n"), name); request->phase = RP_FAIL; run_httpd_now (); return; } GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_short_hash_from_string2 (request->public_key, strlen (request->public_key), &pub)); r.data = &pub; r.data_size = sizeof (pub); r.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; r.record_type = GNUNET_NAMESTORE_TYPE_PKEY; r.flags = GNUNET_NAMESTORE_RF_AUTHORITY; request->qe = GNUNET_NAMESTORE_record_create (ns, fcfs_zone_pkey, request->domain_name, &r, &put_continuation, request); } /** * Process a record that was stored in the namestore. Used to check if * the requested name already exists in the namestore. If not, * proceed to check if the requested key already exists. * * @param cls closure * @param zone_key public key of the zone * @param expire when does the corresponding block in the DHT expire (until * when should we never do a DHT lookup for the same name again)?; * GNUNET_TIME_UNIT_ZERO_ABS if there are no records of any type in the namestore, * or the expiration time of the block in the namestore (even if there are zero * records matching the desired record type) * @param name name that is being mapped (at most 255 characters long) * @param rd_count number of entries in 'rd' array * @param rd array of records with data to store * @param signature signature of the record block, NULL if signature is unavailable (i.e. * because the user queried for a particular record type only) */ static void lookup_result_processor (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *name, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { struct Request *request = cls; struct GNUNET_CRYPTO_ShortHashCode pub; request->qe = NULL; GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_short_hash_from_string2 (request->public_key, strlen (request->public_key), &pub)); if (0 != rd_count) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Found %u existing records for domain `%s'\n"), rd_count, request->domain_name); request->phase = RP_FAIL; run_httpd_now (); return; } request->qe = GNUNET_NAMESTORE_zone_to_name (ns, &fcfsd_zone, &pub, &zone_to_name_cb, request); } /** * Main MHD callback for handling requests. * * @param cls unused * @param connection MHD connection handle * @param url the requested url * @param method the HTTP method used ("GET", "PUT", etc.) * @param version the HTTP version string (i.e. "HTTP/1.1") * @param upload_data the data being uploaded (excluding HEADERS, * for a POST that fits into memory and that is encoded * with a supported encoding, the POST data will NOT be * given in upload_data and is instead available as * part of MHD_get_connection_values; very large POST * data *will* be made available incrementally in * upload_data) * @param upload_data_size set initially to the size of the * upload_data provided; the method must update this * value to the number of bytes NOT processed; * @param ptr pointer to location where we store the 'struct Request' * @return MHD_YES if the connection was handled successfully, * MHD_NO if the socket must be closed due to a serious * error while handling the request */ static int create_response (void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **ptr) { struct MHD_Response *response; struct Request *request; int ret; struct GNUNET_CRYPTO_ShortHashCode pub; if ( (0 == strcmp (method, MHD_HTTP_METHOD_GET)) || (0 == strcmp (method, MHD_HTTP_METHOD_HEAD)) ) { ret = serve_main_page (connection); if (ret != MHD_YES) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to create page for `%s'\n"), url); return ret; } if (0 == strcmp (method, MHD_HTTP_METHOD_POST)) { request = *ptr; if (NULL == request) { request = GNUNET_malloc (sizeof (struct Request)); *ptr = request; request->pp = MHD_create_post_processor (connection, 1024, &post_iterator, request); if (NULL == request->pp) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to setup post processor for `%s'\n"), url); return MHD_NO; /* internal error */ } return MHD_YES; } if (NULL != request->pp) { /* evaluate POST data */ MHD_post_process (request->pp, upload_data, *upload_data_size); if (0 != *upload_data_size) { *upload_data_size = 0; return MHD_YES; } /* done with POST data, serve response */ MHD_destroy_post_processor (request->pp); request->pp = NULL; } if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string2 (request->public_key, strlen (request->public_key), &pub)) { /* parse error */ return fill_s_reply ("Failed to parse given public key", request, connection); } switch (request->phase) { case RP_START: request->phase = RP_LOOKUP; request->qe = GNUNET_NAMESTORE_lookup_record (ns, &fcfsd_zone, request->domain_name, GNUNET_NAMESTORE_TYPE_PKEY, &lookup_result_processor, request); break; case RP_LOOKUP: break; case RP_PUT: break; case RP_FAIL: return fill_s_reply ("Request failed, sorry.", request, connection); case RP_SUCCESS: return fill_s_reply ("Success.", request, connection); default: GNUNET_break (0); return MHD_NO; } return MHD_YES; /* will have a reply later... */ } /* unsupported HTTP method */ response = MHD_create_response_from_buffer (strlen (METHOD_ERROR), (void *) METHOD_ERROR, MHD_RESPMEM_PERSISTENT); ret = MHD_queue_response (connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE, response); MHD_destroy_response (response); return ret; } /** * Callback called upon completion of a request. * Decrements session reference counter. * * @param cls not used * @param connection connection that completed * @param con_cls session handle * @param toe status code */ static void request_completed_callback (void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_RequestTerminationCode toe) { struct Request *request = *con_cls; if (NULL == request) return; if (NULL != request->pp) MHD_destroy_post_processor (request->pp); if (NULL != request->qe) GNUNET_NAMESTORE_cancel (request->qe); GNUNET_free (request); } /** * Schedule tasks to run MHD server. */ static void run_httpd () { fd_set rs; fd_set ws; fd_set es; struct GNUNET_NETWORK_FDSet *wrs; struct GNUNET_NETWORK_FDSet *wws; struct GNUNET_NETWORK_FDSet *wes; int max; int haveto; unsigned MHD_LONG_LONG timeout; struct GNUNET_TIME_Relative tv; FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es); wrs = GNUNET_NETWORK_fdset_create (); wes = GNUNET_NETWORK_fdset_create (); wws = GNUNET_NETWORK_fdset_create (); max = -1; GNUNET_assert (MHD_YES == MHD_get_fdset (httpd, &rs, &ws, &es, &max)); haveto = MHD_get_timeout (httpd, &timeout); if (haveto == MHD_YES) tv.rel_value = (uint64_t) timeout; else tv = GNUNET_TIME_UNIT_FOREVER_REL; GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1); httpd_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, tv, wrs, wws, &do_httpd, NULL); GNUNET_NETWORK_fdset_destroy (wrs); GNUNET_NETWORK_fdset_destroy (wws); GNUNET_NETWORK_fdset_destroy (wes); } /** * Task run whenever HTTP server operations are pending. * * @param cls unused * @param tc scheduler context */ static void do_httpd (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { httpd_task = GNUNET_SCHEDULER_NO_TASK; MHD_run (httpd); run_httpd (); } /** * Task run on shutdown. Cleans up everything. * * @param cls unused * @param tc scheduler context */ static void do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (GNUNET_SCHEDULER_NO_TASK != httpd_task) { GNUNET_SCHEDULER_cancel (httpd_task); httpd_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != ns) { GNUNET_NAMESTORE_disconnect (ns, GNUNET_NO); ns = NULL; } if (NULL != httpd) { MHD_stop_daemon (httpd); httpd = NULL; } if (NULL != fcfs_zone_pkey) { GNUNET_CRYPTO_rsa_key_free (fcfs_zone_pkey); fcfs_zone_pkey = NULL; } } /** * Main function that will be run. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param cfg configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { char *keyfile; unsigned long long port; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "fcfsd", "HTTPPORT", &port)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Option `%s' not specified in configuration section `%s'\n"), "HTTPPORT", "fcfsd"); return; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "fcfsd", "ZONEKEY", &keyfile)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Option `%s' not specified in configuration section `%s'\n"), "ZONEKEY", "fcfsd"); return; } fcfs_zone_pkey = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); GNUNET_free (keyfile); if (NULL == fcfs_zone_pkey) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to read or create private zone key\n")); return; } GNUNET_CRYPTO_rsa_key_get_public (fcfs_zone_pkey, &pub); GNUNET_CRYPTO_short_hash (&pub, sizeof (pub), &fcfsd_zone); ns = GNUNET_NAMESTORE_connect (cfg); if (NULL == ns) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to connect to namestore\n")); return; } httpd = MHD_start_daemon (MHD_USE_DEBUG, (uint16_t) port, NULL, NULL, &create_response, NULL, MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 128, MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1, MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16, MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (4 * 1024), MHD_OPTION_NOTIFY_COMPLETED, &request_completed_callback, NULL, MHD_OPTION_END); if (NULL == httpd) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to start HTTP server\n")); GNUNET_NAMESTORE_disconnect (ns, GNUNET_NO); ns = NULL; return; } run_httpd (); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &do_shutdown, NULL); } /** * The main function for the fcfs daemon. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; int ret; GNUNET_log_setup ("fcfsd", "WARNING", NULL); ret = (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "fcfsd", _("GNUnet GNS first come first serve registration service"), options, &run, NULL)) ? 0 : 1; return ret; } /* end of gnunet-gns-fcfsd.c */ gnunet-0.9.3/src/gns/gnunet-gns.c0000644000175000017500000001515011760502551013557 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file gnunet-gns.c * @brief command line tool to access distributed GNS * @author Christian Grothoff * * TODO: * - everything */ #include "platform.h" #include #include #include #include /** * Handle to GNS service. */ static struct GNUNET_GNS_Handle *gns; /** * GNS name to shorten. (-s option) */ static char *shorten_name; /** * GNS name to lookup. (-u option) */ static char *lookup_name; /** * record type to look up (-t option) */ static char *lookup_type; /** * name to look up authority for (-a option) */ static char *auth_name; /** * raw output */ static int raw = 0; static enum GNUNET_GNS_RecordType rtype; /** * Task run on shutdown. Cleans up everything. * * @param cls unused * @param tc scheduler context */ static void do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (NULL != gns) { GNUNET_GNS_disconnect (gns); gns = NULL; } } static void process_shorten_result(void* cls, const char* nshort) { if (raw) printf("%s", nshort); else printf("%s shortened to %s\n", (char*) cls, nshort); GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); } static void process_lookup_result(void* cls, uint32_t rd_count, const struct GNUNET_NAMESTORE_RecordData *rd) { int i; char* name = (char*) cls; const char* typename; char* string_val; if (!raw) { if (rd_count == 0) printf("No results.\n"); else printf("%s:\n", name); } for (i=0; iclient); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Trying to connect to GNS...\n"); h->client = GNUNET_CLIENT_connect ("gns", h->cfg); GNUNET_assert (NULL != h->client); } /** * Reconnect to GNS * * @param cls the handle * @param tc task context */ static void reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_GNS_Handle *h = cls; h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; reconnect (h); } /** * Disconnect from service and then reconnect. * * @param h our handle */ static void force_reconnect (struct GNUNET_GNS_Handle *h) { h->reconnect = GNUNET_NO; GNUNET_CLIENT_disconnect (h->client); h->client = NULL; h->reconnect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task, h); } /** * Transmit the next pending message, called by notify_transmit_ready */ static size_t transmit_pending (void *cls, size_t size, void *buf); /** * Handler for messages received from the GNS service * * @param cls the 'struct GNUNET_GNS_Handle' * @param msg the incoming message */ static void process_message (void *cls, const struct GNUNET_MessageHeader *msg); /** * Try to send messages from list of messages to send */ static void process_pending_messages (struct GNUNET_GNS_Handle *handle) { struct PendingMessage *p; if (handle->client == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "process_pending_messages called, but client is null\n"); return; } if (handle->th != NULL) return; if (NULL == (p = handle->pending_head)) return; GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Trying to transmit %d bytes...\n", p->size); handle->th = GNUNET_CLIENT_notify_transmit_ready (handle->client, p->size, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_NO, &transmit_pending, handle); if (NULL != handle->th) return; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "notify_transmit_ready returned NULL!\n"); } /** * Transmit the next pending message, called by notify_transmit_ready */ static size_t transmit_pending (void *cls, size_t size, void *buf) { struct GNUNET_GNS_Handle *handle = cls; struct PendingMessage *p; size_t tsize; char *cbuf; handle->th = NULL; if ((size == 0) || (buf == NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission to GNS service failed!\n"); force_reconnect(handle); return 0; } tsize = 0; cbuf = buf; if (NULL == (p = handle->pending_head)) return 0; while ((NULL != (p = handle->pending_head)) && (p->size <= size)) { memcpy (&cbuf[tsize], &p[1], p->size); tsize += p->size; size -= p->size; GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail, p); if (GNUNET_YES != handle->in_receive) { GNUNET_CLIENT_receive (handle->client, &process_message, handle, GNUNET_TIME_UNIT_FOREVER_REL); handle->in_receive = GNUNET_YES; } GNUNET_free(p); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending %d bytes\n", tsize); process_pending_messages(handle); return tsize; } /** * Process a given reply that might match the given * request. * * @param qe a queue entry * @param msg the shorten msg received */ static void process_shorten_reply (struct GNUNET_GNS_QueueEntry *qe, const struct GNUNET_GNS_ClientShortenResultMessage *msg) { struct GNUNET_GNS_Handle *h = qe->gns_handle; const char *short_name; GNUNET_CONTAINER_DLL_remove(h->shorten_head, h->shorten_tail, qe); short_name = (char*)(&msg[1]); if (ntohs (((struct GNUNET_MessageHeader*)msg)->size) < sizeof (struct GNUNET_GNS_ClientShortenResultMessage)) { GNUNET_break (0); force_reconnect (h); GNUNET_free(qe); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received shortened reply `%s' from GNS service\n", short_name); GNUNET_CLIENT_receive (h->client, &process_message, h, GNUNET_TIME_UNIT_FOREVER_REL); qe->shorten_proc(qe->proc_cls, short_name); GNUNET_free(qe); } /** * Process a given reply that might match the given * request. * * @param qe the handle to the request * @param msg the message to process */ static void process_get_auth_reply (struct GNUNET_GNS_QueueEntry *qe, const struct GNUNET_GNS_ClientGetAuthResultMessage *msg) { struct GNUNET_GNS_Handle *h = qe->gns_handle; const char *auth_name; GNUNET_CONTAINER_DLL_remove(h->get_auth_head, h->get_auth_tail, qe); auth_name = (char*)(&msg[1]); if (ntohs (((struct GNUNET_MessageHeader*)msg)->size) < sizeof (struct GNUNET_GNS_ClientGetAuthResultMessage)) { GNUNET_free(qe); GNUNET_break (0); force_reconnect (h); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received GET_AUTH reply `%s' from GNS service\n", auth_name); GNUNET_CLIENT_receive (h->client, &process_message, h, GNUNET_TIME_UNIT_FOREVER_REL); qe->auth_proc(qe->proc_cls, auth_name); GNUNET_free(qe); } /** * Process a given reply to the lookup request * * @param qe a queue entry * @param msg the lookup message received */ static void process_lookup_reply (struct GNUNET_GNS_QueueEntry *qe, const struct GNUNET_GNS_ClientLookupResultMessage *msg) { struct GNUNET_GNS_Handle *h = qe->gns_handle; int rd_count = ntohl(msg->rd_count); size_t len = ntohs (((struct GNUNET_MessageHeader*)msg)->size); struct GNUNET_NAMESTORE_RecordData rd[rd_count]; GNUNET_CONTAINER_DLL_remove(h->lookup_head, h->lookup_tail, qe); if (len < sizeof (struct GNUNET_GNS_ClientLookupResultMessage)) { GNUNET_free(qe); GNUNET_break (0); force_reconnect (h); return; } len -= sizeof(struct GNUNET_GNS_ClientLookupResultMessage); GNUNET_CLIENT_receive (h->client, &process_message, h, GNUNET_TIME_UNIT_FOREVER_REL); if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (len, (char*)&msg[1], rd_count, rd)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to serialize lookup reply from GNS service!\n"); qe->lookup_proc(qe->proc_cls, 0, NULL); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received lookup reply from GNS service (count=%d)\n", ntohl(msg->rd_count)); qe->lookup_proc(qe->proc_cls, rd_count, rd); } GNUNET_free(qe); } /** * Handler for messages received from the GNS service * * @param cls the 'struct GNUNET_GNS_Handle' * @param msg the incoming message */ static void process_message (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_GNS_Handle *handle = cls; struct GNUNET_GNS_QueueEntry *qe; const struct GNUNET_GNS_ClientLookupResultMessage *lookup_msg; const struct GNUNET_GNS_ClientShortenResultMessage *shorten_msg; const struct GNUNET_GNS_ClientGetAuthResultMessage *get_auth_msg; uint16_t type; uint32_t r_id; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got message\n"); if (msg == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error receiving data from GNS service, reconnecting\n"); force_reconnect (handle); return; } type = ntohs (msg->type); if (type == GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got lookup msg\n"); lookup_msg = (const struct GNUNET_GNS_ClientLookupResultMessage *) msg; r_id = ntohl (lookup_msg->id); if (r_id > handle->r_id) { /** no request found */ GNUNET_break_op (0); GNUNET_CLIENT_receive (handle->client, &process_message, handle, GNUNET_TIME_UNIT_FOREVER_REL); return; } for (qe = handle->lookup_head; qe != NULL; qe = qe->next) { if (qe->r_id == r_id) break; } if (qe) process_lookup_reply(qe, lookup_msg); return; } else if (type == GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got SHORTEN_RESULT msg\n"); shorten_msg = (struct GNUNET_GNS_ClientShortenResultMessage *) msg; r_id = ntohl (shorten_msg->id); if (r_id > handle->r_id) { /** no request found */ GNUNET_break_op (0); GNUNET_CLIENT_receive (handle->client, &process_message, handle, GNUNET_TIME_UNIT_FOREVER_REL); return; } for (qe = handle->shorten_head; qe != NULL; qe = qe->next) { if (qe->r_id == r_id) break; } if (qe) process_shorten_reply(qe, shorten_msg); return; } else if (type == GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got GET_AUTH_RESULT msg\n"); get_auth_msg = (struct GNUNET_GNS_ClientGetAuthResultMessage *) msg; r_id = ntohl (get_auth_msg->id); if (r_id > handle->r_id) { /** no request found */ GNUNET_break_op (0); GNUNET_CLIENT_receive (handle->client, &process_message, handle, GNUNET_TIME_UNIT_FOREVER_REL); return; } for (qe = handle->get_auth_head; qe != NULL; qe = qe->next) { if (qe->r_id == r_id) break; } if (qe) process_get_auth_reply(qe, get_auth_msg); return; } if (GNUNET_YES == handle->reconnect) force_reconnect (handle); } /** * Initialize the connection with the GNS service. * * @param cfg configuration to use * @return handle to the GNS service, or NULL on error */ struct GNUNET_GNS_Handle * GNUNET_GNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_GNS_Handle *handle; handle = GNUNET_malloc (sizeof (struct GNUNET_GNS_Handle)); handle->reconnect = GNUNET_NO; handle->cfg = cfg; reconnect (handle); //handle->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect_task, handle); handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; handle->r_id = 0; handle->in_receive = GNUNET_NO; return handle; } /** * Shutdown connection with the GNS service. * * @param handle handle of the GNS connection to stop */ void GNUNET_GNS_disconnect (struct GNUNET_GNS_Handle *handle) { GNUNET_CLIENT_disconnect (handle->client); if (GNUNET_SCHEDULER_NO_TASK != handle->reconnect_task) { GNUNET_SCHEDULER_cancel (handle->reconnect_task); handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_free(handle); /* disco from GNS */ } /* * Helper function to generate request ids * * @param h handle * @return a new id */ static uint32_t get_request_id (struct GNUNET_GNS_Handle *h) { uint32_t r_id = h->r_id; h->r_id++; return r_id; } /** * Perform an asynchronous Lookup operation on the GNS. * * @param handle handle to the GNS service * @param name the name to look up * @param zone the zone to start the resolution in * @param type the record type to look up * @param proc processor to call on result * @param proc_cls closure for processor * @return handle to the get */ struct GNUNET_GNS_QueueEntry * GNUNET_GNS_lookup_zone (struct GNUNET_GNS_Handle *handle, const char * name, struct GNUNET_CRYPTO_ShortHashCode *zone, enum GNUNET_GNS_RecordType type, GNUNET_GNS_LookupResultProcessor proc, void *proc_cls) { /* IPC to shorten gns names, return shorten_handle */ struct GNUNET_GNS_ClientLookupMessage *lookup_msg; struct GNUNET_GNS_QueueEntry *qe; size_t msize; struct PendingMessage *pending; if (NULL == name) { return NULL; } msize = sizeof (struct GNUNET_GNS_ClientLookupMessage) + strlen(name) + 1; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to lookup %s in GNS\n", name); qe = GNUNET_malloc(sizeof (struct GNUNET_GNS_QueueEntry)); qe->gns_handle = handle; qe->lookup_proc = proc; qe->proc_cls = proc_cls; qe->r_id = get_request_id(handle); GNUNET_CONTAINER_DLL_insert_tail(handle->lookup_head, handle->lookup_tail, qe); pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize); memset(pending, 0, (sizeof (struct PendingMessage) + msize)); pending->size = msize; lookup_msg = (struct GNUNET_GNS_ClientLookupMessage *) &pending[1]; lookup_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_LOOKUP); lookup_msg->header.size = htons (msize); lookup_msg->id = htonl(qe->r_id); if (NULL != zone) { lookup_msg->use_default_zone = htonl(0); memcpy(&lookup_msg->zone, zone, sizeof(struct GNUNET_CRYPTO_ShortHashCode)); } else { lookup_msg->use_default_zone = htonl(1); memset(&lookup_msg->zone, 0, sizeof(struct GNUNET_CRYPTO_ShortHashCode)); } lookup_msg->type = htonl(type); memcpy(&lookup_msg[1], name, strlen(name)); GNUNET_CONTAINER_DLL_insert_tail (handle->pending_head, handle->pending_tail, pending); process_pending_messages (handle); return qe; } /** * Perform an asynchronous Lookup operation on the GNS. * * @param handle handle to the GNS service * @param name the name to look up * @param type the record type to look up * @param proc processor to call on result * @param proc_cls closure for processor * @return handle to the get */ struct GNUNET_GNS_QueueEntry * GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle, const char * name, enum GNUNET_GNS_RecordType type, GNUNET_GNS_LookupResultProcessor proc, void *proc_cls) { return GNUNET_GNS_lookup_zone (handle, name, NULL, type, proc, proc_cls); } /** * Perform a name shortening operation on the GNS. * * @param handle handle to the GNS service * @param name the name to look up * @param zone the zone to start the resolution in * @param proc function to call on result * @param proc_cls closure for processor * @return handle to the operation */ struct GNUNET_GNS_QueueEntry * GNUNET_GNS_shorten_zone (struct GNUNET_GNS_Handle *handle, const char * name, struct GNUNET_CRYPTO_ShortHashCode *zone, GNUNET_GNS_ShortenResultProcessor proc, void *proc_cls) { /* IPC to shorten gns names, return shorten_handle */ struct GNUNET_GNS_ClientShortenMessage *shorten_msg; struct GNUNET_GNS_QueueEntry *qe; size_t msize; struct PendingMessage *pending; if (NULL == name) { return NULL; } msize = sizeof (struct GNUNET_GNS_ClientShortenMessage) + strlen(name) + 1; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to shorten %s in GNS\n", name); qe = GNUNET_malloc(sizeof (struct GNUNET_GNS_QueueEntry)); qe->gns_handle = handle; qe->shorten_proc = proc; qe->proc_cls = proc_cls; qe->r_id = get_request_id(handle); GNUNET_CONTAINER_DLL_insert_tail(handle->shorten_head, handle->shorten_tail, qe); pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize); memset(pending, 0, (sizeof (struct PendingMessage) + msize)); pending->size = msize; shorten_msg = (struct GNUNET_GNS_ClientShortenMessage *) &pending[1]; shorten_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_SHORTEN); shorten_msg->header.size = htons (msize); shorten_msg->id = htonl(qe->r_id); if (NULL != zone) { shorten_msg->use_default_zone = htonl(0); memcpy(&shorten_msg->zone, zone, sizeof(struct GNUNET_CRYPTO_ShortHashCode)); } else { shorten_msg->use_default_zone = htonl(1); memset(&shorten_msg->zone, 0, sizeof(struct GNUNET_CRYPTO_ShortHashCode)); } memcpy(&shorten_msg[1], name, strlen(name)); GNUNET_CONTAINER_DLL_insert_tail (handle->pending_head, handle->pending_tail, pending); process_pending_messages (handle); return qe; } /** * Perform a name shortening operation on the GNS. * * @param handle handle to the GNS service * @param name the name to look up * @param proc function to call on result * @param proc_cls closure for processor * @return handle to the operation */ struct GNUNET_GNS_QueueEntry * GNUNET_GNS_shorten (struct GNUNET_GNS_Handle *handle, const char * name, GNUNET_GNS_ShortenResultProcessor proc, void *proc_cls) { return GNUNET_GNS_shorten_zone (handle, name, NULL, proc, proc_cls); } /** * Perform an authority lookup for a given name. * * @param handle handle to the GNS service * @param name the name to look up authority for * @param proc function to call on result * @param proc_cls closure for processor * @return handle to the operation */ struct GNUNET_GNS_QueueEntry * GNUNET_GNS_get_authority (struct GNUNET_GNS_Handle *handle, const char * name, GNUNET_GNS_GetAuthResultProcessor proc, void *proc_cls) { struct GNUNET_GNS_ClientGetAuthMessage *get_auth_msg; struct GNUNET_GNS_QueueEntry *qe; size_t msize; struct PendingMessage *pending; if (NULL == name) { return NULL; } msize = sizeof (struct GNUNET_GNS_ClientGetAuthMessage) + strlen(name) + 1; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to look up authority for %s in GNS\n", name); qe = GNUNET_malloc(sizeof (struct GNUNET_GNS_QueueEntry)); qe->gns_handle = handle; qe->auth_proc = proc; qe->proc_cls = proc_cls; qe->r_id = get_request_id(handle); GNUNET_CONTAINER_DLL_insert_tail(handle->get_auth_head, handle->get_auth_tail, qe); pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize); memset(pending, 0, (sizeof (struct PendingMessage) + msize)); pending->size = msize; get_auth_msg = (struct GNUNET_GNS_ClientGetAuthMessage *) &pending[1]; get_auth_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_GET_AUTH); get_auth_msg->header.size = htons (msize); get_auth_msg->id = htonl(qe->r_id); memcpy(&get_auth_msg[1], name, strlen(name)); GNUNET_CONTAINER_DLL_insert_tail (handle->pending_head, handle->pending_tail, pending); process_pending_messages (handle); return qe; } /* end of gns_api.c */ gnunet-0.9.3/src/gns/test_gns_dht_default.conf0000644000175000017500000000352311741577433016401 00000000000000@INLINE@ test_gns_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-gns-dht/ DEFAULTCONFIG = test_gns_dht_default.conf [transport-tcp] PORT = 22568 [dht] UNIXPATH = /tmp/gnunet-service-dht.sock DEBUG = NO AUTOSTART = YES ACCEPT_FROM6 = ::1; ACCEPT_FROM = 127.0.0.1; HOSTNAME = localhost PORT = 2102 BINARY = gnunet-service-dht [block] plugins = dht test gns [dhtcache] QUOTA = 1 MB DATABASE = sqlite [arm] PORT = 22566 DEFAULTSERVICES = core namestore dht gns UNIXPATH = /tmp/gnunet-default-service-arm.sock [statistics] PORT = 22567 UNIXPATH = /tmp/gnunet-default-service-statistics.sock [resolver] PORT = 22564 UNIXPATH = /tmp/gnunet-default-service-resolver.sock [peerinfo] PORT = 22569 UNIXPATH = /tmp/gnunet-default-service-peerinfo.sock [transport] PORT = 22565 UNIXPATH = /tmp/gnunet-default-service-transport.sock [core] PORT = 22570 UNIXPATH = /tmp/gnunet-default-service-core.sock [ats] PORT = 22571 UNIXPATH = /tmp/gnunet-default-service-ats.sock [dns] UNIXPATH = /tmp/gnunet-default-service-dns.sock PORT = 22369 AUTOSTART = YES DNS_EXIT = 8.8.8.8 [gns] PORT = 22370 #PREFIX = valgrind -v --leak-check=full --track-origins=yes. AUTOSTART = YES BINARY = gnunet-service-gns ZONEKEY = $SERVICEHOME/zonekey.zkey HIJACK_DNS = NO UNIXPATH = /tmp/gnunet-service-gns-default.sock HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG AUTO_IMPORT_PKEY = NO MAX_PARALLEL_BACKGROUND_QUERIES = 10 DEFAULT_LOOKUP_TIMEOUT = 60 RECORD_PUT_INTERVAL = 1 ZONE_PUT_INTERVAL = 5 [namestore] PORT = 22371 AUTOSTART = YES UNIXPATH = /tmp/gnunet-service-namestore-default.sock UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-namestore ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DATABASE = sqlite ZONEFILE_DIRECTORY = $SERVICEHOME [namestore-sqlite] FILENAME = $SERVICEHOME/sqlite-default.db gnunet-0.9.3/src/gns/plugin_block_gns.c0000644000175000017500000002141211760516130015005 00000000000000/* This file is part of GNUnet (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file gns/plugin_block_gns.c * @brief blocks used for GNS records * @author Martin Schanzenbach */ #include "platform.h" #include "gnunet_block_plugin.h" #include "gnunet_namestore_service.h" #include "block_gns.h" #include "gnunet_signatures.h" /** * Number of bits we set per entry in the bloomfilter. * Do not change! -from fs */ #define BLOOMFILTER_K 16 /** * Function called to validate a reply or a request. For * request evaluation, simply pass "NULL" for the reply_block. * Note that it is assumed that the reply has already been * matched to the key (and signatures checked) as it would * be done with the "get_key" function. * * @param cls closure * @param type block type * @param query original query (hash) * @param bf pointer to bloom filter associated with query; possibly updated (!) * @param bf_mutator mutation value for bf * @param xquery extrended query data (can be NULL, depending on type) * @param xquery_size number of bytes in xquery * @param reply_block response to validate * @param reply_block_size number of bytes in reply block * @return characterization of result */ static enum GNUNET_BLOCK_EvaluationResult block_plugin_gns_evaluate (void *cls, enum GNUNET_BLOCK_Type type, const GNUNET_HashCode * query, struct GNUNET_CONTAINER_BloomFilter **bf, int32_t bf_mutator, const void *xquery, size_t xquery_size, const void *reply_block, size_t reply_block_size) { char* name; GNUNET_HashCode pkey_hash_double; GNUNET_HashCode query_key; GNUNET_HashCode name_hash_double; GNUNET_HashCode mhash; GNUNET_HashCode chash; struct GNUNET_CRYPTO_ShortHashCode pkey_hash; struct GNUNET_CRYPTO_ShortHashCode name_hash; struct GNSNameRecordBlock *nrb; uint32_t rd_count; char* rd_data = NULL; int rd_len; uint32_t record_xquery; unsigned int record_match; //GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "RB SIZE %d\n", reply_block_size); if (type != GNUNET_BLOCK_TYPE_GNS_NAMERECORD) return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; if (reply_block == NULL) { /** * check if request is valid * FIXME we could check for the record types here **/ if (xquery_size < sizeof(uint32_t)) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; } return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; } /* this is a reply */ nrb = (struct GNSNameRecordBlock *)reply_block; name = (char*)&nrb[1]; GNUNET_CRYPTO_short_hash(&nrb->public_key, sizeof(nrb->public_key), &pkey_hash); GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash); GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double); GNUNET_CRYPTO_short_hash_double(&pkey_hash, &pkey_hash_double); GNUNET_CRYPTO_hash_xor(&pkey_hash_double, &name_hash_double, &query_key); struct GNUNET_CRYPTO_HashAsciiEncoded xor_exp; struct GNUNET_CRYPTO_HashAsciiEncoded xor_got; GNUNET_CRYPTO_hash_to_enc (&query_key, &xor_exp); GNUNET_CRYPTO_hash_to_enc (query, &xor_got); //GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, // "BLOCK_TEST for %s got %s expected %s\n", // name, (char*) &xor_got, (char*) &xor_exp); /* Check query key against public key */ if (0 != GNUNET_CRYPTO_hash_cmp(query, &query_key)) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } record_match = 0; rd_count = ntohl(nrb->rd_count); rd_data = (char*)&nrb[1]; rd_data += strlen(name) + 1; rd_len = reply_block_size - (strlen(name) + 1 + sizeof(struct GNSNameRecordBlock)); { struct GNUNET_NAMESTORE_RecordData rd[rd_count]; unsigned int i; struct GNUNET_TIME_Absolute exp = GNUNET_TIME_UNIT_FOREVER_ABS; if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_len, rd_data, rd_count, rd)) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Data invalid (%d bytes, %d records)\n", rd_len, rd_count); GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } if (xquery_size < sizeof(uint32_t)) record_xquery = 0; else record_xquery = ntohl(*((uint32_t*)xquery)); for (i=0; ipublic_key, exp, name, rd_count, rd, &nrb->signature)) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Signature invalid for name %s\n"); GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } } if (NULL != bf) { GNUNET_CRYPTO_hash(reply_block, reply_block_size, &chash); GNUNET_BLOCK_mingle_hash(&chash, bf_mutator, &mhash); if (NULL != *bf) { if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test(*bf, &mhash)) return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE; } else { *bf = GNUNET_CONTAINER_bloomfilter_init(NULL, 8, BLOOMFILTER_K); } GNUNET_CONTAINER_bloomfilter_add(*bf, &mhash); } return GNUNET_BLOCK_EVALUATION_OK_MORE; } /** * Function called to obtain the key for a block. * * @param cls closure * @param type block type * @param block block to get the key for * @param block_size number of bytes in block * @param key set to the key (query) for the given block * @return GNUNET_OK on success, GNUNET_SYSERR if type not supported * (or if extracting a key from a block of this type does not work) */ static int block_plugin_gns_get_key (void *cls, enum GNUNET_BLOCK_Type type, const void *block, size_t block_size, GNUNET_HashCode * key) { if (type != GNUNET_BLOCK_TYPE_GNS_NAMERECORD) return GNUNET_SYSERR; struct GNUNET_CRYPTO_ShortHashCode name_hash; struct GNUNET_CRYPTO_ShortHashCode pkey_hash; GNUNET_HashCode name_hash_double; GNUNET_HashCode pkey_hash_double; struct GNSNameRecordBlock *nrb = (struct GNSNameRecordBlock *)block; GNUNET_CRYPTO_short_hash(&nrb[1], strlen((char*)&nrb[1]), &name_hash); GNUNET_CRYPTO_short_hash(&nrb->public_key, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &pkey_hash); GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double); GNUNET_CRYPTO_short_hash_double(&pkey_hash, &pkey_hash_double); GNUNET_CRYPTO_hash_xor(&name_hash_double, &pkey_hash_double, key); return GNUNET_OK; } /** * Entry point for the plugin. */ void * libgnunet_plugin_block_gns_init (void *cls) { static enum GNUNET_BLOCK_Type types[] = { GNUNET_BLOCK_TYPE_GNS_NAMERECORD, GNUNET_BLOCK_TYPE_ANY /* end of list */ }; struct GNUNET_BLOCK_PluginFunctions *api; api = GNUNET_malloc (sizeof (struct GNUNET_BLOCK_PluginFunctions)); api->evaluate = &block_plugin_gns_evaluate; api->get_key = &block_plugin_gns_get_key; api->types = types; return api; } /** * Exit point from the plugin. */ void * libgnunet_plugin_block_gns_done (void *cls) { struct GNUNET_TRANSPORT_PluginFunctions *api = cls; GNUNET_free (api); return NULL; } /* end of plugin_block_gns.c */ gnunet-0.9.3/src/gns/test_gns_simple_lookup.c0000644000175000017500000002073111760520073016262 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file gns/test_gns_simple_lookup.c * @brief base testcase for testing a local GNS record lookup * */ #include "platform.h" #include "gnunet_testing_lib.h" #include "gnunet_core_service.h" #include "block_dns.h" #include "gnunet_signatures.h" #include "gnunet_namestore_service.h" #include "gnunet_dnsparser_lib.h" #include "gnunet_gns_service.h" /* DEFINES */ #define VERBOSE GNUNET_YES /* Timeout for entire testcase */ #define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 20) /* If number of peers not in config file, use this number */ #define DEFAULT_NUM_PEERS 2 /* test records to resolve */ #define TEST_DOMAIN "www.gnunet" #define TEST_IP "127.0.0.1" #define TEST_RECORD_NAME "www" /* Globals */ /** * Directory to store temp data in, defined in config file */ static char *test_directory; static struct GNUNET_TESTING_PeerGroup *pg; /* Task handle to use to schedule test failure */ GNUNET_SCHEDULER_TaskIdentifier die_task; /* Global return value (0 for success, anything else for failure) */ static int ok; static struct GNUNET_NAMESTORE_Handle *namestore_handle; static struct GNUNET_GNS_Handle *gns_handle; const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Check whether peers successfully shut down. */ void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error on shutdown! ret=%d\n", ok); if (ok == 0) ok = 2; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "done(ret=%d)!\n", ok); } static void on_lookup_result(void *cls, uint32_t rd_count, const struct GNUNET_NAMESTORE_RecordData *rd) { struct in_addr a; int i; char* addr; if (rd_count == 0) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Lookup failed, rp_filtering?\n"); ok = 2; } else { ok = 1; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "name: %s\n", (char*)cls); for (i=0; isignature = *sig; nrb->public_key = alice_pkey; nrb->rd_count = htonl(1); memset(&nrb[1], 0, strlen("+") + 1); strcpy((char*)&nrb[1], "+"); nrb_data = (char*)&nrb[1]; nrb_data += strlen("+") + 1; if (-1 == GNUNET_NAMESTORE_records_serialize (1, &rd, rd_payload_length, nrb_data)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Record serialization failed!\n"); ok = 3; GNUNET_DHT_disconnect(dht_handle); GNUNET_CRYPTO_rsa_key_free(our_key); GNUNET_CRYPTO_rsa_key_free(bob_key); GNUNET_CRYPTO_rsa_key_free(alice_key); GNUNET_free(sig); GNUNET_free (nrb); return; } GNUNET_CRYPTO_short_hash("+", strlen("+"), &name_hash); GNUNET_CRYPTO_short_hash(&alice_pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &zone_hash); GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double); GNUNET_CRYPTO_short_hash_double(&zone_hash, &zone_hash_double); GNUNET_CRYPTO_hash_xor(&zone_hash_double, &name_hash_double, &xor_hash); rd_payload_length += sizeof(struct GNSNameRecordBlock) + strlen("+") + 1; GNUNET_DHT_put (dht_handle, &xor_hash, 0, GNUNET_DHT_RO_NONE, GNUNET_BLOCK_TYPE_GNS_NAMERECORD, rd_payload_length, (char*)nrb, rd.expiration, DHT_OPERATION_TIMEOUT, &commence_testing, NULL); GNUNET_free(sig); GNUNET_free (nrb); } static void put_www_dht(void *cls, int success) { struct GNSNameRecordBlock *nrb; struct GNUNET_CRYPTO_ShortHashCode name_hash; struct GNUNET_CRYPTO_ShortHashCode zone_hash; GNUNET_HashCode xor_hash; GNUNET_HashCode name_hash_double; GNUNET_HashCode zone_hash_double; uint32_t rd_payload_length; char* nrb_data = NULL; struct GNUNET_CRYPTO_RsaSignature *sig; struct GNUNET_NAMESTORE_RecordData rd; char* ip = TEST_IP; struct in_addr *web = GNUNET_malloc(sizeof(struct in_addr)); rd.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; GNUNET_assert(1 == inet_pton (AF_INET, ip, web)); rd.data_size = sizeof(struct in_addr); rd.data = web; rd.record_type = GNUNET_DNSPARSER_TYPE_A; sig = GNUNET_NAMESTORE_create_signature(alice_key, GNUNET_TIME_UNIT_FOREVER_ABS, TEST_RECORD_NAME, &rd, 1); rd_payload_length = GNUNET_NAMESTORE_records_get_size (1, &rd); nrb = GNUNET_malloc(rd_payload_length + strlen(TEST_RECORD_NAME) + 1 + sizeof(struct GNSNameRecordBlock)); nrb->signature = *sig; nrb->public_key = alice_pkey; nrb->rd_count = htonl(1); memset(&nrb[1], 0, strlen(TEST_RECORD_NAME) + 1); strcpy((char*)&nrb[1], TEST_RECORD_NAME); nrb_data = (char*)&nrb[1]; nrb_data += strlen(TEST_RECORD_NAME) + 1; if (-1 == GNUNET_NAMESTORE_records_serialize (1, &rd, rd_payload_length, nrb_data)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Record serialization failed!\n"); ok = 3; GNUNET_DHT_disconnect(dht_handle); GNUNET_CRYPTO_rsa_key_free(our_key); GNUNET_CRYPTO_rsa_key_free(bob_key); GNUNET_CRYPTO_rsa_key_free(alice_key); GNUNET_free(web); GNUNET_free (nrb); return; } GNUNET_CRYPTO_short_hash(TEST_RECORD_NAME, strlen(TEST_RECORD_NAME), &name_hash); GNUNET_CRYPTO_short_hash(&alice_pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &zone_hash); GNUNET_CRYPTO_short_hash_double(&zone_hash, &zone_hash_double); GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double); GNUNET_CRYPTO_hash_xor(&zone_hash_double, &name_hash_double, &xor_hash); rd_payload_length += sizeof(struct GNSNameRecordBlock) + strlen(TEST_RECORD_NAME) + 1; GNUNET_DHT_put (dht_handle, &xor_hash, 0, GNUNET_DHT_RO_NONE, GNUNET_BLOCK_TYPE_GNS_NAMERECORD, rd_payload_length, (char*)nrb, rd.expiration, DHT_OPERATION_TIMEOUT, &put_pseu_dht, NULL); GNUNET_free(web); GNUNET_free (nrb); } static void put_pkey_dht(void *cls, int32_t success, const char *emsg) { struct GNSNameRecordBlock *nrb; struct GNUNET_CRYPTO_ShortHashCode name_hash; struct GNUNET_CRYPTO_ShortHashCode zone_hash; GNUNET_HashCode xor_hash; GNUNET_HashCode name_hash_double; GNUNET_HashCode zone_hash_double; uint32_t rd_payload_length; char* nrb_data = NULL; struct GNUNET_CRYPTO_RsaSignature *sig; struct GNUNET_NAMESTORE_RecordData rd; rd.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; rd.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode); rd.data = &alice_hash; rd.record_type = GNUNET_GNS_RECORD_PKEY; sig = GNUNET_NAMESTORE_create_signature(bob_key, GNUNET_TIME_UNIT_FOREVER_ABS, TEST_AUTHORITY_ALICE, &rd, 1); rd_payload_length = GNUNET_NAMESTORE_records_get_size (1, &rd); nrb = GNUNET_malloc(rd_payload_length + strlen(TEST_AUTHORITY_ALICE) + 1 + sizeof(struct GNSNameRecordBlock)); nrb->signature = *sig; nrb->public_key = bob_pkey; nrb->rd_count = htonl(1); memset(&nrb[1], 0, strlen(TEST_AUTHORITY_ALICE) + 1); strcpy((char*)&nrb[1], TEST_AUTHORITY_ALICE); nrb_data = (char*)&nrb[1]; nrb_data += strlen(TEST_AUTHORITY_ALICE) + 1; if (-1 == GNUNET_NAMESTORE_records_serialize (1, &rd, rd_payload_length, nrb_data)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Record serialization failed!\n"); ok = 3; GNUNET_CRYPTO_rsa_key_free(our_key); GNUNET_CRYPTO_rsa_key_free(bob_key); GNUNET_CRYPTO_rsa_key_free(alice_key); GNUNET_free(sig); GNUNET_free (nrb); return; } GNUNET_CRYPTO_short_hash(TEST_AUTHORITY_ALICE, strlen(TEST_AUTHORITY_ALICE), &name_hash); GNUNET_CRYPTO_short_hash(&bob_pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &zone_hash); GNUNET_CRYPTO_short_hash_double(&zone_hash, &zone_hash_double); GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double); GNUNET_CRYPTO_hash_xor(&zone_hash_double, &name_hash_double, &xor_hash); rd_payload_length += sizeof(struct GNSNameRecordBlock) + strlen(TEST_AUTHORITY_ALICE) + 1; GNUNET_DHT_put (dht_handle, &xor_hash, 0, GNUNET_DHT_RO_NONE, GNUNET_BLOCK_TYPE_GNS_NAMERECORD, rd_payload_length, (char*)nrb, rd.expiration, DHT_OPERATION_TIMEOUT, &put_www_dht, NULL); GNUNET_NAMESTORE_disconnect(namestore_handle, GNUNET_NO); GNUNET_free (nrb); } static void do_lookup(void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *_cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { char* our_keyfile; cfg = _cfg; GNUNET_SCHEDULER_cancel (die_task); /* put records into namestore */ namestore_handle = GNUNET_NAMESTORE_connect(cfg); if (NULL == namestore_handle) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to namestore\n"); ok = -1; return; } /* dht */ dht_handle = GNUNET_DHT_connect(cfg, 1); if (NULL == dht_handle) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to dht\n"); ok = -1; return; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", "ZONEKEY", &our_keyfile)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n"); ok = -1; return; } our_key = GNUNET_CRYPTO_rsa_key_create_from_file (our_keyfile); bob_key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE_BOB); alice_key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE_ALICE); GNUNET_free(our_keyfile); GNUNET_CRYPTO_rsa_key_get_public (our_key, &our_pkey); GNUNET_CRYPTO_rsa_key_get_public (bob_key, &bob_pkey); GNUNET_CRYPTO_rsa_key_get_public (alice_key, &alice_pkey); GNUNET_CRYPTO_short_hash(&bob_pkey, sizeof(bob_pkey), &bob_hash); GNUNET_CRYPTO_short_hash(&alice_pkey, sizeof(alice_pkey), &alice_hash); struct GNUNET_NAMESTORE_RecordData rd; rd.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; rd.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode); rd.data = &bob_hash; rd.record_type = GNUNET_GNS_RECORD_PKEY; GNUNET_NAMESTORE_record_create (namestore_handle, our_key, TEST_AUTHORITY_BOB, &rd, &put_pkey_dht, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { cfg = c; /* Get path from configuration file */ if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", &test_directory)) { ok = 404; return; } /* Set up a task to end testing if peer start fails */ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "didn't start all daemons in reasonable amount of time!!!"); /* Start alice */ //d1 = GNUNET_TESTING_daemon_start(cfg, TIMEOUT, GNUNET_NO, NULL, NULL, 0, // NULL, NULL, NULL, &do_lookup, NULL); pg = GNUNET_TESTING_daemons_start(cfg, 1, 1, 1, TIMEOUT, NULL, NULL, &do_lookup, NULL, NULL, NULL, NULL); } static int check () { int ret; /* Arguments for GNUNET_PROGRAM_run */ char *const argv[] = { "test-gns-pseu-shorten", /* Name to give running binary */ "-c", "test_gns_simple_lookup.conf", /* Config file to use */ #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; /* Run the run function as a new program */ ret = GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-gns-pseu-shorten", "nohelp", options, &run, &ok); if (ret != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "`test-gns-pseu-shorten': Failed with error code %d\n", ret); } return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-gns-pseu-shorten", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); /** * Need to remove base directory, subdirectories taken care * of by the testing framework. */ return ret; } /* end of test_gns_twopeer.c */ gnunet-0.9.3/src/gns/test_gns_max_queries.c0000644000175000017500000002562711760520101015723 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file gns/test_gns_max_queries.c * @brief base testcase for testing GNS background queries * in particular query replacement and clean shutdown */ #include "platform.h" #include "gnunet_testing_lib.h" #include "gnunet_core_service.h" #include "block_dns.h" #include "gns.h" #include "gnunet_signatures.h" #include "gnunet_namestore_service.h" #include "gnunet_dnsparser_lib.h" #include "gnunet_gns_service.h" /* DEFINES */ #define VERBOSE GNUNET_YES /* Timeout for entire testcase */ #define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 20) /* If number of peers not in config file, use this number */ #define DEFAULT_NUM_PEERS 2 /* test records to resolve */ #define TEST_DOMAIN "www.gnunet" #define TEST_DOMAIN_NACK "doesnotexist.bob.gnunet" #define TEST_IP "127.0.0.1" #define TEST_RECORD_NAME "www" #define TEST_ADDITIONAL_LOOKUPS 5 #define TEST_AUTHORITY_NAME "bob" #define KEYFILE_BOB "../namestore/zonefiles/HGU0A0VCU334DN7F2I9UIUMVQMM7JMSD142LIMNUGTTV9R0CF4EG.zkey" /* Globals */ /** * Directory to store temp data in, defined in config file */ static char *test_directory; static struct GNUNET_TESTING_PeerGroup *pg; /* Task handle to use to schedule test failure */ GNUNET_SCHEDULER_TaskIdentifier die_task; /* Global return value (0 for success, anything else for failure) */ static int ok; static struct GNUNET_NAMESTORE_Handle *namestore_handle; static struct GNUNET_GNS_Handle *gns_handle; const struct GNUNET_CONFIGURATION_Handle *cfg; static unsigned long long max_parallel_lookups; /** * Check whether peers successfully shut down. */ void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error on shutdown! ret=%d\n", ok); if (ok == 0) ok = 2; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "done(ret=%d)!\n", ok); } static void on_lookup_result_dummy(void *cls, uint32_t rd_count, const struct GNUNET_NAMESTORE_RecordData *rd) { if (rd_count != 0) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Got %d results from dummy lookup! Wanted: 0\n", rd_count); ok = -1; } } static void on_lookup_result(void *cls, uint32_t rd_count, const struct GNUNET_NAMESTORE_RecordData *rd) { struct in_addr a; int i; char* addr; if (rd_count == 0) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Lookup failed, rp_filtering?\n"); ok = 2; } else { ok = 1; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "name: %s\n", (char*)cls); for (i=0; ipacket; unsigned int num_answers = 0; /** * Put records in the DNS packet and modify it * to a response */ for (i=0; i < rd_count; i++) { if (rd[i].record_type == ilh->query->type) num_answers++; } struct GNUNET_DNSPARSER_Record answer_records[num_answers]; struct GNUNET_DNSPARSER_Record additional_records[rd_count-(num_answers)]; packet->answers = answer_records; packet->additional_records = additional_records; for (i=0; i < rd_count; i++) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Adding type %d to DNS response\n", rd[i].record_type); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Name: %s\n", ilh->query->name); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record %d/%d\n", i+1, rd_count); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record len %d\n", rd[i].data_size); if (rd[i].record_type == ilh->query->type) { answer_records[i].name = ilh->query->name; answer_records[i].type = rd[i].record_type; switch(rd[i].record_type) { case GNUNET_GNS_RECORD_TYPE_NS: case GNUNET_GNS_RECORD_TYPE_CNAME: case GNUNET_GNS_RECORD_TYPE_PTR: answer_records[i].data.hostname = (char*)rd[i].data; break; case GNUNET_GNS_RECORD_TYPE_SOA: answer_records[i].data.soa = (struct GNUNET_DNSPARSER_SoaRecord *)rd[i].data; break; case GNUNET_GNS_RECORD_MX: answer_records[i].data.mx = (struct GNUNET_DNSPARSER_MxRecord *)rd[i].data; break; default: answer_records[i].data.raw.data_len = rd[i].data_size; answer_records[i].data.raw.data = (char*)rd[i].data; } answer_records[i].expiration_time = rd[i].expiration; answer_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn } else { additional_records[i].name = ilh->query->name; additional_records[i].type = rd[i].record_type; switch(rd[i].record_type) { case GNUNET_GNS_RECORD_TYPE_NS: case GNUNET_GNS_RECORD_TYPE_CNAME: case GNUNET_GNS_RECORD_TYPE_PTR: additional_records[i].data.hostname = (char*)rd[i].data; break; case GNUNET_GNS_RECORD_TYPE_SOA: additional_records[i].data.soa = (struct GNUNET_DNSPARSER_SoaRecord *)rd[i].data; break; case GNUNET_GNS_RECORD_MX: additional_records[i].data.mx = (struct GNUNET_DNSPARSER_MxRecord *)rd[i].data; break; default: additional_records[i].data.raw.data_len = rd[i].data_size; additional_records[i].data.raw.data = (char*)rd[i].data; } additional_records[i].expiration_time = rd[i].expiration; additional_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn } } packet->num_answers = num_answers; packet->num_additional_records = rd_count-(num_answers); packet->flags.authoritative_answer = 1; if (rd == NULL) packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NAME_ERROR; else packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NO_ERROR; packet->flags.query_or_response = 1; /** * Reply to DNS */ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Building DNS response\n"); ret = GNUNET_DNSPARSER_pack (packet, 1024, /* FIXME magic from dns redirector */ &buf, &len); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Built DNS response! (ret=%d,len=%d)\n", ret, len); if (ret == GNUNET_OK) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Answering DNS request\n"); GNUNET_DNS_request_answer(ilh->request_handle, len, buf); GNUNET_free(buf); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Answered DNS request\n"); } else { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error building DNS response! (ret=%d)", ret); } packet->num_answers = 0; packet->answers = NULL; packet->num_additional_records = 0; packet->additional_records = NULL; GNUNET_DNSPARSER_free_packet(packet); GNUNET_free(ilh); } /** * Entry point for name resolution * Setup a new query and try to resolve * * @param request the request handle of the DNS request from a client * @param p the DNS query packet we received * @param q the DNS query we received parsed from p */ static void start_resolution_for_dns(struct GNUNET_DNS_RequestHandle *request, struct GNUNET_DNSPARSER_Packet *p, struct GNUNET_DNSPARSER_Query *q) { struct InterceptLookupHandle* ilh; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting resolution for %s (type=%d)!\n", q->name, q->type); ilh = GNUNET_malloc(sizeof(struct InterceptLookupHandle)); ilh->packet = p; ilh->query = q; ilh->request_handle = request; /* Start resolution in our zone */ gns_resolver_lookup_record(our_zone, our_zone, q->type, q->name, our_key, default_lookup_timeout, &reply_to_dns, ilh); } /** * The DNS request handler * Called for every incoming DNS request. * * @param cls closure * @param rh request handle to user for reply * @param request_length number of bytes in request * @param request udp payload of the DNS request */ static void handle_dns_request(void *cls, struct GNUNET_DNS_RequestHandle *rh, size_t request_length, const char *request) { struct GNUNET_DNSPARSER_Packet *p; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hijacked a DNS request...processing\n"); p = GNUNET_DNSPARSER_parse (request, request_length); if (NULL == p) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Received malformed DNS packet, leaving it untouched\n"); GNUNET_DNS_request_forward (rh); GNUNET_DNSPARSER_free_packet (p); return; } /** * Check tld and decide if we or * legacy dns is responsible * * FIXME now in theory there could be more than 1 query in the request * but if this is case we get into trouble: * either we query the GNS or the DNS. We cannot do both! * So I suggest to either only allow a single query per request or * only allow GNS or DNS requests. * The way it is implemented here now is buggy and will lead to erratic * behaviour (if multiple queries are present). */ if (p->num_queries == 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No Queries in DNS packet... forwarding\n"); GNUNET_DNS_request_forward (rh); GNUNET_DNSPARSER_free_packet(p); return; } if (p->num_queries > 1) { /* Note: We could also look for .gnunet */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, ">1 queriy in DNS packet... odd. We only process #1\n"); } /** * Check for .gnunet/.zkey */ if ((is_gnunet_tld(p->queries[0].name) == GNUNET_YES) || (is_zkey_tld(p->queries[0].name) == GNUNET_YES) || (strcmp(p->queries[0].name, GNUNET_GNS_TLD) == 0)) { start_resolution_for_dns(rh, p, p->queries); } else { /** * This request does not concern us. Forward to real DNS. */ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Request for %s is forwarded to DNS\n", p->queries[0].name); GNUNET_DNS_request_forward (rh); GNUNET_DNSPARSER_free_packet (p); } } /** * Initialized the interceptor * * @param zone the zone to work in * @param key the prov key of the zone (can be null, needed for caching) * @param c the configuration * @return GNUNET_OK on success */ int gns_interceptor_init(struct GNUNET_CRYPTO_ShortHashCode zone, struct GNUNET_CRYPTO_RsaPrivateKey *key, const struct GNUNET_CONFIGURATION_Handle *c) { unsigned long long default_lookup_timeout_secs = 0; GNUNET_log(GNUNET_ERROR_TYPE_INFO, "DNS hijacking enabled... connecting to service.\n"); our_zone = zone; our_key = key; /** * Do gnunet dns init here */ dns_handle = GNUNET_DNS_connect(c, GNUNET_DNS_FLAG_PRE_RESOLUTION, &handle_dns_request, /* rh */ NULL); /* Closure */ if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(c, "gns", "DEFAULT_LOOKUP_TIMEOUT", &default_lookup_timeout_secs)) { default_lookup_timeout = GNUNET_TIME_relative_multiply( GNUNET_TIME_UNIT_SECONDS, default_lookup_timeout_secs); } if (NULL == dns_handle) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to the dnsservice!\n"); return GNUNET_SYSERR; } return GNUNET_YES; } /** * Disconnect from interceptor */ void gns_interceptor_stop(void) { if (dns_handle) GNUNET_DNS_disconnect(dns_handle); } /* end of gns_interceptor.c */ gnunet-0.9.3/src/gns/gns.conf.in0000644000175000017500000000103611760502552013370 00000000000000[gns] AUTOSTART = YES HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-gns UNIXPATH = /tmp/gnunet-service-gns.sock ZONEKEY = $SERVICEHOME/gns/zonekey.zkey HIJACK_DNS = NO AUTO_IMPORT_PKEY = YES AUTO_IMPORT_CONFIRMATION_REQ = NO MAX_PARALLEL_BACKGROUND_QUERIES = 25 DEFAULT_LOOKUP_TIMEOUT = 10 RECORD_PUT_INTERVAL = 60 ZONE_PUT_INTERVAL = 900 [fcfsd] HTTPPORT = 18080 ZONEKEY = $SERVICEHOME/fcfsd/zonekey.zkey HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-gns-fcfsd gnunet-0.9.3/src/gns/test_gns_defaults.conf0000644000175000017500000000137411741361776015730 00000000000000[PATHS] SERVICEHOME = /tmp/test-gnunet-testing/ DEFAULTCONFIG = test_testing_defaults.conf [resolver] PORT = 2564 [transport] PORT = 2565 PLUGINS = tcp [arm] PORT = 2566 DEFAULTSERVICES = [statistics] PORT = 2567 [transport-tcp] PORT = 2568 BINDTO = 127.0.0.1 [peerinfo] PORT = 2569 [core] PORT = 2570 [testing] NUM_PEERS = 5 WEAKRANDOM = YES F2F = YES HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat [dht] AUTOSTART = NO [nat] DISABLEV6 = YES ENABLE_UPNP = NO BEHIND_NAT = NO ALLOW_NAT = NO INTERNAL_ADDRESS = 127.0.0.1 EXTERNAL_ADDRESS = 127.0.0.1 USE_LOCALADDR = NO [dns] AUTOSTART = NO [nse] AUTOSTART = NO [mesh] AUTOSTART = NO [datastore] AUTOSTART = NO [fs] AUTOSTART = NO [dv] AUTOSTART = NO [chat] AUTOSTART = NO [vpn] AUTOSTART = NO gnunet-0.9.3/src/gns/gnunet-service-gns_interceptor.h0000644000175000017500000000103011760502551017630 00000000000000#ifndef GNUNET_GNS_INTERCEPTOR_H #define GNUNET_GNS_INTERCEPTOR_H /** * Initialize dns interceptor * * @param zone the zone * @param key the private key of the local zone * @param c the configuration * @return GNUNET_YES on success GNUNET_SYSERR on error */ int gns_interceptor_init(struct GNUNET_CRYPTO_ShortHashCode zone, struct GNUNET_CRYPTO_RsaPrivateKey *key, const struct GNUNET_CONFIGURATION_Handle *c); /** * Stops the interceptor */ void gns_interceptor_stop(void); #endif gnunet-0.9.3/src/gns/test_gns_simple_zkey_lookup.c0000644000175000017500000002412711760520021017320 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file gns/test_gns_simple_zkey_lookup.c * @brief base testcase for testing zkey lookup * */ #include "platform.h" #include "gnunet_testing_lib.h" #include "gnunet_core_service.h" #include "block_dns.h" #include "gnunet_signatures.h" #include "gnunet_namestore_service.h" #include "../namestore/namestore.h" #include "gnunet_dnsparser_lib.h" #include "gnunet_gns_service.h" #include "gns.h" /* DEFINES */ #define VERBOSE GNUNET_YES /* Timeout for entire testcase */ #define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 20) /* If number of peers not in config file, use this number */ #define DEFAULT_NUM_PEERS 2 /* test records to resolve */ #define TEST_IP "127.0.0.1" #define TEST_RECORD_NAME "www" #define TEST_AUTHORITY_NAME "bob" #define KEYFILE_BOB "../namestore/zonefiles/HGU0A0VCU334DN7F2I9UIUMVQMM7JMSD142LIMNUGTTV9R0CF4EG.zkey" /* Globals */ /** * Directory to store temp data in, defined in config file */ static char *test_directory; static struct GNUNET_TESTING_PeerGroup *pg; /* Task handle to use to schedule test failure */ GNUNET_SCHEDULER_TaskIdentifier die_task; /* Global return value (0 for success, anything else for failure) */ static int ok; static struct GNUNET_NAMESTORE_Handle *namestore_handle; static struct GNUNET_GNS_Handle *gns_handle; const struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_CRYPTO_ShortHashCode bob_hash; /** * Check whether peers successfully shut down. */ void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error on shutdown! ret=%d\n", ok); if (ok == 0) ok = 2; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "done(ret=%d)!\n", ok); } static void on_lookup_result(void *cls, uint32_t rd_count, const struct GNUNET_NAMESTORE_RecordData *rd) { struct in_addr a; int i; char* addr; if (rd_count == 0) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Lookup failed, rp_filtering?\n"); ok = 2; } else { ok = 1; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "name: %s\n", (char*)cls); for (i=0; isignature = *sig; nrb->public_key = bob_pkey; nrb->rd_count = htonl(1); memset(&nrb[1], 0, strlen(TEST_RECORD_NAME) + 1); strcpy((char*)&nrb[1], TEST_RECORD_NAME); nrb_data = (char*)&nrb[1]; nrb_data += strlen(TEST_RECORD_NAME) + 1; if (-1 == GNUNET_NAMESTORE_records_serialize (1, &rd, rd_payload_length, nrb_data)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Record serialization failed!\n"); ok = 3; GNUNET_free (nrb); return; } GNUNET_CRYPTO_short_hash(TEST_RECORD_NAME, strlen(TEST_RECORD_NAME), &name_hash); GNUNET_CRYPTO_short_hash(&bob_pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &zone_hash); GNUNET_CRYPTO_short_hash_double(&zone_hash, &zone_hash_double); GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double); GNUNET_CRYPTO_hash_xor(&zone_hash_double, &name_hash_double, &xor_hash); rd_payload_length += sizeof(struct GNSNameRecordBlock) + strlen(TEST_RECORD_NAME) + 1; GNUNET_DHT_put (dht_handle, &xor_hash, 0, GNUNET_DHT_RO_NONE, GNUNET_BLOCK_TYPE_GNS_NAMERECORD, rd_payload_length, (char*)nrb, rd.expiration, DHT_OPERATION_TIMEOUT, NULL, NULL); GNUNET_free (nrb); GNUNET_SCHEDULER_add_delayed(TIMEOUT, &commence_testing, NULL); } static void do_lookup(void *cls, const struct GNUNET_PeerIdentity *id, const struct GNUNET_CONFIGURATION_Handle *_cfg, struct GNUNET_TESTING_Daemon *d, const char *emsg) { char* alice_keyfile; struct GNUNET_CRYPTO_ShortHashCode bob_hash; cfg = _cfg; GNUNET_SCHEDULER_cancel (die_task); /* put records into namestore */ namestore_handle = GNUNET_NAMESTORE_connect(cfg); if (NULL == namestore_handle) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to namestore\n"); ok = -1; return; } /* dht */ dht_handle = GNUNET_DHT_connect(cfg, 1); if (NULL == dht_handle) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to dht\n"); ok = -1; return; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", "ZONEKEY", &alice_keyfile)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n"); ok = -1; return; } alice_key = GNUNET_CRYPTO_rsa_key_create_from_file (alice_keyfile); bob_key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE_BOB); GNUNET_free(alice_keyfile); GNUNET_CRYPTO_rsa_key_get_public (alice_key, &alice_pkey); GNUNET_CRYPTO_rsa_key_get_public (bob_key, &bob_pkey); GNUNET_CRYPTO_short_hash(&bob_pkey, sizeof(bob_pkey), &bob_hash); struct GNUNET_NAMESTORE_RecordData rd; rd.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; rd.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode); rd.data = &bob_hash; rd.record_type = GNUNET_GNS_RECORD_PKEY; GNUNET_NAMESTORE_record_create (namestore_handle, alice_key, TEST_AUTHORITY_NAME, &rd, &put_dht, NULL); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { cfg = c; /* Get path from configuration file */ if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", &test_directory)) { ok = 404; return; } /* Set up a task to end testing if peer start fails */ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "didn't start all daemons in reasonable amount of time!!!"); /* Start alice */ //d1 = GNUNET_TESTING_daemon_start(cfg, TIMEOUT, GNUNET_NO, NULL, NULL, 0, // NULL, NULL, NULL, &do_lookup, NULL); pg = GNUNET_TESTING_daemons_start(cfg, 1, 1, 1, TIMEOUT, NULL, NULL, &do_lookup, NULL, NULL, NULL, NULL); } static int check () { int ret; /* Arguments for GNUNET_PROGRAM_run */ char *const argv[] = { "test-gns-dht-delegated-lookup", /* Name to give running binary */ "-c", "test_gns_simple_lookup.conf", /* Config file to use */ #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; /* Run the run function as a new program */ ret = GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-gns-dht-delegated-lookup", "nohelp", options, &run, &ok); if (ret != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "`test-gns-dht-delegated-lookup': Failed with error code %d\n", ret); } return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_log_setup ("test-gns-simple-lookup", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); /** * Need to remove base directory, subdirectories taken care * of by the testing framework. */ return ret; } /* end of test_gns_twopeer.c */ gnunet-0.9.3/src/gns/gnunet-service-gns_resolver.h0000644000175000017500000002242011760502551017141 00000000000000#ifndef GNS_RESOLVER_H #define GNS_RESOLVER_H #include "gns.h" #include "gnunet_dht_service.h" #define DHT_OPERATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) #define GNUNET_GNS_DEFAULT_LOOKUP_TIMEOUT \ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) #define DHT_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT #define DHT_GNS_REPLICATION_LEVEL 5 #define GNUNET_GNS_MAX_PARALLEL_LOOKUPS 500 /* * DLL to hold the authority chain * we had to pass in the resolution process */ struct AuthorityChain { struct AuthorityChain *prev; struct AuthorityChain *next; /* the zone hash of the authority */ struct GNUNET_CRYPTO_ShortHashCode zone; /* (local) name of the authority */ char name[MAX_DNS_LABEL_LENGTH]; /* was the ns entry fresh */ int fresh; }; /* handle to a resolution process */ struct ResolverHandle; /** * continuation called when cleanup of resolver finishes */ typedef void (*ResolverCleanupContinuation) (void); /** * processor for a record lookup result * * @param cls the closure * @param rd_count number of results * @param rd result data */ typedef void (*RecordLookupProcessor) (void *cls, uint32_t rd_count, const struct GNUNET_NAMESTORE_RecordData *rd); /** * processor for a shorten result * * @param cls the closure * @param name shortened name */ typedef void (*ShortenResultProcessor) (void *cls, const char* name); /** * processor for an authority result * * @param cls the closure * @param name name */ typedef void (*GetAuthorityResultProcessor) (void *cls, const char* name); /** * processor for a resolution result * * @param cls the closure * @param rh the resolution handle * @param rd_count number of results * @param rd result data */ typedef void (*ResolutionResultProcessor) (void *cls, struct ResolverHandle *rh, uint32_t rd_count, const struct GNUNET_NAMESTORE_RecordData *rd); /** * Resolution status indicator * RSL_RECORD_EXISTS: the name to lookup exists * RSL_RECORD_EXPIRED: the name in the record expired * RSL_TIMED_OUT: resolution timed out */ enum ResolutionStatus { RSL_RECORD_EXISTS = 1, RSL_RECORD_EXPIRED = 2, RSL_TIMED_OUT = 4 }; /** * Handle to a currenty pending resolution * a ResolverHandle is passed to, for example * resolve_record_ns to resolve a record in the namestore. * On result (positive or negative) the ResolutionResultProcessor * is called. * If a timeout is set timeout_cont will be called. * If no timeout is set (ie timeout forever) then background resolutions * might be triggered. */ struct ResolverHandle { /* The name to resolve */ char name[MAX_DNS_NAME_LENGTH]; /* has this query been answered? how many matches */ int answered; /* the authoritative zone to query */ struct GNUNET_CRYPTO_ShortHashCode authority; /* the name of the authoritative zone to query */ char authority_name[MAX_DNS_LABEL_LENGTH]; /* a handle for dht lookups. should be NULL if no lookups are in progress */ struct GNUNET_DHT_GetHandle *get_handle; /* timeout set for this lookup task */ struct GNUNET_TIME_Relative timeout; /* timeout task for the lookup */ GNUNET_SCHEDULER_TaskIdentifier timeout_task; /* continuation to call on timeout */ GNUNET_SCHEDULER_Task timeout_cont; /* closure for timeout cont */ void* timeout_cont_cls; /* called when resolution phase finishes */ ResolutionResultProcessor proc; /* closure passed to proc */ void* proc_cls; /* DLL to store the authority chain */ struct AuthorityChain *authority_chain_head; /* DLL to store the authority chain */ struct AuthorityChain *authority_chain_tail; /* status of the resolution result */ enum ResolutionStatus status; /* The provate local zone of this request */ struct GNUNET_CRYPTO_ShortHashCode private_local_zone; /** * private key of an/our authoritative zone * can be NULL but automatical PKEY import will not work */ struct GNUNET_CRYPTO_RsaPrivateKey *priv_key; /** * the heap node associated with this lookup, null if timeout is set * used for DHT background lookups. */ struct GNUNET_CONTAINER_HeapNode *dht_heap_node; /** * Id for resolution process */ unsigned long long id; }; /** * Handle to a record lookup */ struct RecordLookupHandle { /* the record type to look up */ enum GNUNET_GNS_RecordType record_type; /* the name to look up */ char name[MAX_DNS_NAME_LENGTH]; /* Method to call on record resolution result */ RecordLookupProcessor proc; /* closure to pass to proc */ void* proc_cls; }; /** * Handle to a shorten context */ struct NameShortenHandle { /* Method to call on shorten result */ ShortenResultProcessor proc; /* closure to pass to proc */ void* proc_cls; }; /** * Handle to a get authority context */ struct GetNameAuthorityHandle { /* the name to look up authority for */ char name[MAX_DNS_NAME_LENGTH]; /* Method to call on result */ GetAuthorityResultProcessor proc; /* closure to pass to proc */ void* proc_cls; }; /** * Handle to a pseu lookup */ struct GetPseuAuthorityHandle { /* the name given from delegation */ char name[MAX_DNS_LABEL_LENGTH]; /* name to store the pseu under */ char new_name[MAX_DNS_LABEL_LENGTH]; /* the zone of discovered authority */ struct GNUNET_CRYPTO_ShortHashCode new_zone; /* the zone of our authority */ struct GNUNET_CRYPTO_ShortHashCode zone; /* the private key of the zone to store the pseu in */ struct GNUNET_CRYPTO_RsaPrivateKey *key; /* a handle for dht lookups. should be NULL if no lookups are in progress */ struct GNUNET_DHT_GetHandle *get_handle; /* timeout task for lookup */ GNUNET_SCHEDULER_TaskIdentifier timeout; }; /** * Initialize the resolver * MUST be called before other gns_resolver_* methods * * @param nh handle to the namestore * @param dh handle to the dht * @param lz the local zone * @param max_bg_queries maximum amount of background queries * @param ignore_pending ignore records that still require user confirmation * on lookup * @returns GNUNET_OK on success */ int gns_resolver_init(struct GNUNET_NAMESTORE_Handle *nh, struct GNUNET_DHT_Handle *dh, struct GNUNET_CRYPTO_ShortHashCode lz, unsigned long long max_bg_queries, int ignore_pending); /** * Cleanup resolver: Terminate pending lookups * * @param cont continuation to call when finished */ void gns_resolver_cleanup(ResolverCleanupContinuation cont); /** * Lookup of a record in a specific zone * calls RecordLookupProcessor on result or timeout * * @param zone the root zone * @param pzone the private local zone * @param record_type the record type to look up * @param name the name to look up * @param key optional private key for authority caching * @param timeout timeout for the resolution * @param proc the processor to call * @param cls the closure to pass to proc */ void gns_resolver_lookup_record(struct GNUNET_CRYPTO_ShortHashCode zone, struct GNUNET_CRYPTO_ShortHashCode pzone, uint32_t record_type, const char* name, struct GNUNET_CRYPTO_RsaPrivateKey *key, struct GNUNET_TIME_Relative timeout, RecordLookupProcessor proc, void* cls); /** * Shortens a name if possible. If the shortening fails * name will be returned as shortened string. Else * a shorter version of the name will be returned. * There is no guarantee that the shortened name will * actually be canonical/short etc. * * @param zone the zone to perform the operation in * @param pzone the private local zone * @param name name to shorten * @param key optional private key for background lookups and PSEU import * @param proc the processor to call on shorten result * @param proc_cls the closure to pass to proc */ void gns_resolver_shorten_name(struct GNUNET_CRYPTO_ShortHashCode zone, struct GNUNET_CRYPTO_ShortHashCode pzone, const char* name, struct GNUNET_CRYPTO_RsaPrivateKey *key, ShortenResultProcessor proc, void* proc_cls); /** * Tries to resolve the authority for name * in our namestore * * @param zone the root zone to look up for * @param pzone the private local zone * @param name the name to lookup up * @param proc the processor to call when finished * @param proc_cls the closure to pass to the processor */ void gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone, struct GNUNET_CRYPTO_ShortHashCode pzone, const char* name, GetAuthorityResultProcessor proc, void* proc_cls); /** * Generic function to check for TLDs * * @param name the name to check * @param tld the tld to check * @return GNUNET_YES or GNUNET_NO */ int is_tld(const char* name, const char* tld); /** * Checks for gnunet/zkey */ #define is_gnunet_tld(name) is_tld(name, GNUNET_GNS_TLD) #define is_zkey_tld(name) is_tld(name, GNUNET_GNS_TLD_ZKEY) #endif gnunet-0.9.3/src/gns/test_gns_simple_mx_lookup.c0000644000175000017500000002712311760520002016760 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file gns/test_gns_simple_mx_lookup.c * @brief base testcase for testing GNS MX lookups * */ #include "platform.h" #include "gnunet_testing_lib.h" #include "gnunet_core_service.h" #include "block_dns.h" #include "gnunet_signatures.h" #include "gnunet_namestore_service.h" #include "../namestore/namestore.h" #include "gnunet_dnsparser_lib.h" #include "gnunet_gns_service.h" /* DEFINES */ #define VERBOSE GNUNET_YES /* Timeout for entire testcase */ #define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 20) /* If number of peers not in config file, use this number */ #define DEFAULT_NUM_PEERS 2 /* test records to resolve */ #define TEST_DOMAIN "bob.gnunet" #define TEST_IP "127.0.0.1" #define TEST_RECORD_NAME "mail" #define TEST_MX_NAME "mail.+" #define TEST_EXPECTED_MX "mail.bob.gnunet" #define TEST_AUTHORITY_NAME "bob" #define KEYFILE_BOB "../namestore/zonefiles/HGU0A0VCU334DN7F2I9UIUMVQMM7JMSD142LIMNUGTTV9R0CF4EG.zkey" /* Globals */ /** * Directory to store temp data in, defined in config file */ static char *test_directory; static struct GNUNET_TESTING_PeerGroup *pg; /* Task handle to use to schedule test failure */ GNUNET_SCHEDULER_TaskIdentifier die_task; /* Global return value (0 for success, anything else for failure) */ static int ok; static struct GNUNET_NAMESTORE_Handle *namestore_handle; static struct GNUNET_GNS_Handle *gns_handle; const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Check whether peers successfully shut down. */ void shutdown_callback (void *cls, const char *emsg) { if (emsg != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error on shutdown! ret=%d\n", ok); if (ok == 0) ok = 2; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "done(ret=%d)!\n", ok); } static void on_lookup_result(void *cls, uint32_t rd_count, const struct GNUNET_NAMESTORE_RecordData *rd) { struct in_addr a; int i; char* addr; int mx_found = 0; int ip_found = 0; uint16_t mx_preference; char* mx; if (rd_count == 0) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Lookup failed, rp_filtering?\n"); ok = 2; } else { ok = 1; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "name: %s\n", (char*)cls); for (i=0; i #include #include #include #include #include #include #include #include #include #include "nss_gns_query.h" #include /** macro to align idx to 32bit boundary */ #define ALIGN(idx) do { \ if (idx % sizeof(void*)) \ idx += (sizeof(void*) - idx % sizeof(void*)); /* Align on 32 bit boundary */ \ } while(0) /** * function to check if name ends with a specific suffix * * @param name the name to check * @param suffix the suffix to check for * @return 1 if true */ static int ends_with(const char *name, const char* suffix) { size_t ln, ls; assert(name); assert(suffix); if ((ls = strlen(suffix)) > (ln = strlen(name))) return 0; return strcasecmp(name+ln-ls, suffix) == 0; } /** * Check if name is inside .gnunet or .zkey TLD * * @param name name to check * @return 1 if true */ static int verify_name_allowed(const char *name) { return ends_with(name, ".gnunet") || ends_with(name, ".zkey"); } /** * The gethostbyname hook executed by nsswitch * * @param name the name to resolve * @param af the address family to resolve * @param result the result hostent * @param buffer the result buffer * @param buflen length of the buffer * @param errnop idk * @param h_errnop idk * @return a nss_status code */ enum nss_status _nss_gns_gethostbyname2_r( const char *name, int af, struct hostent * result, char *buffer, size_t buflen, int *errnop, int *h_errnop) { struct userdata u; enum nss_status status = NSS_STATUS_UNAVAIL; int i; size_t address_length, l, idx, astart; int name_allowed; if (af == AF_UNSPEC) #ifdef NSS_IPV6_ONLY af = AF_INET6; #else af = AF_INET; #endif #ifdef NSS_IPV4_ONLY if (af != AF_INET) #elif NSS_IPV6_ONLY if (af != AF_INET6) #else if (af != AF_INET && af != AF_INET6) #endif { *errnop = EINVAL; *h_errnop = NO_RECOVERY; goto finish; } address_length = af == AF_INET ? sizeof(ipv4_address_t) : sizeof(ipv6_address_t); if (buflen < sizeof(char*)+ /* alias names */ strlen(name)+1) { /* official name */ *errnop = ERANGE; *h_errnop = NO_RECOVERY; status = NSS_STATUS_TRYAGAIN; goto finish; } u.count = 0; u.data_len = 0; name_allowed = verify_name_allowed(name); if (name_allowed) { if (!gns_resolve_name(af, name, &u) == 0) { status = NSS_STATUS_NOTFOUND; } } if (u.count == 0) { *errnop = ETIMEDOUT; *h_errnop = HOST_NOT_FOUND; printf("not found\n"); goto finish; } /* Alias names */ *((char**) buffer) = NULL; result->h_aliases = (char**) buffer; idx = sizeof(char*); /* Official name */ strcpy(buffer+idx, name); result->h_name = buffer+idx; idx += strlen(name)+1; ALIGN(idx); result->h_addrtype = af; result->h_length = address_length; /* Check if there's enough space for the addresses */ if (buflen < idx+u.data_len+sizeof(char*)*(u.count+1)) { *errnop = ERANGE; *h_errnop = NO_RECOVERY; status = NSS_STATUS_TRYAGAIN; goto finish; } /* Addresses */ astart = idx; l = u.count*address_length; memcpy(buffer+astart, &u.data, l); /* address_length is a multiple of 32bits, so idx is still aligned * correctly */ idx += l; /* Address array address_lenght is always a multiple of 32bits */ for (i = 0; i < u.count; i++) ((char**) (buffer+idx))[i] = buffer+astart+address_length*i; ((char**) (buffer+idx))[i] = NULL; result->h_addr_list = (char**) (buffer+idx); status = NSS_STATUS_SUCCESS; finish: return status; } /** * The gethostbyname hook executed by nsswitch * * @param name the name to resolve * @param result the result hostent * @param buffer the result buffer * @param buflen length of the buffer * @param errnop idk * @param h_errnop idk * @return a nss_status code */ enum nss_status _nss_gns_gethostbyname_r ( const char *name, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop) { return _nss_gns_gethostbyname2_r( name, AF_UNSPEC, result, buffer, buflen, errnop, h_errnop); } /** * The gethostbyaddr hook executed by nsswitch * We can't do this so we always return NSS_STATUS_UNAVAIL * * @param addr the address to resolve * @param len the length of the address * @param af the address family of the address * @param result the result hostent * @param buffer the result buffer * @param buflen length of the buffer * @param errnop idk * @param h_errnop idk * @return NSS_STATUS_UNAVAIL */ enum nss_status _nss_gns_gethostbyaddr_r( const void* addr, int len, int af, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop) { /* we dont do this */ enum nss_status status = NSS_STATUS_UNAVAIL; *errnop = EINVAL; *h_errnop = NO_RECOVERY; /* Check for address types */ *h_errnop = NO_RECOVERY; status = NSS_STATUS_NOTFOUND; return status; } gnunet-0.9.3/src/gns/nss/nss_gns_query.c0000644000175000017500000000241411762111032015163 00000000000000#include #include #include #include "nss_gns_query.h" #include /** * Wrapper function that uses gnunet-gns cli tool to resolve * an IPv4/6 address. * * @param af address family * @param name the name to resolve * @param u the userdata (result struct) * @return -1 on error else 0 */ int gns_resolve_name(int af, const char *name, struct userdata *u) { FILE *p; char *cmd; char line[128]; if (af == AF_INET6) { if (-1 == asprintf(&cmd, "%s -t AAAA -u %s\n", "gnunet-gns -r", name)) return -1; } else { if (-1 == asprintf(&cmd, "%s %s\n", "gnunet-gns -r -u", name)) return -1; } p = popen(cmd,"r"); if (p != NULL ) { while (fgets( line, sizeof(line), p ) != NULL) { if (u->count >= MAX_ENTRIES) break; if (line[strlen(line)-1] == '\n') { line[strlen(line)-1] = '\0'; if (af == AF_INET) { inet_pton(af, line, &(u->data.ipv4[u->count++])); u->data_len += sizeof(ipv4_address_t); } else if ((af == AF_INET6)) { inet_pton(af, line, &(u->data.ipv6[u->count++])); u->data_len += sizeof(ipv6_address_t); } } } } fclose(p); free(cmd); return 0; } gnunet-0.9.3/src/gns/nss/nss_gns_query.h0000644000175000017500000000317311762111032015173 00000000000000#ifndef NSS_GNS_QUERY_H #define NSS_GNS_QUERY_H /** * Parts taken from nss-mdns. Original license statement follows */ /* $Id$ */ /*** This file is part of nss-mdns. nss-mdns is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. nss-mdns is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with nss-mdns; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #include /* Maximum number of entries to return */ #define MAX_ENTRIES 16 typedef struct { uint32_t address; } ipv4_address_t; typedef struct { uint8_t address[16]; } ipv6_address_t; struct userdata { int count; int data_len; /* only valid when doing reverse lookup */ union { ipv4_address_t ipv4[MAX_ENTRIES]; ipv6_address_t ipv6[MAX_ENTRIES]; char *name[MAX_ENTRIES]; } data; }; /** * Wrapper function that uses gnunet-gns cli tool to resolve * an IPv4/6 address. * * @param af address family * @param name the name to resolve * @param u the userdata (result struct) * @return -1 on error else 0 */ int gns_resolve_name(int af, const char *name, struct userdata *userdata); #endif gnunet-0.9.3/src/gns/nss/Makefile.in0000644000175000017500000007474611762217211014214 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # $Id$ # # This file taken and modified from nss-gns. # # nss-gns is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; either version 2 of the # License, or (at your option) any later version. # # nss-gns is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with nss-gns; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = src/gns/nss DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(nssdir)" LTLIBRARIES = $(nss_LTLIBRARIES) libnss_gns_la_LIBADD = am__objects_1 = libnss_gns_la-nss_gns_query.lo am_libnss_gns_la_OBJECTS = $(am__objects_1) libnss_gns_la-nss_gns.lo libnss_gns_la_OBJECTS = $(am_libnss_gns_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libnss_gns_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libnss_gns_la_CFLAGS) \ $(CFLAGS) $(libnss_gns_la_LDFLAGS) $(LDFLAGS) -o $@ @MINGW_FALSE@am_libnss_gns_la_rpath = -rpath $(nssdir) libnss_gns4_la_LIBADD = am__objects_2 = libnss_gns4_la-nss_gns_query.lo am__objects_3 = $(am__objects_2) libnss_gns4_la-nss_gns.lo am_libnss_gns4_la_OBJECTS = $(am__objects_3) libnss_gns4_la_OBJECTS = $(am_libnss_gns4_la_OBJECTS) libnss_gns4_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(libnss_gns4_la_CFLAGS) $(CFLAGS) $(libnss_gns4_la_LDFLAGS) \ $(LDFLAGS) -o $@ @MINGW_FALSE@am_libnss_gns4_la_rpath = -rpath $(nssdir) libnss_gns6_la_LIBADD = am__objects_4 = libnss_gns6_la-nss_gns_query.lo am__objects_5 = $(am__objects_4) libnss_gns6_la-nss_gns.lo am_libnss_gns6_la_OBJECTS = $(am__objects_5) libnss_gns6_la_OBJECTS = $(am_libnss_gns6_la_OBJECTS) libnss_gns6_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(libnss_gns6_la_CFLAGS) $(CFLAGS) $(libnss_gns6_la_LDFLAGS) \ $(LDFLAGS) -o $@ @MINGW_FALSE@am_libnss_gns6_la_rpath = -rpath $(nssdir) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libnss_gns_la_SOURCES) $(libnss_gns4_la_SOURCES) \ $(libnss_gns6_la_SOURCES) DIST_SOURCES = $(libnss_gns_la_SOURCES) $(libnss_gns4_la_SOURCES) \ $(libnss_gns6_la_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = $(SUDO_BINARY) $(SHELL) $(top_builddir)/libtool LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = map-file AM_LDFLAGS = -avoid-version -module -export-dynamic @HAVE_SUDO_FALSE@nssdir = $(libdir) @HAVE_SUDO_TRUE@nssdir = /lib/ @MINGW_FALSE@nss_LTLIBRARIES = \ @MINGW_FALSE@ libnss_gns.la \ @MINGW_FALSE@ libnss_gns4.la \ @MINGW_FALSE@ libnss_gns6.la sources = nss_gns_query.h nss_gns_query.c # GNU Libc libnss_gns_la_SOURCES = $(sources) nss_gns.c libnss_gns_la_CFLAGS = $(AM_CFLAGS) -D_GNU_SOURCE libnss_gns_la_LDFLAGS = $(AM_LDFLAGS) -shrext .so.2 -Wl,-version-script=$(srcdir)/map-file libnss_gns4_la_SOURCES = $(libnss_gns_la_SOURCES) libnss_gns4_la_CFLAGS = $(libnss_gns_la_CFLAGS) -DNSS_IPV4_ONLY=1 libnss_gns4_la_LDFLAGS = $(libnss_gns_la_LDFLAGS) libnss_gns6_la_SOURCES = $(libnss_gns_la_SOURCES) libnss_gns6_la_CFLAGS = $(libnss_gns_la_CFLAGS) -DNSS_IPV6_ONLY=1 libnss_gns6_la_LDFLAGS = $(libnss_gns_la_LDFLAGS) all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/gns/nss/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/gns/nss/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-nssLTLIBRARIES: $(nss_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(nssdir)" || $(MKDIR_P) "$(DESTDIR)$(nssdir)" @list='$(nss_LTLIBRARIES)'; test -n "$(nssdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(nssdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(nssdir)"; \ } uninstall-nssLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(nss_LTLIBRARIES)'; test -n "$(nssdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(nssdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(nssdir)/$$f"; \ done clean-nssLTLIBRARIES: -test -z "$(nss_LTLIBRARIES)" || rm -f $(nss_LTLIBRARIES) @list='$(nss_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libnss_gns.la: $(libnss_gns_la_OBJECTS) $(libnss_gns_la_DEPENDENCIES) $(AM_V_CCLD)$(libnss_gns_la_LINK) $(am_libnss_gns_la_rpath) $(libnss_gns_la_OBJECTS) $(libnss_gns_la_LIBADD) $(LIBS) libnss_gns4.la: $(libnss_gns4_la_OBJECTS) $(libnss_gns4_la_DEPENDENCIES) $(AM_V_CCLD)$(libnss_gns4_la_LINK) $(am_libnss_gns4_la_rpath) $(libnss_gns4_la_OBJECTS) $(libnss_gns4_la_LIBADD) $(LIBS) libnss_gns6.la: $(libnss_gns6_la_OBJECTS) $(libnss_gns6_la_DEPENDENCIES) $(AM_V_CCLD)$(libnss_gns6_la_LINK) $(am_libnss_gns6_la_rpath) $(libnss_gns6_la_OBJECTS) $(libnss_gns6_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnss_gns4_la-nss_gns.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnss_gns4_la-nss_gns_query.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnss_gns6_la-nss_gns.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnss_gns6_la-nss_gns_query.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnss_gns_la-nss_gns.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnss_gns_la-nss_gns_query.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< libnss_gns_la-nss_gns_query.lo: nss_gns_query.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns_la_CFLAGS) $(CFLAGS) -MT libnss_gns_la-nss_gns_query.lo -MD -MP -MF $(DEPDIR)/libnss_gns_la-nss_gns_query.Tpo -c -o libnss_gns_la-nss_gns_query.lo `test -f 'nss_gns_query.c' || echo '$(srcdir)/'`nss_gns_query.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnss_gns_la-nss_gns_query.Tpo $(DEPDIR)/libnss_gns_la-nss_gns_query.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nss_gns_query.c' object='libnss_gns_la-nss_gns_query.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns_la_CFLAGS) $(CFLAGS) -c -o libnss_gns_la-nss_gns_query.lo `test -f 'nss_gns_query.c' || echo '$(srcdir)/'`nss_gns_query.c libnss_gns_la-nss_gns.lo: nss_gns.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns_la_CFLAGS) $(CFLAGS) -MT libnss_gns_la-nss_gns.lo -MD -MP -MF $(DEPDIR)/libnss_gns_la-nss_gns.Tpo -c -o libnss_gns_la-nss_gns.lo `test -f 'nss_gns.c' || echo '$(srcdir)/'`nss_gns.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnss_gns_la-nss_gns.Tpo $(DEPDIR)/libnss_gns_la-nss_gns.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nss_gns.c' object='libnss_gns_la-nss_gns.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns_la_CFLAGS) $(CFLAGS) -c -o libnss_gns_la-nss_gns.lo `test -f 'nss_gns.c' || echo '$(srcdir)/'`nss_gns.c libnss_gns4_la-nss_gns_query.lo: nss_gns_query.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns4_la_CFLAGS) $(CFLAGS) -MT libnss_gns4_la-nss_gns_query.lo -MD -MP -MF $(DEPDIR)/libnss_gns4_la-nss_gns_query.Tpo -c -o libnss_gns4_la-nss_gns_query.lo `test -f 'nss_gns_query.c' || echo '$(srcdir)/'`nss_gns_query.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnss_gns4_la-nss_gns_query.Tpo $(DEPDIR)/libnss_gns4_la-nss_gns_query.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nss_gns_query.c' object='libnss_gns4_la-nss_gns_query.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns4_la_CFLAGS) $(CFLAGS) -c -o libnss_gns4_la-nss_gns_query.lo `test -f 'nss_gns_query.c' || echo '$(srcdir)/'`nss_gns_query.c libnss_gns4_la-nss_gns.lo: nss_gns.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns4_la_CFLAGS) $(CFLAGS) -MT libnss_gns4_la-nss_gns.lo -MD -MP -MF $(DEPDIR)/libnss_gns4_la-nss_gns.Tpo -c -o libnss_gns4_la-nss_gns.lo `test -f 'nss_gns.c' || echo '$(srcdir)/'`nss_gns.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnss_gns4_la-nss_gns.Tpo $(DEPDIR)/libnss_gns4_la-nss_gns.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nss_gns.c' object='libnss_gns4_la-nss_gns.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns4_la_CFLAGS) $(CFLAGS) -c -o libnss_gns4_la-nss_gns.lo `test -f 'nss_gns.c' || echo '$(srcdir)/'`nss_gns.c libnss_gns6_la-nss_gns_query.lo: nss_gns_query.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns6_la_CFLAGS) $(CFLAGS) -MT libnss_gns6_la-nss_gns_query.lo -MD -MP -MF $(DEPDIR)/libnss_gns6_la-nss_gns_query.Tpo -c -o libnss_gns6_la-nss_gns_query.lo `test -f 'nss_gns_query.c' || echo '$(srcdir)/'`nss_gns_query.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnss_gns6_la-nss_gns_query.Tpo $(DEPDIR)/libnss_gns6_la-nss_gns_query.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nss_gns_query.c' object='libnss_gns6_la-nss_gns_query.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns6_la_CFLAGS) $(CFLAGS) -c -o libnss_gns6_la-nss_gns_query.lo `test -f 'nss_gns_query.c' || echo '$(srcdir)/'`nss_gns_query.c libnss_gns6_la-nss_gns.lo: nss_gns.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns6_la_CFLAGS) $(CFLAGS) -MT libnss_gns6_la-nss_gns.lo -MD -MP -MF $(DEPDIR)/libnss_gns6_la-nss_gns.Tpo -c -o libnss_gns6_la-nss_gns.lo `test -f 'nss_gns.c' || echo '$(srcdir)/'`nss_gns.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnss_gns6_la-nss_gns.Tpo $(DEPDIR)/libnss_gns6_la-nss_gns.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nss_gns.c' object='libnss_gns6_la-nss_gns.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns6_la_CFLAGS) $(CFLAGS) -c -o libnss_gns6_la-nss_gns.lo `test -f 'nss_gns.c' || echo '$(srcdir)/'`nss_gns.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) installdirs: for dir in "$(DESTDIR)$(nssdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-nssLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-nssLTLIBRARIES @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-data-hook install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-nssLTLIBRARIES @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) uninstall-hook .MAKE: install-am install-data-am install-strip uninstall-am .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libtool clean-nssLTLIBRARIES ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-data-hook install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-nssLTLIBRARIES install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-hook \ uninstall-nssLTLIBRARIES install-data-hook: $(SUDO_BINARY) $(SHELL) $(top_builddir)/libtool --finish $(nssdir) $(SUDO_BINARY) rm -f $(nssdir)/libnss_gns.la $(nssdir)/libnss_gns4.la $(nssdir)/libnss_gns6.la uninstall-hook: $(SUDO_BINARY) rm -f $(nssdir)/libnss_gns.so.2 $(nssdir)/libnss_gns4.so.2 $(nssdir)/libnss_gns6.so.2 # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/gns/gnunet-gns-proxy.c0000644000175000017500000005751011762202310014734 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "platform.h" #include #include #include "gns_proxy_proto.h" #include "gns.h" #define GNUNET_GNS_PROXY_PORT 7777 //TODO maybe make this an api call /** * Checks if name is in tld * * @param name the name to check * @param tld the TLD to check for * @return GNUNET_YES or GNUNET_NO */ int is_tld(const char* name, const char* tld) { int offset = 0; if (strlen(name) <= strlen(tld)) { return GNUNET_NO; } offset = strlen(name)-strlen(tld); if (strcmp (name+offset, tld) != 0) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "%s is not in .%s TLD\n", name, tld); return GNUNET_NO; } return GNUNET_YES; } struct Socks5Request { struct GNUNET_NETWORK_Handle *sock; struct GNUNET_NETWORK_Handle *remote_sock; int state; GNUNET_SCHEDULER_TaskIdentifier rtask; GNUNET_SCHEDULER_TaskIdentifier fwdrtask; GNUNET_SCHEDULER_TaskIdentifier wtask; GNUNET_SCHEDULER_TaskIdentifier fwdwtask; char rbuf[2048]; char wbuf[2048]; unsigned int rbuf_len; unsigned int wbuf_len; }; unsigned long port = GNUNET_GNS_PROXY_PORT; static struct GNUNET_NETWORK_Handle *lsock; GNUNET_SCHEDULER_TaskIdentifier ltask; static struct MHD_Daemon *httpd; static GNUNET_SCHEDULER_TaskIdentifier httpd_task; static int con_val_iter (void *cls, enum MHD_ValueKind kind, const char *key, const char *value) { char* buf = (char*)cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s:%s\n", key, value); if (0 == strcmp ("Host", key)) { strcpy (buf, value); return MHD_NO; } return MHD_YES; } /** * Main MHD callback for handling requests. * * @param cls unused * @param connection MHD connection handle * @param method the HTTP method used ("GET", "PUT", etc.) * @param version the HTTP version string (i.e. "HTTP/1.1") * @param upload_data the data being uploaded (excluding HEADERS, * for a POST that fits into memory and that is encoded * with a supported encoding, the POST data will NOT be * given in upload_data and is instead available as * part of MHD_get_connection_values; very large POST * data *will* be made available incrementally in * upload_data) * @param upload_data_size set initially to the size of the * upload_data provided; the method must update this * value to the number of bytes NOT processed; * @param ptr pointer to location where we store the 'struct Request' * @return MHD_YES if the connection was handled successfully, * MHD_NO if the socket must be closed due to a serious * error while handling the request */ static int create_response (void *cls, struct MHD_Connection *con, const char *url, const char *meth, const char *ver, const char *upload_data, size_t *upload_data_size, void **con_cls) { static int dummy; const char* page = "gnoxy"\ "gnoxy demo"; struct MHD_Response *response; char host[265]; int ret; if (0 != strcmp (meth, "GET")) return MHD_NO; if (&dummy != *con_cls) { *con_cls = &dummy; return MHD_YES; } if (0 != *upload_data_size) return MHD_NO; *con_cls = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "url %s\n", url); MHD_get_connection_values (con, MHD_HEADER_KIND, &con_val_iter, host); response = MHD_create_response_from_buffer (strlen (page), (void*)page, MHD_RESPMEM_PERSISTENT); ret = MHD_queue_response (con, MHD_HTTP_OK, response); MHD_destroy_response (response); return ret; } /** * Task run whenever HTTP server operations are pending. * * @param cls unused * @param tc sched context */ static void do_httpd (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Schedule MHD */ static void run_httpd () { fd_set rs; fd_set ws; fd_set es; struct GNUNET_NETWORK_FDSet *wrs; struct GNUNET_NETWORK_FDSet *wws; struct GNUNET_NETWORK_FDSet *wes; int max; int haveto; unsigned MHD_LONG_LONG timeout; struct GNUNET_TIME_Relative tv; FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es); wrs = GNUNET_NETWORK_fdset_create (); wes = GNUNET_NETWORK_fdset_create (); wws = GNUNET_NETWORK_fdset_create (); max = -1; GNUNET_assert (MHD_YES == MHD_get_fdset (httpd, &rs, &ws, &es, &max)); haveto = MHD_get_timeout (httpd, &timeout); if (haveto == MHD_YES) tv.rel_value = (uint64_t) timeout; else tv = GNUNET_TIME_UNIT_FOREVER_REL; GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1); if (httpd_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (httpd_task); httpd_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, tv, wrs, wws, &do_httpd, NULL); GNUNET_NETWORK_fdset_destroy (wrs); GNUNET_NETWORK_fdset_destroy (wws); GNUNET_NETWORK_fdset_destroy (wes); } /** * Task run whenever HTTP server operations are pending. * * @param cls unused * @param tc sched context */ static void do_httpd (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { httpd_task = GNUNET_SCHEDULER_NO_TASK; MHD_run (httpd); run_httpd (); } /** * Read data from socket * * @param cls the closure * @param tc scheduler context */ static void do_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Read from remote end * * @param cls closure * @param tc scheduler context */ static void do_read_remote (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Write data to remote socket * * @param cls the closure * @param tc scheduler context */ static void do_write_remote (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Socks5Request *s5r = cls; unsigned int len; s5r->fwdwtask = GNUNET_SCHEDULER_NO_TASK; if ((NULL != tc->read_ready) && (GNUNET_NETWORK_fdset_isset (tc->write_ready, s5r->remote_sock)) && (len = GNUNET_NETWORK_socket_send (s5r->remote_sock, s5r->rbuf, s5r->rbuf_len))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully sent %d bytes to remote socket\n", len); } else { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write remote"); //Really!?!?!? if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (s5r->rtask); if (s5r->wtask != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (s5r->wtask); if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (s5r->fwdrtask); GNUNET_NETWORK_socket_close (s5r->remote_sock); GNUNET_NETWORK_socket_close (s5r->sock); GNUNET_free(s5r); return; } s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, s5r->sock, &do_read, s5r); } /** * Write data to socket * * @param cls the closure * @param tc scheduler context */ static void do_write (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Socks5Request *s5r = cls; unsigned int len; s5r->wtask = GNUNET_SCHEDULER_NO_TASK; if ((NULL != tc->read_ready) && (GNUNET_NETWORK_fdset_isset (tc->write_ready, s5r->sock)) && (len = GNUNET_NETWORK_socket_send (s5r->sock, s5r->wbuf, s5r->wbuf_len))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully sent %d bytes to socket\n", len); } else { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write"); //Really!?!?!? if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (s5r->rtask); if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (s5r->fwdwtask); if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (s5r->fwdrtask); GNUNET_NETWORK_socket_close (s5r->remote_sock); GNUNET_NETWORK_socket_close (s5r->sock); GNUNET_free(s5r); return; } if ((s5r->state == SOCKS5_DATA_TRANSFER) && (s5r->fwdrtask == GNUNET_SCHEDULER_NO_TASK)) s5r->fwdrtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, s5r->remote_sock, &do_read_remote, s5r); } /** * Read from remote end * * @param cls closure * @param tc scheduler context */ static void do_read_remote (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Socks5Request *s5r = cls; s5r->fwdrtask = GNUNET_SCHEDULER_NO_TASK; if ((NULL != tc->write_ready) && (GNUNET_NETWORK_fdset_isset (tc->read_ready, s5r->remote_sock)) && (s5r->wbuf_len = GNUNET_NETWORK_socket_recv (s5r->remote_sock, s5r->wbuf, sizeof (s5r->wbuf)))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully read %d bytes from remote socket\n", s5r->wbuf_len); } else { if (s5r->wbuf_len == 0) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "0 bytes received from remote... graceful shutdown!\n"); if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (s5r->fwdwtask); if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (s5r->rtask); GNUNET_NETWORK_socket_close (s5r->remote_sock); s5r->remote_sock = NULL; GNUNET_NETWORK_socket_close (s5r->sock); GNUNET_free(s5r); return; } s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, s5r->sock, &do_write, s5r); } static int add_handle_to_mhd (struct GNUNET_NETWORK_Handle *h) { int fd; struct sockaddr *addr; socklen_t len; fd = GNUNET_NETWORK_get_fd (h); addr = GNUNET_NETWORK_get_addr (h); len = GNUNET_NETWORK_get_addrlen (h); return MHD_add_connection (httpd, fd, addr, len); } /** * Read data from incoming connection * * @param cls the closure * @param tc the scheduler context */ static void do_read (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Socks5Request *s5r = cls; struct socks5_client_hello *c_hello; struct socks5_server_hello *s_hello; struct socks5_client_request *c_req; struct socks5_server_response *s_resp; char domain[256]; uint8_t dom_len; uint16_t req_port; struct hostent *phost; uint32_t remote_ip; struct sockaddr_in remote_addr; struct in_addr *r_sin_addr; s5r->rtask = GNUNET_SCHEDULER_NO_TASK; if ((NULL != tc->write_ready) && (GNUNET_NETWORK_fdset_isset (tc->read_ready, s5r->sock)) && (s5r->rbuf_len = GNUNET_NETWORK_socket_recv (s5r->sock, s5r->rbuf, sizeof (s5r->rbuf)))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully read %d bytes from socket\n", s5r->rbuf_len); } else { if (s5r->rbuf_len != 0) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "read"); else GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "client disco!\n"); if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (s5r->fwdrtask); if (s5r->wtask != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (s5r->wtask); if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (s5r->fwdwtask); GNUNET_NETWORK_socket_close (s5r->remote_sock); GNUNET_NETWORK_socket_close (s5r->sock); GNUNET_free(s5r); return; } if (s5r->state == SOCKS5_INIT) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SOCKS5 init\n"); c_hello = (struct socks5_client_hello*)&s5r->rbuf; GNUNET_assert (c_hello->version == SOCKS_VERSION_5); s_hello = (struct socks5_server_hello*)&s5r->wbuf; s5r->wbuf_len = sizeof( struct socks5_server_hello ); s_hello->version = c_hello->version; s_hello->auth_method = SOCKS_AUTH_NONE; /* Write response to client */ s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, s5r->sock, &do_write, s5r); s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, s5r->sock, &do_read, s5r); s5r->state = SOCKS5_REQUEST; return; } if (s5r->state == SOCKS5_REQUEST) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing SOCKS5 request\n"); c_req = (struct socks5_client_request*)&s5r->rbuf; s_resp = (struct socks5_server_response*)&s5r->wbuf; //Only 10byte for ipv4 response! s5r->wbuf_len = 10;//sizeof (struct socks5_server_response); GNUNET_assert (c_req->addr_type == 3); dom_len = *((uint8_t*)(&(c_req->addr_type) + 1)); memset(domain, 0, sizeof(domain)); strncpy(domain, (char*)(&(c_req->addr_type) + 2), dom_len); req_port = *((uint16_t*)(&(c_req->addr_type) + 2 + dom_len)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Requested connection is %s:%d\n", domain, ntohs(req_port)); if (is_tld (domain, GNUNET_GNS_TLD) || is_tld (domain, GNUNET_GNS_TLD_ZKEY)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Requested connection is gnunet tld\n", domain); if (NULL == httpd) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to start HTTP server\n")); s_resp->version = 0x05; s_resp->reply = 0x01; s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, s5r->sock, &do_write, s5r); //ERROR! //TODO! close socket after the write! schedule task //GNUNET_NETWORK_socket_close (s5r->sock); //GNUNET_free(s5r); return; } if (MHD_YES == add_handle_to_mhd ( s5r->sock )) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sucessfully added client to MHD!\n"); s_resp->version = 0x05; s_resp->reply = 0x00; s_resp->reserved = 0x00; s_resp->addr_type = 0x01; s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, s5r->sock, &do_write, s5r); run_httpd (); //GNUNET_free ( s5r ); //FIXME complete socks resp! return; } else { phost = (struct hostent*)gethostbyname (domain); if (phost == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Resolve %s error!\n", domain ); s_resp->version = 0x05; s_resp->reply = 0x01; s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, s5r->sock, &do_write, s5r); //ERROR! //TODO! close socket after the write! schedule task //GNUNET_NETWORK_socket_close (s5r->sock); //GNUNET_free(s5r); return; } s5r->remote_sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); r_sin_addr = (struct in_addr*)(phost->h_addr); remote_ip = r_sin_addr->s_addr; memset(&remote_addr, 0, sizeof(remote_addr)); remote_addr.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN remote_addr.sin_len = sizeof (remote_addr); #endif remote_addr.sin_addr.s_addr = remote_ip; remote_addr.sin_port = req_port; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "target server: %s:%u\n", inet_ntoa(remote_addr.sin_addr), ntohs(req_port)); if ((GNUNET_OK != GNUNET_NETWORK_socket_connect ( s5r->remote_sock, (const struct sockaddr*)&remote_addr, sizeof (remote_addr))) && (errno != EINPROGRESS)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "connect"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "socket request error...\n"); s_resp->version = 0x05; s_resp->reply = 0x01; s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, s5r->sock, &do_write, s5r); //TODO see above return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "new remote connection\n"); s_resp->version = 0x05; s_resp->reply = 0x00; s_resp->reserved = 0x00; s_resp->addr_type = 0x01; s5r->state = SOCKS5_DATA_TRANSFER; s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, s5r->sock, &do_write, s5r); s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, s5r->sock, &do_read, s5r); } return; } if (s5r->state == SOCKS5_DATA_TRANSFER) { if ((s5r->remote_sock == NULL) || (s5r->rbuf_len == 0)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Closing connection to client\n"); if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (s5r->rtask); if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (s5r->fwdwtask); if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (s5r->fwdrtask); if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (s5r->fwdrtask); if (s5r->remote_sock != NULL) GNUNET_NETWORK_socket_close (s5r->remote_sock); GNUNET_NETWORK_socket_close (s5r->sock); GNUNET_free(s5r); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "forwarding %d bytes from client\n", s5r->rbuf_len); s5r->fwdwtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, s5r->remote_sock, &do_write_remote, s5r); if (s5r->fwdrtask == GNUNET_SCHEDULER_NO_TASK) { s5r->fwdrtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, s5r->remote_sock, &do_read_remote, s5r); } } //GNUNET_CONTAINER_DLL_remove (s5conns.head, s5conns.tail, s5r); } /** * Accept new incoming connections * * @param cls the closure * @param tc the scheduler context */ static void do_accept (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_NETWORK_Handle *s; struct Socks5Request *s5r; ltask = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, lsock, &do_accept, NULL); s = GNUNET_NETWORK_socket_accept (lsock, NULL, NULL); if (NULL == s) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO, "accept"); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got an inbound connection, waiting for data\n"); s5r = GNUNET_malloc (sizeof (struct Socks5Request)); s5r->sock = s; s5r->state = SOCKS5_INIT; s5r->wtask = GNUNET_SCHEDULER_NO_TASK; s5r->fwdwtask = GNUNET_SCHEDULER_NO_TASK; s5r->fwdrtask = GNUNET_SCHEDULER_NO_TASK; s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, s5r->sock, &do_read, s5r); //GNUNET_CONTAINER_DLL_insert (s5conns.head, s5conns.tail, s5r); } /** * Main function that will be run * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param cfg configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct sockaddr_in sa; memset (&sa, 0, sizeof (sa)); sa.sin_family = AF_INET; sa.sin_port = htons (port); #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = sizeof (sa); #endif lsock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); if ((NULL == lsock) || (GNUNET_OK != GNUNET_NETWORK_socket_bind (lsock, (const struct sockaddr *) &sa, sizeof (sa)))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to create listen socket bound to `%s'", GNUNET_a2s ((const struct sockaddr *) &sa, sizeof (sa))); if (NULL != lsock) GNUNET_NETWORK_socket_close (lsock); return; } if (GNUNET_OK != GNUNET_NETWORK_socket_listen (lsock, 5)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to listen on socket bound to `%s'", GNUNET_a2s ((const struct sockaddr *) &sa, sizeof (sa))); return; } ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, lsock, &do_accept, NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Proxy listens on port %u\n", port); httpd = MHD_start_daemon (MHD_USE_DEBUG, 4444, NULL, NULL, &create_response, NULL, MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 128, MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16, MHD_OPTION_NOTIFY_COMPLETED, NULL, NULL, MHD_OPTION_END); run_httpd (); } /** * The main function for gnunet-gns-proxy. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { {'p', "port", NULL, gettext_noop ("listen on specified port"), 1, &GNUNET_GETOPT_set_string, &port}, GNUNET_GETOPT_OPTION_END }; int ret; GNUNET_log_setup ("gnunet-gns-proxy", "WARNING", NULL); ret = (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-gns-proxy", _("GNUnet GNS proxy"), options, &run, NULL)) ? 0 : 1; return ret; } gnunet-0.9.3/src/gns/gns.h0000644000175000017500000001014111760502551012261 00000000000000/* This file is part of GNUnet (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "gnunet_gns_service.h" /** * @file gns/gns.h * @brief IPC messages between GNS API and GNS service * @author Martin Schanzenbach */ #ifndef GNS_H #define GNS_H #define GNUNET_GNS_TLD "gnunet" #define GNUNET_GNS_TLD_ZKEY "zkey" #define GNUNET_GNS_DHT_MAX_UPDATE_INTERVAL 3600 #define MAX_DNS_LABEL_LENGTH 63 #define MAX_DNS_NAME_LENGTH 253 GNUNET_NETWORK_STRUCT_BEGIN /** * Message from client to GNS service to lookup records. */ struct GNUNET_GNS_ClientLookupMessage { /** * Header of type GNUNET_MESSAGE_TYPE_GNS_CLIENT_LOOKUP */ struct GNUNET_MessageHeader header; /** * Unique identifier for this request (for key collisions). */ uint32_t id GNUNET_PACKED; /** * Should we look up in the default zone? */ uint32_t use_default_zone GNUNET_PACKED; /** * If use_default_zone is empty this zone is used for lookup */ struct GNUNET_CRYPTO_ShortHashCode zone; /** * the type of record to look up */ enum GNUNET_GNS_RecordType type; /* Followed by the name to look up */ }; /** * Message from GNS service to client: new results. */ struct GNUNET_GNS_ClientLookupResultMessage { /** * Header of type GNUNET_MESSAGE_TYPE_GNS_CLIENT_RESULT */ struct GNUNET_MessageHeader header; /** * Unique identifier for this request (for key collisions). */ uint32_t id GNUNET_PACKED; /** * The number of records contained in response */ uint32_t rd_count; // FIXME: what format has a GNS_Record? /* followed by rd_count GNUNET_NAMESTORE_RecordData structs*/ }; /** * Message from client to GNS service to shorten names. */ struct GNUNET_GNS_ClientShortenMessage { /** * Header of type GNUNET_MESSAGE_TYPE_GNS_CLIENT_SHORTEN */ struct GNUNET_MessageHeader header; /** * Unique identifier for this request */ uint32_t id GNUNET_PACKED; /** * Should we look up in the default zone? */ uint32_t use_default_zone GNUNET_PACKED; /** * If use_default_zone is empty this zone is used for lookup */ struct GNUNET_CRYPTO_ShortHashCode zone; /* Followed by the name to shorten up */ }; /** * Message from GNS service to client: shorten result. */ struct GNUNET_GNS_ClientShortenResultMessage { /** * Header of type GNUNET_MESSAGE_TYPE_GNS_CLIENT_SHORTEN_RESULT */ struct GNUNET_MessageHeader header; /** * Unique identifier for this request (for key collisions). */ uint32_t id GNUNET_PACKED; /* followed by the shortened name or '\0' for no result*/ }; /** * Message from client to GNS service to lookup an authority of a name. */ struct GNUNET_GNS_ClientGetAuthMessage { /** * Header of type GNUNET_MESSAGE_TYPE_GNS_CLIENT_GET_AUTH */ struct GNUNET_MessageHeader header; /** * Unique identifier for this request */ uint32_t id GNUNET_PACKED; /* Followed by the name to get authority for */ }; /** * Message from GNS service to client: authority result. */ struct GNUNET_GNS_ClientGetAuthResultMessage { /** * Header of type GNUNET_MESSAGE_TYPE_GNS_CLIENT_GET_AUTH_RESULT */ struct GNUNET_MessageHeader header; /** * Unique identifier for this request (for key collisions). */ uint32_t id GNUNET_PACKED; /* followed by the authority part of the name or '\0' for no result*/ }; GNUNET_NETWORK_STRUCT_END #endif gnunet-0.9.3/src/gns/Makefile.in0000644000175000017500000014605711762441721013411 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-service-gns$(EXEEXT) $(am__EXEEXT_1) \ $(am__EXEEXT_2) gnunet-gns$(EXEEXT) check_PROGRAMS = test_gns_simple_shorten$(EXEEXT) \ test_gns_simple_get_authority$(EXEEXT) \ test_gns_simple_lookup$(EXEEXT) \ test_gns_simple_delegated_lookup$(EXEEXT) \ test_gns_simple_mx_lookup$(EXEEXT) \ test_gns_simple_zkey_lookup$(EXEEXT) \ test_gns_dht_delegated_lookup$(EXEEXT) \ test_gns_pseu_shorten$(EXEEXT) test_gns_max_queries$(EXEEXT) \ test_gns_dht_threepeer$(EXEEXT) subdir = src/gns DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/gns.conf.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = gns.conf CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \ "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) $(plugin_LTLIBRARIES) am_libgnunet_plugin_block_gns_la_OBJECTS = plugin_block_gns.lo libgnunet_plugin_block_gns_la_OBJECTS = \ $(am_libgnunet_plugin_block_gns_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunet_plugin_block_gns_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) \ $(libgnunet_plugin_block_gns_la_LDFLAGS) $(LDFLAGS) -o $@ am_libgnunetgns_la_OBJECTS = gns_api.lo libgnunetgns_la_OBJECTS = $(am_libgnunetgns_la_OBJECTS) libgnunetgns_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetgns_la_LDFLAGS) $(LDFLAGS) \ -o $@ @HAVE_MHD_TRUE@am__EXEEXT_1 = gnunet-gns-fcfsd$(EXEEXT) @HAVE_MHD_TRUE@am__EXEEXT_2 = gnunet-gns-proxy$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) am_gnunet_gns_OBJECTS = gnunet-gns.$(OBJEXT) gnunet_gns_OBJECTS = $(am_gnunet_gns_OBJECTS) am__DEPENDENCIES_1 = am_gnunet_gns_fcfsd_OBJECTS = gnunet-gns-fcfsd.$(OBJEXT) gnunet_gns_fcfsd_OBJECTS = $(am_gnunet_gns_fcfsd_OBJECTS) am_gnunet_gns_proxy_OBJECTS = gnunet-gns-proxy.$(OBJEXT) gnunet_gns_proxy_OBJECTS = $(am_gnunet_gns_proxy_OBJECTS) am_gnunet_service_gns_OBJECTS = gnunet-service-gns.$(OBJEXT) \ gnunet-service-gns_resolver.$(OBJEXT) \ gnunet-service-gns_interceptor.$(OBJEXT) gnunet_service_gns_OBJECTS = $(am_gnunet_service_gns_OBJECTS) am_test_gns_dht_delegated_lookup_OBJECTS = \ test_gns_dht_delegated_lookup.$(OBJEXT) test_gns_dht_delegated_lookup_OBJECTS = \ $(am_test_gns_dht_delegated_lookup_OBJECTS) am_test_gns_dht_threepeer_OBJECTS = test_gns_dht_threepeer.$(OBJEXT) test_gns_dht_threepeer_OBJECTS = $(am_test_gns_dht_threepeer_OBJECTS) am_test_gns_max_queries_OBJECTS = test_gns_max_queries.$(OBJEXT) test_gns_max_queries_OBJECTS = $(am_test_gns_max_queries_OBJECTS) am_test_gns_pseu_shorten_OBJECTS = test_gns_pseu_shorten.$(OBJEXT) test_gns_pseu_shorten_OBJECTS = $(am_test_gns_pseu_shorten_OBJECTS) am_test_gns_simple_delegated_lookup_OBJECTS = \ test_gns_simple_delegated_lookup.$(OBJEXT) test_gns_simple_delegated_lookup_OBJECTS = \ $(am_test_gns_simple_delegated_lookup_OBJECTS) am_test_gns_simple_get_authority_OBJECTS = \ test_gns_simple_get_authority.$(OBJEXT) test_gns_simple_get_authority_OBJECTS = \ $(am_test_gns_simple_get_authority_OBJECTS) am_test_gns_simple_lookup_OBJECTS = test_gns_simple_lookup.$(OBJEXT) test_gns_simple_lookup_OBJECTS = $(am_test_gns_simple_lookup_OBJECTS) am_test_gns_simple_mx_lookup_OBJECTS = \ test_gns_simple_mx_lookup.$(OBJEXT) test_gns_simple_mx_lookup_OBJECTS = \ $(am_test_gns_simple_mx_lookup_OBJECTS) am_test_gns_simple_shorten_OBJECTS = \ test_gns_simple_shorten.$(OBJEXT) test_gns_simple_shorten_OBJECTS = \ $(am_test_gns_simple_shorten_OBJECTS) am_test_gns_simple_zkey_lookup_OBJECTS = \ test_gns_simple_zkey_lookup.$(OBJEXT) test_gns_simple_zkey_lookup_OBJECTS = \ $(am_test_gns_simple_zkey_lookup_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunet_plugin_block_gns_la_SOURCES) \ $(libgnunetgns_la_SOURCES) $(gnunet_gns_SOURCES) \ $(gnunet_gns_fcfsd_SOURCES) $(gnunet_gns_proxy_SOURCES) \ $(gnunet_service_gns_SOURCES) \ $(test_gns_dht_delegated_lookup_SOURCES) \ $(test_gns_dht_threepeer_SOURCES) \ $(test_gns_max_queries_SOURCES) \ $(test_gns_pseu_shorten_SOURCES) \ $(test_gns_simple_delegated_lookup_SOURCES) \ $(test_gns_simple_get_authority_SOURCES) \ $(test_gns_simple_lookup_SOURCES) \ $(test_gns_simple_mx_lookup_SOURCES) \ $(test_gns_simple_shorten_SOURCES) \ $(test_gns_simple_zkey_lookup_SOURCES) DIST_SOURCES = $(libgnunet_plugin_block_gns_la_SOURCES) \ $(libgnunetgns_la_SOURCES) $(gnunet_gns_SOURCES) \ $(gnunet_gns_fcfsd_SOURCES) $(gnunet_gns_proxy_SOURCES) \ $(gnunet_service_gns_SOURCES) \ $(test_gns_dht_delegated_lookup_SOURCES) \ $(test_gns_dht_threepeer_SOURCES) \ $(test_gns_max_queries_SOURCES) \ $(test_gns_pseu_shorten_SOURCES) \ $(test_gns_simple_delegated_lookup_SOURCES) \ $(test_gns_simple_get_authority_SOURCES) \ $(test_gns_simple_lookup_SOURCES) \ $(test_gns_simple_mx_lookup_SOURCES) \ $(test_gns_simple_shorten_SOURCES) \ $(test_gns_simple_zkey_lookup_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive DATA = $(pkgcfg_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DIST_SUBDIRS = . nss DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @HAVE_GLIBCNSS_TRUE@NSS_SUBDIR = nss SUBDIRS = . $(NSS_SUBDIR) @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 pkgcfgdir = $(pkgdatadir)/config.d/ plugindir = $(libdir)/gnunet pkgcfg_DATA = \ gns.conf lib_LTLIBRARIES = \ libgnunetgns.la @HAVE_MHD_TRUE@DO_FCFSD = gnunet-gns-fcfsd @HAVE_MHD_TRUE@DO_PROXY = gnunet-gns-proxy # test_gns_simple_lookup # test_gns_simple_delegated_lookup # test_gns_dht_delegated_lookup plugin_LTLIBRARIES = \ libgnunet_plugin_block_gns.la test_gns_dht_threepeer_SOURCES = \ test_gns_dht_threepeer.c test_gns_dht_threepeer_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_dht_threepeer_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_lookup_SOURCES = \ test_gns_simple_lookup.c test_gns_simple_lookup_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_lookup_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_delegated_lookup_SOURCES = \ test_gns_simple_delegated_lookup.c test_gns_simple_delegated_lookup_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_delegated_lookup_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_mx_lookup_SOURCES = \ test_gns_simple_mx_lookup.c test_gns_simple_mx_lookup_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_mx_lookup_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_zkey_lookup_SOURCES = \ test_gns_simple_zkey_lookup.c test_gns_simple_zkey_lookup_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_zkey_lookup_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_dht_delegated_lookup_SOURCES = \ test_gns_dht_delegated_lookup.c test_gns_dht_delegated_lookup_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_dht_delegated_lookup_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_shorten_SOURCES = \ test_gns_simple_shorten.c test_gns_simple_shorten_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_shorten_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_get_authority_SOURCES = \ test_gns_simple_get_authority.c test_gns_simple_get_authority_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_simple_get_authority_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_pseu_shorten_SOURCES = \ test_gns_pseu_shorten.c test_gns_pseu_shorten_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_pseu_shorten_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_max_queries_SOURCES = \ test_gns_max_queries.c test_gns_max_queries_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la test_gns_max_queries_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la gnunet_gns_SOURCES = \ gnunet-gns.c gnunet_gns_LDADD = \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(GN_LIBINTL) gnunet_gns_DEPENDENCIES = \ libgnunetgns.la gnunet_gns_proxy_SOURCES = \ gnunet-gns-proxy.c gns_proxy_proto.h gnunet_gns_proxy_LDADD = -lmicrohttpd \ $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_gns_proxy_DEPENDENCIES = \ libgnunetgns.la gnunet_service_gns_SOURCES = \ gnunet-service-gns.c \ gnunet-service-gns_resolver.c gnunet-service-gns_resolver.h \ gnunet-service-gns_interceptor.c gnunet-service-gns_interceptor.h gnunet_service_gns_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/dns/libgnunetdns.la \ $(top_builddir)/src/dns/libgnunetdnsparser.la \ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(GN_LIBINTL) gnunet_service_gns_DEPENDENCIES = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/dns/libgnunetdns.la \ $(top_builddir)/src/dns/libgnunetdnsparser.la \ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la gnunet_gns_fcfsd_SOURCES = \ gnunet-gns-fcfsd.c gnunet_gns_fcfsd_LDADD = -lmicrohttpd \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(GN_LIBINTL) gnunet_gns_fcfsd_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la libgnunetgns_la_SOURCES = \ gns_api.c gns.h libgnunetgns_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la $(XLIB) \ $(top_builddir)/src/namestore/libgnunetnamestore.la libgnunetgns_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) libgnunetgns_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la libgnunet_plugin_block_gns_la_SOURCES = \ plugin_block_gns.c libgnunet_plugin_block_gns_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/block/libgnunetblock.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la libgnunet_plugin_block_gns_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_block_gns_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/block/libgnunetblock.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la #Build stub api #libgnunetnamestore_la_SOURCES = \ # namestore_stub_api.c #libgnunetnamestore_la_LIBADD = \ # $(top_builddir)/src/util/libgnunetutil.la $(XLIB) #libgnunetnamestore_la_LDFLAGS = \ # $(GN_LIB_LDFLAGS) #libgnunetnamestore_la_DEPENDENCIES = \ # $(top_builddir)/src/util/libgnunetutil.la @ENABLE_TEST_RUN_TRUE@@LINUX_TRUE@TESTS = $(check_PROGRAMS) EXTRA_DIST = \ test_gns_defaults.conf \ test_gns_simple_lookup.conf \ test_gns_dht_default.conf all: all-recursive .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/gns/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/gns/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): gns.conf: $(top_builddir)/config.status $(srcdir)/gns.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ } uninstall-pluginLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ done clean-pluginLTLIBRARIES: -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunet_plugin_block_gns.la: $(libgnunet_plugin_block_gns_la_OBJECTS) $(libgnunet_plugin_block_gns_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_block_gns_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_block_gns_la_OBJECTS) $(libgnunet_plugin_block_gns_la_LIBADD) $(LIBS) libgnunetgns.la: $(libgnunetgns_la_OBJECTS) $(libgnunetgns_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetgns_la_LINK) -rpath $(libdir) $(libgnunetgns_la_OBJECTS) $(libgnunetgns_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-gns$(EXEEXT): $(gnunet_gns_OBJECTS) $(gnunet_gns_DEPENDENCIES) @rm -f gnunet-gns$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_gns_OBJECTS) $(gnunet_gns_LDADD) $(LIBS) gnunet-gns-fcfsd$(EXEEXT): $(gnunet_gns_fcfsd_OBJECTS) $(gnunet_gns_fcfsd_DEPENDENCIES) @rm -f gnunet-gns-fcfsd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_gns_fcfsd_OBJECTS) $(gnunet_gns_fcfsd_LDADD) $(LIBS) gnunet-gns-proxy$(EXEEXT): $(gnunet_gns_proxy_OBJECTS) $(gnunet_gns_proxy_DEPENDENCIES) @rm -f gnunet-gns-proxy$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_gns_proxy_OBJECTS) $(gnunet_gns_proxy_LDADD) $(LIBS) gnunet-service-gns$(EXEEXT): $(gnunet_service_gns_OBJECTS) $(gnunet_service_gns_DEPENDENCIES) @rm -f gnunet-service-gns$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_service_gns_OBJECTS) $(gnunet_service_gns_LDADD) $(LIBS) test_gns_dht_delegated_lookup$(EXEEXT): $(test_gns_dht_delegated_lookup_OBJECTS) $(test_gns_dht_delegated_lookup_DEPENDENCIES) @rm -f test_gns_dht_delegated_lookup$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gns_dht_delegated_lookup_OBJECTS) $(test_gns_dht_delegated_lookup_LDADD) $(LIBS) test_gns_dht_threepeer$(EXEEXT): $(test_gns_dht_threepeer_OBJECTS) $(test_gns_dht_threepeer_DEPENDENCIES) @rm -f test_gns_dht_threepeer$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gns_dht_threepeer_OBJECTS) $(test_gns_dht_threepeer_LDADD) $(LIBS) test_gns_max_queries$(EXEEXT): $(test_gns_max_queries_OBJECTS) $(test_gns_max_queries_DEPENDENCIES) @rm -f test_gns_max_queries$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gns_max_queries_OBJECTS) $(test_gns_max_queries_LDADD) $(LIBS) test_gns_pseu_shorten$(EXEEXT): $(test_gns_pseu_shorten_OBJECTS) $(test_gns_pseu_shorten_DEPENDENCIES) @rm -f test_gns_pseu_shorten$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gns_pseu_shorten_OBJECTS) $(test_gns_pseu_shorten_LDADD) $(LIBS) test_gns_simple_delegated_lookup$(EXEEXT): $(test_gns_simple_delegated_lookup_OBJECTS) $(test_gns_simple_delegated_lookup_DEPENDENCIES) @rm -f test_gns_simple_delegated_lookup$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gns_simple_delegated_lookup_OBJECTS) $(test_gns_simple_delegated_lookup_LDADD) $(LIBS) test_gns_simple_get_authority$(EXEEXT): $(test_gns_simple_get_authority_OBJECTS) $(test_gns_simple_get_authority_DEPENDENCIES) @rm -f test_gns_simple_get_authority$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gns_simple_get_authority_OBJECTS) $(test_gns_simple_get_authority_LDADD) $(LIBS) test_gns_simple_lookup$(EXEEXT): $(test_gns_simple_lookup_OBJECTS) $(test_gns_simple_lookup_DEPENDENCIES) @rm -f test_gns_simple_lookup$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gns_simple_lookup_OBJECTS) $(test_gns_simple_lookup_LDADD) $(LIBS) test_gns_simple_mx_lookup$(EXEEXT): $(test_gns_simple_mx_lookup_OBJECTS) $(test_gns_simple_mx_lookup_DEPENDENCIES) @rm -f test_gns_simple_mx_lookup$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gns_simple_mx_lookup_OBJECTS) $(test_gns_simple_mx_lookup_LDADD) $(LIBS) test_gns_simple_shorten$(EXEEXT): $(test_gns_simple_shorten_OBJECTS) $(test_gns_simple_shorten_DEPENDENCIES) @rm -f test_gns_simple_shorten$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gns_simple_shorten_OBJECTS) $(test_gns_simple_shorten_LDADD) $(LIBS) test_gns_simple_zkey_lookup$(EXEEXT): $(test_gns_simple_zkey_lookup_OBJECTS) $(test_gns_simple_zkey_lookup_DEPENDENCIES) @rm -f test_gns_simple_zkey_lookup$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gns_simple_zkey_lookup_OBJECTS) $(test_gns_simple_zkey_lookup_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gns_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-gns-fcfsd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-gns-proxy.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-gns.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-gns.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-gns_interceptor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-gns_resolver.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_block_gns.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gns_dht_delegated_lookup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gns_dht_threepeer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gns_max_queries.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gns_pseu_shorten.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gns_simple_delegated_lookup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gns_simple_get_authority.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gns_simple_lookup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gns_simple_mx_lookup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gns_simple_shorten.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gns_simple_zkey_lookup.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgcfgDATA: $(pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. # To change the values of `make' variables: instead of editing Makefiles, # (1) if the variable is set in `config.status', edit `config.status' # (which will cause the Makefiles to be regenerated when you run `make'); # (2) otherwise, pass the desired values on the `make' command line. $(RECURSIVE_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ list='$(SUBDIRS)'; for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ rev="$$rev ."; \ target=`echo $@ | sed s/-recursive//`; \ for subdir in $$rev; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-recursive all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) install-binPROGRAMS: install-libLTLIBRARIES installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool clean-pluginLTLIBRARIES \ mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-pkgcfgDATA install-pluginLTLIBRARIES install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) check-am \ ctags-recursive install-am install-strip tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am check check-TESTS check-am clean clean-binPROGRAMS \ clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool clean-pluginLTLIBRARIES ctags ctags-recursive \ distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-libLTLIBRARIES \ install-man install-pdf install-pdf-am install-pkgcfgDATA \ install-pluginLTLIBRARIES install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-libLTLIBRARIES uninstall-pkgcfgDATA \ uninstall-pluginLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/gns/gnunet-service-gns_resolver.c0000644000175000017500000024260111760516147017147 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * * * @file gns/gnunet-service-gns_resolver.c * @brief GNUnet GNS resolver logic * @author Martin Schanzenbach */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_transport_service.h" #include "gnunet_dns_service.h" #include "gnunet_dht_service.h" #include "gnunet_namestore_service.h" #include "gnunet_dns_service.h" #include "gnunet_dnsparser_lib.h" #include "gnunet_gns_service.h" #include "block_gns.h" #include "gns.h" #include "gnunet-service-gns_resolver.h" #define DHT_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT #define DHT_GNS_REPLICATION_LEVEL 5 #define MAX_DNS_LABEL_LENGTH 63 /** * Our handle to the namestore service */ static struct GNUNET_NAMESTORE_Handle *namestore_handle; /** * Resolver handle to the dht */ static struct GNUNET_DHT_Handle *dht_handle; /** * Heap for parallel DHT lookups */ static struct GNUNET_CONTAINER_Heap *dht_lookup_heap; /** * Maximum amount of parallel queries in background */ static unsigned long long max_allowed_background_queries; /** * Wheather or not to ignore pending records */ static int ignore_pending_records; /** * Our local zone */ static struct GNUNET_CRYPTO_ShortHashCode local_zone; /** * a resolution identifier pool variable * FIXME overflow? * This is a non critical identifier useful for debugging */ static unsigned long long rid = 0; /** * Namestore calls this function if we have record for this name. * (or with rd_count=0 to indicate no matches) * * @param cls the pending query * @param key the key of the zone we did the lookup * @param expiration expiration date of the namestore entry * @param name the name for which we need an authority * @param rd_count the number of records with 'name' * @param rd the record data * @param signature the signature of the authority for the record data */ static void process_pseu_lookup_ns(void* cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key, struct GNUNET_TIME_Absolute expiration, const char *name, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls; struct GNUNET_NAMESTORE_RecordData new_pkey; if (rd_count > 0) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_AUTO_PSEU: Name %s already taken in NS!\n", name); if (0 == strcmp(gph->name, name)) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_AUTO_PSEU: Intelligent replacement not implemented\n", name); GNUNET_free(gph); return; } GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_AUTO_PSEU: Trying delegated name %s\n", gph->name); memcpy(gph->new_name, gph->name, strlen(gph->name)+1); GNUNET_NAMESTORE_lookup_record(namestore_handle, &gph->zone, gph->new_name, GNUNET_NAMESTORE_TYPE_ANY, &process_pseu_lookup_ns, gph); return; } /** name is free */ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_AUTO_PSEU: Name %s not taken in NS! Adding\n", gph->new_name); new_pkey.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; new_pkey.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode); new_pkey.data = &gph->new_zone; new_pkey.record_type = GNUNET_GNS_RECORD_PKEY; new_pkey.flags = GNUNET_NAMESTORE_RF_AUTHORITY | GNUNET_NAMESTORE_RF_PRIVATE | GNUNET_NAMESTORE_RF_PENDING; GNUNET_NAMESTORE_record_create (namestore_handle, gph->key, gph->new_name, &new_pkey, NULL, //cont NULL); //cls GNUNET_free(gph); } /** * process result of a dht pseu lookup * * @param gph the handle * @param name the pseu result or NULL */ static void process_pseu_result(struct GetPseuAuthorityHandle* gph, char* name) { if (NULL == name) { memcpy(gph->new_name, gph->name, strlen(gph->name)+1); } else { memcpy(gph->new_name, name, strlen(name)+1); } GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_AUTO_PSEU: Checking %s for collision in NS\n", gph->new_name); /** * Check for collision */ GNUNET_NAMESTORE_lookup_record(namestore_handle, &gph->zone, gph->new_name, GNUNET_NAMESTORE_TYPE_ANY, &process_pseu_lookup_ns, gph); } /** * Handle timeout for dht request * * @param cls the request handle as closure * @param tc the task context */ static void handle_auth_discovery_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls; GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: dht lookup for query PSEU timed out.\n"); GNUNET_DHT_get_stop (gph->get_handle); gph->get_handle = NULL; process_pseu_result(gph, NULL); } /** * Function called when we find a PSEU entry in the DHT * * @param cls the request handle * @param exp lifetime * @param key the key the record was stored under * @param get_path get path * @param get_path_length get path length * @param put_path put path * @param put_path_length put path length * @param type the block type * @param size the size of the record * @param data the record data */ static void process_auth_discovery_dht_result(void* cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int put_path_length, enum GNUNET_BLOCK_Type type, size_t size, const void *data) { struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls; struct GNSNameRecordBlock *nrb; char* rd_data = (char*)data; char* name; int num_records; size_t rd_size; int i; GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: got dht result (size=%d)\n", size); if (data == NULL) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "GNS_GET_AUTH: got dht result null!\n", size); GNUNET_break(0); GNUNET_free(gph); return; } nrb = (struct GNSNameRecordBlock*)data; /* stop lookup and timeout task */ GNUNET_DHT_get_stop (gph->get_handle); gph->get_handle = NULL; GNUNET_SCHEDULER_cancel(gph->timeout); gph->get_handle = NULL; nrb = (struct GNSNameRecordBlock*)data; name = (char*)&nrb[1]; num_records = ntohl(nrb->rd_count); { struct GNUNET_NAMESTORE_RecordData rd[num_records]; rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock); rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock); if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size, rd_data, num_records, rd)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "GNS_GET_AUTH: Error deserializing data!\n"); GNUNET_break(0); GNUNET_free(gph); return; } for (i=0; inew_zone, &zone_hash_double); GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key); GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_AUTO_PSEU: starting dht lookup for %s with key: %s\n", "+", (char*)&lookup_key_string); gph->timeout = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT, &handle_auth_discovery_timeout, gph); xquery = htonl(GNUNET_GNS_RECORD_PSEU); GNUNET_assert(gph->get_handle == NULL); gph->get_handle = GNUNET_DHT_get_start(dht_handle, GNUNET_BLOCK_TYPE_GNS_NAMERECORD, &lookup_key, DHT_GNS_REPLICATION_LEVEL, GNUNET_DHT_RO_NONE, &xquery, sizeof(xquery), &process_auth_discovery_dht_result, gph); return; } for (i=0; inew_zone, "+", GNUNET_GNS_RECORD_PSEU, &process_auth_discovery_ns_result, gph); } } /** * Callback for new authories * * @param name the name given by delegation * @param zone the authority * @param our_zone our local zone * @param key the private key of our authority */ static void process_discovered_authority(char* name, struct GNUNET_CRYPTO_ShortHashCode zone, struct GNUNET_CRYPTO_ShortHashCode our_zone, struct GNUNET_CRYPTO_RsaPrivateKey *key) { struct GetPseuAuthorityHandle *gph; size_t namelen; GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_AUTO_PSEU: New authority %s discovered\n", name); gph = GNUNET_malloc(sizeof(struct GetPseuAuthorityHandle)); namelen = strlen(name) + 1; memcpy(gph->name, name, namelen); gph->new_zone = zone; gph->zone = our_zone; gph->key = key; GNUNET_NAMESTORE_zone_to_name (namestore_handle, &our_zone, &gph->new_zone, &process_zone_to_name_discover, gph); } /** * Initialize the resolver * * @param nh the namestore handle * @param dh the dht handle * @param lz the local zone's hash * @param max_bg_queries maximum number of parallel background queries in dht * @param ignore_pending ignore records that still require user confirmation * on lookup * @return GNUNET_OK on success */ int gns_resolver_init(struct GNUNET_NAMESTORE_Handle *nh, struct GNUNET_DHT_Handle *dh, struct GNUNET_CRYPTO_ShortHashCode lz, unsigned long long max_bg_queries, int ignore_pending) { namestore_handle = nh; dht_handle = dh; local_zone = lz; dht_lookup_heap = GNUNET_CONTAINER_heap_create(GNUNET_CONTAINER_HEAP_ORDER_MIN); max_allowed_background_queries = max_bg_queries; ignore_pending_records = ignore_pending; if ((namestore_handle != NULL) && (dht_handle != NULL)) { return GNUNET_OK; } return GNUNET_SYSERR; } /** * Cleanup background lookups * * @param cls closure to iterator * @param node heap nodes * @param element the resolver handle * @param cost heap cost * @return always GNUNET_YES */ static int cleanup_pending_background_queries(void* cls, struct GNUNET_CONTAINER_HeapNode *node, void *element, GNUNET_CONTAINER_HeapCostType cost) { struct ResolverHandle *rh = (struct ResolverHandle *)element; ResolverCleanupContinuation cont = cls; GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_CLEANUP-%llu: Terminating background lookup for %s\n", rh->id, rh->name); GNUNET_DHT_get_stop(rh->get_handle); rh->get_handle = NULL; rh->proc(rh->proc_cls, rh, 0, NULL); GNUNET_CONTAINER_heap_remove_node(node); if (GNUNET_CONTAINER_heap_get_size(dht_lookup_heap) == 0) cont(); return GNUNET_YES; } /** * Shutdown resolver */ void gns_resolver_cleanup(ResolverCleanupContinuation cont) { unsigned int s = GNUNET_CONTAINER_heap_get_size(dht_lookup_heap); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_CLEANUP: %d pending background queries to terminate\n", s); if (0 != s) GNUNET_CONTAINER_heap_iterate (dht_lookup_heap, &cleanup_pending_background_queries, cont); else cont(); } /** * Helper function to free resolver handle * * @param rh the handle to free */ static void free_resolver_handle(struct ResolverHandle* rh) { struct AuthorityChain *ac; struct AuthorityChain *ac_next; if (NULL == rh) return; ac = rh->authority_chain_head; while (NULL != ac) { ac_next = ac->next; GNUNET_free(ac); ac = ac_next; } GNUNET_free(rh); } /** * Callback when record data is put into namestore * * @param cls the closure * @param success GNUNET_OK on success * @param emsg the error message. NULL if SUCCESS==GNUNET_OK */ void on_namestore_record_put_result(void *cls, int32_t success, const char *emsg) { if (GNUNET_NO == success) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_NS: records already in namestore\n"); return; } else if (GNUNET_YES == success) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_NS: records successfully put in namestore\n"); return; } GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "GNS_NS: Error putting records into namestore: %s\n", emsg); } static void handle_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ResolverHandle *rh = cls; if (rh->timeout_cont) rh->timeout_cont(rh->timeout_cont_cls, tc); } /** * Processor for background lookups in the DHT * * @param cls closure (NULL) * @param rd_count number of records found (not 0) * @param rd record data */ static void background_lookup_result_processor(void *cls, uint32_t rd_count, const struct GNUNET_NAMESTORE_RecordData *rd) { //We could do sth verbose/more useful here but it doesn't make any difference GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_BG: background dht lookup for finished. (%d results)\n", rd_count); } /** * Handle timeout for DHT requests * * @param cls the request handle as closure * @param tc the task context */ static void dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ResolverHandle *rh = cls; struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls; char new_name[MAX_DNS_NAME_LENGTH]; GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_REC-%d: dht lookup for query %s (%ds)timed out.\n", rh->id, rh->name, rh->timeout.rel_value); /** * Start resolution in bg */ //strcpy(new_name, rh->name); //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD)); GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s", rh->name, GNUNET_GNS_TLD); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_REC-%d: Starting background lookup for %s type %d\n", rh->id, new_name, rlh->record_type); gns_resolver_lookup_record(rh->authority, rh->private_local_zone, rlh->record_type, new_name, rh->priv_key, GNUNET_TIME_UNIT_FOREVER_REL, &background_lookup_result_processor, NULL); rh->timeout_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_DHT_get_stop (rh->get_handle); rh->get_handle = NULL; rh->proc(rh->proc_cls, rh, 0, NULL); } /** * Function called when we get a result from the dht * for our record query * * @param cls the request handle * @param exp lifetime * @param key the key the record was stored under * @param get_path get path * @param get_path_length get path length * @param put_path put path * @param put_path_length put path length * @param type the block type * @param size the size of the record * @param data the record data */ static void process_record_result_dht(void* cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int put_path_length, enum GNUNET_BLOCK_Type type, size_t size, const void *data) { struct ResolverHandle *rh; struct RecordLookupHandle *rlh; struct GNSNameRecordBlock *nrb; uint32_t num_records; char* name = NULL; char* rd_data = (char*)data; int i; int rd_size; rh = (struct ResolverHandle *)cls; GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_REC-%d: got dht result (size=%d)\n", rh->id, size); if (data == NULL) return; //FIXME maybe check expiration here, check block type rlh = (struct RecordLookupHandle *) rh->proc_cls; nrb = (struct GNSNameRecordBlock*)data; /* stop lookup and timeout task */ GNUNET_DHT_get_stop (rh->get_handle); rh->get_handle = NULL; if (rh->dht_heap_node != NULL) { GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node); rh->dht_heap_node = NULL; } if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel(rh->timeout_task); rh->timeout_task = GNUNET_SCHEDULER_NO_TASK; } rh->get_handle = NULL; name = (char*)&nrb[1]; num_records = ntohl(nrb->rd_count); { struct GNUNET_NAMESTORE_RecordData rd[num_records]; rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock); rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock); if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size, rd_data, num_records, rd)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "GNS_PHASE_REC-%d: Error deserializing data!\n", rh->id); return; } for (i=0; iid, name, rh->name); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_REC-%d: Got type: %d\n", rh->id, rd[i].record_type); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_REC-%d: Got data length: %d\n", rh->id, rd[i].data_size); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_REC-%d: Got flag %d\n", rh->id, rd[i].flags); if ((strcmp(name, rh->name) == 0) && (rd[i].record_type == rlh->record_type)) { rh->answered++; } } /** * FIXME check pubkey against existing key in namestore? * https://gnunet.org/bugs/view.php?id=2179 */ /* Save to namestore */ GNUNET_NAMESTORE_record_put (namestore_handle, &nrb->public_key, name, exp, num_records, rd, &nrb->signature, &on_namestore_record_put_result, //cont NULL); //cls if (rh->answered) rh->proc(rh->proc_cls, rh, num_records, rd); else rh->proc(rh->proc_cls, rh, 0, NULL); } } /** * Start DHT lookup for a (name -> query->record_type) record in * rh->authority's zone * * @param rh the pending gns query context */ static void resolve_record_dht(struct ResolverHandle *rh) { uint32_t xquery; struct GNUNET_CRYPTO_ShortHashCode name_hash; GNUNET_HashCode lookup_key; GNUNET_HashCode name_hash_double; GNUNET_HashCode zone_hash_double; struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string; struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls; struct ResolverHandle *rh_heap_root; GNUNET_CRYPTO_short_hash(rh->name, strlen(rh->name), &name_hash); GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double); GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double); GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key); GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_REC-%d: starting dht lookup for %s with key: %s\n", rh->id, rh->name, (char*)&lookup_key_string); //rh->timeout_task = GNUNET_SCHEDULER_NO_TASK; rh->dht_heap_node = NULL; if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value) { /** * Update timeout if necessary */ if (rh->timeout_task == GNUNET_SCHEDULER_NO_TASK) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_REC-%d: Adjusting timeout\n", rh->id); /* * Set timeout for authority lookup phase to 1/2 */ rh->timeout_task = GNUNET_SCHEDULER_add_delayed( GNUNET_TIME_relative_divide(rh->timeout, 2), &handle_lookup_timeout, rh); } //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT, // &dht_lookup_timeout, // rh); rh->timeout_cont = &dht_lookup_timeout; rh->timeout_cont_cls = rh; } else { if (max_allowed_background_queries <= GNUNET_CONTAINER_heap_get_size (dht_lookup_heap)) { rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap); GNUNET_DHT_get_stop(rh_heap_root->get_handle); rh_heap_root->get_handle = NULL; rh_heap_root->dht_heap_node = NULL; GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_REC-%d: Replacing oldest background query for %s\n", rh->id, rh_heap_root->name); rh_heap_root->proc(rh_heap_root->proc_cls, rh_heap_root, 0, NULL); } rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap, rh, GNUNET_TIME_absolute_get().abs_value); } xquery = htonl(rlh->record_type); GNUNET_assert(rh->get_handle == NULL); rh->get_handle = GNUNET_DHT_get_start(dht_handle, GNUNET_BLOCK_TYPE_GNS_NAMERECORD, &lookup_key, DHT_GNS_REPLICATION_LEVEL, GNUNET_DHT_RO_NONE, &xquery, sizeof(xquery), &process_record_result_dht, rh); } /** * Namestore calls this function if we have record for this name. * (or with rd_count=0 to indicate no matches) * * @param cls the pending query * @param key the key of the zone we did the lookup * @param expiration expiration date of the namestore entry * @param name the name for which we need an authority * @param rd_count the number of records with 'name' * @param rd the record data * @param signature the signature of the authority for the record data */ static void process_record_result_ns(void* cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key, struct GNUNET_TIME_Absolute expiration, const char *name, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { struct ResolverHandle *rh; struct RecordLookupHandle *rlh; struct GNUNET_TIME_Relative remaining_time; struct GNUNET_CRYPTO_ShortHashCode zone; rh = (struct ResolverHandle *) cls; rlh = (struct RecordLookupHandle *)rh->proc_cls; GNUNET_CRYPTO_short_hash(key, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &zone); remaining_time = GNUNET_TIME_absolute_get_remaining (expiration); rh->status = 0; if (name != NULL) { rh->status |= RSL_RECORD_EXISTS; } if (remaining_time.rel_value == 0) { rh->status |= RSL_RECORD_EXPIRED; } if (rd_count == 0) { /** * Lookup terminated and no results */ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_REC-%d: Namestore lookup for %s terminated without results\n", rh->id, name); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_REC-%d: Record %s unknown in namestore\n", rh->id, rh->name); /** * Our zone and no result? Cannot resolve TT */ rh->proc(rh->proc_cls, rh, 0, NULL); return; } else { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_REC-%d: Processing additional result %s from namestore\n", rh->id, name); int i; for (i=0; irecord_type) continue; if (ignore_pending_records && (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING)) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_REC-%d: Record %s is awaiting user confirmation. Skipping\n", rh->id, name); continue; } if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value == 0) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_REC-%d: This record is expired. Skipping\n", rh->id); continue; } rh->answered++; } /** * no answers found */ if (rh->answered == 0) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_REC-%d: No answers found. This is odd!\n", rh->id); rh->proc(rh->proc_cls, rh, 0, NULL); return; } GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_REC-%d: Found %d answer(s) to query in %d records!\n", rh->id, rh->answered, rd_count); rh->proc(rh->proc_cls, rh, rd_count, rd); } } /** * The final phase of resolution. * rh->name is a name that is canonical and we do not have a delegation. * Query namestore for this record * * @param rh the pending lookup */ static void resolve_record_ns(struct ResolverHandle *rh) { struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls; /* We cancel here as to not include the ns lookup in the timeout */ if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel(rh->timeout_task); rh->timeout_task = GNUNET_SCHEDULER_NO_TASK; } /** * Try to resolve this record in our namestore. * The name to resolve is now in rh->authority_name * since we tried to resolve it to an authority * and failed. **/ GNUNET_NAMESTORE_lookup_record(namestore_handle, &rh->authority, rh->name, rlh->record_type, &process_record_result_ns, rh); } /** * Handle timeout for DHT requests * * @param cls the request handle as closure * @param tc the task context */ static void dht_authority_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ResolverHandle *rh = cls; struct RecordLookupHandle *rlh = rh->proc_cls; char new_name[MAX_DNS_NAME_LENGTH]; GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_DHT-%llu: dht lookup for query %s (%ds)timed out.\n", rh->id, rh->authority_name, rh->timeout.rel_value); rh->status |= RSL_TIMED_OUT; rh->timeout_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_DHT_get_stop (rh->get_handle); rh->get_handle = NULL; if (strcmp(rh->name, "") == 0) { /* * promote authority back to name and try to resolve record */ strcpy(rh->name, rh->authority_name); rh->proc(rh->proc_cls, rh, 0, NULL); return; } /** * Start resolution in bg */ GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s.%s", rh->name, rh->authority_name, GNUNET_GNS_TLD); //strcpy(new_name, rh->name); //strcpy(new_name+strlen(new_name), "."); //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD)); strcpy(rh->name, new_name); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_DHT-%llu: Starting background query for %s type %d\n", rh->id, rh->name, rlh->record_type); gns_resolver_lookup_record(rh->authority, rh->private_local_zone, rlh->record_type, new_name, rh->priv_key, GNUNET_TIME_UNIT_FOREVER_REL, &background_lookup_result_processor, NULL); rh->proc(rh->proc_cls, rh, 0, NULL); } /* Prototype */ static void resolve_delegation_dht(struct ResolverHandle *rh); /* Prototype */ static void resolve_delegation_ns(struct ResolverHandle *rh); /** * Namestore resolution for delegation finished. Processing result. * * @param cls the closure * @param rh resolver handle * @param rd_count number of results (always 0) * @param rd record data (always NULL) */ static void handle_delegation_ns(void* cls, struct ResolverHandle *rh, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd); /** * Function called when we get a result from the dht * for our query. Recursively tries to resolve authorities * for name in DHT. * * @param cls the request handle * @param exp lifetime * @param key the key the record was stored under * @param get_path get path * @param get_path_length get path length * @param put_path put path * @param put_path_length put path length * @param type the block type * @param size the size of the record * @param data the record data */ static void process_delegation_result_dht(void* cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int put_path_length, enum GNUNET_BLOCK_Type type, size_t size, const void *data) { struct ResolverHandle *rh; struct GNSNameRecordBlock *nrb; uint32_t num_records; char* name = NULL; char* rd_data = (char*) data; int i; int rd_size; struct GNUNET_CRYPTO_ShortHashCode zone, name_hash; GNUNET_HashCode zone_hash_double, name_hash_double; rh = (struct ResolverHandle *)cls; GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_DHT-%llu: Got DHT result\n", rh->id); if (data == NULL) return; nrb = (struct GNSNameRecordBlock*)data; /* stop dht lookup and timeout task */ GNUNET_DHT_get_stop (rh->get_handle); rh->get_handle = NULL; if (rh->dht_heap_node != NULL) { GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node); rh->dht_heap_node = NULL; } num_records = ntohl(nrb->rd_count); name = (char*)&nrb[1]; { struct GNUNET_NAMESTORE_RecordData rd[num_records]; rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock); rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock); if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size, rd_data, num_records, rd)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "GNS_PHASE_DELEGATE_DHT-%llu: Error deserializing data!\n", rh->id); return; } GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n", rh->id, name, rh->authority_name); for (i=0; iid, name, rh->authority_name); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_DHT-%llu: Got type: %d (wanted %d)\n", rh->id, rd[i].record_type, GNUNET_GNS_RECORD_PKEY); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_DHT-%llu: Got data length: %d\n", rh->id, rd[i].data_size); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_DHT-%llu: Got flag %d\n", rh->id, rd[i].flags); if ((strcmp(name, rh->authority_name) == 0) && (rd[i].record_type == GNUNET_GNS_RECORD_PKEY)) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_DHT-%llu: Authority found in DHT\n", rh->id); rh->answered = 1; memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode)); struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain)); auth->zone = rh->authority; memset(auth->name, 0, strlen(rh->authority_name)+1); strcpy(auth->name, rh->authority_name); GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head, rh->authority_chain_tail, auth); /** try to import pkey if private key available */ if (rh->priv_key) process_discovered_authority(name, auth->zone, rh->authority_chain_tail->zone, rh->priv_key); } } GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash); GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double); GNUNET_CRYPTO_hash_xor(key, &name_hash_double, &zone_hash_double); GNUNET_CRYPTO_short_hash_from_truncation (&zone_hash_double, &zone); /* Save to namestore */ if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_tail->zone, &zone)) { GNUNET_NAMESTORE_record_put (namestore_handle, &nrb->public_key, name, exp, num_records, rd, &nrb->signature, &on_namestore_record_put_result, //cont NULL); //cls } } if (rh->answered) { rh->answered = 0; /** * delegate * FIXME in this case. should we ask namestore again? */ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_DHT-%llu: Answer from DHT for %s. Yet to resolve: %s\n", rh->id, rh->authority_name, rh->name); if (strcmp(rh->name, "") == 0) { rh->proc(rh->proc_cls, rh, 0, NULL); } else { rh->proc = &handle_delegation_ns; resolve_delegation_ns(rh); } return; } /** * No pkey but name exists * promote back */ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_DHT-%llu: Adding %s back to %s\n", rh->id, rh->authority_name, rh->name); if (strcmp(rh->name, "") == 0) strcpy(rh->name, rh->authority_name); else GNUNET_snprintf(rh->name, MAX_DNS_NAME_LENGTH, "%s.%s", rh->name, rh->authority_name); //FIXME ret GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_DHT-%llu: %s restored\n", rh->id, rh->name); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_DHT-%llu: DHT authority lookup found no match!\n", rh->id); rh->proc(rh->proc_cls, rh, 0, NULL); } #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\ +(MAX_DNS_NAME_LENGTH*2) #define MAX_MX_LENGTH sizeof(uint16_t)+MAX_DNS_NAME_LENGTH static void expand_plus(char** dest, char* src, char* repl) { char* pos; unsigned int s_len = strlen(src)+1; GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_POSTPROCESS: Got %s to expand with %s\n", src, repl); if (s_len < 3) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_POSTPROCESS: %s to short\n", src); /* no postprocessing */ memcpy(*dest, src, s_len+1); return; } if (0 == strcmp(src+s_len-3, ".+")) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_POSTPROCESS: Expanding .+ in %s\n", src); memset(*dest, 0, s_len+strlen(repl)+strlen(GNUNET_GNS_TLD)); strcpy(*dest, src); pos = *dest+s_len-2; strcpy(pos, repl); pos += strlen(repl); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_POSTPROCESS: Expanded to %s\n", *dest); } else { memcpy(*dest, src, s_len+1); } } /** * finish lookup */ static void finish_lookup(struct ResolverHandle *rh, struct RecordLookupHandle* rlh, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd) { int i; char new_rr_data[MAX_DNS_NAME_LENGTH]; char new_mx_data[MAX_MX_LENGTH]; char new_soa_data[MAX_SOA_LENGTH]; struct GNUNET_NAMESTORE_RecordData p_rd[rd_count]; char* repl_string; char* pos; unsigned int offset; if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel(rh->timeout_task); rh->timeout_task = GNUNET_SCHEDULER_NO_TASK; } if (rd_count > 0) memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData)); for (i = 0; i < rd_count; i++) { if (rd[i].record_type != GNUNET_GNS_RECORD_TYPE_NS && rd[i].record_type != GNUNET_GNS_RECORD_TYPE_CNAME && rd[i].record_type != GNUNET_GNS_RECORD_MX && rd[i].record_type != GNUNET_GNS_RECORD_TYPE_SOA) { p_rd[i].data = rd[i].data; continue; } /** * for all those records we 'should' * also try to resolve the A/AAAA records (RFC1035) * This is a feature and not important */ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_POSTPROCESS: Postprocessing\n"); if (strcmp(rh->name, "+") == 0) repl_string = rlh->name; else repl_string = rlh->name+strlen(rh->name)+1; offset = 0; if (rd[i].record_type == GNUNET_GNS_RECORD_MX) { memcpy(new_mx_data, (char*)rd[i].data, sizeof(uint16_t)); offset = sizeof(uint16_t); pos = new_mx_data+offset; expand_plus(&pos, (char*)rd[i].data+sizeof(uint16_t), repl_string); offset += strlen(new_mx_data+sizeof(uint16_t))+1; p_rd[i].data = new_mx_data; p_rd[i].data_size = offset; } else if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_SOA) { /* expand mname and rname */ pos = new_soa_data; expand_plus(&pos, (char*)rd[i].data, repl_string); offset = strlen(new_soa_data)+1; pos = new_soa_data+offset; expand_plus(&pos, (char*)rd[i].data+offset, repl_string); offset += strlen(new_soa_data+offset)+1; /* cpy the 4 numbers serial refresh retry and expire */ memcpy(new_soa_data+offset, (char*)rd[i].data+offset, sizeof(uint32_t)*5); offset += sizeof(uint32_t)*5; p_rd[i].data_size = offset; p_rd[i].data = new_soa_data; } else { pos = new_rr_data; expand_plus(&pos, (char*)rd[i].data, repl_string); p_rd[i].data_size = strlen(new_rr_data)+1; p_rd[i].data = new_rr_data; } } rlh->proc(rlh->proc_cls, rd_count, p_rd); GNUNET_free(rlh); } /** * Process DHT lookup result for record. * * @param cls the closure * @param rh resolver handle * @param rd_count number of results * @param rd record data */ static void handle_record_dht(void* cls, struct ResolverHandle *rh, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd) { struct RecordLookupHandle* rlh; rlh = (struct RecordLookupHandle*)cls; if (rd_count == 0) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_REC-%d: No records for %s found in DHT. Aborting\n", rh->id, rh->name); /* give up, cannot resolve */ finish_lookup(rh, rlh, 0, NULL); free_resolver_handle(rh); return; } /* results found yay */ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_REC-%d: Record resolved from DHT!", rh->id); finish_lookup(rh, rlh, rd_count, rd); free_resolver_handle(rh); } /** * Process namestore lookup result for record. * * @param cls the closure * @param rh resolver handle * @param rd_count number of results * @param rd record data */ static void handle_record_ns(void* cls, struct ResolverHandle *rh, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd) { struct RecordLookupHandle* rlh; rlh = (struct RecordLookupHandle*) cls; if (rd_count == 0) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_REC-%d: NS returned no records. (status: %d)!\n", rh->id, rh->status); /** * There are 4 conditions that have to met for us to consult the DHT: * 1. The entry in the DHT is RSL_RECORD_EXPIRED AND * 2. No entry in the NS existed AND * 3. The zone queried is not the local resolver's zone AND * 4. The name that was looked up is '+' * because if it was any other canonical name we either already queried * the DHT for the authority in the authority lookup phase (and thus * would already have an entry in the NS for the record) */ if (rh->status & (RSL_RECORD_EXPIRED | !RSL_RECORD_EXISTS) && GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone, &rh->private_local_zone) && (strcmp(rh->name, "+") == 0)) { rh->proc = &handle_record_dht; resolve_record_dht(rh); return; } /* give up, cannot resolve */ finish_lookup(rh, rlh, 0, NULL); free_resolver_handle(rh); return; } /* results found yay */ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_REC-%d: Record resolved from namestore!", rh->id); finish_lookup(rh, rlh, rd_count, rd); free_resolver_handle(rh); } /** * Determine if this name is canonical. * i.e. * a.b.gnunet = not canonical * a = canonical * * @param name the name to test * @return 1 if canonical */ static int is_canonical(char* name) { uint32_t len = strlen(name); int i; for (i=0; i 0; len--) { if (*(name+len) == '.') break; } //Was canonical? if (len == 0) return; name[len] = '\0'; strcpy(dest, (name+len+1)); } /** * Checks if name is in tld * * @param name the name to check * @param tld the TLD to check for * @return GNUNET_YES or GNUNET_NO */ int is_tld(const char* name, const char* tld) { int offset = 0; if (strlen(name) <= strlen(tld)) { return GNUNET_NO; } offset = strlen(name)-strlen(tld); if (strcmp(name+offset, tld) != 0) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "%s is not in .%s TLD\n", name, tld); return GNUNET_NO; } return GNUNET_YES; } /** * DHT resolution for delegation finished. Processing result. * * @param cls the closure * @param rh resolver handle * @param rd_count number of results (always 0) * @param rd record data (always NULL) */ static void handle_delegation_dht(void* cls, struct ResolverHandle *rh, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd) { struct RecordLookupHandle* rlh; rlh = (struct RecordLookupHandle*) cls; if (strcmp(rh->name, "") == 0) { if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY)) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_DHT-%llu: Resolved queried PKEY via DHT.\n", rh->id); finish_lookup(rh, rlh, rd_count, rd); free_resolver_handle(rh); return; } /* We resolved full name for delegation. resolving record */ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_DHT-%llu: Resolved full name for delegation via DHT.\n", rh->id); strcpy(rh->name, "+\0"); rh->proc = &handle_record_ns; resolve_record_ns(rh); return; } /** * we still have some left **/ if (is_canonical(rh->name)) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_DHT-%llu: Resolving canonical record %s in ns\n", rh->id, rh->name); rh->proc = &handle_record_ns; resolve_record_ns(rh); return; } /* give up, cannot resolve */ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_DHT-%llu: Cannot fully resolve delegation for %s via DHT!\n", rh->id, rh->name); finish_lookup(rh, rlh, 0, NULL); free_resolver_handle(rh); } /** * Start DHT lookup for a name -> PKEY (compare NS) record in * rh->authority's zone * * @param rh the pending gns query */ static void resolve_delegation_dht(struct ResolverHandle *rh) { uint32_t xquery; struct GNUNET_CRYPTO_ShortHashCode name_hash; GNUNET_HashCode name_hash_double; GNUNET_HashCode zone_hash_double; GNUNET_HashCode lookup_key; struct ResolverHandle *rh_heap_root; pop_tld(rh->name, rh->authority_name); GNUNET_CRYPTO_short_hash(rh->authority_name, strlen(rh->authority_name), &name_hash); GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double); GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double); GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key); rh->dht_heap_node = NULL; if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value) { //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT, // &dht_authority_lookup_timeout, // rh); rh->timeout_cont = &dht_authority_lookup_timeout; rh->timeout_cont_cls = rh; } else { if (max_allowed_background_queries <= GNUNET_CONTAINER_heap_get_size (dht_lookup_heap)) { /* terminate oldest lookup */ rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap); GNUNET_DHT_get_stop(rh_heap_root->get_handle); rh_heap_root->dht_heap_node = NULL; GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_DHT-%llu: Replacing oldest background query for %s\n", rh->id, rh_heap_root->authority_name); rh_heap_root->proc(rh_heap_root->proc_cls, rh_heap_root, 0, NULL); } rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap, rh, GNUNET_TIME_absolute_get().abs_value); } xquery = htonl(GNUNET_GNS_RECORD_PKEY); GNUNET_assert(rh->get_handle == NULL); rh->get_handle = GNUNET_DHT_get_start(dht_handle, GNUNET_BLOCK_TYPE_GNS_NAMERECORD, &lookup_key, DHT_GNS_REPLICATION_LEVEL, GNUNET_DHT_RO_NONE, &xquery, sizeof(xquery), &process_delegation_result_dht, rh); } /** * Namestore resolution for delegation finished. Processing result. * * @param cls the closure * @param rh resolver handle * @param rd_count number of results (always 0) * @param rd record data (always NULL) */ static void handle_delegation_ns(void* cls, struct ResolverHandle *rh, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd) { struct RecordLookupHandle* rlh; rlh = (struct RecordLookupHandle*) cls; GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_NS-%llu: Resolution status: %d.\n", rh->id, rh->status); if (strcmp(rh->name, "") == 0) { if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY)) { GNUNET_assert(rd_count == 1); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried PKEY in NS.\n", rh->id); finish_lookup(rh, rlh, rd_count, rd); free_resolver_handle(rh); return; } /* We resolved full name for delegation. resolving record */ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_NS-%llu: Resolved full name for delegation.\n", rh->id); strcpy(rh->name, "+\0"); rh->proc = &handle_record_ns; resolve_record_ns(rh); return; } /** * we still have some left * check if authority in ns is fresh * and exists * or we are authority **/ if (((rh->status & RSL_RECORD_EXISTS) && (!(rh->status & RSL_RECORD_EXPIRED))) || !GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone, &rh->private_local_zone)) { if (is_canonical(rh->name)) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_NS-%llu: Resolving canonical record %s\n", rh->id, rh->name); rh->proc = &handle_record_ns; resolve_record_ns(rh); } else { /* give up, cannot resolve */ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_NS-%llu: Cannot fully resolve delegation for %s!\n", rh->id, rh->name); finish_lookup(rh, rlh, rd_count, rd); //rlh->proc(rlh->proc_cls, 0, NULL); } return; } GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_NS-%llu: Trying to resolve delegation for %s via DHT\n", rh->id, rh->name); rh->proc = &handle_delegation_dht; resolve_delegation_dht(rh); } /** * This is a callback function that should give us only PKEY * records. Used to query the namestore for the authority (PKEY) * for 'name'. It will recursively try to resolve the * authority for a given name from the namestore. * * @param cls the pending query * @param key the key of the zone we did the lookup * @param expiration expiration date of the record data set in the namestore * @param name the name for which we need an authority * @param rd_count the number of records with 'name' * @param rd the record data * @param signature the signature of the authority for the record data */ static void process_delegation_result_ns(void* cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key, struct GNUNET_TIME_Absolute expiration, const char *name, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { struct ResolverHandle *rh; struct GNUNET_TIME_Relative remaining_time; struct GNUNET_CRYPTO_ShortHashCode zone; char new_name[MAX_DNS_NAME_LENGTH]; rh = (struct ResolverHandle *)cls; GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_NS-%llu: Got %d records from authority lookup\n", rh->id, rd_count); GNUNET_CRYPTO_short_hash(key, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &zone); remaining_time = GNUNET_TIME_absolute_get_remaining (expiration); rh->status = 0; if (name != NULL) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_NS-%llu: Records with name %s exist.\n", rh->id, name); rh->status |= RSL_RECORD_EXISTS; } if (remaining_time.rel_value == 0) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_NS-%llu: Record set %s expired.\n", rh->id, name); rh->status |= RSL_RECORD_EXPIRED; } /** * No authority found in namestore. */ if (rd_count == 0) { /** * We did not find an authority in the namestore */ /** * No PKEY in zone. * Promote this authority back to a name maybe it is * our record. */ if (strcmp(rh->name, "") == 0) { /* simply promote back */ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n", rh->id, rh->authority_name); strcpy(rh->name, rh->authority_name); } else { /* add back to existing name */ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_NS-%llu: Adding %s back to %s\n", rh->id, rh->authority_name, rh->name); //memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2); GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s", rh->name, rh->authority_name); //strcpy(new_name, rh->name); //strcpy(new_name+strlen(new_name), "."); //strcpy(new_name+strlen(new_name), rh->authority_name); strcpy(rh->name, new_name); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_NS-%llu: %s restored\n", rh->id, rh->name); } rh->proc(rh->proc_cls, rh, 0, NULL); return; } /** * We found an authority that may be able to help us * move on with query * Note only 1 pkey should have been returned.. anything else would be strange */ int i; for (i=0; iid); continue; } if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value == 0) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_NS-%llu: This pkey is expired.\n", rh->id); if (remaining_time.rel_value == 0) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_NS-%llu: This dht entry is expired.\n", rh->id); rh->authority_chain_head->fresh = 0; rh->proc(rh->proc_cls, rh, 0, NULL); return; } continue; } /** * Resolve rest of query with new authority */ GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY); memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode)); struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain)); auth->zone = rh->authority; memset(auth->name, 0, strlen(rh->authority_name)+1); strcpy(auth->name, rh->authority_name); GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head, rh->authority_chain_tail, auth); /** try to import pkey if private key available * TODO: Only import last one? */ if (rh->priv_key && (name != NULL)) process_discovered_authority((char*)name, auth->zone, rh->authority_chain_tail->zone, rh->priv_key); /** * We are done with PKEY resolution if name is empty * else resolve again with new authority */ if (strcmp(rh->name, "") == 0) rh->proc(rh->proc_cls, rh, rd_count, rd); else resolve_delegation_ns(rh); return; } /** * no answers found */ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_NS-%llu: Authority lookup and no PKEY...\n", rh->id); /** * If we have found some records for the LAST label * we return the results. Else null. */ if (strcmp(rh->name, "") == 0) { /* simply promote back */ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n", rh->id, rh->authority_name); strcpy(rh->name, rh->authority_name); rh->proc(rh->proc_cls, rh, rd_count, rd); } else { rh->proc(rh->proc_cls, rh, 0, NULL); } } /** * Resolve the delegation chain for the request in our namestore * * @param rh the resolver handle */ static void resolve_delegation_ns(struct ResolverHandle *rh) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE_NS-%llu: Resolving delegation for %s\n", rh->id, rh->name); pop_tld(rh->name, rh->authority_name); GNUNET_NAMESTORE_lookup_record(namestore_handle, &rh->authority, rh->authority_name, GNUNET_GNS_RECORD_ANY, &process_delegation_result_ns, rh); } /** * Lookup of a record in a specific zone * calls lookup result processor on result * * @param zone the root zone * @param pzone the private local zone * @param record_type the record type to look up * @param name the name to look up * @param key a private key for use with PSEU import (can be NULL) * @param timeout timeout for resolution * @param proc the processor to call on result * @param cls the closure to pass to proc */ void gns_resolver_lookup_record(struct GNUNET_CRYPTO_ShortHashCode zone, struct GNUNET_CRYPTO_ShortHashCode pzone, uint32_t record_type, const char* name, struct GNUNET_CRYPTO_RsaPrivateKey *key, struct GNUNET_TIME_Relative timeout, RecordLookupProcessor proc, void* cls) { struct ResolverHandle *rh; struct RecordLookupHandle* rlh; char string_hash[MAX_DNS_LABEL_LENGTH]; char nzkey[MAX_DNS_LABEL_LENGTH]; char* nzkey_ptr = nzkey; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting resolution for %s (type=%d)!\n", name, record_type); if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s is canonical and not gnunet -> cannot resolve!\n", name); proc(cls, 0, NULL); return; } rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle)); rh = GNUNET_malloc(sizeof (struct ResolverHandle)); rh->authority = zone; rh->id = rid++; rh->proc_cls = rlh; rh->priv_key = key; rh->timeout = timeout; rh->get_handle = NULL; rh->private_local_zone = pzone; if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value) { /* * Set timeout for authority lookup phase to 1/2 */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Timeout for lookup set to %ds\n", rh->timeout.rel_value); rh->timeout_task = GNUNET_SCHEDULER_add_delayed( GNUNET_TIME_relative_divide(timeout, 2), &handle_lookup_timeout, rh); rh->timeout_cont = &dht_authority_lookup_timeout; rh->timeout_cont_cls = rh; } else { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n"); rh->timeout_task = GNUNET_SCHEDULER_NO_TASK; } if (strcmp(GNUNET_GNS_TLD, name) == 0) { /** * Only 'gnunet' given */ strcpy(rh->name, "\0"); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking for TLD...\n"); if (is_zkey_tld(name) == GNUNET_YES) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TLD is zkey\n"); /** * This is a zkey tld * build hash and use as initial authority */ memset(rh->name, 0, strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY)); memcpy(rh->name, name, strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1); pop_tld(rh->name, string_hash); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ZKEY is %s!\n", string_hash); GNUNET_STRINGS_utf8_toupper(string_hash, &nzkey_ptr); if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey, &rh->authority)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot convert ZKEY %s to hash!\n", string_hash); GNUNET_free(rh); GNUNET_free(rlh); proc(cls, 0, NULL); return; } } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TLD is gnunet\n"); /** * Presumably GNUNET tld */ memset(rh->name, 0, strlen(name)-strlen(GNUNET_GNS_TLD)); memcpy(rh->name, name, strlen(name)-strlen(GNUNET_GNS_TLD) - 1); } } /** * Initialize authority chain */ rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain)); rh->authority_chain_head->prev = NULL; rh->authority_chain_head->next = NULL; rh->authority_chain_tail = rh->authority_chain_head; rh->authority_chain_head->zone = rh->authority; /** * Copy original query into lookup handle */ rlh->record_type = record_type; memset(rlh->name, 0, strlen(name) + 1); strcpy(rlh->name, name); rlh->proc = proc; rlh->proc_cls = cls; rh->proc = &handle_delegation_ns; resolve_delegation_ns(rh); } /******** END Record Resolver ***********/ /** * Callback calles by namestore for a zone to name * result * * @param cls the closure * @param zone_key the zone we queried * @param expire the expiration time of the name * @param name the name found or NULL * @param rd_len number of records for the name * @param rd the record data (PKEY) for the name * @param signature the signature for the record data */ static void process_zone_to_name_shorten(void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *name, unsigned int rd_len, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { struct ResolverHandle *rh = (struct ResolverHandle *)cls; struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls; struct AuthorityChain *next_authority; char result[MAX_DNS_NAME_LENGTH]; char tmp_name[MAX_DNS_NAME_LENGTH]; size_t answer_len; /* we found a match in our own zone */ if (rd_len != 0) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "result strlen %d\n", strlen(name)); answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3; memset(result, 0, answer_len); if (strlen(rh->name) > 0) { strcpy(result, rh->name); strcpy(result+strlen(rh->name), "."); } strcpy(result+strlen(result), name); strcpy(result+strlen(result), "."); strcpy(result+strlen(result), GNUNET_GNS_TLD); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Sending shorten result %s\n", result); nsh->proc(nsh->proc_cls, result); GNUNET_free(nsh); free_resolver_handle(rh); } else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone, &rh->private_local_zone) == 0) { /* our zone, just append .gnunet */ answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2; memset(result, 0, answer_len); strcpy(result, rh->name); strcpy(result+strlen(rh->name), "."); strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Our zone: Sending name as shorten result %s\n", rh->name); nsh->proc(nsh->proc_cls, result); GNUNET_free(nsh); free_resolver_handle(rh); } else { /** * No PSEU found. * continue with next authority */ next_authority = rh->authority_chain_head; GNUNET_snprintf(tmp_name, MAX_DNS_NAME_LENGTH, "%s.%s", rh->name, next_authority->name); strcpy(rh->name, tmp_name); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No PSEU found for authority %s. Promoting back: %s\n", next_authority->name, rh->name); GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head, rh->authority_chain_tail, next_authority); GNUNET_NAMESTORE_zone_to_name (namestore_handle, &rh->authority_chain_tail->zone, &rh->authority_chain_head->zone, &process_zone_to_name_shorten, rh); } } /** * DHT resolution for delegation. Processing result. * * @param cls the closure * @param rh resolver handle * @param rd_count number of results * @param rd record data */ static void handle_delegation_dht_bg_shorten(void* cls, struct ResolverHandle *rh, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd) { /* We resolved full name for delegation. resolving record */ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_SHORTEN: Resolved up to %s for delegation via DHT in background.\n", rh->name); free_resolver_handle(rh); } /** * Process result from namestore delegation lookup * for shorten operation * * @param cls the client shorten handle * @param rh the resolver handle * @param rd_count number of results (0) * @param rd data (NULL) */ void handle_delegation_ns_shorten(void* cls, struct ResolverHandle *rh, uint32_t rd_count, const struct GNUNET_NAMESTORE_RecordData *rd) { struct NameShortenHandle *nsh; char result[MAX_DNS_NAME_LENGTH]; size_t answer_len; struct ResolverHandle *rh_bg; nsh = (struct NameShortenHandle *)cls; /** * At this point rh->name contains the part of the name * that we do not have a PKEY in our namestore to resolve. * The authority chain in the resolver handle is now * useful to backtrack if needed */ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "PKEY resolved as far as possible in ns up to %s!\n", rh->name); if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone, &rh->private_local_zone) == 0) { /** * This is our zone append .gnunet unless name is empty * (it shouldn't be, usually FIXME what happens if we * shorten to our zone to a "" record??) */ answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2; memset(result, 0, answer_len); strcpy(result, rh->name); strcpy(result+strlen(rh->name), "."); strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Our zone: Sending name as shorten result %s\n", rh->name); nsh->proc(nsh->proc_cls, result); GNUNET_free(nsh); free_resolver_handle(rh); return; } /** * we have to this before zone to name for rh might * be freed by then */ rh_bg = NULL; if (!is_canonical(rh->name)) { rh_bg = GNUNET_malloc(sizeof(struct ResolverHandle)); memcpy(rh_bg, rh, sizeof(struct ResolverHandle)); rh_bg->id = rid++; } /* backtrack authorities for names */ GNUNET_NAMESTORE_zone_to_name (namestore_handle, &rh->authority_chain_tail->zone, //ours &rh->authority_chain_head->zone, &process_zone_to_name_shorten, rh); if (rh_bg == NULL) { return; } /** * If authority resolution is incomplete we can do a background lookup * of the full name so that next time we can (likely) fully or at least * further shorten the name */ rh_bg->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain)); rh_bg->authority_chain_tail = rh_bg->authority_chain_head; rh_bg->authority_chain_head->zone = rh_bg->authority; rh_bg->proc = &handle_delegation_dht_bg_shorten; rh_bg->proc_cls = NULL; GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_SHORTEN: Starting background lookup for %s\n", rh_bg->name); resolve_delegation_dht(rh_bg); } /** * Callback calles by namestore for a zone to name * result * * @param cls the closure * @param zone_key the zone we queried * @param expire the expiration time of the name * @param name the name found or NULL * @param rd_len number of records for the name * @param rd the record data (PKEY) for the name * @param signature the signature for the record data */ static void process_zone_to_name_zkey(void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *name, unsigned int rd_len, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { struct ResolverHandle *rh = cls; struct NameShortenHandle *nsh = rh->proc_cls; struct GNUNET_CRYPTO_ShortHashAsciiEncoded enc; char new_name[MAX_DNS_NAME_LENGTH]; /* zkey not in our zone */ if (name == NULL) { /** * In this case we have not given this PKEY a name (yet) * It is either just not in our zone or not even cached * Since we do not know at this point we will not try to shorten * because PKEY import will happen if the user follows the zkey * link. */ GNUNET_CRYPTO_short_hash_to_enc ((struct GNUNET_CRYPTO_ShortHashCode*)rd, &enc); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No name found for zkey %s returning verbatim!\n", enc); if (strcmp(rh->name, "") != 0) GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s.%s", rh->name, enc, GNUNET_GNS_TLD_ZKEY); else GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s", enc, GNUNET_GNS_TLD_ZKEY); nsh->proc(nsh->proc_cls, new_name); GNUNET_free(nsh); free_resolver_handle(rh); return; } if (strcmp(rh->name, "") != 0) GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s", rh->name, name); else strcpy(new_name, name); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Continue shorten for %s!\n", new_name); strcpy(rh->name, new_name); rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain)); rh->authority_chain_tail = rh->authority_chain_head; rh->authority_chain_head->zone = rh->authority; /* Start delegation resolution in our namestore */ resolve_delegation_ns(rh); } /** * Shorten api from resolver * * @param zone the zone to use * @param pzone the private local zone * @param name the name to shorten * @param key optional private key for background lookups and PSEU import * @param proc the processor to call with result * @param proc_cls closure to pass to proc */ void gns_resolver_shorten_name(struct GNUNET_CRYPTO_ShortHashCode zone, struct GNUNET_CRYPTO_ShortHashCode pzone, const char* name, struct GNUNET_CRYPTO_RsaPrivateKey *key, ShortenResultProcessor proc, void* proc_cls) { struct ResolverHandle *rh; struct NameShortenHandle *nsh; char string_hash[MAX_DNS_LABEL_LENGTH]; struct GNUNET_CRYPTO_ShortHashCode zkey; char nzkey[MAX_DNS_LABEL_LENGTH]; char* nzkey_ptr = nzkey; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting shorten for %s!\n", name); if (is_canonical((char*)name)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s is canonical. Returning verbatim\n", name); proc(proc_cls, name); return; } nsh = GNUNET_malloc(sizeof (struct NameShortenHandle)); nsh->proc = proc; nsh->proc_cls = proc_cls; rh = GNUNET_malloc(sizeof (struct ResolverHandle)); rh->authority = zone; rh->id = rid++; rh->priv_key = key; rh->proc = &handle_delegation_ns_shorten; rh->proc_cls = nsh; rh->id = rid++; rh->private_local_zone = pzone; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking for TLD...\n"); if (is_zkey_tld(name) == GNUNET_YES) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TLD is zkey\n"); /** * This is a zkey tld * build hash and use as initial authority * FIXME sscanf */ memset(rh->name, 0, strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY)); memcpy(rh->name, name, strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1); pop_tld(rh->name, string_hash); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ZKEY is %s!\n", string_hash); GNUNET_STRINGS_utf8_toupper(string_hash, &nzkey_ptr); if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey, &zkey)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot convert ZKEY %s to hash!\n", nzkey); GNUNET_free(rh); GNUNET_free(nsh); proc(proc_cls, name); return; } GNUNET_NAMESTORE_zone_to_name (namestore_handle, &zone, //ours &zkey, &process_zone_to_name_zkey, rh); return; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TLD is gnunet\n"); /** * Presumably GNUNET tld */ memset(rh->name, 0, strlen(name)-strlen(GNUNET_GNS_TLD)); memcpy(rh->name, name, strlen(name)-strlen(GNUNET_GNS_TLD) - 1); } rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain)); rh->authority_chain_tail = rh->authority_chain_head; rh->authority_chain_head->zone = zone; /* Start delegation resolution in our namestore */ resolve_delegation_ns(rh); } /*********** END NAME SHORTEN ********************/ /** * Process result from namestore delegation lookup * for get authority operation * * @param cls the client get auth handle * @param rh the resolver handle * @param rd_count number of results (0) * @param rd data (NULL) */ void handle_delegation_result_ns_get_auth(void* cls, struct ResolverHandle *rh, uint32_t rd_count, const struct GNUNET_NAMESTORE_RecordData *rd) { struct GetNameAuthorityHandle* nah; char result[MAX_DNS_NAME_LENGTH]; size_t answer_len; nah = (struct GetNameAuthorityHandle*) rh->proc_cls; /** * At this point rh->name contains the part of the name * that we do not have a PKEY in our namestore to resolve. * The authority chain in the resolver handle is now * useful to backtrack if needed */ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "PKEY resolved as far as possible in ns up to %s!\n", rh->name); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Building response!\n"); if (is_canonical(rh->name)) { /** * We successfully resolved the authority in the ns * FIXME for our purposes this is fine * but maybe we want to have an api that also looks * into the dht (i.e. option in message) **/ if (strlen(rh->name) > strlen(nah->name)) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record name longer than original lookup name... odd!\n"); //FIXME to sth here } answer_len = strlen(nah->name) - strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 1; memset(result, 0, answer_len); strcpy(result, nah->name + strlen(rh->name) + 1); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got authority result %s\n", result); nah->proc(nah->proc_cls, result); GNUNET_free(nah); free_resolver_handle(rh); } else { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Unable to resolve authority for remaining %s!\n", rh->name); nah->proc(nah->proc_cls, ""); GNUNET_free(nah); free_resolver_handle(rh); } } /** * Tries to resolve the authority for name * in our namestore * * @param zone the root zone to look up for * @param pzone the private local zone * @param name the name to lookup up * @param proc the processor to call when finished * @param proc_cls the closure to pass to the processor */ void gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone, struct GNUNET_CRYPTO_ShortHashCode pzone, const char* name, GetAuthorityResultProcessor proc, void* proc_cls) { struct ResolverHandle *rh; struct GetNameAuthorityHandle *nah; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting authority resolution for %s!\n", name); nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle)); rh = GNUNET_malloc(sizeof (struct ResolverHandle)); rh->authority = zone; rh->id = rid++; rh->private_local_zone = pzone; if (strcmp(GNUNET_GNS_TLD, name) == 0) { strcpy(rh->name, "\0"); } else { memset(rh->name, 0, strlen(name)-strlen(GNUNET_GNS_TLD)); memcpy(rh->name, name, strlen(name)-strlen(GNUNET_GNS_TLD) - 1); } memset(nah->name, 0, strlen(name)+1); strcpy(nah->name, name); rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain)); rh->authority_chain_tail = rh->authority_chain_head; rh->authority_chain_head->zone = zone; rh->proc = &handle_delegation_result_ns_get_auth; rh->proc_cls = (void*)nah; nah->proc = proc; nah->proc_cls = proc_cls; /* Start delegation resolution in our namestore */ resolve_delegation_ns(rh); } /******** END GET AUTHORITY *************/ /* end of gnunet-service-gns_resolver.c */ gnunet-0.9.3/src/gns/gnunet-service-gns.c0000644000175000017500000007520611761753146015236 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * * @file gns/gnunet-service-gns.c * @brief GNUnet GNS service * @author Martin Schanzenbach */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_transport_service.h" #include "gnunet_dns_service.h" #include "gnunet_dnsparser_lib.h" #include "gnunet_dht_service.h" #include "gnunet_namestore_service.h" #include "gnunet_gns_service.h" #include "block_gns.h" #include "gns.h" #include "gnunet-service-gns_resolver.h" #include "gnunet-service-gns_interceptor.h" /* FIXME move to proper header in include */ #define GNUNET_MESSAGE_TYPE_GNS_LOOKUP 23 #define GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT 24 #define GNUNET_MESSAGE_TYPE_GNS_SHORTEN 25 #define GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT 26 #define GNUNET_MESSAGE_TYPE_GNS_GET_AUTH 27 #define GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT 28 /** * Handle to a shorten operation from api */ struct ClientShortenHandle { /* the requesting client that */ struct GNUNET_SERVER_Client *client; /* request id */ uint64_t unique_id; /* request type */ enum GNUNET_GNS_RecordType type; /* optional zone private key used for lookup */ struct GNUNET_CRYPTO_RsaPrivateKey *zone_key; /* name to shorten */ char* name; }; /** * Handle to a get auhtority operation from api */ struct ClientGetAuthHandle { /* the requesting client that */ struct GNUNET_SERVER_Client *client; /* request id */ uint64_t unique_id; /* name to lookup authority */ char* name; }; /** * Handle to a lookup operation from api */ struct ClientLookupHandle { /* the requesting client that */ struct GNUNET_SERVER_Client *client; /* request id */ uint64_t unique_id; /* request type */ enum GNUNET_GNS_RecordType type; /* optional zone private key used for lookup */ struct GNUNET_CRYPTO_RsaPrivateKey *zone_key; /* the name to look up */ char* name; //Needed? }; /** * Our handle to the DHT */ static struct GNUNET_DHT_Handle *dht_handle; /** * Our zone's private key */ struct GNUNET_CRYPTO_RsaPrivateKey *zone_key; /** * Our handle to the namestore service * FIXME maybe need a second handle for iteration */ struct GNUNET_NAMESTORE_Handle *namestore_handle; /** * Handle to iterate over our authoritative zone in namestore */ struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter; /** * The configuration the GNS service is running with */ const struct GNUNET_CONFIGURATION_Handle *GNS_cfg; /** * Our notification context. */ static struct GNUNET_SERVER_NotificationContext *nc; /** * Our zone hash */ struct GNUNET_CRYPTO_ShortHashCode zone_hash; /** * Useful for zone update for DHT put */ static int num_public_records; /** * update interval in seconds */ static unsigned long long max_record_put_interval; static unsigned long long dht_max_update_interval; /* dht update interval FIXME define? */ static struct GNUNET_TIME_Relative record_put_interval; /* zone update task */ GNUNET_SCHEDULER_TaskIdentifier zone_update_taskid = GNUNET_SCHEDULER_NO_TASK; /* automatic pkey import for name shortening */ static int auto_import_pkey; /* lookup timeout */ static struct GNUNET_TIME_Relative default_lookup_timeout; /** * Continue shutdown */ static void on_resolver_cleanup(void) { GNUNET_NAMESTORE_disconnect(namestore_handle, 1); GNUNET_DHT_disconnect(dht_handle); } /** * Task run during shutdown. * * @param cls unused * @param tc unused */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Shutting down!"); /* Kill zone task for it may make the scheduler hang */ if (zone_update_taskid != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel(zone_update_taskid); GNUNET_SERVER_notification_context_destroy (nc); gns_interceptor_stop(); gns_resolver_cleanup(&on_resolver_cleanup); } /** * Method called periodicattluy that triggers * iteration over root zone * * @param cls closure * @param tc task context */ static void update_zone_dht_next(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { zone_update_taskid = GNUNET_SCHEDULER_NO_TASK; GNUNET_NAMESTORE_zone_iterator_next(namestore_iter); } /** * Continuation for DHT put * * @param cls closure * @param success GNUNET_OK if the PUT was transmitted, * GNUNET_NO on timeout, * GNUNET_SYSERR on disconnect from service * after the PUT message was transmitted * (so we don't know if it was received or not) */ static void record_dht_put(void *cls, int success) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "put request transmitted\n"); } /* prototype */ static void update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Function used to put all records successively into the DHT. * * @param cls the closure (NULL) * @param key the public key of the authority (ours) * @param expiration lifetime of the namestore entry * @param name the name of the records * @param rd_count the number of records in data * @param rd the record data * @param signature the signature for the record data */ static void put_gns_record(void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key, struct GNUNET_TIME_Absolute expiration, const char *name, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { struct GNSNameRecordBlock *nrb; struct GNUNET_CRYPTO_ShortHashCode name_hash; struct GNUNET_CRYPTO_ShortHashCode zhash; GNUNET_HashCode xor_hash; GNUNET_HashCode name_hash_double; GNUNET_HashCode zone_hash_double; uint32_t rd_payload_length; char* nrb_data = NULL; size_t namelen; /* we're done */ if (NULL == name) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Zone iteration finished. Rescheduling put in %ds\n", dht_max_update_interval); zone_update_taskid = GNUNET_SCHEDULER_add_delayed ( GNUNET_TIME_relative_multiply( GNUNET_TIME_UNIT_SECONDS, dht_max_update_interval ), &update_zone_dht_start, NULL); return; } namelen = strlen(name) + 1; if (signature == NULL) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "No signature for %s record data provided! Skipping...\n", name); zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_next, NULL); return; } GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Putting records for %s into the DHT\n", name); rd_payload_length = GNUNET_NAMESTORE_records_get_size (rd_count, rd); nrb = GNUNET_malloc(rd_payload_length + namelen + sizeof(struct GNSNameRecordBlock)); nrb->signature = *signature; nrb->public_key = *key; nrb->rd_count = htonl(rd_count); memcpy(&nrb[1], name, namelen); nrb_data = (char*)&nrb[1]; nrb_data += namelen; rd_payload_length += sizeof(struct GNSNameRecordBlock) + namelen; if (-1 == GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_payload_length, nrb_data)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Record serialization failed! Skipping...\n"); GNUNET_free(nrb); zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_next, NULL); return; } /* * calculate DHT key: H(name) xor H(pubkey) */ GNUNET_CRYPTO_short_hash(key, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &zhash); GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash); GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double); GNUNET_CRYPTO_short_hash_double (&zhash, &zone_hash_double); GNUNET_CRYPTO_hash_xor(&zone_hash_double, &name_hash_double, &xor_hash); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "zone identity: %s\n", GNUNET_h2s (&zone_hash_double)); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "putting records for %s under key: %s with size %d\n", name, GNUNET_h2s (&xor_hash), rd_payload_length); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "DHT req to %d\n", DHT_OPERATION_TIMEOUT.rel_value); /* FIXME: keep return value to possibly cancel? */ GNUNET_DHT_put (dht_handle, &xor_hash, DHT_GNS_REPLICATION_LEVEL, GNUNET_DHT_RO_NONE, GNUNET_BLOCK_TYPE_GNS_NAMERECORD, rd_payload_length, (char*)nrb, expiration, DHT_OPERATION_TIMEOUT, &record_dht_put, NULL); //cls for cont num_public_records++; /** * Reschedule periodic put */ zone_update_taskid = GNUNET_SCHEDULER_add_delayed (record_put_interval, &update_zone_dht_next, NULL); GNUNET_free(nrb); } /** * Periodically iterate over our zone and store everything in dht * * @param cls NULL * @param tc task context */ static void update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { unsigned long long interval = 0; zone_update_taskid = GNUNET_SCHEDULER_NO_TASK; GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Scheduling DHT zone update!\n"); if (0 == num_public_records) { /** * If no records are known (startup) or none present * we can safely set the interval to 1s */ record_put_interval = GNUNET_TIME_relative_multiply( GNUNET_TIME_UNIT_SECONDS, 1); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No records in db. Adjusted record put interval to 1s\n"); } else { interval = max_record_put_interval/num_public_records; if (interval == 0) interval = 1; record_put_interval = GNUNET_TIME_relative_multiply( GNUNET_TIME_UNIT_SECONDS, interval); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Adjusted DHT update interval to %ds!\n", interval); } /* start counting again */ num_public_records = 0; namestore_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle, NULL, //All zones GNUNET_NAMESTORE_RF_AUTHORITY, GNUNET_NAMESTORE_RF_PRIVATE, &put_gns_record, NULL); } /** * Lookup the private key for the zone * * @param zone the zone we want a private key for * @return NULL of not found else the key */ struct GNUNET_CRYPTO_RsaPrivateKey* lookup_private_key(struct GNUNET_CRYPTO_ShortHashCode *zone) { char* keydir; struct GNUNET_CRYPTO_ShortHashAsciiEncoded zonename; char* location; struct GNUNET_CRYPTO_RsaPrivateKey *key = NULL; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Looking for private key\n"); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (GNS_cfg, "namestore", "ZONEFILE_DIRECTORY", &keydir)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No zonefile directory!\n"); return NULL; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Zonefile directory is %s\n", keydir); GNUNET_CRYPTO_short_hash_to_enc (zone, &zonename); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Zonefile is %s.zkey\n", &zonename); GNUNET_asprintf(&location, "%s%s%s.zkey", keydir, DIR_SEPARATOR_STR, &zonename); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Checking for %s\n", location); if (GNUNET_YES == GNUNET_DISK_file_test (location)) key = GNUNET_CRYPTO_rsa_key_create_from_file (location); GNUNET_free(location); GNUNET_free(keydir); return key; } /* END DHT ZONE PROPAGATION */ /** * Send shorten response back to client * * @param cls the closure containing a client shorten handle * @param name the shortened name result or NULL if cannot be shortened */ static void send_shorten_response(void* cls, const char* name) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %s\n", "SHORTEN_RESULT", name); struct GNUNET_GNS_ClientShortenResultMessage *rmsg; struct ClientShortenHandle *csh = (struct ClientShortenHandle *)cls; if (name == NULL) { name = ""; } rmsg = GNUNET_malloc(sizeof(struct GNUNET_GNS_ClientShortenResultMessage) + strlen(name) + 1); rmsg->id = csh->unique_id; rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT); rmsg->header.size = htons(sizeof(struct GNUNET_GNS_ClientShortenResultMessage) + strlen(name) + 1); strcpy((char*)&rmsg[1], name); GNUNET_SERVER_notification_context_unicast (nc, csh->client, (const struct GNUNET_MessageHeader *) rmsg, GNUNET_NO); GNUNET_SERVER_receive_done (csh->client, GNUNET_OK); GNUNET_free(rmsg); GNUNET_free_non_null(csh->name); GNUNET_free_non_null(csh->zone_key); GNUNET_free(csh); } /** * Handle a shorten message from the api * * @param cls the closure * @param client the client * @param message the message */ static void handle_shorten(void *cls, struct GNUNET_SERVER_Client * client, const struct GNUNET_MessageHeader * message) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "SHORTEN"); size_t msg_size = 0; struct ClientShortenHandle *csh; char name[MAX_DNS_NAME_LENGTH]; char* nameptr = name; struct GNUNET_CRYPTO_ShortHashCode zone; struct GNUNET_CRYPTO_RsaPrivateKey *key; if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientShortenMessage)) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } struct GNUNET_GNS_ClientShortenMessage *sh_msg = (struct GNUNET_GNS_ClientShortenMessage *) message; msg_size = ntohs(message->size); if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } csh = GNUNET_malloc(sizeof(struct ClientShortenHandle)); csh->client = client; csh->unique_id = sh_msg->id; csh->zone_key = NULL; GNUNET_STRINGS_utf8_tolower((char*)&sh_msg[1], &nameptr); if (strlen (name) < strlen(GNUNET_GNS_TLD)) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "SHORTEN: %s is too short", name); csh->name = NULL; send_shorten_response(csh, name); return; } if (strlen (name) > MAX_DNS_NAME_LENGTH) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "SHORTEN: %s is too long", name); csh->name = NULL; send_shorten_response(csh, name); return; } if (!is_gnunet_tld(name) && !is_zkey_tld(name)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s is not our domain. Returning\n", name); csh->name = NULL; send_shorten_response(csh, name); return; } GNUNET_SERVER_notification_context_add (nc, client); if (1 == ntohl(sh_msg->use_default_zone)) zone = zone_hash; //Default zone else zone = sh_msg->zone; /* Start shortening */ if (GNUNET_YES == auto_import_pkey) { if (1 == ntohl(sh_msg->use_default_zone)) key = zone_key; else { key = lookup_private_key(&sh_msg->zone); csh->zone_key = key; } gns_resolver_shorten_name(zone, zone, name, key, &send_shorten_response, csh); } else gns_resolver_shorten_name(zone, zone, name, NULL, &send_shorten_response, csh); } /** * Send get authority response back to client * * @param cls the closure containing a client get auth handle * @param name the shortened name result or NULL if cannot be shortened */ static void send_get_auth_response(void *cls, const char* name) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %s\n", "GET_AUTH_RESULT", name); struct GNUNET_GNS_ClientGetAuthResultMessage *rmsg; struct ClientGetAuthHandle *cah = (struct ClientGetAuthHandle *)cls; if (name == NULL) { name = ""; } rmsg = GNUNET_malloc(sizeof(struct GNUNET_GNS_ClientGetAuthResultMessage) + strlen(name) + 1); rmsg->id = cah->unique_id; rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT); rmsg->header.size = htons(sizeof(struct GNUNET_GNS_ClientGetAuthResultMessage) + strlen(name) + 1); strcpy((char*)&rmsg[1], name); GNUNET_SERVER_notification_context_unicast (nc, cah->client, (const struct GNUNET_MessageHeader *) rmsg, GNUNET_NO); GNUNET_SERVER_receive_done (cah->client, GNUNET_OK); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up handles...\n"); GNUNET_free(rmsg); GNUNET_free_non_null(cah->name); GNUNET_free(cah); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "done.\n"); } /** * Handle a get authority message from the api * * @param cls the closure * @param client the client * @param message the message */ static void handle_get_authority(void *cls, struct GNUNET_SERVER_Client * client, const struct GNUNET_MessageHeader * message) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "GET_AUTH"); size_t msg_size = 0; struct ClientGetAuthHandle *cah; char name[MAX_DNS_NAME_LENGTH]; char* nameptr = name; if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientGetAuthMessage)) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } GNUNET_SERVER_notification_context_add (nc, client); struct GNUNET_GNS_ClientGetAuthMessage *sh_msg = (struct GNUNET_GNS_ClientGetAuthMessage *) message; msg_size = ntohs(message->size); if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } GNUNET_STRINGS_utf8_tolower((char*)&sh_msg[1], &nameptr); cah = GNUNET_malloc(sizeof(struct ClientGetAuthHandle)); cah->client = client; cah->unique_id = sh_msg->id; if (strlen(name) < strlen(GNUNET_GNS_TLD)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GET_AUTH: %s is too short. Returning\n", name); cah->name = NULL; send_get_auth_response(cah, name); return; } if (strlen (name) > MAX_DNS_NAME_LENGTH) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GET_AUTH: %s is too long", name); cah->name = NULL; send_get_auth_response(cah, name); return; } if (strcmp(name+strlen(name)-strlen(GNUNET_GNS_TLD), GNUNET_GNS_TLD) != 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GET_AUTH: %s is not our domain. Returning\n", name); cah->name = NULL; send_get_auth_response(cah, name); return; } if (strcmp(name, GNUNET_GNS_TLD) == 0) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GET_AUTH: %s is us. Returning\n", name); cah->name = NULL; send_get_auth_response(cah, name); return; } cah->name = GNUNET_malloc(strlen(name) - strlen(GNUNET_GNS_TLD) + 1); memset(cah->name, 0, strlen(name)-strlen(GNUNET_GNS_TLD) + 1); memcpy(cah->name, name, strlen(name)-strlen(GNUNET_GNS_TLD)); /* Start delegation resolution in our namestore */ gns_resolver_get_authority(zone_hash, zone_hash, name, &send_get_auth_response, cah); } /** * Reply to client with the result from our lookup. * * @param cls the closure (our client lookup handle) * @param rd_count the number of records * @param rd the record data */ static void send_lookup_response(void* cls, uint32_t rd_count, const struct GNUNET_NAMESTORE_RecordData *rd) { struct ClientLookupHandle* clh = (struct ClientLookupHandle*)cls; struct GNUNET_GNS_ClientLookupResultMessage *rmsg; size_t len; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %d results\n", "LOOKUP_RESULT", rd_count); len = GNUNET_NAMESTORE_records_get_size (rd_count, rd); rmsg = GNUNET_malloc(len+sizeof(struct GNUNET_GNS_ClientLookupResultMessage)); rmsg->id = clh->unique_id; rmsg->rd_count = htonl(rd_count); rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT); rmsg->header.size = htons(len+sizeof(struct GNUNET_GNS_ClientLookupResultMessage)); GNUNET_NAMESTORE_records_serialize (rd_count, rd, len, (char*)&rmsg[1]); GNUNET_SERVER_notification_context_unicast (nc, clh->client, (const struct GNUNET_MessageHeader *) rmsg, GNUNET_NO); GNUNET_SERVER_receive_done (clh->client, GNUNET_OK); GNUNET_free(rmsg); GNUNET_free(clh->name); if (NULL != clh->zone_key) GNUNET_free(clh->zone_key); GNUNET_free(clh); } /** * Handle lookup requests from client * * @param cls the closure * @param client the client * @param message the message */ static void handle_lookup(void *cls, struct GNUNET_SERVER_Client * client, const struct GNUNET_MessageHeader * message) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "LOOKUP"); size_t msg_size = 0; size_t namelen; char name[MAX_DNS_NAME_LENGTH]; struct ClientLookupHandle *clh; char* nameptr = name; struct GNUNET_CRYPTO_RsaPrivateKey *key = NULL; struct GNUNET_CRYPTO_ShortHashCode zone; if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientLookupMessage)) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } GNUNET_SERVER_notification_context_add (nc, client); struct GNUNET_GNS_ClientLookupMessage *sh_msg = (struct GNUNET_GNS_ClientLookupMessage *) message; msg_size = ntohs(message->size); if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break_op (0); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } GNUNET_STRINGS_utf8_tolower((char*)&sh_msg[1], &nameptr); namelen = strlen(name)+1; clh = GNUNET_malloc(sizeof(struct ClientLookupHandle)); clh->client = client; clh->name = GNUNET_malloc(namelen); strcpy(clh->name, name); clh->unique_id = sh_msg->id; clh->type = ntohl(sh_msg->type); clh->zone_key = NULL; if (strlen (name) > MAX_DNS_NAME_LENGTH) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "LOOKUP: %s is too long", name); clh->name = NULL; send_lookup_response(clh, 0, NULL); return; } if (1 == ntohl(sh_msg->use_default_zone)) zone = zone_hash; //Default zone else zone = sh_msg->zone; if (GNUNET_YES == auto_import_pkey) { if (1 == ntohl(sh_msg->use_default_zone)) key = zone_key; else { key = lookup_private_key(&zone); clh->zone_key = key; } gns_resolver_lookup_record(zone, zone, clh->type, name, key, default_lookup_timeout, &send_lookup_response, clh); } else { gns_resolver_lookup_record(zone, zone, clh->type, name, NULL, default_lookup_timeout, &send_lookup_response, clh); } } /** * Process GNS requests. * * @param cls closure) * @param server the initialized server * @param c configuration to use */ static void run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *c) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Initializing GNS\n"); char* keyfile; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; unsigned long long max_parallel_bg_queries = 0; unsigned long long default_lookup_timeout_secs = 0; int ignore_pending = GNUNET_NO; static const struct GNUNET_SERVER_MessageHandler handlers[] = { {&handle_shorten, NULL, GNUNET_MESSAGE_TYPE_GNS_SHORTEN, 0}, {&handle_lookup, NULL, GNUNET_MESSAGE_TYPE_GNS_LOOKUP, 0}, {&handle_get_authority, NULL, GNUNET_MESSAGE_TYPE_GNS_GET_AUTH, 0} }; GNS_cfg = c; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (c, "gns", "ZONEKEY", &keyfile)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No private key for root zone specified!\n"); GNUNET_SCHEDULER_shutdown (); return; } GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Using keyfile %s for root zone.\n", keyfile); zone_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); GNUNET_CRYPTO_rsa_key_get_public (zone_key, &pkey); GNUNET_CRYPTO_short_hash(&pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &zone_hash); GNUNET_free(keyfile); /** * handle to our local namestore */ namestore_handle = GNUNET_NAMESTORE_connect(c); if (NULL == namestore_handle) { //FIXME do error handling; GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to the namestore!\n"); GNUNET_SCHEDULER_shutdown (); return; } auto_import_pkey = GNUNET_NO; if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (c, "gns", "AUTO_IMPORT_PKEY")) { GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Automatic PKEY import is enabled.\n"); auto_import_pkey = GNUNET_YES; } dht_max_update_interval = GNUNET_GNS_DHT_MAX_UPDATE_INTERVAL; if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (c, "gns", "ZONE_PUT_INTERVAL", &dht_max_update_interval)) { GNUNET_log(GNUNET_ERROR_TYPE_INFO, "DHT zone update interval: %d\n", dht_max_update_interval); } max_record_put_interval = 1; if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (c, "gns", "RECORD_PUT_INTERVAL", &max_record_put_interval)) { GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Record put interval: %d\n", max_record_put_interval); } if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (c, "gns", "MAX_PARALLEL_BACKGROUND_QUERIES", &max_parallel_bg_queries)) { GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Number of allowed parallel background queries: %d\n", max_parallel_bg_queries); } if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (c, "gns", "AUTO_IMPORT_CONFIRMATION_REQ")) { GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Auto import requires user confirmation\n"); ignore_pending = GNUNET_YES; } if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(c, "gns", "DEFAULT_LOOKUP_TIMEOUT", &default_lookup_timeout_secs)) { GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Default lookup timeout: %ds\n", default_lookup_timeout_secs); default_lookup_timeout = GNUNET_TIME_relative_multiply( GNUNET_TIME_UNIT_SECONDS, default_lookup_timeout_secs); } /** * handle to the dht */ dht_handle = GNUNET_DHT_connect(c, //max_parallel_bg_queries); //FIXME get ht_len from cfg 1024); if (NULL == dht_handle) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not connect to DHT!\n"); } if (gns_resolver_init(namestore_handle, dht_handle, zone_hash, max_parallel_bg_queries, ignore_pending) == GNUNET_SYSERR) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Unable to initialize resolver!\n"); GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); return; } if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (c, "gns", "HIJACK_DNS")) { GNUNET_log(GNUNET_ERROR_TYPE_INFO, "DNS hijacking enabled... connecting to service.\n"); if (gns_interceptor_init(zone_hash, zone_key, c) == GNUNET_SYSERR) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to enable the dns interceptor!\n"); } } /** * Schedule periodic put * for our records * We have roughly an hour for all records; */ record_put_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 1); zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start, NULL); GNUNET_SERVER_add_handlers (server, handlers); //FIXME //GNUNET_SERVER_disconnect_notify (server, // &client_disconnect_notification, // NULL); nc = GNUNET_SERVER_notification_context_create (server, 1); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); } /** * The main function for the GNS service. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { int ret; ret = (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "gns", GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; return ret; } /* end of gnunet-service-gns.c */ gnunet-0.9.3/src/dns/0000755000175000017500000000000011763406750011410 500000000000000gnunet-0.9.3/src/dns/test_gnunet_dns.sh0000755000175000017500000000055311705372513015070 00000000000000#!/bin/bash ME=`whoami` if [ "$ME" != "root" ] then echo "This test only works if run as root. Skipping." exit 0 fi export PATH=".:$PATH" gnunet-service-dns -c dns.conf & gnunet-dns-redirector -c dns.conf -4 127.0.0.1 & sleep 1 LO=`nslookup gnunet.org | grep Address | tail -n1` if [ "$LO" != "Address: 127.0.0.1" ] then echo "Fail: $LO" fi kill `jobs -p` gnunet-0.9.3/src/dns/Makefile.am0000644000175000017500000000526611751540170013365 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 endif pkgcfgdir= $(pkgdatadir)/config.d/ plugindir = $(libdir)/gnunet pkgcfg_DATA = \ dns.conf if LINUX HIJACKBIN = gnunet-helper-dns install-exec-hook: $(SUDO_BINARY) chown root $(bindir)/gnunet-helper-dns || true $(SUDO_BINARY) chgrp $(GNUNETDNS_GROUP) $(bindir)/gnunet-helper-dns || true $(SUDO_BINARY) chmod 4750 $(bindir)/gnunet-helper-dns || true $(SUDO_BINARY) chown gnunet:$(GNUNETDNS_GROUP) $(bindir)/gnunet-service-dns || true $(SUDO_BINARY) chmod 2750 $(bindir)/gnunet-service-dns || true else install-exec-hook: endif lib_LTLIBRARIES = \ libgnunetdnsparser.la \ libgnunetdns.la bin_PROGRAMS = \ gnunet-service-dns $(HIJACKBIN) noinst_PROGRAMS = \ gnunet-dns-monitor gnunet-dns-redirector plugin_LTLIBRARIES = \ libgnunet_plugin_block_dns.la if LINUX check_SCRIPTS = \ test_gnunet_dns.sh endif gnunet_helper_dns_SOURCES = \ gnunet-helper-dns.c gnunet_dns_monitor_SOURCES = \ gnunet-dns-monitor.c gnunet_dns_monitor_LDADD = \ $(top_builddir)/src/dns/libgnunetdnsparser.la \ $(top_builddir)/src/dns/libgnunetdns.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_dns_monitor_DEPENDENCIES = \ libgnunetdnsparser.la \ libgnunetdns.la gnunet_dns_redirector_SOURCES = \ gnunet-dns-redirector.c gnunet_dns_redirector_LDADD = \ $(top_builddir)/src/dns/libgnunetdnsparser.la \ $(top_builddir)/src/dns/libgnunetdns.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_dns_redirector_DEPENDENCIES = \ libgnunetdnsparser.la \ libgnunetdns.la gnunet_service_dns_SOURCES = \ gnunet-service-dns.c gnunet_service_dns_LDADD = \ $(top_builddir)/src/tun/libgnunettun.la \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) libgnunetdnsparser_la_SOURCES = \ dnsparser.c libgnunetdnsparser_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la $(XLIB) libgnunetdnsparser_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:0:0 libgnunetdns_la_SOURCES = \ dns_api.c dns.h libgnunetdns_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la $(XLIB) libgnunetdns_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:0:0 libgnunet_plugin_block_dns_la_SOURCES = \ plugin_block_dns.c libgnunet_plugin_block_dns_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_block_dns_la_LDFLAGS = \ $(top_builddir)/src/block/$(GN_PLUGIN_LDFLAGS) if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) $(check_SCRIPTS) endif EXTRA_DIST = \ $(check_SCRIPTS) gnunet-0.9.3/src/dns/gnunet-helper-dns.c0000644000175000017500000006164511760502551015040 00000000000000/* This file is part of GNUnet. (C) 2010, 2011, 2012 Christian Grothoff GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dns/gnunet-helper-dns.c * @brief helper to install firewall rules to hijack all DNS traffic * and send it to our virtual interface (except for DNS traffic * that originates on the specified port). We then * allow interacting with our virtual interface via stdin/stdout. * @author Philipp Tölke * @author Christian Grothoff * * This program alters the Linux firewall rules so that DNS traffic * that ordinarily exits the system can be intercepted and managed by * a virtual interface. In order to achieve this, DNS traffic is * marked with the DNS_MARK given in below and re-routed to a custom * table with the DNS_TABLE ID given below. Systems and * administrators must take care to not cause conflicts with these * values (it was deemed safest to hardcode them as passing these * values as arguments might permit messing with arbitrary firewall * rules, which would be dangerous). Traffic coming from the same * group ID as the effective group ID that this process is running * as is not intercepted. * * The code first sets up the virtual interface, then begins to * redirect the DNS traffic to it, and then on errors or SIGTERM shuts * down the virtual interface and removes the rules for the traffic * redirection. * * * Note that having this binary SUID is only partially safe: it will * allow redirecting (and intercepting / mangling) of all DNS traffic * originating from this system by any user who is able to run it. * Furthermore, this code will make it trivial to DoS all DNS traffic * originating from the current system, simply by sending it to * nowhere (redirect stdout to /dev/null). * * Naturally, neither of these problems can be helped as this is the * fundamental purpose of the binary. Certifying that this code is * "safe" thus only means that it doesn't allow anything else (such * as local priv. escalation, etc.). * * The following list of people have reviewed this code and considered * it safe (within specifications) since the last modification (if you * reviewed it, please have your name added to the list): * * - Christian Grothoff */ #include "platform.h" #include /** * Need 'struct GNUNET_MessageHeader'. */ #include "gnunet_common.h" /** * Need DNS message types. */ #include "gnunet_protocols.h" /** * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE) */ #define MAX_SIZE 65536 #ifndef _LINUX_IN6_H /** * This is in linux/include/net/ipv6.h, but not always exported... */ struct in6_ifreq { struct in6_addr ifr6_addr; uint32_t ifr6_prefixlen; unsigned int ifr6_ifindex; }; #endif /** * Name and full path of IPTABLES binary. */ static const char *sbin_iptables; /** * Name and full path of IPTABLES binary. */ static const char *sbin_ip; /** * Port for DNS traffic. */ #define DNS_PORT "53" /** * Marker we set for our hijacked DNS traffic. We use GNUnet's * port (2086) plus the DNS port (53) in HEX to make a 32-bit mark * (which is hopefully long enough to not collide); so * 0x08260035 = 136708149 (hopefully unique enough...). */ #define DNS_MARK "136708149" /** * Table we use for our DNS rules. 0-255 is the range and * 0, 253, 254 and 255 are already reserved. As this is about * DNS and as "53" is likely (fingers crossed!) high enough to * not usually conflict with a normal user's setup, we use 53 * to give a hint that this has something to do with DNS. */ #define DNS_TABLE "53" /** * Control pipe for shutdown via signal. [0] is the read end, * [1] is the write end. */ static int cpipe[2]; /** * Signal handler called to initiate "nice" shutdown. Signals select * loop via non-bocking pipe 'cpipe'. * * @param signal signal number of the signal (not used) */ static void signal_handler (int signal) { /* ignore return value, as the signal handler could theoretically be called many times before the shutdown can actually happen */ (void) write (cpipe[1], "K", 1); } /** * Run the given command and wait for it to complete. * * @param file name of the binary to run * @param cmd command line arguments (as given to 'execv') * @return 0 on success, 1 on any error */ static int fork_and_exec (const char *file, char *const cmd[]) { int status; pid_t pid; pid_t ret; pid = fork (); if (-1 == pid) { fprintf (stderr, "fork failed: %s\n", strerror (errno)); return 1; } if (0 == pid) { /* we are the child process */ /* close stdin/stdout to not cause interference with the helper's main protocol! */ (void) close (0); (void) close (1); (void) execv (file, cmd); /* can only get here on error */ fprintf (stderr, "exec `%s' failed: %s\n", file, strerror (errno)); _exit (1); } /* keep running waitpid as long as the only error we get is 'EINTR' */ while ( (-1 == (ret = waitpid (pid, &status, 0))) && (errno == EINTR) ); if (-1 == ret) { fprintf (stderr, "waitpid failed: %s\n", strerror (errno)); return 1; } if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)))) return 1; /* child process completed and returned success, we're happy */ return 0; } /** * Creates a tun-interface called dev; * * @param dev is asumed to point to a char[IFNAMSIZ] * if *dev == '\\0', uses the name supplied by the kernel; * @return the fd to the tun or -1 on error */ static int init_tun (char *dev) { struct ifreq ifr; int fd; if (NULL == dev) { errno = EINVAL; return -1; } if (-1 == (fd = open ("/dev/net/tun", O_RDWR))) { fprintf (stderr, "Error opening `%s': %s\n", "/dev/net/tun", strerror (errno)); return -1; } if (fd >= FD_SETSIZE) { fprintf (stderr, "File descriptor to large: %d", fd); (void) close (fd); return -1; } memset (&ifr, 0, sizeof (ifr)); ifr.ifr_flags = IFF_TUN; if ('\0' != *dev) strncpy (ifr.ifr_name, dev, IFNAMSIZ); if (-1 == ioctl (fd, TUNSETIFF, (void *) &ifr)) { fprintf (stderr, "Error with ioctl on `%s': %s\n", "/dev/net/tun", strerror (errno)); (void) close (fd); return -1; } strcpy (dev, ifr.ifr_name); return fd; } /** * @brief Sets the IPv6-Address given in address on the interface dev * * @param dev the interface to configure * @param address the IPv6-Address * @param prefix_len the length of the network-prefix */ static void set_address6 (const char *dev, const char *address, unsigned long prefix_len) { struct ifreq ifr; struct in6_ifreq ifr6; struct sockaddr_in6 sa6; int fd; /* * parse the new address */ memset (&sa6, 0, sizeof (struct sockaddr_in6)); sa6.sin6_family = AF_INET6; if (1 != inet_pton (AF_INET6, address, sa6.sin6_addr.s6_addr)) { fprintf (stderr, "Failed to parse address `%s': %s\n", address, strerror (errno)); exit (1); } if (-1 == (fd = socket (PF_INET6, SOCK_DGRAM, 0))) { fprintf (stderr, "Error creating socket: %s\n", strerror (errno)); exit (1); } memset (&ifr, 0, sizeof (struct ifreq)); /* * Get the index of the if */ strncpy (ifr.ifr_name, dev, IFNAMSIZ); if (-1 == ioctl (fd, SIOGIFINDEX, &ifr)) { fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } memset (&ifr6, 0, sizeof (struct in6_ifreq)); ifr6.ifr6_addr = sa6.sin6_addr; ifr6.ifr6_ifindex = ifr.ifr_ifindex; ifr6.ifr6_prefixlen = prefix_len; /* * Set the address */ if (-1 == ioctl (fd, SIOCSIFADDR, &ifr6)) { fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } /* * Get the flags */ if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr)) { fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } /* * Add the UP and RUNNING flags */ ifr.ifr_flags |= IFF_UP | IFF_RUNNING; if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr)) { fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } if (0 != close (fd)) { fprintf (stderr, "close failed: %s\n", strerror (errno)); exit (1); } } /** * @brief Sets the IPv4-Address given in address on the interface dev * * @param dev the interface to configure * @param address the IPv4-Address * @param mask the netmask */ static void set_address4 (const char *dev, const char *address, const char *mask) { int fd; struct sockaddr_in *addr; struct ifreq ifr; memset (&ifr, 0, sizeof (struct ifreq)); addr = (struct sockaddr_in *) &(ifr.ifr_addr); addr->sin_family = AF_INET; /* * Parse the address */ if (1 != inet_pton (AF_INET, address, &addr->sin_addr.s_addr)) { fprintf (stderr, "Failed to parse address `%s': %s\n", address, strerror (errno)); exit (1); } if (-1 == (fd = socket (PF_INET, SOCK_DGRAM, 0))) { fprintf (stderr, "Error creating socket: %s\n", strerror (errno)); exit (1); } strncpy (ifr.ifr_name, dev, IFNAMSIZ); /* * Set the address */ if (-1 == ioctl (fd, SIOCSIFADDR, &ifr)) { fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } /* * Parse the netmask */ addr = (struct sockaddr_in *) &(ifr.ifr_netmask); if (1 != inet_pton (AF_INET, mask, &addr->sin_addr.s_addr)) { fprintf (stderr, "Failed to parse address `%s': %s\n", mask, strerror (errno)); (void) close (fd); exit (1); } /* * Set the netmask */ if (-1 == ioctl (fd, SIOCSIFNETMASK, &ifr)) { fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } /* * Get the flags */ if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr)) { fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } /* * Add the UP and RUNNING flags */ ifr.ifr_flags |= IFF_UP | IFF_RUNNING; if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr)) { fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, strerror (errno)); (void) close (fd); exit (1); } if (0 != close (fd)) { fprintf (stderr, "close failed: %s\n", strerror (errno)); (void) close (fd); exit (1); } } /** * Start forwarding to and from the tunnel. This function runs with * "reduced" priviledges (saved UID is still 0, but effective UID is * the real user ID). * * @param fd_tun tunnel FD */ static void run (int fd_tun) { /* * The buffer filled by reading from fd_tun */ unsigned char buftun[MAX_SIZE]; ssize_t buftun_size = 0; unsigned char *buftun_read = NULL; /* * The buffer filled by reading from stdin */ unsigned char bufin[MAX_SIZE]; ssize_t bufin_size = 0; size_t bufin_rpos = 0; unsigned char *bufin_read = NULL; fd_set fds_w; fd_set fds_r; int max; while (1) { FD_ZERO (&fds_w); FD_ZERO (&fds_r); /* * We are supposed to read and the buffer is empty * -> select on read from tun */ if (0 == buftun_size) FD_SET (fd_tun, &fds_r); /* * We are supposed to read and the buffer is not empty * -> select on write to stdout */ if (0 != buftun_size) FD_SET (1, &fds_w); /* * We are supposed to write and the buffer is empty * -> select on read from stdin */ if (NULL == bufin_read) FD_SET (0, &fds_r); /* * We are supposed to write and the buffer is not empty * -> select on write to tun */ if (NULL != bufin_read) FD_SET (fd_tun, &fds_w); FD_SET (cpipe[0], &fds_r); max = (fd_tun > cpipe[0]) ? fd_tun : cpipe[0]; int r = select (max + 1, &fds_r, &fds_w, NULL, NULL); if (-1 == r) { if (EINTR == errno) continue; fprintf (stderr, "select failed: %s\n", strerror (errno)); return; } if (r > 0) { if (FD_ISSET (cpipe[0], &fds_r)) return; /* aborted by signal */ if (FD_ISSET (fd_tun, &fds_r)) { buftun_size = read (fd_tun, buftun + sizeof (struct GNUNET_MessageHeader), MAX_SIZE - sizeof (struct GNUNET_MessageHeader)); if (-1 == buftun_size) { if ( (errno == EINTR) || (errno == EAGAIN) ) continue; fprintf (stderr, "read-error: %s\n", strerror (errno)); return; } if (0 == buftun_size) { fprintf (stderr, "EOF on tun\n"); return; } buftun_read = buftun; { struct GNUNET_MessageHeader *hdr = (struct GNUNET_MessageHeader *) buftun; buftun_size += sizeof (struct GNUNET_MessageHeader); hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER); hdr->size = htons (buftun_size); } } else if (FD_ISSET (1, &fds_w)) { ssize_t written = write (1, buftun_read, buftun_size); if (-1 == written) { if ( (errno == EINTR) || (errno == EAGAIN) ) continue; fprintf (stderr, "write-error to stdout: %s\n", strerror (errno)); return; } if (0 == written) { fprintf (stderr, "write returned 0\n"); return; } buftun_size -= written; buftun_read += written; } if (FD_ISSET (0, &fds_r)) { bufin_size = read (0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos); if (-1 == bufin_size) { bufin_read = NULL; if ( (errno == EINTR) || (errno == EAGAIN) ) continue; fprintf (stderr, "read-error: %s\n", strerror (errno)); return; } if (0 == bufin_size) { bufin_read = NULL; fprintf (stderr, "EOF on stdin\n"); return; } { struct GNUNET_MessageHeader *hdr; PROCESS_BUFFER: bufin_rpos += bufin_size; if (bufin_rpos < sizeof (struct GNUNET_MessageHeader)) continue; hdr = (struct GNUNET_MessageHeader *) bufin; if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_DNS_HELPER) { fprintf (stderr, "protocol violation!\n"); return; } if (ntohs (hdr->size) > bufin_rpos) continue; bufin_read = bufin + sizeof (struct GNUNET_MessageHeader); bufin_size = ntohs (hdr->size) - sizeof (struct GNUNET_MessageHeader); bufin_rpos -= bufin_size + sizeof (struct GNUNET_MessageHeader); } } else if (FD_ISSET (fd_tun, &fds_w)) { ssize_t written = write (fd_tun, bufin_read, bufin_size); if (-1 == written) { if ( (errno == EINTR) || (errno == EAGAIN) ) continue; fprintf (stderr, "write-error to tun: %s\n", strerror (errno)); return; } if (0 == written) { fprintf (stderr, "write returned 0\n"); return; } { bufin_size -= written; bufin_read += written; if (0 == bufin_size) { memmove (bufin, bufin_read, bufin_rpos); bufin_read = NULL; /* start reading again */ bufin_size = 0; goto PROCESS_BUFFER; } } } } } } /** * Main function of "gnunet-helper-dns", which opens a VPN tunnel interface, * redirects all outgoing DNS traffic (except from the specified port) to that * interface and then passes traffic from and to the interface via stdin/stdout. * * Once stdin/stdout close or have other errors, the tunnel is closed and the * DNS traffic redirection is stopped. * * @param argc number of arguments * @param argv 0: binary name (should be "gnunet-helper-vpn") * 1: tunnel interface name (typically "gnunet-dns") * 2: IPv6 address for the tunnel ("FE80::1") * 3: IPv6 netmask length in bits ("64") * 4: IPv4 address for the tunnel ("1.2.3.4") * 5: IPv4 netmask ("255.255.0.0") * @return 0 on success, otherwise code indicating type of error: * 1 wrong number of arguments * 2 invalid arguments (i.e. port number / prefix length wrong) * 3 iptables not executable * 4 ip not executable * 5 failed to initialize tunnel interface * 6 failed to initialize control pipe * 8 failed to change routing table, cleanup successful * 9-23 failed to change routing table and failed to undo some changes to routing table * 24 failed to drop privs * 25-39 failed to drop privs and then failed to undo some changes to routing table * 40 failed to regain privs * 41-55 failed to regain prisv and then failed to undo some changes to routing table * 255 failed to handle kill signal properly */ int main (int argc, char *const*argv) { int r; char dev[IFNAMSIZ]; char mygid[32]; int fd_tun; if (6 != argc) { fprintf (stderr, "Fatal: must supply 6 arguments!\n"); return 1; } /* verify that the binaries were care about are executable */ if (0 == access ("/sbin/iptables", X_OK)) sbin_iptables = "/sbin/iptables"; else if (0 == access ("/usr/sbin/iptables", X_OK)) sbin_iptables = "/usr/sbin/iptables"; else { fprintf (stderr, "Fatal: executable iptables not found in approved directories: %s\n", strerror (errno)); return 3; } if (0 == access ("/sbin/ip", X_OK)) sbin_ip = "/sbin/ip"; else if (0 == access ("/usr/sbin/ip", X_OK)) sbin_ip = "/usr/sbin/ip"; else { fprintf (stderr, "Fatal: executable ip not found in approved directories: %s\n", strerror (errno)); return 4; } /* setup 'mygid' string */ snprintf (mygid, sizeof (mygid), "%d", (int) getegid()); /* do not die on SIGPIPE */ if (SIG_ERR == signal (SIGPIPE, SIG_IGN)) { fprintf (stderr, "Failed to protect against SIGPIPE: %s\n", strerror (errno)); return 7; } /* setup pipe to shutdown nicely on SIGINT */ if (0 != pipe (cpipe)) { fprintf (stderr, "Fatal: could not setup control pipe: %s\n", strerror (errno)); return 6; } if (cpipe[0] >= FD_SETSIZE) { fprintf (stderr, "Pipe file descriptor to large: %d", cpipe[0]); (void) close (cpipe[0]); (void) close (cpipe[1]); return 6; } { /* make pipe non-blocking, as we theoretically could otherwise block in the signal handler */ int flags = fcntl (cpipe[1], F_GETFL); if (-1 == flags) { fprintf (stderr, "Failed to read flags for pipe: %s", strerror (errno)); (void) close (cpipe[0]); (void) close (cpipe[1]); return 6; } flags |= O_NONBLOCK; if (0 != fcntl (cpipe[1], F_SETFL, flags)) { fprintf (stderr, "Failed to make pipe non-blocking: %s", strerror (errno)); (void) close (cpipe[0]); (void) close (cpipe[1]); return 6; } } if ( (SIG_ERR == signal (SIGTERM, &signal_handler)) || (SIG_ERR == signal (SIGINT, &signal_handler)) || (SIG_ERR == signal (SIGHUP, &signal_handler)) ) { fprintf (stderr, "Fatal: could not initialize signal handler: %s\n", strerror (errno)); (void) close (cpipe[0]); (void) close (cpipe[1]); return 7; } /* get interface name */ strncpy (dev, argv[1], IFNAMSIZ); dev[IFNAMSIZ - 1] = '\0'; /* now open virtual interface (first part that requires root) */ if (-1 == (fd_tun = init_tun (dev))) { fprintf (stderr, "Fatal: could not initialize tun-interface\n"); (void) signal (SIGTERM, SIG_IGN); (void) signal (SIGINT, SIG_IGN); (void) signal (SIGHUP, SIG_IGN); (void) close (cpipe[0]); (void) close (cpipe[1]); return 5; } /* now set interface addresses */ { const char *address = argv[2]; long prefix_len = atol (argv[3]); if ((prefix_len < 1) || (prefix_len > 127)) { fprintf (stderr, "Fatal: prefix_len out of range\n"); (void) signal (SIGTERM, SIG_IGN); (void) signal (SIGINT, SIG_IGN); (void) signal (SIGHUP, SIG_IGN); (void) close (cpipe[0]); (void) close (cpipe[1]); return 2; } set_address6 (dev, address, prefix_len); } { const char *address = argv[4]; const char *mask = argv[5]; set_address4 (dev, address, mask); } /* update routing tables -- next part why we need SUID! */ /* Forward everything from our EGID (which should only be held by the 'gnunet-service-dns') and with destination to port 53 on UDP, without hijacking */ r = 8; /* failed to fully setup routing table */ { char *const mangle_args[] = { "iptables", "-m", "owner", "-t", "mangle", "-I", "OUTPUT", "1", "-p", "udp", "--gid-owner", mygid, "--dport", DNS_PORT, "-j", "ACCEPT", NULL }; if (0 != fork_and_exec (sbin_iptables, mangle_args)) goto cleanup_rest; } /* Mark all of the other DNS traffic using our mark DNS_MARK */ { char *const mark_args[] = { "iptables", "-t", "mangle", "-I", "OUTPUT", "2", "-p", "udp", "--dport", DNS_PORT, "-j", "MARK", "--set-mark", DNS_MARK, NULL }; if (0 != fork_and_exec (sbin_iptables, mark_args)) goto cleanup_mangle_1; } /* Forward all marked DNS traffic to our DNS_TABLE */ { char *const forward_args[] = { "ip", "rule", "add", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL }; if (0 != fork_and_exec (sbin_ip, forward_args)) goto cleanup_mark_2; } /* Finally, add rule in our forwarding table to pass to our virtual interface */ { char *const route_args[] = { "ip", "route", "add", "default", "dev", dev, "table", DNS_TABLE, NULL }; if (0 != fork_and_exec (sbin_ip, route_args)) goto cleanup_forward_3; } /* drop privs *except* for the saved UID; this is not perfect, but better than doing nothing */ uid_t uid = getuid (); #ifdef HAVE_SETRESUID if (0 != setresuid (uid, uid, 0)) { fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno)); r = 24; goto cleanup_route_4; } #else /* Note: no 'setuid' here as we must keep our saved UID as root */ if (0 != seteuid (uid)) { fprintf (stderr, "Failed to seteuid: %s\n", strerror (errno)); r = 24; goto cleanup_route_4; } #endif r = 0; /* did fully setup routing table (if nothing else happens, we were successful!) */ /* now forward until we hit a problem */ run (fd_tun); /* now need to regain privs so we can remove the firewall rules we added! */ #ifdef HAVE_SETRESUID if (0 != setresuid (uid, 0, 0)) { fprintf (stderr, "Failed to setresuid back to root: %s\n", strerror (errno)); r = 40; goto cleanup_route_4; } #else if (0 != seteuid (0)) { fprintf (stderr, "Failed to seteuid back to root: %s\n", strerror (errno)); r = 40; goto cleanup_route_4; } #endif /* update routing tables again -- this is why we could not fully drop privs */ /* now undo updating of routing tables; normal exit or clean-up-on-error case */ cleanup_route_4: { char *const route_clean_args[] = { "ip", "route", "del", "default", "dev", dev, "table", DNS_TABLE, NULL }; if (0 != fork_and_exec (sbin_ip, route_clean_args)) r += 1; } cleanup_forward_3: { char *const forward_clean_args[] = { "ip", "rule", "del", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL }; if (0 != fork_and_exec (sbin_ip, forward_clean_args)) r += 2; } cleanup_mark_2: { char *const mark_clean_args[] = { "iptables", "-t", "mangle", "-D", "OUTPUT", "-p", "udp", "--dport", DNS_PORT, "-j", "MARK", "--set-mark", DNS_MARK, NULL }; if (0 != fork_and_exec (sbin_iptables, mark_clean_args)) r += 4; } cleanup_mangle_1: { char *const mangle_clean_args[] = { "iptables", "-m", "owner", "-t", "mangle", "-D", "OUTPUT", "-p", "udp", "--gid-owner", mygid, "--dport", DNS_PORT, "-j", "ACCEPT", NULL }; if (0 != fork_and_exec (sbin_iptables, mangle_clean_args)) r += 8; } cleanup_rest: /* close virtual interface */ (void) close (fd_tun); /* remove signal handler so we can close the pipes */ (void) signal (SIGTERM, SIG_IGN); (void) signal (SIGINT, SIG_IGN); (void) signal (SIGHUP, SIG_IGN); (void) close (cpipe[0]); (void) close (cpipe[1]); return r; } /* end of gnunet-helper-dns.c */ gnunet-0.9.3/src/dns/dns.conf.in0000644000175000017500000000320711760502552013364 00000000000000[dns] AUTOSTART = YES HOSTNAME = localhost HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-dns UNIXPATH = /tmp/gnunet-service-dns.sock # Access to this service can compromise all DNS queries in this # system. Thus access should be restricted to the same UID. # (see https://gnunet.org/gnunet-access-control-model) UNIX_MATCH_UID = YES UNIX_MATCH_GID = YES # As there is no sufficiently restrictive access control for TCP, # we never use it, even if @UNIXONLY@ is not set (just to be safe) @UNIXONLY@ PORT = 0 # This option should be set to YES to allow the DNS service to # perform lookups against the locally configured DNS resolver. # (set to "NO" if no normal ISP is locally available and thus # requests for normal ".com"/".org"/etc. must be routed via # the GNUnet VPN (the GNUNET PT daemon then needs to be configured # to intercept and route DNS queries via mesh). PROVIDE_EXIT = YES # Name of the virtual interface we use to intercept DNS traffic. IFNAME = gnunet-dns # Use RFC 3849-style documentation IPv6 address (RFC 4773 might provide an alternative in the future) # FIXME: or just default to a site-local address scope as we do for VPN!? IPV6ADDR = 2001:DB8::1 IPV6PREFIX = 126 # Use RFC 3927-style link-local address IPV4ADDR = 169.254.1.1 IPV4MASK = 255.255.0.0 # Enable GNUnet-wide DNS-EXIT service by setting this value to the IP address (IPv4 or IPv6) # of a DNS resolver to use. Only works if "PROVIDE_EXIT" is also set to YES. Must absolutely # NOT be an address of any of GNUnet's virtual tunnel interfaces. Use a well-known # public DNS resolver or your ISP's resolver from /etc/resolv.conf. # DNS_EXIT = 8.8.8.8 gnunet-0.9.3/src/dns/gnunet-dns-monitor.c0000644000175000017500000002326611760502551015245 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/dns/gnunet-dns-monitor.c * @brief Tool to monitor DNS queries * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_dns_service.h" #include "gnunet_dnsparser_lib.h" /** * Handle to transport service. */ static struct GNUNET_DNS_Handle *handle; /** * Option -i. */ static int inbound_only; /** * Option -o. */ static int outbound_only; /** * Global return value (0 success). */ static int ret; /** * Selected level of verbosity. */ static int verbosity; /** * Convert numeric DNS record type to a string. * * @param type type to convert * @return type as string, only valid until the next call to this function */ static const char * get_type (uint16_t type) { static char buf[6]; switch (type) { case GNUNET_DNSPARSER_TYPE_A: return "A"; case GNUNET_DNSPARSER_TYPE_NS: return "NS"; case GNUNET_DNSPARSER_TYPE_CNAME: return "CNAME"; case GNUNET_DNSPARSER_TYPE_SOA: return "SOA"; case GNUNET_DNSPARSER_TYPE_PTR: return "PTR"; case GNUNET_DNSPARSER_TYPE_MX: return "MX"; case GNUNET_DNSPARSER_TYPE_TXT: return "TXT"; case GNUNET_DNSPARSER_TYPE_AAAA: return "AAAA"; } GNUNET_snprintf (buf, sizeof (buf), "%u", (unsigned int) type); return buf; } /** * Convert numeric DNS record class to a string. * * @param class class to convert * @return class as string, only valid until the next call to this function */ static const char * get_class (uint16_t class) { static char buf[6]; switch (class) { case GNUNET_DNSPARSER_CLASS_INTERNET: return "IN"; case GNUNET_DNSPARSER_CLASS_CHAOS: return "CHAOS"; case GNUNET_DNSPARSER_CLASS_HESIOD: return "HESIOD"; } GNUNET_snprintf (buf, sizeof (buf), "%u", (unsigned int) class); return buf; } /** * Output the given DNS query to stdout. * * @param query query to display. */ static void display_query (const struct GNUNET_DNSPARSER_Query *query) { fprintf (stdout, "\t\t%s %s: %s\n", get_class (query->class), get_type (query->type), query->name); } /** * Output the given DNS record to stdout. * * @param record record to display. */ static void display_record (const struct GNUNET_DNSPARSER_Record *record) { const char *format; char buf[INET6_ADDRSTRLEN]; char *tmp; tmp = NULL; switch (record->type) { case GNUNET_DNSPARSER_TYPE_A: if (record->data.raw.data_len != sizeof (struct in_addr)) format = ""; else format = inet_ntop (AF_INET, record->data.raw.data, buf, sizeof (buf)); break; case GNUNET_DNSPARSER_TYPE_AAAA: if (record->data.raw.data_len != sizeof (struct in6_addr)) format = ""; else format = inet_ntop (AF_INET6, record->data.raw.data, buf, sizeof (buf)); break; case GNUNET_DNSPARSER_TYPE_NS: case GNUNET_DNSPARSER_TYPE_CNAME: case GNUNET_DNSPARSER_TYPE_PTR: format = record->data.hostname; break; case GNUNET_DNSPARSER_TYPE_SOA: if (record->data.soa == NULL) format = ""; else { GNUNET_asprintf (&tmp, "origin: %s, mail: %s, serial = %u, refresh = %u s, retry = %u s, expire = %u s, minimum = %u s", record->data.soa->mname, record->data.soa->rname, (unsigned int) record->data.soa->serial, (unsigned int) record->data.soa->refresh, (unsigned int) record->data.soa->retry, (unsigned int) record->data.soa->expire, (unsigned int) record->data.soa->minimum_ttl); format = tmp; } break; case GNUNET_DNSPARSER_TYPE_MX: if (record->data.mx == NULL) format = ""; else { GNUNET_asprintf (&tmp, "%u: %s", record->data.mx->preference, record->data.mx->mxhost); format = tmp; } break; case GNUNET_DNSPARSER_TYPE_TXT: GNUNET_asprintf (&tmp, "%.*s", (unsigned int) record->data.raw.data_len, record->data.raw.data); format = tmp; break; default: format = ""; break; } fprintf (stdout, "\t\t%s %s: %s = %s (%u s)\n", get_class (record->class), get_type (record->type), record->name, format, (unsigned int) (GNUNET_TIME_absolute_get_remaining (record->expiration_time).rel_value / 1000)); GNUNET_free_non_null (tmp); } /** * Signature of a function that is called whenever the DNS service * encounters a DNS request and needs to do something with it. The * function has then the chance to generate or modify the response by * calling one of the three "GNUNET_DNS_request_*" continuations. * * When a request is intercepted, this function is called first to * give the client a chance to do the complete address resolution; * "rdata" will be NULL for this first call for a DNS request, unless * some other client has already filled in a response. * * If multiple clients exist, all of them are called before the global * DNS. The global DNS is only called if all of the clients' * functions call GNUNET_DNS_request_forward. Functions that call * GNUNET_DNS_request_forward will be called again before a final * response is returned to the application. If any of the clients' * functions call GNUNET_DNS_request_drop, the response is dropped. * * @param cls closure * @param rh request handle to user for reply * @param request_length number of bytes in request * @param request udp payload of the DNS request */ static void display_request (void *cls, struct GNUNET_DNS_RequestHandle *rh, size_t request_length, const char *request) { static const char *return_codes[] = { "No error", "Format error", "Server failure", "Name error", "Not implemented", "Refused", "YXDomain", "YXRRset", "NXRRset", "NOT AUTH", "NOT ZONE", "", "", "", "", "" }; static const char *op_codes[] = { "Query", "Inverse query", "Status", "", "", "", "", "", "", "", "", "", "", "", "", "" }; struct GNUNET_DNSPARSER_Packet *p; unsigned int i; p = GNUNET_DNSPARSER_parse (request, request_length); if (NULL == p) { fprintf (stderr, "Received malformed DNS packet!\n"); // FIXME: drop instead? GNUNET_DNS_request_forward (rh); return; } fprintf (stdout, "%s with ID: %5u Flags: %s%s%s%s%s%s, Return Code: %s, Opcode: %s\n", p->flags.query_or_response ? "Response" : "Query", p->id, p->flags.recursion_desired ? "RD " : "", p->flags.message_truncated ? "MT " : "", p->flags.authoritative_answer ? "AA " : "", p->flags.checking_disabled ? "CD " : "", p->flags.authenticated_data ? "AD " : "", p->flags.recursion_available ? "RA " : "", return_codes[p->flags.return_code & 15], op_codes[p->flags.opcode & 15]); if (p->num_queries > 0) fprintf (stdout, "\tQueries:\n"); for (i=0;inum_queries;i++) display_query (&p->queries[i]); if (p->num_answers > 0) fprintf (stdout, "\tAnswers:\n"); for (i=0;inum_answers;i++) display_record (&p->answers[i]); fprintf (stdout, "\n"); GNUNET_DNSPARSER_free_packet (p); GNUNET_DNS_request_forward (rh); } /** * Shutdown. */ static void do_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (NULL != handle) { GNUNET_DNS_disconnect (handle); handle = NULL; } } /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param cfg configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { enum GNUNET_DNS_Flags flags; flags = GNUNET_DNS_FLAG_REQUEST_MONITOR | GNUNET_DNS_FLAG_RESPONSE_MONITOR; if (inbound_only | outbound_only) flags = 0; if (inbound_only) flags |= GNUNET_DNS_FLAG_REQUEST_MONITOR; if (outbound_only) flags |= GNUNET_DNS_FLAG_RESPONSE_MONITOR; handle = GNUNET_DNS_connect (cfg, flags, &display_request, NULL); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &do_disconnect, NULL); } int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { {'i', "inbound-only", NULL, gettext_noop ("only monitor DNS queries"), 0, &GNUNET_GETOPT_set_one, &inbound_only}, {'o', "outbound-only", NULL, gettext_noop ("only monitor DNS replies"), 0, &GNUNET_GETOPT_set_one, &outbound_only}, GNUNET_GETOPT_OPTION_VERBOSE (&verbosity), GNUNET_GETOPT_OPTION_END }; return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-dns-monitor", gettext_noop ("Monitor DNS queries."), options, &run, NULL)) ? ret : 1; } /* end of gnunet-dns-monitor.c */ gnunet-0.9.3/src/dns/dns_api.c0000644000175000017500000003150111760502551013102 00000000000000/* This file is part of GNUnet (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dns/dns_api.c * @brief API to access the DNS service. * @author Christian Grothoff */ #include "platform.h" #include "gnunet_dns_service.h" #include "dns.h" /** * Reply to send to service. */ struct ReplyQueueEntry { /** * Kept in DLL. */ struct ReplyQueueEntry *next; /** * Kept in DLL. */ struct ReplyQueueEntry *prev; /** * Message to transmit, allocated at the end of this struct. */ const struct GNUNET_MessageHeader *msg; }; /** * Handle to identify an individual DNS request. */ struct GNUNET_DNS_RequestHandle { /** * Handle to DNS API. */ struct GNUNET_DNS_Handle *dh; /** * Stored in network byte order (as for us, it is just a random number). */ uint64_t request_id; /** * Re-connect counter, to make sure we did not reconnect in the meantime. */ uint32_t generation; }; /** * DNS handle */ struct GNUNET_DNS_Handle { /** * Connection to DNS service, or NULL. */ struct GNUNET_CLIENT_Connection *dns_connection; /** * Handle to active transmission request, or NULL. */ struct GNUNET_CLIENT_TransmitHandle *dns_transmit_handle; /** * Configuration to use. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Function to call to get replies. */ GNUNET_DNS_RequestHandler rh; /** * Closure for 'rh'. */ void *rh_cls; /** * Head of replies to transmit. */ struct ReplyQueueEntry *rq_head; /** * Tail of replies to transmit. */ struct ReplyQueueEntry *rq_tail; /** * Task to reconnect to the service. */ GNUNET_SCHEDULER_TaskIdentifier reconnect_task; /** * Re-connect counter, to make sure we did not reconnect in the meantime. */ uint32_t generation; /** * Flags for events we care about. */ enum GNUNET_DNS_Flags flags; /** * Did we start the receive loop yet? */ int in_receive; /** * Number of GNUNET_DNS_RequestHandles we have outstanding. Must be 0 before * we can be disconnected. */ unsigned int pending_requests; }; /** * Add the given reply to our transmission queue and trigger sending if needed. * * @param dh handle with the connection * @param qe reply to queue */ static void queue_reply (struct GNUNET_DNS_Handle *dh, struct ReplyQueueEntry *qe); /** * Reconnect to the DNS service. * * @param cls handle with the connection to connect * @param tc scheduler context (unused) */ static void reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_DNS_Handle *dh = cls; struct ReplyQueueEntry *qe; struct GNUNET_DNS_Register *msg; dh->reconnect_task = GNUNET_SCHEDULER_NO_TASK; dh->dns_connection = GNUNET_CLIENT_connect ("dns", dh->cfg); if (NULL == dh->dns_connection) return; dh->generation++; qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + sizeof (struct GNUNET_DNS_Register)); msg = (struct GNUNET_DNS_Register*) &qe[1]; qe->msg = &msg->header; msg->header.size = htons (sizeof (struct GNUNET_DNS_Register)); msg->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT); msg->flags = htonl (dh->flags); queue_reply (dh, qe); } /** * Disconnect from the DNS service. * * @param dh handle with the connection to disconnect */ static void disconnect (struct GNUNET_DNS_Handle *dh) { struct ReplyQueueEntry *qe; if (NULL != dh->dns_transmit_handle) { GNUNET_CLIENT_notify_transmit_ready_cancel (dh->dns_transmit_handle); dh->dns_transmit_handle = NULL; } if (NULL != dh->dns_connection) { GNUNET_CLIENT_disconnect (dh->dns_connection); dh->dns_connection = NULL; } while (NULL != (qe = dh->rq_head)) { GNUNET_CONTAINER_DLL_remove (dh->rq_head, dh->rq_tail, qe); GNUNET_free (qe); } dh->in_receive = GNUNET_NO; } /** * This receives packets from the DNS service and calls the application to * handle it. * * @param cls the struct GNUNET_DNS_Handle * @param msg message from the service (request) */ static void request_handler (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_DNS_Handle *dh = cls; const struct GNUNET_DNS_Request *req; struct GNUNET_DNS_RequestHandle *rh; size_t payload_length; /* the service disconnected, reconnect after short wait */ if (msg == NULL) { disconnect (dh); dh->reconnect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect, dh); return; } if ( (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST) || (ntohs (msg->size) < sizeof (struct GNUNET_DNS_Request)) ) { /* the service did something strange, reconnect immediately */ GNUNET_break (0); disconnect (dh); dh->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, dh); return; } req = (const struct GNUNET_DNS_Request *) msg; GNUNET_break (ntohl (req->reserved) == 0); payload_length = ntohs (req->header.size) - sizeof (struct GNUNET_DNS_Request); GNUNET_CLIENT_receive (dh->dns_connection, &request_handler, dh, GNUNET_TIME_UNIT_FOREVER_REL); /* finally, pass request to callback for answers */ rh = GNUNET_malloc (sizeof (struct GNUNET_DNS_RequestHandle)); rh->dh =dh; rh->request_id = req->request_id; rh->generation = dh->generation; dh->pending_requests++; dh->rh (dh->rh_cls, rh, payload_length, (const char*) &req[1]); } /** * Callback called by notify_transmit_ready; sends DNS replies * to the DNS service. * * @param cls the struct GNUNET_DNS_Handle * @param size number of bytes available in buf * @param buf where to copy the message for transmission * @return number of bytes copied to buf */ static size_t send_response (void *cls, size_t size, void *buf) { struct GNUNET_DNS_Handle *dh = cls; struct ReplyQueueEntry *qe; size_t len; dh->dns_transmit_handle = NULL; if (NULL == buf) { disconnect (dh); dh->reconnect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect, dh); return 0; } qe = dh->rq_head; if (NULL == qe) return 0; len = ntohs (qe->msg->size); if (len > size) { dh->dns_transmit_handle = GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection, len, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_NO, &send_response, dh); return 0; } memcpy (buf, qe->msg, len); GNUNET_CONTAINER_DLL_remove (dh->rq_head, dh->rq_tail, qe); GNUNET_free (qe); if (GNUNET_NO == dh->in_receive) { dh->in_receive = GNUNET_YES; GNUNET_CLIENT_receive (dh->dns_connection, &request_handler, dh, GNUNET_TIME_UNIT_FOREVER_REL); } if (NULL != (qe = dh->rq_head)) { dh->dns_transmit_handle = GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection, ntohs (qe->msg->size), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_NO, &send_response, dh); } return len; } /** * Add the given reply to our transmission queue and trigger sending if needed. * * @param dh handle with the connection * @param qe reply to queue */ static void queue_reply (struct GNUNET_DNS_Handle *dh, struct ReplyQueueEntry *qe) { if (NULL == dh->dns_connection) { GNUNET_free (qe); return; } GNUNET_CONTAINER_DLL_insert_tail (dh->rq_head, dh->rq_tail, qe); if (NULL != dh->dns_transmit_handle) return; /* trigger sending */ dh->dns_transmit_handle = GNUNET_CLIENT_notify_transmit_ready (dh->dns_connection, ntohs (dh->rq_head->msg->size), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_NO, &send_response, dh); } /** * If a GNUNET_DNS_RequestHandler calls this function, the request is * given to other clients or the global DNS for resolution. Once a * global response has been obtained, the request handler is AGAIN * called to give it a chance to observe and modify the response after * the "normal" resolution. It is not legal for the request handler * to call this function if a response is already present. * * @param rh request that should now be forwarded */ void GNUNET_DNS_request_forward (struct GNUNET_DNS_RequestHandle *rh) { struct ReplyQueueEntry *qe; struct GNUNET_DNS_Response *resp; GNUNET_assert (0 < rh->dh->pending_requests--); if (rh->generation != rh->dh->generation) { GNUNET_free (rh); return; } qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + sizeof (struct GNUNET_DNS_Response)); resp = (struct GNUNET_DNS_Response*) &qe[1]; qe->msg = &resp->header; resp->header.size = htons (sizeof (struct GNUNET_DNS_Response)); resp->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE); resp->drop_flag = htonl (1); resp->request_id = rh->request_id; queue_reply (rh->dh, qe); GNUNET_free (rh); } /** * If a GNUNET_DNS_RequestHandler calls this function, the request is * to be dropped and no response should be generated. * * @param rh request that should now be dropped */ void GNUNET_DNS_request_drop (struct GNUNET_DNS_RequestHandle *rh) { struct ReplyQueueEntry *qe; struct GNUNET_DNS_Response *resp; GNUNET_assert (0 < rh->dh->pending_requests--); if (rh->generation != rh->dh->generation) { GNUNET_free (rh); return; } qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + sizeof (struct GNUNET_DNS_Response)); resp = (struct GNUNET_DNS_Response*) &qe[1]; qe->msg = &resp->header; resp->header.size = htons (sizeof (struct GNUNET_DNS_Response)); resp->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE); resp->request_id = rh->request_id; resp->drop_flag = htonl (0); queue_reply (rh->dh, qe); GNUNET_free (rh); } /** * If a GNUNET_DNS_RequestHandler calls this function, the request is * supposed to be answered with the data provided to this call (with * the modifications the function might have made). * * @param rh request that should now be answered * @param reply_length size of reply (uint16_t to force sane size) * @param reply reply data */ void GNUNET_DNS_request_answer (struct GNUNET_DNS_RequestHandle *rh, uint16_t reply_length, const char *reply) { struct ReplyQueueEntry *qe; struct GNUNET_DNS_Response *resp; GNUNET_assert (0 < rh->dh->pending_requests--); if (rh->generation != rh->dh->generation) { GNUNET_free (rh); return; } if (reply_length + sizeof (struct GNUNET_DNS_Response) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); GNUNET_free (rh); return; } qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + sizeof (struct GNUNET_DNS_Response) + reply_length); resp = (struct GNUNET_DNS_Response*) &qe[1]; qe->msg = &resp->header; resp->header.size = htons (sizeof (struct GNUNET_DNS_Response) + reply_length); resp->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE); resp->drop_flag = htonl (2); resp->request_id = rh->request_id; memcpy (&resp[1], reply, reply_length); queue_reply (rh->dh, qe); GNUNET_free (rh); } /** * Connect to the service-dns * * @param cfg configuration to use * @param flags when to call rh * @param rh function to call with DNS requests * @param rh_cls closure to pass to rh * @return DNS handle */ struct GNUNET_DNS_Handle * GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, enum GNUNET_DNS_Flags flags, GNUNET_DNS_RequestHandler rh, void *rh_cls) { struct GNUNET_DNS_Handle *dh; dh = GNUNET_malloc (sizeof (struct GNUNET_DNS_Handle)); dh->cfg = cfg; dh->flags = flags; dh->rh = rh; dh->rh_cls = rh_cls; dh->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, dh); return dh; } /** * Disconnect from the DNS service. * * @param dh DNS handle */ void GNUNET_DNS_disconnect (struct GNUNET_DNS_Handle *dh) { if (GNUNET_SCHEDULER_NO_TASK != dh->reconnect_task) { GNUNET_SCHEDULER_cancel (dh->reconnect_task); dh->reconnect_task = GNUNET_SCHEDULER_NO_TASK; } disconnect (dh); /* make sure client has no pending requests left over! */ GNUNET_assert (0 == dh->pending_requests); GNUNET_free (dh); } /* end of dns_api_new.c */ gnunet-0.9.3/src/dns/plugin_block_dns.c0000644000175000017500000001257011760516110015002 00000000000000/* This file is part of GNUnet (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dns/plugin_block_dns.c * @brief block plugin for storing .gnunet-bindings * @author Philipp Tölke */ #include "platform.h" #include "gnunet_block_plugin.h" #include "block_dns.h" #include "gnunet_signatures.h" #define DEBUG_DHT GNUNET_EXTRA_LOGGING /** * Function called to validate a reply or a request. For * request evaluation, simply pass "NULL" for the reply_block. * * @param cls closure * @param type block type * @param query original query (hash) * @param bf pointer to bloom filter associated with query; possibly updated (!) * @param bf_mutator mutation value for bf * @param xquery extended query data (can be NULL, depending on type) * @param xquery_size number of bytes in xquery * @param reply_block response to validate * @param reply_block_size number of bytes in reply block * @return characterization of result */ static enum GNUNET_BLOCK_EvaluationResult block_plugin_dns_evaluate (void *cls, enum GNUNET_BLOCK_Type type, const GNUNET_HashCode * query, struct GNUNET_CONTAINER_BloomFilter **bf, int32_t bf_mutator, const void *xquery, size_t xquery_size, const void *reply_block, size_t reply_block_size) { switch (type) { case GNUNET_BLOCK_TYPE_DNS: if (xquery_size != 0) return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; if (reply_block_size == 0) return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; if (reply_block_size != sizeof (struct GNUNET_DNS_Record)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "DNS-Block is invalid: reply_block_size=%d != %d\n", reply_block_size, sizeof (struct GNUNET_DNS_Record)); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } const struct GNUNET_DNS_Record *rec = reply_block; if (ntohl (rec->purpose.size) != sizeof (struct GNUNET_DNS_Record) - sizeof (struct GNUNET_CRYPTO_RsaSignature)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "DNS-Block is invalid: rec->purpose.size=%d != %d\n", ntohl (rec->purpose.size), sizeof (struct GNUNET_DNS_Record) - sizeof (struct GNUNET_CRYPTO_RsaSignature)); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (rec->expiration_time)).rel_value) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "DNS-Block is invalid: Timeout\n"); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } if (GNUNET_OK != GNUNET_CRYPTO_rsa_verify (htonl (GNUNET_SIGNATURE_PURPOSE_DNS_RECORD), &rec->purpose, &rec->signature, &rec->peer)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "DNS-Block is invalid: invalid signature\n"); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } /* How to decide whether there are no more? */ return GNUNET_BLOCK_EVALUATION_OK_MORE; default: return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; } } /** * Function called to obtain the key for a block. * * @param cls closure * @param type block type * @param block block to get the key for * @param block_size number of bytes in block * @param key set to the key (query) for the given block * @return GNUNET_OK on success, GNUNET_SYSERR if type not supported * (or if extracting a key from a block of this type does not work) */ static int block_plugin_dns_get_key (void *cls, enum GNUNET_BLOCK_Type type, const void *block, size_t block_size, GNUNET_HashCode * key) { if (type != GNUNET_BLOCK_TYPE_DNS) return GNUNET_SYSERR; const struct GNUNET_DNS_Record *rec = block; memcpy (key, &rec->service_descriptor, sizeof (GNUNET_HashCode)); return GNUNET_OK; } /** * Entry point for the plugin. */ void * libgnunet_plugin_block_dns_init (void *cls) { static enum GNUNET_BLOCK_Type types[] = { GNUNET_BLOCK_TYPE_DNS, GNUNET_BLOCK_TYPE_ANY /* end of list */ }; struct GNUNET_BLOCK_PluginFunctions *api; api = GNUNET_malloc (sizeof (struct GNUNET_BLOCK_PluginFunctions)); api->evaluate = &block_plugin_dns_evaluate; api->get_key = &block_plugin_dns_get_key; api->types = types; return api; } /** * Exit point from the plugin. */ void * libgnunet_plugin_block_dns_done (void *cls) { struct GNUNET_TRANSPORT_PluginFunctions *api = cls; GNUNET_free (api); return NULL; } /* end of plugin_block_dns.c */ gnunet-0.9.3/src/dns/dnsparser.c0000644000175000017500000005222111760502551013470 00000000000000/* This file is part of GNUnet (C) 2010, 2011, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dns/dnsparser.c * @brief helper library to parse DNS packets. * @author Philipp Toelke * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_dnsparser_lib.h" // DNS-Stuff GNUNET_NETWORK_STRUCT_BEGIN /* FIXME: replace this one with the one from tcpip_tun.h! */ struct GNUNET_TUN_DnsHeader { uint16_t id GNUNET_PACKED; struct GNUNET_DNSPARSER_Flags flags; uint16_t query_count GNUNET_PACKED; // number of questions uint16_t answer_rcount GNUNET_PACKED; // number of answers uint16_t authority_rcount GNUNET_PACKED; // number of authority-records uint16_t additional_rcount GNUNET_PACKED; // number of additional records }; struct query_line { uint16_t type GNUNET_PACKED; uint16_t class GNUNET_PACKED; }; struct record_line { uint16_t type GNUNET_PACKED; uint16_t class GNUNET_PACKED; uint32_t ttl GNUNET_PACKED; uint16_t data_len GNUNET_PACKED; }; struct soa_data { uint32_t serial GNUNET_PACKED; uint32_t refresh GNUNET_PACKED; uint32_t retry GNUNET_PACKED; uint32_t expire GNUNET_PACKED; uint32_t minimum GNUNET_PACKED; }; GNUNET_NETWORK_STRUCT_END /** * Parse name inside of a DNS query or record. * * @param udp_payload entire UDP payload * @param udp_payload_length length of udp_payload * @param off pointer to the offset of the name to parse in the udp_payload (to be * incremented by the size of the name) * @param depth current depth of our recursion (to prevent stack overflow) * @return name as 0-terminated C string on success, NULL if the payload is malformed */ static char * parse_name (const char *udp_payload, size_t udp_payload_length, size_t *off, unsigned int depth) { const uint8_t *input = (const uint8_t *) udp_payload; char *ret; char *tmp; char *xstr; uint8_t len; size_t xoff; ret = GNUNET_strdup (""); while (1) { if (*off >= udp_payload_length) goto error; len = input[*off]; if (0 == len) { (*off)++; break; } if (len < 64) { if (*off + 1 + len > udp_payload_length) goto error; GNUNET_asprintf (&tmp, "%s%.*s.", ret, (int) len, &udp_payload[*off + 1]); GNUNET_free (ret); ret = tmp; *off += 1 + len; } else if ((64 | 128) == (len & (64 | 128)) ) { if (depth > 32) goto error; /* hard bound on stack to prevent "infinite" recursion, disallow! */ /* pointer to string */ if (*off + 1 > udp_payload_length) goto error; xoff = ((len - (64 | 128)) << 8) + input[*off+1]; xstr = parse_name (udp_payload, udp_payload_length, &xoff, depth + 1); if (NULL == xstr) goto error; GNUNET_asprintf (&tmp, "%s%s.", ret, xstr); GNUNET_free (ret); GNUNET_free (xstr); ret = tmp; if (strlen (ret) > udp_payload_length) goto error; /* we are looping (building an infinite string) */ *off += 2; /* pointers always terminate names */ break; } else { /* neither pointer nor inline string, not supported... */ goto error; } } if (0 < strlen(ret)) ret[strlen(ret)-1] = '\0'; /* eat tailing '.' */ return ret; error: GNUNET_free (ret); return NULL; } /** * Parse a DNS query entry. * * @param udp_payload entire UDP payload * @param udp_payload_length length of udp_payload * @param off pointer to the offset of the query to parse in the udp_payload (to be * incremented by the size of the query) * @param q where to write the query information * @return GNUNET_OK on success, GNUNET_SYSERR if the query is malformed */ static int parse_query (const char *udp_payload, size_t udp_payload_length, size_t *off, struct GNUNET_DNSPARSER_Query *q) { char *name; struct query_line ql; name = parse_name (udp_payload, udp_payload_length, off, 0); if (NULL == name) return GNUNET_SYSERR; q->name = name; if (*off + sizeof (struct query_line) > udp_payload_length) return GNUNET_SYSERR; memcpy (&ql, &udp_payload[*off], sizeof (ql)); *off += sizeof (ql); q->type = ntohs (ql.type); q->class = ntohs (ql.class); return GNUNET_OK; } /** * Parse a DNS record entry. * * @param udp_payload entire UDP payload * @param udp_payload_length length of udp_payload * @param off pointer to the offset of the record to parse in the udp_payload (to be * incremented by the size of the record) * @param r where to write the record information * @return GNUNET_OK on success, GNUNET_SYSERR if the record is malformed */ static int parse_record (const char *udp_payload, size_t udp_payload_length, size_t *off, struct GNUNET_DNSPARSER_Record *r) { char *name; struct record_line rl; size_t old_off; struct soa_data soa; uint16_t mxpref; uint16_t data_len; name = parse_name (udp_payload, udp_payload_length, off, 0); if (NULL == name) return GNUNET_SYSERR; r->name = name; if (*off + sizeof (struct record_line) > udp_payload_length) return GNUNET_SYSERR; memcpy (&rl, &udp_payload[*off], sizeof (rl)); (*off) += sizeof (rl); r->type = ntohs (rl.type); r->class = ntohs (rl.class); r->expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, ntohl (rl.ttl))); data_len = ntohs (rl.data_len); if (*off + data_len > udp_payload_length) return GNUNET_SYSERR; switch (r->type) { case GNUNET_DNSPARSER_TYPE_NS: case GNUNET_DNSPARSER_TYPE_CNAME: case GNUNET_DNSPARSER_TYPE_PTR: old_off = *off; r->data.hostname = parse_name (udp_payload, udp_payload_length, off, 0); if ( (NULL == r->data.hostname) || (old_off + data_len != *off) ) return GNUNET_SYSERR; return GNUNET_OK; case GNUNET_DNSPARSER_TYPE_SOA: old_off = *off; r->data.soa = GNUNET_malloc (sizeof (struct GNUNET_DNSPARSER_SoaRecord)); r->data.soa->mname = parse_name (udp_payload, udp_payload_length, off, 0); r->data.soa->rname = parse_name (udp_payload, udp_payload_length, off, 0); if ( (NULL == r->data.soa->mname) || (NULL == r->data.soa->rname) || (*off + sizeof (struct soa_data) > udp_payload_length) ) return GNUNET_SYSERR; memcpy (&soa, &udp_payload[*off], sizeof (struct soa_data)); r->data.soa->serial = ntohl (soa.serial); r->data.soa->refresh = ntohl (soa.refresh); r->data.soa->retry = ntohl (soa.retry); r->data.soa->expire = ntohl (soa.expire); r->data.soa->minimum_ttl = ntohl (soa.minimum); (*off) += sizeof (struct soa_data); if (old_off + data_len != *off) return GNUNET_SYSERR; return GNUNET_OK; case GNUNET_DNSPARSER_TYPE_MX: old_off = *off; if (*off + sizeof (uint16_t) > udp_payload_length) return GNUNET_SYSERR; memcpy (&mxpref, &udp_payload[*off], sizeof (uint16_t)); (*off) += sizeof (uint16_t); r->data.mx = GNUNET_malloc (sizeof (struct GNUNET_DNSPARSER_MxRecord)); r->data.mx->preference = ntohs (mxpref); r->data.mx->mxhost = parse_name (udp_payload, udp_payload_length, off, 0); if (old_off + data_len != *off) return GNUNET_SYSERR; return GNUNET_OK; default: r->data.raw.data = GNUNET_malloc (data_len); r->data.raw.data_len = data_len; memcpy (r->data.raw.data, &udp_payload[*off], data_len); break; } (*off) += data_len; return GNUNET_OK; } /** * Parse a UDP payload of a DNS packet in to a nice struct for further * processing and manipulation. * * @param udp_payload wire-format of the DNS packet * @param udp_payload_length number of bytes in udp_payload * @return NULL on error, otherwise the parsed packet */ struct GNUNET_DNSPARSER_Packet * GNUNET_DNSPARSER_parse (const char *udp_payload, size_t udp_payload_length) { struct GNUNET_DNSPARSER_Packet *p; const struct GNUNET_TUN_DnsHeader *dns; size_t off; unsigned int n; unsigned int i; if (udp_payload_length < sizeof (struct GNUNET_TUN_DnsHeader)) return NULL; dns = (const struct GNUNET_TUN_DnsHeader *) udp_payload; off = sizeof (struct GNUNET_TUN_DnsHeader); p = GNUNET_malloc (sizeof (struct GNUNET_DNSPARSER_Packet)); p->flags = dns->flags; p->id = dns->id; n = ntohs (dns->query_count); if (n > 0) { p->queries = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Query)); p->num_queries = n; for (i=0;iqueries[i])) goto error; } n = ntohs (dns->answer_rcount); if (n > 0) { p->answers = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record)); p->num_answers = n; for (i=0;ianswers[i])) goto error; } n = ntohs (dns->authority_rcount); if (n > 0) { p->authority_records = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record)); p->num_authority_records = n; for (i=0;iauthority_records[i])) goto error; } n = ntohs (dns->additional_rcount); if (n > 0) { p->additional_records = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record)); p->num_additional_records = n; for (i=0;iadditional_records[i])) goto error; } return p; error: GNUNET_DNSPARSER_free_packet (p); return NULL; } /** * Free SOA information record. * * @param soa record to free */ static void free_soa (struct GNUNET_DNSPARSER_SoaRecord *soa) { if (NULL == soa) return; GNUNET_free_non_null (soa->mname); GNUNET_free_non_null (soa->rname); GNUNET_free (soa); } /** * Free MX information record. * * @param mx record to free */ static void free_mx (struct GNUNET_DNSPARSER_MxRecord *mx) { if (NULL == mx) return; GNUNET_free_non_null (mx->mxhost); GNUNET_free (mx); } static void free_record (struct GNUNET_DNSPARSER_Record *r) { GNUNET_free_non_null (r->name); switch (r->type) { case GNUNET_DNSPARSER_TYPE_MX: free_mx (r->data.mx); break; case GNUNET_DNSPARSER_TYPE_SOA: free_soa (r->data.soa); break; case GNUNET_DNSPARSER_TYPE_NS: case GNUNET_DNSPARSER_TYPE_CNAME: case GNUNET_DNSPARSER_TYPE_PTR: GNUNET_free_non_null (r->data.hostname); break; default: GNUNET_free_non_null (r->data.raw.data); break; } } /** * Free memory taken by a packet. * * @param p packet to free */ void GNUNET_DNSPARSER_free_packet (struct GNUNET_DNSPARSER_Packet *p) { unsigned int i; for (i=0;inum_queries;i++) GNUNET_free_non_null (p->queries[i].name); GNUNET_free_non_null (p->queries); for (i=0;inum_answers;i++) free_record (&p->answers[i]); GNUNET_free_non_null (p->answers); for (i=0;inum_authority_records;i++) free_record (&p->authority_records[i]); GNUNET_free_non_null (p->authority_records); for (i=0;inum_additional_records;i++) free_record (&p->additional_records[i]); GNUNET_free_non_null (p->additional_records); GNUNET_free (p); } /* ********************** DNS packet assembly code **************** */ /** * Add a DNS name to the UDP packet at the given location. * * @param dst where to write the name * @param dst_len number of bytes in dst * @param off pointer to offset where to write the name (increment by bytes used) * must not be changed if there is an error * @param name name to write * @return GNUNET_SYSERR if 'name' is invalid * GNUNET_NO if 'name' did not fit * GNUNET_OK if 'name' was added to 'dst' */ static int add_name (char *dst, size_t dst_len, size_t *off, const char *name) { const char *dot; size_t start; size_t pos; size_t len; if (NULL == name) return GNUNET_SYSERR; start = *off; if (start + strlen (name) + 2 > dst_len) return GNUNET_NO; pos = start; do { dot = strchr (name, '.'); if (NULL == dot) len = strlen (name); else len = dot - name; if ( (len >= 64) || (len == 0) ) return GNUNET_NO; /* segment too long or empty */ dst[pos++] = (char) (uint8_t) len; memcpy (&dst[pos], name, len); pos += len; name += len + 1; /* also skip dot */ } while (NULL != dot); dst[pos++] = '\0'; /* terminator */ *off = pos; return GNUNET_OK; } /** * Add a DNS query to the UDP packet at the given location. * * @param dst where to write the query * @param dst_len number of bytes in dst * @param off pointer to offset where to write the query (increment by bytes used) * must not be changed if there is an error * @param query query to write * @return GNUNET_SYSERR if 'query' is invalid * GNUNET_NO if 'query' did not fit * GNUNET_OK if 'query' was added to 'dst' */ static int add_query (char *dst, size_t dst_len, size_t *off, const struct GNUNET_DNSPARSER_Query *query) { int ret; struct query_line ql; ret = add_name (dst, dst_len - sizeof (struct query_line), off, query->name); if (ret != GNUNET_OK) return ret; ql.type = htons (query->type); ql.class = htons (query->class); memcpy (&dst[*off], &ql, sizeof (ql)); (*off) += sizeof (ql); return GNUNET_OK; } /** * Add an MX record to the UDP packet at the given location. * * @param dst where to write the mx record * @param dst_len number of bytes in dst * @param off pointer to offset where to write the mx information (increment by bytes used); * can also change if there was an error * @param mx mx information to write * @return GNUNET_SYSERR if 'mx' is invalid * GNUNET_NO if 'mx' did not fit * GNUNET_OK if 'mx' was added to 'dst' */ static int add_mx (char *dst, size_t dst_len, size_t *off, const struct GNUNET_DNSPARSER_MxRecord *mx) { uint16_t mxpref; if (*off + sizeof (uint16_t) > dst_len) return GNUNET_NO; mxpref = htons (mx->preference); memcpy (&dst[*off], &mxpref, sizeof (mxpref)); (*off) += sizeof (mxpref); return add_name (dst, dst_len, off, mx->mxhost); } /** * Add an SOA record to the UDP packet at the given location. * * @param dst where to write the SOA record * @param dst_len number of bytes in dst * @param off pointer to offset where to write the SOA information (increment by bytes used) * can also change if there was an error * @param soa SOA information to write * @return GNUNET_SYSERR if 'soa' is invalid * GNUNET_NO if 'soa' did not fit * GNUNET_OK if 'soa' was added to 'dst' */ static int add_soa (char *dst, size_t dst_len, size_t *off, const struct GNUNET_DNSPARSER_SoaRecord *soa) { struct soa_data sd; int ret; if ( (GNUNET_OK != (ret = add_name (dst, dst_len, off, soa->mname))) || (GNUNET_OK != (ret = add_name (dst, dst_len, off, soa->rname)) ) ) return ret; if (*off + sizeof (struct soa_data) > dst_len) return GNUNET_NO; sd.serial = htonl (soa->serial); sd.refresh = htonl (soa->refresh); sd.retry = htonl (soa->retry); sd.expire = htonl (soa->expire); sd.minimum = htonl (soa->minimum_ttl); memcpy (&dst[*off], &sd, sizeof (sd)); (*off) += sizeof (sd); return GNUNET_OK; } /** * Add a DNS record to the UDP packet at the given location. * * @param dst where to write the query * @param dst_len number of bytes in dst * @param off pointer to offset where to write the query (increment by bytes used) * must not be changed if there is an error * @param record record to write * @return GNUNET_SYSERR if 'record' is invalid * GNUNET_NO if 'record' did not fit * GNUNET_OK if 'record' was added to 'dst' */ static int add_record (char *dst, size_t dst_len, size_t *off, const struct GNUNET_DNSPARSER_Record *record) { int ret; size_t start; size_t pos; struct record_line rl; start = *off; ret = add_name (dst, dst_len - sizeof (struct record_line), off, record->name); if (ret != GNUNET_OK) return ret; /* '*off' is now the position where we will need to write the record line */ pos = *off + sizeof (struct record_line); switch (record->type) { case GNUNET_DNSPARSER_TYPE_MX: ret = add_mx (dst, dst_len, &pos, record->data.mx); break; case GNUNET_DNSPARSER_TYPE_SOA: ret = add_soa (dst, dst_len, &pos, record->data.soa); break; case GNUNET_DNSPARSER_TYPE_NS: case GNUNET_DNSPARSER_TYPE_CNAME: case GNUNET_DNSPARSER_TYPE_PTR: ret = add_name (dst, dst_len, &pos, record->data.hostname); break; default: if (pos + record->data.raw.data_len > dst_len) { ret = GNUNET_NO; break; } memcpy (&dst[pos], record->data.raw.data, record->data.raw.data_len); pos += record->data.raw.data_len; ret = GNUNET_OK; break; } if (ret != GNUNET_OK) { *off = start; return GNUNET_NO; } if (pos - (*off + sizeof (struct record_line)) > UINT16_MAX) { /* record data too long */ *off = start; return GNUNET_NO; } rl.type = htons (record->type); rl.class = htons (record->class); rl.ttl = htonl (GNUNET_TIME_absolute_get_remaining (record->expiration_time).rel_value / 1000); /* in seconds */ rl.data_len = htons ((uint16_t) (pos - (*off + sizeof (struct record_line)))); memcpy (&dst[*off], &rl, sizeof (struct record_line)); *off = pos; return GNUNET_OK; } /** * Given a DNS packet, generate the corresponding UDP payload. * Note that we do not attempt to pack the strings with pointers * as this would complicate the code and this is about being * simple and secure, not fast, fancy and broken like bind. * * @param p packet to pack * @param max maximum allowed size for the resulting UDP payload * @param buf set to a buffer with the packed message * @param buf_length set to the length of buf * @return GNUNET_SYSERR if 'p' is invalid * GNUNET_NO if 'p' was truncated (but there is still a result in 'buf') * GNUNET_OK if 'p' was packed completely into '*buf' */ int GNUNET_DNSPARSER_pack (const struct GNUNET_DNSPARSER_Packet *p, uint16_t max, char **buf, size_t *buf_length) { struct GNUNET_TUN_DnsHeader dns; size_t off; char tmp[max]; unsigned int i; int ret; int trc; if ( (p->num_queries > UINT16_MAX) || (p->num_answers > UINT16_MAX) || (p->num_authority_records > UINT16_MAX) || (p->num_additional_records > UINT16_MAX) ) return GNUNET_SYSERR; dns.id = p->id; dns.flags = p->flags; dns.query_count = htons (p->num_queries); dns.answer_rcount = htons (p->num_answers); dns.authority_rcount = htons (p->num_authority_records); dns.additional_rcount = htons (p->num_additional_records); off = sizeof (struct GNUNET_TUN_DnsHeader); trc = GNUNET_NO; for (i=0;inum_queries;i++) { ret = add_query (tmp, sizeof (tmp), &off, &p->queries[i]); if (GNUNET_SYSERR == ret) return GNUNET_SYSERR; if (GNUNET_NO == ret) { dns.query_count = htons ((uint16_t) (i-1)); trc = GNUNET_YES; break; } } for (i=0;inum_answers;i++) { ret = add_record (tmp, sizeof (tmp), &off, &p->answers[i]); if (GNUNET_SYSERR == ret) return GNUNET_SYSERR; if (GNUNET_NO == ret) { dns.answer_rcount = htons ((uint16_t) (i-1)); trc = GNUNET_YES; break; } } for (i=0;inum_authority_records;i++) { ret = add_record (tmp, sizeof (tmp), &off, &p->authority_records[i]); if (GNUNET_SYSERR == ret) return GNUNET_SYSERR; if (GNUNET_NO == ret) { dns.authority_rcount = htons ((uint16_t) (i-1)); trc = GNUNET_YES; break; } } for (i=0;inum_additional_records;i++) { ret = add_record (tmp, sizeof (tmp), &off, &p->additional_records[i]); if (GNUNET_SYSERR == ret) return GNUNET_SYSERR; if (GNUNET_NO == ret) { dns.additional_rcount = htons (i-1); trc = GNUNET_YES; break; } } if (GNUNET_YES == trc) dns.flags.message_truncated = 1; memcpy (tmp, &dns, sizeof (struct GNUNET_TUN_DnsHeader)); *buf = GNUNET_malloc (off); *buf_length = off; memcpy (*buf, tmp, off); if (GNUNET_YES == trc) return GNUNET_NO; return GNUNET_OK; } /* end of dnsparser.c */ gnunet-0.9.3/src/dns/gnunet-dns-redirector.c0000644000175000017500000001502311760502551015710 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/dns/gnunet-dns-redirector.c * @brief Tool to change DNS replies (for testing) * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_dns_service.h" #include "gnunet_dnsparser_lib.h" /** * Handle to DNS service. */ static struct GNUNET_DNS_Handle *handle; /** * New target for A records. */ static char *n4; /** * New target for AAAA records. */ static char *n6; /** * Global return value (0 success). */ static int ret; /** * Selected level of verbosity. */ static int verbosity; /** * Modify the given DNS record. * * @param record record to modify */ static void modify_record (const struct GNUNET_DNSPARSER_Record *record) { char buf[INET6_ADDRSTRLEN]; switch (record->type) { case GNUNET_DNSPARSER_TYPE_A: if (record->data.raw.data_len != sizeof (struct in_addr)) return; if (NULL != n4) { if (verbosity > 1) fprintf (stderr, "Changing A record from `%s' to `%s'\n", inet_ntop (AF_INET, record->data.raw.data, buf, sizeof (buf)), n4); GNUNET_assert (1 == inet_pton (AF_INET, n4, record->data.raw.data)); } break; case GNUNET_DNSPARSER_TYPE_AAAA: if (record->data.raw.data_len != sizeof (struct in6_addr)) return; if (NULL != n6) { if (verbosity > 1) fprintf (stderr, "Changing AAAA record from `%s' to `%s'\n", inet_ntop (AF_INET6, record->data.raw.data, buf, sizeof (buf)), n6); GNUNET_assert (1 == inet_pton (AF_INET6, n6, record->data.raw.data)); } break; case GNUNET_DNSPARSER_TYPE_NS: case GNUNET_DNSPARSER_TYPE_CNAME: case GNUNET_DNSPARSER_TYPE_PTR: case GNUNET_DNSPARSER_TYPE_SOA: case GNUNET_DNSPARSER_TYPE_MX: case GNUNET_DNSPARSER_TYPE_TXT: break; default: break; } } /** * Signature of a function that is called whenever the DNS service * encounters a DNS request and needs to do something with it. The * function has then the chance to generate or modify the response by * calling one of the three "GNUNET_DNS_request_*" continuations. * * When a request is intercepted, this function is called first to * give the client a chance to do the complete address resolution; * "rdata" will be NULL for this first call for a DNS request, unless * some other client has already filled in a response. * * If multiple clients exist, all of them are called before the global * DNS. The global DNS is only called if all of the clients' * functions call GNUNET_DNS_request_forward. Functions that call * GNUNET_DNS_request_forward will be called again before a final * response is returned to the application. If any of the clients' * functions call GNUNET_DNS_request_drop, the response is dropped. * * @param cls closure * @param rh request handle to user for reply * @param request_length number of bytes in request * @param request udp payload of the DNS request */ static void modify_request (void *cls, struct GNUNET_DNS_RequestHandle *rh, size_t request_length, const char *request) { struct GNUNET_DNSPARSER_Packet *p; unsigned int i; char *buf; size_t len; int ret; p = GNUNET_DNSPARSER_parse (request, request_length); if (NULL == p) { fprintf (stderr, "Received malformed DNS packet, leaving it untouched\n"); GNUNET_DNS_request_forward (rh); return; } for (i=0;inum_answers;i++) modify_record (&p->answers[i]); buf = NULL; ret = GNUNET_DNSPARSER_pack (p, 1024, &buf, &len); GNUNET_DNSPARSER_free_packet (p); if (GNUNET_OK != ret) { if (GNUNET_NO == ret) fprintf (stderr, "Modified DNS response did not fit, keeping old response\n"); else GNUNET_break (0); /* our modifications should have been sane! */ GNUNET_DNS_request_forward (rh); } else { if (verbosity > 0) fprintf (stdout, "Injecting modified DNS response\n"); GNUNET_DNS_request_answer (rh, len, buf); } GNUNET_free_non_null (buf); } /** * Shutdown. */ static void do_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (NULL != handle) { GNUNET_DNS_disconnect (handle); handle = NULL; } } /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param cfg configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct in_addr i4; struct in6_addr i6; if ( (n4 != NULL) && (1 != inet_pton (AF_INET, n4, &i4)) ) { fprintf (stderr, "`%s' is nto a valid IPv4 address!\n", n4); return; } if ( (n6 != NULL) && (1 != inet_pton (AF_INET6, n6, &i6)) ) { fprintf (stderr, "`%s' is nto a valid IPv6 address!\n", n6); return; } handle = GNUNET_DNS_connect (cfg, GNUNET_DNS_FLAG_POST_RESOLUTION, &modify_request, NULL); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &do_disconnect, NULL); } int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { {'4', "ipv4", "IPV4", gettext_noop ("set A records"), 1, &GNUNET_GETOPT_set_string, &n4}, {'6', "ipv4", "IPV6", gettext_noop ("set AAAA records"), 1, &GNUNET_GETOPT_set_string, &n6}, GNUNET_GETOPT_OPTION_VERBOSE (&verbosity), GNUNET_GETOPT_OPTION_END }; return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-dns-redirector", gettext_noop ("Change DNS replies to point elsewhere."), options, &run, NULL)) ? ret : 1; } /* end of gnunet-dns-redirector.c */ gnunet-0.9.3/src/dns/dns.h0000644000175000017500000000432111760502551012256 00000000000000/* This file is part of GNUnet (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dns/dns.h * @brief IPC messages between DNS API and DNS service * @author Christian Grothoff */ #ifndef DNS_H #define DNS_H GNUNET_NETWORK_STRUCT_BEGIN /** * Message from client to DNS service to register itself. */ struct GNUNET_DNS_Register { /** * Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT */ struct GNUNET_MessageHeader header; /** * NBO encoding of 'enum GNUNET_DNS_Flags' for the client. */ uint32_t flags; }; /** * Message from DNS service to client: please handle a request. */ struct GNUNET_DNS_Request { /** * Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST */ struct GNUNET_MessageHeader header; /** * Always zero. */ uint32_t reserved GNUNET_PACKED; /** * Unique request ID. */ uint64_t request_id GNUNET_PACKED; /* followed by original DNS request (without UDP header) */ }; /** * Message from client to DNS service: here is my reply. */ struct GNUNET_DNS_Response { /** * Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE */ struct GNUNET_MessageHeader header; /** * Zero to drop, 1 for no change (no payload), 2 for update (message has payload). */ uint32_t drop_flag GNUNET_PACKED; /** * Unique request ID. */ uint64_t request_id GNUNET_PACKED; /* followed by original DNS request (without UDP header) */ }; GNUNET_NETWORK_STRUCT_END #endif gnunet-0.9.3/src/dns/Makefile.in0000644000175000017500000010463411762217211013374 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-service-dns$(EXEEXT) $(am__EXEEXT_1) noinst_PROGRAMS = gnunet-dns-monitor$(EXEEXT) \ gnunet-dns-redirector$(EXEEXT) @ENABLE_TEST_RUN_TRUE@TESTS = $(check_SCRIPTS) subdir = src/dns DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/dns.conf.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = dns.conf CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \ "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" LTLIBRARIES = $(lib_LTLIBRARIES) $(plugin_LTLIBRARIES) libgnunet_plugin_block_dns_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_libgnunet_plugin_block_dns_la_OBJECTS = plugin_block_dns.lo libgnunet_plugin_block_dns_la_OBJECTS = \ $(am_libgnunet_plugin_block_dns_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunet_plugin_block_dns_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) \ $(libgnunet_plugin_block_dns_la_LDFLAGS) $(LDFLAGS) -o $@ libgnunetdns_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_libgnunetdns_la_OBJECTS = dns_api.lo libgnunetdns_la_OBJECTS = $(am_libgnunetdns_la_OBJECTS) libgnunetdns_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetdns_la_LDFLAGS) $(LDFLAGS) \ -o $@ libgnunetdnsparser_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_libgnunetdnsparser_la_OBJECTS = dnsparser.lo libgnunetdnsparser_la_OBJECTS = $(am_libgnunetdnsparser_la_OBJECTS) libgnunetdnsparser_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetdnsparser_la_LDFLAGS) \ $(LDFLAGS) -o $@ @LINUX_TRUE@am__EXEEXT_1 = gnunet-helper-dns$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) am_gnunet_dns_monitor_OBJECTS = gnunet-dns-monitor.$(OBJEXT) gnunet_dns_monitor_OBJECTS = $(am_gnunet_dns_monitor_OBJECTS) am__DEPENDENCIES_1 = am_gnunet_dns_redirector_OBJECTS = gnunet-dns-redirector.$(OBJEXT) gnunet_dns_redirector_OBJECTS = $(am_gnunet_dns_redirector_OBJECTS) am_gnunet_helper_dns_OBJECTS = gnunet-helper-dns.$(OBJEXT) gnunet_helper_dns_OBJECTS = $(am_gnunet_helper_dns_OBJECTS) gnunet_helper_dns_LDADD = $(LDADD) am_gnunet_service_dns_OBJECTS = gnunet-service-dns.$(OBJEXT) gnunet_service_dns_OBJECTS = $(am_gnunet_service_dns_OBJECTS) gnunet_service_dns_DEPENDENCIES = \ $(top_builddir)/src/tun/libgnunettun.la \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunet_plugin_block_dns_la_SOURCES) \ $(libgnunetdns_la_SOURCES) $(libgnunetdnsparser_la_SOURCES) \ $(gnunet_dns_monitor_SOURCES) $(gnunet_dns_redirector_SOURCES) \ $(gnunet_helper_dns_SOURCES) $(gnunet_service_dns_SOURCES) DIST_SOURCES = $(libgnunet_plugin_block_dns_la_SOURCES) \ $(libgnunetdns_la_SOURCES) $(libgnunetdnsparser_la_SOURCES) \ $(gnunet_dns_monitor_SOURCES) $(gnunet_dns_redirector_SOURCES) \ $(gnunet_helper_dns_SOURCES) $(gnunet_service_dns_SOURCES) DATA = $(pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 pkgcfgdir = $(pkgdatadir)/config.d/ plugindir = $(libdir)/gnunet pkgcfg_DATA = \ dns.conf @LINUX_TRUE@HIJACKBIN = gnunet-helper-dns lib_LTLIBRARIES = \ libgnunetdnsparser.la \ libgnunetdns.la plugin_LTLIBRARIES = \ libgnunet_plugin_block_dns.la @LINUX_TRUE@check_SCRIPTS = \ @LINUX_TRUE@ test_gnunet_dns.sh gnunet_helper_dns_SOURCES = \ gnunet-helper-dns.c gnunet_dns_monitor_SOURCES = \ gnunet-dns-monitor.c gnunet_dns_monitor_LDADD = \ $(top_builddir)/src/dns/libgnunetdnsparser.la \ $(top_builddir)/src/dns/libgnunetdns.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_dns_monitor_DEPENDENCIES = \ libgnunetdnsparser.la \ libgnunetdns.la gnunet_dns_redirector_SOURCES = \ gnunet-dns-redirector.c gnunet_dns_redirector_LDADD = \ $(top_builddir)/src/dns/libgnunetdnsparser.la \ $(top_builddir)/src/dns/libgnunetdns.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_dns_redirector_DEPENDENCIES = \ libgnunetdnsparser.la \ libgnunetdns.la gnunet_service_dns_SOURCES = \ gnunet-service-dns.c gnunet_service_dns_LDADD = \ $(top_builddir)/src/tun/libgnunettun.la \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) libgnunetdnsparser_la_SOURCES = \ dnsparser.c libgnunetdnsparser_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la $(XLIB) libgnunetdnsparser_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:0:0 libgnunetdns_la_SOURCES = \ dns_api.c dns.h libgnunetdns_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la $(XLIB) libgnunetdns_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:0:0 libgnunet_plugin_block_dns_la_SOURCES = \ plugin_block_dns.c libgnunet_plugin_block_dns_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_block_dns_la_LDFLAGS = \ $(top_builddir)/src/block/$(GN_PLUGIN_LDFLAGS) EXTRA_DIST = \ $(check_SCRIPTS) all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/dns/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/dns/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): dns.conf: $(top_builddir)/config.status $(srcdir)/dns.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ } uninstall-pluginLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ done clean-pluginLTLIBRARIES: -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunet_plugin_block_dns.la: $(libgnunet_plugin_block_dns_la_OBJECTS) $(libgnunet_plugin_block_dns_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunet_plugin_block_dns_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_block_dns_la_OBJECTS) $(libgnunet_plugin_block_dns_la_LIBADD) $(LIBS) libgnunetdns.la: $(libgnunetdns_la_OBJECTS) $(libgnunetdns_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetdns_la_LINK) -rpath $(libdir) $(libgnunetdns_la_OBJECTS) $(libgnunetdns_la_LIBADD) $(LIBS) libgnunetdnsparser.la: $(libgnunetdnsparser_la_OBJECTS) $(libgnunetdnsparser_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetdnsparser_la_LINK) -rpath $(libdir) $(libgnunetdnsparser_la_OBJECTS) $(libgnunetdnsparser_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-dns-monitor$(EXEEXT): $(gnunet_dns_monitor_OBJECTS) $(gnunet_dns_monitor_DEPENDENCIES) @rm -f gnunet-dns-monitor$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_dns_monitor_OBJECTS) $(gnunet_dns_monitor_LDADD) $(LIBS) gnunet-dns-redirector$(EXEEXT): $(gnunet_dns_redirector_OBJECTS) $(gnunet_dns_redirector_DEPENDENCIES) @rm -f gnunet-dns-redirector$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_dns_redirector_OBJECTS) $(gnunet_dns_redirector_LDADD) $(LIBS) gnunet-helper-dns$(EXEEXT): $(gnunet_helper_dns_OBJECTS) $(gnunet_helper_dns_DEPENDENCIES) @rm -f gnunet-helper-dns$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_helper_dns_OBJECTS) $(gnunet_helper_dns_LDADD) $(LIBS) gnunet-service-dns$(EXEEXT): $(gnunet_service_dns_OBJECTS) $(gnunet_service_dns_DEPENDENCIES) @rm -f gnunet-service-dns$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_service_dns_OBJECTS) $(gnunet_service_dns_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dns_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsparser.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-dns-monitor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-dns-redirector.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-dns.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-dns.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_block_dns.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgcfgDATA: $(pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_SCRIPTS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool clean-noinstPROGRAMS clean-pluginLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgcfgDATA install-pluginLTLIBRARIES install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-exec-hook install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES .MAKE: check-am install-am install-exec-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool clean-noinstPROGRAMS clean-pluginLTLIBRARIES \ ctags distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-exec-hook install-html \ install-html-am install-info install-info-am \ install-libLTLIBRARIES install-man install-pdf install-pdf-am \ install-pkgcfgDATA install-pluginLTLIBRARIES install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ uninstall-am uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES @LINUX_TRUE@install-exec-hook: @LINUX_TRUE@ $(SUDO_BINARY) chown root $(bindir)/gnunet-helper-dns || true @LINUX_TRUE@ $(SUDO_BINARY) chgrp $(GNUNETDNS_GROUP) $(bindir)/gnunet-helper-dns || true @LINUX_TRUE@ $(SUDO_BINARY) chmod 4750 $(bindir)/gnunet-helper-dns || true @LINUX_TRUE@ $(SUDO_BINARY) chown gnunet:$(GNUNETDNS_GROUP) $(bindir)/gnunet-service-dns || true @LINUX_TRUE@ $(SUDO_BINARY) chmod 2750 $(bindir)/gnunet-service-dns || true @LINUX_FALSE@install-exec-hook: # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/dns/gnunet-service-dns.c0000644000175000017500000012704711760502551015220 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file dns/gnunet-service-dns.c * @brief service to intercept and modify DNS queries (and replies) of this system * @author Christian Grothoff * * For "secure" interaction with the legacy DNS system, we permit * replies only to arrive within a 5s window (and they must match * ports, IPs and request IDs). Furthermore, we let the OS pick a * source port, opening up to 128 sockets per address family (IPv4 or * IPv6). Those sockets are closed if they are not in use for 5s * (which means they will be freshly randomized afterwards). For new * requests, we pick a random slot in the array with 128 socket slots * (and re-use an existing socket if the slot is still in use). Thus * each request will be given one of 128 random source ports, and the * 128 random source ports will also change "often" (less often if the * system is very busy, each time if we are mostly idle). At the same * time, the system will never use more than 256 UDP sockets. */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_applications.h" #include "gnunet_constants.h" #include "gnunet_protocols.h" #include "gnunet_signatures.h" #include "dns.h" #include "gnunet_dns_service.h" #include "gnunet_dnsparser_lib.h" #include "gnunet_mesh_service.h" #include "gnunet_statistics_service.h" #include "gnunet_tun_lib.h" /** * Timeout for an external (Internet-DNS) DNS resolution */ #define REQUEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) /** * How many DNS sockets do we open at most at the same time? * (technical socket maximum is this number x2 for IPv4+IPv6) */ #define DNS_SOCKET_MAX 128 /** * Phases each request goes through. */ enum RequestPhase { /** * Request has just been received. */ RP_INIT, /** * Showing the request to all monitor clients. If * client list is empty, will enter QUERY phase. */ RP_REQUEST_MONITOR, /** * Showing the request to PRE-RESOLUTION clients to find an answer. * If client list is empty, will trigger global DNS request. */ RP_QUERY, /** * Global Internet query is now pending. */ RP_INTERNET_DNS, /** * Client (or global DNS request) has resulted in a response. * Forward to all POST-RESOLUTION clients. If client list is empty, * will enter RESPONSE_MONITOR phase. */ RP_MODIFY, /** * Showing the request to all monitor clients. If * client list is empty, give the result to the hijacker (and be done). */ RP_RESPONSE_MONITOR, /** * Some client has told us to drop the request. */ RP_DROP }; /** * Entry we keep for each client. */ struct ClientRecord { /** * Kept in doubly-linked list. */ struct ClientRecord *next; /** * Kept in doubly-linked list. */ struct ClientRecord *prev; /** * Handle to the client. */ struct GNUNET_SERVER_Client *client; /** * Flags for the client. */ enum GNUNET_DNS_Flags flags; }; /** * UDP socket we are using for sending DNS requests to the Internet. */ struct RequestSocket { /** * UDP socket we use for this request for IPv4 */ struct GNUNET_NETWORK_Handle *dnsout4; /** * UDP socket we use for this request for IPv6 */ struct GNUNET_NETWORK_Handle *dnsout6; /** * Task for reading from dnsout4 and dnsout6. */ GNUNET_SCHEDULER_TaskIdentifier read_task; /** * When should this socket be closed? */ struct GNUNET_TIME_Absolute timeout; }; /** * Entry we keep for each active request. */ struct RequestRecord { /** * List of clients that still need to see this request (each entry * is set to NULL when the client is done). */ struct ClientRecord **client_wait_list; /** * Payload of the UDP packet (the UDP payload), can be either query * or already the response. */ char *payload; /** * Socket we are using to transmit this request (must match if we receive * a response). Must NOT be freed as part of this request record (as it * might be shared with other requests). */ struct GNUNET_NETWORK_Handle *dnsout; /** * Source address of the original request (for sending response). */ struct sockaddr_storage src_addr; /** * Destination address of the original request (for potential use as exit). */ struct sockaddr_storage dst_addr; /** * When should this request time out? */ struct GNUNET_TIME_Absolute timeout; /** * ID of this request, also basis for hashing. Lowest 16 bit will * be our message ID when doing a global DNS request and our index * into the 'requests' array. */ uint64_t request_id; /** * Number of bytes in payload. */ size_t payload_length; /** * Length of the client wait list. */ unsigned int client_wait_list_length; /** * In which phase this this request? */ enum RequestPhase phase; }; /** * State we keep for each DNS tunnel that terminates at this node. */ struct TunnelState { /** * Associated MESH tunnel. */ struct GNUNET_MESH_Tunnel *tunnel; /** * Active request for sending a reply. */ struct GNUNET_MESH_TransmitHandle *th; /** * DNS reply ready for transmission. */ char *reply; /** * Socket we are using to transmit this request (must match if we receive * a response). Must NOT be freed as part of this request record (as it * might be shared with other requests). */ struct GNUNET_NETWORK_Handle *dnsout; /** * Address we sent the DNS request to. */ struct sockaddr_storage addr; /** * When should this request time out? */ struct GNUNET_TIME_Absolute timeout; /** * Number of bytes in 'addr'. */ socklen_t addrlen; /** * Number of bytes in 'reply'. */ size_t reply_length; /** * Original DNS request ID as used by the client. */ uint16_t original_id; /** * DNS request ID that we used for forwarding. */ uint16_t my_id; }; /** * Global return value from 'main'. */ static int global_ret; /** * The configuration to use */ static const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Statistics. */ static struct GNUNET_STATISTICS_Handle *stats; /** * Handle to DNS hijacker helper process ("gnunet-helper-dns"). */ static struct GNUNET_HELPER_Handle *hijacker; /** * Command-line arguments we are giving to the hijacker process. */ static char *helper_argv[7]; /** * Head of DLL of clients we consult. */ static struct ClientRecord *clients_head; /** * Tail of DLL of clients we consult. */ static struct ClientRecord *clients_tail; /** * Our notification context. */ static struct GNUNET_SERVER_NotificationContext *nc; /** * Array of all open requests. */ static struct RequestRecord requests[UINT16_MAX + 1]; /** * Array of all open requests from tunnels. */ static struct TunnelState *tunnels[UINT16_MAX + 1]; /** * Array of all open sockets for DNS requests. */ static struct RequestSocket sockets[DNS_SOCKET_MAX]; /** * Generator for unique request IDs. */ static uint64_t request_id_gen; /** * IP address to use for the DNS server if we are a DNS exit service * (for VPN via mesh); otherwise NULL. */ static char *dns_exit; /** * Handle to the MESH service (for receiving DNS queries), or NULL * if we are not a DNS exit. */ static struct GNUNET_MESH_Handle *mesh; /** * We're done with a RequestSocket, close it for now. * * @param rs request socket to clean up */ static void cleanup_rs (struct RequestSocket *rs) { if (NULL != rs->dnsout4) { GNUNET_NETWORK_socket_close (rs->dnsout4); rs->dnsout4 = NULL; } if (NULL != rs->dnsout6) { GNUNET_NETWORK_socket_close (rs->dnsout6); rs->dnsout6 = NULL; } if (GNUNET_SCHEDULER_NO_TASK != rs->read_task) { GNUNET_SCHEDULER_cancel (rs->read_task); rs->read_task = GNUNET_SCHEDULER_NO_TASK; } } /** * We're done processing a DNS request, free associated memory. * * @param rr request to clean up */ static void cleanup_rr (struct RequestRecord *rr) { GNUNET_free_non_null (rr->payload); rr->payload = NULL; rr->payload_length = 0; GNUNET_array_grow (rr->client_wait_list, rr->client_wait_list_length, 0); } /** * Task run during shutdown. * * @param cls unused * @param tc unused */ static void cleanup_task (void *cls GNUNET_UNUSED, const struct GNUNET_SCHEDULER_TaskContext *tc) { unsigned int i; GNUNET_HELPER_stop (hijacker); hijacker = NULL; for (i=0;i<7;i++) GNUNET_free_non_null (helper_argv[i]); for (i=0;i<=UINT16_MAX;i++) cleanup_rr (&requests[i]); GNUNET_SERVER_notification_context_destroy (nc); nc = NULL; if (stats != NULL) { GNUNET_STATISTICS_destroy (stats, GNUNET_NO); stats = NULL; } if (NULL != dns_exit) { GNUNET_free (dns_exit); dns_exit = NULL; } if (NULL != mesh) { GNUNET_MESH_disconnect(mesh); mesh = NULL; } } /** * Open source port for sending DNS requests * * @param af AF_INET or AF_INET6 * @return GNUNET_OK on success */ static struct GNUNET_NETWORK_Handle * open_socket (int af) { struct sockaddr_in a4; struct sockaddr_in6 a6; struct sockaddr *sa; socklen_t alen; struct GNUNET_NETWORK_Handle *ret; ret = GNUNET_NETWORK_socket_create (af, SOCK_DGRAM, 0); if (NULL == ret) return NULL; switch (af) { case AF_INET: memset (&a4, 0, alen = sizeof (struct sockaddr_in)); sa = (struct sockaddr *) &a4; break; case AF_INET6: memset (&a6, 0, alen = sizeof (struct sockaddr_in6)); sa = (struct sockaddr *) &a6; break; default: GNUNET_break (0); GNUNET_NETWORK_socket_close (ret); return NULL; } sa->sa_family = af; if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ret, sa, alen)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not bind to any port: %s\n"), STRERROR (errno)); GNUNET_NETWORK_socket_close (ret); return NULL; } return ret; } /** * We're done with some request, finish processing. * * @param rr request send to the network or just clean up. */ static void request_done (struct RequestRecord *rr) { struct GNUNET_MessageHeader *hdr; size_t reply_len; uint16_t source_port; uint16_t destination_port; GNUNET_array_grow (rr->client_wait_list, rr->client_wait_list_length, 0); if (RP_RESPONSE_MONITOR != rr->phase) { /* no response, drop */ cleanup_rr (rr); return; } /* send response via hijacker */ reply_len = sizeof (struct GNUNET_MessageHeader); reply_len += sizeof (struct GNUNET_TUN_Layer2PacketHeader); switch (rr->src_addr.ss_family) { case AF_INET: reply_len += sizeof (struct GNUNET_TUN_IPv4Header); break; case AF_INET6: reply_len += sizeof (struct GNUNET_TUN_IPv6Header); break; default: GNUNET_break (0); cleanup_rr (rr); return; } reply_len += sizeof (struct GNUNET_TUN_UdpHeader); reply_len += rr->payload_length; if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { /* response too big, drop */ GNUNET_break (0); /* how can this be? */ cleanup_rr(rr); return; } { char buf[reply_len] GNUNET_ALIGN; size_t off; struct GNUNET_TUN_IPv4Header ip4; struct GNUNET_TUN_IPv6Header ip6; /* first, GNUnet message header */ hdr = (struct GNUNET_MessageHeader*) buf; hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER); hdr->size = htons ((uint16_t) reply_len); off = sizeof (struct GNUNET_MessageHeader); /* first, TUN header */ { struct GNUNET_TUN_Layer2PacketHeader tun; tun.flags = htons (0); if (rr->src_addr.ss_family == AF_INET) tun.proto = htons (ETH_P_IPV4); else tun.proto = htons (ETH_P_IPV6); memcpy (&buf[off], &tun, sizeof (struct GNUNET_TUN_Layer2PacketHeader)); off += sizeof (struct GNUNET_TUN_Layer2PacketHeader); } /* now IP header */ switch (rr->src_addr.ss_family) { case AF_INET: { struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr; struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr; source_port = dst->sin_port; destination_port = src->sin_port; GNUNET_TUN_initialize_ipv4_header (&ip4, IPPROTO_UDP, reply_len - off - sizeof (struct GNUNET_TUN_IPv4Header), &dst->sin_addr, &src->sin_addr); memcpy (&buf[off], &ip4, sizeof (ip4)); off += sizeof (ip4); } break; case AF_INET6: { struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr; struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr; source_port = dst->sin6_port; destination_port = src->sin6_port; GNUNET_TUN_initialize_ipv6_header (&ip6, IPPROTO_UDP, reply_len - sizeof (struct GNUNET_TUN_IPv6Header), &dst->sin6_addr, &src->sin6_addr); memcpy (&buf[off], &ip6, sizeof (ip6)); off += sizeof (ip6); } break; default: GNUNET_assert (0); } /* now UDP header */ { struct GNUNET_TUN_UdpHeader udp; udp.source_port = source_port; udp.destination_port = destination_port; udp.len = htons (reply_len - off); if (AF_INET == rr->src_addr.ss_family) GNUNET_TUN_calculate_udp4_checksum (&ip4, &udp, rr->payload, rr->payload_length); else GNUNET_TUN_calculate_udp6_checksum (&ip6, &udp, rr->payload, rr->payload_length); memcpy (&buf[off], &udp, sizeof (udp)); off += sizeof (udp); } /* now DNS payload */ { memcpy (&buf[off], rr->payload, rr->payload_length); off += rr->payload_length; } /* final checks & sending */ GNUNET_assert (off == reply_len); (void) GNUNET_HELPER_send (hijacker, hdr, GNUNET_YES, NULL, NULL); GNUNET_STATISTICS_update (stats, gettext_noop ("# DNS requests answered via TUN interface"), 1, GNUNET_NO); } /* clean up, we're done */ cleanup_rr (rr); } /** * Show the payload of the given request record to the client * (and wait for a response). * * @param rr request to send to client * @param client client to send the response to */ static void send_request_to_client (struct RequestRecord *rr, struct GNUNET_SERVER_Client *client) { char buf[sizeof (struct GNUNET_DNS_Request) + rr->payload_length] GNUNET_ALIGN; struct GNUNET_DNS_Request *req; if (sizeof (buf) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); cleanup_rr (rr); return; } req = (struct GNUNET_DNS_Request*) buf; req->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST); req->header.size = htons (sizeof (buf)); req->reserved = htonl (0); req->request_id = rr->request_id; memcpy (&req[1], rr->payload, rr->payload_length); GNUNET_SERVER_notification_context_unicast (nc, client, &req->header, GNUNET_NO); } /** * Read a DNS response from the (unhindered) UDP-Socket * * @param cls socket to read from * @param tc scheduler context (must be shutdown or read ready) */ static void read_response (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Get a socket of the specified address family to send out a * UDP DNS request to the Internet. * * @param af desired address family * @return NULL on error (given AF not "supported") */ static struct GNUNET_NETWORK_Handle * get_request_socket (int af) { struct RequestSocket *rs; struct GNUNET_NETWORK_FDSet *rset; static struct GNUNET_NETWORK_Handle *ret; rs = &sockets[GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, DNS_SOCKET_MAX)]; rs->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT); switch (af) { case AF_INET: if (NULL == rs->dnsout4) rs->dnsout4 = open_socket (AF_INET); ret = rs->dnsout4; break; case AF_INET6: if (NULL == rs->dnsout6) rs->dnsout6 = open_socket (AF_INET6); ret = rs->dnsout6; break; default: return NULL; } if (GNUNET_SCHEDULER_NO_TASK != rs->read_task) { GNUNET_SCHEDULER_cancel (rs->read_task); rs->read_task = GNUNET_SCHEDULER_NO_TASK; } if ( (NULL == rs->dnsout4) && (NULL == rs->dnsout6) ) return NULL; rset = GNUNET_NETWORK_fdset_create (); if (NULL != rs->dnsout4) GNUNET_NETWORK_fdset_set (rset, rs->dnsout4); if (NULL != rs->dnsout6) GNUNET_NETWORK_fdset_set (rset, rs->dnsout6); rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, REQUEST_TIMEOUT, rset, NULL, &read_response, rs); GNUNET_NETWORK_fdset_destroy (rset); return ret; } /** * A client has completed its processing for this * request. Move on. * * @param rr request to process further */ static void next_phase (struct RequestRecord *rr) { struct ClientRecord *cr; int nz; unsigned int j; socklen_t salen; if (rr->phase == RP_DROP) { cleanup_rr (rr); return; } nz = -1; for (j=0;jclient_wait_list_length;j++) { if (NULL != rr->client_wait_list[j]) { nz = (int) j; break; } } if (-1 != nz) { send_request_to_client (rr, rr->client_wait_list[nz]->client); return; } /* done with current phase, advance! */ switch (rr->phase) { case RP_INIT: rr->phase = RP_REQUEST_MONITOR; for (cr = clients_head; NULL != cr; cr = cr->next) { if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR)) GNUNET_array_append (rr->client_wait_list, rr->client_wait_list_length, cr); } next_phase (rr); return; case RP_REQUEST_MONITOR: rr->phase = RP_QUERY; for (cr = clients_head; NULL != cr; cr = cr->next) { if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION)) GNUNET_array_append (rr->client_wait_list, rr->client_wait_list_length, cr); } next_phase (rr); return; case RP_QUERY: switch (rr->dst_addr.ss_family) { case AF_INET: salen = sizeof (struct sockaddr_in); break; case AF_INET6: salen = sizeof (struct sockaddr_in6); break; default: GNUNET_assert (0); } rr->phase = RP_INTERNET_DNS; rr->dnsout = get_request_socket (rr->dst_addr.ss_family); if (NULL == rr->dnsout) { GNUNET_STATISTICS_update (stats, gettext_noop ("# DNS exit failed (failed to open socket)"), 1, GNUNET_NO); cleanup_rr (rr); return; } GNUNET_NETWORK_socket_sendto (rr->dnsout, rr->payload, rr->payload_length, (struct sockaddr*) &rr->dst_addr, salen); rr->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT); return; case RP_INTERNET_DNS: rr->phase = RP_MODIFY; for (cr = clients_head; NULL != cr; cr = cr->next) { if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION)) GNUNET_array_append (rr->client_wait_list, rr->client_wait_list_length, cr); } next_phase (rr); return; case RP_MODIFY: rr->phase = RP_RESPONSE_MONITOR; for (cr = clients_head; NULL != cr; cr = cr->next) { if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR)) GNUNET_array_append (rr->client_wait_list, rr->client_wait_list_length, cr); } next_phase (rr); return; case RP_RESPONSE_MONITOR: request_done (rr); break; case RP_DROP: cleanup_rr (rr); break; default: GNUNET_break (0); cleanup_rr (rr); break; } } /** * A client disconnected, clean up after it. * * @param cls unused * @param client handle of client that disconnected */ static void client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) { struct ClientRecord *cr; struct RequestRecord *rr; unsigned int i; unsigned int j; for (cr = clients_head; NULL != cr; cr = cr->next) { if (cr->client == client) { GNUNET_SERVER_client_drop (client); GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, cr); for (i=0;iclient_wait_list_length) continue; /* not in use */ for (j=0;jclient_wait_list_length;j++) { if (rr->client_wait_list[j] == cr) { rr->client_wait_list[j] = NULL; next_phase (rr); } } } GNUNET_free (cr); return; } } } /** * We got a reply from DNS for a request of a MESH tunnel. Send it * via the tunnel (after changing the request ID back). * * @param cls the 'struct TunnelState' * @param size number of bytes available in buf * @param buf where to copy the reply * @return number of bytes written to buf */ static size_t transmit_reply_to_mesh (void *cls, size_t size, void *buf) { struct TunnelState *ts = cls; size_t off; size_t ret; char *cbuf = buf; struct GNUNET_MessageHeader hdr; struct GNUNET_TUN_DnsHeader dns; ts->th = NULL; GNUNET_assert (ts->reply != NULL); if (size == 0) return 0; ret = sizeof (struct GNUNET_MessageHeader) + ts->reply_length; GNUNET_assert (ret <= size); hdr.size = htons (ret); hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET); memcpy (&dns, ts->reply, sizeof (dns)); dns.id = ts->original_id; off = 0; memcpy (&cbuf[off], &hdr, sizeof (hdr)); off += sizeof (hdr); memcpy (&cbuf[off], &dns, sizeof (dns)); off += sizeof (dns); memcpy (&cbuf[off], &ts->reply[sizeof (dns)], ts->reply_length - sizeof (dns)); off += ts->reply_length - sizeof (dns); GNUNET_free (ts->reply); ts->reply = NULL; ts->reply_length = 0; GNUNET_assert (ret == off); return ret; } /** * Actually do the reading of a DNS packet from our UDP socket and see * if we have a valid, matching, pending request. * * @param dnsout socket to read from * @return GNUNET_OK on success, GNUNET_NO on drop, GNUNET_SYSERR on IO-errors (closed socket) */ static int do_dns_read (struct GNUNET_NETWORK_Handle *dnsout) { struct sockaddr_storage addr; socklen_t addrlen; struct GNUNET_TUN_DnsHeader *dns; struct RequestRecord *rr; struct TunnelState *ts; ssize_t r; int len; #ifndef MINGW if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len)) { /* conservative choice: */ len = UINT16_MAX; } #else /* port the code above? */ len = UINT16_MAX; #endif { unsigned char buf[len] GNUNET_ALIGN; addrlen = sizeof (addr); memset (&addr, 0, sizeof (addr)); r = GNUNET_NETWORK_socket_recvfrom (dnsout, buf, sizeof (buf), (struct sockaddr*) &addr, &addrlen); if (-1 == r) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom"); GNUNET_NETWORK_socket_close (dnsout); return GNUNET_SYSERR; } if (sizeof (struct GNUNET_TUN_DnsHeader) > r) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Received DNS response that is too small (%u bytes)"), r); return GNUNET_NO; } dns = (struct GNUNET_TUN_DnsHeader *) buf; /* Handle case that this is a reply to a request from a MESH DNS tunnel */ ts = tunnels[dns->id]; if ( (NULL == ts) || (ts->dnsout != dnsout) || (addrlen != ts->addrlen) || (0 != memcmp (&ts->addr, &addr, addrlen)) || (0 == GNUNET_TIME_absolute_get_remaining (ts->timeout).rel_value) ) ts = NULL; /* DNS responder address missmatch */ if (NULL != ts) { tunnels[dns->id] = NULL; GNUNET_free_non_null (ts->reply); ts->reply = GNUNET_malloc (r); ts->reply_length = r; memcpy (ts->reply, dns, r); if (ts->th != NULL) GNUNET_MESH_notify_transmit_ready_cancel (ts->th); ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel, GNUNET_NO, 0, GNUNET_TIME_UNIT_FOREVER_REL, NULL, sizeof (struct GNUNET_MessageHeader) + r, &transmit_reply_to_mesh, ts); } /* Handle case that this is a reply to a local request (intercepted from TUN interface) */ rr = &requests[dns->id]; if ( (rr->phase != RP_INTERNET_DNS) || (rr->dnsout != dnsout) || (0 != memcmp (&rr->dst_addr, &addr, addrlen)) || (0 == GNUNET_TIME_absolute_get_remaining (rr->timeout).rel_value) ) { if (NULL == ts) { /* unexpected / bogus reply */ GNUNET_STATISTICS_update (stats, gettext_noop ("# External DNS response discarded (no matching request)"), 1, GNUNET_NO); } return GNUNET_NO; } GNUNET_free_non_null (rr->payload); rr->payload = GNUNET_malloc (r); memcpy (rr->payload, buf, r); rr->payload_length = r; next_phase (rr); } return GNUNET_OK; } /** * Read a DNS response from the (unhindered) UDP-Socket * * @param cls socket to read from * @param tc scheduler context (must be shutdown or read ready) */ static void read_response (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct RequestSocket *rs = cls; struct GNUNET_NETWORK_FDSet *rset; rs->read_task = GNUNET_SCHEDULER_NO_TASK; if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) { /* timeout or shutdown */ cleanup_rs (rs); return; } /* read and process ready sockets */ if ((NULL != rs->dnsout4) && (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout4)) && (GNUNET_SYSERR == do_dns_read (rs->dnsout4))) rs->dnsout4 = NULL; if ((NULL != rs->dnsout6) && (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout6)) && (GNUNET_SYSERR == do_dns_read (rs->dnsout6))) rs->dnsout6 = NULL; /* re-schedule read task */ rset = GNUNET_NETWORK_fdset_create (); if (NULL != rs->dnsout4) GNUNET_NETWORK_fdset_set (rset, rs->dnsout4); if (NULL != rs->dnsout6) GNUNET_NETWORK_fdset_set (rset, rs->dnsout6); rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_TIME_absolute_get_remaining (rs->timeout), rset, NULL, &read_response, rs); GNUNET_NETWORK_fdset_destroy (rset); } /** * We got a new client. Make sure all new DNS requests pass by its desk. * * @param cls unused * @param client the new client * @param message the init message (unused) */ static void handle_client_init (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct ClientRecord *cr; const struct GNUNET_DNS_Register *reg = (const struct GNUNET_DNS_Register*) message; cr = GNUNET_malloc (sizeof (struct ClientRecord)); cr->client = client; cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags); GNUNET_SERVER_client_keep (client); GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, cr); GNUNET_SERVER_notification_context_add (nc, client); GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** * We got a response from a client. * * @param cls unused * @param client the client * @param message the response */ static void handle_client_response (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct GNUNET_DNS_Response *resp; struct RequestRecord *rr; unsigned int i; uint16_t msize; uint16_t off; msize = ntohs (message->size); if (msize < sizeof (struct GNUNET_DNS_Response)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } resp = (const struct GNUNET_DNS_Response*) message; off = (uint16_t) resp->request_id; rr = &requests[off]; if (rr->request_id != resp->request_id) { GNUNET_STATISTICS_update (stats, gettext_noop ("# Client response discarded (no matching request)"), 1, GNUNET_NO); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } for (i=0;iclient_wait_list_length;i++) { if (NULL == rr->client_wait_list[i]) continue; if (rr->client_wait_list[i]->client != client) continue; rr->client_wait_list[i] = NULL; switch (ntohl (resp->drop_flag)) { case 0: /* drop */ rr->phase = RP_DROP; break; case 1: /* no change */ break; case 2: /* update */ msize -= sizeof (struct GNUNET_DNS_Response); if ( (sizeof (struct GNUNET_TUN_DnsHeader) > msize) || (RP_REQUEST_MONITOR == rr->phase) || (RP_RESPONSE_MONITOR == rr->phase) ) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); next_phase (rr); return; } GNUNET_free_non_null (rr->payload); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Changing DNS reply according to client specifications\n"); rr->payload = GNUNET_malloc (msize); rr->payload_length = msize; memcpy (rr->payload, &resp[1], msize); if (rr->phase == RP_QUERY) { /* clear wait list, we're moving to MODIFY phase next */ GNUNET_array_grow (rr->client_wait_list, rr->client_wait_list_length, 0); } /* if query changed to answer, move past DNS resolution phase... */ if ( (RP_QUERY == rr->phase) && (rr->payload_length > sizeof (struct GNUNET_TUN_DnsHeader)) && ((struct GNUNET_DNSPARSER_Flags*)&(((struct GNUNET_TUN_DnsHeader*) rr->payload)->flags))->query_or_response == 1) { rr->phase = RP_INTERNET_DNS; GNUNET_array_grow (rr->client_wait_list, rr->client_wait_list_length, 0); } break; } next_phase (rr); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } /* odd, client was not on our list for the request, that ought to be an error */ GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); } /** * Functions with this signature are called whenever a complete * message is received by the tokenizer from the DNS hijack process. * * @param cls closure * @param client identification of the client * @param message the actual message, a DNS request we should handle */ static int process_helper_messages (void *cls GNUNET_UNUSED, void *client, const struct GNUNET_MessageHeader *message) { uint16_t msize; const struct GNUNET_TUN_Layer2PacketHeader *tun; const struct GNUNET_TUN_IPv4Header *ip4; const struct GNUNET_TUN_IPv6Header *ip6; const struct GNUNET_TUN_UdpHeader *udp; const struct GNUNET_TUN_DnsHeader *dns; struct RequestRecord *rr; struct sockaddr_in *srca4; struct sockaddr_in6 *srca6; struct sockaddr_in *dsta4; struct sockaddr_in6 *dsta6; msize = ntohs (message->size); if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_TUN_IPv4Header)) { /* non-IP packet received on TUN!? */ GNUNET_break (0); return GNUNET_OK; } msize -= sizeof (struct GNUNET_MessageHeader); tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1]; msize -= sizeof (struct GNUNET_TUN_Layer2PacketHeader); switch (ntohs (tun->proto)) { case ETH_P_IPV4: ip4 = (const struct GNUNET_TUN_IPv4Header *) &tun[1]; ip6 = NULL; /* make compiler happy */ if ( (msize < sizeof (struct GNUNET_TUN_IPv4Header)) || (ip4->version != 4) || (ip4->header_length != sizeof (struct GNUNET_TUN_IPv4Header) / 4) || (ntohs(ip4->total_length) != msize) || (ip4->protocol != IPPROTO_UDP) ) { /* non-IP/UDP packet received on TUN (or with options) */ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Received malformed IPv4-UDP packet on TUN interface.\n")); return GNUNET_OK; } udp = (const struct GNUNET_TUN_UdpHeader*) &ip4[1]; msize -= sizeof (struct GNUNET_TUN_IPv4Header); break; case ETH_P_IPV6: ip4 = NULL; /* make compiler happy */ ip6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1]; if ( (msize < sizeof (struct GNUNET_TUN_IPv6Header)) || (ip6->version != 6) || (ntohs (ip6->payload_length) != msize) || (ip6->next_header != IPPROTO_UDP) ) { /* non-IP/UDP packet received on TUN (or with extensions) */ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Received malformed IPv6-UDP packet on TUN interface.\n")); return GNUNET_OK; } udp = (const struct GNUNET_TUN_UdpHeader*) &ip6[1]; msize -= sizeof (struct GNUNET_TUN_IPv6Header); break; default: /* non-IP packet received on TUN!? */ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Got non-IP packet with %u bytes and protocol %u from TUN\n"), (unsigned int) msize, ntohs (tun->proto)); return GNUNET_OK; } if (msize <= sizeof (struct GNUNET_TUN_UdpHeader) + sizeof (struct GNUNET_TUN_DnsHeader)) { /* non-DNS packet received on TUN, ignore */ GNUNET_STATISTICS_update (stats, gettext_noop ("# Non-DNS UDP packet received via TUN interface"), 1, GNUNET_NO); return GNUNET_OK; } msize -= sizeof (struct GNUNET_TUN_UdpHeader); dns = (const struct GNUNET_TUN_DnsHeader*) &udp[1]; rr = &requests[dns->id]; /* clean up from previous request */ GNUNET_free_non_null (rr->payload); rr->payload = NULL; GNUNET_array_grow (rr->client_wait_list, rr->client_wait_list_length, 0); /* setup new request */ rr->phase = RP_INIT; switch (ntohs (tun->proto)) { case ETH_P_IPV4: { srca4 = (struct sockaddr_in*) &rr->src_addr; dsta4 = (struct sockaddr_in*) &rr->dst_addr; memset (srca4, 0, sizeof (struct sockaddr_in)); memset (dsta4, 0, sizeof (struct sockaddr_in)); srca4->sin_family = AF_INET; dsta4->sin_family = AF_INET; srca4->sin_addr = ip4->source_address; dsta4->sin_addr = ip4->destination_address; srca4->sin_port = udp->source_port; dsta4->sin_port = udp->destination_port; #if HAVE_SOCKADDR_IN_SIN_LEN srca4->sin_len = sizeof (struct sockaddr_in); dsta4->sin_len = sizeof (struct sockaddr_in); #endif } break; case ETH_P_IPV6: { srca6 = (struct sockaddr_in6*) &rr->src_addr; dsta6 = (struct sockaddr_in6*) &rr->dst_addr; memset (srca6, 0, sizeof (struct sockaddr_in6)); memset (dsta6, 0, sizeof (struct sockaddr_in6)); srca6->sin6_family = AF_INET6; dsta6->sin6_family = AF_INET6; srca6->sin6_addr = ip6->source_address; dsta6->sin6_addr = ip6->destination_address; srca6->sin6_port = udp->source_port; dsta6->sin6_port = udp->destination_port; #if HAVE_SOCKADDR_IN_SIN_LEN srca6->sin6_len = sizeof (struct sockaddr_in6); dsta6->sin6_len = sizeof (struct sockaddr_in6); #endif } break; default: GNUNET_assert (0); } rr->payload = GNUNET_malloc (msize); rr->payload_length = msize; memcpy (rr->payload, dns, msize); rr->request_id = dns->id | (request_id_gen << 16); request_id_gen++; GNUNET_STATISTICS_update (stats, gettext_noop ("# DNS requests received via TUN interface"), 1, GNUNET_NO); /* start request processing state machine */ next_phase (rr); return GNUNET_OK; } /** * Process a request via mesh to perform a DNS query. * * @param cls closure, NULL * @param tunnel connection to the other end * @param tunnel_ctx pointer to our 'struct TunnelState *' * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int receive_dns_request (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) { struct TunnelState *ts = *tunnel_ctx; const struct GNUNET_TUN_DnsHeader *dns; size_t mlen = ntohs (message->size); size_t dlen = mlen - sizeof (struct GNUNET_MessageHeader); char buf[dlen] GNUNET_ALIGN; struct GNUNET_TUN_DnsHeader *dout; struct sockaddr_in v4; struct sockaddr_in6 v6; struct sockaddr *so; socklen_t salen; if (dlen < sizeof (struct GNUNET_TUN_DnsHeader)) { GNUNET_break_op (0); return GNUNET_SYSERR; } dns = (const struct GNUNET_TUN_DnsHeader *) &message[1]; ts->original_id = dns->id; if (tunnels[ts->my_id] == ts) tunnels[ts->my_id] = NULL; ts->my_id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT16_MAX + 1); tunnels[ts->my_id] = ts; memcpy (buf, dns, dlen); dout = (struct GNUNET_TUN_DnsHeader*) buf; dout->id = ts->my_id; memset (&v4, 0, sizeof (v4)); memset (&v6, 0, sizeof (v6)); if (1 == inet_pton (AF_INET, dns_exit, &v4.sin_addr)) { salen = sizeof (v4); v4.sin_family = AF_INET; v4.sin_port = htons (53); #if HAVE_SOCKADDR_IN_SIN_LEN v4.sin_len = (u_char) salen; #endif so = (struct sockaddr *) &v4; ts->dnsout = get_request_socket (AF_INET); } else if (1 == inet_pton (AF_INET6, dns_exit, &v6.sin6_addr)) { salen = sizeof (v6); v6.sin6_family = AF_INET6; v6.sin6_port = htons (53); #if HAVE_SOCKADDR_IN_SIN_LEN v6.sin6_len = (u_char) salen; #endif so = (struct sockaddr *) &v6; ts->dnsout = get_request_socket (AF_INET6); } else { GNUNET_break (0); return GNUNET_SYSERR; } if (NULL == ts->dnsout) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Configured DNS exit `%s' is not working / valid.\n"), dns_exit); return GNUNET_SYSERR; } memcpy (&ts->addr, so, salen); ts->addrlen = salen; GNUNET_NETWORK_socket_sendto (ts->dnsout, buf, dlen, so, salen); ts->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT); return GNUNET_OK; } /** * Callback from GNUNET_MESH for new tunnels. * * @param cls closure * @param tunnel new handle to the tunnel * @param initiator peer that started the tunnel * @param ats performance information for the tunnel * @return initial tunnel context for the tunnel */ static void * accept_dns_tunnel (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, const struct GNUNET_PeerIdentity *initiator GNUNET_UNUSED, const struct GNUNET_ATS_Information *ats GNUNET_UNUSED) { struct TunnelState *ts = GNUNET_malloc (sizeof (struct TunnelState)); GNUNET_STATISTICS_update (stats, gettext_noop ("# Inbound MESH tunnels created"), 1, GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received inbound tunnel from `%s'\n", GNUNET_i2s (initiator)); ts->tunnel = tunnel; return ts; } /** * Function called by mesh whenever an inbound tunnel is destroyed. * Should clean up any associated state. * * @param cls closure (set from GNUNET_MESH_connect) * @param tunnel connection to the other end (henceforth invalid) * @param tunnel_ctx place where local state associated * with the tunnel is stored */ static void destroy_dns_tunnel (void *cls GNUNET_UNUSED, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx) { struct TunnelState *ts = tunnel_ctx; if (tunnels[ts->my_id] == ts) tunnels[ts->my_id] = NULL; if (NULL != ts->th) GNUNET_MESH_notify_transmit_ready_cancel (ts->th); GNUNET_free_non_null (ts->reply); GNUNET_free (ts); } /** * @param cls closure * @param server the initialized server * @param cfg_ configuration to use */ static void run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *cfg_) { static const struct GNUNET_SERVER_MessageHandler handlers[] = { /* callback, cls, type, size */ {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT, sizeof (struct GNUNET_DNS_Register)}, {&handle_client_response, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, 0}, {NULL, NULL, 0, 0} }; char *ifc_name; char *ipv4addr; char *ipv4mask; char *ipv6addr; char *ipv6prefix; struct in_addr dns_exit4; struct in6_addr dns_exit6; cfg = cfg_; if (GNUNET_YES != GNUNET_OS_check_helper_binary ("gnunet-helper-dns")) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("`%s' must be installed SUID, refusing to run\n"), "gnunet-helper-dns"); global_ret = 1; return; } stats = GNUNET_STATISTICS_create ("dns", cfg); nc = GNUNET_SERVER_notification_context_create (server, 1); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, cls); if ( (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT")) && ( (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "DNS_EXIT", &dns_exit)) || ( (1 != inet_pton (AF_INET, dns_exit, &dns_exit4)) && (1 != inet_pton (AF_INET6, dns_exit, &dns_exit6)) ) ) ) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Configured to provide DNS exit, but no valid DNS server configured!\n")); GNUNET_free_non_null (dns_exit); dns_exit = NULL; } helper_argv[0] = GNUNET_strdup ("gnunet-dns"); if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No entry 'IFNAME' in configuration!\n"); GNUNET_SCHEDULER_shutdown (); return; } helper_argv[1] = ifc_name; if ( (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6ADDR", &ipv6addr)) ) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No entry 'IPV6ADDR' in configuration!\n"); GNUNET_SCHEDULER_shutdown (); return; } helper_argv[2] = ipv6addr; if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6PREFIX", &ipv6prefix)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No entry 'IPV6PREFIX' in configuration!\n"); GNUNET_SCHEDULER_shutdown (); return; } helper_argv[3] = ipv6prefix; if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4ADDR", &ipv4addr)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No entry 'IPV4ADDR' in configuration!\n"); GNUNET_SCHEDULER_shutdown (); return; } helper_argv[4] = ipv4addr; if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK", &ipv4mask)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No entry 'IPV4MASK' in configuration!\n"); GNUNET_SCHEDULER_shutdown (); return; } helper_argv[5] = ipv4mask; helper_argv[6] = NULL; if (NULL != dns_exit) { static struct GNUNET_MESH_MessageHandler mesh_handlers[] = { {&receive_dns_request, GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET, 0}, {NULL, 0, 0} }; static GNUNET_MESH_ApplicationType mesh_types[] = { GNUNET_APPLICATION_TYPE_INTERNET_RESOLVER, GNUNET_APPLICATION_TYPE_END }; mesh = GNUNET_MESH_connect (cfg, 1, NULL, &accept_dns_tunnel, &destroy_dns_tunnel, mesh_handlers, mesh_types); } hijacker = GNUNET_HELPER_start ("gnunet-helper-dns", helper_argv, &process_helper_messages, NULL); GNUNET_SERVER_add_handlers (server, handlers); GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL); } /** * The main function for the dns service. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { return (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, "dns", GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? global_ret : 1; } /* end of gnunet-service-dns.c */ gnunet-0.9.3/src/Makefile.in0000644000175000017500000005103211762217210012600 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ #if WANT_FRAMEWORK # INTLEMU_SUBDIRS = intlemu #endif VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = src DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir ETAGS = etags CTAGS = ctags DIST_SUBDIRS = include util hello tun block statistics arm peerinfo \ mysql postgres datacache datastore namestore template ats nat \ fragmentation transport peerinfo-tool core testing testbed nse \ dht hostlist topology fs mesh lockmanager dns gns exit vpn pt \ integration-tests chat dv stream regex DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ @HAVE_EXPERIMENTAL_TRUE@EXP_DIR = chat dv stream regex # All of these currently only work on GNU/Linux @LINUX_TRUE@LINUX_DIR = dns gns exit vpn pt @HAVE_MYSQL_TRUE@MYSQL_DIR = mysql @HAVE_POSTGRES_TRUE@POSTGRES_DIR = postgres SUBDIRS = \ include $(INTLEMU_SUBDIRS) \ util \ hello \ tun \ block \ statistics \ arm \ peerinfo \ $(MYSQL_DIR) \ $(POSTGRES_DIR) \ datacache \ datastore \ namestore \ template \ ats \ nat \ fragmentation \ transport \ peerinfo-tool \ core \ testing \ testbed \ nse \ dht \ hostlist \ topology \ fs \ mesh \ lockmanager \ $(LINUX_DIR) \ integration-tests \ $(EXP_DIR) all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. # To change the values of `make' variables: instead of editing Makefiles, # (1) if the variable is set in `config.status', edit `config.status' # (which will cause the Makefiles to be regenerated when you run `make'); # (2) otherwise, pass the desired values on the `make' command line. $(RECURSIVE_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ list='$(SUBDIRS)'; for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ rev="$$rev ."; \ target=`echo $@ | sed s/-recursive//`; \ for subdir in $$rev; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ install-am install-strip tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am check check-am clean clean-generic clean-libtool \ ctags ctags-recursive distclean distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/hello/0000755000175000017500000000000011763406747011735 500000000000000gnunet-0.9.3/src/hello/address.c0000644000175000017500000000655611760502551013445 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file hello/address.c * @brief helper functions for handling addresses * @author Christian Grothoff */ #include "platform.h" #include "gnunet_hello_lib.h" #include "gnunet_util_lib.h" /** * Allocate an address struct. * * @param peer the peer * @param transport_name plugin name * @param address binary address * @param address_length number of bytes in 'address' * @return the address struct */ struct GNUNET_HELLO_Address * GNUNET_HELLO_address_allocate (const struct GNUNET_PeerIdentity *peer, const char *transport_name, const void *address, size_t address_length) { struct GNUNET_HELLO_Address *addr; size_t slen; char *end; GNUNET_assert (transport_name != NULL); slen = strlen (transport_name) + 1; addr = GNUNET_malloc (sizeof (struct GNUNET_HELLO_Address) + address_length + slen); addr->peer = *peer; addr->address = &addr[1]; end = (char *) &addr[1]; memcpy (end, address, address_length); addr->address_length = address_length; addr->transport_name = &end[address_length]; memcpy (&end[address_length], transport_name, slen); return addr; } /** * Get the size of an address struct. * * @param address address * @return the size */ size_t GNUNET_HELLO_address_get_size (const struct GNUNET_HELLO_Address * address) { return sizeof (struct GNUNET_HELLO_Address) + address->address_length + strlen (address->transport_name) + 1; } /** * Copy an address struct. * * @param address address to copy * @return a copy of the address struct */ struct GNUNET_HELLO_Address * GNUNET_HELLO_address_copy (const struct GNUNET_HELLO_Address *address) { return GNUNET_HELLO_address_allocate (&address->peer, address->transport_name, address->address, address->address_length); } /** * Compare two addresses. Does NOT compare the peer identity, * that is assumed already to match! * * @param a1 first address * @param a2 second address * @return 0 if the addresses are equal, -1 if a1a2. */ int GNUNET_HELLO_address_cmp (const struct GNUNET_HELLO_Address *a1, const struct GNUNET_HELLO_Address *a2) { int ret; ret = strcmp (a1->transport_name, a2->transport_name); if (0 != ret) return ret; if (a1->address_length < a2->address_length) return -1; if (a1->address_length > a2->address_length) return 1; return memcmp (a1->address, a1->address, a1->address_length); } /* end of address.c */ gnunet-0.9.3/src/hello/Makefile.am0000644000175000017500000000166111732024427013700 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIB = -lgcov endif lib_LTLIBRARIES = libgnunethello.la libgnunethello_la_SOURCES = \ hello.c address.c libgnunethello_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la $(XLIB) libgnunethello_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:0:0 noinst_PROGRAMS = \ gnunet-hello check_PROGRAMS = \ test_hello if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) endif test_hello_SOURCES = \ test_hello.c test_hello_LDADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la gnunet_hello_SOURCES = \ gnunet-hello.c gnunet_hello_LDADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la gnunet_hello_DEPENDENCIES = \ libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la gnunet-0.9.3/src/hello/test_hello.c0000644000175000017500000001430211760502551014146 00000000000000/* This file is part of GNUnet (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file hello/test_hello.c * @brief test for hello.c * @author Christian Grothoff */ #include "platform.h" #include "gnunet_hello_lib.h" #define DEBUG GNUNET_NO #define VERBOSE GNUNET_NO static size_t my_addr_gen (void *cls, size_t max, void *buf) { unsigned int *i = cls; size_t ret; struct GNUNET_HELLO_Address address; #if DEBUG FPRINTF (stderr, "DEBUG: my_addr_gen called with i = %d\n", *i); #endif if (0 == *i) return 0; memset (&address.peer, 0, sizeof (struct GNUNET_PeerIdentity)); address.address = "address_information"; address.transport_name = "test"; address.address_length = *i; ret = GNUNET_HELLO_add_address (&address, GNUNET_TIME_absolute_get (), buf, max); (*i)--; return ret; } static int check_addr (void *cls, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration) { unsigned int *i = cls; #if DEBUG FPRINTF (stderr, "DEBUG: check_addr called with i = %d and addrlen = %u\n", *i, (unsigned int) address->address_length); #endif GNUNET_assert (address->address_length > 0); GNUNET_assert (*i & (1 << (address->address_length - 1))); *i -= (1 << (address->address_length - 1)); GNUNET_assert (0 == strncmp ("address_information", address->address, address->address_length)); GNUNET_assert (0 == strcmp ("test", address->transport_name)); return GNUNET_OK; } static int remove_some (void *cls, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration) { unsigned int *i = cls; #if DEBUG FPRINTF (stderr, "DEBUG: remove_some called with i = %d and addrlen = %u\n", *i, (unsigned int) address->address_length); #endif GNUNET_assert (address->address_length > 0); if (*i & (1 << (address->address_length - 1))) { *i -= (1 << (address->address_length - 1)); return GNUNET_NO; } return GNUNET_OK; } int main (int argc, char *argv[]) { struct GNUNET_HELLO_Message *msg1; struct GNUNET_HELLO_Message *msg2; struct GNUNET_HELLO_Message *msg3; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk; struct GNUNET_TIME_Absolute startup_time; unsigned int i; GNUNET_log_setup ("test-hello", "DEBUG", NULL); startup_time = GNUNET_TIME_absolute_get (); memset (&publicKey, 42, sizeof (publicKey)); #if VERBOSE FPRINTF (stderr, "%s", "Testing HELLO creation (without addresses)...\n"); #endif i = 0; msg1 = GNUNET_HELLO_create (&publicKey, &my_addr_gen, &i); GNUNET_assert (msg1 != NULL); GNUNET_assert (0 < GNUNET_HELLO_size (msg1)); #if VERBOSE FPRINTF (stderr, "%s", "Testing address iteration (empty set)...\n"); #endif GNUNET_assert (NULL == GNUNET_HELLO_iterate_addresses (msg1, GNUNET_NO, &check_addr, &i)); #if VERBOSE FPRINTF (stderr, "%s", "Testing HELLO creation (with one address)...\n"); #endif i = 1; msg2 = GNUNET_HELLO_create (&publicKey, &my_addr_gen, &i); GNUNET_assert (msg2 != NULL); GNUNET_assert (GNUNET_HELLO_size (msg1) < GNUNET_HELLO_size (msg2)); #if VERBOSE FPRINTF (stderr, "%s", "Testing address iteration (one address)...\n"); #endif i = 1; GNUNET_assert (NULL == GNUNET_HELLO_iterate_addresses (msg2, GNUNET_NO, &check_addr, &i)); GNUNET_assert (i == 0); #if VERBOSE FPRINTF (stderr, "%s", "Testing get_key from HELLO...\n"); #endif GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_key (msg2, &pk)); GNUNET_assert (0 == memcmp (&publicKey, &pk, sizeof (pk))); GNUNET_free (msg1); #if VERBOSE FPRINTF (stderr, "%s", "Testing HELLO creation (with two addresses)...\n"); #endif i = 2; msg3 = GNUNET_HELLO_create (&publicKey, &my_addr_gen, &i); GNUNET_assert (msg3 != NULL); GNUNET_assert (GNUNET_HELLO_size (msg2) < GNUNET_HELLO_size (msg3)); #if VERBOSE FPRINTF (stderr, "%s", "Testing address iteration (two addresses)...\n"); #endif i = 3; GNUNET_assert (NULL == GNUNET_HELLO_iterate_addresses (msg3, GNUNET_NO, &check_addr, &i)); GNUNET_assert (i == 0); #if VERBOSE FPRINTF (stderr, "%s", "Testing HELLO merge...\n"); #endif msg1 = GNUNET_HELLO_merge (msg2, msg3); GNUNET_assert (GNUNET_HELLO_size (msg1) == GNUNET_HELLO_size (msg3)); i = 3; GNUNET_assert (NULL == GNUNET_HELLO_iterate_addresses (msg1, GNUNET_NO, &check_addr, &i)); GNUNET_assert (i == 0); GNUNET_free (msg1); #if VERBOSE FPRINTF (stderr, "%s", "Testing address iteration to copy HELLO...\n"); #endif i = 2; msg1 = GNUNET_HELLO_iterate_addresses (msg3, GNUNET_YES, &remove_some, &i); GNUNET_assert (msg1 != NULL); GNUNET_assert (i == 0); i = 1; GNUNET_assert (NULL == GNUNET_HELLO_iterate_addresses (msg1, GNUNET_NO, &check_addr, &i)); GNUNET_assert (i == 0); GNUNET_free (msg1); #if VERBOSE FPRINTF (stderr, "%s", "Testing delta address iteration...\n"); #endif i = 2; GNUNET_HELLO_iterate_new_addresses (msg3, msg2, startup_time, &check_addr, &i); GNUNET_assert (i == 0); GNUNET_free (msg2); GNUNET_free (msg3); return 0; /* testcase passed */ } gnunet-0.9.3/src/hello/hello.c0000644000175000017500000004707211760502551013121 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file hello/hello.c * @brief helper library for handling HELLOs * @author Christian Grothoff */ #include "platform.h" #include "gnunet_hello_lib.h" #include "gnunet_protocols.h" #include "gnunet_util_lib.h" GNUNET_NETWORK_STRUCT_BEGIN /** * A HELLO message is used to exchange information about * transports with other peers. This struct is always * followed by the actual network addresses which have * the format: * * 1) transport-name (0-terminated) * 2) address-length (uint16_t, network byte order; possibly * unaligned!) * 3) address expiration (GNUNET_TIME_AbsoluteNBO); possibly * unaligned!) * 4) address (address-length bytes; possibly unaligned!) */ struct GNUNET_HELLO_Message { /** * Type will be GNUNET_MESSAGE_TYPE_HELLO. */ struct GNUNET_MessageHeader header; /** * Always zero (for alignment). */ uint32_t reserved GNUNET_PACKED; /** * The public key of the peer. */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey; }; GNUNET_NETWORK_STRUCT_END /** * Copy the given address information into * the given buffer using the format of HELLOs. * * @param address the address * @param expiration expiration for the address * @param target where to copy the address * @param max maximum number of bytes to copy to target * @return number of bytes copied, 0 if * the target buffer was not big enough. */ size_t GNUNET_HELLO_add_address (const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration, char *target, size_t max) { uint16_t alen; size_t slen; struct GNUNET_TIME_AbsoluteNBO exp; slen = strlen (address->transport_name) + 1; if (slen + sizeof (uint16_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + address->address_length > max) return 0; exp = GNUNET_TIME_absolute_hton (expiration); alen = htons ((uint16_t) address->address_length); memcpy (target, address->transport_name, slen); memcpy (&target[slen], &alen, sizeof (uint16_t)); slen += sizeof (uint16_t); memcpy (&target[slen], &exp, sizeof (struct GNUNET_TIME_AbsoluteNBO)); slen += sizeof (struct GNUNET_TIME_AbsoluteNBO); memcpy (&target[slen], address->address, address->address_length); slen += address->address_length; return slen; } /** * Get the size of an address entry in a HELLO message. * * @param buf pointer to the start of the address entry * @param max maximum size of the entry (end of buf) * @param ralen set to the address length * @return size of the entry, or 0 if max is not large enough */ static size_t get_hello_address_size (const char *buf, size_t max, uint16_t * ralen) { const char *pos; uint16_t alen; size_t left; size_t slen; left = max; pos = buf; slen = 1; while ((left > 0) && ('\0' != *pos)) { left--; pos++; slen++; } if (left == 0) { /* 0-termination not found */ GNUNET_break_op (0); return 0; } pos++; if (left < sizeof (uint16_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO)) { /* not enough space for addrlen */ GNUNET_break_op (0); return 0; } memcpy (&alen, pos, sizeof (uint16_t)); alen = ntohs (alen); *ralen = alen; slen += alen + sizeof (uint16_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO); if (max < slen) { /* not enough space for addr */ GNUNET_break_op (0); return 0; } return slen; } /** * Construct a HELLO message given the public key, * expiration time and an iterator that spews the * transport addresses. * * @return the hello message */ struct GNUNET_HELLO_Message * GNUNET_HELLO_create (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey, GNUNET_HELLO_GenerateAddressListCallback addrgen, void *addrgen_cls) { char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - 256 - sizeof (struct GNUNET_HELLO_Message)]; size_t max; size_t used; size_t ret; struct GNUNET_HELLO_Message *hello; max = sizeof (buffer); used = 0; if (addrgen != NULL) { while (0 != (ret = addrgen (addrgen_cls, max, &buffer[used]))) { max -= ret; used += ret; } } hello = GNUNET_malloc (sizeof (struct GNUNET_HELLO_Message) + used); hello->header.type = htons (GNUNET_MESSAGE_TYPE_HELLO); hello->header.size = htons (sizeof (struct GNUNET_HELLO_Message) + used); memcpy (&hello->publicKey, publicKey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); memcpy (&hello[1], buffer, used); return hello; } /** * Iterate over all of the addresses in the HELLO. * * @param msg HELLO to iterate over * @param return_modified if a modified copy should be returned, * otherwise NULL will be returned * @param it iterator to call on each address * @param it_cls closure for it */ struct GNUNET_HELLO_Message * GNUNET_HELLO_iterate_addresses (const struct GNUNET_HELLO_Message *msg, int return_modified, GNUNET_HELLO_AddressIterator it, void *it_cls) { struct GNUNET_HELLO_Address address; uint16_t msize; struct GNUNET_HELLO_Message *ret; const char *inptr; size_t insize; size_t esize; size_t wpos; char *woff; uint16_t alen; struct GNUNET_TIME_AbsoluteNBO expire; int iret; msize = GNUNET_HELLO_size (msg); if ((msize < sizeof (struct GNUNET_HELLO_Message)) || (ntohs (msg->header.type) != GNUNET_MESSAGE_TYPE_HELLO)) return NULL; ret = NULL; if (return_modified) { ret = GNUNET_malloc (msize); memcpy (ret, msg, msize); } inptr = (const char *) &msg[1]; insize = msize - sizeof (struct GNUNET_HELLO_Message); wpos = 0; woff = (ret != NULL) ? (char *) &ret[1] : NULL; GNUNET_CRYPTO_hash (&msg->publicKey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &address.peer.hashPubKey); while (insize > 0) { esize = get_hello_address_size (inptr, insize, &alen); if (esize == 0) { GNUNET_break (0); GNUNET_free_non_null (ret); return NULL; } memcpy (&expire, &inptr[esize - alen - sizeof (struct GNUNET_TIME_AbsoluteNBO)], sizeof (struct GNUNET_TIME_AbsoluteNBO)); address.address = &inptr[esize - alen]; address.address_length = alen; address.transport_name = inptr; iret = it (it_cls, &address, GNUNET_TIME_absolute_ntoh (expire)); if (iret == GNUNET_SYSERR) { if (ret != NULL) ret->header.size = ntohs (sizeof (struct GNUNET_HELLO_Message) + wpos); return ret; } if ((iret == GNUNET_OK) && (ret != NULL)) { memcpy (woff, inptr, esize); woff += esize; wpos += esize; } insize -= esize; inptr += esize; } if (ret != NULL) ret->header.size = ntohs (sizeof (struct GNUNET_HELLO_Message) + wpos); return ret; } struct ExpireContext { const struct GNUNET_HELLO_Address *address; int found; struct GNUNET_TIME_Absolute expiration; }; static int get_match_exp (void *cls, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration) { struct ExpireContext *ec = cls; if (0 == GNUNET_HELLO_address_cmp (address, ec->address)) { ec->found = GNUNET_YES; ec->expiration = expiration; return GNUNET_SYSERR; /* done here */ } return GNUNET_OK; } struct MergeContext { const struct GNUNET_HELLO_Message *h1; const struct GNUNET_HELLO_Message *h2; const struct GNUNET_HELLO_Message *other; char *buf; size_t max; size_t ret; int take_equal; }; static int copy_latest (void *cls, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration) { struct MergeContext *mc = cls; struct ExpireContext ec; ec.address = address; ec.found = GNUNET_NO; GNUNET_HELLO_iterate_addresses (mc->other, GNUNET_NO, &get_match_exp, &ec); if ((ec.found == GNUNET_NO) || (ec.expiration.abs_value < expiration.abs_value) || ((ec.expiration.abs_value == expiration.abs_value) && (mc->take_equal == GNUNET_YES))) { mc->ret += GNUNET_HELLO_add_address (address, expiration, &mc->buf[mc->ret], mc->max - mc->ret); } return GNUNET_OK; } static size_t merge_addr (void *cls, size_t max, void *buf) { struct MergeContext *mc = cls; if (mc->h1 == NULL) return 0; mc->ret = 0; mc->max = max; mc->buf = buf; mc->take_equal = GNUNET_NO; mc->other = mc->h2; GNUNET_HELLO_iterate_addresses (mc->h1, GNUNET_NO, ©_latest, mc); mc->take_equal = GNUNET_YES; mc->other = mc->h1; GNUNET_HELLO_iterate_addresses (mc->h2, GNUNET_NO, ©_latest, mc); mc->h1 = NULL; return mc->ret; } /** * Construct a HELLO message by merging the * addresses in two existing HELLOs (which * must be for the same peer). * * @param h1 first HELLO message * @param h2 the second HELLO message * @return the combined hello message */ struct GNUNET_HELLO_Message * GNUNET_HELLO_merge (const struct GNUNET_HELLO_Message *h1, const struct GNUNET_HELLO_Message *h2) { struct MergeContext mc = { h1, h2, NULL, NULL, 0, 0, 0 }; return GNUNET_HELLO_create (&h1->publicKey, &merge_addr, &mc); } struct DeltaContext { struct GNUNET_TIME_Absolute expiration_limit; GNUNET_HELLO_AddressIterator it; void *it_cls; const struct GNUNET_HELLO_Message *old_hello; }; static int delta_match (void *cls, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration) { struct DeltaContext *dc = cls; int ret; struct ExpireContext ec; ec.address = address; ec.found = GNUNET_NO; GNUNET_HELLO_iterate_addresses (dc->old_hello, GNUNET_NO, &get_match_exp, &ec); if ((ec.found == GNUNET_YES) && ((ec.expiration.abs_value > expiration.abs_value) || (ec.expiration.abs_value >= dc->expiration_limit.abs_value))) return GNUNET_YES; /* skip */ ret = dc->it (dc->it_cls, address, expiration); return ret; } /** * Iterate over addresses in "new_hello" that * are NOT already present in "old_hello". * * @param new_hello a HELLO message * @param old_hello a HELLO message * @param expiration_limit ignore addresses in old_hello * that expired before the given time stamp * @param it iterator to call on each address * @param it_cls closure for it */ void GNUNET_HELLO_iterate_new_addresses (const struct GNUNET_HELLO_Message *new_hello, const struct GNUNET_HELLO_Message *old_hello, struct GNUNET_TIME_Absolute expiration_limit, GNUNET_HELLO_AddressIterator it, void *it_cls) { struct DeltaContext dc; dc.expiration_limit = expiration_limit; dc.it = it; dc.it_cls = it_cls; dc.old_hello = old_hello; GNUNET_HELLO_iterate_addresses (new_hello, GNUNET_NO, &delta_match, &dc); } /** * Return the size of the given HELLO message. * @param hello to inspect * @return the size, 0 if HELLO is invalid */ uint16_t GNUNET_HELLO_size (const struct GNUNET_HELLO_Message *hello) { uint16_t ret = ntohs (hello->header.size); if ((ret < sizeof (struct GNUNET_HELLO_Message)) || (ntohs (hello->header.type) != GNUNET_MESSAGE_TYPE_HELLO)) return 0; return ret; } /** * Get the public key from a HELLO message. * * @param hello the hello message * @param publicKey where to copy the public key information, can be NULL * @return GNUNET_SYSERR if the HELLO was malformed */ int GNUNET_HELLO_get_key (const struct GNUNET_HELLO_Message *hello, struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey) { uint16_t ret = ntohs (hello->header.size); if ((ret < sizeof (struct GNUNET_HELLO_Message)) || (ntohs (hello->header.type) != GNUNET_MESSAGE_TYPE_HELLO)) return GNUNET_SYSERR; *publicKey = hello->publicKey; return GNUNET_OK; } /** * Get the peer identity from a HELLO message. * * @param hello the hello message * @param peer where to store the peer's identity * @return GNUNET_SYSERR if the HELLO was malformed */ int GNUNET_HELLO_get_id (const struct GNUNET_HELLO_Message *hello, struct GNUNET_PeerIdentity *peer) { uint16_t ret = ntohs (hello->header.size); if ((ret < sizeof (struct GNUNET_HELLO_Message)) || (ntohs (hello->header.type) != GNUNET_MESSAGE_TYPE_HELLO)) return GNUNET_SYSERR; GNUNET_CRYPTO_hash (&hello->publicKey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &peer->hashPubKey); return GNUNET_OK; } /** * Get the header from a HELLO message, used so other code * can correctly send HELLO messages. * * @param hello the hello message * * @return header or NULL if the HELLO was malformed */ struct GNUNET_MessageHeader * GNUNET_HELLO_get_header (struct GNUNET_HELLO_Message *hello) { uint16_t ret = ntohs (hello->header.size); if ((ret < sizeof (struct GNUNET_HELLO_Message)) || (ntohs (hello->header.type) != GNUNET_MESSAGE_TYPE_HELLO)) return NULL; return &hello->header; } struct EqualsContext { struct GNUNET_TIME_Absolute expiration_limit; struct GNUNET_TIME_Absolute result; const struct GNUNET_HELLO_Message *h2; const struct GNUNET_HELLO_Address *address; struct GNUNET_TIME_Absolute expiration; int found; }; static int find_other_matching (void *cls, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration) { struct EqualsContext *ec = cls; if (expiration.abs_value < ec->expiration_limit.abs_value) return GNUNET_YES; if (0 == GNUNET_HELLO_address_cmp (address, ec->address)) { ec->found = GNUNET_YES; if (expiration.abs_value < ec->expiration.abs_value) ec->result = GNUNET_TIME_absolute_min (expiration, ec->result); return GNUNET_SYSERR; } return GNUNET_YES; } static int find_matching (void *cls, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration) { struct EqualsContext *ec = cls; if (expiration.abs_value < ec->expiration_limit.abs_value) return GNUNET_YES; ec->address = address; ec->expiration = expiration; ec->found = GNUNET_NO; GNUNET_HELLO_iterate_addresses (ec->h2, GNUNET_NO, &find_other_matching, ec); if (ec->found == GNUNET_NO) { ec->result = GNUNET_TIME_UNIT_ZERO_ABS; return GNUNET_SYSERR; } return GNUNET_OK; } /** * Test if two HELLO messages contain the same addresses. * If they only differ in expiration time, the lowest * expiration time larger than 'now' where they differ * is returned. * * @param h1 first HELLO message * @param h2 the second HELLO message * @param now time to use for deciding which addresses have * expired and should not be considered at all * @return absolute time forever if the two HELLOs are * totally identical; smallest timestamp >= now if * they only differ in timestamps; * zero if the some addresses with expirations >= now * do not match at all */ struct GNUNET_TIME_Absolute GNUNET_HELLO_equals (const struct GNUNET_HELLO_Message *h1, const struct GNUNET_HELLO_Message *h2, struct GNUNET_TIME_Absolute now) { struct EqualsContext ec; if (0 != memcmp (&h1->publicKey, &h2->publicKey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded))) return GNUNET_TIME_UNIT_ZERO_ABS; ec.expiration_limit = now; ec.result = GNUNET_TIME_UNIT_FOREVER_ABS; ec.h2 = h2; GNUNET_HELLO_iterate_addresses (h1, GNUNET_NO, &find_matching, &ec); if (ec.result.abs_value == GNUNET_TIME_UNIT_ZERO.rel_value) return ec.result; ec.h2 = h1; GNUNET_HELLO_iterate_addresses (h2, GNUNET_NO, &find_matching, &ec); return ec.result; } static int find_min_expire (void *cls, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration) { struct GNUNET_TIME_Absolute *min = cls; *min = GNUNET_TIME_absolute_min (*min, expiration); return GNUNET_OK; } /** * When does the last address in the given HELLO expire? * * @param msg HELLO to inspect * @return time the last address expires, 0 if there are no addresses in the HELLO */ struct GNUNET_TIME_Absolute GNUNET_HELLO_get_last_expiration (const struct GNUNET_HELLO_Message *msg) { struct GNUNET_TIME_Absolute ret; ret.abs_value = 0; GNUNET_HELLO_iterate_addresses (msg, GNUNET_NO, &find_min_expire, &ret); return ret; } /** * GNUnet URIs are of the general form "gnunet://MODULE/IDENTIFIER". * The specific structure of "IDENTIFIER" depends on the module and * maybe differenciated into additional subcategories if applicable. * This module only deals with hello identifiers (MODULE = "hello"). *

    * * The concrete URI format is: * * "gnunet://hello/PEER[!YYYYMMDDHHNNSS!!

    ]...". * These URIs can be used to add a peer record to peerinfo service. * PEER is the string representation of peer's public key. * YYYYMMDDHHNNSS is the expiration date. * TYPE is a transport type. * ADDRESS is the address, its format depends upon the transport type. * The concrete transport types and corresponding address formats are: * *
    • * * !IPADDRESS * IPVDDRESS is either IPV4 .-delimited address in form of XXX.XXX.XXX.XXX:PPPPP * or IPV6 :-delimited address, but with '(' and ')' instead of '[' and ']' (RFC2396 advises against using square brackets in URIs): * (XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX):PPPPP * PPPPP is the port number. May be 0. * *
    • * * [add SMTP, HTTP and other addresses here] * *
    * * The encoding for hexadecimal values is defined in the crypto_hash.c * module in the gnunetutil library and discussed there. * * Examples: * * gnunet://hello/0430205UC7D56PTQK8NV05776671CNN44FK4TL6D0GQ35OMF8MEN4RNMKA5UF6AL3DQO8B1SC5AQF50SQ2MABIRU4HC8H2HAJKJ59JL1JVRJAK308F9GASRFLMGUBB5TQ5AKR94AS5T3MDG8B9O1EMPRKB0HVCG7T6QPP4CDJ913LAEHVJ2DI1TOBB15Q1JIT5ARBOD12U4SIGRFDV3Q7T66G4TBVSJJ90UQF1BG29TGJJKLGEIMSPHHKO544D6EALQ4F2K0416311JC22GVAD48R616I7VK03K7MP7N0RS2MBV1TE9JV8CK1LSQMR7KCDRTLDA6917UGA67DHTGHERIACCGQ54TGSR48RMSGS9BA5HLMOKASFC1I6V4TT09TUGCU8GNDHQF0JF3H7LPV59UL5I38QID040G000!20120302010059!TCP!192.168.0.1:2086!TCP!64.23.8.174:0 * gnunet://hello/0430205UC7D56PTQK8NV05776671CNN44FK4TL6D0GQ35OMF8MEN4RNMKA5UF6AL3DQO8B1SC5AQF50SQ2MABIRU4HC8H2HAJKJ59JL1JVRJAK308F9GASRFLMGUBB5TQ5AKR94AS5T3MDG8B9O1EMPRKB0HVCG7T6QPP4CDJ913LAEHVJ2DI1TOBB15Q1JIT5ARBOD12U4SIGRFDV3Q7T66G4TBVSJJ90UQF1BG29TGJJKLGEIMSPHHKO544D6EALQ4F2K0416311JC22GVAD48R616I7VK03K7MP7N0RS2MBV1TE9JV8CK1LSQMR7KCDRTLDA6917UGA67DHTGHERIACCGQ54TGSR48RMSGS9BA5HLMOKASFC1I6V4TT09TUGCU8GNDHQF0JF3H7LPV59UL5I38QID040G000!20120302010059!TCP!(2001:db8:85a3:8d3:1319:8a2e:370:7348):2086 * *

    */ /* end of hello.c */ gnunet-0.9.3/src/hello/gnunet-hello.c0000644000175000017500000001146411760502551014413 00000000000000/* This file is part of GNUnet (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file hello/gnunet-hello.c * @brief change HELLO files to never expire * @author Christian Grothoff */ #include "platform.h" #include "gnunet_hello_lib.h" #define DEBUG GNUNET_EXTRA_LOGGING #define VERBOSE GNUNET_NO /** * Closure for 'add_to_buf'. */ struct AddContext { /** * Where to add. */ char *buf; /** * Maximum number of bytes left */ size_t max; /** * Number of bytes added so far. */ size_t ret; }; /** * Add the given address with infinit expiration to the buffer. * * @param cls closure * @param address address to add * @param expiration old expiration * @return GNUNET_OK keep iterating */ static int add_to_buf (void *cls, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration) { struct AddContext *ac = cls; size_t ret; ret = GNUNET_HELLO_add_address (address, GNUNET_TIME_UNIT_FOREVER_ABS, ac->buf, ac->max); ac->buf += ret; ac->max -= ret; ac->ret += ret; return GNUNET_OK; } /** * Add addresses from the address list to the HELLO. * * @param cls the HELLO with the addresses to add * @param max maximum space available * @param buf where to add the addresses * @return number of bytes added, 0 to terminate */ static size_t add_from_hello (void *cls, size_t max, void *buf) { struct GNUNET_HELLO_Message **orig = cls; struct AddContext ac; if (NULL == *orig) return 0; /* already done */ ac.buf = buf; ac.max = max; ac.ret = 0; GNUNET_assert (NULL == GNUNET_HELLO_iterate_addresses (*orig, GNUNET_NO, &add_to_buf, &ac)); *orig = NULL; return ac.ret; } int main (int argc, char *argv[]) { struct GNUNET_DISK_FileHandle *fh; struct GNUNET_HELLO_Message *orig; struct GNUNET_HELLO_Message *result; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk; uint64_t fsize; GNUNET_log_setup ("gnunet-hello", "INFO", NULL); if (argc != 2) { FPRINTF (stderr, "%s", _("Call with name of HELLO file to modify.\n")); return 1; } if (GNUNET_OK != GNUNET_DISK_file_size (argv[1], &fsize, GNUNET_YES, GNUNET_YES)) { FPRINTF (stderr, _("Error accessing file `%s': %s\n"), argv[1], STRERROR (errno)); return 1; } if (fsize > 65536) { FPRINTF (stderr, _("File `%s' is too big to be a HELLO\n"), argv[1]); return 1; } if (fsize < sizeof (struct GNUNET_MessageHeader)) { FPRINTF (stderr, _("File `%s' is too small to be a HELLO\n"), argv[1]); return 1; } fh = GNUNET_DISK_file_open (argv[1], GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_USER_READ); if (NULL == fh) { FPRINTF (stderr, _("Error opening file `%s': %s\n"), argv[1], STRERROR (errno)); return 1; } { char buf[fsize] GNUNET_ALIGN; GNUNET_assert (fsize == GNUNET_DISK_file_read (fh, buf, fsize)); GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); orig = (struct GNUNET_HELLO_Message *) buf; if ( (fsize != GNUNET_HELLO_size (orig)) || (GNUNET_OK != GNUNET_HELLO_get_key (orig, &pk)) ) { FPRINTF (stderr, _("Did not find well-formed HELLO in file `%s'\n"), argv[1]); return 1; } result = GNUNET_HELLO_create (&pk, &add_from_hello, &orig); GNUNET_assert (NULL != result); fh = GNUNET_DISK_file_open (argv[1], GNUNET_DISK_OPEN_WRITE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (NULL == fh) { FPRINTF (stderr, _("Error opening file `%s': %s\n"), argv[1], STRERROR (errno)); GNUNET_free (result); return 1; } fsize = GNUNET_HELLO_size (result); if (fsize != GNUNET_DISK_file_write (fh, result, fsize)) { FPRINTF (stderr, _("Error writing HELLO to file `%s': %s\n"), argv[1], STRERROR (errno)); (void) GNUNET_DISK_file_close (fh); return 1; } GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); } return 0; } /* end of gnunet-hello.c */ gnunet-0.9.3/src/hello/Makefile.in0000644000175000017500000006246611762217212013722 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ noinst_PROGRAMS = gnunet-hello$(EXEEXT) check_PROGRAMS = test_hello$(EXEEXT) subdir = src/hello DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libgnunethello_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) am_libgnunethello_la_OBJECTS = hello.lo address.lo libgnunethello_la_OBJECTS = $(am_libgnunethello_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunethello_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunethello_la_LDFLAGS) $(LDFLAGS) \ -o $@ PROGRAMS = $(noinst_PROGRAMS) am_gnunet_hello_OBJECTS = gnunet-hello.$(OBJEXT) gnunet_hello_OBJECTS = $(am_gnunet_hello_OBJECTS) am_test_hello_OBJECTS = test_hello.$(OBJEXT) test_hello_OBJECTS = $(am_test_hello_OBJECTS) test_hello_DEPENDENCIES = $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunethello_la_SOURCES) $(gnunet_hello_SOURCES) \ $(test_hello_SOURCES) DIST_SOURCES = $(libgnunethello_la_SOURCES) $(gnunet_hello_SOURCES) \ $(test_hello_SOURCES) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @USE_COVERAGE_TRUE@XLIB = -lgcov lib_LTLIBRARIES = libgnunethello.la libgnunethello_la_SOURCES = \ hello.c address.c libgnunethello_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la $(XLIB) libgnunethello_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:0:0 @ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) test_hello_SOURCES = \ test_hello.c test_hello_LDADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la gnunet_hello_SOURCES = \ gnunet-hello.c gnunet_hello_LDADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la gnunet_hello_DEPENDENCIES = \ libgnunethello.la \ $(top_builddir)/src/util/libgnunetutil.la all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/hello/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/hello/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunethello.la: $(libgnunethello_la_OBJECTS) $(libgnunethello_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunethello_la_LINK) -rpath $(libdir) $(libgnunethello_la_OBJECTS) $(libgnunethello_la_LIBADD) $(LIBS) clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-hello$(EXEEXT): $(gnunet_hello_OBJECTS) $(gnunet_hello_DEPENDENCIES) @rm -f gnunet-hello$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_hello_OBJECTS) $(gnunet_hello_LDADD) $(LIBS) test_hello$(EXEEXT): $(test_hello_OBJECTS) $(test_hello_DEPENDENCIES) @rm -f test_hello$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_hello_OBJECTS) $(test_hello_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/address.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-hello.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hello.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_hello.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool clean-noinstPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool clean-noinstPROGRAMS ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libLTLIBRARIES install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/regex/0000755000175000017500000000000011763406751011737 500000000000000gnunet-0.9.3/src/regex/test_regex_eval_api.c0000644000175000017500000002110311760502551016021 00000000000000/* This file is part of GNUnet (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file regex/test_regex_eval_api.c * @brief test for regex.c * @author Maximilian Szengel */ #include #include #include "platform.h" #include "gnunet_regex_lib.h" enum Match_Result { match = 0, nomatch = 1 }; struct Regex_String_Pair { char *regex; int string_count; char *strings[20]; enum Match_Result expected_results[20]; }; static const char allowed_literals[] = "0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"; int test_random (unsigned int rx_length, unsigned int max_str_len, unsigned int str_count) { int i; int j; int rx_exp; char rand_rx[rx_length + 1]; char matching_str[str_count][max_str_len + 1]; char *rand_rxp; char *matching_strp; int char_op_switch; int last_was_op; char current_char; int eval; int eval_check; struct GNUNET_REGEX_Automaton *dfa; regex_t rx; regmatch_t matchptr[1]; char error[200]; int result; unsigned int str_len; // At least one string is needed for matching GNUNET_assert (str_count > 0); // The string should be at least as long as the regex itself GNUNET_assert (max_str_len >= rx_length); rand_rxp = rand_rx; matching_strp = matching_str[0]; current_char = 0; last_was_op = 1; // Generate random regex and a string that matches the regex for (i = 0; i < rx_length; i++) { char_op_switch = 0 + (int) (1.0 * rand () / (RAND_MAX + 1.0)); if (0 == char_op_switch && !last_was_op) { last_was_op = 1; rx_exp = rand () % 4; switch (rx_exp) { case 0: current_char = '+'; break; case 1: current_char = '*'; break; case 2: current_char = '?'; break; case 3: if (i < rx_length - 1) // '|' cannot be at the end current_char = '|'; else current_char = allowed_literals[rand () % (sizeof (allowed_literals) - 1)]; break; } } else { current_char = allowed_literals[rand () % (sizeof (allowed_literals) - 1)]; last_was_op = 0; } if (current_char != '+' && current_char != '*' && current_char != '?' && current_char != '|') { *matching_strp = current_char; matching_strp++; } *rand_rxp = current_char; rand_rxp++; } *rand_rxp = '\0'; *matching_strp = '\0'; // Generate some random strings for matching... // Start at 1, because the first string is generated above during regex generation for (i = 1; i < str_count; i++) { str_len = rand () % max_str_len; for (j = 0; j < str_len; j++) matching_str[i][j] = allowed_literals[rand () % (sizeof (allowed_literals) - 1)]; matching_str[i][str_len] = '\0'; } // Now match result = 0; for (i = 0; i < str_count; i++) { // Match string using DFA dfa = GNUNET_REGEX_construct_dfa (rand_rx, strlen (rand_rx)); if (NULL == dfa) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constructing DFA failed\n"); return -1; } eval = GNUNET_REGEX_eval (dfa, matching_str[i]); GNUNET_REGEX_automaton_destroy (dfa); // Match string using glibc regex if (0 != regcomp (&rx, rand_rx, REG_EXTENDED)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not compile regex using regcomp\n"); return -1; } eval_check = regexec (&rx, matching_str[i], 1, matchptr, 0); regfree (&rx); // We only want to match the whole string, because that's what our DFA does, too. if (eval_check == 0 && (matchptr[0].rm_so != 0 || matchptr[0].rm_eo != strlen (matching_str[i]))) eval_check = 1; // compare result if (eval_check != eval) { regerror (eval_check, &rx, error, sizeof error); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected result:\nregex: %s\nstring: %s\ngnunet regex: %i\nglibc regex: %i\nglibc error: %s\n\n", rand_rx, matching_str, eval, eval_check, error); result += 1; } } return result; } int test_automaton (struct GNUNET_REGEX_Automaton *a, regex_t * rx, struct Regex_String_Pair *rxstr) { int result; int eval; int eval_check; char error[200]; regmatch_t matchptr[1]; int i; if (NULL == a) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Automaton was NULL\n"); return 1; } result = 0; for (i = 0; i < rxstr->string_count; i++) { eval = GNUNET_REGEX_eval (a, rxstr->strings[i]); eval_check = regexec (rx, rxstr->strings[i], 1, matchptr, 0); // We only want to match the whole string, because that's what our DFA does, too. if (eval_check == 0 && (matchptr[0].rm_so != 0 || matchptr[0].rm_eo != strlen (rxstr->strings[i]))) eval_check = 1; if ((rxstr->expected_results[i] == match && (0 != eval || 0 != eval_check)) || (rxstr->expected_results[i] == nomatch && (0 == eval || 0 == eval_check))) { result = 1; regerror (eval_check, rx, error, sizeof error); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected result:\nregex: %s\nstring: %s\nexpected result: %i\n" "gnunet regex: %i\nglibc regex: %i\nglibc error: %s\nrm_so: %i\nrm_eo: %i\n\n", rxstr->regex, rxstr->strings[i], rxstr->expected_results[i], eval, eval_check, error, matchptr[0].rm_so, matchptr[0].rm_eo); } } return result; } int main (int argc, char *argv[]) { GNUNET_log_setup ("test-regex", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); struct GNUNET_REGEX_Automaton *a; regex_t rx; int i; int check_nfa; int check_dfa; int check_rand; struct Regex_String_Pair rxstr[8] = { {"ab?(abcd)?", 5, {"ababcd", "abab", "aabcd", "a", "abb"}, {match, nomatch, match, match, nomatch}}, {"ab(c|d)+c*(a(b|c)d)+", 5, {"abcdcdcdcdddddabd", "abcd", "abcddddddccccccccccccccccccccccccabdacdabd", "abccccca", "abcdcdcdccdabdabd"}, {match, nomatch, match, nomatch, match}}, {"ab+c*(a(bx|c)d)+", 5, {"abcdcdcdcdddddabd", "abcd", "abcddddddccccccccccccccccccccccccabdacdabd", "abccccca", "abcdcdcdccdabdabd"}, {nomatch, nomatch, nomatch, nomatch, nomatch}}, {"a+X*y+c|p|R|Z*K*y*R+w|Y*6+n+h*k*w+V*F|W*B*e*", 1, {"kaXycQepRZKyRwY6nhkwVFWBegNVtLPj39XhJJ6bEifRSZRYZg"}, {nomatch}}, {"k|a+X*y+c|Q*e|p|R|Z*K*y*R+w|Y*6+n+h*k*w+V*F|W*B*e*g|N+V|t+L|P*j*3*9+X*h*J|J*6|b|E*i*f*R+S|Z|R|Y*Z|g*", 1, {"kaXycQepRZKyRwY6nhkwVFWBegNVtLPj39XhJJ6bEifRSZRYZg"}, {nomatch}}, {"F?W+m+2*6*c*s|P?U?a|B|y*i+t+A|V|6*C*7*e?Z*n*i|J?5+g?W*V?7*j?p?1|r?B?C+E+3+6*i+W*P?K?0|D+7?y*m+3?g?K?", 1, {"osfjsodfonONONOnosndfsdnfsd"}, {nomatch}}, {"V|M*o?x*p*d+h+b|E*m?h?Y*E*O?W*W*P+o?Z+H*M|I*q+C*a+5?5*9|b?z|G*y*k?R|p+u|8*h?B+l*H|e|L*O|1|F?v*0?5|C+", 1, {"VMoxpdhbEmhYEOWWPoZHMIqCa559bzGykRpu8hBlHeLO1Fv05C"}, {nomatch}}, {"ab(c|d)+c*(a(b|c)d)+", 1, {"abacd"}, {nomatch}} }; check_nfa = 0; check_dfa = 0; check_rand = 0; for (i = 0; i < 8; i++) { if (0 != regcomp (&rx, rxstr[i].regex, REG_EXTENDED)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not compile regex using regcomp()\n"); return 1; } // NFA test a = GNUNET_REGEX_construct_nfa (rxstr[i].regex, strlen (rxstr[i].regex)); check_nfa += test_automaton (a, &rx, &rxstr[i]); GNUNET_REGEX_automaton_destroy (a); // DFA test a = GNUNET_REGEX_construct_dfa (rxstr[i].regex, strlen (rxstr[i].regex)); check_dfa += test_automaton (a, &rx, &rxstr[i]); GNUNET_REGEX_automaton_destroy (a); regfree (&rx); } srand (time (NULL)); for (i = 0; i < 150; i++) check_rand += test_random (150, 200, 25); return check_nfa + check_dfa + check_rand; } gnunet-0.9.3/src/regex/Makefile.am0000644000175000017500000000161111752320520013675 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif if USE_COVERAGE AM_CFLAGS = --coverage endif lib_LTLIBRARIES = libgnunetregex.la libgnunetregex_la_SOURCES = \ regex.c libgnunetregex_la_LIBADD = -lm \ $(top_builddir)/src/util/libgnunetutil.la libgnunetregex_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:0:0 check_PROGRAMS = \ test_regex_eval_api \ test_regex_iterate_api if ENABLE_TEST_RUN TESTS = $(check_PROGRAMS) endif test_regex_eval_api_SOURCES = \ test_regex_eval_api.c test_regex_eval_api_LDADD = \ $(top_builddir)/src/regex/libgnunetregex.la \ $(top_builddir)/src/util/libgnunetutil.la test_regex_iterate_api_SOURCES = \ test_regex_iterate_api.c test_regex_iterate_api_LDADD = \ $(top_builddir)/src/regex/libgnunetregex.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = # test_regex_data.conf gnunet-0.9.3/src/regex/regex.c0000644000175000017500000015022011760502551013125 00000000000000/* This file is part of GNUnet (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/regex/regex.c * @brief library to create automatons from regular expressions * @author Maximilian Szengel */ #include "platform.h" #include "gnunet_container_lib.h" #include "gnunet_crypto_lib.h" #include "gnunet_regex_lib.h" #include "regex.h" #define initial_bits 10 /** * Context that contains an id counter for states and transitions as well as a * DLL of automatons used as a stack for NFA construction. */ struct GNUNET_REGEX_Context { /** * Unique state id. */ unsigned int state_id; /** * Unique transition id. */ unsigned int transition_id; /** * Unique SCC (Strongly Connected Component) id. */ unsigned int scc_id; /** * DLL of GNUNET_REGEX_Automaton's used as a stack. */ struct GNUNET_REGEX_Automaton *stack_head; /** * DLL of GNUNET_REGEX_Automaton's used as a stack. */ struct GNUNET_REGEX_Automaton *stack_tail; }; /** * Type of an automaton. */ enum GNUNET_REGEX_automaton_type { NFA, DFA }; /** * Automaton representation. */ struct GNUNET_REGEX_Automaton { /** * This is a linked list. */ struct GNUNET_REGEX_Automaton *prev; /** * This is a linked list. */ struct GNUNET_REGEX_Automaton *next; /** * First state of the automaton. This is mainly used for constructing an NFA, * where each NFA itself consists of one or more NFAs linked together. */ struct GNUNET_REGEX_State *start; /** * End state of the automaton. */ struct GNUNET_REGEX_State *end; /** * Number of states in the automaton. */ unsigned int state_count; /** * DLL of states. */ struct GNUNET_REGEX_State *states_head; /** * DLL of states */ struct GNUNET_REGEX_State *states_tail; /** * Type of the automaton. */ enum GNUNET_REGEX_automaton_type type; }; /** * A state. Can be used in DFA and NFA automatons. */ struct GNUNET_REGEX_State { /** * This is a linked list. */ struct GNUNET_REGEX_State *prev; /** * This is a linked list. */ struct GNUNET_REGEX_State *next; /** * Unique state id. */ unsigned int id; /** * If this is an accepting state or not. */ int accepting; /** * Marking of the state. This is used for marking all visited states when * traversing all states of an automaton and for cases where the state id * cannot be used (dfa minimization). */ int marked; /** * Marking the state as contained. This is used for checking, if the state is * contained in a set in constant time */ int contained; /** * Marking the state as part of an SCC (Strongly Connected Component). All * states with the same scc_id are part of the same SCC. scc_id is 0, if state * is not a part of any SCC. */ unsigned int scc_id; /** * Used for SCC detection. */ int index; /** * Used for SCC detection. */ int lowlink; /** * Human readable name of the automaton. Used for debugging and graph * creation. */ char *name; /** * Hash of the state. */ GNUNET_HashCode hash; /** * Proof for this state. */ char *proof; /** * Number of transitions from this state to other states. */ unsigned int transition_count; /** * DLL of transitions. */ struct Transition *transitions_head; /** * DLL of transitions. */ struct Transition *transitions_tail; /** * Set of states on which this state is based on. Used when creating a DFA out * of several NFA states. */ struct GNUNET_REGEX_StateSet *nfa_set; }; /** * Transition between two states. Each state can have 0-n transitions. If label * is 0, this is considered to be an epsilon transition. */ struct Transition { /** * This is a linked list. */ struct Transition *prev; /** * This is a linked list. */ struct Transition *next; /** * Unique id of this transition. */ unsigned int id; /** * Label for this transition. This is basically the edge label for the graph. */ char label; /** * State to which this transition leads. */ struct GNUNET_REGEX_State *to_state; /** * State from which this transition origins. */ struct GNUNET_REGEX_State *from_state; /** * Mark this transition. For example when reversing the automaton. */ int mark; }; /** * Set of states. */ struct GNUNET_REGEX_StateSet { /** * Array of states. */ struct GNUNET_REGEX_State **states; /** * Length of the 'states' array. */ unsigned int len; }; /* * Debug helper functions */ void debug_print_transitions (struct GNUNET_REGEX_State *); void debug_print_state (struct GNUNET_REGEX_State *s) { char *proof; if (NULL == s->proof) proof = "NULL"; else proof = s->proof; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "State %i: %s marked: %i accepting: %i scc_id: %i transitions: %i proof: %s\n", s->id, s->name, s->marked, s->accepting, s->scc_id, s->transition_count, proof); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transitions:\n"); debug_print_transitions (s); } void debug_print_states (struct GNUNET_REGEX_Automaton *a) { struct GNUNET_REGEX_State *s; for (s = a->states_head; NULL != s; s = s->next) debug_print_state (s); } void debug_print_transition (struct Transition *t) { char *to_state; char *from_state; char label; if (NULL == t) return; if (0 == t->label) label = '0'; else label = t->label; if (NULL == t->to_state) to_state = "NULL"; else to_state = t->to_state->name; if (NULL == t->from_state) from_state = "NULL"; else from_state = t->from_state->name; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transition %i: From %s on %c to %s\n", t->id, from_state, label, to_state); } void debug_print_transitions (struct GNUNET_REGEX_State *s) { struct Transition *t; for (t = s->transitions_head; NULL != t; t = t->next) debug_print_transition (t); } /** * Recursive function doing DFS with 'v' as a start, detecting all SCCs inside * the subgraph reachable from 'v'. Used with scc_tarjan function to detect all * SCCs inside an automaton. * * @param ctx context * @param v start vertex * @param index current index * @param stack stack for saving all SCCs * @param stack_size current size of the stack */ static void scc_tarjan_strongconnect (struct GNUNET_REGEX_Context *ctx, struct GNUNET_REGEX_State *v, int *index, struct GNUNET_REGEX_State **stack, unsigned int *stack_size) { struct GNUNET_REGEX_State *w; struct Transition *t; v->index = *index; v->lowlink = *index; (*index)++; stack[(*stack_size)++] = v; v->contained = 1; for (t = v->transitions_head; NULL != t; t = t->next) { w = t->to_state; if (NULL != w && w->index < 0) { scc_tarjan_strongconnect (ctx, w, index, stack, stack_size); v->lowlink = (v->lowlink > w->lowlink) ? w->lowlink : v->lowlink; } else if (0 != w->contained) v->lowlink = (v->lowlink > w->index) ? w->index : v->lowlink; } if (v->lowlink == v->index) { w = stack[--(*stack_size)]; w->contained = 0; if (v != w) { ctx->scc_id++; while (v != w) { w->scc_id = ctx->scc_id; w = stack[--(*stack_size)]; w->contained = 0; } w->scc_id = ctx->scc_id; } } } /** * Detect all SCCs (Strongly Connected Components) inside the given automaton. * SCCs will be marked using the scc_id on each state. * * @param ctx context * @param a automaton */ static void scc_tarjan (struct GNUNET_REGEX_Context *ctx, struct GNUNET_REGEX_Automaton *a) { int index; struct GNUNET_REGEX_State *v; struct GNUNET_REGEX_State *stack[a->state_count]; unsigned int stack_size; for (v = a->states_head; NULL != v; v = v->next) { v->contained = 0; v->index = -1; v->lowlink = -1; } stack_size = 0; index = 0; for (v = a->states_head; NULL != v; v = v->next) { if (v->index < 0) scc_tarjan_strongconnect (ctx, v, &index, stack, &stack_size); } } /** * Adds a transition from one state to another on 'label'. Does not add * duplicate states. * * @param ctx context * @param from_state starting state for the transition * @param label transition label * @param to_state state to where the transition should point to */ static void state_add_transition (struct GNUNET_REGEX_Context *ctx, struct GNUNET_REGEX_State *from_state, const char label, struct GNUNET_REGEX_State *to_state) { int is_dup; struct Transition *t; if (NULL == from_state) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not create Transition.\n"); return; } // Do not add duplicate state transitions is_dup = GNUNET_NO; for (t = from_state->transitions_head; NULL != t; t = t->next) { if (t->to_state == to_state && t->label == label && t->from_state == from_state) { is_dup = GNUNET_YES; break; } } if (is_dup) return; t = GNUNET_malloc (sizeof (struct Transition)); t->id = ctx->transition_id++; t->label = label; t->to_state = to_state; t->from_state = from_state; // Add outgoing transition to 'from_state' from_state->transition_count++; GNUNET_CONTAINER_DLL_insert (from_state->transitions_head, from_state->transitions_tail, t); } /** * Compare two states. Used for sorting. * * @param a first state * @param b second state * * @return an integer less than, equal to, or greater than zero * if the first argument is considered to be respectively * less than, equal to, or greater than the second. */ static int state_compare (const void *a, const void *b) { struct GNUNET_REGEX_State **s1; struct GNUNET_REGEX_State **s2; s1 = (struct GNUNET_REGEX_State **) a; s2 = (struct GNUNET_REGEX_State **) b; return (*s1)->id - (*s2)->id; } /** * Get all edges leaving state 's'. * * @param s state. * @param edges all edges leaving 's'. * * @return number of edges. */ static unsigned int state_get_edges (struct GNUNET_REGEX_State *s, struct GNUNET_REGEX_Edge *edges) { struct Transition *t; unsigned int count; if (NULL == s) return 0; count = 0; for (t = s->transitions_head; NULL != t; t = t->next) { if (NULL != t->to_state) { edges[count].label = &t->label; edges[count].destination = t->to_state->hash; count++; } } return count; } /** * Compare to state sets by comparing the id's of the states that are contained * in each set. Both sets are expected to be sorted by id! * * @param sset1 first state set * @param sset2 second state set * * @return an integer less than, equal to, or greater than zero * if the first argument is considered to be respectively * less than, equal to, or greater than the second. */ static int state_set_compare (struct GNUNET_REGEX_StateSet *sset1, struct GNUNET_REGEX_StateSet *sset2) { int result; int i; if (NULL == sset1 || NULL == sset2) return 1; result = sset1->len - sset2->len; for (i = 0; i < sset1->len; i++) { if (0 != result) break; result = state_compare (&sset1->states[i], &sset2->states[i]); } return result; } /** * Clears the given StateSet 'set' * * @param set set to be cleared */ static void state_set_clear (struct GNUNET_REGEX_StateSet *set) { if (NULL != set) { if (NULL != set->states) GNUNET_free (set->states); GNUNET_free (set); } } /** * Clears an automaton fragment. Does not destroy the states inside the * automaton. * * @param a automaton to be cleared */ static void automaton_fragment_clear (struct GNUNET_REGEX_Automaton *a) { if (NULL == a) return; a->start = NULL; a->end = NULL; a->states_head = NULL; a->states_tail = NULL; a->state_count = 0; GNUNET_free (a); } /** * Frees the memory used by State 's' * * @param s state that should be destroyed */ static void automaton_destroy_state (struct GNUNET_REGEX_State *s) { struct Transition *t; struct Transition *next_t; if (NULL == s) return; if (NULL != s->name) GNUNET_free (s->name); if (NULL != s->proof) GNUNET_free (s->proof); for (t = s->transitions_head; NULL != t; t = next_t) { next_t = t->next; GNUNET_CONTAINER_DLL_remove (s->transitions_head, s->transitions_tail, t); GNUNET_free (t); } state_set_clear (s->nfa_set); GNUNET_free (s); } /** * Remove a state from the given automaton 'a'. Always use this function when * altering the states of an automaton. Will also remove all transitions leading * to this state, before destroying it. * * @param a automaton * @param s state to remove */ static void automaton_remove_state (struct GNUNET_REGEX_Automaton *a, struct GNUNET_REGEX_State *s) { struct GNUNET_REGEX_State *ss; struct GNUNET_REGEX_State *s_check; struct Transition *t_check; if (NULL == a || NULL == s) return; // remove state ss = s; GNUNET_CONTAINER_DLL_remove (a->states_head, a->states_tail, s); a->state_count--; // remove all transitions leading to this state for (s_check = a->states_head; NULL != s_check; s_check = s_check->next) { for (t_check = s_check->transitions_head; NULL != t_check; t_check = t_check->next) { if (t_check->to_state == ss) { GNUNET_CONTAINER_DLL_remove (s_check->transitions_head, s_check->transitions_tail, t_check); s_check->transition_count--; } } } automaton_destroy_state (ss); } /** * Merge two states into one. Will merge 's1' and 's2' into 's1' and destroy * 's2'. * * @param ctx context * @param a automaton * @param s1 first state * @param s2 second state, will be destroyed */ static void automaton_merge_states (struct GNUNET_REGEX_Context *ctx, struct GNUNET_REGEX_Automaton *a, struct GNUNET_REGEX_State *s1, struct GNUNET_REGEX_State *s2) { struct GNUNET_REGEX_State *s_check; struct Transition *t_check; char *new_name; GNUNET_assert (NULL != ctx && NULL != a && NULL != s1 && NULL != s2); if (s1 == s2) return; // 1. Make all transitions pointing to s2 point to s1 for (s_check = a->states_head; NULL != s_check; s_check = s_check->next) { for (t_check = s_check->transitions_head; NULL != t_check; t_check = t_check->next) { if (s2 == t_check->to_state) t_check->to_state = s1; } } // 2. Add all transitions from s2 to sX to s1 for (t_check = s2->transitions_head; NULL != t_check; t_check = t_check->next) { if (t_check->to_state != s1) state_add_transition (ctx, s1, t_check->label, t_check->to_state); } // 3. Rename s1 to {s1,s2} new_name = GNUNET_strdup (s1->name); if (NULL != s1->name) { GNUNET_free (s1->name); s1->name = NULL; } GNUNET_asprintf (&s1->name, "{%s,%s}", new_name, s2->name); GNUNET_free (new_name); // remove state GNUNET_CONTAINER_DLL_remove (a->states_head, a->states_tail, s2); a->state_count--; automaton_destroy_state (s2); } /** * Add a state to the automaton 'a', always use this function to alter the * states DLL of the automaton. * * @param a automaton to add the state to * @param s state that should be added */ static void automaton_add_state (struct GNUNET_REGEX_Automaton *a, struct GNUNET_REGEX_State *s) { GNUNET_CONTAINER_DLL_insert (a->states_head, a->states_tail, s); a->state_count++; } /** * Function that is called with each state, when traversing an automaton. * * @param cls closure * @param s state */ typedef void (*GNUNET_REGEX_traverse_action) (void *cls, struct GNUNET_REGEX_State * s); /** * Traverses all states that are reachable from state 's'. Expects the states to * be unmarked (s->marked == GNUNET_NO). Performs 'action' on each visited * state. * * @param cls closure. * @param s start state. * @param action action to be performed on each state. */ static void automaton_state_traverse (void *cls, struct GNUNET_REGEX_State *s, GNUNET_REGEX_traverse_action action) { struct Transition *t; if (GNUNET_NO == s->marked) { s->marked = GNUNET_YES; if (action > 0) action (cls, s); for (t = s->transitions_head; NULL != t; t = t->next) automaton_state_traverse (cls, t->to_state, action); } } /** * Traverses the given automaton from it's start state, visiting all reachable * states and calling 'action' on each one of them. * * @param cls closure. * @param a automaton. * @param action action to be performed on each state. */ static void automaton_traverse (void *cls, struct GNUNET_REGEX_Automaton *a, GNUNET_REGEX_traverse_action action) { struct GNUNET_REGEX_State *s; for (s = a->states_head; NULL != s; s = s->next) s->marked = GNUNET_NO; automaton_state_traverse (cls, a->start, action); } /** * Reverses all transitions of the given automaton. * * @param a automaton. */ static void automaton_reverse (struct GNUNET_REGEX_Automaton *a) { struct GNUNET_REGEX_State *s; struct Transition *t; struct Transition *t_next; struct GNUNET_REGEX_State *s_swp; for (s = a->states_head; NULL != s; s = s->next) for (t = s->transitions_head; NULL != t; t = t->next) t->mark = GNUNET_NO; for (s = a->states_head; NULL != s; s = s->next) { for (t = s->transitions_head; NULL != t; t = t_next) { t_next = t->next; if (GNUNET_YES == t->mark || t->from_state == t->to_state) continue; t->mark = GNUNET_YES; GNUNET_CONTAINER_DLL_remove (t->from_state->transitions_head, t->from_state->transitions_tail, t); t->from_state->transition_count--; GNUNET_CONTAINER_DLL_insert (t->to_state->transitions_head, t->to_state->transitions_tail, t); t->to_state->transition_count++; s_swp = t->from_state; t->from_state = t->to_state; t->to_state = s_swp; } } } /** * Create proof for the given state. * * @param cls closure. * @param s state. */ static void automaton_create_proofs_step (void *cls, struct GNUNET_REGEX_State *s) { struct Transition *t; int i; char *tmp; for (i = 0, t = s->transitions_head; NULL != t; t = t->next, i++) { if (t->to_state == s) GNUNET_asprintf (&tmp, "%c*", t->label); else if (i != s->transition_count - 1) GNUNET_asprintf (&tmp, "%c|", t->label); else GNUNET_asprintf (&tmp, "%c", t->label); if (NULL != s->proof) s->proof = GNUNET_realloc (s->proof, strlen (s->proof) + strlen (tmp) + 1); else s->proof = GNUNET_malloc (strlen (tmp) + 1); strcat (s->proof, tmp); GNUNET_free (tmp); } } /** * Create proofs for all states in the given automaton. * * @param a automaton. */ static void automaton_create_proofs (struct GNUNET_REGEX_Automaton *a) { struct GNUNET_REGEX_State *s; automaton_reverse (a); for (s = a->states_head; NULL != s; s = s->next) automaton_create_proofs_step (NULL, s); automaton_reverse (a); } /** * Creates a new DFA state based on a set of NFA states. Needs to be freed using * automaton_destroy_state. * * @param ctx context * @param nfa_states set of NFA states on which the DFA should be based on * * @return new DFA state */ static struct GNUNET_REGEX_State * dfa_state_create (struct GNUNET_REGEX_Context *ctx, struct GNUNET_REGEX_StateSet *nfa_states) { struct GNUNET_REGEX_State *s; char *name; int len = 0; struct GNUNET_REGEX_State *cstate; struct Transition *ctran; int insert = 1; struct Transition *t; int i; s = GNUNET_malloc (sizeof (struct GNUNET_REGEX_State)); s->id = ctx->state_id++; s->accepting = 0; s->marked = 0; s->name = NULL; s->scc_id = 0; s->index = -1; s->lowlink = -1; s->contained = 0; s->proof = NULL; if (NULL == nfa_states) { GNUNET_asprintf (&s->name, "s%i", s->id); return s; } s->nfa_set = nfa_states; if (nfa_states->len < 1) return s; // Create a name based on 'sset' s->name = GNUNET_malloc (sizeof (char) * 2); strcat (s->name, "{"); name = NULL; for (i = 0; i < nfa_states->len; i++) { cstate = nfa_states->states[i]; GNUNET_asprintf (&name, "%i,", cstate->id); if (NULL != name) { len = strlen (s->name) + strlen (name) + 1; s->name = GNUNET_realloc (s->name, len); strcat (s->name, name); GNUNET_free (name); name = NULL; } // Add a transition for each distinct label to NULL state for (ctran = cstate->transitions_head; NULL != ctran; ctran = ctran->next) { if (0 != ctran->label) { insert = 1; for (t = s->transitions_head; NULL != t; t = t->next) { if (t->label == ctran->label) { insert = 0; break; } } if (insert) state_add_transition (ctx, s, ctran->label, NULL); } } // If the nfa_states contain an accepting state, the new dfa state is also // accepting if (cstate->accepting) s->accepting = 1; } s->name[strlen (s->name) - 1] = '}'; return s; } /** * Move from the given state 's' to the next state on transition 'label' * * @param s starting state * @param label edge label to follow * * @return new state or NULL, if transition on label not possible */ static struct GNUNET_REGEX_State * dfa_move (struct GNUNET_REGEX_State *s, const char label) { struct Transition *t; struct GNUNET_REGEX_State *new_s; if (NULL == s) return NULL; new_s = NULL; for (t = s->transitions_head; NULL != t; t = t->next) { if (label == t->label) { new_s = t->to_state; break; } } return new_s; } /** * Remove all unreachable states from DFA 'a'. Unreachable states are those * states that are not reachable from the starting state. * * @param a DFA automaton */ static void dfa_remove_unreachable_states (struct GNUNET_REGEX_Automaton *a) { struct GNUNET_REGEX_State *s; struct GNUNET_REGEX_State *s_next; // 1. unmark all states for (s = a->states_head; NULL != s; s = s->next) s->marked = GNUNET_NO; // 2. traverse dfa from start state and mark all visited states automaton_traverse (NULL, a, NULL); // 3. delete all states that were not visited for (s = a->states_head; NULL != s; s = s_next) { s_next = s->next; if (GNUNET_NO == s->marked) automaton_remove_state (a, s); } } /** * Remove all dead states from the DFA 'a'. Dead states are those states that do * not transition to any other state but themselfes. * * @param a DFA automaton */ static void dfa_remove_dead_states (struct GNUNET_REGEX_Automaton *a) { struct GNUNET_REGEX_State *s; struct Transition *t; int dead; GNUNET_assert (DFA == a->type); for (s = a->states_head; NULL != s; s = s->next) { if (s->accepting) continue; dead = 1; for (t = s->transitions_head; NULL != t; t = t->next) { if (NULL != t->to_state && t->to_state != s) { dead = 0; break; } } if (0 == dead) continue; // state s is dead, remove it automaton_remove_state (a, s); } } /** * Merge all non distinguishable states in the DFA 'a' * * @param ctx context * @param a DFA automaton */ static void dfa_merge_nondistinguishable_states (struct GNUNET_REGEX_Context *ctx, struct GNUNET_REGEX_Automaton *a) { int i; int table[a->state_count][a->state_count]; struct GNUNET_REGEX_State *s1; struct GNUNET_REGEX_State *s2; struct Transition *t1; struct Transition *t2; struct GNUNET_REGEX_State *s1_next; struct GNUNET_REGEX_State *s2_next; int change; int num_equal_edges; for (i = 0, s1 = a->states_head; i < a->state_count && NULL != s1; i++, s1 = s1->next) { s1->marked = i; } // Mark all pairs of accepting/!accepting states for (s1 = a->states_head; NULL != s1; s1 = s1->next) { for (s2 = a->states_head; NULL != s2; s2 = s2->next) { table[s1->marked][s2->marked] = 0; if ((s1->accepting && !s2->accepting) || (!s1->accepting && s2->accepting)) { table[s1->marked][s2->marked] = 1; } } } // Find all equal states change = 1; while (0 != change) { change = 0; for (s1 = a->states_head; NULL != s1; s1 = s1->next) { for (s2 = a->states_head; NULL != s2 && s1 != s2; s2 = s2->next) { if (0 != table[s1->marked][s2->marked]) continue; num_equal_edges = 0; for (t1 = s1->transitions_head; NULL != t1; t1 = t1->next) { for (t2 = s2->transitions_head; NULL != t2; t2 = t2->next) { if (t1->label == t2->label) { num_equal_edges++; if (0 != table[t1->to_state->marked][t2->to_state->marked] || 0 != table[t2->to_state->marked][t1->to_state->marked]) { table[s1->marked][s2->marked] = t1->label != 0 ? t1->label : 1; change = 1; } } } } if (num_equal_edges != s1->transition_count || num_equal_edges != s2->transition_count) { // Make sure ALL edges of possible equal states are the same table[s1->marked][s2->marked] = -2; } } } } // Merge states that are equal for (s1 = a->states_head; NULL != s1; s1 = s1_next) { s1_next = s1->next; for (s2 = a->states_head; NULL != s2 && s1 != s2; s2 = s2_next) { s2_next = s2->next; if (table[s1->marked][s2->marked] == 0) automaton_merge_states (ctx, a, s1, s2); } } } /** * Minimize the given DFA 'a' by removing all unreachable states, removing all * dead states and merging all non distinguishable states * * @param ctx context * @param a DFA automaton */ static void dfa_minimize (struct GNUNET_REGEX_Context *ctx, struct GNUNET_REGEX_Automaton *a) { if (NULL == a) return; GNUNET_assert (DFA == a->type); // 1. remove unreachable states dfa_remove_unreachable_states (a); // 2. remove dead states dfa_remove_dead_states (a); // 3. Merge nondistinguishable states dfa_merge_nondistinguishable_states (ctx, a); } /** * Creates a new NFA fragment. Needs to be cleared using * automaton_fragment_clear. * * @param start starting state * @param end end state * * @return new NFA fragment */ static struct GNUNET_REGEX_Automaton * nfa_fragment_create (struct GNUNET_REGEX_State *start, struct GNUNET_REGEX_State *end) { struct GNUNET_REGEX_Automaton *n; n = GNUNET_malloc (sizeof (struct GNUNET_REGEX_Automaton)); n->type = NFA; n->start = NULL; n->end = NULL; if (NULL == start && NULL == end) return n; automaton_add_state (n, end); automaton_add_state (n, start); n->start = start; n->end = end; return n; } /** * Adds a list of states to the given automaton 'n'. * * @param n automaton to which the states should be added * @param states_head head of the DLL of states * @param states_tail tail of the DLL of states */ static void nfa_add_states (struct GNUNET_REGEX_Automaton *n, struct GNUNET_REGEX_State *states_head, struct GNUNET_REGEX_State *states_tail) { struct GNUNET_REGEX_State *s; if (NULL == n || NULL == states_head) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not add states\n"); return; } if (NULL == n->states_head) { n->states_head = states_head; n->states_tail = states_tail; return; } if (NULL != states_head) { n->states_tail->next = states_head; n->states_tail = states_tail; } for (s = states_head; NULL != s; s = s->next) n->state_count++; } /** * Creates a new NFA state. Needs to be freed using automaton_destroy_state. * * @param ctx context * @param accepting is it an accepting state or not * * @return new NFA state */ static struct GNUNET_REGEX_State * nfa_state_create (struct GNUNET_REGEX_Context *ctx, int accepting) { struct GNUNET_REGEX_State *s; s = GNUNET_malloc (sizeof (struct GNUNET_REGEX_State)); s->id = ctx->state_id++; s->accepting = accepting; s->marked = 0; s->contained = 0; s->index = -1; s->lowlink = -1; s->scc_id = 0; s->name = NULL; GNUNET_asprintf (&s->name, "s%i", s->id); return s; } /** * Calculates the NFA closure set for the given state. * * @param nfa the NFA containing 's' * @param s starting point state * @param label transitioning label on which to base the closure on, * pass 0 for epsilon transition * * @return sorted nfa closure on 'label' (epsilon closure if 'label' is 0) */ static struct GNUNET_REGEX_StateSet * nfa_closure_create (struct GNUNET_REGEX_Automaton *nfa, struct GNUNET_REGEX_State *s, const char label) { struct GNUNET_REGEX_StateSet *cls; struct GNUNET_REGEX_StateSet *cls_check; struct GNUNET_REGEX_State *clsstate; struct GNUNET_REGEX_State *currentstate; struct Transition *ctran; if (NULL == s) return NULL; cls = GNUNET_malloc (sizeof (struct GNUNET_REGEX_StateSet)); cls_check = GNUNET_malloc (sizeof (struct GNUNET_REGEX_StateSet)); for (clsstate = nfa->states_head; NULL != clsstate; clsstate = clsstate->next) clsstate->contained = 0; // Add start state to closure only for epsilon closure if (0 == label) GNUNET_array_append (cls->states, cls->len, s); GNUNET_array_append (cls_check->states, cls_check->len, s); while (cls_check->len > 0) { currentstate = cls_check->states[cls_check->len - 1]; GNUNET_array_grow (cls_check->states, cls_check->len, cls_check->len - 1); for (ctran = currentstate->transitions_head; NULL != ctran; ctran = ctran->next) { if (NULL != ctran->to_state && label == ctran->label) { clsstate = ctran->to_state; if (NULL != clsstate && 0 == clsstate->contained) { GNUNET_array_append (cls->states, cls->len, clsstate); GNUNET_array_append (cls_check->states, cls_check->len, clsstate); clsstate->contained = 1; } } } } GNUNET_assert (0 == cls_check->len); GNUNET_free (cls_check); if (cls->len > 1) qsort (cls->states, cls->len, sizeof (struct GNUNET_REGEX_State *), state_compare); return cls; } /** * Calculates the closure set for the given set of states. * * @param nfa the NFA containing 's' * @param states list of states on which to base the closure on * @param label transitioning label for which to base the closure on, * pass 0 for epsilon transition * * @return sorted nfa closure on 'label' (epsilon closure if 'label' is 0) */ static struct GNUNET_REGEX_StateSet * nfa_closure_set_create (struct GNUNET_REGEX_Automaton *nfa, struct GNUNET_REGEX_StateSet *states, const char label) { struct GNUNET_REGEX_State *s; struct GNUNET_REGEX_StateSet *sset; struct GNUNET_REGEX_StateSet *cls; int i; int j; int k; int contains; if (NULL == states) return NULL; cls = GNUNET_malloc (sizeof (struct GNUNET_REGEX_StateSet)); for (i = 0; i < states->len; i++) { s = states->states[i]; sset = nfa_closure_create (nfa, s, label); for (j = 0; j < sset->len; j++) { contains = 0; for (k = 0; k < cls->len; k++) { if (sset->states[j]->id == cls->states[k]->id) { contains = 1; break; } } if (!contains) GNUNET_array_append (cls->states, cls->len, sset->states[j]); } state_set_clear (sset); } if (cls->len > 1) qsort (cls->states, cls->len, sizeof (struct GNUNET_REGEX_State *), state_compare); return cls; } /** * Pops two NFA fragments (a, b) from the stack and concatenates them (ab) * * @param ctx context */ static void nfa_add_concatenation (struct GNUNET_REGEX_Context *ctx) { struct GNUNET_REGEX_Automaton *a; struct GNUNET_REGEX_Automaton *b; struct GNUNET_REGEX_Automaton *new; b = ctx->stack_tail; GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, b); a = ctx->stack_tail; GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, a); state_add_transition (ctx, a->end, 0, b->start); a->end->accepting = 0; b->end->accepting = 1; new = nfa_fragment_create (NULL, NULL); nfa_add_states (new, a->states_head, a->states_tail); nfa_add_states (new, b->states_head, b->states_tail); new->start = a->start; new->end = b->end; automaton_fragment_clear (a); automaton_fragment_clear (b); GNUNET_CONTAINER_DLL_insert_tail (ctx->stack_head, ctx->stack_tail, new); } /** * Pops a NFA fragment from the stack (a) and adds a new fragment (a*) * * @param ctx context */ static void nfa_add_star_op (struct GNUNET_REGEX_Context *ctx) { struct GNUNET_REGEX_Automaton *a; struct GNUNET_REGEX_Automaton *new; struct GNUNET_REGEX_State *start; struct GNUNET_REGEX_State *end; a = ctx->stack_tail; GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, a); if (NULL == a) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "nfa_add_star_op failed, because there was no element on the stack"); return; } start = nfa_state_create (ctx, 0); end = nfa_state_create (ctx, 1); state_add_transition (ctx, start, 0, a->start); state_add_transition (ctx, start, 0, end); state_add_transition (ctx, a->end, 0, a->start); state_add_transition (ctx, a->end, 0, end); a->end->accepting = 0; end->accepting = 1; new = nfa_fragment_create (start, end); nfa_add_states (new, a->states_head, a->states_tail); automaton_fragment_clear (a); GNUNET_CONTAINER_DLL_insert_tail (ctx->stack_head, ctx->stack_tail, new); } /** * Pops an NFA fragment (a) from the stack and adds a new fragment (a+) * * @param ctx context */ static void nfa_add_plus_op (struct GNUNET_REGEX_Context *ctx) { struct GNUNET_REGEX_Automaton *a; a = ctx->stack_tail; GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, a); state_add_transition (ctx, a->end, 0, a->start); GNUNET_CONTAINER_DLL_insert_tail (ctx->stack_head, ctx->stack_tail, a); } /** * Pops an NFA fragment (a) from the stack and adds a new fragment (a?) * * @param ctx context */ static void nfa_add_question_op (struct GNUNET_REGEX_Context *ctx) { struct GNUNET_REGEX_Automaton *a; struct GNUNET_REGEX_Automaton *new; struct GNUNET_REGEX_State *start; struct GNUNET_REGEX_State *end; a = ctx->stack_tail; GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, a); if (NULL == a) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "nfa_add_question_op failed, because there was no element on the stack"); return; } start = nfa_state_create (ctx, 0); end = nfa_state_create (ctx, 1); state_add_transition (ctx, start, 0, a->start); state_add_transition (ctx, start, 0, end); state_add_transition (ctx, a->end, 0, end); a->end->accepting = 0; new = nfa_fragment_create (start, end); nfa_add_states (new, a->states_head, a->states_tail); automaton_fragment_clear (a); GNUNET_CONTAINER_DLL_insert_tail (ctx->stack_head, ctx->stack_tail, new); } /** * Pops two NFA fragments (a, b) from the stack and adds a new NFA fragment that * alternates between a and b (a|b) * * @param ctx context */ static void nfa_add_alternation (struct GNUNET_REGEX_Context *ctx) { struct GNUNET_REGEX_Automaton *a; struct GNUNET_REGEX_Automaton *b; struct GNUNET_REGEX_Automaton *new; struct GNUNET_REGEX_State *start; struct GNUNET_REGEX_State *end; b = ctx->stack_tail; GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, b); a = ctx->stack_tail; GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, a); start = nfa_state_create (ctx, 0); end = nfa_state_create (ctx, 1); state_add_transition (ctx, start, 0, a->start); state_add_transition (ctx, start, 0, b->start); state_add_transition (ctx, a->end, 0, end); state_add_transition (ctx, b->end, 0, end); a->end->accepting = 0; b->end->accepting = 0; end->accepting = 1; new = nfa_fragment_create (start, end); nfa_add_states (new, a->states_head, a->states_tail); nfa_add_states (new, b->states_head, b->states_tail); automaton_fragment_clear (a); automaton_fragment_clear (b); GNUNET_CONTAINER_DLL_insert_tail (ctx->stack_head, ctx->stack_tail, new); } /** * Adds a new nfa fragment to the stack * * @param ctx context * @param lit label for nfa transition */ static void nfa_add_label (struct GNUNET_REGEX_Context *ctx, const char lit) { struct GNUNET_REGEX_Automaton *n; struct GNUNET_REGEX_State *start; struct GNUNET_REGEX_State *end; GNUNET_assert (NULL != ctx); start = nfa_state_create (ctx, 0); end = nfa_state_create (ctx, 1); state_add_transition (ctx, start, lit, end); n = nfa_fragment_create (start, end); GNUNET_assert (NULL != n); GNUNET_CONTAINER_DLL_insert_tail (ctx->stack_head, ctx->stack_tail, n); } /** * Initialize a new context * * @param ctx context */ static void GNUNET_REGEX_context_init (struct GNUNET_REGEX_Context *ctx) { if (NULL == ctx) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Context was NULL!"); return; } ctx->state_id = 0; ctx->transition_id = 0; ctx->scc_id = 0; ctx->stack_head = NULL; ctx->stack_tail = NULL; } /** * Construct an NFA by parsing the regex string of length 'len'. * * @param regex regular expression string * @param len length of the string * * @return NFA, needs to be freed using GNUNET_REGEX_destroy_automaton */ struct GNUNET_REGEX_Automaton * GNUNET_REGEX_construct_nfa (const char *regex, const size_t len) { struct GNUNET_REGEX_Context ctx; struct GNUNET_REGEX_Automaton *nfa; const char *regexp; char *error_msg; unsigned int count; unsigned int altcount; unsigned int atomcount; unsigned int pcount; struct { int altcount; int atomcount; } *p; GNUNET_REGEX_context_init (&ctx); regexp = regex; p = NULL; error_msg = NULL; altcount = 0; atomcount = 0; pcount = 0; for (count = 0; count < len && *regexp; count++, regexp++) { switch (*regexp) { case '(': if (atomcount > 1) { --atomcount; nfa_add_concatenation (&ctx); } GNUNET_array_grow (p, pcount, pcount + 1); p[pcount - 1].altcount = altcount; p[pcount - 1].atomcount = atomcount; altcount = 0; atomcount = 0; break; case '|': if (0 == atomcount) { error_msg = "Cannot append '|' to nothing"; goto error; } while (--atomcount > 0) nfa_add_concatenation (&ctx); altcount++; break; case ')': if (0 == pcount) { error_msg = "Missing opening '('"; goto error; } if (0 == atomcount) { // Ignore this: "()" pcount--; altcount = p[pcount].altcount; atomcount = p[pcount].atomcount; break; } while (--atomcount > 0) nfa_add_concatenation (&ctx); for (; altcount > 0; altcount--) nfa_add_alternation (&ctx); pcount--; altcount = p[pcount].altcount; atomcount = p[pcount].atomcount; atomcount++; break; case '*': if (atomcount == 0) { error_msg = "Cannot append '*' to nothing"; goto error; } nfa_add_star_op (&ctx); break; case '+': if (atomcount == 0) { error_msg = "Cannot append '+' to nothing"; goto error; } nfa_add_plus_op (&ctx); break; case '?': if (atomcount == 0) { error_msg = "Cannot append '?' to nothing"; goto error; } nfa_add_question_op (&ctx); break; case 92: /* escape: \ */ regexp++; count++; default: if (atomcount > 1) { --atomcount; nfa_add_concatenation (&ctx); } nfa_add_label (&ctx, *regexp); atomcount++; break; } } if (0 != pcount) { error_msg = "Unbalanced parenthesis"; goto error; } while (--atomcount > 0) nfa_add_concatenation (&ctx); for (; altcount > 0; altcount--) nfa_add_alternation (&ctx); if (NULL != p) GNUNET_free (p); nfa = ctx.stack_tail; GNUNET_CONTAINER_DLL_remove (ctx.stack_head, ctx.stack_tail, nfa); if (NULL != ctx.stack_head) { error_msg = "Creating the NFA failed. NFA stack was not empty!"; goto error; } return nfa; error: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not parse regex\n"); if (NULL != error_msg) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", error_msg); if (NULL != p) GNUNET_free (p); while (NULL != ctx.stack_tail) { GNUNET_REGEX_automaton_destroy (ctx.stack_tail); GNUNET_CONTAINER_DLL_remove (ctx.stack_head, ctx.stack_tail, ctx.stack_tail); } return NULL; } /** * Create DFA states based on given 'nfa' and starting with 'dfa_state'. * * @param ctx context. * @param nfa NFA automaton. * @param dfa DFA automaton. * @param dfa_state current dfa state, pass epsilon closure of first nfa state * for starting. */ static void construct_dfa_states (struct GNUNET_REGEX_Context *ctx, struct GNUNET_REGEX_Automaton *nfa, struct GNUNET_REGEX_Automaton *dfa, struct GNUNET_REGEX_State *dfa_state) { struct Transition *ctran; struct GNUNET_REGEX_State *state_iter; struct GNUNET_REGEX_State *new_dfa_state; struct GNUNET_REGEX_State *state_contains; struct GNUNET_REGEX_StateSet *tmp; struct GNUNET_REGEX_StateSet *nfa_set; for (ctran = dfa_state->transitions_head; NULL != ctran; ctran = ctran->next) { if (0 == ctran->label || NULL != ctran->to_state) continue; tmp = nfa_closure_set_create (nfa, dfa_state->nfa_set, ctran->label); nfa_set = nfa_closure_set_create (nfa, tmp, 0); state_set_clear (tmp); new_dfa_state = dfa_state_create (ctx, nfa_set); state_contains = NULL; for (state_iter = dfa->states_head; NULL != state_iter; state_iter = state_iter->next) { if (0 == state_set_compare (state_iter->nfa_set, new_dfa_state->nfa_set)) state_contains = state_iter; } if (NULL == state_contains) { automaton_add_state (dfa, new_dfa_state); ctran->to_state = new_dfa_state; construct_dfa_states (ctx, nfa, dfa, new_dfa_state); } else { ctran->to_state = state_contains; automaton_destroy_state (new_dfa_state); } } } /** * Construct DFA for the given 'regex' of length 'len' * * @param regex regular expression string * @param len length of the regular expression * * @return DFA, needs to be freed using GNUNET_REGEX_destroy_automaton */ struct GNUNET_REGEX_Automaton * GNUNET_REGEX_construct_dfa (const char *regex, const size_t len) { struct GNUNET_REGEX_Context ctx; struct GNUNET_REGEX_Automaton *dfa; struct GNUNET_REGEX_Automaton *nfa; struct GNUNET_REGEX_StateSet *nfa_set; GNUNET_REGEX_context_init (&ctx); // Create NFA nfa = GNUNET_REGEX_construct_nfa (regex, len); if (NULL == nfa) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not create DFA, because NFA creation failed\n"); return NULL; } dfa = GNUNET_malloc (sizeof (struct GNUNET_REGEX_Automaton)); dfa->type = DFA; // Create DFA start state from epsilon closure nfa_set = nfa_closure_create (nfa, nfa->start, 0); dfa->start = dfa_state_create (&ctx, nfa_set); automaton_add_state (dfa, dfa->start); construct_dfa_states (&ctx, nfa, dfa, dfa->start); GNUNET_REGEX_automaton_destroy (nfa); // Minimize DFA dfa_minimize (&ctx, dfa); // Calculate SCCs scc_tarjan (&ctx, dfa); // Create proofs for all states automaton_create_proofs (dfa); return dfa; } /** * Free the memory allocated by constructing the GNUNET_REGEX_Automaton data * structure. * * @param a automaton to be destroyed */ void GNUNET_REGEX_automaton_destroy (struct GNUNET_REGEX_Automaton *a) { struct GNUNET_REGEX_State *s; struct GNUNET_REGEX_State *next_state; if (NULL == a) return; for (s = a->states_head; NULL != s;) { next_state = s->next; automaton_destroy_state (s); s = next_state; } GNUNET_free (a); } /** * Save the given automaton as a GraphViz dot file * * @param a the automaton to be saved * @param filename where to save the file */ void GNUNET_REGEX_automaton_save_graph (struct GNUNET_REGEX_Automaton *a, const char *filename) { struct GNUNET_REGEX_State *s; struct Transition *ctran; char *s_acc = NULL; char *s_tran = NULL; char *start; char *end; FILE *p; if (NULL == a) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not print NFA, was NULL!"); return; } if (NULL == filename || strlen (filename) < 1) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No Filename given!"); return; } p = fopen (filename, "w"); if (NULL == p) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not open file for writing: %s", filename); return; } start = "digraph G {\nrankdir=LR\n"; fwrite (start, strlen (start), 1, p); for (s = a->states_head; NULL != s; s = s->next) { if (s->accepting) { GNUNET_asprintf (&s_acc, "\"%s\" [shape=doublecircle, color=\"0.%i 0.8 0.95\"];\n", s->name, s->scc_id); } else { GNUNET_asprintf (&s_acc, "\"%s\" [color=\"0.%i 0.8 0.95\"];\n", s->name, s->scc_id); } if (NULL == s_acc) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not print state %s\n", s->name); return; } fwrite (s_acc, strlen (s_acc), 1, p); GNUNET_free (s_acc); s_acc = NULL; for (ctran = s->transitions_head; NULL != ctran; ctran = ctran->next) { if (NULL == ctran->to_state) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Transition from State %i has has no state for transitioning\n", s->id); continue; } if (ctran->label == 0) { GNUNET_asprintf (&s_tran, "\"%s\" -> \"%s\" [label = \"epsilon\", color=\"0.%i 0.8 0.95\"];\n", s->name, ctran->to_state->name, s->scc_id); } else { GNUNET_asprintf (&s_tran, "\"%s\" -> \"%s\" [label = \"%c\", color=\"0.%i 0.8 0.95\"];\n", s->name, ctran->to_state->name, ctran->label, s->scc_id); } if (NULL == s_tran) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not print state %s\n", s->name); return; } fwrite (s_tran, strlen (s_tran), 1, p); GNUNET_free (s_tran); s_tran = NULL; } } end = "\n}\n"; fwrite (end, strlen (end), 1, p); fclose (p); } /** * Evaluates the given string using the given DFA automaton * * @param a automaton, type must be DFA * @param string string that should be evaluated * * @return 0 if string matches, non 0 otherwise */ static int evaluate_dfa (struct GNUNET_REGEX_Automaton *a, const char *string) { const char *strp; struct GNUNET_REGEX_State *s; if (DFA != a->type) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Tried to evaluate DFA, but NFA automaton given"); return -1; } s = a->start; for (strp = string; NULL != strp && *strp; strp++) { s = dfa_move (s, *strp); if (NULL == s) break; } if (NULL != s && s->accepting) return 0; return 1; } /** * Evaluates the given string using the given NFA automaton * * @param a automaton, type must be NFA * @param string string that should be evaluated * * @return 0 if string matches, non 0 otherwise */ static int evaluate_nfa (struct GNUNET_REGEX_Automaton *a, const char *string) { const char *strp; struct GNUNET_REGEX_State *s; struct GNUNET_REGEX_StateSet *sset; struct GNUNET_REGEX_StateSet *new_sset; int i; int result; if (NFA != a->type) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Tried to evaluate NFA, but DFA automaton given"); return -1; } result = 1; strp = string; sset = nfa_closure_create (a, a->start, 0); for (strp = string; NULL != strp && *strp; strp++) { new_sset = nfa_closure_set_create (a, sset, *strp); state_set_clear (sset); sset = nfa_closure_set_create (a, new_sset, 0); state_set_clear (new_sset); } for (i = 0; i < sset->len; i++) { s = sset->states[i]; if (NULL != s && s->accepting) { result = 0; break; } } state_set_clear (sset); return result; } /** * Evaluates the given 'string' against the given compiled regex * * @param a automaton * @param string string to check * * @return 0 if string matches, non 0 otherwise */ int GNUNET_REGEX_eval (struct GNUNET_REGEX_Automaton *a, const char *string) { int result; switch (a->type) { case DFA: result = evaluate_dfa (a, string); break; case NFA: result = evaluate_nfa (a, string); break; default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Evaluating regex failed, automaton has no type!\n"); result = GNUNET_SYSERR; break; } return result; } /** * Get the first key for the given 'input_string'. This hashes the first x bits * of the 'input_strings'. * * @param input_string string. * @param string_len length of the 'input_string'. * @param key pointer to where to write the hash code. * * @return number of bits of 'input_string' that have been consumed * to construct the key */ unsigned int GNUNET_REGEX_get_first_key (const char *input_string, unsigned int string_len, GNUNET_HashCode * key) { unsigned int size; size = string_len < initial_bits ? string_len : initial_bits; if (NULL == input_string) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Given input string was NULL!\n"); return 0; } GNUNET_CRYPTO_hash (input_string, size, key); return size; } /** * Check if the given 'proof' matches the given 'key'. * * @param proof partial regex * @param key hash * * @return GNUNET_OK if the proof is valid for the given key */ int GNUNET_REGEX_check_proof (const char *proof, const GNUNET_HashCode * key) { return GNUNET_OK; } /** * Iterate over all edges helper function starting from state 's', calling * iterator on for each edge. * * @param s state. * @param iterator iterator function called for each edge. * @param iterator_cls closure. */ static void iterate_edge (struct GNUNET_REGEX_State *s, GNUNET_REGEX_KeyIterator iterator, void *iterator_cls) { struct Transition *t; struct GNUNET_REGEX_Edge edges[s->transition_count]; unsigned int num_edges; if (GNUNET_YES != s->marked) { s->marked = GNUNET_YES; num_edges = state_get_edges (s, edges); iterator (iterator_cls, &s->hash, s->proof, s->accepting, num_edges, edges); for (t = s->transitions_head; NULL != t; t = t->next) iterate_edge (t->to_state, iterator, iterator_cls); } } /** * Iterate over all edges starting from start state of automaton 'a'. Calling * iterator for each edge. * * @param a automaton. * @param iterator iterator called for each edge. * @param iterator_cls closure. */ void GNUNET_REGEX_iterate_all_edges (struct GNUNET_REGEX_Automaton *a, GNUNET_REGEX_KeyIterator iterator, void *iterator_cls) { struct GNUNET_REGEX_State *s; for (s = a->states_head; NULL != s; s = s->next) s->marked = GNUNET_NO; iterate_edge (a->start, iterator, iterator_cls); } gnunet-0.9.3/src/regex/Makefile.in0000644000175000017500000006223411762217213013723 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ check_PROGRAMS = test_regex_eval_api$(EXEEXT) \ test_regex_iterate_api$(EXEEXT) subdir = src/regex DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) libgnunetregex_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la am_libgnunetregex_la_OBJECTS = regex.lo libgnunetregex_la_OBJECTS = $(am_libgnunetregex_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent libgnunetregex_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetregex_la_LDFLAGS) $(LDFLAGS) \ -o $@ am_test_regex_eval_api_OBJECTS = test_regex_eval_api.$(OBJEXT) test_regex_eval_api_OBJECTS = $(am_test_regex_eval_api_OBJECTS) test_regex_eval_api_DEPENDENCIES = \ $(top_builddir)/src/regex/libgnunetregex.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_regex_iterate_api_OBJECTS = test_regex_iterate_api.$(OBJEXT) test_regex_iterate_api_OBJECTS = $(am_test_regex_iterate_api_OBJECTS) test_regex_iterate_api_DEPENDENCIES = \ $(top_builddir)/src/regex/libgnunetregex.la \ $(top_builddir)/src/util/libgnunetutil.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunetregex_la_SOURCES) $(test_regex_eval_api_SOURCES) \ $(test_regex_iterate_api_SOURCES) DIST_SOURCES = $(libgnunetregex_la_SOURCES) \ $(test_regex_eval_api_SOURCES) \ $(test_regex_iterate_api_SOURCES) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage lib_LTLIBRARIES = libgnunetregex.la libgnunetregex_la_SOURCES = \ regex.c libgnunetregex_la_LIBADD = -lm \ $(top_builddir)/src/util/libgnunetutil.la libgnunetregex_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:0:0 @ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) test_regex_eval_api_SOURCES = \ test_regex_eval_api.c test_regex_eval_api_LDADD = \ $(top_builddir)/src/regex/libgnunetregex.la \ $(top_builddir)/src/util/libgnunetutil.la test_regex_iterate_api_SOURCES = \ test_regex_iterate_api.c test_regex_iterate_api_LDADD = \ $(top_builddir)/src/regex/libgnunetregex.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/regex/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/regex/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libgnunetregex.la: $(libgnunetregex_la_OBJECTS) $(libgnunetregex_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetregex_la_LINK) -rpath $(libdir) $(libgnunetregex_la_OBJECTS) $(libgnunetregex_la_LIBADD) $(LIBS) clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list test_regex_eval_api$(EXEEXT): $(test_regex_eval_api_OBJECTS) $(test_regex_eval_api_DEPENDENCIES) @rm -f test_regex_eval_api$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_regex_eval_api_OBJECTS) $(test_regex_eval_api_LDADD) $(LIBS) test_regex_iterate_api$(EXEEXT): $(test_regex_iterate_api_OBJECTS) $(test_regex_iterate_api_DEPENDENCIES) @rm -f test_regex_iterate_api$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_regex_iterate_api_OBJECTS) $(test_regex_iterate_api_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regex.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_regex_eval_api.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_regex_iterate_api.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool ctags distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-libLTLIBRARIES \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ uninstall-am uninstall-libLTLIBRARIES # test_regex_data.conf # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/regex/test_regex_iterate_api.c0000644000175000017500000000375411760502551016543 00000000000000/* This file is part of GNUnet (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file regex/test_regex_iterate_api.c * @brief test for regex.c * @author Maximilian Szengel */ #include #include #include "platform.h" #include "gnunet_regex_lib.h" void key_iterator (void *cls, const GNUNET_HashCode * key, const char *proof, int accepting, unsigned int num_edges, const struct GNUNET_REGEX_Edge *edges) { int i; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Iterating...\n"); for (i = 0; i < num_edges; i++) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Edge %i: %s\n", i, edges[i].label); } if (NULL != proof) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Proof: %s\n", proof); } int main (int argc, char *argv[]) { GNUNET_log_setup ("test-regex", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); int error; const char *regex; struct GNUNET_REGEX_Automaton *dfa; error = 0; regex = "ab(c|d)+c*(a(b|c)d)+"; dfa = GNUNET_REGEX_construct_dfa (regex, strlen (regex)); GNUNET_REGEX_automaton_save_graph (dfa, "dfa.dot"); GNUNET_REGEX_iterate_all_edges (dfa, key_iterator, NULL); GNUNET_REGEX_automaton_destroy (dfa); return error; } gnunet-0.9.3/src/hostlist/0000755000175000017500000000000011763406750012475 500000000000000gnunet-0.9.3/src/hostlist/hostlist.conf0000644000175000017500000000067711730462232015136 00000000000000[hostlist] # port for hostlist http server HTTPPORT = 8080 HOME = $SERVICEHOME HOSTLISTFILE = $SERVICEHOME/hostlist/learned.data CONFIG = $DEFAULTCONFIG BINARY = gnunet-daemon-hostlist # consider having "-e" as default as well once implemented OPTIONS = -b SERVERS = http://v9.gnunet.org/hostlist http://ioerror.gnunet.org:65535/ # proxy for downloading hostlists HTTP-PROXY = # bind hostlist http server to a specific IPv4 or IPv6 # BINDTOIP = gnunet-0.9.3/src/hostlist/Makefile.am0000644000175000017500000000440611654545774014466 00000000000000INCLUDES = -I$(top_srcdir)/src/include pkgcfgdir= $(pkgdatadir)/config.d/ dist_pkgcfg_DATA = \ hostlist.conf if USE_COVERAGE AM_CFLAGS = --coverage -O0 endif if HAVE_MHD HOSTLIST_SERVER_SOURCES = hostlist-server.c hostlist-server.h GN_LIBMHD = -lmicrohttpd endif bin_PROGRAMS = \ gnunet-daemon-hostlist gnunet_daemon_hostlist_SOURCES = \ gnunet-daemon-hostlist.c gnunet-daemon-hostlist.h \ hostlist-client.c hostlist-client.h \ $(HOSTLIST_SERVER_SOURCES) gnunet_daemon_hostlist_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBMHD) \ @LIBCURL@ \ $(GN_LIBINTL) gnunet_daemon_hostlist_CPPFLAGS = \ @LIBCURL_CPPFLAGS@ check_PROGRAMS = \ test_gnunet_daemon_hostlist \ test_gnunet_daemon_hostlist_reconnect \ test_gnunet_daemon_hostlist_learning if HAVE_MHD if ENABLE_TEST_RUN TESTS = \ test_gnunet_daemon_hostlist \ test_gnunet_daemon_hostlist_reconnect \ test_gnunet_daemon_hostlist_learning endif endif test_gnunet_daemon_hostlist_SOURCES = \ test_gnunet_daemon_hostlist.c test_gnunet_daemon_hostlist_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la test_gnunet_daemon_hostlist_reconnect_SOURCES = \ test_gnunet_daemon_hostlist_reconnect.c test_gnunet_daemon_hostlist_reconnect_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la test_gnunet_daemon_hostlist_learning_SOURCES = \ test_gnunet_daemon_hostlist_learning.c test_gnunet_daemon_hostlist_learning_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ test_hostlist_defaults.conf \ test_gnunet_daemon_hostlist_data.conf \ test_gnunet_daemon_hostlist_peer1.conf \ test_gnunet_daemon_hostlist_peer2.conf \ test_learning_adv_peer.conf \ test_learning_learn_peer.conf \ test_learning_learn_peer2.conf \ learning_data.conf gnunet-0.9.3/src/hostlist/test_gnunet_daemon_hostlist_peer2.conf0000644000175000017500000000146311647100202022160 00000000000000@INLINE@ test_hostlist_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-hostlist-peer-2/ DEFAULTCONFIG = test_gnunet_daemon_hostlist_peer2.conf [transport-tcp] PORT = 22968 [arm] PORT = 22966 DEFAULTSERVICES = hostlist topology UNIXPATH = /tmp/gnunet-p2-service-arm.sock [statistics] PORT = 22967 UNIXPATH = /tmp/gnunet-p2-service-statistics.sock [resolver] PORT = 22964 UNIXPATH = /tmp/gnunet-p2-service-resolver.sock [peerinfo] PORT = 22969 UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock [transport] PORT = 22965 UNIXPATH = /tmp/gnunet-p2-service-transport.sock [core] PORT = 22970 UNIXPATH = /tmp/gnunet-p2-service-core.sock [hostlist] HTTPPORT = 12981 HOSTLISTFILE = hostlists_peer2.file OPTIONS = -b -p SERVERS = http://localhost:12980/ [ats] PORT = 22971 UNIXPATH = /tmp/gnunet-p2-service-ats.sock gnunet-0.9.3/src/hostlist/test_gnunet_daemon_hostlist_data.conf0000644000175000017500000000053011615567501022064 00000000000000@INLINE@ test_hostlist_defaults.conf [transport-tcp] PORT = 12968 [arm] PORT = 12966 DEFAULTSERVICES = hostlist topology [statistics] PORT = 12967 [resolver] PORT = 12964 [peerinfo] PORT = 12969 [transport] PORT = 12965 [core] PORT = 12970 [hostlist] HTTPPORT = 28080 SERVERS = http://gnunet.org:8080/ PORT = 23354 HOSTNAME = localhost gnunet-0.9.3/src/hostlist/hostlist-client.c0000644000175000017500000012674211760516030015710 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file hostlist/hostlist-client.c * @brief hostlist support. Downloads HELLOs via HTTP. * @author Christian Grothoff * @author Matthias Wachs */ #include "platform.h" #include "hostlist-client.h" #include "gnunet_core_service.h" #include "gnunet_hello_lib.h" #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" #include "gnunet-daemon-hostlist.h" #include #include "gnunet_common.h" #include "gnunet_bio_lib.h" /** * Number of connections that we must have to NOT download * hostlists anymore. */ #define MIN_CONNECTIONS 4 /** * Interval between two advertised hostlist tests */ #define TESTING_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) /** * A single hostlist obtained by hostlist advertisements */ struct Hostlist { /** * previous entry, used to manage entries in a double linked list */ struct Hostlist *prev; /** * next entry, used to manage entries in a double linked list */ struct Hostlist *next; /** * URI where hostlist can be obtained */ const char *hostlist_uri; /** * Value describing the quality of the hostlist, the bigger the better but (should) never < 0 * used for deciding which hostlist is replaced if MAX_NUMBER_HOSTLISTS in data structure is reached * intial value = HOSTLIST_INITIAL * increased every successful download by HOSTLIST_SUCCESSFULL_DOWNLOAD * increased every successful download by number of obtained HELLO messages * decreased every failed download by HOSTLIST_SUCCESSFULL_DOWNLOAD */ uint64_t quality; /** * Time the hostlist advertisement was recieved and the entry was created */ struct GNUNET_TIME_Absolute time_creation; /** * Last time the hostlist was obtained */ struct GNUNET_TIME_Absolute time_last_usage; /** * Number of HELLO messages obtained during last download */ uint32_t hello_count; /** * Number of times the hostlist was successfully obtained */ uint32_t times_used; }; /** * Our configuration. */ static const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Statistics handle. */ static struct GNUNET_STATISTICS_Handle *stats; /** * Transport handle. */ static struct GNUNET_TRANSPORT_Handle *transport; /** * Proxy that we are using (can be NULL). */ static char *proxy; /** * Number of bytes valid in 'download_buffer'. */ static size_t download_pos; /** * Current URL that we are using. */ static char *current_url; /** * Current CURL handle. */ static CURL *curl; /** * Current multi-CURL handle. */ static CURLM *multi; /** * How many bytes did we download from the current hostlist URL? */ static uint32_t stat_bytes_downloaded; /** * Amount of time we wait between hostlist downloads. */ static struct GNUNET_TIME_Relative hostlist_delay; /** * ID of the task, checking if hostlist download should take plate */ static GNUNET_SCHEDULER_TaskIdentifier ti_check_download; /** * ID of the task downloading the hostlist */ static GNUNET_SCHEDULER_TaskIdentifier ti_download; /** * ID of the task saving the hostlsit in a regular intervall */ static GNUNET_SCHEDULER_TaskIdentifier ti_saving_task; /** * ID of the task called to initiate a download */ static GNUNET_SCHEDULER_TaskIdentifier ti_download_dispatcher_task; /** * ID of the task controlling the locking between two hostlist tests */ static GNUNET_SCHEDULER_TaskIdentifier ti_testing_intervall_task; /** * At what time MUST the current hostlist request be done? */ static struct GNUNET_TIME_Absolute end_time; /** * Head of the linked list used to store hostlists */ static struct Hostlist *linked_list_head; /** * Tail of the linked list used to store hostlists */ static struct Hostlist *linked_list_tail; /** * Current hostlist used for downloading */ static struct Hostlist *current_hostlist; /** * Size of the linke list used to store hostlists */ static unsigned int linked_list_size; /** * Head of the linked list used to store hostlists */ static struct Hostlist *hostlist_to_test; /** * Handle for our statistics GET operation. */ static struct GNUNET_STATISTICS_GetHandle *sget; /** * Set to GNUNET_YES if the current URL had some problems. */ static int stat_bogus_url; /** * Value controlling if a hostlist is tested at the moment */ static int stat_testing_hostlist; /** * Value controlling if a hostlist testing is allowed at the moment */ static int stat_testing_allowed; /** * Value controlling if a hostlist download is running at the moment */ static int stat_download_in_progress; /** * Value saying if a preconfigured bootstrap server is used */ static unsigned int stat_use_bootstrap; /** * Set if we are allowed to learn new hostlists and use them */ static int stat_learning; /** * Value saying if hostlist download was successful */ static unsigned int stat_download_successful; /** * Value saying how many valid HELLO messages were obtained during download */ static unsigned int stat_hellos_obtained; /** * Number of active connections (according to core service). */ static unsigned int stat_connection_count; /** * Process downloaded bits by calling callback on each HELLO. * * @param ptr buffer with downloaded data * @param size size of a record * @param nmemb number of records downloaded * @param ctx unused * @return number of bytes that were processed (always size*nmemb) */ static size_t callback_download (void *ptr, size_t size, size_t nmemb, void *ctx) { static char download_buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; const char *cbuf = ptr; const struct GNUNET_MessageHeader *msg; size_t total; size_t cpy; size_t left; uint16_t msize; total = size * nmemb; stat_bytes_downloaded += total; if ((total == 0) || (stat_bogus_url)) { return total; /* ok, no data or bogus data */ } GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes downloaded from hostlist servers"), (int64_t) total, GNUNET_NO); left = total; while ((left > 0) || (download_pos > 0)) { cpy = GNUNET_MIN (left, GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - download_pos); memcpy (&download_buffer[download_pos], cbuf, cpy); cbuf += cpy; download_pos += cpy; left -= cpy; if (download_pos < sizeof (struct GNUNET_MessageHeader)) { GNUNET_assert (left == 0); break; } msg = (const struct GNUNET_MessageHeader *) download_buffer; msize = ntohs (msg->size); if (msize < sizeof (struct GNUNET_MessageHeader)) { GNUNET_STATISTICS_update (stats, gettext_noop ("# invalid HELLOs downloaded from hostlist servers"), 1, GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Invalid `%s' message received from hostlist at `%s'\n"), "HELLO", current_url); stat_hellos_obtained++; stat_bogus_url = 1; return total; } if (download_pos < msize) { GNUNET_assert (left == 0); break; } if (GNUNET_HELLO_size ((const struct GNUNET_HELLO_Message *) msg) == msize) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received valid `%s' message from hostlist server.\n", "HELLO"); GNUNET_STATISTICS_update (stats, gettext_noop ("# valid HELLOs downloaded from hostlist servers"), 1, GNUNET_NO); stat_hellos_obtained++; GNUNET_TRANSPORT_offer_hello (transport, msg, NULL, NULL); } else { GNUNET_STATISTICS_update (stats, gettext_noop ("# invalid HELLOs downloaded from hostlist servers"), 1, GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Invalid `%s' message received from hostlist at `%s'\n"), "HELLO", current_url); stat_bogus_url = GNUNET_YES; stat_hellos_obtained++; return total; } memmove (download_buffer, &download_buffer[msize], download_pos - msize); download_pos -= msize; } return total; } /** * Obtain a hostlist URL that we should use. * * @return NULL if there is no URL available */ static char * get_bootstrap_server () { char *servers; char *ret; size_t urls; size_t pos; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "HOSTLIST", "SERVERS", &servers)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("No `%s' specified in `%s' configuration, will not bootstrap.\n"), "SERVERS", "HOSTLIST"); return NULL; } urls = 0; if (strlen (servers) > 0) { urls++; pos = strlen (servers) - 1; while (pos > 0) { if (servers[pos] == ' ') urls++; pos--; } } if (urls == 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("No `%s' specified in `%s' configuration, will not bootstrap.\n"), "SERVERS", "HOSTLIST"); GNUNET_free (servers); return NULL; } urls = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, urls) + 1; pos = strlen (servers) - 1; while (pos > 0) { if (servers[pos] == ' ') { urls--; servers[pos] = '\0'; } if (urls == 0) { pos++; break; } pos--; } ret = GNUNET_strdup (&servers[pos]); GNUNET_free (servers); return ret; } /** * Method deciding if a preconfigured or advertisied hostlist is used on a 50:50 ratio * @return uri to use, NULL if there is no URL available */ static char * download_get_url () { uint32_t index; unsigned int counter; struct Hostlist *pos; if (GNUNET_NO == stat_learning) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using preconfigured bootstrap server\n"); current_hostlist = NULL; return get_bootstrap_server (); } if ((GNUNET_YES == stat_testing_hostlist) && (NULL != hostlist_to_test)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing new advertised hostlist if it is obtainable\n"); current_hostlist = hostlist_to_test; return GNUNET_strdup (hostlist_to_test->hostlist_uri); } if ((GNUNET_YES == stat_use_bootstrap) || (linked_list_size == 0)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using preconfigured bootstrap server\n"); current_hostlist = NULL; return get_bootstrap_server (); } index = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, linked_list_size); counter = 0; pos = linked_list_head; while (counter < index) { pos = pos->next; counter++; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using learned hostlist `%s'\n", pos->hostlist_uri); current_hostlist = pos; return GNUNET_strdup (pos->hostlist_uri); } #define CURL_EASY_SETOPT(c, a, b) do { ret = curl_easy_setopt(c, a, b); if (ret != CURLE_OK) GNUNET_log(GNUNET_ERROR_TYPE_WARNING, _("%s failed at %s:%d: `%s'\n"), "curl_easy_setopt", __FILE__, __LINE__, curl_easy_strerror(ret)); } while (0) /** * Method to save hostlist to a file during hostlist client shutdown * @param shutdown set if called because of shutdown, entries in linked list will be destroyed */ static void save_hostlist_file (int shutdown); /** * add val2 to val1 with overflow check * @param val1 value 1 * @param val2 value 2 * @return result */ static uint64_t checked_add (uint64_t val1, uint64_t val2) { static uint64_t temp; static uint64_t maxv; maxv = 0; maxv--; temp = val1 + val2; if (temp < val1) return maxv; else return temp; } /** * Subtract val2 from val1 with underflow check * @param val1 value 1 * @param val2 value 2 * @return result */ static uint64_t checked_sub (uint64_t val1, uint64_t val2) { if (val1 <= val2) return 0; else return (val1 - val2); } /** * Method to check if a URI is in hostlist linked list * @param uri uri to check * @return GNUNET_YES if existing in linked list, GNUNET_NO if not */ static int linked_list_contains (const char *uri) { struct Hostlist *pos; pos = linked_list_head; while (pos != NULL) { if (0 == strcmp (pos->hostlist_uri, uri)) return GNUNET_YES; pos = pos->next; } return GNUNET_NO; } /** * Method returning the hostlist element with the lowest quality in the datastore * @return hostlist with lowest quality */ static struct Hostlist * linked_list_get_lowest_quality () { struct Hostlist *pos; struct Hostlist *lowest; if (linked_list_size == 0) return NULL; lowest = linked_list_head; pos = linked_list_head->next; while (pos != NULL) { if (pos->quality < lowest->quality) lowest = pos; pos = pos->next; } return lowest; } /** * Method to insert a hostlist into the datastore. If datastore * contains maximum number of elements, the elements with lowest * quality is dismissed */ static void insert_hostlist () { struct Hostlist *lowest_quality; if (MAX_NUMBER_HOSTLISTS <= linked_list_size) { /* No free entries available, replace existing entry */ lowest_quality = linked_list_get_lowest_quality (); GNUNET_assert (lowest_quality != NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing hostlist with URI `%s' which has the worst quality of all (%llu)\n", lowest_quality->hostlist_uri, (unsigned long long) lowest_quality->quality); GNUNET_CONTAINER_DLL_remove (linked_list_head, linked_list_tail, lowest_quality); linked_list_size--; GNUNET_free (lowest_quality); } GNUNET_CONTAINER_DLL_insert (linked_list_head, linked_list_tail, hostlist_to_test); linked_list_size++; GNUNET_STATISTICS_set (stats, gettext_noop ("# advertised hostlist URIs"), linked_list_size, GNUNET_NO); stat_testing_hostlist = GNUNET_NO; } /** * Method updating hostlist statistics */ static void update_hostlist () { char *stat; if (((stat_use_bootstrap == GNUNET_NO) && (NULL != current_hostlist)) || ((stat_testing_hostlist == GNUNET_YES) && (NULL != current_hostlist))) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Updating hostlist statics for URI `%s'\n", current_hostlist->hostlist_uri); current_hostlist->hello_count = stat_hellos_obtained; current_hostlist->time_last_usage = GNUNET_TIME_absolute_get (); current_hostlist->quality = checked_add (current_hostlist->quality, (stat_hellos_obtained * HOSTLIST_SUCCESSFUL_HELLO)); if (GNUNET_YES == stat_download_successful) { current_hostlist->times_used++; current_hostlist->quality = checked_add (current_hostlist->quality, HOSTLIST_SUCCESSFUL_DOWNLOAD); GNUNET_asprintf (&stat, gettext_noop ("# advertised URI `%s' downloaded"), current_hostlist->hostlist_uri); GNUNET_STATISTICS_update (stats, stat, 1, GNUNET_YES); GNUNET_free (stat); } else current_hostlist->quality = checked_sub (current_hostlist->quality, HOSTLIST_FAILED_DOWNLOAD); } current_hostlist = NULL; /* Alternating the usage of preconfigured and learned hostlists */ if (stat_testing_hostlist == GNUNET_YES) return; if (GNUNET_YES == stat_learning) { if (stat_use_bootstrap == GNUNET_YES) stat_use_bootstrap = GNUNET_NO; else stat_use_bootstrap = GNUNET_YES; } else stat_use_bootstrap = GNUNET_YES; } /** * Clean up the state from the task that downloaded the * hostlist and schedule the next task. */ static void clean_up () { CURLMcode mret; if ((stat_testing_hostlist == GNUNET_YES) && (GNUNET_NO == stat_download_successful) && (NULL != hostlist_to_test)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Advertised hostlist with URI `%s' could not be downloaded. Advertised URI gets dismissed.\n"), hostlist_to_test->hostlist_uri); } if (stat_testing_hostlist == GNUNET_YES) { stat_testing_hostlist = GNUNET_NO; } if (NULL != hostlist_to_test) { GNUNET_free (hostlist_to_test); hostlist_to_test = NULL; } if (multi != NULL) { mret = curl_multi_remove_handle (multi, curl); if (mret != CURLM_OK) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), "curl_multi_remove_handle", __FILE__, __LINE__, curl_multi_strerror (mret)); } mret = curl_multi_cleanup (multi); if (mret != CURLM_OK) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), "curl_multi_cleanup", __FILE__, __LINE__, curl_multi_strerror (mret)); multi = NULL; } if (curl != NULL) { curl_easy_cleanup (curl); curl = NULL; } GNUNET_free_non_null (current_url); current_url = NULL; stat_bytes_downloaded = 0; stat_download_in_progress = GNUNET_NO; } /** * Task that is run when we are ready to receive more data from the hostlist * server. * * @param cls closure, unused * @param tc task context, unused */ static void task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Ask CURL for the select set and then schedule the * receiving task with the scheduler. */ static void download_prepare () { CURLMcode mret; fd_set rs; fd_set ws; fd_set es; int max; struct GNUNET_NETWORK_FDSet *grs; struct GNUNET_NETWORK_FDSet *gws; long timeout; struct GNUNET_TIME_Relative rtime; max = -1; FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es); mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); if (mret != CURLM_OK) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), "curl_multi_fdset", __FILE__, __LINE__, curl_multi_strerror (mret)); clean_up (); return; } mret = curl_multi_timeout (multi, &timeout); if (mret != CURLM_OK) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), "curl_multi_timeout", __FILE__, __LINE__, curl_multi_strerror (mret)); clean_up (); return; } rtime = GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (end_time), GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, timeout)); grs = GNUNET_NETWORK_fdset_create (); gws = GNUNET_NETWORK_fdset_create (); GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1); GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scheduling task for hostlist download using cURL\n"); ti_download = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, rtime, grs, gws, &task_download, multi); GNUNET_NETWORK_fdset_destroy (gws); GNUNET_NETWORK_fdset_destroy (grs); } /** * Task that is run when we are ready to receive more data from the hostlist * server. * * @param cls closure, unused * @param tc task context, unused */ static void task_download (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { int running; struct CURLMsg *msg; CURLMcode mret; ti_download = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown requested while trying to download hostlist from `%s'\n", current_url); update_hostlist (); clean_up (); return; } if (GNUNET_TIME_absolute_get_remaining (end_time).rel_value == 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Timeout trying to download hostlist from `%s'\n"), current_url); update_hostlist (); clean_up (); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ready for processing hostlist client request\n"); do { running = 0; if (stat_bytes_downloaded > MAX_BYTES_PER_HOSTLISTS) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Download limit of %u bytes exceeded, stopping download\n"), MAX_BYTES_PER_HOSTLISTS); clean_up (); return; } mret = curl_multi_perform (multi, &running); if (running == 0) { do { msg = curl_multi_info_read (multi, &running); GNUNET_break (msg != NULL); if (msg == NULL) break; switch (msg->msg) { case CURLMSG_DONE: if ((msg->data.result != CURLE_OK) && (msg->data.result != CURLE_GOT_NOTHING)) GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Download of hostlist from `%s' failed: `%s'\n"), current_url, curl_easy_strerror (msg->data.result)); else { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Download of hostlist `%s' completed.\n"), current_url); stat_download_successful = GNUNET_YES; update_hostlist (); if (GNUNET_YES == stat_testing_hostlist) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Adding successfully tested hostlist `%s' datastore.\n"), current_url); insert_hostlist (); hostlist_to_test = NULL; stat_testing_hostlist = GNUNET_NO; } } clean_up (); return; default: break; } } while ((running > 0)); } } while (mret == CURLM_CALL_MULTI_PERFORM); if (mret != CURLM_OK) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("%s failed at %s:%d: `%s'\n"), "curl_multi_perform", __FILE__, __LINE__, curl_multi_strerror (mret)); clean_up (); } download_prepare (); } /** * Main function that will download a hostlist and process its * data. */ static void download_hostlist () { CURLcode ret; CURLMcode mret; current_url = download_get_url (); if (current_url == NULL) return; curl = curl_easy_init (); multi = NULL; if (curl == NULL) { GNUNET_break (0); clean_up (); return; } GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK, _("Bootstrapping using hostlist at `%s'.\n"), current_url); stat_download_in_progress = GNUNET_YES; stat_download_successful = GNUNET_NO; stat_hellos_obtained = 0; stat_bytes_downloaded = 0; GNUNET_STATISTICS_update (stats, gettext_noop ("# hostlist downloads initiated"), 1, GNUNET_NO); if (proxy != NULL) CURL_EASY_SETOPT (curl, CURLOPT_PROXY, proxy); download_pos = 0; stat_bogus_url = 0; CURL_EASY_SETOPT (curl, CURLOPT_WRITEFUNCTION, &callback_download); if (ret != CURLE_OK) { clean_up (); return; } CURL_EASY_SETOPT (curl, CURLOPT_WRITEDATA, NULL); if (ret != CURLE_OK) { clean_up (); return; } CURL_EASY_SETOPT (curl, CURLOPT_FOLLOWLOCATION, 1); CURL_EASY_SETOPT (curl, CURLOPT_MAXREDIRS, 4); /* no need to abort if the above failed */ CURL_EASY_SETOPT (curl, CURLOPT_URL, current_url); if (ret != CURLE_OK) { clean_up (); return; } CURL_EASY_SETOPT (curl, CURLOPT_FAILONERROR, 1); #if 0 CURL_EASY_SETOPT (curl, CURLOPT_VERBOSE, 1); #endif CURL_EASY_SETOPT (curl, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE); if (0 == strncmp (current_url, "http", 4)) CURL_EASY_SETOPT (curl, CURLOPT_USERAGENT, "GNUnet"); CURL_EASY_SETOPT (curl, CURLOPT_CONNECTTIMEOUT, 60L); CURL_EASY_SETOPT (curl, CURLOPT_TIMEOUT, 60L); #if 0 /* this should no longer be needed; we're now single-threaded! */ CURL_EASY_SETOPT (curl, CURLOPT_NOSIGNAL, 1); #endif multi = curl_multi_init (); if (multi == NULL) { GNUNET_break (0); /* clean_up (); */ return; } mret = curl_multi_add_handle (multi, curl); if (mret != CURLM_OK) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), "curl_multi_add_handle", __FILE__, __LINE__, curl_multi_strerror (mret)); mret = curl_multi_cleanup (multi); if (mret != CURLM_OK) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), "curl_multi_cleanup", __FILE__, __LINE__, curl_multi_strerror (mret)); multi = NULL; clean_up (); return; } end_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); download_prepare (); } static void task_download_dispatcher (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { ti_download_dispatcher_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download is initiated...\n"); if (GNUNET_NO == stat_download_in_progress) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download can start immediately...\n"); download_hostlist (); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download in progess, have to wait...\n"); ti_download_dispatcher_task = GNUNET_SCHEDULER_add_delayed (WAITING_INTERVALL, &task_download_dispatcher, NULL); } } /** * Task that checks if we should try to download a hostlist. * If so, we initiate the download, otherwise we schedule * this task again for a later time. */ static void task_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { static int once; struct GNUNET_TIME_Relative delay; ti_check_download = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; if (stats == NULL) { curl_global_cleanup (); return; /* in shutdown */ } if ( (stat_connection_count < MIN_CONNECTIONS) && (GNUNET_SCHEDULER_NO_TASK == ti_download_dispatcher_task) ) ti_download_dispatcher_task = GNUNET_SCHEDULER_add_now (&task_download_dispatcher, NULL); delay = hostlist_delay; if (hostlist_delay.rel_value == 0) hostlist_delay = GNUNET_TIME_UNIT_SECONDS; else hostlist_delay = GNUNET_TIME_relative_multiply (hostlist_delay, 2); if (hostlist_delay.rel_value > GNUNET_TIME_UNIT_HOURS.rel_value * (1 + stat_connection_count)) hostlist_delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, (1 + stat_connection_count)); GNUNET_STATISTICS_set (stats, gettext_noop ("# milliseconds between hostlist downloads"), hostlist_delay.rel_value, GNUNET_YES); if (0 == once) { delay = GNUNET_TIME_UNIT_ZERO; once = 1; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Have %u/%u connections. Will consider downloading hostlist in %llums\n"), stat_connection_count, MIN_CONNECTIONS, (unsigned long long) delay.rel_value); ti_check_download = GNUNET_SCHEDULER_add_delayed (delay, &task_check, NULL); } /** * This tasks sets hostlist testing to allowed after intervall between to testings is reached * * @param cls closure * @param tc TaskContext */ static void task_testing_intervall_reset (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { ti_testing_intervall_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; stat_testing_allowed = GNUNET_OK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing new hostlist advertisements is allowed again\n"); } /** * Task that writes hostlist entries to a file on a regular base * * @param cls closure * @param tc TaskContext */ static void task_hostlist_saving (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { ti_saving_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Scheduled saving of hostlists\n")); save_hostlist_file (GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Hostlists will be saved to file again in %llums\n"), (unsigned long long) SAVING_INTERVALL.rel_value); ti_saving_task = GNUNET_SCHEDULER_add_delayed (SAVING_INTERVALL, &task_hostlist_saving, NULL); } /** * Method called whenever a given peer connects. * * @param cls closure * @param peer peer identity this notification is about * @param atsi performance data * @param atsi_count number of records in 'atsi' */ static void handler_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { GNUNET_assert (stat_connection_count < UINT_MAX); stat_connection_count++; GNUNET_STATISTICS_update (stats, gettext_noop ("# active connections"), 1, GNUNET_NO); } /** * Method called whenever a given peer disconnects. * * @param cls closure * @param peer peer identity this notification is about */ static void handler_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) { GNUNET_assert (stat_connection_count > 0); stat_connection_count--; GNUNET_STATISTICS_update (stats, gettext_noop ("# active connections"), -1, GNUNET_NO); } /** * Method called whenever an advertisement message arrives. * * @param cls closure (always NULL) * @param peer the peer sending the message * @param message the actual message * @param atsi performance data * @param atsi_count number of records in 'atsi' * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ static int handler_advertisement (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { size_t size; size_t uri_size; const struct GNUNET_MessageHeader *incoming; const char *uri; struct Hostlist *hostlist; GNUNET_assert (ntohs (message->type) == GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT); size = ntohs (message->size); if (size <= sizeof (struct GNUNET_MessageHeader)) { GNUNET_break_op (0); return GNUNET_SYSERR; } incoming = (const struct GNUNET_MessageHeader *) message; uri = (const char *) &incoming[1]; uri_size = size - sizeof (struct GNUNET_MessageHeader); if (uri[uri_size - 1] != '\0') { GNUNET_break_op (0); return GNUNET_SYSERR; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist client recieved advertisement from `%s' containing URI `%s'\n", GNUNET_i2s (peer), uri); if (GNUNET_NO != linked_list_contains (uri)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "URI `%s' is already known\n", uri); return GNUNET_OK; } if (GNUNET_NO == stat_testing_allowed) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Currently not accepting new advertisements: interval between to advertisements is not reached\n"); return GNUNET_SYSERR; } if (GNUNET_YES == stat_testing_hostlist) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Currently not accepting new advertisements: we are already testing a hostlist\n"); return GNUNET_SYSERR; } hostlist = GNUNET_malloc (sizeof (struct Hostlist) + uri_size); hostlist->hostlist_uri = (const char *) &hostlist[1]; memcpy (&hostlist[1], uri, uri_size); hostlist->time_creation = GNUNET_TIME_absolute_get (); hostlist->quality = HOSTLIST_INITIAL; hostlist_to_test = hostlist; stat_testing_hostlist = GNUNET_YES; stat_testing_allowed = GNUNET_NO; ti_testing_intervall_task = GNUNET_SCHEDULER_add_delayed (TESTING_INTERVAL, &task_testing_intervall_reset, NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testing new hostlist advertisements is locked for the next %u ms\n", TESTING_INTERVAL.rel_value); ti_download_dispatcher_task = GNUNET_SCHEDULER_add_now (&task_download_dispatcher, NULL); return GNUNET_OK; } /** * Continuation called by the statistics code once * we go the stat. Initiates hostlist download scheduling. * * @param cls closure * @param success GNUNET_OK if statistics were * successfully obtained, GNUNET_SYSERR if not. */ static void primary_task (void *cls, int success) { sget = NULL; GNUNET_assert (stats != NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Statistics request done, scheduling hostlist download\n"); ti_check_download = GNUNET_SCHEDULER_add_now (&task_check, NULL); } static int process_stat (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Initial time between hostlist downloads is %llums\n"), (unsigned long long) value); hostlist_delay.rel_value = value; return GNUNET_OK; } /** * Method to load persistent hostlist file during hostlist client startup */ static void load_hostlist_file () { char *filename; char *uri; char *emsg; struct Hostlist *hostlist; uri = NULL; uint32_t times_used; uint32_t hellos_returned; uint64_t quality; uint64_t last_used; uint64_t created; uint32_t counter; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "HOSTLIST", "HOSTLISTFILE", &filename)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("No `%s' specified in `%s' configuration, cannot load hostlists from file.\n"), "HOSTLISTFILE", "HOSTLIST"); return; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading saved hostlist entries from file `%s' \n"), filename); if (GNUNET_NO == GNUNET_DISK_file_test (filename)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Hostlist file `%s' is not existing\n"), filename); GNUNET_free (filename); return; } struct GNUNET_BIO_ReadHandle *rh = GNUNET_BIO_read_open (filename); if (NULL == rh) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Could not open file `%s' for reading to load hostlists: %s\n"), filename, STRERROR (errno)); GNUNET_free (filename); return; } counter = 0; while ((GNUNET_OK == GNUNET_BIO_read_string (rh, "url", &uri, MAX_URL_LEN)) && (NULL != uri) && (GNUNET_OK == GNUNET_BIO_read_int32 (rh, ×_used)) && (GNUNET_OK == GNUNET_BIO_read_int64 (rh, &quality)) && (GNUNET_OK == GNUNET_BIO_read_int64 (rh, &last_used)) && (GNUNET_OK == GNUNET_BIO_read_int64 (rh, &created)) && (GNUNET_OK == GNUNET_BIO_read_int32 (rh, &hellos_returned))) { hostlist = GNUNET_malloc (sizeof (struct Hostlist) + strlen (uri) + 1); hostlist->hello_count = hellos_returned; hostlist->hostlist_uri = (const char *) &hostlist[1]; memcpy (&hostlist[1], uri, strlen (uri) + 1); hostlist->quality = quality; hostlist->time_creation.abs_value = created; hostlist->time_last_usage.abs_value = last_used; GNUNET_CONTAINER_DLL_insert (linked_list_head, linked_list_tail, hostlist); linked_list_size++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added hostlist entry eith URI `%s' \n", hostlist->hostlist_uri); GNUNET_free (uri); uri = NULL; counter++; if (counter >= MAX_NUMBER_HOSTLISTS) break; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("%u hostlist URIs loaded from file\n"), counter); GNUNET_STATISTICS_set (stats, gettext_noop ("# hostlist URIs read from file"), counter, GNUNET_YES); GNUNET_STATISTICS_set (stats, gettext_noop ("# advertised hostlist URIs"), linked_list_size, GNUNET_NO); GNUNET_free_non_null (uri); emsg = NULL; GNUNET_BIO_read_close (rh, &emsg); if (emsg != NULL) GNUNET_free (emsg); GNUNET_free (filename); } /** * Method to save persistent hostlist file during hostlist client shutdown * @param shutdown set if called because of shutdown, entries in linked list will be destroyed */ static void save_hostlist_file (int shutdown) { char *filename; struct Hostlist *pos; struct GNUNET_BIO_WriteHandle *wh; int ok; uint32_t counter; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "HOSTLIST", "HOSTLISTFILE", &filename)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("No `%s' specified in `%s' configuration, cannot save hostlists to file.\n"), "HOSTLISTFILE", "HOSTLIST"); return; } if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename)) { GNUNET_free (filename); return; } wh = GNUNET_BIO_write_open (filename); if (NULL == wh) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not open file `%s' for writing to save hostlists: %s\n"), filename, STRERROR (errno)); GNUNET_free (filename); return; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Writing %u hostlist URIs to `%s'\n"), linked_list_size, filename); /* add code to write hostlists to file using bio */ ok = GNUNET_YES; counter = 0; while (NULL != (pos = linked_list_head)) { if (GNUNET_YES == shutdown) { GNUNET_CONTAINER_DLL_remove (linked_list_head, linked_list_tail, pos); linked_list_size--; } if (GNUNET_YES == ok) { if ((GNUNET_OK != GNUNET_BIO_write_string (wh, pos->hostlist_uri)) || (GNUNET_OK != GNUNET_BIO_write_int32 (wh, pos->times_used)) || (GNUNET_OK != GNUNET_BIO_write_int64 (wh, pos->quality)) || (GNUNET_OK != GNUNET_BIO_write_int64 (wh, pos->time_last_usage.abs_value)) || (GNUNET_OK != GNUNET_BIO_write_int64 (wh, pos->time_creation.abs_value)) || (GNUNET_OK != GNUNET_BIO_write_int32 (wh, pos->hello_count))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Error writing hostlist URIs to file `%s'\n"), filename); ok = GNUNET_NO; } } if (GNUNET_YES == shutdown) GNUNET_free (pos); counter++; if (counter >= MAX_NUMBER_HOSTLISTS) break; } GNUNET_STATISTICS_set (stats, gettext_noop ("# hostlist URIs written to file"), counter, GNUNET_YES); if (GNUNET_OK != GNUNET_BIO_write_close (wh)) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Error writing hostlist URIs to file `%s'\n"), filename); GNUNET_free (filename); } /** * Start downloading hostlists from hostlist servers as necessary. */ int GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_STATISTICS_Handle *st, GNUNET_CORE_ConnectEventHandler *ch, GNUNET_CORE_DisconnectEventHandler *dh, GNUNET_CORE_MessageCallback *msgh, int learn) { char *filename; int result; GNUNET_assert (NULL != st); if (0 != curl_global_init (CURL_GLOBAL_WIN32)) { GNUNET_break (0); return GNUNET_SYSERR; } transport = GNUNET_TRANSPORT_connect (c, NULL, NULL, NULL, NULL, NULL); if (NULL == transport) { curl_global_cleanup (); return GNUNET_SYSERR; } cfg = c; stats = st; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "HOSTLIST", "HTTP-PROXY", &proxy)) proxy = NULL; stat_learning = learn; *ch = &handler_connect; *dh = &handler_disconnect; linked_list_head = NULL; linked_list_tail = NULL; stat_use_bootstrap = GNUNET_YES; stat_testing_hostlist = GNUNET_NO; stat_testing_allowed = GNUNET_YES; if (GNUNET_YES == stat_learning) { *msgh = &handler_advertisement; GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Learning is enabled on this peer\n")); load_hostlist_file (); GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Hostlists will be saved to file again in %llums\n"), (unsigned long long) SAVING_INTERVALL.rel_value); ti_saving_task = GNUNET_SCHEDULER_add_delayed (SAVING_INTERVALL, &task_hostlist_saving, NULL); } else { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Learning is not enabled on this peer\n")); *msgh = NULL; if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, "HOSTLIST", "HOSTLISTFILE", &filename)) { if (GNUNET_YES == GNUNET_DISK_file_test (filename)) { result = remove (filename); if (result == 0) GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Since learning is not enabled on this peer, hostlist file `%s' was removed\n"), filename); else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Hostlist file `%s' could not be removed\n"), filename); } } GNUNET_free (filename); } sget = GNUNET_STATISTICS_get (stats, "hostlist", gettext_noop ("# milliseconds between hostlist downloads"), GNUNET_TIME_UNIT_MINUTES, &primary_task, &process_stat, NULL); return GNUNET_OK; } /** * Stop downloading hostlists from hostlist servers as necessary. */ void GNUNET_HOSTLIST_client_stop () { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist client shutdown\n"); if (NULL != sget) { GNUNET_STATISTICS_get_cancel (sget); sget = NULL; } stats = NULL; if (GNUNET_YES == stat_learning) save_hostlist_file (GNUNET_YES); if (ti_saving_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (ti_saving_task); ti_saving_task = GNUNET_SCHEDULER_NO_TASK; } if (ti_download_dispatcher_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (ti_download_dispatcher_task); ti_download_dispatcher_task = GNUNET_SCHEDULER_NO_TASK; } if (ti_testing_intervall_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (ti_testing_intervall_task); ti_testing_intervall_task = GNUNET_SCHEDULER_NO_TASK; } if (ti_download != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (ti_download); ti_download = GNUNET_SCHEDULER_NO_TASK; } if (ti_check_download != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (ti_check_download); ti_check_download = GNUNET_SCHEDULER_NO_TASK; curl_global_cleanup (); } if (transport != NULL) { GNUNET_TRANSPORT_disconnect (transport); transport = NULL; } GNUNET_free_non_null (proxy); proxy = NULL; cfg = NULL; } /* end of hostlist-client.c */ gnunet-0.9.3/src/hostlist/test_learning_learn_peer2.conf0000644000175000017500000000136211615567501020400 00000000000000@INLINE@ test_hostlist_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-hostlist-peer-3/ DEFAULTCONFIG = test_learning_learn_peer2.conf [transport-tcp] PORT = 32968 [arm] PORT = 32966 DEFAULTSERVICES = topology hostlist UNIXPATH = /tmp/gnunet-p3-service-arm.sock [statistics] PORT = 32967 UNIXPATH = /tmp/gnunet-p3-service-statistics.sock [resolver] PORT = 32964 UNIXPATH = /tmp/gnunet-p3-service-resolver.sock [peerinfo] PORT = 32969 UNIXPATH = /tmp/gnunet-p3-service-peerinfo.sock [transport] PORT = 32965 UNIXPATH = /tmp/gnunet-p3-service-transport.sock [core] PORT = 32970 UNIXPATH = /tmp/gnunet-p3-service-core.sock [hostlist] HTTPPORT = 32980 HOSTLISTFILE = hostlists_learn_peer2.file OPTIONS = -b -e SERVERS = http://localhost:12981/ gnunet-0.9.3/src/hostlist/test_learning_adv_peer.conf0000644000175000017500000000163211647100202017751 00000000000000@INLINE@ test_hostlist_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-hostlist-peer-1/ DEFAULTCONFIG = test_learning_adv_peer.conf [transport-tcp] PORT = 22968 [arm] PORT = 22966 DEFAULTSERVICES = topology hostlist UNIXPATH = /tmp/gnunet-hostlist-p2-service-arm.sock [statistics] PORT = 22967 UNIXPATH = /tmp/gnunet-hostlist-p2-service-statistics.sock [resolver] PORT = 22964 UNIXPATH = /tmp/gnunet-hostlist-p2-service-resolver.sock [peerinfo] PORT = 22969 UNIXPATH = /tmp/gnunet-hostlist-p2-service-peerinfo.sock [transport] PORT = 22965 UNIXPATH = /tmp/gnunet-hostlist-p2-service-transport.sock [core] PORT = 22970 UNIXPATH = /tmp/gnunet-hostlist-p2-service-core.sock [hostlist] HTTPPORT = 12981 HOSTLISTFILE = hostlists_adv_peer.file OPTIONS = -p -a SERVERS = http://localhost:12981/ EXTERNAL_DNS_NAME = localhost [dht] AUTOSTART = NO [ats] PORT = 22971 UNIXPATH = /tmp/gnunet-ats-p2-service-core.sock gnunet-0.9.3/src/hostlist/test_gnunet_daemon_hostlist_peer1.conf0000644000175000017500000000147611762206504022175 00000000000000@INLINE@ test_hostlist_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-hostlist-peer-1/ DEFAULTCONFIG = test_gnunet_daemon_hostlist_peer1.conf [transport-tcp] PORT = 12968 [arm] PORT = 12966 DEFAULTSERVICES = hostlist topology UNIXPATH = /tmp/gnunet-p1-service-arm.sock [statistics] PORT = 12967 UNIXPATH = /tmp/gnunet-p1-service-statistics.sock [resolver] PORT = 12964 UNIXPATH = /tmp/gnunet-p1-service-resolver.sock [peerinfo] PORT = 12969 UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock [transport] PORT = 12965 UNIXPATH = /tmp/gnunet-p1-service-transport.sock DEBUG = NO [core] PORT = 12970 UNIXPATH = /tmp/gnunet-p1-service-core.sock [hostlist] HTTPPORT = 12980 HOSTLISTFILE = hostlists_peer1.file OPTIONS = -b -p SERVERS = http://localhost:12981/ [ats] PORT = 12971 UNIXPATH = /tmp/gnunet-p1-service-ats.sock gnunet-0.9.3/src/hostlist/gnunet-daemon-hostlist.c0000644000175000017500000002215611760502551017170 00000000000000/* This file is part of GNUnet. (C) 2007, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file hostlist/gnunet-daemon-hostlist.c * @brief code for bootstrapping via hostlist servers * @author Christian Grothoff */ #include #include "platform.h" #include "hostlist-client.h" #include "gnunet_core_service.h" #include "gnunet_getopt_lib.h" #include "gnunet_protocols.h" #include "gnunet_program_lib.h" #include "gnunet_statistics_service.h" #include "gnunet_strings_lib.h" #include "gnunet_time_lib.h" #include "gnunet_util_lib.h" #if HAVE_MHD #include "hostlist-server.h" /** * Set if we are allowed to advertise our hostlist to others. */ static int advertising; /** * Set if the user wants us to run a hostlist server. */ static int provide_hostlist; /** * Handle to hostlist server's connect handler */ static GNUNET_CORE_ConnectEventHandler server_ch; /** * Handle to hostlist server's disconnect handler */ static GNUNET_CORE_DisconnectEventHandler server_dh; #endif /** * Set if we are allowed to learn about peers by accessing * hostlist servers. */ static int bootstrapping; /** * Set if the user allows us to learn about new hostlists * from the network. */ static int learning; /** * Statistics handle. */ static struct GNUNET_STATISTICS_Handle *stats; /** * Handle to the core service (NULL until we've connected to it). */ static struct GNUNET_CORE_Handle *core; /** * Handle to the hostlist client's advertisement handler */ static GNUNET_CORE_MessageCallback client_adv_handler; /** * Handle to hostlist client's connect handler */ static GNUNET_CORE_ConnectEventHandler client_ch; /** * Handle to hostlist client's disconnect handler */ static GNUNET_CORE_DisconnectEventHandler client_dh; GNUNET_NETWORK_STRUCT_BEGIN /** * A HOSTLIST_ADV message is used to exchange information about * hostlist advertisements. This struct is always * followed by the actual url under which the hostlist can be obtained: * * 1) transport-name (0-terminated) * 2) address-length (uint32_t, network byte order; possibly * unaligned!) * 3) address expiration (GNUNET_TIME_AbsoluteNBO); possibly * unaligned!) * 4) address (address-length bytes; possibly unaligned!) */ struct GNUNET_HOSTLIST_ADV_Message { /** * Type will be GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT. */ struct GNUNET_MessageHeader header; /** * Always zero (for alignment). */ uint32_t reserved GNUNET_PACKED; }; GNUNET_NETWORK_STRUCT_END static struct GNUNET_PeerIdentity me; static void core_init (void *cls, struct GNUNET_CORE_Handle *server, const struct GNUNET_PeerIdentity *my_identity) { me = *my_identity; } /** * Core handler for p2p hostlist advertisements * * @param cls closure * @param peer identity of the sender * @param message advertisement message we got * @param atsi performance information * @param atsi_count number of records in 'atsi' * @return GNUNET_OK on success */ static int advertisement_handler (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { GNUNET_assert (NULL != client_adv_handler); return (*client_adv_handler) (cls, peer, message, atsi, atsi_count); } /** * Method called whenever a given peer connects. Wrapper to call both client's and server's functions * * @param cls closure * @param peer peer identity this notification is about * @param atsi performance data * @param atsi_count number of records in 'atsi' */ static void connect_handler (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { if (0 == memcmp (&me, peer, sizeof (struct GNUNET_PeerIdentity))) return; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "A new peer connected, notifying client and server\n"); if (NULL != client_ch) (*client_ch) (cls, peer, atsi, atsi_count); #if HAVE_MHD if (NULL != server_ch) (*server_ch) (cls, peer, atsi, atsi_count); #endif } /** * Method called whenever a given peer disconnects. Wrapper to call both client's and server's functions * * @param cls closure * @param peer peer identity this notification is about */ static void disconnect_handler (void *cls, const struct GNUNET_PeerIdentity *peer) { if (0 == memcmp (&me, peer, sizeof (struct GNUNET_PeerIdentity))) return; /* call hostlist client disconnect handler */ if (NULL != client_dh) (*client_dh) (cls, peer); #if HAVE_MHD /* call hostlist server disconnect handler */ if (NULL != server_dh) (*server_dh) (cls, peer); #endif } /** * Last task run during shutdown. Disconnects us from * the other services. */ static void cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist daemon is shutting down\n"); if (core != NULL) { GNUNET_CORE_disconnect (core); core = NULL; } if (bootstrapping) { GNUNET_HOSTLIST_client_stop (); } #if HAVE_MHD if (provide_hostlist) { GNUNET_HOSTLIST_server_stop (); } #endif if (stats != NULL) { GNUNET_STATISTICS_destroy (stats, GNUNET_NO); stats = NULL; } } /** * Main function that will be run. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param cfg configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { static const struct GNUNET_CORE_MessageHandler learn_handlers[] = { {&advertisement_handler, GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT, 0}, {NULL, 0, 0} }; static const struct GNUNET_CORE_MessageHandler no_learn_handlers[] = { {NULL, 0, 0} }; if ((!bootstrapping) && (!learning) #if HAVE_MHD && (!provide_hostlist) #endif ) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("None of the functions for the hostlist daemon were enabled. I have no reason to run!\n")); return; } stats = GNUNET_STATISTICS_create ("hostlist", cfg); core = GNUNET_CORE_connect (cfg, 1, NULL, &core_init, &connect_handler, &disconnect_handler, NULL, GNUNET_NO, NULL, GNUNET_NO, learning ? learn_handlers : no_learn_handlers); if (bootstrapping) { GNUNET_HOSTLIST_client_start (cfg, stats, &client_ch, &client_dh, &client_adv_handler, learning); } #if HAVE_MHD if (provide_hostlist) { GNUNET_HOSTLIST_server_start (cfg, stats, core, &server_ch, &server_dh, advertising); } #endif GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleaning_task, NULL); if (NULL == core) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to connect to `%s' service.\n"), "core"); GNUNET_SCHEDULER_shutdown (); return; } } /** * The main function for the hostlist daemon. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { #if HAVE_MHD {'a', "advertise", NULL, gettext_noop ("advertise our hostlist to other peers"), GNUNET_NO, &GNUNET_GETOPT_set_one, &advertising}, #endif {'b', "bootstrap", NULL, gettext_noop ("bootstrap using hostlists (it is highly recommended that you always use this option)"), GNUNET_NO, &GNUNET_GETOPT_set_one, &bootstrapping}, {'e', "enable-learning", NULL, gettext_noop ("enable learning about hostlist servers from other peers"), GNUNET_NO, &GNUNET_GETOPT_set_one, &learning}, #if HAVE_MHD {'p', "provide-hostlist", NULL, gettext_noop ("provide a hostlist server"), GNUNET_NO, &GNUNET_GETOPT_set_one, &provide_hostlist}, #endif GNUNET_GETOPT_OPTION_END }; int ret; GNUNET_log_setup ("hostlist", "WARNING", NULL); ret = (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "hostlist", _("GNUnet hostlist server and client"), options, &run, NULL)) ? 0 : 1; return ret; } /* end of gnunet-daemon-hostlist.c */ gnunet-0.9.3/src/hostlist/test_gnunet_daemon_hostlist_reconnect.c0000644000175000017500000001600311760502551022425 00000000000000/* This file is part of GNUnet (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file hostlist/test_gnunet_daemon_hostlist_reconnect.c * @brief test for gnunet_daemon_hostslist.c; tries to re-start the peers * and connect a second time * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_arm_service.h" #include "gnunet_transport_service.h" #define VERBOSE GNUNET_NO #define START_ARM GNUNET_YES /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 150) static int ok; static GNUNET_SCHEDULER_TaskIdentifier timeout_task; struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_TRANSPORT_Handle *th; struct GNUNET_MessageHeader *hello; struct GNUNET_TRANSPORT_GetHelloHandle *ghh; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static struct PeerContext p1; static struct PeerContext p2; static void clean_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (NULL != p1.ghh) { GNUNET_TRANSPORT_get_hello_cancel (p1.ghh); p1.ghh = NULL; } if (p1.th != NULL) { GNUNET_TRANSPORT_disconnect (p1.th); p1.th = NULL; } if (NULL != p2.ghh) { GNUNET_TRANSPORT_get_hello_cancel (p2.ghh); p2.ghh = NULL; } if (p2.th != NULL) { GNUNET_TRANSPORT_disconnect (p2.th); p2.th = NULL; } GNUNET_SCHEDULER_shutdown (); } /** * Timeout, give up. */ static void timeout_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { timeout_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout trying to connect peers, test failed.\n"); clean_up (NULL, tc); } /** * Function called to notify transport users that another * peer connected to us. * * @param cls closure * @param peer the peer that connected * @param latency current latency of the connection * @param distance in overlay hops, as given by transport plugin */ static void notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { if (peer == NULL) return; #if VERBOSE FPRINTF (stderr, "Peer %s connected\n", GNUNET_i2s (peer)); #endif GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected, shutting down.\n"); ok = 0; if (timeout_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (timeout_task); timeout_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_SCHEDULER_add_now (&clean_up, NULL); } static void process_hello (void *cls, const struct GNUNET_MessageHeader *message) { struct PeerContext *p = cls; GNUNET_TRANSPORT_get_hello_cancel (p->ghh); p->ghh = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received HELLO, starting hostlist service.\n"); } static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", #if VERBOSE "-L", "DEBUG", #endif "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p, NULL, ¬ify_connect, NULL); GNUNET_assert (p->th != NULL); p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &process_hello, p); } static void waitpid_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerContext *p = cls; #if START_ARM GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Killing ARM process.\n"); if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; #endif GNUNET_CONFIGURATION_destroy (p->cfg); } static void stop_arm (struct PeerContext *p) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking ARM to stop core service\n"); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &waitpid_task, p); } /** * Try again to connect to transport service. */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { stop_arm (&p1); stop_arm (&p2); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { GNUNET_assert (ok == 1); ok++; timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_error, NULL); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); setup_peer (&p1, "test_gnunet_daemon_hostlist_peer1.conf"); setup_peer (&p2, "test_gnunet_daemon_hostlist_peer2.conf"); } static int check () { char *const argv[] = { "test-gnunet-daemon-hostlist", "-c", "test_gnunet_daemon_hostlist_data.conf", #if VERBOSE "-L", "DEBUG", #endif NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; ok = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-gnunet-daemon-hostlist", "nohelp", options, &run, &ok); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-1"); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-2"); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-3"); GNUNET_log_setup ("test-gnunet-daemon-hostlist", #if VERBOSE "DEBUG", #else "WARNING", #endif NULL); ret = check (); if (ret == 0) { FPRINTF (stderr, "%s", "."); /* now do it again */ ret = check (); FPRINTF (stderr, "%s", ".\n"); } GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-1"); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-2"); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-3"); return ret; } /* end of test_gnunet_daemon_hostlist_reconnect.c */ gnunet-0.9.3/src/hostlist/gnunet-daemon-hostlist.h0000644000175000017500000000276011760502551017174 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file hostlist/gnunet-daemon-hostlist.h * @brief common internal definitions for hostlist daemon * @author Matthias Wachs */ #include #include "platform.h" #include "hostlist-client.h" #include "hostlist-server.h" #include "gnunet_core_service.h" #include "gnunet_getopt_lib.h" #include "gnunet_protocols.h" #include "gnunet_program_lib.h" #include "gnunet_statistics_service.h" #include "gnunet_strings_lib.h" #include "gnunet_time_lib.h" #include "gnunet_util_lib.h" /** * General hostlist daemon debugging. */ #define DEBUG_HOSTLIST GNUNET_EXTRA_LOGGING #define MAX_URL_LEN 1000 #define MAX_BYTES_PER_HOSTLISTS 500000 /* end of gnunet-daemon-hostlist.h */ gnunet-0.9.3/src/hostlist/test_hostlist_defaults.conf0000644000175000017500000000117311762206631020060 00000000000000[PATHS] SERVICEHOME = /tmp/test-gnunet-hostlist/ DEFAULTCONFIG = test_hostlist_default.conf [resolver] PORT = 12464 [transport] PORT = 12465 PLUGINS = tcp [arm] PORT = 12466 DEFAULTSERVICES = hostlist [statistics] PORT = 12467 [tcp] PORT = 12468 [peerinfo] PORT = 12469 [core] PORT = 12470 [testing] WEAKRANDOM = YES [hostlist] HTTP-PROXY = [mesh] AUTOSTART = NO [dns] AUTOSTART = NO [nse] AUTOSTART = NO [datastore] AUTOSTART = NO [fs] AUTOSTART = NO [dht] AUTOSTART = NO [dv] AUTOSTART = NO [chat] AUTOSTART = NO [gns] AUTOSTART = NO [vpn] AUTOSTART = NO [namestore] AUTOSTART = NO [lockmanager] AUTOSTART = NO gnunet-0.9.3/src/hostlist/learning_data.conf0000644000175000017500000000022611745513743016055 00000000000000@INLINE@ test_hostlist_defaults.conf [hostlist] HTTPPORT = 28080 OPTIONS = -b -e SERVERS = http://gnunet.org:8080/ PORT = 23354 HOSTNAME = localhost gnunet-0.9.3/src/hostlist/test_gnunet_daemon_hostlist.c0000644000175000017500000001507211762206603020373 00000000000000/* This file is part of GNUnet (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file hostlist/test_gnunet_daemon_hostlist.c * @brief test for gnunet_daemon_hostslist.c * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_arm_service.h" #include "gnunet_transport_service.h" #define VERBOSE GNUNET_NO #define START_ARM GNUNET_YES /** * How long until we give up on transmitting the message? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 150) static int ok; static GNUNET_SCHEDULER_TaskIdentifier timeout_task; struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_TRANSPORT_Handle *th; struct GNUNET_MessageHeader *hello; struct GNUNET_TRANSPORT_GetHelloHandle *ghh; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static struct PeerContext p1; static struct PeerContext p2; static void clean_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (p1.th != NULL) { if (p1.ghh != NULL) { GNUNET_TRANSPORT_get_hello_cancel (p1.ghh); p1.ghh = NULL; } GNUNET_TRANSPORT_disconnect (p1.th); p1.th = NULL; } if (p2.th != NULL) { if (p2.ghh != NULL) { GNUNET_TRANSPORT_get_hello_cancel (p2.ghh); p2.ghh = NULL; } GNUNET_TRANSPORT_disconnect (p2.th); p2.th = NULL; } GNUNET_SCHEDULER_shutdown (); } /** * Timeout, give up. */ static void timeout_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { timeout_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout trying to connect peers, test failed.\n"); clean_up (NULL, tc); } /** * Function called to notify transport users that another * peer connected to us. * * @param cls closure * @param peer the peer that connected * @param latency current latency of the connection * @param distance in overlay hops, as given by transport plugin */ static void notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *ats, uint32_t ats_count) { if (peer == NULL) return; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected, shutting down.\n"); ok = 0; if (timeout_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (timeout_task); timeout_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_SCHEDULER_add_now (&clean_up, NULL); } static void process_hello (void *cls, const struct GNUNET_MessageHeader *message) { struct PeerContext *p = cls; GNUNET_TRANSPORT_get_hello_cancel (p->ghh); p->ghh = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received HELLO, starting hostlist service.\n"); } static void setup_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p, NULL, ¬ify_connect, NULL); GNUNET_assert (p->th != NULL); p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &process_hello, p); } static void waitpid_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerContext *p = cls; #if START_ARM GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Killing ARM process.\n"); if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc)); GNUNET_OS_process_destroy (p->arm_proc); p->arm_proc = NULL; #endif GNUNET_CONFIGURATION_destroy (p->cfg); } static void stop_arm (struct PeerContext *p) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking ARM to stop core service\n"); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &waitpid_task, p); } /** * Try again to connect to transport service. */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { stop_arm (&p1); stop_arm (&p2); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { GNUNET_assert (ok == 1); ok++; timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_error, NULL); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); setup_peer (&p1, "test_gnunet_daemon_hostlist_peer1.conf"); setup_peer (&p2, "test_gnunet_daemon_hostlist_peer2.conf"); } static int check () { char *const argv[] = { "test-gnunet-daemon-hostlist", "-c", "test_gnunet_daemon_hostlist_data.conf", NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; ok = 1; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-gnunet-daemon-hostlist", "nohelp", options, &run, &ok); return ok; } int main (int argc, char *argv[]) { int ret; GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-1"); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-2"); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist"); GNUNET_log_setup ("test-gnunet-daemon-hostlist", "WARNING", NULL); ret = check (); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-1"); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-2"); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist"); return ret; } /* end of test_gnunet_daemon_hostlist.c */ gnunet-0.9.3/src/hostlist/test_learning_learn_peer.conf0000644000175000017500000000160011647100202020273 00000000000000@INLINE@ test_hostlist_defaults.conf [PATHS] SERVICEHOME = /tmp/test-gnunet-hostlist-peer-2/ DEFAULTCONFIG = test_learning_learn_peer.conf [transport-tcp] PORT = 12968 [arm] PORT = 12966 DEFAULTSERVICES = topology hostlist UNIXPATH = /tmp/gnunet-hostlist-p1-service-arm.sock [statistics] PORT = 12967 UNIXPATH = /tmp/gnunet-hostlist-p1-service-statistics.sock [resolver] PORT = 12964 UNIXPATH = /tmp/gnunet-hostlist-p1-service-resolver.sock [peerinfo] PORT = 12969 UNIXPATH = /tmp/gnunet-hostlist-p1-service-peerinfo.sock [transport] PORT = 12965 UNIXPATH = /tmp/gnunet-hostlist-p1-service-transport.sock [core] PORT = 12970 UNIXPATH = /tmp/gnunet-hostlist-p1-service-core.sock [hostlist] HTTPPORT = 12980 HOSTLISTFILE = hostlists_learn_peer.file OPTIONS = -b -e SERVERS = http://localhost:12981/ [dht] AUTOSTART = NO [ats] PORT = 12971 UNIXPATH = /tmp/gnunet-ats-p1-service-core.sock gnunet-0.9.3/src/hostlist/hostlist-server.h0000644000175000017500000000344211760502551015737 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file hostlist/hostlist-server.h * @brief hostlist support. Downloads HELLOs via HTTP. * @author Christian Grothoff */ #ifndef HOSTLIST_SERVER_H #define HOSTLIST_SERVER_H #include "gnunet_core_service.h" #include "gnunet_statistics_service.h" #include "gnunet_util_lib.h" #define GNUNET_ADV_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) /** * Start server offering our hostlist. * * @return GNUNET_OK on success */ int GNUNET_HOSTLIST_server_start (const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_STATISTICS_Handle *st, struct GNUNET_CORE_Handle *core, GNUNET_CORE_ConnectEventHandler *server_ch, GNUNET_CORE_DisconnectEventHandler *server_dh, int advertise); /** * Stop server offering our hostlist. */ void GNUNET_HOSTLIST_server_stop (void); #endif /* end of hostlist-server.h */ gnunet-0.9.3/src/hostlist/Makefile.in0000644000175000017500000011264011762217212014456 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-daemon-hostlist$(EXEEXT) check_PROGRAMS = test_gnunet_daemon_hostlist$(EXEEXT) \ test_gnunet_daemon_hostlist_reconnect$(EXEEXT) \ test_gnunet_daemon_hostlist_learning$(EXEEXT) @ENABLE_TEST_RUN_TRUE@@HAVE_MHD_TRUE@TESTS = test_gnunet_daemon_hostlist$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@@HAVE_MHD_TRUE@ test_gnunet_daemon_hostlist_reconnect$(EXEEXT) \ @ENABLE_TEST_RUN_TRUE@@HAVE_MHD_TRUE@ test_gnunet_daemon_hostlist_learning$(EXEEXT) subdir = src/hostlist DIST_COMMON = $(dist_pkgcfg_DATA) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)" PROGRAMS = $(bin_PROGRAMS) am__gnunet_daemon_hostlist_SOURCES_DIST = gnunet-daemon-hostlist.c \ gnunet-daemon-hostlist.h hostlist-client.c hostlist-client.h \ hostlist-server.c hostlist-server.h @HAVE_MHD_TRUE@am__objects_1 = gnunet_daemon_hostlist-hostlist-server.$(OBJEXT) am_gnunet_daemon_hostlist_OBJECTS = \ gnunet_daemon_hostlist-gnunet-daemon-hostlist.$(OBJEXT) \ gnunet_daemon_hostlist-hostlist-client.$(OBJEXT) \ $(am__objects_1) gnunet_daemon_hostlist_OBJECTS = $(am_gnunet_daemon_hostlist_OBJECTS) am__DEPENDENCIES_1 = gnunet_daemon_hostlist_DEPENDENCIES = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent am_test_gnunet_daemon_hostlist_OBJECTS = \ test_gnunet_daemon_hostlist.$(OBJEXT) test_gnunet_daemon_hostlist_OBJECTS = \ $(am_test_gnunet_daemon_hostlist_OBJECTS) test_gnunet_daemon_hostlist_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_gnunet_daemon_hostlist_learning_OBJECTS = \ test_gnunet_daemon_hostlist_learning.$(OBJEXT) test_gnunet_daemon_hostlist_learning_OBJECTS = \ $(am_test_gnunet_daemon_hostlist_learning_OBJECTS) test_gnunet_daemon_hostlist_learning_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la am_test_gnunet_daemon_hostlist_reconnect_OBJECTS = \ test_gnunet_daemon_hostlist_reconnect.$(OBJEXT) test_gnunet_daemon_hostlist_reconnect_OBJECTS = \ $(am_test_gnunet_daemon_hostlist_reconnect_OBJECTS) test_gnunet_daemon_hostlist_reconnect_DEPENDENCIES = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(gnunet_daemon_hostlist_SOURCES) \ $(test_gnunet_daemon_hostlist_SOURCES) \ $(test_gnunet_daemon_hostlist_learning_SOURCES) \ $(test_gnunet_daemon_hostlist_reconnect_SOURCES) DIST_SOURCES = $(am__gnunet_daemon_hostlist_SOURCES_DIST) \ $(test_gnunet_daemon_hostlist_SOURCES) \ $(test_gnunet_daemon_hostlist_learning_SOURCES) \ $(test_gnunet_daemon_hostlist_reconnect_SOURCES) am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' DATA = $(dist_pkgcfg_DATA) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include pkgcfgdir = $(pkgdatadir)/config.d/ dist_pkgcfg_DATA = \ hostlist.conf @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @HAVE_MHD_TRUE@HOSTLIST_SERVER_SOURCES = hostlist-server.c hostlist-server.h @HAVE_MHD_TRUE@GN_LIBMHD = -lmicrohttpd gnunet_daemon_hostlist_SOURCES = \ gnunet-daemon-hostlist.c gnunet-daemon-hostlist.h \ hostlist-client.c hostlist-client.h \ $(HOSTLIST_SERVER_SOURCES) gnunet_daemon_hostlist_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBMHD) \ @LIBCURL@ \ $(GN_LIBINTL) gnunet_daemon_hostlist_CPPFLAGS = \ @LIBCURL_CPPFLAGS@ test_gnunet_daemon_hostlist_SOURCES = \ test_gnunet_daemon_hostlist.c test_gnunet_daemon_hostlist_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la test_gnunet_daemon_hostlist_reconnect_SOURCES = \ test_gnunet_daemon_hostlist_reconnect.c test_gnunet_daemon_hostlist_reconnect_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la test_gnunet_daemon_hostlist_learning_SOURCES = \ test_gnunet_daemon_hostlist_learning.c test_gnunet_daemon_hostlist_learning_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ test_hostlist_defaults.conf \ test_gnunet_daemon_hostlist_data.conf \ test_gnunet_daemon_hostlist_peer1.conf \ test_gnunet_daemon_hostlist_peer2.conf \ test_learning_adv_peer.conf \ test_learning_learn_peer.conf \ test_learning_learn_peer2.conf \ learning_data.conf all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/hostlist/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/hostlist/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-daemon-hostlist$(EXEEXT): $(gnunet_daemon_hostlist_OBJECTS) $(gnunet_daemon_hostlist_DEPENDENCIES) @rm -f gnunet-daemon-hostlist$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_daemon_hostlist_OBJECTS) $(gnunet_daemon_hostlist_LDADD) $(LIBS) test_gnunet_daemon_hostlist$(EXEEXT): $(test_gnunet_daemon_hostlist_OBJECTS) $(test_gnunet_daemon_hostlist_DEPENDENCIES) @rm -f test_gnunet_daemon_hostlist$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gnunet_daemon_hostlist_OBJECTS) $(test_gnunet_daemon_hostlist_LDADD) $(LIBS) test_gnunet_daemon_hostlist_learning$(EXEEXT): $(test_gnunet_daemon_hostlist_learning_OBJECTS) $(test_gnunet_daemon_hostlist_learning_DEPENDENCIES) @rm -f test_gnunet_daemon_hostlist_learning$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gnunet_daemon_hostlist_learning_OBJECTS) $(test_gnunet_daemon_hostlist_learning_LDADD) $(LIBS) test_gnunet_daemon_hostlist_reconnect$(EXEEXT): $(test_gnunet_daemon_hostlist_reconnect_OBJECTS) $(test_gnunet_daemon_hostlist_reconnect_DEPENDENCIES) @rm -f test_gnunet_daemon_hostlist_reconnect$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gnunet_daemon_hostlist_reconnect_OBJECTS) $(test_gnunet_daemon_hostlist_reconnect_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet_daemon_hostlist-gnunet-daemon-hostlist.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet_daemon_hostlist-hostlist-client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet_daemon_hostlist-hostlist-server.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gnunet_daemon_hostlist.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gnunet_daemon_hostlist_learning.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gnunet_daemon_hostlist_reconnect.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< gnunet_daemon_hostlist-gnunet-daemon-hostlist.o: gnunet-daemon-hostlist.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gnunet_daemon_hostlist-gnunet-daemon-hostlist.o -MD -MP -MF $(DEPDIR)/gnunet_daemon_hostlist-gnunet-daemon-hostlist.Tpo -c -o gnunet_daemon_hostlist-gnunet-daemon-hostlist.o `test -f 'gnunet-daemon-hostlist.c' || echo '$(srcdir)/'`gnunet-daemon-hostlist.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnunet_daemon_hostlist-gnunet-daemon-hostlist.Tpo $(DEPDIR)/gnunet_daemon_hostlist-gnunet-daemon-hostlist.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gnunet-daemon-hostlist.c' object='gnunet_daemon_hostlist-gnunet-daemon-hostlist.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gnunet_daemon_hostlist-gnunet-daemon-hostlist.o `test -f 'gnunet-daemon-hostlist.c' || echo '$(srcdir)/'`gnunet-daemon-hostlist.c gnunet_daemon_hostlist-gnunet-daemon-hostlist.obj: gnunet-daemon-hostlist.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gnunet_daemon_hostlist-gnunet-daemon-hostlist.obj -MD -MP -MF $(DEPDIR)/gnunet_daemon_hostlist-gnunet-daemon-hostlist.Tpo -c -o gnunet_daemon_hostlist-gnunet-daemon-hostlist.obj `if test -f 'gnunet-daemon-hostlist.c'; then $(CYGPATH_W) 'gnunet-daemon-hostlist.c'; else $(CYGPATH_W) '$(srcdir)/gnunet-daemon-hostlist.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnunet_daemon_hostlist-gnunet-daemon-hostlist.Tpo $(DEPDIR)/gnunet_daemon_hostlist-gnunet-daemon-hostlist.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gnunet-daemon-hostlist.c' object='gnunet_daemon_hostlist-gnunet-daemon-hostlist.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gnunet_daemon_hostlist-gnunet-daemon-hostlist.obj `if test -f 'gnunet-daemon-hostlist.c'; then $(CYGPATH_W) 'gnunet-daemon-hostlist.c'; else $(CYGPATH_W) '$(srcdir)/gnunet-daemon-hostlist.c'; fi` gnunet_daemon_hostlist-hostlist-client.o: hostlist-client.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gnunet_daemon_hostlist-hostlist-client.o -MD -MP -MF $(DEPDIR)/gnunet_daemon_hostlist-hostlist-client.Tpo -c -o gnunet_daemon_hostlist-hostlist-client.o `test -f 'hostlist-client.c' || echo '$(srcdir)/'`hostlist-client.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnunet_daemon_hostlist-hostlist-client.Tpo $(DEPDIR)/gnunet_daemon_hostlist-hostlist-client.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='hostlist-client.c' object='gnunet_daemon_hostlist-hostlist-client.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gnunet_daemon_hostlist-hostlist-client.o `test -f 'hostlist-client.c' || echo '$(srcdir)/'`hostlist-client.c gnunet_daemon_hostlist-hostlist-client.obj: hostlist-client.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gnunet_daemon_hostlist-hostlist-client.obj -MD -MP -MF $(DEPDIR)/gnunet_daemon_hostlist-hostlist-client.Tpo -c -o gnunet_daemon_hostlist-hostlist-client.obj `if test -f 'hostlist-client.c'; then $(CYGPATH_W) 'hostlist-client.c'; else $(CYGPATH_W) '$(srcdir)/hostlist-client.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnunet_daemon_hostlist-hostlist-client.Tpo $(DEPDIR)/gnunet_daemon_hostlist-hostlist-client.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='hostlist-client.c' object='gnunet_daemon_hostlist-hostlist-client.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gnunet_daemon_hostlist-hostlist-client.obj `if test -f 'hostlist-client.c'; then $(CYGPATH_W) 'hostlist-client.c'; else $(CYGPATH_W) '$(srcdir)/hostlist-client.c'; fi` gnunet_daemon_hostlist-hostlist-server.o: hostlist-server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gnunet_daemon_hostlist-hostlist-server.o -MD -MP -MF $(DEPDIR)/gnunet_daemon_hostlist-hostlist-server.Tpo -c -o gnunet_daemon_hostlist-hostlist-server.o `test -f 'hostlist-server.c' || echo '$(srcdir)/'`hostlist-server.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnunet_daemon_hostlist-hostlist-server.Tpo $(DEPDIR)/gnunet_daemon_hostlist-hostlist-server.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='hostlist-server.c' object='gnunet_daemon_hostlist-hostlist-server.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gnunet_daemon_hostlist-hostlist-server.o `test -f 'hostlist-server.c' || echo '$(srcdir)/'`hostlist-server.c gnunet_daemon_hostlist-hostlist-server.obj: hostlist-server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gnunet_daemon_hostlist-hostlist-server.obj -MD -MP -MF $(DEPDIR)/gnunet_daemon_hostlist-hostlist-server.Tpo -c -o gnunet_daemon_hostlist-hostlist-server.obj `if test -f 'hostlist-server.c'; then $(CYGPATH_W) 'hostlist-server.c'; else $(CYGPATH_W) '$(srcdir)/hostlist-server.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnunet_daemon_hostlist-hostlist-server.Tpo $(DEPDIR)/gnunet_daemon_hostlist-hostlist-server.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='hostlist-server.c' object='gnunet_daemon_hostlist-hostlist-server.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnunet_daemon_hostlist_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gnunet_daemon_hostlist-hostlist-server.obj `if test -f 'hostlist-server.c'; then $(CYGPATH_W) 'hostlist-server.c'; else $(CYGPATH_W) '$(srcdir)/hostlist-server.c'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_pkgcfgDATA: $(dist_pkgcfg_DATA) @$(NORMAL_INSTALL) test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \ done uninstall-dist_pkgcfgDATA: @$(NORMAL_UNINSTALL) @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(PROGRAMS) $(DATA) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_pkgcfgDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-dist_pkgcfgDATA .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libtool ctags distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-binPROGRAMS install-data install-data-am \ install-dist_pkgcfgDATA install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-dist_pkgcfgDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/hostlist/test_gnunet_daemon_hostlist_learning.c0000644000175000017500000003673211762206213022255 00000000000000/* This file is part of GNUnet (C) 2009, 2010, 2011, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file hostlist/test_gnunet_daemon_hostlist_learning.c * @brief test for gnunet_daemon_hostslist.c * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_arm_service.h" #include "gnunet_core_service.h" #include "gnunet_transport_service.h" #include "gnunet_resolver_service.h" #include "gnunet_statistics_service.h" #define START_ARM GNUNET_YES #define MAX_URL_LEN 1000 /** * How long until wait until testcases fails */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 180) #define CHECK_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) struct PeerContext { struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_TRANSPORT_Handle *th; struct GNUNET_MessageHeader *hello; struct GNUNET_CORE_Handle *core; struct GNUNET_STATISTICS_Handle *stats; #if START_ARM struct GNUNET_OS_Process *arm_proc; #endif }; static int timeout; static int adv_sent; static int adv_arrived; static int learned_hostlist_saved; static int learned_hostlist_downloaded; static char *current_adv_uri; static const struct GNUNET_CONFIGURATION_Handle *cfg; static GNUNET_SCHEDULER_TaskIdentifier timeout_task; static GNUNET_SCHEDULER_TaskIdentifier check_task; static struct PeerContext adv_peer; static struct PeerContext learn_peer; static struct GNUNET_STATISTICS_GetHandle *download_stats; static struct GNUNET_STATISTICS_GetHandle *urisrecv_stat; static struct GNUNET_STATISTICS_GetHandle *advsent_stat; static void shutdown_testcase () { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown testcase....\n"); if (timeout_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (timeout_task); timeout_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != download_stats) { GNUNET_STATISTICS_get_cancel (download_stats); download_stats = NULL; } if (NULL != urisrecv_stat) { GNUNET_STATISTICS_get_cancel (urisrecv_stat); urisrecv_stat = NULL; } if (NULL != advsent_stat) { GNUNET_STATISTICS_get_cancel (advsent_stat); advsent_stat = NULL; } if (NULL != adv_peer.stats) { GNUNET_STATISTICS_destroy (adv_peer.stats, GNUNET_NO); adv_peer.stats = NULL; } if (NULL != learn_peer.stats) { GNUNET_STATISTICS_destroy (learn_peer.stats, GNUNET_NO); learn_peer.stats = NULL; } if (check_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (check_task); check_task = GNUNET_SCHEDULER_NO_TASK; } if (NULL != current_adv_uri) { GNUNET_free (current_adv_uri); current_adv_uri = NULL; } if (adv_peer.th != NULL) { GNUNET_TRANSPORT_disconnect (adv_peer.th); adv_peer.th = NULL; } if (learn_peer.th != NULL) { GNUNET_TRANSPORT_disconnect (learn_peer.th); learn_peer.th = NULL; } if (adv_peer.core != NULL) { GNUNET_CORE_disconnect (adv_peer.core); adv_peer.core = NULL; } if (learn_peer.core != NULL) { GNUNET_CORE_disconnect (learn_peer.core); learn_peer.core = NULL; } #if START_ARM GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Killing hostlist server ARM process.\n"); if (0 != GNUNET_OS_process_kill (adv_peer.arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (adv_peer.arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_OS_process_destroy (adv_peer.arm_proc); adv_peer.arm_proc = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Killing hostlist client ARM process.\n"); if (0 != GNUNET_OS_process_kill (learn_peer.arm_proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); if (GNUNET_OS_process_wait (learn_peer.arm_proc) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); GNUNET_OS_process_destroy (learn_peer.arm_proc); learn_peer.arm_proc = NULL; #endif GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown complete....\n"); } /** * Timeout, give up. */ static void timeout_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { timeout_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout while executing testcase, test failed.\n"); timeout = GNUNET_YES; shutdown_testcase (); } static void process_downloads_done (void *cls, int success) { download_stats = NULL; } static void do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { shutdown_testcase (); } static int process_downloads (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent) { if ((value >= 2) && (learned_hostlist_downloaded == GNUNET_NO)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer has successfully downloaded advertised URI\n"); learned_hostlist_downloaded = GNUNET_YES; if ((learned_hostlist_saved == GNUNET_YES) && (adv_sent == GNUNET_YES)) { GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); } } return GNUNET_OK; } static void process_uris_recv_done (void *cls, int success) { urisrecv_stat = NULL; } static int process_uris_recv (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent) { if (((struct PeerContext *) cls == &learn_peer) && (value == 1) && (learned_hostlist_saved == GNUNET_NO)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer has successfully saved advertised URI\n"); learned_hostlist_saved = GNUNET_YES; if ((learned_hostlist_downloaded == GNUNET_YES) && (adv_sent == GNUNET_YES)) { GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); } } return GNUNET_OK; } static void process_adv_sent_done (void *cls, int success) { advsent_stat = NULL; } static int process_adv_sent (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent) { if ((value >= 1) && (adv_sent == GNUNET_NO)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Server has successfully sent advertisement\n"); adv_sent = GNUNET_YES; if ((learned_hostlist_downloaded == GNUNET_YES) && (learned_hostlist_saved == GNUNET_YES)) { GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); } } return GNUNET_OK; } /** * Check the server statistics regularly */ static void check_statistics (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { char *stat; check_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; GNUNET_asprintf (&stat, gettext_noop ("# advertised URI `%s' downloaded"), current_adv_uri); if (NULL != learn_peer.stats) { if (NULL != download_stats) GNUNET_STATISTICS_get_cancel (download_stats); download_stats = GNUNET_STATISTICS_get (learn_peer.stats, "hostlist", stat, GNUNET_TIME_UNIT_MINUTES, &process_downloads_done, &process_downloads, &learn_peer); if (NULL != urisrecv_stat) GNUNET_STATISTICS_get_cancel (urisrecv_stat); urisrecv_stat = GNUNET_STATISTICS_get (learn_peer.stats, "hostlist", gettext_noop ("# advertised hostlist URIs"), GNUNET_TIME_UNIT_MINUTES, &process_uris_recv_done, &process_uris_recv, &learn_peer); } GNUNET_free (stat); if (NULL != adv_peer.stats) { if (NULL != advsent_stat) GNUNET_STATISTICS_get_cancel (advsent_stat); advsent_stat = GNUNET_STATISTICS_get (adv_peer.stats, "hostlist", gettext_noop ("# hostlist advertisements send"), GNUNET_TIME_UNIT_MINUTES, &process_adv_sent_done, &process_adv_sent, NULL); } check_task = GNUNET_SCHEDULER_add_delayed (CHECK_INTERVALL, &check_statistics, NULL); } /** * Core handler for p2p hostlist advertisements */ static int ad_arrive_handler (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_MessageHeader *message, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { char *hostname; char *expected_uri; unsigned long long port; const struct GNUNET_MessageHeader *incoming; const char *end; if (-1 == GNUNET_CONFIGURATION_get_value_number (adv_peer.cfg, "HOSTLIST", "HTTPPORT", &port)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not read advertising server's configuration\n"); return GNUNET_SYSERR; } if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (adv_peer.cfg, "HOSTLIST", "EXTERNAL_DNS_NAME", &hostname)) hostname = GNUNET_RESOLVER_local_fqdn_get (); GNUNET_asprintf (&expected_uri, "http://%s:%u/", hostname != NULL ? hostname : "localhost", (unsigned int) port); incoming = (const struct GNUNET_MessageHeader *) message; end = (const char *) &incoming[1]; if ('\0' != end[ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) - 1]) { GNUNET_break (0); GNUNET_free (expected_uri); GNUNET_free_non_null (hostname); return GNUNET_SYSERR; } current_adv_uri = GNUNET_strdup (end); if (0 == strcmp (expected_uri, current_adv_uri)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received hostlist advertisement with URI `%s' as expected\n", current_adv_uri); adv_arrived = GNUNET_YES; adv_sent = GNUNET_YES; } else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected URI `%s' and recieved URI `%s' differ\n", expected_uri, current_adv_uri); GNUNET_free (expected_uri); GNUNET_free_non_null (hostname); return GNUNET_OK; } /** * List of handlers if we are learning. */ static struct GNUNET_CORE_MessageHandler learn_handlers[] = { {&ad_arrive_handler, GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT, 0}, {NULL, 0, 0} }; static void setup_learn_peer (struct PeerContext *p, const char *cfgname) { char *filename; unsigned int result; p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (p->cfg, "HOSTLIST", "HOSTLISTFILE", &filename)) { if (GNUNET_YES == GNUNET_DISK_file_test (filename)) { result = UNLINK (filename); if (result == 0) GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Hostlist file `%s' was removed\n"), filename); } GNUNET_free (filename); } p->core = GNUNET_CORE_connect (p->cfg, 1, NULL, NULL, NULL, NULL, NULL, GNUNET_NO, NULL, GNUNET_NO, learn_handlers); GNUNET_assert (NULL != p->core); p->stats = GNUNET_STATISTICS_create ("hostlist", p->cfg); GNUNET_assert (NULL != p->stats); } static void setup_adv_peer (struct PeerContext *p, const char *cfgname) { p->cfg = GNUNET_CONFIGURATION_create (); #if START_ARM p->arm_proc = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm", "gnunet-service-arm", "-c", cfgname, NULL); #endif GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); p->stats = GNUNET_STATISTICS_create ("hostlist", p->cfg); GNUNET_assert (NULL != p->stats); } static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { timeout = GNUNET_NO; adv_sent = GNUNET_NO; adv_arrived = 0; learned_hostlist_saved = GNUNET_NO; learned_hostlist_downloaded = GNUNET_NO; cfg = c; setup_adv_peer (&adv_peer, "test_learning_adv_peer.conf"); setup_learn_peer (&learn_peer, "test_learning_learn_peer.conf"); timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_error, NULL); check_task = GNUNET_SCHEDULER_add_delayed (CHECK_INTERVALL, &check_statistics, NULL); } static int check () { unsigned int failed; char *const argv[] = { "test-gnunet-daemon-hostlist-learning", "-c", "learning_data.conf", NULL }; struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-gnunet-daemon-hostlist-learning", "nohelp", options, &run, NULL); failed = GNUNET_NO; if (timeout == GNUNET_YES) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Testcase timeout\n"); failed = GNUNET_YES; } if (adv_arrived != GNUNET_YES) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Learning peer did not receive advertisement from server\n"); failed = GNUNET_YES; } if (learned_hostlist_saved == GNUNET_NO) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Advertised hostlist was not saved in datastore\n"); failed = GNUNET_YES; } if (learned_hostlist_downloaded == GNUNET_NO) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Advertised hostlist could not be downloaded from server\n"); failed = GNUNET_YES; } if (adv_sent == GNUNET_NO) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Advertised was not sent from server to client\n"); failed = GNUNET_YES; } if (GNUNET_YES == failed) return GNUNET_YES; return GNUNET_NO; } int main (int argc, char *argv[]) { int ret; GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-1"); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-2"); GNUNET_log_setup ("test-gnunet-daemon-hostlist", "WARNING", NULL); #if !WINDOWS system ("gnunet-peerinfo -s -c test_learning_adv_peer.conf > /dev/null"); system ("gnunet-peerinfo -s -c test_learning_learn_peer.conf > /dev/null"); #else system ("gnunet-peerinfo -s -c test_learning_adv_peer.conf > NUL"); system ("gnunet-peerinfo -s -c test_learning_learn_peer.conf > NUL"); #endif ret = check (); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-1"); GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-2"); if (GNUNET_YES == GNUNET_DISK_file_test ("hostlists_learn_peer.file")) { if (0 == UNLINK ("hostlists_learn_peer.file")) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Hostlist file hostlists_learn_peer.file was removed\n"); } return ret; } /* end of test_gnunet_daemon_hostlist.c */ gnunet-0.9.3/src/hostlist/hostlist-client.h0000644000175000017500000000603311760502551015706 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file hostlist/hostlist-client.h * @brief hostlist support. Downloads HELLOs via HTTP. * @author Christian Grothoff */ #ifndef HOSTLIST_CLIENT_H #define HOSTLIST_CLIENT_H #include "gnunet_core_service.h" #include "gnunet_statistics_service.h" #include "gnunet_util_lib.h" #include "gnunet_time_lib.h" /** * Maximum number of hostlist that are saved */ #define MAX_NUMBER_HOSTLISTS 30 /** * Time intervall hostlists are saved to disk */ #define SAVING_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30) /** * Time interval between two hostlist tests */ #define TESTING_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3) /** * Time interval for download dispatcher before a download is re-scheduled */ #define WAITING_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) /** * Defines concerning the hostlist quality metric */ /** * Initial quality of a new created hostlist */ #define HOSTLIST_INITIAL 10000 /** * Value subtracted each time a hostlist download fails */ #define HOSTLIST_FAILED_DOWNLOAD 100 /** * Value added each time a hostlist download is successful */ #define HOSTLIST_SUCCESSFUL_DOWNLOAD 100 /** * Value added for each valid HELLO recived during a hostlist download */ #define HOSTLIST_SUCCESSFUL_HELLO 1 /** * Start downloading hostlists from hostlist servers as necessary. * * @param c the configuration to use * @param st hande for publishing statistics * @param ch set to handler for connect notifications * @param dh set to handler for disconnect notifications * @param msgh set to handler for message handler notifications * @param learn set if client is learning new hostlists * @return GNUNET_OK on success */ int GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_STATISTICS_Handle *st, GNUNET_CORE_ConnectEventHandler *ch, GNUNET_CORE_DisconnectEventHandler *dh, GNUNET_CORE_MessageCallback *msgh, int learn); /** * Stop downloading hostlists from hostlist servers as necessary. */ void GNUNET_HOSTLIST_client_stop (void); #endif /* end of hostlist-client.h */ gnunet-0.9.3/src/hostlist/hostlist-server.c0000644000175000017500000005310411760502551015732 00000000000000/* This file is part of GNUnet. (C) 2008, 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file hostlist/hostlist-server.c * @author Christian Grothoff, Matthias Wachs * @brief application to provide an integrated hostlist HTTP server */ #include "platform.h" #include #include "hostlist-server.h" #include "gnunet_hello_lib.h" #include "gnunet_peerinfo_service.h" #include "gnunet-daemon-hostlist.h" #include "gnunet_resolver_service.h" /** * Handle to the HTTP server as provided by libmicrohttpd for IPv6. */ static struct MHD_Daemon *daemon_handle_v6; /** * Handle to the HTTP server as provided by libmicrohttpd for IPv4. */ static struct MHD_Daemon *daemon_handle_v4; /** * Our configuration. */ static const struct GNUNET_CONFIGURATION_Handle *cfg; /** * For keeping statistics. */ static struct GNUNET_STATISTICS_Handle *stats; /** * Handle to the core service (NULL until we've connected to it). */ static struct GNUNET_CORE_Handle *core; /** * Handle to the peerinfo notify service (NULL until we've connected to it). */ static struct GNUNET_PEERINFO_NotifyContext *notify; /** * Our primary task for IPv4. */ static GNUNET_SCHEDULER_TaskIdentifier hostlist_task_v4; /** * Our primary task for IPv6. */ static GNUNET_SCHEDULER_TaskIdentifier hostlist_task_v6; /** * Our canonical response. */ static struct MHD_Response *response; /** * NULL if we are not currenlty iterating over peer information. */ static struct GNUNET_PEERINFO_IteratorContext *pitr; /** * Handle for accessing peerinfo service. */ static struct GNUNET_PEERINFO_Handle *peerinfo; /** * Set if we are allowed to advertise our hostlist to others. */ static int advertising; /** * Buffer for the hostlist address */ static char *hostlist_uri; /** * Context for host processor. */ struct HostSet { unsigned int size; char *data; }; /** * Function that assembles our response. */ static void finish_response (struct HostSet *results) { if (NULL != response) MHD_destroy_response (response); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating hostlist response with %u bytes\n", (unsigned int) results->size); response = MHD_create_response_from_data (results->size, results->data, MHD_YES, MHD_NO); if ((NULL == daemon_handle_v4) && (NULL == daemon_handle_v6)) { MHD_destroy_response (response); response = NULL; } GNUNET_STATISTICS_set (stats, gettext_noop ("bytes in hostlist"), results->size, GNUNET_YES); GNUNET_free (results); } /** * Set 'cls' to GNUNET_YES (we have an address!). * * @param cls closure, an 'int*' * @param address the address (ignored) * @param expiration expiration time (call is ignored if this is in the past) * @return GNUNET_SYSERR to stop iterating (unless expiration has occured) */ static int check_has_addr (void *cls, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration) { int *arg = cls; if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value == 0) { GNUNET_STATISTICS_update (stats, gettext_noop ("expired addresses encountered"), 1, GNUNET_YES); return GNUNET_YES; /* ignore this address */ } *arg = GNUNET_YES; return GNUNET_SYSERR; } /** * Callback that processes each of the known HELLOs for the * hostlist response construction. */ static void host_processor (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Message *hello, const char *err_msg) { struct HostSet *results = cls; size_t old; size_t s; int has_addr; if (NULL != err_msg) { GNUNET_assert (NULL == peer); pitr = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Error in communication with PEERINFO service: %s\n"), err_msg); return; } if (NULL == peer) { pitr = NULL; finish_response (results); return; } if (NULL == hello) return; has_addr = GNUNET_NO; GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &check_has_addr, &has_addr); if (GNUNET_NO == has_addr) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "HELLO for peer `%4s' has no address, not suitable for hostlist!\n", GNUNET_i2s (peer)); GNUNET_STATISTICS_update (stats, gettext_noop ("HELLOs without addresses encountered (ignored)"), 1, GNUNET_NO); return; } old = results->size; s = GNUNET_HELLO_size (hello); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received %u bytes of `%s' from peer `%s' for hostlist.\n", (unsigned int) s, "HELLO", GNUNET_i2s (peer)); if ((old + s >= GNUNET_MAX_MALLOC_CHECKED) || (old + s >= MAX_BYTES_PER_HOSTLISTS)) { GNUNET_STATISTICS_update (stats, gettext_noop ("bytes not included in hostlist (size limit)"), s, GNUNET_NO); return; /* too large, skip! */ } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Adding peer `%s' to hostlist (%u bytes)\n", GNUNET_i2s (peer), (unsigned int) s); GNUNET_array_grow (results->data, results->size, old + s); memcpy (&results->data[old], hello, s); } /** * Hostlist access policy (very permissive, allows everything). */ static int accept_policy_callback (void *cls, const struct sockaddr *addr, socklen_t addrlen) { if (NULL == response) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received request for hostlist, but I am not yet ready; rejecting!\n"); return MHD_NO; } return MHD_YES; /* accept all */ } /** * Main request handler. */ static int access_handler_callback (void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t * upload_data_size, void **con_cls) { static int dummy; if (0 != strcmp (method, MHD_HTTP_METHOD_GET)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Refusing `%s' request to hostlist server\n"), method); GNUNET_STATISTICS_update (stats, gettext_noop ("hostlist requests refused (not HTTP GET)"), 1, GNUNET_YES); return MHD_NO; } if (NULL == *con_cls) { (*con_cls) = &dummy; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Sending 100 CONTINUE reply\n")); return MHD_YES; /* send 100 continue */ } if (0 != *upload_data_size) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Refusing `%s' request with %llu bytes of upload data\n"), method, (unsigned long long) *upload_data_size); GNUNET_STATISTICS_update (stats, gettext_noop ("hostlist requests refused (upload data)"), 1, GNUNET_YES); return MHD_NO; /* do not support upload data */ } if (NULL == response) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not handle hostlist request since I do not have a response yet\n")); GNUNET_STATISTICS_update (stats, gettext_noop ("hostlist requests refused (not ready)"), 1, GNUNET_YES); return MHD_NO; /* internal error, no response yet */ } GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Received request for our hostlist\n")); GNUNET_STATISTICS_update (stats, gettext_noop ("hostlist requests processed"), 1, GNUNET_YES); return MHD_queue_response (connection, MHD_HTTP_OK, response); } /** * Handler called by core when core is ready to transmit message * @param cls closure * @param size size of buffer to copy message to * @param buf buffer to copy message to */ static size_t adv_transmit_ready (void *cls, size_t size, void *buf) { static uint64_t hostlist_adv_count; size_t transmission_size; size_t uri_size; /* Including \0 termination! */ struct GNUNET_MessageHeader header; char *cbuf; if (NULL == buf) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission failed, buffer invalid!\n"); return 0; } uri_size = strlen (hostlist_uri) + 1; transmission_size = sizeof (struct GNUNET_MessageHeader) + uri_size; header.type = htons (GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT); header.size = htons (transmission_size); GNUNET_assert (size >= transmission_size); memcpy (buf, &header, sizeof (struct GNUNET_MessageHeader)); cbuf = buf; memcpy (&cbuf[sizeof (struct GNUNET_MessageHeader)], hostlist_uri, uri_size); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent advertisement message: Copied %u bytes into buffer!\n", (unsigned int) transmission_size); hostlist_adv_count++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " # Sent advertisement message: %u\n", hostlist_adv_count); GNUNET_STATISTICS_update (stats, gettext_noop ("# hostlist advertisements send"), 1, GNUNET_NO); return transmission_size; } /** * Method called whenever a given peer connects. * * @param cls closure * @param peer peer identity this notification is about * @param atsi performance data * @param atsi_count number of records in 'atsi' */ static void connect_handler (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_ATS_Information *atsi, unsigned int atsi_count) { size_t size; if (!advertising) return; if (NULL == hostlist_uri) return; size = strlen (hostlist_uri) + 1; if (size + sizeof (struct GNUNET_MessageHeader) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); return; } size += sizeof (struct GNUNET_MessageHeader); if (NULL == core) { GNUNET_break (0); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asked core to transmit advertisement message with a size of %u bytes to peer `%s'\n", size, GNUNET_i2s (peer)); if (NULL == GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 0, GNUNET_ADV_TIMEOUT, peer, size, &adv_transmit_ready, NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Advertisement message could not be queued by core\n")); } } /** * Method called whenever a given peer disconnects. * * @param cls closure * @param peer peer identity this notification is about */ static void disconnect_handler (void *cls, const struct GNUNET_PeerIdentity *peer) { /* nothing to do */ } /** * PEERINFO calls this function to let us know about a possible peer * that we might want to connect to. * * @param cls closure (not used) * @param peer potential peer to connect to * @param hello HELLO for this peer (or NULL) * @param err_msg NULL if successful, otherwise contains error message */ static void process_notify (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Message *hello, const char *err_msg) { struct HostSet *results; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peerinfo is notifying us to rebuild our hostlist\n"); if (NULL != err_msg) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Error in communication with PEERINFO service: %s\n"), err_msg); if (NULL != pitr) return; /* re-build already in progress ... */ results = GNUNET_malloc (sizeof (struct HostSet)); GNUNET_assert (NULL != peerinfo); pitr = GNUNET_PEERINFO_iterate (peerinfo, NULL, GNUNET_TIME_UNIT_MINUTES, &host_processor, results); } /** * Function that queries MHD's select sets and * starts the task waiting for them. */ static GNUNET_SCHEDULER_TaskIdentifier prepare_daemon (struct MHD_Daemon *daemon_handle); /** * Call MHD to process pending requests and then go back * and schedule the next run. */ static void run_daemon (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct MHD_Daemon *daemon_handle = cls; if (daemon_handle == daemon_handle_v4) hostlist_task_v4 = GNUNET_SCHEDULER_NO_TASK; else hostlist_task_v6 = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; GNUNET_assert (MHD_YES == MHD_run (daemon_handle)); if (daemon_handle == daemon_handle_v4) hostlist_task_v4 = prepare_daemon (daemon_handle); else hostlist_task_v6 = prepare_daemon (daemon_handle); } /** * Function that queries MHD's select sets and * starts the task waiting for them. */ static GNUNET_SCHEDULER_TaskIdentifier prepare_daemon (struct MHD_Daemon *daemon_handle) { GNUNET_SCHEDULER_TaskIdentifier ret; fd_set rs; fd_set ws; fd_set es; struct GNUNET_NETWORK_FDSet *wrs; struct GNUNET_NETWORK_FDSet *wws; struct GNUNET_NETWORK_FDSet *wes; int max; unsigned MHD_LONG_LONG timeout; int haveto; struct GNUNET_TIME_Relative tv; FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es); wrs = GNUNET_NETWORK_fdset_create (); wes = GNUNET_NETWORK_fdset_create (); wws = GNUNET_NETWORK_fdset_create (); max = -1; GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max)); haveto = MHD_get_timeout (daemon_handle, &timeout); if (haveto == MHD_YES) tv.rel_value = (uint64_t) timeout; else tv = GNUNET_TIME_UNIT_FOREVER_REL; GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1); ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, tv, wrs, wws, &run_daemon, daemon_handle); GNUNET_NETWORK_fdset_destroy (wrs); GNUNET_NETWORK_fdset_destroy (wws); GNUNET_NETWORK_fdset_destroy (wes); return ret; } /** * Start server offering our hostlist. * * @return GNUNET_OK on success */ int GNUNET_HOSTLIST_server_start (const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_STATISTICS_Handle *st, struct GNUNET_CORE_Handle *co, GNUNET_CORE_ConnectEventHandler *server_ch, GNUNET_CORE_DisconnectEventHandler *server_dh, int advertise) { unsigned long long port; char *hostname; char *ip; size_t size; struct in_addr i4; struct in6_addr i6; struct sockaddr_in v4; struct sockaddr_in6 v6; const struct sockaddr *sa; advertising = advertise; if (!advertising) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Advertising not enabled on this hostlist server\n"); else GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Advertising enabled on this hostlist server\n"); cfg = c; stats = st; peerinfo = GNUNET_PEERINFO_connect (cfg); if (NULL == peerinfo) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not access PEERINFO service. Exiting.\n")); return GNUNET_SYSERR; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "HOSTLIST", "HTTPPORT", &port)) return GNUNET_SYSERR; if ((0 == port) || (port > UINT16_MAX)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Invalid port number %llu. Exiting.\n"), port); return GNUNET_SYSERR; } if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "HOSTLIST", "EXTERNAL_DNS_NAME", &hostname)) hostname = GNUNET_RESOLVER_local_fqdn_get (); GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Hostlist service starts on %s:%llu\n"), hostname, port); if (NULL != hostname) { size = strlen (hostname); if (size + 15 > MAX_URL_LEN) { GNUNET_break (0); } else { GNUNET_asprintf (&hostlist_uri, "http://%s:%u/", hostname, (unsigned int) port); GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Address to obtain hostlist: `%s'\n"), hostlist_uri); } GNUNET_free (hostname); } if (GNUNET_CONFIGURATION_have_value (cfg, "HOSTLIST", "BINDTOIP")) { GNUNET_break (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, "HOSTLIST", "BINDTOIP", &ip)); } else ip = NULL; if (NULL != ip) { if (1 == inet_pton (AF_INET, ip, &i4)) { memset (&v4, 0, sizeof (v4)); v4.sin_family = AF_INET; v4.sin_addr = i4; v4.sin_port = htons (port); #if HAVE_SOCKADDR_IN_SIN_LEN v4.sin_len = sizeof (v4); #endif sa = (const struct sockaddr *) &v4; } else if (1 == inet_pton (AF_INET6, ip, &i6)) { memset (&v6, 0, sizeof (v6)); v6.sin6_family = AF_INET6; v6.sin6_addr = i6; v6.sin6_port = htons (port); #if HAVE_SOCKADDR_IN_SIN_LEN v6.sin6_len = sizeof (v6); #endif sa = (const struct sockaddr *) &v6; } else { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("`%s' is not a valid IP address! Ignoring BINDTOIP.\n"), ip); sa = NULL; } } else sa = NULL; daemon_handle_v6 = MHD_start_daemon (MHD_USE_IPv6 | MHD_USE_DEBUG, (uint16_t) port, &accept_policy_callback, NULL, &access_handler_callback, NULL, MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 16, MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1, MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16, MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024), MHD_OPTION_SOCK_ADDR, sa, MHD_OPTION_END); daemon_handle_v4 = MHD_start_daemon (MHD_NO_FLAG | MHD_USE_DEBUG, (uint16_t) port, &accept_policy_callback, NULL, &access_handler_callback, NULL, MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 16, MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1, MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16, MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024), MHD_OPTION_SOCK_ADDR, sa, MHD_OPTION_END); if ((NULL == daemon_handle_v6) && (NULL == daemon_handle_v4)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not start hostlist HTTP server on port %u\n"), (unsigned short) port); return GNUNET_SYSERR; } core = co; *server_ch = &connect_handler; *server_dh = &disconnect_handler; if (daemon_handle_v4 != NULL) hostlist_task_v4 = prepare_daemon (daemon_handle_v4); if (daemon_handle_v6 != NULL) hostlist_task_v6 = prepare_daemon (daemon_handle_v6); notify = GNUNET_PEERINFO_notify (cfg, &process_notify, NULL); return GNUNET_OK; } /** * Stop server offering our hostlist. */ void GNUNET_HOSTLIST_server_stop () { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist server shutdown\n"); if (GNUNET_SCHEDULER_NO_TASK != hostlist_task_v6) { GNUNET_SCHEDULER_cancel (hostlist_task_v6); hostlist_task_v6 = GNUNET_SCHEDULER_NO_TASK; } if (GNUNET_SCHEDULER_NO_TASK != hostlist_task_v4) { GNUNET_SCHEDULER_cancel (hostlist_task_v4); hostlist_task_v4 = GNUNET_SCHEDULER_NO_TASK; } if (NULL != daemon_handle_v4) { MHD_stop_daemon (daemon_handle_v4); daemon_handle_v4 = NULL; } if (NULL != daemon_handle_v6) { MHD_stop_daemon (daemon_handle_v6); daemon_handle_v6 = NULL; } if (NULL != response) { MHD_destroy_response (response); response = NULL; } if (NULL != notify) { GNUNET_PEERINFO_notify_cancel (notify); notify = NULL; } if (NULL != pitr) { GNUNET_PEERINFO_iterate_cancel (pitr); pitr = NULL; } if (NULL != peerinfo) { GNUNET_PEERINFO_disconnect (peerinfo); peerinfo = NULL; } cfg = NULL; stats = NULL; core = NULL; } /* end of hostlist-server.c */ gnunet-0.9.3/src/include/0000755000175000017500000000000011763406747012255 500000000000000gnunet-0.9.3/src/include/gnunet_service_lib.h0000644000175000017500000001225711760502551016206 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_service_lib.h * @brief functions related to starting services * @author Christian Grothoff */ #ifndef GNUNET_SERVICE_LIB_H #define GNUNET_SERVICE_LIB_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_configuration_lib.h" #include "gnunet_server_lib.h" /** * Get the list of addresses that a server for the given service * should bind to. * * @param service_name name of the service * @param cfg configuration (which specifies the addresses) * @param addrs set (call by reference) to an array of pointers to the * addresses the server should bind to and listen on; the * array will be NULL-terminated (on success) * @param addr_lens set (call by reference) to an array of the lengths * of the respective 'struct sockaddr' struct in the 'addrs' * array (on success) * @return number of addresses found on success, * GNUNET_SYSERR if the configuration * did not specify reasonable finding information or * if it specified a hostname that could not be resolved; * GNUNET_NO if the number of addresses configured is * zero (in this case, '*addrs' and '*addr_lens' will be * set to NULL). */ int GNUNET_SERVICE_get_server_addresses (const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg, struct sockaddr ***addrs, socklen_t ** addr_lens); /** * Function called by the service's run * method to run service-specific setup code. * * @param cls closure * @param server the initialized server * @param cfg configuration to use */ typedef void (*GNUNET_SERVICE_Main) (void *cls, struct GNUNET_SERVER_Handle * server, const struct GNUNET_CONFIGURATION_Handle * cfg); /** * Options for the service (bitmask). */ enum GNUNET_SERVICE_Options { /** * Use defaults. */ GNUNET_SERVICE_OPTION_NONE = 0, /** * Do not trigger server shutdown on signals, allow for the user * to terminate the server explicitly when needed. */ GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN = 1, /** * Trigger a SOFT server shutdown on signals, allowing active * non-monitor clients to complete their transactions. */ GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN = 2 }; /** * Run a standard GNUnet service startup sequence (initialize loggers * and configuration, parse options). * * @param argc number of command line arguments * @param argv command line arguments * @param service_name our service name * @param options service options * @param task main task of the service * @param task_cls closure for task * @return GNUNET_SYSERR on error, GNUNET_OK * if we shutdown nicely */ int GNUNET_SERVICE_run (int argc, char *const *argv, const char *service_name, enum GNUNET_SERVICE_Options options, GNUNET_SERVICE_Main task, void *task_cls); /** * Opaque handle for a service. */ struct GNUNET_SERVICE_Context; /** * Run a service startup sequence within an existing * initialized system. * * @param service_name our service name * @param cfg configuration to use * @param options service options * @return NULL on error, service handle */ struct GNUNET_SERVICE_Context * GNUNET_SERVICE_start (const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg, enum GNUNET_SERVICE_Options options); /** * Obtain the server used by a service. Note that the server must NOT * be destroyed by the caller. * * @param ctx the service context returned from the start function * @return handle to the server for this service, NULL if there is none */ struct GNUNET_SERVER_Handle * GNUNET_SERVICE_get_server (struct GNUNET_SERVICE_Context *ctx); /** * Stop a service that was started with "GNUNET_SERVICE_start". * * @param sctx the service context returned from the start function */ void GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Context *sctx); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_SERVICE_LIB_H */ #endif /* end of gnunet_service_lib.h */ gnunet-0.9.3/src/include/gnunet_arm_service.h0000644000175000017500000001406411760502551016215 00000000000000/* This file is part of GNUnet (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_arm_service.h * @brief API to access gnunet-arm * @author Christian Grothoff */ #ifndef GNUNET_ARM_SERVICE_H #define GNUNET_ARM_SERVICE_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_configuration_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" /** * Version of the arm API. */ #define GNUNET_ARM_VERSION 0x00000001 /** * Values characterizing GNUnet process states. */ enum GNUNET_ARM_ProcessStatus { /** * Service name is unknown to ARM. */ GNUNET_ARM_PROCESS_UNKNOWN = -1, /** * Service is now down (due to client request). */ GNUNET_ARM_PROCESS_DOWN = 0, /** * Service is already running. */ GNUNET_ARM_PROCESS_ALREADY_RUNNING = 1, /** * Service is currently being started (due to client request). */ GNUNET_ARM_PROCESS_STARTING = 2, /** * Service is already being stopped by some other client. */ GNUNET_ARM_PROCESS_ALREADY_STOPPING = 3, /** * Service is already down (no action taken) */ GNUNET_ARM_PROCESS_ALREADY_DOWN = 4, /** * ARM is currently being shut down (no more process starts) */ GNUNET_ARM_PROCESS_SHUTDOWN = 5, /** * Error in communication with ARM */ GNUNET_ARM_PROCESS_COMMUNICATION_ERROR = 6, /** * Timeout in communication with ARM */ GNUNET_ARM_PROCESS_COMMUNICATION_TIMEOUT = 7, /** * Failure to perform operation */ GNUNET_ARM_PROCESS_FAILURE = 8 }; /** * Callback function invoked when operation is complete. * * @param cls closure * @param result outcome of the operation */ typedef void (*GNUNET_ARM_Callback) (void *cls, enum GNUNET_ARM_ProcessStatus result); /** * Callback function invoked when list operation is complete. * * @param cls closure * @param result outcome of the operation (GNUNET_YES if successful) * @param count number of strings in the list * @param list list of running services */ typedef void (*GNUNET_ARM_List_Callback) (void *cls, int result, unsigned int count, const char *const *list); /** * Handle for interacting with ARM. */ struct GNUNET_ARM_Handle; /** * Setup a context for communicating with ARM. Note that this * can be done even if the ARM service is not yet running. * * @param cfg configuration to use (needed to contact ARM; * the ARM service may internally use a different * configuration to determine how to start the service). * @param service service that *this* process is implementing/providing, can be NULL * @return context to use for further ARM operations, NULL on error */ struct GNUNET_ARM_Handle * GNUNET_ARM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *service); /** * Disconnect from the ARM service. * * @param h the handle that was being used */ void GNUNET_ARM_disconnect (struct GNUNET_ARM_Handle *h); /** * Start a service. Note that this function merely asks ARM to start * the service and that ARM merely confirms that it forked the * respective process. The specified callback may thus return before * the service has started to listen on the server socket and it may * also be that the service has crashed in the meantime. Clients * should repeatedly try to connect to the service at the respective * port (with some delays in between) before assuming that the service * actually failed to start. Note that if an error is returned to the * callback, clients obviously should not bother with trying to * contact the service. * * @param h handle to ARM * @param service_name name of the service * @param timeout how long to wait before failing for good * @param cb callback to invoke when service is ready * @param cb_cls closure for callback */ void GNUNET_ARM_start_service (struct GNUNET_ARM_Handle *h, const char *service_name, struct GNUNET_TIME_Relative timeout, GNUNET_ARM_Callback cb, void *cb_cls); /** * Stop a service. Note that the callback is invoked as soon * as ARM confirms that it will ask the service to terminate. * The actual termination may still take some time. * * @param h handle to ARM * @param service_name name of the service * @param timeout how long to wait before failing for good * @param cb callback to invoke when service is ready * @param cb_cls closure for callback */ void GNUNET_ARM_stop_service (struct GNUNET_ARM_Handle *h, const char *service_name, struct GNUNET_TIME_Relative timeout, GNUNET_ARM_Callback cb, void *cb_cls); /** * List all running services. * * @param h handle to ARM * @param timeout how long to wait before failing for good * @param cb callback to invoke when service is ready * @param cb_cls closure for callback */ void GNUNET_ARM_list_running_services (struct GNUNET_ARM_Handle *h, struct GNUNET_TIME_Relative timeout, GNUNET_ARM_List_Callback cb, void *cb_cls); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif #endif gnunet-0.9.3/src/include/gnunet_peerinfo_service.h0000644000175000017500000001534511760502551017250 00000000000000/* This file is part of GNUnet (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_peerinfo_service.h * @brief Code to maintain the list of currently known hosts * (in memory structure of data/hosts). * @author Christian Grothoff */ #ifndef GNUNET_PEERINFO_SERVICE_H #define GNUNET_PEERINFO_SERVICE_H #include "gnunet_common.h" #include "gnunet_configuration_lib.h" #include "gnunet_crypto_lib.h" #include "gnunet_hello_lib.h" #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * Handle to the peerinfo service. */ struct GNUNET_PEERINFO_Handle; /** * Connect to the peerinfo service. * * @param cfg configuration to use * @return NULL on error (configuration related, actual connection * etablishment may happen asynchronously). */ struct GNUNET_PEERINFO_Handle * GNUNET_PEERINFO_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); /** * Disconnect from the peerinfo service. Note that all iterators must * have completed or have been cancelled by the time this function is * called (otherwise, calling this function is a serious error). * Furthermore, if 'GNUNET_PEERINFO_add_peer' operations are still * pending, they will be cancelled silently on disconnect. * * @param h handle to disconnect */ void GNUNET_PEERINFO_disconnect (struct GNUNET_PEERINFO_Handle *h); /** * Continuation called with a status result. * * @param cls closure * @param emsg error message, NULL on success */ typedef void (*GNUNET_PEERINFO_Continuation)(void *cls, const char *emsg); /** * Opaque handle to cancel 'add' operation. */ struct GNUNET_PEERINFO_AddContext; /** * Add a host to the persistent list. This method operates in * semi-reliable mode: if the transmission is not completed by * the time 'GNUNET_PEERINFO_disconnect' is called, it will be * aborted. Furthermore, if a second HELLO is added for the * same peer before the first one was transmitted, PEERINFO may * merge the two HELLOs prior to transmission to the service. * * @param h handle to the peerinfo service * @param hello the verified (!) HELLO message * @param cont continuation to call when done, NULL is allowed * @param cont_cls closure for 'cont' * @return handle to cancel add operation; all pending * 'add' operations will be cancelled automatically * on disconnect, so it is not necessary to keep this * handle (unless 'cont' is NULL and at some point * calling 'cont' must be prevented) */ struct GNUNET_PEERINFO_AddContext * GNUNET_PEERINFO_add_peer (struct GNUNET_PEERINFO_Handle *h, const struct GNUNET_HELLO_Message *hello, GNUNET_PEERINFO_Continuation cont, void *cont_cls); /** * Cancel pending 'add' operation. Must only be called before * either 'cont' or 'GNUNET_PEERINFO_disconnect' are invoked. * * @param ac handle for the add operation to cancel */ void GNUNET_PEERINFO_add_peer_cancel (struct GNUNET_PEERINFO_AddContext *ac); /** * Type of an iterator over the hosts. Note that each * host will be called with each available protocol. * * @param cls closure * @param peer id of the peer, NULL for last call * @param hello hello message for the peer (can be NULL) * @param error message */ typedef void (*GNUNET_PEERINFO_Processor) (void *cls, const struct GNUNET_PeerIdentity * peer, const struct GNUNET_HELLO_Message * hello, const char *err_msg); /** * Handle for cancellation of iteration over peers. */ struct GNUNET_PEERINFO_IteratorContext; /** * Call a method for each known matching host to get its HELLO. * The callback method will be invoked once for each matching * host and then finally once with a NULL pointer. After that final * invocation, the iterator context must no longer be used. * * Instead of calling this function with 'peer == NULL' * it is often better to use 'GNUNET_PEERINFO_notify'. * * @param h handle to the peerinfo service * @param peer restrict iteration to this peer only (can be NULL) * @param timeout how long to wait until timing out * @param callback the method to call for each peer * @param callback_cls closure for callback * @return NULL on error (in this case, 'callback' is never called!), * otherwise an iterator context */ struct GNUNET_PEERINFO_IteratorContext * GNUNET_PEERINFO_iterate (struct GNUNET_PEERINFO_Handle *h, const struct GNUNET_PeerIdentity *peer, struct GNUNET_TIME_Relative timeout, GNUNET_PEERINFO_Processor callback, void *callback_cls); /** * Cancel an iteration over peer information. * * @param ic context of the iterator to cancel */ void GNUNET_PEERINFO_iterate_cancel (struct GNUNET_PEERINFO_IteratorContext *ic); /** * Handle for notifications about changes to the set of known peers. */ struct GNUNET_PEERINFO_NotifyContext; /** * Call a method whenever our known information about peers * changes. Initially calls the given function for all known * peers and then only signals changes. Note that it is * possible (i.e. on disconnects) that the callback is called * twice with the same peer information. * * @param cfg configuration to use * @param callback the method to call for each peer * @param callback_cls closure for callback * @return NULL on error */ struct GNUNET_PEERINFO_NotifyContext * GNUNET_PEERINFO_notify (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_PEERINFO_Processor callback, void *callback_cls); /** * Stop notifying about changes. * * @param nc context to stop notifying */ void GNUNET_PEERINFO_notify_cancel (struct GNUNET_PEERINFO_NotifyContext *nc); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* end of gnunet_peerinfo_service.h */ #endif gnunet-0.9.3/src/include/gnunet_block_lib.h0000644000175000017500000001556311760502551015643 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_block_lib.h * @brief library for data block manipulation * @author Christian Grothoff */ #ifndef GNUNET_BLOCK_LIB_H #define GNUNET_BLOCK_LIB_H #include "gnunet_util_lib.h" #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * Blocks in the datastore and the datacache must have a unique type. */ enum GNUNET_BLOCK_Type { /** * Any type of block, used as a wildcard when searching. Should * never be attached to a specific block. */ GNUNET_BLOCK_TYPE_ANY = 0, /** * Data block (leaf) in the CHK tree. */ GNUNET_BLOCK_TYPE_FS_DBLOCK = 1, /** * Inner block in the CHK tree. */ GNUNET_BLOCK_TYPE_FS_IBLOCK = 2, /** * Type of a block representing a keyword search result. Note that * the values for KBLOCK, SBLOCK and NBLOCK must be consecutive. */ GNUNET_BLOCK_TYPE_FS_KBLOCK = 3, /** * Type of a block that is used to advertise content in a namespace. */ GNUNET_BLOCK_TYPE_FS_SBLOCK = 4, /** * Type of a block that is used to advertise a namespace. */ GNUNET_BLOCK_TYPE_FS_NBLOCK = 5, /** * Type of a block representing a block to be encoded on demand from disk. * Should never appear on the network directly. */ GNUNET_BLOCK_TYPE_FS_ONDEMAND = 6, /** * Type of a block that contains a HELLO for a peer (for * DHT find-peer operations). */ GNUNET_BLOCK_TYPE_DHT_HELLO = 7, /** * Block for testing. */ GNUNET_BLOCK_TYPE_TEST = 8, /** * Block for storing .gnunet-domains */ GNUNET_BLOCK_TYPE_DNS = 10, /** * Block for storing record data */ GNUNET_BLOCK_TYPE_GNS_NAMERECORD = 11 }; /** * Possible ways for how a block may relate to a query. */ enum GNUNET_BLOCK_EvaluationResult { /** * Valid result, and there may be more. */ GNUNET_BLOCK_EVALUATION_OK_MORE = 0, /** * Last possible valid result. */ GNUNET_BLOCK_EVALUATION_OK_LAST = 1, /** * Valid result, but suppressed because it is a duplicate. */ GNUNET_BLOCK_EVALUATION_OK_DUPLICATE = 2, /** * Block does not match query (invalid result) */ GNUNET_BLOCK_EVALUATION_RESULT_INVALID = 3, /** * Query is valid, no reply given. */ GNUNET_BLOCK_EVALUATION_REQUEST_VALID = 4, /** * Query format does not match block type (invalid query). For * example, xquery not given or xquery_size not appropriate for * type. */ GNUNET_BLOCK_EVALUATION_REQUEST_INVALID = 5, /** * Specified block type not supported by this plugin. */ GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED = 6 }; /** * Handle to an initialized block library. */ struct GNUNET_BLOCK_Context; /** * Mingle hash with the mingle_number to produce different bits. * * @param in original hash code * @param mingle_number number for hash permutation * @param hc where to store the result. */ void GNUNET_BLOCK_mingle_hash (const GNUNET_HashCode * in, uint32_t mingle_number, GNUNET_HashCode * hc); /** * Create a block context. Loads the block plugins. * * @param cfg configuration to use * @return NULL on error */ struct GNUNET_BLOCK_Context * GNUNET_BLOCK_context_create (const struct GNUNET_CONFIGURATION_Handle *cfg); /** * Destroy the block context. * * @param ctx context to destroy */ void GNUNET_BLOCK_context_destroy (struct GNUNET_BLOCK_Context *ctx); /** * Function called to validate a reply or a request. For * request evaluation, simply pass "NULL" for the reply_block. * Note that it is assumed that the reply has already been * matched to the key (and signatures checked) as it would * be done with the "get_key" function. * * @param ctx block contxt * @param type block type * @param query original query (hash) * @param bf pointer to bloom filter associated with query; possibly updated (!) * @param bf_mutator mutation value for bf * @param xquery extrended query data (can be NULL, depending on type) * @param xquery_size number of bytes in xquery * @param reply_block response to validate * @param reply_block_size number of bytes in reply block * @return characterization of result */ enum GNUNET_BLOCK_EvaluationResult GNUNET_BLOCK_evaluate (struct GNUNET_BLOCK_Context *ctx, enum GNUNET_BLOCK_Type type, const GNUNET_HashCode * query, struct GNUNET_CONTAINER_BloomFilter **bf, int32_t bf_mutator, const void *xquery, size_t xquery_size, const void *reply_block, size_t reply_block_size); /** * Function called to obtain the key for a block. * * @param ctx block context * @param type block type * @param block block to get the key for * @param block_size number of bytes in block * @param key set to the key (query) for the given block * @return GNUNET_YES on success, * GNUNET_NO if the block is malformed * GNUNET_SYSERR if type not supported * (or if extracting a key from a block of this type does not work) */ int GNUNET_BLOCK_get_key (struct GNUNET_BLOCK_Context *ctx, enum GNUNET_BLOCK_Type type, const void *block, size_t block_size, GNUNET_HashCode * key); /** * Construct a bloom filter that would filter out the given * results. * * @param bf_mutator mutation value to use * @param seen_results results already seen * @param seen_results_count number of entries in 'seen_results' * @return NULL if seen_results_count is 0, otherwise a BF * that would match the given results. */ struct GNUNET_CONTAINER_BloomFilter * GNUNET_BLOCK_construct_bloomfilter (int32_t bf_mutator, const GNUNET_HashCode * seen_results, unsigned int seen_results_count); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_BLOCK_LIB_H */ #endif /* end of gnunet_block_lib.h */ gnunet-0.9.3/src/include/gnunet_resolver_service.h0000644000175000017500000001203711760502551017275 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_resolver_service.h * @brief functions related to doing DNS lookups * @author Christian Grothoff */ #ifndef GNUNET_RESOLVER_SERVICE_H #define GNUNET_RESOLVER_SERVICE_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_configuration_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" /** * Function called by the resolver for each address obtained from DNS. * * @param cls closure * @param addr one of the addresses of the host, NULL for the last address * @param addrlen length of the address */ typedef void (*GNUNET_RESOLVER_AddressCallback) (void *cls, const struct sockaddr * addr, socklen_t addrlen); /** * Handle to a request given to the resolver. Can be used to cancel * the request prior to the timeout or successful execution. */ struct GNUNET_RESOLVER_RequestHandle; /** * Create the connection to the resolver service. * * @param cfg configuration to use */ void GNUNET_RESOLVER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); /** * Destroy the connection to the resolver service. */ void GNUNET_RESOLVER_disconnect (void); /** * Convert a string to one or more IP addresses. * * @param hostname the hostname to resolve * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any" * @param callback function to call with addresses * @param callback_cls closure for callback * @param timeout how long to try resolving * @return handle that can be used to cancel the request, NULL on error */ struct GNUNET_RESOLVER_RequestHandle * GNUNET_RESOLVER_ip_get (const char *hostname, int af, struct GNUNET_TIME_Relative timeout, GNUNET_RESOLVER_AddressCallback callback, void *callback_cls); /** * Resolve our hostname to an IP address. * * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any" * @param callback function to call with addresses * @param cls closure for callback * @param timeout how long to try resolving * @return handle that can be used to cancel the request, NULL on error */ struct GNUNET_RESOLVER_RequestHandle * GNUNET_RESOLVER_hostname_resolve (int af, struct GNUNET_TIME_Relative timeout, GNUNET_RESOLVER_AddressCallback callback, void *cls); /** * Function called by the resolver for each hostname obtained from DNS. * * @param cls closure * @param hostname one of the names for the host, NULL * on the last call to the callback */ typedef void (*GNUNET_RESOLVER_HostnameCallback) (void *cls, const char *hostname); /** * Get local fully qualified domain name * * @return local hostname, caller must free */ char * GNUNET_RESOLVER_local_fqdn_get (void); /** * Perform a reverse DNS lookup. * * @param sa host address * @param salen length of host address * @param do_resolve use GNUNET_NO to return numeric hostname * @param timeout how long to try resolving * @param callback function to call with hostnames * @param cls closure for callback * @return handle that can be used to cancel the request, NULL on error */ struct GNUNET_RESOLVER_RequestHandle * GNUNET_RESOLVER_hostname_get (const struct sockaddr *sa, socklen_t salen, int do_resolve, struct GNUNET_TIME_Relative timeout, GNUNET_RESOLVER_HostnameCallback callback, void *cls); /** * Cancel a request that is still pending with the resolver. * Note that a client MUST NOT cancel a request that has * been completed (i.e, the callback has been called to * signal timeout or the final result). * * @param rh handle of request to cancel */ void GNUNET_RESOLVER_request_cancel (struct GNUNET_RESOLVER_RequestHandle *rh); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_RESOLVER_SERVICE_H */ #endif /* end of gnunet_resolver_service.h */ gnunet-0.9.3/src/include/gnunet_server_lib.h0000644000175000017500000005735011760502551016057 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_server_lib.h * @brief library for building GNUnet network servers * * @author Christian Grothoff */ #ifndef GNUNET_SERVER_LIB_H #define GNUNET_SERVER_LIB_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_common.h" #include "gnunet_connection_lib.h" /** * Largest supported message. */ #define GNUNET_SERVER_MAX_MESSAGE_SIZE 65536 /** * Smallest supported message. */ #define GNUNET_SERVER_MIN_BUFFER_SIZE sizeof (struct GNUNET_MessageHeader) /** * @brief handle for a server */ struct GNUNET_SERVER_Handle; /** * @brief opaque handle for a client of the server */ struct GNUNET_SERVER_Client; /** * @brief opaque handle server returns for aborting transmission to a client. */ struct GNUNET_SERVER_TransmitHandle; /** * Functions with this signature are called whenever a message is * received. * * @param cls closure * @param client identification of the client * @param message the actual message */ typedef void (*GNUNET_SERVER_MessageCallback) (void *cls, struct GNUNET_SERVER_Client * client, const struct GNUNET_MessageHeader * message); /** * Message handler. Each struct specifies how to handle on particular * type of message received. */ struct GNUNET_SERVER_MessageHandler { /** * Function to call for messages of "type". */ GNUNET_SERVER_MessageCallback callback; /** * Closure argument for "callback". */ void *callback_cls; /** * Type of the message this handler covers. */ uint16_t type; /** * Expected size of messages of this type. Use 0 for * variable-size. If non-zero, messages of the given * type will be discarded (and the connection closed) * if they do not have the right size. */ uint16_t expected_size; }; /** * Create a new server. * * @param access function for access control * @param access_cls closure for access * @param lsocks NULL-terminated array of listen sockets * @param idle_timeout after how long should we timeout idle connections? * @param require_found if YES, connections sending messages of unknown type * will be closed * @return handle for the new server, NULL on error * (typically, "port" already in use) */ struct GNUNET_SERVER_Handle * GNUNET_SERVER_create_with_sockets (GNUNET_CONNECTION_AccessCheck access, void *access_cls, struct GNUNET_NETWORK_Handle **lsocks, struct GNUNET_TIME_Relative idle_timeout, int require_found); /** * Create a new server. * * @param access function for access control * @param access_cls closure for access * @param serverAddr address toes listen on (including port), NULL terminated array * @param socklen lengths of respective serverAddr * @param idle_timeout after how long should we timeout idle connections? * @param require_found if YES, connections sending messages of unknown type * will be closed * @return handle for the new server, NULL on error * (typically, "port" already in use) */ struct GNUNET_SERVER_Handle * GNUNET_SERVER_create (GNUNET_CONNECTION_AccessCheck access, void *access_cls, struct sockaddr *const *serverAddr, const socklen_t * socklen, struct GNUNET_TIME_Relative idle_timeout, int require_found); /** * Stop the listen socket and get ready to shutdown the server * once only 'monitor' clients are left. * * @param server server to stop listening on */ void GNUNET_SERVER_stop_listening (struct GNUNET_SERVER_Handle *server); /** * Free resources held by this server. * * @param server server to destroy */ void GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server); /** * Add additional handlers to an existing server. * * @param server the server to add handlers to * @param handlers array of message handlers for * incoming messages; the last entry must * have "NULL" for the "callback"; multiple * entries for the same type are allowed, * they will be called in order of occurence. * These handlers can be removed later; * the handlers array must exist until removed * (or server is destroyed). */ void GNUNET_SERVER_add_handlers (struct GNUNET_SERVER_Handle *server, const struct GNUNET_SERVER_MessageHandler *handlers); /** * Notify us when the server has enough space to transmit * a message of the given size to the given client. * * @param client client to transmit message to * @param size requested amount of buffer space * @param timeout after how long should we give up (and call * notify with buf NULL and size 0)? * @param callback function to call when space is available * @param callback_cls closure for callback * @return non-NULL if the notify callback was queued; can be used * to cancel the request using * GNUNET_SERVER_notify_transmit_ready_cancel. * NULL if we are already going to notify someone else (busy) */ struct GNUNET_SERVER_TransmitHandle * GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client, size_t size, struct GNUNET_TIME_Relative timeout, GNUNET_CONNECTION_TransmitReadyNotify callback, void *callback_cls); /** * Abort transmission request. * * @param th request to abort */ void GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th); /** * Set the 'monitor' flag on this client. Clients which have been * marked as 'monitors' won't prevent the server from shutting down * once 'GNUNET_SERVER_stop_listening' has been invoked. The idea is * that for "normal" clients we likely want to allow them to process * their requests; however, monitor-clients are likely to 'never' * disconnect during shutdown and thus will not be considered when * determining if the server should continue to exist after * 'GNUNET_SERVER_destroy' has been called. * * @param client the client to set the 'monitor' flag on */ void GNUNET_SERVER_client_mark_monitor (struct GNUNET_SERVER_Client *client); /** * Set the persistent flag on this client, used to setup client connection * to only be killed when the service it's connected to is actually dead. * * @param client the client to set the persistent flag on */ void GNUNET_SERVER_client_persist_ (struct GNUNET_SERVER_Client *client); /** * Resume receiving from this client, we are done processing the * current request. This function must be called from within each * GNUNET_SERVER_MessageCallback (or its respective continuations). * * @param client client we were processing a message of * @param success GNUNET_OK to keep the connection open and * continue to receive * GNUNET_NO to close the connection (normal behavior) * GNUNET_SYSERR to close the connection (signal * serious error) */ void GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client, int success); /** * Change the timeout for a particular client. Decreasing the timeout * may not go into effect immediately (only after the previous timeout * times out or activity happens on the socket). * * @param client the client to update * @param timeout new timeout for activities on the socket */ void GNUNET_SERVER_client_set_timeout (struct GNUNET_SERVER_Client *client, struct GNUNET_TIME_Relative timeout); /** * Disable the warning the server issues if a message is not acknowledged * in a timely fashion. Use this call if a client is intentionally delayed * for a while. Only applies to the current message. * * @param client client for which to disable the warning */ void GNUNET_SERVER_disable_receive_done_warning (struct GNUNET_SERVER_Client *client); /** * Inject a message into the server, pretend it came * from the specified client. Delivery of the message * will happen instantly (if a handler is installed; * otherwise the call does nothing). * * @param server the server receiving the message * @param sender the "pretended" sender of the message * can be NULL! * @param message message to transmit * @return GNUNET_OK if the message was OK and the * connection can stay open * GNUNET_SYSERR if the connection to the * client should be shut down */ int GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server, struct GNUNET_SERVER_Client *sender, const struct GNUNET_MessageHeader *message); /** * Add a TCP socket-based connection to the set of handles managed by * this server. Use this function for outgoing (P2P) connections that * we initiated (and where this server should process incoming * messages). * * @param server the server to use * @param connection the connection to manage (client must * stop using this connection from now on) * @return the client handle (client should call * "client_drop" on the return value eventually) */ struct GNUNET_SERVER_Client * GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server, struct GNUNET_CONNECTION_Handle *connection); /** * Notify the server that the given client handle should * be kept (keeps the connection up if possible, increments * the internal reference counter). * * @param client the client to keep */ void GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client); /** * Notify the server that the given client handle is no * longer required. Decrements the reference counter. If * that counter reaches zero an inactive connection maybe * closed. * * @param client the client to drop */ void GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client); /** * Obtain the network address of the other party. * * @param client the client to get the address for * @param addr where to store the address * @param addrlen where to store the length of the address * @return GNUNET_OK on success */ int GNUNET_SERVER_client_get_address (struct GNUNET_SERVER_Client *client, void **addr, size_t * addrlen); /** * Functions with this signature are called whenever a client * is disconnected on the network level. * * @param cls closure * @param client identification of the client; NULL * for the last call when the server is destroyed */ typedef void (*GNUNET_SERVER_DisconnectCallback) (void *cls, struct GNUNET_SERVER_Client * client); /** * Ask the server to notify us whenever a client disconnects. * This function is called whenever the actual network connection * is closed; the reference count may be zero or larger than zero * at this point. If the server is destroyed before this * notification is explicitly cancelled, the 'callback' will * once be called with a 'client' argument of NULL to indicate * that the server itself is now gone (and that the callback * won't be called anymore and also can no longer be cancelled). * * @param server the server manageing the clients * @param callback function to call on disconnect * @param callback_cls closure for callback */ void GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server, GNUNET_SERVER_DisconnectCallback callback, void *callback_cls); /** * Ask the server to stop notifying us whenever a client disconnects. * * @param server the server manageing the clients * @param callback function to call on disconnect * @param callback_cls closure for callback */ void GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server, GNUNET_SERVER_DisconnectCallback callback, void *callback_cls); /** * Ask the server to disconnect from the given client. * This is the same as returning GNUNET_SYSERR from a message * handler, except that it allows dropping of a client even * when not handling a message from that client. * * @param client the client to disconnect from */ void GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client); /** * Disable the "CORK" feature for communication with the given client, * forcing the OS to immediately flush the buffer on transmission * instead of potentially buffering multiple messages. * * @param client handle to the client * @return GNUNET_OK on success */ int GNUNET_SERVER_client_disable_corking (struct GNUNET_SERVER_Client *client); /** * The tansmit context is the key datastructure for a conveniance API * used for transmission of complex results to the client followed * ONLY by signaling receive_done with success or error */ struct GNUNET_SERVER_TransmitContext; /** * Create a new transmission context for the * given client. * * @param client client to create the context for. * @return NULL on error */ struct GNUNET_SERVER_TransmitContext * GNUNET_SERVER_transmit_context_create (struct GNUNET_SERVER_Client *client); /** * Append a message to the transmission context. * All messages in the context will be sent by * the transmit_context_run method. * * @param tc context to use * @param data what to append to the result message * @param length length of data * @param type type of the message */ void GNUNET_SERVER_transmit_context_append_data (struct GNUNET_SERVER_TransmitContext *tc, const void *data, size_t length, uint16_t type); /** * Append a message to the transmission context. * All messages in the context will be sent by * the transmit_context_run method. * * @param tc context to use * @param msg message to append */ void GNUNET_SERVER_transmit_context_append_message (struct GNUNET_SERVER_TransmitContext *tc, const struct GNUNET_MessageHeader *msg); /** * Execute a transmission context. If there is an error in the * transmission, the receive_done method will be called with an error * code (GNUNET_SYSERR), otherwise with GNUNET_OK. * * @param tc transmission context to use * @param timeout when to time out and abort the transmission */ void GNUNET_SERVER_transmit_context_run (struct GNUNET_SERVER_TransmitContext *tc, struct GNUNET_TIME_Relative timeout); /** * Destroy a transmission context. This function must not be called * after 'GNUNET_SERVER_transmit_context_run'. * * @param tc transmission context to destroy * @param success code to give to 'GNUNET_SERVER_receive_done' for * the client: GNUNET_OK to keep the connection open and * continue to receive * GNUNET_NO to close the connection (normal behavior) * GNUNET_SYSERR to close the connection (signal * serious error) */ void GNUNET_SERVER_transmit_context_destroy (struct GNUNET_SERVER_TransmitContext *tc, int success); /** * The notification context is the key datastructure for a conveniance * API used for transmission of notifications to the client until the * client disconnects (or the notification context is destroyed, in * which case we disconnect these clients). Essentially, all * (notification) messages are queued up until the client is able to * read them. */ struct GNUNET_SERVER_NotificationContext; /** * Create a new notification context. * * @param server server for which this function creates the context * @param queue_length maximum number of messages to keep in * the notification queue; optional messages are dropped * if the queue gets longer than this number of messages * @return handle to the notification context */ struct GNUNET_SERVER_NotificationContext * GNUNET_SERVER_notification_context_create (struct GNUNET_SERVER_Handle *server, unsigned int queue_length); /** * Destroy the context, force disconnect for all clients. * * @param nc context to destroy. */ void GNUNET_SERVER_notification_context_destroy (struct GNUNET_SERVER_NotificationContext *nc); /** * Add a client to the notification context. * * @param nc context to modify * @param client client to add */ void GNUNET_SERVER_notification_context_add (struct GNUNET_SERVER_NotificationContext *nc, struct GNUNET_SERVER_Client *client); /** * Send a message to a particular client; must have * already been added to the notification context. * * @param nc context to modify * @param client client to transmit to * @param msg message to send * @param can_drop can this message be dropped due to queue length limitations */ void GNUNET_SERVER_notification_context_unicast (struct GNUNET_SERVER_NotificationContext *nc, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *msg, int can_drop); /** * Send a message to all clients of this context. * * @param nc context to modify * @param msg message to send * @param can_drop can this message be dropped due to queue length limitations */ void GNUNET_SERVER_notification_context_broadcast (struct GNUNET_SERVER_NotificationContext *nc, const struct GNUNET_MessageHeader *msg, int can_drop); /** * Handle to a message stream tokenizer. */ struct GNUNET_SERVER_MessageStreamTokenizer; /** * Functions with this signature are called whenever a * complete message is received by the tokenizer. * * Do not call GNUNET_SERVER_mst_destroy in callback * * @param cls closure * @param client identification of the client * @param message the actual message * * @return GNUNET_OK on success, GNUNET_SYSERR to stop further processing */ typedef int (*GNUNET_SERVER_MessageTokenizerCallback) (void *cls, void *client, const struct GNUNET_MessageHeader * message); /** * Create a message stream tokenizer. * * @param cb function to call on completed messages * @param cb_cls closure for cb * @return handle to tokenizer */ struct GNUNET_SERVER_MessageStreamTokenizer * GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb, void *cb_cls); /** * Add incoming data to the receive buffer and call the * callback for all complete messages. * * @param mst tokenizer to use * @param client_identity ID of client for which this is a buffer, * can be NULL (will be passed back to 'cb') * @param buf input data to add * @param size number of bytes in buf * @param purge should any excess bytes in the buffer be discarded * (i.e. for packet-based services like UDP) * @param one_shot only call callback once, keep rest of message in buffer * @return GNUNET_OK if we are done processing (need more data) * GNUNET_NO if one_shot was set and we have another message ready * GNUNET_SYSERR if the data stream is corrupt */ int GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst, void *client_identity, const char *buf, size_t size, int purge, int one_shot); /** * Destroys a tokenizer. * * @param mst tokenizer to destroy */ void GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst); /** * Signature of a function to create a custom tokenizer. * * @param cls closure from 'GNUNET_SERVER_set_callbacks' * @param client handle to client the tokenzier will be used for * @return handle to custom tokenizer ('mst') */ typedef void* (*GNUNET_SERVER_MstCreateCallback) (void *cls, struct GNUNET_SERVER_Client *client); /** * Signature of a function to destroy a custom tokenizer. * * @param cls closure from 'GNUNET_SERVER_set_callbacks' * @param mst custom tokenizer handle */ typedef void (*GNUNET_SERVER_MstDestroyCallback) (void *cls, void *mst); /** * Signature of a function to destroy a custom tokenizer. * * @param cls closure from 'GNUNET_SERVER_set_callbacks' * @param mst custom tokenizer handle * @param client_identity ID of client for which this is a buffer, * can be NULL (will be passed back to 'cb') * @param buf input data to add * @param size number of bytes in buf * @param purge should any excess bytes in the buffer be discarded * (i.e. for packet-based services like UDP) * @param one_shot only call callback once, keep rest of message in buffer * @return GNUNET_OK if we are done processing (need more data) * GNUNET_NO if one_shot was set and we have another message ready * GNUNET_SYSERR if the data stream is corrupt */ typedef int (*GNUNET_SERVER_MstReceiveCallback) (void *cls, void *mst, struct GNUNET_SERVER_Client *client, const char *buf, size_t size, int purge, int one_shot); /** * Change functions used by the server to tokenize the message stream. * (very rarely used). * * @param server server to modify * @param create new tokenizer initialization function * @param destroy new tokenizer destruction function * @param receive new tokenizer receive function * @param cls closure for 'create', 'receive', 'destroy' */ void GNUNET_SERVER_set_callbacks (struct GNUNET_SERVER_Handle *server, GNUNET_SERVER_MstCreateCallback create, GNUNET_SERVER_MstDestroyCallback destroy, GNUNET_SERVER_MstReceiveCallback receive, void *cls); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_SERVER_LIB_H */ #endif /* end of gnunet_server_lib.h */ gnunet-0.9.3/src/include/winproc.h0000644000175000017500000002601011760502551014011 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/winproc.h * @brief Definitions for MS Windows * @author Nils Durner */ #ifndef _WINPROC_H #define _WINPROC_H #include #include #include #include #include #include #include #ifndef FD_SETSIZE #define FD_SETSIZE 1024 #endif #include #include #include #include #include #include #include #include /* #define BYTE_ORDER */ #include #include #include #ifdef __cplusplus extern "C" { #endif #ifndef MAX_NAME_LENGTH #define MAX_NAME_LENGTH 25 #endif typedef DWORD WINAPI (*TNtQuerySystemInformation) (int, PVOID, ULONG, PULONG); typedef DWORD WINAPI (*TGetIfEntry) (PMIB_IFROW pIfRow); typedef DWORD WINAPI (*TGetIpAddrTable) (PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder); typedef DWORD WINAPI (*TGetIfTable) (PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder); typedef DWORD WINAPI (*TGetBestInterfaceEx) (struct sockaddr *, PDWORD); /* TODO: Explicitly import -A variants (i.e. TCreateHardLinkA) or -W * variants (TCreateHardLinkW), etc. */ typedef DWORD WINAPI (*TCreateHardLink) (LPCTSTR lpFileName, LPCTSTR lpExistingFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes); typedef SC_HANDLE WINAPI (*TOpenSCManager) (LPCTSTR lpMachineName, LPCTSTR lpDatabaseName, DWORD dwDesiredAccess); typedef SC_HANDLE WINAPI (*TCreateService) (SC_HANDLE hSCManager, LPCTSTR lpServiceName, LPCTSTR lpDisplayName, DWORD dwDesiredAccess, DWORD dwServiceType, DWORD dwStartType, DWORD dwErrorControl, LPCTSTR lpBinaryPathName, LPCTSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCTSTR lpDependencies, LPCTSTR lpServiceStartName, LPCTSTR lpPassword); typedef BOOL WINAPI (*TCloseServiceHandle) (SC_HANDLE hSCObject); typedef BOOL WINAPI (*TDeleteService) (SC_HANDLE hService); typedef SERVICE_STATUS_HANDLE WINAPI (*TRegisterServiceCtrlHandler) (LPCTSTR lpServiceName, LPHANDLER_FUNCTION lpHandlerProc); typedef BOOL WINAPI (*TSetServiceStatus) (SERVICE_STATUS_HANDLE hServiceStatus, LPSERVICE_STATUS lpServiceStatus); typedef BOOL WINAPI (*TStartServiceCtrlDispatcher) (const LPSERVICE_TABLE_ENTRY lpServiceTable); typedef BOOL WINAPI (*TControlService) (SC_HANDLE hService, DWORD dwControl, LPSERVICE_STATUS lpServiceStatus); typedef SC_HANDLE WINAPI (*TOpenService) (SC_HANDLE hSCManager, LPCTSTR lpServiceName, DWORD dwDesiredAccess); typedef DWORD WINAPI (*TGetAdaptersInfo) (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen); typedef NET_API_STATUS WINAPI (*TNetUserAdd) (LPCWSTR, DWORD, PBYTE, PDWORD); typedef NET_API_STATUS WINAPI (*TNetUserSetInfo) (LPCWSTR servername, LPCWSTR username, DWORD level, LPBYTE buf, LPDWORD parm_err); typedef NTSTATUS NTAPI (*TLsaOpenPolicy) (PLSA_UNICODE_STRING, PLSA_OBJECT_ATTRIBUTES, ACCESS_MASK, PLSA_HANDLE); typedef NTSTATUS NTAPI (*TLsaAddAccountRights) (LSA_HANDLE, PSID, PLSA_UNICODE_STRING, ULONG); typedef NTSTATUS NTAPI (*TLsaRemoveAccountRights) (LSA_HANDLE, PSID, BOOLEAN, PLSA_UNICODE_STRING, ULONG); typedef NTSTATUS NTAPI (*TLsaClose) (LSA_HANDLE); typedef BOOL WINAPI (*TLookupAccountName) (LPCTSTR lpSystemName, LPCTSTR lpAccountName, PSID Sid, LPDWORD cbSid, LPTSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, PSID_NAME_USE peUse); typedef BOOL WINAPI (*TGetFileSecurity) (LPCTSTR lpFileName, SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded); typedef BOOL WINAPI (*TInitializeSecurityDescriptor) (PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD dwRevision); typedef BOOL WINAPI (*TGetSecurityDescriptorDacl) (PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL * pDacl, LPBOOL lpbDaclDefaulted); typedef BOOL WINAPI (*TGetAclInformation) (PACL pAcl, LPVOID pAclInformation, DWORD nAclInformationLength, ACL_INFORMATION_CLASS dwAclInformationClass); typedef BOOL WINAPI (*TInitializeAcl) (PACL pAcl, DWORD nAclLength, DWORD dwAclRevision); typedef BOOL WINAPI (*TGetAce) (PACL pAcl, DWORD dwAceIndex, LPVOID * pAce); typedef BOOL WINAPI (*TEqualSid) (PSID pSid1, PSID pSid2); typedef BOOL WINAPI (*TAddAce) (PACL pAcl, DWORD dwAceRevision, DWORD dwStartingAceIndex, LPVOID pAceList, DWORD nAceListLength); typedef BOOL WINAPI (*TAddAccessAllowedAce) (PACL pAcl, DWORD dwAceRevision, DWORD AccessMask, PSID pSid); typedef BOOL WINAPI (*TSetNamedSecurityInfo) (LPTSTR pObjectName, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, PSID psidOwner, PSID psidGroup, PACL pDacl, PACL pSacl); extern TGetBestInterfaceEx GNGetBestInterfaceEx; extern TNtQuerySystemInformation GNNtQuerySystemInformation; extern TGetIfEntry GNGetIfEntry; extern TGetIpAddrTable GNGetIpAddrTable; extern TGetIfTable GNGetIfTable; extern TCreateHardLink GNCreateHardLink; extern TOpenSCManager GNOpenSCManager; extern TCreateService GNCreateService; extern TCloseServiceHandle GNCloseServiceHandle; extern TDeleteService GNDeleteService; extern TRegisterServiceCtrlHandler GNRegisterServiceCtrlHandler; extern TSetServiceStatus GNSetServiceStatus; extern TStartServiceCtrlDispatcher GNStartServiceCtrlDispatcher; extern TControlService GNControlService; extern TOpenService GNOpenService; extern TGetAdaptersInfo GNGetAdaptersInfo; extern TNetUserAdd GNNetUserAdd; extern TNetUserSetInfo GNNetUserSetInfo; extern TLsaOpenPolicy GNLsaOpenPolicy; extern TLsaAddAccountRights GNLsaAddAccountRights; extern TLsaRemoveAccountRights GNLsaRemoveAccountRights; extern TLsaClose GNLsaClose; extern TLookupAccountName GNLookupAccountName; extern TGetFileSecurity GNGetFileSecurity; extern TInitializeSecurityDescriptor GNInitializeSecurityDescriptor; extern TGetSecurityDescriptorDacl GNGetSecurityDescriptorDacl; extern TGetAclInformation GNGetAclInformation; extern TInitializeAcl GNInitializeAcl; extern TGetAce GNGetAce; extern TEqualSid GNEqualSid; extern TAddAce GNAddAce; extern TAddAccessAllowedAce GNAddAccessAllowedAce; extern TSetNamedSecurityInfo GNSetNamedSecurityInfo; BOOL CreateShortcut (const char *pszSrc, const char *pszDest); BOOL DereferenceShortcut (char *pszShortcut); long QueryRegistry (HKEY hMainKey, const char *pszKey, const char *pszSubKey, char *pszBuffer, long *pdLength); int ListNICs (void (*callback) (void *, const char *, int), void *cls); BOOL AddPathAccessRights (char *lpszFileName, char *lpszAccountName, DWORD dwAccessMask); char *winErrorStr (const char *prefix, int dwErr); void EnumNICs (PMIB_IFTABLE * pIfTable, PMIB_IPADDRTABLE * pAddrTable); #define ENUMNICS3_MASK_OK 0x01 #define ENUMNICS3_BCAST_OK 0x02 struct EnumNICs3_results { unsigned char flags; int is_default; char pretty_name[1001]; size_t addr_size; SOCKADDR_STORAGE address; SOCKADDR_STORAGE mask; SOCKADDR_STORAGE broadcast; }; int EnumNICs3 (struct EnumNICs3_results **, int *EnumNICs3_results_count); void EnumNICs3_free (struct EnumNICs3_results *); int GNInitWinEnv (); void GNShutdownWinEnv (); #ifdef __cplusplus } #endif #endif gnunet-0.9.3/src/include/gnunet_connection_lib.h0000644000175000017500000002745511760502551016713 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_connection_lib.h * @brief basic, low-level TCP networking interface * @author Christian Grothoff */ #ifndef GNUNET_CONNECTION_LIB_H #define GNUNET_CONNECTION_LIB_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_network_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" /** * Timeout we use on TCP connect before trying another * result from the DNS resolver. Actual value used * is this value divided by the number of address families. * Default is 5s. */ #define GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) /** * @brief handle for a network connection */ struct GNUNET_CONNECTION_Handle; /** * Credentials for UNIX domain sockets. */ struct GNUNET_CONNECTION_Credentials { /** * UID of the other end of the connection. */ uid_t uid; /** * GID of the other end of the connection. */ gid_t gid; }; /** * Function to call for access control checks. * * @param cls closure * @param ucred credentials, if available, otherwise NULL * @param addr address * @param addrlen length of address * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR * for unknown address family (will be denied). */ typedef int (*GNUNET_CONNECTION_AccessCheck) (void *cls, const struct GNUNET_CONNECTION_Credentials * ucred, const struct sockaddr * addr, socklen_t addrlen); /** * Callback function for data received from the network. Note that * both "available" and "err" would be 0 if the read simply timed out. * * @param cls closure * @param buf pointer to received data * @param available number of bytes availabe in "buf", * possibly 0 (on errors) * @param addr address of the sender * @param addrlen size of addr * @param errCode value of errno (on errors receiving) */ typedef void (*GNUNET_CONNECTION_Receiver) (void *cls, const void *buf, size_t available, const struct sockaddr * addr, socklen_t addrlen, int errCode); /** * Set the persist option on this connection handle. Indicates * that the underlying socket or fd should never really be closed. * Used for indicating process death. * * @param connection the connection to set persistent */ void GNUNET_CONNECTION_persist_ (struct GNUNET_CONNECTION_Handle *connection); /** * Disable the "CORK" feature for communication with the given socket, * forcing the OS to immediately flush the buffer on transmission * instead of potentially buffering multiple messages. Essentially * reduces the OS send buffers to zero. * Used to make sure that the last messages sent through the connection * reach the other side before the process is terminated. * * @param connection the connection to make flushing and blocking * @return GNUNET_OK on success */ int GNUNET_CONNECTION_disable_corking (struct GNUNET_CONNECTION_Handle *connection); /** * Create a connection handle by boxing an existing OS socket. The OS * socket should henceforth be no longer used directly. * GNUNET_CONNECTION_destroy will close it. * * @param osSocket existing socket to box * @return the boxed socket handle */ struct GNUNET_CONNECTION_Handle * GNUNET_CONNECTION_create_from_existing (struct GNUNET_NETWORK_Handle *osSocket); /** * Create a connection handle by accepting on a listen socket. This * function may block if the listen socket has no connection ready. * * @param access function to use to check if access is allowed * @param access_cls closure for access * @param lsock listen socket * @return the connection handle, NULL on error (for example, access refused) */ struct GNUNET_CONNECTION_Handle * GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access, void *access_cls, struct GNUNET_NETWORK_Handle *lsock); /** * Create a connection handle by (asynchronously) connecting to a host. * This function returns immediately, even if the connection has not * yet been established. This function only creates TCP connections. * * @param cfg configuration to use * @param hostname name of the host to connect to * @param port port to connect to * @return the connection handle */ struct GNUNET_CONNECTION_Handle * GNUNET_CONNECTION_create_from_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *hostname, uint16_t port); /** * Create a connection handle by connecting to a UNIX domain service. * This function returns immediately, even if the connection has not * yet been established. This function only creates UNIX connections. * * @param cfg configuration to use * @param unixpath path to connect to) * @return the connection handle, NULL on systems without UNIX support */ struct GNUNET_CONNECTION_Handle * GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *unixpath); /** * Create a connection handle by (asynchronously) connecting to a host. * This function returns immediately, even if the connection has not * yet been established. This function only creates TCP connections. * * @param af_family address family to use * @param serv_addr server address * @param addrlen length of server address * @return the connection handle */ struct GNUNET_CONNECTION_Handle * GNUNET_CONNECTION_create_from_sockaddr (int af_family, const struct sockaddr *serv_addr, socklen_t addrlen); /** * Check if connection is valid (no fatal errors have happened so far). * Note that a connection that is still trying to connect is considered * valid. * * @param connection handle to check * @return GNUNET_YES if valid, GNUNET_NO otherwise */ int GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *connection); /** * Obtain the network address of the other party. * * @param connection the client to get the address for * @param addr where to store the address * @param addrlen where to store the length of the address * @return GNUNET_OK on success */ int GNUNET_CONNECTION_get_address (struct GNUNET_CONNECTION_Handle *connection, void **addr, size_t * addrlen); /** * Close the connection and free associated resources. There must * not be any pending requests for reading or writing to the * connection at this time. * * @param connection connection to destroy */ void GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection); /** * Receive data from the given connection. Note that this function will * call "receiver" asynchronously using the scheduler. It will * "immediately" return. Note that there MUST only be one active * receive call per connection at any given point in time (so do not * call receive again until the receiver callback has been invoked). * * @param connection connection handle * @param max maximum number of bytes to read * @param timeout maximum amount of time to wait * @param receiver function to call with received data * @param receiver_cls closure for receiver */ void GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *connection, size_t max, struct GNUNET_TIME_Relative timeout, GNUNET_CONNECTION_Receiver receiver, void *receiver_cls); /** * Cancel receive job on the given connection. Note that the * receiver callback must not have been called yet in order * for the cancellation to be valid. * * @param connection connection handle * @return closure of the original receiver callback closure */ void * GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *connection); /** * Function called to notify a client about the connection * begin ready to queue more data. "buf" will be * NULL and "size" zero if the connection was closed for * writing in the meantime. * * @param cls closure * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ typedef size_t (*GNUNET_CONNECTION_TransmitReadyNotify) (void *cls, size_t size, void *buf); /** * Opaque handle that can be used to cancel * a transmit-ready notification. */ struct GNUNET_CONNECTION_TransmitHandle; /** * Ask the connection to call us once the specified number of bytes * are free in the transmission buffer. May call the notify * method immediately if enough space is available. Note that * this function will abort if "size" is greater than * GNUNET_SERVER_MAX_MESSAGE_SIZE. * * Note that "notify" will be called either when enough * buffer space is available OR when the connection is destroyed. * The size parameter given to notify is guaranteed to be * larger or equal to size if the buffer is ready, or zero * if the connection was destroyed (or at least closed for * writing). Finally, any time before 'notify' is called, a * client may call "notify_transmit_ready_cancel" to cancel * the transmission request. * * Only one transmission request can be scheduled at the same * time. Notify will be run with the same scheduler priority * as that of the caller. * * @param connection connection * @param size number of bytes to send * @param timeout after how long should we give up (and call * notify with buf NULL and size 0)? * @param notify function to call when buffer space is available * @param notify_cls closure for notify * @return non-NULL if the notify callback was queued, * NULL if we are already going to notify someone else (busy) */ struct GNUNET_CONNECTION_TransmitHandle * GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle *connection, size_t size, struct GNUNET_TIME_Relative timeout, GNUNET_CONNECTION_TransmitReadyNotify notify, void *notify_cls); /** * Cancel the specified transmission-ready * notification. * * @param th handle for notification to cancel */ void GNUNET_CONNECTION_notify_transmit_ready_cancel (struct GNUNET_CONNECTION_TransmitHandle *th); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_CONNECTION_LIB_H */ #endif /* end of gnunet_connection_lib.h */ gnunet-0.9.3/src/include/gnunet_namestore_service.h0000644000175000017500000003761511760502551017442 00000000000000/* This file is part of GNUnet (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_namestore_service.h * @brief API that can be used to store naming information on a GNUnet node; * @author Christian Grothoff * * Other functions we might want: * - enumerate all known zones * - convenience function to gather record and the full affilliated stree * in one shot */ #ifndef GNUNET_NAMESTORE_SERVICE_H #define GNUNET_NAMESTORE_SERVICE_H #include "gnunet_util_lib.h" #include "gnunet_block_lib.h" #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * Record type indicating any record/'*' */ #define GNUNET_NAMESTORE_TYPE_ANY 0 /** * Record type for GNS zone transfer ("PKEY"). */ #define GNUNET_NAMESTORE_TYPE_PKEY 65536 /** * Record type for GNS zone transfer ("PSEU"). */ #define GNUNET_NAMESTORE_TYPE_PSEU 65537 /** * Record type for GNS legacy hostnames ("LEHO"). */ #define GNUNET_NAMESTORE_TYPE_LEHO 65538 /** * Entry in the queue. */ struct GNUNET_NAMESTORE_QueueEntry; /** * Handle to the namestore service. */ struct GNUNET_NAMESTORE_Handle; /** * Handle to the namestore zone iterator. */ struct GNUNET_NAMESTORE_ZoneIterator; /** * Maximum size of a value that can be stored in the namestore. */ #define GNUNET_NAMESTORE_MAX_VALUE_SIZE (63 * 1024) /** * Connect to the namestore service. * * @param cfg configuration to use * @return handle to use to access the service */ struct GNUNET_NAMESTORE_Handle * GNUNET_NAMESTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); /** * Disconnect from the namestore service (and free associated * resources). * * @param h handle to the namestore * @param drop set to GNUNET_YES to delete all data in namestore (!) */ void GNUNET_NAMESTORE_disconnect (struct GNUNET_NAMESTORE_Handle *h, int drop); /** * Continuation called to notify client about result of the * operation. * * @param cls closure * @param success GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate) * GNUNET_NO if content was already there or not found * GNUNET_YES (or other positive value) on success * @param emsg NULL on success, otherwise an error message */ typedef void (*GNUNET_NAMESTORE_ContinuationWithStatus) (void *cls, int32_t success, const char *emsg); /** * Flags that can be set for a record. */ enum GNUNET_NAMESTORE_RecordFlags { /** * No special options. */ GNUNET_NAMESTORE_RF_NONE = 0, /** * This peer is the authority for this record; it must thus * not be deleted (other records can be deleted if we run * out of space). */ GNUNET_NAMESTORE_RF_AUTHORITY = 1, /** * This is a private record of this peer and it should * thus not be handed out to other peers. */ GNUNET_NAMESTORE_RF_PRIVATE = 2, /** * This record was added by the system * and is pending user confimation */ GNUNET_NAMESTORE_RF_PENDING = 4 }; /** * A GNS record. */ struct GNUNET_NAMESTORE_RecordData { /** * Binary value stored in the DNS record. */ const void *data; /** * Expiration time for the DNS record. */ struct GNUNET_TIME_Absolute expiration; /** * Number of bytes in 'data'. */ size_t data_size; /** * Type of the GNS/DNS record. */ uint32_t record_type; /** * Flags for the record. */ enum GNUNET_NAMESTORE_RecordFlags flags; }; /** * Store an item in the namestore. If the item is already present, * the expiration time is updated to the max of the existing time and * the new time. This API is used when we cache signatures from other * authorities. * * @param h handle to the namestore * @param zone_key public key of the zone * @param name name that is being mapped (at most 255 characters long) * @param freshness when does the corresponding block in the DHT expire (until * when should we never do a DHT lookup for the same name again)? * @param rd_count number of entries in 'rd' array * @param rd array of records with data to store * @param signature signature for all the records in the zone under the given name * @param cont continuation to call when done * @param cont_cls closure for cont * @return handle to abort the request */ struct GNUNET_NAMESTORE_QueueEntry * GNUNET_NAMESTORE_record_put (struct GNUNET_NAMESTORE_Handle *h, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, const char *name, struct GNUNET_TIME_Absolute freshness, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature, GNUNET_NAMESTORE_ContinuationWithStatus cont, void *cont_cls); /** * Check if a signature is valid. This API is used by the GNS Block * to validate signatures received from the network. * * @param public_key public key of the zone * @param expire block expiration * @param name name that is being mapped (at most 255 characters long) * @param rd_count number of entries in 'rd' array * @param rd array of records with data to store * @param signature signature for all the records in the zone under the given name * @return GNUNET_OK if the signature is valid */ int GNUNET_NAMESTORE_verify_signature (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, const struct GNUNET_TIME_Absolute freshness, const char *name, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature); /** * Store an item in the namestore. If the item is already present, * the expiration time is updated to the max of the existing time and * the new time. This API is used by the authority of a zone. * * @param h handle to the namestore * @param pkey private key of the zone * @param name name that is being mapped (at most 255 characters long) * @param rd record data to store * @param cont continuation to call when done * @param cont_cls closure for cont * @return handle to abort the request */ struct GNUNET_NAMESTORE_QueueEntry * GNUNET_NAMESTORE_record_create (struct GNUNET_NAMESTORE_Handle *h, const struct GNUNET_CRYPTO_RsaPrivateKey *pkey, const char *name, const struct GNUNET_NAMESTORE_RecordData *rd, GNUNET_NAMESTORE_ContinuationWithStatus cont, void *cont_cls); /** * Explicitly remove some content from the database. The * "cont"inuation will be called with status "GNUNET_OK" if content * was removed, "GNUNET_NO" if no matching entry was found and * "GNUNET_SYSERR" on all other types of errors. * This API is used by the authority of a zone. * * @param h handle to the namestore * @param pkey private key of the zone * @param name name that is being mapped (at most 255 characters long) * @param rd record data, remove specific record, NULL to remove the name and all records * @param cont continuation to call when done * @param cont_cls closure for cont * @return handle to abort the request */ struct GNUNET_NAMESTORE_QueueEntry * GNUNET_NAMESTORE_record_remove (struct GNUNET_NAMESTORE_Handle *h, const struct GNUNET_CRYPTO_RsaPrivateKey *pkey, const char *name, const struct GNUNET_NAMESTORE_RecordData *rd, GNUNET_NAMESTORE_ContinuationWithStatus cont, void *cont_cls); /** * Process a record that was stored in the namestore. * * @param cls closure * @param zone_key public key of the zone * @param expire when does the corresponding block in the DHT expire (until * when should we never do a DHT lookup for the same name again)?; * GNUNET_TIME_UNIT_ZERO_ABS if there are no records of any type in the namestore, * or the expiration time of the block in the namestore (even if there are zero * records matching the desired record type) * @param name name that is being mapped (at most 255 characters long) * @param rd_count number of entries in 'rd' array * @param rd array of records with data to store * @param signature signature of the record block, NULL if signature is unavailable (i.e. * because the user queried for a particular record type only) */ typedef void (*GNUNET_NAMESTORE_RecordProcessor) (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute freshness, const char *name, unsigned int rd_len, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature); /** * Get a result for a particular key from the namestore. The processor * will only be called once. * * @param h handle to the namestore * @param zone zone to look up a record from * @param name name to look up * @param record_type desired record type, 0 for all * @param proc function to call on the matching records, or with * NULL (rd_count == 0) if there are no matching records * @param proc_cls closure for proc * @return a handle that can be used to * cancel */ struct GNUNET_NAMESTORE_QueueEntry * GNUNET_NAMESTORE_lookup_record (struct GNUNET_NAMESTORE_Handle *h, const struct GNUNET_CRYPTO_ShortHashCode *zone, const char *name, uint32_t record_type, GNUNET_NAMESTORE_RecordProcessor proc, void *proc_cls); /** * Look for an existing PKEY delegation record for a given public key. * Returns at most one result to the processor. * * @param h handle to the namestore * @param zone hash of public key of the zone to look up in, never NULL * @param value_zone hash of the public key of the target zone (value), never NULL * @param proc function to call on the matching records, or with * NULL (rd_count == 0) if there are no matching records * @param proc_cls closure for proc * @return a handle that can be used to * cancel */ struct GNUNET_NAMESTORE_QueueEntry * GNUNET_NAMESTORE_zone_to_name (struct GNUNET_NAMESTORE_Handle *h, const struct GNUNET_CRYPTO_ShortHashCode *zone, const struct GNUNET_CRYPTO_ShortHashCode *value_zone, GNUNET_NAMESTORE_RecordProcessor proc, void *proc_cls); /** * Starts a new zone iteration (used to periodically PUT all of our * records into our DHT). "proc" will be called once * immediately, and then again after * "GNUNET_NAMESTORE_zone_iterator_next" is invoked. * * @param h handle to the namestore * @param zone zone to access, NULL for all zones * @param must_have_flags flags that must be set for the record to be returned * @param must_not_have_flags flags that must NOT be set for the record to be returned * @param proc function to call on each name from the zone; it * will be called repeatedly with a value (if available) * and always once at the end with a name of NULL. * @param proc_cls closure for proc * @return an iterator handle to use for iteration */ struct GNUNET_NAMESTORE_ZoneIterator * GNUNET_NAMESTORE_zone_iteration_start (struct GNUNET_NAMESTORE_Handle *h, const struct GNUNET_CRYPTO_ShortHashCode *zone, enum GNUNET_NAMESTORE_RecordFlags must_have_flags, enum GNUNET_NAMESTORE_RecordFlags must_not_have_flags, GNUNET_NAMESTORE_RecordProcessor proc, void *proc_cls); /** * Calls the record processor specified in GNUNET_NAMESTORE_zone_iteration_start * for the next record. * * @param it the iterator */ void GNUNET_NAMESTORE_zone_iterator_next (struct GNUNET_NAMESTORE_ZoneIterator *it); /** * Stops iteration and releases the namestore handle for further calls. * * @param it the iterator */ void GNUNET_NAMESTORE_zone_iteration_stop (struct GNUNET_NAMESTORE_ZoneIterator *it); /** * Cancel a namestore operation. The final callback from the * operation must not have been done yet. * * @param qe operation to cancel */ void GNUNET_NAMESTORE_cancel (struct GNUNET_NAMESTORE_QueueEntry *qe); /* convenience APIs for serializing / deserializing GNS records */ /** * Calculate how many bytes we will need to serialize the given * records. * * @param rd_count number of records in the rd array * @param rd array of GNUNET_NAMESTORE_RecordData with rd_count elements * * @return the required size to serialize * */ size_t GNUNET_NAMESTORE_records_get_size (unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd); /** * Serialize the given records to the given destination buffer. * * @param rd_count number of records in the rd array * @param rd array of GNUNET_NAMESTORE_RecordData with rd_count elements * @param dest_size size of the destination array * @param dest where to write the result * * @return the size of serialized records */ ssize_t GNUNET_NAMESTORE_records_serialize (unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, size_t dest_size, char *dest); /** * Deserialize the given records to the given destination. * * @param len size of the serialized record data * @param src the serialized record data * @param rd_count number of records in the rd array * @param dest where to put the data * * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_NAMESTORE_records_deserialize (size_t len, const char *src, unsigned int rd_count, struct GNUNET_NAMESTORE_RecordData *dest); /** * Checks if a name is wellformed * * @param name the name to check * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_NAMESTORE_check_name (const char * name); /** * Convert the 'value' of a record to a string. * * @param type type of the record * @param data value in binary encoding * @param data_size number of bytes in data * @return NULL on error, otherwise human-readable representation of the value */ char * GNUNET_NAMESTORE_value_to_string (uint32_t type, const void *data, size_t data_size); /** * Convert human-readable version of a 'value' of a record to the binary * representation. * * @param type type of the record * @param s human-readable string * @param data set to value in binary encoding (will be allocated) * @param data_size set to number of bytes in data * @return GNUNET_OK on success */ int GNUNET_NAMESTORE_string_to_value (uint32_t type, const char *s, void **data, size_t *data_size); /** * Convert a type name (i.e. "AAAA") to the corresponding number. * * @param typename name to convert * @return corresponding number, UINT32_MAX on error */ uint32_t GNUNET_NAMESTORE_typename_to_number (const char *typename); /** * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A") * * @param type number of a type to convert * @return corresponding typestring, NULL on error */ const char * GNUNET_NAMESTORE_number_to_typename (uint32_t type); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* end of gnunet_namestore_service.h */ #endif gnunet-0.9.3/src/include/gnunet_core_service.h0000644000175000017500000003211611760502551016364 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_core_service.h * @brief core service; this is the main API for encrypted P2P * communications * @author Christian Grothoff */ #ifndef GNUNET_CORE_SERVICE_H #define GNUNET_CORE_SERVICE_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_util_lib.h" #include "gnunet_transport_service.h" /** * Version number of GNUnet-core API. */ #define GNUNET_CORE_VERSION 0x00000000 /** * Opaque handle to the service. */ struct GNUNET_CORE_Handle; /** * Method called whenever a given peer connects. * * @param cls closure * @param peer peer identity this notification is about * @param atsi performance data for the connection * @param atsi_count number of records in 'atsi' */ typedef void (*GNUNET_CORE_ConnectEventHandler) (void *cls, const struct GNUNET_PeerIdentity * peer, const struct GNUNET_ATS_Information * atsi, unsigned int atsi_count); /** * Method called whenever a peer disconnects. * * @param cls closure * @param peer peer identity this notification is about */ typedef void (*GNUNET_CORE_DisconnectEventHandler) (void *cls, const struct GNUNET_PeerIdentity * peer); /** * Functions with this signature are called whenever a message is * received or transmitted. * * @param cls closure (set from GNUNET_CORE_connect) * @param peer the other peer involved (sender or receiver, NULL * for loopback messages where we are both sender and receiver) * @param message the actual message * @param atsi performance data for the connection * @param atsi_count number of records in 'atsi' * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ typedef int (*GNUNET_CORE_MessageCallback) (void *cls, const struct GNUNET_PeerIdentity * other, const struct GNUNET_MessageHeader * message, const struct GNUNET_ATS_Information * atsi, unsigned int atsi_count); /** * Message handler. Each struct specifies how to handle on particular * type of message received. */ struct GNUNET_CORE_MessageHandler { /** * Function to call for messages of "type". */ GNUNET_CORE_MessageCallback callback; /** * Type of the message this handler covers. */ uint16_t type; /** * Expected size of messages of this type. Use 0 for variable-size. * If non-zero, messages of the given type will be discarded if they * do not have the right size. */ uint16_t expected_size; }; /** * Function called after GNUNET_CORE_connect has succeeded (or failed * for good). Note that the private key of the peer is intentionally * not exposed here; if you need it, your process should try to read * the private key file directly (which should work if you are * authorized...). * * @param cls closure * @param server handle to the server, NULL if we failed * @param my_identity ID of this peer, NULL if we failed */ typedef void (*GNUNET_CORE_StartupCallback) (void *cls, struct GNUNET_CORE_Handle * server, const struct GNUNET_PeerIdentity * my_identity); /** * Connect to the core service. Note that the connection may complete * (or fail) asynchronously. This function primarily causes the given * callback notification functions to be invoked whenever the * specified event happens. The maximum number of queued * notifications (queue length) is per client but the queue is shared * across all types of notifications. So a slow client that registers * for 'outbound_notify' also risks missing 'inbound_notify' messages. * Certain events (such as connect/disconnect notifications) are not * subject to queue size limitations. * * @param cfg configuration to use * @param queue_size size of the per-peer message queue * @param cls closure for the various callbacks that follow (including handlers in the handlers array) * @param init callback to call once we have successfully * connected to the core service * @param connects function to call on peer connect, can be NULL * @param disconnects function to call on peer disconnect / timeout, can be NULL * @param inbound_notify function to call for all inbound messages, can be NULL * note that the core is allowed to drop notifications about inbound * messages if the client does not process them fast enough (for this * notification type, a bounded queue is used) * @param inbound_hdr_only set to GNUNET_YES if inbound_notify will only read the * GNUNET_MessageHeader and hence we do not need to give it the full message; * can be used to improve efficiency, ignored if inbound_notify is NULL * note that the core is allowed to drop notifications about inbound * messages if the client does not process them fast enough (for this * notification type, a bounded queue is used) * @param outbound_notify function to call for all outbound messages, can be NULL; * note that the core is allowed to drop notifications about outbound * messages if the client does not process them fast enough (for this * notification type, a bounded queue is used) * @param outbound_hdr_only set to GNUNET_YES if outbound_notify will only read the * GNUNET_MessageHeader and hence we do not need to give it the full message * can be used to improve efficiency, ignored if outbound_notify is NULL * note that the core is allowed to drop notifications about outbound * messages if the client does not process them fast enough (for this * notification type, a bounded queue is used) * @param handlers callbacks for messages we care about, NULL-terminated * note that the core is allowed to drop notifications about inbound * messages if the client does not process them fast enough (for this * notification type, a bounded queue is used) * @return handle to the core service (only useful for disconnect until 'init' is called), * NULL on error (in this case, init is never called) */ struct GNUNET_CORE_Handle * GNUNET_CORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned int queue_size, void *cls, GNUNET_CORE_StartupCallback init, GNUNET_CORE_ConnectEventHandler connects, GNUNET_CORE_DisconnectEventHandler disconnects, GNUNET_CORE_MessageCallback inbound_notify, int inbound_hdr_only, GNUNET_CORE_MessageCallback outbound_notify, int outbound_hdr_only, const struct GNUNET_CORE_MessageHandler *handlers); /** * Disconnect from the core service. This function can only * be called *after* all pending 'GNUNET_CORE_notify_transmit_ready' * requests have been explicitly cancelled. * * @param handle connection to core to disconnect */ void GNUNET_CORE_disconnect (struct GNUNET_CORE_Handle *handle); /** * Handle for a transmission request. */ struct GNUNET_CORE_TransmitHandle; /** * Ask the core to call "notify" once it is ready to transmit the * given number of bytes to the specified "target". Must only be * called after a connection to the respective peer has been * established (and the client has been informed about this). * * * @param handle connection to core service * @param cork is corking allowed for this transmission? * @param priority how important is the message? * @param maxdelay how long can the message wait? * @param target who should receive the message, never NULL (can be this peer's identity for loopback) * @param notify_size how many bytes of buffer space does notify want? * @param notify function to call when buffer space is available; * will be called with NULL on timeout or if the overall queue * for this peer is larger than queue_size and this is currently * the message with the lowest priority; will also be called * with 'NULL' buf if the peer disconnects; since the disconnect * signal will be emmitted even later, clients MUST cancel * all pending transmission requests DURING the disconnect * handler (unless they ensure that 'notify' never calls * 'GNUNET_CORE_notify_transmit_ready'). * @param notify_cls closure for notify * @return non-NULL if the notify callback was queued, * NULL if we can not even queue the request (insufficient * memory); if NULL is returned, "notify" will NOT be called. */ struct GNUNET_CORE_TransmitHandle * GNUNET_CORE_notify_transmit_ready (struct GNUNET_CORE_Handle *handle, int cork, uint32_t priority, struct GNUNET_TIME_Relative maxdelay, const struct GNUNET_PeerIdentity *target, size_t notify_size, GNUNET_CONNECTION_TransmitReadyNotify notify, void *notify_cls); /** * Cancel the specified transmission-ready notification. * * @param th handle that was returned by "notify_transmit_ready". */ void GNUNET_CORE_notify_transmit_ready_cancel (struct GNUNET_CORE_TransmitHandle *th); /** * Iterate over all connected peers. Calls peer_cb with each * connected peer, and then once with NULL to indicate that all peers * have been handled. Normal users of the CORE API are not expected * to use this function. It is different in that it truly lists * all connections, not just those relevant to the application. This * function is used by special applications for diagnostics. This * function is NOT part of the 'versioned', 'official' API. * * FIXME: we should probably make it possible to 'cancel' the * operation... * * @param cfg configuration handle * @param peer_cb function to call with the peer information * @param cb_cls closure for peer_cb * @return GNUNET_OK on success, GNUNET_SYSERR on errors */ int GNUNET_CORE_iterate_peers (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_CORE_ConnectEventHandler peer_cb, void *cb_cls); /** * Handle to cancel 'is_peer_connected' test. */ struct GNUNET_CORE_ConnectTestHandle; /** * Check if the given peer is currently connected and return information * about the session if so. This function is for special cirumstances * (GNUNET_TESTING uses it), normal users of the CORE API are * expected to track which peers are connected based on the * connect/disconnect callbacks from GNUNET_CORE_connect. This * function is NOT part of the 'versioned', 'official' API. * * @param cfg configuration to use * @param peer the specific peer to check for * @param peer_cb function to call with the peer information * @param cb_cls closure for peer_cb * @return handle to cancel the operation */ struct GNUNET_CORE_ConnectTestHandle * GNUNET_CORE_is_peer_connected (const struct GNUNET_CONFIGURATION_Handle *cfg, const struct GNUNET_PeerIdentity *peer, GNUNET_CORE_ConnectEventHandler peer_cb, void *cb_cls); /** * Abort 'is_connected' test operation. * * @param cth handle for operation to cancel */ void GNUNET_CORE_is_peer_connected_cancel (struct GNUNET_CORE_ConnectTestHandle *cth); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_CORE_SERVICE_H */ #endif /* end of gnunet_core_service.h */ gnunet-0.9.3/src/include/gnunet_statistics_service.h0000644000175000017500000001472511760502551017634 00000000000000/* This file is part of GNUnet (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_statistics_service.h * @brief API to create, modify and access statistics about * the operation of GNUnet; all statistical values * must be of type "unsigned long long". * @author Christian Grothoff */ #ifndef GNUNET_STATISTICS_SERVICE_H #define GNUNET_STATISTICS_SERVICE_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_common.h" #include "gnunet_configuration_lib.h" #include "gnunet_scheduler_lib.h" /** * Version of the statistics API. */ #define GNUNET_STATISTICS_VERSION 0x00000000 /** * Opaque handle for the statistics service. */ struct GNUNET_STATISTICS_Handle; /** * Callback function to process statistic values. * * @param cls closure * @param subsystem name of subsystem that created the statistic * @param name the name of the datum * @param value the current value * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration */ typedef int (*GNUNET_STATISTICS_Iterator) (void *cls, const char *subsystem, const char *name, uint64_t value, int is_persistent); /** * Get handle for the statistics service. * * @param subsystem name of subsystem using the service * @param cfg services configuration in use * @return handle to use */ struct GNUNET_STATISTICS_Handle * GNUNET_STATISTICS_create (const char *subsystem, const struct GNUNET_CONFIGURATION_Handle *cfg); /** * Destroy a handle (free all state associated with * it). * * @param h statistics handle to destroy * @param sync_first set to GNUNET_YES if pending SET requests should * be completed */ void GNUNET_STATISTICS_destroy (struct GNUNET_STATISTICS_Handle *h, int sync_first); /** * Watch statistics from the peer (be notified whenever they change). * * @param handle identification of the statistics service * @param subsystem limit to the specified subsystem, never NULL * @param name name of the statistic value, never NULL * @param proc function to call on each value * @param proc_cls closure for proc * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_STATISTICS_watch (struct GNUNET_STATISTICS_Handle *handle, const char *subsystem, const char *name, GNUNET_STATISTICS_Iterator proc, void *proc_cls); /** * Stop watching statistics from the peer. * * @param handle identification of the statistics service * @param subsystem limit to the specified subsystem, never NULL * @param name name of the statistic value, never NULL * @param proc function to call on each value * @param proc_cls closure for proc * @return GNUNET_OK on success, GNUNET_SYSERR on error (no such watch) */ int GNUNET_STATISTICS_watch_cancel (struct GNUNET_STATISTICS_Handle *handle, const char *subsystem, const char *name, GNUNET_STATISTICS_Iterator proc, void *proc_cls); /** * Continuation called by the "get_all" and "get" functions. * * @param cls closure * @param success GNUNET_OK if statistics were * successfully obtained, GNUNET_SYSERR if not. */ typedef void (*GNUNET_STATISTICS_Callback) (void *cls, int success); /** * Handle that can be used to cancel a statistics 'get' operation. */ struct GNUNET_STATISTICS_GetHandle; /** * Get statistic from the peer. * * @param handle identification of the statistics service * @param subsystem limit to the specified subsystem, NULL for our subsystem * @param name name of the statistic value, NULL for all values * @param timeout after how long should we give up (and call * notify with buf NULL and size 0)? * @param cont continuation to call when done (can be NULL) * This callback CANNOT destroy the statistics handle in the same call. * @param proc function to call on each value * @param cls closure for proc and cont * @return NULL on error */ struct GNUNET_STATISTICS_GetHandle * GNUNET_STATISTICS_get (struct GNUNET_STATISTICS_Handle *handle, const char *subsystem, const char *name, struct GNUNET_TIME_Relative timeout, GNUNET_STATISTICS_Callback cont, GNUNET_STATISTICS_Iterator proc, void *cls); /** * Cancel a 'get' request. Must be called before the 'cont' * function is called. * * @param gh handle of the request to cancel */ void GNUNET_STATISTICS_get_cancel (struct GNUNET_STATISTICS_GetHandle *gh); /** * Set statistic value for the peer. Will always use our * subsystem (the argument used when "handle" was created). * * @param handle identification of the statistics service * @param name name of the statistic value * @param value new value to set * @param make_persistent should the value be kept across restarts? */ void GNUNET_STATISTICS_set (struct GNUNET_STATISTICS_Handle *handle, const char *name, uint64_t value, int make_persistent); /** * Set statistic value for the peer. Will always use our * subsystem (the argument used when "handle" was created). * * @param handle identification of the statistics service * @param name name of the statistic value * @param delta change in value (added to existing value) * @param make_persistent should the value be kept across restarts? */ void GNUNET_STATISTICS_update (struct GNUNET_STATISTICS_Handle *handle, const char *name, int64_t delta, int make_persistent); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif #endif gnunet-0.9.3/src/include/gnunet_regex_lib.h0000644000175000017500000001152111760502551015651 00000000000000/* This file is part of GNUnet (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_regex_lib.h * @brief library to parse regular expressions into dfa * @author Maximilian Szengel * */ #ifndef GNUNET_REGEX_LIB_H #define GNUNET_REGEX_LIB_H #include "gnunet_util_lib.h" #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * Automaton (NFA/DFA) representation. */ struct GNUNET_REGEX_Automaton; /** * Edge representation. */ struct GNUNET_REGEX_Edge { /** * Label of the edge. */ const char *label; /** * Destionation of the edge. */ GNUNET_HashCode destination; }; /** * Construct an NFA by parsing the regex string of length 'len'. * * @param regex regular expression string. * @param len length of the string. * * @return NFA, needs to be freed using GNUNET_REGEX_destroy_automaton. */ struct GNUNET_REGEX_Automaton * GNUNET_REGEX_construct_nfa (const char *regex, const size_t len); /** * Construct DFA for the given 'regex' of length 'len'. * * @param regex regular expression string. * @param len length of the regular expression. * * @return DFA, needs to be freed using GNUNET_REGEX_destroy_automaton. */ struct GNUNET_REGEX_Automaton * GNUNET_REGEX_construct_dfa (const char *regex, const size_t len); /** * Free the memory allocated by constructing the GNUNET_REGEX_Automaton. * data structure. * * @param a automaton to be destroyed. */ void GNUNET_REGEX_automaton_destroy (struct GNUNET_REGEX_Automaton *a); /** * Save the given automaton as a GraphViz dot file. * * @param a the automaton to be saved. * @param filename where to save the file. */ void GNUNET_REGEX_automaton_save_graph (struct GNUNET_REGEX_Automaton *a, const char *filename); /** * Evaluates the given 'string' against the given compiled regex. * * @param a automaton. * @param string string to check. * * @return 0 if string matches, non 0 otherwise. */ int GNUNET_REGEX_eval (struct GNUNET_REGEX_Automaton *a, const char *string); /** * Get the first key for the given 'input_string'. This hashes * the first x bits of the 'input_strings'. * * @param input_string string. * @param string_len length of the 'input_string'. * @param key pointer to where to write the hash code. * * @return number of bits of 'input_string' that have been consumed * to construct the key */ unsigned int GNUNET_REGEX_get_first_key (const char *input_string, unsigned int string_len, GNUNET_HashCode * key); /** * Check if the given 'proof' matches the given 'key'. * * @param proof partial regex * @param key hash * * @return GNUNET_OK if the proof is valid for the given key */ int GNUNET_REGEX_check_proof (const char *proof, const GNUNET_HashCode *key); /** * Iterator callback function. * * @param cls closure. * @param key hash for current state. * @param proof proof for current state. * @param accepting GNUNET_YES if this is an accepting state, GNUNET_NO if not. * @param num_edges number of edges leaving current state. * @param edges edges leaving current state. */ typedef void (*GNUNET_REGEX_KeyIterator)(void *cls, const GNUNET_HashCode *key, const char *proof, int accepting, unsigned int num_edges, const struct GNUNET_REGEX_Edge *edges); /** * Iterate over all edges starting from start state of automaton 'a'. Calling * iterator for each edge. * * @param a automaton. * @param iterator iterator called for each edge. * @param iterator_cls closure. */ void GNUNET_REGEX_iterate_all_edges (struct GNUNET_REGEX_Automaton *a, GNUNET_REGEX_KeyIterator iterator, void *iterator_cls); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* end of gnunet_regex_lib.h */ #endif gnunet-0.9.3/src/include/gnunet_strings_lib.h0000644000175000017500000003102411760502551016230 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_strings_lib.h * @brief strings and string handling functions (including malloc * and string tokenizing) * * @author Christian Grothoff * @author Krista Bennett * @author Gerd Knorr * @author Ioana Patrascu * @author Tzvetan Horozov */ #ifndef GNUNET_STRINGS_LIB_H #define GNUNET_STRINGS_LIB_H /* we need size_t, and since it can be both unsigned int or unsigned long long, this IS platform dependent; but "stdlib.h" should be portable 'enough' to be unconditionally available... */ #include #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_time_lib.h" /** * Convert a given fancy human-readable size to bytes. * * @param fancy_size human readable string (i.e. 1 MB) * @param size set to the size in bytes * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_STRINGS_fancy_size_to_bytes (const char *fancy_size, unsigned long long *size); /** * Convert a given fancy human-readable time to our internal * representation. * * @param fancy_time human readable string (i.e. 1 minute) * @param rtime set to the relative time * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_STRINGS_fancy_time_to_relative (const char *fancy_time, struct GNUNET_TIME_Relative *rtime); /** * Convert a given filesize into a fancy human-readable format. * * @param size number of bytes * @return fancy representation of the size (possibly rounded) for humans */ char * GNUNET_STRINGS_byte_size_fancy (unsigned long long size); /** * Convert the len characters long character sequence * given in input that is in the given input charset * to a string in given output charset. * @return the converted string (0-terminated), * if conversion fails, a copy of the orignal * string is returned. */ char * GNUNET_STRINGS_conv (const char *input, size_t len, const char *input_charset, const char *output_charset); /** * Convert the len characters long character sequence * given in input that is in the given charset * to UTF-8. * * @param input the input string (not necessarily 0-terminated) * @param len the number of bytes in the input * @param charset character set to convert from * @return the converted string (0-terminated) */ char * GNUNET_STRINGS_to_utf8 (const char *input, size_t len, const char *charset); /** * Convert the len bytes-long UTF-8 string * given in input to the given charset. * @return the converted string (0-terminated), * if conversion fails, a copy of the orignal * string is returned. */ char * GNUNET_STRINGS_from_utf8 (const char *input, size_t len, const char *charset); /** * Convert the utf-8 input string to lowercase * Output needs to be allocated appropriately * * @param input input string * @param output output buffer */ void GNUNET_STRINGS_utf8_tolower(const char* input, char** output); /** * Convert the utf-8 input string to lowercase * Output needs to be allocated appropriately * * @param input input string * @param output output buffer */ void GNUNET_STRINGS_utf8_toupper(const char* input, char** output); /** * Complete filename (a la shell) from abbrevition. * * @param fil the name of the file, may contain ~/ or * be relative to the current directory * @return the full file name, * NULL is returned on error */ char * GNUNET_STRINGS_filename_expand (const char *fil); /** * Fill a buffer of the given size with * count 0-terminated strings (given as varargs). * If "buffer" is NULL, only compute the amount of * space required (sum of "strlen(arg)+1"). * * Unlike using "snprintf" with "%s", this function * will add 0-terminators after each string. The * "GNUNET_string_buffer_tokenize" function can be * used to parse the buffer back into individual * strings. * * @param buffer the buffer to fill with strings, can * be NULL in which case only the necessary * amount of space will be calculated * @param size number of bytes available in buffer * @param count number of strings that follow * @param ... count 0-terminated strings to copy to buffer * @return number of bytes written to the buffer * (or number of bytes that would have been written) */ size_t GNUNET_STRINGS_buffer_fill (char *buffer, size_t size, unsigned int count, ...); /** * Given a buffer of a given size, find "count" * 0-terminated strings in the buffer and assign * the count (varargs) of type "const char**" to the * locations of the respective strings in the * buffer. * * @param buffer the buffer to parse * @param size size of the buffer * @param count number of strings to locate * @param ... pointers to where to store the strings * @return offset of the character after the last 0-termination * in the buffer, or 0 on error. */ unsigned int GNUNET_STRINGS_buffer_tokenize (const char *buffer, size_t size, unsigned int count, ...); /** * "man ctime_r", except for GNUnet time; also, unlike ctime, the * return value does not include the newline character. * * @param t the absolute time to convert * @return timestamp in human-readable form */ char * GNUNET_STRINGS_absolute_time_to_string (struct GNUNET_TIME_Absolute t); /** * Give relative time in human-readable fancy format. * * @param delta time in milli seconds * @return string in human-readable form */ char * GNUNET_STRINGS_relative_time_to_string (struct GNUNET_TIME_Relative delta); /** * "man basename" * Returns a pointer to a part of filename (allocates nothing)! * * @param filename filename to extract basename from * @return short (base) name of the file (that is, everything following the * last directory separator in filename. If filename ends with a * directory separator, the result will be a zero-length string. * If filename has no directory separators, the result is filename * itself. */ const char * GNUNET_STRINGS_get_short_name (const char *filename); /** * Convert binary data to ASCII encoding. The ASCII encoding is rather * GNUnet specific. It was chosen such that it only uses characters * in [0-9A-V], can be produced without complex arithmetics and uses a * small number of characters. The GNUnet encoding uses 103 characters. * Does not append 0-terminator, but returns a pointer to the place where * it should be placed, if needed. * * @param data data to encode * @param size size of data (in bytes) * @param out buffer to fill * @param out_size size of the buffer. Must be large enough to hold * ((size*8) + (((size*8) % 5) > 0 ? 5 - ((size*8) % 5) : 0)) / 5 * @return pointer to the next byte in 'out' or NULL on error. */ char * GNUNET_STRINGS_data_to_string (const unsigned char *data, size_t size, char *out, size_t out_size); /** * Convert ASCII encoding back to data * out_size must match exactly the size of the data before it was encoded. * * @param enc the encoding * @param enclen number of characters in 'enc' (without 0-terminator, which can be missing) * @param out location where to store the decoded data * @param out_size sizeof the output buffer * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding */ int GNUNET_STRINGS_string_to_data (const char *enc, size_t enclen, unsigned char *out, size_t out_size); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif enum GNUNET_STRINGS_FilenameCheck { GNUNET_STRINGS_CHECK_EXISTS = 0x00000001, GNUNET_STRINGS_CHECK_IS_DIRECTORY = 0x00000002, GNUNET_STRINGS_CHECK_IS_LINK = 0x00000004, GNUNET_STRINGS_CHECK_IS_ABSOLUTE = 0x00000008 }; /** * Parse a path that might be an URI. * * @param path path to parse. Must be NULL-terminated. * @param scheme_part a pointer to 'char *' where a pointer to a string that * represents the URI scheme will be stored. Can be NULL. The string is * allocated by the function, and should be freed by GNUNET_free() when * it is no longer needed. * @param path_part a pointer to 'const char *' where a pointer to the path * part of the URI will be stored. Can be NULL. Points to the same block * of memory as 'path', and thus must not be freed. Might point to '\0', * if path part is zero-length. * @return GNUNET_YES if it's an URI, GNUNET_NO otherwise. If 'path' is not * an URI, '* scheme_part' and '*path_part' will remain unchanged * (if they weren't NULL). */ int GNUNET_STRINGS_parse_uri (const char *path, char **scheme_part, const char **path_part); /** * Check whether filename is absolute or not, and if it's an URI * * @param filename filename to check * @param can_be_uri GNUNET_YES to check for being URI, GNUNET_NO - to * assume it's not URI * @param r_is_uri a pointer to an int that is set to GNUNET_YES if 'filename' * is URI and to GNUNET_NO otherwise. Can be NULL. If 'can_be_uri' is * not GNUNET_YES, *r_is_uri is set to GNUNET_NO. * @param r_uri_scheme a pointer to a char * that is set to a pointer to URI scheme. * The string is allocated by the function, and should be freed with * GNUNET_free (). Can be NULL. * @return GNUNET_YES if 'filename' is absolute, GNUNET_NO otherwise. */ int GNUNET_STRINGS_path_is_absolute (const char *filename, int can_be_uri, int *r_is_uri, char **r_uri_scheme); /** * Perform checks on 'filename; * * @param filename file to check * @param checks checks to perform * @return GNUNET_YES if all checks pass, GNUNET_NO if at least one of them * fails, GNUNET_SYSERR when a check can't be performed */ int GNUNET_STRINGS_check_filename (const char *filename, enum GNUNET_STRINGS_FilenameCheck checks); /** * Tries to convert 'zt_addr' string to an IPv6 address. * The string is expected to have the format "[ABCD::01]:80". * * @param zt_addr 0-terminated string. May be mangled by the function. * @param addrlen length of zt_addr (not counting 0-terminator). * @param r_buf a buffer to fill. Initially gets filled with zeroes, * then its sin6_port, sin6_family and sin6_addr are set appropriately. * @return GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which * case the contents of r_buf are undefined. */ int GNUNET_STRINGS_to_address_ipv6 (const char *zt_addr, uint16_t addrlen, struct sockaddr_in6 *r_buf); /** * Tries to convert 'zt_addr' string to an IPv4 address. * The string is expected to have the format "1.2.3.4:80". * * @param zt_addr 0-terminated string. May be mangled by the function. * @param addrlen length of zt_addr (not counting 0-terminator). * @param r_buf a buffer to fill. * @return GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which case * the contents of r_buf are undefined. */ int GNUNET_STRINGS_to_address_ipv4 (const char *zt_addr, uint16_t addrlen, struct sockaddr_in *r_buf); /** * Tries to convert 'addr' string to an IP (v4 or v6) address. * Will automatically decide whether to treat 'addr' as v4 or v6 address. * * @param addr a string, may not be 0-terminated. * @param addrlen number of bytes in addr (if addr is 0-terminated, * 0-terminator should not be counted towards addrlen). * @param r_buf a buffer to fill. * @return GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which * case the contents of r_buf are undefined. */ int GNUNET_STRINGS_to_address_ip (const char *addr, uint16_t addrlen, struct sockaddr_storage *r_buf); /* ifndef GNUNET_UTIL_STRING_H */ #endif /* end of gnunet_util_string.h */ gnunet-0.9.3/src/include/platform.h0000644000175000017500000001216411761753145014171 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/platform.h * @brief plaform specifics * * @author Nils Durner * * This file should never be included by installed * header files (thos starting with "gnunet_"). */ #ifndef PLATFORM_H #define PLATFORM_H #ifndef HAVE_USED_CONFIG_H #define HAVE_USED_CONFIG_H #if HAVE_CONFIG_H #include "gnunet_config.h" #endif #endif #ifdef WINDOWS #define BREAKPOINT asm("int $3;"); #define GNUNET_SIGCHLD 17 #else #define BREAKPOINT #define GNUNET_SIGCHLD SIGCHLD #endif #ifdef HAVE_SYS_TYPES_H #include #endif #define ALLOW_EXTRA_CHECKS GNUNET_NO /** * For strptime (glibc2 needs this). */ #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE #endif #ifndef _REENTRANT #define _REENTRANT #endif /* configuration options */ #define VERBOSE_STATS 0 #ifdef CYGWIN #include #endif #ifdef _MSC_VER #ifndef FD_SETSIZE #define FD_SETSIZE 1024 #endif #include #include #else #ifndef MINGW #include #include #include #if HAVE_NETINET_IN_H #include #endif #if HAVE_NETINET_IN_SYSTM_H #include #endif #include /* superset of previous */ #include #include #include #include #include #include #else #include "winproc.h" #endif #endif #include #include #include #include #include #include #include #include #ifdef WINDOWS #include /* for alloca(), on other OSes it's in stdlib.h */ #endif #ifndef _MSC_VER #include /* KLB_FIX */ #endif #include #include #ifndef _MSC_VER #include /* KLB_FIX */ #endif #include #include #if HAVE_SYS_PARAM_H #include #endif #if TIME_WITH_SYS_TIME #include #include #else #if HAVE_SYS_TIME_H #include #else #include #endif #endif #ifdef SOMEBSD #include #endif #ifdef GNUNET_freeBSD #include #endif #ifdef DARWIN #include #include #include #endif #ifdef LINUX #include #endif #ifdef SOLARIS #include #include #include #include #endif #if HAVE_UCRED_H #include #endif #ifdef CYGWIN #include #include #endif #if HAVE_IFADDRS_H #include #endif #include #include #if HAVE_VFORK_H #include #endif #include #if HAVE_SYS_RESOURCE_H #include #endif #if HAVE_ENDIAN_H #include #endif #if HAVE_SYS_ENDIAN_H #include #endif #include "plibc.h" #include #ifndef FRAMEWORK_BUILD #include "gettext.h" /** * GNU gettext support macro. */ #define _(String) dgettext("gnunet",String) #define LIBEXTRACTOR_GETTEXT_DOMAIN "libextractor" #else #include "libintlemu.h" #define _(String) dgettext("org.gnunet.gnunet",String) #define LIBEXTRACTOR_GETTEXT_DOMAIN "org.gnunet.libextractor" #endif #ifdef CYGWIN #define SIOCGIFCONF _IOW('s', 100, struct ifconf) /* get if list */ #define SIOCGIFFLAGS _IOW('s', 101, struct ifreq) /* Get if flags */ #define SIOCGIFADDR _IOW('s', 102, struct ifreq) /* Get if addr */ #endif #ifndef MINGW #include #endif #ifdef FREEBSD #define __BYTE_ORDER BYTE_ORDER #define __BIG_ENDIAN BIG_ENDIAN #endif #ifdef DARWIN #define __BYTE_ORDER BYTE_ORDER #define __BIG_ENDIAN BIG_ENDIAN /* not available on darwin, override configure */ #undef HAVE_STAT64 #undef HAVE_MREMAP #endif #if !HAVE_ATOLL long long atoll (const char *nptr); #endif #if ENABLE_NLS #include "langinfo.h" #endif #ifndef SIZE_MAX #define SIZE_MAX ((size_t)(-1)) #endif #ifndef O_LARGEFILE #define O_LARGEFILE 0 #endif /** * AI_NUMERICSERV not defined in windows. Then we just do without. */ #ifndef AI_NUMERICSERV #define AI_NUMERICSERV 0 #endif #if defined(__sparc__) #define MAKE_UNALIGNED(val) ({ __typeof__((val)) __tmp; memmove(&__tmp, &(val), sizeof((val))); __tmp; }) #else #define MAKE_UNALIGNED(val) val #endif #if WINDOWS #define FDTYPE HANDLE #define SOCKTYPE SOCKET #else #define FDTYPE int #define SOCKTYPE int #endif #endif gnunet-0.9.3/src/include/gnunet_load_lib.h0000644000175000017500000000555211760502551015465 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_load_lib.h * @brief functions related to load calculations * @author Christian Grothoff */ #ifndef GNUNET_LOAD_LIB_H #define GNUNET_LOAD_LIB_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_common.h" #include "gnunet_time_lib.h" /** * Opaque load handle. */ struct GNUNET_LOAD_Value; /** * Create a new load value. * * @param autodecline speed at which this value should automatically * decline in the absence of external events; at the given * frequency, 0-load values will be added to the load * @return the new load value */ struct GNUNET_LOAD_Value * GNUNET_LOAD_value_init (struct GNUNET_TIME_Relative autodecline); /** * Change the value by which the load automatically declines. * * @param load load to update * @param autodecline frequency of load decline */ void GNUNET_LOAD_value_set_decline (struct GNUNET_LOAD_Value *load, struct GNUNET_TIME_Relative autodecline); /** * Free a load value. * * @param lv value to free */ #define GNUNET_LOAD_value_free(lv) GNUNET_free (lv) /** * Get the current load. * * @param load load handle * @return zero for below-average load, otherwise * number of std. devs we are above average; * 100 if the latest updates were so large * that we could not do proper calculations */ double GNUNET_LOAD_get_load (struct GNUNET_LOAD_Value *load); /** * Get the average value given to update so far. * * @param load load handle * @return zero if update was never called */ double GNUNET_LOAD_get_average (struct GNUNET_LOAD_Value *load); /** * Update the current load. * * @param load to update * @param data latest measurement value (for example, delay) */ void GNUNET_LOAD_update (struct GNUNET_LOAD_Value *load, uint64_t data); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_LOAD_LIB_H */ #endif /* end of gnunet_load_lib.h */ gnunet-0.9.3/src/include/gnunet_ats_service.h0000644000175000017500000005607111760502551016231 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_ats_service.h * @brief automatic transport selection and outbound bandwidth determination * @author Christian Grothoff * @author Matthias Wachs */ #ifndef GNUNET_ATS_SERVICE_H #define GNUNET_ATS_SERVICE_H #include "gnunet_constants.h" #include "gnunet_util_lib.h" #include "gnunet_hello_lib.h" enum GNUNET_ATS_Network_Type { GNUNET_ATS_NET_UNSPECIFIED = 0, GNUNET_ATS_NET_LOOPBACK = 1, GNUNET_ATS_NET_LAN = 2, GNUNET_ATS_NET_WAN = 3, GNUNET_ATS_NET_WLAN = 4, }; /** * Enum defining all known property types for ATS Enum values are used * in the GNUNET_ATS_Information struct as * (key,value)-pairs. * * Cost are always stored in uint32_t, so all units used to define costs * have to be normalized to fit in uint32_t [0 .. 4.294.967.295] */ enum GNUNET_ATS_Property { /** * End of the array. * @deprecated */ GNUNET_ATS_ARRAY_TERMINATOR = 0, /** * Actual traffic on this connection from the other peer to this peer. * * Unit: [bytes/second] */ GNUNET_ATS_UTILIZATION_UP, /** * Actual traffic on this connection from this peer to the other peer. * * Unit: [bytes/second] */ GNUNET_ATS_UTILIZATION_DOWN, /** * Is this address located in WAN, LAN or a loopback address * Value is element of GNUNET_ATS_Network_Type */ GNUNET_ATS_NETWORK_TYPE, /** * Delay * Time between when the time packet is sent and the packet arrives * * Unit: [ms] * * Examples: * * LAN : 1 * WLAN : 2 * Dialup: 500 */ GNUNET_ATS_QUALITY_NET_DELAY, /** * Distance on network layer (required for distance-vector routing). * * Unit: [DV-hops] */ GNUNET_ATS_QUALITY_NET_DISTANCE, /** * Network overhead on WAN (Wide-Area Network) * * How many bytes are sent on the WAN when 1 kilobyte (1024 bytes) * of application data is transmitted? * A factor used with connect cost, bandwidth cost and energy cost * to describe the overhead produced by the transport protocol * * Unit: [bytes/kb] * * Interpretation: less is better * * Examples: * * TCP/IPv4 over Ethernet: 1024 + 38 + 20 + 20 = 1102 [bytes/kb] * TCP/IPv6 over Ethernet: 1024 + 38 + 20 + 40 = 1122 [bytes/kb] * UDP/IPv4 over Ethernet: 1024 + 38 + 20 + 8 = 1090 [bytes/kb] * UDP/IPv6 over Ethernet: 1024 + 38 + 40 + 8 = 1110 [bytes/kb] */ GNUNET_ATS_COST_WAN, /** * Network overhead on LAN (Local-Area Network) * * How many bytes are sent on the LAN when 1 kilobyte (1024 bytes) * of application data is transmitted? * A factor used with connect cost, bandwidth cost and energy cost * to describe the overhead produced by the transport protocol * * Unit: [bytes/kb] * * Interpretation: less is better * * Examples: * * TCP/IPv4 over Ethernet: 1024 + 38 + 20 + 20 = 1102 [bytes/kb] * TCP/IPv6 over Ethernet: 1024 + 38 + 20 + 40 = 1122 [bytes/kb] * UDP/IPv4 over Ethernet: 1024 + 38 + 20 + 8 = 1090 [bytes/kb] * UDP/IPv6 over Ethernet: 1024 + 38 + 40 + 8 = 1110 [bytes/kb] */ GNUNET_ATS_COST_LAN, /** * Network overhead on WLAN (Wireless Local Area Network) * * How many bytes are sent on the LAN when 1 kilobyte (1024 bytes) * of application data is transmitted? * A factor used with connect cost, bandwidth cost and energy cost * to describe the overhead produced by the transport protocol * * Unit: [bytes/kb] * * Interpretation: less is better * * Examples: * * TCP/IPv4 over Ethernet: 1024 + 38 + 20 + 20 = 1102 [bytes/kb] * TCP/IPv6 over Ethernet: 1024 + 38 + 20 + 40 = 1122 [bytes/kb] * UDP/IPv4 over Ethernet: 1024 + 38 + 20 + 8 = 1090 [bytes/kb] * UDP/IPv6 over Ethernet: 1024 + 38 + 40 + 8 = 1110 [bytes/kb] */ GNUNET_ATS_COST_WLAN /* Cost related values */ /* =================== */ /** * Volume based cost in financial units to transmit data * * Note: This value is not bound to a specific currency or unit and only * used locally. * "cent" just refers the smallest amount of money in the respective * currency. * * Unit: [cent/MB] * * Interpretation: less is better * * Examples: * LAN: 0 [cent/MB] * 2G : 10 [cent/MB] */ // GNUNET_ATS_COST_FINANCIAL_PER_VOLUME = 1, /** * Time based cost in financial units to transmit data * * Note: This value is not bound to a specific currency or unit and only * used locally. * "cent" just refers the smallest amount of money in the respective * currency. * * Unit: [cent/h] * * Interpretation: less is better * * Examples: * LAN : 0 [cent/h] * Dialup: 10 [cent/h] */ // GNUNET_ATS_COST_FINANCIAL_PER_TIME = 2, /** * Computational costs * * Effort of preparing data to be sent with this transport * Includes encoding, encryption and conversion of data * Partial values can be summed up: c_sum = c_enc + c_enc + c_conv * Resulting values depend on local system properties, e.g. CPU * * Unit: [ms/GB] * * Interpretation: less is better * * Examples: * * HTTPS with AES CBC-256: 7,382 * HTTPS with AES CBC-128: 5,279 * HTTPS with RC4-1024: 2,652 */ // GNUNET_ATS_COST_COMPUTATIONAL = 3, /** * Energy consumption * * Energy consumption using this transport when sending with a certain * power at a certain bitrate. This is only an approximation based on: * Energy consumption E = P / D * * with: * Power P in Watt (J/s) * Datarate D in MBit/s * * Conversion between power P and dBm used by WLAN in radiotap's dBm TX power: * * Lp(dbm) = 10 log10 (P/ 1mW) * * => P = 1 mW * 10^(Lp(dbm)/10) * * Unit: [mJ/MB] * * Interpretation: less is better * * Examples: * * LAN: 0 * WLAN: 89 (600 mW @ 802.11g /w 54 MBit/s) * Bluetooth: 267 (100 mW @ BT2.0 EDR /w 3 MBit/s) */ // GNUNET_ATS_COST_ENERGY_CONSUMPTION = 4, /** * Connect cost * How many bytes are transmitted to initiate a new connection using * this transport? * * Unit: [bytes] * * Interpretation: less is better * * Examples: * * UDP (No connection) : * 0 bytes * TCP (TCP 3-Way handshake): * 220 bytes Ethernet, 172 bytes TCP/IP, 122 bytes TCP * HTTP (TCP + Header) : * 477 bytes Ethernet, 429 bytes TCP/IP, 374 bytes TCP, 278 bytes HTTP * HTTPS HTTP+TLS Handshake: * 2129 bytes Ethernet, 1975 bytes TCP/IP, 1755 bytes TCP, 1403 bytes HTTPS * * */ // GNUNET_ATS_COST_CONNECT = 5, /** * Bandwidth cost * * How many bandwidth is available to consume? * Used to calculate which impact sending data with this transport has * * Unit: [kB/s] * * Interpretation: more is better * * Examples: * LAN: 12,800 (100 MBit/s) * WLAN: 6,912 (54 MBit/s) * Dial-up: 8 (64 Kbit/s) * */ // GNUNET_ATS_COST_BANDWITH_AVAILABLE = 6, /** * Network overhead * * How many bytes are sent over the wire when 1 kilobyte (1024 bytes) * of application data is transmitted? * A factor used with connect cost, bandwidth cost and energy cost * to describe the overhead produced by the transport protocol * * Unit: [bytes/kb] * * Interpretation: less is better * * Examples: * * TCP/IPv4 over Ethernet: 1024 + 38 + 20 + 20 = 1102 [bytes/kb] * TCP/IPv6 over Ethernet: 1024 + 38 + 20 + 40 = 1122 [bytes/kb] * UDP/IPv4 over Ethernet: 1024 + 38 + 20 + 8 = 1090 [bytes/kb] * UDP/IPv6 over Ethernet: 1024 + 38 + 40 + 8 = 1110 [bytes/kb] */ // GNUNET_ATS_COST_NETWORK_OVERHEAD = 7, /* Quality related values */ /* ====================== */ /* Physical layer quality properties */ /** * Signal strength on physical layer * * Unit: [dBm] */ // GNUNET_ATS_QUALITY_PHY_SIGNAL_STRENGTH = 1025, /** * Collision rate on physical layer * * Unit: [B/s] */ // GNUNET_ATS_QUALITY_PHY_COLLISION_RATE = 1026, /** * Error rate on physical layer * * Unit: [B/s] */ // GNUNET_ATS_QUALITY_PHY_ERROR_RATE = 1027, /** * Jitter * Time variations of the delay * 1st derivative of a delay function * * Unit: [ms] */ // GNUNET_ATS_QUALITY_NET_JITTER = 1029, /** * Error rate on network layer * * Unit: [B/s] * * Examples: * * LAN : 0 * WLAN : 400 * Bluetooth : 100 * Note: This numbers are just assumptions as an example, not * measured or somehow determined */ // GNUNET_ATS_QUALITY_NET_ERRORRATE = 1030, /** * Drop rate on network layer * Bytes actively dismissed by a network component during transmission * Reasons for dropped data can be full queues, congestion, quota violations... * * Unit: [B/s] * * Examples: * * LAN : 0 * WLAN : 400 * Bluetooth : 100 * Note: This numbers are just assumptions as an example, not * measured or somehow determined */ // GNUNET_ATS_QUALITY_NET_DROPRATE = 1031, /** * Loss rate on network layer * Bytes lost during transmission * Reasons can be collisions, ... * * Unit: [B/s] * * Examples: * * LAN : 0 * WLAN : 40 * Bluetooth : 10 * Note: This numbers are just assumptions as an example, not measured * or somehow determined */ // GNUNET_ATS_QUALITY_NET_LOSSRATE = 1032, /** * Throughput on network layer * * Unit: [kB/s] * * Examples: * * LAN : 3400 * WLAN : 1200 * Dialup: 4 * */ // GNUNET_ATS_QUALITY_NET_THROUGHPUT = 1033, /* Availability related values */ /* =========================== */ /** * Is a peer reachable? */ // GNUNET_ATS_AVAILABILITY_REACHABLE = 2048, /** * Is there a connection established to a peer using this transport */ // GNUNET_ATS_AVAILABILITY_CONNECTED = 2049 }; /** * Number of ATS quality properties */ #define GNUNET_ATS_QualityPropertiesCount 2 /** * ATS quality properties as array initializer */ #define GNUNET_ATS_QualityProperties {GNUNET_ATS_QUALITY_NET_DELAY, GNUNET_ATS_QUALITY_NET_DISTANCE} /** * Number of ATS quality properties */ #define GNUNET_ATS_NetworkTypeCount 5 /** * ATS quality properties as array initializer */ #define GNUNET_ATS_NetworkType {GNUNET_ATS_NET_UNSPECIFIED, GNUNET_ATS_NET_LOOPBACK, GNUNET_ATS_NET_LAN, GNUNET_ATS_NET_WAN, GNUNET_ATS_NET_WLAN} GNUNET_NETWORK_STRUCT_BEGIN /** * struct used to communicate the transport's properties like cost and * quality of service as well as high-level constraints on resource * consumption. * * +---+ * +-----------+ Constraints | | Plugin properties +---------+ * | Highlevel |------------> |ATS| <------------------|Transport| * | Component | ATS struct | | ATS struct | Plugin | * +-----------+ | | +---------+ * +---+ * * This structure will be used by transport plugins to communicate * costs to ATS or by higher level components to tell ATS their * constraints. Always a pair of (GNUNET_ATS_Property, * uint32_t value). Value is always uint32_t, so all units used to * define costs have to be normalized to fit uint32_t. */ struct GNUNET_ATS_Information { /** * ATS property type, in network byte order. */ uint32_t type GNUNET_PACKED; /** * ATS property value, in network byte order. */ uint32_t value GNUNET_PACKED; }; GNUNET_NETWORK_STRUCT_END /* ******************************** Scheduling API ***************************** */ /** * Handle to the ATS subsystem for bandwidth/transport scheduling information. */ struct GNUNET_ATS_SchedulingHandle; /** * Opaque session handle, defined by plugins. Contents not known to ATS. */ struct Session; /** * Signature of a function called by ATS with the current bandwidth * and address preferences as determined by ATS. * * @param cls closure * @param address suggested address (including peer identity of the peer) * @param session session to use * @param bandwidth_out assigned outbound bandwidth for the connection * @param bandwidth_in assigned inbound bandwidth for the connection * @param ats performance data for the address (as far as known) * @param ats_count number of performance records in 'ats' */ typedef void (*GNUNET_ATS_AddressSuggestionCallback) (void *cls, const struct GNUNET_HELLO_Address * address, struct Session * session, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, const struct GNUNET_ATS_Information * ats, uint32_t ats_count); /** * Initialize the ATS subsystem. * * @param cfg configuration to use * @param suggest_cb notification to call whenever the suggestation changed * @param suggest_cb_cls closure for 'suggest_cb' * @return ats context */ struct GNUNET_ATS_SchedulingHandle * GNUNET_ATS_scheduling_init (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_ATS_AddressSuggestionCallback suggest_cb, void *suggest_cb_cls); /** * Client is done with ATS scheduling, release resources. * * @param sh handle to release */ void GNUNET_ATS_scheduling_done (struct GNUNET_ATS_SchedulingHandle *sh); /** * We would like to reset the address suggestion block time for this * peer * * @param sh handle * @param peer identity of the peer we want to reset */ void GNUNET_ATS_reset_backoff (struct GNUNET_ATS_SchedulingHandle *sh, const struct GNUNET_PeerIdentity *peer); /** * We would like to establish a new connection with a peer. ATS * should suggest a good address to begin with. * * @param sh handle * @param peer identity of the peer we need an address for */ void GNUNET_ATS_suggest_address (struct GNUNET_ATS_SchedulingHandle *sh, const struct GNUNET_PeerIdentity *peer); /** * We want to cancel ATS suggesting addresses for a peer. * * @param sh handle * @param peer identity of the peer */ void GNUNET_ATS_suggest_address_cancel (struct GNUNET_ATS_SchedulingHandle *sh, const struct GNUNET_PeerIdentity *peer); /** * Returns where the address is located: LAN or WAN or ... * @param sh the GNUNET_ATS_SchedulingHandle handle * @param addr address * @param addrlen address length * @return location as GNUNET_ATS_Information */ struct GNUNET_ATS_Information GNUNET_ATS_address_get_type (struct GNUNET_ATS_SchedulingHandle *sh, const struct sockaddr * addr, socklen_t addrlen); /** * We have updated performance statistics for a given address. Note * that this function can be called for addresses that are currently * in use as well as addresses that are valid but not actively in use. * Furthermore, the peer may not even be connected to us right now (in * which case the call may be ignored or the information may be stored * for later use). Update bandwidth assignments. * * @param sh handle * @param address updated address * @param session session handle (if available) * @param ats performance data for the address * @param ats_count number of performance records in 'ats' */ void GNUNET_ATS_address_update (struct GNUNET_ATS_SchedulingHandle *sh, const struct GNUNET_HELLO_Address *address, struct Session *session, const struct GNUNET_ATS_Information *ats, uint32_t ats_count); /** * An address is now in use or not used any more. * * @param sh handle * @param address the address * @param session session handle * @param in_use GNUNET_YES if this address is now used, GNUNET_NO * if address is not used any more */ void GNUNET_ATS_address_in_use (struct GNUNET_ATS_SchedulingHandle *sh, const struct GNUNET_HELLO_Address *address, struct Session *session, int in_use); /** * A session got destroyed, stop including it as a valid address. * * @param sh handle * @param address the address * @param session session handle that is no longer valid (if available) */ void GNUNET_ATS_address_destroyed (struct GNUNET_ATS_SchedulingHandle *sh, const struct GNUNET_HELLO_Address *address, struct Session *session); /* ******************************** Performance API ***************************** */ /** * ATS Handle to obtain and/or modify performance information. */ struct GNUNET_ATS_PerformanceHandle; /** * Signature of a function that is called with QoS information about a peer. * * @param cls closure * @param address the address * @param bandwidth_out assigned outbound bandwidth for the connection * @param bandwidth_in assigned inbound bandwidth for the connection * @param ats performance data for the address (as far as known) * @param ats_count number of performance records in 'ats' */ typedef void (*GNUNET_ATS_PeerInformationCallback) (void *cls, const struct GNUNET_HELLO_Address * address, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, const struct GNUNET_ATS_Information * ats, uint32_t ats_count); /** * Get handle to access performance API of the ATS subsystem. * * @param cfg configuration to use * @param infocb function to call on performance changes, can be NULL * @param infocb_cls closure for infocb * @return ats performance context */ struct GNUNET_ATS_PerformanceHandle * GNUNET_ATS_performance_init (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_ATS_PeerInformationCallback infocb, void *infocb_cls); /** * Client is done using the ATS performance subsystem, release resources. * * @param ph handle */ void GNUNET_ATS_performance_done (struct GNUNET_ATS_PerformanceHandle *ph); /** * Function called with reservation result. * * @param cls closure * @param peer identifies the peer * @param amount set to the amount that was actually reserved or unreserved; * either the full requested amount or zero (no partial reservations) * @param res_delay if the reservation could not be satisfied (amount was 0), how * long should the client wait until re-trying? */ typedef void (*GNUNET_ATS_ReservationCallback) (void *cls, const struct GNUNET_PeerIdentity * peer, int32_t amount, struct GNUNET_TIME_Relative res_delay); /** * Context that can be used to cancel a peer information request. */ struct GNUNET_ATS_ReservationContext; /** * Reserve inbound bandwidth from the given peer. ATS will look at * the current amount of traffic we receive from the peer and ensure * that the peer could add 'amount' of data to its stream. * * @param ph performance handle * @param peer identifies the peer * @param amount reserve N bytes for receiving, negative * amounts can be used to undo a (recent) reservation; * @param rcb function to call with the resulting reservation information * @param rcb_cls closure for info * @return NULL on error * @deprecated will be replaced soon */ struct GNUNET_ATS_ReservationContext * GNUNET_ATS_reserve_bandwidth (struct GNUNET_ATS_PerformanceHandle *ph, const struct GNUNET_PeerIdentity *peer, int32_t amount, GNUNET_ATS_ReservationCallback rcb, void *rcb_cls); /** * Cancel request for reserving bandwidth. * * @param rc context returned by the original GNUNET_ATS_reserve_bandwidth call */ void GNUNET_ATS_reserve_bandwidth_cancel (struct GNUNET_ATS_ReservationContext *rc); /** * Enum defining all known preference categories. */ enum GNUNET_ATS_PreferenceKind { /** * End of preference list. */ GNUNET_ATS_PREFERENCE_END = 0, /** * Change the peer's bandwidth value (value per byte of bandwidth in * the goal function) to the given amount. The argument is followed * by a double value giving the desired value (can be negative). * Preference changes are forgotten if peers disconnect. */ GNUNET_ATS_PREFERENCE_BANDWIDTH, /** * Change the peer's latency value to the given amount. The * argument is followed by a double value giving the desired value * (can be negative). The absolute score in the goal function is * the inverse of the latency in ms (minimum: 1 ms) multiplied by * the latency preferences. */ GNUNET_ATS_PREFERENCE_LATENCY }; /** * Change preferences for the given peer. Preference changes are forgotten if peers * disconnect. * * @param ph performance handle * @param peer identifies the peer * @param ... 0-terminated specification of the desired changes */ void GNUNET_ATS_change_preference (struct GNUNET_ATS_PerformanceHandle *ph, const struct GNUNET_PeerIdentity *peer, ...); #endif /* end of file gnunet-service-transport_ats.h */ gnunet-0.9.3/src/include/gnunet_getopt_lib.h0000644000175000017500000002444411760502551016051 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_getopt_lib.h * @brief command line parsing and --help formatting * * @author Christian Grothoff */ #ifndef GNUNET_GETOPT_LIB_H #define GNUNET_GETOPT_LIB_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_configuration_lib.h" /** * @brief General context for command line processors. */ struct GNUNET_GETOPT_CommandLineProcessorContext { /** * Name of the application */ const char *binaryName; /** * Name of application with option summary */ const char *binaryOptions; /** * Array with all command line options. */ const struct GNUNET_GETOPT_CommandLineOption *allOptions; /** * Original command line */ char *const *argv; /** * Total number of argv's. */ unsigned int argc; /** * Current argument. */ unsigned int currentArgument; }; /** * @brief Process a command line option * * @param ctx context for all options * @param scls specific closure (for this processor) * @param option long name of the option (i.e. "config" for --config) * @param value argument, NULL if none was given * @return GNUNET_OK to continue processing other options, GNUNET_SYSERR to abort */ typedef int (*GNUNET_GETOPT_CommandLineOptionProcessor) (struct GNUNET_GETOPT_CommandLineProcessorContext * ctx, void *scls, const char *option, const char *value); /** * @brief Definition of a command line option. */ struct GNUNET_GETOPT_CommandLineOption { /** * Short name of the option (use '\\0' for none). */ const char shortName; /** * Long name of the option (may not be NULL) */ const char *name; /** * Name of the argument for the user in help text */ const char *argumentHelp; /** * Help text for the option (description) */ const char *description; /** * Is an argument required? 0: GNUNET_NO (includes optional), 1: GNUNET_YES. */ int require_argument; /** * Handler for the option. */ GNUNET_GETOPT_CommandLineOptionProcessor processor; /** * Specific closure to pass to the processor. */ void *scls; }; /** * Macro defining the option to print the command line * help text (-h option). * * @param about string with brief description of the application */ #define GNUNET_GETOPT_OPTION_HELP(about) \ { 'h', "help", (const char *) NULL, gettext_noop("print this help"), 0, &GNUNET_GETOPT_format_help_, (void *) about } /** * Macro defining the option to print the version of * the application (-v option) * * @param version string with the version number */ #define GNUNET_GETOPT_OPTION_VERSION(version) \ { 'v', "version", (const char *) NULL, gettext_noop("print the version number"), 0, &GNUNET_GETOPT_print_version_, (void *) version } /** * Allow user to specify log file name (-l option) * * @param logfn set to the name of the logfile */ #define GNUNET_GETOPT_OPTION_LOGFILE(logfn) \ { 'l', "logfile", "LOGFILE", gettext_noop("configure logging to write logs to LOGFILE"), 1, &GNUNET_GETOPT_set_string, (void *) logfn } /** * Allow user to specify log level (-L option) * * @param loglev set to the log level */ #define GNUNET_GETOPT_OPTION_LOGLEVEL(loglev) \ { 'L', "log", "LOGLEVEL", gettext_noop("configure logging to use LOGLEVEL"), 1, &GNUNET_GETOPT_set_string, (void *) loglev } /** * Get number of verbose (-V) flags * * @param level where to store the verbosity level (should be an 'int') */ #define GNUNET_GETOPT_OPTION_VERBOSE(level) \ { 'V', "verbose", (const char *) NULL, gettext_noop("be verbose"), 0, &GNUNET_GETOPT_increment_value, (void *) level } /** * Get configuration file name (-c option) * * @param fn set to the configuration file name */ #define GNUNET_GETOPT_OPTION_CFG_FILE(fn) \ { 'c', "config", "FILENAME", gettext_noop("use configuration file FILENAME"), 1, &GNUNET_GETOPT_set_string, (void *) fn } /** * Marker for the end of the list of options. */ #define GNUNET_GETOPT_OPTION_END \ { '\0', NULL, NULL, NULL, 0, NULL, NULL } /** * Parse the command line. * * @param binaryOptions Name of application with option summary * @param allOptions defined options and handlers * @param argc number of arguments * @param argv actual arguments * @return index into argv with first non-option * argument, or GNUNET_SYSERR on error */ int GNUNET_GETOPT_run (const char *binaryOptions, const struct GNUNET_GETOPT_CommandLineOption *allOptions, unsigned int argc, char *const *argv); /** * Set an option of type 'unsigned long long' from the command line. * A pointer to this function should be passed as part of the * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options * of this type. It should be followed by a pointer to a value of * type 'unsigned long long'. * * @param ctx command line processing context * @param scls additional closure (will point to the 'unsigned long long') * @param option name of the option * @param value actual value of the option as a string. * @return GNUNET_OK if parsing the value worked */ int GNUNET_GETOPT_set_ulong (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, const char *value); /** * Set an option of type 'unsigned int' from the command line. * A pointer to this function should be passed as part of the * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options * of this type. It should be followed by a pointer to a value of * type 'unsigned int'. * * @param ctx command line processing context * @param scls additional closure (will point to the 'unsigned int') * @param option name of the option * @param value actual value of the option as a string. * @return GNUNET_OK if parsing the value worked */ int GNUNET_GETOPT_set_uint (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, const char *value); /** * Set an option of type 'int' from the command line to 1 if the * given option is present. * A pointer to this function should be passed as part of the * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options * of this type. It should be followed by a pointer to a value of * type 'int'. * * @param ctx command line processing context * @param scls additional closure (will point to the 'int') * @param option name of the option * @param value not used (NULL) * @return GNUNET_OK */ int GNUNET_GETOPT_set_one (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, const char *value); /** * Set an option of type 'char *' from the command line. * A pointer to this function should be passed as part of the * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options * of this type. It should be followed by a pointer to a value of * type 'char *'. * * @param ctx command line processing context * @param scls additional closure (will point to the 'char *', * which will be allocated) * @param option name of the option * @param value actual value of the option (a string) * @return GNUNET_OK */ int GNUNET_GETOPT_set_string (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, const char *value); /** * Set an option of type 'unsigned int' from the command line. Each * time the option flag is given, the value is incremented by one. * A pointer to this function should be passed as part of the * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options * of this type. It should be followed by a pointer to a value of * type 'int'. * * @param ctx command line processing context * @param scls additional closure (will point to the 'int') * @param option name of the option * @param value not used (NULL) * @return GNUNET_OK */ int GNUNET_GETOPT_increment_value (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, const char *value); /* *************** internal prototypes - use macros above! ************* */ /** * Print out details on command line options (implements --help). * * @param ctx command line processing context * @param scls additional closure (points to about text) * @param option name of the option * @param value not used (NULL) * @return GNUNET_SYSERR (do not continue) */ int GNUNET_GETOPT_format_help_ (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, const char *value); /** * Print out program version (implements --version). * * @param ctx command line processing context * @param scls additional closure (points to version string) * @param option name of the option * @param value not used (NULL) * @return GNUNET_SYSERR (do not continue) */ int GNUNET_GETOPT_print_version_ (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, const char *value); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_GETOPT_LIB_H */ #endif /* end of gnunet_getopt_lib.h */ gnunet-0.9.3/src/include/Makefile.am0000644000175000017500000000375011762207554014230 00000000000000SUBDIRS = . gnunetincludedir = $(includedir)/gnunet nodist_gnunetinclude_HEADERS = \ gnunet_directories.h \ block_fs.h if MINGW WINPROC = winproc.h endif gnunetinclude_HEADERS = \ gauger.h \ gettext.h \ platform.h \ plibc.h \ $(WINPROC) \ block_dns.h \ block_gns.h \ block_fs.h \ gnunet_applications.h \ gnunet_arm_service.h \ gnunet_ats_service.h \ gnunet_bandwidth_lib.h \ gnunet_bio_lib.h \ gnunet_block_lib.h \ gnunet_block_plugin.h \ gnunet_client_lib.h \ gnunet_chat_service.h \ gnunet_common.h \ gnunet_constants.h \ gnunet_configuration_lib.h \ gnunet_container_lib.h \ gnunet_connection_lib.h \ gnunet_core_service.h \ gnunet_crypto_lib.h \ gnunet_datacache_lib.h \ gnunet_datacache_plugin.h \ gnunet_datastore_service.h \ gnunet_datastore_plugin.h \ gnunet_dht_service.h \ gnunet_disk_lib.h \ gnunet_dnsparser_lib.h \ gnunet_dns_service.h \ gnunet_dv_service.h \ gnunet_fragmentation_lib.h \ gnunet_fs_service.h \ gnunet_getopt_lib.h \ gnunet_gns_service.h \ gnunet_hello_lib.h \ gnunet_helper_lib.h \ gnunet_load_lib.h \ gnunet_lockmanager_service.h \ gnunet_mesh_service.h \ gnunet_mysql_lib.h \ gnunet_namestore_plugin.h \ gnunet_namestore_service.h \ gnunet_nat_lib.h \ gnunet_network_lib.h \ gnunet_nse_service.h \ gnunet_os_lib.h \ gnunet_peer_lib.h \ gnunet_peerinfo_service.h \ gnunet_plugin_lib.h \ gnunet_postgres_lib.h \ gnunet_program_lib.h \ gnunet_protocols.h \ gnunet_pseudonym_lib.h \ gnunet_resolver_service.h \ gnunet_regex_lib.h \ gnunet_scheduler_lib.h \ gnunet_server_lib.h \ gnunet_service_lib.h \ gnunet_signal_lib.h \ gnunet_signatures.h \ gnunet_statistics_service.h \ gnunet_stream_lib.h \ gnunet_strings_lib.h \ gnunet_testbed_service.h \ gnunet_testing_lib.h \ gnunet_testing_lib-new.h \ gnunet_time_lib.h \ gnunet_transport_service.h \ gnunet_transport_plugin.h \ gnunet_tun_lib.h \ gnunet_util_lib.h \ gnunet_vpn_service.h gnunet-0.9.3/src/include/gnunet_configuration_lib.h0000644000175000017500000003440011760502551017407 00000000000000/* This file is part of GNUnet. (C) 2006, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_configuration_lib.h * @brief configuration API * * @author Christian Grothoff */ #ifndef GNUNET_CONFIGURATION_LIB_H #define GNUNET_CONFIGURATION_LIB_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_common.h" #include "gnunet_time_lib.h" /** * A configuration object. */ struct GNUNET_CONFIGURATION_Handle; /** * Create a new configuration object. * @return fresh configuration object */ struct GNUNET_CONFIGURATION_Handle * GNUNET_CONFIGURATION_create (void); /** * Duplicate an existing configuration object. * * @param cfg configuration to duplicate * @return duplicate configuration */ struct GNUNET_CONFIGURATION_Handle * GNUNET_CONFIGURATION_dup (const struct GNUNET_CONFIGURATION_Handle *cfg); /** * Destroy configuration object. * * @param cfg configuration to destroy */ void GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg); /** * Load configuration. This function will first parse the * defaults and then parse the specific configuration file * to overwrite the defaults. * * @param cfg configuration to update * @param filename name of the configuration file, NULL to load defaults * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg, const char *filename); /** * Load default configuration. This function will parse the * defaults from the given defaults_d directory. * * @param cfg configuration to update * @param defaults_d directory with the defaults * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_load_from (struct GNUNET_CONFIGURATION_Handle *cfg, const char *defaults_d); /** * Parse a configuration file, add all of the options in the * file to the configuration environment. * * @param cfg configuration to update * @param filename name of the configuration file * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg, const char *filename); /** * Write configuration file. * * @param cfg configuration to write * @param filename where to write the configuration * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *cfg, const char *filename); /** * Write only configuration entries that have been changed to configuration file * @param cfgDefault default configuration * @param cfgNew new configuration * @param filename where to write the configuration diff between default and new * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_write_diffs (const struct GNUNET_CONFIGURATION_Handle *cfgDefault, const struct GNUNET_CONFIGURATION_Handle *cfgNew, const char *filename); /** * Test if there are configuration options that were * changed since the last save. * * @param cfg configuration to inspect * @return GNUNET_NO if clean, GNUNET_YES if dirty, GNUNET_SYSERR on error (i.e. last save failed) */ int GNUNET_CONFIGURATION_is_dirty (const struct GNUNET_CONFIGURATION_Handle *cfg); /** * Function to iterate over options. * * @param cls closure * @param section name of the section * @param option name of the option * @param value value of the option */ typedef void (*GNUNET_CONFIGURATION_Iterator) (void *cls, const char *section, const char *option, const char *value); /** * Function to iterate over section. * * @param cls closure * @param section name of the section */ typedef void (*GNUNET_CONFIGURATION_Section_Iterator) (void *cls, const char *section); /** * Iterate over all options in the configuration. * * @param cfg configuration to inspect * @param iter function to call on each option * @param iter_cls closure for iter */ void GNUNET_CONFIGURATION_iterate (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_CONFIGURATION_Iterator iter, void *iter_cls); /** * Iterate over all sections in the configuration. * * @param cfg configuration to inspect * @param iter function to call on each section * @param iter_cls closure for iter */ void GNUNET_CONFIGURATION_iterate_sections (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_CONFIGURATION_Section_Iterator iter, void *iter_cls); /** * Remove the given section and all options in it. * * @param cfg configuration to inspect * @param section name of the section to remove */ void GNUNET_CONFIGURATION_remove_section (struct GNUNET_CONFIGURATION_Handle *cfg, const char *section); /** * Get a configuration value that should be a number. * * @param cfg configuration to inspect * @param section section of interest * @param option option of interest * @param number where to store the numeric value of the option * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_get_value_number (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, unsigned long long *number); /** * Get a configuration value that should be a relative time. * * @param cfg configuration to inspect * @param section section of interest * @param option option of interest * @param time set to the time value stored in the configuration * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_get_value_time (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, struct GNUNET_TIME_Relative *time); /** * Get a configuration value that should be a size in bytes. * * @param cfg configuration to inspect * @param section section of interest * @param option option of interest * @param size set to the size in bytes as stored in the configuration * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_get_value_size (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, unsigned long long *size); /** * Test if we have a value for a particular option * * @param cfg configuration to inspect * @param section section of interest * @param option option of interest * @return GNUNET_YES if so, GNUNET_NO if not. */ int GNUNET_CONFIGURATION_have_value (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option); /** * Get a configuration value that should be a string. * * @param cfg configuration to inspect * @param section section of interest * @param option option of interest * @param value will be set to a freshly allocated configuration * value, or NULL if option is not specified * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_get_value_string (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value); /** * Get a configuration value that should be the name of a file * or directory. * * @param cfg configuration to inspect * @param section section of interest * @param option option of interest * @param value will be set to a freshly allocated configuration * value, or NULL if option is not specified * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_get_value_filename (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value); /** * Iterate over the set of filenames stored in a configuration value. * * @param cfg configuration to inspect * @param section section of interest * @param option option of interest * @param cb function to call on each filename * @param cb_cls closure for cb * @return number of filenames iterated over, -1 on error */ int GNUNET_CONFIGURATION_iterate_value_filenames (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, GNUNET_FileNameCallback cb, void *cb_cls); /** * Iterate over values of a section in the configuration. * * @param cfg configuration to inspect * @param section the section * @param iter function to call on each option * @param iter_cls closure for iter */ void GNUNET_CONFIGURATION_iterate_section_values (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, GNUNET_CONFIGURATION_Iterator iter, void *iter_cls); /** * Get a configuration value that should be in a set of * predefined strings * * @param cfg configuration to inspect * @param section section of interest * @param option option of interest * @param choices NULL-terminated list of legal values * @param value will be set to an entry in the legal list, * or NULL if option is not specified and no default given * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_get_value_choice (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, const char **choices, const char **value); /** * Get a configuration value that should be in a set of * "YES" or "NO". * * @param cfg configuration to inspect * @param section section of interest * @param option option of interest * @return GNUNET_YES, GNUNET_NO or if option has no valid value, GNUNET_SYSERR */ int GNUNET_CONFIGURATION_get_value_yesno (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option); /** * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR" * where either in the "PATHS" section or the environtment * "FOO" is set to "DIRECTORY". * * @param cfg configuration to use for path expansion * @param orig string to $-expand (will be freed!) * @return $-expanded string */ char * GNUNET_CONFIGURATION_expand_dollar (const struct GNUNET_CONFIGURATION_Handle *cfg, char *orig); /** * Set a configuration value that should be a number. * * @param cfg configuration to update * @param section section of interest * @param option option of interest * @param number value to set */ void GNUNET_CONFIGURATION_set_value_number (struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, unsigned long long number); /** * Set a configuration value that should be a string. * * @param cfg configuration to update * @param section section of interest * @param option option of interest * @param value value to set */ void GNUNET_CONFIGURATION_set_value_string (struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, const char *value); /** * Remove a filename from a configuration value that * represents a list of filenames * * @param cfg configuration to update * @param section section of interest * @param option option of interest * @param value filename to remove * @return GNUNET_OK on success, * GNUNET_SYSERR if the filename is not in the list */ int GNUNET_CONFIGURATION_remove_value_filename (struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, const char *value); /** * Append a filename to a configuration value that * represents a list of filenames * * @param cfg configuration to update * @param section section of interest * @param option option of interest * @param value filename to append * @return GNUNET_OK on success, * GNUNET_SYSERR if the filename already in the list */ int GNUNET_CONFIGURATION_append_value_filename (struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, const char *value); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif #endif gnunet-0.9.3/src/include/gnunet_util_lib.h0000644000175000017500000000402011760502551015510 00000000000000/* This file is part of GNUnet (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_util_lib.h * @brief convenience header including all headers of subsystems in * gnunet_util library * @author Christian Grothoff */ #ifndef GNUNET_UTIL_LIB_H #define GNUNET_UTIL_LIB_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_common.h" #include "gnunet_bandwidth_lib.h" #include "gnunet_bio_lib.h" #include "gnunet_client_lib.h" #include "gnunet_configuration_lib.h" #include "gnunet_connection_lib.h" #include "gnunet_container_lib.h" #include "gnunet_crypto_lib.h" #include "gnunet_disk_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_helper_lib.h" #include "gnunet_network_lib.h" #include "gnunet_os_lib.h" #include "gnunet_peer_lib.h" #include "gnunet_plugin_lib.h" #include "gnunet_program_lib.h" #include "gnunet_protocols.h" #include "gnunet_pseudonym_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_server_lib.h" #include "gnunet_service_lib.h" #include "gnunet_signal_lib.h" #include "gnunet_strings_lib.h" #include "gnunet_time_lib.h" #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif #endif gnunet-0.9.3/src/include/gnunet_disk_lib.h0000644000175000017500000004742111760502551015501 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_disk_lib.h * @brief disk IO apis */ #ifndef GNUNET_DISK_LIB_H #define GNUNET_DISK_LIB_H #if WINDOWS #define OFF_T uint64_t #else #define OFF_T off_t #endif /** * Handle used to manage a pipe. */ struct GNUNET_DISK_PipeHandle; enum GNUNET_FILE_Type { GNUNET_DISK_FILE, GNUNET_PIPE }; /** * Handle used to access files (and pipes). */ struct GNUNET_DISK_FileHandle { #if WINDOWS /** * File handle under W32. */ HANDLE h; /** * Type */ enum GNUNET_FILE_Type type; /** * Structure for overlapped reading (for pipes) */ OVERLAPPED *oOverlapRead; /** * Structure for overlapped writing (for pipes) */ OVERLAPPED *oOverlapWrite; #else /** * File handle on other OSes. */ int fd; #endif /* */ }; /* we need size_t, and since it can be both unsigned int or unsigned long long, this IS platform dependent; but "stdlib.h" should be portable 'enough' to be unconditionally available... */ #include #include "gnunet_configuration_lib.h" #include "gnunet_scheduler_lib.h" #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * Specifies how a file should be opened. */ enum GNUNET_DISK_OpenFlags { /** * Open the file for reading */ GNUNET_DISK_OPEN_READ = 1, /** * Open the file for writing */ GNUNET_DISK_OPEN_WRITE = 2, /** * Open the file for both reading and writing */ GNUNET_DISK_OPEN_READWRITE = 3, /** * Fail if file already exists */ GNUNET_DISK_OPEN_FAILIFEXISTS = 4, /** * Truncate file if it exists */ GNUNET_DISK_OPEN_TRUNCATE = 8, /** * Create file if it doesn't exist */ GNUNET_DISK_OPEN_CREATE = 16, /** * Append to the file */ GNUNET_DISK_OPEN_APPEND = 32 }; /** * Specifies what type of memory map is desired. */ enum GNUNET_DISK_MapType { /** * Read-only memory map. */ GNUNET_DISK_MAP_TYPE_READ = 1, /** * Write-able memory map. */ GNUNET_DISK_MAP_TYPE_WRITE = 2, /** * Read-write memory map. */ GNUNET_DISK_MAP_TYPE_READWRITE = 3 }; /** * File access permissions, UNIX-style. */ enum GNUNET_DISK_AccessPermissions { /** * Nobody is allowed to do anything to the file. */ GNUNET_DISK_PERM_NONE = 0, /** * Owner can read. */ GNUNET_DISK_PERM_USER_READ = 1, /** * Owner can write. */ GNUNET_DISK_PERM_USER_WRITE = 2, /** * Owner can execute. */ GNUNET_DISK_PERM_USER_EXEC = 4, /** * Group can read. */ GNUNET_DISK_PERM_GROUP_READ = 8, /** * Group can write. */ GNUNET_DISK_PERM_GROUP_WRITE = 16, /** * Group can execute. */ GNUNET_DISK_PERM_GROUP_EXEC = 32, /** * Everybody can read. */ GNUNET_DISK_PERM_OTHER_READ = 64, /** * Everybody can write. */ GNUNET_DISK_PERM_OTHER_WRITE = 128, /** * Everybody can execute. */ GNUNET_DISK_PERM_OTHER_EXEC = 256 }; /** * Constants for specifying how to seek. */ enum GNUNET_DISK_Seek { /** * Seek an absolute position (from the start of the file). */ GNUNET_DISK_SEEK_SET, /** * Seek a relative position (from the current offset). */ GNUNET_DISK_SEEK_CUR, /** * Seek an absolute position from the end of the file. */ GNUNET_DISK_SEEK_END }; /** * Enumeration identifying the two ends of a pipe. */ enum GNUNET_DISK_PipeEnd { /** * The reading-end of a pipe. */ GNUNET_DISK_PIPE_END_READ = 0, /** * The writing-end of a pipe. */ GNUNET_DISK_PIPE_END_WRITE = 1 }; /** * Get the number of blocks that are left on the partition that * contains the given file (for normal users). * * @param part a file on the partition to check * @return -1 on errors, otherwise the number of free blocks */ long GNUNET_DISK_get_blocks_available (const char *part); /** * Checks whether a handle is invalid * * @param h handle to check * @return GNUNET_YES if invalid, GNUNET_NO if valid */ int GNUNET_DISK_handle_invalid (const struct GNUNET_DISK_FileHandle *h); /** * Check that fil corresponds to a filename * (of a file that exists and that is not a directory). * * @param fil filename to check * @return GNUNET_YES if yes, GNUNET_NO if not a file, GNUNET_SYSERR if something * else (will print an error message in that case, too). */ int GNUNET_DISK_file_test (const char *fil); /** * Move the read/write pointer in a file * @param h handle of an open file * @param offset position to move to * @param whence specification to which position the offset parameter relates to * @return the new position on success, GNUNET_SYSERR otherwise */ OFF_T GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle *h, OFF_T offset, enum GNUNET_DISK_Seek whence); /** * Get the size of the file (or directory) of the given file (in * bytes). * * @param filename name of the file or directory * @param size set to the size of the file (or, * in the case of directories, the sum * of all sizes of files in the directory) * @param includeSymLinks should symbolic links be * included? * @param singleFileMode GNUNET_YES to only get size of one file * and return GNUNET_SYSERR for directories. * @return GNUNET_SYSERR on error, GNUNET_OK on success */ int GNUNET_DISK_file_size (const char *filename, uint64_t * size, int includeSymLinks, int singleFileMode); /** * Obtain some unique identifiers for the given file * that can be used to identify it in the local system. * This function is used between GNUnet processes to * quickly check if two files with the same absolute path * are actually identical. The two processes represent * the same peer but may communicate over the network * (and the file may be on an NFS volume). This function * may not be supported on all operating systems. * * @param filename name of the file * @param dev set to the device ID * @param ino set to the inode ID * @return GNUNET_OK on success */ int GNUNET_DISK_file_get_identifiers (const char *filename, uint64_t * dev, uint64_t * ino); /** * Create an (empty) temporary file on disk. If the given name is not * an absolute path, the current 'TMPDIR' will be prepended. In any case, * 6 random characters will be appended to the name to create a unique * filename. * * @param t component to use for the name; * does NOT contain "XXXXXX" or "/tmp/". * @return NULL on error, otherwise name of fresh * file on disk in directory for temporary files */ char * GNUNET_DISK_mktemp (const char *t); /** * Open a file. Note that the access permissions will only be * used if a new file is created and if the underlying operating * system supports the given permissions. * * @param fn file name to be opened * @param flags opening flags, a combination of GNUNET_DISK_OPEN_xxx bit flags * @param perm permissions for the newly created file, use * GNUNET_DISK_PERM_NONE if a file could not be created by this * call (because of flags) * @return IO handle on success, NULL on error */ struct GNUNET_DISK_FileHandle * GNUNET_DISK_file_open (const char *fn, enum GNUNET_DISK_OpenFlags flags, enum GNUNET_DISK_AccessPermissions perm); /** * Get the size of an open file. * * @param fh open file handle * @param size where to write size of the file * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_DISK_file_handle_size (struct GNUNET_DISK_FileHandle *fh, OFF_T *size); /** * Creates an interprocess channel * * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO * @param inherit_read 1 to make read handle inheritable, 0 otherwise (NT only) * @param inherit_write 1 to make write handle inheritable, 0 otherwise (NT only) * @return handle to the new pipe, NULL on error */ struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int inherit_write); /** * Creates a pipe object from a couple of file descriptors. * Useful for wrapping existing pipe FDs. * * @param blocking_read creates an asynchronous pipe for reading if set to GNUNET_NO * @param blocking_write creates an asynchronous pipe for writing if set to GNUNET_NO * @param fd an array of two fd values. One of them may be -1 for read-only or write-only pipes * * @return handle to the new pipe, NULL on error */ struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2]); /** * Closes an interprocess channel * @param p pipe * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p); /** * Closes one half of an interprocess channel * * @param p pipe to close end of * @param end which end of the pipe to close * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd end); /** * Close an open file. * * @param h file handle * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h); /** * Get the handle to a particular pipe end * * @param p pipe * @param n end to access * @return handle for the respective end */ const struct GNUNET_DISK_FileHandle * GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd n); /** * Read the contents of a binary file into a buffer. * @param h handle to an open file * @param result the buffer to write the result to * @param len the maximum number of bytes to read * @return the number of bytes read on success, GNUNET_SYSERR on failure */ ssize_t GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle *h, void *result, size_t len); /** * Read the contents of a binary file into a buffer. * Guarantees not to block (returns GNUNET_SYSERR and sets errno to EAGAIN * when no data can be read). * * @param h handle to an open file * @param result the buffer to write the result to * @param len the maximum number of bytes to read * @return the number of bytes read on success, GNUNET_SYSERR on failure */ ssize_t GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle * h, void *result, size_t len); /** * Read the contents of a binary file into a buffer. * * @param fn file name * @param result the buffer to write the result to * @param len the maximum number of bytes to read * @return number of bytes read, GNUNET_SYSERR on failure */ ssize_t GNUNET_DISK_fn_read (const char *fn, void *result, size_t len); /** * Write a buffer to a file. * * @param h handle to open file * @param buffer the data to write * @param n number of bytes to write * @return number of bytes written on success, GNUNET_SYSERR on error */ ssize_t GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle *h, const void *buffer, size_t n); /** * Write a buffer to a file, blocking, if necessary. * @param h handle to open file * @param buffer the data to write * @param n number of bytes to write * @return number of bytes written on success, GNUNET_SYSERR on error */ ssize_t GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle * h, const void *buffer, size_t n); /** * Write a buffer to a file. If the file is longer than * the given buffer size, it will be truncated. * * @param fn file name * @param buffer the data to write * @param n number of bytes to write * @param mode file permissions * @return number of bytes written on success, GNUNET_SYSERR on error */ ssize_t GNUNET_DISK_fn_write (const char *fn, const void *buffer, size_t n, enum GNUNET_DISK_AccessPermissions mode); /** * Copy a file. * * @param src file to copy * @param dst destination file name * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_DISK_file_copy (const char *src, const char *dst); /** * Scan a directory for files. * * @param dirName the name of the directory * @param callback the method to call for each file * @param callback_cls closure for callback * @return the number of files found, -1 on error */ int GNUNET_DISK_directory_scan (const char *dirName, GNUNET_FileNameCallback callback, void *callback_cls); /** * Opaque handle used for iterating over a directory. */ struct GNUNET_DISK_DirectoryIterator; /** * Function called to iterate over a directory. * * @param cls closure * @param di argument to pass to "GNUNET_DISK_directory_iterator_next" to * get called on the next entry (or finish cleanly); * NULL on error (will be the last call in that case) * @param filename complete filename (absolute path) * @param dirname directory name (absolute path) */ typedef void (*GNUNET_DISK_DirectoryIteratorCallback) (void *cls, struct GNUNET_DISK_DirectoryIterator * di, const char *filename, const char *dirname); /** * This function must be called during the DiskIteratorCallback * (exactly once) to schedule the task to process the next * filename in the directory (if there is one). * * @param iter opaque handle for the iterator * @param can set to GNUNET_YES to terminate the iteration early * @return GNUNET_YES if iteration will continue, * GNUNET_NO if this was the last entry (and iteration is complete), * GNUNET_SYSERR if "can" was YES */ int GNUNET_DISK_directory_iterator_next (struct GNUNET_DISK_DirectoryIterator *iter, int can); /** * Scan a directory for files using the scheduler to run a task for * each entry. The name of the directory must be expanded first (!). * If a scheduler does not need to be used, GNUNET_DISK_directory_scan * may provide a simpler API. * * @param prio priority to use * @param dirName the name of the directory * @param callback the method to call for each file * @param callback_cls closure for callback * @return GNUNET_YES if directory is not empty and 'callback' * will be called later, GNUNET_NO otherwise, GNUNET_SYSERR on error. */ int GNUNET_DISK_directory_iterator_start (enum GNUNET_SCHEDULER_Priority prio, const char *dirName, GNUNET_DISK_DirectoryIteratorCallback callback, void *callback_cls); /** * Create the directory structure for storing * a file. * * @param filename name of a file in the directory * @returns GNUNET_OK on success, GNUNET_SYSERR on failure, * GNUNET_NO if directory exists but is not writeable */ int GNUNET_DISK_directory_create_for_file (const char *filename); /** * Test if "fil" is a directory that can be accessed. * Will not print an error message if the directory * does not exist. Will log errors if GNUNET_SYSERR is * returned. * * @param fil filename to test * @return GNUNET_YES if yes, GNUNET_NO if does not exist, GNUNET_SYSERR * on any error and if exists but not directory */ int GNUNET_DISK_directory_test (const char *fil); /** * Remove all files in a directory (rm -rf). Call with * caution. * * @param fileName the file to remove * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_DISK_directory_remove (const char *fileName); /** * Implementation of "mkdir -p" * * @param dir the directory to create * @returns GNUNET_SYSERR on failure, GNUNET_OK otherwise */ int GNUNET_DISK_directory_create (const char *dir); /** * Lock a part of a file. * * @param fh file handle * @param lockStart absolute position from where to lock * @param lockEnd absolute position until where to lock * @param excl GNUNET_YES for an exclusive lock * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, OFF_T lockStart, OFF_T lockEnd, int excl); /** * Unlock a part of a file * @param fh file handle * @param unlockStart absolute position from where to unlock * @param unlockEnd absolute position until where to unlock * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, OFF_T unlockStart, OFF_T unlockEnd); /** * @brief Removes special characters as ':' from a filename. * @param fn the filename to canonicalize */ void GNUNET_DISK_filename_canonicalize (char *fn); /** * @brief Change owner of a file * @param filename file to change * @param user new owner of the file * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int GNUNET_DISK_file_change_owner (const char *filename, const char *user); /** * Construct full path to a file inside of the private * directory used by GNUnet. Also creates the corresponding * directory. If the resulting name is supposed to be * a directory, end the last argument in '/' (or pass * DIR_SEPARATOR_STR as the last argument before NULL). * * @param cfg configuration to use * @param serviceName name of the service asking * @param ... is NULL-terminated list of * path components to append to the * private directory name. * @return the constructed filename */ char * GNUNET_DISK_get_home_filename (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *serviceName, ...); /** * Opaque handle for a memory-mapping operation. */ struct GNUNET_DISK_MapHandle; /** * Map a file into memory * @param h open file handle * @param m handle to the new mapping (will be set) * @param access access specification, GNUNET_DISK_MAP_TYPE_xxx * @param len size of the mapping * @return pointer to the mapped memory region, NULL on failure */ void * GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h, struct GNUNET_DISK_MapHandle **m, enum GNUNET_DISK_MapType access, size_t len); /** * Unmap a file * * @param h mapping handle * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h); /** * Write file changes to disk * @param h handle to an open file * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_DISK_LIB_H */ #endif /* end of gnunet_disk_lib.h */ gnunet-0.9.3/src/include/gnunet_datastore_plugin.h0000644000175000017500000002412311760502551017257 00000000000000/* This file is part of GNUnet (C) 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_datastore_plugin.h * @brief API for the database backend plugins. * @author Christian Grothoff */ #ifndef PLUGIN_DATASTORE_H #define PLUGIN_DATASTORE_H #include "gnunet_block_lib.h" #include "gnunet_configuration_lib.h" #include "gnunet_datastore_service.h" #include "gnunet_statistics_service.h" #include "gnunet_scheduler_lib.h" /** * How many bytes of overhead will we assume per entry * in any DB (for reservations)? */ #define GNUNET_DATASTORE_ENTRY_OVERHEAD 256 /** * Function invoked to notify service of disk utilization * changes. * * @param cls closure * @param delta change in disk utilization, * 0 for "reset to empty" */ typedef void (*DiskUtilizationChange) (void *cls, int delta); /** * The datastore service will pass a pointer to a struct * of this type as the first and only argument to the * entry point of each datastore plugin. */ struct GNUNET_DATASTORE_PluginEnvironment { /** * Configuration to use. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Function to call on disk utilization change. */ DiskUtilizationChange duc; /** * Closure. */ void *cls; }; /** * An processor over a set of items stored in the datastore. * * @param cls closure * @param key key for the content * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param expiration expiration time for the content * @param uid unique identifier for the datum * * @return GNUNET_OK to keep the item * GNUNET_NO to delete the item */ typedef int (*PluginDatumProcessor) (void *cls, const GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid); /** * Get an estimate of how much space the database is * currently using. * * @param cls closure * @return number of bytes used on disk */ typedef unsigned long long (*PluginEstimateSize) (void *cls); /** * Store an item in the datastore. If the item is already present, * the priorities and replication levels are summed up and the higher * expiration time and lower anonymity level is used. * * @param cls closure * @param key key for the item * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param replication replication-level for the content * @param expiration expiration time for the content * @param msg set to an error message (on failure) * @return GNUNET_OK on success, * GNUNET_SYSERR on failure */ typedef int (*PluginPut) (void *cls, const GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, uint32_t replication, struct GNUNET_TIME_Absolute expiration, char **msg); /** * An processor over a set of keys stored in the datastore. * * @param cls closure * @param key key in the data store * @param count how many values are stored under this key in the datastore */ typedef void (*PluginKeyProcessor) (void *cls, const GNUNET_HashCode *key, unsigned int count); /** * Get all of the keys in the datastore. * * @param cls closure * @param proc function to call on each key * @param proc_cls closure for proc */ typedef void (*PluginGetKeys) (void *cls, PluginKeyProcessor proc, void *proc_cls); /** * Get one of the results for a particular key in the datastore. * * @param cls closure * @param offset offset of the result (modulo num-results); * specific ordering does not matter for the offset * @param key key to match, never NULL * @param vhash hash of the value, maybe NULL (to * match all values that have the right key). * Note that for DBlocks there is no difference * betwen key and vhash, but for other blocks * there may be! * @param type entries of which type are relevant? * Use 0 for any type. * @param min find the smallest key that is larger than the given min, * NULL for no minimum (return smallest key) * @param proc function to call on the matching value; * proc should be called with NULL if there is no result * @param proc_cls closure for proc */ typedef void (*PluginGetKey) (void *cls, uint64_t offset, const GNUNET_HashCode * key, const GNUNET_HashCode * vhash, enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc, void *proc_cls); /** * Get a random item (additional constraints may apply depending on * the specific implementation). Calls 'proc' with all values ZERO or * NULL if no item applies, otherwise 'proc' is called once and only * once with an item. * * @param cls closure * @param proc function to call the value (once only). * @param proc_cls closure for proc */ typedef void (*PluginGetRandom) (void *cls, PluginDatumProcessor proc, void *proc_cls); /** * Update the priority for a particular key in the datastore. If * the expiration time in value is different than the time found in * the datastore, the higher value should be kept. For the * anonymity level, the lower value is to be used. The specified * priority should be added to the existing priority, ignoring the * priority in value. * * Note that it is possible for multiple values to match this put. * In that case, all of the respective values are updated. * * @param cls closure * @param uid unique identifier of the datum * @param delta by how much should the priority * change? If priority + delta < 0 the * priority should be set to 0 (never go * negative). * @param expire new expiration time should be the * MAX of any existing expiration time and * this value * @param msg set to an error message (on error) * @return GNUNET_OK on success */ typedef int (*PluginUpdate) (void *cls, uint64_t uid, int delta, struct GNUNET_TIME_Absolute expire, char **msg); /** * Select a single item from the datastore at the specified offset * (among those applicable). * * @param cls closure * @param offset offset of the result (modulo num-results); * specific ordering does not matter for the offset * @param type entries of which type should be considered? * Must not be zero (ANY). * @param proc function to call on the matching value * @param proc_cls closure for proc */ typedef void (*PluginGetType) (void *cls, uint64_t offset, enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc, void *proc_cls); /** * Drop database. * * @param cls closure */ typedef void (*PluginDrop) (void *cls); /** * Each plugin is required to return a pointer to a struct of this * type as the return value from its entry point. */ struct GNUNET_DATASTORE_PluginFunctions { /** * Closure to use for all of the following callbacks * (except "next_request"). */ void *cls; /** * Calculate the current on-disk size of the SQ store. Estimates * are fine, if that's the only thing available. */ PluginEstimateSize estimate_size; /** * Function to store an item in the datastore. */ PluginPut put; /** * Update the priority for a particular key in the datastore. If * the expiration time in value is different than the time found in * the datastore, the higher value should be kept. For the * anonymity level, the lower value is to be used. The specified * priority should be added to the existing priority, ignoring the * priority in value. */ PluginUpdate update; /** * Get a particular datum matching a given hash from the datastore. */ PluginGetKey get_key; /** * Get datum (of the specified type) with anonymity level zero. * This function is allowed to ignore the 'offset' argument * and instead return a random result (with zero anonymity of * the correct type) if implementing an offset is expensive. */ PluginGetType get_zero_anonymity; /** * Function to get a random item with high replication score from * the database, lowering the item's replication score. Returns a * single random item from those with the highest replication * counters. The item's replication counter is decremented by one * IF it was positive before. */ PluginGetRandom get_replication; /** * Function to get a random expired item or, if none are expired, * either the oldest entry or one with a low priority (depending * on what was efficiently implementable). */ PluginGetRandom get_expiration; /** * Delete the database. The next operation is * guaranteed to be unloading of the module. */ PluginDrop drop; /** * Iterate over all keys in the database. */ PluginGetKeys get_keys; }; #endif gnunet-0.9.3/src/include/gnunet_gns_service.h0000644000175000017500000001572511760502551016232 00000000000000/* This file is part of GNUnet (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_gns_service.h * @brief API to the GNS service * @author Martin Schanzenbach * * TODO: * - decide what goes into storage API and what into GNS-service API * - decide where to pass/expose/check keys / signatures * - are GNS private keys per peer or per user? */ #ifndef GNUNET_GNS_SERVICE_H #define GNUNET_GNS_SERVICE_H #include "gnunet_util_lib.h" #include "gnunet_dnsparser_lib.h" #include "gnunet_namestore_service.h" #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * Connection to the GNS service. */ struct GNUNET_GNS_Handle; /** * Handle to control a get operation. */ struct GNUNET_GNS_LookupHandle; /** * Handle to control a shorten operation */ /** * Record types * Based on GNUNET_DNSPARSER_TYPEs (standard DNS) */ enum GNUNET_GNS_RecordType { /* Standard DNS */ GNUNET_GNS_RECORD_TYPE_A = GNUNET_DNSPARSER_TYPE_A, GNUNET_GNS_RECORD_TYPE_NS = GNUNET_DNSPARSER_TYPE_NS, GNUNET_GNS_RECORD_TYPE_CNAME = GNUNET_DNSPARSER_TYPE_CNAME, GNUNET_GNS_RECORD_TYPE_SOA = GNUNET_DNSPARSER_TYPE_SOA, GNUNET_GNS_RECORD_TYPE_PTR = GNUNET_DNSPARSER_TYPE_PTR, GNUNET_GNS_RECORD_MX = GNUNET_DNSPARSER_TYPE_MX, GNUNET_GNS_RECORD_TXT = GNUNET_DNSPARSER_TYPE_TXT, GNUNET_GNS_RECORD_AAAA = GNUNET_DNSPARSER_TYPE_AAAA, /* GNS specific */ GNUNET_GNS_RECORD_PKEY = GNUNET_NAMESTORE_TYPE_PKEY, GNUNET_GNS_RECORD_PSEU = GNUNET_NAMESTORE_TYPE_PSEU, GNUNET_GNS_RECORD_ANY = GNUNET_NAMESTORE_TYPE_ANY }; /** * Initialize the connection with the GNS service. * * @param cfg configuration to use * * @return handle to the GNS service, or NULL on error */ struct GNUNET_GNS_Handle * GNUNET_GNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); /** * Shutdown connection with the GNS service. * * @param handle connection to shut down */ void GNUNET_GNS_disconnect (struct GNUNET_GNS_Handle *handle); /* *************** Standard API: lookup ******************* */ /** * Iterator called on obtained result for a GNS * lookup * * @param cls closure * @param name "name" of the original lookup * @param rd_count number of records * @param rd the records in reply */ typedef void (*GNUNET_GNS_LookupResultProcessor) (void *cls, uint32_t rd_count, const struct GNUNET_NAMESTORE_RecordData *rd); /** * Perform an asynchronous lookup operation on the GNS * in the default zone. * * @param handle handle to the GNS service * @param name the name to look up * @param type the GNUNET_GNS_RecordType to look for * @param proc function to call on result * @param proc_cls closure for processor * * @return handle to the queued request */ struct GNUNET_GNS_QueueEntry * GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle, const char * name, enum GNUNET_GNS_RecordType type, GNUNET_GNS_LookupResultProcessor proc, void *proc_cls); /** * Perform an asynchronous lookup operation on the GNS * in the zone specified by 'zone'. * * @param handle handle to the GNS service * @param name the name to look up * @param zone the zone to start the resolution in * @param type the GNUNET_GNS_RecordType to look for * @param proc function to call on result * @param proc_cls closure for processor * * @return handle to the queued request */ struct GNUNET_GNS_QueueEntry * GNUNET_GNS_lookup_zone (struct GNUNET_GNS_Handle *handle, const char * name, struct GNUNET_CRYPTO_ShortHashCode *zone, enum GNUNET_GNS_RecordType type, GNUNET_GNS_LookupResultProcessor proc, void *proc_cls); /* *************** Standard API: shorten ******************* */ /** * Processor called on for a name shortening result * called only once * * @param cls closure * @param short_name the shortened name or NULL if no result */ typedef void (*GNUNET_GNS_ShortenResultProcessor) (void *cls, const char* short_name); /** * Perform a name shortening operation on the GNS. * * @param handle handle to the GNS service * @param name the name to look up * @param proc function to call on result * @param proc_cls closure for processor * @return handle to the operation */ struct GNUNET_GNS_QueueEntry * GNUNET_GNS_shorten (struct GNUNET_GNS_Handle *handle, const char * name, GNUNET_GNS_ShortenResultProcessor proc, void *proc_cls); /** * Perform a name shortening operation on the GNS. * * @param handle handle to the GNS service * @param name the name to look up * @param zone the zone to start the resolution in * @param proc function to call on result * @param proc_cls closure for processor * @return handle to the operation */ struct GNUNET_GNS_QueueEntry * GNUNET_GNS_shorten_zone (struct GNUNET_GNS_Handle *handle, const char * name, struct GNUNET_CRYPTO_ShortHashCode *zone, GNUNET_GNS_ShortenResultProcessor proc, void *proc_cls); /* *************** Standard API: get authority ******************* */ /** * Processor called on for a name shortening result * called only once * * @param cls closure * @param auth_name the name of the auhtority or NULL */ typedef void (*GNUNET_GNS_GetAuthResultProcessor) (void *cls, const char* short_name); /** * Perform an authority lookup for a given name. * * @param handle handle to the GNS service * @param name the name to look up authority for * @param proc function to call on result * @param proc_cls closure for processor * @return handle to the operation */ struct GNUNET_GNS_QueueEntry * GNUNET_GNS_get_authority (struct GNUNET_GNS_Handle *handle, const char * name, GNUNET_GNS_GetAuthResultProcessor proc, void *proc_cls); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif #endif /* gnunet_gns_service.h */ gnunet-0.9.3/src/include/gnunet_dnsparser_lib.h0000644000175000017500000002066111760502551016545 00000000000000/* This file is part of GNUnet (C) 2010, 2011, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_dnsparser_lib.h * @brief API for helper library to parse DNS packets. * @author Philipp Toelke * @author Christian Grothoff */ #ifndef GNUNET_DNSPARSER_LIB_H #define GNUNET_DNSPARSER_LIB_H #include "platform.h" #include "gnunet_common.h" /** * A few common DNS types. */ #define GNUNET_DNSPARSER_TYPE_A 1 #define GNUNET_DNSPARSER_TYPE_NS 2 #define GNUNET_DNSPARSER_TYPE_CNAME 5 #define GNUNET_DNSPARSER_TYPE_SOA 6 #define GNUNET_DNSPARSER_TYPE_PTR 12 #define GNUNET_DNSPARSER_TYPE_MX 15 #define GNUNET_DNSPARSER_TYPE_TXT 16 #define GNUNET_DNSPARSER_TYPE_AAAA 28 /** * A few common DNS classes (ok, only one is common, but I list a * couple more to make it clear what we're talking about here). */ #define GNUNET_DNSPARSER_CLASS_INTERNET 1 #define GNUNET_DNSPARSER_CLASS_CHAOS 3 #define GNUNET_DNSPARSER_CLASS_HESIOD 4 #define GNUNET_DNSPARSER_OPCODE_QUERY 0 #define GNUNET_DNSPARSER_OPCODE_INVERSE_QUERY 1 #define GNUNET_DNSPARSER_OPCODE_STATUS 2 /** * RFC 1035 codes. */ #define GNUNET_DNSPARSER_RETURN_CODE_NO_ERROR 0 #define GNUNET_DNSPARSER_RETURN_CODE_FORMAT_ERROR 1 #define GNUNET_DNSPARSER_RETURN_CODE_SERVER_FAILURE 2 #define GNUNET_DNSPARSER_RETURN_CODE_NAME_ERROR 3 #define GNUNET_DNSPARSER_RETURN_CODE_NOT_IMPLEMENTED 4 #define GNUNET_DNSPARSER_RETURN_CODE_REFUSED 5 /** * RFC 2136 codes */ #define GNUNET_DNSPARSER_RETURN_CODE_YXDOMAIN 6 #define GNUNET_DNSPARSER_RETURN_CODE_YXRRSET 7 #define GNUNET_DNSPARSER_RETURN_CODE_NXRRSET 8 #define GNUNET_DNSPARSER_RETURN_CODE_NOT_AUTH 9 #define GNUNET_DNSPARSER_RETURN_CODE_NOT_ZONE 10 /** * DNS flags (largely RFC 1035 / RFC 2136). */ struct GNUNET_DNSPARSER_Flags { /** * Set to 1 if recursion is desired (client -> server) */ unsigned int recursion_desired : 1 GNUNET_PACKED; /** * Set to 1 if message is truncated */ unsigned int message_truncated : 1 GNUNET_PACKED; /** * Set to 1 if this is an authoritative answer */ unsigned int authoritative_answer : 1 GNUNET_PACKED; /** * See GNUNET_DNSPARSER_OPCODE_ defines. */ unsigned int opcode : 4 GNUNET_PACKED; /** * query:0, response:1 */ unsigned int query_or_response : 1 GNUNET_PACKED; /** * See GNUNET_DNSPARSER_RETURN_CODE_ defines. */ unsigned int return_code : 4 GNUNET_PACKED; /** * See RFC 4035. */ unsigned int checking_disabled : 1 GNUNET_PACKED; /** * Response has been cryptographically verified, RFC 4035. */ unsigned int authenticated_data : 1 GNUNET_PACKED; /** * Always zero. */ unsigned int zero : 1 GNUNET_PACKED; /** * Set to 1 if recursion is available (server -> client) */ unsigned int recursion_available : 1 GNUNET_PACKED; } GNUNET_GCC_STRUCT_LAYOUT; /** * A DNS query. */ struct GNUNET_DNSPARSER_Query { /** * Name of the record that the query is for (0-terminated). */ char *name; /** * See GNUNET_DNSPARSER_TYPE_*. */ uint16_t type; /** * See GNUNET_DNSPARSER_CLASS_*. */ uint16_t class; }; /** * Information from MX records (RFC 1035). */ struct GNUNET_DNSPARSER_MxRecord { /** * Preference for this entry (lower value is higher preference). */ uint16_t preference; /** * Name of the mail server. */ char *mxhost; }; /** * Information from SOA records (RFC 1035). */ struct GNUNET_DNSPARSER_SoaRecord { /** *The domainname of the name server that was the * original or primary source of data for this zone. */ char *mname; /** * A domainname which specifies the mailbox of the * person responsible for this zone. */ char *rname; /** * The version number of the original copy of the zone. */ uint32_t serial; /** * Time interval before the zone should be refreshed. */ uint32_t refresh; /** * Time interval that should elapse before a failed refresh should * be retried. */ uint32_t retry; /** * Time value that specifies the upper limit on the time interval * that can elapse before the zone is no longer authoritative. */ uint32_t expire; /** * The bit minimum TTL field that should be exported with any RR * from this zone. */ uint32_t minimum_ttl; }; /** * Binary record information (unparsed). */ struct GNUNET_DNSPARSER_RawRecord { /** * Binary record data. */ void *data; /** * Number of bytes in data. */ size_t data_len; }; /** * A DNS response record. */ struct GNUNET_DNSPARSER_Record { /** * Name of the record that the query is for (0-terminated). */ char *name; union { /** * For NS, CNAME and PTR records, this is the uncompressed 0-terminated hostname. */ char *hostname; /** * SOA data for SOA records. */ struct GNUNET_DNSPARSER_SoaRecord *soa; /** * MX data for MX records. */ struct GNUNET_DNSPARSER_MxRecord *mx; /** * Raw data for all other types. */ struct GNUNET_DNSPARSER_RawRecord raw; } data; /** * When does the record expire? */ struct GNUNET_TIME_Absolute expiration_time; /** * See GNUNET_DNSPARSER_TYPE_*. */ uint16_t type; /** * See GNUNET_DNSPARSER_CLASS_*. */ uint16_t class; }; /** * Easy-to-process, parsed version of a DNS packet. */ struct GNUNET_DNSPARSER_Packet { /** * Array of all queries in the packet, must contain "num_queries" entries. */ struct GNUNET_DNSPARSER_Query *queries; /** * Array of all answers in the packet, must contain "num_answers" entries. */ struct GNUNET_DNSPARSER_Record *answers; /** * Array of all authority records in the packet, must contain "num_authority_records" entries. */ struct GNUNET_DNSPARSER_Record *authority_records; /** * Array of all additional answers in the packet, must contain "num_additional_records" entries. */ struct GNUNET_DNSPARSER_Record *additional_records; /** * Number of queries in the packet. */ unsigned int num_queries; /** * Number of answers in the packet, should be 0 for queries. */ unsigned int num_answers; /** * Number of authoritative answers in the packet, should be 0 for queries. */ unsigned int num_authority_records; /** * Number of additional records in the packet, should be 0 for queries. */ unsigned int num_additional_records; /** * Bitfield of DNS flags. */ struct GNUNET_DNSPARSER_Flags flags; /** * DNS ID (to match replies to requests). */ uint16_t id; }; /** * Parse a UDP payload of a DNS packet in to a nice struct for further * processing and manipulation. * * @param udp_payload wire-format of the DNS packet * @param udp_payload_length number of bytes in udp_payload * @return NULL on error, otherwise the parsed packet */ struct GNUNET_DNSPARSER_Packet * GNUNET_DNSPARSER_parse (const char *udp_payload, size_t udp_payload_length); /** * Free memory taken by a packet. * * @param p packet to free */ void GNUNET_DNSPARSER_free_packet (struct GNUNET_DNSPARSER_Packet *p); /** * Given a DNS packet, generate the corresponding UDP payload. * * @param p packet to pack * @param max maximum allowed size for the resulting UDP payload * @param buf set to a buffer with the packed message * @param buf_length set to the length of buf * @return GNUNET_SYSERR if 'p' is invalid * GNUNET_NO if 'p' was truncated (but there is still a result in 'buf') * GNUNET_OK if 'p' was packed completely into '*buf' */ int GNUNET_DNSPARSER_pack (const struct GNUNET_DNSPARSER_Packet *p, uint16_t max, char **buf, size_t *buf_length); #endif gnunet-0.9.3/src/include/gnunet_datacache_plugin.h0000644000175000017500000000763411760502551017176 00000000000000/* This file is part of GNUnet (C) 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_datacache_plugin.h * @brief API for database backends for the datacache * @author Christian Grothoff */ #ifndef PLUGIN_DATACACHE_H #define PLUGIN_DATACACHE_H #include "gnunet_datacache_lib.h" #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * Function called by plugins to notify the datacache * about content deletions. * * @param cls closure * @param key key of the content that was deleted * @param size number of bytes that were made available */ typedef void (*GNUNET_DATACACHE_DeleteNotifyCallback) (void *cls, const GNUNET_HashCode * key, size_t size); /** * The datastore service will pass a pointer to a struct * of this type as the first and only argument to the * entry point of each datastore plugin. */ struct GNUNET_DATACACHE_PluginEnvironment { /** * Configuration to use. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Configuration section to use. */ const char *section; /** * Closure to use for callbacks. */ void *cls; /** * Function to call whenever the plugin needs to * discard content that it was asked to store. */ GNUNET_DATACACHE_DeleteNotifyCallback delete_notify; /** * How much space are we allowed to use? */ unsigned long long quota; }; /** * @brief struct returned by the initialization function of the plugin */ struct GNUNET_DATACACHE_PluginFunctions { /** * Closure to pass to all plugin functions. */ void *cls; /** * Store an item in the datastore. * * @param cls closure (internal context for the plugin) * @param size number of bytes in data * @param data data to store * @param type type of the value * @param discard_time when to discard the value in any case * @return 0 on error, number of bytes used otherwise */ size_t (*put) (void *cls, const GNUNET_HashCode * key, size_t size, const char *data, enum GNUNET_BLOCK_Type type, struct GNUNET_TIME_Absolute discard_time); /** * Iterate over the results for a particular key * in the datastore. * * @param cls closure (internal context for the plugin) * @param key * @param type entries of which type are relevant? * @param iter maybe NULL (to just count) * @param iter_cls closure for iter * @return the number of results found */ unsigned int (*get) (void *cls, const GNUNET_HashCode * key, enum GNUNET_BLOCK_Type type, GNUNET_DATACACHE_Iterator iter, void *iter_cls); /** * Delete the entry with the lowest expiration value * from the datacache right now. * * @param cls closure (internal context for the plugin) * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int (*del) (void *cls); }; #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* end of gnunet_datacache_plugin.h */ #endif gnunet-0.9.3/src/include/gnunet_directories.h.in0000644000175000017500000000216711760502552016641 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_directories.h * @brief directories and files in GNUnet (default locations) * * @author Christian Grothoff */ #ifndef GNUNET_DIRECTORIES #define GNUNET_DIRECTORIES #define GNUNET_DEFAULT_USER_CONFIG_FILE "@GN_USER_HOME_DIR@/gnunet.conf" #endif gnunet-0.9.3/src/include/gnunet_crypto_lib.h0000644000175000017500000007160211760502551016065 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_crypto_lib.h * @brief cryptographic primitives for GNUnet * * @author Christian Grothoff * @author Krista Bennett * @author Gerd Knorr * @author Ioana Patrascu * @author Tzvetan Horozov */ #ifndef GNUNET_CRYPTO_LIB_H #define GNUNET_CRYPTO_LIB_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_common.h" #include "gnunet_scheduler_lib.h" /** * Desired quality level for cryptographic operations. */ enum GNUNET_CRYPTO_Quality { /** * No good quality of the operation is needed (i.e., * random numbers can be pseudo-random). */ GNUNET_CRYPTO_QUALITY_WEAK, /** * High-quality operations are desired. */ GNUNET_CRYPTO_QUALITY_STRONG, /** * Randomness for IVs etc. is required. */ GNUNET_CRYPTO_QUALITY_NONCE }; /** * @brief length of the sessionkey in bytes (256 BIT sessionkey) */ #define GNUNET_CRYPTO_AES_KEY_LENGTH (256/8) /** * @brief Length of RSA encrypted data (2048 bit) * * We currently do not handle encryption of data * that can not be done in a single call to the * RSA methods (read: large chunks of data). * We should never need that, as we can use * the GNUNET_CRYPTO_hash for larger pieces of data for signing, * and for encryption, we only need to encode sessionkeys! */ #define GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH 256 /** * Length of an RSA KEY (n,e,len), 2048 bit (=256 octests) key n, 2 byte e */ #define GNUNET_CRYPTO_RSA_KEY_LENGTH 258 /** * Length of a hash value */ #define GNUNET_CRYPTO_HASH_LENGTH 512/8 /** * The private information of an RSA key pair. */ struct GNUNET_CRYPTO_RsaPrivateKey; GNUNET_NETWORK_STRUCT_BEGIN /** * GNUnet mandates a certain format for the encoding * of private RSA key information that is provided * by the RSA implementations. This format is used * to serialize a private RSA key (typically when * writing it to disk). */ struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded { /** * Total size of the structure, in bytes, in big-endian! */ uint16_t len GNUNET_PACKED; uint16_t sizen GNUNET_PACKED; /* in big-endian! */ uint16_t sizee GNUNET_PACKED; /* in big-endian! */ uint16_t sized GNUNET_PACKED; /* in big-endian! */ uint16_t sizep GNUNET_PACKED; /* in big-endian! */ uint16_t sizeq GNUNET_PACKED; /* in big-endian! */ uint16_t sizedmp1 GNUNET_PACKED; /* in big-endian! */ uint16_t sizedmq1 GNUNET_PACKED; /* in big-endian! */ /* followed by the actual values */ }; GNUNET_NETWORK_STRUCT_END /** * @brief 0-terminated ASCII encoding of a GNUNET_HashCode. */ struct GNUNET_CRYPTO_HashAsciiEncoded { unsigned char encoding[104]; }; /** * @brief 256-bit hashcode */ struct GNUNET_CRYPTO_ShortHashCode { uint32_t bits[256 / 8 / sizeof (uint32_t)]; /* = 8 */ }; /** * @brief 0-terminated ASCII encoding of a 'struct GNUNET_ShortHashCode'. */ struct GNUNET_CRYPTO_ShortHashAsciiEncoded { unsigned char short_encoding[53]; }; /** * @brief an RSA signature */ struct GNUNET_CRYPTO_RsaSignature { unsigned char sig[GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH]; }; GNUNET_NETWORK_STRUCT_BEGIN /** * @brief header of what an RSA signature signs * this must be followed by "size - 8" bytes of * the actual signed data */ struct GNUNET_CRYPTO_RsaSignaturePurpose { /** * How many bytes does this signature sign? * (including this purpose header); in network * byte order (!). */ uint32_t size GNUNET_PACKED; /** * What does this signature vouch for? This * must contain a GNUNET_SIGNATURE_PURPOSE_XXX * constant (from gnunet_signatures.h). In * network byte order! */ uint32_t purpose GNUNET_PACKED; }; /** * @brief A public key. */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded { /** * In big-endian, must be GNUNET_CRYPTO_RSA_KEY_LENGTH+4 */ uint16_t len GNUNET_PACKED; /** * Size of n in key; in big-endian! */ uint16_t sizen GNUNET_PACKED; /** * The key itself, contains n followed by e. */ unsigned char key[GNUNET_CRYPTO_RSA_KEY_LENGTH]; /** * Padding (must be 0) */ uint16_t padding GNUNET_PACKED; }; /** * RSA Encrypted data. */ struct GNUNET_CRYPTO_RsaEncryptedData { unsigned char encoding[GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH]; }; /** * @brief type for session keys */ struct GNUNET_CRYPTO_AesSessionKey { /** * Actual key. */ unsigned char key[GNUNET_CRYPTO_AES_KEY_LENGTH]; /** * checksum! */ uint32_t crc32 GNUNET_PACKED; }; GNUNET_NETWORK_STRUCT_END /** * @brief IV for sym cipher * * NOTE: must be smaller (!) in size than the * GNUNET_HashCode. */ struct GNUNET_CRYPTO_AesInitializationVector { unsigned char iv[GNUNET_CRYPTO_AES_KEY_LENGTH / 2]; }; /** * @brief type for (message) authentication keys */ struct GNUNET_CRYPTO_AuthKey { unsigned char key[GNUNET_CRYPTO_HASH_LENGTH]; }; /* **************** Functions and Macros ************* */ /** * Seed a weak random generator. Only GNUNET_CRYPTO_QUALITY_WEAK-mode generator * can be seeded. * * @param seed the seed to use */ void GNUNET_CRYPTO_seed_weak_random (int32_t seed); /** * Perform an incremental step in a CRC16 (for TCP/IP) calculation. * * @param sum current sum, initially 0 * @param buf buffer to calculate CRC over (must be 16-bit aligned) * @param len number of bytes in hdr, must be multiple of 2 * @return updated crc sum (must be subjected to GNUNET_CRYPTO_crc16_finish to get actual crc16) */ uint32_t GNUNET_CRYPTO_crc16_step (uint32_t sum, const void *buf, size_t len); /** * Convert results from GNUNET_CRYPTO_crc16_step to final crc16. * * @param sum cummulative sum * @return crc16 value */ uint16_t GNUNET_CRYPTO_crc16_finish (uint32_t sum); /** * Calculate the checksum of a buffer in one step. * * @param buf buffer to calculate CRC over (must be 16-bit aligned) * @param len number of bytes in hdr, must be multiple of 2 * @return crc16 value */ uint16_t GNUNET_CRYPTO_crc16_n (const void *buf, size_t len); /** * Compute the CRC32 checksum for the first len * bytes of the buffer. * * @param buf the data over which we're taking the CRC * @param len the length of the buffer in bytes * @return the resulting CRC32 checksum */ int32_t GNUNET_CRYPTO_crc32_n (const void *buf, size_t len); /** * Produce a random value. * * @param mode desired quality of the random number * @param i the upper limit (exclusive) for the random number * @return a random value in the interval [0,i) (exclusive). */ uint32_t GNUNET_CRYPTO_random_u32 (enum GNUNET_CRYPTO_Quality mode, uint32_t i); /** * Random on unsigned 64-bit values. * * @param mode desired quality of the random number * @param max value returned will be in range [0,max) (exclusive) * @return random 64-bit number */ uint64_t GNUNET_CRYPTO_random_u64 (enum GNUNET_CRYPTO_Quality mode, uint64_t max); /** * Get an array with a random permutation of the * numbers 0...n-1. * @param mode GNUNET_CRYPTO_QUALITY_STRONG if the strong (but expensive) PRNG should be used, GNUNET_CRYPTO_QUALITY_WEAK otherwise * @param n the size of the array * @return the permutation array (allocated from heap) */ unsigned int * GNUNET_CRYPTO_random_permute (enum GNUNET_CRYPTO_Quality mode, unsigned int n); /** * Create a new Session key. * * @param key key to initialize */ void GNUNET_CRYPTO_aes_create_session_key (struct GNUNET_CRYPTO_AesSessionKey *key); /** * Check that a new session key is well-formed. * * @param key key to check * @return GNUNET_OK if the key is valid */ int GNUNET_CRYPTO_aes_check_session_key (const struct GNUNET_CRYPTO_AesSessionKey *key); /** * Encrypt a block with the public key of another * host that uses the same cyper. * * @param block the block to encrypt * @param len the size of the block * @param sessionkey the key used to encrypt * @param iv the initialization vector to use, use INITVALUE * for streams. * @return the size of the encrypted block, -1 for errors */ ssize_t GNUNET_CRYPTO_aes_encrypt (const void *block, size_t len, const struct GNUNET_CRYPTO_AesSessionKey *sessionkey, const struct GNUNET_CRYPTO_AesInitializationVector *iv, void *result); /** * Decrypt a given block with the sessionkey. * * @param block the data to decrypt, encoded as returned by encrypt * @param size how big is the block? * @param sessionkey the key used to decrypt * @param iv the initialization vector to use * @param result address to store the result at * @return -1 on failure, size of decrypted block on success */ ssize_t GNUNET_CRYPTO_aes_decrypt (const void *block, size_t size, const struct GNUNET_CRYPTO_AesSessionKey *sessionkey, const struct GNUNET_CRYPTO_AesInitializationVector *iv, void *result); /** * @brief Derive an IV * @param iv initialization vector * @param skey session key * @param salt salt for the derivation * @param salt_len size of the salt * @param ... pairs of void * & size_t for context chunks, terminated by NULL */ void GNUNET_CRYPTO_aes_derive_iv (struct GNUNET_CRYPTO_AesInitializationVector *iv, const struct GNUNET_CRYPTO_AesSessionKey *skey, const void *salt, size_t salt_len, ...); /** * @brief Derive an IV * @param iv initialization vector * @param skey session key * @param salt salt for the derivation * @param salt_len size of the salt * @param argp pairs of void * & size_t for context chunks, terminated by NULL */ void GNUNET_CRYPTO_aes_derive_iv_v (struct GNUNET_CRYPTO_AesInitializationVector *iv, const struct GNUNET_CRYPTO_AesSessionKey *skey, const void *salt, size_t salt_len, va_list argp); /** * Convert hash to ASCII encoding. * @param block the hash code * @param result where to store the encoding (struct GNUNET_CRYPTO_HashAsciiEncoded can be * safely cast to char*, a '\\0' termination is set). */ void GNUNET_CRYPTO_hash_to_enc (const GNUNET_HashCode * block, struct GNUNET_CRYPTO_HashAsciiEncoded *result); /** * Convert short hash to ASCII encoding. * * @param block the hash code * @param result where to store the encoding (struct GNUNET_CRYPTO_ShortHashAsciiEncoded can be * safely cast to char*, a '\\0' termination is set). */ void GNUNET_CRYPTO_short_hash_to_enc (const struct GNUNET_CRYPTO_ShortHashCode * block, struct GNUNET_CRYPTO_ShortHashAsciiEncoded *result); /** * Convert ASCII encoding back to a 'GNUNET_HashCode' * * @param enc the encoding * @param enclen number of characters in 'enc' (without 0-terminator, which can be missing) * @param result where to store the GNUNET_CRYPTO_hash code * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding */ int GNUNET_CRYPTO_hash_from_string2 (const char *enc, size_t enclen, GNUNET_HashCode * result); /** * Convert ASCII encoding back to a 'struct GNUNET_CRYPTO_ShortHash' * * @param enc the encoding * @param enclen number of characters in 'enc' (without 0-terminator, which can be missing) * @param result where to store the GNUNET_CRYPTO_hash code * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding */ int GNUNET_CRYPTO_short_hash_from_string2 (const char *enc, size_t enclen, struct GNUNET_CRYPTO_ShortHashCode * result); /** * Convert ASCII encoding back to GNUNET_HashCode * * @param enc the encoding * @param result where to store the hash code * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding */ #define GNUNET_CRYPTO_hash_from_string(enc, result) \ GNUNET_CRYPTO_hash_from_string2 (enc, strlen(enc), result) /** * Convert ASCII encoding back to a 'struct GNUNET_CRYPTO_ShortHash' * * @param enc the encoding * @param result where to store the GNUNET_CRYPTO_ShortHash * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding */ #define GNUNET_CRYPTO_short_hash_from_string(enc, result) \ GNUNET_CRYPTO_short_hash_from_string2 (enc, strlen(enc), result) /** * Compare function for ShortHashCodes, producing a total ordering * of all hashcodes. * * @param h1 some hash code * @param h2 some hash code * @return 1 if h1 > h2, -1 if h1 < h2 and 0 if h1 == h2. */ int GNUNET_CRYPTO_short_hash_cmp (const struct GNUNET_CRYPTO_ShortHashCode * h1, const struct GNUNET_CRYPTO_ShortHashCode * h2); /** * Compute the distance between 2 hashcodes. * The computation must be fast, not involve * a.a or a.e (they're used elsewhere), and * be somewhat consistent. And of course, the * result should be a positive number. * * @param a some hash code * @param b some hash code * @return number between 0 and UINT32_MAX */ uint32_t GNUNET_CRYPTO_hash_distance_u32 (const GNUNET_HashCode * a, const GNUNET_HashCode * b); /** * Compute hash of a given block. * * @param block the data to hash * @param size size of the block * @param ret pointer to where to write the hashcode */ void GNUNET_CRYPTO_hash (const void *block, size_t size, GNUNET_HashCode * ret); /** * Compute short (256-bit) hash of a given block. * * @param block the data to hash * @param size size of the block * @param ret pointer to where to write the hashcode */ void GNUNET_CRYPTO_short_hash (const void *block, size_t size, struct GNUNET_CRYPTO_ShortHashCode * ret); /** * Double short (256-bit) hash to create a long hash. * * @param sh short hash to double * @param dh where to store the (doubled) long hash (not really a hash) */ void GNUNET_CRYPTO_short_hash_double (const struct GNUNET_CRYPTO_ShortHashCode *sh, struct GNUNET_HashCode *dh); /** * Truncate doubled short hash back to a short hash. * * @param dh doubled short hash to reduce again * @param sh where to store the short hash * @return GNUNET_OK on success, GNUNET_SYSERR if this was not a * doubled short hash */ int GNUNET_CRYPTO_short_hash_from_truncation (const struct GNUNET_HashCode *dh, struct GNUNET_CRYPTO_ShortHashCode *sh); /** * Calculate HMAC of a message (RFC 2104) * * @param key secret key * @param plaintext input plaintext * @param plaintext_len length of plaintext * @param hmac where to store the hmac */ void GNUNET_CRYPTO_hmac (const struct GNUNET_CRYPTO_AuthKey *key, const void *plaintext, size_t plaintext_len, GNUNET_HashCode * hmac); /** * Function called once the hash computation over the * specified file has completed. * * @param cls closure * @param res resulting hash, NULL on error */ typedef void (*GNUNET_CRYPTO_HashCompletedCallback) (void *cls, const GNUNET_HashCode * res); /** * Handle to file hashing operation. */ struct GNUNET_CRYPTO_FileHashContext; /** * Compute the hash of an entire file. * * @param priority scheduling priority to use * @param filename name of file to hash * @param blocksize number of bytes to process in one task * @param callback function to call upon completion * @param callback_cls closure for callback * @return NULL on (immediate) errror */ struct GNUNET_CRYPTO_FileHashContext * GNUNET_CRYPTO_hash_file (enum GNUNET_SCHEDULER_Priority priority, const char *filename, size_t blocksize, GNUNET_CRYPTO_HashCompletedCallback callback, void *callback_cls); /** * Cancel a file hashing operation. * * @param fhc operation to cancel (callback must not yet have been invoked) */ void GNUNET_CRYPTO_hash_file_cancel (struct GNUNET_CRYPTO_FileHashContext *fhc); /** * Create a random hash code. * * @param mode desired quality level * @param result hash code that is randomized */ void GNUNET_CRYPTO_hash_create_random (enum GNUNET_CRYPTO_Quality mode, GNUNET_HashCode * result); /** * compute result(delta) = b - a * * @param a some hash code * @param b some hash code * @param result set to b - a */ void GNUNET_CRYPTO_hash_difference (const GNUNET_HashCode * a, const GNUNET_HashCode * b, GNUNET_HashCode * result); /** * compute result(b) = a + delta * * @param a some hash code * @param delta some hash code * @param result set to a + delta */ void GNUNET_CRYPTO_hash_sum (const GNUNET_HashCode * a, const GNUNET_HashCode * delta, GNUNET_HashCode * result); /** * compute result = a ^ b * * @param a some hash code * @param b some hash code * @param result set to a ^ b */ void GNUNET_CRYPTO_hash_xor (const GNUNET_HashCode * a, const GNUNET_HashCode * b, GNUNET_HashCode * result); /** * Convert a hashcode into a key. * * @param hc hash code that serves to generate the key * @param skey set to a valid session key * @param iv set to a valid initialization vector */ void GNUNET_CRYPTO_hash_to_aes_key (const GNUNET_HashCode * hc, struct GNUNET_CRYPTO_AesSessionKey *skey, struct GNUNET_CRYPTO_AesInitializationVector *iv); /** * Obtain a bit from a hashcode. * * @param code the GNUNET_CRYPTO_hash to index bit-wise * @param bit index into the hashcode, [0...159] * @return Bit \a bit from hashcode \a code, -1 for invalid index */ int GNUNET_CRYPTO_hash_get_bit (const GNUNET_HashCode * code, unsigned int bit); /** * Determine how many low order bits match in two * GNUNET_HashCodes. i.e. - 010011 and 011111 share * the first two lowest order bits, and therefore the * return value is two (NOT XOR distance, nor how many * bits match absolutely!). * * @param first the first hashcode * @param second the hashcode to compare first to * * @return the number of bits that match */ unsigned int GNUNET_CRYPTO_hash_matching_bits (const GNUNET_HashCode * first, const GNUNET_HashCode * second); /** * Compare function for HashCodes, producing a total ordering * of all hashcodes. * * @param h1 some hash code * @param h2 some hash code * @return 1 if h1 > h2, -1 if h1 < h2 and 0 if h1 == h2. */ int GNUNET_CRYPTO_hash_cmp (const GNUNET_HashCode * h1, const GNUNET_HashCode * h2); /** * Find out which of the two GNUNET_CRYPTO_hash codes is closer to target * in the XOR metric (Kademlia). * * @param h1 some hash code * @param h2 some hash code * @param target some hash code * @return -1 if h1 is closer, 1 if h2 is closer and 0 if h1==h2. */ int GNUNET_CRYPTO_hash_xorcmp (const GNUNET_HashCode * h1, const GNUNET_HashCode * h2, const GNUNET_HashCode * target); /** * @brief Derive an authentication key * @param key authentication key * @param rkey root key * @param salt salt * @param salt_len size of the salt * @param argp pair of void * & size_t for context chunks, terminated by NULL */ void GNUNET_CRYPTO_hmac_derive_key_v (struct GNUNET_CRYPTO_AuthKey *key, const struct GNUNET_CRYPTO_AesSessionKey *rkey, const void *salt, size_t salt_len, va_list argp); /** * @brief Derive an authentication key * @param key authentication key * @param rkey root key * @param salt salt * @param salt_len size of the salt * @param ... pair of void * & size_t for context chunks, terminated by NULL */ void GNUNET_CRYPTO_hmac_derive_key (struct GNUNET_CRYPTO_AuthKey *key, const struct GNUNET_CRYPTO_AesSessionKey *rkey, const void *salt, size_t salt_len, ...); /** * @brief Derive key * @param result buffer for the derived key, allocated by caller * @param out_len desired length of the derived key * @param xtr_algo hash algorithm for the extraction phase, GCRY_MD_... * @param prf_algo hash algorithm for the expansion phase, GCRY_MD_... * @param xts salt * @param xts_len length of xts * @param skm source key material * @param skm_len length of skm * @return GNUNET_YES on success */ int GNUNET_CRYPTO_hkdf (void *result, size_t out_len, int xtr_algo, int prf_algo, const void *xts, size_t xts_len, const void *skm, size_t skm_len, ...); /** * @brief Derive key * @param result buffer for the derived key, allocated by caller * @param out_len desired length of the derived key * @param xtr_algo hash algorithm for the extraction phase, GCRY_MD_... * @param prf_algo hash algorithm for the expansion phase, GCRY_MD_... * @param xts salt * @param xts_len length of xts * @param skm source key material * @param skm_len length of skm * @param argp va_list of void * & size_t pairs for context chunks * @return GNUNET_YES on success */ int GNUNET_CRYPTO_hkdf_v (void *result, size_t out_len, int xtr_algo, int prf_algo, const void *xts, size_t xts_len, const void *skm, size_t skm_len, va_list argp); /** * @brief Derive key * @param result buffer for the derived key, allocated by caller * @param out_len desired length of the derived key * @param xts salt * @param xts_len length of xts * @param skm source key material * @param skm_len length of skm * @param argp va_list of void * & size_t pairs for context chunks * @return GNUNET_YES on success */ int GNUNET_CRYPTO_kdf_v (void *result, size_t out_len, const void *xts, size_t xts_len, const void *skm, size_t skm_len, va_list argp); /** * @brief Derive key * @param result buffer for the derived key, allocated by caller * @param out_len desired length of the derived key * @param xts salt * @param xts_len length of xts * @param skm source key material * @param skm_len length of skm * @param ... void * & size_t pairs for context chunks * @return GNUNET_YES on success */ int GNUNET_CRYPTO_kdf (void *result, size_t out_len, const void *xts, size_t xts_len, const void *skm, size_t skm_len, ...); /** * Create a new private key. Caller must free return value. * * @return fresh private key */ struct GNUNET_CRYPTO_RsaPrivateKey * GNUNET_CRYPTO_rsa_key_create (void); /** * Convert a public key to a string. * * @param pub key to convert * @return string representing 'pub' */ char * GNUNET_CRYPTO_rsa_public_key_to_string (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pub); /** * Convert a string representing a public key to a public key. * * @param enc encoded public key * @param enclen number of bytes in enc (without 0-terminator) * @param pub where to store the public key * @return GNUNET_OK on success */ int GNUNET_CRYPTO_rsa_public_key_from_string (const char *enc, size_t enclen, struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pub); /** * Encode the private key in a format suitable for * storing it into a file. * @returns encoding of the private key. * The first 4 bytes give the size of the array, as usual. */ struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded * GNUNET_CRYPTO_rsa_encode_key (const struct GNUNET_CRYPTO_RsaPrivateKey *hostkey); /** * Decode the private key from the data-format back * to the "normal", internal format. * * @param buf the buffer where the private key data is stored * @param len the length of the data in 'buffer' */ struct GNUNET_CRYPTO_RsaPrivateKey * GNUNET_CRYPTO_rsa_decode_key (const char *buf, uint16_t len); /** * Create a new private key by reading it from a file. If the * files does not exist, create a new key and write it to the * file. Caller must free return value. Note that this function * can not guarantee that another process might not be trying * the same operation on the same file at the same time. * If the contents of the file * are invalid the old file is deleted and a fresh key is * created. * * @param filename name of file to use for storage * @return new private key, NULL on error (for example, * permission denied) */ struct GNUNET_CRYPTO_RsaPrivateKey * GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename); /** * Setup a hostkey file for a peer given the name of the * configuration file (!). This function is used so that * at a later point code can be certain that reading a * hostkey is fast (for example in time-dependent testcases). * * @param cfg_name name of the configuration file to use */ void GNUNET_CRYPTO_setup_hostkey (const char *cfg_name); /** * Deterministically (!) create a private key using only the * given HashCode as input to the PRNG. * * @param hc "random" input to PRNG * @return some private key purely dependent on input */ struct GNUNET_CRYPTO_RsaPrivateKey * GNUNET_CRYPTO_rsa_key_create_from_hash (const GNUNET_HashCode * hc); /** * Free memory occupied by the private key. * @param hostkey pointer to the memory to free */ void GNUNET_CRYPTO_rsa_key_free (struct GNUNET_CRYPTO_RsaPrivateKey *hostkey); /** * Extract the public key of the host. * * @param priv the private key * @param pub where to write the public key */ void GNUNET_CRYPTO_rsa_key_get_public (const struct GNUNET_CRYPTO_RsaPrivateKey *priv, struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pub); /** * Encrypt a block with the public key of another host that uses the * same cyper. * * @param block the block to encrypt * @param size the size of block * @param publicKey the encoded public key used to encrypt * @param target where to store the encrypted block * @return GNUNET_SYSERR on error, GNUNET_OK if ok */ int GNUNET_CRYPTO_rsa_encrypt (const void *block, size_t size, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey, struct GNUNET_CRYPTO_RsaEncryptedData *target); /** * Decrypt a given block with the hostkey. * * @param key the key to use * @param block the data to decrypt, encoded as returned by encrypt, not consumed * @param result pointer to a location where the result can be stored * @param max how many bytes of a result are expected? Must be exact. * @return the size of the decrypted block (that is, size) or -1 on error */ ssize_t GNUNET_CRYPTO_rsa_decrypt (const struct GNUNET_CRYPTO_RsaPrivateKey *key, const struct GNUNET_CRYPTO_RsaEncryptedData *block, void *result, size_t max); /** * Sign a given block. * * @param key private key to use for the signing * @param purpose what to sign (size, purpose) * @param sig where to write the signature * @return GNUNET_SYSERR on error, GNUNET_OK on success */ int GNUNET_CRYPTO_rsa_sign (const struct GNUNET_CRYPTO_RsaPrivateKey *key, const struct GNUNET_CRYPTO_RsaSignaturePurpose *purpose, struct GNUNET_CRYPTO_RsaSignature *sig); /** * Verify signature. Note that the caller MUST have already * checked that "validate->size" bytes are actually available. * * @param purpose what is the purpose that validate should have? * @param validate block to validate (size, purpose, data) * @param sig signature that is being validated * @param publicKey public key of the signer * @return GNUNET_OK if ok, GNUNET_SYSERR if invalid */ int GNUNET_CRYPTO_rsa_verify (uint32_t purpose, const struct GNUNET_CRYPTO_RsaSignaturePurpose *validate, const struct GNUNET_CRYPTO_RsaSignature *sig, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey); /** * This function should only be called in testcases * where strong entropy gathering is not desired * (for example, for hostkey generation). */ void GNUNET_CRYPTO_random_disable_entropy_gathering (void); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_CRYPTO_LIB_H */ #endif /* end of gnunet_crypto_lib.h */ gnunet-0.9.3/src/include/gnunet_bandwidth_lib.h0000644000175000017500000001462411760502551016512 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_bandwidth_lib.h * @brief functions related to bandwidth (unit) * @author Christian Grothoff */ #ifndef GNUNET_BANDWIDTH_LIB_H #define GNUNET_BANDWIDTH_LIB_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_common.h" #include "gnunet_time_lib.h" GNUNET_NETWORK_STRUCT_BEGIN /** * 32-bit bandwidth used for network exchange by GNUnet, in bytes per second. */ struct GNUNET_BANDWIDTH_Value32NBO { /** * The actual value (bytes per second). */ uint32_t value__ GNUNET_PACKED; }; GNUNET_NETWORK_STRUCT_END /** * Struct to track available bandwidth. Combines a time stamp with a * number of bytes transmitted, a quota and a maximum amount that * carries over. Not opaque so that it can be inlined into data * structures (reducing malloc-ing); however, values should not be * accessed directly by clients (hence the '__'). */ struct GNUNET_BANDWIDTH_Tracker { /** * Number of bytes consumed since we last updated the tracker. */ int64_t consumption_since_last_update__; /** * Time when we last updated the tracker. */ struct GNUNET_TIME_Absolute last_update__; /** * Bandwidth limit to enforce in bytes per s. */ uint32_t available_bytes_per_s__; /** * Maximum number of seconds over which bandwidth may "accumulate". * Note that additionally, we also always allow at least * GNUNET_SERVER_MAX_MESSAGE_SIZE to accumulate. */ uint32_t max_carry_s__; }; /** * Create a new bandwidth value. * * @param bytes_per_second value to create * @return the new bandwidth value */ struct GNUNET_BANDWIDTH_Value32NBO GNUNET_BANDWIDTH_value_init (uint32_t bytes_per_second); /** * Maximum possible bandwidth value. */ #define GNUNET_BANDWIDTH_VALUE_MAX GNUNET_BANDWIDTH_value_init(UINT32_MAX) /** * At the given bandwidth, calculate how much traffic will be * available until the given deadline. * * @param bps bandwidth * @param deadline when is the deadline * @return number of bytes available at bps until deadline */ uint64_t GNUNET_BANDWIDTH_value_get_available_until (struct GNUNET_BANDWIDTH_Value32NBO bps, struct GNUNET_TIME_Relative deadline); /** * At the given bandwidth, calculate how long it would take for * 'size' bytes to be transmitted. * * @param bps bandwidth * @param size number of bytes we want to have available * @return how long it would take */ struct GNUNET_TIME_Relative GNUNET_BANDWIDTH_value_get_delay_for (struct GNUNET_BANDWIDTH_Value32NBO bps, uint64_t size); /** * Compute the MIN of two bandwidth values. * * @param b1 first value * @param b2 second value * @return the min of b1 and b2 */ struct GNUNET_BANDWIDTH_Value32NBO GNUNET_BANDWIDTH_value_min (struct GNUNET_BANDWIDTH_Value32NBO b1, struct GNUNET_BANDWIDTH_Value32NBO b2); /** * Initialize bandwidth tracker. Note that in addition to the * 'max_carry_s' limit, we also always allow at least * GNUNET_SERVER_MAX_MESSAGE_SIZE to accumulate. So if the * bytes-per-second limit is so small that within 'max_carry_s' not * even GNUNET_SERVER_MAX_MESSAGE_SIZE is allowed to accumulate, it is * ignored and replaced by GNUNET_SERVER_MAX_MESSAGE_SIZE (which is in * bytes). * * @param av tracker to initialize * @param bytes_per_second_limit initial limit to assume * @param max_carry_s maximum number of seconds unused bandwidth * may accumulate before it expires */ void GNUNET_BANDWIDTH_tracker_init (struct GNUNET_BANDWIDTH_Tracker *av, struct GNUNET_BANDWIDTH_Value32NBO bytes_per_second_limit, uint32_t max_carry_s); /** * Notify the tracker that a certain number of bytes of bandwidth have * been consumed. Note that it is legal to consume bytes even if not * enough bandwidth is available (in that case, * GNUNET_BANDWIDTH_tracker_get_delay may return non-zero delay values * even for a size of zero for a while). * * @param av tracker to update * @param size number of bytes consumed * @return GNUNET_YES if this consumption is above the limit */ int GNUNET_BANDWIDTH_tracker_consume (struct GNUNET_BANDWIDTH_Tracker *av, ssize_t size); /** * Compute how long we should wait until consuming 'size' * bytes of bandwidth in order to stay within the given * quota. * * @param av tracker to query * @param size number of bytes we would like to consume * @return time to wait for consumption to be OK */ struct GNUNET_TIME_Relative GNUNET_BANDWIDTH_tracker_get_delay (struct GNUNET_BANDWIDTH_Tracker *av, size_t size); /** * Compute how many bytes are available for consumption right now. * quota. * * @param av tracker to query * @return number of bytes available for consumption right now */ int64_t GNUNET_BANDWIDTH_tracker_get_available (struct GNUNET_BANDWIDTH_Tracker *av); /** * Update quota of bandwidth tracker. * * @param av tracker to initialize * @param bytes_per_second_limit new limit to assume */ void GNUNET_BANDWIDTH_tracker_update_quota (struct GNUNET_BANDWIDTH_Tracker *av, struct GNUNET_BANDWIDTH_Value32NBO bytes_per_second_limit); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_BANDWIDTH_LIB_H */ #endif /* end of gnunet_bandwidth_lib.h */ gnunet-0.9.3/src/include/gnunet_fragmentation_lib.h0000644000175000017500000001501211760502551017374 00000000000000/* This file is part of GNUnet (C) 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_fragmentation_lib.h * @brief library to help fragment messages * @author Christian Grothoff * * TODO: consider additional flow-control for sending from * fragmentation based on continuations. */ #ifndef GNUNET_FRAGMENTATION_LIB_H #define GNUNET_FRAGMENTATION_LIB_H #include "gnunet_util_lib.h" #include "gnunet_bandwidth_lib.h" #include "gnunet_statistics_service.h" #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * Fragmentation context. */ struct GNUNET_FRAGMENT_Context; /** * Function that is called with messages created by the fragmentation * module. In the case of the 'proc' callback of the * GNUNET_FRAGMENT_context_create function, this function must * eventually call 'GNUNET_FRAGMENT_context_transmission_done'. * * @param cls closure * @param msg the message that was created */ typedef void (*GNUNET_FRAGMENT_MessageProcessor) (void *cls, const struct GNUNET_MessageHeader * msg); /** * Create a fragmentation context for the given message. * Fragments the message into fragments of size "mtu" or * less. Calls 'proc' on each un-acknowledged fragment, * using both the expected 'delay' between messages and * acknowledgements and the given 'tracker' to guide the * frequency of calls to 'proc'. * * @param stats statistics context * @param mtu the maximum message size for each fragment * @param tracker bandwidth tracker to use for flow control (can be NULL) * @param delay expected delay between fragment transmission * and ACK based on previous messages * @param msg the message to fragment * @param proc function to call for each fragment to transmit * @param proc_cls closure for proc * @return the fragmentation context */ struct GNUNET_FRAGMENT_Context * GNUNET_FRAGMENT_context_create (struct GNUNET_STATISTICS_Handle *stats, uint16_t mtu, struct GNUNET_BANDWIDTH_Tracker *tracker, struct GNUNET_TIME_Relative delay, const struct GNUNET_MessageHeader *msg, GNUNET_FRAGMENT_MessageProcessor proc, void *proc_cls); /** * Continuation to call from the 'proc' function after the fragment * has been transmitted (and hence the next fragment can now be * given to proc). * * @param fc fragmentation context */ void GNUNET_FRAGMENT_context_transmission_done (struct GNUNET_FRAGMENT_Context *fc); /** * Process an acknowledgement message we got from the other * side (to control re-transmits). * * @param fc fragmentation context * @param msg acknowledgement message we received * @return GNUNET_OK if this ack completes the work of the 'fc' * (all fragments have been received); * GNUNET_NO if more messages are pending * GNUNET_SYSERR if this ack is not valid for this fc */ int GNUNET_FRAGMENT_process_ack (struct GNUNET_FRAGMENT_Context *fc, const struct GNUNET_MessageHeader *msg); /** * Destroy the given fragmentation context (stop calling 'proc', free * resources). * * @param fc fragmentation context * @return average delay between transmission and ACK for the * last message, FOREVER if the message was not fully transmitted */ struct GNUNET_TIME_Relative GNUNET_FRAGMENT_context_destroy (struct GNUNET_FRAGMENT_Context *fc); /** * Defragmentation context (one per connection). */ struct GNUNET_DEFRAGMENT_Context; /** * Function that is called with acknowledgement messages created by * the fragmentation module. Acknowledgements are cummulative, * so it is OK to only transmit the 'latest' ack message for the same * message ID. * * @param cls closure * @param id unique message ID (modulo collisions) * @param msg the message that was created */ typedef void (*GNUNET_DEFRAGMENT_AckProcessor) (void *cls, uint32_t id, const struct GNUNET_MessageHeader * msg); /** * Create a defragmentation context. * * @param stats statistics context * @param mtu the maximum message size for each fragment * @param num_msgs how many fragmented messages * to we defragment at most at the same time? * @param cls closure for proc and ackp * @param proc function to call with defragmented messages * @param ackp function to call with acknowledgements (to send * back to the other side) * @return the defragmentation context */ struct GNUNET_DEFRAGMENT_Context * GNUNET_DEFRAGMENT_context_create (struct GNUNET_STATISTICS_Handle *stats, uint16_t mtu, unsigned int num_msgs, void *cls, GNUNET_FRAGMENT_MessageProcessor proc, GNUNET_DEFRAGMENT_AckProcessor ackp); /** * Destroy the given defragmentation context. * * @param dc defragmentation context */ void GNUNET_DEFRAGMENT_context_destroy (struct GNUNET_DEFRAGMENT_Context *dc); /** * We have received a fragment. Process it. * * @param dc the context * @param msg the message that was received * @return GNUNET_OK on success, GNUNET_NO if this was a duplicate, GNUNET_SYSERR on error */ int GNUNET_DEFRAGMENT_process_fragment (struct GNUNET_DEFRAGMENT_Context *dc, const struct GNUNET_MessageHeader *msg); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* end of gnunet_fragmentation_lib.h */ #endif gnunet-0.9.3/src/include/gnunet_vpn_service.h0000644000175000017500000001311411760502551016234 00000000000000/* This file is part of GNUnet (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_vpn_service.h * @brief API to access the VPN service. * @author Christian Grothoff */ #ifndef GNUNET_VPN_SERVICE_H #define GNUNET_VPN_SERVICE_H #include "gnunet_util_lib.h" /** * Opaque VPN handle */ struct GNUNET_VPN_Handle; /** * Opaque redirection request handle. */ struct GNUNET_VPN_RedirectionRequest; /** * Callback invoked from the VPN service once a redirection is * available. Provides the IP address that can now be used to * reach the requested destination. * * @param cls closure * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error; * will match 'result_af' from the request * @param address IP address (struct in_addr or struct in_addr6, depending on 'af') * that the VPN allocated for the redirection; * traffic to this IP will now be redirected to the * specified target peer; NULL on error */ typedef void (*GNUNET_VPN_AllocationCallback)(void *cls, int af, const void *address); /** * Cancel redirection request with the service. * * @param rr request to cancel */ void GNUNET_VPN_cancel_request (struct GNUNET_VPN_RedirectionRequest *rr); /** * Tell the VPN that a forwarding to a particular peer offering a * particular service is requested. The VPN is to reserve a * particular IP for the redirection and return it. The VPN will * begin the redirection as soon as possible and maintain it as long * as it is actively used and keeping it is feasible. Given resource * limitations, the longest inactive mappings will be destroyed. * * @param vh VPN handle * @param result_af desired address family for the returned allocation * can also be AF_UNSPEC * @param protocol protocol, IPPROTO_UDP or IPPROTO_TCP * @param peer target peer for the redirection * @param serv service descriptor to give to the peer * @param nac GNUNET_YES to notify via callback only after completion of * the MESH-level connection, * GNUNET_NO to notify as soon as the IP has been reserved * @param expiration_time at what time should the redirection expire? * (this should not impact connections that are active at that time) * @param cb function to call with the IP * @param cb_cls closure for cb * @return handle to cancel the request (means the callback won't be * invoked anymore; the mapping may or may not be established * anyway) */ struct GNUNET_VPN_RedirectionRequest * GNUNET_VPN_redirect_to_peer (struct GNUNET_VPN_Handle *vh, int result_af, uint8_t protocol, const struct GNUNET_PeerIdentity *peer, const GNUNET_HashCode *serv, int nac, struct GNUNET_TIME_Absolute expiration_time, GNUNET_VPN_AllocationCallback cb, void *cb_cls); /** * Tell the VPN that forwarding to the Internet via some exit node is * requested. Note that both UDP and TCP traffic will be forwarded, * but possibly to different exit nodes. The VPN is to reserve a * particular IP for the redirection and return it. The VPN will * begin the redirection as soon as possible and maintain it as long * as it is actively used and keeping it is feasible. Given resource * limitations, the longest inactive mappings will be destroyed. * * @param vh VPN handle * @param result_af desired address family for the returned allocation, * can also be AF_UNSPEC * @param addr_af address family for 'addr', AF_INET or AF_INET6 * @param addr destination IP address on the Internet; destination * port is to be taken from the VPN packet itself * @param nac GNUNET_YES to notify via callback only after completion of * the MESH-level connection, * GNUNET_NO to notify as soon as the IP has been reserved * @param expiration_time at what time should the redirection expire? * (this should not impact connections that are active at that time) * @param cb function to call with the IP * @param cb_cls closure for cb * @return handle to cancel the request (means the callback won't be * invoked anymore; the mapping may or may not be established * anyway) */ struct GNUNET_VPN_RedirectionRequest * GNUNET_VPN_redirect_to_ip (struct GNUNET_VPN_Handle *vh, int result_af, int addr_af, const void *addr, int nac, struct GNUNET_TIME_Absolute expiration_time, GNUNET_VPN_AllocationCallback cb, void *cb_cls); /** * Connect to the VPN service * * @param cfg configuration to use * @return VPN handle */ struct GNUNET_VPN_Handle * GNUNET_VPN_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); /** * Disconnect from the VPN service. * * @param vh VPN handle */ void GNUNET_VPN_disconnect (struct GNUNET_VPN_Handle *vh); #endif gnunet-0.9.3/src/include/gnunet_nse_service.h0000644000175000017500000000605711760502551016226 00000000000000/* This file is part of GNUnet (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef GNUNET_NSE_SERVICE_H_ #define GNUNET_NSE_SERVICE_H_ /** * @file include/gnunet_nse_service.h * @brief API to retrieve the current network size estimate, * also to register for notifications whenever a new * network size estimate is calculated. * * @author Nathan Evans */ #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_common.h" #include "gnunet_configuration_lib.h" #include "gnunet_scheduler_lib.h" /** * Version of the network size estimation API. */ #define GNUNET_NSE_VERSION 0x00000000 /** * Handle for the network size estimation service. */ struct GNUNET_NSE_Handle; /** * Callback to call when network size estimate is updated. * * @param cls closure * @param timestamp time when the estimate was received from the server (or created by the server) * @param logestimate the log(Base 2) value of the current network size estimate * @param std_dev standard deviation for the estimate * */ typedef void (*GNUNET_NSE_Callback) (void *cls, struct GNUNET_TIME_Absolute timestamp, double logestimate, double std_dev); /** * Convert the logarithmic estimated returned to the 'GNUNET_NSE_Callback' * into an absolute estimate in terms of the number of peers in the network. * * @param loge logarithmic estimate * @return absolute number of peers in the network (estimated) */ #define GNUNET_NSE_log_estimate_to_n(loge) pow(2.0, (loge)) /** * Connect to the network size estimation service. * * @param cfg the configuration to use * @param func funtion to call with network size estimate * @param func_cls closure to pass for network size estimate callback * * @return handle to use */ struct GNUNET_NSE_Handle * GNUNET_NSE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_NSE_Callback func, void *func_cls); /** * Disconnect from network size estimation service * * @param h handle to destroy * */ void GNUNET_NSE_disconnect (struct GNUNET_NSE_Handle *h); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif #endif /* GNUNET_NSE_SERVICE_H_ */ gnunet-0.9.3/src/include/gnunet_protocols.h0000644000175000017500000010263111760502551015740 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_protocols.h * @brief constants for network protocols * @author Christian Grothoff */ #ifndef GNUNET_PROTOCOLS_H #define GNUNET_PROTOCOLS_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /******************************************************************************* * UTIL message types ******************************************************************************/ /** * Test if service is online. */ #define GNUNET_MESSAGE_TYPE_TEST 1 /** * Dummy messages for testing / benchmarking. */ #define GNUNET_MESSAGE_TYPE_DUMMY 2 /******************************************************************************* * RESOLVER message types ******************************************************************************/ /** * Request DNS resolution. */ #define GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST 4 /** * Response to a DNS resolution request. */ #define GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE 5 /******************************************************************************* * ARM message types ******************************************************************************/ /** * Request to ARM to start a service. */ #define GNUNET_MESSAGE_TYPE_ARM_START 8 /** * Request to ARM to stop a service. */ #define GNUNET_MESSAGE_TYPE_ARM_STOP 9 /** * Request ARM service itself to shutdown. */ #define GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN 10 /** * Response from ARM. */ #define GNUNET_MESSAGE_TYPE_ARM_RESULT 11 /** * Request to ARM to list all currently running services */ #define GNUNET_MESSAGE_TYPE_ARM_LIST 12 /** * Response from ARM for listing currently running services */ #define GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT 13 /******************************************************************************* * HELLO message types ******************************************************************************/ /** * HELLO message used for communicating peer addresses. * Managed by libgnunethello. */ #define GNUNET_MESSAGE_TYPE_HELLO 16 /******************************************************************************* * FRAGMENTATION message types ******************************************************************************/ /** * FRAGMENT of a larger message. * Managed by libgnunetfragment. */ #define GNUNET_MESSAGE_TYPE_FRAGMENT 18 /** * Acknowledgement of a FRAGMENT of a larger message. * Managed by libgnunetfragment. */ #define GNUNET_MESSAGE_TYPE_FRAGMENT_ACK 19 /******************************************************************************* * Transport-WLAN message types ******************************************************************************/ /** * Type of data messages from the plugin to the gnunet-wlan-helper */ #define GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER 39 /** * Type of data messages from the gnunet-wlan-helper to the plugin */ #define GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER 40 /** * Control message between the gnunet-wlan-helper and the daemon (with the MAC). */ #define GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL 41 /** * Type of messages for advertisement over wlan */ #define GNUNET_MESSAGE_TYPE_WLAN_ADVERTISEMENT 42 /** * Type of messages for data over the wlan */ #define GNUNET_MESSAGE_TYPE_WLAN_DATA 43 /******************************************************************************* * Transport-DV message types ******************************************************************************/ /** * DV service to DV Plugin message, when a message is * unwrapped by the DV service and handed to the plugin * for processing */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_DV_RECEIVE 44 /** * DV Plugin to DV service message, indicating a message * should be sent out. */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND 45 /** * DV service to DV api message, containing a confirmation * or failure of a DV_SEND message. */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND_RESULT 46 /** * P2P DV message encapsulating some real message */ #define GNUNET_MESSAGE_TYPE_DV_DATA 47 /** * P2P DV message gossipping peer information */ #define GNUNET_MESSAGE_TYPE_DV_GOSSIP 48 /** * DV Plugin to DV service message, indicating * startup. */ #define GNUNET_MESSAGE_TYPE_DV_START 49 /** * P2P DV message notifying connected peers of a disconnect */ #define GNUNET_MESSAGE_TYPE_DV_DISCONNECT 50 /******************************************************************************* * Transport-UDP message types ******************************************************************************/ /** * Normal UDP message type. */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_MESSAGE 56 /** * UDP ACK. */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_ACK 57 /******************************************************************************* * Transport-TCP message types ******************************************************************************/ /** * TCP NAT probe message, send from NAT'd peer to * other peer to establish bi-directional communication */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE 60 /** * Welcome message between TCP transports. */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME 61 /** * Message to force transport to update bandwidth assignment (LEGACY) */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_ATS 62 /******************************************************************************* * NAT message types ******************************************************************************/ /** * Message to ask NAT server to perform traversal test */ #define GNUNET_MESSAGE_TYPE_NAT_TEST 63 /******************************************************************************* * CORE message types ******************************************************************************/ /** * Initial setup message from core client to core. */ #define GNUNET_MESSAGE_TYPE_CORE_INIT 64 /** * Response from core to core client to INIT message. */ #define GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY 65 /** * Notify clients about new peer-to-peer connections (triggered * after key exchange). */ #define GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT 67 /** * Notify clients about peer disconnecting. */ #define GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT 68 /** * Notify clients about peer status change. */ #define GNUNET_MESSAGE_TYPE_CORE_NOTIFY_STATUS_CHANGE 69 /** * Notify clients about incoming P2P messages. */ #define GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND 70 /** * Notify clients about outgoing P2P transmissions. */ #define GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND 71 /** * Request from client to transmit message. */ #define GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST 74 /** * Confirmation from core that message can now be sent */ #define GNUNET_MESSAGE_TYPE_CORE_SEND_READY 75 /** * Client with message to transmit (after SEND_READY confirmation * was received). */ #define GNUNET_MESSAGE_TYPE_CORE_SEND 76 /** * Request for peer iteration from CORE service. */ #define GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS 78 /** * Last reply from core to request for peer iteration from CORE service. */ #define GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END 79 /** * Check whether a given peer is currently connected to CORE. */ #define GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED 80 /** * Session key exchange between peers. */ #define GNUNET_MESSAGE_TYPE_CORE_SET_KEY 81 /** * Encapsulation for an encrypted message between peers. */ #define GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE 82 /** * Check that other peer is alive (challenge). */ #define GNUNET_MESSAGE_TYPE_CORE_PING 83 /** * Confirmation that other peer is alive. */ #define GNUNET_MESSAGE_TYPE_CORE_PONG 84 /** * Request by the other peer to terminate the connection. */ #define GNUNET_MESSAGE_TYPE_CORE_HANGUP 85 /** * gzip-compressed type map of the sender */ #define GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP 86 /** * uncompressed type map of the sender */ #define GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP 87 /******************************************************************************* * DATASTORE message types ******************************************************************************/ /** * Message sent by datastore client on join. */ #define GNUNET_MESSAGE_TYPE_DATASTORE_RESERVE 92 /** * Message sent by datastore client on join. */ #define GNUNET_MESSAGE_TYPE_DATASTORE_RELEASE_RESERVE 93 /** * Message sent by datastore to client informing about status * processing a request * (in response to RESERVE, RELEASE_RESERVE, PUT, UPDATE and REMOVE requests). */ #define GNUNET_MESSAGE_TYPE_DATASTORE_STATUS 94 /** * Message sent by datastore client to store data. */ #define GNUNET_MESSAGE_TYPE_DATASTORE_PUT 95 /** * Message sent by datastore client to update data. */ #define GNUNET_MESSAGE_TYPE_DATASTORE_UPDATE 96 /** * Message sent by datastore client to get data. */ #define GNUNET_MESSAGE_TYPE_DATASTORE_GET 97 /** * Message sent by datastore client to get random data. */ #define GNUNET_MESSAGE_TYPE_DATASTORE_GET_REPLICATION 98 /** * Message sent by datastore client to get random data. */ #define GNUNET_MESSAGE_TYPE_DATASTORE_GET_ZERO_ANONYMITY 99 /** * Message sent by datastore to client providing requested data * (in response to GET or GET_RANDOM request). */ #define GNUNET_MESSAGE_TYPE_DATASTORE_DATA 100 /** * Message sent by datastore to client signaling end of matching data. * This message will also be sent for "GET_RANDOM", even though * "GET_RANDOM" returns at most one data item. */ #define GNUNET_MESSAGE_TYPE_DATASTORE_DATA_END 101 /** * Message sent by datastore client to remove data. */ #define GNUNET_MESSAGE_TYPE_DATASTORE_REMOVE 102 /** * Message sent by datastore client to drop the database. */ #define GNUNET_MESSAGE_TYPE_DATASTORE_DROP 103 /******************************************************************************* * FS message types ******************************************************************************/ /** * Message sent by fs client to start indexing. */ #define GNUNET_MESSAGE_TYPE_FS_INDEX_START 128 /** * Affirmative response to a request for start indexing. */ #define GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK 129 /** * Response to a request for start indexing that * refuses. */ #define GNUNET_MESSAGE_TYPE_FS_INDEX_START_FAILED 130 /** * Request from client for list of indexed files. */ #define GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET 131 /** * Reply to client with an indexed file name. */ #define GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_ENTRY 132 /** * Reply to client indicating end of list. */ #define GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_END 133 /** * Request from client to unindex a file. */ #define GNUNET_MESSAGE_TYPE_FS_UNINDEX 134 /** * Reply to client indicating unindex receipt. */ #define GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK 135 /** * Client asks FS service to start a (keyword) search. */ #define GNUNET_MESSAGE_TYPE_FS_START_SEARCH 136 /** * P2P request for content (one FS to another). */ #define GNUNET_MESSAGE_TYPE_FS_GET 137 /** * P2P response with content or active migration of content. Also * used between the service and clients (in response to START_SEARCH). */ #define GNUNET_MESSAGE_TYPE_FS_PUT 138 /** * Peer asks us to stop migrating content towards it for a while. */ #define GNUNET_MESSAGE_TYPE_FS_MIGRATION_STOP 139 /******************************************************************************* * DHT message types ******************************************************************************/ /** * Client wants to store item in DHT. */ #define GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT 142 /** * Client wants to lookup item in DHT. */ #define GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET 143 /** * Client wants to stop search in DHT. */ #define GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_STOP 144 /** * Service returns result to client. */ #define GNUNET_MESSAGE_TYPE_DHT_CLIENT_RESULT 145 /** * Peer is storing data in DHT. */ #define GNUNET_MESSAGE_TYPE_DHT_P2P_PUT 146 /** * Peer tries to find data in DHT. */ #define GNUNET_MESSAGE_TYPE_DHT_P2P_GET 147 /** * Data is returned to peer from DHT. */ #define GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT 148 /** * Receive information about transiting GETs */ #define GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET 149 /** * Receive information about transiting GET responses */ #define GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET_RESP 150 /** * Receive information about transiting PUTs */ #define GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT 151 /** * Receive information about transiting PUT responses (TODO) */ #define GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT_RESP 152 /** * Request information about transiting messages */ #define GNUNET_MESSAGE_TYPE_DHT_MONITOR_START 153 /** * Stop information about transiting messages */ #define GNUNET_MESSAGE_TYPE_DHT_MONITOR_STOP 154 /** * Acknowledge receiving PUT request */ #define GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT_OK 155 /******************************************************************************* * HOSTLIST message types ******************************************************************************/ /** * Hostlist advertisement message */ #define GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT 160 /******************************************************************************* * STATISTICS message types ******************************************************************************/ /** * Set a statistical value. */ #define GNUNET_MESSAGE_TYPE_STATISTICS_SET 168 /** * Get a statistical value(s). */ #define GNUNET_MESSAGE_TYPE_STATISTICS_GET 169 /** * Response to a STATISTICS_GET message (with value). */ #define GNUNET_MESSAGE_TYPE_STATISTICS_VALUE 170 /** * Response to a STATISTICS_GET message (end of value stream). */ #define GNUNET_MESSAGE_TYPE_STATISTICS_END 171 /** * Watch changes to a statistical value. Message format is the same * as for GET, except that the subsystem and entry name must be given. */ #define GNUNET_MESSAGE_TYPE_STATISTICS_WATCH 172 /** * Changes to a watched value. */ #define GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE 173 /******************************************************************************* * VPN message types ******************************************************************************/ /** * Type of messages between the gnunet-vpn-helper and the daemon */ #define GNUNET_MESSAGE_TYPE_VPN_HELPER 185 /** * Type of messages containing an ICMP packet for a service. */ #define GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE 190 /** * Type of messages containing an ICMP packet for the Internet. */ #define GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET 191 /** * Type of messages containing an ICMP packet for the VPN */ #define GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN 192 /** * Type of messages containing an DNS request for a DNS exit service. */ #define GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET 193 /** * Type of messages containing an DNS reply from a DNS exit service. */ #define GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET 194 /** * Type of messages containing an TCP packet for a service. */ #define GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START 195 /** * Type of messages containing an TCP packet for the Internet. */ #define GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START 196 /** * Type of messages containing an TCP packet of an established connection. */ #define GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT 197 /** * Type of messages containing an TCP packet of an established connection. */ #define GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN 198 /** * Type of messages containing an UDP packet for a service. */ #define GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE 199 /** * Type of messages containing an UDP packet for the Internet. */ #define GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET 200 /** * Type of messages containing an UDP packet from a remote host */ #define GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY 201 /** * Client asks VPN service to setup an IP to redirect traffic * via an exit node to some global IP address. */ #define GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP 202 /** * Client asks VPN service to setup an IP to redirect traffic * to some peer offering a service. */ #define GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE 203 /** * VPN service responds to client with an IP to use for the * requested redirection. */ #define GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP 204 /******************************************************************************* * VPN-DNS message types ******************************************************************************/ /** * Initial message from client to DNS service for registration. */ #define GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT 211 /** * Type of messages between the gnunet-helper-dns and the service */ #define GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST 212 /** * Type of messages between the gnunet-helper-dns and the service */ #define GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE 213 /** * Type of messages between the gnunet-helper-dns and the service */ #define GNUNET_MESSAGE_TYPE_DNS_HELPER 214 /******************************************************************************* * MESH message types ******************************************************************************/ /** * Type of message used to transport messages throug a MESH-tunnel (LEGACY) */ #define GNUNET_MESSAGE_TYPE_MESH 215 /** * Type of message used to send another peer which messages we want to receive * through a mesh-tunnel (LEGACY) */ #define GNUNET_MESSAGE_TYPE_MESH_HELLO 216 /** * Request the creation of a path */ #define GNUNET_MESSAGE_TYPE_MESH_PATH_CREATE 256 /** * Request the modification of an existing path */ #define GNUNET_MESSAGE_TYPE_MESH_PATH_CHANGE 257 /** * Notify that a connection of a path is no longer valid */ #define GNUNET_MESSAGE_TYPE_MESH_PATH_BROKEN 258 /** * At some point, the route will spontaneously change */ #define GNUNET_MESSAGE_TYPE_MESH_PATH_CHANGED 259 /** * Transport data in the mesh (origin->end) unicast */ #define GNUNET_MESSAGE_TYPE_MESH_UNICAST 260 /** * Transport data to all peers in a tunnel */ #define GNUNET_MESSAGE_TYPE_MESH_MULTICAST 261 /** * Transport data back in the mesh (end->origin) */ #define GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN 262 /** * Send origin an ACK that the path is complete */ #define GNUNET_MESSAGE_TYPE_MESH_PATH_ACK 263 /** * Avoid path timeouts */ #define GNUNET_MESSAGE_TYPE_MESH_PATH_KEEPALIVE 264 /** * Request the destuction of a path */ #define GNUNET_MESSAGE_TYPE_MESH_PATH_DESTROY 265 /** * Request the destruction of a whole tunnel */ #define GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY 266 /** * We need flow control */ #define GNUNET_MESSAGE_TYPE_MESH_SPEED_NOTIFY 270 /** * Connect to the mesh service, specifying subscriptions */ #define GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT 272 /** * Ask the mesh service to create a new tunnel */ #define GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE 273 /** * Ask the mesh service to destroy a tunnel */ #define GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY 274 /** * Ask the mesh service to add a peer to an existing tunnel */ #define GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD 275 /** * Ask the mesh service to remove a peer from a tunnel */ #define GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL 276 /** * Ask the mesh service to add a peer offering a service to an existing tunnel */ #define GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD_BY_TYPE 277 /** * 640kb should be enough for everybody */ #define GNUNET_MESSAGE_TYPE_MESH_RESERVE_END 288 /******************************************************************************* * CHAT message types START ******************************************************************************/ /** * Message sent from client to join a chat room. */ #define GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST 300 /** * Message sent to client to indicate joining of another room member. */ #define GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION 301 /** * Message sent to client to indicate leaving of another room member. */ #define GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION 302 /** * Notification sent by service to client indicating that we've received a chat * message. */ #define GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION 303 /** * Request sent by client to transmit a chat message to another room members. */ #define GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST 304 /** * Receipt sent from a message receiver to the service to confirm delivery of * a chat message. */ #define GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT 305 /** * Notification sent from the service to the original sender * to acknowledge delivery of a chat message. */ #define GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION 306 /** * P2P message sent to indicate joining of another room member. */ #define GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION 307 /** * P2P message sent to indicate leaving of another room member. */ #define GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION 308 /** * P2P message sent to a newly connected peer to request its known clients in * order to synchronize room members. */ #define GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST 309 /** * Notification sent from one peer to another to indicate that we have received * a chat message. */ #define GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION 310 /** * P2P receipt confirming delivery of a chat message. */ #define GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT 311 /******************************************************************************* * NSE (network size estimation) message types ******************************************************************************/ /** * client->service message indicating start */ #define GNUNET_MESSAGE_TYPE_NSE_START 321 /** * P2P message sent from nearest peer */ #define GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD 322 /** * service->client message indicating */ #define GNUNET_MESSAGE_TYPE_NSE_ESTIMATE 323 /******************************************************************************* * PEERINFO message types ******************************************************************************/ /** * Request update and listing of a peer. */ #define GNUNET_MESSAGE_TYPE_PEERINFO_GET 330 /** * Request update and listing of all peers. */ #define GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL 331 /** * Information about one of the peers. */ #define GNUNET_MESSAGE_TYPE_PEERINFO_INFO 332 /** * End of information about other peers. */ #define GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END 333 /** * Start notifying this client about all changes to * the known peers until it disconnects. */ #define GNUNET_MESSAGE_TYPE_PEERINFO_NOTIFY 334 /******************************************************************************* * ATS message types ******************************************************************************/ /** * Type of the 'struct ClientStartMessage' sent by clients to ATS to * identify the type of the client. */ #define GNUNET_MESSAGE_TYPE_ATS_START 340 /** * Type of the 'struct RequestAddressMessage' sent by clients to ATS * to request an address to help connect. */ #define GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS 341 /** * Type of the 'struct RequestAddressMessage' sent by clients to ATS * to request an address to help connect. */ #define GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS_CANCEL 342 /** * Type of the 'struct AddressUpdateMessage' sent by clients to ATS * to inform ATS about performance changes. */ #define GNUNET_MESSAGE_TYPE_ATS_ADDRESS_UPDATE 343 /** * Type of the 'struct AddressDestroyedMessage' sent by clients to ATS * to inform ATS about an address being unavailable. */ #define GNUNET_MESSAGE_TYPE_ATS_ADDRESS_DESTROYED 344 /** * Type of the 'struct AddressSuggestionMessage' sent by ATS to clients * to suggest switching to a different address. */ #define GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION 345 /** * Type of the 'struct PeerInformationMessage' sent by ATS to clients * to inform about QoS for a particular connection. */ #define GNUNET_MESSAGE_TYPE_ATS_PEER_INFORMATION 346 /** * Type of the 'struct ReservationRequestMessage' sent by clients to ATS * to ask for inbound bandwidth reservations. */ #define GNUNET_MESSAGE_TYPE_ATS_RESERVATION_REQUEST 347 /** * Type of the 'struct ReservationResultMessage' sent by ATS to clients * in response to a reservation request. */ #define GNUNET_MESSAGE_TYPE_ATS_RESERVATION_RESULT 348 /** * Type of the 'struct ChangePreferenceMessage' sent by clients to ATS * to ask for allocation preference changes. */ #define GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_CHANGE 349 /** * Type of the 'struct SessionReleaseMessage' sent by ATS to client * to confirm that a session ID was destroyed. */ #define GNUNET_MESSAGE_TYPE_ATS_SESSION_RELEASE 350 /** * Type of the 'struct AddressUseMessage' sent by ATS to client * to confirm that an address is used or not used anymore */ #define GNUNET_MESSAGE_TYPE_ATS_ADDRESS_IN_USE 351 /** * Type of the 'struct AddressUseMessage' sent by ATS to client * to confirm that an address is used or not used anymore */ #define GNUNET_MESSAGE_TYPE_ATS_RESET_BACKOFF 352 /******************************************************************************* * TRANSPORT message types ******************************************************************************/ /** * Message from the core saying that the transport * server should start giving it messages. This * should automatically trigger the transmission of * a HELLO message. */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_START 360 /** * Message from TRANSPORT notifying about a * client that connected to us. */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT 361 /** * Message from TRANSPORT notifying about a * client that disconnected from us. */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT 362 /** * Request to TRANSPORT to transmit a message. */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_SEND 363 /** * Confirmation from TRANSPORT that message for transmission has been * queued (and that the next message to this peer can now be passed to * the service). Note that this confirmation does NOT imply that the * message was fully transmitted. */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK 364 /** * Message from TRANSPORT notifying about a * message that was received. */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_RECV 365 /** * Message telling transport to limit its receive rate. */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA 366 /** * Request to look addresses of peers in server. */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING 367 /** * Response to the address lookup request. */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY 368 /** * Register a client that wants to do blacklisting. */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT 369 /** * Query to a blacklisting client (is this peer blacklisted)? */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY 370 /** * Reply from blacklisting client (answer to blacklist query). */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY 371 /** * Transport PING message */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_PING 372 /** * Transport PONG message */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_PONG 373 /** * Message for transport service from a client asking that a * connection be initiated with another peer. */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT 374 /** * Transport CONNECT message exchanged between transport services to * indicate that a session should be marked as 'connected'. */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT 375 /** * Transport CONNECT_ACK message exchanged between transport services to * indicate that a CONNECT message was accepted */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT_ACK 376 /** * Transport CONNECT_ACK message exchanged between transport services to * indicate that a CONNECT message was accepted */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK 377 /** * Transport DISCONNECT message exchanged between transport services to * indicate that a connection should be dropped. */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT 378 /** * Request to monitor addresses used by a peer or all peers. */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE 380 /** * Message send by a peer to notify the other to keep the session alive * and measure latency in a regular interval */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE 381 /** * Response to a GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE message to * measure latency in a regular interval */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE 382 /** * Request to iterate over all known addresses. */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE 383 /** * Message send by a peer to notify the other to keep the session alive. */ #define GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON 384 /******************************************************************************* * STREAM LIRBRARY MESSAGES ******************************************************************************/ /** * Message containing data exchanged between stream end-points over mesh. */ #define GNUNET_MESSAGE_TYPE_STREAM_DATA 400 /** * ACK message */ #define GNUNET_MESSAGE_TYPE_STREAM_ACK 401 /** * Handshake hello message */ #define GNUNET_MESSAGE_TYPE_STREAM_HELLO 402 /** * Handshake hello acknowledgement message */ #define GNUNET_MESSAGE_TYPE_STREAM_HELLO_ACK 403 /** * Reset message */ #define GNUNET_MESSAGE_TYPE_STREAM_RESET 404 /** * Transmit close message (data transmission no longer possible after this * message) */ #define GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE 405 /** * Transmit close acknowledgement message */ #define GNUNET_MESSAGE_TYPE_STREAM_TRANSMIT_CLOSE_ACK 406 /** * Receive close message (data is no loger read by the receiver after this * message) */ #define GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE 407 /** * Receive close acknowledgement message */ #define GNUNET_MESSAGE_TYPE_STREAM_RECEIVE_CLOSE_ACK 408 /** * Stream close message (data is no longer sent or read after this message) */ #define GNUNET_MESSAGE_TYPE_STREAM_CLOSE 409 /** * Close acknowledgement message */ #define GNUNET_MESSAGE_TYPE_STREAM_CLOSE_ACK 410 /******************************************************************************* * FS-PUBLISH-HELPER IPC Messages ******************************************************************************/ /** * Progress information from the helper: found a file */ #define GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_FILE 420 /** * Progress information from the helper: found a directory */ #define GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_PROGRESS_DIRECTORY 421 /** * Error signal from the helper. */ #define GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_ERROR 422 /** * Signal that helper skipped a file. */ #define GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_SKIP_FILE 423 /** * Signal that helper is done scanning the directory tree. */ #define GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_COUNTING_DONE 424 /** * Extracted meta data from the helper. */ #define GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_META_DATA 425 /** * Signal that helper is done. */ #define GNUNET_MESSAGE_TYPE_FS_PUBLISH_HELPER_FINISHED 426 /******************************************************************************* * NAMESTORE message types ******************************************************************************/ /** * Request update and listing of a peer. */ #define GNUNET_MESSAGE_TYPE_NAMESTORE_START 430 /******************************************************************************* * LOCKMANAGER message types ******************************************************************************/ /** * Message to acquire Lock */ #define GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE 440 /** * Message to release lock */ #define GNUNET_MESSAGE_TYPE_LOCKMANAGER_RELEASE 441 /** * SUCESS reply from lockmanager */ #define GNUNET_MESSAGE_TYPE_LOCKMANAGER_SUCCESS 442 /** * Next available: 450 */ /******************************************************************************* * TODO: we need a way to register message types centrally (via some webpage). * For now: unofficial extensions should start at 48k, internal extensions * define here should leave some room (4-10 additional messages to the previous * extension). ******************************************************************************/ /** * Type used to match 'all' message types. */ #define GNUNET_MESSAGE_TYPE_ALL 65535 #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_PROTOCOLS_H */ #endif /* end of gnunet_protocols.h */ gnunet-0.9.3/src/include/block_gns.h0000644000175000017500000000375611760502551014305 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/block_gns.h * @brief fs block formats (shared between fs and block) * @author Martin Schanzenbach */ #ifndef BLOCK_GNS_H #define BLOCK_GNS_H #include "gnunet_util_lib.h" GNUNET_NETWORK_STRUCT_BEGIN /** * @brief a simgle record inside a record block */ struct GNSRecordBlock { /** * the record type */ uint32_t type GNUNET_PACKED; /** * expiration time of the record */ struct GNUNET_TIME_AbsoluteNBO expiration; /** * length of the data */ uint32_t data_length GNUNET_PACKED; /* record flags */ uint32_t flags GNUNET_PACKED; //Class of the record? /* followed by the record data */ }; /** * @brief a record block for a given name of a single authority */ struct GNSNameRecordBlock { /** * The public key of the authority */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; /** * GNUNET_RSA_Signature using RSA-key generated from the records. */ struct GNUNET_CRYPTO_RsaSignature signature; /* number of records that follow */ uint32_t rd_count GNUNET_PACKED; /* 0-terminated name here */ /* variable-size GNSRecordBlocks follows here */ }; GNUNET_NETWORK_STRUCT_END #endif gnunet-0.9.3/src/include/gnunet_testbed_service.h0000644000175000017500000007375711760502551017106 00000000000000/* This file is part of GNUnet (C) 2008, 2009, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_testbed_service.h * @brief API for writing tests and creating large-scale * emulation testbeds for GNUnet. * @author Christian Grothoff */ #ifndef GNUNET_TESTBED_SERVICE_H #define GNUNET_TESTBED_SERVICE_H #include "gnunet_util_lib.h" #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * Opaque handle to a host running experiments managed by the testbed framework. * The master process must be able to SSH to this host without password (via * ssh-agent). */ struct GNUNET_TESTBED_Host; /** * Opaque handle to a peer controlled by the testbed framework. A peer runs * at a particular host. */ struct GNUNET_TESTBED_Peer; /** * Opaque handle to an abstract operation to be executed by the testbed framework. */ struct GNUNET_TESTBED_Operation; /** * Handle to interact with a GNUnet testbed controller. Each controller has at * least one master handle which is created when the controller is created; this * master handle interacts with the controller via stdin/stdout of the controller * process. Additionally, controllers can interact with each other (in a P2P * fashion); those links are established via TCP/IP on the controller's service * port. */ struct GNUNET_TESTBED_Controller; /** * Handle to a large-scale testbed that is managed at a high level. */ struct GNUNET_TESTBED_Testbed; /** * Create a host to run peers and controllers on. * * @param hostname name of the host, use "NULL" for localhost * @param username username to use for the login; may be NULL * @param port port number to use for ssh; use 0 to let ssh decide * @return handle to the host, NULL on error */ struct GNUNET_TESTBED_Host * GNUNET_TESTBED_host_create (const char *hostname, const char *username, uint16_t port); /** * Load a set of hosts from a configuration file. * * @param filename file with the host specification * @param hosts set to the hosts found in the file * @return number of hosts returned in 'hosts', 0 on error */ unsigned int GNUNET_TESTBED_hosts_load_from_file (const char *filename, struct GNUNET_TESTBED_Host **hosts); /** * Destroy a host handle. Must only be called once everything * running on that host has been stopped. * * @param host handle to destroy */ void GNUNET_TESTBED_host_destroy (struct GNUNET_TESTBED_Host *host); /** * Enumeration with (at most 64) possible event types that * can be monitored using the testbed framework. */ enum GNUNET_TESTBED_EventType { /** * A peer has been started. */ GNUNET_TESTBED_ET_PEER_START = 0, /** * A peer has been stopped. */ GNUNET_TESTBED_ET_PEER_STOP = 1, /** * A connection between two peers was established. */ GNUNET_TESTBED_ET_CONNECT = 2, /** * A connection between two peers was torn down. */ GNUNET_TESTBED_ET_DISCONNECT = 3, /** * A requested testbed operation has been completed. */ GNUNET_TESTBED_ET_OPERATION_FINISHED = 4, /** * The 'GNUNET_TESTBED_run' operation has been completed */ GNUNET_TESTBED_ET_TESTBED_ONLINE = 5 }; /** * Types of information that can be requested about a peer. */ enum GNUNET_TESTBED_PeerInformationType { /** * Special value (not valid for requesting information) * that is used in the event struct if a 'generic' pointer * is returned (for other operations not related to this * enumeration). */ GNUNET_TESTBED_PIT_GENERIC = 0, /** * What host is the peer running on? Returns a 'const struct * GNUNET_TESTBED_Host *'. Valid until * 'GNUNET_TESTBED_operation_done' is called. */ GNUNET_TESTBED_PIT_HOST, /** * What configuration is the peer using? Returns a 'const struct * GNUNET_CONFIGURATION_Handle *'. Valid until * 'GNUNET_TESTNIG_operation_done' is called. However, the * values may be inaccurate if the peer is reconfigured in * the meantime. */ GNUNET_TESTBED_PIT_CONFIGURATION, /** * What is the identity of the peer? Returns a * 'const struct GNUNET_PeerIdentity *'. Valid until * 'GNUNET_TESTNIG_operation_done' is called. */ GNUNET_TESTBED_PIT_IDENTITY }; /** * Argument to GNUNET_TESTBED_ControllerCallback with details about * the event. */ struct GNUNET_TESTBED_EventInformation { /** * Type of the event. */ enum GNUNET_TESTBED_EventType type; /** * Details about the event. */ union { /** * Details about peer start event. */ struct { /** * Handle for the host where the peer * was started. */ struct GNUNET_TESTBED_Host *host; /** * Handle for the peer that was started. */ struct GNUNET_TESTBED_Peer *peer; } peer_start; /** * Details about peer stop event. */ struct { /** * Handle for the peer that was started. */ struct GNUNET_TESTBED_Peer *peer; } peer_stop; /** * Details about connect event. */ struct { /** * Handle for one of the connected peers. */ struct GNUNET_TESTBED_Peer *peer1; /** * Handle for one of the connected peers. */ struct GNUNET_TESTBED_Peer *peer2; } peer_connect; /** * Details about disconnect event. */ struct { /** * Handle for one of the disconnected peers. */ struct GNUNET_TESTBED_Peer *peer1; /** * Handle for one of the disconnected peers. */ struct GNUNET_TESTBED_Peer *peer2; } peer_disconnect; /** * Details about an operation finished event. */ struct { /** * Handle for the operation that was finished. */ struct GNUNET_TESTBED_Operation *operation; /** * Closure that was passed in when the event was * requested. */ void *op_cls; /** * Error message for the operation, NULL on success. */ const char *emsg; /** * Peer information type; captures which of the types * in the 'op_result' is actually in use. */ enum GNUNET_TESTBED_PeerInformationType pit; /** * Pointer to an operation-specific return value; NULL on error; * can be NULL for certain operations. Valid until * 'GNUNET_TESTBED_operation_done' is called. */ union { /** * No result (NULL pointer) or generic result * (whatever the GNUNET_TESTBED_ConnectAdapter returned). */ void *generic; /** * Identity of host running the peer. */ struct GNUNET_TESTBED_Host *host; /** * Identity of the peer. */ const struct GNUNET_PeerIdentity *pid; /** * Configuration of the peer. */ const struct GNUNET_CONFIGURATION_Handle *cfg; } op_result; } operation_finished; /** * Details about an testbed run completed event. */ struct { /** * Error message for the operation, NULL on success. */ const char *emsg; /** * Array of peers now running (valid until * 'GNUNET_TESTBED_testbed_stop' is called). Note that it is * not allowed to call 'GNUNET_TESTBED_peer_destroy' on peers * from this array. */ struct GNUNET_TESTBED_Peer **peers; /** * Size of the 'peers' array. */ unsigned int num_peers; } testbed_run_finished; } details; }; /** * Signature of the event handler function called by the * respective event controller. * * @param cls closure * @param event information about the event */ typedef void (*GNUNET_TESTBED_ControllerCallback)(void *cls, const struct GNUNET_TESTBED_EventInformation *event); /** * Start a controller process using the given configuration at the * given host. * * @param cfg configuration to use * @param host host to run the controller on, NULL for 'localhost' * @param event_mask bit mask with set of events to call 'cc' for; * or-ed values of "1LL" shifted by the * respective 'enum GNUNET_TESTBED_EventType' * (i.e. "(1LL << GNUNET_TESTBED_ET_CONNECT) | ...") * @param cc controller callback to invoke on events * @param cc_cls closure for cc * @return handle to the controller */ struct GNUNET_TESTBED_Controller * GNUNET_TESTBED_controller_start (const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTBED_Host *host, uint64_t event_mask, GNUNET_TESTBED_ControllerCallback cc, void *cc_cls); /** * Configure shared services at a controller. Using this function, * you can specify that certain services (such as "resolver") * should not be run for each peer but instead be shared * across N peers on the specified host. This function * must be called before any peers are created at the host. * * @param controller controller to configure * @param service_name name of the service to share * @param num_peers number of peers that should share one instance * of the specified service (1 for no sharing is the default), * use 0 to disable the service */ void GNUNET_TESTBED_controller_configure_sharing (struct GNUNET_TESTBED_Controller *controller, const char *service_name, uint32_t num_peers); /** * Stop the given controller (also will terminate all peers and * controllers dependent on this controller). This function * blocks until the testbed has been fully terminated (!). * * @param controller handle to controller to stop */ void GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_Controller *controller); /** * Create a link from a 'master' controller to a slave controller. * Whenever the master controller is asked to start a peer at the * given 'delegated_host', it will delegate the request to the * specified slave controller. Note that the slave controller runs at * the 'slave_host', which may or may not be the same host as the * 'delegated_host' (for hierarchical delegations). The configuration * of the slave controller is given and to be used to either create * the slave controller or to connect to an existing slave controller * process. 'is_subordinate' specifies if the given slave controller * should be started and managed by the master controller, or if the * slave already has a master and this is just a secondary master that * is also allowed to use the existing slave. * * @param master handle to the master controller who creates the association * @param delegated_host requests to which host should be delegated * @param slave_host which host is used to run the slave controller * @param slave_cfg configuration to use for the slave controller * @param is_subordinate GNUNET_YES if the slave should be started (and stopped) * by the master controller; GNUNET_NO if we are just * allowed to use the slave via TCP/IP */ void GNUNET_TESTBED_controller_link (struct GNUNET_TESTBED_Controller *master, struct GNUNET_TESTBED_Host *delegated_host, struct GNUNET_TESTBED_Host *slave_host, const struct GNUNET_CONFIGURATION_Handle *slave_cfg, int is_subordinate); /** * Create the given peer at the specified host using the given * controller. If the given controller is not running on the target * host, it should find or create a controller at the target host and * delegate creating the peer. Explicit delegation paths can be setup * using 'GNUNET_TESTBED_controller_link'. If no explicit delegation * path exists, a direct link with a subordinate controller is setup * for the first delegated peer to a particular host; the subordinate * controller is then destroyed once the last peer that was delegated * to the remote host is stopped. * * Creating the peer only creates the handle to manipulate and further * configure the peer; use "GNUNET_TESTBED_peer_start" and * "GNUNET_TESTBED_peer_stop" to actually start/stop the peer's * processes. * * Note that the given configuration will be adjusted by the * controller to avoid port/path conflicts with other peers. * The "final" configuration can be obtained using * 'GNUNET_TESTBED_peer_get_information'. * * @param controller controller process to use * @param host host to run the peer on * @param cfg configuration to use for the peer * @return handle to the peer (actual startup will happen asynchronously) */ struct GNUNET_TESTBED_Peer * GNUNET_TESTBED_peer_create (struct GNUNET_TESTBED_Controller *controller, struct GNUNET_TESTBED_Host *host, const struct GNUNET_CONFIGURATION_Handle *cfg); /** * Start the given peer. * * @param peer peer to start * @return handle to the operation */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_peer_start (struct GNUNET_TESTBED_Peer *peer); /** * Stop the given peer. The handle remains valid (use * "GNUNET_TESTBED_peer_destroy" to fully clean up the * state of the peer). * * @param peer peer to stop * @return handle to the operation */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_peer_stop (struct GNUNET_TESTBED_Peer *peer); /** * Request information about a peer. * * @param peer peer to request information about * @param pit desired information * @return handle to the operation */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_peer_get_information (struct GNUNET_TESTBED_Peer *peer, enum GNUNET_TESTBED_PeerInformationType pit); /** * Change peer configuration. Must only be called while the * peer is stopped. Ports and paths cannot be changed this * way. * * @param peer peer to change configuration for * @param cfg new configuration (differences to existing * configuration only) * @return handle to the operation */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_peer_update_configuration (struct GNUNET_TESTBED_Peer *peer, const struct GNUNET_CONFIGURATION_Handle *cfg); /** * Destroy the given peer; the peer should have been * stopped first (if it was started). * * @param peer peer to stop * @return handle to the operation */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_peer_destroy (struct GNUNET_TESTBED_Peer *peer); /** * Options for peer connections. */ enum GNUNET_TESTBED_ConnectOption { /** * No option (not valid as an argument). */ GNUNET_TESTBED_CO_NONE = 0, /** * Allow or disallow a connection between the specified peers. * Followed by GNUNET_NO (int) if a connection is disallowed * or GNUNET_YES if a connection is allowed. Note that the * default (all connections allowed or disallowed) is * specified in the configuration of the controller. */ GNUNET_TESTBED_CO_ALLOW = 1, /** * FIXME: add (and implement) options to limit connection to * particular transports, force simulation of particular latencies * or message loss rates, or set bandwidth limitations. */ }; /** * Manipulate the P2P underlay topology by configuring a link * between two peers. * * @param op_cls closure argument to give with the operation event * @param p1 first peer * @param p2 second peer * @param co option to change * @param ap option-specific values * @return handle to the operation, NULL if configuring the link at this * time is not allowed */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_underlay_configure_link_va (void *op_cls, struct GNUNET_TESTBED_Peer *p1, struct GNUNET_TESTBED_Peer *p2, enum GNUNET_TESTBED_ConnectOption co, va_list ap); /** * Manipulate the P2P underlay topology by configuring a link * between two peers. * * @param op_cls closure argument to give with the operation event * @param p1 first peer * @param p2 second peer * @param co option to change * @param ... option-specific values * @return handle to the operation, NULL if configuring the link at this * time is not allowed */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_underlay_configure_link (void *op_cls, struct GNUNET_TESTBED_Peer *p1, struct GNUNET_TESTBED_Peer *p2, enum GNUNET_TESTBED_ConnectOption co, ...); /** * Topologies supported for testbeds. */ enum GNUNET_TESTBED_TopologyOption { /** * A clique (everyone connected to everyone else). No options. */ GNUNET_TESTBED_TOPOLOGY_CLIQUE, /** * Small-world network (2d torus plus random links). Followed * by the number of random links to add (unsigned int). */ GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD, /** * Small-world network (ring plus random links). Followed * by the number of random links to add (unsigned int). */ GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING, /** * Ring topology. No options. */ GNUNET_TESTBED_TOPOLOGY_RING, /** * 2-d torus. No options. */ GNUNET_TESTBED_TOPOLOGY_2D_TORUS, /** * Random graph. Followed by the link density, that is the * percentage of links present in relation to a clique * (float). */ GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI, /** * Certain percentage of peers are unable to communicate directly * replicating NAT conditions. Followed by the fraction of * NAT'ed peers (float). */ GNUNET_TESTBED_TOPOLOGY_INTERNAT, /** * Scale free topology. FIXME: options? */ GNUNET_TESTBED_TOPOLOGY_SCALE_FREE, /** * Straight line topology. No options. */ GNUNET_TESTBED_TOPOLOGY_LINE, /** * All peers are disconnected. No options. */ GNUNET_TESTBED_TOPOLOGY_NONE, /** * Read a topology from a given file. Followed by the name of the file (const char *). */ GNUNET_TESTBED_TOPOLOGY_FROM_FILE }; /** * Configure overall network topology to have a particular shape. * * @param op_cls closure argument to give with the operation event * @param num_peers number of peers in 'peers' * @param peers array of 'num_peers' with the peers to configure * @param topo desired underlay topology to use * @param ap topology-specific options * @return handle to the operation, NULL if configuring the topology * is not allowed at this time */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_underlay_configure_topology_va (void *op_cls, unsigned int num_peers, struct GNUNET_TESTBED_Peer **peers, enum GNUNET_TESTBED_TopologyOption topo, va_list ap); /** * Configure overall network topology to have a particular shape. * * @param op_cls closure argument to give with the operation event * @param num_peers number of peers in 'peers' * @param peers array of 'num_peers' with the peers to configure * @param topo desired underlay topology to use * @param ... topology-specific options * @return handle to the operation, NULL if configuring the topology * is not allowed at this time */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_underlay_configure_topology (void *op_cls, unsigned int num_peers, struct GNUNET_TESTBED_Peer **peers, enum GNUNET_TESTBED_TopologyOption topo, ...); /** * Both peers must have been started before calling this function. * This function then obtains a HELLO from 'p1', gives it to 'p2' * and asks 'p2' to connect to 'p1'. * * @param op_cls closure argument to give with the operation event * @param p1 first peer * @param p2 second peer * @return handle to the operation, NULL if connecting these two * peers is fundamentally not possible at this time (peers * not running or underlay disallows) */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_overlay_connect (void *op_cls, struct GNUNET_TESTBED_Peer *p1, struct GNUNET_TESTBED_Peer *p2); /** * All peers must have been started before calling this function. * This function then connects the given peers in the P2P overlay * using the given topology. * * @param op_cls closure argument to give with the operation event * @param num_peers number of peers in 'peers' * @param peers array of 'num_peers' with the peers to configure * @param topo desired underlay topology to use * @param va topology-specific options * @return handle to the operation, NULL if connecting these * peers is fundamentally not possible at this time (peers * not running or underlay disallows) */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_overlay_configure_topology_va (void *op_cls, unsigned int num_peers, struct GNUNET_TESTBED_Peer *peers, enum GNUNET_TESTBED_TopologyOption topo, va_list va); /** * All peers must have been started before calling this function. * This function then connects the given peers in the P2P overlay * using the given topology. * * @param op_cls closure argument to give with the operation event * @param num_peers number of peers in 'peers' * @param peers array of 'num_peers' with the peers to configure * @param topo desired underlay topology to use * @param ... topology-specific options * @return handle to the operation, NULL if connecting these * peers is fundamentally not possible at this time (peers * not running or underlay disallows) */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_overlay_configure_topology (void *op_cls, unsigned int num_peers, struct GNUNET_TESTBED_Peer *peers, enum GNUNET_TESTBED_TopologyOption topo, ...); /** * Ask the testbed controller to write the current overlay topology to * a file. Naturally, the file will only contain a snapshot as the * topology may evolve all the time. * * @param controller overlay controller to inspect * @param filename name of the file the topology should * be written to. */ void GNUNET_TESTBED_overlay_write_topology_to_file (struct GNUNET_TESTBED_Controller *controller, const char *filename); /** * Adapter function called to establish a connection to * a service. * * @param cls closure * @param cfg configuration of the peer to connect to * @return service handle to return in 'op_result', NULL on error */ typedef void * (*GNUNET_TESTBED_ConnectAdapter)(void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg); /** * Adapter function called to destroy a connection to * a service. * * @param cls closure * @param op_result service handle returned from the connect adapter */ typedef void (*GNUNET_TESTBED_DisconnectAdapter)(void *cls, void *op_result); /** * Connect to a service offered by the given peer. Will ensure that * the request is queued to not overwhelm our ability to create and * maintain connections with other systems. The actual service * handle is then returned via the 'op_result' member in the event * callback. The 'ca' callback is used to create the connection * when the time is right; the 'da' callback will be used to * destroy the connection (upon 'GNUNET_TESTBED_operation_done'). * 'GNUNET_TESTBED_operation_cancel' can be used to abort this * operation until the event callback has been called. * * @param op_cls closure to pass in operation event * @param peer peer that runs the service * @param service_name name of the service to connect to * @param ca helper function to establish the connection * @param da helper function to close the connection * @param cada_cls closure for ca and da * @return handle for the operation */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_service_connect (void *op_cls, struct GNUNET_TESTBED_Peer *peer, const char *service_name, GNUNET_TESTBED_ConnectAdapter ca, GNUNET_TESTBED_DisconnectAdapter da, void *cada_cls); /** * Cancel a pending operation. Releases all resources * of the operation and will ensure that no event * is generated for the operation. Does NOT guarantee * that the operation will be fully undone (or that * nothing ever happened). * * @param operation operation to cancel */ void GNUNET_TESTBED_operation_cancel (struct GNUNET_TESTBED_Operation *operation); /** * Signal that the information from an operation has been fully * processed. This function MUST be called for each event * of type 'operation_finished' to fully remove the operation * from the operation queue. After calling this function, the * 'op_result' becomes invalid (!). * * @param operation operation to signal completion for */ void GNUNET_TESTBED_operation_done (struct GNUNET_TESTBED_Operation *operation); /** * Configure and run a testbed using the given * master controller on 'num_hosts' starting * 'num_peers' using the given peer configuration. * * @param controller master controller for the testbed * (must not be destroyed until after the * testbed is destroyed). * @param num_hosts number of hosts in 'hosts', 0 to only * use 'localhost' * @param hosts list of hosts to use for the testbed * @param num_peers number of peers to start * @param peer_cfg peer configuration template to use * @param underlay_topology underlay topology to create * @param va topology-specific options * @return handle to the testbed */ struct GNUNET_TESTBED_Testbed * GNUNET_TESTBED_create_va (struct GNUNET_TESTBED_Controller *controller, unsigned int num_hosts, struct GNUNET_TESTBED_Host **hosts, unsigned int num_peers, const struct GNUNET_CONFIGURATION_Handle *peer_cfg, enum GNUNET_TESTBED_TopologyOption underlay_topology, va_list va); /** * Configure and run a testbed using the given * master controller on 'num_hosts' starting * 'num_peers' using the given peer configuration. * * @param controller master controller for the testbed * (must not be destroyed until after the * testbed is destroyed). * @param num_hosts number of hosts in 'hosts', 0 to only * use 'localhost' * @param hosts list of hosts to use for the testbed * @param num_peers number of peers to start * @param peer_cfg peer configuration template to use * @param underlay_topology underlay topology to create * @param ... topology-specific options */ struct GNUNET_TESTBED_Testbed * GNUNET_TESTBED_create (struct GNUNET_TESTBED_Controller *controller, unsigned int num_hosts, struct GNUNET_TESTBED_Host **hosts, unsigned int num_peers, const struct GNUNET_CONFIGURATION_Handle *peer_cfg, enum GNUNET_TESTBED_TopologyOption underlay_topology, ...); /** * Destroy a testbed. Stops all running peers and then * destroys all peers. Does NOT destroy the master controller. * * @param testbed testbed to destroy */ void GNUNET_TESTBED_destroy (struct GNUNET_TESTBED_Testbed *testbed); /** * Convenience method for running a testbed with * a single call. Underlay and overlay topology * are configured using the "UNDERLAY" and "OVERLAY" * options in the "[testbed]" section of the configuration\ * (with possible options given in "UNDERLAY_XXX" and/or * "OVERLAY_XXX"). * * The testbed is to be terminated using a call to * "GNUNET_SCHEDULER_shutdown". * * @param host_filename name of the file with the 'hosts', NULL * to run everything on 'localhost' * @param cfg configuration to use (for testbed, controller and peers) * @param num_peers number of peers to start; FIXME: maybe put that ALSO into cfg? * @param event_mask bit mask with set of events to call 'cc' for; * or-ed values of "1LL" shifted by the * respective 'enum GNUNET_TESTBED_EventType' * (i.e. "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...") * @param cc controller callback to invoke on events * @param cc_cls closure for cc * @param master task to run once the testbed is ready * @param master_cls closure for 'task'. */ void GNUNET_TESTBED_run (const char *host_filename, const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned int num_peers, uint64_t event_mask, GNUNET_TESTBED_ControllerCallback cc, void *cc_cls, GNUNET_SCHEDULER_Task master, void *master_cls); /** * Signature of a main function for a testcase. * * @param cls closure * @param num_peers number of peers in 'peers' * @param peers handle to peers run in the testbed */ typedef void (*GNUNET_TESTBED_TestMaster)(void *cls, unsigned int num_peers, struct GNUNET_TESTBED_Peer **peers); /** * Convenience method for running a "simple" test on the local system * with a single call from 'main'. Underlay and overlay topology are * configured using the "UNDERLAY" and "OVERLAY" options in the * "[testbed]" section of the configuration (with possible options * given in "UNDERLAY_XXX" and/or "OVERLAY_XXX"). * * The test is to be terminated using a call to * "GNUNET_SCHEDULER_shutdown". If starting the test fails, * the program is stopped without 'master' ever being run. * * NOTE: this function should be called from 'main', NOT from * within a GNUNET_SCHEDULER-loop. This function will initialze * the scheduler loop, the testbed and then pass control to * 'master'. * * @param testname name of the testcase (to configure logging, etc.) * @param cfg_filename configuration filename to use * (for testbed, controller and peers) * @param num_peers number of peers to start * @param test_master task to run once the test is ready * @param test_master_cls closure for 'task'. */ void GNUNET_TESTBED_test_run (const char *testname, const char *cfg_filename, unsigned int num_peers, GNUNET_TESTBED_TestMaster test_master, void *test_master_cls); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif #endif gnunet-0.9.3/src/include/gnunet_dht_service.h0000644000175000017500000003163211760504736016224 00000000000000/* This file is part of GNUnet (C) 2004, 2005, 2006, 2008, 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_dht_service.h * @brief API to the DHT service * @author Christian Grothoff */ #ifndef GNUNET_DHT_SERVICE_H #define GNUNET_DHT_SERVICE_H #include "gnunet_util_lib.h" #include "gnunet_block_lib.h" #include "gnunet_hello_lib.h" #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * Default republication frequency for stored data in the DHT. */ #define GNUNET_DHT_DEFAULT_REPUBLISH_FREQUENCY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 60) /** * Connection to the DHT service. */ struct GNUNET_DHT_Handle; /** * Handle to control a get operation. */ struct GNUNET_DHT_GetHandle; /** * Handle to control a find peer operation. */ struct GNUNET_DHT_FindPeerHandle; /** * Options for routing. */ enum GNUNET_DHT_RouteOption { /** * Default. Do nothing special. */ GNUNET_DHT_RO_NONE = 0, /** * Each peer along the way should look at 'enc' (otherwise * only the k-peers closest to the key should look at it). */ GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE = 1, /** * We should keep track of the route that the message * took in the P2P network. */ GNUNET_DHT_RO_RECORD_ROUTE = 2, /** * This is a 'FIND-PEER' request, so approximate results are fine. */ GNUNET_DHT_RO_FIND_PEER = 4, /** * Possible message option for query key randomization. */ GNUNET_DHT_RO_BART = 8 }; /** * Initialize the connection with the DHT service. * * @param cfg configuration to use * @param ht_len size of the internal hash table to use for * processing multiple GET/FIND requests in parallel * @return NULL on error */ struct GNUNET_DHT_Handle * GNUNET_DHT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned int ht_len); /** * Shutdown connection with the DHT service. * * @param handle connection to shut down */ void GNUNET_DHT_disconnect (struct GNUNET_DHT_Handle *handle); /* *************** Standard API: get and put ******************* */ /** * Opaque handle to cancel a PUT operation. */ struct GNUNET_DHT_PutHandle; /** * Type of a PUT continuation. You must not call * "GNUNET_DHT_disconnect" in this continuation. * * @param cls closure * @param success GNUNET_OK if the PUT was transmitted, * GNUNET_NO on timeout, * GNUNET_SYSERR on disconnect from service * after the PUT message was transmitted * (so we don't know if it was received or not) */ typedef void (*GNUNET_DHT_PutContinuation)(void *cls, int success); /** * Perform a PUT operation storing data in the DHT. * * @param handle handle to DHT service * @param key the key to store under * @param desired_replication_level estimate of how many * nearest peers this request should reach * @param options routing options for this message * @param type type of the value * @param size number of bytes in data; must be less than 64k * @param data the data to store * @param exp desired expiration time for the value * @param timeout how long to wait for transmission of this request * @param cont continuation to call when done (transmitting request to service) * You must not call "GNUNET_DHT_disconnect" in this continuation * @param cont_cls closure for cont * @return handle to cancel the "PUT" operation, NULL on error * (size too big) */ struct GNUNET_DHT_PutHandle * GNUNET_DHT_put (struct GNUNET_DHT_Handle *handle, const GNUNET_HashCode * key, uint32_t desired_replication_level, enum GNUNET_DHT_RouteOption options, enum GNUNET_BLOCK_Type type, size_t size, const char *data, struct GNUNET_TIME_Absolute exp, struct GNUNET_TIME_Relative timeout, GNUNET_DHT_PutContinuation cont, void *cont_cls); /** * Cancels a DHT PUT operation. Note that the PUT request may still * go out over the network (we can't stop that); However, if the PUT * has not yet been sent to the service, cancelling the PUT will stop * this from happening (but there is no way for the user of this API * to tell if that is the case). The only use for this API is to * prevent a later call to 'cont' from "GNUNET_DHT_put" (i.e. because * the system is shutting down). * * @param ph put operation to cancel ('cont' will no longer be called) */ void GNUNET_DHT_put_cancel (struct GNUNET_DHT_PutHandle *ph); /** * Iterator called on each result obtained for a DHT * operation that expects a reply * * @param cls closure * @param exp when will this value expire * @param key key of the result * @param get_path peers on reply path (or NULL if not recorded) * @param get_path_length number of entries in get_path * @param put_path peers on the PUT path (or NULL if not recorded) * @param put_path_length number of entries in get_path * @param type type of the result * @param size number of bytes in data * @param data pointer to the result data */ typedef void (*GNUNET_DHT_GetIterator) (void *cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity * get_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity * put_path, unsigned int put_path_length, enum GNUNET_BLOCK_Type type, size_t size, const void *data); /** * Perform an asynchronous GET operation on the DHT identified. See * also "GNUNET_BLOCK_evaluate". * * @param handle handle to the DHT service * @param type expected type of the response object * @param key the key to look up * @param desired_replication_level estimate of how many nearest peers this request should reach * @param options routing options for this message * @param xquery extended query data (can be NULL, depending on type) * @param xquery_size number of bytes in xquery * @param iter function to call on each result * @param iter_cls closure for iter * * @return handle to stop the async get */ struct GNUNET_DHT_GetHandle * GNUNET_DHT_get_start (struct GNUNET_DHT_Handle *handle, enum GNUNET_BLOCK_Type type, const GNUNET_HashCode * key, uint32_t desired_replication_level, enum GNUNET_DHT_RouteOption options, const void *xquery, size_t xquery_size, GNUNET_DHT_GetIterator iter, void *iter_cls); /** * Stop async DHT-get. Frees associated resources. * * @param get_handle GET operation to stop. * * On return get_handle will no longer be valid, caller * must not use again!!! */ void GNUNET_DHT_get_stop (struct GNUNET_DHT_GetHandle *get_handle); /* *************** Extended API: monitor ******************* */ /** * Handle to monitor requests */ struct GNUNET_DHT_MonitorHandle; /** * Callback called on each GET request going through the DHT. * * @param cls Closure. * @param options Options, for instance RecordRoute, DemultiplexEverywhere. * @param type The type of data in the request. * @param hop_count Hop count so far. * @param path_length number of entries in path (or 0 if not recorded). * @param path peers on the GET path (or NULL if not recorded). * @param desired_replication_level Desired replication level. * @param key Key of the requested data. */ typedef void (*GNUNET_DHT_MonitorGetCB) (void *cls, enum GNUNET_DHT_RouteOption options, enum GNUNET_BLOCK_Type type, uint32_t hop_count, uint32_t desired_replication_level, unsigned int path_length, const struct GNUNET_PeerIdentity *path, const GNUNET_HashCode * key); /** * Callback called on each GET reply going through the DHT. * * @param cls Closure. * @param type The type of data in the result. * @param get_path Peers on GET path (or NULL if not recorded). * @param get_path_length number of entries in get_path. * @param put_path peers on the PUT path (or NULL if not recorded). * @param put_path_length number of entries in get_path. * @param exp Expiration time of the data. * @param key Key of the data. * @param data Pointer to the result data. * @param size Number of bytes in data. */ typedef void (*GNUNET_DHT_MonitorGetRespCB) (void *cls, enum GNUNET_BLOCK_Type type, const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity * put_path, unsigned int put_path_length, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const void *data, size_t size); /** * Callback called on each PUT request going through the DHT. * * @param cls Closure. * @param options Options, for instance RecordRoute, DemultiplexEverywhere. * @param type The type of data in the request. * @param hop_count Hop count so far. * @param path_length number of entries in path (or 0 if not recorded). * @param path peers on the PUT path (or NULL if not recorded). * @param desired_replication_level Desired replication level. * @param exp Expiration time of the data. * @param key Key under which data is to be stored. * @param data Pointer to the data carried. * @param size Number of bytes in data. */ typedef void (*GNUNET_DHT_MonitorPutCB) (void *cls, enum GNUNET_DHT_RouteOption options, enum GNUNET_BLOCK_Type type, uint32_t hop_count, uint32_t desired_replication_level, unsigned int path_length, const struct GNUNET_PeerIdentity *path, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, const void *data, size_t size); /** * Start monitoring the local DHT service. * * @param handle Handle to the DHT service. * @param type Type of blocks that are of interest. * @param key Key of data of interest, NULL for all. * @param get_cb Callback to process monitored get messages. * @param get_resp_cb Callback to process monitored get response messages. * @param put_cb Callback to process monitored put messages. * @param cb_cls Closure for cb. * * @return Handle to stop monitoring. */ struct GNUNET_DHT_MonitorHandle * GNUNET_DHT_monitor_start (struct GNUNET_DHT_Handle *handle, enum GNUNET_BLOCK_Type type, const GNUNET_HashCode *key, GNUNET_DHT_MonitorGetCB get_cb, GNUNET_DHT_MonitorGetRespCB get_resp_cb, GNUNET_DHT_MonitorPutCB put_cb, void *cb_cls); /** * Stop monitoring. * * @param handle The handle to the monitor request returned by monitor_start. * * On return handle will no longer be valid, caller must not use again!!! */ void GNUNET_DHT_monitor_stop (struct GNUNET_DHT_MonitorHandle *handle); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif #endif /* gnunet_dht_service.h */ gnunet-0.9.3/src/include/gnunet_stream_lib.h0000644000175000017500000002566611760502551016051 00000000000000/* This file is part of GNUnet. (C) 2011, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_stream_lib.h * @brief stream handling using mesh API * @author Sree Harsha Totakura */ #ifndef GNUNET_STREAM_LIB_H #define GNUNET_STREAM_LIB_H #ifdef __cplusplus extern "C" { #if 0 } #endif #endif #include "gnunet_util_lib.h" #include "gnunet_mesh_service.h" /** * Stream status */ enum GNUNET_STREAM_Status { /** * All previous read/write operations are successfully done */ GNUNET_STREAM_OK = 0, /** * A timeout occured while reading/writing the stream */ GNUNET_STREAM_TIMEOUT = 1, /** * Other side has shutdown the socket for this type of operation * (reading/writing) */ GNUNET_STREAM_SHUTDOWN = 2, /** * A serious error occured while operating on this stream */ GNUNET_STREAM_SYSERR = 3, /** * An error resulted in an unusable stream */ GNUNET_STREAM_BROKEN }; /** * Opaque handler for stream */ struct GNUNET_STREAM_Socket; /** * Functions of this type will be called when a stream is established * * @param cls the closure from GNUNET_STREAM_open * @param socket socket to use to communicate with the other side (read/write) */ typedef void (*GNUNET_STREAM_OpenCallback) (void *cls, struct GNUNET_STREAM_Socket *socket); /** * Options for the stream. */ enum GNUNET_STREAM_Option { /** * End of the option list. */ GNUNET_STREAM_OPTION_END = 0, /** * Option to set the initial retransmission timeout (when do we retransmit * a packet that did not yield an acknowledgement for the first time?). * Repeated retransmissions will then use an exponential back-off. * Takes a 'struct GNUNET_TIME_Relative' as the only argument. A value * of '0' means to use the round-trip time (plus a tiny grace period); * this is also the default. */ GNUNET_STREAM_OPTION_INITIAL_RETRANSMIT_TIMEOUT }; /** * Tries to open a stream to the target peer * * @param cfg configuration to use * @param target the target peer to which the stream has to be opened * @param app_port the application port number which uniquely identifies this * stream * @param open_cb this function will be called after stream has be established * @param open_cb_cls the closure for open_cb * @param ... options to the stream, terminated by GNUNET_STREAM_OPTION_END * @return if successful it returns the stream socket; NULL if stream cannot be * opened */ struct GNUNET_STREAM_Socket * GNUNET_STREAM_open (const struct GNUNET_CONFIGURATION_Handle *cfg, const struct GNUNET_PeerIdentity *target, GNUNET_MESH_ApplicationType app_port, GNUNET_STREAM_OpenCallback open_cb, void *open_cb_cls, ...); /** * Handle for shutdown */ struct GNUNET_STREAM_ShutdownHandle; /** * Completion callback for shutdown * * @param cls the closure from GNUNET_STREAM_shutdown call * @param operation the operation that was shutdown (SHUT_RD, SHUT_WR, * SHUT_RDWR) */ typedef void (*GNUNET_STREAM_ShutdownCompletion) (void *cls, int operation); /** * Shutdown the stream for reading or writing (similar to man 2 shutdown). * * @param socket the stream socket * @param operation SHUT_RD, SHUT_WR or SHUT_RDWR * @param completion_cb the callback that will be called upon successful * shutdown of given operation * @param completion_cls the closure for the completion callback * @return the shutdown handle; NULL in case of any error */ struct GNUNET_STREAM_ShutdownHandle * GNUNET_STREAM_shutdown (struct GNUNET_STREAM_Socket *socket, int operation, GNUNET_STREAM_ShutdownCompletion completion_cb, void *completion_cls); /** * Cancels a pending shutdown * * @param handle the shutdown handle returned from GNUNET_STREAM_shutdown */ void GNUNET_STREAM_shutdown_cancel (struct GNUNET_STREAM_ShutdownHandle *handle); /** * Closes the stream and frees the associated state. The stream should be * shutdown before closing. * * @param socket the stream socket */ void GNUNET_STREAM_close (struct GNUNET_STREAM_Socket *socket); /** * Functions of this type are called upon new stream connection from other peers * * @param cls the closure from GNUNET_STREAM_listen * @param socket the socket representing the stream * @param initiator the identity of the peer who wants to establish a stream * with us * @return GNUNET_OK to keep the socket open, GNUNET_SYSERR to close the * stream (the socket will be invalid after the call) */ typedef int (*GNUNET_STREAM_ListenCallback) (void *cls, struct GNUNET_STREAM_Socket *socket, const struct GNUNET_PeerIdentity *initiator); /** * A socket for listening. */ struct GNUNET_STREAM_ListenSocket; /** * Listens for stream connections for a specific application ports * * @param cfg the configuration to use * @param app_port the application port for which new streams will be accepted * @param listen_cb this function will be called when a peer tries to establish * a stream with us * @param listen_cb_cls closure for listen_cb * @return listen socket, NULL for any error */ struct GNUNET_STREAM_ListenSocket * GNUNET_STREAM_listen (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_MESH_ApplicationType app_port, GNUNET_STREAM_ListenCallback listen_cb, void *listen_cb_cls); /** * Closes the listen socket * * @param lsocket the listen socket */ void GNUNET_STREAM_listen_close (struct GNUNET_STREAM_ListenSocket *lsocket); /** * Functions of this signature are called whenever writing operations * on a stream are executed * * @param cls the closure from GNUNET_STREAM_write * @param status the status of the stream at the time this function is called * @param size the number of bytes written */ typedef void (*GNUNET_STREAM_CompletionContinuation) (void *cls, enum GNUNET_STREAM_Status status, size_t size); /** * Handle to cancel IO write operations. */ struct GNUNET_STREAM_IOWriteHandle; /** * Handle to cancel IO read operations. */ struct GNUNET_STREAM_IOReadHandle; /** * Tries to write the given data to the stream. The maximum size of data that * can be written as part of a write operation is (64 * (64000 - sizeof (struct * GNUNET_STREAM_DataMessage))). If size is greater than this it is not an API * violation, however only the said number of maximum bytes will be written. * * @param socket the socket representing a stream * @param data the data buffer from where the data is written into the stream * @param size the number of bytes to be written from the data buffer * @param timeout the timeout period * @param write_cont the function to call upon writing some bytes into the * stream * @param write_cont_cls the closure * * @return handle to cancel the operation; if a previous write is pending or * the stream has been shutdown for this operation then write_cont is * immediately called and NULL is returned. */ struct GNUNET_STREAM_IOWriteHandle * GNUNET_STREAM_write (struct GNUNET_STREAM_Socket *socket, const void *data, size_t size, struct GNUNET_TIME_Relative timeout, GNUNET_STREAM_CompletionContinuation write_cont, void *write_cont_cls); /** * Functions of this signature are called whenever data is available from the * stream. * * @param cls the closure from GNUNET_STREAM_read * @param status the status of the stream at the time this function is called * @param data traffic from the other side * @param size the number of bytes available in data read; will be 0 on timeout * @return number of bytes of processed from 'data' (any data remaining should be * given to the next time the read processor is called). */ typedef size_t (*GNUNET_STREAM_DataProcessor) (void *cls, enum GNUNET_STREAM_Status status, const void *data, size_t size); /** * Tries to read data from the stream. * * @param socket the socket representing a stream * @param timeout the timeout period * @param proc function to call with data (once only) * @param proc_cls the closure for proc * * @return handle to cancel the operation; if the stream has been shutdown for * this type of opeartion then the DataProcessor is immediately * called with GNUNET_STREAM_SHUTDOWN as status and NULL if returned */ struct GNUNET_STREAM_IOReadHandle * GNUNET_STREAM_read (struct GNUNET_STREAM_Socket *socket, struct GNUNET_TIME_Relative timeout, GNUNET_STREAM_DataProcessor proc, void *proc_cls); /** * Cancels pending write operation. Also cancels packet retransmissions which * may have resulted otherwise. * * CAUTION: Normally a write operation is considered successful if the data * given to it is sent and acknowledged by the receiver. As data is divided * into packets, it is possible that not all packets are received by the * receiver. Any missing packets are then retransmitted till the receiver * acknowledges all packets or until a timeout . During this scenario if the * write operation is cancelled all such retransmissions are also * cancelled. This may leave the receiver's receive buffer incompletely filled * as some missing packets are never retransmitted. So this operation should be * used before shutting down transmission from our side or before closing the * socket. * * @param ioh handle to operation to cancel */ void GNUNET_STREAM_io_write_cancel (struct GNUNET_STREAM_IOWriteHandle *iowh); /** * Cancel pending read operation. * * @param ioh handle to operation to cancel */ void GNUNET_STREAM_io_read_cancel (struct GNUNET_STREAM_IOReadHandle *iorh); #if 0 { #endif #ifdef __cplusplus } #endif #endif /* STREAM_PROTOCOL_H */ gnunet-0.9.3/src/include/gnunet_postgres_lib.h0000644000175000017500000001115411760502551016407 00000000000000/* This file is part of GNUnet (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_postgres_lib.h * @brief library to help with access to a Postgres database * @author Christian Grothoff */ #ifndef GNUNET_POSTGRES_LIB_H #define GNUNET_POSTGRES_LIB_H #include "gnunet_util_lib.h" #include #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * Check if the result obtained from Postgres has * the desired status code. If not, log an error, clear the * result and return GNUNET_SYSERR. * * @param dbh database handle * @param ret return value from database operation to check * @param expected_status desired status * @param command description of the command that was run * @param args arguments given to the command * @param filename name of the source file where the command was run * @param line line number in the source file * @return GNUNET_OK if the result is acceptable */ int GNUNET_POSTGRES_check_result_ (PGconn *dbh, PGresult * ret, int expected_status, const char *command, const char *args, const char *filename, int line); /** * Check if the result obtained from Postgres has * the desired status code. If not, log an error, clear the * result and return GNUNET_SYSERR. * * @param dbh database handle * @param ret return value from database operation to check * @param expected_status desired status * @param command description of the command that was run * @param args arguments given to the command * @return GNUNET_OK if the result is acceptable */ #define GNUNET_POSTGRES_check_result(dbh,ret,expected_status,command,args) GNUNET_POSTGRES_check_result_(dbh,ret,expected_status,command,args,__FILE__,__LINE__) /** * Run simple SQL statement (without results). * * @param dbh database handle * @param sql statement to run * @param filename filename for error reporting * @param line code line for error reporting * @return GNUNET_OK on success */ int GNUNET_POSTGRES_exec_ (PGconn *dbh, const char *sql, const char *filename, int line); /** * Run simple SQL statement (without results). * * @param dbh database handle * @param sql statement to run * @return GNUNET_OK on success */ #define GNUNET_POSTGRES_exec(dbh,sql) GNUNET_POSTGRES_exec_(dbh,sql,__FILE__,__LINE__) /** * Prepare SQL statement. * * @param dbh database handle * @param name name for the prepared SQL statement * @param sql SQL code to prepare * @param nparms number of parameters in sql * @param filename filename for error reporting * @param line code line for error reporting * @return GNUNET_OK on success */ int GNUNET_POSTGRES_prepare_ (PGconn *dbh, const char *name, const char *sql, int nparms, const char *filename, int line); /** * Prepare SQL statement. * * @param dbh database handle * @param name name for the prepared SQL statement * @param sql SQL code to prepare * @param nparams number of parameters in sql * @return GNUNET_OK on success */ #define GNUNET_POSTGRES_prepare(dbh,name,sql,nparams) GNUNET_POSTGRES_prepare_(dbh,name,sql,nparams,__FILE__,__LINE__) /** * Connect to a postgres database * * @param cfg configuration * @param section configuration section to use to get Postgres configuration options * @return the postgres handle */ PGconn * GNUNET_POSTGRES_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section); /** * Delete the row identified by the given rowid (qid * in postgres). * * @param dbh database handle * @param stmt name of the prepared statement * @param rowid which row to delete * @return GNUNET_OK on success */ int GNUNET_POSTGRES_delete_by_rowid (PGconn *dbh, const char *stmt, uint32_t rowid); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* end of gnunet_postgres_lib.h */ #endif gnunet-0.9.3/src/include/gnunet_mysql_lib.h0000644000175000017500000001442111760502551015706 00000000000000/* This file is part of GNUnet (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_mysql_lib.h * @brief library to help with access to a MySQL database * @author Christian Grothoff */ #ifndef GNUNET_MYSQL_LIB_H #define GNUNET_MYSQL_LIB_H #include "gnunet_util_lib.h" #include #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * Mysql context. */ struct GNUNET_MYSQL_Context; /** * Handle for a prepared statement. */ struct GNUNET_MYSQL_StatementHandle; /** * Type of a callback that will be called for each * data set returned from MySQL. * * @param cls user-defined argument * @param num_values number of elements in values * @param values values returned by MySQL * @return GNUNET_OK to continue iterating, GNUNET_SYSERR to abort */ typedef int (*GNUNET_MYSQL_DataProcessor) (void *cls, unsigned int num_values, MYSQL_BIND * values); /** * Create a mysql context. * * @param cfg configuration * @param section configuration section to use to get MySQL configuration options * @return the mysql context */ struct GNUNET_MYSQL_Context * GNUNET_MYSQL_context_create (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section); /** * Destroy a mysql context. Also frees all associated prepared statements. * * @param mc context to destroy */ void GNUNET_MYSQL_context_destroy (struct GNUNET_MYSQL_Context *mc); /** * Close database connection and all prepared statements (we got a DB * error). The connection will automatically be re-opened and * statements will be re-prepared if they are needed again later. * * @param mc mysql context */ void GNUNET_MYSQL_statements_invalidate (struct GNUNET_MYSQL_Context *mc); /** * Get internal handle for a prepared statement. This function should rarely * be used, and if, with caution! On failures during the interaction with * the handle, you must call 'GNUNET_MYSQL_statements_invalidate'! * * @param mc mysql context * @param sh prepared statement to introspect * @return MySQL statement handle, NULL on error */ MYSQL_STMT * GNUNET_MYSQL_statement_get_stmt (struct GNUNET_MYSQL_Context *mc, struct GNUNET_MYSQL_StatementHandle *sh); /** * Prepare a statement. Prepared statements are automatically discarded * when the MySQL context is destroyed. * * @param mc mysql context * @param query query text * @return prepared statement, NULL on error */ struct GNUNET_MYSQL_StatementHandle * GNUNET_MYSQL_statement_prepare (struct GNUNET_MYSQL_Context *mc, const char *query); /** * Run a SQL statement. * * @param mc mysql context * @param sql SQL statement to run * @return GNUNET_OK on success * GNUNET_SYSERR if there was a problem */ int GNUNET_MYSQL_statement_run (struct GNUNET_MYSQL_Context *mc, const char *sql); /** * Run a prepared SELECT statement. * * @param mc mysql context * @param sh handle to SELECT statment * @param result_size number of elements in results array * @param results pointer to already initialized MYSQL_BIND * array (of sufficient size) for passing results * @param processor function to call on each result * @param processor_cls extra argument to processor * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective * values (size + buffer-reference for pointers); terminated * with "-1" * @return GNUNET_SYSERR on error, otherwise * the number of successfully affected (or queried) rows */ int GNUNET_MYSQL_statement_run_prepared_select (struct GNUNET_MYSQL_Context *mc, struct GNUNET_MYSQL_StatementHandle *sh, unsigned int result_size, MYSQL_BIND * results, GNUNET_MYSQL_DataProcessor processor, void *processor_cls, ...); /** * Run a prepared SELECT statement. * * @param mc mysql context * @param s statement to run * @param result_size number of elements in results array * @param results pointer to already initialized MYSQL_BIND * array (of sufficient size) for passing results * @param processor function to call on each result * @param processor_cls extra argument to processor * @param ap pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective * values (size + buffer-reference for pointers); terminated * with "-1" * @return GNUNET_SYSERR on error, otherwise * the number of successfully affected (or queried) rows */ int GNUNET_MYSQL_statement_run_prepared_select_va (struct GNUNET_MYSQL_Context *mc, struct GNUNET_MYSQL_StatementHandle *s, unsigned int result_size, MYSQL_BIND * results, GNUNET_MYSQL_DataProcessor processor, void *processor_cls, va_list ap); /** * Run a prepared statement that does NOT produce results. * * @param mc mysql context * @param sh handle to statment * @param insert_id NULL or address where to store the row ID of whatever * was inserted (only for INSERT statements!) * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective * values (size + buffer-reference for pointers); terminated * with "-1" * @return GNUNET_SYSERR on error, otherwise * the number of successfully affected rows */ int GNUNET_MYSQL_statement_run_prepared (struct GNUNET_MYSQL_Context *mc, struct GNUNET_MYSQL_StatementHandle *sh, unsigned long long *insert_id, ...); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* end of gnunet_mysql_lib.h */ #endif gnunet-0.9.3/src/include/gnunet_datacache_lib.h0000644000175000017500000000764411760502551016447 00000000000000/* This file is part of GNUnet (C) 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_datacache_lib.h * @brief datacache is a simple, transient hash table * of bounded size with content expiration. * In contrast to the sqstore there is * no prioritization, deletion or iteration. * All of the data is discarded when the peer shuts down! * @author Christian Grothoff */ #ifndef GNUNET_DATACACHE_LIB_H #define GNUNET_DATACACHE_LIB_H #include "gnunet_util_lib.h" #include "gnunet_block_lib.h" #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * Handle to the cache. */ struct GNUNET_DATACACHE_Handle; /** * Create a data cache. * * @param cfg configuration to use * @param section section in the configuration that contains our options * @return handle to use to access the service */ struct GNUNET_DATACACHE_Handle * GNUNET_DATACACHE_create (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section); /** * Destroy a data cache (and free associated resources). * * @param h handle to the datastore */ void GNUNET_DATACACHE_destroy (struct GNUNET_DATACACHE_Handle *h); /** * An iterator over a set of items stored in the datacache. * * @param cls closure * @param exp when will the content expire? * @param key key for the content * @param size number of bytes in data * @param data content stored * @param type type of the content * @return GNUNET_OK to continue iterating, GNUNET_SYSERR to abort */ typedef int (*GNUNET_DATACACHE_Iterator) (void *cls, struct GNUNET_TIME_Absolute exp, const GNUNET_HashCode * key, size_t size, const char *data, enum GNUNET_BLOCK_Type type); /** * Store an item in the datacache. * * @param h handle to the datacache * @param key key to store data under * @param size number of bytes in data * @param data data to store * @param type type of the value * @param discard_time when to discard the value in any case * @return GNUNET_OK on success, GNUNET_SYSERR on error (full, etc.) */ int GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h, const GNUNET_HashCode * key, size_t size, const char *data, enum GNUNET_BLOCK_Type type, struct GNUNET_TIME_Absolute discard_time); /** * Iterate over the results for a particular key * in the datacache. * * @param h handle to the datacache * @param key what to look up * @param type entries of which type are relevant? * @param iter maybe NULL (to just count) * @param iter_cls closure for iter * @return the number of results found */ unsigned int GNUNET_DATACACHE_get (struct GNUNET_DATACACHE_Handle *h, const GNUNET_HashCode * key, enum GNUNET_BLOCK_Type type, GNUNET_DATACACHE_Iterator iter, void *iter_cls); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* end of gnunet_datacache_lib.h */ #endif gnunet-0.9.3/src/include/gnunet_scheduler_lib.h0000644000175000017500000004436411760676437016547 00000000000000/* This file is part of GNUnet (C) 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_scheduler_lib.h * @brief API to schedule computations using continuation passing style * @author Christian Grothoff */ #ifndef GNUNET_SCHEDULER_LIB_H #define GNUNET_SCHEDULER_LIB_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * Opaque reference to a task. */ typedef unsigned long long GNUNET_SCHEDULER_TaskIdentifier; /** * Constant used to indicate that the scheduled * task has no others as prerequisites. */ #define GNUNET_SCHEDULER_NO_TASK ((GNUNET_SCHEDULER_TaskIdentifier) 0) /** * Reasons why the schedule may have triggered * the task now. */ enum GNUNET_SCHEDULER_Reason { /** * This is the very first task run during startup. */ GNUNET_SCHEDULER_REASON_STARTUP = 0, /** * We are shutting down and are running all shutdown-related tasks * (regardless of timeout, etc.). */ GNUNET_SCHEDULER_REASON_SHUTDOWN = 1, /** * The specified timeout has expired. * (also set if the delay given was 0). */ GNUNET_SCHEDULER_REASON_TIMEOUT = 2, /** * The reading socket is ready. */ GNUNET_SCHEDULER_REASON_READ_READY = 4, /** * The writing socket is ready. */ GNUNET_SCHEDULER_REASON_WRITE_READY = 8, /** * The prerequisite task is done. */ GNUNET_SCHEDULER_REASON_PREREQ_DONE = 16 }; /** * Valid task priorities. Use these, do not * pass random integers! */ enum GNUNET_SCHEDULER_Priority { /** * Run with the same priority as the current job. */ GNUNET_SCHEDULER_PRIORITY_KEEP = 0, /** * Run when otherwise idle. */ GNUNET_SCHEDULER_PRIORITY_IDLE = 1, /** * Run as background job (higher than idle, * lower than default). */ GNUNET_SCHEDULER_PRIORITY_BACKGROUND = 2, /** * Run with the default priority (normal * P2P operations). Any task that is scheduled * without an explicit priority being specified * will run with this priority. */ GNUNET_SCHEDULER_PRIORITY_DEFAULT = 3, /** * Run with high priority (important requests). * Higher than DEFAULT. */ GNUNET_SCHEDULER_PRIORITY_HIGH = 4, /** * Run with priority for interactive tasks. * Higher than "HIGH". */ GNUNET_SCHEDULER_PRIORITY_UI = 5, /** * Run with priority for urgent tasks. Use * for things like aborts and shutdowns that * need to preempt "UI"-level tasks. * Higher than "UI". */ GNUNET_SCHEDULER_PRIORITY_URGENT = 6, /** * This is an internal priority level that is only used for tasks * that are being triggered due to shutdown (they have automatically * highest priority). User code must not use this priority level * directly. Tasks run with this priority level that internally * schedule other tasks will see their original priority level * be inherited (unless otherwise specified). */ GNUNET_SCHEDULER_PRIORITY_SHUTDOWN = 7, /** * Number of priorities (must be the last priority). * This priority must not be used by clients. */ GNUNET_SCHEDULER_PRIORITY_COUNT = 8 }; #include "gnunet_time_lib.h" #include "gnunet_network_lib.h" /** * Context information passed to each scheduler task. */ struct GNUNET_SCHEDULER_TaskContext { /** * Reason why the task is run now */ enum GNUNET_SCHEDULER_Reason reason; /** * Set of file descriptors ready for reading; * note that additional bits may be set * that were not in the original request */ const struct GNUNET_NETWORK_FDSet *read_ready; /** * Set of file descriptors ready for writing; * note that additional bits may be set * that were not in the original request. */ const struct GNUNET_NETWORK_FDSet *write_ready; }; /** * Signature of the main function of a task. * * @param cls closure * @param tc context information (why was this task triggered now) */ typedef void (*GNUNET_SCHEDULER_Task) (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc); /** * Signature of the select function used by the scheduler. * GNUNET_NETWORK_socket_select matches it. * * @param cls closure * @param rfds set of sockets to be checked for readability * @param wfds set of sockets to be checked for writability * @param efds set of sockets to be checked for exceptions * @param timeout relative value when to return * @return number of selected sockets, GNUNET_SYSERR on error */ typedef int (*GNUNET_SCHEDULER_select) (void *cls, struct GNUNET_NETWORK_FDSet * rfds, struct GNUNET_NETWORK_FDSet * wfds, struct GNUNET_NETWORK_FDSet * efds, struct GNUNET_TIME_Relative timeout); /** * Initialize and run scheduler. This function will return when all * tasks have completed. On systems with signals, receiving a SIGTERM * (and other similar signals) will cause "GNUNET_SCHEDULER_shutdown" * to be run after the active task is complete. As a result, SIGTERM * causes all active tasks to be scheduled with reason * "GNUNET_SCHEDULER_REASON_SHUTDOWN". (However, tasks added * afterwards will execute normally!). Note that any particular * signal will only shut down one scheduler; applications should * always only create a single scheduler. * * @param task task to run first (and immediately) * @param task_cls closure of task */ void GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls); /** * Request the shutdown of a scheduler. Marks all currently * pending tasks as ready because of shutdown. This will * cause all tasks to run (as soon as possible, respecting * priorities and prerequisite tasks). Note that tasks * scheduled AFTER this call may still be delayed arbitrarily. */ void GNUNET_SCHEDULER_shutdown (void); /** * Get information about the current load of this scheduler. Use this * function to determine if an elective task should be added or simply * dropped (if the decision should be made based on the number of * tasks ready to run). * * * @param p priority-level to query, use KEEP to query the level * of the current task, use COUNT to get the sum over * all priority levels * @return number of tasks pending right now */ unsigned int GNUNET_SCHEDULER_get_load (enum GNUNET_SCHEDULER_Priority p); /** * Obtain the reason code for why the current task was * started. Will return the same value as * the GNUNET_SCHEDULER_TaskContext's reason field. * * * @return reason(s) why the current task is run */ enum GNUNET_SCHEDULER_Reason GNUNET_SCHEDULER_get_reason (void); /** * Cancel the task with the specified identifier. * The task must not yet have run. * * * @param task id of the task to cancel * @return the closure of the callback of the cancelled task */ void * GNUNET_SCHEDULER_cancel (GNUNET_SCHEDULER_TaskIdentifier task); /** * Continue the current execution with the given function. This is * similar to the other "add" functions except that there is no delay * and the reason code can be specified. * * * @param task main function of the task * @param task_cls closure of task * @param reason reason for task invocation */ void GNUNET_SCHEDULER_add_continuation (GNUNET_SCHEDULER_Task task, void *task_cls, enum GNUNET_SCHEDULER_Reason reason); /** * Continue the current execution with the given function. This is * similar to the other "add" functions except that there is no delay * and the reason code can be specified. * * @param task main function of the task * @param task_cls closure for 'main' * @param reason reason for task invocation * @param priority priority to use for the task */ void GNUNET_SCHEDULER_add_continuation_with_priority (GNUNET_SCHEDULER_Task task, void *task_cls, enum GNUNET_SCHEDULER_Reason reason, enum GNUNET_SCHEDULER_Priority priority); /** * Schedule a new task to be run with a specified priority. * * * @param prio how important is the new task? * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_with_priority (enum GNUNET_SCHEDULER_Priority prio, GNUNET_SCHEDULER_Task task, void *task_cls); /** * Schedule a new task to be run as soon as possible. The task * will be run with the DEFAULT priority. * * * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_Task task, void *task_cls); /** * Schedule a new task to be run as soon as possible with the * (transitive) ignore-shutdown flag either explicitly set or * explicitly enabled. This task (and all tasks created from it, * other than by another call to this function) will either count or * not count for the 'lifeness' of the process. This API is only * useful in a few special cases. * * @param lifeness GNUNET_YES if the task counts for lifeness, GNUNET_NO if not. * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_now_with_lifeness (int lifeness, GNUNET_SCHEDULER_Task task, void *task_cls); /** * Schedule a new task to be run with a specified delay. The task * will be scheduled for execution once the delay has expired. It * will be run with the DEFAULT priority. * * * @param delay when should this operation time out? Use * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_delayed (struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_Task task, void *task_cls); /** * Schedule a new task to be run with a specified delay. The task * will be scheduled for execution once the delay has expired. * * @param delay when should this operation time out? Use * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" * @param priority priority to use for the task * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_delayed_with_priority (struct GNUNET_TIME_Relative delay, enum GNUNET_SCHEDULER_Priority priority, GNUNET_SCHEDULER_Task task, void *task_cls); /** * Schedule a new task to be run with a specified delay or when the * specified file descriptor is ready for reading. The delay can be * used as a timeout on the socket being ready. The task will be * scheduled for execution once either the delay has expired or the * socket operation is ready. It will be run with the DEFAULT priority. * * * @param delay when should this operation time out? Use * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" * @param rfd read file-descriptor * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *rfd, GNUNET_SCHEDULER_Task task, void *task_cls); /** * Schedule a new task to be run with a specified priority and to be * run after the specified delay or when the specified file descriptor * is ready for reading. The delay can be used as a timeout on the * socket being ready. The task will be scheduled for execution once * either the delay has expired or the socket operation is ready. It * will be run with the DEFAULT priority. * * @param delay when should this operation time out? Use * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" * @param priority priority to use for the task * @param rfd read file-descriptor * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_read_net_with_priority (struct GNUNET_TIME_Relative delay, enum GNUNET_SCHEDULER_Priority priority, struct GNUNET_NETWORK_Handle *rfd, GNUNET_SCHEDULER_Task task, void *task_cls); /** * Schedule a new task to be run with a specified delay or when the * specified file descriptor is ready for writing. The delay can be * used as a timeout on the socket being ready. The task will be * scheduled for execution once either the delay has expired or the * socket operation is ready. It will be run with the DEFAULT priority. * * * @param delay when should this operation time out? Use * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" * @param wfd write file-descriptor * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *wfd, GNUNET_SCHEDULER_Task task, void *task_cls); /** * Schedule a new task to be run with a specified delay or when the * specified file descriptor is ready for reading. The delay can be * used as a timeout on the socket being ready. The task will be * scheduled for execution once either the delay has expired or the * socket operation is ready. It will be run with the DEFAULT priority. * * * @param delay when should this operation time out? Use * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" * @param rfd read file-descriptor * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay, const struct GNUNET_DISK_FileHandle *rfd, GNUNET_SCHEDULER_Task task, void *task_cls); /** * Schedule a new task to be run with a specified delay or when the * specified file descriptor is ready for writing. The delay can be * used as a timeout on the socket being ready. The task will be * scheduled for execution once either the delay has expired or the * socket operation is ready. It will be run with the DEFAULT priority. * * * @param delay when should this operation time out? Use * GNUNET_TIME_UNIT_FOREVER_REL for "on shutdown" * @param wfd write file-descriptor * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay, const struct GNUNET_DISK_FileHandle *wfd, GNUNET_SCHEDULER_Task task, void *task_cls); /** * Schedule a new task to be run with a specified delay or when any of * the specified file descriptor sets is ready. The delay can be used * as a timeout on the socket(s) being ready. The task will be * scheduled for execution once either the delay has expired or any of * the socket operations is ready. This is the most general * function of the "add" family. Note that the "prerequisite_task" * must be satisfied in addition to any of the other conditions. In * other words, the task will be started when * * (prerequisite-run) * && (delay-ready * || any-rs-ready * || any-ws-ready * || shutdown-active) * * * @param prio how important is this task? * @param delay how long should we wait? Use GNUNET_TIME_UNIT_FOREVER_REL for "forever", * which means that the task will only be run after we receive SIGTERM * @param rs set of file descriptors we want to read (can be NULL) * @param ws set of file descriptors we want to write (can be NULL) * @param task main function of the task * @param task_cls closure of task * @return unique task identifier for the job * only valid until "task" is started! */ GNUNET_SCHEDULER_TaskIdentifier GNUNET_SCHEDULER_add_select (enum GNUNET_SCHEDULER_Priority prio, struct GNUNET_TIME_Relative delay, const struct GNUNET_NETWORK_FDSet *rs, const struct GNUNET_NETWORK_FDSet *ws, GNUNET_SCHEDULER_Task task, void *task_cls); /** * Sets the select function to use in the scheduler (scheduler_select). * * @param new_select new select function to use (NULL to reset to default) * @param new_select_cls closure for 'new_select' */ void GNUNET_SCHEDULER_set_select (GNUNET_SCHEDULER_select new_select, void *new_select_cls); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif #endif gnunet-0.9.3/src/include/gauger.h0000644000175000017500000000464611760502551013615 00000000000000/** --------------------------------------------------------------------------- * This software is in the public domain, furnished "as is", without technical * support, and with no warranty, express or implied, as to its usefulness for * any purpose. * * gauger.h * Interface for C programs to log remotely to a gauger server * * Author: Bartlomiej Polot * -------------------------------------------------------------------------*/ #ifndef __GAUGER_H__ #define __GAUGER_H__ #ifndef WINDOWS #include #include #include #define GAUGER(category, counter, value, unit)\ {\ char* __gauger_v[10];\ char __gauger_s[32];\ pid_t __gauger_p;\ if(!(__gauger_p=fork())){\ close (1); \ close (2); \ if(!fork()){\ sprintf(__gauger_s,"%Lf", (long double) (value));\ __gauger_v[0] = "gauger";\ __gauger_v[1] = "-n";\ __gauger_v[2] = counter;\ __gauger_v[3] = "-d";\ __gauger_v[4] = __gauger_s;\ __gauger_v[5] = "-u";\ __gauger_v[6] = unit;\ __gauger_v[7] = "-c";\ __gauger_v[8] = category;\ __gauger_v[9] = (char *)NULL;\ execvp("gauger",__gauger_v);\ _exit(1);\ }else{\ _exit(0);\ }\ }else{\ waitpid(__gauger_p,NULL,0);\ }\ } #define GAUGER_ID(category, counter, value, unit, id)\ {\ char* __gauger_v[12];\ char __gauger_s[32];\ pid_t __gauger_p;\ if(!(__gauger_p=fork())){\ close (1); \ close (2); \ if(!fork()){\ sprintf(__gauger_s,"%Lf", (long double) (value));\ __gauger_v[0] = "gauger";\ __gauger_v[1] = "-n";\ __gauger_v[2] = counter;\ __gauger_v[3] = "-d";\ __gauger_v[4] = __gauger_s;\ __gauger_v[5] = "-u";\ __gauger_v[6] = unit;\ __gauger_v[7] = "-i";\ __gauger_v[8] = id;\ __gauger_v[9] = "-c";\ __gauger_v[10] = category;\ __gauger_v[11] = (char *)NULL;\ execvp("gauger",__gauger_v);\ _exit(1);\ }else{\ _exit(0);\ }\ }else{\ waitpid(__gauger_p,NULL,0);\ }\ } #else #define GAUGER_ID(category, counter, value, unit, id) {} #define GAUGER(category, counter, value, unit) {} #endif // WINDOWS #endif gnunet-0.9.3/src/include/gnunet_fs_service.h0000644000175000017500000023661411760502551016055 00000000000000/* This file is part of GNUnet (C) 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_fs_service.h * @brief API for file-sharing via GNUnet * @author Christian Grothoff */ #ifndef GNUNET_FS_LIB_H #define GNUNET_FS_LIB_H #include "gnunet_util_lib.h" #include "gnunet_scheduler_lib.h" #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * Version number of the implementation. * History: * * 1.x.x: initial version with triple GNUNET_hash and merkle tree * 2.x.x: root node with mime-type, filename and version number * 2.1.x: combined GNUNET_EC_ContentHashKey/3HASH encoding with 25:1 super-nodes * 2.2.x: with directories * 3.0.x: with namespaces * 3.1.x: with namespace meta-data * 3.2.x: with collections * 4.0.x: with expiration, variable meta-data, kblocks * 4.1.x: with new error and configuration handling * 5.0.x: with location URIs * 6.0.0: with support for OR in KSKs * 6.1.x: with simplified namespace support * 9.0.0: CPS-style integrated API * 9.1.1: asynchronous directory scanning */ #define GNUNET_FS_VERSION 0x00090102 /* ******************** URI API *********************** */ #define GNUNET_FS_URI_PREFIX "gnunet://fs/" #define GNUNET_FS_URI_KSK_INFIX "ksk/" #define GNUNET_FS_URI_SKS_INFIX "sks/" #define GNUNET_FS_URI_CHK_INFIX "chk/" #define GNUNET_FS_URI_LOC_INFIX "loc/" /** * A Universal Resource Identifier (URI), opaque. */ struct GNUNET_FS_Uri; /** * Iterator over keywords * * @param cls closure * @param keyword the keyword * @param is_mandatory is the keyword mandatory (in a search) * @return GNUNET_OK to continue to iterate, GNUNET_SYSERR to abort */ typedef int (*GNUNET_FS_KeywordIterator) (void *cls, const char *keyword, int is_mandatory); /** * Get a unique key from a URI. This is for putting URIs * into HashMaps. The key may change between FS implementations. * * @param uri uri to convert to a unique key * @param key wherer to store the unique key */ void GNUNET_FS_uri_to_key (const struct GNUNET_FS_Uri *uri, GNUNET_HashCode * key); /** * Convert a URI to a UTF-8 String. * * @param uri uri to convert to a string * @return the UTF-8 string */ char * GNUNET_FS_uri_to_string (const struct GNUNET_FS_Uri *uri); /** * Convert keyword URI to a human readable format * (i.e. the search query that was used in the first place) * * @param uri ksk uri to convert to a string * @return string with the keywords */ char * GNUNET_FS_uri_ksk_to_string_fancy (const struct GNUNET_FS_Uri *uri); /** * Add the given keyword to the set of keywords represented by the URI. * Does nothing if the keyword is already present. * * @param uri ksk uri to modify * @param keyword keyword to add * @param is_mandatory is this keyword mandatory? */ void GNUNET_FS_uri_ksk_add_keyword (struct GNUNET_FS_Uri *uri, const char *keyword, int is_mandatory); /** * Remove the given keyword from the set of keywords represented by the URI. * Does nothing if the keyword is not present. * * @param uri ksk uri to modify * @param keyword keyword to add */ void GNUNET_FS_uri_ksk_remove_keyword (struct GNUNET_FS_Uri *uri, const char *keyword); /** * Convert a UTF-8 String to a URI. * * @param uri string to parse * @param emsg where to store the parser error message (if any) * @return NULL on error */ struct GNUNET_FS_Uri * GNUNET_FS_uri_parse (const char *uri, char **emsg); /** * Free URI. * * @param uri uri to free */ void GNUNET_FS_uri_destroy (struct GNUNET_FS_Uri *uri); /** * How many keywords are ANDed in this keyword URI? * * @param uri ksk uri to get the number of keywords from * @return 0 if this is not a keyword URI */ unsigned int GNUNET_FS_uri_ksk_get_keyword_count (const struct GNUNET_FS_Uri *uri); /** * Iterate over all keywords in this keyword URI. * * @param uri ksk uri to get the keywords from * @param iterator function to call on each keyword * @param iterator_cls closure for iterator * @return -1 if this is not a keyword URI, otherwise number of * keywords iterated over until iterator aborted */ int GNUNET_FS_uri_ksk_get_keywords (const struct GNUNET_FS_Uri *uri, GNUNET_FS_KeywordIterator iterator, void *iterator_cls); /** * Obtain the identity of the peer offering the data * * @param uri the location URI to inspect * @param peer where to store the identify of the peer (presumably) offering the content * @return GNUNET_SYSERR if this is not a location URI, otherwise GNUNET_OK */ int GNUNET_FS_uri_loc_get_peer_identity (const struct GNUNET_FS_Uri *uri, struct GNUNET_PeerIdentity *peer); /** * Obtain the URI of the content itself. * * @param uri location URI to get the content URI from * @return NULL if argument is not a location URI */ struct GNUNET_FS_Uri * GNUNET_FS_uri_loc_get_uri (const struct GNUNET_FS_Uri *uri); /** * Obtain the expiration of the LOC URI. * * @param uri location URI to get the expiration from * @return expiration time of the URI */ struct GNUNET_TIME_Absolute GNUNET_FS_uri_loc_get_expiration (const struct GNUNET_FS_Uri *uri); /** * Construct a location URI (this peer will be used for the location). * * @param baseUri content offered by the sender * @param cfg configuration information (used to find our hostkey) * @param expiration_time how long will the content be offered? * @return the location URI, NULL on error */ struct GNUNET_FS_Uri * GNUNET_FS_uri_loc_create (const struct GNUNET_FS_Uri *baseUri, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TIME_Absolute expiration_time); /** * Merge the sets of keywords from two KSK URIs. * * @param u1 first uri * @param u2 second uri * @return merged URI, NULL on error */ struct GNUNET_FS_Uri * GNUNET_FS_uri_ksk_merge (const struct GNUNET_FS_Uri *u1, const struct GNUNET_FS_Uri *u2); /** * Duplicate URI. * * @param uri the URI to duplicate * @return copy of the URI */ struct GNUNET_FS_Uri * GNUNET_FS_uri_dup (const struct GNUNET_FS_Uri *uri); /** * Create an FS URI from a single user-supplied string of keywords. * The string is broken up at spaces into individual keywords. * Keywords that start with "+" are mandatory. Double-quotes can * be used to prevent breaking up strings at spaces (and also * to specify non-mandatory keywords starting with "+"). * * Keywords must contain a balanced number of double quotes and * double quotes can not be used in the actual keywords (for * example, the string '""foo bar""' will be turned into two * "OR"ed keywords 'foo' and 'bar', not into '"foo bar"'. * * @param keywords the keyword string * @param emsg where to store an error message * @return an FS URI for the given keywords, NULL * if keywords is not legal (i.e. empty). */ struct GNUNET_FS_Uri * GNUNET_FS_uri_ksk_create (const char *keywords, char **emsg); /** * Create an FS URI from a user-supplied command line of keywords. * Arguments should start with "+" to indicate mandatory * keywords. * * @param argc number of keywords * @param argv keywords (double quotes are not required for * keywords containing spaces; however, double * quotes are required for keywords starting with * "+"); there is no mechanism for having double * quotes in the actual keywords (if the user * did specifically specify double quotes, the * caller should convert each double quote * into two single quotes). * @return an FS URI for the given keywords, NULL * if keywords is not legal (i.e. empty). */ struct GNUNET_FS_Uri * GNUNET_FS_uri_ksk_create_from_args (unsigned int argc, const char **argv); /** * Test if two URIs are equal. * * @param u1 one of the URIs * @param u2 the other URI * @return GNUNET_YES if the URIs are equal */ int GNUNET_FS_uri_test_equal (const struct GNUNET_FS_Uri *u1, const struct GNUNET_FS_Uri *u2); /** * Is this a namespace URI? * * @param uri the uri to check * @return GNUNET_YES if this is an SKS uri */ int GNUNET_FS_uri_test_sks (const struct GNUNET_FS_Uri *uri); /** * Handle to one of our namespaces. */ struct GNUNET_FS_Namespace; /** * Create an SKS URI from a namespace and an identifier. * * @param ns namespace * @param id identifier * @param emsg where to store an error message * @return an FS URI for the given namespace and identifier */ struct GNUNET_FS_Uri * GNUNET_FS_uri_sks_create (struct GNUNET_FS_Namespace *ns, const char *id, char **emsg); /** * Create an SKS URI from a namespace ID and an identifier. * * @param nsid namespace ID * @param id identifier * @return an FS URI for the given namespace and identifier */ struct GNUNET_FS_Uri * GNUNET_FS_uri_sks_create_from_nsid (GNUNET_HashCode * nsid, const char *id); /** * Get the ID of a namespace from the given * namespace URI. * * @param uri the uri to get the namespace ID from * @param nsid where to store the ID of the namespace * @return GNUNET_OK on success */ int GNUNET_FS_uri_sks_get_namespace (const struct GNUNET_FS_Uri *uri, GNUNET_HashCode * nsid); /** * Get the content identifier of an SKS URI. * * @param uri the sks uri * @return NULL on error (not a valid SKS URI) */ char * GNUNET_FS_uri_sks_get_content_id (const struct GNUNET_FS_Uri *uri); /** * Convert namespace URI to a human readable format * (using the namespace description, if available). * * @param cfg configuration to use * @param uri SKS uri to convert * @return NULL on error (not an SKS URI) */ char * GNUNET_FS_uri_sks_to_string_fancy (struct GNUNET_CONFIGURATION_Handle *cfg, const struct GNUNET_FS_Uri *uri); /** * Is this a keyword URI? * * @param uri the uri * @return GNUNET_YES if this is a KSK uri */ int GNUNET_FS_uri_test_ksk (const struct GNUNET_FS_Uri *uri); /** * Is this a file (or directory) URI? * * @param uri the uri to check * @return GNUNET_YES if this is a CHK uri */ int GNUNET_FS_uri_test_chk (const struct GNUNET_FS_Uri *uri); /** * What is the size of the file that this URI * refers to? * * @param uri the CHK (or LOC) URI to inspect * @return size of the file as specified in the CHK URI */ uint64_t GNUNET_FS_uri_chk_get_file_size (const struct GNUNET_FS_Uri *uri); /** * Is this a location URI? * * @param uri the uri to check * @return GNUNET_YES if this is a LOC uri */ int GNUNET_FS_uri_test_loc (const struct GNUNET_FS_Uri *uri); /** * Construct a keyword-URI from meta-data (take all entries * in the meta-data and construct one large keyword URI * that lists all keywords that can be found in the meta-data). * * @param md metadata to use * @return NULL on error, otherwise a KSK URI */ struct GNUNET_FS_Uri * GNUNET_FS_uri_ksk_create_from_meta_data (const struct GNUNET_CONTAINER_MetaData *md); /* ******************** command-line option parsing API *********************** */ /** * Command-line option parser function that allows the user * to specify one or more '-k' options with keywords. Each * specified keyword will be added to the URI. A pointer to * the URI must be passed as the "scls" argument. * * @param ctx command line processor context * @param scls must be of type "struct GNUNET_FS_Uri **" * @param option name of the option (typically 'k') * @param value command line argument given * @return GNUNET_OK on success */ int GNUNET_FS_getopt_set_keywords (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, const char *value); /** * Command-line option parser function that allows the user to specify * one or more '-m' options with metadata. Each specified entry of * the form "type=value" will be added to the metadata. A pointer to * the metadata must be passed as the "scls" argument. * * @param ctx command line processor context * @param scls must be of type "struct GNUNET_CONTAINER_MetaData **" * @param option name of the option (typically 'k') * @param value command line argument given * @return GNUNET_OK on success */ int GNUNET_FS_getopt_set_metadata (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, const char *value); /* ************************* sharing API ***************** */ /** * Possible status codes used in the callback for the * various file-sharing operations. On each file (or search), * the callback is guaranteed to be called once with "START" * and once with STOPPED; calls with PROGRESS, ERROR or COMPLETED * are optional and depend on the circumstances; parent operations * will be STARTED before child-operations and STOPPED after * their respective child-operations. START and STOP signals * are typically generated either due to explicit client requests * or because of suspend/resume operations. */ enum GNUNET_FS_Status { /** * Notification that we have started to publish a file structure. */ GNUNET_FS_STATUS_PUBLISH_START = 0, /** * Notification that we have resumed sharing a file structure. */ GNUNET_FS_STATUS_PUBLISH_RESUME = 1, /** * Notification that we have suspended sharing a file structure. */ GNUNET_FS_STATUS_PUBLISH_SUSPEND = 2, /** * Notification that we are making progress sharing a file structure. */ GNUNET_FS_STATUS_PUBLISH_PROGRESS = 3, /** * Notification that an error was encountered sharing a file structure. * The application will continue to receive resume/suspend events for * this structure until "GNUNET_FS_publish_stop" is called. */ GNUNET_FS_STATUS_PUBLISH_ERROR = 4, /** * Notification that we completed sharing a file structure. * The application will continue to receive resume/suspend events for * this structure until "GNUNET_FS_publish_stop" is called. */ GNUNET_FS_STATUS_PUBLISH_COMPLETED = 5, /** * Notification that we have stopped * the process of uploading a file structure; no * futher events will be generated for this action. */ GNUNET_FS_STATUS_PUBLISH_STOPPED = 6, /** * Notification that we have started this download. */ GNUNET_FS_STATUS_DOWNLOAD_START = 7, /** * Notification that this download is being resumed. */ GNUNET_FS_STATUS_DOWNLOAD_RESUME = 8, /** * Notification that this download was suspended. */ GNUNET_FS_STATUS_DOWNLOAD_SUSPEND = 9, /** * Notification about progress with this download. */ GNUNET_FS_STATUS_DOWNLOAD_PROGRESS = 10, /** * Notification that this download encountered an error. */ GNUNET_FS_STATUS_DOWNLOAD_ERROR = 11, /** * Notification that this download completed. Note that for * directories, completion does not imply completion of all files in * the directory. */ GNUNET_FS_STATUS_DOWNLOAD_COMPLETED = 12, /** * Notification that this download was stopped * (final event with respect to this action). */ GNUNET_FS_STATUS_DOWNLOAD_STOPPED = 13, /** * Notification that this download is now actively being * pursued (as opposed to waiting in the queue). */ GNUNET_FS_STATUS_DOWNLOAD_ACTIVE = 14, /** * Notification that this download is no longer actively * being pursued (back in the queue). */ GNUNET_FS_STATUS_DOWNLOAD_INACTIVE = 15, /** * Notification that this download is no longer part of a * recursive download or search but now a 'stand-alone' * download (and may thus need to be moved in the GUI * into a different category). */ GNUNET_FS_STATUS_DOWNLOAD_LOST_PARENT = 16, /** * First event generated when a client requests * a search to begin or when a namespace result * automatically triggers the search for updates. */ GNUNET_FS_STATUS_SEARCH_START = 17, /** * Last event when a search is being resumed; * note that "GNUNET_FS_SEARCH_START" will not * be generated in this case. */ GNUNET_FS_STATUS_SEARCH_RESUME = 18, /** * Event generated for each search result * when the respective search is resumed. */ GNUNET_FS_STATUS_SEARCH_RESUME_RESULT = 19, /** * Last event when a search is being suspended; * note that "GNUNET_FS_SEARCH_STOPPED" will not * be generated in this case. */ GNUNET_FS_STATUS_SEARCH_SUSPEND = 20, /** * This search has yielded a result. */ GNUNET_FS_STATUS_SEARCH_RESULT = 21, /** * We have discovered a new namespace. */ GNUNET_FS_STATUS_SEARCH_RESULT_NAMESPACE = 22, /** * We have additional data about the quality * or availability of a search result. */ GNUNET_FS_STATUS_SEARCH_UPDATE = 23, /** * Signals a problem with this search. */ GNUNET_FS_STATUS_SEARCH_ERROR = 24, /** * Signals that this search was paused. */ GNUNET_FS_STATUS_SEARCH_PAUSED = 25, /** * Signals that this search was continued (unpaused). */ GNUNET_FS_STATUS_SEARCH_CONTINUED = 26, /** * Event generated for each search result * when the respective search is stopped. */ GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED = 27, /** * Event generated for each search result * when the respective search is suspended. */ GNUNET_FS_STATUS_SEARCH_RESULT_SUSPEND = 28, /** * Last message from a search; this signals * that there will be no further events associated * with this search. */ GNUNET_FS_STATUS_SEARCH_STOPPED = 29, /** * Notification that we started to unindex a file. */ GNUNET_FS_STATUS_UNINDEX_START = 30, /** * Notification that we resumed unindexing of a file. */ GNUNET_FS_STATUS_UNINDEX_RESUME = 31, /** * Notification that we suspended unindexing a file. */ GNUNET_FS_STATUS_UNINDEX_SUSPEND = 32, /** * Notification that we made progress unindexing a file. */ GNUNET_FS_STATUS_UNINDEX_PROGRESS = 33, /** * Notification that we encountered an error unindexing * a file. */ GNUNET_FS_STATUS_UNINDEX_ERROR = 34, /** * Notification that the unindexing of this file * was completed. */ GNUNET_FS_STATUS_UNINDEX_COMPLETED = 35, /** * Notification that the unindexing of this file * was stopped (final event for this action). */ GNUNET_FS_STATUS_UNINDEX_STOPPED = 36 }; /** * Handle for controlling an upload. */ struct GNUNET_FS_PublishContext; /** * Handle for controlling an unindexing operation. */ struct GNUNET_FS_UnindexContext; /** * Handle for controlling a search. */ struct GNUNET_FS_SearchContext; /** * Result from a search. Opaque handle to refer to the search * (typically used when starting a download associated with the search * result). */ struct GNUNET_FS_SearchResult; /** * Context for controlling a download. */ struct GNUNET_FS_DownloadContext; /** * Handle for detail information about a file that is being publishd. * Specifies metadata, keywords, how to get the contents of the file * (i.e. data-buffer in memory, filename on disk) and other options. */ struct GNUNET_FS_FileInformation; /** * Argument given to the progress callback with * information about what is going on. */ struct GNUNET_FS_ProgressInfo { /** * Values that depend on the event type. */ union { /** * Values for all "GNUNET_FS_STATUS_PUBLISH_*" events. */ struct { /** * Context for controlling the upload. */ struct GNUNET_FS_PublishContext *pc; /** * Information about the file that is being publishd. */ const struct GNUNET_FS_FileInformation *fi; /** * Client context pointer (set the last time by the client for * this operation; initially NULL on START/RESUME events). */ void *cctx; /** * Client context pointer for the parent operation * (if this is a file in a directory or a subdirectory). */ void *pctx; /** * Name of the file being published; can be NULL. */ const char *filename; /** * How large is the file overall? For directories, * this is only the size of the directory itself, * not of the other files contained within the * directory. */ uint64_t size; /** * At what time do we expect to finish the upload? * (will be a value in the past for completed * uploads). */ struct GNUNET_TIME_Relative eta; /** * How long has this upload been actively running * (excludes times where the upload was suspended). */ struct GNUNET_TIME_Relative duration; /** * How many bytes have we completed? */ uint64_t completed; /** * What anonymity level is used for this upload? */ uint32_t anonymity; /** * Additional values for specific events. */ union { /** * These values are only valid for * GNUNET_FS_STATUS_PUBLISH_PROGRESS events. */ struct { /** * Data block we just published. */ const void *data; /** * At what offset in the file is "data"? */ uint64_t offset; /** * Length of the data block. */ uint64_t data_len; /** * Depth of the given block in the tree; * 0 would be the lowest level (DBLOCKs). */ unsigned int depth; } progress; /** * These values are only valid for * GNUNET_FS_STATUS_PUBLISH_RESUME events. */ struct { /** * Error message, NULL if no error was encountered so far. */ const char *message; /** * URI of the file (if the download had been completed) */ const struct GNUNET_FS_Uri *chk_uri; } resume; /** * These values are only valid for * GNUNET_FS_STATUS_PUBLISH_COMPLETED events. */ struct { /** * URI of the file. */ const struct GNUNET_FS_Uri *chk_uri; } completed; /** * These values are only valid for * GNUNET_FS_STATUS_PUBLISH_ERROR events. */ struct { /** * Error message, never NULL. */ const char *message; } error; } specifics; } publish; /** * Values for all "GNUNET_FS_STATUS_DOWNLOAD_*" events. */ struct { /** * Context for controlling the download. */ struct GNUNET_FS_DownloadContext *dc; /** * Client context pointer (set the last time * by the client for this operation; initially * NULL on START/RESUME events). */ void *cctx; /** * Client context pointer for the parent operation * (if this is a file in a directory or a subdirectory). */ void *pctx; /** * Client context pointer for the associated search operation * (specifically, context pointer for the specific search * result, not the overall search); only set if this * download was started from a search result. */ void *sctx; /** * URI used for this download. */ const struct GNUNET_FS_Uri *uri; /** * Name of the file that we are downloading. */ const char *filename; /** * How large is the download overall? This * is NOT necessarily the size from the * URI since we may be doing a partial download. */ uint64_t size; /** * At what time do we expect to finish the download? * (will be a value in the past for completed * uploads). */ struct GNUNET_TIME_Relative eta; /** * How long has this download been active? */ struct GNUNET_TIME_Relative duration; /** * How many bytes have we completed? */ uint64_t completed; /** * What anonymity level is used for this download? */ uint32_t anonymity; /** * Is the download currently active. */ int is_active; /** * Additional values for specific events. */ union { /** * These values are only valid for * GNUNET_FS_STATUS_DOWNLOAD_PROGRESS events. */ struct { /** * Data block we just obtained, can be NULL (even if * data_len > 0) if we found the entire block 'intact' on * disk. In this case, it is also possible for 'data_len' * to be larger than an individual (32k) block. */ const void *data; /** * At what offset in the file is "data"? */ uint64_t offset; /** * Length of the data block. */ uint64_t data_len; /** * Depth of the given block in the tree; * 0 would be the lowest level (DBLOCKS). */ unsigned int depth; /** * How much trust did we offer for downloading this block? */ unsigned int trust_offered; /** * How much time passed between us asking for this block and * actually getting it? GNUNET_TIME_UNIT_FOREVER_REL if unknown. */ struct GNUNET_TIME_Relative block_download_duration; } progress; /** * These values are only valid for * GNUNET_FS_STATUS_DOWNLOAD_START events. */ struct { /** * Known metadata for the download. */ const struct GNUNET_CONTAINER_MetaData *meta; } start; /** * These values are only valid for * GNUNET_FS_STATUS_DOWNLOAD_RESUME events. */ struct { /** * Known metadata for the download. */ const struct GNUNET_CONTAINER_MetaData *meta; /** * Error message, NULL if we have not encountered any error yet. */ const char *message; } resume; /** * These values are only valid for * GNUNET_FS_STATUS_DOWNLOAD_ERROR events. */ struct { /** * Error message. */ const char *message; } error; } specifics; } download; /** * Values for all "GNUNET_FS_STATUS_SEARCH_*" events. */ struct { /** * Context for controlling the search, NULL for * searches that were not explicitly triggered * by the client (i.e., searches for updates in * namespaces). */ struct GNUNET_FS_SearchContext *sc; /** * Client context pointer (set the last time by the client for * this operation; initially NULL on START/RESUME events). Note * that this value can only be set on START/RESUME; returning * non-NULL on RESULT/RESUME_RESULT will actually update the * private context for "UPDATE" events. */ void *cctx; /** * Client parent-context pointer; NULL for top-level searches, * refers to the client context of the associated search result * for automatically triggered searches for updates in * namespaces. In this case, 'presult' refers to that search * result. */ void *pctx; /** * What query is used for this search * (list of keywords or SKS identifier). */ const struct GNUNET_FS_Uri *query; /** * How long has this search been actively running * (excludes times where the search was paused or * suspended). */ struct GNUNET_TIME_Relative duration; /** * What anonymity level is used for this search? */ uint32_t anonymity; /** * Additional values for specific events. */ union { /** * These values are only valid for * GNUNET_FS_STATUS_SEARCH_RESULT events. */ struct { /** * Metadata for the search result. */ const struct GNUNET_CONTAINER_MetaData *meta; /** * URI for the search result. */ const struct GNUNET_FS_Uri *uri; /** * Handle to the result (for starting downloads). */ struct GNUNET_FS_SearchResult *result; /** * Applicability rank (the larger, the better the result * fits the search criteria). */ uint32_t applicability_rank; } result; /** * These values are only valid for * GNUNET_FS_STATUS_SEARCH_RESUME_RESULT events. */ struct { /** * Metadata for the search result. */ const struct GNUNET_CONTAINER_MetaData *meta; /** * URI for the search result. */ const struct GNUNET_FS_Uri *uri; /** * Handle to the result (for starting downloads). */ struct GNUNET_FS_SearchResult *result; /** * Current availability rank (negative: * unavailable, positive: available) */ int32_t availability_rank; /** * On how many total queries is the given * availability_rank based? */ uint32_t availability_certainty; /** * Updated applicability rank (the larger, * the better the result fits the search * criteria). */ uint32_t applicability_rank; } resume_result; /** * These values are only valid for * GNUNET_FS_STATUS_SEARCH_UPDATE events. */ struct { /** * Private context set for for this result * during the "RESULT" event. */ void *cctx; /** * Metadata for the search result. */ const struct GNUNET_CONTAINER_MetaData *meta; /** * URI for the search result. */ const struct GNUNET_FS_Uri *uri; /** * Current availability rank (negative: * unavailable, positive: available) */ int32_t availability_rank; /** * On how many total queries is the given * availability_rank based? */ uint32_t availability_certainty; /** * Updated applicability rank (the larger, * the better the result fits the search * criteria). */ uint32_t applicability_rank; } update; /** * These values are only valid for * GNUNET_FS_STATUS_SEARCH_RESULT_SUSPEND events. * These events are automatically triggered for * each search result before the * GNUNET_FS_STATUS_SEARCH_SUSPEND event. This * happens primarily to give the client a chance * to clean up the "cctx" (if needed). */ struct { /** * Private context set for for this result * during the "RESULT" event. */ void *cctx; /** * Metadata for the search result. */ const struct GNUNET_CONTAINER_MetaData *meta; /** * URI for the search result. */ const struct GNUNET_FS_Uri *uri; } result_suspend; /** * These values are only valid for * GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED events. * These events are automatically triggered for * each search result before the * GNUNET_FS_STATUS_SEARCH_STOPPED event. This * happens primarily to give the client a chance * to clean up the "cctx" (if needed). */ struct { /** * Private context set for for this result * during the "RESULT" event. */ void *cctx; /** * Metadata for the search result. */ const struct GNUNET_CONTAINER_MetaData *meta; /** * URI for the search result. */ const struct GNUNET_FS_Uri *uri; } result_stopped; /** * These values are only valid for * GNUNET_FS_STATUS_SEARCH_RESUME events. */ struct { /** * Error message, NULL if we have not encountered any error yet. */ const char *message; /** * Is this search currently paused? */ int is_paused; } resume; /** * These values are only valid for * GNUNET_FS_STATUS_SEARCH_ERROR events. */ struct { /** * Error message. */ const char *message; } error; /** * Values for all "GNUNET_FS_STATUS_SEARCH_RESULT_NAMESPACE" events. */ struct { /** * Handle to the namespace (NULL if it is not a local * namespace). */ struct GNUNET_FS_Namespace *ns; /** * Short, human-readable name of the namespace. */ const char *name; /** * Root identifier for the namespace, can be NULL. */ const char *root; /** * Metadata for the namespace. */ const struct GNUNET_CONTAINER_MetaData *meta; /** * Hash-identifier for the namespace. */ GNUNET_HashCode id; } namespace; } specifics; } search; /** * Values for all "GNUNET_FS_STATUS_UNINDEX_*" events. */ struct { /** * Context for controlling the unindexing. */ struct GNUNET_FS_UnindexContext *uc; /** * Client context pointer (set the last time * by the client for this operation; initially * NULL on START/RESUME events). */ void *cctx; /** * Name of the file that is being unindexed. */ const char *filename; /** * How large is the file overall? */ uint64_t size; /** * At what time do we expect to finish unindexing? * (will be a value in the past for completed * unindexing opeations). */ struct GNUNET_TIME_Relative eta; /** * How long has this upload been actively running * (excludes times where the upload was suspended). */ struct GNUNET_TIME_Relative duration; /** * How many bytes have we completed? */ uint64_t completed; /** * Additional values for specific events. */ union { /** * These values are only valid for * GNUNET_FS_STATUS_UNINDEX_PROGRESS events. */ struct { /** * Data block we just unindexed. */ const void *data; /** * At what offset in the file is "data"? */ uint64_t offset; /** * Length of the data block. */ uint64_t data_len; /** * Depth of the given block in the tree; * 0 would be the lowest level (DBLOCKS). */ unsigned int depth; } progress; /** * These values are only valid for * GNUNET_FS_STATUS_UNINDEX_RESUME events. */ struct { /** * Error message, NULL if we have not encountered any error yet. */ const char *message; } resume; /** * These values are only valid for * GNUNET_FS_STATUS_UNINDEX_ERROR events. */ struct { /** * Error message. */ const char *message; } error; } specifics; } unindex; } value; /** * Specific status code (determines the event type). */ enum GNUNET_FS_Status status; }; /** * Notification of FS to a client about the progress of an * operation. Callbacks of this type will be used for uploads, * downloads and searches. Some of the arguments depend a bit * in their meaning on the context in which the callback is used. * * @param cls closure * @param info details about the event, specifying the event type * and various bits about the event * @return client-context (for the next progress call * for this operation; should be set to NULL for * SUSPEND and STOPPED events). The value returned * will be passed to future callbacks in the respective * field in the GNUNET_FS_ProgressInfo struct. */ typedef void *(*GNUNET_FS_ProgressCallback) (void *cls, const struct GNUNET_FS_ProgressInfo * info); /** * General (global) option flags for file-sharing. */ enum GNUNET_FS_Flags { /** * No special flags set. */ GNUNET_FS_FLAGS_NONE = 0, /** * Is persistence of operations desired? * (will create SUSPEND/RESUME events). */ GNUNET_FS_FLAGS_PERSISTENCE = 1, /** * Should we automatically trigger probes for search results * to determine availability? * (will create GNUNET_FS_STATUS_SEARCH_UPDATE events). */ GNUNET_FS_FLAGS_DO_PROBES = 2 }; /** * Options specified in the VARARGs portion of GNUNET_FS_start. */ enum GNUNET_FS_OPTIONS { /** * Last option in the VARARG list. */ GNUNET_FS_OPTIONS_END = 0, /** * Select the desired amount of parallelism (this option should be * followed by an "unsigned int" giving the desired maximum number * of parallel downloads). */ GNUNET_FS_OPTIONS_DOWNLOAD_PARALLELISM = 1, /** * Maximum number of requests that should be pending at a given * point in time (invidivual downloads may go above this, but * if we are above this threshold, we should not activate any * additional downloads. */ GNUNET_FS_OPTIONS_REQUEST_PARALLELISM = 2 }; /** * Settings for publishing a block (which may of course also * apply to an entire directory or file). */ struct GNUNET_FS_BlockOptions { /** * At what time should the block expire? Data blocks (DBLOCKS and * IBLOCKS) may still be used even if they are expired (however, * they'd be removed quickly from the datastore if we are short on * space), all other types of blocks will no longer be returned * after they expire. */ struct GNUNET_TIME_Absolute expiration_time; /** * At which anonymity level should the block be shared? * (0: no anonymity, 1: normal GAP, >1: with cover traffic). */ uint32_t anonymity_level; /** * How important is it for us to store the block? If we run * out of space, the highest-priority, non-expired blocks will * be kept. */ uint32_t content_priority; /** * How often should we try to migrate the block to other peers? * Only used if "CONTENT_PUSHING" is set to YES, in which case we * first push each block to other peers according to their * replication levels. Once each block has been pushed that many * times to other peers, blocks are chosen for migration at random. * Naturally, there is no guarantee that the other peers will keep * these blocks for any period of time (since they won't have any * priority or might be too busy to even store the block in the * first place). */ uint32_t replication_level; }; /** * Return the current year (i.e. '2011'). */ unsigned int GNUNET_FS_get_current_year (void); /** * Convert a year to an expiration time of January 1st of that year. * * @param year a year (after 1970, please ;-)). * @return absolute time for January 1st of that year. */ struct GNUNET_TIME_Absolute GNUNET_FS_year_to_time (unsigned int year); /** * Convert an expiration time to the respective year (rounds) * * @param at absolute time * @return year a year (after 1970), 0 on error */ unsigned int GNUNET_FS_time_to_year (struct GNUNET_TIME_Absolute at); /** * Handle to the file-sharing service. */ struct GNUNET_FS_Handle; /** * Setup a connection to the file-sharing service. * * @param cfg configuration to use * @param client_name unique identifier for this client * @param upcb function to call to notify about FS actions * @param upcb_cls closure for upcb * @param flags specific attributes for fs-operations * @param ... list of optional options, terminated with GNUNET_FS_OPTIONS_END * @return NULL on error */ struct GNUNET_FS_Handle * GNUNET_FS_start (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *client_name, GNUNET_FS_ProgressCallback upcb, void *upcb_cls, enum GNUNET_FS_Flags flags, ...); /** * Close our connection with the file-sharing service. * The callback given to GNUNET_FS_start will no longer be * called after this function returns. * * @param h handle that was returned from GNUNET_FS_start */ void GNUNET_FS_stop (struct GNUNET_FS_Handle *h); /** * Function called on entries in a GNUNET_FS_FileInformation publish-structure. * * @param cls closure * @param fi the entry in the publish-structure * @param length length of the file or directory * @param meta metadata for the file or directory (can be modified) * @param uri pointer to the keywords that will be used for this entry (can be modified) * @param bo block options (can be modified) * @param do_index should we index (can be modified) * @param client_info pointer to client context set upon creation (can be modified) * @return GNUNET_OK to continue, GNUNET_NO to remove * this entry from the directory, GNUNET_SYSERR * to abort the iteration */ typedef int (*GNUNET_FS_FileInformationProcessor) (void *cls, struct GNUNET_FS_FileInformation * fi, uint64_t length, struct GNUNET_CONTAINER_MetaData * meta, struct GNUNET_FS_Uri ** uri, struct GNUNET_FS_BlockOptions * bo, int *do_index, void **client_info); /** * Obtain the name under which this file information * structure is stored on disk. Only works for top-level * file information structures. * * @param s structure to get the filename for * @return NULL on error, otherwise filename that * can be passed to "GNUNET_FS_file_information_recover" * to read this fi-struct from disk. */ const char * GNUNET_FS_file_information_get_id (struct GNUNET_FS_FileInformation *s); /** * Obtain the filename from the file information structure. * * @param s structure to get the filename for * @return "filename" field of the structure (can be NULL) */ const char * GNUNET_FS_file_information_get_filename (struct GNUNET_FS_FileInformation *s); /** * Set the filename in the file information structure. * If filename was already set, frees it before setting the new one. * Makes a copy of the argument. * * @param s structure to get the filename for * @param filename filename to set */ void GNUNET_FS_file_information_set_filename (struct GNUNET_FS_FileInformation *s, const char *filename); /** * Create an entry for a file in a publish-structure. * * @param h handle to the file sharing subsystem * @param client_info initial client-info value for this entry * @param filename name of the file or directory to publish * @param keywords under which keywords should this file be available * directly; can be NULL * @param meta metadata for the file * @param do_index GNUNET_YES for index, GNUNET_NO for insertion, * GNUNET_SYSERR for simulation * @param bo block options * @return publish structure entry for the file */ struct GNUNET_FS_FileInformation * GNUNET_FS_file_information_create_from_file (struct GNUNET_FS_Handle *h, void *client_info, const char *filename, const struct GNUNET_FS_Uri *keywords, const struct GNUNET_CONTAINER_MetaData *meta, int do_index, const struct GNUNET_FS_BlockOptions *bo); /** * Create an entry for a file in a publish-structure. * * @param h handle to the file sharing subsystem * @param client_info initial client-info value for this entry * @param length length of the file * @param data data for the file (should not be used afterwards by * the caller; callee will "free") * @param keywords under which keywords should this file be available * directly; can be NULL * @param meta metadata for the file * @param do_index GNUNET_YES for index, GNUNET_NO for insertion, * GNUNET_SYSERR for simulation * @param bo block options * @return publish structure entry for the file */ struct GNUNET_FS_FileInformation * GNUNET_FS_file_information_create_from_data (struct GNUNET_FS_Handle *h, void *client_info, uint64_t length, void *data, const struct GNUNET_FS_Uri *keywords, const struct GNUNET_CONTAINER_MetaData *meta, int do_index, const struct GNUNET_FS_BlockOptions *bo); /** * Function that provides data. * * @param cls closure * @param offset offset to read from; it is possible * that the caller might need to go backwards * a bit at times; set to UINT64_MAX to tell * the reader that we won't be reading for a while * (used to close the file descriptor but NOT fully * clean up the reader's state); in this case, * a value of '0' for max should be ignored * @param max maximum number of bytes that should be * copied to buf; readers are not allowed * to provide less data unless there is an error; * a value of "0" will be used at the end to allow * the reader to clean up its internal state * @param buf where the reader should write the data * @param emsg location for the reader to store an error message * @return number of bytes written, usually "max", 0 on error */ typedef size_t (*GNUNET_FS_DataReader) (void *cls, uint64_t offset, size_t max, void *buf, char **emsg); /** * Create an entry for a file in a publish-structure. * * @param h handle to the file sharing subsystem * @param client_info initial client-info value for this entry * @param length length of the file * @param reader function that can be used to obtain the data for the file * @param reader_cls closure for "reader" * @param keywords under which keywords should this file be available * directly; can be NULL * @param meta metadata for the file * @param do_index GNUNET_YES for index, GNUNET_NO for insertion, * GNUNET_SYSERR for simulation * @param bo block options * @return publish structure entry for the file */ struct GNUNET_FS_FileInformation * GNUNET_FS_file_information_create_from_reader (struct GNUNET_FS_Handle *h, void *client_info, uint64_t length, GNUNET_FS_DataReader reader, void *reader_cls, const struct GNUNET_FS_Uri *keywords, const struct GNUNET_CONTAINER_MetaData *meta, int do_index, const struct GNUNET_FS_BlockOptions *bo); /** * Create an entry for an empty directory in a publish-structure. * This function should be used by applications for which the * use of "GNUNET_FS_file_information_create_from_directory" * is not appropriate. * * @param h handle to the file sharing subsystem * @param client_info initial client-info value for this entry * @param keywords under which keywords should this directory be available * directly; can be NULL * @param meta metadata for the directory * @param bo block options * @param filename name of the directory; can be NULL * @return publish structure entry for the directory , NULL on error */ struct GNUNET_FS_FileInformation * GNUNET_FS_file_information_create_empty_directory (struct GNUNET_FS_Handle *h, void *client_info, const struct GNUNET_FS_Uri *keywords, const struct GNUNET_CONTAINER_MetaData *meta, const struct GNUNET_FS_BlockOptions *bo, const char *filename); /** * Test if a given entry represents a directory. * * @param ent check if this FI represents a directory * @return GNUNET_YES if so, GNUNET_NO if not */ int GNUNET_FS_file_information_is_directory (const struct GNUNET_FS_FileInformation *ent); /** * Add an entry to a directory in a publish-structure. Clients * should never modify publish structures that were passed to * "GNUNET_FS_publish_start" already. * * @param dir the directory * @param ent the entry to add; the entry must not have been * added to any other directory at this point and * must not include "dir" in its structure * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_FS_file_information_add (struct GNUNET_FS_FileInformation *dir, struct GNUNET_FS_FileInformation *ent); /** * Inspect a file or directory in a publish-structure. Clients * should never modify publish structures that were passed to * "GNUNET_FS_publish_start" already. When called on a directory, * this function will FIRST call "proc" with information about * the directory itself and then for each of the files in the * directory (but not for files in subdirectories). When called * on a file, "proc" will be called exactly once (with information * about the specific file). * * @param dir the directory * @param proc function to call on each entry * @param proc_cls closure for proc */ void GNUNET_FS_file_information_inspect (struct GNUNET_FS_FileInformation *dir, GNUNET_FS_FileInformationProcessor proc, void *proc_cls); /** * Destroy publish-structure. Clients should never destroy publish * structures that were passed to "GNUNET_FS_publish_start" already. * * @param fi structure to destroy * @param cleaner function to call on each entry in the structure * (useful to clean up client_info); can be NULL; return * values are ignored * @param cleaner_cls closure for cleaner */ void GNUNET_FS_file_information_destroy (struct GNUNET_FS_FileInformation *fi, GNUNET_FS_FileInformationProcessor cleaner, void *cleaner_cls); /** * Options for publishing. Compatible options * can be OR'ed together. */ enum GNUNET_FS_PublishOptions { /** * No options (use defaults for everything). */ GNUNET_FS_PUBLISH_OPTION_NONE = 0, /** * Simulate publishing. With this option, no data will be stored * in the datastore. Useful for computing URIs from files. */ GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY = 1 }; /** * Publish a file or directory. * * @param h handle to the file sharing subsystem * @param fi information about the file or directory structure to publish * @param namespace namespace to publish the file in, NULL for no namespace * @param nid identifier to use for the publishd content in the namespace * (can be NULL, must be NULL if namespace is NULL) * @param nuid update-identifier that will be used for future updates * (can be NULL, must be NULL if namespace or nid is NULL) * @param options options for the publication * @return context that can be used to control the publish operation */ struct GNUNET_FS_PublishContext * GNUNET_FS_publish_start (struct GNUNET_FS_Handle *h, struct GNUNET_FS_FileInformation *fi, struct GNUNET_FS_Namespace *namespace, const char *nid, const char *nuid, enum GNUNET_FS_PublishOptions options); /** * Stop a publication. Will abort incomplete publications (but * not remove blocks that have already been published) or * simply clean up the state for completed publications. * Must NOT be called from within the event callback! * * @param pc context for the publication to stop */ void GNUNET_FS_publish_stop (struct GNUNET_FS_PublishContext *pc); /** * Signature of a function called as the continuation of a KBlock or * SBlock publication. * * @param cls closure * @param uri URI under which the block is now available, NULL on error * @param emsg error message, NULL on success */ typedef void (*GNUNET_FS_PublishContinuation) (void *cls, const struct GNUNET_FS_Uri * uri, const char *emsg); /** * Handle to cancel publish KSK operation. */ struct GNUNET_FS_PublishKskContext; /** * Publish a KBlock on GNUnet. * * @param h handle to the file sharing subsystem * @param ksk_uri keywords to use * @param meta metadata to use * @param uri URI to refer to in the KBlock * @param bo block options * @param options publication options * @param cont continuation * @param cont_cls closure for cont * @return NULL on error ('cont' will still be called) */ struct GNUNET_FS_PublishKskContext * GNUNET_FS_publish_ksk (struct GNUNET_FS_Handle *h, const struct GNUNET_FS_Uri *ksk_uri, const struct GNUNET_CONTAINER_MetaData *meta, const struct GNUNET_FS_Uri *uri, const struct GNUNET_FS_BlockOptions *bo, enum GNUNET_FS_PublishOptions options, GNUNET_FS_PublishContinuation cont, void *cont_cls); /** * Abort the KSK publishing operation. * * @param pkc context of the operation to abort. */ void GNUNET_FS_publish_ksk_cancel (struct GNUNET_FS_PublishKskContext *pkc); /** * Handle to cancel publish SKS operation. */ struct GNUNET_FS_PublishSksContext; /** * Publish an SBlock on GNUnet. * * @param h handle to the file sharing subsystem * @param namespace namespace to publish in * @param identifier identifier to use * @param update update identifier to use * @param meta metadata to use * @param uri URI to refer to in the SBlock * @param bo block options * @param options publication options * @param cont continuation * @param cont_cls closure for cont * @return NULL on error ('cont' will still be called) */ struct GNUNET_FS_PublishSksContext * GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h, struct GNUNET_FS_Namespace *namespace, const char *identifier, const char *update, const struct GNUNET_CONTAINER_MetaData *meta, const struct GNUNET_FS_Uri *uri, const struct GNUNET_FS_BlockOptions *bo, enum GNUNET_FS_PublishOptions options, GNUNET_FS_PublishContinuation cont, void *cont_cls); /** * Abort the SKS publishing operation. * * @param psc context of the operation to abort. */ void GNUNET_FS_publish_sks_cancel (struct GNUNET_FS_PublishSksContext *psc); /** * Type of a function called by "GNUNET_FS_get_indexed_files". * * @param cls closure * @param filename the name of the file, NULL for end of list * @param file_id hash of the contents of the indexed file * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort */ typedef int (*GNUNET_FS_IndexedFileProcessor) (void *cls, const char *filename, const GNUNET_HashCode * file_id); /** * Handle to cancel 'GNUNET_FS_get_indexed_files'. */ struct GNUNET_FS_GetIndexedContext; /** * Iterate over all indexed files. * * @param h handle to the file sharing subsystem * @param iterator function to call on each indexed file * @param iterator_cls closure for iterator * @return NULL on error ('iter' is not called) */ struct GNUNET_FS_GetIndexedContext * GNUNET_FS_get_indexed_files (struct GNUNET_FS_Handle *h, GNUNET_FS_IndexedFileProcessor iterator, void *iterator_cls); /** * Cancel iteration over all indexed files. * * @param gic operation to cancel */ void GNUNET_FS_get_indexed_files_cancel (struct GNUNET_FS_GetIndexedContext *gic); /** * Unindex a file. * * @param h handle to the file sharing subsystem * @param filename file to unindex * @param cctx initial value for the client context * @return NULL on error, otherwise handle */ struct GNUNET_FS_UnindexContext * GNUNET_FS_unindex_start (struct GNUNET_FS_Handle *h, const char *filename, void *cctx); /** * Clean up after completion of an unindex operation. * * @param uc handle */ void GNUNET_FS_unindex_stop (struct GNUNET_FS_UnindexContext *uc); /** * Context for advertising a namespace. */ struct GNUNET_FS_AdvertisementContext; /** * Publish an advertismement for a namespace. * * @param h handle to the file sharing subsystem * @param ksk_uri keywords to use for advertisment * @param namespace handle for the namespace that should be advertised * @param meta meta-data for the namespace advertisement * @param bo block options * @param rootEntry name of the root of the namespace * @param cont continuation * @param cont_cls closure for cont * @return NULL on error ('cont' will still be called) */ struct GNUNET_FS_AdvertisementContext * GNUNET_FS_namespace_advertise (struct GNUNET_FS_Handle *h, struct GNUNET_FS_Uri *ksk_uri, struct GNUNET_FS_Namespace *namespace, const struct GNUNET_CONTAINER_MetaData *meta, const struct GNUNET_FS_BlockOptions *bo, const char *rootEntry, GNUNET_FS_PublishContinuation cont, void *cont_cls); /** * Abort the namespace advertisement operation. * * @param ac context of the operation to abort. */ void GNUNET_FS_namespace_advertise_cancel (struct GNUNET_FS_AdvertisementContext *ac); /** * Create a namespace with the given name; if one already * exists, return a handle to the existing namespace. * * @param h handle to the file sharing subsystem * @param name name to use for the namespace * @return handle to the namespace, NULL on error */ struct GNUNET_FS_Namespace * GNUNET_FS_namespace_create (struct GNUNET_FS_Handle *h, const char *name); /** * Duplicate a namespace handle. * * @param ns namespace handle * @return duplicated handle to the namespace */ struct GNUNET_FS_Namespace * GNUNET_FS_namespace_dup (struct GNUNET_FS_Namespace *ns); /** * Delete a namespace handle. Can be used for a clean shutdown (free * memory) or also to freeze the namespace to prevent further * insertions by anyone. * * @param namespace handle to the namespace that should be deleted / freed * @param freeze prevents future insertions; creating a namespace * with the same name again will create a fresh namespace instead * * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_FS_namespace_delete (struct GNUNET_FS_Namespace *namespace, int freeze); /** * Callback with information about local (!) namespaces. * Contains the names of the local namespace and the global * ID. * * @param cls closure * @param name human-readable identifier of the namespace * @param id hash identifier for the namespace */ typedef void (*GNUNET_FS_NamespaceInfoProcessor) (void *cls, const char *name, const GNUNET_HashCode * id); /** * Build a list of all available local (!) namespaces The returned * names are only the nicknames since we only iterate over the local * namespaces. * * @param h handle to the file sharing subsystem * @param cb function to call on each known namespace * @param cb_cls closure for cb */ void GNUNET_FS_namespace_list (struct GNUNET_FS_Handle *h, GNUNET_FS_NamespaceInfoProcessor cb, void *cb_cls); /** * Function called on updateable identifiers. * * @param cls closure * @param last_id last identifier * @param last_uri uri used for the content published under the last_id * @param last_meta metadata associated with last_uri * @param next_id identifier that should be used for updates */ typedef void (*GNUNET_FS_IdentifierProcessor) (void *cls, const char *last_id, const struct GNUNET_FS_Uri * last_uri, const struct GNUNET_CONTAINER_MetaData * last_meta, const char *next_id); /** * List all of the identifiers in the namespace for which we could * produce an update. Namespace updates form a graph where each node * has a name. Each node can have any number of URI/meta-data entries * which can each be linked to other nodes. Cycles are possible. * * Calling this function with "next_id" NULL will cause the library to * call "ip" with a root for each strongly connected component of the * graph (a root being a node from which all other nodes in the Scc * are reachable). * * Calling this function with "next_id" being the name of a node will * cause the library to call "ip" with all children of the node. Note * that cycles within an SCC are possible (including self-loops). * * @param namespace namespace to inspect for updateable content * @param next_id ID to look for; use NULL to look for SCC roots * @param ip function to call on each updateable identifier * @param ip_cls closure for ip */ void GNUNET_FS_namespace_list_updateable (struct GNUNET_FS_Namespace *namespace, const char *next_id, GNUNET_FS_IdentifierProcessor ip, void *ip_cls); /** * Options for searching. Compatible options * can be OR'ed together. */ enum GNUNET_FS_SearchOptions { /** * No options (use defaults for everything). */ GNUNET_FS_SEARCH_OPTION_NONE = 0, /** * Only search the local host, do not search remote systems (no P2P) */ GNUNET_FS_SEARCH_OPTION_LOOPBACK_ONLY = 1 }; /** * Start search for content. * * @param h handle to the file sharing subsystem * @param uri specifies the search parameters; can be * a KSK URI or an SKS URI. * @param anonymity desired level of anonymity * @param options options for the search * @param cctx initial value for the client context * @return context that can be used to control the search */ struct GNUNET_FS_SearchContext * GNUNET_FS_search_start (struct GNUNET_FS_Handle *h, const struct GNUNET_FS_Uri *uri, uint32_t anonymity, enum GNUNET_FS_SearchOptions options, void *cctx); /** * Pause search. * * @param sc context for the search that should be paused */ void GNUNET_FS_search_pause (struct GNUNET_FS_SearchContext *sc); /** * Continue paused search. * * @param sc context for the search that should be resumed */ void GNUNET_FS_search_continue (struct GNUNET_FS_SearchContext *sc); /** * Stop search for content. * * @param sc context for the search that should be stopped */ void GNUNET_FS_search_stop (struct GNUNET_FS_SearchContext *sc); /** * Options for downloading. Compatible options * can be OR'ed together. */ enum GNUNET_FS_DownloadOptions { /** * No options (use defaults for everything). */ GNUNET_FS_DOWNLOAD_OPTION_NONE = 0, /** * Only download from the local host, do not access remote systems (no P2P) */ GNUNET_FS_DOWNLOAD_OPTION_LOOPBACK_ONLY = 1, /** * Do a recursive download (that is, automatically trigger the * download of files in directories). */ GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE = 2, /** * Do not append temporary data to * the target file (for the IBlocks). */ GNUNET_FS_DOWNLOAD_NO_TEMPORARIES = 4, /** * Internal option used to flag this download as a 'probe' for a * search result. Impacts the priority with which the download is * run and causes signalling callbacks to be done differently. * Also, probe downloads are not serialized on suspension. Normal * clients should not use this! */ GNUNET_FS_DOWNLOAD_IS_PROBE = (1 << 31) }; /** * Download parts of a file. Note that this will store * the blocks at the respective offset in the given file. Also, the * download is still using the blocking of the underlying FS * encoding. As a result, the download may *write* outside of the * given boundaries (if offset and length do not match the 32k FS * block boundaries).

    * * The given range can be used to focus a download towards a * particular portion of the file (optimization), not to strictly * limit the download to exactly those bytes. * * @param h handle to the file sharing subsystem * @param uri the URI of the file (determines what to download); CHK or LOC URI * @param meta known metadata for the file (can be NULL) * @param filename where to store the file, maybe NULL (then no file is * created on disk and data must be grabbed from the callbacks) * @param tempname where to store temporary file data, not used if filename is non-NULL; * can be NULL (in which case we will pick a name if needed); the temporary file * may already exist, in which case we will try to use the data that is there and * if it is not what is desired, will overwrite it * @param offset at what offset should we start the download (typically 0) * @param length how many bytes should be downloaded starting at offset * @param anonymity anonymity level to use for the download * @param options various download options * @param cctx initial value for the client context for this download * @param parent parent download to associate this download with (use NULL * for top-level downloads; useful for manually-triggered recursive downloads) * @return context that can be used to control this download */ struct GNUNET_FS_DownloadContext * GNUNET_FS_download_start (struct GNUNET_FS_Handle *h, const struct GNUNET_FS_Uri *uri, const struct GNUNET_CONTAINER_MetaData *meta, const char *filename, const char *tempname, uint64_t offset, uint64_t length, uint32_t anonymity, enum GNUNET_FS_DownloadOptions options, void *cctx, struct GNUNET_FS_DownloadContext *parent); /** * Download parts of a file based on a search result. The download * will be associated with the search result (and the association * will be preserved when serializing/deserializing the state). * If the search is stopped, the download will not be aborted but * be 'promoted' to a stand-alone download. * * As with the other download function, this will store * the blocks at the respective offset in the given file. Also, the * download is still using the blocking of the underlying FS * encoding. As a result, the download may *write* outside of the * given boundaries (if offset and length do not match the 32k FS * block boundaries).

    * * The given range can be used to focus a download towards a * particular portion of the file (optimization), not to strictly * limit the download to exactly those bytes. * * @param h handle to the file sharing subsystem * @param sr the search result to use for the download (determines uri and * meta data and associations) * @param filename where to store the file, maybe NULL (then no file is * created on disk and data must be grabbed from the callbacks) * @param tempname where to store temporary file data, not used if filename is non-NULL; * can be NULL (in which case we will pick a name if needed); the temporary file * may already exist, in which case we will try to use the data that is there and * if it is not what is desired, will overwrite it * @param offset at what offset should we start the download (typically 0) * @param length how many bytes should be downloaded starting at offset * @param anonymity anonymity level to use for the download * @param options various download options * @param cctx initial value for the client context for this download * @return context that can be used to control this download */ struct GNUNET_FS_DownloadContext * GNUNET_FS_download_start_from_search (struct GNUNET_FS_Handle *h, struct GNUNET_FS_SearchResult *sr, const char *filename, const char *tempname, uint64_t offset, uint64_t length, uint32_t anonymity, enum GNUNET_FS_DownloadOptions options, void *cctx); /** * Stop a download (aborts if download is incomplete). * * @param dc handle for the download * @param do_delete delete files of incomplete downloads */ void GNUNET_FS_download_stop (struct GNUNET_FS_DownloadContext *dc, int do_delete); /* ******************** Directory API *********************** */ #define GNUNET_FS_DIRECTORY_MIME "application/gnunet-directory" #define GNUNET_FS_DIRECTORY_MAGIC "\211GND\r\n\032\n" #define GNUNET_FS_DIRECTORY_EXT ".gnd" /** * Does the meta-data claim that this is a directory? * Checks if the mime-type is that of a GNUnet directory. * * @return GNUNET_YES if it is, GNUNET_NO if it is not, GNUNET_SYSERR if * we have no mime-type information (treat as 'GNUNET_NO') */ int GNUNET_FS_meta_data_test_for_directory (const struct GNUNET_CONTAINER_MetaData *md); /** * Set the MIMETYPE information for the given * metadata to "application/gnunet-directory". * * @param md metadata to add mimetype to */ void GNUNET_FS_meta_data_make_directory (struct GNUNET_CONTAINER_MetaData *md); /** * Suggest a filename based on given metadata. * * @param md given meta data * @return NULL if meta data is useless for suggesting a filename */ char * GNUNET_FS_meta_data_suggest_filename (const struct GNUNET_CONTAINER_MetaData *md); /** * Function used to process entries in a directory. * * @param cls closure * @param filename name of the file in the directory * @param uri URI of the file * @param metadata metadata for the file; metadata for * the directory if everything else is NULL/zero * @param length length of the available data for the file * (of type size_t since data must certainly fit * into memory; if files are larger than size_t * permits, then they will certainly not be * embedded with the directory itself). * @param data data available for the file (length bytes) */ typedef void (*GNUNET_FS_DirectoryEntryProcessor) (void *cls, const char *filename, const struct GNUNET_FS_Uri * uri, const struct GNUNET_CONTAINER_MetaData * meta, size_t length, const void *data); /** * Iterate over all entries in a directory. Note that directories * are structured such that it is possible to iterate over the * individual blocks as well as over the entire directory. Thus * a client can call this function on the buffer in the * GNUNET_FS_ProgressCallback. Also, directories can optionally * include the contents of (small) files embedded in the directory * itself; for those files, the processor may be given the * contents of the file directly by this function. * * @param size number of bytes in data * @param data pointer to the beginning of the directory * @param offset offset of data in the directory * @param dep function to call on each entry * @param dep_cls closure for dep * @return GNUNET_OK if this could be a block in a directory, * GNUNET_NO if this could be part of a directory (but not 100% OK) * GNUNET_SYSERR if 'data' does not represent a directory */ int GNUNET_FS_directory_list_contents (size_t size, const void *data, uint64_t offset, GNUNET_FS_DirectoryEntryProcessor dep, void *dep_cls); /** * Opaque handle to a directory builder. */ struct GNUNET_FS_DirectoryBuilder; /** * Create a directory builder. * * @param mdir metadata for the directory */ struct GNUNET_FS_DirectoryBuilder * GNUNET_FS_directory_builder_create (const struct GNUNET_CONTAINER_MetaData *mdir); /** * Add an entry to a directory. * * @param bld directory to extend * @param uri uri of the entry (must not be a KSK) * @param md metadata of the entry * @param data raw data of the entry, can be NULL, otherwise * data must point to exactly the number of bytes specified * by the uri */ void GNUNET_FS_directory_builder_add (struct GNUNET_FS_DirectoryBuilder *bld, const struct GNUNET_FS_Uri *uri, const struct GNUNET_CONTAINER_MetaData *md, const void *data); /** * Finish building the directory. Frees the * builder context and returns the directory * in-memory. * * @param bld directory to finish * @param rsize set to the number of bytes needed * @param rdata set to the encoded directory * @return GNUNET_OK on success */ int GNUNET_FS_directory_builder_finish (struct GNUNET_FS_DirectoryBuilder *bld, size_t * rsize, void **rdata); /* ******************** DirScanner API *********************** */ /** * Progress reasons of the directory scanner. */ enum GNUNET_FS_DirScannerProgressUpdateReason { /** * We've started processing a file or directory. */ GNUNET_FS_DIRSCANNER_FILE_START = 0, /** * We're having trouble accessing a file (soft-error); it will * be ignored. */ GNUNET_FS_DIRSCANNER_FILE_IGNORED, /** * We've found all files (in the pre-pass). */ GNUNET_FS_DIRSCANNER_ALL_COUNTED, /** * We've finished extracting meta data from a file. */ GNUNET_FS_DIRSCANNER_EXTRACT_FINISHED, /** * Last call to the progress function: we have finished scanning * the directory. */ GNUNET_FS_DIRSCANNER_FINISHED, /** * There was an internal error. Application should abort the scan. */ GNUNET_FS_DIRSCANNER_INTERNAL_ERROR }; /** * Function called over time as the directory scanner makes * progress on the job at hand. * * @param cls closure * @param filename which file we are making progress on * @param is_directory GNUNET_YES if this is a directory, * GNUNET_NO if this is a file * GNUNET_SYSERR if it is neither (or unknown) * @param reason kind of progress we are making */ typedef void (*GNUNET_FS_DirScannerProgressCallback) (void *cls, const char *filename, int is_directory, enum GNUNET_FS_DirScannerProgressUpdateReason reason); /** * A node of a directory tree (produced by dirscanner) */ struct GNUNET_FS_ShareTreeItem { /** * This is a doubly-linked list */ struct GNUNET_FS_ShareTreeItem *prev; /** * This is a doubly-linked list */ struct GNUNET_FS_ShareTreeItem *next; /** * This is a doubly-linked tree * NULL for top-level entries. */ struct GNUNET_FS_ShareTreeItem *parent; /** * This is a doubly-linked tree * NULL for files and empty directories */ struct GNUNET_FS_ShareTreeItem *children_head; /** * This is a doubly-linked tree * NULL for files and empty directories */ struct GNUNET_FS_ShareTreeItem *children_tail; /** * Metadata for this file or directory */ struct GNUNET_CONTAINER_MetaData *meta; /** * Keywords for this file or directory (derived from metadata). */ struct GNUNET_FS_Uri *ksk_uri; /** * Name of the file/directory */ char *filename; /** * Base name of the file/directory. */ char *short_filename; /** * GNUNET_YES if this is a directory */ int is_directory; }; /** * Opaqe handle to an asynchronous directory scanning activity. */ struct GNUNET_FS_DirScanner; /** * Start a directory scanner. * * @param filename name of the directory to scan * @param disable_extractor GNUNET_YES to not to run libextractor on files (only build a tree) * @param ex if not NULL, must be a list of extra plugins for extractor * @param cb the callback to call when there are scanning progress messages * @param cb_cls closure for 'cb' * @return directory scanner object to be used for controlling the scanner */ struct GNUNET_FS_DirScanner * GNUNET_FS_directory_scan_start (const char *filename, int disable_extractor, const char *ex, GNUNET_FS_DirScannerProgressCallback cb, void *cb_cls); /** * Abort the scan. Must not be called from within the progress_callback * function. * * @param ds directory scanner structure */ void GNUNET_FS_directory_scan_abort (struct GNUNET_FS_DirScanner *ds); /** * Obtain the result of the scan after the scan has signalled * completion. Must not be called prior to completion. The 'ds' is * freed as part of this call. * * @param ds directory scanner structure * @return the results of the scan (a directory tree) */ struct GNUNET_FS_ShareTreeItem * GNUNET_FS_directory_scan_get_result (struct GNUNET_FS_DirScanner *ds); /** * Process a share item tree, moving frequent keywords up and * copying frequent metadata up. * * @param toplevel toplevel directory in the tree, returned by the scanner */ void GNUNET_FS_share_tree_trim (struct GNUNET_FS_ShareTreeItem *toplevel); /** * Release memory of a share item tree. * * @param toplevel toplevel of the tree to be freed */ void GNUNET_FS_share_tree_free (struct GNUNET_FS_ShareTreeItem *toplevel); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif #endif gnunet-0.9.3/src/include/gnunet_dv_service.h0000644000175000017500000000510411760502551016042 00000000000000/* This file is part of GNUnet (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_dv_service.h * @brief API to deal with dv service * * @author Christian Grothoff * @author Nathan Evans */ #ifndef GNUNET_DV_SERVICE_H #define GNUNET_DV_SERVICE_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_common.h" #include "gnunet_configuration_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_transport_plugin.h" /** * Version of the dv API. */ #define GNUNET_DV_VERSION 0x00000000 /** * Opaque handle for the dv service. */ struct GNUNET_DV_Handle; /** * Send a message from the plugin to the DV service indicating that * a message should be sent via DV to some peer. * * @param dv_handle the handle to the DV api * @param target the final target of the message * @param msgbuf the msg(s) to send * @param msgbuf_size the size of msgbuf * @param priority priority to pass on to core when sending the message * @param timeout how long can this message be delayed (pass through to core) * @param addr the address of this peer (internally known to DV) * @param addrlen the length of the peer address * @param cont continuation to call once the message has been sent (or failed) * @param cont_cls closure for continuation * */ int GNUNET_DV_send (struct GNUNET_DV_Handle *dv_handle, const struct GNUNET_PeerIdentity *target, const char *msgbuf, size_t msgbuf_size, unsigned int priority, struct GNUNET_TIME_Relative timeout, const void *addr, size_t addrlen, GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif #endif gnunet-0.9.3/src/include/gnunet_transport_service.h0000644000175000017500000003447711760502551017504 00000000000000/* This file is part of GNUnet. (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_transport_service.h * @brief low-level P2P IO * @author Christian Grothoff */ #ifndef GNUNET_TRANSPORT_SERVICE_H #define GNUNET_TRANSPORT_SERVICE_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_util_lib.h" #include "gnunet_ats_service.h" /** * Version number of the transport API. */ #define GNUNET_TRANSPORT_VERSION 0x00000000 /** * Function called by the transport for each received message. * * @param cls closure * @param peer (claimed) identity of the other peer * @param message the message * @param ats performance data * @param ats_count number of entries in ats */ typedef void (*GNUNET_TRANSPORT_ReceiveCallback) (void *cls, const struct GNUNET_PeerIdentity * peer, const struct GNUNET_MessageHeader * message, const struct GNUNET_ATS_Information * ats, uint32_t ats_count); /** * Opaque handle to the service. */ struct GNUNET_TRANSPORT_Handle; /** * Function called to notify transport users that another * peer connected to us. * * @param cls closure * @param peer the peer that connected * @param ats performance data * @param ats_count number of entries in ats (excluding 0-termination) */ typedef void (*GNUNET_TRANSPORT_NotifyConnect) (void *cls, const struct GNUNET_PeerIdentity * peer, const struct GNUNET_ATS_Information * ats, uint32_t ats_count); /** * Function called to notify transport users that another * peer disconnected from us. * * @param cls closure * @param peer the peer that disconnected */ typedef void (*GNUNET_TRANSPORT_NotifyDisconnect) (void *cls, const struct GNUNET_PeerIdentity * peer); /** * Function to call with a textual representation of an address. * This function will be called several times with different possible * textual representations, and a last time with NULL to signal the end * of the iteration. * * @param cls closure * @param address NULL on error or end of iteration, * otherwise 0-terminated printable UTF-8 string */ typedef void (*GNUNET_TRANSPORT_AddressToStringCallback) (void *cls, const char *address); /** * Function to call with a binary format of an address * * @param cls closure * @param peer peer this update is about (never NULL) * @param address address, NULL for disconnect notification in monitor mode */ typedef void (*GNUNET_TRANSPORT_PeerIterateCallback) (void *cls, const struct GNUNET_PeerIdentity * peer, const struct GNUNET_HELLO_Address * address); /** * Connect to the transport service. Note that the connection may * complete (or fail) asynchronously. * * @param cfg configuration to use * @param self our own identity (API should check that it matches * the identity found by transport), or NULL (no check) * @param cls closure for the callbacks * @param rec receive function to call * @param nc function to call on connect events * @param nd function to call on disconnect events * @return NULL on error */ struct GNUNET_TRANSPORT_Handle * GNUNET_TRANSPORT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, const struct GNUNET_PeerIdentity *self, void *cls, GNUNET_TRANSPORT_ReceiveCallback rec, GNUNET_TRANSPORT_NotifyConnect nc, GNUNET_TRANSPORT_NotifyDisconnect nd); /** * Disconnect from the transport service. * * @param handle handle returned from connect */ void GNUNET_TRANSPORT_disconnect (struct GNUNET_TRANSPORT_Handle *handle); /** * Ask the transport service to establish a connection to * the given peer. * * @param handle connection to transport service * @param target who we should try to connect to */ void GNUNET_TRANSPORT_try_connect (struct GNUNET_TRANSPORT_Handle *handle, const struct GNUNET_PeerIdentity *target); /** * Opaque handle for a transmission-ready request. */ struct GNUNET_TRANSPORT_TransmitHandle; /** * Check if we could queue a message of the given size for * transmission. The transport service will take both its internal * buffers and bandwidth limits imposed by the other peer into * consideration when answering this query. * * @param handle connection to transport service * @param target who should receive the message * @param size how big is the message we want to transmit? * @param priority how important is the message? @deprecated - remove? * @param timeout after how long should we give up (and call * notify with buf NULL and size 0)? * @param notify function to call when we are ready to * send such a message * @param notify_cls closure for notify * @return NULL if someone else is already waiting to be notified * non-NULL if the notify callback was queued (can be used to cancel * using GNUNET_TRANSPORT_notify_transmit_ready_cancel) */ struct GNUNET_TRANSPORT_TransmitHandle * GNUNET_TRANSPORT_notify_transmit_ready (struct GNUNET_TRANSPORT_Handle *handle, const struct GNUNET_PeerIdentity *target, size_t size, uint32_t priority, struct GNUNET_TIME_Relative timeout, GNUNET_CONNECTION_TransmitReadyNotify notify, void *notify_cls); /** * Cancel the specified transmission-ready notification. * * @param th handle of the transmission notification request to cancel */ void GNUNET_TRANSPORT_notify_transmit_ready_cancel (struct GNUNET_TRANSPORT_TransmitHandle *th); /** * Function called whenever there is an update to the * HELLO of this peer. * * @param cls closure * @param hello our updated HELLO */ typedef void (*GNUNET_TRANSPORT_HelloUpdateCallback) (void *cls, const struct GNUNET_MessageHeader * hello); /** * Handle to cancel a 'GNUNET_TRANSPORT_get_hello' operation. */ struct GNUNET_TRANSPORT_GetHelloHandle; /** * Obtain updates on changes to the HELLO message for this peer. * * @param handle connection to transport service * @param rec function to call with the HELLO * @param rec_cls closure for rec * @return handle to cancel the operation */ struct GNUNET_TRANSPORT_GetHelloHandle * GNUNET_TRANSPORT_get_hello (struct GNUNET_TRANSPORT_Handle *handle, GNUNET_TRANSPORT_HelloUpdateCallback rec, void *rec_cls); /** * Stop receiving updates about changes to our HELLO message. * * @param ghh handle returned from 'GNUNET_TRANSPORT_get_hello') */ void GNUNET_TRANSPORT_get_hello_cancel (struct GNUNET_TRANSPORT_GetHelloHandle *ghh); /** * Offer the transport service the HELLO of another peer. Note that * the transport service may just ignore this message if the HELLO is * malformed or useless due to our local configuration. * * @param handle connection to transport service * @param hello the hello message * @param cont continuation to call when HELLO has been sent * @param cls closure for continuation */ void GNUNET_TRANSPORT_offer_hello (struct GNUNET_TRANSPORT_Handle *handle, const struct GNUNET_MessageHeader *hello, GNUNET_SCHEDULER_Task cont, void *cls); /** * Handle to cancel a pending address lookup. */ struct GNUNET_TRANSPORT_AddressToStringContext; /** * Convert a binary address into a human readable address. * * @param cfg configuration to use * @param address address to convert (binary format) * @param numeric should (IP) addresses be displayed in numeric form * (otherwise do reverse DNS lookup) * @param timeout how long is the lookup allowed to take at most * @param aluc function to call with the results * @param aluc_cls closure for aluc * @return handle to cancel the operation, NULL on error */ struct GNUNET_TRANSPORT_AddressToStringContext * GNUNET_TRANSPORT_address_to_string (const struct GNUNET_CONFIGURATION_Handle *cfg, const struct GNUNET_HELLO_Address *address, int numeric, struct GNUNET_TIME_Relative timeout, GNUNET_TRANSPORT_AddressToStringCallback aluc, void *aluc_cls); /** * Cancel request for address conversion. * * @param alc handle for the request to cancel */ void GNUNET_TRANSPORT_address_to_string_cancel (struct GNUNET_TRANSPORT_AddressToStringContext *alc); /** * Return all the known addresses for a specific peer or all peers. * Returns continously all address if one_shot is set to GNUNET_NO * * CHANGE: Returns the address(es) that we are currently using for this * peer. Upon completion, the 'AddressLookUpCallback' is called one more * time with 'NULL' for the address and the peer. After this, the operation must no * longer be explicitly cancelled. * * @param cfg configuration to use * @param peer peer identity to look up the addresses of, CHANGE: allow NULL for all (connected) peers * @param one_shot GNUNET_YES to return the current state and then end (with NULL+NULL), * GNUNET_NO to monitor the set of addresses used (continuously, must be explicitly canceled, NOT implemented yet!) * @param timeout how long is the lookup allowed to take at most * @param peer_address_callback function to call with the results * @param peer_address_callback_cls closure for peer_address_callback */ struct GNUNET_TRANSPORT_PeerIterateContext * GNUNET_TRANSPORT_peer_get_active_addresses (const struct GNUNET_CONFIGURATION_Handle *cfg, const struct GNUNET_PeerIdentity *peer, int one_shot, struct GNUNET_TIME_Relative timeout, GNUNET_TRANSPORT_PeerIterateCallback peer_address_callback, void *peer_address_callback_cls); /** * Cancel request for peer lookup. * * @param alc handle for the request to cancel */ void GNUNET_TRANSPORT_peer_get_active_addresses_cancel (struct GNUNET_TRANSPORT_PeerIterateContext *alc); /** * Handle for blacklisting peers. */ struct GNUNET_TRANSPORT_Blacklist; /** * Function that decides if a connection is acceptable or not. * * @param cls closure * @param pid peer to approve or disapproave * @return GNUNET_OK if the connection is allowed, GNUNET_SYSERR if not */ typedef int (*GNUNET_TRANSPORT_BlacklistCallback) (void *cls, const struct GNUNET_PeerIdentity * pid); /** * Install a blacklist callback. The service will be queried for all * existing connections as well as any fresh connections to check if * they are permitted. If the blacklisting callback is unregistered, * all hosts that were denied in the past will automatically be * whitelisted again. Cancelling the blacklist handle is also the * only way to re-enable connections from peers that were previously * blacklisted. * * @param cfg configuration to use * @param cb callback to invoke to check if connections are allowed * @param cb_cls closure for cb * @return NULL on error, otherwise handle for cancellation */ struct GNUNET_TRANSPORT_Blacklist * GNUNET_TRANSPORT_blacklist (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_TRANSPORT_BlacklistCallback cb, void *cb_cls); /** * Abort the blacklist. Note that this function is the only way for * removing a peer from the blacklist. * * @param br handle of the request that is to be cancelled */ void GNUNET_TRANSPORT_blacklist_cancel (struct GNUNET_TRANSPORT_Blacklist *br); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_TRANSPORT_SERVICE_H */ #endif /* end of gnunet_transport_service.h */ gnunet-0.9.3/src/include/block_dns.h0000644000175000017500000000441011760502551014266 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/block_dns.h * @author Philipp Toelke */ #ifndef _GNVPN_BLOCKDNS_H_ #define _GNVPN_BLOCKDNS_H_ #include "gnunet_common.h" #include "gnunet_crypto_lib.h" /** * Bitmask describing what IP-protocols are supported by the service */ enum GNUNET_DNS_ServiceTypes { GNUNET_DNS_SERVICE_TYPE_UDP = 1, GNUNET_DNS_SERVICE_TYPE_TCP = 2 }; GNUNET_NETWORK_STRUCT_BEGIN /** * This is the structure describing an dns-record such as www.gnunet. */ struct GNUNET_DNS_Record { /** * Signature of the peer affirming that he is offering the service. */ struct GNUNET_CRYPTO_RsaSignature signature; /** * Beginning of signed portion of the record, signs everything until * the end of the struct. */ struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; /** * The peer providing this service */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded peer; /** * The descriptor for the service * (a peer may provide more than one service) */ GNUNET_HashCode service_descriptor; /** * When does this record expire? */ struct GNUNET_TIME_AbsoluteNBO expiration_time; /** * Four TCP and UDP-Ports that are used by this service, big endian format */ uint64_t ports GNUNET_PACKED; /** * What connection-types (UDP, TCP, ...) are supported by the service. * Contains an 'enum GNUNET_DNS_ServiceTypes' in big endian format. */ uint32_t service_type GNUNET_PACKED; }; GNUNET_NETWORK_STRUCT_END #endif gnunet-0.9.3/src/include/gnunet_namestore_plugin.h0000644000175000017500000001345511760502551017274 00000000000000/* This file is part of GNUnet (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_namestore_plugin.h * @brief plugin API for the namestore database backend * @author Christian Grothoff */ #ifndef GNUNET_NAMESTORE_PLUGIN_H #define GNUNET_NAMESTORE_PLUGIN_H #include "gnunet_common.h" #include "gnunet_util_lib.h" #include "gnunet_namestore_service.h" #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * Function called by for each matching record. * * @param cls closure * @param zone_key public key of the zone * @param expire when does the corresponding block in the DHT expire (until * when should we never do a DHT lookup for the same name again)? * @param name name that is being mapped (at most 255 characters long) * @param rd_count number of entries in 'rd' array * @param rd array of records with data to store * @param signature signature of the record block, NULL if signature is unavailable (i.e. * because the user queried for a particular record type only) */ typedef void (*GNUNET_NAMESTORE_RecordIterator) (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *name, unsigned int rd_len, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature); /** * @brief struct returned by the initialization function of the plugin */ struct GNUNET_NAMESTORE_PluginFunctions { /** * Closure to pass to all plugin functions. */ void *cls; /** * Store a record in the datastore. Removes any existing record in the * same zone with the same name. * * @param cls closure (internal context for the plugin) * @param zone_key public key of the zone * @param expire when does the corresponding block in the DHT expire (until * when should we never do a DHT lookup for the same name again)? * @param name name that is being mapped (at most 255 characters long) * @param rd_count number of entries in 'rd' array * @param rd array of records with data to store * @param signature signature of the record block, NULL if signature is unavailable (i.e. * because the user queried for a particular record type only) * @return GNUNET_OK on success, else GNUNET_SYSERR */ int (*put_records) (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, struct GNUNET_TIME_Absolute expire, const char *name, unsigned int rd_len, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature); /** * Removes any existing record in the given zone with the same name. * * @param cls closure (internal context for the plugin) * @param zone hash of the public key of the zone * @param name name to remove (at most 255 characters long) * @return GNUNET_OK on success */ int (*remove_records) (void *cls, const struct GNUNET_CRYPTO_ShortHashCode *zone, const char *name); /** * Iterate over the results for a particular key and zone in the * datastore. Will return at most one result to the iterator. * * @param cls closure (internal context for the plugin) * @param zone hash of public key of the zone, NULL to iterate over all zones * @param name name as '\0' terminated string, NULL to iterate over all records of the zone * @param offset offset in the list of all matching records * @param iter function to call with the result * @param iter_cls closure for iter * @return GNUNET_OK on success, GNUNET_NO if there were no results, GNUNET_SYSERR on error */ int (*iterate_records) (void *cls, const struct GNUNET_CRYPTO_ShortHashCode *zone, const char *name, uint64_t offset, GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls); /** * Look for an existing PKEY delegation record for a given public key. * Returns at most one result to the iterator. * * @param cls closure (internal context for the plugin) * @param zone hash of public key of the zone to look up in, never NULL * @param value_zone hash of the public key of the target zone (value), never NULL * @param iter function to call with the result * @param iter_cls closure for iter * @return GNUNET_OK on success, GNUNET_NO if there were no results, GNUNET_SYSERR on error */ int (*zone_to_name) (void *cls, const struct GNUNET_CRYPTO_ShortHashCode *zone, const struct GNUNET_CRYPTO_ShortHashCode *value_zone, GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls); /** * Delete an entire zone (all records). Not used in normal operation. * * @param cls closure (internal context for the plugin) * @param zone zone to delete */ void (*delete_zone) (void *cls, const struct GNUNET_CRYPTO_ShortHashCode *zone); }; #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* end of gnunet_namestore_plugin.h */ #endif gnunet-0.9.3/src/include/plibc.h0000644000175000017500000007416711762422575013452 00000000000000/* This file is part of PlibC. (C) 2005, 2006, 2007, 2008, 2009, 2010 Nils Durner (and other contributing authors) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /** * @file include/plibc.h * @brief PlibC header * @attention This file is usually not installed under Unix, * so ship it with your application * @version $Revision: 84 $ */ #ifndef _PLIBC_H_ #define _PLIBC_H_ #ifndef SIGALRM #define SIGALRM 14 #endif #ifdef __cplusplus extern "C" { #endif #include #ifdef Q_OS_WIN32 #define WINDOWS 1 #endif #define HAVE_PLIBC_FD 0 #ifdef WINDOWS #if ENABLE_NLS #include "langinfo.h" #endif #include #include #include #include #include #include #include #include #include #include #define __BYTE_ORDER BYTE_ORDER #define __BIG_ENDIAN BIG_ENDIAN /* Conflicts with our definitions */ #define __G_WIN32_H__ /* Convert LARGE_INTEGER to double */ #define Li2Double(x) ((double)((x).HighPart) * 4.294967296E9 + \ (double)((x).LowPart)) #ifndef __MINGW64__ struct stat64 { _dev_t st_dev; _ino_t st_ino; _mode_t st_mode; short st_nlink; short st_uid; short st_gid; _dev_t st_rdev; __int64 st_size; __time64_t st_atime; __time64_t st_mtime; __time64_t st_ctime; }; #endif typedef unsigned int sa_family_t; struct sockaddr_un { short sun_family; /*AF_UNIX*/ char sun_path[108]; /*path name */ }; #ifndef pid_t #define pid_t DWORD #endif #ifndef error_t #define error_t int #endif #ifndef WEXITSTATUS #define WEXITSTATUS(status) (((status) & 0xff00) >> 8) #endif #ifndef MSG_DONTWAIT #define MSG_DONTWAIT 0 #endif enum { _SC_PAGESIZE = 30, _SC_PAGE_SIZE = 30 }; /* Thanks to the Cygwin project */ #define ENOCSI 43 /* No CSI structure available */ #define EL2HLT 44 /* Level 2 halted */ #ifndef EDEADLK #define EDEADLK 45 /* Deadlock condition */ #endif #ifndef ENOLCK #define ENOLCK 46 /* No record locks available */ #endif #define EBADE 50 /* Invalid exchange */ #define EBADR 51 /* Invalid request descriptor */ #define EXFULL 52 /* Exchange full */ #define ENOANO 53 /* No anode */ #define EBADRQC 54 /* Invalid request code */ #define EBADSLT 55 /* Invalid slot */ #ifndef EDEADLOCK #define EDEADLOCK EDEADLK /* File locking deadlock error */ #endif #define EBFONT 57 /* Bad font file fmt */ #define ENOSTR 60 /* Device not a stream */ #define ENODATA 61 /* No data (for no delay io) */ #define ETIME 62 /* Timer expired */ #define ENOSR 63 /* Out of streams resources */ #define ENONET 64 /* Machine is not on the network */ #define ENOPKG 65 /* Package not installed */ #define EREMOTE 66 /* The object is remote */ #define ENOLINK 67 /* The link has been severed */ #define EADV 68 /* Advertise error */ #define ESRMNT 69 /* Srmount error */ #define ECOMM 70 /* Communication error on send */ #define EPROTO 71 /* Protocol error */ #define EMULTIHOP 74 /* Multihop attempted */ #define ELBIN 75 /* Inode is remote (not really error) */ #define EDOTDOT 76 /* Cross mount point (not really error) */ #define EBADMSG 77 /* Trying to read unreadable message */ #define ENOTUNIQ 80 /* Given log. name not unique */ #define EBADFD 81 /* f.d. invalid for this operation */ #define EREMCHG 82 /* Remote address changed */ #define ELIBACC 83 /* Can't access a needed shared lib */ #define ELIBBAD 84 /* Accessing a corrupted shared lib */ #define ELIBSCN 85 /* .lib section in a.out corrupted */ #define ELIBMAX 86 /* Attempting to link in too many libs */ #define ELIBEXEC 87 /* Attempting to exec a shared library */ #ifndef ENOSYS #define ENOSYS 88 /* Function not implemented */ #endif #define ENMFILE 89 /* No more files */ #ifndef ENOTEMPTY #define ENOTEMPTY 90 /* Directory not empty */ #endif #ifndef ENAMETOOLONG #define ENAMETOOLONG 91 /* File or path name too long */ #endif #define ELOOP 92 /* Too many symbolic links */ #define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ #define EPFNOSUPPORT 96 /* Protocol family not supported */ #define ECONNRESET 104 /* Connection reset by peer */ #define ENOBUFS 105 /* No buffer space available */ #define EAFNOSUPPORT 106 /* Address family not supported by protocol family */ #define EPROTOTYPE 107 /* Protocol wrong type for socket */ #define ENOTSOCK 108 /* Socket operation on non-socket */ #define ENOPROTOOPT 109 /* Protocol not available */ #define ESHUTDOWN 110 /* Can't send after socket shutdown */ #define ECONNREFUSED 111 /* Connection refused */ #define EADDRINUSE 112 /* Address already in use */ #define ECONNABORTED 113 /* Connection aborted */ #define ENETUNREACH 114 /* Network is unreachable */ #define ENETDOWN 115 /* Network interface is not configured */ #ifndef ETIMEDOUT #define ETIMEDOUT 116 /* Connection timed out */ #endif #define EHOSTDOWN 117 /* Host is down */ #define EHOSTUNREACH 118 /* Host is unreachable */ #define EINPROGRESS 119 /* Connection already in progress */ #define EALREADY 120 /* Socket already connected */ #define EDESTADDRREQ 121 /* Destination address required */ #define EMSGSIZE 122 /* Message too long */ #define EPROTONOSUPPORT 123 /* Unknown protocol */ #define ESOCKTNOSUPPORT 124 /* Socket type not supported */ #define EADDRNOTAVAIL 125 /* Address not available */ #define ENETRESET 126 /* Connection aborted by network */ #define EISCONN 127 /* Socket is already connected */ #define ENOTCONN 128 /* Socket is not connected */ #define ETOOMANYREFS 129 /* Too many references: cannot splice */ #define EPROCLIM 130 /* Too many processes */ #define EUSERS 131 /* Too many users */ #define EDQUOT 132 /* Disk quota exceeded */ #define ESTALE 133 /* Unknown error */ #ifndef ENOTSUP #define ENOTSUP 134 /* Not supported */ #endif #define ENOMEDIUM 135 /* No medium (in tape drive) */ #define ENOSHARE 136 /* No such host or network path */ #define ECASECLASH 137 /* Filename exists with different case */ #define EWOULDBLOCK EAGAIN /* Operation would block */ #define EOVERFLOW 139 /* Value too large for defined data type */ #undef HOST_NOT_FOUND #define HOST_NOT_FOUND 1 #undef TRY_AGAIN #define TRY_AGAIN 2 #undef NO_RECOVERY #define NO_RECOVERY 3 #undef NO_ADDRESS #define NO_ADDRESS 4 #define PROT_READ 0x1 #define PROT_WRITE 0x2 #define MAP_SHARED 0x1 #define MAP_PRIVATE 0x2 /* unsupported */ #define MAP_FIXED 0x10 #define MAP_ANONYMOUS 0x20 /* unsupported */ #define MAP_FAILED ((void *)-1) #define MS_ASYNC 1 /* sync memory asynchronously */ #define MS_INVALIDATE 2 /* invalidate the caches */ #define MS_SYNC 4 /* synchronous memory sync */ struct statfs { long f_type; /* type of filesystem (see below) */ long f_bsize; /* optimal transfer block size */ long f_blocks; /* total data blocks in file system */ long f_bfree; /* free blocks in fs */ long f_bavail; /* free blocks avail to non-superuser */ long f_files; /* total file nodes in file system */ long f_ffree; /* free file nodes in fs */ long f_fsid; /* file system id */ long f_namelen; /* maximum length of filenames */ long f_spare[6]; /* spare for later */ }; extern const struct in6_addr in6addr_any; /* :: */ extern const struct in6_addr in6addr_loopback; /* ::1 */ /* Taken from the Wine project /wine/include/winternl.h */ enum SYSTEM_INFORMATION_CLASS { SystemBasicInformation = 0, Unknown1, SystemPerformanceInformation = 2, SystemTimeOfDayInformation = 3, /* was SystemTimeInformation */ Unknown4, SystemProcessInformation = 5, Unknown6, Unknown7, SystemProcessorPerformanceInformation = 8, Unknown9, Unknown10, SystemDriverInformation, Unknown12, Unknown13, Unknown14, Unknown15, SystemHandleList, Unknown17, Unknown18, Unknown19, Unknown20, SystemCacheInformation, Unknown22, SystemInterruptInformation = 23, SystemExceptionInformation = 33, SystemRegistryQuotaInformation = 37, SystemLookasideInformation = 45 }; typedef struct { LARGE_INTEGER IdleTime; LARGE_INTEGER KernelTime; LARGE_INTEGER UserTime; LARGE_INTEGER Reserved1[2]; ULONG Reserved2; } SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; #define sleep(secs) (Sleep(secs * 1000)) /*********************** statfs *****************************/ /* fake block size */ #define FAKED_BLOCK_SIZE 512 /* linux-compatible values for fs type */ #define MSDOS_SUPER_MAGIC 0x4d44 #define NTFS_SUPER_MAGIC 0x5346544E /*********************** End of statfs ***********************/ #define SHUT_RDWR SD_BOTH /* Operations for flock() */ #define LOCK_SH 1 /* shared lock */ #define LOCK_EX 2 /* exclusive lock */ #define LOCK_NB 4 /* or'd with one of the above to prevent blocking */ #define LOCK_UN 8 /* remove lock */ /* Not supported under MinGW */ #define S_IRGRP 0 #define S_IWGRP 0 #define S_IROTH 0 #define S_IXGRP 0 #define S_IWOTH 0 #define S_IXOTH 0 #define S_ISUID 0 #define S_ISGID 0 #define S_ISVTX 0 #define S_IRWXG 0 #define S_IRWXO 0 #define SHUT_WR SD_SEND #define SHUT_RD SD_RECEIVE #define SHUT_RDWR SD_BOTH #define SIGKILL 9 #define SIGTERM 15 #define SetErrnoFromWinError(e) _SetErrnoFromWinError(e, __FILE__, __LINE__) BOOL _plibc_CreateShortcut(const char *pszSrc, const char *pszDest); BOOL _plibc_CreateShortcutW(const wchar_t *pwszSrc, const wchar_t *pwszDest); BOOL _plibc_DereferenceShortcut(char *pszShortcut); BOOL _plibc_DereferenceShortcutW(wchar_t *pwszShortcut); char *plibc_ChooseDir(char *pszTitle, unsigned long ulFlags); wchar_t *plibc_ChooseDirW(wchar_t *pwszTitle, unsigned long ulFlags); char *plibc_ChooseFile(char *pszTitle, unsigned long ulFlags); wchar_t *plibc_ChooseFileW(wchar_t *pwszTitle, unsigned long ulFlags); long QueryRegistry(HKEY hMainKey, const char *pszKey, const char *pszSubKey, char *pszBuffer, long *pdLength); long QueryRegistryW(HKEY hMainKey, const wchar_t *pszKey, const wchar_t *pszSubKey, wchar_t *pszBuffer, long *pdLength); BOOL __win_IsHandleMarkedAsBlocking(int hHandle); void __win_SetHandleBlockingMode(int s, BOOL bBlocking); void __win_DiscardHandleBlockingMode(int s); int _win_isSocketValid(int s); int plibc_conv_to_win_path(const char *pszUnix, char *pszWindows); int plibc_conv_to_win_pathw(const wchar_t *pszUnix, wchar_t *pwszWindows); int plibc_conv_to_win_pathwconv(const char *pszUnix, wchar_t *pwszWindows); int plibc_conv_to_win_pathwconv_ex(const char *pszUnix, wchar_t *pszWindows, int derefLinks); unsigned plibc_get_handle_count(); typedef void (*TPanicProc) (int, char *); void plibc_set_panic_proc(TPanicProc proc); int flock(int fd, int operation); int fsync(int fildes); int inet_pton(int af, const char *src, void *dst); int inet_pton4(const char *src, u_char *dst, int pton); #if USE_IPV6 int inet_pton6(const char *src, u_char *dst); #endif int truncate(const char *fname, int distance); int statfs(const char *path, struct statfs *buf); const char *hstrerror(int err); int mkstemp(char *tmplate); char *strptime (const char *buf, const char *format, struct tm *tm); const char *inet_ntop(int af, const void *src, char *dst, size_t size); struct tm *gmtime_r(const time_t *clock, struct tm *result); int plibc_init(char *pszOrg, char *pszApp); int plibc_init_utf8(char *pszOrg, char *pszApp, int utf8_mode); void plibc_shutdown(); int plibc_initialized(); void _SetErrnoFromWinError(long lWinError, char *pszCaller, int iLine); void SetErrnoFromWinsockError(long lWinError); void SetHErrnoFromWinError(long lWinError); void SetErrnoFromHRESULT(HRESULT hRes); int GetErrnoFromWinsockError(long lWinError); FILE *_win_fopen(const char *filename, const char *mode); int _win_fclose(FILE *); DIR *_win_opendir(const char *dirname); struct dirent *_win_readdir(DIR *dirp); int _win_closedir(DIR *dirp); int _win_open(const char *filename, int oflag, ...); #ifdef ENABLE_NLS char *_win_bindtextdomain(const char *domainname, const char *dirname); #endif int _win_chdir(const char *path); int _win_close(int fd); int _win_creat(const char *path, mode_t mode); char *_win_ctime(const time_t *clock); char *_win_ctime_r(const time_t *clock, char *buf); int _win_fstat(int handle, struct stat *buffer); int _win_ftruncate(int fildes, off_t length); void _win_gettimeofday(struct timeval *tp, void *tzp); int _win_kill(pid_t pid, int sig); int _win_pipe(int *phandles); int _win_rmdir(const char *path); int _win_access( const char *path, int mode ); int _win_chmod(const char *filename, int pmode); char *realpath(const char *file_name, char *resolved_name); long _win_random(void); void _win_srandom(unsigned int seed); int _win_remove(const char *path); int _win_rename(const char *oldname, const char *newname); int _win_stat(const char *path, struct stat *buffer); int _win_stat64(const char *path, struct stat64 *buffer); long _win_sysconf(int name); int _win_unlink(const char *filename); int _win_write(int fildes, const void *buf, size_t nbyte); int _win_read(int fildes, void *buf, size_t nbyte); size_t _win_fwrite(const void *buffer, size_t size, size_t count, FILE *stream); size_t _win_fread( void *buffer, size_t size, size_t count, FILE *stream ); int _win_symlink(const char *path1, const char *path2); void *_win_mmap(void *start, size_t len, int access, int flags, int fd, unsigned long long offset); int _win_msync(void *start, size_t length, int flags); int _win_munmap(void *start, size_t length); int _win_lstat(const char *path, struct stat *buf); int _win_lstat64(const char *path, struct stat64 *buf); int _win_readlink(const char *path, char *buf, size_t bufsize); int _win_accept(int s, struct sockaddr *addr, int *addrlen); int _win_printf(const char *format,...); int _win_wprintf(const wchar_t *format, ...); int _win_fprintf(FILE *f,const char *format,...); int _win_fwprintf(FILE *f,const wchar_t *format, ...); int _win_vprintf(const char *format, va_list ap); int _win_vfwprintf(FILE *stream, const wchar_t *format, va_list arg_ptr); int _win_vfprintf(FILE *stream, const char *format, va_list arg_ptr); int _win_vwprintf(const wchar_t *format, va_list ap); int _win_vsprintf(char *dest,const char *format, va_list arg_ptr); int _win_vswprintf(wchar_t *dest, const wchar_t *format, va_list arg_ptr); int _win_vsnprintf(char* str, size_t size, const char *format, va_list arg_ptr); int _win_vsnwprintf(wchar_t* wstr, size_t size, const wchar_t *format, va_list arg_ptr); int _win_snprintf(char *str,size_t size,const char *format,...); int _win_snwprintf(wchar_t *str, size_t size, const wchar_t *format, ...); int _win_sprintf(char *dest,const char *format,...); int _win_swprintf(wchar_t *dest, const wchar_t *format, ...); int _win_vsscanf(const char* str, const char* format, va_list arg_ptr); int _win_vswscanf(const wchar_t* wstr, const wchar_t* format, va_list arg_ptr); int _win_sscanf(const char *str, const char *format, ...); int _win_swscanf(const wchar_t *wstr, const wchar_t *format, ...); int _win_vfscanf(FILE *stream, const char *format, va_list arg_ptr); int _win_vfwscanf(FILE *stream, const wchar_t *format, va_list arg_ptr); int _win_vscanf(const char *format, va_list arg_ptr); int _win_vwscanf(const wchar_t *format, va_list arg_ptr); int _win_scanf(const char *format, ...); int _win_wscanf(const wchar_t *format, ...); int _win_fscanf(FILE *stream, const char *format, ...); int _win_fwscanf(FILE *stream, const wchar_t *format, ...); pid_t _win_waitpid(pid_t pid, int *stat_loc, int options); int _win_bind(int s, const struct sockaddr *name, int namelen); int _win_connect(int s,const struct sockaddr *name, int namelen); int _win_getpeername(int s, struct sockaddr *name, int *namelen); int _win_getsockname(int s, struct sockaddr *name, int *namelen); int _win_getsockopt(int s, int level, int optname, char *optval, int *optlen); int _win_listen(int s, int backlog); int _win_recv(int s, char *buf, int len, int flags); int _win_recvfrom(int s, void *buf, int len, int flags, struct sockaddr *from, int *fromlen); int _win_select(int max_fd, fd_set * rfds, fd_set * wfds, fd_set * efds, const struct timeval *tv); int _win_send(int s, const char *buf, int len, int flags); int _win_sendto(int s, const char *buf, int len, int flags, const struct sockaddr *to, int tolen); int _win_setsockopt(int s, int level, int optname, const void *optval, int optlen); int _win_shutdown(int s, int how); int _win_socket(int af, int type, int protocol); struct hostent *_win_gethostbyaddr(const char *addr, int len, int type); struct hostent *_win_gethostbyname(const char *name); struct hostent *gethostbyname2(const char *name, int af); char *_win_strerror(int errnum); int IsWinNT(); char *index(const char *s, int c); #if !HAVE_STRNDUP char *strndup (const char *s, size_t n); #endif #if !HAVE_STRNLEN size_t strnlen (const char *str, size_t maxlen); #endif char *stpcpy(char *dest, const char *src); char *strcasestr(const char *haystack_start, const char *needle_start); #ifndef __MINGW64__ #define strcasecmp(a, b) stricmp(a, b) #define wcscasecmp(a, b) wcsicmp(a, b) #define strncasecmp(a, b, c) strnicmp(a, b, c) #define wcsncasecmp(a, b, c) wcsnicmp(a, b, c) #endif #endif /* WINDOWS */ #ifndef WINDOWS #define DIR_SEPARATOR '/' #define DIR_SEPARATOR_STR "/" #define PATH_SEPARATOR ':' #define PATH_SEPARATOR_STR ":" #define NEWLINE "\n" #ifdef ENABLE_NLS #define BINDTEXTDOMAIN(d, n) bindtextdomain(d, n) #endif #define CREAT(p, m) creat(p, m) #define PLIBC_CTIME(c) ctime(c) #define CTIME_R(c, b) ctime_r(c, b) #undef FOPEN #define FOPEN(f, m) fopen(f, m) #define FCLOSE(f) fclose(f) #define FTRUNCATE(f, l) ftruncate(f, l) #define OPENDIR(d) opendir(d) #define CLOSEDIR(d) closedir(d) #define READDIR(d) readdir(d) #define OPEN open #define CHDIR(d) chdir(d) #define CLOSE(f) close(f) #define LSEEK(f, o, w) lseek(f, o, w) #define RMDIR(f) rmdir(f) #define ACCESS(p, m) access(p, m) #define CHMOD(f, p) chmod(f, p) #define FSTAT(h, b) fstat(h, b) #define PLIBC_KILL(p, s) kill(p, s) #define PIPE(h) pipe(h) #define REMOVE(p) remove(p) #define RENAME(o, n) rename(o, n) #define STAT(p, b) stat(p, b) #define STAT64(p, b) stat64(p, b) #define SYSCONF(n) sysconf(n) #define UNLINK(f) unlink(f) #define WRITE(f, b, n) write(f, b, n) #define READ(f, b, n) read(f, b, n) #define GN_FREAD(b, s, c, f) fread(b, s, c, f) #define GN_FWRITE(b, s, c, f) fwrite(b, s, c, f) #define SYMLINK(a, b) symlink(a, b) #define MMAP(s, l, p, f, d, o) mmap(s, l, p, f, d, o) #define MKFIFO(p, m) mkfifo(p, m) #define MSYNC(s, l, f) msync(s, l, f) #define MUNMAP(s, l) munmap(s, l) #define STRERROR(i) strerror(i) #define RANDOM() random() #define SRANDOM(s) srandom(s) #define READLINK(p, b, s) readlink(p, b, s) #define LSTAT(p, b) lstat(p, b) #define LSTAT64(p, b) lstat64(p, b) #define PRINTF printf #define FPRINTF fprintf #define VPRINTF(f, a) vprintf(f, a) #define VFPRINTF(s, f, a) vfprintf(s, f, a) #define VSPRINTF(d, f, a) vsprintf(d, f, a) #define VSNPRINTF(str, size, fmt, a) vsnprintf(str, size, fmt, a) #define _REAL_SNPRINTF snprintf #define SPRINTF sprintf #define VSSCANF(s, f, a) vsscanf(s, f, a) #define SSCANF sscanf #define VFSCANF(s, f, a) vfscanf(s, f, a) #define VSCANF(f, a) vscanf(f, a) #define SCANF scanf #define FSCANF fscanf #define WAITPID(p, s, o) waitpid(p, s, o) #define ACCEPT(s, a, l) accept(s, a, l) #define BIND(s, n, l) bind(s, n, l) #define CONNECT(s, n, l) connect(s, n, l) #define GETPEERNAME(s, n, l) getpeername(s, n, l) #define GETSOCKNAME(s, n, l) getsockname(s, n, l) #define GETSOCKOPT(s, l, o, v, p) getsockopt(s, l, o, v, p) #define LISTEN(s, b) listen(s, b) #define RECV(s, b, l, f) recv(s, b, l, f) #define RECVFROM(s, b, l, f, r, o) recvfrom(s, b, l, f, r, o) #define SELECT(n, r, w, e, t) select(n, r, w, e, t) #define SEND(s, b, l, f) send(s, b, l, f) #define SENDTO(s, b, l, f, o, n) sendto(s, b, l, f, o, n) #define SETSOCKOPT(s, l, o, v, n) setsockopt(s, l, o, v, n) #define SHUTDOWN(s, h) shutdown(s, h) #define SOCKET(a, t, p) socket(a, t, p) #define GETHOSTBYADDR(a, l, t) gethostbyname(a, l, t) #define GETHOSTBYNAME(n) gethostbyname(n) #define GETTIMEOFDAY(t, n) gettimeofday(t, n) #define INSQUE(e, p) insque(e, p) #define REMQUE(e) remque(e) #define HSEARCH(i, a) hsearch(i, a) #define HCREATE(n) hcreate(n) #define HDESTROY() hdestroy() #define HSEARCH_R(i, a, r, h) hsearch_r(i, a, r, h) #define HCREATE_R(n, h) hcreate_r(n, h) #define HDESTROY_R(h) hdestroy_r(h) #define TSEARCH(k, r, c) tsearch(k, r, c) #define TFIND(k, r, c) tfind(k, r, c) #define TDELETE(k, r, c) tdelete(k, r, c) #define TWALK(r, a) twalk(r, a) #define TDESTROY(r, f) tdestroy(r, f) #define LFIND(k, b, n, s, c) lfind(k, b, n, s, c) #define LSEARCH(k, b, n, s, c) lsearch(k, b, n, s, c) #else #define DIR_SEPARATOR '\\' #define DIR_SEPARATOR_STR "\\" #define PATH_SEPARATOR ';' #define PATH_SEPARATOR_STR ";" #define NEWLINE "\r\n" #ifdef ENABLE_NLS #define BINDTEXTDOMAIN(d, n) _win_bindtextdomain(d, n) #endif #define CREAT(p, m) _win_creat(p, m) #define PLIBC_CTIME(c) _win_ctime(c) #define CTIME_R(c, b) _win_ctime_r(c, b) #define FOPEN(f, m) _win_fopen(f, m) #define FCLOSE(f) _win_fclose(f) #define FTRUNCATE(f, l) _win_ftruncate(f, l) #define OPENDIR(d) _win_opendir(d) #define CLOSEDIR(d) _win_closedir(d) #define READDIR(d) _win_readdir(d) #define OPEN _win_open #define CHDIR(d) _win_chdir(d) #define CLOSE(f) _win_close(f) #define PLIBC_KILL(p, s) _win_kill(p, s) #define LSEEK(f, o, w) _win_lseek(f, o, w) #define FSTAT(h, b) _win_fstat(h, b) #define RMDIR(f) _win_rmdir(f) #define ACCESS(p, m) _win_access(p, m) #define CHMOD(f, p) _win_chmod(f, p) #define PIPE(h) _win_pipe(h) #define RANDOM() _win_random() #define SRANDOM(s) _win_srandom(s) #define REMOVE(p) _win_remove(p) #define RENAME(o, n) _win_rename(o, n) #define STAT(p, b) _win_stat(p, b) #define STAT64(p, b) _win_stat64(p, b) #define SYSCONF(n) _win_sysconf(n) #define UNLINK(f) _win_unlink(f) #define WRITE(f, b, n) _win_write(f, b, n) #define READ(f, b, n) _win_read(f, b, n) #define GN_FREAD(b, s, c, f) _win_fread(b, s, c, f) #define GN_FWRITE(b, s, c, f) _win_fwrite(b, s, c, f) #define SYMLINK(a, b) _win_symlink(a, b) #define MMAP(s, l, p, f, d, o) _win_mmap(s, l, p, f, d, o) #define MKFIFO(p, m) _win_mkfifo(p, m) #define MSYNC(s, l, f) _win_msync(s, l, f) #define MUNMAP(s, l) _win_munmap(s, l) #define STRERROR(i) _win_strerror(i) #define READLINK(p, b, s) _win_readlink(p, b, s) #define LSTAT(p, b) _win_lstat(p, b) #define LSTAT64(p, b) _win_lstat64(p, b) #define PRINTF(f, ...) _win_printf(f , __VA_ARGS__) #define FPRINTF(fil, fmt, ...) _win_fprintf(fil, fmt, __VA_ARGS__) #define VPRINTF(f, a) _win_vprintf(f, a) #define VFPRINTF(s, f, a) _win_vfprintf(s, f, a) #define VSPRINTF(d, f, a) _win_vsprintf(d, f, a) #define VSNPRINTF(str, size, fmt, a) _win_vsnprintf(str, size, fmt, a) #define _REAL_SNPRINTF(str, size, fmt, ...) _win_snprintf(str, size, fmt, __VA_ARGS__) #define SPRINTF(d, f, ...) _win_sprintf(d, f, __VA_ARGS__) #define VSSCANF(s, f, a) _win_vsscanf(s, f, a) #define SSCANF(s, f, ...) _win_sscanf(s, f, __VA_ARGS__) #define VFSCANF(s, f, a) _win_vfscanf(s, f, a) #define VSCANF(f, a) _win_vscanf(f, a) #define SCANF(f, ...) _win_scanf(f, __VA_ARGS__) #define FSCANF(s, f, ...) _win_fscanf(s, f, __VA_ARGS__) #define WAITPID(p, s, o) _win_waitpid(p, s, o) #define ACCEPT(s, a, l) _win_accept(s, a, l) #define BIND(s, n, l) _win_bind(s, n, l) #define CONNECT(s, n, l) _win_connect(s, n, l) #define GETPEERNAME(s, n, l) _win_getpeername(s, n, l) #define GETSOCKNAME(s, n, l) _win_getsockname(s, n, l) #define GETSOCKOPT(s, l, o, v, p) _win_getsockopt(s, l, o, v, p) #define LISTEN(s, b) _win_listen(s, b) #define RECV(s, b, l, f) _win_recv(s, b, l, f) #define RECVFROM(s, b, l, f, r, o) _win_recvfrom(s, b, l, f, r, o) #define SELECT(n, r, w, e, t) _win_select(n, r, w, e, t) #define SEND(s, b, l, f) _win_send(s, b, l, f) #define SENDTO(s, b, l, f, o, n) _win_sendto(s, b, l, f, o, n) #define SETSOCKOPT(s, l, o, v, n) _win_setsockopt(s, l, o, v, n) #define SHUTDOWN(s, h) _win_shutdown(s, h) #define SOCKET(a, t, p) _win_socket(a, t, p) #define GETHOSTBYADDR(a, l, t) _win_gethostbyname(a, l, t) #define GETHOSTBYNAME(n) _win_gethostbyname(n) #define GETTIMEOFDAY(t, n) _win_gettimeofday(t, n) #define INSQUE(e, p) _win_insque(e, p) #define REMQUE(e) _win_remque(e) #define HSEARCH(i, a) _win_hsearch(i, a) #define HCREATE(n) _win_hcreate(n) #define HDESTROY() _win_hdestroy() #define HSEARCH_R(i, a, r, h) _win_hsearch_r(i, a, r, h) #define HCREATE_R(n, h) _win_hcreate_r(n, h) #define HDESTROY_R(h) _win_hdestroy_r(h) #define TSEARCH(k, r, c) _win_tsearch(k, r, c) #define TFIND(k, r, c) _win_tfind(k, r, c) #define TDELETE(k, r, c) _win_tdelete(k, r, c) #define TWALK(r, a) _win_twalk(r, a) #define TDESTROY(r, f) _win_tdestroy(r, f) #define LFIND(k, b, n, s, c) _win_lfind(k, b, n, s, c) #define LSEARCH(k, b, n, s, c) _win_lsearch(k, b, n, s, c) #endif /* search.h */ /* Prototype structure for a linked-list data structure. This is the type used by the `insque' and `remque' functions. */ struct PLIBC_SEARCH_QELEM { struct qelem *q_forw; struct qelem *q_back; char q_data[1]; }; /* Insert ELEM into a doubly-linked list, after PREV. */ void _win_insque (void *__elem, void *__prev); /* Unlink ELEM from the doubly-linked list that it is in. */ void _win_remque (void *__elem); /* For use with hsearch(3). */ typedef int (*PLIBC_SEARCH__compar_fn_t) (__const void *, __const void *); typedef PLIBC_SEARCH__compar_fn_t _win_comparison_fn_t; /* Action which shall be performed in the call the hsearch. */ typedef enum { PLIBC_SEARCH_FIND, PLIBC_SEARCH_ENTER } PLIBC_SEARCH_ACTION; typedef struct PLIBC_SEARCH_entry { char *key; void *data; } PLIBC_SEARCH_ENTRY; /* The reentrant version has no static variables to maintain the state. Instead the interface of all functions is extended to take an argument which describes the current status. */ typedef struct _PLIBC_SEARCH_ENTRY { unsigned int used; PLIBC_SEARCH_ENTRY entry; } _PLIBC_SEARCH_ENTRY; /* Family of hash table handling functions. The functions also have reentrant counterparts ending with _r. The non-reentrant functions all work on a signle internal hashing table. */ /* Search for entry matching ITEM.key in internal hash table. If ACTION is `FIND' return found entry or signal error by returning NULL. If ACTION is `ENTER' replace existing data (if any) with ITEM.data. */ PLIBC_SEARCH_ENTRY *_win_hsearch (PLIBC_SEARCH_ENTRY __item, PLIBC_SEARCH_ACTION __action); /* Create a new hashing table which will at most contain NEL elements. */ int _win_hcreate (size_t __nel); /* Destroy current internal hashing table. */ void _win_hdestroy (void); /* Data type for reentrant functions. */ struct PLIBC_SEARCH_hsearch_data { struct _PLIBC_SEARCH_ENTRY *table; unsigned int size; unsigned int filled; }; /* Reentrant versions which can handle multiple hashing tables at the same time. */ int _win_hsearch_r (PLIBC_SEARCH_ENTRY __item, PLIBC_SEARCH_ACTION __action, PLIBC_SEARCH_ENTRY **__retval, struct PLIBC_SEARCH_hsearch_data *__htab); int _win_hcreate_r (size_t __nel, struct PLIBC_SEARCH_hsearch_data *__htab); void _win_hdestroy_r (struct PLIBC_SEARCH_hsearch_data *__htab); /* The tsearch routines are very interesting. They make many assumptions about the compiler. It assumes that the first field in node must be the "key" field, which points to the datum. Everything depends on that. */ /* For tsearch */ typedef enum { PLIBC_SEARCH_preorder, PLIBC_SEARCH_postorder, PLIBC_SEARCH_endorder, PLIBC_SEARCH_leaf } PLIBC_SEARCH_VISIT; /* Search for an entry matching the given KEY in the tree pointed to by *ROOTP and insert a new element if not found. */ void *_win_tsearch (__const void *__key, void **__rootp, PLIBC_SEARCH__compar_fn_t __compar); /* Search for an entry matching the given KEY in the tree pointed to by *ROOTP. If no matching entry is available return NULL. */ void *_win_tfind (__const void *__key, void *__const *__rootp, PLIBC_SEARCH__compar_fn_t __compar); /* Remove the element matching KEY from the tree pointed to by *ROOTP. */ void *_win_tdelete (__const void *__restrict __key, void **__restrict __rootp, PLIBC_SEARCH__compar_fn_t __compar); typedef void (*PLIBC_SEARCH__action_fn_t) (__const void *__nodep, PLIBC_SEARCH_VISIT __value, int __level); /* Walk through the whole tree and call the ACTION callback for every node or leaf. */ void _win_twalk (__const void *__root, PLIBC_SEARCH__action_fn_t __action); /* Callback type for function to free a tree node. If the keys are atomic data this function should do nothing. */ typedef void (*PLIBC_SEARCH__free_fn_t) (void *__nodep); /* Destroy the whole tree, call FREEFCT for each node or leaf. */ void _win_tdestroy (void *__root, PLIBC_SEARCH__free_fn_t __freefct); /* Perform linear search for KEY by comparing by COMPAR in an array [BASE,BASE+NMEMB*SIZE). */ void *_win_lfind (__const void *__key, __const void *__base, size_t *__nmemb, size_t __size, PLIBC_SEARCH__compar_fn_t __compar); /* Perform linear search for KEY by comparing by COMPAR function in array [BASE,BASE+NMEMB*SIZE) and insert entry if not found. */ void *_win_lsearch (__const void *__key, void *__base, size_t *__nmemb, size_t __size, PLIBC_SEARCH__compar_fn_t __compar); #ifdef __cplusplus } #endif #endif //_PLIBC_H_ /* end of plibc.h */ gnunet-0.9.3/src/include/gnunet_testing_lib-new.h0000644000175000017500000002214711761753145017021 00000000000000/* This file is part of GNUnet (C) 2008, 2009, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_testing_lib-new.h * @brief convenience API for writing testcases for GNUnet; * can start/stop one or more peers on a system; * testing is responsible for managing private keys, * ports and paths; it is a low-level library that * does not support higher-level functions such as * P2P connection, topology management or distributed * testbed maintenance (those are in gnunet_testbed_service.h) * @author Christian Grothoff */ #ifndef GNUNET_TESTING_LIB_NEW_H #define GNUNET_TESTING_LIB_NEW_H #include "gnunet_util_lib.h" #include "gnunet_statistics_service.h" #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * Handle for a system on which GNUnet peers are executed; * a system is used for reserving unique paths and ports. */ struct GNUNET_TESTING_System; /** * Handle for a GNUnet peer controlled by testing. */ struct GNUNET_TESTING_Peer; /** * Create a system handle. There must only be one system * handle per operating system. * * @param tmppath prefix path to use for all service homes * @param controller hostname of the controlling host, * service configurations are modified to allow * control connections from this host; can be NULL * @return handle to this system, NULL on error */ struct GNUNET_TESTING_System * GNUNET_TESTING_system_create (const char *tmppath, const char *controller); /** * Free system resources. * * @param system system to be freed * @param remove_paths should the 'tmppath' and all subdirectories * be removed (clean up on shutdown)? */ void GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system, int remove_paths); /** * Testing includes a number of pre-created hostkeys for faster peer * startup. This function loads such keys into memory from a file. * * @param system the testing system handle * @param filename the path of the hostkeys file * @return GNUNET_OK on success; GNUNET_SYSERR on error */ int GNUNET_TESTING_hostkeys_load (struct GNUNET_TESTING_System *system, const char *filename); /** * Function to remove the loaded hostkeys * * @param system the testing system handle */ void GNUNET_TESTING_hostkeys_unload (struct GNUNET_TESTING_System *system); /** * Testing includes a number of pre-created hostkeys for * faster peer startup. This function can be used to * access the n-th key of those pre-created hostkeys; note * that these keys are ONLY useful for testing and not * secure as the private keys are part of the public * GNUnet source code. * * This is primarily a helper function used internally * by 'GNUNET_TESTING_peer_configure'. * * @param system the testing system handle * @param key_number desired pre-created hostkey to obtain * @param id set to the peer's identity (hash of the public * key; if NULL, GNUNET_SYSERR is returned immediately * @return GNUNET_SYSERR on error (not enough keys) */ int GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system, uint32_t key_number, struct GNUNET_PeerIdentity *id); /** * Reserve a TCP or UDP port for a peer. * * @param system system to use for reservation tracking * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP * @return 0 if no free port was available */ uint16_t GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system, int is_tcp); /** * Release reservation of a TCP or UDP port for a peer * (used during GNUNET_TESTING_peer_destroy). * * @param system system to use for reservation tracking * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP * @param port reserved port to release */ void GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system, int is_tcp, uint16_t port); /** * Create a new configuration using the given configuration * as a template; ports and paths will be modified to select * available ports on the local system. If we run * out of "*port" numbers, return SYSERR. * * This is primarily a helper function used internally * by 'GNUNET_TESTING_peer_configure'. * * @param system system to use to coordinate resource usage * @param cfg template configuration to update * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will * be incomplete and should not be used there upon */ int GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system, struct GNUNET_CONFIGURATION_Handle *cfg); // FIXME: add dual to 'release' ports again... /** * Configure a GNUnet peer. GNUnet must be installed on the local * system and available in the PATH. * * @param system system to use to coordinate resource usage * @param cfg configuration to use; will be UPDATED (to reflect needed * changes in port numbers and paths) * @param key_number number of the hostkey to use for the peer * @param id identifier for the daemon, will be set, can be NULL * @param emsg set to error message (set to NULL on success), can be NULL * @return handle to the peer, NULL on error */ struct GNUNET_TESTING_Peer * GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system, struct GNUNET_CONFIGURATION_Handle *cfg, uint32_t key_number, struct GNUNET_PeerIdentity *id, char **emsg); /** * Start the peer. * * @param peer peer to start * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running) */ int GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer); /** * Stop the peer. * * @param peer peer to stop * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer not running) */ int GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer); /** * Destroy the peer. Releases resources locked during peer configuration. * If the peer is still running, it will be stopped AND a warning will be * printed (users of the API should stop the peer explicitly first). * * @param peer peer to destroy */ void GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer); /** * Signature of the 'main' function for a (single-peer) testcase that * is run using 'GNUNET_TESTING_peer_run'. * * @param cls closure * @param cfg configuration of the peer that was started */ typedef void (*GNUNET_TESTING_TestMain)(void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg); /** * Start a single peer and run a test using the testing library. * Starts a peer using the given configuration and then invokes the * given callback. This function ALSO initializes the scheduler loop * and should thus be called directly from "main". The testcase * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'. * * @param tmppath path for storing temporary data for the test * @param cfgfilename name of the configuration file to use; * use NULL to only run with defaults * @param tm main function of the testcase * @param tm_cls closure for 'tm' * @return 0 on success, 1 on error */ int GNUNET_TESTING_peer_run (const char *tmppath, const char *cfgfilename, GNUNET_TESTING_TestMain tm, void *tm_cls); /** * Start a single service (no ARM, except of course if the given * service name is 'arm') and run a test using the testing library. * Starts a service using the given configuration and then invokes the * given callback. This function ALSO initializes the scheduler loop * and should thus be called directly from "main". The testcase * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'. * * This function is useful if the testcase is for a single service * and if that service doesn't itself depend on other services. * * @param tmppath path for storing temporary data for the test * @param service_name name of the service to run * @param cfgfilename name of the configuration file to use; * use NULL to only run with defaults * @param tm main function of the testcase * @param tm_cls closure for 'tm' * @return 0 on success, 1 on error */ int GNUNET_TESTING_service_run (const char *tmppath, const char *service_name, const char *cfgfilename, GNUNET_TESTING_TestMain tm, void *tm_cls); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif #endif gnunet-0.9.3/src/include/gnunet_hello_lib.h0000644000175000017500000002345511760502551015653 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_hello_lib.h * @brief helper library for handling HELLOs * @author Christian Grothoff */ #ifndef GNUNET_HELLO_LIB_H #define GNUNET_HELLO_LIB_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_common.h" #include "gnunet_crypto_lib.h" /** * An address for communicating with a peer. We frequently * need this tuple and the components cannot really be * separated. This is NOT the format that would be used * on the wire. */ struct GNUNET_HELLO_Address { /** * For which peer is this an address? */ struct GNUNET_PeerIdentity peer; /** * Name of the transport plugin enabling the communication using * this address. */ const char *transport_name; /** * Binary representation of the address (plugin-specific). */ const void *address; /** * Number of bytes in 'address'. */ size_t address_length; }; /** * Allocate an address struct. * * @param peer the peer * @param transport_name plugin name * @param address binary address * @param address_length number of bytes in 'address' * @return the address struct */ struct GNUNET_HELLO_Address * GNUNET_HELLO_address_allocate (const struct GNUNET_PeerIdentity *peer, const char *transport_name, const void *address, size_t address_length); /** * Copy an address struct. * * @param address address to copy * @return a copy of the address struct */ struct GNUNET_HELLO_Address * GNUNET_HELLO_address_copy (const struct GNUNET_HELLO_Address *address); /** * Compare two addresses. Does NOT compare the peer identity, * that is assumed already to match! * * @param a1 first address * @param a2 second address * @return 0 if the addresses are equal, -1 if a1a2. */ int GNUNET_HELLO_address_cmp (const struct GNUNET_HELLO_Address *a1, const struct GNUNET_HELLO_Address *a2); /** * Get the size of an address struct. * * @param address address * @return the size */ size_t GNUNET_HELLO_address_get_size (const struct GNUNET_HELLO_Address *address); /** * Free an address. * * @param addr address to free */ #define GNUNET_HELLO_address_free(addr) GNUNET_free(addr) /** * A HELLO message is used to exchange information about * transports with other peers. This struct is guaranteed * to start with a "GNUNET_MessageHeader", everything else * should be internal to the HELLO library. */ struct GNUNET_HELLO_Message; /** * Copy the given address information into * the given buffer using the format of HELLOs. * * @param address address to add * @param expiration expiration for the address * @param target where to copy the address * @param max maximum number of bytes to copy to target * @return number of bytes copied, 0 if * the target buffer was not big enough. */ size_t GNUNET_HELLO_add_address (const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration, char *target, size_t max); /** * Callback function used to fill a buffer of max bytes with a list of * addresses in the format used by HELLOs. Should use * "GNUNET_HELLO_add_address" as a helper function. * * @param cls closure * @param max maximum number of bytes that can be written to buf * @param buf where to write the address information * @return number of bytes written, 0 to signal the * end of the iteration. */ typedef size_t (*GNUNET_HELLO_GenerateAddressListCallback) (void *cls, size_t max, void *buf); /** * Construct a HELLO message given the public key, * expiration time and an iterator that spews the * transport addresses. * * @return the hello message */ struct GNUNET_HELLO_Message * GNUNET_HELLO_create (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey, GNUNET_HELLO_GenerateAddressListCallback addrgen, void *addrgen_cls); /** * Return the size of the given HELLO message. * @param hello to inspect * @return the size, 0 if HELLO is invalid */ uint16_t GNUNET_HELLO_size (const struct GNUNET_HELLO_Message *hello); /** * Construct a HELLO message by merging the * addresses in two existing HELLOs (which * must be for the same peer). * * @param h1 first HELLO message * @param h2 the second HELLO message * @return the combined hello message */ struct GNUNET_HELLO_Message * GNUNET_HELLO_merge (const struct GNUNET_HELLO_Message *h1, const struct GNUNET_HELLO_Message *h2); /** * Test if two HELLO messages contain the same addresses. * If they only differ in expiration time, the lowest * expiration time larger than 'now' where they differ * is returned. * * @param h1 first HELLO message * @param h2 the second HELLO message * @param now time to use for deciding which addresses have * expired and should not be considered at all * @return absolute time forever if the two HELLOs are * totally identical; smallest timestamp >= now if * they only differ in timestamps; * zero if the some addresses with expirations >= now * do not match at all */ struct GNUNET_TIME_Absolute GNUNET_HELLO_equals (const struct GNUNET_HELLO_Message *h1, const struct GNUNET_HELLO_Message *h2, struct GNUNET_TIME_Absolute now); /** * Iterator callback to go over all addresses. * * @param cls closure * @param address the address * @param expiration expiration time * @return GNUNET_OK to keep the address, * GNUNET_NO to delete it from the HELLO * GNUNET_SYSERR to stop iterating (but keep current address) */ typedef int (*GNUNET_HELLO_AddressIterator) (void *cls, const struct GNUNET_HELLO_Address * address, struct GNUNET_TIME_Absolute expiration); /** * When does the last address in the given HELLO expire? * * @param msg HELLO to inspect * @return time the last address expires, 0 if there are no addresses in the HELLO */ struct GNUNET_TIME_Absolute GNUNET_HELLO_get_last_expiration (const struct GNUNET_HELLO_Message *msg); /** * Iterate over all of the addresses in the HELLO. * * @param msg HELLO to iterate over; client does not need to * have verified that msg is well-formed (beyond starting * with a GNUNET_MessageHeader of the right type). * @param return_modified if a modified copy should be returned, * otherwise NULL will be returned * @param it iterator to call on each address * @param it_cls closure for it * @return the modified HELLO or NULL */ struct GNUNET_HELLO_Message * GNUNET_HELLO_iterate_addresses (const struct GNUNET_HELLO_Message *msg, int return_modified, GNUNET_HELLO_AddressIterator it, void *it_cls); /** * Iterate over addresses in "new_hello" that * are NOT already present in "old_hello". * * @param new_hello a HELLO message * @param old_hello a HELLO message * @param expiration_limit ignore addresses in old_hello * that expired before the given time stamp * @param it iterator to call on each address * @param it_cls closure for it */ void GNUNET_HELLO_iterate_new_addresses (const struct GNUNET_HELLO_Message *new_hello, const struct GNUNET_HELLO_Message *old_hello, struct GNUNET_TIME_Absolute expiration_limit, GNUNET_HELLO_AddressIterator it, void *it_cls); /** * Get the public key from a HELLO message. * * @param hello the hello message * @param publicKey where to copy the public key information, can be NULL * @return GNUNET_SYSERR if the HELLO was malformed */ int GNUNET_HELLO_get_key (const struct GNUNET_HELLO_Message *hello, struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey); /** * Get the peer identity from a HELLO message. * * @param hello the hello message * @param peer where to store the peer's identity * @return GNUNET_SYSERR if the HELLO was malformed */ int GNUNET_HELLO_get_id (const struct GNUNET_HELLO_Message *hello, struct GNUNET_PeerIdentity *peer); /** * Get the header from a HELLO message, used so other code * can correctly send HELLO messages. * * @param hello the hello message * * @return header or NULL if the HELLO was malformed */ struct GNUNET_MessageHeader * GNUNET_HELLO_get_header (struct GNUNET_HELLO_Message *hello); /* ifndef GNUNET_HELLO_LIB_H */ #endif /* end of gnunet_hello_lib.h */ gnunet-0.9.3/src/include/gnunet_mesh_service.h0000644000175000017500000003074411760502551016375 00000000000000/* This file is part of GNUnet. (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_mesh_service.h * @brief mesh service; establish tunnels to distant peers * @author Christian Grothoff */ #ifndef GNUNET_MESH_SERVICE_H #define GNUNET_MESH_SERVICE_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_util_lib.h" #include "gnunet_transport_service.h" /** * Version number of GNUnet-mesh API. */ #define GNUNET_MESH_VERSION 0x00000000 /** * Opaque handle to the service. */ struct GNUNET_MESH_Handle; /** * Opaque handle to a tunnel. */ struct GNUNET_MESH_Tunnel; /** * Functions with this signature are called whenever a message is * received. * * @param cls closure (set from GNUNET_MESH_connect) * @param tunnel connection to the other end * @param tunnel_ctx place to store local state associated with the tunnel * @param sender who sent the message * @param message the actual message * @param atsi performance data for the connection * @return GNUNET_OK to keep the connection open, * GNUNET_SYSERR to close it (signal serious error) */ typedef int (*GNUNET_MESH_MessageCallback) (void *cls, struct GNUNET_MESH_Tunnel * tunnel, void **tunnel_ctx, const struct GNUNET_PeerIdentity * sender, const struct GNUNET_MessageHeader * message, const struct GNUNET_ATS_Information * atsi); /** * Message handler. Each struct specifies how to handle on particular * type of message received. */ struct GNUNET_MESH_MessageHandler { /** * Function to call for messages of "type". */ GNUNET_MESH_MessageCallback callback; /** * Type of the message this handler covers. */ uint16_t type; /** * Expected size of messages of this type. Use 0 for variable-size. * If non-zero, messages of the given type will be discarded if they * do not have the right size. */ uint16_t expected_size; }; /** * Method called whenever another peer has added us to a tunnel * the other peer initiated. * * @param cls closure * @param tunnel new handle to the tunnel * @param initiator peer that started the tunnel * @param atsi performance information for the tunnel * @return initial tunnel context for the tunnel * (can be NULL -- that's not an error) */ typedef void *(GNUNET_MESH_InboundTunnelNotificationHandler) (void *cls, struct GNUNET_MESH_Tunnel * tunnel, const struct GNUNET_PeerIdentity * initiator, const struct GNUNET_ATS_Information * atsi); /** * Function called whenever an inbound tunnel is destroyed. Should clean up * any associated state. This function is NOT called if the client has * explicitly asked for the tunnel to be destroyed using * GNUNET_MESH_tunnel_destroy. It must NOT call GNUNET_MESH_tunnel_destroy on * the tunnel. * * @param cls closure (set from GNUNET_MESH_connect) * @param tunnel connection to the other end (henceforth invalid) * @param tunnel_ctx place where local state associated * with the tunnel is stored */ typedef void (GNUNET_MESH_TunnelEndHandler) (void *cls, const struct GNUNET_MESH_Tunnel * tunnel, void *tunnel_ctx); /** * Type for an application. Values defined in gnunet_applications.h */ typedef uint32_t GNUNET_MESH_ApplicationType; /** * Connect to the mesh service. * * @param cfg configuration to use * @param queue_size size of the data message queue, shared among all tunnels * (each tunnel is guaranteed to accept at least one message, * no matter what is the status of other tunnels) * @param cls closure for the various callbacks that follow * (including handlers in the handlers array) * @param new_tunnel function called when an *inbound* tunnel is created * @param cleaner function called when an *inbound* tunnel is destroyed by the * remote peer, it is *not* called if GNUNET_MESH_tunnel_destroy * is called on the tunnel * @param handlers callbacks for messages we care about, NULL-terminated * note that the mesh is allowed to drop notifications about * inbound messages if the client does not process them fast * enough (for this notification type, a bounded queue is used) * @param stypes list of the applications that this client claims to provide * @return handle to the mesh service NULL on error * (in this case, init is never called) */ struct GNUNET_MESH_Handle * GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned int queue_size, void *cls, GNUNET_MESH_InboundTunnelNotificationHandler new_tunnel, GNUNET_MESH_TunnelEndHandler cleaner, const struct GNUNET_MESH_MessageHandler *handlers, const GNUNET_MESH_ApplicationType *stypes); /** * Disconnect from the mesh service. All tunnels will be destroyed. All tunnel * disconnect callbacks will be called on any still connected peers, notifying * about their disconnection. The registered inbound tunnel cleaner will be * called should any inbound tunnels still exist. * * @param handle connection to mesh to disconnect */ void GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle); /** * Method called whenever a peer has disconnected from the tunnel. * Implementations of this callback must NOT call * GNUNET_MESH_tunnel_destroy immediately, but instead schedule those * to run in some other task later. However, calling * "GNUNET_MESH_notify_transmit_ready_cancel" is allowed. * * @param cls closure * @param peer peer identity the tunnel stopped working with */ typedef void (*GNUNET_MESH_PeerDisconnectHandler) (void *cls, const struct GNUNET_PeerIdentity * peer); /** * Method called whenever a peer has connected to the tunnel. * * @param cls closure * @param peer peer identity the tunnel was created to, NULL on timeout * @param atsi performance data for the connection * * TODO: change to return int to let client allow the new peer or not? */ typedef void (*GNUNET_MESH_PeerConnectHandler) (void *cls, const struct GNUNET_PeerIdentity * peer, const struct GNUNET_ATS_Information * atsi); /** * Create a new tunnel (we're initiator and will be allowed to add/remove peers * and to broadcast). * * @param h mesh handle * @param tunnel_ctx client's tunnel context to associate with the tunnel * @param connect_handler function to call when peers are actually connected * @param disconnect_handler function to call when peers are disconnected * @param handler_cls closure for connect/disconnect handlers */ struct GNUNET_MESH_Tunnel * GNUNET_MESH_tunnel_create (struct GNUNET_MESH_Handle *h, void *tunnel_ctx, GNUNET_MESH_PeerConnectHandler connect_handler, GNUNET_MESH_PeerDisconnectHandler disconnect_handler, void *handler_cls); /** * Destroy an existing tunnel. The existing callback for the tunnel will NOT * be called. * * @param tunnel tunnel handle */ void GNUNET_MESH_tunnel_destroy (struct GNUNET_MESH_Tunnel *tunnel); /** * Request that a peer should be added to the tunnel. The connect handler * will be called when the peer connects * * @param tunnel handle to existing tunnel * @param peer peer to add */ void GNUNET_MESH_peer_request_connect_add (struct GNUNET_MESH_Tunnel *tunnel, const struct GNUNET_PeerIdentity *peer); /** * Request that a peer should be removed from the tunnel. The existing * disconnect handler will be called ONCE if we were connected. * * @param tunnel handle to existing tunnel * @param peer peer to remove */ void GNUNET_MESH_peer_request_connect_del (struct GNUNET_MESH_Tunnel *tunnel, const struct GNUNET_PeerIdentity *peer); /** * Request that the mesh should try to connect to a peer supporting the given * message type. * * @param tunnel handle to existing tunnel * @param app_type application type that must be supported by the peer * (MESH should discover peer in proximity handling this type) */ void GNUNET_MESH_peer_request_connect_by_type (struct GNUNET_MESH_Tunnel *tunnel, GNUNET_MESH_ApplicationType app_type); /** * Handle for a transmission request. */ struct GNUNET_MESH_TransmitHandle; /** * Ask the mesh to call "notify" once it is ready to transmit the * given number of bytes to the specified tunnel or target. * * @param tunnel tunnel to use for transmission * @param cork is corking allowed for this transmission? * @param priority how important is the message? * @param maxdelay how long can the message wait? * @param target destination for the message * NULL for multicast to all tunnel targets * @param notify_size how many bytes of buffer space does notify want? * @param notify function to call when buffer space is available; * will be called with NULL on timeout or if the overall queue * for this peer is larger than queue_size and this is currently * the message with the lowest priority * @param notify_cls closure for notify * @return non-NULL if the notify callback was queued, * NULL if we can not even queue the request (insufficient * memory); if NULL is returned, "notify" will NOT be called. */ struct GNUNET_MESH_TransmitHandle * GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel, int cork, uint32_t priority, struct GNUNET_TIME_Relative maxdelay, const struct GNUNET_PeerIdentity *target, size_t notify_size, GNUNET_CONNECTION_TransmitReadyNotify notify, void *notify_cls); /** * Cancel the specified transmission-ready notification. * * @param th handle that was returned by "notify_transmit_ready". */ void GNUNET_MESH_notify_transmit_ready_cancel (struct GNUNET_MESH_TransmitHandle *th); /** * Transition API for tunnel ctx management */ void GNUNET_MESH_tunnel_set_data (struct GNUNET_MESH_Tunnel *tunnel, void *data); /** * Transition API for tunnel ctx management */ void * GNUNET_MESH_tunnel_get_data (struct GNUNET_MESH_Tunnel *tunnel); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_MESH_SERVICE_H */ #endif /* end of gnunet_mesh_service.h */ gnunet-0.9.3/src/include/gnunet_chat_service.h0000644000175000017500000002121111760502551016345 00000000000000/* This file is part of GNUnet. (C) 2009, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_chat_service.h * @brief API for chatting via GNUnet * @author Christian Grothoff * @author Nathan Evans * @author Vitaly Minko */ #ifndef GNUNET_CHAT_SERVICE_H #define GNUNET_CHAT_SERVICE_H #include "gnunet_util_lib.h" #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #define GNUNET_CHAT_VERSION 0x00000003 #define MAX_MESSAGE_LENGTH (32 * 1024) /** * Options for messaging. Compatible options can be OR'ed together. */ enum GNUNET_CHAT_MsgOptions { /** * No special options. */ GNUNET_CHAT_MSG_OPTION_NONE = 0, /** * Encrypt the message so that only the receiver can decrypt it. */ GNUNET_CHAT_MSG_PRIVATE = 1, /** * Hide the identity of the sender. */ GNUNET_CHAT_MSG_ANONYMOUS = 2, /** * Sign the content, authenticating the sender (using the provided private * key, which may represent a pseudonym). */ GNUNET_CHAT_MSG_AUTHENTICATED = 4, /** * Require signed acknowledgment before completing delivery (and of course, * only acknowledge if delivery is guaranteed). */ GNUNET_CHAT_MSG_ACKNOWLEDGED = 8, /** * Authenticate for the receiver, but ensure that receiver cannot prove * authenticity to third parties later. (not yet implemented) */ GNUNET_CHAT_MSG_OFF_THE_RECORD = 16, }; /** * Handle for a (joined) chat room. */ struct GNUNET_CHAT_Room; /** * Callback used for notification that we have joined the room. * * @param cls closure * @return GNUNET_OK */ typedef int (*GNUNET_CHAT_JoinCallback) (void *cls); /** * Callback used for notification about incoming messages. * * @param cls closure * @param room in which room was the message received? * @param sender what is the ID of the sender? (maybe NULL) * @param member_info information about the joining member * @param message the message text * @param timestamp when was the message sent? * @param options options for the message * @return GNUNET_OK to accept the message now, GNUNET_NO to * accept (but user is away), GNUNET_SYSERR to signal denied delivery */ typedef int (*GNUNET_CHAT_MessageCallback) (void *cls, struct GNUNET_CHAT_Room * room, const GNUNET_HashCode * sender, const struct GNUNET_CONTAINER_MetaData * member_info, const char *message, struct GNUNET_TIME_Absolute timestamp, enum GNUNET_CHAT_MsgOptions options); /** * Callback used for notification that another room member has joined or left. * * @param cls closure * @param member_info will be non-null if the member is joining, NULL if he is * leaving * @param member_id hash of public key of the user (for unique identification) * @param options what types of messages is this member willing to receive? * @return GNUNET_OK */ typedef int (*GNUNET_CHAT_MemberListCallback) (void *cls, const struct GNUNET_CONTAINER_MetaData * member_info, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded * member_id, enum GNUNET_CHAT_MsgOptions options); /** * Callback used for message delivery confirmations. * * @param cls closure * @param room in which room was the message received? * @param orig_seq_number sequence number of the original message * @param timestamp when was the message received? * @param receiver who is confirming the receipt? * @return GNUNET_OK to continue, GNUNET_SYSERR to refuse processing further * confirmations from anyone for this message */ typedef int (*GNUNET_CHAT_MessageConfirmation) (void *cls, struct GNUNET_CHAT_Room * room, uint32_t orig_seq_number, struct GNUNET_TIME_Absolute timestamp, const GNUNET_HashCode * receiver); /** * Join a chat room. * * @param cfg configuration * @param nick_name nickname of the user joining (used to * determine which public key to use); * the nickname should probably also * be used in the member_info (as "EXTRACTOR_TITLE") * @param member_info information about the joining member * @param room_name name of the room * @param msg_options message options of the joining user * @param joinCallback which function to call when we've joined the room * @param join_cls argument to callback * @param messageCallback which function to call if a message has * been received? * @param message_cls argument to callback * @param memberCallback which function to call for join/leave notifications * @param member_cls argument to callback * @param confirmationCallback which function to call for confirmations * (maybe NULL) * @param confirmation_cls argument to callback * @param me member ID (pseudonym) * @return NULL on error */ struct GNUNET_CHAT_Room * GNUNET_CHAT_join_room (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *nick_name, struct GNUNET_CONTAINER_MetaData *member_info, const char *room_name, enum GNUNET_CHAT_MsgOptions msg_options, GNUNET_CHAT_JoinCallback joinCallback, void *join_cls, GNUNET_CHAT_MessageCallback messageCallback, void *message_cls, GNUNET_CHAT_MemberListCallback memberCallback, void *member_cls, GNUNET_CHAT_MessageConfirmation confirmationCallback, void *confirmation_cls, GNUNET_HashCode * me); /** * Send a message. * * @param room handle for the chat room * @param message message to be sent * @param options options for the message * @param receiver use NULL to send to everyone in the room * @param sequence_number where to write the sequence id of the message */ void GNUNET_CHAT_send_message (struct GNUNET_CHAT_Room *room, const char *message, enum GNUNET_CHAT_MsgOptions options, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *receiver, uint32_t * sequence_number); /** * Leave a chat room. */ void GNUNET_CHAT_leave_room (struct GNUNET_CHAT_Room *chat_room); #if 0 /* these are not yet implemented / supported */ /** * Callback function to iterate over rooms. * * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration */ typedef int (*GNUNET_CHAT_RoomIterator) (const char *room, const char *topic, void *cls); /** * List all of the (publically visible) chat rooms. * @return number of rooms on success, GNUNET_SYSERR if iterator aborted */ int GNUNET_CHAT_list_rooms (struct GNUNET_GE_Context *ectx, struct GNUNET_GC_Configuration *cfg, GNUNET_CHAT_RoomIterator it, void *cls); #endif #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif #endif /* end of gnunet_chat_service.h */ gnunet-0.9.3/src/include/gnunet_client_lib.h0000644000175000017500000001675111760502551016027 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_client_lib.h * @brief functions related to accessing services * @author Christian Grothoff */ #ifndef GNUNET_CLIENT_LIB_H #define GNUNET_CLIENT_LIB_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_common.h" #include "gnunet_configuration_lib.h" #include "gnunet_connection_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_time_lib.h" /** * Opaque handle for a connection to a service. */ struct GNUNET_CLIENT_Connection; /** * Get a connection with a service. * * @param service_name name of the service * @param cfg configuration to use * @return NULL on error (service unknown to configuration) */ struct GNUNET_CLIENT_Connection * GNUNET_CLIENT_connect (const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg); /** * Destroy connection with the service. This will automatically * cancel any pending "receive" request (however, the handler will * *NOT* be called, not even with a NULL message). Any pending * transmission request will also be cancelled UNLESS the callback for * the transmission request has already been called, in which case the * transmission 'finish_pending_write' argument determines whether or * not the write is guaranteed to complete before the socket is fully * destroyed (unless, of course, there is an error with the server in * which case the message may still be lost). * * @param client handle to the service connection */ void GNUNET_CLIENT_disconnect (struct GNUNET_CLIENT_Connection *client); /** * Type of a function to call when we receive a message * from the service. * * @param cls closure * @param msg message received, NULL on timeout or fatal error */ typedef void (*GNUNET_CLIENT_MessageHandler) (void *cls, const struct GNUNET_MessageHeader * msg); /** * Type of a function to call when we have finished shutting * down a service, or failed. * * @param cls closure * @param reason what is the result of the shutdown * GNUNET_NO on shutdown (not running) * GNUNET_YES on running * GNUNET_SYSERR on failure to transmit message */ typedef void (*GNUNET_CLIENT_ShutdownTask) (void *cls, int reason); /** * Read from the service. * * @param client connection to the service * @param handler function to call with the message * @param handler_cls closure for handler * @param timeout how long to wait until timing out */ void GNUNET_CLIENT_receive (struct GNUNET_CLIENT_Connection *client, GNUNET_CLIENT_MessageHandler handler, void *handler_cls, struct GNUNET_TIME_Relative timeout); /** * Transmit handle for client connections. */ struct GNUNET_CLIENT_TransmitHandle; /** * Ask the client to call us once the specified number of bytes * are free in the transmission buffer. May call the notify * method immediately if enough space is available. * * @param client connection to the service * @param size number of bytes to send * @param timeout after how long should we give up (and call * notify with buf NULL and size 0)? * @param auto_retry if the connection to the service dies, should we * automatically re-connect and retry (within the timeout period) * or should we immediately fail in this case? Pass GNUNET_YES * if the caller does not care about temporary connection errors, * for example because the protocol is stateless * @param notify function to call * @param notify_cls closure for notify * @return NULL if someone else is already waiting to be notified * non-NULL if the notify callback was queued (can be used to cancel * using GNUNET_CONNECTION_notify_transmit_ready_cancel) */ struct GNUNET_CLIENT_TransmitHandle * GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *client, size_t size, struct GNUNET_TIME_Relative timeout, int auto_retry, GNUNET_CONNECTION_TransmitReadyNotify notify, void *notify_cls); /** * Cancel a request for notification. * * @param th handle from the original request. */ void GNUNET_CLIENT_notify_transmit_ready_cancel (struct GNUNET_CLIENT_TransmitHandle *th); /** * Convenience API that combines sending a request * to the service and waiting for a response. * If either operation times out, the callback * will be called with a "NULL" response (in which * case the connection should probably be destroyed). * * @param client connection to use * @param hdr message to transmit * @param timeout when to give up (for both transmission * and for waiting for a response) * @param auto_retry if the connection to the service dies, should we * automatically re-connect and retry (within the timeout period) * or should we immediately fail in this case? Pass GNUNET_YES * if the caller does not care about temporary connection errors, * for example because the protocol is stateless * @param rn function to call with the response * @param rn_cls closure for rn * @return GNUNET_OK on success, GNUNET_SYSERR if a request * is already pending */ int GNUNET_CLIENT_transmit_and_get_response (struct GNUNET_CLIENT_Connection *client, const struct GNUNET_MessageHeader *hdr, struct GNUNET_TIME_Relative timeout, int auto_retry, GNUNET_CLIENT_MessageHandler rn, void *rn_cls); /** * Wait until the service is running. * * @param service name of the service to wait for * @param cfg configuration to use * @param timeout how long to wait at most in ms * @param task task to run if service is running * (reason will be "PREREQ_DONE" (service running) * or "TIMEOUT" (service not known to be running)) * @param task_cls closure for task */ void GNUNET_CLIENT_service_test (const char *service, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TIME_Relative timeout, GNUNET_SCHEDULER_Task task, void *task_cls); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_CLIENT_LIB_H */ #endif /* end of gnunet_client_lib.h */ gnunet-0.9.3/src/include/gnunet_container_lib.h0000644000175000017500000010525211760502551016526 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_container_lib.h * @brief container classes for GNUnet * * @author Christian Grothoff * @author Nils Durner */ #ifndef GNUNET_CONTAINER_LIB_H #define GNUNET_CONTAINER_LIB_H /* add error and config prototypes */ #include "gnunet_crypto_lib.h" #include #ifndef EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME /* hack for LE < 0.6.3 */ #define EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME 180 #endif #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /* ******************* bloomfilter ***************** */ /** * @brief bloomfilter representation (opaque) */ struct GNUNET_CONTAINER_BloomFilter; /** * Iterator over HashCodes. * * @param cls closure * @param next set to the next hash code * @return GNUNET_YES if next was updated * GNUNET_NO if there are no more entries */ typedef int (*GNUNET_HashCodeIterator) (void *cls, GNUNET_HashCode * next); /** * Load a bloom-filter from a file. * * @param filename the name of the file (or the prefix) * @param size the size of the bloom-filter (number of * bytes of storage space to use); will be rounded up * to next power of 2 * @param k the number of GNUNET_CRYPTO_hash-functions to apply per * element (number of bits set per element in the set) * @return the bloomfilter */ struct GNUNET_CONTAINER_BloomFilter * GNUNET_CONTAINER_bloomfilter_load (const char *filename, size_t size, unsigned int k); /** * Create a bloom filter from raw bits. * * @param data the raw bits in memory (maybe NULL, * in which case all bits should be considered * to be zero). * @param size the size of the bloom-filter (number of * bytes of storage space to use); also size of data * -- unless data is NULL. Must be a power of 2. * @param k the number of GNUNET_CRYPTO_hash-functions to apply per * element (number of bits set per element in the set) * @return the bloomfilter */ struct GNUNET_CONTAINER_BloomFilter * GNUNET_CONTAINER_bloomfilter_init (const char *data, size_t size, unsigned int k); /** * Copy the raw data of this bloomfilter into * the given data array. * * @param data where to write the data * @param size the size of the given data array * @return GNUNET_SYSERR if the data array of the wrong size */ int GNUNET_CONTAINER_bloomfilter_get_raw_data (const struct GNUNET_CONTAINER_BloomFilter *bf, char *data, size_t size); /** * Test if an element is in the filter. * @param e the element * @param bf the filter * @return GNUNET_YES if the element is in the filter, GNUNET_NO if not */ int GNUNET_CONTAINER_bloomfilter_test (const struct GNUNET_CONTAINER_BloomFilter *bf, const GNUNET_HashCode * e); /** * Add an element to the filter * @param bf the filter * @param e the element */ void GNUNET_CONTAINER_bloomfilter_add (struct GNUNET_CONTAINER_BloomFilter *bf, const GNUNET_HashCode * e); /** * Remove an element from the filter. * @param bf the filter * @param e the element to remove */ void GNUNET_CONTAINER_bloomfilter_remove (struct GNUNET_CONTAINER_BloomFilter *bf, const GNUNET_HashCode * e); /** * Create a copy of a bloomfilter. * * @param bf the filter * @return copy of bf */ struct GNUNET_CONTAINER_BloomFilter * GNUNET_CONTAINER_bloomfilter_copy (const struct GNUNET_CONTAINER_BloomFilter *bf); /** * Free the space associcated with a filter * in memory, flush to drive if needed (do not * free the space on the drive) * @param bf the filter */ void GNUNET_CONTAINER_bloomfilter_free (struct GNUNET_CONTAINER_BloomFilter *bf); /** * Get size of the bloom filter. * * @param bf the filter * @return number of bytes used for the data of the bloom filter */ size_t GNUNET_CONTAINER_bloomfilter_get_size (const struct GNUNET_CONTAINER_BloomFilter *bf); /** * Reset a bloom filter to empty. * @param bf the filter */ void GNUNET_CONTAINER_bloomfilter_clear (struct GNUNET_CONTAINER_BloomFilter *bf); /** * Or the entries of the given raw data array with the * data of the given bloom filter. Assumes that * the size of the data array and the current filter * match. * * @param bf the filter * @param data data to OR-in * @param size size of data * @return GNUNET_OK on success */ int GNUNET_CONTAINER_bloomfilter_or (struct GNUNET_CONTAINER_BloomFilter *bf, const char *data, size_t size); /** * Or the entries of the given raw data array with the * data of the given bloom filter. Assumes that * the size of the data array and the current filter * match. * * @param bf the filter * @param to_or the bloomfilter to or-in * @param size number of bytes in data */ int GNUNET_CONTAINER_bloomfilter_or2 (struct GNUNET_CONTAINER_BloomFilter *bf, const struct GNUNET_CONTAINER_BloomFilter *to_or, size_t size); /** * Resize a bloom filter. Note that this operation * is pretty costly. Essentially, the bloom filter * needs to be completely re-build. * * @param bf the filter * @param iterator an iterator over all elements stored in the BF * @param iterator_cls closure for iterator * @param size the new size for the filter * @param k the new number of GNUNET_CRYPTO_hash-function to apply per element */ void GNUNET_CONTAINER_bloomfilter_resize (struct GNUNET_CONTAINER_BloomFilter *bf, GNUNET_HashCodeIterator iterator, void *iterator_cls, size_t size, unsigned int k); /* ****************** metadata ******************* */ /** * Meta data to associate with a file, directory or namespace. */ struct GNUNET_CONTAINER_MetaData; /** * Create a fresh MetaData token. * * @return empty meta-data container */ struct GNUNET_CONTAINER_MetaData * GNUNET_CONTAINER_meta_data_create (void); /** * Duplicate a MetaData token. * * @param md what to duplicate * @return duplicate meta-data container */ struct GNUNET_CONTAINER_MetaData * GNUNET_CONTAINER_meta_data_duplicate (const struct GNUNET_CONTAINER_MetaData *md); /** * Free meta data. * * @param md what to free */ void GNUNET_CONTAINER_meta_data_destroy (struct GNUNET_CONTAINER_MetaData *md); /** * Test if two MDs are equal. We consider them equal if * the meta types, formats and content match (we do not * include the mime types and plugins names in this * consideration). * * @param md1 first value to check * @param md2 other value to check * @return GNUNET_YES if they are equal */ int GNUNET_CONTAINER_meta_data_test_equal (const struct GNUNET_CONTAINER_MetaData *md1, const struct GNUNET_CONTAINER_MetaData *md2); /** * Extend metadata. * * @param md metadata to extend * @param plugin_name name of the plugin that produced this value; * special values can be used (i.e. '<zlib>' for zlib being * used in the main libextractor library and yielding * meta data). * @param type libextractor-type describing the meta data * @param format basic format information about data * @param data_mime_type mime-type of data (not of the original file); * can be NULL (if mime-type is not known) * @param data actual meta-data found * @param data_len number of bytes in data * @return GNUNET_OK on success, GNUNET_SYSERR if this entry already exists * data_mime_type and plugin_name are not considered for "exists" checks */ int GNUNET_CONTAINER_meta_data_insert (struct GNUNET_CONTAINER_MetaData *md, const char *plugin_name, enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat format, const char *data_mime_type, const char *data, size_t data_len); /** * Extend metadata. Merges the meta data from the second argument * into the first, discarding duplicate key-value pairs. * * @param md metadata to extend * @param in metadata to merge */ void GNUNET_CONTAINER_meta_data_merge (struct GNUNET_CONTAINER_MetaData *md, const struct GNUNET_CONTAINER_MetaData *in); /** * Remove an item. * * @param md metadata to manipulate * @param type type of the item to remove * @param data specific value to remove, NULL to remove all * entries of the given type * @param data_len number of bytes in data * @return GNUNET_OK on success, GNUNET_SYSERR if the item does not exist in md */ int GNUNET_CONTAINER_meta_data_delete (struct GNUNET_CONTAINER_MetaData *md, enum EXTRACTOR_MetaType type, const char *data, size_t data_len); /** * Remove all items in the container. * * @param md metadata to manipulate */ void GNUNET_CONTAINER_meta_data_clear (struct GNUNET_CONTAINER_MetaData *md); /** * Add the current time as the publication date * to the meta-data. * * @param md metadata to modify */ void GNUNET_CONTAINER_meta_data_add_publication_date (struct GNUNET_CONTAINER_MetaData *md); /** * Iterate over MD entries. * * @param md metadata to inspect * @param iter function to call on each entry * @param iter_cls closure for iterator * @return number of entries */ int GNUNET_CONTAINER_meta_data_iterate (const struct GNUNET_CONTAINER_MetaData *md, EXTRACTOR_MetaDataProcessor iter, void *iter_cls); /** * Get the first MD entry of the given type. Caller * is responsible for freeing the return value. * Also, only meta data items that are strings (0-terminated) * are returned by this function. * * @param md metadata to inspect * @param type type to look for * @return NULL if no entry was found */ char * GNUNET_CONTAINER_meta_data_get_by_type (const struct GNUNET_CONTAINER_MetaData *md, enum EXTRACTOR_MetaType type); /** * Get the first matching MD entry of the given types. Caller is * responsible for freeing the return value. Also, only meta data * items that are strings (0-terminated) are returned by this * function. * * @param md metadata to inspect * @param ... -1-terminated list of types * @return NULL if we do not have any such entry, * otherwise client is responsible for freeing the value! */ char * GNUNET_CONTAINER_meta_data_get_first_by_types (const struct GNUNET_CONTAINER_MetaData *md, ...); /** * Get a thumbnail from the meta-data (if present). Only matches meta * data with mime type "image" and binary format. * * @param md metadata to inspect * @param thumb will be set to the thumbnail data. Must be * freed by the caller! * @return number of bytes in thumbnail, 0 if not available */ size_t GNUNET_CONTAINER_meta_data_get_thumbnail (const struct GNUNET_CONTAINER_MetaData *md, unsigned char **thumb); /** * Options for metadata serialization. */ enum GNUNET_CONTAINER_MetaDataSerializationOptions { /** * Serialize all of the data. */ GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL = 0, /** * If not enough space is available, it is acceptable * to only serialize some of the metadata. */ GNUNET_CONTAINER_META_DATA_SERIALIZE_PART = 1, /** * Speed is of the essence, do not allow compression. */ GNUNET_CONTAINER_META_DATA_SERIALIZE_NO_COMPRESS = 2 }; /** * Serialize meta-data to target. * * @param md metadata to serialize * @param target where to write the serialized metadata; * *target can be NULL, in which case memory is allocated * @param max maximum number of bytes available * @param opt is it ok to just write SOME of the * meta-data to match the size constraint, * possibly discarding some data? * @return number of bytes written on success, * -1 on error (typically: not enough * space) */ ssize_t GNUNET_CONTAINER_meta_data_serialize (const struct GNUNET_CONTAINER_MetaData *md, char **target, size_t max, enum GNUNET_CONTAINER_MetaDataSerializationOptions opt); /** * Get the size of the full meta-data in serialized form. * * @param md metadata to inspect * @return number of bytes needed for serialization, -1 on error */ ssize_t GNUNET_CONTAINER_meta_data_get_serialized_size (const struct GNUNET_CONTAINER_MetaData *md); /** * Deserialize meta-data. Initializes md. * * @param input serialized meta-data. * @param size number of bytes available * @return MD on success, NULL on error (i.e. * bad format) */ struct GNUNET_CONTAINER_MetaData * GNUNET_CONTAINER_meta_data_deserialize (const char *input, size_t size); /* ******************************* HashMap **************************** */ /** * Opaque handle for a HashMap. */ struct GNUNET_CONTAINER_MultiHashMap; /** * Options for storing values in the HashMap. */ enum GNUNET_CONTAINER_MultiHashMapOption { /** * If a value with the given key exists, replace it. Note that the * old value would NOT be freed by replace (the application has to * make sure that this happens if required). */ GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE, /** * Allow multiple values with the same key. */ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE, /** * There must only be one value per key; storing a value should fail * if a value under the same key already exists. */ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY, /** * There must only be one value per key, but don't bother checking * if a value already exists (faster than UNIQUE_ONLY; implemented * just like MULTIPLE but this option documents better what is * intended if UNIQUE is what is desired). */ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST }; /** * Iterator over hash map entries. * * @param cls closure * @param key current key code * @param value value in the hash map * @return GNUNET_YES if we should continue to * iterate, * GNUNET_NO if not. */ typedef int (*GNUNET_CONTAINER_HashMapIterator) (void *cls, const GNUNET_HashCode * key, void *value); /** * Create a multi hash map. * * @param len initial size (map will grow as needed) * @return NULL on error */ struct GNUNET_CONTAINER_MultiHashMap * GNUNET_CONTAINER_multihashmap_create (unsigned int len); /** * Destroy a hash map. Will not free any values * stored in the hash map! * * @param map the map */ void GNUNET_CONTAINER_multihashmap_destroy (struct GNUNET_CONTAINER_MultiHashMap *map); /** * Given a key find a value in the map matching the key. * * @param map the map * @param key what to look for * @return NULL if no value was found; note that * this is indistinguishable from values that just * happen to be NULL; use "contains" to test for * key-value pairs with value NULL */ void * GNUNET_CONTAINER_multihashmap_get (const struct GNUNET_CONTAINER_MultiHashMap *map, const GNUNET_HashCode * key); /** * Remove the given key-value pair from the map. Note that if the * key-value pair is in the map multiple times, only one of the pairs * will be removed. * * @param map the map * @param key key of the key-value pair * @param value value of the key-value pair * @return GNUNET_YES on success, GNUNET_NO if the key-value pair * is not in the map */ int GNUNET_CONTAINER_multihashmap_remove (struct GNUNET_CONTAINER_MultiHashMap *map, const GNUNET_HashCode * key, void *value); /** * Remove all entries for the given key from the map. * Note that the values would not be "freed". * * @param map the map * @param key identifies values to be removed * @return number of values removed */ int GNUNET_CONTAINER_multihashmap_remove_all (struct GNUNET_CONTAINER_MultiHashMap *map, const GNUNET_HashCode * key); /** * Check if the map contains any value under the given * key (including values that are NULL). * * @param map the map * @param key the key to test if a value exists for it * @return GNUNET_YES if such a value exists, * GNUNET_NO if not */ int GNUNET_CONTAINER_multihashmap_contains (const struct GNUNET_CONTAINER_MultiHashMap *map, const GNUNET_HashCode * key); /** * Check if the map contains the given value under the given * key. * * @param map the map * @param key the key to test if a value exists for it * @param value value to test for * @return GNUNET_YES if such a value exists, * GNUNET_NO if not */ int GNUNET_CONTAINER_multihashmap_contains_value (const struct GNUNET_CONTAINER_MultiHashMap *map, const GNUNET_HashCode * key, const void *value); /** * Store a key-value pair in the map. * * @param map the map * @param key key to use * @param value value to use * @param opt options for put * @return GNUNET_OK on success, * GNUNET_NO if a value was replaced (with REPLACE) * GNUNET_SYSERR if UNIQUE_ONLY was the option and the * value already exists */ int GNUNET_CONTAINER_multihashmap_put (struct GNUNET_CONTAINER_MultiHashMap *map, const GNUNET_HashCode * key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt); /** * Get the number of key-value pairs in the map. * * @param map the map * @return the number of key value pairs */ unsigned int GNUNET_CONTAINER_multihashmap_size (const struct GNUNET_CONTAINER_MultiHashMap *map); /** * Iterate over all entries in the map. * * @param map the map * @param it function to call on each entry * @param it_cls extra argument to it * @return the number of key value pairs processed, * GNUNET_SYSERR if it aborted iteration */ int GNUNET_CONTAINER_multihashmap_iterate (const struct GNUNET_CONTAINER_MultiHashMap *map, GNUNET_CONTAINER_HashMapIterator it, void *it_cls); /** * Iterate over all entries in the map that match a particular key. * * @param map the map * @param key key that the entries must correspond to * @param it function to call on each entry * @param it_cls extra argument to it * @return the number of key value pairs processed, * GNUNET_SYSERR if it aborted iteration */ int GNUNET_CONTAINER_multihashmap_get_multiple (const struct GNUNET_CONTAINER_MultiHashMap *map, const GNUNET_HashCode * key, GNUNET_CONTAINER_HashMapIterator it, void *it_cls); /* ******************** doubly-linked list *************** */ /* To avoid mistakes: head->prev == tail->next == NULL */ /** * Insert an element at the head of a DLL. Assumes that head, tail and * element are structs with prev and next fields. * * @param head pointer to the head of the DLL * @param tail pointer to the tail of the DLL * @param element element to insert */ #define GNUNET_CONTAINER_DLL_insert(head,tail,element) do { \ GNUNET_assert ( ( (element)->prev == NULL) && ((head) != (element))); \ GNUNET_assert ( ( (element)->next == NULL) && ((tail) != (element))); \ (element)->next = (head); \ (element)->prev = NULL; \ if ((tail) == NULL) \ (tail) = element; \ else \ (head)->prev = element; \ (head) = (element); } while (0) /** * Insert an element at the tail of a DLL. Assumes that head, tail and * element are structs with prev and next fields. * * @param head pointer to the head of the DLL * @param tail pointer to the tail of the DLL * @param element element to insert */ #define GNUNET_CONTAINER_DLL_insert_tail(head,tail,element) do { \ GNUNET_assert ( ( (element)->prev == NULL) && ((head) != (element))); \ GNUNET_assert ( ( (element)->next == NULL) && ((tail) != (element))); \ (element)->prev = (tail); \ (element)->next = NULL; \ if ((head) == NULL) \ (head) = element; \ else \ (tail)->next = element; \ (tail) = (element); } while (0) /** * Insert an element into a DLL after the given other element. Insert * at the head if the other element is NULL. * * @param head pointer to the head of the DLL * @param tail pointer to the tail of the DLL * @param other prior element, NULL for insertion at head of DLL * @param element element to insert */ #define GNUNET_CONTAINER_DLL_insert_after(head,tail,other,element) do { \ GNUNET_assert ( ( (element)->prev == NULL) && ((head) != (element))); \ GNUNET_assert ( ( (element)->next == NULL) && ((tail) != (element))); \ (element)->prev = (other); \ if (NULL == other) \ { \ (element)->next = (head); \ (head) = (element); \ } \ else \ { \ (element)->next = (other)->next; \ (other)->next = (element); \ } \ if (NULL == (element)->next) \ (tail) = (element); \ else \ (element)->next->prev = (element); } while (0) /** * Insert an element into a DLL before the given other element. Insert * at the tail if the other element is NULL. * * @param head pointer to the head of the DLL * @param tail pointer to the tail of the DLL * @param other prior element, NULL for insertion at head of DLL * @param element element to insert */ #define GNUNET_CONTAINER_DLL_insert_before(head,tail,other,element) do { \ GNUNET_assert ( ( (element)->prev == NULL) && ((head) != (element))); \ GNUNET_assert ( ( (element)->next == NULL) && ((tail) != (element))); \ (element)->next = (other); \ if (NULL == other) \ { \ (element)->prev = (tail); \ (tail) = (element); \ } \ else \ { \ (element)->prev = (other)->prev; \ (other)->prev = (element); \ } \ if (NULL == (element)->prev) \ (head) = (element); \ else \ (element)->prev->next = (element); } while (0) /** * Remove an element from a DLL. Assumes * that head, tail and element are structs * with prev and next fields. * * @param head pointer to the head of the DLL * @param tail pointer to the tail of the DLL * @param element element to remove */ #define GNUNET_CONTAINER_DLL_remove(head,tail,element) do { \ GNUNET_assert ( ( (element)->prev != NULL) || ((head) == (element))); \ GNUNET_assert ( ( (element)->next != NULL) || ((tail) == (element))); \ if ((element)->prev == NULL) \ (head) = (element)->next; \ else \ (element)->prev->next = (element)->next; \ if ((element)->next == NULL) \ (tail) = (element)->prev; \ else \ (element)->next->prev = (element)->prev; \ (element)->next = NULL; \ (element)->prev = NULL; } while (0) /* ******************** Heap *************** */ /** * Cost by which elements in a heap can be ordered. */ typedef uint64_t GNUNET_CONTAINER_HeapCostType; /* * Heap type, either max or min. Hopefully makes the * implementation more useful. */ enum GNUNET_CONTAINER_HeapOrder { /** * Heap with the maximum cost at the root. */ GNUNET_CONTAINER_HEAP_ORDER_MAX, /** * Heap with the minimum cost at the root. */ GNUNET_CONTAINER_HEAP_ORDER_MIN }; /** * Handle to a Heap. */ struct GNUNET_CONTAINER_Heap; /** * Handle to a node in a heap. */ struct GNUNET_CONTAINER_HeapNode; /** * Create a new heap. * * @param order how should the heap be sorted? * @return handle to the heap */ struct GNUNET_CONTAINER_Heap * GNUNET_CONTAINER_heap_create (enum GNUNET_CONTAINER_HeapOrder order); /** * Destroys the heap. Only call on a heap that * is already empty. * * @param heap heap to destroy */ void GNUNET_CONTAINER_heap_destroy (struct GNUNET_CONTAINER_Heap *heap); /** * Get element stored at root of heap. * * @param heap heap to inspect * @return NULL if heap is empty */ void * GNUNET_CONTAINER_heap_peek (const struct GNUNET_CONTAINER_Heap *heap); /** * Get the current size of the heap * * @param heap the heap to get the size of * @return number of elements stored */ unsigned int GNUNET_CONTAINER_heap_get_size (const struct GNUNET_CONTAINER_Heap *heap); /** * Get the current cost of the node * * @param node the node to get the cost of * @return cost of the node */ GNUNET_CONTAINER_HeapCostType GNUNET_CONTAINER_heap_node_get_cost (const struct GNUNET_CONTAINER_HeapNode *node); /** * Iterator for heap * * @param cls closure * @param node internal node of the heap * @param element value stored at the node * @param cost cost associated with the node * @return GNUNET_YES if we should continue to iterate, * GNUNET_NO if not. */ typedef int (*GNUNET_CONTAINER_HeapIterator) (void *cls, struct GNUNET_CONTAINER_HeapNode * node, void *element, GNUNET_CONTAINER_HeapCostType cost); /** * Iterate over all entries in the heap. * * @param heap the heap * @param iterator function to call on each entry * @param iterator_cls closure for iterator */ void GNUNET_CONTAINER_heap_iterate (const struct GNUNET_CONTAINER_Heap *heap, GNUNET_CONTAINER_HeapIterator iterator, void *iterator_cls); /** * Return a *uniform* random element from the heap. Choose a random * number between 0 and heap size and then walk directly to it. * This cost can be between 0 and n, amortized cost of logN. * * @param heap heap to choose random element from * @param max how many nodes from the heap to choose from * * @return data stored at the chosen random node, * NULL if the heap is empty. * */ void * GNUNET_CONTAINER_heap_get_random (struct GNUNET_CONTAINER_Heap *heap, uint32_t max); /** * Perform a random walk of the tree. The walk is biased * towards elements closer to the root of the tree (since * each walk starts at the root and ends at a random leaf). * The heap internally tracks the current position of the * walk. * * @param heap heap to walk * @return data stored at the next random node in the walk; * NULL if the tree is empty. */ void * GNUNET_CONTAINER_heap_walk_get_next (struct GNUNET_CONTAINER_Heap *heap); /** * Inserts a new element into the heap. * * @param heap heap to modify * @param element element to insert * @param cost cost for the element * @return node for the new element */ struct GNUNET_CONTAINER_HeapNode * GNUNET_CONTAINER_heap_insert (struct GNUNET_CONTAINER_Heap *heap, void *element, GNUNET_CONTAINER_HeapCostType cost); /** * Remove root of the heap. * * @param heap heap to modify * @return element data stored at the root node */ void * GNUNET_CONTAINER_heap_remove_root (struct GNUNET_CONTAINER_Heap *heap); /** * Removes a node from the heap. * * @param node node to remove * @return element data stored at the node, NULL if heap is empty */ void * GNUNET_CONTAINER_heap_remove_node (struct GNUNET_CONTAINER_HeapNode *node); /** * Updates the cost of any node in the tree * * @param heap heap to modify * @param node node for which the cost is to be changed * @param new_cost new cost for the node */ void GNUNET_CONTAINER_heap_update_cost (struct GNUNET_CONTAINER_Heap *heap, struct GNUNET_CONTAINER_HeapNode *node, GNUNET_CONTAINER_HeapCostType new_cost); /* ******************** Singly linked list *************** */ /** * Possible ways for how data stored in the linked list * might be allocated. */ enum GNUNET_CONTAINER_SListDisposition { /** * Single-linked list must copy the buffer. */ GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT = 0, /** * Data is static, no need to copy or free. */ GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC = 2, /** * Data is dynamic, do not copy but free when done. */ GNUNET_CONTAINER_SLIST_DISPOSITION_DYNAMIC = 4 }; /** * Handle to a singly linked list */ struct GNUNET_CONTAINER_SList; /** * Handle to a singly linked list iterator */ struct GNUNET_CONTAINER_SList_Iterator { /** * Linked list that we are iterating over. */ struct GNUNET_CONTAINER_SList *list; /** * Last element accessed. */ struct GNUNET_CONTAINER_SList_Elem *last; /** * Current list element. */ struct GNUNET_CONTAINER_SList_Elem *elem; }; /** * Add a new element to the list * @param l list * @param disp memory disposition * @param buf payload buffer * @param len length of the buffer */ void GNUNET_CONTAINER_slist_add (struct GNUNET_CONTAINER_SList *l, enum GNUNET_CONTAINER_SListDisposition disp, const void *buf, size_t len); /** * Add a new element to the end of the list * @param l list * @param disp memory disposition * @param buf payload buffer * @param len length of the buffer */ void GNUNET_CONTAINER_slist_add_end (struct GNUNET_CONTAINER_SList *l, enum GNUNET_CONTAINER_SListDisposition disp, const void *buf, size_t len); /** * Append a singly linked list to another * @param dst list to append to * @param src source */ void GNUNET_CONTAINER_slist_append (struct GNUNET_CONTAINER_SList *dst, struct GNUNET_CONTAINER_SList *src); /** * Create a new singly linked list * @return the new list */ struct GNUNET_CONTAINER_SList * GNUNET_CONTAINER_slist_create (void); /** * Destroy a singly linked list * @param l the list to be destroyed */ void GNUNET_CONTAINER_slist_destroy (struct GNUNET_CONTAINER_SList *l); /** * Return the beginning of a list * * @param l list * @return iterator pointing to the beginning (by value! Either allocate the * structure on the stack, or use GNUNET_malloc() yourself! All other * functions do take pointer to this struct though) */ struct GNUNET_CONTAINER_SList_Iterator GNUNET_CONTAINER_slist_begin (struct GNUNET_CONTAINER_SList *l); /** * Clear a list * * @param l list */ void GNUNET_CONTAINER_slist_clear (struct GNUNET_CONTAINER_SList *l); /** * Check if a list contains a certain element * @param l list * @param buf payload buffer to find * @param len length of the payload (number of bytes in buf) * * @return GNUNET_YES if found, GNUNET_NO otherwise */ int GNUNET_CONTAINER_slist_contains (const struct GNUNET_CONTAINER_SList *l, const void *buf, size_t len); /** * Check if a list contains a certain element using 'compare' function * * @param l list * @param buf payload buffer to find * @param len length of the payload (number of bytes in buf) * @param compare comparison function * * @return NULL if the 'buf' could not be found, pointer to the * list element, if found */ void * GNUNET_CONTAINER_slist_contains2 (const struct GNUNET_CONTAINER_SList *l, const void *buf, size_t len, int (*compare)(const void *, const size_t, const void *, const size_t)); /** * Count the elements of a list * @param l list * @return number of elements in the list */ int GNUNET_CONTAINER_slist_count (const struct GNUNET_CONTAINER_SList *l); /** * Remove an element from the list * @param i iterator that points to the element to be removed */ void GNUNET_CONTAINER_slist_erase (struct GNUNET_CONTAINER_SList_Iterator *i); /** * Insert an element into a list at a specific position * @param before where to insert the new element * @param disp memory disposition * @param buf payload buffer * @param len length of the payload */ void GNUNET_CONTAINER_slist_insert (struct GNUNET_CONTAINER_SList_Iterator *before, enum GNUNET_CONTAINER_SListDisposition disp, const void *buf, size_t len); /** * Advance an iterator to the next element * @param i iterator * @return GNUNET_YES on success, GNUNET_NO if the end has been reached */ int GNUNET_CONTAINER_slist_next (struct GNUNET_CONTAINER_SList_Iterator *i); /** * Check if an iterator points beyond the end of a list * @param i iterator * @return GNUNET_YES if the end has been reached, GNUNET_NO if the iterator * points to a valid element */ int GNUNET_CONTAINER_slist_end (struct GNUNET_CONTAINER_SList_Iterator *i); /** * Retrieve the element at a specific position in a list * * @param i iterator * @param len set to the payload length * @return payload */ void * GNUNET_CONTAINER_slist_get (const struct GNUNET_CONTAINER_SList_Iterator *i, size_t * len); /** * Release an iterator * @param i iterator */ void GNUNET_CONTAINER_slist_iter_destroy (struct GNUNET_CONTAINER_SList_Iterator *i); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_CONTAINER_LIB_H */ #endif /* end of gnunet_container_lib.h */ gnunet-0.9.3/src/include/gnunet_signatures.h0000644000175000017500000000616011760502551016100 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_signatures.h * @brief constants for network signatures * @author Christian Grothoff */ #ifndef GNUNET_SIGNATURES_H #define GNUNET_SIGNATURES_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * Test signature, not valid for anything other than writing * a test. (Note that the signature verification code will * accept this value). */ #define GNUNET_SIGNATURE_PURPOSE_TEST 0 /** * Signature for confirming that this peer uses a particular address. */ #define GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN 1 /** * Signature for confirming that this peer intends to disconnect. */ #define GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DISCONNECT 2 /** * Purpose is to set a session key. */ #define GNUNET_SIGNATURE_PURPOSE_SET_KEY 3 /** * Signature for a namespace/pseudonym advertisement (by * the namespace owner). */ #define GNUNET_SIGNATURE_PURPOSE_NAMESPACE_ADVERTISEMENT 4 /** * Signature by which a peer affirms that it is * providing a certain bit of content (used * in LOCation URIs). */ #define GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT 5 /** * Signature in a KBlock of the FS module. */ #define GNUNET_SIGNATURE_PURPOSE_FS_KBLOCK 6 /** * Signature of content URI placed into a namespace. */ #define GNUNET_SIGNATURE_PURPOSE_FS_SBLOCK 7 /** * Signature of advertisment for a namespace. */ #define GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK 8 /** * Keyword-based signature of advertisment for a namespace. */ #define GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK_KSIG 9 /** * */ #define GNUNET_SIGNATURE_PURPOSE_RESOLVER_RESPONSE 10 /** * Signature of an GNUNET_DNS_Record */ #define GNUNET_SIGNATURE_PURPOSE_DNS_RECORD 11 /** * Signature of a chat message. */ #define GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE 12 /** * Signature of confirmation receipt for a chat message. */ #define GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT 13 /** * Signature of a network size estimate message. */ #define GNUNET_SIGNATURE_PURPOSE_NSE_SEND 14 /** * Signature of a gnunet naming system record block */ #define GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN 15 #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_SIGNATURES_H */ #endif /* end of gnunet_signatures.h */ gnunet-0.9.3/src/include/gnunet_peer_lib.h0000644000175000017500000000517511760502551015502 00000000000000/* This file is part of GNUnet. (C) 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_peer_lib.h * @brief helper library for interning of peer identifiers * @author Christian Grothoff */ #ifndef GNUNET_PEER_LIB_H #define GNUNET_PEER_LIB_H #include "gnunet_util_lib.h" #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * A GNUNET_PEER_Id is simply a shorter * version of a "struct GNUNET_PeerIdentifier" * that can be used inside of a GNUnet peer * to save memory when the same identifier * needs to be used over and over again. */ typedef unsigned int GNUNET_PEER_Id; /** * Search for a peer identity. The reference counter is not changed. * * @param pid identity to find * @return the interned identity or 0. */ GNUNET_PEER_Id GNUNET_PEER_search (const struct GNUNET_PeerIdentity *pid); /** * Intern an peer identity. If the identity is already known, its * reference counter will be increased by one. * * @param pid identity to intern * @return the interned identity. */ GNUNET_PEER_Id GNUNET_PEER_intern (const struct GNUNET_PeerIdentity *pid); /** * Change the reference counter of an interned PID. * * @param id identity to change the RC of * @param delta how much to change the RC */ void GNUNET_PEER_change_rc (GNUNET_PEER_Id id, int delta); /** * Decrement multiple RCs of peer identities by one. * * @param ids array of PIDs to decrement the RCs of * @param count size of the ids array */ void GNUNET_PEER_decrement_rcs (const GNUNET_PEER_Id *ids, unsigned int count); /** * Convert an interned PID to a normal peer identity. * * @param id interned PID to convert * @param pid where to write the normal peer identity */ void GNUNET_PEER_resolve (GNUNET_PEER_Id id, struct GNUNET_PeerIdentity *pid); /* ifndef GNUNET_PEER_LIB_H */ #endif /* end of gnunet_peer_lib.h */ gnunet-0.9.3/src/include/gnunet_nat_lib.h0000644000175000017500000002032111760502551015317 00000000000000/* This file is part of GNUnet. (C) 2007, 2008, 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_nat_lib.h * @brief Library handling UPnP and NAT-PMP port forwarding and * external IP address retrieval * * @author Milan Bouchet-Valat */ #ifndef GNUNET_NAT_LIB_H #define GNUNET_NAT_LIB_H #include "gnunet_util_lib.h" /** * Signature of the callback passed to GNUNET_NAT_register for * a function to call whenever our set of 'valid' addresses changes. * * @param cls closure * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean * the previous (now invalid) one * @param addr either the previous or the new public IP address * @param addrlen actual lenght of the address */ typedef void (*GNUNET_NAT_AddressCallback) (void *cls, int add_remove, const struct sockaddr * addr, socklen_t addrlen); /** * Signature of the callback passed to GNUNET_NAT_register * for a function to call whenever someone asks us to do connection * reversal. * * @param cls closure * @param addr public IP address of the other peer * @param addrlen actual lenght of the address */ typedef void (*GNUNET_NAT_ReversalCallback) (void *cls, const struct sockaddr * addr, socklen_t addrlen); /** * Handle for active NAT registrations. */ struct GNUNET_NAT_Handle; /** * Attempt to enable port redirection and detect public IP address contacting * UPnP or NAT-PMP routers on the local network. Use addr to specify to which * of the local host's addresses should the external port be mapped. The port * is taken from the corresponding sockaddr_in[6] field. The NAT module * should call the given callback for any 'plausible' external address. * * @param cfg configuration to use * @param is_tcp GNUNET_YES for TCP, GNUNET_NO for UDP * @param adv_port advertised port (port we are either bound to or that our OS * locally performs redirection from to our bound port). * @param num_addrs number of addresses in 'addrs' * @param addrs list of local addresses packets should be redirected to * @param addrlens actual lengths of the addresses * @param address_callback function to call everytime the public IP address changes * @param reversal_callback function to call if someone wants connection reversal from us, * NULL if connection reversal is not supported * @param callback_cls closure for callback * @return NULL on error, otherwise handle that can be used to unregister */ struct GNUNET_NAT_Handle * GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg, int is_tcp, uint16_t adv_port, unsigned int num_addrs, const struct sockaddr **addrs, const socklen_t * addrlens, GNUNET_NAT_AddressCallback address_callback, GNUNET_NAT_ReversalCallback reversal_callback, void *callback_cls); /** * Test if the given address is (currently) a plausible IP address for this peer. * * @param h the handle returned by register * @param addr IP address to test (IPv4 or IPv6) * @param addrlen number of bytes in addr * @return GNUNET_YES if the address is plausible, * GNUNET_NO if the address is not plausible, * GNUNET_SYSERR if the address is malformed */ int GNUNET_NAT_test_address (struct GNUNET_NAT_Handle *h, const void *addr, socklen_t addrlen); /** * We learned about a peer (possibly behind NAT) so run the * gnunet-nat-client to send dummy ICMP responses to cause * that peer to connect to us (connection reversal). * * @param h handle (used for configuration) * @param sa the address of the peer (IPv4-only) * * @return GNUNET_SYSERR on error, GNUNET_NO if nat client is disabled, * GNUNET_OK otherwise */ int GNUNET_NAT_run_client (struct GNUNET_NAT_Handle *h, const struct sockaddr_in *sa); /** * Stop port redirection and public IP address detection for the given handle. * This frees the handle, after having sent the needed commands to close open ports. * * @param h the handle to stop */ void GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *h); /** * Handle to a NAT test. */ struct GNUNET_NAT_Test; /** * Function called to report success or failure for * NAT configuration test. * * @param cls closure * @param success GNUNET_OK on success, GNUNET_NO on failure, * GNUNET_SYSERR if the test could not be * properly started (internal failure) */ typedef void (*GNUNET_NAT_TestCallback) (void *cls, int success); /** * Start testing if NAT traversal works using the * given configuration (IPv4-only). * * @param cfg configuration for the NAT traversal * @param is_tcp GNUNET_YES to test TCP, GNUNET_NO to test UDP * @param bnd_port port to bind to, 0 for connection reversal * @param adv_port externally advertised port to use * @param report function to call with the result of the test * @param report_cls closure for report * @return handle to cancel NAT test */ struct GNUNET_NAT_Test * GNUNET_NAT_test_start (const struct GNUNET_CONFIGURATION_Handle *cfg, int is_tcp, uint16_t bnd_port, uint16_t adv_port, GNUNET_NAT_TestCallback report, void *report_cls); /** * Stop an active NAT test. * * @param tst test to stop. */ void GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst); /** * Signature of a callback that is given an IP address. * * @param cls closure * @param addr the address, NULL on errors */ typedef void (*GNUNET_NAT_IPCallback) (void *cls, const struct in_addr * addr); /** * Opaque handle to cancel "GNUNET_NAT_mini_get_external_ipv4" operation. */ struct GNUNET_NAT_ExternalHandle; /** * Try to get the external IPv4 address of this peer. * * @param timeout when to fail * @param cb function to call with result * @param cb_cls closure for 'cb' * @return handle for cancellation (can only be used until 'cb' is called), NULL on error */ struct GNUNET_NAT_ExternalHandle * GNUNET_NAT_mini_get_external_ipv4 (struct GNUNET_TIME_Relative timeout, GNUNET_NAT_IPCallback cb, void *cb_cls); /** * Cancel operation. * * @param eh operation to cancel */ void GNUNET_NAT_mini_get_external_ipv4_cancel (struct GNUNET_NAT_ExternalHandle *eh); /** * Handle to a mapping created with upnpc. */ struct GNUNET_NAT_MiniHandle; /** * Start mapping the given port using (mini)upnpc. This function * should typically not be used directly (it is used within the * general-purpose 'GNUNET_NAT_register' code). However, it can be * used if specifically UPnP-based NAT traversal is to be used or * tested. * * @param port port to map * @param is_tcp GNUNET_YES to map TCP, GNUNET_NO for UDP * @param ac function to call with mapping result * @param ac_cls closure for 'ac' * @return NULL on error */ struct GNUNET_NAT_MiniHandle * GNUNET_NAT_mini_map_start (uint16_t port, int is_tcp, GNUNET_NAT_AddressCallback ac, void *ac_cls); /** * Remove a mapping created with (mini)upnpc. Calling * this function will give 'upnpc' 1s to remove tha mapping, * so while this function is non-blocking, a task will be * left with the scheduler for up to 1s past this call. * * @param mini the handle */ void GNUNET_NAT_mini_map_stop (struct GNUNET_NAT_MiniHandle *mini); #endif /* end of gnunet_nat_lib.h */ gnunet-0.9.3/src/include/gnunet_transport_plugin.h0000644000175000017500000004737511761753145017353 00000000000000/* This file is part of GNUnet (C) 2009, 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_transport_plugin.h * @brief API for the transport services. This header * specifies the struct that is given to the plugin's entry * method and the other struct that must be returned. * Note that the destructors of transport plugins will * be given the value returned by the constructor * and is expected to return a NULL pointer. * @author Christian Grothoff */ #ifndef PLUGIN_TRANSPORT_H #define PLUGIN_TRANSPORT_H #include "gnunet_configuration_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_statistics_service.h" #include "gnunet_transport_service.h" /** * Opaque pointer that plugins can use to distinguish specific * connections to a given peer. Typically used by stateful plugins to * allow the service to refer to specific streams instead of a more * general notion of "some connection" to the given peer. This is * useful since sometimes (i.e. for inbound TCP connections) a * connection may not have an address that can be used for meaningful * distinction between sessions to the same peer. */ struct Session; /** * Every 'struct Session' must begin with this header. */ struct SessionHeader { /** * Cached signature for PONG generation for the session. Do not use * in the plugin! */ struct GNUNET_CRYPTO_RsaSignature pong_signature; /** * Expiration time for signature. Do not use in the plugin! */ struct GNUNET_TIME_Absolute pong_sig_expires; }; /** * Function that will be called whenever the plugin internally * cleans up a session pointer and hence the service needs to * discard all of those sessions as well. Plugins that do not * use sessions can simply omit calling this function and always * use NULL wherever a session pointer is needed. This function * should be called BEFORE a potential "TransmitContinuation" * from the "TransmitFunction". * * @param cls closure * @param peer which peer was the session for * @param session which session is being destoyed */ typedef void (*GNUNET_TRANSPORT_SessionEnd) (void *cls, const struct GNUNET_PeerIdentity * peer, struct Session * session); /** * Function called by the transport for each received message. * This function should also be called with "NULL" for the * message to signal that the other peer disconnected. * * @param cls closure * @param peer (claimed) identity of the other peer * @param message the message, NULL if we only care about * learning about the delay until we should receive again * @param session identifier used for this session (NULL for plugins * that do not offer bi-directional communication to the sender * using the same "connection") * @param sender_address binary address of the sender (if we established the * connection or are otherwise sure of it; should be NULL * for inbound TCP/UDP connections since it it not clear * that we could establish ourselves a connection to that * IP address and get the same system) * @param sender_address_len number of bytes in sender_address * @return how long the plugin should wait until receiving more data * (plugins that do not support this, can ignore the return value) */ typedef struct GNUNET_TIME_Relative (*GNUNET_TRANSPORT_PluginReceiveCallback) (void *cls, const struct GNUNET_PeerIdentity * peer, const struct GNUNET_MessageHeader * message, const struct GNUNET_ATS_Information * ats, uint32_t ats_count, struct Session * session, const char *sender_address, uint16_t sender_address_len); /** * Function that will be called to figure if an address is an loopback, * LAN, WAN etc. address * * @param cls closure * @param addr binary address * @param addrlen length of the address * @return ATS Information containing the network type */ typedef struct GNUNET_ATS_Information (*GNUNET_TRANSPORT_AddressToType) (void *cls, const struct sockaddr *addr, size_t addrlen); /** * Function that will be called for each address the transport * is aware that it might be reachable under. * * @param cls closure * @param add_remove should the address added (YES) or removed (NO) from the * set of valid addresses? * @param addr one of the addresses of the host * the specific address format depends on the transport * @param addrlen length of the address */ typedef void (*GNUNET_TRANSPORT_AddressNotification) (void *cls, int add_remove, const void *addr, size_t addrlen); /** * Function that will be called whenever the plugin receives data over * the network and wants to determine how long it should wait until * the next time it reads from the given peer. Note that some plugins * (such as UDP) may not be able to wait (for a particular peer), so * the waiting part is optional. Plugins that can wait should call * this function, sleep the given amount of time, and call it again * (with zero bytes read) UNTIL it returns zero and only then read. * * @param cls closure * @param peer which peer did we read data from * @param amount_recved number of bytes read (can be zero) * @return how long to wait until reading more from this peer * (to enforce inbound quotas) */ typedef struct GNUNET_TIME_Relative (*GNUNET_TRANSPORT_TrafficReport) (void *cls, const struct GNUNET_PeerIdentity * peer, size_t amount_recved); /** * Function that returns a HELLO message. */ typedef const struct GNUNET_MessageHeader *(*GNUNET_TRANSPORT_GetHelloCallback) (void); /** * The transport service will pass a pointer to a struct * of this type as the first and only argument to the * entry point of each transport plugin. */ struct GNUNET_TRANSPORT_PluginEnvironment { /** * Configuration to use. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Identity of this peer. */ const struct GNUNET_PeerIdentity *my_identity; /** * Closure for the various callbacks. */ void *cls; /** * Handle for reporting statistics. */ struct GNUNET_STATISTICS_Handle *stats; /** * Function that should be called by the transport plugin * whenever a message is received. If this field is "NULL", * the plugin should load in 'stub' mode and NOT fully * initialize and instead only return an API with the * 'address_pretty_printer', 'address_to_string' and * 'string_to_address' functions. */ GNUNET_TRANSPORT_PluginReceiveCallback receive; /** * Function that returns our HELLO. */ GNUNET_TRANSPORT_GetHelloCallback get_our_hello; /** * Function that must be called by each plugin to notify the * transport service about the addresses under which the transport * provided by the plugin can be reached. */ GNUNET_TRANSPORT_AddressNotification notify_address; /** * Function that must be called by the plugin when a non-NULL * session handle stops being valid (is destroyed). */ GNUNET_TRANSPORT_SessionEnd session_end; /** * Function that will be called to figure if an address is an loopback, * LAN, WAN etc. address */ GNUNET_TRANSPORT_AddressToType get_address_type; /** * What is the maximum number of connections that this transport * should allow? Transports that do not have sessions (such as * UDP) can ignore this value. */ uint32_t max_connections; }; /** * Function called by the GNUNET_TRANSPORT_TransmitFunction * upon "completion". In the case that a peer disconnects, * this function must be called for each pending request * (with a 'failure' indication) AFTER notifying the service * about the disconnect event (so that the service won't try * to transmit more messages, believing the connection still * exists...). * * @param cls closure * @param target who was the recipient of the message? * @param result GNUNET_OK on success * GNUNET_SYSERR if the target disconnected; * disconnect will ALSO be signalled using * the ReceiveCallback. */ typedef void (*GNUNET_TRANSPORT_TransmitContinuation) (void *cls, const struct GNUNET_PeerIdentity * target, int result); /** * The new send function with just the session and no address * * Function that can be used by the transport service to transmit * a message using the plugin. Note that in the case of a * peer disconnecting, the continuation MUST be called * prior to the disconnect notification itself. This function * will be called with this peer's HELLO message to initiate * a fresh connection to another peer. * * @param cls closure * @param session which session must be used * @param msgbuf the message to transmit * @param msgbuf_size number of bytes in 'msgbuf' * @param priority how important is the message (most plugins will * ignore message priority and just FIFO) * @param timeout how long to wait at most for the transmission (does not * require plugins to discard the message after the timeout, * just advisory for the desired delay; most plugins will ignore * this as well) * @param cont continuation to call once the message has * been transmitted (or if the transport is ready * for the next transmission call; or if the * peer disconnected...); can be NULL * @param cont_cls closure for cont * @return number of bytes used (on the physical network, with overheads); * -1 on hard errors (i.e. address invalid); 0 is a legal value * and does NOT mean that the message was not transmitted (DV) */ typedef ssize_t (*GNUNET_TRANSPORT_TransmitFunction) (void *cls, struct Session *session, const char *msgbuf, size_t msgbuf_size, unsigned int priority, struct GNUNET_TIME_Relative to, GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls); /** * Function that can be called to force a disconnect from the * specified neighbour. This should also cancel all previously * scheduled transmissions. Obviously the transmission may have been * partially completed already, which is OK. The plugin is supposed * to close the connection (if applicable) and no longer call the * transmit continuation(s). * * Finally, plugin MUST NOT call the services's receive function to * notify the service that the connection to the specified target was * closed after a getting this call. * * @param cls closure * @param target peer for which the last transmission is * to be cancelled */ typedef void (*GNUNET_TRANSPORT_DisconnectFunction) (void *cls, const struct GNUNET_PeerIdentity * target); /** * Function called by the pretty printer for the resolved address for * each human-readable address obtained. * * @param cls closure * @param hostname one of the names for the host, NULL * on the last call to the callback */ typedef void (*GNUNET_TRANSPORT_AddressStringCallback) (void *cls, const char *address); /** * Convert the transports address to a nice, human-readable * format. * * @param cls closure * @param name name of the transport that generated the address * @param addr one of the addresses of the host, NULL for the last address * the specific address format depends on the transport * @param addrlen length of the address * @param numeric should (IP) addresses be displayed in numeric form? * @param timeout after how long should we give up? * @param asc function to call on each string * @param asc_cls closure for asc */ typedef void (*GNUNET_TRANSPORT_AddressPrettyPrinter) (void *cls, const char *type, const void *addr, size_t addrlen, int numeric, struct GNUNET_TIME_Relative timeout, GNUNET_TRANSPORT_AddressStringCallback asc, void *asc_cls); /** * Another peer has suggested an address for this peer and transport * plugin. Check that this could be a valid address. This function * is not expected to 'validate' the address in the sense of trying to * connect to it but simply to see if the binary format is technically * legal for establishing a connection to this peer (and make sure that * the address really corresponds to our network connection/settings * and not some potential man-in-the-middle). * * @param addr pointer to the address * @param addrlen length of addr * @return GNUNET_OK if this is a plausible address for this peer * and transport, GNUNET_SYSERR if not */ typedef int (*GNUNET_TRANSPORT_CheckAddress) (void *cls, const void *addr, size_t addrlen); /** * Create a new session to transmit data to the target * This session will used to send data to this peer and the plugin will * notify us by calling the env->session_end function * * @param cls the plugin * @param target the neighbour id * @param addr pointer to the address * @param addrlen length of addr * @return the session if the address is valid, NULL otherwise */ typedef struct Session * (*GNUNET_TRANSPORT_CreateSession) (void *cls, const struct GNUNET_HELLO_Address *address); /** * Function called for a quick conversion of the binary address to * a numeric address. Note that the caller must not free the * address and that the next call to this function is allowed * to override the address again. * * @param cls closure * @param addr binary address * @param addr_len length of the address * @return string representing the same address */ typedef const char *(*GNUNET_TRANSPORT_AddressToString) (void *cls, const void *addr, size_t addrlen); /** * Function called to convert a string address to * a binary address. * * @param cls closure ('struct Plugin*') * @param addr string address * @param addrlen length of the address * @param buf location to store the buffer * If the function returns GNUNET_SYSERR, its contents are undefined. * @param added length of created address * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ typedef int (*GNUNET_TRANSPORT_StringToAddress) (void *cls, const char *addr, uint16_t addrlen, void **buf, size_t *added); /** * Each plugin is required to return a pointer to a struct of this * type as the return value from its entry point. */ struct GNUNET_TRANSPORT_PluginFunctions { /** * Closure for all of the callbacks. */ void *cls; /** * Function that the transport service will use to transmit data to * another peer. May be NULL for plugins that only support * receiving data. After this call, the plugin call the specified * continuation with success or error before notifying us about the * target having disconnected. */ GNUNET_TRANSPORT_TransmitFunction send; /** * Function that can be used to force the plugin to disconnect from * the given peer and cancel all previous transmissions (and their * continuations). */ GNUNET_TRANSPORT_DisconnectFunction disconnect; /** * Function to pretty-print addresses. NOTE: this function is not * yet used by transport-service, but will be used in the future * once the transport-API has been completed. */ GNUNET_TRANSPORT_AddressPrettyPrinter address_pretty_printer; /** * Function that will be called to check if a binary address * for this plugin is well-formed and corresponds to an * address for THIS peer (as per our configuration). Naturally, * if absolutely necessary, plugins can be a bit conservative in * their answer, but in general plugins should make sure that the * address does not redirect traffic to a 3rd party that might * try to man-in-the-middle our traffic. */ GNUNET_TRANSPORT_CheckAddress check_address; /** * Function that will be called to convert a binary address * to a string (numeric conversion only). */ GNUNET_TRANSPORT_AddressToString address_to_string; /** * Function that will be called to convert a string address * to binary (numeric conversion only). */ GNUNET_TRANSPORT_StringToAddress string_to_address; /** * Function that will be called tell the plugin to create a session * object */ GNUNET_TRANSPORT_CreateSession get_session; }; #endif gnunet-0.9.3/src/include/gnunet_lockmanager_service.h0000644000175000017500000001144411760502551017720 00000000000000/* This file is part of GNUnet. (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_lockmanager_service.h * @brief API for the lockmanger service * @author Sree Harsha Totakura */ #ifndef GNUNET_LOCKMANAGER_SERVICE_H #define GNUNET_LOCKMANAGER_SERVICE_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_configuration_lib.h" /** * Opaque handle for the lockmanager service */ struct GNUNET_LOCKMANAGER_Handle; /** * Connect to the lockmanager service * * @param cfg the configuration to use * * @return upon success the handle to the service; NULL upon error */ struct GNUNET_LOCKMANAGER_Handle * GNUNET_LOCKMANAGER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); /** * Disconnect from the lockmanager service * * @param handle the handle to the lockmanager service */ void GNUNET_LOCKMANAGER_disconnect (struct GNUNET_LOCKMANAGER_Handle *handle); /** * Enumeration for status */ enum GNUNET_LOCKMANAGER_Status { /** * Signifies a successful operation */ GNUNET_LOCKMANAGER_SUCCESS = 1, /** * Used to signal that a lock is no longer valid. It must then be released */ GNUNET_LOCKMANAGER_RELEASE }; /** * This callback will be called when a lock has been successfully acquired or * when an acquired lock has been lost (happens when the lockmanager service * crashes/restarts). * * @param cls the closure from GNUNET_LOCKMANAGER_lock call * * @param domain_name the locking domain of the lock * * @param lock the lock for which this status is relevant * * @param status GNUNET_LOCKMANAGER_SUCCESS if the lock has been successfully * acquired; GNUNET_LOCKMANAGER_RELEASE when the acquired lock is lost */ typedef void (*GNUNET_LOCKMANAGER_StatusCallback) (void *cls, const char *domain_name, uint32_t lock, enum GNUNET_LOCKMANAGER_Status status); /** * Opaque handle to locking request */ struct GNUNET_LOCKMANAGER_LockingRequest; /** * Tries to acquire the given lock(even if the lock has been lost) until the * request is called. If the lock is available the status_cb will be * called. If the lock is busy then the request is queued and status_cb * will be called when the lock has been made available and acquired by us. * * @param handle the handle to the lockmanager service * * @param domain_name name of the locking domain. Clients who want to share * locks must use the same name for the locking domain. Also the * domain_name should be selected with the prefix * "GNUNET__" to avoid domain name collisions. * * * @param lock which lock to lock * * @param status_cb the callback for signalling when the lock is acquired and * when it is lost * * @param status_cb_cls the closure to the above callback * * @return the locking request handle for this request */ struct GNUNET_LOCKMANAGER_LockingRequest * GNUNET_LOCKMANAGER_acquire_lock (struct GNUNET_LOCKMANAGER_Handle *handle, const char *domain_name, uint32_t lock, GNUNET_LOCKMANAGER_StatusCallback status_cb, void *status_cb_cls); /** * Function to cancel the locking request generated by * GNUNET_LOCKMANAGER_acquire_lock. If the lock is acquired us then the lock is * released. GNUNET_LOCKMANAGER_StatusCallback will not be called upon any * status changes resulting due to this call. * * @param request the LockingRequest to cancel */ void GNUNET_LOCKMANAGER_cancel_request (struct GNUNET_LOCKMANAGER_LockingRequest *request); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_LOCKMANAGER_SERVICE_H */ #endif /* end of gnunet_lockmanager_service.h */ gnunet-0.9.3/src/include/gettext.h0000644000175000017500000000601711760502551014021 00000000000000/* Convenience header for conditional use of GNU . Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _LIBGETTEXT_H #define _LIBGETTEXT_H 1 /* NLS can be disabled through the configure --disable-nls option. */ #if ENABLE_NLS /* Get declarations of GNU message catalog functions. */ #include #else /* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which chokes if dcgettext is defined as a macro. So include it now, to make later inclusions of a NOP. We don't include as well because people using "gettext.h" will not include , and also including would fail on SunOS 4, whereas is GNUNET_OK. */ #if defined(__sun) #include #endif /* Disabled NLS. The casts to 'const char *' serve the purpose of producing warnings for invalid uses of the value returned from these functions. On pre-ANSI systems without 'const', the config.h file is supposed to contain "#define const". */ #define gettext(Msgid) ((const char *) (Msgid)) #define dgettext(Domainname, Msgid) ((const char *) (Msgid)) #define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid)) #define ngettext(Msgid1, Msgid2, N) \ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) #define dngettext(Domainname, Msgid1, Msgid2, N) \ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) #define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) /* slight modification here to avoid warnings: generate GNUNET_NO code, not even the cast... */ #define textdomain(Domainname) #define bindtextdomain(Domainname, Dirname) #define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset)) #endif /* A pseudo function call that serves as a marker for the automated extraction of messages, but does not call gettext(). The run-time translation is done at a different place in the code. The argument, String, should be a literal string. Concatenated strings and other string expressions won't work. The macro's expansion is not parenthesized, so that it is suitable as initializer for static 'char[]' or 'const char[]' variables. */ #define gettext_noop(String) String #endif /* _LIBGETTEXT_H */ gnunet-0.9.3/src/include/gnunet_program_lib.h0000644000175000017500000000677411760502551016224 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_program_lib.h * @brief functions related to starting programs * @author Christian Grothoff */ #ifndef GNUNET_PROGRAM_LIB_H #define GNUNET_PROGRAM_LIB_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_configuration_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_scheduler_lib.h" /** * Main function that will be run. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param cfg configuration */ typedef void (*GNUNET_PROGRAM_Main) (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle * cfg); /** * Run a standard GNUnet command startup sequence (initialize loggers * and configuration, parse options). * * @param argc number of command line arguments * @param argv command line arguments * @param binaryName our expected name * @param binaryHelp help text for the program * @param options command line options * @param task main function to run * @param task_cls closure for task * @param run_without_scheduler GNUNET_NO start the scheduler, GNUNET_YES do not * start the scheduler just run the main task * @return GNUNET_SYSERR on error, GNUNET_OK on success */ int GNUNET_PROGRAM_run2 (int argc, char *const *argv, const char *binaryName, const char *binaryHelp, const struct GNUNET_GETOPT_CommandLineOption *options, GNUNET_PROGRAM_Main task, void *task_cls, int run_without_scheduler); /** * Run a standard GNUnet command startup sequence (initialize loggers * and configuration, parse options). * * @param argc number of command line arguments * @param argv command line arguments * @param binaryName our expected name * @param binaryHelp helptext for "-h" option (about the app) * @param options command line options * @param task main function to run * @param task_cls closure for task * @return GNUNET_SYSERR on error, GNUNET_OK on success */ int GNUNET_PROGRAM_run (int argc, char *const *argv, const char *binaryName, const char *binaryHelp, const struct GNUNET_GETOPT_CommandLineOption *options, GNUNET_PROGRAM_Main task, void *task_cls); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_PROGRAM_LIB_H */ #endif /* end of gnunet_program_lib.h */ gnunet-0.9.3/src/include/gnunet_time_lib.h0000644000175000017500000002625511760515074015513 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_time_lib.h * @brief functions related to time * * @author Christian Grothoff */ #ifndef GNUNET_TIME_LIB_H #define GNUNET_TIME_LIB_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_common.h" /** * Time for absolute times used by GNUnet, in milliseconds. */ struct GNUNET_TIME_Absolute { /** * The actual value. */ uint64_t abs_value; }; /** * Time for relative time used by GNUnet, in milliseconds. * Always positive, so we can only refer to future time. */ struct GNUNET_TIME_Relative { /** * The actual value. */ uint64_t rel_value; }; GNUNET_NETWORK_STRUCT_BEGIN /** * Time for relative time used by GNUnet, in milliseconds and in network byte order. */ struct GNUNET_TIME_RelativeNBO { /** * The actual value (in network byte order). */ uint64_t rel_value__ GNUNET_PACKED; }; /** * Time for absolute time used by GNUnet, in milliseconds and in network byte order. */ struct GNUNET_TIME_AbsoluteNBO { /** * The actual value (in network byte order). */ uint64_t abs_value__ GNUNET_PACKED; }; GNUNET_NETWORK_STRUCT_END /** * Relative time zero. */ #define GNUNET_TIME_UNIT_ZERO GNUNET_TIME_relative_get_zero_() /** * Absolute time zero. */ #define GNUNET_TIME_UNIT_ZERO_ABS GNUNET_TIME_absolute_get_zero_() /** * One millisecond, our basic time unit. */ #define GNUNET_TIME_UNIT_MILLISECONDS GNUNET_TIME_relative_get_unit_() /** * One second. */ #define GNUNET_TIME_UNIT_SECONDS GNUNET_TIME_relative_get_second_() /** * One minute. */ #define GNUNET_TIME_UNIT_MINUTES GNUNET_TIME_relative_get_minute_() /** * One hour. */ #define GNUNET_TIME_UNIT_HOURS GNUNET_TIME_relative_get_hour_() /** * One day. */ #define GNUNET_TIME_UNIT_DAYS GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_HOURS, 24) /** * One week. */ #define GNUNET_TIME_UNIT_WEEKS GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_DAYS, 7) /** * One month (30 days). */ #define GNUNET_TIME_UNIT_MONTHS GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_DAYS, 30) /** * One year (365 days). */ #define GNUNET_TIME_UNIT_YEARS GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_DAYS, 365) /** * Constant used to specify "forever". This constant * will be treated specially in all time operations. */ #define GNUNET_TIME_UNIT_FOREVER_REL GNUNET_TIME_relative_get_forever_ () /** * Constant used to specify "forever". This constant * will be treated specially in all time operations. */ #define GNUNET_TIME_UNIT_FOREVER_ABS GNUNET_TIME_absolute_get_forever_ () /** * Return relative time of 0ms. */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_get_zero_ (void); /** * Return absolute time of 0ms. */ struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get_zero_ (void); /** * Return relative time of 1ms. */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_get_unit_ (void); /** * Return relative time of 1s. */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_get_second_ (void); /** * Return relative time of 1 minute. */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_get_minute_ (void); /** * Return relative time of 1 hour. */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_get_hour_ (void); /** * Return "forever". */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_get_forever_ (void); /** * Return "forever". */ struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get_forever_ (void); /** * Get the current time. * * @return the current time */ struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get (void); /** * Convert relative time to an absolute time in the * future. * * @param rel relative time to convert * @return timestamp that is "rel" in the future, or FOREVER if rel==FOREVER (or if we would overflow) */ struct GNUNET_TIME_Absolute GNUNET_TIME_relative_to_absolute (struct GNUNET_TIME_Relative rel); /** * Return the minimum of two relative time values. * * @param t1 first timestamp * @param t2 other timestamp * @return timestamp that is smaller */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_min (struct GNUNET_TIME_Relative t1, struct GNUNET_TIME_Relative t2); /** * Return the maximum of two relative time values. * * @param t1 first timestamp * @param t2 other timestamp * @return timestamp that is larger */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_max (struct GNUNET_TIME_Relative t1, struct GNUNET_TIME_Relative t2); /** * Return the minimum of two absolute time values. * * @param t1 first timestamp * @param t2 other timestamp * @return timestamp that is smaller */ struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_min (struct GNUNET_TIME_Absolute t1, struct GNUNET_TIME_Absolute t2); /** * Return the maximum of two absolute time values. * * @param t1 first timestamp * @param t2 other timestamp * @return timestamp that is smaller */ struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_max (struct GNUNET_TIME_Absolute t1, struct GNUNET_TIME_Absolute t2); /** * Given a timestamp in the future, how much time * remains until then? * * @param future some absolute time, typically in the future * @return future - now, or 0 if now >= future, or FOREVER if future==FOREVER. */ struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_remaining (struct GNUNET_TIME_Absolute future); /** * Calculate the estimate time of arrival/completion * for an operation. * * @param start when did the operation start? * @param finished how much has been done? * @param total how much must be done overall (same unit as for "finished") * @return remaining duration for the operation, * assuming it continues at the same speed */ struct GNUNET_TIME_Relative GNUNET_TIME_calculate_eta (struct GNUNET_TIME_Absolute start, uint64_t finished, uint64_t total); /** * Compute the time difference between the given start and end times. * Use this function instead of actual subtraction to ensure that * "FOREVER" and overflows are handeled correctly. * * @param start some absolute time * @param end some absolute time (typically larger or equal to start) * @return 0 if start >= end; FOREVER if end==FOREVER; otherwise end - start */ struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_difference (struct GNUNET_TIME_Absolute start, struct GNUNET_TIME_Absolute end); /** * Get the duration of an operation as the * difference of the current time and the given start time "hence". * * @param whence some absolute time, typically in the past * @return aborts if hence==FOREVER, 0 if hence > now, otherwise now-hence. */ struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_duration (struct GNUNET_TIME_Absolute whence); /** * Add a given relative duration to the * given start time. * * @param start some absolute time * @param duration some relative time to add * @return FOREVER if either argument is FOREVER or on overflow; start+duration otherwise */ struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_add (struct GNUNET_TIME_Absolute start, struct GNUNET_TIME_Relative duration); /** * Subtract a given relative duration from the * given start time. * * @param start some absolute time * @param duration some relative time to subtract * @return ZERO if start <= duration, or FOREVER if start time is FOREVER; start-duration otherwise */ struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_subtract (struct GNUNET_TIME_Absolute start, struct GNUNET_TIME_Relative duration); /** * Multiply relative time by a given factor. * * @param rel some duration * @param factor integer to multiply with * @return FOREVER if rel=FOREVER or on overflow; otherwise rel*factor */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_multiply (struct GNUNET_TIME_Relative rel, unsigned int factor); /** * Divide relative time by a given factor. * * @param rel some duration * @param factor integer to divide by * @return FOREVER if rel=FOREVER or factor==0; otherwise rel/factor */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_divide (struct GNUNET_TIME_Relative rel, unsigned int factor); /** * Add relative times together. * * @param a1 some relative time * @param a2 some other relative time * @return FOREVER if either argument is FOREVER or on overflow; a1+a2 otherwise */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_add (struct GNUNET_TIME_Relative a1, struct GNUNET_TIME_Relative a2); /** * Subtract relative timestamp from the other. * * @param a1 first timestamp * @param a2 second timestamp * @return ZERO if a2>=a1 (including both FOREVER), FOREVER if a1 is FOREVER, a1-a2 otherwise */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_subtract (struct GNUNET_TIME_Relative a1, struct GNUNET_TIME_Relative a2); /** * Convert relative time to network byte order. * * @param a time to convert * @return converted time value */ struct GNUNET_TIME_RelativeNBO GNUNET_TIME_relative_hton (struct GNUNET_TIME_Relative a); /** * Convert relative time from network byte order. * * @param a time to convert * @return converted time value */ struct GNUNET_TIME_Relative GNUNET_TIME_relative_ntoh (struct GNUNET_TIME_RelativeNBO a); /** * Convert relative time to network byte order. * * @param a time to convert * @return converted time value */ struct GNUNET_TIME_AbsoluteNBO GNUNET_TIME_absolute_hton (struct GNUNET_TIME_Absolute a); /** * Convert relative time from network byte order. * * @param a time to convert * @return converted time value */ struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_ntoh (struct GNUNET_TIME_AbsoluteNBO a); /** * Convert a relative time to a string. * NOT reentrant! * * @param time the time to print * * @return string form of the time (as milliseconds) */ const char * GNUNET_TIME_relative_to_string (struct GNUNET_TIME_Relative time); /** * Set the timestamp offset for this instance. * * @param offset the offset to skew the locale time by */ void GNUNET_TIME_set_offset (long long offset); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_TIME_LIB_H */ #endif /* end of gnunet_time_lib.h */ gnunet-0.9.3/src/include/gnunet_signal_lib.h0000644000175000017500000000474611760502552016030 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_signal_lib.h * @brief functions related to signals * @author Christian Grothoff */ #ifndef GNUNET_SIGNAL_LIB_H #define GNUNET_SIGNAL_LIB_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * Context created when a signal handler is installed; * can be used to restore it to the previous state later. */ struct GNUNET_SIGNAL_Context; /** * A signal handler. Since different OSes have different signatures * for their handlers, the API only gives the most restrictive * signature -- no arguments, no return value. Note that this will * work even if the OS expects a function with arguments. However, * the implementation must guarantee that this handler is not called * for signals other than the one that it has been registered for. */ typedef void (*GNUNET_SIGNAL_Handler) (void); /** * Install a signal handler that will be run if the * given signal is received. * * @param signal the number of the signal * @param handler the function to call * @return context that can be used to restore, NULL on error */ struct GNUNET_SIGNAL_Context * GNUNET_SIGNAL_handler_install (int signal, GNUNET_SIGNAL_Handler handler); /** * Uninstall a previously installed signal hander. * * @param ctx context that was returned when the * signal handler was installed */ void GNUNET_SIGNAL_handler_uninstall (struct GNUNET_SIGNAL_Context *ctx); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_SIGNAL_LIB_H */ #endif /* end of gnunet_signal_lib.h */ gnunet-0.9.3/src/include/gnunet_pseudonym_lib.h0000644000175000017500000001557011760502552016573 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_pseudonym_lib.h * @brief functions related to pseudonyms * @author Christian Grothoff */ #ifndef GNUNET_PSEUDONYM_LIB_H #define GNUNET_PSEUDONYM_LIB_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_common.h" #include "gnunet_configuration_lib.h" #include "gnunet_container_lib.h" /** * Iterator over all known pseudonyms. * * @param cls closure * @param pseudonym hash code of public key of pseudonym * @param name name of the pseudonym (might be NULL) * @param unique_name unique name of the pseudonym (might be NULL) * @param md meta data known about the pseudonym * @param rating the local rating of the pseudonym * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort */ typedef int (*GNUNET_PSEUDONYM_Iterator) (void *cls, const GNUNET_HashCode * pseudonym, const char *name, const char *unique_name, const struct GNUNET_CONTAINER_MetaData * md, int rating); /** * Change the ranking of a pseudonym. * * @param cfg overall configuration * @param nsid id of the pseudonym * @param delta by how much should the rating be changed? * @return new rating of the namespace */ int GNUNET_PSEUDONYM_rank (const struct GNUNET_CONFIGURATION_Handle *cfg, const GNUNET_HashCode * nsid, int delta); /** * Add a pseudonym to the set of known pseudonyms. * For all pseudonym advertisements that we discover * FS should automatically call this function. * * @param cfg overall configuration * @param id the pseudonym identifier * @param meta metadata for the pseudonym */ void GNUNET_PSEUDONYM_add (const struct GNUNET_CONFIGURATION_Handle *cfg, const GNUNET_HashCode * id, const struct GNUNET_CONTAINER_MetaData *meta); /** * List all known pseudonyms. * * @param cfg overall configuration * @param iterator function to call for each pseudonym * @param closure closure for iterator * @return number of pseudonyms found */ int GNUNET_PSEUDONYM_list_all (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_PSEUDONYM_Iterator iterator, void *closure); /** * Register callback to be invoked whenever we discover * a new pseudonym. */ int GNUNET_PSEUDONYM_discovery_callback_register (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_PSEUDONYM_Iterator iterator, void *closure); /** * Unregister namespace discovery callback. */ int GNUNET_PSEUDONYM_discovery_callback_unregister (GNUNET_PSEUDONYM_Iterator iterator, void *closure); /** * Return unique variant of the namespace name. * Use after GNUNET_PSEUDONYM_id_to_name() to make sure * that name is unique. * * @param cfg configuration * @param nsid cryptographic ID of the namespace * @param name name to uniquify * @param suffix if not NULL, filled with the suffix value * @return NULL on failure (should never happen), name on success. * Free the name with GNUNET_free(). */ char * GNUNET_PSEUDONYM_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg, const GNUNET_HashCode * nsid, const char *name, unsigned int *suffix); /** * Get namespace name, metadata and rank * This is a wrapper around internal read_info() call, and ensures that * returned data is not invalid (not NULL). * Writing back information returned by this function will give * a name "no-name" to pseudonyms that have no name. This side-effect is * unavoidable, but hardly harmful. * * @param cfg configuration * @param nsid cryptographic ID of the namespace * @param ret_meta a location to store metadata pointer. NULL, if metadata * is not needed. Destroy with GNUNET_CONTAINER_meta_data_destroy(). * @param ret_rank a location to store rank. NULL, if rank not needed. * @param ret_name a location to store human-readable name. Name is not unique. * NULL, if name is not needed. Free with GNUNET_free(). * @param name_is_a_dup is set to GNUNET_YES, if ret_name was filled with * a duplicate of a "no-name" placeholder * @return GNUNET_OK on success. GNUENT_SYSERR if the data was * unobtainable (in that case ret_* are filled with placeholders - * empty metadata container, rank -1 and a "no-name" name). */ int GNUNET_PSEUDONYM_get_info (const struct GNUNET_CONFIGURATION_Handle *cfg, const GNUNET_HashCode * nsid, struct GNUNET_CONTAINER_MetaData **ret_meta, int32_t *ret_rank, char **ret_name, int *name_is_a_dup); /** * Get the namespace ID belonging to the given namespace name. * * @param cfg configuration to use * @param ns_uname unique (!) human-readable name for the namespace * @param nsid set to namespace ID based on 'ns_uname' * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int GNUNET_PSEUDONYM_name_to_id (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *ns_uname, GNUNET_HashCode * nsid); /** * Set the pseudonym metadata, rank and name. * * @param cfg overall configuration * @param nsid id of the pseudonym * @param name name to set. Must be the non-unique version of it. * May be NULL, in which case it erases pseudonym's name! * @param md metadata to set * May be NULL, in which case it erases pseudonym's metadata! * @param rank rank to assign * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int GNUNET_PSEUDONYM_set_info (const struct GNUNET_CONFIGURATION_Handle *cfg, const GNUNET_HashCode * nsid, const char *name, const struct GNUNET_CONTAINER_MetaData *md, int rank); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_PSEUDONYM_LIB_H */ #endif /* end of gnunet_pseudonym_lib.h */ gnunet-0.9.3/src/include/gnunet_testing_lib.h0000644000175000017500000012031411760502552016216 00000000000000/* This file is part of GNUnet (C) 2008, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_testing_lib.h * @brief convenience API for writing testcases for GNUnet * Many testcases need to start and stop gnunetd, * and this library is supposed to make that easier * for TESTCASES. Normal programs should always * use functions from gnunet_{util,arm}_lib.h. This API is * ONLY for writing testcases! * @author Christian Grothoff */ #ifndef GNUNET_TESTING_LIB_H #define GNUNET_TESTING_LIB_H #include "gnunet_util_lib.h" #include "gnunet_statistics_service.h" #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #define HOSTKEYFILESIZE 914 /** * Handle for a GNUnet daemon (technically a set of * daemons; the handle is really for the master ARM * daemon) started by the testing library. */ struct GNUNET_TESTING_Daemon; /** * Linked list of hostnames and ports to use for starting daemons. */ struct GNUNET_TESTING_Host { /** * Pointer to next item in the list. */ struct GNUNET_TESTING_Host *next; /** * Hostname to connect to. */ char *hostname; /** * Username to use when connecting (may be null). */ char *username; /** * Port to use for SSH connection (used for ssh * connection forwarding, 0 to let ssh decide) */ uint16_t port; }; /** * Prototype of a function that will be called whenever * a daemon was started by the testing library. * * @param cls closure * @param id identifier for the daemon, NULL on error * @param d handle for the daemon * @param emsg error message (NULL on success) */ typedef void (*GNUNET_TESTING_NotifyHostkeyCreated) (void *cls, const struct GNUNET_PeerIdentity * id, struct GNUNET_TESTING_Daemon * d, const char *emsg); /** * Prototype of a function that will be called whenever * a daemon was started by the testing library. * * @param cls closure * @param id identifier for the daemon, NULL on error * @param cfg configuration used by this daemon * @param d handle for the daemon * @param emsg error message (NULL on success) */ typedef void (*GNUNET_TESTING_NotifyDaemonRunning) (void *cls, const struct GNUNET_PeerIdentity * id, const struct GNUNET_CONFIGURATION_Handle * cfg, struct GNUNET_TESTING_Daemon * d, const char *emsg); /** * Handle to an entire testbed of GNUnet peers. */ struct GNUNET_TESTING_Testbed; /** * Phases of starting GNUnet on a system. */ enum GNUNET_TESTING_StartPhase { /** * Copy the configuration file to the target system. */ SP_COPYING, /** * Configuration file has been copied, generate hostkey. */ SP_COPIED, /** * Create the hostkey for the peer. */ SP_HOSTKEY_CREATE, /** * Hostkey generated, wait for topology to be finished. */ SP_HOSTKEY_CREATED, /** * Topology has been created, now start ARM. */ SP_TOPOLOGY_SETUP, /** * ARM has been started, check that it has properly daemonized and * then try to connect to the CORE service (which should be * auto-started by ARM). */ SP_START_ARMING, /** * We're waiting for CORE to start. */ SP_START_CORE, /** * CORE is up, now make sure we get the HELLO for this peer. */ SP_GET_HELLO, /** * Core has notified us that we've established a connection to the service. * The main FSM halts here and waits to be moved to UPDATE or CLEANUP. */ SP_START_DONE, /** * We've been asked to terminate the instance and are now waiting for * the remote command to stop the gnunet-arm process and delete temporary * files. */ SP_SHUTDOWN_START, /** * We should shutdown a *single* service via gnunet-arm. Call the dead_cb * upon notification from gnunet-arm that the service has been stopped. */ SP_SERVICE_SHUTDOWN_START, /** * We should start a *single* service via gnunet-arm. Call the daemon cb * upon notification from gnunet-arm that the service has been started. */ SP_SERVICE_START, /** * We've received a configuration update and are currently waiting for * the copy process for the update to complete. Once it is, we will * return to "SP_START_DONE" (and rely on ARM to restart all affected * services). */ SP_CONFIG_UPDATE }; /** * Prototype of a function that will be called when a * particular operation was completed the testing library. * * @param cls closure * @param emsg NULL on success */ typedef void (*GNUNET_TESTING_NotifyCompletion) (void *cls, const char *emsg); /** * Prototype of a function that will be called with the * number of connections created for a particular topology. * * @param cls closure * @param num_connections the number of connections created */ typedef void (*GNUNET_TESTING_NotifyConnections) (void *cls, unsigned int num_connections); /** * Handle for a GNUnet daemon (technically a set of * daemons; the handle is really for the master ARM * daemon) started by the testing library. */ struct GNUNET_TESTING_Daemon { /** * Our configuration. */ struct GNUNET_CONFIGURATION_Handle *cfg; /** * At what time to give up starting the peer */ struct GNUNET_TIME_Absolute max_timeout; /** * Host to run GNUnet on. */ char *hostname; /** * Port to use for ssh, NULL to let system choose default. */ char *ssh_port_str; /** * Result of GNUNET_i2s of this peer, * for printing */ char *shortname; /** * Username we are using. */ char *username; /** * Name of the configuration file */ char *cfgfile; /** * Callback to inform initiator that the peer's * hostkey has been created. */ GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback; /** * Closure for hostkey creation callback. */ void *hostkey_cls; /** * Function to call when the peer is running. */ GNUNET_TESTING_NotifyDaemonRunning cb; /** * Closure for cb. */ void *cb_cls; /** * Arguments from "daemon_stop" call. */ GNUNET_TESTING_NotifyCompletion dead_cb; /** * Closure for 'dead_cb'. */ void *dead_cb_cls; /** * Arguments from "daemon_stop" call. */ GNUNET_TESTING_NotifyCompletion update_cb; /** * Closure for 'update_cb'. */ void *update_cb_cls; /** * PID of the process we used to run gnunet-arm or SSH to start the peer. */ struct GNUNET_OS_Process *proc_arm_start; /** * PID of the process we used to run gnunet-arm or SSH to stop the peer. */ struct GNUNET_OS_Process *proc_arm_stop; /** * PID of the process we used to run gnunet-arm or SSH to manage services at the peer. */ struct GNUNET_OS_Process *proc_arm_srv_start; /** * PID of the process we used to run gnunet-arm or SSH to manage services at the peer. */ struct GNUNET_OS_Process *proc_arm_srv_stop; /** * PID of the process we used to run copy files */ struct GNUNET_OS_Process *proc_arm_copying; /** * PID of the process we used to run gnunet-peerinfo. */ struct GNUNET_OS_Process *proc_arm_peerinfo; /** * Handle to the server. */ struct GNUNET_CORE_Handle *server; /** * Handle to the transport service of this peer */ struct GNUNET_TRANSPORT_Handle *th; /** * Handle for getting HELLOs from transport */ struct GNUNET_TRANSPORT_GetHelloHandle *ghh; /** * HELLO message for this peer */ struct GNUNET_HELLO_Message *hello; /** * Handle to a pipe for reading the hostkey. */ struct GNUNET_DISK_PipeHandle *pipe_stdout; /** * Currently, a single char * pointing to a service * that has been churned off. * * FIXME: make this a linked list of services that have been churned off!!! */ char *churned_services; /** * ID of the current task. */ GNUNET_SCHEDULER_TaskIdentifier task; /** * Identity of this peer (once started). */ struct GNUNET_PeerIdentity id; /** * Flag to indicate that we've already been asked * to terminate (but could not because some action * was still pending). */ int dead; /** * GNUNET_YES if the hostkey has been created * for this peer, GNUNET_NO otherwise. */ int have_hostkey; /** * In which phase are we during the start of * this process? */ enum GNUNET_TESTING_StartPhase phase; /** * Current position in 'hostkeybuf' (for reading from gnunet-peerinfo) */ unsigned int hostkeybufpos; /** * Set to GNUNET_YES once the peer is up. */ int running; /** * Used to tell shutdown not to remove configuration for the peer * (if it's going to be restarted later) */ int churn; /** * Output from gnunet-peerinfo is read into this buffer. */ char hostkeybuf[105]; }; /** * Handle to a group of GNUnet peers. */ struct GNUNET_TESTING_PeerGroup; /** * Prototype of a function that will be called whenever * two daemons are connected by the testing library. * * @param cls closure * @param first peer id for first daemon * @param second peer id for the second daemon * @param distance distance between the connected peers * @param first_cfg config for the first daemon * @param second_cfg config for the second daemon * @param first_daemon handle for the first daemon * @param second_daemon handle for the second daemon * @param emsg error message (NULL on success) */ typedef void (*GNUNET_TESTING_NotifyConnection) (void *cls, const struct GNUNET_PeerIdentity * first, const struct GNUNET_PeerIdentity * second, uint32_t distance, const struct GNUNET_CONFIGURATION_Handle * first_cfg, const struct GNUNET_CONFIGURATION_Handle * second_cfg, struct GNUNET_TESTING_Daemon * first_daemon, struct GNUNET_TESTING_Daemon * second_daemon, const char *emsg); /** * Prototype of a callback function indicating that two peers * are currently connected. * * @param cls closure * @param first peer id for first daemon * @param second peer id for the second daemon * @param distance distance between the connected peers * @param emsg error message (NULL on success) */ typedef void (*GNUNET_TESTING_NotifyTopology) (void *cls, const struct GNUNET_PeerIdentity * first, const struct GNUNET_PeerIdentity * second, const char *emsg); /** * Starts a GNUnet daemon. GNUnet must be installed on the target * system and available in the PATH. The machine must furthermore be * reachable via "ssh" (unless the hostname is "NULL") without the * need to enter a password. * * @param cfg configuration to use * @param timeout how long to wait starting up peers * @param pretend GNUNET_YES to set up files but not start peer GNUNET_NO * to really start the peer (default) * @param hostname name of the machine where to run GNUnet * (use NULL for localhost). * @param ssh_username ssh username to use when connecting to hostname * @param sshport port to pass to ssh process when connecting to hostname * @param hostkey pointer to a hostkey to be written to disk (instead of being generated) * @param hostkey_callback function to call once the hostkey has been * generated for this peer, but it hasn't yet been started * (NULL to start immediately, otherwise waits on GNUNET_TESTING_daemon_continue_start) * @param hostkey_cls closure for hostkey callback * @param cb function to call once peer is up, or failed to start * @param cb_cls closure for cb * @return handle to the daemon (actual start will be completed asynchronously) */ struct GNUNET_TESTING_Daemon * GNUNET_TESTING_daemon_start (const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TIME_Relative timeout, int pretend, const char *hostname, const char *ssh_username, uint16_t sshport, const char *hostkey, GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback, void *hostkey_cls, GNUNET_TESTING_NotifyDaemonRunning cb, void *cb_cls); /** * Continues GNUnet daemon startup when user wanted to be notified * once a hostkey was generated (for creating friends files, blacklists, * etc.). * * @param daemon the daemon to finish starting */ void GNUNET_TESTING_daemon_continue_startup (struct GNUNET_TESTING_Daemon *daemon); /** * Check whether the given daemon is running. * * @param daemon the daemon to check * @return GNUNET_YES if the daemon is up, GNUNET_NO if the * daemon is down, GNUNET_SYSERR on error. */ int GNUNET_TESTING_test_daemon_running (struct GNUNET_TESTING_Daemon *daemon); /** * Obtain the peer identity of the peer with the given configuration * handle. This function reads the private key of the peer, obtains * the public key and hashes it. * * @param cfg configuration of the peer * @param pid where to store the peer identity * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int GNUNET_TESTING_get_peer_identity (const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_PeerIdentity *pid); /** * Restart (stop and start) a GNUnet daemon. * * @param d the daemon that should be restarted * @param cb function called once the daemon is (re)started * @param cb_cls closure for cb */ void GNUNET_TESTING_daemon_restart (struct GNUNET_TESTING_Daemon *d, GNUNET_TESTING_NotifyDaemonRunning cb, void *cb_cls); /** * Start a peer that has previously been stopped using the daemon_stop * call (and files weren't deleted and the allow restart flag) * * @param daemon the daemon to start (has been previously stopped) * @param timeout how long to wait for restart * @param cb the callback for notification when the peer is running * @param cb_cls closure for the callback */ void GNUNET_TESTING_daemon_start_stopped (struct GNUNET_TESTING_Daemon *daemon, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_NotifyDaemonRunning cb, void *cb_cls); /** * Starts a GNUnet daemon's service. * * @param d the daemon for which the service should be started * @param service the name of the service to start * @param timeout how long to wait for process for startup * @param cb function called once gnunet-arm returns * @param cb_cls closure for cb */ void GNUNET_TESTING_daemon_start_service (struct GNUNET_TESTING_Daemon *d, const char *service, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_NotifyDaemonRunning cb, void *cb_cls); /** * Starts a GNUnet daemon's service which has been previously turned off. * * @param d the daemon for which the service should be started * @param service the name of the service to start * @param timeout how long to wait for process for startup * @param cb function called once gnunet-arm returns * @param cb_cls closure for cb */ void GNUNET_TESTING_daemon_start_stopped_service (struct GNUNET_TESTING_Daemon *d, char *service, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_NotifyDaemonRunning cb, void *cb_cls); /** * Get a certain testing daemon handle. * * @param pg handle to the set of running peers * @param position the number of the peer to return */ struct GNUNET_TESTING_Daemon * GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg, unsigned int position); /** * Get a daemon by peer identity, so callers can * retrieve the daemon without knowing it's offset. * * @param pg the peer group to retrieve the daemon from * @param peer_id the peer identity of the daemon to retrieve * * @return the daemon on success, or NULL if no such peer identity is found */ struct GNUNET_TESTING_Daemon * GNUNET_TESTING_daemon_get_by_id (struct GNUNET_TESTING_PeerGroup *pg, const struct GNUNET_PeerIdentity *peer_id); /** * Stops a GNUnet daemon. * * @param d the daemon that should be stopped * @param timeout how long to wait for process for shutdown to complete * @param cb function called once the daemon was stopped * @param cb_cls closure for cb * @param delete_files GNUNET_YES to remove files, GNUNET_NO * to leave them (i.e. for restarting at a later time, * or logfile inspection once finished) * @param allow_restart GNUNET_YES to restart peer later (using this API) * GNUNET_NO to kill off and clean up for good */ void GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_NotifyCompletion cb, void *cb_cls, int delete_files, int allow_restart); /** * Create a new configuration using the given configuration * as a template; however, each PORT in the existing cfg * must be renumbered by incrementing "*port". If we run * out of "*port" numbers, return NULL. * * @param cfg template configuration * @param off the current peer offset * @param port port numbers to use, update to reflect * port numbers that were used * @param upnum number to make unix domain socket names unique * @param hostname hostname of the controlling host, to allow control connections from * @param fdnum number used to offset the unix domain socket for grouped processes * (such as statistics or peerinfo, which can be shared among others) * * @return new configuration, NULL on error */ struct GNUNET_CONFIGURATION_Handle * GNUNET_TESTING_create_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, uint32_t off, uint16_t * port, uint32_t * upnum, const char *hostname, uint32_t * fdnum); /** * Changes the configuration of a GNUnet daemon. * * @param d the daemon that should be modified * @param cfg the new configuration for the daemon * @param cb function called once the configuration was changed * @param cb_cls closure for cb */ void GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d, struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_TESTING_NotifyCompletion cb, void *cb_cls); /** * Stops a single service of a GNUnet daemon. Used like daemon_stop, * only doesn't stop the entire peer in any case. If the service * is not currently running, this call is likely to fail after * timeout! * * @param d the daemon that should be stopped * @param service the name of the service to stop * @param timeout how long to wait for process for shutdown to complete * @param cb function called once the service was stopped * @param cb_cls closure for cb */ void GNUNET_TESTING_daemon_stop_service (struct GNUNET_TESTING_Daemon *d, const char *service, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_NotifyCompletion cb, void *cb_cls); /** * Read a testing hosts file based on a configuration. * Returns a DLL of hosts (caller must free!) on success * or NULL on failure. * * @param cfg a configuration with a testing section * * @return DLL of hosts on success, NULL on failure */ struct GNUNET_TESTING_Host * GNUNET_TESTING_hosts_load (const struct GNUNET_CONFIGURATION_Handle *cfg); /** * Start count gnunet instances with the same set of transports and * applications. The port numbers (any option called "PORT") will be * adjusted to ensure that no two peers running on the same system * have the same port(s) in their respective configurations. * * @param cfg configuration template to use * @param total number of daemons to start * @param max_concurrent_connections for testing, how many peers can * we connect to simultaneously * @param max_concurrent_ssh when starting with ssh, how many ssh * connections will we allow at once (based on remote hosts allowed!) * @param timeout total time allowed for peers to start * @param hostkey_callback function to call on each peers hostkey generation * if NULL, peers will be started by this call, if non-null, * GNUNET_TESTING_daemons_continue_startup must be called after * successful hostkey generation * @param hostkey_cls closure for hostkey callback * @param cb function to call on each daemon that was started * @param cb_cls closure for cb * @param connect_callback function to call each time two hosts are connected * @param connect_callback_cls closure for connect_callback * @param hostnames linked list of host structs to use to start peers on * (NULL to run on localhost only) * * @return NULL on error, otherwise handle to control peer group */ struct GNUNET_TESTING_PeerGroup * GNUNET_TESTING_daemons_start (const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned int total, unsigned int max_concurrent_connections, unsigned int max_concurrent_ssh, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback, void *hostkey_cls, GNUNET_TESTING_NotifyDaemonRunning cb, void *cb_cls, GNUNET_TESTING_NotifyConnection connect_callback, void *connect_callback_cls, const struct GNUNET_TESTING_Host *hostnames); /** * Function which continues a peer group starting up * after successfully generating hostkeys for each peer. * * @param pg the peer group to continue starting */ void GNUNET_TESTING_daemons_continue_startup (struct GNUNET_TESTING_PeerGroup *pg); /** * Handle for an active request to connect two peers. */ struct GNUNET_TESTING_ConnectContext; /** * Establish a connection between two GNUnet daemons. The daemons * must both be running and not be stopped until either the * 'cb' callback is called OR the connection request has been * explicitly cancelled. * * @param d1 handle for the first daemon * @param d2 handle for the second daemon * @param timeout how long is the connection attempt * allowed to take? * @param max_connect_attempts how many times should we try to reconnect * (within timeout) * @param send_hello GNUNET_YES to send the HELLO, GNUNET_NO to assume * the HELLO has already been exchanged * @param cb function to call at the end * @param cb_cls closure for cb * @return handle to cancel the request, NULL on error */ struct GNUNET_TESTING_ConnectContext * GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1, struct GNUNET_TESTING_Daemon *d2, struct GNUNET_TIME_Relative timeout, unsigned int max_connect_attempts, int send_hello, GNUNET_TESTING_NotifyConnection cb, void *cb_cls); /** * Cancel an attempt to connect two daemons. * * @param cc connect context */ void GNUNET_TESTING_daemons_connect_cancel (struct GNUNET_TESTING_ConnectContext *cc); /** * Restart all peers in the given group. * * @param pg the handle to the peer group * @param callback function to call on completion (or failure) * @param callback_cls closure for the callback function */ void GNUNET_TESTING_daemons_restart (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_NotifyCompletion callback, void *callback_cls); /** * Shutdown all peers started in the given group. * * @param pg handle to the peer group * @param timeout how long to wait for shutdown * @param cb callback to notify upon success or failure * @param cb_cls closure for cb */ void GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_NotifyCompletion cb, void *cb_cls); /** * Count the number of running peers. * * @param pg handle for the peer group * * @return the number of currently running peers in the peer group */ unsigned int GNUNET_TESTING_daemons_running (struct GNUNET_TESTING_PeerGroup *pg); /** * Simulate churn by stopping some peers (and possibly * re-starting others if churn is called multiple times). This * function can only be used to create leave-join churn (peers "never" * leave for good). First "voff" random peers that are currently * online will be taken offline; then "von" random peers that are then * offline will be put back online. No notifications will be * generated for any of these operations except for the callback upon * completion. Note that the implementation is at liberty to keep * the ARM service itself (but none of the other services or daemons) * running even though the "peer" is being varied offline. * * @param pg handle for the peer group * @param service the service to churn on/off, NULL for all * @param voff number of peers that should go offline * @param von number of peers that should come back online; * must be zero on first call (since "testbed_start" * always starts all of the peers) * @param timeout how long to wait for operations to finish before * giving up * @param cb function to call at the end * @param cb_cls closure for cb */ void GNUNET_TESTING_daemons_churn (struct GNUNET_TESTING_PeerGroup *pg, char *service, unsigned int voff, unsigned int von, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_NotifyCompletion cb, void *cb_cls); /** * Start a given service for each of the peers in the peer group. * * @param pg handle for the peer group * @param service the service to start * @param timeout how long to wait for operations to finish before * giving up * @param cb function to call once finished * @param cb_cls closure for cb * */ void GNUNET_TESTING_daemons_start_service (struct GNUNET_TESTING_PeerGroup *pg, char *service, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_NotifyCompletion cb, void *cb_cls); /** * Callback function to process statistic values. * * @param cls closure * @param peer the peer the statistics belong to * @param subsystem name of subsystem that created the statistic * @param name the name of the datum * @param value the current value * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration */ typedef int (*GNUNET_TESTING_STATISTICS_Iterator) (void *cls, const struct GNUNET_PeerIdentity * peer, const char *subsystem, const char *name, uint64_t value, int is_persistent); /** * Iterate over all (running) peers in the peer group, retrieve * all statistics from each. * * @param pg the peergroup to iterate statistics of * @param cont continuation to call once call is completed(?) * @param proc processing function for each statistic retrieved * @param cls closure to pass to proc */ void GNUNET_TESTING_get_statistics (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_STATISTICS_Callback cont, GNUNET_TESTING_STATISTICS_Iterator proc, void *cls); /** * Topologies supported for testbeds. */ enum GNUNET_TESTING_Topology { /** * A clique (everyone connected to everyone else). */ GNUNET_TESTING_TOPOLOGY_CLIQUE, /** * Small-world network (2d torus plus random links). */ GNUNET_TESTING_TOPOLOGY_SMALL_WORLD, /** * Small-world network (ring plus random links). */ GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING, /** * Ring topology. */ GNUNET_TESTING_TOPOLOGY_RING, /** * 2-d torus. */ GNUNET_TESTING_TOPOLOGY_2D_TORUS, /** * Random graph. */ GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI, /** * Certain percentage of peers are unable to communicate directly * replicating NAT conditions */ GNUNET_TESTING_TOPOLOGY_INTERNAT, /** * Scale free topology. */ GNUNET_TESTING_TOPOLOGY_SCALE_FREE, /** * Straight line topology. */ GNUNET_TESTING_TOPOLOGY_LINE, /** * All peers are disconnected. */ GNUNET_TESTING_TOPOLOGY_NONE, /** * Read a topology from a given file. */ GNUNET_TESTING_TOPOLOGY_FROM_FILE }; /** * Options for connecting a topology. */ enum GNUNET_TESTING_TopologyOption { /** * Try to connect all peers specified in the topology. */ GNUNET_TESTING_TOPOLOGY_OPTION_ALL, /** * Choose a random subset of connections to create. */ GNUNET_TESTING_TOPOLOGY_OPTION_RANDOM, /** * Create at least X connections for each peer. */ GNUNET_TESTING_TOPOLOGY_OPTION_MINIMUM, /** * Using a depth first search, create one connection * per peer. If any are missed (graph disconnected) * start over at those peers until all have at least one * connection. */ GNUNET_TESTING_TOPOLOGY_OPTION_DFS, /** * Find the N closest peers to each allowed peer in the * topology and make sure a connection to those peers * exists in the connect topology. */ GNUNET_TESTING_TOPOLOGY_OPTION_ADD_CLOSEST, /** * No options specified. */ GNUNET_TESTING_TOPOLOGY_OPTION_NONE }; /** * Get a topology from a string input. * * @param topology where to write the retrieved topology * @param topology_string The string to attempt to * get a configuration value from * @return GNUNET_YES if topology string matched a * known topology, GNUNET_NO if not */ int GNUNET_TESTING_topology_get (enum GNUNET_TESTING_Topology *topology, const char *topology_string); /** * Get connect topology option from string input. * * @param topology_option where to write the retrieved topology * @param topology_string The string to attempt to * get a configuration value from * @return GNUNET_YES if topology string matched a * known topology, GNUNET_NO if not */ int GNUNET_TESTING_topology_option_get (enum GNUNET_TESTING_TopologyOption *topology_option, const char *topology_string); /** * Takes a peer group and creates a topology based on the * one specified. Creates a topology means generates friend * files for the peers so they can only connect to those allowed * by the topology. This will only have an effect once peers * are started if the FRIENDS_ONLY option is set in the base * config. * * Also takes an optional restrict topology which * disallows direct connections UNLESS they are specified in * the restricted topology. * * A simple example; if the topology option is set to LINE * peers can ONLY connect in a LINE. However, if the topology * option is set to 2D-torus and the restrict option is set to * line with restrict_transports equal to "tcp udp", then peers * may connect in a 2D-torus, but will be restricted to tcp and * udp connections only in a LINE. Generally it only makes * sense to do this if restrict_topology is a subset of topology. * * For testing peer discovery, etc. it is generally better to * leave restrict_topology as GNUNET_TESTING_TOPOLOGY_NONE and * then use the connect_topology function to restrict the initial * connection set. * * @param pg the peer group struct representing the running peers * @param topology which topology to connect the peers in * @param restrict_topology allow only direct connections in this topology, * based on those listed in restrict_transports, set to * GNUNET_TESTING_TOPOLOGY_NONE for no restrictions * @param restrict_transports space delimited list of transports to blacklist * to create restricted topology, NULL for none * * @return the maximum number of connections were all allowed peers * connected to each other */ unsigned int GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg, enum GNUNET_TESTING_Topology topology, enum GNUNET_TESTING_Topology restrict_topology, const char *restrict_transports); /** * Iterate over all (running) peers in the peer group, retrieve * all connections that each currently has. * * @param pg the peer group we are concerned with * @param cb callback for topology information * @param cls closure for callback */ void GNUNET_TESTING_get_topology (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_NotifyTopology cb, void *cls); /** * Stop the connection process temporarily. * * @param pg the peer group to stop connecting */ void GNUNET_TESTING_stop_connections (struct GNUNET_TESTING_PeerGroup *pg); /** * Resume the connection process. * * @param pg the peer group to resume connecting */ void GNUNET_TESTING_resume_connections (struct GNUNET_TESTING_PeerGroup *pg); /** * There are many ways to connect peers that are supported by this function. * To connect peers in the same topology that was created via the * GNUNET_TESTING_create_topology, the topology variable must be set to * GNUNET_TESTING_TOPOLOGY_NONE. If the topology variable is specified, * a new instance of that topology will be generated and attempted to be * connected. This could result in some connections being impossible, * because some topologies are non-deterministic. * * @param pg the peer group struct representing the running peers * @param topology which topology to connect the peers in * @param options options for connecting the topology * @param option_modifier modifier for options that take a parameter * @param connect_timeout how long to wait before giving up on connecting * two peers * @param connect_attempts how many times to attempt to connect two peers * over the connect_timeout duration * @param notify_callback notification to be called once all connections completed * @param notify_cls closure for notification callback * * @return the number of connections that will be attempted, GNUNET_SYSERR on error */ int GNUNET_TESTING_connect_topology (struct GNUNET_TESTING_PeerGroup *pg, enum GNUNET_TESTING_Topology topology, enum GNUNET_TESTING_TopologyOption options, double option_modifier, struct GNUNET_TIME_Relative connect_timeout, unsigned int connect_attempts, GNUNET_TESTING_NotifyCompletion notify_callback, void *notify_cls); /** * Start or stop an individual peer from the given group. * * @param pg handle to the peer group * @param offset which peer to start or stop * @param desired_status GNUNET_YES to have it running, GNUNET_NO to stop it * @param timeout how long to wait for shutdown * @param cb function to call at the end * @param cb_cls closure for cb */ void GNUNET_TESTING_daemons_vary (struct GNUNET_TESTING_PeerGroup *pg, unsigned int offset, int desired_status, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_NotifyCompletion cb, void *cb_cls); /** * Start a peer group with a given number of peers. Notify * on completion of peer startup and connection based on given * topological constraints. Optionally notify on each * established connection. * * @param cfg configuration template to use * @param total number of daemons to start * @param timeout total time allowed for peers to start * @param connect_cb function to call each time two daemons are connected * @param peergroup_cb function to call once all peers are up and connected * @param peergroup_cls closure for peergroup callbacks * @param hostnames linked list of host structs to use to start peers on * (NULL to run on localhost only) * * @return NULL on error, otherwise handle to control peer group */ struct GNUNET_TESTING_PeerGroup * GNUNET_TESTING_peergroup_start (const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned int total, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_NotifyConnection connect_cb, GNUNET_TESTING_NotifyCompletion peergroup_cb, void *peergroup_cls, const struct GNUNET_TESTING_Host *hostnames); /** * Print current topology to a graphviz readable file. * * @param pg a currently running peergroup to print to file * @param output_filename the file to write the topology to * @param notify_cb callback to call upon completion or failure * @param notify_cb_cls closure for notify_cb * */ void GNUNET_TESTING_peergroup_topology_to_file (struct GNUNET_TESTING_PeerGroup *pg, const char *output_filename, GNUNET_TESTING_NotifyCompletion notify_cb, void *notify_cb_cls); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif #endif gnunet-0.9.3/src/include/gnunet_plugin_lib.h0000644000175000017500000001016011760502552016034 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_plugin_lib.h * @brief plugin loading and unloading * @author Christian Grothoff */ #ifndef GNUNET_PLUGIN_LIB_H #define GNUNET_PLUGIN_LIB_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_common.h" #include "gnunet_configuration_lib.h" /** * Signature of any function exported by a plugin. * * @param arg argument to the function (context) * @return some pointer, NULL if the plugin was * shutdown or if there was an error, otherwise * the plugin's API on success */ typedef void *(*GNUNET_PLUGIN_Callback) (void *arg); /** * Test if a plugin exists. * * Note that the library must export a symbol called * "library_name_init" for the test to succeed. * * @param library_name name of the plugin to test if it is installed * @return GNUNET_YES if the plugin exists, GNUNET_NO if not */ int GNUNET_PLUGIN_test (const char *library_name); /** * Setup plugin (runs the "init" callback and returns whatever "init" * returned). If "init" returns NULL, the plugin is unloaded. * * Note that the library must export symbols called * "library_name_init" and "library_name_done". These will be called * when the library is loaded and unloaded respectively. * * @param library_name name of the plugin to load * @param arg argument to the plugin initialization function * @return whatever the initialization function returned, NULL on error */ void * GNUNET_PLUGIN_load (const char *library_name, void *arg); /** * Signature of a function called by 'GNUNET_PLUGIN_load_all'. * * @param cls closure * @param library_name full name of the library (to be used with * 'GNUNET_PLUGIN_unload') * @param lib_ret return value from the initialization function * of the library (same as what 'GNUNET_PLUGIN_load' would * have returned for the given library name) */ typedef void (*GNUNET_PLUGIN_LoaderCallback) (void *cls, const char *library_name, void *lib_ret); /** * Load all compatible plugins with the given base name. * * Note that the library must export symbols called * "basename_ANYTHING_init" and "basename_ANYTHING__done". These will * be called when the library is loaded and unloaded respectively. * * @param basename basename of the plugins to load * @param arg argument to the plugin initialization function * @param cb function to call for each plugin found * @param cb_cls closure for 'cb' */ void GNUNET_PLUGIN_load_all (const char *basename, void *arg, GNUNET_PLUGIN_LoaderCallback cb, void *cb_cls); /** * Unload plugin (runs the "done" callback and returns whatever "done" * returned). The plugin is then unloaded. * * @param library_name name of the plugin to unload * @param arg argument to the plugin shutdown function * @return whatever the shutdown function returned, typically NULL * or a "char *" representing the error message */ void * GNUNET_PLUGIN_unload (const char *library_name, void *arg); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_PLUGIN_LIB_H */ #endif /* end of gnunet_plugin_lib.h */ gnunet-0.9.3/src/include/gnunet_constants.h0000644000175000017500000001224111760502552015726 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_constants.h * @brief "global" constants for performance tuning * @author Christian Grothoff */ #ifndef GNUNET_CONSTANTS_H #define GNUNET_CONSTANTS_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_bandwidth_lib.h" /** * Bandwidth (in/out) to assume initially (before either peer has * communicated any particular preference). Should be rather low; set * so that at least one maximum-size message can be send roughly once * per minute. */ #define GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT GNUNET_BANDWIDTH_value_init (1024) /** * After how long do we consider a connection to a peer dead * if we don't receive messages from the peer? */ #define GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) /** * After how long do we consider a connection to a peer dead * if we got an explicit disconnect and were unable to reconnect? */ #define GNUNET_CONSTANTS_DISCONNECT_SESSION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3) /** * How long do we delay reading more from a peer after a quota violation? */ #define GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2) /** * How long do we wait after a FORK+EXEC before testing for the * resulting process to be up (port open, waitpid, etc.)? */ #define GNUNET_CONSTANTS_EXEC_WAIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 200) /** * After how long do we retry a service connection that was * unavailable? Used in cases where an exponential back-off * seems inappropriate. */ #define GNUNET_CONSTANTS_SERVICE_RETRY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500) /** * After how long do we consider a service unresponsive * even if we assume that the service commonly does not * respond instantly (DNS, Database, etc.). */ #define GNUNET_CONSTANTS_SERVICE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 10) /** * How long do we delay messages to get larger packet sizes (CORKing)? */ #define GNUNET_CONSTANTS_MAX_CORK_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) /** * Until which load do we consider the peer overly idle * (which means that we would like to use more resources).

    * * Note that we use 70 to leave some room for applications * to consume resources "idly" (i.e. up to 85%) and then * still have some room for "paid for" resource consumption. */ #define GNUNET_CONSTANTS_IDLE_LOAD_THRESHOLD 70 /** * For how long do we allow unused bandwidth * from the past to carry over into the future? (in seconds) */ #define GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S 5 /** * After how long do we expire an address in a HELLO that we just * validated? This value is also used for our own addresses when we * create a HELLO. */ #define GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12) /** * Size of the 'struct EncryptedMessage' of the core (which * is the per-message overhead of the core). */ #define GNUNET_CONSTANTS_CORE_SIZE_ENCRYPTED_MESSAGE (24 + sizeof (GNUNET_HashCode)) /** * Size of the 'struct OutboundMessage' of the transport * (which, in combination with the * GNUNET_CONSTANTS_CORE_SIZE_ENCRYPTED_MESSAGE) defines * the headers that must be pre-pendable to all GNUnet * messages. Taking GNUNET_SERVER_MAX_MESSAGE_SIZE * and subtracting these two constants defines the largest * message core can handle. */ #define GNUNET_CONSTANTS_TRANSPORT_SIZE_OUTBOUND_MESSAGE (16 + sizeof (struct GNUNET_PeerIdentity)) /** * What is the maximum size for encrypted messages? Note that this * number imposes a clear limit on the maximum size of any message. * Set to a value close to 64k but not so close that transports will * have trouble with their headers. * * Could theoretically be 64k minus (GNUNET_CONSTANTS_CORE_SIZE_ENCRYPTED_MESSAGE + * GNUNET_CONSTANTS_TRANSPORT_SIZE_OUTBOUND_MESSAGE), but we're going * to be more conservative for now. */ #define GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE (63 * 1024) /** * K-value that must be used for the bloom filters in 'GET' * queries. */ #define GNUNET_CONSTANTS_BLOOMFILTER_K 16 #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif #endif gnunet-0.9.3/src/include/gnunet_bio_lib.h0000644000175000017500000001655011760502552015320 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_bio_lib.h * @brief buffered IO API * @author Christian Grothoff */ #ifndef GNUNET_BIO_LIB_H #define GNUNET_BIO_LIB_H #include "gnunet_container_lib.h" #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * Handle for buffered reading. */ struct GNUNET_BIO_ReadHandle; /** * Open a file for reading. * * @param fn file name to be opened * @return IO handle on success, NULL on error */ struct GNUNET_BIO_ReadHandle * GNUNET_BIO_read_open (const char *fn); /** * Close an open file. Reports if any errors reading * from the file were encountered. * * @param h file handle * @param emsg set to the error message * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_BIO_read_close (struct GNUNET_BIO_ReadHandle *h, char **emsg); /** * Read the contents of a binary file into a buffer. * * @param h handle to an open file * @param what describes what is being read (for error message creation) * @param result the buffer to write the result to * @param len the number of bytes to read * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int GNUNET_BIO_read (struct GNUNET_BIO_ReadHandle *h, const char *what, void *result, size_t len); /** * Read the contents of a binary file into a buffer. * * @param h handle to an open file * @param file name of the source file * @param line line number in the source file * @param result the buffer to write the result to * @param len the number of bytes to read * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int GNUNET_BIO_read_fn (struct GNUNET_BIO_ReadHandle *h, const char *file, int line, void *result, size_t len); /** * Read 0-terminated string from a file. * * @param h handle to an open file * @param what describes what is being read (for error message creation) * @param result the buffer to store a pointer to the (allocated) string to * (note that *result could be set to NULL as well) * @param maxLen maximum allowed length for the string * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int GNUNET_BIO_read_string (struct GNUNET_BIO_ReadHandle *h, const char *what, char **result, size_t maxLen); /** * Read metadata container from a file. * * @param h handle to an open file * @param what describes what is being read (for error message creation) * @param result the buffer to store a pointer to the (allocated) metadata * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int GNUNET_BIO_read_meta_data (struct GNUNET_BIO_ReadHandle *h, const char *what, struct GNUNET_CONTAINER_MetaData **result); /** * Read a float. * * @param h hande to open file * @param f address of float to read */ #define GNUNET_BIO_read_float(h, f) (GNUNET_BIO_read_fn (h, __FILE__, __LINE__, f, sizeof(float))) /** * Read a double. * * @param h hande to open file * @param f address of double to read */ #define GNUNET_BIO_read_double(h, f) (GNUNET_BIO_read_fn (h, __FILE__, __LINE__, f, sizeof(double))) /** * Read an (u)int32_t. * * @param h hande to open file * @param file name of the source file * @param line line number in the code * @param i address of 32-bit integer to read * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_BIO_read_int32__ (struct GNUNET_BIO_ReadHandle *h, const char *file, int line, int32_t * i); /** * Read an (u)int32_t. * * @param h hande to open file * @param i address of 32-bit integer to read */ #define GNUNET_BIO_read_int32(h, i) GNUNET_BIO_read_int32__ (h, __FILE__, __LINE__, (int32_t*) i) /** * Read an (u)int64_t. * * @param h hande to open file * @param file name of the source file * @param line line number in the code * @param i address of 64-bit integer to read * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_BIO_read_int64__ (struct GNUNET_BIO_ReadHandle *h, const char *file, int line, int64_t * i); /** * Read an (u)int64_t. * * @param h hande to open file * @param i address of 64-bit integer to read */ #define GNUNET_BIO_read_int64(h, i) GNUNET_BIO_read_int64__ (h, __FILE__, __LINE__, (int64_t*) i) /** * Handle for buffered writing. */ struct GNUNET_BIO_WriteHandle; /** * Open a file for writing. * * @param fn file name to be opened * @return IO handle on success, NULL on error */ struct GNUNET_BIO_WriteHandle * GNUNET_BIO_write_open (const char *fn); /** * Close an open file for writing. * * @param h file handle * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_BIO_write_close (struct GNUNET_BIO_WriteHandle *h); /** * Write a buffer to a file. * * @param h handle to open file * @param buffer the data to write * @param n number of bytes to write * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_BIO_write (struct GNUNET_BIO_WriteHandle *h, const void *buffer, size_t n); /** * Write a string to a file. * * @param h handle to open file * @param s string to write (can be NULL) * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_BIO_write_string (struct GNUNET_BIO_WriteHandle *h, const char *s); /** * Write metadata container to a file. * * @param h handle to open file * @param m metadata to write * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_BIO_write_meta_data (struct GNUNET_BIO_WriteHandle *h, const struct GNUNET_CONTAINER_MetaData *m); /** * Write a float. * * @param h hande to open file * @param f float to write (must be a variable) */ #define GNUNET_BIO_write_float(h, f) GNUNET_BIO_write (h, &f, sizeof(float)) /** * Write a double. * * @param h hande to open file * @param f double to write (must be a variable) */ #define GNUNET_BIO_write_double(h, f) GNUNET_BIO_write (h, &f, sizeof(double)) /** * Write an (u)int32_t. * * @param h hande to open file * @param i 32-bit integer to write * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_BIO_write_int32 (struct GNUNET_BIO_WriteHandle *h, int32_t i); /** * Write an (u)int64_t. * * @param h hande to open file * @param i 64-bit integer to write * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_BIO_write_int64 (struct GNUNET_BIO_WriteHandle *h, int64_t i); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_BIO_LIB_H */ #endif /* end of gnunet_bio_lib.h */ gnunet-0.9.3/src/include/Makefile.in0000644000175000017500000006525111762217212014235 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = src/include DIST_COMMON = $(am__gnunetinclude_HEADERS_DIST) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/gnunet_directories.h.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = gnunet_directories.h CONFIG_CLEAN_VPATH_FILES = AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive am__gnunetinclude_HEADERS_DIST = gauger.h gettext.h platform.h plibc.h \ winproc.h block_dns.h block_gns.h block_fs.h \ gnunet_applications.h gnunet_arm_service.h \ gnunet_ats_service.h gnunet_bandwidth_lib.h gnunet_bio_lib.h \ gnunet_block_lib.h gnunet_block_plugin.h gnunet_client_lib.h \ gnunet_chat_service.h gnunet_common.h gnunet_constants.h \ gnunet_configuration_lib.h gnunet_container_lib.h \ gnunet_connection_lib.h gnunet_core_service.h \ gnunet_crypto_lib.h gnunet_datacache_lib.h \ gnunet_datacache_plugin.h gnunet_datastore_service.h \ gnunet_datastore_plugin.h gnunet_dht_service.h \ gnunet_disk_lib.h gnunet_dnsparser_lib.h gnunet_dns_service.h \ gnunet_dv_service.h gnunet_fragmentation_lib.h \ gnunet_fs_service.h gnunet_getopt_lib.h gnunet_gns_service.h \ gnunet_hello_lib.h gnunet_helper_lib.h gnunet_load_lib.h \ gnunet_lockmanager_service.h gnunet_mesh_service.h \ gnunet_mysql_lib.h gnunet_namestore_plugin.h \ gnunet_namestore_service.h gnunet_nat_lib.h \ gnunet_network_lib.h gnunet_nse_service.h gnunet_os_lib.h \ gnunet_peer_lib.h gnunet_peerinfo_service.h \ gnunet_plugin_lib.h gnunet_postgres_lib.h gnunet_program_lib.h \ gnunet_protocols.h gnunet_pseudonym_lib.h \ gnunet_resolver_service.h gnunet_regex_lib.h \ gnunet_scheduler_lib.h gnunet_server_lib.h \ gnunet_service_lib.h gnunet_signal_lib.h gnunet_signatures.h \ gnunet_statistics_service.h gnunet_stream_lib.h \ gnunet_strings_lib.h gnunet_testbed_service.h \ gnunet_testing_lib.h gnunet_testing_lib-new.h \ gnunet_time_lib.h gnunet_transport_service.h \ gnunet_transport_plugin.h gnunet_tun_lib.h gnunet_util_lib.h \ gnunet_vpn_service.h am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(gnunetincludedir)" \ "$(DESTDIR)$(gnunetincludedir)" HEADERS = $(gnunetinclude_HEADERS) $(nodist_gnunetinclude_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = . gnunetincludedir = $(includedir)/gnunet nodist_gnunetinclude_HEADERS = \ gnunet_directories.h \ block_fs.h @MINGW_TRUE@WINPROC = winproc.h gnunetinclude_HEADERS = \ gauger.h \ gettext.h \ platform.h \ plibc.h \ $(WINPROC) \ block_dns.h \ block_gns.h \ block_fs.h \ gnunet_applications.h \ gnunet_arm_service.h \ gnunet_ats_service.h \ gnunet_bandwidth_lib.h \ gnunet_bio_lib.h \ gnunet_block_lib.h \ gnunet_block_plugin.h \ gnunet_client_lib.h \ gnunet_chat_service.h \ gnunet_common.h \ gnunet_constants.h \ gnunet_configuration_lib.h \ gnunet_container_lib.h \ gnunet_connection_lib.h \ gnunet_core_service.h \ gnunet_crypto_lib.h \ gnunet_datacache_lib.h \ gnunet_datacache_plugin.h \ gnunet_datastore_service.h \ gnunet_datastore_plugin.h \ gnunet_dht_service.h \ gnunet_disk_lib.h \ gnunet_dnsparser_lib.h \ gnunet_dns_service.h \ gnunet_dv_service.h \ gnunet_fragmentation_lib.h \ gnunet_fs_service.h \ gnunet_getopt_lib.h \ gnunet_gns_service.h \ gnunet_hello_lib.h \ gnunet_helper_lib.h \ gnunet_load_lib.h \ gnunet_lockmanager_service.h \ gnunet_mesh_service.h \ gnunet_mysql_lib.h \ gnunet_namestore_plugin.h \ gnunet_namestore_service.h \ gnunet_nat_lib.h \ gnunet_network_lib.h \ gnunet_nse_service.h \ gnunet_os_lib.h \ gnunet_peer_lib.h \ gnunet_peerinfo_service.h \ gnunet_plugin_lib.h \ gnunet_postgres_lib.h \ gnunet_program_lib.h \ gnunet_protocols.h \ gnunet_pseudonym_lib.h \ gnunet_resolver_service.h \ gnunet_regex_lib.h \ gnunet_scheduler_lib.h \ gnunet_server_lib.h \ gnunet_service_lib.h \ gnunet_signal_lib.h \ gnunet_signatures.h \ gnunet_statistics_service.h \ gnunet_stream_lib.h \ gnunet_strings_lib.h \ gnunet_testbed_service.h \ gnunet_testing_lib.h \ gnunet_testing_lib-new.h \ gnunet_time_lib.h \ gnunet_transport_service.h \ gnunet_transport_plugin.h \ gnunet_tun_lib.h \ gnunet_util_lib.h \ gnunet_vpn_service.h all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/include/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/include/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): gnunet_directories.h: $(top_builddir)/config.status $(srcdir)/gnunet_directories.h.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-gnunetincludeHEADERS: $(gnunetinclude_HEADERS) @$(NORMAL_INSTALL) test -z "$(gnunetincludedir)" || $(MKDIR_P) "$(DESTDIR)$(gnunetincludedir)" @list='$(gnunetinclude_HEADERS)'; test -n "$(gnunetincludedir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(gnunetincludedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(gnunetincludedir)" || exit $$?; \ done uninstall-gnunetincludeHEADERS: @$(NORMAL_UNINSTALL) @list='$(gnunetinclude_HEADERS)'; test -n "$(gnunetincludedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(gnunetincludedir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(gnunetincludedir)" && rm -f $$files install-nodist_gnunetincludeHEADERS: $(nodist_gnunetinclude_HEADERS) @$(NORMAL_INSTALL) test -z "$(gnunetincludedir)" || $(MKDIR_P) "$(DESTDIR)$(gnunetincludedir)" @list='$(nodist_gnunetinclude_HEADERS)'; test -n "$(gnunetincludedir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(gnunetincludedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(gnunetincludedir)" || exit $$?; \ done uninstall-nodist_gnunetincludeHEADERS: @$(NORMAL_UNINSTALL) @list='$(nodist_gnunetinclude_HEADERS)'; test -n "$(gnunetincludedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(gnunetincludedir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(gnunetincludedir)" && rm -f $$files # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. # To change the values of `make' variables: instead of editing Makefiles, # (1) if the variable is set in `config.status', edit `config.status' # (which will cause the Makefiles to be regenerated when you run `make'); # (2) otherwise, pass the desired values on the `make' command line. $(RECURSIVE_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ list='$(SUBDIRS)'; for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ rev="$$rev ."; \ target=`echo $@ | sed s/-recursive//`; \ for subdir in $$rev; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(HEADERS) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(gnunetincludedir)" "$(DESTDIR)$(gnunetincludedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-gnunetincludeHEADERS \ install-nodist_gnunetincludeHEADERS install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-gnunetincludeHEADERS \ uninstall-nodist_gnunetincludeHEADERS .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ install-am install-strip tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am check check-am clean clean-generic clean-libtool \ ctags ctags-recursive distclean distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-gnunetincludeHEADERS install-html \ install-html-am install-info install-info-am install-man \ install-nodist_gnunetincludeHEADERS install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ uninstall uninstall-am uninstall-gnunetincludeHEADERS \ uninstall-nodist_gnunetincludeHEADERS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/include/gnunet_datastore_service.h0000644000175000017500000004114111760502552017421 00000000000000/* This file is part of GNUnet (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_datastore_service.h * @brief API that can be used manage the * datastore for files stored on a GNUnet node; * note that the datastore is NOT responsible for * on-demand encoding, that is achieved using * a special kind of entry. * @author Christian Grothoff */ #ifndef GNUNET_DATASTORE_SERVICE_H #define GNUNET_DATASTORE_SERVICE_H #include "gnunet_util_lib.h" #include "gnunet_block_lib.h" #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * Entry in the queue. */ struct GNUNET_DATASTORE_QueueEntry; /** * Handle to the datastore service. */ struct GNUNET_DATASTORE_Handle; /** * Maximum size of a value that can be stored in the datastore. */ #define GNUNET_DATASTORE_MAX_VALUE_SIZE 65536 /** * Connect to the datastore service. * * @param cfg configuration to use * @return handle to use to access the service */ struct GNUNET_DATASTORE_Handle * GNUNET_DATASTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); /** * Disconnect from the datastore service (and free * associated resources). * * @param h handle to the datastore * @param drop set to GNUNET_YES to delete all data in datastore (!) */ void GNUNET_DATASTORE_disconnect (struct GNUNET_DATASTORE_Handle *h, int drop); /** * Continuation called to notify client about result of the * operation. * * @param cls closure * @param success GNUNET_SYSERR on failure (including timeout/queue drop) * GNUNET_NO if content was already there * GNUNET_YES (or other positive value) on success * @param min_expiration minimum expiration time required for 0-priority content to be stored * by the datacache at this time, zero for unknown, forever if we have no * space for 0-priority content * @param msg NULL on success, otherwise an error message */ typedef void (*GNUNET_DATASTORE_ContinuationWithStatus) (void *cls, int32_t success, struct GNUNET_TIME_Absolute min_expiration, const char *msg); /** * Reserve space in the datastore. This function should be used * to avoid "out of space" failures during a longer sequence of "put" * operations (for example, when a file is being inserted). * * @param h handle to the datastore * @param amount how much space (in bytes) should be reserved (for content only) * @param entries how many entries will be created (to calculate per-entry overhead) * @param queue_priority ranking of this request in the priority queue * @param max_queue_size at what queue size should this request be dropped * (if other requests of higher priority are in the queue) * @param timeout how long to wait at most for a response (or before dying in queue) * @param cont continuation to call when done; "success" will be set to * a positive reservation value if space could be reserved. * @param cont_cls closure for cont * @return NULL if the entry was not queued, otherwise a handle that can be used to * cancel; note that even if NULL is returned, the callback will be invoked * (or rather, will already have been invoked) */ struct GNUNET_DATASTORE_QueueEntry * GNUNET_DATASTORE_reserve (struct GNUNET_DATASTORE_Handle *h, uint64_t amount, uint32_t entries, unsigned int queue_priority, unsigned int max_queue_size, struct GNUNET_TIME_Relative timeout, GNUNET_DATASTORE_ContinuationWithStatus cont, void *cont_cls); /** * Store an item in the datastore. If the item is already present, * the priorities and replication values are summed up and the higher * expiration time and lower anonymity level is used. * * @param h handle to the datastore * @param rid reservation ID to use (from "reserve"); use 0 if no * prior reservation was made * @param key key for the value * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param replication how often should the content be replicated to other peers? * @param expiration expiration time for the content * @param queue_priority ranking of this request in the priority queue * @param max_queue_size at what queue size should this request be dropped * (if other requests of higher priority are in the queue) * @param timeout timeout for the operation * @param cont continuation to call when done * @param cont_cls closure for cont * @return NULL if the entry was not queued, otherwise a handle that can be used to * cancel; note that even if NULL is returned, the callback will be invoked * (or rather, will already have been invoked) */ struct GNUNET_DATASTORE_QueueEntry * GNUNET_DATASTORE_put (struct GNUNET_DATASTORE_Handle *h, uint32_t rid, const GNUNET_HashCode * key, size_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, uint32_t replication, struct GNUNET_TIME_Absolute expiration, unsigned int queue_priority, unsigned int max_queue_size, struct GNUNET_TIME_Relative timeout, GNUNET_DATASTORE_ContinuationWithStatus cont, void *cont_cls); /** * Signal that all of the data for which a reservation was made has * been stored and that whatever excess space might have been reserved * can now be released. * * @param h handle to the datastore * @param rid reservation ID (value of "success" in original continuation * from the "reserve" function). * @param queue_priority ranking of this request in the priority queue * @param max_queue_size at what queue size should this request be dropped * (if other requests of higher priority are in the queue) * @param queue_priority ranking of this request in the priority queue * @param max_queue_size at what queue size should this request be dropped * (if other requests of higher priority are in the queue) * @param timeout how long to wait at most for a response * @param cont continuation to call when done * @param cont_cls closure for cont * @return NULL if the entry was not queued, otherwise a handle that can be used to * cancel; note that even if NULL is returned, the callback will be invoked * (or rather, will already have been invoked) */ struct GNUNET_DATASTORE_QueueEntry * GNUNET_DATASTORE_release_reserve (struct GNUNET_DATASTORE_Handle *h, uint32_t rid, unsigned int queue_priority, unsigned int max_queue_size, struct GNUNET_TIME_Relative timeout, GNUNET_DATASTORE_ContinuationWithStatus cont, void *cont_cls); /** * Update a value in the datastore. * * @param h handle to the datastore * @param uid identifier for the value * @param priority how much to increase the priority of the value * @param expiration new expiration value should be MAX of existing and this argument * @param queue_priority ranking of this request in the priority queue * @param max_queue_size at what queue size should this request be dropped * (if other requests of higher priority are in the queue) * @param timeout how long to wait at most for a response * @param cont continuation to call when done * @param cont_cls closure for cont * @return NULL if the entry was not queued, otherwise a handle that can be used to * cancel; note that even if NULL is returned, the callback will be invoked * (or rather, will already have been invoked) */ struct GNUNET_DATASTORE_QueueEntry * GNUNET_DATASTORE_update (struct GNUNET_DATASTORE_Handle *h, uint64_t uid, uint32_t priority, struct GNUNET_TIME_Absolute expiration, unsigned int queue_priority, unsigned int max_queue_size, struct GNUNET_TIME_Relative timeout, GNUNET_DATASTORE_ContinuationWithStatus cont, void *cont_cls); /** * Explicitly remove some content from the database. * The "cont"inuation will be called with status * "GNUNET_OK" if content was removed, "GNUNET_NO" * if no matching entry was found and "GNUNET_SYSERR" * on all other types of errors. * * @param h handle to the datastore * @param key key for the value * @param size number of bytes in data * @param data content stored * @param queue_priority ranking of this request in the priority queue * @param max_queue_size at what queue size should this request be dropped * (if other requests of higher priority are in the queue) * @param timeout how long to wait at most for a response * @param cont continuation to call when done * @param cont_cls closure for cont * @return NULL if the entry was not queued, otherwise a handle that can be used to * cancel; note that even if NULL is returned, the callback will be invoked * (or rather, will already have been invoked) */ struct GNUNET_DATASTORE_QueueEntry * GNUNET_DATASTORE_remove (struct GNUNET_DATASTORE_Handle *h, const GNUNET_HashCode * key, size_t size, const void *data, unsigned int queue_priority, unsigned int max_queue_size, struct GNUNET_TIME_Relative timeout, GNUNET_DATASTORE_ContinuationWithStatus cont, void *cont_cls); /** * Process a datum that was stored in the datastore. * * @param cls closure * @param key key for the content * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param expiration expiration time for the content * @param uid unique identifier for the datum; * maybe 0 if no unique identifier is available */ typedef void (*GNUNET_DATASTORE_DatumProcessor) (void *cls, const GNUNET_HashCode * key, size_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid); /** * Get a result for a particular key from the datastore. The processor * will only be called once. * * @param h handle to the datastore * @param offset offset of the result (modulo num-results); set to * a random 64-bit value initially; then increment by * one each time; detect that all results have been found by uid * being again the first uid ever returned. * @param key maybe NULL (to match all entries) * @param type desired type, 0 for any * @param queue_priority ranking of this request in the priority queue * @param max_queue_size at what queue size should this request be dropped * (if other requests of higher priority are in the queue) * @param timeout how long to wait at most for a response * @param proc function to call on a matching value; * or with a NULL value if no datum matches * @param proc_cls closure for proc * @return NULL if the entry was not queued, otherwise a handle that can be used to * cancel */ struct GNUNET_DATASTORE_QueueEntry * GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h, uint64_t offset, const GNUNET_HashCode * key, enum GNUNET_BLOCK_Type type, unsigned int queue_priority, unsigned int max_queue_size, struct GNUNET_TIME_Relative timeout, GNUNET_DATASTORE_DatumProcessor proc, void *proc_cls); /** * Get a single zero-anonymity value from the datastore. * Note that some implementations can ignore the 'offset' and * instead return a random zero-anonymity value. In that case, * detecting the wrap-around based on a repeating UID is at best * probabilistic. * * @param h handle to the datastore * @param offset offset of the result (modulo num-results); set to * a random 64-bit value initially; then increment by * one each time; detect that all results have been found by uid * being again the first uid ever returned. * @param queue_priority ranking of this request in the priority queue * @param max_queue_size at what queue size should this request be dropped * (if other requests of higher priority are in the queue) * @param timeout how long to wait at most for a response * @param type allowed type for the operation (never zero) * @param proc function to call on a random value; it * will be called once with a value (if available) * or with NULL if none value exists. * @param proc_cls closure for proc * @return NULL if the entry was not queued, otherwise a handle that can be used to * cancel */ struct GNUNET_DATASTORE_QueueEntry * GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h, uint64_t offset, unsigned int queue_priority, unsigned int max_queue_size, struct GNUNET_TIME_Relative timeout, enum GNUNET_BLOCK_Type type, GNUNET_DATASTORE_DatumProcessor proc, void *proc_cls); /** * Get a random value from the datastore for content replication. * Returns a single, random value among those with the highest * replication score, lowering positive replication scores by one for * the chosen value (if only content with a replication score exists, * a random value is returned and replication scores are not changed). * * @param h handle to the datastore * @param queue_priority ranking of this request in the priority queue * @param max_queue_size at what queue size should this request be dropped * (if other requests of higher priority are in the queue) * @param timeout how long to wait at most for a response * @param proc function to call on a random value; it * will be called once with a value (if available) * and always once with a value of NULL. * @param proc_cls closure for proc * @return NULL if the entry was not queued, otherwise a handle that can be used to * cancel */ struct GNUNET_DATASTORE_QueueEntry * GNUNET_DATASTORE_get_for_replication (struct GNUNET_DATASTORE_Handle *h, unsigned int queue_priority, unsigned int max_queue_size, struct GNUNET_TIME_Relative timeout, GNUNET_DATASTORE_DatumProcessor proc, void *proc_cls); /** * Cancel a datastore operation. The final callback from the * operation must not have been done yet. * * @param qe operation to cancel */ void GNUNET_DATASTORE_cancel (struct GNUNET_DATASTORE_QueueEntry *qe); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* end of gnunet_datastore_service.h */ #endif gnunet-0.9.3/src/include/gnunet_block_plugin.h0000644000175000017500000001153411760502552016366 00000000000000/* This file is part of GNUnet (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_block_plugin.h * @brief API for block plugins. Each block plugin must conform to * the API specified by this header. * @author Christian Grothoff */ #ifndef PLUGIN_BLOCK_H #define PLUGIN_BLOCK_H #include "gnunet_util_lib.h" #include "gnunet_container_lib.h" #include "gnunet_block_lib.h" /** * Function called to validate a reply or a request. For * request evaluation, simply pass "NULL" for the reply_block. * Note that it is assumed that the reply has already been * matched to the key (and signatures checked) as it would * be done with the "get_key" function. * * @param cls closure * @param type block type * @param query original query (hash) * @param bf pointer to bloom filter associated with query; possibly updated (!) * @param bf_mutator mutation value for bf * @param xquery extrended query data (can be NULL, depending on type) * @param xquery_size number of bytes in xquery * @param reply_block response to validate * @param reply_block_size number of bytes in reply block * @return characterization of result */ typedef enum GNUNET_BLOCK_EvaluationResult (*GNUNET_BLOCK_EvaluationFunction) (void *cls, enum GNUNET_BLOCK_Type type, const GNUNET_HashCode * query, struct GNUNET_CONTAINER_BloomFilter ** bf, int32_t bf_mutator, const void *xquery, size_t xquery_size, const void *reply_block, size_t reply_block_size); /** * Function called to obtain the key for a block. * * @param cls closure * @param type block type * @param block block to get the key for * @param block_size number of bytes in block * @param key set to the key (query) for the given block * @return GNUNET_YES on success, * GNUNET_NO if the block is malformed * GNUNET_SYSERR if type not supported * (or if extracting a key from a block of this type does not work) */ typedef int (*GNUNET_BLOCK_GetKeyFunction) (void *cls, enum GNUNET_BLOCK_Type type, const void *block, size_t block_size, GNUNET_HashCode * key); /** * Each plugin is required to return a pointer to a struct of this * type as the return value from its entry point. */ struct GNUNET_BLOCK_PluginFunctions { /** * Closure for all of the callbacks. */ void *cls; /** * 0-terminated array of block types supported by this plugin. */ const enum GNUNET_BLOCK_Type *types; /** * Main function of a block plugin. Allows us to check if a * block matches a query. */ GNUNET_BLOCK_EvaluationFunction evaluate; /** * Obtain the key for a given block (if possible). */ GNUNET_BLOCK_GetKeyFunction get_key; }; #endif gnunet-0.9.3/src/include/gnunet_network_lib.h0000644000175000017500000003006311762202311016223 00000000000000/* This file is part of GNUnet. (C) 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_network_lib.h * @brief basic low-level networking interface * @author Nils Durner */ #ifndef GNUNET_NETWORK_LIB_H #define GNUNET_NETWORK_LIB_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * @brief handle to a socket */ struct GNUNET_NETWORK_Handle; /** * @brief collection of IO descriptors */ struct GNUNET_NETWORK_FDSet { /** * Maximum number of any socket socket descriptor in the set (plus one) */ int nsds; /** * Bitset with the descriptors. */ fd_set sds; #ifdef WINDOWS /** * Linked list of handles */ struct GNUNET_CONTAINER_SList *handles; #endif }; #include "gnunet_disk_lib.h" #include "gnunet_time_lib.h" /** * Accept a new connection on a socket. Configure it for non-blocking * IO and mark it as non-inheritable to child processes (set the * close-on-exec flag). * * @param desc bound socket * @param address address of the connecting peer, may be NULL * @param address_len length of address * @return client socket */ struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Handle *desc, struct sockaddr *address, socklen_t * address_len); /** * Box a native socket (and check that it is a socket). * * @param fd socket to box * @return NULL on error (including not supported on target platform) */ struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_box_native (SOCKTYPE fd); /** * Bind to a connected socket * * @param desc socket to bind * @param address address to be bound * @param address_len length of address * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc, const struct sockaddr *address, socklen_t address_len); /** * Close a socket. * * @param desc socket to close * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Handle *desc); /** * Connect a socket * * @param desc socket to connect * @param address peer address * @param address_len of address * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_NETWORK_socket_connect (const struct GNUNET_NETWORK_Handle *desc, const struct sockaddr *address, socklen_t address_len); /** * Get socket options * * @param desc socket to inspect * @param level protocol level of the option * @param optname identifier of the option * @param optval options * @param optlen length of optval * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_NETWORK_socket_getsockopt (const struct GNUNET_NETWORK_Handle *desc, int level, int optname, void *optval, socklen_t * optlen); /** * Listen on a socket * * @param desc socket to start listening on * @param backlog length of the listen queue * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Handle *desc, int backlog); /** * How much data is available to be read on this descriptor? * @param desc socket */ ssize_t GNUNET_NETWORK_socket_recvfrom_amount (const struct GNUNET_NETWORK_Handle *desc); /** * Read data from a connected socket (always non-blocking). * @param desc socket * @param buffer buffer * @param length length of buffer * @param src_addr either the source to recv from, or all zeroes * to be filled in by recvfrom * @param addrlen length of the addr */ ssize_t GNUNET_NETWORK_socket_recvfrom (const struct GNUNET_NETWORK_Handle *desc, void *buffer, size_t length, struct sockaddr *src_addr, socklen_t * addrlen); /** * Read data from a connected socket (always non-blocking). * * @param desc socket * @param buffer buffer * @param length length of buffer * @return number of bytes read */ ssize_t GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Handle *desc, void *buffer, size_t length); /** * Check if sockets meet certain conditions * @param rfds set of sockets to be checked for readability * @param wfds set of sockets to be checked for writability * @param efds set of sockets to be checked for exceptions * @param timeout relative value when to return * @return number of selected sockets, GNUNET_SYSERR on error */ int GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, struct GNUNET_NETWORK_FDSet *wfds, struct GNUNET_NETWORK_FDSet *efds, struct GNUNET_TIME_Relative timeout); /** * Send data (always non-blocking). * * @param desc socket * @param buffer data to send * @param length size of the buffer * @return number of bytes sent, GNUNET_SYSERR on error */ ssize_t GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Handle *desc, const void *buffer, size_t length); /** * Send data to a particular destination (always non-blocking). * This function only works for UDP sockets. * * @param desc socket * @param message data to send * @param length size of the data * @param dest_addr destination address * @param dest_len length of address * @return number of bytes sent, GNUNET_SYSERR on error */ ssize_t GNUNET_NETWORK_socket_sendto (const struct GNUNET_NETWORK_Handle *desc, const void *message, size_t length, const struct sockaddr *dest_addr, socklen_t dest_len); /** * Set socket option * * @param fd socket * @param level protocol level of the option * @param option_name option identifier * @param option_value value to set * @param option_len size of option_value * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_NETWORK_socket_setsockopt (struct GNUNET_NETWORK_Handle *fd, int level, int option_name, const void *option_value, socklen_t option_len); /** * Shut down socket operations * * @param desc socket * @param how type of shutdown * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Handle *desc, int how); /** * Disable the "CORK" feature for communication with the given socket, * forcing the OS to immediately flush the buffer on transmission * instead of potentially buffering multiple messages. Essentially * reduces the OS send buffers to zero. * * @param desc socket * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_NETWORK_socket_disable_corking (struct GNUNET_NETWORK_Handle *desc); /** * Create a new socket. Configure it for non-blocking IO and * mark it as non-inheritable to child processes (set the * close-on-exec flag). * * @param domain domain of the socket * @param type socket type * @param protocol network protocol * @return new socket, NULL on error */ struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_create (int domain, int type, int protocol); /** * Reset FD set (clears all file descriptors). * * @param fds fd set to clear */ void GNUNET_NETWORK_fdset_zero (struct GNUNET_NETWORK_FDSet *fds); /** * Add a socket to the FD set * @param fds fd set * @param desc socket to add */ void GNUNET_NETWORK_fdset_set (struct GNUNET_NETWORK_FDSet *fds, const struct GNUNET_NETWORK_Handle *desc); #if WINDOWS /** * Add a W32 file handle to the fd set * @param fds fd set * @param h the file handle to add */ void GNUNET_NETWORK_fdset_handle_set_native_w32_handle (struct GNUNET_NETWORK_FDSet *fds, HANDLE h); #endif /** * Check whether a socket is part of the fd set * @param fds fd set * @param desc socket * @return GNUNET_YES if the socket is in the set */ int GNUNET_NETWORK_fdset_isset (const struct GNUNET_NETWORK_FDSet *fds, const struct GNUNET_NETWORK_Handle *desc); /** * Add one fd set to another * @param dst the fd set to add to * @param src the fd set to add from */ void GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst, const struct GNUNET_NETWORK_FDSet *src); /** * Copy one fd set to another * @param to destination * @param from source */ void GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to, const struct GNUNET_NETWORK_FDSet *from); /** * Return file descriptor for this network handle * * @param desc wrapper to process * @return POSIX file descriptor */ int GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc); /** * Return the sockaddr for this network handle * * @param desc wrapper to process * @return POSIX file descriptor */ struct sockaddr* GNUNET_NETWORK_get_addr (struct GNUNET_NETWORK_Handle *desc); /** * Return sockaddr length for this network handle * * @param desc wrapper to process * @return socklen_t for sockaddr */ socklen_t GNUNET_NETWORK_get_addrlen (struct GNUNET_NETWORK_Handle *desc); /** * Copy a native fd set * @param to destination * @param from native source set * @param nfds the biggest socket number in from + 1 */ void GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to, const fd_set * from, int nfds); /** * Set a native fd in a set * * @param to destination * @param nfd native FD to set */ void GNUNET_NETWORK_fdset_set_native (struct GNUNET_NETWORK_FDSet *to, int nfd); /** * Test native fd in a set * * @param to set to test, NULL for empty set * @param nfd native FD to test, -1 for none * @return GNUNET_YES if to contains nfd */ int GNUNET_NETWORK_fdset_test_native (const struct GNUNET_NETWORK_FDSet *to, int nfd); /** * Add a file handle to the fd set * @param fds fd set * @param h the file handle to add */ void GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds, const struct GNUNET_DISK_FileHandle *h); /** * Check if a file handle is part of an fd set * @param fds fd set * @param h file handle * @return GNUNET_YES if the file handle is part of the set */ int GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds, const struct GNUNET_DISK_FileHandle *h); /** * Checks if two fd sets overlap * @param fds1 first fd set * @param fds2 second fd set * @return GNUNET_YES if they do overlap, GNUNET_NO otherwise */ int GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1, const struct GNUNET_NETWORK_FDSet *fds2); /** * Creates an fd set * @return a new fd set */ struct GNUNET_NETWORK_FDSet * GNUNET_NETWORK_fdset_create (void); /** * Releases the associated memory of an fd set * @param fds fd set */ void GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif #endif /* GNUNET_NETWORK_LIB_H */ gnunet-0.9.3/src/include/gnunet_dns_service.h0000644000175000017500000001337211760502552016224 00000000000000/* This file is part of GNUnet (C) 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_dns_service.h * @brief API to access the DNS service. * @author Christian Grothoff */ #ifndef GNUNET_DNS_SERVICE_NEW_H #define GNUNET_DNS_SERVICE_NEW_H #include "gnunet_common.h" #include "gnunet_util_lib.h" /** * Opaque DNS handle */ struct GNUNET_DNS_Handle; /** * Handle to identify an individual DNS request. */ struct GNUNET_DNS_RequestHandle; /** * Flags that specify when to call the client's handler. */ enum GNUNET_DNS_Flags { /** * Useless option: never call the client. */ GNUNET_DNS_FLAG_NEVER = 0, /** * Set this flag to see all requests first prior to resolution * (for monitoring). Clients that set this flag must then * call "GNUNET_DNS_request_forward" when they process a request * for the first time. Caling "GNUNET_DNS_request_answer" is * not allowed for MONITOR peers. */ GNUNET_DNS_FLAG_REQUEST_MONITOR = 1, /** * This client should be called on requests that have not * yet been resolved as this client provides a resolution * service. Note that this does not guarantee that the * client will see all requests as another client might be * called first and that client might have already done the * resolution, in which case other pre-resolution clients * won't see the request anymore. */ GNUNET_DNS_FLAG_PRE_RESOLUTION = 2, /** * This client wants to be called on the results of a DNS resolution * (either resolved by PRE-RESOLUTION clients or the global DNS). * The client then has a chance to modify the answer (or cause it to * be dropped). There is no guarantee that other POST-RESOLUTION * client's won't modify (or drop) the answer afterwards. */ GNUNET_DNS_FLAG_POST_RESOLUTION = 4, /** * Set this flag to see all requests just before they are * returned to the network. Clients that set this flag must then * call "GNUNET_DNS_request_forward" when they process a request * for the last time. Caling "GNUNET_DNS_request_answer" is * not allowed for MONITOR peers. */ GNUNET_DNS_FLAG_RESPONSE_MONITOR = 8 }; /** * Signature of a function that is called whenever the DNS service * encounters a DNS request and needs to do something with it. The * function has then the chance to generate or modify the response by * calling one of the three "GNUNET_DNS_request_*" continuations. * * When a request is intercepted, this function is called first to * give the client a chance to do the complete address resolution; * "rdata" will be NULL for this first call for a DNS request, unless * some other client has already filled in a response. * * If multiple clients exist, all of them are called before the global * DNS. The global DNS is only called if all of the clients' * functions call GNUNET_DNS_request_forward. Functions that call * GNUNET_DNS_request_forward will be called again before a final * response is returned to the application. If any of the clients' * functions call GNUNET_DNS_request_drop, the response is dropped. * * @param cls closure * @param rh request handle to user for reply * @param request_length number of bytes in request * @param request udp payload of the DNS request */ typedef void (*GNUNET_DNS_RequestHandler)(void *cls, struct GNUNET_DNS_RequestHandle *rh, size_t request_length, const char *request); /** * If a GNUNET_DNS_RequestHandler calls this function, the client * has no desire to interfer with the request and it should * continue to be processed normally. * * @param rh request that should now be forwarded */ void GNUNET_DNS_request_forward (struct GNUNET_DNS_RequestHandle *rh); /** * If a GNUNET_DNS_RequestHandler calls this function, the request is * to be dropped and no response should be generated. * * @param rh request that should now be dropped */ void GNUNET_DNS_request_drop (struct GNUNET_DNS_RequestHandle *rh); /** * If a GNUNET_DNS_RequestHandler calls this function, the request is * supposed to be answered with the data provided to this call (with * the modifications the function might have made). The reply given * must always be a valid DNS reply and not a mutated DNS request. * * @param rh request that should now be answered * @param reply_length size of reply (uint16_t to force sane size) * @param reply reply data */ void GNUNET_DNS_request_answer (struct GNUNET_DNS_RequestHandle *rh, uint16_t reply_length, const char *reply); /** * Connect to the service-dns * * @param cfg configuration to use * @param flags when to call rh * @param rh function to call with DNS requests * @param rh_cls closure to pass to rh * @return DNS handle */ struct GNUNET_DNS_Handle * GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, enum GNUNET_DNS_Flags flags, GNUNET_DNS_RequestHandler rh, void *rh_cls); /** * Disconnect from the DNS service. * * @param dh DNS handle */ void GNUNET_DNS_disconnect (struct GNUNET_DNS_Handle *dh); #endif gnunet-0.9.3/src/include/gnunet_helper_lib.h0000644000175000017500000000644011760502552016023 00000000000000/* This file is part of GNUnet. (C) 2011, 2012 Christian Grothoff GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_helper_lib.h * @brief API for dealing with (SUID) helper processes that communicate via GNUNET_MessageHeaders on stdin/stdout * @author Philipp Toelke * @author Christian Grothoff */ #ifndef GNUNET_HELPER_LIB_H #define GNUNET_HELPER_LIB_H #include "gnunet_scheduler_lib.h" #include "gnunet_server_lib.h" /** * The handle to a helper process. */ struct GNUNET_HELPER_Handle; /** * @brief Starts a helper and begins reading from it * * @param binary_name name of the binary to run * @param binary_argv NULL-terminated list of arguments to give when starting the binary (this * argument must not be modified by the client for * the lifetime of the helper handle) * @param cb function to call if we get messages from the helper * @param cb_cls Closure for the callback * @return the new Handle, NULL on error */ struct GNUNET_HELPER_Handle * GNUNET_HELPER_start (const char *binary_name, char *const binary_argv[], GNUNET_SERVER_MessageTokenizerCallback cb, void *cb_cls); /** * @brief Kills the helper, closes the pipe and frees the handle * * @param h handle to helper to stop */ void GNUNET_HELPER_stop (struct GNUNET_HELPER_Handle *h); /** * Continuation function. * * @param cls closure * @param result GNUNET_OK on success, * GNUNET_NO if helper process died * GNUNET_SYSERR during GNUNET_HELPER_stop */ typedef void (*GNUNET_HELPER_Continuation)(void *cls, int result); /** * Handle to cancel 'send' */ struct GNUNET_HELPER_SendHandle; /** * Send an message to the helper. * * @param h helper to send message to * @param msg message to send * @param can_drop can the message be dropped if there is already one in the queue? * @param cont continuation to run once the message is out * @param cont_cls closure for 'cont' * @return NULL if the message was dropped, * otherwise handle to cancel *cont* (actual transmission may * not be abortable) */ struct GNUNET_HELPER_SendHandle * GNUNET_HELPER_send (struct GNUNET_HELPER_Handle *h, const struct GNUNET_MessageHeader *msg, int can_drop, GNUNET_HELPER_Continuation cont, void *cont_cls); /** * Cancel a 'send' operation. If possible, transmitting the * message is also aborted, but at least 'cont' won't be * called. * * @param sh operation to cancel */ void GNUNET_HELPER_send_cancel (struct GNUNET_HELPER_SendHandle *sh); #endif /* end of include guard: GNUNET_HELPER_LIB_H */ gnunet-0.9.3/src/include/gnunet_tun_lib.h0000644000175000017500000002273711760502552015361 00000000000000/* This file is part of GNUnet. (C) 2010, 2011, 2012 Christian Grothoff GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_tun_lib.h * @brief standard TCP/IP network structs and IP checksum calculations for TUN interaction * @author Philipp Toelke * @author Christian Grothoff */ #ifndef GNUNET_TUN_LIB_H #define GNUNET_TUN_LIB_H #include "gnunet_util_lib.h" /* see http://www.iana.org/assignments/ethernet-numbers */ #ifndef ETH_P_IPV4 /** * Number for IPv4 */ #define ETH_P_IPV4 0x0800 #endif #ifndef ETH_P_IPV6 /** * Number for IPv6 */ #define ETH_P_IPV6 0x86DD #endif GNUNET_NETWORK_STRUCT_BEGIN /** * Header from Linux TUN interface. */ struct GNUNET_TUN_Layer2PacketHeader { /** * Some flags (unused). */ uint16_t flags GNUNET_PACKED; /** * Here we get an ETH_P_-number. */ uint16_t proto GNUNET_PACKED; }; /** * Standard IPv4 header. */ struct GNUNET_TUN_IPv4Header { #if __BYTE_ORDER == __LITTLE_ENDIAN unsigned int header_length:4 GNUNET_PACKED; unsigned int version:4 GNUNET_PACKED; #elif __BYTE_ORDER == __BIG_ENDIAN unsigned int version:4 GNUNET_PACKED; unsigned int header_length:4 GNUNET_PACKED; #else #error byteorder undefined #endif uint8_t diff_serv; /** * Length of the packet, including this header. */ uint16_t total_length GNUNET_PACKED; /** * Unique random ID for matching up fragments. */ uint16_t identification GNUNET_PACKED; unsigned int flags:3 GNUNET_PACKED; unsigned int fragmentation_offset:13 GNUNET_PACKED; /** * How many more hops can this packet be forwarded? */ uint8_t ttl; /** * L4-protocol, for example, IPPROTO_UDP or IPPROTO_TCP. */ uint8_t protocol; /** * Checksum. */ uint16_t checksum GNUNET_PACKED; /** * Origin of the packet. */ struct in_addr source_address GNUNET_PACKED; /** * Destination of the packet. */ struct in_addr destination_address GNUNET_PACKED; } GNUNET_GCC_STRUCT_LAYOUT; /** * Standard IPv6 header. */ struct GNUNET_TUN_IPv6Header { #if __BYTE_ORDER == __LITTLE_ENDIAN unsigned int traffic_class_h:4 GNUNET_PACKED; unsigned int version:4 GNUNET_PACKED; unsigned int traffic_class_l:4 GNUNET_PACKED; unsigned int flow_label:20 GNUNET_PACKED; #elif __BYTE_ORDER == __BIG_ENDIAN unsigned int version:4 GNUNET_PACKED; unsigned int traffic_class:8 GNUNET_PACKED; unsigned int flow_label:20 GNUNET_PACKED; #else #error byteorder undefined #endif /** * Length of the payload, excluding this header. */ uint16_t payload_length GNUNET_PACKED; /** * For example, IPPROTO_UDP or IPPROTO_TCP. */ uint8_t next_header; /** * How many more hops can this packet be forwarded? */ uint8_t hop_limit; /** * Origin of the packet. */ struct in6_addr source_address GNUNET_PACKED; /** * Destination of the packet. */ struct in6_addr destination_address GNUNET_PACKED; } GNUNET_GCC_STRUCT_LAYOUT; /** * TCP packet header. */ struct GNUNET_TUN_TcpHeader { uint16_t source_port GNUNET_PACKED; uint16_t destination_port GNUNET_PACKED; /** * Sequence number. */ uint32_t seq GNUNET_PACKED; /** * Acknowledgement number. */ uint32_t ack GNUNET_PACKED; #if __BYTE_ORDER == __LITTLE_ENDIAN /** * Reserved. Must be zero. */ unsigned int reserved : 4 GNUNET_PACKED; /** * Number of 32-bit words in TCP header. */ unsigned int off : 4 GNUNET_PACKED; #elif __BYTE_ORDER == __BIG_ENDIAN /** * Number of 32-bit words in TCP header. */ unsigned int off : 4 GNUNET_PACKED; /** * Reserved. Must be zero. */ unsigned int reserved : 4 GNUNET_PACKED; #else #error byteorder undefined #endif /** * Flags (SYN, FIN, ACK, etc.) */ uint8_t flags; /** * Window size. */ uint16_t window_size GNUNET_PACKED; /** * Checksum. */ uint16_t crc GNUNET_PACKED; /** * Urgent pointer. */ uint16_t urgent_pointer GNUNET_PACKED; } GNUNET_GCC_STRUCT_LAYOUT; /** * UDP packet header. */ struct GNUNET_TUN_UdpHeader { uint16_t source_port GNUNET_PACKED; uint16_t destination_port GNUNET_PACKED; uint16_t len GNUNET_PACKED; uint16_t crc GNUNET_PACKED; }; /** * DNS header. */ struct GNUNET_TUN_DnsHeader { uint16_t id GNUNET_PACKED; uint16_t flags GNUNET_PACKED; uint16_t qdcount GNUNET_PACKED; uint16_t ancount GNUNET_PACKED; uint16_t nscount GNUNET_PACKED; uint16_t arcount GNUNET_PACKED; }; #define GNUNET_TUN_ICMPTYPE_ECHO_REPLY 0 #define GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE 3 #define GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH 4 #define GNUNET_TUN_ICMPTYPE_REDIRECT_MESSAGE 5 #define GNUNET_TUN_ICMPTYPE_ECHO_REQUEST 8 #define GNUNET_TUN_ICMPTYPE_ROUTER_ADVERTISEMENT 9 #define GNUNET_TUN_ICMPTYPE_ROUTER_SOLICITATION 10 #define GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED 11 #define GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE 1 #define GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG 2 #define GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED 3 #define GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM 4 #define GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST 128 #define GNUNET_TUN_ICMPTYPE6_ECHO_REPLY 129 /** * ICMP header. */ struct GNUNET_TUN_IcmpHeader { uint8_t type; uint8_t code; uint16_t crc GNUNET_PACKED; union { /** * ICMP Echo (request/reply) */ struct { uint16_t identifier GNUNET_PACKED; uint16_t sequence_number GNUNET_PACKED; } echo; /** * ICMP Destination Unreachable (RFC 1191) */ struct ih_pmtu { uint16_t empty GNUNET_PACKED; uint16_t next_hop_mtu GNUNET_PACKED; /* followed by original IP header + first 8 bytes of original IP datagram */ } destination_unreachable; /** * ICMP Redirect */ struct in_addr redirect_gateway_address GNUNET_PACKED; /** * MTU for packets that are too big (IPv6). */ uint32_t packet_too_big_mtu GNUNET_PACKED; } quench; }; GNUNET_NETWORK_STRUCT_END /** * Initialize an IPv4 header. * * @param ip header to initialize * @param protocol protocol to use (i.e. IPPROTO_UDP) * @param payload_length number of bytes of payload that follow (excluding IPv4 header) * @param src source IP address to use * @param dst destination IP address to use */ void GNUNET_TUN_initialize_ipv4_header (struct GNUNET_TUN_IPv4Header *ip, uint8_t protocol, uint16_t payload_length, const struct in_addr *src, const struct in_addr *dst); /** * Initialize an IPv6 header. * * @param ip header to initialize * @param protocol protocol to use (i.e. IPPROTO_UDP) * @param payload_length number of bytes of payload that follow (excluding IPv4 header) * @param src source IP address to use * @param dst destination IP address to use */ void GNUNET_TUN_initialize_ipv6_header (struct GNUNET_TUN_IPv6Header *ip, uint8_t protocol, uint16_t payload_length, const struct in6_addr *src, const struct in6_addr *dst); /** * Calculate IPv4 TCP checksum. * * @param ip ipv4 header fully initialized * @param tcp TCP header (initialized except for CRC) * @param payload the TCP payload * @param payload_length number of bytes of TCP payload */ void GNUNET_TUN_calculate_tcp4_checksum (const struct GNUNET_TUN_IPv4Header *ip, struct GNUNET_TUN_TcpHeader *tcp, const void *payload, uint16_t payload_length); /** * Calculate IPv6 TCP checksum. * * @param ip ipv6 header fully initialized * @param tcp TCP header (initialized except for CRC) * @param payload the TCP payload * @param payload_length number of bytes of TCP payload */ void GNUNET_TUN_calculate_tcp6_checksum (const struct GNUNET_TUN_IPv6Header *ip, struct GNUNET_TUN_TcpHeader *tcp, const void *payload, uint16_t payload_length); /** * Calculate IPv4 UDP checksum. * * @param ip ipv4 header fully initialized * @param udp UDP header (initialized except for CRC) * @param payload the UDP payload * @param payload_length number of bytes of UDP payload */ void GNUNET_TUN_calculate_udp4_checksum (const struct GNUNET_TUN_IPv4Header *ip, struct GNUNET_TUN_UdpHeader *udp, const void *payload, uint16_t payload_length); /** * Calculate IPv6 UDP checksum. * * @param ip ipv6 header fully initialized * @param udp UDP header (initialized except for CRC) * @param payload the UDP payload * @param payload_length number of bytes of UDP payload */ void GNUNET_TUN_calculate_udp6_checksum (const struct GNUNET_TUN_IPv6Header *ip, struct GNUNET_TUN_UdpHeader *udp, const void *payload, uint16_t payload_length); /** * Calculate ICMP checksum. * * @param icmp IMCP header (initialized except for CRC) * @param payload the ICMP payload * @param payload_length number of bytes of ICMP payload */ void GNUNET_TUN_calculate_icmp_checksum (struct GNUNET_TUN_IcmpHeader *icmp, const void *payload, uint16_t payload_length); #endif gnunet-0.9.3/src/include/gnunet_os_lib.h0000644000175000017500000003104311760502552015162 00000000000000/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006, 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_os_lib.h * @brief low level process routines * @author Christian Grothoff * @author Krista Bennett * @author Gerd Knorr * @author Ioana Patrascu * @author Tzvetan Horozov * @author Milan * * This code manages child processes. We can communicate with child * processes using signals. Because signals are not supported on W32 * and Java (at least not nicely), we can alternatively use a pipe * to send signals to the child processes (if the child process is * a full-blown GNUnet process that supports reading signals from * a pipe, of course). Naturally, this also only works for 'normal' * termination via signals, and not as a replacement for SIGKILL. * Thus using pipes to communicate signals should only be enabled if * the child is a Java process OR if we are on Windoze. */ #ifndef GNUNET_OS_LIB_H #define GNUNET_OS_LIB_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif #include "gnunet_common.h" #include "gnunet_configuration_lib.h" #include "gnunet_scheduler_lib.h" /** * Process information (OS-dependent) */ struct GNUNET_OS_Process; /** * Possible installation paths to request */ enum GNUNET_OS_InstallationPathKind { /** * Return the "PREFIX" directory given to configure. */ GNUNET_OS_IPK_PREFIX, /** * Return the directory where the program binaries are installed. (bin/) */ GNUNET_OS_IPK_BINDIR, /** * Return the directory where libraries are installed. (lib/gnunet/) */ GNUNET_OS_IPK_LIBDIR, /** * Return the directory where data is installed (share/gnunet/) */ GNUNET_OS_IPK_DATADIR, /** * Return the directory where translations are installed (share/locale/) */ GNUNET_OS_IPK_LOCALEDIR, /** * Return the installation directory of this application, not * the one of the overall GNUnet installation (in case they * are different). */ GNUNET_OS_IPK_SELF_PREFIX, /** * Return the prefix of the path with application icons (share/icons/). */ GNUNET_OS_IPK_ICONDIR, /** * Return the prefix of the path with documentation files, including the * license (share/doc/gnunet/). */ GNUNET_OS_IPK_DOCDIR }; /** * Process status types */ enum GNUNET_OS_ProcessStatusType { /** * The process is not known to the OS (or at * least not one of our children). */ GNUNET_OS_PROCESS_UNKNOWN, /** * The process is still running. */ GNUNET_OS_PROCESS_RUNNING, /** * The process is paused (but could be resumed). */ GNUNET_OS_PROCESS_STOPPED, /** * The process exited with a return code. */ GNUNET_OS_PROCESS_EXITED, /** * The process was killed by a signal. */ GNUNET_OS_PROCESS_SIGNALED }; /** * Get the path to a specific GNUnet installation directory or, with * GNUNET_OS_IPK_SELF_PREFIX, the current running apps installation * directory. * * @param dirkind what kind of directory is desired? * @return a pointer to the dir path (to be freed by the caller) */ char * GNUNET_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind); /** * Callback function invoked for each interface found. * * @param cls closure * @param name name of the interface (can be NULL for unknown) * @param isDefault is this presumably the default interface * @param addr address of this interface (can be NULL for unknown or unassigned) * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned) * @param netmask the network mask (can be NULL for unknown or unassigned)) * @param addrlen length of the address * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort */ typedef int (*GNUNET_OS_NetworkInterfaceProcessor) (void *cls, const char *name, int isDefault, const struct sockaddr * addr, const struct sockaddr * broadcast_addr, const struct sockaddr * netmask, socklen_t addrlen); /** * @brief Enumerate all network interfaces * @param proc the callback function * @param proc_cls closure for proc */ void GNUNET_OS_network_interfaces_list (GNUNET_OS_NetworkInterfaceProcessor proc, void *proc_cls); /** * @brief Get maximum string length returned by gethostname() */ #if HAVE_SYSCONF && defined(_SC_HOST_NAME_MAX) #define GNUNET_OS_get_hostname_max_length() ({ int __sc_tmp = sysconf(_SC_HOST_NAME_MAX); __sc_tmp <= 0 ? 255 : __sc_tmp; }) #elif defined(HOST_NAME_MAX) #define GNUNET_OS_get_hostname_max_length() HOST_NAME_MAX #else #define GNUNET_OS_get_hostname_max_length() 255 #endif /** * Get process structure for current process * * The pointer it returns points to static memory location and must not be * deallocated/closed * * @return pointer to the process sturcutre for this process */ struct GNUNET_OS_Process * GNUNET_OS_process_current (void); /** * Sends a signal to the process * * @param proc pointer to process structure * @param sig signal * @return 0 on success, -1 on error */ int GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig); /** * Cleans up process structure contents (OS-dependent) and deallocates it * * @param proc pointer to process structure */ void GNUNET_OS_process_destroy (struct GNUNET_OS_Process *proc); /** * Get the pid of the process in question * * @param proc the process to get the pid of * * @return the current process id */ pid_t GNUNET_OS_process_get_pid (struct GNUNET_OS_Process *proc); /** * Set process priority * * @param proc pointer to process structure * @param prio priority value * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc, enum GNUNET_SCHEDULER_Priority prio); /** * Start a process. * * @param pipe_control should a pipe be used to send signals to the child? * @param pipe_stdin pipe to use to send input to child process (or NULL) * @param pipe_stdout pipe to use to get output from child process (or NULL) * @param filename name of the binary * @param argv NULL-terminated array of arguments to the process * @return pointer to process structure of the new process, NULL on error */ struct GNUNET_OS_Process * GNUNET_OS_start_process_vap (int pipe_control, struct GNUNET_DISK_PipeHandle *pipe_stdin, struct GNUNET_DISK_PipeHandle *pipe_stdout, const char *filename, char *const argv[]); /** * Start a process. * * @param pipe_control should a pipe be used to send signals to the child? * @param pipe_stdin pipe to use to send input to child process (or NULL) * @param pipe_stdout pipe to use to get output from child process (or NULL) * @param filename name of the binary * @param ... NULL-terminated list of arguments to the process * @return pointer to process structure of the new process, NULL on error */ struct GNUNET_OS_Process * GNUNET_OS_start_process (int pipe_control, struct GNUNET_DISK_PipeHandle *pipe_stdin, struct GNUNET_DISK_PipeHandle *pipe_stdout, const char *filename, ...); /** * Start a process. * * @param pipe_control should a pipe be used to send signals to the child? * @param pipe_stdin pipe to use to send input to child process (or NULL) * @param pipe_stdout pipe to use to get output from child process (or NULL) * @param filename name of the binary * @param va NULL-terminated list of arguments to the process * @return pointer to process structure of the new process, NULL on error */ struct GNUNET_OS_Process * GNUNET_OS_start_process_va (int pipe_control, struct GNUNET_DISK_PipeHandle *pipe_stdin, struct GNUNET_DISK_PipeHandle *pipe_stdout, const char *filename, va_list va); /** * Start a process. * * @param pipe_control should a pipe be used to send signals to the child? * @param lsocks array of listen sockets to dup systemd-style (or NULL); * must be NULL on platforms where dup is not supported * @param filename name of the binary * @param argv NULL-terminated list of arguments to the process, * including the process name as the first argument * @return pointer to process structure of the new process, NULL on error */ struct GNUNET_OS_Process * GNUNET_OS_start_process_v (int pipe_control, const SOCKTYPE *lsocks, const char *filename, char *const argv[]); /** * Handle to a command action. */ struct GNUNET_OS_CommandHandle; /** * Type of a function to process a line of output. * * @param cls closure * @param line line of output from a command, NULL for the end */ typedef void (*GNUNET_OS_LineProcessor) (void *cls, const char *line); /** * Stop/kill a command. * * @param cmd handle to the process */ void GNUNET_OS_command_stop (struct GNUNET_OS_CommandHandle *cmd); /** * Run the given command line and call the given function * for each line of the output. * * @param proc function to call for each line of the output * @param proc_cls closure for proc * @param timeout when to time out * @param binary command to run * @param ... arguments to command * @return NULL on error */ struct GNUNET_OS_CommandHandle * GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls, struct GNUNET_TIME_Relative timeout, const char *binary, ...); /** * Retrieve the status of a process, waiting on him if dead. * Nonblocking version. * * @param proc pointer to process structure * @param type status type * @param code return code/signal number * @return GNUNET_OK on success, GNUNET_NO if the process is still running, GNUNET_SYSERR otherwise */ int GNUNET_OS_process_status (struct GNUNET_OS_Process *proc, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code); /** * Wait for a process to terminate. The return code is discarded. * You must not use 'GNUNET_OS_process_status' on the same process * after calling this function! This function is blocking and should * thus only be used if the child process is known to have terminated * or to terminate very soon. * * @param proc pointer to process structure of the process to wait for * @return GNUNET_OK on success, GNUNET_SYSERR otherwise */ int GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc); /** * Connects this process to its parent via pipe; * essentially, the parent control handler will read signal numbers * from the 'GNUNET_OS_CONTROL_PIPE' (as given in an environment * variable) and raise those signals. * * @param cls closure (unused) * @param tc scheduler context (unused) */ void GNUNET_OS_install_parent_control_handler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Check whether an executable exists and possibly * if the suid bit is set on the file. * Attempts to find the file using the current * PATH environment variable as a search path. * * @param binary the name of the file to check * @return GNUNET_YES if the file is SUID, * GNUNET_NO if not SUID (but binary exists) * GNUNET_SYSERR on error (no such binary or not executable) */ int GNUNET_OS_check_helper_binary (const char *binary); #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_OS_LIB_H */ #endif /* end of gnunet_os_lib.h */ gnunet-0.9.3/src/include/block_fs.h0000644000175000017500000000747711760502552014133 00000000000000/* This file is part of GNUnet. (C) 2010 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/block_fs.h * @brief fs block formats (shared between fs and block) * @author Christian Grothoff */ #ifndef BLOCK_FS_H #define BLOCK_FS_H #include "gnunet_util_lib.h" /** * @brief keyword block (advertising data under a keyword) */ struct KBlock { /** * GNUNET_RSA_Signature using RSA-key generated from search keyword. */ struct GNUNET_CRYPTO_RsaSignature signature; /** * What is being signed and why? */ struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; /** * Key generated (!) from the H(keyword) as the seed! */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded keyspace; /* 0-terminated URI here */ /* variable-size Meta-Data follows here */ }; /** * @brief namespace content block (advertising data under an identifier in a namespace) */ struct SBlock { /** * GNUNET_RSA_Signature using RSA-key of the namespace */ struct GNUNET_CRYPTO_RsaSignature signature; /** * What is being signed and why? */ struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; /** * Hash of the hash of the human-readable identifier used for * this entry (the hash of the human-readable identifier is * used as the key for decryption; the xor of this identifier * and the hash of the "keyspace" is the datastore-query hash). */ GNUNET_HashCode identifier; /** * Public key of the namespace. */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded subspace; /* 0-terminated update-identifier here */ /* 0-terminated URI here (except for NBlocks) */ /* variable-size Meta-Data follows here */ }; /** * @brief namespace advertisement block (advertising root of a namespace) */ struct NBlock { /** * GNUNET_RSA_Signature using RSA-key generated from search keyword. */ struct GNUNET_CRYPTO_RsaSignature ksk_signature; /** * What is being signed and why? */ struct GNUNET_CRYPTO_RsaSignaturePurpose ksk_purpose; /** * Key generated (!) from the H(keyword) as the seed! */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded keyspace; /** * GNUNET_RSA_Signature using RSA-key of the namespace */ struct GNUNET_CRYPTO_RsaSignature ns_signature; /** * What is being signed and why? */ struct GNUNET_CRYPTO_RsaSignaturePurpose ns_purpose; /** * Public key of the namespace. */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded subspace; /* from here on, data is encrypted with H(keyword) */ /* 0-terminated root identifier here */ /* variable-size Meta-Data follows here */ }; GNUNET_NETWORK_STRUCT_BEGIN /** * @brief index block (indexing a DBlock that * can be obtained directly from reading * the plaintext file) */ struct OnDemandBlock { /** * Hash code of the entire content of the * file that was indexed (used to uniquely * identify the plaintext file). */ GNUNET_HashCode file_id; /** * At which offset should we be able to find * this on-demand encoded block? (in NBO) */ uint64_t offset GNUNET_PACKED; }; GNUNET_NETWORK_STRUCT_END #endif gnunet-0.9.3/src/include/gnunet_common.h0000644000175000017500000006206311760502552015211 00000000000000/* This file is part of GNUnet. (C) 2006, 2009 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_common.h * @brief commonly used definitions; globals in this file * are exempt from the rule that the module name ("common") * must be part of the symbol name. * * @author Christian Grothoff * @author Nils Durner */ #ifndef GNUNET_COMMON_H #define GNUNET_COMMON_H #if HAVE_SYS_SOCKET_H #include #endif #if HAVE_NETINET_IN_H #include #endif #ifdef MINGW #include "winproc.h" #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_STDARG_H #include #endif /** * Version of the API (for entire gnunetutil.so library). */ #define GNUNET_UTIL_VERSION 0x00090200 /** * Named constants for return values. The following * invariants hold: "GNUNET_NO == 0" (to allow "if (GNUNET_NO)") * "GNUNET_OK != GNUNET_SYSERR", "GNUNET_OK != GNUNET_NO", "GNUNET_NO != GNUNET_SYSERR" * and finally "GNUNET_YES != GNUNET_NO". */ #define GNUNET_OK 1 #define GNUNET_SYSERR -1 #define GNUNET_YES 1 #define GNUNET_NO 0 #define GNUNET_MIN(a,b) (((a) < (b)) ? (a) : (b)) #define GNUNET_MAX(a,b) (((a) > (b)) ? (a) : (b)) /* some systems use one underscore only, and mingw uses no underscore... */ #ifndef __BYTE_ORDER #ifdef _BYTE_ORDER #define __BYTE_ORDER _BYTE_ORDER #else #ifdef BYTE_ORDER #define __BYTE_ORDER BYTE_ORDER #endif #endif #endif #ifndef __BIG_ENDIAN #ifdef _BIG_ENDIAN #define __BIG_ENDIAN _BIG_ENDIAN #else #ifdef BIG_ENDIAN #define __BIG_ENDIAN BIG_ENDIAN #endif #endif #endif #ifndef __LITTLE_ENDIAN #ifdef _LITTLE_ENDIAN #define __LITTLE_ENDIAN _LITTLE_ENDIAN #else #ifdef LITTLE_ENDIAN #define __LITTLE_ENDIAN LITTLE_ENDIAN #endif #endif #endif /** * Endian operations */ # if __BYTE_ORDER == __LITTLE_ENDIAN # define GNUNET_htobe16(x) __bswap_16 (x) # define GNUNET_htole16(x) (x) # define GNUNET_be16toh(x) __bswap_16 (x) # define GNUNET_le16toh(x) (x) # define GNUNET_htobe32(x) __bswap_32 (x) # define GNUNET_htole32(x) (x) # define GNUNET_be32toh(x) __bswap_32 (x) # define GNUNET_le32toh(x) (x) # define GNUNET_htobe64(x) __bswap_64 (x) # define GNUNET_htole64(x) (x) # define GNUNET_be64toh(x) __bswap_64 (x) # define GNUNET_le64toh(x) (x) #endif # if __BYTE_ORDER == __BIG_ENDIAN # define GNUNET_htobe16(x) (x) # define GNUNET_htole16(x) __bswap_16 (x) # define GNUNET_be16toh(x) (x) # define GNUNET_le16toh(x) __bswap_16 (x) # define GNUNET_htobe32(x) (x) # define GNUNET_htole32(x) __bswap_32 (x) # define GNUNET_be32toh(x) (x) # define GNUNET_le32toh(x) __bswap_32 (x) # define GNUNET_htobe64(x) (x) # define GNUNET_htole64(x) __bswap_64 (x) # define GNUNET_be64toh(x) (x) # define GNUNET_le64toh(x) __bswap_64 (x) #endif /** * gcc-ism to get packed structs. */ #define GNUNET_PACKED __attribute__((packed)) /** * gcc-ism to get gcc bitfield layout when compiling with -mms-bitfields */ #if MINGW #define GNUNET_GCC_STRUCT_LAYOUT __attribute__((gcc_struct)) #else #define GNUNET_GCC_STRUCT_LAYOUT #endif /** * gcc-ism to force alignment; we use this to align char-arrays * that may then be cast to 'struct's. See also gcc * bug #33594. */ #ifdef __BIGGEST_ALIGNMENT__ #define GNUNET_ALIGN __attribute__((aligned (__BIGGEST_ALIGNMENT__))) #else #define GNUNET_ALIGN __attribute__((aligned (8))) #endif /** * gcc-ism to document unused arguments */ #define GNUNET_UNUSED __attribute__((unused)) /** * gcc-ism to document functions that don't return */ #define GNUNET_NORETURN __attribute__((noreturn)) #if __GNUC__ > 3 /** * gcc 4.x-ism to pack structures even on W32 (to be used before structs) */ #define GNUNET_NETWORK_STRUCT_BEGIN \ _Pragma("pack(push)") \ _Pragma("pack(1)") /** * gcc 4.x-ism to pack structures even on W32 (to be used after structs) */ #define GNUNET_NETWORK_STRUCT_END _Pragma("pack(pop)") #else #ifdef MINGW #error gcc 4.x or higher required on W32 systems #endif /** * Good luck, GNUNET_PACKED should suffice, but this won't work on W32 */ #define GNUNET_NETWORK_STRUCT_BEGIN /** * Good luck, GNUNET_PACKED should suffice, but this won't work on W32 */ #define GNUNET_NETWORK_STRUCT_END #endif /* ************************ super-general types *********************** */ GNUNET_NETWORK_STRUCT_BEGIN /** * Header for all communications. */ struct GNUNET_MessageHeader { /** * The length of the struct (in bytes, including the length field itself), * in big-endian format. */ uint16_t size GNUNET_PACKED; /** * The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format. */ uint16_t type GNUNET_PACKED; }; /** * @brief 512-bit hashcode */ typedef struct GNUNET_HashCode { uint32_t bits[512 / 8 / sizeof (uint32_t)]; /* = 16 */ } GNUNET_HashCode; /** * The identity of the host (basically the SHA-512 hashcode of * it's public key). */ struct GNUNET_PeerIdentity { GNUNET_HashCode hashPubKey; }; GNUNET_NETWORK_STRUCT_END /** * Function called with a filename. * * @param cls closure * @param filename complete filename (absolute path) * @return GNUNET_OK to continue to iterate, * GNUNET_SYSERR to abort iteration with error! */ typedef int (*GNUNET_FileNameCallback) (void *cls, const char *filename); /* ****************************** logging ***************************** */ /** * Types of errors. */ enum GNUNET_ErrorType { GNUNET_ERROR_TYPE_UNSPECIFIED = -1, GNUNET_ERROR_TYPE_NONE = 0, GNUNET_ERROR_TYPE_ERROR = 1, GNUNET_ERROR_TYPE_WARNING = 2, GNUNET_ERROR_TYPE_INFO = 4, GNUNET_ERROR_TYPE_DEBUG = 8, GNUNET_ERROR_TYPE_INVALID = 16, GNUNET_ERROR_TYPE_BULK = 32 }; /** * User-defined handler for log messages. * * @param cls closure * @param kind severeity * @param component what component is issuing the message? * @param date when was the message logged? * @param message what is the message */ typedef void (*GNUNET_Logger) (void *cls, enum GNUNET_ErrorType kind, const char *component, const char *date, const char *message); /** * Number of log calls to ignore. */ extern unsigned int skip_log; #if !defined(GNUNET_CULL_LOGGING) int GNUNET_get_log_call_status (int caller_level, const char *comp, const char *file, const char *function, int line); #endif /** * Main log function. * * @param kind how serious is the error? * @param message what is the message (format string) * @param ... arguments for format string */ void GNUNET_log_nocheck (enum GNUNET_ErrorType kind, const char *message, ...); /* from glib */ #if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) #define _GNUNET_BOOLEAN_EXPR(expr) \ __extension__ ({ \ int _gnunet_boolean_var_; \ if (expr) \ _gnunet_boolean_var_ = 1; \ else \ _gnunet_boolean_var_ = 0; \ _gnunet_boolean_var_; \ }) #define GN_LIKELY(expr) (__builtin_expect (_GNUNET_BOOLEAN_EXPR(expr), 1)) #define GN_UNLIKELY(expr) (__builtin_expect (_GNUNET_BOOLEAN_EXPR(expr), 0)) #else #define GN_LIKELY(expr) (expr) #define GN_UNLIKELY(expr) (expr) #endif #if !defined(GNUNET_LOG_CALL_STATUS) #define GNUNET_LOG_CALL_STATUS -1 #endif /** * Log function that specifies an alternative component. * This function should be used by plugins. * * @param kind how serious is the error? * @param comp component responsible for generating the message * @param message what is the message (format string) * @param ... arguments for format string */ void GNUNET_log_from_nocheck (enum GNUNET_ErrorType kind, const char *comp, const char *message, ...); #if !defined(GNUNET_CULL_LOGGING) #define GNUNET_log_from(kind,comp,...) do { int log_line = __LINE__;\ static int log_call_enabled = GNUNET_LOG_CALL_STATUS;\ if ((GNUNET_EXTRA_LOGGING > 0) || ((GNUNET_ERROR_TYPE_DEBUG & (kind)) == 0)) { \ if (GN_UNLIKELY(log_call_enabled == -1))\ log_call_enabled = GNUNET_get_log_call_status ((kind) & (~GNUNET_ERROR_TYPE_BULK), (comp), __FILE__, __FUNCTION__, log_line); \ if (GN_UNLIKELY(skip_log > 0)) {skip_log--;}\ else {\ if (GN_UNLIKELY(log_call_enabled))\ GNUNET_log_from_nocheck ((kind), comp, __VA_ARGS__); \ }\ }\ } while (0) #define GNUNET_log(kind,...) do { int log_line = __LINE__;\ static int log_call_enabled = GNUNET_LOG_CALL_STATUS;\ if ((GNUNET_EXTRA_LOGGING > 0) || ((GNUNET_ERROR_TYPE_DEBUG & (kind)) == 0)) { \ if (GN_UNLIKELY(log_call_enabled == -1))\ log_call_enabled = GNUNET_get_log_call_status ((kind) & (~GNUNET_ERROR_TYPE_BULK), NULL, __FILE__, __FUNCTION__, log_line);\ if (GN_UNLIKELY(skip_log > 0)) {skip_log--;}\ else {\ if (GN_UNLIKELY(log_call_enabled))\ GNUNET_log_nocheck ((kind), __VA_ARGS__); \ }\ }\ } while (0) #else #define GNUNET_log(...) #define GNUNET_log_from(...) #endif /** * Abort the process, generate a core dump if possible. */ void GNUNET_abort (void) GNUNET_NORETURN; /** * Ignore the next n calls to the log function. * * @param n number of log calls to ignore * @param check_reset GNUNET_YES to assert that the log skip counter is currently zero */ void GNUNET_log_skip (unsigned int n, int check_reset); /** * Setup logging. * * @param comp default component to use * @param loglevel what types of messages should be logged * @param logfile change logging to logfile (use NULL to keep stderr) * @return GNUNET_OK on success, GNUNET_SYSERR if logfile could not be opened */ int GNUNET_log_setup (const char *comp, const char *loglevel, const char *logfile); /** * Add a custom logger. * * @param logger log function * @param logger_cls closure for logger */ void GNUNET_logger_add (GNUNET_Logger logger, void *logger_cls); /** * Remove a custom logger. * * @param logger log function * @param logger_cls closure for logger */ void GNUNET_logger_remove (GNUNET_Logger logger, void *logger_cls); /** * Convert a hash value to a string (for printing debug messages). * This is one of the very few calls in the entire API that is * NOT reentrant! * * @param hc the hash code * @return string */ const char * GNUNET_h2s (const GNUNET_HashCode * hc); /** * Convert a hash value to a string (for printing debug messages). * This prints all 104 characters of a hashcode! * This is one of the very few calls in the entire API that is * NOT reentrant! * * @param hc the hash code * @return string */ const char * GNUNET_h2s_full (const GNUNET_HashCode * hc); /** * Convert a peer identity to a string (for printing debug messages). * This is one of the very few calls in the entire API that is * NOT reentrant! * * @param pid the peer identity * @return string form of the pid; will be overwritten by next * call to GNUNET_i2s. */ const char * GNUNET_i2s (const struct GNUNET_PeerIdentity *pid); /** * Convert a peer identity to a string (for printing debug messages). * This is one of the very few calls in the entire API that is * NOT reentrant! * * @param pid the peer identity * @return string form of the pid; will be overwritten by next * call to GNUNET_i2s. */ const char * GNUNET_i2s_full (const struct GNUNET_PeerIdentity *pid); /** * Convert a "struct sockaddr*" (IPv4 or IPv6 address) to a string * (for printing debug messages). This is one of the very few calls * in the entire API that is NOT reentrant! * * @param addr the address * @param addrlen the length of the address * @return nicely formatted string for the address * will be overwritten by next call to GNUNET_a2s. */ const char * GNUNET_a2s (const struct sockaddr *addr, socklen_t addrlen); /** * Convert error type to string. * * @param kind type to convert * @return string corresponding to the type */ const char * GNUNET_error_type_to_string (enum GNUNET_ErrorType kind); /** * Use this for fatal errors that cannot be handled */ #define GNUNET_assert(cond) do { if (! (cond)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Assertion failed at %s:%d.\n"), __FILE__, __LINE__); GNUNET_abort(); } } while(0) /** * Use this for fatal errors that cannot be handled */ #define GNUNET_assert_at(cond, f, l) do { if (! (cond)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Assertion failed at %s:%d.\n"), f, l); GNUNET_abort(); } } while(0) /** * Use this for internal assertion violations that are * not fatal (can be handled) but should not occur. */ #define GNUNET_break(cond) do { if (! (cond)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Assertion failed at %s:%d.\n"), __FILE__, __LINE__); } } while(0) /** * Use this for assertion violations caused by other * peers (i.e. protocol violations). We do not want to * confuse end-users (say, some other peer runs an * older, broken or incompatible GNUnet version), but * we still want to see these problems during * development and testing. "OP == other peer". */ #define GNUNET_break_op(cond) do { if (! (cond)) { GNUNET_log(GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, _("External protocol violation detected at %s:%d.\n"), __FILE__, __LINE__); } } while(0) /** * Log an error message at log-level 'level' that indicates * a failure of the command 'cmd' with the message given * by strerror(errno). */ #define GNUNET_log_strerror(level, cmd) do { GNUNET_log(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, STRERROR(errno)); } while(0) /** * Log an error message at log-level 'level' that indicates * a failure of the command 'cmd' with the message given * by strerror(errno). */ #define GNUNET_log_from_strerror(level, component, cmd) do { GNUNET_log_from (level, component, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, STRERROR(errno)); } while(0) /** * Log an error message at log-level 'level' that indicates * a failure of the command 'cmd' with the message given * by strerror(errno). */ #define GNUNET_log_strerror_file(level, cmd, filename) do { GNUNET_log(level, _("`%s' failed on file `%s' at %s:%d with error: %s\n"), cmd, filename,__FILE__, __LINE__, STRERROR(errno)); } while(0) /** * Log an error message at log-level 'level' that indicates * a failure of the command 'cmd' with the message given * by strerror(errno). */ #define GNUNET_log_from_strerror_file(level, component, cmd, filename) do { GNUNET_log_from (level, component, _("`%s' failed on file `%s' at %s:%d with error: %s\n"), cmd, filename,__FILE__, __LINE__, STRERROR(errno)); } while(0) /* ************************* endianess conversion ****************** */ /** * Convert unsigned 64-bit integer to host-byte-order. * @param n the value in network byte order * @return the same value in host byte order */ uint64_t GNUNET_ntohll (uint64_t n); /** * Convert unsigned 64-bit integer to network-byte-order. * @param n the value in host byte order * @return the same value in network byte order */ uint64_t GNUNET_htonll (uint64_t n); /** * Convert double to network-byte-order. * @param d the value in network byte order * @return the same value in host byte order */ double GNUNET_hton_double (double d); /** * Convert double to host-byte-order * @param d the value in network byte order * @return the same value in host byte order */ double GNUNET_ntoh_double (double d); /* ************************* allocation functions ****************** */ /** * Maximum allocation with GNUNET_malloc macro. */ #define GNUNET_MAX_MALLOC_CHECKED (1024 * 1024 * 40) /** * Wrapper around malloc. Allocates size bytes of memory. * The memory will be zero'ed out. * * @param size the number of bytes to allocate, must be * smaller than 40 MB. * @return pointer to size bytes of memory, never NULL (!) */ #define GNUNET_malloc(size) GNUNET_xmalloc_(size, __FILE__, __LINE__) /** * Allocate and initialize a block of memory. * * @param buf data to initalize the block with * @param size the number of bytes in buf (and size of the allocation) * @return pointer to size bytes of memory, never NULL (!) */ #define GNUNET_memdup(buf,size) GNUNET_xmemdup_(buf, size, __FILE__, __LINE__) /** * Wrapper around malloc. Allocates size bytes of memory. * The memory will be zero'ed out. * * @param size the number of bytes to allocate * @return pointer to size bytes of memory, NULL if we do not have enough memory */ #define GNUNET_malloc_large(size) GNUNET_xmalloc_unchecked_(size, __FILE__, __LINE__) /** * Wrapper around realloc. Rellocates size bytes of memory. * * @param ptr the pointer to reallocate * @param size the number of bytes to reallocate * @return pointer to size bytes of memory */ #define GNUNET_realloc(ptr, size) GNUNET_xrealloc_(ptr, size, __FILE__, __LINE__) /** * Wrapper around free. Frees the memory referred to by ptr. * Note that is is generally better to free memory that was * allocated with GNUNET_array_grow using GNUNET_array_grow(mem, size, 0) instead of GNUNET_free. * * @param ptr location where to free the memory. ptr must have * been returned by GNUNET_strdup, GNUNET_strndup, GNUNET_malloc or GNUNET_array_grow earlier. */ #define GNUNET_free(ptr) GNUNET_xfree_(ptr, __FILE__, __LINE__) /** * Free the memory pointed to by ptr if ptr is not NULL. * Equivalent to if (ptr!=null)GNUNET_free(ptr). * * @param ptr the location in memory to free */ #define GNUNET_free_non_null(ptr) do { void * __x__ = ptr; if (__x__ != NULL) { GNUNET_free(__x__); } } while(0) /** * Wrapper around GNUNET_strdup. Makes a copy of the zero-terminated string * pointed to by a. * * @param a pointer to a zero-terminated string * @return a copy of the string including zero-termination */ #define GNUNET_strdup(a) GNUNET_xstrdup_(a,__FILE__,__LINE__) /** * Wrapper around GNUNET_strndup. Makes a partial copy of the string * pointed to by a. * * @param a pointer to a string * @param length of the string to duplicate * @return a partial copy of the string including zero-termination */ #define GNUNET_strndup(a,length) GNUNET_xstrndup_(a,length,__FILE__,__LINE__) /** * Grow a well-typed (!) array. This is a convenience * method to grow a vector arr of size size * to the new (target) size tsize. *

    * * Example (simple, well-typed stack): * *

     * static struct foo * myVector = NULL;
     * static int myVecLen = 0;
     *
     * static void push(struct foo * elem) {
     *   GNUNET_array_grow(myVector, myVecLen, myVecLen+1);
     *   memcpy(&myVector[myVecLen-1], elem, sizeof(struct foo));
     * }
     *
     * static void pop(struct foo * elem) {
     *   if (myVecLen == 0) die();
     *   memcpy(elem, myVector[myVecLen-1], sizeof(struct foo));
     *   GNUNET_array_grow(myVector, myVecLen, myVecLen-1);
     * }
     * 
    * * @param arr base-pointer of the vector, may be NULL if size is 0; * will be updated to reflect the new address. The TYPE of * arr is important since size is the number of elements and * not the size in bytes * @param size the number of elements in the existing vector (number * of elements to copy over) * @param tsize the target size for the resulting vector, use 0 to * free the vector (then, arr will be NULL afterwards). */ #define GNUNET_array_grow(arr,size,tsize) GNUNET_xgrow_((void**)&arr, sizeof(arr[0]), &size, tsize, __FILE__, __LINE__) /** * Append an element to a list (growing the * list by one). */ #define GNUNET_array_append(arr,size,element) do { GNUNET_array_grow(arr,size,size+1); arr[size-1] = element; } while(0) /** * Like snprintf, just aborts if the buffer is of insufficient size. * * @param buf pointer to buffer that is written to * @param size number of bytes in buf * @param format format strings * @param ... data for format string * @return number of bytes written to buf or negative value on error */ int GNUNET_snprintf (char *buf, size_t size, const char *format, ...); /** * Like asprintf, just portable. * * @param buf set to a buffer of sufficient size (allocated, caller must free) * @param format format string (see printf, fprintf, etc.) * @param ... data for format string * @return number of bytes in "*buf" excluding 0-termination */ int GNUNET_asprintf (char **buf, const char *format, ...); /* ************** internal implementations, use macros above! ************** */ /** * Allocate memory. Checks the return value, aborts if no more * memory is available. Don't use GNUNET_xmalloc_ directly. Use the * GNUNET_malloc macro. * The memory will be zero'ed out. * * @param size number of bytes to allocate * @param filename where is this call being made (for debugging) * @param linenumber line where this call is being made (for debugging) * @return allocated memory, never NULL */ void * GNUNET_xmalloc_ (size_t size, const char *filename, int linenumber); /** * Allocate and initialize memory. Checks the return value, aborts if no more * memory is available. Don't use GNUNET_xmemdup_ directly. Use the * GNUNET_memdup macro. * * @param buf buffer to initialize from (must contain size bytes) * @param size number of bytes to allocate * @param filename where is this call being made (for debugging) * @param linenumber line where this call is being made (for debugging) * @return allocated memory, never NULL */ void * GNUNET_xmemdup_ (const void *buf, size_t size, const char *filename, int linenumber); /** * Allocate memory. This function does not check if the allocation * request is within reasonable bounds, allowing allocations larger * than 40 MB. If you don't expect the possibility of very large * allocations, use GNUNET_malloc instead. The memory will be zero'ed * out. * * @param size number of bytes to allocate * @param filename where is this call being made (for debugging) * @param linenumber line where this call is being made (for debugging) * @return pointer to size bytes of memory, NULL if we do not have enough memory */ void * GNUNET_xmalloc_unchecked_ (size_t size, const char *filename, int linenumber); /** * Reallocate memory. Checks the return value, aborts if no more * memory is available. */ void * GNUNET_xrealloc_ (void *ptr, size_t n, const char *filename, int linenumber); /** * Free memory. Merely a wrapper for the case that we * want to keep track of allocations. Don't use GNUNET_xfree_ * directly. Use the GNUNET_free macro. * * @param ptr pointer to memory to free * @param filename where is this call being made (for debugging) * @param linenumber line where this call is being made (for debugging) */ void GNUNET_xfree_ (void *ptr, const char *filename, int linenumber); /** * Dup a string. Don't call GNUNET_xstrdup_ directly. Use the GNUNET_strdup macro. * @param str string to duplicate * @param filename where is this call being made (for debugging) * @param linenumber line where this call is being made (for debugging) * @return the duplicated string */ char * GNUNET_xstrdup_ (const char *str, const char *filename, int linenumber); /** * Dup partially a string. Don't call GNUNET_xstrndup_ directly. Use the GNUNET_strndup macro. * * @param str string to duplicate * @param len length of the string to duplicate * @param filename where is this call being made (for debugging) * @param linenumber line where this call is being made (for debugging) * @return the duplicated string */ char * GNUNET_xstrndup_ (const char *str, size_t len, const char *filename, int linenumber); /** * Grow an array, the new elements are zeroed out. * Grows old by (*oldCount-newCount)*elementSize * bytes and sets *oldCount to newCount. * * Don't call GNUNET_xgrow_ directly. Use the GNUNET_array_grow macro. * * @param old address of the pointer to the array * *old may be NULL * @param elementSize the size of the elements of the array * @param oldCount address of the number of elements in the *old array * @param newCount number of elements in the new array, may be 0 (then *old will be NULL afterwards) * @param filename where is this call being made (for debugging) * @param linenumber line where this call is being made (for debugging) */ void GNUNET_xgrow_ (void **old, size_t elementSize, unsigned int *oldCount, unsigned int newCount, const char *filename, int linenumber); /** * Create a copy of the given message. * * @param msg message to copy * @return duplicate of the message */ struct GNUNET_MessageHeader * GNUNET_copy_message (const struct GNUNET_MessageHeader *msg); #if __STDC_VERSION__ < 199901L #if __GNUC__ >= 2 #define __func__ __FUNCTION__ #else #define __func__ "" #endif #endif #endif /*GNUNET_COMMON_H_ */ gnunet-0.9.3/src/include/gnunet_applications.h0000644000175000017500000000341711760502552016405 00000000000000/* This file is part of GNUnet. (C) 2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file include/gnunet_applications.h * @brief constants for network applications operating on top of the MESH service * @author Christian Grothoff */ #ifndef GNUNET_APPLICATIONS_H #define GNUNET_APPLICATIONS_H #ifdef __cplusplus extern "C" { #if 0 /* keep Emacsens' auto-indent happy */ } #endif #endif /** * End of list marker. */ #define GNUNET_APPLICATION_TYPE_END 0 /** * Test. */ #define GNUNET_APPLICATION_TYPE_TEST 1 /** * Internet DNS resolution (external DNS gateway). */ #define GNUNET_APPLICATION_TYPE_INTERNET_RESOLVER 2 /** * Internet IPv4 gateway (any TCP/UDP/ICMP). */ #define GNUNET_APPLICATION_TYPE_IPV4_GATEWAY 16 /** * Internet IPv6 gateway (any TCP/UDP/ICMP). */ #define GNUNET_APPLICATION_TYPE_IPV6_GATEWAY 17 #if 0 /* keep Emacsens' auto-indent happy */ { #endif #ifdef __cplusplus } #endif /* ifndef GNUNET_APPLICATIONS_H */ #endif /* end of gnunet_applications.h */ gnunet-0.9.3/src/peerinfo-tool/0000755000175000017500000000000011763406750013406 500000000000000gnunet-0.9.3/src/peerinfo-tool/test_gnunet_peerinfo_data.conf0000644000175000017500000000044411634323401021402 00000000000000[PATHS] SERVICEHOME = /tmp/gnunet-test-peerinfo/ [peerinfo] PORT = 24354 [resolver] PORT = 24355 [arm] DEFAULTSERVICES = [testing] WEAKRANDOM = YES [transport] plugins = tcp PORT = 24356 [transport-tcp] PORT = 24357 [dns] AUTOSTART = NO [mesh] AUTOSTART = NO [nse] AUTOSTART = NO gnunet-0.9.3/src/peerinfo-tool/Makefile.am0000644000175000017500000000214111727710217015354 00000000000000INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -lole32 -lshell32 -liconv -lstdc++ -lcomdlg32 -lgdi32 endif if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIB = -lgcov endif bin_PROGRAMS = \ gnunet-peerinfo gnunet_peerinfo_SOURCES = \ gnunet-peerinfo.c \ gnunet-peerinfo_plugins.c gnunet-peerinfo_plugins.h gnunet_peerinfo_LDADD = \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la if HAVE_PYTHON_PEXPECT check_SCRIPTS = \ test_gnunet_peerinfo.py endif if ENABLE_TEST_RUN TESTS = $(check_SCRIPTS) endif do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' test_gnunet_peerinfo.py: test_gnunet_peerinfo.py.in Makefile $(do_subst) < $(srcdir)/test_gnunet_peerinfo.py.in > test_gnunet_peerinfo.py chmod +x test_gnunet_peerinfo.py EXTRA_DIST = \ test_gnunet_peerinfo.py.in \ test_gnunet_peerinfo_data.conf CLEANFILES = $(check_SCRIPTS) gnunet-0.9.3/src/peerinfo-tool/test_gnunet_peerinfo.py.in0000644000175000017500000000755611760502552020542 00000000000000#!@PYTHON@ # This file is part of GNUnet. # (C) 2010 Christian Grothoff (and other contributing authors) # # GNUnet is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2, or (at your # option) any later version. # # GNUnet is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNUnet; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # Testcase for gnunet-peerinfo import sys import os import subprocess import re import shutil import time srcdir = "../.." gnunet_pyexpect_dir = os.path.join (srcdir, "contrib") if gnunet_pyexpect_dir not in sys.path: sys.path.append (gnunet_pyexpect_dir) from gnunet_pyexpect import pexpect if os.name == 'posix': peerinfo = 'gnunet-peerinfo' gnunetarm = 'gnunet-arm' elif os.name == 'nt': peerinfo = 'gnunet-peerinfo.exe' gnunetarm = 'gnunet-arm.exe' pinfo = pexpect () pinfo.spawn (None, [peerinfo, '-i', '-c', 'test_gnunet_peerinfo_data.conf', '-L', 'ERROR'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pinfo.expect ("stdout", re.compile (r'Error in communication with PEERINFO service: Timeout transmitting iteration request to `PEERINFO\' service.\r?\n')) pinfo.expect ("stdout", "EOF") if os.name == "nt": shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-peerinfo"), True) else: shutil.rmtree ("/tmp/gnunet-test-peerinfo", True) arm = subprocess.Popen ([gnunetarm, '-sq', '-c', 'test_gnunet_peerinfo_data.conf']) arm.communicate () try: pinfo.spawn (None, [peerinfo, '-c', 'test_gnunet_peerinfo_data.conf', '-s'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pinfo.expect ("stdout", re.compile (r'I am peer `.*\'.\r?\n')) pinfo.spawn (None, [peerinfo, '-c', 'test_gnunet_peerinfo_data.conf', '-qs'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pinfo.expect ("stdout", re.compile (r'.......................................................................................................\r?\n')) pinfo.spawn (None, [peerinfo, '-c', 'test_gnunet_peerinfo_data.conf', 'invalid'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pinfo.expect ("stdout", re.compile (r'Invalid command line argument `invalid\'\r?\n')) arm = subprocess.Popen ([gnunetarm, '-q', '-i', 'transport', '-c', 'test_gnunet_peerinfo_data.conf']) arm.communicate () time.sleep (1) pinfo.spawn (None, [peerinfo, '-i', '-c', 'test_gnunet_peerinfo_data.conf'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pinfo.expect ("stdout", re.compile ("Peer `.*'\r?\n")) m = pinfo.expect ("stdout", re.compile ("\s.*:24357\r?\n")) while len (m.group (0)) > 0: m = pinfo.expect ("stdout", re.compile ("(\s.*:24357\r?\n|\r?\n|)")) pinfo.spawn (None, [peerinfo, '-i', '-c', 'test_gnunet_peerinfo_data.conf', '-n'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pinfo.expect ("stdout", re.compile ("Peer `.*'\r?\n")) m = pinfo.expect ("stdout", re.compile ("\s.*:24357\r?\n")) while len (m.group (0)) > 0: m = pinfo.expect ("stdout", re.compile ("(\s.*:24357\r?\n|\r?\n|)")) pinfo.spawn (None, [peerinfo, '-c', 'test_gnunet_peerinfo_data.conf', '-qs'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pid = pinfo.read ("stdout") pid.strip () finally: arm = subprocess.Popen ([gnunetarm, '-eq', '-c', 'test_gnunet_peerinfo_data.conf']) arm.communicate () if os.name == "nt": shutil.rmtree (os.path.join (os.getenv ("TEMP"), "gnunet-test-peerinfo"), True) else: shutil.rmtree ("/tmp/gnunet-test-peerinfo", True) gnunet-0.9.3/src/peerinfo-tool/gnunet-peerinfo_plugins.h0000644000175000017500000000302411760502552020336 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file peerinfo-tool/gnunet-peerinfo_plugins.h * @brief plugin management API * @author Christian Grothoff */ #ifndef GNUNET_PEERINFO_PLUGINS_H #define GNUNET_PEERINFO_PLUGINS_H #include "gnunet_util_lib.h" /** * Load transport plugins. * * @param cfg configuration to use */ void GPI_plugins_load (const struct GNUNET_CONFIGURATION_Handle *cfg); /** * Unload all plugins */ void GPI_plugins_unload (void); /** * Obtain the plugin API based on a plugin name. * * @param name name of the plugin * @return the plugin's API, NULL if the plugin is not loaded */ struct GNUNET_TRANSPORT_PluginFunctions * GPI_plugins_find (const char *name); #endif /* end of file gnunet-peerinfo_plugins.h */ gnunet-0.9.3/src/peerinfo-tool/gnunet-peerinfo.c0000644000175000017500000005567111760502551016606 00000000000000/* This file is part of GNUnet. (C) 2001-2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file peerinfo-tool/gnunet-peerinfo.c * @brief Print information about other known peers. * @author Christian Grothoff */ #include "platform.h" #include "gnunet_crypto_lib.h" #include "gnunet_configuration_lib.h" #include "gnunet_getopt_lib.h" #include "gnunet_peerinfo_service.h" #include "gnunet_transport_service.h" #include "gnunet_program_lib.h" #include "gnunet_transport_plugin.h" #include "gnunet-peerinfo_plugins.h" /** * Prefix that every HELLO URI must start with. */ #define HELLO_URI_PREFIX "gnunet://hello/" /** * How long until we time out during peerinfo iterations? */ #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) /** * Structure we use to collect printable address information. */ struct PrintContext; /** * Record we keep for each printable address. */ struct AddressRecord { /** * Current address-to-string context (if active, otherwise NULL). */ struct GNUNET_TRANSPORT_AddressToStringContext *atsc; /** * Printable address. */ char *result; /** * Print context this address record belongs to. */ struct PrintContext *pc; }; /** * Structure we use to collect printable address information. */ struct PrintContext { /** * Kept in DLL. */ struct PrintContext *next; /** * Kept in DLL. */ struct PrintContext *prev; /** * Identity of the peer. */ struct GNUNET_PeerIdentity peer; /** * List of printable addresses. */ struct AddressRecord *address_list; /** * Number of completed addresses in 'address_list'. */ unsigned int num_addresses; /** * Number of addresses allocated in 'address_list'. */ unsigned int address_list_size; /** * Current offset in 'address_list' (counted down). */ unsigned int off; }; /** * Context used for building our own URI. */ struct GetUriContext { /** * Final URI. */ char *uri; }; /** * Context for 'add_address_to_hello'. */ struct GNUNET_PEERINFO_HelloAddressParsingContext { /** * Position in the URI with the next address to parse. */ const char *pos; /** * Set to GNUNET_SYSERR to indicate parse errors. */ int ret; }; /** * Option '-n' */ static int no_resolve; /** * Option '-q' */ static int be_quiet; /** * Option '-s' */ static int get_self; /** * Option */ static int get_uri; /** * Option '-i' */ static int get_info; /** * Option */ static char *put_uri; /** * Handle to peerinfo service. */ static struct GNUNET_PEERINFO_Handle *peerinfo; /** * Configuration handle. */ static const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Main state machine task (if active). */ static GNUNET_SCHEDULER_TaskIdentifier tt; /** * Current iterator context (if active, otherwise NULL). */ static struct GNUNET_PEERINFO_IteratorContext *pic; /** * My peer identity. */ static struct GNUNET_PeerIdentity my_peer_identity; /** * My public key. */ static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; /** * Head of list of print contexts. */ static struct PrintContext *pc_head; /** * Tail of list of print contexts. */ static struct PrintContext *pc_tail; /** * Handle to current 'GNUNET_PEERINFO_add_peer' operation. */ static struct GNUNET_PEERINFO_AddContext *ac; /** * Main state machine that goes over all options and * runs the next requested function. * * @param cls unused * @param tc unused */ static void state_machine (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); /** * Replace all characters in the input 'in' according * to the mapping. The mapping says to map each character * in 'oldchars' to the corresponding character (by offset) * in 'newchars'. * * @param in input string to remap * @param oldchars characters to replace * @param newchars replacement characters, must have same length as 'oldchars' * @return copy of string with replacement applied. */ static char * map_characters (const char *in, const char *oldchars, const char *newchars) { char *ret; const char *off; size_t i; GNUNET_assert (strlen (oldchars) == strlen (newchars)); ret = GNUNET_strdup (in); i = 0; while (ret[i] != '\0') { off = strchr (oldchars, ret[i]); if (NULL != off) ret[i] = newchars[off - oldchars]; i++; } return ret; } /* ********************* 'get_info' ******************* */ /** * Print the collected address information to the console and free 'pc'. * * @param pc printing context */ static void dump_pc (struct PrintContext *pc) { struct GNUNET_CRYPTO_HashAsciiEncoded enc; unsigned int i; GNUNET_CRYPTO_hash_to_enc (&pc->peer.hashPubKey, &enc); printf (_("Peer `%s'\n"), (const char *) &enc); for (i = 0; i < pc->num_addresses; i++) { if (NULL != pc->address_list[i].result) { printf ("\t%s\n", pc->address_list[i].result); GNUNET_free (pc->address_list[i].result); } } printf ("\n"); GNUNET_free_non_null (pc->address_list); GNUNET_CONTAINER_DLL_remove (pc_head, pc_tail, pc); GNUNET_free (pc); if ( (NULL == pc_head) && (NULL == pic) ) tt = GNUNET_SCHEDULER_add_now (&state_machine, NULL); } /* ************************* list all known addresses **************** */ /** * Function to call with a human-readable format of an address * * @param cls closure * @param address NULL on error, otherwise 0-terminated printable UTF-8 string */ static void process_resolved_address (void *cls, const char *address) { struct AddressRecord * ar = cls; struct PrintContext *pc = ar->pc; if (NULL != address) { if (NULL == ar->result) ar->result = GNUNET_strdup (address); return; } ar->atsc = NULL; pc->num_addresses++; if (pc->num_addresses == pc->address_list_size) dump_pc (pc); } /** * Iterator callback to go over all addresses and count them. * * @param cls 'struct PrintContext' with 'off' to increment * @param address the address * @param expiration expiration time * @return GNUNET_OK to keep the address and continue */ static int count_address (void *cls, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration) { struct PrintContext *pc = cls; pc->off++; return GNUNET_OK; } /** * Iterator callback to go over all addresses. * * @param cls closure * @param address the address * @param expiration expiration time * @return GNUNET_OK to keep the address and continue */ static int print_address (void *cls, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration) { struct PrintContext *pc = cls; struct AddressRecord *ar; GNUNET_assert (0 < pc->off); ar = &pc->address_list[--pc->off]; ar->pc = pc; ar->atsc = GNUNET_TRANSPORT_address_to_string (cfg, address, no_resolve, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10), &process_resolved_address, ar); return GNUNET_OK; } /** * Print information about the peer. * Currently prints the GNUNET_PeerIdentity and the transport address. * * @param cls the 'struct PrintContext' * @param peer identity of the peer * @param hello addresses of the peer * @param err_msg error message */ static void print_peer_info (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Message *hello, const char *err_msg) { struct GNUNET_CRYPTO_HashAsciiEncoded enc; struct PrintContext *pc; if (peer == NULL) { pic = NULL; /* end of iteration */ if (err_msg != NULL) { FPRINTF (stderr, _("Error in communication with PEERINFO service: %s\n"), err_msg); } if (NULL == pc_head) tt = GNUNET_SCHEDULER_add_now (&state_machine, NULL); return; } if ((GNUNET_YES == be_quiet) || (NULL == hello)) { GNUNET_CRYPTO_hash_to_enc (&peer->hashPubKey, &enc); printf ("%s\n", (const char *) &enc); return; } pc = GNUNET_malloc (sizeof (struct PrintContext)); GNUNET_CONTAINER_DLL_insert (pc_head, pc_tail, pc); pc->peer = *peer; GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &count_address, pc); if (0 == pc->off) { dump_pc (pc); return; } pc->address_list_size = pc->off; pc->address_list = GNUNET_malloc (sizeof (struct AddressRecord) * pc->off); GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &print_address, pc); } /* ************************* GET URI ************************** */ /** * Function that is called on each address of this peer. * Expands the corresponding URI string. * * @param cls the 'GetUriContext' * @param address address to add * @param expiration expiration time for the address * @return GNUNET_OK (continue iteration). */ static int compose_uri (void *cls, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration) { struct GetUriContext *guc = cls; struct GNUNET_TRANSPORT_PluginFunctions *papi; const char *addr; char *uri_addr; char *ret; char tbuf[16]; struct tm *t; time_t seconds; papi = GPI_plugins_find (address->transport_name); if (papi == NULL) { /* Not an error - we might just not have the right plugin. */ return GNUNET_OK; } if (NULL == papi->address_to_string) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "URI conversion not implemented for plugin `%s'\n", address->transport_name); return GNUNET_OK; } addr = papi->address_to_string (papi->cls, address->address, address->address_length); if ( (addr == NULL) || (strlen(addr) == 0) ) return GNUNET_OK; /* For URIs we use '(' and ')' instead of '[' and ']' as brackets are reserved characters in URIs */ uri_addr = map_characters (addr, "[]", "()"); seconds = expiration.abs_value / 1000; t = gmtime (&seconds); GNUNET_assert (0 != strftime (tbuf, sizeof (tbuf), "%Y%m%d%H%M%S", t)); GNUNET_asprintf (&ret, "%s!%s!%s!%s", guc->uri, tbuf, address->transport_name, uri_addr); GNUNET_free (uri_addr); GNUNET_free (guc->uri); guc->uri = ret; return GNUNET_OK; } /** * Print URI of the peer. * * @param cls the 'struct GetUriContext' * @param peer identity of the peer (unused) * @param hello addresses of the peer * @param err_msg error message */ static void print_my_uri (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Message *hello, const char *err_msg) { struct GetUriContext *guc = cls; if (peer == NULL) { pic = NULL; if (err_msg != NULL) FPRINTF (stderr, _("Error in communication with PEERINFO service: %s\n"), err_msg); GNUNET_free_non_null (guc->uri); GNUNET_free (guc); tt = GNUNET_SCHEDULER_add_now (&state_machine, NULL); return; } if (NULL != hello) GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &compose_uri, guc); printf ("%s\n", (const char *) guc->uri); } /* ************************* import HELLO by URI ********************* */ /** * We're building a HELLO. Parse the next address from the * parsing context and append it. * * @param cls the 'struct GNUNET_PEERINFO_HelloAddressParsingContext' * @param max number of bytes available for HELLO construction * @param buffer where to copy the next address (in binary format) * @return number of bytes added to buffer */ static size_t add_address_to_hello (void *cls, size_t max, void *buffer) { struct GNUNET_PEERINFO_HelloAddressParsingContext *ctx = cls; const char *tname; const char *address; char *uri_address; char *plugin_address; const char *end; char *plugin_name; struct tm expiration_time; time_t expiration_seconds; struct GNUNET_TIME_Absolute expire; struct GNUNET_TRANSPORT_PluginFunctions *papi; void *addr; size_t addr_len; struct GNUNET_HELLO_Address haddr; size_t ret; if (NULL == ctx->pos) return 0; if ('!' != ctx->pos[0]) { ctx->ret = GNUNET_SYSERR; GNUNET_break (0); return 0; } ctx->pos++; memset (&expiration_time, 0, sizeof (expiration_time)); tname = strptime (ctx->pos, "%Y%m%d%H%M%S", &expiration_time); if (NULL == tname) { ctx->ret = GNUNET_SYSERR; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to parse HELLO message: missing expiration time\n")); GNUNET_break (0); return 0; } expiration_seconds = mktime (&expiration_time); if (expiration_seconds == (time_t) -1) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to parse HELLO message: invalid expiration time\n")); ctx->ret = GNUNET_SYSERR; GNUNET_break (0); return 0; } expire.abs_value = expiration_seconds * 1000; if ('!' != tname[0]) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to parse HELLO message: malformed\n")); ctx->ret = GNUNET_SYSERR; GNUNET_break (0); return 0; } tname++; address = strchr (tname, (int) '!'); if (NULL == address) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to parse HELLO message: missing transport plugin\n")); ctx->ret = GNUNET_SYSERR; GNUNET_break (0); return 0; } address++; end = strchr (address, (int) '!'); ctx->pos = end; plugin_name = GNUNET_strndup (tname, address - (tname+1)); papi = GPI_plugins_find (plugin_name); if (NULL == papi) { /* Not an error - we might just not have the right plugin. * Skip this part, advance to the next one and recurse. * But only if this is not the end of string. */ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Plugin `%s' not found\n"), plugin_name); GNUNET_free (plugin_name); GNUNET_break (0); return 0; } if (NULL == papi->string_to_address) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Plugin `%s' does not support URIs yet\n"), plugin_name); GNUNET_free (plugin_name); GNUNET_break (0); return 0; } uri_address = GNUNET_strndup (address, end - address); /* For URIs we use '(' and ')' instead of '[' and ']' as brackets are reserved characters in URIs; need to convert back to '[]' for the plugin */ plugin_address = map_characters (uri_address, "()", "[]"); GNUNET_free (uri_address); if (GNUNET_OK != papi->string_to_address (papi->cls, plugin_address, strlen (plugin_address) + 1, &addr, &addr_len)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to parse `%s' as an address for plugin `%s'\n"), plugin_address, plugin_name); GNUNET_free (plugin_name); GNUNET_free (plugin_address); return 0; } GNUNET_free (plugin_address); /* address.peer is unset - not used by add_address() */ haddr.address_length = addr_len; haddr.address = addr; haddr.transport_name = plugin_name; ret = GNUNET_HELLO_add_address (&haddr, expire, buffer, max); GNUNET_free (addr); GNUNET_free (plugin_name); return ret; } /** * Continuation called from 'GNUNET_PEERINFO_add_peer' * * @param cls closure, NULL * @param emsg error message, NULL on success */ static void add_continuation (void *cls, const char *emsg) { ac = NULL; if (NULL != emsg) fprintf (stderr, _("Failure adding HELLO: %s\n"), emsg); tt = GNUNET_SCHEDULER_add_now (&state_machine, NULL); } /** * Parse the PUT URI given at the command line and add it to our peerinfo * database. * * @param put_uri URI string to parse * @return GNUNET_OK on success, GNUNET_SYSERR if the URI was invalid, GNUNET_NO on other errors */ static int parse_hello_uri (const char *put_uri) { const char *pks; const char *exc; struct GNUNET_HELLO_Message *hello; struct GNUNET_PEERINFO_HelloAddressParsingContext ctx; if (0 != strncmp (put_uri, HELLO_URI_PREFIX, strlen (HELLO_URI_PREFIX))) return GNUNET_SYSERR; pks = &put_uri[strlen (HELLO_URI_PREFIX)]; exc = strstr (pks, "!"); if (GNUNET_OK != GNUNET_STRINGS_string_to_data (pks, (NULL == exc) ? strlen (pks) : (exc - pks), (unsigned char *) &my_public_key, sizeof (my_public_key))) return GNUNET_SYSERR; ctx.pos = exc; ctx.ret = GNUNET_OK; hello = GNUNET_HELLO_create (&my_public_key, &add_address_to_hello, &ctx); if (NULL != hello) { /* WARNING: this adds the address from URI WITHOUT verification! */ if (GNUNET_OK == ctx.ret) ac = GNUNET_PEERINFO_add_peer (peerinfo, hello, &add_continuation, NULL); else tt = GNUNET_SCHEDULER_add_now (&state_machine, NULL); GNUNET_free (hello); } /* wait 1s to give peerinfo operation a chance to succeed */ /* FIXME: current peerinfo API sucks to require this; not to mention that we get no feedback to determine if the operation actually succeeded */ return ctx.ret; } /* ************************ Main state machine ********************* */ /** * Main state machine that goes over all options and * runs the next requested function. * * @param cls unused * @param tc scheduler context */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PrintContext *pc; struct AddressRecord *ar; unsigned int i; if (NULL != ac) { GNUNET_PEERINFO_add_peer_cancel (ac); ac = NULL; } if (GNUNET_SCHEDULER_NO_TASK != tt) { GNUNET_SCHEDULER_cancel (tt); tt = GNUNET_SCHEDULER_NO_TASK; } if (NULL != pic) { GNUNET_PEERINFO_iterate_cancel (pic); pic = NULL; } while (NULL != (pc = pc_head)) { GNUNET_CONTAINER_DLL_remove (pc_head, pc_tail, pc); for (i=0;iaddress_list_size;i++) { ar = &pc->address_list[i]; GNUNET_free_non_null (ar->result); if (NULL != ar->atsc) { GNUNET_TRANSPORT_address_to_string_cancel (ar->atsc); ar->atsc = NULL; } } GNUNET_free_non_null (pc->address_list); GNUNET_free (pc); } GPI_plugins_unload (); if (NULL != peerinfo) { GNUNET_PEERINFO_disconnect (peerinfo); peerinfo = NULL; } } /** * Main function that will be run by the scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param c configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { struct GNUNET_CRYPTO_RsaPrivateKey *priv; char *fn; cfg = c; if (args[0] != NULL) { FPRINTF (stderr, _("Invalid command line argument `%s'\n"), args[0]); return; } peerinfo = GNUNET_PEERINFO_connect (cfg); if (peerinfo == NULL) { FPRINTF (stderr, "%s", _("Could not access PEERINFO service. Exiting.\n")); return; } if ( (GNUNET_YES == get_self) || (GNUNET_YES == get_uri) ) { /* load private key */ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY", &fn)) { FPRINTF (stderr, _("Could not find option `%s:%s' in configuration.\n"), "GNUNETD", "HOSTKEYFILE"); return; } if (NULL == (priv = GNUNET_CRYPTO_rsa_key_create_from_file (fn))) { FPRINTF (stderr, _("Loading hostkey from `%s' failed.\n"), fn); GNUNET_free (fn); return; } GNUNET_free (fn); GNUNET_CRYPTO_rsa_key_get_public (priv, &my_public_key); GNUNET_CRYPTO_rsa_key_free (priv); GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key), &my_peer_identity.hashPubKey); } tt = GNUNET_SCHEDULER_add_now (&state_machine, NULL); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); } /** * Main state machine that goes over all options and * runs the next requested function. * * @param cls unused * @param tc scheduler context */ static void state_machine (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { tt = GNUNET_SCHEDULER_NO_TASK; if (NULL != put_uri) { GPI_plugins_load (cfg); if (GNUNET_SYSERR == parse_hello_uri (put_uri)) fprintf (stderr, _("Invalid URI `%s'\n"), put_uri); GNUNET_free (put_uri); put_uri = NULL; return; } if (GNUNET_YES == get_info) { get_info = GNUNET_NO; GPI_plugins_load (cfg); pic = GNUNET_PEERINFO_iterate (peerinfo, NULL, TIMEOUT, &print_peer_info, NULL); return; } if (GNUNET_YES == get_self) { struct GNUNET_CRYPTO_HashAsciiEncoded enc; get_self = GNUNET_NO; GNUNET_CRYPTO_hash_to_enc (&my_peer_identity.hashPubKey, &enc); if (be_quiet) printf ("%s\n", (char *) &enc); else printf (_("I am peer `%s'.\n"), (const char *) &enc); } if (GNUNET_YES == get_uri) { struct GetUriContext *guc; char *pkey; guc = GNUNET_malloc (sizeof (struct GetUriContext)); pkey = GNUNET_CRYPTO_rsa_public_key_to_string (&my_public_key); GNUNET_asprintf (&guc->uri, "%s%s", HELLO_URI_PREFIX, pkey); GNUNET_free (pkey); GPI_plugins_load (cfg); pic = GNUNET_PEERINFO_iterate (peerinfo, &my_peer_identity, TIMEOUT, &print_my_uri, guc); get_uri = GNUNET_NO; return; } GNUNET_SCHEDULER_shutdown (); } /** * The main function to obtain peer information. * * @param argc number of arguments from the command line * @param argv command line arguments * @return 0 ok, 1 on error */ int main (int argc, char *const *argv) { static const struct GNUNET_GETOPT_CommandLineOption options[] = { {'n', "numeric", NULL, gettext_noop ("don't resolve host names"), 0, &GNUNET_GETOPT_set_one, &no_resolve}, {'q', "quiet", NULL, gettext_noop ("output only the identity strings"), 0, &GNUNET_GETOPT_set_one, &be_quiet}, {'s', "self", NULL, gettext_noop ("output our own identity only"), 0, &GNUNET_GETOPT_set_one, &get_self}, {'i', "info", NULL, gettext_noop ("list all known peers"), 0, &GNUNET_GETOPT_set_one, &get_info}, {'g', "get-hello", NULL, gettext_noop ("also output HELLO uri(s)"), 0, &GNUNET_GETOPT_set_one, &get_uri}, {'p', "put-hello", "HELLO", gettext_noop ("add given HELLO uri to the database"), 1, &GNUNET_GETOPT_set_string, &put_uri}, GNUNET_GETOPT_OPTION_END }; return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, "gnunet-peerinfo", gettext_noop ("Print information about peers."), options, &run, NULL)) ? 0 : 1; } /* end of gnunet-peerinfo.c */ gnunet-0.9.3/src/peerinfo-tool/Makefile.in0000644000175000017500000005723411762217212015376 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = gnunet-peerinfo$(EXEEXT) subdir = src/peerinfo-tool DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnunet_config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) am_gnunet_peerinfo_OBJECTS = gnunet-peerinfo.$(OBJEXT) \ gnunet-peerinfo_plugins.$(OBJEXT) gnunet_peerinfo_OBJECTS = $(am_gnunet_peerinfo_OBJECTS) gnunet_peerinfo_DEPENDENCIES = \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(gnunet_peerinfo_SOURCES) DIST_SOURCES = $(gnunet_peerinfo_SOURCES) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ARGZ_H = @ARGZ_H@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLDIR = @DLLDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT_LIBS = @EXT_LIBS@ EXT_LIB_PATH = @EXT_LIB_PATH@ FGREP = @FGREP@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ GN_INTLINCL = @GN_INTLINCL@ GN_LIBINTL = @GN_LIBINTL@ GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ GREP = @GREP@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ INCLTDL = @INCLTDL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ LIBADD_DLOPEN = @LIBADD_DLOPEN@ LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ LIBCURL = @LIBCURL@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ LIBPREFIX = @LIBPREFIX@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIPO = @LIPO@ LN_S = @LN_S@ LTDLDEPS = @LTDLDEPS@ LTDLINCL = @LTDLINCL@ LTDLOPEN = @LTDLOPEN@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LTLIBUNISTRING = @LTLIBUNISTRING@ LT_CONFIG_H = @LT_CONFIG_H@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJC = @OBJC@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ POSUB = @POSUB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ STRIP = @STRIP@ SUDO_BINARY = @SUDO_BINARY@ UNIXONLY = @UNIXONLY@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ _libcurl_config = @_libcurl_config@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_target = @build_target@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ ltdl_LIBOBJS = @ltdl_LIBOBJS@ ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sys_symbol_underscore = @sys_symbol_underscore@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -lole32 -lshell32 -liconv -lstdc++ -lcomdlg32 -lgdi32 @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 @USE_COVERAGE_TRUE@XLIB = -lgcov gnunet_peerinfo_SOURCES = \ gnunet-peerinfo.c \ gnunet-peerinfo_plugins.c gnunet-peerinfo_plugins.h gnunet_peerinfo_LDADD = \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la @HAVE_PYTHON_PEXPECT_TRUE@check_SCRIPTS = \ @HAVE_PYTHON_PEXPECT_TRUE@ test_gnunet_peerinfo.py @ENABLE_TEST_RUN_TRUE@TESTS = $(check_SCRIPTS) do_subst = $(SED) -e 's,[@]PYTHON[@],$(PYTHON),g' EXTRA_DIST = \ test_gnunet_peerinfo.py.in \ test_gnunet_peerinfo_data.conf CLEANFILES = $(check_SCRIPTS) all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/peerinfo-tool/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/peerinfo-tool/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gnunet-peerinfo$(EXEEXT): $(gnunet_peerinfo_OBJECTS) $(gnunet_peerinfo_DEPENDENCIES) @rm -f gnunet-peerinfo$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_peerinfo_OBJECTS) $(gnunet_peerinfo_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-peerinfo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-peerinfo_plugins.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_SCRIPTS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-binPROGRAMS clean-generic clean-libtool ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-binPROGRAMS install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-binPROGRAMS test_gnunet_peerinfo.py: test_gnunet_peerinfo.py.in Makefile $(do_subst) < $(srcdir)/test_gnunet_peerinfo.py.in > test_gnunet_peerinfo.py chmod +x test_gnunet_peerinfo.py # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gnunet-0.9.3/src/peerinfo-tool/gnunet-peerinfo_plugins.c0000644000175000017500000001110011760502551020322 00000000000000/* This file is part of GNUnet. (C) 2010,2011 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file peerinfo-tool/gnunet-peerinfo_plugins.c * @brief plugin management * @author Christian Grothoff */ #include "platform.h" #include "gnunet-peerinfo_plugins.h" #include "gnunet_transport_plugin.h" #include "gnunet_hello_lib.h" /** * Entry in doubly-linked list of all of our plugins. */ struct TransportPlugin { /** * This is a doubly-linked list. */ struct TransportPlugin *next; /** * This is a doubly-linked list. */ struct TransportPlugin *prev; /** * API of the transport as returned by the plugin's * initialization function. */ struct GNUNET_TRANSPORT_PluginFunctions *api; /** * Short name for the plugin (i.e. "tcp"). */ char *short_name; /** * Name of the library (i.e. "gnunet_plugin_transport_tcp"). */ char *lib_name; /** * Environment this transport service is using * for this plugin. */ struct GNUNET_TRANSPORT_PluginEnvironment env; }; /** * Head of DLL of all loaded plugins. */ static struct TransportPlugin *plugins_head; /** * Head of DLL of all loaded plugins. */ static struct TransportPlugin *plugins_tail; /** * Load and initialize all plugins. The respective functions will be * invoked by the plugins when the respective events happen. The * closure will be set to a 'const char*' containing the name of the * plugin that caused the call. * * @param cfg configuration to use */ void GPI_plugins_load (const struct GNUNET_CONFIGURATION_Handle *cfg) { struct TransportPlugin *plug; struct TransportPlugin *next; char *libname; char *plugs; char *pos; if (NULL != plugins_head) return; /* already loaded */ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "TRANSPORT", "PLUGINS", &plugs)) return; GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting transport plugins `%s'\n"), plugs); for (pos = strtok (plugs, " "); pos != NULL; pos = strtok (NULL, " ")) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' transport plugin\n"), pos); GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", pos); plug = GNUNET_malloc (sizeof (struct TransportPlugin)); plug->short_name = GNUNET_strdup (pos); plug->lib_name = libname; plug->env.cfg = cfg; plug->env.cls = plug->short_name; GNUNET_CONTAINER_DLL_insert (plugins_head, plugins_tail, plug); } GNUNET_free (plugs); next = plugins_head; while (next != NULL) { plug = next; next = plug->next; plug->api = GNUNET_PLUGIN_load (plug->lib_name, &plug->env); if (plug->api == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to load transport plugin for `%s'\n"), plug->lib_name); GNUNET_CONTAINER_DLL_remove (plugins_head, plugins_tail, plug); GNUNET_free (plug->short_name); GNUNET_free (plug->lib_name); GNUNET_free (plug); } } } /** * Unload all plugins */ void GPI_plugins_unload () { struct TransportPlugin *plug; while (NULL != (plug = plugins_head)) { GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api)); GNUNET_free (plug->lib_name); GNUNET_free (plug->short_name); GNUNET_CONTAINER_DLL_remove (plugins_head, plugins_tail, plug); GNUNET_free (plug); } } /** * Obtain the plugin API based on a plugin name. * * @param name name of the plugin * @return the plugin's API, NULL if the plugin is not loaded */ struct GNUNET_TRANSPORT_PluginFunctions * GPI_plugins_find (const char *name) { struct TransportPlugin *head = plugins_head; while ((head != NULL) && (0 != strcmp (name, head->short_name))) head = head->next; if (NULL == head) return NULL; return head->api; } /* end of file gnunet-peerinfo_plugins.c */